gigatron/rom/Contrib/psr/multiply/out/ROM.lst
2025-01-28 19:17:01 +03:00

7553 lines
560 KiB
Plaintext

* source: C:\Users\peter.russell\Documents\Personal\multiply\Contrib\psr\multiply\sys\ROM.asm.py
169 if __name__ == '__main__': enableListing()
170 #-----------------------------------------------------------------------
171 #
172 # Start of core
173 #
174 #-----------------------------------------------------------------------
175
176 # Pre-loading the formal interface as a way to get warnings when
177 # accidentally redefined with a different value
178 #
179 loadBindings(repo_root / 'interface.json')
180 loadBindings(repo_root / 'Core' / 'interface-dev.json') # Provisional values for DEVROM
181
182 # Gigatron clock
183 cpuClock = 6.250e+06
184
185 # Output pin assignment for VGA
186 R, G, B, hSync, vSync = 1, 4, 16, 64, 128
187 syncBits = hSync+vSync # Both pulses negative
188
189 # When the XOUT register is in the circuit, the rising edge triggers its update.
190 # The loop can therefore not be agnostic to the horizontal pulse polarity.
191 assert syncBits & hSync != 0
192
193 # VGA 640x480 defaults (to be adjusted below!)
194 vFront = 10 # Vertical front porch
195 vPulse = 2 # Vertical sync pulse
196 vBack = 33 # Vertical back porch
197 vgaLines = vFront + vPulse + vBack + 480
198 vgaClock = 25.175e+06
199
200 # Video adjustments for Gigatron
201 # 1. Our clock is (slightly) slower than 1/4th VGA clock. Not all monitors will
202 # accept the decreased frame rate, so we restore the frame rate to above
203 # minimum 59.94 Hz by cutting some lines from the vertical front porch.
204 vFrontAdjust = vgaLines - int(4 * cpuClock / vgaClock * vgaLines)
205 vFront -= vFrontAdjust
206 # 2. Extend vertical sync pulse so we can feed the game controller the same
207 # signal. This is needed for controllers based on the 4021 instead of 74165
208 vPulseExtension = max(0, 8-vPulse)
209 vPulse += vPulseExtension
210 # 3. Borrow these lines from the back porch so the refresh rate remains
211 # unaffected
212 vBack -= vPulseExtension
213
214 # Start value of vertical blank counter
215 videoYline0 = 1-2*(vFront+vPulse+vBack-2)
216
217 # Mismatch between video lines and sound channels
218 soundDiscontinuity = (vFront+vPulse+vBack) % 4
219
220 # QQVGA resolution
221 qqVgaWidth = 160
222 qqVgaHeight = 120
223
224 # Game controller bits (actual controllers in kit have negative output)
225 # +----------------------------------------+
226 # | Up B* |
227 # | Left Right B A* |
228 # | Down Select Start A |
229 # +----------------------------------------+ *=Auto fire
230 buttonRight = 1
231 buttonLeft = 2
232 buttonDown = 4
233 buttonUp = 8
234 buttonStart = 16
235 buttonSelect = 32
236 buttonB = 64
237 buttonA = 128
238
239 #-----------------------------------------------------------------------
240 #
241 # RAM page 0: zero-page variables
242 #
243 #-----------------------------------------------------------------------
244
245 # Memory size in pages from auto-detect
246 memSize = zpByte()
247
248 # The current channel number for sound generation. Advanced every scan line
249 # and independent of the vertical refresh to maintain constant oscillation.
250 channel = zpByte()
251
252 # Next sound sample being synthesized
253 sample = zpByte()
254 # To save one instruction in the critical inner loop, `sample' is always
255 # reset with its own address instead of, for example, the value 0. Compare:
256 # 1 instruction reset
257 # st sample,[sample]
258 # 2 instruction reset:
259 # ld 0
260 # st [sample]
261 # The difference is not audible. This is fine when the reset/address
262 # value is low and doesn't overflow with 4 channels added to it.
263 # There is an alternative, but it requires pull-down diodes on the data bus:
264 # st [sample],[sample]
265 assert 4*63 + sample < 256
266 # We pin this reset/address value to 3, so `sample' swings from 3 to 255
267 assert sample == 3
268
269 # Former bootCount and bootCheck (<= ROMv3)
270 zpReserved = zpByte() # Recycled and still unused. Candidate future uses:
271 # - Video driver high address (for alternative video modes)
272 # - v6502: ADH offset ("MMU")
273 # - v8080: ???
274 vCpuSelect = zpByte() # Active interpreter page
275
276 # Entropy harvested from SRAM startup and controller input
277 entropy = zpByte(3)
278
279 # Visible video
280 videoY = zpByte() # Counts up from 0 to 238 in steps of 2
281 # Counts up (and is odd) during vertical blank
282 videoModeB = zpByte() # Handler for every 2nd line (pixel burst or vCPU)
283 videoModeC = zpByte() # Handler for every 3rd line (pixel burst or vCPU)
284 videoModeD = zpByte() # Handler for every 4th line (pixel burst or vCPU)
285
286 nextVideo = zpByte() # Jump offset to scan line handler (videoA, B, C...)
287 videoPulse = nextVideo # Used for pulse width modulation
288
289 # Frame counter is good enough as system clock
290 frameCount = zpByte(1)
291
292 # Serial input (game controller)
293 serialRaw = zpByte() # New raw serial read
294 serialLast = zpByte() # Previous serial read
295 buttonState = zpByte() # Clearable button state
296 resetTimer = zpByte() # After 2 seconds of holding 'Start', do a soft reset
297 # XXX move to page 1 to free up space
298
299 # Extended output (blinkenlights in bit 0:3 and audio in bit 4:7). This
300 # value must be present in AC during a rising hSync edge. It then gets
301 # copied to the XOUT register by the hardware. The XOUT register is only
302 # accessible in this indirect manner because it isn't part of the core
303 # CPU architecture.
304 xout = zpByte()
305 xoutMask = zpByte() # The blinkenlights and sound on/off state
306
307 # vCPU interpreter
308 vTicks = zpByte() # Interpreter ticks are units of 2 clocks
309 vPC = zpByte(2) # Interpreter program counter, points into RAM
310 vAC = zpByte(2) # Interpreter accumulator, 16-bits
311 vLR = zpByte(2) # Return address, for returning after CALL
312 vSP = zpByte(1) # Stack pointer
313 vTmp = zpByte()
314 vReturn = zpByte() # Return into video loop (in page of vBlankStart)
315
316 # Scratch
317 frameX = zpByte() # Starting byte within page
318 frameY = zpByte() # Page of current pixel line (updated by videoA)
319
320 # Vertical blank (reuse some variables used in the visible part)
321 videoSync0 = frameX # Vertical sync type on current line (0xc0 or 0x40)
322 videoSync1 = frameY # Same during horizontal pulse (0x80 or 0x00)
323
324 # Versioning for GT1 compatibility
325 # Please refer to Docs/GT1-files.txt for interpreting this variable
326 romType = zpByte(1)
327
328 # The low 3 bits are repurposed to select the actively updated sound channels.
329 # Valid bit combinations are:
330 # xxxxx011 Default after reset: 4 channels (page 1,2,3,4)
331 # xxxxx001 2 channels at double update rate (page 1,2)
332 # xxxxx000 1 channel at quadruple update rate (page 1)
333 # The main application for this is to free up the high bytes of page 2,3,4.
334 channelMask = symbol('channelMask_v4')
335 assert romType == channelMask
336
337 # SYS function arguments and results/scratch
338 sysFn = zpByte(2)
339 sysArgs = zpByte(8)
340
341 # Play sound if non-zero, count down and stop sound when zero
342 soundTimer = zpByte()
343
344 # Fow now the LED state machine itself is hard-coded in the program ROM
345 ledTimer = zpByte() # Number of ticks until next LED change
346 ledState_v2 = zpByte() # Current LED state
347 ledTempo = zpByte() # Next value for ledTimer after LED state change
348
349 # All bytes above, except 0x80, are free for temporary/scratch/stacks etc
350 userVars = zpByte(0)
351
352 #-----------------------------------------------------------------------
353 #
354 # RAM page 1: video line table
355 #
356 #-----------------------------------------------------------------------
357
358 # Byte 0-239 define the video lines
359 videoTable = 0x0100 # Indirection table: Y[0] dX[0] ..., Y[119] dX[119]
360
361 vReset = 0x01f0
362 vIRQ_v5 = 0x01f6
363 ctrlBits = 0x01f8
364 videoTop_v5 = 0x01f9 # Number of skip lines
365
366 # Highest bytes are for sound channel variables
367 wavA = 250 # Waveform modulation with `adda'
368 wavX = 251 # Waveform modulation with `xora'
369 keyL = 252 # Frequency low 7 bits (bit7 == 0)
370 keyH = 253 # Frequency high 8 bits
371 oscL = 254 # Phase low 7 bits
372 oscH = 255 # Phase high 8 bits
373
374 #-----------------------------------------------------------------------
375 # Memory layout
376 #-----------------------------------------------------------------------
377
378 userCode = 0x0200 # Application vCPU code
379 soundTable = 0x0700 # Wave form tables (doubles as right-shift-2 table)
380 screenMemory = 0x0800 # Default start of screen memory: 0x0800 to 0x7fff
381
382 #-----------------------------------------------------------------------
383 # Application definitions
384 #-----------------------------------------------------------------------
385
386 maxTicks = 28//2 # Duration of vCPU's slowest virtual opcode (ticks)
387 minTicks = 14//2 # vcPU's fastest instruction
388 v6502_maxTicks = 38//2 # Max duration of v6502 processing phase (ticks)
389
390 runVcpu_overhead = 5 # Caller overhead (cycles)
391 vCPU_overhead = 9 # Callee overhead of jumping in and out (cycles)
392 v6502_overhead = 11 # Callee overhead for v6502 (cycles)
393
394 v6502_adjust = (v6502_maxTicks - maxTicks) + (v6502_overhead - vCPU_overhead)//2
395 assert v6502_adjust >= 0 # v6502's overhead is a bit more than vCPU
396
397 def runVcpu(n, ref=None, returnTo=None):
398 """Macro to run interpreter for exactly n cycles. Returns 0 in AC.
399
400 - `n' is the number of available Gigatron cycles including overhead.
401 This is converted into interpreter ticks and takes into account
402 the vCPU calling overheads. A `nop' is inserted when necessary
403 for alignment between cycles and ticks.
404 - `returnTo' is where program flow continues after return. If not set
405 explicitely, it will be the first instruction behind the expansion.
406 - If another interpreter than vCPU is active (v6502...), that one
407 must adjust for the timing differences, because runVcpu wouldn't know."""
408
409 overhead = runVcpu_overhead + vCPU_overhead
410 if returnTo == 0x100: # Special case for videoZ
411 overhead -= 2
412
413 if n is None:
414 # (Clumsily) create a maximum time slice, corresponding to a vTicks
415 # value of 127 (giving 282 cycles). A higher value doesn't work because
416 # then SYS functions that just need 28 cycles (0 excess) won't start.
417 n = (127 + maxTicks) * 2 + overhead
418
419 n -= overhead
420 assert n > 0
421
422 if n % 2 == 1:
423 nop() # Tick alignment
424 n -= 1
425 assert n % 2 == 0
426
427 print('runVcpu at $%04x net cycles %3s info %s' % (pc(), n, ref))
428
429 if returnTo != 0x100:
430 if returnTo is None:
431 returnTo = pc() + 5 # Next instruction
432 ld(lo(returnTo)) #0
433 st([vReturn]) #1
434
435 n //= 2
436 n -= maxTicks # First instruction always runs
437 assert n < 128
438 assert n >= v6502_adjust
439
440 ld([vCpuSelect],Y) #2
441 jmp(Y,'ENTER') #3
442 ld(n) #4
443 assert runVcpu_overhead == 5
444
445 #-----------------------------------------------------------------------
446 # v6502 definitions
447 #-----------------------------------------------------------------------
448
449 # Registers are zero page variables
450 v6502_PC = vLR # Program Counter
451 v6502_PCL = vLR+0 # Program Counter Low
452 v6502_PCH = vLR+1 # Program Counter High
453 v6502_S = vSP # Stack Pointer (kept as "S+1")
454 v6502_A = vAC+0 # Accumulator
455 v6502_BI = vAC+1 # B Input Register (used by SBC)
456 v6502_ADL = sysArgs+0 # Low Address Register
457 v6502_ADH = sysArgs+1 # High Address Register
458 v6502_IR = sysArgs+2 # Instruction Register
459 v6502_P = sysArgs+3 # Processor Status Register (V flag in bit 7)
460 v6502_Qz = sysArgs+4 # Quick Status Register for Z flag
461 v6502_Qn = sysArgs+5 # Quick Status Register for N flag
462 v6502_X = sysArgs+6 # Index Register X
463 v6502_Y = sysArgs+7 # Index Register Y
464 v6502_Tmp = vTmp # Scratch (may be clobbered outside v6502)
465
466 # MOS 6502 definitions for P register
467 v6502_Cflag = 1 # Carry Flag (unsigned overflow)
468 v6502_Zflag = 2 # Zero Flag (all bits zero)
469 v6502_Iflag = 4 # Interrupt Enable Flag (1=Disable)
470 v6502_Dflag = 8 # Decimal Enable Flag (aka BCD mode, 1=Enable)
471 v6502_Bflag = 16 # Break (or PHP) Instruction Flag
472 v6502_Uflag = 32 # Unused (always 1)
473 v6502_Vflag = 64 # Overflow Flag (signed overflow)
474 v6502_Nflag = 128 # Negative Flag (bit 7 of result)
475
476 # In emulation it is much faster to keep the V flag in bit 7
477 # This can be corrected when importing/exporting with PHP, PLP, etc
478 v6502_Vemu = 128
479
480 # On overflow:
481 # """Overflow is set if two inputs with the same sign produce
482 # a result with a different sign. Otherwise it is clear."""
483 # Formula (without carry/borrow in!):
484 # (A ^ (A+B)) & (B ^ (A+B)) & 0x80
485 # References:
486 # http://www.righto.com/2012/12/the-6502-overflow-flag-explained.html
487 # http://6502.org/tutorials/vflag.html
488
489 # Memory layout
490 v6502_Stack = 0x0000 # 0x0100 is already used in the Gigatron
491 #v6502_NMI = 0xfffa
492 #v6502_RESET = 0xfffc
493 #v6502_IRQ = 0xfffe
494
495 #-----------------------------------------------------------------------
496 #
497 # $0000 ROM page 0: Boot
498 #
499 #-----------------------------------------------------------------------
500
501 align(0x100, size=0x80)
502
503 # Give a first sign of life that can be checked with a voltmeter
address
| encoding
| | instruction
| | | operands
| | | |
V V V V
0000 0000 ld $00 504 ld(0b0000) # LEDs |OOOO|
0001 1880 ld $80,out 505 ld(syncBits^hSync,OUT) # Prepare XOUT update, hSync goes down, RGB to black
0002 18c0 ld $c0,out 506 ld(syncBits,OUT) # hSync goes up, updating XOUT
507
508 # Setup I/O and RAM expander
0003 c17c ctrl $7c 509 ctrl(0b01111100) # Disable SPI slaves, enable RAM, bank 1
510 # ^^^^^^^^
511 # |||||||`-- SCLK
512 # ||||||`--- Not connected
513 # |||||`---- /SS0
514 # ||||`----- /SS1
515 # |||`------ /SS2
516 # ||`------- /SS3
517 # |`-------- B0
518 # `--------- B1
519 # bit15 --------- MOSI = 0
520
521 # Simple RAM test and size check by writing to [1<<n] and see if [0] changes or not.
0004 0001 ld $01 522 ld(1) # Quick RAM test and count
523 label('.countMem0')
.countMem0: 0005 d601 st [$01],y 524 st([memSize],Y) # Store in RAM and load AC in Y
0006 00ff ld $ff 525 ld(255)
0007 6900 xora [y,$00] 526 xora([Y,0]) # Invert value from memory
0008 ca00 st [y,$00] 527 st([Y,0]) # Test RAM by writing the new value
0009 c200 st [$00] 528 st([0]) # Copy result in [0]
000a 6900 xora [y,$00] 529 xora([Y,0]) # Read back and compare if written ok
000b ec0b bne $000b 530 bne(pc()) # Loop forever on RAM failure here
000c 00ff ld $ff 531 ld(255)
000d 6900 xora [y,$00] 532 xora([Y,0]) # Invert memory value again
000e ca00 st [y,$00] 533 st([Y,0]) # To restore original value
000f 6100 xora [$00] 534 xora([0]) # Compare with inverted copy
0010 f014 beq .countMem1 535 beq('.countMem1') # If equal, we wrapped around
0011 0101 ld [$01] 536 ld([memSize])
0012 fc05 bra .countMem0 537 bra('.countMem0') # Loop to test next address line
0013 8200 adda ac 538 adda(AC) # Executes in the branch delay slot!
539 label('.countMem1')
540
541 # Momentarily wait to allow for debouncing of the reset switch by spinning
542 # roughly 2^15 times at 2 clocks per loop: 6.5ms@10MHz to 10ms@6.3MHz
543 # Real-world switches normally bounce shorter than that.
544 # "[...] 16 switches exhibited an average 1557 usec of bouncing, with,
545 # as I said, a max of 6200 usec" (From: http://www.ganssle.com/debouncing.htm)
546 # Relevant for the breadboard version, as the kit doesn't have a reset switch.
547
.countMem1: 0014 00ff ld $ff 548 ld(255) # Debounce reset button
549 label('.debounce')
.debounce: 0015 c200 st [$00] 550 st([0])
0016 ec16 bne $0016 551 bne(pc())
0017 a001 suba $01 552 suba(1) # Branch delay slot
0018 0100 ld [$00] 553 ld([0])
0019 ec15 bne .debounce 554 bne('.debounce')
001a a001 suba $01 555 suba(1) # Branch delay slot
556
557 # Update LEDs (memory is present and counted, reset is stable)
001b 0001 ld $01 558 ld(0b0001) # LEDs |*OOO|
001c 1880 ld $80,out 559 ld(syncBits^hSync,OUT)
001d 18c0 ld $c0,out 560 ld(syncBits,OUT)
561
562 # Scan the entire RAM space to collect entropy for a random number generator.
563 # The 16-bit address space is scanned, even if less RAM was detected.
001e 0000 ld $00 564 ld(0) # Collect entropy from RAM
001f d218 st [$18],x 565 st([vAC+0],X)
0020 d619 st [$19],y 566 st([vAC+1],Y)
567 label('.initEnt0')
.initEnt0: 0021 0106 ld [$06] 568 ld([entropy+0])
0022 f425 bge .initEnt1 569 bpl('.initEnt1')
0023 8d00 adda [y,x] 570 adda([Y,X])
0024 60bf xora $bf 571 xora(191)
572 label('.initEnt1')
.initEnt1: 0025 c206 st [$06] 573 st([entropy+0])
0026 0107 ld [$07] 574 ld([entropy+1])
0027 f42a bge .initEnt2 575 bpl('.initEnt2')
0028 8106 adda [$06] 576 adda([entropy+0])
0029 60c1 xora $c1 577 xora(193)
578 label('.initEnt2')
.initEnt2: 002a c207 st [$07] 579 st([entropy+1])
002b 8108 adda [$08] 580 adda([entropy+2])
002c c208 st [$08] 581 st([entropy+2])
002d 0118 ld [$18] 582 ld([vAC+0])
002e 8001 adda $01 583 adda(1)
002f ec21 bne .initEnt0 584 bne('.initEnt0')
0030 d218 st [$18],x 585 st([vAC+0],X)
0031 0119 ld [$19] 586 ld([vAC+1])
0032 8001 adda $01 587 adda(1)
0033 ec21 bne .initEnt0 588 bne('.initEnt0')
0034 d619 st [$19],y 589 st([vAC+1],Y)
590
591 # Update LEDs
0035 0003 ld $03 592 ld(0b0011) # LEDs |**OO|
0036 1880 ld $80,out 593 ld(syncBits^hSync,OUT)
0037 18c0 ld $c0,out 594 ld(syncBits,OUT)
595
596 # vCPU reset handler
0038 00ee ld $ee 597 ld((vReset&255)-2) # Setup vCPU reset handler
0039 c216 st [$16] 598 st([vPC])
003a 9002 adda $02,x 599 adda(2,X)
003b 0001 ld $01 600 ld(vReset>>8)
003c d617 st [$17],y 601 st([vPC+1],Y)
003d dc59 st $59,[y,x++] 602 st('LDI', [Y,Xpp])
003e dc5e st $5e,[y,x++] 603 st('SYS_Reset_88', [Y,Xpp])
003f dc2b st $2b,[y,x++] 604 st('STW', [Y,Xpp])
0040 dc22 st $22,[y,x++] 605 st(sysFn, [Y,Xpp])
0041 dcb4 st $b4,[y,x++] 606 st('SYS', [Y,Xpp]) # SYS -> SYS_Reset_88 -> SYS_Exec_88
0042 dce2 st $e2,[y,x++] 607 st(256-88//2+maxTicks,[Y,Xpp])
0043 dc00 st $00,[y,x++] 608 st(0, [Y,Xpp]) # vIRQ_v5: Disable interrupts
0044 dc00 st $00,[y,x++] 609 st(0, [Y,Xpp]) # vIRQ_v5
0045 dcfc st $fc,[y,x++] 610 st(0b11111100, [Y,Xpp]) # Control register
0046 dc00 st $00,[y,x++] 611 st(0, [Y,Xpp]) # videoTop
612
0047 0002 ld $02 613 ld(hi('ENTER')) # Active interpreter (vCPU,v6502) = vCPU
0048 c205 st [$05] 614 st([vCpuSelect])
615
0049 00ff ld $ff 616 ld(255) # Setup serial input
004a c20e st [$0e] 617 st([frameCount])
004b c20f st [$0f] 618 st([serialRaw])
004c c210 st [$10] 619 st([serialLast])
004d c211 st [$11] 620 st([buttonState])
004e c212 st [$12] 621 st([resetTimer]) # resetTimer<0 when entering Main.gcl
622
004f 0007 ld $07 623 ld(0b0111) # LEDs |***O|
0050 1880 ld $80,out 624 ld(syncBits^hSync,OUT)
0051 18c0 ld $c0,out 625 ld(syncBits,OUT)
626
0052 0000 ld $00 627 ld(0)
0053 c200 st [$00] 628 st([0]) # Carry lookup ([0x80] in 1st line of vBlank)
0054 c202 st [$02] 629 st([channel])
0055 c22c st [$2c] 630 st([soundTimer])
631
0056 000f ld $0f 632 ld(0b1111) # LEDs |****|
0057 1880 ld $80,out 633 ld(syncBits^hSync,OUT)
0058 18c0 ld $c0,out 634 ld(syncBits,OUT)
0059 c213 st [$13] 635 st([xout]) # Setup for control by video loop
005a c214 st [$14] 636 st([xoutMask])
637
005b 1401 ld $01,y 638 ld(hi('startVideo'),Y) # Enter video loop at vertical blank
005c e003 jmp y,$03 639 jmp(Y,'startVideo')
005d c22e st [$2e] 640 st([ledState_v2]) # Setting to 1..126 means "stopped"
641
642 #-----------------------------------------------------------------------
643 # Extension SYS_Reset_88: Soft reset
644 #-----------------------------------------------------------------------
645
646 # SYS_Reset_88 initiates an immediate Gigatron reset from within the vCPU.
647 # The reset sequence itself is mostly implemented in GCL by Reset.gcl,
648 # which must first be loaded into RAM. But as that takes more than 1 scanline,
649 # some vCPU bootstrapping code gets loaded with SYS_Exec_88.
650 # !!! This function was REMOVED from interface.json
651 # !!! Better use vReset as generic entry point for soft reset
652
653 # ROM type (see also Docs/GT1-files.txt)
654 romTypeValue = symbol('romTypeValue_ROMv5')
655
656 label('SYS_Reset_88')
657 assert pc()>>8 == 0
658 assert (romTypeValue & 7) == 0
SYS_Reset_88: 005e 0040 ld $40 659 ld(romTypeValue) #15 Set ROM type/version and clear channel mask
005f c221 st [$21] 660 st([romType]) #16
0060 0000 ld $00 661 ld(0) #17
0061 c21c st [$1c] 662 st([vSP]) #18 vSP
0062 1401 ld $01,y 663 ld(hi('videoTop_v5'),Y) #19
0063 caf9 st [y,$f9] 664 st([Y,lo('videoTop_v5')]) #20 Show all 120 pixel lines
0064 caf6 st [y,$f6] 665 st([Y,vIRQ_v5]) #21 Disable vIRQ dispatch
0065 caf7 st [y,$f7] 666 st([Y,vIRQ_v5+1]) #22
0066 c22c st [$2c] 667 st([soundTimer]) #23 soundTimer
668 assert userCode&255 == 0
0067 c21a st [$1a] 669 st([vLR]) #24 vLR
0068 0002 ld $02 670 ld(userCode>>8) #25
0069 c21b st [$1b] 671 st([vLR+1]) #26
006a 00f6 ld $f6 672 ld('nopixels') #27 Video mode 3 (fast)
006b c20a st [$0a] 673 st([videoModeB]) #28
006c c20b st [$0b] 674 st([videoModeC]) #29
006d c20c st [$0c] 675 st([videoModeD]) #30
006e 00ad ld $ad 676 ld('SYS_Exec_88') #31 SYS_Exec_88
006f c222 st [$22] 677 st([sysFn]) #32 High byte (remains) 0
0070 0000 ld $00 678 ld('Reset') #33 Reset.gt1 from EPROM
0071 c224 st [$24] 679 st([sysArgs+0]) #34
0072 0000 ld $00 680 ld(hi('Reset')) #35
0073 c225 st [$25] 681 st([sysArgs+1]) #36
0074 0116 ld [$16] 682 ld([vPC]) #37 Force second SYS call
0075 a002 suba $02 683 suba(2) #38
0076 c216 st [$16] 684 st([vPC]) #39
685 # Return to interpreter
0077 1403 ld $03,y 686 ld(hi('NEXTY'),Y) #40
0078 e000 jmp y,$00 687 jmp(Y,'NEXTY') #41
0079 00ea ld $ea 688 ld(-44/2) #42
689
690 #-----------------------------------------------------------------------
691 # Placeholders for future SYS functions. This works as a kind of jump
692 # table. The indirection allows SYS implementations to be moved around
693 # between ROM versions, at the expense of 2 clock cycles (or 1). When
694 # the function is not present it just acts as a NOP. Of course, when a
695 # SYS function must be patched or extended it needs to have budget for
696 # that in its declared maximum cycle count.
697 #
698 # Technically the same goal can be achieved by starting each function
699 # with 2 nop's, or by overdeclaring their duration in the first place
700 # (a bit is still wise to do). But this can result in fragmentation
701 # of future ROM images. The indirection avoids that.
702 #
703 # An added advantage of having these in ROM page 0 is that it saves one
704 # byte when setting sysFn: LDI+STW (4 bytes) instead of LDWI+STW (5 bytes)
705 #-----------------------------------------------------------------------
706
007a 0200 nop 707 align(0x80, size=0x80)
007b 0200 nop
007c 0200 nop
* 6 times
708 assert pc() == 0x80
709
0080 1403 ld $03,y 710 ld(hi('REENTER'),Y) #15 slot 0x80
0081 e0cb jmp y,$cb 711 jmp(Y,'REENTER') #16
0082 00f6 ld $f6 712 ld(-20/2) #17
713
0083 1403 ld $03,y 714 ld(hi('REENTER'),Y) #15 slot 0x83
0084 e0cb jmp y,$cb 715 jmp(Y,'REENTER') #16
0085 00f6 ld $f6 716 ld(-20/2) #17
717
0086 1403 ld $03,y 718 ld(hi('REENTER'),Y) #15 slot 0x86
0087 e0cb jmp y,$cb 719 jmp(Y,'REENTER') #16
0088 00f6 ld $f6 720 ld(-20/2) #17
721
0089 1403 ld $03,y 722 ld(hi('REENTER'),Y) #15 slot 0x89
008a e0cb jmp y,$cb 723 jmp(Y,'REENTER') #16
008b 00f6 ld $f6 724 ld(-20/2) #17
725
008c 1403 ld $03,y 726 ld(hi('REENTER'),Y) #15 slot 0x8c
008d e0cb jmp y,$cb 727 jmp(Y,'REENTER') #16
008e 00f6 ld $f6 728 ld(-20/2) #17
729
008f 1403 ld $03,y 730 ld(hi('REENTER'),Y) #15 slot 0x8f
0090 e0cb jmp y,$cb 731 jmp(Y,'REENTER') #16
0091 00f6 ld $f6 732 ld(-20/2) #17
733
0092 1403 ld $03,y 734 ld(hi('REENTER'),Y) #15 slot 0x92
0093 e0cb jmp y,$cb 735 jmp(Y,'REENTER') #16
0094 00f6 ld $f6 736 ld(-20/2) #17
737
0095 1403 ld $03,y 738 ld(hi('REENTER'),Y) #15 slot 0x95
0096 e0cb jmp y,$cb 739 jmp(Y,'REENTER') #16
0097 00f6 ld $f6 740 ld(-20/2) #17
741
0098 1403 ld $03,y 742 ld(hi('REENTER'),Y) #15 slot 0x98
0099 e0cb jmp y,$cb 743 jmp(Y,'REENTER') #16
009a 00f6 ld $f6 744 ld(-20/2) #17
745
009b 1403 ld $03,y 746 ld(hi('REENTER'),Y) #15 slot 0x9b
009c e0cb jmp y,$cb 747 jmp(Y,'REENTER') #16
009d 00f6 ld $f6 748 ld(-20/2) #17
749
009e 1403 ld $03,y 750 ld(hi('REENTER'),Y) #15 slot 0x9e
009f e0cb jmp y,$cb 751 jmp(Y,'REENTER') #16
00a0 00f6 ld $f6 752 ld(-20/2) #17
753
00a1 1403 ld $03,y 754 ld(hi('REENTER'),Y) #15 slot 0xa1
00a2 e0cb jmp y,$cb 755 jmp(Y,'REENTER') #16
00a3 00f6 ld $f6 756 ld(-20/2) #17
757
00a4 1403 ld $03,y 758 ld(hi('REENTER'),Y) #15 slot 0xa4
00a5 e0cb jmp y,$cb 759 jmp(Y,'REENTER') #16
00a6 00f6 ld $f6 760 ld(-20/2) #17
761
00a7 1403 ld $03,y 762 ld(hi('REENTER'),Y) #15 slot 0xa7
00a8 e0cb jmp y,$cb 763 jmp(Y,'REENTER') #16
00a9 00f6 ld $f6 764 ld(-20/2) #17
765
00aa 1403 ld $03,y 766 ld(hi('REENTER'),Y) #15 slot 0xaa
00ab e0cb jmp y,$cb 767 jmp(Y,'REENTER') #16
00ac 00f6 ld $f6 768 ld(-20/2) #17
769
770 #-----------------------------------------------------------------------
771 # Extension SYS_Exec_88: Load code from ROM into memory and execute it
772 #-----------------------------------------------------------------------
773 #
774 # This loads the vCPU code with consideration of the current vSP
775 # Used during reset, but also for switching between applications or for
776 # loading data from ROM from within an application (overlays).
777 #
778 # ROM stream format is [<addrH> <addrL> <n&255> n*<byte>]* 0
779 # on top of lookup tables.
780 #
781 # Variables:
782 # sysArgs[0:1] ROM pointer (in)
783 # sysArgs[2:3] RAM pointer (changed)
784 # sysArgs[4] State counter (changed)
785 # vLR vCPU continues here (in)
786
787 label('SYS_Exec_88')
SYS_Exec_88: 00ad 1412 ld $12,y 788 ld(hi('sys_Exec'),Y) #15
00ae e04b jmp y,$4b 789 jmp(Y,'sys_Exec') #16
00af 0000 ld $00 790 ld(0) #17 Address of loader on zero page
791
792 #-----------------------------------------------------------------------
793 # More placeholders for future SYS functions
794 #-----------------------------------------------------------------------
795
00b0 1403 ld $03,y 796 ld(hi('REENTER'),Y) #15 slot 0xb0
00b1 e0cb jmp y,$cb 797 jmp(Y,'REENTER') #16
00b2 00f6 ld $f6 798 ld(-20/2) #17
799
00b3 1403 ld $03,y 800 ld(hi('REENTER'),Y) #15 slot 0xb3
00b4 e0cb jmp y,$cb 801 jmp(Y,'REENTER') #16
00b5 00f6 ld $f6 802 ld(-20/2) #17
803
00b6 1403 ld $03,y 804 ld(hi('REENTER'),Y) #15 slot 0xb6
00b7 e0cb jmp y,$cb 805 jmp(Y,'REENTER') #16
00b8 00f6 ld $f6 806 ld(-20/2) #17
807
00b9 1403 ld $03,y 808 ld(hi('REENTER'),Y) #15 slot 0xb9
00ba e0cb jmp y,$cb 809 jmp(Y,'REENTER') #16
00bb 00f6 ld $f6 810 ld(-20/2) #17
811
00bc 1403 ld $03,y 812 ld(hi('REENTER'),Y) #15 slot 0xbc
00bd e0cb jmp y,$cb 813 jmp(Y,'REENTER') #16
00be 00f6 ld $f6 814 ld(-20/2) #17
815
00bf 1403 ld $03,y 816 ld(hi('REENTER'),Y) #15 slot 0xbf
00c0 e0cb jmp y,$cb 817 jmp(Y,'REENTER') #16
00c1 00f6 ld $f6 818 ld(-20/2) #17
819
00c2 1403 ld $03,y 820 ld(hi('REENTER'),Y) #15 slot 0xc2
00c3 e0cb jmp y,$cb 821 jmp(Y,'REENTER') #16
00c4 00f6 ld $f6 822 ld(-20/2) #17
823
00c5 1403 ld $03,y 824 ld(hi('REENTER'),Y) #15 slot 0xc5
00c6 e0cb jmp y,$cb 825 jmp(Y,'REENTER') #16
00c7 00f6 ld $f6 826 ld(-20/2) #17
827
00c8 1403 ld $03,y 828 ld(hi('REENTER'),Y) #15 slot 0xc8
00c9 e0cb jmp y,$cb 829 jmp(Y,'REENTER') #16
00ca 00f6 ld $f6 830 ld(-20/2) #17
831
00cb 1403 ld $03,y 832 ld(hi('REENTER'),Y) #15 slot 0xcb
00cc e0cb jmp y,$cb 833 jmp(Y,'REENTER') #16
00cd 00f6 ld $f6 834 ld(-20/2) #17
835
00ce 1403 ld $03,y 836 ld(hi('REENTER'),Y) #15 slot 0xce
00cf e0cb jmp y,$cb 837 jmp(Y,'REENTER') #16
00d0 00f6 ld $f6 838 ld(-20/2) #17
839
00d1 1403 ld $03,y 840 ld(hi('REENTER'),Y) #15 slot 0xd1
00d2 e0cb jmp y,$cb 841 jmp(Y,'REENTER') #16
00d3 00f6 ld $f6 842 ld(-20/2) #17
843
00d4 1403 ld $03,y 844 ld(hi('REENTER'),Y) #15 slot 0xd4
00d5 e0cb jmp y,$cb 845 jmp(Y,'REENTER') #16
00d6 00f6 ld $f6 846 ld(-20/2) #17
847
00d7 1403 ld $03,y 848 ld(hi('REENTER'),Y) #15 slot 0xd7
00d8 e0cb jmp y,$cb 849 jmp(Y,'REENTER') #16
00d9 00f6 ld $f6 850 ld(-20/2) #17
851
00da 1403 ld $03,y 852 ld(hi('REENTER'),Y) #15 slot 0xda
00db e0cb jmp y,$cb 853 jmp(Y,'REENTER') #16
00dc 00f6 ld $f6 854 ld(-20/2) #17
855
00dd 1403 ld $03,y 856 ld(hi('REENTER'),Y) #15 slot 0xdd
00de e0cb jmp y,$cb 857 jmp(Y,'REENTER') #16
00df 00f6 ld $f6 858 ld(-20/2) #17
859
00e0 1403 ld $03,y 860 ld(hi('REENTER'),Y) #15 slot 0xe0
00e1 e0cb jmp y,$cb 861 jmp(Y,'REENTER') #16
00e2 00f6 ld $f6 862 ld(-20/2) #17
863
00e3 1403 ld $03,y 864 ld(hi('REENTER'),Y) #15 slot 0xe3
00e4 e0cb jmp y,$cb 865 jmp(Y,'REENTER') #16
00e5 00f6 ld $f6 866 ld(-20/2) #17
867
00e6 1403 ld $03,y 868 ld(hi('REENTER'),Y) #15 slot 0xe6
00e7 e0cb jmp y,$cb 869 jmp(Y,'REENTER') #16
00e8 00f6 ld $f6 870 ld(-20/2) #17
871
872 #-----------------------------------------------------------------------
873 # Extension SYS_StoreBytes_DEVROM_XXX
874 #-----------------------------------------------------------------------
875
00e9 1403 ld $03,y 876 ld(hi('REENTER'),Y) #15 slot 0xe9
00ea e0cb jmp y,$cb 877 jmp(Y,'REENTER') #16
00eb 00f6 ld $f6 878 ld(-20/2) #17
879
880 #-----------------------------------------------------------------------
881 # Extension SYS_LoadBytes_DEVROM_XXX
882 #-----------------------------------------------------------------------
883
884 # Load object variables into zero-page
885 # XXX Unfinished
886 #
887 # Variables
888 # vLR Pointer to size byte + object variables
889 # $30...$30+n-1 Target location
890
891 label('SYS_LoadBytes_DEVROM_XXX')
SYS_LoadBytes_DEVROM_XXX:
00ec 1412 ld $12,y 892 ld(hi('sys_LoadBytes'),Y) #15
00ed e0e9 jmp y,$e9 893 jmp(Y,'sys_LoadBytes') #16
00ee 151b ld [$1b],y 894 ld([vLR+1],Y) #17
895
896 #-----------------------------------------------------------------------
897 # Extension SYS_ReadRomDir_v5_80
898 #-----------------------------------------------------------------------
899
900 # Get next entry from ROM file system. Use vAC=0 to get the first entry.
901
902 # Variables:
903 # vAC Start address of current entry (inout)
904 # sysArgs[0:7] File name, padded with zeroes (out)
905
906 label('SYS_ReadRomDir_v5_80')
SYS_ReadRomDir_v5_80:
00ef 1415 ld $15,y 907 ld(hi('sys_ReadRomDir'),Y) #15
00f0 e06f jmp y,$6f 908 jmp(Y,'sys_ReadRomDir') #16
00f1 0119 ld [$19] 909 ld([vAC+1]) #17
910
00f2 0200 nop 911 fillers(until=symbol('SYS_Out_22') & 255)
00f3 0200 nop
912
913 #-----------------------------------------------------------------------
914 # Extension SYS_Out_22
915 #-----------------------------------------------------------------------
916
917 # Send byte to output port
918 #
919 # Variables:
920 # vAC
921
922 label('SYS_Out_22')
SYS_Out_22: 00f4 1924 ld [$24],out 923 ld([sysArgs+0],OUT) #15
00f5 0200 nop 924 nop() #16
00f6 1403 ld $03,y 925 ld(hi('REENTER'),Y) #17
00f7 e0cb jmp y,$cb 926 jmp(Y,'REENTER') #18
00f8 00f5 ld $f5 927 ld(-22/2) #19
928
929 #-----------------------------------------------------------------------
930 # Extension SYS_In_24
931 #-----------------------------------------------------------------------
932
933 # Read a byte from the input port
934 #
935 # Variables:
936 # vAC
937
938 label('SYS_In_24')
SYS_In_24: 00f9 c318 st in,[$18] 939 st(IN, [vAC]) #15
00fa 0000 ld $00 940 ld(0) #16
00fb c219 st [$19] 941 st([vAC+1]) #17
00fc 0200 nop 942 nop() #18
00fd 1403 ld $03,y 943 ld(hi('REENTER'),Y) #19
00fe e0cb jmp y,$cb 944 jmp(Y,'REENTER') #20
00ff 00f4 ld $f4 945 ld(-24/2) #21
946
947 assert pc()&255 == 0
948
949 #-----------------------------------------------------------------------
950 #
951 # $0100 ROM page 1: Video loop vertical blank
952 #
953 #-----------------------------------------------------------------------
954 align(0x100, size=0x100)
955
956 # Video off mode (also no sound, serial, timer, blinkenlights, ...).
957 # For benchmarking purposes. This still has the overhead for the vTicks
958 # administration, time slice granularity etc.
959 label('videoZ')
960 videoZ = pc()
videoZ: 0100 1505 ld [$05],y 961 runVcpu(None, '---- novideo', returnTo=videoZ)
0101 e0ff jmp y,$ff
0102 007f ld $7f
962
963 label('startVideo') # (Re)start of video signal from idle state
startVideo: 0103 00c0 ld $c0 964 ld(syncBits)
965
966 # Start of vertical blank interval
967 label('vBlankStart')
vBlankStart: 0104 c21f st [$1f] 968 st([videoSync0]) #32 Start of vertical blank interval
0105 0080 ld $80 969 ld(syncBits^hSync) #33
0106 c220 st [$20] 970 st([videoSync1]) #34
971
972 # Reset line counter before vCPU can see it
0107 00b3 ld $b3 973 ld(videoYline0) #35
0108 c209 st [$09] 974 st([videoY]) #36
975
976 # Update frame count and [0x80] (4 cycles)
0109 0001 ld $01 977 ld(1) #37 Reinitialize carry lookup, for robustness
010a c280 st [$80] 978 st([0x80]) #38
010b 810e adda [$0e] 979 adda([frameCount]) #39 Frame counter
010c c20e st [$0e] 980 st([frameCount]) #40
981
982 # Mix entropy (11 cycles)
010d 6107 xora [$07] 983 xora([entropy+1]) #41 Mix entropy
010e 610f xora [$0f] 984 xora([serialRaw]) #42 Mix in serial input
010f 8106 adda [$06] 985 adda([entropy+0]) #43
0110 c206 st [$06] 986 st([entropy+0]) #44
0111 8108 adda [$08] 987 adda([entropy+2]) #45 Some hidden state
0112 c208 st [$08] 988 st([entropy+2]) #46
0113 e816 blt $0116 989 bmi(pc()+3) #47
0114 fc17 bra $0117 990 bra(pc()+3) #48
0115 6053 xora $53 991 xora(64+16+2+1) #49
0116 606c xora $6c 992 xora(64+32+8+4) #49(!)
0117 8107 adda [$07] 993 adda([entropy+1]) #50
0118 c207 st [$07] 994 st([entropy+1]) #51
995
996 # LED sequencer (18 cycles)
0119 012d ld [$2d] 997 ld([ledTimer]) #52 Blinkenlight sequencer
011a f01d beq $011d 998 beq(pc()+3) #53
011b fc1e bra $011e 999 bra(pc()+3) #54
011c a001 suba $01 1000 suba(1) #55
011d 012f ld [$2f] 1001 ld([ledTempo]) #55(!)
011e c22d st [$2d] 1002 st([ledTimer]) #56
011f f022 beq $0122 1003 beq(pc()+3) #57
0120 fc23 bra $0123 1004 bra(pc()+3) #58
0121 0000 ld $00 1005 ld(0) #59 Don't advance state
0122 0001 ld $01 1006 ld(1) #59(!) Advance state when timer passes through 0
0123 812e adda [$2e] 1007 adda([ledState_v2]) #60
0124 ec27 bne $0127 1008 bne(pc()+3) #61
0125 fc28 bra $0128 1009 bra(pc()+3) #62
0126 00e8 ld $e8 1010 ld(-24) #63 State 0 becomes -24, start of sequence
0127 e42c bgt .leds#65 1011 bgt('.leds#65') #63(!) Catch the stopped state (>0)
0128 c22e st [$2e] 1012 st([ledState_v2]) #64
0129 8048 adda $48 1013 adda('.leds#69') #65
012a fe00 bra ac 1014 bra(AC) #66 Jump to lookup table
012b fc48 bra .leds#69 1015 bra('.leds#69') #67 Single-instruction subroutine
1016
1017 label('.leds#65')
.leds#65: 012c 000f ld $0f 1018 ld(0x0f) #65 Maintain stopped state
012d c22e st [$2e] 1019 st([ledState_v2]) #66
012e fc48 bra .leds#69 1020 bra('.leds#69') #67
012f 2114 anda [$14] 1021 anda([xoutMask]) #68 Always clear sound bits (this is why AC=0x0f)
1022
0130 000f ld $0f 1023 ld(0b1111) #68 LEDs |****| offset -24 Low 4 bits are the LED output
0131 0007 ld $07 1024 ld(0b0111) #68 LEDs |***O|
0132 0003 ld $03 1025 ld(0b0011) #68 LEDs |**OO|
0133 0001 ld $01 1026 ld(0b0001) #68 LEDs |*OOO|
0134 0002 ld $02 1027 ld(0b0010) #68 LEDs |O*OO|
0135 0004 ld $04 1028 ld(0b0100) #68 LEDs |OO*O|
0136 0008 ld $08 1029 ld(0b1000) #68 LEDs |OOO*|
0137 0004 ld $04 1030 ld(0b0100) #68 LEDs |OO*O|
0138 0002 ld $02 1031 ld(0b0010) #68 LEDs |O*OO|
0139 0001 ld $01 1032 ld(0b0001) #68 LEDs |*OOO|
013a 0003 ld $03 1033 ld(0b0011) #68 LEDs |**OO|
013b 0007 ld $07 1034 ld(0b0111) #68 LEDs |***O|
013c 000f ld $0f 1035 ld(0b1111) #68 LEDs |****|
013d 000e ld $0e 1036 ld(0b1110) #68 LEDs |O***|
013e 000c ld $0c 1037 ld(0b1100) #68 LEDs |OO**|
013f 0008 ld $08 1038 ld(0b1000) #68 LEDs |OOO*|
0140 0004 ld $04 1039 ld(0b0100) #68 LEDs |OO*O|
0141 0002 ld $02 1040 ld(0b0010) #68 LEDs |O*OO|
0142 0001 ld $01 1041 ld(0b0001) #68 LEDs |*OOO|
0143 0002 ld $02 1042 ld(0b0010) #68 LEDs |O*OO|
0144 0004 ld $04 1043 ld(0b0100) #68 LEDs |OO*O|
0145 0008 ld $08 1044 ld(0b1000) #68 LEDs |OOO*|
0146 000c ld $0c 1045 ld(0b1100) #68 LEDs |OO**|
0147 000e ld $0e 1046 ld(0b1110) #68 LEDs |O***| offset -1
1047 label('.leds#69')
.leds#69: 0148 c214 st [$14] 1048 st([xoutMask]) #69 Sound bits will be re-enabled below
0149 0010 ld $10 1049 ld(vPulse*2) #70 vPulse default length when not modulated
014a c20d st [$0d] 1050 st([videoPulse]) #71
1051
1052 # When the total number of scan lines per frame is not an exact multiple of the
1053 # (4) channels, there will be an audible discontinuity if no measure is taken.
1054 # This static noise can be suppressed by swallowing the first `lines mod 4'
1055 # partial samples after transitioning into vertical blank. This is easiest if
1056 # the modulo is 0 (do nothing), 1 (reset sample when entering the last visible
1057 # scan line), or 2 (reset sample while in the first blank scan line). For the
1058 # last case there is no solution yet: give a warning.
1059 extra = 0
1060 if soundDiscontinuity == 2:
1061 st(sample, [sample]) # Sound continuity
1062 extra += 1
1063 if soundDiscontinuity > 2:
1064 highlight('Warning: sound discontinuity not suppressed')
1065
1066 # vCPU interrupt
014b 010e ld [$0e] 1067 ld([frameCount]) #72
1068 beq('vBlankFirst#75') #73
014c f052 beq vBlankFirst#75
1069
014d 0055 ld $55 1070 runVcpu(186-74-extra, #74 Application cycles (scan line 0)
014e c21e st [$1e]
014f 1505 ld [$05],y
0150 e0ff jmp y,$ff
0151 0023 ld $23
1071 '---D line 0 no timeout',
1072 returnTo='vBlankFirst#186')
1073
1074 label('vBlankFirst#75')
vBlankFirst#75:
0152 1412 ld $12,y 1075 ld(hi('vBlankFirst#78'),Y) #75
0153 e000 jmp y,$00 1076 jmp(Y,'vBlankFirst#78') #76
0154 1401 ld $01,y 1077 ld(hi(vIRQ_v5),Y) #77
1078 label('vBlankFirst#186')
1079
1080 # Mitigation for rogue channelMask (3 cycles)
vBlankFirst#186:
0155 0121 ld [$21] 1081 ld([channelMask]) #186 Normalize channelMask, for robustness
0156 20fb anda $fb 1082 anda(0b11111011) #187
0157 c221 st [$21] 1083 st([channelMask]) #188
1084
1085 # Sound on/off (6 cycles)
0158 012c ld [$2c] 1086 ld([soundTimer]) #189 Sound on/off
0159 ec5c bne $015c 1087 bne(pc()+3) #190
015a fc5d bra $015d 1088 bra(pc()+3) #191
015b 0000 ld $00 1089 ld(0) #192 Keeps sound unchanged (should be off here)
015c 00f0 ld $f0 1090 ld(0xf0) #192(!) Turns sound back on
015d 4114 ora [$14] 1091 ora([xoutMask]) #193
015e c214 st [$14] 1092 st([xoutMask]) #194
1093
1094 # Sound timer count down (5 cycles)
015f 012c ld [$2c] 1095 ld([soundTimer]) #195 Sound timer
0160 f063 beq $0163 1096 beq(pc()+3) #196
0161 fc64 bra $0164 1097 bra(pc()+3) #197
0162 a001 suba $01 1098 suba(1) #198
0163 0000 ld $00 1099 ld(0) #198
0164 c22c st [$2c] 1100 st([soundTimer]) #199
1101
0165 191f ld [$1f],out 1102 ld([videoSync0],OUT) #0 <New scan line start>
1103 label('sound1')
sound1: 0166 0102 ld [$02] 1104 ld([channel]) #1 Advance to next sound channel
0167 2121 anda [$21] 1105 anda([channelMask]) #2
0168 8001 adda $01 1106 adda(1) #3
0169 1920 ld [$20],out 1107 ld([videoSync1],OUT) #4 Start horizontal pulse
016a d602 st [$02],y 1108 st([channel],Y) #5
016b 007f ld $7f 1109 ld(0x7f) #6 Update sound channel
016c 29fe anda [y,$fe] 1110 anda([Y,oscL]) #7
016d 89fc adda [y,$fc] 1111 adda([Y,keyL]) #8
016e cafe st [y,$fe] 1112 st([Y,oscL]) #9
016f 3080 anda $80,x 1113 anda(0x80,X) #10
0170 0500 ld [x] 1114 ld([X]) #11
0171 89ff adda [y,$ff] 1115 adda([Y,oscH]) #12
0172 89fd adda [y,$fd] 1116 adda([Y,keyH]) #13
0173 caff st [y,$ff] 1117 st([Y,oscH]) #14
0174 20fc anda $fc 1118 anda(0xfc) #15
0175 69fb xora [y,$fb] 1119 xora([Y,wavX]) #16
0176 1200 ld ac,x 1120 ld(AC,X) #17
0177 09fa ld [y,$fa] 1121 ld([Y,wavA]) #18
0178 1407 ld $07,y 1122 ld(soundTable>>8,Y) #19
0179 8d00 adda [y,x] 1123 adda([Y,X]) #20
017a e87d blt $017d 1124 bmi(pc()+3) #21
017b fc7e bra $017e 1125 bra(pc()+3) #22
017c 203f anda $3f 1126 anda(63) #23
017d 003f ld $3f 1127 ld(63) #23(!)
017e 8103 adda [$03] 1128 adda([sample]) #24
017f c203 st [$03] 1129 st([sample]) #25
1130
0180 0113 ld [$13] 1131 ld([xout]) #26 Gets copied to XOUT
0181 1412 ld $12,y 1132 ld(hi('vBlankLast#34'),Y) #27 Prepare jumping out of page in last line
0182 191f ld [$1f],out 1133 ld([videoSync0],OUT) #28 End horizontal pulse
1134
1135 # Count through the vertical blank interval until its last scan line
0183 0109 ld [$09] 1136 ld([videoY]) #29
1137 bpl('.vBlankLast#32') #30
0184 f4b1 bge .vBlankLast#32
0185 8002 adda $02 1138 adda(2) #31
0186 c209 st [$09] 1139 st([videoY]) #32
1140
1141 # Determine if we're in the vertical sync pulse
0187 a0bd suba $bd 1142 suba(1-2*(vBack+vPulse-1)) #33 Prepare sync values
0188 ec8d bne .prepSync36 1143 bne('.prepSync36') #34 Tests for start of vPulse
0189 a10d suba [$0d] 1144 suba([videoPulse]) #35
018a 0040 ld $40 1145 ld(syncBits^vSync) #36 Entering vertical sync pulse
018b fc92 bra .prepSync39 1146 bra('.prepSync39') #37
018c c21f st [$1f] 1147 st([videoSync0]) #38
1148 label('.prepSync36')
.prepSync36: 018d ec91 bne .prepSync38 1149 bne('.prepSync38') #36 Tests for end of vPulse
018e 00c0 ld $c0 1150 ld(syncBits) #37
018f fc93 bra .prepSync40 1151 bra('.prepSync40') #38 Entering vertical back porch
0190 c21f st [$1f] 1152 st([videoSync0]) #39
1153 label('.prepSync38')
.prepSync38: 0191 011f ld [$1f] 1154 ld([videoSync0]) #38 Load current value
1155 label('.prepSync39')
.prepSync39: 0192 0200 nop 1156 nop() #39
1157 label('.prepSync40')
.prepSync40: 0193 6040 xora $40 1158 xora(hSync) #40 Precompute, as during the pulse there is no time
0194 c220 st [$20] 1159 st([videoSync1]) #41
1160
1161 # Capture the serial input before the '595 shifts it out
0195 0109 ld [$09] 1162 ld([videoY]) #42 Capture serial input
0196 60cf xora $cf 1163 xora(1-2*(vBack-1-1)) #43 Exactly when the 74HC595 has captured all 8 controller bits
0197 ec9a bne $019a 1164 bne(pc()+3) #44
0198 fc9b bra $019b 1165 bra(pc()+3) #45
0199 c30f st in,[$0f] 1166 st(IN, [serialRaw]) #46
019a c000 st $00,[$00] 1167 st(0,[0]) #46(!) Reinitialize carry lookup, for robustness
1168
1169 # Update [xout] with the next sound sample every 4 scan lines.
1170 # Keep doing this on 'videoC equivalent' scan lines in vertical blank.
019b 0109 ld [$09] 1171 ld([videoY]) #47
019c 2006 anda $06 1172 anda(6) #48
1173 beq('vBlankSample') #49
019d f0a6 beq vBlankSample
019e 0103 ld [$03] 1174 ld([sample]) #50
1175
1176 label('vBlankNormal')
vBlankNormal: 019f 00a4 ld $a4 1177 runVcpu(199-51, 'AB-D line 1-36')#51 Application cycles (vBlank scan lines without sound sample update)
01a0 c21e st [$1e]
01a1 1505 ld [$05],y
01a2 e0ff jmp y,$ff
01a3 0035 ld $35
01a4 fc66 bra sound1 1178 bra('sound1') #199
01a5 191f ld [$1f],out 1179 ld([videoSync0],OUT) #0 <New scan line start>
1180
1181 label('vBlankSample')
vBlankSample: 01a6 400f ora $0f 1182 ora(0x0f) #51 New sound sample is ready
01a7 2114 anda [$14] 1183 anda([xoutMask]) #52
01a8 c213 st [$13] 1184 st([xout]) #53
01a9 c003 st $03,[$03] 1185 st(sample, [sample]) #54 Reset for next sample
1186
01aa 00af ld $af 1187 runVcpu(199-55, '--C- line 3-39')#55 Application cycles (vBlank scan lines with sound sample update)
01ab c21e st [$1e]
01ac 1505 ld [$05],y
01ad e0ff jmp y,$ff
01ae 0033 ld $33
01af fc66 bra sound1 1188 bra('sound1') #199
01b0 191f ld [$1f],out 1189 ld([videoSync0],OUT) #0 <New scan line start>
1190
1191 #-----------------------------------------------------------------------
1192
1193 label('.vBlankLast#32')
.vBlankLast#32:
01b1 e02e jmp y,$2e 1194 jmp(Y,'vBlankLast#34') #32 Jump out of page for space reasons
1195 #assert hi(controllerType) == hi(pc()) # Assume these share the high address
01b2 1401 ld $01,y 1196 ld(hi(pc()),Y) #33
1197
1198 label('vBlankLast#52')
1199
1200 # Respond to reset button (14 cycles)
1201 # - ResetTimer decrements as long as just [Start] is pressed down
1202 # - Reaching 0 (normal) or 128 (extended) triggers the soft reset sequence
1203 # - Initial value is 128 (or 255 at boot), first decrement, then check
1204 # - This starts vReset -> SYS_Reset_88 -> SYS_Exec_88 -> Reset.gcl -> Main.gcl
1205 # - Main.gcl then recognizes extended presses if resetTimer is 0..127 ("paasei")
1206 # - This requires a full cycle (4s) in the warm boot scenario
1207 # - Or a half cycle (2s) when pressing [Select] down during hard reset
1208 # - This furthermore requires >=1 frame (and <=128) to have passed between
1209 # reaching 128 and getting through Reset and the start of Main, while [Start]
1210 # was still pressed so the count reaches <128. Two reasonable expectations.
1211 # - The unintended power-up scenarios of ROMv1 (pulling SER_DATA low, or
1212 # pressing [Select] together with another button) now don't trigger anymore.
1213
vBlankLast#52:
01b3 0111 ld [$11] 1214 ld([buttonState]) #52 Check [Start] for soft reset
01b4 60ef xora $ef 1215 xora(~buttonStart) #53
01b5 ecbe bne .restart#56 1216 bne('.restart#56') #54
01b6 0112 ld [$12] 1217 ld([resetTimer]) #55 As long as button pressed
01b7 a001 suba $01 1218 suba(1) #56 ... count down the timer
01b8 c212 st [$12] 1219 st([resetTimer]) #57
01b9 207f anda $7f 1220 anda(127) #58
01ba f0c6 beq .restart#61 1221 beq('.restart#61') #59 Reset at 0 (normal 2s) or 128 (extended 4s)
01bb 00ee ld $ee 1222 ld((vReset&255)-2) #60 Start force reset when hitting 0
01bc fcc5 bra .restart#63 1223 bra('.restart#63') #61 ... otherwise do nothing yet
01bd fcc4 bra .restart#64 1224 bra('.restart#64') #62
1225 label('.restart#56')
.restart#56: 01be 0001 ld $01 1226 wait(62-56) #56
01bf ecbf bne $01bf
01c0 a001 suba $01
01c1 0200 nop
01c2 0080 ld $80 1227 ld(128) #62 Not pressed, reset the timer
01c3 c212 st [$12] 1228 st([resetTimer]) #63
1229 label('.restart#64')
.restart#64: 01c4 fccb bra .restart#66 1230 bra('.restart#66') #64
1231 label('.restart#63')
.restart#63: 01c5 0200 nop 1232 nop() #63,65
1233 label('.restart#61')
.restart#61: 01c6 c216 st [$16] 1234 st([vPC]) #61 Point vPC at vReset
01c7 0001 ld $01 1235 ld(vReset>>8) #62
01c8 c217 st [$17] 1236 st([vPC+1]) #63
01c9 0002 ld $02 1237 ld(hi('ENTER')) #64 Set active interpreter to vCPU
01ca c205 st [$05] 1238 st([vCpuSelect]) #65
1239 label('.restart#66')
1240
1241 # Switch video mode when (only) select is pressed (16 cycles)
1242 # XXX We could make this a vCPU interrupt
.restart#66: 01cb 0111 ld [$11] 1243 ld([buttonState]) #66 Check [Select] to switch modes
01cc 60df xora $df 1244 xora(~buttonSelect) #67 Only trigger when just [Select] is pressed
01cd ece2 bne .select#70 1245 bne('.select#70') #68
01ce 010b ld [$0b] 1246 ld([videoModeC]) #69
01cf e8d5 blt .select#72 1247 bmi('.select#72') #70 Branch when line C is off
01d0 010a ld [$0a] 1248 ld([videoModeB]) #71 Rotate: Off->D->B->C
01d1 c20b st [$0b] 1249 st([videoModeC]) #72
01d2 010c ld [$0c] 1250 ld([videoModeD]) #73
01d3 c20a st [$0a] 1251 st([videoModeB]) #74
01d4 fcda bra .select#77 1252 bra('.select#77') #75
1253 label('.select#72')
.select#72: 01d5 00f6 ld $f6 1254 ld('nopixels') #72,76
01d6 000a ld $0a 1255 ld('pixels') #73 Reset: On->D->B->C
01d7 c20b st [$0b] 1256 st([videoModeC]) #74
01d8 c20a st [$0a] 1257 st([videoModeB]) #75
01d9 0200 nop 1258 nop() #76
1259 label('.select#77')
.select#77: 01da c20c st [$0c] 1260 st([videoModeD]) #77
01db 0035 ld $35 1261 wait(188-78) #78 Don't waste code space expanding runVcpu here
01dc ecdc bne $01dc
01dd a001 suba $01
01de 0200 nop
1262 # AC==255 now
01df c211 st [$11] 1263 st([buttonState]) #188
1264 bra('vBlankEnd#191') #189
01e0 fcea bra vBlankEnd#191
01e1 0000 ld $00 1265 ld(0) #190
1266 label('.select#70')
1267
1268 # Mitigation of runaway channel variable
.select#70: 01e2 0102 ld [$02] 1269 ld([channel]) #70 Normalize channel, for robustness
01e3 2003 anda $03 1270 anda(0b00000011) #71
01e4 c202 st [$02] 1271 st([channel]) #72 Stop wild channel updates
1272
01e5 00ea ld $ea 1273 runVcpu(191-73, '---D line 40') #73 Application cycles (scan line 40)
01e6 c21e st [$1e]
01e7 1505 ld [$05],y
01e8 e0ff jmp y,$ff
01e9 0026 ld $26
1274
1275 # AC==0 now
1276 label('vBlankEnd#191')
vBlankEnd#191:
01ea 1401 ld $01,y 1277 ld(videoTop_v5>>8,Y) #191
01eb 09f9 ld [y,$f9] 1278 ld([Y,videoTop_v5]) #192
01ec c209 st [$09] 1279 st([videoY]) #193
01ed c21f st [$1f] 1280 st([frameX]) #194
01ee ecf1 bne $01f1 1281 bne(pc()+3) #195
01ef fcf2 bra $01f2 1282 bra(pc()+3) #196
01f0 0001 ld $01 1283 ld('videoA') #197
01f1 00ec ld $ec 1284 ld('videoF') #197(!)
01f2 c20d st [$0d] 1285 st([nextVideo]) #198
01f3 0102 ld [$02] 1286 ld([channel]) #199 Advance to next sound channel
01f4 2121 anda [$21] 1287 anda([channelMask]) #0 <New scan line start>
01f5 8001 adda $01 1288 adda(1) #1
01f6 1402 ld $02,y 1289 ld(hi('sound2'),Y) #2
01f7 e0b1 jmp y,$b1 1290 jmp(Y,'sound2') #3
01f8 1880 ld $80,out 1291 ld(syncBits^hSync,OUT) #4 Start horizontal pulse
1292
01f9 0200 nop 1293 fillers(until=0xff)
01fa 0200 nop
01fb 0200 nop
* 6 times
1294
1295 #-----------------------------------------------------------------------
1296 # Return point for vCPU slices during visible screen area
1297 #-----------------------------------------------------------------------
1298
1299 assert pc() == 0x1ff # Enables runVcpu() to re-enter into the next page
01ff fcae bra sound3 1300 bra('sound3') #200,0 <New scan line start>
1301
1302 #-----------------------------------------------------------------------
1303 #
1304 # $0200 ROM page 2: Video loop visible scanlines
1305 #
1306 #-----------------------------------------------------------------------
1307 align(0x100, size=0x100)
0200 0102 ld [$02] 1308 ld([channel]) #1 Advance to next sound channel
1309
1310 # Back porch A: first of 4 repeated scan lines
1311 # - Fetch next Yi and store it for retrieval in the next scan lines
1312 # - Calculate Xi from dXi, but there is no cycle time left to store it as well
1313 label('videoA')
videoA: 0201 00ca ld $ca 1314 ld('videoB') #29 1st scanline of 4 (always visible)
0202 c20d st [$0d] 1315 st([nextVideo]) #30
0203 1401 ld $01,y 1316 ld(videoTable>>8,Y) #31
0204 1109 ld [$09],x 1317 ld([videoY],X) #32
0205 0d00 ld [y,x] 1318 ld([Y,X]) #33
0206 de00 st [y,x++] 1319 st([Y,Xpp]) #34 Just X++
0207 c220 st [$20] 1320 st([frameY]) #35
0208 0d00 ld [y,x] 1321 ld([Y,X]) #36
0209 911f adda [$1f],x 1322 adda([frameX],X) #37
1323 label('pixels')
pixels: 020a 1520 ld [$20],y 1324 ld([frameY],Y) #38
020b 00c0 ld $c0 1325 ld(syncBits) #39
1326
1327 # Stream 160 pixels from memory location <Yi,Xi> onwards
1328 # Superimpose the sync signal bits to be robust against misprogramming
1329 for i in range(qqVgaWidth):
020c 5d00 ora [y,x++],out 1330 ora([Y,Xpp],OUT) #40-199 Pixel burst
020d 5d00 ora [y,x++],out
020e 5d00 ora [y,x++],out
* 160 times
02ac 18c0 ld $c0,out 1331 ld(syncBits,OUT) #0 <New scan line start> Back to black
1332
1333 # Front porch
02ad 0102 ld [$02] 1334 ld([channel]) #1 Advance to next sound channel
1335 label('sound3') # Return from vCPU interpreter
sound3: 02ae 2121 anda [$21] 1336 anda([channelMask]) #2
02af 8001 adda $01 1337 adda(1) #3
02b0 1880 ld $80,out 1338 ld(syncBits^hSync,OUT) #4 Start horizontal pulse
1339
1340 # Horizontal sync and sound channel update for scanlines outside vBlank
1341 label('sound2')
sound2: 02b1 d602 st [$02],y 1342 st([channel],Y) #5
02b2 007f ld $7f 1343 ld(0x7f) #6
02b3 29fe anda [y,$fe] 1344 anda([Y,oscL]) #7
02b4 89fc adda [y,$fc] 1345 adda([Y,keyL]) #8
02b5 cafe st [y,$fe] 1346 st([Y,oscL]) #9
02b6 3080 anda $80,x 1347 anda(0x80,X) #10
02b7 0500 ld [x] 1348 ld([X]) #11
02b8 89ff adda [y,$ff] 1349 adda([Y,oscH]) #12
02b9 89fd adda [y,$fd] 1350 adda([Y,keyH]) #13
02ba caff st [y,$ff] 1351 st([Y,oscH] ) #14
02bb 20fc anda $fc 1352 anda(0xfc) #15
02bc 69fb xora [y,$fb] 1353 xora([Y,wavX]) #16
02bd 1200 ld ac,x 1354 ld(AC,X) #17
02be 09fa ld [y,$fa] 1355 ld([Y,wavA]) #18
02bf 1407 ld $07,y 1356 ld(soundTable>>8,Y) #19
02c0 8d00 adda [y,x] 1357 adda([Y,X]) #20
02c1 e8c4 blt $02c4 1358 bmi(pc()+3) #21
02c2 fcc5 bra $02c5 1359 bra(pc()+3) #22
02c3 203f anda $3f 1360 anda(63) #23
02c4 003f ld $3f 1361 ld(63) #23(!)
02c5 8103 adda [$03] 1362 adda([sample]) #24
02c6 c203 st [$03] 1363 st([sample]) #25
1364
02c7 0113 ld [$13] 1365 ld([xout]) #26 Gets copied to XOUT
02c8 fd0d bra [$0d] 1366 bra([nextVideo]) #27
02c9 18c0 ld $c0,out 1367 ld(syncBits,OUT) #28 End horizontal pulse
1368
1369 # Back porch B: second of 4 repeated scan lines
1370 # - Recompute Xi from dXi and store for retrieval in the next scan lines
1371 label('videoB')
videoB: 02ca 00d3 ld $d3 1372 ld('videoC') #29 2nd scanline of 4
02cb c20d st [$0d] 1373 st([nextVideo]) #30
02cc 1401 ld $01,y 1374 ld(videoTable>>8,Y) #31
02cd 0109 ld [$09] 1375 ld([videoY]) #32
02ce 9001 adda $01,x 1376 adda(1,X) #33
02cf 011f ld [$1f] 1377 ld([frameX]) #34
02d0 8d00 adda [y,x] 1378 adda([Y,X]) #35
02d1 fd0a bra [$0a] 1379 bra([videoModeB]) #36
02d2 d21f st [$1f],x 1380 st([frameX],X) #37 Store in RAM and X
1381
1382 # Back porch C: third of 4 repeated scan lines
1383 # - Nothing new to for video do as Yi and Xi are known,
1384 # - This is the time to emit and reset the next sound sample
1385 label('videoC')
videoC: 02d3 00dc ld $dc 1386 ld('videoD') #29 3rd scanline of 4
02d4 c20d st [$0d] 1387 st([nextVideo]) #30
02d5 0103 ld [$03] 1388 ld([sample]) #31 New sound sample is ready (didn't fit in the audio loop)
02d6 400f ora $0f 1389 ora(0x0f) #32
02d7 2114 anda [$14] 1390 anda([xoutMask]) #33
02d8 c213 st [$13] 1391 st([xout]) #34 Update [xout] with new sample (4 channels just updated)
02d9 c003 st $03,[$03] 1392 st(sample, [sample]) #35 Reset for next sample
02da fd0b bra [$0b] 1393 bra([videoModeC]) #36
02db 111f ld [$1f],x 1394 ld([frameX],X) #37
1395
1396 # Back porch D: last of 4 repeated scan lines
1397 # - Calculate the next frame index
1398 # - Decide if this is the last line or not
1399 label('videoD') # Default video mode
videoD: 02dc 111f ld [$1f],x 1400 ld([frameX], X) #29 4th scanline of 4
02dd 0109 ld [$09] 1401 ld([videoY]) #30
02de a0ee suba $ee 1402 suba((120-1)*2) #31
1403 beq('.lastpixels#34') #32
02df f0e5 beq .lastpixels#34
02e0 80f0 adda $f0 1404 adda(120*2) #33 More pixel lines to go
02e1 c209 st [$09] 1405 st([videoY]) #34
02e2 0001 ld $01 1406 ld('videoA') #35
02e3 fd0c bra [$0c] 1407 bra([videoModeD]) #36
02e4 c20d st [$0d] 1408 st([nextVideo]) #37
1409
1410 label('.lastpixels#34')
1411 if soundDiscontinuity == 1:
.lastpixels#34:
02e5 c003 st $03,[$03] 1412 st(sample, [sample]) #34 Sound continuity
1413 else:
1414 nop() #34
02e6 00e9 ld $e9 1415 ld('videoE') #35 No more pixel lines to go
02e7 fd0c bra [$0c] 1416 bra([videoModeD]) #36
02e8 c20d st [$0d] 1417 st([nextVideo]) #37
1418
1419 # Back porch "E": after the last line
1420 # - Go back and and enter vertical blank (program page 2)
1421 label('videoE') # Exit visible area
videoE: 02e9 1401 ld $01,y 1422 ld(hi('vBlankStart'),Y) #29 Return to vertical blank interval
02ea e004 jmp y,$04 1423 jmp(Y,'vBlankStart') #30
02eb 00c0 ld $c0 1424 ld(syncBits) #31
1425
1426 # Video mode that blacks out one or more pixel lines from the top of screen.
1427 # This yields some speed, but also frees up screen memory for other purposes.
1428 # Note: Sound output becomes choppier the more pixel lines are skipped
1429 # Note: The vertical blank driver leaves 0x80 behind in [videoSync1]
1430 label('videoF')
videoF: 02ec 0120 ld [$20] 1431 ld([videoSync1]) #29 Completely black pixel line
02ed 8080 adda $80 1432 adda(0x80) #30
02ee d220 st [$20],x 1433 st([videoSync1],X) #31
02ef 011f ld [$1f] 1434 ld([frameX]) #32
02f0 a500 suba [x] 1435 suba([X]) #33 Decrements every two VGA scanlines
02f1 f0f4 beq .videoF#36 1436 beq('.videoF#36') #34
02f2 c21f st [$1f] 1437 st([frameX]) #35
02f3 fcf6 bra nopixels 1438 bra('nopixels') #36
1439 label('.videoF#36')
.videoF#36: 02f4 0001 ld $01 1440 ld('videoA') #36,37 Transfer to visible screen area
02f5 c20d st [$0d] 1441 st([nextVideo]) #37
1442 #
1443 # Alternative for pixel burst: faster application mode
1444 label('nopixels')
nopixels: 02f6 00ff ld $ff 1445 runVcpu(200-38, 'ABCD line 40-520',
02f7 c21e st [$1e]
02f8 1505 ld [$05],y
02f9 e0ff jmp y,$ff
02fa 003c ld $3c
1446 returnTo=0x1ff) #38 Application interpreter (black scanlines)
1447
1448 #-----------------------------------------------------------------------
1449 #
1450 # $0300 ROM page 3: Application interpreter primary page
1451 #
1452 #-----------------------------------------------------------------------
1453
1454 # Enter the timing-aware application interpreter (aka virtual CPU, vCPU)
1455 #
1456 # This routine will execute as many as possible instructions in the
1457 # allotted time. When time runs out, it synchronizes such that the total
1458 # duration matches the caller's request. Durations are counted in `ticks',
1459 # which are multiples of 2 clock cycles.
1460 #
1461 # Synopsis: Use the runVcpu() macro as entry point
1462
1463 # We let 'ENTER' begin one word before the page boundary, for a bit extra
1464 # precious space in the packed interpreter code page. Although ENTER's
1465 # first instruction is bra() which normally doesn't cross page boundaries,
1466 # in this case it will still jump into the right space, because branches
1467 # from $xxFF land in the next page anyway.
1468 while pc()&255 < 255:
02fb 0200 nop 1469 nop()
02fc 0200 nop
02fd 0200 nop
02fe 0200 nop
1470 label('ENTER')
ENTER: 02ff fc03 bra .next2 1471 bra('.next2') #0 Enter at '.next2' (so no startup overhead)
1472 # --- Page boundary ---
1473 align(0x100,size=0x100)
1474 label('NEXTY') # Alternative for REENTER
NEXTY: 0300 1517 ld [$17],y 1475 ld([vPC+1],Y) #1
1476
1477 # Fetch next instruction and execute it, but only if there are sufficient
1478 # ticks left for the slowest instruction.
1479 label('NEXT')
NEXT: 0301 8115 adda [$15] 1480 adda([vTicks]) #0 Track elapsed ticks (actually counting down: AC<0)
0302 e80b blt EXIT 1481 blt('EXIT') #1 Escape near time out
1482 label('.next2')
.next2: 0303 c215 st [$15] 1483 st([vTicks]) #2
0304 0116 ld [$16] 1484 ld([vPC]) #3 Advance vPC
0305 8002 adda $02 1485 adda(2) #4
0306 d216 st [$16],x 1486 st([vPC],X) #5
0307 0d00 ld [y,x] 1487 ld([Y,X]) #6 Fetch opcode (actually a branch target)
0308 de00 st [y,x++] 1488 st([Y,Xpp]) #7 Just X++
0309 fe00 bra ac 1489 bra(AC) #8 Dispatch
030a 0d00 ld [y,x] 1490 ld([Y,X]) #9 Prefetch operand
1491
1492 # Resync with video driver and transfer control
1493 label('EXIT')
EXIT: 030b 800e adda $0e 1494 adda(maxTicks) #3
1495 label('RESYNC')
RESYNC: 030c e40c bgt RESYNC 1496 bgt(pc()&255) #4 Resync
030d a001 suba $01 1497 suba(1) #5
030e 1401 ld $01,y 1498 ld(hi('vBlankStart'),Y) #6
030f e11e jmp y,[$1e] 1499 jmp(Y,[vReturn]) #7 To video driver
0310 0000 ld $00 1500 ld(0) #8 AC should be 0 already. Still..
1501 assert vCPU_overhead == 9
1502
1503 # Instruction LDWI: Load immediate word constant (vAC=D), 20 cycles
1504 label('LDWI')
LDWI: 0311 c218 st [$18] 1505 st([vAC]) #10
0312 de00 st [y,x++] 1506 st([Y,Xpp]) #11 Just X++
0313 0d00 ld [y,x] 1507 ld([Y,X]) #12 Fetch second operand
0314 c219 st [$19] 1508 st([vAC+1]) #13
0315 0116 ld [$16] 1509 ld([vPC]) #14 Advance vPC one more
0316 8001 adda $01 1510 adda(1) #15
0317 c216 st [$16] 1511 st([vPC]) #16
0318 00f6 ld $f6 1512 ld(-20/2) #17
0319 fc01 bra NEXT 1513 bra('NEXT') #18
1514 #dummy() #19 Overlap
1515 #
1516 # Instruction LD: Load byte from zero page (vAC=[D]), 22 cycles
1517 label('LD')
LD: 031a 1200 ld ac,x 1518 ld(AC,X) #10,19
031b 0500 ld [x] 1519 ld([X]) #11
031c 1404 ld $04,y 1520 ld(hi('ld#15'),Y) #12
031d e013 jmp y,$13 1521 jmp(Y,'ld#15') #13
031e c218 st [$18] 1522 st([vAC]) #14
1523
1524 # Instruction CMPHS: Adjust high byte for signed compare (vACH=XXX), 28 cycles
1525 label('CMPHS_v5')
CMPHS_v5: 031f 140b ld $0b,y 1526 ld(hi('cmphs#13'),Y) #10
0320 e0bc jmp y,$bc 1527 jmp(Y,'cmphs#13') #11
1528 #ld(AC,X) #12 Overlap
1529 #
1530 # Instruction LDW: Load word from zero page (vAC=[D]+256*[D+1]), 20 cycles
1531 label('LDW')
LDW: 0321 1200 ld ac,x 1532 ld(AC,X) #10,12
0322 8001 adda $01 1533 adda(1) #11
0323 c21d st [$1d] 1534 st([vTmp]) #12 Address of high byte
0324 0500 ld [x] 1535 ld([X]) #13
0325 c218 st [$18] 1536 st([vAC]) #14
0326 111d ld [$1d],x 1537 ld([vTmp],X) #15
0327 0500 ld [x] 1538 ld([X]) #16
0328 c219 st [$19] 1539 st([vAC+1]) #17
0329 fc01 bra NEXT 1540 bra('NEXT') #18
032a 00f6 ld $f6 1541 ld(-20/2) #19
1542
1543 # Instruction STW: Store word in zero page ([D],[D+1]=vAC&255,vAC>>8), 20 cycles
1544 label('STW')
STW: 032b 1200 ld ac,x 1545 ld(AC,X) #10,20
032c 8001 adda $01 1546 adda(1) #11
032d c21d st [$1d] 1547 st([vTmp]) #12 Address of high byte
032e 0118 ld [$18] 1548 ld([vAC]) #13
032f c600 st [x] 1549 st([X]) #14
0330 111d ld [$1d],x 1550 ld([vTmp],X) #15
0331 0119 ld [$19] 1551 ld([vAC+1]) #16
0332 c600 st [x] 1552 st([X]) #17
0333 fc01 bra NEXT 1553 bra('NEXT') #18
0334 00f6 ld $f6 1554 ld(-20/2) #19
1555
1556 # Instruction BCC: Test AC sign and branch conditionally, 28 cycles
1557 label('BCC')
BCC: 0335 0119 ld [$19] 1558 ld([vAC+1]) #10 First inspect high byte of vAC
0336 ec40 bne .bcc#13 1559 bne('.bcc#13') #11
0337 c21d st [$1d] 1560 st([vTmp]) #12
0338 0118 ld [$18] 1561 ld([vAC]) #13 Additionally inspect low byte of vAC
0339 f043 beq .bcc#16 1562 beq('.bcc#16') #14
033a 0001 ld $01 1563 ld(1) #15
033b c21d st [$1d] 1564 st([vTmp]) #16
033c 0d00 ld [y,x] 1565 ld([Y,X]) #17 Operand is the conditional
1566 label('.bcc#18')
.bcc#18: 033d fe00 bra ac 1567 bra(AC) #18
033e 011d ld [$1d] 1568 ld([vTmp]) #19
1569
1570 # Conditional EQ: Branch if zero (if(vACL==0)vPCL=D)
1571 label('EQ')
EQ: 033f ec45 bne .bcc#22 1572 bne('.bcc#22') #20
1573 label('.bcc#13')
.bcc#13: 0340 f048 beq .bcc#23 1574 beq('.bcc#23') #21,13 AC=0 in EQ, AC!=0 from BCC... Overlap with BCC
0341 0d00 ld [y,x] 1575 ld([Y,X]) #22,14 Overlap with BCC
1576 #
1577 # (continue BCC)
1578 #label('.bcc#13')
1579 #dummy() #13
1580 #dummy() #14
0342 0200 nop 1581 nop() #15
1582 label('.bcc#16')
.bcc#16: 0343 fc3d bra .bcc#18 1583 bra('.bcc#18') #16
0344 0d00 ld [y,x] 1584 ld([Y,X]) #17 Operand is the conditional
1585 label('.bcc#22')
.bcc#22: 0345 0116 ld [$16] 1586 ld([vPC]) #22 False condition
0346 fc4a bra .bcc#25 1587 bra('.bcc#25') #23
0347 8001 adda $01 1588 adda(1) #24
1589 label('.bcc#23')
.bcc#23: 0348 de00 st [y,x++] 1590 st([Y,Xpp]) #23 Just X++ True condition
0349 0d00 ld [y,x] 1591 ld([Y,X]) #24
1592 label('.bcc#25')
.bcc#25: 034a c216 st [$16] 1593 st([vPC]) #25
034b fc01 bra NEXT 1594 bra('NEXT') #26
034c 00f2 ld $f2 1595 ld(-28/2) #27
1596
1597 # Conditional GT: Branch if positive (if(vACL>0)vPCL=D)
1598 label('GT')
GT: 034d f845 ble .bcc#22 1599 ble('.bcc#22') #20
034e e448 bgt .bcc#23 1600 bgt('.bcc#23') #21
034f 0d00 ld [y,x] 1601 ld([Y,X]) #22
1602
1603 # Conditional LT: Branch if negative (if(vACL<0)vPCL=D)
1604 label('LT')
LT: 0350 f445 bge .bcc#22 1605 bge('.bcc#22') #20
0351 e848 blt .bcc#23 1606 blt('.bcc#23') #21
0352 0d00 ld [y,x] 1607 ld([Y,X]) #22
1608
1609 # Conditional GE: Branch if positive or zero (if(vACL>=0)vPCL=D)
1610 label('GE')
GE: 0353 e845 blt .bcc#22 1611 blt('.bcc#22') #20
0354 f448 bge .bcc#23 1612 bge('.bcc#23') #21
0355 0d00 ld [y,x] 1613 ld([Y,X]) #22
1614
1615 # Conditional LE: Branch if negative or zero (if(vACL<=0)vPCL=D)
1616 label('LE')
LE: 0356 e445 bgt .bcc#22 1617 bgt('.bcc#22') #20
0357 f848 ble .bcc#23 1618 ble('.bcc#23') #21
0358 0d00 ld [y,x] 1619 ld([Y,X]) #22
1620
1621 # Instruction LDI: Load immediate small positive constant (vAC=D), 16 cycles
1622 label('LDI')
LDI: 0359 c218 st [$18] 1623 st([vAC]) #10
035a 0000 ld $00 1624 ld(0) #11
035b c219 st [$19] 1625 st([vAC+1]) #12
035c fc00 bra NEXTY 1626 bra('NEXTY') #13
035d 00f8 ld $f8 1627 ld(-16/2) #14
1628
1629 # Instruction ST: Store byte in zero page ([D]=vAC&255), 16 cycles
1630 label('ST')
ST: 035e 1200 ld ac,x 1631 ld(AC,X) #10,15
035f 0118 ld [$18] 1632 ld([vAC]) #11
0360 c600 st [x] 1633 st([X]) #12
0361 fc00 bra NEXTY 1634 bra('NEXTY') #13
0362 00f8 ld $f8 1635 ld(-16/2) #14
1636
1637 # Instruction POP: Pop address from stack (vLR,vSP==[vSP]+256*[vSP+1],vSP+2), 26 cycles
1638 label('POP')
POP: 0363 111c ld [$1c],x 1639 ld([vSP],X) #10,15
0364 0500 ld [x] 1640 ld([X]) #11
0365 c21a st [$1a] 1641 st([vLR]) #12
0366 011c ld [$1c] 1642 ld([vSP]) #13
0367 9001 adda $01,x 1643 adda(1,X) #14
0368 0500 ld [x] 1644 ld([X]) #15
0369 c21b st [$1b] 1645 st([vLR+1]) #16
036a 011c ld [$1c] 1646 ld([vSP]) #17
036b 8002 adda $02 1647 adda(2) #18
036c c21c st [$1c] 1648 st([vSP]) #19
1649 label('.pop#20')
.pop#20: 036d 0116 ld [$16] 1650 ld([vPC]) #20
036e a001 suba $01 1651 suba(1) #21
036f c216 st [$16] 1652 st([vPC]) #22
0370 fc00 bra NEXTY 1653 bra('NEXTY') #23
0371 00f3 ld $f3 1654 ld(-26/2) #24
1655
1656 # Conditional NE: Branch if not zero (if(vACL!=0)vPCL=D)
1657 label('NE')
NE: 0372 f045 beq .bcc#22 1658 beq('.bcc#22') #20,25
0373 ec48 bne .bcc#23 1659 bne('.bcc#23') #21
0374 0d00 ld [y,x] 1660 ld([Y,X]) #22
1661
1662 # Instruction PUSH: Push vLR on stack ([vSP-2],v[vSP-1],vSP=vLR&255,vLR>>8,vLR-2), 26 cycles
1663 label('PUSH')
PUSH: 0375 011c ld [$1c] 1664 ld([vSP]) #10
0376 b001 suba $01,x 1665 suba(1,X) #11
0377 011b ld [$1b] 1666 ld([vLR+1]) #12
0378 c600 st [x] 1667 st([X]) #13
0379 011c ld [$1c] 1668 ld([vSP]) #14
037a a002 suba $02 1669 suba(2) #15
037b d21c st [$1c],x 1670 st([vSP],X) #16
037c 011a ld [$1a] 1671 ld([vLR]) #17
037d fc6d bra .pop#20 1672 bra('.pop#20') #18
037e c600 st [x] 1673 st([X]) #19
1674
1675 # Instruction LUP: ROM lookup (vAC=ROM[vAC+D]), 26 cycles
1676 label('LUP')
LUP: 037f 1519 ld [$19],y 1677 ld([vAC+1],Y) #10
0380 e0fb jmp y,$fb 1678 jmp(Y,251) #11 Trampoline offset
0381 8118 adda [$18] 1679 adda([vAC]) #12
1680
1681 # Instruction ANDI: Logical-AND with small constant (vAC&=D), 22 cycles
1682 label('ANDI')
ANDI: 0382 1404 ld $04,y 1683 ld(hi('andi#13'),Y) #10
0383 e011 jmp y,$11 1684 jmp(Y,'andi#13') #11
0384 2118 anda [$18] 1685 anda([vAC]) #12
1686
1687 # Instruction CALLI: Goto immediate address and remember vPC (vLR,vPC=vPC+3,$HHLL-2), 28 cycles
1688 label('CALLI_v5')
CALLI_v5: 0385 140b ld $0b,y 1689 ld(hi('calli#13'),Y) #10
0386 e0b0 jmp y,$b0 1690 jmp(Y,'calli#13') #11
0387 0116 ld [$16] 1691 ld([vPC]) #12
1692
1693 # Instruction ORI: Logical-OR with small constant (vAC|=D), 14 cycles
1694 label('ORI')
ORI: 0388 4118 ora [$18] 1695 ora([vAC]) #10
0389 c218 st [$18] 1696 st([vAC]) #11
038a fc01 bra NEXT 1697 bra('NEXT') #12
038b 00f9 ld $f9 1698 ld(-14/2) #13
1699
1700 # Instruction XORI: Logical-XOR with small constant (vAC^=D), 14 cycles
1701 label('XORI')
XORI: 038c 6118 xora [$18] 1702 xora([vAC]) #10
038d c218 st [$18] 1703 st([vAC]) #11
038e fc01 bra NEXT 1704 bra('NEXT') #12
038f 00f9 ld $f9 1705 ld(-14/2) #13
1706
1707 # Instruction BRA: Branch unconditionally (vPC=(vPC&0xff00)+D), 14 cycles
1708 label('BRA')
BRA: 0390 c216 st [$16] 1709 st([vPC]) #10
0391 fc00 bra NEXTY 1710 bra('NEXTY') #11
0392 00f9 ld $f9 1711 ld(-14/2) #12
1712
1713 # Instruction INC: Increment zero page byte ([D]++), 20 cycles
1714 label('INC')
INC: 0393 1200 ld ac,x 1715 ld(AC,X) #10,13
0394 1404 ld $04,y 1716 ld(hi('inc#14'),Y) #11
0395 e0e4 jmp y,$e4 1717 jmp(Y,'inc#14') #12
0396 0001 ld $01 1718 ld(1) #13
1719
1720 # Instruction CMPHU: Adjust high byte for unsigned compare (vACH=XXX), 28 cycles
1721 label('CMPHU_v5')
CMPHU_v5: 0397 140b ld $0b,y 1722 ld(hi('cmphu#13'),Y) #10
0398 e0c8 jmp y,$c8 1723 jmp(Y,'cmphu#13') #11
1724 #ld(AC,X) #12 Overlap
1725 #
1726 # Instruction ADDW: Word addition with zero page (vAC+=[D]+256*[D+1]), 28 cycles
1727 label('ADDW')
1728 # The non-carry paths could be 26 cycles at the expense of (much) more code.
1729 # But a smaller size is better so more instructions fit in this code page.
1730 # 28 cycles is still 4.5 usec. The 6502 equivalent takes 20 cycles or 20 usec.
ADDW: 0399 1200 ld ac,x 1731 ld(AC,X) #10,12 Address of low byte to be added
039a 8001 adda $01 1732 adda(1) #11
039b c21d st [$1d] 1733 st([vTmp]) #12 Address of high byte to be added
039c 0118 ld [$18] 1734 ld([vAC]) #13 Add the low bytes
039d 8500 adda [x] 1735 adda([X]) #14
039e c218 st [$18] 1736 st([vAC]) #15 Store low result
039f e8a3 blt .addw#18 1737 bmi('.addw#18') #16 Now figure out if there was a carry
03a0 a500 suba [x] 1738 suba([X]) #17 Gets back the initial value of vAC
03a1 fca5 bra .addw#20 1739 bra('.addw#20') #18
03a2 4500 ora [x] 1740 ora([X]) #19 Carry in bit 7
1741 label('.addw#18')
.addw#18: 03a3 2500 anda [x] 1742 anda([X]) #18 Carry in bit 7
03a4 0200 nop 1743 nop() #19
1744 label('.addw#20')
.addw#20: 03a5 3080 anda $80,x 1745 anda(0x80,X) #20 Move carry to bit 0
03a6 0500 ld [x] 1746 ld([X]) #21
03a7 8119 adda [$19] 1747 adda([vAC+1]) #22 Add the high bytes with carry
03a8 111d ld [$1d],x 1748 ld([vTmp],X) #23
03a9 8500 adda [x] 1749 adda([X]) #24
03aa c219 st [$19] 1750 st([vAC+1]) #25 Store high result
03ab fc01 bra NEXT 1751 bra('NEXT') #26
03ac 00f2 ld $f2 1752 ld(-28/2) #27
1753
1754 # Instruction PEEK: Read byte from memory (vAC=[vAC]), 26 cycles
1755 label('PEEK')
PEEK: 03ad 1404 ld $04,y 1756 ld(hi('peek'),Y) #10
03ae e062 jmp y,$62 1757 jmp(Y,'peek') #11
1758 #ld([vPC]) #12 Overlap
1759 #
1760 # Instruction SYS: Native call, <=256 cycles (<=128 ticks, in reality less)
1761 #
1762 # The 'SYS' vCPU instruction first checks the number of desired ticks given by
1763 # the operand. As long as there are insufficient ticks available in the current
1764 # time slice, the instruction will be retried. This will effectively wait for
1765 # the next scan line if the current slice is almost out of time. Then a jump to
1766 # native code is made. This code can do whatever it wants, but it must return
1767 # to the 'REENTER' label when done. When returning, AC must hold (the negative
1768 # of) the actual consumed number of whole ticks for the entire virtual
1769 # instruction cycle (from NEXT to NEXT). This duration may not exceed the prior
1770 # declared duration in the operand + 28 (or maxTicks). The operand specifies the
1771 # (negative) of the maximum number of *extra* ticks that the native call will
1772 # need. The GCL compiler automatically makes this calculation from gross number
1773 # of cycles to excess number of ticks.
1774 # SYS functions can modify vPC to implement repetition. For example to split
1775 # up work into multiple chucks.
1776 label('.sys#13')
.sys#13: 03af 0116 ld [$16] 1777 ld([vPC]) #13,12 Retry until sufficient time
03b0 a002 suba $02 1778 suba(2) #14
03b1 c216 st [$16] 1779 st([vPC]) #15
03b2 fccb bra REENTER 1780 bra('REENTER') #16
03b3 00f6 ld $f6 1781 ld(-20/2) #17
1782 label('SYS')
SYS: 03b4 8115 adda [$15] 1783 adda([vTicks]) #10
03b5 e8af blt .sys#13 1784 blt('.sys#13') #11
03b6 1523 ld [$23],y 1785 ld([sysFn+1],Y) #12
03b7 e122 jmp y,[$22] 1786 jmp(Y,[sysFn]) #13
1787 #dummy() #14 Overlap
1788 #
1789 # Instruction SUBW: Word subtract with zero page (AC-=[D]+256*[D+1]), 28 cycles
1790 # All cases can be done in 26 cycles, but the code will become much larger
1791 label('SUBW')
SUBW: 03b8 1200 ld ac,x 1792 ld(AC,X) #10,14 Address of low byte to be subtracted
03b9 8001 adda $01 1793 adda(1) #11
03ba c21d st [$1d] 1794 st([vTmp]) #12 Address of high byte to be subtracted
03bb 0118 ld [$18] 1795 ld([vAC]) #13
03bc e8c1 blt .subw#16 1796 bmi('.subw#16') #14
03bd a500 suba [x] 1797 suba([X]) #15
03be c218 st [$18] 1798 st([vAC]) #16 Store low result
03bf fcc4 bra .subw#19 1799 bra('.subw#19') #17
03c0 4500 ora [x] 1800 ora([X]) #18 Carry in bit 7
1801 label('.subw#16')
.subw#16: 03c1 c218 st [$18] 1802 st([vAC]) #16 Store low result
03c2 2500 anda [x] 1803 anda([X]) #17 Carry in bit 7
03c3 0200 nop 1804 nop() #18
1805 label('.subw#19')
.subw#19: 03c4 3080 anda $80,x 1806 anda(0x80,X) #19 Move carry to bit 0
03c5 0119 ld [$19] 1807 ld([vAC+1]) #20
03c6 a500 suba [x] 1808 suba([X]) #21
03c7 111d ld [$1d],x 1809 ld([vTmp],X) #22
03c8 a500 suba [x] 1810 suba([X]) #23
03c9 c219 st [$19] 1811 st([vAC+1]) #24
1812 label('REENTER_28')
REENTER_28: 03ca 00f2 ld $f2 1813 ld(-28/2) #25
1814 label('REENTER')
REENTER: 03cb fc01 bra NEXT 1815 bra('NEXT') #26 Return from SYS calls
03cc 1517 ld [$17],y 1816 ld([vPC+1],Y) #27
1817
1818 # Instruction DEF: Define data or code (vAC,vPC=vPC+2,(vPC&0xff00)+D), 24 cycles
1819 label('DEF')
DEF: 03cd 1404 ld $04,y 1820 ld(hi('def#13'),Y) #10
03ce e007 jmp y,$07 1821 jmp(Y,'def#13') #11
1822 #st([vTmp]) #12 Overlap
1823 #
1824 # Instruction CALL: Goto address and remember vPC (vLR,vPC=vPC+2,[D]+256*[D+1]-2), 26 cycles
1825 label('CALL')
CALL: 03cf c21d st [$1d] 1826 st([vTmp]) #10,12
03d0 0116 ld [$16] 1827 ld([vPC]) #11
03d1 8002 adda $02 1828 adda(2) #12 Point to instruction after CALL
03d2 c21a st [$1a] 1829 st([vLR]) #13
03d3 0117 ld [$17] 1830 ld([vPC+1]) #14
03d4 c21b st [$1b] 1831 st([vLR+1]) #15
03d5 111d ld [$1d],x 1832 ld([vTmp],X) #16
03d6 0500 ld [x] 1833 ld([X]) #17
03d7 a002 suba $02 1834 suba(2) #18 Because NEXT will add 2
03d8 c216 st [$16] 1835 st([vPC]) #19
03d9 011d ld [$1d] 1836 ld([vTmp]) #20
03da 9001 adda $01,x 1837 adda(1,X) #21
03db 0500 ld [x] 1838 ld([X]) #22
03dc d617 st [$17],y 1839 st([vPC+1],Y) #23
03dd fc01 bra NEXT 1840 bra('NEXT') #24
03de 00f3 ld $f3 1841 ld(-26/2) #25
1842
1843 # Instruction ALLOC: Create or destroy stack frame (vSP+=D), 14 cycles
1844 label('ALLOC')
ALLOC: 03df 811c adda [$1c] 1845 adda([vSP]) #10
03e0 c21c st [$1c] 1846 st([vSP]) #11
03e1 fc01 bra NEXT 1847 bra('NEXT') #12
03e2 00f9 ld $f9 1848 ld(-14/2) #13
1849
1850 # The instructions below are all implemented in the second code page. Jumping
1851 # back and forth makes each 6 cycles slower, but it also saves space in the
1852 # primary page for the instructions above. Most of them are in fact not very
1853 # critical, as evidenced by the fact that they weren't needed for the first
1854 # Gigatron applications (Snake, Racer, Mandelbrot, Loader). By providing them
1855 # in this way, at least they don't need to be implemented as a SYS extension.
1856
1857 # Instruction ADDI: Add small positive constant (vAC+=D), 28 cycles
1858 label('ADDI')
ADDI: 03e3 1404 ld $04,y 1859 ld(hi('addi'),Y) #10
03e4 e018 jmp y,$18 1860 jmp(Y,'addi') #11
03e5 c21d st [$1d] 1861 st([vTmp]) #12
1862
1863 # Instruction SUBI: Subtract small positive constant (vAC+=D), 28 cycles
1864 label('SUBI')
SUBI: 03e6 1404 ld $04,y 1865 ld(hi('subi'),Y) #10
03e7 e026 jmp y,$26 1866 jmp(Y,'subi') #11
03e8 c21d st [$1d] 1867 st([vTmp]) #12
1868
1869 # Instruction LSLW: Logical shift left (vAC<<=1), 28 cycles
1870 # Useful, because ADDW can't add vAC to itself. Also more compact.
1871 label('LSLW')
LSLW: 03e9 1404 ld $04,y 1872 ld(hi('lslw'),Y) #10
03ea e035 jmp y,$35 1873 jmp(Y,'lslw') #11
03eb 0118 ld [$18] 1874 ld([vAC]) #12
1875
1876 # Instruction STLW: Store word in stack frame ([vSP+D],[vSP+D+1]=vAC&255,vAC>>8), 26 cycles
1877 label('STLW')
STLW: 03ec 1404 ld $04,y 1878 ld(hi('stlw'),Y) #10
03ed e041 jmp y,$41 1879 jmp(Y,'stlw') #11
1880 #dummy() #12 Overlap
1881 #
1882 # Instruction LDLW: Load word from stack frame (vAC=[vSP+D]+256*[vSP+D+1]), 26 cycles
1883 label('LDLW')
LDLW: 03ee 1404 ld $04,y 1884 ld(hi('ldlw'),Y) #10,12
03ef e04c jmp y,$4c 1885 jmp(Y,'ldlw') #11
1886 #dummy() #12 Overlap
1887 #
1888 # Instruction POKE: Write byte in memory ([[D+1],[D]]=vAC&255), 28 cycles
1889 label('POKE')
POKE: 03f0 1404 ld $04,y 1890 ld(hi('poke'),Y) #10,12
03f1 e057 jmp y,$57 1891 jmp(Y,'poke') #11
03f2 c21d st [$1d] 1892 st([vTmp]) #12
1893
1894 # Instruction DOKE: Write word in memory ([[D+1],[D]],[[D+1],[D]+1]=vAC&255,vAC>>8), 28 cycles
1895 label('DOKE')
DOKE: 03f3 1404 ld $04,y 1896 ld(hi('doke'),Y) #10
03f4 e06d jmp y,$6d 1897 jmp(Y,'doke') #11
03f5 c21d st [$1d] 1898 st([vTmp]) #12
1899
1900 # Instruction DEEK: Read word from memory (vAC=[vAC]+256*[vAC+1]), 28 cycles
1901 label('DEEK')
DEEK: 03f6 1404 ld $04,y 1902 ld(hi('deek'),Y) #10
03f7 e07a jmp y,$7a 1903 jmp(Y,'deek') #11
1904 #dummy() #12 Overlap
1905 #
1906 # Instruction ANDW: Word logical-AND with zero page (vAC&=[D]+256*[D+1]), 28 cycles
1907 label('ANDW')
ANDW: 03f8 1404 ld $04,y 1908 ld(hi('andw'),Y) #10,12
03f9 e086 jmp y,$86 1909 jmp(Y,'andw') #11
1910 #dummy() #12 Overlap
1911 #
1912 # Instruction ORW: Word logical-OR with zero page (vAC|=[D]+256*[D+1]), 28 cycles
1913 label('ORW')
ORW: 03fa 1404 ld $04,y 1914 ld(hi('orw'),Y) #10,12
03fb e091 jmp y,$91 1915 jmp(Y,'orw') #11
1916 #dummy() #12 Overlap
1917 #
1918 # Instruction XORW: Word logical-XOR with zero page (vAC^=[D]+256*[D+1]), 26 cycles
1919 label('XORW')
XORW: 03fc 1404 ld $04,y 1920 ld(hi('xorw'),Y) #10,12
03fd e09c jmp y,$9c 1921 jmp(Y,'xorw') #11
03fe c21d st [$1d] 1922 st([vTmp]) #12
1923 # We keep XORW 2 cycles faster than ANDW/ORW, because that
1924 # can be useful for comparing numbers for equality a tiny
1925 # bit faster than with SUBW
1926
1927 # Instruction RET: Function return (vPC=vLR-2), 16 cycles
1928 label('RET')
RET: 03ff 011a ld [$1a] 1929 ld([vLR]) #10
1930 assert pc()&255 == 0
1931
1932 #-----------------------------------------------------------------------
1933 #
1934 # $0400 ROM page 4: Application interpreter extension
1935 #
1936 #-----------------------------------------------------------------------
1937 align(0x100, size=0x100)
1938
1939 # (Continue RET)
0400 a002 suba $02 1940 suba(2) #11
0401 c216 st [$16] 1941 st([vPC]) #12
0402 011b ld [$1b] 1942 ld([vLR+1]) #13
0403 c217 st [$17] 1943 st([vPC+1]) #14
0404 1403 ld $03,y 1944 ld(hi('REENTER'),Y) #15
0405 e0cb jmp y,$cb 1945 jmp(Y,'REENTER') #16
0406 00f6 ld $f6 1946 ld(-20/2) #17
1947
1948 # DEF implementation
1949 label('def#13')
def#13: 0407 0116 ld [$16] 1950 ld([vPC]) #13
0408 8002 adda $02 1951 adda(2) #14
0409 c218 st [$18] 1952 st([vAC]) #15
040a 0117 ld [$17] 1953 ld([vPC+1]) #16
040b c219 st [$19] 1954 st([vAC+1]) #17
040c 011d ld [$1d] 1955 ld([vTmp]) #18
040d c216 st [$16] 1956 st([vPC]) #19
040e 1403 ld $03,y 1957 ld(hi('NEXTY'),Y) #20
040f e000 jmp y,$00 1958 jmp(Y,'NEXTY') #21
0410 00f4 ld $f4 1959 ld(-24/2) #22
1960
1961 # Clear vACH (continuation of ANDI and LD instructions)
1962 label('andi#13')
andi#13: 0411 0200 nop 1963 nop() #13
0412 c218 st [$18] 1964 st([vAC]) #14
1965 #
1966 label('ld#15')
ld#15: 0413 0000 ld $00 1967 ld(0) #15 Clear high byte
0414 c219 st [$19] 1968 st([vAC+1]) #16
0415 1403 ld $03,y 1969 ld(hi('REENTER'),Y) #17
0416 e0cb jmp y,$cb 1970 jmp(Y,'REENTER') #18
0417 00f5 ld $f5 1971 ld(-22/2) #19
1972
1973 # ADDI implementation
1974 label('addi')
addi: 0418 8118 adda [$18] 1975 adda([vAC]) #13
0419 c218 st [$18] 1976 st([vAC]) #14 Store low result
041a e81e blt .addi#17 1977 bmi('.addi#17') #15 Now figure out if there was a carry
041b a11d suba [$1d] 1978 suba([vTmp]) #16 Gets back the initial value of vAC
041c fc20 bra .addi#19 1979 bra('.addi#19') #17
041d 411d ora [$1d] 1980 ora([vTmp]) #18 Carry in bit 7
1981 label('.addi#17')
.addi#17: 041e 211d anda [$1d] 1982 anda([vTmp]) #17 Carry in bit 7
041f 0200 nop 1983 nop() #18
1984 label('.addi#19')
.addi#19: 0420 3080 anda $80,x 1985 anda(0x80,X) #19 Move carry to bit 0
0421 0500 ld [x] 1986 ld([X]) #20
0422 8119 adda [$19] 1987 adda([vAC+1]) #21 Add the high bytes with carry
0423 1403 ld $03,y 1988 ld(hi('REENTER_28'),Y) #22
0424 e0ca jmp y,$ca 1989 jmp(Y,'REENTER_28') #23
0425 c219 st [$19] 1990 st([vAC+1]) #24 Store high result
1991
1992 # SUBI implementation
1993 label('subi')
subi: 0426 0118 ld [$18] 1994 ld([vAC]) #13
0427 e82c blt .subi#16 1995 bmi('.subi#16') #14
0428 a11d suba [$1d] 1996 suba([vTmp]) #15
0429 c218 st [$18] 1997 st([vAC]) #16 Store low result
042a fc2f bra .subi#19 1998 bra('.subi#19') #17
042b 411d ora [$1d] 1999 ora([vTmp]) #18 Carry in bit 7
2000 label('.subi#16')
.subi#16: 042c c218 st [$18] 2001 st([vAC]) #16 Store low result
042d 211d anda [$1d] 2002 anda([vTmp]) #17 Carry in bit 7
042e 0200 nop 2003 nop() #18
2004 label('.subi#19')
.subi#19: 042f 3080 anda $80,x 2005 anda(0x80,X) #19 Move carry to bit 0
0430 0119 ld [$19] 2006 ld([vAC+1]) #20
0431 a500 suba [x] 2007 suba([X]) #21
0432 1403 ld $03,y 2008 ld(hi('REENTER_28'),Y) #22
0433 e0ca jmp y,$ca 2009 jmp(Y,'REENTER_28') #23
0434 c219 st [$19] 2010 st([vAC+1]) #24
2011
2012 # LSLW implementation
2013 label('lslw')
lslw: 0435 3080 anda $80,x 2014 anda(128,X) #13
0436 8118 adda [$18] 2015 adda([vAC]) #14
0437 c218 st [$18] 2016 st([vAC]) #15
0438 0500 ld [x] 2017 ld([X]) #16
0439 8119 adda [$19] 2018 adda([vAC+1]) #17
043a 8119 adda [$19] 2019 adda([vAC+1]) #18
043b c219 st [$19] 2020 st([vAC+1]) #19
043c 0116 ld [$16] 2021 ld([vPC]) #20
043d a001 suba $01 2022 suba(1) #21
043e 1403 ld $03,y 2023 ld(hi('REENTER_28'),Y) #22
043f e0ca jmp y,$ca 2024 jmp(Y,'REENTER_28') #23
0440 c216 st [$16] 2025 st([vPC]) #24
2026
2027 # STLW implementation
2028 label('stlw')
stlw: 0441 811c adda [$1c] 2029 adda([vSP]) #13
0442 c21d st [$1d] 2030 st([vTmp]) #14
0443 9001 adda $01,x 2031 adda(1,X) #15
0444 0119 ld [$19] 2032 ld([vAC+1]) #16
0445 c600 st [x] 2033 st([X]) #17
0446 111d ld [$1d],x 2034 ld([vTmp],X) #18
0447 0118 ld [$18] 2035 ld([vAC]) #19
0448 c600 st [x] 2036 st([X]) #20
0449 1403 ld $03,y 2037 ld(hi('REENTER'),Y) #21
044a e0cb jmp y,$cb 2038 jmp(Y,'REENTER') #22
044b 00f3 ld $f3 2039 ld(-26/2) #23
2040
2041 # LDLW implementation
2042 label('ldlw')
ldlw: 044c 811c adda [$1c] 2043 adda([vSP]) #13
044d c21d st [$1d] 2044 st([vTmp]) #14
044e 9001 adda $01,x 2045 adda(1,X) #15
044f 0500 ld [x] 2046 ld([X]) #16
0450 c219 st [$19] 2047 st([vAC+1]) #17
0451 111d ld [$1d],x 2048 ld([vTmp],X) #18
0452 0500 ld [x] 2049 ld([X]) #19
0453 c218 st [$18] 2050 st([vAC]) #20
0454 1403 ld $03,y 2051 ld(hi('REENTER'),Y) #21
0455 e0cb jmp y,$cb 2052 jmp(Y,'REENTER') #22
0456 00f3 ld $f3 2053 ld(-26/2) #23
2054
2055 # POKE implementation
2056 label('poke')
poke: 0457 9001 adda $01,x 2057 adda(1,X) #13
0458 0500 ld [x] 2058 ld([X]) #14
0459 1600 ld ac,y 2059 ld(AC,Y) #15
045a 111d ld [$1d],x 2060 ld([vTmp],X) #16
045b 0500 ld [x] 2061 ld([X]) #17
045c 1200 ld ac,x 2062 ld(AC,X) #18
045d 0118 ld [$18] 2063 ld([vAC]) #19
045e ce00 st [y,x] 2064 st([Y,X]) #20
045f 1403 ld $03,y 2065 ld(hi('REENTER'),Y) #21
0460 e0cb jmp y,$cb 2066 jmp(Y,'REENTER') #22
0461 00f3 ld $f3 2067 ld(-26/2) #23
2068
2069 # PEEK implementation
2070 label('peek')
peek: 0462 a001 suba $01 2071 suba(1) #13
0463 c216 st [$16] 2072 st([vPC]) #14
0464 1118 ld [$18],x 2073 ld([vAC],X) #15
0465 1519 ld [$19],y 2074 ld([vAC+1],Y) #16
0466 0d00 ld [y,x] 2075 ld([Y,X]) #17
0467 c218 st [$18] 2076 st([vAC]) #18
2077 label('lupReturn#19') #Nice coincidence that lupReturn can be here
lupReturn#19: 0468 0000 ld $00 2078 ld(0) #19
0469 c219 st [$19] 2079 st([vAC+1]) #20
046a 1403 ld $03,y 2080 ld(hi('REENTER'),Y) #21
046b e0cb jmp y,$cb 2081 jmp(Y,'REENTER') #22
046c 00f3 ld $f3 2082 ld(-26/2) #23
2083
2084 # DOKE implementation
2085 label('doke')
doke: 046d 9001 adda $01,x 2086 adda(1,X) #13
046e 0500 ld [x] 2087 ld([X]) #14
046f 1600 ld ac,y 2088 ld(AC,Y) #15
0470 111d ld [$1d],x 2089 ld([vTmp],X) #16
0471 0500 ld [x] 2090 ld([X]) #17
0472 1200 ld ac,x 2091 ld(AC,X) #18
0473 0118 ld [$18] 2092 ld([vAC]) #19
0474 de00 st [y,x++] 2093 st([Y,Xpp]) #20
0475 0119 ld [$19] 2094 ld([vAC+1]) #21
0476 ce00 st [y,x] 2095 st([Y,X]) #22 Incompatible with REENTER_28
0477 1403 ld $03,y 2096 ld(hi('REENTER'),Y) #23
0478 e0cb jmp y,$cb 2097 jmp(Y,'REENTER') #24
0479 00f2 ld $f2 2098 ld(-28/2) #25
2099
2100 # DEEK implementation
2101 label('deek')
deek: 047a 0116 ld [$16] 2102 ld([vPC]) #13
047b a001 suba $01 2103 suba(1) #14
047c c216 st [$16] 2104 st([vPC]) #15
047d 1118 ld [$18],x 2105 ld([vAC],X) #16
047e 1519 ld [$19],y 2106 ld([vAC+1],Y) #17
047f 0d00 ld [y,x] 2107 ld([Y,X]) #18
0480 de00 st [y,x++] 2108 st([Y,Xpp]) #19 Just X++
0481 c218 st [$18] 2109 st([vAC]) #20
0482 0d00 ld [y,x] 2110 ld([Y,X]) #21
0483 1403 ld $03,y 2111 ld(hi('REENTER_28'),Y) #22
0484 e0ca jmp y,$ca 2112 jmp(Y,'REENTER_28') #23
0485 c219 st [$19] 2113 st([vAC+1]) #24
2114
2115 # ANDW implementation
2116 label('andw')
andw: 0486 c21d st [$1d] 2117 st([vTmp]) #13
0487 9001 adda $01,x 2118 adda(1,X) #14
0488 0500 ld [x] 2119 ld([X]) #15
0489 2119 anda [$19] 2120 anda([vAC+1]) #16
048a c219 st [$19] 2121 st([vAC+1]) #17
048b 111d ld [$1d],x 2122 ld([vTmp],X) #18
048c 0500 ld [x] 2123 ld([X]) #19
048d 2118 anda [$18] 2124 anda([vAC]) #20
048e c218 st [$18] 2125 st([vAC]) #21
048f 1403 ld $03,y 2126 ld(hi('REENTER_28'),Y) #22
0490 e0ca jmp y,$ca 2127 jmp(Y,'REENTER_28') #23
2128 #dummy() #24 Overlap
2129 #
2130 # ORW implementation
2131 label('orw')
orw: 0491 c21d st [$1d] 2132 st([vTmp]) #13,24
0492 9001 adda $01,x 2133 adda(1,X) #14
0493 0500 ld [x] 2134 ld([X]) #15
0494 4119 ora [$19] 2135 ora([vAC+1]) #16
0495 c219 st [$19] 2136 st([vAC+1]) #17
0496 111d ld [$1d],x 2137 ld([vTmp],X) #18
0497 0500 ld [x] 2138 ld([X]) #19
0498 4118 ora [$18] 2139 ora([vAC]) #20
0499 c218 st [$18] 2140 st([vAC]) #21
049a 1403 ld $03,y 2141 ld(hi('REENTER_28'),Y) #22
049b e0ca jmp y,$ca 2142 jmp(Y,'REENTER_28') #23
2143 #dummy() #24 Overlap
2144 #
2145 # XORW implementation
2146 label('xorw')
xorw: 049c 9001 adda $01,x 2147 adda(1,X) #13,24
049d 0500 ld [x] 2148 ld([X]) #14
049e 6119 xora [$19] 2149 xora([vAC+1]) #15
049f c219 st [$19] 2150 st([vAC+1]) #16
04a0 111d ld [$1d],x 2151 ld([vTmp],X) #17
04a1 0500 ld [x] 2152 ld([X]) #18
04a2 6118 xora [$18] 2153 xora([vAC]) #19
04a3 c218 st [$18] 2154 st([vAC]) #20
04a4 1403 ld $03,y 2155 ld(hi('REENTER'),Y) #21
04a5 e0cb jmp y,$cb 2156 jmp(Y,'REENTER') #22
04a6 00f3 ld $f3 2157 ld(-26/2) #23
2158
2159 #-----------------------------------------------------------------------
2160 #
2161 # vCPU extension functions (for acceleration and compaction) follow below.
2162 #
2163 # The naming convention is: SYS_<CamelCase>[_v<V>]_<N>
2164 #
2165 # With <N> the maximum number of cycles the function will run
2166 # (counted from NEXT to NEXT). This is the same number that must
2167 # be passed to the 'SYS' vCPU instruction as operand, and it will
2168 # appear in the GCL code upon use.
2169 #
2170 # If a SYS extension got introduced after ROM v1, the version number of
2171 # introduction is included in the name. This helps the programmer to be
2172 # reminded to verify the acutal ROM version and fail gracefully on older
2173 # ROMs than required. See also Docs/GT1-files.txt on using [romType].
2174 #
2175 #-----------------------------------------------------------------------
2176
2177 #-----------------------------------------------------------------------
2178 # Extension SYS_Random_34: Update entropy and copy to vAC
2179 #-----------------------------------------------------------------------
2180
2181 # This same algorithm runs automatically once per vertical blank.
2182 # Use this function to get numbers at a higher rate.
2183 #
2184 # Variables:
2185 # vAC
2186
2187 label('SYS_Random_34')
SYS_Random_34:
04a7 010e ld [$0e] 2188 ld([frameCount]) #15
04a8 6107 xora [$07] 2189 xora([entropy+1]) #16
04a9 610f xora [$0f] 2190 xora([serialRaw]) #17
04aa 8106 adda [$06] 2191 adda([entropy+0]) #18
04ab c206 st [$06] 2192 st([entropy+0]) #19
04ac c218 st [$18] 2193 st([vAC+0]) #20
04ad 8108 adda [$08] 2194 adda([entropy+2]) #21
04ae c208 st [$08] 2195 st([entropy+2]) #22
04af e8b2 blt .sysRnd0 2196 bmi('.sysRnd0') #23
04b0 fcb3 bra .sysRnd1 2197 bra('.sysRnd1') #24
04b1 6053 xora $53 2198 xora(64+16+2+1) #25
2199 label('.sysRnd0')
.sysRnd0: 04b2 606c xora $6c 2200 xora(64+32+8+4) #25
2201 label('.sysRnd1')
.sysRnd1: 04b3 8107 adda [$07] 2202 adda([entropy+1]) #26
04b4 c207 st [$07] 2203 st([entropy+1]) #27
04b5 c219 st [$19] 2204 st([vAC+1]) #28
04b6 1403 ld $03,y 2205 ld(hi('REENTER'),Y) #29
04b7 e0cb jmp y,$cb 2206 jmp(Y,'REENTER') #30
04b8 00ef ld $ef 2207 ld(-34/2) #31
2208
2209 label('SYS_LSRW7_30')
SYS_LSRW7_30: 04b9 0118 ld [$18] 2210 ld([vAC]) #15
04ba 3080 anda $80,x 2211 anda(128,X) #16
04bb 0119 ld [$19] 2212 ld([vAC+1]) #17
04bc 8200 adda ac 2213 adda(AC) #18
04bd 4500 ora [x] 2214 ora([X]) #19
04be c218 st [$18] 2215 st([vAC]) #20
04bf 0119 ld [$19] 2216 ld([vAC+1]) #21
04c0 3080 anda $80,x 2217 anda(128,X) #22
04c1 0500 ld [x] 2218 ld([X]) #23
04c2 c219 st [$19] 2219 st([vAC+1]) #24
04c3 1403 ld $03,y 2220 ld(hi('REENTER'),Y) #25
04c4 e0cb jmp y,$cb 2221 jmp(Y,'REENTER') #26
04c5 00f1 ld $f1 2222 ld(-30/2) #27
2223
2224 label('SYS_LSRW8_24')
SYS_LSRW8_24: 04c6 0119 ld [$19] 2225 ld([vAC+1]) #15
04c7 c218 st [$18] 2226 st([vAC]) #16
04c8 0000 ld $00 2227 ld(0) #17
04c9 c219 st [$19] 2228 st([vAC+1]) #18
04ca 1403 ld $03,y 2229 ld(hi('REENTER'),Y) #19
04cb e0cb jmp y,$cb 2230 jmp(Y,'REENTER') #20
04cc 00f4 ld $f4 2231 ld(-24/2) #21
2232
2233 label('SYS_LSLW8_24')
SYS_LSLW8_24: 04cd 0118 ld [$18] 2234 ld([vAC]) #15
04ce c219 st [$19] 2235 st([vAC+1]) #16
04cf 0000 ld $00 2236 ld(0) #17
04d0 c218 st [$18] 2237 st([vAC]) #18
04d1 1403 ld $03,y 2238 ld(hi('REENTER'),Y) #19
04d2 e0cb jmp y,$cb 2239 jmp(Y,'REENTER') #20
04d3 00f4 ld $f4 2240 ld(-24/2) #21
2241
2242 #-----------------------------------------------------------------------
2243 # Extension SYS_Draw4_30
2244 #-----------------------------------------------------------------------
2245
2246 # Draw 4 pixels on screen, horizontally next to each other
2247 #
2248 # Variables:
2249 # sysArgs[0:3] Pixels (in)
2250 # sysArgs[4:5] Position on screen (in)
2251
2252 label('SYS_Draw4_30')
SYS_Draw4_30: 04d4 1128 ld [$28],x 2253 ld([sysArgs+4],X) #15
04d5 1529 ld [$29],y 2254 ld([sysArgs+5],Y) #16
04d6 0124 ld [$24] 2255 ld([sysArgs+0]) #17
04d7 de00 st [y,x++] 2256 st([Y,Xpp]) #18
04d8 0125 ld [$25] 2257 ld([sysArgs+1]) #19
04d9 de00 st [y,x++] 2258 st([Y,Xpp]) #20
04da 0126 ld [$26] 2259 ld([sysArgs+2]) #21
04db de00 st [y,x++] 2260 st([Y,Xpp]) #22
04dc 0127 ld [$27] 2261 ld([sysArgs+3]) #23
04dd de00 st [y,x++] 2262 st([Y,Xpp]) #24
04de 1403 ld $03,y 2263 ld(hi('REENTER'),Y) #25
04df e0cb jmp y,$cb 2264 jmp(Y,'REENTER') #26
04e0 00f1 ld $f1 2265 ld(-30/2) #27
2266
2267 #-----------------------------------------------------------------------
2268 # Extension SYS_VDrawBits_134:
2269 #-----------------------------------------------------------------------
2270
2271 # Draw slice of a character, 8 pixels vertical
2272 #
2273 # Variables:
2274 # sysArgs[0] Color 0 "background" (in)
2275 # sysArgs[1] Color 1 "pen" (in)
2276 # sysArgs[2] 8 bits, highest bit first (in, changed)
2277 # sysArgs[4:5] Position on screen (in)
2278
2279 label('SYS_VDrawBits_134')
SYS_VDrawBits_134:
04e1 1412 ld $12,y 2280 ld(hi('sys_VDrawBits'),Y) #15
04e2 e08f jmp y,$8f 2281 jmp(Y,'sys_VDrawBits') #16
04e3 1128 ld [$28],x 2282 ld([sysArgs+4],X) #17
2283
2284 #-----------------------------------------------------------------------
2285
2286 # INC implementation
2287 label('inc#14')
inc#14: 04e4 8500 adda [x] 2288 adda([X]) #14
04e5 c600 st [x] 2289 st([X]) #15
04e6 1403 ld $03,y 2290 ld(hi('NEXTY'),Y) #16
04e7 e000 jmp y,$00 2291 jmp(Y,'NEXTY') #17
04e8 00f6 ld $f6 2292 ld(-20/2) #18
2293
2294 # Interrupt handler:
2295 # ST $xx -> optionally store vCpuSelect
2296 # ... IRQ payload ...
2297 # either:
2298 # LDWI $400
2299 # LUP 0 -> vRTI and don't switch interpreter (immediate resume)
2300 # or:
2301 # LDWI $400
2302 # LUP $xx -> vRTI and switch interpreter type as stored in [$xx]
04e9 0200 nop 2303 fillers(until=251-11)
04ea 0200 nop
04eb 0200 nop
* 7 times
2304 label('vRTI#15')
vRTI#15: 04f0 0130 ld [$30] 2305 ld([0x30]) #15 Continue with vCPU in the same timeslice (faster)
04f1 c216 st [$16] 2306 st([vPC]) #16
04f2 0131 ld [$31] 2307 ld([0x31]) #17
04f3 c217 st [$17] 2308 st([vPC+1]) #18
04f4 0132 ld [$32] 2309 ld([0x32]) #19
04f5 c218 st [$18] 2310 st([vAC]) #20
04f6 0133 ld [$33] 2311 ld([0x33]) #21
04f7 c219 st [$19] 2312 st([vAC+1]) #22
04f8 1403 ld $03,y 2313 ld(hi('REENTER'),Y) #23
04f9 e0cb jmp y,$cb 2314 jmp(Y,'REENTER') #24
04fa 00f2 ld $f2 2315 ld(-28/2) #25
2316 # vRTI entry point
2317 assert(pc()&255 == 251) # The landing offset 251 for LUP trampoline is fixed
04fb f0f0 beq vRTI#15 2318 beq('vRTI#15') #13 vRTI sequence
04fc 9001 adda $01,x 2319 adda(1,X) #14
04fd 1412 ld $12,y 2320 ld(hi('vRTI#18'),Y) #15 Switch and wait for end of timeslice (slower)
04fe e020 jmp y,$20 2321 jmp(Y,'vRTI#18') #16
04ff c21d st [$1d] 2322 st([vTmp]) #17
2323
2324 #-----------------------------------------------------------------------
2325 #
2326 # $0500 ROM page 5-6: Shift table and code
2327 #
2328 #-----------------------------------------------------------------------
2329
2330 align(0x100, size=0x200)
2331
2332 # Lookup table for i>>n, with n in 1..6
2333 # Indexing ix = i & ~b | (b-1), where b = 1<<(n-1)
2334 # ...
2335 # ld <.ret
2336 # st [vTmp]
2337 # ld >shiftTable,y
2338 # <calculate ix>
2339 # jmp y,ac
2340 # bra $ff
2341 # .ret: ...
2342 #
2343 # i >> 7 can be always be done with RAM: [i&128]
2344 # ...
2345 # anda $80,x
2346 # ld [x]
2347 # ...
2348
2349 label('shiftTable')
2350 shiftTable = pc()
2351
2352 for ix in range(255):
2353 for n in range(1,7): # Find first zero
2354 if ~ix & (1 << (n-1)):
2355 break
2356 pattern = ['x' if i<n else '1' if ix&(1<<i) else '0' for i in range(8)]
2357 ld(ix>>n); C('0b%s >> %d' % (''.join(reversed(pattern)), n))
shiftTable: 0500 0000 ld $00 ;0b0000000x >> 1
0501 0000 ld $00 ;0b000000xx >> 2
0502 0001 ld $01 ;0b0000001x >> 1
0503 0000 ld $00 ;0b00000xxx >> 3
0504 0002 ld $02 ;0b0000010x >> 1
0505 0001 ld $01 ;0b000001xx >> 2
0506 0003 ld $03 ;0b0000011x >> 1
0507 0000 ld $00 ;0b0000xxxx >> 4
0508 0004 ld $04 ;0b0000100x >> 1
0509 0002 ld $02 ;0b000010xx >> 2
050a 0005 ld $05 ;0b0000101x >> 1
050b 0001 ld $01 ;0b00001xxx >> 3
050c 0006 ld $06 ;0b0000110x >> 1
050d 0003 ld $03 ;0b000011xx >> 2
050e 0007 ld $07 ;0b0000111x >> 1
050f 0000 ld $00 ;0b000xxxxx >> 5
0510 0008 ld $08 ;0b0001000x >> 1
0511 0004 ld $04 ;0b000100xx >> 2
0512 0009 ld $09 ;0b0001001x >> 1
0513 0002 ld $02 ;0b00010xxx >> 3
0514 000a ld $0a ;0b0001010x >> 1
0515 0005 ld $05 ;0b000101xx >> 2
0516 000b ld $0b ;0b0001011x >> 1
0517 0001 ld $01 ;0b0001xxxx >> 4
0518 000c ld $0c ;0b0001100x >> 1
0519 0006 ld $06 ;0b000110xx >> 2
051a 000d ld $0d ;0b0001101x >> 1
051b 0003 ld $03 ;0b00011xxx >> 3
051c 000e ld $0e ;0b0001110x >> 1
051d 0007 ld $07 ;0b000111xx >> 2
051e 000f ld $0f ;0b0001111x >> 1
051f 0000 ld $00 ;0b00xxxxxx >> 6
0520 0010 ld $10 ;0b0010000x >> 1
0521 0008 ld $08 ;0b001000xx >> 2
0522 0011 ld $11 ;0b0010001x >> 1
0523 0004 ld $04 ;0b00100xxx >> 3
0524 0012 ld $12 ;0b0010010x >> 1
0525 0009 ld $09 ;0b001001xx >> 2
0526 0013 ld $13 ;0b0010011x >> 1
0527 0002 ld $02 ;0b0010xxxx >> 4
0528 0014 ld $14 ;0b0010100x >> 1
0529 000a ld $0a ;0b001010xx >> 2
052a 0015 ld $15 ;0b0010101x >> 1
052b 0005 ld $05 ;0b00101xxx >> 3
052c 0016 ld $16 ;0b0010110x >> 1
052d 000b ld $0b ;0b001011xx >> 2
052e 0017 ld $17 ;0b0010111x >> 1
052f 0001 ld $01 ;0b001xxxxx >> 5
0530 0018 ld $18 ;0b0011000x >> 1
0531 000c ld $0c ;0b001100xx >> 2
0532 0019 ld $19 ;0b0011001x >> 1
0533 0006 ld $06 ;0b00110xxx >> 3
0534 001a ld $1a ;0b0011010x >> 1
0535 000d ld $0d ;0b001101xx >> 2
0536 001b ld $1b ;0b0011011x >> 1
0537 0003 ld $03 ;0b0011xxxx >> 4
0538 001c ld $1c ;0b0011100x >> 1
0539 000e ld $0e ;0b001110xx >> 2
053a 001d ld $1d ;0b0011101x >> 1
053b 0007 ld $07 ;0b00111xxx >> 3
053c 001e ld $1e ;0b0011110x >> 1
053d 000f ld $0f ;0b001111xx >> 2
053e 001f ld $1f ;0b0011111x >> 1
053f 0000 ld $00 ;0b00xxxxxx >> 6
0540 0020 ld $20 ;0b0100000x >> 1
0541 0010 ld $10 ;0b010000xx >> 2
0542 0021 ld $21 ;0b0100001x >> 1
0543 0008 ld $08 ;0b01000xxx >> 3
0544 0022 ld $22 ;0b0100010x >> 1
0545 0011 ld $11 ;0b010001xx >> 2
0546 0023 ld $23 ;0b0100011x >> 1
0547 0004 ld $04 ;0b0100xxxx >> 4
0548 0024 ld $24 ;0b0100100x >> 1
0549 0012 ld $12 ;0b010010xx >> 2
054a 0025 ld $25 ;0b0100101x >> 1
054b 0009 ld $09 ;0b01001xxx >> 3
054c 0026 ld $26 ;0b0100110x >> 1
054d 0013 ld $13 ;0b010011xx >> 2
054e 0027 ld $27 ;0b0100111x >> 1
054f 0002 ld $02 ;0b010xxxxx >> 5
0550 0028 ld $28 ;0b0101000x >> 1
0551 0014 ld $14 ;0b010100xx >> 2
0552 0029 ld $29 ;0b0101001x >> 1
0553 000a ld $0a ;0b01010xxx >> 3
0554 002a ld $2a ;0b0101010x >> 1
0555 0015 ld $15 ;0b010101xx >> 2
0556 002b ld $2b ;0b0101011x >> 1
0557 0005 ld $05 ;0b0101xxxx >> 4
0558 002c ld $2c ;0b0101100x >> 1
0559 0016 ld $16 ;0b010110xx >> 2
055a 002d ld $2d ;0b0101101x >> 1
055b 000b ld $0b ;0b01011xxx >> 3
055c 002e ld $2e ;0b0101110x >> 1
055d 0017 ld $17 ;0b010111xx >> 2
055e 002f ld $2f ;0b0101111x >> 1
055f 0001 ld $01 ;0b01xxxxxx >> 6
0560 0030 ld $30 ;0b0110000x >> 1
0561 0018 ld $18 ;0b011000xx >> 2
0562 0031 ld $31 ;0b0110001x >> 1
0563 000c ld $0c ;0b01100xxx >> 3
0564 0032 ld $32 ;0b0110010x >> 1
0565 0019 ld $19 ;0b011001xx >> 2
0566 0033 ld $33 ;0b0110011x >> 1
0567 0006 ld $06 ;0b0110xxxx >> 4
0568 0034 ld $34 ;0b0110100x >> 1
0569 001a ld $1a ;0b011010xx >> 2
056a 0035 ld $35 ;0b0110101x >> 1
056b 000d ld $0d ;0b01101xxx >> 3
056c 0036 ld $36 ;0b0110110x >> 1
056d 001b ld $1b ;0b011011xx >> 2
056e 0037 ld $37 ;0b0110111x >> 1
056f 0003 ld $03 ;0b011xxxxx >> 5
0570 0038 ld $38 ;0b0111000x >> 1
0571 001c ld $1c ;0b011100xx >> 2
0572 0039 ld $39 ;0b0111001x >> 1
0573 000e ld $0e ;0b01110xxx >> 3
0574 003a ld $3a ;0b0111010x >> 1
0575 001d ld $1d ;0b011101xx >> 2
0576 003b ld $3b ;0b0111011x >> 1
0577 0007 ld $07 ;0b0111xxxx >> 4
0578 003c ld $3c ;0b0111100x >> 1
0579 001e ld $1e ;0b011110xx >> 2
057a 003d ld $3d ;0b0111101x >> 1
057b 000f ld $0f ;0b01111xxx >> 3
057c 003e ld $3e ;0b0111110x >> 1
057d 001f ld $1f ;0b011111xx >> 2
057e 003f ld $3f ;0b0111111x >> 1
057f 0001 ld $01 ;0b01xxxxxx >> 6
0580 0040 ld $40 ;0b1000000x >> 1
0581 0020 ld $20 ;0b100000xx >> 2
0582 0041 ld $41 ;0b1000001x >> 1
0583 0010 ld $10 ;0b10000xxx >> 3
0584 0042 ld $42 ;0b1000010x >> 1
0585 0021 ld $21 ;0b100001xx >> 2
0586 0043 ld $43 ;0b1000011x >> 1
0587 0008 ld $08 ;0b1000xxxx >> 4
0588 0044 ld $44 ;0b1000100x >> 1
0589 0022 ld $22 ;0b100010xx >> 2
058a 0045 ld $45 ;0b1000101x >> 1
058b 0011 ld $11 ;0b10001xxx >> 3
058c 0046 ld $46 ;0b1000110x >> 1
058d 0023 ld $23 ;0b100011xx >> 2
058e 0047 ld $47 ;0b1000111x >> 1
058f 0004 ld $04 ;0b100xxxxx >> 5
0590 0048 ld $48 ;0b1001000x >> 1
0591 0024 ld $24 ;0b100100xx >> 2
0592 0049 ld $49 ;0b1001001x >> 1
0593 0012 ld $12 ;0b10010xxx >> 3
0594 004a ld $4a ;0b1001010x >> 1
0595 0025 ld $25 ;0b100101xx >> 2
0596 004b ld $4b ;0b1001011x >> 1
0597 0009 ld $09 ;0b1001xxxx >> 4
0598 004c ld $4c ;0b1001100x >> 1
0599 0026 ld $26 ;0b100110xx >> 2
059a 004d ld $4d ;0b1001101x >> 1
059b 0013 ld $13 ;0b10011xxx >> 3
059c 004e ld $4e ;0b1001110x >> 1
059d 0027 ld $27 ;0b100111xx >> 2
059e 004f ld $4f ;0b1001111x >> 1
059f 0002 ld $02 ;0b10xxxxxx >> 6
05a0 0050 ld $50 ;0b1010000x >> 1
05a1 0028 ld $28 ;0b101000xx >> 2
05a2 0051 ld $51 ;0b1010001x >> 1
05a3 0014 ld $14 ;0b10100xxx >> 3
05a4 0052 ld $52 ;0b1010010x >> 1
05a5 0029 ld $29 ;0b101001xx >> 2
05a6 0053 ld $53 ;0b1010011x >> 1
05a7 000a ld $0a ;0b1010xxxx >> 4
05a8 0054 ld $54 ;0b1010100x >> 1
05a9 002a ld $2a ;0b101010xx >> 2
05aa 0055 ld $55 ;0b1010101x >> 1
05ab 0015 ld $15 ;0b10101xxx >> 3
05ac 0056 ld $56 ;0b1010110x >> 1
05ad 002b ld $2b ;0b101011xx >> 2
05ae 0057 ld $57 ;0b1010111x >> 1
05af 0005 ld $05 ;0b101xxxxx >> 5
05b0 0058 ld $58 ;0b1011000x >> 1
05b1 002c ld $2c ;0b101100xx >> 2
05b2 0059 ld $59 ;0b1011001x >> 1
05b3 0016 ld $16 ;0b10110xxx >> 3
05b4 005a ld $5a ;0b1011010x >> 1
05b5 002d ld $2d ;0b101101xx >> 2
05b6 005b ld $5b ;0b1011011x >> 1
05b7 000b ld $0b ;0b1011xxxx >> 4
05b8 005c ld $5c ;0b1011100x >> 1
05b9 002e ld $2e ;0b101110xx >> 2
05ba 005d ld $5d ;0b1011101x >> 1
05bb 0017 ld $17 ;0b10111xxx >> 3
05bc 005e ld $5e ;0b1011110x >> 1
05bd 002f ld $2f ;0b101111xx >> 2
05be 005f ld $5f ;0b1011111x >> 1
05bf 0002 ld $02 ;0b10xxxxxx >> 6
05c0 0060 ld $60 ;0b1100000x >> 1
05c1 0030 ld $30 ;0b110000xx >> 2
05c2 0061 ld $61 ;0b1100001x >> 1
05c3 0018 ld $18 ;0b11000xxx >> 3
05c4 0062 ld $62 ;0b1100010x >> 1
05c5 0031 ld $31 ;0b110001xx >> 2
05c6 0063 ld $63 ;0b1100011x >> 1
05c7 000c ld $0c ;0b1100xxxx >> 4
05c8 0064 ld $64 ;0b1100100x >> 1
05c9 0032 ld $32 ;0b110010xx >> 2
05ca 0065 ld $65 ;0b1100101x >> 1
05cb 0019 ld $19 ;0b11001xxx >> 3
05cc 0066 ld $66 ;0b1100110x >> 1
05cd 0033 ld $33 ;0b110011xx >> 2
05ce 0067 ld $67 ;0b1100111x >> 1
05cf 0006 ld $06 ;0b110xxxxx >> 5
05d0 0068 ld $68 ;0b1101000x >> 1
05d1 0034 ld $34 ;0b110100xx >> 2
05d2 0069 ld $69 ;0b1101001x >> 1
05d3 001a ld $1a ;0b11010xxx >> 3
05d4 006a ld $6a ;0b1101010x >> 1
05d5 0035 ld $35 ;0b110101xx >> 2
05d6 006b ld $6b ;0b1101011x >> 1
05d7 000d ld $0d ;0b1101xxxx >> 4
05d8 006c ld $6c ;0b1101100x >> 1
05d9 0036 ld $36 ;0b110110xx >> 2
05da 006d ld $6d ;0b1101101x >> 1
05db 001b ld $1b ;0b11011xxx >> 3
05dc 006e ld $6e ;0b1101110x >> 1
05dd 0037 ld $37 ;0b110111xx >> 2
05de 006f ld $6f ;0b1101111x >> 1
05df 0003 ld $03 ;0b11xxxxxx >> 6
05e0 0070 ld $70 ;0b1110000x >> 1
05e1 0038 ld $38 ;0b111000xx >> 2
05e2 0071 ld $71 ;0b1110001x >> 1
05e3 001c ld $1c ;0b11100xxx >> 3
05e4 0072 ld $72 ;0b1110010x >> 1
05e5 0039 ld $39 ;0b111001xx >> 2
05e6 0073 ld $73 ;0b1110011x >> 1
05e7 000e ld $0e ;0b1110xxxx >> 4
05e8 0074 ld $74 ;0b1110100x >> 1
05e9 003a ld $3a ;0b111010xx >> 2
05ea 0075 ld $75 ;0b1110101x >> 1
05eb 001d ld $1d ;0b11101xxx >> 3
05ec 0076 ld $76 ;0b1110110x >> 1
05ed 003b ld $3b ;0b111011xx >> 2
05ee 0077 ld $77 ;0b1110111x >> 1
05ef 0007 ld $07 ;0b111xxxxx >> 5
05f0 0078 ld $78 ;0b1111000x >> 1
05f1 003c ld $3c ;0b111100xx >> 2
05f2 0079 ld $79 ;0b1111001x >> 1
05f3 001e ld $1e ;0b11110xxx >> 3
05f4 007a ld $7a ;0b1111010x >> 1
05f5 003d ld $3d ;0b111101xx >> 2
05f6 007b ld $7b ;0b1111011x >> 1
05f7 000f ld $0f ;0b1111xxxx >> 4
05f8 007c ld $7c ;0b1111100x >> 1
05f9 003e ld $3e ;0b111110xx >> 2
05fa 007d ld $7d ;0b1111101x >> 1
05fb 001f ld $1f ;0b11111xxx >> 3
05fc 007e ld $7e ;0b1111110x >> 1
05fd 003f ld $3f ;0b111111xx >> 2
05fe 007f ld $7f ;0b1111111x >> 1
2358
2359 assert pc()&255 == 255
05ff fd1d bra [$1d] 2360 bra([vTmp]) # Jumps back into next page
2361
2362 label('SYS_LSRW1_48')
2363 assert pc()&255 == 0 # First instruction on this page *must* be a nop
SYS_LSRW1_48: 0600 0200 nop 2364 nop() #15
0601 1405 ld $05,y 2365 ld(hi('shiftTable'),Y) #16 Logical shift right 1 bit (X >> 1)
0602 0008 ld $08 2366 ld('.sysLsrw1a') #17 Shift low byte
0603 c21d st [$1d] 2367 st([vTmp]) #18
0604 0118 ld [$18] 2368 ld([vAC]) #19
0605 20fe anda $fe 2369 anda(0b11111110) #20
0606 e200 jmp y,ac 2370 jmp(Y,AC) #21
0607 fcff bra $ff 2371 bra(255) #22 bra shiftTable+255
2372 label('.sysLsrw1a')
.sysLsrw1a: 0608 c218 st [$18] 2373 st([vAC]) #26
0609 0119 ld [$19] 2374 ld([vAC+1]) #27 Transfer bit 8
060a 2001 anda $01 2375 anda(1) #28
060b 807f adda $7f 2376 adda(127) #29
060c 2080 anda $80 2377 anda(128) #30
060d 4118 ora [$18] 2378 ora([vAC]) #31
060e c218 st [$18] 2379 st([vAC]) #32
060f 0015 ld $15 2380 ld('.sysLsrw1b') #33 Shift high byte
0610 c21d st [$1d] 2381 st([vTmp]) #34
0611 0119 ld [$19] 2382 ld([vAC+1]) #35
0612 20fe anda $fe 2383 anda(0b11111110) #36
0613 e200 jmp y,ac 2384 jmp(Y,AC) #37
0614 fcff bra $ff 2385 bra(255) #38 bra shiftTable+255
2386 label('.sysLsrw1b')
.sysLsrw1b: 0615 c219 st [$19] 2387 st([vAC+1]) #42
0616 1403 ld $03,y 2388 ld(hi('REENTER'),Y) #43
0617 e0cb jmp y,$cb 2389 jmp(Y,'REENTER') #44
0618 00e8 ld $e8 2390 ld(-48/2) #45
2391
2392 label('SYS_LSRW2_52')
SYS_LSRW2_52: 0619 1405 ld $05,y 2393 ld(hi('shiftTable'),Y) #15 Logical shift right 2 bit (X >> 2)
061a 0021 ld $21 2394 ld('.sysLsrw2a') #16 Shift low byte
061b c21d st [$1d] 2395 st([vTmp]) #17
061c 0118 ld [$18] 2396 ld([vAC]) #18
061d 20fc anda $fc 2397 anda(0b11111100) #19
061e 4001 ora $01 2398 ora( 0b00000001) #20
061f e200 jmp y,ac 2399 jmp(Y,AC) #21
0620 fcff bra $ff 2400 bra(255) #22 bra shiftTable+255
2401 label('.sysLsrw2a')
.sysLsrw2a: 0621 c218 st [$18] 2402 st([vAC]) #26
0622 0119 ld [$19] 2403 ld([vAC+1]) #27 Transfer bit 8:9
0623 8200 adda ac 2404 adda(AC) #28
0624 8200 adda ac 2405 adda(AC) #29
0625 8200 adda ac 2406 adda(AC) #30
0626 8200 adda ac 2407 adda(AC) #31
0627 8200 adda ac 2408 adda(AC) #32
0628 8200 adda ac 2409 adda(AC) #33
0629 4118 ora [$18] 2410 ora([vAC]) #34
062a c218 st [$18] 2411 st([vAC]) #35
062b 0032 ld $32 2412 ld('.sysLsrw2b') #36 Shift high byte
062c c21d st [$1d] 2413 st([vTmp]) #37
062d 0119 ld [$19] 2414 ld([vAC+1]) #38
062e 20fc anda $fc 2415 anda(0b11111100) #39
062f 4001 ora $01 2416 ora( 0b00000001) #40
0630 e200 jmp y,ac 2417 jmp(Y,AC) #41
0631 fcff bra $ff 2418 bra(255) #42 bra shiftTable+255
2419 label('.sysLsrw2b')
.sysLsrw2b: 0632 c219 st [$19] 2420 st([vAC+1]) #46
0633 1403 ld $03,y 2421 ld(hi('REENTER'),Y) #47
0634 e0cb jmp y,$cb 2422 jmp(Y,'REENTER') #48
0635 00e6 ld $e6 2423 ld(-52/2) #49
2424
2425 label('SYS_LSRW3_52')
SYS_LSRW3_52: 0636 1405 ld $05,y 2426 ld(hi('shiftTable'),Y) #15 Logical shift right 3 bit (X >> 3)
0637 003e ld $3e 2427 ld('.sysLsrw3a') #16 Shift low byte
0638 c21d st [$1d] 2428 st([vTmp]) #17
0639 0118 ld [$18] 2429 ld([vAC]) #18
063a 20f8 anda $f8 2430 anda(0b11111000) #19
063b 4003 ora $03 2431 ora( 0b00000011) #20
063c e200 jmp y,ac 2432 jmp(Y,AC) #21
063d fcff bra $ff 2433 bra(255) #22 bra shiftTable+255
2434 label('.sysLsrw3a')
.sysLsrw3a: 063e c218 st [$18] 2435 st([vAC]) #26
063f 0119 ld [$19] 2436 ld([vAC+1]) #27 Transfer bit 8:10
0640 8200 adda ac 2437 adda(AC) #28
0641 8200 adda ac 2438 adda(AC) #29
0642 8200 adda ac 2439 adda(AC) #30
0643 8200 adda ac 2440 adda(AC) #31
0644 8200 adda ac 2441 adda(AC) #32
0645 4118 ora [$18] 2442 ora([vAC]) #33
0646 c218 st [$18] 2443 st([vAC]) #34
0647 004e ld $4e 2444 ld('.sysLsrw3b') #35 Shift high byte
0648 c21d st [$1d] 2445 st([vTmp]) #36
0649 0119 ld [$19] 2446 ld([vAC+1]) #37
064a 20f8 anda $f8 2447 anda(0b11111000) #38
064b 4003 ora $03 2448 ora( 0b00000011) #39
064c e200 jmp y,ac 2449 jmp(Y,AC) #40
064d fcff bra $ff 2450 bra(255) #41 bra shiftTable+255
2451 label('.sysLsrw3b')
.sysLsrw3b: 064e c219 st [$19] 2452 st([vAC+1]) #45
064f 00e6 ld $e6 2453 ld(-52/2) #46
0650 1403 ld $03,y 2454 ld(hi('REENTER'),Y) #47
0651 e0cb jmp y,$cb 2455 jmp(Y,'REENTER') #48
2456 #nop() #49
2457
2458 label('SYS_LSRW4_50')
SYS_LSRW4_50: 0652 1405 ld $05,y 2459 ld(hi('shiftTable'),Y) #15,49 Logical shift right 4 bit (X >> 4)
0653 005a ld $5a 2460 ld('.sysLsrw4a') #16 Shift low byte
0654 c21d st [$1d] 2461 st([vTmp]) #17
0655 0118 ld [$18] 2462 ld([vAC]) #18
0656 20f0 anda $f0 2463 anda(0b11110000) #19
0657 4007 ora $07 2464 ora( 0b00000111) #20
0658 e200 jmp y,ac 2465 jmp(Y,AC) #21
0659 fcff bra $ff 2466 bra(255) #22 bra shiftTable+255
2467 label('.sysLsrw4a')
.sysLsrw4a: 065a c218 st [$18] 2468 st([vAC]) #26
065b 0119 ld [$19] 2469 ld([vAC+1]) #27 Transfer bit 8:11
065c 8200 adda ac 2470 adda(AC) #28
065d 8200 adda ac 2471 adda(AC) #29
065e 8200 adda ac 2472 adda(AC) #30
065f 8200 adda ac 2473 adda(AC) #31
0660 4118 ora [$18] 2474 ora([vAC]) #32
0661 c218 st [$18] 2475 st([vAC]) #33
0662 0069 ld $69 2476 ld('.sysLsrw4b') #34 Shift high byte'
0663 c21d st [$1d] 2477 st([vTmp]) #35
0664 0119 ld [$19] 2478 ld([vAC+1]) #36
0665 20f0 anda $f0 2479 anda(0b11110000) #37
0666 4007 ora $07 2480 ora( 0b00000111) #38
0667 e200 jmp y,ac 2481 jmp(Y,AC) #39
0668 fcff bra $ff 2482 bra(255) #40 bra shiftTable+255
2483 label('.sysLsrw4b')
.sysLsrw4b: 0669 c219 st [$19] 2484 st([vAC+1]) #44
066a 1403 ld $03,y 2485 ld(hi('REENTER'),Y) #45
066b e0cb jmp y,$cb 2486 jmp(Y,'REENTER') #46
066c 00e7 ld $e7 2487 ld(-50/2) #47
2488
2489 label('SYS_LSRW5_50')
SYS_LSRW5_50: 066d 1405 ld $05,y 2490 ld(hi('shiftTable'),Y) #15 Logical shift right 5 bit (X >> 5)
066e 0075 ld $75 2491 ld('.sysLsrw5a') #16 Shift low byte
066f c21d st [$1d] 2492 st([vTmp]) #17
0670 0118 ld [$18] 2493 ld([vAC]) #18
0671 20e0 anda $e0 2494 anda(0b11100000) #19
0672 400f ora $0f 2495 ora( 0b00001111) #20
0673 e200 jmp y,ac 2496 jmp(Y,AC) #21
0674 fcff bra $ff 2497 bra(255) #22 bra shiftTable+255
2498 label('.sysLsrw5a')
.sysLsrw5a: 0675 c218 st [$18] 2499 st([vAC]) #26
0676 0119 ld [$19] 2500 ld([vAC+1]) #27 Transfer bit 8:13
0677 8200 adda ac 2501 adda(AC) #28
0678 8200 adda ac 2502 adda(AC) #29
0679 8200 adda ac 2503 adda(AC) #30
067a 4118 ora [$18] 2504 ora([vAC]) #31
067b c218 st [$18] 2505 st([vAC]) #32
067c 0083 ld $83 2506 ld('.sysLsrw5b') #33 Shift high byte
067d c21d st [$1d] 2507 st([vTmp]) #34
067e 0119 ld [$19] 2508 ld([vAC+1]) #35
067f 20e0 anda $e0 2509 anda(0b11100000) #36
0680 400f ora $0f 2510 ora( 0b00001111) #37
0681 e200 jmp y,ac 2511 jmp(Y,AC) #38
0682 fcff bra $ff 2512 bra(255) #39 bra shiftTable+255
2513 label('.sysLsrw5b')
.sysLsrw5b: 0683 c219 st [$19] 2514 st([vAC+1]) #44
0684 00e7 ld $e7 2515 ld(-50/2) #45
0685 1403 ld $03,y 2516 ld(hi('REENTER'),Y) #46
0686 e0cb jmp y,$cb 2517 jmp(Y,'REENTER') #47
2518 #nop() #48
2519
2520 label('SYS_LSRW6_48')
SYS_LSRW6_48: 0687 1405 ld $05,y 2521 ld(hi('shiftTable'),Y) #15,44 Logical shift right 6 bit (X >> 6)
0688 008f ld $8f 2522 ld('.sysLsrw6a') #16 Shift low byte
0689 c21d st [$1d] 2523 st([vTmp]) #17
068a 0118 ld [$18] 2524 ld([vAC]) #18
068b 20c0 anda $c0 2525 anda(0b11000000) #19
068c 401f ora $1f 2526 ora( 0b00011111) #20
068d e200 jmp y,ac 2527 jmp(Y,AC) #21
068e fcff bra $ff 2528 bra(255) #22 bra shiftTable+255
2529 label('.sysLsrw6a')
.sysLsrw6a: 068f c218 st [$18] 2530 st([vAC]) #26
0690 0119 ld [$19] 2531 ld([vAC+1]) #27 Transfer bit 8:13
0691 8200 adda ac 2532 adda(AC) #28
0692 8200 adda ac 2533 adda(AC) #29
0693 4118 ora [$18] 2534 ora([vAC]) #30
0694 c218 st [$18] 2535 st([vAC]) #31
0695 009c ld $9c 2536 ld('.sysLsrw6b') #32 Shift high byte
0696 c21d st [$1d] 2537 st([vTmp]) #33
0697 0119 ld [$19] 2538 ld([vAC+1]) #34
0698 20c0 anda $c0 2539 anda(0b11000000) #35
0699 401f ora $1f 2540 ora( 0b00011111) #36
069a e200 jmp y,ac 2541 jmp(Y,AC) #37
069b fcff bra $ff 2542 bra(255) #38 bra shiftTable+255
2543 label('.sysLsrw6b')
.sysLsrw6b: 069c c219 st [$19] 2544 st([vAC+1]) #42
069d 1403 ld $03,y 2545 ld(hi('REENTER'),Y) #43
069e e0cb jmp y,$cb 2546 jmp(Y,'REENTER') #44
069f 00e8 ld $e8 2547 ld(-48/2) #45
2548
2549 label('SYS_LSLW4_46')
SYS_LSLW4_46: 06a0 1405 ld $05,y 2550 ld(hi('shiftTable'),Y) #15 Logical shift left 4 bit (X << 4)
06a1 00ae ld $ae 2551 ld('.sysLsrl4') #16
06a2 c21d st [$1d] 2552 st([vTmp]) #17
06a3 0119 ld [$19] 2553 ld([vAC+1]) #18
06a4 8200 adda ac 2554 adda(AC) #19
06a5 8200 adda ac 2555 adda(AC) #20
06a6 8200 adda ac 2556 adda(AC) #21
06a7 8200 adda ac 2557 adda(AC) #22
06a8 c219 st [$19] 2558 st([vAC+1]) #23
06a9 0118 ld [$18] 2559 ld([vAC]) #24
06aa 20f0 anda $f0 2560 anda(0b11110000) #25
06ab 4007 ora $07 2561 ora( 0b00000111) #26
06ac e200 jmp y,ac 2562 jmp(Y,AC) #27
06ad fcff bra $ff 2563 bra(255) #28 bra shiftTable+255
2564 label('.sysLsrl4')
.sysLsrl4: 06ae 4119 ora [$19] 2565 ora([vAC+1]) #32
06af c219 st [$19] 2566 st([vAC+1]) #33
06b0 0118 ld [$18] 2567 ld([vAC]) #34
06b1 8200 adda ac 2568 adda(AC) #35
06b2 8200 adda ac 2569 adda(AC) #36
06b3 8200 adda ac 2570 adda(AC) #37
06b4 8200 adda ac 2571 adda(AC) #38
06b5 c218 st [$18] 2572 st([vAC]) #39
06b6 00e9 ld $e9 2573 ld(-46/2) #40
06b7 1403 ld $03,y 2574 ld(hi('REENTER'),Y) #41
06b8 e0cb jmp y,$cb 2575 jmp(Y,'REENTER') #42
2576 #nop() #43
2577
2578 #-----------------------------------------------------------------------
2579 # Extension SYS_Read3_40
2580 #-----------------------------------------------------------------------
2581
2582 # Read 3 consecutive bytes from ROM
2583 #
2584 # Note: This function a bit obsolete, as it has very limited use. It's
2585 # effectively an application-specific SYS function for the Pictures
2586 # application from ROM v1. It requires the ROM data be organized
2587 # with trampoline3a and trampoline3b fragments, and their address
2588 # in ROM to be known. Better avoid using this.
2589 #
2590 # Variables:
2591 # sysArgs[0:2] Bytes (out)
2592 # sysArgs[6:7] ROM pointer (in)
2593
2594 label('SYS_Read3_40')
SYS_Read3_40: 06b9 152b ld [$2b],y 2595 ld([sysArgs+7],Y) #15,32
06ba e079 jmp y,$79 2596 jmp(Y,128-7) #16 trampoline3a
06bb 012a ld [$2a] 2597 ld([sysArgs+6]) #17
2598 label('txReturn')
txReturn: 06bc c226 st [$26] 2599 st([sysArgs+2]) #34
06bd 1403 ld $03,y 2600 ld(hi('REENTER'),Y) #35
06be e0cb jmp y,$cb 2601 jmp(Y,'REENTER') #36
06bf 00ec ld $ec 2602 ld(-40/2) #37
2603
2604 def trampoline3a():
2605 """Read 3 bytes from ROM page"""
2606 while pc()&255 < 128-7:
2607 nop()
2608 bra(AC) #18
2609 C('Trampoline for page $%02x00 reading (entry)' % (pc()>>8))
2610 bra(123) #19
2611 st([sysArgs+0]) #21
2612 ld([sysArgs+6]) #22
2613 adda(1) #23
2614 bra(AC) #24
2615 bra(250) #25 trampoline3b
2616 align(1, size=0x80)
2617
2618 def trampoline3b():
2619 """Read 3 bytes from ROM page (continue)"""
2620 while pc()&255 < 256-6:
2621 nop()
2622 st([sysArgs+1]) #27
2623 C('Trampoline for page $%02x00 reading (continue)' % (pc()>>8))
2624 ld([sysArgs+6]) #28
2625 adda(2) #29
2626 ld(hi('txReturn'),Y) #30
2627 bra(AC) #31
2628 jmp(Y,'txReturn') #32
2629 align(1, size=0x100)
2630
2631 #-----------------------------------------------------------------------
2632 # Extension SYS_Unpack_56
2633 #-----------------------------------------------------------------------
2634
2635 # Unpack 3 bytes into 4 pixels
2636 #
2637 # Variables:
2638 # sysArgs[0:2] Packed bytes (in)
2639 # sysArgs[0:3] Pixels (out)
2640
2641 label('SYS_Unpack_56')
SYS_Unpack_56:
06c0 1407 ld $07,y 2642 ld(soundTable>>8,Y) #15
06c1 0126 ld [$26] 2643 ld([sysArgs+2]) #16 a[2]>>2
06c2 5003 ora $03,x 2644 ora(0x03,X) #17
06c3 0d00 ld [y,x] 2645 ld([Y,X]) #18
06c4 c227 st [$27] 2646 st([sysArgs+3]) #19 -> Pixel 3
2647
06c5 0126 ld [$26] 2648 ld([sysArgs+2]) #20 (a[2]&3)<<4
06c6 2003 anda $03 2649 anda(0x03) #21
06c7 8200 adda ac 2650 adda(AC) #22
06c8 8200 adda ac 2651 adda(AC) #23
06c9 8200 adda ac 2652 adda(AC) #24
06ca 8200 adda ac 2653 adda(AC) #25
06cb c226 st [$26] 2654 st([sysArgs+2]) #26
06cc 0125 ld [$25] 2655 ld([sysArgs+1]) #27 | a[1]>>4
06cd 5003 ora $03,x 2656 ora(0x03,X) #28
06ce 0d00 ld [y,x] 2657 ld([Y,X]) #29
06cf 5003 ora $03,x 2658 ora(0x03,X) #30
06d0 0d00 ld [y,x] 2659 ld([Y,X]) #31
06d1 4126 ora [$26] 2660 ora([sysArgs+2]) #32
06d2 c226 st [$26] 2661 st([sysArgs+2]) #33 -> Pixel 2
2662
06d3 0125 ld [$25] 2663 ld([sysArgs+1]) #34 (a[1]&15)<<2
06d4 200f anda $0f 2664 anda(0x0f) #35
06d5 8200 adda ac 2665 adda(AC) #36
06d6 8200 adda ac 2666 adda(AC) #37
06d7 c225 st [$25] 2667 st([sysArgs+1]) #38
2668
06d8 0124 ld [$24] 2669 ld([sysArgs+0]) #39 | a[0]>>6
06d9 5003 ora $03,x 2670 ora(0x03,X) #40
06da 0d00 ld [y,x] 2671 ld([Y,X]) #41
06db 5003 ora $03,x 2672 ora(0x03,X) #42
06dc 0d00 ld [y,x] 2673 ld([Y,X]) #43
06dd 5003 ora $03,x 2674 ora(0x03,X) #44
06de 0d00 ld [y,x] 2675 ld([Y,X]) #45
06df 4125 ora [$25] 2676 ora([sysArgs+1]) #46
06e0 c225 st [$25] 2677 st([sysArgs+1]) #47 -> Pixel 1
2678
06e1 0124 ld [$24] 2679 ld([sysArgs+0]) #48 a[1]&63
06e2 203f anda $3f 2680 anda(0x3f) #49
06e3 c224 st [$24] 2681 st([sysArgs+0]) #50 -> Pixel 0
2682
06e4 1403 ld $03,y 2683 ld(hi('REENTER'),Y) #51
06e5 e0cb jmp y,$cb 2684 jmp(Y,'REENTER') #52
06e6 00e4 ld $e4 2685 ld(-56/2) #53
2686
2687 #-----------------------------------------------------------------------
2688 # v6502 right shift instruction
2689 #-----------------------------------------------------------------------
2690
2691 label('v6502_lsr#30')
v6502_lsr#30: 06e7 1525 ld [$25],y 2692 ld([v6502_ADH],Y) #30 Result
06e8 ce00 st [y,x] 2693 st([Y,X]) #31
06e9 c228 st [$28] 2694 st([v6502_Qz]) #32 Z flag
06ea c229 st [$29] 2695 st([v6502_Qn]) #33 N flag
06eb 140e ld $0e,y 2696 ld(hi('v6502_next'),Y) #34
06ec 00ed ld $ed 2697 ld(-38/2) #35
06ed e020 jmp y,$20 2698 jmp(Y,'v6502_next') #36
2699 #nop() #37 Overlap
2700 #
2701 label('v6502_ror#38')
v6502_ror#38: 06ee 1525 ld [$25],y 2702 ld([v6502_ADH],Y) #38,38 Result
06ef 4119 ora [$19] 2703 ora([v6502_BI]) #39 Transfer bit 8
06f0 ce00 st [y,x] 2704 st([Y,X]) #40
06f1 c228 st [$28] 2705 st([v6502_Qz]) #41 Z flag
06f2 c229 st [$29] 2706 st([v6502_Qn]) #42 N flag
06f3 140e ld $0e,y 2707 ld(hi('v6502_next'),Y) #43
06f4 e020 jmp y,$20 2708 jmp(Y,'v6502_next') #44
06f5 00e9 ld $e9 2709 ld(-46/2) #45
2710
2711 label("sys_MultiplyBytes#114")
sys_MultiplyBytes#114:
06f6 8119 adda [$19] 2712 adda([vAC + 1]) #114
06f7 c219 st [$19] 2713 st([vAC + 1]) #115
06f8 1403 ld $03,y 2714 ld(hi('NEXTY'), Y) #116
06f9 e000 jmp y,$00 2715 jmp(Y, 'NEXTY') #117
06fa 00c4 ld $c4 2716 ld(-120/2) #118
2717 #-----------------------------------------------------------------------
2718 #
2719 # $0700 ROM page 7-8: Gigatron font data
2720 #
2721 #-----------------------------------------------------------------------
2722
06fb 0200 nop 2723 align(0x100, size=0x100)
06fc 0200 nop
06fd 0200 nop
* 5 times
2724
2725 label('font32up')
2726 for ch in range(32, 32+50):
2727 comment = 'Char %s' % repr(chr(ch))
2728 for byte in font.font[ch-32]:
2729 ld(byte)
font32up: 0700 0000 ld $00 ;Char ' '
0701 0000 ld $00
0702 0000 ld $00
* 5 times
0705 0000 ld $00 ;Char '!'
0706 0000 ld $00
0707 00fa ld $fa
0708 0000 ld $00
0709 0000 ld $00
070a 00a0 ld $a0 ;Char '"'
070b 00c0 ld $c0
070c 0000 ld $00
070d 00a0 ld $a0
070e 00c0 ld $c0
070f 0028 ld $28 ;Char '#'
0710 00fe ld $fe
0711 0028 ld $28
0712 00fe ld $fe
0713 0028 ld $28
0714 0024 ld $24 ;Char '$'
0715 0054 ld $54
0716 00fe ld $fe
0717 0054 ld $54
0718 0048 ld $48
0719 00c4 ld $c4 ;Char '%'
071a 00c8 ld $c8
071b 0010 ld $10
071c 0026 ld $26
071d 0046 ld $46
071e 006c ld $6c ;Char '&'
071f 0092 ld $92
0720 006a ld $6a
0721 0004 ld $04
0722 000a ld $0a
0723 0000 ld $00 ;Char "'"
0724 00a0 ld $a0
0725 00c0 ld $c0
0726 0000 ld $00
0727 0000 ld $00
0728 0000 ld $00 ;Char '('
0729 0038 ld $38
072a 0044 ld $44
072b 0082 ld $82
072c 0000 ld $00
072d 0000 ld $00 ;Char ')'
072e 0082 ld $82
072f 0044 ld $44
0730 0038 ld $38
0731 0000 ld $00
0732 0028 ld $28 ;Char '*'
0733 0010 ld $10
0734 007c ld $7c
0735 0010 ld $10
0736 0028 ld $28
0737 0010 ld $10 ;Char '+'
0738 0010 ld $10
0739 007c ld $7c
073a 0010 ld $10
073b 0010 ld $10
073c 0000 ld $00 ;Char ','
073d 0005 ld $05
073e 0006 ld $06
073f 0000 ld $00
0740 0000 ld $00
0741 0010 ld $10 ;Char '-'
0742 0010 ld $10
0743 0010 ld $10
* 5 times
0746 0000 ld $00 ;Char '.'
0747 0002 ld $02
0748 0002 ld $02
0749 0000 ld $00
074a 0000 ld $00
074b 0000 ld $00 ;Char '/'
074c 0006 ld $06
074d 0018 ld $18
074e 0060 ld $60
074f 0000 ld $00
0750 007c ld $7c ;Char '0'
0751 008a ld $8a
0752 0092 ld $92
0753 00a2 ld $a2
0754 007c ld $7c
0755 0022 ld $22 ;Char '1'
0756 0042 ld $42
0757 00fe ld $fe
0758 0002 ld $02
0759 0002 ld $02
075a 0046 ld $46 ;Char '2'
075b 008a ld $8a
075c 0092 ld $92
075d 0092 ld $92
075e 0062 ld $62
075f 0044 ld $44 ;Char '3'
0760 0082 ld $82
0761 0092 ld $92
0762 0092 ld $92
0763 006c ld $6c
0764 0018 ld $18 ;Char '4'
0765 0028 ld $28
0766 0048 ld $48
0767 00fe ld $fe
0768 0008 ld $08
0769 00e4 ld $e4 ;Char '5'
076a 00a2 ld $a2
076b 00a2 ld $a2
076c 00a2 ld $a2
076d 009c ld $9c
076e 003c ld $3c ;Char '6'
076f 0052 ld $52
0770 0092 ld $92
0771 0092 ld $92
0772 000c ld $0c
0773 0080 ld $80 ;Char '7'
0774 008e ld $8e
0775 0090 ld $90
0776 00a0 ld $a0
0777 00c0 ld $c0
0778 006c ld $6c ;Char '8'
0779 0092 ld $92
077a 0092 ld $92
077b 0092 ld $92
077c 006c ld $6c
077d 0060 ld $60 ;Char '9'
077e 0092 ld $92
077f 0092 ld $92
0780 0094 ld $94
0781 0078 ld $78
0782 0000 ld $00 ;Char ':'
0783 0024 ld $24
0784 0024 ld $24
0785 0000 ld $00
0786 0000 ld $00
0787 0000 ld $00 ;Char ';'
0788 0025 ld $25
0789 0026 ld $26
078a 0000 ld $00
078b 0000 ld $00
078c 0010 ld $10 ;Char '<'
078d 0028 ld $28
078e 0044 ld $44
078f 0082 ld $82
0790 0000 ld $00
0791 0028 ld $28 ;Char '='
0792 0028 ld $28
0793 0028 ld $28
* 5 times
0796 0000 ld $00 ;Char '>'
0797 0082 ld $82
0798 0044 ld $44
0799 0028 ld $28
079a 0010 ld $10
079b 0040 ld $40 ;Char '?'
079c 0080 ld $80
079d 008a ld $8a
079e 0090 ld $90
079f 0060 ld $60
07a0 007c ld $7c ;Char '@'
07a1 0082 ld $82
07a2 00ba ld $ba
07a3 00aa ld $aa
07a4 0078 ld $78
07a5 003e ld $3e ;Char 'A'
07a6 0048 ld $48
07a7 0088 ld $88
07a8 0048 ld $48
07a9 003e ld $3e
07aa 00fe ld $fe ;Char 'B'
07ab 0092 ld $92
07ac 0092 ld $92
07ad 0092 ld $92
07ae 006c ld $6c
07af 007c ld $7c ;Char 'C'
07b0 0082 ld $82
07b1 0082 ld $82
07b2 0082 ld $82
07b3 0044 ld $44
07b4 00fe ld $fe ;Char 'D'
07b5 0082 ld $82
07b6 0082 ld $82
07b7 0044 ld $44
07b8 0038 ld $38
07b9 00fe ld $fe ;Char 'E'
07ba 0092 ld $92
07bb 0092 ld $92
07bc 0092 ld $92
07bd 0082 ld $82
07be 00fe ld $fe ;Char 'F'
07bf 0090 ld $90
07c0 0090 ld $90
07c1 0090 ld $90
07c2 0080 ld $80
07c3 007c ld $7c ;Char 'G'
07c4 0082 ld $82
07c5 0082 ld $82
07c6 0092 ld $92
07c7 005c ld $5c
07c8 00fe ld $fe ;Char 'H'
07c9 0010 ld $10
07ca 0010 ld $10
07cb 0010 ld $10
07cc 00fe ld $fe
07cd 0000 ld $00 ;Char 'I'
07ce 0082 ld $82
07cf 00fe ld $fe
07d0 0082 ld $82
07d1 0000 ld $00
07d2 0004 ld $04 ;Char 'J'
07d3 0002 ld $02
07d4 0082 ld $82
07d5 00fc ld $fc
07d6 0080 ld $80
07d7 00fe ld $fe ;Char 'K'
07d8 0010 ld $10
07d9 0028 ld $28
07da 0044 ld $44
07db 0082 ld $82
07dc 00fe ld $fe ;Char 'L'
07dd 0002 ld $02
07de 0002 ld $02
07df 0002 ld $02
07e0 0002 ld $02
07e1 00fe ld $fe ;Char 'M'
07e2 0040 ld $40
07e3 0030 ld $30
07e4 0040 ld $40
07e5 00fe ld $fe
07e6 00fe ld $fe ;Char 'N'
07e7 0020 ld $20
07e8 0010 ld $10
07e9 0008 ld $08
07ea 00fe ld $fe
07eb 007c ld $7c ;Char 'O'
07ec 0082 ld $82
07ed 0082 ld $82
07ee 0082 ld $82
07ef 007c ld $7c
07f0 00fe ld $fe ;Char 'P'
07f1 0090 ld $90
07f2 0090 ld $90
07f3 0090 ld $90
07f4 0060 ld $60
07f5 007c ld $7c ;Char 'Q'
07f6 0082 ld $82
07f7 008a ld $8a
07f8 0084 ld $84
07f9 007a ld $7a
2730 comment = C(comment)
2731
07fa 0200 nop 2732 trampoline()
07fb fe00 bra ac ;+-----------------------------------+
07fc fcfd bra $07fd ;| |
07fd 1404 ld $04,y ;| Trampoline for page $0700 lookups |
07fe e068 jmp y,$68 ;| |
07ff c218 st [$18] ;+-----------------------------------+
2733
2734 #-----------------------------------------------------------------------
2735
2736 align(0x100, size=0x100)
2737
2738 label('font82up')
2739 for ch in range(32+50, 132):
2740 comment = 'Char %s' % repr(chr(ch))
2741 for byte in font.font[ch-32]:
2742 ld(byte)
font82up: 0800 00fe ld $fe ;Char 'R'
0801 0090 ld $90
0802 0098 ld $98
0803 0094 ld $94
0804 0062 ld $62
0805 0062 ld $62 ;Char 'S'
0806 0092 ld $92
0807 0092 ld $92
0808 0092 ld $92
0809 000c ld $0c
080a 0080 ld $80 ;Char 'T'
080b 0080 ld $80
080c 00fe ld $fe
080d 0080 ld $80
080e 0080 ld $80
080f 00fc ld $fc ;Char 'U'
0810 0002 ld $02
0811 0002 ld $02
0812 0002 ld $02
0813 00fc ld $fc
0814 00f0 ld $f0 ;Char 'V'
0815 000c ld $0c
0816 0002 ld $02
0817 000c ld $0c
0818 00f0 ld $f0
0819 00fe ld $fe ;Char 'W'
081a 0004 ld $04
081b 0018 ld $18
081c 0004 ld $04
081d 00fe ld $fe
081e 00c6 ld $c6 ;Char 'X'
081f 0028 ld $28
0820 0010 ld $10
0821 0028 ld $28
0822 00c6 ld $c6
0823 00e0 ld $e0 ;Char 'Y'
0824 0010 ld $10
0825 000e ld $0e
0826 0010 ld $10
0827 00e0 ld $e0
0828 0086 ld $86 ;Char 'Z'
0829 008a ld $8a
082a 0092 ld $92
082b 00a2 ld $a2
082c 00c2 ld $c2
082d 0000 ld $00 ;Char '['
082e 00fe ld $fe
082f 0082 ld $82
0830 0082 ld $82
0831 0000 ld $00
0832 0000 ld $00 ;Char '\\'
0833 0060 ld $60
0834 0018 ld $18
0835 0006 ld $06
0836 0000 ld $00
0837 0000 ld $00 ;Char ']'
0838 0082 ld $82
0839 0082 ld $82
083a 00fe ld $fe
083b 0000 ld $00
083c 0020 ld $20 ;Char '^'
083d 0040 ld $40
083e 0080 ld $80
083f 0040 ld $40
0840 0020 ld $20
0841 0002 ld $02 ;Char '_'
0842 0002 ld $02
0843 0002 ld $02
* 5 times
0846 0000 ld $00 ;Char '`'
0847 0000 ld $00
0848 00c0 ld $c0
0849 00a0 ld $a0
084a 0000 ld $00
084b 0004 ld $04 ;Char 'a'
084c 002a ld $2a
084d 002a ld $2a
084e 002a ld $2a
084f 001e ld $1e
0850 00fe ld $fe ;Char 'b'
0851 0022 ld $22
0852 0022 ld $22
0853 0022 ld $22
0854 001c ld $1c
0855 001c ld $1c ;Char 'c'
0856 0022 ld $22
0857 0022 ld $22
0858 0022 ld $22
0859 0002 ld $02
085a 001c ld $1c ;Char 'd'
085b 0022 ld $22
085c 0022 ld $22
085d 0022 ld $22
085e 00fe ld $fe
085f 001c ld $1c ;Char 'e'
0860 002a ld $2a
0861 002a ld $2a
0862 002a ld $2a
0863 0018 ld $18
0864 0010 ld $10 ;Char 'f'
0865 007e ld $7e
0866 0090 ld $90
0867 0080 ld $80
0868 0040 ld $40
0869 0018 ld $18 ;Char 'g'
086a 0025 ld $25
086b 0025 ld $25
086c 0025 ld $25
086d 001e ld $1e
086e 00fe ld $fe ;Char 'h'
086f 0020 ld $20
0870 0020 ld $20
0871 0020 ld $20
0872 001e ld $1e
0873 0000 ld $00 ;Char 'i'
0874 0022 ld $22
0875 00be ld $be
0876 0002 ld $02
0877 0000 ld $00
0878 0002 ld $02 ;Char 'j'
0879 0001 ld $01
087a 0021 ld $21
087b 00be ld $be
087c 0000 ld $00
087d 00fe ld $fe ;Char 'k'
087e 0008 ld $08
087f 0018 ld $18
0880 0024 ld $24
0881 0002 ld $02
0882 0000 ld $00 ;Char 'l'
0883 0082 ld $82
0884 00fe ld $fe
0885 0002 ld $02
0886 0000 ld $00
0887 003e ld $3e ;Char 'm'
0888 0020 ld $20
0889 001c ld $1c
088a 0020 ld $20
088b 001e ld $1e
088c 003e ld $3e ;Char 'n'
088d 0010 ld $10
088e 0020 ld $20
088f 0020 ld $20
0890 001e ld $1e
0891 001c ld $1c ;Char 'o'
0892 0022 ld $22
0893 0022 ld $22
0894 0022 ld $22
0895 001c ld $1c
0896 003f ld $3f ;Char 'p'
0897 0024 ld $24
0898 0024 ld $24
0899 0024 ld $24
089a 0018 ld $18
089b 0018 ld $18 ;Char 'q'
089c 0024 ld $24
089d 0024 ld $24
089e 0024 ld $24
089f 003f ld $3f
08a0 003e ld $3e ;Char 'r'
08a1 0010 ld $10
08a2 0020 ld $20
08a3 0020 ld $20
08a4 0010 ld $10
08a5 0012 ld $12 ;Char 's'
08a6 002a ld $2a
08a7 002a ld $2a
08a8 002a ld $2a
08a9 0004 ld $04
08aa 0020 ld $20 ;Char 't'
08ab 00fc ld $fc
08ac 0022 ld $22
08ad 0002 ld $02
08ae 0004 ld $04
08af 003c ld $3c ;Char 'u'
08b0 0002 ld $02
08b1 0002 ld $02
08b2 0004 ld $04
08b3 003e ld $3e
08b4 0038 ld $38 ;Char 'v'
08b5 0004 ld $04
08b6 0002 ld $02
08b7 0004 ld $04
08b8 0038 ld $38
08b9 003c ld $3c ;Char 'w'
08ba 0002 ld $02
08bb 000c ld $0c
08bc 0002 ld $02
08bd 003c ld $3c
08be 0022 ld $22 ;Char 'x'
08bf 0014 ld $14
08c0 0008 ld $08
08c1 0014 ld $14
08c2 0022 ld $22
08c3 0038 ld $38 ;Char 'y'
08c4 0005 ld $05
08c5 0005 ld $05
08c6 0005 ld $05
08c7 003e ld $3e
08c8 0022 ld $22 ;Char 'z'
08c9 0026 ld $26
08ca 002a ld $2a
08cb 0032 ld $32
08cc 0022 ld $22
08cd 0010 ld $10 ;Char '{'
08ce 006c ld $6c
08cf 0082 ld $82
08d0 0082 ld $82
08d1 0000 ld $00
08d2 0000 ld $00 ;Char '|'
08d3 0000 ld $00
08d4 00fe ld $fe
08d5 0000 ld $00
08d6 0000 ld $00
08d7 0000 ld $00 ;Char '}'
08d8 0082 ld $82
08d9 0082 ld $82
08da 006c ld $6c
08db 0010 ld $10
08dc 0040 ld $40 ;Char '~'
08dd 0080 ld $80
08de 0040 ld $40
08df 0020 ld $20
08e0 0040 ld $40
08e1 00fe ld $fe ;Char '\x7f'
08e2 00fe ld $fe
08e3 00fe ld $fe
* 5 times
08e6 0010 ld $10 ;Char '\x80'
08e7 0038 ld $38
08e8 0054 ld $54
08e9 0010 ld $10
08ea 0010 ld $10
08eb 0010 ld $10 ;Char '\x81'
08ec 0020 ld $20
08ed 007c ld $7c
08ee 0020 ld $20
08ef 0010 ld $10
08f0 0010 ld $10 ;Char '\x82'
08f1 0010 ld $10
08f2 0054 ld $54
08f3 0038 ld $38
08f4 0010 ld $10
08f5 0010 ld $10 ;Char '\x83'
08f6 0008 ld $08
08f7 007c ld $7c
08f8 0008 ld $08
08f9 0010 ld $10
2743 comment = C(comment)
2744
08fa 0200 nop 2745 trampoline()
08fb fe00 bra ac ;+-----------------------------------+
08fc fcfd bra $08fd ;| |
08fd 1404 ld $04,y ;| Trampoline for page $0800 lookups |
08fe e068 jmp y,$68 ;| |
08ff c218 st [$18] ;+-----------------------------------+
2746
2747 #-----------------------------------------------------------------------
2748 #
2749 # $0900 ROM page 9: Key table for music
2750 #
2751 #-----------------------------------------------------------------------
2752
2753 align(0x100, size=0x100)
2754 notes = 'CCDDEFFGGAAB'
2755 sampleRate = cpuClock / 200.0 / 4
2756 label('notesTable')
notesTable: 0900 0000 ld $00 2757 ld(0)
0901 0000 ld $00 2758 ld(0)
2759 for i in range(0, 250, 2):
2760 j = i//2-1
2761 freq = 440.0*2.0**((j-57)/12.0)
2762 if j>=0 and freq <= sampleRate/2.0:
2763 key = int(round(32768 * freq / sampleRate))
2764 octave, note = j//12, notes[j%12]
2765 sharp = '-' if notes[j%12-1] != note else '#'
2766 comment = '%s%s%s (%0.1f Hz)' % (note, sharp, octave, freq)
2767 ld(key&127); C(comment); ld(key>>7)
0902 0045 ld $45 ;C-0 (16.4 Hz)
0903 0000 ld $00
0904 0049 ld $49 ;C#0 (17.3 Hz)
0905 0000 ld $00
0906 004d ld $4d ;D-0 (18.4 Hz)
0907 0000 ld $00
0908 0052 ld $52 ;D#0 (19.4 Hz)
0909 0000 ld $00
090a 0056 ld $56 ;E-0 (20.6 Hz)
090b 0000 ld $00
090c 005c ld $5c ;F-0 (21.8 Hz)
090d 0000 ld $00
090e 0061 ld $61 ;F#0 (23.1 Hz)
090f 0000 ld $00
0910 0067 ld $67 ;G-0 (24.5 Hz)
0911 0000 ld $00
0912 006d ld $6d ;G#0 (26.0 Hz)
0913 0000 ld $00
0914 0073 ld $73 ;A-0 (27.5 Hz)
0915 0000 ld $00
0916 007a ld $7a ;A#0 (29.1 Hz)
0917 0000 ld $00
0918 0001 ld $01 ;B-0 (30.9 Hz)
0919 0001 ld $01
091a 0009 ld $09 ;C-1 (32.7 Hz)
091b 0001 ld $01
091c 0011 ld $11 ;C#1 (34.6 Hz)
091d 0001 ld $01
091e 001a ld $1a ;D-1 (36.7 Hz)
091f 0001 ld $01
0920 0023 ld $23 ;D#1 (38.9 Hz)
0921 0001 ld $01
0922 002d ld $2d ;E-1 (41.2 Hz)
0923 0001 ld $01
0924 0037 ld $37 ;F-1 (43.7 Hz)
0925 0001 ld $01
0926 0042 ld $42 ;F#1 (46.2 Hz)
0927 0001 ld $01
0928 004e ld $4e ;G-1 (49.0 Hz)
0929 0001 ld $01
092a 005a ld $5a ;G#1 (51.9 Hz)
092b 0001 ld $01
092c 0067 ld $67 ;A-1 (55.0 Hz)
092d 0001 ld $01
092e 0074 ld $74 ;A#1 (58.3 Hz)
092f 0001 ld $01
0930 0003 ld $03 ;B-1 (61.7 Hz)
0931 0002 ld $02
0932 0012 ld $12 ;C-2 (65.4 Hz)
0933 0002 ld $02
0934 0023 ld $23 ;C#2 (69.3 Hz)
0935 0002 ld $02
0936 0034 ld $34 ;D-2 (73.4 Hz)
0937 0002 ld $02
0938 0046 ld $46 ;D#2 (77.8 Hz)
0939 0002 ld $02
093a 005a ld $5a ;E-2 (82.4 Hz)
093b 0002 ld $02
093c 006e ld $6e ;F-2 (87.3 Hz)
093d 0002 ld $02
093e 0004 ld $04 ;F#2 (92.5 Hz)
093f 0003 ld $03
0940 001b ld $1b ;G-2 (98.0 Hz)
0941 0003 ld $03
0942 0033 ld $33 ;G#2 (103.8 Hz)
0943 0003 ld $03
0944 004d ld $4d ;A-2 (110.0 Hz)
0945 0003 ld $03
0946 0069 ld $69 ;A#2 (116.5 Hz)
0947 0003 ld $03
0948 0006 ld $06 ;B-2 (123.5 Hz)
0949 0004 ld $04
094a 0025 ld $25 ;C-3 (130.8 Hz)
094b 0004 ld $04
094c 0045 ld $45 ;C#3 (138.6 Hz)
094d 0004 ld $04
094e 0068 ld $68 ;D-3 (146.8 Hz)
094f 0004 ld $04
0950 000c ld $0c ;D#3 (155.6 Hz)
0951 0005 ld $05
0952 0033 ld $33 ;E-3 (164.8 Hz)
0953 0005 ld $05
0954 005c ld $5c ;F-3 (174.6 Hz)
0955 0005 ld $05
0956 0008 ld $08 ;F#3 (185.0 Hz)
0957 0006 ld $06
0958 0036 ld $36 ;G-3 (196.0 Hz)
0959 0006 ld $06
095a 0067 ld $67 ;G#3 (207.7 Hz)
095b 0006 ld $06
095c 001b ld $1b ;A-3 (220.0 Hz)
095d 0007 ld $07
095e 0052 ld $52 ;A#3 (233.1 Hz)
095f 0007 ld $07
0960 000c ld $0c ;B-3 (246.9 Hz)
0961 0008 ld $08
0962 0049 ld $49 ;C-4 (261.6 Hz)
0963 0008 ld $08
0964 000b ld $0b ;C#4 (277.2 Hz)
0965 0009 ld $09
0966 0050 ld $50 ;D-4 (293.7 Hz)
0967 0009 ld $09
0968 0019 ld $19 ;D#4 (311.1 Hz)
0969 000a ld $0a
096a 0067 ld $67 ;E-4 (329.6 Hz)
096b 000a ld $0a
096c 0039 ld $39 ;F-4 (349.2 Hz)
096d 000b ld $0b
096e 0010 ld $10 ;F#4 (370.0 Hz)
096f 000c ld $0c
0970 006c ld $6c ;G-4 (392.0 Hz)
0971 000c ld $0c
0972 004e ld $4e ;G#4 (415.3 Hz)
0973 000d ld $0d
0974 0035 ld $35 ;A-4 (440.0 Hz)
0975 000e ld $0e
0976 0023 ld $23 ;A#4 (466.2 Hz)
0977 000f ld $0f
0978 0017 ld $17 ;B-4 (493.9 Hz)
0979 0010 ld $10
097a 0013 ld $13 ;C-5 (523.3 Hz)
097b 0011 ld $11
097c 0015 ld $15 ;C#5 (554.4 Hz)
097d 0012 ld $12
097e 001f ld $1f ;D-5 (587.3 Hz)
097f 0013 ld $13
0980 0032 ld $32 ;D#5 (622.3 Hz)
0981 0014 ld $14
0982 004d ld $4d ;E-5 (659.3 Hz)
0983 0015 ld $15
0984 0072 ld $72 ;F-5 (698.5 Hz)
0985 0016 ld $16
0986 0020 ld $20 ;F#5 (740.0 Hz)
0987 0018 ld $18
0988 0058 ld $58 ;G-5 (784.0 Hz)
0989 0019 ld $19
098a 001c ld $1c ;G#5 (830.6 Hz)
098b 001b ld $1b
098c 006b ld $6b ;A-5 (880.0 Hz)
098d 001c ld $1c
098e 0046 ld $46 ;A#5 (932.3 Hz)
098f 001e ld $1e
0990 002f ld $2f ;B-5 (987.8 Hz)
0991 0020 ld $20
0992 0025 ld $25 ;C-6 (1046.5 Hz)
0993 0022 ld $22
0994 002a ld $2a ;C#6 (1108.7 Hz)
0995 0024 ld $24
0996 003f ld $3f ;D-6 (1174.7 Hz)
0997 0026 ld $26
0998 0064 ld $64 ;D#6 (1244.5 Hz)
0999 0028 ld $28
099a 001a ld $1a ;E-6 (1318.5 Hz)
099b 002b ld $2b
099c 0063 ld $63 ;F-6 (1396.9 Hz)
099d 002d ld $2d
099e 003f ld $3f ;F#6 (1480.0 Hz)
099f 0030 ld $30
09a0 0031 ld $31 ;G-6 (1568.0 Hz)
09a1 0033 ld $33
09a2 0038 ld $38 ;G#6 (1661.2 Hz)
09a3 0036 ld $36
09a4 0056 ld $56 ;A-6 (1760.0 Hz)
09a5 0039 ld $39
09a6 000d ld $0d ;A#6 (1864.7 Hz)
09a7 003d ld $3d
09a8 005e ld $5e ;B-6 (1975.5 Hz)
09a9 0040 ld $40
09aa 004b ld $4b ;C-7 (2093.0 Hz)
09ab 0044 ld $44
09ac 0055 ld $55 ;C#7 (2217.5 Hz)
09ad 0048 ld $48
09ae 007e ld $7e ;D-7 (2349.3 Hz)
09af 004c ld $4c
09b0 0048 ld $48 ;D#7 (2489.0 Hz)
09b1 0051 ld $51
09b2 0034 ld $34 ;E-7 (2637.0 Hz)
09b3 0056 ld $56
09b4 0046 ld $46 ;F-7 (2793.8 Hz)
09b5 005b ld $5b
09b6 007f ld $7f ;F#7 (2960.0 Hz)
09b7 0060 ld $60
09b8 0061 ld $61 ;G-7 (3136.0 Hz)
09b9 0066 ld $66
09ba 006f ld $6f ;G#7 (3322.4 Hz)
09bb 006c ld $6c
09bc 002c ld $2c ;A-7 (3520.0 Hz)
09bd 0073 ld $73
09be 001a ld $1a ;A#7 (3729.3 Hz)
09bf 007a ld $7a
2768
09c0 0200 nop 2769 trampoline()
09c1 0200 nop
09c2 0200 nop
* 59 times
09fb fe00 bra ac ;+-----------------------------------+
09fc fcfd bra $09fd ;| |
09fd 1404 ld $04,y ;| Trampoline for page $0900 lookups |
09fe e068 jmp y,$68 ;| |
09ff c218 st [$18] ;+-----------------------------------+
2770
2771 #-----------------------------------------------------------------------
2772 #
2773 # $0a00 ROM page 10: Inversion table
2774 #
2775 #-----------------------------------------------------------------------
2776
2777 align(0x100, size=0x100)
2778 label('invTable')
2779
2780 # Unit 64, table offset 16 (=1/4), value offset 1: (x+16)*(y+1) == 64*64 - e
2781 for i in range(251):
invTable: 0a00 00ff ld $ff 2782 ld(4096//(i+16)-1)
0a01 00ef ld $ef
0a02 00e2 ld $e2
0a03 00d6 ld $d6
0a04 00cb ld $cb
0a05 00c2 ld $c2
0a06 00b9 ld $b9
0a07 00b1 ld $b1
0a08 00a9 ld $a9
0a09 00a2 ld $a2
0a0a 009c ld $9c
0a0b 0096 ld $96
0a0c 0091 ld $91
0a0d 008c ld $8c
0a0e 0087 ld $87
0a0f 0083 ld $83
0a10 007f ld $7f
0a11 007b ld $7b
0a12 0077 ld $77
0a13 0074 ld $74
0a14 0070 ld $70
0a15 006d ld $6d
0a16 006a ld $6a
0a17 0068 ld $68
0a18 0065 ld $65
0a19 0062 ld $62
0a1a 0060 ld $60
0a1b 005e ld $5e
0a1c 005c ld $5c
0a1d 005a ld $5a
0a1e 0058 ld $58
0a1f 0056 ld $56
0a20 0054 ld $54
0a21 0052 ld $52
0a22 0050 ld $50
0a23 004f ld $4f
0a24 004d ld $4d
0a25 004c ld $4c
0a26 004a ld $4a
0a27 0049 ld $49
0a28 0048 ld $48
0a29 0046 ld $46
0a2a 0045 ld $45
0a2b 0044 ld $44
0a2c 0043 ld $43
0a2d 0042 ld $42
0a2e 0041 ld $41
0a2f 0040 ld $40
0a30 003f ld $3f
0a31 003e ld $3e
0a32 003d ld $3d
0a33 003c ld $3c
0a34 003b ld $3b
0a35 003a ld $3a
0a36 0039 ld $39
0a37 0038 ld $38
0a38 0037 ld $37
0a39 0037 ld $37
0a3a 0036 ld $36
0a3b 0035 ld $35
0a3c 0034 ld $34
0a3d 0034 ld $34
0a3e 0033 ld $33
0a3f 0032 ld $32
0a40 0032 ld $32
0a41 0031 ld $31
0a42 0030 ld $30
0a43 0030 ld $30
0a44 002f ld $2f
0a45 002f ld $2f
0a46 002e ld $2e
0a47 002e ld $2e
0a48 002d ld $2d
0a49 002d ld $2d
0a4a 002c ld $2c
0a4b 002c ld $2c
0a4c 002b ld $2b
0a4d 002b ld $2b
0a4e 002a ld $2a
0a4f 002a ld $2a
0a50 0029 ld $29
0a51 0029 ld $29
0a52 0028 ld $28
0a53 0028 ld $28
0a54 0027 ld $27
0a55 0027 ld $27
0a56 0027 ld $27
0a57 0026 ld $26
0a58 0026 ld $26
0a59 0026 ld $26
0a5a 0025 ld $25
0a5b 0025 ld $25
0a5c 0024 ld $24
0a5d 0024 ld $24
0a5e 0024 ld $24
0a5f 0023 ld $23
0a60 0023 ld $23
0a61 0023 ld $23
0a62 0022 ld $22
0a63 0022 ld $22
0a64 0022 ld $22
0a65 0022 ld $22
0a66 0021 ld $21
0a67 0021 ld $21
0a68 0021 ld $21
0a69 0020 ld $20
0a6a 0020 ld $20
0a6b 0020 ld $20
0a6c 0020 ld $20
0a6d 001f ld $1f
0a6e 001f ld $1f
0a6f 001f ld $1f
0a70 001f ld $1f
0a71 001e ld $1e
0a72 001e ld $1e
0a73 001e ld $1e
0a74 001e ld $1e
0a75 001d ld $1d
0a76 001d ld $1d
0a77 001d ld $1d
0a78 001d ld $1d
0a79 001c ld $1c
0a7a 001c ld $1c
0a7b 001c ld $1c
* 5 times
0a7e 001b ld $1b
0a7f 001b ld $1b
0a80 001b ld $1b
* 5 times
0a83 001a ld $1a
0a84 001a ld $1a
0a85 001a ld $1a
* 5 times
0a88 0019 ld $19
0a89 0019 ld $19
0a8a 0019 ld $19
* 6 times
0a8e 0018 ld $18
0a8f 0018 ld $18
0a90 0018 ld $18
* 6 times
0a94 0017 ld $17
0a95 0017 ld $17
0a96 0017 ld $17
* 7 times
0a9b 0016 ld $16
0a9c 0016 ld $16
0a9d 0016 ld $16
* 8 times
0aa3 0015 ld $15
0aa4 0015 ld $15
0aa5 0015 ld $15
* 8 times
0aab 0014 ld $14
0aac 0014 ld $14
0aad 0014 ld $14
* 9 times
0ab4 0013 ld $13
0ab5 0013 ld $13
0ab6 0013 ld $13
* 9 times
0abd 0012 ld $12
0abe 0012 ld $12
0abf 0012 ld $12
* 11 times
0ac8 0011 ld $11
0ac9 0011 ld $11
0aca 0011 ld $11
* 12 times
0ad4 0010 ld $10
0ad5 0010 ld $10
0ad6 0010 ld $10
* 13 times
0ae1 000f ld $0f
0ae2 000f ld $0f
0ae3 000f ld $0f
* 16 times
0af1 000e ld $0e
0af2 000e ld $0e
0af3 000e ld $0e
* 10 times
2783
2784 trampoline()
0afb fe00 bra ac ;+-----------------------------------+
0afc fcfd bra $0afd ;| |
0afd 1404 ld $04,y ;| Trampoline for page $0a00 lookups |
0afe e068 jmp y,$68 ;| |
0aff c218 st [$18] ;+-----------------------------------+
2785
2786 #-----------------------------------------------------------------------
2787 #
2788 # $0d00 ROM page 11: More SYS functions
2789 #
2790 #-----------------------------------------------------------------------
2791
2792 align(0x100, size=0x100)
2793
2794 #-----------------------------------------------------------------------
2795 # Extension SYS_SetMode_v2_80
2796 #-----------------------------------------------------------------------
2797
2798 # Set video mode to 0 to 3 black scanlines per pixel line.
2799 #
2800 # Mainly for making the MODE command available in Tiny BASIC, so that
2801 # the user can experiment. It's adviced to refrain from using
2802 # SYS_SetMode_v2_80 in regular applications. Video mode is a deeply
2803 # personal preference, and the programmer shouldn't overrule the user
2804 # in that choice. The Gigatron philisophy is that the end user has
2805 # the final say on what happens on the system, not the application,
2806 # even if that implies a degraded performance. This doesn't mean that
2807 # all applications must work well in all video modes: mode 1 is still
2808 # the default. If an application really doesn't work at all in that
2809 # mode, it's acceptable to change mode once after loading.
2810 #
2811 # There's no "SYS_GetMode" function.
2812 #
2813 # Variables:
2814 # vAC bit 0:1 Mode:
2815 # 0 "ABCD" -> Full mode (slowest)
2816 # 1 "ABC-" -> Default mode after reset
2817 # 2 "A-C-" -> at67's mode
2818 # 3 "A---" -> HGM's mode
2819 # vAC bit 2:15 Ignored bits and should be 0
2820 #
2821 # Special values (ROM v4):
2822 # vAC = 1975 Zombie mode (no video signals, no input,
2823 # no blinkenlights).
2824 # vAC = -1 Leave zombie mode and restore previous mode.
2825
2826 # Actual duration is <80 cycles, but keep some room for future extensions
2827 label('SYS_SetMode_v2_80')
SYS_SetMode_v2_80:
0b00 140b ld $0b,y 2828 ld(hi('sys_SetMode'),Y) #15
0b01 e054 jmp y,$54 2829 jmp(Y,'sys_SetMode') #16
0b02 011e ld [$1e] 2830 ld([vReturn]) #17
2831
2832 #-----------------------------------------------------------------------
2833 # Extension SYS_SetMemory_v2_54
2834 #-----------------------------------------------------------------------
2835
2836 # SYS function for setting 1..256 bytes
2837 #
2838 # sysArgs[0] Copy count (in, changed)
2839 # sysArgs[1] Copy value (in)
2840 # sysArgs[2:3] Destination address (in, changed)
2841 #
2842 # Sets up to 8 bytes per invocation before restarting itself through vCPU.
2843 # Doesn't wrap around page boundary. Can run 3 times per 148-cycle time slice.
2844 # All combined that gives a 300% speedup over ROMv4 and before.
2845
2846 label('SYS_SetMemory_v2_54')
SYS_SetMemory_v2_54:
0b03 0124 ld [$24] 2847 ld([sysArgs+0]) #15
2848 bra('sys_SetMemory#18') #16
0b04 fc18 bra sys_SetMemory#18
0b05 1126 ld [$26],x 2849 ld([sysArgs+2],X) #17
2850
2851 #-----------------------------------------------------------------------
2852 # Extension SYS_SendSerial1_v3_80
2853 #-----------------------------------------------------------------------
2854
2855 # SYS function for sending data over serial controller port using
2856 # pulse width modulation of the vertical sync signal.
2857 #
2858 # Variables:
2859 # sysArgs[0:1] Source address (in, changed)
2860 # sysArgs[2] Start bit mask (typically 1) (in, changed)
2861 # sysArgs[3] Number of send frames X (in, changed)
2862 #
2863 # The sending will abort if input data is detected on the serial port.
2864 # Returns 0 in case of all bits sent, or <>0 in case of abort
2865 #
2866 # This modulates the next upcoming X vertical pulses with the supplied
2867 # data. A zero becomes a 7 line vPulse, a one will be 9 lines.
2868 # After that, the vPulse width falls back to 8 lines (idle).
2869
2870 label('SYS_SendSerial1_v3_80')
SYS_SendSerial1_v3_80:
0b06 0109 ld [$09] 2871 ld([videoY]) #15
2872 bra('sys_SendSerial1') #16
0b07 fc83 bra sys_SendSerial1
0b08 60b3 xora $b3 2873 xora(videoYline0) #17 First line of vertical blank
2874
2875 #-----------------------------------------------------------------------
2876 # Extension SYS_ExpanderControl_v4_40
2877 #-----------------------------------------------------------------------
2878
2879 # Sets the I/O and RAM expander's control register
2880 #
2881 # Variables:
2882 # vAC bit 2 Device enable /SS0
2883 # bit 3 Device enable /SS1
2884 # bit 4 Device enable /SS2
2885 # bit 5 Device enable /SS3
2886 # bit 6 Banking B0
2887 # bit 7 Banking B1
2888 # bit 15 Data out MOSI
2889 # sysArgs[7] Cache for control state (written to)
2890 #
2891 # Intended for prototyping, and probably too low-level for most applications
2892 # Still there's a safeguard: it's not possible to disable RAM using this
2893
2894 label('SYS_ExpanderControl_v4_40')
SYS_ExpanderControl_v4_40:
0b09 140c ld $0c,y 2895 ld(hi('sys_ExpanderControl'),Y) #15
0b0a e0fb jmp y,$fb 2896 jmp(Y,'sys_ExpanderControl') #16
0b0b 00fc ld $fc 2897 ld(0b11111100) #17 Safety (SCLK=0)
2898 # ^^^^^^^^
2899 # |||||||`-- SCLK
2900 # ||||||`--- Not connected
2901 # |||||`---- /SS0
2902 # ||||`----- /SS1
2903 # |||`------ /SS2
2904 # ||`------- /SS3
2905 # |`-------- B0
2906 # `--------- B1
2907
2908 #-----------------------------------------------------------------------
2909 # Extension SYS_Run6502_v4_80
2910 #-----------------------------------------------------------------------
2911
2912 # Transfer control to v6502
2913 #
2914 # Calling 6502 code from vCPU goes (only) through this SYS function.
2915 # Directly modifying the vCpuSelect variable is unreliable. The
2916 # control transfer is immediate, without waiting for the current
2917 # time slice to end or first returning to vCPU.
2918 #
2919 # vCPU code and v6502 code can interoperate without much hassle:
2920 # - The v6502 program counter is vLR, and v6502 doesn't touch vPC
2921 # - Returning to vCPU is with the BRK instruction
2922 # - BRK doesn't dump process state on the stack
2923 # - vCPU can save/restore the vLR with PUSH/POP
2924 # - Stacks are shared, vAC is shared
2925 # - vAC can indicate what the v6502 code wants. vAC+1 will be cleared
2926 # - Alternative is to leave a word in sysArgs[6:7] (v6502 X and Y registers)
2927 # - Another way is to set vPC before BRK, and vCPU will continue there(+2)
2928 #
2929 # Calling v6502 code from vCPU looks like this:
2930 # LDWI SYS_Run6502_v4_80
2931 # STW sysFn
2932 # LDWI $6502_start_address
2933 # STW vLR
2934 # SYS 80
2935 #
2936 # Variables:
2937 # vAC Accumulator
2938 # vLR Program Counter
2939 # vSP Stack Pointer (+1)
2940 # sysArgs[6] Index Register X
2941 # sysArgs[7] Index Register Y
2942 # For info:
2943 # sysArgs[0:1] Address Register, free to clobber
2944 # sysArgs[2] Instruction Register, free to clobber
2945 # sysArgs[3:5] Flags, don't touch
2946 #
2947 # Implementation details::
2948 #
2949 # The time to reserve for this transition is the maximum time
2950 # between NEXT and v6502_check. This is
2951 # SYS call duration + 2*v6502_maxTicks + (v6502_overhead - vCPU_overhead)
2952 # = 22 + 28 + (11 - 9) = 62 cycles.
2953 # So reserving 80 cycles is future proof. This isn't overhead, as it includes
2954 # the fetching of the first 6502 opcode and its operands..
2955 #
2956 # 0 10 28=0 9
2957 # ---+----+---------+------------+------------------+-----------+---
2958 # video | nop| runVcpu | ENTER | At least one ins | EXIT | video
2959 # ---+----+---------+------------+------------------+-----------+---
2960 # sync prelude ENTER-to-ins ins-to-NEXT NEXT-to-video
2961 # |<-->|
2962 # 0/1 |<------->|
2963 # 5 |<----------------------------->|
2964 # runVCpu_overhead 28 |<--------->|
2965 # 2*maxTicks 9
2966 # vCPU_overhead
2967 #
2968 # 0 21 38=0 11
2969 # ---+----+---------+----------------+--------------------+-----------+---
2970 # video | nop| runVcpu | v6502_ENTER | At least one fetch |v6502_exitB| video
2971 # ---+----+---------+----------------+--------------------+-----------+---
2972 # sync prelude enter-to-fetch fetch-to-check check-to-video
2973 # |<-->|
2974 # 0/1 |<------->|
2975 # 5 |<----------------------------------->|
2976 # runVcpu_overhead 38 |<--------->|
2977 # 2*v6520_maxTicks 11
2978 # v6502_overhead
2979
2980 label('SYS_Run6502_v4_80')
SYS_Run6502_v4_80:
0b0c 140d ld $0d,y 2981 ld(hi('sys_v6502'),Y) #15
0b0d e07f jmp y,$7f 2982 jmp(Y,'sys_v6502') #16
0b0e 000d ld $0d 2983 ld(hi('v6502_ENTER')) #17 Activate v6502
2984
2985 #-----------------------------------------------------------------------
2986 # Extension SYS_ResetWaveforms_v4_50
2987 #-----------------------------------------------------------------------
2988
2989 # soundTable[4x+0] = sawtooth, to be modified into metallic/noise
2990 # soundTable[4x+1] = pulse
2991 # soundTable[4x+2] = triangle
2992 # soundTable[4x+3] = sawtooth, also useful to right shift 2 bits
2993
2994 label('SYS_ResetWaveforms_v4_50')
SYS_ResetWaveforms_v4_50:
0b0f 1412 ld $12,y 2995 ld(hi('sys_ResetWaveforms'),Y) #15 Initial setup of waveforms. [vAC+0]=i
0b10 e0ae jmp y,$ae 2996 jmp(Y,'sys_ResetWaveforms') #16
0b11 1407 ld $07,y 2997 ld(soundTable>>8,Y) #17
2998
2999 #-----------------------------------------------------------------------
3000 # Extension SYS_ShuffleNoise_v4_46
3001 #-----------------------------------------------------------------------
3002
3003 # Use simple 6-bits variation of RC4 to permutate waveform 0 in soundTable
3004
3005 label('SYS_ShuffleNoise_v4_46')
SYS_ShuffleNoise_v4_46:
0b12 1412 ld $12,y 3006 ld(hi('sys_ShuffleNoise'),Y) #15 Shuffle soundTable[4i+0]. [vAC+0]=4j, [vAC+1]=4i
0b13 e0cf jmp y,$cf 3007 jmp(Y,'sys_ShuffleNoise') #16
0b14 1407 ld $07,y 3008 ld(soundTable>>8,Y) #17
3009
3010 #-----------------------------------------------------------------------
3011 # Extension SYS_SpiExchangeBytes_v4_134
3012 #-----------------------------------------------------------------------
3013
3014 # Send AND receive 1..256 bytes over SPI interface
3015
3016 # Variables:
3017 # sysArgs[0] Page index start, for both send/receive (in, changed)
3018 # sysArgs[1] Memory page for send data (in)
3019 # sysArgs[2] Page index stop (in)
3020 # sysArgs[3] Memory page for receive data (in)
3021 # sysArgs[4] Scratch (changed)
3022
3023 label('SYS_SpiExchangeBytes_v4_134')
SYS_SpiExchangeBytes_v4_134:
0b15 140d ld $0d,y 3024 ld(hi('sys_SpiExchangeBytes'),Y)#15
0b16 e009 jmp y,$09 3025 jmp(Y,'sys_SpiExchangeBytes') #16
0b17 1401 ld $01,y 3026 ld(hi(ctrlBits),Y) #17 Control state as saved by SYS_ExpanderControl
3027
3028 #-----------------------------------------------------------------------
3029 # Implementations
3030 #-----------------------------------------------------------------------
3031
3032 # SYS_SetMemory_54 implementation
3033 label('sys_SetMemory#18')
sys_SetMemory#18:
0b18 1527 ld [$27],y 3034 ld([sysArgs+3],Y) #18
0b19 f83c ble .sysSb#21 3035 ble('.sysSb#21') #19 Enter fast lane if >=128 or at 0 (-> 256)
0b1a a008 suba $08 3036 suba(8) #20
0b1b f43e bge .sysSb#23 3037 bge('.sysSb#23') #21 Or when >=8
0b1c c224 st [$24] 3038 st([sysArgs+0]) #22
0b1d 2004 anda $04 3039 anda(4) #23
0b1e f025 beq .sysSb#26 3040 beq('.sysSb#26') #24
0b1f 0125 ld [$25] 3041 ld([sysArgs+1]) #25 Set 4 pixels
0b20 de00 st [y,x++] 3042 st([Y,Xpp]) #26
0b21 de00 st [y,x++] 3043 st([Y,Xpp]) #27
0b22 de00 st [y,x++] 3044 st([Y,Xpp]) #28
0b23 fc28 bra .sysSb#31 3045 bra('.sysSb#31') #29
0b24 de00 st [y,x++] 3046 st([Y,Xpp]) #30
3047 label('.sysSb#26')
.sysSb#26: 0b25 0001 ld $01 3048 wait(31-26) #26
0b26 ec26 bne $0b26
0b27 a001 suba $01
3049 label('.sysSb#31')
.sysSb#31: 0b28 0124 ld [$24] 3050 ld([sysArgs+0]) #31
0b29 2002 anda $02 3051 anda(2) #32
0b2a f02f beq .sysSb#35 3052 beq('.sysSb#35') #33
0b2b 0125 ld [$25] 3053 ld([sysArgs+1]) #34 Set 2 pixels
0b2c de00 st [y,x++] 3054 st([Y,Xpp]) #35
0b2d fc32 bra .sysSb#38 3055 bra('.sysSb#38') #36
0b2e de00 st [y,x++] 3056 st([Y,Xpp]) #37
3057 label('.sysSb#35')
.sysSb#35: 0b2f 0200 nop 3058 wait(38-35) #35
0b30 0200 nop
0b31 0200 nop
3059 label('.sysSb#38')
.sysSb#38: 0b32 0124 ld [$24] 3060 ld([sysArgs+0]) #38
0b33 2001 anda $01 3061 anda(1) #39
0b34 f037 beq $0b37 3062 beq(pc()+3) #40
0b35 fc38 bra $0b38 3063 bra(pc()+3) #41
0b36 0125 ld [$25] 3064 ld([sysArgs+1]) #42 Set 1 pixel
0b37 0d00 ld [y,x] 3065 ld([Y,X]) #42(!) No change
0b38 ce00 st [y,x] 3066 st([Y,X]) #43
0b39 1403 ld $03,y 3067 ld(hi('NEXTY'),Y) #44 Return
0b3a e000 jmp y,$00 3068 jmp(Y,'NEXTY') #45 All done
0b3b 00e8 ld $e8 3069 ld(-48/2) #46
3070 label('.sysSb#21')
.sysSb#21: 0b3c 0200 nop 3071 nop() #21
0b3d c224 st [$24] 3072 st([sysArgs+0]) #22
3073 label('.sysSb#23')
.sysSb#23: 0b3e 0125 ld [$25] 3074 ld([sysArgs+1]) #23 Set 8 pixels
0b3f de00 st [y,x++] 3075 st([Y,Xpp]) #24
0b40 de00 st [y,x++] 3076 st([Y,Xpp]) #25
0b41 de00 st [y,x++] 3077 st([Y,Xpp]) #26
0b42 de00 st [y,x++] 3078 st([Y,Xpp]) #27
0b43 de00 st [y,x++] 3079 st([Y,Xpp]) #28
0b44 de00 st [y,x++] 3080 st([Y,Xpp]) #29
0b45 de00 st [y,x++] 3081 st([Y,Xpp]) #30
0b46 de00 st [y,x++] 3082 st([Y,Xpp]) #31
0b47 0126 ld [$26] 3083 ld([sysArgs+2]) #32 Advance write pointer
0b48 8008 adda $08 3084 adda(8) #33
0b49 c226 st [$26] 3085 st([sysArgs+2]) #34
0b4a 0124 ld [$24] 3086 ld([sysArgs+0]) #35
0b4b f04e beq $0b4e 3087 beq(pc()+3) #36
0b4c fc4f bra $0b4f 3088 bra(pc()+3) #37
0b4d 00fe ld $fe 3089 ld(-2) #38 Self-restart when more to do
0b4e 0000 ld $00 3090 ld(0) #38(!)
0b4f 8116 adda [$16] 3091 adda([vPC]) #39
0b50 c216 st [$16] 3092 st([vPC]) #40
0b51 1403 ld $03,y 3093 ld(hi('REENTER'),Y) #41
0b52 e0cb jmp y,$cb 3094 jmp(Y,'REENTER') #42
0b53 00e9 ld $e9 3095 ld(-46/2) #43
3096
3097 # SYS_SetMode_80 implementation
3098 label('sys_SetMode')
sys_SetMode: 0b54 ec57 bne $0b57 3099 bne(pc()+3) #18
0b55 fc57 bra $0b57 3100 bra(pc()+2) #19
0b56 0003 ld $03 3101 ld('startVideo') #20 First enable video if disabled
0b57 c21e st [$1e] 3102 st([vReturn]) #20,21
0b58 0119 ld [$19] 3103 ld([vAC+1]) #22
0b59 f063 beq .sysSm#25 3104 beq('.sysSm#25') #23
0b5a 1403 ld $03,y 3105 ld(hi('REENTER'),Y) #24
0b5b 6118 xora [$18] 3106 xora([vAC]) #25
0b5c 60b0 xora $b0 3107 xora((1975>>8)^(1975&255)) #26 Poor man\'s 1975 detection
0b5d ec60 bne $0b60 3108 bne(pc()+3) #27
0b5e fc61 bra $0b61 3109 bra(pc()+3) #28
3110 assert videoZ == 0x0100
0b5f c21e st [$1e] 3111 st([vReturn]) #29 DISABLE video/audio/serial/etc
0b60 0200 nop 3112 nop() #29(!) Ignore and return
0b61 e0cb jmp y,$cb 3113 jmp(Y,'REENTER') #30
0b62 00ef ld $ef 3114 ld(-34/2) #31
3115 label('.sysSm#25')
.sysSm#25: 0b63 0118 ld [$18] 3116 ld([vAC]) #25 Mode 0,1,2,3
0b64 2003 anda $03 3117 anda(3) #26
0b65 8068 adda $68 3118 adda('.sysSm#30') #27
0b66 fe00 bra ac 3119 bra(AC) #28
0b67 fc6c bra .sysSm#31 3120 bra('.sysSm#31') #29
3121 label('.sysSm#30')
.sysSm#30: 0b68 000a ld $0a 3122 ld('pixels') #30 videoB lines
0b69 000a ld $0a 3123 ld('pixels') #30
0b6a 00f6 ld $f6 3124 ld('nopixels') #30
0b6b 00f6 ld $f6 3125 ld('nopixels') #30
3126 label('.sysSm#31')
.sysSm#31: 0b6c c20a st [$0a] 3127 st([videoModeB]) #31
0b6d 0118 ld [$18] 3128 ld([vAC]) #32
0b6e 2003 anda $03 3129 anda(3) #33
0b6f 8072 adda $72 3130 adda('.sysSm#37') #34
0b70 fe00 bra ac 3131 bra(AC) #35
0b71 fc76 bra .sysSm#38 3132 bra('.sysSm#38') #36
3133 label('.sysSm#37')
.sysSm#37: 0b72 000a ld $0a 3134 ld('pixels') #37 videoC lines
0b73 000a ld $0a 3135 ld('pixels') #37
0b74 000a ld $0a 3136 ld('pixels') #37
0b75 00f6 ld $f6 3137 ld('nopixels') #37
3138 label('.sysSm#38')
.sysSm#38: 0b76 c20b st [$0b] 3139 st([videoModeC]) #38
0b77 0118 ld [$18] 3140 ld([vAC]) #39
0b78 2003 anda $03 3141 anda(3) #40
0b79 807c adda $7c 3142 adda('.sysSm#44') #41
0b7a fe00 bra ac 3143 bra(AC) #42
0b7b fc80 bra .sysSm#45 3144 bra('.sysSm#45') #43
3145 label('.sysSm#44')
.sysSm#44: 0b7c 000a ld $0a 3146 ld('pixels') #44 videoD lines
0b7d 00f6 ld $f6 3147 ld('nopixels') #44
0b7e 00f6 ld $f6 3148 ld('nopixels') #44
0b7f 00f6 ld $f6 3149 ld('nopixels') #44
3150 label('.sysSm#45')
.sysSm#45: 0b80 c20c st [$0c] 3151 st([videoModeD]) #45
0b81 e0cb jmp y,$cb 3152 jmp(Y,'REENTER') #46
0b82 00e7 ld $e7 3153 ld(-50/2) #47
3154
3155 # SYS_SendSerial1_v3_80 implementation
3156 label('sys_SendSerial1')
sys_SendSerial1:
0b83 f08a beq .sysSs#20 3157 beq('.sysSs#20') #18
0b84 1124 ld [$24],x 3158 ld([sysArgs+0],X) #19
0b85 0116 ld [$16] 3159 ld([vPC]) #20 Wait for vBlank
0b86 a002 suba $02 3160 suba(2) #21
0b87 1403 ld $03,y 3161 ld(hi('REENTER_28'),Y) #22
0b88 e0ca jmp y,$ca 3162 jmp(Y,'REENTER_28') #23
0b89 c216 st [$16] 3163 st([vPC]) #24
3164 label('.sysSs#20')
.sysSs#20: 0b8a 1525 ld [$25],y 3165 ld([sysArgs+1],Y) #20 Synchronized with vBlank
0b8b 0d00 ld [y,x] 3166 ld([Y,X]) #21 Copy next bit
0b8c 2126 anda [$26] 3167 anda([sysArgs+2]) #22
0b8d ec90 bne $0b90 3168 bne(pc()+3) #23
0b8e fc91 bra $0b91 3169 bra(pc()+3) #24
0b8f 000e ld $0e 3170 ld(7*2) #25
0b90 0012 ld $12 3171 ld(9*2) #25
0b91 c20d st [$0d] 3172 st([videoPulse]) #26
0b92 0126 ld [$26] 3173 ld([sysArgs+2]) #27 Rotate input bit
0b93 8200 adda ac 3174 adda(AC) #28
0b94 ec97 bne $0b97 3175 bne(pc()+3) #29
0b95 fc97 bra $0b97 3176 bra(pc()+2) #30
0b96 0001 ld $01 3177 ld(1) #31
0b97 c226 st [$26] 3178 st([sysArgs+2]) #31,32 (must be idempotent)
0b98 2001 anda $01 3179 anda(1) #33 Optionally increment pointer
0b99 8124 adda [$24] 3180 adda([sysArgs+0]) #34
0b9a d224 st [$24],x 3181 st([sysArgs+0],X) #35
0b9b 0127 ld [$27] 3182 ld([sysArgs+3]) #36 Frame counter
0b9c a001 suba $01 3183 suba(1) #37
0b9d f0ac beq .sysSs#40 3184 beq('.sysSs#40') #38
0b9e 1403 ld $03,y 3185 ld(hi('REENTER'),Y) #39
0b9f c227 st [$27] 3186 st([sysArgs+3]) #40
0ba0 010f ld [$0f] 3187 ld([serialRaw]) #41 Test for anything being sent back
0ba1 60ff xora $ff 3188 xora(255) #42
0ba2 f0a7 beq .sysSs#45 3189 beq('.sysSs#45') #43
0ba3 c218 st [$18] 3190 st([vAC]) #44 Abort after key press with non-zero error
0ba4 c219 st [$19] 3191 st([vAC+1]) #45
0ba5 e0cb jmp y,$cb 3192 jmp(Y,'REENTER') #46
0ba6 00e7 ld $e7 3193 ld(-50/2) #47
3194 label('.sysSs#45')
.sysSs#45: 0ba7 0116 ld [$16] 3195 ld([vPC]) #45 Continue sending bits
0ba8 a002 suba $02 3196 suba(2) #46
0ba9 c216 st [$16] 3197 st([vPC]) #47
0baa e0cb jmp y,$cb 3198 jmp(Y,'REENTER') #48
0bab 00e6 ld $e6 3199 ld(-52/2) #49
3200 label('.sysSs#40')
.sysSs#40: 0bac c218 st [$18] 3201 st([vAC]) #40 Stop sending bits, no error
0bad c219 st [$19] 3202 st([vAC+1]) #41
0bae e0cb jmp y,$cb 3203 jmp(Y,'REENTER') #42
0baf 00e9 ld $e9 3204 ld(-46/2) #43
3205
3206 # CALLI implementation (vCPU instruction)
3207 label('calli#13')
calli#13: 0bb0 8003 adda $03 3208 adda(3) #13,43
0bb1 c21a st [$1a] 3209 st([vLR]) #14
0bb2 0117 ld [$17] 3210 ld([vPC+1]) #15
0bb3 d61b st [$1b],y 3211 st([vLR+1],Y) #16
0bb4 0d00 ld [y,x] 3212 ld([Y,X]) #17
0bb5 de00 st [y,x++] 3213 st([Y,Xpp]) #18 Just X++
0bb6 a002 suba $02 3214 suba(2) #19
0bb7 c216 st [$16] 3215 st([vPC]) #20
0bb8 0d00 ld [y,x] 3216 ld([Y,X]) #21
0bb9 1403 ld $03,y 3217 ld(hi('REENTER_28'),Y) #22
0bba e0ca jmp y,$ca 3218 jmp(Y,'REENTER_28') #23
0bbb c217 st [$17] 3219 st([vPC+1]) #24
3220
3221 # -------------------------------------------------------------
3222 # vCPU instructions for comparisons between two 16-bit operands
3223 # -------------------------------------------------------------
3224 #
3225 # vCPU's conditional branching (BCC) always compares vAC against 0,
3226 # treating vAC as a two's complement 16-bit number. When we need to
3227 # compare two arbitrary numnbers we normally first take their difference
3228 # with SUBW. However, when this difference is too large, the subtraction
3229 # overflows and we get the wrong outcome. To get it right over the
3230 # entire range, an elaborate sequence is needed. TinyBASIC uses this
3231 # blurp for its relational operators. (It compares stack variable $02
3232 # with zero page variable $3a.)
3233 #
3234 # 0461 ee 02 LDLW $02
3235 # 0463 fc 3a XORW $3a
3236 # 0465 35 53 6a BGE $046c
3237 # 0468 ee 02 LDLW $02
3238 # 046a 90 6e BRA $0470
3239 # 046c ee 02 LDLW $02
3240 # 046e b8 3a SUBW $3a
3241 # 0470 35 56 73 BLE $0475
3242 #
3243 # The CMPHS and CMPHU instructions were introduced to simplify this.
3244 # They inspect both operands to see if there is an overflow risk. If
3245 # so, they modify vAC such that their difference gets smaller, while
3246 # preserving the relation between the two operands. After that, the
3247 # SUBW instruction can't overflow and we achieve a correct comparison.
3248 # Use CMPHS for signed comparisons and CMPHU for unsigned. With these,
3249 # the sequence above becomes:
3250 #
3251 # 0461 ee 02 LDLW $02
3252 # 0463 1f 3b CMPHS $3b Note: high byte of operand
3253 # 0465 b8 3a SUBW $3a
3254 # 0467 35 56 73 BLE $0475
3255 #
3256 # CMPHS/CMPHU don't make much sense other than in combination with
3257 # SUBW. These modify vACH, if needed, as given in the following table:
3258 #
3259 # vACH varH | vACH
3260 # bit7 bit7 | CMPHS CMPHU
3261 # ---------------------------
3262 # 0 0 | vACH vACH no change needed
3263 # 0 1 | varH+1 varH-1 narrowing the range
3264 # 1 0 | varH-1 varH+1 narrowing the range
3265 # 1 1 | vACH vACH no change needed
3266 # ---------------------------
3267
3268 # CMPHS implementation (vCPU instruction)
3269 label('cmphs#13')
cmphs#13: 0bbc 1403 ld $03,y 3270 ld(hi('REENTER'),Y) #13
0bbd 0500 ld [x] 3271 ld([X]) #14
0bbe 6119 xora [$19] 3272 xora([vAC+1]) #15
0bbf f4d0 bge .cmphu#18 3273 bpl('.cmphu#18') #16 Skip if same sign
0bc0 0119 ld [$19] 3274 ld([vAC+1]) #17
0bc1 e8c4 blt $0bc4 3275 bmi(pc()+3) #18
0bc2 fcc5 bra .cmphs#21 3276 bra(pc()+3) #19
3277 label('.cmphs#20')
.cmphs#20: 0bc3 0001 ld $01 3278 ld(+1) #20 vAC < variable
0bc4 00ff ld $ff 3279 ld(-1) #20(!) vAC > variable
3280 label('.cmphs#21')
.cmphs#21: 0bc5 8500 adda [x] 3281 adda([X]) #21
0bc6 c219 st [$19] 3282 st([vAC+1]) #22
0bc7 e0ca jmp y,$ca 3283 jmp(Y,'REENTER_28') #23
3284 #dummy() #24 Overlap
3285 #
3286 # CMPHS implementation (vCPU instruction)
3287 label('cmphu#13')
cmphu#13: 0bc8 1403 ld $03,y 3288 ld(hi('REENTER'),Y) #13,24
0bc9 0500 ld [x] 3289 ld([X]) #14
0bca 6119 xora [$19] 3290 xora([vAC+1]) #15
0bcb f4d0 bge .cmphu#18 3291 bpl('.cmphu#18') #16 Skip if same sign
0bcc 0119 ld [$19] 3292 ld([vAC+1]) #17
0bcd e8c3 blt .cmphs#20 3293 bmi('.cmphs#20') #18
0bce fcc5 bra .cmphs#21 3294 bra('.cmphs#21') #19
0bcf 00ff ld $ff 3295 ld(-1) #20 vAC > variable
3296
3297 # No-operation for CMPHS/CMPHU when high bits are equal
3298 label('.cmphu#18')
.cmphu#18: 0bd0 e0cb jmp y,$cb 3299 jmp(Y,'REENTER') #18
0bd1 00f5 ld $f5 3300 ld(-22/2) #19
3301
3302 #-----------------------------------------------------------------------
3303 #
3304 # $0c00 ROM page 12: More SYS functions (sprites)
3305 #
3306 # Page 1: vertical blank interval
3307 # Page 2: visible scanlines
3308 #
3309 #-----------------------------------------------------------------------
3310
0bd2 0200 nop 3311 align(0x100, size=0x100)
0bd3 0200 nop
0bd4 0200 nop
* 46 times
3312
3313 #-----------------------------------------------------------------------
3314 # Extension SYS_Sprite6_v3_64
3315 # Extension SYS_Sprite6x_v3_64
3316 # Extension SYS_Sprite6y_v3_64
3317 # Extension SYS_Sprite6xy_v3_64
3318 #-----------------------------------------------------------------------
3319
3320 # Blit sprite in screen memory
3321 #
3322 # Variables
3323 # vAC Destination address in screen
3324 # sysArgs[0:1] Source address of 6xY pixels (colors 0..63) terminated
3325 # by negative byte value N (typically N = -Y)
3326 # sysArgs[2:7] Scratch (user as copy buffer)
3327 #
3328 # This SYS function draws a sprite of 6 pixels wide and Y pixels high.
3329 # The pixel data is read sequentually from RAM, in horizontal chunks
3330 # of 6 pixels at a time, and then written to the screen through the
3331 # destination pointer (each chunk underneath the previous), thus
3332 # drawing a 6xY stripe. Pixel values should be non-negative. The first
3333 # negative byte N after a chunk signals the end of the sprite data.
3334 # So the sprite's height Y is determined by the source data and is
3335 # therefore flexible. This negative byte value, typically N == -Y,
3336 # is then used to adjust the destination pointer's high byte, to make
3337 # it easier to draw sprites wider than 6 pixels: just repeat the SYS
3338 # call for as many 6-pixel wide stripes you need. All arguments are
3339 # already left in place to facilitate this. After one call, the source
3340 # pointer will point past that source data, effectively:
3341 # src += Y * 6 + 1
3342 # The destination pointer will have been adjusted as:
3343 # dst += (Y + N) * 256 + 6
3344 # (With arithmetic wrapping around on the same memory page)
3345 #
3346 # Y is only limited by source memory, not by CPU cycles. The
3347 # implementation is such that the SYS function self-repeats, each
3348 # time drawing the next 6-pixel chunk. It can typically draw 12
3349 # pixels per scanline this way.
3350
3351 label('SYS_Sprite6_v3_64')
3352
SYS_Sprite6_v3_64:
0c00 1124 ld [$24],x 3353 ld([sysArgs+0],X) #15 Pixel data source address
0c01 1525 ld [$25],y 3354 ld([sysArgs+1],Y) #16
0c02 0d00 ld [y,x] 3355 ld([Y,X]) #17 Next pixel or stop
0c03 f411 bge .sysDpx0 3356 bpl('.sysDpx0') #18
0c04 de00 st [y,x++] 3357 st([Y,Xpp]) #19 Just X++
3358
0c05 8119 adda [$19] 3359 adda([vAC+1]) #20 Adjust dst for convenience
0c06 c219 st [$19] 3360 st([vAC+1]) #21
0c07 0118 ld [$18] 3361 ld([vAC]) #22
0c08 8006 adda $06 3362 adda(6) #23
0c09 c218 st [$18] 3363 st([vAC]) #24
0c0a 0124 ld [$24] 3364 ld([sysArgs+0]) #25 Adjust src for convenience
0c0b 8001 adda $01 3365 adda(1) #26
0c0c c224 st [$24] 3366 st([sysArgs+0]) #27
0c0d 0200 nop 3367 nop() #28
0c0e 1403 ld $03,y 3368 ld(hi('REENTER'),Y) #29 Normal exit (no self-repeat)
0c0f e0cb jmp y,$cb 3369 jmp(Y,'REENTER') #30
0c10 00ef ld $ef 3370 ld(-34/2) #31
3371
3372 label('.sysDpx0')
.sysDpx0: 0c11 c226 st [$26] 3373 st([sysArgs+2]) #20 Gobble 6 pixels into buffer
0c12 0d00 ld [y,x] 3374 ld([Y,X]) #21
0c13 de00 st [y,x++] 3375 st([Y,Xpp]) #22 Just X++
0c14 c227 st [$27] 3376 st([sysArgs+3]) #23
0c15 0d00 ld [y,x] 3377 ld([Y,X]) #24
0c16 de00 st [y,x++] 3378 st([Y,Xpp]) #25 Just X++
0c17 c228 st [$28] 3379 st([sysArgs+4]) #26
0c18 0d00 ld [y,x] 3380 ld([Y,X]) #27
0c19 de00 st [y,x++] 3381 st([Y,Xpp]) #28 Just X++
0c1a c229 st [$29] 3382 st([sysArgs+5]) #29
0c1b 0d00 ld [y,x] 3383 ld([Y,X]) #30
0c1c de00 st [y,x++] 3384 st([Y,Xpp]) #31 Just X++
0c1d c22a st [$2a] 3385 st([sysArgs+6]) #32
0c1e 0d00 ld [y,x] 3386 ld([Y,X]) #33
0c1f de00 st [y,x++] 3387 st([Y,Xpp]) #34 Just X++
0c20 c22b st [$2b] 3388 st([sysArgs+7]) #35
3389
0c21 1118 ld [$18],x 3390 ld([vAC],X) #36 Screen memory destination address
0c22 1519 ld [$19],y 3391 ld([vAC+1],Y) #37
0c23 0126 ld [$26] 3392 ld([sysArgs+2]) #38 Write 6 pixels
0c24 de00 st [y,x++] 3393 st([Y,Xpp]) #39
0c25 0127 ld [$27] 3394 ld([sysArgs+3]) #40
0c26 de00 st [y,x++] 3395 st([Y,Xpp]) #41
0c27 0128 ld [$28] 3396 ld([sysArgs+4]) #42
0c28 de00 st [y,x++] 3397 st([Y,Xpp]) #43
0c29 0129 ld [$29] 3398 ld([sysArgs+5]) #44
0c2a de00 st [y,x++] 3399 st([Y,Xpp]) #45
0c2b 012a ld [$2a] 3400 ld([sysArgs+6]) #46
0c2c de00 st [y,x++] 3401 st([Y,Xpp]) #47
0c2d 012b ld [$2b] 3402 ld([sysArgs+7]) #48
0c2e de00 st [y,x++] 3403 st([Y,Xpp]) #49
3404
0c2f 0124 ld [$24] 3405 ld([sysArgs+0]) #50 src += 6
0c30 8006 adda $06 3406 adda(6) #51
0c31 c224 st [$24] 3407 st([sysArgs+0]) #52
0c32 0119 ld [$19] 3408 ld([vAC+1]) #53 dst += 256
0c33 8001 adda $01 3409 adda(1) #54
0c34 c219 st [$19] 3410 st([vAC+1]) #55
3411
0c35 0116 ld [$16] 3412 ld([vPC]) #56 Self-repeating SYS call
0c36 a002 suba $02 3413 suba(2) #57
0c37 c216 st [$16] 3414 st([vPC]) #58
0c38 1403 ld $03,y 3415 ld(hi('REENTER'),Y) #59
0c39 e0cb jmp y,$cb 3416 jmp(Y,'REENTER') #60
0c3a 00e0 ld $e0 3417 ld(-64/2) #61
3418
0c3b 0200 nop 3419 align(64)
0c3c 0200 nop
0c3d 0200 nop
* 5 times
3420 label('SYS_Sprite6x_v3_64')
3421
SYS_Sprite6x_v3_64:
0c40 1124 ld [$24],x 3422 ld([sysArgs+0],X) #15 Pixel data source address
0c41 1525 ld [$25],y 3423 ld([sysArgs+1],Y) #16
0c42 0d00 ld [y,x] 3424 ld([Y,X]) #17 Next pixel or stop
0c43 f451 bge .sysDpx1 3425 bpl('.sysDpx1') #18
0c44 de00 st [y,x++] 3426 st([Y,Xpp]) #19 Just X++
3427
0c45 8119 adda [$19] 3428 adda([vAC+1]) #20 Adjust dst for convenience
0c46 c219 st [$19] 3429 st([vAC+1]) #21
0c47 0118 ld [$18] 3430 ld([vAC]) #22
0c48 a006 suba $06 3431 suba(6) #23
0c49 c218 st [$18] 3432 st([vAC]) #24
0c4a 0124 ld [$24] 3433 ld([sysArgs+0]) #25 Adjust src for convenience
0c4b 8001 adda $01 3434 adda(1) #26
0c4c c224 st [$24] 3435 st([sysArgs+0]) #27
0c4d 0200 nop 3436 nop() #28
0c4e 1403 ld $03,y 3437 ld(hi('REENTER'),Y) #29 Normal exit (no self-repeat)
0c4f e0cb jmp y,$cb 3438 jmp(Y,'REENTER') #30
0c50 00ef ld $ef 3439 ld(-34/2) #31
3440
3441 label('.sysDpx1')
.sysDpx1: 0c51 c22b st [$2b] 3442 st([sysArgs+7]) #20 Gobble 6 pixels into buffer (backwards)
0c52 0d00 ld [y,x] 3443 ld([Y,X]) #21
0c53 de00 st [y,x++] 3444 st([Y,Xpp]) #22 Just X++
0c54 c22a st [$2a] 3445 st([sysArgs+6]) #23
0c55 0d00 ld [y,x] 3446 ld([Y,X]) #24
0c56 de00 st [y,x++] 3447 st([Y,Xpp]) #25 Just X++
0c57 c229 st [$29] 3448 st([sysArgs+5]) #26
0c58 0d00 ld [y,x] 3449 ld([Y,X]) #27
0c59 de00 st [y,x++] 3450 st([Y,Xpp]) #28 Just X++
0c5a c228 st [$28] 3451 st([sysArgs+4]) #29
0c5b 0d00 ld [y,x] 3452 ld([Y,X]) #30
0c5c de00 st [y,x++] 3453 st([Y,Xpp]) #31 Just X++
0c5d c227 st [$27] 3454 st([sysArgs+3]) #32
0c5e 0d00 ld [y,x] 3455 ld([Y,X]) #33
0c5f de00 st [y,x++] 3456 st([Y,Xpp]) #34 Just X++
3457
0c60 1118 ld [$18],x 3458 ld([vAC],X) #35 Screen memory destination address
0c61 1519 ld [$19],y 3459 ld([vAC+1],Y) #36
0c62 de00 st [y,x++] 3460 st([Y,Xpp]) #37 Write 6 pixels
0c63 0127 ld [$27] 3461 ld([sysArgs+3]) #38
0c64 de00 st [y,x++] 3462 st([Y,Xpp]) #39
0c65 0128 ld [$28] 3463 ld([sysArgs+4]) #40
0c66 de00 st [y,x++] 3464 st([Y,Xpp]) #41
0c67 0129 ld [$29] 3465 ld([sysArgs+5]) #42
0c68 de00 st [y,x++] 3466 st([Y,Xpp]) #43
0c69 012a ld [$2a] 3467 ld([sysArgs+6]) #44
0c6a de00 st [y,x++] 3468 st([Y,Xpp]) #45
0c6b 012b ld [$2b] 3469 ld([sysArgs+7]) #46
0c6c de00 st [y,x++] 3470 st([Y,Xpp]) #47
3471
0c6d 0124 ld [$24] 3472 ld([sysArgs+0]) #48 src += 6
0c6e 8006 adda $06 3473 adda(6) #49
0c6f c224 st [$24] 3474 st([sysArgs+0]) #50
0c70 0119 ld [$19] 3475 ld([vAC+1]) #51 dst += 256
0c71 8001 adda $01 3476 adda(1) #52
0c72 c219 st [$19] 3477 st([vAC+1]) #53
3478
0c73 0116 ld [$16] 3479 ld([vPC]) #54 Self-repeating SYS call
0c74 a002 suba $02 3480 suba(2) #55
0c75 c216 st [$16] 3481 st([vPC]) #56
0c76 1403 ld $03,y 3482 ld(hi('REENTER'),Y) #57
0c77 e0cb jmp y,$cb 3483 jmp(Y,'REENTER') #58
0c78 00e1 ld $e1 3484 ld(-62/2) #59
3485
0c79 0200 nop 3486 align(64)
0c7a 0200 nop
0c7b 0200 nop
* 7 times
3487 label('SYS_Sprite6y_v3_64')
3488
SYS_Sprite6y_v3_64:
0c80 1124 ld [$24],x 3489 ld([sysArgs+0],X) #15 Pixel data source address
0c81 1525 ld [$25],y 3490 ld([sysArgs+1],Y) #16
0c82 0d00 ld [y,x] 3491 ld([Y,X]) #17 Next pixel or stop
0c83 f493 bge .sysDpx2 3492 bpl('.sysDpx2') #18
0c84 de00 st [y,x++] 3493 st([Y,Xpp]) #19 Just X++
3494
0c85 60ff xora $ff 3495 xora(255) #20 Adjust dst for convenience
0c86 8001 adda $01 3496 adda(1) #21
0c87 8119 adda [$19] 3497 adda([vAC+1]) #22
0c88 c219 st [$19] 3498 st([vAC+1]) #23
0c89 0118 ld [$18] 3499 ld([vAC]) #24
0c8a 8006 adda $06 3500 adda(6) #25
0c8b c218 st [$18] 3501 st([vAC]) #26
0c8c 0124 ld [$24] 3502 ld([sysArgs+0]) #27 Adjust src for convenience
0c8d 8001 adda $01 3503 adda(1) #28
0c8e c224 st [$24] 3504 st([sysArgs+0]) #29
0c8f 0200 nop 3505 nop() #30
0c90 1403 ld $03,y 3506 ld(hi('REENTER'),Y) #31 Normal exit (no self-repeat)
0c91 e0cb jmp y,$cb 3507 jmp(Y,'REENTER') #32
0c92 00ee ld $ee 3508 ld(-36/2) #33
3509
3510 label('.sysDpx2')
.sysDpx2: 0c93 c226 st [$26] 3511 st([sysArgs+2]) #20 Gobble 6 pixels into buffer
0c94 0d00 ld [y,x] 3512 ld([Y,X]) #21
0c95 de00 st [y,x++] 3513 st([Y,Xpp]) #22 Just X++
0c96 c227 st [$27] 3514 st([sysArgs+3]) #23
0c97 0d00 ld [y,x] 3515 ld([Y,X]) #24
0c98 de00 st [y,x++] 3516 st([Y,Xpp]) #25 Just X++
0c99 c228 st [$28] 3517 st([sysArgs+4]) #26
0c9a 0d00 ld [y,x] 3518 ld([Y,X]) #27
0c9b de00 st [y,x++] 3519 st([Y,Xpp]) #28 Just X++
0c9c c229 st [$29] 3520 st([sysArgs+5]) #29
0c9d 0d00 ld [y,x] 3521 ld([Y,X]) #30
0c9e de00 st [y,x++] 3522 st([Y,Xpp]) #31 Just X++
0c9f c22a st [$2a] 3523 st([sysArgs+6]) #32
0ca0 0d00 ld [y,x] 3524 ld([Y,X]) #33
0ca1 de00 st [y,x++] 3525 st([Y,Xpp]) #34 Just X++
0ca2 c22b st [$2b] 3526 st([sysArgs+7]) #35
3527
0ca3 1118 ld [$18],x 3528 ld([vAC],X) #36 Screen memory destination address
0ca4 1519 ld [$19],y 3529 ld([vAC+1],Y) #37
0ca5 0126 ld [$26] 3530 ld([sysArgs+2]) #38 Write 6 pixels
0ca6 de00 st [y,x++] 3531 st([Y,Xpp]) #39
0ca7 0127 ld [$27] 3532 ld([sysArgs+3]) #40
0ca8 de00 st [y,x++] 3533 st([Y,Xpp]) #41
0ca9 0128 ld [$28] 3534 ld([sysArgs+4]) #42
0caa de00 st [y,x++] 3535 st([Y,Xpp]) #43
0cab 0129 ld [$29] 3536 ld([sysArgs+5]) #44
0cac de00 st [y,x++] 3537 st([Y,Xpp]) #45
0cad 012a ld [$2a] 3538 ld([sysArgs+6]) #46
0cae de00 st [y,x++] 3539 st([Y,Xpp]) #47
0caf 012b ld [$2b] 3540 ld([sysArgs+7]) #48
0cb0 de00 st [y,x++] 3541 st([Y,Xpp]) #49
3542
0cb1 0124 ld [$24] 3543 ld([sysArgs+0]) #50 src += 6
0cb2 8006 adda $06 3544 adda(6) #51
0cb3 c224 st [$24] 3545 st([sysArgs+0]) #52
0cb4 0119 ld [$19] 3546 ld([vAC+1]) #53 dst -= 256
0cb5 a001 suba $01 3547 suba(1) #54
0cb6 c219 st [$19] 3548 st([vAC+1]) #55
3549
0cb7 0116 ld [$16] 3550 ld([vPC]) #56 Self-repeating SYS call
0cb8 a002 suba $02 3551 suba(2) #57
0cb9 c216 st [$16] 3552 st([vPC]) #58
0cba 1403 ld $03,y 3553 ld(hi('REENTER'),Y) #59
0cbb e0cb jmp y,$cb 3554 jmp(Y,'REENTER') #60
0cbc 00e0 ld $e0 3555 ld(-64/2) #61
3556
0cbd 0200 nop 3557 align(64)
0cbe 0200 nop
0cbf 0200 nop
3558 label('SYS_Sprite6xy_v3_64')
3559
SYS_Sprite6xy_v3_64:
0cc0 1124 ld [$24],x 3560 ld([sysArgs+0],X) #15 Pixel data source address
0cc1 1525 ld [$25],y 3561 ld([sysArgs+1],Y) #16
0cc2 0d00 ld [y,x] 3562 ld([Y,X]) #17 Next pixel or stop
0cc3 f4d3 bge .sysDpx3 3563 bpl('.sysDpx3') #18
0cc4 de00 st [y,x++] 3564 st([Y,Xpp]) #19 Just X++
3565
0cc5 60ff xora $ff 3566 xora(255) #20 Adjust dst for convenience
0cc6 8001 adda $01 3567 adda(1) #21
0cc7 8119 adda [$19] 3568 adda([vAC+1]) #22
0cc8 c219 st [$19] 3569 st([vAC+1]) #23
0cc9 0118 ld [$18] 3570 ld([vAC]) #24
0cca a006 suba $06 3571 suba(6) #25
0ccb c218 st [$18] 3572 st([vAC]) #26
0ccc 0124 ld [$24] 3573 ld([sysArgs+0]) #27 Adjust src for convenience
0ccd 8001 adda $01 3574 adda(1) #28
0cce c224 st [$24] 3575 st([sysArgs+0]) #29
0ccf 0200 nop 3576 nop() #30
0cd0 1403 ld $03,y 3577 ld(hi('REENTER'),Y) #31 Normal exit (no self-repeat)
0cd1 e0cb jmp y,$cb 3578 jmp(Y,'REENTER') #32
0cd2 00ee ld $ee 3579 ld(-36/2) #33
3580
3581 label('.sysDpx3')
.sysDpx3: 0cd3 c22b st [$2b] 3582 st([sysArgs+7]) #20 Gobble 6 pixels into buffer (backwards)
0cd4 0d00 ld [y,x] 3583 ld([Y,X]) #21
0cd5 de00 st [y,x++] 3584 st([Y,Xpp]) #22 Just X++
0cd6 c22a st [$2a] 3585 st([sysArgs+6]) #23
0cd7 0d00 ld [y,x] 3586 ld([Y,X]) #24
0cd8 de00 st [y,x++] 3587 st([Y,Xpp]) #25 Just X++
0cd9 c229 st [$29] 3588 st([sysArgs+5]) #26
0cda 0d00 ld [y,x] 3589 ld([Y,X]) #27
0cdb de00 st [y,x++] 3590 st([Y,Xpp]) #28 Just X++
0cdc c228 st [$28] 3591 st([sysArgs+4]) #29
0cdd 0d00 ld [y,x] 3592 ld([Y,X]) #30
0cde de00 st [y,x++] 3593 st([Y,Xpp]) #31 Just X++
0cdf c227 st [$27] 3594 st([sysArgs+3]) #32
0ce0 0d00 ld [y,x] 3595 ld([Y,X]) #33
0ce1 de00 st [y,x++] 3596 st([Y,Xpp]) #34 Just X++
3597
0ce2 1118 ld [$18],x 3598 ld([vAC],X) #35 Screen memory destination address
0ce3 1519 ld [$19],y 3599 ld([vAC+1],Y) #36
0ce4 de00 st [y,x++] 3600 st([Y,Xpp]) #37 Write 6 pixels
0ce5 0127 ld [$27] 3601 ld([sysArgs+3]) #38
0ce6 de00 st [y,x++] 3602 st([Y,Xpp]) #39
0ce7 0128 ld [$28] 3603 ld([sysArgs+4]) #40
0ce8 de00 st [y,x++] 3604 st([Y,Xpp]) #41
0ce9 0129 ld [$29] 3605 ld([sysArgs+5]) #42
0cea de00 st [y,x++] 3606 st([Y,Xpp]) #43
0ceb 012a ld [$2a] 3607 ld([sysArgs+6]) #44
0cec de00 st [y,x++] 3608 st([Y,Xpp]) #45
0ced 012b ld [$2b] 3609 ld([sysArgs+7]) #46
0cee de00 st [y,x++] 3610 st([Y,Xpp]) #47
3611
0cef 0124 ld [$24] 3612 ld([sysArgs+0]) #48 src += 6
0cf0 8006 adda $06 3613 adda(6) #49
0cf1 c224 st [$24] 3614 st([sysArgs+0]) #50
0cf2 0119 ld [$19] 3615 ld([vAC+1]) #51 dst -= 256
0cf3 a001 suba $01 3616 suba(1) #52
0cf4 c219 st [$19] 3617 st([vAC+1]) #53
3618
0cf5 0116 ld [$16] 3619 ld([vPC]) #54 Self-repeating SYS call
0cf6 a002 suba $02 3620 suba(2) #55
0cf7 c216 st [$16] 3621 st([vPC]) #56
0cf8 1403 ld $03,y 3622 ld(hi('REENTER'),Y) #57
0cf9 e0cb jmp y,$cb 3623 jmp(Y,'REENTER') #58
0cfa 00e1 ld $e1 3624 ld(-62/2) #59
3625
3626 #-----------------------------------------------------------------------
3627
3628 label('sys_ExpanderControl')
3629
sys_ExpanderControl:
0cfb 2118 anda [$18] 3630 anda([vAC]) #18
0cfc d218 st [$18],x 3631 st([vAC],X) #19
0cfd 1401 ld $01,y 3632 ld(hi(ctrlBits),Y) #20
0cfe caf8 st [y,$f8] 3633 st([Y,ctrlBits]) #21 Set control variable
0cff 1519 ld [$19],y 3634 ld([vAC+1],Y) #22 MOSI (A15)
0d00 cd00 ctrl y,x 3635 ctrl(Y,X) #23 Try set the expander control register
3636
0d01 0127 ld [$27] 3637 ld([sysArgs+3]) #24 Prepare for SYS_SpiExchangeBytes
3638 assert pc()&255 < 255-3 # Beware of page crossing: asm.py won't warn
0d02 ec05 bne $0d05 3639 bne(pc()+3) #25
0d03 fc05 bra $0d05 3640 bra(pc()+2) #26
0d04 0125 ld [$25] 3641 ld([sysArgs+1]) #27
0d05 c227 st [$27] 3642 st([sysArgs+3]) #27,28 (must be idempotent)
3643
0d06 1403 ld $03,y 3644 ld(hi('REENTER'),Y) #29
0d07 e0cb jmp y,$cb 3645 jmp(Y,'REENTER') #30
0d08 00ef ld $ef 3646 ld(-34/2) #31
3647
3648 #-----------------------------------------------------------------------
3649
3650 label('sys_SpiExchangeBytes')
3651
sys_SpiExchangeBytes:
0d09 09f8 ld [y,$f8] 3652 ld([Y,ctrlBits]) #18
0d0a c228 st [$28] 3653 st([sysArgs+4]) #19
3654
0d0b 1124 ld [$24],x 3655 ld([sysArgs+0],X) #20 Fetch byte to send
0d0c 1525 ld [$25],y 3656 ld([sysArgs+1],Y) #21
0d0d 0d00 ld [y,x] 3657 ld([Y,X]) #22
3658
3659 for i in range(8):
3660 st([vTmp],Y);C('Bit %d'%(7-i))#23+i*12
0d0e d61d st [$1d],y ;Bit 7
0d0f 1128 ld [$28],x 3661 ld([sysArgs+4],X) #24+i*12
0d10 dd00 ctrl y,x++ 3662 ctrl(Y,Xpp) #25+i*12 Set MOSI
0d11 dd00 ctrl y,x++ 3663 ctrl(Y,Xpp) #26+i*12 Raise SCLK, disable RAM!
0d12 0100 ld [$00] 3664 ld([0]) #27+i*12 Get MISO
0d13 200f anda $0f 3665 anda(0b00001111) #28+i*12 This is why R1 as pull-DOWN is simpler
0d14 f017 beq $0d17 3666 beq(pc()+3) #29+i*12
0d15 fc17 bra $0d17 3667 bra(pc()+2) #30+i*12
0d16 0001 ld $01 3668 ld(1) #31+i*12
0d17 cd00 ctrl y,x 3669 ctrl(Y,X) #32+i*12,29+i*12 (Must be idempotent) Lower SCLK
0d18 811d adda [$1d] 3670 adda([vTmp]) #33+i*12 Shift
0d19 811d adda [$1d] 3671 adda([vTmp]) #34+i*12
0d1a d61d st [$1d],y ;Bit 6
0d1b 1128 ld [$28],x
0d1c dd00 ctrl y,x++
0d1d dd00 ctrl y,x++
0d1e 0100 ld [$00]
0d1f 200f anda $0f
0d20 f023 beq $0d23
0d21 fc23 bra $0d23
0d22 0001 ld $01
0d23 cd00 ctrl y,x
0d24 811d adda [$1d]
0d25 811d adda [$1d]
0d26 d61d st [$1d],y ;Bit 5
0d27 1128 ld [$28],x
0d28 dd00 ctrl y,x++
0d29 dd00 ctrl y,x++
0d2a 0100 ld [$00]
0d2b 200f anda $0f
0d2c f02f beq $0d2f
0d2d fc2f bra $0d2f
0d2e 0001 ld $01
0d2f cd00 ctrl y,x
0d30 811d adda [$1d]
0d31 811d adda [$1d]
0d32 d61d st [$1d],y ;Bit 4
0d33 1128 ld [$28],x
0d34 dd00 ctrl y,x++
0d35 dd00 ctrl y,x++
0d36 0100 ld [$00]
0d37 200f anda $0f
0d38 f03b beq $0d3b
0d39 fc3b bra $0d3b
0d3a 0001 ld $01
0d3b cd00 ctrl y,x
0d3c 811d adda [$1d]
0d3d 811d adda [$1d]
0d3e d61d st [$1d],y ;Bit 3
0d3f 1128 ld [$28],x
0d40 dd00 ctrl y,x++
0d41 dd00 ctrl y,x++
0d42 0100 ld [$00]
0d43 200f anda $0f
0d44 f047 beq $0d47
0d45 fc47 bra $0d47
0d46 0001 ld $01
0d47 cd00 ctrl y,x
0d48 811d adda [$1d]
0d49 811d adda [$1d]
0d4a d61d st [$1d],y ;Bit 2
0d4b 1128 ld [$28],x
0d4c dd00 ctrl y,x++
0d4d dd00 ctrl y,x++
0d4e 0100 ld [$00]
0d4f 200f anda $0f
0d50 f053 beq $0d53
0d51 fc53 bra $0d53
0d52 0001 ld $01
0d53 cd00 ctrl y,x
0d54 811d adda [$1d]
0d55 811d adda [$1d]
0d56 d61d st [$1d],y ;Bit 1
0d57 1128 ld [$28],x
0d58 dd00 ctrl y,x++
0d59 dd00 ctrl y,x++
0d5a 0100 ld [$00]
0d5b 200f anda $0f
0d5c f05f beq $0d5f
0d5d fc5f bra $0d5f
0d5e 0001 ld $01
0d5f cd00 ctrl y,x
0d60 811d adda [$1d]
0d61 811d adda [$1d]
0d62 d61d st [$1d],y ;Bit 0
0d63 1128 ld [$28],x
0d64 dd00 ctrl y,x++
0d65 dd00 ctrl y,x++
0d66 0100 ld [$00]
0d67 200f anda $0f
0d68 f06b beq $0d6b
0d69 fc6b bra $0d6b
0d6a 0001 ld $01
0d6b cd00 ctrl y,x
0d6c 811d adda [$1d]
0d6d 811d adda [$1d]
3672
0d6e 1124 ld [$24],x 3673 ld([sysArgs+0],X) #119 Store received byte
0d6f 1527 ld [$27],y 3674 ld([sysArgs+3],Y) #120
0d70 ce00 st [y,x] 3675 st([Y,X]) #121
3676
0d71 0124 ld [$24] 3677 ld([sysArgs+0]) #122 Advance pointer
0d72 8001 adda $01 3678 adda(1) #123
0d73 c224 st [$24] 3679 st([sysArgs+0]) #124
3680
0d74 6126 xora [$26] 3681 xora([sysArgs+2]) #125 Reached end?
0d75 f07c beq .sysSpi#128 3682 beq('.sysSpi#128') #126
3683
0d76 0116 ld [$16] 3684 ld([vPC]) #127 Self-repeating SYS call
0d77 a002 suba $02 3685 suba(2) #128
0d78 c216 st [$16] 3686 st([vPC]) #129
0d79 1403 ld $03,y 3687 ld(hi('NEXTY'),Y) #130
0d7a e000 jmp y,$00 3688 jmp(Y,'NEXTY') #131
0d7b 00bd ld $bd 3689 ld(-134/2) #132
3690
3691 label('.sysSpi#128')
.sysSpi#128: 0d7c 1403 ld $03,y 3692 ld(hi('NEXTY'),Y) #128 Continue program
0d7d e000 jmp y,$00 3693 jmp(Y,'NEXTY') #129
0d7e 00be ld $be 3694 ld(-132/2) #130
3695
3696 #-----------------------------------------------------------------------
3697
3698 label('sys_v6502')
3699
sys_v6502: 0d7f d605 st [$05],y 3700 st([vCpuSelect],Y) #18 Activate v6502
0d80 00f5 ld $f5 3701 ld(-22/2) #19
0d81 e0ff jmp y,$ff 3702 jmp(Y,'v6502_ENTER') #20 Transfer control in the same time slice
0d82 8115 adda [$15] 3703 adda([vTicks]) #21
3704 assert (38 - 22)//2 >= v6502_adjust
3705
3706 #-----------------------------------------------------------------------
3707 # MOS 6502 emulator
3708 #-----------------------------------------------------------------------
3709
3710 # Some quirks:
3711 # - Stack in zero page instead of page 1
3712 # - No interrupts
3713 # - No decimal mode (may never be added). D flag is emulated but ignored.
3714 # - BRK switches back to running 16-bits vCPU
3715 # - Illegal opcodes map to BRK, but can read ghost operands before trapping
3716 # - Illegal opcode $ff won't be trapped and cause havoc instead
3717
3718 # Big things TODO:
3719 # XXX Tuning, put most frequent instructions in the primary page
3720
3721 label('v6502_ror')
3722 assert v6502_Cflag == 1
v6502_ror: 0d83 1525 ld [$25],y 3723 ld([v6502_ADH],Y) #12
0d84 00fc ld $fc 3724 ld(-46//2+v6502_maxTicks) #13 Is there enough time for the excess ticks?
0d85 8115 adda [$15] 3725 adda([vTicks]) #14
0d86 e89a blt .recheck17 3726 blt('.recheck17') #15
0d87 0127 ld [$27] 3727 ld([v6502_P]) #16 Transfer C to "bit 8"
0d88 2001 anda $01 3728 anda(1) #17
0d89 807f adda $7f 3729 adda(127) #18
0d8a 2080 anda $80 3730 anda(128) #19
0d8b c219 st [$19] 3731 st([v6502_BI]) #20 The real 6502 wouldn't use BI for this
0d8c 0127 ld [$27] 3732 ld([v6502_P]) #21 Transfer bit 0 to C
0d8d 20fe anda $fe 3733 anda(~1) #22
0d8e c227 st [$27] 3734 st([v6502_P]) #23
0d8f 0d00 ld [y,x] 3735 ld([Y,X]) #24
0d90 2001 anda $01 3736 anda(1) #25
0d91 4127 ora [$27] 3737 ora([v6502_P]) #26
0d92 c227 st [$27] 3738 st([v6502_P]) #27
0d93 00ee ld $ee 3739 ld('v6502_ror#38') #28 Shift table lookup
0d94 c21d st [$1d] 3740 st([vTmp]) #29
0d95 0d00 ld [y,x] 3741 ld([Y,X]) #30
0d96 20fe anda $fe 3742 anda(~1) #31
0d97 1405 ld $05,y 3743 ld(hi('shiftTable'),Y) #32
0d98 e200 jmp y,ac 3744 jmp(Y,AC) #33
0d99 fcff bra $ff 3745 bra(255) #34 bra shiftTable+255
3746 label('.recheck17')
.recheck17: 0d9a 140e ld $0e,y 3747 ld(hi('v6502_check'),Y) #17 Go back to time check before dispatch
0d9b e0f2 jmp y,$f2 3748 jmp(Y,'v6502_check') #18
0d9c 00f6 ld $f6 3749 ld(-20/2) #19
3750
3751 label('v6502_lsr')
3752 assert v6502_Cflag == 1
v6502_lsr: 0d9d 1525 ld [$25],y 3753 ld([v6502_ADH],Y) #12
0d9e 0127 ld [$27] 3754 ld([v6502_P]) #13 Transfer bit 0 to C
0d9f 20fe anda $fe 3755 anda(~1) #14
0da0 c227 st [$27] 3756 st([v6502_P]) #15
0da1 0d00 ld [y,x] 3757 ld([Y,X]) #16
0da2 2001 anda $01 3758 anda(1) #17
0da3 4127 ora [$27] 3759 ora([v6502_P]) #18
0da4 c227 st [$27] 3760 st([v6502_P]) #19
0da5 00e7 ld $e7 3761 ld('v6502_lsr#30') #20 Shift table lookup
0da6 c21d st [$1d] 3762 st([vTmp]) #21
0da7 0d00 ld [y,x] 3763 ld([Y,X]) #22
0da8 20fe anda $fe 3764 anda(~1) #23
0da9 1405 ld $05,y 3765 ld(hi('shiftTable'),Y) #24
0daa e200 jmp y,ac 3766 jmp(Y,AC) #25
0dab fcff bra $ff 3767 bra(255) #26 bra shiftTable+255
3768
3769 label('v6502_rol')
3770 assert v6502_Cflag == 1
v6502_rol: 0dac 1525 ld [$25],y 3771 ld([v6502_ADH],Y) #12
0dad 0d00 ld [y,x] 3772 ld([Y,X]) #13
0dae 2080 anda $80 3773 anda(0x80) #14
0daf c21d st [$1d] 3774 st([v6502_Tmp]) #15
0db0 0127 ld [$27] 3775 ld([v6502_P]) #16
0db1 2001 anda $01 3776 anda(1) #17
3777 label('.rol#18')
.rol#18: 0db2 8d00 adda [y,x] 3778 adda([Y,X]) #18
0db3 8d00 adda [y,x] 3779 adda([Y,X]) #19
0db4 ce00 st [y,x] 3780 st([Y,X]) #20
0db5 c228 st [$28] 3781 st([v6502_Qz]) #21 Z flag
0db6 c229 st [$29] 3782 st([v6502_Qn]) #22 N flag
0db7 0127 ld [$27] 3783 ld([v6502_P]) #23 C Flag
0db8 20fe anda $fe 3784 anda(~1) #24
0db9 111d ld [$1d],x 3785 ld([v6502_Tmp],X) #25
0dba 4500 ora [x] 3786 ora([X]) #26
0dbb c227 st [$27] 3787 st([v6502_P]) #27
0dbc 140e ld $0e,y 3788 ld(hi('v6502_next'),Y) #28
0dbd 00f0 ld $f0 3789 ld(-32/2) #29
0dbe e020 jmp y,$20 3790 jmp(Y,'v6502_next') #30
3791 #nop() #31 Overlap
3792 #
3793 label('v6502_asl')
v6502_asl: 0dbf 1525 ld [$25],y 3794 ld([v6502_ADH],Y) #12,32
0dc0 0d00 ld [y,x] 3795 ld([Y,X]) #13
0dc1 2080 anda $80 3796 anda(0x80) #14
0dc2 c21d st [$1d] 3797 st([v6502_Tmp]) #15
0dc3 fcb2 bra .rol#18 3798 bra('.rol#18') #16
0dc4 0000 ld $00 3799 ld(0) #17
3800
3801 label('v6502_jmp1')
v6502_jmp1: 0dc5 0200 nop 3802 nop() #12
0dc6 0124 ld [$24] 3803 ld([v6502_ADL]) #13
0dc7 c21a st [$1a] 3804 st([v6502_PCL]) #14
0dc8 0125 ld [$25] 3805 ld([v6502_ADH]) #15
0dc9 c21b st [$1b] 3806 st([v6502_PCH]) #16
0dca 140e ld $0e,y 3807 ld(hi('v6502_next'),Y) #17
0dcb e020 jmp y,$20 3808 jmp(Y,'v6502_next') #18
0dcc 00f6 ld $f6 3809 ld(-20/2) #19
3810
3811 label('v6502_jmp2')
v6502_jmp2: 0dcd 0200 nop 3812 nop() #12
0dce 1525 ld [$25],y 3813 ld([v6502_ADH],Y) #13
0dcf 0d00 ld [y,x] 3814 ld([Y,X]) #14
0dd0 de00 st [y,x++] 3815 st([Y,Xpp]) #15 (Just X++) Wrap around: bug compatible with NMOS
0dd1 c21a st [$1a] 3816 st([v6502_PCL]) #16
0dd2 0d00 ld [y,x] 3817 ld([Y,X]) #17
0dd3 c21b st [$1b] 3818 st([v6502_PCH]) #18
0dd4 140e ld $0e,y 3819 ld(hi('v6502_next'),Y) #19
0dd5 e020 jmp y,$20 3820 jmp(Y,'v6502_next') #20
0dd6 00f5 ld $f5 3821 ld(-22/2) #21
3822
3823 label('v6502_pla')
v6502_pla: 0dd7 011c ld [$1c] 3824 ld([v6502_S]) #12
0dd8 1200 ld ac,x 3825 ld(AC,X) #13
0dd9 8001 adda $01 3826 adda(1) #14
0dda c21c st [$1c] 3827 st([v6502_S]) #15
0ddb 0500 ld [x] 3828 ld([X]) #16
0ddc c218 st [$18] 3829 st([v6502_A]) #17
0ddd c228 st [$28] 3830 st([v6502_Qz]) #18 Z flag
0dde c229 st [$29] 3831 st([v6502_Qn]) #19 N flag
0ddf 140e ld $0e,y 3832 ld(hi('v6502_next'),Y) #20
0de0 00f4 ld $f4 3833 ld(-24/2) #21
0de1 e020 jmp y,$20 3834 jmp(Y,'v6502_next') #22
3835 #nop() #23 Overlap
3836 #
3837 label('v6502_pha')
v6502_pha: 0de2 140e ld $0e,y 3838 ld(hi('v6502_next'),Y) #12,24
0de3 011c ld [$1c] 3839 ld([v6502_S]) #13
0de4 a001 suba $01 3840 suba(1) #14
0de5 d21c st [$1c],x 3841 st([v6502_S],X) #15
0de6 0118 ld [$18] 3842 ld([v6502_A]) #16
0de7 c600 st [x] 3843 st([X]) #17
0de8 e020 jmp y,$20 3844 jmp(Y,'v6502_next') #18
0de9 00f6 ld $f6 3845 ld(-20/2) #19
3846
3847 label('v6502_brk')
v6502_brk: 0dea 0002 ld $02 3848 ld(hi('ENTER')) #12 Switch to vCPU
0deb c205 st [$05] 3849 st([vCpuSelect]) #13
3850 assert v6502_A == vAC
0dec 0000 ld $00 3851 ld(0) #14
0ded c219 st [$19] 3852 st([vAC+1]) #15
0dee 1403 ld $03,y 3853 ld(hi('REENTER'),Y) #16 Switch in the current time slice
0def 00fb ld $fb 3854 ld(-22//2+v6502_adjust) #17
0df0 e0cb jmp y,$cb 3855 jmp(Y,'REENTER') #18
0df1 0200 nop 3856 nop() #19
3857
3858 # All interpreter entry points must share the same page offset, because
3859 # this offset is hard-coded as immediate operand in the video driver.
3860 # The Gigatron's original vCPU's 'ENTER' label is already at $2ff, so we
3861 # just use $dff for 'v6502_ENTER'. v6502 actually has two entry points.
3862 # The other is 'v6502_RESUME' at $10ff. It is used for instructions
3863 # that were fetched but not yet executed. Allowing the split gives finer
3864 # granulariy, and hopefully more throughput for the simpler instructions.
3865 # (There is no "overhead" for allowing instruction splitting, because
3866 # both emulation phases must administer [vTicks] anyway.)
3867 while pc()&255 < 255:
0df2 0200 nop 3868 nop()
0df3 0200 nop
0df4 0200 nop
* 13 times
3869 label('v6502_ENTER')
v6502_ENTER: 0dff fc22 bra v6502_next2 3870 bra('v6502_next2') #0 v6502 primary entry point
3871 # --- Page boundary ---
0e00 a006 suba $06 3872 suba(v6502_adjust) #1,19 Adjust for vCPU/v6520 timing differences
3873
3874 #19 Addressing modes
3875 ( 'v6502_mode0' ); bra('v6502_modeIZX'); bra('v6502_modeIMM'); bra('v6502_modeILL') # $00 xxx000xx
0e01 fce0 bra v6502_modeIZX
0e02 fc42 bra v6502_modeIMM
0e03 fc58 bra v6502_modeIMP
3876 bra('v6502_modeZP'); bra('v6502_modeZP'); bra('v6502_modeZP'); bra('v6502_modeILL') # $04 xxx001xx
0e04 fc5d bra v6502_modeZP
0e05 fc5d bra v6502_modeZP
0e06 fc5d bra v6502_modeZP
0e07 fc58 bra v6502_modeIMP
3877 bra('v6502_modeIMP'); bra('v6502_modeIMM'); bra('v6502_modeACC'); bra('v6502_modeILL') # $08 xxx010xx
0e08 fc58 bra v6502_modeIMP
0e09 fc42 bra v6502_modeIMM
0e0a fc52 bra v6502_modeACC
0e0b fc58 bra v6502_modeIMP
3878 bra('v6502_modeABS'); bra('v6502_modeABS'); bra('v6502_modeABS'); bra('v6502_modeILL') # $0c xxx011xx
0e0c fc78 bra v6502_modeABS
0e0d fc78 bra v6502_modeABS
0e0e fc78 bra v6502_modeABS
0e0f fc58 bra v6502_modeIMP
3879 bra('v6502_modeREL'); bra('v6502_modeIZY'); bra('v6502_modeIMM'); bra('v6502_modeILL') # $10 xxx100xx
0e10 fccf bra v6502_modeREL
0e11 fcab bra v6502_modeIZY
0e12 fc42 bra v6502_modeIMM
0e13 fc58 bra v6502_modeIMP
3880 bra('v6502_modeZPX'); bra('v6502_modeZPX'); bra('v6502_modeZPX'); bra('v6502_modeILL') # $14 xxx101xx
0e14 fc5b bra v6502_modeZPX
0e15 fc5b bra v6502_modeZPX
0e16 fc5b bra v6502_modeZPX
0e17 fc58 bra v6502_modeIMP
3881 bra('v6502_modeIMP'); bra('v6502_modeABY'); bra('v6502_modeIMP'); bra('v6502_modeILL') # $18 xxx110xx
0e18 fc58 bra v6502_modeIMP
0e19 fc7b bra v6502_modeABY
0e1a fc58 bra v6502_modeIMP
0e1b fc58 bra v6502_modeIMP
3882 bra('v6502_modeABX'); bra('v6502_modeABX'); bra('v6502_modeABX'); bra('v6502_modeILL') # $1c xxx111xx
0e1c fc7a bra v6502_modeABX
0e1d fc7a bra v6502_modeABX
0e1e fc7a bra v6502_modeABX
0e1f fc58 bra v6502_modeIMP
3883
3884 # Special encoding cases for emulator:
3885 # $00 BRK - but gets mapped to #$DD handled in v6502_mode0
3886 # $20 JSR $DDDD but gets mapped to #$DD handled in v6502_mode0 and v6502_JSR
3887 # $40 RTI - but gets mapped to #$DD handled in v6502_mode0
3888 # $60 RTS - but gets mapped to #$DD handled in v6502_mode0
3889 # $6C JMP ($DDDD) but gets mapped to $DDDD handled in v6502_JMP2
3890 # $96 STX $DD,Y but gets mapped to $DD,X handled in v6502_STX2
3891 # $B6 LDX $DD,Y but gets mapped to $DD,X handled in v6502_LDX2
3892 # $BE LDX $DDDD,Y but gets mapped to $DDDD,X handled in v6502_modeABX
3893
3894 label('v6502_next')
v6502_next: 0e20 8115 adda [$15] 3895 adda([vTicks]) #0
3896 blt('v6502_exitBefore') #1 No more ticks
0e21 e83a blt v6502_exitBefore
3897 label('v6502_next2')
v6502_next2: 0e22 c215 st [$15] 3898 st([vTicks]) #2
3899 #
3900 # Fetch opcode
0e23 111a ld [$1a],x 3901 ld([v6502_PCL],X) #3
0e24 151b ld [$1b],y 3902 ld([v6502_PCH],Y) #4
0e25 0d00 ld [y,x] 3903 ld([Y,X]) #5 Fetch IR
0e26 c226 st [$26] 3904 st([v6502_IR]) #6
0e27 011a ld [$1a] 3905 ld([v6502_PCL]) #7 PC++
0e28 8001 adda $01 3906 adda(1) #8
0e29 d21a st [$1a],x 3907 st([v6502_PCL],X) #9
0e2a f02d beq $0e2d 3908 beq(pc()+3) #10
0e2b fc2e bra $0e2e 3909 bra(pc()+3) #11
0e2c 0000 ld $00 3910 ld(0) #12
0e2d 0001 ld $01 3911 ld(1) #12(!)
0e2e 811b adda [$1b] 3912 adda([v6502_PCH]) #13
0e2f d61b st [$1b],y 3913 st([v6502_PCH],Y) #14
3914 #
3915 # Get addressing mode and fetch operands
0e30 0126 ld [$26] 3916 ld([v6502_IR]) #15 Get addressing mode
0e31 201f anda $1f 3917 anda(31) #16
0e32 fe00 bra ac 3918 bra(AC) #17
0e33 fc34 bra .next20 3919 bra('.next20') #18
3920 # (jump table) #19
3921 label('.next20')
.next20: 0e34 0d00 ld [y,x] 3922 ld([Y,X]) #20 Fetch L
3923 # Most opcodes branch away at this point, but IR & 31 == 0 falls through
3924 #
3925 # Implicit Mode for BRK JSR RTI RTS (< 0x80) -- 26 cycles
3926 # Immediate Mode for LDY CPY CPX (>= 0x80) -- 36 cycles
3927 label('v6502_mode0')
v6502_mode0: 0e35 0126 ld [$26] 3928 ld([v6502_IR]) #21 'xxx0000'
0e36 e845 blt .imm24 3929 bmi('.imm24') #22
0e37 011b ld [$1b] 3930 ld([v6502_PCH]) #23
0e38 fcf2 bra v6502_check 3931 bra('v6502_check') #24
0e39 00f3 ld $f3 3932 ld(-26/2) #25
3933
3934 # Resync with video driver. At this point we're returning BEFORE
3935 # fetching and executing the next instruction.
3936 label('v6502_exitBefore')
v6502_exitBefore:
0e3a 8013 adda $13 3937 adda(v6502_maxTicks) #3 Exit BEFORE fetch
0e3b e43b bgt $0e3b 3938 bgt(pc()&255) #4 Resync
0e3c a001 suba $01 3939 suba(1) #5
0e3d 000d ld $0d 3940 ld(hi('v6502_ENTER')) #6 Set entry point to before 'fetch'
0e3e c205 st [$05] 3941 st([vCpuSelect]) #7
0e3f 1401 ld $01,y 3942 ld(hi('vBlankStart'),Y) #8
0e40 e11e jmp y,[$1e] 3943 jmp(Y,[vReturn]) #9 To video driver
0e41 0000 ld $00 3944 ld(0) #10
3945 assert v6502_overhead == 11
3946
3947 # Immediate Mode: #$FF -- 36 cycles
3948 label('v6502_modeIMM')
v6502_modeIMM:
0e42 0200 nop 3949 nop() #21 Wait for v6502_mode0 to join
0e43 0200 nop 3950 nop() #22
0e44 011b ld [$1b] 3951 ld([v6502_PCH]) #23 Copy PC
3952 label('.imm24')
.imm24: 0e45 c225 st [$25] 3953 st([v6502_ADH]) #24
0e46 011a ld [$1a] 3954 ld([v6502_PCL]) #25
0e47 d224 st [$24],x 3955 st([v6502_ADL],X) #26
0e48 8001 adda $01 3956 adda(1) #27 PC++
0e49 c21a st [$1a] 3957 st([v6502_PCL]) #28
0e4a f04d beq $0e4d 3958 beq(pc()+3) #29
0e4b fc4e bra $0e4e 3959 bra(pc()+3) #30
0e4c 0000 ld $00 3960 ld(0) #31
0e4d 0001 ld $01 3961 ld(1) #31(!)
0e4e 811b adda [$1b] 3962 adda([v6502_PCH]) #32
0e4f c21b st [$1b] 3963 st([v6502_PCH]) #33
0e50 fcf2 bra v6502_check 3964 bra('v6502_check') #34
0e51 00ee ld $ee 3965 ld(-36/2) #35
3966
3967 # Accumulator Mode: ROL ROR LSL ASR -- 28 cycles
3968 label('v6502_modeACC')
v6502_modeACC:
0e52 0018 ld $18 3969 ld(v6502_A&255) #21 Address of AC
0e53 d224 st [$24],x 3970 st([v6502_ADL],X) #22
0e54 0000 ld $00 3971 ld(v6502_A>>8) #23
0e55 c225 st [$25] 3972 st([v6502_ADH]) #24
0e56 00f2 ld $f2 3973 ld(-28/2) #25
0e57 fcf2 bra v6502_check 3974 bra('v6502_check') #26
3975 #nop() #27 Overlap
3976 #
3977 # Implied Mode: no operand -- 24 cycles
3978 label('v6502_modeILL')
3979 label('v6502_modeIMP')
v6502_modeILL:
v6502_modeIMP:
0e58 0200 nop 3980 nop() #21,27
0e59 fcf2 bra v6502_check 3981 bra('v6502_check') #22
0e5a 00f4 ld $f4 3982 ld(-24/2) #23
3983
3984 # Zero Page Modes: $DD $DD,X $DD,Y -- 36 cycles
3985 label('v6502_modeZPX')
v6502_modeZPX:
0e5b fc5f bra .zp23 3986 bra('.zp23') #21
0e5c 812a adda [$2a] 3987 adda([v6502_X]) #22
3988 label('v6502_modeZP')
v6502_modeZP: 0e5d fc5f bra .zp23 3989 bra('.zp23') #21
0e5e 0200 nop 3990 nop() #22
3991 label('.zp23')
.zp23: 0e5f d224 st [$24],x 3992 st([v6502_ADL],X) #23
0e60 0000 ld $00 3993 ld(0) #24 H=0
0e61 c225 st [$25] 3994 st([v6502_ADH]) #25
0e62 0001 ld $01 3995 ld(1) #26 PC++
0e63 811a adda [$1a] 3996 adda([v6502_PCL]) #27
0e64 c21a st [$1a] 3997 st([v6502_PCL]) #28
0e65 f068 beq $0e68 3998 beq(pc()+3) #29
0e66 fc69 bra $0e69 3999 bra(pc()+3) #30
0e67 0000 ld $00 4000 ld(0) #31
0e68 0001 ld $01 4001 ld(1) #31(!)
0e69 811b adda [$1b] 4002 adda([v6502_PCH]) #32
0e6a c21b st [$1b] 4003 st([v6502_PCH]) #33
0e6b fcf2 bra v6502_check 4004 bra('v6502_check') #34
0e6c 00ee ld $ee 4005 ld(-36/2) #35
4006
4007 # Possible retry loop for modeABS and modeIZY. Because these need
4008 # more time than the v6502_maxTicks of 38 Gigatron cycles, we may
4009 # have to restart them after the next horizontal pulse.
4010 label('.retry28')
.retry28: 0e6d f070 beq $0e70 4011 beq(pc()+3) #28,37 PC--
0e6e fc71 bra $0e71 4012 bra(pc()+3) #29
0e6f 0000 ld $00 4013 ld(0) #30
0e70 00ff ld $ff 4014 ld(-1) #30(!)
0e71 811b adda [$1b] 4015 adda([v6502_PCH]) #31
0e72 c21b st [$1b] 4016 st([v6502_PCH]) #32
0e73 011a ld [$1a] 4017 ld([v6502_PCL]) #33
0e74 a001 suba $01 4018 suba(1) #34
0e75 c21a st [$1a] 4019 st([v6502_PCL]) #35
0e76 fc20 bra v6502_next 4020 bra('v6502_next') #36 Retry until sufficient time
0e77 00ed ld $ed 4021 ld(-38/2) #37
4022
4023 # Absolute Modes: $DDDD $DDDD,X $DDDD,Y -- 64 cycles
4024 label('v6502_modeABS')
v6502_modeABS:
0e78 fc7d bra .abs23 4025 bra('.abs23') #21
0e79 0000 ld $00 4026 ld(0) #22
4027 label('v6502_modeABX')
v6502_modeABX:
0e7a fc7d bra .abs23 4028 bra('.abs23') #21
4029 label('v6502_modeABY')
v6502_modeABY:
0e7b 012a ld [$2a] 4030 ld([v6502_X]) #21,22
0e7c 012b ld [$2b] 4031 ld([v6502_Y]) #22
4032 label('.abs23')
.abs23: 0e7d c224 st [$24] 4033 st([v6502_ADL]) #23
0e7e 00f3 ld $f3 4034 ld(-64//2+v6502_maxTicks) #24 Is there enough time for the excess ticks?
0e7f 8115 adda [$15] 4035 adda([vTicks]) #25
0e80 e86d blt .retry28 4036 blt('.retry28') #26
0e81 011a ld [$1a] 4037 ld([v6502_PCL]) #27
0e82 0126 ld [$26] 4038 ld([v6502_IR]) #28 Special case $BE: LDX $DDDD,Y (we got X in ADL)
0e83 60be xora $be 4039 xora(0xbe) #29
0e84 f087 beq $0e87 4040 beq(pc()+3) #30
0e85 fc88 bra $0e88 4041 bra(pc()+3) #31
0e86 0124 ld [$24] 4042 ld([v6502_ADL]) #32
0e87 012b ld [$2b] 4043 ld([v6502_Y]) #32(!)
0e88 8d00 adda [y,x] 4044 adda([Y,X]) #33 Fetch and add L
0e89 c224 st [$24] 4045 st([v6502_ADL]) #34
0e8a e88e blt .abs37 4046 bmi('.abs37') #35 Carry?
0e8b ad00 suba [y,x] 4047 suba([Y,X]) #36 Gets back original operand
0e8c fc90 bra .abs39 4048 bra('.abs39') #37
0e8d 4d00 ora [y,x] 4049 ora([Y,X]) #38 Carry in bit 7
4050 label('.abs37')
.abs37: 0e8e 2d00 anda [y,x] 4051 anda([Y,X]) #37 Carry in bit 7
0e8f 0200 nop 4052 nop() #38
4053 label('.abs39')
.abs39: 0e90 3080 anda $80,x 4054 anda(0x80,X) #39 Move carry to bit 0
0e91 0500 ld [x] 4055 ld([X]) #40
0e92 c225 st [$25] 4056 st([v6502_ADH]) #41
0e93 011a ld [$1a] 4057 ld([v6502_PCL]) #42 PC++
0e94 8001 adda $01 4058 adda(1) #43
0e95 d21a st [$1a],x 4059 st([v6502_PCL],X) #44
0e96 f099 beq $0e99 4060 beq(pc()+3) #45
0e97 fc9a bra $0e9a 4061 bra(pc()+3) #46
0e98 0000 ld $00 4062 ld(0) #47
0e99 0001 ld $01 4063 ld(1) #47(!)
0e9a 811b adda [$1b] 4064 adda([v6502_PCH]) #48
0e9b d61b st [$1b],y 4065 st([v6502_PCH],Y) #49
0e9c 0d00 ld [y,x] 4066 ld([Y,X]) #50 Fetch H
0e9d 8125 adda [$25] 4067 adda([v6502_ADH]) #51
0e9e c225 st [$25] 4068 st([v6502_ADH]) #52
0e9f 011a ld [$1a] 4069 ld([v6502_PCL]) #53 PC++
0ea0 8001 adda $01 4070 adda(1) #54
0ea1 c21a st [$1a] 4071 st([v6502_PCL]) #55
0ea2 f0a5 beq $0ea5 4072 beq(pc()+3) #56
0ea3 fca6 bra $0ea6 4073 bra(pc()+3) #57
0ea4 0000 ld $00 4074 ld(0) #58
0ea5 0001 ld $01 4075 ld(1) #58(!)
0ea6 811b adda [$1b] 4076 adda([v6502_PCH]) #59
0ea7 c21b st [$1b] 4077 st([v6502_PCH]) #60
0ea8 1124 ld [$24],x 4078 ld([v6502_ADL],X) #61
0ea9 fcf2 bra v6502_check 4079 bra('v6502_check') #62
0eaa 00e0 ld $e0 4080 ld(-64/2) #63
4081
4082 # Indirect Indexed Mode: ($DD),Y -- 54 cycles
4083 label('v6502_modeIZY')
v6502_modeIZY:
0eab 1200 ld ac,x 4084 ld(AC,X) #21 $DD
0eac 1400 ld $00,y 4085 ld(0,Y) #22 $00DD
0ead 00f8 ld $f8 4086 ld(-54//2+v6502_maxTicks) #23 Is there enough time for the excess ticks?
0eae 8115 adda [$15] 4087 adda([vTicks]) #24
0eaf 0200 nop 4088 nop() #25
0eb0 e86d blt .retry28 4089 blt('.retry28') #26
0eb1 011a ld [$1a] 4090 ld([v6502_PCL]) #27
0eb2 8001 adda $01 4091 adda(1) #28 PC++
0eb3 c21a st [$1a] 4092 st([v6502_PCL]) #29
0eb4 f0b7 beq $0eb7 4093 beq(pc()+3) #30
0eb5 fcb8 bra $0eb8 4094 bra(pc()+3) #31
0eb6 0000 ld $00 4095 ld(0) #32
0eb7 0001 ld $01 4096 ld(1) #32(!)
0eb8 811b adda [$1b] 4097 adda([v6502_PCH]) #33
0eb9 c21b st [$1b] 4098 st([v6502_PCH]) #34
0eba 0d00 ld [y,x] 4099 ld([Y,X]) #35 Read word from zero-page
0ebb de00 st [y,x++] 4100 st([Y,Xpp]) #36 (Just X++) Wrap-around is correct
0ebc c224 st [$24] 4101 st([v6502_ADL]) #37
0ebd 0d00 ld [y,x] 4102 ld([Y,X]) #38
0ebe c225 st [$25] 4103 st([v6502_ADH]) #39
0ebf 012b ld [$2b] 4104 ld([v6502_Y]) #40 Add Y
0ec0 8124 adda [$24] 4105 adda([v6502_ADL]) #41
0ec1 c224 st [$24] 4106 st([v6502_ADL]) #42
0ec2 e8c6 blt .izy45 4107 bmi('.izy45') #43 Carry?
0ec3 a12b suba [$2b] 4108 suba([v6502_Y]) #44 Gets back original operand
0ec4 fcc8 bra .izy47 4109 bra('.izy47') #45
0ec5 412b ora [$2b] 4110 ora([v6502_Y]) #46 Carry in bit 7
4111 label('.izy45')
.izy45: 0ec6 212b anda [$2b] 4112 anda([v6502_Y]) #45 Carry in bit 7
0ec7 0200 nop 4113 nop() #46
4114 label('.izy47')
.izy47: 0ec8 3080 anda $80,x 4115 anda(0x80,X) #47 Move carry to bit 0
0ec9 0500 ld [x] 4116 ld([X]) #48
0eca 8125 adda [$25] 4117 adda([v6502_ADH]) #49
0ecb c225 st [$25] 4118 st([v6502_ADH]) #50
0ecc 1124 ld [$24],x 4119 ld([v6502_ADL],X) #51
0ecd fcf2 bra v6502_check 4120 bra('v6502_check') #52
0ece 00e5 ld $e5 4121 ld(-54/2) #53
4122
4123 # Relative Mode: BEQ BNE BPL BMI BCC BCS BVC BVS -- 36 cycles
4124 label('v6502_modeREL')
v6502_modeREL:
0ecf d224 st [$24],x 4125 st([v6502_ADL],X) #21 Offset (Only needed for branch)
0ed0 e8d3 blt $0ed3 4126 bmi(pc()+3) #22 Sign extend
0ed1 fcd4 bra $0ed4 4127 bra(pc()+3) #23
0ed2 0000 ld $00 4128 ld(0) #24
0ed3 00ff ld $ff 4129 ld(255) #24(!)
0ed4 c225 st [$25] 4130 st([v6502_ADH]) #25
0ed5 011a ld [$1a] 4131 ld([v6502_PCL]) #26 PC++ (Needed for both cases)
0ed6 8001 adda $01 4132 adda(1) #27
0ed7 c21a st [$1a] 4133 st([v6502_PCL]) #28
0ed8 f0db beq $0edb 4134 beq(pc()+3) #29
0ed9 fcdc bra $0edc 4135 bra(pc()+3) #30
0eda 0000 ld $00 4136 ld(0) #31
0edb 0001 ld $01 4137 ld(1) #31(!)
0edc 811b adda [$1b] 4138 adda([v6502_PCH]) #32
0edd c21b st [$1b] 4139 st([v6502_PCH]) #33
0ede fcf2 bra v6502_check 4140 bra('v6502_check') #34
0edf 00ee ld $ee 4141 ld(-36/2) #53
4142
4143 # Indexed Indirect Mode: ($DD,X) -- 38 cycles
4144 label('v6502_modeIZX')
v6502_modeIZX:
0ee0 812a adda [$2a] 4145 adda([v6502_X]) #21 Add X
0ee1 c21d st [$1d] 4146 st([v6502_Tmp]) #22
0ee2 9001 adda $01,x 4147 adda(1,X) #23 Read word from zero-page
0ee3 0500 ld [x] 4148 ld([X]) #24
0ee4 c225 st [$25] 4149 st([v6502_ADH]) #25
0ee5 111d ld [$1d],x 4150 ld([v6502_Tmp],X) #26
0ee6 0500 ld [x] 4151 ld([X]) #27
0ee7 d224 st [$24],x 4152 st([v6502_ADL],X) #28
0ee8 011a ld [$1a] 4153 ld([v6502_PCL]) #29 PC++
0ee9 8001 adda $01 4154 adda(1) #30
0eea c21a st [$1a] 4155 st([v6502_PCL]) #31
0eeb f0ee beq $0eee 4156 beq(pc()+3) #32
0eec fcef bra $0eef 4157 bra(pc()+3) #33
0eed 0000 ld $00 4158 ld(0) #34
0eee 0001 ld $01 4159 ld(1) #34(!)
0eef 811b adda [$1b] 4160 adda([v6502_PCH]) #35
0ef0 c21b st [$1b] 4161 st([v6502_PCH]) #36
0ef1 00ed ld $ed 4162 ld(-38/2) #37 !!! Fall through to v6502_check !!!
4163 #
4164 # Update elapsed time for the addressing mode processing.
4165 # Then check if we can immediately execute this instruction.
4166 # Otherwise transfer control to the video driver.
4167 label('v6502_check')
v6502_check: 0ef2 8115 adda [$15] 4168 adda([vTicks]) #0
4169 blt('v6502_exitAfter') #1 No more ticks
0ef3 e8f8 blt v6502_exitAfter
0ef4 c215 st [$15] 4170 st([vTicks]) #2
0ef5 140f ld $0f,y 4171 ld(hi('v6502_execute'),Y) #3
0ef6 e126 jmp y,[$26] 4172 jmp(Y,[v6502_IR]) #4
0ef7 fcff bra $ff 4173 bra(255) #5
4174
4175 # Otherwise resync with video driver. At this point we're returning AFTER
4176 # addressing mode decoding, but before executing the instruction.
4177 label('v6502_exitAfter')
v6502_exitAfter:
0ef8 8013 adda $13 4178 adda(v6502_maxTicks) #3 Exit AFTER fetch
0ef9 e4f9 bgt $0ef9 4179 bgt(pc()&255) #4 Resync
0efa a001 suba $01 4180 suba(1) #5
0efb 0010 ld $10 4181 ld(hi('v6502_RESUME')) #6 Set entry point to before 'execute'
0efc c205 st [$05] 4182 st([vCpuSelect]) #7
0efd 1401 ld $01,y 4183 ld(hi('vBlankStart'),Y) #8
0efe e11e jmp y,[$1e] 4184 jmp(Y,[vReturn]) #9 To video driver
0eff 0000 ld $00 4185 ld(0) #10
4186 assert v6502_overhead == 11
4187
4188 align(0x100,size=0x100)
4189 label('v6502_execute')
4190 # This page works as a 255-entry (0..254) jump table for 6502 opcodes.
4191 # Jumping into this page must have 'bra 255' in the branch delay slot
4192 # in order to get out again and dispatch to the right continuation.
4193 # X must hold [v6502_ADL],
4194 # Y will hold hi('v6502_execute'),
4195 # A will be loaded with the code offset (this is skipped at offset $ff)
v6502_execute:
0f00 00fd ld $fd 4196 ld('v6502_BRK'); ld('v6502_ORA'); ld('v6502_ILL'); ld('v6502_ILL') #6 $00
0f01 0089 ld $89
0f02 00fd ld $fd
0f03 00fd ld $fd
0f04 00fd ld $fd 4197 ld('v6502_ILL'); ld('v6502_ORA'); ld('v6502_ASL'); ld('v6502_ILL') #6
0f05 0089 ld $89
0f06 00f1 ld $f1
0f07 00fd ld $fd
0f08 00f3 ld $f3 4198 ld('v6502_PHP'); ld('v6502_ORA'); ld('v6502_ASL'); ld('v6502_ILL') #6
0f09 0089 ld $89
0f0a 00f1 ld $f1
0f0b 00fd ld $fd
0f0c 00fd ld $fd 4199 ld('v6502_ILL'); ld('v6502_ORA'); ld('v6502_ASL'); ld('v6502_ILL') #6
0f0d 0089 ld $89
0f0e 00f1 ld $f1
0f0f 00fd ld $fd
0f10 003f ld $3f 4200 ld('v6502_BPL'); ld('v6502_ORA'); ld('v6502_ILL'); ld('v6502_ILL') #6 $10
0f11 0089 ld $89
0f12 00fd ld $fd
0f13 00fd ld $fd
0f14 00fd ld $fd 4201 ld('v6502_ILL'); ld('v6502_ORA'); ld('v6502_ASL'); ld('v6502_ILL') #6
0f15 0089 ld $89
0f16 00f1 ld $f1
0f17 00fd ld $fd
0f18 0036 ld $36 4202 ld('v6502_CLC'); ld('v6502_ORA'); ld('v6502_ILL'); ld('v6502_ILL') #6
0f19 0089 ld $89
0f1a 00fd ld $fd
0f1b 00fd ld $fd
0f1c 00fd ld $fd 4203 ld('v6502_ILL'); ld('v6502_ORA'); ld('v6502_ASL'); ld('v6502_ILL') #6
0f1d 0089 ld $89
0f1e 00f1 ld $f1
0f1f 00fd ld $fd
0f20 009a ld $9a 4204 ld('v6502_JSR'); ld('v6502_AND'); ld('v6502_ILL'); ld('v6502_ILL') #6 $20
0f21 0085 ld $85
0f22 00fd ld $fd
0f23 00fd ld $fd
0f24 00f5 ld $f5 4205 ld('v6502_BIT'); ld('v6502_AND'); ld('v6502_ROL'); ld('v6502_ILL') #6
0f25 0085 ld $85
0f26 00f7 ld $f7
0f27 00fd ld $fd
0f28 00f9 ld $f9 4206 ld('v6502_PLP'); ld('v6502_AND'); ld('v6502_ROL'); ld('v6502_ILL') #6
0f29 0085 ld $85
0f2a 00f7 ld $f7
0f2b 00fd ld $fd
0f2c 00f5 ld $f5 4207 ld('v6502_BIT'); ld('v6502_AND'); ld('v6502_ROL'); ld('v6502_ILL') #6
0f2d 0085 ld $85
0f2e 00f7 ld $f7
0f2f 00fd ld $fd
0f30 0042 ld $42 4208 ld('v6502_BMI'); ld('v6502_AND'); ld('v6502_ILL'); ld('v6502_ILL') #6 $30
0f31 0085 ld $85
0f32 00fd ld $fd
0f33 00fd ld $fd
0f34 00fd ld $fd 4209 ld('v6502_ILL'); ld('v6502_AND'); ld('v6502_ROL'); ld('v6502_ILL') #6
0f35 0085 ld $85
0f36 00f7 ld $f7
0f37 00fd ld $fd
0f38 0038 ld $38 4210 ld('v6502_SEC'); ld('v6502_AND'); ld('v6502_ILL'); ld('v6502_ILL') #6
0f39 0085 ld $85
0f3a 00fd ld $fd
0f3b 00fd ld $fd
0f3c 00fd ld $fd 4211 ld('v6502_ILL'); ld('v6502_AND'); ld('v6502_ROL'); ld('v6502_ILL') #6
0f3d 0085 ld $85
0f3e 00f7 ld $f7
0f3f 00fd ld $fd
0f40 00d3 ld $d3 4212 ld('v6502_RTI'); ld('v6502_EOR'); ld('v6502_ILL'); ld('v6502_ILL') #6 $40
0f41 008c ld $8c
0f42 00fd ld $fd
0f43 00fd ld $fd
0f44 00fd ld $fd 4213 ld('v6502_ILL'); ld('v6502_EOR'); ld('v6502_LSR'); ld('v6502_ILL') #6
0f45 008c ld $8c
0f46 00d7 ld $d7
0f47 00fd ld $fd
0f48 00d9 ld $d9 4214 ld('v6502_PHA'); ld('v6502_EOR'); ld('v6502_LSR'); ld('v6502_ILL') #6
0f49 008c ld $8c
0f4a 00d7 ld $d7
0f4b 00fd ld $fd
0f4c 0096 ld $96 4215 ld('v6502_JMP1');ld('v6502_EOR'); ld('v6502_LSR'); ld('v6502_ILL') #6
0f4d 008c ld $8c
0f4e 00d7 ld $d7
0f4f 00fd ld $fd
0f50 0045 ld $45 4216 ld('v6502_BVC'); ld('v6502_EOR'); ld('v6502_ILL'); ld('v6502_ILL') #6 $50
0f51 008c ld $8c
0f52 00fd ld $fd
0f53 00fd ld $fd
0f54 00fd ld $fd 4217 ld('v6502_ILL'); ld('v6502_EOR'); ld('v6502_LSR'); ld('v6502_ILL') #6
0f55 008c ld $8c
0f56 00d7 ld $d7
0f57 00fd ld $fd
0f58 00db ld $db 4218 ld('v6502_CLI'); ld('v6502_EOR'); ld('v6502_ILL'); ld('v6502_ILL') #6
0f59 008c ld $8c
0f5a 00fd ld $fd
0f5b 00fd ld $fd
0f5c 00fd ld $fd 4219 ld('v6502_ILL'); ld('v6502_EOR'); ld('v6502_LSR'); ld('v6502_ILL') #6
0f5d 008c ld $8c
0f5e 00d7 ld $d7
0f5f 00fd ld $fd
0f60 00dd ld $dd 4220 ld('v6502_RTS'); ld('v6502_ADC'); ld('v6502_ILL'); ld('v6502_ILL') #6 $60
0f61 0001 ld $01
0f62 00fd ld $fd
0f63 00fd ld $fd
0f64 00fd ld $fd 4221 ld('v6502_ILL'); ld('v6502_ADC'); ld('v6502_ROR'); ld('v6502_ILL') #6
0f65 0001 ld $01
0f66 00d5 ld $d5
0f67 00fd ld $fd
0f68 00df ld $df 4222 ld('v6502_PLA'); ld('v6502_ADC'); ld('v6502_ROR'); ld('v6502_ILL') #6
0f69 0001 ld $01
0f6a 00d5 ld $d5
0f6b 00fd ld $fd
0f6c 0098 ld $98 4223 ld('v6502_JMP2');ld('v6502_ADC'); ld('v6502_ROR'); ld('v6502_ILL') #6
0f6d 0001 ld $01
0f6e 00d5 ld $d5
0f6f 00fd ld $fd
0f70 0049 ld $49 4224 ld('v6502_BVS'); ld('v6502_ADC'); ld('v6502_ILL'); ld('v6502_ILL') #6 $70
0f71 0001 ld $01
0f72 00fd ld $fd
0f73 00fd ld $fd
0f74 00fd ld $fd 4225 ld('v6502_ILL'); ld('v6502_ADC'); ld('v6502_ROR'); ld('v6502_ILL') #6
0f75 0001 ld $01
0f76 00d5 ld $d5
0f77 00fd ld $fd
0f78 00e1 ld $e1 4226 ld('v6502_SEI'); ld('v6502_ADC'); ld('v6502_ILL'); ld('v6502_ILL') #6
0f79 0001 ld $01
0f7a 00fd ld $fd
0f7b 00fd ld $fd
0f7c 00fd ld $fd 4227 ld('v6502_ILL'); ld('v6502_ADC'); ld('v6502_ROR'); ld('v6502_ILL') #6
0f7d 0001 ld $01
0f7e 00d5 ld $d5
0f7f 00fd ld $fd
0f80 00fd ld $fd 4228 ld('v6502_ILL'); ld('v6502_STA'); ld('v6502_ILL'); ld('v6502_ILL') #6 $80
0f81 00c1 ld $c1
0f82 00fd ld $fd
0f83 00fd ld $fd
0f84 00c7 ld $c7 4229 ld('v6502_STY'); ld('v6502_STA'); ld('v6502_STX'); ld('v6502_ILL') #6
0f85 00c1 ld $c1
0f86 00c3 ld $c3
0f87 00fd ld $fd
0f88 007f ld $7f 4230 ld('v6502_DEY'); ld('v6502_ILL'); ld('v6502_TXA'); ld('v6502_ILL') #6
0f89 00fd ld $fd
0f8a 00cd ld $cd
0f8b 00fd ld $fd
0f8c 00c7 ld $c7 4231 ld('v6502_STY'); ld('v6502_STA'); ld('v6502_STX'); ld('v6502_ILL') #6
0f8d 00c1 ld $c1
0f8e 00c3 ld $c3
0f8f 00fd ld $fd
0f90 004d ld $4d 4232 ld('v6502_BCC'); ld('v6502_STA'); ld('v6502_ILL'); ld('v6502_ILL') #6 $90
0f91 00c1 ld $c1
0f92 00fd ld $fd
0f93 00fd ld $fd
0f94 00c7 ld $c7 4233 ld('v6502_STY'); ld('v6502_STA'); ld('v6502_STX2');ld('v6502_ILL') #6
0f95 00c1 ld $c1
0f96 00c5 ld $c5
0f97 00fd ld $fd
0f98 00cf ld $cf 4234 ld('v6502_TYA'); ld('v6502_STA'); ld('v6502_TXS'); ld('v6502_ILL') #6
0f99 00c1 ld $c1
0f9a 00e3 ld $e3
0f9b 00fd ld $fd
0f9c 00fd ld $fd 4235 ld('v6502_ILL'); ld('v6502_STA'); ld('v6502_ILL'); ld('v6502_ILL') #6
0f9d 00c1 ld $c1
0f9e 00fd ld $fd
0f9f 00fd ld $fd
0fa0 00bf ld $bf 4236 ld('v6502_LDY'); ld('v6502_LDA'); ld('v6502_LDX'); ld('v6502_ILL') #6 $A0
0fa1 00b9 ld $b9
0fa2 00bb ld $bb
0fa3 00fd ld $fd
0fa4 00bf ld $bf 4237 ld('v6502_LDY'); ld('v6502_LDA'); ld('v6502_LDX'); ld('v6502_ILL') #6
0fa5 00b9 ld $b9
0fa6 00bb ld $bb
0fa7 00fd ld $fd
0fa8 00cb ld $cb 4238 ld('v6502_TAY'); ld('v6502_LDA'); ld('v6502_TAX'); ld('v6502_ILL') #6
0fa9 00b9 ld $b9
0faa 00c9 ld $c9
0fab 00fd ld $fd
0fac 00bf ld $bf 4239 ld('v6502_LDY'); ld('v6502_LDA'); ld('v6502_LDX'); ld('v6502_ILL') #6
0fad 00b9 ld $b9
0fae 00bb ld $bb
0faf 00fd ld $fd
0fb0 0051 ld $51 4240 ld('v6502_BCS'); ld('v6502_LDA'); ld('v6502_ILL'); ld('v6502_ILL') #6 $B0
0fb1 00b9 ld $b9
0fb2 00fd ld $fd
0fb3 00fd ld $fd
0fb4 00bf ld $bf 4241 ld('v6502_LDY'); ld('v6502_LDA'); ld('v6502_LDX2');ld('v6502_ILL') #6
0fb5 00b9 ld $b9
0fb6 00bd ld $bd
0fb7 00fd ld $fd
0fb8 00d1 ld $d1 4242 ld('v6502_CLV'); ld('v6502_LDA'); ld('v6502_TSX'); ld('v6502_ILL') #6
0fb9 00b9 ld $b9
0fba 00e5 ld $e5
0fbb 00fd ld $fd
0fbc 00bf ld $bf 4243 ld('v6502_LDY'); ld('v6502_LDA'); ld('v6502_LDX'); ld('v6502_ILL') #6
0fbd 00b9 ld $b9
0fbe 00bb ld $bb
0fbf 00fd ld $fd
0fc0 00e7 ld $e7 4244 ld('v6502_CPY'); ld('v6502_CMP'); ld('v6502_ILL'); ld('v6502_ILL') #6 $C0
0fc1 00e9 ld $e9
0fc2 00fd ld $fd
0fc3 00fd ld $fd
0fc4 00e7 ld $e7 4245 ld('v6502_CPY'); ld('v6502_CMP'); ld('v6502_DEC'); ld('v6502_ILL') #6
0fc5 00e9 ld $e9
0fc6 00eb ld $eb
0fc7 00fd ld $fd
0fc8 007b ld $7b 4246 ld('v6502_INY'); ld('v6502_CMP'); ld('v6502_DEX'); ld('v6502_ILL') #6
0fc9 00e9 ld $e9
0fca 0077 ld $77
0fcb 00fd ld $fd
0fcc 00e7 ld $e7 4247 ld('v6502_CPY'); ld('v6502_CMP'); ld('v6502_DEC'); ld('v6502_ILL') #6
0fcd 00e9 ld $e9
0fce 00eb ld $eb
0fcf 00fd ld $fd
0fd0 0055 ld $55 4248 ld('v6502_BNE'); ld('v6502_CMP'); ld('v6502_ILL'); ld('v6502_ILL') #6 $D0
0fd1 00e9 ld $e9
0fd2 00fd ld $fd
0fd3 00fd ld $fd
0fd4 00fd ld $fd 4249 ld('v6502_ILL'); ld('v6502_CMP'); ld('v6502_DEC'); ld('v6502_ILL') #6
0fd5 00e9 ld $e9
0fd6 00eb ld $eb
0fd7 00fd ld $fd
0fd8 00ed ld $ed 4250 ld('v6502_CLD'); ld('v6502_CMP'); ld('v6502_ILL'); ld('v6502_ILL') #6
0fd9 00e9 ld $e9
0fda 00fd ld $fd
0fdb 00fd ld $fd
0fdc 00fd ld $fd 4251 ld('v6502_ILL'); ld('v6502_CMP'); ld('v6502_DEC'); ld('v6502_ILL') #6
0fdd 00e9 ld $e9
0fde 00eb ld $eb
0fdf 00fd ld $fd
0fe0 00ef ld $ef 4252 ld('v6502_CPX'); ld('v6502_SBC'); ld('v6502_ILL'); ld('v6502_ILL') #6 $E0
0fe1 0029 ld $29
0fe2 00fd ld $fd
0fe3 00fd ld $fd
0fe4 00ef ld $ef 4253 ld('v6502_CPX'); ld('v6502_SBC'); ld('v6502_INC'); ld('v6502_ILL') #6
0fe5 0029 ld $29
0fe6 00b7 ld $b7
0fe7 00fd ld $fd
0fe8 006c ld $6c 4254 ld('v6502_INX'); ld('v6502_SBC'); ld('v6502_NOP'); ld('v6502_ILL') #6
0fe9 0029 ld $29
0fea 0083 ld $83
0feb 00fd ld $fd
0fec 00ef ld $ef 4255 ld('v6502_CPX'); ld('v6502_SBC'); ld('v6502_INC'); ld('v6502_ILL') #6
0fed 0029 ld $29
0fee 00b7 ld $b7
0fef 00fd ld $fd
0ff0 0058 ld $58 4256 ld('v6502_BEQ'); ld('v6502_SBC'); ld('v6502_ILL'); ld('v6502_ILL') #6 $F0
0ff1 0029 ld $29
0ff2 00fd ld $fd
0ff3 00fd ld $fd
0ff4 00fd ld $fd 4257 ld('v6502_ILL'); ld('v6502_SBC'); ld('v6502_INC'); ld('v6502_ILL') #6
0ff5 0029 ld $29
0ff6 00b7 ld $b7
0ff7 00fd ld $fd
0ff8 00fb ld $fb 4258 ld('v6502_SED'); ld('v6502_SBC'); ld('v6502_ILL'); ld('v6502_ILL') #6
0ff9 0029 ld $29
0ffa 00fd ld $fd
0ffb 00fd ld $fd
0ffc 00fd ld $fd 4259 ld('v6502_ILL'); ld('v6502_SBC'); ld('v6502_INC') #6
0ffd 0029 ld $29
0ffe 00b7 ld $b7
0fff fe00 bra ac 4260 bra(AC) #6,7 Dispatch into next page
4261 # --- Page boundary ---
4262 align(0x100,size=0x100)
1000 140e ld $0e,y 4263 ld(hi('v6502_next'),Y) #8 Handy for instructions that don't clobber Y
4264
4265 label('v6502_ADC')
4266 assert pc()&255 == 1
4267 assert v6502_Cflag == 1
4268 assert v6502_Vemu == 128
v6502_ADC: 1001 1525 ld [$25],y 4269 ld([v6502_ADH],Y) #9 Must be at page offset 1, so A=1
1002 2127 anda [$27] 4270 anda([v6502_P]) #10 Carry in (AC=1 because lo('v6502_ADC')=1)
1003 8118 adda [$18] 4271 adda([v6502_A]) #11 Sum
1004 f020 beq .adc14 4272 beq('.adc14') #12 Danger zone for dropping a carry
1005 8d00 adda [y,x] 4273 adda([Y,X]) #13
1006 c228 st [$28] 4274 st([v6502_Qz]) #14 Z flag, don't overwrite left-hand side (A) yet
1007 c229 st [$29] 4275 st([v6502_Qn]) #15 N flag
1008 6118 xora [$18] 4276 xora([v6502_A]) #16 V flag, (Q^A) & (B^Q) & 0x80
1009 c218 st [$18] 4277 st([v6502_A]) #17
100a 0d00 ld [y,x] 4278 ld([Y,X]) #18
100b 6128 xora [$28] 4279 xora([v6502_Qz]) #19
100c 2118 anda [$18] 4280 anda([v6502_A]) #20
100d 2080 anda $80 4281 anda(0x80) #21
100e c21d st [$1d] 4282 st([v6502_Tmp]) #22
100f 0128 ld [$28] 4283 ld([v6502_Qz]) #23 Update A
1010 c218 st [$18] 4284 st([v6502_A]) #24
1011 e815 blt .adc27 4285 bmi('.adc27') #25 C flag
1012 ad00 suba [y,x] 4286 suba([Y,X]) #26
1013 fc17 bra .adc29 4287 bra('.adc29') #27
1014 4d00 ora [y,x] 4288 ora([Y,X]) #28
4289 label('.adc27')
.adc27: 1015 2d00 anda [y,x] 4290 anda([Y,X]) #27
1016 0200 nop 4291 nop() #28
4292 label('.adc29')
.adc29: 1017 3080 anda $80,x 4293 anda(0x80,X) #29
1018 0127 ld [$27] 4294 ld([v6502_P]) #30 Update P
1019 207e anda $7e 4295 anda(~v6502_Vemu&~v6502_Cflag) #31
101a 4500 ora [x] 4296 ora([X]) #32
101b 411d ora [$1d] 4297 ora([v6502_Tmp]) #33
101c c227 st [$27] 4298 st([v6502_P]) #34
101d 140e ld $0e,y 4299 ld(hi('v6502_next'),Y) #35
101e e020 jmp y,$20 4300 jmp(Y,'v6502_next') #36
101f 00ed ld $ed 4301 ld(-38/2) #37
4302 # Cin=1, A=$FF, B=$DD --> Result=$DD, Cout=1, V=0
4303 # Cin=0, A=$00, B=$DD --> Result=$DD, Cout=0, V=0
4304 label('.adc14')
.adc14: 1020 c218 st [$18] 4305 st([v6502_A]) #14 Special case
1021 c228 st [$28] 4306 st([v6502_Qz]) #15 Z flag
1022 c229 st [$29] 4307 st([v6502_Qn]) #16 N flag
1023 0127 ld [$27] 4308 ld([v6502_P]) #17
1024 207f anda $7f 4309 anda(0x7f) #18 V=0, keep C
1025 c227 st [$27] 4310 st([v6502_P]) #19
1026 140e ld $0e,y 4311 ld(hi('v6502_next'),Y) #20
1027 00f4 ld $f4 4312 ld(-24/2) #21
1028 e020 jmp y,$20 4313 jmp(Y,'v6502_next') #22
4314 #nop() #23 Overlap
4315 #
4316 label('v6502_SBC')
4317 # No matter how hard we try, v6502_SBC always comes out a lot clumsier
4318 # than v6502_ADC. And that one already barely fits in 38 cycles and is
4319 # hard to follow. So we use a hack: transmorph our SBC into an ADC with
4320 # inverted operand, and then dispatch again. Simple and effective.
v6502_SBC: 1029 1525 ld [$25],y 4321 ld([v6502_ADH],Y) #9,24
102a 0d00 ld [y,x] 4322 ld([Y,X]) #10
102b 60ff xora $ff 4323 xora(255) #11 Invert right-hand side operand
102c c219 st [$19] 4324 st([v6502_BI]) #12 Park modified operand for v6502_ADC
102d 0019 ld $19 4325 ld(v6502_BI&255) #13 Address of BI
102e d224 st [$24],x 4326 st([v6502_ADL],X) #14
102f 0000 ld $00 4327 ld(v6502_BI>>8) #15
1030 c225 st [$25] 4328 st([v6502_ADH]) #16
1031 0069 ld $69 4329 ld(0x69) #17 ADC #$xx (Any ADC opcode will do)
1032 c226 st [$26] 4330 st([v6502_IR]) #18
1033 140e ld $0e,y 4331 ld(hi('v6502_check'),Y) #20 Go back to time check before dispatch
1034 e0f2 jmp y,$f2 4332 jmp(Y,'v6502_check') #20
1035 00f5 ld $f5 4333 ld(-22/2) #21
4334
4335 # Carry calculation table
4336 # L7 R7 C7 RX UC SC
4337 # -- -- -- | -- -- --
4338 # 0 0 0 | 0 0 0
4339 # 0 0 1 | 0 0 0
4340 # 1 0 0 | 0 1 +1
4341 # 1 0 1 | 0 0 0
4342 # 0 1 0 | -1 1 0
4343 # 0 1 1 | -1 0 -1
4344 # 1 1 0 | -1 1 0
4345 # 1 1 1 | -1 1 0
4346 # -- -- -- | -- -- --
4347 # ^ ^ ^ ^ ^ ^
4348 # | | | | | `--- Carry of unsigned L + signed R: SC = RX + UC
4349 # | | | | `----- Carry of unsigned L + unsigned R: UC = C7 ? L7&R7 : L7|R7
4350 # | | | `------- Sign extension of signed R
4351 # | | `--------- MSB of unextended L + R
4352 # | `----------- MSB of right operand R
4353 # `------------- MSB of left operand L
4354
4355 label('v6502_CLC')
v6502_CLC: 1036 0127 ld [$27] 4356 ld([v6502_P]) #9
1037 fc3b bra .sec12 4357 bra('.sec12') #10
4358 label('v6502_SEC')
v6502_SEC: 1038 20fe anda $fe 4359 anda(~v6502_Cflag) #9,11 Overlap
1039 0127 ld [$27] 4360 ld([v6502_P]) #10
103a 4001 ora $01 4361 ora(v6502_Cflag) #11
4362 label('.sec12')
.sec12: 103b c227 st [$27] 4363 st([v6502_P]) #12
103c 0200 nop 4364 nop() #13
4365 label('.next14')
.next14: 103d e020 jmp y,$20 4366 jmp(Y,'v6502_next') #14
103e 00f8 ld $f8 4367 ld(-16/2) #15
4368
4369 label('v6502_BPL')
v6502_BPL: 103f 0129 ld [$29] 4370 ld([v6502_Qn]) #9
1040 e875 blt .next12 4371 bmi('.next12') #10
1041 f45b bge .branch13 4372 bpl('.branch13') #11
4373 #nop() #12 Overlap
4374 label('v6502_BMI')
v6502_BMI: 1042 0129 ld [$29] 4375 ld([v6502_Qn]) #9,12
1043 f475 bge .next12 4376 bpl('.next12') #10
1044 e85b blt .branch13 4377 bmi('.branch13') #11
4378 #nop() #12 Overlap
4379 label('v6502_BVC')
v6502_BVC: 1045 0127 ld [$27] 4380 ld([v6502_P]) #9,12
1046 2080 anda $80 4381 anda(v6502_Vemu) #10
1047 f05b beq .branch13 4382 beq('.branch13') #11
1048 ec3d bne .next14 4383 bne('.next14') #12
4384 #nop() #13 Overlap
4385 label('v6502_BVS')
v6502_BVS: 1049 0127 ld [$27] 4386 ld([v6502_P]) #9,13
104a 2080 anda $80 4387 anda(v6502_Vemu) #10
104b ec5b bne .branch13 4388 bne('.branch13') #11
104c f03d beq .next14 4389 beq('.next14') #12
4390 #nop() #13 Overlap
4391 label('v6502_BCC')
v6502_BCC: 104d 0127 ld [$27] 4392 ld([v6502_P]) #9,13
104e 2001 anda $01 4393 anda(v6502_Cflag) #10
104f f05b beq .branch13 4394 beq('.branch13') #11
1050 ec3d bne .next14 4395 bne('.next14') #12
4396 #nop() #13 Overlap
4397 label('v6502_BCS')
v6502_BCS: 1051 0127 ld [$27] 4398 ld([v6502_P]) #9,13
1052 2001 anda $01 4399 anda(v6502_Cflag) #10
1053 ec5b bne .branch13 4400 bne('.branch13') #11
1054 f03d beq .next14 4401 beq('.next14') #12
4402 #nop() #13 Overlap
4403 label('v6502_BNE')
v6502_BNE: 1055 0128 ld [$28] 4404 ld([v6502_Qz]) #9,13
1056 f075 beq .next12 4405 beq('.next12') #10
1057 ec5b bne .branch13 4406 bne('.branch13') #11
4407 #nop() #12 Overlap
4408 label('v6502_BEQ')
v6502_BEQ: 1058 0128 ld [$28] 4409 ld([v6502_Qz]) #9,12
1059 ec75 bne .next12 4410 bne('.next12') #10
105a f05b beq .branch13 4411 beq('.branch13') #11
4412 #nop() #12 Overlap
4413 label('.branch13')
.branch13: 105b 0124 ld [$24] 4414 ld([v6502_ADL]) #13,12 PC + offset
105c 811a adda [$1a] 4415 adda([v6502_PCL]) #14
105d c21a st [$1a] 4416 st([v6502_PCL]) #15
105e e862 blt .bra0 4417 bmi('.bra0') #16 Carry
105f a124 suba [$24] 4418 suba([v6502_ADL]) #17
1060 fc64 bra .bra1 4419 bra('.bra1') #18
1061 4124 ora [$24] 4420 ora([v6502_ADL]) #19
4421 label('.bra0')
.bra0: 1062 2124 anda [$24] 4422 anda([v6502_ADL]) #18
1063 0200 nop 4423 nop() #19
4424 label('.bra1')
.bra1: 1064 3080 anda $80,x 4425 anda(0x80,X) #20
1065 0500 ld [x] 4426 ld([X]) #21
1066 8125 adda [$25] 4427 adda([v6502_ADH]) #22
1067 811b adda [$1b] 4428 adda([v6502_PCH]) #23
1068 c21b st [$1b] 4429 st([v6502_PCH]) #24
1069 0200 nop 4430 nop() #25
106a e020 jmp y,$20 4431 jmp(Y,'v6502_next') #26
106b 00f2 ld $f2 4432 ld(-28/2) #27
4433
4434 label('v6502_INX')
v6502_INX: 106c 0200 nop 4435 nop() #9
106d 012a ld [$2a] 4436 ld([v6502_X]) #10
106e 8001 adda $01 4437 adda(1) #11
106f c22a st [$2a] 4438 st([v6502_X]) #12
4439 label('.inx13')
.inx13: 1070 c228 st [$28] 4440 st([v6502_Qz]) #13 Z flag
1071 c229 st [$29] 4441 st([v6502_Qn]) #14 N flag
1072 00f7 ld $f7 4442 ld(-18/2) #15
1073 e020 jmp y,$20 4443 jmp(Y,'v6502_next') #16
1074 0200 nop 4444 nop() #17
4445
4446 label('.next12')
.next12: 1075 e020 jmp y,$20 4447 jmp(Y,'v6502_next') #12
1076 00f9 ld $f9 4448 ld(-14/2) #13
4449
4450 label('v6502_DEX')
v6502_DEX: 1077 012a ld [$2a] 4451 ld([v6502_X]) #9
1078 a001 suba $01 4452 suba(1) #10
1079 fc70 bra .inx13 4453 bra('.inx13') #11
107a c22a st [$2a] 4454 st([v6502_X]) #12
4455
4456 label('v6502_INY')
v6502_INY: 107b 012b ld [$2b] 4457 ld([v6502_Y]) #9
107c 8001 adda $01 4458 adda(1) #10
107d fc70 bra .inx13 4459 bra('.inx13') #11
107e c22b st [$2b] 4460 st([v6502_Y]) #12
4461
4462 label('v6502_DEY')
v6502_DEY: 107f 012b ld [$2b] 4463 ld([v6502_Y]) #9
1080 a001 suba $01 4464 suba(1) #10
1081 fc70 bra .inx13 4465 bra('.inx13') #11
1082 c22b st [$2b] 4466 st([v6502_Y]) #12
4467
4468 label('v6502_NOP')
v6502_NOP: 1083 00fa ld $fa 4469 ld(-12/2) #9
1084 e020 jmp y,$20 4470 jmp(Y,'v6502_next') #10
4471 #nop() #11 Overlap
4472 #
4473 label('v6502_AND')
v6502_AND: 1085 1525 ld [$25],y 4474 ld([v6502_ADH],Y) #9,11
1086 0118 ld [$18] 4475 ld([v6502_A]) #10
1087 fc90 bra .eor13 4476 bra('.eor13') #11
1088 2d00 anda [y,x] 4477 anda([Y,X]) #12
4478
4479 label('v6502_ORA')
v6502_ORA: 1089 1525 ld [$25],y 4480 ld([v6502_ADH],Y) #9
108a 0118 ld [$18] 4481 ld([v6502_A]) #10
108b fc90 bra .eor13 4482 bra('.eor13') #11
4483 label('v6502_EOR')
v6502_EOR: 108c 4d00 ora [y,x] 4484 ora([Y,X]) #12,9
4485 #
4486 #label('v6502_EOR')
4487 #nop() #9 Overlap
108d 1525 ld [$25],y 4488 ld([v6502_ADH],Y) #10
108e 0118 ld [$18] 4489 ld([v6502_A]) #11
108f 6d00 xora [y,x] 4490 xora([Y,X]) #12
4491 label('.eor13')
.eor13: 1090 c218 st [$18] 4492 st([v6502_A]) #13
1091 c228 st [$28] 4493 st([v6502_Qz]) #14 Z flag
1092 c229 st [$29] 4494 st([v6502_Qn]) #15 N flag
1093 140e ld $0e,y 4495 ld(hi('v6502_next'),Y) #16
1094 00f6 ld $f6 4496 ld(-20/2) #17
1095 e020 jmp y,$20 4497 jmp(Y,'v6502_next') #18
4498 #nop() #19 Overlap
4499 #
4500 label('v6502_JMP1')
v6502_JMP1: 1096 140d ld $0d,y 4501 ld(hi('v6502_jmp1'),Y) #9,19 JMP $DDDD
1097 e0c5 jmp y,$c5 4502 jmp(Y,'v6502_jmp1') #10
4503 #nop() #11 Overlap
4504 label('v6502_JMP2')
v6502_JMP2: 1098 140d ld $0d,y 4505 ld(hi('v6502_jmp2'),Y) #9 JMP ($DDDD)
1099 e0cd jmp y,$cd 4506 jmp(Y,'v6502_jmp2') #10
4507 #nop() #11 Overlap
4508 label('v6502_JSR')
v6502_JSR: 109a 011c ld [$1c] 4509 ld([v6502_S]) #9,11
109b a002 suba $02 4510 suba(2) #10
109c d21c st [$1c],x 4511 st([v6502_S],X) #11
109d 1400 ld $00,y 4512 ld(v6502_Stack>>8,Y) #12
109e 011b ld [$1b] 4513 ld([v6502_PCH]) #13 Let ADL,ADH point to L operand
109f c225 st [$25] 4514 st([v6502_ADH]) #14
10a0 011a ld [$1a] 4515 ld([v6502_PCL]) #15
10a1 c224 st [$24] 4516 st([v6502_ADL]) #16
10a2 8001 adda $01 4517 adda(1) #17 Push ++PC
10a3 c21a st [$1a] 4518 st([v6502_PCL]) #18 Let PCL,PCH point to H operand
10a4 de00 st [y,x++] 4519 st([Y,Xpp]) #19
10a5 f0a8 beq $10a8 4520 beq(pc()+3) #20
10a6 fca9 bra $10a9 4521 bra(pc()+3) #21
10a7 0000 ld $00 4522 ld(0) #22
10a8 0001 ld $01 4523 ld(1) #22(!)
10a9 811b adda [$1b] 4524 adda([v6502_PCH]) #23
10aa c21b st [$1b] 4525 st([v6502_PCH]) #24
10ab ce00 st [y,x] 4526 st([Y,X]) #25
10ac 1124 ld [$24],x 4527 ld([v6502_ADL],X) #26 Fetch L
10ad 1525 ld [$25],y 4528 ld([v6502_ADH],Y) #27
10ae 0d00 ld [y,x] 4529 ld([Y,X]) #28
10af 111a ld [$1a],x 4530 ld([v6502_PCL],X) #29 Fetch H
10b0 c21a st [$1a] 4531 st([v6502_PCL]) #30
10b1 151b ld [$1b],y 4532 ld([v6502_PCH],Y) #31
10b2 0d00 ld [y,x] 4533 ld([Y,X]) #32
10b3 c21b st [$1b] 4534 st([v6502_PCH]) #33
10b4 140e ld $0e,y 4535 ld(hi('v6502_next'),Y) #34
10b5 00ed ld $ed 4536 ld(-38/2) #35
10b6 e020 jmp y,$20 4537 jmp(Y,'v6502_next') #36
4538 #nop() #37 Overlap
4539 #
4540 label('v6502_INC')
v6502_INC: 10b7 1411 ld $11,y 4541 ld(hi('v6502_inc'),Y) #9,37
10b8 e00e jmp y,$0e 4542 jmp(Y,'v6502_inc') #10
4543 #nop() #11 Overlap
4544 label('v6502_LDA')
v6502_LDA: 10b9 1411 ld $11,y 4545 ld(hi('v6502_lda'),Y) #9,11
10ba e018 jmp y,$18 4546 jmp(Y,'v6502_lda') #10
4547 #nop() #11 Overlap
4548 label('v6502_LDX')
v6502_LDX: 10bb 1411 ld $11,y 4549 ld(hi('v6502_ldx'),Y) #9,11
10bc e022 jmp y,$22 4550 jmp(Y,'v6502_ldx') #10
4551 #nop() #11 Overlap
4552 label('v6502_LDX2')
v6502_LDX2: 10bd 1411 ld $11,y 4553 ld(hi('v6502_ldx2'),Y) #9,11
10be e02a jmp y,$2a 4554 jmp(Y,'v6502_ldx2') #10
4555 #nop() #11 Overlap
4556 label('v6502_LDY')
v6502_LDY: 10bf 1411 ld $11,y 4557 ld(hi('v6502_ldy'),Y) #9,11
10c0 e026 jmp y,$26 4558 jmp(Y,'v6502_ldy') #10
4559 #nop() #11 Overlap
4560 label('v6502_STA')
v6502_STA: 10c1 1411 ld $11,y 4561 ld(hi('v6502_sta'),Y) #9,11
10c2 e034 jmp y,$34 4562 jmp(Y,'v6502_sta') #10
4563 #nop() #11 Overlap
4564 label('v6502_STX')
v6502_STX: 10c3 1411 ld $11,y 4565 ld(hi('v6502_stx'),Y) #9,11
10c4 e03a jmp y,$3a 4566 jmp(Y,'v6502_stx') #10
4567 #nop() #11 Overlap
4568 label('v6502_STX2')
v6502_STX2: 10c5 1411 ld $11,y 4569 ld(hi('v6502_stx2'),Y) #9,11
10c6 e040 jmp y,$40 4570 jmp(Y,'v6502_stx2') #10
4571 #nop() #11 Overlap
4572 label('v6502_STY')
v6502_STY: 10c7 1411 ld $11,y 4573 ld(hi('v6502_sty'),Y) #9,11
10c8 e048 jmp y,$48 4574 jmp(Y,'v6502_sty') #10
4575 #nop() #11 Overlap
4576 label('v6502_TAX')
v6502_TAX: 10c9 1411 ld $11,y 4577 ld(hi('v6502_tax'),Y) #9,11
10ca e04d jmp y,$4d 4578 jmp(Y,'v6502_tax') #10
4579 #nop() #11 Overlap
4580 label('v6502_TAY')
v6502_TAY: 10cb 1411 ld $11,y 4581 ld(hi('v6502_tay'),Y) #9,11
10cc e062 jmp y,$62 4582 jmp(Y,'v6502_tay') #10
4583 #nop() #11 Overlap
4584 label('v6502_TXA')
v6502_TXA: 10cd 1411 ld $11,y 4585 ld(hi('v6502_txa'),Y) #9,11
10ce e065 jmp y,$65 4586 jmp(Y,'v6502_txa') #10
4587 #nop() #11 Overlap
4588 label('v6502_TYA')
v6502_TYA: 10cf 1411 ld $11,y 4589 ld(hi('v6502_tya'),Y) #9,11
10d0 e068 jmp y,$68 4590 jmp(Y,'v6502_tya') #10
4591 #nop() #11 Overlap
4592 label('v6502_CLV')
v6502_CLV: 10d1 1411 ld $11,y 4593 ld(hi('v6502_clv'),Y) #9,11
10d2 e076 jmp y,$76 4594 jmp(Y,'v6502_clv') #10
4595 #nop() #11 Overlap
4596 label('v6502_RTI')
v6502_RTI: 10d3 1411 ld $11,y 4597 ld(hi('v6502_rti'),Y) #9,11
10d4 e0e4 jmp y,$e4 4598 jmp(Y,'v6502_rti') #10
4599 #nop() #11 Overlap
4600 label('v6502_ROR')
v6502_ROR: 10d5 140d ld $0d,y 4601 ld(hi('v6502_ror'),Y) #9,11
10d6 e083 jmp y,$83 4602 jmp(Y,'v6502_ror') #10
4603 #nop() #11 Overlap
4604 label('v6502_LSR')
v6502_LSR: 10d7 140d ld $0d,y 4605 ld(hi('v6502_lsr'),Y) #9,11
10d8 e09d jmp y,$9d 4606 jmp(Y,'v6502_lsr') #10
4607 #nop() #11 Overlap
4608 label('v6502_PHA')
v6502_PHA: 10d9 140d ld $0d,y 4609 ld(hi('v6502_pha'),Y) #9,11
10da e0e2 jmp y,$e2 4610 jmp(Y,'v6502_pha') #10
4611 #nop() #11 Overlap
4612 label('v6502_CLI')
v6502_CLI: 10db 1411 ld $11,y 4613 ld(hi('v6502_cli'),Y) #9,11
10dc e06b jmp y,$6b 4614 jmp(Y,'v6502_cli') #10
4615 #nop() #11 Overlap
4616 label('v6502_RTS')
v6502_RTS: 10dd 1411 ld $11,y 4617 ld(hi('v6502_rts'),Y) #9,11
10de e08f jmp y,$8f 4618 jmp(Y,'v6502_rts') #10
4619 #nop() #11 Overlap
4620 label('v6502_PLA')
v6502_PLA: 10df 140d ld $0d,y 4621 ld(hi('v6502_pla'),Y) #9,11
10e0 e0d7 jmp y,$d7 4622 jmp(Y,'v6502_pla') #10
4623 #nop() #11 Overlap
4624 label('v6502_SEI')
v6502_SEI: 10e1 1411 ld $11,y 4625 ld(hi('v6502_sei'),Y) #9,11
10e2 e06e jmp y,$6e 4626 jmp(Y,'v6502_sei') #10
4627 #nop() #11 Overlap
4628 label('v6502_TXS')
v6502_TXS: 10e3 1411 ld $11,y 4629 ld(hi('v6502_txs'),Y) #9,11
10e4 e05e jmp y,$5e 4630 jmp(Y,'v6502_txs') #10
4631 #nop() #11 Overlap
4632 label('v6502_TSX')
v6502_TSX: 10e5 1411 ld $11,y 4633 ld(hi('v6502_tsx'),Y) #9,11
10e6 e054 jmp y,$54 4634 jmp(Y,'v6502_tsx') #10
4635 #nop() #11 Overlap
4636 label('v6502_CPY')
v6502_CPY: 10e7 1411 ld $11,y 4637 ld(hi('v6502_cpy'),Y) #9,11
10e8 e0bd jmp y,$bd 4638 jmp(Y,'v6502_cpy') #10
4639 #nop() #11 Overlap
4640 label('v6502_CMP')
v6502_CMP: 10e9 1411 ld $11,y 4641 ld(hi('v6502_cmp'),Y) #9,11
10ea e0be jmp y,$be 4642 jmp(Y,'v6502_cmp') #10
4643 #nop() #11 Overlap
4644 label('v6502_DEC')
v6502_DEC: 10eb 1411 ld $11,y 4645 ld(hi('v6502_dec'),Y) #9,11
10ec e005 jmp y,$05 4646 jmp(Y,'v6502_dec') #10
4647 #nop() #11 Overlap
4648 label('v6502_CLD')
v6502_CLD: 10ed 1411 ld $11,y 4649 ld(hi('v6502_cld'),Y) #9,11
10ee e071 jmp y,$71 4650 jmp(Y,'v6502_cld') #10
4651 #nop() #11 Overlap
4652 label('v6502_CPX')
v6502_CPX: 10ef 1411 ld $11,y 4653 ld(hi('v6502_cpx'),Y) #9,11
10f0 e0bb jmp y,$bb 4654 jmp(Y,'v6502_cpx') #10
4655 #nop() #11 Overlap
4656 label('v6502_ASL')
v6502_ASL: 10f1 140d ld $0d,y 4657 ld(hi('v6502_asl'),Y) #9,11
10f2 e0bf jmp y,$bf 4658 jmp(Y,'v6502_asl') #10
4659 #nop() #11 Overlap
4660 label('v6502_PHP')
v6502_PHP: 10f3 1411 ld $11,y 4661 ld(hi('v6502_php'),Y) #9,11
10f4 e0a2 jmp y,$a2 4662 jmp(Y,'v6502_php') #10
4663 #nop() #11 Overlap
4664 label('v6502_BIT')
v6502_BIT: 10f5 1411 ld $11,y 4665 ld(hi('v6502_bit'),Y) #9
10f6 e07d jmp y,$7d 4666 jmp(Y,'v6502_bit') #10
4667 #nop() #11 Overlap
4668 label('v6502_ROL')
v6502_ROL: 10f7 140d ld $0d,y 4669 ld(hi('v6502_rol'),Y) #9
10f8 e0ac jmp y,$ac 4670 jmp(Y,'v6502_rol') #10
4671 #nop() #11 Overlap
4672 label('v6502_PLP')
v6502_PLP: 10f9 1411 ld $11,y 4673 ld(hi('v6502_plp'),Y) #9
10fa e0d4 jmp y,$d4 4674 jmp(Y,'v6502_plp') #10
4675 #nop() #11 Overlap
4676 label('v6502_SED') # Decimal mode not implemented
v6502_SED: 10fb 1411 ld $11,y 4677 ld(hi('v6502_sed'),Y) #9,11
10fc e074 jmp y,$74 4678 jmp(Y,'v6502_sed') #10
4679 #nop() #11 Overlap
4680 label('v6502_ILL') # All illegal opcodes map to BRK, except $FF which will crash
4681 label('v6502_BRK')
v6502_ILL:
v6502_BRK: 10fd 140d ld $0d,y 4682 ld(hi('v6502_brk'),Y) #9
10fe e0ea jmp y,$ea 4683 jmp(Y,'v6502_brk') #10
4684 #nop() #11 Overlap
4685
4686 while pc()&255 < 255:
4687 nop()
4688
4689 # `v6502_RESUME' is the interpreter's secondary entry point for when
4690 # the opcode and operands were already fetched, just before the last hPulse.
4691 # It must be at $xxff, prefably somewhere in v6502's own code pages.
4692 label('v6502_RESUME')
4693 assert (pc()&255) == 255
v6502_RESUME: 10ff a006 suba $06 4694 suba(v6502_adjust) #0,11 v6502 secondary entry point
4695 # --- Page boundary ---
4696 align(0x100,size=0x200)
1100 c215 st [$15] 4697 st([vTicks]) #1
1101 1124 ld [$24],x 4698 ld([v6502_ADL],X) #2
1102 140f ld $0f,y 4699 ld(hi('v6502_execute'),Y) #3
1103 e126 jmp y,[$26] 4700 jmp(Y,[v6502_IR]) #4
1104 fcff bra $ff 4701 bra(255) #5
4702
4703 label('v6502_dec')
v6502_dec: 1105 1525 ld [$25],y 4704 ld([v6502_ADH],Y) #12
1106 0d00 ld [y,x] 4705 ld([Y,X]) #13
1107 a001 suba $01 4706 suba(1) #14
1108 ce00 st [y,x] 4707 st([Y,X]) #15
1109 c228 st [$28] 4708 st([v6502_Qz]) #16 Z flag
110a c229 st [$29] 4709 st([v6502_Qn]) #17 N flag
110b 140e ld $0e,y 4710 ld(hi('v6502_next'),Y) #18
110c 00f5 ld $f5 4711 ld(-22/2) #19
110d e020 jmp y,$20 4712 jmp(Y,'v6502_next') #20
4713 #nop() #21 Overlap
4714 #
4715 label('v6502_inc')
v6502_inc: 110e 1525 ld [$25],y 4716 ld([v6502_ADH],Y) #12,22
110f 0d00 ld [y,x] 4717 ld([Y,X]) #13
1110 8001 adda $01 4718 adda(1) #14
1111 ce00 st [y,x] 4719 st([Y,X]) #15
1112 c228 st [$28] 4720 st([v6502_Qz]) #16 Z flag
1113 c229 st [$29] 4721 st([v6502_Qn]) #17 N flag
1114 140e ld $0e,y 4722 ld(hi('v6502_next'),Y) #18
1115 00f5 ld $f5 4723 ld(-22/2) #19
1116 e020 jmp y,$20 4724 jmp(Y,'v6502_next') #20
1117 0200 nop 4725 nop() #21
4726
4727 label('v6502_lda')
v6502_lda: 1118 0200 nop 4728 nop() #12
1119 1525 ld [$25],y 4729 ld([v6502_ADH],Y) #13
111a 0d00 ld [y,x] 4730 ld([Y,X]) #14
111b c218 st [$18] 4731 st([v6502_A]) #15
4732 label('.lda16')
.lda16: 111c c228 st [$28] 4733 st([v6502_Qz]) #16 Z flag
111d c229 st [$29] 4734 st([v6502_Qn]) #17 N flag
111e 0200 nop 4735 nop() #18
111f 140e ld $0e,y 4736 ld(hi('v6502_next'),Y) #19
1120 e020 jmp y,$20 4737 jmp(Y,'v6502_next') #20
1121 00f5 ld $f5 4738 ld(-22/2) #21
4739
4740 label('v6502_ldx')
v6502_ldx: 1122 1525 ld [$25],y 4741 ld([v6502_ADH],Y) #12
1123 0d00 ld [y,x] 4742 ld([Y,X]) #13
1124 fc1c bra .lda16 4743 bra('.lda16') #14
1125 c22a st [$2a] 4744 st([v6502_X]) #15
4745
4746 label('v6502_ldy')
v6502_ldy: 1126 1525 ld [$25],y 4747 ld([v6502_ADH],Y) #12
1127 0d00 ld [y,x] 4748 ld([Y,X]) #13
1128 fc1c bra .lda16 4749 bra('.lda16') #14
1129 c22b st [$2b] 4750 st([v6502_Y]) #15
4751
4752 label('v6502_ldx2')
v6502_ldx2: 112a 0124 ld [$24] 4753 ld([v6502_ADL]) #12 Special case $B6: LDX $DD,Y
112b a12a suba [$2a] 4754 suba([v6502_X]) #13 Undo X offset
112c 912b adda [$2b],x 4755 adda([v6502_Y],X) #14 Apply Y instead
112d 0500 ld [x] 4756 ld([X]) #15
112e c22a st [$2a] 4757 st([v6502_X]) #16
112f c228 st [$28] 4758 st([v6502_Qz]) #17 Z flag
1130 c229 st [$29] 4759 st([v6502_Qn]) #18 N flag
1131 140e ld $0e,y 4760 ld(hi('v6502_next'),Y) #19
1132 e020 jmp y,$20 4761 jmp(Y,'v6502_next') #20
1133 00f5 ld $f5 4762 ld(-22/2) #21
4763
4764 label('v6502_sta')
v6502_sta: 1134 1525 ld [$25],y 4765 ld([v6502_ADH],Y) #12
1135 0118 ld [$18] 4766 ld([v6502_A]) #13
1136 ce00 st [y,x] 4767 st([Y,X]) #14
1137 140e ld $0e,y 4768 ld(hi('v6502_next'),Y) #15
1138 e020 jmp y,$20 4769 jmp(Y,'v6502_next') #16
1139 00f7 ld $f7 4770 ld(-18/2) #17
4771
4772 label('v6502_stx')
v6502_stx: 113a 1525 ld [$25],y 4773 ld([v6502_ADH],Y) #12
113b 012a ld [$2a] 4774 ld([v6502_X]) #13
113c ce00 st [y,x] 4775 st([Y,X]) #14
113d 140e ld $0e,y 4776 ld(hi('v6502_next'),Y) #15
113e e020 jmp y,$20 4777 jmp(Y,'v6502_next') #16
113f 00f7 ld $f7 4778 ld(-18/2) #17
4779
4780 label('v6502_stx2')
v6502_stx2: 1140 0124 ld [$24] 4781 ld([v6502_ADL]) #12 Special case $96: STX $DD,Y
1141 a12a suba [$2a] 4782 suba([v6502_X]) #13 Undo X offset
1142 912b adda [$2b],x 4783 adda([v6502_Y],X) #14 Apply Y instead
1143 012a ld [$2a] 4784 ld([v6502_X]) #15
1144 c600 st [x] 4785 st([X]) #16
1145 140e ld $0e,y 4786 ld(hi('v6502_next'),Y) #17
1146 e020 jmp y,$20 4787 jmp(Y,'v6502_next') #18
1147 00f6 ld $f6 4788 ld(-20/2) #19
4789
4790 label('v6502_sty')
v6502_sty: 1148 1525 ld [$25],y 4791 ld([v6502_ADH],Y) #12
1149 012b ld [$2b] 4792 ld([v6502_Y]) #13
114a ce00 st [y,x] 4793 st([Y,X]) #14
114b 140e ld $0e,y 4794 ld(hi('v6502_next'),Y) #15
114c e020 jmp y,$20 4795 jmp(Y,'v6502_next') #16
4796 label('v6502_tax')
v6502_tax: 114d 00f7 ld $f7 4797 ld(-18/2) #17,12
4798 #
4799 #label('v6502_tax')
4800 #nop() #12 Overlap
114e 0118 ld [$18] 4801 ld([v6502_A]) #13
114f c22a st [$2a] 4802 st([v6502_X]) #14
4803 label('.tax15')
.tax15: 1150 c228 st [$28] 4804 st([v6502_Qz]) #15 Z flag
1151 c229 st [$29] 4805 st([v6502_Qn]) #16 N flag
1152 140e ld $0e,y 4806 ld(hi('v6502_next'),Y) #17
1153 e020 jmp y,$20 4807 jmp(Y,'v6502_next') #18
4808 label('v6502_tsx')
v6502_tsx: 1154 00f6 ld $f6 4809 ld(-20/2) #19
4810 #
4811 #label('v6502_tsx')
4812 #nop() #12 Overlap
1155 011c ld [$1c] 4813 ld([v6502_S]) #13
1156 a001 suba $01 4814 suba(1) #14 Shift down on export
1157 c22a st [$2a] 4815 st([v6502_X]) #15
4816 label('.tsx16')
.tsx16: 1158 c228 st [$28] 4817 st([v6502_Qz]) #16 Z flag
1159 c229 st [$29] 4818 st([v6502_Qn]) #17 N flag
115a 0200 nop 4819 nop() #18
115b 140e ld $0e,y 4820 ld(hi('v6502_next'),Y) #19
115c e020 jmp y,$20 4821 jmp(Y,'v6502_next') #20
115d 00f5 ld $f5 4822 ld(-22/2) #21
4823
4824 label('v6502_txs')
v6502_txs: 115e 012a ld [$2a] 4825 ld([v6502_X]) #12
115f 8001 adda $01 4826 adda(1) #13 Shift up on import
1160 fc58 bra .tsx16 4827 bra('.tsx16') #14
1161 c21c st [$1c] 4828 st([v6502_S]) #15
4829
4830 label('v6502_tay')
v6502_tay: 1162 0118 ld [$18] 4831 ld([v6502_A]) #12
1163 fc50 bra .tax15 4832 bra('.tax15') #13
1164 c22b st [$2b] 4833 st([v6502_Y]) #14
4834
4835 label('v6502_txa')
v6502_txa: 1165 012a ld [$2a] 4836 ld([v6502_X]) #12
1166 fc50 bra .tax15 4837 bra('.tax15') #13
1167 c218 st [$18] 4838 st([v6502_A]) #14
4839
4840 label('v6502_tya')
v6502_tya: 1168 012b ld [$2b] 4841 ld([v6502_Y]) #12
1169 fc50 bra .tax15 4842 bra('.tax15') #13
116a c218 st [$18] 4843 st([v6502_A]) #14
4844
4845 label('v6502_cli')
v6502_cli: 116b 0127 ld [$27] 4846 ld([v6502_P]) #12
116c fc79 bra .clv15 4847 bra('.clv15') #13
116d 20fb anda $fb 4848 anda(~v6502_Iflag) #14
4849
4850 label('v6502_sei')
v6502_sei: 116e 0127 ld [$27] 4851 ld([v6502_P]) #12
116f fc79 bra .clv15 4852 bra('.clv15') #13
1170 4004 ora $04 4853 ora(v6502_Iflag) #14
4854
4855 label('v6502_cld')
v6502_cld: 1171 0127 ld [$27] 4856 ld([v6502_P]) #12
1172 fc79 bra .clv15 4857 bra('.clv15') #13
1173 20f7 anda $f7 4858 anda(~v6502_Dflag) #14
4859
4860 label('v6502_sed')
v6502_sed: 1174 0127 ld [$27] 4861 ld([v6502_P]) #12
1175 fc79 bra .clv15 4862 bra('.clv15') #13
4863 label('v6502_clv')
v6502_clv: 1176 4008 ora $08 4864 ora(v6502_Dflag) #14,12 Overlap
4865 #
4866 #label('v6502_clv')
4867 #nop() #12
1177 0127 ld [$27] 4868 ld([v6502_P]) #13
1178 207f anda $7f 4869 anda(~v6502_Vemu) #14
4870 label('.clv15')
.clv15: 1179 c227 st [$27] 4871 st([v6502_P]) #15
117a 140e ld $0e,y 4872 ld(hi('v6502_next'),Y) #16
117b 00f6 ld $f6 4873 ld(-20/2) #17
117c e020 jmp y,$20 4874 jmp(Y,'v6502_next') #18
4875 label('v6502_bit')
v6502_bit: 117d 0200 nop 4876 nop() #19,12
4877 #
4878 #label('v6502_bit')
4879 #nop() #12 Overlap
117e 1124 ld [$24],x 4880 ld([v6502_ADL],X) #13
117f 1525 ld [$25],y 4881 ld([v6502_ADH],Y) #14
1180 0d00 ld [y,x] 4882 ld([Y,X]) #15
1181 c229 st [$29] 4883 st([v6502_Qn]) #16 N flag
1182 2118 anda [$18] 4884 anda([v6502_A]) #17 This is a reason we keep N and Z in separate bytes
1183 c228 st [$28] 4885 st([v6502_Qz]) #18 Z flag
1184 0127 ld [$27] 4886 ld([v6502_P]) #19
1185 207f anda $7f 4887 anda(~v6502_Vemu) #20
1186 c227 st [$27] 4888 st([v6502_P]) #21
1187 0d00 ld [y,x] 4889 ld([Y,X]) #22
1188 8200 adda ac 4890 adda(AC) #23
1189 2080 anda $80 4891 anda(v6502_Vemu) #24
118a 4127 ora [$27] 4892 ora([v6502_P]) #25
118b c227 st [$27] 4893 st([v6502_P]) #26 Update V
118c 140e ld $0e,y 4894 ld(hi('v6502_next'),Y) #27
118d e020 jmp y,$20 4895 jmp(Y,'v6502_next') #28
118e 00f1 ld $f1 4896 ld(-30/2) #29
4897
4898 label('v6502_rts')
v6502_rts: 118f 011c ld [$1c] 4899 ld([v6502_S]) #12
1190 1200 ld ac,x 4900 ld(AC,X) #13
1191 8002 adda $02 4901 adda(2) #14
1192 c21c st [$1c] 4902 st([v6502_S]) #15
1193 1400 ld $00,y 4903 ld(0,Y) #16
1194 0d00 ld [y,x] 4904 ld([Y,X]) #17
1195 de00 st [y,x++] 4905 st([Y,Xpp]) #18 Just X++
1196 8001 adda $01 4906 adda(1) #19
1197 c21a st [$1a] 4907 st([v6502_PCL]) #20
1198 f09b beq $119b 4908 beq(pc()+3) #21
1199 fc9c bra $119c 4909 bra(pc()+3) #22
119a 0000 ld $00 4910 ld(0) #23
119b 0001 ld $01 4911 ld(1) #23(!)
119c 8d00 adda [y,x] 4912 adda([Y,X]) #24
119d c21b st [$1b] 4913 st([v6502_PCH]) #25
119e 0200 nop 4914 nop() #26
119f 140e ld $0e,y 4915 ld(hi('v6502_next'),Y) #27
11a0 e020 jmp y,$20 4916 jmp(Y,'v6502_next') #28
11a1 00f1 ld $f1 4917 ld(-30/2) #29
4918
4919 label('v6502_php')
v6502_php: 11a2 011c ld [$1c] 4920 ld([v6502_S]) #12
11a3 a001 suba $01 4921 suba(1) #13
11a4 d21c st [$1c],x 4922 st([v6502_S],X) #14
11a5 0127 ld [$27] 4923 ld([v6502_P]) #15
11a6 20bd anda $bd 4924 anda(~v6502_Vflag&~v6502_Zflag) #16 Keep Vemu,B,D,I,C
11a7 f4aa bge $11aa 4925 bpl(pc()+3) #17 V to bit 6 and clear N
11a8 fcaa bra $11aa 4926 bra(pc()+2) #18
11a9 60c0 xora $c0 4927 xora(v6502_Vflag^v6502_Vemu) #19
11aa c600 st [x] 4928 st([X]) #19,20
11ab 0128 ld [$28] 4929 ld([v6502_Qz]) #21 Z flag
11ac f0af beq $11af 4930 beq(pc()+3) #22
11ad fcb0 bra $11b0 4931 bra(pc()+3) #23
11ae 0000 ld $00 4932 ld(0) #24
11af 0002 ld $02 4933 ld(v6502_Zflag) #24(!)
11b0 4500 ora [x] 4934 ora([X]) #25
11b1 c600 st [x] 4935 st([X]) #26
11b2 0129 ld [$29] 4936 ld([v6502_Qn]) #27 N flag
11b3 2080 anda $80 4937 anda(0x80) #28
11b4 4500 ora [x] 4938 ora([X]) #29
11b5 4020 ora $20 4939 ora(v6502_Uflag) #30 Unused bit
11b6 c600 st [x] 4940 st([X]) #31
11b7 0200 nop 4941 nop() #32
11b8 140e ld $0e,y 4942 ld(hi('v6502_next'),Y) #33
11b9 e020 jmp y,$20 4943 jmp(Y,'v6502_next') #34
11ba 00ee ld $ee 4944 ld(-36/2) #35
4945
4946 label('v6502_cpx')
v6502_cpx: 11bb fcc0 bra .cmp14 4947 bra('.cmp14') #12
11bc 012a ld [$2a] 4948 ld([v6502_X]) #13
4949
4950 label('v6502_cpy')
v6502_cpy: 11bd fcc0 bra .cmp14 4951 bra('.cmp14') #12
4952 label('v6502_cmp')
v6502_cmp: 11be 012b ld [$2b] 4953 ld([v6502_Y]) #13,12
4954 #
4955 #label('v6502_cmp') #12 Overlap
4956 assert v6502_Cflag == 1
11bf 0118 ld [$18] 4957 ld([v6502_A]) #13
4958 label('.cmp14')
.cmp14: 11c0 1525 ld [$25],y 4959 ld([v6502_ADH],Y) #14
11c1 e8c7 blt .cmp17 4960 bmi('.cmp17') #15 Carry?
11c2 ad00 suba [y,x] 4961 suba([Y,X]) #16
11c3 c228 st [$28] 4962 st([v6502_Qz]) #17 Z flag
11c4 c229 st [$29] 4963 st([v6502_Qn]) #18 N flag
11c5 fccb bra .cmp21 4964 bra('.cmp21') #19
11c6 4d00 ora [y,x] 4965 ora([Y,X]) #20
4966 label('.cmp17')
.cmp17: 11c7 c228 st [$28] 4967 st([v6502_Qz]) #17 Z flag
11c8 c229 st [$29] 4968 st([v6502_Qn]) #18 N flag
11c9 2d00 anda [y,x] 4969 anda([Y,X]) #19
11ca 0200 nop 4970 nop() #20
4971 label('.cmp21')
.cmp21: 11cb 6080 xora $80 4972 xora(0x80) #21
11cc 3080 anda $80,x 4973 anda(0x80,X) #22 Move carry to bit 0
11cd 0127 ld [$27] 4974 ld([v6502_P]) #23 C flag
11ce 20fe anda $fe 4975 anda(~1) #24
11cf 4500 ora [x] 4976 ora([X]) #25
11d0 c227 st [$27] 4977 st([v6502_P]) #26
11d1 140e ld $0e,y 4978 ld(hi('v6502_next'),Y) #27
11d2 e020 jmp y,$20 4979 jmp(Y,'v6502_next') #28
11d3 00f1 ld $f1 4980 ld(-30/2) #29
4981
4982 label('v6502_plp')
4983 assert v6502_Nflag == 128
4984 assert 2*v6502_Vflag == v6502_Vemu
v6502_plp: 11d4 011c ld [$1c] 4985 ld([v6502_S]) #12
11d5 1200 ld ac,x 4986 ld(AC,X) #13
11d6 8001 adda $01 4987 adda(1) #14
11d7 c21c st [$1c] 4988 st([v6502_S]) #15
11d8 0500 ld [x] 4989 ld([X]) #16
11d9 c229 st [$29] 4990 st([v6502_Qn]) #17 N flag
11da 2002 anda $02 4991 anda(v6502_Zflag) #18
11db 6002 xora $02 4992 xora(v6502_Zflag) #19
11dc c228 st [$28] 4993 st([v6502_Qz]) #20 Z flag
11dd 0500 ld [x] 4994 ld([X]) #21
11de 207f anda $7f 4995 anda(~v6502_Vemu) #22 V to bit 7
11df 8040 adda $40 4996 adda(v6502_Vflag) #23
11e0 c227 st [$27] 4997 st([v6502_P]) #24 All other flags
11e1 140e ld $0e,y 4998 ld(hi('v6502_next'),Y) #25
11e2 e020 jmp y,$20 4999 jmp(Y,'v6502_next') #26
11e3 00f2 ld $f2 5000 ld(-28/2) #27
5001
5002 label('v6502_rti')
v6502_rti: 11e4 011c ld [$1c] 5003 ld([v6502_S]) #12
11e5 1200 ld ac,x 5004 ld(AC,X) #13
11e6 8003 adda $03 5005 adda(3) #14
11e7 c21c st [$1c] 5006 st([v6502_S]) #15
11e8 0500 ld [x] 5007 ld([X]) #16
11e9 c229 st [$29] 5008 st([v6502_Qn]) #17 N flag
11ea 2002 anda $02 5009 anda(v6502_Zflag) #18
11eb 6002 xora $02 5010 xora(v6502_Zflag) #19
11ec c228 st [$28] 5011 st([v6502_Qz]) #20 Z flag
11ed 1400 ld $00,y 5012 ld(0,Y) #21
11ee 0d00 ld [y,x] 5013 ld([Y,X]) #22
11ef de00 st [y,x++] 5014 st([Y,Xpp]) #23 Just X++
11f0 207f anda $7f 5015 anda(~v6502_Vemu) #24 V to bit 7
11f1 8040 adda $40 5016 adda(v6502_Vflag) #25
11f2 c227 st [$27] 5017 st([v6502_P]) #26 All other flags
11f3 0d00 ld [y,x] 5018 ld([Y,X]) #27
11f4 de00 st [y,x++] 5019 st([Y,Xpp]) #28 Just X++
11f5 c21a st [$1a] 5020 st([v6502_PCL]) #29
11f6 0d00 ld [y,x] 5021 ld([Y,X]) #30
11f7 c21b st [$1b] 5022 st([v6502_PCH]) #31
11f8 0200 nop 5023 nop() #32
11f9 140e ld $0e,y 5024 ld(hi('v6502_next'),Y) #33
11fa e020 jmp y,$20 5025 jmp(Y,'v6502_next') #34
11fb 00ee ld $ee 5026 ld(-36/2) #35
5027
5028 #-----------------------------------------------------------------------
5029 # Extended vertical blank logic: interrupts
5030 #-----------------------------------------------------------------------
11fc 0200 nop 5031 align(0x100)
11fd 0200 nop
11fe 0200 nop
11ff 0200 nop
5032
5033 # Check if an IRQ handler is defined
5034 label('vBlankFirst#78')
vBlankFirst#78:
1200 09f6 ld [y,$f6] 5035 ld([Y,vIRQ_v5]) #78
1201 49f7 ora [y,$f7] 5036 ora([Y,vIRQ_v5+1]) #79
5037 bne('vBlankFirst#82') #80
1202 ec09 bne vBlankFirst#82
1203 0116 ld [$16] 5038 ld([vPC]) #81
1204 0055 ld $55 5039 runVcpu(186-82-extra, #82 Application cycles (scan line 0)
1205 c21e st [$1e]
1206 1505 ld [$05],y
1207 e0ff jmp y,$ff
1208 001f ld $1f
5040 '---D line 0 timeout but no irq',
5041 returnTo='vBlankFirst#186')
5042
5043 label('vBlankFirst#82')
vBlankFirst#82:
1209 c230 st [$30] 5044 st([0x30]) #82 Save vPC
120a 0117 ld [$17] 5045 ld([vPC+1]) #83
120b c231 st [$31] 5046 st([0x31]) #84
120c 0118 ld [$18] 5047 ld([vAC]) #85 Save vAC
120d c232 st [$32] 5048 st([0x32]) #86
120e 0119 ld [$19] 5049 ld([vAC+1]) #87
120f c233 st [$33] 5050 st([0x33]) #88
1210 09f6 ld [y,$f6] 5051 ld([Y,vIRQ_v5]) #89 Set vPC to vIRQ
1211 a002 suba $02 5052 suba(2) #90
1212 c216 st [$16] 5053 st([vPC]) #91
1213 09f7 ld [y,$f7] 5054 ld([Y,vIRQ_v5+1]) #92
1214 c217 st [$17] 5055 st([vPC+1]) #93
1215 0105 ld [$05] 5056 ld([vCpuSelect]) #94 Handler must save this if needed
1216 c219 st [$19] 5057 st([vAC+1]) #95
1217 0000 ld $00 5058 ld(0) #96
1218 c218 st [$18] 5059 st([vAC]) #97
1219 0002 ld $02 5060 ld(hi('ENTER')) #98 Set vCpuSelect to ENTER (=regular vCPU)
121a c205 st [$05] 5061 st([vCpuSelect]) #99
121b 0055 ld $55 5062 runVcpu(186-100-extra, #100 Application cycles (scan line 0)
121c c21e st [$1e]
121d 1505 ld [$05],y
121e e0ff jmp y,$ff
121f 0016 ld $16
5063 '---D line 0 timeout with irq',
5064 returnTo='vBlankFirst#186')
5065
5066 # vIRQ sequence WITH interpreter switch
5067 label('vRTI#18')
vRTI#18: 1220 0500 ld [x] 5068 ld([X]) #18
1221 c205 st [$05] 5069 st([vCpuSelect]) #19
1222 0130 ld [$30] 5070 ld([0x30]) #20
1223 c216 st [$16] 5071 st([vPC]) #21
1224 0131 ld [$31] 5072 ld([0x31]) #22
1225 c217 st [$17] 5073 st([vPC+1]) #23
1226 0132 ld [$32] 5074 ld([0x32]) #24
1227 c218 st [$18] 5075 st([vAC]) #25
1228 0133 ld [$33] 5076 ld([0x33]) #26
1229 c219 st [$19] 5077 st([vAC+1]) #27
122a 0200 nop 5078 nop() #0
122b 1403 ld $03,y 5079 ld(hi('RESYNC'),Y) #1
122c e00c jmp y,$0c 5080 jmp(Y,'RESYNC') #2
122d 0115 ld [$15] 5081 ld([vTicks]) #3
5082
5083 # Entered last line of vertical blank (line 40)
5084 label('vBlankLast#34')
5085
5086 #-----------------------------------------------------------------------
5087 # Extended vertical blank logic: game controller decoding
5088 #-----------------------------------------------------------------------
5089
5090 # Game controller types
5091 # TypeA: Based on 74LS165 shift register (not supported)
5092 # TypeB: Based on CD4021B shift register (standard)
5093 # TypeC: Based on priority encoder
5094 #
5095 # Notes:
5096 # - TypeA was only used during development and first beta test, before ROM v1
5097 # - TypeB appears as type A with negative logic levels
5098 # - TypeB is the game controller type that comes with the original kit and ROM v1
5099 # - TypeB is mimicked by BabelFish / Pluggy McPlugface
5100 # - TypeB requires a prolonged /SER_LATCH, therefore vPulse is 8 scanlines, not 2
5101 # - TypeB and TypeC can be sampled in the same scanline
5102 # - TypeA is 1 scanline shifted as it looks at a different edge (XXX up or down?)
5103 # - TypeC gives incomplete information: lower buttons overshadow higher ones
5104 #
5105 # TypeC Alias Button TypeB
5106 # 00000000 ^@ -> Right 11111110
5107 # 00000001 ^A -> Left 11111101
5108 # 00000011 ^C -> Down 11111011
5109 # 00000111 ^G -> Up 11110111
5110 # 00001111 ^O -> Start 11101111
5111 # 00011111 ^_ -> Select 11011111
5112 # 00111111 ? -> B 10111111
5113 # 01111111 DEL -> A 01111111
5114 # 11111111 -> (None) 11111111
5115 #
5116 # Conversion formula:
5117 # f(x) := 254 - x
5118
5119 # Detect controller TypeC codes
vBlankLast#34:
122e 010f ld [$0f] 5120 ld([serialRaw]) #34 if serialRaw in [0,1,3,7,15,31,63,127,255]
122f 8001 adda $01 5121 adda(1) #35
1230 210f anda [$0f] 5122 anda([serialRaw]) #36
1231 ec42 bne .buttons#39 5123 bne('.buttons#39') #37
5124
5125 # TypeC
1232 010f ld [$0f] 5126 ld([serialRaw]) #38 [TypeC] if serialRaw < serialLast
1233 8001 adda $01 5127 adda(1) #39
1234 2110 anda [$10] 5128 anda([serialLast]) #40
1235 ec39 bne .buttons#43 5129 bne('.buttons#43') #41
1236 00fe ld $fe 5130 ld(254) #42 then clear the selected bit
1237 0200 nop 5131 nop() #43
1238 fc3c bra .buttons#46 5132 bra('.buttons#46') #44
5133 label('.buttons#43')
.buttons#43: 1239 a10f suba [$0f] 5134 suba([serialRaw]) #43,45
123a 2111 anda [$11] 5135 anda([buttonState]) #44
123b c211 st [$11] 5136 st([buttonState]) #45
5137 label('.buttons#46')
.buttons#46: 123c 010f ld [$0f] 5138 ld([serialRaw]) #46 Set the lower bits
123d 4111 ora [$11] 5139 ora([buttonState]) #47
5140 label('.buttons#48')
.buttons#48: 123e c211 st [$11] 5141 st([buttonState]) #48
123f 010f ld [$0f] 5142 ld([serialRaw]) #49 Update serialLast for next pass
1240 e0b3 jmp y,$b3 5143 jmp(Y,'vBlankLast#52') #50
1241 c210 st [$10] 5144 st([serialLast]) #51
5145
5146 # TypeB
5147 # pChange = pNew & ~pOld
5148 # nChange = nNew | ~nOld {DeMorgan}
5149 label('.buttons#39')
.buttons#39: 1242 00ff ld $ff 5150 ld(255) #39 [TypeB] Bitwise edge-filter to detect button presses
1243 6110 xora [$10] 5151 xora([serialLast]) #40
1244 410f ora [$0f] 5152 ora([serialRaw]) #41 Catch button-press events
1245 2111 anda [$11] 5153 anda([buttonState]) #42 Keep active button presses
1246 410f ora [$0f] 5154 ora([serialRaw]) #43
1247 0200 nop 5155 nop() #44
1248 0200 nop 5156 nop() #45
1249 fc3e bra .buttons#48 5157 bra('.buttons#48') #46
124a 0200 nop 5158 nop() #47
5159
5160
5161 #-----------------------------------------------------------------------
5162 # More SYS functions
5163 #-----------------------------------------------------------------------
5164
5165 # SYS_Exec_88 implementation
5166 label('sys_Exec')
sys_Exec: 124b d617 st [$17],y 5167 st([vPC+1],Y) #18 Clear vPCH and Y
124c 011c ld [$1c] 5168 ld([vSP]) #19 Place ROM loader below current stack pointer
124d a037 suba $37 5169 suba(53+2) #20 (AC -> *+0) One extra word for PUSH
124e d21d st [$1d],x 5170 st([vTmp],X) #21
124f 80fe adda $fe 5171 adda(-2) #22 (AC -> *-2)
1250 c216 st [$16] 5172 st([vPC]) #23
5173 # Start of manually compiled vCPU section
1251 dc75 st $75,[y,x++] 5174 st('PUSH', [Y,Xpp]) #24 *+0
1252 dccf st $cf,[y,x++] 5175 st('CALL', [Y,Xpp]) #25 *+26 Fetch first byte
1253 8023 adda $23 5176 adda(33-(-2)) #26 (AC -> *+33)
1254 de00 st [y,x++] 5177 st( [Y,Xpp]) #27 *+27
1255 dc5e st $5e,[y,x++] 5178 st('ST', [Y,Xpp]) #28 *+3 Chunk copy loop
1256 dc27 st $27,[y,x++] 5179 st(sysArgs+3, [Y,Xpp]) #29 *+4 High-address comes first
1257 dccf st $cf,[y,x++] 5180 st('CALL', [Y,Xpp]) #30 *+5
1258 de00 st [y,x++] 5181 st( [Y,Xpp]) #31 *+6
1259 dc5e st $5e,[y,x++] 5182 st('ST', [Y,Xpp]) #32 *+7
125a dc26 st $26,[y,x++] 5183 st(sysArgs+2, [Y,Xpp]) #33 *+8 Then the low address
125b dccf st $cf,[y,x++] 5184 st('CALL', [Y,Xpp]) #34 *+9
125c de00 st [y,x++] 5185 st( [Y,Xpp]) #35 *+10
125d dc5e st $5e,[y,x++] 5186 st('ST', [Y,Xpp]) #36 *+11 Byte copy loop
125e dc28 st $28,[y,x++] 5187 st(sysArgs+4, [Y,Xpp]) #37 *+12 Byte count (0 means 256)
125f dccf st $cf,[y,x++] 5188 st('CALL', [Y,Xpp]) #38 *+13
1260 de00 st [y,x++] 5189 st( [Y,Xpp]) #39 *+14
1261 dcf0 st $f0,[y,x++] 5190 st('POKE', [Y,Xpp]) #40 *+15
1262 dc26 st $26,[y,x++] 5191 st(sysArgs+2, [Y,Xpp]) #41 *+16
1263 dc93 st $93,[y,x++] 5192 st('INC', [Y,Xpp]) #42 *+17
1264 dc26 st $26,[y,x++] 5193 st(sysArgs+2, [Y,Xpp]) #43 *+18
1265 dc1a st $1a,[y,x++] 5194 st('LD', [Y,Xpp]) #44 *+19
1266 dc28 st $28,[y,x++] 5195 st(sysArgs+4, [Y,Xpp]) #45 *+20
1267 dce6 st $e6,[y,x++] 5196 st('SUBI', [Y,Xpp]) #46 *+21
1268 dc01 st $01,[y,x++] 5197 st(1, [Y,Xpp]) #47 *+22
1269 dc35 st $35,[y,x++] 5198 st('BCC', [Y,Xpp]) #48 *+23
126a dc72 st $72,[y,x++] 5199 st('NE', [Y,Xpp]) #49 *+24
126b 80e8 adda $e8 5200 adda(11-2-33) #50 (AC -> *+9)
126c de00 st [y,x++] 5201 st( [Y,Xpp]) #51 *+25
126d dccf st $cf,[y,x++] 5202 st('CALL', [Y,Xpp]) #52 *+26 Go to next block
126e 8018 adda $18 5203 adda(33-9) #53 (AC -> *+33)
126f de00 st [y,x++] 5204 st( [Y,Xpp]) #54 *+27
1270 dc35 st $35,[y,x++] 5205 st('BCC', [Y,Xpp]) #55 *+28
1271 dc72 st $72,[y,x++] 5206 st('NE', [Y,Xpp]) #56 *+29
1272 80e0 adda $e0 5207 adda(3-2-33) #57 (AC -> *+1)
1273 de00 st [y,x++] 5208 st( [Y,Xpp]) #58 *+30
1274 dc63 st $63,[y,x++] 5209 st('POP', [Y,Xpp]) #59 *+31 End
1275 dcff st $ff,[y,x++] 5210 st('RET', [Y,Xpp]) #60 *+32
5211 # Pointer constant pointing to the routine below (for use by CALL)
1276 8022 adda $22 5212 adda(35-1) #61 (AC -> *+35)
1277 de00 st [y,x++] 5213 st( [Y,Xpp]) #62 *+33
1278 dc00 st $00,[y,x++] 5214 st(0, [Y,Xpp]) #63 *+34
5215 # Routine to read next byte from ROM and advance read pointer
1279 dc1a st $1a,[y,x++] 5216 st('LD', [Y,Xpp]) #64 *+35 Test for end of ROM table
127a dc24 st $24,[y,x++] 5217 st(sysArgs+0, [Y,Xpp]) #65 *+36
127b dc8c st $8c,[y,x++] 5218 st('XORI', [Y,Xpp]) #66 *+37
127c dcfb st $fb,[y,x++] 5219 st(251, [Y,Xpp]) #67 *+38
127d dc35 st $35,[y,x++] 5220 st('BCC', [Y,Xpp]) #68 *+39
127e dc72 st $72,[y,x++] 5221 st('NE', [Y,Xpp]) #69 *+40
127f 8009 adda $09 5222 adda(46-2-35) #70 (AC -> *+44)
1280 de00 st [y,x++] 5223 st( [Y,Xpp]) #71 *+41
1281 dc5e st $5e,[y,x++] 5224 st('ST', [Y,Xpp]) #72 *+42 Wrap to next ROM page
1282 dc24 st $24,[y,x++] 5225 st(sysArgs+0, [Y,Xpp]) #73 *+43
1283 dc93 st $93,[y,x++] 5226 st('INC', [Y,Xpp]) #74 *+44
1284 dc25 st $25,[y,x++] 5227 st(sysArgs+1, [Y,Xpp]) #75 *+45
1285 dc21 st $21,[y,x++] 5228 st('LDW', [Y,Xpp]) #76 *+46 Read next byte from ROM table
1286 dc24 st $24,[y,x++] 5229 st(sysArgs+0, [Y,Xpp]) #77 *+47
1287 dc7f st $7f,[y,x++] 5230 st('LUP', [Y,Xpp]) #78 *+48
1288 dc00 st $00,[y,x++] 5231 st(0, [Y,Xpp]) #79 *+49
1289 dc93 st $93,[y,x++] 5232 st('INC', [Y,Xpp]) #80 *+50 Increment read pointer
128a dc24 st $24,[y,x++] 5233 st(sysArgs+0, [Y,Xpp]) #81 *+51
128b dcff st $ff,[y,x++] 5234 st('RET', [Y,Xpp]) #82 *+52 Return
5235 # Return to interpreter
128c 1403 ld $03,y 5236 ld(hi('REENTER'),Y) #83
128d e0cb jmp y,$cb 5237 jmp(Y,'REENTER') #84
128e 00d4 ld $d4 5238 ld(-88/2) #85
5239
5240 # SYS_VDrawBits_134 implementation
5241 label('sys_VDrawBits')
sys_VDrawBits:
128f 0000 ld $00 5242 ld(0) #18
5243 label('.sysVdb0')
.sysVdb0: 1290 c21d st [$1d] 5244 st([vTmp]) #19+i*25
1291 9529 adda [$29],y 5245 adda([sysArgs+5],Y) #20+i*25 Y=[sysPos+1]+[vTmp]
1292 0126 ld [$26] 5246 ld([sysArgs+2]) #21+i*25 Select color
1293 e896 blt $1296 5247 bmi(pc()+3) #22+i*25
1294 fc97 bra $1297 5248 bra(pc()+3) #23+i*25
1295 0124 ld [$24] 5249 ld([sysArgs+0]) #24+i*25
1296 0125 ld [$25] 5250 ld([sysArgs+1]) #24+i*25(!)
1297 ce00 st [y,x] 5251 st([Y,X]) #25+i*25 Draw pixel
1298 0126 ld [$26] 5252 ld([sysArgs+2]) #26+i*25 Shift byte left
1299 8200 adda ac 5253 adda(AC) #27+i*25
129a c226 st [$26] 5254 st([sysArgs+2]) #28+i*25
129b 011d ld [$1d] 5255 ld([vTmp]) #29+i*25 Unrolled loop (once)
129c 8129 adda [$29] 5256 adda([sysArgs+5]) #31+i*25
129d 9401 adda $01,y 5257 adda(1,Y) #30+i*25 Y=[sysPos+1]+[vTmp]+1
129e 0126 ld [$26] 5258 ld([sysArgs+2]) #32+i*25 Select color
129f e8a2 blt $12a2 5259 bmi(pc()+3) #33+i*25
12a0 fca3 bra $12a3 5260 bra(pc()+3) #34+i*25
12a1 0124 ld [$24] 5261 ld([sysArgs+0]) #35+i*25
12a2 0125 ld [$25] 5262 ld([sysArgs+1]) #35+i*25(!)
12a3 ce00 st [y,x] 5263 st([Y,X]) #36+i*25 Draw pixel
12a4 0126 ld [$26] 5264 ld([sysArgs+2]) #37+i*25 Shift byte left
12a5 8200 adda ac 5265 adda(AC) #38+i*25
12a6 c226 st [$26] 5266 st([sysArgs+2]) #39+i*25
12a7 011d ld [$1d] 5267 ld([vTmp]) #40+i*25 Loop counter
12a8 a006 suba $06 5268 suba(6) #41+i*25
12a9 ec90 bne .sysVdb0 5269 bne('.sysVdb0') #42+i*25
12aa 8008 adda $08 5270 adda(8) #43+i*25 Steps of 2
12ab 1403 ld $03,y 5271 ld(hi('REENTER'),Y) #119
12ac e0cb jmp y,$cb 5272 jmp(Y,'REENTER') #120
12ad 00c2 ld $c2 5273 ld(-124/2) #121
5274
5275 # SYS_ResetWaveforms_v4_50 implementation
5276 label('sys_ResetWaveforms')
sys_ResetWaveforms:
12ae 0118 ld [$18] 5277 ld([vAC+0]) #18 X=4i
12af 8200 adda ac 5278 adda(AC) #19
12b0 9200 adda ac,x 5279 adda(AC,X) #20
12b1 0118 ld [$18] 5280 ld([vAC+0]) #21
12b2 de00 st [y,x++] 5281 st([Y,Xpp]) #22 Sawtooth: T[4i+0] = i
12b3 2020 anda $20 5282 anda(0x20) #23 Triangle: T[4i+1] = 2i if i<32 else 127-2i
12b4 ecb7 bne $12b7 5283 bne(pc()+3) #24
12b5 0118 ld [$18] 5284 ld([vAC+0]) #25
12b6 fcb9 bra $12b9 5285 bra(pc()+3) #26
12b7 8118 adda [$18] 5286 adda([vAC+0]) #26,27
12b8 607f xora $7f 5287 xora(127) #27
12b9 de00 st [y,x++] 5288 st([Y,Xpp]) #28
12ba 0118 ld [$18] 5289 ld([vAC+0]) #29 Pulse: T[4i+2] = 0 if i<32 else 63
12bb 2020 anda $20 5290 anda(0x20) #30
12bc ecbf bne $12bf 5291 bne(pc()+3) #31
12bd fcc0 bra $12c0 5292 bra(pc()+3) #32
12be 0000 ld $00 5293 ld(0) #33
12bf 003f ld $3f 5294 ld(63) #33(!)
12c0 de00 st [y,x++] 5295 st([Y,Xpp]) #34
12c1 0118 ld [$18] 5296 ld([vAC+0]) #35 Sawtooth: T[4i+3] = i
12c2 ce00 st [y,x] 5297 st([Y,X]) #36
12c3 8001 adda $01 5298 adda(1) #37 i += 1
12c4 c218 st [$18] 5299 st([vAC+0]) #38
12c5 6040 xora $40 5300 xora(64) #39 For 64 iterations
12c6 f0c9 beq $12c9 5301 beq(pc()+3) #40
12c7 fcca bra $12ca 5302 bra(pc()+3) #41
12c8 00fe ld $fe 5303 ld(-2) #42
12c9 0000 ld $00 5304 ld(0) #42(!)
12ca 8116 adda [$16] 5305 adda([vPC]) #43
12cb c216 st [$16] 5306 st([vPC]) #44
12cc 1403 ld $03,y 5307 ld(hi('REENTER'),Y) #45
12cd e0cb jmp y,$cb 5308 jmp(Y,'REENTER') #46
12ce 00e7 ld $e7 5309 ld(-50/2) #47
5310
5311 # SYS_ShuffleNoise_v4_46 implementation
5312 label('sys_ShuffleNoise')
sys_ShuffleNoise:
12cf 1118 ld [$18],x 5313 ld([vAC+0],X) #18 tmp = T[4j]
12d0 0d00 ld [y,x] 5314 ld([Y,X]) #19
12d1 c21d st [$1d] 5315 st([vTmp]) #20
12d2 1119 ld [$19],x 5316 ld([vAC+1],X) #21 T[4j] = T[4i]
12d3 0d00 ld [y,x] 5317 ld([Y,X]) #22
12d4 1118 ld [$18],x 5318 ld([vAC+0],X) #23
12d5 ce00 st [y,x] 5319 st([Y,X]) #24
12d6 8200 adda ac 5320 adda(AC) #25 j += T[4i]
12d7 8200 adda ac 5321 adda(AC,) #26
12d8 8118 adda [$18] 5322 adda([vAC+0]) #27
12d9 c218 st [$18] 5323 st([vAC+0]) #28
12da 1119 ld [$19],x 5324 ld([vAC+1],X) #29 T[4i] = tmp
12db 011d ld [$1d] 5325 ld([vTmp]) #30
12dc ce00 st [y,x] 5326 st([Y,X]) #31
12dd 0119 ld [$19] 5327 ld([vAC+1]) #32 i += 1
12de 8004 adda $04 5328 adda(4) #33
12df c219 st [$19] 5329 st([vAC+1]) #34
12e0 f0e3 beq $12e3 5330 beq(pc()+3) #35 For 64 iterations
12e1 fce4 bra $12e4 5331 bra(pc()+3) #36
12e2 00fe ld $fe 5332 ld(-2) #37
12e3 0000 ld $00 5333 ld(0) #37(!)
12e4 8116 adda [$16] 5334 adda([vPC]) #38
12e5 c216 st [$16] 5335 st([vPC]) #39
12e6 1403 ld $03,y 5336 ld(hi('NEXTY'),Y) #40
12e7 e000 jmp y,$00 5337 jmp(Y,'NEXTY') #41
12e8 00ea ld $ea 5338 ld(-44/2) #42
5339
5340 # SYS_LoadBytes_DEVROM_XXX implementation
5341 label('sys_LoadBytes')
sys_LoadBytes:
12e9 0030 ld $30 5342 ld(0x30) # Target address
12ea c225 st [$25] 5343 st([sysArgs+1]) #
12eb 011a ld [$1a] 5344 ld([vLR+0]) # Source address
12ec d224 st [$24],x 5345 st([sysArgs+0],X) #
12ed 0d00 ld [y,x] 5346 ld([Y,X]) # Byte count
5347 label('.slb1') #
.slb1: 12ee c226 st [$26] 5348 st([sysArgs+2]) #
5349
12ef 0124 ld [$24] 5350 ld([sysArgs+0]) # Advance source address
12f0 8001 adda $01 5351 adda(1) #
12f1 d224 st [$24],x 5352 st([sysArgs+0],X) #
5353
12f2 0d00 ld [y,x] 5354 ld([Y,X]) # Copy byte
12f3 1125 ld [$25],x 5355 ld([sysArgs+1],X) #
12f4 c600 st [x] 5356 st([X]) #
5357
12f5 0125 ld [$25] 5358 ld([sysArgs+1]) # Advance target address
12f6 8001 adda $01 5359 adda(1) #
12f7 c225 st [$25] 5360 st([sysArgs+1]) #
5361
12f8 0126 ld [$26] 5362 ld([sysArgs+2]) # Decrement byte count and loop
12f9 ecee bne .slb1 5363 bne('.slb1') #
12fa a001 suba $01 5364 suba(1) #
5365
5366 # XXX Unfinished
5367
12fb 0200 nop 5368 align(0x100, 0x200)
12fc 0200 nop
12fd 0200 nop
* 5 times
5369 #-----------------------------------------------------------------------
5370 #
5371 # Quarter-Square table
5372 #
5373 # Used for a reasonably fast multiplication routine
5374 #-----------------------------------------------------------------------
5375 # High-bytes, stored inverted, and shifted down by 32 places
5376 for i in range(32, 256):
5377 val = math.floor(i ** 2 / 4)
5378 ld(hi(~val))
1300 00fe ld $fe ;$0100 = 256 = floor(32 ** 2 / 4); !$0100 >> 8 = $fe
1301 00fe ld $fe ;$0110 = 272 = floor(33 ** 2 / 4); !$0110 >> 8 = $fe
1302 00fe ld $fe ;$0121 = 289 = floor(34 ** 2 / 4); !$0121 >> 8 = $fe
1303 00fe ld $fe ;$0132 = 306 = floor(35 ** 2 / 4); !$0132 >> 8 = $fe
1304 00fe ld $fe ;$0144 = 324 = floor(36 ** 2 / 4); !$0144 >> 8 = $fe
1305 00fe ld $fe ;$0156 = 342 = floor(37 ** 2 / 4); !$0156 >> 8 = $fe
1306 00fe ld $fe ;$0169 = 361 = floor(38 ** 2 / 4); !$0169 >> 8 = $fe
1307 00fe ld $fe ;$017c = 380 = floor(39 ** 2 / 4); !$017c >> 8 = $fe
1308 00fe ld $fe ;$0190 = 400 = floor(40 ** 2 / 4); !$0190 >> 8 = $fe
1309 00fe ld $fe ;$01a4 = 420 = floor(41 ** 2 / 4); !$01a4 >> 8 = $fe
130a 00fe ld $fe ;$01b9 = 441 = floor(42 ** 2 / 4); !$01b9 >> 8 = $fe
130b 00fe ld $fe ;$01ce = 462 = floor(43 ** 2 / 4); !$01ce >> 8 = $fe
130c 00fe ld $fe ;$01e4 = 484 = floor(44 ** 2 / 4); !$01e4 >> 8 = $fe
130d 00fe ld $fe ;$01fa = 506 = floor(45 ** 2 / 4); !$01fa >> 8 = $fe
130e 00fd ld $fd ;$0211 = 529 = floor(46 ** 2 / 4); !$0211 >> 8 = $fd
130f 00fd ld $fd ;$0228 = 552 = floor(47 ** 2 / 4); !$0228 >> 8 = $fd
1310 00fd ld $fd ;$0240 = 576 = floor(48 ** 2 / 4); !$0240 >> 8 = $fd
1311 00fd ld $fd ;$0258 = 600 = floor(49 ** 2 / 4); !$0258 >> 8 = $fd
1312 00fd ld $fd ;$0271 = 625 = floor(50 ** 2 / 4); !$0271 >> 8 = $fd
1313 00fd ld $fd ;$028a = 650 = floor(51 ** 2 / 4); !$028a >> 8 = $fd
1314 00fd ld $fd ;$02a4 = 676 = floor(52 ** 2 / 4); !$02a4 >> 8 = $fd
1315 00fd ld $fd ;$02be = 702 = floor(53 ** 2 / 4); !$02be >> 8 = $fd
1316 00fd ld $fd ;$02d9 = 729 = floor(54 ** 2 / 4); !$02d9 >> 8 = $fd
1317 00fd ld $fd ;$02f4 = 756 = floor(55 ** 2 / 4); !$02f4 >> 8 = $fd
1318 00fc ld $fc ;$0310 = 784 = floor(56 ** 2 / 4); !$0310 >> 8 = $fc
1319 00fc ld $fc ;$032c = 812 = floor(57 ** 2 / 4); !$032c >> 8 = $fc
131a 00fc ld $fc ;$0349 = 841 = floor(58 ** 2 / 4); !$0349 >> 8 = $fc
131b 00fc ld $fc ;$0366 = 870 = floor(59 ** 2 / 4); !$0366 >> 8 = $fc
131c 00fc ld $fc ;$0384 = 900 = floor(60 ** 2 / 4); !$0384 >> 8 = $fc
131d 00fc ld $fc ;$03a2 = 930 = floor(61 ** 2 / 4); !$03a2 >> 8 = $fc
131e 00fc ld $fc ;$03c1 = 961 = floor(62 ** 2 / 4); !$03c1 >> 8 = $fc
131f 00fc ld $fc ;$03e0 = 992 = floor(63 ** 2 / 4); !$03e0 >> 8 = $fc
1320 00fb ld $fb ;$0400 = 1024 = floor(64 ** 2 / 4); !$0400 >> 8 = $fb
1321 00fb ld $fb ;$0420 = 1056 = floor(65 ** 2 / 4); !$0420 >> 8 = $fb
1322 00fb ld $fb ;$0441 = 1089 = floor(66 ** 2 / 4); !$0441 >> 8 = $fb
1323 00fb ld $fb ;$0462 = 1122 = floor(67 ** 2 / 4); !$0462 >> 8 = $fb
1324 00fb ld $fb ;$0484 = 1156 = floor(68 ** 2 / 4); !$0484 >> 8 = $fb
1325 00fb ld $fb ;$04a6 = 1190 = floor(69 ** 2 / 4); !$04a6 >> 8 = $fb
1326 00fb ld $fb ;$04c9 = 1225 = floor(70 ** 2 / 4); !$04c9 >> 8 = $fb
1327 00fb ld $fb ;$04ec = 1260 = floor(71 ** 2 / 4); !$04ec >> 8 = $fb
1328 00fa ld $fa ;$0510 = 1296 = floor(72 ** 2 / 4); !$0510 >> 8 = $fa
1329 00fa ld $fa ;$0534 = 1332 = floor(73 ** 2 / 4); !$0534 >> 8 = $fa
132a 00fa ld $fa ;$0559 = 1369 = floor(74 ** 2 / 4); !$0559 >> 8 = $fa
132b 00fa ld $fa ;$057e = 1406 = floor(75 ** 2 / 4); !$057e >> 8 = $fa
132c 00fa ld $fa ;$05a4 = 1444 = floor(76 ** 2 / 4); !$05a4 >> 8 = $fa
132d 00fa ld $fa ;$05ca = 1482 = floor(77 ** 2 / 4); !$05ca >> 8 = $fa
132e 00fa ld $fa ;$05f1 = 1521 = floor(78 ** 2 / 4); !$05f1 >> 8 = $fa
132f 00f9 ld $f9 ;$0618 = 1560 = floor(79 ** 2 / 4); !$0618 >> 8 = $f9
1330 00f9 ld $f9 ;$0640 = 1600 = floor(80 ** 2 / 4); !$0640 >> 8 = $f9
1331 00f9 ld $f9 ;$0668 = 1640 = floor(81 ** 2 / 4); !$0668 >> 8 = $f9
1332 00f9 ld $f9 ;$0691 = 1681 = floor(82 ** 2 / 4); !$0691 >> 8 = $f9
1333 00f9 ld $f9 ;$06ba = 1722 = floor(83 ** 2 / 4); !$06ba >> 8 = $f9
1334 00f9 ld $f9 ;$06e4 = 1764 = floor(84 ** 2 / 4); !$06e4 >> 8 = $f9
1335 00f8 ld $f8 ;$070e = 1806 = floor(85 ** 2 / 4); !$070e >> 8 = $f8
1336 00f8 ld $f8 ;$0739 = 1849 = floor(86 ** 2 / 4); !$0739 >> 8 = $f8
1337 00f8 ld $f8 ;$0764 = 1892 = floor(87 ** 2 / 4); !$0764 >> 8 = $f8
1338 00f8 ld $f8 ;$0790 = 1936 = floor(88 ** 2 / 4); !$0790 >> 8 = $f8
1339 00f8 ld $f8 ;$07bc = 1980 = floor(89 ** 2 / 4); !$07bc >> 8 = $f8
133a 00f8 ld $f8 ;$07e9 = 2025 = floor(90 ** 2 / 4); !$07e9 >> 8 = $f8
133b 00f7 ld $f7 ;$0816 = 2070 = floor(91 ** 2 / 4); !$0816 >> 8 = $f7
133c 00f7 ld $f7 ;$0844 = 2116 = floor(92 ** 2 / 4); !$0844 >> 8 = $f7
133d 00f7 ld $f7 ;$0872 = 2162 = floor(93 ** 2 / 4); !$0872 >> 8 = $f7
133e 00f7 ld $f7 ;$08a1 = 2209 = floor(94 ** 2 / 4); !$08a1 >> 8 = $f7
133f 00f7 ld $f7 ;$08d0 = 2256 = floor(95 ** 2 / 4); !$08d0 >> 8 = $f7
1340 00f6 ld $f6 ;$0900 = 2304 = floor(96 ** 2 / 4); !$0900 >> 8 = $f6
1341 00f6 ld $f6 ;$0930 = 2352 = floor(97 ** 2 / 4); !$0930 >> 8 = $f6
1342 00f6 ld $f6 ;$0961 = 2401 = floor(98 ** 2 / 4); !$0961 >> 8 = $f6
1343 00f6 ld $f6 ;$0992 = 2450 = floor(99 ** 2 / 4); !$0992 >> 8 = $f6
1344 00f6 ld $f6 ;$09c4 = 2500 = floor(100 ** 2 / 4); !$09c4 >> 8 = $f6
1345 00f6 ld $f6 ;$09f6 = 2550 = floor(101 ** 2 / 4); !$09f6 >> 8 = $f6
1346 00f5 ld $f5 ;$0a29 = 2601 = floor(102 ** 2 / 4); !$0a29 >> 8 = $f5
1347 00f5 ld $f5 ;$0a5c = 2652 = floor(103 ** 2 / 4); !$0a5c >> 8 = $f5
1348 00f5 ld $f5 ;$0a90 = 2704 = floor(104 ** 2 / 4); !$0a90 >> 8 = $f5
1349 00f5 ld $f5 ;$0ac4 = 2756 = floor(105 ** 2 / 4); !$0ac4 >> 8 = $f5
134a 00f5 ld $f5 ;$0af9 = 2809 = floor(106 ** 2 / 4); !$0af9 >> 8 = $f5
134b 00f4 ld $f4 ;$0b2e = 2862 = floor(107 ** 2 / 4); !$0b2e >> 8 = $f4
134c 00f4 ld $f4 ;$0b64 = 2916 = floor(108 ** 2 / 4); !$0b64 >> 8 = $f4
134d 00f4 ld $f4 ;$0b9a = 2970 = floor(109 ** 2 / 4); !$0b9a >> 8 = $f4
134e 00f4 ld $f4 ;$0bd1 = 3025 = floor(110 ** 2 / 4); !$0bd1 >> 8 = $f4
134f 00f3 ld $f3 ;$0c08 = 3080 = floor(111 ** 2 / 4); !$0c08 >> 8 = $f3
1350 00f3 ld $f3 ;$0c40 = 3136 = floor(112 ** 2 / 4); !$0c40 >> 8 = $f3
1351 00f3 ld $f3 ;$0c78 = 3192 = floor(113 ** 2 / 4); !$0c78 >> 8 = $f3
1352 00f3 ld $f3 ;$0cb1 = 3249 = floor(114 ** 2 / 4); !$0cb1 >> 8 = $f3
1353 00f3 ld $f3 ;$0cea = 3306 = floor(115 ** 2 / 4); !$0cea >> 8 = $f3
1354 00f2 ld $f2 ;$0d24 = 3364 = floor(116 ** 2 / 4); !$0d24 >> 8 = $f2
1355 00f2 ld $f2 ;$0d5e = 3422 = floor(117 ** 2 / 4); !$0d5e >> 8 = $f2
1356 00f2 ld $f2 ;$0d99 = 3481 = floor(118 ** 2 / 4); !$0d99 >> 8 = $f2
1357 00f2 ld $f2 ;$0dd4 = 3540 = floor(119 ** 2 / 4); !$0dd4 >> 8 = $f2
1358 00f1 ld $f1 ;$0e10 = 3600 = floor(120 ** 2 / 4); !$0e10 >> 8 = $f1
1359 00f1 ld $f1 ;$0e4c = 3660 = floor(121 ** 2 / 4); !$0e4c >> 8 = $f1
135a 00f1 ld $f1 ;$0e89 = 3721 = floor(122 ** 2 / 4); !$0e89 >> 8 = $f1
135b 00f1 ld $f1 ;$0ec6 = 3782 = floor(123 ** 2 / 4); !$0ec6 >> 8 = $f1
135c 00f0 ld $f0 ;$0f04 = 3844 = floor(124 ** 2 / 4); !$0f04 >> 8 = $f0
135d 00f0 ld $f0 ;$0f42 = 3906 = floor(125 ** 2 / 4); !$0f42 >> 8 = $f0
135e 00f0 ld $f0 ;$0f81 = 3969 = floor(126 ** 2 / 4); !$0f81 >> 8 = $f0
135f 00f0 ld $f0 ;$0fc0 = 4032 = floor(127 ** 2 / 4); !$0fc0 >> 8 = $f0
1360 00ef ld $ef ;$1000 = 4096 = floor(128 ** 2 / 4); !$1000 >> 8 = $ef
1361 00ef ld $ef ;$1040 = 4160 = floor(129 ** 2 / 4); !$1040 >> 8 = $ef
1362 00ef ld $ef ;$1081 = 4225 = floor(130 ** 2 / 4); !$1081 >> 8 = $ef
1363 00ef ld $ef ;$10c2 = 4290 = floor(131 ** 2 / 4); !$10c2 >> 8 = $ef
1364 00ee ld $ee ;$1104 = 4356 = floor(132 ** 2 / 4); !$1104 >> 8 = $ee
1365 00ee ld $ee ;$1146 = 4422 = floor(133 ** 2 / 4); !$1146 >> 8 = $ee
1366 00ee ld $ee ;$1189 = 4489 = floor(134 ** 2 / 4); !$1189 >> 8 = $ee
1367 00ee ld $ee ;$11cc = 4556 = floor(135 ** 2 / 4); !$11cc >> 8 = $ee
1368 00ed ld $ed ;$1210 = 4624 = floor(136 ** 2 / 4); !$1210 >> 8 = $ed
1369 00ed ld $ed ;$1254 = 4692 = floor(137 ** 2 / 4); !$1254 >> 8 = $ed
136a 00ed ld $ed ;$1299 = 4761 = floor(138 ** 2 / 4); !$1299 >> 8 = $ed
136b 00ed ld $ed ;$12de = 4830 = floor(139 ** 2 / 4); !$12de >> 8 = $ed
136c 00ec ld $ec ;$1324 = 4900 = floor(140 ** 2 / 4); !$1324 >> 8 = $ec
136d 00ec ld $ec ;$136a = 4970 = floor(141 ** 2 / 4); !$136a >> 8 = $ec
136e 00ec ld $ec ;$13b1 = 5041 = floor(142 ** 2 / 4); !$13b1 >> 8 = $ec
136f 00ec ld $ec ;$13f8 = 5112 = floor(143 ** 2 / 4); !$13f8 >> 8 = $ec
1370 00eb ld $eb ;$1440 = 5184 = floor(144 ** 2 / 4); !$1440 >> 8 = $eb
1371 00eb ld $eb ;$1488 = 5256 = floor(145 ** 2 / 4); !$1488 >> 8 = $eb
1372 00eb ld $eb ;$14d1 = 5329 = floor(146 ** 2 / 4); !$14d1 >> 8 = $eb
1373 00ea ld $ea ;$151a = 5402 = floor(147 ** 2 / 4); !$151a >> 8 = $ea
1374 00ea ld $ea ;$1564 = 5476 = floor(148 ** 2 / 4); !$1564 >> 8 = $ea
1375 00ea ld $ea ;$15ae = 5550 = floor(149 ** 2 / 4); !$15ae >> 8 = $ea
1376 00ea ld $ea ;$15f9 = 5625 = floor(150 ** 2 / 4); !$15f9 >> 8 = $ea
1377 00e9 ld $e9 ;$1644 = 5700 = floor(151 ** 2 / 4); !$1644 >> 8 = $e9
1378 00e9 ld $e9 ;$1690 = 5776 = floor(152 ** 2 / 4); !$1690 >> 8 = $e9
1379 00e9 ld $e9 ;$16dc = 5852 = floor(153 ** 2 / 4); !$16dc >> 8 = $e9
137a 00e8 ld $e8 ;$1729 = 5929 = floor(154 ** 2 / 4); !$1729 >> 8 = $e8
137b 00e8 ld $e8 ;$1776 = 6006 = floor(155 ** 2 / 4); !$1776 >> 8 = $e8
137c 00e8 ld $e8 ;$17c4 = 6084 = floor(156 ** 2 / 4); !$17c4 >> 8 = $e8
137d 00e7 ld $e7 ;$1812 = 6162 = floor(157 ** 2 / 4); !$1812 >> 8 = $e7
137e 00e7 ld $e7 ;$1861 = 6241 = floor(158 ** 2 / 4); !$1861 >> 8 = $e7
137f 00e7 ld $e7 ;$18b0 = 6320 = floor(159 ** 2 / 4); !$18b0 >> 8 = $e7
1380 00e6 ld $e6 ;$1900 = 6400 = floor(160 ** 2 / 4); !$1900 >> 8 = $e6
1381 00e6 ld $e6 ;$1950 = 6480 = floor(161 ** 2 / 4); !$1950 >> 8 = $e6
1382 00e6 ld $e6 ;$19a1 = 6561 = floor(162 ** 2 / 4); !$19a1 >> 8 = $e6
1383 00e6 ld $e6 ;$19f2 = 6642 = floor(163 ** 2 / 4); !$19f2 >> 8 = $e6
1384 00e5 ld $e5 ;$1a44 = 6724 = floor(164 ** 2 / 4); !$1a44 >> 8 = $e5
1385 00e5 ld $e5 ;$1a96 = 6806 = floor(165 ** 2 / 4); !$1a96 >> 8 = $e5
1386 00e5 ld $e5 ;$1ae9 = 6889 = floor(166 ** 2 / 4); !$1ae9 >> 8 = $e5
1387 00e4 ld $e4 ;$1b3c = 6972 = floor(167 ** 2 / 4); !$1b3c >> 8 = $e4
1388 00e4 ld $e4 ;$1b90 = 7056 = floor(168 ** 2 / 4); !$1b90 >> 8 = $e4
1389 00e4 ld $e4 ;$1be4 = 7140 = floor(169 ** 2 / 4); !$1be4 >> 8 = $e4
138a 00e3 ld $e3 ;$1c39 = 7225 = floor(170 ** 2 / 4); !$1c39 >> 8 = $e3
138b 00e3 ld $e3 ;$1c8e = 7310 = floor(171 ** 2 / 4); !$1c8e >> 8 = $e3
138c 00e3 ld $e3 ;$1ce4 = 7396 = floor(172 ** 2 / 4); !$1ce4 >> 8 = $e3
138d 00e2 ld $e2 ;$1d3a = 7482 = floor(173 ** 2 / 4); !$1d3a >> 8 = $e2
138e 00e2 ld $e2 ;$1d91 = 7569 = floor(174 ** 2 / 4); !$1d91 >> 8 = $e2
138f 00e2 ld $e2 ;$1de8 = 7656 = floor(175 ** 2 / 4); !$1de8 >> 8 = $e2
1390 00e1 ld $e1 ;$1e40 = 7744 = floor(176 ** 2 / 4); !$1e40 >> 8 = $e1
1391 00e1 ld $e1 ;$1e98 = 7832 = floor(177 ** 2 / 4); !$1e98 >> 8 = $e1
1392 00e1 ld $e1 ;$1ef1 = 7921 = floor(178 ** 2 / 4); !$1ef1 >> 8 = $e1
1393 00e0 ld $e0 ;$1f4a = 8010 = floor(179 ** 2 / 4); !$1f4a >> 8 = $e0
1394 00e0 ld $e0 ;$1fa4 = 8100 = floor(180 ** 2 / 4); !$1fa4 >> 8 = $e0
1395 00e0 ld $e0 ;$1ffe = 8190 = floor(181 ** 2 / 4); !$1ffe >> 8 = $e0
1396 00df ld $df ;$2059 = 8281 = floor(182 ** 2 / 4); !$2059 >> 8 = $df
1397 00df ld $df ;$20b4 = 8372 = floor(183 ** 2 / 4); !$20b4 >> 8 = $df
1398 00de ld $de ;$2110 = 8464 = floor(184 ** 2 / 4); !$2110 >> 8 = $de
1399 00de ld $de ;$216c = 8556 = floor(185 ** 2 / 4); !$216c >> 8 = $de
139a 00de ld $de ;$21c9 = 8649 = floor(186 ** 2 / 4); !$21c9 >> 8 = $de
139b 00dd ld $dd ;$2226 = 8742 = floor(187 ** 2 / 4); !$2226 >> 8 = $dd
139c 00dd ld $dd ;$2284 = 8836 = floor(188 ** 2 / 4); !$2284 >> 8 = $dd
139d 00dd ld $dd ;$22e2 = 8930 = floor(189 ** 2 / 4); !$22e2 >> 8 = $dd
139e 00dc ld $dc ;$2341 = 9025 = floor(190 ** 2 / 4); !$2341 >> 8 = $dc
139f 00dc ld $dc ;$23a0 = 9120 = floor(191 ** 2 / 4); !$23a0 >> 8 = $dc
13a0 00db ld $db ;$2400 = 9216 = floor(192 ** 2 / 4); !$2400 >> 8 = $db
13a1 00db ld $db ;$2460 = 9312 = floor(193 ** 2 / 4); !$2460 >> 8 = $db
13a2 00db ld $db ;$24c1 = 9409 = floor(194 ** 2 / 4); !$24c1 >> 8 = $db
13a3 00da ld $da ;$2522 = 9506 = floor(195 ** 2 / 4); !$2522 >> 8 = $da
13a4 00da ld $da ;$2584 = 9604 = floor(196 ** 2 / 4); !$2584 >> 8 = $da
13a5 00da ld $da ;$25e6 = 9702 = floor(197 ** 2 / 4); !$25e6 >> 8 = $da
13a6 00d9 ld $d9 ;$2649 = 9801 = floor(198 ** 2 / 4); !$2649 >> 8 = $d9
13a7 00d9 ld $d9 ;$26ac = 9900 = floor(199 ** 2 / 4); !$26ac >> 8 = $d9
13a8 00d8 ld $d8 ;$2710 = 10000 = floor(200 ** 2 / 4); !$2710 >> 8 = $d8
13a9 00d8 ld $d8 ;$2774 = 10100 = floor(201 ** 2 / 4); !$2774 >> 8 = $d8
13aa 00d8 ld $d8 ;$27d9 = 10201 = floor(202 ** 2 / 4); !$27d9 >> 8 = $d8
13ab 00d7 ld $d7 ;$283e = 10302 = floor(203 ** 2 / 4); !$283e >> 8 = $d7
13ac 00d7 ld $d7 ;$28a4 = 10404 = floor(204 ** 2 / 4); !$28a4 >> 8 = $d7
13ad 00d6 ld $d6 ;$290a = 10506 = floor(205 ** 2 / 4); !$290a >> 8 = $d6
13ae 00d6 ld $d6 ;$2971 = 10609 = floor(206 ** 2 / 4); !$2971 >> 8 = $d6
13af 00d6 ld $d6 ;$29d8 = 10712 = floor(207 ** 2 / 4); !$29d8 >> 8 = $d6
13b0 00d5 ld $d5 ;$2a40 = 10816 = floor(208 ** 2 / 4); !$2a40 >> 8 = $d5
13b1 00d5 ld $d5 ;$2aa8 = 10920 = floor(209 ** 2 / 4); !$2aa8 >> 8 = $d5
13b2 00d4 ld $d4 ;$2b11 = 11025 = floor(210 ** 2 / 4); !$2b11 >> 8 = $d4
13b3 00d4 ld $d4 ;$2b7a = 11130 = floor(211 ** 2 / 4); !$2b7a >> 8 = $d4
13b4 00d4 ld $d4 ;$2be4 = 11236 = floor(212 ** 2 / 4); !$2be4 >> 8 = $d4
13b5 00d3 ld $d3 ;$2c4e = 11342 = floor(213 ** 2 / 4); !$2c4e >> 8 = $d3
13b6 00d3 ld $d3 ;$2cb9 = 11449 = floor(214 ** 2 / 4); !$2cb9 >> 8 = $d3
13b7 00d2 ld $d2 ;$2d24 = 11556 = floor(215 ** 2 / 4); !$2d24 >> 8 = $d2
13b8 00d2 ld $d2 ;$2d90 = 11664 = floor(216 ** 2 / 4); !$2d90 >> 8 = $d2
13b9 00d2 ld $d2 ;$2dfc = 11772 = floor(217 ** 2 / 4); !$2dfc >> 8 = $d2
13ba 00d1 ld $d1 ;$2e69 = 11881 = floor(218 ** 2 / 4); !$2e69 >> 8 = $d1
13bb 00d1 ld $d1 ;$2ed6 = 11990 = floor(219 ** 2 / 4); !$2ed6 >> 8 = $d1
13bc 00d0 ld $d0 ;$2f44 = 12100 = floor(220 ** 2 / 4); !$2f44 >> 8 = $d0
13bd 00d0 ld $d0 ;$2fb2 = 12210 = floor(221 ** 2 / 4); !$2fb2 >> 8 = $d0
13be 00cf ld $cf ;$3021 = 12321 = floor(222 ** 2 / 4); !$3021 >> 8 = $cf
13bf 00cf ld $cf ;$3090 = 12432 = floor(223 ** 2 / 4); !$3090 >> 8 = $cf
13c0 00ce ld $ce ;$3100 = 12544 = floor(224 ** 2 / 4); !$3100 >> 8 = $ce
13c1 00ce ld $ce ;$3170 = 12656 = floor(225 ** 2 / 4); !$3170 >> 8 = $ce
13c2 00ce ld $ce ;$31e1 = 12769 = floor(226 ** 2 / 4); !$31e1 >> 8 = $ce
13c3 00cd ld $cd ;$3252 = 12882 = floor(227 ** 2 / 4); !$3252 >> 8 = $cd
13c4 00cd ld $cd ;$32c4 = 12996 = floor(228 ** 2 / 4); !$32c4 >> 8 = $cd
13c5 00cc ld $cc ;$3336 = 13110 = floor(229 ** 2 / 4); !$3336 >> 8 = $cc
13c6 00cc ld $cc ;$33a9 = 13225 = floor(230 ** 2 / 4); !$33a9 >> 8 = $cc
13c7 00cb ld $cb ;$341c = 13340 = floor(231 ** 2 / 4); !$341c >> 8 = $cb
13c8 00cb ld $cb ;$3490 = 13456 = floor(232 ** 2 / 4); !$3490 >> 8 = $cb
13c9 00ca ld $ca ;$3504 = 13572 = floor(233 ** 2 / 4); !$3504 >> 8 = $ca
13ca 00ca ld $ca ;$3579 = 13689 = floor(234 ** 2 / 4); !$3579 >> 8 = $ca
13cb 00ca ld $ca ;$35ee = 13806 = floor(235 ** 2 / 4); !$35ee >> 8 = $ca
13cc 00c9 ld $c9 ;$3664 = 13924 = floor(236 ** 2 / 4); !$3664 >> 8 = $c9
13cd 00c9 ld $c9 ;$36da = 14042 = floor(237 ** 2 / 4); !$36da >> 8 = $c9
13ce 00c8 ld $c8 ;$3751 = 14161 = floor(238 ** 2 / 4); !$3751 >> 8 = $c8
13cf 00c8 ld $c8 ;$37c8 = 14280 = floor(239 ** 2 / 4); !$37c8 >> 8 = $c8
13d0 00c7 ld $c7 ;$3840 = 14400 = floor(240 ** 2 / 4); !$3840 >> 8 = $c7
13d1 00c7 ld $c7 ;$38b8 = 14520 = floor(241 ** 2 / 4); !$38b8 >> 8 = $c7
13d2 00c6 ld $c6 ;$3931 = 14641 = floor(242 ** 2 / 4); !$3931 >> 8 = $c6
13d3 00c6 ld $c6 ;$39aa = 14762 = floor(243 ** 2 / 4); !$39aa >> 8 = $c6
13d4 00c5 ld $c5 ;$3a24 = 14884 = floor(244 ** 2 / 4); !$3a24 >> 8 = $c5
13d5 00c5 ld $c5 ;$3a9e = 15006 = floor(245 ** 2 / 4); !$3a9e >> 8 = $c5
13d6 00c4 ld $c4 ;$3b19 = 15129 = floor(246 ** 2 / 4); !$3b19 >> 8 = $c4
13d7 00c4 ld $c4 ;$3b94 = 15252 = floor(247 ** 2 / 4); !$3b94 >> 8 = $c4
13d8 00c3 ld $c3 ;$3c10 = 15376 = floor(248 ** 2 / 4); !$3c10 >> 8 = $c3
13d9 00c3 ld $c3 ;$3c8c = 15500 = floor(249 ** 2 / 4); !$3c8c >> 8 = $c3
13da 00c2 ld $c2 ;$3d09 = 15625 = floor(250 ** 2 / 4); !$3d09 >> 8 = $c2
13db 00c2 ld $c2 ;$3d86 = 15750 = floor(251 ** 2 / 4); !$3d86 >> 8 = $c2
13dc 00c1 ld $c1 ;$3e04 = 15876 = floor(252 ** 2 / 4); !$3e04 >> 8 = $c1
13dd 00c1 ld $c1 ;$3e82 = 16002 = floor(253 ** 2 / 4); !$3e82 >> 8 = $c1
13de 00c0 ld $c0 ;$3f01 = 16129 = floor(254 ** 2 / 4); !$3f01 >> 8 = $c0
13df 00c0 ld $c0 ;$3f80 = 16256 = floor(255 ** 2 / 4); !$3f80 >> 8 = $c0
5379 C(f"${val:04x} = {val} = floor({i} ** 2 / 4); !${val:04x} >> 8 = ${(~val & 0xffff) >> 8:02x}")
5380 # Return to code
5381 label("sys_MultiplyBytes.tableExit")
sys_MultiplyBytes.tableExit:
13e0 1415 ld $15,y 5382 ld(hi("sys_MultiplyBytes#44"), Y) #41,65
13e1 e129 jmp y,[$29] 5383 jmp(Y, [sysArgs + 5]) #42,66
13e2 1413 ld $13,y 5384 ld(hi(pc()), Y) #43,67
5385 # Implementation of sysMultiplyBytes
5386 label("SYS_MultiplyBytes_120")
SYS_MultiplyBytes_120:
13e3 00fd ld $fd 5387 ld("sys_MultiplyBytes.high-byte-action.store-inverted") #15
13e4 c228 st [$28] 5388 st([sysArgs + 4]) #16
13e5 0000 ld $00 5389 ld("sys_MultiplyBytes#44") #17
13e6 c229 st [$29] 5390 st([sysArgs + 5]) #18
13e7 0124 ld [$24] 5391 ld([sysArgs + 0]) #19
13e8 207f anda $7f 5392 anda(0b0111_1111) #20
13e9 c226 st [$26] 5393 st([sysArgs + 2]) #21
13ea 0125 ld [$25] 5394 ld([sysArgs + 1]) #22
13eb 207f anda $7f 5395 anda(0b0111_1111) #23
13ec c227 st [$27] 5396 st([sysArgs + 3]) #24
13ed a126 suba [$26] 5397 suba([sysArgs + 2]) #25
13ee e8f1 blt $13f1 5398 blt(pc() + 3) #26
13ef fcf2 bra $13f2 5399 bra(pc() + 3) #27
13f0 a001 suba $01 5400 suba(1) #28
13f1 60ff xora $ff 5401 xora(0xFF) #28
13f2 8001 adda $01 5402 adda(1) #29
5403 label("sys_MultiplyBytes.tableEntry")
sys_MultiplyBytes.tableEntry:
13f3 c21d st [$1d] 5404 st([vTmp]) #30,52
13f4 e8f9 blt $13f9 5405 blt(pc() + 5) #31,53
13f5 a020 suba $20 5406 suba(32) #32,54
13f6 f600 bge ac 5407 bge(AC) #33,55
13f7 fd28 bra [$28] 5408 bra([sysArgs + 4]) #34,56
13f8 00ff ld $ff 5409 ld(0xff) #35,57
13f9 fe00 bra ac 5410 bra(AC) #33,55
13fa fd28 bra [$28] 5411 bra([sysArgs + 4]) #34,56
5412 fillers(until=251)
5413 label("sys_MultiplyBytes.high-byte-action.restore-and-add")
sys_MultiplyBytes.high-byte-action.restore-and-add:
13fb 60ff xora $ff 5414 xora(0xFF) #58
13fc 8119 adda [$19] 5415 adda([vAC + 1]) #59
5416 label("sys_MultiplyBytes.high-byte-action.store-inverted")
sys_MultiplyBytes.high-byte-action.store-inverted:
13fd c219 st [$19] 5417 st([vAC + 1]) #36,60
13fe 011d ld [$1d] 5418 ld([vTmp]) #37,61
5419 assert pc() & 0xFF == 0xFF, pc()
13ff ee00 bne ac 5420 bne(AC) #38,62
1400 e0e0 jmp y,$e0 5421 jmp(Y, "sys_MultiplyBytes.tableExit") #39,63
5422 ld(0xff) #40,64
1401 00ff ld $ff ;0 = floor(0 ** 2 / 4) and floor(1 ** 2 / 4); !$0 = $ff
5423
5424 # Low-bytes, stored inverted.
5425 C("0 = floor(0 ** 2 / 4) and floor(1 ** 2 / 4); !$0 = $ff")
5426 for i in range(2, 256):
5427 val = math.floor(i ** 2 / 4)
5428 ld(~val)
1402 00fe ld $fe ;$0001 = 1 = floor(2 ** 2 / 4); !$01 = $fe
1403 00fd ld $fd ;$0002 = 2 = floor(3 ** 2 / 4); !$02 = $fd
1404 00fb ld $fb ;$0004 = 4 = floor(4 ** 2 / 4); !$04 = $fb
1405 00f9 ld $f9 ;$0006 = 6 = floor(5 ** 2 / 4); !$06 = $f9
1406 00f6 ld $f6 ;$0009 = 9 = floor(6 ** 2 / 4); !$09 = $f6
1407 00f3 ld $f3 ;$000c = 12 = floor(7 ** 2 / 4); !$0c = $f3
1408 00ef ld $ef ;$0010 = 16 = floor(8 ** 2 / 4); !$10 = $ef
1409 00eb ld $eb ;$0014 = 20 = floor(9 ** 2 / 4); !$14 = $eb
140a 00e6 ld $e6 ;$0019 = 25 = floor(10 ** 2 / 4); !$19 = $e6
140b 00e1 ld $e1 ;$001e = 30 = floor(11 ** 2 / 4); !$1e = $e1
140c 00db ld $db ;$0024 = 36 = floor(12 ** 2 / 4); !$24 = $db
140d 00d5 ld $d5 ;$002a = 42 = floor(13 ** 2 / 4); !$2a = $d5
140e 00ce ld $ce ;$0031 = 49 = floor(14 ** 2 / 4); !$31 = $ce
140f 00c7 ld $c7 ;$0038 = 56 = floor(15 ** 2 / 4); !$38 = $c7
1410 00bf ld $bf ;$0040 = 64 = floor(16 ** 2 / 4); !$40 = $bf
1411 00b7 ld $b7 ;$0048 = 72 = floor(17 ** 2 / 4); !$48 = $b7
1412 00ae ld $ae ;$0051 = 81 = floor(18 ** 2 / 4); !$51 = $ae
1413 00a5 ld $a5 ;$005a = 90 = floor(19 ** 2 / 4); !$5a = $a5
1414 009b ld $9b ;$0064 = 100 = floor(20 ** 2 / 4); !$64 = $9b
1415 0091 ld $91 ;$006e = 110 = floor(21 ** 2 / 4); !$6e = $91
1416 0086 ld $86 ;$0079 = 121 = floor(22 ** 2 / 4); !$79 = $86
1417 007b ld $7b ;$0084 = 132 = floor(23 ** 2 / 4); !$84 = $7b
1418 006f ld $6f ;$0090 = 144 = floor(24 ** 2 / 4); !$90 = $6f
1419 0063 ld $63 ;$009c = 156 = floor(25 ** 2 / 4); !$9c = $63
141a 0056 ld $56 ;$00a9 = 169 = floor(26 ** 2 / 4); !$a9 = $56
141b 0049 ld $49 ;$00b6 = 182 = floor(27 ** 2 / 4); !$b6 = $49
141c 003b ld $3b ;$00c4 = 196 = floor(28 ** 2 / 4); !$c4 = $3b
141d 002d ld $2d ;$00d2 = 210 = floor(29 ** 2 / 4); !$d2 = $2d
141e 001e ld $1e ;$00e1 = 225 = floor(30 ** 2 / 4); !$e1 = $1e
141f 000f ld $0f ;$00f0 = 240 = floor(31 ** 2 / 4); !$f0 = $0f
1420 00ff ld $ff ;$0100 = 256 = floor(32 ** 2 / 4); !$100 = $ff
1421 00ef ld $ef ;$0110 = 272 = floor(33 ** 2 / 4); !$110 = $ef
1422 00de ld $de ;$0121 = 289 = floor(34 ** 2 / 4); !$121 = $de
1423 00cd ld $cd ;$0132 = 306 = floor(35 ** 2 / 4); !$132 = $cd
1424 00bb ld $bb ;$0144 = 324 = floor(36 ** 2 / 4); !$144 = $bb
1425 00a9 ld $a9 ;$0156 = 342 = floor(37 ** 2 / 4); !$156 = $a9
1426 0096 ld $96 ;$0169 = 361 = floor(38 ** 2 / 4); !$169 = $96
1427 0083 ld $83 ;$017c = 380 = floor(39 ** 2 / 4); !$17c = $83
1428 006f ld $6f ;$0190 = 400 = floor(40 ** 2 / 4); !$190 = $6f
1429 005b ld $5b ;$01a4 = 420 = floor(41 ** 2 / 4); !$1a4 = $5b
142a 0046 ld $46 ;$01b9 = 441 = floor(42 ** 2 / 4); !$1b9 = $46
142b 0031 ld $31 ;$01ce = 462 = floor(43 ** 2 / 4); !$1ce = $31
142c 001b ld $1b ;$01e4 = 484 = floor(44 ** 2 / 4); !$1e4 = $1b
142d 0005 ld $05 ;$01fa = 506 = floor(45 ** 2 / 4); !$1fa = $05
142e 00ee ld $ee ;$0211 = 529 = floor(46 ** 2 / 4); !$211 = $ee
142f 00d7 ld $d7 ;$0228 = 552 = floor(47 ** 2 / 4); !$228 = $d7
1430 00bf ld $bf ;$0240 = 576 = floor(48 ** 2 / 4); !$240 = $bf
1431 00a7 ld $a7 ;$0258 = 600 = floor(49 ** 2 / 4); !$258 = $a7
1432 008e ld $8e ;$0271 = 625 = floor(50 ** 2 / 4); !$271 = $8e
1433 0075 ld $75 ;$028a = 650 = floor(51 ** 2 / 4); !$28a = $75
1434 005b ld $5b ;$02a4 = 676 = floor(52 ** 2 / 4); !$2a4 = $5b
1435 0041 ld $41 ;$02be = 702 = floor(53 ** 2 / 4); !$2be = $41
1436 0026 ld $26 ;$02d9 = 729 = floor(54 ** 2 / 4); !$2d9 = $26
1437 000b ld $0b ;$02f4 = 756 = floor(55 ** 2 / 4); !$2f4 = $0b
1438 00ef ld $ef ;$0310 = 784 = floor(56 ** 2 / 4); !$310 = $ef
1439 00d3 ld $d3 ;$032c = 812 = floor(57 ** 2 / 4); !$32c = $d3
143a 00b6 ld $b6 ;$0349 = 841 = floor(58 ** 2 / 4); !$349 = $b6
143b 0099 ld $99 ;$0366 = 870 = floor(59 ** 2 / 4); !$366 = $99
143c 007b ld $7b ;$0384 = 900 = floor(60 ** 2 / 4); !$384 = $7b
143d 005d ld $5d ;$03a2 = 930 = floor(61 ** 2 / 4); !$3a2 = $5d
143e 003e ld $3e ;$03c1 = 961 = floor(62 ** 2 / 4); !$3c1 = $3e
143f 001f ld $1f ;$03e0 = 992 = floor(63 ** 2 / 4); !$3e0 = $1f
1440 00ff ld $ff ;$0400 = 1024 = floor(64 ** 2 / 4); !$400 = $ff
1441 00df ld $df ;$0420 = 1056 = floor(65 ** 2 / 4); !$420 = $df
1442 00be ld $be ;$0441 = 1089 = floor(66 ** 2 / 4); !$441 = $be
1443 009d ld $9d ;$0462 = 1122 = floor(67 ** 2 / 4); !$462 = $9d
1444 007b ld $7b ;$0484 = 1156 = floor(68 ** 2 / 4); !$484 = $7b
1445 0059 ld $59 ;$04a6 = 1190 = floor(69 ** 2 / 4); !$4a6 = $59
1446 0036 ld $36 ;$04c9 = 1225 = floor(70 ** 2 / 4); !$4c9 = $36
1447 0013 ld $13 ;$04ec = 1260 = floor(71 ** 2 / 4); !$4ec = $13
1448 00ef ld $ef ;$0510 = 1296 = floor(72 ** 2 / 4); !$510 = $ef
1449 00cb ld $cb ;$0534 = 1332 = floor(73 ** 2 / 4); !$534 = $cb
144a 00a6 ld $a6 ;$0559 = 1369 = floor(74 ** 2 / 4); !$559 = $a6
144b 0081 ld $81 ;$057e = 1406 = floor(75 ** 2 / 4); !$57e = $81
144c 005b ld $5b ;$05a4 = 1444 = floor(76 ** 2 / 4); !$5a4 = $5b
144d 0035 ld $35 ;$05ca = 1482 = floor(77 ** 2 / 4); !$5ca = $35
144e 000e ld $0e ;$05f1 = 1521 = floor(78 ** 2 / 4); !$5f1 = $0e
144f 00e7 ld $e7 ;$0618 = 1560 = floor(79 ** 2 / 4); !$618 = $e7
1450 00bf ld $bf ;$0640 = 1600 = floor(80 ** 2 / 4); !$640 = $bf
1451 0097 ld $97 ;$0668 = 1640 = floor(81 ** 2 / 4); !$668 = $97
1452 006e ld $6e ;$0691 = 1681 = floor(82 ** 2 / 4); !$691 = $6e
1453 0045 ld $45 ;$06ba = 1722 = floor(83 ** 2 / 4); !$6ba = $45
1454 001b ld $1b ;$06e4 = 1764 = floor(84 ** 2 / 4); !$6e4 = $1b
1455 00f1 ld $f1 ;$070e = 1806 = floor(85 ** 2 / 4); !$70e = $f1
1456 00c6 ld $c6 ;$0739 = 1849 = floor(86 ** 2 / 4); !$739 = $c6
1457 009b ld $9b ;$0764 = 1892 = floor(87 ** 2 / 4); !$764 = $9b
1458 006f ld $6f ;$0790 = 1936 = floor(88 ** 2 / 4); !$790 = $6f
1459 0043 ld $43 ;$07bc = 1980 = floor(89 ** 2 / 4); !$7bc = $43
145a 0016 ld $16 ;$07e9 = 2025 = floor(90 ** 2 / 4); !$7e9 = $16
145b 00e9 ld $e9 ;$0816 = 2070 = floor(91 ** 2 / 4); !$816 = $e9
145c 00bb ld $bb ;$0844 = 2116 = floor(92 ** 2 / 4); !$844 = $bb
145d 008d ld $8d ;$0872 = 2162 = floor(93 ** 2 / 4); !$872 = $8d
145e 005e ld $5e ;$08a1 = 2209 = floor(94 ** 2 / 4); !$8a1 = $5e
145f 002f ld $2f ;$08d0 = 2256 = floor(95 ** 2 / 4); !$8d0 = $2f
1460 00ff ld $ff ;$0900 = 2304 = floor(96 ** 2 / 4); !$900 = $ff
1461 00cf ld $cf ;$0930 = 2352 = floor(97 ** 2 / 4); !$930 = $cf
1462 009e ld $9e ;$0961 = 2401 = floor(98 ** 2 / 4); !$961 = $9e
1463 006d ld $6d ;$0992 = 2450 = floor(99 ** 2 / 4); !$992 = $6d
1464 003b ld $3b ;$09c4 = 2500 = floor(100 ** 2 / 4); !$9c4 = $3b
1465 0009 ld $09 ;$09f6 = 2550 = floor(101 ** 2 / 4); !$9f6 = $09
1466 00d6 ld $d6 ;$0a29 = 2601 = floor(102 ** 2 / 4); !$a29 = $d6
1467 00a3 ld $a3 ;$0a5c = 2652 = floor(103 ** 2 / 4); !$a5c = $a3
1468 006f ld $6f ;$0a90 = 2704 = floor(104 ** 2 / 4); !$a90 = $6f
1469 003b ld $3b ;$0ac4 = 2756 = floor(105 ** 2 / 4); !$ac4 = $3b
146a 0006 ld $06 ;$0af9 = 2809 = floor(106 ** 2 / 4); !$af9 = $06
146b 00d1 ld $d1 ;$0b2e = 2862 = floor(107 ** 2 / 4); !$b2e = $d1
146c 009b ld $9b ;$0b64 = 2916 = floor(108 ** 2 / 4); !$b64 = $9b
146d 0065 ld $65 ;$0b9a = 2970 = floor(109 ** 2 / 4); !$b9a = $65
146e 002e ld $2e ;$0bd1 = 3025 = floor(110 ** 2 / 4); !$bd1 = $2e
146f 00f7 ld $f7 ;$0c08 = 3080 = floor(111 ** 2 / 4); !$c08 = $f7
1470 00bf ld $bf ;$0c40 = 3136 = floor(112 ** 2 / 4); !$c40 = $bf
1471 0087 ld $87 ;$0c78 = 3192 = floor(113 ** 2 / 4); !$c78 = $87
1472 004e ld $4e ;$0cb1 = 3249 = floor(114 ** 2 / 4); !$cb1 = $4e
1473 0015 ld $15 ;$0cea = 3306 = floor(115 ** 2 / 4); !$cea = $15
1474 00db ld $db ;$0d24 = 3364 = floor(116 ** 2 / 4); !$d24 = $db
1475 00a1 ld $a1 ;$0d5e = 3422 = floor(117 ** 2 / 4); !$d5e = $a1
1476 0066 ld $66 ;$0d99 = 3481 = floor(118 ** 2 / 4); !$d99 = $66
1477 002b ld $2b ;$0dd4 = 3540 = floor(119 ** 2 / 4); !$dd4 = $2b
1478 00ef ld $ef ;$0e10 = 3600 = floor(120 ** 2 / 4); !$e10 = $ef
1479 00b3 ld $b3 ;$0e4c = 3660 = floor(121 ** 2 / 4); !$e4c = $b3
147a 0076 ld $76 ;$0e89 = 3721 = floor(122 ** 2 / 4); !$e89 = $76
147b 0039 ld $39 ;$0ec6 = 3782 = floor(123 ** 2 / 4); !$ec6 = $39
147c 00fb ld $fb ;$0f04 = 3844 = floor(124 ** 2 / 4); !$f04 = $fb
147d 00bd ld $bd ;$0f42 = 3906 = floor(125 ** 2 / 4); !$f42 = $bd
147e 007e ld $7e ;$0f81 = 3969 = floor(126 ** 2 / 4); !$f81 = $7e
147f 003f ld $3f ;$0fc0 = 4032 = floor(127 ** 2 / 4); !$fc0 = $3f
1480 00ff ld $ff ;$1000 = 4096 = floor(128 ** 2 / 4); !$1000 = $ff
1481 00bf ld $bf ;$1040 = 4160 = floor(129 ** 2 / 4); !$1040 = $bf
1482 007e ld $7e ;$1081 = 4225 = floor(130 ** 2 / 4); !$1081 = $7e
1483 003d ld $3d ;$10c2 = 4290 = floor(131 ** 2 / 4); !$10c2 = $3d
1484 00fb ld $fb ;$1104 = 4356 = floor(132 ** 2 / 4); !$1104 = $fb
1485 00b9 ld $b9 ;$1146 = 4422 = floor(133 ** 2 / 4); !$1146 = $b9
1486 0076 ld $76 ;$1189 = 4489 = floor(134 ** 2 / 4); !$1189 = $76
1487 0033 ld $33 ;$11cc = 4556 = floor(135 ** 2 / 4); !$11cc = $33
1488 00ef ld $ef ;$1210 = 4624 = floor(136 ** 2 / 4); !$1210 = $ef
1489 00ab ld $ab ;$1254 = 4692 = floor(137 ** 2 / 4); !$1254 = $ab
148a 0066 ld $66 ;$1299 = 4761 = floor(138 ** 2 / 4); !$1299 = $66
148b 0021 ld $21 ;$12de = 4830 = floor(139 ** 2 / 4); !$12de = $21
148c 00db ld $db ;$1324 = 4900 = floor(140 ** 2 / 4); !$1324 = $db
148d 0095 ld $95 ;$136a = 4970 = floor(141 ** 2 / 4); !$136a = $95
148e 004e ld $4e ;$13b1 = 5041 = floor(142 ** 2 / 4); !$13b1 = $4e
148f 0007 ld $07 ;$13f8 = 5112 = floor(143 ** 2 / 4); !$13f8 = $07
1490 00bf ld $bf ;$1440 = 5184 = floor(144 ** 2 / 4); !$1440 = $bf
1491 0077 ld $77 ;$1488 = 5256 = floor(145 ** 2 / 4); !$1488 = $77
1492 002e ld $2e ;$14d1 = 5329 = floor(146 ** 2 / 4); !$14d1 = $2e
1493 00e5 ld $e5 ;$151a = 5402 = floor(147 ** 2 / 4); !$151a = $e5
1494 009b ld $9b ;$1564 = 5476 = floor(148 ** 2 / 4); !$1564 = $9b
1495 0051 ld $51 ;$15ae = 5550 = floor(149 ** 2 / 4); !$15ae = $51
1496 0006 ld $06 ;$15f9 = 5625 = floor(150 ** 2 / 4); !$15f9 = $06
1497 00bb ld $bb ;$1644 = 5700 = floor(151 ** 2 / 4); !$1644 = $bb
1498 006f ld $6f ;$1690 = 5776 = floor(152 ** 2 / 4); !$1690 = $6f
1499 0023 ld $23 ;$16dc = 5852 = floor(153 ** 2 / 4); !$16dc = $23
149a 00d6 ld $d6 ;$1729 = 5929 = floor(154 ** 2 / 4); !$1729 = $d6
149b 0089 ld $89 ;$1776 = 6006 = floor(155 ** 2 / 4); !$1776 = $89
149c 003b ld $3b ;$17c4 = 6084 = floor(156 ** 2 / 4); !$17c4 = $3b
149d 00ed ld $ed ;$1812 = 6162 = floor(157 ** 2 / 4); !$1812 = $ed
149e 009e ld $9e ;$1861 = 6241 = floor(158 ** 2 / 4); !$1861 = $9e
149f 004f ld $4f ;$18b0 = 6320 = floor(159 ** 2 / 4); !$18b0 = $4f
14a0 00ff ld $ff ;$1900 = 6400 = floor(160 ** 2 / 4); !$1900 = $ff
14a1 00af ld $af ;$1950 = 6480 = floor(161 ** 2 / 4); !$1950 = $af
14a2 005e ld $5e ;$19a1 = 6561 = floor(162 ** 2 / 4); !$19a1 = $5e
14a3 000d ld $0d ;$19f2 = 6642 = floor(163 ** 2 / 4); !$19f2 = $0d
14a4 00bb ld $bb ;$1a44 = 6724 = floor(164 ** 2 / 4); !$1a44 = $bb
14a5 0069 ld $69 ;$1a96 = 6806 = floor(165 ** 2 / 4); !$1a96 = $69
14a6 0016 ld $16 ;$1ae9 = 6889 = floor(166 ** 2 / 4); !$1ae9 = $16
14a7 00c3 ld $c3 ;$1b3c = 6972 = floor(167 ** 2 / 4); !$1b3c = $c3
14a8 006f ld $6f ;$1b90 = 7056 = floor(168 ** 2 / 4); !$1b90 = $6f
14a9 001b ld $1b ;$1be4 = 7140 = floor(169 ** 2 / 4); !$1be4 = $1b
14aa 00c6 ld $c6 ;$1c39 = 7225 = floor(170 ** 2 / 4); !$1c39 = $c6
14ab 0071 ld $71 ;$1c8e = 7310 = floor(171 ** 2 / 4); !$1c8e = $71
14ac 001b ld $1b ;$1ce4 = 7396 = floor(172 ** 2 / 4); !$1ce4 = $1b
14ad 00c5 ld $c5 ;$1d3a = 7482 = floor(173 ** 2 / 4); !$1d3a = $c5
14ae 006e ld $6e ;$1d91 = 7569 = floor(174 ** 2 / 4); !$1d91 = $6e
14af 0017 ld $17 ;$1de8 = 7656 = floor(175 ** 2 / 4); !$1de8 = $17
14b0 00bf ld $bf ;$1e40 = 7744 = floor(176 ** 2 / 4); !$1e40 = $bf
14b1 0067 ld $67 ;$1e98 = 7832 = floor(177 ** 2 / 4); !$1e98 = $67
14b2 000e ld $0e ;$1ef1 = 7921 = floor(178 ** 2 / 4); !$1ef1 = $0e
14b3 00b5 ld $b5 ;$1f4a = 8010 = floor(179 ** 2 / 4); !$1f4a = $b5
14b4 005b ld $5b ;$1fa4 = 8100 = floor(180 ** 2 / 4); !$1fa4 = $5b
14b5 0001 ld $01 ;$1ffe = 8190 = floor(181 ** 2 / 4); !$1ffe = $01
14b6 00a6 ld $a6 ;$2059 = 8281 = floor(182 ** 2 / 4); !$2059 = $a6
14b7 004b ld $4b ;$20b4 = 8372 = floor(183 ** 2 / 4); !$20b4 = $4b
14b8 00ef ld $ef ;$2110 = 8464 = floor(184 ** 2 / 4); !$2110 = $ef
14b9 0093 ld $93 ;$216c = 8556 = floor(185 ** 2 / 4); !$216c = $93
14ba 0036 ld $36 ;$21c9 = 8649 = floor(186 ** 2 / 4); !$21c9 = $36
14bb 00d9 ld $d9 ;$2226 = 8742 = floor(187 ** 2 / 4); !$2226 = $d9
14bc 007b ld $7b ;$2284 = 8836 = floor(188 ** 2 / 4); !$2284 = $7b
14bd 001d ld $1d ;$22e2 = 8930 = floor(189 ** 2 / 4); !$22e2 = $1d
14be 00be ld $be ;$2341 = 9025 = floor(190 ** 2 / 4); !$2341 = $be
14bf 005f ld $5f ;$23a0 = 9120 = floor(191 ** 2 / 4); !$23a0 = $5f
14c0 00ff ld $ff ;$2400 = 9216 = floor(192 ** 2 / 4); !$2400 = $ff
14c1 009f ld $9f ;$2460 = 9312 = floor(193 ** 2 / 4); !$2460 = $9f
14c2 003e ld $3e ;$24c1 = 9409 = floor(194 ** 2 / 4); !$24c1 = $3e
14c3 00dd ld $dd ;$2522 = 9506 = floor(195 ** 2 / 4); !$2522 = $dd
14c4 007b ld $7b ;$2584 = 9604 = floor(196 ** 2 / 4); !$2584 = $7b
14c5 0019 ld $19 ;$25e6 = 9702 = floor(197 ** 2 / 4); !$25e6 = $19
14c6 00b6 ld $b6 ;$2649 = 9801 = floor(198 ** 2 / 4); !$2649 = $b6
14c7 0053 ld $53 ;$26ac = 9900 = floor(199 ** 2 / 4); !$26ac = $53
14c8 00ef ld $ef ;$2710 = 10000 = floor(200 ** 2 / 4); !$2710 = $ef
14c9 008b ld $8b ;$2774 = 10100 = floor(201 ** 2 / 4); !$2774 = $8b
14ca 0026 ld $26 ;$27d9 = 10201 = floor(202 ** 2 / 4); !$27d9 = $26
14cb 00c1 ld $c1 ;$283e = 10302 = floor(203 ** 2 / 4); !$283e = $c1
14cc 005b ld $5b ;$28a4 = 10404 = floor(204 ** 2 / 4); !$28a4 = $5b
14cd 00f5 ld $f5 ;$290a = 10506 = floor(205 ** 2 / 4); !$290a = $f5
14ce 008e ld $8e ;$2971 = 10609 = floor(206 ** 2 / 4); !$2971 = $8e
14cf 0027 ld $27 ;$29d8 = 10712 = floor(207 ** 2 / 4); !$29d8 = $27
14d0 00bf ld $bf ;$2a40 = 10816 = floor(208 ** 2 / 4); !$2a40 = $bf
14d1 0057 ld $57 ;$2aa8 = 10920 = floor(209 ** 2 / 4); !$2aa8 = $57
14d2 00ee ld $ee ;$2b11 = 11025 = floor(210 ** 2 / 4); !$2b11 = $ee
14d3 0085 ld $85 ;$2b7a = 11130 = floor(211 ** 2 / 4); !$2b7a = $85
14d4 001b ld $1b ;$2be4 = 11236 = floor(212 ** 2 / 4); !$2be4 = $1b
14d5 00b1 ld $b1 ;$2c4e = 11342 = floor(213 ** 2 / 4); !$2c4e = $b1
14d6 0046 ld $46 ;$2cb9 = 11449 = floor(214 ** 2 / 4); !$2cb9 = $46
14d7 00db ld $db ;$2d24 = 11556 = floor(215 ** 2 / 4); !$2d24 = $db
14d8 006f ld $6f ;$2d90 = 11664 = floor(216 ** 2 / 4); !$2d90 = $6f
14d9 0003 ld $03 ;$2dfc = 11772 = floor(217 ** 2 / 4); !$2dfc = $03
14da 0096 ld $96 ;$2e69 = 11881 = floor(218 ** 2 / 4); !$2e69 = $96
14db 0029 ld $29 ;$2ed6 = 11990 = floor(219 ** 2 / 4); !$2ed6 = $29
14dc 00bb ld $bb ;$2f44 = 12100 = floor(220 ** 2 / 4); !$2f44 = $bb
14dd 004d ld $4d ;$2fb2 = 12210 = floor(221 ** 2 / 4); !$2fb2 = $4d
14de 00de ld $de ;$3021 = 12321 = floor(222 ** 2 / 4); !$3021 = $de
14df 006f ld $6f ;$3090 = 12432 = floor(223 ** 2 / 4); !$3090 = $6f
14e0 00ff ld $ff ;$3100 = 12544 = floor(224 ** 2 / 4); !$3100 = $ff
14e1 008f ld $8f ;$3170 = 12656 = floor(225 ** 2 / 4); !$3170 = $8f
14e2 001e ld $1e ;$31e1 = 12769 = floor(226 ** 2 / 4); !$31e1 = $1e
14e3 00ad ld $ad ;$3252 = 12882 = floor(227 ** 2 / 4); !$3252 = $ad
14e4 003b ld $3b ;$32c4 = 12996 = floor(228 ** 2 / 4); !$32c4 = $3b
14e5 00c9 ld $c9 ;$3336 = 13110 = floor(229 ** 2 / 4); !$3336 = $c9
14e6 0056 ld $56 ;$33a9 = 13225 = floor(230 ** 2 / 4); !$33a9 = $56
14e7 00e3 ld $e3 ;$341c = 13340 = floor(231 ** 2 / 4); !$341c = $e3
14e8 006f ld $6f ;$3490 = 13456 = floor(232 ** 2 / 4); !$3490 = $6f
14e9 00fb ld $fb ;$3504 = 13572 = floor(233 ** 2 / 4); !$3504 = $fb
14ea 0086 ld $86 ;$3579 = 13689 = floor(234 ** 2 / 4); !$3579 = $86
14eb 0011 ld $11 ;$35ee = 13806 = floor(235 ** 2 / 4); !$35ee = $11
14ec 009b ld $9b ;$3664 = 13924 = floor(236 ** 2 / 4); !$3664 = $9b
14ed 0025 ld $25 ;$36da = 14042 = floor(237 ** 2 / 4); !$36da = $25
14ee 00ae ld $ae ;$3751 = 14161 = floor(238 ** 2 / 4); !$3751 = $ae
14ef 0037 ld $37 ;$37c8 = 14280 = floor(239 ** 2 / 4); !$37c8 = $37
14f0 00bf ld $bf ;$3840 = 14400 = floor(240 ** 2 / 4); !$3840 = $bf
14f1 0047 ld $47 ;$38b8 = 14520 = floor(241 ** 2 / 4); !$38b8 = $47
14f2 00ce ld $ce ;$3931 = 14641 = floor(242 ** 2 / 4); !$3931 = $ce
14f3 0055 ld $55 ;$39aa = 14762 = floor(243 ** 2 / 4); !$39aa = $55
14f4 00db ld $db ;$3a24 = 14884 = floor(244 ** 2 / 4); !$3a24 = $db
14f5 0061 ld $61 ;$3a9e = 15006 = floor(245 ** 2 / 4); !$3a9e = $61
14f6 00e6 ld $e6 ;$3b19 = 15129 = floor(246 ** 2 / 4); !$3b19 = $e6
14f7 006b ld $6b ;$3b94 = 15252 = floor(247 ** 2 / 4); !$3b94 = $6b
14f8 00ef ld $ef ;$3c10 = 15376 = floor(248 ** 2 / 4); !$3c10 = $ef
14f9 0073 ld $73 ;$3c8c = 15500 = floor(249 ** 2 / 4); !$3c8c = $73
14fa 00f6 ld $f6 ;$3d09 = 15625 = floor(250 ** 2 / 4); !$3d09 = $f6
14fb 0079 ld $79 ;$3d86 = 15750 = floor(251 ** 2 / 4); !$3d86 = $79
14fc 00fb ld $fb ;$3e04 = 15876 = floor(252 ** 2 / 4); !$3e04 = $fb
14fd 007d ld $7d ;$3e82 = 16002 = floor(253 ** 2 / 4); !$3e82 = $7d
14fe 00fe ld $fe ;$3f01 = 16129 = floor(254 ** 2 / 4); !$3f01 = $fe
14ff 007f ld $7f ;$3f80 = 16256 = floor(255 ** 2 / 4); !$3f80 = $7f
5429 C(f"${val:04x} = {val} = floor({i} ** 2 / 4); !${val:02x} = ${(~val) & 0xff:02x}")
5430 align(0x100)
5431
5432
5433 label("sys_MultiplyBytes#44")
sys_MultiplyBytes#44:
1500 c218 st [$18] 5434 st([vAC]) #44
1501 00fb ld $fb 5435 ld("sys_MultiplyBytes.high-byte-action.restore-and-add") #45
1502 c228 st [$28] 5436 st([sysArgs + 4]) #46
1503 0008 ld $08 5437 ld("sys_MultiplyBytes#68") #47
1504 c229 st [$29] 5438 st([sysArgs + 5]) #48
1505 0126 ld [$26] 5439 ld([sysArgs + 2]) #49
1506 e0f3 jmp y,$f3 5440 jmp(Y, "sys_MultiplyBytes.tableEntry") #50
1507 8127 adda [$27] 5441 adda([sysArgs + 3]) #51
5442 label("sys_MultiplyBytes#68")
sys_MultiplyBytes#68:
1508 60ff xora $ff 5443 xora(0xff) #68
1509 8001 adda $01 5444 adda(1) #69
150a 8118 adda [$18] 5445 adda([vAC]) #70
150b c21d st [$1d] 5446 st([vTmp]) #71
150c e810 blt $1510 5447 blt(pc() + 4) #72
150d a118 suba [$18] 5448 suba([vAC]) #73
150e fc12 bra $1512 5449 bra(pc() + 4) #74
150f 4118 ora [$18] 5450 ora([vAC]) #75
1510 fc12 bra $1512 5451 bra(pc() + 2) #74
1511 2118 anda [$18] 5452 anda([vAC]) #75
1512 3080 anda $80,x 5453 anda(0b1000_0000, X) #76
1513 011d ld [$1d] 5454 ld([vTmp]) #77
1514 c218 st [$18] 5455 st([vAC]) #78
1515 0500 ld [x] 5456 ld([X]) #79
1516 8119 adda [$19] 5457 adda([vAC + 1]) #80
1517 c219 st [$19] 5458 st([vAC + 1]) #81
5459 # 7 bit x 7 bit multiply complete
1518 0124 ld [$24] 5460 ld([sysArgs + 0]) #82
1519 6125 xora [$25] 5461 xora([sysArgs + 1]) #83
5462 blt("sys_MultiplyBytes.oneMsbSetCase") # 84
151a e839 blt sys_MultiplyBytes.oneMsbSetCase
151b 0124 ld [$24] 5463 ld([sysArgs + 0]) #85
151c e821 blt $1521 5464 blt(pc() + 5) #86
151d 0040 ld $40 5465 ld(2 ** 14 >> 8) #87
151e 1403 ld $03,y 5466 ld(hi('NEXTY'), Y) #88
151f e000 jmp y,$00 5467 jmp(Y, 'NEXTY') #89
1520 00d2 ld $d2 5468 ld(-92/2) #90
5469
1521 8119 adda [$19] 5470 adda([vAC + 1]) #88
1522 c219 st [$19] 5471 st([vAC + 1]) #89
1523 0126 ld [$26] 5472 ld([sysArgs + 2]) #90
1524 8127 adda [$27] 5473 adda([sysArgs + 3]) #91
5474 label("sys_MultiplyBytes#92")
5475 # Reusing sysArgs + 2, because we can't use vTmp twice
sys_MultiplyBytes#92:
1525 c226 st [$26] 5476 st([sysArgs + 2]) #92
1526 2001 anda $01 5477 anda(0b0000_0001) #93
1527 807f adda $7f 5478 adda(0b0111_1111) #94
1528 2080 anda $80 5479 anda(0b1000_0000) #95
1529 1200 ld ac,x 5480 ld(AC, X) #96
152a 8118 adda [$18] 5481 adda([vAC]) #97
152b c218 st [$18] 5482 st([vAC]) #98
152c e82f blt $152f 5483 blt(pc() + 3) #99
152d fc30 bra $1530 5484 bra(pc() + 3) #100
152e 0500 ld [x] 5485 ld([X]) #101
152f 0000 ld $00 5486 ld(0) #101
1530 8119 adda [$19] 5487 adda([vAC + 1]) #102
1531 c219 st [$19] 5488 st([vAC + 1]) #103
1532 00f6 ld $f6 5489 ld("sys_MultiplyBytes#114") #104
1533 c21d st [$1d] 5490 st([vTmp]) #105
1534 0126 ld [$26] 5491 ld([sysArgs + 2]) #106
1535 20fe anda $fe 5492 anda(0b1111_1110) #107
1536 1405 ld $05,y 5493 ld(hi("shiftTable"), Y) #108
1537 e200 jmp y,ac 5494 jmp(Y, AC) #109
1538 fcff bra $ff 5495 bra(0xFF) #110
5496 # The rest happens in and after the shift table,
5497 # but to save you looking it, looks like this
5498 #111 ld (ac >> 1)
5499 #112 bra [vTmp]
5500 #113 nop
5501 #114 adda [vAC + 1]
5502 #115 st [vAC + 1]
5503 #116 ld hi('NEXTY'), y
5504 #117 jmp y, 'NEXTY'
5505 #118 ld -120/2
5506 label("sys_MultiplyBytes.oneMsbSetCase")
sys_MultiplyBytes.oneMsbSetCase:
1539 f43c bge $153c 5507 bge(pc() + 3) # 86
153a fc3d bra $153d 5508 bra(pc() + 3) # 87
153b 0127 ld [$27] 5509 ld([sysArgs + 3]) # 88
153c 0126 ld [$26] 5510 ld([sysArgs + 2]) # 88
153d 0200 nop 5511 nop() # 89
5512 bra("sys_MultiplyBytes#92") # 90
153e fc25 bra sys_MultiplyBytes#92
153f 0200 nop 5513 nop() # 91
5514
5515
5516 label("SYS_KaratsubaPrepare_54")
5517 # Prepare arguments for SYS_MultiplyBytes.
5518 # Arguments are in sysArgs[0:1] and vAC[0:1]
5519 # Result goes in sysArgs[0:1], and vAC contains zero if the result is going to be positive
5520 #
5521 # First calculate abs(sysArgs[0] - sysArgs[1]), remembering whether we had to negate.
SYS_KaratsubaPrepare_54:
1540 0124 ld [$24] 5522 ld([sysArgs]) # 15
5523 bmi("sysKaratsubaPrepare#18") # 16
1541 e846 blt sysKaratsubaPrepare#18
1542 a125 suba [$25] 5524 suba([sysArgs + 1]) # 17
5525
1543 c224 st [$24] 5526 st([sysArgs]) # 18
5527 bra("sysKaratsubaPrepare#21") # 19
1544 fc49 bra sysKaratsubaPrepare#21
1545 4125 ora [$25] 5528 ora([sysArgs + 1]) # 20
5529
5530 label("sysKaratsubaPrepare#18")
sysKaratsubaPrepare#18:
1546 c224 st [$24] 5531 st([sysArgs]) # 18
1547 2125 anda [$25] 5532 anda([sysArgs + 1]) # 19
1548 0200 nop 5533 nop() # 20
5534
5535 label("sysKaratsubaPrepare#21")
sysKaratsubaPrepare#21:
1549 3080 anda $80,x 5536 anda(0x80,X) # 21 Store sign for later
154a e84e blt $154e 5537 bmi(pc()+4) # 22 Invert if necessary
154b 0124 ld [$24] 5538 ld([sysArgs]) # 23
5539
154c fc50 bra $1550 5540 bra(pc() + 4) # 24 No need to negate
154d 0200 nop 5541 nop() # 25
5542
154e 60ff xora $ff 5543 xora(0xff) # 24 Need to negate
154f 8001 adda $01 5544 adda(1) # 25
5545
1550 c224 st [$24] 5546 st([sysArgs]) # 26
1551 0500 ld [x] 5547 ld([X]) # 27 Store sign
1552 c21d st [$1d] 5548 st([vTmp]) # 28
5549
5550 # Same dance, a second time, but for the other value
1553 0119 ld [$19] 5551 ld([vAC + 1]) # 29
5552 bmi("sysKaratsubaPrepare#32") # 30
1554 e859 blt sysKaratsubaPrepare#32
1555 a118 suba [$18] 5553 suba([vAC]) # 31
5554
1556 c225 st [$25] 5555 st([sysArgs + 1]) # 32
5556 bra("sysKaratsubaPrepare#35") # 33
1557 fc5c bra sysKaratsubaPrepare#35
1558 4118 ora [$18] 5557 ora([vAC]) # 34
5558
5559 label("sysKaratsubaPrepare#32")
sysKaratsubaPrepare#32:
1559 c225 st [$25] 5560 st([sysArgs + 1]) # 32
155a 2118 anda [$18] 5561 anda([vAC]) # 33
155b 0200 nop 5562 nop() # 34
5563
5564 label("sysKaratsubaPrepare#35")
sysKaratsubaPrepare#35:
155c 3080 anda $80,x 5565 anda(0x80,X) # 35 Store sign for later
155d e861 blt $1561 5566 bmi(pc()+4) # 36 Invert if necessary
155e 0125 ld [$25] 5567 ld([sysArgs + 1]) # 37
5568
155f fc63 bra $1563 5569 bra(pc() + 4) # 38
1560 0200 nop 5570 nop() # 39
5571
1561 60ff xora $ff 5572 xora(0xff) # 38
1562 8001 adda $01 5573 adda(1) # 39
5574
1563 c225 st [$25] 5575 st([sysArgs + 1]) # 40
5576
5577 # Store flag to say if result must be inverted
1564 011d ld [$1d] 5578 ld([vTmp]) # 41
1565 6500 xora [x] 5579 xora([X]) # 42
1566 c218 st [$18] 5580 st([vAC]) # 43
1567 c219 st [$19] 5581 st([vAC + 1]) # 44
5582
1568 0013 ld $13 5583 ld(hi("SYS_MultiplyBytes_120")) # 45
1569 c223 st [$23] 5584 st([sysFn + 1]) # 46
156a 00e3 ld $e3 5585 ld("SYS_MultiplyBytes_120") # 47
156b c222 st [$22] 5586 st([sysFn]) # 48
156c 1403 ld $03,y 5587 ld(hi('REENTER'), Y) # 49
156d e0cb jmp y,$cb 5588 jmp(Y, 'REENTER') # 50
156e 00e5 ld $e5 5589 ld(-54/2) # 51
5590
5591
5592
5593
5594 #-----------------------------------------------------------------------
5595 #
5596 # End of core
5597 #
5598 #-----------------------------------------------------------------------
5599 if __name__ == '__main__': disableListing()
sys_ReadRomDir:
156f f075 beq .sysDir#20
1570 1024 ld $24,x
1571 1600 ld ac,y
1572 0118 ld [$18]
1573 a00e suba $0e
1574 e200 jmp y,ac
.sysDir#20: 1575 1400 ld $00,y
1576 007a ld $7a
1577 1415 ld $15,y
1578 e200 jmp y,ac
1579 1400 ld $00,y
.sysDir#25:
.sysDir#39: 157a 1403 ld $03,y
157b e0cb jmp y,$cb
157c 00ea ld $ea
157d 0200 nop ;126 fillers
157e 0200 nop
157f 0200 nop
* 126 times
15fb fe00 bra ac ;+-----------------------------------+
15fc fcfd bra $15fd ;| |
15fd 1404 ld $04,y ;| Trampoline for page $1500 lookups |
15fe e068 jmp y,$68 ;| |
15ff c218 st [$18] ;+-----------------------------------+
1600