/[gxemul]/trunk/src/devices/dev_dc7085.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/src/devices/dev_dc7085.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 30 - (hide annotations)
Mon Oct 8 16:20:40 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 8791 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


1 dpavlin 4 /*
2 dpavlin 22 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 dpavlin 4 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 30 * $Id: dev_dc7085.c,v 1.56 2006/07/23 14:37:34 debug Exp $
29 dpavlin 4 *
30     * DC7085 serial controller, used in some DECstation models.
31     */
32    
33     #include <stdio.h>
34     #include <stdlib.h>
35     #include <string.h>
36    
37     #include "console.h"
38     #include "cpu.h"
39     #include "devices.h"
40     #include "machine.h"
41     #include "memory.h"
42     #include "misc.h"
43    
44     #include "dc7085.h"
45    
46    
47     #define DC_TICK_SHIFT 14
48    
49     #define MAX_QUEUE_LEN 4096
50    
51     struct dc_data {
52     struct dc7085regs regs;
53    
54     int console_handle;
55    
56     /* For slow_serial_interrupts_hack_for_linux: */
57     int just_transmitted_something;
58    
59     unsigned char rx_queue_char[MAX_QUEUE_LEN];
60     char rx_queue_lineno[MAX_QUEUE_LEN];
61     int cur_rx_queue_pos_write;
62     int cur_rx_queue_pos_read;
63    
64     int tx_scanner;
65    
66     int irqnr;
67     int use_fb;
68    
69     struct lk201_data lk201;
70     };
71    
72    
73     /*
74     * Add a character to the receive queue.
75     */
76     void add_to_rx_queue(void *e, int ch, int line_no)
77     {
78     struct dc_data *d = (struct dc_data *) e;
79     int entries_in_use = d->cur_rx_queue_pos_write -
80     d->cur_rx_queue_pos_read;
81     while (entries_in_use < 0)
82     entries_in_use += MAX_QUEUE_LEN;
83    
84     /* Ignore mouse updates, if they come too often: */
85     if (entries_in_use > MAX_QUEUE_LEN/2 && line_no == DCMOUSE_PORT)
86     return;
87    
88     d->rx_queue_char[d->cur_rx_queue_pos_write] = ch;
89     d->rx_queue_lineno[d->cur_rx_queue_pos_write] = line_no;
90     d->cur_rx_queue_pos_write ++;
91     if (d->cur_rx_queue_pos_write == MAX_QUEUE_LEN)
92     d->cur_rx_queue_pos_write = 0;
93    
94     if (d->cur_rx_queue_pos_write == d->cur_rx_queue_pos_read)
95     fatal("warning: add_to_rx_queue(): rx_queue overrun!\n");
96     }
97    
98    
99 dpavlin 30 DEVICE_TICK(dc7085)
100 dpavlin 4 {
101 dpavlin 30 /*
102     * If a key is available from the keyboard, add it to the rx queue.
103     * If other bits are set, an interrupt might need to be caused.
104     */
105 dpavlin 4 struct dc_data *d = extra;
106     int avail;
107    
108     if (cpu->machine->slow_serial_interrupts_hack_for_linux) {
109     /*
110     * Special hack to prevent Linux from Oopsing. (This makes
111     * interrupts not come as fast as possible.)
112     */
113     if (d->just_transmitted_something) {
114     d->just_transmitted_something --;
115     return;
116     }
117     }
118    
119     d->regs.dc_csr &= ~CSR_RDONE;
120    
121     if ((d->regs.dc_csr & CSR_MSE) && !(d->regs.dc_csr & CSR_TRDY)) {
122     int scanner_start = d->tx_scanner;
123    
124     /* Loop until we've checked all 4 channels, or some
125     channel was ready to transmit: */
126    
127     do {
128     d->tx_scanner = (d->tx_scanner + 1) % 4;
129    
130     if (d->regs.dc_tcr & (1 << d->tx_scanner)) {
131     d->regs.dc_csr |= CSR_TRDY;
132     if (d->regs.dc_csr & CSR_TIE)
133     cpu_interrupt(cpu, d->irqnr);
134    
135     d->regs.dc_csr &= ~CSR_TX_LINE_NUM;
136     d->regs.dc_csr |= (d->tx_scanner << 8);
137     }
138     } while (!(d->regs.dc_csr & CSR_TRDY) &&
139     d->tx_scanner != scanner_start);
140    
141     /* We have to return here. NetBSD can handle both
142     rx and tx interrupts simultaneously, but Ultrix
143     doesn't like that? */
144    
145     if (d->regs.dc_csr & CSR_TRDY)
146     return;
147     }
148    
149     lk201_tick(&d->lk201);
150    
151     avail = d->cur_rx_queue_pos_write != d->cur_rx_queue_pos_read;
152    
153     if (avail && (d->regs.dc_csr & CSR_MSE))
154     d->regs.dc_csr |= CSR_RDONE;
155    
156     if ((d->regs.dc_csr & CSR_RDONE) && (d->regs.dc_csr & CSR_RIE))
157     cpu_interrupt(cpu, d->irqnr);
158     }
159    
160    
161 dpavlin 22 DEVICE_ACCESS(dc7085)
162 dpavlin 4 {
163     uint64_t idata = 0, odata = 0;
164 dpavlin 22 size_t i;
165 dpavlin 4 struct dc_data *d = extra;
166    
167 dpavlin 18 if (writeflag == MEM_WRITE)
168     idata = memory_readmax64(cpu, data, len);
169 dpavlin 4
170     /* Always clear: */
171     d->regs.dc_csr &= ~CSR_CLR;
172    
173     switch (relative_addr) {
174     case 0x00: /* CSR: Control and Status */
175     if (writeflag == MEM_WRITE) {
176     debug("[ dc7085 write to CSR: 0x%04x ]\n", idata);
177     idata &= (CSR_TIE | CSR_RIE | CSR_MSE | CSR_CLR
178     | CSR_MAINT);
179     d->regs.dc_csr &= ~(CSR_TIE | CSR_RIE | CSR_MSE
180     | CSR_CLR | CSR_MAINT);
181     d->regs.dc_csr |= idata;
182     if (!(d->regs.dc_csr & CSR_MSE))
183     d->regs.dc_csr &= ~(CSR_TRDY | CSR_RDONE);
184     goto do_return;
185     } else {
186     /* read: */
187    
188     /* fatal("[ dc7085 read from CSR: (csr = 0x%04x) ]\n",
189     d->regs.dc_csr); */
190     odata = d->regs.dc_csr;
191     }
192     break;
193     case 0x08: /* LPR: */
194     if (writeflag == MEM_WRITE) {
195     debug("[ dc7085 write to LPR: 0x%04x ]\n", idata);
196     d->regs.dc_rbuf_lpr = idata;
197     goto do_return;
198     } else {
199     /* read: */
200     int avail = d->cur_rx_queue_pos_write !=
201     d->cur_rx_queue_pos_read;
202     int ch = 0, lineno = 0;
203     /* debug("[ dc7085 read from RBUF: "); */
204     if (avail) {
205     ch = d->rx_queue_char[d->cur_rx_queue_pos_read];
206     lineno = d->rx_queue_lineno[
207     d->cur_rx_queue_pos_read];
208     d->cur_rx_queue_pos_read++;
209     if (d->cur_rx_queue_pos_read == MAX_QUEUE_LEN)
210     d->cur_rx_queue_pos_read = 0;
211     /* if (ch >= ' ' && ch < 127)
212     debug("'%c'", ch);
213     else
214     debug("0x%x", ch);
215     debug(" for lineno %i ", lineno); */
216     } /* else
217     debug("empty ");
218     debug("]\n"); */
219     odata = (avail? RBUF_DVAL:0) |
220     (lineno << RBUF_LINE_NUM_SHIFT) | ch;
221    
222     d->regs.dc_csr &= ~CSR_RDONE;
223     cpu_interrupt_ack(cpu, d->irqnr);
224    
225     d->just_transmitted_something = 4;
226     }
227     break;
228     case 0x10: /* TCR: */
229     if (writeflag == MEM_WRITE) {
230     /* fatal("[ dc7085 write to TCR: 0x%04x) ]\n",
231     (int)idata); */
232     d->regs.dc_tcr = idata;
233     d->regs.dc_csr &= ~CSR_TRDY;
234     cpu_interrupt_ack(cpu, d->irqnr);
235     goto do_return;
236     } else {
237     /* read: */
238     /* debug("[ dc7085 read from TCR: (tcr = 0x%04x) ]\n",
239     d->regs.dc_tcr); */
240     odata = d->regs.dc_tcr;
241     }
242     break;
243     case 0x18: /* Modem status (R), transmit data (W) */
244     if (writeflag == MEM_WRITE) {
245     int line_no = (d->regs.dc_csr >>
246     RBUF_LINE_NUM_SHIFT) & 0x3;
247     idata &= 0xff;
248    
249     lk201_tx_data(&d->lk201, line_no, idata);
250    
251     d->regs.dc_csr &= ~CSR_TRDY;
252     cpu_interrupt_ack(cpu, d->irqnr);
253    
254     d->just_transmitted_something = 4;
255     } else {
256     /* read: */
257     d->regs.dc_msr_tdr |= MSR_DSR2 | MSR_CD2 |
258     MSR_DSR3 | MSR_CD3;
259     debug("[ dc7085 read from MSR: (msr_tdr = 0x%04x) ]\n",
260     d->regs.dc_msr_tdr);
261     odata = d->regs.dc_msr_tdr;
262     }
263     break;
264     default:
265     if (writeflag==MEM_READ) {
266     debug("[ dc7085 read from 0x%08lx ]\n",
267     (long)relative_addr);
268     } else {
269     debug("[ dc7085 write to 0x%08lx:",
270     (long)relative_addr);
271     for (i=0; i<len; i++)
272     debug(" %02x", data[i]);
273     debug(" ]\n");
274     }
275     }
276    
277     if (writeflag == MEM_READ)
278     memory_writemax64(cpu, data, len, odata);
279    
280     do_return:
281     dev_dc7085_tick(cpu, extra);
282    
283     return 1;
284     }
285    
286    
287     /*
288     * dev_dc7085_init():
289     *
290     * Initialize a dc7085 serial controller device. use_fb should be non-zero
291     * if a framebuffer device is used. Channel 0 will then be treated as a
292     * DECstation keyboard, instead of a plain serial console.
293     */
294     int dev_dc7085_init(struct machine *machine, struct memory *mem,
295     uint64_t baseaddr, int irq_nr, int use_fb)
296     {
297     struct dc_data *d;
298    
299     d = malloc(sizeof(struct dc_data));
300     if (d == NULL) {
301     fprintf(stderr, "out of memory\n");
302     exit(1);
303     }
304     memset(d, 0, sizeof(struct dc_data));
305     d->irqnr = irq_nr;
306     d->use_fb = use_fb;
307    
308     d->regs.dc_csr = CSR_TRDY | CSR_MSE;
309     d->regs.dc_tcr = 0x00;
310    
311 dpavlin 22 d->console_handle = console_start_slave(machine, "DC7085", 1);
312 dpavlin 4
313     lk201_init(&d->lk201, use_fb, add_to_rx_queue, d->console_handle, d);
314    
315     memory_device_register(mem, "dc7085", baseaddr, DEV_DC7085_LENGTH,
316 dpavlin 20 dev_dc7085_access, d, DM_DEFAULT, NULL);
317 dpavlin 24 machine_add_tickfunction(machine, dev_dc7085_tick, d,
318     DC_TICK_SHIFT, 0.0);
319 dpavlin 4
320     return d->console_handle;
321     }
322    

  ViewVC Help
Powered by ViewVC 1.1.26