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