|
|
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.