Apple2000/src/AppleII.s

7147 lines
157 KiB
ArmAsm

SECTION APPLEII,CODE
* Changes: PCount is a full 32 bit pointer, so memory model is now flat. ABSOLUTE!!!
* Full "GetByte" IS USED in insts that will ultimately PutByte! (due to hardware rds)
* Fixed a couple instructions to work with more flexible hardware emulation subs
* fixed intertask communication...
* new changes:
* Optimized Video-mode rtns for consecutive mode-changing insts (do nothing until
* last instruction)
* Broke program into different SECTIONS (APPLEII,OPENCLOSE, and TABLES)
* A couple HW locations have data ($c020, $c060) to make a couple progs work
* Fixed Drive emulation to disable physical drive activity unless drive #1 is enabled
* (but ignoring motor status for now due to speed)
* Added 16K ram card emulation! (Currently ignores 2-access rule for write enabling)
* RESET will set system to ROM read and Write enable bank 2 (like //e, not //+)
* NumPad keys used to trim joystick center... (#2,4,5,6, & 8)
* Changing PCount during "Stop Inst" (eg: LOADING an executable) sets Video to Text1
* Loading an executable file also sets ram card to "Rom Read"
* Added PCount History diagnostic for debugging...
* Added "FlushMsgs" so all inputs immediately after a requester are ignored
* Removed 1/2 second delay after requesters (due to fixed intertask comm & flush msgs)
* Added automatic DISK IMAGE COMPRESSION during save, with pseudo-prodos header!
* Expanded Joystick cycle counts to work with LodeRunner...
* Added toggleable MOUSE/JOYSTICK control of pdls... (f9 key) w/ word in title bar
* Reworked Title Bar/Window display so can read mouse buttons ANYWHERE in screen...
* Reworked Diagnostic message in title bar (each has a FORBID due to shared lib)
* Added a custom (blank) pointer so not to confuse it with apple progs...
* I think the DECOMPRESS function automatically handles both ProDos & Dos headers...
* Clear Slot Rom memory ($c100 - $c7ff) to FF's so ProDos thinks they're empty!
* Minor opt in PUSHWORD to write to memory once...
* Reworked all STAT macros!
* --Did I fix the Copperlists by adding a CBUMP at the end of each one???
* DOCYCLE reads word with PostInc'ing of PCount (so PCount needs less adding)
* ** Reg d0 is kept with top word clean at ALL TIMES in 6502 emulation. **
* Lots of MEM_addressing & cpu optimizations because of it...
* Opt'ed BIT__ functions for more straightforward Status update...
* Hi-Res draw routines first check if memory has been changed! (big opt!)
* Text/Lo-Res draw routines first check if memory has been changed!
* Sound is sent to both channel 0 & 1 (stereo'ish)
* Fixed mischevious bug (undocumented) in PUSHSTAT subroutine... (see it)
* Optimized: JSR, RTS, ADC, SBC, ROL, ROR...
* Upon loading executable Apple prog, low memory is reset to fresh "power-up" state
* Major opts to:Vector-Jump table now 256K (16 bit word referenced * 4)
* DOCYCLE doesn't have to clear hi 8 bits of word anymore
* All MEM_IMMED routines opt'd to not reference memory, but use d1 from DOCYCLE
* All Bcc's dont reference mem, but use d1 from DOCYCLE (& other opts)
* PUBLIC RELEASE v1.0 around in April, 94
* 04/21/94 Fixed PBHardware so "unhandled" writes DO NOT change memory
* (fixed probs w/ button read on "Red Alert", which tried to ROL $c061)
* 04/26/94 Included Custom Disk Rom that is used if _DISK.ROM file not present
* 04/27/94 Included ability to load 143,360 byte generic "disk images"
* 04/29/94 Upon any ResumeCPU call, re-activate our window...
* 04/29/94 Check for 68020+ CPU (instead of crashing!)
* 04/29/94 Reading from $c050 - $c057 returns progressive data (Tetris II now boots)
* 05/01/94 Now saves disk images in 143,360 byte "generic disk image" instead of DDD format
* 05/01/94 Opt'd STAT routines a little (ie: use BCHG instead of EOR for inverse carry)
* 05/01/94 Opt'd TX_ Insts to use STAT_SZfast instead of STAT_SZ
* 05/01/94 Opt'd all CLC+ADC and SEC+SBC combinations...
* 05/07/94 Proper Dos/ProDos executable/disk image/Rom file recognition
* 05/08/94 Opt'd all DEX/INX/DEY/INY + CPX/CPY Insts...
* 05/11/94 Put STACK in HIGH WORD of register to make lower word available for use!!!!!!
* 05/13/94 Opt'd STAT_ stuff...
* 05/15/94 Opt'd all DEX/INX/DEY/INY/PHA/TAX/TAY + LDA instruction pairs
* 05/18/94 Opt'd bunch more xxx + STA instruction pairs...
* PUBLIC RELEASE v1.1 on 05/18/94
* 05/28/94 Added support for Analog Joystick w/ 2 buttons!
* 05/29/94 Fixed Stack (now 100% accurate) so words wrap on same page
* (Sargon, MoonPatrol, Lode Runner, Pinball Co Set now work)
* 06/01/94 Added "Page-flipping loop" recognition & skipping...
* (ShortCircuit,BileStoad,OutPost)
* 06/04/94 Overhaul entire video subsystem! No more copper lists, hardware hitting, etc...
* 06/10/94 Continuing to optimize video switches... Useless changes ignored
* 06/17/24 Added StatusBar messaging system
* 06/20/94 Added Lower Case characters from //e charset
* 06/20/94 Flashing/Color-changing only occurs when flashing is visible.
* 06/24/94 Added Dynamic Analog Joystick ranging (for different joysticks)
* 06/24/94 Added Atari Paddle support
* 06/24/94 "Requestor Screen" now uses Workbench colors
* 06/30/94 Fixed AGA/Mode promo bug... Can't set more colors than screen allows!
* 07/01/94 Added 2 drive support (via -2 command) to hardware ($C0xx) handlers...
* 07/02/94 Added 2 drive req support to load/save commands
* 07/03/94 All video-HW reads return values from list (Canyon Climber, Tetris II ttl, Drol)
* 07/03/94 Made keyboard read vals for $c000 - $c007 (Frogger into screen works)
* 07/10/94 Optional DDD compression by ending filename in '>' during save
* 07/12/94 16K card banking routines optimized to prevent needless memcpy...
* 07/15/94 Working Speed Regulation & interface (60 hz screen only)
* 07/17/94 Added 6502 bug- Jump ($xxff) wrap-around getting indirection... (Randamn works)
* 07/18/94 Optimized DDD decompress & denibbleize functions...
* 07/19/94 FileReqs retain independant filenames for each drive for loading/saving
* 07/22/94 Fixed "Rewrite file xxx" requester...
* 07/22/94 Opt'd DDD compress & some saving routines...
* 07/23/94 Screen now 200 lines (standard size)
* 07/24/94 Re-did Joystick & Mouse pdl emu routines (simple, full-range of motion)
* 07/28/94 Added "Warning- Disk image Changed" warnings during disk loads & quit
* 07/28/94 Opt'd Memory Address modes even more...
* 07/28/94 Opt'd BIT, ROL, ROR, ASL insts
* 07/29/94 Free'd up a register ("Temp") by using stack instead (seldom)
* 07/29/94 Opt'd CLC/SEC + ROL pairs...
* 08/02/94 Added cheesy "Monitor off" effect
* 08/18/94 Used old default "requester" colors again... (not WB)
* 08/20/94 Default speed regulation to 100%
* To Do:
* check ADC/SBC bcd status settings, optimize ROL,ROR,ASL, etc...
* Handle lores/hires page swapping (gorgon, zenith, space voyage, etc...)
* Add Icon...
* Check keymap thing (# on swedish keyboard)
* check if potbits & intrpts are turned off at exit properly...
* Comments: Map is clean and flat from $0000->$FFFF
* IMPORTANT! Reg d0 MUST be kept with top word clear at ALL TIMES in 6502 context.
AReg EQUR d7 ;AReg,XReg,&YReg are clean 8 bit nums. KEEP CLEAN!!!
XReg EQUR d6
YReg EQUR d5
StatusSZ EQUR d4
Cycles EQUR d3 ;Progressive counter of effective apple cycles...
Stack EQUR d2 ;(Stack) -> Current byte of stack ($100 - $1ff)(HIGH WORD ONLY!!!!!)
StatusCV EQUR d2 ;bottom word only (shared w/ Stack)
;Temp EQUR a5 ;for routines (CPU inst's) to backup data...
Mem_Ptr EQUR a4 ;reference start of 64k apple memory block...
InstTbl EQUR a3
PCount EQUR a2 ;ABSOLUTE 32 bit ptr, not index!
rts
****************************************
* General Note: All "F" routines are FastGetByte or FastPutByte functions,
* which read/write from apple memory in a QUICK fashion, with no checks
* or support for i/o accesses. 6502 Instructions, Operands, and addressing
* from memory use these routines, and therefore will execute differently
* from an actual apple in these conditions. However, executing from i/o
* would be a rare circumstance (NO reason for it), and in all probability
* would only happen during an apple-crash.
*
* Reading from ROM or RAM Banks (for speed) is not checked for but
* is accounted for. When apple i/o to change "bank/Rom to read from" is
* set, memory is actually copied to the top ($d000-$ffff, whatever) area.
****************************************
CLEAR MACRO.w
moveq.l #0,\1
ENDM
*******************************
* FPUTBYTE does a quick PutByte with no i/o,hardware,graphic checks.
* Enter: a0 = LONG 16 bit address (clean in top 16 bits!!!) to write
* d0 = Byte to write
*******************************
FPUTBYTE MACRO.w
move.b d0,(Mem_Ptr,a0.l)
ENDM
*****************************************
* FGETBYTE does a quick GetByte with no i/o checks. Preserves high bits.
* Enter: a0 = LONG 16 bit address (clean in top 16 bits) to read
* Return: d0 = Byte read, clean!
*****************************************
FGETBYTE MACRO.w
move.b (Mem_Ptr,a0.l),d0 [14]= 18 total!
ENDM
*********************************
* FGETWORD does a fast read of a 'normalized' word from apple memory. No i/o.
* Enter: A0 = Long 16 bit addr to read.
* Return: D0 = Word in form 'xxxxHILO', preserving top 16 bits.
********************************** (used in Brk, ResetCPU, and MEM_routines)
FGETWORD MACRO.w
move.w (Mem_Ptr,a0.l),d0
ror.w #8,d0
ENDM
***** FGETWORDd0 is same as FGETWORD, but refs "D0" instead of "A0" *****
FGETWORDd0 MACRO.w
move.w (Mem_Ptr,d0.l),d0
ror.w #8,d0
ENDM
**************************************************
* GETBYTE - General Routine to Read a Byte of Memory from apple memory.
* Checks for hardware/io access, and handle if rqrd.
* Enter: D0 = LONG 16 bit addr to read (CLEAN!) <------ d0!!!!
* Return: D0 = Byte of Data in D0:0-7. (FGetByte is fast-no check)
******************************************
GETBYTE MACRO.w
cmp.w #$c000,d0 [6] ;in $c001 - $c0ff range???
bls.b .InBnd [9]
cmp.w #$c0ff,d0
bhi.b .InBnd
bsr GBHardWare ;HardWare! Go Handle!
and.l #$ff,d0 ;remove once all GBHardware routines cleaned...
bra.b .EndGB
CNOP 0,4
.InBnd move.b (Mem_Ptr,d0.l),d0 ; [14]
.EndGB
ENDM
*************************************************
* PUTBYTE - General Routine to Write a Byte of Memory to apple memory.
* Checks for ALL EXCEPTIONS (hardware/io/Video pages), and handle if rqrd.
* ENTER: D0 = LONG 16 bit addr to write,
* D1 = Byte to write.
*************************************************
PUTBYTE MACRO.w
move.l d0,a0 [03]
lsr.w #8,d0 ;/64 Memory page # * 4... [04]
move.l #PBPageList,a1 [5]
move.l (a1,d0.w*4),d0 [11] = [29] !
beq.b .safe\@
move.l d0,a1
jsr (a1) ;A0 = address, d1 = Data !!!!
CLEAR d0 ;remove when all routines clean...
bra.b .cont\@
.safe\@ move.b d1,(Mem_Ptr,a0.l) ;modified FPUTBYTE
.cont\@
ENDM
PUTBYTE_DOCYCLE MACRO.w
move.l d0,a0 [03]
lsr.w #8,d0 ;/64 Memory page # * 4... [04]
move.l #PBPageList,a1 [5]
move.l (a1,d0.w*4),d0 [11] = [29] !
beq.b .safe\@
move.l d0,a1
jsr (a1) ;A0 = address, d1 = Data !!!!
CLEAR d0 ;remove when all routines clean...
bra.b .cont\@
; DOCYCLE
.safe\@ move.b d1,(Mem_Ptr,a0.l) ;modified FPUTBYTE
.cont\@ DOCYCLE
ENDM
********************************
* PUSH/PULL will push or pull selected byte to/from Apple Stack ($100-$1ff).
* eg... "PUSH d0", "PULL AReg" etc.... DO NOT push/pull Status this way!!!!
*
* NOTE: Due to Opts, Pre/Post +- opposite of 6502,
* and "Stack" is +1 actual location. TSX & TXS fixed. (INVALID- Works identically)
********************************
PUSH MACRO.w ;eg "PUSH d0"
swap Stack
move.b \1,(Mem_Ptr,Stack.w) ; [08]
subq.b #1,Stack
swap Stack
ENDM
PULL MACRO.w ;eg "PULL AReg"
swap Stack
addq.b #1,Stack
move.b (Mem_Ptr,Stack.w),\1 ; [08]
swap Stack
ENDM
*************************************
* PUSH16 / PULL16 will push or pull a word to/from apple stack & update.
* Push - Hi 1st, LO 2nd. Pull - LO first, HI 2nd.
* Enter: (PUSH16) = D0 = Word to push
* Return (PULL16) = D0 = Word from stack
**************************************
PUSH16 MACRO.w
ror.w #8,d0
PUSH d0
lsr.w #8,d0
PUSH d0
ENDM
;Pull 16 bit number from Apple Stack... LO byte, Then Hi
;Update Stack ptr and return # in D0
PULL16 MACRO.w
PULL d1
PULL d0
lsl.w #8,d0
move.b d1,d0
ENDM
***** All the grind work due to using different bits in the emulated StatusReg
***** are taken care of when pushing/pulling status here...
* Strangely, it appears that the Break flag is always set upon pushing the Status.
* Perhaps its only clear during an interrupt? Saving it as clear allowed a nasty
* bug in Dos 3.3 filtered text, accidentally making a match to the "INIT" command.
* (See dos 3.3 $9fc0 - $9a10). Experiments on the //gs show even if B is forced clear,
* any command that changes the Status reg will automatically set B as well...
* Apple Status= ; Bit 7 6 5 4 3 2 1 0
; _________________________________
; | S | V | | B | D | I | Z | C |
; +---+---+---+---+---+---+---+---+
; | | | | | | |__Carry
; | |_Over- | | | |_Zero
; | Flow | | |_Intrpt Disable
; |_Sign | |_Decimal
; |_Break
PUSHSTAT MACRO.w ;pushes status in proper apple way
;build d0 in proper 6502 Status form (above)
.s7 btst.l #S_BIT,StatusSZ [05]
sne.b d0 [04]
lsl.w d0 [04]
.v6 btst.l #V_BIT,StatusCV
sne.b d0
lsl.w d0
.b54 move.b #$ff,d0 ;B Always set (& unused bit 5 set too!)
lsl.w #2,d0
.d3 btst.l #D_BIT,StatusSZ
sne.b d0
lsl.w d0
.i2 btst.l #I_BIT,StatusSZ
sne.b d0
lsl.w d0
.z1 btst.l #Z_BIT,StatusSZ
sne.b d0
lsl.w d0
.c0 btst.l #C_BIT,StatusCV
sne.b d0
lsl.w d0
lsr.w #8,d0
PUSH d0
ENDM
* Apple Status= ; Bit 7 6 5 4 3 2 1 0
; _________________________________
; | S | V | | B | D | I | Z | C |
; +---+---+---+---+---+---+---+---+
; | | | | | | |__Carry
; | |_Over- | | | |_Zero
; | Flow | | |_Intrpt Disable
; |_Sign | |_Decimal
; |_Break
PULLSTAT MACRO.w
PULL d0
; moveq.l #0,StatusSZ ;build internal Status from 6502 form (above)
; move.w #0,StatusCV ;low word only...
.bdi move.b d0,StatusSZ [03] ;Got B, D, and I
swap StatusSZ [04]
.sBit lsl.b d0 [04] ;get S (temporarily in bit 8)
scs.b StatusSZ [04]
lsl.w StatusSZ [04]
.vBit lsl.b d0 ;get V
scs.b StatusCV
lsl.w StatusCV
.cBit lsr.b #3,d0 ;get C
scs.b StatusCV
.zBit lsr.b d0 ;Get Z
scs.b StatusSZ
lsr.w #5,StatusSZ ;and slide S & Z to proper bits...
ENDM
*************************************
* All MEM_ routines are to handle different 6502 address modes.
* Note: Due to 16 bit read of PCount mem, optimizations are made by
* expecting low byte in D0 to have next byte of data!
*
* Enter: "PCount" = pointing at opcode
* D0 = word of data from "PCount"
* Return: D0 = operand's 16 bit address in A0 (CLEAN!) -----D0-----
* PCount = PCount + Full Inst Size
*
*************************************
MEM_Abs MACRO.w ;*** LDA $xxxx ***
move.b (PCount)+,d0 [07]
lsl.w #8,d0 [04]
move.b d1,d0 [03] = 14
ENDM
MEM_ZP MACRO.w ;*** LDA $xx ***
moveq.l #0,d0 [03]
move.b d1,d0 [03]
ENDM
MEM_PreIndx MACRO.w ;*** LDA ($xx,X) ***
move.w XReg,d0 ;(clear high byte)
add.b d1,d0 ;FGETBYTE1PC
;FGETWORDd0 ;get 16 bit # being pointed at
move.w (Mem_Ptr,d0.l),d0
ror.w #8,d0
ENDM
MEM_PostIndx MACRO.w ;*** LDA ($xx),Y ***
moveq.l #0,d0
move.b d1,d0
FGETWORDd0
add.w YReg,d0 ;16 bit add...(YReg & d0 must be clean!)
ENDM
MEM_ZPIndxX MACRO.w ;*** LDA $xx,X ***
move.w XReg,d0
add.b d1,d0 ;8 bit add
ENDM
MEM_ZPIndxY MACRO.w ;*** LDA $xx,Y ***
move.w YReg,d0
add.b d1,d0 ;8 bit add
ENDM
MEM_AbsIndxX MACRO.w ;*** LDA $xxxx,X ***
move.b (PCount)+,d0 [07]
lsl.w #8,d0 [04]
move.b d1,d0 [03] = 14
add.w XReg,d0 ;16 bit add
ENDM
MEM_AbsIndxY MACRO.w ;*** LDA $xxxx,Y ***
move.b (PCount)+,d0 [07]
lsl.w #8,d0 [04]
move.b d1,d0 [03] = 14
add.w YReg,d0 ;16 bit add
ENDM
*** OLDMEM routines and are for 2'nd INST of CPU inst pairs that don't have operands in D1.
** They read from and Inc PCOUNT to get operands.
OLDMEM_Abs MACRO.w ;*** LDA $xxxx ***
move.w (PCount)+,d0 [07]
ror.w #8,d0 [08] = [15]
ENDM
OLDMEM_ZP MACRO.w ;*** LDA $xx ***
moveq.l #0,d0
move.b (PCount)+,d0 [07]
ENDM
OLDMEM_PreIndx MACRO.w ;*** LDA ($xx,X) *** (optd)
move.w XReg,d0
add.b (PCount)+,d0
FGETWORDd0 ;get 16 bit # being pointed at
ENDM
OLDMEM_PostIndx MACRO.w ;*** LDA ($xx),Y ***
moveq.l #0,d0
move.b (PCount)+,d0
FGETWORDd0
add.w YReg,d0 ;16 bit add...(YReg & d0 must be clean!)
ENDM
OLDMEM_ZPIndxX MACRO.w ;*** LDA $xx,X *** (optd)
move.w XReg,d0
add.b (PCount)+,d0 ;8 bit add
ENDM
OLDMEM_ZPIndxY MACRO.w ;*** LDA $xx,Y *** (optd)
move.w YReg,d0
add.b (PCount)+,d0 ;8 bit add
ENDM
OLDMEM_AbsIndxX MACRO.w ;*** LDA $xxxx,X ***
move.w (PCount)+,d0
ror.w #8,d0
add.w XReg,d0 ;16 bit add
ENDM
OLDMEM_AbsIndxY MACRO.w ;*** LDA $xxxx,Y ***
move.w (PCount)+,d0
ror.w #8,d0
add.w YReg,d0 ;16 bit add
ENDM
OLDMEM_ImmedD0 MACRO.w ;*** LDA #$08 ***
move.b (PCount)+,d0 ;(returns immediate val in d0)
ENDM
*************************************************8
* STAT_ routines check actual CCR reg after an instruction, and will
* copy pertinent bits to Status.
*
* Enter: amiga CCR = conditions set (via operations)
* Return: Status = new status bits properly set
*
* NOTE: due to opts, the BIT / HEX settings are DIFFERENT than the 6502 cpu
* status register. PUSH/PULL STATUS routines accomidate this difference,
* so the apple will never know.
B_BIT equ 20 ;(7,6,5 not in Amiga ccr, but we'll let 'em be in Status high word anyways)
D_BIT equ 19
I_BIT equ 18
S_BIT equ 3 ;within StatusSZ word (just like amiga CCR)
Z_BIT equ 2
V_BIT equ 8 ;within StatusCV word
C_BIT equ 7
S_HEX equ $1<<S_BIT ;x_HEX used to build masks in STAT rtns
Z_HEX equ $1<<Z_BIT
V_HEX equ $1<<V_BIT
C_HEX equ $1<<C_BIT
;Scc SpecAddr [11]
;AND.w #Imm, Dn [06]
;AND.l #Imm, Dn [08]
;Bcc.b [05/09]
;BTST/BSET/BCLR #imm,Dx [05]
;eor.l #Imm, Dn [08]
;BCHG.l #Imm, Dn [05]
* Status bits emulated in two separate registers (low word of each).
* StatusSZ has S & Z bits, and StatusCV holds C & V bits. Note that
* the other bits in these two words can't be used for anything!
STAT_SZ MACRO
move.w ccr,StatusSZ [06]
ENDM
STAT_C MACRO (ASL,ROL,ROR,ADCbcd)
scs.b StatusCV ;set bit 7 (& more) [04] = 10
ENDM
STAT_SZC MACRO (ASL,ROL,ROR,ADCbcd)
move.w ccr,StatusSZ [06]
scs.b StatusCV ;set bit 7 (& more) [04] = 10
ENDM
STAT_SZiC MACRO ;do C bit reversed (CMP, CPX, CPY, SBCbcd)
move.w ccr,StatusSZ [06]
scc.b StatusCV [04] = 10
ENDM
STAT_SVZC MACRO (ADC)
move.w ccr,StatusSZ [06]
move.b StatusSZ,StatusCV [03]
lsl.w #7,StatusCV ;shift C ->bit 7, V ->8 [04] = 13
ENDM
STAT_SVZiC MACRO ;for SBC & CMP due to inverse C... (SBC)
move.w ccr,StatusSZ [06]
move.b StatusSZ,StatusCV [03]
lsl.w #7,StatusCV [04]
bchg.l #C_BIT,StatusCV [05] = 18
ENDM
**************************************
* "Regulate" is a macro that checks if speed regulation is necessary, and if so,
* it properly waits the rqrd amount of time.
**************************************
REGULATE MACRO.w
move.l WaitCycPerFrame,d0 ;d0 = WaitCyc, if -1 then no regulation!
bmi.b .done
move.l Cycles,d1 ;CurrentCycle - LastStopCycle = ElapsedCycles
sub.l LastStopCycle,d1 ; (okay if Cycles has wrapped around)
sub.l d0,d1
bmi.b .done
move.l CIAControlReg,a0
.wait btst.b #0,(a0) ;wait for timer to finish
bne.b .wait
bset.b #0,(a0) ;and restart it
add.l d0,LastStopCycle
sub.l d0,d1 ;Reset LastCycleCount
bpl.b .wait
.done
moveq.l #0,d0
ENDM
RegulateSize dc.l .end-.strt
.strt REGULATE
.end
**************************************
* "DoCycle" is the main routine that reads instruction & jumps via
* table to code to process it. Call with all CPU vars set!
**************************************
DOCYCLE MACRO.w
; jsr KeepHistory ;FOR DEBUGGING!!!! ----------------
move.w (PCount)+,d1 ;read byte, inc PCount by 2... [07]
move.l (InstTbl,d1.w*4),a0
jmp (a0)
CNOP 0,8
ENDM
CNOP 0,4
PCountIndex dc.l 0
PCHistory:
ds.l 256 ;for PC history for debugging!!!
EVEN
KeepHistory:
move.l PCountIndex,d0
move.l PCount,(PCHistory.l,d0.l*4)
addq.b #1,d0
move.l d0,PCountIndex
rts
ReportHistory:
move.l d2,-(sp)
lea .msg,a0
jsr DB_String ;"PC History:"
move.l PCountIndex,d1
sub.b #40,d1 ;d1 = memIndx
move.l #39,d2 ;d2 = count
.lp move.l (PCHistory.l,d1.l*4),d0
sub.l Mem_Ptr,d0
sub.l #2,d0 ;adjust for PostInc of PCount
jsr DB_HexW ;Print HexAddr...
addq.b #1,d1
dbf d2,.lp
move.l (sp)+,d2
rts
.msg dc.b "6502 execution history:",10,13,0
CNOP 0,4
Start6502: ;*** ONLY CALL to BEGIN 6502 emu task!!!! ***
move.l #-1,d0
CALLEXEC AllocSignal ;Get signal for Stop/Resume control.
move.l d0,ChildSigBit ;(fail now and we're screwed!!!)
moveq.l #0,d1
bset d0,d1
move.l d1,ChildSigMask
jsr RestoreTable
move.l ParentTaskPtr,a1
move.l ParentSigMask,d0
CALLEXEC Signal ;critical init'ing done... Tell parent..
move.w #60,Hardware+aud0+ac_vol.l ;Set Channel 0 Volume to Max
move.w #1,Hardware+aud0+ac_per.l ;Channel 0 Period
move.w #60,Hardware+aud1+ac_vol.l ;Set Channel 1 Volume to Max
move.w #1,Hardware+aud1+ac_per.l ;Channel 1 Period
move.l Mem_PtrVar,Mem_Ptr
move.l InstTbl_Var,InstTbl <----
add.l #$20000,InstTbl ;due to (-) word offset reference...
moveq.l #0,Cycles ;start it with 0 elapsed cycles...
move.l Cycles,LastStopCycle
move.l #0,PCount
clr.l XReg
clr.l YReg
clr.l AReg ; _____ (set rom/ram if rqrd)
move.l #$fffc,a0 ; RESET vector!
moveq.l #0,d0
FGETWORD ;D0=apple PC (clean)
add.l Mem_Ptr,d0
move.l d0,PCount
move.l #$01ff0000,Stack ;reset it to top of frame! (high word is used)
clr.l StatusSZ
bset.l #I_BIT,StatusSZ
bset.l #B_BIT,StatusSZ
move.b #%00000001,VidMode ;text page 1
jsr RefreshVideo
CLEAR d0
DOCYCLE
;All CPU instructions are labeled in 3 letter CAPS,
;followed by the Hex Opcode for it... eg: BRK00 .
;Internal Names are 3 letter CAPS, followed by
;a _MEM if gets/puts addr, _ACC if gets addr, puts ACC.
;Enter with: PCount pointing to OpCode + 2 !!!! D1 = word of mem...
;Internally ( _Acc, _Mem) enters with A0=<EA>
;All are called directly from DOCYCLE
;NOTE: Due to a global optimization in 6502 emulation code,
; register d0 must always maintain the high word as 0.
; Any instruction code/hardware handler MUST obey!
*------------------------- BRK / UNDefined --------------------------*
UND00:
; jsr ReportHistory ;<------- DEBUGGING DIAGNOSTIC!
lea .UNDMsg,a0
lea .UNDMsg2,a1
bra BrkPrnt
.UNDMsg dc.b "!!! UNDEFINED INST AT $"
.UNDMsg2 dc.b "0000",0,50
EVEN
BRK00:
; jsr ReportHistory ;<------- DEBUGGING DIAGNOSTIC!
lea .BRKMsg,a0
lea .BRKMsg2,a1
bra BrkPrnt
.BRKMsg dc.b "!!! BREAK INST AT $"
.BRKMsg2 dc.b "0000",0,50,0
EVEN
BrkPrnt move.l PCount,d0 ;<--- for our information
sub.l Mem_Ptr,d0
sub.l #2,d0 ;adjust for PostInc'ing of PCount
move.w d0,d1 ;parse hex digits...
lsr.w #8,d0 ;1st digit...
lsr.w #4,d0
add.b #'0',d0
cmp.b #'9',d0
bls 1$
add.b #'A'-'9'-1,d0
1$ move.b d0,(a1)+
move.w d1,d0
lsr.w #8,d0 ;2st digit...
and.b #$0f,d0
add.b #'0',d0
cmp.b #'9',d0
bls 2$
add.b #'A'-'9'-1,d0
2$ move.b d0,(a1)+
move.w d1,d0
lsr.b #4,d0 ;3rd digit...
add.b #'0',d0
cmp.b #'9',d0
bls 3$
add.b #'A'-'9'-1,d0
3$ move.b d0,(a1)+
move.w d1,d0 ;4th digit...
and.b #$0f,d0
add.b #'0',d0
cmp.b #'9',d0
bls 4$
add.b #'A'-'9'-1,d0
4$ move.b d0,(a1)+
move.l a0,NewStatusMsgPtr ;and set to print!
.DoActualBreak:
move.l #$c081,d0 ;reset 16k card on reset!
GETBYTE
;floob move.l #$c081,d0
; GETBYTE
bset.l #B_BIT,StatusSZ ;Set Break bit...
move.l PCount,d0
sub.l Mem_Ptr,d0
PUSH16
PUSHSTAT
bset.l #I_BIT,StatusSZ ;Set Intrpt Mask
move.l #$fffe,a0
moveq.l #0,d0
FGETWORD
add.l Mem_Ptr,d0
move.l d0,PCount
addq.l #7,Cycles
CLEAR d0
DOCYCLE
EVEN
*------------------- ADC ------ Add Mem + Carry -> Acc---------*** STATUS DEPENDANT ***
ADC6D: MEM_Abs ;ADC $1234
addq.l #4,Cycles
GETBYTE
btst.l #D_BIT,StatusSZ [05]
bne.b .bcd [05]
.dec lsr.b #8,StatusCV [04] Sets/Clrs X flag based on C in Status & Sets Z Flag
addx.b d0,AReg [03] ADDX - Z flag only cleared, not set! = [17]
STAT_SVZC
DOCYCLE
.bcd lsr.b #8,StatusCV ;Sets/Clrs X flag based on C in Status & Sets Z Flag
abcd.b d0,AReg ;ABCD - Z flag only cleared, not set!
STAT_SZC ;manual says Z not set. Is V???
DOCYCLE
ADC61: MEM_PreIndx ;ADC ($06,X)
addq.l #6,Cycles
GETBYTE
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
addx.b d0,AReg
STAT_SVZC
DOCYCLE
.bcd lsr.b #8,StatusCV
abcd.b d0,AReg
STAT_SZC
DOCYCLE
ADC71: MEM_PostIndx ;ADC ($06),Y
addq.l #5,Cycles
GETBYTE
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
addx.b d0,AReg
STAT_SVZC
DOCYCLE
.bcd lsr.b #8,StatusCV
abcd.b d0,AReg
STAT_SZC
DOCYCLE
ADC79: MEM_AbsIndxY ;ADC $1234,Y
addq.l #4,Cycles
GETBYTE
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
addx.b d0,AReg
STAT_SVZC
DOCYCLE
.bcd lsr.b #8,StatusCV
abcd.b d0,AReg
STAT_SZC
DOCYCLE
ADC7D: MEM_AbsIndxX ;ADC $1234,X
addq.l #4,Cycles
GETBYTE
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
addx.b d0,AReg
STAT_SVZC
DOCYCLE
.bcd lsr.b #8,StatusCV
abcd.b d0,AReg
STAT_SZC
DOCYCLE
ADC65: MEM_ZP ;ADC $06
addq.l #3,Cycles
move.b (Mem_Ptr,d0.l),d0
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
addx.b d0,AReg
STAT_SVZC
DOCYCLE
.bcd lsr.b #8,StatusCV
abcd.b d0,AReg
STAT_SZC
DOCYCLE
ADC75: MEM_ZPIndxX ;ADC $06,X
addq.l #4,Cycles
move.b (Mem_Ptr,d0.l),d0
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
addx.b d0,AReg
STAT_SVZC
DOCYCLE
.bcd lsr.b #8,StatusCV
abcd.b d0,AReg
STAT_SZC
DOCYCLE
ADC69: move.b d1,d0 ;Mem_Immed - ADC #$06
addq.l #2,Cycles
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
addx.b d0,AReg
STAT_SVZC
DOCYCLE
.bcd lsr.b #8,StatusCV
abcd.b d0,AReg
STAT_SZC
DOCYCLE
*--------------------------- AND -----------------------------------*
AND2D: MEM_Abs ;AND $1234
addq.l #4,Cycles
GETBYTE
and.b d0,AReg
STAT_SZ
DOCYCLE
AND21: MEM_PreIndx ;AND ($06,X)
addq.l #6,Cycles
GETBYTE
and.b d0,AReg
STAT_SZ
DOCYCLE
AND31: MEM_PostIndx ;AND ($06),Y
addq.l #5,Cycles
GETBYTE
and.b d0,AReg
STAT_SZ
DOCYCLE
AND39: MEM_AbsIndxY ;AND $1234,Y
addq.l #4,Cycles
GETBYTE
and.b d0,AReg
STAT_SZ
DOCYCLE
AND3D: MEM_AbsIndxX ;AND $1234,X
addq.l #4,Cycles
GETBYTE
and.b d0,AReg
STAT_SZ
DOCYCLE
AND29: ;MEM_Immed - AND #$06
addq.l #2,Cycles
and.b d1,AReg
STAT_SZ
DOCYCLE
AND25: MEM_ZP ;AND $06
and.b (Mem_Ptr,d0.l),AReg
STAT_SZ
addq.l #3,Cycles
DOCYCLE
AND35: MEM_ZPIndxX ;AND $06,X
and.b (Mem_Ptr,d0.l),AReg
STAT_SZ
addq.l #4,Cycles
DOCYCLE
*--------------------------- ASL -----------------------------------*
ASL0E: MEM_Abs ;ASL $1234
addq.l #6,Cycles
move.w d0,-(sp)
GETBYTE ;must do safe read in case of PDL, DISK, etc...
move.b d0,d1
lsl.b d1 ;lsl leaves V flag clear
STAT_SZC
move.w (sp)+,d0
PUTBYTE_DOCYCLE
ASL1E: MEM_AbsIndxX ;ASL $1234,X
addq.l #7,Cycles
move.w d0,-(sp)
GETBYTE
move.b d0,d1
lsl.b d1
STAT_SZC
move.w (sp)+,d0
PUTBYTE_DOCYCLE
ASL0A: lsl.b AReg ;ASL Acc
STAT_SZC
subq.w #1,PCount
addq.l #2,Cycles
DOCYCLE
ASL06: MEM_ZP ;ASL $20
move.b (Mem_Ptr,d0.l),d1
lsl.b d1
STAT_SZC ;preserve addr in d0
move.b d1,(Mem_Ptr,d0.l)
addq.l #5,Cycles
DOCYCLE
ASL16: MEM_ZPIndxX ;ASL $06,X
move.b (Mem_Ptr,d0.l),d1
lsl.b d1
STAT_SZC ;preserve addr in d0
move.b d1,(Mem_Ptr,d0.l)
addq.l #6,Cycles
DOCYCLE
*---------------------------- BIT ---------- (Stat Dependant) -------------------*
BIT2C: MEM_Abs ;BIT $1234
addq.l #4,Cycles
GETBYTE ;(Doesnt Change Acc, just Status)
move.b AReg,d1
and.b d0,d1
STAT_SZ ;get Z from result of "and"
lsr.b #6,d0 [04] ;copy this bit into V flag
bfins d0,StatusCV{31-V_BIT:1} [10]
lsr.b d0 [04] ;and S flag
bfins d0,StatusSZ{31-S_BIT:1} [10]
DOCYCLE
BIT24: MEM_ZP ;BIT $06
addq.l #3,Cycles
move.b (Mem_Ptr,d0.l),d0 ;(Doesnt Change Acc, just Status)
move.b AReg,d1
and.b d0,d1
STAT_SZ ;get Z from result of "and"
lsr.b #6,d0 [04] ;copy this bit into V flag
bfins d0,StatusCV{31-V_BIT:1} [10]
lsr.b d0 [04] ;and S flag
bfins d0,StatusSZ{31-S_BIT:1} [10]
DOCYCLE
*----------------------- BRANCHING! --------------------------------*
BPL10Reg:
move.l d1,a6
REGULATE
move.l a6,d1
BPL10: btst.l #S_BIT,StatusSZ ;BPL +-disp branch if plus (s=0)
bne.b .NoJmp
ext.w d1
add.w d1,PCount
addq.l #3,Cycles
DOCYCLE
.NoJmp addq.l #2,Cycles
DOCYCLE
BMI30Reg:
move.l d1,a6
REGULATE
move.l a6,d1
BMI30: btst.l #S_BIT,StatusSZ ;BMI (+-Disp) branch if minus (s=1)
beq.b .NoJmp
ext.w d1
add.w d1,PCount
addq.l #3,Cycles
DOCYCLE
.NoJmp addq.l #2,Cycles
DOCYCLE
BCC90: btst.l #C_BIT,StatusCV ;BCC +- Disp Branch if Carry Clear (C=0)
bne.b .NoJmp
ext.w d1
add.w d1,PCount
addq.l #3,Cycles
DOCYCLE
.NoJmp addq.l #2,Cycles
DOCYCLE
BCSB0: btst.l #C_BIT,StatusCV ;BCS +-Disp Branch Carry Set (C=1)
beq.b .NoJmp
ext.w d1
add.w d1,PCount
addq.l #3,Cycles
DOCYCLE
.NoJmp addq.l #2,Cycles
DOCYCLE
BVC50: btst.l #V_BIT,StatusCV ;BVC +-Disp Branch if Overflow clear (V=0)
bne.b .NoJmp
ext.w d1
add.w d1,PCount
addq.l #3,Cycles
DOCYCLE
.NoJmp addq.l #2,Cycles
DOCYCLE
BVS70: btst.l #V_BIT,StatusCV ;BVS +-Disp branch if overflow (V=1) set
beq.b .NoJmp
ext.w d1
add.w d1,PCount
addq.l #3,Cycles
DOCYCLE
.NoJmp addq.l #2,Cycles
DOCYCLE
BNED0Reg:
move.l d1,a6
REGULATE
move.l a6,d1
BNED0: btst.l #Z_BIT,StatusSZ [05] ;BNE +-Disp Branch if not Equal (z=0)
bne.b .NoJmp [05] ;not taken
ext.w d1 [03]
add.w d1,PCount [03]
addq.l #3,Cycles [03]
DOCYCLE [25]=44
.NoJmp addq.l #2,Cycles
DOCYCLE
BEQF0Reg:
move.l d1,a6
REGULATE
move.l a6,d1
BEQF0: btst.l #Z_BIT,StatusSZ ;beq +-Disp Branch if Equal (z=1)
beq.b .NoJmp
ext.w d1
add.w d1,PCount
addq.l #3,Cycles
DOCYCLE
.NoJmp addq.l #2,Cycles
DOCYCLE
*----------------------- CLEAR STATUS BITS -------------------------*
CLC18: bclr.l #C_BIT,StatusCV ;CLC - Clear Carry (C=0)
subq.w #1,PCount
addq.l #2,Cycles
DOCYCLE
CLVB8: bclr.l #V_BIT,StatusCV ;CLV - Clear Overflow (V=0)
subq.w #1,PCount
addq.l #2,Cycles
DOCYCLE
CLDD8: bclr.l #D_BIT,StatusSZ ;CLD - Clear Decimal status (D=0)
subq.w #1,PCount
addq.l #2,Cycles
DOCYCLE
CLI58: bclr.l #I_BIT,StatusSZ ;CLI- Clear Intrpt Mask (enable) (I=0)
subq.w #1,PCount
addq.l #2,Cycles
DOCYCLE
*--------------------------- CMP -----------------------------------*
CMPCD: MEM_Abs ;CMP $1234
addq.l #4,Cycles
GETBYTE ;read mem, subtract from ACC, set SZC
cmp.b d0,AReg
STAT_SZiC
DOCYCLE
CMPC1: MEM_PreIndx ;CMP ($06,X)
addq.l #6,Cycles
GETBYTE
cmp.b d0,AReg
STAT_SZiC
DOCYCLE
CMPD1: MEM_PostIndx ;CMP ($06),Y
addq.l #5,Cycles
GETBYTE
cmp.b d0,AReg
STAT_SZiC
DOCYCLE
CMPD9: MEM_AbsIndxY ;CMP $1234,Y
addq.l #4,Cycles
GETBYTE
cmp.b d0,AReg
STAT_SZiC
DOCYCLE
CMPDD: MEM_AbsIndxX ;CMP $1234,X
addq.l #4,Cycles
GETBYTE
cmp.b d0,AReg
STAT_SZiC
DOCYCLE
CMPC9: ;MEM_Immed - CMP #$06
cmp.b d1,AReg
STAT_SZiC
addq.l #2,Cycles
DOCYCLE
CMPD5: MEM_ZPIndxX ;CMP $06,X
addq.l #4,Cycles
cmp.b (Mem_Ptr,d0.l),AReg
STAT_SZiC
DOCYCLE
CMPC5: MEM_ZP ;CMP $06
addq.l #3,Cycles
cmp.b (Mem_Ptr,d0.l),AReg
STAT_SZiC
DOCYCLE
*-------------------------- CPX ------------------------------------*
CPXEC: MEM_Abs ;CPX $1234
addq.l #4,Cycles
GETBYTE ;read mem, subtract from XReg, set SZC
cmp.b d0,XReg
STAT_SZiC
DOCYCLE
CPXE4: MEM_ZP ;CPX $06
cmp.b (Mem_Ptr,d0.l),XReg
STAT_SZiC
addq.l #3,Cycles
DOCYCLE
CPXE0: cmp.b d1,XReg ;MEM_Immed - CPX #$06
STAT_SZiC
addq.l #2,Cycles
DOCYCLE
*--------------------------- CPY -----------------------------------*
CPYCC: MEM_Abs ;CPY $1234
addq.l #4,Cycles
GETBYTE ;read mem, subtract from YReg, set SZC
cmp.b d0,YReg
STAT_SZiC
DOCYCLE
CPYC4: MEM_ZP ;CPY $06
cmp.b (Mem_Ptr,d0.l),YReg
STAT_SZiC
addq.l #3,Cycles
DOCYCLE
CPYC0: ;MEM_Immed - CPY #$06
cmp.b d1,YReg
STAT_SZiC
addq.l #2,Cycles
DOCYCLE
*--------------------------- DEC -----------------------------------*
DECCE: MEM_Abs ;DEC $1234
addq.l #6,Cycles
move.b (Mem_Ptr,d0.l),d1 ;fast read now, i/o check at write! (IMPerfect!)
subq.b #1,d1 ;DEC memory by 1, set SZ
STAT_SZ
PUTBYTE ;d0 still there?
DOCYCLE
DECDE: MEM_AbsIndxX ;DEX $1234,X
addq.l #7,Cycles
move.b (Mem_Ptr,d0.l),d1
subq.b #1,d1
STAT_SZ
PUTBYTE
DOCYCLE
DECD6: MEM_ZPIndxX ;DEC $06,X
addq.l #6,Cycles
subq.b #1,(Mem_Ptr,d0.l)
STAT_SZ
DOCYCLE
DECC6: MEM_ZP ;DEC $06
addq.l #5,Cycles
subq.b #1,(Mem_Ptr,d0.l)
STAT_SZ
DOCYCLE
*------------------------ DEX/DEY ----------------------------------*
CNOP 0,4
DEXCA: subq.b #1,XReg [03] ;DEX - Decrement XReg by 1
STAT_SZ [04] ?
subq.w #1,PCount [03]
addq.l #2,Cycles [03]
DOCYCLE [25]=38
CNOP 0,4
DEY88: subq.b #1,YReg ;DEY - Decrement YReg by 1
STAT_SZ
subq.w #1,PCount
addq.l #2,Cycles
DOCYCLE
*-------------------------- EOR ------------------------------------*
EOR4D: MEM_Abs ;EOR $1234
addq.l #4,Cycles
GETBYTE
eor.b d0,AReg
STAT_SZ
DOCYCLE
EOR51: MEM_PostIndx ;EOR ($06),Y
addq.l #5,Cycles
GETBYTE
eor.b d0,AReg
STAT_SZ
DOCYCLE
EOR59: MEM_AbsIndxY ;EOR $1234,Y
addq.l #4,Cycles
GETBYTE
eor.b d0,AReg
STAT_SZ
DOCYCLE
EOR5D: MEM_AbsIndxX ;EOR $1234,X
addq.l #4,Cycles
GETBYTE
eor.b d0,AReg
STAT_SZ
DOCYCLE
EOR41: MEM_PreIndx ;EOR ($06,X)
addq.l #6,Cycles
GETBYTE
eor.b d0,AReg
STAT_SZ
DOCYCLE
EOR49: ;MEM_Immed - EOR #$06
addq.l #2,Cycles
eor.b d1,AReg
STAT_SZ
DOCYCLE
EOR45: MEM_ZP ;EOR $06
addq.l #3,Cycles
move.b (Mem_Ptr,d0.l),d0
eor.b d0,AReg
STAT_SZ
DOCYCLE
EOR55: MEM_ZPIndxX ;EOR $06,X
addq.l #4,Cycles
move.b (Mem_Ptr,d0.l),d0
eor.b d0,AReg
STAT_SZ
DOCYCLE
*-------------------------- INC ------------------------------------*
INCEE: MEM_Abs ;INC $1234
addq.l #6,Cycles
move.b (Mem_Ptr,d0.l),d1 ;INC memory by 1, set SZ
addq.b #1,d1
STAT_SZ
PUTBYTE ;d0 still there?
DOCYCLE
INCFE: MEM_AbsIndxX ;INC $1234,X
addq.l #7,Cycles
move.b (Mem_Ptr,d0.l),d1
addq.b #1,d1
STAT_SZ
PUTBYTE ;d0 still there?
DOCYCLE
INCE6: MEM_ZP ;INC $06
addq.l #5,Cycles
addq.b #1,(Mem_Ptr,d0.l)
STAT_SZ
DOCYCLE
INCF6: MEM_ZPIndxX ;INC $06,X
addq.l #6,Cycles
addq.b #1,(Mem_Ptr,d0.l)
STAT_SZ
DOCYCLE
*----------------------- INX / INY ---------------------------------*
INXE8: subq.w #1,PCount
addq.b #1,XReg ;INX - Increment XReg by 1
STAT_SZ
addq.l #2,Cycles
DOCYCLE
INYC8: subq.w #1,PCount
addq.b #1,YReg ;INY - Increment YReg by 1
STAT_SZ
addq.l #2,Cycles
DOCYCLE
*------------------------ JSR / JMP --------------------------------*
JMP4CReg:
move.l d1,a6
REGULATE
move.l a6,d1
JMP4C: ;JMP $xxxx ;MEM_Abs -> PCount (clean!)
MEM_Abs
lea (Mem_Ptr,d0.l),PCount
addq.l #3,Cycles
DOCYCLE
JSR20: move.l PCount,d0 ;JSR $1234 (only type)
sub.l Mem_Ptr,d0
PUSH16
move.w -1(PCount),d0 ; FGETWORD1PC -> d0
ror.w #8,d0 ; ""
lea (Mem_Ptr,d0.l),PCount
addq.l #6,Cycles
DOCYCLE
JMP6C: ;JMP($xxxx)
; FGETWORD1PC ; Mem_Indirect ($xxxx) for JMP only
move.w -1(PCount),d0 ;FGETWORD1PC -> D0
ror.w #8,d0
move.w (Mem_Ptr,d0.l),d0 ;FGETWORDd0 -> PCount
ror.w #8,d0
lea (Mem_Ptr,d0.l),PCount
addq.l #5,Cycles
DOCYCLE
*--------------------------- LDA -----------------------------------*
LDAAD: MEM_Abs ;LDA $1234
addq.l #4,Cycles
GETBYTE ;read mem into Acc...
move.b d0,AReg
STAT_SZ
DOCYCLE
LDAA1: MEM_PreIndx ;LDA ($06,X)
addq.l #6,Cycles
GETBYTE ;read mem into Acc...
move.b d0,AReg
STAT_SZ
DOCYCLE
LDAB1: MEM_PostIndx ;LDA ($06),Y
addq.l #5,Cycles
GETBYTE ;read mem into Acc...
move.b d0,AReg
STAT_SZ
DOCYCLE
LDAB9: MEM_AbsIndxY ;LDA $1234,Y
addq.l #4,Cycles
GETBYTE ;read mem into Acc...
move.b d0,AReg
STAT_SZ
DOCYCLE
LDABD: MEM_AbsIndxX ;LDA $1234,X
addq.l #4,Cycles
GETBYTE ;read mem into Acc...
move.b d0,AReg
STAT_SZ
DOCYCLE
LDAA9: ;MEM_Immed - LDA #$06
addq.l #2,Cycles
move.b d1,AReg
STAT_SZ
DOCYCLE
LDAB5: MEM_ZPIndxX ;LDA $06,X
addq.l #4,Cycles
move.b (Mem_Ptr,d0.l),AReg
STAT_SZ
DOCYCLE
LDAA5: MEM_ZP ;LDA $06
addq.l #3,Cycles
move.b (Mem_Ptr,d0.l),AReg
STAT_SZ
DOCYCLE
*-------------------------- LDX ------------------------------------*
LDXAE: MEM_Abs ;LDX $1234
addq.l #4,Cycles
GETBYTE ;read mem into XReg
move.b d0,XReg
STAT_SZ
DOCYCLE
LDXBE: MEM_AbsIndxY ;LDX $1234,Y
addq.l #4,Cycles
GETBYTE
move.b d0,XReg
STAT_SZ
DOCYCLE
LDXA2: ;MEM_Immed - LDX #$06
addq.l #2,Cycles
move.b d1,XReg
STAT_SZ
DOCYCLE
LDXA6: MEM_ZP ;LDX $06
addq.l #3,Cycles
move.b (Mem_Ptr,d0.l),XReg
STAT_SZ
DOCYCLE
LDXB6: MEM_ZPIndxY ;LDX $06,Y
addq.l #4,Cycles
move.b (Mem_Ptr,d0.l),XReg
STAT_SZ
DOCYCLE
*------------------------- LDY -------------------------------------*
LDYAC: MEM_Abs ;LDY $1234
addq.l #4,Cycles
GETBYTE ;read mem into YReg..
move.b d0,YReg
STAT_SZ
DOCYCLE
LDYBC: MEM_AbsIndxX ;LDY $1234,X
addq.l #4,Cycles
GETBYTE
move.b d0,YReg
STAT_SZ
DOCYCLE
LDYA0: ;MEM_Immed - LDY #$06
addq.l #2,Cycles
move.b d1,YReg
STAT_SZ
DOCYCLE
LDYA4: MEM_ZP ;LDY $06
addq.l #3,Cycles
move.b (Mem_Ptr,d0.l),YReg
STAT_SZ
DOCYCLE
LDYB4: MEM_ZPIndxX ;LDY $06,X
addq.l #4,Cycles
move.b (Mem_Ptr,d0.l),YReg
STAT_SZ
DOCYCLE
*------------------------- LSR -------------------------------------*
LSR4E: MEM_Abs ;LSR $1234
addq.l #6,Cycles
move.w d0,-(sp)
GETBYTE ;must do long read in case of PDL, DISK, etc...
move.b d0,d1
lsr.b #1,d1
STAT_SZC
move.w (sp)+,d0
PUTBYTE_DOCYCLE
LSR5E: MEM_AbsIndxX ;LSR $1234,X
addq.l #7,Cycles
move.w d0,-(sp)
GETBYTE ;must do long read in case of PDL, DISK, etc...
move.b d0,d1
lsr.b #1,d1
STAT_SZC
move.w (sp)+,d0
PUTBYTE_DOCYCLE
LSR4A: subq.w #1,PCount
lsr.b #1,AReg ;LSR Acc
STAT_SZC
addq.l #2,Cycles
DOCYCLE
LSR46: MEM_ZP ;LSR $06
move.b (Mem_Ptr,d0.l),d1
lsr.b #1,d1
STAT_SZC
move.b d1,(Mem_Ptr,d0.l)
addq.l #5,Cycles
DOCYCLE
LSR56: MEM_ZPIndxX ;LSR $06,X
move.b (Mem_Ptr,d0.l),d1
lsr.b #1,d1
STAT_SZC
move.b d1,(Mem_Ptr,d0.l)
addq.l #6,Cycles
DOCYCLE
dc.b "This program is Copyright 1994 by Kevin Kralian",0
EVEN
*--------------------------------------------------------------------*
NOPEA: subq.w #1,PCount
addq.l #2,Cycles
DOCYCLE ;NOP - Do nothing! time waster
*-------------------------- ORA -------------------------------------*
ORA0D: MEM_Abs ;ORA $1234
addq.l #4,Cycles
GETBYTE
or.b d0,AReg
STAT_SZ
DOCYCLE
ORA01: MEM_PreIndx ;ORA ($20,X)
addq.l #6,Cycles
GETBYTE
or.b d0,AReg
STAT_SZ
DOCYCLE
ORA19: MEM_AbsIndxY ;ORA $1234,Y
addq.l #4,Cycles
GETBYTE
or.b d0,AReg
STAT_SZ
DOCYCLE
ORA1D: MEM_AbsIndxX ;ORA $1234,X
addq.l #4,Cycles
GETBYTE
or.b d0,AReg
STAT_SZ
DOCYCLE
ORA11: MEM_PostIndx ;ORA ($06),Y
addq.l #5,Cycles
GETBYTE
or.b d0,AReg
STAT_SZ
DOCYCLE
ORA09: ;MEM_Immed - ORA #$20
addq.l #2,Cycles
or.b d1,AReg
STAT_SZ
DOCYCLE
ORA05: MEM_ZP ;ORA $20
addq.l #3,Cycles
or.b (Mem_Ptr,d0.l),AReg
STAT_SZ
DOCYCLE
ORA15: MEM_ZPIndxX ;ORA $06,X
addq.l #4,Cycles
or.b (Mem_Ptr,d0.l),AReg
STAT_SZ
DOCYCLE
*-------------------------- PHP ------------------------------------*
PHA48: PUSH AReg ;PHA - Push AReg
subq.w #1,PCount
addq.l #3,Cycles
DOCYCLE
PHP08: PUSHSTAT ;PHP
subq.w #1,PCount
addq.l #3,Cycles
DOCYCLE
*---------------------- PLA / PLP ----------------------------------*
PLA68: addq.l #4,Cycles
PULL AReg ;PLA - Pull Accum from stack
tst.b AReg
STAT_SZ
subq.w #1,PCount
DOCYCLE
PLP28: addq.l #4,Cycles
PULLSTAT ;PLP
subq.w #1,PCount
DOCYCLE
*-------------------------- ROL (through Carry)----(Status Dependant)---------------*
ROL2E: MEM_Abs ;ROL $1234
addq.l #6,Cycles
.rol move.w d0,-(sp)
GETBYTE
move.b d0,d1 ;needs to be there for PUTBYTE anyways...
lsl.b d1 [04] ;shift it
lsr.b #C_BIT,StatusCV [04] ;and add in carry bit...
add.b StatusCV,d1 [03]
STAT_SZ [06] ;and get SZ flags... (faster than ROXL)
move.b d0,StatusCV [03] ;get Carry Flag
move.w (sp)+,d0
PUTBYTE_DOCYCLE
ROL3E: MEM_AbsIndxX ;ROL $1234,X
addq.l #7,Cycles
.rol move.w d0,-(sp)
GETBYTE
move.b d0,d1
lsl.b d1
lsr.b #C_BIT,StatusCV
add.b StatusCV,d1
STAT_SZ
move.b d0,StatusCV
move.w (sp)+,d0
PUTBYTE_DOCYCLE
ROL26: MEM_ZP ;ROL $06
addq.l #5,Cycles
.rol move.b (Mem_Ptr,d0.l),d1 ;FGETBYTE
lsr.b #C_BIT+1,StatusCV
roxl.b #1,d1
STAT_SZC
move.b d1,(Mem_Ptr,d0.l)
DOCYCLE
ROL36: MEM_ZPIndxX ;ROL $06,X
addq.l #6,Cycles
.rol move.b (Mem_Ptr,d0.l),d1 ;FGETBYTE
lsr.b #C_BIT+1,StatusCV
roxl.b #1,d1
STAT_SZC
move.b d1,(Mem_Ptr,d0.l)
DOCYCLE
CNOP 0,4
ROL2A: subq.w #1,PCount ;ROL Acc
addq.l #2,Cycles
lsr.b #C_BIT+1,StatusCV [04]
roxl.b #1,AReg [12]
STAT_SZC [10] 26
DOCYCLE
*-------------------------- ROR (through Carry)------------------------*
ROR6E: MEM_Abs ;ROR $2134
addq.l #6,Cycles
.ror move.w d0,-(sp)
GETBYTE
move.b d0,d1 ;needs to be there for PUTBYTE anyways...
lsr.b #C_BIT+1,StatusCV ;Sets/Clrs Extend (X) flag based on C
roxr.b #1,d1 ;(this always clears V in CCR)
STAT_SZC
move.w (sp)+,d0
PUTBYTE_DOCYCLE
ROR66: MEM_ZP ;ROR $06
addq.l #5,Cycles
.ror move.b (Mem_Ptr,d0.l),d1
lsr.b #C_BIT+1,StatusCV
roxr.b #1,d1
STAT_SZC
move.b d1,(Mem_Ptr,d0.l)
DOCYCLE
ROR76: MEM_ZPIndxX ;ROR $06,X
addq.l #6,Cycles
.ror move.b (Mem_Ptr,d0.l),d1
lsr.b #C_BIT+1,StatusCV
roxr.b #1,d1
STAT_SZC
move.b d1,(Mem_Ptr,d0.l)
DOCYCLE
ROR7E: MEM_AbsIndxX ;ROR $1234,X
addq.l #7,Cycles
.ror move.w d0,-(sp)
GETBYTE
move.b d0,d1
lsr.b #C_BIT+1,StatusCV
roxr.b #1,d1
STAT_SZC
move.w (sp)+,d0
PUTBYTE_DOCYCLE
CNOP 0,4
ROR6A: subq.w #1,PCount ;ROR ACC
lsr.b #C_BIT+1,StatusCV
roxr.b #1,AReg
STAT_SZC
addq.l #2,Cycles
DOCYCLE
*---------------------- RTI / RTS -----------------------------------*
RTI40: addq.l #7,Cycles
PULLSTAT ;RTI - Return From Intrpt
PULL16
lea (Mem_Ptr,d0.l),PCount
DOCYCLE
RTS60: PULL16 ;RTS - Return from Subroutine
lea 1(Mem_Ptr,d0.l),PCount
addq.l #6,Cycles
DOCYCLE
*------------------------- SBC -------------------------------------* STATUS DEPENDANT!!!
SBCE5: MEM_ZP ;SBC $06
addq.l #3,Cycles
GETBYTE
eor.b #C_HEX,StatusCV [06] ;for subtraction, C flag works backwards
btst.l #D_BIT,StatusSZ [05]
bne.b .bcd [05]
.dec lsr.b #8,StatusCV [04] ;Sets/Clrs X flag based on C & Sets Z Flag
subx.b d0,AReg [03] ; SUBX - Z flag only cleared, not set!
STAT_SVZiC
DOCYCLE
.bcd lsr.b #8,StatusCV ;Sets/Clrs X flag based on C & Sets Z Flag
sbcd.b d0,AReg ;SBCD - Z flag only cleared, not set!
STAT_SZiC ;manual says Z not set. Is V???
DOCYCLE
SBCE1: MEM_PreIndx ;SBC ($06,X)
addq.l #6,Cycles
GETBYTE
eor.b #C_HEX,StatusCV
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
subx.b d0,AReg
STAT_SVZiC
DOCYCLE
.bcd lsr.b #8,StatusCV
sbcd.b d0,AReg
STAT_SZiC
DOCYCLE
SBCED: MEM_Abs ;SBC $1234
addq.l #4,Cycles
GETBYTE
eor.b #C_HEX,StatusCV
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
subx.b d0,AReg
STAT_SVZiC
DOCYCLE
.bcd lsr.b #8,StatusCV
sbcd.b d0,AReg
STAT_SZiC
DOCYCLE
SBCF1: MEM_PostIndx ;SBC ($06),Y
addq.l #5,Cycles
GETBYTE
eor.b #C_HEX,StatusCV
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
subx.b d0,AReg
STAT_SVZiC
DOCYCLE
.bcd lsr.b #8,StatusCV
sbcd.b d0,AReg
STAT_SZiC
DOCYCLE
SBCF9: MEM_AbsIndxY ;SBC $1234,Y
addq.l #4,Cycles
GETBYTE
eor.b #C_HEX,StatusCV
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
subx.b d0,AReg
STAT_SVZiC
DOCYCLE
.bcd lsr.b #8,StatusCV
sbcd.b d0,AReg
STAT_SZiC
DOCYCLE
SBCFD: MEM_AbsIndxX ;SBC $1234,X
addq.l #4,Cycles
GETBYTE
eor.b #C_HEX,StatusCV
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
subx.b d0,AReg
STAT_SVZiC
DOCYCLE
.bcd lsr.b #8,StatusCV
sbcd.b d0,AReg
STAT_SZiC
DOCYCLE
SBCE9: ;MEM_Immed - SBC #$06
addq.l #2,Cycles
move.b d1,d0
eor.b #C_HEX,StatusCV
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
subx.b d0,AReg
STAT_SVZiC
DOCYCLE
.bcd lsr.b #8,StatusCV
sbcd.b d0,AReg
STAT_SZiC
DOCYCLE
SBCF5: MEM_ZPIndxX ;SBC $06,X
addq.l #4,Cycles
move.b (Mem_Ptr,d0.l),d0
eor.b #C_HEX,StatusCV
btst.l #D_BIT,StatusSZ
bne.b .bcd
.dec lsr.b #8,StatusCV
subx.b d0,AReg
STAT_SVZiC
DOCYCLE
.bcd lsr.b #8,StatusCV
sbcd.b d0,AReg
STAT_SZiC
DOCYCLE
*-------------------- SET STATUS BITS ------------------------------*
SEI78: subq.w #1,PCount
bset.l #I_BIT,StatusSZ ;SEI - Set Interrupt Mask (disable intrps)
addq.l #2,Cycles
DOCYCLE
SEDF8: subq.w #1,PCount
bset.l #D_BIT,StatusSZ ;SED - Set Decimal mode (D=1)
addq.l #2,Cycles
DOCYCLE
SEC38: subq.w #1,PCount
bset.l #C_BIT,StatusCV ;SEC - Set Carry (C=1)
addq.l #2,Cycles
DOCYCLE
*-------------------------- STA ------------------------------------*
STA81: MEM_PreIndx ;STA ($06,X)
addq.l #6,Cycles
move.b AReg,d1
PUTBYTE_DOCYCLE
STA8D<