|
|
1.1 root 1: #include "main.h"
2: #include "configuration.h"
3: #include "m68000.h"
4: #include "sysdeps.h"
5: #include "sysReg.h"
6: #include "adb.h"
7: #include "tmc.h"
8:
9: #define LOG_TMC_LEVEL LOG_DEBUG
10:
11: /* NeXT TMC emulation */
12:
13: #define TMC_ADB_ADDR_MASK 0x02208000
14:
15: #define TMC_REGS_MASK 0x0000FFFF
16:
17: /* TMC registers */
18:
19: struct {
20: Uint32 scr1;
21: Uint32 control;
22: Uint32 horizontal;
23: Uint32 vertical;
24: Uint8 video_intr;
25: Uint32 nitro;
26: } tmc;
27:
28: /* Additional System Control Register for Turbo systems:
29: * -------- -------- -------- -----xxx bits 0:2 --> cpu speed
30: * -------- -------- -------- --xx---- bits 4:5 --> main memory speed
31: * -------- -------- -------- xx------ bits 6:7 --> video memory speed
32: * -------- -------- ----xxxx -------- bits 8:11 --> cpu revision
33: * -------- -------- xxxx---- -------- bits 12:15 --> cpu type
34: * xxxx---- -------- -------- -------- bits 28:31 --> slot id
35: * ----xxxx xxxxxxxx -------- ----x--- all other bits: 1
36: *
37: * cpu speed: 7 = 33MHz?
38: * main mem speed: 0 = 60ns, 1 = 70ns, 2 = 80ns, 3 = 100ns
39: * video mem speed: 3 on all Turbo systems (100ns)?
40: * cpu revision: 0xF = rev 0
41: * 0xE = rev 1
42: * 0xD = rev 2
43: * 0xC - 0x0: rev 3 - 15
44: * cpu type: 4 = NeXTstation turbo monochrome
45: * 5 = NeXTstation turbo color
46: * 8 = NeXTcube turbo
47: */
48:
49: #define TURBOSCR_FMASK 0x0FFF0F08
50:
51: static void TurboSCR1_Reset(void) {
52: Uint8 memory_speed = 0;
53: Uint8 cpu_speed = 0x07; // 33 MHz
54:
55: if (ConfigureParams.System.nCpuFreq<20) {
56: cpu_speed = 4;
57: } else if (ConfigureParams.System.nCpuFreq<25) {
58: cpu_speed = 5;
59: } else if (ConfigureParams.System.nCpuFreq<33) {
60: cpu_speed = 6;
61: } else {
62: cpu_speed = 7;
63: }
64:
65: switch (ConfigureParams.Memory.nMemorySpeed) {
66: case MEMORY_120NS: memory_speed = 0x00; break;
67: case MEMORY_100NS: memory_speed = 0x50; break;
68: case MEMORY_80NS: memory_speed = 0xA0; break;
69: case MEMORY_60NS: memory_speed = 0xF0; break;
70: default: Log_Printf(LOG_WARN, "Turbo SCR1 error: unknown memory speed\n"); break;
71: }
72: tmc.scr1 = ((memory_speed&0xF0)|(cpu_speed&0x07));
73: if (ConfigureParams.System.nMachineType == NEXT_CUBE040)
74: tmc.scr1 |= 0x8000;
75: else if (ConfigureParams.System.bColor) {
76: tmc.scr1 |= 0x5000;
77: } else {
78: tmc.scr1 |= 0x4000;
79: }
80: tmc.scr1 |= TURBOSCR_FMASK;
81: }
82:
83:
84:
85: /* Register read/write functions */
86:
87: static void tmc_ill_write(Uint8 val) {
88: Log_Printf(LOG_WARN, "[TMC] Illegal write!\n");
89: }
90:
91: static Uint8 tmc_unimpl_read(void) {
92: Log_Printf(LOG_WARN, "[TMC] Unimplemented read!\n");
93: return 0;
94: }
95:
96: static void tmc_unimpl_write(Uint8 val) {
97: Log_Printf(LOG_WARN, "[TMC] Unimplemented write!\n");
98: }
99:
100: static Uint8 tmc_void_read(void) {
101: return 0;
102: }
103:
104: static void tmc_void_write(Uint8 val) {
105: }
106:
107: /* SCR1 */
108: static Uint8 tmc_scr1_read0(void) {
109: Log_Printf(LOG_WARN,"[TMC] SCR1 read at $0x2200000 PC=$%08x\n",m68k_getpc());
110: return (tmc.scr1>>24);
111: }
112: static Uint8 tmc_scr1_read1(void) {
113: Log_Printf(LOG_WARN,"[TMC] SCR1 read at $0x2200001 PC=$%08x\n",m68k_getpc());
114: return (tmc.scr1>>16);
115: }
116: static Uint8 tmc_scr1_read2(void) {
117: Log_Printf(LOG_WARN,"[TMC] SCR1 read at $0x2200002 PC=$%08x\n",m68k_getpc());
118: return (tmc.scr1>>8);
119: }
120: static Uint8 tmc_scr1_read3(void) {
121: Log_Printf(LOG_WARN,"[TMC] SCR1 read at $0x2200003 PC=$%08x\n",m68k_getpc());
122: return tmc.scr1;
123: }
124:
125: /* TMC Control Register */
126:
127: static Uint8 tmc_ctrl_read0(void) {
128: return (tmc.control>>24);
129: }
130: static Uint8 tmc_ctrl_read1(void) {
131: return (tmc.control>>16);
132: }
133: static Uint8 tmc_ctrl_read2(void) {
134: return (tmc.control>>8);
135: }
136: static Uint8 tmc_ctrl_read3(void) {
137: return tmc.control;
138: }
139:
140: static void tmc_ctrl_write0(Uint8 val) {
141: tmc.control &= 0x00FFFFFF;
142: tmc.control |= (val&0xFF)<<24;
143: }
144: static void tmc_ctrl_write1(Uint8 val) {
145: tmc.control &= 0xFF00FFFF;
146: tmc.control |= (val&0xFF)<<16;
147: }
148: static void tmc_ctrl_write2(Uint8 val) {
149: val &= ~0x04; /* no parity memory */
150:
151: tmc.control &= 0xFFFF00FF;
152: tmc.control |= (val&0xFF)<<8;
153: }
154: static void tmc_ctrl_write3(Uint8 val) {
155: tmc.control &= 0xFFFFFF00;
156: tmc.control |= val&0xFF;
157: }
158:
159:
160: /* Video Interrupt Register */
161: #define TMC_VI_INTERRUPT 0x01
162: #define TMC_VI_INT_MASK 0x02
163:
164: /* Horizontal and Vertical Configruation Registers */
165: #define HFPORCH 0x18
166: #define HSYNC 0x20
167: #define HBPORCH 0x48
168: #define HDISCNT 0x118
169:
170: #define VFPORCH 0x08
171: #define VSYNC 0x08
172: #define VBPORCH 0x30
173: #define VDISCNT 0x340
174:
175: static void tmc_video_reg_reset(void) {
176: tmc.video_intr = 0x00;
177: tmc.horizontal = (HFPORCH<<25)|(HSYNC<<19)|(HBPORCH<<12)|HDISCNT;
178: tmc.vertical = (VFPORCH<<25)|(VSYNC<<19)|(VBPORCH<<12)|VDISCNT;
179: }
180:
181: void tmc_video_interrupt(void) {
182: if (tmc.video_intr&TMC_VI_INT_MASK) {
183: set_interrupt(INT_DISK, SET_INT);
184: tmc.video_intr |= TMC_VI_INTERRUPT;
185: }
186: }
187:
188: static Uint8 tmc_vir_read0(void) {
189: return tmc.video_intr;
190: }
191:
192: static void tmc_vir_write0(Uint8 val) {
193: tmc.video_intr = val;
194: if (tmc.video_intr&TMC_VI_INTERRUPT) {
195: tmc.video_intr &= ~TMC_VI_INTERRUPT;
196: set_interrupt(INT_DISK, RELEASE_INT);
197: }
198: }
199:
200: static Uint8 tmc_hcr_read0(void) {
201: return (tmc.horizontal>>24);
202: }
203: static Uint8 tmc_hcr_read1(void) {
204: return (tmc.horizontal>>16);
205: }
206: static Uint8 tmc_hcr_read2(void) {
207: return (tmc.horizontal>>8);
208: }
209: static Uint8 tmc_hcr_read3(void) {
210: return tmc.horizontal;
211: }
212:
213: static void tmc_hcr_write0(Uint8 val) {
214: tmc.horizontal &= 0x00FFFFFF;
215: tmc.horizontal |= (val&0xFF)<<24;
216: }
217: static void tmc_hcr_write1(Uint8 val) {
218: tmc.horizontal &= 0xFF00FFFF;
219: tmc.horizontal |= (val&0xFF)<<16;
220: }
221: static void tmc_hcr_write2(Uint8 val) {
222: tmc.horizontal &= 0xFFFF00FF;
223: tmc.horizontal |= (val&0xFF)<<8;
224: }
225: static void tmc_hcr_write3(Uint8 val) {
226: tmc.horizontal &= 0xFFFFFF00;
227: tmc.horizontal |= val&0xFF;
228: }
229:
230: static Uint8 tmc_vcr_read0(void) {
231: return (tmc.vertical>>24);
232: }
233: static Uint8 tmc_vcr_read1(void) {
234: return (tmc.vertical>>16);
235: }
236: static Uint8 tmc_vcr_read2(void) {
237: return (tmc.vertical>>8);
238: }
239: static Uint8 tmc_vcr_read3(void) {
240: return tmc.vertical;
241: }
242:
243: static void tmc_vcr_write0(Uint8 val) {
244: tmc.vertical &= 0x00FFFFFF;
245: tmc.vertical |= (val&0xFF)<<24;
246: }
247: static void tmc_vcr_write1(Uint8 val) {
248: tmc.vertical &= 0xFF00FFFF;
249: tmc.vertical |= (val&0xFF)<<16;
250: }
251: static void tmc_vcr_write2(Uint8 val) {
252: tmc.vertical &= 0xFFFF00FF;
253: tmc.vertical |= (val&0xFF)<<8;
254: }
255: static void tmc_vcr_write3(Uint8 val) {
256: tmc.vertical &= 0xFFFFFF00;
257: tmc.vertical |= val&0xFF;
258: }
259:
260:
261: /* Read register functions */
262: static Uint8 (*tmc_read_reg[36])(void) = {
263: tmc_scr1_read0, tmc_scr1_read1, tmc_scr1_read2, tmc_scr1_read3,
264: tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read,
265: tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read,
266: tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read,
267: tmc_ctrl_read0, tmc_ctrl_read1, tmc_ctrl_read2, tmc_ctrl_read3,
268: tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read,
269: tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read,
270: tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read,
271: tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read
272: };
273:
274: static Uint8 (*tmc_read_vid_reg[16])(void) = {
275: tmc_vir_read0, tmc_void_read, tmc_void_read, tmc_void_read,
276: tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read, tmc_unimpl_read,
277: tmc_hcr_read0, tmc_hcr_read1, tmc_hcr_read2, tmc_hcr_read3,
278: tmc_vcr_read0, tmc_vcr_read1, tmc_vcr_read2, tmc_vcr_read3
279: };
280:
281: /* Write register functions */
282: static void (*tmc_write_reg[36])(Uint8) = {
283: tmc_ill_write, tmc_ill_write, tmc_ill_write, tmc_ill_write,
284: tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write,
285: tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write,
286: tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write,
287: tmc_ctrl_write0, tmc_ctrl_write1, tmc_ctrl_write2, tmc_ctrl_write3,
288: tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write,
289: tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write,
290: tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write,
291: tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write
292: };
293:
294: static void (*tmc_write_vid_reg[16])(Uint8) = {
295: tmc_vir_write0, tmc_void_write, tmc_void_write, tmc_void_write,
296: tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write, tmc_unimpl_write,
297: tmc_hcr_write0, tmc_hcr_write1, tmc_hcr_write2, tmc_hcr_write3,
298: tmc_vcr_write0, tmc_vcr_write1, tmc_vcr_write2, tmc_vcr_write3
299: };
300:
301:
302: Uint32 tmc_lget(uaecptr addr) {
303: Uint32 val = 0;
304:
305: if (addr%4) {
306: Log_Printf(LOG_WARN, "[TMC] Unaligned access.");
307: abort();
308: }
309:
310: if (addr==0x02210000) {
311: Log_Printf(LOG_WARN, "[TMC] Nitro register lget from $%08X",addr);
312: if (ConfigureParams.System.nCpuFreq==40) {
313: val = tmc.nitro;
314: } else {
315: Log_Printf(LOG_WARN, "[TMC] No nitro --> bus error!");
316: M68000_BusError(addr, 1);
317: }
318: return val;
319: }
320:
321: if ((addr&0xFFFFF00)==TMC_ADB_ADDR_MASK) {
322: return adb_lget(addr);
323: }
324:
325: Log_Printf(LOG_TMC_LEVEL, "[TMC] lget from %08X",addr);
326:
327: addr &= TMC_REGS_MASK;
328:
329: if (addr<36) {
330: val = tmc_read_reg[addr]()<<24;
331: val |= tmc_read_reg[addr+1]()<<16;
332: val |= tmc_read_reg[addr+2]()<<8;
333: val |= tmc_read_reg[addr+3]();
334: } else if (addr>=128 && addr<144) {
335: val = tmc_read_vid_reg[addr&0xF]()<<24;
336: val |= tmc_read_vid_reg[(addr+1)&0xF]()<<16;
337: val |= tmc_read_vid_reg[(addr+2)&0xF]()<<8;
338: val |= tmc_read_vid_reg[(addr+3)&0xF]();
339: }
340:
341: return val;
342: }
343:
344: Uint32 tmc_wget(uaecptr addr) {
345: Uint32 val = 0;
346:
347: if (addr%2) {
348: Log_Printf(LOG_WARN, "[TMC] Unaligned access.");
349: abort();
350: }
351:
352: if ((addr&0xFFFFF00)==TMC_ADB_ADDR_MASK) {
353: return adb_wget(addr);
354: }
355:
356: Log_Printf(LOG_TMC_LEVEL, "[TMC] wget from %08X",addr);
357:
358: addr &= TMC_REGS_MASK;
359:
360: if (addr<36) {
361: val = tmc_read_reg[addr]()<<8;
362: val |= tmc_read_reg[addr+1]();
363: } else if (addr>=128 && addr<144) {
364: val = tmc_read_vid_reg[addr&0xF]()<<8;
365: val |= tmc_read_vid_reg[(addr+1)&0xF]();
366: }
367:
368: return val;
369: }
370:
371: Uint32 tmc_bget(uaecptr addr) {
372: if ((addr&0xFFFFF00)==TMC_ADB_ADDR_MASK) {
373: return adb_bget(addr);
374: }
375:
376: Log_Printf(LOG_TMC_LEVEL, "[TMC] bget from %08X",addr);
377:
378: addr &= TMC_REGS_MASK;
379:
380: if (addr<36) {
381: return tmc_read_reg[addr]();
382: } else if (addr>=128 && addr<144) {
383: return tmc_read_vid_reg[addr&0xF]();
384: }
385:
386: return 0;
387: }
388:
389: void tmc_lput(uaecptr addr, Uint32 l) {
390: if (addr%4) {
391: Log_Printf(LOG_WARN, "[TMC] Unaligned access.");
392: abort();
393: }
394:
395: if (addr==0x02210000) {
396: Log_Printf(LOG_WARN, "[TMC] Nitro register lput %08X at $%08X",l,addr);
397: if (ConfigureParams.System.nCpuFreq==40) {
398: tmc.nitro = l&0x0000011F;
399: } else {
400: Log_Printf(LOG_WARN, "[TMC] No nitro --> bus error!");
401: M68000_BusError(addr, 0);
402: }
403: return;
404: }
405:
406: if ((addr&0xFFFFF00)==TMC_ADB_ADDR_MASK) {
407: adb_lput(addr, l);
408: return;
409: }
410:
411: Log_Printf(LOG_TMC_LEVEL, "[TMC] lput %08X to %08X",l,addr);
412:
413: addr &= TMC_REGS_MASK;
414:
415: if (addr<36) {
416: tmc_write_reg[addr](l>>24);
417: tmc_write_reg[addr+1](l>>16);
418: tmc_write_reg[addr+2](l>>8);
419: tmc_write_reg[addr+3](l);
420: } else if (addr>=128 && addr<144) {
421: tmc_write_vid_reg[addr&0xF](l>>24);
422: tmc_write_vid_reg[(addr+1)&0xF](l>>16);
423: tmc_write_vid_reg[(addr+2)&0xF](l>>8);
424: tmc_write_vid_reg[(addr+3)&0xF](l);
425: }
426: }
427:
428: void tmc_wput(uaecptr addr, Uint32 w) {
429: if (addr%2) {
430: Log_Printf(LOG_WARN, "[TMC] Unaligned access.");
431: abort();
432: }
433:
434: if ((addr&0xFFFFF00)==TMC_ADB_ADDR_MASK) {
435: adb_wput(addr, w);
436: return;
437: }
438:
439: Log_Printf(LOG_TMC_LEVEL, "[TMC] wput %04X to %08X",w,addr);
440:
441: addr &= TMC_REGS_MASK;
442:
443: if (addr<36) {
444: tmc_write_reg[addr](w>>8);
445: tmc_write_reg[addr+1](w);
446: } else if (addr>=128 && addr<144) {
447: tmc_write_vid_reg[addr&0xF](w>>8);
448: tmc_write_vid_reg[(addr+1)&0xF](w);
449: }
450: }
451:
452: void tmc_bput(uaecptr addr, Uint32 b) {
453: if ((addr&0xFFFFF00)==TMC_ADB_ADDR_MASK) {
454: adb_bput(addr, b);
455: return;
456: }
457:
458: Log_Printf(LOG_TMC_LEVEL, "[TMC] bput %02X to %08X",b,addr);
459:
460: addr &= TMC_REGS_MASK;
461:
462: if (addr<36) {
463: tmc_write_reg[addr](b);
464: } else if (addr>=128 && addr<144) {
465: tmc_write_vid_reg[addr&0xF](b);
466: }
467: }
468:
469:
470: /* TMC Reset */
471:
472: void TMC_Reset(void) {
473: TurboSCR1_Reset();
474:
475: tmc_video_reg_reset();
476: tmc.control = 0x0D17038F;
477: tmc.nitro = 0x00000000;
478: ADB_Reset();
479: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.