Add addressing modes and opcodes for SPC700

This commit is contained in:
scawful
2023-08-25 17:44:04 -04:00
parent 25c43cbaaa
commit af73af4300
2 changed files with 356 additions and 59 deletions

View File

@@ -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

View File

@@ -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