pl011.cc (10718:4ed87af2930f) pl011.cc (10905:a6ca6831e775)
1/*
2 * Copyright (c) 2010, 2015 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 * Andreas Sandberg
42 */
43
44#include "dev/arm/pl011.hh"
45
46#include "base/trace.hh"
47#include "debug/Checkpoint.hh"
48#include "debug/Uart.hh"
49#include "dev/arm/amba_device.hh"
50#include "dev/arm/base_gic.hh"
51#include "dev/terminal.hh"
52#include "mem/packet.hh"
53#include "mem/packet_access.hh"
54#include "sim/sim_exit.hh"
55#include "params/Pl011.hh"
56
57Pl011::Pl011(const Pl011Params *p)
58 : Uart(p, 0xfff),
59 intEvent(this),
60 control(0x300), fbrd(0), ibrd(0), lcrh(0), ifls(0x12),
61 imsc(0), rawInt(0),
62 gic(p->gic), endOnEOT(p->end_on_eot), intNum(p->int_num),
63 intDelay(p->int_delay)
64{
65}
66
67Tick
68Pl011::read(PacketPtr pkt)
69{
70 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
71
72 Addr daddr = pkt->getAddr() - pioAddr;
73
74 DPRINTF(Uart, " read register %#x size=%d\n", daddr, pkt->getSize());
75
76 // use a temporary data since the uart registers are read/written with
77 // different size operations
78 //
79 uint32_t data = 0;
80
81 switch(daddr) {
82 case UART_DR:
83 data = 0;
84 if (term->dataAvailable()) {
85 data = term->in();
86 // Since we don't simulate a FIFO for incoming data, we
87 // assume it's empty and clear RXINTR and RTINTR.
88 clearInterrupts(UART_RXINTR | UART_RTINTR);
89 }
90 break;
91 case UART_FR:
92 data =
93 UART_FR_CTS | // Clear To Send
94 (!term->dataAvailable() ? UART_FR_RXFE : 0) | // RX FIFO Empty
95 UART_FR_TXFE; // TX FIFO empty
96
97 DPRINTF(Uart,
98 "Reading FR register as %#x rawInt=0x%x "
99 "imsc=0x%x maskInt=0x%x\n",
100 data, rawInt, imsc, maskInt());
101 break;
102 case UART_CR:
103 data = control;
104 break;
105 case UART_IBRD:
106 data = ibrd;
107 break;
108 case UART_FBRD:
109 data = fbrd;
110 break;
111 case UART_LCRH:
112 data = lcrh;
113 break;
114 case UART_IFLS:
115 data = ifls;
116 break;
117 case UART_IMSC:
118 data = imsc;
119 break;
120 case UART_RIS:
121 data = rawInt;
122 DPRINTF(Uart, "Reading Raw Int status as 0x%x\n", rawInt);
123 break;
124 case UART_MIS:
125 DPRINTF(Uart, "Reading Masked Int status as 0x%x\n", maskInt());
126 data = maskInt();
127 break;
128 default:
129 if (readId(pkt, AMBA_ID, pioAddr)) {
130 // Hack for variable size accesses
131 data = pkt->get<uint32_t>();
132 break;
133 }
134
135 panic("Tried to read PL011 at offset %#x that doesn't exist\n", daddr);
136 break;
137 }
138
139 switch(pkt->getSize()) {
140 case 1:
141 pkt->set<uint8_t>(data);
142 break;
143 case 2:
144 pkt->set<uint16_t>(data);
145 break;
146 case 4:
147 pkt->set<uint32_t>(data);
148 break;
149 default:
150 panic("Uart read size too big?\n");
151 break;
152 }
153
154
155 pkt->makeAtomicResponse();
156 return pioDelay;
157}
158
159Tick
160Pl011::write(PacketPtr pkt)
161{
162
163 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
164
165 Addr daddr = pkt->getAddr() - pioAddr;
166
167 DPRINTF(Uart, " write register %#x value %#x size=%d\n", daddr,
168 pkt->get<uint8_t>(), pkt->getSize());
169
170 // use a temporary data since the uart registers are read/written with
171 // different size operations
172 //
173 uint32_t data = 0;
174
175 switch(pkt->getSize()) {
176 case 1:
177 data = pkt->get<uint8_t>();
178 break;
179 case 2:
180 data = pkt->get<uint16_t>();
181 break;
182 case 4:
183 data = pkt->get<uint32_t>();
184 break;
185 default:
186 panic("Uart write size too big?\n");
187 break;
188 }
189
190
191 switch (daddr) {
192 case UART_DR:
193 if ((data & 0xFF) == 0x04 && endOnEOT)
194 exitSimLoop("UART received EOT", 0);
195
196 term->out(data & 0xFF);
197 // We're supposed to clear TXINTR when this register is
198 // written to, however. since we're also infinitely fast, we
199 // need to immediately raise it again.
200 clearInterrupts(UART_TXINTR);
201 raiseInterrupts(UART_TXINTR);
202 break;
203 case UART_CR:
204 control = data;
205 break;
206 case UART_IBRD:
207 ibrd = data;
208 break;
209 case UART_FBRD:
210 fbrd = data;
211 break;
212 case UART_LCRH:
213 lcrh = data;
214 break;
215 case UART_IFLS:
216 ifls = data;
217 break;
218 case UART_IMSC:
219 DPRINTF(Uart, "Setting interrupt mask 0x%x\n", data);
220 setInterruptMask(data);
221 break;
222
223 case UART_ICR:
224 DPRINTF(Uart, "Clearing interrupts 0x%x\n", data);
225 clearInterrupts(data);
226 break;
227 default:
228 panic("Tried to write PL011 at offset %#x that doesn't exist\n", daddr);
229 break;
230 }
231 pkt->makeAtomicResponse();
232 return pioDelay;
233}
234
235void
236Pl011::dataAvailable()
237{
238 /*@todo ignore the fifo, just say we have data now
239 * We might want to fix this, or we might not care */
240 DPRINTF(Uart, "Data available, scheduling interrupt\n");
241 raiseInterrupts(UART_RXINTR | UART_RTINTR);
242}
243
244void
245Pl011::generateInterrupt()
246{
247 DPRINTF(Uart, "Generate Interrupt: imsc=0x%x rawInt=0x%x maskInt=0x%x\n",
248 imsc, rawInt, maskInt());
249
250 if (maskInt()) {
251 gic->sendInt(intNum);
252 DPRINTF(Uart, " -- Generated\n");
253 }
254}
255
256void
257Pl011::setInterrupts(uint16_t ints, uint16_t mask)
258{
259 const bool old_ints(!!maskInt());
260
261 imsc = mask;
262 rawInt = ints;
263
264 if (!old_ints && maskInt()) {
265 if (!intEvent.scheduled())
266 schedule(intEvent, curTick() + intDelay);
267 } else if (old_ints && !maskInt()) {
268 gic->clearInt(intNum);
269 }
270}
271
272
273
274void
1/*
2 * Copyright (c) 2010, 2015 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 * Andreas Sandberg
42 */
43
44#include "dev/arm/pl011.hh"
45
46#include "base/trace.hh"
47#include "debug/Checkpoint.hh"
48#include "debug/Uart.hh"
49#include "dev/arm/amba_device.hh"
50#include "dev/arm/base_gic.hh"
51#include "dev/terminal.hh"
52#include "mem/packet.hh"
53#include "mem/packet_access.hh"
54#include "sim/sim_exit.hh"
55#include "params/Pl011.hh"
56
57Pl011::Pl011(const Pl011Params *p)
58 : Uart(p, 0xfff),
59 intEvent(this),
60 control(0x300), fbrd(0), ibrd(0), lcrh(0), ifls(0x12),
61 imsc(0), rawInt(0),
62 gic(p->gic), endOnEOT(p->end_on_eot), intNum(p->int_num),
63 intDelay(p->int_delay)
64{
65}
66
67Tick
68Pl011::read(PacketPtr pkt)
69{
70 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
71
72 Addr daddr = pkt->getAddr() - pioAddr;
73
74 DPRINTF(Uart, " read register %#x size=%d\n", daddr, pkt->getSize());
75
76 // use a temporary data since the uart registers are read/written with
77 // different size operations
78 //
79 uint32_t data = 0;
80
81 switch(daddr) {
82 case UART_DR:
83 data = 0;
84 if (term->dataAvailable()) {
85 data = term->in();
86 // Since we don't simulate a FIFO for incoming data, we
87 // assume it's empty and clear RXINTR and RTINTR.
88 clearInterrupts(UART_RXINTR | UART_RTINTR);
89 }
90 break;
91 case UART_FR:
92 data =
93 UART_FR_CTS | // Clear To Send
94 (!term->dataAvailable() ? UART_FR_RXFE : 0) | // RX FIFO Empty
95 UART_FR_TXFE; // TX FIFO empty
96
97 DPRINTF(Uart,
98 "Reading FR register as %#x rawInt=0x%x "
99 "imsc=0x%x maskInt=0x%x\n",
100 data, rawInt, imsc, maskInt());
101 break;
102 case UART_CR:
103 data = control;
104 break;
105 case UART_IBRD:
106 data = ibrd;
107 break;
108 case UART_FBRD:
109 data = fbrd;
110 break;
111 case UART_LCRH:
112 data = lcrh;
113 break;
114 case UART_IFLS:
115 data = ifls;
116 break;
117 case UART_IMSC:
118 data = imsc;
119 break;
120 case UART_RIS:
121 data = rawInt;
122 DPRINTF(Uart, "Reading Raw Int status as 0x%x\n", rawInt);
123 break;
124 case UART_MIS:
125 DPRINTF(Uart, "Reading Masked Int status as 0x%x\n", maskInt());
126 data = maskInt();
127 break;
128 default:
129 if (readId(pkt, AMBA_ID, pioAddr)) {
130 // Hack for variable size accesses
131 data = pkt->get<uint32_t>();
132 break;
133 }
134
135 panic("Tried to read PL011 at offset %#x that doesn't exist\n", daddr);
136 break;
137 }
138
139 switch(pkt->getSize()) {
140 case 1:
141 pkt->set<uint8_t>(data);
142 break;
143 case 2:
144 pkt->set<uint16_t>(data);
145 break;
146 case 4:
147 pkt->set<uint32_t>(data);
148 break;
149 default:
150 panic("Uart read size too big?\n");
151 break;
152 }
153
154
155 pkt->makeAtomicResponse();
156 return pioDelay;
157}
158
159Tick
160Pl011::write(PacketPtr pkt)
161{
162
163 assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
164
165 Addr daddr = pkt->getAddr() - pioAddr;
166
167 DPRINTF(Uart, " write register %#x value %#x size=%d\n", daddr,
168 pkt->get<uint8_t>(), pkt->getSize());
169
170 // use a temporary data since the uart registers are read/written with
171 // different size operations
172 //
173 uint32_t data = 0;
174
175 switch(pkt->getSize()) {
176 case 1:
177 data = pkt->get<uint8_t>();
178 break;
179 case 2:
180 data = pkt->get<uint16_t>();
181 break;
182 case 4:
183 data = pkt->get<uint32_t>();
184 break;
185 default:
186 panic("Uart write size too big?\n");
187 break;
188 }
189
190
191 switch (daddr) {
192 case UART_DR:
193 if ((data & 0xFF) == 0x04 && endOnEOT)
194 exitSimLoop("UART received EOT", 0);
195
196 term->out(data & 0xFF);
197 // We're supposed to clear TXINTR when this register is
198 // written to, however. since we're also infinitely fast, we
199 // need to immediately raise it again.
200 clearInterrupts(UART_TXINTR);
201 raiseInterrupts(UART_TXINTR);
202 break;
203 case UART_CR:
204 control = data;
205 break;
206 case UART_IBRD:
207 ibrd = data;
208 break;
209 case UART_FBRD:
210 fbrd = data;
211 break;
212 case UART_LCRH:
213 lcrh = data;
214 break;
215 case UART_IFLS:
216 ifls = data;
217 break;
218 case UART_IMSC:
219 DPRINTF(Uart, "Setting interrupt mask 0x%x\n", data);
220 setInterruptMask(data);
221 break;
222
223 case UART_ICR:
224 DPRINTF(Uart, "Clearing interrupts 0x%x\n", data);
225 clearInterrupts(data);
226 break;
227 default:
228 panic("Tried to write PL011 at offset %#x that doesn't exist\n", daddr);
229 break;
230 }
231 pkt->makeAtomicResponse();
232 return pioDelay;
233}
234
235void
236Pl011::dataAvailable()
237{
238 /*@todo ignore the fifo, just say we have data now
239 * We might want to fix this, or we might not care */
240 DPRINTF(Uart, "Data available, scheduling interrupt\n");
241 raiseInterrupts(UART_RXINTR | UART_RTINTR);
242}
243
244void
245Pl011::generateInterrupt()
246{
247 DPRINTF(Uart, "Generate Interrupt: imsc=0x%x rawInt=0x%x maskInt=0x%x\n",
248 imsc, rawInt, maskInt());
249
250 if (maskInt()) {
251 gic->sendInt(intNum);
252 DPRINTF(Uart, " -- Generated\n");
253 }
254}
255
256void
257Pl011::setInterrupts(uint16_t ints, uint16_t mask)
258{
259 const bool old_ints(!!maskInt());
260
261 imsc = mask;
262 rawInt = ints;
263
264 if (!old_ints && maskInt()) {
265 if (!intEvent.scheduled())
266 schedule(intEvent, curTick() + intDelay);
267 } else if (old_ints && !maskInt()) {
268 gic->clearInt(intNum);
269 }
270}
271
272
273
274void
275Pl011::serialize(std::ostream &os)
275Pl011::serialize(CheckpointOut &cp) const
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 // Preserve backwards compatibility by giving these silly names.
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 // Preserve backwards compatibility by giving these silly names.
285 paramOut(os, "imsc_serial", imsc);
286 paramOut(os, "rawInt_serial", rawInt);
285 paramOut(cp, "imsc_serial", imsc);
286 paramOut(cp, "rawInt_serial", rawInt);
287}
288
289void
287}
288
289void
290Pl011::unserialize(Checkpoint *cp, const std::string &section)
290Pl011::unserialize(CheckpointIn &cp)
291{
292 DPRINTF(Checkpoint, "Unserializing Arm PL011\n");
293
294 UNSERIALIZE_SCALAR(control);
295 UNSERIALIZE_SCALAR(fbrd);
296 UNSERIALIZE_SCALAR(ibrd);
297 UNSERIALIZE_SCALAR(lcrh);
298 UNSERIALIZE_SCALAR(ifls);
299
300 // Preserve backwards compatibility by giving these silly names.
291{
292 DPRINTF(Checkpoint, "Unserializing Arm PL011\n");
293
294 UNSERIALIZE_SCALAR(control);
295 UNSERIALIZE_SCALAR(fbrd);
296 UNSERIALIZE_SCALAR(ibrd);
297 UNSERIALIZE_SCALAR(lcrh);
298 UNSERIALIZE_SCALAR(ifls);
299
300 // Preserve backwards compatibility by giving these silly names.
301 paramIn(cp, section, "imsc_serial", imsc);
302 paramIn(cp, section, "rawInt_serial", rawInt);
301 paramIn(cp, "imsc_serial", imsc);
302 paramIn(cp, "rawInt_serial", rawInt);
303}
304
305Pl011 *
306Pl011Params::create()
307{
308 return new Pl011(this);
309}
303}
304
305Pl011 *
306Pl011Params::create()
307{
308 return new Pl011(this);
309}