25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: dev_z8530.c,v 1.5 2006/02/09 20:02:59 debug Exp $ |
* $Id: dev_z8530.c,v 1.9 2006/10/07 02:05:21 debug Exp $ |
29 |
* |
* |
30 |
* Zilog "zs" serial controller (Z8530). |
* Zilog "zs" serial controller (Z8530). |
31 |
* |
* |
32 |
* Features: |
* Features: |
33 |
* o) Two channels, 0 = "channel B", 1 = "channel A". |
* o) Two channels, 0 = "channel B", 1 = "channel A". |
34 |
|
* Normally, only channel B is in use. |
35 |
* |
* |
36 |
* This is a work in progress... TODOs include: |
* This is a work in progress... TODOs include: |
37 |
* o) Implement more of the register set. |
* o) Implement more of the register set. |
53 |
#include "z8530reg.h" |
#include "z8530reg.h" |
54 |
|
|
55 |
|
|
56 |
#define debug fatal |
/* #define debug fatal */ |
57 |
|
|
58 |
#define ZS_TICK_SHIFT 14 |
#define ZS_TICK_SHIFT 14 |
59 |
#define ZS_N_REGS 16 |
#define ZS_N_REGS 16 |
60 |
|
#define ZS_N_CHANNELS 2 |
61 |
#define DEV_Z8530_LENGTH 4 |
#define DEV_Z8530_LENGTH 4 |
62 |
|
|
63 |
struct z8530_data { |
struct z8530_data { |
64 |
int irq_nr; |
int irq_nr; |
65 |
int dma_irq_nr; |
int dma_irq_nr; |
66 |
int irq_asserted; |
int irq_asserted; |
|
|
|
|
int in_use; |
|
67 |
int addr_mult; |
int addr_mult; |
68 |
|
|
69 |
/* 2 of everything, because there are two channels. */ |
int console_handle[ZS_N_CHANNELS]; |
70 |
int console_handle[2]; |
int reg_select[ZS_N_CHANNELS]; |
71 |
int reg_select[2]; |
uint8_t rr[ZS_N_CHANNELS][ZS_N_REGS]; |
72 |
uint8_t rr[2][ZS_N_REGS]; |
uint8_t wr[ZS_N_CHANNELS][ZS_N_REGS]; |
|
uint8_t wr[2][ZS_N_REGS]; |
|
73 |
}; |
}; |
74 |
|
|
75 |
|
|
76 |
/* |
/* |
77 |
* check_incoming(): |
* check_incoming(): |
78 |
|
* |
79 |
|
* Sets the RX interrupt flag for ports B and A, if something there is input |
80 |
|
* available on port 0 or 1, respectively. |
81 |
*/ |
*/ |
82 |
static void check_incoming(struct cpu *cpu, struct z8530_data *d) |
static void check_incoming(struct cpu *cpu, struct z8530_data *d) |
83 |
{ |
{ |
92 |
} |
} |
93 |
|
|
94 |
|
|
95 |
/* |
DEVICE_TICK(z8530) |
|
* dev_z8530_tick(): |
|
|
*/ |
|
|
void dev_z8530_tick(struct cpu *cpu, void *extra) |
|
96 |
{ |
{ |
97 |
|
/* Generate transmit and receive interrupts at regular intervals. */ |
98 |
struct z8530_data *d = (struct z8530_data *) extra; |
struct z8530_data *d = (struct z8530_data *) extra; |
99 |
int asserted = 0; |
int asserted = 0; |
100 |
|
|
125 |
} |
} |
126 |
|
|
127 |
|
|
|
/* |
|
|
* dev_z8530_access(): |
|
|
*/ |
|
128 |
DEVICE_ACCESS(z8530) |
DEVICE_ACCESS(z8530) |
129 |
{ |
{ |
130 |
struct z8530_data *d = extra; |
struct z8530_data *d = extra; |
140 |
|
|
141 |
relative_addr /= d->addr_mult; |
relative_addr /= d->addr_mult; |
142 |
|
|
143 |
port_nr = relative_addr / 2; |
port_nr = (relative_addr / 2) % ZS_N_CHANNELS; |
144 |
relative_addr &= 1; |
relative_addr &= 1; |
145 |
|
|
146 |
if (relative_addr == 0) { |
if (relative_addr == 0) { |
147 |
/* Register access: */ |
/* Register access: */ |
148 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
149 |
odata = d->rr[port_nr][d->reg_select[port_nr]]; |
odata = d->rr[port_nr][d->reg_select[port_nr]]; |
150 |
if (d->reg_select[port_nr] != 0) |
debug("[ z8530: read from port %i reg %2i: " |
151 |
debug("[ z8530: read from port %i reg %2i: " |
"0x%02x ]\n", port_nr, d->reg_select[ |
152 |
"0x%02x ]\n", port_nr, d->reg_select[ |
port_nr], (int)odata); |
|
port_nr], (int)odata); |
|
153 |
d->reg_select[port_nr] = 0; |
d->reg_select[port_nr] = 0; |
154 |
} else { |
} else { |
155 |
if (d->reg_select[port_nr] == 0) { |
if (d->reg_select[port_nr] == 0) { |
156 |
d->reg_select[port_nr] = idata & 15; |
if (idata < 16) |
157 |
|
d->reg_select[port_nr] = idata & 15; |
158 |
|
else |
159 |
|
d->reg_select[port_nr] = idata & 7; |
160 |
|
switch (idata & 0xf8) { |
161 |
|
case ZSWR0_CLR_INTR: /* Interrupt ack: */ |
162 |
|
d->rr[1][3] = 0; |
163 |
|
break; |
164 |
|
} |
165 |
} else { |
} else { |
166 |
d->wr[port_nr][d->reg_select[port_nr]] = idata; |
d->wr[port_nr][d->reg_select[port_nr]] = idata; |
167 |
switch (d->reg_select[port_nr]) { |
switch (d->reg_select[port_nr]) { |
|
case 8: /* Interrupt ack: */ |
|
|
if (idata == ZSWR0_CLR_INTR) |
|
|
d->rr[1][3] = 0; |
|
|
break; |
|
168 |
default:debug("[ z8530: write to port %i reg " |
default:debug("[ z8530: write to port %i reg " |
169 |
"%2i: 0x%02x ]\n", port_nr, d-> |
"%2i: 0x%02x ]\n", port_nr, d-> |
170 |
reg_select[port_nr], (int)idata); |
reg_select[port_nr], (int)idata); |
213 |
memset(d, 0, sizeof(struct z8530_data)); |
memset(d, 0, sizeof(struct z8530_data)); |
214 |
d->irq_nr = devinit->irq_nr; |
d->irq_nr = devinit->irq_nr; |
215 |
d->dma_irq_nr = devinit->dma_irq_nr; |
d->dma_irq_nr = devinit->dma_irq_nr; |
|
d->in_use = devinit->in_use; |
|
216 |
d->addr_mult = devinit->addr_mult; |
d->addr_mult = devinit->addr_mult; |
217 |
|
|
218 |
snprintf(tmp, sizeof(tmp), "%s [ch-b]", devinit->name); |
snprintf(tmp, sizeof(tmp), "%s [ch-b]", devinit->name); |
219 |
d->console_handle[0] = console_start_slave(devinit->machine, tmp, |
d->console_handle[0] = console_start_slave(devinit->machine, tmp, |
220 |
d->in_use); |
devinit->in_use); |
221 |
snprintf(tmp, sizeof(tmp), "%s [ch-a]", devinit->name); |
snprintf(tmp, sizeof(tmp), "%s [ch-a]", devinit->name); |
222 |
d->console_handle[1] = console_start_slave(devinit->machine, tmp, 0); |
d->console_handle[1] = console_start_slave(devinit->machine, tmp, 0); |
223 |
|
|
232 |
NULL); |
NULL); |
233 |
|
|
234 |
machine_add_tickfunction(devinit->machine, dev_z8530_tick, d, |
machine_add_tickfunction(devinit->machine, dev_z8530_tick, d, |
235 |
ZS_TICK_SHIFT); |
ZS_TICK_SHIFT, 0.0); |
236 |
|
|
237 |
devinit->return_ptr = (void *)(size_t) d->console_handle[0]; |
devinit->return_ptr = (void *)(size_t) d->console_handle[0]; |
238 |
|
|