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.8 2006/03/04 12:38:49 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 |
{ |
{ |
94 |
|
|
95 |
/* |
/* |
96 |
* dev_z8530_tick(): |
* dev_z8530_tick(): |
97 |
|
* |
98 |
|
* Generate transmit and receive interrupts at regular intervals. |
99 |
*/ |
*/ |
100 |
void dev_z8530_tick(struct cpu *cpu, void *extra) |
void dev_z8530_tick(struct cpu *cpu, void *extra) |
101 |
{ |
{ |
129 |
} |
} |
130 |
|
|
131 |
|
|
|
/* |
|
|
* dev_z8530_access(): |
|
|
*/ |
|
132 |
DEVICE_ACCESS(z8530) |
DEVICE_ACCESS(z8530) |
133 |
{ |
{ |
134 |
struct z8530_data *d = extra; |
struct z8530_data *d = extra; |
144 |
|
|
145 |
relative_addr /= d->addr_mult; |
relative_addr /= d->addr_mult; |
146 |
|
|
147 |
port_nr = relative_addr / 2; |
port_nr = (relative_addr / 2) % ZS_N_CHANNELS; |
148 |
relative_addr &= 1; |
relative_addr &= 1; |
149 |
|
|
150 |
if (relative_addr == 0) { |
if (relative_addr == 0) { |
151 |
/* Register access: */ |
/* Register access: */ |
152 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
153 |
odata = d->rr[port_nr][d->reg_select[port_nr]]; |
odata = d->rr[port_nr][d->reg_select[port_nr]]; |
154 |
if (d->reg_select[port_nr] != 0) |
debug("[ z8530: read from port %i reg %2i: " |
155 |
debug("[ z8530: read from port %i reg %2i: " |
"0x%02x ]\n", port_nr, d->reg_select[ |
156 |
"0x%02x ]\n", port_nr, d->reg_select[ |
port_nr], (int)odata); |
|
port_nr], (int)odata); |
|
157 |
d->reg_select[port_nr] = 0; |
d->reg_select[port_nr] = 0; |
158 |
} else { |
} else { |
159 |
if (d->reg_select[port_nr] == 0) { |
if (d->reg_select[port_nr] == 0) { |
160 |
d->reg_select[port_nr] = idata & 15; |
if (idata < 16) |
161 |
|
d->reg_select[port_nr] = idata & 15; |
162 |
|
else |
163 |
|
d->reg_select[port_nr] = idata & 7; |
164 |
|
switch (idata & 0xf8) { |
165 |
|
case ZSWR0_CLR_INTR: /* Interrupt ack: */ |
166 |
|
d->rr[1][3] = 0; |
167 |
|
break; |
168 |
|
} |
169 |
} else { |
} else { |
170 |
d->wr[port_nr][d->reg_select[port_nr]] = idata; |
d->wr[port_nr][d->reg_select[port_nr]] = idata; |
171 |
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; |
|
172 |
default:debug("[ z8530: write to port %i reg " |
default:debug("[ z8530: write to port %i reg " |
173 |
"%2i: 0x%02x ]\n", port_nr, d-> |
"%2i: 0x%02x ]\n", port_nr, d-> |
174 |
reg_select[port_nr], (int)idata); |
reg_select[port_nr], (int)idata); |
217 |
memset(d, 0, sizeof(struct z8530_data)); |
memset(d, 0, sizeof(struct z8530_data)); |
218 |
d->irq_nr = devinit->irq_nr; |
d->irq_nr = devinit->irq_nr; |
219 |
d->dma_irq_nr = devinit->dma_irq_nr; |
d->dma_irq_nr = devinit->dma_irq_nr; |
|
d->in_use = devinit->in_use; |
|
220 |
d->addr_mult = devinit->addr_mult; |
d->addr_mult = devinit->addr_mult; |
221 |
|
|
222 |
snprintf(tmp, sizeof(tmp), "%s [ch-b]", devinit->name); |
snprintf(tmp, sizeof(tmp), "%s [ch-b]", devinit->name); |
223 |
d->console_handle[0] = console_start_slave(devinit->machine, tmp, |
d->console_handle[0] = console_start_slave(devinit->machine, tmp, |
224 |
d->in_use); |
devinit->in_use); |
225 |
snprintf(tmp, sizeof(tmp), "%s [ch-a]", devinit->name); |
snprintf(tmp, sizeof(tmp), "%s [ch-a]", devinit->name); |
226 |
d->console_handle[1] = console_start_slave(devinit->machine, tmp, 0); |
d->console_handle[1] = console_start_slave(devinit->machine, tmp, 0); |
227 |
|
|
236 |
NULL); |
NULL); |
237 |
|
|
238 |
machine_add_tickfunction(devinit->machine, dev_z8530_tick, d, |
machine_add_tickfunction(devinit->machine, dev_z8530_tick, d, |
239 |
ZS_TICK_SHIFT); |
ZS_TICK_SHIFT, 0.0); |
240 |
|
|
241 |
devinit->return_ptr = (void *)(size_t) d->console_handle[0]; |
devinit->return_ptr = (void *)(size_t) d->console_handle[0]; |
242 |
|
|