1 /*
2 * Copyright (c) 2015, Marcos Medeiros
3 * Licensed under BSD 3-clause.
4 */
5 #include "tms34010.h"
6 #include "tms34010_memacc.h"
7 #include "tms34010_ctrl.h"
8 #include "tms34010_mov.h"
9 #include "tms34010_arithm.h"
10 #include "tms34010_jump.h"
11 #include "tms34010_shift.h"
12 #include "tms34010_gfx.h"
13 #include "stddef.h"
14 #include "tiles_generic.h"
15
16 #ifdef TMS34010_DEBUGGER
17 #include <algorithm>
18 #include <iterator>
19 #include <QDebug>
20 #endif
21
22 namespace tms {
23
24
25 #define IO(reg) cpu->io_regs[reg]
26
27 const char *io_regs_names[32] = {
28 "HESYNC", "HEBLNK", "HSBLNK", "HTOTAL", "VESYNC", "VEBLNK", "VSBLNK",
29 "VTOTAL", "DPYCTL", "DPYSTRT", "DPYINT", "CONTROL", "HSTDATA", "HSTADRL",
30 "HSTADRH", "HSTCTLL", "HSTCTLH", "INTENB", "INTPEND", "CONVSP", "CONVDP",
31 "PSIZE", "PMASK", "RS_70", "RS_80", "RS_90", "RS_A0",
32 "DPYTAP", "HCOUNT", "VCOUNT", "DPYADR", "REFCNT"
33 };
34
scan(cpu_state * cpu,sdword nAction)35 void scan(cpu_state *cpu, sdword nAction)
36 {
37 if (nAction & ACB_DRIVER_DATA) {
38 struct BurnArea ba;
39 memset(&ba, 0, sizeof(ba));
40 ba.Data = cpu;
41 ba.nLen = STRUCT_SIZE_HELPER(cpu_state, shiftreg);
42 ba.szName = "TMS34010 Regs";
43 BurnAcb(&ba);
44 }
45 }
46
reset(cpu_state * cpu)47 void reset(cpu_state *cpu)
48 {
49 cpu->pc = rdfield_32(VECT_RESET);
50 cpu->icounter = 0;
51 cpu->total_cycles = 0;
52 cpu->st = 0x00000010;
53 for (int i = 0; i < 15; i++) {
54 cpu->a[i].value = 0;
55 cpu->b[i].value = 0;
56 }
57 for (int i = 0; i < 32; i++) {
58 cpu->io_regs[i] = 0;
59 }
60
61 memset(cpu->shiftreg, 0, 4096*2);
62
63 cpu->timer_active = 0;
64 cpu->timer_cyc = 0;
65 }
66
check_irq(cpu_state * cpu)67 static void check_irq(cpu_state *cpu)
68 {
69 if (cpu->io_regs[HSTCTLH] & 0x0100) {
70 cpu->io_regs[HSTCTLH] &= ~0x0100;
71
72 if (~cpu->io_regs[HSTCTLH] & 0x0200) {
73 _push(_pc);
74 _push(_st);
75 }
76
77 _st = 0x10;
78 _pc = mem_read_d(0xfffffee0);
79 CONSUME_CYCLES(16);
80 return;
81 }
82
83 int irq = cpu->io_regs[INTPEND] & cpu->io_regs[INTENB];
84 if (!(_st & ST_IE) || !irq)
85 return;
86
87 dword trap_addr = 0;
88 if (irq & INTERRUPT_HOST) {
89 trap_addr = 0xFFFFFEC0;
90 }
91 else if (irq & INTERRUPT_DISPLAY) {
92 trap_addr = 0xFFFFFEA0;
93 }
94 else if (irq & INTERRUPT_EXTERN_1) {
95 trap_addr = 0xFFFFFFC0;
96 }
97 else if (irq & INTERRUPT_EXTERN_2) {
98 trap_addr = 0xFFFFFFA0;
99 }
100 if (trap_addr) {
101 _push(_pc);
102 _push(_st);
103 _st = 0x10;
104 _pc = mem_read_d(trap_addr) & 0xFFFFFFF0;
105 CONSUME_CYCLES(16);
106 }
107 }
108
check_timer(cpu_state * cpu,int cyc)109 void check_timer(cpu_state *cpu, int cyc)
110 {
111 if (cpu->timer_active) {
112 cpu->timer_cyc -= cyc;
113 if (cpu->timer_cyc <= 0) {
114 //bprintf(0, _T("timer hit @ %I64d\n"), TMS34010TotalCycles());
115 cpu->timer_active = 0;
116 cpu->timer_cyc = 0;
117
118 if (cpu->timer_cb)
119 cpu->timer_cb();
120 }
121 }
122 }
123
timer_set_cb(cpu_state * cpu,void (* t_cb)())124 void timer_set_cb(cpu_state *cpu, void (*t_cb)())
125 {
126 cpu->timer_cb = t_cb;
127 }
128
timer_arm(cpu_state * cpu,int cycle)129 void timer_arm(cpu_state *cpu, int cycle)
130 {
131 //bprintf(0, _T("timer arm @ %d time now %I64d\n"), cycle, TMS34010TotalCycles());
132 if (cpu->timer_active) {
133 bprintf(0, _T("TMS34010: timer_arm() arm timer when timer pending!\n"));
134 }
135 cpu->timer_active = 1;
136 cpu->timer_cyc = cycle;
137 }
138
139 #ifdef TMS34010_DEBUGGER
perform_trace(cpu_state * cpu)140 static void perform_trace(cpu_state *cpu)
141 {
142 int pc_count = std::count(std::begin(cpu->history), std::end(cpu->history), cpu->pc);
143 if (pc_count) {
144 cpu->loop_counter++;
145 return;
146 }
147
148 if (cpu->loop_counter) {
149 cpu->trace << "\n\t(Loop for " << cpu->loop_counter << " instructions)\n\n";
150 }
151 cpu->loop_counter = 0;
152
153 char pcbuf[16];
154 snprintf(pcbuf, 16, "%08X\t", _pc);
155 cpu->trace << pcbuf << new_dasm(_pc, nullptr) << std::endl;
156
157 cpu->history[cpu->history_idx] = cpu->pc;
158 cpu->history_idx = (cpu->history_idx + 1) % cpu->history.size();
159 }
160
run(cpu_state * cpu,int cycles,bool stepping)161 void run(cpu_state *cpu, int cycles, bool stepping)
162 {
163 cpu->cycles_start = cycles;
164 cpu->icounter = cycles;
165 cpu->stop = 0;
166
167 if (cpu->io_regs[HSTCTLH] & 0x8000) {
168 // halt
169 cpu->icounter = 0;
170 cpu->stop = 1;
171 }
172
173 check_timer(cpu, 0);
174
175 while (cpu->icounter > 0 && !cpu->stop) {
176
177 check_irq(cpu);
178
179 if (!stepping) {
180 if (std::find(std::begin(cpu->bpoints), std::end(cpu->bpoints), _pc) !=
181 std::end(cpu->bpoints)) {
182 cpu->reason = BREAKPOINT_FOUND;
183 return;
184 }
185 }
186
187 if (cpu->tracing && cpu->trace.is_open()) {
188 perform_trace(cpu);
189 }
190
191 cpu->pc &= 0xFFFFFFF0;
192
193 word opcode = mem_read(cpu->pc);
194 cpu->last_pc = cpu->pc;
195 cpu->pc += 16;
196 opcode_table[(opcode >> 4) & 0xFFF](cpu, opcode);
197 if (cpu->icounter == 0)
198 return;
199 }
200 cpu->reason = ICOUNTER_EXPIRED;
201
202 cycles = cycles - cpu->icounter;
203 cpu->total_cycles += cycles;
204 cpu->cycles_start = cpu->icounter = 0;
205 }
206
207 #else
run(cpu_state * cpu,int cycles)208 int run(cpu_state *cpu, int cycles)
209 {
210 cpu->cycles_start = cycles;
211 cpu->icounter = cycles;
212 cpu->stop = 0;
213 if (cpu->io_regs[HSTCTLH] & 0x8000) {
214 // halt
215 cpu->icounter = 0;
216 cpu->stop = 1;
217 }
218
219 check_timer(cpu, 0);
220
221 while (cpu->icounter > 0 && !cpu->stop) {
222
223 check_irq(cpu);
224 cpu->pc &= 0xFFFFFFF0;
225 word opcode = mem_read(cpu->pc);
226 cpu->last_pc = cpu->pc;
227 cpu->pc += 16;
228 opcode_table[(opcode >> 4) & 0xFFF](cpu, opcode);
229 }
230
231 cycles = cycles - cpu->icounter;
232 cpu->total_cycles += cycles;
233 cpu->cycles_start = cpu->icounter = 0;
234
235 return cycles;
236 }
237 #endif
238
stop(cpu_state * cpu)239 void stop(cpu_state *cpu)
240 {
241 cpu->stop = 1;
242 }
243
total_cycles(cpu_state * cpu)244 i64 total_cycles(cpu_state *cpu)
245 {
246 return cpu->total_cycles + (cpu->cycles_start - cpu->icounter);
247 }
248
new_frame(cpu_state * cpu)249 void new_frame(cpu_state *cpu)
250 {
251 cpu->total_cycles = 0;
252 }
253
get_pc(cpu_state * cpu)254 dword get_pc(cpu_state *cpu)
255 {
256 return cpu->pc;
257 }
258
get_ppc(cpu_state * cpu)259 dword get_ppc(cpu_state *cpu)
260 {
261 return cpu->last_pc;
262 }
263
generate_irq(cpu_state * cpu,int num)264 void generate_irq(cpu_state *cpu, int num)
265 {
266 cpu->io_regs[INTPEND] |= num;
267 }
268
clear_irq(cpu_state * cpu,int num)269 void clear_irq(cpu_state *cpu, int num)
270 {
271 cpu->io_regs[INTPEND] &= ~num;
272 }
273
write_ioreg(cpu_state * cpu,dword addr,word value)274 void write_ioreg(cpu_state *cpu, dword addr, word value)
275 {
276 const int reg = (addr >> 4) & 0x1F;
277 cpu->io_regs[reg] = value;
278 switch (reg) {
279 case PSIZE: cpu->pshift = log2((double)value); break;
280 case CONVDP: cpu->convdp = 1 << (~value & 0x1F); break;
281 case CONVSP: cpu->convsp = 1 << (~value & 0x1F); break;
282 case INTPEND:
283 if (!(value & INTERRUPT_DISPLAY)) {
284 //bprintf(0, _T("clear VBL irq @ %I64d\n"), TMS34010TotalCycles());
285 cpu->io_regs[INTPEND] &= ~INTERRUPT_DISPLAY;
286 }
287 break;
288 case DPYSTRT:
289 break;
290 case HSTCTLL:
291 //bprintf(0,_T("hstctll %x\n"), value);
292 break;
293 case VTOTAL:
294 case HTOTAL:
295 case HSBLNK:
296 case HEBLNK:
297 case VSBLNK:
298 case VEBLNK:
299 #ifdef TMS34010_DEBUGGER
300 qDebug() << QString().sprintf("vga crtc %dx%d - v:%d,h:%d",
301 cpu->io_regs[HSBLNK]-cpu->io_regs[HEBLNK],
302 cpu->io_regs[VSBLNK]-cpu->io_regs[VEBLNK],
303 cpu->io_regs[VTOTAL],
304 cpu->io_regs[HTOTAL]);
305 #endif
306 break;
307 }
308
309 }
310
read_ioreg(cpu_state * cpu,dword addr)311 dword read_ioreg(cpu_state *cpu, dword addr)
312 {
313 int reg = (addr >> 4) & 0x1F;
314 switch(reg) {
315 case HCOUNT: {
316 INT32 hc = TMS34010TotalCycles() % nScreenWidth;
317 INT32 ht = cpu->io_regs[HTOTAL] + 1;
318 hc = hc * ht / nScreenWidth;
319 hc += cpu->io_regs[HEBLNK];
320 return (hc > ht) ? (hc - ht) : hc;
321 }
322 case REFCNT:
323 return (TMS34010TotalCycles() / 0x10) & 0xfffc;
324 }
325
326 return cpu->io_regs[reg];
327 }
328
generate_scanline(cpu_state * cpu,int line,scanline_render_t render)329 int generate_scanline(cpu_state *cpu, int line, scanline_render_t render)
330 {
331 /* if (line==0) {
332 bprintf(0, _T("vtotal %X veblnk %X vsblnk %X. dpyint %X (enable: %X)\n"), cpu->io_regs[VTOTAL], cpu->io_regs[VEBLNK], cpu->io_regs[VSBLNK], cpu->io_regs[DPYINT], cpu->io_regs[DPYCTL] & 0x8000);
333 }
334 */
335 int enabled = cpu->io_regs[DPYCTL] & 0x8000;
336 cpu->io_regs[VCOUNT] = line;
337
338 if (enabled && line == cpu->io_regs[DPYINT]) {
339 generate_irq(cpu, INTERRUPT_DISPLAY);
340 //bprintf(0, _T("DO VBL irq @ %I64d\n"), TMS34010TotalCycles());
341 }
342
343 if (line == cpu->io_regs[VSBLNK]) {
344 cpu->io_regs[DPYADR] = cpu->io_regs[DPYSTRT];
345 }
346
347 if (line >= cpu->io_regs[VEBLNK] && line <= cpu->io_regs[VSBLNK]) {
348 word dpyadr = cpu->io_regs[DPYADR];
349 if (!(cpu->io_regs[DPYCTL] & 0x0400))
350 dpyadr ^= 0xFFFC;
351
352 int rowaddr = dpyadr >> 4;
353 int coladdr = ((dpyadr & 0x007C) << 4) | (cpu->io_regs[DPYTAP] & 0x3FFF);
354
355 display_info info;
356 info.coladdr = coladdr;
357 info.rowaddr = rowaddr;
358 info.heblnk = cpu->io_regs[HEBLNK];
359 info.hsblnk = cpu->io_regs[HSBLNK];
360 info.htotal = cpu->io_regs[HTOTAL];
361 if (render) {
362 render(line, &info);
363 }
364 }
365
366 if (line >= cpu->io_regs[VEBLNK] && line < cpu->io_regs[VSBLNK]) {
367 word dpyadr = cpu->io_regs[DPYADR];
368 if ((dpyadr & 3) == 0) {
369 dpyadr = ((dpyadr & 0xFFFC) - (cpu->io_regs[DPYCTL] & 0x03FC));
370 dpyadr |= (cpu->io_regs[DPYSTRT] & 0x0003);
371 } else {
372 dpyadr = (dpyadr & 0xfffc) | ((dpyadr - 1) & 3);
373 }
374 cpu->io_regs[DPYADR] = dpyadr;
375 }
376 if (++line >= cpu->io_regs[VTOTAL])
377 line = 0;
378 return line;
379 }
380
381 wrfield_handler wrfield_table[32] = {
382 &wrfield_32, &wrfield_1, &wrfield_2, &wrfield_3, &wrfield_4, &wrfield_5, &wrfield_6, &wrfield_7,
383 &wrfield_8, &wrfield_9, &wrfield_10, &wrfield_11, &wrfield_12, &wrfield_13, &wrfield_14, &wrfield_15,
384 &wrfield_16, &wrfield_17, &wrfield_18, &wrfield_19, &wrfield_20, &wrfield_21, &wrfield_22, &wrfield_23,
385 &wrfield_24, &wrfield_25, &wrfield_26, &wrfield_27, &wrfield_28, &wrfield_29, &wrfield_30, &wrfield_31,
386 };
387
388 rdfield_handler rdfield_table[64] = {
389 &rdfield_32, &rdfield_1, &rdfield_2, &rdfield_3, &rdfield_4, &rdfield_5, &rdfield_6, &rdfield_7,
390 &rdfield_8, &rdfield_9, &rdfield_10, &rdfield_11, &rdfield_12, &rdfield_13, &rdfield_14, &rdfield_15,
391 &rdfield_16, &rdfield_17, &rdfield_18, &rdfield_19, &rdfield_20, &rdfield_21, &rdfield_22, &rdfield_23,
392 &rdfield_24, &rdfield_25, &rdfield_26, &rdfield_27, &rdfield_28, &rdfield_29, &rdfield_30, &rdfield_31,
393 &rdfield_32, &rdfield_1_sx, &rdfield_2_sx, &rdfield_3_sx, &rdfield_4_sx, &rdfield_5_sx, &rdfield_6_sx, &rdfield_7_sx,
394 &rdfield_8_sx, &rdfield_9_sx, &rdfield_10_sx, &rdfield_11_sx, &rdfield_12_sx, &rdfield_13_sx, &rdfield_14_sx, &rdfield_15_sx,
395 &rdfield_16_sx, &rdfield_17_sx, &rdfield_18_sx, &rdfield_19_sx, &rdfield_20_sx, &rdfield_21_sx, &rdfield_22_sx, &rdfield_23_sx,
396 &rdfield_24_sx, &rdfield_25_sx, &rdfield_26_sx, &rdfield_27_sx, &rdfield_28_sx, &rdfield_29_sx, &rdfield_30_sx, &rdfield_31_sx,
397 };
398
399
400
401
402 }
403