You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
422 lines
17 KiB
422 lines
17 KiB
/* SharpLr35902.Decode.cpp |
|
* |
|
* Sharp LR35902 instruction decoding. |
|
*/ |
|
|
|
#include <sstream> |
|
|
|
#include "../../PlipEmulationException.h" |
|
#include "../../PlipUtility.h" |
|
|
|
#include "SharpLr35902.h" |
|
#include "SharpLr35902.Macros.h" |
|
|
|
namespace Plip::Cpu { |
|
void SharpLr35902::Decode() { |
|
switch(m_instr[0]) { |
|
/* |
|
* Non-parameterized opcodes. |
|
*/ |
|
|
|
// NOP |
|
case 0b00000000: |
|
NUM_MCYCLES(2); break; |
|
|
|
// 0xCB |
|
case 0b11001011: |
|
CYCLE(2) { FETCH; m_mcycle++; } |
|
else { DecodeCB(); } |
|
break; |
|
|
|
// RLCA |
|
case 0b00000111: |
|
OpAccumRotateLeft(); break; |
|
|
|
// LD (nn), SP |
|
case 0b00001000: |
|
OpLdMemSp(); break; |
|
|
|
// RRCA |
|
case 0b00001111: |
|
OpAccumRotateRight(); break; |
|
|
|
// STOP |
|
case 0b00010000: |
|
OpStop(); break; |
|
|
|
// JR e |
|
case 0b00011000: |
|
OpJumpRelUnc(); break; |
|
|
|
// RLA |
|
case 0b00010111: |
|
OpAccumRotateLeftThruCarry(); break; |
|
|
|
// RRA |
|
case 0b00011111: |
|
OpAccumRotateRightThruCarry(); break; |
|
|
|
// DAA |
|
case 0b00100111: |
|
OpAccumBcd(); break; |
|
|
|
// CPL |
|
case 0b00101111: |
|
OpAccumFlip(); break; |
|
|
|
// SCF |
|
case 0b00110111: |
|
OpSetCarry(); break; |
|
|
|
// CCF |
|
case 0b00111111: |
|
OpFlipCarry(); break; |
|
|
|
// HALT |
|
case 0b01110110: |
|
OpHalt(); break; |
|
|
|
// ADD A, n |
|
case 0b11000110: |
|
OpAccumAddImm(); break; |
|
|
|
// RET |
|
case 0b11001001: |
|
OpRetUnc(); break; |
|
|
|
// JP nn |
|
case 0b11000011: |
|
OpJumpAbsUnc(); break; |
|
|
|
// CALL nn |
|
case 0b11001101: |
|
OpCallUnc(); break; |
|
|
|
// ADC A, n |
|
case 0b11001110: |
|
OpAccumAddCarryImm(); break; |
|
|
|
// RETI |
|
case 0b11011001: |
|
OpRetImeUnc(); break; |
|
|
|
// SUB A, n |
|
case 0b11010110: |
|
OpAccumSubImm(); break; |
|
|
|
// SBC A, n |
|
case 0b11011110: |
|
OpAccumSubBorrowImm(); break; |
|
|
|
// LDH (n), A |
|
case 0b11100000: |
|
OpLdMemHighImmAccum(); break; |
|
|
|
// LDH (C), A |
|
case 0b11100010: |
|
OpLdMemHighCAccum(); break; |
|
|
|
// AND n |
|
case 0b11100110: |
|
OpAccumAndImm(); break; |
|
|
|
// ADD SP, e |
|
case 0b11101000: |
|
OpAddSpOffset(); break; |
|
|
|
// JP (HL) |
|
case 0b11101001: |
|
OpJumpRegUnc(); break; |
|
|
|
// LD (nn), A |
|
case 0b11101010: |
|
OpLdMemAccum(); break; |
|
|
|
// XOR n |
|
case 0b11101110: |
|
OpAccumXorImm(); break; |
|
|
|
// LDH A, (n) |
|
case 0b11110000: |
|
OpLdAccumMemHighImm(); break; |
|
|
|
// OR n |
|
case 0b11110110: |
|
OpAccumOrImm(); break; |
|
|
|
// LDH A, (C) |
|
case 0b11110010: |
|
OpLdAccumMemHighC(); break; |
|
|
|
// DI |
|
case 0b11110011: |
|
OpDisableInterrupts(); break; |
|
|
|
// LD HL, SP+e |
|
case 0b11111000: |
|
OpLdHlSpOffset(); break; |
|
|
|
// LD SP, HL |
|
case 0b11111001: |
|
OpLdSpHl(); break; |
|
|
|
// LD A, (nn) |
|
case 0b11111010: |
|
OpLdAccumMem(); break; |
|
|
|
// EI |
|
case 0b11111011: |
|
OpEnableInterrupts(); break; |
|
|
|
// CP n |
|
case 0b11111110: |
|
OpAccumCarryImm(); break; |
|
|
|
/* |
|
* Parameterized opcodes. |
|
*/ |
|
|
|
// INC r (mask: 0b11000111, op: 0b00000100) |
|
case 0b00000100: case 0b00001100: case 0b00010100: case 0b00011100: |
|
case 0b00100100: case 0b00101100: case 0b00110100: case 0b00111100: |
|
OpIncReg(); break; |
|
|
|
// DEC r (mask: 0b11000111, op: 0b00000101) |
|
case 0b00000101: case 0b00001101: case 0b00010101: case 0b00011101: |
|
case 0b00100101: case 0b00101101: case 0b00110101: case 0b00111101: |
|
OpDecReg(); break; |
|
|
|
// INC rr (mask: 0b11001111, op: 0b00000011) |
|
case 0b00000011: case 0b00010011: case 0b00100011: case 0b00110011: |
|
OpIncPair(); break; |
|
|
|
// DEC rr (mask: 0b11001111, op: 0b00001011) |
|
case 0b00001011: case 0b00011011: case 0b00101011: case 0b00111011: |
|
OpDecPair(); break; |
|
|
|
// LD r, r' / LD r, (HL) / LD (HL), r |
|
// (mask: 0b11000000, 0b01000000) |
|
case 0b01000000: case 0b01000001: case 0b01000010: case 0b01000011: |
|
case 0b01000100: case 0b01000101: case 0b01000110: case 0b01000111: |
|
case 0b01001000: case 0b01001001: case 0b01001010: case 0b01001011: |
|
case 0b01001100: case 0b01001101: case 0b01001110: case 0b01001111: |
|
case 0b01010000: case 0b01010001: case 0b01010010: case 0b01010011: |
|
case 0b01010100: case 0b01010101: case 0b01010110: case 0b01010111: |
|
case 0b01011000: case 0b01011001: case 0b01011010: case 0b01011011: |
|
case 0b01011100: case 0b01011101: case 0b01011110: case 0b01011111: |
|
case 0b01100000: case 0b01100001: case 0b01100010: case 0b01100011: |
|
case 0b01100100: case 0b01100101: case 0b01100110: case 0b01100111: |
|
case 0b01101000: case 0b01101001: case 0b01101010: case 0b01101011: |
|
case 0b01101100: case 0b01101101: case 0b01101110: case 0b01101111: |
|
case 0b01110000: case 0b01110001: case 0b01110010: case 0b01110011: |
|
case 0b01110100: case 0b01110101: /* 0b01110110 */ case 0b01110111: |
|
case 0b01111000: case 0b01111001: case 0b01111010: case 0b01111011: |
|
case 0b01111100: case 0b01111101: case 0b01111110: case 0b01111111: |
|
OpLdRegReg(); break; |
|
|
|
// LD r, n (mask: 0b11000111, op: 0b00000110) |
|
case 0b00000110: case 0b00001110: case 0b00010110: case 0b00011110: |
|
case 0b00100110: case 0b00101110: case 0b00110110: case 0b00111110: |
|
OpLdRegImm(); break; |
|
|
|
// LD A, (rr) (mask: 0b11001111, op: 0b00001010) |
|
case 0b00001010: case 0b00011010: case 0b00101010: case 0b00111010: |
|
OpLdRegMem(); break; |
|
|
|
// LD (rr), A (mask: 0b11001111, op: 0b00000010) |
|
case 0b00000010: case 0b00010010: case 0b00100010: case 0b00110010: |
|
OpLdMemReg(); break; |
|
|
|
// LD rr, nn (mask: 0b11001111, op: 0b00000001) |
|
case 0b00000001: case 0b00010001: case 0b00100001: case 0b00110001: |
|
OpLdReg16Imm16(); break; |
|
|
|
// JR cc, e (mask: 0b11100111, op: 0b00100000) |
|
case 0b00100000: case 0b00101000: case 0b00110000: case 0b00111000: |
|
OpJumpRelCond(); break; |
|
|
|
// ADD A, r (mask: 0b11111000, op: 0b10000000) |
|
case 0b10000000: case 0b10000001: case 0b10000010: case 0b10000011: |
|
case 0b10000100: case 0b10000101: case 0b10000110: case 0b10000111: |
|
OpAdd(); break; |
|
|
|
// ADD HL, rr (mask: 0b11001111, op: 0b00001001) |
|
case 0b00001001: case 0b00011001: case 0b00101001: case 0b00111001: |
|
OpAdd16(); break; |
|
|
|
// ADC A, r (mask: 0b11111000, op: 0b10001000) |
|
case 0b10001000: case 0b10001001: case 0b10001010: case 0b10001011: |
|
case 0b10001100: case 0b10001101: case 0b10001110: case 0b10001111: |
|
OpAddCarry(); break; |
|
|
|
// SUB A, r (mask: 0b11111000, 0b10010000) |
|
case 0b10010000: case 0b10010001: case 0b10010010: case 0b10010011: |
|
case 0b10010100: case 0b10010101: case 0b10010110: case 0b10010111: |
|
OpSub(); break; |
|
|
|
// SBC A, r (mask: 0b11111000, 0b10011000) |
|
case 0b10011000: case 0b10011001: case 0b10011010: case 0b10011011: |
|
case 0b10011100: case 0b10011101: case 0b10011110: case 0b10011111: |
|
OpSubBorrow(); break; |
|
|
|
// AND r (mask: 0b11111000, 0b10100000) |
|
case 0b10100000: case 0b10100001: case 0b10100010: case 0b10100011: |
|
case 0b10100100: case 0b10100101: case 0b10100110: case 0b10100111: |
|
OpAnd(); break; |
|
|
|
// XOR r (mask: 0b11111000, op: 0b10101000) |
|
case 0b10101000: case 0b10101001: case 0b10101010: case 0b10101011: |
|
case 0b10101100: case 0b10101101: case 0b10101110: case 0b10101111: |
|
OpXor(); break; |
|
|
|
// OR r (mask: 0b11111000, op: 0b10110000) |
|
case 0b10110000: case 0b10110001: case 0b10110010: case 0b10110011: |
|
case 0b10110100: case 0b10110101: case 0b10110110: case 0b10110111: |
|
OpOr(); break; |
|
|
|
// CP r (mask: 0b11111000, op: 0b10111000)) |
|
case 0b10111000: case 0b10111001: case 0b10111010: case 0b10111011: |
|
case 0b10111100: case 0b10111101: case 0b10111110: case 0b10111111: |
|
OpCarry(); break; |
|
|
|
// RET cc (mask: 0b11100111, op: 0b11000000) |
|
case 0b11000000: case 0b11001000: case 0b11010000: case 0b11011000: |
|
OpRetCond(); break; |
|
|
|
// JP cc, nn (mask: 0b11100111, op: 0b11000010) |
|
case 0b11000010: case 0b11001010: case 0b11010010: case 0b11011010: |
|
OpJumpAbsCond(); break; |
|
|
|
// CALL cc, nn (mask: 0b11100111, op: 0b11000100) |
|
case 0b11000100: case 0b11001100: case 0b11010100: case 0b11011100: |
|
OpCallCond(); break; |
|
|
|
// POP rr (mask: 0b11001111, op: 0b11000001) |
|
case 0b11000001: case 0b11010001: case 0b11100001: case 0b11110001: |
|
OpPopReg16(); break; |
|
|
|
// PUSH rr (mask: 0b11001111, op: 0b11000101) |
|
case 0b11000101: case 0b11010101: case 0b11100101: case 0b11110101: |
|
OpPushReg16(); break; |
|
|
|
// RST [00h, 08h, 10h, 18h, 20h, 28h, 30h, 38h] |
|
// (mask: 0b11000111, op: 0b11000111) |
|
case 0b11000111: case 0b11001111: case 0b11010111: case 0b11011111: |
|
case 0b11100111: case 0b11101111: case 0b11110111: case 0b11111111: |
|
OpFuncFixedUnc(); break; |
|
|
|
default: |
|
std::stringstream ex; |
|
ex << "unknown opcode: " << PlipUtility::FormatHex(m_instr[0], 2) |
|
<< "\n\n" << DumpRegisters(); |
|
throw PlipEmulationException(ex.str().c_str()); |
|
} |
|
} |
|
|
|
void SharpLr35902::DecodeCB() { |
|
switch(m_instr[1]) { |
|
// RLC r (mask: 0b11111000, op: 0b00000000) |
|
case 0b00000000: case 0b00000001: case 0b00000010: case 0b00000011: |
|
case 0b00000100: case 0b00000101: case 0b00000110: case 0b00000111: |
|
OpRotateLeft(); break; |
|
|
|
// RRC r (mask: 0b11111000, op: 0b00001000) |
|
case 0b00001000: case 0b00001001: case 0b00001010: case 0b00001011: |
|
case 0b00001100: case 0b00001101: case 0b00001110: case 0b00001111: |
|
OpRotateRight(); break; |
|
|
|
// RL r (mask: 0b11111000, op: 0b00010000) |
|
case 0b00010000: case 0b00010001: case 0b00010010: case 0b00010011: |
|
case 0b00010100: case 0b00010101: case 0b00010110: case 0b00010111: |
|
OpRotateLeftThruCarry(); break; |
|
|
|
// RR r (mask: 0b11111000, op: 0b00011000) |
|
case 0b00011000: case 0b00011001: case 0b00011010: case 0b00011011: |
|
case 0b00011100: case 0b00011101: case 0b00011110: case 0b00011111: |
|
OpRotateRightThruCarry(); break; |
|
|
|
// SLA r (mask: 0b11111000, op: 0b00100000) |
|
case 0b00100000: case 0b00100001: case 0b00100010: case 0b00100011: |
|
case 0b00100100: case 0b00100101: case 0b00100110: case 0b00100111: |
|
OpShiftLeftArithmetic(); break; |
|
|
|
// SRA r (mask: 0b11111000, op: 0b00101000) |
|
case 0b00101000: case 0b00101001: case 0b00101010: case 0b00101011: |
|
case 0b00101100: case 0b00101101: case 0b00101110: case 0b00101111: |
|
OpShiftRightArithmetic(); break; |
|
|
|
// SWAP r (mask: 0b11111000, op: 0b00110000) |
|
case 0b00110000: case 0b00110001: case 0b00110010: case 0b00110011: |
|
case 0b00110100: case 0b00110101: case 0b00110110: case 0b00110111: |
|
OpNibbleSwap(); break; |
|
|
|
// SRL r (mask: 0b11111000, op: 0b00111000) |
|
case 0b00111000: case 0b00111001: case 0b00111010: case 0b00111011: |
|
case 0b00111100: case 0b00111101: case 0b00111110: case 0b00111111: |
|
OpShiftRightLogical(); break; |
|
|
|
// BIT n, r (mask: 0b11000000, op: 0b01000000) |
|
case 0b01000000: case 0b01000001: case 0b01000010: case 0b01000011: |
|
case 0b01000100: case 0b01000101: case 0b01000110: case 0b01000111: |
|
case 0b01001000: case 0b01001001: case 0b01001010: case 0b01001011: |
|
case 0b01001100: case 0b01001101: case 0b01001110: case 0b01001111: |
|
case 0b01010000: case 0b01010001: case 0b01010010: case 0b01010011: |
|
case 0b01010100: case 0b01010101: case 0b01010110: case 0b01010111: |
|
case 0b01011000: case 0b01011001: case 0b01011010: case 0b01011011: |
|
case 0b01011100: case 0b01011101: case 0b01011110: case 0b01011111: |
|
case 0b01100000: case 0b01100001: case 0b01100010: case 0b01100011: |
|
case 0b01100100: case 0b01100101: case 0b01100110: case 0b01100111: |
|
case 0b01101000: case 0b01101001: case 0b01101010: case 0b01101011: |
|
case 0b01101100: case 0b01101101: case 0b01101110: case 0b01101111: |
|
case 0b01110000: case 0b01110001: case 0b01110010: case 0b01110011: |
|
case 0b01110100: case 0b01110101: case 0b01110110: case 0b01110111: |
|
case 0b01111000: case 0b01111001: case 0b01111010: case 0b01111011: |
|
case 0b01111100: case 0b01111101: case 0b01111110: case 0b01111111: |
|
OpBitTest(); break; |
|
|
|
// RES n, r (mask: 0b11000000, op: 0b10000000) |
|
case 0b10000000: case 0b10000001: case 0b10000010: case 0b10000011: |
|
case 0b10000100: case 0b10000101: case 0b10000110: case 0b10000111: |
|
case 0b10001000: case 0b10001001: case 0b10001010: case 0b10001011: |
|
case 0b10001100: case 0b10001101: case 0b10001110: case 0b10001111: |
|
case 0b10010000: case 0b10010001: case 0b10010010: case 0b10010011: |
|
case 0b10010100: case 0b10010101: case 0b10010110: case 0b10010111: |
|
case 0b10011000: case 0b10011001: case 0b10011010: case 0b10011011: |
|
case 0b10011100: case 0b10011101: case 0b10011110: case 0b10011111: |
|
case 0b10100000: case 0b10100001: case 0b10100010: case 0b10100011: |
|
case 0b10100100: case 0b10100101: case 0b10100110: case 0b10100111: |
|
case 0b10101000: case 0b10101001: case 0b10101010: case 0b10101011: |
|
case 0b10101100: case 0b10101101: case 0b10101110: case 0b10101111: |
|
case 0b10110000: case 0b10110001: case 0b10110010: case 0b10110011: |
|
case 0b10110100: case 0b10110101: case 0b10110110: case 0b10110111: |
|
case 0b10111000: case 0b10111001: case 0b10111010: case 0b10111011: |
|
case 0b10111100: case 0b10111101: case 0b10111110: case 0b10111111: |
|
OpBitClear(); break; |
|
|
|
// SET n, r (mask: 0b11000000, op: 0b11000000) |
|
case 0b11000000: case 0b11000001: case 0b11000010: case 0b11000011: |
|
case 0b11000100: case 0b11000101: case 0b11000110: case 0b11000111: |
|
case 0b11001000: case 0b11001001: case 0b11001010: case 0b11001011: |
|
case 0b11001100: case 0b11001101: case 0b11001110: case 0b11001111: |
|
case 0b11010000: case 0b11010001: case 0b11010010: case 0b11010011: |
|
case 0b11010100: case 0b11010101: case 0b11010110: case 0b11010111: |
|
case 0b11011000: case 0b11011001: case 0b11011010: case 0b11011011: |
|
case 0b11011100: case 0b11011101: case 0b11011110: case 0b11011111: |
|
case 0b11100000: case 0b11100001: case 0b11100010: case 0b11100011: |
|
case 0b11100100: case 0b11100101: case 0b11100110: case 0b11100111: |
|
case 0b11101000: case 0b11101001: case 0b11101010: case 0b11101011: |
|
case 0b11101100: case 0b11101101: case 0b11101110: case 0b11101111: |
|
case 0b11110000: case 0b11110001: case 0b11110010: case 0b11110011: |
|
case 0b11110100: case 0b11110101: case 0b11110110: case 0b11110111: |
|
case 0b11111000: case 0b11111001: case 0b11111010: case 0b11111011: |
|
case 0b11111100: case 0b11111101: case 0b11111110: case 0b11111111: |
|
OpBitSet(); break; |
|
|
|
default: |
|
std::stringstream ex; |
|
ex << "unknown opcode: 0xCB " << PlipUtility::FormatHex(m_instr[1], 2) |
|
<< "\n\n" << DumpRegisters(); |
|
throw PlipEmulationException(ex.str().c_str()); |
|
} |
|
} |
|
}
|
|
|