From 2957a31f4038368f503fb2ee8bb5a27a61dd00dc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 25 Sep 2020 21:16:36 -0400 Subject: [PATCH] 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. --- .../65816/Implementation/65816Storage.cpp | 164 ++++++++++++------ .../65816/Implementation/65816Storage.hpp | 22 +++ 2 files changed, 135 insertions(+), 51 deletions(-) diff --git a/Processors/65816/Implementation/65816Storage.cpp b/Processors/65816/Implementation/65816Storage.cpp index 54beddf0d..5281a1aa8 100644 --- a/Processors/65816/Implementation/65816Storage.cpp +++ b/Processors/65816/Implementation/65816Storage.cpp @@ -28,8 +28,12 @@ struct CPU::WDC65816::ProcessorStorageConstructor { 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 ASL: case DEC: case INC: case LSR: + case ROL: case ROR: case TRB: case TSB: + return AccessType::Read; 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 &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. static void absolute(AccessType type, bool is8bit, const std::function &target) { target(CycleFetchIncrementPC); // AAL. @@ -167,16 +184,7 @@ struct CPU::WDC65816::ProcessorStorageConstructor { target(CycleFetchIncrementPC); // AAH. target(OperationConstructAbsolute); // Calculate data address. - 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]. + read_modify_write(is8bit, target); }; // 2a. Absolute Indexed Indirect; (a, x), JMP. @@ -281,6 +289,60 @@ struct CPU::WDC65816::ProcessorStorageConstructor { read_write(type, is8bit, target); } + + // 6a. Absolute, X; a, x. + static void absolute_x(AccessType type, bool is8bit, const std::function &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 &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 &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 &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. @@ -302,11 +364,11 @@ ProcessorStorage::ProcessorStorage() { /* 0x07 ORA [d] */ /* 0x08 PHP s */ /* 0x09 ORA # */ - /* 0x0a ASL a */ + /* 0x0a ASL A */ op(accumulator, ASL); /* 0x0b PHD s */ - /* 0x0c TSB a */ + /* 0x0c TSB a */ op(absolute_rmw, TSB); /* 0x0d ORA a */ op(absolute, ORA); - /* 0x0e ASL a */ + /* 0x0e ASL a */ op(absolute_rmw, ASL); /* 0x0f ORA al */ op(absolute_long, ORA); /* 0x10 BPL r */ @@ -318,12 +380,12 @@ ProcessorStorage::ProcessorStorage() { /* 0x16 ASL d, x */ /* 0x17 ORA [d], y */ /* 0x18 CLC i */ - /* 0x19 ORA a, y */ - /* 0x1a INC A */ + /* 0x19 ORA a, y */ op(absolute_y, ORA); + /* 0x1a INC A */ op(accumulator, INC); /* 0x1b TCS i */ - /* 0x1c TRB a */ - /* 0x1d ORA a, x */ - /* 0x1e ASL a, x */ + /* 0x1c TRB a */ op(absolute_rmw, TRB); + /* 0x1d ORA a, x */ op(absolute_x, ORA); + /* 0x1e ASL a, x */ op(absolute_x_rmw, ASL); /* 0x1f ORA al, x */ op(absolute_long_x, ORA); /* 0x20 JSR a */ op(absolute_jsr, JSR); @@ -332,15 +394,15 @@ ProcessorStorage::ProcessorStorage() { /* 0x23 JSL al */ op(absolute_long_jsl, JSL); /* 0x24 BIT d */ /* 0x25 AND d */ - /* 0x26 ROL d */ + /* 0x26 ROL d */ op(absolute_x_rmw, ROL); /* 0x27 AND [d] */ /* 0x28 PLP s */ /* 0x29 AND # */ - /* 0x2a ROL A */ + /* 0x2a ROL A */ op(accumulator, ROL); /* 0x2b PLD s */ /* 0x2c BIT a */ op(absolute, BIT); /* 0x2d AND a */ op(absolute, AND); - /* 0x2e ROL a */ + /* 0x2e ROL a */ op(absolute_rmw, ROL); /* 0x2f AND al */ op(absolute_long, AND); /* 0x30 BMI R */ @@ -352,11 +414,11 @@ ProcessorStorage::ProcessorStorage() { /* 0x36 TOL d, x */ /* 0x37 AND [d], y */ /* 0x38 SEC i */ - /* 0x39 AND a, y */ - /* 0x3a DEC A */ + /* 0x39 AND a, y */ op(absolute_y, AND); + /* 0x3a DEC A */ op(accumulator, DEC); /* 0x3b TSC i */ - /* 0x3c BIT a, x */ - /* 0x3d AND a, x */ + /* 0x3c BIT a, x */ op(absolute_x, BIT); + /* 0x3d AND a, x */ op(absolute_x, AND); /* 0x3e TLD a, x */ /* 0x3f AND al, x */ op(absolute_long_x, AND); @@ -370,11 +432,11 @@ ProcessorStorage::ProcessorStorage() { /* 0x47 EOR [d] */ /* 0x48 PHA s */ /* 0x49 EOR # */ - /* 0x4a LSR A */ + /* 0x4a LSR A */ op(accumulator, LSR); /* 0x4b PHK s */ /* 0x4c JMP a */ op(absolute, JMP); /* 0x4d EOR a */ op(absolute, EOR); - /* 0x4e LSR a */ + /* 0x4e LSR a */ op(absolute_rmw, LSR); /* 0x4f EOR al */ op(absolute_long, EOR); /* 0x50 BVC r */ @@ -386,12 +448,12 @@ ProcessorStorage::ProcessorStorage() { /* 0x56 LSR d, x */ /* 0x57 EOR [d],y */ /* 0x58 CLI i */ - /* 0x59 EOR a, y */ + /* 0x59 EOR a, y */ op(absolute_y, EOR); /* 0x5a PHY s */ /* 0x5b TCD i */ /* 0x5c JMP al */ op(absolute_long_jmp, JML); // [sic]; this updates PBR so it's JML. - /* 0x5d EOR a, x */ - /* 0x5e LSR a, x */ + /* 0x5d EOR a, x */ op(absolute_x, EOR); + /* 0x5e LSR a, x */ op(absolute_x_rmw, LSR); /* 0x5f EOR al, x */ op(absolute_long_x, EOR); /* 0x60 RTS s */ @@ -404,11 +466,11 @@ ProcessorStorage::ProcessorStorage() { /* 0x67 ADC [d] */ /* 0x68 PLA s */ /* 0x69 ADC # */ - /* 0x6a ROR A */ + /* 0x6a ROR A */ op(accumulator, ROR); /* 0x6b RTL s */ /* 0x6c JMP (a) */ op(absolute_indirect_jmp, JMP); /* 0x6d ADC a */ op(absolute, ADC); - /* 0x6e ROR a */ + /* 0x6e ROR a */ op(absolute_rmw, ROR); /* 0x6f ADC al */ op(absolute_long, ADC); /* 0x70 BVS r */ @@ -420,12 +482,12 @@ ProcessorStorage::ProcessorStorage() { /* 0x76 ROR d, x */ /* 0x77 ADC [d], y */ /* 0x78 SEI i */ - /* 0x79 ADC a, y */ + /* 0x79 ADC a, y */ op(absolute_y, ADC); /* 0x7a PLY s */ /* 0x7b TDC i */ /* 0x7c JMP (a, x) */ op(absolute_indexed_indirect_jmp, JMP); - /* 0x7d ADC a, x */ - /* 0x7e ROR a, x */ + /* 0x7d ADC a, x */ op(absolute_x, ADC); + /* 0x7e ROR a, x */ op(absolute_x_rmw, ROR); /* 0x7f ADC al, x */ op(absolute_long_x, ADC); /* 0x80 BRA r */ @@ -454,12 +516,12 @@ ProcessorStorage::ProcessorStorage() { /* 0x96 STX d, y */ /* 0x97 STA [d], y */ /* 0x98 TYA i */ - /* 0x99 STA a, y */ + /* 0x99 STA a, y */ op(absolute_y, STA); /* 0x9a TXS i */ /* 0x9b TXY i */ /* 0x9c STZ a */ op(absolute, STZ); - /* 0x9d STA a, x */ - /* 0x9e STZ a, x */ + /* 0x9d STA a, x */ op(absolute_x, STA); + /* 0x9e STZ a, x */ op(absolute_x, STZ); /* 0x9f STA al, x */ op(absolute_long_x, STA); /* 0xa0 LDY # */ @@ -488,12 +550,12 @@ ProcessorStorage::ProcessorStorage() { /* 0xb6 LDX d, y */ /* 0xb7 LDA [d], y */ /* 0xb8 CLV i */ - /* 0xb9 LDA a, y */ + /* 0xb9 LDA a, y */ op(absolute_y, LDA); /* 0xba TSX i */ /* 0xbb TYX i */ - /* 0xbc LDY a, x */ - /* 0xbd LDA a, x */ - /* 0xbe LDX a, y */ + /* 0xbc LDY a, x */ op(absolute_x, LDY); + /* 0xbd LDA a, x */ op(absolute_x, LDA); + /* 0xbe LDX a, y */ op(absolute_y, LDX); /* 0xbf LDA al, x */ op(absolute_long_x, LDA); /* 0xc0 CPY # */ @@ -510,7 +572,7 @@ ProcessorStorage::ProcessorStorage() { /* 0xcb WAI i */ /* 0xcc CPY a */ op(absolute, CPY); /* 0xcd CMP a */ op(absolute, CMP); - /* 0xce DEC a */ + /* 0xce DEC a */ op(absolute_rmw, DEC); /* 0xcf CMP al */ op(absolute_long, CMP); /* 0xd0 BNE r */ @@ -522,12 +584,12 @@ ProcessorStorage::ProcessorStorage() { /* 0xd6 DEC d, x */ /* 0xd7 CMP [d], y */ /* 0xd8 CLD i */ - /* 0xd9 CMP a, y */ + /* 0xd9 CMP a, y */ op(absolute_y, CMP); /* 0xda PHX s */ /* 0xdb STP i */ /* 0xdc JML (a) */ op(absolute_indirect_jml, JML); - /* 0xdd CMP a, x */ - /* 0xde DEC a, x */ + /* 0xdd CMP a, x */ op(absolute_x, CMP); + /* 0xde DEC a, x */ op(absolute_x_rmw, DEC); /* 0xdf CMP al, x */ op(absolute_long_x, CMP); /* 0xe0 CPX # */ @@ -544,7 +606,7 @@ ProcessorStorage::ProcessorStorage() { /* 0xeb XBA i */ /* 0xec CPX a */ op(absolute, CPX); /* 0xed SBC a */ op(absolute, SBC); - /* 0xee INC a */ + /* 0xee INC a */ op(absolute_rmw, INC); /* 0xef SBC al */ op(absolute_long, SBC); /* 0xf0 BEQ r */ @@ -556,12 +618,12 @@ ProcessorStorage::ProcessorStorage() { /* 0xf6 INC d, x */ /* 0xf7 SBC [d], y */ /* 0xf8 SED i */ - /* 0xf9 SBC a, y */ + /* 0xf9 SBC a, y */ op(absolute_y, SBC); /* 0xfa PLX s */ /* 0xfb XCE i */ /* 0xfc JSR (a, x) */ op(absolute_indexed_indirect_jsr, JMP); // [sic] - /* 0xfd SBC a, x */ - /* 0xfe INC a, x */ + /* 0xfd SBC a, x */ op(absolute_x, SBC); + /* 0xfe INC a, x */ op(absolute_x_rmw, INC); /* 0xff SBC al, x */ op(absolute_long_x, SBC); #undef op diff --git a/Processors/65816/Implementation/65816Storage.hpp b/Processors/65816/Implementation/65816Storage.hpp index e0b6671c3..bb1840d78 100644 --- a/Processors/65816/Implementation/65816Storage.hpp +++ b/Processors/65816/Implementation/65816Storage.hpp @@ -19,6 +19,9 @@ enum MicroOp: uint8_t { CycleFetchData, /// Fetches a byte from the data address to the data buffer and increments the data address. 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. CycleStoreData, @@ -39,6 +42,19 @@ enum MicroOp: uint8_t { OperationConstructAbsoluteIndexedIndirect, 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. OperationPerform, @@ -48,6 +64,9 @@ enum MicroOp: uint8_t { /// Copies the current PBR to the data buffer. OperationCopyPBRToData, + OperationCopyAToData, + OperationCopyDataToA, + /// Complete this set of micr-ops. OperationMoveToNextProgram }; @@ -65,6 +84,9 @@ enum Operation: uint8_t { // they are implicitly AccessType::Write. 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. JMP,