Merge zizzer.eecs.umich.edu:/bk/linux
[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/functional_mem/memory_control.hh"
26 #include "sim/builder.hh"
27 #include "targetarch/ev5.hh"
28
29 using namespace std;
30
31 #define CONS_INT_TX 0x01 // interrupt enable / state bits
32 #define CONS_INT_RX 0x02
33
34 TsunamiUart::TsunamiUart(const string &name, SimConsole *c, Addr a,
35 MemoryController *mmu)
36 : FunctionalMemory(name), addr(a), cons(c), status_store(0),
37 valid_char(false)
38 {
39 mmu->add_child(this, Range<Addr>(addr, addr + size));
40
41 IER = 0;
42 }
43
44 Fault
45 TsunamiUart::read(MemReqPtr &req, uint8_t *data)
46 {
47 Addr daddr = req->paddr - (addr & PA_IMPL_MASK);
48 DPRINTF(TsunamiUart, " read register %#x\n", daddr);
49
50 switch (req->size) {
51 case sizeof(uint64_t):
52 *(uint64_t *)data = 0;
53 break;
54 case sizeof(uint32_t):
55 *(uint32_t *)data = 0;
56 break;
57 case sizeof(uint16_t):
58 *(uint16_t *)data = 0;
59 break;
60 case sizeof(uint8_t):
61 *(uint8_t *)data = 0;
62 break;
63 }
64
65 switch (daddr) {
66 case 0x5: // Status Register
67 {
68 int status = cons->intStatus();
69 if (!valid_char) {
70 valid_char = cons->in(next_char);
71 if (!valid_char)
72 status &= ~CONS_INT_RX;
73 } else {
74 status |= CONS_INT_RX;
75 }
76
77 if (status_store == 3) {
78 // RR3 stuff? Don't really understand it, btw
79 status_store = 0;
80 if (status & CONS_INT_TX) {
81 *data = (1 << 4);
82 return No_Fault;
83 } else if (status & CONS_INT_RX) {
84 *data = (1 << 5);
85 return No_Fault;
86 } else {
87 DPRINTF(TsunamiUart, "spurious read\n");
88 return No_Fault;
89 }
90 } else {
91 int reg = (1 << 2) | (1 << 5) | (1 << 6);
92 if (status & CONS_INT_RX)
93 reg |= (1 << 0);
94 *data = reg;
95 return No_Fault;
96 }
97 break;
98 }
99
100 case 0x0: // Data register (RX)
101 // if (!valid_char)
102 // panic("Invalid character");
103
104 DPRINTF(TsunamiUart, "read data register \'%c\' %#02x\n",
105 isprint(next_char) ? next_char : ' ', next_char);
106
107 *data = next_char;
108 valid_char = false;
109 return No_Fault;
110
111 case 0x1: // Interrupt Enable Register
112 // This is the lovely way linux checks there is actually a serial
113 // port at the desired address
114 if (IER == 0)
115 *data = 0;
116 else if (IER == 0x0F)
117 *data = 0x0F;
118 else
119 *data = 0;
120 return No_Fault;
121 case 0x2:
122 *data = 0; // This means a 8250 serial port, do we want a 16550?
123 return No_Fault;
124 }
125 *data = 0;
126 // panic("%s: read daddr=%#x type=read *data=%#x\n", name(), daddr, *data);
127
128 return No_Fault;
129 }
130
131 Fault
132 TsunamiUart::write(MemReqPtr &req, const uint8_t *data)
133 {
134 Addr daddr = req->paddr - (addr & PA_IMPL_MASK);
135
136 DPRINTF(TsunamiUart, " write register %#x value %#x\n", daddr, *(uint8_t*)data);
137 switch (daddr) {
138 case 0x3:
139 status_store = *data;
140 switch (*data) {
141 case 0x03: // going to read RR3
142 return No_Fault;
143
144 case 0x28: // Ack of TX
145 {
146 if ((cons->intStatus() & CONS_INT_TX) == 0)
147 panic("Ack of transmit, though there was no interrupt");
148
149 cons->clearInt(CONS_INT_TX);
150 return No_Fault;
151 }
152
153 case 0x00:
154 case 0x01:
155 case 0x12:
156 // going to write data???
157 return No_Fault;
158
159 default:
160 DPRINTF(TsunamiUart, "writing status register %#x \n",
161 *(uint8_t *)data);
162 return No_Fault;
163 }
164
165 case 0x0: // Data register (TX)
166 cons->out(*(uint64_t *)data);
167 return No_Fault;
168 case 0x1: // DLM
169 DPRINTF(TsunamiUart, "writing to DLM/IER %#x\n", *(uint8_t*)data);
170 IER = *(uint8_t*)data;
171 return No_Fault;
172 case 0x4: // MCR
173 DPRINTF(TsunamiUart, "writing to MCR %#x\n", *(uint8_t*)data);
174 return No_Fault;
175
176 }
177
178 return No_Fault;
179 }
180
181 void
182 TsunamiUart::serialize(ostream &os)
183 {
184 SERIALIZE_SCALAR(status_store);
185 SERIALIZE_SCALAR(next_char);
186 SERIALIZE_SCALAR(valid_char);
187 SERIALIZE_SCALAR(IER);
188 }
189
190 void
191 TsunamiUart::unserialize(Checkpoint *cp, const std::string &section)
192 {
193 UNSERIALIZE_SCALAR(status_store);
194 UNSERIALIZE_SCALAR(next_char);
195 UNSERIALIZE_SCALAR(valid_char);
196 UNSERIALIZE_SCALAR(IER);
197 }
198
199 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiUart)
200
201 SimObjectParam<SimConsole *> console;
202 SimObjectParam<MemoryController *> mmu;
203 Param<Addr> addr;
204
205 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiUart)
206
207 BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiUart)
208
209 INIT_PARAM(console, "The console"),
210 INIT_PARAM(mmu, "Memory Controller"),
211 INIT_PARAM(addr, "Device Address")
212
213 END_INIT_SIM_OBJECT_PARAMS(TsunamiUart)
214
215 CREATE_SIM_OBJECT(TsunamiUart)
216 {
217 return new TsunamiUart(getInstanceName(), console, addr, mmu);
218 }
219
220 REGISTER_SIM_OBJECT("TsunamiUart", TsunamiUart)