/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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     #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 dpavlin 2 /* Register offset divisor */
57     u_int reg_div;
58    
59 dpavlin 1 /* 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 dpavlin 2 offset >>= d->reg_div;
132    
133     if (offset >= 0x08)
134 dpavlin 1 channel = 1;
135    
136     switch(offset) {
137     /* Receiver Buffer Reg. (RBR) / Transmitting Holding Reg. (THR) */
138     case 0x00:
139 dpavlin 2 case 0x08:
140 dpavlin 1 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 dpavlin 2 case 0x01:
154     case 0x09:
155 dpavlin 1 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 dpavlin 2 case 0x02:
169 dpavlin 1 vm_clear_irq(d->vm,d->irq);
170 dpavlin 2 case 0x0A:
171 dpavlin 1 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 dpavlin 2 case 0x05:
189     case 0x0D:
190 dpavlin 1 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 dpavlin 2 u_int reg_div,u_int irq,vtty_t *vtty_A,vtty_t *vtty_B)
237 dpavlin 1 {
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 dpavlin 2 d->reg_div = reg_div;
250     d->channel[0].vtty = vtty_A;
251     d->channel[1].vtty = vtty_B;
252 dpavlin 1
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 dpavlin 2 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 dpavlin 1
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