1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-29 12:50:28 +00:00

Adds absolute, x; absolute,y; and accumulator addressing modes.

Now covered: 80/256 opcodes, from 2/6 pages of the data sheet; or 16/47 bus programs.
This commit is contained in:
Thomas Harte 2020-09-25 21:16:36 -04:00
parent 8c11df52bf
commit 2957a31f40
2 changed files with 135 additions and 51 deletions

View File

@ -28,8 +28,12 @@ struct CPU::WDC65816::ProcessorStorageConstructor {
case LDA: case LDX: case LDY: case LDA: case LDX: case LDY:
// The access type for these is arbitrary, though consistency is beneficial. // The access type for the rest of these ::Reads is arbitrary.
case JMP: case JSR: case JML: case JSL: case JMP: case JSR: case JML: case JSL:
case ASL: case DEC: case INC: case LSR:
case ROL: case ROR: case TRB: case TSB:
return AccessType::Read; return AccessType::Read;
case STA: case STX: case STY: case STZ: case STA: case STX: case STY: case STZ:
@ -133,6 +137,19 @@ struct CPU::WDC65816::ProcessorStorageConstructor {
} }
} }
static void read_modify_write(bool is8bit, const std::function<void(MicroOp)> &target) {
if(!is8bit) target(CycleFetchIncrementData); // Data low.
target(CycleFetchData); // Data [high].
if(!is8bit) target(CycleFetchData); // 16-bit: reread final byte of data.
else target(CycleStoreData); // 8-bit rewrite final byte of data.
target(OperationPerform); // Perform operation within the data buffer.
if(!is8bit) target(CycleStoreDecrementData); // Data high.
target(CycleStoreData); // Data [low].
}
// 1a. Absolute; a. // 1a. Absolute; a.
static void absolute(AccessType type, bool is8bit, const std::function<void(MicroOp)> &target) { static void absolute(AccessType type, bool is8bit, const std::function<void(MicroOp)> &target) {
target(CycleFetchIncrementPC); // AAL. target(CycleFetchIncrementPC); // AAL.
@ -167,16 +184,7 @@ struct CPU::WDC65816::ProcessorStorageConstructor {
target(CycleFetchIncrementPC); // AAH. target(CycleFetchIncrementPC); // AAH.
target(OperationConstructAbsolute); // Calculate data address. target(OperationConstructAbsolute); // Calculate data address.
if(!is8bit) target(CycleFetchIncrementData); // Data low. read_modify_write(is8bit, target);
target(CycleFetchData); // Data [high].
if(!is8bit) target(CycleFetchData); // 16-bit: reread final byte of data.
else target(CycleStoreData); // 8-bit rewrite final byte of data.
target(OperationPerform); // Perform operation within the data buffer.
if(!is8bit) target(CycleStoreDecrementData); // Data high.
target(CycleStoreData); // Data [low].
}; };
// 2a. Absolute Indexed Indirect; (a, x), JMP. // 2a. Absolute Indexed Indirect; (a, x), JMP.
@ -281,6 +289,60 @@ struct CPU::WDC65816::ProcessorStorageConstructor {
read_write(type, is8bit, target); read_write(type, is8bit, target);
} }
// 6a. Absolute, X; a, x.
static void absolute_x(AccessType type, bool is8bit, const std::function<void(MicroOp)> &target) {
target(CycleFetchIncrementPC); // AAL.
target(CycleFetchIncrementPC); // AAH.
if(type == AccessType::Read) {
target(OperationConstructAbsoluteXRead); // Calculate data address, potentially skipping the next fetch.
} else {
target(OperationConstructAbsoluteX); // Calculate data address.
}
target(CycleFetchIncorrectDataAddress); // Do the dummy read if necessary; OperationConstructAbsoluteX
// will skip this if it isn't required.
read_write(type, is8bit, target);
}
// 6b. Absolute, X; a, x, read-modify-write.
static void absolute_x_rmw(AccessType, bool is8bit, const std::function<void(MicroOp)> &target) {
target(CycleFetchIncrementPC); // AAL.
target(CycleFetchIncrementPC); // AAH.
target(OperationConstructAbsoluteX); // Calculate data address.
target(CycleFetchIncorrectDataAddress); // Perform dummy read.
read_modify_write(is8bit, target);
}
// 6a. Absolute, Y; a, y.
static void absolute_y(AccessType type, bool is8bit, const std::function<void(MicroOp)> &target) {
target(CycleFetchIncrementPC); // AAL.
target(CycleFetchIncrementPC); // AAH.
if(type == AccessType::Read) {
target(OperationConstructAbsoluteYRead); // Calculate data address, potentially skipping the next fetch.
} else {
target(OperationConstructAbsoluteY); // Calculate data address.
}
target(CycleFetchIncorrectDataAddress); // Do the dummy read if necessary; OperationConstructAbsoluteX
// will skip this if it isn't required.
read_write(type, is8bit, target);
}
// 7. Accumulator; A.
static void accumulator(AccessType, bool, const std::function<void(MicroOp)> &target) {
target(CycleFetchPC); // IO.
// TODO: seriously consider a-specific versions of all relevant operations;
// the cost of interpreting three things here is kind of silly.
target(OperationCopyAToData);
target(OperationPerform);
target(OperationCopyDataToA);
}
}; };
// TEMPORARY. Kneejerk way to get a step debug of 65816 storage construction. // TEMPORARY. Kneejerk way to get a step debug of 65816 storage construction.
@ -302,11 +364,11 @@ ProcessorStorage::ProcessorStorage() {
/* 0x07 ORA [d] */ /* 0x07 ORA [d] */
/* 0x08 PHP s */ /* 0x08 PHP s */
/* 0x09 ORA # */ /* 0x09 ORA # */
/* 0x0a ASL a */ /* 0x0a ASL A */ op(accumulator, ASL);
/* 0x0b PHD s */ /* 0x0b PHD s */
/* 0x0c TSB a */ /* 0x0c TSB a */ op(absolute_rmw, TSB);
/* 0x0d ORA a */ op(absolute, ORA); /* 0x0d ORA a */ op(absolute, ORA);
/* 0x0e ASL a */ /* 0x0e ASL a */ op(absolute_rmw, ASL);
/* 0x0f ORA al */ op(absolute_long, ORA); /* 0x0f ORA al */ op(absolute_long, ORA);
/* 0x10 BPL r */ /* 0x10 BPL r */
@ -318,12 +380,12 @@ ProcessorStorage::ProcessorStorage() {
/* 0x16 ASL d, x */ /* 0x16 ASL d, x */
/* 0x17 ORA [d], y */ /* 0x17 ORA [d], y */
/* 0x18 CLC i */ /* 0x18 CLC i */
/* 0x19 ORA a, y */ /* 0x19 ORA a, y */ op(absolute_y, ORA);
/* 0x1a INC A */ /* 0x1a INC A */ op(accumulator, INC);
/* 0x1b TCS i */ /* 0x1b TCS i */
/* 0x1c TRB a */ /* 0x1c TRB a */ op(absolute_rmw, TRB);
/* 0x1d ORA a, x */ /* 0x1d ORA a, x */ op(absolute_x, ORA);
/* 0x1e ASL a, x */ /* 0x1e ASL a, x */ op(absolute_x_rmw, ASL);
/* 0x1f ORA al, x */ op(absolute_long_x, ORA); /* 0x1f ORA al, x */ op(absolute_long_x, ORA);
/* 0x20 JSR a */ op(absolute_jsr, JSR); /* 0x20 JSR a */ op(absolute_jsr, JSR);
@ -332,15 +394,15 @@ ProcessorStorage::ProcessorStorage() {
/* 0x23 JSL al */ op(absolute_long_jsl, JSL); /* 0x23 JSL al */ op(absolute_long_jsl, JSL);
/* 0x24 BIT d */ /* 0x24 BIT d */
/* 0x25 AND d */ /* 0x25 AND d */
/* 0x26 ROL d */ /* 0x26 ROL d */ op(absolute_x_rmw, ROL);
/* 0x27 AND [d] */ /* 0x27 AND [d] */
/* 0x28 PLP s */ /* 0x28 PLP s */
/* 0x29 AND # */ /* 0x29 AND # */
/* 0x2a ROL A */ /* 0x2a ROL A */ op(accumulator, ROL);
/* 0x2b PLD s */ /* 0x2b PLD s */
/* 0x2c BIT a */ op(absolute, BIT); /* 0x2c BIT a */ op(absolute, BIT);
/* 0x2d AND a */ op(absolute, AND); /* 0x2d AND a */ op(absolute, AND);
/* 0x2e ROL a */ /* 0x2e ROL a */ op(absolute_rmw, ROL);
/* 0x2f AND al */ op(absolute_long, AND); /* 0x2f AND al */ op(absolute_long, AND);
/* 0x30 BMI R */ /* 0x30 BMI R */
@ -352,11 +414,11 @@ ProcessorStorage::ProcessorStorage() {
/* 0x36 TOL d, x */ /* 0x36 TOL d, x */
/* 0x37 AND [d], y */ /* 0x37 AND [d], y */
/* 0x38 SEC i */ /* 0x38 SEC i */
/* 0x39 AND a, y */ /* 0x39 AND a, y */ op(absolute_y, AND);
/* 0x3a DEC A */ /* 0x3a DEC A */ op(accumulator, DEC);
/* 0x3b TSC i */ /* 0x3b TSC i */
/* 0x3c BIT a, x */ /* 0x3c BIT a, x */ op(absolute_x, BIT);
/* 0x3d AND a, x */ /* 0x3d AND a, x */ op(absolute_x, AND);
/* 0x3e TLD a, x */ /* 0x3e TLD a, x */
/* 0x3f AND al, x */ op(absolute_long_x, AND); /* 0x3f AND al, x */ op(absolute_long_x, AND);
@ -370,11 +432,11 @@ ProcessorStorage::ProcessorStorage() {
/* 0x47 EOR [d] */ /* 0x47 EOR [d] */
/* 0x48 PHA s */ /* 0x48 PHA s */
/* 0x49 EOR # */ /* 0x49 EOR # */
/* 0x4a LSR A */ /* 0x4a LSR A */ op(accumulator, LSR);
/* 0x4b PHK s */ /* 0x4b PHK s */
/* 0x4c JMP a */ op(absolute, JMP); /* 0x4c JMP a */ op(absolute, JMP);
/* 0x4d EOR a */ op(absolute, EOR); /* 0x4d EOR a */ op(absolute, EOR);
/* 0x4e LSR a */ /* 0x4e LSR a */ op(absolute_rmw, LSR);
/* 0x4f EOR al */ op(absolute_long, EOR); /* 0x4f EOR al */ op(absolute_long, EOR);
/* 0x50 BVC r */ /* 0x50 BVC r */
@ -386,12 +448,12 @@ ProcessorStorage::ProcessorStorage() {
/* 0x56 LSR d, x */ /* 0x56 LSR d, x */
/* 0x57 EOR [d],y */ /* 0x57 EOR [d],y */
/* 0x58 CLI i */ /* 0x58 CLI i */
/* 0x59 EOR a, y */ /* 0x59 EOR a, y */ op(absolute_y, EOR);
/* 0x5a PHY s */ /* 0x5a PHY s */
/* 0x5b TCD i */ /* 0x5b TCD i */
/* 0x5c JMP al */ op(absolute_long_jmp, JML); // [sic]; this updates PBR so it's JML. /* 0x5c JMP al */ op(absolute_long_jmp, JML); // [sic]; this updates PBR so it's JML.
/* 0x5d EOR a, x */ /* 0x5d EOR a, x */ op(absolute_x, EOR);
/* 0x5e LSR a, x */ /* 0x5e LSR a, x */ op(absolute_x_rmw, LSR);
/* 0x5f EOR al, x */ op(absolute_long_x, EOR); /* 0x5f EOR al, x */ op(absolute_long_x, EOR);
/* 0x60 RTS s */ /* 0x60 RTS s */
@ -404,11 +466,11 @@ ProcessorStorage::ProcessorStorage() {
/* 0x67 ADC [d] */ /* 0x67 ADC [d] */
/* 0x68 PLA s */ /* 0x68 PLA s */
/* 0x69 ADC # */ /* 0x69 ADC # */
/* 0x6a ROR A */ /* 0x6a ROR A */ op(accumulator, ROR);
/* 0x6b RTL s */ /* 0x6b RTL s */
/* 0x6c JMP (a) */ op(absolute_indirect_jmp, JMP); /* 0x6c JMP (a) */ op(absolute_indirect_jmp, JMP);
/* 0x6d ADC a */ op(absolute, ADC); /* 0x6d ADC a */ op(absolute, ADC);
/* 0x6e ROR a */ /* 0x6e ROR a */ op(absolute_rmw, ROR);
/* 0x6f ADC al */ op(absolute_long, ADC); /* 0x6f ADC al */ op(absolute_long, ADC);
/* 0x70 BVS r */ /* 0x70 BVS r */
@ -420,12 +482,12 @@ ProcessorStorage::ProcessorStorage() {
/* 0x76 ROR d, x */ /* 0x76 ROR d, x */
/* 0x77 ADC [d], y */ /* 0x77 ADC [d], y */
/* 0x78 SEI i */ /* 0x78 SEI i */
/* 0x79 ADC a, y */ /* 0x79 ADC a, y */ op(absolute_y, ADC);
/* 0x7a PLY s */ /* 0x7a PLY s */
/* 0x7b TDC i */ /* 0x7b TDC i */
/* 0x7c JMP (a, x) */ op(absolute_indexed_indirect_jmp, JMP); /* 0x7c JMP (a, x) */ op(absolute_indexed_indirect_jmp, JMP);
/* 0x7d ADC a, x */ /* 0x7d ADC a, x */ op(absolute_x, ADC);
/* 0x7e ROR a, x */ /* 0x7e ROR a, x */ op(absolute_x_rmw, ROR);
/* 0x7f ADC al, x */ op(absolute_long_x, ADC); /* 0x7f ADC al, x */ op(absolute_long_x, ADC);
/* 0x80 BRA r */ /* 0x80 BRA r */
@ -454,12 +516,12 @@ ProcessorStorage::ProcessorStorage() {
/* 0x96 STX d, y */ /* 0x96 STX d, y */
/* 0x97 STA [d], y */ /* 0x97 STA [d], y */
/* 0x98 TYA i */ /* 0x98 TYA i */
/* 0x99 STA a, y */ /* 0x99 STA a, y */ op(absolute_y, STA);
/* 0x9a TXS i */ /* 0x9a TXS i */
/* 0x9b TXY i */ /* 0x9b TXY i */
/* 0x9c STZ a */ op(absolute, STZ); /* 0x9c STZ a */ op(absolute, STZ);
/* 0x9d STA a, x */ /* 0x9d STA a, x */ op(absolute_x, STA);
/* 0x9e STZ a, x */ /* 0x9e STZ a, x */ op(absolute_x, STZ);
/* 0x9f STA al, x */ op(absolute_long_x, STA); /* 0x9f STA al, x */ op(absolute_long_x, STA);
/* 0xa0 LDY # */ /* 0xa0 LDY # */
@ -488,12 +550,12 @@ ProcessorStorage::ProcessorStorage() {
/* 0xb6 LDX d, y */ /* 0xb6 LDX d, y */
/* 0xb7 LDA [d], y */ /* 0xb7 LDA [d], y */
/* 0xb8 CLV i */ /* 0xb8 CLV i */
/* 0xb9 LDA a, y */ /* 0xb9 LDA a, y */ op(absolute_y, LDA);
/* 0xba TSX i */ /* 0xba TSX i */
/* 0xbb TYX i */ /* 0xbb TYX i */
/* 0xbc LDY a, x */ /* 0xbc LDY a, x */ op(absolute_x, LDY);
/* 0xbd LDA a, x */ /* 0xbd LDA a, x */ op(absolute_x, LDA);
/* 0xbe LDX a, y */ /* 0xbe LDX a, y */ op(absolute_y, LDX);
/* 0xbf LDA al, x */ op(absolute_long_x, LDA); /* 0xbf LDA al, x */ op(absolute_long_x, LDA);
/* 0xc0 CPY # */ /* 0xc0 CPY # */
@ -510,7 +572,7 @@ ProcessorStorage::ProcessorStorage() {
/* 0xcb WAI i */ /* 0xcb WAI i */
/* 0xcc CPY a */ op(absolute, CPY); /* 0xcc CPY a */ op(absolute, CPY);
/* 0xcd CMP a */ op(absolute, CMP); /* 0xcd CMP a */ op(absolute, CMP);
/* 0xce DEC a */ /* 0xce DEC a */ op(absolute_rmw, DEC);
/* 0xcf CMP al */ op(absolute_long, CMP); /* 0xcf CMP al */ op(absolute_long, CMP);
/* 0xd0 BNE r */ /* 0xd0 BNE r */
@ -522,12 +584,12 @@ ProcessorStorage::ProcessorStorage() {
/* 0xd6 DEC d, x */ /* 0xd6 DEC d, x */
/* 0xd7 CMP [d], y */ /* 0xd7 CMP [d], y */
/* 0xd8 CLD i */ /* 0xd8 CLD i */
/* 0xd9 CMP a, y */ /* 0xd9 CMP a, y */ op(absolute_y, CMP);
/* 0xda PHX s */ /* 0xda PHX s */
/* 0xdb STP i */ /* 0xdb STP i */
/* 0xdc JML (a) */ op(absolute_indirect_jml, JML); /* 0xdc JML (a) */ op(absolute_indirect_jml, JML);
/* 0xdd CMP a, x */ /* 0xdd CMP a, x */ op(absolute_x, CMP);
/* 0xde DEC a, x */ /* 0xde DEC a, x */ op(absolute_x_rmw, DEC);
/* 0xdf CMP al, x */ op(absolute_long_x, CMP); /* 0xdf CMP al, x */ op(absolute_long_x, CMP);
/* 0xe0 CPX # */ /* 0xe0 CPX # */
@ -544,7 +606,7 @@ ProcessorStorage::ProcessorStorage() {
/* 0xeb XBA i */ /* 0xeb XBA i */
/* 0xec CPX a */ op(absolute, CPX); /* 0xec CPX a */ op(absolute, CPX);
/* 0xed SBC a */ op(absolute, SBC); /* 0xed SBC a */ op(absolute, SBC);
/* 0xee INC a */ /* 0xee INC a */ op(absolute_rmw, INC);
/* 0xef SBC al */ op(absolute_long, SBC); /* 0xef SBC al */ op(absolute_long, SBC);
/* 0xf0 BEQ r */ /* 0xf0 BEQ r */
@ -556,12 +618,12 @@ ProcessorStorage::ProcessorStorage() {
/* 0xf6 INC d, x */ /* 0xf6 INC d, x */
/* 0xf7 SBC [d], y */ /* 0xf7 SBC [d], y */
/* 0xf8 SED i */ /* 0xf8 SED i */
/* 0xf9 SBC a, y */ /* 0xf9 SBC a, y */ op(absolute_y, SBC);
/* 0xfa PLX s */ /* 0xfa PLX s */
/* 0xfb XCE i */ /* 0xfb XCE i */
/* 0xfc JSR (a, x) */ op(absolute_indexed_indirect_jsr, JMP); // [sic] /* 0xfc JSR (a, x) */ op(absolute_indexed_indirect_jsr, JMP); // [sic]
/* 0xfd SBC a, x */ /* 0xfd SBC a, x */ op(absolute_x, SBC);
/* 0xfe INC a, x */ /* 0xfe INC a, x */ op(absolute_x_rmw, INC);
/* 0xff SBC al, x */ op(absolute_long_x, SBC); /* 0xff SBC al, x */ op(absolute_long_x, SBC);
#undef op #undef op

View File

@ -19,6 +19,9 @@ enum MicroOp: uint8_t {
CycleFetchData, CycleFetchData,
/// Fetches a byte from the data address to the data buffer and increments the data address. /// Fetches a byte from the data address to the data buffer and increments the data address.
CycleFetchIncrementData, CycleFetchIncrementData,
/// Fetches from the address formed by the low byte of the data address and the high byte
/// of the instruction buffer, throwing the result away.
CycleFetchIncorrectDataAddress,
/// Stores a byte from the data buffer. /// Stores a byte from the data buffer.
CycleStoreData, CycleStoreData,
@ -39,6 +42,19 @@ enum MicroOp: uint8_t {
OperationConstructAbsoluteIndexedIndirect, OperationConstructAbsoluteIndexedIndirect,
OperationConstructAbsoluteLongX, OperationConstructAbsoluteLongX,
/// Calculates an a, x address; if:
/// there was no carry into the top byte of the address; and
/// the process or in emulation or 8-bit index mode;
/// then it also skips the next micro-op.
OperationConstructAbsoluteXRead,
/// Calculates an a, x address.
OperationConstructAbsoluteX,
// These are analogous to the X versions above.
OperationConstructAbsoluteY,
OperationConstructAbsoluteYRead,
/// Performs whatever operation goes with this program. /// Performs whatever operation goes with this program.
OperationPerform, OperationPerform,
@ -48,6 +64,9 @@ enum MicroOp: uint8_t {
/// Copies the current PBR to the data buffer. /// Copies the current PBR to the data buffer.
OperationCopyPBRToData, OperationCopyPBRToData,
OperationCopyAToData,
OperationCopyDataToA,
/// Complete this set of micr-ops. /// Complete this set of micr-ops.
OperationMoveToNextProgram OperationMoveToNextProgram
}; };
@ -65,6 +84,9 @@ enum Operation: uint8_t {
// they are implicitly AccessType::Write. // they are implicitly AccessType::Write.
STA, STX, STY, STZ, STA, STX, STY, STZ,
// These modify the value in the data buffer as part of a read-modify-write.
ASL, DEC, INC, LSR, ROL, ROR, TRB, TSB,
/// Loads the PC with the operand from the data buffer. /// Loads the PC with the operand from the data buffer.
JMP, JMP,