1 |
/* |
/* |
2 |
* Copyright (C) 2003-2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2003-2007 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: dev_scc.c,v 1.27 2005/02/25 06:14:30 debug Exp $ |
* $Id: dev_scc.c,v 1.40 2007/06/15 19:57:34 debug Exp $ |
29 |
* |
* |
30 |
* Serial controller on some DECsystems and SGI machines. (Z8530 ?) |
* COMMENT: Serial controller used in some DECsystem and SGI machines |
31 |
* Most of the code in here is written for DECsystem emulation, though. |
* |
32 |
|
* Hm... Same as Z8530? Most of the code in here is written for DECsystem |
33 |
|
* emulation, though. |
34 |
* |
* |
35 |
* NOTE: |
* NOTE: |
36 |
* Each scc device is responsible for two lines; the first scc device |
* Each scc device is responsible for two lines; the first scc device |
42 |
* emulate the same lk201 behaviour as when using the dc device) |
* emulate the same lk201 behaviour as when using the dc device) |
43 |
* DMA |
* DMA |
44 |
* More correct interrupt support. |
* More correct interrupt support. |
45 |
|
* |
46 |
|
****************************************************************************** |
47 |
|
* _____ ___ ____ ___ _ |
48 |
|
* |_ _/ _ \| _ \ / _ \| | |
49 |
|
* | || | | | | | | | | | | |
50 |
|
* | || |_| | |_| | |_| |_| |
51 |
|
* |_| \___/|____/ \___/(_) |
52 |
|
* |
53 |
|
* Since this is actually a Z8530, it should be merged with dev_z8530.c! |
54 |
*/ |
*/ |
55 |
|
|
56 |
#include <stdio.h> |
#include <stdio.h> |
149 |
} |
} |
150 |
|
|
151 |
|
|
152 |
/* |
DEVICE_TICK(scc) |
|
* dev_scc_tick(): |
|
|
*/ |
|
|
void dev_scc_tick(struct cpu *cpu, void *extra) |
|
153 |
{ |
{ |
154 |
|
struct scc_data *d = extra; |
155 |
int i; |
int i; |
|
struct scc_data *d = (struct scc_data *) extra; |
|
156 |
|
|
157 |
/* Add keystrokes to the rx queue: */ |
/* Add keystrokes to the rx queue: */ |
158 |
if (d->use_fb == 0 && d->scc_nr == 1) { |
if (d->use_fb == 0 && d->scc_nr == 1) { |
161 |
d->console_handle), 2); |
d->console_handle), 2); |
162 |
} |
} |
163 |
if (d->use_fb == 1 && d->scc_nr == 1) |
if (d->use_fb == 1 && d->scc_nr == 1) |
164 |
lk201_tick(&d->lk201); |
lk201_tick(cpu->machine, &d->lk201); |
165 |
|
|
166 |
for (i=0; i<N_SCC_PORTS; i++) { |
for (i=0; i<N_SCC_PORTS; i++) { |
167 |
d->scc_register_r[i * N_SCC_REGS + SCC_RR0] |= SCC_RR0_TX_EMPTY; |
d->scc_register_r[i * N_SCC_REGS + SCC_RR0] |= SCC_RR0_TX_EMPTY; |
186 |
if (d->scc_register_r[i * N_SCC_REGS + SCC_RR3] |
if (d->scc_register_r[i * N_SCC_REGS + SCC_RR3] |
187 |
& SCC_RR3_TX_IP_A || |
& SCC_RR3_TX_IP_A || |
188 |
d->scc_register_r[i * N_SCC_REGS + SCC_RR3] |
d->scc_register_r[i * N_SCC_REGS + SCC_RR3] |
189 |
& SCC_RR3_TX_IP_B) |
& SCC_RR3_TX_IP_B) { |
190 |
cpu_interrupt(cpu, d->irq_nr); |
fatal("TODO: legacy rewrite!\n"); |
191 |
|
abort(); |
192 |
|
// cpu_interrupt(cpu, d->irq_nr); |
193 |
|
} |
194 |
} |
} |
195 |
|
|
196 |
/* RX interrupts? */ |
/* RX interrupts? */ |
209 |
if (d->scc_register_r[i * N_SCC_REGS + SCC_RR3] |
if (d->scc_register_r[i * N_SCC_REGS + SCC_RR3] |
210 |
& SCC_RR3_RX_IP_A || |
& SCC_RR3_RX_IP_A || |
211 |
d->scc_register_r[i * N_SCC_REGS + SCC_RR3] |
d->scc_register_r[i * N_SCC_REGS + SCC_RR3] |
212 |
& SCC_RR3_RX_IP_B) |
& SCC_RR3_RX_IP_B) { |
213 |
cpu_interrupt(cpu, d->irq_nr); |
fatal("TODO: legacy rewrite!\n"); |
214 |
|
abort(); |
215 |
|
// cpu_interrupt(cpu, d->irq_nr); |
216 |
|
} |
217 |
} |
} |
218 |
|
|
219 |
if (d->scc_register_w[N_SCC_REGS + SCC_WR1] & |
if (d->scc_register_w[N_SCC_REGS + SCC_WR1] & |
235 |
d->scc_register_r[i * N_SCC_REGS + SCC_RR3] |
d->scc_register_r[i * N_SCC_REGS + SCC_RR3] |
236 |
& SCC_RR3_EXT_IP_B) |
& SCC_RR3_EXT_IP_B) |
237 |
{ |
{ |
238 |
cpu_interrupt(cpu, d->irq_nr); |
fatal("TODO: legacy rewrite!\n"); |
239 |
|
abort(); |
240 |
|
// cpu_interrupt(cpu, d->irq_nr); |
241 |
/* TODO: huh? */ |
/* TODO: huh? */ |
242 |
cpu_interrupt(cpu, 8 + 0x02000000); |
//cpu_interrupt(cpu, 8 + 0x02000000); |
243 |
} |
} |
244 |
} |
} |
245 |
} |
} |
305 |
} |
} |
306 |
|
|
307 |
|
|
308 |
/* |
DEVICE_ACCESS(scc) |
|
* dev_scc_access(): |
|
|
*/ |
|
|
int dev_scc_access(struct cpu *cpu, struct memory *mem, |
|
|
uint64_t relative_addr, unsigned char *data, size_t len, |
|
|
int writeflag, void *extra) |
|
309 |
{ |
{ |
310 |
struct scc_data *d = (struct scc_data *) extra; |
struct scc_data *d = extra; |
311 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
312 |
int port; |
int port; |
313 |
int ultrix_mode = 0; |
int ultrix_mode = 0; |
314 |
|
|
315 |
idata = memory_readmax64(cpu, data, len); |
if (writeflag == MEM_WRITE) |
316 |
|
idata = memory_readmax64(cpu, data, len); |
317 |
|
|
318 |
/* relative_addr /= d->addrmul; */ |
/* relative_addr /= d->addrmul; */ |
319 |
/* See SGI comment below instead. */ |
/* See SGI comment below instead. */ |
356 |
|
|
357 |
d->scc_register_r[port * N_SCC_REGS + |
d->scc_register_r[port * N_SCC_REGS + |
358 |
SCC_RR3] = 0; |
SCC_RR3] = 0; |
359 |
cpu_interrupt_ack(cpu, d->irq_nr); |
|
360 |
|
fatal("TODO: legacy rewrite!\n"); |
361 |
|
abort(); |
362 |
|
// cpu_interrupt_ack(cpu, d->irq_nr); |
363 |
} |
} |
364 |
|
|
365 |
#ifdef SCC_DEBUG |
#ifdef SCC_DEBUG |
406 |
|
|
407 |
/* TODO: perhaps only clear the RX part of RR3? */ |
/* TODO: perhaps only clear the RX part of RR3? */ |
408 |
d->scc_register_r[N_SCC_REGS + SCC_RR3] = 0; |
d->scc_register_r[N_SCC_REGS + SCC_RR3] = 0; |
|
cpu_interrupt_ack(cpu, d->irq_nr); |
|
409 |
|
|
410 |
debug("[ scc: (port %i) read from 0x%08lx: 0x%02x ]\n", |
fatal("TODO: legacy rewrite!\n"); |
411 |
port, (long)relative_addr, (int)odata); |
abort(); |
412 |
|
// cpu_interrupt_ack(cpu, d->irq_nr); |
413 |
|
|
414 |
|
// debug("[ scc: (port %i) read from 0x%08lx: 0x%02x ]\n", |
415 |
|
// port, (long)relative_addr, (int)odata); |
416 |
} else { |
} else { |
417 |
/* debug("[ scc: (port %i) write to 0x%08lx: " |
/* debug("[ scc: (port %i) write to 0x%08lx: " |
418 |
"0x%08x ]\n", port, (long)relative_addr, |
"0x%08x ]\n", port, (long)relative_addr, |
476 |
{ |
{ |
477 |
struct scc_data *d; |
struct scc_data *d; |
478 |
|
|
479 |
d = malloc(sizeof(struct scc_data)); |
CHECK_ALLOCATION(d = malloc(sizeof(struct scc_data))); |
|
if (d == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
480 |
memset(d, 0, sizeof(struct scc_data)); |
memset(d, 0, sizeof(struct scc_data)); |
481 |
|
|
482 |
d->irq_nr = irq_nr; |
d->irq_nr = irq_nr; |
483 |
d->scc_nr = scc_nr; |
d->scc_nr = scc_nr; |
484 |
d->use_fb = use_fb; |
d->use_fb = use_fb; |
485 |
d->addrmul = addrmul; |
d->addrmul = addrmul; |
486 |
d->console_handle = console_start_slave(machine, "SCC"); |
d->console_handle = console_start_slave(machine, "SCC", 1); |
487 |
|
|
488 |
lk201_init(&d->lk201, use_fb, dev_scc_add_to_rx_queue, |
lk201_init(&d->lk201, use_fb, dev_scc_add_to_rx_queue, |
489 |
d->console_handle, d); |
d->console_handle, d); |
490 |
|
|
491 |
memory_device_register(mem, "scc", baseaddr, DEV_SCC_LENGTH, |
memory_device_register(mem, "scc", baseaddr, DEV_SCC_LENGTH, |
492 |
dev_scc_access, d, MEM_DEFAULT, NULL); |
dev_scc_access, d, DM_DEFAULT, NULL); |
493 |
machine_add_tickfunction(machine, dev_scc_tick, d, SCC_TICK_SHIFT); |
machine_add_tickfunction(machine, dev_scc_tick, d, SCC_TICK_SHIFT); |
494 |
|
|
495 |
return (void *) d; |
return (void *) d; |