|
|
1.1 root 1: /* Previous - scc.c
2:
3: This file is distributed under the GNU Public License, version 2 or at
4: your option any later version. Read the file gpl.txt for details.
5:
6: Serial Communication Controller (AMD AM8530H) Emulation.
7:
8: Incomplete. Hacked to pass power-on test --> see SCC_Reset()
9:
10: */
11:
12: #include "ioMem.h"
13: #include "ioMemTables.h"
14: #include "m68000.h"
15: #include "configuration.h"
16: #include "scc.h"
17: #include "sysReg.h"
18: #include "dma.h"
19:
20: #define IO_SEG_MASK 0x1FFFF
21:
22: #define LOG_SCC_LEVEL LOG_NONE
23: #define LOG_SCC_REG_LEVEL LOG_NONE
24:
25:
26: /* Registers */
27:
28: Uint8 scc_control_read(Uint8 channel);
29: void scc_control_write(Uint8 channel, Uint8 val);
30: Uint8 scc_data_read(Uint8 channel);
31: void scc_data_write(Uint8 channel, Uint8 val);
32:
33:
34: void SCC_ControlB_Read(void) { // 0x02018000
35: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = scc_control_read(1);
36: Log_Printf(LOG_SCC_REG_LEVEL,"[SCC] Channel B control read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
37: }
38:
39: void SCC_ControlB_Write(void) {
40: scc_control_write(1, IoMem[IoAccessCurrentAddress & IO_SEG_MASK]);
41: Log_Printf(LOG_SCC_REG_LEVEL,"[SCC] Channel B control write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
42: }
43:
44: void SCC_ControlA_Read(void) { // 0x02018001
45: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = scc_control_read(0);
46: Log_Printf(LOG_SCC_REG_LEVEL,"[SCC] Channel A control read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
47: }
48:
49: void SCC_ControlA_Write(void) {
50: scc_control_write(0, IoMem[IoAccessCurrentAddress & IO_SEG_MASK]);
51: Log_Printf(LOG_SCC_REG_LEVEL,"[SCC] Channel A control write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
52: }
53:
54: void SCC_DataB_Read(void) { // 0x02018002
55: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = scc_data_read(1);
56: Log_Printf(LOG_SCC_REG_LEVEL,"[SCC] Channel B data read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
57: }
58:
59: void SCC_DataB_Write(void) {
60: scc_data_write(1, IoMem[IoAccessCurrentAddress & IO_SEG_MASK]);
61: Log_Printf(LOG_SCC_REG_LEVEL,"[SCC] Channel B data write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
62: }
63:
64: void SCC_DataA_Read(void) { // 0x02018003
65: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = scc_data_read(0);
66: Log_Printf(LOG_SCC_REG_LEVEL,"[SCC] Channel A data read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
67: }
68:
69: void SCC_DataA_Write(void) {
70: scc_data_write(0, IoMem[IoAccessCurrentAddress & IO_SEG_MASK]);
71: Log_Printf(LOG_SCC_REG_LEVEL,"[SCC] Channel A data write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc());
72: }
73:
74:
75: /* SCC Registers */
76:
77: struct {
78: Uint8 rreg[16];
79: Uint8 wreg[16];
80: } scc[2];
81:
82: Uint8 scc_register_pointer = 0;
83:
84: /* Write function prototypes */
85: void scc_write_init_command(Uint8 ch, Uint8 val);
86: void scc_write_mode(Uint8 ch, Uint8 val);
87: void scc_write_master_intr_reset(Uint8 val);
88:
89:
90: Uint8 scc_control_read(Uint8 ch) {
91: Uint8 val = 0;
92:
93: switch (scc_register_pointer) {
94: case 0:
95: case 1:
96: case 3:
97: case 10:
98: val = scc[ch].rreg[scc_register_pointer];
99: break;
100:
101: case 12:
102: case 13:
103: case 15:
104: val = scc[ch].wreg[scc_register_pointer];
105: break;
106:
107: case 2:
108: val = scc[0].wreg[2]; // FIXME: different for channel B
109: break;
110:
111: case 8:
112: val = 0; // FIXME: Data Read
113: break;
114:
115: default:
116: Log_Printf(LOG_WARN, "[SCC] Invalid register (%i) read\n",scc_register_pointer);
117: break;
118: }
119:
120: Log_Printf(LOG_SCC_LEVEL,"[SCC] Channel %c: Register %i read %02X\n",
121: ch?'B':'A',scc_register_pointer,val);
122:
123: scc_register_pointer = 0;
124:
125: return val;
126: }
127:
128: void scc_control_write(Uint8 ch, Uint8 val) {
129:
130: if (scc_register_pointer==0) {
131: scc_register_pointer = val&7;
132: if ((val&0x38)==8) {
133: scc_register_pointer |= 8;
134: }
135: if (val&0xF0) {
136: scc_write_init_command(ch, val);
137: }
138: } else {
139: Log_Printf(LOG_SCC_LEVEL,"[SCC] Channel %c: Register %i write %02X\n",
140: ch?'B':'A',scc_register_pointer,val);
141:
142: switch (scc_register_pointer) {
143: case 1:
144: scc_write_mode(ch, val);
145: break;
146: case 9:
147: scc_write_master_intr_reset(val);
148: break;
149: case 2:
150: case 3:
151: case 4:
152: case 5:
153: case 6:
154: case 7:
155: case 8:
156: case 10:
157: case 11:
158: case 12:
159: case 13:
160: case 14:
161: case 15:
162: break;
163:
164: default:
165: Log_Printf(LOG_WARN, "[SCC] Invalid register (%i) write\n",scc_register_pointer);
166: break;
167: }
168:
169: scc_register_pointer = 0;
170: }
171: }
172:
173: Uint8 scc_data_read(Uint8 ch) {
174: Uint8 val = 0;
175:
176: val = scc_buf[0];
177:
178: Log_Printf(LOG_SCC_LEVEL,"[SCC] Channel %c: Data read %02X\n",
179: ch?'B':'A',val);
180:
181: return val;
182: }
183:
184: void scc_data_write(Uint8 ch, Uint8 val) {
185:
186: scc_buf[0] = val;
187:
188: scc[ch].rreg[R_STATUS] = RR0_TXEMPTY|RR0_RXAVAIL;
189:
190: Log_Printf(LOG_SCC_LEVEL,"[SCC] Channel %c: Data write %02X\n",
191: ch?'B':'A',val);
192: }
193:
194:
195: /* Reset functions */
196: static void scc_channel_reset(Uint8 ch, bool hard) {
197:
198: Log_Printf(LOG_SCC_LEVEL, "[SCC] Reset channel %c\n", ch?'B':'A');
199:
200: scc[ch].wreg[0] = 0x00;
201: scc[ch].wreg[1] &= ~0xDB;
202: scc[ch].wreg[3] &= ~0x01;
203: scc[ch].wreg[4] |= 0x04;
204: scc[ch].wreg[5] &= ~0x9E;
205: scc[0].wreg[9] &= ~0x20;
206: scc[1].wreg[9] &= ~0x20;
207: scc[ch].wreg[10] &= ~0x9F;
208: scc[ch].wreg[14] = (scc[ch].wreg[14]&~0x3C)|0x20;
209: scc[ch].wreg[15] = 0xF8;
210:
211: scc[ch].rreg[0] = (scc[ch].rreg[0]&~0xC7)|0x44;
212: scc[ch].rreg[1] = 0x06;
213: scc[ch].rreg[3] = 0x00;
214: scc[ch].rreg[10] = 0x00;
215:
216: if (hard) {
217: scc[0].wreg[9] = (scc[0].wreg[9]&~0xFC)|0xC0;
218: scc[1].wreg[9] = (scc[1].wreg[9]&~0xFC)|0xC0;
219: scc[ch].wreg[10] = 0x00;
220: scc[ch].wreg[11] = 0x08;
221: scc[ch].wreg[14] = (scc[ch].wreg[14]&~0x3F)|0x20;
222: }
223: }
224:
225: void SCC_Reset(Uint8 ch) {
226: if(ch==0 || ch==1) { // channel reset
227: scc_channel_reset(ch, false);
228: } else { // hard reset
229: scc_channel_reset(0, true);
230: scc_channel_reset(1, true);
231: }
232: }
233:
234: /* Register write functions */
235:
236: void scc_write_init_command(Uint8 ch, Uint8 val) {
237:
238: }
239:
240: void scc_write_mode(Uint8 ch, Uint8 val) {
241: if ((val&0xC0)==0xC0) {
242: dma_scc_read_memory();
243: scc[ch].rreg[R_STATUS] |= RR0_RXAVAIL;
244: }
245: }
246:
247: void scc_write_master_intr_reset(Uint8 val) {
248: switch ((val>>6)&3) {
249: case 1:
250: SCC_Reset(1);
251: break;
252: case 2:
253: SCC_Reset(0);
254: break;
255: case 3:
256: SCC_Reset(2);
257: break;
258:
259: default:
260: break;
261: }
262: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.