.TITLE 6502 Simulator ; Y6502 - 6502 Microprocessor simulator ; ; Copyright Peter Coghlan 1996 ; ; Y6502_Execute - This module contains the 6502 instruction interpreter ; and miscellaneous support routines to enable external routines to read ; and write the 6502 memory and to support instruction profiling. ; ; Register usage : ; ; R0 Temporary / Addressbus as returned by AddressModes routines ; R1 Temporary ; R2 Temporary ; R3 Current opcode / temporary ; R4 Current instruction address for Trace and Invalid opcode calls ; R5 Unused ; R6 6502 Accumulator ; R7 6502 X Index Register ; R8 6502 Y Index Register ; R9 6502 P Processor Status Register plus emulation flags ; R10 6502 PC Program Counter ; R11 6502 SP Stack pointer ; 6502 memory - 64Kb - Set up as a common block in case required. .Psect Y6502_Memory, Quad, Pic, Ovr, Gbl, Rel, Shr, Rd, Wrt, Noexe Memory: .Blkb 65536 ; Common block / Arguments for calls to various routines. .Psect Y6502_Registers, Quad, Pic, Ovr, Gbl, Rel, Shr, Rd, Wrt, Noexe .Align Quad ProgramCounter: .Long 0 Accumulator: .Long 0 Xregister: .Long 0 Yregister: .Long 0 ProcessorStatus: .Long 0 StackPointer: .Long 0 Flags: AddressBus: .Long 0 ; Traps for Operating System and I/O emulation .Psect Y6502_Traps, Quad, Pic, Ovr, Gbl, Rel, Shr, Rd, Wrt, Noexe .Align Quad ExecuteTrap: .Long 0 DataTrap: .Long 0 ; Counters for instruction profiling .If Df, Y6502_Instruction_Profile .Psect Y6502_Counters, Quad, Pic, Ovr, Gbl, Rel, Shr, Rd, Wrt, Noexe .Align Quad Counter: .Blkl 256 .Endc ; Other miscellaneous writeable data structures .Psect Y6502_Data, Long, Noexe, Noshr, Rd, Wrt .Align Long TraceRoutine: .Address Y6502_Return TrapRoutine: .Address Y6502_Return InvalidRoutine: .Address Y6502_Return ; Constant data structures .Psect Y6502_Constants, Long, Noexe, Shr, Rd, Nowrt .Align Long ; Addresses of argument list for calls to various routines Arguments: .Long 7 .Address ProgramCounter .Address Accumulator .Address Xregister .Address Yregister .Address ProcessorStatus .Address StackPointer .Address Flags ; or AddressBus as the case may be ; Addresses of routines implementing 6502 instructions .Align Long Instructions: .Address BRK, ORA, Op02, Op03, Op04, ORA, ASL, Op07 .Address PHP, ORA, ASLA, Op0B, Op0c, ORA, ASL, Op0F .Address BPL, ORA, Op02, Op03, Op04, ORA, ASL, Op07 .Address CLC, ORA, Op0A, Op0B, Op0C, ORA, ASL, Op0F .Address JSR, AND, Op02, Op03, BIT, AND, ROL, Op07 .Address PLP, AND, ROLA, Op0B, BIT, AND, ROL, Op0F .Address BMI, AND, Op02, Op03, Op04, AND, ROL, Op07 .Address SEC, AND, Op0A, Op0B, Op0C, AND, ROL, Op0F .Address RTI, EOR, Op02, Op03, Op04, EOR, LSR, Op07 .Address PHA, EOR, LSRA, Op0B, JMP, EOR, LSR, Op0F .Address BVC, EOR, Op02, Op03, Op04, EOR, LSR, Op07 .Address CLI, EOR, Op0A, Op0B, Op0C, EOR, LSR, Op0F .Address RTS, ADC, Op02, Op03, Op04, ADC, ROR, Op07 .Address PLA, ADC, RORA, Op0B, JMPi, ADC, ROR, Op0F .Address BVS, ADC, Op02, Op03, Op04, ADC, ROR, Op07 .Address SEI, ADC, Op0A, Op0B, Op0C, ADC, ROR, Op0F .Address Op80, STA, Op02, Op03, STY, STA, STX, Op07 .Address DEY, Op89, TXA, Op0B, STY, STA, STX, Op0F .Address BCC, STA, Op02, Op03, STY, STA, STX, Op07 .Address TYA, STA, TXS, Op0B, Op0C, STA, Op9E, Op0F .Address LDY, LDA, LDX, Op03, LDY, LDA, LDX, Op07 .Address TAY, LDA, TAX, Op0B, LDY, LDA, LDX, Op0F .Address BCS, LDA, Op02, Op03, LDY, LDA, LDX, Op07 .Address CLV, LDA, TSX, Op0B, LDY, LDA, LDX, Op0F .Address CPY, CMP, Op02, Op03, CPY, CMP, DEC, Op07 .Address INY, CMP, DEX, Op0B, CPY, CMP, DEC, Op0F .Address BNE, CMP, Op02, Op03, Op04, CMP, DEC, Op07 .Address CLD, CMP, Op0A, Op0B, Op0C, CMP, DEC, Op0F .Address CPX, SBC, Op02, Op03, CPX, SBC, INC, Op07 .Address INX, SBC, NOP, Op0B, CPX, SBC, INC, Op0F .Address BEQ, SBC, Op02, Op03, Op04, SBC, INC, Op07 .Address SED, SBC, Op0A, Op0B, Op0C, SBC, INC, Op0F ; Addresses of address mode processing routines - one for each opcode AddressModes: .Address Null, IndIndX, Null, Null, ZeroPg, ZeroPg, ZeroPg, Null .Address Null, Immed, Null, Null, Abs, Abs, Abs, Null .Address Null, IndIndY, Null, Null, ZeroPg, ZeroPgX, ZeroPgX, Null .Address Null, AbsY, Null, Null, Abs, AbsX, AbsX, Null .Address Null, IndIndX, Null, Null, ZeroPg, ZeroPg, ZeroPg, Null .Address Null, Immed, Null, Null, Abs, Abs, Abs, Null .Address Null, IndIndY, Null, Null, ZeroPgX, ZeroPgX, ZeroPgX, Null .Address Null, AbsY, Null, Null, AbsX, AbsX, AbsX, Null .Address Null, IndIndX, Null, Null, ZeroPg, ZeroPg, ZeroPg, Null .Address Null, Immed, Null, Null, Abs, Abs, Abs, Null .Address Null, IndIndY, Null, Null, ZeroPgX, ZeroPgX, ZeroPgX, Null .Address Null, AbsY, Null, Null, AbsX, AbsX, AbsX, Null .Address Null, IndIndX, Null, Null, ZeroPg, ZeroPg, ZeroPg, Null .Address Null, Immed, Null, Null, Null, Abs, Abs, Null .Address Null, IndIndY, Null, Null, ZeroPgX, ZeroPgX, ZeroPgX, Null .Address Null, AbsY, Null, Null, Null, AbsX, AbsX, Null .Address Null, IndIndX, Null, Null, ZeroPg, ZeroPg, ZeroPg, Null .Address Null, Immed, Null, Null, Abs, Abs, Abs, Null .Address Null, IndIndY, Null, Null, ZeroPgX, ZeroPgX, ZeroPgY, Null .Address Null, AbsY, Null, Null, Abs, AbsX, AbsX, Null .Address Immed, IndIndX, Immed, Null, ZeroPg, ZeroPg, ZeroPg, Null .Address Null, Immed, Null, Null, Abs, Abs, Abs, Null .Address Null, IndIndY, Null, Null, ZeroPgX, ZeroPgX, ZeroPgY, Null .Address Null, AbsY, Null, Null, AbsX, AbsX, AbsY, Null .Address Immed, IndIndX, Null, Null, ZeroPg, ZeroPg, ZeroPg, Null .Address Null, Immed, Null, Null, Abs, Abs, Abs, Null .Address Null, IndIndY, Null, Null, ZeroPgX, ZeroPgX, ZeroPgX, Null .Address Null, AbsY, Null, Null, AbsX, AbsX, AbsX, Null .Address Immed, IndIndX, Null, Null, ZeroPg, ZeroPg, ZeroPg, Null .Address Null, Immed, Null, Null, Abs, Abs, Abs, Null .Address Null, IndIndY, Null, Null, ZeroPgX, ZeroPgX, ZeroPgX, Null .Address Null, AbsY, Null, Null, AbsX, AbsX, AbsX, Null ; Executable code and macros .Psect Y6502_Code, Long, Exe, Shr, Rd, Nowrt .MACRO PushPc ; Push Program Counter onto 6502 stack ASHL #-8,R10,R1 ; Get high byte of Program Counter MOVB R1,Memory+^X100(R11) ; Push it on the stack DECB R11 ; Decrement Stack Pointer MOVB R10,Memory+^X100(R11) ; Push low byte of Program Counter DECB R11 ; Decrement Stack Pointer .ENDM PushPc .MACRO PullPc ; Pop Program Counter from 6502 stack INCB R11 ; Increment Stack Pointer MOVZBL Memory+^X100(R11),R10 ; Pop low byte of Program Counter INCB R11 ; Increment Stack Pointer INSV Memory+^X100(R11),#8,#8,R10 ; Pop high byte of Program Cntr .ENDM PullPc .MACRO PackP ; Convert P to 6502 format for stack etc ASHL #-10,R9,R1 ; Extract VAX N and Z from R9 b11 & b10 INSV R1,#1,#1,R9 ; Insert Z at bit 1 ASHL #-1,R1,R1 ; Shift N to bit 0 INSV R1,#7,#1,R9 ; Insert N at bit 7 BISB2 #^B00100000,R9 ; Ensure bit 5 is set .ENDM PackP .MACRO UnPackP ; Convert P from 6502 format to internal CVTBW R9,R9 ; Extend N (bit 7) across bit 11 INSV R9,#9,#2,R9 ; Insert Z at bit 10 (Also C at bit 9) .ENDM UnPackP ; The real code begins here .ENTRY Y6502_Execute,^M ; Set everything to defaults CLRL R4 ; Clear saved PC CLRQ R6 ; Clear A and X CLRQ R8 ; Clear Y and P CLRL R11 ; Clear SP MOVZWL Memory+^XFFFC,R10 ; Load PC with contents of reset vector ; Get arguments and use any provided to override defaults CASEB (AP),#0,#11 ; Act based on number of arguments 0$: .Word NoPC-0$, NoA-0$, NoX-0$, NoY-0$, NoPSR-0$, NoSP-0$, NoFlags-0$ .Word NoPage-0$, NoTrap-0$, NoTrace-0$, NoInvalid-0$, Everything-0$ MOVL #SS$_OvrMaxArg,R0 ; Too many arguments - give up RET Everything: MOVL 44(AP),R0 ; Check for Invalid opcode routine BEQL NoInvalid MOVL R0,InvalidRoutine ; Grab address of routine NoInvalid: MOVL 40(AP),R0 ; Check for Trace routine address BEQL NoTrace MOVL R0,TraceRoutine ; Grab address of trace routine NoTrace: MOVL 36(AP),R0 ; Check for Trap routine address BEQL NoTrap MOVL R0,TrapRoutine ; Grab the address NoTrap: MOVL 32(AP),R0 ; Check for trap page BEQL NoPage MOVB (R0),ExecuteTrap ; Grab trap page NoPage: MOVL 28(AP),R0 ; Check if flags were supplied BEQL NoFlags INSV (R0),#24,#8,R9 ; Grab flags NoFlags: MOVL 24(AP),R0 ; Check if SP was supplied BEQL NOSP MOVB (R0),R11 ; Grab SP NoSP: MOVL 20(AP),R0 ; Check if P was supplied BEQL NoPSR MOVB (R0),R9 ; Grab P NoPSR: MOVL 16(AP),R0 ; Check if Y was supplied BEQL NoY MOVB (R0),R8 ; Grab Y NoY: MOVL 12(AP),R0 ; Check if X was supplied BEQL NoX MOVB (R0),R7 ; Grab X NoX: MOVL 8(AP),R0 ; Check if A was supplied BEQL NoA MOVB (R0),R6 ; Grab A NoA: MOVL 4(AP),R0 ; Check if PC was supplied BEQL NoPC MOVW (R0),R10 ; Grab PC NoPC: BRB Loop ; Skip over alignment ; Main loop .Align Long Loop: MOVW R10,R4 ; Retain address of current instruction MOVZBL Memory(R10),R3 ; Get next Opcode INCW R10 ; Increment PC .If Df, Y6502_Instruction_Profile INCL Counter[R3] ; Do instruction profiling .Endc ASHL #2,R3,R3 ; Multiply by 4 for JMP JMP @Instructions(R3) ; Execute appropriate opcode routine .Align Long SetFlags: ; Return here to set N and Z flags MOVPSL R1 ; Get VAX flags from last operation INSV R1,#8,#4,R9 ; Save NZCV into R9 (Only N and Z used) OpDone: ; Return here after executing opcode Nop: ; Call external routine to print trace listing if required BBC #31,R9,Loop ; Check if trace listing required ; Provide registers and general information to trace routine MOVW R4,ProgramCounter ; Original contents of Program Counter MOVB R6,Accumulator ; Current contents of Accumulator MOVB R7,Xregister ; Current contents of X Register MOVB R8,Yregister ; Current contents of Y Register PackP MOVB R9,ProcessorStatus ; Current Processor Status Register MOVB R11,StackPointer ; Current contents of Stack Pointer MOVW R0,AddressBus ; Value on address bus CALLG Arguments,@TraceRoutine ; Call external trace routine BRW Loop ; Come here to check if a new assignment to the program counter ; is valid. Used to trap execution of certain addresses to enable ; I/O or Operating System emulation to be done. .Align Long CheckPc: CMPZV #8,#8,R10,ExecuteTrap ; Compare MSB of PC with the trap page BNEQ OpDone TSTB ExecuteTrap ; Make sure a trap is required BEQL OpDone ; Provide registers to trap routine MOVZWL R10,ProgramCounter ; Contents of (current) Program Counter MOVZBL R6,Accumulator ; Contents of Accumulator MOVZBL R7,Xregister ; Contents of X Register MOVZBL R8,Yregister ; Contents of Y Register PackP MOVZBL R9,ProcessorStatus ; Contents of Processor Status Register MOVZBL R11,StackPointer ; Contents of Stack Pointer EXTZV #24,#8,R9,Flags ; Emulation flags CALLG Arguments,@TrapRoutine ; Call the trap routine if specified ; Copy the registers back in case they have been changed MOVB Accumulator,R6 MOVB Xregister,R7 MOVB Yregister,R8 MOVB ProcessorStatus,R9 UnpackP MOVB StackPointer,R11 INSV Flags,#24,#8,R9 ; There should be a return address on the stack ... RTS to it. PullPc ; Pop program counter off stack INCW R10 ; Add one to Program Counter BRW OpDone ; Ignore the possibility of another trap ; The code that implements the actual opcodes starts here .Align Long BPL: Cvtbw Memory(R10),R0 ; Get the operand byte, extend sign Incw R10 ; Increment PC Bbc #11,R9,Branch ; Branch if N is clear Brw Opdone .Align Long BMI: Cvtbw Memory(R10),R0 ; Get the operand byte, extend sign Incw R10 ; Increment PC Bbs #11,R9,Branch ; Branch if N is set Brw Opdone .Align Long BVC: Cvtbw Memory(R10),R0 ; Get the operand byte, extend sign Incw R10 ; Increment PC Bbc #6,R9,Branch ; Branch if V is clear Brw Opdone .Align Long BVS: Cvtbw Memory(R10),R0 ; Get the operand byte, extend sign Incw R10 ; Increment PC Bbs #6,R9,Branch ; Branch if V is set Brw Opdone .Align Long Branch: ; Take the branch Addw R0,R10 ; Add the offset read to the PC Brw OpDone ; No check for traps on branch .Align Long BCC: Cvtbw Memory(R10),R0 ; Get the operand byte, extend sign Incw R10 ; Increment PC Blbc R9,Branch ; Branch if C is clear Brw Opdone .Align Long BCS: Cvtbw Memory(R10),R0 ; Get the operand byte, extend sign Incw R10 ; Increment PC Blbs R9,Branch ; Branch if C is set Brw Opdone .Align Long BNE: Cvtbw Memory(R10),R0 ; Get the operand byte, extend sign Incw R10 ; Increment PC Bbc #10,R9,Branch ; Branch if Z is clear Brw Opdone .Align Long BEQ: Cvtbw Memory(R10),R0 ; Get the operand byte, extend sign Incw R10 ; Increment PC Bbs #10,R9,Branch ; Branch if Z is set Brw Opdone .Align Long BRK: INCW R10 ; Increment PC as if a 2 byte inst BISB2 #^B00010000,R9 ; Set the BRK bit in P PushPc ; Push Program Counter onto stack PackP ; Fix up order of bits in P MOVB R9,Memory+^X100(R11) ; Push P onto stack DECB R11 ; Decrement Stack Pointer BISB2 #^B00000100,R9 ; Set interrupt mask bit in P MOVW Memory+^XFFFE,R10 ; Load PC from interrupt vector BRW CheckPc ; Check for trap .Align Long JSR: MOVZBL Memory(R10),R0 ; Get low byte of address INCW R10 ; Increment PC INSV Memory(R10),#8,#8,R0 ; Get high byte of address PushPc ; Push Program Counter onto stack MOVW R0,R10 ; Load Program Counter with new value BRW CheckPc ; Check for trap .Align Long RTI: INCB R11 ; Increment Stack Pointer MOVB Memory+^X100(R11),R9 ; Pop P off stack UnPackP PullPc ; Pop program counter off stack BRW CheckPc ; Check for trap .Align Long RTS: PullPc ; Pop program counter off stack INCW R10 ; Increment Program Counter BRW CheckPc ; Check for trap .Align Long LDY: JSB @AddressModes(R3) ; Get address of operand MOVB Memory(R0),R8 ; Load Y with required value BRW SetFlags .Align Long CPY: JSB @AddressModes(R3) ; Get address of operand MOVZBL Memory(R0),R1 ; Get the operand SUBW3 R1,R8,R2 ; Subtract items to be compared EXTZV #8,#1,R2,R3 ; Extract the new borrow bit BISB2 #1,R9 ; Set the carry flag XORB2 R3,R9 ; Form carry from the inverted borrow TSTB R2 ; Set up to test N, Z BRW SetFlags .Align Long CPX: JSB @AddressModes(R3) ; Get address of operand MOVZBL Memory(R0),R1 ; Get the operand SUBW3 R1,R7,R2 ; Subtract items to be compared EXTZV #8,#1,R2,R3 ; Extract the new borrow bit BISB2 #1,R9 ; Set the carry flag XORB2 R3,R9 ; Form carry from the inverted borrow TSTB R2 ; Set up to test N, Z BRW SetFlags ; ORA, AND, EOR, ADC, STA, LDA, CMP, SBC .Align Long ORA: JSB @AddressModes(R3) ; Get address of operand BISB2 Memory(R0),R6 ; OR A with operand BRW SetFlags .Align Long AND: JSB @AddressModes(R3) ; Get address of operand MCOMB Memory(R0),R2 ; Invert operand as required by BICB2 BICB2 R2,R6 ; Clear bits of A given by NOT operand BRW SetFlags .Align Long EOR: JSB @AddressModes(R3) ; Get address of operand XORB2 Memory(R0),R6 ; EOR A with operand BRW SetFlags .Align Long ADC: JSB @AddressModes(R3) ; Get address of operand MOVZBL Memory(R0),R1 ; Get operand EXTZV #0,#1,R9,R2 ; Get Carry flag, Clear top of R2 BBS #3,R9,ADCbcd ; Do BCD fixup etc if BCD is enabled ADDW2 R6,R2 ; Add A to C, interim result in R2 ADDW2 R1,R2 ; Add in Operand, final result in R2 XORB2 R1,R6 ; Find I = [Operand]b7 xor [A]b7 (in A) XORB3 R1,R2,R3 ; Find J = [Operand]b7 xor [Result]b7 BICB2 R6,R3 ; Find V = [^I and J]b7 ASHL #-7,R3,R3 ; Move V to bit 0 for INSV INSV R3,#6,#1,R9 ; Put new V flag into P ASHL #-8,R2,R3 ; Get new Carry flag INSV R3,#0,#1,R9 ; Put new Carry flag into P MOVB R2,R6 ; Move result to A, set up to test N,Z BRW SetFlags .Align Long ADCbcd: BICB3 #^B11110000,R6,R0 ; Get lower nibble of A BICB3 #^B11110000,R1,R3 ; Get lower nibble of operand ADDB2 R2,R3 ; Add A to C, interim result in R3 ADDB2 R0,R3 ; Add in operand, result in R3 ADDW2 R6,R2 ; Add A to C, interim result in R2 ADDW2 R1,R2 ; Add in Operand, final result in R2 CMPB R3,#10 ; Check for valid lower BCD digit BLSSU 10$ ADDW2 #^X0006,R2 ; Add an extra 6 to make it valid 10$: ; Do the N, Z and V flags now! XORB2 R1,R6 ; Find I = [Operand]b7 xor [A]b7 (in A) XORB3 R1,R2,R3 ; Find J = [Operand]b7 xor [Result]b7 BICB2 R6,R3 ; Find V = [^I and J]b7 ASHL #-7,R3,R3 ; Move V to bit 0 for INSV INSV R3,#6,#1,R9 ; Put new V flag into P TSTB R2 ; Set N and Z flags from result so far MOVPSL R1 ; Get VAX flags from last operation INSV R1,#8,#4,R9 ; Save NZCV into R9 (Only N and Z used) BICB2 #1,R9 ; Clear carry flag BICW3 #^X000F,R2,R3 ; Get upper nibble and any carry CMPW R3,#^X00A0 ; Check for valid BCD digit or carry BLSSU 20$ ADDW2 #^X0060,R2 ; Add an extra 6 to make it valid BISB2 #1,R9 ; Set carry flag 20$: MOVB R2,R6 ; Put the result back in A BRW OpDone .Align Long SBC: JSB @AddressModes(R3) ; Get address of operand CLRL R1 ; Clear top of R1 MCOMB Memory(R0),R1 ; Complement operand, then as for ADC EXTZV #0,#1,R9,R2 ; Get Carry flag, Clear top of R2 BBS #3,R9,ADCbcd ; Do BCD fixup etc if BCD is enabled ADDW2 R6,R2 ; Add A to C, interim result in R2 ADDW2 R1,R2 ; Add in Operand, final result in R2 ASHL #-8,R2,R3 ; Get new Carry flag INSV R3,#0,#1,R9 ; Put new Carry flag into P XORB2 R1,R6 ; Find I = [Operand]b7 xor [A]b7 (in A) XORB3 R1,R2,R3 ; Find J = [Operand]b7 xor [Result]b7 BICB2 R6,R3 ; Find V = [^I and J]b7 ASHL #-7,R3,R3 ; Move V to bit 0 for INSV INSV R3,#6,#1,R9 ; Put new V flag into P MOVB R2,R6 ; Move result to A, set up to test N,Z BRW SetFlags .Align Long STA: JSB @AddressModes(R3) ; Get address of operand MOVB R6,Memory(R0) ; Store A at location given by operand BRW OpDone .Align Long LDA: JSB @AddressModes(R3) ; Get address of operand MOVB Memory(R0),R6 ; Load A with byte in question BRW SetFlags .Align Long CMP: JSB @AddressModes(R3) ; Get address of operand MOVZBL Memory(R0),R1 ; Get the operand SUBW3 R1,R6,R2 ; Subtract items to be compared EXTZV #8,#1,R2,R3 ; Extract the new borrow bit BISB2 #1,R9 ; Set the carry flag XORB2 R3,R9 ; Form carry from the inverted borrow TSTB R2 ; Set up to test N, Z BRW SetFlags .Align Long PHP: PackP ; Fix up order of bits in P MOVB R9,Memory+^X100(R11) ; Push P onto stack DECB R11 ; Decrement Stack Pointer BRW OpDone .Align Long CLC: BICB2 #1,R9 ; Clear bit 0 of P BRW OpDone .Align Long PLP: INCB R11 ; Increment Stack Pointer MOVB Memory+^X100(R11),R9 ; Pull P off the stack UnPackP BRW OpDone .Align Long SEC: BISB2 #^B00000001,R9 ; Set bit 0 of P BRW OpDone .Align Long PHA: MOVB R6,Memory+^X100(R11) ; Push P onto stack DECB R11 ; Decrement stack pointer BRW OpDone .Align Long CLI: BICB2 #^B00000100,R9 ; Clear bit 2 of P BRW OpDone .Align Long PLA: INCB R11 ; Increment Stack Pointer MOVB Memory+^X100(R11),R6 ; Pull A off the stack BRW SetFlags .Align Long SEI: BISB2 #^B00000100,R9 ; Set bit 2 of P BRW OpDone .Align Long DEY: DECB R8 ; Decrement Y BRW SetFlags .Align Long TYA: MOVB R8,R6 ; Copy Y to A BRW SetFlags .Align Long TAY: MOVB R6,R8 ; Copy A to Y BRW SetFlags .Align Long CLV: BICB2 #^B01000000,R9 ; Clear bit 6 of P BRW OpDone .Align Long INY: INCB R8 ; Increment Y BRW SetFlags .Align Long CLD: BICB2 #^B00001000,R9 ; Clear bit 3 of P BRW OpDone .Align Long INX: INCB R7 ; Increment X BRW SetFlags .Align Long SED: BISB2 #^B00001000,R9 ; Set bit 3 of P BRW OpDone .Align Long JMP: MOVZBL Memory(R10),R0 ; Get low byte of operand INCW R10 ; Increment PC INSV Memory(R10),#8,#8,R0 ; Get high byte of operand MOVW R0,R10 ; Set PC to address obtained BRW CheckPc .Align Long JMPi: MOVZBL Memory(R10),R0 ; Get low byte of operand INCW R10 ; Increment PC INSV Memory(R10),#8,#8,R0 ; Get high byte of operand MOVB Memory(R0),R10 ; Read low byte of address into PC ; Can use INCB here to obtain the standard buggy 6502 behaviour. INCW R0 ; Point at high byte of address INSV Memory(R0),#8,#8,R10 ; Read high byte of address into PC BRW CheckPc .Align Long JMPindx: ; MOVZBL memory(R10),R0 ; Get low byte of operand ; INCW R10 ; Increment PC ; MOVB memory(R10),R2 ; Get high byte of operand ;; INCW R10 ; Increment PC ;; ASHL #8,R2,R2 ; Move up high byte by 8 bits ;; BISW2 R2,R0 ; Add in low byte ; INSV R2,#8,#8,R0 ; Insert high byte into R1 ; ADDW2 R7,R0 ; Add in X ; MOVB memory(R0),R10 ; Read low byte of address into PC ; INCW R0 ; Point at high byte of address ; MOVB memory(R0),R2 ; Read high byte of address ;; ASHL #8,R2,R2 ; Move up high byte by 8 bits ;; BISW2 R2,R10 ; Add in low byte ; INSV R2,#8,#8,R10 ; Insert high byte into PC ; ; BRW checkpc .Align Long ;BIT: ; JSB @AddressModes(R3) ; Get address of operand ; CVTBW Memory(R0),R1 ; Extend operand sign bit to cover b11 ; MCOMB R1,R2 ; Grab an inverted copy for BICB3 ; ; XORW2 R9,R1 ; Toggle with the old N and V (b11 & b6) ; BICW2 #^XF7BF,R1 ; Clear everything except N and V ; XORW2 R1,R9 ; Toggle out the old N and V ; ; BISW2 #^X0400,R9 ; Set Z bit ; BICB3 R2,R6,R1 ; AND operand with A, chuck result ; BEQL IsZero ; BICW2 #^X0400,R9 ; Clear the Z flag ;IsZero: ; BRW opdone ; BIT: JSB @AddressModes(R3) ; Get address of operand CVTBW Memory(R0),R1 ; Get operand. Copy sign to cover b11 BITB R1,R6 ; Do the AND part MOVPSL R2 ; Grab the VAX Z flag (b3) INSV R2,#8,#3,R9 ; Save ZCV into b8-10 of P (Only Z used) BICW2 #^X0840,R9 ; Clear N (b11) and V (b6) in P BICW2 #^XF7BF,R1 ; Mask off operand b11 (N) and b6 (V) XORW2 R1,R9 ; Toggle the relevant bits of P BRW opdone ;BIT: ; JSB @AddressModes(R3) ; Get address of operand ; MCOMB Memory(R0),R1 ; Invert the operand (for BICB3) ; ; BISW2 #^X0C40,R9 ; Set N (b11), Z (b10) and V (b6) ; CVTBW R1,R2 ; Copy operand sign bit to cover b11 ; BICW2 #^XF7BF,R2 ; Mask off all but b11 (N) and b6 (V) ; XORW2 R2,R9 ; Toggle the relevant bits of P ; ; BICB3 R1,R6,R2 ; AND operand with A, chuck result ; BEQL IsZero ; BICW2 #^X0400,R9 ; Clear the Z flag ;IsZero: ; BRW opdone ; ;BIT: ; JSB @AddressModes(R3) ; Get address of operand ; CVTBW Memory(R0),R1 ; Get operand. Copy sign to cover b11 ; ; BITB R1,R6 ; Do the AND part ; MOVPSL R2 ; Grab the VAX Z flag (b3) ; INSV R2,#8,#3,R1 ; Save ZCV into b8-10 (Only Z used) ; ; ASHL #-6,R1,R1 ; Shift operand b6 to b0 ; INSV R1,#6,#6,R9 ; Put N, Z, V into P at b11, b10, b6 ; ; BRW opdone ; .Align Long STY: JSB @AddressModes(R3) ; Get address of operand MOVB R8,Memory(R0) ; Store it there BRW OpDone .Align Long ASL: JSB @AddressModes(R3) ; Get address of operand MOVB Memory(R0),R1 ; Get operand value ASHL #1,R1,R1 ; Shift our operand left one bit ASHL #-8,R1,R2 ; Get new Carry flag INSV R2,#0,#1,R9 ; Put new Carry flag into P MOVB R1,Memory(R0) ; Store the result where it came from BRW SetFlags .Align Long ROL: JSB @AddressModes(R3) ; Get address of operand MOVB Memory(R0),R1 ; Get operand value ASHL #1,R1,R1 ; Shift our operand left one bit INSV R9,#0,#1,R1 ; Insert the carry flag at bit 0 ASHL #-8,R1,R2 ; Get new Carry flag INSV R2,#0,#1,R9 ; Put new Carry flag into P MOVB R1,Memory(R0) ; Store the result where it came from BRW SetFlags .Align Long LSR: JSB @AddressModes(R3) ; Get address of operand MOVZBL Memory(R0),R1 ; Get operand value INSV R1,#0,#1,R9 ; Insert new Carry flag into P ASHL #-1,R1,R1 ; Shift the operand one bit right MOVB R1,Memory(R0) ; Store the result where it came from BRW SetFlags .Align Long ROR: JSB @AddressModes(R3) ; Get address of operand MOVZBL Memory(R0),R1 ; Get operand value INSV R9,#8,#1,R1 ; Insert the Carry flag into the operand INSV R1,#0,#1,R9 ; Insert the new Carry flag into P ASHL #-1,R1,R1 ; Shift the operand one bit right MOVB R1,Memory(R0) ; Store the result where it came from BRW SetFlags .Align Long STX: JSB @AddressModes(R3) ; Get address of operand MOVB R7,Memory(R0) ; Store X at the required location BRW OpDone .Align Long LDX: JSB @AddressModes(R3) ; Get address of operand MOVB Memory(R0),R7 ; Load X with the operand given BRW SetFlags .Align Long DEC: JSB @AddressModes(R3) ; Get address of operand DECB Memory(R0) ; Decrement operand given BRW SetFlags .Align Long INC: JSB @AddressModes(R3) ; Get address of operand INCB Memory(R0) ; Increment operand given BRW SetFlags .Align Long ASLA: ASHL #1,R6,R0 ; Shift our operand left one bit ASHL #-8,R0,R2 ; Get new Carry flag INSV R2,#0,#1,R9 ; Put new Carry flag into P MOVB R0,R6 ; Store the result where it came from BRW SetFlags .Align Long ROLA: ASHL #1,R6,R0 ; Shift our operand left one bit INSV R9,#0,#1,R0 ; Insert the carry flag at bit 0 ASHL #-8,R0,R2 ; Get new Carry flag INSV R2,#0,#1,R9 ; Put new Carry flag into P MOVB R0,R6 ; Store the result where it came from BRW SetFlags .Align Long LSRA: INSV R6,#0,#1,R9 ; Insert the new Carry flag into P ASHL #-1,R6,R6 ; Shift the operand one bit right TSTB R6 ; Set up to test for N and Z BRW SetFlags .Align Long RORA: INSV R9,#8,#1,R6 ; Insert the Carry flag into the operand INSV R6,#0,#1,R9 ; Insert the new Carry flag into P ASHL #-1,R6,R6 ; Shift the operand one bit right TSTB R6 ; Set up to test for N and Z BRW SetFlags .Align Long TXA: MOVB R7,R6 ; Copy X to A BRW SetFlags .Align Long TXS: MOVB R7,R11 ; Copy X to SP BRW OpDone .Align Long TAX: MOVB R6,R7 ; Copy A to X BRW SetFlags .Align Long TSX: MOVB R11,R7 ; Copy SP to X BRW SetFlags .Align Long DEX: DECB R7 ; Decrement X BRW SetFlags .Align Long Op02: Op03: Op04: Op07: Op0A: Op0B: Op0C: Op0F: Op80: Op89: Op9E: Null: ; Invalid Opcode encountered. Call provided routine to ; print error message etc. Pass it the address of the opcode. InvalidOpCode: MOVZWL R4,addressbus ; Store the address of the bad opcode PUSHAL addressbus ; Pass it to the handling routine CALLS #1,@InvalidRoutine ; Call the routine if its defined BRW OpDone ; The following routines calculate the 6502 address of the operand of the ; current instruction. They are entered by JSBing to a computed target. ; The address is returned as a word zero extended to a longword in R0. ; Not all instructions result in one of these routines being called - ; some do not have operands and some use special case code. .Align Long IndIndX: ; (zp,x) MOVZBL Memory(R10),R1 ; Get base address of vector INCW R10 ; Increment PC ADDB2 R7,R1 ; Add X to get low byte of vector MOVZBL Memory(R1),R0 ; Read low byte of the address INCB R1 ; Point at high byte of address INSV Memory(R1),#8,#8,R0 ; Read high byte of the address RSB .Align Long IndIndY: ; (zp),y MOVZBL Memory(R10),R1 ; Get address of vector INCW R10 ; Increment PC MOVZBL Memory(R1),R0 ; Read low byte of vector INCB R1 ; Point at high byte of vector INSV Memory(R1),#8,#8,R0 ; Read high byte of vector ADDW2 R8,R0 ; Add in Y RSB .Align Long ZeroPg: ; zp MOVZBL Memory(R10),R0 ; Get address of operand INCW R10 ; Increment PC RSB .Align Long ZeroPgX: ; zp,x MOVZBL Memory(R10),R0 ; Get address base of operand INCW R10 ; Increment PC ADDB2 R7,R0 ; Add in X RSB .Align Long Immed: ; # imm MOVZWL R10,R0 ; Address of operand is PC INCW R10 ; Increment PC RSB .Align Long AbsY: ; abs,y MOVZBL Memory(R10),R0 ; Get low byte of base address INCW R10 ; Increment PC INSV Memory(R10),#8,#8,R0 ; Get high byte of base address INCW R10 ; Increment PC ADDW2 R8,R0 ; Add in Y RSB .Align Long Abs: ; abs MOVZBL Memory(R10),R0 ; Get low byte of address INCW R10 ; Increment PC INSV Memory(R10),#8,#8,R0 ; Get high byte of address INCW R10 ; Increment PC RSB .Align Long AbsX: ; abs,x MOVZBL Memory(R10),R0 ; Get low byte of base address INCW R10 ; Increment PC INSV Memory(R10),#8,#8,R0 ; Get high byte of base address INCW R10 ; Increment PC ADDW2 R7,R0 ; Add in X RSB .Align Long ZeroPgY: ; zp,y MOVZBL Memory(R10),R0 ; Get base address INCW R10 ; Increment PC ADDB2 R8,R0 ; Add in Y RSB .Align Long IndZp: ; (zp) MOVZBL Memory(R10),R1 ; Get address of vector INCW R10 ; Increment PC MOVZBL Memory(R1),R0 ; Read low byte of vector INCB R1 ; Point at high byte INSV Memory(R1),#8,#8,R0 ; Read high byte of vector RSB ; Dummy routine to initialize variable address routines to .Entry Y6502_Return, 0 RET ; Routines to read and write memory - for FORTRAN part. .Align Long .ENTRY Y6502_Read_Memory, 0 ; Read a byte in memory MOVZWL @4(AP),R1 ; Get value of first argument MOVZBL Memory(R1),R0 ; Read relevant byte of memory into R0 RET .Align Long .ENTRY Y6502_Write_Memory, 0 ; Write a byte to memory MOVZWL @4(AP),R1 ; Get value of first argument MOVB @8(AP),Memory(R1) ; Store value of second argument MOVL #1,R0 ; Set a good return code in case RET ; Routine to read instruction profiling counters .If Df, Y6502_Intruction_Profile .Align Long .ENTRY Y6502_Get_Instruction_Count, 0 MOVZWL @4(AP),R1 ; Get value of first argument MOVL Counter[R1],R0 ; Read relevant counter into R0 RET .Endc .End