Add addressing modes and opcodes for SPC700
This commit is contained in:
@@ -11,41 +11,59 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
|||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
// 8-bit Move Memory to Register
|
// 8-bit Move Memory to Register
|
||||||
case 0xE8: // MOV A, #imm
|
case 0xE8: // MOV A, #imm
|
||||||
MOV(A, true);
|
MOV(A, imm());
|
||||||
break;
|
break;
|
||||||
case 0xE6: // MOV A, (X)
|
case 0xE6: // MOV A, (X)
|
||||||
|
MOV(A, X);
|
||||||
break;
|
break;
|
||||||
case 0xBF: // MOV A, (X)+
|
case 0xBF: // MOV A, (X)+
|
||||||
|
MOV(A, X);
|
||||||
|
X++;
|
||||||
break;
|
break;
|
||||||
case 0xE4: // MOV A, dp
|
case 0xE4: // MOV A, dp
|
||||||
|
MOV(A, dp());
|
||||||
break;
|
break;
|
||||||
case 0xF4: // MOV A, dp+X
|
case 0xF4: // MOV A, dp+X
|
||||||
|
MOV(A, dp_plus_x());
|
||||||
break;
|
break;
|
||||||
case 0xE5: // MOV A, !abs
|
case 0xE5: // MOV A, !abs
|
||||||
|
MOV(A, abs());
|
||||||
break;
|
break;
|
||||||
case 0xF5: // MOV A, !abs+X
|
case 0xF5: // MOV A, !abs+X
|
||||||
|
MOV(A, abs() + X);
|
||||||
break;
|
break;
|
||||||
case 0xF6: // MOV A, !abs+Y
|
case 0xF6: // MOV A, !abs+Y
|
||||||
|
MOV(A, abs() + Y);
|
||||||
break;
|
break;
|
||||||
case 0xE7: // MOV A, [dp+X]
|
case 0xE7: // MOV A, [dp+X]
|
||||||
|
MOV(A, read(dp_plus_x_indirect()));
|
||||||
break;
|
break;
|
||||||
case 0xF7: // MOV A, [dp]+Y
|
case 0xF7: // MOV A, [dp]+Y
|
||||||
|
MOV(A, read(dp_indirect_plus_y()));
|
||||||
break;
|
break;
|
||||||
case 0xCD: // MOV X, #imm
|
case 0xCD: // MOV X, #imm
|
||||||
|
MOV(X, imm());
|
||||||
break;
|
break;
|
||||||
case 0xF8: // MOV X, dp
|
case 0xF8: // MOV X, dp
|
||||||
|
MOV(X, dp());
|
||||||
break;
|
break;
|
||||||
case 0xF9: // MOV X, dp+Y
|
case 0xF9: // MOV X, dp+Y
|
||||||
|
MOV(X, dp_plus_y());
|
||||||
break;
|
break;
|
||||||
case 0xE9: // MOV X, !abs
|
case 0xE9: // MOV X, !abs
|
||||||
|
MOV(X, abs());
|
||||||
break;
|
break;
|
||||||
case 0x8D: // MOV Y, #imm
|
case 0x8D: // MOV Y, #imm
|
||||||
|
MOV(Y, imm());
|
||||||
break;
|
break;
|
||||||
case 0xEB: // MOV Y, dp
|
case 0xEB: // MOV Y, dp
|
||||||
|
MOV(Y, dp());
|
||||||
break;
|
break;
|
||||||
case 0xFB: // MOV Y, dp+X
|
case 0xFB: // MOV Y, dp+X
|
||||||
|
MOV(Y, dp_plus_x());
|
||||||
break;
|
break;
|
||||||
case 0xEC: // MOV Y, !abs
|
case 0xEC: // MOV Y, !abs
|
||||||
|
MOV(Y, abs());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// 8-bit move register to memory
|
// 8-bit move register to memory
|
||||||
@@ -55,30 +73,43 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
|||||||
case 0xAF: // MOV (X)+, A
|
case 0xAF: // MOV (X)+, A
|
||||||
break;
|
break;
|
||||||
case 0xC4: // MOV dp, A
|
case 0xC4: // MOV dp, A
|
||||||
|
MOV_ADDR(get_dp_addr(), A);
|
||||||
break;
|
break;
|
||||||
case 0xD4: // MOV dp+X, A
|
case 0xD4: // MOV dp+X, A
|
||||||
|
MOV_ADDR(get_dp_addr() + X, A);
|
||||||
break;
|
break;
|
||||||
case 0xC5: // MOV !abs, A
|
case 0xC5: // MOV !abs, A
|
||||||
|
MOV_ADDR(abs(), A);
|
||||||
break;
|
break;
|
||||||
case 0xD5: // MOV !abs+X, A
|
case 0xD5: // MOV !abs+X, A
|
||||||
|
MOV_ADDR(abs() + X, A);
|
||||||
break;
|
break;
|
||||||
case 0xD6: // MOV !abs+Y, A
|
case 0xD6: // MOV !abs+Y, A
|
||||||
|
MOV_ADDR(abs() + Y, A);
|
||||||
break;
|
break;
|
||||||
case 0xC7: // MOV [dp+X], A
|
case 0xC7: // MOV [dp+X], A
|
||||||
|
MOV_ADDR(dp_plus_x_indirect(), A);
|
||||||
break;
|
break;
|
||||||
case 0xD7: // MOV [dp]+Y, A
|
case 0xD7: // MOV [dp]+Y, A
|
||||||
|
MOV_ADDR(dp_indirect_plus_y(), A);
|
||||||
break;
|
break;
|
||||||
case 0xD8: // MOV dp, X
|
case 0xD8: // MOV dp, X
|
||||||
|
MOV_ADDR(get_dp_addr(), X);
|
||||||
break;
|
break;
|
||||||
case 0xD9: // MOV dp+Y, X
|
case 0xD9: // MOV dp+Y, X
|
||||||
|
MOV_ADDR(get_dp_addr() + Y, X);
|
||||||
break;
|
break;
|
||||||
case 0xC9: // MOV !abs, X
|
case 0xC9: // MOV !abs, X
|
||||||
|
MOV_ADDR(abs(), X);
|
||||||
break;
|
break;
|
||||||
case 0xCB: // MOV dp, Y
|
case 0xCB: // MOV dp, Y
|
||||||
|
MOV_ADDR(get_dp_addr(), Y);
|
||||||
break;
|
break;
|
||||||
case 0xDB: // MOV dp+X, Y
|
case 0xDB: // MOV dp+X, Y
|
||||||
|
MOV_ADDR(get_dp_addr() + X, Y);
|
||||||
break;
|
break;
|
||||||
case 0xCC: // MOV !abs, Y
|
case 0xCC: // MOV !abs, Y
|
||||||
|
MOV_ADDR(abs(), Y);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// . 8-bit move register to register / special direct page moves
|
// . 8-bit move register to register / special direct page moves
|
||||||
@@ -103,22 +134,28 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
|||||||
// . 8-bit arithmetic
|
// . 8-bit arithmetic
|
||||||
|
|
||||||
case 0x88: // ADC A, #imm
|
case 0x88: // ADC A, #imm
|
||||||
|
ADC(A, imm());
|
||||||
break;
|
break;
|
||||||
case 0x86: // ADC A, (X)
|
case 0x86: // ADC A, (X)
|
||||||
break;
|
break;
|
||||||
case 0x84: // ADC A, dp
|
case 0x84: // ADC A, dp
|
||||||
|
ADC(A, dp());
|
||||||
break;
|
break;
|
||||||
case 0x94: // ADC A, dp+X
|
case 0x94: // ADC A, dp+X
|
||||||
|
ADC(A, dp_plus_x());
|
||||||
break;
|
break;
|
||||||
case 0x85: // ADC A, !abs
|
case 0x85: // ADC A, !abs
|
||||||
|
ADC(A, abs());
|
||||||
break;
|
break;
|
||||||
case 0x95: // ADC A, !abs+X
|
case 0x95: // ADC A, !abs+X
|
||||||
break;
|
break;
|
||||||
case 0x96: // ADC A, !abs+Y
|
case 0x96: // ADC A, !abs+Y
|
||||||
break;
|
break;
|
||||||
case 0x87: // ADC A, [dp+X]
|
case 0x87: // ADC A, [dp+X]
|
||||||
|
ADC(A, dp_plus_x_indirect());
|
||||||
break;
|
break;
|
||||||
case 0x97: // ADC A, [dp]+Y
|
case 0x97: // ADC A, [dp]+Y
|
||||||
|
ADC(A, dp_indirect_plus_y());
|
||||||
break;
|
break;
|
||||||
case 0x99: // ADC (X), (Y)
|
case 0x99: // ADC (X), (Y)
|
||||||
break;
|
break;
|
||||||
@@ -127,6 +164,7 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
|||||||
case 0x98: // ADC dp, #imm
|
case 0x98: // ADC dp, #imm
|
||||||
break;
|
break;
|
||||||
case 0xA8: // SBC A, #imm
|
case 0xA8: // SBC A, #imm
|
||||||
|
SBC(A, imm());
|
||||||
break;
|
break;
|
||||||
case 0xA6: // SBC A, (X)
|
case 0xA6: // SBC A, (X)
|
||||||
break;
|
break;
|
||||||
@@ -214,14 +252,18 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
|||||||
case 0x38: // AND dp, #imm
|
case 0x38: // AND dp, #imm
|
||||||
break;
|
break;
|
||||||
case 0x08: // OR A, #imm
|
case 0x08: // OR A, #imm
|
||||||
|
OR(A, imm());
|
||||||
break;
|
break;
|
||||||
case 0x06: // OR A, (X)
|
case 0x06: // OR A, (X)
|
||||||
break;
|
break;
|
||||||
case 0x04: // OR A, dp
|
case 0x04: // OR A, dp
|
||||||
|
OR(A, dp());
|
||||||
break;
|
break;
|
||||||
case 0x14: // OR A, dp+X
|
case 0x14: // OR A, dp+X
|
||||||
|
OR(A, dp_plus_x());
|
||||||
break;
|
break;
|
||||||
case 0x05: // OR A, !abs
|
case 0x05: // OR A, !abs
|
||||||
|
OR(A, abs());
|
||||||
break;
|
break;
|
||||||
case 0x15: // OR A, !abs+X
|
case 0x15: // OR A, !abs+X
|
||||||
break;
|
break;
|
||||||
@@ -238,10 +280,12 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
|||||||
case 0x18: // OR dp, #imm
|
case 0x18: // OR dp, #imm
|
||||||
break;
|
break;
|
||||||
case 0x48: // EOR A, #imm
|
case 0x48: // EOR A, #imm
|
||||||
|
EOR(A, imm());
|
||||||
break;
|
break;
|
||||||
case 0x46: // EOR A, (X)
|
case 0x46: // EOR A, (X)
|
||||||
break;
|
break;
|
||||||
case 0x44: // EOR A, dp
|
case 0x44: // EOR A, dp
|
||||||
|
EOR(A, dp());
|
||||||
break;
|
break;
|
||||||
case 0x54: // EOR A, dp+X
|
case 0x54: // EOR A, dp+X
|
||||||
break;
|
break;
|
||||||
@@ -265,6 +309,7 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
|||||||
// . 8-bit increment / decrement
|
// . 8-bit increment / decrement
|
||||||
|
|
||||||
case 0xBC: // INC A
|
case 0xBC: // INC A
|
||||||
|
INC(A);
|
||||||
break;
|
break;
|
||||||
case 0xAB: // INC dp
|
case 0xAB: // INC dp
|
||||||
break;
|
break;
|
||||||
@@ -273,10 +318,13 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
|||||||
case 0xAC: // INC !abs
|
case 0xAC: // INC !abs
|
||||||
break;
|
break;
|
||||||
case 0x3D: // INC X
|
case 0x3D: // INC X
|
||||||
|
INC(X);
|
||||||
break;
|
break;
|
||||||
case 0xFC: // INC Y
|
case 0xFC: // INC Y
|
||||||
|
INC(Y);
|
||||||
break;
|
break;
|
||||||
case 0x9C: // DEC A
|
case 0x9C: // DEC A
|
||||||
|
DEC(A);
|
||||||
break;
|
break;
|
||||||
case 0x8B: // DEC dp
|
case 0x8B: // DEC dp
|
||||||
break;
|
break;
|
||||||
@@ -285,21 +333,28 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
|||||||
case 0x8C: // DEC !abs
|
case 0x8C: // DEC !abs
|
||||||
break;
|
break;
|
||||||
case 0x1D: // DEC X
|
case 0x1D: // DEC X
|
||||||
|
DEC(X);
|
||||||
break;
|
break;
|
||||||
case 0xDC: // DEC Y
|
case 0xDC: // DEC Y
|
||||||
|
DEC(Y);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// 8-bit shift / rotation
|
// 8-bit shift / rotation
|
||||||
|
|
||||||
case 0x1C: // ASL A
|
case 0x1C: // ASL A
|
||||||
|
ASL(A);
|
||||||
break;
|
break;
|
||||||
case 0x0B: // ASL dp
|
case 0x0B: // ASL dp
|
||||||
|
ASL(dp());
|
||||||
break;
|
break;
|
||||||
case 0x1B: // ASL dp+X
|
case 0x1B: // ASL dp+X
|
||||||
|
ASL(dp_plus_x());
|
||||||
break;
|
break;
|
||||||
case 0x0C: // ASL !abs
|
case 0x0C: // ASL !abs
|
||||||
|
ASL(abs());
|
||||||
break;
|
break;
|
||||||
case 0x5C: // LSR A
|
case 0x5C: // LSR A
|
||||||
|
LSR(A);
|
||||||
break;
|
break;
|
||||||
case 0x4B: // LSR dp
|
case 0x4B: // LSR dp
|
||||||
break;
|
break;
|
||||||
@@ -324,6 +379,7 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
|||||||
case 0x6C: // ROR !abs
|
case 0x6C: // ROR !abs
|
||||||
break;
|
break;
|
||||||
case 0x9F: // XCN A Exchange nibbles of A
|
case 0x9F: // XCN A Exchange nibbles of A
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// . 16-bit operations
|
// . 16-bit operations
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ class VirtualAudioRAM {
|
|||||||
|
|
||||||
class AudioRAM : public VirtualAudioRAM {
|
class AudioRAM : public VirtualAudioRAM {
|
||||||
static const size_t ARAM_SIZE = 64 * 1024; // 64 KB
|
static const size_t ARAM_SIZE = 64 * 1024; // 64 KB
|
||||||
std::vector<uint8_t> ram;
|
std::vector<uint8_t> ram = std::vector<uint8_t>(ARAM_SIZE, 0);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AudioRAM() : ram(ARAM_SIZE, 0) {}
|
AudioRAM() = default;
|
||||||
|
|
||||||
// Read a byte from ARAM at the given address
|
// Read a byte from ARAM at the given address
|
||||||
uint8_t read(uint16_t address) const override {
|
uint8_t read(uint16_t address) const override {
|
||||||
@@ -38,39 +38,40 @@ class AudioRAM : public VirtualAudioRAM {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDSP {
|
// Digital Signal Processor
|
||||||
|
class DigitalSignalProcessor {
|
||||||
|
private:
|
||||||
static const size_t NUM_VOICES = 8;
|
static const size_t NUM_VOICES = 8;
|
||||||
static const size_t NUM_VOICE_REGS = 10;
|
static const size_t NUM_VOICE_REGS = 10;
|
||||||
static const size_t NUM_GLOBAL_REGS = 15;
|
static const size_t NUM_GLOBAL_REGS = 15;
|
||||||
|
|
||||||
// Each voice has 10 registers
|
// Each voice has 10 registers
|
||||||
std::vector<std::vector<uint8_t>> voices;
|
std::vector<std::vector<uint8_t>> voices = std::vector<std::vector<uint8_t>>(
|
||||||
|
NUM_VOICES, std::vector<uint8_t>(NUM_VOICE_REGS, 0));
|
||||||
|
|
||||||
// Global registers
|
// Global registers
|
||||||
std::vector<uint8_t> globalRegs;
|
std::vector<uint8_t> globalRegs = std::vector<uint8_t>(NUM_GLOBAL_REGS, 0x00);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SDSP()
|
DigitalSignalProcessor() = default;
|
||||||
: voices(NUM_VOICES, std::vector<uint8_t>(NUM_VOICE_REGS, 0)),
|
|
||||||
globalRegs(NUM_GLOBAL_REGS, 0) {}
|
|
||||||
|
|
||||||
// Read a byte from a voice register
|
// Read a byte from a voice register
|
||||||
uint8_t readVoiceReg(uint8_t voice, uint8_t reg) const {
|
uint8_t ReadVoiceReg(uint8_t voice, uint8_t reg) const {
|
||||||
return voices[voice % NUM_VOICES][reg % NUM_VOICE_REGS];
|
return voices[voice % NUM_VOICES][reg % NUM_VOICE_REGS];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write a byte to a voice register
|
// Write a byte to a voice register
|
||||||
void writeVoiceReg(uint8_t voice, uint8_t reg, uint8_t value) {
|
void WriteVoiceReg(uint8_t voice, uint8_t reg, uint8_t value) {
|
||||||
voices[voice % NUM_VOICES][reg % NUM_VOICE_REGS] = value;
|
voices[voice % NUM_VOICES][reg % NUM_VOICE_REGS] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a byte from a global register
|
// Read a byte from a global register
|
||||||
uint8_t readGlobalReg(uint8_t reg) const {
|
uint8_t ReadGlobalReg(uint8_t reg) const {
|
||||||
return globalRegs[reg % NUM_GLOBAL_REGS];
|
return globalRegs[reg % NUM_GLOBAL_REGS];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write a byte to a global register
|
// Write a byte to a global register
|
||||||
void writeGlobalReg(uint8_t reg, uint8_t value) {
|
void WriteGlobalReg(uint8_t reg, uint8_t value) {
|
||||||
globalRegs[reg % NUM_GLOBAL_REGS] = value;
|
globalRegs[reg % NUM_GLOBAL_REGS] = value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -81,7 +82,7 @@ class SPC700 {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SPC700(VirtualAudioRAM& aram) : aram_(aram) {}
|
explicit SPC700(VirtualAudioRAM& aram) : aram_(aram) {}
|
||||||
SDSP sdsp;
|
DigitalSignalProcessor sdsp;
|
||||||
uint8_t test_register_;
|
uint8_t test_register_;
|
||||||
uint8_t control_register_;
|
uint8_t control_register_;
|
||||||
uint8_t dsp_address_register_;
|
uint8_t dsp_address_register_;
|
||||||
@@ -118,7 +119,7 @@ class SPC700 {
|
|||||||
case 0xF2:
|
case 0xF2:
|
||||||
return dsp_address_register_;
|
return dsp_address_register_;
|
||||||
case 0xF3:
|
case 0xF3:
|
||||||
return sdsp.readGlobalReg(dsp_address_register_);
|
return sdsp.ReadGlobalReg(dsp_address_register_);
|
||||||
default:
|
default:
|
||||||
if (address < 0xFFC0) {
|
if (address < 0xFFC0) {
|
||||||
return aram_.read(address);
|
return aram_.read(address);
|
||||||
@@ -142,7 +143,7 @@ class SPC700 {
|
|||||||
dsp_address_register_ = value;
|
dsp_address_register_ = value;
|
||||||
break;
|
break;
|
||||||
case 0xF3:
|
case 0xF3:
|
||||||
sdsp.writeGlobalReg(dsp_address_register_, value);
|
sdsp.WriteGlobalReg(dsp_address_register_, value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (address < 0xFFC0) {
|
if (address < 0xFFC0) {
|
||||||
@@ -153,18 +154,60 @@ class SPC700 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
// Addressing modes
|
// Addressing modes
|
||||||
|
|
||||||
|
// Immediate
|
||||||
uint8_t imm() {
|
uint8_t imm() {
|
||||||
PC++;
|
PC++;
|
||||||
return read(PC);
|
return read(PC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Direct page
|
||||||
uint8_t dp() {
|
uint8_t dp() {
|
||||||
PC++;
|
PC++;
|
||||||
uint8_t offset = read(PC);
|
uint8_t offset = read(PC);
|
||||||
return read((PSW.P << 8) + offset);
|
return read((PSW.P << 8) + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t get_dp_addr() {
|
||||||
|
PC++;
|
||||||
|
uint8_t offset = read(PC);
|
||||||
|
return (PSW.P << 8) + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direct page indexed by X
|
||||||
|
uint8_t dp_plus_x() {
|
||||||
|
PC++;
|
||||||
|
uint8_t offset = read(PC);
|
||||||
|
return read((PSW.P << 8) + offset + X);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direct page indexed by Y
|
||||||
|
uint8_t dp_plus_y() {
|
||||||
|
PC++;
|
||||||
|
uint8_t offset = read(PC);
|
||||||
|
return read((PSW.P << 8) + offset + Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indexed indirect (add index before 16-bit lookup).
|
||||||
|
uint16_t dp_plus_x_indirect() {
|
||||||
|
PC++;
|
||||||
|
uint8_t offset = read(PC);
|
||||||
|
uint16_t addr = read((PSW.P << 8) + offset + X) |
|
||||||
|
(read((PSW.P << 8) + offset + X + 1) << 8);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indirect indexed (add index after 16-bit lookup).
|
||||||
|
uint16_t dp_indirect_plus_y() {
|
||||||
|
PC++;
|
||||||
|
uint8_t offset = read(PC);
|
||||||
|
uint16_t baseAddr =
|
||||||
|
read((PSW.P << 8) + offset) | (read((PSW.P << 8) + offset + 1) << 8);
|
||||||
|
return baseAddr + Y;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t abs() {
|
uint16_t abs() {
|
||||||
PC++;
|
PC++;
|
||||||
uint16_t addr = read(PC) | (read(PC) << 8);
|
uint16_t addr = read(PC) | (read(PC) << 8);
|
||||||
@@ -197,82 +240,280 @@ class SPC700 {
|
|||||||
return read(addr) | (read(addr + 1) << 8);
|
return read(addr) | (read(addr + 1) << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
// Instructions
|
// Instructions
|
||||||
|
|
||||||
// MOV
|
// MOV
|
||||||
void MOV(uint8_t operand, bool isImmediate = false) {
|
void MOV(uint8_t& dest, uint8_t operand) {
|
||||||
uint8_t value = isImmediate ? imm() : operand;
|
dest = operand;
|
||||||
operand = value;
|
PSW.Z = (operand == 0);
|
||||||
|
PSW.N = (operand & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOV_ADDR(uint16_t address, uint8_t operand) {
|
||||||
|
write(address, operand);
|
||||||
PSW.Z = (operand == 0);
|
PSW.Z = (operand == 0);
|
||||||
PSW.N = (operand & 0x80);
|
PSW.N = (operand & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ADC
|
// ADC
|
||||||
void ADC(uint8_t operand, bool isImmediate = false) {
|
void ADC(uint8_t& dest, uint8_t operand) {
|
||||||
uint8_t value = isImmediate ? imm() : operand;
|
uint16_t result = dest + operand + PSW.C;
|
||||||
uint16_t result = A + value + PSW.C;
|
PSW.V = ((A ^ result) & (operand ^ result) & 0x80);
|
||||||
PSW.V = ((A ^ result) & (value ^ result) & 0x80);
|
|
||||||
PSW.C = (result > 0xFF);
|
PSW.C = (result > 0xFF);
|
||||||
PSW.Z = ((result & 0xFF) == 0);
|
PSW.Z = ((result & 0xFF) == 0);
|
||||||
PSW.N = (result & 0x80);
|
PSW.N = (result & 0x80);
|
||||||
PSW.H = ((A ^ value ^ result) & 0x10);
|
PSW.H = ((A ^ operand ^ result) & 0x10);
|
||||||
A = result & 0xFF;
|
dest = result & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SBC
|
// SBC
|
||||||
void SBC(uint8_t operand, bool isImmediate = false) {
|
void SBC(uint8_t& dest, uint8_t operand) {
|
||||||
uint8_t value = isImmediate ? imm() : operand;
|
uint16_t result = dest - operand - (1 - PSW.C);
|
||||||
uint16_t result = A - value - (1 - PSW.C);
|
PSW.V = ((dest ^ result) & (dest ^ operand) & 0x80);
|
||||||
PSW.V = ((A ^ result) & (A ^ value) & 0x80);
|
|
||||||
PSW.C = (result < 0x100);
|
PSW.C = (result < 0x100);
|
||||||
PSW.Z = ((result & 0xFF) == 0);
|
PSW.Z = ((result & 0xFF) == 0);
|
||||||
PSW.N = (result & 0x80);
|
PSW.N = (result & 0x80);
|
||||||
PSW.H = ((A ^ value ^ result) & 0x10);
|
PSW.H = ((dest ^ operand ^ result) & 0x10);
|
||||||
A = result & 0xFF;
|
dest = result & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CMP
|
// CMP
|
||||||
void CMP(uint8_t operand, bool isImmediate = false) {
|
void CMP(uint8_t& dest, uint8_t operand) {
|
||||||
uint8_t value = isImmediate ? imm() : operand;
|
uint16_t result = dest - operand;
|
||||||
uint16_t result = A - value;
|
|
||||||
PSW.C = (result < 0x100);
|
PSW.C = (result < 0x100);
|
||||||
PSW.Z = ((result & 0xFF) == 0);
|
PSW.Z = ((result & 0xFF) == 0);
|
||||||
PSW.N = (result & 0x80);
|
PSW.N = (result & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
// AND
|
// AND
|
||||||
void AND(uint8_t operand, bool isImmediate = false) {
|
void AND(uint8_t& dest, uint8_t operand) {
|
||||||
uint8_t value = isImmediate ? imm() : operand;
|
dest &= operand;
|
||||||
A &= value;
|
PSW.Z = (dest == 0);
|
||||||
PSW.Z = (A == 0);
|
PSW.N = (dest & 0x80);
|
||||||
PSW.N = (A & 0x80);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OR
|
// OR
|
||||||
void OR(uint8_t operand, bool isImmediate = false) {
|
void OR(uint8_t& dest, uint8_t operand) {
|
||||||
uint8_t value = isImmediate ? imm() : operand;
|
dest |= operand;
|
||||||
A |= value;
|
PSW.Z = (dest == 0);
|
||||||
PSW.Z = (A == 0);
|
PSW.N = (dest & 0x80);
|
||||||
PSW.N = (A & 0x80);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EOR
|
// EOR
|
||||||
void EOR(uint8_t operand, bool isImmediate = false) {
|
void EOR(uint8_t& dest, uint8_t operand) {
|
||||||
uint8_t value = isImmediate ? imm() : operand;
|
dest ^= operand;
|
||||||
A ^= value;
|
PSW.Z = (dest == 0);
|
||||||
PSW.Z = (A == 0);
|
PSW.N = (dest & 0x80);
|
||||||
PSW.N = (A & 0x80);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ASL LSR ROL XCN
|
// ASL
|
||||||
// INC DEC
|
void ASL(uint8_t operand) {
|
||||||
// MOVW INCW DECW ADDW SUBW CMPW MUL DIV
|
PSW.C = (operand & 0x80);
|
||||||
// DAA DAS
|
operand <<= 1;
|
||||||
// BRA BEQ BNE BCS BCC BVS BVC BMI BPL BBS BBC CBNE DBNZ JMP
|
PSW.Z = (operand == 0);
|
||||||
// CALL PCALL TCALL BRK RET RETI
|
PSW.N = (operand & 0x80);
|
||||||
// PUSH POP
|
// A = value;
|
||||||
// SET1 CLR1 TSET1 TCLR1 AND1 OR1 EOR1 NOT1 MOV1
|
}
|
||||||
// CLRC SETC NOTC CLRV CLRP SETP EI DI
|
|
||||||
// NOP SLEEP STOP
|
// LSR
|
||||||
|
void LSR(uint8_t& operand) {
|
||||||
|
PSW.C = (operand & 0x01);
|
||||||
|
operand >>= 1;
|
||||||
|
PSW.Z = (operand == 0);
|
||||||
|
PSW.N = (operand & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ROL
|
||||||
|
void ROL(uint8_t operand, bool isImmediate = false) {
|
||||||
|
uint8_t value = isImmediate ? imm() : operand;
|
||||||
|
uint8_t carry = PSW.C;
|
||||||
|
PSW.C = (value & 0x80);
|
||||||
|
value <<= 1;
|
||||||
|
value |= carry;
|
||||||
|
PSW.Z = (value == 0);
|
||||||
|
PSW.N = (value & 0x80);
|
||||||
|
// operand = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XCN
|
||||||
|
void XCN(uint8_t operand, bool isImmediate = false) {
|
||||||
|
uint8_t value = isImmediate ? imm() : operand;
|
||||||
|
value = ((value & 0xF0) >> 4) | ((value & 0x0F) << 4);
|
||||||
|
PSW.Z = (value == 0);
|
||||||
|
PSW.N = (value & 0x80);
|
||||||
|
// operand = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// INC
|
||||||
|
void INC(uint8_t& operand) {
|
||||||
|
operand++;
|
||||||
|
PSW.Z = (operand == 0);
|
||||||
|
PSW.N = (operand & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEC
|
||||||
|
void DEC(uint8_t& operand) {
|
||||||
|
operand--;
|
||||||
|
PSW.Z = (operand == 0);
|
||||||
|
PSW.N = (operand & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MOVW
|
||||||
|
void MOVW(uint16_t& dest, uint16_t operand) {
|
||||||
|
dest = operand;
|
||||||
|
PSW.Z = (operand == 0);
|
||||||
|
PSW.N = (operand & 0x8000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// INCW
|
||||||
|
void INCW(uint16_t& operand) {
|
||||||
|
operand++;
|
||||||
|
PSW.Z = (operand == 0);
|
||||||
|
PSW.N = (operand & 0x8000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DECW
|
||||||
|
void DECW(uint16_t& operand) {
|
||||||
|
operand--;
|
||||||
|
PSW.Z = (operand == 0);
|
||||||
|
PSW.N = (operand & 0x8000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ADDW
|
||||||
|
void ADDW(uint16_t& dest, uint16_t operand) {
|
||||||
|
uint32_t result = dest + operand;
|
||||||
|
PSW.C = (result > 0xFFFF);
|
||||||
|
PSW.Z = ((result & 0xFFFF) == 0);
|
||||||
|
PSW.N = (result & 0x8000);
|
||||||
|
PSW.V = ((dest ^ result) & (operand ^ result) & 0x8000);
|
||||||
|
dest = result & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SUBW
|
||||||
|
void SUBW(uint16_t& dest, uint16_t operand) {
|
||||||
|
uint32_t result = dest - operand;
|
||||||
|
PSW.C = (result < 0x10000);
|
||||||
|
PSW.Z = ((result & 0xFFFF) == 0);
|
||||||
|
PSW.N = (result & 0x8000);
|
||||||
|
PSW.V = ((dest ^ result) & (dest ^ operand) & 0x8000);
|
||||||
|
dest = result & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CMPW
|
||||||
|
void CMPW(uint16_t operand) {
|
||||||
|
uint32_t result = YA - operand;
|
||||||
|
PSW.C = (result < 0x10000);
|
||||||
|
PSW.Z = ((result & 0xFFFF) == 0);
|
||||||
|
PSW.N = (result & 0x8000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MUL
|
||||||
|
void MUL(uint8_t operand) {
|
||||||
|
uint16_t result = A * operand;
|
||||||
|
YA = result;
|
||||||
|
PSW.Z = (result == 0);
|
||||||
|
PSW.N = (result & 0x8000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DIV
|
||||||
|
void DIV(uint8_t operand) {
|
||||||
|
if (operand == 0) {
|
||||||
|
// Handle divide by zero error
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t quotient = A / operand;
|
||||||
|
uint8_t remainder = A % operand;
|
||||||
|
A = quotient;
|
||||||
|
Y = remainder;
|
||||||
|
PSW.Z = (quotient == 0);
|
||||||
|
PSW.N = (quotient & 0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DAA
|
||||||
|
|
||||||
|
// BRA
|
||||||
|
void BRA(int8_t offset) { PC += offset; }
|
||||||
|
|
||||||
|
// BEQ
|
||||||
|
void BEQ(int8_t offset) {
|
||||||
|
if (PSW.Z) {
|
||||||
|
PC += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BNE
|
||||||
|
void BNE(int8_t offset) {
|
||||||
|
if (!PSW.Z) {
|
||||||
|
PC += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BCS
|
||||||
|
void BCS(int8_t offset) {
|
||||||
|
if (PSW.C) {
|
||||||
|
PC += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BCC
|
||||||
|
void BCC(int8_t offset) {
|
||||||
|
if (!PSW.C) {
|
||||||
|
PC += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BVS
|
||||||
|
void BVS(int8_t offset) {
|
||||||
|
if (PSW.V) {
|
||||||
|
PC += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BVC
|
||||||
|
void BVC(int8_t offset) {
|
||||||
|
if (!PSW.V) {
|
||||||
|
PC += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BMI
|
||||||
|
void BMI(int8_t offset) {
|
||||||
|
if (PSW.N) {
|
||||||
|
PC += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BPL
|
||||||
|
void BPL(int8_t offset) {
|
||||||
|
if (!PSW.N) {
|
||||||
|
PC += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BBS
|
||||||
|
void BBS(uint8_t bit, uint8_t operand) {
|
||||||
|
if (operand & (1 << bit)) {
|
||||||
|
PC += rel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BBC
|
||||||
|
void BBC(uint8_t bit, uint8_t operand) {
|
||||||
|
if (!(operand & (1 << bit))) {
|
||||||
|
PC += rel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CBNE DBNZ
|
||||||
|
// JMP
|
||||||
|
void JMP(uint16_t address) { PC = address; }
|
||||||
|
|
||||||
|
// CALL PCALL TCALL BRK RET RETI
|
||||||
|
// PUSH POP
|
||||||
|
// SET1 CLR1 TSET1 TCLR1 AND1 OR1 EOR1 NOT1 MOV1
|
||||||
|
// CLRC SETC NOTC CLRV CLRP SETP EI DI
|
||||||
|
// NOP SLEEP STOP
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emu
|
} // namespace emu
|
||||||
|
|||||||
Reference in New Issue
Block a user