/[dynamips]/trunk/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

Annotation of /trunk/dev_ns16552.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (hide annotations)
Sat Oct 6 16:26:06 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC3/dev_ns16552.c
File MIME type: text/plain
File size: 6716 byte(s)
dynamips-0.2.7-RC3

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

  ViewVC Help
Powered by ViewVC 1.1.26