|
|
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 (Zilog 8530) Emulation.
7:
8: Based on MESS source code.
9:
10: Port to Previous incomplete. Hacked to pass power-on test --> see SCC_Reset()
11:
12: */
13:
14: #include "ioMem.h"
15: #include "ioMemTables.h"
16: #include "m68000.h"
17: #include "configuration.h"
18: #include "scc.h"
19: #include "sysReg.h"
20: #include "dma.h"
21:
22: #define LOG_SCC_LEVEL LOG_WARN
23: #define IO_SEG_MASK 0x1FFFF
24:
25: #define SCC_BUFSIZE 10 // what is actual buffer size of our controller?
26:
27:
28: /* Variables */
29: bool MasterIRQEnable;
30: int lastIRQStat;
31: typedef enum {
32: IRQ_NONE,
33: IRQ_B_TX,
34: IRQ_A_TX,
35: IRQ_B_EXT,
36: IRQ_A_EXT
37: } IRQ_TYPES;
38:
39: IRQ_TYPES IRQType;
40:
41: typedef struct {
42: Uint8 rreg[16];
43: Uint8 wreg[16];
44: bool txIRQEnable;
45: bool txIRQPending;
46: bool extIRQEnable;
47: bool extIRQPending;
48: bool rxIRQEnable;
49: bool rxIRQPending;
50: bool rxEnable;
51: bool txEnable;
52: bool syncHunt;
53: bool txUnderrun;
54:
55: Uint8 rx_buf[SCC_BUFSIZE];
56: Uint8 tx_buf[SCC_BUFSIZE];
57: Uint32 rx_buf_size;
58: Uint32 tx_buf_size;
59: } SCC_CHANNEL;
60:
61: SCC_CHANNEL channel[2];
62:
63: int IRQV;
64:
65: bool write_reg_pointer; // true --> byte written is number of register, false --> byte gets written to register
66: Uint8 regnumber;
67:
68:
69: void SCC_Read(void) {
70: bool data;
71: Uint8 ch;
72: Uint8 reg;
73:
74: if (IoAccessCurrentAddress&0x1)
75: ch = 1; // Channel A
76: else
77: ch = 0; // Channel B
78:
79: if (IoAccessCurrentAddress&0x2)
80: data = true;
81: else
82: data = false;
83:
84: if (data) {
85: IoMem[IoAccessCurrentAddress&IO_SEG_MASK] = channel[ch].rx_buf[0];
86: Log_Printf(LOG_SCC_LEVEL, "SCC %c, Data read: %02x\n", ch == 1?'A':'B', channel[ch].rx_buf[0]);
87: } else {
88: reg = regnumber;
89: IoMem[IoAccessCurrentAddress&IO_SEG_MASK] = channel[ch].rreg[reg];
90: Log_Printf(LOG_SCC_LEVEL, "SCC %c, Reg%i read: %02x\n", ch == 1?'A':'B', reg, channel[ch].rreg[reg]);
91: }
92: write_reg_pointer = true;
93: }
94:
95:
96: void SCC_Write(void) {
97: bool data;
98: Uint8 ch;
99: Uint8 reg;
100: Uint8 val;
101:
102: if (IoAccessCurrentAddress&0x1)
103: ch = 1;
104: else
105: ch = 0;
106:
107: if (IoAccessCurrentAddress&0x2)
108: data = true;
109: else
110: data = false;
111:
112: if (data) {
113: channel[ch].rx_buf[0] = IoMem[IoAccessCurrentAddress&IO_SEG_MASK];
114: Log_Printf(LOG_SCC_LEVEL, "SCC %c, Data write: %02x\n", ch == 1?'A':'B', channel[ch].rx_buf[0]);
115: channel[ch].rreg[R_STATUS] = RR0_TXEMPTY|RR0_RXAVAIL; // Tx buffer empty | Rx Character Available
116: return;
117: }
118:
119: if (write_reg_pointer == true) {
120: regnumber = IoMem[IoAccessCurrentAddress&IO_SEG_MASK];
121: write_reg_pointer = false;
122: return;
123: } else if (write_reg_pointer == false) {
124: reg = regnumber;
125: val = channel[ch].wreg[reg] = IoMem[IoAccessCurrentAddress&IO_SEG_MASK];
126: Log_Printf(LOG_SCC_LEVEL, "SCC %c, Reg%i write: %02x\n", ch == 1?'A':'B', reg, channel[ch].wreg[reg]);
127:
128: switch (reg) {
129: case W_INIT:
130: switch ((val>>3) & 7) {
131: case 2: SCC_Interrupt(); break; // Reset Ext/Status Interrupts
132: case 5: channel[0].txIRQPending = false; break; // Reset pending Tx Interrupt
133: case 0: // Nothing
134: case 3: // Send SDLC abort
135: case 4: // Enable interrupt on next char Rx
136: case 6: // Error reset
137: case 7: // Reset Interrupt Under Service
138: break; // Not handled
139: default: break;
140: }
141: break;
142:
143: case W_MODE: // Tx/Rx IRQ and data transfer mode definition
144: channel[ch].extIRQEnable = (val&1)?true:false; // External Interrupt Enable
145: channel[ch].txIRQEnable = (val&2)?true:false; // Transmit Interrupt Enable
146: channel[ch].rxIRQEnable = ((val&0x18)==0x18)?true:false; // Interrupt on Special only
147: SCC_Interrupt();
148:
149: if (val&0x40 && val&0x80) {
150: dma_memory_read(channel[ch].rx_buf, &channel[ch].rx_buf_size, CHANNEL_SCC);
151: channel[ch].rreg[R_STATUS] = RR0_RXAVAIL; // Rx Character Available
152: }
153: break;
154:
155: case W_INTVEC: // Interrupt vector
156: IRQV = channel[ch].rreg[R_INTVEC] = val;
157: break;
158:
159: case W_RECCONT: // Rx parameters and controls
160: channel[ch].rxEnable = channel[ch].wreg[reg]&1; // Rx Enable
161: channel[ch].syncHunt = (channel[ch].wreg[reg]&0x10)?true:false; // Enter Hunt Mode
162: break;
163:
164: case W_TRANSCONT: // Tx parameters and controls
165: channel[ch].rxEnable = channel[ch].wreg[reg]&8;
166: if (channel[ch].txEnable)
167: channel[ch].rreg[R_STATUS] |= RR0_TXEMPTY; // Tx Empty
168:
169: case W_MISCMODE: // Tx/Rx miscellaneous parameters and modes
170: case W_SYNCCHARA: // sync chars/SDLC address field
171: case W_SYNCCHARF: // sync char/SDLC flag
172: break;
173:
174: case W_TRANSBUF:
175: channel[ch].tx_buf[0] = val;
176: break;
177:
178: case W_MASTERINT: // Master Interrupt Control
179: MasterIRQEnable = (val&8)?true:false;
180: SCC_Interrupt();
181:
182: /* Reset channels */
183: switch ((val>>6)&3) {
184: case 1: SCC_ResetChannel(0); break; // Reset Channel B
185: case 2: SCC_ResetChannel(1); break; // Reset Channel A
186: case 3: // Hardware Reset
187: SCC_Reset();
188: SCC_Interrupt();
189: break;
190: default: break;
191: }
192: break;
193:
194: case W_MISCCONT: // Miscellaneous transmitter/receiver control bits
195: case W_CLOCK: // Clock mode control
196: case W_BRG_LOW: // Lower byte of baud rate generator
197: case W_BRG_HIGH: // Upper byte of baud rate generator
198: break;
199:
200: case W_MISC: // Miscellaneous control bits
201: if (val&0x01) // Baud rate generator enable?
202: {} // later
203: break;
204:
205: case W_EXTSTAT: // later ...
206: break;
207: }
208: }
209: write_reg_pointer = true;
210: }
211:
212:
213:
214: /* Functions */
215:
216: void SCC_Interrupt(void)
217: {
218: int irqstat;
219:
220: irqstat = 0;
221: if (MasterIRQEnable)
222: {
223: if ((channel[0].txIRQEnable) && (channel[0].txIRQPending))
224: {
225: IRQType = IRQ_B_TX;
226: irqstat = 1;
227: }
228: else if ((channel[1].txIRQEnable) && (channel[1].txIRQPending))
229: {
230: IRQType = IRQ_A_TX;
231: irqstat = 1;
232: }
233: else if ((channel[0].extIRQEnable) && (channel[0].extIRQPending))
234: {
235: IRQType = IRQ_B_EXT;
236: irqstat = 1;
237: }
238: else if ((channel[1].extIRQEnable) && (channel[1].extIRQPending))
239: {
240: IRQType = IRQ_A_EXT;
241: irqstat = 1;
242: }
243: }
244: else
245: {
246: IRQType = IRQ_NONE;
247: }
248:
249: // printf("SCC: irqstat %d, last %d\n", irqstat, lastIRQStat);
250: // printf("ch0: en %d pd %d ch1: en %d pd %d\n", channel[0].txIRQEnable, channel[0].txIRQPending, channel[1].txIRQEnable, channel[1].txIRQPending);
251:
252: // don't spam the driver with unnecessary transitions
253: if (irqstat != lastIRQStat)
254: {
255: lastIRQStat = irqstat;
256:
257: // tell the driver the new IRQ line status if possible
258: Log_Printf(LOG_SCC_LEVEL, "SCC8530 IRQ status => %d\n", irqstat);
259:
260: if (irqstat) {
261: set_interrupt(INT_SCC, SET_INT);
262: Log_Printf(LOG_SCC_LEVEL, "SCC: Raise IRQ");
263: }else{
264: set_interrupt(INT_SCC, RELEASE_INT);
265: Log_Printf(LOG_SCC_LEVEL, "SCC: Lower IRQ");
266: }
267:
268: // if(!intrq_cb.isnull())
269: // intrq_cb(irqstat);
270: }
271: }
272:
273:
274: void SCC_ResetChannel(int ch)
275: {
276: // emu_timer *timersave = channel[ch].baudtimer;
277:
278: memset(&channel[ch], 0, sizeof(SCC_CHANNEL));
279:
280: channel[ch].txUnderrun = 1;
281: // channel[ch].baudtimer = timersave;
282:
283: // channel[ch].baudtimer->adjust(attotime::never, ch);
284: }
285:
286: void SCC_InitChannel(int ch)
287: {
288: channel[ch].syncHunt = 1;
289: }
290:
291: void SCC_Reset(void) {
292: Log_Printf(LOG_WARN, "SCC: Device Reset (Hacked!)");
293: IRQType = IRQ_NONE;
294: MasterIRQEnable = false;
295: IRQV = 0;
296:
297: SCC_InitChannel(0);
298: SCC_InitChannel(1);
299: SCC_ResetChannel(0);
300: SCC_ResetChannel(1);
301:
302: write_reg_pointer = true;
303: regnumber = 0;
304:
305: /*--- Hack to pass power-on test ---*/
306: channel[0].rreg[R_STATUS] = 0xFF;
307: channel[1].rreg[R_STATUS] = 0xFF;
308: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.