|
|
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:
1.1.1.2 ! root 6: Serial Communication Controller (AMD AM8530H) Emulation.
1.1 root 7:
1.1.1.2 ! root 8: Incomplete. Hacked to pass power-on test --> see SCC_Reset()
1.1 root 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:
1.1.1.2 ! root 22: #define LOG_SCC_LEVEL LOG_WARN
! 23: #define LOG_SCC_REG_LEVEL LOG_DEBUG
1.1 root 24:
25:
1.1.1.2 ! root 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;
1.1 root 134: }
1.1.1.2 ! root 135: if (val&0xF0) {
! 136: scc_write_init_command(ch, val);
1.1 root 137: }
1.1.1.2 ! root 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;
1.1 root 167: }
1.1.1.2 ! root 168:
! 169: scc_register_pointer = 0;
1.1 root 170: }
1.1.1.2 ! root 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: 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;
1.1 root 222: }
1.1.1.2 ! root 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);
1.1 root 231: }
232: }
233:
1.1.1.2 ! root 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: }
1.1 root 246:
1.1.1.2 ! root 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.