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