yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
spc700.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EMU_SPC700_H
2#define YAZE_APP_EMU_SPC700_H
3
4#include <cstdint>
5#include <functional>
6#include <string>
7#include <vector>
8
9namespace yaze {
10namespace emu {
11
15class AudioRam {
16 public:
17 virtual ~AudioRam() = default;
18 virtual void reset() = 0;
19 virtual uint8_t read(uint16_t address) const = 0;
20 virtual uint8_t& mutable_read(uint16_t address) = 0;
21 virtual void write(uint16_t address, uint8_t value) = 0;
22 uint8_t operator[](uint16_t address) { return mutable_read(address); }
23};
24
28class AudioRamImpl : public AudioRam {
29 static const int ARAM_SIZE = 0x10000;
30 std::vector<uint8_t> ram = std::vector<uint8_t>(ARAM_SIZE, 0);
31
32 public:
33 AudioRamImpl() = default;
34 void reset() override { ram = std::vector<uint8_t>(ARAM_SIZE, 0); }
35
36 uint8_t read(uint16_t address) const override {
37 return ram[address % ARAM_SIZE];
38 }
39
40 uint8_t& mutable_read(uint16_t address) override {
41 return ram.at(address % ARAM_SIZE);
42 }
43
44 void write(uint16_t address, uint8_t value) override {
45 ram[address % ARAM_SIZE] = value;
46 }
47
48 // add [] operators
49 uint8_t operator[](uint16_t address) const { return read(address); }
50};
51
52typedef struct ApuCallbacks {
53 std::function<void(uint16_t, uint8_t)> write;
54 std::function<uint8_t(uint16_t)> read;
55 std::function<void(bool)> idle;
56} ApuCallbacks;
57
69class Spc700 {
70 private:
72 std::vector<std::string> log_;
73
76 // single-cycle
77 uint8_t opcode;
78 uint32_t step = 0;
79 uint32_t bstep;
80 uint16_t adr;
81 uint16_t adr1;
82 uint8_t dat;
83 uint16_t dat16;
84 uint8_t param;
86
87 // Cycle tracking for accurate APU synchronization
89
90 const uint8_t ipl_rom_[64]{
91 0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0, 0xFC, 0x8F, 0xAA,
92 0xF4, 0x8F, 0xBB, 0xF5, 0x78, 0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19,
93 0xEB, 0xF4, 0xD0, 0xFC, 0x7E, 0xF4, 0xD0, 0x0B, 0xE4, 0xF5, 0xCB,
94 0xF4, 0xD7, 0x00, 0xFC, 0xD0, 0xF3, 0xAB, 0x01, 0x10, 0xEF, 0x7E,
95 0xF4, 0x10, 0xEB, 0xBA, 0xF6, 0xDA, 0x00, 0xBA, 0xF4, 0xC4, 0xF4,
96 0xDD, 0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF};
97
98 public:
99 explicit Spc700(ApuCallbacks& callbacks) : callbacks_(callbacks) {}
100
101 // Registers
102 uint8_t A = 0x00; // 8-bit accumulator
103 uint8_t X = 0x00; // 8-bit index
104 uint8_t Y = 0x00; // 8-bit index
105 uint16_t YA = 0x00; // 16-bit pair of A (lsb) and Y (msb)
106 uint16_t PC = 0xFFC0; // program counter
107 uint8_t SP = 0x00; // stack pointer
108
109 struct Flags {
110 bool N : 1; // Negative flag
111 bool V : 1; // Overflow flag
112 bool P : 1; // Direct page flag
113 bool B : 1; // Break flag
114 bool H : 1; // Half-carry flag
115 bool I : 1; // Interrupt enable
116 bool Z : 1; // Zero flag
117 bool C : 1; // Carry flag
118 };
119 Flags PSW; // Processor status word
120
121 uint8_t FlagsToByte(Flags flags) {
122 return (flags.N << 7) | (flags.V << 6) | (flags.P << 5) | (flags.B << 4) |
123 (flags.H << 3) | (flags.I << 2) | (flags.Z << 1) | (flags.C);
124 }
125
126 Flags ByteToFlags(uint8_t byte) {
127 Flags flags;
128 flags.N = (byte & 0x80) >> 7;
129 flags.V = (byte & 0x40) >> 6;
130 flags.P = (byte & 0x20) >> 5;
131 flags.B = (byte & 0x10) >> 4;
132 flags.H = (byte & 0x08) >> 3;
133 flags.I = (byte & 0x04) >> 2;
134 flags.Z = (byte & 0x02) >> 1;
135 flags.C = (byte & 0x01);
136 return flags;
137 }
138
139 void Reset(bool hard = false);
140
141 void RunOpcode();
142
143 // New atomic step function - executes one complete instruction and returns cycles consumed
144 // This is the preferred method for cycle-accurate emulation
145 int Step();
146
147 // Get the number of cycles consumed by the last opcode execution
149
150 void ExecuteInstructions(uint8_t opcode);
151 void LogInstruction(uint16_t initial_pc, uint8_t opcode);
152
153 // Read a byte from the memory-mapped registers
154 uint8_t read(uint16_t address) { return callbacks_.read(address); }
155
156 uint16_t read_word(uint16_t address) {
157 uint16_t adrl = address;
158 uint16_t adrh = address + 1;
159 uint8_t value = callbacks_.read(adrl);
160 return value | (callbacks_.read(adrh) << 8);
161 }
162
163 uint8_t ReadOpcode() {
164 uint8_t opcode = callbacks_.read(PC++);
165 return opcode;
166 }
167
168 uint16_t ReadOpcodeWord() {
169 uint8_t low = ReadOpcode();
170 uint8_t high = ReadOpcode();
171 return low | (high << 8);
172 }
173
174 void DoBranch(uint8_t value, bool check) {
175 callbacks_.idle(false); // Add missing base cycle for all branches
176 if (check) {
177 // taken branch: 2 extra cycles
178 callbacks_.idle(false);
179 callbacks_.idle(false);
180 PC += (int8_t)value;
181 extra_cycles_ = 2;
182 }
183 }
184
185 // Write a byte to the memory-mapped registers
186 void write(uint16_t address, uint8_t value) {
187 callbacks_.write(address, value);
188 }
189
190 void push_byte(uint8_t value) {
191 callbacks_.write(0x100 | SP, value);
192 SP--;
193 }
194
195 void push_word(uint16_t value) {
196 push_byte(value >> 8);
197 push_byte(value & 0xFF);
198 }
199
200 uint8_t pull_byte() {
201 SP++;
202 return read(0x100 | SP);
203 }
204
205 uint16_t pull_word() {
206 uint16_t value = pull_byte();
207 value |= pull_byte() << 8;
208 return value;
209 }
210
211 // ======================================================
212 // Addressing modes
213
214 // Immediate
215 uint16_t imm();
216
217 // Direct page
218 uint8_t dp();
219 uint16_t dpx();
220
221 uint8_t get_dp_addr();
222
223 uint8_t abs_bit(uint16_t* adr);
224 uint16_t dp_dp(uint8_t* src);
225 uint16_t ind();
226 uint16_t ind_ind(uint8_t* srcVal);
227 uint16_t dp_word(uint16_t* low);
228 uint16_t ind_p();
229 uint16_t abs_x();
230 uint16_t abs_y();
231 uint16_t idx();
232 uint16_t idy();
233 uint16_t dp_y();
234 uint16_t dp_imm(uint8_t* srcVal);
235 uint16_t abs();
236
237 int8_t rel();
238
239 // Direct page indexed by X
240 uint8_t dp_plus_x();
241
242 // Direct page indexed by Y
243 uint8_t dp_plus_y();
244
245 // Indexed indirect (add index before 16-bit lookup).
246 uint16_t dp_plus_x_indirect();
247
248 // Indirect indexed (add index after 16-bit lookup).
249 uint16_t dp_indirect_plus_y();
250 uint8_t i();
251
252 uint8_t i_postinc();
253
254 uint16_t addr_plus_i();
255
256 uint16_t addr_plus_i_indexed();
257
258 // ==========================================================================
259 // Instructions
260
261 void MOV(uint16_t adr);
262 void MOV_ADDR(uint16_t address, uint8_t operand);
263 void MOVY(uint16_t adr);
264 void MOVX(uint16_t adr);
265 void MOVS(uint16_t adr);
266 void MOVSX(uint16_t adr);
267 void MOVSY(uint16_t adr);
268
269 void ADC(uint16_t adr);
270 void ADCM(uint16_t& dest, uint8_t operand);
271
272 void SBC(uint16_t adr);
273 void SBCM(uint16_t& dest, uint8_t operand);
274
275 void CMP(uint16_t adr);
276 void CMPX(uint16_t adr);
277 void CMPM(uint16_t dst, uint8_t value);
278 void CMPY(uint16_t adr);
279
280 void AND(uint16_t adr);
281 void ANDM(uint16_t dest, uint8_t operand);
282
283 void OR(uint16_t adr);
284 void ORM(uint16_t dest, uint8_t operand);
285
286 void EOR(uint16_t adr);
287 void EORM(uint16_t dest, uint8_t operand);
288
289 void ASL(uint16_t operand);
290 void LSR(uint16_t adr);
291
292 void ROL(uint16_t operand);
293 void ROR(uint16_t adr);
294
295 void XCN(uint8_t operand, bool isImmediate = false);
296 void INC(uint16_t adr);
297 void DEC(uint16_t operand);
298 void MOVW(uint16_t& dest, uint16_t operand);
299 void INCW(uint16_t& operand);
300 void DECW(uint16_t& operand);
301 void ADDW(uint16_t& dest, uint16_t operand);
302 void SUBW(uint16_t& dest, uint16_t operand);
303 void CMPW(uint16_t operand);
304 void MUL(uint8_t operand);
305 void DIV(uint8_t operand);
306 void BRA(int8_t offset);
307 void BEQ(int8_t offset);
308 void BNE(int8_t offset);
309 void BCS(int8_t offset);
310 void BCC(int8_t offset);
311 void BVS(int8_t offset);
312 void BVC(int8_t offset);
313 void BMI(int8_t offset);
314 void BPL(int8_t offset);
315 void BBS(uint8_t bit, uint8_t operand);
316 void BBC(uint8_t bit, uint8_t operand);
317 void JMP(uint16_t address);
318 void CALL(uint16_t address);
319 void PCALL(uint8_t offset);
320 void TCALL(uint8_t offset);
321 void BRK();
322 void RET();
323 void RETI();
324 void PUSH(uint8_t operand);
325 void POP(uint8_t& operand);
326 void SET1(uint8_t bit, uint8_t& operand);
327 void CLR1(uint8_t bit, uint8_t& operand);
328 void TSET1(uint8_t bit, uint8_t& operand);
329 void TCLR1(uint8_t bit, uint8_t& operand);
330 void AND1(uint8_t bit, uint8_t& operand);
331 void OR1(uint8_t bit, uint8_t& operand);
332 void EOR1(uint8_t bit, uint8_t& operand);
333 void NOT1(uint8_t bit, uint8_t& operand);
334 void MOV1(uint8_t bit, uint8_t& operand);
335 void CLRC();
336 void SETC();
337 void NOTC();
338 void CLRV();
339 void CLRP();
340 void SETP();
341 void EI();
342 void DI();
343 void NOP();
344 void SLEEP();
345 void STOP();
346
347 // CBNE DBNZ
348};
349
350} // namespace emu
351} // namespace yaze
352
353#endif // YAZE_APP_EMU_SPC700_H
AudioRamImpl is an implementation of the AudioRam interface.
Definition spc700.h:28
uint8_t read(uint16_t address) const override
Definition spc700.h:36
void reset() override
Definition spc700.h:34
std::vector< uint8_t > ram
Definition spc700.h:30
void write(uint16_t address, uint8_t value) override
Definition spc700.h:44
uint8_t & mutable_read(uint16_t address) override
Definition spc700.h:40
uint8_t operator[](uint16_t address) const
Definition spc700.h:49
static const int ARAM_SIZE
Definition spc700.h:29
AudioRam is an interface for the Audio RAM used by the SPC700.
Definition spc700.h:15
virtual void reset()=0
uint8_t operator[](uint16_t address)
Definition spc700.h:22
virtual void write(uint16_t address, uint8_t value)=0
virtual uint8_t & mutable_read(uint16_t address)=0
virtual uint8_t read(uint16_t address) const =0
virtual ~AudioRam()=default
The Spc700 class represents the SPC700 processor.
Definition spc700.h:69
uint16_t adr1
Definition spc700.h:81
void CMPM(uint16_t dst, uint8_t value)
void BEQ(int8_t offset)
void SUBW(uint16_t &dest, uint16_t operand)
std::vector< std::string > log_
Definition spc700.h:72
void PCALL(uint8_t offset)
void JMP(uint16_t address)
void MOVS(uint16_t adr)
uint16_t pull_word()
Definition spc700.h:205
uint8_t read(uint16_t address)
Definition spc700.h:154
uint8_t dp_plus_x()
Definition addressing.cc:87
void MOVSX(uint16_t adr)
void NOT1(uint8_t bit, uint8_t &operand)
uint16_t ind_p()
Definition addressing.cc:73
uint16_t adr
Definition spc700.h:80
void MOVX(uint16_t adr)
uint16_t dp_y()
Definition addressing.cc:25
uint32_t bstep
Definition spc700.h:79
uint8_t abs_bit(uint16_t *adr)
Definition addressing.cc:61
void AND1(uint8_t bit, uint8_t &operand)
void SBC(uint16_t adr)
void CMPY(uint16_t adr)
void ANDM(uint16_t dest, uint8_t operand)
uint8_t opcode
Definition spc700.h:77
uint16_t dat16
Definition spc700.h:83
void MOVW(uint16_t &dest, uint16_t operand)
uint8_t dat
Definition spc700.h:82
void EORM(uint16_t dest, uint8_t operand)
uint16_t dp_indirect_plus_y()
uint16_t addr_plus_i_indexed()
void DEC(uint16_t operand)
uint16_t ind_ind(uint8_t *srcVal)
Definition addressing.cc:55
uint32_t step
Definition spc700.h:78
uint8_t i_postinc()
uint16_t dp_plus_x_indirect()
void BCS(int8_t offset)
uint16_t addr_plus_i()
void DIV(uint8_t operand)
uint8_t dp_plus_y()
Definition addressing.cc:94
void MOV(uint16_t adr)
void EOR1(uint8_t bit, uint8_t &operand)
void BVS(int8_t offset)
void SBCM(uint16_t &dest, uint8_t operand)
void BVC(int8_t offset)
void Reset(bool hard=false)
Definition spc700.cc:16
void LSR(uint16_t adr)
void SET1(uint8_t bit, uint8_t &operand)
void push_byte(uint8_t value)
Definition spc700.h:190
void CMPX(uint16_t adr)
void TCLR1(uint8_t bit, uint8_t &operand)
uint8_t FlagsToByte(Flags flags)
Definition spc700.h:121
bool reset_wanted_
Definition spc700.h:75
void LogInstruction(uint16_t initial_pc, uint8_t opcode)
Definition spc700.cc:1432
const uint8_t ipl_rom_[64]
Definition spc700.h:90
uint16_t abs_y()
Definition addressing.cc:37
uint16_t dp_imm(uint8_t *srcVal)
Definition addressing.cc:50
void TCALL(uint8_t offset)
uint16_t ReadOpcodeWord()
Definition spc700.h:168
void CMP(uint16_t adr)
uint16_t dp_dp(uint8_t *src)
void ROL(uint16_t operand)
void MOV_ADDR(uint16_t address, uint8_t operand)
void write(uint16_t address, uint8_t value)
Definition spc700.h:186
uint8_t param
Definition spc700.h:84
void XCN(uint8_t operand, bool isImmediate=false)
void PUSH(uint8_t operand)
void INC(uint16_t adr)
void ADDW(uint16_t &dest, uint16_t operand)
uint16_t abs_x()
Definition addressing.cc:31
void INCW(uint16_t &operand)
void BBC(uint8_t bit, uint8_t operand)
int GetLastOpcodeCycles() const
Definition spc700.h:148
void BMI(int8_t offset)
void CALL(uint16_t address)
void BNE(int8_t offset)
uint16_t dp_word(uint16_t *low)
Definition addressing.cc:67
uint8_t get_dp_addr()
void DECW(uint16_t &operand)
void push_word(uint16_t value)
Definition spc700.h:195
void ADC(uint16_t adr)
void EOR(uint16_t adr)
void ROR(uint16_t adr)
void BBS(uint8_t bit, uint8_t operand)
uint16_t read_word(uint16_t address)
Definition spc700.h:156
void POP(uint8_t &operand)
void ASL(uint16_t operand)
void BCC(int8_t offset)
void CLR1(uint8_t bit, uint8_t &operand)
uint16_t YA
Definition spc700.h:105
void OR(uint16_t adr)
void ADCM(uint16_t &dest, uint8_t operand)
int last_opcode_cycles_
Definition spc700.h:88
void BRA(int8_t offset)
void BPL(int8_t offset)
void OR1(uint8_t bit, uint8_t &operand)
void DoBranch(uint8_t value, bool check)
Definition spc700.h:174
void CMPW(uint16_t operand)
uint16_t PC
Definition spc700.h:106
Spc700(ApuCallbacks &callbacks)
Definition spc700.h:99
void AND(uint16_t adr)
uint8_t pull_byte()
Definition spc700.h:200
void MOV1(uint8_t bit, uint8_t &operand)
void TSET1(uint8_t bit, uint8_t &operand)
ApuCallbacks callbacks_
Definition spc700.h:71
void MOVSY(uint16_t adr)
void ExecuteInstructions(uint8_t opcode)
Definition spc700.cc:160
void MOVY(uint16_t adr)
void ORM(uint16_t dest, uint8_t operand)
uint16_t ind()
Definition addressing.cc:8
uint8_t ReadOpcode()
Definition spc700.h:163
Flags ByteToFlags(uint8_t byte)
Definition spc700.h:126
void RunOpcode()
Definition spc700.cc:74
void MUL(uint8_t operand)
Main namespace for the application.
std::function< void(uint16_t, uint8_t)> write
Definition spc700.h:53
std::function< void(bool)> idle
Definition spc700.h:55
std::function< uint8_t(uint16_t)> read
Definition spc700.h:54