Building a proper 6502 vm

This commit is contained in:
Damian Peckett 2015-04-08 22:56:14 +10:00
parent 2798ae6d16
commit 8e82eb6705
10 changed files with 377 additions and 67 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

BIN
6502tests/.DS_Store vendored Normal file

Binary file not shown.

BIN
6502tests/test/.DS_Store vendored Normal file

Binary file not shown.

BIN
APPLEII/.DS_Store vendored Normal file

Binary file not shown.

54
APPLEII/addressing.ino Normal file
View 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;
}

View File

@ -1,6 +1,6 @@
// μ6502 - Barebones 6502 Emulator By Damian Peckett // μ6502 - Barebones 6502 Emulator By Damian Peckett
// dpeckett.com, <damian.peckett@gmail.com> // dpeckett.com, <damian.peckett@gmail.com>
/*
// Address Modes // Address Modes
#define AD_IMP 0x01 #define AD_IMP 0x01
#define AD_A 0x02 #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 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 // CPU registers
unsigned short PC; unsigned short PC;
unsigned char STP = 0xFD, A = 0x00, X = 0x00, Y = 0x00, SR = SR_FIXED_BITS; 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; 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() { void run() {
// Load the reset vector // Load the reset vector
PC = read16(0xFFFC); PC = read16(0xFFFC);
@ -171,6 +156,8 @@ void run() {
break; break;
} }
//opcodes //opcodes
switch(opcode) { switch(opcode) {
//ADC //ADC
@ -525,4 +512,4 @@ void run() {
break; break;
} }
} }
} }*/

209
APPLEII/fastcpu.ino Normal file
View 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
View 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;
}

View File

@ -1026,52 +1026,82 @@ const unsigned char rom[] PROGMEM = { //$E000 - FFFF
}; };
unsigned char ram[1024]; unsigned char ram[1024];
// Free memory for storing BASIC programs
unsigned char basic[512];
unsigned char read8(unsigned short address) { unsigned char inline read8(unsigned short address) {
unsigned char page = address>>8; switch(address>>8) {
if(page < 0x04) { case 0x00: case 0x01:
case 0x02: case 0x03:
return ram[address]; return ram[address];
} else if (page >= 0x04 && page < 0x08) { case 0x04: case 0x05:
case 0x06: case 0x07:
return screenRead(address); return screenRead(address);
} else if (page >= 0x08 && page < 0x10) { case 0xC0:
return basic[address-0x800]; return softSwitch(address);
} else if (page >= 0xE0) { 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); return pgm_read_byte_near(rom+address-0xE000);
} else { default:
// Keyboard Data return 0xFF;
if(address == 0xC000) return keyboard_read();
// Keyboard Strobe
if(address == 0xC010) keyboard_strobe();
// Speaker toggle
if(address == 0xC030) speaker_toggle();
return 0;
} }
} }
unsigned short read16(unsigned short address) { unsigned short inline read16(unsigned short address) {
return (unsigned short)read8(address) | (((unsigned short)read8(address+1))<<8); return (unsigned short)read8(address) | (((unsigned short)read8(address+1))<<8);
} }
void write8(unsigned short address, unsigned char value) { void inline write8(unsigned short address, unsigned char value) {
unsigned char page = address>>8; switch(address>>8) {
if(page < 0x04) { case 0x00: case 0x01:
case 0x02: case 0x03:
ram[address] = value; ram[address] = value;
} else if(page >= 0x04 && page < 0x08) { break;
case 0x04: case 0x05:
case 0x06: case 0x07:
screenWrite(address, value); screenWrite(address, value);
} else if (page >= 0x08 && page < 0x10) { break;
basic[address-0x800] = value; case 0xC0:
} else { softSwitch(address);
// Keyboard Strobe break;
if(address == 0xC010) keyboard_strobe(); default:
// Speaker toggle return;
if(address == 0xC030) speaker_toggle();
} }
} }
void write16(unsigned short address, unsigned short value) { void inline write16(unsigned short address, unsigned short value) {
write8(address, value&0x00FF); write8(address, value&0x00FF);
write8(address+1, (value>>8)&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
View 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;
}
}