Update Spc700, separate addressing and opcodes
This commit is contained in:
361
src/app/emu/audio/internal/addressing.cc
Normal file
361
src/app/emu/audio/internal/addressing.cc
Normal file
@@ -0,0 +1,361 @@
|
||||
#include "app/emu/audio/spc700.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace emu {
|
||||
|
||||
void Spc700::MOV(uint8_t& dest, uint8_t operand) {
|
||||
dest = operand;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::MOV_ADDR(uint16_t address, uint8_t operand) {
|
||||
write(address, operand);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::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;
|
||||
}
|
||||
|
||||
void Spc700::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;
|
||||
}
|
||||
|
||||
void Spc700::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);
|
||||
}
|
||||
|
||||
void Spc700::AND(uint8_t& dest, uint8_t operand) {
|
||||
dest &= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::OR(uint8_t& dest, uint8_t operand) {
|
||||
dest |= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::EOR(uint8_t& dest, uint8_t operand) {
|
||||
dest ^= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::ASL(uint8_t operand) {
|
||||
PSW.C = (operand & 0x80);
|
||||
operand <<= 1;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
// A = value;
|
||||
}
|
||||
|
||||
void Spc700::LSR(uint8_t& operand) {
|
||||
PSW.C = (operand & 0x01);
|
||||
operand >>= 1;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::ROL(uint8_t operand, bool isImmediate) {
|
||||
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;
|
||||
}
|
||||
|
||||
void Spc700::XCN(uint8_t operand, bool isImmediate) {
|
||||
uint8_t value = isImmediate ? imm() : operand;
|
||||
value = ((value & 0xF0) >> 4) | ((value & 0x0F) << 4);
|
||||
PSW.Z = (value == 0);
|
||||
PSW.N = (value & 0x80);
|
||||
// operand = value;
|
||||
}
|
||||
|
||||
void Spc700::INC(uint8_t& operand) {
|
||||
operand++;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::DEC(uint8_t& operand) {
|
||||
operand--;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::MOVW(uint16_t& dest, uint16_t operand) {
|
||||
dest = operand;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::INCW(uint16_t& operand) {
|
||||
operand++;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::DECW(uint16_t& operand) {
|
||||
operand--;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::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;
|
||||
}
|
||||
|
||||
void Spc700::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;
|
||||
}
|
||||
|
||||
void Spc700::CMPW(uint16_t operand) {
|
||||
uint32_t result = YA - operand;
|
||||
PSW.C = (result < 0x10000);
|
||||
PSW.Z = ((result & 0xFFFF) == 0);
|
||||
PSW.N = (result & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::MUL(uint8_t operand) {
|
||||
uint16_t result = A * operand;
|
||||
YA = result;
|
||||
PSW.Z = (result == 0);
|
||||
PSW.N = (result & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::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);
|
||||
}
|
||||
|
||||
void Spc700::BRA(int8_t offset) { PC += offset; }
|
||||
|
||||
void Spc700::BEQ(int8_t offset) {
|
||||
if (PSW.Z) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BNE(int8_t offset) {
|
||||
if (!PSW.Z) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BCS(int8_t offset) {
|
||||
if (PSW.C) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BCC(int8_t offset) {
|
||||
if (!PSW.C) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BVS(int8_t offset) {
|
||||
if (PSW.V) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BVC(int8_t offset) {
|
||||
if (!PSW.V) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BMI(int8_t offset) {
|
||||
if (PSW.N) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BPL(int8_t offset) {
|
||||
if (!PSW.N) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BBS(uint8_t bit, uint8_t operand) {
|
||||
if (operand & (1 << bit)) {
|
||||
PC += rel();
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BBC(uint8_t bit, uint8_t operand) {
|
||||
if (!(operand & (1 << bit))) {
|
||||
PC += rel();
|
||||
}
|
||||
}
|
||||
|
||||
// CBNE DBNZ
|
||||
// JMP
|
||||
void Spc700::JMP(uint16_t address) { PC = address; }
|
||||
|
||||
void Spc700::CALL(uint16_t address) {
|
||||
uint16_t return_address = PC + 2;
|
||||
write(SP, return_address & 0xFF);
|
||||
write(SP - 1, (return_address >> 8) & 0xFF);
|
||||
SP -= 2;
|
||||
PC = address;
|
||||
}
|
||||
|
||||
void Spc700::PCALL(uint8_t offset) {
|
||||
uint16_t return_address = PC + 2;
|
||||
write(SP, return_address & 0xFF);
|
||||
write(SP - 1, (return_address >> 8) & 0xFF);
|
||||
SP -= 2;
|
||||
PC += offset;
|
||||
}
|
||||
|
||||
void Spc700::TCALL(uint8_t offset) {
|
||||
uint16_t return_address = PC + 2;
|
||||
write(SP, return_address & 0xFF);
|
||||
write(SP - 1, (return_address >> 8) & 0xFF);
|
||||
SP -= 2;
|
||||
PC = 0xFFDE + offset;
|
||||
}
|
||||
|
||||
void Spc700::BRK() {
|
||||
uint16_t return_address = PC + 2;
|
||||
write(SP, return_address & 0xFF);
|
||||
write(SP - 1, (return_address >> 8) & 0xFF);
|
||||
SP -= 2;
|
||||
PC = 0xFFDE;
|
||||
}
|
||||
|
||||
void Spc700::RET() {
|
||||
uint16_t return_address = read(SP) | (read(SP + 1) << 8);
|
||||
SP += 2;
|
||||
PC = return_address;
|
||||
}
|
||||
|
||||
void Spc700::RETI() {
|
||||
uint16_t return_address = read(SP) | (read(SP + 1) << 8);
|
||||
SP += 2;
|
||||
PC = return_address;
|
||||
PSW.I = 1;
|
||||
}
|
||||
|
||||
void Spc700::PUSH(uint8_t operand) {
|
||||
write(SP, operand);
|
||||
SP--;
|
||||
}
|
||||
|
||||
void Spc700::POP(uint8_t& operand) {
|
||||
SP++;
|
||||
operand = read(SP);
|
||||
}
|
||||
|
||||
void Spc700::SET1(uint8_t bit, uint8_t& operand) { operand |= (1 << bit); }
|
||||
|
||||
void Spc700::CLR1(uint8_t bit, uint8_t& operand) { operand &= ~(1 << bit); }
|
||||
|
||||
void Spc700::TSET1(uint8_t bit, uint8_t& operand) {
|
||||
PSW.C = (operand & (1 << bit));
|
||||
operand |= (1 << bit);
|
||||
}
|
||||
|
||||
void Spc700::TCLR1(uint8_t bit, uint8_t& operand) {
|
||||
PSW.C = (operand & (1 << bit));
|
||||
operand &= ~(1 << bit);
|
||||
}
|
||||
|
||||
void Spc700::AND1(uint8_t bit, uint8_t& operand) {
|
||||
operand &= (1 << bit);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::OR1(uint8_t bit, uint8_t& operand) {
|
||||
operand |= (1 << bit);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::EOR1(uint8_t bit, uint8_t& operand) {
|
||||
operand ^= (1 << bit);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::NOT1(uint8_t bit, uint8_t& operand) {
|
||||
operand ^= (1 << bit);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::MOV1(uint8_t bit, uint8_t& operand) {
|
||||
PSW.C = (operand & (1 << bit));
|
||||
operand |= (1 << bit);
|
||||
}
|
||||
|
||||
void Spc700::CLRC() { PSW.C = 0; }
|
||||
|
||||
void Spc700::SETC() { PSW.C = 1; }
|
||||
|
||||
void Spc700::NOTC() { PSW.C = !PSW.C; }
|
||||
|
||||
void Spc700::CLRV() { PSW.V = 0; }
|
||||
|
||||
void Spc700::CLRP() { PSW.P = 0; }
|
||||
|
||||
void Spc700::SETP() { PSW.P = 1; }
|
||||
|
||||
void Spc700::EI() { PSW.I = 1; }
|
||||
|
||||
void Spc700::DI() { PSW.I = 0; }
|
||||
|
||||
void Spc700::NOP() { PC++; }
|
||||
|
||||
void Spc700::SLEEP() {}
|
||||
|
||||
void Spc700::STOP() {}
|
||||
|
||||
} // namespace emu
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
263
src/app/emu/audio/internal/opcodes.h
Normal file
263
src/app/emu/audio/internal/opcodes.h
Normal file
@@ -0,0 +1,263 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
const std::unordered_map<uint8_t, std::string> spc_opcode_map = {
|
||||
{0x00, "NOP"},
|
||||
{0x01, "TCALL0"},
|
||||
{0x02, "SET1 direct.0"},
|
||||
{0x03, "BBS direct.0,rel"},
|
||||
{0x04, "OR A,direct"},
|
||||
{0x05, "OR A,abs"},
|
||||
{0x06, "OR A,(X)"},
|
||||
{0x07, "OR A,(direct+X)"},
|
||||
{0x08, "OR A,#imm"},
|
||||
{0x09, "OR direct,imm"},
|
||||
{0x0A, "OR1 C,membit"},
|
||||
{0x0B, "ASL direct"},
|
||||
{0x0C, "ASL abs"},
|
||||
{0x0D, "PUSH PSW"},
|
||||
{0x0E, "TSET1 abs"},
|
||||
{0x0F, "BRK"},
|
||||
{0x10, "BPL rel"},
|
||||
{0x11, "TCALL1"},
|
||||
{0x12, "CLR1 direct.0"},
|
||||
{0x13, "BBC direct.0,rel"},
|
||||
{0x14, "OR A,direct+X"},
|
||||
{0x15, "OR A,abs+X"},
|
||||
{0x16, "OR A,abs+Y"},
|
||||
{0x17, "OR A,(direct)+Y"},
|
||||
{0x18, "OR direct,direct"},
|
||||
{0x19, "OR (X),(Y)"},
|
||||
{0x1A, "DECW direct"},
|
||||
{0x1B, "ASL direct+X"},
|
||||
{0x1C, "ASL A"},
|
||||
{0x1D, "DEC X"},
|
||||
{0x1E, "CMP X,abs"},
|
||||
{0x1F, "JMP (abs+X)"},
|
||||
{0x20, "CLRP"},
|
||||
{0x21, "TCALL2"},
|
||||
{0x22, "SET1 direct.1"},
|
||||
{0x23, "BBS direct.1,rel"},
|
||||
{0x24, "AND A,direct"},
|
||||
{0x25, "AND A,abs"},
|
||||
{0x26, "AND A,(X)"},
|
||||
{0x27, "AND A,(direct+X)"},
|
||||
{0x28, "AND A,#imm"},
|
||||
{0x29, "AND direct,imm"},
|
||||
{0x2A, "OR1 C,/membit"},
|
||||
{0x2B, "ROL direct"},
|
||||
{0x2C, "ROL abs"},
|
||||
{0x2D, "PUSH A"},
|
||||
{0x2E, "CBNE direct,rel"},
|
||||
{0x2F, "BRA rel"},
|
||||
{0x30, "BMI rel"},
|
||||
{0x31, "TCALL3"},
|
||||
{0x32, "CLR1 direct.1"},
|
||||
{0x33, "BBC direct.1,rel"},
|
||||
{0x34, "AND A,direct+X"},
|
||||
{0x35, "AND A,abs+X"},
|
||||
{0x36, "AND A,abs+Y"},
|
||||
{0x37, "AND A,(direct)+Y"},
|
||||
{0x38, "AND direct,direct"},
|
||||
{0x39, "AND (X),(Y)"},
|
||||
{0x3A, "INCW direct"},
|
||||
{0x3B, "ROL direct+X"},
|
||||
{0x3C, "ROL A"},
|
||||
{0x3D, "INC X"},
|
||||
{0x3E, "CMP X,direct"},
|
||||
{0x3F, "CALL abs"},
|
||||
{0x40, "SETP"},
|
||||
{0x41, "TCALL4"},
|
||||
{0x42, "SET1 direct.2"},
|
||||
{0x43, "BBS direct.2,rel"},
|
||||
{0x44, "EOR A,direct"},
|
||||
{0x45, "EOR A,abs"},
|
||||
{0x46, "EOR A,(X)"},
|
||||
{0x47, "EOR A,(direct+X)"},
|
||||
{0x48, "EOR A,#imm"},
|
||||
{0x49, "EOR direct,imm"},
|
||||
{0x4A, "AND1 C,membit"},
|
||||
{0x4B, "LSR direct"},
|
||||
{0x4C, "LSR abs"},
|
||||
{0x4D, "PUSH X"},
|
||||
{0x4E, "TCLR1 abs"},
|
||||
{0x4F, "PCALL addr"},
|
||||
{0x50, "BVC rel"},
|
||||
{0x51, "TCALL5"},
|
||||
{0x52, "CLR1 direct.2"},
|
||||
{0x53, "BBC direct.2,rel"},
|
||||
{0x54, "EOR A,direct+X"},
|
||||
{0x55, "EOR A,abs+X"},
|
||||
{0x56, "EOR A,abs+Y"},
|
||||
{0x57, "EOR A,(direct)+Y"},
|
||||
{0x58, "EOR direct,direct"},
|
||||
{0x59, "EOR (X),(Y)"},
|
||||
{0x5A, "CMPW YA,direct"},
|
||||
{0x5B, "LSR direct+X"},
|
||||
{0x5C, "LSR A"},
|
||||
{0x5D, "MOV X,A"},
|
||||
{0x5E, "CMP Y,abs"},
|
||||
{0x5F, "JMP abs"},
|
||||
{0x60, "CLRC"},
|
||||
{0x61, "TCALL6"},
|
||||
{0x62, "SET1 direct.3"},
|
||||
{0x63, "BBS direct.3,rel"},
|
||||
{0x64, "CMP A,direct"},
|
||||
{0x65, "CMP A,abs"},
|
||||
{0x66, "CMP A,(X)"},
|
||||
{0x67, "CMP A,(direct+X)"},
|
||||
{0x68, "CMP A,#imm"},
|
||||
{0x69, "CMP direct,imm"},
|
||||
{0x6A, "AND1 C,/membit"},
|
||||
{0x6B, "ROR direct"},
|
||||
{0x6C, "ROR abs"},
|
||||
{0x6D, "PUSH Y"},
|
||||
{0x6E, "DBNZ direct,rel"},
|
||||
{0x6F, "RET"},
|
||||
{0x70, "BVS rel"},
|
||||
{0x71, "TCALL7"},
|
||||
{0x72, "CLR1 direct.3"},
|
||||
{0x73, "BBC direct.3,rel"},
|
||||
{0x74, "CMP A,direct+X"},
|
||||
{0x75, "CMP A,abs+X"},
|
||||
{0x76, "CMP A,abs+Y"},
|
||||
{0x77, "CMP A,(direct)+Y"},
|
||||
{0x78, "CMP direct,direct"},
|
||||
{0x79, "CMP (X),(Y)"},
|
||||
{0x7A, "ADDW YA,direct"},
|
||||
{0x7B, "ROR direct+X"},
|
||||
{0x7C, "ROR A"},
|
||||
{0x7D, "MOV A,X"},
|
||||
{0x7E, "CMP Y,direct"},
|
||||
{0x7F, "RETI"},
|
||||
{0x80, "SETC"},
|
||||
{0x81, "TCALL8"},
|
||||
{0x82, "SET1 direct.4"},
|
||||
{0x83, "BBS direct.4,rel"},
|
||||
{0x84, "ADC A,direct"},
|
||||
{0x85, "ADC A,abs"},
|
||||
{0x86, "ADC A,(X)"},
|
||||
{0x87, "ADC A,(direct+X)"},
|
||||
{0x88, "ADC A,#imm"},
|
||||
{0x89, "ADC direct,imm"},
|
||||
{0x8A, "EOR1 C,membit"},
|
||||
{0x8B, "DEC direct"},
|
||||
{0x8C, "DEC abs"},
|
||||
{0x8D, "MOV Y,#imm"},
|
||||
{0x8E, "POP PSW"},
|
||||
{0x8F, "MOV direct,#imm"},
|
||||
{0x90, "BCC rel"},
|
||||
{0x91, "TCALL9"},
|
||||
{0x92, "CLR1 direct.4"},
|
||||
{0x93, "BBC direct.4,rel"},
|
||||
{0x94, "ADC A,direct+X"},
|
||||
{0x95, "ADC A,abs+X"},
|
||||
{0x96, "ADC A,abs+Y"},
|
||||
{0x97, "ADC A,(direct)+Y"},
|
||||
{0x98, "ADC direct,direct"},
|
||||
{0x99, "ADC (X),(Y)"},
|
||||
{0x9A, "SUBW YA,direct"},
|
||||
{0x9B, "DEC direct+X"},
|
||||
{0x9C, "DEC A"},
|
||||
{0x9D, "MOV X,SP"},
|
||||
{0x9E, "DIV YA,X"},
|
||||
{0x9F, "XCN A"},
|
||||
{0xA0, "EI"},
|
||||
{0xA1, "TCALL10"},
|
||||
{0xA2, "SET1 direct.5"},
|
||||
{0xA3, "BBS direct.5,rel"},
|
||||
{0xA4, "SBC A,direct"},
|
||||
{0xA5, "SBC A,abs"},
|
||||
{0xA6, "SBC A,(X)"},
|
||||
{0xA7, "SBC A,(direct+X)"},
|
||||
{0xA8, "SBC A,#imm"},
|
||||
{0xA9, "SBC direct,imm"},
|
||||
{0xAA, "MOV1 C,membit"},
|
||||
{0xAB, "INC direct"},
|
||||
{0xAC, "INC abs"},
|
||||
{0xAD, "CMP Y,#imm"},
|
||||
{0xAE, "POP A"},
|
||||
{0xAF, "MOV (X)+,A"},
|
||||
{0xB0, "BCS rel"},
|
||||
{0xB1, "TCALL11"},
|
||||
{0xB2, "CLR1 direct.5"},
|
||||
{0xB3, "BBC direct.5,rel"},
|
||||
{0xB4, "SBC A,direct+X"},
|
||||
{0xB5, "SBC A,abs+X"},
|
||||
{0xB6, "SBC A,abs+Y"},
|
||||
{0xB7, "SBC A,(direct)+Y"},
|
||||
{0xB8, "SBC direct,direct"},
|
||||
{0xB9, "SBC (X),(Y)"},
|
||||
{0xBA, "MOVW YA,direct"},
|
||||
{0xBB, "INC direct+X"},
|
||||
{0xBC, "INC A"},
|
||||
{0xBD, "MOV SP,X"},
|
||||
{0xBE, "DAS"},
|
||||
{0xBF, "MOV A,(X)+"},
|
||||
{0xC0, "DI"},
|
||||
{0xC1, "TCALL12"},
|
||||
{0xC2, "SET1 direct.6"},
|
||||
{0xC3, "BBS direct.6,rel"},
|
||||
{0xC4, "MOV direct,A"},
|
||||
{0xC5, "MOV abs,A"},
|
||||
{0xC6, "MOV (X),A"},
|
||||
{0xC7, "MOV (direct+X),A"},
|
||||
{0xC8, "CMP X,#imm"},
|
||||
{0xC9, "MOV abs,X"},
|
||||
{0xCA, "MOV1 membit,C"},
|
||||
{0xCB, "MOV direct,Y"},
|
||||
{0xCC, "MOV abs,Y"},
|
||||
{0xCD, "MOV X,#imm"},
|
||||
{0xCE, "POP X"},
|
||||
{0xCF, "MUL YA"},
|
||||
{0xD0, "BNE rel"},
|
||||
{0xD1, "TCALL13"},
|
||||
{0xD2, "CLR1 direct.6"},
|
||||
{0xD3, "BBC direct.6,rel"},
|
||||
{0xD4, "MOV direct+X,A"},
|
||||
{0xD5, "MOV abs+X,A"},
|
||||
{0xD6, "MOV abs+Y,A"},
|
||||
{0xD7, "MOV (direct)+Y,A"},
|
||||
{0xD8, "MOV direct,X"},
|
||||
{0xD9, "MOV direct+Y,X"},
|
||||
{0xDA, "MOVW direct,YA"},
|
||||
{0xDB, "MOV direct+X,Y"},
|
||||
{0xDC, "DEC Y"},
|
||||
{0xDD, "MOV A,Y"},
|
||||
{0xDE, "CBNE direct+X,rel"},
|
||||
{0xDF, "DAA"},
|
||||
{0xE0, "CLRV"},
|
||||
{0xE1, "TCALL14"},
|
||||
{0xE2, "SET1 direct.7"},
|
||||
{0xE3, "BBS direct.7,rel"},
|
||||
{0xE4, "MOV A,direct"},
|
||||
{0xE5, "MOV A,abs"},
|
||||
{0xE6, "MOV A,(X)"},
|
||||
{0xE7, "MOV A,(direct+X)"},
|
||||
{0xE8, "MOV A,#imm"},
|
||||
{0xE9, "MOV X,abs"},
|
||||
{0xEA, "NOT1 membit"},
|
||||
{0xEB, "MOV Y,direct"},
|
||||
{0xEC, "MOV Y,abs"},
|
||||
{0xED, "NOTC"},
|
||||
{0xEE, "POP Y"},
|
||||
{0xEF, "SLEEP"},
|
||||
{0xF0, "BEQ rel"},
|
||||
{0xF1, "TCALL15"},
|
||||
{0xF2, "CLR1 direct.7"},
|
||||
{0xF3, "BBC direct.7,rel"},
|
||||
{0xF4, "MOV A,direct+X"},
|
||||
{0xF5, "MOV A,abs+X"},
|
||||
{0xF6, "MOV A,abs+Y"},
|
||||
{0xF7, "MOV A,(direct)+Y"},
|
||||
{0xF8, "MOV X,direct"},
|
||||
{0xF9, "MOV X,direct+Y"},
|
||||
{0xFA, "MOV direct,S"},
|
||||
{0xFB, "MOV Y,direct+X"},
|
||||
{0xFC, "INC Y"},
|
||||
{0xFD, "MOV Y,A"},
|
||||
{0xFE, "DBNZ Y,rel"},
|
||||
{0xFF, "STOP"}};
|
||||
@@ -1,206 +1,337 @@
|
||||
#include "app/emu/audio/spc700.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "app/emu/audio/internal/opcodes.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace emu {
|
||||
|
||||
void SPC700::Reset() {}
|
||||
void Spc700::Reset() {}
|
||||
|
||||
void SPC700::Notify(uint32_t address, uint8_t data) {
|
||||
// Check if the address corresponds to the APU's I/O ports
|
||||
if (address >= 0x2140 && address <= 0x2143) {
|
||||
// Handle the IPL process based on the address and data
|
||||
if (address == 0x2140) {
|
||||
// ... Handle data sent to APUIO0 ...
|
||||
// For instance, checking for the $CC signal to start the APU program
|
||||
} else if (address == 0x2141) {
|
||||
// ... Handle data sent to APUIO1 ...
|
||||
// This might involve storing data for the APU or signaling the DSP, etc.
|
||||
} else if (address == 0x2142) {
|
||||
// ... Handle data sent to APUIO2 ...
|
||||
} else if (address == 0x2143) {
|
||||
// ... Handle data sent to APUIO3 ...
|
||||
void Spc700::BootIplRom() {
|
||||
PC = 0xFFC0;
|
||||
A = 0;
|
||||
X = 0;
|
||||
Y = 0;
|
||||
|
||||
// for (int i = 0; i < 0x40; ++i) {
|
||||
// uint8_t opcode = read(PC);
|
||||
// ExecuteInstructions(opcode);
|
||||
// PC++;
|
||||
// }
|
||||
|
||||
int i = 0;
|
||||
while (PC != 0xFFC0 + 0x3F) {
|
||||
uint8_t opcode = read(PC);
|
||||
ExecuteInstructions(opcode);
|
||||
PC++;
|
||||
i++;
|
||||
|
||||
if (i > 1000) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
void Spc700::ExecuteInstructions(uint8_t opcode) {
|
||||
uint16_t initialPC = PC;
|
||||
switch (opcode) {
|
||||
// 8-bit Move Memory to Register
|
||||
// 8-bit Move Memory to Register
|
||||
case 0xE8: // MOV A, #imm
|
||||
{
|
||||
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
|
||||
|
||||
// 8-bit move register to memory
|
||||
case 0xC6: // MOV (X), A
|
||||
{
|
||||
MOV_ADDR(X, A);
|
||||
break;
|
||||
}
|
||||
case 0xAF: // MOV (X)+, A
|
||||
{
|
||||
MOV_ADDR(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
|
||||
|
||||
// . 8-bit move register to register / special direct page moves
|
||||
case 0x7D: // MOV A, X
|
||||
{
|
||||
MOV(A, X);
|
||||
break;
|
||||
}
|
||||
case 0xDD: // MOV A, Y
|
||||
{
|
||||
MOV(A, Y);
|
||||
break;
|
||||
}
|
||||
case 0x5D: // MOV X, A
|
||||
{
|
||||
MOV(X, A);
|
||||
break;
|
||||
}
|
||||
case 0xFD: // MOV Y, A
|
||||
{
|
||||
MOV(Y, A);
|
||||
break;
|
||||
}
|
||||
case 0x9D: // MOV X, SP
|
||||
{
|
||||
MOV(X, SP);
|
||||
break;
|
||||
}
|
||||
case 0xBD: // MOV SP, X
|
||||
{
|
||||
MOV(SP, X);
|
||||
break;
|
||||
}
|
||||
case 0xFA: // MOV dp, dp
|
||||
{
|
||||
MOV_ADDR(get_dp_addr(), dp());
|
||||
break;
|
||||
}
|
||||
case 0x8F: // MOV dp, #imm
|
||||
{
|
||||
MOV_ADDR(get_dp_addr(), imm());
|
||||
break;
|
||||
}
|
||||
|
||||
// . 8-bit arithmetic
|
||||
|
||||
// . 8-bit arithmetic
|
||||
case 0x88: // ADC A, #imm
|
||||
{
|
||||
ADC(A, imm());
|
||||
break;
|
||||
}
|
||||
case 0x86: // ADC A, (X)
|
||||
{
|
||||
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
|
||||
{
|
||||
ADC(A, abs() + X);
|
||||
break;
|
||||
}
|
||||
case 0x96: // ADC A, !abs+Y
|
||||
{
|
||||
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;
|
||||
case 0x89: // ADC dp, dp
|
||||
break;
|
||||
case 0x98: // ADC dp, #imm
|
||||
break;
|
||||
|
||||
case 0xA8: // SBC A, #imm
|
||||
SBC(A, imm());
|
||||
break;
|
||||
case 0xA6: // SBC A, (X)
|
||||
break;
|
||||
case 0xA4: // SBC A, dp
|
||||
SBC(A, dp());
|
||||
break;
|
||||
case 0xB4: // SBC A, dp+X
|
||||
SBC(A, dp_plus_x());
|
||||
break;
|
||||
case 0xA5: // SBC A, !abs
|
||||
SBC(A, abs());
|
||||
break;
|
||||
case 0xB5: // SBC A, !abs+X
|
||||
SBC(A, abs() + X);
|
||||
break;
|
||||
case 0xB6: // SBC A, !abs+Y
|
||||
SBC(A, abs() + Y);
|
||||
break;
|
||||
case 0xA7: // SBC A, [dp+X]
|
||||
SBC(A, dp_plus_x_indirect());
|
||||
break;
|
||||
case 0xB7: // SBC A, [dp]+Y
|
||||
SBC(A, dp_indirect_plus_y());
|
||||
break;
|
||||
case 0xB9: // SBC (X), (Y)
|
||||
break;
|
||||
@@ -208,19 +339,26 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
break;
|
||||
case 0xB8: // SBC dp, #imm
|
||||
break;
|
||||
|
||||
case 0x68: // CMP A, #imm
|
||||
CMP(A, imm());
|
||||
break;
|
||||
case 0x66: // CMP A, (X)
|
||||
break;
|
||||
case 0x64: // CMP A, dp
|
||||
CMP(A, dp());
|
||||
break;
|
||||
case 0x74: // CMP A, dp+X
|
||||
CMP(A, dp_plus_x());
|
||||
break;
|
||||
case 0x65: // CMP A, !abs
|
||||
CMP(A, abs());
|
||||
break;
|
||||
case 0x75: // CMP A, !abs+X
|
||||
CMP(A, abs() + X);
|
||||
break;
|
||||
case 0x76: // CMP A, !abs+Y
|
||||
CMP(A, abs() + Y);
|
||||
break;
|
||||
case 0x67: // CMP A, [dp+X]
|
||||
break;
|
||||
@@ -245,8 +383,7 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
case 0x5E: // CMP Y, !abs
|
||||
break;
|
||||
|
||||
// 8-bit boolean logic
|
||||
|
||||
// 8-bit boolean logic
|
||||
case 0x28: // AND A, #imm
|
||||
AND(A, imm());
|
||||
break;
|
||||
@@ -287,12 +424,16 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
OR(A, abs());
|
||||
break;
|
||||
case 0x15: // OR A, !abs+X
|
||||
OR(A, abs() + X);
|
||||
break;
|
||||
case 0x16: // OR A, !abs+Y
|
||||
OR(A, abs() + Y);
|
||||
break;
|
||||
case 0x07: // OR A, [dp+X]
|
||||
OR(A, dp_plus_x_indirect());
|
||||
break;
|
||||
case 0x17: // OR A, [dp]+Y
|
||||
OR(A, dp_indirect_plus_y());
|
||||
break;
|
||||
case 0x19: // OR (X), (Y)
|
||||
break;
|
||||
@@ -309,16 +450,22 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
EOR(A, dp());
|
||||
break;
|
||||
case 0x54: // EOR A, dp+X
|
||||
EOR(A, dp_plus_x());
|
||||
break;
|
||||
case 0x45: // EOR A, !abs
|
||||
EOR(A, abs());
|
||||
break;
|
||||
case 0x55: // EOR A, !abs+X
|
||||
EOR(A, abs() + X);
|
||||
break;
|
||||
case 0x56: // EOR A, !abs+Y
|
||||
EOR(A, abs() + Y);
|
||||
break;
|
||||
case 0x47: // EOR A, [dp+X]
|
||||
EOR(A, dp_plus_x_indirect());
|
||||
break;
|
||||
case 0x57: // EOR A, [dp]+Y
|
||||
EOR(A, dp_indirect_plus_y());
|
||||
break;
|
||||
case 0x59: // EOR (X), (Y)
|
||||
break;
|
||||
@@ -406,6 +553,7 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
// . 16-bit operations
|
||||
|
||||
case 0xBA: // MOVW YA, dp
|
||||
MOVW(YA, dp());
|
||||
break;
|
||||
case 0xDA: // MOVW dp, YA
|
||||
break;
|
||||
@@ -478,24 +626,50 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
case 0x7F: // RETI
|
||||
break;
|
||||
|
||||
// . stack
|
||||
|
||||
// . stack
|
||||
case 0x2D: // PUSH A
|
||||
{
|
||||
PUSH(A);
|
||||
break;
|
||||
}
|
||||
case 0x4D: // PUSH X
|
||||
{
|
||||
PUSH(X);
|
||||
break;
|
||||
}
|
||||
case 0x6D: // PUSH Y
|
||||
{
|
||||
PUSH(Y);
|
||||
break;
|
||||
}
|
||||
case 0x0D: // PUSH PSW
|
||||
{
|
||||
PUSH(FlagsToByte(PSW));
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xAE: // POP A
|
||||
{
|
||||
POP(A);
|
||||
break;
|
||||
}
|
||||
case 0xCE: // POP X
|
||||
{
|
||||
POP(X);
|
||||
break;
|
||||
}
|
||||
case 0xEE: // POP Y
|
||||
{
|
||||
POP(Y);
|
||||
break;
|
||||
}
|
||||
case 0x8E: // POP PSW
|
||||
{
|
||||
uint8_t flags_byte;
|
||||
POP(flags_byte);
|
||||
PSW = ByteToFlags(flags_byte);
|
||||
break;
|
||||
}
|
||||
|
||||
// . memory bit operations
|
||||
|
||||
@@ -519,35 +693,81 @@ void SPC700::ExecuteInstructions(uint8_t opcode) {
|
||||
// . status flags
|
||||
|
||||
case 0x60: // CLRC
|
||||
CLRC();
|
||||
break;
|
||||
case 0x80: // SETC
|
||||
SETC();
|
||||
break;
|
||||
case 0xED: // NOTC
|
||||
NOTC();
|
||||
break;
|
||||
case 0xE0: // CLRV
|
||||
CLRV();
|
||||
break;
|
||||
case 0x20: // CLRP
|
||||
CLRP();
|
||||
break;
|
||||
case 0x40: // SETP
|
||||
SETP();
|
||||
break;
|
||||
case 0xA0: // EI
|
||||
EI();
|
||||
break;
|
||||
case 0xC0: // DI
|
||||
DI();
|
||||
break;
|
||||
|
||||
// .no-operation and halt
|
||||
|
||||
// .no-operation and haltF
|
||||
case 0x00: // NOP
|
||||
{
|
||||
NOP();
|
||||
break;
|
||||
}
|
||||
case 0xEF: // SLEEP
|
||||
{
|
||||
SLEEP();
|
||||
break;
|
||||
}
|
||||
case 0x0F: // STOP
|
||||
{
|
||||
STOP();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
std::cout << "Unknown opcode: " << std::hex << opcode << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
LogInstruction(initialPC, opcode);
|
||||
}
|
||||
|
||||
void Spc700::LogInstruction(uint16_t initial_pc, uint8_t opcode) {
|
||||
std::string mnemonic = spc_opcode_map.at(opcode);
|
||||
|
||||
std::stringstream log_entry_stream;
|
||||
log_entry_stream << "\033[1;36m$" << std::hex << std::setw(4)
|
||||
<< std::setfill('0') << initial_pc << "\033[0m";
|
||||
log_entry_stream << " \033[1;32m" << std::hex << std::setw(2)
|
||||
<< std::setfill('0') << static_cast<int>(opcode) << "\033[0m"
|
||||
<< " \033[1;35m" << std::setw(18) << std::left
|
||||
<< std::setfill(' ') << mnemonic << "\033[0m";
|
||||
|
||||
log_entry_stream << " \033[1;33mA: " << std::hex << std::setw(2)
|
||||
<< std::setfill('0') << std::right << static_cast<int>(A)
|
||||
<< "\033[0m";
|
||||
log_entry_stream << " \033[1;33mX: " << std::hex << std::setw(2)
|
||||
<< std::setfill('0') << std::right << static_cast<int>(X)
|
||||
<< "\033[0m";
|
||||
log_entry_stream << " \033[1;33mY: " << std::hex << std::setw(2)
|
||||
<< std::setfill('0') << std::right << static_cast<int>(Y)
|
||||
<< "\033[0m";
|
||||
std::string log_entry = log_entry_stream.str();
|
||||
|
||||
std::cerr << log_entry << std::endl;
|
||||
|
||||
// Append the log entry to the log
|
||||
log_.push_back(log_entry);
|
||||
}
|
||||
|
||||
} // namespace emu
|
||||
|
||||
@@ -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