|
|
1.1 root 1: /*
2: * scc.cpp - SCC 85C30 emulation code
3: *
4: * Adaptions to Hatari:
5: *
6: * Copyright 2018 Thomas Huth
7: *
8: * Original code taken from Aranym:
9: *
10: * Copyright (c) 2001-2004 Petr Stehlik of ARAnyM dev team
11: * 2010 Jean Conter
12: *
13: * This code is free software; you can redistribute it and/or modify
14: * it under the terms of the GNU General Public License as published by
15: * the Free Software Foundation; either version 2 of the License, or
16: * (at your option) any later version.
17: *
18: * This code is distributed in the hope that it will be useful,
19: * but WITHOUT ANY WARRANTY; without even the implied warranty of
20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21: * GNU General Public License for more details.
22: *
23: * You should have received a copy of the GNU General Public License
24: * along with ARAnyM; if not, write to the Free Software
25: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26: */
27:
28: #include "main.h"
29:
30: #if HAVE_TERMIOS_H
31: # include <termios.h>
32: # include <unistd.h>
33: #endif
34: #if HAVE_SYS_IOCTL_H
35: # include <sys/ioctl.h>
36: #endif
37: #include <sys/types.h>
38: #include <sys/stat.h>
39: #include <fcntl.h>
40: #include <errno.h>
41:
42: #include "configuration.h"
43: #include "ioMem.h"
44: #include "log.h"
45: #include "memorySnapShot.h"
46: #include "scc.h"
47:
48: #if 0
49: #define bug printf
50: #define D(x) x
51: #else
52: #define bug(...)
53: #define D(x)
54: #endif
55:
56: #ifndef O_NONBLOCK
57: # ifdef O_NDELAY
58: # define O_NONBLOCK O_NDELAY
59: # else
60: # define O_NONBLOCK 0
61: # endif
62: #endif
63:
64: #define RCA 0
65: #define TBE 2
66: #define CTS 5
67:
68: struct SCC {
69: uint8_t regs[16];
70: int charcount;
71: int rd_handle, wr_handle;
72: uint16_t oldTBE;
73: uint16_t oldStatus;
74: bool bFileHandleIsATTY;
75: };
76:
77: static struct SCC scc[2];
78:
79: static int active_reg;
80: static uint8_t RR3, RR3M; // common to channel A & B
81:
82: bool SCC_IsAvailable(CNF_PARAMS *cnf)
83: {
84: return ConfigureParams.System.nMachineType == MACHINE_MEGA_STE
85: || ConfigureParams.System.nMachineType == MACHINE_TT
86: || ConfigureParams.System.nMachineType == MACHINE_FALCON;
87: }
88:
89: void SCC_Init(void)
90: {
91: SCC_Reset();
92:
93: scc[0].oldTBE = scc[1].oldTBE = 0;
94: scc[0].oldStatus = scc[1].oldStatus = 0;
95:
96: scc[0].rd_handle = scc[0].wr_handle = -1;
97: scc[1].rd_handle = scc[1].wr_handle = -1;
98:
99: D(bug("SCC: interface initialized\n"));
100:
101: if (!ConfigureParams.RS232.bEnableSccB || !SCC_IsAvailable(&ConfigureParams))
102: return;
103:
104: if (ConfigureParams.RS232.sSccBInFileName[0] &&
105: strcmp(ConfigureParams.RS232.sSccBInFileName, ConfigureParams.RS232.sSccBOutFileName) == 0)
106: {
107: #if HAVE_TERMIOS_H
108: scc[1].rd_handle = open(ConfigureParams.RS232.sSccBInFileName, O_RDWR | O_NONBLOCK);
109: if (scc[1].rd_handle >= 0)
110: {
111: if (isatty(scc[1].rd_handle))
112: {
113: scc[1].wr_handle = scc[1].rd_handle;
114: }
115: else
116: {
117: Log_Printf(LOG_ERROR, "SCC_Init: Setting SCC-B input and output "
118: "to the same file only works with tty devices.\n");
119: close(scc[1].rd_handle);
120: scc[1].rd_handle = -1;
121: }
122: }
123: else
124: {
125: Log_Printf(LOG_ERROR, "SCC_Init: Can not open device '%s'\n",
126: ConfigureParams.RS232.sSccBInFileName);
127: }
128: #else
129: Log_Printf(LOG_ERROR, "SCC_Init: Setting SCC-B input and output "
130: "to the same file is not supported on this system.\n");
131: #endif
132: }
133: else
134: {
135: if (ConfigureParams.RS232.sSccBInFileName[0])
136: {
137: scc[1].rd_handle = open(ConfigureParams.RS232.sSccBInFileName, O_RDONLY | O_NONBLOCK);
138: if (scc[1].rd_handle < 0)
139: {
140: Log_Printf(LOG_ERROR, "SCC_Init: Can not open input file '%s'\n",
141: ConfigureParams.RS232.sSccBInFileName);
142: }
143: }
144: if (ConfigureParams.RS232.sSccBOutFileName[0])
145: {
146: scc[1].wr_handle = open(ConfigureParams.RS232.sSccBOutFileName,
147: O_CREAT | O_WRONLY | O_NONBLOCK, S_IRUSR | S_IWUSR);
148: if (scc[1].wr_handle < 0)
149: {
150: Log_Printf(LOG_ERROR, "SCC_Init: Can not open output file '%s'\n",
151: ConfigureParams.RS232.sSccBOutFileName);
152: }
153: }
154: }
155: if (scc[1].rd_handle == -1 && scc[1].wr_handle == -1)
156: {
157: ConfigureParams.RS232.bEnableSccB = false;
158: }
159: }
160:
161: void SCC_UnInit(void)
162: {
163: D(bug("SCC: interface destroyed\n"));
164: if (scc[1].rd_handle >= 0)
165: {
166: if (scc[1].wr_handle == scc[1].rd_handle)
167: scc[1].wr_handle = -1;
168: close(scc[1].rd_handle);
169: scc[1].rd_handle = -1;
170: }
171: if (scc[1].wr_handle >= 0)
172: {
173: close(scc[1].wr_handle);
174: scc[1].wr_handle = -1;
175: }
176: }
177:
178: void SCC_MemorySnapShot_Capture(bool bSave)
179: {
180: MemorySnapShot_Store(&active_reg, sizeof(active_reg));
181: MemorySnapShot_Store(&RR3, sizeof(RR3));
182: MemorySnapShot_Store(&RR3M, sizeof(RR3M));
183: for (int c = 0; c < 2; c++)
184: {
185: MemorySnapShot_Store(scc[c].regs, sizeof(scc[c].regs));
186: MemorySnapShot_Store(&scc[c].charcount, sizeof(scc[c].charcount));
187: MemorySnapShot_Store(&scc[c].oldTBE, sizeof(scc[c].oldTBE));
188: MemorySnapShot_Store(&scc[c].oldStatus, sizeof(scc[c].oldStatus));
189: }
190: }
191:
192: static void SCC_channelAreset(void)
193: {
194: scc[0].regs[15] = 0xF8;
195: scc[0].regs[14] = 0xA0;
196: scc[0].regs[11] = 0x08;
197: scc[0].regs[9] = 0;
198: RR3 &= ~0x38;
199: RR3M &= ~0x38;
200: scc[0].regs[0] = 1 << TBE; // RR0A
201: }
202:
203: static void SCC_channelBreset(void)
204: {
205: scc[1].regs[15] = 0xF8;
206: scc[1].regs[14] = 0xA0;
207: scc[1].regs[11] = 0x08;
208: scc[0].regs[9] = 0; // single WR9
209: RR3 &= ~7;
210: RR3M &= ~7;
211: scc[1].regs[0] = 1 << TBE; // RR0B
212: }
213:
214: void SCC_Reset()
215: {
216: active_reg = 0;
217: memset(scc[0].regs, 0, sizeof(scc[0].regs));
218: memset(scc[1].regs, 0, sizeof(scc[1].regs));
219: SCC_channelAreset();
220: SCC_channelBreset();
221: RR3 = 0;
222: RR3M = 0;
223: scc[0].charcount = scc[1].charcount = 0;
224: }
225:
226: static void TriggerSCC(bool enable)
227: {
228: if (enable)
229: {
230: Log_Printf(LOG_TODO, "TriggerSCC\n");
231: }
232: }
233:
234: static uint8_t SCC_serial_getData(int channel)
235: {
236: uint8_t value = 0;
237: int nb;
238:
239: D(bug("SCC: getData\n"));
240: if (scc[channel].rd_handle >= 0)
241: {
242: nb = read(scc[channel].rd_handle, &value, 1);
243: if (nb < 0)
244: {
245: D(bug("SCC: impossible to get data\n"));
246: }
247: }
248: return value;
249: }
250:
251: static void SCC_serial_setData(int channel, uint8_t value)
252: {
253: int nb;
254:
255: D(bug("SCC: setData\n"));
256: if (scc[channel].wr_handle >= 0)
257: {
258: do
259: {
260: nb = write(scc[channel].wr_handle, &value, 1);
261: } while (nb < 0 && (errno == EAGAIN || errno == EINTR));
262: }
263: }
264:
265: #if HAVE_TERMIOS_H
266: static void SCC_serial_setBaudAttr(int handle, speed_t new_speed)
267: {
268: struct termios options;
269:
270: if (handle < 0)
271: return;
272:
273: tcgetattr(handle, &options);
274:
275: cfsetispeed(&options, new_speed);
276: cfsetospeed(&options, new_speed);
277:
278: options.c_cflag |= (CLOCAL | CREAD);
279: options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // raw input
280: options.c_iflag &= ~(ICRNL); // CR is not CR+LF
281:
282: tcsetattr(handle, TCSANOW, &options);
283: }
284: #endif
285:
286: static void SCC_serial_setBaud(int channel, int value)
287: {
288: #if HAVE_TERMIOS_H
289: speed_t new_speed = B0;
290:
291: D(bug("SCC: setBaud %i\n", value));
292:
293: switch (value)
294: {
295: case 230400: new_speed = B230400; break;
296: case 115200: new_speed = B115200; break;
297: case 57600: new_speed = B57600; break;
298: case 38400: new_speed = B38400; break;
299: case 19200: new_speed = B19200; break;
300: case 9600: new_speed = B9600; break;
301: case 4800: new_speed = B4800; break;
302: case 2400: new_speed = B2400; break;
303: case 1800: new_speed = B1800; break;
304: case 1200: new_speed = B1200; break;
305: case 600: new_speed = B600; break;
306: case 300: new_speed = B300; break;
307: case 200: new_speed = B200; break;
308: case 150: new_speed = B150; break;
309: case 134: new_speed = B134; break;
310: case 110: new_speed = B110; break;
311: case 75: new_speed = B75; break;
312: case 50: new_speed = B50; break;
313: default: D(bug("SCC: unsupported baud rate %i\n", value)); break;
314: }
315:
316: if (new_speed == B0)
317: return;
318:
319: SCC_serial_setBaudAttr(scc[channel].rd_handle, new_speed);
320: if (scc[channel].rd_handle != scc[channel].wr_handle)
321: SCC_serial_setBaudAttr(scc[channel].wr_handle, new_speed);
322: #endif
323: }
324:
325: static inline uint16_t SCC_getTBE(int chn)
326: {
327: uint16_t value = 0;
328:
329: #if defined(HAVE_SYS_IOCTL_H) && defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)
330: int status = 0;
331: if (ioctl(scc[chn].wr_handle, TIOCSERGETLSR, &status) < 0) // OK with ttyS0, not OK with ttyUSB0
332: {
333: // D(bug("SCC: Can't get LSR"));
334: value |= (1<<TBE); // only for serial USB
335: }
336: else if (status & TIOCSER_TEMT)
337: {
338: value = (1 << TBE); // this is a real TBE for ttyS0
339: if ((scc[chn].oldTBE & (1 << TBE)) == 0)
340: {
341: value |= 0x200;
342: } // TBE rise=>TxIP (based on real TBE)
343: }
344: #endif
345:
346: scc[chn].oldTBE = value;
347: return value;
348: }
349:
350: static uint16_t SCC_serial_getStatus(int chn)
351: {
352: uint16_t value = 0;
353: uint16_t diff;
354:
355: #if defined(HAVE_SYS_IOCTL_H) && defined(FIONREAD)
356: if (scc[chn].rd_handle >= 0)
357: {
358: int nbchar = 0;
359:
360: if (ioctl(scc[chn].rd_handle, FIONREAD, &nbchar) < 0)
361: {
362: D(bug("SCC: Can't get input fifo count\n"));
363: }
364: scc[chn].charcount = nbchar; // to optimize input (see UGLY in handleWrite)
365: if (nbchar > 0)
366: value = 0x0401; // RxIC+RBF
367: }
368: #endif
369: #if defined(HAVE_SYS_IOCTL_H) && defined(TIOCMGET)
370: if (scc[chn].wr_handle >= 0 && scc[chn].bFileHandleIsATTY)
371: {
372: int status = 0;
373:
374: value |= SCC_getTBE(chn); // TxIC
375: value |= (1 << TBE); // fake TBE to optimize output (for ttyS0)
376: if (ioctl(scc[chn].wr_handle, TIOCMGET, &status) < 0)
377: {
378: D(bug("SCC: Can't get status\n"));
379: }
380: if (status & TIOCM_CTS)
381: value |= (1 << CTS);
382: }
383: #endif
384:
385: if (scc[chn].wr_handle >= 0 && !scc[chn].bFileHandleIsATTY)
386: {
387: /* Output is a normal file, thus always set Clear-To-Send
388: * and Transmit-Buffer-Empty: */
389: value |= (1 << CTS) | (1 << TBE);
390: }
391: else if (scc[chn].wr_handle < 0)
392: {
393: /* If not connected, signal transmit-buffer-empty anyway to
394: * avoid that the program blocks while polling this bit */
395: value |= (1 << TBE);
396: }
397:
398: diff = scc[chn].oldStatus ^ value;
399: if (diff & (1 << CTS))
400: value |= 0x100; // ext status IC on CTS change
401:
402: D(bug("SCC: getStatus 0x%04x\n", value));
403:
404: scc[chn].oldStatus = value;
405: return value;
406: }
407:
408: static void SCC_serial_setRTS(int chn, bool value)
409: {
410: #if defined(HAVE_SYS_IOCTL_H) && defined(TIOCMGET)
411: int status = 0;
412:
413: if (scc[chn].wr_handle >= 0 && scc[chn].bFileHandleIsATTY)
414: {
415: if (ioctl(scc[chn].wr_handle, TIOCMGET, &status) < 0)
416: {
417: D(bug("SCC: Can't get status for RTS\n"));
418: }
419: if (value)
420: status |= TIOCM_RTS;
421: else
422: status &= ~TIOCM_RTS;
423: ioctl(scc[chn].wr_handle, TIOCMSET, &status);
424: }
425: #endif
426: }
427:
428: static void SCC_serial_setDTR(int chn, bool value)
429: {
430: #if defined(HAVE_SYS_IOCTL_H) && defined(TIOCMGET)
431: int status = 0;
432:
433: if (scc[chn].wr_handle >= 0 && scc[chn].bFileHandleIsATTY)
434: {
435: if (ioctl(scc[chn].wr_handle, TIOCMGET, &status) < 0)
436: {
437: D(bug("SCC: Can't get status for DTR\n"));
438: }
439: if (value)
440: status |= TIOCM_DTR;
441: else
442: status &= ~TIOCM_DTR;
443: ioctl(scc[chn].wr_handle, TIOCMSET, &status);
444: }
445: #endif
446: }
447:
448: static uint8_t SCC_ReadControl(int chn)
449: {
450: uint8_t value = 0;
451: uint16_t temp;
452:
453: switch (active_reg)
454: {
455: case 0: // RR0
456: temp = SCC_serial_getStatus(chn);
457: scc[chn].regs[0] = temp & 0xFF; // define CTS(5), TBE(2) and RBF=RCA(0)
458: if (chn)
459: RR3 = RR3M & (temp >> 8); // define RxIP(2), TxIP(1) and ExtIP(0)
460: else if (scc[0].regs[9] == 0x20)
461: RR3 |= 0x8;
462: value = scc[chn].regs[0];
463: break;
464: case 2: // not really useful (RR2 seems unaccessed...)
465: value = scc[0].regs[2];
466: if (chn == 0) // vector base only for RR2A
467: break;
468: if ((scc[0].regs[9] & 1) == 0) // no status bit added
469: break;
470: // status bit added to vector
471: if (scc[0].regs[9] & 0x10) // modify high bits
472: {
473: if (RR3 == 0)
474: {
475: value |= 0x60;
476: break;
477: }
478: if (RR3 & 32)
479: {
480: value |= 0x30; // A RxIP
481: break;
482: }
483: if (RR3 & 16)
484: {
485: value |= 0x10; // A TxIP
486: break;
487: }
488: if (RR3 & 8)
489: {
490: value |= 0x50; // A Ext IP
491: break;
492: }
493: if (RR3 & 4)
494: {
495: value |= 0x20; // B RBF
496: break;
497: }
498: if (RR3 & 2)
499: break; // B TBE
500: if (RR3 & 1)
501: value |= 0x40; // B Ext Status
502: }
503: else // modify low bits
504: {
505: if (RR3 == 0)
506: {
507: value |= 6; // no one
508: break;
509: }
510: if (RR3 & 32)
511: {
512: value |= 0xC; // A RxIP
513: break;
514: }
515: if (RR3 & 16)
516: {
517: value |= 0x8; // A TxIP
518: break;
519: }
520: if (RR3 & 8)
521: {
522: value |= 0xA; // A Ext IP
523: break;
524: }
525: if (RR3 & 4)
526: {
527: value |= 4; // B RBF
528: break;
529: }
530: if (RR3 & 2)
531: break; // B TBE
532: if (RR3 & 1)
533: value |= 2; // B Ext Status (CTS)
534: }
535: break;
536: case 3:
537: value = chn ? 0 : RR3; // access on A channel only
538: break;
539: case 4: // RR0
540: value = scc[chn].regs[0];
541: break;
542: case 8: // DATA reg
543: scc[chn].regs[8] = SCC_serial_getData(chn);
544: value = scc[chn].regs[8];
545: break;
546: case 9: // WR13
547: value = scc[chn].regs[13];
548: break;
549: case 11: // WR15
550: case 15: // EXT/STATUS IT Ctrl
551: value = scc[chn].regs[15] &= 0xFA; // mask out D2 and D0
552: break;
553: case 12: // BRG LSB
554: case 13: // BRG MSB
555: value = scc[chn].regs[active_reg];
556: break;
557:
558: default: // RR5,RR6,RR7,RR10,RR14 not processed
559: D(bug("scc : unprocessed read address=$%x *********\n", active_reg));
560: value = 0;
561: break;
562: }
563:
564: return value;
565: }
566:
567: static uint8_t SCC_handleRead(uint32_t addr)
568: {
569: uint8_t value = 0;
570: int channel;
571:
572: addr &= 0x6;
573: channel = (addr >= 4) ? 1 : 0; // 0 = channel A, 1 = channel B
574: switch (addr)
575: {
576: case 0: // channel A
577: case 4: // channel B
578: value = SCC_ReadControl(channel);
579: break;
580: case 2: // channel A
581: case 6: // channel B
582: scc[channel].regs[8] = SCC_serial_getData(channel);
583: value = scc[channel].regs[8];
584: break;
585: default:
586: D(bug("scc : illegal read address=$%x\n", addr));
587: break;
588: }
589:
590: active_reg = 0; // next access for RR0 or WR0
591:
592: return value;
593: }
594:
595: static void SCC_WriteControl(int chn, uint8_t value)
596: {
597: uint32_t BaudRate;
598: int i;
599:
600: if (active_reg == 0)
601: {
602:
603: if (value <= 15)
604: {
605: active_reg = value & 0x0f;
606: }
607: else
608: {
609: if ((value & 0x38) == 0x38) // Reset Highest IUS (last operation in IT service routine)
610: {
611: for (i = 0x20; i; i >>= 1)
612: {
613: if (RR3 & i)
614: break;
615: }
616: #define UGLY
617: #ifdef UGLY
618: // tricky & ugly speed improvement for input
619: if (i == 4) // RxIP
620: {
621: scc[chn].charcount--;
622: if (scc[chn].charcount <= 0)
623: RR3 &= ~4; // optimize input; don't reset RxIP when chars are buffered
624: }
625: else
626: {
627: RR3 &= ~i;
628: }
629: #else
630: RR3 &= ~i;
631: #endif
632: }
633: else if ((value & 0x38) == 0x28) // Reset Tx int pending
634: {
635: if (chn)
636: RR3 &= ~2; // channel B
637: else
638: RR3 &= ~0x10; // channel A
639: }
640: else if ((value & 0x38) == 0x10) // Reset Ext/Status ints
641: {
642: if (chn)
643: RR3 &= ~1; // channel B
644: else
645: RR3 &= ~8; // channel A
646: }
647: // Clear SCC flag if no pending IT or no properly
648: // configured WR9. Must be done here to avoid
649: // scc_do_Interrupt call without pending IT
650: TriggerSCC((RR3 & RR3M) && ((0xB & scc[0].regs[9]) == 9));
651: }
652: return;
653: }
654:
655: // active_reg > 0:
656: scc[chn].regs[active_reg] = value;
657: if (active_reg == 2)
658: {
659: scc[0].regs[active_reg] = value; // single WR2 on SCC
660: }
661: else if (active_reg == 8)
662: {
663: SCC_serial_setData(chn, value);
664: }
665: else if (active_reg == 1) // Tx/Rx interrupt enable
666: {
667: if (chn == 0)
668: {
669: // channel A
670: if (value & 1)
671: RR3M |= 8;
672: else
673: RR3 &= ~8; // no IP(RR3) if not enabled(RR3M)
674: if (value & 2)
675: RR3M |= 16;
676: else
677: RR3 &= ~16;
678: if (value & 0x18)
679: RR3M |= 32;
680: else
681: RR3 &= ~32;
682: }
683: else
684: {
685: // channel B
686: if (value & 1)
687: RR3M |= 1;
688: else
689: RR3 &= ~1;
690: if (value & 2)
691: RR3M |= 2;
692: else
693: RR3 &= ~2;
694: if (value & 0x18)
695: RR3M |= 4;
696: else
697: RR3 &= ~4;
698: // set or clear SCC flag if necessary (see later)
699: }
700: }
701: else if (active_reg == 5) // Transmit parameter and control
702: {
703: SCC_serial_setRTS(chn, value & 2);
704: SCC_serial_setDTR(chn, value & 128);
705: // Tx character format & Tx CRC would be selected also here (8 bits/char and no CRC assumed)
706: }
707: else if (active_reg == 9) // Master interrupt control (common for both channels)
708: {
709: scc[0].regs[9] = value; // single WR9 (accessible by both channels)
710: if (value & 0x40)
711: {
712: SCC_channelBreset();
713: }
714: if (value & 0x80)
715: {
716: SCC_channelAreset();
717: }
718: // set or clear SCC flag accordingly (see later)
719: }
720: else if (active_reg == 13) // set baud rate according to WR13 and WR12
721: {
722: // Normally we have to set the baud rate according
723: // to clock source (WR11) and clock mode (WR4)
724: // In fact, we choose the baud rate from the value stored in WR12 & WR13
725: // Note: we assume that WR13 is always written last (after WR12)
726: // we tried to be more or less compatible with HSMODEM (see below)
727: // 75 and 50 bauds are preserved because 153600 and 76800 were not available
728: // 3600 and 2000 were also unavailable and are remapped to 57600 and 38400 respectively
729: BaudRate = 0;
730: switch (value)
731: {
732: case 0:
733: switch (scc[chn].regs[12])
734: {
735: case 0: // HSMODEM for 200 mapped to 230400
736: BaudRate = 230400;
737: break;
738: case 2: // HSMODEM for 150 mapped to 115200
739: BaudRate = 115200;
740: break;
741: case 6: // HSMODEM for 134 mapped to 57600
742: case 0x7e: // HSMODEM for 3600 remapped to 57600
743: case 0x44: // normal for 3600 remapped to 57600
744: BaudRate = 57600;
745: break;
746: case 0xa: // HSMODEM for 110 mapped to 38400
747: case 0xe4: // HSMODEM for 2000 remapped to 38400
748: case 0x7c: // normal for 2000 remapped to 38400
749: BaudRate = 38400;
750: break;
751: case 0x16: // HSMODEM for 19200
752: case 0xb: // normal for 19200
753: BaudRate = 19200;
754: break;
755: case 0x2e: // HSMODEM for 9600
756: case 0x18: // normal for 9600
757: BaudRate = 9600;
758: break;
759: case 0x5e: // HSMODEM for 4800
760: case 0x32: // normal for 4800
761: BaudRate = 4800;
762: break;
763: case 0xbe: // HSMODEM for 2400
764: case 0x67: // normal
765: BaudRate = 2400;
766: break;
767: case 0xfe: // HSMODEM for 1800
768: case 0x8a: // normal for 1800
769: BaudRate = 1800;
770: break;
771: case 0xd0: // normal for 1200
772: BaudRate = 1200;
773: break;
774: case 1: // HSMODEM for 75 kept to 75
775: BaudRate = 75;
776: break;
777: case 4: // HSMODEM for 50 kept to 50
778: BaudRate = 50;
779: break;
780: default:
781: D(bug("SCC: unexpected LSB constant for baud rate\n"));
782: break;
783: }
784: break;
785: case 1:
786: switch (scc[chn].regs[12])
787: {
788: case 0xa1: // normal for 600
789: BaudRate = 600;
790: break;
791: case 0x7e: // HSMODEM for 1200
792: BaudRate = 1200;
793: break;
794: }
795: break;
796: case 2:
797: if (scc[chn].regs[12] == 0xfe)
798: BaudRate = 600; //HSMODEM
799: break;
800: case 3:
801: if (scc[chn].regs[12] == 0x45)
802: BaudRate = 300; //normal
803: break;
804: case 4:
805: if (scc[chn].regs[12] == 0xe8)
806: BaudRate = 200; //normal
807: break;
808: case 5:
809: if (scc[chn].regs[12] == 0xfe)
810: BaudRate = 300; //HSMODEM
811: break;
812: case 6:
813: if (scc[chn].regs[12] == 0x8c)
814: BaudRate = 150; //normal
815: break;
816: case 7:
817: if (scc[chn].regs[12] == 0x4d)
818: BaudRate = 134; //normal
819: break;
820: case 8:
821: if (scc[chn].regs[12] == 0xee)
822: BaudRate = 110; //normal
823: break;
824: case 0xd:
825: if (scc[chn].regs[12] == 0x1a)
826: BaudRate = 75; //normal
827: break;
828: case 0x13:
829: if (scc[chn].regs[12] == 0xa8)
830: BaudRate = 50; //normal
831: break;
832: case 0xff: // HSMODEM dummy value->silently ignored
833: break;
834: default:
835: D(bug("SCC: unexpected MSB constant for baud rate\n"));
836: break;
837: }
838: if (BaudRate) // set only if defined
839: SCC_serial_setBaud(chn, BaudRate);
840:
841: /* summary of baud rates:
842: Rsconf Falcon Falcon(+HSMODEM) Hatari Hatari(+HSMODEM)
843: 0 19200 19200 19200 19200
844: 1 9600 9600 9600 9600
845: 2 4800 4800 4800 4800
846: 3 3600 3600 57600 57600
847: 4 2400 2400 2400 2400
848: 5 2000 2000 38400 38400
849: 6 1800 1800 1800 1800
850: 7 1200 1200 1200 1200
851: 8 600 600 600 600
852: 9 300 300 300 300
853: 10 200 230400 200 230400
854: 11 150 115200 150 115200
855: 12 134 57600 134 57600
856: 13 110 38400 110 38400
857: 14 75 153600 75 75
858: 15 50 76800 50 50
859: */
860: }
861: else if (active_reg == 15) // external status int control
862: {
863: if (value & 1)
864: {
865: D(bug("SCC WR7 prime not yet processed\n"));
866: }
867: }
868:
869: // set or clear SCC flag accordingly. Yes it's ugly but avoids unnecessary useless calls
870: if (active_reg == 1 || active_reg == 2 || active_reg == 9)
871: TriggerSCC((RR3 & RR3M) && ((0xB & scc[0].regs[9]) == 9));
872:
873: active_reg = 0; // next access for RR0 or WR0
874: }
875:
876: static void SCC_handleWrite(uint32_t addr, uint8_t value)
877: {
878: int channel;
879:
880: addr &= 0x6;
881: channel = (addr >= 4) ? 1 : 0; // 0 = channel A, 1 = channel B
882: switch (addr)
883: {
884: case 0:
885: case 4:
886: SCC_WriteControl(channel, value);
887: break;
888: case 2: // channel A
889: case 6: // channel B
890: SCC_serial_setData(channel, value);
891: break;
892: default:
893: D(bug( "scc : illegal write address =$%x\n", addr));
894: break;
895: }
896: }
897:
898: void SCC_IRQ(void)
899: {
900: uint16_t temp;
901: temp = SCC_serial_getStatus(0);
902: if (scc[0].regs[9] == 0x20)
903: temp |= 0x800; // fake ExtStatusChange for HSMODEM install
904: scc[1].regs[0] = temp & 0xFF; // RR0B
905: RR3 = RR3M & (temp >> 8);
906: if (RR3 && (scc[0].regs[9] & 0xB) == 9)
907: TriggerSCC(true);
908: }
909:
910:
911: // return : vector number, or zero if no interrupt
912: int SCC_doInterrupt()
913: {
914: int vector;
915: uint8_t i;
916: for (i = 0x20 ; i ; i >>= 1) // highest priority first
917: {
918: if (RR3 & i & RR3M)
919: break ;
920: }
921: vector = scc[0].regs[2]; // WR2 = base of vectored interrupts for SCC
922: if ((scc[0].regs[9] & 3) == 0)
923: return vector; // no status included in vector
924: if ((scc[0].regs[9] & 0x32) != 0) // shouldn't happen with TOS, (to be completed if needed)
925: {
926: D(bug( "unexpected WR9 contents \n"));
927: // no Soft IACK, Status Low control bit expected, no NV
928: return 0;
929: }
930: switch (i)
931: {
932: case 0: /* this shouldn't happen :-) */
933: D(bug( "scc_do_interrupt called with no pending interrupt\n"));
934: vector = 0; // cancel
935: break;
936: case 1:
937: vector |= 2; // Ch B Ext/status change
938: break;
939: case 2:
940: break;// Ch B Transmit buffer Empty
941: case 4:
942: vector |= 4; // Ch B Receive Char available
943: break;
944: case 8:
945: vector |= 0xA; // Ch A Ext/status change
946: break;
947: case 16:
948: vector |= 8; // Ch A Transmit Buffer Empty
949: break;
950: case 32:
951: vector |= 0xC; // Ch A Receive Char available
952: break;
953: // special receive condition not yet processed
954: }
955: #if 0
956: D(bug( "SCC_doInterrupt : vector %d\n", vector));
957: #endif
958: return vector ;
959: }
960:
961:
962: void SCC_IoMem_ReadByte(void)
963: {
964: int i;
965:
966: for (i = 0; i < nIoMemAccessSize; i++)
967: {
968: uint32_t addr = IoAccessBaseAddress + i;
969: if (addr & 1)
970: IoMem[addr] = SCC_handleRead(addr);
971: else
972: IoMem[addr] = 0xff;
973: }
974: }
975:
976: void SCC_IoMem_WriteByte(void)
977: {
978: int i;
979:
980: for (i = 0; i < nIoMemAccessSize; i++)
981: {
982: uint32_t addr = IoAccessBaseAddress + i;
983: if (addr & 1)
984: SCC_handleWrite(addr, IoMem[addr]);
985: }
986: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.