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
SCC_IsAvailable(CNF_PARAMS * cnf)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
SCC_Init(void)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
SCC_UnInit(void)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
SCC_MemorySnapShot_Capture(bool bSave)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
SCC_channelAreset(void)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
SCC_channelBreset(void)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
SCC_Reset()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
TriggerSCC(bool enable)226 static void TriggerSCC(bool enable)
227 {
228 if (enable)
229 {
230 Log_Printf(LOG_TODO, "TriggerSCC\n");
231 }
232 }
233
SCC_serial_getData(int channel)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
SCC_serial_setData(int channel,uint8_t value)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
SCC_serial_setBaudAttr(int handle,speed_t new_speed)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
SCC_serial_setBaud(int channel,int value)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
SCC_getTBE(int chn)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
SCC_serial_getStatus(int chn)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
SCC_serial_setRTS(int chn,bool value)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
SCC_serial_setDTR(int chn,bool value)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
SCC_ReadControl(int chn)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
SCC_handleRead(uint32_t addr)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
SCC_WriteControl(int chn,uint8_t value)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
SCC_handleWrite(uint32_t addr,uint8_t value)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
SCC_IRQ(void)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
SCC_doInterrupt()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
SCC_IoMem_ReadByte(void)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
SCC_IoMem_WriteByte(void)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 }
987