int main() { M6502 *mpu = M6502_new(0, 0, 0); /* Make a 6502 */ unsigned pc = 0x1000; /* PC for 'assembly' */ /* Install the two callback functions defined above. */ M6502_setCallback(mpu, call, WRCH, wrch); /* Calling FFEE -> wrch() */ M6502_setCallback(mpu, call, 0, done); /* Calling 0 -> done() */ /* A few macros that dump bytes into the 6502's memory. */ # define gen1(X) (mpu->memory[pc++]= (uint8_t)(X)) # define gen2(X,Y) gen1(X); gen1(Y) # define gen3(X,Y,Z) gen1(X); gen2(Y,Z) /* Hand-assemble the program. */ gen2(0xA2, 'A' ); // LDX #'A' gen1(0x8A ); // TXA gen3(0x20,0xEE,0xFF); // JSR FFEE gen1(0xE8 ); // INX gen2(0xE0, 'Z'+1 ); // CPX #'Z'+1 gen2(0xD0, -9 ); // BNE 0x1002 gen2(0xA9, '\n' ); // LDA #'\n' gen3(0x20,0xEE,0xFF); // JSR FFEE gen2(0x00,0x00 ); // BRK /* Just for fun: disssemble the program. */ { char insn[64]; uint16_t ip= 0x1000; while (ip < pc) { ip += M6502_disassemble(mpu, ip, insn); printf("%04X %s\n", ip, insn); } } /* Point the RESET vector at the first instruction in the assembled * program. */ M6502_setVector(mpu, RST, 0x1000); /* Reset the 6502 and run the program. */ M6502_reset(mpu); M6502_run(mpu); M6502_delete(mpu); /* We never reach here, but what the hey. */ return 0; }
int main(int argc, char *argv[]) { M6502 *mpu = M6502_new(0, 0, 0); parse_args(argc, argv, mpu); unsigned pc = 0x1000; unsigned saved_pc; M6502_setCallback(mpu, call, 0, done ); M6502_setCallback(mpu, call, 0xffee, oswrch); gen2(0xa2, 0xff ); // LDX #&FF gen1(0x9a ); // TXS gen2(0xa9, 'A' ); // LDA #'A' // LDA #'B' is 0xa9, 0x42. So if we execute a JSR at 0x42a7, it will // push 0x42 and then 0xa9 onto the stack. Since the stack grows downwards // those bytes will be in the right order for execution. gen3(0x4c, 0xa7, 0x42); // JMP &42A7 pc = 0x42a7; gen3(0x20, 0x00, 0x30); // JSR &3000 saved_pc = pc; pc = 0x3000; gen3(0x4c, 0xfe, 0x01); // JMP &01FE pc = 0x200; gen3(0x20, 0xee, 0xff); // JSR &FFEE gen1(0x60 ); // RTS pc = saved_pc; // Let's do the same thing again, but this time code has already been // executed from that address on the stack, so we're verifying the change // is picked up. We do LDA #'C' this time, so we execute the JSR from // 0x43a7. gen3(0x4c, 0xa7, 0x43); // JMP &43A7 pc = 0x43a7; gen3(0x20, 0x00, 0x30); // JSR &3000 gen2(0x00, 0x00 ); // BRK M6502_setVector(mpu, RST, 0x1000); M6502_reset(mpu); M6502_run(mpu); M6502_delete(mpu); /* We never reach here, but what the hey. */ return 0; }
int main(int argc, char *argv[]) { M6502 *mpu = M6502_new(0, 0, 0); parse_args(argc, argv, mpu); unsigned pc = 0x1000; M6502_setCallback(mpu, call, 0, done); M6502_setCallback(mpu, call, 0xffee, oswrch); M6502_setCallback(mpu, write, 0x42, wr ); gen2(0xa9, '>' ); // LDA #'>' gen3(0x20, 0xee, 0xff); // JSR &FFEE gen2(0xa2, 'A' ); // LDX #'A' gen3(0x8e, 0x42, 0x00); // STX &0042 gen3(0x20, 0x00, 0x60); // JSR &6000 gen1(0xe8 ); // INX gen2(0xe0, 'Z'+1 ); // CPX #('Z'+1) gen2(0x90, 0xf5 ); // BCC to STX gen2(0xa0, 0x05 ); // LDY #&05 gen2(0xa9, '>' ); // LDA #'>' gen3(0x20, 0xee, 0xff); // JSR &FFEE gen2(0xa2, 'A' ); // LDX #'A' gen2(0x96, 0x42-0x05 ); // STX (&42-&05),Y gen3(0x20, 0x00, 0x60); // JSR &6000 gen1(0xe8 ); // INX gen2(0xe0, 'Z'+1 ); // CPX #('Z'+1) gen2(0x90, 0xf6 ); // BCC to STX gen2(0x00, 0x00 ); // BRK pc = 0x2000; gen3(0x20, 0xee, 0xff); // JSR &FFEE gen1(0x60 ); // RTS M6502_setVector(mpu, RST, 0x1000); M6502_reset(mpu); M6502_run(mpu); M6502_delete(mpu); /* We never reach here, but what the hey. */ return 0; }
int main(int argc, char *argv[]) { M6502 *mpu = M6502_new(0, 0, 0); parse_args(argc, argv, mpu); unsigned pc = 0x1000; unsigned saved_pc; M6502_setCallback(mpu, call, 0xf000, done ); M6502_setCallback(mpu, call, 0xffee, oswrch); gen2(0xa2, 0xff ); // LDX #&FF gen1(0x9a ); // TXS gen2(0xa9, 'A' ); // LDA #'A' // LDA #'B' is 0xa9, 0x42. So if we execute a BRK at 0x42a7, it will // push 0x42, 0xa9 and the flags onto the stack. Since the stack grows // downwards those bytes will be in the right order for execution. We'll // additionally push an LDX immediate opcode so we can "execute" the flags // value. We can nearly force the flags to be whatever we like using PLP, // although the BRK will set the B and X bits in the stacked value. We // demonstrate this by explicitly masking off those bits in the values we // force into the flags. enum { flagX= (1<<5), /* unused */ flagB= (1<<4) /* irq from brk */ }; uint8_t mask = ~(flagX | flagB); gen2(0xa0, '0' & mask); // LDY #('0' with B/X masked off) gen1(0x5a ); // PHY gen1(0x28 ); // PLP gen3(0x4c, 0xa7, 0x42); // JMP &42A7 pc = 0x42a7; gen2(0x00, 0x00 ); // BRK saved_pc = pc; pc = 0x0; // BRK vector gen2(0xa9, 0xa2 ); // LDA #<LDX # opcode> gen1(0x48 ); // PHA gen3(0x4c, 0xfc, 0x01); // JMP &01FC pc = 0x200; gen3(0x20, 0xee, 0xff); // JSR &FFEE gen1(0x8a ); // TXA gen3(0x20, 0xee, 0xff); // JSR &FFEE gen1(0x68 ); // PLA gen1(0x40 ); // RTI pc = saved_pc; // Let's do the same thing again, but this time code has already been // executed from that address on the stack, so we're verifying the change // is picked up. We do LDA #'C' this time, so we execute the BRK from // 0x43a7. gen2(0xa0, '1' & mask); // LDY #('1' with B/X masked off) gen1(0x5a ); // PHY gen1(0x28 ); // PLP gen3(0x4c, 0xa7, 0x43); // JMP &43A7 pc = 0x43a7; gen2(0x00, 0x00 ); // BRK gen3(0x4c, 0x00, 0xf0); // JMP &F000 (quit) M6502_setVector(mpu, RST, 0x1000); M6502_reset(mpu); M6502_run(mpu); M6502_delete(mpu); /* We never reach here, but what the hey. */ return 0; }