mirror of
https://github.com/dpeckett/arduino-appleii.git
synced 2024-08-31 17:29:01 +00:00
Building a proper 6502 vm
This commit is contained in:
parent
2798ae6d16
commit
8e82eb6705
BIN
6502tests/.DS_Store
vendored
Normal file
BIN
6502tests/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
6502tests/test/.DS_Store
vendored
Normal file
BIN
6502tests/test/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
APPLEII/.DS_Store
vendored
Normal file
BIN
APPLEII/.DS_Store
vendored
Normal file
Binary file not shown.
54
APPLEII/addressing.ino
Normal file
54
APPLEII/addressing.ino
Normal file
@ -0,0 +1,54 @@
|
||||
// In fastcpu ino
|
||||
extern unsigned short PC;
|
||||
extern unsigned char X, Y;
|
||||
|
||||
// Addressing Modes
|
||||
unsigned short inline a_abs() {
|
||||
PC += 2;
|
||||
return read16(PC-2);
|
||||
}
|
||||
|
||||
unsigned short inline a_absx() {
|
||||
PC += 2;
|
||||
return (read16(PC-2) + (unsigned short)X);
|
||||
}
|
||||
|
||||
unsigned short inline a_absy() {
|
||||
PC += 2;
|
||||
return (read16(PC-2) + (unsigned short)Y);
|
||||
}
|
||||
|
||||
unsigned short inline a_imm() {
|
||||
return PC++;
|
||||
}
|
||||
|
||||
//ignore page wrap bug
|
||||
unsigned short inline a_ind() {
|
||||
PC += 2;
|
||||
return read16(read16(PC-2));
|
||||
}
|
||||
|
||||
unsigned short inline a_indx() {
|
||||
return read16(((unsigned short)read8(PC++) + (unsigned short)X)&0xFF);
|
||||
}
|
||||
|
||||
unsigned short inline a_indy() {
|
||||
return read16(((unsigned short)read8(PC++) + (unsigned short)Y)&0xFF);
|
||||
}
|
||||
|
||||
unsigned short inline a_rel() {
|
||||
unsigned short addr = (unsigned short)read8(PC++);
|
||||
return addr | ((addr&0x80)?0xFF00:0x0000);
|
||||
}
|
||||
|
||||
unsigned short inline a_zpg() {
|
||||
return (unsigned short)read8(PC++);
|
||||
}
|
||||
|
||||
unsigned short inline a_zpgx() {
|
||||
return ((unsigned short)read8(PC++) + (unsigned short)X)&0xFF;
|
||||
}
|
||||
|
||||
unsigned short inline a_zpgy() {
|
||||
return ((unsigned short)read8(PC++) + (unsigned short)Y)&0xFF;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// μ6502 - Barebones 6502 Emulator By Damian Peckett
|
||||
// dpeckett.com, <damian.peckett@gmail.com>
|
||||
|
||||
/*
|
||||
// Address Modes
|
||||
#define AD_IMP 0x01
|
||||
#define AD_A 0x02
|
||||
@ -60,6 +60,10 @@ const unsigned char flags[] PROGMEM = {
|
||||
AD_REL, FL_ALL|AD_INDY, UNDF, UNDF, UNDF, FL_ALL|AD_ZPGX, FL_ZN|AD_ZPGX, UNDF, AD_IMP, FL_ALL|AD_ABSY, UNDF, UNDF, UNDF, FL_ALL|AD_ABSX, FL_ZN|AD_ABSX, UNDF
|
||||
};
|
||||
|
||||
const void *opcode[] PROGMEM = {
|
||||
|
||||
}
|
||||
|
||||
// CPU registers
|
||||
unsigned short PC;
|
||||
unsigned char STP = 0xFD, A = 0x00, X = 0x00, Y = 0x00, SR = SR_FIXED_BITS;
|
||||
@ -89,25 +93,6 @@ void setflags() {
|
||||
if(opflags&0x40) SR |= ((result^((unsigned short)A))&(result^value16)&0x0080)>>1;
|
||||
}
|
||||
|
||||
// Stack functions
|
||||
void push16(unsigned short pushval) {
|
||||
write8(STP_BASE + (STP--), (pushval>>8)&0xFF);
|
||||
write8(STP_BASE + (STP--), pushval&0xFF);
|
||||
}
|
||||
|
||||
void push8(unsigned char pushval) {
|
||||
write8(STP_BASE + (STP--), pushval);
|
||||
}
|
||||
|
||||
unsigned short pull16() {
|
||||
value16 = read8(STP_BASE + (++STP)) | ((unsigned short)read8(STP_BASE + (++STP))<< 8);
|
||||
return value16;
|
||||
}
|
||||
|
||||
unsigned char pull8() {
|
||||
return read8(STP_BASE + (++STP));
|
||||
}
|
||||
|
||||
void run() {
|
||||
// Load the reset vector
|
||||
PC = read16(0xFFFC);
|
||||
@ -171,6 +156,8 @@ void run() {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//opcodes
|
||||
switch(opcode) {
|
||||
//ADC
|
||||
@ -525,4 +512,4 @@ void run() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
209
APPLEII/fastcpu.ino
Normal file
209
APPLEII/fastcpu.ino
Normal file
@ -0,0 +1,209 @@
|
||||
// μ6502 v2.0 - Barebones 6502 Emulator By Damian Peckett
|
||||
// dpeckett.com, <damian.peckett@gmail.com>
|
||||
|
||||
//Other constants
|
||||
#define SR_FIXED_BITS 0x20
|
||||
#define SR_CARRY 0x01
|
||||
#define SR_ZERO 0x02
|
||||
#define SR_INT 0x04
|
||||
#define SR_DEC 0x08
|
||||
#define SR_BRK 0x10
|
||||
#define SR_OVER 0x40
|
||||
#define SR_NEG 0x80
|
||||
|
||||
//Stack pointer base address
|
||||
#define STP_BASE 0x100
|
||||
|
||||
// CPU registers
|
||||
unsigned short PC;
|
||||
unsigned char STP = 0xFD, A = 0x00, X = 0x00, Y = 0x00, SR = SR_FIXED_BITS;
|
||||
|
||||
void run() {
|
||||
// Opcode Addresses, Labels As Values
|
||||
static const void* opcodes[] = {
|
||||
&&BRK, &&ORA_INDX, &&UNDF, &&UNDF, &&UNDF, &&ORA_ZPG, &&ASL_ZPG, &&UNDF, &&PHP, &&ORA_IMM, &&ASL_A, &&UNDF, &&UNDF, &&ORA_ABS, &&ASL_ABS, &&UNDF,
|
||||
&&BPL_REL, &&ORA_INDY, &&UNDF, &&UNDF, &&UNDF, &&ORA_ZPGX, &&ASL_ZPGX, &&UNDF, &&CLC, &&ORA_ABSY, &&UNDF, &&UNDF, &&UNDF, &&ORA_ABSX, &&ASL_ABSX, &&UNDF,
|
||||
&&JSR_ABS, &&AND_INDX, &&UNDF, &&UNDF, &&BIT_ZPG, &&AND_ZPG, &&ROL_ZPG, &&UNDF, &&PLP, &&AND_IMM, &&ROL_A, &&UNDF, &&BIT_ABS, &&AND_ABS, &&ROL_ABS, &&UNDF
|
||||
};
|
||||
|
||||
unsigned char value8, result8;
|
||||
unsigned short value16, result16;
|
||||
unsigned short ptr;
|
||||
|
||||
// Load the reset vector
|
||||
PC = read16(0xFFFC);
|
||||
|
||||
// Begin Execution
|
||||
goto *opcodes[read8(PC++)];
|
||||
|
||||
// Instruction interpreter
|
||||
BRK:
|
||||
push16(PC+1);
|
||||
push8(SR|SR_BRK);
|
||||
SR |= SR_INT;
|
||||
PC = read16(0xFFFE);
|
||||
goto *opcodes[read8(PC++)];
|
||||
ORA_INDX:
|
||||
A |= read8(a_indx());
|
||||
flagZero(A);
|
||||
flagNegative(A);
|
||||
goto *opcodes[read8(PC++)];
|
||||
ORA_ZPG:
|
||||
A |= read8(a_zpg());
|
||||
flagZero(A);
|
||||
flagNegative(A);
|
||||
goto *opcodes[read8(PC++)];
|
||||
ASL_ZPG:
|
||||
ptr = a_zpg();
|
||||
value16 = read8(ptr);
|
||||
result16 = value16<<1;
|
||||
flagZero(result16&0x00FF);
|
||||
flagNegative(result16&0x00FF);
|
||||
flagCarry(result16);
|
||||
write8(ptr, result16&0x00FF);
|
||||
goto *opcodes[read8(PC++)];
|
||||
PHP:
|
||||
push8(SR|SR_BRK);
|
||||
goto *opcodes[read8(PC++)];
|
||||
ORA_IMM:
|
||||
A |= read8(a_imm());
|
||||
flagZero(A);
|
||||
flagNegative(A);
|
||||
goto *opcodes[read8(PC++)];
|
||||
ASL_A:
|
||||
value16 = A;
|
||||
result16 = value16<<1;
|
||||
flagZero(result16&0x00FF);
|
||||
flagNegative(result16&0x00FF);
|
||||
flagCarry(result16);
|
||||
A = result16&0x00FF;
|
||||
goto *opcodes[read8(PC++)];
|
||||
ORA_ABS:
|
||||
A |= read8(a_abs());
|
||||
flagZero(A);
|
||||
flagNegative(A);
|
||||
goto *opcodes[read8(PC++)];
|
||||
ASL_ABS:
|
||||
ptr = a_abs();
|
||||
value16 = read8(ptr);
|
||||
result16 = value16<<1;
|
||||
flagZero(result16&0x00FF);
|
||||
flagNegative(result16&0x00FF);
|
||||
flagCarry(result16);
|
||||
write8(ptr, result16&0x00FF);
|
||||
goto *opcodes[read8(PC++)];
|
||||
BPL_REL:
|
||||
if(!(SR&SR_NEG)) PC += a_rel();
|
||||
goto *opcodes[read8(PC++)];
|
||||
ORA_INDY:
|
||||
A |= read8(a_indy());
|
||||
flagZero(A);
|
||||
flagNegative(A);
|
||||
goto *opcodes[read8(PC++)];
|
||||
ORA_ZPGX:
|
||||
A |= read8(a_zpgx());
|
||||
flagZero(A);
|
||||
flagNegative(A);
|
||||
goto *opcodes[read8(PC++)];
|
||||
ASL_ZPGX:
|
||||
ptr = a_zpgx();
|
||||
value16 = read8(ptr);
|
||||
result16 = value16<<1;
|
||||
flagZero(result16&0x00FF);
|
||||
flagNegative(result16&0x00FF);
|
||||
flagCarry(result16);
|
||||
write8(ptr, result16&0x00FF);
|
||||
goto *opcodes[read8(PC++)];
|
||||
CLC:
|
||||
SR &= ~SR_CARRY;
|
||||
goto *opcodes[read8(PC++)];
|
||||
ORA_ABSY:
|
||||
A |= read8(a_absy());
|
||||
flagZero(A);
|
||||
flagNegative(A);
|
||||
goto *opcodes[read8(PC++)];
|
||||
ORA_ABSX:
|
||||
A |= read8(a_absx());
|
||||
flagZero(A);
|
||||
flagNegative(A);
|
||||
goto *opcodes[read8(PC++)];
|
||||
ASL_ABSX:
|
||||
ptr = a_absx();
|
||||
value16 = read8(ptr);
|
||||
result16 = value16<<1;
|
||||
flagZero(result16&0x00FF);
|
||||
flagNegative(result16&0x00FF);
|
||||
flagCarry(result16);
|
||||
write8(ptr, result16&0x00FF);
|
||||
goto *opcodes[read8(PC++)];
|
||||
JSR_ABS:
|
||||
push16(PC-1);
|
||||
PC = a_abs();
|
||||
goto *opcodes[read8(PC++)];
|
||||
AND_INDX:
|
||||
A &= read8(a_indx());
|
||||
flagZero(A);
|
||||
flagNegative(A);
|
||||
goto *opcodes[read8(PC++)];
|
||||
BIT_ZPG:
|
||||
value8 = read8(a_zpg());
|
||||
result8 = A & value8;
|
||||
flagZero(result8);
|
||||
SR = (SR&0x3F) | (value8&0xC0);
|
||||
goto *opcodes[read8(PC++)];
|
||||
AND_ZPG:
|
||||
A &= read8(a_zpg());
|
||||
flagZero(A);
|
||||
flagNegative(A);
|
||||
goto *opcodes[read8(PC++)];
|
||||
ROL_ZPG:
|
||||
ptr = a_zpg();
|
||||
value16 = read8(ptr);
|
||||
result16 = (value16 << 1) | (SR&SR_CARRY);
|
||||
flagZero(result16&0x00FF);
|
||||
flagNegative(result16&0x00FF);
|
||||
flagCarry(result16);
|
||||
write8(ptr, result16&0x00FF);
|
||||
goto *opcodes[read8(PC++)];
|
||||
PLP:
|
||||
SR = pull8() | SR_FIXED_BITS;
|
||||
goto *opcodes[read8(PC++)];
|
||||
AND_IMM:
|
||||
A &= read8(a_imm());
|
||||
flagZero(A);
|
||||
flagNegative(A);
|
||||
goto *opcodes[read8(PC++)];
|
||||
ROL_A:
|
||||
value16 = A;
|
||||
result16 = (value16 << 1) | (SR&SR_CARRY);
|
||||
flagZero(result16&0x00FF);
|
||||
flagNegative(result16&0x00FF);
|
||||
flagCarry(result16);
|
||||
A = result16&0x00FF;
|
||||
goto *opcodes[read8(PC++)];
|
||||
BIT_ABS:
|
||||
value8 = read8(a_abs());
|
||||
result8 = A & value8;
|
||||
flagZero(result8);
|
||||
SR = (SR&0x3F) | (value8&0xC0);
|
||||
goto *opcodes[read8(PC++)];
|
||||
AND_ABS:
|
||||
A &= read8(a_abs());
|
||||
flagZero(A);
|
||||
flagNegative(A);
|
||||
goto *opcodes[read8(PC++)];
|
||||
ROL_ABS:
|
||||
ptr = a_abs();
|
||||
value16 = read8(ptr);
|
||||
result16 = (value16 << 1) | (SR&SR_CARRY);
|
||||
flagZero(result16&0x00FF);
|
||||
flagNegative(result16&0x00FF);
|
||||
flagCarry(result16);
|
||||
write8(ptr, result16&0x00FF);
|
||||
goto *opcodes[read8(PC++)];
|
||||
|
||||
// -- Undefined Opcodes
|
||||
UNDF:
|
||||
// Raise an error
|
||||
goto *opcodes[read8(PC++)];
|
||||
}
|
16
APPLEII/flags.ino
Normal file
16
APPLEII/flags.ino
Normal file
@ -0,0 +1,16 @@
|
||||
void inline flagZero(unsigned char value) {
|
||||
if(!value) SR |= SR_ZERO;
|
||||
else SR &= ~SR_ZERO;
|
||||
}
|
||||
|
||||
void inline flagNegative(unsigned char value) {
|
||||
if(value&0x80) SR |= SR_NEG;
|
||||
else SR &= ~SR_NEG;
|
||||
}
|
||||
|
||||
void inline flagCarry(unsigned short value) {
|
||||
if(value&0xFF00) SR |= SR_CARRY;
|
||||
else SR &= ~SR_CARRY;
|
||||
}
|
||||
|
||||
|
@ -1026,52 +1026,82 @@ const unsigned char rom[] PROGMEM = { //$E000 - FFFF
|
||||
};
|
||||
|
||||
unsigned char ram[1024];
|
||||
// Free memory for storing BASIC programs
|
||||
unsigned char basic[512];
|
||||
|
||||
unsigned char read8(unsigned short address) {
|
||||
unsigned char page = address>>8;
|
||||
if(page < 0x04) {
|
||||
unsigned char inline read8(unsigned short address) {
|
||||
switch(address>>8) {
|
||||
case 0x00: case 0x01:
|
||||
case 0x02: case 0x03:
|
||||
return ram[address];
|
||||
} else if (page >= 0x04 && page < 0x08) {
|
||||
case 0x04: case 0x05:
|
||||
case 0x06: case 0x07:
|
||||
return screenRead(address);
|
||||
} else if (page >= 0x08 && page < 0x10) {
|
||||
return basic[address-0x800];
|
||||
} else if (page >= 0xE0) {
|
||||
case 0xC0:
|
||||
return softSwitch(address);
|
||||
case 0xE0: case 0xE1:
|
||||
case 0xE2: case 0xE3:
|
||||
case 0xE4: case 0xE5:
|
||||
case 0xE6: case 0xE7:
|
||||
case 0xE8: case 0xE9:
|
||||
case 0xEA: case 0xEB:
|
||||
case 0xEC: case 0xED:
|
||||
case 0xEE: case 0xEF:
|
||||
case 0xF0: case 0xF1:
|
||||
case 0xF2: case 0xF3:
|
||||
case 0xF4: case 0xF5:
|
||||
case 0xF6: case 0xF7:
|
||||
case 0xF8: case 0xF9:
|
||||
case 0xFA: case 0xFB:
|
||||
case 0xFC: case 0xFD:
|
||||
case 0xFE: case 0xFF:
|
||||
return pgm_read_byte_near(rom+address-0xE000);
|
||||
} else {
|
||||
// Keyboard Data
|
||||
if(address == 0xC000) return keyboard_read();
|
||||
// Keyboard Strobe
|
||||
if(address == 0xC010) keyboard_strobe();
|
||||
// Speaker toggle
|
||||
if(address == 0xC030) speaker_toggle();
|
||||
return 0;
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short read16(unsigned short address) {
|
||||
unsigned short inline read16(unsigned short address) {
|
||||
return (unsigned short)read8(address) | (((unsigned short)read8(address+1))<<8);
|
||||
}
|
||||
|
||||
void write8(unsigned short address, unsigned char value) {
|
||||
unsigned char page = address>>8;
|
||||
if(page < 0x04) {
|
||||
void inline write8(unsigned short address, unsigned char value) {
|
||||
switch(address>>8) {
|
||||
case 0x00: case 0x01:
|
||||
case 0x02: case 0x03:
|
||||
ram[address] = value;
|
||||
} else if(page >= 0x04 && page < 0x08) {
|
||||
break;
|
||||
case 0x04: case 0x05:
|
||||
case 0x06: case 0x07:
|
||||
screenWrite(address, value);
|
||||
} else if (page >= 0x08 && page < 0x10) {
|
||||
basic[address-0x800] = value;
|
||||
} else {
|
||||
// Keyboard Strobe
|
||||
if(address == 0xC010) keyboard_strobe();
|
||||
// Speaker toggle
|
||||
if(address == 0xC030) speaker_toggle();
|
||||
break;
|
||||
case 0xC0:
|
||||
softSwitch(address);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void write16(unsigned short address, unsigned short value) {
|
||||
void inline write16(unsigned short address, unsigned short value) {
|
||||
write8(address, value&0x00FF);
|
||||
write8(address+1, (value>>8)&0x00FF);
|
||||
}
|
||||
|
||||
// Stack functions
|
||||
void inline push16(unsigned short pushval) {
|
||||
write8(STP_BASE + (STP--), (pushval>>8)&0xFF);
|
||||
write8(STP_BASE + (STP--), pushval&0xFF);
|
||||
}
|
||||
|
||||
void inline push8(unsigned char pushval) {
|
||||
write8(STP_BASE + (STP--), pushval);
|
||||
}
|
||||
|
||||
unsigned short inline pull16() {
|
||||
unsigned short value16 = read8(STP_BASE + (++STP)) | ((unsigned short)read8(STP_BASE + (++STP))<< 8);
|
||||
return value16;
|
||||
}
|
||||
|
||||
unsigned char inline pull8() {
|
||||
return read8(STP_BASE + (++STP));
|
||||
}
|
||||
|
||||
|
14
APPLEII/softswitch.ino
Normal file
14
APPLEII/softswitch.ino
Normal file
@ -0,0 +1,14 @@
|
||||
unsigned char softSwitch(unsigned short address) {
|
||||
switch(address&0x00FF) {
|
||||
case 0x00: // Keyboard Data
|
||||
return keyboard_read();
|
||||
case 0x10: // Keyboard Strobe
|
||||
keyboard_strobe();
|
||||
return 0xFF;
|
||||
case 0x30: // Speaker toggle
|
||||
speaker_toggle();
|
||||
return 0xFF;
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user