If the opcode targets the Accumulator, then the operand size depends only on the M flag. If the opcode targets X or Y, then it only depends on the X flag. It makes sense to me, but still...
That is correct if an immediate-mode instruction is being disassembled.
Awesome, thanks for the feedback!
PS. Do not try to make sense of the code in the image, I am using a 64kb image of random bytes.
The disassembly of
PEA at
$0006 and
PEI at
$0026 is incorrect. Where are the operands?
Lost in the WDC datasheet I'm afraid.
In Table 5-5 Operation, Operation Codes, and Status Register, both PEA (opcode F4) and PEI (opcode D4) are listed as using the
Stack, s addressing mode. Then...
3.5.22 Stack-s.
Stack (s) addressing refers to all instructions that push or pull data from the stack, such as Push, Pull, Jump to Subroutine, Return from Subroutine, Interrupts, and Return from Interrupt. The bank address is always 0. Interrupt Vectors are always fetched from Bank 0.
Unlike most other addresing modes in the datasheet, gives no indication on how many bytes the operand has. Next source of information was Table 3-1 Addressing Mode Summary which, indeed, says that stack addresing mode opcodes use only 1 byte (So no operand). Other opcodes with this addresing mode (Again, always blindly trusting the datasheet) which I'm familiar with, from my limited experience with the 6502... PHA, PLA, PHX, PLX.... all single byte, no operand, so I didn't even question the other opcodes which were unfamiliar to me.
To be be fair, Table 5-4 Opcode Matrix actually lists PEA and PEI as being 3 bytes and 2 bytes long respectively. I've noticed I've made the same exact mistake with PER.
It's an easy fix though. In the disassembler I have :
Code: Select all
static const char OPCODE_NAMES[256][4] = {
// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
"BRK", "ORA", "COP", "ORA", "TSB", "ORA", "ASL", "ORA", "PHP", "ORA", "ASL", "PHD", "TSB", "ORA", "ASL", "ORA",
"BPL", "ORA", "ORA", "ORA", "TRB", "ORA", "ASL", "ORA", "CLC", "ORA", "INC", "TCS", "TRB", "ORA", "ASL", "ORA",
"JSR", "AND", "JSR", "AND", "BIT", "AND", "ROL", "AND", "PLP", "AND", "ROL", "PLD", "BIT", "AND", "ROL", "AND",
"BMI", "AND", "AND", "AND", "BIT", "AND", "ROL", "AND", "SEC", "AND", "DEC", "TSC", "BIT", "AND", "ROL", "AND",
"RTI", "EOR", "WDM", "EOR", "MVP", "EOR", "LSR", "EOR", "PHA", "EOR", "LSR", "PHK", "JMP", "EOR", "LSR", "EOR",
"BVC", "EOR", "EOR", "EOR", "MVN", "EOR", "LSR", "EOR", "CLI", "EOR", "PHY", "TCD", "JMP", "EOR", "LSR", "EOR",
"RTS", "ADC", "PER", "ADC", "STZ", "ADC", "ROR", "ADC", "PLA", "ADC", "ROR", "RTL", "JMP", "ADC", "ROR", "ADC",
"BVS", "ADC", "ADC", "ADC", "STZ", "ADC", "ROR", "ADC", "SEI", "ADC", "PLY", "TDC", "JMP", "ADC", "ROR", "ADC",
"BRA", "STA", "BRL", "STA", "STY", "STA", "STX", "STA", "DEY", "BIT", "TXA", "PHB", "STY", "STA", "STX", "STA",
"BCC", "STA", "STA", "STA", "STY", "STA", "STX", "STA", "TYA", "STA", "TXS", "TXY", "STZ", "STA", "STZ", "STA",
"LDY", "LDA", "LDX", "LDA", "LDY", "LDA", "LDX", "LDA", "TAY", "LDA", "TAX", "PLB", "LDY", "LDA", "LDX", "LDA",
"BCS", "LDA", "LDA", "LDA", "LDY", "LDA", "LDX", "LDA", "CLV", "LDA", "TSX", "TYX", "LDY", "LDA", "LDX", "LDA",
"CPY", "CMP", "REP", "CMP", "CPY", "CMP", "DEC", "CMP", "INY", "CMP", "DEX", "WAI", "CPY", "CMP", "DEC", "CMP",
"BNE", "CMP", "CMP", "CMP", "PEI", "CMP", "DEC", "CMP", "CLD", "CMP", "PHX", "STP", "JML", "CMP", "DEC", "CMP",
"CPX", "SBC", "SEP", "SBC", "CPX", "SBC", "INC", "SBC", "INX", "SBC", "NOP", "XBA", "CPX", "SBC", "INC", "SBC",
"BEQ", "SBC", "SBC", "SBC", "PEA", "SBC", "INC", "SBC", "SED", "SBC", "PLX", "XCE", "JSR", "SBC", "INC", "SBC"
};
An array for the 256 opcodes.
Code: Select all
typedef enum ADDR_MODE {
NONE = 0, //> NONE, Placeholder // // Non-existant. Just a placeholder
ABSA , //> Absolute // a // 3.5.1 in WDC DataSheet
JAII , //> Absolute Indexed Indirect Jump // (a,x) // 3.5.2 in WDC DataSheet
ABIX , //> Absolute Indexed with X // a,x // 3.5.3 in WDC DataSheet
ABIY , //> Absolute Indexed with Y // a,y // 3.5.4 in WDC DataSheet
ABSI , //> Absolute Indirect // (a) // 3.5.5 in WDC DataSheet
ALIX , //> Absolute Long Indexes with X // al,x // 3.5.6 in WDC DataSheet
ABSL , //> Absolute Long // al // 3.5.7 in WDC DataSheet
ACCU , //> Accumulator // A // 3.5.8 in WDC DataSheet
BLKM , //> Block Move // xyc // 3.5.9 in WDC DataSheet
DIIX , //> Direct Indexed Indirect // (d,x) // 3.5.10 in WDC DataSheet
DINX , //> Direct Indexed with X // d,x // 3.5.11 in WDC DataSheet
DINY , //> Direct Indexed with Y // d,y // 3.5.12 in WDC DataSheet
DIIN , //> Direct Indirect Indexed // (d),y // 3.5.13 in WDC DataSheet
DILI , //> Direct Indirect Long Indexed // [d],y // 3.5.14 in WDC DataSheet
DILO , //> Direct Indirect Long // [d] // 3.5.15 in WDC DataSheet
DIRI , //> Direct Indirect // (d) // 3.5.16 in WDC DataSheet
DIRE , //> Direct // d // 3.5.17 in WDC DataSheet
IMME , //> Immediate // # // 3.5.18 in WDC DataSheet 2 bytes or 3 depending on MX....
// 0000 1001 3 bytes if M = 0 else 2
// 0010 1001
// 0100 1001
// 0110 1001
// 1000 1001
// 1010 1001
// 1100 1001
// 1110 1001
// 1010 0000 3 bytes if X = 0 else 2
// 1010 0010
// 1100 0000
// 1110 0000
// 1100 0010 2 bytes always
// 1110 0010
IMPL , //> Implied // i // 3.5.19 in WDC DataSheet
PCRL , //> Program Counter Relative Long // rl // 3.5.20 in WDC DataSheet
PCRE , //> Program Counter Relative // r // 3.5.21 in WDC DataSheet
STCK , //> Stack // s // 3.5.22 in WDC DataSheet
SREL , //> Stack Relative // d,s // 3.5.23 in WDC DataSheet
SRII , //> Stack Relative Indirect Indexed // (d,s),y // 3.5.24 in WDC DataSheet
} ADDR_MODE;
An enum containing all the addressing modes.
Code: Select all
static const ADDR_MODE OPCODE_ADDRESS_MODES[256] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
STCK, DIIX, STCK, SREL, DIRE, DIRE, DIRE, DILO, STCK, IMME, ACCU, STCK, ABSA, ABSA, ABSA, ABSL, // 0
PCRE, DIIN, DIRI, SRII, DIRE, DINX, DINX, DILI, IMPL, ABIY, ACCU, IMPL, ABSA, ABIX, ABIX, ALIX, // 1
ABSA, DIIX, ABSL, SREL, DIRE, DIRE, DIRE, DILO, STCK, IMME, ACCU, STCK, ABSA, ABSA, ABSA, ABSL, // 2
PCRE, DIIN, DIRI, SRII, DINX, DINX, DINX, DILI, IMPL, ABIY, ACCU, IMPL, ABIX, ABIX, ABIX, ALIX, // 3
STCK, DIIX, IMME, SREL, BLKM, DIRE, DIRE, DILO, STCK, IMME, ACCU, STCK, ABSA, ABSA, ABSA, ABSL, // 4
PCRE, DIIN, DIRI, SRII, BLKM, DINX, DINX, DILI, IMPL, ABIY, STCK, IMPL, ABSL, ABIX, ABIX, ALIX, // 5
STCK, DIIX, STCK, SREL, DIRE, DIRE, DIRE, DILO, STCK, IMME, ACCU, STCK, ABSI, ABSA, ABSA, ABSL, // 6
PCRE, DIIN, DIRI, SRII, DINX, DINX, DINX, DILI, IMPL, ABIY, STCK, IMPL, JAII, ABIX, ABIX, ALIX, // 7
PCRE, DIIX, PCRL, SREL, DIRE, DIRE, DIRE, DILO, IMPL, IMME, IMPL, STCK, ABSA, ABSA, ABSA, ABSL, // 8
PCRE, DIIN, DIRI, SRII, DINX, DINX, DINY, DILI, IMPL, ABIY, IMPL, IMPL, ABSA, ABIX, ABIX, ALIX, // 9
IMME, DIIX, IMME, SREL, DIRE, DIRE, DIRE, DILO, IMPL, IMME, IMPL, STCK, ABSA, ABSA, ABSA, ABSL, // a
PCRE, DIIN, DIRI, SRII, DINX, DINX, DINY, DILI, IMPL, ABIY, IMPL, IMPL, ABIX, ABIX, ABIY, ALIX, // b
IMME, DIIX, IMME, SREL, DIRE, DIRE, DIRE, DILO, IMPL, IMME, IMPL, IMPL, ABSA, ABSA, ABSA, ABSL, // c
PCRE, DIIN, DIRI, SRII, STCK, DINX, DINX, DILI, IMPL, ABIY, STCK, IMPL, ABSI, ABIX, ABIX, ALIX, // D
IMME, DIIX, IMME, SREL, DIRE, DIRE, DIRE, DILO, IMPL, IMME, IMPL, IMPL, ABSA, ABSA, ABSA, ABSL, // E
PCRE, DIIN, DIRI, SRII, STCK, DINX, DINX, DILI, IMPL, ABIY, STCK, IMPL, JAII, ABIX, ABIX, ALIX // F
};
And then, another array containg the addresing mode for each opcode.
Each addresing mode has an associated length, and a printing format. Fixing PEA, PEI and PER it's as simple as adjusting it's addresing mode to the correct one. It's importante to note, this is just for the dissasembler, this is not used in the actual instruction emulation, though it may be a good idea at some point.
The above code still contains the wrong values for those three opcodes. And there may be others. As I implement each one of the opcodes, each one of them will be put to test, so I hope to catch any mistakes, sooner or later.
Cheers!