manual merge of linux_system and makefile
[gem5.git] / dev / tsunami_uart.cc
1 /* $Id$ */
2
3 /* @file
4 * Tsunami UART
5 */
6
7 /*
8 * Copyright (C) 1998 by the Board of Trustees
9 * of Leland Stanford Junior University.
10 * Copyright (C) 1998 Digital Equipment Corporation
11 *
12 * This file is part of the SimOS distribution.
13 * See LICENSE file for terms of the license.
14 *
15 */
16
17 #include <string>
18 #include <vector>
19
20 #include "base/inifile.hh"
21 #include "base/str.hh" // for to_number
22 #include "base/trace.hh"
23 #include "dev/console.hh"
24 #include "dev/tsunami_uart.hh"
25 #include "mem/bus/bus.hh"
26 #include "mem/bus/pio_interface.hh"
27 #include "mem/bus/pio_interface_impl.hh"
28 #include "mem/functional_mem/memory_control.hh"
29 #include "sim/builder.hh"
30 #include "targetarch/ev5.hh"
31
32 using namespace std;
33
34 #define CONS_INT_TX 0x01 // interrupt enable / state bits
35 #define CONS_INT_RX 0x02
36
37 TsunamiUart::TsunamiUart(const string &name, SimConsole *c,
38 MemoryController *mmu, Addr a,
39 HierParams *hier, Bus *bus)
40 : PioDevice(name), addr(a), cons(c), status_store(0), valid_char(false)
41 {
42 mmu->add_child(this, Range<Addr>(addr, addr + size));
43
44 if (bus) {
45 pioInterface = newPioInterface(name, hier, bus, this,
46 &TsunamiUart::cacheAccess);
47 pioInterface->addAddrRange(addr, addr + size - 1);
48 }
49
50 IER = 0;
51 }
52
53 Fault
54 TsunamiUart::read(MemReqPtr &req, uint8_t *data)
55 {
56 Addr daddr = req->paddr - (addr & PA_IMPL_MASK);
57 DPRINTF(TsunamiUart, " read register %#x\n", daddr);
58
59 switch (req->size) {
60 case sizeof(uint64_t):
61 *(uint64_t *)data = 0;
62 break;
63 case sizeof(uint32_t):
64 *(uint32_t *)data = 0;
65 break;
66 case sizeof(uint16_t):
67 *(uint16_t *)data = 0;
68 break;
69 case sizeof(uint8_t):
70 *(uint8_t *)data = 0;
71 break;
72 }
73
74
75 switch(daddr) {
76 case 0x5: // Status Register
77 {
78 int status = cons->intStatus();
79 if (!valid_char) {
80 valid_char = cons->in(next_char);
81 if (!valid_char)
82 status &= ~CONS_INT_RX;
83 } else {
84 status |= CONS_INT_RX;
85 }
86
87 if (status_store == 3) {
88 // RR3 stuff? Don't really understand it, btw
89 status_store = 0;
90 if (status & CONS_INT_TX) {
91 *data = (1 << 4);
92 return No_Fault;
93 } else if (status & CONS_INT_RX) {
94 *data = (1 << 5);
95 return No_Fault;
96 } else {
97 DPRINTF(TsunamiUart, "spurious read\n");
98 return No_Fault;
99 }
100 } else {
101 int reg = (1 << 2) | (1 << 5) | (1 << 6);
102 if (status & CONS_INT_RX)
103 reg |= (1 << 0);
104 *data = reg;
105 return No_Fault;
106 }
107 break;
108 }
109
110 case 0x0: // Data register (RX)
111 // if (!valid_char)
112 // panic("Invalid character");
113
114 DPRINTF(TsunamiUart, "read data register \'%c\' %#02x\n",
115 isprint(next_char) ? next_char : ' ', next_char);
116
117 *data = next_char;
118 valid_char = false;
119 return No_Fault;
120
121 case 0x1: // Interrupt Enable Register
122 // This is the lovely way linux checks there is actually a serial
123 // port at the desired address
124 if (IER == 0)
125 *data = 0;
126 else if (IER == 0x0F)
127 *data = 0x0F;
128 else
129 *data = 0;
130 return No_Fault;
131 case 0x2:
132 *data = 0; // This means a 8250 serial port, do we want a 16550?
133 return No_Fault;
134 }
135 *data = 0;
136 // panic("%s: read daddr=%#x type=read *data=%#x\n", name(), daddr, *data);
137
138 return No_Fault;
139 }
140
141 Fault
142 TsunamiUart::write(MemReqPtr &req, const uint8_t *data)
143 {
144 Addr daddr = req->paddr - (addr & PA_IMPL_MASK);
145
146 DPRINTF(TsunamiUart, " write register %#x value %#x\n", daddr, *(uint8_t*)data);
147
148 switch (daddr) {
149 case 0x3:
150 status_store = *data;
151 switch (*data) {
152 case 0x03: // going to read RR3
153 return No_Fault;
154
155 case 0x28: // Ack of TX
156 {
157 if ((cons->intStatus() & CONS_INT_TX) == 0)
158 panic("Ack of transmit, though there was no interrupt");
159
160 cons->clearInt(CONS_INT_TX);
161 return No_Fault;
162 }
163
164 case 0x00:
165 case 0x01:
166 case 0x12:
167 // going to write data???
168 return No_Fault;
169
170 default:
171 DPRINTF(TsunamiUart, "writing status register %#x \n",
172 *(uint8_t *)data);
173 return No_Fault;
174 }
175
176 case 0x0: // Data register (TX)
177 char ourchar;
178 ourchar = *(uint64_t *)data;
179 if ((isprint(ourchar) || iscntrl(ourchar)) && (ourchar != 0x0C))
180 cons->out(ourchar);
181 if (UART_IER_THRI & IER)
182 cons->setInt(CONS_INT_TX);
183 return No_Fault;
184 break;
185 case 0x1: // DLM
186 DPRINTF(TsunamiUart, "writing to DLM/IER %#x\n", *(uint8_t*)data);
187 IER = *(uint8_t*)data;
188 if (UART_IER_THRI & IER)
189 cons->setInt(CONS_INT_TX);
190 return No_Fault;
191 break;
192 case 0x4: // MCR
193 DPRINTF(TsunamiUart, "writing to MCR %#x\n", *(uint8_t*)data);
194 return No_Fault;
195
196 }
197
198 return No_Fault;
199 }
200
201 Tick
202 TsunamiUart::cacheAccess(MemReqPtr &req)
203 {
204 return curTick + 1000;
205 }
206
207 void
208 TsunamiUart::serialize(ostream &os)
209 {
210 SERIALIZE_SCALAR(status_store);
211 SERIALIZE_SCALAR(next_char);
212 SERIALIZE_SCALAR(valid_char);
213 SERIALIZE_SCALAR(IER);
214 }
215
216 void
217 TsunamiUart::unserialize(Checkpoint *cp, const std::string &section)
218 {
219 UNSERIALIZE_SCALAR(status_store);
220 UNSERIALIZE_SCALAR(next_char);
221 UNSERIALIZE_SCALAR(valid_char);
222 UNSERIALIZE_SCALAR(IER);
223 }
224
225 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiUart)
226
227 SimObjectParam<SimConsole *> console;
228 SimObjectParam<MemoryController *> mmu;
229 Param<Addr> addr;
230 SimObjectParam<Bus*> io_bus;
231 SimObjectParam<HierParams *> hier;
232
233
234 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiUart)
235
236 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiUart)
237
238 INIT_PARAM(console, "The console"),
239 INIT_PARAM(mmu, "Memory Controller"),
240 INIT_PARAM(addr, "Device Address"),
241 INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL),
242 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams)
243
244 END_INIT_SIM_OBJECT_PARAMS(TsunamiUart)
245
246 CREATE_SIM_OBJECT(TsunamiUart)
247 {
248 return new TsunamiUart(getInstanceName(), console, mmu, addr, hier, io_bus);
249 }
250
251 REGISTER_SIM_OBJECT("TsunamiUart", TsunamiUart)