root / hw / etraxfs_ser.c @ 4af39611
History | View | Annotate | Download (4.5 kB)
1 | 83fa1010 | ths | /*
|
---|---|---|---|
2 | 83fa1010 | ths | * QEMU ETRAX System Emulator
|
3 | 83fa1010 | ths | *
|
4 | 83fa1010 | ths | * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
|
5 | 83fa1010 | ths | *
|
6 | 83fa1010 | ths | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | 83fa1010 | ths | * of this software and associated documentation files (the "Software"), to deal
|
8 | 83fa1010 | ths | * in the Software without restriction, including without limitation the rights
|
9 | 83fa1010 | ths | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | 83fa1010 | ths | * copies of the Software, and to permit persons to whom the Software is
|
11 | 83fa1010 | ths | * furnished to do so, subject to the following conditions:
|
12 | 83fa1010 | ths | *
|
13 | 83fa1010 | ths | * The above copyright notice and this permission notice shall be included in
|
14 | 83fa1010 | ths | * all copies or substantial portions of the Software.
|
15 | 83fa1010 | ths | *
|
16 | 83fa1010 | ths | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | 83fa1010 | ths | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | 83fa1010 | ths | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | 83fa1010 | ths | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | 83fa1010 | ths | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | 83fa1010 | ths | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | 83fa1010 | ths | * THE SOFTWARE.
|
23 | 83fa1010 | ths | */
|
24 | 83fa1010 | ths | |
25 | 83fa1010 | ths | #include <stdio.h> |
26 | 83fa1010 | ths | #include <ctype.h> |
27 | 87ecb68b | pbrook | #include "hw.h" |
28 | f062058f | edgar_igl | #include "qemu-char.h" |
29 | cc53adbc | edgar_igl | #include "etraxfs.h" |
30 | 83fa1010 | ths | |
31 | bbaf29c7 | edgar_igl | #define D(x)
|
32 | bbaf29c7 | edgar_igl | |
33 | 72af9170 | Edgar E. Iglesias | #define RW_TR_CTRL (0x00 / 4) |
34 | 72af9170 | Edgar E. Iglesias | #define RW_TR_DMA_EN (0x04 / 4) |
35 | 72af9170 | Edgar E. Iglesias | #define RW_REC_CTRL (0x08 / 4) |
36 | 72af9170 | Edgar E. Iglesias | #define RW_DOUT (0x1c / 4) |
37 | 72af9170 | Edgar E. Iglesias | #define RS_STAT_DIN (0x20 / 4) |
38 | 72af9170 | Edgar E. Iglesias | #define R_STAT_DIN (0x24 / 4) |
39 | 72af9170 | Edgar E. Iglesias | #define RW_INTR_MASK (0x2c / 4) |
40 | 72af9170 | Edgar E. Iglesias | #define RW_ACK_INTR (0x30 / 4) |
41 | 72af9170 | Edgar E. Iglesias | #define R_INTR (0x34 / 4) |
42 | 72af9170 | Edgar E. Iglesias | #define R_MASKED_INTR (0x38 / 4) |
43 | 72af9170 | Edgar E. Iglesias | #define R_MAX (0x3c / 4) |
44 | 83fa1010 | ths | |
45 | f062058f | edgar_igl | #define STAT_DAV 16 |
46 | f062058f | edgar_igl | #define STAT_TR_IDLE 22 |
47 | f062058f | edgar_igl | #define STAT_TR_RDY 24 |
48 | f062058f | edgar_igl | |
49 | f2964260 | Edgar E. Iglesias | struct etrax_serial
|
50 | 83fa1010 | ths | { |
51 | f062058f | edgar_igl | CPUState *env; |
52 | f062058f | edgar_igl | CharDriverState *chr; |
53 | f062058f | edgar_igl | qemu_irq *irq; |
54 | f062058f | edgar_igl | |
55 | 72af9170 | Edgar E. Iglesias | /* This pending thing is a hack. */
|
56 | f062058f | edgar_igl | int pending_tx;
|
57 | f062058f | edgar_igl | |
58 | f062058f | edgar_igl | /* Control registers. */
|
59 | 72af9170 | Edgar E. Iglesias | uint32_t regs[R_MAX]; |
60 | f062058f | edgar_igl | }; |
61 | f062058f | edgar_igl | |
62 | f2964260 | Edgar E. Iglesias | static void ser_update_irq(struct etrax_serial *s) |
63 | f062058f | edgar_igl | { |
64 | 72af9170 | Edgar E. Iglesias | s->regs[R_INTR] &= ~(s->regs[RW_ACK_INTR]); |
65 | 72af9170 | Edgar E. Iglesias | s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK]; |
66 | 72af9170 | Edgar E. Iglesias | |
67 | 72af9170 | Edgar E. Iglesias | qemu_set_irq(s->irq[0], !!s->regs[R_MASKED_INTR]);
|
68 | 72af9170 | Edgar E. Iglesias | s->regs[RW_ACK_INTR] = 0;
|
69 | 83fa1010 | ths | } |
70 | f062058f | edgar_igl | |
71 | 83fa1010 | ths | static uint32_t ser_readl (void *opaque, target_phys_addr_t addr) |
72 | 83fa1010 | ths | { |
73 | f2964260 | Edgar E. Iglesias | struct etrax_serial *s = opaque;
|
74 | f062058f | edgar_igl | D(CPUState *env = s->env); |
75 | 83fa1010 | ths | uint32_t r = 0;
|
76 | 83fa1010 | ths | |
77 | 72af9170 | Edgar E. Iglesias | addr >>= 2;
|
78 | 0db74b07 | edgar_igl | switch (addr)
|
79 | 83fa1010 | ths | { |
80 | 83fa1010 | ths | case R_STAT_DIN:
|
81 | 72af9170 | Edgar E. Iglesias | r = s->regs[RS_STAT_DIN]; |
82 | f062058f | edgar_igl | break;
|
83 | 72af9170 | Edgar E. Iglesias | case RS_STAT_DIN:
|
84 | 72af9170 | Edgar E. Iglesias | r = s->regs[addr]; |
85 | 72af9170 | Edgar E. Iglesias | /* Read side-effect: clear dav. */
|
86 | 72af9170 | Edgar E. Iglesias | s->regs[addr] &= ~(1 << STAT_DAV);
|
87 | 83fa1010 | ths | break;
|
88 | 83fa1010 | ths | default:
|
89 | 72af9170 | Edgar E. Iglesias | r = s->regs[addr]; |
90 | 72af9170 | Edgar E. Iglesias | D(printf ("%s %x=%x\n", __func__, addr, r));
|
91 | 83fa1010 | ths | break;
|
92 | 83fa1010 | ths | } |
93 | 83fa1010 | ths | return r;
|
94 | 83fa1010 | ths | } |
95 | 83fa1010 | ths | |
96 | 83fa1010 | ths | static void |
97 | 83fa1010 | ths | ser_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
|
98 | 83fa1010 | ths | { |
99 | f2964260 | Edgar E. Iglesias | struct etrax_serial *s = opaque;
|
100 | f062058f | edgar_igl | unsigned char ch = value; |
101 | f062058f | edgar_igl | D(CPUState *env = s->env); |
102 | 83fa1010 | ths | |
103 | 72af9170 | Edgar E. Iglesias | D(printf ("%s %x %x\n", __func__, addr, value));
|
104 | 72af9170 | Edgar E. Iglesias | addr >>= 2;
|
105 | 0db74b07 | edgar_igl | switch (addr)
|
106 | 83fa1010 | ths | { |
107 | 83fa1010 | ths | case RW_DOUT:
|
108 | f062058f | edgar_igl | qemu_chr_write(s->chr, &ch, 1);
|
109 | 72af9170 | Edgar E. Iglesias | s->regs[R_INTR] |= 1;
|
110 | f062058f | edgar_igl | s->pending_tx = 1;
|
111 | 72af9170 | Edgar E. Iglesias | s->regs[addr] = value; |
112 | f062058f | edgar_igl | break;
|
113 | f062058f | edgar_igl | case RW_ACK_INTR:
|
114 | 72af9170 | Edgar E. Iglesias | s->regs[addr] = value; |
115 | 72af9170 | Edgar E. Iglesias | if (s->pending_tx && (s->regs[addr] & 1)) { |
116 | 72af9170 | Edgar E. Iglesias | s->regs[R_INTR] |= 1;
|
117 | f062058f | edgar_igl | s->pending_tx = 0;
|
118 | 72af9170 | Edgar E. Iglesias | s->regs[addr] &= ~1;
|
119 | f062058f | edgar_igl | } |
120 | f062058f | edgar_igl | break;
|
121 | 83fa1010 | ths | default:
|
122 | 72af9170 | Edgar E. Iglesias | s->regs[addr] = value; |
123 | 83fa1010 | ths | break;
|
124 | 83fa1010 | ths | } |
125 | f062058f | edgar_igl | ser_update_irq(s); |
126 | 83fa1010 | ths | } |
127 | 83fa1010 | ths | |
128 | 83fa1010 | ths | static CPUReadMemoryFunc *ser_read[] = {
|
129 | 4ad804df | Edgar E. Iglesias | NULL, NULL, |
130 | ca87d03b | edgar_igl | &ser_readl, |
131 | 83fa1010 | ths | }; |
132 | 83fa1010 | ths | |
133 | 83fa1010 | ths | static CPUWriteMemoryFunc *ser_write[] = {
|
134 | 4ad804df | Edgar E. Iglesias | NULL, NULL, |
135 | ca87d03b | edgar_igl | &ser_writel, |
136 | 83fa1010 | ths | }; |
137 | 83fa1010 | ths | |
138 | f062058f | edgar_igl | static void serial_receive(void *opaque, const uint8_t *buf, int size) |
139 | 83fa1010 | ths | { |
140 | f2964260 | Edgar E. Iglesias | struct etrax_serial *s = opaque;
|
141 | f062058f | edgar_igl | |
142 | 72af9170 | Edgar E. Iglesias | s->regs[R_INTR] |= 8;
|
143 | 72af9170 | Edgar E. Iglesias | s->regs[RS_STAT_DIN] &= ~0xff;
|
144 | 72af9170 | Edgar E. Iglesias | s->regs[RS_STAT_DIN] |= (buf[0] & 0xff); |
145 | 72af9170 | Edgar E. Iglesias | s->regs[RS_STAT_DIN] |= (1 << STAT_DAV); /* dav. */ |
146 | f062058f | edgar_igl | ser_update_irq(s); |
147 | f062058f | edgar_igl | } |
148 | f062058f | edgar_igl | |
149 | f062058f | edgar_igl | static int serial_can_receive(void *opaque) |
150 | f062058f | edgar_igl | { |
151 | f2964260 | Edgar E. Iglesias | struct etrax_serial *s = opaque;
|
152 | f062058f | edgar_igl | int r;
|
153 | f062058f | edgar_igl | |
154 | f062058f | edgar_igl | /* Is the receiver enabled? */
|
155 | 72af9170 | Edgar E. Iglesias | r = s->regs[RW_REC_CTRL] & 1;
|
156 | f062058f | edgar_igl | |
157 | f062058f | edgar_igl | /* Pending rx data? */
|
158 | 72af9170 | Edgar E. Iglesias | r |= !(s->regs[R_INTR] & 8);
|
159 | f062058f | edgar_igl | return r;
|
160 | f062058f | edgar_igl | } |
161 | f062058f | edgar_igl | |
162 | f062058f | edgar_igl | static void serial_event(void *opaque, int event) |
163 | f062058f | edgar_igl | { |
164 | f062058f | edgar_igl | |
165 | f062058f | edgar_igl | } |
166 | f062058f | edgar_igl | |
167 | f062058f | edgar_igl | void etraxfs_ser_init(CPUState *env, qemu_irq *irq, CharDriverState *chr,
|
168 | f062058f | edgar_igl | target_phys_addr_t base) |
169 | f062058f | edgar_igl | { |
170 | f2964260 | Edgar E. Iglesias | struct etrax_serial *s;
|
171 | 83fa1010 | ths | int ser_regs;
|
172 | f062058f | edgar_igl | |
173 | f062058f | edgar_igl | s = qemu_mallocz(sizeof *s);
|
174 | f062058f | edgar_igl | |
175 | f062058f | edgar_igl | s->env = env; |
176 | f062058f | edgar_igl | s->irq = irq; |
177 | f062058f | edgar_igl | s->chr = chr; |
178 | f062058f | edgar_igl | |
179 | f062058f | edgar_igl | /* transmitter begins ready and idle. */
|
180 | 72af9170 | Edgar E. Iglesias | s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
|
181 | 72af9170 | Edgar E. Iglesias | s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
|
182 | f062058f | edgar_igl | |
183 | f062058f | edgar_igl | qemu_chr_add_handlers(chr, serial_can_receive, serial_receive, |
184 | f062058f | edgar_igl | serial_event, s); |
185 | f062058f | edgar_igl | |
186 | f062058f | edgar_igl | ser_regs = cpu_register_io_memory(0, ser_read, ser_write, s);
|
187 | 72af9170 | Edgar E. Iglesias | cpu_register_physical_memory (base, R_MAX * 4, ser_regs);
|
188 | 83fa1010 | ths | } |