Update Spc700, separate addressing and opcodes
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace yaze {
|
||||
@@ -38,23 +39,32 @@ class AudioRamImpl : public AudioRam {
|
||||
}
|
||||
};
|
||||
|
||||
class SPC700 {
|
||||
class Spc700 {
|
||||
private:
|
||||
AudioRam& aram_;
|
||||
std::vector<std::string> log_;
|
||||
|
||||
const uint8_t ipl_rom_[64]{
|
||||
0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0, 0xFC, 0x8F, 0xAA,
|
||||
0xF4, 0x8F, 0xBB, 0xF5, 0x78, 0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19,
|
||||
0xEB, 0xF4, 0xD0, 0xFC, 0x7E, 0xF4, 0xD0, 0x0B, 0xE4, 0xF5, 0xCB,
|
||||
0xF4, 0xD7, 0x00, 0xFC, 0xD0, 0xF3, 0xAB, 0x01, 0x10, 0xEF, 0x7E,
|
||||
0xF4, 0x10, 0xEB, 0xBA, 0xF6, 0xDA, 0x00, 0xBA, 0xF4, 0xC4, 0xF4,
|
||||
0xDD, 0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF};
|
||||
|
||||
public:
|
||||
explicit SPC700(AudioRam& aram) : aram_(aram) {}
|
||||
explicit Spc700(AudioRam& aram) : aram_(aram) {}
|
||||
uint8_t test_register_;
|
||||
uint8_t control_register_;
|
||||
uint8_t dsp_address_register_;
|
||||
|
||||
// Registers
|
||||
uint8_t A; // 8-bit accumulator
|
||||
uint8_t X; // 8-bit index
|
||||
uint8_t Y; // 8-bit index
|
||||
uint16_t YA; // 16-bit pair of A (lsb) and Y (msb)
|
||||
uint16_t PC; // program counter
|
||||
uint8_t SP; // stack pointer
|
||||
uint8_t A = 0; // 8-bit accumulator
|
||||
uint8_t X = 0; // 8-bit index
|
||||
uint8_t Y = 0; // 8-bit index
|
||||
uint16_t YA = 0; // 16-bit pair of A (lsb) and Y (msb)
|
||||
uint16_t PC = 0; // program counter
|
||||
uint8_t SP = 0; // stack pointer
|
||||
|
||||
struct Flags {
|
||||
uint8_t N : 1; // Negative flag
|
||||
@@ -68,11 +78,30 @@ class SPC700 {
|
||||
};
|
||||
Flags PSW; // Processor status word
|
||||
|
||||
uint8_t FlagsToByte(Flags flags) {
|
||||
return (flags.N << 7) | (flags.V << 6) | (flags.P << 5) | (flags.B << 4) |
|
||||
(flags.H << 3) | (flags.I << 2) | (flags.Z << 1) | (flags.C);
|
||||
}
|
||||
|
||||
Flags ByteToFlags(uint8_t byte) {
|
||||
Flags flags;
|
||||
flags.N = (byte & 0x80) >> 7;
|
||||
flags.V = (byte & 0x40) >> 6;
|
||||
flags.P = (byte & 0x20) >> 5;
|
||||
flags.B = (byte & 0x10) >> 4;
|
||||
flags.H = (byte & 0x08) >> 3;
|
||||
flags.I = (byte & 0x04) >> 2;
|
||||
flags.Z = (byte & 0x02) >> 1;
|
||||
flags.C = (byte & 0x01);
|
||||
return flags;
|
||||
}
|
||||
|
||||
void Reset();
|
||||
|
||||
void Notify(uint32_t address, uint8_t data);
|
||||
void BootIplRom();
|
||||
|
||||
void ExecuteInstructions(uint8_t opcode);
|
||||
void LogInstruction(uint16_t initial_pc, uint8_t opcode);
|
||||
|
||||
// Read a byte from the memory-mapped registers
|
||||
uint8_t read(uint16_t address) {
|
||||
@@ -88,6 +117,7 @@ class SPC700 {
|
||||
return aram_.read(address);
|
||||
} else {
|
||||
// Handle IPL ROM or RAM reads here
|
||||
return ipl_rom_[address - 0xFFC0];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -203,277 +233,70 @@ class SPC700 {
|
||||
// ==========================================================================
|
||||
// Instructions
|
||||
|
||||
// MOV
|
||||
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& 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 ^ operand ^ result) & 0x10);
|
||||
dest = result & 0xFF;
|
||||
}
|
||||
|
||||
// SBC
|
||||
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 = ((dest ^ operand ^ result) & 0x10);
|
||||
dest = result & 0xFF;
|
||||
}
|
||||
|
||||
// CMP
|
||||
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& dest, uint8_t operand) {
|
||||
dest &= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
}
|
||||
|
||||
// OR
|
||||
void OR(uint8_t& dest, uint8_t operand) {
|
||||
dest |= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
}
|
||||
|
||||
// EOR
|
||||
void EOR(uint8_t& dest, uint8_t operand) {
|
||||
dest ^= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
void MOV(uint8_t& dest, uint8_t operand);
|
||||
void MOV_ADDR(uint16_t address, uint8_t operand);
|
||||
void ADC(uint8_t& dest, uint8_t operand);
|
||||
void SBC(uint8_t& dest, uint8_t operand);
|
||||
void CMP(uint8_t& dest, uint8_t operand);
|
||||
void AND(uint8_t& dest, uint8_t operand);
|
||||
void OR(uint8_t& dest, uint8_t operand);
|
||||
void EOR(uint8_t& dest, uint8_t operand);
|
||||
void ASL(uint8_t operand);
|
||||
void LSR(uint8_t& operand);
|
||||
void ROL(uint8_t operand, bool isImmediate = false);
|
||||
void XCN(uint8_t operand, bool isImmediate = false);
|
||||
void INC(uint8_t& operand);
|
||||
void DEC(uint8_t& operand);
|
||||
void MOVW(uint16_t& dest, uint16_t operand);
|
||||
void INCW(uint16_t& operand);
|
||||
void DECW(uint16_t& operand);
|
||||
void ADDW(uint16_t& dest, uint16_t operand);
|
||||
void SUBW(uint16_t& dest, uint16_t operand);
|
||||
void CMPW(uint16_t operand);
|
||||
void MUL(uint8_t operand);
|
||||
void DIV(uint8_t operand);
|
||||
void BRA(int8_t offset);
|
||||
void BEQ(int8_t offset);
|
||||
void BNE(int8_t offset);
|
||||
void BCS(int8_t offset);
|
||||
void BCC(int8_t offset);
|
||||
void BVS(int8_t offset);
|
||||
void BVC(int8_t offset);
|
||||
void BMI(int8_t offset);
|
||||
void BPL(int8_t offset);
|
||||
void BBS(uint8_t bit, uint8_t operand);
|
||||
void BBC(uint8_t bit, uint8_t operand);
|
||||
void JMP(uint16_t address);
|
||||
void CALL(uint16_t address);
|
||||
void PCALL(uint8_t offset);
|
||||
void TCALL(uint8_t offset);
|
||||
void BRK();
|
||||
void RET();
|
||||
void RETI();
|
||||
void PUSH(uint8_t operand);
|
||||
void POP(uint8_t& operand);
|
||||
void SET1(uint8_t bit, uint8_t& operand);
|
||||
void CLR1(uint8_t bit, uint8_t& operand);
|
||||
void TSET1(uint8_t bit, uint8_t& operand);
|
||||
void TCLR1(uint8_t bit, uint8_t& operand);
|
||||
void AND1(uint8_t bit, uint8_t& operand);
|
||||
void OR1(uint8_t bit, uint8_t& operand);
|
||||
void EOR1(uint8_t bit, uint8_t& operand);
|
||||
void NOT1(uint8_t bit, uint8_t& operand);
|
||||
void MOV1(uint8_t bit, uint8_t& operand);
|
||||
void CLRC();
|
||||
void SETC();
|
||||
void NOTC();
|
||||
void CLRV();
|
||||
void CLRP();
|
||||
void SETP();
|
||||
void EI();
|
||||
void DI();
|
||||
void NOP();
|
||||
void SLEEP();
|
||||
void STOP();
|
||||
|
||||
// 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