pl011.cc (7733:08d6a773d1b6) pl011.cc (7823:dac01f14f20f)
1/*
2 * Copyright (c) 2010 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Ali Saidi
41 */
42
43#include "base/trace.hh"
44#include "dev/arm/amba_device.hh"
45#include "dev/arm/gic.hh"
46#include "dev/arm/pl011.hh"
47#include "dev/terminal.hh"
48#include "mem/packet.hh"
49#include "mem/packet_access.hh"
50#include "sim/sim_exit.hh"
51
52Pl011::Pl011(const Params *p)
53 : Uart(p), control(0x300), fbrd(0), ibrd(0), lcrh(0), ifls(0x12), imsc(0),
54 rawInt(0), maskInt(0), intNum(p->int_num), gic(p->gic),
55 endOnEOT(p->end_on_eot), intDelay(p->int_delay), intEvent(this)
56{
57 pioSize = 0xfff;
58}
59
60Tick
61Pl011::read(PacketPtr pkt)
62{
63 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
64
65 Addr daddr = pkt->getAddr() - pioAddr;
66 pkt->allocate();
67
68 DPRINTF(Uart, " read register %#x size=%d\n", daddr, pkt->getSize());
69
70 // use a temporary data since the uart registers are read/written with
71 // different size operations
72 //
73 uint32_t data = 0;
74
75 switch(daddr) {
76 case UART_DR:
77 data = 0;
78 if (term->dataAvailable())
79 data = term->in();
80 break;
81 case UART_FR:
82 // For now we're infintely fast, so TX is never full, always empty,
83 // always clear to send
84 data = UART_FR_TXFE | UART_FR_CTS;
85 if (!term->dataAvailable())
86 data |= UART_FR_RXFE;
87 DPRINTF(Uart, "Reading FR register as %#x rawInt=0x%x imsc=0x%x maskInt=0x%x\n",
88 data, rawInt, imsc, maskInt);
89 break;
90 case UART_CR:
91 data = control;
92 break;
93 case UART_IBRD:
94 data = ibrd;
95 break;
96 case UART_FBRD:
97 data = fbrd;
98 break;
99 case UART_LCRH:
100 data = lcrh;
101 break;
102 case UART_IFLS:
103 data = ifls;
104 break;
105 case UART_IMSC:
106 data = imsc;
107 break;
108 case UART_RIS:
109 data = rawInt;
110 DPRINTF(Uart, "Reading Raw Int status as 0x%x\n", rawInt);
111 break;
112 case UART_MIS:
113 DPRINTF(Uart, "Reading Masked Int status as 0x%x\n", rawInt);
114 data = maskInt;
115 break;
116 default:
117 if (AmbaDev::readId(pkt, AMBA_ID, pioAddr)) {
118 // Hack for variable size accesses
119 data = pkt->get<uint32_t>();
120 break;
121 }
122
123 panic("Tried to read PL011 at offset %#x that doesn't exist\n", daddr);
124 break;
125 }
126
127 switch(pkt->getSize()) {
128 case 1:
129 pkt->set<uint8_t>(data);
130 break;
131 case 2:
132 pkt->set<uint16_t>(data);
133 break;
134 case 4:
135 pkt->set<uint32_t>(data);
136 break;
137 default:
138 panic("Uart read size too big?\n");
139 break;
140 }
141
142
143 pkt->makeAtomicResponse();
144 return pioDelay;
145}
146
147Tick
148Pl011::write(PacketPtr pkt)
149{
150
151 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
152
153 Addr daddr = pkt->getAddr() - pioAddr;
154
155 DPRINTF(Uart, " write register %#x value %#x size=%d\n", daddr,
156 pkt->get<uint8_t>(), pkt->getSize());
157
158 // use a temporary data since the uart registers are read/written with
159 // different size operations
160 //
161 uint32_t data = 0;
162
163 switch(pkt->getSize()) {
164 case 1:
165 data = pkt->get<uint8_t>();
166 break;
167 case 2:
168 data = pkt->get<uint16_t>();
169 break;
170 case 4:
171 data = pkt->get<uint32_t>();
172 break;
173 default:
174 panic("Uart write size too big?\n");
175 break;
176 }
177
178
179 switch (daddr) {
180 case UART_DR:
181 if ((data & 0xFF) == 0x04 && endOnEOT)
182 exitSimLoop("UART received EOT", 0);
183
184 term->out(data & 0xFF);
185
186 if (imsc.txim) {
187 DPRINTF(Uart, "TX int enabled, scheduling interruptt\n");
188 rawInt.txim = 1;
189 if (!intEvent.scheduled())
1/*
2 * Copyright (c) 2010 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Ali Saidi
41 */
42
43#include "base/trace.hh"
44#include "dev/arm/amba_device.hh"
45#include "dev/arm/gic.hh"
46#include "dev/arm/pl011.hh"
47#include "dev/terminal.hh"
48#include "mem/packet.hh"
49#include "mem/packet_access.hh"
50#include "sim/sim_exit.hh"
51
52Pl011::Pl011(const Params *p)
53 : Uart(p), control(0x300), fbrd(0), ibrd(0), lcrh(0), ifls(0x12), imsc(0),
54 rawInt(0), maskInt(0), intNum(p->int_num), gic(p->gic),
55 endOnEOT(p->end_on_eot), intDelay(p->int_delay), intEvent(this)
56{
57 pioSize = 0xfff;
58}
59
60Tick
61Pl011::read(PacketPtr pkt)
62{
63 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
64
65 Addr daddr = pkt->getAddr() - pioAddr;
66 pkt->allocate();
67
68 DPRINTF(Uart, " read register %#x size=%d\n", daddr, pkt->getSize());
69
70 // use a temporary data since the uart registers are read/written with
71 // different size operations
72 //
73 uint32_t data = 0;
74
75 switch(daddr) {
76 case UART_DR:
77 data = 0;
78 if (term->dataAvailable())
79 data = term->in();
80 break;
81 case UART_FR:
82 // For now we're infintely fast, so TX is never full, always empty,
83 // always clear to send
84 data = UART_FR_TXFE | UART_FR_CTS;
85 if (!term->dataAvailable())
86 data |= UART_FR_RXFE;
87 DPRINTF(Uart, "Reading FR register as %#x rawInt=0x%x imsc=0x%x maskInt=0x%x\n",
88 data, rawInt, imsc, maskInt);
89 break;
90 case UART_CR:
91 data = control;
92 break;
93 case UART_IBRD:
94 data = ibrd;
95 break;
96 case UART_FBRD:
97 data = fbrd;
98 break;
99 case UART_LCRH:
100 data = lcrh;
101 break;
102 case UART_IFLS:
103 data = ifls;
104 break;
105 case UART_IMSC:
106 data = imsc;
107 break;
108 case UART_RIS:
109 data = rawInt;
110 DPRINTF(Uart, "Reading Raw Int status as 0x%x\n", rawInt);
111 break;
112 case UART_MIS:
113 DPRINTF(Uart, "Reading Masked Int status as 0x%x\n", rawInt);
114 data = maskInt;
115 break;
116 default:
117 if (AmbaDev::readId(pkt, AMBA_ID, pioAddr)) {
118 // Hack for variable size accesses
119 data = pkt->get<uint32_t>();
120 break;
121 }
122
123 panic("Tried to read PL011 at offset %#x that doesn't exist\n", daddr);
124 break;
125 }
126
127 switch(pkt->getSize()) {
128 case 1:
129 pkt->set<uint8_t>(data);
130 break;
131 case 2:
132 pkt->set<uint16_t>(data);
133 break;
134 case 4:
135 pkt->set<uint32_t>(data);
136 break;
137 default:
138 panic("Uart read size too big?\n");
139 break;
140 }
141
142
143 pkt->makeAtomicResponse();
144 return pioDelay;
145}
146
147Tick
148Pl011::write(PacketPtr pkt)
149{
150
151 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
152
153 Addr daddr = pkt->getAddr() - pioAddr;
154
155 DPRINTF(Uart, " write register %#x value %#x size=%d\n", daddr,
156 pkt->get<uint8_t>(), pkt->getSize());
157
158 // use a temporary data since the uart registers are read/written with
159 // different size operations
160 //
161 uint32_t data = 0;
162
163 switch(pkt->getSize()) {
164 case 1:
165 data = pkt->get<uint8_t>();
166 break;
167 case 2:
168 data = pkt->get<uint16_t>();
169 break;
170 case 4:
171 data = pkt->get<uint32_t>();
172 break;
173 default:
174 panic("Uart write size too big?\n");
175 break;
176 }
177
178
179 switch (daddr) {
180 case UART_DR:
181 if ((data & 0xFF) == 0x04 && endOnEOT)
182 exitSimLoop("UART received EOT", 0);
183
184 term->out(data & 0xFF);
185
186 if (imsc.txim) {
187 DPRINTF(Uart, "TX int enabled, scheduling interruptt\n");
188 rawInt.txim = 1;
189 if (!intEvent.scheduled())
190 schedule(intEvent, curTick + intDelay);
190 schedule(intEvent, curTick() + intDelay);
191 }
192
193 break;
194 case UART_CR:
195 control = data;
196 break;
197 case UART_IBRD:
198 ibrd = data;
199 break;
200 case UART_FBRD:
201 fbrd = data;
202 break;
203 case UART_LCRH:
204 lcrh = data;
205 break;
206 case UART_IFLS:
207 ifls = data;
208 break;
209 case UART_IMSC:
210 imsc = data;
211
212 if (imsc.rimim || imsc.ctsmim || imsc.dcdmim || imsc.dsrmim
213 || imsc.feim || imsc.peim || imsc.beim || imsc.oeim || imsc.rsvd)
214 panic("Unknown interrupt enabled\n");
215
216 if (imsc.txim) {
217 DPRINTF(Uart, "Writing to IMSC: TX int enabled, scheduling interruptt\n");
218 rawInt.txim = 1;
219 if (!intEvent.scheduled())
191 }
192
193 break;
194 case UART_CR:
195 control = data;
196 break;
197 case UART_IBRD:
198 ibrd = data;
199 break;
200 case UART_FBRD:
201 fbrd = data;
202 break;
203 case UART_LCRH:
204 lcrh = data;
205 break;
206 case UART_IFLS:
207 ifls = data;
208 break;
209 case UART_IMSC:
210 imsc = data;
211
212 if (imsc.rimim || imsc.ctsmim || imsc.dcdmim || imsc.dsrmim
213 || imsc.feim || imsc.peim || imsc.beim || imsc.oeim || imsc.rsvd)
214 panic("Unknown interrupt enabled\n");
215
216 if (imsc.txim) {
217 DPRINTF(Uart, "Writing to IMSC: TX int enabled, scheduling interruptt\n");
218 rawInt.txim = 1;
219 if (!intEvent.scheduled())
220 schedule(intEvent, curTick + intDelay);
220 schedule(intEvent, curTick() + intDelay);
221 }
222
223 break;
224
225 case UART_ICR:
226 DPRINTF(Uart, "Clearing interrupts 0x%x\n", data);
227 rawInt = rawInt & ~data;
228 maskInt = rawInt & imsc;
229
230 DPRINTF(Uart, " -- Masked interrupts 0x%x\n", maskInt);
231
232 if (!maskInt)
233 gic->clearInt(intNum);
234
235 break;
236 default:
237 panic("Tried to write PL011 at offset %#x that doesn't exist\n", daddr);
238 break;
239 }
240 pkt->makeAtomicResponse();
241 return pioDelay;
242}
243
244void
245Pl011::dataAvailable()
246{
247 /*@todo ignore the fifo, just say we have data now
248 * We might want to fix this, or we might not care */
249 rawInt.rxim = 1;
250 rawInt.rtim = 1;
251
252 DPRINTF(Uart, "Data available, scheduling interrupt\n");
253
254 if (!intEvent.scheduled())
221 }
222
223 break;
224
225 case UART_ICR:
226 DPRINTF(Uart, "Clearing interrupts 0x%x\n", data);
227 rawInt = rawInt & ~data;
228 maskInt = rawInt & imsc;
229
230 DPRINTF(Uart, " -- Masked interrupts 0x%x\n", maskInt);
231
232 if (!maskInt)
233 gic->clearInt(intNum);
234
235 break;
236 default:
237 panic("Tried to write PL011 at offset %#x that doesn't exist\n", daddr);
238 break;
239 }
240 pkt->makeAtomicResponse();
241 return pioDelay;
242}
243
244void
245Pl011::dataAvailable()
246{
247 /*@todo ignore the fifo, just say we have data now
248 * We might want to fix this, or we might not care */
249 rawInt.rxim = 1;
250 rawInt.rtim = 1;
251
252 DPRINTF(Uart, "Data available, scheduling interrupt\n");
253
254 if (!intEvent.scheduled())
255 schedule(intEvent, curTick + intDelay);
255 schedule(intEvent, curTick() + intDelay);
256}
257
258void
259Pl011::generateInterrupt()
260{
261 DPRINTF(Uart, "Generate Interrupt: imsc=0x%x rawInt=0x%x maskInt=0x%x\n",
262 imsc, rawInt, maskInt);
263 maskInt = imsc & rawInt;
264
265 if (maskInt.rxim || maskInt.rtim || maskInt.txim) {
266 gic->sendInt(intNum);
267 DPRINTF(Uart, " -- Generated\n");
268 }
269
270}
271
272
273
274void
275Pl011::serialize(std::ostream &os)
276{
277 DPRINTF(Checkpoint, "Serializing Arm PL011\n");
278 SERIALIZE_SCALAR(control);
279 SERIALIZE_SCALAR(fbrd);
280 SERIALIZE_SCALAR(ibrd);
281 SERIALIZE_SCALAR(lcrh);
282 SERIALIZE_SCALAR(ifls);
283
284 uint16_t imsc_serial = imsc;
285 SERIALIZE_SCALAR(imsc_serial);
286
287 uint16_t rawInt_serial = rawInt;
288 SERIALIZE_SCALAR(rawInt_serial);
289
290 uint16_t maskInt_serial = maskInt;
291 SERIALIZE_SCALAR(maskInt_serial);
292
293 SERIALIZE_SCALAR(endOnEOT);
294 SERIALIZE_SCALAR(intDelay);
295}
296
297void
298Pl011::unserialize(Checkpoint *cp, const std::string &section)
299{
300 DPRINTF(Checkpoint, "Unserializing Arm PL011\n");
301
302 UNSERIALIZE_SCALAR(control);
303 UNSERIALIZE_SCALAR(fbrd);
304 UNSERIALIZE_SCALAR(ibrd);
305 UNSERIALIZE_SCALAR(lcrh);
306 UNSERIALIZE_SCALAR(ifls);
307
308 uint16_t imsc_serial;
309 UNSERIALIZE_SCALAR(imsc_serial);
310 imsc = imsc_serial;
311
312 uint16_t rawInt_serial;
313 UNSERIALIZE_SCALAR(rawInt_serial);
314 rawInt = rawInt_serial;
315
316 uint16_t maskInt_serial;
317 UNSERIALIZE_SCALAR(maskInt_serial);
318 maskInt = maskInt_serial;
319
320 UNSERIALIZE_SCALAR(endOnEOT);
321 UNSERIALIZE_SCALAR(intDelay);
322}
323
324Pl011 *
325Pl011Params::create()
326{
327 return new Pl011(this);
328}
256}
257
258void
259Pl011::generateInterrupt()
260{
261 DPRINTF(Uart, "Generate Interrupt: imsc=0x%x rawInt=0x%x maskInt=0x%x\n",
262 imsc, rawInt, maskInt);
263 maskInt = imsc & rawInt;
264
265 if (maskInt.rxim || maskInt.rtim || maskInt.txim) {
266 gic->sendInt(intNum);
267 DPRINTF(Uart, " -- Generated\n");
268 }
269
270}
271
272
273
274void
275Pl011::serialize(std::ostream &os)
276{
277 DPRINTF(Checkpoint, "Serializing Arm PL011\n");
278 SERIALIZE_SCALAR(control);
279 SERIALIZE_SCALAR(fbrd);
280 SERIALIZE_SCALAR(ibrd);
281 SERIALIZE_SCALAR(lcrh);
282 SERIALIZE_SCALAR(ifls);
283
284 uint16_t imsc_serial = imsc;
285 SERIALIZE_SCALAR(imsc_serial);
286
287 uint16_t rawInt_serial = rawInt;
288 SERIALIZE_SCALAR(rawInt_serial);
289
290 uint16_t maskInt_serial = maskInt;
291 SERIALIZE_SCALAR(maskInt_serial);
292
293 SERIALIZE_SCALAR(endOnEOT);
294 SERIALIZE_SCALAR(intDelay);
295}
296
297void
298Pl011::unserialize(Checkpoint *cp, const std::string &section)
299{
300 DPRINTF(Checkpoint, "Unserializing Arm PL011\n");
301
302 UNSERIALIZE_SCALAR(control);
303 UNSERIALIZE_SCALAR(fbrd);
304 UNSERIALIZE_SCALAR(ibrd);
305 UNSERIALIZE_SCALAR(lcrh);
306 UNSERIALIZE_SCALAR(ifls);
307
308 uint16_t imsc_serial;
309 UNSERIALIZE_SCALAR(imsc_serial);
310 imsc = imsc_serial;
311
312 uint16_t rawInt_serial;
313 UNSERIALIZE_SCALAR(rawInt_serial);
314 rawInt = rawInt_serial;
315
316 uint16_t maskInt_serial;
317 UNSERIALIZE_SCALAR(maskInt_serial);
318 maskInt = maskInt_serial;
319
320 UNSERIALIZE_SCALAR(endOnEOT);
321 UNSERIALIZE_SCALAR(intDelay);
322}
323
324Pl011 *
325Pl011Params::create()
326{
327 return new Pl011(this);
328}