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

Contents of /trunk/src/devices/dev_sgi_ip32.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 5 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 /*
2 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 *
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 * $Id: dev_sgi_ip32.c,v 1.46 2006/08/30 15:07:47 debug Exp $
29 *
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 DEVICE_ACCESS(crime)
110 {
111 struct crime_data *d = extra;
112 uint64_t idata = 0;
113 size_t i;
114
115 if (writeflag == MEM_WRITE)
116 idata = memory_readmax64(cpu, data, len);
117
118 /*
119 * Set crime version/revision:
120 *
121 * 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 *
125 * NetBSD 2.0 complains about "unknown" crime for 0x11, but I guess
126 * that's something one has to live with. (TODO?)
127 */
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 if ((relative_addr >= 0x18 && relative_addr <= 0x1f) ||
155 (relative_addr+len-1 >= 0x18 && relative_addr+len-1 <= 0x1f)) {
156 /*
157 * Force interrupt re-assertion:
158 *
159 * NOTE: Ugly hack. Hopefully CRMERR is never used.
160 */
161 #if 0
162 /*
163 No. If this is enabled, the mec bugs out on either NetBSD or OpenBSD.
164 TODO.
165 */
166 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 int j;
184
185 /* This is used by the IP32 PROM's
186 "reboot" command: */
187 for (j=0; j<cpu->machine->ncpus; j++)
188 cpu->machine->cpus[j]->running = 0;
189 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 #if 0
199 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 #endif
207 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 dev_crime_access, d, DM_DEFAULT, NULL);
245 machine_add_tickfunction(machine, dev_crime_tick, d,
246 CRIME_TICKSHIFT, 0.0);
247
248 return d;
249 }
250
251
252 /****************************************************************************/
253
254
255 /*
256 * dev_mace_access():
257 */
258 DEVICE_ACCESS(mace)
259 {
260 size_t i;
261 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 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 switch (relative_addr) {
273 #if 0
274 case 0x10: /* Current interrupt assertions */
275 case 0x14:
276 /* don't dump debug info for these */
277 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 break;
285 case 0x18: /* Interrupt mask */
286 case 0x1c:
287 /* don't dump debug info for these */
288 break;
289 #endif
290 default:
291 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 } 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 dev_mace_access, d, DM_DEFAULT, NULL);
326
327 return d;
328 }
329
330
331 /****************************************************************************/
332
333
334 /*
335 * dev_macepci_access():
336 */
337 DEVICE_ACCESS(macepci)
338 {
339 struct macepci_data *d = (struct macepci_data *) extra;
340 uint64_t idata = 0, odata=0;
341 int regnr, res = 1, bus, dev, func, pcireg;
342
343 if (writeflag == MEM_WRITE)
344 idata = memory_readmax64(cpu, data, len);
345
346 regnr = relative_addr / sizeof(uint32_t);
347
348 /* Read from/write to the macepci: */
349 switch (relative_addr) {
350
351 case 0x00: /* Error address */
352 if (writeflag == MEM_WRITE) {
353 } else {
354 odata = 0;
355 }
356 break;
357
358 case 0x04: /* Error flags */
359 if (writeflag == MEM_WRITE) {
360 } else {
361 odata = 0x06;
362 }
363 break;
364
365 case 0x0c: /* Revision number */
366 if (writeflag == MEM_WRITE) {
367 } else {
368 odata = 0x01;
369 }
370 break;
371
372 case 0xcf8: /* PCI ADDR */
373 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 case 0xcfc: /* PCI DATA */
378 bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ?
379 &odata : &idata, len, writeflag);
380 break;
381
382 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 struct pci_data *dev_macepci_init(struct machine *machine,
404 struct memory *mem, uint64_t baseaddr, int pciirq)
405 {
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 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
424 memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH,
425 dev_macepci_access, (void *)d, DM_DEFAULT, NULL);
426
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 #if 0
550 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 d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |=
576 (d->cur_rx_addr_index & 0x1f) << 8;
577 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 DEVICE_ACCESS(sgi_mec)
781 {
782 struct sgi_mec_data *d = (struct sgi_mec_data *) extra;
783 uint64_t idata = 0, odata = 0;
784 int regnr;
785
786 if (writeflag == MEM_WRITE)
787 idata = memory_readmax64(cpu, data, len);
788
789 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 size_t nlen = 55;
944 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 name2 = malloc(nlen);
957 if (name2 == NULL) {
958 fprintf(stderr, "out of memory in dev_sgi_mec_init()\n");
959 exit(1);
960 }
961 snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
962 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 DM_DEFAULT, NULL);
968
969 machine_add_tickfunction(machine, dev_sgi_mec_tick, d,
970 MEC_TICK_SHIFT, 0.0);
971
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 DEVICE_ACCESS(sgi_ust)
988 {
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 debug("[ sgi_ust: unimplemented write to "
1009 "address 0x%llx, data=0x%016llx ]\n",
1010 (long long)relative_addr, (long long)idata);
1011 else
1012 debug("[ sgi_ust: unimplemented read from address"
1013 " 0x%llx ]\n", (long long)relative_addr);
1014 }
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 DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d,
1037 DM_DEFAULT, NULL);
1038 }
1039
1040
1041 /****************************************************************************/
1042
1043
1044 /*
1045 * SGI "mte". This device seems to be an accelerator for copying/clearing
1046 * memory. Used by (at least) the SGI O2 PROM.
1047 *
1048 * Actually, it seems to be used for graphics output as well. (?)
1049 * The O2's PROM uses it to output graphics.
1050 */
1051 /* #define debug fatal */
1052 /* #define MTE_DEBUG */
1053 #define ZERO_CHUNK_LEN 4096
1054
1055 struct sgi_mte_data {
1056 uint32_t reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)];
1057 };
1058
1059 /*
1060 * dev_sgi_mte_access():
1061 */
1062 DEVICE_ACCESS(sgi_mte)
1063 {
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 regnr = relative_addr / sizeof(uint32_t);
1072
1073 /*
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 if (writeflag == MEM_WRITE)
1087 d->reg[regnr] = idata;
1088 else
1089 odata = d->reg[regnr];
1090
1091 #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 /*
1099 * 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 *
1103 * 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 *
1110 * write to 0x1700, data=0x80001ea080001ea1 <-- also containing the
1111 * write to 0x1708, data=0x80001ea280001ea3 address to fill (?)
1112 * write to 0x1710, data=0x80001ea480001ea5
1113 * ...
1114 * write to 0x1770, data=0x80001e9c80001e9d
1115 * write to 0x1778, data=0x80001e9e80001e9f
1116 */
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 /* 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
1158 /* 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 uint32_t y;
1170
1171 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 size_t x, y;
1216
1217 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
1226 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 /* Operations: */
1247 case 0x3800:
1248 if (writeflag == MEM_WRITE) {
1249 switch (idata) {
1250 case 0x11: /* zerofill */
1251 first_addr = d->reg[0x3030 / sizeof(uint32_t)];
1252 last_addr = d->reg[0x3038 / sizeof(uint32_t)];
1253 zerobuflen = last_addr - first_addr + 1;
1254 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
1259 /* TODO: is there a better way to
1260 implement this? */
1261 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 fatal("[ sgi_mte: UNKNOWN operation "
1278 "0x%x ]\n", idata);
1279 }
1280 }
1281 break;
1282 default:
1283 if (writeflag == MEM_WRITE)
1284 debug("[ sgi_mte: unimplemented write to "
1285 "address 0x%llx, data=0x%016llx ]\n",
1286 (long long)relative_addr, (long long)idata);
1287 else
1288 debug("[ sgi_mte: unimplemented read from address"
1289 " 0x%llx ]\n", (long long)relative_addr);
1290 }
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 dev_sgi_mte_access, (void *)d, DM_DEFAULT, NULL);
1313 }
1314

  ViewVC Help
Powered by ViewVC 1.1.26