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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (hide annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 32645 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


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 32 * $Id: dev_sgi_ip32.c,v 1.46 2006/08/30 15:07:47 debug Exp $
29 dpavlin 4 *
30     * SGI IP32 devices.
31     *
32     * o) CRIME
33     * o) MACE
34     * o) MACE PCI bus
35     * o) mec (ethernet)
36     * o) ust (unknown device)
37     * o) mte (memory transfer engine? details unknown)
38     */
39    
40     #include <stdio.h>
41     #include <stdlib.h>
42     #include <string.h>
43    
44     #include "bus_pci.h"
45     #include "console.h"
46     #include "cpu.h"
47     #include "devices.h"
48     #include "emul.h"
49     #include "machine.h"
50     #include "memory.h"
51     #include "misc.h"
52     #include "net.h"
53    
54     #include "crimereg.h"
55    
56     #include "if_mecreg.h"
57    
58    
59     #define CRIME_TICKSHIFT 14
60     #define CRIME_SPEED_MUL_FACTOR 1
61     #define CRIME_SPEED_DIV_FACTOR 1
62    
63     struct macepci_data {
64     struct pci_data *pci_data;
65     uint32_t reg[DEV_MACEPCI_LENGTH / 4];
66     };
67    
68    
69     /*
70     * dev_crime_tick():
71     *
72     * This function simply updates CRIME_TIME each tick.
73     *
74     * The names DIV and MUL may be a bit confusing. Increasing the
75     * MUL factor will result in an OS running on the emulated machine
76     * detecting a faster CPU. Increasing the DIV factor will result
77     * in a slower detected CPU.
78     *
79     * A R10000 is detected as running at
80     * CRIME_SPEED_FACTOR * 66 MHz. (TODO: this is not correct anymore)
81     */
82     void dev_crime_tick(struct cpu *cpu, void *extra)
83     {
84     int j, carry, old, new, add_byte;
85     uint64_t what_to_add = (1<<CRIME_TICKSHIFT)
86     * CRIME_SPEED_DIV_FACTOR / CRIME_SPEED_MUL_FACTOR;
87     struct crime_data *d = extra;
88    
89     j = 0;
90     carry = 0;
91     while (j < 8) {
92     old = d->reg[CRIME_TIME + 7 - j];
93     add_byte = what_to_add >> ((int64_t)j * 8);
94     add_byte &= 255;
95     new = old + add_byte + carry;
96     d->reg[CRIME_TIME + 7 - j] = new & 255;
97     if (new >= 256)
98     carry = 1;
99     else
100     carry = 0;
101     j++;
102     }
103     }
104    
105    
106     /*
107     * dev_crime_access():
108     */
109 dpavlin 22 DEVICE_ACCESS(crime)
110 dpavlin 4 {
111 dpavlin 18 struct crime_data *d = extra;
112     uint64_t idata = 0;
113 dpavlin 22 size_t i;
114 dpavlin 4
115 dpavlin 18 if (writeflag == MEM_WRITE)
116     idata = memory_readmax64(cpu, data, len);
117 dpavlin 4
118     /*
119     * Set crime version/revision:
120     *
121 dpavlin 18 * This might not be the most elegant or correct solution, but it
122     * seems that the IP32 PROM likes 0x11 for machines without graphics,
123     * and 0xa1 for machines with graphics.
124 dpavlin 4 *
125 dpavlin 18 * NetBSD 2.0 complains about "unknown" crime for 0x11, but I guess
126     * that's something one has to live with. (TODO?)
127 dpavlin 4 */
128     d->reg[4] = 0x00; d->reg[5] = 0x00; d->reg[6] = 0x00;
129     d->reg[7] = d->use_fb? 0xa1 : 0x11;
130    
131     /*
132     * Amount of memory. Bit 8 of bank control set ==> 128MB instead
133     * of 32MB per bank (?)
134     *
135     * When the bank control registers contain the same value as the
136     * previous one, that bank is not valid. (?)
137     */
138     d->reg[CRM_MEM_BANK_CTRL0 + 6] = 0; /* lowbit set=128MB, clear=32MB */
139     d->reg[CRM_MEM_BANK_CTRL0 + 7] = 0; /* address * 32MB */
140     d->reg[CRM_MEM_BANK_CTRL1 + 6] = 0; /* lowbit set=128MB, clear=32MB */
141     d->reg[CRM_MEM_BANK_CTRL1 + 7] = 1; /* address * 32MB */
142    
143     if (relative_addr >= CRIME_TIME && relative_addr < CRIME_TIME+8) {
144     if (writeflag == MEM_READ)
145     memcpy(data, &d->reg[relative_addr], len);
146     return 1;
147     }
148    
149     if (writeflag == MEM_WRITE)
150     memcpy(&d->reg[relative_addr], data, len);
151     else
152     memcpy(data, &d->reg[relative_addr], len);
153    
154 dpavlin 10 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
155     (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f)) {
156 dpavlin 4 /*
157     * Force interrupt re-assertion:
158     *
159     * NOTE: Ugly hack. Hopefully CRMERR is never used.
160     */
161     #if 0
162 dpavlin 10 /*
163 dpavlin 4 No. If this is enabled, the mec bugs out on either NetBSD or OpenBSD.
164     TODO.
165 dpavlin 10 */
166 dpavlin 4 cpu_interrupt_ack(cpu, 8); /* CRM_INT_CRMERR); */
167     #endif
168     }
169    
170     switch (relative_addr) {
171     case CRIME_CONTROL: /* 0x008 */
172     /* TODO: 64-bit write to CRIME_CONTROL, but some things
173     (such as NetBSD 1.6.2) write to 0x00c! */
174     if (writeflag == MEM_WRITE) {
175     /*
176     * 0x200 = watchdog timer (according to NetBSD)
177     * 0x800 = "reboot" used by the IP32 PROM
178     */
179     if (idata & 0x200) {
180     idata &= ~0x200;
181     }
182     if (idata & 0x800) {
183 dpavlin 22 int j;
184    
185 dpavlin 4 /* This is used by the IP32 PROM's
186     "reboot" command: */
187 dpavlin 22 for (j=0; j<cpu->machine->ncpus; j++)
188     cpu->machine->cpus[j]->running = 0;
189 dpavlin 4 cpu->machine->
190     exit_without_entering_debugger = 1;
191     idata &= ~0x800;
192     }
193     if (idata != 0)
194     fatal("[ CRIME_CONTROL: unimplemented "
195     "control 0x%016llx ]\n", (long long)idata);
196     }
197     break;
198 dpavlin 10 #if 0
199 dpavlin 4 case CRIME_INTSTAT: /* 0x010, Current interrupt status */
200     case 0x14:
201     case CRIME_INTMASK: /* 0x018, Current interrupt mask */
202     case 0x1c:
203     case 0x34:
204     /* don't dump debug info for these */
205     break;
206 dpavlin 10 #endif
207 dpavlin 4 default:
208     if (writeflag==MEM_READ) {
209     debug("[ crime: read from 0x%x, len=%i:",
210     (int)relative_addr, len);
211     for (i=0; i<len; i++)
212     debug(" %02x", data[i]);
213     debug(" ]\n");
214     } else {
215     debug("[ crime: write to 0x%x:", (int)relative_addr);
216     for (i=0; i<len; i++)
217     debug(" %02x", data[i]);
218     debug(" (len=%i) ]\n", len);
219     }
220     }
221    
222     return 1;
223     }
224    
225    
226     /*
227     * dev_crime_init():
228     */
229     struct crime_data *dev_crime_init(struct machine *machine, struct memory *mem,
230     uint64_t baseaddr, int irq_nr, int use_fb)
231     {
232     struct crime_data *d;
233    
234     d = malloc(sizeof(struct crime_data));
235     if (d == NULL) {
236     fprintf(stderr, "out of memory\n");
237     exit(1);
238     }
239     memset(d, 0, sizeof(struct crime_data));
240     d->irq_nr = irq_nr;
241     d->use_fb = use_fb;
242    
243     memory_device_register(mem, "crime", baseaddr, DEV_CRIME_LENGTH,
244 dpavlin 20 dev_crime_access, d, DM_DEFAULT, NULL);
245 dpavlin 24 machine_add_tickfunction(machine, dev_crime_tick, d,
246     CRIME_TICKSHIFT, 0.0);
247 dpavlin 4
248     return d;
249     }
250    
251    
252     /****************************************************************************/
253    
254    
255     /*
256     * dev_mace_access():
257     */
258 dpavlin 22 DEVICE_ACCESS(mace)
259 dpavlin 4 {
260 dpavlin 22 size_t i;
261 dpavlin 4 struct mace_data *d = extra;
262    
263     if (writeflag == MEM_WRITE)
264     memcpy(&d->reg[relative_addr], data, len);
265     else
266     memcpy(data, &d->reg[relative_addr], len);
267    
268 dpavlin 10 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
269     (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f))
270     cpu_interrupt_ack(cpu, 8); /* CRM_INT_CRMERR); */
271    
272 dpavlin 4 switch (relative_addr) {
273     #if 0
274 dpavlin 10 case 0x10: /* Current interrupt assertions */
275     case 0x14:
276 dpavlin 4 /* don't dump debug info for these */
277 dpavlin 10 if (writeflag == MEM_WRITE) {
278     fatal("[ NOTE/TODO: WRITE to mace intr: "
279     "reladdr=0x%x data=", (int)relative_addr);
280     for (i=0; i<len; i++)
281     fatal(" %02x", data[i]);
282     fatal(" (len=%i) ]\n", len);
283     }
284 dpavlin 4 break;
285 dpavlin 10 case 0x18: /* Interrupt mask */
286     case 0x1c:
287     /* don't dump debug info for these */
288     break;
289 dpavlin 4 #endif
290     default:
291 dpavlin 10 if (writeflag == MEM_READ) {
292     debug("[ mace: read from 0x%x:", (int)relative_addr);
293     for (i=0; i<len; i++)
294     debug(" %02x", data[i]);
295     debug(" (len=%i) ]\n", len);
296 dpavlin 4 } else {
297     debug("[ mace: write to 0x%x:", (int)relative_addr);
298     for (i=0; i<len; i++)
299     debug(" %02x", data[i]);
300     debug(" (len=%i) ]\n", len);
301     }
302     }
303    
304     return 1;
305     }
306    
307    
308     /*
309     * dev_mace_init():
310     */
311     struct mace_data *dev_mace_init(struct memory *mem, uint64_t baseaddr,
312     int irqnr)
313     {
314     struct mace_data *d;
315    
316     d = malloc(sizeof(struct mace_data));
317     if (d == NULL) {
318     fprintf(stderr, "out of memory\n");
319     exit(1);
320     }
321     memset(d, 0, sizeof(struct mace_data));
322     d->irqnr = irqnr;
323    
324     memory_device_register(mem, "mace", baseaddr, DEV_MACE_LENGTH,
325 dpavlin 20 dev_mace_access, d, DM_DEFAULT, NULL);
326 dpavlin 4
327     return d;
328     }
329    
330    
331     /****************************************************************************/
332    
333    
334     /*
335     * dev_macepci_access():
336     */
337 dpavlin 22 DEVICE_ACCESS(macepci)
338 dpavlin 4 {
339     struct macepci_data *d = (struct macepci_data *) extra;
340     uint64_t idata = 0, odata=0;
341 dpavlin 22 int regnr, res = 1, bus, dev, func, pcireg;
342 dpavlin 4
343 dpavlin 18 if (writeflag == MEM_WRITE)
344     idata = memory_readmax64(cpu, data, len);
345    
346 dpavlin 4 regnr = relative_addr / sizeof(uint32_t);
347    
348     /* Read from/write to the macepci: */
349     switch (relative_addr) {
350 dpavlin 22
351 dpavlin 4 case 0x00: /* Error address */
352     if (writeflag == MEM_WRITE) {
353     } else {
354     odata = 0;
355     }
356     break;
357 dpavlin 22
358 dpavlin 4 case 0x04: /* Error flags */
359     if (writeflag == MEM_WRITE) {
360     } else {
361     odata = 0x06;
362     }
363     break;
364 dpavlin 22
365 dpavlin 4 case 0x0c: /* Revision number */
366     if (writeflag == MEM_WRITE) {
367     } else {
368     odata = 0x01;
369     }
370     break;
371 dpavlin 22
372 dpavlin 4 case 0xcf8: /* PCI ADDR */
373 dpavlin 22 bus_pci_decompose_1(idata, &bus, &dev, &func, &pcireg);
374     bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, pcireg);
375     break;
376    
377 dpavlin 4 case 0xcfc: /* PCI DATA */
378 dpavlin 22 bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ?
379     &odata : &idata, len, writeflag);
380 dpavlin 4 break;
381 dpavlin 22
382 dpavlin 4 default:
383     if (writeflag == MEM_WRITE) {
384     debug("[ macepci: unimplemented write to address "
385     "0x%x, data=0x%02x ]\n",
386     (int)relative_addr, (int)idata);
387     } else {
388     debug("[ macepci: unimplemented read from address "
389     "0x%x ]\n", (int)relative_addr);
390     }
391     }
392    
393     if (writeflag == MEM_READ)
394     memory_writemax64(cpu, data, len, odata);
395    
396     return res;
397     }
398    
399    
400     /*
401     * dev_macepci_init():
402     */
403 dpavlin 22 struct pci_data *dev_macepci_init(struct machine *machine,
404     struct memory *mem, uint64_t baseaddr, int pciirq)
405 dpavlin 4 {
406     struct macepci_data *d = malloc(sizeof(struct macepci_data));
407     if (d == NULL) {
408     fprintf(stderr, "out of memory\n");
409     exit(1);
410     }
411     memset(d, 0, sizeof(struct macepci_data));
412    
413 dpavlin 32 d->pci_data = bus_pci_init(machine,
414     pciirq,
415     0,
416     0,
417     0,
418     0,
419     0,
420     0x18000003, /* ISA portbase */
421     0,
422     0);
423 dpavlin 4
424     memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
425 dpavlin 20 dev_macepci_access, (void *)d, DM_DEFAULT, NULL);
426 dpavlin 4
427     return d->pci_data;
428     }
429    
430    
431     /****************************************************************************/
432    
433    
434     /*
435     * SGI "mec" ethernet. Used in SGI-IP32.
436     *
437     * Study http://www.openbsd.org/cgi-bin/cvsweb/src/sys/arch/sgi/dev/if_mec.c
438     * and/or NetBSD. TODO:
439     *
440     * x) tx and rx interrupts/ring/slot stuff
441     */
442    
443     #define MEC_TICK_SHIFT 14
444    
445     #define MAX_TX_PACKET_LEN 1700
446     #define N_RX_ADDRESSES 16
447    
448     struct sgi_mec_data {
449     uint64_t reg[DEV_SGI_MEC_LENGTH / sizeof(uint64_t)];
450    
451     int irq_nr;
452     unsigned char macaddr[6];
453    
454     unsigned char cur_tx_packet[MAX_TX_PACKET_LEN];
455     int cur_tx_packet_len;
456    
457     unsigned char *cur_rx_packet;
458     int cur_rx_packet_len;
459    
460     uint64_t rx_addr[N_RX_ADDRESSES];
461     int cur_rx_addr_index_write;
462     int cur_rx_addr_index;
463     };
464    
465    
466     /*
467     * mec_reset():
468     */
469     static void mec_reset(struct sgi_mec_data *d)
470     {
471     if (d->cur_rx_packet != NULL)
472     free(d->cur_rx_packet);
473    
474     memset(d->reg, 0, sizeof(d->reg));
475     }
476    
477    
478     /*
479     * mec_control_write():
480     */
481     static void mec_control_write(struct cpu *cpu, struct sgi_mec_data *d,
482     uint64_t x)
483     {
484     if (x & MEC_MAC_CORE_RESET) {
485     debug("[ sgi_mec: CORE RESET ]\n");
486     mec_reset(d);
487     }
488     }
489    
490    
491     /*
492     * mec_try_rx():
493     */
494     static int mec_try_rx(struct cpu *cpu, struct sgi_mec_data *d)
495     {
496     uint64_t base;
497     unsigned char data[8];
498     int i, res, retval = 0;
499    
500     base = d->rx_addr[d->cur_rx_addr_index];
501     if (base & 0xfff)
502     fatal("[ mec_try_rx(): WARNING! lowest bits of base are "
503     "non-zero (0x%3x). TODO ]\n", (int)(base & 0xfff));
504     base &= 0xfffff000ULL;
505     if (base == 0)
506     goto skip;
507    
508     /* printf("rx base = 0x%016llx\n", (long long)base); */
509    
510     /* Read an rx descriptor from memory: */
511     res = cpu->memory_rw(cpu, cpu->mem, base,
512     &data[0], sizeof(data), MEM_READ, PHYSICAL);
513     if (!res)
514     return 0;
515    
516     #if 0
517     printf("{ mec: rxdesc %i: ", d->cur_rx_addr_index);
518     for (i=0; i<sizeof(data); i++) {
519     if ((i & 3) == 0)
520     printf(" ");
521     printf("%02x", data[i]);
522     }
523     printf(" }\n");
524     #endif
525    
526     /* Is this descriptor already in use? */
527     if (data[0] & 0x80) {
528     /* printf("INTERRUPT for base = 0x%x\n", (int)base); */
529     goto skip_and_advance;
530     }
531    
532     if (d->cur_rx_packet == NULL &&
533     net_ethernet_rx_avail(cpu->machine->emul->net, d))
534     net_ethernet_rx(cpu->machine->emul->net, d,
535     &d->cur_rx_packet, &d->cur_rx_packet_len);
536    
537     if (d->cur_rx_packet == NULL)
538     goto skip;
539    
540     /* Copy the packet data: */
541     /* printf("RX: "); */
542     for (i=0; i<d->cur_rx_packet_len; i++) {
543     res = cpu->memory_rw(cpu, cpu->mem, base + 32 + i + 2,
544     d->cur_rx_packet + i, 1, MEM_WRITE, PHYSICAL);
545     /* printf(" %02x", d->cur_rx_packet[i]); */
546     }
547     /* printf("\n"); */
548    
549 dpavlin 10 #if 0
550 dpavlin 4 printf("RX: %i bytes, index %i, base = 0x%x\n",
551     d->cur_rx_packet_len, d->cur_rx_addr_index, (int)base);
552     #endif
553    
554     /* 4 bytes of CRC at the end. Hm. TODO */
555     d->cur_rx_packet_len += 4;
556    
557     memset(data, 0, sizeof(data));
558     data[6] = (d->cur_rx_packet_len >> 8) & 255;
559     data[7] = d->cur_rx_packet_len & 255;
560     /* TODO: lots of bits :-) */
561     data[4] = 0x04; /* match MAC */
562     data[0] = 0x80; /* 0x80 = received. */
563     res = cpu->memory_rw(cpu, cpu->mem, base,
564     &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
565    
566     /* Free the packet from memory: */
567     free(d->cur_rx_packet);
568     d->cur_rx_packet = NULL;
569    
570     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_RX_THRESHOLD;
571     skip_and_advance:
572     d->cur_rx_addr_index ++;
573     d->cur_rx_addr_index %= N_RX_ADDRESSES;
574     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &= ~MEC_INT_RX_MCL_FIFO_ALIAS;
575 dpavlin 12 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
576     (d->cur_rx_addr_index & 0x1f) << 8;
577 dpavlin 4 retval = 1;
578    
579     skip:
580     return retval;
581     }
582    
583    
584     /*
585     * mec_try_tx():
586     */
587     static int mec_try_tx(struct cpu *cpu, struct sgi_mec_data *d)
588     {
589     uint64_t base, addr, dma_base;
590     int tx_ring_ptr, ringread, ringwrite, res, i, j;
591     unsigned char data[32];
592     int len, start_offset, dma_ptr_nr, dma_len;
593    
594     base = d->reg[MEC_TX_RING_BASE / sizeof(uint64_t)];
595     tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
596    
597     if (base == 0)
598     return 0;
599    
600     /* printf("base = 0x%016llx\n", base); */
601    
602     ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
603     ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
604     ringread >>= 16;
605     /* All done? Then abort. */
606     if (ringread == ringwrite)
607     return 0;
608    
609     tx_ring_ptr &= MEC_TX_RING_READ_PTR;
610     tx_ring_ptr >>= 16;
611    
612     /* Each tx descriptor (+ buffer) is 128 bytes: */
613     addr = base + tx_ring_ptr*128;
614     res = cpu->memory_rw(cpu, cpu->mem, addr,
615     &data[0], sizeof(data), MEM_READ, PHYSICAL);
616     if (!res)
617     return 0;
618    
619     /* Is this packet transmitted already? */
620     if (data[0] & 0x80) {
621     fatal("[ mec_try_tx: tx_ring_ptr = %i, already"
622     " transmitted? ]\n", tx_ring_ptr);
623     goto advance_tx;
624     }
625    
626     len = data[6] * 256 + data[7];
627     start_offset = data[5] & 0x7f;
628    
629     /* Is this packet empty? Then don't transmit. */
630     if (len == 0)
631     return 0;
632    
633     /* Hm. Is len one too little? TODO */
634     len ++;
635    
636     #if 0
637     printf("{ mec: txdesc %i: ", tx_ring_ptr);
638     for (i=0; i<sizeof(data); i++) {
639     if ((i & 3) == 0)
640     printf(" ");
641     printf("%02x", data[i]);
642     }
643     printf(" }\n");
644     #endif
645     dma_ptr_nr = 0;
646    
647     j = 0;
648     d->cur_tx_packet_len = len;
649    
650     for (i=start_offset; i<start_offset+len; i++) {
651     unsigned char ch;
652    
653     if ((i & 0x7f) == 0x00)
654     break;
655    
656     res = cpu->memory_rw(cpu, cpu->mem, addr + i,
657     &ch, sizeof(ch), MEM_READ, PHYSICAL);
658     /* printf(" %02x", ch); */
659    
660     d->cur_tx_packet[j++] = ch;
661     if (j >= MAX_TX_PACKET_LEN) {
662     fatal("[ mec_try_tx: packet too large? ]\n");
663     break;
664     }
665     }
666     /* printf("\n"); */
667    
668     if (j < len) {
669     /* Continue with DMA: */
670     for (;;) {
671     dma_ptr_nr ++;
672     if (dma_ptr_nr >= 4)
673     break;
674     if (!(data[4] & (0x01 << dma_ptr_nr)))
675     break;
676     dma_base = (data[dma_ptr_nr * 8 + 4] << 24)
677     + (data[dma_ptr_nr * 8 + 5] << 16)
678     + (data[dma_ptr_nr * 8 + 6] << 8)
679     + (data[dma_ptr_nr * 8 + 7]);
680     dma_base &= 0xfffffff8ULL;
681     dma_len = (data[dma_ptr_nr * 8 + 2] << 8)
682     + (data[dma_ptr_nr * 8 + 3]) + 1;
683    
684     /* printf("dma_base = %08x, dma_len = %i\n",
685     (int)dma_base, dma_len); */
686    
687     while (dma_len > 0) {
688     unsigned char ch;
689     res = cpu->memory_rw(cpu, cpu->mem, dma_base,
690     &ch, sizeof(ch), MEM_READ, PHYSICAL);
691     /* printf(" %02x", ch); */
692    
693     d->cur_tx_packet[j++] = ch;
694     if (j >= MAX_TX_PACKET_LEN) {
695     fatal("[ mec_try_tx: packet too large?"
696     " ]\n");
697     break;
698     }
699     dma_base ++;
700     dma_len --;
701     }
702     }
703     }
704    
705     if (j < len)
706     fatal("[ mec_try_tx: not enough data? ]\n");
707    
708     net_ethernet_tx(cpu->machine->emul->net, d,
709     d->cur_tx_packet, d->cur_tx_packet_len);
710    
711     /* see openbsd's if_mec.c for details */
712     if (data[4] & 0x01) {
713     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
714     MEC_INT_TX_PACKET_SENT;
715     }
716     memset(data, 0, 6); /* last 2 bytes are len */
717     data[0] = 0x80;
718     data[5] = 0x80;
719    
720     res = cpu->memory_rw(cpu, cpu->mem, addr,
721     &data[0], sizeof(data), MEM_WRITE, PHYSICAL);
722    
723     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_EMPTY;
724     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_PACKET_SENT;
725    
726     advance_tx:
727     /* Advance the ring Read ptr. */
728     tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
729     ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR;
730     ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR;
731    
732     ringread = (ringread >> 16) + 1;
733     ringread &= 63;
734     ringread <<= 16;
735    
736     d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] =
737     (ringwrite & MEC_TX_RING_WRITE_PTR) |
738     (ringread & MEC_TX_RING_READ_PTR);
739    
740     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
741     ~MEC_INT_TX_RING_BUFFER_ALIAS;
742     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
743     (d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] &
744     MEC_INT_TX_RING_BUFFER_ALIAS);
745    
746     return 1;
747     }
748    
749    
750     /*
751     * dev_sgi_mec_tick():
752     */
753     void dev_sgi_mec_tick(struct cpu *cpu, void *extra)
754     {
755     struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
756     int n = 0;
757    
758     while (mec_try_tx(cpu, d))
759     ;
760    
761     while (mec_try_rx(cpu, d) && n < 16)
762     n++;
763    
764     /* Interrupts: (TODO: only when enabled) */
765     if (d->reg[MEC_INT_STATUS / sizeof(uint64_t)] & MEC_INT_STATUS_MASK) {
766     #if 0
767     printf("[%02x]", (int)(d->reg[MEC_INT_STATUS /
768     sizeof(uint64_t)] & MEC_INT_STATUS_MASK));
769     fflush(stdout);
770     #endif
771     cpu_interrupt(cpu, d->irq_nr);
772     } else
773     cpu_interrupt_ack(cpu, d->irq_nr);
774     }
775    
776    
777     /*
778     * dev_sgi_mec_access():
779     */
780 dpavlin 22 DEVICE_ACCESS(sgi_mec)
781 dpavlin 4 {
782     struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
783     uint64_t idata = 0, odata = 0;
784     int regnr;
785    
786 dpavlin 18 if (writeflag == MEM_WRITE)
787     idata = memory_readmax64(cpu, data, len);
788    
789 dpavlin 4 regnr = relative_addr / sizeof(uint64_t);
790    
791     /* Treat most registers as read/write, by default. */
792     if (writeflag == MEM_WRITE) {
793     switch (relative_addr) {
794     case MEC_INT_STATUS: /* 0x08 */
795     /* Clear bits on write: (This is just a guess) */
796     d->reg[regnr] = (d->reg[regnr] & ~0xff)
797     | ((d->reg[regnr] & ~idata) & 0xff);
798     break;
799     case MEC_TX_RING_PTR: /* 0x30 */
800     idata &= MEC_TX_RING_WRITE_PTR;
801     d->reg[regnr] = (d->reg[regnr] &
802     ~MEC_TX_RING_WRITE_PTR) | idata;
803     /* TODO */
804     break;
805     default:
806     d->reg[regnr] = idata;
807     }
808     } else
809     odata = d->reg[regnr];
810    
811     switch (relative_addr) {
812     case MEC_MAC_CONTROL: /* 0x00 */
813     if (writeflag)
814     mec_control_write(cpu, d, idata);
815     else {
816     /* Fake "revision 1": */
817     odata &= ~MEC_MAC_REVISION;
818     odata |= 1 << MEC_MAC_REVISION_SHIFT;
819     }
820     break;
821     case MEC_INT_STATUS: /* 0x08 */
822     if (writeflag)
823     debug("[ sgi_mec: write to MEC_INT_STATUS: "
824     "0x%016llx ]\n", (long long)idata);
825     break;
826     case MEC_DMA_CONTROL: /* 0x10 */
827     if (writeflag) {
828     debug("[ sgi_mec: write to MEC_DMA_CONTROL: "
829     "0x%016llx ]\n", (long long)idata);
830     if (!(idata & MEC_DMA_TX_INT_ENABLE)) {
831     /* This should apparently stop the
832     TX Empty interrupt. */
833     d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &=
834     ~MEC_INT_TX_EMPTY;
835     }
836     }
837     break;
838     case MEC_TX_ALIAS: /* 0x20 */
839     if (writeflag) {
840     debug("[ sgi_mec: write to MEC_TX_ALIAS: "
841     "0x%016llx ]\n", (long long)idata);
842     } else {
843     debug("[ sgi_mec: read from MEC_TX_ALIAS: "
844     "0x%016llx ]\n", (long long)idata);
845     odata = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)];
846     }
847     break;
848     case MEC_RX_ALIAS: /* 0x28 */
849     if (writeflag)
850     debug("[ sgi_mec: write to MEC_RX_ALIAS: "
851     "0x%016llx ]\n", (long long)idata);
852     break;
853     case MEC_TX_RING_PTR: /* 0x30 */
854     if (writeflag)
855     debug("[ sgi_mec: write to MEC_TX_RING_PTR: "
856     "0x%016llx ]\n", (long long)idata);
857     break;
858     case MEC_PHY_DATA: /* 0x64 */
859     if (writeflag)
860     fatal("[ sgi_mec: write to MEC_PHY_DATA: "
861     "0x%016llx ]\n", (long long)idata);
862     else
863     odata = 0; /* ? */
864     break;
865     case MEC_PHY_ADDRESS: /* 0x6c */
866     if (writeflag)
867     debug("[ sgi_mec: write to MEC_PHY_ADDRESS: "
868     "0x%016llx ]\n", (long long)idata);
869     break;
870     case MEC_PHY_READ_INITIATE: /* 0x70 */
871     if (writeflag)
872     debug("[ sgi_mec: write to MEC_PHY_READ_INITIATE: "
873     "0x%016llx ]\n", (long long)idata);
874     break;
875     case 0x74:
876     if (writeflag)
877     debug("[ sgi_mec: write to 0x74: 0x%016llx ]\n",
878     (long long)idata);
879     else
880     debug("[ sgi_mec: read from 0x74 ]\n");
881     break;
882     case MEC_STATION: /* 0xa0 */
883     if (writeflag)
884     debug("[ sgi_mec: setting the MAC address to "
885     "%02x:%02x:%02x:%02x:%02x:%02x ]\n",
886     (idata >> 40) & 255, (idata >> 32) & 255,
887     (idata >> 24) & 255, (idata >> 16) & 255,
888     (idata >> 8) & 255, (idata >> 0) & 255);
889     break;
890     case MEC_STATION_ALT: /* 0xa8 */
891     if (writeflag)
892     debug("[ sgi_mec: setting the ALTERNATIVE MAC address"
893     " to %02x:%02x:%02x:%02x:%02x:%02x ]\n",
894     (idata >> 40) & 255, (idata >> 32) & 255,
895     (idata >> 24) & 255, (idata >> 16) & 255,
896     (idata >> 8) & 255, (idata >> 0) & 255);
897     break;
898     case MEC_MULTICAST: /* 0xb0 */
899     if (writeflag)
900     debug("[ sgi_mec: write to MEC_MULTICAST: "
901     "0x%016llx ]\n", (long long)idata);
902     break;
903     case MEC_TX_RING_BASE: /* 0xb8 */
904     if (writeflag)
905     debug("[ sgi_mec: write to MEC_TX_RING_BASE: "
906     "0x%016llx ]\n", (long long)idata);
907     break;
908     case MEC_MCL_RX_FIFO: /* 0x100 */
909     if (writeflag) {
910     debug("[ sgi_mec: write to MEC_MCL_RX_FIFO: 0x"
911     "%016llx ]\n", (long long)idata);
912     d->rx_addr[d->cur_rx_addr_index_write] = idata;
913     d->cur_rx_addr_index_write ++;
914     d->cur_rx_addr_index_write %= N_RX_ADDRESSES;
915     }
916     break;
917     default:
918     if (writeflag == MEM_WRITE)
919     fatal("[ sgi_mec: unimplemented write to address"
920     " 0x%llx, data=0x%016llx ]\n",
921     (long long)relative_addr, (long long)idata);
922     else
923     fatal("[ sgi_mec: unimplemented read from address"
924     " 0x%llx ]\n", (long long)relative_addr);
925     }
926    
927     if (writeflag == MEM_READ)
928     memory_writemax64(cpu, data, len, odata);
929    
930     dev_sgi_mec_tick(cpu, extra);
931    
932     return 1;
933     }
934    
935    
936     /*
937     * dev_sgi_mec_init():
938     */
939     void dev_sgi_mec_init(struct machine *machine, struct memory *mem,
940     uint64_t baseaddr, int irq_nr, unsigned char *macaddr)
941     {
942     char *name2;
943 dpavlin 10 size_t nlen = 55;
944 dpavlin 4 struct sgi_mec_data *d = malloc(sizeof(struct sgi_mec_data));
945    
946     if (d == NULL) {
947     fprintf(stderr, "out of memory\n");
948     exit(1);
949     }
950     memset(d, 0, sizeof(struct sgi_mec_data));
951     d->irq_nr = irq_nr;
952     memcpy(d->macaddr, macaddr, 6);
953    
954     mec_reset(d);
955    
956 dpavlin 10 name2 = malloc(nlen);
957 dpavlin 4 if (name2 == NULL) {
958     fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
959     exit(1);
960     }
961 dpavlin 10 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
962 dpavlin 4 d->macaddr[0], d->macaddr[1], d->macaddr[2],
963     d->macaddr[3], d->macaddr[4], d->macaddr[5]);
964    
965     memory_device_register(mem, name2, baseaddr,
966     DEV_SGI_MEC_LENGTH, dev_sgi_mec_access, (void *)d,
967 dpavlin 20 DM_DEFAULT, NULL);
968 dpavlin 4
969 dpavlin 24 machine_add_tickfunction(machine, dev_sgi_mec_tick, d,
970     MEC_TICK_SHIFT, 0.0);
971 dpavlin 4
972     net_add_nic(machine->emul->net, d, macaddr);
973     }
974    
975    
976     /****************************************************************************/
977    
978    
979     struct sgi_ust_data {
980     uint64_t reg[DEV_SGI_UST_LENGTH / sizeof(uint64_t)];
981     };
982    
983    
984     /*
985     * dev_sgi_ust_access():
986     */
987 dpavlin 22 DEVICE_ACCESS(sgi_ust)
988 dpavlin 4 {
989     struct sgi_ust_data *d = (struct sgi_ust_data *) extra;
990     uint64_t idata = 0, odata = 0;
991     int regnr;
992    
993     idata = memory_readmax64(cpu, data, len);
994     regnr = relative_addr / sizeof(uint64_t);
995    
996     /* Treat all registers as read/write, by default. */
997     if (writeflag == MEM_WRITE)
998     d->reg[regnr] = idata;
999     else
1000     odata = d->reg[regnr];
1001    
1002     switch (relative_addr) {
1003     case 0:
1004     d->reg[regnr] += 0x2710;
1005     break;
1006     default:
1007     if (writeflag == MEM_WRITE)
1008 dpavlin 12 debug("[ sgi_ust: unimplemented write to "
1009     "address 0x%llx, data=0x%016llx ]\n",
1010     (long long)relative_addr, (long long)idata);
1011 dpavlin 4 else
1012 dpavlin 12 debug("[ sgi_ust: unimplemented read from address"
1013     " 0x%llx ]\n", (long long)relative_addr);
1014 dpavlin 4 }
1015    
1016     if (writeflag == MEM_READ)
1017     memory_writemax64(cpu, data, len, odata);
1018    
1019     return 1;
1020     }
1021    
1022    
1023     /*
1024     * dev_sgi_ust_init():
1025     */
1026     void dev_sgi_ust_init(struct memory *mem, uint64_t baseaddr)
1027     {
1028     struct sgi_ust_data *d = malloc(sizeof(struct sgi_ust_data));
1029     if (d == NULL) {
1030     fprintf(stderr, "out of memory\n");
1031     exit(1);
1032     }
1033     memset(d, 0, sizeof(struct sgi_ust_data));
1034    
1035     memory_device_register(mem, "sgi_ust", baseaddr,
1036 dpavlin 12 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d,
1037 dpavlin 20 DM_DEFAULT, NULL);
1038 dpavlin 4 }
1039    
1040    
1041     /****************************************************************************/
1042    
1043    
1044     /*
1045     * SGI "mte". This device seems to be an accelerator for copying/clearing
1046 dpavlin 12 * memory. Used by (at least) the SGI O2 PROM.
1047     *
1048     * Actually, it seems to be used for graphics output as well. (?)
1049 dpavlin 14 * The O2's PROM uses it to output graphics.
1050 dpavlin 4 */
1051 dpavlin 12 /* #define debug fatal */
1052 dpavlin 14 /* #define MTE_DEBUG */
1053 dpavlin 4 #define ZERO_CHUNK_LEN 4096
1054    
1055     struct sgi_mte_data {
1056 dpavlin 14 uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
1057 dpavlin 4 };
1058    
1059     /*
1060     * dev_sgi_mte_access():
1061     */
1062 dpavlin 22 DEVICE_ACCESS(sgi_mte)
1063 dpavlin 4 {
1064     struct sgi_mte_data *d = (struct sgi_mte_data *) extra;
1065     uint64_t first_addr, last_addr, zerobuflen, fill_addr, fill_len;
1066     unsigned char zerobuf[ZERO_CHUNK_LEN];
1067     uint64_t idata = 0, odata = 0;
1068     int regnr;
1069    
1070     idata = memory_readmax64(cpu, data, len);
1071 dpavlin 14 regnr = relative_addr / sizeof(uint32_t);
1072 dpavlin 4
1073 dpavlin 14 /*
1074     * Treat all registers as read/write, by default. Sometimes these
1075     * are accessed as 32-bit words, sometimes as 64-bit words.
1076     */
1077     if (len != 4) {
1078     if (writeflag == MEM_WRITE) {
1079     d->reg[regnr] = idata >> 32;
1080     d->reg[regnr+1] = idata;
1081     } else
1082     odata = ((uint64_t)d->reg[regnr] << 32) +
1083     d->reg[regnr+1];
1084     }
1085    
1086 dpavlin 4 if (writeflag == MEM_WRITE)
1087     d->reg[regnr] = idata;
1088     else
1089     odata = d->reg[regnr];
1090    
1091 dpavlin 14 #ifdef MTE_DEBUG
1092     if (writeflag == MEM_WRITE && relative_addr >= 0x2000 &&
1093     relative_addr < 0x3000)
1094     fatal("[ MTE: 0x%08x: 0x%016llx ]\n", (int)relative_addr,
1095     (long long)idata);
1096     #endif
1097    
1098 dpavlin 4 /*
1099 dpavlin 12 * I've not found any docs about this 'mte' device at all, so this is
1100     * just a guess. The mte seems to be used for copying and zeroing
1101     * chunks of memory.
1102 dpavlin 4 *
1103 dpavlin 14 * write to 0x3030, data=0x00000000003da000 ] <-- first address
1104     * write to 0x3038, data=0x00000000003f9fff ] <-- last address
1105     * write to 0x3018, data=0x0000000000000000 ] <-- what to fill?
1106     * write to 0x3008, data=0x00000000ffffffff ] <-- ?
1107     * write to 0x3800, data=0x0000000000000011 ] <-- operation
1108     * (0x11 = zerofill)
1109 dpavlin 4 *
1110 dpavlin 14 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1111     * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1112     * write to 0x1710, data=0x80001ea480001ea5
1113 dpavlin 4 * ...
1114 dpavlin 14 * write to 0x1770, data=0x80001e9c80001e9d
1115     * write to 0x1778, data=0x80001e9e80001e9f
1116 dpavlin 4 */
1117     switch (relative_addr) {
1118    
1119     /* No warnings for these: */
1120     case 0x3030:
1121     case 0x3038:
1122     break;
1123    
1124     /* Unknown, but no warning: */
1125     case 0x4000:
1126     case 0x3018:
1127     case 0x3008:
1128     case 0x1700:
1129     case 0x1708:
1130     case 0x1710:
1131     case 0x1718:
1132     case 0x1720:
1133     case 0x1728:
1134     case 0x1730:
1135     case 0x1738:
1136     case 0x1740:
1137     case 0x1748:
1138     case 0x1750:
1139     case 0x1758:
1140     case 0x1760:
1141     case 0x1768:
1142     case 0x1770:
1143     case 0x1778:
1144     break;
1145    
1146 dpavlin 14 /* Graphics stuff? No warning: */
1147     case 0x2018:
1148     case 0x2060:
1149     case 0x2070:
1150     case 0x2074:
1151     case 0x20c0:
1152     case 0x20c4:
1153     case 0x20d0:
1154     case 0x21b0:
1155     case 0x21b8:
1156     break;
1157 dpavlin 12
1158 dpavlin 14 /* Perform graphics operation: */
1159     case 0x21f8:
1160     {
1161     uint32_t op = d->reg[0x2060 / sizeof(uint32_t)];
1162     uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1163     uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1164     >> 16) & 0xfff;
1165     uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1166     uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1167     >> 16) & 0xfff;
1168     uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1169 dpavlin 22 uint32_t y;
1170 dpavlin 12
1171 dpavlin 14 op >>= 24;
1172    
1173     switch (op) {
1174     case 1: /* Unknown. Used after drawing bitmaps? */
1175     break;
1176     case 3: /* Fill: */
1177     if (x2 < x1) {
1178     int tmp = x1; x1 = x2; x2 = tmp;
1179     }
1180     if (y2 < y1) {
1181     int tmp = y1; y1 = y2; y2 = tmp;
1182     }
1183     for (y=y1; y<=y2; y++) {
1184     unsigned char buf[1280];
1185     int length = x2-x1+1;
1186     int addr = (x1 + y*1280);
1187     if (length < 1)
1188     length = 1;
1189     memset(buf, color, length);
1190     if (x1 < 1280 && y < 1024)
1191     cpu->memory_rw(cpu, cpu->mem,
1192     0x38000000 + addr, buf,
1193     length, MEM_WRITE,
1194     NO_EXCEPTIONS | PHYSICAL);
1195     }
1196     break;
1197    
1198     default:fatal("\n--- MTE OP %i color 0x%02x: %i,%i - "
1199     "%i,%i\n\n", op, color, x1,y1, x2,y2);
1200     }
1201     }
1202     break;
1203    
1204     case 0x29f0:
1205     /* Pixel output: */
1206     {
1207     uint32_t data = d->reg[0x20c4 / sizeof(uint32_t)];
1208     uint32_t color = d->reg[0x20d0 / sizeof(uint32_t)]&255;
1209     uint32_t x1 = (d->reg[0x2070 / sizeof(uint32_t)]
1210     >> 16) & 0xfff;
1211     uint32_t y1 = d->reg[0x2070 / sizeof(uint32_t)]& 0xfff;
1212     uint32_t x2 = (d->reg[0x2074 / sizeof(uint32_t)]
1213     >> 16) & 0xfff;
1214     uint32_t y2 = d->reg[0x2074 / sizeof(uint32_t)]& 0xfff;
1215 dpavlin 22 size_t x, y;
1216    
1217 dpavlin 14 if (x2 < x1) {
1218     int tmp = x1; x1 = x2; x2 = tmp;
1219     }
1220     if (y2 < y1) {
1221     int tmp = y1; y1 = y2; y2 = tmp;
1222     }
1223     if (x2-x1 <= 15)
1224     data <<= 16;
1225 dpavlin 22
1226 dpavlin 14 x=x1; y=y1;
1227     while (x <= x2 && y <= y2) {
1228     unsigned char buf = color;
1229     int addr = x + y*1280;
1230     int bit_set = data & 0x80000000UL;
1231     data <<= 1;
1232     if (x < 1280 && y < 1024 && bit_set)
1233     cpu->memory_rw(cpu, cpu->mem,
1234     0x38000000 + addr, &buf,1,MEM_WRITE,
1235     NO_EXCEPTIONS | PHYSICAL);
1236     x++;
1237     if (x > x2) {
1238     x = x1;
1239     y++;
1240     }
1241     }
1242     }
1243     break;
1244    
1245    
1246 dpavlin 4 /* Operations: */
1247     case 0x3800:
1248     if (writeflag == MEM_WRITE) {
1249     switch (idata) {
1250     case 0x11: /* zerofill */
1251 dpavlin 14 first_addr = d->reg[0x3030 / sizeof(uint32_t)];
1252     last_addr = d->reg[0x3038 / sizeof(uint32_t)];
1253 dpavlin 4 zerobuflen = last_addr - first_addr + 1;
1254 dpavlin 14 debug("[ sgi_mte: zerofill: first = 0x%016llx,"
1255     " last = 0x%016llx, length = 0x%llx ]\n",
1256     (long long)first_addr, (long long)
1257     last_addr, (long long)zerobuflen);
1258 dpavlin 4
1259 dpavlin 14 /* TODO: is there a better way to
1260     implement this? */
1261 dpavlin 4 memset(zerobuf, 0, sizeof(zerobuf));
1262     fill_addr = first_addr;
1263     while (zerobuflen != 0) {
1264     if (zerobuflen > sizeof(zerobuf))
1265     fill_len = sizeof(zerobuf);
1266     else
1267     fill_len = zerobuflen;
1268     cpu->memory_rw(cpu, mem, fill_addr,
1269     zerobuf, fill_len, MEM_WRITE,
1270     NO_EXCEPTIONS | PHYSICAL);
1271     fill_addr += fill_len;
1272     zerobuflen -= sizeof(zerobuf);
1273     }
1274    
1275     break;
1276     default:
1277 dpavlin 14 fatal("[ sgi_mte: UNKNOWN operation "
1278     "0x%x ]\n", idata);
1279 dpavlin 4 }
1280     }
1281     break;
1282     default:
1283     if (writeflag == MEM_WRITE)
1284 dpavlin 14 debug("[ sgi_mte: unimplemented write to "
1285     "address 0x%llx, data=0x%016llx ]\n",
1286     (long long)relative_addr, (long long)idata);
1287 dpavlin 4 else
1288 dpavlin 14 debug("[ sgi_mte: unimplemented read from address"
1289     " 0x%llx ]\n", (long long)relative_addr);
1290 dpavlin 4 }
1291    
1292     if (writeflag == MEM_READ)
1293     memory_writemax64(cpu, data, len, odata);
1294    
1295     return 1;
1296     }
1297    
1298    
1299     /*
1300     * dev_sgi_mte_init():
1301     */
1302     void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr)
1303     {
1304     struct sgi_mte_data *d = malloc(sizeof(struct sgi_mte_data));
1305     if (d == NULL) {
1306     fprintf(stderr, "out of memory\n");
1307     exit(1);
1308     }
1309     memset(d, 0, sizeof(struct sgi_mte_data));
1310    
1311     memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH,
1312 dpavlin 20 dev_sgi_mte_access, (void *)d, DM_DEFAULT, NULL);
1313 dpavlin 4 }
1314    

  ViewVC Help
Powered by ViewVC 1.1.26