Add addressing modes and opcodes for SPC700
This commit is contained in:
@@ -11,41 +11,59 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
switch (opcode) {
|
||||
// 8-bit Move Memory to Register
|
||||
case 0xE8: // MOV A, #imm
|
||||
MOV(A, true);
|
||||
MOV(A, imm());
|
||||
break;
|
||||
case 0xE6: // MOV A, (X)
|
||||
MOV(A, X);
|
||||
break;
|
||||
case 0xBF: // MOV A, (X)+
|
||||
MOV(A, X);
|
||||
X++;
|
||||
break;
|
||||
case 0xE4: // MOV A, dp
|
||||
MOV(A, dp());
|
||||
break;
|
||||
case 0xF4: // MOV A, dp+X
|
||||
MOV(A, dp_plus_x());
|
||||
break;
|
||||
case 0xE5: // MOV A, !abs
|
||||
MOV(A, abs());
|
||||
break;
|
||||
case 0xF5: // MOV A, !abs+X
|
||||
MOV(A, abs() + X);
|
||||
break;
|
||||
case 0xF6: // MOV A, !abs+Y
|
||||
MOV(A, abs() + Y);
|
||||
break;
|
||||
case 0xE7: // MOV A, [dp+X]
|
||||
MOV(A, read(dp_plus_x_indirect()));
|
||||
break;
|
||||
case 0xF7: // MOV A, [dp]+Y
|
||||
MOV(A, read(dp_indirect_plus_y()));
|
||||
break;
|
||||
case 0xCD: // MOV X, #imm
|
||||
MOV(X, imm());
|
||||
break;
|
||||
case 0xF8: // MOV X, dp
|
||||
MOV(X, dp());
|
||||
break;
|
||||
case 0xF9: // MOV X, dp+Y
|
||||
MOV(X, dp_plus_y());
|
||||
break;
|
||||
case 0xE9: // MOV X, !abs
|
||||
MOV(X, abs());
|
||||
break;
|
||||
case 0x8D: // MOV Y, #imm
|
||||
MOV(Y, imm());
|
||||
break;
|
||||
case 0xEB: // MOV Y, dp
|
||||
MOV(Y, dp());
|
||||
break;
|
||||
case 0xFB: // MOV Y, dp+X
|
||||
MOV(Y, dp_plus_x());
|
||||
break;
|
||||
case 0xEC: // MOV Y, !abs
|
||||
MOV(Y, abs());
|
||||
break;
|
||||
|
||||
// 8-bit move register to memory
|
||||
@@ -55,30 +73,43 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
case 0xAF: // MOV (X)+, A
|
||||
break;
|
||||
case 0xC4: // MOV dp, A
|
||||
MOV_ADDR(get_dp_addr(), A);
|
||||
break;
|
||||
case 0xD4: // MOV dp+X, A
|
||||
MOV_ADDR(get_dp_addr() + X, A);
|
||||
break;
|
||||
case 0xC5: // MOV !abs, A
|
||||
MOV_ADDR(abs(), A);
|
||||
break;
|
||||
case 0xD5: // MOV !abs+X, A
|
||||
MOV_ADDR(abs() + X, A);
|
||||
break;
|
||||
case 0xD6: // MOV !abs+Y, A
|
||||
MOV_ADDR(abs() + Y, A);
|
||||
break;
|
||||
case 0xC7: // MOV [dp+X], A
|
||||
MOV_ADDR(dp_plus_x_indirect(), A);
|
||||
break;
|
||||
case 0xD7: // MOV [dp]+Y, A
|
||||
MOV_ADDR(dp_indirect_plus_y(), A);
|
||||
break;
|
||||
case 0xD8: // MOV dp, X
|
||||
MOV_ADDR(get_dp_addr(), X);
|
||||
break;
|
||||
case 0xD9: // MOV dp+Y, X
|
||||
MOV_ADDR(get_dp_addr() + Y, X);
|
||||
break;
|
||||
case 0xC9: // MOV !abs, X
|
||||
MOV_ADDR(abs(), X);
|
||||
break;
|
||||
case 0xCB: // MOV dp, Y
|
||||
MOV_ADDR(get_dp_addr(), Y);
|
||||
break;
|
||||
case 0xDB: // MOV dp+X, Y
|
||||
MOV_ADDR(get_dp_addr() + X, Y);
|
||||
break;
|
||||
case 0xCC: // MOV !abs, Y
|
||||
MOV_ADDR(abs(), Y);
|
||||
break;
|
||||
|
||||
// . 8-bit move register to register / special direct page moves
|
||||
@@ -103,22 +134,28 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
// . 8-bit arithmetic
|
||||
|
||||
case 0x88: // ADC A, #imm
|
||||
ADC(A, imm());
|
||||
break;
|
||||
case 0x86: // ADC A, (X)
|
||||
break;
|
||||
case 0x84: // ADC A, dp
|
||||
ADC(A, dp());
|
||||
break;
|
||||
case 0x94: // ADC A, dp+X
|
||||
ADC(A, dp_plus_x());
|
||||
break;
|
||||
case 0x85: // ADC A, !abs
|
||||
ADC(A, abs());
|
||||
break;
|
||||
case 0x95: // ADC A, !abs+X
|
||||
break;
|
||||
case 0x96: // ADC A, !abs+Y
|
||||
break;
|
||||
case 0x87: // ADC A, [dp+X]
|
||||
ADC(A, dp_plus_x_indirect());
|
||||
break;
|
||||
case 0x97: // ADC A, [dp]+Y
|
||||
ADC(A, dp_indirect_plus_y());
|
||||
break;
|
||||
case 0x99: // ADC (X), (Y)
|
||||
break;
|
||||
@@ -127,6 +164,7 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
case 0x98: // ADC dp, #imm
|
||||
break;
|
||||
case 0xA8: // SBC A, #imm
|
||||
SBC(A, imm());
|
||||
break;
|
||||
case 0xA6: // SBC A, (X)
|
||||
break;
|
||||
@@ -214,14 +252,18 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
case 0x38: // AND dp, #imm
|
||||
break;
|
||||
case 0x08: // OR A, #imm
|
||||
OR(A, imm());
|
||||
break;
|
||||
case 0x06: // OR A, (X)
|
||||
break;
|
||||
case 0x04: // OR A, dp
|
||||
OR(A, dp());
|
||||
break;
|
||||
case 0x14: // OR A, dp+X
|
||||
OR(A, dp_plus_x());
|
||||
break;
|
||||
case 0x05: // OR A, !abs
|
||||
OR(A, abs());
|
||||
break;
|
||||
case 0x15: // OR A, !abs+X
|
||||
break;
|
||||
@@ -238,10 +280,12 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
case 0x18: // OR dp, #imm
|
||||
break;
|
||||
case 0x48: // EOR A, #imm
|
||||
EOR(A, imm());
|
||||
break;
|
||||
case 0x46: // EOR A, (X)
|
||||
break;
|
||||
case 0x44: // EOR A, dp
|
||||
EOR(A, dp());
|
||||
break;
|
||||
case 0x54: // EOR A, dp+X
|
||||
break;
|
||||
@@ -265,6 +309,7 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
// . 8-bit increment / decrement
|
||||
|
||||
case 0xBC: // INC A
|
||||
INC(A);
|
||||
break;
|
||||
case 0xAB: // INC dp
|
||||
break;
|
||||
@@ -273,10 +318,13 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
case 0xAC: // INC !abs
|
||||
break;
|
||||
case 0x3D: // INC X
|
||||
INC(X);
|
||||
break;
|
||||
case 0xFC: // INC Y
|
||||
INC(Y);
|
||||
break;
|
||||
case 0x9C: // DEC A
|
||||
DEC(A);
|
||||
break;
|
||||
case 0x8B: // DEC dp
|
||||
break;
|
||||
@@ -285,21 +333,28 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
case 0x8C: // DEC !abs
|
||||
break;
|
||||
case 0x1D: // DEC X
|
||||
DEC(X);
|
||||
break;
|
||||
case 0xDC: // DEC Y
|
||||
DEC(Y);
|
||||
break;
|
||||
|
||||
// 8-bit shift / rotation
|
||||
|
||||
case 0x1C: // ASL A
|
||||
ASL(A);
|
||||
break;
|
||||
case 0x0B: // ASL dp
|
||||
ASL(dp());
|
||||
break;
|
||||
case 0x1B: // ASL dp+X
|
||||
ASL(dp_plus_x());
|
||||
break;
|
||||
case 0x0C: // ASL !abs
|
||||
ASL(abs());
|
||||
break;
|
||||
case 0x5C: // LSR A
|
||||
LSR(A);
|
||||
break;
|
||||
case 0x4B: // LSR dp
|
||||
break;
|
||||
@@ -324,6 +379,7 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
case 0x6C: // ROR !abs
|
||||
break;
|
||||
case 0x9F: // XCN A Exchange nibbles of A
|
||||
|
||||
break;
|
||||
|
||||
// . 16-bit operations
|
||||
|
||||
@@ -22,10 +22,10 @@ class VirtualAudioRAM {
|
||||
|
||||
class AudioRAM : public VirtualAudioRAM {
|
||||
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:
|
||||
AudioRAM() : ram(ARAM_SIZE, 0) {}
|
||||
AudioRAM() = default;
|
||||
|
||||
// Read a byte from ARAM at the given address
|
||||
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_VOICE_REGS = 10;
|
||||
static const size_t NUM_GLOBAL_REGS = 15;
|
||||
|
||||
// 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
|
||||
std::vector<uint8_t> globalRegs;
|
||||
std::vector<uint8_t> globalRegs = std::vector<uint8_t>(NUM_GLOBAL_REGS, 0x00);
|
||||
|
||||
public:
|
||||
SDSP()
|
||||
: voices(NUM_VOICES, std::vector<uint8_t>(NUM_VOICE_REGS, 0)),
|
||||
globalRegs(NUM_GLOBAL_REGS, 0) {}
|
||||
DigitalSignalProcessor() = default;
|
||||
|
||||
// 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];
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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];
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
@@ -81,7 +82,7 @@ class SPC700 {
|
||||
|
||||
public:
|
||||
explicit SPC700(VirtualAudioRAM& aram) : aram_(aram) {}
|
||||
SDSP sdsp;
|
||||
DigitalSignalProcessor sdsp;
|
||||
uint8_t test_register_;
|
||||
uint8_t control_register_;
|
||||
uint8_t dsp_address_register_;
|
||||
@@ -118,7 +119,7 @@ class SPC700 {
|
||||
case 0xF2:
|
||||
return dsp_address_register_;
|
||||
case 0xF3:
|
||||
return sdsp.readGlobalReg(dsp_address_register_);
|
||||
return sdsp.ReadGlobalReg(dsp_address_register_);
|
||||
default:
|
||||
if (address < 0xFFC0) {
|
||||
return aram_.read(address);
|
||||
@@ -142,7 +143,7 @@ class SPC700 {
|
||||
dsp_address_register_ = value;
|
||||
break;
|
||||
case 0xF3:
|
||||
sdsp.writeGlobalReg(dsp_address_register_, value);
|
||||
sdsp.WriteGlobalReg(dsp_address_register_, value);
|
||||
break;
|
||||
default:
|
||||
if (address < 0xFFC0) {
|
||||
@@ -153,18 +154,60 @@ class SPC700 {
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Addressing modes
|
||||
|
||||
// Immediate
|
||||
uint8_t imm() {
|
||||
PC++;
|
||||
return read(PC);
|
||||
}
|
||||
|
||||
// Direct page
|
||||
uint8_t dp() {
|
||||
PC++;
|
||||
uint8_t offset = read(PC);
|
||||
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() {
|
||||
PC++;
|
||||
uint16_t addr = read(PC) | (read(PC) << 8);
|
||||
@@ -197,82 +240,280 @@ class SPC700 {
|
||||
return read(addr) | (read(addr + 1) << 8);
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Instructions
|
||||
|
||||
// MOV
|
||||
void MOV(uint8_t operand, bool isImmediate = false) {
|
||||
uint8_t value = isImmediate ? imm() : operand;
|
||||
operand = value;
|
||||
void MOV(uint8_t& dest, uint8_t operand) {
|
||||
dest = operand;
|
||||
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.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
// ADC
|
||||
void ADC(uint8_t operand, bool isImmediate = false) {
|
||||
uint8_t value = isImmediate ? imm() : operand;
|
||||
uint16_t result = A + value + PSW.C;
|
||||
PSW.V = ((A ^ result) & (value ^ result) & 0x80);
|
||||
void ADC(uint8_t& dest, uint8_t operand) {
|
||||
uint16_t result = dest + operand + PSW.C;
|
||||
PSW.V = ((A ^ result) & (operand ^ result) & 0x80);
|
||||
PSW.C = (result > 0xFF);
|
||||
PSW.Z = ((result & 0xFF) == 0);
|
||||
PSW.N = (result & 0x80);
|
||||
PSW.H = ((A ^ value ^ result) & 0x10);
|
||||
A = result & 0xFF;
|
||||
PSW.H = ((A ^ operand ^ result) & 0x10);
|
||||
dest = result & 0xFF;
|
||||
}
|
||||
|
||||
// SBC
|
||||
void SBC(uint8_t operand, bool isImmediate = false) {
|
||||
uint8_t value = isImmediate ? imm() : operand;
|
||||
uint16_t result = A - value - (1 - PSW.C);
|
||||
PSW.V = ((A ^ result) & (A ^ value) & 0x80);
|
||||
void SBC(uint8_t& dest, uint8_t operand) {
|
||||
uint16_t result = dest - operand - (1 - PSW.C);
|
||||
PSW.V = ((dest ^ result) & (dest ^ operand) & 0x80);
|
||||
PSW.C = (result < 0x100);
|
||||
PSW.Z = ((result & 0xFF) == 0);
|
||||
PSW.N = (result & 0x80);
|
||||
PSW.H = ((A ^ value ^ result) & 0x10);
|
||||
A = result & 0xFF;
|
||||
PSW.H = ((dest ^ operand ^ result) & 0x10);
|
||||
dest = result & 0xFF;
|
||||
}
|
||||
|
||||
// CMP
|
||||
void CMP(uint8_t operand, bool isImmediate = false) {
|
||||
uint8_t value = isImmediate ? imm() : operand;
|
||||
uint16_t result = A - value;
|
||||
void CMP(uint8_t& dest, uint8_t operand) {
|
||||
uint16_t result = dest - operand;
|
||||
PSW.C = (result < 0x100);
|
||||
PSW.Z = ((result & 0xFF) == 0);
|
||||
PSW.N = (result & 0x80);
|
||||
}
|
||||
|
||||
// AND
|
||||
void AND(uint8_t operand, bool isImmediate = false) {
|
||||
uint8_t value = isImmediate ? imm() : operand;
|
||||
A &= value;
|
||||
PSW.Z = (A == 0);
|
||||
PSW.N = (A & 0x80);
|
||||
void AND(uint8_t& dest, uint8_t operand) {
|
||||
dest &= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
}
|
||||
|
||||
// OR
|
||||
void OR(uint8_t operand, bool isImmediate = false) {
|
||||
uint8_t value = isImmediate ? imm() : operand;
|
||||
A |= value;
|
||||
PSW.Z = (A == 0);
|
||||
PSW.N = (A & 0x80);
|
||||
void OR(uint8_t& dest, uint8_t operand) {
|
||||
dest |= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
}
|
||||
|
||||
// EOR
|
||||
void EOR(uint8_t operand, bool isImmediate = false) {
|
||||
uint8_t value = isImmediate ? imm() : operand;
|
||||
A ^= value;
|
||||
PSW.Z = (A == 0);
|
||||
PSW.N = (A & 0x80);
|
||||
void EOR(uint8_t& dest, uint8_t operand) {
|
||||
dest ^= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
}
|
||||
|
||||
// ASL LSR ROL XCN
|
||||
// INC DEC
|
||||
// MOVW INCW DECW ADDW SUBW CMPW MUL DIV
|
||||
// DAA DAS
|
||||
// BRA BEQ BNE BCS BCC BVS BVC BMI BPL BBS BBC CBNE DBNZ JMP
|
||||
// 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
|
||||
// ASL
|
||||
void ASL(uint8_t operand) {
|
||||
PSW.C = (operand & 0x80);
|
||||
operand <<= 1;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
// A = value;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user