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_dc7085.c,v 1.51 2005/11/13 00:14:08 debug Exp $ |
* $Id: dev_dc7085.c,v 1.62 2007/06/15 18:44:19 debug Exp $ |
29 |
* |
* |
30 |
* DC7085 serial controller, used in some DECstation models. |
* COMMENT: DC7085 serial controller, used in some DECstation models |
31 |
*/ |
*/ |
32 |
|
|
33 |
#include <stdio.h> |
#include <stdio.h> |
46 |
|
|
47 |
#define DC_TICK_SHIFT 14 |
#define DC_TICK_SHIFT 14 |
48 |
|
|
49 |
#define MAX_QUEUE_LEN 4096 |
#define MAX_QUEUE_LEN 32768 |
50 |
|
|
51 |
struct dc_data { |
struct dc_data { |
52 |
struct dc7085regs regs; |
struct dc7085regs regs; |
63 |
|
|
64 |
int tx_scanner; |
int tx_scanner; |
65 |
|
|
66 |
int irqnr; |
struct interrupt irq; |
67 |
int use_fb; |
int use_fb; |
68 |
|
|
69 |
struct lk201_data lk201; |
struct lk201_data lk201; |
78 |
struct dc_data *d = (struct dc_data *) e; |
struct dc_data *d = (struct dc_data *) e; |
79 |
int entries_in_use = d->cur_rx_queue_pos_write - |
int entries_in_use = d->cur_rx_queue_pos_write - |
80 |
d->cur_rx_queue_pos_read; |
d->cur_rx_queue_pos_read; |
81 |
|
|
82 |
while (entries_in_use < 0) |
while (entries_in_use < 0) |
83 |
entries_in_use += MAX_QUEUE_LEN; |
entries_in_use += MAX_QUEUE_LEN; |
84 |
|
|
97 |
} |
} |
98 |
|
|
99 |
|
|
100 |
/* |
DEVICE_TICK(dc7085) |
|
* dev_dc7085_tick(): |
|
|
* |
|
|
* This function is called "every now and then". |
|
|
* If a key is available from the keyboard, add it to the rx queue. |
|
|
* If other bits are set, an interrupt might need to be caused. |
|
|
*/ |
|
|
void dev_dc7085_tick(struct cpu *cpu, void *extra) |
|
101 |
{ |
{ |
102 |
|
/* |
103 |
|
* If a key is available from the keyboard, add it to the rx queue. |
104 |
|
* If other bits are set, an interrupt might need to be caused. |
105 |
|
*/ |
106 |
struct dc_data *d = extra; |
struct dc_data *d = extra; |
107 |
int avail; |
int avail; |
108 |
|
|
131 |
if (d->regs.dc_tcr & (1 << d->tx_scanner)) { |
if (d->regs.dc_tcr & (1 << d->tx_scanner)) { |
132 |
d->regs.dc_csr |= CSR_TRDY; |
d->regs.dc_csr |= CSR_TRDY; |
133 |
if (d->regs.dc_csr & CSR_TIE) |
if (d->regs.dc_csr & CSR_TIE) |
134 |
cpu_interrupt(cpu, d->irqnr); |
INTERRUPT_ASSERT(d->irq); |
135 |
|
|
136 |
d->regs.dc_csr &= ~CSR_TX_LINE_NUM; |
d->regs.dc_csr &= ~CSR_TX_LINE_NUM; |
137 |
d->regs.dc_csr |= (d->tx_scanner << 8); |
d->regs.dc_csr |= (d->tx_scanner << 8); |
147 |
return; |
return; |
148 |
} |
} |
149 |
|
|
150 |
lk201_tick(&d->lk201); |
lk201_tick(cpu->machine, &d->lk201); |
151 |
|
|
152 |
avail = d->cur_rx_queue_pos_write != d->cur_rx_queue_pos_read; |
avail = d->cur_rx_queue_pos_write != d->cur_rx_queue_pos_read; |
153 |
|
|
155 |
d->regs.dc_csr |= CSR_RDONE; |
d->regs.dc_csr |= CSR_RDONE; |
156 |
|
|
157 |
if ((d->regs.dc_csr & CSR_RDONE) && (d->regs.dc_csr & CSR_RIE)) |
if ((d->regs.dc_csr & CSR_RDONE) && (d->regs.dc_csr & CSR_RIE)) |
158 |
cpu_interrupt(cpu, d->irqnr); |
INTERRUPT_ASSERT(d->irq); |
159 |
} |
} |
160 |
|
|
161 |
|
|
162 |
/* |
DEVICE_ACCESS(dc7085) |
|
* dev_dc7085_access(): |
|
|
*/ |
|
|
int dev_dc7085_access(struct cpu *cpu, struct memory *mem, |
|
|
uint64_t relative_addr, unsigned char *data, size_t len, |
|
|
int writeflag, void *extra) |
|
163 |
{ |
{ |
|
uint64_t idata = 0, odata = 0; |
|
|
int i; |
|
164 |
struct dc_data *d = extra; |
struct dc_data *d = extra; |
165 |
|
uint64_t idata = 0, odata = 0; |
166 |
|
size_t i; |
167 |
|
|
168 |
if (writeflag == MEM_WRITE) |
if (writeflag == MEM_WRITE) |
169 |
idata = memory_readmax64(cpu, data, len); |
idata = memory_readmax64(cpu, data, len); |
172 |
d->regs.dc_csr &= ~CSR_CLR; |
d->regs.dc_csr &= ~CSR_CLR; |
173 |
|
|
174 |
switch (relative_addr) { |
switch (relative_addr) { |
175 |
|
|
176 |
case 0x00: /* CSR: Control and Status */ |
case 0x00: /* CSR: Control and Status */ |
177 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
178 |
debug("[ dc7085 write to CSR: 0x%04x ]\n", idata); |
debug("[ dc7085 write to CSR: 0x%04x ]\n", idata); |
192 |
odata = d->regs.dc_csr; |
odata = d->regs.dc_csr; |
193 |
} |
} |
194 |
break; |
break; |
195 |
|
|
196 |
case 0x08: /* LPR: */ |
case 0x08: /* LPR: */ |
197 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
198 |
debug("[ dc7085 write to LPR: 0x%04x ]\n", idata); |
debug("[ dc7085 write to LPR: 0x%04x ]\n", idata); |
223 |
(lineno << RBUF_LINE_NUM_SHIFT) | ch; |
(lineno << RBUF_LINE_NUM_SHIFT) | ch; |
224 |
|
|
225 |
d->regs.dc_csr &= ~CSR_RDONE; |
d->regs.dc_csr &= ~CSR_RDONE; |
226 |
cpu_interrupt_ack(cpu, d->irqnr); |
INTERRUPT_DEASSERT(d->irq); |
227 |
|
|
228 |
d->just_transmitted_something = 4; |
d->just_transmitted_something = 4; |
229 |
} |
} |
230 |
break; |
break; |
231 |
|
|
232 |
case 0x10: /* TCR: */ |
case 0x10: /* TCR: */ |
233 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
234 |
/* fatal("[ dc7085 write to TCR: 0x%04x) ]\n", |
/* fatal("[ dc7085 write to TCR: 0x%04x) ]\n", |
235 |
(int)idata); */ |
(int)idata); */ |
236 |
d->regs.dc_tcr = idata; |
d->regs.dc_tcr = idata; |
237 |
d->regs.dc_csr &= ~CSR_TRDY; |
d->regs.dc_csr &= ~CSR_TRDY; |
238 |
cpu_interrupt_ack(cpu, d->irqnr); |
INTERRUPT_DEASSERT(d->irq); |
239 |
goto do_return; |
goto do_return; |
240 |
} else { |
} else { |
241 |
/* read: */ |
/* read: */ |
244 |
odata = d->regs.dc_tcr; |
odata = d->regs.dc_tcr; |
245 |
} |
} |
246 |
break; |
break; |
247 |
|
|
248 |
case 0x18: /* Modem status (R), transmit data (W) */ |
case 0x18: /* Modem status (R), transmit data (W) */ |
249 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
250 |
int line_no = (d->regs.dc_csr >> |
int line_no = (d->regs.dc_csr >> |
254 |
lk201_tx_data(&d->lk201, line_no, idata); |
lk201_tx_data(&d->lk201, line_no, idata); |
255 |
|
|
256 |
d->regs.dc_csr &= ~CSR_TRDY; |
d->regs.dc_csr &= ~CSR_TRDY; |
257 |
cpu_interrupt_ack(cpu, d->irqnr); |
INTERRUPT_DEASSERT(d->irq); |
258 |
|
|
259 |
d->just_transmitted_something = 4; |
d->just_transmitted_something = 4; |
260 |
} else { |
} else { |
266 |
odata = d->regs.dc_msr_tdr; |
odata = d->regs.dc_msr_tdr; |
267 |
} |
} |
268 |
break; |
break; |
269 |
|
|
270 |
default: |
default: |
271 |
if (writeflag==MEM_READ) { |
if (writeflag==MEM_READ) { |
272 |
debug("[ dc7085 read from 0x%08lx ]\n", |
debug("[ dc7085 read from 0x%08lx ]\n", |
298 |
* DECstation keyboard, instead of a plain serial console. |
* DECstation keyboard, instead of a plain serial console. |
299 |
*/ |
*/ |
300 |
int dev_dc7085_init(struct machine *machine, struct memory *mem, |
int dev_dc7085_init(struct machine *machine, struct memory *mem, |
301 |
uint64_t baseaddr, int irq_nr, int use_fb) |
uint64_t baseaddr, char *irq_path, int use_fb) |
302 |
{ |
{ |
303 |
struct dc_data *d; |
struct dc_data *d; |
304 |
|
|
305 |
d = malloc(sizeof(struct dc_data)); |
CHECK_ALLOCATION(d = malloc(sizeof(struct dc_data))); |
|
if (d == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
306 |
memset(d, 0, sizeof(struct dc_data)); |
memset(d, 0, sizeof(struct dc_data)); |
307 |
d->irqnr = irq_nr; |
|
308 |
|
INTERRUPT_CONNECT(irq_path, d->irq); |
309 |
d->use_fb = use_fb; |
d->use_fb = use_fb; |
310 |
|
|
311 |
d->regs.dc_csr = CSR_TRDY | CSR_MSE; |
d->regs.dc_csr = CSR_TRDY | CSR_MSE; |
312 |
d->regs.dc_tcr = 0x00; |
d->regs.dc_tcr = 0x00; |
313 |
|
|
314 |
d->console_handle = console_start_slave(machine, "DC7085"); |
d->console_handle = console_start_slave(machine, "DC7085", 1); |
315 |
|
|
316 |
lk201_init(&d->lk201, use_fb, add_to_rx_queue, d->console_handle, d); |
lk201_init(&d->lk201, use_fb, add_to_rx_queue, d->console_handle, d); |
317 |
|
|
318 |
memory_device_register(mem, "dc7085", baseaddr, DEV_DC7085_LENGTH, |
memory_device_register(mem, "dc7085", baseaddr, DEV_DC7085_LENGTH, |
319 |
dev_dc7085_access, d, DM_DEFAULT, NULL); |
dev_dc7085_access, d, DM_DEFAULT, NULL); |
320 |
machine_add_tickfunction(machine, dev_dc7085_tick, d, DC_TICK_SHIFT); |
machine_add_tickfunction(machine, dev_dc7085_tick, d, |
321 |
|
DC_TICK_SHIFT); |
322 |
|
|
323 |
return d->console_handle; |
return d->console_handle; |
324 |
} |
} |