|
|
1.1 root 1: /*
2: * dsp.c - Atari DSP56001 emulation code
3: *
4: * Copyright (c) 2001-2004 Petr Stehlik of ARAnyM dev team
5: * Adaption to Hatari (C) 2006 by Thomas Huth
6: *
7: * This program is free software; you can redistribute it and/or modify
8: * it under the terms of the GNU General Public License as published by
9: * the Free Software Foundation; either version 2 of the License, or
10: * (at your option) any later version.
11: *
12: * This program is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: * GNU General Public License for more details.
16: *
17: * You should have received a copy of the GNU General Public License
18: * along with ARAnyM; if not, write to the Free Software
19: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20: */
21:
22: #include "main.h"
23: #include "sysdeps.h"
24: #include "ioMem.h"
25: #include "dsp.h"
26: #include "dsp_cpu.h"
27:
28: #define DSP_EMULATION 1
29: #define DEBUG 1
30:
31: #if DEBUG
32: #define D(x) x
33: #else
34: #define D(x)
35: #endif
36:
37: #include <math.h>
38:
39: #include <SDL.h>
40: #include <SDL_thread.h>
41:
42: #ifndef M_PI
43: #define M_PI 3.141592653589793238462643383279502
44: #endif
45:
46:
47: /* DSP state */
48: uint8 dsp_state;
49:
50: /* Registers */
51: uint16 dsp_pc;
52: uint32 dsp_registers[64];
53:
54: /* stack[0=ssh], stack[1=ssl] */
55: uint16 dsp_stack[2][15];
56:
57: /* ram[0] is x:, ram[1] is y:, ram[2] is p: */
58: uint32 dsp_ram[3][DSP_RAMSIZE];
59:
60: /* rom[0] is x:, rom[1] is y: */
61: uint32 dsp_rom[2][512];
62:
63: /* peripheral space, [x|y]:0xffc0-0xffff */
64: uint32 dsp_periph[2][64];
65:
66: /* host port, CPU side */
67: uint8 dsp_hostport[8];
68:
69: /* Misc */
70: uint32 dsp_loop_rep; /* executing rep ? */
71: uint32 dsp_last_loop_inst; /* executing the last instruction in DO ? */
72: uint32 dsp_first_host_write; /* first byte written to host port */
73:
74: SDL_sem *dsp56k_sem;
75:
76:
77: /* For bootstrap routine */
78: static uint16 bootstrap_pos;
79: static uint32 bootstrap_accum;
80:
81: static SDL_Thread *dsp56k_thread;
82:
83:
84:
85: #if DSP_EMULATION
86:
87: /* More disasm infos, if wanted */
88: #define DSP_DISASM_HOSTREAD 0 /* Dsp->Host transfer */
89: #define DSP_DISASM_HOSTWRITE 0 /* Host->Dsp transfer */
90: #define DSP_DISASM_STATE 0 /* State changes */
91:
92: /* Execute DSP instructions till the DSP waits for a read/write */
93: #define DSP_HOST_FORCEEXEC 0
94:
95:
96: static inline Uint32 getHWoffset(void)
97: {
98: return 0xFFA200;
99: }
100:
101:
102: /* Constructor and destructor for DSP class */
103: void DSP_Init(void)
104: {
105: int i;
106:
107: memset(dsp_ram, 0,sizeof(dsp_ram));
108:
109: /* Initialize Y:rom[0x0100-0x01ff] with a sin table */
110: {
111: float src;
112: int32 dest;
113:
114: for (i=0;i<256;i++) {
115: src = (((float) i)*M_PI)/128.0;
116: dest = (int32) (sin(src) * 8388608.0); /* 1<<23 */
117: if (dest>8388607) {
118: dest = 8388607;
119: } else if (dest<-8388608) {
120: dest = -8388608;
121: }
122: dsp_rom[DSP_SPACE_Y][0x100+i]=dest & 0x00ffffff;
123: }
124: }
125:
126: /* Initialize X:rom[0x0100-0x017f] with a mu-law table */
127: {
128: const uint16 mulaw_base[8]={
129: 0x7d7c, 0x3e7c, 0x1efc, 0x0f3c, 0x075c, 0x036c, 0x0174, 0x0078
130: };
131:
132: uint32 value, offset, position;
133: int j;
134:
135: position = 0x0100;
136: offset = 0x040000;
137: for(i=0;i<8;i++) {
138: value = mulaw_base[i]<<8;
139:
140: for (j=0;j<16;j++) {
141: dsp_rom[DSP_SPACE_X][position++]=value;
142: value -= offset;
143: }
144:
145: offset >>= 1;
146: }
147: }
148:
149: /* Initialize X:rom[0x0180-0x01ff] with a a-law table */
150: {
151: const int32 multiply_base[8]={
152: 0x1580, 0x0ac0, 0x5600, 0x2b00,
153: 0x1580, 0x0058, 0x0560, 0x02b0
154: };
155: const int32 multiply_col[4]={0x10, 0x01, 0x04, 0x02};
156: const int32 multiply_line[4]={0x40, 0x04, 0x10, 0x08};
157: const int32 base_values[4]={0, -1, 2, 1};
158: uint32 pos=0x0180;
159:
160: for (i=0;i<8;i++) {
161: int32 alawbase, j;
162:
163: alawbase = multiply_base[i]<<8;
164: for (j=0;j<4;j++) {
165: int32 alawbase1, k;
166:
167: alawbase1 = alawbase + ((base_values[j]*multiply_line[i & 3])<<12);
168:
169: for (k=0;k<4;k++) {
170: int32 alawbase2;
171:
172: alawbase2 = alawbase1 + ((base_values[k]*multiply_col[i & 3])<<12);
173:
174: dsp_rom[DSP_SPACE_X][pos++]=alawbase2;
175: }
176: }
177: }
178: }
179:
180: D(bug("Dsp: power-on done"));
181:
182: dsp56k_thread = NULL;
183: dsp56k_sem = NULL;
184:
185: dsp_state = DSP_HALT;
186: #if DSP_DISASM_STATE
187: D(bug("Dsp: state = HALT"));
188: #endif
189: }
190:
191: void DSP_UnInit(void)
192: {
193: DSP_shutdown();
194: }
195:
196: /* Other functions to init/shutdown dsp emulation */
197: void DSP_Reset(void)
198: {
199: int i;
200:
201: /* Kill existing thread and semaphore */
202: DSP_shutdown();
203:
204: /* Pause thread */
205: dsp_state = DSP_BOOTING;
206: #if DSP_DISASM_STATE
207: D(bug("Dsp: state = BOOTING"));
208: #endif
209:
210: /* Memory */
211: memset(dsp_periph, 0,sizeof(dsp_periph));
212: memset(dsp_stack, 0,sizeof(dsp_stack));
213: memset(dsp_registers, 0,sizeof(dsp_registers));
214:
215: bootstrap_pos = bootstrap_accum = 0;
216:
217: /* Registers */
218: dsp_pc = 0x0000;
219: dsp_registers[DSP_REG_OMR]=0x02;
220: for (i=0;i<8;i++) {
221: dsp_registers[DSP_REG_M0+i]=0x00ffff;
222: }
223:
224: /* host port init, dsp side */
225: dsp_periph[DSP_SPACE_X][DSP_HOST_HSR]=(1<<DSP_HOST_HSR_HTDE);
226:
227: /* host port init, cpu side */
228: dsp_hostport[CPU_HOST_CVR]=0x12;
229: dsp_hostport[CPU_HOST_ISR]=(1<<CPU_HOST_ISR_TRDY)|(1<<CPU_HOST_ISR_TXDE);
230: dsp_hostport[CPU_HOST_IVR]=0x0f;
231:
232: /* Other hardware registers */
233: dsp_periph[DSP_SPACE_X][DSP_IPR]=0;
234: dsp_periph[DSP_SPACE_X][DSP_BCR]=0xffff;
235:
236: /* Misc */
237: dsp_loop_rep = 0;
238: dsp_last_loop_inst = 0;
239: dsp_first_host_write = 1;
240:
241: D(bug("Dsp: reset done"));
242:
243: /* Create thread and semaphore if needed */
244: if (dsp56k_sem == NULL) {
245: dsp56k_sem = SDL_CreateSemaphore(0);
246: }
247:
248: if (dsp56k_thread == NULL) {
249: dsp56k_thread = SDL_CreateThread(dsp56k_do_execute, NULL);
250: }
251: }
252:
253: void DSP_shutdown(void)
254: {
255: if (dsp56k_thread != NULL) {
256:
257: /* Stop thread */
258: dsp_state = DSP_STOPTHREAD;
259: #if DSP_DISASM_STATE
260: D(bug("Dsp: state = STOPTHREAD"));
261: #endif
262:
263: /* Release semaphore, if thread waiting for it */
264: if (SDL_SemValue(dsp56k_sem)==0) {
265: SDL_SemPost(dsp56k_sem);
266: }
267:
268: /* Wait for the thread to finish */
269: while (dsp_state != DSP_STOPPEDTHREAD) {
270: SDL_Delay(1);
271: }
272:
273: dsp56k_thread = NULL;
274: }
275:
276: /* Destroy the semaphore */
277: if (dsp56k_sem != NULL) {
278: SDL_DestroySemaphore(dsp56k_sem);
279: dsp56k_sem = NULL;
280: }
281: }
282:
283: /**********************************
284: * Force execution of DSP, till something
285: * to read from/write to host port
286: **********************************/
287:
288: static inline void DSP_force_exec(void)
289: {
290: #if DSP_HOST_FORCEEXEC
291: while (state == DSP_RUNNING) {
292: }
293: #endif
294: }
295:
296: #endif /* DSP_EMULATION */
297:
298: /**********************************
299: * Hardware address read/write by CPU
300: **********************************/
301:
302: static uint8 DSP_handleRead(Uint32 addr)
303: {
304: #if DSP_EMULATION
305: uint8 value=0;
306:
307: addr -= getHWoffset();
308:
309: /* D(bug("HWget_b(0x%08x)=0x%02x at 0x%08x", addr+HW_DSP, value, showPC()));*/
310:
311: /* Whenever the host want to read something on host port, we test if a
312: transfer is needed */
313: DSP_dsp2host();
314:
315: switch(addr) {
316: case CPU_HOST_ICR:
317: value = dsp_hostport[CPU_HOST_ICR];
318: break;
319: case CPU_HOST_CVR:
320: value = dsp_hostport[CPU_HOST_CVR];
321: break;
322: case CPU_HOST_ISR:
323: value = dsp_hostport[CPU_HOST_ISR];
324: break;
325: case CPU_HOST_IVR:
326: value = dsp_hostport[CPU_HOST_IVR];
327: break;
328: case CPU_HOST_RX0:
329: DSP_force_exec();
330: value = 0;
331: break;
332: case CPU_HOST_RXH:
333: DSP_force_exec();
334: value = dsp_hostport[CPU_HOST_RXH];
335: break;
336: case CPU_HOST_RXM:
337: DSP_force_exec();
338: value = dsp_hostport[CPU_HOST_RXM];
339: break;
340: case CPU_HOST_RXL:
341: DSP_force_exec();
342: value = dsp_hostport[CPU_HOST_RXL];
343:
344: if (dsp_state!=DSP_BOOTING) {
345: /* Clear RXDF bit to say that CPU has read */
346: dsp_hostport[CPU_HOST_ISR] &= 0xff-(1<<CPU_HOST_ISR_RXDF);
347: #if DSP_DISASM_HOSTWRITE
348: D(bug("Dsp: (D->H): Host RXDF cleared"));
349: #endif
350: }
351:
352: /* Wake up DSP if it was waiting our read */
353: if (dsp_state==DSP_WAITHOSTREAD) {
354: #if DSP_DISASM_STATE
355: D(bug("Dsp: state = DSP_RUNNING"));
356: #endif
357: dsp_state = DSP_RUNNING;
358:
359: if (SDL_SemValue(dsp56k_sem)==0) {
360: SDL_SemPost(dsp56k_sem);
361: }
362: }
363:
364: break;
365: }
366:
367: return value;
368: #else
369: return 0xff; // this value prevents TOS from hanging in the DSP init code */
370: #endif /* DSP_EMULATION */
371: }
372:
373: void DSP_HandleReadAccess(void)
374: {
375: Uint32 a;
376: Uint8 v;
377: for (a = IoAccessBaseAddress; a < IoAccessBaseAddress+nIoMemAccessSize; a++)
378: {
379: v = DSP_handleRead(a);
380: IoMem_WriteByte(a, v);
381: }
382: }
383:
384: static void DSP_handleWrite(Uint32 addr, uint8 value)
385: {
386: #if DSP_EMULATION
387: addr -= getHWoffset();
388:
389: /* D(bug("HWput_b(0x%08x,0x%02x) at 0x%08x", addr+HW_DSP, value, showPC()));*/
390:
391: switch(addr) {
392: case CPU_HOST_ICR:
393: dsp_hostport[CPU_HOST_ICR]=value & 0xfb;
394: /* Set HF1 and HF0 accordingly on the host side */
395: dsp_periph[DSP_SPACE_X][DSP_HOST_HSR] &=
396: 0xff-((1<<DSP_HOST_HSR_HF1)|(1<<DSP_HOST_HSR_HF0));
397: dsp_periph[DSP_SPACE_X][DSP_HOST_HSR] |=
398: dsp_hostport[CPU_HOST_ICR] & ((1<<DSP_HOST_HSR_HF1)|(1<<DSP_HOST_HSR_HF0));
399: break;
400: case CPU_HOST_CVR:
401: dsp_hostport[CPU_HOST_CVR]=value & 0x9f;
402: /* if bit 7=1, host command */
403: if (value & (1<<7)) {
404: dsp_periph[DSP_SPACE_X][DSP_HOST_HSR] |= 1<<DSP_HOST_HSR_HCP;
405: }
406: break;
407: case CPU_HOST_ISR:
408: /* Read only */
409: break;
410: case CPU_HOST_IVR:
411: dsp_hostport[CPU_HOST_IVR]=value;
412: break;
413: case CPU_HOST_TX0:
414: DSP_force_exec();
415:
416: if (dsp_first_host_write) {
417: dsp_first_host_write = 0;
418: bootstrap_accum = 0;
419: }
420: break;
421: case CPU_HOST_TXH:
422: DSP_force_exec();
423:
424: if (dsp_first_host_write) {
425: dsp_first_host_write = 0;
426: bootstrap_accum = 0;
427: }
428: dsp_hostport[CPU_HOST_TXH]=value;
429: bootstrap_accum |= value<<16;
430: break;
431: case CPU_HOST_TXM:
432: DSP_force_exec();
433:
434: if (dsp_first_host_write) {
435: dsp_first_host_write = 0;
436: dsp_hostport[CPU_HOST_TXH]=value; /* FIXME: is it correct ? */
437: bootstrap_accum = 0;
438: }
439: dsp_hostport[CPU_HOST_TXM]=value;
440: bootstrap_accum |= value<<8;
441: break;
442: case CPU_HOST_TXL:
443: DSP_force_exec();
444:
445: if (dsp_first_host_write) {
446: dsp_first_host_write = 0;
447: dsp_hostport[CPU_HOST_TXH]=value; /* FIXME: is it correct ? */
448: dsp_hostport[CPU_HOST_TXM]=value; /* FIXME: is it correct ? */
449: bootstrap_accum = 0;
450: }
451: dsp_hostport[CPU_HOST_TXL]=value;
452: bootstrap_accum |= value;
453:
454: dsp_first_host_write = 1;
455:
456: if (dsp_state != DSP_BOOTING) {
457: /* Clear TXDE to say that host has written */
458: dsp_hostport[CPU_HOST_ISR] &= 0xff-(1<<CPU_HOST_ISR_TXDE);
459: #if DSP_DISASM_HOSTREAD
460: D(bug("Dsp: (H->D): Host TXDE cleared"));
461: #endif
462:
463: DSP_host2dsp();
464: }
465:
466: switch(dsp_state) {
467: case DSP_BOOTING:
468: dsp_ram[DSP_SPACE_P][bootstrap_pos] = bootstrap_accum;
469: /* D(bug("Dsp: bootstrap: p:0x%04x: 0x%06x written", bootstrap_pos, bootstrap_accum));*/
470: bootstrap_pos++;
471: if (bootstrap_pos == 0x200) {
472: #if DSP_DISASM_STATE
473: D(bug("Dsp: bootstrap done"));
474: #endif
475: dsp_state = DSP_RUNNING;
476:
477: SDL_SemPost(dsp56k_sem);
478: }
479: bootstrap_accum = 0;
480: break;
481: case DSP_WAITHOSTWRITE:
482: /* Wake up DSP if it was waiting our write */
483: #if DSP_DISASM_STATE
484: D(bug("Dsp: state = DSP_RUNNING"));
485: #endif
486: dsp_state = DSP_RUNNING;
487:
488: if (SDL_SemValue(dsp56k_sem)==0) {
489: SDL_SemPost(dsp56k_sem);
490: }
491: break;
492: }
493:
494: break;
495: }
496: #endif /* DSP_EMULATION */
497: }
498:
499: void DSP_HandleWriteAccess(void)
500: {
501: Uint32 a;
502: Uint8 v;
503: for (a = IoAccessBaseAddress; a < IoAccessBaseAddress+nIoMemAccessSize; a++)
504: {
505: v = IoMem_ReadByte(a);
506: DSP_handleWrite(a,v);
507: }
508: }
509:
510:
511: #if DSP_EMULATION
512:
513: /**********************************
514: * Host transfer
515: **********************************/
516:
517: void DSP_host2dsp(void)
518: {
519: int trdy;
520:
521: /* Host port transfer ? (host->dsp) */
522: if (
523: ((dsp_hostport[CPU_HOST_ISR] & (1<<CPU_HOST_ISR_TXDE))==0) &&
524: ((dsp_periph[DSP_SPACE_X][DSP_HOST_HSR] & (1<<DSP_HOST_HSR_HRDF))==0)
525: ) {
526:
527: dsp_periph[DSP_SPACE_X][DSP_HOST_HRX] = dsp_hostport[CPU_HOST_TXL];
528: dsp_periph[DSP_SPACE_X][DSP_HOST_HRX] |= dsp_hostport[CPU_HOST_TXM]<<8;
529: dsp_periph[DSP_SPACE_X][DSP_HOST_HRX] |= dsp_hostport[CPU_HOST_TXH]<<16;
530:
531: #if DSP_DISASM_HOSTREAD
532: D(bug("Dsp: (H->D): Transfer 0x%06x",dsp_periph[DSP_SPACE_X][DSP_HOST_HRX]));
533: #endif
534:
535: /* Set HRDF bit to say that DSP can read */
536: dsp_periph[DSP_SPACE_X][DSP_HOST_HSR] |= 1<<DSP_HOST_HSR_HRDF;
537: #if DSP_DISASM_HOSTREAD
538: D(bug("Dsp: (H->D): Dsp HRDF set"));
539: #endif
540:
541: /* Set TXDE bit to say that host can write */
542: dsp_hostport[CPU_HOST_ISR] |= 1<<CPU_HOST_ISR_TXDE;
543: #if DSP_DISASM_HOSTREAD
544: D(bug("Dsp: (H->D): Host TXDE set"));
545: #endif
546:
547: /* Clear/set TRDY bit */
548: dsp_hostport[CPU_HOST_ISR] &= 0xff-(1<<CPU_HOST_ISR_TRDY);
549: trdy = (dsp_hostport[CPU_HOST_ISR]>>CPU_HOST_ISR_TXDE) & 1;
550: trdy &= !((dsp_periph[DSP_SPACE_X][DSP_HOST_HSR]>>DSP_HOST_HSR_HRDF) & 1);
551: dsp_hostport[CPU_HOST_ISR] |= (trdy & 1)<< CPU_HOST_ISR_TRDY;
552: }
553: }
554:
555: void DSP_dsp2host(void)
556: {
557: /* Host port transfer ? (dsp->host) */
558: if (
559: ((dsp_hostport[CPU_HOST_ISR] & (1<<CPU_HOST_ISR_RXDF))==0) &&
560: ((dsp_periph[DSP_SPACE_X][DSP_HOST_HSR] & (1<<DSP_HOST_HSR_HTDE))==0)
561: ) {
562:
563: dsp_hostport[CPU_HOST_RXL] = dsp_periph[DSP_SPACE_X][DSP_HOST_HTX];
564: dsp_hostport[CPU_HOST_RXM] = dsp_periph[DSP_SPACE_X][DSP_HOST_HTX]>>8;
565: dsp_hostport[CPU_HOST_RXH] = dsp_periph[DSP_SPACE_X][DSP_HOST_HTX]>>16;
566:
567: #if DSP_DISASM_HOSTWRITE
568: D(bug("Dsp: (D->H): Transfer 0x%06x",dsp_periph[DSP_SPACE_X][DSP_HOST_HTX]));
569: #endif
570:
571: /* Set HTDE bit to say that DSP can write */
572: dsp_periph[DSP_SPACE_X][DSP_HOST_HSR] |= 1<<DSP_HOST_HSR_HTDE;
573: #if DSP_DISASM_HOSTWRITE
574: D(bug("Dsp: (D->H): Dsp HTDE set"));
575: #endif
576:
577: /* Set RXDF bit to say that host can read */
578: dsp_hostport[CPU_HOST_ISR] |= 1<<CPU_HOST_ISR_RXDF;
579: #if DSP_DISASM_HOSTWRITE
580: D(bug("Dsp: (D->H): Host RXDF set"));
581: #endif
582: }
583: }
584:
585: #endif /* DSP_EMULATION */
586:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.