/[dynamips]/upstream/dynamips-0.2.6-RC1/dev_ns16552.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/dynamips-0.2.6-RC1/dev_ns16552.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations)
Sat Oct 6 16:03:58 2007 UTC (12 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 6663 byte(s)
import dynamips-0.2.6-RC1

1 /*
2 * Cisco 3600 simulation platform.
3 * Copyright (c) 2006 Christophe Fillot (cf@utc.fr)
4 *
5 * NS16552 DUART.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <sys/types.h>
13
14 #include <termios.h>
15 #include <fcntl.h>
16 #include <pthread.h>
17
18 #include "ptask.h"
19 #include "mips64.h"
20 #include "dynamips.h"
21 #include "memory.h"
22 #include "device.h"
23 #include "dev_vtty.h"
24
25 /* Debugging flags */
26 #define DEBUG_UNKNOWN 1
27 #define DEBUG_ACCESS 0
28
29 /* Interrupt Enable Register (IER) */
30 #define IER_ERXRDY 0x1
31 #define IER_ETXRDY 0x2
32
33 /* Interrupt Identification Register */
34 #define IIR_NPENDING 0x01 /* 0: irq pending, 1: no irq pending */
35 #define IIR_TXRDY 0x02
36 #define IIR_RXRDY 0x04
37
38 /* Line Status Register (LSR) */
39 #define LSR_RXRDY 0x01
40 #define LSR_TXRDY 0x20
41 #define LSR_TXEMPTY 0x40
42
43 /* UART channel */
44 struct ns16552_channel {
45 u_int ier,output;
46 vtty_t *vtty;
47 };
48
49 /* NS16552 structure */
50 struct ns16552_data {
51 vm_obj_t vm_obj;
52 struct vdevice dev;
53 vm_instance_t *vm;
54 u_int irq;
55
56 /* Register offset divisor */
57 u_int reg_div;
58
59 /* Periodic task to trigger DUART IRQ */
60 ptask_id_t tid;
61
62 struct ns16552_channel channel[2];
63 u_int duart_irq_seq;
64 };
65
66 /* Console port input */
67 static void tty_con_input(vtty_t *vtty)
68 {
69 struct ns16552_data *d = vtty->priv_data;
70
71 if (d->channel[0].ier & IER_ERXRDY)
72 vm_set_irq(d->vm,d->irq);
73 }
74
75 /* AUX port input */
76 static void tty_aux_input(vtty_t *vtty)
77 {
78 struct ns16552_data *d = vtty->priv_data;
79
80 if (d->channel[1].ier & IER_ERXRDY)
81 vm_set_irq(d->vm,d->irq);
82 }
83
84 /* IRQ trickery for Console and AUX ports */
85 static int tty_trigger_dummy_irq(struct ns16552_data *d,void *arg)
86 {
87 d->duart_irq_seq++;
88
89 if (d->duart_irq_seq == 2) {
90 if (d->channel[0].ier & IER_ETXRDY) {
91 d->channel[0].output = TRUE;
92 vm_set_irq(d->vm,d->irq);
93 }
94
95 #if 0
96 if (d->channel[1].ier & IER_ETXRDY) {
97 d->channel[1].output = TRUE;
98 vm_set_irq(d->vm,d->irq);
99 }
100 #endif
101
102 d->duart_irq_seq = 0;
103 }
104
105 return(0);
106 }
107
108 /*
109 * dev_ns16552_access()
110 */
111 void *dev_ns16552_access(cpu_mips_t *cpu,struct vdevice *dev,m_uint32_t offset,
112 u_int op_size,u_int op_type,m_uint64_t *data)
113 {
114 struct ns16552_data *d = dev->priv_data;
115 int channel = 0;
116 u_char odata;
117
118 if (op_type == MTS_READ)
119 *data = 0;
120
121 #if DEBUG_ACCESS
122 if (op_type == MTS_READ) {
123 cpu_log(cpu,"NS16552","read from 0x%x, pc=0x%llx, ra=0x%llx\n",
124 offset,cpu->pc,cpu->gpr[MIPS_GPR_RA]);
125 } else {
126 cpu_log(cpu,"NS16552","write to 0x%x, value=0x%llx, pc=0x%llx\n",
127 offset,*data,cpu->pc);
128 }
129 #endif
130
131 offset >>= d->reg_div;
132
133 if (offset >= 0x08)
134 channel = 1;
135
136 switch(offset) {
137 /* Receiver Buffer Reg. (RBR) / Transmitting Holding Reg. (THR) */
138 case 0x00:
139 case 0x08:
140 if (op_type == MTS_WRITE) {
141 vtty_put_char(d->channel[channel].vtty,(char)*data);
142
143 if (d->channel[channel].ier & IER_ETXRDY)
144 vm_set_irq(d->vm,d->irq);
145
146 d->channel[channel].output = TRUE;
147 } else {
148 *data = vtty_get_char(d->channel[channel].vtty);
149 }
150 break;
151
152 /* Interrupt Enable Register (IER) */
153 case 0x01:
154 case 0x09:
155 if (op_type == MTS_READ) {
156 *data = d->channel[channel].ier;
157 } else {
158 d->channel[channel].ier = *data & 0xFF;
159
160 if ((*data & 0x02) == 0) { /* transmit holding register */
161 d->channel[channel].vtty->managed_flush = TRUE;
162 vtty_flush(d->channel[channel].vtty);
163 }
164 }
165 break;
166
167 /* Interrupt Ident Register (IIR) */
168 case 0x02:
169 vm_clear_irq(d->vm,d->irq);
170 case 0x0A:
171 if (op_type == MTS_READ) {
172 odata = IIR_NPENDING;
173
174 if (vtty_is_char_avail(d->channel[channel].vtty)) {
175 odata = IIR_RXRDY;
176 } else {
177 if (d->channel[channel].output) {
178 odata = IIR_TXRDY;
179 d->channel[channel].output = 0;
180 }
181 }
182
183 *data = odata;
184 }
185 break;
186
187 /* Line Status Register (LSR) */
188 case 0x05:
189 case 0x0D:
190 if (op_type == MTS_READ) {
191 odata = 0;
192
193 if (vtty_is_char_avail(d->channel[channel].vtty))
194 odata |= LSR_RXRDY;
195
196 odata |= LSR_TXRDY|LSR_TXEMPTY;
197 *data = odata;
198 }
199 break;
200
201 #if DEBUG_UNKNOWN
202 default:
203 if (op_type == MTS_READ) {
204 cpu_log(cpu,"NS16552","read from addr 0x%x, pc=0x%llx (size=%u)\n",
205 offset,cpu->pc,op_size);
206 } else {
207 cpu_log(cpu,"NS16552","write to addr 0x%x, value=0x%llx, "
208 "pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size);
209 }
210 #endif
211 }
212
213 return NULL;
214 }
215
216 /* Shutdown a NS16552 device */
217 void dev_ns16552_shutdown(vm_instance_t *vm,struct ns16552_data *d)
218 {
219 if (d != NULL) {
220 d->channel[0].vtty->read_notifier = NULL;
221 d->channel[1].vtty->read_notifier = NULL;
222
223 /* Remove the periodic task */
224 ptask_remove(d->tid);
225
226 /* Remove the device */
227 dev_remove(vm,&d->dev);
228
229 /* Free the structure itself */
230 free(d);
231 }
232 }
233
234 /* Create a NS16552 device */
235 int dev_ns16552_init(vm_instance_t *vm,m_uint64_t paddr,m_uint32_t len,
236 u_int reg_div,u_int irq,vtty_t *vtty_A,vtty_t *vtty_B)
237 {
238 struct ns16552_data *d;
239
240 /* Allocate private data structure */
241 if (!(d = malloc(sizeof(*d)))) {
242 fprintf(stderr,"NS16552: out of memory\n");
243 return(-1);
244 }
245
246 memset(d,0,sizeof(*d));
247 d->vm = vm;
248 d->irq = irq;
249 d->reg_div = reg_div;
250 d->channel[0].vtty = vtty_A;
251 d->channel[1].vtty = vtty_B;
252
253 vm_object_init(&d->vm_obj);
254 d->vm_obj.name = "ns16552";
255 d->vm_obj.data = d;
256 d->vm_obj.shutdown = (vm_shutdown_t)dev_ns16552_shutdown;
257
258 /* Set device properties */
259 dev_init(&d->dev);
260 d->dev.name = "ns16552";
261 d->dev.phys_addr = paddr;
262 d->dev.phys_len = len;
263 d->dev.handler = dev_ns16552_access;
264 d->dev.priv_data = d;
265
266 vtty_A->priv_data = d;
267 vtty_B->priv_data = d;
268 vtty_A->read_notifier = tty_con_input;
269 vtty_B->read_notifier = tty_aux_input;
270
271 /* Trigger periodically a dummy IRQ to flush buffers */
272 d->tid = ptask_add((ptask_callback)tty_trigger_dummy_irq,d,NULL);
273
274 /* Map this device to the VM */
275 vm_bind_device(vm,&d->dev);
276 vm_object_add(vm,&d->vm_obj);
277 return(0);
278 }

  ViewVC Help
Powered by ViewVC 1.1.26