1 /*
2 * Copyright (C) 2003-2018 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * COMMENT: Serial controller used in some DECsystem and SGI machines
29 *
30 * Hm... Same as Z8530? Most of the code in here is written for DECsystem
31 * emulation, though.
32 *
33 * NOTE:
34 * Each scc device is responsible for two lines; the first scc device
35 * controls mouse (0) and keyboard (1), and the second device controls
36 * serial ports (2 and 3).
37 *
38 * TODO:
39 * Mouse support!!! (scc0 and scc1 need to cooperate, in order to
40 * emulate the same lk201 behaviour as when using the dc device)
41 * DMA
42 * More correct interrupt support.
43 *
44 ******************************************************************************
45 * _____ ___ ____ ___ _
46 * |_ _/ _ \| _ \ / _ \| |
47 * | || | | | | | | | | | |
48 * | || |_| | |_| | |_| |_|
49 * |_| \___/|____/ \___/(_)
50 *
51 * Since this is actually a Z8530, it should be merged with dev_z8530.c!
52 */
53
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57
58 #include "console.h"
59 #include "cpu.h"
60 #include "devices.h"
61 #include "machine.h"
62 #include "memory.h"
63 #include "misc.h"
64
65 #include "thirdparty/sccreg.h"
66
67
68 #define SCC_TICK_SHIFT 14
69
70 #define N_SCC_PORTS 2
71 #define N_SCC_REGS 16
72 #define MAX_QUEUE_LEN 1024
73
74 /* #define SCC_DEBUG */
75
76
77 struct scc_data {
78 struct interrupt irq;
79
80 int use_fb;
81 int console_handle;
82
83 int scc_nr;
84 int addrmul;
85
86 int register_select_in_progress[N_SCC_PORTS];
87 int register_selected[N_SCC_PORTS];
88
89 unsigned char scc_register_r[N_SCC_PORTS * N_SCC_REGS];
90 unsigned char scc_register_w[N_SCC_PORTS * N_SCC_REGS];
91
92 unsigned char rx_queue_char[N_SCC_PORTS * MAX_QUEUE_LEN];
93 int cur_rx_queue_pos_write[N_SCC_PORTS];
94 int cur_rx_queue_pos_read[N_SCC_PORTS];
95
96 struct lk201_data lk201;
97 };
98
99
100 /*
101 * dev_scc_add_to_rx_queue():
102 *
103 * Add a character to the receive queue.
104 */
dev_scc_add_to_rx_queue(void * e,int ch,int portnr)105 void dev_scc_add_to_rx_queue(void *e, int ch, int portnr)
106 {
107 struct scc_data *d = (struct scc_data *) e;
108 int scc_nr;
109
110 /* DC's keyboard port ==> SCC keyboard port */
111 if (portnr == 0)
112 portnr = 3;
113
114 scc_nr = portnr / N_SCC_PORTS;
115 if (scc_nr != d->scc_nr)
116 return;
117
118 portnr &= (N_SCC_PORTS - 1);
119
120 d->rx_queue_char[portnr * MAX_QUEUE_LEN +
121 d->cur_rx_queue_pos_write[portnr]] = ch;
122 d->cur_rx_queue_pos_write[portnr] ++;
123 if (d->cur_rx_queue_pos_write[portnr] == MAX_QUEUE_LEN)
124 d->cur_rx_queue_pos_write[portnr] = 0;
125
126 if (d->cur_rx_queue_pos_write[portnr] ==
127 d->cur_rx_queue_pos_read[portnr])
128 fatal("warning: add_to_rx_queue(): rx_queue overrun!\n");
129 }
130
131
rx_avail(struct scc_data * d,int portnr)132 static int rx_avail(struct scc_data *d, int portnr)
133 {
134 return d->cur_rx_queue_pos_write[portnr] !=
135 d->cur_rx_queue_pos_read[portnr];
136 }
137
138
rx_nextchar(struct scc_data * d,int portnr)139 static unsigned char rx_nextchar(struct scc_data *d, int portnr)
140 {
141 unsigned char ch;
142 ch = d->rx_queue_char[portnr * MAX_QUEUE_LEN +
143 d->cur_rx_queue_pos_read[portnr]];
144 d->cur_rx_queue_pos_read[portnr]++;
145 if (d->cur_rx_queue_pos_read[portnr] == MAX_QUEUE_LEN)
146 d->cur_rx_queue_pos_read[portnr] = 0;
147 return ch;
148 }
149
150
DEVICE_TICK(scc)151 DEVICE_TICK(scc)
152 {
153 struct scc_data *d = (struct scc_data *) extra;
154 int i;
155
156 /* Add keystrokes to the rx queue: */
157 if (d->scc_nr == 1) {
158 if (d->use_fb == 0) {
159 if (console_charavail(d->console_handle))
160 dev_scc_add_to_rx_queue(extra, console_readchar(
161 d->console_handle), 2);
162 } else if (d->use_fb == 1)
163 lk201_tick(cpu->machine, &d->lk201);
164 }
165
166 for (i=0; i<N_SCC_PORTS; i++) {
167 d->scc_register_r[i * N_SCC_REGS + SCC_RR0] |= SCC_RR0_TX_EMPTY;
168 d->scc_register_r[i * N_SCC_REGS + SCC_RR1] = 0;
169 /* No receive errors */
170
171 d->scc_register_r[i * N_SCC_REGS + SCC_RR0] &=
172 ~SCC_RR0_RX_AVAIL;
173 if (rx_avail(d, i))
174 d->scc_register_r[i * N_SCC_REGS + SCC_RR0] |=
175 SCC_RR0_RX_AVAIL;
176
177 /*
178 * Interrupts:
179 * (NOTE: Interrupt enables are always at channel A)
180 */
181 if (d->scc_register_w[N_SCC_REGS + SCC_WR9] &
182 SCC_WR9_MASTER_IE) {
183 /* TX interrupts? */
184 if (d->scc_register_w[i * N_SCC_REGS + SCC_WR1] &
185 SCC_WR1_TX_IE) {
186 if (d->scc_register_r[i * N_SCC_REGS + SCC_RR3]
187 & SCC_RR3_TX_IP_A ||
188 d->scc_register_r[i * N_SCC_REGS + SCC_RR3]
189 & SCC_RR3_TX_IP_B) {
190 INTERRUPT_ASSERT(d->irq);
191 }
192 }
193
194 /* RX interrupts? */
195 if (d->scc_register_w[N_SCC_REGS + SCC_WR1] &
196 (SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_RXI_ALL_CHAR)) {
197 if (d->scc_register_r[i * N_SCC_REGS + SCC_RR0]
198 & SCC_RR0_RX_AVAIL) {
199 if (i == SCC_CHANNEL_A)
200 d->scc_register_r[N_SCC_REGS +
201 SCC_RR3] |= SCC_RR3_RX_IP_A;
202 else
203 d->scc_register_r[N_SCC_REGS +
204 SCC_RR3] |= SCC_RR3_RX_IP_B;
205 }
206
207 if (d->scc_register_r[i * N_SCC_REGS + SCC_RR3]
208 & SCC_RR3_RX_IP_A ||
209 d->scc_register_r[i * N_SCC_REGS + SCC_RR3]
210 & SCC_RR3_RX_IP_B) {
211 INTERRUPT_ASSERT(d->irq);
212 }
213 }
214
215 if (d->scc_register_w[N_SCC_REGS + SCC_WR1] &
216 SCC_WR1_DMA_MODE) {
217 if (d->scc_register_r[i * N_SCC_REGS + SCC_RR0]
218 & SCC_RR0_RX_AVAIL) {
219 if (i == SCC_CHANNEL_A)
220 d->scc_register_r[N_SCC_REGS +
221 SCC_RR3] |=
222 SCC_RR3_EXT_IP_A;
223 else
224 d->scc_register_r[N_SCC_REGS +
225 SCC_RR3] |=
226 SCC_RR3_EXT_IP_B;
227 }
228
229 if (d->scc_register_r[i * N_SCC_REGS + SCC_RR3]
230 & SCC_RR3_EXT_IP_A ||
231 d->scc_register_r[i * N_SCC_REGS + SCC_RR3]
232 & SCC_RR3_EXT_IP_B) {
233 INTERRUPT_ASSERT(d->irq);
234 }
235 }
236 }
237 }
238 }
239
240
241 /*
242 * dev_scc_dma_func():
243 */
dev_scc_dma_func(struct cpu * cpu,void * extra,uint64_t addr,size_t dma_len,int tx)244 int dev_scc_dma_func(struct cpu *cpu, void *extra, uint64_t addr,
245 size_t dma_len, int tx)
246 {
247 /* printf("dev_scc_dma_func(): addr = %08x, len = %i\n",
248 (int)addr, (int)dma_len); */
249 unsigned char word[4];
250 struct scc_data *d = (struct scc_data *) extra;
251 int n;
252
253 int port = SCC_CHANNEL_A; /* TODO */
254
255 if (tx) {
256 do {
257 cpu->memory_rw(cpu, cpu->mem, addr, &word[0],
258 sizeof(word), MEM_READ, NO_EXCEPTIONS | PHYSICAL);
259
260 lk201_tx_data(&d->lk201, d->scc_nr * 2 + port, word[1]);
261 /* Loopback: */
262 if (d->scc_register_w[port * N_SCC_REGS + SCC_WR14]
263 & SCC_WR14_LOCAL_LOOPB)
264 dev_scc_add_to_rx_queue(d, word[1],
265 d->scc_nr * 2 + port);
266
267 addr += sizeof(word);
268 } while ((addr & 0xffc) != 0);
269
270 dev_scc_tick(cpu, extra);
271 return 1;
272 } else {
273 printf("dev_scc_dma_func(): addr = %08x, len = %i\n",
274 (int)addr, (int)dma_len);
275
276
277 /* TODO: all this is just nonsense */
278
279 n = 0;
280 while (rx_avail(d, port)) {
281 word[0] = word[1] = word[2] = word[3] = 0;
282 word[0] = word[1] = word[2] = word[3] =
283 rx_nextchar(d, port);
284 n++;
285 cpu->memory_rw(cpu, cpu->mem, addr, &word[0],
286 sizeof(word), MEM_WRITE, NO_EXCEPTIONS | PHYSICAL);
287
288 addr += sizeof(word);
289 /* Half-page? */
290 if ((addr & 0x7fc) == 0)
291 break;
292 }
293 dev_scc_tick(cpu, extra);
294 return n*4;
295 }
296 }
297
298
DEVICE_ACCESS(scc)299 DEVICE_ACCESS(scc)
300 {
301 struct scc_data *d = (struct scc_data *) extra;
302 uint64_t idata = 0, odata = 0;
303 int port;
304 int ultrix_mode = 0;
305
306 if (writeflag == MEM_WRITE)
307 idata = memory_readmax64(cpu, data, len);
308
309 /* relative_addr /= d->addrmul; */
310 /* See SGI comment below instead. */
311 /*
312 * SGI writes command to 0x0f, and data to 0x1f.
313 * (TODO: This works for port nr 0, how about port nr 1?)
314 */
315 if ((relative_addr & 0x0f) == 0xf) {
316 if (relative_addr == 0x0f)
317 relative_addr = 1;
318 else
319 relative_addr = 5;
320 }
321
322 port = relative_addr / 8;
323 relative_addr &= 7;
324
325 dev_scc_tick(cpu, extra);
326
327 /*
328 * Ultrix writes words such as 0x1200 to relative address 0,
329 * instead of writing the byte 0x12 directly to address 1.
330 */
331 if ((relative_addr == 0 || relative_addr == 4) && (idata & 0xff) == 0) {
332 ultrix_mode = 1;
333 relative_addr ++;
334 idata >>= 8;
335 }
336
337 switch (relative_addr) {
338 case 1: /* command */
339 if (writeflag==MEM_READ) {
340 odata = d->scc_register_r[port * N_SCC_REGS +
341 d->register_selected[port]];
342
343 if (d->register_selected[port] == SCC_RR3) {
344 if (port == SCC_CHANNEL_B)
345 fatal("WARNING! scc channel B has "
346 "no RR3\n");
347
348 d->scc_register_r[port * N_SCC_REGS +
349 SCC_RR3] = 0;
350
351 INTERRUPT_DEASSERT(d->irq);
352 }
353
354 #ifdef SCC_DEBUG
355 fatal("[ scc: port %i, register %i, read value "
356 "0x%02x ]\n", port, d->register_selected[port],
357 (int)odata);
358 #endif
359 d->register_select_in_progress[port] = 0;
360 d->register_selected[port] = 0;
361 /* debug("[ scc: (port %i) read from 0x%08lx ]\n",
362 port, (long)relative_addr); */
363 } else {
364 /* If no register is selected, then select one.
365 Otherwise, write to the selected register. */
366 if (d->register_select_in_progress[port] == 0) {
367 d->register_select_in_progress[port] = 1;
368 d->register_selected[port] = idata;
369 d->register_selected[port] &= (N_SCC_REGS-1);
370 } else {
371 d->scc_register_w[port * N_SCC_REGS +
372 d->register_selected[port]] = idata;
373 #ifdef SCC_DEBUG
374 fatal("[ scc: port %i, register %i, write "
375 "value 0x%02x ]\n", port,
376 d->register_selected[port], idata);
377 #endif
378
379 d->scc_register_r[port * N_SCC_REGS +
380 SCC_RR12] = d->scc_register_w[port *
381 N_SCC_REGS + SCC_WR12];
382 d->scc_register_r[port * N_SCC_REGS +
383 SCC_RR13] = d->scc_register_w[port *
384 N_SCC_REGS + SCC_WR13];
385
386 d->register_select_in_progress[port] = 0;
387 d->register_selected[port] = 0;
388 }
389 }
390 break;
391 case 5: /* data */
392 if (writeflag==MEM_READ) {
393 if (rx_avail(d, port))
394 odata = rx_nextchar(d, port);
395
396 /* TODO: perhaps only clear the RX part of RR3? */
397 d->scc_register_r[N_SCC_REGS + SCC_RR3] = 0;
398
399 INTERRUPT_DEASSERT(d->irq);
400
401 // debug("[ scc: (port %i) read from 0x%08lx: 0x%02x ]\n",
402 // port, (long)relative_addr, (int)odata);
403 } else {
404 /* debug("[ scc: (port %i) write to 0x%08lx: "
405 "0x%08x ]\n", port, (long)relative_addr,
406 (int)idata); */
407
408 /* Send the character: */
409 lk201_tx_data(&d->lk201, d->scc_nr * 2 + port, idata);
410
411 /* Loopback: */
412 if (d->scc_register_w[port * N_SCC_REGS + SCC_WR14]
413 & SCC_WR14_LOCAL_LOOPB)
414 dev_scc_add_to_rx_queue(d, idata, d->scc_nr
415 * 2 + port);
416
417 /* TX interrupt: */
418 if (d->scc_register_w[port * N_SCC_REGS + SCC_WR9] &
419 SCC_WR9_MASTER_IE &&
420 d->scc_register_w[port * N_SCC_REGS + SCC_WR1] &
421 SCC_WR1_TX_IE) {
422 if (port == SCC_CHANNEL_A)
423 d->scc_register_r[N_SCC_REGS + SCC_RR3]
424 |= SCC_RR3_TX_IP_A;
425 else
426 d->scc_register_r[N_SCC_REGS + SCC_RR3]
427 |= SCC_RR3_TX_IP_B;
428 }
429
430 dev_scc_tick(cpu, extra);
431 }
432 break;
433 default:
434 if (writeflag==MEM_READ) {
435 debug("[ scc: (port %i) read from 0x%08lx ]\n",
436 port, (long)relative_addr);
437 } else {
438 debug("[ scc: (port %i) write to 0x%08lx: 0x%08x ]\n",
439 port, (long)relative_addr, (int)idata);
440 }
441 }
442
443 if (ultrix_mode && writeflag == MEM_READ) {
444 odata <<= 8;
445 }
446
447 if (writeflag == MEM_READ)
448 memory_writemax64(cpu, data, len, odata);
449
450 return 1;
451 }
452
453
454 /*
455 * dev_scc_init():
456 *
457 * use_fb = non-zero when using graphical console + keyboard
458 * scc_nr = 0 or 1
459 * addmul = 1 in most cases, 8 on SGI?
460 */
dev_scc_init(struct machine * machine,struct memory * mem,uint64_t baseaddr,char * irq_path,int use_fb,int scc_nr,int addrmul)461 void *dev_scc_init(struct machine *machine, struct memory *mem,
462 uint64_t baseaddr, char* irq_path, int use_fb, int scc_nr, int addrmul)
463 {
464 struct scc_data *d;
465
466 CHECK_ALLOCATION(d = (struct scc_data *) malloc(sizeof(struct scc_data)));
467 memset(d, 0, sizeof(struct scc_data));
468
469 INTERRUPT_CONNECT(irq_path, d->irq);
470 d->scc_nr = scc_nr;
471 d->use_fb = use_fb;
472 d->addrmul = addrmul;
473 d->console_handle = console_start_slave(machine, "SCC", 1);
474
475 d->scc_register_r[SCC_RR0] |= SCC_RR0_TX_UNDERRUN;
476
477 lk201_init(&d->lk201, use_fb, dev_scc_add_to_rx_queue,
478 d->console_handle, d);
479
480 memory_device_register(mem, "scc", baseaddr, DEV_SCC_LENGTH,
481 dev_scc_access, d, DM_DEFAULT, NULL);
482 machine_add_tickfunction(machine, dev_scc_tick, d, SCC_TICK_SHIFT);
483
484 return (void *) d;
485 }
486
487