* 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<>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 [ n*]* 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 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 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 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 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 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 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 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_[_v]_ 2164 # 2165 # With 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 # 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); 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