Update Spc700, separate addressing and opcodes

This commit is contained in:
scawful
2023-12-05 03:44:24 -05:00
parent dbedd83612
commit b7558371b3
4 changed files with 974 additions and 307 deletions

View File

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