gxemul-0.6.1/000755 001750 001750 00000000000 13402411502 013225 5ustar00debugdebug000000 000000 gxemul-0.6.1/demos/000755 001750 001750 00000000000 13402411502 014334 5ustar00debugdebug000000 000000 gxemul-0.6.1/HISTORY000644 001750 001750 00000752340 13402411501 014323 0ustar00debugdebug000000 000000 Changelog for GXemul: --------------------- 20030829 Skeleton. ELF stuff. Some instructions. 20030830 Simple test programs using +-*/^|&%, function calls, loops, and stuff like that work. 20030903 Adding more instructions, fixing some bugs. 20030907 Making adding of memory mapped devices easier, although the framework isn't built for speed. Adding a -q switch to turn of debug output. 20030911 Trying to fix some bugs. Minor changes. Some COP0 registers are now meaningful. 20030919 Making APs (non-bootstrap cpus) available via a simple 'mp' device. Implementing ll/lld and sc/scd (for atomic memory updates, needed by MP operating systems). 20030923 Minor updates: more instructions (divu, mulu, lwu, perhaps some more), and opcode usage statistics. 20030924 If the next instruction is nullified (for 'branch likely' type of instructions), counters for delays etc are now decreased as they should. Adding some comments. Adding instructions: movz, movn. Adding a simple mandelbrot test to mipstest.c. 20030925 Adding instructions: bltzl, bgezl, lh, lhu, sh, mfc*, mtc*. Adding a dummy instructions: sync, cache. Adding minimal DECstation PROM functionality: printf() and getsysid() callback functions. Beginning work on address translation. 20030927 Adding some more cop0 functionality (tlb stuff). Adding mc146818 real-time clock. (Skeleton stuff.) 20030928 Adding a dc7085 serial console device (dummy, but enough to output chars to the screen). NetBSD uses this for the MIPSMATE 5100. 20030929 Working on the TLB stuff. Adding instructions: srlv, tlbwr, tlbr, tlbp, eret. 20030930 Trying to find a bug which causes NetBSD to bug out, but it is really hard. Adding some a.out support (for loading an old OpenBSD 2.8/pmax kernel image). Adding instructions: lwc*, ldc*, swc1 and swc3. Beginning to add special code to handle the differences between R4000 (the default emulation) and R2000/R3000. 20031001 Symbol listings produced by 'nm -S' can be used to show symbolic names for addresses. (-S) 20031002 Fixing the i/d fake cache for R2000/R3000. It's still just an ugly hack, though. Fixing minor bugs to make the 3100 emulation use the dc device (serial console) correctly. So far, 5100 and 3100 are the only ones that get far enough to print stuff, when booting NetBSD. 20031004 Adding skeleton Cobalt machine emulation (-E). Adding a dummy ns16550 serial controller, used by the Cobalt machine emulation. 20031006 Adding unaligned load/store instructions (lwl, lwr, ldl, ldr, swl, swr, sdl, sdr), although they are not tested yet. Fixed a "data modified on freelist" bug when running NetBSD/cobalt: setting the top bit of the index register when a tlbp fails (as the R4000 manual says) isn't sufficient, I had to clear the low bits as well. Adding break and syscall instructions, but they are not tested yet. Adding a 'gt' device, faking a PCI bus, for the Cobalt emulation. 20031008 Adding initial support for HPCmips (-F), a framebuffer device using X11. NetBSD/hpcmips can output pixels to the framebuffer, but that's about it. 20031009 Fixing the NetBSD/pmax bug: the "0/tftp/netbsd" style bootstring was only passed correctly in the bootinfo block, it needs to be passed as argv[0] as well. Adding instructions: mtlo, mthi. Rearrangning the source tree layout. Adding console input functionality. The NetBSD/cobalt kernel's ddb can now be interacted with. 20031010 Adding experimental (semi-useless) -t option, to show a function call tree while a program runs. Linux/cobalt now prints a few messages, but then hangs at "Calibrating delay loop..." unless an ugly hack is used (setting a word of memory at 0x801e472c to non-zero). 20031013 Adding a framebuffer device used in DECstation 3100; VFB01 for mono is implemented so far, not yet the VFB02 (color) variant. Rewriting the framebuffer device so that it is usable by both HPCmips and DECstation emulation. 20031014 Minor fixes. Everything should compile and run ok both with and without X11. 20031015 Adding support for ECOFF binary images; text, data, and symbols are loaded. (Playing around with ultrixboot and ultrix kernels.) 20031016 The DECstation argv,argc stuff must be at 0xa0000000, not 0x80000000, or Ultrix kernels complain. Adding R2000/R3000 'rfe' instruction. Implementing more R2K/R3K tlb specific stuff, so that NetBSD boots and uses the tlb correctly, but much of it is ugly. (Needs to be separated in a cleaner way.) ECOFF symbols sizes are now calculated, so that offsets within symbols are usable. 20031017 DECstation bootstrings now automatically include the correct name of the kernel that is booting. Ultrix boots a bit. 20031018 ELF symbols are now read automatically from the binary. -t trace looks a bit better (string arguments are shown). Trying to get initial R5900 stuff working (the 128-bit CPU used in Playstation 2). Fixing a minor bug to make the VFB02 (color framebuffer) device work better, but it is still just 256 grayscales, not real color. Ultrix can now use the framebuffer (it calls it PMAX-CFB). A machine can now consist of CPUs of different types. Adding instructions: daddi, mov_xxx, mult_xx. The xxx instructions are not documented MIPS64 instructions, but NetBSD/playstation2 uses them. Perhaps VR5432 instructions? Adding sign-extension to 32-bit mult. Adding Playstation 2 devices: dmac (DMA controller), gs (Graphic something?), and gif (graphics something else, which has access to the PS2's framebuffer). NetBSD/playstation2 works a bit, and prints a few bootup messages. 20031020 The cpu_type field of the cpu struct now contains usable values in a much better form than before. This simplifies adding of new CPU types. 20031021 Fixing an interrupt related bug: pc_last was used, but for interrupts this was incorrect. Fixed now. Fixing a load/store related bug: if a load into a register was aborted due to an exception, the register was still modified. The mc146818 rtc now reads its time from the system's time() function. Fixing another exception bug: if loading an instruction caused an exception, something bogus happened as the emulator tried to execute the instruction anyway. This has been fixed now. 20031023 Adding a quick hack which skips "while (reg --) ;" kind of loops. NetBSD/pmax suddenly reached userland (!), but only once and attempts to repeat it have failed. I believe it is problems with my interrupt handling system. 20031024 Adding 8-bit color palette support to the framebuffer. Connecting the pmax vdac device to the framebuffer's rgb palette. Fixing a bug in the dc device, so that console input is possible; interaction with NetBSD/pmax's built-in kernel debugger works now. Symbol sizes for file formats where symbol size isn't included are now calculated regardless of file format. Physical memory space can now be smaller than 64 bits, improving emulation speed a bit. Doing other minor performance enhancements by moving around some statements in critical parts of the code. 20031025 Minor changes to the dc device. 20031026 Adding support for reading symbols directly from a.out files. (Works with OpenBSD/pmax binaries.) Hardware devices may now register "tick functions" at specific cycle intervals in a generic fashion. All four channels of the dc serial controller device should now work; playing around with keyboard scan code generation when using the DECstation framebuffer. Making various (speed) improvements to the framebuffer device. 20031027 Playing around with the sii SCSI controller. 20031028 Minor fixes. Adding an SGI emulation mode (-G), and some ARCBIOS stuff, which SGIs seem to use. Adding getbitmap() to the DEC prom emulation layer, so some more -D x models become more usable. Adding a dummy 'ssc' serial console device for DECsystem 5400 emulation. Playing around with TURBOchannel stuff. 20031030 Minor fixes. Adding the sub instruction. (Not tested yet?) Sign-extending the results of multu, addi,addiu, add,addu,sub,subu,mfcZ. Adding a colorplanemask device for DECstation 3100. Fixed the NetBSD/pmax bug: I had forgotten to reset asid_match to 0 between tlb entry checks. :-) Now userland runs nicely... 20031031 Fixing more bugs: unaligned load/store could fail because of an exception, but registers could be "half updated". This has been fixed now. (As a result, NetBSD/pmax can now run with any of r2000,r3000,r4000, r4400, or r5000.) Adding some R5K and R10000 stuff. (Note: R5K is NOT R5000. Weird.) Adding dummy serial console (scc) for MAXINE. MAXINE also works with framebuffer, but there is no color palette yet (only black and white output). 20031101 Moving code chunks around to increase performance by a few percent. The opcode statistics option (-s) now shows opcode names, and not just numbers. :-) Fixing the bug which caused NetBSD/pmax to refuse input in serial console mode, but not in keyboard/ framebuffer mode: the osconsole environment variable wasn't set correctly. Adding DEC PROM getchar() call. The transmitter scanner of the dc device now scans all four channels at once, for each tick, so serial output is (approximately) 4 times faster. 20031103 Adding a dummy BT459 vdac device, which does nothing but allows a PMAG-BA turbochannel graphics card to be used as framebuffer. Several DECstation machines (-D 2, 3, and 4) can now use TURBOchannel option card framebuffers as console, for output. (Keyboard input is still not implemented for those models.) Only PMAG-AA (1280x1024x8) and PMAG-BA (1024x864x8), both using BT459 vdac, have been tested so far. Modifying the X11 routines so that several framebuffer windows now can be used simultaneously (if several graphics option cards are to be emulated concurrently). 20031104 DEC MIPSMATE 5100 (KN230) interrupts are shared between devices. I've added an ugly hack to allow that to work, which makes it possible to boot NetBSD into userland with serial console. 20031106 Removing the -S (symbol) option, as symbol files can now be given in any order together with other file names to be loaded. cookin tipped me about using (int64_t) (int32_t) casts instead of manually sign-extending values. Casting sometimes increases performance, sometimes decreases. It's tricky. Importing mips64emul into CVS. 20031107 Adding a generic ARC emulation mode. Increasing performance of the framebuffer by not updating it (or the XImage) if a write to the framebuffer contains exactly what is already in it. (This improves scrolling speed and initialization.) Adding initial MIPS16 support. Adding initial disk image support (-d command line option), but this will not be used until I get some kind of SCSI-controller emulation working. 20031108 Adding the first MIPS16 instructions: "move y,X", "ld y,D(x)", and "daddiu S,K" (but the last one doesn't work yet). Fixing the console environment variable for Enough of the 'asc' controller is now implemented to let NetBSD get past scsi disk detection when no disk images are used. DECstation machine type 2; both serial console and graphical console work now. Other X-windows bit-depths than 24 bits work now, but colors are still not correct in non-24 bit modes. Keypresses in X framebuffer windows are now translated into console keypresses. (Normal keys, but not cursor keys or other special keys.) 20031111 Adding support for X11 using non-24-bit output. 20031120 Adding X11 mouse event to emulated mouse event translation, but it's not tested yet. Trying to get more of the SCSI controller emulation to work. 20031124 Raw binaries can now be loaded into memory. 20031204 Adding srec binary support. 20031220 Adding some super-ugly arcbios emulation code. Making some progress on the SGI and ARC machine emulations. 20031222 SGI and ARC progress. Multiple CPUs are now added to the arcbios component tree (although NetBSD cannot actually use more than one). 20031228 Adding 'crime' and 'macepci' fake devices for SGI emulation. Finally implementing the cop0 'compare' register. Improvements to the ns16550 device, but it is still incomplete. SGI userland is now reached, but interaction is broken (due to the buggy ns16550). 20031229 Adding some more instructions: teq, dsllv Adding a Nintendo 64 emulation mode (skeleton). Adding R4300 and R12000 to the cpu list. 20031230 Adding bltzal, bltzall, bgezal, bgezall (not really tested yet). Fixing the 16550 serial controller device (by not supporting fifo, so in fact it emulates a 16450 instead). This causes NetBSD/sgimips to run nicely into userland, sysinst, and so on. Some ARC/RD94 interrupts seem to work ok now, but i/o interrupts are still not correctly implemented. NetBSD/arc userland is reached and can be interacted with, but there's no sysinst (?). 20040103 Trying to get some Irix stuff to work, but it's hard. Fixing some Cobalt/linux problems. 20040104 Adding a dummy 8250 device, so that Linux/sgimips can output console messages. Adding dmultu. (The same as dmult, so I'm not sure it's correct. Perhaps dmultu is correct and dmult is wrong...) Fixing a bug in unaligned load/stores of 64-bit values (a cast was needed). Linux/sgimips in 64-bit works a bit more than before. Adding simple (polled) input functionality to dev_zs. Making some progress on SGI-IP22 (IP32 still works best, though). Fixing the mc146818 clock device in ARC/NEC and SGI emulation modes, the year field was not correct. Adding a fake 'pref' instruction (lwc3). 20040106 Separating out memory.h from misc.h. Refactoring of a lot of small code fragments. The PCI bus device is now shared between Cobalt, SGI, and ARC. Support for RAM mirroring (dev_ram.c, not really tested yet). Ugly hack to select the largest of ELF string symbol tables, if there are more than one. Memory hole fix for ARCBIOS, and a fix for very large (>= 4GB) amounts of emulated RAM. TGA (DEC 21030) PCI graphics device. NetBSD/arc can boot with this card and use it as a framebuffer console. 20040107 Adding a fix (partly incorrect) to daddi, to allow Linux/sgimips to boot in 64-bit mode. 20040108 Fixing a sll/nop bug (rd==0 for nop, not sa==0 as before). 20040109 Trying to get an SGI-IP32 PROM image to boot. 20040110 Faking R10000 cache things. The PROM image boots, although it takes almost forever for it to realize that there is no keyboard. The 'gbe' SGI-IP32 graphics device works enough to display the Linux framebuffer penguin in the upper left corner :-) 20040111 -p and -P addresses can now be given as symbol names, not just numeric values. Experimenting with adding a PCIIDE (dev_wdc) controller to the Cobalt emulation. 20040120 Adding src/bintrans.c. No code yet, but this is a place for ideas to be written down. Increasing performance a little bit by inlining the check for interrupts (which occurs for every instruction). 20040124 Experimenting with pure userland (syscall) emulation. 20040127 Fixes for compiling under Solaris. 20040206 Some bintrans experiments. 20040209 Adding some simple Ultrix userland emulation syscalls. 20040211 Adding decprom_dump_txt_to_bin.c to the experiments/ dir. Adding a section to doc/ on how to use DECstation PROM dumps. Adding a hello world example to doc/ as well. 20040218 TURBOchannel slots that are empty now return a DBE exception, so that Ultrix and DECstation PROMs don't complain about broken TURBOchannel ROMs. Working some more on the machine-dependant interrupt stuff. 20040219 Trying out some Linux/DECstation kernels (semi-successfully). 20040222 YES! I finally found the bug that caused Linux/SGI-IP32 to only work on Alpha, not on 32-bit machines. It was a shift left, probably done using 6 bits on alpha, 5 bits on 32-bit machines. 20040223 Some minimal DEC KN5800 progress; Ultrix prints some boot messages, detects 16 XMI R3000 cpus, and get a NULL panic. It's all fake, though, the CPUs don't actually work. Still, better than nothing :-) 20040225 An Ultrix OSF1 kernel with a ramdisk now boots :-) (It was a problem with ultrixboot not giving the same arguments as NetBSD's boot program.) 20040225(later) Fixing a bug in the DECstation dc serial device; digits 0-9 were translated to numeric keypad 0-9, not the normal 0-9. (This caused Ultrix to print escape sequences instead of digits.) 20040226 Some progress on machine-dependant interrupt delivery for -D7 (Maxine) and -D4, and some more 'scc' serial controller featuers are implemented (but no interrupts/ dma/keyboard/mouse stuff yet). 20040228 Progress on the scc controller; -D4 works in both serial console mode and with keyboard (graphical console), but no mouse yet. 20040301 SGI mace interrupts are now done using the new machine- independant interrupt system. 20040303 Fixing an R5900 bug; the lowest 6 bits have special meaning for coprocessor functions, not just 5 bits as on non-R5900 CPUs. (This fixes a bug which caused NetBSD to crash.) 20040304 Adding enough (fake) DMA capabilities to the ioasic device to allow Ultrix to print boot messages in the -D3, -D4, and -D7 modes, and also print graphical console messages in -D4 and -D7 modes. -D11 (DEC5500) polled getchar added (to the 'ssc' device). Adding the 'madd' instruction (including R5900 weird stuff). 20040304(later) Playstation 2's GIF can now copy 640x16 pixel chunks, allowing NetBSD to scroll up the framebuffer. The cursor also works better now. Playstation 2 bootinfo RTC data should now be passed correctly to the running kernel. DECstation rtc year should be either 72 or 73, anything else will cause Ultrix to give a warning about invalid year. 20040306 Combining playstation2's dmac, interrupt, and timer devices into one (ps2_stuff). Adding some R5900 instructions: mfsa, mtsa, pmfhi, pmflo, por, lq, and sq. (Most of them are just guesses, though.) Implementing my own XImage putpixel routine, which can be inlined... significantly faster than normal XPutPixel. :-) 20040307 Implementing the basic functionality of a "PMAG-CA" pixelstamp accellerated framebuffer device. Works with NetBSD and Ultrix, but no cursor or color support. 20040308 PMAG-CA, -DA, and -FA pixelstamps seem to work now. Adding a hack to allow a pmax/mach kernel to be loaded (it's a COFF file with 0 (!) sections). Initial test of bt459 + framebuffer cursor support. 20040309 Fixes/updates of dev_dec5800 and dev_ssc (and dev_decxmi) allow a KN5800 Ultrix-OSF1-ramdisk kernel to boot all the way into userland and be interacted with. The bt459 cursor should now look semi-nice, but it is still a bit fake. 20040310 Moving the DEC CCA stuff from src/machine.c into a separate device file (devices/dev_deccca.c). An ugly hack added to allow some more OSF/1 kernels (almost a.out, but without many of the header fields) to load. 20040314 Adding PMAG-JA and PMAG-RO (1280x1024 x 8-bit) TURBOchannel graphics devices. They work in Ultrix, but only monochrome and no cursor, because there are no ramdacs or such yet. 20040315 Pixelstamp solid fill now supports colors other than just zero-fill. Adding a (new) regression test skeleton. 20040321 Some really minor updates. 20040323 Fixes to allow SGI-IP20 and IP22 to work a bit better (aliased memory), and adding "private" firmware-like vectors to arcbios emul. An IP22 Irix kernel gets far enough to print an assertion warning (and then double panics). :-) 20040324 Adding a generalization hack to the SCC serial controller to work with SGI-IP19 (in addition to DECstations). Adding the 'sdc1' instruction. Some progress on various SGI emulation modes. 20040325 Minor updates. 20040326 Fixed a 'madd' bug (r5900). NetBSD/playstation2 now reaches userland correctly. And a simple fix which allows NetBSD timer interrupts to be triggered; NetBSD uses T_MODE_CMPE (compare), while Linux uses _OVFE (overflow). 20040328 Linux on Playstation 2 boots a bit. The Playstation 2 graphics controller has been extended to work better with NetBSD, and to include some Linux support as well. Some interrupt handling enhancements on Playstation 2, needed for Linux' dma. 128-bit loads and stores (lq and sq) are allowed, although the top half of quadwords are not modified by other instructions. (Linux uses lq and sq.) Big-endian X Windows servers now display correct rgb color, not bgr as before. 20040330 Some minor updates to the documentation. 20040401 Adding a dummy ps2 OHCI device. 20040402 Progress on the asc SCSI controller. 20040406 Hack to allow ./configure, make to work on HP-UX B.11.00 on HPPA-RISC, gcc 3.3.2. (Does not work with HP's cc.) More progress on the asc SCSI controller. Fixing INQUIRY, adding READ_CAPACITY, adding READ. Works a bit with NetBSD and some (but not all) Ultrix kernels, on DECstation type 2. Adding WRITE, SYNCRONIZE_CACHE. Mounting disks works in NetBSD :-) It is a bit buggy, though. Or something else is buggy. 20040407 The bug is triggered by gunzip during NetBSD/pmax install. 20040408 Fixing a bug (non-nul-terminated string) which caused X11 cursors to not display on Solaris. Unnecessary X11 redraws are skipped (removes some weird delays that existed before), and cursors are redrawn on window exposure. (The cursor functionality has been moved from dev_fb.c to x11.c.) 20040411 Fixing the DC7085 device so that Ultrix doesn't behave weird if both tx and rx interrupts occur at the same time. More advancements on the asc SCSI controller. More disk image filename prefixes are now recognized; c (for CD-ROM, as before), d for disk, b for boot device, r for read-only, and 0-7 for scsi id. Mounting disks works in Ultrix. Installing to disk usually crashes for various reasons, but an OSF/1 install gets relatively far (similar to the NetBSD/pmax install). 20040412 Trying to find the bug. 20040415 Finally found and fixed the bug; SCSI reads and writes (actually, any data in or data out) can be split up into multiple DMA transfers. That stuff was only partially implemented, and the part that was implemented was buggy. It works now. NetBSD/pmax and Ultrix 4.3 seems to like the SCSI stuff enough to install almost all the way. 20040415 (more) Adding a hack which allows a host's cdrom device to be used as a cdrom device inside the emulator, eg /dev/cd0c. Making the cycle counter int64_t instead of long, as a 'long' overflows too easily on 32-bit machines. (The bug is still there, though.) I've now verified that a full NetBSD/pmax install can be done. If using a PMAG-AA graphics board, startx brings up X :-) mips64emul can be compiled inside NetBSD inside mips64emul, and it can run NetBSD in that environment. (I'm getting dizzy... :-) 20040417 Moving some coprocessor stuff from cpu.c to coproc.c. 20040424 Adding a BT455 vdac for PMAG-AA. Black and white are now rendered correctly in Xpmax. Adding colormap support to the BT459 device, for PMAG-BA. 20040425 Fixing a buffer length bug, which caused an Ultrix 4.5 install to bug out on an i386 host. 20040429 FPU experiments. 20040502 More FPU experiments. Speedup for exception debug messages: in quiet mode, debug messages were still evaluated, which took a relatively large amount of time. 20040503 Most FPU stuff fixed, but there is at least one known bug left; ps axu in NetBSD triggers it (ps loops forever). 20040504 A default install of Ultrix 4.5 succeeded! It boots up with a graphical login. Fixing the keyboard repetition bug (a lk201 "up" (release) scancode is now sent after every key). 20040505 Both CR and LF now produce the same lk201 scancode, so that pressing 'enter' works as expected in Ultrix. 20040506 Adding a vaddr to paddr translation cache, causing a speedup of perhaps 50% or more. 20040507 Fixing PMAG-BA color for Ultrix. (Ultrix relies on interrupts coming from the TURBOchannel slot to update the palette.) 20040508 Fixing cursor positioning for PMAG-BA. 20040511 Prints current nr of instructions per seconds, not only average, when using -N. 20040515 Some more bintrans experiments. 20040606 Adding ARCBIOS GetReadStatus() and Read(). Adding some instructions: tlt, tltu, tge, tgeu, tne. 20040607 Adding the dsub instruction. Some minimal progress on SGI-IP30 emulation. Applying a patch from Juli Mallett to src/file.c (I'm not sure yet if it breaks or fixes anything). Some minor fixes for SGI-IP22 (such as faked board revision numbers). 20040608 ll/sc should now fail if any unrelated load/store occurs. Minor changes to the configure script. Adding some ifdefs around code which is not often used (the mfhi/mflo delay, and the last_used TLB experimental code); this might cause a tiny speedup. 20040609 Minor fixes. 20040610 Various minor SGI fixes (64-bit ARCS stuff, progress on the CRIME/MACE interrupt system, and some other random things). 20040611 More crime/mace progress, and some more work on pckbc. KN5800 progress: adding a XMI->BI adapter device; a disk controller is detected (but it is just a dummy so far). 20040612 Adding "dev_unreadable", which simplifies making memory areas unreadable. (NetBSD on SGI-IP22 no longer detects non-existant hpc1 and hpc2 busses.) Implementing rudimentary support for IP22 "local0" and "local1" interrupts, and "mappable" local interrupts. Some progress on the WDSC SCSI controller on IP22, enough to let NetBSD get past the disk detection and enter userland! :-) The zs (zilog serial) device now works well enough to let NetBSD/sgimips be interacted with on IP22. :-) (Though it is very ugly and hardcoded.) 20040613 IP32 didn't work last night, because there were too many tick functions registered. That has been increased now. Trying out NetBSD/sgimips 2.0 beta kernels. There are some differences compared to 1.6.2, which I'm trying to solve. Interrupt fixes for IP32: _serial and _misc are different. Separation of IP22 (Full-house) and IP24 (Guiness). 20040614 Modifying the memory layout for IP20,22,24,26 (RAM is now offset by 128MB, leaving room for EISA registers and such), and moving around some code chunks. This is not well tested yet, but seems to work. Moving parts of the tiny translation cache, as suggested by Juli Mallett. It seems that the speedup isn't as apparent as it was a few weeks ago, though. :-( Speedups due to not translating addresses into symbol names unless the symbol name is actually printed. Added support for loading old big-endian (Irix) ECOFF kernels (0x60 0x01 as the first two bytes). 20040615 (late) Adding enough SGI IP20 (Indigo) support to let NetBSD 2.0 enter userland :-) No interrupt specifics are implemented yet, so it hangs while doing terminal output. 20040618 Experimenting with the WDSC SCSI controller for IP20,22,24. 20040620 Adding a program which converts SGI prom dumps from text capture to binary, and some hacks to try to make such an IP22 PROM to work better in the emulator. 20040621 Removing the Nintendo 64 emulation mode, as it is too uninteresting to support. Adding SCSI tape device support (read-only, so far). Fixing a bug which caused the cursor to be corrupted if new data was written to the framebuffer, but the cursor wasn't moved. 20040622(early) Finally! Making progress on the SCSI tape stuff; when going past the end of a file, automagically switch to the beginning of the next. 20040622(late) Trying to track down the last SCSI tape bugs. Removing _all_ dynamic binary translation code (bintrans), starting from scratch again. 20040623(early) Performing a general code cleanup (comments, fixing stuff that led to compiler warnings, ...). Disabling MIPS16 support by default, and making it a configure time option to enable it (--mips16). This gives a few percent speed increase overall. Increasing performance by assuming that instruction loads (reading from memory) will be at the same page as the last load. (Several percent speedup.) Moving the list of kernels that can be found on the net from README to doc/. 20040624 Finally! I found and fixed the bug which caused 'ps', 'top', 'xclock', and other programs in NetBSD/pmax to behave weird. Increasing performance by a few percent by running as many instructions in a row as possible, before checking for hardware ticks. When booting from SCSI tapes on DECstation, the bootstring now contains 'tz' instead of 'rz'. Adding a second ARC machine mode, "Acer PICA-61", -A2. Disabling the support for "instruction delays" by default (it has to be enabled manually in misc.h now, but is never used anywhere anyway). Other minor optimizations (moving around stuff in the cpu struct in misc.h, and caching cpu->pc in cpu.c). Separating the tiny translation cache into two, one for code and one for data. This gives a few percent speed increase. 20040625(early) I think now is a good time for a "feature freeze", to let the code stabilize and then make some kind of first release. 20040625(later) Adding a -v (verbose) command line option. If -v is not specified, the emulator goes into -q (quiet) mode just before it starts to execute MIPS code. 20040627 The configure script now adds -fomit-frame-pointer to the compile flags if the $CC seems to be able to handle that. Found and fixed a serious interrupt bug in BT459 (Ultrix' behaviour required a hack, which was incorrect), so performance for machines using the PMAG-BA framebuffer is now improved. For X11 bitdepths other than 8 or 24, a warning message is printed at startup. A number of other minor fixes, optimizations, updated comments and so on. Adding a BUGS file, a list of known bugs. Adding a minimal man page, doc/mips64emul.1. 20040628 Hacks for faking the existance of a second level cache (ARCBIOS and other places). An important fix for dc7085: tx interrupts should happen before rx interrupts, not the other way around as it was before. (This speeds up NetBSD boot on DECstation, and fixes a bug which Ultrix triggered on heavy keyboard input.) A couple of other minor fixes. Framebuffer fix: there was a bug which caused the rightmost/ bottom pixel to sometimes not be updated, when running in scaledown mode. This is now fixed. Adding a small program which removes "zero holes" from harddisk image files. 20040629 More minor fixes. 20040629(later) Adding -A3 (NEC RISCstation 2200) (this is similar to the 2250 model that NetBSD/arc can already boot all the way into userland and be interacted with), and -A4 (Deskstation Tyne). Some more minor fixes. 20040630 Adding support for 15 and 16 bits X11 framebuffers, and converting from XYPixmap to ZPixmap (this fixes the problem of updates appearing in "layers" on some X servers). The pixels in the mouse cursor (for BT459) are now colored as the emulated OS sets them, although no transparency masking is done on the edges of the cursor yet. (In plain English: the mouse cursor is no longer just a white solid square, you can actually see the mouse cursor image on the white square.) ============== RELEASE 0.1 ============== 20040701 The -j option now takes a name, the of the kernel as passed on to the bootloader. ("netbsd" is the default name.) Adding support to load bootstrap code directly from a disk image, for DECstation. Both NetBSD/pmax and Ultrix boot straight of a disk image now, with no need to supply a kernel filename on the command line. (Ultrix still needs -j vmunix, though, to boot from /vmunix instead of /netbsd.) 20040702 Minor bugfix (some new untested code for X11 keypresses was incorrect). 20040702(later) Adding an ugly hack for CDROMs in FreeBSD; if an fread() isn't done at a 2048-byte aligned offset, it will fail. The hack tries to read at 2048-byte aligned offsets and move around buffers to make it work. Adding video off (screen blanking) support to BT459. ============== RELEASE 0.1.1 ============== 20040702(later) Cleanup to remove compiler warnings (Compaq's cc, Solaris' cc, and gcc 3.3.3/3.3.4 in Linux), mostly by putting ULL on large numeric constants. Better support for scaledown of BT459 cursors, but still not color-averaging. Beginning the work on adding better memory latency support (instruction delays), enabled by the --delays configure option. 20040703 Modifications to the configure script so that a config.h file is created, containing things that were passed along as -Dxxx on each cc command line before. More work on instruction latency support; trying to separate the concepts of nr of cycles and nr of instructions. 20040704 Working on R2000/R3000 caches. Adding a '--caches' option to the configure script. Various small optimizations. R3000 caches finally work. (I know that there is at least one bug, regarding interrupt response.) 20040705 Working on the 'le' device, and on a generic (device independant) networking framework. le can transmit and receive packets, and the network framework fakes ARP responses from a fake gateway machine (at a fixed ip address, 10.0.0.254). Adding a '-c' command line option, which makes emulated_hz automatically adjust itself to the current number of emulated cycles per host CPU second (measured at regular intervals). 20040707 Removing the '-c' option again, and making it the default behaviour of the emulator to automatically adjust clock interrupts to runtime speed (as long as it is above 1 MHz). (This can be overridden by specifying a static clock rate with the -I option.) Updating the doc/ stuff a bit. Generalization of the DECstation bootblock loading, to work with Sprite/pmax. Lots of other minor modifications to make Sprite work, such as adding support for DECstation "jump table" PROM functions, in addition to the old callback functions. Sprite boots from a disk image, starting the kernel if the argument "-j vmsprite" is used, but it seems to not like the DBE exceptions caused by reading empty TURBOchannel slots. :-/ 20040708 Minor changes and perhaps some tiny speed improvements. The Lance chip is (apparently) supposed to set the length of received packets to len+4. (I've not found this in any documentation, but this is what NetBSD expects.) So now, ICMP echo replies work :-) UDP works in the outgoing direction, in the incoming direction, tcpdump can see the packets but they seem to be ignored anyway. (Weird.) Adding a separate virtual-address-to-host-page translation cache, 1-entry for loads, 1-entry for stores. (For now, it only works on R4000 as there are conflicts with cache usage on R3000). Changing the lower clock speed bound from 1 MHz to 1.5 MHz. 20040709 Incoming UDP checksums were wrong, but are now set to zero and NetBSD inside the emulator now accepts the packets (eg. nameserver responses). Host lookups and even tftp file transfers (using UDP) work now :-) Adding a section on Networking to the Technical documentation, and a preliminary NetBSD/pmax install instruction for network installs to the User documentation. Some updates to the man page. 20040709(later) Fix to the TURBOchannel code to allow Sprite to get past the card detection. Seems to still work with Ultrix and NetBSD. This also makes Linux/DECstation properly recognize both the Lance controller and the SCSI controller. Linux 2.4.26 from Debian boots nicely in framebuffer mode :-) 20040710 Some bits in the KN02 CSR that were supposed to be readonly weren't. That has been fixed, and this allows Linux/DECstation to get past SCSI detection. :-) Minor updates to the ASC controller, which makes Linux and OpenBSD/pmax like the controller enough to be able to access SCSI devices. OpenBSD/pmax boots from a disk image for the first time. :-) Linux detects SCSI disks, but I have no bootable Linux diskimage to test this with. Updating the doc/ to include instructions on how to install OpenBSD/pmax onto a disk image. Naively added a PMAGB-BA (1280x1024x8) in hopes that it would basically be a PMAG-BA (1024x864x8) in higher resolution, but it didn't work that way. I'll have to look into this later. Adding a -o option, useful for selecting '-s' (single user mode) during OpenBSD install and other things. After a lot of debugging, a serious bug related to the tiny cache was found; Linux just changes the ASID and returns when switching between processes in some occasions without actually _writing_ to the TLB, and I had forgotten to invalidate the tiny cache on such a change. 20040711(early) I've been trying to repeat the OpenBSD install from yesterday, but appart from the first initial install (which was successful), I've only been able to do one more. Several attempts have failed with a filesystem panic in the middle of install. I'm not sure why. 20040711 I found the "bug": wget downloaded the simpleroot28.fs.gz file as read-only, and gunzip preserved those flags. Thus, OpenBSD's installer crashed as it didn't get its writes through to the disk. Parts of the 1280x1024x8 PMAGB-BA graphics card has been implemented, it works (unaccelerated) in NetBSD and OpenBSD, but Ultrix does not seem to like it. Cleaned up the BT459 cursor offset stuff a bit. Trying to make the emulated mouse coordinates follow the host's mouse' coordinates (for lk201, DECstation), by "de-accelerating" the data sent to the emulated OS. 20040711(later) Fix so that Sprite detects the PMAG-BA correctly. Adding some stuff about NFS via UDP to the documentation. Fixed the 'update flag' for seconds, so now Sprite doesn't crash because of timer-related issues anymore. Fixing KN02 interrupt masks a bit more, to make Sprite not crash. Sprite now runs quite well. 20040712 Working on IP/UDP fragementation issues. Incoming UDP packets from the outside world can now be broken up into fragments for the guest OS. (This allows, for example, OpenBSD/pmax to be installed via nfs.) Outgoing fragmented packets are NOT yet handled. Linux doesn't use 64-bit file offsets by default, which is needed when using large disk images (more than 2GB), so the configure script has now been modified to add necessary compiler flags for Linux. 20040713 Trying out some minor optimizations. Refreshing the UDP implementation in src/net.c a little. 20040714 Updating the documentation a little on how to experiment with a Debian Linux install kernel for DECstations. A 'mini.iso' Linux image for DECstation has different fields at offsets 0x10 and 0x14, so I'm guessing that the first is the load address and the second is the initial PC value. Hopefully this doesn't break anything. Some initial TCP hacks, but not much is working yet. Some updates for IP30: The load/store 1-entry cache didn't work too well with IP30 memory, so it's only turned on for "MMU4K" now. (This needs to be fixed some better way.) Adding a hack which allows Linux/Octane to use ARC write() and getchild() on IP30. Linux uses ARCBIOS_SPB_SIGNATURE as a 64-bit field, it was 32-bit before. Making ugly hacks to the arcbios emulation to semi-support 64-bit equivalents of 32-bit structures. 20040716 Minor fixes to the configure script (and a few other places) to make the sources compile out-of-the-box on HP-UX (ia64 and HPPA), old OpenBSD/pmax (inside the emulator itself), and Tru64 (OSF/1) on Alpha. A couple of other minor fixes. 20040717 A little TCP progress; OpenBSD/pmax likes my SYN+ACK replies, and tries to send out data, but NetBSD/pmax just drops the SYN+ACK packets. Trial-and-error led me to change the 64-bit ARCS component struct again (Linux/IP30 likes it now). I'm not sure about all of the offsets yet, but some things seem to work. More 64-bit ARCS updates (memory descriptors etc). Better memory offset fix for IP30, similar to how I did it for IP22 etc. (Hopefully this doesn't break anything else.) Adding a MardiGras graphics controller skeleton for SGI-IP30 (dev_sgi_mardigras.c). Thanks to Stanislaw Skowronek for dual-licensing mgras.h. Finally rewrote get_symbol_name() to O(log n) instead of O(n) (Stanislaw's Linux kernel had so many symbols that tracing with the old get_symbol_name() was unbareably slow). Removing all of the experimental tlbmod tag optimization code (the 1-entry load/store cache), as it causes more trouble than the performance gain was worth. 20040718 The MardiGras device works well enough to let Linux draw the SGI logo and output text. A bunch of other minor changes. 20040719 Trying to move out all of the instruction_trace stuff from the main cpu loop (for two reasons: a little performance gain, and to make it easier to add a GUI later on). 20040720 Finally found and fixed the ethernet/tcp bug. The hardware address is comprised of 6 bytes, where the _first_ byte should have a zero as the lowest bit, not the last byte. (This causes NetBSD and Linux running in the emulator to accept my SYN+ACK packets.) Getting the first nameserver address from /etc/resolv.conf. (This is not used yet, but could be useful if/when I add internal DHCP support.) Working more on the TCP stuff; TCP seems to be almost working, the only immediate problem left is that the guest OS gets stuck in the closing and last-ack states, when it shouldn't. It is now possible to install NetBSD and OpenBSD via ftp. :-) 20040721 Trying to fix the last-ack bug, by sending an RST after the end of a connection. (Probably not a correct fix, but seems to work?) Adding a my_fseek() function, which works like fseek() but with off_t instead of long, so that large disk images can be used on systems where long is 32 bits. 20040722 Trying to fix some more TCP related bugs. 20040725 Changing the inlined asm statement in bintrans_alpha.c into a call to a hardcoded array of bytes that do the same thing (an instruction cache invalidation). This allows the same invalidation code to be used regardless of compiler. Some other minor changes. 20040726 Minor updates. The configure script is now more verbose. A Debian/IP22 Linux tftp boot kernel requires ARCS memory to be FreeMemory, not FreeContiguous. (This should still work with other SGI and ARC OSes.) Fix for ARCS write(), so it returns good write count and success result (0). Some hacks to the IP22 memory controller, to fake 72MB RAM in bank 0. The IP22 Debian kernel reaches userland (ramdisk) when run with -G24 -M72 -CR4400, if a special hack is done to the zs device. 20040730 Removing mgras.h, as I'm not sure a file dual-licensed this way would work. (Dual-licensing as two separate files would work though.) Preparing for the upcoming release (0.2). 20040801 Fixing the 512 vs 2048 cdrom sector size bug; I hadn't implemented the mode select SCSI command. (It still isn't really implemented.) A bug which crashes the emulator is triggered when run with new NetBSD 2.0_BETA snapshots on a Linux/i386 host. I'm not sure why. UDP packets sent to the gateway (at 10.0.0.254) are now forwarded to the machine that the host uses as its nameserver. Some other minor fixes. ============== RELEASE 0.2 ============== 20040803 A post-3.5 OpenBSD/sgimips kernel snapshot with ramdisk seems to boot fine in the emulator, all the way to userland, and can be interacted with. Adding a -y option, used to set how many (random) instructions to run from each CPU at max (useful for SMP instruction interleave experiments). Importing a 8x16 console font from FreeBSD (vt220l.816). Adding a skeleton for a 80x25 text console device (dev_vga), useful for some ARC modes. (Character output is possible, but no cursor yet.) Adding a dev_zero device (returns zeroes on read). OpenBSD/arc 2.3 can get all the way to userland with -A4 (if the wdc devices are commented out) but bugs out there, probably because of interrupt issues. Adding a -A5 ARC emulation mode (Microsoft-Jazz, "MIPS Magnum") which NetBSD seems to like. No interrupt specifics yet, so it hangs while waiting for SCSI. 20040804 Some dev_mp updates. The -y switch has to do with number of cycles, not number of instructions; variable names have been changed to reflect this. 20040805 Minor updates. Adding some more CPU types/names, but they are probably bogus. Adding a MeshCube emulation mode. Just a skeleton so far, but enough to let a Linux kernel print some boot messages. Adding the 'deret' instruction. 20040806 Adding include/impactsr-bsd.h (a newer version of what was in mgras.h before, and this time with only a BSD-style license), but it is not used yet. 20040810 Some Au1500 updates. 20040811 Adding the 'clz', 'clo', 'dclz', and 'dclo' special2 (MIPS32 and MIPS64) instructions. More Au1500 updates. 20040812 Using fseeko(), when it is available. Other minor updates. Adding a NetGear WG602 emulation mode skeleton (-g); after a lot of trial and error, a Linux kernel (WG602_V1715.img) gets all the way to userland, but hangs there. 20040818 Adding signal handlers to better cope with CTRL-Z and CTRL-C. Adding a simple interactive single-step debugger which is activated by CTRL-C. (Commands so far: continue, dump, help, itrace, quit, registers, step, trace, version) 20040818(later) Adding a 'tlbdump' debugger command, and some other minor fixes. 20040819 Minor updates. Adding an 'unassemble' debugger command. 20040822 Minor updates to the regression testing framework. 20040824 Minor updates based on feedback from Alec Voropay (configure script updates for Cygwin and documentation). 20040826 Minor updates. Adding a cursor to the VGA text console device. Changing all old 11:22:..55:66 ethernet macs to 10:20..60, still hardcoded though. 20040828 Minor updates. 20040829 mips64emul is 1 year old today :-) 20040901 tests/README now lists "all" MIPS opcodes. This list should be updated whenever a new opcode is implemented, or when a regression test is added. (A combination of instructions from the TX79 manual, the GNU assembler, and the MIPS64 manual). Hopefully I haven't missed too many. Adding a section on regression testing to doc/technical.html. 20040902 Finally beginning the work on separating out the stuff from main.c into a "struct emul". Very time-consuming. Some minor fixes for LL/SC on R10000. 20040905 Moving more stuff from main.c into struct emul. Unfortunately, it seems that this causes a slowdown of the emulator. Userland emulation is now only used if --userland is used when running configure. Modifying src/symbol.c to not use global variables. 20040906 Minor update. 20040914 Using $COPTIM when detecting which compiler flags to use in the configure script. (This makes sure that combinations of flags should work.) There'll probably be a 0.2.1 release some time soon, but I'll do some more clean-up first. Minor update to the detection of ECOFF files, but I don't like it; sometimes the endianness of the magic value seems to be swapped, but it doesn't have to do with endianness of the actual data? 20040916 Minor updates. Adding an Example section to the manpage, but as I'm not really familiar with manpage formatting, it will need to be rewritten later. 20040917 Finally making the coprocessor instructions disassemblable even when not running. Doing some testing for the 0.2.1 release. ============== RELEASE 0.2.1 ============== 20040923 Updating the documentation about how to (try to) install Debian GNU/Linux. 20040924 Some more updates to the documentation. 20040925 Adding overflow stuff to 'add' and 'sub'. 20040926 Minor updates: possibly a fix to 'sltiu' (the imm value should be treated as signed, and then converted to unsigned, according to the MIPS64 manual), and removing the 'last_was_rfe' stuff (again). OpenBSD/arc used speed-hack jumps with other deltas than just +/- 1 (it used -3 iirc), so the jump speedhack should now support any delta. Also adding bgtzl and blezl as possible instructions for the speed-hack jumps. (This needs to be tested more.) 20040928 Minor updates. Some ARC stuff ("arcdiag" runs now). cpu_register_dump() now also dumps coprocessor registers. 20040929 More ARC updates. Making the code look a tiny bit nicer than before. "arcdiag.ip22" works for -G22 (SGI-IP22). Apparently the overflow support in the 'add' instruction was incorrect, so I disabled it. 20041002 Trying to install Ultrix in the emulator, but the installer crashes; found (and fixed) the bug rather quickly: the "fix" I implemented a few days ago for the 'sub' instruction (according to the MIPS64 manual) caused the bug. 20041004 Changing the behaviour of the -j command line option. The default is now "" (or taken from the last filename given on the command line), not "netbsd". In practice, this doesn't change much, except that -j netbsd.pmax is no longer needed when installing NetBSD. Adding a COMPILE_DATE string to config.h. 20041007 Adding a NEC RISCserver 4200 model (-A6), and some more updates to the ARC component tree generator. 20041008 The 'll' instruction should be signed, not unsigned as before. This (and some other minor fixes) causes Irix on SGI-IP32 (O2) to actually boot far enough to print its first boot messages :) Working on some new dynamic bintrans code. Enough is now implemented so that the 'nop' instruction is translated and there is support for Alpha, i386 and UltraSparc backends, but performance is about 50% worse than when running without bintrans. (This is as expected, though.) 20041009 Minor updates to the documentation. Using mprotect() to make sure that the code created dynamically by the bintrans subsystem is allowed to be executed. (This affects newer OpenBSD systems, and possibly others.) The translated code chunks now only get one argument passed to them, the (struct cpu *) of the current cpu. 20041010 Hack to dev_le.c which makes Ultrix accept the initialization of the LANCE controller. (This goes against the LANCE documentation though.) In src/net.c, a fix for Ultrix (which seems to send larger ethernet packets than the actual TCP/IP contents). The hack to dev_le.c and this fix is enough to let Ultrix access the Internet. For DECstation, when booting without a disk image (or when "-O" is used on the command line), use "tftp" instead of "rzX" for the boot string. 20041011 Adding cache size variables to the emul struct, so that these can be set on a per-machine basis (or potentially manually on the command line). 20041012 Mach/PMAX now passes the LK201 keyboard self-test (although the keyboard ID is still bogus). 20041013 Minor updates. Hacks to the ASC SCSI controller for Mach/PMAX, hopefully this will not break support for other OSes. 20041014 Minor fix to src/emul.c for reading bootblocks at the end of a disk or cdrom image (thanks to Alexandru Lazar for making me aware of this). Adding "gets()" to src/dec_prom.c. Working a bit on ARC stuff. Importing pica.h from NetBSD. Minor updates to the ARC component tree for PICA-61. Adding a dev_jazz.c (mostly for PICA-61). Renaming dev_jazz.c into dev_pica.c. Working on PICA timer and interrupt specifics. 20041016 Adding some dummy entries to lk201.c to reduce debug output. Some bintrans updates (don't run in delay slots or nullified slots, read directly from host memory and not via memory_rw(), try mmap() before malloc() at startup, and many other minor updates). Adding bintrans_mips.c for 64-bit MIPS hosts, but it is not used yet. 20041017 Minor updates. 20041018 Update to dev_mc146818 to allow Mach to boot a bit further. The "hardware random" in dev_mp.c now returns up to 64 bits of random. 20041019 Minor updates to the way cache sizes are used throughout the code. Should be mostly ok for R[234]x00. src/file.c now loads files using NO_EXCEPTIONS. Whether this is good or bad, I'm not sure. 20041020 Adding a Linksys WRT54G emulation skeleton (-H). 20041021 Minor updates. R1[024]000 cache size bits in the config register should now be ok. Trying to make dev_asc.c work better with PICA. More work on PICA interrupts (but they are broken now). 20041022 Generalizing the dev_vga text console device so that it can be used in other resolutions than just 80x25. Works with OpenBSD/arc. emul->boot_string_argument is now empty by default (except for DECstation modes, where it is "-a"). Speedup of dev_ram by using mmap() instead of malloc(). Using mmap() in memory.c as well, which reduces memory usage when emulating large memory sizes if the memory isn't actually written to. 20041023 Minor updates. 20041024 Updates to the PC-style keyboard controller, used by PICA. Updates to the PICA (Jazz) interrupt system. Both NetBSD/arc and OpenBSD/arc now reach userland with PICA emulation, and can be interacted with (there are a few programs on the INSTALL kernel ramdisks). In the case of OpenBSD, a VGA text console and PC-style keyboard controller is used, NetBSD runs on serial console. Adding a framework for DMA transfer for the ASC SCSI controller. Implementing a R4030 DMA controller for PICA, enough to let OpenBSD/arc and NetBSD/arc be installed on an emulated Pica. :-) Updates to the documentation. 20041025 Working on ISA interrupts for PICA. Adding an Olivetti M700 emulation mode (-A7). Better separation of PICA and M700 stuff (which I accidentally mixed up before, I thought the M700 Linux kernel would also work on PICA because it almost booted). Writing a skeleton G364 framebuffer for M700, enough to show the Linux penguin and some text, although scrolling isn't correctly implemented yet. Adding a dummy SONIC (ethernet) device, dev_sn, for PICA. Fixing the passing of OSLOADOPTIONS for ARC, the default is now "-aN" which works fine with OpenBSD/arc and NetBSD/arc. 20041027 Minor updates. 20041029 Adding a Sony NeWS "newsmips" emulation mode skeleton (-f). Found and fixed a bug which prevented Linux/IP32 from running (the speed-hack-jump-optimization fix I made a few weeks ago was buggy). Adding the trunc.w.fmt and trunc.l.fmt instructions, although the are probably not really tested yet. Changes to how floating point values are handled in src/coproc.c, but right now it is probably very unstable. 20041101 I had accidentally removed the instructions on how to install Ultrix from doc/index.html. They are back now. Adding a -Z option, which makes it easier to run dual- or tripple-head with Ultrix. (Default nr of graphics cards without -X is 0, with -X is 1.) Minor update which makes it possible to switch to the left monitor when running tripple-head, not just right as before. When using more than one framebuffer window, and the host's mouse cursor is in a different window than the emulated mouse cursor, the emulated mouse will now try to move "very far", so that it in practice changes screen. Running Ultrix with dual- and tripple-head now feels really great. 20041101(later) OpenBSD/arc and Linux/Olivetti-M700 don't both work at the same time with the speed-hack stuff. So, from now on, you need to add -J for Linux, and add nothing for openbsd. 20041102 Minor update for OSF/1 V4.0 (include sys/time.h in src/net.c and add -D_POSIX_PII_SOCKET to the C compiler flags). 20041103 Minor updates for the release. For some reason, Mach/PMAX caused the emulator to bug out on SunOS/sparc64 (compiled in 64-bit mode); a minor update/hack to dev_asc fixed this. ============== RELEASE 0.2.2 ============== 20041103 Minor updates. 20041104 Minor updates. 20041105 Running with different framebuffer windows on different X11 displays works now (even with different bit depths and endiannesses on different displays). A new command line option (-z) adds DISPLAYs that should be used. Update regarding how DECstation BT459 cursors are used; transparency :-) and some other bug fixes. 20041106 More bt459 updates. The cursor color seems to be correct for NetBSD, OpenBSD, Ultrix, and Sprite. Some minor bintrans updates (redesigning some things). 20041107 More bintrans updates (probably broken for non-Alpha targets). Moving doc/mips64emul.1 to man/. 20041108 Some updates. 20041109 More updates. Bintrans experiments mostly. 20041110 Some minor bintrans updates. 20041111 Minor updates. 20041112 A little rewrite of the bintrans system (again :-), this time a lot more naïve and non-optimizing, in order to support delay slots in a much simpler way. Ultrix 4.5 boots into a usable desktop on my home machine in 3min 28sec, compared to 6-8 minutes without bintrans. 20041113 Some minor bintrans updates. 20041114 More bintrans updates. Ultrix now boots in exactly 3 minutes on my home machine. 20041115 More bintrans updates. 20041116 Bintrans updates. 20041117 Working on dev_dec_ioasic and related issues. Adding support for letting translated code access devices in some cases (such as framebuffers). 20041118 Moving some MIPS registers into Alpha registers, which gives a speed improvement. Beginning to write an i386 bintrans backend. Skeleton stuff works, lui, jr/jalr, addiu/daddiu/andi/ori/xori, j/jal, addu/daddu/subu/xor/or/nor/and. 20041119 dsubu/sll/srl/sra, rfe,mfc0,dmfc0, beq,bne, delayed branches. Some load/store (but not for bigendian emulation yet.) Time to reach Ultrix 4.5's graphical login on a 2.8 GHz Xeon host is now down to 20 seconds! Adding bgez, bltz, bgtz, and blez to the i386 backend. 20041120 Minor updates (bintrans related mostly). Time to reach Ultrix login on the Xeon is now 11 seconds. Adding 'mult', 'multu' and a some parts of mtc0 to the Alpha backend. The transparency updates to the X11 cursor support made the OpenBSD/arc cursor disappear; that has been fixed now. Unfortunately, something with Acer Pica emulation is broken when bintrans is enabled. 20041121 Making tlbwr, tlbwi, tlbp, tlbr callable directly from translated code. Adding sltiu, slti, slt, and sltu to the i386 backend. 20041122 More bintrans updates. With the Alpha backend, the status and entryhi registers can (in some cases) be written without exiting to the main loop. Ultrix boot time until a usable desktop is reached is about 1 min 35 seconds on the 533 MHz pca56. Adding srlv, srav, and sllv to the i386 backend. 20041123 Removing the special handling of high physical addresses for DECstation emulation from the main memory handling code, and replacing it with a mirror device instead. (This results in a tiny increase in performance, and cleaner code.) Various minor updates. 20041124 Ripping out _all_ bintrans load/store code, because I have a new idea I'd like to try out. A total rewrite of the load/store system. It works when emulating 32-bit MIPS, but not for 64-bit code yet. Some minor updates to the dev_fb, but no speed improvement. Making the 'le' ethernet device' SRAM work with bintrans. 20041125 Various updates. Adding a little "bootup logo" to the framebuffer. There is now one translate_address() for R3000-style MMUs, and one for the other types. (This gives a tiny speed improvement.) 20041126 Minor updates, bintrans. Fixing the bug which caused OpenBSD/arc (R4000) to bug out; it was introduced between the 7:th and 10:th of November when moving up the check for interrupts to above the code which runs bintrans code, in src/cpu.c. Adding movn and movz to the Alpha bintrans backend. 20041127 Various minor updates. 20041128 Making the R2000/R3000 caches work with bintrans, even in isolated mode. (Not true cache emulation, but it works with NetBSD/pmax, OpenBSD/pmax, and Ultrix.) Making the default cache size for R3000 4KB instr, 4 KB data; a real R3000 could have 64KB each, but emulated OSes run faster when they think the cache is smaller :-) Updates to the i386 backend: the nr of executed instructions is now placed in ebp at all times, and some support for mtc0 similar to how it is done in the Alpha backend has been added. A full NetBSD/pmax 1.6.2 install can now be done in 5 minutes 35 seconds, on a 2.8 GHz Xeon host (with -bD2 -M20). Adding mult and multu to the i386 bintrans backend. Reducing the number of malloc/free calls used by the diskimage subsystem. 20041129 Minor updates to the Alpha bintrans backend. 20041130 Trying to fix the bug which prevents Linux from working with bintrans. It _seems_ to work now. (Pages could in some cases be written to after they were translated, but that has been fixed now.) A couple of other minor fixes. Minor updates to the Alpha backend (directly using Alpha registers in some cases, instead of loading into temporaries). Updates to the i386 backend (special hacks for 32-bit MIPS emulation, which are fast on i386, for example only updating half of the pc register). 20041201 More updates to the i386 backend, similar to those yesterday. Preparing for release 0.2.3. Adding a generic load/store mechanism, which is used when the 32-bit optimized version cannot be used (for R4000 etc). ============== RELEASE 0.2.3 ============== 20041202 If ALWAYS_SIGNEXTEND_32 is defined in misc.h, and an incorrectly extended register is detected, the emulator now exits instead of continues. Removing the LAST_USED_TLB_EXPERIMENT stuff. Minor updates to work better with Windows NT's ARCINST.EXE; printing 0x9b via arcbios becomes ESC + '[', and the ARC memory descriptor stuff has been generalized a bit more. Adding arbios hacks for Open(), Seek(), GetRelativeTime(), and Read() to allow WinNT's SETUPLDR to read the filesystem on the diskimage used for booting. 20041203 Adding a terminal emulation layer which converts arcbios stdout writes to "VGA text console" cell characters. Seems to work with Windows NT and arcdiag. Adding a 8x8 font to dev_vga. Adding more ARC components to the component tree (for PICA emulation). 20041204 Minor updates. More updates to dev_vga. Adding a 8x10 font. Adding a hack so that the framebuffer logo is visible at startup with dev_vga. (It disappears at the first scroll.) A minor fix for a bug which was triggered when running dual- or tripple-head, on 2 or 3 actual X11 displays. 20041205 Fixing a bintrans bug. Some other minor updates (some of them bintrans related). 20041206 Moving the web page to http://gavare.se. Adding a hack for mmap() which supports anonymous mapping using /dev/zero, but not using MAP_ANON{,YMOUS}. Separating out opcodes.h, cop0.h, and cpu_types.h from misc.h. 20041207 Minor bintrans update. (In some cases, it isn't necessary to return to the main loop, when translating from a new page.) Some other minor i386 bintrans backend optimizations. And some other minor updates. i386 backend update: the lowest 32 bits of the pc register are now placed in an i386 register. 20041208 Adding GetConfigurationData() and some support for config data, to src/arcbios.c. Adding a bogus 0xbd SCSI command (used by Windows NT). It is not listed in http://www.danbbs.dk/~dino/SCSI/SCSI2-D.html. If the framebuffer cursor contains more than 1 color, then the host's X11 cursor disappears. (Nice for DECstation emulation with emulated X.) For ARC and SGI emulation, if an exception occurs before an exception handler is installed, the emulator now exits nicely (as suggested by Alec Voropay). A couple of minor updates to the ARCBIOS emulation subsystem. The single step debugger is now automatically entered when all CPUs have stopped running, unless there was a clean shutdown of some kind (PROM halt() call, or similar). Adding a -V option for starting up in a paused state, into the single-step debugger. Adding a note about 'mmon' to the documentation (http://www.brouhaha.com/~eric/software/mmon/). 20041209 Fixes to devices/console.c which makes cursor keys and such a bit more reliable. ARCBIOS hack/update which creates memory descriptors _after_ loading the executable. (Seems to work with OpenBSD/arc, NetBSD/arc, arcdiag, IRIX, NetBSD/sgimips, OpenBSD/sgi, and some Windows NT executables.) ARCBIOS support for cursor keys (ESC + '[' ==> 0x9b). A bintrans update (for 32-bit emulation) which speeds up jumps between pages, if code is already translated. Changing the default bintrans cache from 20 to 24 MB. 20041210 Optimizing unaligned load/stores a little bit in src/cpu.c. Omiting the check for nr of executed bintrans instructions on some forward jumps. Adding the 'syscall' and 'break' instructions to the bintrans backends. Allowing more bits of the status register to be written to from within inside translated code, on R3000. Getting rid of the final pixel when hiding the host's mouse cursor. store_buf() now copies data 8 or 4 bytes at a time, when possible. (This speeds up emulated ROM disk reads, etc.) Tiny bug fix: coprocessor unusable exceptions are now also generated (for coproc 1..3) even when in kernel mode, if the coprocessors are not enabled. This allows a Debian installation to proceed further than before. (It's still very unstable, though.) 20041212 Updating doc/index.html with better Debian installation instructions. If SLOWSERIALINTERRUPTS is defined at compile time, interrupts from the dc7085 device will not come as often as they normally do. This makes Debian seem more stable. Decreasing the bintrans cache to 20 MB again. Updating some files in preparation for a 0.2.4 release. 20041213 Updating the docs on how to install NetBSD 2.0/pmax, and also some updates to the section on installing Debian. 32-bit bintrans backend optimization: don't inline large chunks of code, such as general jumps. 20041214 Minor fix for coproc unusable for R4000 (it's the PC that, matters, not the KSU bits). Separating out the debugger from emul.c into debugger.c. Rewriting parts of the debugger. Removing the -U command line option, as it wasn't really useful. Also removing the -P option. Renaming all instances of dumppoint to breakpoint, as that is what it really is. When a breakpoint is reached, the single-step debugger is entered, instead of just turning on instruction trace. Adding a 'breakpoints' debugger command. Better fix for coproc unusable on R4000: the KSU bits matter, but the ERL and EXL bits override that. Fix which allows Debian to boot directly from a disk image (with DELO). (It reads multiple separate areas from disk.) Update to the SLOWSERIALINTERRUPTS stuff, making it even slower. Fixes based on feedback from Alec Voropay (-Q with ARC emulation skips the setup of arcbios data structures in memory, and no sign-extension _after_ writing a 32-bit value to a 64-bit coproc 0 register). Adding a 'devices' command to the debugger. The 'registers' and 'tlbdump' commands now take an optional argument (a cpu id). Adding rudimentary tab-completion and cursor key stuff to debugger_readline(). Adding some more debugger commands: 'bintrans' and 'machine'. 20041215 Adding a 'devstate' command; implementing a skeleton for a state function for the bt459 device. Implementing yet another variant of the SLOWSERIALINTERRUPTS stuff. Implementing more of the different exception offsets (taking CAUSE_IV and STATUS_BEV into account). hpc_bootinfo should now be correctly filled on big-endian hosts. Always shift left by 12, not by pageshift, to get physical addresses on MMU4K etc. (Thanks to Alec Voropay for noticing this.) 20041216 The KN02's CSR can now be read from bintranslated code. Adding a dummy dev_sgi_mec. 20041217 The default framebuffer and model settings for -F (hpcmips) should now be almost like Cassiopeia E-500. Changing -DSLOWSERIALINTERRUPTS into a command line option, -U. 20041218 Continuing a little bit on the mec controller. Removing lots of #include that weren't really used. 20041219 Fixing stuff that broke because of the pageshift bugfix. Adding an argument to the s (step) debugger command, for doing more than 1 step at a time. ARCBIOS components representing disk images are now created to actually match the disk images in use, and some other arcbios-related updates; adding a dummy GetComponent(). Adding a 'lookup' command to the debugger, for symbol lookups. Adding a "NEC Express RISCserver" mode (NEC-R96, -A8). Adding a dummy ARCBIOS GetFileInformation(), GetTime(), and SetEnvironmentVariable(). 20041220 Improved command line editing (including command history) in the debugger. Separating some more .h files from each other, and fixing some Solaris compiler warnings. 20041221 Minor updates. 20041222 Minor updates; hpcmips (BE300, VR41xx) stuff. The 'register' debugger command is now 'reg', and it can be used to modify registers, not just read them. The syntax for hpcmips (-F) is now -F xx, where xx is a machine model identifier. (1 = BE300.) 20041223 Some really minor updates. 20041226 Minor updates to doc/index.html (NetBSD 1.6.2 -> 2.0, and some other rearrangements). Many updates to the debugger (better register manipulation, breakpoint manipulation, and other updates). Fix to dev_cons.c to allow the regression tests to work again. The configure script now tries to detect the presence of a MIPS cross compiler. (Used by "make regtest".) Regression tests are now run both with and without bintrans. 20041227 Some hacks to the VR41xx code to allow Linux for BE300 to get far enough to show the penguin on the framebuffer. 20041228 Merging dev_kn01_csr.c and dev_vdac.c into dev_kn01.c. 20041229 Various updates to the debugger (nicer tlb output and other things). Some floating point fixes in src/coproc.c (mov is not an arithmetic instruction), and in src/cpu.c (ldcX/sdcX in 32-bit mode uses register pairs). '-O' now also affects the bootstring for SGI and ARC emulation. Bintrans updates (slightly faster 32-bit load/store on alpha). Updates to the i386 backend too, but no real speed improvement. 20041230 Cleaning up parts of the 64-bit virtual-to-physical code for R10000, and per-machine default TLB entries can now be set for SGI and ARC machines. Fix: SGI-IP27 is ARC64, not ARCS. 20050101 Minor updates. 20050102 Minor updates. Fixing a 32-bit 'addu' bug in the bintrans backends. Allowing fast load/stores even in 64-bit bintrans mode, if the top 32 bits are either 0x00000000 or 0xffffffff (for Alpha only). Re-enabling ctc0/cfc0 (but what do they do?). Adding beql, bnel, blezl, and bgtzl to the Alpha backend. 20050103 Adding fast 32-bit load/store for 64-bit mode emulation to the i386 backend too (similar to the Alpha code). Not really tested yet, though. Adding an incomplete regression test case for lwl/lwr/ldl/ldr. Playing around with bintranslated lwl and lwr for Alpha. 20040104 Changing many occurances of pica to jazz. Various other updates. 20050105 Fixing some more bintrans bugs (both Alpha and i386). Unaligned stores that cause tlb refill exceptions should now cause TLBS exceptions, not TLBL. Adding experimental swl and swr to the Alpha backend. Adding lwl, lwr, swl, and swr to the i386 backend. 20050106 Adding another hpcmips model (Casio E-105, -F2), and doing some updates to the VR41xx code. NetBSD/hpcmips prints some boot messages. 20050108 Minor updates. 20050109 dev_dec5500_ioboard.c and dev_sgec.c => dev_kn220.c. dev_crime.c, _mace.c, and _macepci.c => dev_sgi_ip32.c. Also adding dev_sgi_mec, _ust, and _mte into dev_sgi_ip32.c. A slight license change. Still revised BSD-style, though. memory_v2p.c is now included separately for MMU10K and MMU8K. Fixing a NS16550 bug, triggered by NetBSD 2.0, but not 1.6.2. Refreshing the UltraSPARC bintrans backend skeleton. Merging dev_decbi, _deccca, and _decxmi into dev_dec5800.c. Sparc backend instructions done so far: mthi/mtlo/mfhi/mflo, lui, addu, daddu, subu, dsubu, and, or, nor, xor, sll, dsll, srl, and sra. Adding more sparc backend instructions: addiu, daddiu, xori, ori, andi, srlv, srav, sllv, slt, sltu, slti, sltiu. 20050110 Changing the default bintrans cache to 16 MB, and some other minor updates. Adding div and divu to the i386 backend (but not Alpha yet). More work on ARCBIOS emulation. Trying to find a bug which affects Linux on Playstation 2 in bintrans mode. 20050111 Moving around some Playstation 2 stuff, but I haven't found the bug yet. It is triggered by load/stores. More ARCBIOS updates, enough to let Windows NT partition disks in some rudimentary fashion. 20050112 Testing for release 0.2.4. Fixes to suppress compiler warnings. ============== RELEASE 0.2.4 ============== 20050113 Minor updates. 20050114 Fix to the Alpha bintrans backend to allow compilation with old versions of gcc (2.95.4). ============== RELEASE 0.2.4.1 ============== 20050115 Various updates and fixes: some IP32 stuff, the debugger, ns16550 loopback tx isn't transmitted out anymore, ... Removing old/broken R10000 cache hacks, which weren't really used. 20050116 Minor updates to the documentation on using PROM images. Adding ARCBIOS function 0x100 (used by IRIX when returning from main, but undocumented). MC146818 updates (mostly SGI-related). ARCS64 updates (testing with an OpenBSD snapshot in IP27 mode). This causes Linux/IP30 to not work. Maybe IP27 and IP30 differ, even though both are 64-bit? Removing some nonsensical ARCS64 code from machine.c. Better handling of 128MB and 512MB memory offsets used by various SGI models. Trying to revert the ARCS64 changes (OpenBSD/sgi does seem to be aware of 64-bit vs 32-bit data structures in _some_ places, but not all), to make Linux/IP30 work again. Adding "power off" capability to the RTC, as used on IP32 (and possibly IP30 and others). Some IP30 updates. 20050117 Debugger updates (symbolic register names instead of just rX, and using %08x instead of %016llx when emulating 32-bit CPUs in more places than before). Removing the dummy sgi_nasid and sgi_cpuinfo devices. Also using symbolic names for coprocessor 0 registers. Adding DEV_MP_MEMORY to dev_mp.c. Adding a 'put' command to the debugger. ARCBIOS function 0x100 used by IRIX seems to _NOT_ be a ReturnFromMain(), but something else undocumented. The count and compare registers are now 32-bit in all places, as they should be. (This causes, among other things, OpenBSD/sgi to not hang randomly in userspace anymore.) On breakpoints, the debugger is now entered _at_ the instruction at the breakpoint, not after it. Some cursor keys now work when inputed via X. Refreshing the MC146818 device a bit more. 20050118 Trying to add some support for less-than-4KB virtual pages, used by at least VR4131. Thanks to Alexander Yurchenko for noticing this. (I'm assuming for now that all R41xx work this way, which is not necessarily true.) It doesn't really work yet though. Renicing the "loading files" messages and other things displayed during startup. Changing the disassembly output of ori, xori, and andi to unsigned hex immediate, instead of decimal (as suggested by Alec Voropay). configure-script update for HP-UX, and switching from using inet_aton() to inet_pton() (as suggested by Nils Weller). Also adding -lnsl on Solaris, if required by inet_pton(). Lots of minor R4100-related updates. 20050119 Correcting the R4100 config register in src/coproc.c, and a minor update to dev_vr41xx. Finally began a redesign/remodelling/cleanup that I have had in mind for quite some time... moving many things that were in struct emul into a new struct machine. Userland emulation now works with bintrans. Refreshing the LANCE controller (dev_le.c). Fixing the LK201 keyboard id. 20050120 Continuing on the remodelling/cleanup. Fixing the SCSI bug (which was triggered sometimes by NetBSD 2.0/pmax on Linux/i386 hosts). Adding a speed-limit hack to the mc146818 device when running in DECstation mode (limiting to emulated 30 MHz clock, so that Ultrix doesn't freak out). Adding an ugly workaround for the floating-point bug which is triggered when running NetBSD/pmax 2.0 on an Alpha host. The count/compare interrupt will not be triggered now, if the compare register is left untouched. Many, many other fixes... 20050121 Continuing the remodelling/cleanup. (Mostly working on the network stack, and on moving towards multiple emulations with multiple machines per emulation.) Fixbug: not clearing lowest parts of lo0 and hi on tlbr (seems to increase performance when emulating Linux?). 20050122 Continuing the remodelling/cleanup. Linux on DECstation uses a non-used part of the RTC registers for the year value; this is supported now, so Linux thinks it is 2005 and not 2000. Began hacking on something to reply to Debian's DHCP requests, but it's not working yet. 20050123 Continuing the remodelling/cleanup. 20050124 Continuing the remodelling/cleanup. Converting the dev_vga charcell memory to support direct bintrans access (similar to how dev_fb works), and fixing a couple of bintrans bugs in the process. The emulator now compiles under OpenBSD/arc 2.3 without crashing (mostly due to the bintrans fixes, but also some minor updates to the configure script). 20050125 Continuing the remodelling/cleanup. The '-a' option was missing in the Hello World example in the documentation. (Thanks to Soohyun Cho for noticing this.) 20050126 Continuing the remodelling/cleanup. Moving around stuff in the header files, etc. Adding a '-K' command line option, which forces the debugger to be entered at the exit of a simulation, regardless of failure or success. Beginning to work on the config file parser. Splitting doc/index.html into experiments.html, guestoses.html, intro.html, and misc.html. Updating the man page and adding a skeleton section about the configure files to doc/misc.html. 20050127 Minor documentation updates. 20050128 Continuing the remodelling/cleanup, mostly working on the config file parser (adding a couple of machine words, enough to run simple emulations, and adding support for multi-line comments using tuborgs). Removing some command line options for the least working emulation modes (-e, -f, -g, -E, -H), adding new -E and -e options for selecting machine type. Moving global variables from src/x11.c into struct machine (a bit buggy, but it seems to almost work). 20050129 Removing the Playstation 2 mode (-B) and hpcmips modes (-F) from the command line as well. Changing the -T command line option from meaning "trace on bad address" to meaning "enter the single-step debugger on bad address". More updates to the configuration file parser (nested tuborg comments, more options, ...). Making -s a global setting, not just affecting one machine. Trying to fix the X11 event stuff... but it's so ugly that it must be rewritten later. Continuing the multi-emul cleanup. Bugfixes and other updates to dev_vga. 20050130 Continuing the remodelling/cleanup. Finally moving out the MIPS dependant stuff of the cpu struct into its own struct. Renaming cpu.c to cpu_mips.c, and cpu_common.c to cpu.c. Adding a dummy cpu_ppc.c. Removing the UltraSPARC bintrans backend. Many other minor updates. src/file.c should now be free from MIPS-dependancies. 20050131 Continuing a little bit more on src/file.c. PPC ELFs can now be loaded, it seems. Continuing on src/cpu_ppc.c. 'mips' is undefined by the configure script, if it is defined by default. (Fixes build on at least OpenBSD/arc and NetBSD/arc, where gcc defines 'mips'.) A couple of other minor fixes. Removing the "Changing framebuffer resolution" section from doc/misc.h (because it's buggy and not very useful anway). Adding a mystrtoull(), used on systems where there is no strtoull() in libc. Adding 'add_x11_display' to the configure file parser (corresponding to the -z command line option). Continuing the multi-emul machine cleanup. 20050201 Minor updates (man page, RELEASE, README). Continuing the cleanup. Adding a 'name' field to the emul struct, and adding a command to the debugger ("focus") to make it possible to switch focus to different machines (in different emuls). Beginning to work on the PPC disassembler etc. Hello World for linux-ppc64 can be disassembled :-) 20050202 Adding a hack for reading symbols from Microsoft's variant of COFF files. Adding a dummy cpu_sparc.c and include/cpu_sparc.h. Cleaning up more to support multiple cpu families. Various other minor updates. Fixing another old-gcc-on-Alpha problem. 20050203 Bintrans cache size is now variable, settable by a new configuration file option 'bintrans_size'. The debugger can now theoretically call disassembler functions for cpu families with non-fixed instruction word length. Working more on the mec controller. It now works well enough to let both NetBSD/sgimips and OpenBSD/sgi connect to the outside world using ftp :-) Continuing on the cleanup of the networking subsystem. 20050204 Continuing the cleanup. Working on a way to use separate xterms for serial ports and other console input, when emulating multiple machines (or one machine with multiple serial lines active). 20050205 Minor documentation updates. 20050206 Moving console.c from devices/ to src/, and continuing the work on using separate windows for each serial console. Trying to get OpenBSD/sgi to boot with root-on-nfs on an emulated NetBSD/pmax server, but no success in setting up the server yet. 20050207 Continuing on the console cleanup. Adding a 'start_paused' configuration file option, and a 'pause' command to the debugger. 20050208 Everything now builds with --withoutmips. Continuing on the documentation on how to run OpenBSD/sgi, but no actual success yet. sizeof => (int)sizeof in the configure script (as suggested by Nils Weller). 20050209 Adding a check for -lm to the configure script. Continuing on the cleanup: trying to make memory_rw non-MIPS dependant. Trying to make a better fix for the cdrom-block-size problems on FreeBSD. (It now works with a Windows NT 4.0 cdrom in my drive.) Began a clean-up of the userland subsystem. 20050210 Continuing the userland cleanup. IBM's Hello World example for Linux/PPC64 runs fine now. 20050211 Continuing the cleanup. Removing the --userland configure option (because support for userland is always included now). Working more on getting OpenBSD/sgi to boot with root on nfs. (Booting with the ramdisk kernel, and mounting root via nfs works, but not yet from the generic kernel.) Major update to the manpage. Removing the -G command line option (SGI modes). 20050212 Updating the documentation (experimental devices: dev_cons and dev_mp, better hello.c, and some other things). 20050213 Some minor fixes: documentation, 80 columns in some source files, better configure script options. Adding some more PPC instructions. Added a NOFPU flag to the MIPS cpu flags, so that executing FPU instructions on for example VR4xxx will fail (as suggested by Alexander Yurchenko). 20050214 Implementing more PPC instructions. Adding dev_pmppc. 20050215 Continuing the work on PPC emulation. Adding a (mostly non- working) NetBSD/powerpc userland mode, a (buggy) show_trace_tree thing (simliar to the MIPS version). 20050216 Continuing... 20050218 Continuing the clean-up. (Merging the devices and devstate debugger commands, more 80-column cleanup, some documentation updates, ...). 20050219 Removing the -D, -A, and -a command line options. Updating the documentation, in preparation for the next release. Adding interrupt stuff to dev_cons. Single-stepping now looks/works better with bintrans enabled. Beginning the first phase of release testing; various minor updates to make everything build cleanly on Solaris. 20050220 Continuing testing for the release... ============== RELEASE 0.3 ============== 20050221 Minor updates. Some more clean-up. Beginning on the new device registry stuff. 20050222 Continuing on the device stuff, and doing various other kinds of clean-up. Adding a dummy BeBox mode. Making the pc register common for all cpu families. Adding some more PPC instructions and fixing some bugs. 20050223 Continuing on the BeBox stuff, and adding more instructions. Adding an ns16550 to the VR4131 emulation (which is probably a close enough fake to the VR4131's SIU unit). 20050224 Minor updates. Adding dummy PReP, macppc, and DB64360 modes. Continuing on the device registry rewrite. 20050225 Continuing on the device stuff. 20050226 Continuing more on the device rewrite. Separating the "testmips" machine into testmips and baremips (and similarly with the ppc machine). Redesigning the device registry again :-) Adding a "device" command to the config file parser. Adding "device add" and "device remove" to the debugger. Removing pcidevs.h, because it was almost unused. 20050228 Correcting the Sprite disk image url in the documentation. 20050301 Adding an URISC cpu emulation mode (single-opcode machine). 20050303 Adding some files to the experiments directory (rssb_as.c, rssb_as.README, urisc_test.s). Continuing on the device stuff. 20050304 Minor documentation update. Also, the SPARC, PPC, and URISC modes are now enabled by default in the configure script. Some minor PPC updates (adding a VGA device to the bebox emulation mode). 20050305 Moving the static i386 bintrans runchunk code snippet (and the others) to be dynamically generated. (This allows the code to compile on i386 with old gcc.) Loading PPC64 ELFs now sets R2 to the TOC base. Changing the name of the emulator from mips64emul to GXemul. Splitting out the configuration file part of the documentation into its own file (configfiles.html). 20050306 Some really minor documentation updates. Adding a -D command line option (for "fully deterministic" behaviour). 20050308 Minor PPC updates. Adding a dummy OpenFirmware emulation layer. 20050309 Adding a hack for systems without inet_pton (such as Cygwin in Windows) as suggested by Soohyun Cho. (And updating the configure script too.) Adding a dummy HPPA cpu family. Some more OpenFirmware updates. Faster loading of badly aligned ELF regions. 20050311 Minor updates. Adding a dummy "NEC MobilePro 780" hpcmips machine mode; disabling direct bintrans access to framebuffers that are not 4K page aligned. 20050312 Adding an ugly KIU hack to the VR41xx device (which enables NetBSD/hpcmips MobilePro 780 keyboard input). 20050313 Adding a dummy "pcic" device (a pcmcia card controller). Adding a dummy Alpha cpu emulation mode. Fixing a strcmp length bug (thanks to Alexander Yurchenko for noticing the bug). 20050314 Some minor bintrans-related updates in preparation for a new bintrans subsystem: command line option -b now means "old bintrans", -B means "disable bintrans", and using no option at all selects "new bintrans". Better generation of MAC addresses when emulating multiple machines and/or NICs. Minor documentation updates (regarding configuration files). 20050315 Adding dummy standby, suspend, and hibernate MIPS opcodes. RTC interrupt hack for VR4121 (hpcmips). Enough of the pcic is now emulated to let NetBSD/hpcmips detect a PCMCIA harddisk controller card (but there is no support for ISA/PCMCIA interrupts yet). Adding preliminary instructions on how to install NetBSD/hpcmips. Continuing the attempt to get harddisks working with interrupts (pcic, wdc on hpcmips). 20050318 Minor updates. (Fixing disassembly of MIPS bgtz etc., continuing on the device cleanup, ...) 20050319 Minor updates. 20050320 Minor updates. 20050322 Various minor updates. 20050323 Some more minor updates. 20050328 VR41xx-related updates (keyboard stuff: the space key and shifted and ctrled keys are now working in userland (ie NetBSD/hpcmips' ramdisk installer). Also adding simple cursor key support to the VR41xx kiu. 20050329 Some progress on the wdc. Updating the documentation of how to (possibly) install NetBSD/hpcmips, once it is working. Adding delays before wdc interrupts; this allows NetBSD 2.0/hpcmips to be successfully installed! Mirroring physical addresses 0x8....... to 0x00000000 on hpcmips; this makes it possible to run X11 inside NetBSD/hpcmips :-) Updating the documentation regarding NetBSD/hpcmips. Fixing 16-bit vs 15-bit color in dev_fb. 20050330 Print a warning when the user attempts to load a gzipped file. (Thanks to Juan RP for making me aware of this "bug".) 20050331 Importing aic7xxx_reg.h from NetBSD. Adding a "-x" command line option, which forces xterms for each emulated serial port to always be opened. Adding a MobilePro 770 mode (same as 780, but different framebuffer address which allows bintrans = fast scrolling), and a MobilePro 800 (with 800x600 pixels framebuffer :-). 20050401 Minor updates. 20050402 Minor updates. (The standby and suspend instructions are bintransed as NOPs, and some minor documentation updates.) 20050403 Adding an Agenda VR3 mode, and playing around with a Linux kernel image, but not much success yet. Changing BIFB_D16_FFFF -> BIFB_D16_0000 for the hpcmips framebuffers, causing NetBSD to boot with correct colors. New syntax for loading raw files: loadaddr:skiplen: initialpc:filename. (This is necessary to boot the Linux VR3 kernels.) The Linux VR3 kernel boots in both serial console mode and using the framebuffer, but it panics relatively early. 20050404 Continuing on the AHC, and some other minor updates. 20050405 Adding a note in doc/experimental.html about "root1.2.6.cramfs" (thanks to Alec Voropay for noticing that it wasn't part of root1.2.6.kernel-8.00). Also adding a note about another cramfs image. -o options are now added to the command line passed to the Linux kernel, when emulating the VR3. Adding a MobilePro 880 mode, and a dummy IBM WorkPad Z50 mode. 20050406 Connecting the VR3 serial controller to irq 9 (Linux calls this irq 17), and some other interrupt-related cleanups. Reducing the memory overhead per bintranslated page. (Hopefully this makes things faster, or at least not slower...) 20050407 Some more cleanup regarding command line argument passing for the hpcmips modes. Playing with Linux kernels for MobilePro 770 and 800; they get as far as mounting a root filesystem, but then crash. Doing some testing for the next release. ============== RELEASE 0.3.1 ============== 20050408 Some minor updates to the wdc. Linux now doesn't complain anymore if a disk is non-present. 20050409 Various minor fixes (a bintrans bug, and some other things). The wdc seems to work with Playstation2 emulation, but there is a _long_ annoying delay when disks are detected. Fixing a really important bintrans bug (when devices and RAM are mixed within 4KB pages), which was triggered with NetBSD/playstation2 kernels. 20050410 Adding a dummy dev_ps2_ether (just so that NetBSD doesn't complain as much during bootup). Symbols starting with '$' are now ignored. Renaming dev_ps2_ohci.c to dev_ohci.c, etc. 20050411 Moving the bintrans-cache-isolation check from cpu_mips.c to cpu_mips_coproc.c. (I thought this would give a speedup, but it's not noticable.) Better playstation2 sbus interrupt code. Skip ahead many ticks if the count register is read manually. (This increases the speed of delay-loops that simply read the count register.) 20050412 Updates to the playstation2 timer/interrupt code. Some other minor updates. 20050413 NetBSD/cobalt runs from a disk image :-) including userland; updating the documentation on how to install NetBSD/cobalt using NetBSD/pmax (!). Some minor bintrans updates (no real speed improvement) and other minor updates (playstation2 now uses the -o options). 20050414 Adding a dummy x86 (and AMD64) mode. 20050415 Adding some (32-bit and 16-bit) x86 instructions. Adding some initial support for non-SCSI, non-IDE floppy images. (The x86 mode can boot from these, more or less.) Moving the devices/ and include/ directories to src/devices/ and src/include/, respectively. 20050416 Continuing on the x86 stuff. (Adding pc_bios.c and some simple support for software interrupts in 16-bit mode.) 20050417 Ripping out most of the x86 instruction decoding stuff, trying to rewrite it in a cleaner way. Disabling some of the least working CPU families in the configure script (sparc, x86, alpha, hppa), so that they are not enabled by default. 20050418 Trying to fix the bug which caused problems when turning on and off bintrans interactively, by flushing the bintrans cache whenever bintrans is manually (re)enabled. 20050419 Adding the 'lswi' ppc instruction. Minor updates to the x86 instruction decoding. 20050420 Renaming x86 register name indices from R_xx to X86_R_xx (this makes building on Tru64 nicer). 20050422 Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi. 20050427 Adding screenshots to guestoses.html. Some minor fixes and testing for the next release. ============== RELEASE 0.3.2 ============== 20050428 Disabling the "-fmove-all-movables" option in the configure script, because it causes the compile to fail on OpenBSD/sgi. 20050502 Minor updates. 20050503 Removing the WRT54G mode (it was bogus anyway), and adding a comment about Windows NT for MIPS in doc/experiments.html. Minor updates to the x86 instruction decoding. 20050504 Adding some more x86 instructions. Adding support for reading files from ISO9660 CDROMs (including gzipped files). It's an ugly hack, but it seems to work. Various other minor updates (dev_vga.c, pc_bios.c etc). 20050505 Some more x86-related updates. Beginning (what I hope will be) a major code cleanup phase. "bootris" (an x86 bootsector) runs :-) 20050506 Adding some more x86 instructions. 20050507 tmpnam => mkstemp. Working on a hack to allow VGA charcells to be shown even when not running with X11. Adding more x86 instructions. 20050508 x86 32-bit SIB addressing fix, and more instructions. 20050509 Adding more x86 instructions. 20050510 Minor documentation updates, and other updates (x86 stuff etc.) 20050511 More x86-related updates. 20050513 Various updates, mostly x86-related. (Trying to fix flag calculation, factoring out the ugly shift/rotate code, and some other things.) 20050514 Adding support for loading some old i386 a.out executables. Finally beginning the cleanup of machine/PROM/bios dependant info. Some minor documentation updates. Trying to clean up ARCBIOS stuff a little. 20050515 Trying to make it possible to actually use more than one disk type per machine (floppy, ide, scsi). Trying to clean up the kbd vs PROM console stuff. (For PC and ARC emulation modes, mostly.) Beginning to add an 8259 interrupt controller, and connecting it to the x86 emulation. 20050516 The first x86 interrupts seem to work (keyboard stuff). Adding a 8253/8254 programmable interval timer skeleton. FreeDOS now reaches a command prompt and can be interacted with. 20050517 After some bugfixes, MS-DOS also (sometimes) reaches a command prompt now. Trying to fix the pckbc to work with MS-DOS' keyb.com, but no success yet. 20050518 Adding a simple 32-bit x86 MMU skeleton. 20050519 Some more work on the x86 stuff. (Beginning the work on paging, and various other fixes). 20050520 More updates. Working on dev_vga (4-bit graphics modes), adding 40 columns support to the PC bios emulation. Trying to add support for resizing windows when switching between graphics modes. 20050521 Many more x86-related updates. 20050522 Correcting the initial stack pointer's sign-extension for ARCBIOS emulation (thanks to Alec Voropay for noticing the error). Continuing on the cleanup (ARCBIOS etc). dev_vga updates. 20050523 More x86 updates: trying to add some support for protected mode interrupts (via gate descriptors) and many other fixes. More ARCBIOS cleanup. Adding a device flag which indicates that reads cause no side-effects. (Useful for the "dump" command in the debugger, and other things.) Adding support for directly starting up x86 ELFs, skipping the bootloader stage. (Most ELFs, however, are not suitable for this.) 20050524 Adding simple 32-bit x86 TSS task switching, but no privilege level support yet. More work on dev_vga. A small "Copper bars" demo works. :-) Adding support for Trap Flag (single-step exceptions), at least in real mode, and various other x86-related fixes. 20050525 Adding a new disk image prefix (gH;S;) which can be used to override the default nr of heads and sectors per track. 20050527 Various bug fixes, more work on the x86 mode (stack change on interrupts between different priv.levels), and some minor documentation updates. 20050528 Various fixes (x86 stuff). 20050529 More x86 fixes. An OpenBSD/i386 bootfloppy reaches userland and can be interacted with (although there are problems with key repetition). NetBSD/i386 triggers a serious CISC-related problem: instruction fetches across page boundaries, where the later part isn't actually part of the instruction. 20050530 Various minor updates. (Documentation updates, etc.) 20050531 Adding some experimental code (experiments/new_test_*) which could be useful for dynamic (but not binary) translation in the future. 20050602 Adding a dummy ARM skeleton. Fixing the pckbc key repetition problem (by adding release scancodes for all keypresses). 20050603 Minor updates for the next release. 20050604 Release testing. Minor updates. ============== RELEASE 0.3.3 ============== 20050604 There'll probably be a 0.3.3.1 release soon, with some very very tiny updates. ============== RELEASE 0.3.3.1 ============== 20050609 Adding simple MIPS IPIs (to dev_mp). 20050611 Adding an ugly hack to track down low-reference bugs (define TRACE_NULL_CRASHES, or configure --tracenull). Other minor updates. 20050612 Adding a dummy evbmips mode. ============== RELEASE 0.3.3.2 ============== 20050617 Experimenting some more with netbooting OpenBSD/sgi. Adding a hack which allows emulated ethernet networks to be distributed across multiple emulator processes. 20050618 Minor updates (documentation, dummy YAMON emulation, etc). 20050620 strcpy/strcat -> strlcpy/strlcat updates. Some more progress on evbmips (Malta). 20050621 Adding a section to doc/configfiles.html about ethernet emulation across multiple hosts. Beginning the work on the ARM translation engine (using the dynamic-but-not-binary translation method). Fixing a bintrans bug: 0x9fc00000 should always be treated as PROM area, just as 0xbfc00000 is. Minor progress on Malta emulation (the PCI-ISA bus). 20050622 NetBSD/evbmips can now be installed (using another emulated machine) and run (including userland and so on). :-) Spliting up the bintrans haddr_entry field into two (one for read, one for write). Probably not much of a speed increase, though. Updating some NetBSD 2.0 -> 2.0.2 in the documentation. 20050623 Minor updates (documentation, the TODO file, etc). gzipped kernels are now always automagically gunzipped when loaded. 20050624 Adding a dummy Playstation Portable (PSP) mode, just barely enough to run Hello World (in weird colors :-). Removing the -b command line option; old bintrans is enabled by default instead. It makes more sense. Trying to finally fix the non-working performance measurement thing (instr/second etc). 20050625 Continuing on the essential basics for ARM emulation. Two instructions seem to work, a branch and a simple "mov". (The mov arguments are not correct yet.) Performance is definitely reasonable. Various other minor updates. Adding the ARM "bl" instruction. Adding support for combining multiple ARM instructions into one function call. ("mov" + "mov" is the only one implemented so far, but it seems to work.) Cleaning up some IP32 interrupt things (crime/mace); disabling the PS/2 keyboard controller on IP32, so that NetBSD/sgimips boots into userland again. 20050626 Finally! NetBSD/sgimips netboots. Adding instructions to doc/guestoses.html on how to set up an nfs server etc. Various other minor fixes. Playstation Portable ".pbp" files can now be used directly. (The ELF part of the .pbp is extracted transparently.) Converting some sprintf -> snprintf. Adding some more instructions to the ARM disassembler. 20050627 More ARM updates. Adding some simple ldr(b), str(b), cmps, and conditional branch instructions, enough to run a simple Hello World program. All ARM instructions are now inlined/generated for all possible condition codes. Adding add and sub, and more load/store instructions. Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c. Some minor documentation updates; preparing for a 0.3.4 release. Updating some URLs. ============== RELEASE 0.3.4 ============== 20050628 Continuing the work on the ARM translation engine. end_of_page works. Experimenting with load/store translation caches (virtual -> physical -> host). 20050629 More ARM stuff (memory access translation cache, mostly). This might break a lot of stuff elsewhere, probably some MIPS- related translation things. 20050630 Many load/stores are now automatically generated and included into cpu_arm_instr.c; 1024 functions in total (!). Fixes based on feedback from Alec Voropay: only print 8 hex digits instead of 16 in some cases when emulating 32-bit machines; similar 8 vs 16 digit fix for breakpoint addresses; 4Kc has 16 TLB entries, not 48; the MIPS config select1 register is now printed with "reg ,0". Also changing many other occurances of 16 vs 8 digit output. Adding cache associativity fields to mips_cpu_types.h; updating some other cache fields; making the output of mips_cpu_dumpinfo() look nicer. Generalizing the bintrans stuff for device accesses to also work with the new translation system. (This might also break some MIPS things.) Adding multi-load/store instructions to the ARM disassembler and the translator, and some optimizations of various kinds. 20050701 Adding a simple dev_disk (it can read/write sectors from disk images). 20050712 Adding dev_ether (a simple ethernet send/receive device). Debugger command "ninstrs" for toggling show_nr_of_instructions during runtime. Removing the framebuffer logo. 20050713 Continuing on dev_ether. Adding a dummy cpu_alpha (again). 20050714 More work on cpu_alpha. 20050715 More work on cpu_alpha. Many instructions work, enough to run a simple framebuffer fill test (similar to the ARM test). 20050716 More Alpha stuff. 20050717 Minor updates (Alpha stuff). 20050718 Minor updates (Alpha stuff). 20050719 Generalizing some Alpha instructions. 20050720 More Alpha-related updates. 20050721 Continuing on cpu_alpha. Importing rpb.h from NetBSD/alpha. 20050722 Alpha-related updates: userland stuff (Hello World using write() compiled statically for FreeBSD/Alpha runs fine), and more instructions are now implemented. 20050723 Fixing ldq_u and stq_u. Adding more instructions (conditional moves, masks, extracts, shifts). 20050724 More FreeBSD/Alpha userland stuff, and adding some more instructions (inserts). 20050725 Continuing on the Alpha stuff. (Adding dummy ldt/stt.) Adding a -A command line option to turn off alignment checks in some cases (for translated code). Trying to remove the old bintrans code which updated the pc and nr_of_executed_instructions for every instruction. 20050726 Making another attempt att removing the pc/nr of instructions code. This time it worked, huge performance increase for artificial test code, but performance loss for real-world code :-( so I'm scrapping that code for now. Tiny performance increase on Alpha (by using ret instead of jmp, to play nice with the Alpha's branch prediction) for the old MIPS bintrans backend. 20050727 Various minor fixes and cleanups. 20050728 Switching from a 2-level virtual to host/physical translation system for ARM emulation, to a 1-level translation. Trying to switch from 2-level to 1-level for the MIPS bintrans system as well (Alpha only, so far), but there is at least one problem: caches and/or how they work with device mappings. 20050730 Doing the 2-level to 1-level conversion for the i386 backend. The cache/device bug is still there for R2K/3K :( Various other minor updates (Malta etc). The mc146818 clock now updates the UIP bit in a way which works better with Linux for at least sgimips and Malta emulation. Beginning the work on refactoring the dyntrans system. 20050731 Continuing the dyntrans refactoring. Fixing a small but serious host alignment bug in memory_rw. Adding support for big-endian load/stores to the i386 bintrans backend. Another minor i386 bintrans backend update: stores from the zero register are now one (or two) loads shorter. The slt and sltu instructions were incorrectly implemented for the i386 backend; only using them for 32-bit mode for now. 20050801 Continuing the dyntrans refactoring. Cleanup of the ns16550 serial controller (removing unnecessary code). Bugfix (memory corruption bug) in dev_gt, and a patch/hack from Alec Voropay for Linux/Malta. 20050802 More cleanup/refactoring of the dyntrans subsystem: adding phys_page pointers to the lookup tables, for quick jumps between translated pages. Better fix for the ns16550 device (but still no real FIFO functionality). Converting cpu_ppc to the new dyntrans system. This means that I will have to start from scratch with implementing each instruction, and figure out how to implement dual 64/32-bit modes etc. Removing the URISC CPU family, because it was useless. 20050803 When selecting a machine type, the main type can now be omitted if the subtype name is unique. (I.e. -E can be omitted.) Fixing a dyntrans/device update bug. (Writes to offset 0 of a device could sometimes go unnoticed.) Adding an experimental "instruction combination" hack for ARM for memset-like byte fill loops. 20050804 Minor progress on cpu_alpha and related things. Finally fixing the MIPS dmult/dmultu bugs. Fixing some minor TODOs. 20050805 Generalizing the 8259 PIC. It now also works with Cobalt and evbmips emulation, in addition to the x86 hack. Finally converting the ns16550 device to use devinit. Continuing the work on the dyntrans system. Thinking about how to add breakpoints. 20050806 More dyntrans updates. Breakpoints seem to work now. 20050807 Minor updates: cpu_alpha and related things; removing dev_malta (as it isn't used any more). Dyntrans: working on general "show trace tree" support. The trace tree stuff now works with both the old MIPS code and with newer dyntrans modes. :) Continuing on Alpha-related stuff (trying to get *BSD to boot a bit further, adding more instructions, etc). 20050808 Adding a dummy IA64 cpu family, and continuing the refactoring of the dyntrans system. Removing the regression test stuff, because it was more or less useless. Adding loadlinked/storeconditional type instructions to the Alpha emulation. (Needed for Linux/alpha. Not very well tested yet.) 20050809 The function call trace tree now prints a per-function nr of arguments. (Semi-meaningless, since that data isn't read yet from the ELFs; some hardcoded symbols such as memcpy() and strlen() work fine, though.) More dyntrans refactoring; taking out more of the things that are common to all cpu families. 20050810 Working on adding support for "dual mode" for PPC dyntrans (i.e. both 64-bit and 32-bit modes). (Re)adding some simple PPC instructions. 20050811 Adding a dummy M68K cpu family. The dyntrans system isn't ready for variable-length ISAs yet, so it's completely bogus so far. Re-adding more PPC instructions. Adding a hack to src/file.c which allows OpenBSD/mac68k a.out kernels to be loaded. Beginning to add PPC loads/stores. So far they only work in 32-bit mode. 20050812 The configure file option "add_remote" now accepts symbolic host names, in addition to numeric IPv4 addresses. Re-adding more PPC instructions. 20050814 Continuing to port back more PPC instructions. Found and fixed the cache/device write-update bug for 32-bit MIPS bintrans. :-) Triggered a really weird and annoying bug in Compaq's C compiler; ccc sometimes outputs code which loads from an address _before_ checking whether the pointer was NULL or not. (I'm not sure how to handle this problem.) 20050815 Removing all of the old x86 instruction execution code; adding a new (dummy) dyntrans module for x86. Taking the first steps to extend the dyntrans system to support variable-length instructions. Slowly preparing for the next release. 20050816 Adding a dummy SPARC cpu module. Minor updates (documentation etc) for the release. ============== RELEASE 0.3.5 ============== 20050816 Some success in decoding the way the SGI O2 PROM draws graphics during bootup; lines/rectangles and bitmaps work, enough to show the bootlogo etc. :-) Adding more PPC instructions, and (dummy) BAT registers. 20050817 Updating the pckbc to support scancode type 3 keyboards (required in order to interact with the SGI O2 PROM). Adding more PPC instructions. 20050818 Adding more ARM instructions; general register forms. Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy) CATS machine mode (using SA110 as the default CPU). Continuing on general dyntrans related stuff. 20050819 Register forms for ARM load/stores. Gaah! The Compaq C Compiler bug is triggered for ARM loads as well, not just PPC :-( Adding full support for ARM PC-relative load/stores, and load/ stores where the PC register is the destination register. Adding support for ARM a.out binaries. 20050820 Continuing to add more ARM instructions, and correcting some bugs. Continuing on CATS emulation. More work on the PPC stuff. 20050821 Minor PPC and ARM updates. Adding more machine types. 20050822 All ARM "data processing instructions" are now generated automatically. 20050824 Beginning the work on the ARM system control coprocessor. Adding support for ARM halfword load/stores, and signed loads. 20050825 Fixing an important bug related to the ARM condition codes. OpenBSD/zaurus and NetBSD/netwinder now print some boot messages. :) Adding a dummy SH (Hitachi SuperH) cpu family. Beginning to add some ARM virtual address translation. MIPS bugfixes: unaligned PC now cause an ADEL exception (at least for non-bintrans execution), and ADEL/ADES (not TLBL/TLBS) are used if userland tries to access kernel space. (Thanks to Joshua Wise for making me aware of these bugs.) 20050827 More work on the ARM emulation, and various other updates. 20050828 More ARM updates. Finally taking the time to work on translation invalidation (i.e. invalidating translated code mappings when memory is written to). Hopefully this doesn't break anything. 20050829 Moving CPU related files from src/ to a new subdir, src/cpus/. Moving PROM emulation stuff from src/ to src/promemul/. Better debug instruction trace for ARM loads and stores. 20050830 Various ARM updates (correcting CMP flag calculation, etc). 20050831 PPC instruction updates. (Flag fixes, etc.) 20050901 Various minor PPC and ARM instruction emulation updates. Minor OpenFirmware emulation updates. 20050903 Adding support for adding arbitrary ARM coprocessors (with the i80321 I/O coprocessor as a first test). Various other ARM and PPC updates. 20050904 Adding some SHcompact disassembly routines. 20050907 (Re)adding a dummy HPPA CPU module, and a dummy i960 module. 20050908 Began hacking on some Apple Partition Table support. 20050909 Adding support for loading Mach-O (Darwin PPC) binaries. 20050910 Fixing an ARM bug (Carry flag was incorrectly updated for some data processing instructions); OpenBSD/cats and NetBSD/ netwinder get quite a bit further now. Applying a patch to dev_wdc, and a one-liner to dev_pcic, to make them work better when emulating new versions of OpenBSD. (Thanks to Alexander Yurchenko for the patches.) Also doing some other minor updates to dev_wdc. (Some cleanup, and finally converting to devinit, etc.) 20050912 IRIX doesn't have u_int64_t by default (noticed by Andreas ); configure updated to reflect this. Working on ARM register bank switching, CPSR vs SPSR issues, and beginning the work on interrupt/exception support. 20050913 Various minor ARM updates (speeding up load/store multiple, and fixing a ROR bug in R(); NetBSD/cats now boots as far as OpenBSD/cats). 20050917 Adding a dummy Atmel AVR (8-bit) cpu family skeleton. 20050918 Various minor updates. 20050919 Symbols are now loaded from Mach-O executables. Continuing the work on adding ARM exception support. 20050920 More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach userland! :-) 20050921 Some more progress on ARM interrupt specifics. 20050923 Fixing linesize for VR4121 (patch by Yurchenko). Also fixing linesizes/cachesizes for some other VR4xxx. Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a dummy Symphony Labs 83C553 bridge (for Netwinder), usable by dev_footbridge. 20050924 Some PPC progress. 20050925 More PPC progress. 20050926 PPC progress (fixing some bugs etc); Darwin's kernel gets slightly further than before. 20050928 Various updates: footbridge/ISA/pciide stuff, and finally fixing the VGA text scroll-by-changing-the-base-offset bug. 20050930 Adding a dummy S3 ViRGE pci card for CATS emulation, which both NetBSD and OpenBSD detects as VGA. Continuing on Footbridge (timers, ISA interrupt stuff). 20051001 Continuing... there are still bugs, probably interrupt- related. 20051002 More work on the Footbridge (interrupt stuff). 20051003 Various minor updates. (Trying to find the bug(s).) 20051004 Continuing on the ARM stuff. 20051005 More ARM-related fixes. 20051007 FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the other was because of an error in the ARM manual (load multiple with the S-bit set should _NOT_ load usermode registers, as the manual says, but it should load saved registers, which may or may not happen to be usermode registers). NetBSD/cats and OpenBSD/cats seem to install fine now :-) except for a minor bug at the end of the OpenBSD/cats install. Updating the documentation, preparing for the next release. 20051008 Continuing with release testing and cleanup. ============== RELEASE 0.3.6 ============== 20051008 The bug was not because of faulty ARM documentation after all, but it was related to those parts of the code. Fixing the RTC (dev_mc146818) to work with CATS. 20051009 Rewriting the R() function; now there are 8192 automatically generated smaller functions doing the same thing, but hopefully faster. This also fixes some bugs which were triggered when trying to compile GXemul inside itself. :-) Adding a dummy dev_lpt. 20051010 Small hack to not update virtual translation tables if memory accesses are done with the NO_EXCEPTION flag; a time reduction of almost a factor 2 for a full NetBSD/cats install. :-) 20051011 Passing -A as the default boot arg for CATS (works fine with OpenBSD/cats). ============== RELEASE 0.3.6.1 ============== 20051012 Fixing the VGA cursor offset bug, and speeding up framebuffer redraws if character cells contain the same thing as during the last redraw. 20051013 Adding a slow strd ARM instruction hack. 20051017 Minor updates: Adding a dummy i80321 Verde controller (for XScale emulation), fixing the disassembly of the ARM "ldrd" instruction, adding "support" for less-than-4KB pages for ARM (by not adding them to translation tables). 20051020 Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints some boot messages on an emulated Jornada 720. Making dev_ram work better with dyntrans (speeds up some things quite a bit). 20051021 Automatically generating some of the most common ARM load/store multiple instructions. 20051022 Better statistics gathering for the ARM load/store multiple. Various other dyntrans and device updates. 20051023 Various minor updates. 20051024 Continuing; minor device and dyntrans fine-tuning. Adding the first "reasonable" instruction combination hacks for ARM (the cores of NetBSD/cats' memset and memcpy). 20051025 Fixing a dyntrans-related bug in dev_vga. Also changing the dyntrans low/high access notification to only be updated on writes, not reads. Hopefully it will be enough. (dev_vga in charcell mode now seems to work correctly with both reads and writes.) Experimenting with gathering dyntrans statistics (which parts of emulated RAM that are actually executed), and adding instruction combination hacks for cache cleaning and a part of NetBSD's scanc() function. 20051026 Adding a bitmap for ARM emulation which indicates if a page is (specifically) user accessible; loads and stores with the t- flag set can now use the translation arrays, which results in a measurable speedup. 20051027 Dyntrans updates; adding an extra bitmap array for 32-bit emulation modes, speeding up the check whether a physical page has any code translations or not (O(n) -> O(1)). Doing a similar reduction of O(n) to O(1) by avoiding the scan through the translation entries on a translation update (32-bit mode only). Various other minor hacks. 20051029 Quick release, without any testing at all. ============== RELEASE 0.3.6.2 ============== 20051031 Adding disassembly support for more ARM instructions (clz, smul* etc), and adding a hack to support "new tiny" pages for StrongARM. 20051101 Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD 3.7 -> 3.8, and lots of testing). Changing from 1-sector PIO mode 0 transfers to 128-sector PIO mode 3 (in dev_wdc). Various minor ARM dyntrans updates (pc-relative loads from within the same page as the instruction are now treated as constant "mov"). 20051102 Re-enabling instruction combinations (they were accidentally disabled). Dyntrans TLB entries are now overwritten using a round-robin scheme instead of randomly. This increases performance. Fixing a typo in file.c (thanks to Chuan-Hua Chang for noticing it). Experimenting with adding ATAPI support to dev_wdc (to make emulated *BSD detect cdroms as cdroms, not harddisks). 20051104 Various minor updates. 20051105 Continuing on the ATAPI emulation. Seems to work well enough for a NetBSD/cats installation, but not OpenBSD/cats. Various other updates. 20051106 Modifying the -Y command line option to allow scaleup with certain graphic controllers (only dev_vga so far), not just scaledown. Some minor dyntrans cleanups. 20051107 Beginning a cleanup up the PCI subsystem (removing the read_register hack, etc). 20051108 Continuing the cleanup; splitting up some pci devices into a normal autodev device and some separate pci glue code. 20051109 Continuing on the PCI bus stuff; all old pci_*.c have been incorporated into normal devices and/or rewritten as glue code only, adding a dummy Intel 82371AB PIIX4 for Malta (not really tested yet). Minor pckbc fix so that Linux doesn't complain. Working on the DEC 21143 NIC (ethernet mac rom stuff mostly). Various other minor fixes. 20051110 Some more ARM dyntrans fine-tuning (e.g. some instruction combinations (cmps followed by conditional branch within the same page) and special cases for DPIs with regform when the shifter isn't used). 20051111 ARM dyntrans updates: O(n)->O(1) for just-mark-as-non- writable in the generic pc_to_pointers function, and some other minor hacks. Merging Cobalt and evbmips (Malta) ISA interrupt handling, and some minor fixes to allow Linux to accept harddisk irqs. 20051112 Minor device updates (pckbc, dec21143, lpt, ...), most importantly fixing the ALI M1543/M5229 so that harddisk irqs work with Linux/CATS. 20051113 Some more generalizations of the PCI subsystem. Finally took the time to add a hack for SCSI CDROM TOCs; this enables OpenBSD to use partition 'a' (as needed by the OpenBSD installer), and Windows NT's installer to get a bit further. Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs. Continuing on the DEC 21143. 20051114 Minor ARM dyntrans tweaks; ARM cmps+branch optimization when comparing with 0, and generalizing the xchg instr. comb. Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}. 20051115 Continuing on various PPC things (BATs, other address trans- lation things, various loads/stores, BeBox emulation, etc.). Beginning to work on PPC interrupt/exception support. 20051116 Factoring out some code which initializes legacy ISA devices from those machines that use them (bus_isa). Continuing on PPC interrupt/exception support. 20051117 Minor Malta fixes: RTC year offset = 80, disabling a speed hack which caused NetBSD to detect a too fast cpu, and adding a new hack to make Linux detect a faster cpu. Continuing on the Artesyn PM/PPC emulation mode. Adding an Algor emulation skeleton (P4032 and P5064); implementing some of the basics. Continuing on PPC emulation in general; usage of unimplemented SPRs is now easier to track, continuing on memory/exception related issues, etc. 20051118 More work on PPC emulation (tgpr0..3, exception handling, memory stuff, syscalls, etc.). 20051119 Changing the ARM dyntrans code to mostly use cpu->pc, and not necessarily use arm reg 15. Seems to work. Various PPC updates; continuing on the PReP emulation mode. 20051120 Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep to detect the clock. 20051121 More cleanup of the PCI bus (memory and I/O bases, etc). Continuing on various PPC things (decrementer and timebase, WDCs on obio (on PReP) use irq 13, not 14/15). 20051122 Continuing on the CPC700 controller (interrupts etc) for PMPPC, and on PPC stuff in general. Finally! After some bug fixes to the virtual to physical addr translation, NetBSD/{prep,pmppc} 2.1 reach userland and are stable enough to be interacted with. More PCI updates; reverse-endian device access for PowerPC etc. 20051123 Generalizing the IEEE floating point subsystem (moving it out from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c). Input via slave xterms was sometimes not really working; fixing this for ns16550, and a warning message is now displayed if multiple non-xterm consoles are active. Adding some PPC floating point support, etc. Various interrupt related updates (dev_wdc, _ns16550, _8259, and the isa32 common code in machine.c). NetBSD/prep can now be installed! :-) (Well, with some manual commands necessary before running sysinst.) Updating the documentation and various other things to reflect this. 20051124 Various minor documentation updates. Continuing the work on the DEC 21143 NIC. 20051125 LOTS of work on the 21143. Both OpenBSD and NetBSD work fine with it now, except that OpenBSD sometimes gives a time-out warning. Minor documentation updates. ============== RELEASE 0.3.7 ============== 20051126 Cobalt and PReP now work with the 21143 NIC. Continuing on Alpha dyntrans things. Fixing some more left-shift-by-24 to unsigned. 20051127 Working on OpenFirmware emulation; major cleanup/redesign. Progress on MacPPC emulation: NetBSD detects two CPUs (when running with -n 2), framebuffer output (for text) works. Adding quick-hack Bandit PCI controller and "gc" interrupt controller for MacPPC. 20051128 Changing from a Bandit to a Uni-North controller for macppc. Continuing on OpenFirmware and MacPPC emulation in general (obio controller, and wdc attached to the obio seems to work). 20051129 More work on MacPPC emulation (adding a dummy ADB controller). Continuing the PCI bus cleanup (endianness and tag composition) and rewriting all PCI controllers' access functions. 20051130 Various minor PPC dyntrans optimizations. Manually inlining some parts of the framebuffer redraw routine. Slowly beginning the conversion of the old MIPS emulation into dyntrans (but this will take quite some time to get right). Generalizing quick_pc_to_pointers. 20051201 Documentation update (David Muse has made available a kernel which simplifies Debian/DECstation installation). Continuing on the ADB bus controller. 20051202 Beginning a rewrite of the Zilog serial controller (dev_zs). 20051203 Continuing on the zs rewrite (now called dev_z8530); conversion to devinit style. Reworking some of the input-only vs output-only vs input-output details of src/console.c, better warning messages, and adding a debug dump. Removing the concept of "device state"; it wasn't really used. Changing some debug output (-vv should now be used to show all details about devices and busses; not shown during normal startup anymore). Beginning on some SPARC instruction disassembly support. 20051204 Minor PPC updates (WALNUT skeleton stuff). Continuing on the MIPS dyntrans rewrite. More progress on the ADB controller (a keyboard is "detected" by NetBSD and OpenBSD). Downgrading OpenBSD/arc as a guest OS from "working" to "almost working" in the documentation. Progress on Algor emulation ("v3" PCI controller). 20051205 Minor updates. 20051207 Sorting devices according to address; this reduces complexity of device lookups from O(n) to O(log n) in memory_rw (but no real performance increase (yet) in experiments). 20051210 Beginning the work on native dyntrans backends (by making a simple skeleton; so far only for Alpha hosts). 20051211 Some very minor SPARC updates. 20051215 Fixing a bug in the MIPS mul (note: not mult) instruction, so it also works with non-64-bit emulation. (Thanks to Alec Voropay for noticing the problem.) 20051216 More work on the fake/empty/simple/skeleton/whatever backend; performance doesn't increase, so this isn't really worth it, but it was probably worth it to prepare for a real backend later. 20051219 More instr call statistics gathering and analysis stuff. 20051220 Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z} to dyntrans. memory_ppc.c syntax error fix (noticed by Peter Valchev). Beginning to move out machines from src/machine.c into individual files in src/machines (in a way similar to the autodev system for devices). 20051222 Updating the documentation regarding NetBSD/pmax 3.0. 20051223 - " - NetBSD/cats 3.0. 20051225 - " - NetBSD/hpcmips 3.0. 20051226 Continuing on the machine registry redesign. Adding support for ARM rrx (33-bit rotate). Fixing some signed/unsigned issues (exposed by gcc -W). 20051227 Fixing the bug which prevented a NetBSD/prep 3.0 install kernel from starting (triggered when an mtmsr was the last instruction on a page). Unfortunately not enough to get the kernel to run as well as the 2.1 kernels did. 20051230 Some dyntrans refactoring. 20051231 Continuing on the machine registry redesign. 20060101-10 Continuing... moving more machines. Moving MD interrupt stuff from machine.c into a new src/machines/interrupts.c. 20060114 Adding various mvmeppc machine skeletons. 20060115 Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages (for MVME1600) and reaches the root device prompt, but no specific hardware devices are emulated yet. 20060116 Minor updates to the mvme1600 emulation mode; the Eagle PCI bus seems to work without much modification, and a 21143 can be detected, interrupts might work (but untested so far). Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc. 20060121 Adding an aux control register for ARM. (A BIG thank you to Olivier Houchard for tracking down this bug.) 20060122 Adding more ARM instructions (smulXY), and dev_iq80321_7seg. 20060124 Adding disassembly of more ARM instructions (mia*, mra/mar), and some semi-bogus XScale and i80321 registers. 20060201-02 Various minor updates. Moving the last machines out of machine.c. 20060204 Adding a -c command line option, for running debugger commands before the simulation starts, but after all files have been loaded. Minor iq80321-related updates. 20060209 Minor hacks (DEVINIT macro, etc). Preparing for the generalization of the 64-bit dyntrans address translation subsystem. 20060216 Adding ARM ldrd (double-register load). 20060217 Continuing on various ARM-related stuff. 20060218 More progress on the ATA/wdc emulation for NetBSD/iq80321. NetBSD/evbarm can now be installed :-) Updating the docs, etc. Continuing on Algor emulation. ============== RELEASE 0.3.8 ============== 20060219 Various minor updates. Removing the old MIPS16 skeleton code, because it will need to be rewritten for dyntrans anyway. 20060220-22 Removing the non-working dyntrans backend support. Continuing on the 64-bit dyntrans virtual memory generalization. 20060223 More work on the 64-bit vm generalization. 20060225 Beginning on MIPS dyntrans load/store instructions. Minor PPC updates (64-bit load/store, etc). Fixes for the variable-instruction-length framework, some minor AVR updates (a simple Hello World program works!). Beginning on a skeleton for automatically generating documen- tation (for devices etc.). 20060226 PPC updates (adding some more 64-bit instructions, etc). AVR updates (more instructions). FINALLY found and fixed the zs bug, making NetBSD/macppc accept the serial console. 20060301 Adding more AVR instructions. 20060304 Continuing on AVR-related stuff. Beginning on a framework for cycle-accurate device emulation. Adding an experimental "PAL TV" device (just a dummy so far). 20060305 Adding more AVR instructions. Adding a dummy epcom serial controller (for TS7200 emulation). 20060310 Removing the emul() command from configuration files, so only net() and machine() are supported. Minor progress on the MIPS dyntrans rewrite. 20060311 Continuing on the MIPS dyntrans rewrite (adding more instructions, etc). 20060315 Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l], beql, bnel, slti[u], various loads and stores). 20060316 Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely used. Adding more MIPS dyntrans instructions, and fixing bugs. 20060318 Implementing fast loads/stores for MIPS dyntrans (big/little endian, 32-bit and 64-bit modes). 20060320 Making MIPS dyntrans the default configure option; use "--enable-oldmips" to use the old bintrans system. Adding MIPS dyntrans dmult[u]; minor updates. 20060322 Continuing... adding some more instructions. Adding a simple skeleton for demangling C++ "_ZN" symbols. 20060323 Moving src/debugger.c into a new directory (src/debugger/). 20060324 Fixing the hack used to load PPC ELFs (useful for relocated Linux/ppc kernels), and adding a dummy G3 machine mode. 20060325-26 Beginning to experiment with GDB remote serial protocol connections; adding a -G command line option for selecting which TCP port to listen to. 20060330 Beginning a major cleanup to replace things like "0x%016llx" with more correct "0x%016"PRIx64, etc. Continuing on the GDB remote serial protocol support. 20060331 More cleanup, and some minor GDB remote progress. 20060402 Adding a hack to the configure script, to allow compilation on systems that lack PRIx64 etc. 20060406 Removing the temporary FreeBSD/arm hack in dev_ns16550.c and replacing it with a better fix from Olivier Houchard. 20060407 A remote debugger (gdb or ddd) can now start and stop the emulator using the GDB remote serial protocol, and registers and memory can be read. MIPS only for now. 20060408 More GDB progress: single-stepping also works, and also adding support for ARM, PowerPC, and Alpha targets. Continuing on the delay-slot-across-page-boundary issue. 20060412 Minor update: beginning to add support for the SPARC target to the remote GDB functionality. 20060414 Various MIPS updates: adding more instructions for dyntrans (eret, add), and making some exceptions work. Fixing a bug in dmult[u]. Implementing the first SPARC instructions (sethi, or). 20060415 Adding "magic trap" instructions so that PROM calls can be software emulated in MIPS dyntrans. Adding more MIPS dyntrans instructions (ddiv, dadd) and fixing another bug in dmult. 20060416 More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv, rfi, an ugly hack for supporting R2000/R3000 style faked caches, preliminary interrupt support, and various other updates and bugfixes. 20060417 Adding more SPARC instructions (add, sub, sll[x], sra[x], srl[x]), and useful SPARC header definitions. Adding the first (trivial) x86/AMD64 dyntrans instructions (nop, cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other x86 updates related to variable instruction length stuff. Adding unaligned loads/stores to the MIPS dyntrans mode (but still using the pre-dyntrans (slow) imlementation). 20060419 Fixing a MIPS dyntrans exception-in-delay-slot bug. Removing the old "show opcode statistics" functionality, since it wasn't really useful and isn't implemented for dyntrans. Single-stepping (or running with instruction trace) now looks ok with dyntrans with delay-slot architectures. 20060420 Minor hacks (removing the -B command line option when compiled for non-bintrans, and some other very minor updates). Adding (slow) MIPS dyntrans load-linked/store-conditional. 20060422 Applying fixes for bugs discovered by Nils Weller's nwcc (static DEC memmap => now per machine, and adding an extern keyword in cpu_arm_instr.c). Finally found one of the MIPS dyntrans bugs that I've been looking for (copy/paste spelling error BIG vs LITTLE endian in cpu_mips_instr_loadstore.c for 16-bit fast stores). FINALLY found the major MIPS dyntrans bug: slti vs sltiu signed/unsigned code in cpu_mips_instr.c. :-) Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l], ctc1, tlt[u], tge[u], tne, beginning on rdhwr). NetBSD/hpcmips can now reach userland when using dyntrans :-) Adding some more x86 dyntrans instructions. Finally removed the old Alpha-specific virtual memory code, and replaced it with the generic 64-bit version. Beginning to add disassembly support for SPECIAL3 MIPS opcodes. 20060423 Continuing on the delay-slot-across-page-boundary issue; adding an end_of_page2 ic slot (like I had planned before, but had removed for some reason). Adding a quick-and-dirty fallback to legacy coprocessor 1 code (i.e. skipping dyntrans implementation for now). NetBSD/hpcmips and NetBSD/pmax (when running on an emulated R4400) can now be installed and run. :-) (Many bugs left to fix, though.) Adding more MIPS dyntrans instructions: madd[u], msub[u]. Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode maps somewhat (disassembly and dyntrans instruction decoding). 20060424 Adding an isa_revision field to mips_cpu_types.h, and making sure that SPECIAL3 opcodes cause Reserved Instruction exceptions on MIPS32/64 revisions lower than 2. Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor' instructions. 20060425 Removing the -m command line option ("run at most x instructions") and -T ("single_step_on_bad_addr"), because they never worked correctly with dyntrans anyway. Freshening up the man page. 20060428 Adding more MIPS dyntrans instructions: bltzal[l], idle. Enabling MIPS dyntrans compare interrupts. 20060429 FINALLY found the weird dyntrans bug, causing NetBSD etc. to behave strangely: some floating point code (conditional coprocessor branches) could not be reused from the old non-dyntrans code. The "quick-and-dirty fallback" only appeared to work. Fixing by implementing bc1* for MIPS dyntrans. More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0. Freshening up MIPS floating point disassembly appearance. 20060430 Continuing on C790/R5900/TX79 disassembly; implementing 128-bit "por" and "pextlw". 20060504 Disabling -u (userland emulation) unless compiled as unstable development version. Beginning on freshening up the testmachine include files, to make it easier to reuse those files (placing them in src/include/testmachine/), and beginning on a set of "demos" or "tutorials" for the testmachine functionality. Minor updates to the MIPS GDB remote protocol stub. Refreshing doc/experiments.html and gdb_remote.html. Enabling Alpha emulation in the stable release configuration, even though no guest OSes for Alpha can run yet. 20060505 Adding a generic 'settings' object, which will contain references to settable variables (which will later be possible to access using the debugger). 20060506 Updating dev_disk and corresponding demo/documentation (and switching from SCSI to IDE disk types, so it actually works with current test machines :-). 20060510 Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts, so that fseeko() doesn't give a warning. Updating the section about how dyntrans works (the "runnable IR") in doc/intro.html. Instruction updates (some x64=1 checks, some more R5900 dyntrans stuff: better mul/mult separation from MIPS32/64, adding ei and di). Updating MIPS cpuregs.h to a newer one (from NetBSD). Adding more MIPS dyntrans instructions: deret, ehb. 20060514 Adding disassembly and beginning implementation of SPARC wr and wrpr instructions. 20060515 Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1 machines. Adding the 32-bit "rd psr" instruction. 20060517 Disassembly support for the general SPARC rd instruction. Partial implementation of the cmp (subcc) instruction. Some other minor updates (making sure that R5900 processors start up with the EIE bit enabled, otherwise Linux/playstation2 receives no interrupts). 20060519 Minor MIPS updates/cleanups. 20060521 Moving the MeshCube machine into evbmips; this seems to work reasonably well with a snapshot of a NetBSD MeshCube kernel. Cleanup/fix of MIPS config0 register initialization. 20060529 Minor MIPS fixes, including a sign-extension fix to the unaligned load/store code, which makes NetBSD/pmax on R3000 work better with dyntrans. (Ultrix and Linux/DECstation still don't work, though.) 20060530 Minor updates to the Alpha machine mode: adding an AlphaBook mode, an LCA bus (forwarding accesses to an ISA bus), etc. 20060531 Applying a bugfix for the MIPS dyntrans sc[d] instruction from Ondrej Palkovsky. (Many thanks.) 20060601 Minifix to allow ARM immediate msr instruction to not give an error for some valid values. More Alpha updates. 20060602 Some minor Alpha updates. 20060603 Adding the Alpha cmpbge instruction. NetBSD/alpha prints its first boot messages :-) on an emulated Alphabook 1. 20060612 Minor updates; adding a dev_ether.h include file for the testmachine ether device. Continuing the hunt for the dyntrans bug which makes Linux and Ultrix on DECstation behave strangely... FINALLY found it! It seems to be related to invalidation of the translation cache, on tlbw{r,i}. There also seems to be some remaining interrupt-related problems. 20060614 Correcting the implementation of ldc1/sdc1 for MIPS dyntrans (so that it uses 16 32-bit registers if the FR bit in the status register is not set). 20060616 REMOVING BINTRANS COMPLETELY! Removing the old MIPS interpretation mode. Removing the MFHILO_DELAY and instruction delay stuff, because they wouldn't work with dyntrans anyway. 20060617 Some documentation updates (adding "NetBSD-archive" to some URLs, and new Debian/DECstation installation screenshots). Removing the "tracenull" and "enable-caches" configure options. Improving MIPS dyntrans performance somewhat (only invalidate translations if necessary, on writes to the entryhi register, instead of doing it for all cop0 writes). 20060618 More cleanup after the removal of the old MIPS emulation. Trying to fix the MIPS dyntrans performance bugs/bottlenecks; only semi-successful so far (for R3000). 20060620 Minor update to allow clean compilation again on Tru64/Alpha. 20060622 MIPS cleanup and fixes (removing the pc_last stuff, which doesn't make sense with dyntrans anyway, and fixing a cross- page-delay-slot-with-exception case in end_of_page). Removing the old max_random_cycles_per_chunk stuff, and the concept of cycles vs instructions for MIPS emulation. FINALLY found and fixed the bug which caused NetBSD/pmax clocks to behave strangely (it was a load to the zero register, which was treated as a NOP; now it is treated as a load to a dummy scratch register). 20060623 Increasing the dyntrans chunk size back to N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2. Preparing for a quick release, even though there are known bugs, and performance for non-R3000 MIPS emulation is very poor. :-/ Reverting to half the dyntrans chunk size again, because NetBSD/cats seemed less stable with full size chunks. :( NetBSD/sgimips 3.0 can now run :-) (With release 0.3.8, only NetBSD/sgimips 2.1 worked, not 3.0.) ============== RELEASE 0.4.0 ============== 20060624 Replacing the error-prone machine type initialization stuff with something more reasonable. Finally removing the old "cpu_run" kludge; moving around stuff in machine.c and emul.c to better suit the dyntrans system. Various minor dyntrans cleanups (renaming translate_address to translate_v2p, and experimenting with template physpages). 20060625 Removing the speed hack which separated the vph entries into two halves (code vs data); things seem a lot more stable now. Minor performance hack: R2000/R3000 cache isolation now only clears address translations when going into isolation, not when going out of it. Fixing the MIPS interrupt problems by letting mtc0 immediately cause interrupts. ============== RELEASE 0.4.0.1 ============== 20060626 Continuing on SPARC emulation (beginning on the 'save' instruction, register windows, etc). 20060629 Planning statistics gathering (new -s command line option), and renaming speed_tricks to allow_instruction_combinations. 20060630 Some minor manual page updates. Various cleanups. Implementing the -s command line option. 20060701 FINALLY found the bug which prevented Linux and Ultrix from running without the ugly hack in the R2000/R3000 cache isol code; it was the phystranslation hint array which was buggy. Removing the phystranslation hint code completely, for now. 20060702 Minor dyntrans cleanups; invalidation of physpages now only invalidate those parts of a page that have actually been translated. (32 parts per page.) Some MIPS non-R3000 speed fixes. Experimenting with MIPS instruction combination for some addiu+bne+sw loops, and sw+sw+sw. Adding support (again) for larger-than-4KB pages in MIPS tlbw*. Continuing on SPARC emulation: adding load/store instructions. 20060704 Fixing a virtual vs physical page shift bug in the new tlbw* implementation. Problem noticed by Jakub Jermar. (Many thanks.) Moving rfe and eret to cpu_mips_instr.c, since that is the only place that uses them nowadays. 20060705 Removing the BSD license from the "testmachine" include files, placing them in the public domain instead; this enables the testmachine stuff to be used from projects which are incompatible with the BSD license for some reason. 20060707 Adding instruction combinations for the R2000/R3000 L1 I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu, various branches followed by addiu or nop, and jr ra followed by addiu. The time it takes to perform a full NetBSD/pmax R3000 install on the laptop has dropped from 573 seconds to 539. :-) 20060708 Adding a framebuffer controller device (dev_fbctrl), which so far can be used to change the fb resolution during runtime, but in the future will also be useful for accelerated block fill/ copy, and possibly also simplified character output. Adding an instruction combination for NetBSD/pmax' strlen. 20060709 Minor fixes: reading raw files in src/file.c wasn't memblock aligned, removing buggy multi_sw MIPS instruction combination, etc. 20060711 Adding a machine_qemu.c, which contains a "qemu_mips" machine. (It mimics QEMU's MIPS machine mode, so that a test kernel made for QEMU_MIPS also can run in GXemul... at least to some extent.) Adding a short section about how to run this mode to doc/guestoses.html. 20060714 Misc. minor code cleanups. 20060715 Applying a patch which adds getchar() to promemul/yamon.c (from Oleksandr Tymoshenko). Adding yamon.h from NetBSD, and rewriting yamon.c to use it (instead of ugly hardcoded numbers) + some cleanup. 20060716 Found and fixed the bug which broke single-stepping of 64-bit programs between 0.4.0 and 0.4.0.1 (caused by too quick refactoring and no testing). Hopefully this fix will not break too many other things. 20060718 Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS. Re-adding the sw+sw+sw instr comb (the problem was that I had ignored endian issues); however, it doesn't seem to give any big performance gain. 20060720 Adding a dummy Transputer mode (T414, T800 etc) skeleton (only the 'j' and 'ldc' instructions are implemented so far). :-} 20060721 Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus misc. other updates to get Linux 2.6 for evbmips/malta working (thanks to Alec Voropay for the details). FINALLY found and fixed the bug which made tlbw* for non-R3000 buggy; it was a reference count problem in the dyntrans core. 20060722 Testing stuff; things seem stable enough for a new release. ============== RELEASE 0.4.1 ============== 20060723 More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp, eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move, wcnt, add, bcnt). Adding more SPARC instructions (andcc, addcc, bl, rdpr). Progress on the igsfb framebuffer used by NetBSD/netwinder. Enabling 8-bit fills in dev_fb. NetBSD/netwinder 3.0.1 can now run from a disk image :-) 20060724 Cleanup/performance fix for 64-bit virtual translation table updates (by removing the "timestamp" stuff). A full NetBSD/pmax 3.0.1 install for R4400 has dropped from 667 seconds to 584 :) Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit). Adding some MIPS instruction combinations (3*lw, and 3*addu). The 8048 keyboard now turns off interrupt enable between the KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6. Not causing PPC DEC interrupts if PPC_NO_DEC is set for a specific CPU; NetBSD/bebox gets slightly further than before. Adding some more SPARC instructions: branches, udiv. 20060725 Refreshing dev_pckbc.c a little. Cleanups for the SH emulation mode, and adding the first "compact" (16-bit) instructions: various simple movs, nop, shll, stc, or, ldc. 20060726 Adding dummy "pcn" (AMD PCnet NIC) PCI glue. 20060727 Various cleanups; removing stuff from cpu.h, such as running_translated (not really meaningful anymore), and page flags (breaking into the debugger clears all translations anyway). Minor MIPS instruction combination updates. 20060807 Expanding the 3*sw and 3*lw MIPS instruction combinations to work with 2* and 4* too, resulting in a minor performance gain. Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait" instruction (when emulating 1 cpu). 20060808 Experimenting with some more MIPS instruction combinations. Implementing support for showing a (hardcoded 12x22) text cursor in igsfb. 20060809 Simplifying the NetBSD/evbmips (Malta) install instructions somewhat (by using a NetBSD/pmax ramdisk install kernel). 20060812 Experimenting more with the MIPS 'wait' instruction. PCI configuration register writes can now be handled, which allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.) 20060813 Updating dev_gt.c based on numbers from Alec Voropay, to enable Linux 2.6 to use PCI on Malta. Continuing on Algor interrupt stuff. 20060814 Adding support for routing ISA interrupts to two different interrupts, making it possible to run NetBSD/algor :-) 20060814-15 Testing for the release. ============== RELEASE 0.4.2 ============== 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 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 ============== 20061107 Adding a new disk image option (-d o...) which sets the ISO9660 filesystem base offset; also making some other hacks to allow NetBSD/dreamcast and homebrew demos/games to boot directly from a filesystem image. Moving Dreamcast-specific stuff in the documentation to its own page (dreamcast.html). Adding a border to the Dreamcast PVR framebuffer. 20061108 Adding a -T command line option (again?), for halting the emulator on unimplemented memory accesses. 20061109 Continuing on various SH4 and Dreamcast related things. The emulator should now halt on more unimplemented device accesses, instead of just printing a warning, forcing me to actually implement missing stuff :) 20061111 Continuing on SH4 and Dreamcast stuff. Adding a bogus Landisk (SH4) machine mode. 20061112 Implementing some parts of the Dreamcast GDROM device. With some ugly hacks, NetBSD can (barely) mount an ISO image. 20061113 NetBSD/dreamcast now starts booting from the Live CD image, but crashes randomly quite early on in the boot process. 20061122 Beginning on a skeleton interrupt.h and interrupt.c for the new interrupt subsystem. 20061124 Continuing on the new interrupt system; taking the first steps to attempt to connect CPUs (SuperH and MIPS) and devices (dev_cons and SH4 timer interrupts) to it. Many things will probably break from now on. 20061125 Converting dev_ns16550, dev_8253 to the new interrupt system. Attempting to begin to convert the ISA bus. 20061130 Incorporating a patch from Brian Foley for the configure script, which checks for X11 libs in /usr/X11R6/lib64 (which is used on some Linux systems). 20061227 Adding a note in the man page about booting from Dreamcast CDROM images (i.e. that no external kernel is needed). 20061229 Continuing on the interrupt system rewrite: beginning to convert more devices, adding abort() calls for legacy interrupt system calls so that everything now _has_ to be rewritten! Almost all machine modes are now completely broken. 20061230 More progress on removing old interrupt code, mostly related to the ISA bus + devices, the LCA bus (on AlphaBook1), and the Footbridge bus (for CATS). And some minor PCI stuff. Connecting the ARM cpu to the new interrupt system. The CATS, NetWinder, and QEMU_MIPS machine modes now work with the new interrupt system :) 20061231 Connecting PowerPC CPUs to the new interrupt system. Making PReP machines (IBM 6050) work again. Beginning to convert the GT PCI controller (for e.g. Malta and Cobalt emulation). Some things work, but not everything. Updating Copyright notices for 2007. 20070101 Converting dev_kn02 from legacy style to devinit; the 3max machine mode now works with the new interrupt system :-] 20070105 Beginning to convert the SGI O2 machine to the new interrupt system; finally converting O2 (IP32) devices to devinit, etc. 20070106 Continuing on the interrupt system redesign/rewrite; KN01 (PMAX), KN230, and Dreamcast ASIC interrupts should work again, moving out stuff from machine.h and devices.h into the corresponding devices, beginning the rewrite of i80321 interrupts, etc. 20070107 Beginning on the rewrite of Eagle interrupt stuff (PReP, etc). 20070117 Beginning the rewrite of Algor (V3) interrupts (finally changing dev_v3 into devinit style). 20070118 Removing the "bus" registry concept from machine.h, because it was practically meaningless. Continuing on the rewrite of Algor V3 ISA interrupts. 20070121 More work on Algor interrupts; they are now working again, well enough to run NetBSD/algor. :-) 20070122 Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips can be installed using the new interrupt system :-) 20070123 Making the testmips mode work with the new interrupt system. 20070127 Beginning to convert DEC5800 devices to devinit, and to the new interrupt system. Converting Playstation 2 devices to devinit, and converting the interrupt system. Also fixing a severe bug: the interrupt mask register on Playstation 2 is bitwise _toggled_ on writes. 20070128 Removing the dummy NetGear machine mode and the 8250 device (which was only used by the NetGear machine). Beginning to convert the MacPPC GC (Grand Central) interrupt controller to the new interrupt system. Converting Jazz interrupts (PICA61 etc.) to the new interrupt system. NetBSD/arc can be installed again :-) Fixing the JAZZ timer (hardcoding it at 100 Hz, works with NetBSD and it is better than a completely dummy timer as it was before). Converting dev_mp to the new interrupt system, although I haven't had time to actually test it yet. Completely removing src/machines/interrupts.c, cpu_interrupt and cpu_interrupt_ack in src/cpu.c, and src/include/machine_interrupts.h! Adding fatal error messages + abort() in the few places that are left to fix. Converting dev_z8530 to the new interrupt system. FINALLY removing the md_int struct completely from the machine struct. SH4 fixes (adding a PADDR invalidation in the ITLB replacement code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs all the way to the login prompt, and can be interacted with :-) Converting the CPC700 controller (PCI and interrupt controller for PM/PPC) to the new interrupt system. 20070129 Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/ sgimips' and OpenBSD/sgi's ramdisk kernels can now be interacted with again. 20070130 Moving out the MIPS multi_lw and _sw instruction combinations so that they are auto-generated at compile time instead. 20070131 Adding detection of amd64/x86_64 hosts in the configure script, for doing initial experiments (again :-) with native code generation. Adding a -k command line option to set the size of the dyntrans cache, and a -B command line option to disable native code generation, even if GXemul was compiled with support for native code generation for the specific host CPU architecture. 20070201 Experimenting with a skeleton for native code generation. Changing the default behaviour, so that native code generation is now disabled by default, and has to be enabled by using -b on the command line. 20070202 Continuing the native code generation experiments. Making PCI interrupts work for Footbridge again. 20070203 More native code generation experiments. Removing most of the native code generation experimental code, it does not make sense to include any quick hacks like this. Minor cleanup/removal of some more legacy MIPS interrupt code. 20070204 Making i80321 interrupts work again (for NetBSD/evbarm etc.), and fixing the timer at 100 Hz. 20070206 Experimenting with removing the wdc interrupt slowness hack. 20070207 Lowering the number of dyntrans TLB entries for MIPS from 192 to 128, resulting in a minor speed improvement. Minor optimization to the code invalidation routine in cpu_dyntrans.c. 20070208 Increasing (experimentally) the nr of dyntrans instructions per loop from 60 to 120. 20070210 Commenting out (experimentally) the dyntrans_device_danger detection in memory_rw.c. Changing the testmips and baremips machines to use a revision 2 MIPS64 CPU by default, instead of revision 1. Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC files, the PC bios emulation, and the Olivetti M700 (ARC) and db64360 emulation modes. 20070211 Adding an "mp" demo to the demos directory, which tests the SMP functionality of the testmips machine. Fixing PReP interrupts some more. NetBSD/prep now boots again. 20070216 Adding a "nop workaround" for booting Mach/PMAX to the documentation; thanks to Artur Bujdoso for the values. Converting more of the MacPPC interrupt stuff to the new system. Beginning to convert BeBox interrupts to the new system. PPC603e should NOT have the PPC_NO_DEC flag! Removing it. Correcting BeBox clock speed (it was set to 100 in the NetBSD bootinfo block, but should be 33000000/4), allowing NetBSD to start without using the (incorrect) PPC_NO_DEC hack. 20070217 Implementing (slow) AltiVec vector loads and stores, allowing NetBSD/macppc to finally boot using the GENERIC kernel :-) Updating the documentation with install instructions for NetBSD/macppc. 20070218-19 Regression testing for the release. ============== RELEASE 0.4.4 ============== 20070224 Minor update to the initialization of the ns16550 in machine_walnut.c, to allow that machine type to boot with the new interrupt system (although it is still a dummy machine). Adding a wdc at 0x14000000 to machine_landisk.c, and fixing the SCIF serial interrupts of the SH4 cpu enough to get NetBSD/landisk booting from a disk image :-) Adding a preliminary install instruction skeleton to guestoses.html. 20070306 Adding SH-IPL+G PROM emulation, and also passing the "end" symbol in r5 on bootup, for Landisk emulation. This is enough to get OpenBSD/landisk to install :) Adding a preliminary install instruction skeleton to the documentation. SuperH emulation is still shaky, though :-/ 20070307 Fixed a strangeness in memory_sh.c (read/write was never returned for any page). (Unknown whether this fixes any actual problems, though.) 20070308 dev_ram.c fix: invalidate code translations on writes to RAM, emulated as separate devices. Linux/dreamcast gets further in the boot process than before, but still bugs out in userland. Fixing bugs in the "stc.l gbr,@-rN" and "ldc.l @rN+,gbr" SuperH instructions (they should NOT check the MD bit), allowing the Linux/dreamcast Live CD to reach userland correctly :-) 20070310 Changing the cpu name "Alpha" in src/useremul.c to "21364" to unbreak userland syscall emulation of FreeBSD/Alpha binaries. 20070314 Applying a patch from Michael Yaroslavtsev which fixes the previous Linux lib64 patch to the configure script. 20070315 Adding a (dummy) sun4v machine type, and SPARC T1 cpu type. 20070316 Creating a new directory, src/disk, and moving diskimage.c to it. Separating out bootblock loading stuff from emul.c into new files in src/disk. Adding some more SPARC registers. 20070318 Preparing/testing for a minirelease, 0.4.4.1. ============== RELEASE 0.4.4.1 ============== 20070324 Adding a "--debug" option to the configure script, to disable optimizations in unstable development builds. Moving out SCSI-specific stuff from diskimage.c into a new diskimage_scsicmd.c. Applying Håvard Eidnes' patch for SCSICDROM_READ_DISKINFO and SCSICDROM_READ_TRACKINFO. (Not really tested yet.) Implementing disk image "overlays" (to allow simple roll-back to previous disk state). Adding a 'V' disk flag for this, and updating the man page and misc.html. 20070325 Stability fix to cpu_dyntrans.c, when multiple physical pages share the same initial table entry. (The ppp == NULL check should be physpage_ofs == 0.) Bug found by analysing GXemul against a version patched for Godson. Fixing a second occurance of the same problem (also in cpu_dyntrans.c). Fixing a MAJOR physical page leak in cpu_dyntrans.c; pages weren't _added_ to the set of translated pages, they _replaced_ all previous pages. It's amazing that this bug has been able to live for this long. (Triggered when emulating >128MB RAM.) 20070326 Removing the GDB debugging stub support; it was too hackish and ugly. 20070328 Moving around some native code generation skeleton code. 20070329 The -lm check in the configure script now also checks for sin() in addition to sqrt(). (Thanks to Nigel Horne for noticing that sqrt was not enough on Fedora Core 6.) (Not verified yet.) 20070330 Fixing an indexing bug in dev_sh4.c, found by using gcc version 4.3.0 20070323. 20070331 Some more experimentation with native code generation. 20070404 Attempting to fix some more SH4 SCIF interrupt bugs; rewriting the SH interrupt assertion/deassertion code somewhat. 20070410 Splitting src/file.c into separate files in src/file/. Cleanup: Removing the dummy TS7200, Walnut, PB1000, and Meshcube emulation modes, and dev_epcom and dev_au1x00. Removing the experimental CHIP8/RCA180x code; it wasn't really working much lately, anyway. It was fun while it lasted. Also removing the experimental Transputer CPU support. 20070412 Moving the section about how the dynamic translation system works from intro.html to a separate translation.html file. Minor SH fixes; attempting to get OpenBSD/landisk to run without randomly bugging out, but no success yet. 20070413 SH SCI (serial bit interface) should now work together with a (new) RS5C313 clock device (for Landisk emulation). 20070414 Moving Redhat/MIPS down from supported to experimental, in guestoses.html. Preparing for a new release; doing some regression testing etc. ============== RELEASE 0.4.5 ============== 20070415 Landisk PCLOCK should be 33.33 MHz, not 50 MHz. (This makes the clock run at correct speed.) FINALLY found and fixed the bug which caused OpenBSD/landisk to randomly bug out: an &-sign was missing in the special case handling of FPSCR in the 'LDS.L @Rm+,FPSCR' instruction. Adding similar special case handling for 'LDC.L @Rm+,SR' (calling sh_update_sr() instead of just loading). Implementing the 'FCNVSD FPUL,DRn' and 'FCNVDS DRm,FPUL' SuperH instructions. The 'LDC Rm,SR' instruction now immediately breaks out of the dyntrans loop if an interrupt is to be triggered. 20070416 In memory_rw.c, if mapping a page as writable, make sure to invalidate code translations even if the data access was a read. Minor SuperH updates. 20070418 Removing the dummy M68K emulation mode. Minor SH update (turning unnecessary sts_mach_rn, sts_macl_rn, and sts_pr_rn instruction handlers into mov_rm_rn). 20070419 Beginning to add a skeleton for an M88K mode: Adding a hack to allow OpenBSD/m88k a.out binaries to be loaded, and disassembly of a few simple 88K instructions. Commenting out the 'LDC Rm,SR' fix from a few days ago, because it made Linux/dreamcast bug out. Adding a hack to dev_sh4.c (an extra translation cache invalidation), which allows OpenBSD/landisk to boot ok after an install. Upgrading the Landisk machine mode to stable, updating documentation, etc. 20070420 Experimenting with adding a PCI controller (pcic) to dev_sh4. Adding a dummy Realtek 8139C+ skeleton device (dev_rtl8139c). Implementing the first M88K instructions (br, or[.u] imm), and adding disassembly of some more instructions. 20070421 Continuing a little on dev_rtl8139c. 20070422 Implementing the 9346 EEPROM "read" command for dev_rtl8139c. Finally found and fixed an old bug in the log n symbol search (it sometimes missed symbols). Debug trace (-i, -t etc) should now show more symbols. :-) 20070423 Continuing a little on M88K disassembly. 20070428 Fixing a memset arg order bug in src/net/net.c (thanks to Nigel Horne for noticing the bug). Applying parts of a patch from Carl van Schaik to clear out bottom bits of MIPS addresses more correctly, when using large page sizes, and doing some other minor cleanup/refactoring. Fixing a couple of warnings given by gcc with the -W option (a few more warnings than just plain -Wall). Reducing SuperH dyntrans physical address space from 64-bit to 32-bit (since SH5/SH64 isn't imlemented yet anyway). Adding address-to-symbol annotation to a few more instructions in the SuperH instruction trace output. Beginning regression testing for the next release. Reverting the value of SCIF_DELAYED_TX_VALUE from 1 to 2, because OpenBSD/landisk may otherwise hang randomly. 20070429 The ugly hack/workaround to get OpenBSD/landisk booting without crashing does NOT work anymore (with the April 21 snapshot of OpenBSD/landisk). Strangely enough, removing the hack completely causes OpenBSD/landisk to work (!). More regression testing (re-testing everything SuperH-related, and some other things). Cobalt interrupts were actually broken; fixing by commenting out the DEC21143s in the Cobalt machine. 20070430 More regression testing. 20070501 Updating the OpenBSD/landisk install instructions to use 4.1 instead of the current snapshot. GAAAH! OpenBSD/landisk 4.1 _needs_ the ugly hack/workaround; reintroducing it again. (The 4.1 kernel is actually from 2007-03-11.) Simplifying the NetBSD/evbarm install instructions a bit. More regression testing. ============== RELEASE 0.4.5.1 ============== 20070501 Continuing a little on m88k disassembly (control registers, more instructions). Adding a dummy mvme88k machine mode. 20070502 Re-adding MIPS load/store alignment exceptions. 20070503 Implementing more of the M88K disassembly code. 20070504 Adding disassembly of some more M88K load/store instructions. Implementing some relatively simple M88K instructions (br.n, xor[.u] imm, and[.u] imm). 20070505 Implementing M88K three-register and, or, xor, and jmp[.n], bsr[.n] including function call trace stuff. Applying a patch from Bruce M. Simpson which implements the SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in the yamon PROM emulation. 20070506 Implementing M88K bb0[.n] and bb1[.n], and skeletons for ldcr and stcr (although no control regs are implemented yet). 20070509 Found and fixed the bug which caused Linux for QEMU_MIPS to stop working in 0.4.5.1: It was a faulty change to the MIPS 'sc' and 'scd' instructions I made while going through gcc -W warnings on 20070428. 20070510 Updating the Linux/QEMU_MIPS section in guestoses.html to use mips-test-0.2.tar.gz instead of 0.1. A big thank you to Miod Vallat for sending me M88K manuals. Implementing more M88K instructions (addu, subu, div[u], mulu, ext[u], clr, set, cmp). 20070511 Fixing bugs in the M88K "and" and "and.u" instructions (found by comparing against the manual). Implementing more M88K instructions (mask[.u], mak, bcnd (auto- generated)) and some more control register details. Cleanup: Removing the experimental AVR emulation mode and corresponding devices; AVR emulation wasn't really meaningful. Implementing autogeneration of most M88K loads/stores. The rectangle drawing demo (with -O0) for M88K runs :-) Beginning on M88K exception handling. More M88K instructions: tb0, tb1, rte, sub, jsr[.n]. Adding some skeleton MVME PROM ("BUG") emulation. 20070512 Fixing a bug in the M88K cmp instruction. Adding the M88K lda (scaled register) instruction. Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores. Removing the unused tick_hz stuff from the machine struct. Implementing the M88K xmem instruction. OpenBSD/mvme88k gets far enough to display the Copyright banner :-) Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1. Adding a dev_mvme187, for MVME187-specific devices/registers. OpenBSD/mvme88k prints more boot messages. :) 20070515 Continuing on MVME187 emulation (adding more devices, beginning on the CMMUs, etc). Adding the M88K and.c, xor.c, and or.c instructions, and making sure that mul, div, etc cause exceptions if executed when SFD1 is disabled. 20070517 Continuing on M88K and MVME187 emulation in general; moving the CMMU registers to the CPU struct, separating dev_pcc2 from dev_mvme187, and beginning on memory_m88k.c (BATC and PATC). Fixing a bug in 64-bit (32-bit pairs) M88K fast stores. Implementing the clock part of dev_mk48txx. Implementing the M88K fstcr and xcr instructions. Implementing m88k_cpu_tlbdump(). Beginning on the implementation of a separate address space for M88K .usr loads/stores. 20070520 Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK Dnard, and Zaurus machine modes. Experimenting with dyntrans to_be_translated read-ahead. It seems to give a very small performance increase for MIPS emulation, but a large performance degradation for SuperH. Hm. 20070522 Disabling correct SuperH ITLB emulation; it does not seem to be necessary in order to let SH4 guest OSes run, and it slows down userspace code. Implementing "samepage" branches for SuperH emulation, and some other minor speed hacks. 20070525 Continuing on M88K memory-related stuff: exceptions, memory transaction register contents, etc. Implementing the M88K subu.ci instruction. Removing the non-working (skeleton) Iyonix machine mode. OpenBSD/mvme88k reaches userland :-), starts executing /sbin/init's instructions, and issues a few syscalls, before crashing. 20070526 Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects the correct time-of-day. Implementing a generic IRQ controller for the test machines (dev_irqc), similar to a proposed patch from Petr Stepan. Experimenting some more with translation read-ahead. Adding an "expect" script for automated OpenBSD/landisk install regression/performance tests. 20070527 Adding a dummy mmEye (SH3) machine mode skeleton. FINALLY found the strange M88K bug I have been hunting: I had not emulated the SNIP value for exceptions occurring in branch delay slots correctly. Implementing correct exceptions for 64-bit M88K loads/stores. Address to symbol lookups are now disabled when M88K is running in usermode (because usermode addresses don't have anything to do with supervisor addresses). 20070531 Removing the mmEye machine mode skeleton. 20070604 Some minor code cleanup. 20070605 Moving src/useremul.c into a subdir (src/useremul/), and cleaning up some more legacy constructs. Adding -Wstrict-aliasing and -fstrict-aliasing detection to the configure script. 20070606 Adding a check for broken GCC on Solaris to the configure script. (GCC 3.4.3 on Solaris cannot handle static variables which are initialized to 0 or NULL. :-/) Removing the old (non-working) ARC emulation modes: NEC RD94, R94, R96, and R98, and the last traces of Olivetti M700 and Deskstation Tyne. Removing the non-working skeleton WDSC device (dev_wdsc). 20070607 Thinking about how to use the host's cc + ld at runtime to generate native code. (See experiments/native_cc_ld_test.i for an example.) 20070608 Adding a program counter sampling timer, which could be useful for native code generation experiments. The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR should always be set, to allow a 5000/200 PROM to boot. 20070609 Moving out breakpoint details from the machine struct into a helper struct, and removing the limit on max nr of breakpoints. 20070610 Moving out tick functions into a helper struct as well (which also gets rid of the max limit). 20070612 FINALLY figured out why Debian/DECstation stopped working when translation read-ahead was enabled: in src/memory_rw.c, the call to invalidate_code_translation was made also if the memory access was an instruction load (if the page was mapped as writable); it shouldn't be called in that case. 20070613 Implementing some more MIPS32/64 revision 2 instructions: di, ei, ext, dext, dextm, dextu, and ins. 20070614 Implementing an instruction combination for the NetBSD/arm idle loop (making the host not use any cpu if NetBSD/arm inside the emulator is not using any cpu). Increasing the nr of ARM VPH entries from 128 to 384. 20070615 Removing the ENABLE_arch stuff from the configure script, so that all included architectures are included in both release and development builds. Moving memory related helper functions from misc.c to memory.c. Adding preliminary instructions for netbooting NetBSD/pmppc to guestoses.html; it doesn't work yet, there are weird timeouts. Beginning a total rewrite of the userland emulation modes (removing all emulation modes, beginning from scratch with NetBSD/MIPS and FreeBSD/Alpha only). 20070616 After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was only cleared for the last segment when transmitting, not all segments), NetBSD/pmppc boots with root-on-nfs without the timeouts. Updating guestoses.html. Removing the skeleton PSP (Playstation Portable) mode. Moving X11-related stuff in the machine struct into a helper struct. Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION macro (which prints a meaningful error message). Adding a COMMENT to each machine and device (for automagic .index comment generation). Doing regression testing for the next release. ============== RELEASE 0.4.6 ============== 20070616 Implementing the MIPS32/64 revision 2 "ror" instruction. 20070617 Adding a struct for each physpage which keeps track of which ranges within that page (base offset, length) that are continuously translatable. When running with native code generation enabled (-b), a range is added after each read- ahead loop. Experimenting with using the physical program counter sample data (implemented 20070608) together with the "translatable range" information, to figure out which physical address ranges would be worth translating to native code (if the number of samples falling within a range is above a certain threshold). 20070618 Adding automagic building of .index comment files for src/file/, src/promemul/, src src/useremul/ as well. Adding a "has been translated" bit to the ranges, so that only not-yet-translated ranges will be sampled. 20070619 Moving src/cpu.c and src/memory_rw.c into src/cpus/, src/device.c into src/devices/, and src/machine.c into src/machines/. Creating a skeleton cc/ld native backend module; beginning on the function which will detect cc command line, etc. 20070620 Continuing on the native code generation infrastructure. 20070621 Moving src/x11.c and src/console.c into a new src/console/ subdir (for everything that is console or framebuffer related). Moving src/symbol*.c into a new src/symbol/, which should contain anything that is symbol handling related. 20070624 Making the program counter sampling threshold a "settings variable" (sampling_threshold), i.e. it can now be changed during runtime. Switching the RELEASE notes format from plain text to HTML. If the TMPDIR environment variable is set, it is used instead of "/tmp" for temporary files. Continuing on the cc/ld backend: simple .c code is generated, the compiler and linker are called, etc. Adding detection of host architecture to the configure script (again), and adding icache invalidation support (only implemented for Alpha hosts so far). 20070625 Simplifying the program counter sampling mechanism. 20070626 Removing the cc/ld native code generation stuff, program counter sampling, etc; it would not have worked well in the general case. 20070627 Removing everything related to native code generation. 20070629 Removing the (practically unusable) support for multiple emulations. (The single emulation allowed now still supports multiple simultaneous machines, as before.) Beginning on PCCTWO and M88K interrupts. 20070723 Adding a dummy skeleton for emulation of M32R processors. 20070901 Fixing a warning found by "gcc version 4.3.0 20070817 (experimental)" on amd64. 20070905 Removing some more traces of the old "multiple emulations" code. Also looking in /usr/local/include and /usr/local/lib for X11 libs, when running configure. 20070909 Minor updates to the guest OS install instructions, in preparation for the NetBSD 4.0 release. 20070918 More testing of NetBSD 4.0 RC1. 20070920 Adding a section about HelenOS (for testarm and testmips) to the guestoses.html page. 20071014 src/console/console.c now includes (thanks to Juli Mallett for noticing that this was required on Cygwin). 20071017 Updating Sprite URL in guestoses.html. 20071102 Updating the OpenBSD/landisk install instructions in guestoses.html from OpenBSD 4.1 to 4.2. 20071112 Branching in CVS to a 0.4.6.1 version, separate from the main development. ------------------------------------------------------------------------------- (This is the C++ development branch.) EXPERIMENTALLY beginning to convert various source code files to C++ (.c to .cc); it will of course be a major undertaking to redesign the code so that it fits C++, but I think it will be worth it. (main.c => main.cc only so far.) Note: Release 0.4.6.1 will most likely be made from the code base as it was yesterday, plus perhaps some documentation updates. Adding configure options "--with-gui" and "--without-gui"; autodetection of gtkmm-2.4 >= 2.12.1. A binary "gxemul-gui" is hardlinked to "gxemul"; when started, it should (in the future) bring up a GUI version of GXemul. For now, it just displays a dummy GTK+ window. 20071113 The dummy GUI now includes a menu bar. 20071114 Minor manpage and Makefile updates. Building and running GXemul now requires both X11 and gtkmm. debug/fatal are moved from main.cc to misc.cc. main.cc now just calls the main emulator, which is moved to src/GXemul.cc. 20071116 Reverting the stuff I did two days ago: gtkmm/X11 are now optional again. Finally adding "install" and "uninstall" Makefile targets. :) Moving the rest of main.cc (the main function) into GXemul.cc. Removing the old config file parser (src/emul_parse.c), and doc/configfiles.html. Moving remaining src/*.c{,c} into a new src/main/ directory. Beginning on separating the main GUI window into a "workspace" and a "debug console" area. 20071117 Removing the dummy M32R skeleton again. Converting some .c files to .cc (without redesigning the code, just to make it use the C++ compiler): cpu_sparc.c, cpu_mips_coproc.c, memory_*.c. Converting most of src/cpus/. Converting src/net/*.c and src/promemul/*.c to *.cc. 20071119 Converting src/file/*.c to *.cc. 20071120 Removing remaining references to the old config file stuff in the documentaion. 20071121 Converting src/useremul/*.c, src/symbol/*.c, and some remaining files in src/main/ to *.cc. (Still no redesign, simply converting to use the C++ compiler.) 20071123 Beginning to converting src/machines/*.c to *.cc. 20071124 Planning a new configuration file format; beginning on ConfigNode.{cc,h}. Adding doc/fileformat.html. Adding a "test" makefile target, for unit testing. "make install" runs the test target. Implementing a simple refcount_ptr class. 20071127 configure now uses -g also for non-development builds. Incorporating Wu Yongwei's debug_new, for memory leak detection. 20071209 Converting the remaining src/machine/*.c to *.cc. Converting src/debugger/*.c to *.cc. 20071212 Including a Doxyfile, for doxygen generation (source code comments to HTML). 20071213 Performing a VERY bold move: Removing pretty much everything of the old code. All CPUs, devices, documentation, PROM emulation modes, disk and file handling, console handling, the old debugger, etc. Thinking about the new Component framework. 20071214 Updating the TODO (basically removing all 0.4.x stuff). Beginning on some Doxygen documentation for simple classes. 20071217 Moving Doxygen documentation to doc/doxygen/html.... src/main/GXemul.cc is used for the "main page" of the generated Doxygen HTML documentation, so that is where all the general code concepts should be documented. Adding skeleton Action, ActionStack, and UnitTest frameworks. 20071218 Continuing on the ActionStack and the UnitTest framework. Adding a small intro.html documentation page. ------------------------------------------------------------------------------- (This is the 0.4.x branch.) 20071219 NetBSD 4.0 has been released. Doing regression testing of some systems listed on guestoses.html. Fixing an alignment bug in dev_vga, when allocating 1 byte. ============== RELEASE 0.4.6.1 ============== ------------------------------------------------------------------------------- (This is the C++ development branch.) 20071221 Some extremely minor Doxygen comment updates. 20071227 Adding StateVariable and StateVariableValue classes; writing unit tests, etc. The ActionStack now uses lists instead of vectors, for the undo and redo stack. (For O(1) undo/redo operations.) Continuing on the Component infrastructure: parent/child relationships, state variables, and serialization. Adding a simple Checksum class; useful as a helper for unit tests. 20071228 Implementing a CreateComponent function, which when given a "component class name" creates a Component. Adding a simple EscapedString helper class, for generating and decoding C-style escaped strings. Simple deserialization works. :) 20071229 Beginning on the CommandInterpreter class. 20071231 Moving src/gui to src/ui/gtkmm, and creating src/ui/console. The idea is that all UIs, not only graphical ones, will share a common base class (the UI class), making it reasonably easy to add other GUIs later on if necessary. Moving printing of the startup "banner" to a UI member function. (No banner is currently displayed for the GTKMM UI though, because it would feel too heavy-weight.) The ConsoleUI shows a "GXemul> " prompt, but does not support input yet. 20080101 Continuing on the ConsoleUI; it now reads input from stdin and sends it to a CommandInterpreter. Simple handling of CTRL-C, CTRL-Z, and treating DEL as backspace. Adding a Command base class, and adding the first command, which is "quit" :-). Simplifying the syntax of the UNITTEST macro. 20080102 Adding a section about GXemul being Free Software to intro.html (same as in previous versions of GXemul). Implementing CommandInterpreter::RunCommand, so that commands can be executed. "help", "quit", and "version" work interactively now :) 20080103 CTRL-A/E (for start/end of line) and CTRL-B/F (for back/ forward cursor movement) now work in the console UI. Mapping ANSI/VTxxx/xterm cursor keys (escape + [ + misc) to CTRL-A/E/B/F/N/P. Adding command history support to the CommandInterpreter. Classes that perform unit tests using the UNITTESTS(classname) macro are now tested (almost) automagically by UnitTest::RunTests(). (.h files must still be included.) 20080104 Connecting cursor up/down keys to the command history. Adding Component::Clone. (Not really used yet.) Adding CTRL-D support to the command interpreter (remove character to the right). Actions will now be placed in src/main/actions/. Implementing an AddComponentAction. 20080105 Beginning on TAB completion in the CommandInterpreter. Implementing the UndoCommand and the RedoCommand. Adding CTRL-K (kill end of line) to the command interpreter. Implementing RemoveComponentAction. 20080106 Classes that use UNITTESTS(classname) are now fully auto tested, no need to manually include .h files anymore. (This relies on the fact that .h files have names that are exactly the same as the class name they represent, otherwise it would not work that well.) Updating some Doxygen comments to reflect the current state of automagic unit testing. Renaming TODO to doc/TODO.html. Changing the Doxyfile to include full .cc source code in the built documentation. 20080107 The "tree" command now shows a fancy ASCII tree of components. Beginning on the "add" command (AddComponentCommand). Components now get names based on their class name, followed by a zero-based increasing integer, e.g. dummy0, dummy1, etc. when added (if they don't already have a unique name). 20080108 TAB complete of empty string now shows all available commands. Implementing Component helpers: GeneratePath and LookupPath. The "add" command now takes path into account, but it must be a complete path from the root component (i.e. "root.blahblah"). Component::Serialize now serializes into a std::stringstream instead of returning a plain string. 20080109 Implementing Component::FindPathByPartialMatch (helper func.). The "add" command now uses FindPathByPartialMatch for the where-to-add argument. Tab completion now expands component names :) also using FindPathByPartialMatch. (Syntax of different parts of a command line are not taken into account yet, though, so it also for example tries to expand the argument of the "help" command as a component name.) Component::Serialize now serializes into an ostream instead of a stringstream. Implementing the "save" command. CTRL-T now runs a "status" command (not yet implemented), instead of using a status line hack of its own. Implementing ClearEmulationAction and LoadEmulationAction. Implementing the "close" and "load" commands. 20080110 Making the LoadEmulationAction undo-able (in the case the new component was added to the tree, and did not entierly replace the root component). 20080112 The gxemul binary can now be started with a config file as an argument, which causes it to be loaded. The default RunState is now Running on startup, and -V is used to set it to Paused. Adding a NullUI, so that the result of GXemul::GetUI() does not have to be checked all the time. Creating a ComponentFactory; moving Component::CreateComponent to ComponentFactory::CreateComponent. Reworking how components are created, in preparation for getting "templates" (such as the testmips machine) to work. A list of Components is now generated by the configure script, so that all .h files with a COMPONENT(name) command in src/include/components/ (including template machines, etc) will be creatable using ComponentFactory::CreateComponent. The -E command line option now works :-) 20080113 Adding a "quiet mode" to the GXemul class, set to true by the -q command line option. Adding some more simple commands: continue, list-components. ------------------------------------------------------------------------------- (This is the 0.4.x branch.) 20080118 Applying a WDC patch from Oleksandr Tymoshenko (dev_wdc.c and bus_pci.c), fixing the order of 16-bit words within 32-bit words in the identify struct, and not clearing the error on reads from the error register anymore. ============== RELEASE 0.4.6.2 ============== ------------------------------------------------------------------------------- (This is the C++ branch.) 20080119 Adding a generic GetAttribute function to components. Planned attributes are "template", "stable", "machine", "description", and "contributors". Unimplemented attributes result in an empty string being returned from GetAttribute. Moving the ASCII tree generator from TreeCommand.cc to Component::GenerateTreeDump. Documentation of available machine templates and all components is now automagically generated on a "make documentation". (doc/machines.html and doc/components.html.) ------------------------------------------------------------------------------- (This is the 0.4.x branch.) 20080120 Some minor OpenFirmware fixes: Adding a "memory" property to "/chosen", adding a dummy claim() service. ------------------------------------------------------------------------------- (This is the C++ branch.) 20080120 Adding CTRL-W handling (remove current/last word) to the CommandInterpreter. The machines.html and components.html documentation pages now point to individual doc/machine_XXX.html and component_XXX.html pages, if they exist. 20080122 Beginning to rewrite the component state variable implementation a bit, in preparation for serialization/ deserialization, undo/redo, and "run backwards" with data tightly tied to components. 20080123 Continuing on the state variable stuff. Both strings and integers (8-bit through 64-bit, signed and unsigned) can be used as state variables so far, but more unit tests are needed. Component classes can now also be registered runtime. (This is needed to enable meaningful unit testing of some things, such as cloning of dummy unit test components.) 20080124 Moving doc/machine_*.html and component_*.html into subdirs. 20080129 Re-adding detection of host arch (ABI) to the configure script. 20080203 Continuing on state variables (unit tests etc). ------------------------------------------------------------------------------- (This is the 0.4.x branch.) 20080205 Switching order of DINCLUDE and XINCLUDE in src/devices/Makefile (thanks to Ning Zhao for the tip). ------------------------------------------------------------------------------- (This is the C++ branch.) 20080210 Adding -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC to CFLAGS for debug builds. 20080222 Beginning on the main run loop, GXemul::ExecuteCycles. ------------------------------------------------------------------------------- (This is the 0.4.x branch.) 20080222 Adding a DEV_DISK_OFFSET_HIGH32 register, for reading/writing the top 32 bits of the offset register (useful for emulated 32-bit archs), as suggested by Julian Elischer. ============== RELEASE 0.4.6.3 ============== ------------------------------------------------------------------------------- (This is the C++ branch.) 20080226 Implementing an IRInstruction base class, and some initial IR instructions (simple adds, moves, stores). 20080227 Continuing on IRInstruction stuff; unit tests to see that automatic native code generation kicks in, etc. Implementing a simple IRBlockCache, which is just a linear memory range with PROT_EXEC, which is reset when it overflows. Beginning on a (so far dummy) IRNativeAMD64 code generator. Adding a configure option for disabling native code generation support completely. 20080229 Rethinking how the IR stuff should work: I'll probably use simple and traditional interpretation by default (read instr, decode, execute), and only let native code generation via some form of IR kick in when necessary. Two advantages: it will be easier to add new cpu types (because an interpretation switch/ case block is very easy to understand), and there will be no waste of memory (for IR data) for code which is not commonly used. Removing IRBlock and IRInstruction, but keeping IRBlockCache and IRNativeAMD64 for later. The IRBlockCache can now be resized during runtime (and it expands automatically if necessary). 20080314 Working on the main loop, GXemul::ExecuteCycles(), which should call each component's Run function in suitable proportions. Adding a CPUComponent base class, from which MIPS_CPUComponent inherits. 20080316 Switching from CVS to SVN. Adding a test to the configure script for the "-ansi" compiler option; implementing a simple parse_number to replace strtoull to make everything build with -ansi. Various minor fixes to make -ansi work on a Debian GNU/Linux system (using CXXFLAGS instead of CFLAGS in Makefiles, and probe MAP_ANON in the configure script using $CXX, not $CC). Moving NativeTranslationExists and LookupCurrentCodePage from MIPS_CPUComponent to CPUComponent; these are intended to be used from most CPU components. Removing lots of "cd .." stuff from the Makefiles; GNU make did not work too well with them. Hopefully this will make tracking down compile problems on GNU/Linux machines easier. 20080317 Beginning on an AddressDataBus abstract class/interface, which e.g. the RAM component will implement. 20080320 Continuing on the RAMComponent class. 20080321 "make install" now installs .desktop and icon files. More work on the RAMComponent class: endianness for loads and stores larger than 8 bits, some simple unit tests. 20080322 Adding a preliminary toolbar to the GTKMM GUI. Upgrading configure script check for gtkmm-2.4 from version 2.12.1 to 2.12.5. (Maybe not stricly necessary, but that's what I am currently using for development.) 20080323 Experimenting with graying out the Undo and Redo actions in the GUI (by querying the ActionStack). 20080324 Making the code compile cleanly with GNU C++' -pedantic. The only module where -pedantic is not used is src/ir/, which needs to cast e.g. uint8_t* to function pointer (for runtime generated code). Beginning on a mainbus (MainbusComponent), which will forward reads and writes to other devices (such as RAM). 20080325 Making the counter in the ReferenceCountable class mutable, because const objects also need to be reference countable. Attempting to fix a bug related to the integer types passed to UnitTest::Assert. (Problem noticed by Hollis Blanchard.) Fixing arguments to and return handling of mmap(). (Also noticed by Hollis.) 20080328 Making everything build using SunStudio (Sun C++ 5.9). Implementing support for Double state variables. CPU speed is now a state variable, in CPUComponent. Cleaning up the CFLAGS/CXXFLAGS/COPTIM/CWARNINGS mess in the configure script and Makefile.skel files; only CXXFLAGS (and CXXFLAGSBASE) are used from now on. Also removing some other unused legacy stuff from the configure script. 20080329 Minor fixes to make the source code build with a 20080321 snapshot of GCC 4.4. 20080330 Continuing on the GTKMM GUI (File->Open/Save/Save As show file chooser dialogs, and Edit->Undo/Redo execute the "undo" and "redo" commands). "File->New from Blank" and "Go/Continue" also have bare-bones implementations. Continuing on mainbus related things; moving the mips_cpu in the testmips machine so that it is placed on the mainbus. Adding a MemoryMappedComponent base class, which all memory- mapped components should inherit. (The canonical example is the RAMComponent class.) The mainbus can now forward reads and writes to memory-mapped child components. 20080401 Continuing on the mainbus (writing unit tests). Reintroduce the 'bool' state variable type. Adding a 'writeProtected' state bool for the RAMComponent, to emulate ROM behavior in a simple way. 20080402 Creating a src/include/thirdparty directory. Moving debug_new.h etc there. Also importing exec_elf.h from NetBSD [HEAD], and updating doc/RELEASE.html to reflect the location of thirdparty imports. Implementing the initial framework for I18N/localization. The first translation is Swedish. :-) 20080404 Making it possible to build with GTKMM 2.15.5 with --debug; note, however, that this produces memory leak warnings, so the GTKMM with --debug combination is not very useful yet. Implementing basic support for updating the UI when some things change: Undo/Redo-applicability, the name of the emulation, and the RunState. (As UI::UpdateUI().) Removing all old CVS $Id$ tags; they are not useful anymore. The GTKMM GUI EmulationDesignArea now shows some dummy circles (one for each component in the emulation setup). 20080405 Beginning on a FileLoader class, for loading binaries (e.g. ELFs). Also adding a test/ directory, where small test files used for unit tests may be stored. ELF program segments are loaded, but no additional information yet (entry point etc.). Catching std::exception at the outermost level, in order to print a reasonable message if the application crashes. Instead of loading binaries into an AddressDataBus, they are now loaded into a Component, which, if it has a "pc" state variable, is set to the entry point. Starting gxemul with -E testmips test/FileLoader_ELF_MIPS actually attempts to start running the binary now :-) Some more work on the GTKMM GUI: the debug output window now shows debug messages and commands being executed. 20080406 Adding a section about Model-View-Controller to the source code documentation main page, and a simple picture of what the component tree may look like. Introducing "visible class names" in addition to the normal class name, for components. This makes mips_cpu0 show up as just cpu0, which is much nicer. uint16_t, 32_t, and 64_t state variables are now outputted in hexadecimal form in ToString(), for readability. The ListComponents command now shows the short description of each command. Links are now generated from component names in machines.html to corresponding component_xxx.html pages. Beginning on internal support for instruction disassembly (not user-accessible yet). 20080407 Continuing on the instruction disassembly stuff; importing some MIPS defines from GXemul 0.4.6.3. 20080409 Implementing support in the CommandInterpreter for running methods on components. If a component name is "executed" with no method name given, the component tree is dumped. (This means that there is no need for the 'tree' command anymore, so it has been removed.) Implementing the first component method: "unassemble" for the CPUComponent. GTKMM GUI test: Connecting to the "activate" signal of a text entry, so that commands are executed once ENTER is pressed; this does not work with tab-completion and command line editing though, since only ENTER is signaled. 20080410 CPUComponent's unassemble method now remembers where it last unassembled, and starts at m_pc if it is the first time it is executed. Porting more MIPS-related code from GXemul 0.4.6.3; some more instructions can be disassembled now. 20080412 Implementing tab-completion of methods on components. Executing a component name without any method name, which results in the component tree being dumped, will now also dump all of the component's state variables. Continuing on porting GXemul 0.4.6.3's MIPS disassembly code. The GTKMM GUI can now be shut down by the "quit" command. 20080413 Introducing a new RunState (NotRunning). Making the GTKMM GUI Run/Pause buttons stay down while in the Running/Paused runstates. (Also making the icons smaller by not showing text labels, and enabling tooltips instead. Looks/feels nicer.) Implementing an undoable ResetAction. 20080416 GUI updates: Fixed-width font in the debug console, and it now scrolls to bottom on text output. 20080419 AddComponentAction must not remember component references (for undo/redo); instead it now remember paths. Also implementing a similar fix for RemoveComponentAction. 20080423 Action::Execute and Undo are now private, and only reachable from the ActionStack (now a friend class of Action). 20080424 Upgrading configure script check for gtkmm-2.4 from version 2.12.5 to 2.12.7, to be in synch with my system. 20080426 The continue command now clears the Undo stack. State variable names of components can now be tab completed. "Running" a variable (e.g. cpu0.pc) will print its value. 20080427 Continuing a little on tab completion of variable names. Implementing a "dirty flag" for the emulation; the GTKMM GUI now asks for confirmation before quitting, opening a new emulation, etc, if the model is dirty. 20080501 Fixing LoadComponentAction so that it uses path names for Undo, and not reference pointers to components. Fixing a crash bug in CommandInterpreter when tab completing non-existant component names. Implementing a VariableAssignmentAction. No expressions yet, only simple values (numeric, strings, and boolean values). 20080531 Refactoring the Component::AddVariable* functions into a single template function. ------------------------------------------------------------------------------- (This is the 0.4.x branch.) 20080605 Fixing a corner case in ARM pc-relative loads, which was unimplemented before. (Triggered by doing builds of pkgsrc stuff inside emulated NetBSD/cats.) 20080610 Applying a patch from Jiri Svoboda, which implements the ARM "bkpt" instruction. ============== RELEASE 0.4.6.4 ============== 20080611 Correcting the ARM pc-relative load fix; the wrong address variable was used. Also, the pc-relative _load_ code was used for stores as well, which was completely incorrect. On ARM, since pc-relative loads are converted into immediate movs, on writes to pages that contain such translations, the ENTIRE page must be invalidated, not just the 1/32th that was code. This has now been implemented. ============== RELEASE 0.4.6.5 ============== 20080808 Applying a patch from Kiyotaka Inaba which causes an ARM UND exception to be generated by the instruction word 0xe6000011, which is needed by gdb when running inside the emulator. Also enabling ARM UND exceptions for ARM floating point instructions (needed by both Linux and NetBSD/arm). ------------------------------------------------------------------------------- (This is the C++ branch.) 20080810 Implementing a basic Trigger framework. 20080812 Continuing on Triggers; it's now possible to use static member functions as callback functions. Beginning to connect triggers to the GTKMM GUI. ------------------------------------------------------------------------------- (This is the 0.4.x branch.) 20081103 Fix for a free() bug in bootblock_iso9660.c. Updating the OpenBSD/landisk installation instructions from 4.2 to 4.4, after verifying that it works. 20081104 NOTE: I'm throwing away the C++ rewrite attempt ("0.5.x"), moving back gxemul-legacy to gxemul/trunk. The old C++ rewrite attempt is archived under gxemul/branches/. 20081109 Updating most NetBSD 4.0 install instructions to 4.0.1. ============== RELEASE 0.4.6.6 ============== 20081114 Adding the M88K 'add' instruction for immediate values (add_imm in cpu_m88k_instr.c). Continuing on dev_pcc2 (used by mvme187). Working on M88K interrupts. Very unstable so far; OpenBSD/ mvme88k bugs out randomly after the first few interrupts. 20081115 More work on dev_pcc2. Found the "random" failure bug: the M88K interrupt handling code didn't execute the interrupted instruction, but skipped it instead. Fixing a bug in the implementation of the m88k 'ext' instruction (it worked like extu!). Adding disassembly of all 88100 floating point instructions. Minor updates to make the code build with GCC "4.4.0 20081017". 20081116 Implementing the m88k flt.ss, flt.ds, trnc.ss, trnc.sd, and fadd.dds floating point instructions. 20081121 Updating the HelenOS version in the documentation to 0.3.0. Continuing on 88100 interrupt/exception handling. 20081125 Bringing back the dummy machine_iyonix.c, which was removed in SVN rev. 4866. Fixing a bug in ARM pc-relative loads, when loading within the same page as the pc. 20081126 Continuing on the Iyonix mode: connecting initial i80321 interrupts, and importing NetBSD/iyonix' bootconfig.h. 20081127 Importing iopi2creg.h from NetBSD (ARM Xscale I2C registers). Implementing the SH4 fsrra instruction, 1/sqrt(x), and the fipr instruction (vector dot-product). 20081203 Using register names in dev_clmpcc, but no actual progress on getting OpenBSD/mvme88k to boot further. FINALLY found the M88K bug I've been hunting: conditional branches with delay slots did not set the delay target address correctly in the case the branch was _not_ taken. 20081204 Interrupt exceptions (in cpu_dyntrans.c) are no longer generated while single-stepping. (It was too annoying.) 20081206 Implementing rudimentary tx/rx interrupts for clmpcc; OpenBSD/mvme88k can input/output stuff in userland now :) Implementing the "max negative number" condition of the M88K bcnd instruction. Implementing the M88K triadic register 'rot' instruction. The FIP != NIP+4 situation in the M88K rte instruction is now supported (i.e. executing one instruction from the pipeline, and then continuing somewhere else). Continuing on Dreamcast PowerVR register names, etc. 20081208 Beginning on a osiop (NCR 53C710 SCSI) device skeleton. 20081210 The SH4 Store Queue memory area is 0x04000000 long, not 0x40. 20081211 OpenBSD/m88k's badaddr() should now be able to detect invalid addresses; memory_rw.c causes exceptions on reads that fail (but no actual address is supplied yet). 20081212 Moving the Dreamcast PowerVR2 DMA handling from dev_dreamcast_g2 to dev_pvr, where it belongs. 20081213 Continuing on SH4 and PowerVR2 DMA. Moving the unsupported guest OSes from guestoses.html to a new page, unsupported.html, for clarity. Continuing on the NCR 53C710 SCSI controller (dev_osiop.c). 20081217 Beginning on implementing the SCRIPTS instruction set for dev_osiop. 20081219 Continuing a little bit on the osiop SCRIPTS ISA. 20081221 Implementing an instruction combination for M88K idle loop detection (works with OpenBSD/mvme88k). Adding a dummy LUNA 88K machine mode (machine_luna88k.c). 20081229 Continuing on the osiop SCRIPTS ISA. 20081231 More progress on dev_osiop.c. 20090101 FINALLY the osiop works well enough to let OpenBSD detect SCSI devices! :-) After some more hacking, everything is finally stable enough to allow OpenBSD/mvme88k to be installed onto a disk image! 20090102 Optimizing the osiop SCSI device a bit; a default scripted install of OpenBSD/mvme88k has dropped from 30 minutes to 10. Fixing a bug which was caused by instructions like subu.co with a destination register of r0 being treated as nop. Various updates to make the source code build better on Linux (Ubuntu 8.10), and with GNU make. ============== RELEASE 0.4.7 ============== 20090103 Merging fixes from the main trunk. 20090122 Merging in fdiv.sss and fadd.dsd from the main trunk. 20090123 NetBSD/hpcmips can now be installed and run using serial console (i.e. without -X), in addition to using the framebuffer. ============== RELEASE 0.4.7.1 ============== 20090215 Updating the guest OS page for HelenOS 0.4.0. 20090513 Fixing the MIPS tne, teq, tge, tgeu, tlt, and tltu instructions to allow non-zero "code" values. Adding a new Linux/Malta "variant 2" entry to the unsupported guest OS page. 20090518 Changing the 8253 interrupt mechanism to assert interrupts regardless of "mode" bits, causing Linux/Malta to get further. Hacking on piix4 a bit to attempt to please Linux/Malta; interrupts are lost. 20090610 Making configuration files work again! (Thanks to Wu Kan for noticing this bug.) 20090611 Documentation updates (NetBSD 5 etc). 20090621 Adding a hack for the pcc2 PSCALEADJ register, making it possible to install and run OpenBSD/mvme88k 4.5. NetBSD/evbmips, /sgimips, and /cobalt 5.0 have been verified to work. ============== RELEASE 0.4.7.2 ============== 20090626 Attempting to switch from C to C++ (_WITHOUT_ starting over from scratch). Step 1: Rename all .c files to .cc. 2. Rename all occurances of 'template' and 'class' to other things. Step 3: Fix malloc/realloc cast errors. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NOTE: From here on, stuff was merged piece by piece from the experimental C++ branch to the trunk; only the trunk is used from this point. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 20090627 Continuing on the C to C++ switch. Updating the OpenBSD/mvme88k regression test expect script from 4.4 to 4.5. Everything now builds with "make -j X". 20090628 Moving src/*.cc into a new directory, src/main/. Finally adding the "make install" target (again). Moving TODO and RELEASE notes to doc/. Adding Doxygen documentation generation (again). 20090703 Moving more C++ code from the old branch into the main trunk. (UnitTest, Component*, StateVariable, debug_new, ...) Removing bogus/unfinished archs (Alpha, SPARC, M32R) and the skeleton "userland emulation". 20090704 Moving thirdparty includes into src/include/thirdparty/. 20090705 Beginning to import various Components from the experimental C++ branch (starting with the MVME187Machine). Removing more bogus/unfinished code: Bebox and Luna88k. Attempting to move in more code from the experimental C++ branch: the GXemul main class, command interpreter and related commands, file loader, UIs, etc. 20090710 Moving in more code. Added a note in guestoses.html that all current modes are legacy modes, using the old framework. Updating the OpenBSD/landisk regression test expect script from 4.1 to 4.5. Attempting to connect -V and -e so that the new framework is used for new template machines. Making everything build on Linux (missing includes etc.). Removing all $CC stuff from configure (only $CXX remains). Merging in the automated component and machine HTML documentation stuff from the C++ branch. Applying a patch from Izumi Tsutsui which makes NetBSD/hpcmips work well with the clock again. 20090711 Applying another patch from Izumi Tsutsui, for setting the ARCBIOS OSLOADPARTITION environment variable in a more correct way. (Also updating the guest OS page for NetBSD/arc 5.0.) Updating the NetBSD/pmax regression test expect scripts from 3.1 to 5.0 (for both R3000 and R4400). Moving regression test expect scripts to the test/ directory. Creating a regression test expect script for NetBSD/arc 5.0. 20090712 Adding a dummy "testm88k" machine for the new framework. Updating the install instructions for NetBSD/cobalt to use the RAMDISK installer (thanks to Izumi Tsutsui for noticing). 20090713 Beginning on an a.out FileLoader for the new framework. 20090714 Continuing on the a.out FileLoader. 20090716 a.out (big-endian only so far) can now be loaded into AddressDataBus objects. Modifying the "load" command so that it can load both component trees _and_ other binaries (ELFs etc) into components. Merging in a lot of TODO entries from the old C++ branch's TODO file. 20090717 Implementing the 'move' command for moving components. Removing the 'dirty flag' concept (it wasn't really used). Adding a .dump method to the RAMComponent, for dumping raw (physical) memory contents. Adding a similar .dump method to the CPUComponent, for dumping the virtual memory space. (Note that this can have side effects, when reading from devices...) Implementing the 'copy' command, for cloning components. 20090718 Updating the man page to reflect new command line options vs legacy options. Adding a .registers method to the CPUComponent for dumping CPU registers; implementing specifics for MIPS and M88K. Enabling simple variable assignment [again]. Implementing (in a ugly hack-ish way) serialization support for the RAM component, using a "custom" StateVariable type. Beginning to implement a "pre run check" mechanism. 20090720 Implementing PreRunCheck for CPU components (they need to have an address/data bus, either as a child or as a parent, to run). 20090721 Implementing PreRunCheck for MainBusComponent. At startup, a suitable part of the component tree is now shown. Adding a GenerateShortestPossiblePath method on Component. Adding a helper for outputting pre-0.6.0 style debug messages from components ("[ componentname: message ]"). Tab completion (in the CommandInterpreter) now uses shortest path, whenever possible, instead of full paths. 20090722 Implementing a new concept of "on reset commands"; beginning on extending the ELF loader for symbol loading support. 20090723 Moving 'step' and 'time' concepts from the GXemul class to a new component, the RootComponent. Minor configure script fixes (allow --without-unittests etc.). Removing the "NotRunning" run state. Adding dummy "step", "backward-step", and "continue-backwards" commands. Implementing support for re-executing commands without args ("step" and "backward-step" so far). 20090724 The CPUComponent's .unassemble and .dump methods, and the RAMComponent's .dump method, are now also re-executable. CPU endianness is now serialized (as a bool, not enum). Beginning to work on cycle execution! 20090725 The step command now takes an argument (default is 1). 20090726 Removing the "global time" concept. Adding a helper for debug message indentation. Adding an "accuracy" variable to the RootComponent, which must be set to either "cycle" or "sloppy". Implementing pre-run-checks for M88K and MIPS cpus, for checking the r0 and zr registers, respectively. 20090727 When single-stepping, all state change (except for Custom StateVariables such as RAM contents) is now displayed. Porting the 88100 disassembly code from the old implementation to the new. Moving old main files into src/old_main/ (for clarity). 20090728 Including screenshots in auto generated machines.html. Finally managed to implement cycle-accurate continuous execution of multiple components at different speeds. :-) RAMComponent now clears ram on reset. Implementing a symbol registry for the new framework (which is per CPU). 20090729 Slowly beginning to reimplement dyntrans in C++: Beginning on the CPUComponent::DyntransExecute core loop, and some basic structures. MIPS and M88K cpus call DyntransExecute. 20090731 Continuing on the new dyntrans core. The first instruction (a M88K subu) can be executed on a dummy IC page. [Re]implementing some simple MIPS and M88K instructions. Arguments can now be passed during component creation, e.g. nr CPUs, CPU model, or ram amount for a template machine. Adding a 'raw' file loader, and a dummy SGI IP32 template. 20090801 Two MIPS16 instructions can be disassembled; disassembly address is now not necessarily the same as m_pc (e.g. on MIPS16, the lowest bit is cleared). Beginning on implementing branches: the MIPS "b" instruction, with delay slot (both continuous execution, and single-stepping with pause in the middle of the branch, etc). Continuing on the dyntrans core loop (inlined instruction calls first, then run a few remaining calls). 20090802 Implementing a skeleton implementation for the backward-step command (but since variable write handlers aren't implemented yet, it doesn't really work). Updating the Introduction chapter in the documentation with a section about the New framework. Beginning on M88K bsr and jmp.n instruction implementations, function call trace support, etc. 20090803 Continuing on function call trace support. 20090804 Using anonymous unions and ptrdiff_t, to avoid overloading pointers and size_t members unsafely, and other size_t usage. (Thanks to Weinholt for commenting on this.) 20090807 Getting rid of the last 'delete' call (in MainbusComponent, there was a _pointer_ to a memory map, instead of just a memory map). The new GXemul framework is thus completely free of malloc/free and manual delete. (mmap/munmap are, for natural reasons, used though by the RAMComponent.) Separating out the dyntrans specific parts of CPUComponent into another base class, CPUDyntransComponent, so that it in theory is possible to implement non-dyntrans CPUs. Partial support for choosing MIPS ABI (affects disassembly and register dumps, mostly). 20090810 Beginning on variable write handlers: MIPS zr register is read-only, MIPS' model can now be changed correctly, and root.accuracy can only be assigned "cycle" or "sloppy". 20090814 Continuing on write handlers for variables (root.step), beginning on component tree snapshotting (using Clone). The backward-step command now works reasonably well (but the only snapshot taken so far is at step=0). 20090815 Reimplementing the M88K br, or_imm, or.u_imm, cmp, cmp_imm, and_imm, and.u_imm, mask_imm, mask.u_imm, mak, mak_imm, mulu_imm, xor_imm, and xor.u_imm instructions. 20090819 Base OTHERLIBS in configure on LDFLAGS. 20090821 Updating the TODO with thoughts/plans for the "plugin" part of the new framework. 20090822 Beginning on a doc/framework.html, describing the new framework concepts to end-users. 20090905 Continuing on the dyntrans core: page allocation. 20091207 The dev_ether MAC address can now be read. 20091212 Updating the OpenBSD/landisk install instructions in guestoses.html from OpenBSD 4.5 to 4.6. 20091219 Include _GLIBCXX_DEBUG and _GLIBCXX_DEBUG_PEDANTIC defines in debug builds, to potentially catch some STL misuses. If valgrind is found by the configure script, it is used when running 'make test'. If there is any output from valgrind -q (i.e. errors), then make test fails. 20100127 Patch from Tassilo Philipp to enable PPC's fabs instruction. Patch from Yana to use return value from net_ethernet_rx() correctly in dev_ether.c. 20100128 Adding a check (for "make test") to see that delete isn't used. Only a few exceptions are allowed. 20100129 Reimplementing the (non-specialized) M88K bsr instruction. Continuing on the dyntrans core: page allocation. The basics (page allocation and LRU deallocation) have been implemented, but not really tested in practice yet. 20100130 Reimplementing the M88K ldcr instruction, and a slow version of the st instruction (store 32-bit word). Updating guest OS documentation (NetBSD/landisk 4.0.1 to 5.0.1, NetBSD/pmax 5.0 to 5.0.1, NetBSD/arc 5.0 to 5.0.1, NetBSD/cobalt 5.0 to 5.0.1). Renaming old testmips to oldtestmips, so that the name testmips can be used by the new framework. 20100131 Reimplementing a slow version of the st.d M88K instruction. "Quiet mode" is now turned off, if dropping into the debugger, both by using -V and by triggering unimplemented instructions. The m88k_cpu now takes a creation argument called r31, for the initial stack pointer value. (Needed to run the rectangle drawing demo, which assumes a valid r31 on startup.) Reimplementing the M88K bsr.n instruction, including single- stepping scenarios. 20100202 Reimplementing generic M88K loads/stores using templates. (In the old implementation, these were constructed using build- time generated define/include magic to simulate a template- style mechanism in C). Reimplementing the M88K divu d,s1,imm instruction. Reimplementing the M88K lda.* instruction. 20100203 Beginning on reimplementing M88K bb0.n and bb1.n; only the non-singlestepping variant done so far. 20100204 bb0.n and bb1.n should now also work when single-stepping. Implementing the non-singlestep variant of M88K jmp.n. Beginning on the M88K bcnd.n instruction. 20100205 Continuing on bcnd.n. The testm88k rectangle drawing demo now runs :) both when running continuously, and when single-stepping. (No graphical output yet, of course.) 20100206 Reimplementing the M88K ext and extu instructions. Reimplementing the M88K bb0 and bb1 non-delayslot instructions, including samepage variants. Reimplementing the M88K stcr, jmp, and tb0 and tb1 instructions. Fixing a bug in the MRU list in DyntransTranslationCache. Fixing disassembly of tb0 and tb1, and implementing the rest of the bcnd conditions. Beginning on reimplementing MIPS (slow) loads/stores, and reimplementing the MIPS addu, subu, srl, xor, multu, mfhi, mflo, mthi, and mtlo instructions. 20100207 Reimplementing the MIPS slt and sltu instructions, various branch instructions, and fixing some bugs; the rectangle drawing demo for testmips runs in the new framework :) Switching function call trace on/off during runtime now clears [individual] translation pages. 20100213 Working on dyntrans abort peculiarities (in the middle of delay-slots, etc). 20100214 Preparing for a quick 0.6.0 release. ============== RELEASE 0.6.0 ============== 20100214 Fixing order of machine.html and components.html generation, relative to individual machines from skeleton files. 20100220 Improve install path guessing (DESTDIR and MANDIR) based on feedback from Tom Callaway. Moving the multiple identical instances of parse_number and SplitStringIntoVector to a new StringHelper class, and adding some unit tests. Adding a PluginDescriptor class, for parsing plugin descriptor strings (component:plugin(args):filename etc). Beginning on the new plugin mechanism: adding an 'attach' command, to be used instead of 'load'. 20100222 Scrapping the "plugin" concept; the already existing component framework should hopefully be enough as it is. 20100314 Updating doc/translation.html with more examples on how the dyntrans system works (in pre-0.6.x and in 0.6.x). 20100319 Fixing flawed mymkstemp by also passing O_CREAT | O_EXCL (used on systems without mkstemp) (reported as Debian bug #574537). 20100322 const fixes, enabling builds using GCC's -Wcast-qual. Fixes to allow build using GCC's -Wshadow. 20100326 Running 'make test' will now treat memory leaks as test failure (in debug builds only). Also fixing a memory leak. 20100406 Bogus hack to machine_evbmips.cc to let RTEMS print some boot messages (again?) for mvme5500. 20100806 nbjoerg on #GXemul (FreeNode) noticed an easy way to trigger an unhandled case in memory_sh.cc; applying a potential fix. 20100830 Updating the OpenBSD/landisk guest operating system install instructions from 4.6 to 4.7. Improved the "pretty print" of components in the tree dump, by moving it out to a per-component virtual function. 20100901 Beginning on CacheComponent (a generic memory cache component). 20100910 The mechanism for detecting when to assert MIPS compare interrupts could sometimes stop delivering interrupts, if the count register was read. Fixed by keeping track of how many times the register is read and reverting it before doing the count/compare interrupt assert check. (Thanks to Jakub Jermar for noticing this bug using HelenOS.) 20100912 Updating the NetBSD/hpcmips guest operating system install instructions from 4.0.1 to 5.0.2, and the NetBSD/algor install instructions from 3.1 to 5.0.2. 20110212 Updating the NetBSD/pmax install instructions: 5.0.2 -> 5.1. Updating OpenBSD/landisk instructions: 4.7 -> 4.8. 20110606 Updating the documentation on how to start Dreamcast binaries, and updating from NetBSD/dreamcast 5.0.1 to 5.1. 20110609 Adding automagic guessing of Dreamcast ISO filesystem offset, so that Linux/dreamcast can be booted without specifying the offset. Booting Dreamcast via bootblock now uses software PROM starting point instead of calling a particular bootblock address, making it possible to run a complete boot sequence in more cases. When unimplemented SuperH instructions cause an abort failure, GXemul now drops into the debugger instead of calling exit() (if started with -K). 20110610 In SH4 instruction trace, include address in printout in a few more cases than before. Make NetBSD/dreamcast etc. boot correctly with 480 pixels in the y direction (random read hack from PDTRA). Use the 8x16 font as a fake Dreamcast ROM font. Adding fake/skeleton Dreamcast ROM SYSINFO_INIT, SYSINFO_ID, FLASHROM_INIT, and FLASHROM_READ calls. 20110616 Adding Dreamcast devices as symbols, so that runtime debugging will show meaningful names instead of just addresses, when reading and writing device registers. 20110621 Adding "trace" versions of SuperH bsr and bsrf_rn instructions. Adding the first SuperH instruction combination for speeding up a variable read loop (bt_samepage_wait_for_variable). 20110622 Continuing on Dreamcast and SuperH emulation: the SH4 DMA channel numbers were off-by-one (but didn't really have any negative effect). Experimenting with end-of-DMA mechanism in dev_pvr. Adding a second device thing at 0x005f7c00, which seems to be a PVR DMA register range, but not much used? 20110623 Found a bug in the SH4 fsca instruction: the angle argument for sin and cos was incorrectly calculated. "dcfighting.bin" and "gltest.bin" (two "homebrew" Dreamcast programs) now look much more like on the real Dreamcast. Various other small Dreamcast and/or SH4 related updates. 20110624 Updating OpenBSD/landisk installation instructions: 4.8 -> 4.9. 20110626 Moving Dreamcast BIOS emulation entry points to 0x8c000100+ofs, so they are not "in the way" of the real BIOS' data area at 0x8c000000-0x8c0000ff. Some other minor Dreamcast fixes. Moving GDROM DMA register handling into dev_dreamcast_gdrom. Fixing a bug in the SH4 fipr instruction (inner product): the rm and rn registers were reversed! Implementing fmov_rm_frn for double-sized register access. 20110702 dev_ram now has a "trace" flag. Useful for figuring out e.g. when/if a program accesses certain memory ranges. Continuing on Dreamcast PVR (graphics) emulation; implementing software triangle rendering, so that some demo programs (such as Comstedt's "tatest", KOS' "gltest.bin" and "dcfighting.bin") now render solid polygons. Color is random though, and no textures yet. 20110706 Implementing register pair variant of SuperH fmov_frm_rn, adding implementations of "LDS Rm,MACH", and "LDS Rm,MACL". 20110902 Reviving the old legacy Alpha CPU support, which was removed 20090703 (i.e. NOT using the new framework). 20110906 Slowly continuing on the Alpha emulation mode: going through the existing virtual memory and PALcode stuff. 20120120 Avoid crash in cpu_ppc_instr_loadstore.cc for 64-bit emulation (since only 32-bit access is actually implemented); fallback to generic (slow) access. Minor OpenFirmware and SPR fixes to reach further with a FreeBSD/powerpc 9.0 kernel (-Xe g4). Updating the NetBSD/pmax install instructions: 5.1 -> 5.1.1. Updating the NetBSD/cobalt install instructions 5.0.1 to 5.1.1. Redirect PowerPC SPRs 0x10c/10d to 0x11c/11d (Time Base). 20120121 Updating OpenBSD/landisk installation instructions: 4.9 -> 5.0. 20120507 Adding a patch from Juli Mallett for MIPS rdhwr reg 29. 20120617 Adding a patch from James Peacock for ARM MSR fields. 20120724 Adding a patch from David Brownlee (mkstemp on NetBSD), and trying to make things build without warnings with GCC 4.6.x. 20120731 Adding a patch from David Brownlee: a more reasonable TOC is returned in dev_dreamcast_gdrom.cc (for NetBSD/dreamcast). 20120906 Adding a patch from George Koehler to fix DHCP response bug. 20120922 Fixing an ARM instruction encoding bug: for shifter_operand immediates, the carry bit should be set to bit 31 of the shifter_operand if and only if rotate_imm != 0. I've added detection for the case when this would bug out (although I have never seen it happen yet), and fixed a bug which did happen: for short register formats (i.e. no shift or other complex things), the code should not be run, but it was run anyway, leading to wrong Carry flag results for e.g. the TST instruction. This was triggered when running int64_t modulo. 20130907 Updating NetBSD/dreamcast test instructions: 5.1 -> 6.1.1. Updating NetBSD/pmax install instructions: 5.1.1 -> 6.1.1. 20131006 Adding a dummy Raspberry Pi machine mode. 20131109 Updating OpenBSD/landisk install instructions: 5.0 -> 5.4. 20140803 Some cleanup and minor progress of the Dreamcast PVR graphics. (The graphics displayed when attempting to run the original ROM now looks more reasonable.) Updating NetBSD/dreamcast test instructions: 6.1.1 -> 6.1.4. Updating NetBSD/pmax install instructions: 6.1.1 -> 6.1.4. Renaming machine mvme187 to mvme187old to avoid collision. Enabling ELF file support for 88K experiments. 20140805 Fixing color bug in dev_pvr.cc simpleline, which is used when rendering Gouraud shaded triangles. 20140810 Beginning on disassembly of ARM THUMB (16-bit) encoding. 20140815 Adding rudimentary culling of clockwise / counter-clockwise polygons in the PVR rendering code. 20140816 Fixing console.cc so that it doesn't complain about buffer overrun when pasting a lot of data. ============== RELEASE 0.6.0.1 ============== 20150312 Making old framework config files work again (@filename). 20180203 Reviving the (dummy) Luna 88K machine mode from r5458. 20180204 Continuing on LUNA 88K stuff; some initial fake PROM putchar functionality for experimenting with OpenBSD/luna88k. 20180205 Some initial OpenBSD/luna88k syscnputc() output works (hack). 20180206 Adding enough of a hack to let OpenBSD/luna88k distinguish between LUNA 88K and 88K2, by faking FUSE_ROM string. 20180207 Adding a semi-broken framebuffer for LUNA 88K. 20180208 Making the code build with reasonably modern GNU C++ (6.4) and clang (3.4.1), although there are lots of warnings. Updating NetBSD/pmax install instructions: 6.1.4 -> 7.1.1. 20180209 Making OpenBSD/luna88k print some more things, by faking more things in dev_luna88k.cc. 20180214 Minor fixes for LUNA 88K. 88K disasm shows "nop" instead of "or r0,r0,r0" now. OpenBSD/luna88k 5.2 (an older version) now reaches userland :-) issuing syscalls, but not 6.2 yet :-( and since no interrupts are implemented yet, it doesn't really do much. Removing notes about "legacy modes" in the documentation, since it was too ugly and those modes are pretty much the main focus of end-users of GXemul still. 20180219 Basic interrupt controller and timer interrupt for LUNA88K. 20180220 Minor progress on the LUNA88K framebuffer. 20180223 Serial controller interrupt progress for LUNA88K; some interaction can be done with OpenBSD/luna88k ramdisk user- land but it is shaky. 20180302 Fixing bug in dev_mp when returning amount of memory (it was truncated to 32 bits). Found during YCX5 development. 20180410 Adding a dummy skeleton for an Intel i960 CPU component using the new framework. 20180418 Adding dummy skeletons for a Cyclone/VH (i960VH) evaluation board, and the HP 700/RX X-terminal (i960CA). 20180419 Implementing basic disassembly of some i960 instructions (only the CTRL group so far), and basic register dump functionality. 20180420 i960 MEM and COBR instruction group disassembly has now been implemented. 20180422 Adding a simple b.out file loader for i960 binaries, but no support for symbols yet. Beginning to add some REG instruction disassembly (i960). 20180423 Implementing the rest of i960CA REG instruction disasm. 20180424 Beginning to implement i960 dyntrans instructions (a simple 'b' branch and a simple 'mov lit,reg' so far). 20180428 Implementing happy case of an "lda" i960 instruction which has an extra displacement word, i.e. non-standard dyntrans instruction length. 20180503 Implementing i960 lda with immediate 12-bit offset, and dummy (nop) sysctl cache invalidation (msg type 0x01). 20180613 Fixing an old TODO for invalidating translation caches when using non-4KB pages for MIPS. This makes HelenOS 0.7.1/malta boot further than before. 20180614 Removing an old TODO regarding MIPS count/compare interrupts; this causes HelenOS on Malta to run much faster (while NetBSD/evbmips (malta) and /cobalt are not worse off than before). Updating NetBSD/evmbips and /cobalt installation instructions to 7.1.2 (with a note about clock not being correct). More work on the other-than-4KB bug fix. 20180618 Doubling DEFAULT_DYNTRANS_CACHE_SIZE from 48 to 96 MB. Updating more NetBSD install instructions to 7.1.2. 20180619 When reading disk sectors from the 'disk' device (for e.g. testmips), automatically move to the next sector after reading (or writing). Allow testmips programs to detect whether the X11 framebuffer is in use or not (returns 0x0 as resolution if not). 20180706 Adding a dummy VoCore machine skeleton using the old framework (with the wrong CPU type 4KEc instead of 24K). 20180707 Implementing the rorv (aka rotrv?) MIPS instruction. 20180725 More clang fixes. 20180726 Minor progress on booting Linux/VoCore. MIPS rdhwr CC is implemented as reading the COP0_COUNT register. 20180819 Applying a patch from Andreas Gustafsson (gson) for the MIPS div and ddiv instructions, which checks for divide overflow manually before doing the divide. 20180820 Updating the Sprite/DECstation URLs. 20180821 DECstation 5000/125 "3MIN" mode has been broken for quite a while; attempting to rewrite/resurrect it. 20180822 Rewrote/refactored enough of the dec_ioasic code to make the 5000/125's original PROM output its first boot messages again (and NetBSD/pmax and OpenBSD/pmax too). 20180823 Continuing on making 5000/125 emulation work again: rewriting the interrupt code for the scc serial controller, and connecting TURBOchannel graphics cards. Fixing the LK201 keyboard self-test codes so that the 5000/125 PROM doesn't complain. ============== RELEASE 0.6.0.2 ============== 20180910 Running the SGI O2 PROM works a little bit again, with some hacks (updating the documentation). 20180917 OpenBSD/landisk 6.3 guest OS install instruction update. 20180918 Fixing a regression bug which was introduced September 2012 (svn r5805), regarding shifted immediate values, which caused OpenBSD/cats to fail during install. 20180920 Making ARM disassembly show THUMB instructions, if the lowest bit of the address is 1. (They can not be executed yet though.) Fixing broken "print" command. Oops. Implement some more THUMB disassembly. Fail rather than silently treating ARM instructions beginning with 0xf as nops. Allow the emulator to start in THUMB mode (lowest pc bit set). 20180921 Continuing on ARM THUMB disassembly. Beginning to implement very slow THUMB interpretation (not dyntrans). Horrible performance-wise, but better than nothing. 20180924 Oops, forgot to add machine_rpi.cc back in 20131006. 20180925 Cleaning up some more files on make clean_all. Thanks to Göran Weinholt for noticing. 20180927 Fixing big-endian ARM loads/stores (except perhaps double-word loads and stores); probably slows everything down a bit. 20181001 Continuing on the slow THUMB instruction interpretation. 20181008 Disk images added using -d for SGI modes are now SCSI, not IDE. Importing newer crimereg.h and crmfbreg.h from NetBSD. 20181009 Moving around SGI O2 graphics code, in preparation for making more use of the "new" NetBSD defines. 20181011 SGI O2 GBE now switches resolution if the OS wants it (i.e. Linux/O2), rather than requiring a recompile. Also, detection of Linux' "tweaked" (linear) mode, thus avoiding a recompile when experimenting with Linux/O2. NetBSD can now show some output on the O2 framebuffer too. 20181012 Fixing a bug in the generic X11 framebuffer output, so that scaledown is preserved even when a guest OS switches resultion at runtime. Continuing on the SGI O2 graphics; when the nr of tiles or "partial pixels" is in mismatch with the screen resolution, the skewed result now looks the same as on my real physical O2. 20181013 More SGI O2 graphics work: TLBs. OpenBSD can now show graphical console messages. 20181015 Some more emulated O2 registers now return the same values as my real O2 does. Refactoring the O2 "output" to always be 24-bit, separate from the emulated framebuffer tiles (which may be e.g. 8 bit). NetBSD's colors (RG3B2 mode) are now probably more correct. Changing from 64 to 128 MB ram for the O2; this matches what my real O2 has, and it is now detected correctly both by OSes and the PROM. Implementing the O2's GBE cursor; both bitmap and crosshair modes work exactly like on the real machine now. Finally fixed the bug which caused scroll-up to not work when running the O2's PROM. 20181016 More work on the O2 graphics; managed to get rid of the Linux tweaked special case rendering mode. Splitting the O2 GBE into a GBE part and a Rendering Engine part. 20181017 Refactored the register representation in dev_sgi_ip32's crime interrupt controller. Adding a horrible hack to enable the use of a RAM_MIRROR at 0x40000000 (for SGI O2 emulation). 20181018 Updating the OpenBSD/sgi installation instructions (still in unsupported.html though, and still only diskless). 20181019 Fixing some 8242 key encodings (used by the SGI O2 mode). Better memory bank stuff for SGI O2 (128 vs 256 MB RAM). Taking the FR bit of the MIPS status register into account to use 64-bit floating point registers rather than pairs of 32-bit registers (need for OpenBSD/sgi to work). Moving OpenBSD/sgi from unsupported.html to guestoes.html. 20181022 Fixing broken MACE interrupt mechanism for SGI O2. 20181025 Implementing MTE_MODE_COPY in the SGI O2 memory transfer engine to allow NetBSD to scroll up the framebuffer. Made the pckbc work with NetBSD/sgimips. Only allow SGI O2 MTE memory fills to pages that are in a TLB. 20181026 Some cleanup and refactoring of the O2 rendering engine and other things. ARCS environment fixes (better values for diskless booting). 20181030 Updating NetBSD/sgimips guest OS instructions to version 8.0. Some progress on the hw accelerated graphics operations used by NetBSD/sgimips' Xorg driver. 20181031 Better separation of pckbc scancode translation tables 1, 2, and 3, and beginning to play around with PS/2 mouse movement. 20181101 Fixes to the SGI O2 mec ethernet implementation's register alignment to correctly support mixed 32/64-bit access. 20181102 Adding some PHY/MII related parts of the O2 mec device (not needed by NetBSD/OpenBSD it seems, but by the O2 PROM). 20181106 Splitting SGI O2 rectangle drawing and line drawing into separate parts; NetBSD/sgimips' Xorg now looks reasonable. 20181107 Progress on PS/2 mouse emulation; NetBSD accepts it as "pms0 at macekbc0" in the SGI O2 emulation mode. (No actual host mouse input yet though.) 20181108 Implementing host X11 mouse input for the pckbc device. 20181112 More work on the O2 rendering engine Raster Ops. Moving windows within NetBSD's X11 now looks as it should. 20181115 Changing the PCI product ID for the AIC7880 SCSI controller in the SGI O2 emulation mode to match my real O2 (0x9004, 0x8078). 20181120 Continuing on SGI O2 graphics: "overlays" (seem to always be 8 bits deep?). 20181121 Getting rid of a hack in the O2 rendering code for "stipple patterns", by looking at the "stipple mode" register. 20181122 Fixing an old very annoying bug where floating point number 0x0 was interpreted as 2.22507e-308 rather than 0.0. Thanks to Maya Rashish (coypu@SDF.ORG) for reporting the bug. 20181203 Beginning on test/floatingpoint infrastructure. Fixing some more floating point bugs. ============== RELEASE 0.6.1 ============== gxemul-0.6.1/README000644 001750 001750 00000007062 13402411502 014112 0ustar00debugdebug000000 000000 -------------------------------------------------------- Gavare's eXperimental Emulator -- GXemul 0.6.1 -------------------------------------------------------- Copyright (C) 2003-2018 Anders Gavare Overview -- What is GXemul? ----------------------------- GXemul is a framework for full-system computer architecture emulation. Several processor architectures and machine types have been implemented. It is working well enough to allow unmodified "guest" operating systems to run inside the emulator, as if they were running on real hardware. The emulator emulates (networks of) real machines. The machines may consist of ARM, MIPS, Motorola 88K, PowerPC, and SuperH processors, and various surrounding hardware components such as framebuffers, busses, interrupt controllers, ethernet controllers, disk controllers, and serial port controllers. GXemul, including the dynamic translation system, is implemented in portable C++, which means that the emulator will (at least in theory) run on practically any modern host architecture and unix-like operating system, for which a C++ compiler is available. The documentation lists the machines and specific guest operating systems that can be regarded as "working" in GXemul. The guest operating system that works best in GXemul is NetBSD/pmax. Possible uses of GXemul include: o) running guest operating systems in a "sandboxed" environment o) compiling your source code inside a guest operating system which you otherwise would not have access to (e.g. various exotic ports of NetBSD or OpenBSD), to make sure that your source code is portable to those platforms o) educational purposes, e.g. to learn how to write code for MIPS o) hobby operating system development; the emulator can be used as a complement to testing your code on real hardware o) preservation of computer history, by simulating old/obsolete hardware o) simulating (ethernet) networks of computers running various operating systems, to study their interaction with each other o) debugging code in general Use your imagination :-) GXemul's limitations -------------------- o) GXemul does not simulate micro-architectural things such as pipe-line stalls, instruction latency effects, out-of-order execution etc. o) CPUs and other hardware devices have been implemented in an ad-hoc and as-needed manner, usually only enough to fool guest operating systems such as NetBSD into believing that the hardware devices exist and function well enough for the guest operating systems to use them. (A consequence of this is that a machine mode may be implemented well enough to run NetBSD for that machine mode, but other guest operating systems may not run at all, or behave strangely.) Quick start ----------- To compile, type './configure' and then 'make'. This should work on most Unix-like systems. If it does not, then please mail me a bug report. If you are impatient, and want to try out running a guest operating system inside GXemul, read this: doc/guestoses.html#netbsdpmaxinstall If you want to use GXemul for experimenting with code of your own, then I suggest you compile a Hello World program according to the tips listed here: doc/experiments.html#hello Please read the rest of the documentation in the doc/ sub-directory for more detailed information on how to use the emulator. Feedback -------- If you have found GXemul useful in some way, or feel like sending me comments or feedback in general, then mail me at gavare@gmail.com. gxemul-0.6.1/Makefile.skel000644 001750 001750 00000004617 13402411502 015632 0ustar00debugdebug000000 000000 # # Makefile for GXemul # BIN=gxemul LIBS=$(XLIB) $(OTHERLIBS) all: build build: do_src $(CXX) $(COPTIM) src/components/*/*.o src/console/*.o src/cpus/*.o src/debugger/*.o src/devices/*.o src/disk/*.o src/file/*.o src/machines/*.o src/main/*.o src/main/*/*.o src/net/*.o src/old_main/*.o src/promemul/*.o src/symbol/*.o src/ui/*/*.o $(LIBS) -o $(BIN) do_src: cd src; $(MAKE) test: build test/check_delete_calls.sh @rm -f tmp_valgrind.out $(VALGRIND) ./$(BIN) -WW@U @if [ -s tmp_valgrind.out ]; then cat tmp_valgrind.out; false; fi documentation: build doc/generate_machine_doc.sh sed s/PAGETITLE/Machines/g < doc/head.html > doc/machines.html ./$(BIN) -WW@M >> doc/machines.html cat doc/tail.html >> doc/machines.html sed s/PAGETITLE/Components/g < doc/head.html > doc/components.html ./$(BIN) -WW@C >> doc/components.html cat doc/tail.html >> doc/components.html $(DOXYGEN) doc/Doxyfile install: documentation test @echo Installing binaries, man page, and documentation... mkdir -p $(DESTDIR)$(PREFIX)/bin cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin/ mkdir -p $(DESTDIR)$(MANDIR)/man1 cp -f man/gxemul.1 $(DESTDIR)$(MANDIR)/man1/ mkdir -p $(DESTDIR)$(PREFIX)/share/doc/gxemul cp -R doc/* $(DESTDIR)$(PREFIX)/share/doc/gxemul/ uninstall: @echo Removing binaries, man pages, and documentation... rm -f $(DESTDIR)$(PREFIX)/bin/gxemul rm -f $(DESTDIR)$(MANDIR)/man1/gxemul.1 rm -rf $(DESTDIR)$(PREFIX)/share/doc/gxemul clean: rm -f $(BIN) *core core.* *.gmon _* *.exe ktrace.out tmp_*.out* callgrind.out* cachegrind.out* rm -f unittest*.h components*.h commands*.h rm -rf doc/doxygen cd src; $(MAKE) clean # experiments and demos are not cleaned on a normal clean, only on a clean_all. clean_all: clean cd experiments; $(MAKE) clean_all cd demos; $(MAKE) clean rm -f config.h Makefile src/Makefile src/cpus/Makefile rm -f src/ui/*/Makefile src/ui/Makefile src/main/fileloaders/Makefile rm -f src/main/commands/Makefile rm -f src/components/Makefile src/components/*/Makefile rm -f src/debugger/Makefile src/devices/Makefile rm -f src/devices/fonts/Makefile src/disk/Makefile rm -f src/file/Makefile src/machines/Makefile rm -f src/main/Makefile src/old_main/Makefile src/net/Makefile rm -f src/promemul/Makefile src/include/Makefile rm -f src/useremul/Makefile src/include/Makefile rm -f src/console/Makefile src/symbol/Makefile rm -f doc/machines.html doc/components.html doc/machines/machine_*.html gxemul-0.6.1/doc/000755 001750 001750 00000000000 13402411501 013771 5ustar00debugdebug000000 000000 gxemul-0.6.1/man/000755 001750 001750 00000000000 13402411502 014000 5ustar00debugdebug000000 000000 gxemul-0.6.1/test/000755 001750 001750 00000000000 13402411502 014204 5ustar00debugdebug000000 000000 gxemul-0.6.1/configure000755 001750 001750 00000106647 13402411502 015152 0ustar00debugdebug000000 000000 #!/bin/sh ############################################################################### # # Copyright (C) 2003-2018 Anders Gavare. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # # This is a minimal configure script, hardcoded for GXemul. This script # figures out which compiler flags will work, and creates Makefiles in # sub-directories. A config.h file is also created. # # # ---> FOR NORMAL USE, JUST RUN ./configure WITHOUT OPTIONS! # # # To compile the emulator with profiling (during development), use # CXXFLAGS="-pg", run the emulator, and then run 'gprof gxemul' and study # the results. # # Or better, using callgrind/cachegrind/kcachegrind: # valgrind --tool=callgrind --dump-instr=yes ./gxemul -e testm88k test/FileLoader_A.OUT_M88K # or # valgrind --tool=cachegrind ./gxemul -e testm88k test/FileLoader_A.OUT_M88K # followed by # kcachegrind # # # The main things that are detected by this script: # # o) special hacks for some OSes # o) which compiler(s) to use (overridden by setting CXX) # o) which compiler flags to use (overridden by setting CXXFLAGS) # o) X11 flags and libraries (TODO: should be possible to override # via command line options?) # # The general philosophy regarding command line switches is that anything # which can be incorporated into the program as a runtime command line option # should be, instead of requiring a recompile. # ############################################################################### # # Figure out the default prefix for "make install": # # If the PREFIX environment variable is set before running configure, it is # used. The DEFAULTPREFIX calculated here is only used if PREFIX is undefined. # DEFAULTPREFIX=/usr/local # Special exception for Linux systems: /usr if [ z`uname` = zLinux ]; then DEFAULTPREFIX=/usr else TRY=/usr/local if [ -d $TRY/bin ]; then DEFAULTPREFIX=$TRY else TRY=/opt if [ -d $TRY ]; then DEFAULTPREFIX=$TRY else TRY=/usr if [ -d $TRY ]; then DEFAULTPREFIX=$TRY fi fi fi fi OTHERLIBS="$LDFLAGS" UNITTESTS=YES # Figure out if this is a stable version (0.x.x). X=`basename \`pwd\`|cut -d \- -f 2-|cut -c1-2` if [ z"$X" = z0. ]; then # Stable. : else # Development. UNSTABLE=YES fi if [ z"$*" != z ]; then # Parse command line options: for a in $*; do if [ z$a = z--disable-x ]; then NOX11=YES else if [ z$a = z--without-unittests ]; then UNITTESTS=NO else if [ z$a = z--disable-valgrind ]; then DISABLEVALGRIND=YES else if [ z$a = z--debug ]; then DEBUG=YES else if [ z$a = z--help ]; then printf "usage: $0 [options]\n\n" echo " --disable-x don't include X11 support,"\ "even if the host supports it" echo " --disable-valgrind don't use valgrind, even"\ "if it is installed" echo " --without-unittests don't include unit tests" echo " --debug configure for a" \ "debug build (turn off optimizations)" echo echo "If the PREFIX environment variable is set," \ "it will override the default" echo "value, which on this platform is: $DEFAULTPREFIX" echo exit else echo "Invalid option: $a" echo "Run $0 --help to get a list of" \ "available options." exit fi; fi; fi; fi; fi done fi ############################################################################### # # Configure options: # # This creates a config.h file, which is then included from include/misc.h. # ############################################################################### # Head of config.h: printf "/* * THIS FILE IS AUTOMATICALLY CREATED BY configure! * DON'T EDIT THIS FILE MANUALLY, IT WILL BE OVERWRITTEN. */ \n#ifndef CONFIG_H\n#define CONFIG_H\n\n" > config.h # Figure out if VERSION should be defined. X=`basename \`pwd\`|cut -d \- -f 2-` if [ z"$X" = zgxemul ]; then printf "#define VERSION \"(unknown version)\"\n" >> config.h else printf "#define VERSION \"$X\"\n" >> config.h fi if [ z"$UNSTABLE" = zYES ]; then printf "#define UNSTABLE_DEVEL\n" >> config.h fi if [ z"$UNITTESTS" = zYES ]; then printf "#define WITHUNITTESTS\n" >> config.h fi if [ z"$DEBUG" = zYES ]; then echo "Building a debug version!" CXXFLAGS="-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC $CXXFLAGS" else CXXFLAGS="-DNDEBUG $CXXFLAGS" fi ZZ=`echo compiled on \`uname\`/\`uname -m\`, \`date\`` printf "#define COMPILE_DATE \"$ZZ\"\n" >> config.h # Include support for all CPU types: printf "#define ADD_ALL_CPU_FAMILIES " >> config.h # Alpha printf " add_cpu_family(alpha_cpu_family_init, ARCH_ALPHA);" >> config.h CPU_ARCHS="$CPU_ARCHS cpu_alpha.o cpu_alpha_palcode.o memory_alpha.o" CPU_TOOLS="$CPU_TOOLS generate_alpha_misc" # ARM printf " add_cpu_family(arm_cpu_family_init, ARCH_ARM);" >> config.h CPU_ARCHS="$CPU_ARCHS cpu_arm.o cpu_arm_coproc.o memory_arm.o " CPU_ARCHS="$CPU_ARCHS tmp_arm_loadstore.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_loadstore_p0_u0_w0.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_loadstore_p0_u0_w1.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_loadstore_p0_u1_w0.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_loadstore_p0_u1_w1.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_loadstore_p1_u0_w0.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_loadstore_p1_u0_w1.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_loadstore_p1_u1_w0.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_loadstore_p1_u1_w1.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_dpi.o tmp_arm_r.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_r0.o tmp_arm_r1.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_r2.o tmp_arm_r3.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_r4.o tmp_arm_r5.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_r6.o tmp_arm_r7.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_r8.o tmp_arm_r9.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_ra.o tmp_arm_rb.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_rc.o tmp_arm_rd.o" CPU_ARCHS="$CPU_ARCHS tmp_arm_re.o tmp_arm_rf.o tmp_arm_multi.o" CPU_TOOLS="$CPU_TOOLS generate_arm_dpi generate_arm_r" CPU_TOOLS="$CPU_TOOLS generate_arm_loadstore generate_arm_multi" # M88K printf " add_cpu_family(m88k_cpu_family_init, ARCH_M88K);" >> config.h CPU_ARCHS="$CPU_ARCHS cpu_m88k.o memory_m88k.o" CPU_TOOLS="$CPU_TOOLS generate_m88k_bcnd" CPU_TOOLS="$CPU_TOOLS generate_m88k_loadstore" # MIPS printf " add_cpu_family(mips_cpu_family_init, ARCH_MIPS);" >> config.h CPU_ARCHS="$CPU_ARCHS cpu_mips.o cpu_mips_coproc.o " CPU_ARCHS="$CPU_ARCHS cpu_mips_instr_unaligned.o" CPU_TOOLS="$CPU_TOOLS generate_mips_loadstore" CPU_TOOLS="$CPU_TOOLS generate_mips_loadstore_multi" # POWER/PowerPC printf " add_cpu_family(ppc_cpu_family_init, ARCH_PPC);" >> config.h CPU_ARCHS="$CPU_ARCHS cpu_ppc.o" CPU_TOOLS="$CPU_TOOLS generate_ppc_loadstore" # SuperH printf " add_cpu_family(sh_cpu_family_init, ARCH_SH);" >> config.h CPU_ARCHS="$CPU_ARCHS cpu_sh.o memory_sh.o" printf "\n" >> config.h ############################################################################### # # Special hacks for some host OSes: # ############################################################################### if [ z"`uname|cut -c 1-6`" = zCYGWIN ]; then CYGWIN=YES if [ z"$CXX" = z ]; then # Assume GNU C++ on Cygwin (Windows) systems. CC=g++ fi fi ############################################################################### # # Create the Makefile header: # ############################################################################### rm -f _Makefile.header printf "# # DO NOT EDIT THIS FILE! It is automagically created by # the configure script, based on Makefile.skel. #\n\n" >> _Makefile.header # Try with the simplest possible test program. Actually, test static variables # as well, because GXemul uses things like NULL-initialized global pointers, # and it is important that they work. (Some versions of GCC on Solaris are # known to be completely broken, for instance.) echo '#include int main(int argc, char *argv[]) { static int x = 0; static int y = 1; printf("%i,%i", x, y); return 0; } ' > _testprog.cc # Try to detect which C++ compiler to use, if CXX is not set: printf "checking which C++ compiler to use... " rm -f _testprog if [ z"$CXX" = z ]; then # Try g++ first: printf "#!/bin/sh\ng++ $CXXFLAGS _testprog.cc -o _testprog >" > _test.sh printf " /dev/null 2> /dev/null\n" >> _test.sh chmod 755 _test.sh ./_test.sh > /dev/null 2> /dev/null if [ -x _testprog ]; then if [ z`./_testprog` = z0,1 ]; then CXX=g++ else printf "broken g++ detected\n" printf "The test program:\n\n" cat _testprog.cc printf "\nshould have resulted in 0,1, but the" printf " result was: " ./_testprog printf "\n\nchecking for other C++ compilers... " fi fi rm -f _testprog # If both g++ and c++ exist, then c++ might be a vendor specific # compiler which produces faster code: printf "#!/bin/sh\nc++ $CXXFLAGS _testprog.cc -o _testprog >" > _test.sh printf " /dev/null 2> /dev/null\n" >> _test.sh chmod 755 _test.sh ./_test.sh > /dev/null 2> /dev/null if [ -x _testprog ]; then if [ z`./_testprog` = z0,1 ]; then CXX=c++ else printf "broken c++ detected\n" printf "checking for other C++ compilers... " fi fi rm -f _testprog rm -f _test.sh fi rm -f _testprog if [ z"$CXX" = z ]; then printf "no working compiler detected\n" printf "\nPlease set the CXX environment variable to a working C++ " printf "compiler before running\nthe configure script, and make" printf " sure that the CXXFLAGS environment variable is\nalso valid" printf " for that compiler.\n" exit fi echo "$CXX $CXXFLAGS" if [ z$NOX11 = z ]; then printf "checking for X11 headers and libs\n" # Try to compile a small X11 test program: printf "#include #include Display *dis; void f(void) { dis = XOpenDisplay(NULL); } int main(int argc, char *argv[]) { return 0; } " > _test_x11.cc XOK=0 XINCLUDE=-I/usr/X11R6/include $CXX $CXXFLAGS _test_x11.cc -c -o _test_x11.o $XINCLUDE 2> /dev/null XLIB="-L/usr/X11R6/lib -lX11" $CXX $CXXFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null if [ -x _test_x11 ]; then XOK=1 fi rm -f _test_x11 _test_x11.o if [ z$XOK = z0 ]; then XINCLUDE=-I/usr/local/include $CXX $CXXFLAGS _test_x11.cc -c -o _test_x11.o $XINCLUDE 2> /dev/null XLIB="-L/usr/local/lib -lX11" $CXX $CXXFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null if [ -x _test_x11 ]; then XOK=1 fi fi rm -f _test_x11 _test_x11.o # Special case for some 64-bit Linux/x86_64 systems: if [ z$XOK = z0 ]; then $CXX $CXXFLAGS _test_x11.cc -c -o _test_x11.o $XINCLUDE 2> /dev/null XLIB="-L/usr/X11R6/lib64 -lX11" $CXX $CXXFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null if [ -x _test_x11 ]; then XOK=1 fi fi rm -f _test_x11 _test_x11.o if [ z$XOK = z0 ]; then XINCLUDE="" $CXX $CXXFLAGS _test_x11.cc -c -o _test_x11.o $XINCLUDE 2> /dev/null # -lsocket for Solaris XLIB="-lX11 -lsocket" $CXX $CXXFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null if [ -x _test_x11 ]; then XOK=1 fi rm -f _test_x11 _test_x11.o fi if [ z`uname` = zNetBSD ]; then echo "Using NetBSD hack for X11 libs..." XLIB="$XLIB -Wl,-rpath,/usr/X11R6/lib" fi if [ z`uname` = zOpenBSD ]; then if [ z`uname -m` = zarc ]; then echo "Using old OpenBSD/arc hack for X11 libs..." XLIB="$XLIB -Wl,-rpath,/usr/X11R6/lib" fi fi if [ z$XOK = z0 ]; then echo "Failed to compile X11 test program." \ "Configuring without X11." else printf "X11 headers: $XINCLUDE\n" printf "X11 libraries: $XLIB\n" echo "XINCLUDE=$XINCLUDE" >> _Makefile.header echo "XLIB=$XLIB" >> _Makefile.header printf "#define WITH_X11\n" >> config.h fi rm -f _test_x11.cc fi if [ z$HPUX = zYES ]; then CXXFLAGS="-D_XOPEN_SOURCE_EXTENDED $CXXFLAGS" printf "#define HPUX\n" >> config.h fi if [ z$OSF1 = zYES ]; then CXXFLAGS="-D_XOPEN_SOURCE=500 -D_OSF_SOURCE -D_POSIX_PII_SOCKET $CXXFLAGS" fi # CWARNINGS: printf "checking whether -Wall can be used... " $CXX $CXXFLAGS _testprog.cc -o _testprog -Wall 2> /dev/null if [ -x _testprog ]; then printf "yes\n" CWARNINGS="-Wall $CWARNINGS" if [ z"$UNSTABLE" = zYES ]; then printf "checking whether -Werror can be used... " rm -f _testprog $CXX $CWARNINGS $CXXFLAGS _testprog.cc -o _testprog -Werror 2> _testprog.err if [ -x _testprog ]; then printf "yes\n" # CWARNINGS="$CWARNINGS -Werror" else printf "no\n" #printf "CXXFLAGS = $CXXFLAGS\n" #cat _testprog.err #printf "\n" fi fi else printf "no\n" fi rm -f _testprog _testprog.err # -Wstrict-aliasing printf "checking whether -Wstrict-aliasing can be used... " $CXX $CXXFLAGS -Wstrict-aliasing _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep strict _testprog.error > /dev/null 2>&1; then printf "no\n" else if [ -x _testprog ]; then CWARNINGS="-Wstrict-aliasing $CWARNINGS" printf "yes\n" else printf "no\n" fi fi rm -f _testprog _testprog.error _testprog.stdout # -Wnon-virtual-dtor printf "checking whether -Wnon-virtual-dtor can be used... " $CXX $CXXFLAGS -Wnon-virtual-dtor _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep strict _testprog.error > /dev/null 2>&1; then printf "no\n" else if [ -x _testprog ]; then CWARNINGS="-Wnon-virtual-dtor $CWARNINGS" printf "yes\n" else printf "no\n" fi fi rm -f _testprog _testprog.error _testprog.stdout # -Wextra -Wno-unused-parameter printf "checking whether -Wextra -Wno-unused-parameter can be used... " $CXX $CXXFLAGS -Wextra -Wno-unused-parameter _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep strict _testprog.error > /dev/null 2>&1; then printf "no\n" else if [ -x _testprog ]; then CWARNINGS="$CWARNINGS -Wextra -Wno-unused-parameter" printf "yes\n" else printf "no\n" fi fi rm -f _testprog _testprog.error _testprog.stdout # -Wcast-align printf "checking whether -Wcast-align can be used... " $CXX $CXXFLAGS -Wcast-align _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep strict _testprog.error > /dev/null 2>&1; then printf "no\n" else if [ -x _testprog ]; then CWARNINGS="-Wcast-align $CWARNINGS" printf "yes\n" else printf "no\n" fi fi rm -f _testprog _testprog.error _testprog.stdout # -Wcast-qual #printf "checking whether -Wcast-qual can be used... " #$CXX $CXXFLAGS -Wcast-qual _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 #cat _testprog.stdout >> _testprog.error #if grep strict _testprog.error > /dev/null 2>&1; then #printf "no\n" #else #if [ -x _testprog ]; then # CWARNINGS="-Wcast-qual $CWARNINGS" #printf "yes\n" # else #printf "no\n" # fi #fi #rm -f _testprog _testprog.error _testprog.stdout # -Wshadow printf "checking whether -Wshadow can be used... " $CXX $CXXFLAGS -Wshadow _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep strict _testprog.error > /dev/null 2>&1; then printf "no\n" else if [ -x _testprog ]; then CWARNINGS="-Wshadow $CWARNINGS" printf "yes\n" else printf "no\n" fi fi rm -f _testprog _testprog.error _testprog.stdout # -O optimization for non-debug builds. Try -O and -O3. if [ ! z"$DEBUG" = zYES ]; then $CXX $CXXFLAGS -O _testprog.cc -o _testprog 2> /dev/null if [ -x _testprog ]; then rm -f _testprog $CXX $CXXFLAGS -O3 _testprog.cc -o _testprog 2> /dev/null if [ -x _testprog ]; then CXXFLAGS="-O3 $CXXFLAGS" else CXXFLAGS="-O $CXXFLAGS" fi fi fi rm -f _testprog # -fpeephole if [ ! z"$DEBUG" = zYES ]; then printf "checking whether -fpeephole can be used... " $CXX $CXXFLAGS -fpeephole _testprog.cc -o _testprog > _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep peephole _testprog.error > /dev/null 2>&1; then printf "no\n" else if [ -x _testprog ]; then CXXFLAGS="-fpeephole $CXXFLAGS" printf "yes\n" else printf "no\n" fi fi rm -f _testprog _testprog.error _testprog.stdout fi # -fomit-frame-pointer if [ ! z"$DEBUG" = zYES ]; then printf "checking whether -fomit-frame-pointer can be used... " $CXX $CXXFLAGS -fomit-frame-pointer _testprog.cc -o \ _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep frame _testprog.error > /dev/null 2>&1; then printf "no\n" else if [ -x _testprog ]; then CXXFLAGS="-fomit-frame-pointer $CXXFLAGS" printf "yes\n" else printf "no\n" fi fi rm -f _testprog _testprog.error _testprog.stdout fi # -fstrict-aliasing if [ ! z"$DEBUG" = zYES ]; then printf "checking whether -fstrict-aliasing can be used... " $CXX $CXXFLAGS -fstrict-aliasing _testprog.cc -o \ _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep strict _testprog.error > /dev/null 2>&1; then printf "no\n" else if [ -x _testprog ]; then CXXFLAGS="-fstrict-aliasing $CXXFLAGS" printf "yes\n" else printf "no\n" fi fi rm -f _testprog _testprog.error _testprog.stdout fi # -fno-rtti if [ ! z"$DEBUG" = zYES ]; then printf "checking whether -fno-rtti can be used... " $CXX $CXXFLAGS -fno-rtti _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep rtti _testprog.error > /dev/null 2>&1; then printf "no\n" else if [ -x _testprog ]; then CXXFLAGS="-fno-rtti $CXXFLAGS" printf "yes\n" else printf "no\n" fi fi rm -f _testprog _testprog.error _testprog.stdout fi # -g, for development builds if [ z"$UNSTABLE" = zYES ]; then printf "checking whether -g can be used... " $CXX $CXXFLAGS -g _testprog.cc -o _testprog > _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if [ -x _testprog ]; then CXXFLAGS="-g $CXXFLAGS" printf "yes\n" else printf "no\n" fi rm -f _testprog _testprog.error _testprog.stdout fi # -lrt for nanosleep? printf "checking whether -lrt is required for nanosleep... " printf "#include \n#include int main(int argc, char *argv[]){nanosleep(NULL,NULL);return 0;}\n" > _testns.cc $CXX $CXXFLAGS _testns.cc -o _testns 2> /dev/null if [ ! -x _testns ]; then $CXX $CXXFLAGS -lrt _testns.cc -o _testns 2> /dev/null if [ ! -x _testns ]; then printf "WARNING! COULD NOT COMPILE WITH nanosleep AT ALL!\n" else # -lrt for nanosleep OTHERLIBS="-lrt $OTHERLIBS" printf "yes\n" fi else printf "no\n" fi rm -f _testns.cc _testns # -lresolv for inet_pton? printf "checking whether -lresolv is required for inet_pton... " printf "int inet_pton(void); int main(int argc, " > _testr.cc printf "char *argv[]) { return inet_pton(); }\n" >> _testr.cc $CXX $CXXFLAGS _testr.cc -o _testr 2> /dev/null if [ ! -x _testr ]; then $CXX $CXXFLAGS _testr.cc -lresolv -o _testr 2> /dev/null if [ ! -x _testr ]; then $CXX $CXXFLAGS _testr.cc -lresolv -lnsl -o _testr 2> /dev/null if [ ! -x _testr ]; then printf "no, using inet_aton\n" else # -lresolv -lnsl for inet_pton OTHERLIBS="-lresolv -lnsl $OTHERLIBS" printf "yes (and -lnsl)\n" printf "#define HAVE_INET_PTON\n" >> config.h fi else # -lresolv for inet_pton OTHERLIBS="-lresolv $OTHERLIBS" printf "yes\n" printf "#define HAVE_INET_PTON\n" >> config.h fi else printf "no\n" printf "#define HAVE_INET_PTON\n" >> config.h fi rm -f _testr.cc _testr.o _testr # -lm? printf "checking for math libs..." printf "#include \nint main(int argc, char *argv[]) { " > _testr.cc printf "double x = sqrt(sin((double)argc)); return (int)x; }\n" >> _testr.cc $CXX $CXXFLAGS _testr.cc -o _testr 2> /dev/null if [ ! -x _testr ]; then $CXX $CXXFLAGS _testr.cc -lm -o _testr 2> /dev/null if [ ! -x _testr ]; then $CXX $CXXFLAGS _testr.cc -lm -lcpml -o _testr 2> /dev/null if [ ! -x _testr ]; then printf "\nWARNING! Could not compile math test " printf "at all!\nContinuing anyway.\n\n" else # -lm AND -lcpml OTHERLIBS="-lm -lcpml $OTHERLIBS" printf " -lm -lcpml\n" fi else # Normal -lm OTHERLIBS="-lm $OTHERLIBS" printf " -lm\n" fi else printf " none needed\n" fi rm -f _testr.cc _testr.o _testr # strlcpy missing? printf "checking for strlcpy... " printf "#include int main(int argc, char *argv[]) { char *p; char *q; size_t x; x = strlcpy(p, q, 50); return 0;}\n" > _tests.cc $CXX $CXXFLAGS _tests.cc -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "missing, using mystrlcpy\n" printf "#define strlcpy mystrlcpy\n" >> config.h printf "#define strlcat mystrlcat\n" >> config.h printf "#define USE_STRLCPY_REPLACEMENTS\n" >> config.h else printf "found\n" fi rm -f _tests.cc _tests.o _tests # strtoull missing? printf "checking for strtoull... " printf "#include #include #include int main(int argc, char *argv[]) { long long x = strtoull(argv[1], NULL, 0); return 0;}\n" > _tests.cc $CXX $CXXFLAGS _tests.cc -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "missing, using mystrtoull\n" printf "#define strtoull mystrtoull\n" >> config.h else printf "found\n" fi rm -f _tests.cc _tests.o _tests # mkstemp missing? printf "checking for mkstemp... " printf "#include #include int main(int argc, char *argv[]) { int x; char y[4] = \"abc\"; x = mkstemp(y); return 0;}\n" > _tests.cc $CXX $CXXFLAGS _tests.cc -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "missing, using workaround (perhaps not working properly)\n" printf "#define mkstemp mymkstemp\n" >> config.h else printf "found\n" fi rm -f _tests.cc _tests.o _tests # fseeko missing? printf "checking for fseeko... " printf "#include #include #include #include int main(int argc, char *argv[]) { fseeko(NULL, 0, 0); return 0;}\n" > _tests.cc $CXX $CXXFLAGS $CWARNINGS _tests.cc -o _tests 2> /dev/null if [ ! -x _tests ]; then # Try with _LARGEFILE_SOURCE (hack to make fseeko # work on 64-bit Linux): $CXX $CXXFLAGS -D_LARGEFILE_SOURCE $CWARNINGS _tests.cc -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "missing\n" printf "WARNING! fseeko missing from libc. Using a hack, " printf "which probably doesn't work.\n" printf "#define HACK_FSEEKO\n" >> config.h else printf "using -D_LARGEFILE_SOURCE hack\n" CXXFLAGS="$CXXFLAGS -D_LARGEFILE_SOURCE" fi else printf "found\n" fi rm -f _tests.cc _tests.o _tests # socklen_t missing? # (for example really old OpenBSD/arc 2.3, inside the emulator) printf "checking for socklen_t... " printf "#include #include #include #include int main(int argc, char *argv[]) { socklen_t x; return 0;}\n" > _tests.cc $CXX $CXXFLAGS _tests.cc -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "no, using int\n" CXXFLAGS="$CXXFLAGS -Dsocklen_t=int" else printf "socklen_t\n" fi rm -f _tests.cc _tests.o _tests # MAP_ANON missing? (On some HP-UX systems? Use MAP_ANONYMOUS instead.) printf "checking for MAP_ANON... " rm -f _tests printf "#include #include #include int main(int argc, char *argv[]) { int x = MAP_ANON; return 0;}\n" > _tests.cc $CXX $CXXFLAGS _tests.cc -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "#include #include #include int main(int argc, char *argv[]) { int x = MAP_ANONYMOUS; return 0;}\n" > _tests.cc $CXX $CXXFLAGS _tests.cc -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "no\n\n" printf "WARNING! Neither MAP_ANON nor MAP_ANONYMOUS work on " printf "this system.\nPlease try to compile anyway, and report" printf " to me whether it builds/runs or not.\n\n" printf "#define MAP_ANON 0\n" >> config.h printf "#define NO_MAP_ANON\n" >> config.h else printf "using MAP_ANONYMOUS\n" printf "#define MAP_ANON MAP_ANONYMOUS\n" >> config.h fi else printf "yes\n" fi rm -f _tests.cc _tests.o _tests # Check for PRIx64 in inttypes.h: printf "checking for PRIx64 in inttypes.h... " printf "#include \nint main(int argc, char *argv[])\n {\n#ifdef PRIx64\nreturn 0;\n#else\nreturn 1;\n#endif\n}\n" > _testpri.cc $CXX $CXXFLAGS _testpri.cc -o _testpri 2> /dev/null if [ ! -x _testpri ]; then printf "\nERROR! COULD NOT COMPILE PRIx64 TEST PROGRAM AT ALL!\n" exit else if ./_testpri; then printf "yes\n" else $CXX $CXXFLAGS -D__STDC_FORMAT_MACROS _testpri.cc -o _testpri 2> /dev/null if [ -x _testpri ]; then printf "using __STDC_FORMAT_MACROS\n" CXXFLAGS="$CXXFLAGS -D__STDC_FORMAT_MACROS" else printf "no, using an ugly hack instead, " printf "#define NO_C99_PRINTF_DEFINES\n" >> config.h # Try llx first: printf "#include \n#include \nint main(int argc, char *argv[]){ printf(\"%%llx\\\n\", (int64_t)128);return 0;}\n" > _testpri.cc rm -f _testpri $CXX $CXXFLAGS $CWARNINGS _testpri.cc -o _testpri 2> /dev/null if [ z`./_testpri` = z80 ]; then printf "PRIx64=llx\n" printf "#define NO_C99_64BIT_LONGLONG\n" >> config.h else # Try lx too: printf "#include \n#include \nint main(int argc, char *argv[]){ printf(\"%%lx\\\n\", (int64_t)128);return 0;}\n" > _testpri.cc rm -f _testpri $CXX $CXXFLAGS $CWARNINGS _testpri.cc -o _testpri 2> _testpri.result if [ z`./_testpri` = z80 ]; then printf "PRIx64=lx\n" else printf "\nFailed, neither lx nor llx worked!\n" exit fi fi fi fi fi rm -f _testpri.cc _testpri _testpri.result # Check for 64-bit off_t: printf "checking for 64-bit off_t... " printf "#include \n#include \n#include \n int main(int argc, char *argv[]){printf(\"%%i\\\n\", (int)sizeof(off_t));return 0;}\n" > _testoff.cc $CXX $CXXFLAGS _testoff.cc -o _testoff 2> /dev/null if [ ! -x _testoff ]; then printf "\nWARNING! COULD NOT COMPILE off_t TEST PROGRAM AT ALL!\n" else if [ z`./_testoff` = z8 ]; then printf "yes\n" else $CXX $CXXFLAGS -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \ _testoff.cc -o _testoff 2> /dev/null if [ ! -x _testoff ]; then printf "\nWARNING! COULD NOT COMPILE off_t TEST " printf "PROGRAM!\n" else if [ z`./_testoff` = z8 ]; then CXXFLAGS="-D_FILE_OFFSET_BITS=64 $CXXFLAGS" CXXFLAGS="-D_LARGEFILE_SOURCE $CXXFLAGS" printf "using -D_FILE_OFFSET_BITS=64" printf " -D_LARGEFILE_SOURCE\n" else printf "NO\n" printf "Warning! No 64-bit off_t. Continuing " printf "anyway.\n" fi fi fi fi rm -f _testoff.cc _testoff # Check for u_int8_t etc: # These are needed because some header files in src/include/ use u_int* # instead of uint*, and I don't have time to rewrite them all. printf "checking for u_int8_t... " printf "#include \n#include \n#include \n int main(int argc, char *argv[]){printf(\"%%i\\\n\", (int)sizeof(u_int8_t));return 0;}\n" > _testuint.cc $CXX $CXXFLAGS _testuint.cc -o _testuint 2> /dev/null if [ ! -x _testuint ]; then rm -f _testuint* printf "#include \n#include \n#include \nint main(int argc, char *argv[]) {printf(\"%%i\\\n\", (int)sizeof(uint8_t));return 0;}\n" > _testuint.cc $CXX $CXXFLAGS _testuint.cc -o _testuint 2> /dev/null if [ ! -x _testuint ]; then printf "no\n\nERROR: No u_int8_t or uint8_t. Aborting\n" # TODO: Automagically detect using various combinations # of char, int, short, long etc. exit fi printf "typedef uint8_t u_int8_t;\n" >> config.h printf "typedef uint16_t u_int16_t;\n" >> config.h printf "typedef uint32_t u_int32_t;\n" >> config.h printf "uint8_t\n" else printf "yes\n" fi rm -f _testuint.cc _testuint printf "checking for u_int64_t... " printf "#include \n#include \n#include \n int main(int argc, char *argv[]){printf(\"%%i\\\n\", (int)sizeof(u_int64_t));return 0;}\n" > _testuint.cc $CXX $CXXFLAGS _testuint.cc -o _testuint 2> /dev/null if [ ! -x _testuint ]; then rm -f _testuint* printf "#include \n#include \n#include \nint main(int argc, char *argv[]) {printf(\"%%i\\\n\", (int)sizeof(uint64_t));return 0;}\n" > _testuint.cc $CXX $CXXFLAGS _testuint.cc -o _testuint 2> /dev/null if [ ! -x _testuint ]; then printf "no\n\nERROR: No u_int64_t or uint64_t. Aborting\n" # TODO: Automagically detect using various combinations # of char, int, short, long etc. exit fi printf "typedef uint64_t u_int64_t;\n" >> config.h printf "uint64_t\n" else printf "yes\n" fi rm -f _testuint* printf "checking for __FUNCTION__... " printf "#include \n\nint main(int argc, char *argv[]) { if (__FUNCTION__) printf(__FUNCTION__);\n return 0;\n}\n" > _testfunction.cc $CXX $CXXFLAGS _testfunction.cc -o _testfunction 2> /dev/null if [ ! -x _testfunction ]; then printf "no\n" else if [ z`./_testfunction` = zmain ]; then printf "yes\n" printf "#define HAVE___FUNCTION__\n" >> config.h else printf "no\n" fi fi rm -f _testfunction* ############################################################################### # Host byte order? printf "checking host endianness... " rm -f _test_end* printf '#include int main(int argc, char *argv[]) { int x = 1; void *xp = (void *)&x; char *p = (char *)xp; if (*p) printf("little\\\n"); else printf("big\\\n"); } ' > _test_end.cc $CXX $CXXFLAGS _test_end.cc -o _test_end 2> /dev/null X=`./_test_end` echo $X if [ z$X = zlittle ]; then printf "#define HOST_LITTLE_ENDIAN\n" >> config.h else if [ z$X = zbig ]; then printf "#define HOST_BIG_ENDIAN\n" >> config.h else echo "Error! Could not determine host's endianness." exit fi fi rm -f _test_end* ############################################################################### printf "checking for Doxygen... " if (doxygen --version); then # Version is printed, if found. DOXYGEN=doxygen else # Not found is already printed, if doxygen is not found. DOXYGEN="\#" fi ############################################################################### printf "checking for valgrind... " if [ z$DISABLEVALGRIND = zYES ]; then echo skipped else if (valgrind --version); then # Version is printed, if found. VALGRIND="valgrind -q --log-file=tmp_valgrind.out" else # Not found is already printed, if valgrind is not found. VALGRIND="" fi fi ############################################################################### if [ "z$PREFIX" = z ]; then PREFIX="$DEFAULTPREFIX" fi echo "checking for 'make install' prefix: $PREFIX" ############################################################################### if [ z"$MANDIR" = z ]; then # Guess either $PREFIX/share/man or $PREFIX/man, depending on existing # directories. Fallback is $PREFIX/man. TRY=$PREFIX/share/man if [ -d "$TRY" ]; then MANDIR="$TRY" else MANDIR="$PREFIX"/man fi fi echo "checking for 'make install' man dir: $MANDIR" ############################################################################### INCLUDE=-Iinclude/ DINCLUDE=-I../include/ INCLUDE2=-I../../include/ rm -f _testprog.c* echo C++ compiler flags: $CXXFLAGS $CWARNINGS echo Linker flags: $OTHERLIBS if [ z"$DESTDIR" != z ]; then echo "Destination dir: $DESTDIR" fi echo "CWARNINGS=$CWARNINGS" >> _Makefile.header echo "COPTIM=$CXXFLAGS" >> _Makefile.header echo "INCLUDE=$INCLUDE" >> _Makefile.header echo "DINCLUDE=$DINCLUDE" >> _Makefile.header echo "INCLUDE2=$INCLUDE2" >> _Makefile.header echo "CXX=$CXX" >> _Makefile.header echo "OTHERLIBS=$OTHERLIBS" >> _Makefile.header echo "CPU_ARCHS=$CPU_ARCHS" >> _Makefile.header echo "CPU_TOOLS=$CPU_TOOLS" >> _Makefile.header echo "DOXYGEN=$DOXYGEN" >> _Makefile.header echo "VALGRIND=$VALGRIND" >> _Makefile.header echo "PREFIX=$PREFIX" >> _Makefile.header echo "MANDIR=$MANDIR" >> _Makefile.header echo "DESTDIR=$DESTDIR" >> _Makefile.header echo "" >> _Makefile.header # Create list of unit testable classes: rm -f unittest.h unittest_h.h printf "// DO NOT EDIT. Automagically generated by the configure script.\n" >> unittest.h printf "// DO NOT EDIT. Automagically generated by the configure script.\n" >> unittest_h.h printf "// Will be removed by make clean_all\n\n" >> unittest.h printf "// Will be removed by make clean_all\n\n" >> unittest_h.h for a in `find src -name "*.cc" -print`; do grep UNITTESTS\( "$a"; done | cut -d \( -f 2|cut -d \) -f 1 > _unittests.tmp for a in `cat _unittests.tmp`; do if [ ! z$a = zclassName ]; then cd src/include HNAME=`find . -name $a.h | cut -c 3-` cd ../.. printf "#include \"$HNAME\"\n" >> unittest_h.h printf "\t$a::RunUnitTests(nSucceeded, nFailed);\n" >> unittest.h fi done rm -f _unittests.tmp # Create a list of Commands: rm -f commands_h.h commands.h printf "// DO NOT EDIT. Automagically generated by the configure script.\n" >> commands.h printf "// DO NOT EDIT. Automagically generated by the configure script.\n" >> commands_h.h printf "// Will be removed by make clean_all\n\n" >> commands.h printf "// Will be removed by make clean_all\n\n" >> commands_h.h for a in src/main/commands/*.cc; do echo $a|cut -d / -f 4-; done > _commands.tmp for a in `cat _commands.tmp`; do CNAME=`echo $a|cut -d . -f 1` printf "#include \"commands/$CNAME.h\"\n" >> commands_h.h printf "\tAddCommand(new $CNAME);\n" >> commands.h done rm -f _commands.tmp # Create a list of Components: rm -f components.h components_h.h printf "// DO NOT EDIT. Automagically generated by the configure script.\n" >> components.h printf "// DO NOT EDIT. Automagically generated by the configure script.\n" >> components_h.h printf "// Will be removed by make clean_all\n\n" >> components.h printf "// Will be removed by make clean_all\n\n" >> components_h.h grep COMPONENT\( src/include/components/*.h|cut -d \( -f 2|cut -d \) -f 1 > _components.tmp cd src/include/components for a in `cat ../../../_components.tmp`; do CNAME=`grep COMPONENT\($a\) *.h|cut -d . -f 1` printf "#include \"components/$CNAME.h\"\n" >> ../../../components_h.h printf "\t{ \"$a\", $CNAME::Create, $CNAME::GetAttribute },\n" >> ../../../components.h done cd ../../.. rm -f _components.tmp # Create the Makefiles: D=". src src/components src/components/busses src/components/cpu" D="$D src/components/machines src/components/memory src/components/special" D="$D src/console src/cpus src/debugger src/devices src/old_main" D="$D src/devices/fonts src/disk src/file src/include src/machines src/main" D="$D src/main/commands src/main/fileloaders src/net" D="$D src/promemul src/symbol src/ui src/ui/console src/ui/nullui" for a in $D; do echo "creating $a/Makefile" touch $a/Makefile cat _Makefile.header > $a/Makefile cat $a/Makefile.skel >> $a/Makefile done # Undefine 'mips', to enable build on OpenBSD's MIPS platforms: printf "\n#undef mips\n" >> config.h # Tail of config.h: printf "\n#endif /* CONFIG_H */\n" >> config.h # Remove temporary Makefile header, etc.: rm -f _Makefile.header _test* echo Configured. You may now run make to build gxemul. gxemul-0.6.1/src/000755 001750 001750 00000000000 13402411502 014014 5ustar00debugdebug000000 000000 gxemul-0.6.1/LICENSE000644 001750 001750 00000004012 13402411502 014227 0ustar00debugdebug000000 000000 Copyright (C) 2003-2018 Anders Gavare. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Exceptions to the license above: The demos in the demos/ directories, and the testmachine header files in src/include/testmachine/, are placed in the public domain. This way, they can be reused in projects which for some reason are incompatible with the conditions required by the BSD-style license. Some of the header files in the src/include/ directory, containing definitions of bitfields for hardware devices etc., are copied from NetBSD and other sources. If you plan to redistribute GXemul (for example as a binary package), or reuse code from GXemul, then you should check those files for their license terms. gxemul-0.6.1/experiments/000755 001750 001750 00000000000 13402411502 015570 5ustar00debugdebug000000 000000 gxemul-0.6.1/experiments/udp_snoop.c000644 001750 001750 00000005362 13402411502 017750 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * $Id: udp_snoop.c,v 1.1 2006-09-07 11:44:42 debug Exp $ * * Dumps UDP packets in hex and ASCII that arrive at a specific port. */ #include #include #include #include #include void dump_buf(unsigned char *p, ssize_t len) { while (len > 0) { ssize_t i, n = len>=16? 16 : len; for (i=0; i=32 && p[i]<127) printf("%c", p[i]); else printf("."); } printf("\n"); p += 16; len -= 16; } } int main(int argc, char *argv[]) { struct sockaddr_in si; int s; if (argc < 2) { fprintf(stderr, "usage: %s udp_portnr\n", argv[0]); exit(1); } if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("socket"); exit(1); } memset((char *)&si, 0, sizeof(si)); si.sin_family = AF_INET; si.sin_port = htons(atoi(argv[1])); si.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(s, (struct sockaddr *)&si, sizeof(si)) < 0) { perror("bind"); exit(1); } for (;;) { unsigned char buf[2048]; ssize_t r = recv(s, buf, sizeof(buf), 0); if (r < 0) { perror("recv"); exit(1); } dump_buf(buf, r); printf("\n"); } return 0; } gxemul-0.6.1/experiments/Makefile000644 001750 001750 00000000660 13402411502 017232 0ustar00debugdebug000000 000000 BINS=cp_removeblocks bintrans_eval try_runlen udp_snoop \ sgiprom_to_bin decprom_dump_txt_to_bin hex_to_bin \ new_test_1 new_test_2 new_test_x new_test_loadstore ic_statistics all: $(BINS) new_test_loadstore: new_test_loadstore_a.o new_test_loadstore_b.o $(CC) new_test_loadstore_a.o new_test_loadstore_b.o -o new_test_loadstore clean: rm -f $(BINS) *.o *core native_cc_ld_test native_cc_ld_test.o clean_all: $(MAKE) clean gxemul-0.6.1/experiments/new_test_idea.txt000644 001750 001750 00000020540 13402411502 021144 0ustar00debugdebug000000 000000 2005-05-31: Idea about reasonably fast emulation using Dynamic Translation, but _NOT_ binary translation. (So there is no need for individual assembly language backends.) I got the inspiration for this when geist (in #osdev on Freenode) said that he had a 10-instruction overhead per emulated instruction in his emulator. I went to sleep with that statement ringing in my mind, and woke up a few hours later. Depending on how you count, it seems to be possible to get down to as few as 5+n+1 instructions overhead on i386, per emulated instruction, where n is the number of instructions it takes to do the actual work (for example 7 for a simple "add"-like instruction). (On Alpha, it's about 8+n+1, or 7+n+1 if you skip an alignment-unop. Also, on i386, a variant with 6+n+1 instructions gives better performance than 5+n+1, so this is probably best to leave for the compiler to optimize.) ------------------------------------------------------------------------------- Initial tests: a full page of 1024 add instructions followed by a return to the start of the page gives the following result: 2.8 GHz Xeon: 168 MIPS (16.66 cycles per emulated instruction) [ 6 instrs in the main loop + 7 instrs for the add + 1 instr for the return from the add function = 14. ] with gcc -O3 -fomit-frame-pointer 533 MHz pca56: 14.6 MIPS (36.3 cycles per emulated instruction) [ 7 instrs in the main loop + 7 instrs for the add + 1 instr for the return from the add function + 1 unop for alignment in the main loop = 16 instrs. ] with ccc -fast -O4 (see new_test_1.c) ------------------------------------------------------------------------------- run_one_instruction(struct cpu *cpu) { /* * Get the instruction to execute, and advance the * program counter: * * Actually, the program counter itself isn't increased here. * cpu->next_instr_call can be seen as an offset into the * current "page". cpu->current_page can be a pointer to that * page. So by taking * * ((size_t)cpu->next_instr_call - (size_t)cpu->current_page * ) / sizeof(struct instr_call) * * we get the lowest bits of the program counter. This is * only necessary for jumps and at the end of a translated * page. */ struct instr_call *ic = cpu->next_instr_call; cpu->next_instr_call ++; ic->f(cpu, ic); Pseudo-code for Alpha: cpu is in a0. move a0, s0 ; save away a0 lop: lq a1, next_instr_call(a0) ; a1 is ic addq a1, 64, t1 ; t1 = a1 + sizeof(struct instr_call) sq t1, next_instr_call(a0) ; cpu->next_instr_call ++; lq t2, f(a1) ; t2 = ic->f jsr ra,(t2),0 ; call ic->f(cpu, ic); move s0, a0 ; restore a0 + some fuss about the global pointer (goto lop) On i386, perhaps: ; assuming ebx is cpu mov esi, [ebx + next_instr_call] ; esi = ic = cpu->next_ic.. add [ebx + next_instr_call], 32 ; cpu->next_instr_call ++; push esi ; push ic push ebx ; push cpu call [esi + f] ; ic->f pop ebx ; restore cpu pointer pop eax ; nonsense loop... /* * If the program counter is changed because of a jump or so, * then cpu->next_instr_call should have been updated by * the 'f' function. * * If there was an exception, it could simply have been set * to something outside of the array. * * If we reach the end of a "translated" page, then there * could be a special function there as well. */ } f could be something like: f_add(struct cpu *cpu, struct instr_call *ic) { int32_t *a = (int32_t *) ic->arg[0]; int32_t *b = (int32_t *) ic->arg[1]; int32_t *c = (int32_t *) ic->arg[2]; *a = (*b) + (*c); In pseudo-alpha assembler: a0=cpu, a1=ic ld t0, 8(a1) ld t1, 16(a1) ld t2, 24(a1) ld t3, 0(t1) ld t4, 0(t2) addl t3,t4, t5 sd t5, 0(t0) ret } The arguments in the instr_call struct should be set up specifically for each function. An "add", as seen in the example above, usually needs two pointers to source values in memory, and a destination. ------------------------------------------------------------------------------- Things to think about: x) Exceptions: need to be detected by individual functions, and when detected, change cpu->next_instr_call to something which breaks out of the main loop. x) Single-stepping One solution is to have multiple run-loops. One which is used with single-stepping, and one for fast runs. x) End of page? What is a good page size? (It must be equal or less than an emulated hardware page, so maybe 4KB or less.) x) Default page = filled with entries of "this needs to be translated" function. (An optimization is to try to translate a few at a time, not just one, to minimize the number of calls/returns from the translator function.) x) Writes to a translated page should either invalidate the entire page's translations, or at least those entries that are written to. x) Common "combinations" of instructions: o) Doesn't work at the end of a page. o) The second (and third etc) of the instructions still has to be translated, but still, common instructions can be combined. x) Keeping track of the number of executed instructions: Any instruction which changes the execution flow, or at the end of a page, or if an exception occurs, can check what the program counter is and compare it to the last value where the number of instructions was known. This works for fixed-size ISAs such as MIPS, anyway. ------------------------------------------------------------------------------- A variant for non-fixed-size-ISAs: o) The instr_call struct can contain a field which says how many bytes long the instruction was. struct instr_call *ic = cpu->next_instr_call; cpu->next_instr_call ++; ic->f(cpu, ic); must then be changed into struct instr_call *ic = cpu->next_instr_call; cpu->next_instr_call += id->instruction_length; ic->f(cpu, ic); At the end of the page, there must be more than one "end of page" entry, to account for the various possible instruction lengths. o) There has to be one translation entry for each _byte_ of code, not just for each possible instruction (say, every fourth byte for MIPS). (Another example would be m68k, where there would have to be a translation entry for every other byte of code.) ------------------------------------------------------------------------------- An alternative would be to have the main run-loop look like this: (see new_test_2.c) for (;;) { ic = cpu->next_instr_call++; ic->f(ic); ic = cpu->next_instr_call++; ic->f(ic); /* .. */ } if ic contains a pointer to the cpu struct (for those functions that need it; a simple "add" doesn't, for example). This results in just 5 (!) instructions overhead per emulated instruction, plus the code for the specific instruction (for example 8 for a simple "add"). objdump -d shows that the main run-loop looks like this on i386, if no cpu struct argument is used: 080485ba : 80485ba: 53 push %ebx 80485bb: 83 ec 08 sub $0x8,%esp 80485be: 8b 5c 24 10 mov 0x10(%esp,1),%ebx 80485c2: 8b 43 08 mov 0x8(%ebx),%eax ! 1 80485c5: 8d 48 14 lea 0x14(%eax),%ecx ! 2 80485c8: 89 4b 08 mov %ecx,0x8(%ebx) ! 3 80485cb: 89 04 24 mov %eax,(%esp,1) ! 4 80485ce: ff 10 call *(%eax) ! 5 where the last 5 lines are then repeated for each inlined instruction call. However, initial experiments on both Alpha and i386 hosts indicate that this is _slower_ in practice than ic->f(cpu, ic), even when cpu is not used. So, since passing along cpu produces faster code, and since cpu often _will_ be used, then the first choice is better. ------------------------------------------------------------------------------- 2007-04-21: Interestingly, this approach is very similar to what is used in a paper from 1990, by Robert Bedichek. "Some Efficient Architecture Simlation Techniques". http://xsim.com/papers/bedichek90some.pdf The paper details the same solution to intermediate representation that I use in GXemul, including the end-of-page stuff, and to-be-translated instruction. ------------------------------------------------------------------------------- gxemul-0.6.1/experiments/ic_statistics.c000644 001750 001750 00000011614 13402411502 020604 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2006 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * $Id: ic_statistics.c,v 1.4 2006-07-15 09:44:13 debug Exp $ * * This program is not optimized for speed, but it should work. * * Run gxemul -s i:log.txt blahblahblah, and then * * for a in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do \ * ./ic_statistics log.txt $a |sort -n > statistics.$a.txt; done */ #include #include #include #include #include struct entry { uint64_t *ptrs; long long count; }; struct entry *entries = NULL; int n_entries = 0; size_t *cache_s = NULL; char **cache_symbol = NULL; int n_cached_symbols = 0; char *cached_size_t_to_symbol(uint64_t s) { int i = 0; FILE *q; char tmp[200]; char *urk, *urk2; while (i < n_cached_symbols) { if (cache_s[i] == s) return cache_symbol[i]; i++; } n_cached_symbols ++; cache_s = realloc(cache_s, sizeof(size_t) * n_cached_symbols); cache_symbol = realloc(cache_symbol, sizeof(char *) * n_cached_symbols); cache_s[n_cached_symbols - 1] = s; snprintf(tmp, sizeof(tmp), "nm ../gxemul | grep %"PRIx64, s); q = popen(tmp, "r"); if (q == NULL) { perror("popen()"); exit(1); } fgets(tmp, sizeof(tmp), q); pclose(q); while (tmp[0] && (tmp[strlen(tmp)-1] == '\n' || tmp[strlen(tmp)-1] == '\r')) tmp[strlen(tmp)-1] = '\0'; urk = strrchr(tmp, ' '); if (urk == NULL) urk = tmp; else urk ++; urk2 = strstr(urk, "instr_"); if (urk2 != NULL) urk = urk2 + 6; cache_symbol[n_cached_symbols - 1] = strdup(urk); } void print_all(int n) { int i = 0; while (i < n_entries) { uint64_t *pp = entries[i].ptrs; int j = 0; printf("%lli\t", (long long)entries[i].count); while (j < n) { uint64_t s = pp[j]; if (j > 0) printf(", "); printf("%s", cached_size_t_to_symbol(s)); j++; } printf("\n"); i++; } } void add_count(uint64_t *icpointers, int n) { int i = 0; /* Scan all existing entries. */ while (i < n_entries) { if (memcmp(icpointers, entries[i].ptrs, sizeof(uint64_t) * n) == 0) { entries[i].count ++; return; } i++; } /* Add new entry: */ n_entries ++; entries = realloc(entries, sizeof(struct entry) * n_entries); entries[n_entries-1].ptrs = malloc(sizeof(void *) * n); memcpy(entries[n_entries-1].ptrs, &icpointers[0], n * sizeof(uint64_t)); entries[n_entries-1].count = 1; } void try_len(FILE *f, int len) { uint64_t *icpointers; off_t off, n_read = 0; icpointers = malloc(sizeof(uint64_t) * len); fseek(f, 0, SEEK_END); off = ftello(f); fseek(f, 0, SEEK_SET); while (!feof(f)) { static long long yo = 0; char buf[100]; yo ++; if ((yo & 0xfffff) == 0) { fprintf(stderr, "[ len=%i, %i%% done ]\n", len, 100 * yo * sizeof(void *) / off); } /* Make room for next icpointer value: */ if (len > 1) memmove(&icpointers[0], &icpointers[1], (len-1) * sizeof(uint64_t)); /* Read one value into icpointers[len-1]: */ fgets(buf, sizeof(buf), f); icpointers[len-1] = strtoull(buf, NULL, 0); n_read ++; if (n_read >= len) add_count(&icpointers[0], len); } free(icpointers); } int main(int argc, char *argv[]) { FILE *f; int len = 1; if (argc < 3) { fprintf(stderr, "usage: %s input.log n\n", argv[0]); exit(1); } f = fopen(argv[1], "r"); if (f == NULL) { perror(argv[1]); exit(1); } len = atoi(argv[2]); if (len < 1) { fprintf(stderr, "bad len\n"); exit(1); } try_len(f, len); print_all(len); return 0; } gxemul-0.6.1/experiments/bintrans_eval.c000644 001750 001750 00000004777 13402411502 020602 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * $Id: bintrans_eval.c,v 1.3 2005-01-09 01:55:27 debug Exp $ * * Bintrans algorithm evaluation. */ #include #include #include #include #include int64_t n_instrs = 0; int64_t time_used = 0; int64_t cost_of_interpreted_instruction = 500; int64_t cost_of_native_instruction = 5; int64_t cost_of_translation = 10000; void print_stats(void) { printf("%10lli instructions, time used: %lli\n", (long long)n_instrs, (long long)time_used); } int main(int argc, char *argv[]) { FILE *f; int ticks = 0; uint64_t addr; char buf[40]; if (argc < 2) { fprintf(stderr, "usage: %s inputfile\n", argv[0]); exit(1); } f = fopen(argv[1], "r"); if (f == NULL) { perror(argv[1]); exit(1); } while (!feof(f)) { buf[2] = buf[sizeof(buf)-1] = 0; fgets(buf + 2, sizeof(buf) - 2, f); addr = strtoull(buf, NULL, 0); n_instrs ++; /* TODO */ if ((++ ticks) == 100000) { ticks = 0; print_stats(); } } print_stats(); return 0; } gxemul-0.6.1/experiments/hex_to_bin.c000644 001750 001750 00000002716 13402411502 020060 0ustar00debugdebug000000 000000 /* * $Id: hex_to_bin.c,v 1.2 2007-05-11 07:51:56 debug Exp $ * * Quick hack to convert .hex files (such as the AVR Hello World program at * http://www.tfs.net/~petek/atmel/hiworld/hiworld.hex) into raw binaries. * * E.g. hex_to_bin hiworld.hex hiworld.bin * * and then: gxemul -E bareavr ..... 0:hiworld.bin * * Note: The experimental AVR emulation was removed from GXemul at 20070511. * Use versions prior to this versions if you want to play with AVR * emulation. */ #include int fromhex(char *p) { char c1 = p[0], c2 = p[1]; if (c1 >= '0' && c1 <= '9') c1 -= '0'; else if (c1 >= 'A' && c1 <= 'F') c1 = c1 - 'A' + 10; if (c2 >= '0' && c2 <= '9') c2 -= '0'; else if (c2 >= 'A' && c2 <= 'F') c2 = c2 - 'A' + 10; return c1 * 16 + c2; } int hex_to_bin(char *fname, char *outname) { FILE *f = fopen(fname, "r"); FILE *fout = fopen(outname, "w"); while (!feof(f)) { char s[80]; int nbytes, i, addr; s[0] = '\0'; fgets(s, sizeof(s), f); if (s[0] == 0) break; if (s[0] != ':') continue; nbytes = fromhex(s+1); addr = fromhex(s+3) * 256 + fromhex(s+5); fseek(fout, addr, SEEK_SET); for (i=0; i> .index echo "$B"|cut -d : -f 2- >> .index fi done gxemul-0.6.1/experiments/try_runlen.c000644 001750 001750 00000005336 13402411502 020144 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * $Id: try_runlen.c,v 1.4 2005-01-09 01:55:27 debug Exp $ * * Run length test. * This program takes a text file of the following format as input: * * 8003005c * 80030060 * 80030064 * 80030068 * 8003006c * 80030070 * 8013f740 * 8013f744 * 8013f748 * 8013f74c * * and returns the number of successive instructions in a block. Using * the example above, the output would be: * * 6 * 4 */ #include #include #include #include int main(int argc, char *argv[]) { FILE *f; long long addr = 1; /* Magic number 1 */ long long newaddr; char buf[100]; int count; if (argc < 2) { fprintf(stderr, "usage: %s inputfile\n", argv[0]); exit(1); } f = fopen(argv[1], "r"); if (f == NULL) { perror(argv[1]); exit(1); } count = 0; buf[0] = '0'; buf[1] = 'x'; while (!feof(f)) { buf[2] = buf[sizeof(buf)-1] = 0; fgets(buf + 2, sizeof(buf) - 2, f); /* printf("buf = '%s'\n", buf); */ if (strlen(buf) < 4) break; newaddr = strtoull(buf, NULL, 0); if (addr != 1 && newaddr != addr + 4) { printf("%i\n", count); count = 0; } count ++; addr = newaddr; } /* Print the length of the last block: */ printf("%i\n", count); return 0; } gxemul-0.6.1/experiments/cp_removeblocks.c000644 001750 001750 00000010152 13402411502 021110 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * $Id: cp_removeblocks.c,v 1.11 2005-01-09 01:55:27 debug Exp $ * * This program copies a file, but only those blocks that are not zero- * filled. Typical usage would be if you have a harddisk image stored * as a file, which has all its zeroed blocks explicitly saved on disk, * and would like to save space. * * Example: You download a file called diskimage.gz from somewhere, * run gunzip on it, and the resulting file diskimage is * 1 GB large. ls -l reports the file size as 1 GB, and * so does 'du -k diskimage'. If a lot of the space used * by diskimage is actually zeroes, those parts do not need * to actually be saved. By running this program on diskimage: * * ./cp_removeblocks diskimage diskimage_compact * * you will get a file with the same functionality, but possibly * using less disk space. ('ls -l diskimage_compact' should * return the same size as for diskimage, but 'du -k' will * print only how many kb the file takes up on your disk.) * * You don't even need to gunzip the file to be 1 GB first, * you can pipe it through cp_removeblocks directly. * * gunzip -c file.img.gz | ./cp_removeblocks - file.img */ #include #include #include #include #define BSIZE 512 int main(int argc, char *argv[]) { FILE *f1, *f2; unsigned char buf[BSIZE]; off_t len; off_t in_pos = 0; int i, res, wrote_last = 0; if (argc != 3) { fprintf(stderr, "usage: %s infile outfile\n", argv[0]); fprintf(stderr, "if infile is \"-\", then stdin is used.\n"); fprintf(stderr, "if outfile is \"-\", then stdout is used.\n"); exit(1); } if (strcmp(argv[1], "-") == 0) f1 = stdin; else f1 = fopen(argv[1], "r"); if (f1 == NULL) { perror(argv[1]); exit(1); } if (strcmp(argv[2], "-") == 0) f2 = stdout; else f2 = fopen(argv[2], "w"); if (f2 == NULL) { perror(argv[2]); exit(1); } while (!feof(f1)) { len = fread(buf, 1, BSIZE, f1); if (len > 0) { /* Check for data in buf: */ for (i=0; i 0) { res = fseeko(f2, in_pos - 1, SEEK_SET); if (res != 0) perror("fseeko(f2)"); buf[0] = '\0'; fwrite(&buf[0], 1, 1, f2); } fclose(f1); fclose(f2); return 0; } gxemul-0.6.1/experiments/new_test_loadstore_b.c000644 001750 001750 00000002441 13402411502 022142 0ustar00debugdebug000000 000000 /* * $Id: new_test_loadstore_b.c,v 1.4 2005-07-22 20:01:25 debug Exp $ * * Experimenting with dynamic-but-not-binary-translation load/store. */ #include #include #include "new_test_loadstore.h" /* These are in new_test_loadstore_a.c: */ void x(struct cpu *cpu, struct ic *ic); void y(struct cpu *cpu, struct ic *ic); int main(int argc, char *argv[]) { int x1 = 72, x2 = 1234; struct ic ic = { 0, &x1, 5, &x2 }; struct ic ic2 = { 0, &x2, 9, &x1 }; struct cpu cpu; int i; char *page = malloc(4096); #ifdef AAA /* cpu.table0 = malloc(sizeof(void *) * 1048576); */ for (i=0; i<1048576; i++) cpu.table0[i] = page; #else cpu.table0[0] = malloc(sizeof(void *) * 2 * 1024); for (i=0; i<1024; i++) { cpu.table0[0][i*2+0] = page; cpu.table0[0][i*2+1] = page; } #endif printf("A: 100 Million loads + 100 Million stores\n"); printf("y=%i\n", x2); for (i=0; i<10000000; i++) { x(&cpu, &ic); y(&cpu, &ic2); x(&cpu, &ic); y(&cpu, &ic2); x(&cpu, &ic); y(&cpu, &ic2); x(&cpu, &ic); y(&cpu, &ic2); x(&cpu, &ic); y(&cpu, &ic2); x(&cpu, &ic); y(&cpu, &ic2); x(&cpu, &ic); y(&cpu, &ic2); x(&cpu, &ic); y(&cpu, &ic2); x(&cpu, &ic); y(&cpu, &ic2); x(&cpu, &ic); y(&cpu, &ic2); } printf("y=%i\n", x2); printf("B\n"); return 0; } gxemul-0.6.1/experiments/new_test_2.c000644 001750 001750 00000003723 13402411502 020012 0ustar00debugdebug000000 000000 /* NOTE: This is actually _slower_ than new_test_1.c */ #include #include typedef int int32_t; struct cpu; struct instr_call { void (*f)(struct instr_call *ic); struct cpu *cpu; /* int instr_len; */ void *arg[3]; }; struct cpu { void *curpage; int nloops; struct instr_call *next_instr_call; }; void r(struct cpu *cpu) { struct instr_call *ic; for (;;) { ic = cpu->next_instr_call++; ic->f(ic); ic = cpu->next_instr_call++; ic->f(ic); ic = cpu->next_instr_call++; ic->f(ic); ic = cpu->next_instr_call++; ic->f(ic); ic = cpu->next_instr_call++; ic->f(ic); ic = cpu->next_instr_call++; ic->f(ic); ic = cpu->next_instr_call++; ic->f(ic); ic = cpu->next_instr_call++; ic->f(ic); } } void f_add(struct instr_call *ic) { int32_t *a = (int32_t *) ic->arg[0]; int32_t *b = (int32_t *) ic->arg[1]; int32_t *c = (int32_t *) ic->arg[2]; *a = (*b) + (*c); } void f_end(struct instr_call *ic) { struct cpu *cpu = ic->cpu; cpu->next_instr_call = cpu->curpage; cpu->nloops--; if (cpu->nloops > 0) return; /* printf(" %i", cpu->nloops); fflush(stdout); */ printf("Exiting correctly\n"); exit(1); } int main(int argc, char *argv[]) { int32_t tmp_a, tmp_b, tmp_c; struct instr_call *call_array; int i, ncalls; struct cpu *cpu = malloc(sizeof(struct cpu)); if (argc <= 1) { fprintf(stderr, "usage: %s n\n", argv[0]); exit(1); } cpu->nloops = atoi(argv[1]); ncalls = 1024 + 1; /* Fill a range of nonsense calls: */ call_array = malloc(sizeof(struct instr_call) * ncalls); cpu->curpage = call_array; printf("ncalls = %i\n", ncalls); for (i=0; inext_instr_call = &call_array[0]; r(cpu); printf("ERROR!\n"); return 0; } gxemul-0.6.1/experiments/sgiprom_to_bin.c000644 001750 001750 00000010134 13402411502 020745 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2005 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * $Id: sgiprom_to_bin.c,v 1.5 2005-02-21 07:18:10 debug Exp $ * * sgiprom_to_bin.c * * This program takes a textfile containing a SGI PROM memory dump of * the following format: * * >> dump -b 0xBFC00000:0xBFCF0000 * 0xbfc00000: b f0 0 f0 0 0 0 0 * 0xbfc00008: b f0 1 f6 0 0 0 0 * SAME * 0xbfc00200: b f0 3 c9 0 0 0 0 * 0xbfc00208: b f0 1 f6 0 0 0 0 * SAME * 0xbfc00280: b f0 3 cb 0 0 0 0 * .. * * and turns it into a binary image. Input is read from stdin. */ #include #include #include #include #define MAX 200 int main(int argc, char *argv[]) { FILE *f; unsigned char previous_line[8]; int same_flag = 0; off_t same_start_offset = 0; if (argc < 2) { fprintf(stderr, "usage: %s output_filename\n", argv[0]); fprintf(stderr, "input is read from stdin\n"); exit(1); } f = fopen(argv[1], "w"); while (!feof(stdin)) { char s[MAX]; s[0] = 0; fgets(s, sizeof(s), stdin); while (s[0] == '\r') { memcpy(s, s+1, sizeof(s)-1); s[MAX-1] = '\0'; } /* 0xbfc00460: 24 5 0 10 0 5 28 c2 */ if (s[0] == '0' && s[10]==':') { unsigned long x; int i; x = strtol(s, NULL, 0); if (x < 0xbfc00000) { printf("x = 0x%08lx, less than 0xbfc00000. " "aborting\n", (long)x); exit(1); } x -= 0xbfc00000; if (same_flag) { /* * We should fill from same_start_offset to * just before x, using previous_line data. */ off_t ofs; printf("same_flag set, filling until just " "before 0x%08lx\n", (long)x); fseek(f, same_start_offset, SEEK_SET); for (ofs = same_start_offset; ofs < x; ofs += 8) { fwrite(previous_line, 1, sizeof(previous_line), f); } same_flag = 0; } printf("x = 0x%08lx\n", (long)x); fseek(f, x, SEEK_SET); for (i=0; i= '0' && d1<='9') d1 -= '0'; else d1 = d1 - 'a' + 10; if (d2 >= '0' && d2<='9') d2 -= '0'; else d2 = d2 - 'a' + 10; d1 = d1*16 + d2; printf(" %02x", d1); fprintf(f, "%c", d1); previous_line[i] = d1; } printf("\n"); } /* "SAME": */ if (s[0] == 'S' && s[1] == 'A') { /* * This should produce "same" output until the * next normal "0xbfc.." line. */ same_flag = 1; same_start_offset = ftell(f); } } fclose(f); return 0; } gxemul-0.6.1/experiments/native_cc_ld_test.i000644 001750 001750 00000007020 13402411502 021412 0ustar00debugdebug000000 000000 /* Idea 2007-06-06 on how to use a C compiler + linker as a native code generation backend. gcc native_cc_ld_test.i -Wall -O3 -fomit-frame-pointer -fpeephole -fno-builtin -c ld native_cc_ld_test.o -o native_cc_ld_test -e f -Ttext 0x1234560 objdump -d native_cc_ld_test The text part of that binary should then be easy to just copy directly into the translation cache. (The address 0x12340040 in the example is where I want the code fragment to end up in the cache.) It might even be possible to only do the cc step, and skip the ld step, if the code is position-independent. A couple of tricks are used: o) Note that the cpu and ic structs only contain just enough to mimic the cpu and ic structs in the emulator itself. The dummy fillers are there to make sure that the interesting fields (reg, next_ic, and ninstrs) end up at the correct offsets. o) No #include directives are needed, if reasonable types are used (int, unsigned long long, etc). These will have to be detected before running the compiler. Also, this makes it possible to skip the preprocessor, i.e. output a .i file instead of a .c file. o) Values in the cpu struct that are used are first loaded into local variables, used, and then stored back before any kind of return path (e.g. in a generic load/store, or at the end of the function, or on a non-samepage branch). o) Delay slots are handled by setting a "condition", then executing the next instruction, then branching. TODO: How about instructions in delay slots which may cause exceptions? o) Samepage-branches can be implemented using C labels (goto). Good: o) Somewhat portable. The same mechanism could be used for amd64, Alpha, MIPS, and most likely several other host architectures. o) A good optimizing compiler will generate very good code, probably much better code than I would be able to generate manually. Bad: o) Very high overhead. Calling cc + ld on my laptop takes 1/30th of a second, which is quite high. On my older Alpha workstation, it takes about 1/10th of a second. This means that the mechanism which desides whether or not to actually natively translate a block of code must take into account how much the overhead is vs how much time will be saved etc. */ struct cpu; struct ic { void (*f)(struct cpu *, struct ic*); long arg[3]; }; struct cpu { char dummy[800]; int reg[32]; char dummy2[80]; struct ic* next_ic; char dummy3[120]; int ninstrs; void *host_load[1048576]; void *host_store[1048576]; }; void f(struct cpu *cpu, struct ic *ic) { int cond0; void (*g0)(struct cpu *, struct ic *) = (void (*)(struct cpu *, struct ic *)) 0x123801234560ULL; unsigned int r2 = cpu->reg[2]; unsigned int r3 = cpu->reg[3]; unsigned int r4 = cpu->reg[4]; unsigned int r9 = cpu->reg[9]; unsigned int addr0; unsigned char *page0; unsigned int ninstrs = cpu->ninstrs; ninstrs --; L0: /* st.b r3,r0,r2 */ addr0 = r2; page0 = (unsigned char *) cpu->host_store[addr0 >> 12]; if (page0 == (void *)0) { cpu->reg[2] = r2; cpu->reg[3] = r3; cpu->reg[4] = r4; cpu->reg[9] = r9; cpu->ninstrs = ninstrs; g0(cpu, ic + 0); return; } page0[addr0 & 0xfff] = r3; ninstrs ++; /* addu r2,r2,1 */ r2 = r2 + 1; ninstrs ++; /* or r9,r0,r4 */ r9 = r4; ninstrs ++; /* bcnd.n gt0,r9,L0 */ /* subu r4, r4, 1 */ cond0 = (int)r9 > 0; r4 = r4 - 1; ninstrs += 2; if (cond0) goto L0; cpu->reg[2] = r2; cpu->reg[3] = r3; cpu->reg[4] = r4; cpu->reg[9] = r9; cpu->ninstrs = ninstrs; cpu->next_ic = ic + 5; } gxemul-0.6.1/experiments/new_test_x.c000644 001750 001750 00000006471 13402411502 020123 0ustar00debugdebug000000 000000 #include #include #include #include #include /* #define N_CALLS_PER_PAGE 1024 */ #define N_CALLS_PER_PAGE 128 #define MHZ 533 struct cpu; struct instr_call { void (*f)(struct cpu *cpu, struct instr_call *ic); /* int instr_len; */ void *arg[3]; }; struct cpu { void *curpage; int orig_nloops; int nloops; struct instr_call *next_instr_call; }; void r(struct cpu *cpu) { struct instr_call *ic; for (;;) { ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); } } void f_add(struct cpu *cpu, struct instr_call *ic) { #if 0 #if 0 int *a = (int *) ic->arg[0]; int *b = (int *) ic->arg[1]; int *c = (int *) ic->arg[2]; *a = (*b) + (*c); #else int *a = (int *) ic->arg[0]; int *b = (int *) ic->arg[1]; int *c = (int *) ic->arg[2]; int *d, *e, *f; ic = cpu->next_instr_call++; d = (int *) ic->arg[0]; e = (int *) ic->arg[1]; f = (int *) ic->arg[2]; *a = (*b) + (*c); *d = (*e) + (*f); #endif #endif } void f_sub(struct cpu *cpu, struct instr_call *ic) { int *a = (int *) ic->arg[0]; int *b = (int *) ic->arg[1]; int *c = (int *) ic->arg[2]; *a = (*b) - (*c); } void f_and(struct cpu *cpu, struct instr_call *ic) { int *a = (int *) ic->arg[0]; int *b = (int *) ic->arg[1]; int *c = (int *) ic->arg[2]; *a = (*b) & (*c); } void f_or(struct cpu *cpu, struct instr_call *ic) { int *a = (int *) ic->arg[0]; int *b = (int *) ic->arg[1]; int *c = (int *) ic->arg[2]; *a = (*b) | (*c); } void f_end(struct cpu *cpu, struct instr_call *ic) { struct rusage rusage; double t, mips; cpu->nloops--; if (cpu->nloops > 0) { cpu->next_instr_call = cpu->curpage; return; } getrusage(RUSAGE_SELF, &rusage); t = rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec / 1000000.0; mips = (float)(N_CALLS_PER_PAGE * cpu->orig_nloops) / t / 1000000.0; printf("%.2f user seconds = %.1f MIPS. %.1f cycles/emulated " "instruction on a %i MHz machine\n", (float)t, (float)mips, (float)MHZ/mips, MHZ); exit(1); } int main(int argc, char *argv[]) { int32_t tmp_a, tmp_b, tmp_c; struct instr_call *call_array; int i, ncalls; struct cpu *cpu = malloc(sizeof(struct cpu)); if (argc <= 1) { fprintf(stderr, "usage: %s n\n", argv[0]); exit(1); } cpu->orig_nloops = cpu->nloops = atoi(argv[1]); ncalls = N_CALLS_PER_PAGE + 1; /* Fill a range of nonsense calls: */ call_array = malloc(sizeof(struct instr_call) * ncalls); cpu->curpage = call_array; printf("ncalls = %i\n", ncalls); for (i=0; inext_instr_call = &call_array[0]; r(cpu); printf("ERROR!\n"); return 0; } gxemul-0.6.1/experiments/decprom_dump_txt_to_bin.c000644 001750 001750 00000006150 13402411502 022645 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2005 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * $Id: decprom_dump_txt_to_bin.c,v 1.4 2005-02-21 07:18:10 debug Exp $ * * decprom_dump_txt_to_bin.c * * This program takes a textfile containing a DECstation * PROM memory dump of the following format: * * bfc00000: 0x12345678 * bfc00004: 0x9a8a8a7f * and so on * * and turns it into a binary image (32-bit little-endian words -> bytes), * * 0x78 0x56 0x34 0x12 0x7f 0x8a ... * * To produce such a dump, hook up a serial terminal capable of capturing * data to a file, and enter the commands * * setenv more 0 * e -w 0xbfc00000:0xbfffffff * * at the DECstation's PROM prompt. */ #include #include int main(int argc, char *argv[]) { FILE *fin, *fout; char s[500]; if (argc != 3) { fprintf(stderr, "usage: %s dump.txt dump.bin\n", argv[0]); fprintf(stderr, "The resulting dump binary will be written" " to dump.bin\n"); exit(1); } fin = fopen(argv[1], "r"); if (fin == NULL) { perror(argv[1]); exit(1); } fout = fopen(argv[2], "w"); if (fout == NULL) { perror(argv[2]); exit(1); } while (!feof(fin)) { s[0] = 0; fgets(s, sizeof(s), fin); if (s[0]=='b' && s[1]=='f' && strlen(s)>15) { unsigned long addr = strtoul(s, NULL, 16); unsigned long data = strtoul(s + 12, NULL, 16); unsigned char obuf[4]; printf("addr = 0x%0l8x data = 0x%08lx\n", (long)addr, (long)data); addr -= 0xbfc00000L; obuf[0] = data & 255; obuf[1] = (data >> 8) & 255; obuf[2] = (data >> 16) & 255; obuf[3] = (data >> 24) & 255; fseek(fout, addr, SEEK_SET); fwrite(obuf, 1, 4, fout); } } fclose(fin); fclose(fout); return 0; } gxemul-0.6.1/experiments/new_test_loadstore_a.c000644 001750 001750 00000002006 13402411502 022136 0ustar00debugdebug000000 000000 /* * $Id: new_test_loadstore_a.c,v 1.3 2005-07-22 20:01:25 debug Exp $ * * Experimenting with dynamic-but-not-binary-translation load/store. * See new_test_loadstore_b.c for the main() function. */ #include "new_test_loadstore.h" static void inline general_store(struct cpu *cpu, struct ic *ic) { general_store(cpu, ic); } void x(struct cpu *cpu, struct ic *ic) { unsigned int addr = *ic->arg1; /* + ic->arg2; */ unsigned char **table1, *page; #ifdef AAA page = cpu->table0[addr >> 12]; #else table1 = cpu->table0[addr >> 22]; page = table1[((addr >> 12) & 1023)*2 + 1]; #endif if (page != 0) page[addr & 4095] = *(ic->arg3); else general_store(cpu, ic); } void y(struct cpu *cpu, struct ic *ic) { unsigned int addr = *ic->arg1; /* + ic->arg2; */ unsigned char **table1, *page; #ifdef AAA page = cpu->table0[addr >> 12]; #else table1 = cpu->table0[addr >> 22]; page = table1[((addr >> 12) & 1023)*2 + 0]; #endif if (page != 0) *(ic->arg3) = page[addr & 4095]; else general_store(cpu, ic); } gxemul-0.6.1/experiments/new_test_1.c000644 001750 001750 00000003655 13402411502 020015 0ustar00debugdebug000000 000000 #include #include typedef int int32_t; struct cpu; struct instr_call { void (*f)(struct cpu *cpu, struct instr_call *ic); /* int instr_len; */ void *arg[3]; }; struct cpu { void *curpage; int nloops; struct instr_call *next_instr_call; }; void r(struct cpu *cpu) { struct instr_call *ic; for (;;) { ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); ic = cpu->next_instr_call++; ic->f(cpu, ic); } } void f_add(struct cpu *cpu, struct instr_call *ic) { int32_t *a = (int32_t *) ic->arg[0]; int32_t *b = (int32_t *) ic->arg[1]; int32_t *c = (int32_t *) ic->arg[2]; *a = (*b) + (*c); } void f_end(struct cpu *cpu, struct instr_call *ic) { cpu->nloops--; if (cpu->nloops > 0) { cpu->next_instr_call = cpu->curpage; return; } /* printf(" %i", cpu->nloops); fflush(stdout); */ printf("Exiting correctly\n"); exit(1); } int main(int argc, char *argv[]) { int32_t tmp_a, tmp_b, tmp_c; struct instr_call *call_array; int i, ncalls; struct cpu *cpu = malloc(sizeof(struct cpu)); if (argc <= 1) { fprintf(stderr, "usage: %s n\n", argv[0]); exit(1); } cpu->nloops = atoi(argv[1]); ncalls = 1024 + 1; /* Fill a range of nonsense calls: */ call_array = malloc(sizeof(struct instr_call) * ncalls); cpu->curpage = call_array; printf("ncalls = %i\n", ncalls); for (i=0; inext_instr_call = &call_array[0]; r(cpu); printf("ERROR!\n"); return 0; } gxemul-0.6.1/src/net/000755 001750 001750 00000000000 13402411502 014602 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/file/000755 001750 001750 00000000000 13402411502 014733 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/devices/000755 001750 001750 00000000000 13402411502 015436 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/old_main/000755 001750 001750 00000000000 13402411502 015576 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/include/000755 001750 001750 00000000000 13402411502 015437 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/promemul/000755 001750 001750 00000000000 13402411502 015654 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/disk/000755 001750 001750 00000000000 13402411502 014746 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/console/000755 001750 001750 00000000000 13402411502 015456 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/README000644 001750 001750 00000001136 13402411502 014675 0ustar00debugdebug000000 000000 GXemul's source code contains a large portion of legacy code, and some new (better structured) code. NEW CODE -------- components main plugins ui SHARED ------ include LEGACY CODE (Should be removed as soon as it's been reimplemented) ------------------------------------------------------------------- console cpus (new cpus are in components/cpu/) debugger (corresponds to main/CommandInterpreter.cc) devices (corresponds to components/) disk file (new file loaders are in main/fileloaders/) machines (new machines are in components/machines/) net old_main promemul symbol gxemul-0.6.1/src/cpus/000755 001750 001750 00000000000 13402411502 014766 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/debugger/000755 001750 001750 00000000000 13402411502 015600 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/main/000755 001750 001750 00000000000 13402411502 014740 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/symbol/000755 001750 001750 00000000000 13402411502 015321 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/ui/000755 001750 001750 00000000000 13402411502 014431 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/components/000755 001750 001750 00000000000 13402411502 016201 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/Makefile.skel000644 001750 001750 00000003134 13402411502 016412 0ustar00debugdebug000000 000000 # # Makefile for GXemul src # all: do_include $(MAKE) the_rest the_rest: do_components do_console do_cpus do_debugger do_devices do_disk \ do_file do_machines do_main do_net do_old_main \ do_promemul do_symbol do_ui do_include: cd include; $(MAKE) do_components: cd components; $(MAKE) do_console: cd console; $(MAKE) do_cpus: cd cpus; $(MAKE) do_debugger: cd debugger; $(MAKE) do_devices: cd devices; $(MAKE) do_disk: cd disk; $(MAKE) do_file: cd file; $(MAKE) do_machines: cd machines; $(MAKE) do_main: cd main; $(MAKE) do_net: cd net; $(MAKE) do_old_main: cd old_main; $(MAKE) do_promemul: cd promemul; $(MAKE) do_symbol: cd symbol; $(MAKE) do_ui: cd ui; $(MAKE) $(OBJS): Makefile clean: rm -f $(OBJS) *core cd include; $(MAKE) clean cd components; $(MAKE) clean cd console; $(MAKE) clean cd cpus; $(MAKE) clean cd debugger; $(MAKE) clean cd devices; $(MAKE) clean cd disk; $(MAKE) clean cd file; $(MAKE) clean cd machines; $(MAKE) clean cd main; $(MAKE) clean cd net; $(MAKE) clean cd old_main; $(MAKE) clean cd promemul; $(MAKE) clean cd symbol; $(MAKE) clean cd ui; $(MAKE) clean clean_all: clean cd include; $(MAKE) clean_all cd components; $(MAKE) clean_all cd console; $(MAKE) clean_all cd cpus; $(MAKE) clean_all cd debugger; $(MAKE) clean_all cd devices; $(MAKE) clean_all cd disk; $(MAKE) clean_all cd file; $(MAKE) clean_all cd machines; $(MAKE) clean_all cd main; $(MAKE) clean_all cd net; $(MAKE) clean_all cd old_main; $(MAKE) clean_all cd promemul; $(MAKE) clean_all cd symbol; $(MAKE) clean_all cd ui; $(MAKE) clean_all rm -f Makefile gxemul-0.6.1/src/machines/000755 001750 001750 00000000000 13402411502 015603 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/machines/machine_qemu.cc000644 001750 001750 00000006421 13402411502 020550 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Machine mimicing QEMU's default MIPS emulation mode * * See e.g. http://fabrice.bellard.free.fr/qemu/mips-test-0.2.tar.gz */ #include #include #include #include "bus_isa.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" MACHINE_SETUP(qemu_mips) { char tmpstr[300]; machine->machine_name = strdup("QEMU MIPS"); cpu->byte_order = EMUL_BIG_ENDIAN; /* * An ISA bus, I/O ports at 0x14000000, memory at 0x10000000, * connected to MIPS irq 2: */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2", machine->path, machine->bootstrap_cpu); bus_isa_init(machine, tmpstr, BUS_ISA_IDE0 | BUS_ISA_IDE1, 0x14000000ULL, 0x10000000ULL); if (!machine->prom_emulation) return; /* * Registers at startup do not seem to be defined in QEMU, but * bootargs and memory size are placed just below 16 MB. * * Remember to start the emulator with options, e.g.: * * -o "console=ttyS0 root=/dev/ram rd_start=0x80800000 * rd_size=10000000 init=/bin/sh" */ store_string(cpu, (int32_t)(0x80000000 + 16*1048576 - 256), machine->boot_string_argument); store_32bit_word(cpu, (int32_t)(0x80000000 + 16*1048576 - 260), 0x12345678); store_32bit_word(cpu, (int32_t)(0x80000000 + 16*1048576 - 264), machine->physical_ram_in_mb * 1048576); } MACHINE_DEFAULT_CPU(qemu_mips) { /* QEMU emulates a MIPS32 rev 1, so 4Kc will do just fine. */ machine->cpu_name = strdup("4Kc"); } MACHINE_DEFAULT_RAM(qemu_mips) { machine->physical_ram_in_mb = 64; } MACHINE_REGISTER(qemu_mips) { MR_DEFAULT(qemu_mips, "QEMU MIPS", ARCH_MIPS, MACHINE_QEMU_MIPS); me->set_default_ram = machine_default_ram_qemu_mips; machine_entry_add_alias(me, "qemu_mips"); } gxemul-0.6.1/src/machines/machine.cc000644 001750 001750 00000054116 13402411502 017525 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Machine registry. */ #include #include #include #include #include #include #include "cpu.h" #include "device.h" #include "diskimage.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "settings.h" #include "symbol.h" /* This is initialized by machine_init(): */ struct machine_entry *first_machine_entry = NULL; /* * machine_new(): * * Returns a reasonably initialized struct machine. */ struct machine *machine_new(char *name, struct emul *emul, int id) { struct machine *m; CHECK_ALLOCATION(m = (struct machine *) malloc(sizeof(struct machine))); memset(m, 0, sizeof(struct machine)); /* Pointer back to the emul object that this machine belongs to: */ m->emul = emul; if (name != NULL) CHECK_ALLOCATION(m->name = strdup(name)); /* Full path, e.g. "machine[0]": */ CHECK_ALLOCATION(m->path = (char *) malloc(20)); snprintf(m->path, 20, "machine[%i]", id); /* Sane default values: */ m->serial_nr = 1; m->machine_type = MACHINE_NONE; m->machine_subtype = MACHINE_NONE; m->arch_pagesize = 4096; /* Should be overriden in emul.c for other pagesizes. */ m->prom_emulation = 1; m->allow_instruction_combinations = 1; m->byte_order_override = NO_BYTE_ORDER_OVERRIDE; m->boot_kernel_filename = strdup(""); m->boot_string_argument = NULL; m->x11_md.scaledown = 1; m->x11_md.scaleup = 1; m->n_gfx_cards = 1; symbol_init(&m->symbol_context); /* Settings: */ m->settings = settings_new(); settings_add(m->settings, "name", 0, SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING, (void *) &m->name); settings_add(m->settings, "serial_nr", 0, SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL, (void *) &m->serial_nr); settings_add(m->settings, "arch_pagesize", 0, SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL, (void *) &m->arch_pagesize); settings_add(m->settings, "prom_emulation", 0, SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *) &m->prom_emulation); settings_add(m->settings, "allow_instruction_combinations", 0, SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *) &m->allow_instruction_combinations); settings_add(m->settings, "n_gfx_cards", 0, SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL, (void *) &m->n_gfx_cards); settings_add(m->settings, "statistics_enabled", 1, SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *) &m->statistics.enabled); return m; } /* * machine_destroy(): * * Destroys a machine object. */ void machine_destroy(struct machine *machine) { int i; for (i=0; incpus; i++) cpu_destroy(machine->cpus[i]); // TODO: Memory leak; but it's ok, since the whole legacy thing should // be replaced anyway. // if (machine->name != NULL) // free(machine->name); if (machine->path != NULL) free(machine->path); /* Remove any remaining level-1 settings: */ settings_remove_all(machine->settings); settings_destroy(machine->settings); free(machine); } /* * machine_name_to_type(): * * Take a type and a subtype as strings, and convert them into numeric * values used internally throughout the code. * * Return value is 1 on success, 0 if there was no match. * Also, any errors/warnings are printed using fatal()/debug(). */ int machine_name_to_type(char *stype, char *ssubtype, int *type, int *subtype, int *arch) { struct machine_entry *me; int i, j, k, nmatches = 0; *type = MACHINE_NONE; *subtype = 0; /* Check stype, and optionally ssubtype: */ me = first_machine_entry; while (me != NULL) { for (i=0; in_aliases; i++) if (strcasecmp(me->aliases[i], stype) == 0) { /* Found a type: */ *type = me->machine_type; *arch = me->arch; if (me->n_subtypes == 0) return 1; /* Check for subtype: */ for (j=0; jn_subtypes; j++) for (k=0; ksubtype[j]->n_aliases; k++) if (strcasecmp(ssubtype, me->subtype[j]->aliases[k] ) == 0) { *subtype = me->subtype[ j]->machine_subtype; return 1; } fatal("Unknown subtype '%s' for emulation" " '%s'\n", ssubtype, stype); if (!ssubtype[0]) fatal("(Maybe you forgot the -e" " command line option?)\n"); exit(1); } me = me->next; } /* Not found? Then just check ssubtype: */ me = first_machine_entry; while (me != NULL) { if (me->n_subtypes == 0) { me = me->next; continue; } /* Check for subtype: */ for (j=0; jn_subtypes; j++) for (k=0; ksubtype[j]->n_aliases; k++) if (strcasecmp(ssubtype, me->subtype[j]-> aliases[k]) == 0) { *type = me->machine_type; *arch = me->arch; *subtype = me->subtype[j]-> machine_subtype; nmatches ++; } me = me->next; } switch (nmatches) { case 0: fatal("\nSorry, emulation \"%s\"", stype); if (ssubtype != NULL && ssubtype[0] != '\0') fatal(" (subtype \"%s\")", ssubtype); fatal(" is unknown.\n"); break; case 1: return 1; default:fatal("\nSorry, multiple matches for \"%s\"", stype); if (ssubtype != NULL && ssubtype[0] != '\0') fatal(" (subtype \"%s\")", ssubtype); fatal(".\n"); } *type = MACHINE_NONE; *subtype = 0; fatal("Use the -H command line option to get a list of " "available types and subtypes.\n\n"); return 0; } /* * machine_add_breakpoint_string(): * * Add a breakpoint string to the machine. Later (in emul.c) these will be * converted to actual breakpoints. */ void machine_add_breakpoint_string(struct machine *machine, char *str) { int n = machine->breakpoints.n + 1; CHECK_ALLOCATION(machine->breakpoints.string = (char **) realloc(machine->breakpoints.string, n * sizeof(char *))); CHECK_ALLOCATION(machine->breakpoints.addr = (uint64_t *) realloc(machine->breakpoints.addr, n * sizeof(uint64_t))); CHECK_ALLOCATION(machine->breakpoints.string[machine->breakpoints.n] = strdup(optarg)); machine->breakpoints.addr[machine->breakpoints.n] = 0; machine->breakpoints.n ++; } /* * machine_add_tickfunction(): * * Adds a tick function (a function called every now and then, depending on * clock cycle count) to a machine. * * If tickshift is non-zero, a tick will occur every (1 << tickshift) cycles. * This is used for the normal (fast dyntrans) emulation modes. * * If tickshift is zero, then this is a cycle-accurate tick function. * The hz value is used in this case. */ void machine_add_tickfunction(struct machine *machine, void (*func) (struct cpu *, void *), void *extra, int tickshift) { int n = machine->tick_functions.n_entries; CHECK_ALLOCATION(machine->tick_functions.ticks_till_next = (int *) realloc( machine->tick_functions.ticks_till_next, (n+1) * sizeof(int))); CHECK_ALLOCATION(machine->tick_functions.ticks_reset_value = (int *) realloc( machine->tick_functions.ticks_reset_value, (n+1) * sizeof(int))); CHECK_ALLOCATION(machine->tick_functions.f = (void (**)(cpu*,void*)) realloc( machine->tick_functions.f, (n+1) * sizeof(void *))); CHECK_ALLOCATION(machine->tick_functions.extra = (void **) realloc( machine->tick_functions.extra, (n+1) * sizeof(void *))); /* * The dyntrans subsystem wants to run code in relatively * large chunks without checking for external interrupts; * too low tickshifts are not allowed. */ if (tickshift < N_SAFE_DYNTRANS_LIMIT_SHIFT) { fatal("ERROR! tickshift = %i, less than " "N_SAFE_DYNTRANS_LIMIT_SHIFT (%i)\n", tickshift, N_SAFE_DYNTRANS_LIMIT_SHIFT); exit(1); } machine->tick_functions.ticks_till_next[n] = 0; machine->tick_functions.ticks_reset_value[n] = 1 << tickshift; machine->tick_functions.f[n] = func; machine->tick_functions.extra[n] = extra; machine->tick_functions.n_entries = n + 1; } /* * machine_statistics_init(): * * Initialize the parts of a machine struct that deal with instruction * statistics gathering. * * Note: The fname argument contains "flags:filename". */ void machine_statistics_init(struct machine *machine, char *fname) { int n_fields = 0; char *pcolon = fname; const char *mode = "a"; /* Append by default */ machine->allow_instruction_combinations = 0; if (machine->statistics.fields != NULL) { fprintf(stderr, "Only one -s option is allowed.\n"); exit(1); } machine->statistics.enabled = 1; CHECK_ALLOCATION(machine->statistics.fields = (char *) malloc(1)); machine->statistics.fields[0] = '\0'; while (*pcolon && *pcolon != ':') pcolon ++; if (*pcolon != ':') { fprintf(stderr, "The syntax for the -s option is: " "-s flags:filename\nYou omitted the flags. Run g" "xemul -h for a list of available flags.\n"); exit(1); } while (*fname != ':') { switch (*fname) { /* Type flags: */ case 'v': case 'i': case 'p': CHECK_ALLOCATION(machine->statistics.fields = (char *) realloc( machine->statistics.fields, strlen( machine->statistics.fields) + 2)); machine->statistics.fields[n_fields ++] = *fname; machine->statistics.fields[n_fields] = '\0'; break; /* Optional flags: */ case 'o': mode = "w"; break; case 'd': machine->statistics.enabled = 0; break; default:fprintf(stderr, "Unknown flag '%c' used with the" " -s option. Aborting.\n", *fname); exit(1); } fname ++; } fname ++; /* point to the filename after the colon */ CHECK_ALLOCATION(machine->statistics.filename = strdup(fname)); machine->statistics.file = fopen(machine->statistics.filename, mode); } /* * machine_dumpinfo(): * * Dumps info about a machine in some kind of readable format. (Used by * the 'machine' debugger command.) */ void machine_dumpinfo(struct machine *m) { int i; debug("serial nr: %i", m->serial_nr); if (m->nr_of_nics > 0) debug(" (nr of NICs: %i)", m->nr_of_nics); debug("\n"); debug("memory: %i MB", m->physical_ram_in_mb); if (m->memory_offset_in_mb != 0) debug(" (offset by %i MB)", m->memory_offset_in_mb); if (m->random_mem_contents) debug(", randomized contents"); debug("\n"); if (!m->prom_emulation) debug("PROM emulation disabled\n"); for (i=0; incpus; i++) cpu_dumpinfo(m, m->cpus[i]); if (m->ncpus > 1) debug("Bootstrap cpu is nr %i\n", m->bootstrap_cpu); if (m->slow_serial_interrupts_hack_for_linux) debug("Using slow_serial_interrupts_hack_for_linux\n"); if (m->x11_md.in_use) { debug("Using X11"); if (m->x11_md.scaledown > 1) debug(", scaledown %i", m->x11_md.scaledown); if (m->x11_md.scaleup > 1) debug(", scaleup %i", m->x11_md.scaleup); if (m->x11_md.n_display_names > 0) { for (i=0; ix11_md.n_display_names; i++) { debug(i? ", " : " ("); debug("\"%s\"", m->x11_md.display_names[i]); } debug(")"); } debug("\n"); } diskimage_dump_info(m); if (m->force_netboot) debug("Forced netboot\n"); } /* * machine_setup(): * * This function initializes memory, registers, and/or devices * required by specific machine emulations. */ void machine_setup(struct machine *machine) { struct memory *mem; struct machine_entry *me; /* Abreviation: :-) */ struct cpu *cpu = machine->cpus[machine->bootstrap_cpu]; machine->bootdev_id = diskimage_bootdev(machine, &machine->bootdev_type); mem = cpu->mem; machine->machine_name = NULL; /* TODO: Move this somewhere else? */ if (machine->boot_string_argument == NULL) { switch (machine->machine_type) { case MACHINE_ARC: machine->boot_string_argument = strdup("-aN"); break; case MACHINE_CATS: machine->boot_string_argument = strdup("-A"); break; case MACHINE_PMAX: machine->boot_string_argument = strdup("-a"); break; default: /* Important, because boot_string_argument should not be set to NULL: */ machine->boot_string_argument = strdup(""); } } /* * If the machine has a setup function in src/machines/machine_*.c * then use that one, otherwise use the old hardcoded stuff here: */ me = first_machine_entry; while (me != NULL) { if (machine->machine_type == me->machine_type && me->setup != NULL) { me->setup(machine, cpu); break; } me = me->next; } if (me == NULL) { fatal("Unknown emulation type %i\n", machine->machine_type); exit(1); } if (machine->machine_name != NULL) debug("machine: %s", machine->machine_name); if (machine->emulated_hz > 0) debug(" (%.2f MHz)", (float)machine->emulated_hz / 1000000); debug("\n"); if (machine->bootstr != NULL) { debug("bootstring%s: %s", (machine->bootarg!=NULL && strlen(machine->bootarg) >= 1)? "(+bootarg)" : "", machine->bootstr); if (machine->bootarg != NULL && strlen(machine->bootarg) >= 1) debug(" %s", machine->bootarg); debug("\n"); } } /* * machine_memsize_fix(): * * Sets physical_ram_in_mb (if not already set), and memory_offset_in_mb, * depending on machine type. */ void machine_memsize_fix(struct machine *m) { if (m == NULL) { fatal("machine_defaultmemsize(): m == NULL?\n"); exit(1); } if (m->physical_ram_in_mb == 0) { struct machine_entry *me = first_machine_entry; while (me != NULL) { if (m->machine_type == me->machine_type && me->set_default_ram != NULL) { me->set_default_ram(m); break; } me = me->next; } } /* Special SGI memory offsets: (TODO: move this somewhere else) */ if (m->machine_type == MACHINE_SGI) { switch (m->machine_subtype) { case 20: case 22: case 24: case 26: m->memory_offset_in_mb = 128; break; case 28: case 30: m->memory_offset_in_mb = 512; break; } } if (m->physical_ram_in_mb == 0) m->physical_ram_in_mb = DEFAULT_RAM_IN_MB; } /* * machine_default_cputype(): * * Sets m->cpu_name, if it isn't already set, depending on the machine type. */ void machine_default_cputype(struct machine *m) { struct machine_entry *me; if (m == NULL) { fatal("machine_default_cputype(): m == NULL?\n"); exit(1); } /* Already set? Then return. */ if (m->cpu_name != NULL) return; me = first_machine_entry; while (me != NULL) { if (m->machine_type == me->machine_type && me->set_default_cpu != NULL) { me->set_default_cpu(m); break; } me = me->next; } if (m->cpu_name == NULL) { fprintf(stderr, "machine_default_cputype(): no default" " cpu for machine type %i subtype %i\n", m->machine_type, m->machine_subtype); exit(1); } } /*****************************************************************************/ /* * machine_run(): * * Run one or more instructions on all CPUs in this machine. (Usually, * around N_SAFE_DYNTRANS_LIMIT instructions will be run by the dyntrans * system.) * * Return value is 1 if any CPU in this machine is still running, * or 0 if all CPUs are stopped. */ int machine_run(struct machine *machine) { struct cpu **cpus = machine->cpus; int ncpus = machine->ncpus, cpu0instrs = 0, i, te; for (i=0; irunning) { int instrs_run = cpus[i]->run_instr(cpus[i]); if (i == 0) cpu0instrs += instrs_run; } } /* * Hardware 'ticks': (clocks, interrupt sources...) * * Here, cpu0instrs is the number of instructions executed on cpu0. * * TODO: This should be redesigned into some "mainbus" stuff instead! */ for (te=0; tetick_functions.n_entries; te++) { machine->tick_functions.ticks_till_next[te] -= cpu0instrs; if (machine->tick_functions.ticks_till_next[te] <= 0) { while (machine->tick_functions.ticks_till_next[te]<=0) { machine->tick_functions.ticks_till_next[te] += machine->tick_functions. ticks_reset_value[te]; } machine->tick_functions.f[te](cpus[0], machine->tick_functions.extra[te]); } } /* Is any CPU still alive? */ for (i=0; irunning) return 1; return 0; } /*****************************************************************************/ /* * machine_entry_new(): * * This function creates a new machine_entry struct, and fills it with some * valid data; it is up to the caller to add additional data that weren't * passed as arguments to this function, such as alias names and machine * subtypes. */ struct machine_entry *machine_entry_new(const char *name, int arch, int oldstyle_type) { struct machine_entry *me; CHECK_ALLOCATION(me = (struct machine_entry *) malloc(sizeof(struct machine_entry))); memset(me, 0, sizeof(struct machine_entry)); me->name = name; me->arch = arch; me->machine_type = oldstyle_type; me->n_aliases = 0; me->aliases = NULL; me->n_subtypes = 0; me->setup = NULL; return me; } /* * machine_entry_add_alias(): * * This function adds an "alias" to a machine entry. */ void machine_entry_add_alias(struct machine_entry *me, const char *name) { me->n_aliases ++; CHECK_ALLOCATION(me->aliases = (char **) realloc(me->aliases, sizeof(char *) * me->n_aliases)); me->aliases[me->n_aliases - 1] = strdup(name); } /* * machine_entry_add_subtype(): * * This function adds a subtype to a machine entry. The argument list after * oldstyle_subtype is a list of one or more char *, followed by NULL. E.g.: * * machine_entry_add_subtype(me, "Machine X", MACHINE_X, * "machine-x", "x", NULL); */ void machine_entry_add_subtype(struct machine_entry *me, const char *name, int oldstyle_subtype, ...) { va_list argp; struct machine_entry_subtype *mes; /* Allocate a new subtype struct: */ CHECK_ALLOCATION(mes = (struct machine_entry_subtype *) malloc(sizeof(struct machine_entry_subtype))); /* Add the subtype to the machine entry: */ me->n_subtypes ++; CHECK_ALLOCATION(me->subtype = (struct machine_entry_subtype **) realloc(me->subtype, sizeof(struct machine_entry_subtype *) * me->n_subtypes)); me->subtype[me->n_subtypes - 1] = mes; /* Fill the struct with subtype data: */ memset(mes, 0, sizeof(struct machine_entry_subtype)); mes->name = name; mes->machine_subtype = oldstyle_subtype; /* ... and all aliases: */ mes->n_aliases = 0; mes->aliases = NULL; va_start(argp, oldstyle_subtype); for (;;) { char *s = va_arg(argp, char *); if (s == NULL) break; mes->n_aliases ++; CHECK_ALLOCATION(mes->aliases = (char **) realloc(mes->aliases, sizeof(char *) * mes->n_aliases)); mes->aliases[mes->n_aliases - 1] = s; } va_end(argp); } /* * machine_entry_register(): * * Inserts a new machine_entry into the machine entries list. */ void machine_entry_register(struct machine_entry *me, int arch) { struct machine_entry *prev, *next; /* Only insert it if the architecture is implemented in this emulator configuration: */ if (cpu_family_ptr_by_number(arch) == NULL) return; prev = NULL; next = first_machine_entry; for (;;) { if (next == NULL) break; if (strcasecmp(me->name, next->name) < 0) break; prev = next; next = next->next; } if (prev != NULL) prev->next = me; else first_machine_entry = me; me->next = next; } /* * machine_list_available_types_and_cpus(): * * List all available machine types (for example when running the emulator * with just -H as command line argument). */ void machine_list_available_types_and_cpus(void) { struct machine_entry *me; int iadd = DEBUG_INDENTATION * 2; debug("Available CPU types:\n\n"); debug_indentation(iadd); cpu_list_available_types(); debug_indentation(-iadd); debug("\nMost of the CPU types are bogus, and not really implemented." " The main effect of\nselecting a specific CPU type is to choose " "what kind of 'id' it will have.\n\nAvailable machine types (with " "aliases) and their subtypes:\n\n"); debug_indentation(iadd); me = first_machine_entry; if (me == NULL) fatal("No machines defined!\n"); while (me != NULL) { int i, j, iadd2 = DEBUG_INDENTATION; debug("%s [%s] (", me->name, cpu_family_ptr_by_number(me->arch)->name); for (i=0; in_aliases; i++) debug("%s\"%s\"", i? ", " : "", me->aliases[i]); debug(")\n"); debug_indentation(iadd2); for (i=0; in_subtypes; i++) { struct machine_entry_subtype *mes; mes = me->subtype[i]; debug("- %s", mes->name); debug(" ("); for (j=0; jn_aliases; j++) debug("%s\"%s\"", j? ", " : "", mes->aliases[j]); debug(")\n"); } debug_indentation(-iadd2); me = me->next; } debug_indentation(-iadd); debug("\nMost of the machine types are bogus too. Please read the " "GXemul documentation\nfor information about which machine types " "that actually work. Use the alias\nwhen selecting a machine type " "or subtype, not the real name.\n"); debug("\n"); } /* * machine_init(): * * This function should be called before any other machine_*() function * is used. automachine_init() registers all machines in src/machines/. */ void machine_init(void) { if (first_machine_entry != NULL) { fatal("machine_init(): already called?\n"); exit(1); } automachine_init(); } gxemul-0.6.1/src/machines/machine_dreamcast.cc000644 001750 001750 00000017142 13402411502 021546 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2014 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SEGA Dreamcast */ #include #include #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" using namespace std; MACHINE_SETUP(dreamcast) { machine->machine_name = strdup("Dreamcast"); if (machine->emulated_hz == 0) machine->emulated_hz = 200000000; /* 50 MHz SH4 PCLOCK: */ machine->cpus[0]->cd.sh.pclock = 50000000; if (!machine->x11_md.in_use) fprintf(stderr, "-------------------------------------" "------------------------------------------\n" "\n WARNING! You are emulating a Dreamcast without -X." "\n You will miss graphical output!\n\n" "-------------------------------------" "------------------------------------------\n"); /* * Physical address layout on the Dreamcast, according to a * combination of sources: NetBSD sources, KallistiOS sources, * http://www.boob.co.uk/docs/Dreamcast_memory.txt, and * http://www.ludd.luth.se/~jlo/dc/memory.txt, and possibly some * others: * * 0x00000000 - 0x001fffff Boot ROM (2 MB) * 0x00200000 - 0x0021ffff Flash (128 KB) (perhaps multiple images afterwards?) * The bytes read by the Dreamcast PROM during * boot are: * Offset 0x1a000 .. 0x1a004 = 5 bytes debug/startup state? * hex digits (maybe limited to 0x30, 0x31, 0x32, or 0x33) * Offset 0x1a02d .. 0x1a037 = date/time values. * Offset 0x1a056 .. 0x1a05d = 8 bytes serial number / machine ID. * 0x005f0000 - ... ??? * 0x005f6800 - ... PowerVR2 DMA registers * 0x005f6900 - ... ASIC registers * 0x005f6c00 - ... Maple registers (controller ports) * 0x005f7000 - ... GDROM registers * 0x005f7400 - ... (G2 External DMA registers? Or GDROM?) * 0x005f74e4 - ... GDROM re-enable disabled drive (?) * 0x005f7800 - ... G2 External DMA registers * 0x005f7c00 - ... DMA (?) for some device (PVR related?) * 0x005f8000 - 0x005f9fff PVR registers (graphics) * 0x00600000 - 0x006007ff G2 bus: Modem * 0x00600400 - 0x0060047f G2 bus: LAN Adapter (MB86967) registers? * 0x00620000 - 0x00623fff G2 bus: Expansion port? * 0x00606900 - ... ??? * 0x00700000 - ... SPU registers (sound) * 0x00702800 - 0x007028ff ??? * 0x00702c00 - Cable select and AICA (?) (*3) * 0x00703xxx - ... AICA something * 0x00710000 - 0x00710007 RTC registers * 0x00800000 - 0x009fffff AICA (Sound) RAM (2 MB) (*4) * 0x01000000 - 0x01ffffff G2 bus or Parallel port registers? * 0x02000000 - ... CD-ROM port registers * 0x03000000 - 0x03ffffff G2 bus (?) * 0x04000000 - 0x047fffff Video RAM (*) (64-bit) * 0x05000000 - 0x057fffff Video RAM (8 MB) (32-bit) * 0x06000000 - 0x067fffff Video RAM (*) (64-bit) (copy) * 0x07000000 - 0x077fffff Video RAM (8 MB) (32-bit) (copy) * 0x0c000000 - 0x0cffffff RAM (16 MB) * 0x0e000000 - 0x0effffff Copy of RAM? (*2) * 0x10000000 - 0x107fffff Tile Accelerator: command area * 0x10800000 - 0x10ffffff Tile Accelerator: YUV data * 0x11000000 - 0x11ffffff Tile Accelerator: Texture data * 0x14000000 - 0x17ffffff G2 bus (?) * * (*1) = with banks 0 and 1 switched; 64-bit read/write access... * (*2) The "luftvarg" 4KB intro uses memory at paddr 0x0ef00000... * (*3) = See VOUTC in Linux' drivers/video/pvr2fb.c. * (*4) = It seems that ARM machine code is placed here. */ dev_ram_init(machine, 0x00000000, 2 * 1024 * 1024, DEV_RAM_RAM /* | DEV_RAM_TRACE_ALL_ACCESSES */, 0x0, "bootrom"); dev_ram_init(machine, 0x00200000, 128 * 1024, DEV_RAM_RAM /* | DEV_RAM_TRACE_ALL_ACCESSES */, 0x0, "flash"); dev_ram_init(machine, 0x00600004, 4, DEV_RAM_RAM, 0); dev_ram_init(machine, 0x00700000, 0x27ff, DEV_RAM_RAM, 0); dev_ram_init(machine, 0x00702800, 256, DEV_RAM_RAM, 0); dev_ram_init(machine, 0x00702c00, 4, DEV_RAM_RAM, 0); dev_ram_init(machine, 0x00703000, 0x1fff, DEV_RAM_RAM, 0); /* Sound RAM: */ dev_ram_init(machine, 0x00800000, 2 * 1048576, DEV_RAM_RAM, 0, "sound_ram"); /* * HACK! TODO: Remove this device at 0x00a00000 once NetBSD has * been fixed to not clear 6 MB beyound the sound RAM area. */ dev_ram_init(machine, 0x00a00000, 6 * 1048576, DEV_RAM_RAM, 0, "hack_for_netbsd"); /* RAM: */ dev_ram_init(machine, 0x0c000000, 16 * 1048576, DEV_RAM_RAM, 0x0); /* Image of RAM: */ dev_ram_init(machine, 0x0e000000, 16 * 1048576, DEV_RAM_MIRROR | DEV_RAM_MIGHT_POINT_TO_DEVICES, 0x0c000000, "ram_mirror"); device_add(machine, "pvr"); /* device_add(machine, "mb8696x addr=0x600400 addr_mult=4"); */ device_add(machine, "dreamcast_asic"); device_add(machine, "dreamcast_g2"); device_add(machine, "dreamcast_gdrom"); device_add(machine, "dreamcast_maple"); device_add(machine, "dreamcast_rtc"); // Add devices as symbols, so that they show up in disassembly/runtime. struct memory *mem = cpu->mem; for (int i = 0; i < mem->n_mmapped_devices; i++) { // Add everything which is not called "ram" (for now). if (strcmp(mem->devices[i].name, "ram") == 0) { continue; } stringstream ss; ss.flags(ios::hex); ss << "(" << mem->devices[i].name << "@0x" << mem->devices[i].baseaddr << ")"; string name = ss.str(); add_symbol_name( &machine->symbol_context, mem->devices[i].baseaddr | 0x80000000U, mem->devices[i].length, name.c_str(), 0, 0); add_symbol_name( &machine->symbol_context, mem->devices[i].baseaddr | 0xa0000000U, mem->devices[i].length, name.c_str(), 0, 0); } if (!machine->prom_emulation) return; dreamcast_machine_setup(machine); } MACHINE_DEFAULT_CPU(dreamcast) { // Hitachi SH4, 200 MHz. (Or probably an "SH4a".) machine->cpu_name = strdup("SH7750"); } MACHINE_DEFAULT_RAM(dreamcast) { // Note: This is the size of the boot ROM area, since the // Dreamcast's RAM isn't located at physical address zero. machine->physical_ram_in_mb = 2; } MACHINE_REGISTER(dreamcast) { MR_DEFAULT(dreamcast, "Dreamcast", ARCH_SH, MACHINE_DREAMCAST); me->set_default_ram = machine_default_ram_dreamcast; machine_entry_add_alias(me, "dreamcast"); } gxemul-0.6.1/src/machines/machine_sgi.cc000644 001750 001750 00000054416 13402411502 020372 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Silicon Graphics' MIPS-based machines * * http://obsolete.majix.org/computers/sgi/iptable.shtml contains a * pretty detailed list of IP ("Inhouse Processor") model numbers. * * See also: http://hardware.majix.org/computers/sgi/iptable.shtml */ #include #include #include #include "arcbios.h" #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "diskimage.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "net.h" #include "thirdparty/sgi_arcbios.h" #include "thirdparty/crimereg.h" #define ETHERNET_STRING_MAXLEN 40 #define MACHINE_NAME_MAXBUF 100 MACHINE_SETUP(sgi) { uint64_t sgi_ram_offset = 0; int arc_wordlen = sizeof(uint32_t); struct memory *mem = machine->memory; char tmpstr[1000]; int i, j; char *eaddr_string = strdup("eaddr=10:20:30:40:50:60"); /* bogus */ unsigned char macaddr[6]; char *machineName; struct pci_data *pci_data = NULL; CHECK_ALLOCATION(machineName = (char *) malloc(MACHINE_NAME_MAXBUF)); machine->machine_name = machineName; cpu->byte_order = EMUL_BIG_ENDIAN; snprintf(machineName, MACHINE_NAME_MAXBUF, "SGI-IP%i", machine->machine_subtype); sgi_ram_offset = 1048576 * machine->memory_offset_in_mb; /* Special cases for IP20,22,24,26 memory offset: */ if (machine->machine_subtype == 20 || machine->machine_subtype == 22 || machine->machine_subtype == 24 || machine->machine_subtype == 26) { dev_ram_init(machine, 0x00000000, 0x10000, DEV_RAM_MIRROR | DEV_RAM_MIGHT_POINT_TO_DEVICES, sgi_ram_offset); dev_ram_init(machine, 0x00050000, sgi_ram_offset-0x50000, DEV_RAM_MIRROR | DEV_RAM_MIGHT_POINT_TO_DEVICES, sgi_ram_offset + 0x50000); } /* Special cases for IP28,30 memory offset: */ if (machine->machine_subtype == 28 || machine->machine_subtype == 30) { /* TODO: length below should maybe not be 128MB? */ dev_ram_init(machine, 0x00000000, 128*1048576, DEV_RAM_MIRROR | DEV_RAM_MIGHT_POINT_TO_DEVICES, sgi_ram_offset); } net_generate_unique_mac(machine, macaddr); CHECK_ALLOCATION(eaddr_string = (char *) malloc(ETHERNET_STRING_MAXLEN)); switch (machine->machine_subtype) { case 10: strlcat(machineName, " (4D/25)", MACHINE_NAME_MAXBUF); /* TODO */ break; case 12: strlcat(machineName, " (Iris Indigo IP12)", MACHINE_NAME_MAXBUF); /* TODO */ /* 33 MHz R3000, according to http://www.irisindigo.com/ */ /* "capable of addressing up to 96MB of memory." */ break; case 19: strlcat(machineName, " (Everest IP19)", MACHINE_NAME_MAXBUF); machine->main_console_handle = (size_t)device_add(machine, "z8530 addr=0x1fbd9830 irq=0 addr_mult=4"); fatal("TODO ip19 interrupt rewrite\n"); abort(); //dev_scc_init(machine, mem, 0x10086000, 0, // machine->x11_md.in_use, 0, 8); /* serial? irix? */ device_add(machine, "sgi_ip19 addr=0x18000000"); /* Irix' reads this device: */ device_add(machine, "random addr=0x10006000 len=16"); /* Irix' get_mpconf() looks for this: (TODO) */ store_32bit_word(cpu, 0xa0000000 + 0x3000, 0xbaddeed2); /* Memory size, not 4096 byte pages, but 256 bytes? (16 is size of kernel... approx) */ store_32bit_word(cpu, 0xa0000000 + 0x26d0, 30000); /* (machine->physical_ram_in_mb - 16) * (1048576 / 256)); */ break; case 20: strlcat(machineName, " (Indigo)", MACHINE_NAME_MAXBUF); /* * Guesses based on NetBSD 2.0 beta, 20040606. * * int0 at mainbus0 addr 0x1fb801c0: bus 1MHz, CPU 2MHz * imc0 at mainbus0 addr 0x1fa00000: revision 0 * gio0 at imc0 * unknown GIO card (product 0x00 revision 0x00) * at gio0 slot 0 addr 0x1f400000 not configured * unknown GIO card (product 0x00 revision 0x00) * at gio0 slot 1 addr 0x1f600000 not configured * unknown GIO card (product 0x00 revision 0x00) * at gio0 slot 2 addr 0x1f000000 not configured * hpc0 at gio0 addr 0x1fb80000: SGI HPC1 * zsc0 at hpc0 offset 0xd10 (channels 0 and 1, * channel 1 for console) * zsc1 at hpc0 offset 0xd00 (2 channels) * sq0 at hpc0 offset 0x100: SGI Seeq 80c03 * wdsc0 at hpc0 offset 0x11f * dpclock0 at hpc0 offset 0xe00 */ /* int0 at mainbus0 addr 0x1fb801c0 */ fatal("TODO: SGI legacy interrupt system rewrite!\n"); abort(); // machine->md_int.sgi_ip20_data = dev_sgi_ip20_init(cpu, mem, // DEV_SGI_IP20_BASE); /* imc0 at mainbus0 addr 0x1fa00000: revision 0: TODO (or in dev_sgi_ip20?) */ machine->main_console_handle = (size_t)device_add(machine, "z8530 addr=0x1fbd9830 irq=0 addr_mult=4"); /* This is the zsc0 reported by NetBSD: TODO: irqs */ machine->main_console_handle = (size_t)device_add(machine, "z8530 addr=0x1fb80d10 irq=0 addr_mult=4"); machine->main_console_handle = (size_t)device_add(machine, "z8530 addr=0x1fb80d00 irq=0 addr_mult=4"); /* WDSC SCSI controller: */ /* dev_wdsc_init(machine, mem, 0x1fb8011f, 0, 0); */ /* Return memory read errors so that hpc1 and hpc2 are not detected: */ device_add(machine, "unreadable addr=0x1fb00000 len=0x10000"); device_add(machine, "unreadable addr=0x1f980000 len=0x10000"); /* Return nothing for gio slots 0, 1, and 2: */ device_add(machine, "unreadable addr=0x1f400000 len=0x1000"); device_add(machine, "unreadable addr=0x1f600000 len=0x1000"); device_add(machine, "unreadable addr=0x1f000000 len=0x1000"); break; case 21: strlcat(machineName, /* TODO */ " (uknown SGI-IP21 ?)", MACHINE_NAME_MAXBUF); /* NOTE: Special case for arc_wordlen: */ arc_wordlen = sizeof(uint64_t); device_add(machine, "random addr=0x418000200, len=0x20000"); break; case 22: case 24: if (machine->machine_subtype == 22) { strlcat(machineName, " (Indy, Indigo2, Challenge S; Full-house)", MACHINE_NAME_MAXBUF); fatal("TODO: SGI legacy interrupt system rewrite!\n"); abort(); // machine->md_int.sgi_ip22_data = // dev_sgi_ip22_init(machine, mem, 0x1fbd9000, 0); } else { strlcat(machineName, " (Indy, Indigo2, Challenge S; Guiness)", MACHINE_NAME_MAXBUF); fatal("TODO: SGI legacy interrupt system rewrite!\n"); abort(); // machine->md_int.sgi_ip22_data = // dev_sgi_ip22_init(machine, mem, 0x1fbd9880, 1); } /* Why is this here? TODO dev_ram_init(machine, 0x88000000ULL, 128 * 1048576, DEV_RAM_MIRROR, 0x08000000); */ fatal("TODO: Legacy rewrite\n"); abort(); // machine->md_interrupt = sgi_ip22_interrupt; /* * According to NetBSD 1.6.2: * * imc0 at mainbus0 addr 0x1fa00000, Revision 0 * gio0 at imc0 * hpc0 at gio0 addr 0x1fb80000: SGI HPC3 * zsc0 at hpc0 offset 0x59830 * zstty0 at zsc0 channel 1 (console i/o) * zstty1 at zsc0 channel 0 * sq0 at hpc0 offset 0x54000: SGI Seeq 80c03 (Ethernet) * wdsc0 at hpc0 offset 0x44000: WD33C93 SCSI, rev=0, target 7 * scsibus2 at wdsc0: 8 targets, 8 luns per target * dsclock0 at hpc0 offset 0x60000 * * According to Linux/IP22: * tty00 at 0xbfbd9830 (irq = 45) is a Zilog8530 * tty01 at 0xbfbd9838 (irq = 45) is a Zilog8530 * * and according to NetBSD 2.0_BETA (20040606): * * haltwo0 at hpc0 offset 0x58000: HAL2 revision 0.0.0 * audio0 at haltwo0: half duplex * * IRQ numbers are of the form 8 + x, where x=0..31 for local0 * interrupts, and 32..63 for local1. + y*65 for "mappable". */ /* zsc0 serial console. 8 + 32 + 3 + 64*5 = 43+64*5 = 363 */ i = (size_t)device_add(machine, "z8530 addr=0x1fbd9830 irq=363 addr_mult=4"); /* Not supported by NetBSD 1.6.2, but by 2.0_BETA: */ fatal("TODO: legacy rewrite\n"); abort(); // j = dev_pckbc_init(machine, mem, 0x1fbd9840, PCKBC_8242, // 0, 0, machine->x11_md.in_use, 0); /* TODO: irq numbers */ j = 0; if (machine->x11_md.in_use) machine->main_console_handle = j; /* sq0: Ethernet. TODO: This should have irq_nr = 8 + 3 */ /* dev_sq_init... */ /* wdsc0: SCSI */ /* dev_wdsc_init(machine, mem, 0x1fbc4000, 0, 8 + 1); */ /* wdsc1: SCSI TODO: irq nr */ /* dev_wdsc_init(machine, mem, 0x1fbcc000, 1, 8 + 1); */ /* dsclock0: TODO: possibly irq 8 + 33 */ /* Return memory read errors so that hpc1 and hpc2 are not detected: */ device_add(machine, "unreadable addr=0x1fb00000, len=0x10000"); device_add(machine, "unreadable addr=0x1f980000, len=0x10000"); /* Similarly for gio slots 0, 1, and 2: */ device_add(machine, "unreadable addr=0x1f400000, len=0x1000"); device_add(machine, "unreadable addr=0x1f600000, len=0x1000"); device_add(machine, "unreadable addr=0x1f000000, len=0x1000"); break; case 25: /* NOTE: Special case for arc_wordlen: */ arc_wordlen = sizeof(uint64_t); strlcat(machineName, " (Everest IP25)", MACHINE_NAME_MAXBUF); /* serial? irix? */ fatal("TODO ip25 interrupt rewrite\n"); abort(); //dev_scc_init(machine, mem, // 0x400086000ULL, 0, machine->x11_md.in_use, 0, 8); /* NOTE: ip19! (perhaps not really the same */ device_add(machine, "sgi_ip19 addr=0x18000000"); /* * Memory size, not 4096 byte pages, but 256 * bytes? (16 is size of kernel... approx) */ store_32bit_word(cpu, 0xa0000000ULL + 0x26d0, 30000); /* (machine->physical_ram_in_mb - 16) * (1048576 / 256)); */ break; case 26: /* NOTE: Special case for arc_wordlen: */ arc_wordlen = sizeof(uint64_t); strlcat(machineName, " (uknown SGI-IP26 ?)", MACHINE_NAME_MAXBUF); /* TODO */ machine->main_console_handle = (size_t)device_add(machine, "z8530 addr=0x1fbd9830 irq=0 addr_mult=4"); break; case 27: strlcat(machineName, " (Origin 200/2000, Onyx2)", MACHINE_NAME_MAXBUF); arc_wordlen = sizeof(uint64_t); /* 2 cpus per node */ machine->main_console_handle = (size_t)device_add(machine, "z8530 addr=0x1fbd9830 irq=0 addr_mult=4"); break; case 28: /* NOTE: Special case for arc_wordlen: */ arc_wordlen = sizeof(uint64_t); strlcat(machineName, " (Impact Indigo2 ?)", MACHINE_NAME_MAXBUF); device_add(machine, "random addr=0x1fbe0000, len=1"); /* Something at paddr 0x1880fb0000. */ break; case 30: /* NOTE: Special case for arc_wordlen: */ arc_wordlen = sizeof(uint64_t); strlcat(machineName, " (Octane)", MACHINE_NAME_MAXBUF); // TODO: Interrupts! snprintf(tmpstr, sizeof(tmpstr), "sgi_ip30 addr=0x0ff00000"); device_add(machine, tmpstr); dev_ram_init(machine, 0xa0000000ULL, 128 * 1048576, DEV_RAM_MIRROR | DEV_RAM_MIGHT_POINT_TO_DEVICES, 0x00000000); dev_ram_init(machine, 0x80000000ULL, 32 * 1048576, DEV_RAM_RAM, 0x00000000); /* * Something at paddr=1f022004: TODO * Something at paddr=813f0510 - paddr=813f0570 ? * Something at paddr=813f04b8 * Something at paddr=f8000003c used by Linux/Octane * * 16550 serial port at paddr=1f620178, addr mul 1 * (Error messages are printed to this serial port by * the PROM.) * * There seems to also be a serial port at 1f620170. The * "symmon" program dumps something there, but it doesn't * look like readable text. (TODO) */ /* TODO: irq! */ snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.cpu[%i].2 addr=" "0x1f620170 name2=tty0 in_use=%i", machine->path, machine->bootstrap_cpu, machine->x11_md.in_use? 0 : 1); machine->main_console_handle = (size_t)device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.cpu[%i].2 addr=" "0x1f620178 name2=tty1 in_use=0", machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); /* MardiGras graphics: */ device_add(machine, "sgi_mardigras addr=0x1c000000"); break; case 32: strlcat(machineName, " (O2)", MACHINE_NAME_MAXBUF); /* * The IP32 prom probes "bank 0" with the following * TLB entries: * * 00: vaddr=0000000000000000 (global): p0=0x040000000 D p1=0x041000000 D (16MB) * 01: vaddr=0000000002000000 (global): p0=0x042000000 D p1=0x043000000 D (16MB) * 02: vaddr=0000000004000000 (global): p0=0x044000000 D p1=0x045000000 D (16MB) * 03: vaddr=0000000006000000 (global): p0=0x046000000 D p1=0x047000000 D (16MB) * * In other words, it uses real memory at 0x40000000 and up. * However, it is _also_ accessible at physical address 0x0. * * Max amount of RAM in an O2 is 1 GB. However, devices start at * 0x14000000 (or below that), so 256 MB is the most that the legacy GXemul * framework can handle. Memory above that must be accessed from 0x40000000 and up. */ if (machine->physical_ram_in_mb > 256) { fatal("TODO: Legacy framework cannot handle more than 256 MB for the SGI O2.\n"); exit(1); } /* In the new framework, this would be the other way around :-), i.e. actual memory at 0x40000000 and the first 256 MB would be mirrored at address 0. */ dev_ram_init(machine, 0x40000000ULL, machine->physical_ram_in_mb * 1048576, DEV_RAM_MIRROR, 0); /* Connect CRIME (Interrupt Controller) to MIPS irq 2: */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2", machine->path, machine->bootstrap_cpu); dev_crime_init(machine, mem, 0x14000000, tmpstr, machine->x11_md.in_use); /* Rendering Engine */ dev_sgi_re_init(machine, mem, 0x15000000); /* Graphics Back End */ dev_sgi_gbe_init(machine, mem, 0x16000000); /* * A combination of NetBSD and Linux info: * * 14000000 crime (interrupt/memory controller?) * 15000000 drawing engine, memory transfer engine, rendering engine * 16000000 gbe (graphics), crm framebuffer control * 17000000 vice (Video Image Compression Engine) * 18000000 pci (?) * 1f000000 mace * 1f080000 macepci * 1f100000 vin1 * 1f180000 vin2 * 1f200000 vout * 1f280000 enet (mec0, MAC-110 Ethernet) * 1f300000 perif: * 1f300000 audio ("a3"?) * 1f310000 isa * 1f318000 (unknown, accessed by Irix' pciio_pio_write64 and by the PROM during bootup) * 1f31c000 (unknown, accessed by the PROM during bootup) * 1f320000 kbdms * 1f330000 i2c * 1f340000 ust * 1f380000 isa ext * 1f390000 com0 (serial) * 1f398000 com1 (serial) * 1f3a0000 mcclock0 */ /* * IRQ mapping is really ugly. TODO: fix * * com0 at mace0 offset 0x390000 intr 4 intrmask * 0x3f00000: ns16550a, working fifo * com1 at mace0 offset 0x398000 intr 4 intrmask * 0xfc000000: ns16550a, working fifo * pckbc0 at mace0 offset 0x320000 intr 5 intrmask 0x0 * mcclock0 at mace0 offset 0x3a0000 intrmask 0x0 * macepci0 at mace0 offset 0x80000 intr 7 intrmask 0x0: rev 1 * * intr 4 = CRIME_INT_PERIPH_SERIAL * intr 5 = CRIME_INT_PERIPH_MISC * intr 7 = CRIME_INT_PCI_BRIDGE */ snprintf(eaddr_string, ETHERNET_STRING_MAXLEN, "eaddr=%02x:%02x:%02x:%02x:%02x:%02x", macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2.crime.0x%x", machine->path, machine->bootstrap_cpu, CRIME_INT_ETHERNET); dev_sgi_mec_init(machine, mem, 0x1f280000, tmpstr, macaddr); dev_sgi_ust_init(mem, 0x1f340000); /* ust? */ snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.cpu[%i].2.crime.0x%x.mace.%i addr=" "0x1f390000 addr_mult=0x100 in_use=%i name2=tty0", machine->path, machine->bootstrap_cpu, CRIME_INT_PERIPH_SERIAL, 20, machine->x11_md.in_use? 0 : 1); j = (size_t)device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.cpu[%i].2.crime.0x%x.mace.%i addr=" "0x1f398000 addr_mult=0x100 in_use=%i name2=tty1", machine->path, machine->bootstrap_cpu, CRIME_INT_PERIPH_SERIAL, 26, 0); device_add(machine, tmpstr); machine->main_console_handle = j; { /* keyb+mouse (mace irq numbers) */ char tmpstr1[1000]; char tmpstr2[1000]; snprintf(tmpstr1, sizeof(tmpstr1), "%s.cpu[%i].2.crime.0x%x.mace.%i", machine->path, machine->bootstrap_cpu, CRIME_INT_PERIPH_MISC, 9); snprintf(tmpstr2, sizeof(tmpstr2), "%s.cpu[%i].2.crime.0x%x.mace.%i", machine->path, machine->bootstrap_cpu, CRIME_INT_PERIPH_MISC, 11); i = dev_pckbc_init(machine, mem, 0x1f320000, PCKBC_8242, tmpstr1, tmpstr2, machine->x11_md.in_use, 0); if (machine->x11_md.in_use) machine->main_console_handle = i; } snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2.crime.0x%x.mace.%i", machine->path, machine->bootstrap_cpu, CRIME_INT_PERIPH_MISC, 8); dev_mc146818_init(machine, mem, 0x1f3a0000, tmpstr, MC146818_SGI, 0x40); /* mcclock0 */ /* * PCI devices: (according to NetBSD's GENERIC * config file for sgimips) * * ne* at pci? dev ? function ? * ahc0 at pci0 dev 1 function ? * ahc1 at pci0 dev 2 function ? */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2.crime.0x%x", machine->path, machine->bootstrap_cpu, CRIME_INT_PCI_BRIDGE); pci_data = dev_macepci_init(machine, mem, 0x1f080000, tmpstr); /* macepci0 */ /* bus_pci_add(machine, pci_data, mem, 0, 0, 0, "ne2000"); TODO */ /* * OpenBSD accesses the SCSI controller at paddr=0x2800010xx. * Note that the 2 is above 32-bit range. * * TODO: Investigate what this actually means. Possibly * a bug in GXemul's 64-bit instructions? Or perhaps it really * is correct. */ dev_ram_init(machine, 0x280000000ULL, 0x01000000, DEV_RAM_MIRROR, 0x18000000); // ahc0: /* TODO: Make it possible to add the controller, regardless of the existence of disks! */ if (diskimage_exist(machine, 0, DISKIMAGE_SCSI) || diskimage_exist(machine, 1, DISKIMAGE_SCSI) || diskimage_exist(machine, 2, DISKIMAGE_SCSI) || diskimage_exist(machine, 3, DISKIMAGE_SCSI) || diskimage_exist(machine, 4, DISKIMAGE_SCSI) || diskimage_exist(machine, 5, DISKIMAGE_SCSI) || diskimage_exist(machine, 6, DISKIMAGE_SCSI) || diskimage_exist(machine, 7, DISKIMAGE_SCSI)) bus_pci_add(machine, pci_data, mem, 0, 1, 0, "ahc"); // ahc1: // bus_pci_add(machine, pci_data, mem, 0, 2, 0, "ahc"); break; case 35: strlcat(machineName, " (Origin 3000)", MACHINE_NAME_MAXBUF); /* 4 cpus per node */ // TODO: Correct Interrupt! snprintf(tmpstr, sizeof(tmpstr), "z8530 addr=0x1fbd9830 irq=%s.cpu[%i].2", machine->path, machine->bootstrap_cpu); machine->main_console_handle = (size_t)device_add(machine, tmpstr); break; case 53: strlcat(machineName, " (Origin 350)", MACHINE_NAME_MAXBUF); /* * According to http://kumba.drachentekh.net/xml/myguide.html * Origin 350, Tezro IP53 R16000 */ break; default: fatal("unimplemented SGI machine type IP%i\n", machine->machine_subtype); exit(1); } if (!machine->prom_emulation) return; arcbios_init(machine, arc_wordlen == sizeof(uint64_t), sgi_ram_offset, eaddr_string, macaddr); } MACHINE_DEFAULT_CPU(sgi) { if (machine->machine_subtype <= 12) machine->cpu_name = strdup("R3000"); if (machine->cpu_name == NULL && machine->machine_subtype == 35) machine->cpu_name = strdup("R12000"); if (machine->cpu_name == NULL && (machine->machine_subtype == 25 || machine->machine_subtype == 27 || machine->machine_subtype == 28 || machine->machine_subtype == 30 || machine->machine_subtype == 32)) machine->cpu_name = strdup("R10000"); if (machine->cpu_name == NULL && (machine->machine_subtype == 21 || machine->machine_subtype == 26)) machine->cpu_name = strdup("R8000"); if (machine->cpu_name == NULL && machine->machine_subtype == 24) machine->cpu_name = strdup("R5000"); /* Other SGIs should probably work with R4000, R4400 or R5000 or similar: */ if (machine->cpu_name == NULL) machine->cpu_name = strdup("R4400"); } MACHINE_DEFAULT_RAM(sgi) { // Self-compilation fails with OpenBSD/sgi 6.3 with as low as 128 MB // RAM, so 256 would be better. But my O2 has 128 MB, so this is kept // as 128 to simplify comparison between the real machine and the // emulator. machine->physical_ram_in_mb = 128; } MACHINE_REGISTER(sgi) { MR_DEFAULT(sgi, "SGI", ARCH_MIPS, MACHINE_SGI); me->set_default_ram = machine_default_ram_sgi; machine_entry_add_alias(me, "silicon graphics"); machine_entry_add_alias(me, "sgi"); machine_entry_add_subtype(me, "IP12", 12, "ip12", NULL); machine_entry_add_subtype(me, "IP19", 19, "ip19", NULL); machine_entry_add_subtype(me, "IP20", 20, "ip20", NULL); machine_entry_add_subtype(me, "IP22", 22, "ip22", "indy", NULL); machine_entry_add_subtype(me, "IP24", 24, "ip24", NULL); machine_entry_add_subtype(me, "IP27", 27, "ip27", "origin 200", "origin 2000", NULL); machine_entry_add_subtype(me, "IP28", 28, "ip28", NULL); machine_entry_add_subtype(me, "IP30", 30, "ip30", "octane", NULL); machine_entry_add_subtype(me, "IP32", 32, "ip32", "o2", NULL); machine_entry_add_subtype(me, "IP35", 35, "ip35", NULL); } gxemul-0.6.1/src/machines/machine_test.cc000644 001750 001750 00000024302 13402411502 020556 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Various test machines * * Generally, the machines are as follows: * * bareXYZ: A bare machine using an XYZ processor. * * testXYZ: A machine with an XYZ processor, and some experimental * devices connected to it. * * The experimental devices in the test machines are: * * cons A serial I/O console device. * disk A device for reading/writing (emulated) disk sectors. * ether An ethernet device, for sending/receiving ethernet * frames on an emulated network. * fb Framebuffer (24-bit RGB per pixel). * irqc A generic interrupt controller. * mp A multiprocessor controller. * rtc A real-time clock device. */ #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/sh4_exception.h" #include "testmachine/dev_cons.h" #include "testmachine/dev_disk.h" #include "testmachine/dev_ether.h" #include "testmachine/dev_fb.h" #include "testmachine/dev_irqc.h" #include "testmachine/dev_mp.h" #include "testmachine/dev_rtc.h" /* * default_test(): * * Initializes devices for most test machines. (Note: MIPS is different, * because of legacy reasons.) */ static void default_test(struct machine *machine, struct cpu *cpu) { char tmpstr[2000]; char base_irq[1000]; char end_of_base_irq[50]; /* * First add the interrupt controller. Most processor architectures * in GXemul have only 1 interrupt pin on the CPU, and it is simply * called "machine[y].cpu[z]". * * MIPS is an exception, dealt with in a separate setup function. * ARM and SH are dealt with here. */ switch (machine->arch) { case ARCH_ARM: snprintf(end_of_base_irq, sizeof(end_of_base_irq), ".irq"); break; case ARCH_SH: snprintf(end_of_base_irq, sizeof(end_of_base_irq), ".irq[0x%x]", SH4_INTEVT_IRQ15); break; default: end_of_base_irq[0] = '\0'; } snprintf(base_irq, sizeof(base_irq), "%s.cpu[%i]%s", machine->path, machine->bootstrap_cpu, end_of_base_irq); snprintf(tmpstr, sizeof(tmpstr), "irqc addr=0x%" PRIx64" irq=%s", (uint64_t) DEV_IRQC_ADDRESS, base_irq); device_add(machine, tmpstr); /* Now, add the other devices: */ snprintf(tmpstr, sizeof(tmpstr), "cons addr=0x%" PRIx64 " irq=%s.irqc.2 in_use=%i", (uint64_t) DEV_CONS_ADDRESS, base_irq, machine->arch != ARCH_SH); machine->main_console_handle = (size_t)device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "mp addr=0x%" PRIx64" irq=%s%sirqc.6", (uint64_t) DEV_MP_ADDRESS, end_of_base_irq[0]? end_of_base_irq + 1 : "", end_of_base_irq[0]? "." : ""); device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "fbctrl addr=0x%" PRIx64, (uint64_t) DEV_FBCTRL_ADDRESS); device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "disk addr=0x%" PRIx64, (uint64_t) DEV_DISK_ADDRESS); device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "ether addr=0x%" PRIx64" irq=%s.irqc.3", (uint64_t) DEV_ETHER_ADDRESS, base_irq); device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "rtc addr=0x%" PRIx64" irq=%s.irqc.4", (uint64_t) DEV_RTC_ADDRESS, base_irq); device_add(machine, tmpstr); } MACHINE_SETUP(barearm) { machine->machine_name = strdup("Generic \"bare\" ARM machine"); #if 1 // An experiment with running a particular firmware image on a device; // move some other place when/if it works? cpu->byte_order = EMUL_BIG_ENDIAN; dev_ram_init(machine, 0xa0000000, 128 * 1048576, DEV_RAM_MIRROR | DEV_RAM_MIGHT_POINT_TO_DEVICES, 0x00000000, "ram_mirror"); #endif } MACHINE_SETUP(testarm) { machine->machine_name = strdup("ARM test machine"); default_test(machine, cpu); /* * Place a tiny stub at end of memory, and set the link register to * point to it. This stub halts the machine (making it easy to try * out simple stand-alone C functions). */ cpu->cd.arm.r[ARM_SP] = machine->physical_ram_in_mb * 1048576 - 4096; cpu->cd.arm.r[ARM_LR] = cpu->cd.arm.r[ARM_SP] + 32; store_32bit_word(cpu, cpu->cd.arm.r[ARM_LR] + 0, 0xe3a00201); store_32bit_word(cpu, cpu->cd.arm.r[ARM_LR] + 4, 0xe5c00010); store_32bit_word(cpu, cpu->cd.arm.r[ARM_LR] + 8, 0xeafffffe); } MACHINE_DEFAULT_CPU(barearm) { machine->cpu_name = strdup("SA1110"); } MACHINE_DEFAULT_CPU(testarm) { machine->cpu_name = strdup("SA1110"); } MACHINE_REGISTER(barearm) { MR_DEFAULT(barearm, "Generic \"bare\" ARM machine", ARCH_ARM, MACHINE_BAREARM); machine_entry_add_alias(me, "barearm"); } MACHINE_REGISTER(testarm) { MR_DEFAULT(testarm, "Test-machine for ARM", ARCH_ARM, MACHINE_TESTARM); machine_entry_add_alias(me, "testarm"); } MACHINE_SETUP(barem88k) { machine->machine_name = strdup("Generic \"bare\" M88K machine"); } MACHINE_SETUP(oldtestm88k) { machine->machine_name = strdup("M88K test machine"); default_test(machine, cpu); } MACHINE_DEFAULT_CPU(barem88k) { machine->cpu_name = strdup("88110"); } MACHINE_DEFAULT_CPU(oldtestm88k) { machine->cpu_name = strdup("88110"); } MACHINE_REGISTER(barem88k) { MR_DEFAULT(barem88k, "Generic \"bare\" M88K machine", ARCH_M88K, MACHINE_BAREM88K); machine_entry_add_alias(me, "barem88k"); } MACHINE_REGISTER(oldtestm88k) { MR_DEFAULT(oldtestm88k, "Test-machine for M88K", ARCH_M88K, MACHINE_TESTM88K); machine_entry_add_alias(me, "oldtestm88k"); } MACHINE_SETUP(baremips) { machine->machine_name = strdup("Generic \"bare\" MIPS machine"); cpu->byte_order = EMUL_BIG_ENDIAN; } MACHINE_SETUP(oldtestmips) { /* * A MIPS test machine. Originally, this was created as a way for * me to test my master's thesis code; since then it has both * evolved to support new things, and suffered bit rot so that it * no longer can run my thesis code. Well, well... * * IRQ map: * 7 CPU counter * 6 SMP IPIs * 5 not used yet * 4 rtc * 3 ethernet * 2 serial console */ char tmpstr[300]; machine->machine_name = strdup("MIPS test machine"); cpu->byte_order = EMUL_BIG_ENDIAN; snprintf(tmpstr, sizeof(tmpstr), "cons addr=0x%" PRIx64" irq=%s." "cpu[%i].2", (uint64_t) DEV_CONS_ADDRESS, machine->path, machine->bootstrap_cpu); machine->main_console_handle = (size_t)device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "mp addr=0x%" PRIx64" irq=6", (uint64_t) DEV_MP_ADDRESS); device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "fbctrl addr=0x%" PRIx64, (uint64_t) DEV_FBCTRL_ADDRESS); device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "disk addr=0x%" PRIx64, (uint64_t) DEV_DISK_ADDRESS); device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "ether addr=0x%" PRIx64" irq=%s." "cpu[%i].3", (uint64_t) DEV_ETHER_ADDRESS, machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "rtc addr=0x%" PRIx64" irq=%s." "cpu[%i].4", (uint64_t) DEV_RTC_ADDRESS, machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); } MACHINE_DEFAULT_CPU(baremips) { machine->cpu_name = strdup("5KE"); } MACHINE_DEFAULT_CPU(oldtestmips) { machine->cpu_name = strdup("5KE"); } MACHINE_REGISTER(baremips) { MR_DEFAULT(baremips, "Generic \"bare\" MIPS machine", ARCH_MIPS, MACHINE_BAREMIPS); machine_entry_add_alias(me, "baremips"); } MACHINE_REGISTER(oldtestmips) { MR_DEFAULT(oldtestmips, "Test-machine for MIPS", ARCH_MIPS, MACHINE_TESTMIPS); machine_entry_add_alias(me, "oldtestmips"); } MACHINE_SETUP(bareppc) { machine->machine_name = strdup("Generic \"bare\" PPC machine"); } MACHINE_SETUP(testppc) { machine->machine_name = strdup("PPC test machine"); default_test(machine, cpu); } MACHINE_DEFAULT_CPU(bareppc) { machine->cpu_name = strdup("PPC970"); } MACHINE_DEFAULT_CPU(testppc) { machine->cpu_name = strdup("PPC970"); } MACHINE_REGISTER(bareppc) { MR_DEFAULT(bareppc, "Generic \"bare\" PPC machine", ARCH_PPC, MACHINE_BAREPPC); machine_entry_add_alias(me, "bareppc"); } MACHINE_REGISTER(testppc) { MR_DEFAULT(testppc, "Test-machine for PPC", ARCH_PPC, MACHINE_TESTPPC); machine_entry_add_alias(me, "testppc"); } MACHINE_SETUP(baresh) { machine->machine_name = strdup("Generic \"bare\" SH machine"); } MACHINE_SETUP(testsh) { machine->machine_name = strdup("SH test machine"); default_test(machine, cpu); } MACHINE_DEFAULT_CPU(baresh) { machine->cpu_name = strdup("SH7750"); } MACHINE_DEFAULT_CPU(testsh) { machine->cpu_name = strdup("SH7750"); } MACHINE_REGISTER(baresh) { MR_DEFAULT(baresh, "Generic \"bare\" SH machine", ARCH_SH, MACHINE_BARESH); machine_entry_add_alias(me, "baresh"); } MACHINE_REGISTER(testsh) { MR_DEFAULT(testsh, "Test-machine for SH", ARCH_SH, MACHINE_TESTSH); machine_entry_add_alias(me, "testsh"); } gxemul-0.6.1/src/machines/automachine_head.cc000644 001750 001750 00000003550 13402411502 021373 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Automatically register all machines in the src/machines/ subdir. * * NOTE: automachine_head.c, plus a line for each machine, plus * automachine_middle.c, plus another line (again) for each machine, plus * automachine_tail.c should be combined into one. See makeautomachine.sh * for more info. */ #include #include "machine.h" gxemul-0.6.1/src/machines/Makefile.skel000644 001750 001750 00000001570 13402411502 020203 0ustar00debugdebug000000 000000 # # Makefile for GXemul machines # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(XINCLUDE) $(DINCLUDE) OBJS= machine.o machine_algor.o machine_alpha.o machine_arc.o \ machine_cats.o machine_cobalt.o machine_dreamcast.o machine_evbmips.o \ machine_hpcarm.o machine_hpcmips.o machine_hpcsh.o machine_iq80321.o \ machine_iyonix.o machine_landisk.o machine_luna88k.o machine_macppc.o \ machine_mvme88k.o machine_mvmeppc.o machine_netwinder.o \ machine_playstation2.o machine_pmax.o machine_pmppc.o machine_prep.o \ machine_qemu.o machine_rpi.o machine_sgi.o machine_test.o machine_vocore.o all: $(MAKE) objs $(MAKE) automachine.o automachine.cc: $(OBJS) automachine_head.cc automachine_middle.cc automachine_tail.cc makeautomachine.sh ./makeautomachine.sh objs: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) *core rm -f automachine.cc automachine.o clean_all: clean rm -f Makefile gxemul-0.6.1/src/machines/machine_hpcsh.cc000644 001750 001750 00000007434 13402411502 020713 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Handheld SuperH-based machines */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/hpc_bootinfo.h" #include "thirdparty/vripreg.h" MACHINE_SETUP(hpcsh) { /* char tmpstr[1000]; struct hpc_bootinfo hpc_bootinfo; int hpc_platid_flags = 0, hpc_platid_cpu_submodel = 0, hpc_platid_cpu_model = 0, hpc_platid_cpu_series = 0, hpc_platid_cpu_arch = 0, hpc_platid_submodel = 0, hpc_platid_model = 0, hpc_platid_series = 0, hpc_platid_vendor = 0; uint64_t hpc_fb_addr = 0; int hpc_fb_bits = 0, hpc_fb_encoding = 0; int hpc_fb_xsize = 0; int hpc_fb_ysize = 0; int hpc_fb_xsize_mem = 0; int hpc_fb_ysize_mem = 0; memset(&hpc_bootinfo, 0, sizeof(hpc_bootinfo)); */ machine->machine_name = strdup("HPCsh"); cpu->byte_order = EMUL_LITTLE_ENDIAN; if (!machine->x11_md.in_use) fprintf(stderr, "-------------------------------------" "------------------------------------------\n" "\n WARNING! You are emulating a HPCsh without -X." "\n You will miss graphical output!\n\n" "-------------------------------------" "------------------------------------------\n"); /* 32 MB in two parts, each included twice (shadowed): */ dev_ram_init(machine, 0x0c000000, 0x01000000, DEV_RAM_MIRROR, 0x0); dev_ram_init(machine, 0x0d000000, 0x01000000, DEV_RAM_MIRROR, 0x0); dev_ram_init(machine, 0x0e000000, 0x01000000, DEV_RAM_MIRROR, 0x01000000); dev_ram_init(machine, 0x0f000000, 0x01000000, DEV_RAM_MIRROR, 0x01000000); dev_fb_init(machine, machine->memory, 0x10000000, VFB_HPC, 640,240, 640,240, 16, machine->machine_name); } MACHINE_DEFAULT_CPU(hpcsh) { machine->cpu_name = strdup("SH7750"); } MACHINE_DEFAULT_RAM(hpcsh) { /* TODO: Model dependent. */ machine->physical_ram_in_mb = 32; } MACHINE_REGISTER(hpcsh) { MR_DEFAULT(hpcsh, "Handhelp SH (HPCsh)", ARCH_SH, MACHINE_HPCSH); machine_entry_add_alias(me, "hpcsh"); machine_entry_add_subtype(me, "Jornada 680", MACHINE_HPCSH_JORNADA680, "jornada680", NULL); machine_entry_add_subtype(me, "Jornada 690", MACHINE_HPCSH_JORNADA690, "jornada690", NULL); me->set_default_ram = machine_default_ram_hpcsh; } gxemul-0.6.1/src/machines/automachine_tail.cc000644 001750 001750 00000000004 13402411502 021412 0ustar00debugdebug000000 000000 } gxemul-0.6.1/src/machines/machine_cats.cc000644 001750 001750 00000012161 13402411502 020531 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Simtec Electronics' CATS board */ #include #include #include #include "bus_isa.h" #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/cyclone_boot.h" MACHINE_SETUP(cats) { struct ebsaboot ebsaboot; struct pci_data *pci_bus; char bs[300], tmpstr[400]; int boot_id = machine->bootdev_id >= 0? machine->bootdev_id : 0; machine->machine_name = strdup("CATS evaluation board"); if (machine->emulated_hz == 0) machine->emulated_hz = 50000000; if (machine->physical_ram_in_mb > 256) fprintf(stderr, "WARNING! Real CATS machines cannot" " have more than 256 MB RAM. Continuing anyway.\n"); snprintf(tmpstr, sizeof(tmpstr), "footbridge irq=%s.cpu[%i].irq" " addr=0x42000000", machine->path, machine->bootstrap_cpu); pci_bus = (struct pci_data *) device_add(machine, tmpstr); /* DC21285_ROM_BASE (256 KB at 0x41000000) */ dev_ram_init(machine, 0x41000000, 256 * 1024, DEV_RAM_RAM, 0); /* NetBSD, OpenBSD, and Linux (?) clean their caches here: */ dev_ram_init(machine, 0x50000000, 0x10000, DEV_RAM_RAM, 0); /* Interrupt ack space? */ dev_ram_init(machine, 0x80000000, 0x1000, DEV_RAM_RAM, 0); /* Linux uses 0xc0000000 as phys.: */ dev_ram_init(machine, 0xc0000000, 0x20000000, DEV_RAM_MIRROR, 0x0); /* OpenBSD reboot needs 0xf??????? to be mapped to phys.: */ dev_ram_init(machine, 0xf0000000, 0x1000000, DEV_RAM_MIRROR, 0x0); bus_pci_add(machine, pci_bus, machine->memory, 0xc0, 8, 0, "s3_virge"); if (!machine->prom_emulation) return; /* See cyclone_boot.h for details. */ /* DC21285_ROM_BASE "reboot" code: (works with NetBSD) */ store_32bit_word(cpu, 0x41000008ULL, 0xef8c64ebUL); cpu->cd.arm.r[0] = /* machine->physical_ram_in_mb */ 7 * 1048576 - 0x1000; memset(&ebsaboot, 0, sizeof(struct ebsaboot)); store_32bit_word_in_host(cpu, (unsigned char *) &(ebsaboot.bt_magic), BT_MAGIC_NUMBER_CATS); store_32bit_word_in_host(cpu, (unsigned char *) &(ebsaboot.bt_vargp), 0); store_32bit_word_in_host(cpu, (unsigned char *) &(ebsaboot.bt_pargp), 0); store_32bit_word_in_host(cpu, (unsigned char *) &(ebsaboot.bt_args), cpu->cd.arm.r[0] + sizeof(struct ebsaboot)); store_32bit_word_in_host(cpu, (unsigned char *) &(ebsaboot.bt_l1), 7 * 1048576 - 32768); store_32bit_word_in_host(cpu, (unsigned char *) &(ebsaboot.bt_memstart), 0); store_32bit_word_in_host(cpu, (unsigned char *) &(ebsaboot.bt_memend), machine->physical_ram_in_mb * 1048576); store_32bit_word_in_host(cpu, (unsigned char *) &(ebsaboot.bt_memavail), 7 * 1048576); store_32bit_word_in_host(cpu, (unsigned char *) &(ebsaboot.bt_fclk), 50 * 1000000); store_32bit_word_in_host(cpu, (unsigned char *) &(ebsaboot.bt_pciclk), 66 * 1000000); /* TODO: bt_vers */ /* TODO: bt_features */ store_buf(cpu, cpu->cd.arm.r[0], (char *)&ebsaboot, sizeof(struct ebsaboot)); snprintf(bs, sizeof(bs), "(hd%i)%s root=/dev/wd%i%s%s", boot_id, machine->boot_kernel_filename, boot_id, (machine->boot_string_argument[0])? " " : "", machine->boot_string_argument); store_string(cpu, cpu->cd.arm.r[0]+sizeof(struct ebsaboot), bs); arm_setup_initial_translation_table(cpu, 7 * 1048576 - 32768); } MACHINE_DEFAULT_CPU(cats) { machine->cpu_name = strdup("SA110"); } MACHINE_DEFAULT_RAM(cats) { machine->physical_ram_in_mb = 64; } MACHINE_REGISTER(cats) { MR_DEFAULT(cats, "CATS evaluation board", ARCH_ARM, MACHINE_CATS); machine_entry_add_alias(me, "cats"); me->set_default_ram = machine_default_ram_cats; } gxemul-0.6.1/src/machines/machine_luna88k.cc000644 001750 001750 00000007614 13402411502 021100 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: LUNA88K machine * * This is for experiments with OpenBSD/luna88k. See * openbsd/sys/arch/luna88k/luna88k/locore0.S for more information about * how OpenBSD starts up on this platform. * * RAMDISK kernel used for experiments: * * https://ftp.eu.openbsd.org/pub/OpenBSD/6.2/luna88k/bsd.rd * * Launch with gxemul -e luna-88k2 -Ttv bsd.rd */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/luna88k_board.h" MACHINE_SETUP(luna88k) { const char* luna88k2_fuse_string = "MNAME=LUNA88K+"; device_add(machine, "luna88k"); switch (machine->machine_subtype) { case MACHINE_LUNA_88K: machine->machine_name = strdup("LUNA 88K"); break; case MACHINE_LUNA_88K2: machine->machine_name = strdup("LUNA 88K2"); /* According to OpenBSD source code, the string "MNAME=LUNA88K+" in FUSE_ROM_DATA is used to determine that this is a 88K2, and not an 88K. fuse_rom_data[i] = (char)((((p->h) >> 24) & 0x000000f0) | (((p->l) >> 28) & 0x0000000f)); where h is first 32-bit word, l is second. */ for (int i = 0; i < strlen(luna88k2_fuse_string); ++i) { uint32_t h = luna88k2_fuse_string[i] & 0xf0; uint32_t l = luna88k2_fuse_string[i] & 0x0f; store_32bit_word(cpu, FUSE_ROM_ADDR + i * 8 + 0, h << 24); store_32bit_word(cpu, FUSE_ROM_ADDR + i * 8 + 4, l << 28); } break; default:fatal("Unimplemented LUNA88K machine subtype %i\n", machine->machine_subtype); exit(1); } if (machine->ncpus > 4) { fatal("More than 4 CPUs is not supported for LUNA 88K.\n"); exit(1); } if (!machine->prom_emulation) return; luna88kprom_init(machine); } MACHINE_DEFAULT_CPU(luna88k) { machine->cpu_name = strdup("88100"); } MACHINE_DEFAULT_RAM(luna88k) { // Two OpenBSD dmesgs found on the Internet for a LUNA-88K2 showed 112 MB of real mem. machine->physical_ram_in_mb = 112; } MACHINE_REGISTER(luna88k) { MR_DEFAULT(luna88k, "LUNA88K", ARCH_M88K, MACHINE_LUNA88K); machine_entry_add_alias(me, "luna88k"); machine_entry_add_subtype(me, "LUNA-88K", MACHINE_LUNA_88K, "luna-88k", NULL); machine_entry_add_subtype(me, "LUNA-88K2", MACHINE_LUNA_88K2, "luna-88k2", NULL); me->set_default_ram = machine_default_ram_luna88k; } gxemul-0.6.1/src/machines/README000644 001750 001750 00000003470 13402411502 016467 0ustar00debugdebug000000 000000 $Id: README,v 1.5 2007-05-20 10:49:11 debug Exp $ How to add new machine types to GXemul: --------------------------------------- The easiest way is to simply copy an existing machine (e.g. machine_landisk.c) into whatever you want the new machine to be called (machine_foo.c), update Makefile.skel to include machine_foo.o in the list of object files to build, and then change the contents of machine_foo.c. A machine_*.c file may contain more than one machine specification (e.g. machine_test.c contains several "bare" and "test" machines), but usually it is best to think of these files as containing one machine per file. The main code parts are: MACHINE_SETUP(my_machine_name) { machine->machine_name = "My Machine Name"; ... /* add devices and busses here */ if (!machine->prom_emulation) return; /* add prom emulation stuff here, e.g. register contents and memory contents at startup */ } MACHINE_DEFAULT_CPU(my_machine_name) { /* Replace 5Kc with the name of the CPU in the machine you are emulating: */ machine->cpu_name = strdup("5Kc"); } MACHINE_DEFAULT_RAM(my_machine_name) { /* Set this to the amount of RAM in MB that the machine mode will use by default, unless overridden with the -M option: */ machine->physical_ram_in_mb = 64; } MACHINE_REGISTER(my_machine_name) { /* Register the machine name. Change ARCH_MIPS to the desired architecture, and make sure that MACHINE_MY_MACHINE is defined in src/include/machine.h! */ MR_DEFAULT(my_machine_name, "My Machine Name", ARCH_MIPS, MACHINE_MY_MACHINE); me->set_default_ram = machine_default_ram_my_machine_name; /* Add an alias. This is what will show up in the -H list, and is used by the -E option: */ machine_entry_add_alias(me, "my_machine_name"); } gxemul-0.6.1/src/machines/machine_evbmips.cc000644 001750 001750 00000013724 13402411502 021252 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: MIPS evaluation boards (e.g. Malta) */ #include #include #include #include "bus_isa.h" #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/maltareg.h" MACHINE_SETUP(evbmips) { char tmpstr[1000], tmpstr2[1000]; struct pci_data *pci_data; int i; /* See http://www.netbsd.org/ports/evbmips/ for more info. */ switch (machine->machine_subtype) { case MACHINE_EVBMIPS_MALTA: case MACHINE_EVBMIPS_MALTA_BE: if (machine->emulated_hz == 0) machine->emulated_hz = 33000000; cpu->byte_order = EMUL_LITTLE_ENDIAN; machine->machine_name = strdup("MALTA (evbmips, little endian)"); if (machine->machine_subtype == MACHINE_EVBMIPS_MALTA_BE) { machine->machine_name = strdup("MALTA (evbmips, big endian)"); cpu->byte_order = EMUL_BIG_ENDIAN; } /* ISA bus at MIPS irq 2: */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2", machine->path, machine->bootstrap_cpu); bus_isa_init(machine, tmpstr, 0, 0x18000000, 0x10000000); snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.cpu[%i].4 " "addr=0x%x name2=tty2 in_use=0", machine->path, machine->bootstrap_cpu, MALTA_CBUSUART); device_add(machine, tmpstr); /* Add a GT controller; timer interrupts at ISA irq 9: */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2.isa.9", machine->path, machine->bootstrap_cpu); snprintf(tmpstr2, sizeof(tmpstr2), "%s.cpu[%i].2", machine->path, machine->bootstrap_cpu); pci_data = dev_gt_init(machine, machine->memory, 0x1be00000, tmpstr, tmpstr2, 120); if (machine->x11_md.in_use) { if (strlen(machine->boot_string_argument) < 3) { fatal("WARNING: remember to use -o 'console=" "tty0' if you are emulating Linux. (Not" " needed for NetBSD.)\n"); } bus_pci_add(machine, pci_data, machine->memory, 0, 8, 0, "s3_virge"); } bus_pci_add(machine, pci_data, machine->memory, 0, 9, 0, "piix4_isa"); bus_pci_add(machine, pci_data, machine->memory, 0, 9, 1, "piix4_ide"); /* pcn: Not yet, since it is just a bogus device, so far. */ /* bus_pci_add(machine, pci_data, machine->memory, 0, 11, 0, "pcn"); */ device_add(machine, "malta_lcd addr=0x1f000400"); break; default:fatal("Unimplemented EVBMIPS model.\n"); exit(1); } if (!machine->prom_emulation) return; /* NetBSD/evbmips wants these: (at least for Malta) */ /* a0 = argc */ cpu->cd.mips.gpr[MIPS_GPR_A0] = 2; /* a1 = argv */ cpu->cd.mips.gpr[MIPS_GPR_A1] = (int32_t)0x9fc01000; store_32bit_word(cpu, (int32_t)0x9fc01000, 0x9fc01040); store_32bit_word(cpu, (int32_t)0x9fc01004, 0x9fc01200); store_32bit_word(cpu, (int32_t)0x9fc01008, 0); machine->bootstr = strdup(machine->boot_kernel_filename); machine->bootarg = strdup(machine->boot_string_argument); store_string(cpu, (int32_t)0x9fc01040, machine->bootstr); store_string(cpu, (int32_t)0x9fc01200, machine->bootarg); /* a2 = (yamon_env_var *)envp */ cpu->cd.mips.gpr[MIPS_GPR_A2] = (int32_t)0x9fc01800; yamon_machine_setup(machine, cpu->cd.mips.gpr[MIPS_GPR_A2]); /* a3 = memsize */ cpu->cd.mips.gpr[MIPS_GPR_A3] = machine->physical_ram_in_mb * 1048576; /* Hm. Linux ignores a3. */ /* Set the Core ID. See maltareg.h for more info. */ store_32bit_word(cpu, (int32_t)(0x80000000 + MALTA_REVISION), (1 << 10) + 0x26); /* Call vectors at 0x9fc005xx: */ for (i=0; i<0x100; i+=4) store_32bit_word(cpu, (int64_t)(int32_t)0x9fc00500 + i, (int64_t)(int32_t)0x9fc00800 + i); /* "Magic trap" PROM instructions at 0x9fc008xx: */ for (i=0; i<0x100; i+=4) store_32bit_word(cpu, (int64_t)(int32_t)0x9fc00800 + i, 0x00c0de0c); } MACHINE_DEFAULT_CPU(evbmips) { switch (machine->machine_subtype) { case MACHINE_EVBMIPS_MALTA: case MACHINE_EVBMIPS_MALTA_BE: /* 5Kc = MIPS64 rev 1, 5KE = MIPS64 rev 2 */ machine->cpu_name = strdup("5Kc"); break; default:fatal("Unimplemented evbmips subtype.\n"); exit(1); } } MACHINE_DEFAULT_RAM(evbmips) { machine->physical_ram_in_mb = 128; } MACHINE_REGISTER(evbmips) { MR_DEFAULT(evbmips, "MIPS evaluation boards (evbmips)", ARCH_MIPS, MACHINE_EVBMIPS); machine_entry_add_alias(me, "evbmips"); machine_entry_add_subtype(me, "Malta", MACHINE_EVBMIPS_MALTA, "malta", NULL); machine_entry_add_subtype(me, "Malta (Big-Endian)", MACHINE_EVBMIPS_MALTA_BE, "maltabe", NULL); me->set_default_ram = machine_default_ram_evbmips; } gxemul-0.6.1/src/machines/machine_netwinder.cc000644 001750 001750 00000005517 13402411502 021605 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: NetWinder */ #include #include #include #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" MACHINE_SETUP(netwinder) { char tmpstr[300]; struct pci_data *pci_bus; machine->machine_name = strdup("NetWinder"); if (machine->physical_ram_in_mb > 256) fprintf(stderr, "WARNING! Real NetWinders cannot" " have more than 256 MB RAM. Continuing anyway.\n"); /* CPU at 63.75 MHz, according to NetBSD's netwinder_machdep.c. */ machine->emulated_hz = 63750000; snprintf(tmpstr, sizeof(tmpstr), "footbridge irq=%s.cpu[%i].irq" " addr=0x42000000", machine->path, machine->bootstrap_cpu); pci_bus = (struct pci_data *) device_add(machine, tmpstr); if (machine->x11_md.in_use) { bus_pci_add(machine, pci_bus, machine->memory, 0xc0, 8, 0, "igsfb"); } if (!machine->prom_emulation) return; arm_setup_initial_translation_table(cpu, 0x4000); } MACHINE_DEFAULT_CPU(netwinder) { machine->cpu_name = strdup("SA110"); } MACHINE_DEFAULT_RAM(netwinder) { machine->physical_ram_in_mb = 16; } MACHINE_REGISTER(netwinder) { MR_DEFAULT(netwinder, "NetWinder", ARCH_ARM, MACHINE_NETWINDER); machine_entry_add_alias(me, "netwinder"); me->set_default_ram = machine_default_ram_netwinder; } gxemul-0.6.1/src/machines/machine_pmax.cc000644 001750 001750 00000102321 13402411502 020542 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Digital DECstation ("PMAX") machines */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "diskimage.h" #include "machine.h" #include "machine_pmax.h" #include "memory.h" #include "misc.h" #include "thirdparty/dec_prom.h" #include "thirdparty/dec_bootinfo.h" #include "thirdparty/dec_5100.h" #include "thirdparty/dec_kn01.h" #include "thirdparty/dec_kn02.h" #include "thirdparty/dec_kn03.h" #include "thirdparty/dec_kmin.h" #include "thirdparty/dec_maxine.h" #define BOOTARG_BUFLEN 2000 MACHINE_SETUP(pmax) { const char *framebuffer_console_name, *serial_console_name; char *init_bootpath; int color_fb_flag, i; int boot_scsi_boardnumber = 3, boot_net_boardnumber = 3; const char *turbochannel_default_gfx_card = "PMAG-BA"; /* PMAG-AA, -BA, -CA/DA/EA/FA, -JA, -RO, PMAGB-BA */ struct xx { struct btinfo_magic a; struct btinfo_bootpath b; struct btinfo_symtab c; } xx; char tmpstr[1000]; struct vfb_data *fb; struct memory *mem = machine->memory; uint64_t addr; cpu->byte_order = EMUL_LITTLE_ENDIAN; /* * Add an R2020 or R3220 writeback memory thing: */ cpu->cd.mips.coproc[3] = mips_coproc_new(cpu, 3); /* There aren't really any good standard values... */ framebuffer_console_name = "osconsole=0,3"; serial_console_name = "osconsole=1"; switch (machine->machine_subtype) { case MACHINE_DEC_PMAX_3100: /* type 1, KN01 */ /* Supposed to have 12MHz or 16.67MHz R2000 CPU, R2010 FPC, R2020 Memory coprocessor */ machine->machine_name = strdup("DEC PMAX 3100 (KN01)"); /* 12 MHz for 2100, 16.67 MHz for 3100 */ if (machine->emulated_hz == 0) machine->emulated_hz = 16670000; if (machine->physical_ram_in_mb > 24) fprintf(stderr, "WARNING! Real DECstation 3100 machines" " cannot have more than 24MB RAM.\n"); if ((machine->physical_ram_in_mb % 4) != 0) fprintf(stderr, "WARNING! Real DECstation 3100 machines" " have an integer multiple of 4 MBs of RAM.\n"); /* 1 for color, 0 for mono. TODO: command line option? */ color_fb_flag = 1; /* * According to NetBSD/pmax: * * pm0 at ibus0 addr 0xfc00000: 1024x864x1 (or x8 for color) * dc0 at ibus0 addr 0x1c000000 * le0 at ibus0 addr 0x18000000: address 00:00:00:00:00:00 * sii0 at ibus0 addr 0x1a000000 * mcclock0 at ibus0 addr 0x1d000000: mc146818 or compatible * 0x1e000000 = system status and control register */ fb = dev_fb_init(machine, mem, KN01_PHYS_FBUF_START, color_fb_flag? VFB_DEC_VFB02 : VFB_DEC_VFB01, 0,0,0,0,0, color_fb_flag? "VFB02":"VFB01"); dev_colorplanemask_init(mem, KN01_PHYS_COLMASK_START, &fb->color_plane_mask); dev_vdac_init(mem, KN01_SYS_VDAC, fb->rgb_palette, color_fb_flag); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%i", machine->path, machine->bootstrap_cpu, KN01_INT_LANCE); dev_le_init(machine, mem, KN01_SYS_LANCE, KN01_SYS_LANCE_B_START, KN01_SYS_LANCE_B_END, tmpstr, 4*1048576); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%i", machine->path, machine->bootstrap_cpu, KN01_INT_SII); dev_sii_init(machine, mem, KN01_SYS_SII, KN01_SYS_SII_B_START, KN01_SYS_SII_B_END, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%i", machine->path, machine->bootstrap_cpu, KN01_INT_DZ); dev_dc7085_init(machine, mem, KN01_SYS_DZ, tmpstr, machine->x11_md.in_use); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%i", machine->path, machine->bootstrap_cpu, KN01_INT_CLOCK); dev_mc146818_init(machine, mem, KN01_SYS_CLOCK, tmpstr, MC146818_DEC, 1); dev_kn01_init(mem, KN01_SYS_CSR, color_fb_flag); framebuffer_console_name = "osconsole=0,3"; /* fb,keyb */ serial_console_name = "osconsole=3"; /* 3 */ break; case MACHINE_DEC_3MAX_5000: /* type 2, KN02 */ /* Supposed to have 25MHz R3000 CPU, R3010 FPC, */ /* and a R3220 Memory coprocessor */ machine->machine_name = strdup("DECstation 5000/200 (3MAX, KN02)"); if (machine->emulated_hz == 0) machine->emulated_hz = 25000000; if (machine->physical_ram_in_mb < 8) fprintf(stderr, "WARNING! Real KN02 machines do not " "have less than 8MB RAM. Continuing anyway.\n"); if (machine->physical_ram_in_mb > 480) fprintf(stderr, "WARNING! Real KN02 machines cannot " "have more than 480MB RAM. Continuing anyway.\n"); /* An R3220 memory thingy: */ cpu->cd.mips.coproc[3] = mips_coproc_new(cpu, 3); /* * According to NetBSD/pmax: * asc0 at tc0 slot 5 offset 0x0 * le0 at tc0 slot 6 offset 0x0 * ibus0 at tc0 slot 7 offset 0x0 * dc0 at ibus0 addr 0x1fe00000 * mcclock0 at ibus0 addr 0x1fe80000: mc146818 */ /* KN02 mainbus (TurboChannel interrupt controller): */ snprintf(tmpstr, sizeof(tmpstr), "kn02 addr=0x%x " "irq=%s.cpu[%i].2", (int) KN02_SYS_CSR, machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); /* * TURBOchannel slots 0, 1, and 2 are free for option cards. * Let's put in zero or more graphics boards: * * TODO: It's also possible to have larger graphics cards that * occupy several slots. How should this be solved nicely? */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2.kn02.%i", machine->path, machine->bootstrap_cpu, 0); dev_turbochannel_init(machine, mem, 0, KN02_PHYS_TC_0_START, KN02_PHYS_TC_0_END, machine->n_gfx_cards >= 1? turbochannel_default_gfx_card : "", tmpstr); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2.kn02.%i", machine->path, machine->bootstrap_cpu, 1); dev_turbochannel_init(machine, mem, 1, KN02_PHYS_TC_1_START, KN02_PHYS_TC_1_END, machine->n_gfx_cards >= 2? turbochannel_default_gfx_card : "", tmpstr); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2.kn02.%i", machine->path, machine->bootstrap_cpu, 2); dev_turbochannel_init(machine, mem, 2, KN02_PHYS_TC_2_START, KN02_PHYS_TC_2_END, machine->n_gfx_cards >= 3? turbochannel_default_gfx_card : "", tmpstr); /* TURBOchannel slots 3 and 4 are reserved. */ /* TURBOchannel slot 5 is PMAZ-AA ("asc" SCSI). */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2.kn02.%i", machine->path, machine->bootstrap_cpu, 5); dev_turbochannel_init(machine, mem, 5, KN02_PHYS_TC_5_START, KN02_PHYS_TC_5_END, "PMAZ-AA", tmpstr); /* TURBOchannel slot 6 is PMAD-AA ("le" ethernet). */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2.kn02.%i", machine->path, machine->bootstrap_cpu, 6); dev_turbochannel_init(machine, mem, 6, KN02_PHYS_TC_6_START, KN02_PHYS_TC_6_END, "PMAD-AA", tmpstr); /* TURBOchannel slot 7 is system stuff. */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2.kn02.%i", machine->path, machine->bootstrap_cpu, 7); machine->main_console_handle = dev_dc7085_init(machine, mem, KN02_SYS_DZ, tmpstr, machine->x11_md.in_use); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%i", machine->path, machine->bootstrap_cpu, KN02_INT_CLOCK); dev_mc146818_init(machine, mem, KN02_SYS_CLOCK, tmpstr, MC146818_DEC, 1); framebuffer_console_name = "osconsole=0,7"; /* fb,keyb */ serial_console_name = "osconsole=2"; boot_scsi_boardnumber = 5; boot_net_boardnumber = 6; /* TODO: 3? */ break; case MACHINE_DEC_3MIN_5000: /* type 3, KN02BA */ machine->machine_name = strdup("DECstation 5000/112, 125, or 145 (3MIN," " KN02BA)"); if (machine->emulated_hz == 0) machine->emulated_hz = 33000000; if (machine->physical_ram_in_mb > 128) fprintf(stderr, "WARNING! Real 3MIN machines cannot " "have more than 128MB RAM. Continuing anyway.\n"); /* KN02BA "3min" TurboChannel interrupt controller: */ snprintf(tmpstr, sizeof(tmpstr), "kn02ba irq=%s.cpu[%i].%i", machine->path, machine->bootstrap_cpu, KMIN_INT_TC3); device_add(machine, tmpstr); /* * tc0 at mainbus0: 12.5 MHz clock (0x10000000,slotsize=64MB) * tc slot 1: 0x14000000 * tc slot 2: 0x18000000 * ioasic0 at tc0 slot 3 offset 0x0 (0x1c000000) slot 0 * asic regs (0x1c040000) slot 1 * station's ether address (0x1c080000) slot 2 * le0 at ioasic0 offset 0xc0000: address 00:00:00:00:00:00 * (0x1c0c0000) slot 3 * scc0 at ioasic0 offset 0x100000 (0x1c100000) slot 4 * scc1 at ioasic0 offset 0x180000: console(0x1c180000) slot 6 * mcclock0 at ioasic0 offset 0x200000: mc146818 or * compatible (0x1c200000) slot 8 * asc0 at ioasic0 offset 0x300000: NCR53C94, 25MHz, * SCSI ID 7 (0x1c300000) slot 12 * dma for asc0 (0x1c380000) slot 14 */ ////fatal("TODO: kmin dev_le_init.\n"); ////abort(); // dev_le_init(machine, mem, 0x1c0c0000, 0, 0, // KMIN_INTR_LANCE + 8, 4 * 65536); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%i.kn02ba.0x%x", machine->path, machine->bootstrap_cpu, KMIN_INT_TC3, KMIN_INTR_SCC_0); dev_scc_init(machine, mem, 0x1c100000, tmpstr, machine->x11_md.in_use, 0, 1); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%i.kn02ba.0x%x", machine->path, machine->bootstrap_cpu, KMIN_INT_TC3, KMIN_INTR_SCC_1); dev_scc_init(machine, mem, 0x1c180000, tmpstr, machine->x11_md.in_use, 1, 1); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%i.kn02ba.0x%x", machine->path, machine->bootstrap_cpu, KMIN_INT_TC3, KMIN_INTR_CLOCK); dev_mc146818_init(machine, mem, KMIN_SYS_CLOCK, tmpstr, MC146818_DEC, 1); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%i.kn02ba.0x%x", machine->path, machine->bootstrap_cpu, KMIN_INT_TC3, KMIN_INTR_SCSI); dev_asc_init(machine, mem, 0x1c300000, tmpstr, NULL, DEV_ASC_DEC, NULL, NULL); /* * TURBOchannel slots 0, 1, and 2 are free for * option cards. These are by default filled with * zero or more graphics boards. * * TODO: irqs */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%i", machine->path, machine->bootstrap_cpu, KMIN_INT_TC0); dev_turbochannel_init(machine, mem, 0, KMIN_PHYS_TC_0_START, KMIN_PHYS_TC_0_END, machine->n_gfx_cards >= 1? turbochannel_default_gfx_card : "", tmpstr); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%i", machine->path, machine->bootstrap_cpu, KMIN_INT_TC1); dev_turbochannel_init(machine, mem, 0, KMIN_PHYS_TC_1_START, KMIN_PHYS_TC_1_END, machine->n_gfx_cards >= 2? turbochannel_default_gfx_card : "", tmpstr); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%i", machine->path, machine->bootstrap_cpu, KMIN_INT_TC2); dev_turbochannel_init(machine, mem, 0, KMIN_PHYS_TC_2_START, KMIN_PHYS_TC_2_END, machine->n_gfx_cards >= 3? turbochannel_default_gfx_card : "", tmpstr); /* (kmin shared irq numbers (IP) are offset by +8 in the emulator) */ /* kmin_csr = dev_kmin_init(cpu, mem, KMIN_REG_INTR); */ framebuffer_console_name = "osconsole=0,3"; /* fb,keyb(?) */ serial_console_name = "osconsole=3"; /* ? */ break; case MACHINE_DEC_3MAXPLUS_5000: /* type 4, KN03 */ machine->machine_name = strdup("DECsystem 5900 or 5000 (3MAX+) (KN03)"); /* 5000/240 (KN03-GA, R3000): 40 MHz */ /* 5000/260 (KN05-NB, R4000): 60 MHz */ /* TODO: are both these type 4? */ if (machine->emulated_hz == 0) machine->emulated_hz = 40000000; if (machine->physical_ram_in_mb > 480) fprintf(stderr, "WARNING! Real KN03 machines cannot " "have more than 480MB RAM. Continuing anyway.\n"); /* KN03 interrupts: */ fatal("TODO: Legacy rewrite\n"); abort(); // machine->md_interrupt = kn03_interrupt; /* * tc0 at mainbus0: 25 MHz clock (slot 0) (0x1e000000) * tc0 slot 1 (0x1e800000) * tc0 slot 2 (0x1f000000) * ioasic0 at tc0 slot 3 offset 0x0 (0x1f800000) * something that has to do with interrupts? (?)(0x1f840000?) * le0 at ioasic0 offset 0xc0000 (0x1f8c0000) * scc0 at ioasic0 offset 0x100000 (0x1f900000) * scc1 at ioasic0 offset 0x180000: console (0x1f980000) * mcclock0 at ioasic0 offset 0x200000: mc146818 or * compatible (0x1fa00000) * asc0 at ioasic0 offset 0x300000: NCR53C94, 25MHz, * SCSI ID 7 (0x1fb00000) */ fatal("TODO: dec_ioasic legacy rewrite\n"); abort(); // machine->md_int.dec_ioasic_data = dev_dec_ioasic_init(cpu, // mem, 0x1f800000, 0); fatal("TODO: kn03 dev_le_init rewrite\n"); abort(); // dev_le_init(machine, mem, KN03_SYS_LANCE, 0, 0, // KN03_INTR_LANCE +8, 4 * 65536); fatal("TODO: dec_ioasic legacy rewrite\n"); abort(); // machine->md_int.dec_ioasic_data->dma_func[3] = // dev_scc_dma_func; // machine->md_int.dec_ioasic_data->dma_func_extra[2] = // dev_scc_init(machine, mem, KN03_SYS_SCC_0, // KN03_INTR_SCC_0 +8, machine->x11_md.in_use, 0, 1); // machine->md_int.dec_ioasic_data->dma_func[2] = // dev_scc_dma_func; // machine->md_int.dec_ioasic_data->dma_func_extra[3] = // dev_scc_init(machine, mem, KN03_SYS_SCC_1, // KN03_INTR_SCC_1 +8, machine->x11_md.in_use, 1, 1); fatal("TODO: mc146818 irq\n"); abort(); // dev_mc146818_init(machine, mem, KN03_SYS_CLOCK, KN03_INT_RTC, // MC146818_DEC, 1); fatal("TODO: asc init rewrite\n"); abort(); // dev_asc_init(machine, mem, KN03_SYS_SCSI, // KN03_INTR_SCSI +8, NULL, DEV_ASC_DEC, NULL, NULL); /* * TURBOchannel slots 0, 1, and 2 are free for * option cards. These are by default filled with * zero or more graphics boards. * * TODO: irqs */ fatal("TODO: turbochannel rewrite init\n"); abort(); #if 0 dev_turbochannel_init(machine, mem, 0, KN03_PHYS_TC_0_START, KN03_PHYS_TC_0_END, machine->n_gfx_cards >= 1? turbochannel_default_gfx_card : "", KN03_INTR_TC_0 +8); dev_turbochannel_init(machine, mem, 1, KN03_PHYS_TC_1_START, KN03_PHYS_TC_1_END, machine->n_gfx_cards >= 2? turbochannel_default_gfx_card : "", KN03_INTR_TC_1 +8); dev_turbochannel_init(machine, mem, 2, KN03_PHYS_TC_2_START, KN03_PHYS_TC_2_END, machine->n_gfx_cards >= 3? turbochannel_default_gfx_card : "", KN03_INTR_TC_2 +8); #endif /* TODO: interrupts */ /* shared (turbochannel) interrupts are +8 */ framebuffer_console_name = "osconsole=0,3"; /* fb,keyb(?) */ serial_console_name = "osconsole=3"; /* ? */ break; case MACHINE_DEC_5800: /* type 5, KN5800 */ machine->machine_name = strdup("DECsystem 5800"); /* TODO: this is incorrect, banks multiply by 8 etc */ if (machine->physical_ram_in_mb < 48) fprintf(stderr, "WARNING! 5800 will probably not run " "with less than 48MB RAM. Continuing anyway.\n"); /* * According to * http://www2.no.netbsd.org/ports/pmax/models.html, * the 5800-series is based on VAX 6000/300. */ /* * Ultrix might support SMP on this machine type. * * Something at 0x10000000. * ssc serial console at 0x10140000, interrupt 2 (shared * with XMI?). * xmi 0 at address 0x11800000 (node x at offset x*0x80000) * Clock uses interrupt 3 (shared with XMI?). */ device_add(machine, "dec5800 addr=0x10000000"); device_add(machine, "decbi addr=0x10000000"); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].dec5800.28", machine->path, machine->bootstrap_cpu); dev_ssc_init(machine, mem, 0x10140000, tmpstr, machine->x11_md.in_use); dev_decxmi_init(mem, 0x11800000); dev_deccca_init(mem, DEC_DECCCA_BASEADDR); break; case MACHINE_DEC_5400: /* type 6, KN210 */ machine->machine_name = strdup("DECsystem 5400 (KN210)"); /* * Misc. info from the KN210 manual: * * Interrupt lines: * irq5 fpu * irq4 halt * irq3 pwrfl -> mer1 -> mer0 -> wear * irq2 100 Hz -> birq7 * irq1 dssi -> ni -> birq6 * irq0 birq5 -> console -> timers -> birq4 * * Interrupt status register at 0x10048000. * Main memory error status register at 0x1008140. * Interval Timer Register (ITR) at 0x10084010. * Q22 stuff at 0x10088000 - 0x1008ffff. * TODR at 0x1014006c. * TCR0 (timer control register 0) 0x10140100. * TIR0 (timer interval register 0) 0x10140104. * TCR1 (timer control register 1) 0x10140110. * TIR1 (timer interval register 1) 0x10140114. * VRR0 (Vector Read Register 0) at 0x16000050. * VRR1 (Vector Read Register 1) at 0x16000054. * VRR2 (Vector Read Register 2) at 0x16000058. * VRR3 (Vector Read Register 3) at 0x1600005c. */ /* ln (ethernet) at 0x10084x00 ? and 0x10120000 ? */ /* error registers (?) at 0x17000000 and 0x10080000 */ /* device_add(machine, "kn210 addr=0x10080000"); */ dev_ssc_init(machine, mem, 0x10140000, "irq? TODO", machine->x11_md.in_use); break; case MACHINE_DEC_MAXINE_5000: /* type 7, KN02CA */ machine->machine_name = strdup("Personal DECstation 5000/xxx " "(MAXINE) (KN02CA)"); if (machine->emulated_hz == 0) machine->emulated_hz = 33000000; if (machine->physical_ram_in_mb < 8) fprintf(stderr, "WARNING! Real KN02CA machines do not " "have less than 8MB RAM. Continuing anyway.\n"); if (machine->physical_ram_in_mb > 40) fprintf(stderr, "WARNING! Real KN02CA machines cannot " "have more than 40MB RAM. Continuing anyway.\n"); /* Maxine interrupts: */ fatal("TODO: Legacy rewrite\n"); abort(); // machine->md_interrupt = maxine_interrupt; /* * Something at address 0xca00000. (?) * Something at address 0xe000000. (?) * tc0 slot 0 (0x10000000) * tc0 slot 1 (0x14000000) * (tc0 slot 2 used by the framebuffer) * ioasic0 at tc0 slot 3 offset 0x0 (0x1c000000) * le0 at ioasic0 offset 0xc0000: address 00:00:00:00:00:00 * (0x1c0c0000) * scc0 at ioasic0 offset 0x100000: console <-- serial * (0x1c100000) * mcclock0 at ioasic0 offset 0x200000: mc146818 (0x1c200000) * isdn at ioasic0 offset 0x240000 not configured (0x1c240000) * bba0 at ioasic0 offset 0x240000 (audio0 at bba0) * ^--- which one of isdn and bba0? * dtop0 at ioasic0 offset 0x280000 (0x1c280000) * fdc at ioasic0 offset 0x2c0000 not configured * ^-- floppy (0x1c2c0000) * asc0 at ioasic0 offset 0x300000: NCR53C94, 25MHz, SCSI * ID 7 (0x1c300000) * xcfb0 at tc0 slot 2 offset 0x0: 1024x768x8 * built-in framebuffer (0xa000000) */ fatal("TODO: dec_ioasic legacy rewrite\n"); abort(); // machine->md_int.dec_ioasic_data = // dev_dec_ioasic_init(cpu, mem, 0x1c000000, 0); fatal("TODO: turbochannel rewrite!\n"); abort(); #if 0 /* TURBOchannel slots (0 and 1): */ dev_turbochannel_init(machine, mem, 0, 0x10000000, 0x103fffff, machine->n_gfx_cards >= 2? turbochannel_default_gfx_card : "", XINE_INTR_TC_0 +8); dev_turbochannel_init(machine, mem, 1, 0x14000000, 0x143fffff, machine->n_gfx_cards >= 3? turbochannel_default_gfx_card : "", XINE_INTR_TC_1 +8); /* * TURBOchannel slot 2 is hardwired to be used by * the framebuffer: (NOTE: 0x8000000, not 0x18000000) */ dev_turbochannel_init(machine, mem, 2, 0x8000000, 0xbffffff, "PMAG-DV", 0); #endif /* * TURBOchannel slot 3: fixed, ioasic * (the system stuff), 0x1c000000 */ fatal("TODO: xine dev_le_init rewrite\n"); abort(); // dev_le_init(machine, mem, 0x1c0c0000, 0, 0, // XINE_INTR_LANCE +8, 4*65536); // dev_scc_init(machine, mem, 0x1c100000, // XINE_INTR_SCC_0 +8, machine->x11_md.in_use, 0, 1); fatal("TODO: mc146818 irq\n"); abort(); // dev_mc146818_init(machine, mem, 0x1c200000, // XINE_INT_TOY, MC146818_DEC, 1); fatal("TODO: xine asc init rewrite\n"); abort(); // dev_asc_init(machine, mem, 0x1c300000, // XINE_INTR_SCSI +8, NULL, DEV_ASC_DEC, NULL, NULL); framebuffer_console_name = "osconsole=3,2"; /* keyb,fb? */ serial_console_name = "osconsole=3"; break; case MACHINE_DEC_5500: /* type 11, KN220 */ machine->machine_name = strdup("DECsystem 5500 (KN220)"); /* * According to NetBSD's pmax ports page: * KN220-AA is a "30 MHz R3000 CPU with R3010 FPU" * with "512 kBytes of Prestoserve battery backed RAM." */ if (machine->emulated_hz == 0) machine->emulated_hz = 30000000; /* * See KN220 docs for more info. * * something at 0x10000000 * something at 0x10001000 * something at 0x10040000 * scc at 0x10140000 * qbus at (or around) 0x10080000 * dssi (disk controller) buffers at 0x10100000, * registers at 0x10160000. * sgec (ethernet) registers at 0x10008000, station * addresss at 0x10120000. * asc (scsi) at 0x17100000. */ dev_ssc_init(machine, mem, 0x10140000, "TODO: irq", machine->x11_md.in_use); /* something at 0x17000000, ultrix says "cpu 0 panic: " "DS5500 I/O Board is missing" if this is not here */ dev_dec5500_ioboard_init(cpu, mem, 0x17000000); dev_sgec_init(mem, 0x10008000, 0); /* irq? */ /* The asc controller might be TURBOchannel-ish? */ #if 0 dev_turbochannel_init(machine, mem, 0, 0x17100000, 0x171fffff, "PMAZ-AA", 0); /* irq? */ #else dev_asc_init(machine, mem, 0x17100000, 0, NULL, DEV_ASC_DEC, NULL, NULL); /* irq? */ #endif framebuffer_console_name = "osconsole=0,0"; /* TODO (?) */ serial_console_name = "osconsole=0"; break; case MACHINE_DEC_MIPSMATE_5100: /* type 12 */ machine->machine_name = strdup("DEC MIPSMATE 5100 (KN230)"); if (machine->emulated_hz == 0) machine->emulated_hz = 20000000; if (machine->physical_ram_in_mb > 128) fprintf(stderr, "WARNING! Real MIPSMATE 5100 machines " "cannot have more than 128MB RAM. Continuing" " anyway.\n"); if (machine->x11_md.in_use) fprintf(stderr, "WARNING! Real MIPSMATE 5100 machines " "cannot have a graphical framebuffer. " "Continuing anyway.\n"); /* KN230 mainbus / interrupt controller: */ snprintf(tmpstr, sizeof(tmpstr), "kn230 addr=0x%" PRIx64, (uint64_t) KN230_SYS_ICSR); device_add(machine, tmpstr); /* * According to NetBSD/pmax: * dc0 at ibus0 addr 0x1c000000 * le0 at ibus0 addr 0x18000000: address 00:00:00:00:00:00 * sii0 at ibus0 addr 0x1a000000 */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%i", machine->path, machine->bootstrap_cpu, 4); dev_mc146818_init(machine, mem, KN230_SYS_CLOCK, tmpstr, MC146818_DEC, 1); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].kn230.0x%x", machine->path, machine->bootstrap_cpu, KN230_CSR_INTR_DZ0); dev_dc7085_init(machine, mem, KN230_SYS_DZ0, tmpstr, machine->x11_md.in_use); /* dev_dc7085_init(machine, mem, KN230_SYS_DZ1, KN230_CSR_INTR_OPT0, machine->x11_md.in_use); */ /* dev_dc7085_init(machine, mem, KN230_SYS_DZ2, KN230_CSR_INTR_OPT1, machine->x11_md.in_use); */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].kn230.0x%x", machine->path, machine->bootstrap_cpu, KN230_CSR_INTR_LANCE); dev_le_init(machine, mem, KN230_SYS_LANCE, KN230_SYS_LANCE_B_START, KN230_SYS_LANCE_B_END, tmpstr, 4*1048576); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].kn230.0x%x", machine->path, machine->bootstrap_cpu, KN230_CSR_INTR_SII); dev_sii_init(machine, mem, KN230_SYS_SII, KN230_SYS_SII_B_START, KN230_SYS_SII_B_END, tmpstr); serial_console_name = "osconsole=0"; break; default:fatal("Unknown DEC machine type: %i\n", machine->machine_subtype); exit(1); } /* * Most OSes on DECstation use physical addresses below * 0x20000000, but both OSF/1 and Sprite use 0xbe...... as if * it was 0x1e......, so we need this hack: */ dev_ram_init(machine, 0xa0000000, 0x20000000, DEV_RAM_MIRROR | DEV_RAM_MIGHT_POINT_TO_DEVICES, 0x0); if (!machine->prom_emulation) return; /* DECstation PROM stuff: (TODO: endianness) */ for (i=0; i<150; i++) store_32bit_word(cpu, DEC_PROM_CALLBACK_STRUCT + i*4, DEC_PROM_EMULATION + i*8); /* Fill PROM with special "magic trap" instructions: */ for (i=0; i<150; i++) { store_32bit_word(cpu, DEC_PROM_EMULATION + i*8, 0x00c0de0c); /* trap instruction */ store_32bit_word(cpu, DEC_PROM_EMULATION + i*8 + 4, 0x00000000); /* nop */ } /* Jumptable at beginning of PROM: also "magic trap" instructions: */ for (i=0; i<0x180; i+=8) { store_32bit_word(cpu, 0xbfc00000 + i, 0x00c0de0c); /* trap instruction */ store_32bit_word(cpu, 0xbfc00000 + i + 4, 0x00000000); /* nop */ } /* * According to dec_prom.h from NetBSD: * * "Programs loaded by the new PROMs pass the following arguments: * a0 argc * a1 argv * a2 DEC_PROM_MAGIC * a3 The callback vector defined below" * * So we try to emulate a PROM, even though no such thing has been * loaded. */ cpu->cd.mips.gpr[MIPS_GPR_A0] = 3; cpu->cd.mips.gpr[MIPS_GPR_A1] = DEC_PROM_INITIAL_ARGV; cpu->cd.mips.gpr[MIPS_GPR_A2] = DEC_PROM_MAGIC; cpu->cd.mips.gpr[MIPS_GPR_A3] = DEC_PROM_CALLBACK_STRUCT; store_32bit_word(cpu, INITIAL_STACK_POINTER + 0x10, BOOTINFO_MAGIC); store_32bit_word(cpu, INITIAL_STACK_POINTER + 0x14, BOOTINFO_ADDR); store_32bit_word(cpu, DEC_PROM_INITIAL_ARGV, (DEC_PROM_INITIAL_ARGV + 0x10)); store_32bit_word(cpu, DEC_PROM_INITIAL_ARGV+4, (DEC_PROM_INITIAL_ARGV + 0x70)); store_32bit_word(cpu, DEC_PROM_INITIAL_ARGV+8, (DEC_PROM_INITIAL_ARGV + 0xe0)); store_32bit_word(cpu, DEC_PROM_INITIAL_ARGV+12, 0); /* * NetBSD and Ultrix expect the boot args to be like this: * * "boot" "bootdev" [args?] * * where bootdev is supposed to be "rz(0,0,0)netbsd" for * 3100/2100 (although that crashes Ultrix :-/), and * "5/rz0a/netbsd" for all others. The number '5' is the * slot number of the boot device. * * 'rz' for disks, 'tz' for tapes. * * TODO: Make this nicer. */ { char bootpath[200]; #if 0 if (machine->machine_subtype == MACHINE_DEC_PMAX_3100) strlcpy(bootpath, "rz(0,0,0)", sizeof(bootpath)); else #endif strlcpy(bootpath, "5/rz1/", sizeof(bootpath)); if (machine->bootdev_id < 0 || machine->force_netboot) { /* tftp boot: */ strlcpy(bootpath, "5/tftp/", sizeof(bootpath)); bootpath[0] = '0' + boot_net_boardnumber; } else { /* disk boot: */ bootpath[0] = '0' + boot_scsi_boardnumber; if (diskimage_is_a_tape(machine, machine->bootdev_id, machine->bootdev_type)) bootpath[2] = 't'; bootpath[4] = '0' + machine->bootdev_id; } init_bootpath = bootpath; } CHECK_ALLOCATION(machine->bootarg = (char *) malloc(BOOTARG_BUFLEN)); strlcpy(machine->bootarg, init_bootpath, BOOTARG_BUFLEN); if (strlcat(machine->bootarg, machine->boot_kernel_filename, BOOTARG_BUFLEN) > BOOTARG_BUFLEN) { fprintf(stderr, "bootarg truncated?\n"); exit(1); } machine->bootstr = strdup("boot"); store_string(cpu, DEC_PROM_INITIAL_ARGV+0x10, machine->bootstr); store_string(cpu, DEC_PROM_INITIAL_ARGV+0x70, machine->bootarg); store_string(cpu, DEC_PROM_INITIAL_ARGV+0xe0, machine->boot_string_argument); /* Decrease the nr of args, if there are no args :-) */ if (machine->boot_string_argument == NULL || machine->boot_string_argument[0] == '\0') cpu->cd.mips.gpr[MIPS_GPR_A0] --; if (machine->boot_string_argument[0] != '\0') { strlcat(machine->bootarg, " ", BOOTARG_BUFLEN); if (strlcat(machine->bootarg, machine->boot_string_argument, BOOTARG_BUFLEN) >= BOOTARG_BUFLEN) { fprintf(stderr, "bootstr truncated?\n"); exit(1); } } xx.a.common.next = (char *)&xx.b - (char *)&xx; xx.a.common.type = BTINFO_MAGIC; xx.a.magic = BOOTINFO_MAGIC; xx.b.common.next = (char *)&xx.c - (char *)&xx.b; xx.b.common.type = BTINFO_BOOTPATH; strlcpy(xx.b.bootpath, machine->bootstr, sizeof(xx.b.bootpath)); xx.c.common.next = 0; xx.c.common.type = BTINFO_SYMTAB; xx.c.nsym = 0; xx.c.ssym = 0; xx.c.esym = machine->file_loaded_end_addr; store_buf(cpu, BOOTINFO_ADDR, (char *)&xx, sizeof(xx)); CHECK_ALLOCATION(machine->md.pmax = (struct machine_pmax *) malloc(sizeof(struct machine_pmax))); memset(machine->md.pmax, 0, sizeof(struct machine_pmax)); /* The system's memmap: */ CHECK_ALLOCATION(machine->md.pmax->memmap = (struct dec_memmap *) malloc(sizeof(struct dec_memmap))); store_32bit_word_in_host(cpu, (unsigned char *)&machine->md.pmax->memmap->pagesize, 4096); for (unsigned int j=0; jmd.pmax->memmap->bitmap); j++) machine->md.pmax->memmap->bitmap[j] = ((int)j * 4096*8 < 1048576*machine->physical_ram_in_mb)? 0xff : 0x00; store_buf(cpu, DEC_MEMMAP_ADDR, (char *)machine->md.pmax->memmap, sizeof(struct dec_memmap)); /* Environment variables: */ addr = DEC_PROM_STRINGS; if (machine->x11_md.in_use && machine->n_gfx_cards > 0) /* (0,3) Keyboard and Framebuffer */ add_environment_string(cpu, framebuffer_console_name, &addr); else /* Serial console */ add_environment_string(cpu, serial_console_name, &addr); /* * The KN5800 (SMP system) uses a CCA (console communications * area): (See VAX 6000 documentation for details.) */ { char tmps[300]; snprintf(tmps, sizeof(tmps), "cca=%" PRIx32, (uint32_t) (DEC_DECCCA_BASEADDR + 0xa0000000ULL)); add_environment_string(cpu, tmps, &addr); } /* These are needed for Sprite to boot: */ { char tmps[500]; snprintf(tmps, sizeof(tmps), "boot=%s", machine->bootarg); tmps[sizeof(tmps)-1] = '\0'; add_environment_string(cpu, tmps, &addr); snprintf(tmps, sizeof(tmps), "bitmap=0x%" PRIx32, (uint32_t) ( (DEC_MEMMAP_ADDR + sizeof(uint32_t) /* skip the page size and point to the memmap */ ) & 0xffffffffULL) ); tmps[sizeof(tmps)-1] = '\0'; add_environment_string(cpu, tmps, &addr); snprintf(tmps, sizeof(tmps), "bitmaplen=0x%" PRIx32, (uint32_t) ( machine->physical_ram_in_mb * 1048576 / 4096 / 8) ); tmps[sizeof(tmps)-1] = '\0'; add_environment_string(cpu, tmps, &addr); } add_environment_string(cpu, "scsiid0=7", &addr); add_environment_string(cpu, "bootmode=a", &addr); add_environment_string(cpu, "testaction=q", &addr); add_environment_string(cpu, "haltaction=h", &addr); add_environment_string(cpu, "more=24", &addr); /* Used in at least Ultrix on the 5100: */ add_environment_string(cpu, "scsiid=7", &addr); add_environment_string(cpu, "baud0=9600", &addr); add_environment_string(cpu, "baud1=9600", &addr); add_environment_string(cpu, "baud2=9600", &addr); add_environment_string(cpu, "baud3=9600", &addr); add_environment_string(cpu, "iooption=0x1", &addr); /* The end: */ add_environment_string(cpu, "", &addr); } MACHINE_DEFAULT_CPU(pmax) { if (machine->machine_subtype > 2) CHECK_ALLOCATION(machine->cpu_name = strdup("R3000A")); if (machine->machine_subtype > 1 && machine->cpu_name == NULL) CHECK_ALLOCATION(machine->cpu_name = strdup("R3000")); if (machine->cpu_name == NULL) CHECK_ALLOCATION(machine->cpu_name = strdup("R2000")); } MACHINE_DEFAULT_RAM(pmax) { switch (machine->machine_subtype) { case MACHINE_DEC_PMAX_3100: machine->physical_ram_in_mb = 24; break; case MACHINE_DEC_3MAX_5000: machine->physical_ram_in_mb = 64; break; default:machine->physical_ram_in_mb = 32; } } MACHINE_REGISTER(pmax) { MR_DEFAULT(pmax, "DECstation/DECsystem", ARCH_MIPS, MACHINE_PMAX); machine_entry_add_alias(me, "decstation"); machine_entry_add_alias(me, "decsystem"); machine_entry_add_alias(me, "dec"); machine_entry_add_subtype(me, "DECstation 3100 (PMAX)", MACHINE_DEC_PMAX_3100, "pmax", "3100", "2100", NULL); machine_entry_add_subtype(me, "DECstation 5000/200 (3MAX)", MACHINE_DEC_3MAX_5000, "3max", "5000/200", NULL); machine_entry_add_subtype(me, "DECstation 5000/1xx (3MIN)", MACHINE_DEC_3MIN_5000, "3min", "5000/1xx", NULL); machine_entry_add_subtype(me, "DECstation 5000 (3MAXPLUS)", MACHINE_DEC_3MAXPLUS_5000, "3maxplus", "3max+", NULL); machine_entry_add_subtype(me, "DECsystem 58x0", MACHINE_DEC_5800, "5800", "58x0", NULL); machine_entry_add_subtype(me, "DECsystem 5400", MACHINE_DEC_5400, "5400", NULL); machine_entry_add_subtype(me, "DECstation Maxine (5000)", MACHINE_DEC_MAXINE_5000, "maxine", NULL); machine_entry_add_subtype(me, "DECsystem 5500", MACHINE_DEC_5500, "5500", NULL); machine_entry_add_subtype(me, "DECstation MipsMate (5100)", MACHINE_DEC_MIPSMATE_5100, "5100", "mipsmate", NULL); me->set_default_ram = machine_default_ram_pmax; } gxemul-0.6.1/src/machines/machine_arc.cc000644 001750 001750 00000020250 13402411502 020342 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: ARC (Advanced RISC Computing) machines */ #include #include #include #include "arcbios.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #define MACHINE_NAME_MAXBUF 100 MACHINE_SETUP(arc) { void *jazz_data; struct memory *mem = machine->memory; char tmpstr[1000]; char tmpstr2[1000]; int i, j; const char *eaddr_string = "eaddr=10:20:30:40:50:60"; /* bogus */ unsigned char macaddr[6]; char *machineName; CHECK_ALLOCATION(machineName = (char *) malloc(MACHINE_NAME_MAXBUF)); cpu->byte_order = EMUL_LITTLE_ENDIAN; snprintf(machineName, MACHINE_NAME_MAXBUF, "ARC"); machine->machine_name = machineName; switch (machine->machine_subtype) { case MACHINE_ARC_JAZZ_PICA: case MACHINE_ARC_JAZZ_MAGNUM: /* * "PICA-61" * * According to NetBSD 1.6.2: * * jazzio0 at mainbus0 * timer0 at jazzio0 addr 0xe0000228 * mcclock0 at jazzio0 addr 0xe0004000: mc146818 or compatible * lpt at jazzio0 addr 0xe0008000 intr 0 not configured * fdc at jazzio0 addr 0xe0003000 intr 1 not configured * MAGNUM at jazzio0 addr 0xe000c000 intr 2 not configured * ALI_S3 at jazzio0 addr 0xe0800000 intr 3 not configured * sn0 at jazzio0 addr 0xe0001000 intr 4: SONIC Ethernet * sn0: Ethernet address 69:6a:6b:6c:00:00 * asc0 at jazzio0 addr 0xe0002000 intr 5: NCR53C94, target 0 * pckbd at jazzio0 addr 0xe0005000 intr 6 not configured * pms at jazzio0 addr 0xe0005000 intr 7 not configured * com0 at jazzio0 addr 0xe0006000 intr 8: ns16550a, * working fifo * com at jazzio0 addr 0xe0007000 intr 9 not configured * jazzisabr0 at mainbus0 * isa0 at jazzisabr0 isa_io_base 0xe2000000 isa_mem_base * 0xe3000000 * * "Microsoft-Jazz", "MIPS Magnum" * * timer0 at jazzio0 addr 0xe0000228 * mcclock0 at jazzio0 addr 0xe0004000: mc146818 or compatible * lpt at jazzio0 addr 0xe0008000 intr 0 not configured * fdc at jazzio0 addr 0xe0003000 intr 1 not configured * MAGNUM at jazzio0 addr 0xe000c000 intr 2 not configured * VXL at jazzio0 addr 0xe0800000 intr 3 not configured * sn0 at jazzio0 addr 0xe0001000 intr 4: SONIC Ethernet * sn0: Ethernet address 69:6a:6b:6c:00:00 * asc0 at jazzio0 addr 0xe0002000 intr 5: NCR53C94, target 0 * scsibus0 at asc0: 8 targets, 8 luns per target * pckbd at jazzio0 addr 0xe0005000 intr 6 not configured * pms at jazzio0 addr 0xe0005000 intr 7 not configured * com0 at jazzio0 addr 0xe0006000 intr 8: ns16550a, * working fifo * com at jazzio0 addr 0xe0007000 intr 9 not configured * jazzisabr0 at mainbus0 * isa0 at jazzisabr0 isa_io_base 0xe2000000 isa_mem_base * 0xe3000000 */ switch (machine->machine_subtype) { case MACHINE_ARC_JAZZ_PICA: strlcat(machineName, " (Microsoft Jazz, Acer PICA-61)", MACHINE_NAME_MAXBUF); break; case MACHINE_ARC_JAZZ_MAGNUM: strlcat(machineName, " (Microsoft Jazz, MIPS Magnum)", MACHINE_NAME_MAXBUF); break; default: fatal("error in machine.c. jazz\n"); exit(1); } jazz_data = device_add(machine, "jazz addr=0x80000000"); /* Keyboard IRQ is jazz.6, mouse is jazz.7 */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].jazz.6", machine->path, machine->bootstrap_cpu); snprintf(tmpstr2, sizeof(tmpstr2), "%s.cpu[%i].jazz.7", machine->path, machine->bootstrap_cpu); i = dev_pckbc_init(machine, mem, 0x80005000ULL, PCKBC_JAZZ, tmpstr, tmpstr2, machine->x11_md.in_use, 0); /* Serial controllers at JAZZ irq 8 and 9: */ snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.cpu[%i].jazz.8 addr=0x80006000" " in_use=%i name2=tty0", machine->path, machine->bootstrap_cpu, machine->x11_md.in_use? 0 : 1); j = (size_t)device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.cpu[%i].jazz.9 addr=0x80007000" " in_use=0 name2=tty1", machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); if (machine->x11_md.in_use) machine->main_console_handle = i; else machine->main_console_handle = j; switch (machine->machine_subtype) { case MACHINE_ARC_JAZZ_PICA: if (machine->x11_md.in_use) { dev_vga_init(machine, mem, 0x400a0000ULL, 0x600003c0ULL, machine->machine_name); arcbios_console_init(machine, 0x400b8000ULL, 0x600003c0ULL); } break; case MACHINE_ARC_JAZZ_MAGNUM: /* PROM mirror? */ dev_ram_init(machine, 0xfff00000, 0x100000, DEV_RAM_MIRROR | DEV_RAM_MIGHT_POINT_TO_DEVICES, 0x1fc00000); /* VXL. TODO */ /* control at 0x60100000? */ dev_fb_init(machine, mem, 0x60200000ULL, VFB_GENERIC, 1024,768, 1024,768, 8, "VXL"); break; } /* SN at JAZZ irq 4 */ snprintf(tmpstr, sizeof(tmpstr), "sn addr=0x80001000 irq=%s.cpu[%i].jazz.4", machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); /* ASC at JAZZ irq 5 */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].jazz.5", machine->path, machine->bootstrap_cpu); dev_asc_init(machine, mem, 0x80002000ULL, tmpstr, NULL, DEV_ASC_PICA, dev_jazz_dma_controller, jazz_data); /* FDC at JAZZ irq 1 */ snprintf(tmpstr, sizeof(tmpstr), "fdc addr=0x80003000 irq=%s.cpu[%i].jazz.1", machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); /* MC146818 at MIPS irq 2: */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2", machine->path, machine->bootstrap_cpu); dev_mc146818_init(machine, mem, 0x80004000ULL, tmpstr, MC146818_ARC_JAZZ, 1); #if 0 Not yet. /* WDC at ISA irq 14 */ device_add(machine, "wdc addr=0x900001f0, irq=38"); #endif break; default:fatal("Unimplemented ARC machine type %i\n", machine->machine_subtype); exit(1); } /* * NOTE: ARCBIOS shouldn't be used before this point. (The only * exception is that arcbios_console_init() may be called.) */ if (!machine->prom_emulation) return; arcbios_init(machine, 0, 0, eaddr_string, macaddr); } MACHINE_DEFAULT_CPU(arc) { switch (machine->machine_subtype) { case MACHINE_ARC_JAZZ_PICA: CHECK_ALLOCATION(machine->cpu_name = strdup("R4000")); break; default: CHECK_ALLOCATION(machine->cpu_name = strdup("R4400")); } } MACHINE_DEFAULT_RAM(arc) { machine->physical_ram_in_mb = 64; } MACHINE_REGISTER(arc) { MR_DEFAULT(arc, "ARC", ARCH_MIPS, MACHINE_ARC); me->set_default_ram = machine_default_ram_arc; machine_entry_add_alias(me, "arc"); machine_entry_add_subtype(me, "Acer PICA-61", MACHINE_ARC_JAZZ_PICA, "pica-61", "acer pica", "pica", NULL); machine_entry_add_subtype(me, "Jazz Magnum", MACHINE_ARC_JAZZ_MAGNUM, "magnum", "jazz magnum", NULL); } gxemul-0.6.1/src/machines/machine_iq80321.cc000644 001750 001750 00000007226 13402411502 020614 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Intel IQ80321 (ARM) */ #include #include #include #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" MACHINE_SETUP(iq80321) { char tmpstr[300]; struct pci_data *pci; /* * Intel IQ80321. See http://sources.redhat.com/ecos/ * docs-latest/redboot/iq80321.html * for more details about the memory map. */ machine->machine_name = strdup("Intel IQ80321"); cpu->cd.arm.coproc[6] = arm_coproc_i80321_6; snprintf(tmpstr, sizeof(tmpstr), "i80321 irq=%s.cpu[%i].irq " "addr=0xffffe000", machine->path, machine->bootstrap_cpu); pci = (struct pci_data *) device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.cpu[%i].irq." "i80321.%i addr=0xfe800000 name2='serial console'", machine->path, machine->bootstrap_cpu, 28); device_add(machine, tmpstr); /* 0xa0000000 = physical ram, 0xc0000000 = uncached */ dev_ram_init(machine, 0xa0000000, 0x20000000, DEV_RAM_MIRROR, 0x0); dev_ram_init(machine, 0xc0000000, 0x20000000, DEV_RAM_MIRROR, 0x0); /* 0xe0000000 and 0xff000000 = cache flush regions */ dev_ram_init(machine, 0xe0000000, 0x100000, DEV_RAM_RAM, 0x0); dev_ram_init(machine, 0xff000000, 0x100000, DEV_RAM_RAM, 0x0); device_add(machine, "iq80321_7seg addr=0xfe840000"); /* TODO: "Intel i82546EB 1000BASE-T Ethernet" */ /* * "Intel 31244 Serial ATA Controller", must be at device 6 according * to NetBSD's iq80321/iq80321_pci.c:iq80321_pci_intr_map(). */ bus_pci_add(machine, pci, machine->memory, 0, 6, 0, "i31244"); if (!machine->prom_emulation) return; arm_setup_initial_translation_table(cpu, 0x4000); arm_translation_table_set_l1(cpu, 0xa0000000, 0xa0000000); arm_translation_table_set_l1(cpu, 0xc0000000, 0xa0000000); arm_translation_table_set_l1(cpu, 0xe0000000, 0xe0000000); arm_translation_table_set_l1(cpu, 0xf0000000, 0xf0000000); } MACHINE_DEFAULT_CPU(iq80321) { machine->cpu_name = strdup("80321_600_2"); } MACHINE_REGISTER(iq80321) { MR_DEFAULT(iq80321, "Intel IQ80321", ARCH_ARM, MACHINE_IQ80321); machine_entry_add_alias(me, "iq80321"); } gxemul-0.6.1/src/machines/machine_playstation2.cc000644 001750 001750 00000014004 13402411502 022226 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Sony PlayStation 2 */ #include #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "diskimage.h" #include "machine.h" #include "memory.h" #include "misc.h" #define PLAYSTATION2_BDA 0xffffffffa0001000ULL #define PLAYSTATION2_OPTARGS 0xffffffff81fff100ULL #define PLAYSTATION2_SIFBIOS 0xffffffffbfc10000ULL static int int_to_bcd(int i) { return (i/10) * 16 + (i % 10); } MACHINE_SETUP(playstation2) { char tmpstr[200]; int tmplen; char *tmp; time_t timet; struct tm *tm_ptr; machine->machine_name = strdup("Playstation 2"); cpu->byte_order = EMUL_LITTLE_ENDIAN; if (machine->physical_ram_in_mb != 32) fprintf(stderr, "WARNING! Playstation 2 machines are supposed " "to have exactly 32 MB RAM. Continuing anyway.\n"); if (!machine->x11_md.in_use) fprintf(stderr, "WARNING! Playstation 2 without -X is pretty " "meaningless. Continuing anyway.\n"); /* * According to NetBSD: * * Hardware irq 0 is timer/interrupt controller * Hardware irq 1 is dma controller * * Some things are not yet emulated (at all), and hence are detected * incorrectly: * * sbus0 at mainbus0: controller type 2 * ohci0 at sbus0 (at 0x1f801600, according to linux) * ohci0: OHCI version 1.0 */ device_add(machine, "ps2 addr=0x10000000"); device_add(machine, "ps2_gs addr=0x12000000"); device_add(machine, "ps2_ether addr=0x14001000"); /* TODO: how much? */ dev_ram_init(machine, 0x1c000000, 4 * 1048576, DEV_RAM_RAM, 0); /* OHCI at SBUS irq 1: */ snprintf(tmpstr, sizeof(tmpstr), "ohci addr=0x1f801600 irq=" "%s.cpu[%i].ps2_sbus.1", machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); /* Set the Harddisk controller present flag, if either disk 0 or 1 is present: */ if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { if (machine->prom_emulation) store_32bit_word(cpu, 0xa0000000 + machine-> physical_ram_in_mb*1048576 - 0x1000 + 0x0, 0x100); device_add(machine, "ps2_spd addr=0x14000000"); } if (!machine->prom_emulation) return; tmplen = 1000; CHECK_ALLOCATION(tmp = (char *) malloc(tmplen)); add_symbol_name(&machine->symbol_context, PLAYSTATION2_SIFBIOS, 0x10000, "[SIFBIOS entry]", 0, 0); store_32bit_word(cpu, PLAYSTATION2_BDA + 0, PLAYSTATION2_SIFBIOS); store_buf(cpu, PLAYSTATION2_BDA + 4, "PS2b", 4); /* "Magic trap" instruction for software PROM emulation: */ store_32bit_word(cpu, PLAYSTATION2_SIFBIOS, 0x00c0de0c); store_32bit_word(cpu, 0xa0000000 + machine->physical_ram_in_mb * 1048576 - 0x1000 + 0x4, PLAYSTATION2_OPTARGS); strlcpy(tmp, "root=/dev/hda1 crtmode=vesa0,60", tmplen); if (machine->boot_string_argument[0]) snprintf(tmp+strlen(tmp), tmplen-strlen(tmp), " %s", machine->boot_string_argument); tmp[tmplen-1] = '\0'; machine->bootstr = tmp; store_string(cpu, PLAYSTATION2_OPTARGS, machine->bootstr); /* TODO: netbsd's bootinfo.h, for symbolic names */ /* RTC data given by the BIOS: */ timet = time(NULL) + 9*3600; /* PS2 uses Japanese time */ tm_ptr = gmtime(&timet); /* TODO: are these 0- or 1-based? */ store_byte(cpu, 0xa0000000 + machine->physical_ram_in_mb * 1048576 - 0x1000 + 0x10 + 1, int_to_bcd(tm_ptr->tm_sec)); store_byte(cpu, 0xa0000000 + machine->physical_ram_in_mb * 1048576 - 0x1000 + 0x10 + 2, int_to_bcd(tm_ptr->tm_min)); store_byte(cpu, 0xa0000000 + machine->physical_ram_in_mb * 1048576 - 0x1000 + 0x10 + 3, int_to_bcd(tm_ptr->tm_hour)); store_byte(cpu, 0xa0000000 + machine->physical_ram_in_mb * 1048576 - 0x1000 + 0x10 + 5, int_to_bcd(tm_ptr->tm_mday)); store_byte(cpu, 0xa0000000 + machine->physical_ram_in_mb * 1048576 - 0x1000 + 0x10 + 6, int_to_bcd(tm_ptr->tm_mon+1)); store_byte(cpu, 0xa0000000 + machine->physical_ram_in_mb * 1048576 - 0x1000 + 0x10 + 7, int_to_bcd(tm_ptr->tm_year-100)); /* "BOOTINFO_PCMCIA_TYPE" in NetBSD's bootinfo.h. This contains the sbus controller type. */ store_32bit_word(cpu, 0xa0000000 + machine->physical_ram_in_mb * 1048576 - 0x1000 + 0x1c, 2); } MACHINE_DEFAULT_CPU(playstation2) { machine->cpu_name = strdup("R5900"); } MACHINE_DEFAULT_RAM(playstation2) { machine->physical_ram_in_mb = 32; } MACHINE_REGISTER(playstation2) { MR_DEFAULT(playstation2, "Playstation 2", ARCH_MIPS, MACHINE_PS2); machine_entry_add_alias(me, "playstation2"); machine_entry_add_alias(me, "ps2"); me->set_default_ram = machine_default_ram_playstation2; } gxemul-0.6.1/src/machines/machine_iyonix.cc000644 001750 001750 00000010332 13402411502 021114 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: A Iyonix machine * * According to NetBSD/iyonix, for Tungsten motherboards: * * 0x90000000 (1 MB) obio * 0x900002f8 = uart1 * 0xa0000000 (8 MB) Flash memory * 0xfe400000 iopxs vbase * * A dmesg can be found at the end of the following URL: * http://www.sarasarado.org/~hatano/diary/d200411.html */ #include #include #include "bus_isa.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/netbsd_iyonix_bootconfig.h" #include "thirdparty/i80321reg.h" MACHINE_SETUP(iyonix) { char tmpstr[1000]; uint32_t bootblock_addr; struct bootconfig bootconfigData; machine->machine_name = strdup("Iyonix"); cpu->cd.arm.coproc[6] = arm_coproc_i80321_6; /* TODO: Is it flash, or just RAM? */ dev_ram_init(machine, 0xa0000000, machine->physical_ram_in_mb * 1048576, DEV_RAM_MIRROR, 0x0); /* Uncached RAM? */ dev_ram_init(machine, 0xc0000000, machine->physical_ram_in_mb * 1048576, DEV_RAM_MIRROR, 0x0); snprintf(tmpstr, sizeof(tmpstr), "i80321 irq=%s.cpu[%i].irq " "addr=0x%08x", machine->path, machine->bootstrap_cpu, (int) VERDE_PMMR_BASE); device_add(machine, tmpstr); /* TODO: actual irq on the i80321! */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].irq.i80321.1", machine->path, machine->bootstrap_cpu); bus_isa_init(machine, tmpstr, 0, 0x90000000ULL, 0x98000000ULL); if (!machine->prom_emulation) return; /* * Set up suitable virtual memory mappings and bootconfig struct * in order to boot a plain NetBSD/iyonix ELF kernel: * * r0 is expected to point to the bootconfig struct. */ arm_setup_initial_translation_table(cpu, machine->physical_ram_in_mb * 1048576 - 65536); arm_translation_table_set_l1(cpu, 0x90000000, 0x90000000); arm_translation_table_set_l1(cpu, 0xf0000000, 0x00000000); arm_translation_table_set_l1_b(cpu, 0xff000000, 0xff000000); bootblock_addr = machine->physical_ram_in_mb * 1048576 - 65536 - 16384; cpu->cd.arm.r[0] = bootblock_addr; memset(&bootconfigData, 0, sizeof(bootconfigData)); store_32bit_word_in_host(cpu, (unsigned char *) &bootconfigData.magic, BOOTCONFIG_MAGIC); store_32bit_word_in_host(cpu, (unsigned char *) &bootconfigData.version, BOOTCONFIG_VERSION); /* TODO: More fields. */ store_buf(cpu, bootblock_addr, (char *)&bootconfigData, sizeof(bootconfigData)); } MACHINE_DEFAULT_CPU(iyonix) { machine->cpu_name = strdup("80321_600_B0"); } MACHINE_DEFAULT_RAM(iyonix) { machine->physical_ram_in_mb = 64; } MACHINE_REGISTER(iyonix) { MR_DEFAULT(iyonix, "Iyonix", ARCH_ARM, MACHINE_IYONIX); machine_entry_add_alias(me, "iyonix"); me->set_default_ram = machine_default_ram_iyonix; } gxemul-0.6.1/src/machines/machine_algor.cc000644 001750 001750 00000010136 13402411502 020703 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Algorithmic P4032 and P5064 evaluation boards */ #include #include #include #include "bus_isa.h" #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" MACHINE_SETUP(algor) { struct pci_data *pci_bus; char tmpstr[300]; machine->emulated_hz = 166560000; switch (machine->machine_subtype) { case MACHINE_ALGOR_P4032: machine->machine_name = strdup("Algor P4032"); break; case MACHINE_ALGOR_P5064: machine->machine_name = strdup("Algor P5064"); break; default:fatal("Unimplemented Algor machine.\n"); exit(1); } /* * Algor CPU interrupts: * * 7 = CPU count/compare * 4 = Local * 3 = PCI * 2 = ISA */ pci_bus = (struct pci_data *) device_add(machine, "v3"); device_add(machine, "algor addr=0x1ff00000"); snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].v3", machine->path, machine->bootstrap_cpu); bus_isa_init(machine, tmpstr, BUS_ISA_EXTERNAL_PIC | BUS_ISA_FDC, 0x1d000000, 0x10000000); /* bus_pci_add(machine, pci_bus, machine->memory, 0, 0, 0, "dec21143"); */ if (!machine->prom_emulation) return; /* NetBSD/algor wants these: */ /* a0 = argc */ cpu->cd.mips.gpr[MIPS_GPR_A0] = 2; /* a1 = argv */ cpu->cd.mips.gpr[MIPS_GPR_A1] = (int32_t)0x9fc01000; store_32bit_word(cpu, (int32_t)0x9fc01000, 0x9fc01040); store_32bit_word(cpu, (int32_t)0x9fc01004, 0x9fc01200); store_32bit_word(cpu, (int32_t)0x9fc01008, 0); machine->bootstr = strdup(machine->boot_kernel_filename); machine->bootarg = strdup(machine->boot_string_argument); store_string(cpu, (int32_t)0x9fc01040, machine->bootstr); store_string(cpu, (int32_t)0x9fc01200, machine->bootarg); /* a2 = pointer to environment strings */ cpu->cd.mips.gpr[MIPS_GPR_A2] = (int32_t)0x9fc01800; { char tmps[50]; store_32bit_word(cpu, (int32_t)0x9fc01800, 0x9fc01900); store_32bit_word(cpu, (int32_t)0x9fc01804, 0x9fc01a00); store_32bit_word(cpu, (int32_t)0x9fc01808, 0); snprintf(tmps, sizeof(tmps), "memsize=0x%08x", machine->physical_ram_in_mb * 1048576); store_string(cpu, (int)0x9fc01900, tmps); store_string(cpu, (int)0x9fc01a00, "ethaddr=10:20:30:30:20:10"); } } MACHINE_DEFAULT_CPU(algor) { machine->cpu_name = strdup("RM5200"); } MACHINE_REGISTER(algor) { MR_DEFAULT(algor, "Algor evaluation board", ARCH_MIPS, MACHINE_ALGOR); machine_entry_add_alias(me, "algor"); machine_entry_add_subtype(me, "P4032", MACHINE_ALGOR_P4032, "p4032", NULL); machine_entry_add_subtype(me, "P5064", MACHINE_ALGOR_P5064, "p5064", NULL); } gxemul-0.6.1/src/machines/machine_pmppc.cc000644 001750 001750 00000005437 13402411502 020726 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Artesyn's PM/PPC board */ #include #include #include #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" MACHINE_SETUP(pmppc) { struct pci_data *pci_data; char tmpstr[300]; /* * NetBSD/pmppc (http://www.netbsd.org/ports/pmppc/) */ machine->machine_name = strdup("Artesyn's PM/PPC board"); /* Bogus default speed = 33 MHz */ if (machine->emulated_hz == 0) machine->emulated_hz = 33000000; /* PM/PPC specific motherboard registers: */ device_add(machine, "pmppc"); /* PCI and Interrupt controller: */ pci_data = (struct pci_data *) device_add(machine, "cpc700"); /* RTC at "ext int 5" = "int 25" in IBM jargon, int 31-25 = 6 for the rest of us. */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].cpc700.%i", machine->path, machine->bootstrap_cpu, 31-25); dev_mc146818_init(machine, machine->memory, 0x7ff00000, tmpstr, MC146818_PMPPC, 1); bus_pci_add(machine, pci_data, machine->memory, 0, 8, 0, "dec21143"); } MACHINE_DEFAULT_CPU(pmppc) { machine->cpu_name = strdup("PPC750"); } MACHINE_REGISTER(pmppc) { MR_DEFAULT(pmppc, "Artesyn's PM/PPC board", ARCH_PPC, MACHINE_PMPPC); machine_entry_add_alias(me, "pmppc"); } gxemul-0.6.1/src/machines/machine_vocore.cc000644 001750 001750 00000005501 13402411502 021074 0ustar00debugdebug000000 000000 /* * Copyright (C) 2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: VoCore */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" MACHINE_SETUP(vocore) { machine->machine_name = strdup("VoCore"); machine->emulated_hz = 360000000; /* Some devices mentioned in the Linux kernel (as shown using strings): i/palmbus@10000000/spi@b00 n/palmbus@10000000/spi@b40 s/palmbus@10000000/uartlite@c00 palmbus@10000000 timer@100 ethernet@10100000 esw@10110000 wmac@10180000 ehci@101c0000 ohci@101c1000 */ device_add(machine, "palmbus addr=0x10000000"); if (!machine->prom_emulation) return; // TODO: uboot emulation? } MACHINE_DEFAULT_CPU(vocore) { // According to http://vocore.io/v1d.html: RT5350, 360 MHz, MIPS 24K // According to Linux booting on my real machine: // CPU revision is: 0001964c (MIPS 24KEc) // Primary instruction cache 32kB, VIPT, 4-way, linesize 32 bytes. // Primary data cache 16kB, 4-way, VIPT, no aliases, linesize 32 bytes machine->cpu_name = strdup("24KEc"); } MACHINE_DEFAULT_RAM(vocore) { machine->physical_ram_in_mb = 32; } MACHINE_REGISTER(vocore) { MR_DEFAULT(vocore, "VoCore", ARCH_MIPS, MACHINE_VOCORE); machine_entry_add_alias(me, "vocore"); me->set_default_ram = machine_default_ram_vocore; } gxemul-0.6.1/src/machines/machine_hpcmips.cc000644 001750 001750 00000036747 13402411502 021262 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Handheld MIPS-based machines */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/hpc_bootinfo.h" #include "thirdparty/vripreg.h" MACHINE_SETUP(hpcmips) { char tmpstr[1000]; struct hpc_bootinfo hpc_bootinfo; int hpc_platid_flags = 0, hpc_platid_cpu_submodel = 0, hpc_platid_cpu_model = 0, hpc_platid_cpu_series = 0, hpc_platid_cpu_arch = 0, hpc_platid_submodel = 0, hpc_platid_model = 0, hpc_platid_series = 0, hpc_platid_vendor = 0; uint64_t hpc_fb_addr = 0; int hpc_fb_bits = 0, hpc_fb_encoding = 0; int hpc_fb_xsize = 0; int hpc_fb_ysize = 0; int hpc_fb_xsize_mem = 0; int hpc_fb_ysize_mem = 0; cpu->byte_order = EMUL_LITTLE_ENDIAN; memset(&hpc_bootinfo, 0, sizeof(hpc_bootinfo)); /* * NOTE: See http://forums.projectmayo.com/viewtopic.php?topic=2743& * forum=23 for info on framebuffer addresses. */ switch (machine->machine_subtype) { case MACHINE_HPCMIPS_CASIO_BE300: /* 166MHz VR4131 */ machine->machine_name = strdup("Casio Cassiopeia BE-300"); hpc_fb_addr = 0x0a200000; hpc_fb_xsize = 240; hpc_fb_ysize = 320; hpc_fb_xsize_mem = 256; hpc_fb_ysize_mem = 320; hpc_fb_bits = 15; hpc_fb_encoding = BIFB_D16_0000; /* TODO: irq? */ snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=0 addr=0x" "0a008680 addr_mult=4 in_use=%i", !machine->x11_md.in_use); machine->main_console_handle = (size_t) device_add(machine, tmpstr); dev_vr41xx_init(machine, machine->memory, 4131); hpc_platid_cpu_arch = 1; /* MIPS */ hpc_platid_cpu_series = 1; /* VR */ hpc_platid_cpu_model = 1; /* VR41XX */ hpc_platid_cpu_submodel = 6; /* VR4131 */ hpc_platid_vendor = 3; /* Casio */ hpc_platid_series = 1; /* CASSIOPEIAE */ hpc_platid_model = 2; /* EXXX */ hpc_platid_submodel = 3; /* E500 */ /* TODO: Don't use model number for E500, it's a BE300! */ break; case MACHINE_HPCMIPS_CASIO_E105: /* 131MHz VR4121 */ machine->machine_name = strdup("Casio Cassiopeia E-105"); hpc_fb_addr = 0x0a200000; /* TODO? */ hpc_fb_xsize = 240; hpc_fb_ysize = 320; hpc_fb_xsize_mem = 256; hpc_fb_ysize_mem = 320; hpc_fb_bits = 16; hpc_fb_encoding = BIFB_D16_0000; /* TODO: irq? */ snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=0 addr=0x" "0a008680 addr_mult=4 in_use=%i", !machine->x11_md.in_use); machine->main_console_handle = (size_t) device_add(machine, tmpstr); dev_vr41xx_init(machine, machine->memory, 4121); hpc_platid_cpu_arch = 1; /* MIPS */ hpc_platid_cpu_series = 1; /* VR */ hpc_platid_cpu_model = 1; /* VR41XX */ hpc_platid_cpu_submodel = 3; /* VR4121 */ hpc_platid_vendor = 3; /* Casio */ hpc_platid_series = 1; /* CASSIOPEIAE */ hpc_platid_model = 2; /* EXXX */ hpc_platid_submodel = 2; /* E105 */ break; case MACHINE_HPCMIPS_NEC_MOBILEPRO_770: /* 131 MHz VR4121 */ machine->machine_name = strdup("NEC MobilePro 770"); hpc_fb_addr = 0xa000000; hpc_fb_xsize = 640; hpc_fb_ysize = 240; hpc_fb_xsize_mem = 800; hpc_fb_ysize_mem = 240; hpc_fb_bits = 16; hpc_fb_encoding = BIFB_D16_0000; dev_vr41xx_init(machine, machine->memory, 4121); hpc_platid_cpu_arch = 1; /* MIPS */ hpc_platid_cpu_series = 1; /* VR */ hpc_platid_cpu_model = 1; /* VR41XX */ hpc_platid_cpu_submodel = 3; /* VR4121 */ hpc_platid_vendor = 1; /* NEC */ hpc_platid_series = 2; /* NEC MCR */ hpc_platid_model = 2; /* MCR 5XX */ hpc_platid_submodel = 4; /* MCR 520A */ break; case MACHINE_HPCMIPS_NEC_MOBILEPRO_780: /* 166 (or 168) MHz VR4121 */ machine->machine_name = strdup("NEC MobilePro 780"); hpc_fb_addr = 0xa180100; hpc_fb_xsize = 640; hpc_fb_ysize = 240; hpc_fb_xsize_mem = 640; hpc_fb_ysize_mem = 240; hpc_fb_bits = 16; hpc_fb_encoding = BIFB_D16_0000; dev_vr41xx_init(machine, machine->memory, 4121); hpc_platid_cpu_arch = 1; /* MIPS */ hpc_platid_cpu_series = 1; /* VR */ hpc_platid_cpu_model = 1; /* VR41XX */ hpc_platid_cpu_submodel = 3; /* VR4121 */ hpc_platid_vendor = 1; /* NEC */ hpc_platid_series = 2; /* NEC MCR */ hpc_platid_model = 2; /* MCR 5XX */ hpc_platid_submodel = 8; /* MCR 530A */ break; case MACHINE_HPCMIPS_NEC_MOBILEPRO_800: /* 131 MHz VR4121 */ machine->machine_name = strdup("NEC MobilePro 800"); hpc_fb_addr = 0xa000000; hpc_fb_xsize = 800; hpc_fb_ysize = 600; hpc_fb_xsize_mem = 800; hpc_fb_ysize_mem = 600; hpc_fb_bits = 16; hpc_fb_encoding = BIFB_D16_0000; dev_vr41xx_init(machine, machine->memory, 4121); hpc_platid_cpu_arch = 1; /* MIPS */ hpc_platid_cpu_series = 1; /* VR */ hpc_platid_cpu_model = 1; /* VR41XX */ hpc_platid_cpu_submodel = 3; /* VR4121 */ hpc_platid_vendor = 1; /* NEC */ hpc_platid_series = 2; /* NEC MCR */ hpc_platid_model = 3; /* MCR 7XX */ hpc_platid_submodel = 2; /* MCR 700A */ break; case MACHINE_HPCMIPS_NEC_MOBILEPRO_880: /* 168 MHz VR4121 */ machine->machine_name = strdup("NEC MobilePro 880"); hpc_fb_addr = 0xa0ea600; hpc_fb_xsize = 800; hpc_fb_ysize = 600; hpc_fb_xsize_mem = 800; hpc_fb_ysize_mem = 600; hpc_fb_bits = 16; hpc_fb_encoding = BIFB_D16_0000; dev_vr41xx_init(machine, machine->memory, 4121); hpc_platid_cpu_arch = 1; /* MIPS */ hpc_platid_cpu_series = 1; /* VR */ hpc_platid_cpu_model = 1; /* VR41XX */ hpc_platid_cpu_submodel = 3; /* VR4121 */ hpc_platid_vendor = 1; /* NEC */ hpc_platid_series = 2; /* NEC MCR */ hpc_platid_model = 3; /* MCR 7XX */ hpc_platid_submodel = 4; /* MCR 730A */ break; case MACHINE_HPCMIPS_AGENDA_VR3: /* 66 MHz VR4181 */ machine->machine_name = strdup("Agenda VR3"); /* TODO: */ hpc_fb_addr = 0x1000; hpc_fb_xsize = 160; hpc_fb_ysize = 240; hpc_fb_xsize_mem = 160; hpc_fb_ysize_mem = 240; hpc_fb_bits = 4; hpc_fb_encoding = BIFB_D4_M2L_F; dev_vr41xx_init(machine, machine->memory, 4181); /* TODO: Hm... irq 17 according to linux, but VRIP_INTR_SIU (=9) here? */ { int x; snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%i addr=0x0c000010", 8+VRIP_INTR_SIU); x = (size_t)device_add(machine, tmpstr); if (!machine->x11_md.in_use) machine->main_console_handle = x; } hpc_platid_cpu_arch = 1; /* MIPS */ hpc_platid_cpu_series = 1; /* VR */ hpc_platid_cpu_model = 1; /* VR41XX */ hpc_platid_cpu_submodel = 4; /* VR4181 */ hpc_platid_vendor = 15; /* Agenda */ hpc_platid_series = 1; /* VR */ hpc_platid_model = 1; /* VR3 */ hpc_platid_submodel = 0; /* - */ dev_ram_init(machine, 0x0f000000, 0x01000000, DEV_RAM_MIRROR | DEV_RAM_MIGHT_POINT_TO_DEVICES, 0x0); break; case MACHINE_HPCMIPS_IBM_WORKPAD_Z50: /* 131 MHz VR4121 */ machine->machine_name = strdup("IBM Workpad Z50"); /* TODO: */ hpc_fb_addr = 0xa000000; hpc_fb_xsize = 640; hpc_fb_ysize = 480; hpc_fb_xsize_mem = 640; hpc_fb_ysize_mem = 480; hpc_fb_bits = 16; hpc_fb_encoding = BIFB_D16_0000; dev_vr41xx_init(machine, machine->memory, 4121); hpc_platid_cpu_arch = 1; /* MIPS */ hpc_platid_cpu_series = 1; /* VR */ hpc_platid_cpu_model = 1; /* VR41XX */ hpc_platid_cpu_submodel = 3; /* VR4121 */ hpc_platid_vendor = 9; /* IBM */ hpc_platid_series = 1; /* WorkPad */ hpc_platid_model = 1; /* Z50 */ hpc_platid_submodel = 0; /* 0 */ break; default:printf("Unimplemented hpcmips machine number.\n"); exit(1); } store_32bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.platid_cpu, (hpc_platid_cpu_arch << 26) + (hpc_platid_cpu_series << 20) + (hpc_platid_cpu_model << 14) + (hpc_platid_cpu_submodel << 8) + hpc_platid_flags); store_32bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo. platid_machine, (hpc_platid_vendor << 22) + (hpc_platid_series<<16) + (hpc_platid_model << 8) + hpc_platid_submodel); if (hpc_fb_addr != 0) { dev_fb_init(machine, machine->memory, hpc_fb_addr, VFB_HPC, hpc_fb_xsize, hpc_fb_ysize, hpc_fb_xsize_mem, hpc_fb_ysize_mem, hpc_fb_bits, machine->machine_name); /* NetBSD/hpcmips uses framebuffer at physical address 0x8.......: */ dev_ram_init(machine, 0x80000000, 0x20000000, DEV_RAM_MIRROR | DEV_RAM_MIGHT_POINT_TO_DEVICES, 0x0); } if (!machine->prom_emulation) return; /* NetBSD/hpcmips and possibly others expects the following: */ cpu->cd.mips.gpr[MIPS_GPR_A0] = 1; /* argc */ cpu->cd.mips.gpr[MIPS_GPR_A1] = machine->physical_ram_in_mb * 1048576 + 0xffffffff80000000ULL - 512; /* argv */ cpu->cd.mips.gpr[MIPS_GPR_A2] = machine->physical_ram_in_mb * 1048576 + 0xffffffff80000000ULL - 256; /* ptr to hpc_bootinfo */ machine->bootstr = machine->boot_kernel_filename; store_32bit_word(cpu, 0x80000000ULL + (machine->physical_ram_in_mb << 20) - 512, 0x80000000ULL + (machine->physical_ram_in_mb << 20) - 512 + 16); store_32bit_word(cpu, 0x80000000ULL + (machine->physical_ram_in_mb << 20) - 512 + 4, 0); store_string(cpu, 0x80000000ULL + (machine->physical_ram_in_mb << 20) - 512 + 16, machine->bootstr); /* Special case for the Agenda VR3: */ if (machine->machine_subtype == MACHINE_HPCMIPS_AGENDA_VR3) { const int tmplen = 1000; char *tmp = (char *) malloc(tmplen); cpu->cd.mips.gpr[MIPS_GPR_A0] = 2; /* argc */ store_32bit_word(cpu, 0x80000000 + machine->physical_ram_in_mb * 1048576-512 + 4, 0x80000000 + machine->physical_ram_in_mb * 1048576 - 512 + 64); store_32bit_word(cpu, 0x80000000 + machine->physical_ram_in_mb * 1048576 - 512 + 8, 0); snprintf(tmp, tmplen, "root=/dev/rom video=vr4181fb:xres:160,y" "res:240,bpp:4,gray,hpck:3084,inv ether=0,0x03fe0300,eth0"); tmp[tmplen-1] = '\0'; if (!machine->x11_md.in_use) snprintf(tmp+strlen(tmp), tmplen-strlen(tmp), " console=ttyS0,115200"); tmp[tmplen-1] = '\0'; if (machine->boot_string_argument[0]) snprintf(tmp+strlen(tmp), tmplen-strlen(tmp), " %s", machine->boot_string_argument); tmp[tmplen-1] = '\0'; store_string(cpu, 0x80000000 + machine->physical_ram_in_mb * 1048576 - 512 + 64, tmp); machine->bootarg = tmp; } else if (machine->boot_string_argument[0]) { cpu->cd.mips.gpr[MIPS_GPR_A0] ++; /* argc */ store_32bit_word(cpu, 0x80000000 + machine->physical_ram_in_mb * 1048576-512 + 4, 0x80000000 + machine->physical_ram_in_mb * 1048576 - 512 + 64); store_32bit_word(cpu, 0x80000000 + machine->physical_ram_in_mb * 1048576 - 512 + 8, 0); store_string(cpu, 0x80000000 + machine->physical_ram_in_mb * 1048576 - 512 + 64, machine->boot_string_argument); machine->bootarg = machine->boot_string_argument; } store_16bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.length, sizeof(hpc_bootinfo)); store_32bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.magic, HPC_BOOTINFO_MAGIC); store_32bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.fb_addr, 0x80000000 + hpc_fb_addr); store_16bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo. fb_line_bytes, hpc_fb_xsize_mem * (((hpc_fb_bits-1)|7)+1) / 8); store_16bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.fb_width, hpc_fb_xsize); store_16bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.fb_height, hpc_fb_ysize); store_16bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.fb_type, hpc_fb_encoding); store_16bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.bi_cnuse, machine->x11_md.in_use? BI_CNUSE_BUILTIN : BI_CNUSE_SERIAL); /* printf("hpc_bootinfo.platid_cpu = 0x%08x\n", hpc_bootinfo.platid_cpu); printf("hpc_bootinfo.platid_machine = 0x%08x\n", hpc_bootinfo.platid_machine); */ store_32bit_word_in_host(cpu,(unsigned char *)&hpc_bootinfo.timezone,0); store_buf(cpu, 0x80000000 + machine->physical_ram_in_mb * 1048576 - 256, (char *)&hpc_bootinfo, sizeof(hpc_bootinfo)); } MACHINE_DEFAULT_CPU(hpcmips) { switch (machine->machine_subtype) { case MACHINE_HPCMIPS_CASIO_BE300: machine->cpu_name = strdup("VR4131"); break; case MACHINE_HPCMIPS_CASIO_E105: machine->cpu_name = strdup("VR4121"); break; case MACHINE_HPCMIPS_NEC_MOBILEPRO_770: case MACHINE_HPCMIPS_NEC_MOBILEPRO_780: case MACHINE_HPCMIPS_NEC_MOBILEPRO_800: case MACHINE_HPCMIPS_NEC_MOBILEPRO_880: machine->cpu_name = strdup("VR4121"); break; case MACHINE_HPCMIPS_AGENDA_VR3: machine->cpu_name = strdup("VR4181"); break; case MACHINE_HPCMIPS_IBM_WORKPAD_Z50: machine->cpu_name = strdup("VR4121"); break; default:printf("Unimplemented HPCMIPS model?\n"); exit(1); } } MACHINE_DEFAULT_RAM(hpcmips) { /* Most have 32 MB by default. */ machine->physical_ram_in_mb = 32; switch (machine->machine_subtype) { case MACHINE_HPCMIPS_CASIO_BE300: machine->physical_ram_in_mb = 16; break; case MACHINE_HPCMIPS_CASIO_E105: machine->physical_ram_in_mb = 32; break; case MACHINE_HPCMIPS_AGENDA_VR3: machine->physical_ram_in_mb = 16; break; } } MACHINE_REGISTER(hpcmips) { MR_DEFAULT(hpcmips, "Handhelp MIPS (HPCmips)", ARCH_MIPS, MACHINE_HPCMIPS); machine_entry_add_alias(me, "hpcmips"); machine_entry_add_subtype(me, "Casio Cassiopeia BE-300", MACHINE_HPCMIPS_CASIO_BE300, "be-300", "be300", NULL); machine_entry_add_subtype(me, "Casio Cassiopeia E-105", MACHINE_HPCMIPS_CASIO_E105, "e-105", "e105", NULL); machine_entry_add_subtype(me, "Agenda VR3", MACHINE_HPCMIPS_AGENDA_VR3, "agenda", "vr3", NULL); machine_entry_add_subtype(me, "IBM WorkPad Z50", MACHINE_HPCMIPS_IBM_WORKPAD_Z50, "workpad", "z50", NULL); machine_entry_add_subtype(me, "NEC MobilePro 770", MACHINE_HPCMIPS_NEC_MOBILEPRO_770, "mobilepro770", NULL); machine_entry_add_subtype(me, "NEC MobilePro 780", MACHINE_HPCMIPS_NEC_MOBILEPRO_780, "mobilepro780", NULL); machine_entry_add_subtype(me, "NEC MobilePro 800", MACHINE_HPCMIPS_NEC_MOBILEPRO_800, "mobilepro800", NULL); machine_entry_add_subtype(me, "NEC MobilePro 880", MACHINE_HPCMIPS_NEC_MOBILEPRO_880, "mobilepro880", NULL); me->set_default_ram = machine_default_ram_hpcmips; } gxemul-0.6.1/src/machines/machine_mvme88k.cc000644 001750 001750 00000014407 13402411502 021103 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2014 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: MVME88K machines (MVME187) * * This is for experiments with OpenBSD/mvme88k. * * MVME187 according to http://mcg.motorola.com/us/products/docs/pdf/187igd.pdf * ("MVME187 RISC Single Board Computer Installation Guide"): * * 88100 MPU, two MC88200 or MC88204 CMMUs (one for data cache and * one for instruction cache). * 82596CA LAN Ethernet * 53C710 SCSI * CD2401 SCC SERIAL IO * PRINTER PORT * MK48T08 BBRAM & CLOCK * EPROM * VME bus * * ... and more details from OpenBSD/mvme88k sources: * * 0xff800000 .. 0xffbfffff = BUG PROM * 0xffe00000 .. 0xffe1ffff = BUG SRAM * 0xfff00000 = PCCTWO * 0xfff40000 = VME bus * 0xfff43000 = MEMC040 (Memory controller) * 0xfff45000 = CD2401 SCC SERIAL IO (cl0) * 0xfff46000 = 82596 Ethernet (ie0) * 0xfff47000 = 53C710 SCSI (osiop0) * 0xfffc0000 = MK48T08 (nvram0) * * Note: It may turn out to be easier to support Lance ethernet (via VME) * than to support the 82596 ethernet controller. */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/mvme187.h" #include "thirdparty/mvme88k_vme.h" #include "thirdparty/mvme_pcctworeg.h" MACHINE_SETUP(mvme88k) { char tmpstr[300]; switch (machine->machine_subtype) { case MACHINE_MVME88K_187: machine->machine_name = strdup("MVME187"); /* The mvme187 device contains 187-specific stuff, such as motherboard registers, and the memory controller: */ device_add(machine, "mvme187"); /* PCC2 bus at 0xfff00000: */ snprintf(tmpstr, sizeof(tmpstr), "pcc2 addr=0x%x", PCC2_BASE); device_add(machine, tmpstr); /* VME2 bus at 0xfff40000: */ snprintf(tmpstr, sizeof(tmpstr), "vme addr=0x%x", VME2_BASE); device_add(machine, tmpstr); /* Cirrus Logic serial console at 0xfff45000: */ snprintf(tmpstr, sizeof(tmpstr), "clmpcc irq=%s.cpu[%i].pcc2 " "addr=0x%08x name2=cl0", machine->path, machine->bootstrap_cpu, 0xfff45000); machine->main_console_handle = (size_t) device_add(machine, tmpstr); /* ie0 ethernet: TODO */ device_add(machine, "unreadable addr=0xfff46000 len=0x1000"); /* 53C710 SCSI at 0xfff47000: */ snprintf(tmpstr, sizeof(tmpstr), "osiop irq=%s.cpu[%i].pcc2.%i " "addr=0x%08x", machine->path, machine->bootstrap_cpu, PCC2V_SCSI, 0xfff47000); device_add(machine, tmpstr); /* MK48T08 clock/nvram at 0xfffc0000: */ snprintf(tmpstr, sizeof(tmpstr), "mk48txx addr=0x%x", 0xfffc0000); device_add(machine, tmpstr); /* VMES (?): TODO */ device_add(machine, "unreadable addr=0xff780000 len=0x80000"); /* VME devices: TODO */ device_add(machine, "unreadable addr=0xffff0000 len=0x10000"); break; case MACHINE_MVME88K_188: machine->machine_name = strdup("MVME188"); /* TODO */ break; case MACHINE_MVME88K_197: machine->machine_name = strdup("MVME197"); /* TODO */ break; default:fatal("Unimplemented MVME88K machine subtype %i\n", machine->machine_subtype); exit(1); } if (!machine->prom_emulation) return; mvmeprom_init(machine); /* * Boot loader args, according to OpenBSD/mvme88k's locore.S: * * r2 = boot flags * r3 = boot controller physical address * r4 = esym * r5 = start of miniroot * r6 = end of miniroot * r7 = ((Clun << 8) | Dlun): encoded bootdev * r8 = board type (0x187, 0x188, 0x197) */ /* Some address beyond the loaded kernel: */ cpu->cd.m88k.r[4] = 6 * 1048576; switch (machine->machine_subtype) { case MACHINE_MVME88K_187: cpu->cd.m88k.r[8] = 0x187; break; case MACHINE_MVME88K_188: cpu->cd.m88k.r[8] = 0x188; break; case MACHINE_MVME88K_197: cpu->cd.m88k.r[8] = 0x197; break; } /* TODO: r3 and r7 must be set correctly to let OpenBSD/mvme88k detect correct boot device. */ } MACHINE_DEFAULT_CPU(mvme88k) { switch (machine->machine_subtype) { case MACHINE_MVME88K_187: case MACHINE_MVME88K_188: machine->cpu_name = strdup("88100"); break; case MACHINE_MVME88K_197: machine->cpu_name = strdup("88110"); break; default:fatal("Unimplemented MVME88K machine subtype %i\n", machine->machine_subtype); exit(1); } } MACHINE_DEFAULT_RAM(mvme88k) { machine->physical_ram_in_mb = 64; } MACHINE_REGISTER(mvme88k) { MR_DEFAULT(mvme88k, "MVME88K", ARCH_M88K, MACHINE_MVME88K); machine_entry_add_alias(me, "mvme88k"); machine_entry_add_subtype(me, "MVME187", MACHINE_MVME88K_187, "mvme187old", NULL); machine_entry_add_subtype(me, "MVME188", MACHINE_MVME88K_188, "mvme188", NULL); machine_entry_add_subtype(me, "MVME197", MACHINE_MVME88K_197, "mvme197", NULL); me->set_default_ram = machine_default_ram_mvme88k; } gxemul-0.6.1/src/machines/.index000644 001750 001750 00000002336 13402411502 016717 0ustar00debugdebug000000 000000 machine_algor.cc Algorithmic P4032 and P5064 evaluation boards machine_alpha.cc DEC Alpha machines machine_arc.cc ARC (Advanced RISC Computing) machines machine_cats.cc Simtec Electronics' CATS board machine_cobalt.cc Cobalt (MIPS-based) machine_dreamcast.cc SEGA Dreamcast machine_evbmips.cc MIPS evaluation boards (e.g. Malta) machine_hpcarm.cc Handheld ARM-based machines machine_hpcmips.cc Handheld MIPS-based machines machine_hpcsh.cc Handheld SuperH-based machines machine_iq80321.cc Intel IQ80321 (ARM) machine_iyonix.cc A Iyonix machine machine_landisk.cc I-O DATA LanDisk USL-5P machine_luna88k.cc LUNA88K machine machine_macppc.cc Generic PowerPC-based Macintosh machines machine_mvme88k.cc MVME88K machines (MVME187) machine_mvmeppc.cc MVMEPPC machines machine_netwinder.cc NetWinder machine_playstation2.cc Sony PlayStation 2 machine_pmax.cc Digital DECstation ("PMAX") machines machine_pmppc.cc Artesyn's PM/PPC board machine_prep.cc Machines conforming to the PowerPC Reference Platform specs machine_qemu.cc Machine mimicing QEMU's default MIPS emulation mode machine_rpi.cc Raspberry Pi machine_sgi.cc Silicon Graphics' MIPS-based machines machine_test.cc Various test machines machine_vocore.cc VoCore gxemul-0.6.1/src/machines/makeautomachine.sh000755 001750 001750 00000004762 13402411502 021306 0ustar00debugdebug000000 000000 #!/bin/sh ############################################################################### # # Copyright (C) 2005-2009 Anders Gavare. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. printf "Generating automachine.cc... " rm -f automachine.cc printf "/*\n * DO NOT EDIT. AUTOMATICALLY CREATED\n */\n\n" >> automachine.cc cat automachine_head.cc >> automachine.cc printf "3" rm -f .index for a in *.cc; do B=`grep COMMENT $a` if [ z"$B" != z ]; then printf "$a " >> .index echo "$B"|cut -d : -f 2- >> .index fi done printf "2" for a in machine_*.cc; do B=`grep MACHINE_REGISTER $a` if [ z"$B" != z ]; then C=`grep MACHINE_REGISTER $a | cut -d \( -f 2|cut -d \) -f 1` for B in $C; do printf "void machine_register_$B(void);\n" >> automachine.cc done fi done cat automachine_middle.cc >> automachine.cc printf "1" for a in machine_*.cc; do B=`grep MACHINE_REGISTER $a` if [ z"$B" != z ]; then C=`grep MACHINE_REGISTER $a | cut -d \( -f 2|cut -d \) -f 1` for B in $C; do printf "\tmachine_register_$B();\n" >> automachine.cc done fi done cat automachine_tail.cc >> automachine.cc printf " done\n" gxemul-0.6.1/src/machines/machine_cobalt.cc000644 001750 001750 00000011602 13402411502 021042 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Cobalt (MIPS-based) */ #include #include #include #include "bus_isa.h" #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" MACHINE_SETUP(cobalt) { char tmpstr[500], tmpstr2[500]; struct pci_data *pci_data; struct memory *mem = machine->memory; cpu->byte_order = EMUL_LITTLE_ENDIAN; machine->machine_name = strdup("Cobalt"); /* * Interrupts seem to be the following: * (according to http://www.funet.fi/pub/Linux/PEOPLE/Linus/v2.4/ * patch-html/patch-2.4.19/linux-2.4.19_arch_mips_cobalt_irq.c.html) * * 2 Galileo chip (timer) * 3 Tulip 0 + NCR SCSI * 4 Tulip 1 * 5 16550 UART (serial console) * 6 VIA southbridge PIC * 7 PCI (Note: Not used. The PCI controller * interrupts at ISA interrupt 9.) */ /* ISA bus at MIPS irq 6: */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].6", machine->path, machine->bootstrap_cpu); bus_isa_init(machine, tmpstr, 0, 0x10000000, 0x14000000 /* TODO */); snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.cpu[%i].5" " addr=0x1c800000 name2=tty0 in_use=1", machine->path, machine->bootstrap_cpu); machine->main_console_handle = (size_t) device_add(machine, tmpstr); /* * According to NetBSD/cobalt: * * pchb0 at pci0 dev 0 function 0: Galileo GT-64111 System Controller, * rev 1 (NOTE: added by dev_gt_init()) * tlp0 at pci0 dev 7 function 0: DECchip 21143 Ethernet, pass 4.1 * Symbios Logic 53c860 (SCSI mass storage, revision 0x02) at pci0 * dev 8 * pcib0 at pci0 dev 9 function 0, VIA Technologies VT82C586 (Apollo * VP) PCI-ISA Bridge, rev 37 * pciide0 at pci0 dev 9 function 1: VIA Technologies VT82C586 (Apollo * VP) ATA33 cr * tlp1 at pci0 dev 12 function 0: DECchip 21143 Ethernet, pass 4.1 * * The PCI controller interrupts at ISA interrupt 9. (TODO?) */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].2", machine->path, machine->bootstrap_cpu); snprintf(tmpstr2, sizeof(tmpstr2), "%s.cpu[%i].6", machine->path, machine->bootstrap_cpu); pci_data = dev_gt_init(machine, mem, 0x14000000, tmpstr, tmpstr2, 11); /* bus_pci_add(machine, pci_data, mem, 0, 7, 0, "dec21143"); */ /* bus_pci_add(machine, pci_data, mem, 0, 8, 0, "symbios_860"); PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_860 */ bus_pci_add(machine, pci_data, mem, 0, 9, 0, "vt82c586_isa"); bus_pci_add(machine, pci_data, mem, 0, 9, 1, "vt82c586_ide"); /* bus_pci_add(machine, pci_data, mem, 0, 12, 0, "dec21143"); */ if (!machine->prom_emulation) return; /* * NetBSD/cobalt expects memsize in a0, but it seems that what * it really wants is the end of memory + 0x80000000. * * The bootstring is stored 512 bytes before the end of * physical ram. */ cpu->cd.mips.gpr[MIPS_GPR_A0] = machine->physical_ram_in_mb * 1048576 + 0xffffffff80000000ULL; machine->bootstr = strdup("root=/dev/hda1 ro"); /* bootstr = "nfsroot=/usr/cobalt/"; */ /* TODO: bootarg, and/or automagic boot device detection */ store_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0] - 512, machine->bootstr); } MACHINE_DEFAULT_CPU(cobalt) { machine->cpu_name = strdup("RM5200"); } MACHINE_DEFAULT_RAM(cobalt) { machine->physical_ram_in_mb = 64; } MACHINE_REGISTER(cobalt) { MR_DEFAULT(cobalt, "Cobalt", ARCH_MIPS, MACHINE_COBALT); machine_entry_add_alias(me, "cobalt"); } gxemul-0.6.1/src/machines/machine_hpcarm.cc000644 001750 001750 00000017250 13402411502 021055 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Handheld ARM-based machines */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/hpc_bootinfo.h" #include "thirdparty/vripreg.h" MACHINE_SETUP(hpcarm) { struct hpc_bootinfo hpc_bootinfo; int hpc_platid_flags = 0, hpc_platid_cpu_submodel = 0, hpc_platid_cpu_model = 0, hpc_platid_cpu_series = 0, hpc_platid_cpu_arch = 0, hpc_platid_submodel = 0, hpc_platid_model = 0, hpc_platid_series = 0, hpc_platid_vendor = 0; uint64_t hpc_fb_addr = 0; int hpc_fb_bits = 0, hpc_fb_encoding = 0; int hpc_fb_xsize = 0; int hpc_fb_ysize = 0; int hpc_fb_xsize_mem = 0; int hpc_fb_ysize_mem = 0; memset(&hpc_bootinfo, 0, sizeof(hpc_bootinfo)); cpu->byte_order = EMUL_LITTLE_ENDIAN; switch (machine->machine_subtype) { case MACHINE_HPCARM_IPAQ: /* SA-1110 206MHz */ machine->machine_name = strdup("Compaq iPAQ H3600"); hpc_fb_addr = 0x48200000; /* TODO */ hpc_fb_xsize = 240; hpc_fb_ysize = 320; hpc_fb_xsize_mem = 256; hpc_fb_ysize_mem = 320; hpc_fb_bits = 15; hpc_fb_encoding = BIFB_D16_0000; hpc_platid_cpu_arch = 3; /* ARM */ hpc_platid_cpu_series = 1; /* StrongARM */ hpc_platid_cpu_model = 2; /* SA-1110 */ hpc_platid_cpu_submodel = 0; hpc_platid_vendor = 7; /* Compaq */ hpc_platid_series = 4; /* IPAQ */ hpc_platid_model = 2; /* H36xx */ hpc_platid_submodel = 1; /* H3600 */ break; case MACHINE_HPCARM_JORNADA720: case MACHINE_HPCARM_JORNADA728: /* SA-1110 206MHz */ machine->machine_name = ((machine->machine_subtype == MACHINE_HPCARM_JORNADA720) ? "Jornada 720" : "Jornada 728"); hpc_fb_addr = 0x48200000; hpc_fb_xsize = 640; hpc_fb_ysize = 240; hpc_fb_xsize_mem = 640; hpc_fb_ysize_mem = 240; hpc_fb_bits = 16; hpc_fb_encoding = BIFB_D16_0000; hpc_platid_cpu_arch = 3; /* ARM */ hpc_platid_cpu_series = 1; /* StrongARM */ hpc_platid_cpu_model = 2; /* SA-1110 */ hpc_platid_cpu_submodel = 0; hpc_platid_vendor = 11; /* HP */ hpc_platid_series = 2; /* Jornada */ hpc_platid_model = 2; /* 7xx */ hpc_platid_submodel = 1; /* 720 */ break; default:printf("Unimplemented hpcarm machine number.\n"); exit(1); } store_32bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.platid_cpu, (hpc_platid_cpu_arch << 26) + (hpc_platid_cpu_series << 20) + (hpc_platid_cpu_model << 14) + (hpc_platid_cpu_submodel << 8) + hpc_platid_flags); store_32bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo. platid_machine,(hpc_platid_vendor << 22) + (hpc_platid_series << 16) + (hpc_platid_model << 8) + hpc_platid_submodel); /* Physical RAM at 0xc0000000: */ dev_ram_init(machine, 0xc0000000, 0x20000000, DEV_RAM_MIRROR, 0x0); /* Cache flush region: */ dev_ram_init(machine, 0xe0000000, 0x10000, DEV_RAM_RAM, 0x0); if (hpc_fb_addr != 0) { dev_fb_init(machine, machine->memory, hpc_fb_addr, VFB_HPC, hpc_fb_xsize, hpc_fb_ysize, hpc_fb_xsize_mem, hpc_fb_ysize_mem, hpc_fb_bits, machine->machine_name); } if (!machine->prom_emulation) return; /* NetBSD/hpcarm and possibly others expects the following: */ cpu->cd.arm.r[0] = 1; /* argc */ cpu->cd.arm.r[1] = machine->physical_ram_in_mb * 1048576 - 512; /*argv*/ cpu->cd.arm.r[2] = machine->physical_ram_in_mb * 1048576 - 256; /* r[2] = ptr to hpc_bootinfo */ machine->bootstr = machine->boot_kernel_filename; store_32bit_word(cpu, machine->physical_ram_in_mb * 1048576 - 512, machine->physical_ram_in_mb * 1048576 - 512 + 16); store_32bit_word(cpu, machine->physical_ram_in_mb * 1048576 - 512 +4,0); store_string(cpu, machine->physical_ram_in_mb * 1048576 - 512 + 16, machine->bootstr); if (machine->boot_string_argument[0]) { cpu->cd.arm.r[0] ++; /* argc */ store_32bit_word(cpu, machine->physical_ram_in_mb * 1048576 - 512 + 4, machine->physical_ram_in_mb * 1048576 - 512 + 64); store_32bit_word(cpu, machine->physical_ram_in_mb * 1048576 - 512 + 8, 0); store_string(cpu, machine->physical_ram_in_mb * 1048576 - 512 + 64, machine->boot_string_argument); machine->bootarg = machine->boot_string_argument; } store_16bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.length, sizeof(hpc_bootinfo)); store_32bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.magic, HPC_BOOTINFO_MAGIC); store_32bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.fb_addr, hpc_fb_addr); store_16bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo. fb_line_bytes, hpc_fb_xsize_mem * (((hpc_fb_bits-1)|7)+1) / 8); store_16bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.fb_width, hpc_fb_xsize); store_16bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.fb_height, hpc_fb_ysize); store_16bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.fb_type, hpc_fb_encoding); store_16bit_word_in_host(cpu, (unsigned char *)&hpc_bootinfo.bi_cnuse, machine->x11_md.in_use? BI_CNUSE_BUILTIN : BI_CNUSE_SERIAL); store_32bit_word_in_host(cpu,(unsigned char *)&hpc_bootinfo.timezone,0); store_buf(cpu, machine->physical_ram_in_mb * 1048576 - 256, (char *)&hpc_bootinfo, sizeof(hpc_bootinfo)); /* TODO: What is a good default stack pointer? */ /* I.e. what does hpcboot.exe for NetBSD/hpcarm usually use? */ cpu->cd.arm.r[ARM_SP] = 0xc02dfff0; } MACHINE_DEFAULT_CPU(hpcarm) { machine->cpu_name = strdup("SA1110"); } MACHINE_DEFAULT_RAM(hpcarm) { switch (machine->machine_subtype) { case MACHINE_HPCARM_JORNADA728: /* 720 has 32 MB, 728 has 64 MB. */ machine->physical_ram_in_mb = 64; break; default: /* Most have 32 MB by default. */ machine->physical_ram_in_mb = 32; } } MACHINE_REGISTER(hpcarm) { MR_DEFAULT(hpcarm, "Handhelp ARM (HPCarm)", ARCH_ARM, MACHINE_HPCARM); machine_entry_add_alias(me, "hpcarm"); machine_entry_add_subtype(me, "Ipaq", MACHINE_HPCARM_IPAQ, "ipaq", NULL); machine_entry_add_subtype(me, "Jornada 720", MACHINE_HPCARM_JORNADA720, "jornada720", NULL); machine_entry_add_subtype(me, "Jornada 728", MACHINE_HPCARM_JORNADA728, "jornada728", NULL); me->set_default_ram = machine_default_ram_hpcarm; } gxemul-0.6.1/src/machines/machine_landisk.cc000644 001750 001750 00000010675 13402411502 021234 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: I-O DATA LanDisk USL-5P * * This machine consists of: * * o) An SH4 processor, which includes serial console etc, * o) 64 MB RAM (at 0x0c000000), * o) an IDE controller at address 0x14000000 (irq 10), * o) a RS5C313 real time clock, connected to the SH4 SCI port, * o) a PCI controller (PCIC), * o) and a minimal SH-IPL+G PROM emulation layer (required to make * OpenBSD/landisk boot). * * TODO: * Realtek NIC (irq 5), PCIIDE (irq 6), USB controllers, etc. * * TODO 2: * Make it possible to select different landisk models. */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/sh4_exception.h" #include "thirdparty/sh4_scireg.h" /* This is not really implemented yet: (experimental) */ /* #define INCLUDE_LANDISK_NIC */ MACHINE_SETUP(landisk) { #ifdef INCLUDE_LANDISK_NIC struct pci_data *pcibus = machine->cpus[machine->bootstrap_cpu]->cd.sh.pcic_pcibus; #endif char tmpstr[300]; machine->machine_name = strdup("Landisk USL-5P"); /* 266.67 MHz SH4 CPU clock: */ if (machine->emulated_hz == 0) machine->emulated_hz = 266666666; /* 33.33 MHz SH4 PCLOCK: */ machine->cpus[machine->bootstrap_cpu]->cd.sh.pclock = 33333333; /* Note: 64 MB RAM at 0x0c000000, not at 0x00000000. */ dev_ram_init(machine, 0x0c000000, 64 * 1048576, DEV_RAM_RAM, 0x0); /* wdc0 at obio0 port 0x14000000-0x1400000f irq 10 */ snprintf(tmpstr, sizeof(tmpstr), "wdc irq=%s.cpu[%i].irq[0x%x]" " addr_mult=2 addr=0x14000000", machine->path, machine->bootstrap_cpu, SH4_INTEVT_IRQ10); device_add(machine, tmpstr); /* rsclock0 at shb0: RS5C313 real time clock */ snprintf(tmpstr, sizeof(tmpstr), "rs5c313 addr=0x%" PRIx64, (uint64_t) SCI_DEVICE_BASE); device_add(machine, tmpstr); #ifdef INCLUDE_LANDISK_NIC /* Realtek PCI NIC: */ bus_pci_add(machine, pcibus, machine->memory, 0, 0, 0, "rtl8139c"); #endif if (!machine->prom_emulation) return; /* * Ugly hardcoded register contents at bootup: * * r4 (arg 0) = boot howto flags * r5 (arg 1) = bootinfo pointer for NetBSD (?) and * symbol end pointer for OpenBSD (?) * * TODO: Make nicer. */ cpu->cd.sh.r[4] = 0; cpu->cd.sh.r[5] = 0x8c000000 + 10 * 1048576; /* Note/TODO: Assuming hardcoded 10 MB kernel size! */ sh_ipl_g_emul_init(machine); } MACHINE_DEFAULT_CPU(landisk) { /* Hitachi SH4 7751R, 266.67 MHz */ machine->cpu_name = strdup("SH7751R"); } MACHINE_DEFAULT_RAM(landisk) { /* Note: This is the size of the boot ROM area, since the Landisk's RAM isn't located at physical address zero. */ machine->physical_ram_in_mb = 2; } MACHINE_REGISTER(landisk) { MR_DEFAULT(landisk, "Landisk", ARCH_SH, MACHINE_LANDISK); me->set_default_ram = machine_default_ram_landisk; machine_entry_add_alias(me, "landisk"); machine_entry_add_alias(me, "usl-5p"); } gxemul-0.6.1/src/machines/machine_rpi.cc000644 001750 001750 00000004711 13402411502 020373 0ustar00debugdebug000000 000000 /* * Copyright (C) 2013 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Raspberry Pi */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" MACHINE_SETUP(rpi) { machine->machine_name = strdup("Raspberry Pi"); if (machine->emulated_hz == 0) machine->emulated_hz = 700000000; if (!machine->prom_emulation) return; arm_setup_initial_translation_table(cpu, 7 * 1048576 - 32768); } MACHINE_DEFAULT_CPU(rpi) { // "700 MHz ARM1176JZF-S core (ARM11 family, ARMv6 instruction set)[3]" // according to Wikipedia. // NOTE/TODO: This is wrong, but should be enough for // starting with simple experiments. machine->cpu_name = strdup("ARM1136JSR1"); } MACHINE_DEFAULT_RAM(rpi) { machine->physical_ram_in_mb = 512; } MACHINE_REGISTER(rpi) { MR_DEFAULT(rpi, "Raspberry Pi", ARCH_ARM, MACHINE_RPI); machine_entry_add_alias(me, "rpi"); me->set_default_ram = machine_default_ram_rpi; } gxemul-0.6.1/src/machines/automachine_middle.cc000644 001750 001750 00000000222 13402411502 021721 0ustar00debugdebug000000 000000 /* * automachine_init(): */ void automachine_init(void) { /* printf("automachine_init()\n"); */ /* automachine_middle.c ends here. */ gxemul-0.6.1/src/machines/machine_mvmeppc.cc000644 001750 001750 00000014311 13402411502 021245 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: MVMEPPC machines * * This is for experiments with NetBSD/mvmeppc. * (ftp://ftp.netbsd.org/pub/NetBSD/arch/mvmeppc/snapshot/20020302/README) * * Note: MVME machines that really adhere to the PReP standard should be * in machine_prep.c instead. * * * TODO: This is mostly bogus. */ #include #include #include #include "bus_isa.h" #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "diskimage.h" #include "machine.h" #include "memory.h" #include "misc.h" MACHINE_SETUP(mvmeppc) { char tmpstr[300], tmpstr2[300];; struct pci_data *pci_data = NULL; switch (machine->machine_subtype) { case MACHINE_MVMEPPC_1600: machine->machine_name = strdup("MVME1600"); snprintf(tmpstr, sizeof(tmpstr), "eagle irq=%s.cpu[%i]", machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); bus_pci_add(machine, pci_data, machine->memory, 0, 14, 0, "dec21143"); device_add(machine, "nvram addr=0x80000074 name2=mvme1600"); /* * "DRAM size register": TODO: turn this into a device? * See the definition of p160x_dram_size in NetBSD's * .../arch/mvmeppc/platform_160x.c for details. * * 0x11 = two banks of 32 MB each. */ dev_ram_init(machine, 0x80000804, 1, DEV_RAM_RAM, 0); store_byte(cpu, 0x80000804, 0x11); break; case MACHINE_MVMEPPC_2100: machine->machine_name = strdup("MVME2100"); /* 0xfe000000 isa bus space */ /* 0xfec00000 pci indirect addr */ /* 0xfee00000 pci indirect data */ /* TODO: irq */ device_add(machine, "ns16550 irq=0 addr=0xffe10000"); break; case MACHINE_MVMEPPC_5500: /* Could possibly be used for RTEMS experiments some day. */ machine->machine_name = strdup("MVME5500"); /* GT64260 interrupt and PCI controller: */ snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i]", machine->path, machine->bootstrap_cpu); snprintf(tmpstr2, sizeof(tmpstr2), "%s.cpu[%i]", machine->path, machine->bootstrap_cpu); pci_data = dev_gt_init(machine, machine->memory, 0xf1000000, tmpstr, // timer irq path: TODO tmpstr2, // ISA irq path: TODO 260); /* TODO: irq */ snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.cpu[%i] addr=0xf1120000", machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); break; default:fatal("Unimplemented MVMEPPC machine subtype %i\n", machine->machine_subtype); exit(1); } if (!machine->prom_emulation) return; /* r3 = start of kernel, r4 = end of kernel (for NetBSD/mvmeppc) */ cpu->cd.ppc.gpr[3] = 0; cpu->cd.ppc.gpr[4] = 1048576 * 10; cpu->cd.ppc.gpr[5] = machine->physical_ram_in_mb * 1048576-0x100; store_string(cpu, cpu->cd.ppc.gpr[5]+ 44, "PC16550"); store_32bit_word(cpu, cpu->cd.ppc.gpr[5]+ 68, 9600); store_32bit_word(cpu, cpu->cd.ppc.gpr[5]+ 72, 0); store_16bit_word(cpu, cpu->cd.ppc.gpr[5]+ 76, 0x1600); store_32bit_word(cpu, cpu->cd.ppc.gpr[5]+ 80, machine->physical_ram_in_mb * 1048576); store_32bit_word(cpu, cpu->cd.ppc.gpr[5]+ 84, 33 * 1000000); store_32bit_word(cpu, cpu->cd.ppc.gpr[5]+ 88, 33 * 1000000); #if 0 0 u_int32_t bi_boothowto; 4 u_int32_t bi_bootaddr; 8 u_int16_t bi_bootclun; 10 u_int16_t bi_bootdlun; 12 char bi_bootline[BOOTLINE_LEN]; (32) 44 char bi_consoledev[CONSOLEDEV_LEN]; (16) 60 u_int32_t bi_consoleaddr; 64 u_int32_t bi_consolechan; 68 u_int32_t bi_consolespeed; 72 u_int32_t bi_consolecflag; 76 u_int16_t bi_modelnumber; 80 u_int32_t bi_memsize; 84 u_int32_t bi_mpuspeed; 88 u_int32_t bi_busspeed; 92 u_int32_t bi_clocktps; #endif } MACHINE_DEFAULT_CPU(mvmeppc) { switch (machine->machine_subtype) { case MACHINE_MVMEPPC_1600: /* Suitable for NetBSD/mvmeppc: */ machine->cpu_name = strdup("PPC603e"); break; case MACHINE_MVMEPPC_2100: machine->cpu_name = strdup("PPC603e"); break; case MACHINE_MVMEPPC_5500: machine->cpu_name = strdup("PPC750"); break; default:fatal("Unimplemented MVMEPPC machine subtype %i\n", machine->machine_subtype); exit(1); } } MACHINE_DEFAULT_RAM(mvmeppc) { machine->physical_ram_in_mb = 64; } MACHINE_REGISTER(mvmeppc) { MR_DEFAULT(mvmeppc, "MVMEPPC", ARCH_PPC, MACHINE_MVMEPPC); machine_entry_add_alias(me, "mvmeppc"); machine_entry_add_subtype(me, "MVME1600", MACHINE_MVMEPPC_1600, "mvme1600", NULL); machine_entry_add_subtype(me, "MVME2100", MACHINE_MVMEPPC_2100, "mvme2100", NULL); machine_entry_add_subtype(me, "MVME5500", MACHINE_MVMEPPC_5500, "mvme5500", NULL); me->set_default_ram = machine_default_ram_mvmeppc; } gxemul-0.6.1/src/machines/machine_macppc.cc000644 001750 001750 00000014446 13402411502 021052 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Generic PowerPC-based Macintosh machines * * See also: * * NetBSD/macppc (http://www.netbsd.org/ports/macppc/) * OpenBSD/macppc (http://www.openbsd.org/macppc.html) * * Currently, these are skeletons for generic PowerMac G3, G4, and G5 systems. * They do not model real PowerMacs, but should be enough to begin * experimenting with running NetBSD/macppc and OpenBSD/macppc. */ #include #include #include #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "of.h" MACHINE_SETUP(macppc) { char tmpstr[300]; struct pci_data *pci_data; struct vfb_data *fb; uint64_t b, a; int i; machine->machine_name = strdup("Macintosh (PPC)"); if (machine->emulated_hz == 0) machine->emulated_hz = 40000000; device_add(machine, "gc addr=0xf3000000"); pci_data = dev_uninorth_init(machine, machine->memory, 0xe2000000, 64 /* isa irq base */, 0 /* pci irq: TODO */); /* bus_pci_add( machine, pci_data, machine->memory, 0, 12, 0, "dec21143"); */ bus_pci_add(machine, pci_data, machine->memory, 0, 15, 0, "gc_obio"); if (machine->x11_md.in_use) bus_pci_add(machine, pci_data, machine->memory, 0, 16, 0, "ati_radeon_9200_2"); snprintf(tmpstr, sizeof(tmpstr), "z8530 addr=0xf3013000 irq=" "%s.cpu[%i].gc.lo.23 addr_mult=0x10", machine->path, machine->bootstrap_cpu); machine->main_console_handle = (size_t)device_add(machine, tmpstr); fb = dev_fb_init(machine, machine->memory, 0xf1000000, VFB_GENERIC | VFB_REVERSE_START, 1024,768, 1024,768, 8, "ofb"); device_add(machine, "hammerhead addr=0xf2800000"); snprintf(tmpstr, sizeof(tmpstr), "adb addr=0xf3016000 irq=" "%s.cpu[%i].gc.lo.1", machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); if (!machine->prom_emulation) return; b = 8 * 1048576; a = b - 0x800; of_emul_init(machine, fb, 0xf1000000, 1024, 768); of_emul_init_uninorth(machine); if (machine->x11_md.in_use) of_emul_init_adb(machine); else of_emul_init_zs(machine); /* * r3 = pointer to boot_args (for the Mach kernel). * See http://darwinsource.opendarwin.org/10.3/ * BootX-59/bootx.tproj/include.subproj/boot_args.h * for more info. */ cpu->cd.ppc.gpr[3] = a; store_16bit_word(cpu, a + 0x0000, 1); /* revision */ store_16bit_word(cpu, a + 0x0002, 2); /* version */ store_buf(cpu, a + 0x0004, machine->boot_string_argument, 256); /* 26 dram banks; "long base; long size" */ store_32bit_word(cpu, a + 0x0104, 0); /* base */ store_32bit_word(cpu, a + 0x0108, machine->physical_ram_in_mb * 256); /* size (in pages) */ for (i=8; i<26*8; i+= 4) store_32bit_word(cpu, a + 0x0104 + i, 0); a += (0x104 + 26 * 8); /* Video info: */ store_32bit_word(cpu, a+0, 0xf1000000); /* video base */ store_32bit_word(cpu, a+4, 0); /* display code (?) */ store_32bit_word(cpu, a+8, 1024); /* bytes per pixel row */ store_32bit_word(cpu, a+12, 1024); /* width */ store_32bit_word(cpu, a+16, 768); /* height */ store_32bit_word(cpu, a+20, 8); /* pixel depth */ a += 24; store_32bit_word(cpu, a+0, 127); /* gestalt number (TODO) */ store_32bit_word(cpu, a+4, 0); /* device tree pointer (TODO)*/ store_32bit_word(cpu, a+8, 0); /* device tree length */ store_32bit_word(cpu, a+12, b); /* last address of kernel data area */ /* r4 = "MOSX" (0x4D4F5358) */ cpu->cd.ppc.gpr[4] = 0x4D4F5358; /* * r5 = OpenFirmware entry point. NOTE: See * cpu_ppc.c for the rest of this semi-ugly hack. */ dev_ram_init(machine, cpu->cd.ppc.of_emul_addr, 0x1000, DEV_RAM_RAM, 0x0); store_32bit_word(cpu, cpu->cd.ppc.of_emul_addr, 0x44ee0002); cpu->cd.ppc.gpr[5] = cpu->cd.ppc.of_emul_addr; #if 0 /* r6 = args */ cpu->cd.ppc.gpr[1] -= 516; cpu->cd.ppc.gpr[6] = cpu->cd.ppc.gpr[1] + 4; store_string(cpu, cpu->cd.ppc.gpr[6], machine->boot_string_argument); /* should be something like '/controller/disk/bsd' */ /* r7 = length? TODO */ cpu->cd.ppc.gpr[7] = 5; #endif } MACHINE_DEFAULT_CPU(macppc) { switch (machine->machine_subtype) { case MACHINE_MACPPC_G3: machine->cpu_name = strdup("PPC750"); break; case MACHINE_MACPPC_G4: machine->cpu_name = strdup("MPC7400"); break; case MACHINE_MACPPC_G5: machine->cpu_name = strdup("PPC970"); break; } } MACHINE_DEFAULT_RAM(macppc) { machine->physical_ram_in_mb = 64; } MACHINE_REGISTER(macppc) { MR_DEFAULT(macppc, "Macintosh", ARCH_PPC, MACHINE_MACPPC); machine_entry_add_alias(me, "macppc"); machine_entry_add_subtype(me, "MacPPC G3", MACHINE_MACPPC_G3, "g3", NULL); machine_entry_add_subtype(me, "MacPPC G4", MACHINE_MACPPC_G4, "g4", NULL); machine_entry_add_subtype(me, "MacPPC G5", MACHINE_MACPPC_G5, "g5", NULL); me->set_default_ram = machine_default_ram_macppc; } gxemul-0.6.1/src/machines/machine_alpha.cc000644 001750 001750 00000020330 13402411502 020661 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: DEC Alpha machines */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/alpha_autoconf.h" #include "thirdparty/alpha_rpb.h" MACHINE_SETUP(alpha) { struct rpb rpb; struct crb crb; struct ctb ctb; struct mddt mddt; struct pcs *pcs = (struct pcs *) malloc(sizeof(struct pcs) * machine->ncpus); int i; switch (machine->machine_subtype) { case ST_ALPHABOOK1: machine->machine_name = strdup("AlphaBook 1"); if (machine->emulated_hz == 0) machine->emulated_hz = 233000000; device_add(machine, "lca"); break; case ST_DEC_4100: machine->machine_name = strdup("AlphaServer 4100"); break; case ST_DEC_3000_300: machine->machine_name = strdup("DEC 3000/300"); machine->main_console_handle = (size_t)device_add(machine, "z8530 addr=0x1b0200000 irq=0 addr_mult=4"); break; case ST_EB164: machine->machine_name = strdup("EB164"); break; default:fatal("Unimplemented Alpha machine type %i\n", machine->machine_subtype); exit(1); } if (!machine->prom_emulation) return; /* These are used by NetBSD/alpha: */ /* a0 = First free Page Frame Number */ /* a1 = PFN of current Level 1 page table */ /* a2 = Bootinfo magic */ /* a3 = Bootinfo pointer */ /* a4 = Bootinfo version */ cpu->cd.alpha.r[ALPHA_A0] = 16*1024*1024 / 8192; cpu->cd.alpha.r[ALPHA_A1] = 0; /* TODO */ cpu->cd.alpha.r[ALPHA_A2] = 0; /* Note: NOT ALPHA_BOOTINFO_MAGIC */ cpu->cd.alpha.r[ALPHA_A3] = 0; /* TODO */ cpu->cd.alpha.r[ALPHA_A4] = 1; /* * HWRPB: Hardware Restart Parameter Block * * TODO: Almost everything. */ memset(&rpb, 0, sizeof(struct rpb)); store_64bit_word_in_host(cpu, (unsigned char *) &(rpb.rpb_phys), 0x14000); strlcpy((char *)&(rpb.rpb_magic), "HWRPB", 8); store_64bit_word_in_host(cpu, (unsigned char *) &(rpb.rpb_version), HWRPB_DSRDB_MINVERS); store_64bit_word_in_host(cpu, (unsigned char *) &(rpb.rpb_size), sizeof(struct rpb)); store_64bit_word_in_host(cpu, (unsigned char *) &(rpb.rpb_page_size), 8192); strlcpy((char *)&(rpb.rpb_ssn), "123456789", 10); store_64bit_word_in_host(cpu, (unsigned char *) &(rpb.rpb_type), machine->machine_subtype); store_64bit_word_in_host(cpu, (unsigned char *) &(rpb.rpb_cc_freq), machine->emulated_hz); store_64bit_word_in_host(cpu, (unsigned char *) &(rpb.rpb_intr_freq), 1024 << 12); store_64bit_word_in_host(cpu, (unsigned char *) &(rpb.rpb_pcs_cnt), machine->ncpus); store_64bit_word_in_host(cpu, (unsigned char *) &(rpb.rpb_pcs_size), sizeof(struct pcs)); store_64bit_word_in_host(cpu, (unsigned char *) &(rpb.rpb_pcs_off), PCS_ADDR - HWRPB_ADDR); store_64bit_word_in_host(cpu, (unsigned char *) &(rpb.rpb_ctb_off), CTB_ADDR - HWRPB_ADDR); store_64bit_word_in_host(cpu, (unsigned char *) &(rpb.rpb_crb_off), CRB_ADDR - HWRPB_ADDR); store_64bit_word_in_host(cpu, (unsigned char *) &(rpb.rpb_memdat_off), MEMDAT_ADDR - HWRPB_ADDR); /* CTB: Console Terminal Block */ memset(&ctb, 0, sizeof(struct ctb)); store_64bit_word_in_host(cpu, (unsigned char *) &(ctb.ctb_term_type), machine->x11_md.in_use? CTB_GRAPHICS : CTB_PRINTERPORT); /* CRB: Console Routine Block */ memset(&crb, 0, sizeof(struct crb)); store_64bit_word_in_host(cpu, (unsigned char *) &(crb.crb_v_dispatch), CRB_ADDR - 0x100); store_64bit_word(cpu, CRB_ADDR - 0x100 + 8, PROM_ENTRY_PADDR); store_64bit_word_in_host(cpu, (unsigned char *) &(crb.crb_v_fixup), CRB_ADDR - 0x80); store_64bit_word(cpu, CRB_ADDR - 0x80 + 8, PROM_ENTRY_PADDR + 0x800); /* PCS: Processor ID etc. */ for (i=0; incpus; i++) { memset(&pcs[i], 0, sizeof(struct pcs)); store_64bit_word_in_host(cpu, (unsigned char *) &(pcs[i].pcs_flags), PCS_RC | PCS_PA | PCS_PP | PCS_CV | PCS_PV | PCS_PMV | PCS_PL); store_64bit_word_in_host(cpu, (unsigned char *) &(pcs[i].pcs_proc_type), machine->cpus[i]->cd.alpha.cpu_type.pcs_type); } /* * MDDT: Memory Data Descriptor Table. For now, it is a simple * two-entry table with half of the available RAM in each entry. * (The values are in number of 8K pages.) * The first 16 MB are not included (the kernel lives there). * The last 1 MB is not included either, it is reserved for bootup * and similar. */ memset(&mddt, 0, sizeof(struct mddt)); memset(&mddt.mddt_clusters[0], 0, sizeof(struct mddt_cluster)); memset(&mddt.mddt_clusters[1], 0, sizeof(struct mddt_cluster)); store_64bit_word_in_host(cpu, (unsigned char *) &(mddt.mddt_cluster_cnt), 2); store_64bit_word_in_host(cpu, (unsigned char *) &(mddt.mddt_clusters[0].mddt_pfn), 16 * 128); store_64bit_word_in_host(cpu, (unsigned char *) &(mddt.mddt_clusters[0].mddt_pg_cnt), (machine->physical_ram_in_mb/2 - 16) * 128); store_64bit_word_in_host(cpu, (unsigned char *) &(mddt.mddt_clusters[1].mddt_pfn), machine->physical_ram_in_mb/2 * 128); store_64bit_word_in_host(cpu, (unsigned char *) &(mddt.mddt_clusters[1].mddt_pg_cnt), (machine->physical_ram_in_mb/2) * 128); /* * Place a special "hack" palcode call at PROM_ENTRY_PADDR and * PROM_ENTRY_PADDR + 0x800: * (Hopefully nothing else will be there.) */ store_32bit_word(cpu, PROM_ENTRY_PADDR, 0x3fffffe); store_32bit_word(cpu, PROM_ENTRY_PADDR + 0x800, 0x3fffffd); store_buf(cpu, HWRPB_ADDR, (char *)&rpb, sizeof(struct rpb)); store_buf(cpu, CTB_ADDR, (char *)&ctb, sizeof(struct ctb)); store_buf(cpu, CRB_ADDR, (char *)&crb, sizeof(struct crb)); store_buf(cpu, MEMDAT_ADDR, (char *)&mddt, sizeof(struct mddt)); store_buf(cpu, PCS_ADDR, (char *)pcs, sizeof(struct pcs) * machine->ncpus); free(pcs); } MACHINE_DEFAULT_CPU(alpha) { switch (machine->machine_subtype) { case ST_ALPHABOOK1: machine->cpu_name = strdup("21066"); break; case ST_DEC_4100: machine->cpu_name = strdup("21164A-2"); break; case ST_DEC_3000_300: machine->cpu_name = strdup("21064"); break; case ST_EB164: machine->cpu_name = strdup("21164PC"); break; default:fatal("Unimplemented Alpha machine type %i\n", machine->machine_subtype); exit(1); } } MACHINE_DEFAULT_RAM(alpha) { machine->physical_ram_in_mb = 128; } MACHINE_REGISTER(alpha) { MR_DEFAULT(alpha, "Alpha", ARCH_ALPHA, MACHINE_ALPHA); machine_entry_add_alias(me, "alpha"); machine_entry_add_subtype(me, "AlphaBook 1", ST_ALPHABOOK1, "alphabook1", NULL); machine_entry_add_subtype(me, "AlphaServer 4100", ST_DEC_4100, "alphaserver4100", NULL); machine_entry_add_subtype(me, "DEC 3000/300", ST_DEC_3000_300, "3000/300", NULL); machine_entry_add_subtype(me, "EB164", ST_EB164, "eb164", NULL); me->set_default_ram = machine_default_ram_alpha; } gxemul-0.6.1/src/machines/machine_prep.cc000644 001750 001750 00000013116 13402411502 020546 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Machines conforming to the PowerPC Reference Platform specs */ #include #include #include #include "bus_isa.h" #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" MACHINE_SETUP(prep) { char tmpstr[300]; struct pci_data *pci_data; const char *model_name = ""; switch (machine->machine_subtype) { case MACHINE_PREP_IBM6050: machine->machine_name = strdup("PowerPC Reference Platform, IBM 6050/6070"); model_name = "IBM PPS Model 6050/6070 (E)"; if (machine->emulated_hz == 0) machine->emulated_hz = 20000000; snprintf(tmpstr, sizeof(tmpstr), "prep irq=%s.cpu[%i]", machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "eagle irq=%s.cpu[%i]", machine->path, machine->bootstrap_cpu); pci_data = (struct pci_data *) device_add(machine, tmpstr); bus_pci_add(machine, pci_data, machine->memory, 0, 13, 0, "dec21143"); if (machine->x11_md.in_use) { bus_pci_add(machine, pci_data, machine->memory, 0, 14, 0, "s3_virge"); } break; case MACHINE_PREP_MVME2400: machine->machine_name = strdup("PowerPC Reference Platform, MVME2400"); /* TODO: _EXACT_ model name for mvme2400? */ model_name = "MOT MVME2400"; snprintf(tmpstr, sizeof(tmpstr), "prep irq=%s.cpu[%i]", machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "eagle irq=%s.cpu[%i]", machine->path, machine->bootstrap_cpu); pci_data = (struct pci_data *) device_add(machine, tmpstr); break; default:fatal("Unimplemented PReP machine subtype %i\n", machine->machine_subtype); exit(1); } if (!machine->prom_emulation) return; /* Linux on PReP has 0xdeadc0de at address 0? (See http://joshua.raleigh.nc.us/docs/linux-2.4.10_html/ 113568.html) */ store_32bit_word(cpu, 0, 0xdeadc0de); /* * r4 should point to first free byte after the loaded kernel. * r6 should point to bootinfo. */ cpu->cd.ppc.gpr[4] = 6 * 1048576; cpu->cd.ppc.gpr[6] = machine->physical_ram_in_mb*1048576-0x8000; /* * (See NetBSD's prep/include/bootinfo.h for details.) * * 32-bit "next" offset; * 32-bit "type"; * type-specific data... */ /* type: clock */ store_32bit_word(cpu, cpu->cd.ppc.gpr[6]+ 0, 12); store_32bit_word(cpu, cpu->cd.ppc.gpr[6]+ 4, 2); store_32bit_word(cpu, cpu->cd.ppc.gpr[6]+ 8, machine->emulated_hz); /* type: console */ store_32bit_word(cpu, cpu->cd.ppc.gpr[6]+12, 20); store_32bit_word(cpu, cpu->cd.ppc.gpr[6]+16, 1); store_buf(cpu, cpu->cd.ppc.gpr[6]+20, machine->x11_md.in_use? "vga":"com", 4); store_32bit_word(cpu, cpu->cd.ppc.gpr[6]+24, 0x3f8);/* addr */ store_32bit_word(cpu, cpu->cd.ppc.gpr[6]+28, 9600);/* speed */ /* type: residual */ store_32bit_word(cpu, cpu->cd.ppc.gpr[6]+32, 0); store_32bit_word(cpu, cpu->cd.ppc.gpr[6]+36, 0); store_32bit_word(cpu, cpu->cd.ppc.gpr[6]+40,/* addr of data */ cpu->cd.ppc.gpr[6] + 0x100); /* Residual data: (TODO) */ store_32bit_word(cpu, cpu->cd.ppc.gpr[6]+0x100, 0x200); store_string(cpu, cpu->cd.ppc.gpr[6]+0x100+0x8, model_name); store_32bit_word(cpu, cpu->cd.ppc.gpr[6]+0x100+0x1f8, machine->physical_ram_in_mb * 1048576); /* memsize */ } MACHINE_DEFAULT_CPU(prep) { switch (machine->machine_subtype) { case MACHINE_PREP_IBM6050: machine->cpu_name = strdup("PPC604"); break; case MACHINE_PREP_MVME2400: machine->cpu_name = strdup("PPC750"); break; default:fatal("Unimplemented PReP machine subtype %i\n", machine->machine_subtype); exit(1); } } MACHINE_DEFAULT_RAM(prep) { machine->physical_ram_in_mb = 64; } MACHINE_REGISTER(prep) { MR_DEFAULT(prep, "PowerPC Reference Platform", ARCH_PPC, MACHINE_PREP); machine_entry_add_alias(me, "prep"); me->set_default_ram = machine_default_ram_prep; machine_entry_add_subtype(me, "IBM 6050/6070", MACHINE_PREP_IBM6050, "ibm6050", "ibm6070", NULL); machine_entry_add_subtype(me, "MVME2400", MACHINE_PREP_MVME2400, "mvme2400", NULL); } gxemul-0.6.1/src/components/README000644 001750 001750 00000001050 13402411502 017055 0ustar00debugdebug000000 000000 How to add a new component: --------------------------- Assuming you want to implement a FooComponent class: 1. Copy a reasonably similar component's .cc file, e.g. MIPS_CPUComponent.cc, to FooComponent.cc. 2. Copy MIPS_CPUComponent.h to FooComponent.h. 3. Substitute all occurances of MIPS_CPUComponent with FooComponent in the .cc and .h files. 4. Edit Makefile.skel to include FooComponent.o among the OBJS to build. Then run make clean_all and ./configure && make test Now you can modify the new component to suit your needs. gxemul-0.6.1/src/components/special/000755 001750 001750 00000000000 13402411502 017621 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/components/machines/000755 001750 001750 00000000000 13402411502 017770 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/components/busses/000755 001750 001750 00000000000 13402411502 017505 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/components/Makefile.skel000644 001750 001750 00000001105 13402411502 020573 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/components # all: do_special do_machines do_busses do_cpu do_memory do_busses: cd busses; $(MAKE) do_cpu: cd cpu; $(MAKE) do_special: cd special; $(MAKE) do_machines: cd machines; $(MAKE) do_memory: cd memory; $(MAKE) clean: cd busses; $(MAKE) clean cd cpu; $(MAKE) clean cd special; $(MAKE) clean cd machines; $(MAKE) clean cd memory; $(MAKE) clean clean_all: clean cd busses; $(MAKE) clean_all cd cpu; $(MAKE) clean_all cd special; $(MAKE) clean_all cd machines; $(MAKE) clean_all cd memory; $(MAKE) clean_all rm -f Makefile gxemul-0.6.1/src/components/cpu/000755 001750 001750 00000000000 13402411502 016770 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/components/memory/000755 001750 001750 00000000000 13402411502 017511 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/components/memory/MemoryMappedComponent.cc000644 001750 001750 00000005744 13402411502 024314 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "components/MemoryMappedComponent.h" MemoryMappedComponent::MemoryMappedComponent(const string& className, const string& visibleClassName) : Component(className, visibleClassName) , m_memoryMappedBase(0) , m_memoryMappedSize(0) , m_memoryMappedAddrMul(1) { AddVariable("memoryMappedBase", &m_memoryMappedBase); AddVariable("memoryMappedSize", &m_memoryMappedSize); AddVariable("memoryMappedAddrMul", &m_memoryMappedAddrMul); } string MemoryMappedComponent::GenerateDetails() const { stringstream ss; ss << Component::GenerateDetails(); const StateVariable* memoryMappedBase = GetVariable("memoryMappedBase"); const StateVariable* memoryMappedSize = GetVariable("memoryMappedSize"); const StateVariable* memoryMappedAddrMul = GetVariable("memoryMappedAddrMul"); if (memoryMappedBase != NULL && memoryMappedSize != NULL) { if (!ss.str().empty()) ss << ", "; uint64_t nBytes = memoryMappedSize->ToInteger(); if (nBytes >= (1 << 30)) ss << (nBytes >> 30) << " GB"; else if (nBytes >= (1 << 20)) ss << (nBytes >> 20) << " MB"; else if (nBytes >= (1 << 10)) ss << (nBytes >> 10) << " KB"; else if (nBytes != 1) ss << nBytes << " bytes"; else ss << nBytes << " byte"; ss << " at offset "; ss.flags(std::ios::hex | std::ios::showbase); ss << memoryMappedBase->ToInteger(); if (memoryMappedAddrMul != NULL && memoryMappedAddrMul->ToInteger() != 1) ss << ", addrmul " << memoryMappedAddrMul->ToInteger(); } return ss.str(); } gxemul-0.6.1/src/components/memory/Makefile.skel000644 001750 001750 00000000426 13402411502 022110 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/components/memory # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(CPEDANTIC) $(INCLUDE2) LIBS=$(OTHERLIBS) OBJS=CacheComponent.o MemoryMappedComponent.o RAMComponent.o all: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) clean_all: clean rm -f Makefile gxemul-0.6.1/src/components/memory/CacheComponent.cc000644 001750 001750 00000023234 13402411502 022712 0ustar00debugdebug000000 000000 /* * Copyright (C) 2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "components/CacheComponent.h" #include "GXemul.h" CacheComponent::CacheComponent(const string& visibleClassName) : Component("cache", visibleClassName) , m_size(0) , m_lineSize(64) , m_lastDumpAddr(0) , m_associativity(1) , m_addressSelect(0) { AddVariable("size", &m_size); AddVariable("lineSize", &m_lineSize); AddVariable("lastDumpAddr", &m_lastDumpAddr); AddVariable("associativity", &m_associativity); // AddCustomVariable("data", &m_dataHandler); } CacheComponent::~CacheComponent() { } refcount_ptr CacheComponent::Create(const ComponentCreateArgs& args) { return new CacheComponent(); } string CacheComponent::GetAttribute(const string& attributeName) { if (attributeName == "stable") return "yes"; if (attributeName == "description") return "A generic memory cache component."; return Component::GetAttribute(attributeName); } string CacheComponent::GenerateDetails() const { stringstream ss; ss << Component::GenerateDetails(); if (!ss.str().empty()) ss << ", "; if (m_size >= (1 << 30)) ss << (m_size >> 30) << " GB"; else if (m_size >= (1 << 20)) ss << (m_size >> 20) << " MB"; else if (m_size >= (1 << 10)) ss << (m_size >> 10) << " KB"; else if (m_size != 1) ss << m_size << " bytes"; else ss << m_size << " byte"; if (m_associativity == 0) ss << ", fully associative, "; else if (m_associativity == 1) ss << ", direct-mapped, "; else ss << ", " << m_associativity << "-way, "; if (m_lineSize >= (1 << 30)) ss << (m_lineSize >> 30) << " GB"; else if (m_lineSize >= (1 << 20)) ss << (m_lineSize >> 20) << " MB"; else if (m_lineSize >= (1 << 10)) ss << (m_lineSize >> 10) << " KB"; else if (m_lineSize != 1) ss << m_lineSize << " bytes"; else ss << m_lineSize << " byte"; ss << " per line"; return ss.str(); } void CacheComponent::ResetState() { } void CacheComponent::GetMethodNames(vector& names) const { // Add our method names... names.push_back("dump"); // ... and make sure to call the base class implementation: Component::GetMethodNames(names); } bool CacheComponent::MethodMayBeReexecutedWithoutArgs(const string& methodName) const { if (methodName == "dump") return true; // ... and make sure to call the base class implementation: return Component::MethodMayBeReexecutedWithoutArgs(methodName); } void CacheComponent::ExecuteMethod(GXemul* gxemul, const string& methodName, const vector& arguments) { if (methodName == "dump") { uint64_t vaddr = m_lastDumpAddr; if (arguments.size() > 1) { gxemul->GetUI()->ShowDebugMessage("syntax: .dump [addr]\n"); return; } if (arguments.size() == 1) { gxemul->GetUI()->ShowDebugMessage("TODO: parse address expression\n"); gxemul->GetUI()->ShowDebugMessage("(for now, only hex immediate values are supported!)\n"); stringstream ss; ss << arguments[0]; ss.flags(std::ios::hex); ss >> vaddr; } const int nRows = 16; for (int i=0; i 0xffffffff) ss << std::setw(16); else ss << std::setw(8); ss << std::setfill('0') << vaddr; size_t k; for (k=0; k= 32 && data[k] < 127? data[k] : '.'; s[1] = '\0'; if (readable[k]) ss << s; else ss << "-"; } ss << "\n"; gxemul->GetUI()->ShowDebugMessage(ss.str()); vaddr += len; } m_lastDumpAddr = vaddr; return; } // Call base... Component::ExecuteMethod(gxemul, methodName, arguments); } AddressDataBus* CacheComponent::AsAddressDataBus() { return this; } void CacheComponent::AddressSelect(uint64_t address) { #if 0 m_addressSelect = address; uint64_t blockNr = address >> m_blockSizeShift; if (blockNr+1 > m_memoryBlocks.size()) m_selectedHostMemoryBlock = NULL; else m_selectedHostMemoryBlock = m_memoryBlocks[blockNr]; m_selectedOffsetWithinBlock = address & (m_blockSize-1); #endif } bool CacheComponent::ReadData(uint8_t& data, Endianness endianness) { #if 0 if (m_selectedHostMemoryBlock == NULL) data = 0; else data = (((uint8_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock]); return true; #endif return false; } bool CacheComponent::ReadData(uint16_t& data, Endianness endianness) { #if 0 assert((m_addressSelect & 1) == 0); if (m_selectedHostMemoryBlock == NULL) data = 0; else data = (((uint16_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock >> 1]); if (endianness == BigEndian) data = BE16_TO_HOST(data); else data = LE16_TO_HOST(data); return true; #endif return false; } bool CacheComponent::ReadData(uint32_t& data, Endianness endianness) { #if 0 assert((m_addressSelect & 3) == 0); if (m_selectedHostMemoryBlock == NULL) data = 0; else data = (((uint32_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock >> 2]); if (endianness == BigEndian) data = BE32_TO_HOST(data); else data = LE32_TO_HOST(data); return true; #endif return false; } bool CacheComponent::ReadData(uint64_t& data, Endianness endianness) { #if 0 assert((m_addressSelect & 7) == 0); if (m_selectedHostMemoryBlock == NULL) data = 0; else data = (((uint64_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock >> 3]); if (endianness == BigEndian) data = BE64_TO_HOST(data); else data = LE64_TO_HOST(data); return true; #endif return false; } bool CacheComponent::WriteData(const uint8_t& data, Endianness endianness) { #if 0 if (m_writeProtected) return false; if (m_selectedHostMemoryBlock == NULL) m_selectedHostMemoryBlock = AllocateBlock(); (((uint8_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock]) = data; return true; #endif return false; } bool CacheComponent::WriteData(const uint16_t& data, Endianness endianness) { #if 0 assert((m_addressSelect & 1) == 0); if (m_writeProtected) return false; if (m_selectedHostMemoryBlock == NULL) m_selectedHostMemoryBlock = AllocateBlock(); uint16_t d; if (endianness == BigEndian) d = BE16_TO_HOST(data); else d = LE16_TO_HOST(data); (((uint16_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock >> 1]) = d; return true; #endif return false; } bool CacheComponent::WriteData(const uint32_t& data, Endianness endianness) { #if 0 assert((m_addressSelect & 3) == 0); if (m_writeProtected) return false; if (m_selectedHostMemoryBlock == NULL) m_selectedHostMemoryBlock = AllocateBlock(); uint32_t d; if (endianness == BigEndian) d = BE32_TO_HOST(data); else d = LE32_TO_HOST(data); (((uint32_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock >> 2]) = d; return true; #endif return false; } bool CacheComponent::WriteData(const uint64_t& data, Endianness endianness) { #if 0 assert((m_addressSelect & 7) == 0); if (m_writeProtected) return false; if (m_selectedHostMemoryBlock == NULL) m_selectedHostMemoryBlock = AllocateBlock(); uint64_t d; if (endianness == BigEndian) d = BE64_TO_HOST(data); else d = LE64_TO_HOST(data); (((uint64_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock >> 3]) = d; return true; #endif return false; } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_CacheComponent_IsStable() { UnitTest::Assert("the CacheComponent should be stable", ComponentFactory::HasAttribute("cache", "stable")); } static void Test_CacheComponent_AddressDataBus() { refcount_ptr ram = ComponentFactory::CreateComponent("cache"); AddressDataBus* bus = ram->AsAddressDataBus(); UnitTest::Assert("The CacheComponent should implement the " "AddressDataBus interface", bus != NULL); } UNITTESTS(CacheComponent) { UNITTEST(Test_CacheComponent_IsStable); UNITTEST(Test_CacheComponent_AddressDataBus); } #endif gxemul-0.6.1/src/components/memory/RAMComponent.cc000644 001750 001750 00000040370 13402411502 022326 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "components/RAMComponent.h" #include "GXemul.h" RAMComponent::RAMComponent(const string& visibleClassName) : MemoryMappedComponent("ram", visibleClassName) , m_blockSizeShift(22) // 22 = 4 MB per block , m_blockSize(1 << m_blockSizeShift) , m_dataHandler(*this) , m_writeProtected(false) , m_lastDumpAddr(0) , m_addressSelect(0) , m_selectedHostMemoryBlock(NULL) , m_selectedOffsetWithinBlock(0) { AddVariable("writeProtect", &m_writeProtected); AddVariable("lastDumpAddr", &m_lastDumpAddr); AddCustomVariable("data", &m_dataHandler); } RAMComponent::~RAMComponent() { ReleaseAllBlocks(); } void RAMComponent::ReleaseAllBlocks() { for (size_t i=0; i RAMComponent::Create(const ComponentCreateArgs& args) { return new RAMComponent(); } string RAMComponent::GetAttribute(const string& attributeName) { if (attributeName == "stable") return "yes"; if (attributeName == "description") return "A generic RAM component."; return MemoryMappedComponent::GetAttribute(attributeName); } void RAMComponent::ResetState() { ReleaseAllBlocks(); } void RAMComponent::GetMethodNames(vector& names) const { // Add our method names... names.push_back("dump"); // ... and make sure to call the base class implementation: Component::GetMethodNames(names); } bool RAMComponent::MethodMayBeReexecutedWithoutArgs(const string& methodName) const { if (methodName == "dump") return true; // ... and make sure to call the base class implementation: return Component::MethodMayBeReexecutedWithoutArgs(methodName); } void RAMComponent::ExecuteMethod(GXemul* gxemul, const string& methodName, const vector& arguments) { if (methodName == "dump") { uint64_t vaddr = m_lastDumpAddr; if (arguments.size() > 1) { gxemul->GetUI()->ShowDebugMessage("syntax: .dump [addr]\n"); return; } if (arguments.size() == 1) { gxemul->GetUI()->ShowDebugMessage("TODO: parse address expression\n"); gxemul->GetUI()->ShowDebugMessage("(for now, only hex immediate values are supported!)\n"); stringstream ss; ss << arguments[0]; ss.flags(std::ios::hex); ss >> vaddr; } const int nRows = 16; for (int i=0; i 0xffffffff) ss << std::setw(16); else ss << std::setw(8); ss << std::setfill('0') << vaddr; size_t k; for (k=0; k= 32 && data[k] < 127? data[k] : '.'; s[1] = '\0'; if (readable[k]) ss << s; else ss << "-"; } ss << "\n"; gxemul->GetUI()->ShowDebugMessage(ss.str()); vaddr += len; } m_lastDumpAddr = vaddr; return; } // Call base... Component::ExecuteMethod(gxemul, methodName, arguments); } AddressDataBus* RAMComponent::AsAddressDataBus() { return this; } void RAMComponent::AddressSelect(uint64_t address) { m_addressSelect = address; uint64_t blockNr = address >> m_blockSizeShift; if (blockNr+1 > m_memoryBlocks.size()) m_selectedHostMemoryBlock = NULL; else m_selectedHostMemoryBlock = m_memoryBlocks[blockNr]; m_selectedOffsetWithinBlock = address & (m_blockSize-1); } void* RAMComponent::AllocateBlock() { void * p = mmap(NULL, m_blockSize, PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0); if (p == MAP_FAILED || p == NULL) { std::cerr << "RAMComponent::AllocateBlock: Could not allocate " << m_blockSize << " bytes. Aborting.\n"; throw std::exception(); } uint64_t blockNr = m_addressSelect >> m_blockSizeShift; if (blockNr+1 > m_memoryBlocks.size()) m_memoryBlocks.resize(blockNr + 1); m_memoryBlocks[blockNr] = p; return p; } bool RAMComponent::ReadData(uint8_t& data, Endianness endianness) { if (m_selectedHostMemoryBlock == NULL) data = 0; else data = (((uint8_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock]); return true; } bool RAMComponent::ReadData(uint16_t& data, Endianness endianness) { assert((m_addressSelect & 1) == 0); if (m_selectedHostMemoryBlock == NULL) data = 0; else data = (((uint16_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock >> 1]); if (endianness == BigEndian) data = BE16_TO_HOST(data); else data = LE16_TO_HOST(data); return true; } bool RAMComponent::ReadData(uint32_t& data, Endianness endianness) { assert((m_addressSelect & 3) == 0); if (m_selectedHostMemoryBlock == NULL) data = 0; else data = (((uint32_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock >> 2]); if (endianness == BigEndian) data = BE32_TO_HOST(data); else data = LE32_TO_HOST(data); return true; } bool RAMComponent::ReadData(uint64_t& data, Endianness endianness) { assert((m_addressSelect & 7) == 0); if (m_selectedHostMemoryBlock == NULL) data = 0; else data = (((uint64_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock >> 3]); if (endianness == BigEndian) data = BE64_TO_HOST(data); else data = LE64_TO_HOST(data); return true; } bool RAMComponent::WriteData(const uint8_t& data, Endianness endianness) { if (m_writeProtected) return false; if (m_selectedHostMemoryBlock == NULL) m_selectedHostMemoryBlock = AllocateBlock(); (((uint8_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock]) = data; return true; } bool RAMComponent::WriteData(const uint16_t& data, Endianness endianness) { assert((m_addressSelect & 1) == 0); if (m_writeProtected) return false; if (m_selectedHostMemoryBlock == NULL) m_selectedHostMemoryBlock = AllocateBlock(); uint16_t d; if (endianness == BigEndian) d = BE16_TO_HOST(data); else d = LE16_TO_HOST(data); (((uint16_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock >> 1]) = d; return true; } bool RAMComponent::WriteData(const uint32_t& data, Endianness endianness) { assert((m_addressSelect & 3) == 0); if (m_writeProtected) return false; if (m_selectedHostMemoryBlock == NULL) m_selectedHostMemoryBlock = AllocateBlock(); uint32_t d; if (endianness == BigEndian) d = BE32_TO_HOST(data); else d = LE32_TO_HOST(data); (((uint32_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock >> 2]) = d; return true; } bool RAMComponent::WriteData(const uint64_t& data, Endianness endianness) { assert((m_addressSelect & 7) == 0); if (m_writeProtected) return false; if (m_selectedHostMemoryBlock == NULL) m_selectedHostMemoryBlock = AllocateBlock(); uint64_t d; if (endianness == BigEndian) d = BE64_TO_HOST(data); else d = LE64_TO_HOST(data); (((uint64_t*)m_selectedHostMemoryBlock) [m_selectedOffsetWithinBlock >> 3]) = d; return true; } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_RAMComponent_IsStable() { UnitTest::Assert("the RAMComponent should be stable", ComponentFactory::HasAttribute("ram", "stable")); } static void Test_RAMComponent_AddressDataBus() { refcount_ptr ram = ComponentFactory::CreateComponent("ram"); AddressDataBus* bus = ram->AsAddressDataBus(); UnitTest::Assert("The RAMComponent should implement the " "AddressDataBus interface", bus != NULL); } static void Test_RAMComponent_InitiallyZero() { refcount_ptr ram = ComponentFactory::CreateComponent("ram"); AddressDataBus* bus = ram->AsAddressDataBus(); bus->AddressSelect(0); // By default, RAM should be zero-filled: uint8_t data8 = 42; bus->ReadData(data8); UnitTest::Assert("A: memory should be zero filled (8)", data8, 0); uint16_t data16 = 142; bus->ReadData(data16, BigEndian); UnitTest::Assert("A: memory should be zero filled (16)", data16, 0); uint32_t data32 = 342; bus->ReadData(data32, BigEndian); UnitTest::Assert("A: memory should be zero filled (32)", data32, 0); uint64_t data64 = 942; bus->ReadData(data64, BigEndian); UnitTest::Assert("A: memory should be zero filled (64)", data64, 0); bus->AddressSelect(0x10000); data8 = 43; bus->ReadData(data8); UnitTest::Assert("B: memory should be zero filled (8)", data8, 0); data16 = 143; bus->ReadData(data16, BigEndian); UnitTest::Assert("B: memory should be zero filled (16)", data16, 0); data32 = 343; bus->ReadData(data32, BigEndian); UnitTest::Assert("B: memory should be zero filled (32)", data32, 0); data64 = 943; bus->ReadData(data64, BigEndian); UnitTest::Assert("B: memory should be zero filled (64)", data64, 0); } static void Test_RAMComponent_WriteThenRead() { refcount_ptr ram = ComponentFactory::CreateComponent("ram"); AddressDataBus* bus = ram->AsAddressDataBus(); bus->AddressSelect(256); uint64_t data64 = ((uint64_t)0x1234567 << 32) | 0x89abcdef; bus->WriteData(data64, BigEndian); uint64_t data64_b = 0; bus->ReadData(data64_b, BigEndian); UnitTest::Assert("memory should be same when read", data64_b, data64); uint32_t data32_b = 0; bus->ReadData(data32_b, BigEndian); UnitTest::Assert("32-bit read should give top 32 bits, " "in big endian mode", data32_b, data64 >> 32); uint16_t data16_b = 0; bus->ReadData(data16_b, BigEndian); UnitTest::Assert("16-bit read should give top 16 bits, " "in big endian mode", data16_b, data64 >> 48); uint8_t data8_b = 0; bus->ReadData(data8_b); UnitTest::Assert("8-bit read should give top 8 bits, " "in big endian mode", data8_b, data64 >> 56); } static void Test_RAMComponent_WriteThenRead_ReverseEndianness() { refcount_ptr ram = ComponentFactory::CreateComponent("ram"); AddressDataBus* bus = ram->AsAddressDataBus(); bus->AddressSelect(256); uint64_t data64 = ((uint64_t)0x1234567 << 32) | 0x89abcdef; bus->WriteData(data64, BigEndian); bus->AddressSelect(256 + 4); uint32_t data32_b = 0; bus->ReadData(data32_b, LittleEndian); UnitTest::Assert("32-bit read", data32_b, 0xefcdab89); uint16_t data16_b = 0; bus->ReadData(data16_b, LittleEndian); UnitTest::Assert("16-bit read", data16_b, 0xab89); uint8_t data8_b = 0; bus->ReadData(data8_b); UnitTest::Assert("8-bit read", data8_b, 0x89); } static void Test_RAMComponent_WriteProtect() { refcount_ptr ram = ComponentFactory::CreateComponent("ram"); AddressDataBus* bus = ram->AsAddressDataBus(); uint32_t data32 = 0x89abcdef; bus->AddressSelect(256); UnitTest::Assert("non-writeprotected write should succeed", bus->WriteData(data32, BigEndian)); uint16_t data16_a = 0; bus->AddressSelect(256 + 2); bus->ReadData(data16_a, BigEndian); UnitTest::Assert("16-bit read", data16_a, 0xcdef); ram->SetVariableValue("writeProtect", "true"); data32 = 0x11223344; bus->AddressSelect(256); UnitTest::Assert("writeprotected write should fail", bus->WriteData(data32, BigEndian) == false); data16_a = 0; bus->AddressSelect(256 + 2); bus->ReadData(data16_a, BigEndian); UnitTest::Assert("16-bit read", data16_a, 0xcdef); ram->SetVariableValue("writeProtect", "false"); data32 = 0x12345678; bus->AddressSelect(256); UnitTest::Assert("write should succeed again", bus->WriteData(data32, BigEndian)); data16_a = 0; bus->AddressSelect(256 + 2); bus->ReadData(data16_a, BigEndian); UnitTest::Assert("16-bit read", data16_a, 0x5678); } static void Test_RAMComponent_ClearOnReset() { refcount_ptr ram = ComponentFactory::CreateComponent("ram"); AddressDataBus* bus = ram->AsAddressDataBus(); uint32_t data32 = 0x89abcdef; bus->AddressSelect(256); bus->WriteData(data32, BigEndian); uint16_t data16_a = 0; bus->AddressSelect(256 + 2); bus->ReadData(data16_a, BigEndian); UnitTest::Assert("16-bit read", data16_a, 0xcdef); ram->Reset(); uint16_t data16_b = 0; bus->AddressSelect(256 + 2); bus->ReadData(data16_b, BigEndian); UnitTest::Assert("reset should have cleared RAM", data16_b, 0x0000); } static void Test_RAMComponent_Clone() { refcount_ptr ram = ComponentFactory::CreateComponent("ram"); AddressDataBus* bus = ram->AsAddressDataBus(); uint32_t data32 = 0x89abcdef; bus->AddressSelect(4); bus->WriteData(data32, BigEndian); uint16_t data16_a = 0x1234; bus->AddressSelect(10); bus->WriteData(data16_a, LittleEndian); UnitTest::Assert("serialization/deserialization failed?", ram->CheckConsistency()); refcount_ptr clone = ram->Clone(); bus = clone->AsAddressDataBus(); data32 = 0x22222222; bus->AddressSelect(4); bus->ReadData(data32, LittleEndian); UnitTest::Assert("32-bit read", data32, 0xefcdab89); data16_a = 0xffff; bus->AddressSelect(10); bus->ReadData(data16_a, BigEndian); UnitTest::Assert("16-bit read", data16_a, 0x3412); } static void Test_RAMComponent_ManualSerialization() { refcount_ptr ram = ComponentFactory::CreateComponent("ram"); AddressDataBus* bus = ram->AsAddressDataBus(); uint32_t data32 = 0x89abcde5; bus->AddressSelect(4); bus->WriteData(data32, BigEndian); uint16_t data16_a = 0x1235; bus->AddressSelect(10); bus->WriteData(data16_a, LittleEndian); SerializationContext context; stringstream ss; ram->Serialize(ss, context); string result = ss.str(); size_t pos = 0; stringstream messages; refcount_ptr ram2 = Component::Deserialize(messages, result, pos); bus = ram2->AsAddressDataBus(); data32 = 0x22222222; bus->AddressSelect(4); bus->ReadData(data32, LittleEndian); UnitTest::Assert("32-bit read", data32, 0xe5cdab89); data16_a = 0xffff; bus->AddressSelect(10); bus->ReadData(data16_a, BigEndian); UnitTest::Assert("16-bit read", data16_a, 0x3512); } static void Test_RAMComponent_Methods_Reexecutableness() { refcount_ptr ram = ComponentFactory::CreateComponent("ram"); UnitTest::Assert("dump method SHOULD be re-executable" " without args", ram->MethodMayBeReexecutedWithoutArgs("dump") == true); UnitTest::Assert("nonexistant method should NOT be re-executable" " without args", ram->MethodMayBeReexecutedWithoutArgs("nonexistant") == false); } UNITTESTS(RAMComponent) { UNITTEST(Test_RAMComponent_IsStable); UNITTEST(Test_RAMComponent_AddressDataBus); UNITTEST(Test_RAMComponent_InitiallyZero); UNITTEST(Test_RAMComponent_WriteThenRead); UNITTEST(Test_RAMComponent_WriteThenRead_ReverseEndianness); UNITTEST(Test_RAMComponent_WriteProtect); UNITTEST(Test_RAMComponent_ClearOnReset); UNITTEST(Test_RAMComponent_Clone); UNITTEST(Test_RAMComponent_ManualSerialization); UNITTEST(Test_RAMComponent_Methods_Reexecutableness); } #endif gxemul-0.6.1/src/components/cpu/Makefile.skel000644 001750 001750 00000000506 13402411502 021366 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/components/cpu # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(CPEDANTIC) $(INCLUDE2) LIBS=$(OTHERLIBS) OBJS=CPUComponent.o CPUDyntransComponent.o \ I960_CPUComponent.o \ M88K_CPUComponent.o \ MIPS_CPUComponent.o all: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) clean_all: clean rm -f Makefile gxemul-0.6.1/src/components/cpu/I960_CPUComponent.cc000644 001750 001750 00000101226 13402411502 022322 0ustar00debugdebug000000 000000 /* * Copyright (C) 2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "ComponentFactory.h" #include "GXemul.h" #include "components/I960_CPUComponent.h" struct reg_instruction { int opcode; const char* mnemonic; bool has_src1; bool has_src2; bool has_dst; bool has_src3; // true if the dst/src field is used as a source }; struct reg_instruction reg_instructions[] = { { 0x580, "notbit", true, true, true, false }, { 0x581, "and", true, true, true, false }, { 0x582, "andnot", true, true, true, false }, { 0x583, "setbit", true, true, true, false }, { 0x584, "notand", true, true, true, false }, { 0x586, "xor", true, true, true, false }, { 0x587, "or", true, true, true, false }, { 0x588, "nor", true, true, true, false }, { 0x589, "xnor", true, true, true, false }, { 0x58a, "not", true, false, true, false }, { 0x58b, "ornot", true, true, true, false }, { 0x58c, "clrbit", true, true, true, false }, { 0x58d, "notor", true, true, true, false }, { 0x58e, "nand", true, true, true, false }, { 0x58f, "alterbit", true, true, true, false }, { 0x590, "addo", true, true, true, false }, { 0x591, "addi", true, true, true, false }, { 0x592, "subo", true, true, true, false }, { 0x593, "subi", true, true, true, false }, { 0x598, "shro", true, true, true, false }, { 0x59a, "shrdi", true, true, true, false }, { 0x59b, "shri" , true, true, true, false }, { 0x59c, "shlo", true, true, true, false }, { 0x59d, "rotate", true, true, true, false }, { 0x59e, "shli", true, true, true, false }, { 0x5a0, "cmpo", true, true, false, false }, { 0x5a1, "cmpi", true, true, false, false }, { 0x5a2, "concmpo", true, true, false, false }, { 0x5a3, "concmpi", true, true, false, false }, { 0x5a4, "cmpinco", true, true, true, false }, { 0x5a5, "cmpinci", true, true, true, false }, { 0x5a6, "cmpdeco", true, true, true, false }, { 0x5a7, "cmpdeci", true, true, true, false }, { 0x5ac, "scanbyte", true, true, false, false }, { 0x5ae, "chkbit", true, true, false, false }, { 0x5b0, "addc", true, true, true, false }, { 0x5b2, "subc", true, true, true, false }, { 0x5cc, "mov", true, false, true, false }, { 0x5d8, "eshro", true, true, true, false }, { 0x5dc, "movl", true, false, true, false }, { 0x5ec, "movt", true, false, true, false }, { 0x5fc, "movq", true, false, true, false }, { 0x630, "sdma", true, true, true, true }, { 0x631, "udma", false, false, false, false }, { 0x640, "spanbit", true, false, true, false }, { 0x641, "scanbit", true, false, true, false }, { 0x645, "modac", true, true, true, true }, { 0x650, "modify", true, true, true, true }, { 0x651, "extract", true, true, true, true }, { 0x654, "modtc", true, true, true, true }, { 0x655, "modpc", true, true, true, true }, { 0x659, "sysctl", true, true, true, true }, { 0x660, "calls", true, false, false, false }, { 0x66b, "mark", false, false, false, false }, { 0x66c, "fmark", false, false, false, false }, { 0x66d, "flushreg", false, false, false, false }, { 0x66f, "syncf", false, false, false, false }, { 0x670, "emul", true, true, true, false }, { 0x671, "ediv", true, true, true, false }, { 0x701, "mulo", true, true, true, false }, { 0x708, "remo", true, true, true, false }, { 0x70b, "divo", true, true, true, false }, { 0x741, "muli", true, true, true, false }, { 0x748, "remi", true, true, true, false }, { 0x749, "modi", true, true, true, false }, { 0x74b, "divi", true, true, true, false }, { 0, NULL, false, false, false, false } }; I960_CPUComponent::I960_CPUComponent() : CPUDyntransComponent("i960_cpu", "i960") { m_frequency = 25e6; m_isBigEndian = false; m_model = "i960CA"; ResetState(); AddVariable("model", &m_model); for (size_t i = 0; i < N_I960_REGS; i++) { AddVariable(i960_regnames[i], &m_r[i]); } for (size_t i = 0; i < N_I960_SFRS; i++) { stringstream ss; ss << "sfr" << i; AddVariable(ss.str(), &m_sfr[i]); } AddVariable("i960_ac", &m_i960_ac); AddVariable("i960_pc", &m_i960_pc); AddVariable("i960_tc", &m_i960_tc); AddVariable("nr_of_valid_sfrs", &m_nr_of_valid_sfrs); } refcount_ptr I960_CPUComponent::Create(const ComponentCreateArgs& args) { // Defaults: ComponentCreationSettings settings; settings["model"] = "i960CA"; if (!ComponentFactory::GetCreationArgOverrides(settings, args)) return NULL; refcount_ptr cpu = new I960_CPUComponent(); if (!cpu->SetVariableValue("model", "\"" + settings["model"] + "\"")) return NULL; return cpu; } static string regname_or_literal(int reg, int m, int s) { // Regular g or r registers if (m == 0 && s == 0) return i960_regnames[reg]; stringstream ss; if (m != 0 && s == 0) { // Literal ss << reg; } else if (m == 0 && s != 0) { // Special Function Register ss << "sfr" << reg; } else { ss << "reserved" << reg; } return ss.str(); } void I960_CPUComponent::ResetState() { m_pageSize = 4096; for (size_t i=0; iGetUI()->ShowDebugMessage(this, "the pc register" " can not have bit 0 or 1 set!\n"); return false; } return CPUDyntransComponent::PreRunCheckForComponent(gxemul); } bool I960_CPUComponent::CheckVariableWrite(StateVariable& var, const string& oldValue) { // UI* ui = GetUI(); return CPUDyntransComponent::CheckVariableWrite(var, oldValue); } void I960_CPUComponent::ShowRegisters(GXemul* gxemul, const vector& arguments) const { stringstream ss; ss.flags(std::ios::hex); ss << " ip = 0x" << std::setfill('0') << std::setw(8) << (uint32_t)m_pc; string symbol = GetSymbolRegistry().LookupAddress(m_pc, true); if (symbol != "") ss << " <" << symbol << ">"; ss << "\n"; for (size_t i = 0; i < N_I960_REGS; i++) { ss << std::setfill(' ') << std::setw(4) << i960_regnames[i] << " = 0x" << std::setfill('0') << std::setw(8) << m_r[i]; if ((i&3) == 3) ss << "\n"; else ss << " "; } for (size_t i = 0; i < m_nr_of_valid_sfrs; i++) { stringstream name; name << "sfr" << i; ss << std::setfill(' ') << std::setw(6) << name.str() << " = 0x" << std::setfill('0') << std::setw(8) << m_sfr[i]; if ((i&3) == 3) ss << "\n"; else ss << " "; } gxemul->GetUI()->ShowDebugMessage(ss.str()); } int I960_CPUComponent::FunctionTraceArgumentCount() { return 8; } int64_t I960_CPUComponent::FunctionTraceArgument(int n) { return m_r[I960_G0 + n]; } bool I960_CPUComponent::FunctionTraceReturnImpl(int64_t& retval) { retval = m_r[I960_G0]; return true; } int I960_CPUComponent::GetDyntransICshift() const { // 4 bytes per instruction means 2 bits shift. return 2; } void (*I960_CPUComponent::GetDyntransToBeTranslated())(CPUDyntransComponent*, DyntransIC*) { return instr_ToBeTranslated; } bool I960_CPUComponent::VirtualToPhysical(uint64_t vaddr, uint64_t& paddr, bool& writable) { paddr = vaddr; writable = true; return true; } uint64_t I960_CPUComponent::PCtoInstructionAddress(uint64_t pc) { return pc; } size_t I960_CPUComponent::DisassembleInstruction(uint64_t vaddr, size_t maxLen, unsigned char *instruction, vector& result) { size_t instrSize = sizeof(uint32_t); if (maxLen < instrSize) { assert(false); return 0; } // Read the instruction word: uint32_t instructionWord = ((uint32_t *) (void *) instruction)[0]; if (m_isBigEndian) instructionWord = BE32_TO_HOST(instructionWord); else instructionWord = LE32_TO_HOST(instructionWord); const uint32_t iword = instructionWord; const int opcode = iword >> 24; const int REG_src_dst = (iword >> 19) & 0x1f; const int REG_src2 = (iword >> 14) & 0x1f; const int REG_m3 = (iword >> 13) & 0x1; const int REG_m2 = (iword >> 12) & 0x1; const int REG_m1 = (iword >> 11) & 0x1; const int REG_opcode2 = (iword >> 7) & 0xf; const int REG_sfr2 = (iword >> 6) & 0x1; const int REG_sfr1 = (iword >> 5) & 0x1; const int REG_src1 = (iword >> 0) & 0x1f; const int COBR_src_dst = (iword >> 19) & 0x1f; const int COBR_src_2 = (iword >> 14) & 0x1f; const int COBR_m1 = (iword >> 13) & 0x1; const int COBR_disp = (iword >> 2) & 0x7ff; const int COBR_t = (iword >> 1) & 0x1; const int COBR_s2 = (iword >> 0) & 0x1; const int CTRL_disp = (iword >> 2) & 0x3fffff; const int CTRL_t = (iword >> 1) & 0x1; // const int MEMA_src_dst = (iword >> 19) & 0x1f; Same as MEMB_src_dst const int MEMA_abase = (iword >> 14) & 0x1f; const int MEMA_md = (iword >> 13) & 0x1; // const int MEMA_zero = (iword >> 12) & 0x1; 0 for MEMA, 1 for MEMB const int MEMA_offset = (iword >> 0) & 0xfff; const int MEMB_src_dst = (iword >> 19) & 0x1f; const int MEMB_abase = (iword >> 14) & 0x1f; const int MEMB_mode = (iword >> 10) & 0xf; const int MEMB_scale = (iword >> 7) & 0x7; // const int MEMB_sfr = (iword >> 5) & 0x3; Should be 00? const int MEMB_index = (iword >> 0) & 0x1f; bool hasDisplacementWord = false; if (opcode >= 0x80 && iword & 0x1000) { /* Only some MEMB instructions have displacement words: */ int mode = (iword >> 10) & 0xf; if (mode == 0x5 || mode >= 0xc) hasDisplacementWord = true; } uint32_t displacementWord = 0; if (hasDisplacementWord) { instrSize += sizeof(uint32_t); if (maxLen < instrSize) return 0; displacementWord = ((uint32_t *) (void *) instruction)[1]; if (m_isBigEndian) displacementWord = BE32_TO_HOST(displacementWord); else displacementWord = LE32_TO_HOST(displacementWord); } stringstream ssHex; ssHex.flags(std::ios::hex); ssHex << std::setfill('0') << std::setw(8) << (uint32_t) iword; if (hasDisplacementWord) ssHex << " " << std::setfill('0') << std::setw(8) << (uint32_t) displacementWord; else ssHex << " "; result.push_back(ssHex.str()); stringstream ssOpcode; stringstream ssArgs; stringstream ssComments; if (opcode >= 0x08 && opcode <= 0x1f) { /* CTRL: */ const char* mnemonics[] = { "b", /* 0x08 */ "call", /* 0x09 */ "ret", /* 0x0a */ "bal", /* 0x0b */ "unknown_ctrl_0x0c", /* 0x0c */ "unknown_ctrl_0x0d", /* 0x0d */ "unknown_ctrl_0x0e", /* 0x0e */ "unknown_ctrl_0x0f", /* 0x0f */ "bno", /* 0x10 */ "bg", /* 0x11 */ "be", /* 0x12 */ "bge", /* 0x13 */ "bl", /* 0x14 */ "bne", /* 0x15 */ "ble", /* 0x16 */ "bo", /* 0x17 */ "faultno", /* 0x18 */ "faultg", /* 0x19 */ "faulte", /* 0x1a */ "faultge", /* 0x1b */ "faultl", /* 0x1c */ "faultne", /* 0x1d */ "faultle", /* 0x1e */ "faulto" /* 0x1f */ }; ssOpcode << mnemonics[opcode - 0x08]; if (CTRL_t) ssOpcode << ".f"; bool hasDisplacement = opcode < 0x18 && opcode != 0x0a; if (hasDisplacement) { uint32_t disp = CTRL_disp << 2; if (disp & 0x00800000) disp |= 0xff000000; uint32_t addr = vaddr + disp; ssArgs << "0x"; ssArgs.flags(std::ios::hex); ssArgs << std::setfill('0') << std::setw(8) << addr; } } else if (opcode >= 0x20 && opcode <= 0x3f) { /* COBR: */ const char* mnemonics[] = { "testno", /* 0x20 */ "testg", /* 0x21 */ "teste", /* 0x22 */ "testge", /* 0x23 */ "testl", /* 0x24 */ "testne", /* 0x25 */ "testle", /* 0x26 */ "testo", /* 0x27 */ "unknown_cobr_0x28", /* 0x28 */ "unknown_cobr_0x29", /* 0x29 */ "unknown_cobr_0x2a", /* 0x2a */ "unknown_cobr_0x2b", /* 0x2b */ "unknown_cobr_0x2c", /* 0x2c */ "unknown_cobr_0x2d", /* 0x2d */ "unknown_cobr_0x2e", /* 0x2e */ "unknown_cobr_0x2f", /* 0x2f */ "bbc", /* 0x30 */ "cmpobg", /* 0x31 */ "cmpobe", /* 0x32 */ "cmpobge", /* 0x33 */ "cmpobl", /* 0x34 */ "cmpobne", /* 0x35 */ "cmpobne", /* 0x36 */ "bbs", /* 0x37 */ "cmpibno", /* 0x38 */ "cmpibg", /* 0x39 */ "cmpibe", /* 0x3a */ "cmpibge", /* 0x3b */ "cmpibl", /* 0x3c */ "cmpibne", /* 0x3d */ "cmpible", /* 0x3e */ "cmpibo", /* 0x3f */ }; ssOpcode << mnemonics[opcode - 0x20]; if (COBR_t) ssOpcode << ".f"; bool src1isBitpos = opcode == 0x30 || opcode == 0x37; if (opcode <= 0x27) { ssArgs << regname_or_literal(COBR_src_dst, 0, COBR_s2); } else { uint32_t targ = COBR_disp << 2; if (targ & 0x00001000) targ |= 0xffffe000; targ += vaddr; ssArgs << regname_or_literal(COBR_src_dst, src1isBitpos ? 1 : COBR_m1, 0) << ","; ssArgs << regname_or_literal(COBR_src_2, 0, COBR_s2) << ","; ssArgs << "0x"; ssArgs.flags(std::ios::hex); ssArgs << std::setfill('0') << std::setw(8) << targ; } } else if (opcode >= 0x58 && opcode <= 0x7f) { /* REG: */ struct reg_instruction *rinstr = NULL; for (int i = 0; ; ++i) { if (reg_instructions[i].mnemonic == NULL) break; if (reg_instructions[i].opcode == (opcode << 4) + REG_opcode2) { rinstr = ®_instructions[i]; break; } } bool has_src1 = true, has_src2 = true, has_dst = true, has_src3 = false; if (rinstr == NULL) { ssOpcode << "unknown_reg_"; ssOpcode.flags(std::ios::hex); ssOpcode << std::setfill('0') << std::setw(2) << opcode; ssOpcode << ":" << std::setw(1) << REG_opcode2; } else { ssOpcode << rinstr->mnemonic; has_src1 = rinstr->has_src1; has_src2 = rinstr->has_src2; has_dst = rinstr->has_dst; has_src3 = rinstr->has_src3; } if (has_src1) ssArgs << regname_or_literal(REG_src1, REG_m1, REG_sfr1); if (has_src2) { if (ssArgs.str().length() > 0) ssArgs << ","; ssArgs << regname_or_literal(REG_src2, REG_m2, REG_sfr2); } if (has_dst) { if (ssArgs.str().length() > 0) ssArgs << ","; if (REG_m3) { /* * The manual for i960CA says (when M3 = 1): * * "src/dst is a literal when used as a source * or a special function register when used * as a destination. M3 may not be 1 when * src/dst is used both as a source and * destination in an instruction (atmod, * modify, extract, modpc)." */ if (has_src3) ssArgs << regname_or_literal(REG_src_dst, 1, 0); else ssArgs << regname_or_literal(REG_src_dst, 0, 1); } else ssArgs << regname_or_literal(REG_src_dst, 0, 0); } } else if (opcode >= 0x80 && opcode <= 0xcf) { /* MEM: */ /* NOTE: These are for i960CA. When implementing support for other CPU variants, include an enum indicating which CPU it is for so that a warning can be printed for instructions that will cause faults on another CPU. */ const char* mnemonics[] = { "ldob", /* 0x80 */ "unknown_mem_0x81", /* 0x81 BiiN ldvob */ "stob", /* 0x82 */ "unknown_mem_0x83", /* 0x83 BiiN stvob */ "bx", /* 0x84 */ "balx", /* 0x85 */ "callx", /* 0x86 */ "unknown_mem_0x87", /* 0x87 */ "ldos", /* 0x88 */ "unknown_mem_0x89", /* 0x89 BiiN ldvos */ "stos", /* 0x8a */ "unknown_mem_0x8b", /* 0x8b BiiN stvos */ "lda", /* 0x8c */ "unknown_mem_0x8d", /* 0x8d */ "unknown_mem_0x8e", /* 0x8e */ "unknown_mem_0x8f", /* 0x8f */ "ld", /* 0x90 */ "unknown_mem_0x91", /* 0x91 BiiN ldv */ "st", /* 0x92 */ "unknown_mem_0x93", /* 0x93 Biin stv */ "unknown_mem_0x94", /* 0x94 */ "unknown_mem_0x95", /* 0x95 */ "unknown_mem_0x96", /* 0x96 */ "unknown_mem_0x97", /* 0x97 */ "ldl", /* 0x98 */ "unknown_mem_0x99", /* 0x99 BiiN ldvl */ "stl", /* 0x9a */ "unknown_mem_0x9b", /* 0x9b BiiN stvl */ "unknown_mem_0x9c", /* 0x9c */ "unknown_mem_0x9d", /* 0x9d */ "unknown_mem_0x9e", /* 0x9e */ "unknown_mem_0x9f", /* 0x9f */ "ldt", /* 0xa0 */ "unknown_mem_0xa1", /* 0xa1 BiiN ldvt */ "stt", /* 0xa2 */ "unknown_mem_0xa3", /* 0xa3 Biin stvt */ "unknown_mem_0xa4", /* 0xa4 */ "unknown_mem_0xa5", /* 0xa5 */ "unknown_mem_0xa6", /* 0xa6 */ "unknown_mem_0xa7", /* 0xa7 */ "unknown_mem_0xa8", /* 0xa8 */ "unknown_mem_0xa9", /* 0xa9 */ "unknown_mem_0xaa", /* 0xaa */ "unknown_mem_0xab", /* 0xab */ "unknown_mem_0xac", /* 0xac */ "unknown_mem_0xad", /* 0xad */ "unknown_mem_0xae", /* 0xae */ "unknown_mem_0xaf", /* 0xaf */ "ldq", /* 0xb0 */ "unknown_mem_0xb1", /* 0xb1 BiiN ldvq */ "stq", /* 0xb2 */ "unknown_mem_0xb3", /* 0xb3 BiiN stvq */ "unknown_mem_0xb4", /* 0xb4 */ "unknown_mem_0xb5", /* 0xb5 */ "unknown_mem_0xb6", /* 0xb6 */ "unknown_mem_0xb7", /* 0xb7 */ "unknown_mem_0xb8", /* 0xb8 */ "unknown_mem_0xb9", /* 0xb9 */ "unknown_mem_0xba", /* 0xba */ "unknown_mem_0xbb", /* 0xbb */ "unknown_mem_0xbc", /* 0xbc */ "unknown_mem_0xbd", /* 0xbd */ "unknown_mem_0xbe", /* 0xbe */ "unknown_mem_0xbf", /* 0xbf */ "ldib", /* 0xc0 */ "unknown_mem_0xc1", /* 0xc1 BiiN ldvib */ "stib", /* 0xc2 */ "unknown_mem_0xc3", /* 0xc3 Biin stvib */ "unknown_mem_0xc4", /* 0xc4 */ "unknown_mem_0xc5", /* 0xc5 */ "unknown_mem_0xc6", /* 0xc6 */ "unknown_mem_0xc7", /* 0xc7 */ "ldis", /* 0xc8 */ "unknown_mem_0xc9", /* 0xc9 BiiN ldvis */ "stis", /* 0xca */ "unknown_mem_0xcb", /* 0xcb BiiN stvis */ "unknown_mem_0xcc", /* 0xcc */ "unknown_mem_0xcd", /* 0xcd */ "unknown_mem_0xce", /* 0xce */ "unknown_mem_0xcf", /* 0xcf */ /* BiiN: d0 = ldm d1 = ldvm d2 = stm d3 = stvm d8 = ldml d9 = ldvml da = stml db = stvml */ }; ssOpcode << mnemonics[opcode - 0x80]; bool usesDst = opcode != 0x84 && opcode != 0x86; bool isStore = !!(opcode & 2); if (usesDst && isStore) { ssArgs << regname_or_literal(MEMB_src_dst, 0, 0) << ","; } if (iword & 0x1000) { /* MEMB: */ int scale = 1 << MEMB_scale; switch (MEMB_mode) { case 0x4: ssArgs << "(" << regname_or_literal(MEMB_abase, 0, 0) << ")"; break; case 0x5: { uint32_t offset = displacementWord + 8; ssArgs << "0x"; ssArgs.flags(std::ios::hex); ssArgs << std::setfill('0') << std::setw(8) << offset; ssArgs << "(ip)"; } break; case 0x7: // (reg1)[reg2 * scale] ssArgs << "(" << regname_or_literal(MEMB_abase, 0, 0) << ")"; ssArgs << "[" << regname_or_literal(MEMB_index, 0, 0) << "*" << scale << "]"; break; case 0xc: case 0xd: { uint32_t offset = displacementWord; ssArgs << "0x"; ssArgs.flags(std::ios::hex); ssArgs << std::setfill('0') << std::setw(8) << offset; if (MEMB_mode == 0xd) ssArgs << "(" << regname_or_literal(MEMB_abase, 0, 0) << ")"; } break; case 0xe: case 0xf: { uint32_t offset = displacementWord; ssArgs << "0x"; ssArgs.flags(std::ios::hex); ssArgs << std::setfill('0') << std::setw(8) << offset; if (MEMB_mode == 0xf) ssArgs << "(" << regname_or_literal(MEMB_abase, 0, 0) << ")"; ssArgs << "[" << regname_or_literal(MEMB_index, 0, 0) << "*" << scale << "]"; } break; default: ssArgs << "unimplemented MEMB mode!"; } } else { /* MEMA: */ ssArgs << "0x"; ssArgs.flags(std::ios::hex); ssArgs << std::setfill('0') << std::setw(1) << MEMA_offset; if (MEMA_md) ssArgs << "(" << regname_or_literal(MEMA_abase, 0, 0) << ")"; } if (usesDst && !isStore) { ssArgs << "," << regname_or_literal(MEMB_src_dst, 0, 0); } } else if (iword == 0) { ssOpcode << "--"; } else { ssOpcode << "unknown_0x"; ssOpcode.flags(std::ios::hex); ssOpcode << std::setfill('0') << std::setw(2) << (int)opcode; } result.push_back(ssOpcode.str()); result.push_back(ssArgs.str()); string comments = ssComments.str(); if (comments.length() > 0) result.push_back(comments); return instrSize; } string I960_CPUComponent::GetAttribute(const string& attributeName) { if (attributeName == "stable") return "yes"; if (attributeName == "description") return "Intel i960 processor."; return Component::GetAttribute(attributeName); } /*****************************************************************************/ DYNTRANS_INSTR(I960_CPUComponent,b) { DYNTRANS_INSTR_HEAD(I960_CPUComponent) cpu->m_pc = ic->arg[0].u32; cpu->DyntransPCtoPointers(); } DYNTRANS_INSTR(I960_CPUComponent,lda_displacement) { DYNTRANS_INSTR_HEAD(I960_CPUComponent) REG32(ic->arg[2]) = ic->arg[0].u32; cpu->m_nextIC = ic + 2; } DYNTRANS_INSTR(I960_CPUComponent,mov_lit_reg) { REG32(ic->arg[2]) = ic->arg[0].u32; } DYNTRANS_INSTR(I960_CPUComponent,sysctl) { DYNTRANS_INSTR_HEAD(I960_CPUComponent) uint32_t message = REG32(ic->arg[0]); int type = (message >> 8) & 0xff; if (type == 0x01) { // Invalidate cache. // Right now in GXemul, this is a NOP. UI* ui = cpu->GetUI(); ui->ShowDebugMessage(cpu, "invalidating cache (no-op for now)"); } else { // We didn't actually do anything in this instruction. cpu->m_executedCycles --; // Point to this instruction... DYNTRANS_SYNCH_PC; // ... and then abort. cpu->m_nextIC = &cpu->m_abortIC; UI* ui = cpu->GetUI(); ui->ShowDebugMessage(cpu, "unimplemented sysctl message type"); } } /*****************************************************************************/ void I960_CPUComponent::Translate(uint32_t iword, uint32_t iword2, struct DyntransIC* ic) { UI* ui = GetUI(); // for debug messages unsigned int opcode = iword >> 24; if (opcode >= 0x08 && opcode <= 0x1f) { /* CTRL: */ const int CTRL_disp = (iword >> 2) & 0x3fffff; uint32_t disp = CTRL_disp << 2; if (disp & 0x00800000) disp |= 0xff000000; ic->arg[0].u32 = disp + m_pc; if (opcode == 0x08) { ic->f = instr_b; } } else if (opcode >= 0x58 && opcode <= 0x7f) { /* REG: */ const int REG_src_dst = (iword >> 19) & 0x1f; const int REG_src2 = (iword >> 14) & 0x1f; const int REG_m3 = (iword >> 13) & 0x1; const int REG_m2 = (iword >> 12) & 0x1; const int REG_m1 = (iword >> 11) & 0x1; const int REG_opcode2 = (iword >> 7) & 0xf; const int REG_s2 = (iword >> 6) & 0x1; const int REG_s1 = (iword >> 5) & 0x1; const int REG_src1 = (iword >> 0) & 0x1f; int op3 = (opcode << 4) + REG_opcode2; if (REG_m1) ic->arg[0].u32 = REG_src1; else { if (REG_s1) ic->arg[0].p = &m_sfr[REG_src1]; else ic->arg[0].p = &m_r[REG_src1]; } if (REG_m2) ic->arg[1].u32 = REG_src2; else { if (REG_s2) ic->arg[1].p = &m_sfr[REG_src1]; else ic->arg[1].p = &m_r[REG_src2]; } if (REG_m3) { // TODO: write to sfr. if (ui != NULL) ui->ShowDebugMessage(this, "unimplemented write to sfr"); return; } else { ic->arg[2].p = &m_r[REG_src_dst]; } void (*f_lit_lit_reg)(CPUDyntransComponent*, struct DyntransIC*) = NULL; void (*f_lit_reg_reg)(CPUDyntransComponent*, struct DyntransIC*) = NULL; void (*f_reg_lit_reg)(CPUDyntransComponent*, struct DyntransIC*) = NULL; void (*f_reg_reg_reg)(CPUDyntransComponent*, struct DyntransIC*) = NULL; if (op3 == 0x5cc) { // mov NOTE: mov does not use src2. f_lit_lit_reg = instr_mov_lit_reg; f_lit_reg_reg = instr_mov_lit_reg; } else if (op3 == 0x659) { // sysctl f_reg_reg_reg = instr_sysctl; } if (REG_m3 == 0) { if (REG_m1 && REG_m2) ic->f = f_lit_lit_reg; if (REG_m1 && !REG_m2) ic->f = f_lit_reg_reg; if (!REG_m1 && REG_m2) ic->f = f_reg_lit_reg; if (!REG_m1 && !REG_m2) ic->f = f_reg_reg_reg; } else { if (ui != NULL) ui->ShowDebugMessage(this, "unimplemented write to sfr"); } } else if (opcode >= 0x80 && opcode <= 0xcf) { /* MEM: */ // const int MEMA_abase = (iword >> 14) & 0x1f; const int MEMA_md = (iword >> 13) & 0x1; const int MEMA_offset = (iword >> 0) & 0xfff; const int MEMB_src_dst = (iword >> 19) & 0x1f; // const int MEMB_abase = (iword >> 14) & 0x1f; const int MEMB_mode = (iword >> 10) & 0xf; // const int MEMB_scale = (iword >> 7) & 0x7; // const int MEMB_index = (iword >> 0) & 0x1f; ic->arg[2].p = &m_r[MEMB_src_dst]; if (iword & 0x1000) { /* MEMB: */ switch (MEMB_mode) { case 0xc: ic->arg[0].u32 = iword2; ic->f = instr_lda_displacement; break; default: ui->ShowDebugMessage(this, "unimplemented MEMB_mode"); } } else { /* MEMA: */ if (MEMA_md) ui->ShowDebugMessage(this, "TODO: MEMA"); else { ic->arg[0].u32 = MEMA_offset; ic->f = instr_mov_lit_reg; } } } if (ic->f == NULL && ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "unimplemented opcode 0x" << opcode; ui->ShowDebugMessage(this, ss.str()); } } DYNTRANS_INSTR(I960_CPUComponent,ToBeTranslated) { DYNTRANS_INSTR_HEAD(I960_CPUComponent) cpu->DyntransToBeTranslatedBegin(ic); uint32_t iword; if (cpu->DyntransReadInstruction(iword)) { bool readCompleteInstruction = true; uint32_t iword2 = 0; uint32_t opcode = iword >> 24; if (opcode >= 0x80 && opcode <= 0xcf) { /* Only some MEMB instructions have displacement words: */ int mode = (iword >> 10) & 0xf; if (mode == 0x5 || mode >= 0xc) readCompleteInstruction = cpu->DyntransReadInstruction(iword2, 4); if (!readCompleteInstruction) { UI* ui = cpu->GetUI(); ui->ShowDebugMessage(cpu, "last part of instruction could not be read: TODO"); } } if (readCompleteInstruction) cpu->Translate(iword, iword2, ic); } cpu->DyntransToBeTranslatedDone(ic); } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_I960_CPUComponent_Create() { refcount_ptr cpu = ComponentFactory::CreateComponent("i960_cpu"); UnitTest::Assert("component was not created?", !cpu.IsNULL()); const StateVariable * p = cpu->GetVariable("pfp"); UnitTest::Assert("cpu has no pfp state variable?", p != NULL); } static void Test_I960_CPUComponent_Disassembly_Basic() { refcount_ptr i960_cpu = ComponentFactory::CreateComponent("i960_cpu"); CPUComponent* cpu = i960_cpu->AsCPUComponent(); vector result; size_t len; unsigned char instruction[sizeof(uint32_t) * 2]; // This assumes that the default endianness is little endian... instruction[0] = 0x00; instruction[1] = 0x30; instruction[2] = 0x68; instruction[3] = 0x8c; instruction[4] = 0x01; instruction[5] = 0x23; instruction[6] = 0x34; instruction[7] = 0x45; len = cpu->DisassembleInstruction(0x12345678, sizeof(instruction), instruction, result); UnitTest::Assert("disassembled instruction was wrong length?", len, 8); UnitTest::Assert("disassembly result incomplete?", result.size(), 3); UnitTest::Assert("disassembly result[0]", result[0], "8c683000 45342301"); UnitTest::Assert("disassembly result[1]", result[1], "lda"); UnitTest::Assert("disassembly result[2]", result[2], "0x45342301,r13"); } static GXemul SimpleMachine() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add mainbus"); gxemul.GetCommandInterpreter().RunCommand("add i960_cpu mainbus0"); gxemul.GetCommandInterpreter().RunCommand("add ram mainbus0"); gxemul.GetCommandInterpreter().RunCommand("ram0.memoryMappedBase = 0x3fe00000"); gxemul.GetCommandInterpreter().RunCommand("ram0.memoryMappedSize = 0x1000"); return gxemul; } static void Test_I960_CPUComponent_Execute_mov() { GXemul gxemul = SimpleMachine(); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.mainbus0.cpu0"); AddressDataBus* bus = cpu->AsAddressDataBus(); bus->AddressSelect(0x3fe00048); bus->WriteData((uint32_t)0x5c201e06, LittleEndian); // mov 6,r4 bus->AddressSelect(0x3fe0004c); bus->WriteData((uint32_t)0x5c201e06, LittleEndian); // mov 6,r4 cpu->SetVariableValue("pc", "0x3fe00048"); cpu->SetVariableValue("r4", "0x1234"); gxemul.SetRunState(GXemul::Running); gxemul.Execute(1); UnitTest::Assert("pc should have increased", cpu->GetVariable("pc")->ToInteger(), 0x3fe0004c); UnitTest::Assert("r4 should have been modified", cpu->GetVariable("r4")->ToInteger(), 6); cpu->SetVariableValue("r4", "0x12345"); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(1); UnitTest::Assert("pc should have increased again", cpu->GetVariable("pc")->ToInteger(), 0x3fe00050); UnitTest::Assert("r4 should have been modified again", cpu->GetVariable("r4")->ToInteger(), 6); } static void Test_I960_CPUComponent_Execute_b() { GXemul gxemul = SimpleMachine(); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.mainbus0.cpu0"); AddressDataBus* bus = cpu->AsAddressDataBus(); bus->AddressSelect(0x3fe00004); bus->WriteData((uint32_t)0x080006c0, LittleEndian); // b 0x3fe006c4 cpu->SetVariableValue("pc", "0x3fe00004"); gxemul.SetRunState(GXemul::Running); gxemul.Execute(1); UnitTest::Assert("pc should have changed", cpu->GetVariable("pc")->ToInteger(), 0x3fe006c4); cpu->SetVariableValue("pc", "0x3fe00004"); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(1); UnitTest::Assert("pc should have changed again", cpu->GetVariable("pc")->ToInteger(), 0x3fe006c4); } static void Test_I960_CPUComponent_Execute_lda_with_offset() { GXemul gxemul = SimpleMachine(); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.mainbus0.cpu0"); AddressDataBus* bus = cpu->AsAddressDataBus(); bus->AddressSelect(0x3fe00010); bus->WriteData((uint32_t)0x8c180f13, LittleEndian); // lda r3, 0xf13 cpu->SetVariableValue("pc", "0x3fe00010"); gxemul.SetRunState(GXemul::Running); gxemul.Execute(1); UnitTest::Assert("lda length", cpu->GetVariable("pc")->ToInteger(), 0x3fe00014); UnitTest::Assert("lda", cpu->GetVariable("r3")->ToInteger(), 0xf13); } static void Test_I960_CPUComponent_Execute_lda_with_displacement() { GXemul gxemul = SimpleMachine(); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.mainbus0.cpu0"); AddressDataBus* bus = cpu->AsAddressDataBus(); bus->AddressSelect(0x3fe00010); bus->WriteData((uint32_t)0x8cf03000, LittleEndian); // lda bus->AddressSelect(0x3fe00014); bus->WriteData((uint32_t)0x3fe0507c, LittleEndian); // 0x3fe0507c, g14 cpu->SetVariableValue("pc", "0x3fe00010"); gxemul.SetRunState(GXemul::Running); gxemul.Execute(1); UnitTest::Assert("lda length", cpu->GetVariable("pc")->ToInteger(), 0x3fe00018); UnitTest::Assert("lda", cpu->GetVariable("g14")->ToInteger(), 0x3fe0507c); } UNITTESTS(I960_CPUComponent) { UNITTEST(Test_I960_CPUComponent_Create); UNITTEST(Test_I960_CPUComponent_Disassembly_Basic); UNITTEST(Test_I960_CPUComponent_Execute_mov); UNITTEST(Test_I960_CPUComponent_Execute_b); UNITTEST(Test_I960_CPUComponent_Execute_lda_with_offset); UNITTEST(Test_I960_CPUComponent_Execute_lda_with_displacement); } #endif gxemul-0.6.1/src/components/cpu/M88K_CPUComponent.cc000644 001750 001750 00000250761 13402411502 022373 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include "ComponentFactory.h" #include "GXemul.h" #include "components/M88K_CPUComponent.h" static const char* opcode_names[] = M88K_OPCODE_NAMES; static const char* opcode_names_3c[] = M88K_3C_OPCODE_NAMES; static const char* opcode_names_3d[] = M88K_3D_OPCODE_NAMES; static m88k_cpu_type_def cpu_type_defs[] = M88K_CPU_TYPE_DEFS; static const char *memop[4] = { ".d", "", ".h", ".b" }; static const char *m88k_cr_names[] = M88K_CR_NAMES; //static const char *m88k_cr_197_names[] = M88K_CR_NAMES_197; static const char *m88k_cr_name(int i) { const char **cr_names = m88k_cr_names; // TODO: Is this really MVME197 specific? Or 88110? //if (cpu->machine->machine_subtype == MACHINE_MVME88K_197) // cr_names = m88k_cr_197_names; return cr_names[i]; } M88K_CPUComponent::M88K_CPUComponent() : CPUDyntransComponent("m88k_cpu", "Motorola 88000") , m_m88k_type("88100") { m_frequency = 50e6; // 50 MHz // Find (and cache) the cpu type in m_type: memset((void*) &m_type, 0, sizeof(m_type)); for (size_t j=0; cpu_type_defs[j].name != NULL; j++) { if (m_m88k_type == cpu_type_defs[j].name) { m_type = cpu_type_defs[j]; break; } } if (m_type.name == NULL) { std::cerr << "Internal error: Unimplemented M88K type?\n"; throw std::exception(); } AddVariable("model", &m_m88k_type); for (size_t i=0; i M88K_CPUComponent::Create(const ComponentCreateArgs& args) { // Defaults: ComponentCreationSettings settings; settings["model"] = "88100"; settings["r31"] = "0x00000000"; if (!ComponentFactory::GetCreationArgOverrides(settings, args)) return NULL; // Create the CPU... refcount_ptr cpu = new M88K_CPUComponent(); // ... and apply settings: if (!cpu->SetVariableValue("model", "\"" + settings["model"] + "\"")) return NULL; if (!cpu->SetVariableValue("initial_r31", settings["r31"])) return NULL; if (!cpu->SetVariableValue("r31", settings["r31"])) return NULL; return cpu; } void M88K_CPUComponent::ResetState() { m_pageSize = 4096; // r0 .. r31 and the extra "r32/r0" zero register: for (size_t i=0; iGetUI()->ShowDebugMessage(this, "the r0 register " "must contain the value 0.\n"); return false; } if (m_pc > (uint64_t)0xffffffff) { gxemul->GetUI()->ShowDebugMessage(this, "the pc register " "must be a 32-bit value.\n"); return false; } if (m_pc & 0x2) { gxemul->GetUI()->ShowDebugMessage(this, "the pc register must have" " its lower two bits clear!\n"); return false; } if (m_r[N_M88K_REGS] != 0) { gxemul->GetUI()->ShowDebugMessage(this, "internal error: the " "register following r31 must mimic the r0 register.\nIf" " you encounter this message, please write a bug report!\n"); return false; } return CPUDyntransComponent::PreRunCheckForComponent(gxemul); } bool M88K_CPUComponent::CheckVariableWrite(StateVariable& var, const string& oldValue) { UI* ui = GetUI(); if (m_r[M88K_ZERO_REG] != 0) { if (ui != NULL) { ui->ShowDebugMessage(this, "the zero register (r0) " "must contain the value 0.\n"); } return false; } if (m_m88k_type != m_type.name) { bool found = false; for (size_t j=0; cpu_type_defs[j].name != NULL; j++) { if (m_m88k_type == cpu_type_defs[j].name) { m_type = cpu_type_defs[j]; found = true; break; } } if (!found) { if (ui != NULL) { stringstream ss; ss << "Unknown model \"" + m_m88k_type + "\". Available types are:\n"; for (size_t j=0; cpu_type_defs[j].name != NULL; j++) { if ((j % 6) != 0) ss << "\t"; ss << cpu_type_defs[j].name; if ((j % 6) == 5) ss << "\n"; } ui->ShowDebugMessage(this, ss.str()); } return false; } } return CPUDyntransComponent::CheckVariableWrite(var, oldValue); } void M88K_CPUComponent::ShowRegisters(GXemul* gxemul, const vector& arguments) const { bool done = false; stringstream ss; ss.flags(std::ios::hex); if (arguments.size() == 0 || find(arguments.begin(), arguments.end(), "r") != arguments.end()) { ss << " pc = 0x" << std::setfill('0') << std::setw(8) << m_pc; string symbol = GetSymbolRegistry().LookupAddress(m_pc, true); if (symbol != "") ss << " <" << symbol << ">"; ss << "\n"; for (size_t i=0; iGetUI()->ShowDebugMessage(ss.str()); } int M88K_CPUComponent::GetDyntransICshift() const { // 4 bytes per instruction, i.e. shift is 2 bits. return M88K_INSTR_ALIGNMENT_SHIFT; } void (*M88K_CPUComponent::GetDyntransToBeTranslated())(CPUDyntransComponent*, DyntransIC*) { return instr_ToBeTranslated; } bool M88K_CPUComponent::VirtualToPhysical(uint64_t vaddr, uint64_t& paddr, bool& writable) { // TODO. For now, just return paddr = vaddr. paddr = vaddr & 0xffffffff; writable = true; return true; } void M88K_CPUComponent::Exception(int vector, int is_trap) { std::cerr << "TODO: M88K exception\n"; throw std::exception(); } size_t M88K_CPUComponent::DisassembleInstruction(uint64_t vaddr, size_t maxLen, unsigned char *instruction, vector& result) { const size_t instrSize = sizeof(uint32_t); if (maxLen < instrSize) { assert(false); return 0; } // Read the instruction word: uint32_t instructionWord = *((uint32_t *)(void*) instruction); if (m_isBigEndian) instructionWord = BE32_TO_HOST(instructionWord); else instructionWord = LE32_TO_HOST(instructionWord); const uint32_t iw = instructionWord; // ... and add it to the result: { stringstream ss; ss.flags(std::ios::hex); ss << std::setfill('0') << std::setw(8) << (uint32_t) iw; if (m_pc == vaddr && m_inDelaySlot) ss << " (delayslot)"; result.push_back(ss.str()); } const uint32_t op26 = (iw >> 26) & 0x3f; const uint32_t op11 = (iw >> 11) & 0x1f; const uint32_t op10 = (iw >> 10) & 0x3f; const uint32_t d = (iw >> 21) & 0x1f; const uint32_t s1 = (iw >> 16) & 0x1f; const uint32_t s2 = iw & 0x1f; const uint32_t op3d = (iw >> 8) & 0xff; const uint32_t imm16 = iw & 0xffff; const uint32_t w5 = (iw >> 5) & 0x1f; const uint32_t cr6 = (iw >> 5) & 0x3f; const int32_t d16 = ((int16_t) (iw & 0xffff)) * 4; const int32_t d26 = ((int32_t)((iw & 0x03ffffff) << 6)) >> 4; switch (op26) { case 0x00: /* xmem.bu */ case 0x01: /* xmem */ case 0x02: /* ld.hu */ case 0x03: /* ld.bu */ case 0x04: /* ld.d */ case 0x05: /* ld */ case 0x06: /* ld.h */ case 0x07: /* ld.b */ case 0x08: /* st.d */ case 0x09: /* st */ case 0x0a: /* st.h */ case 0x0b: /* st.b */ case 0x10: /* and */ case 0x11: /* and.u */ case 0x12: /* mask */ case 0x13: /* mask.u */ case 0x14: /* xor */ case 0x15: /* xor.u */ case 0x16: /* or */ case 0x17: /* or.u */ case 0x18: /* addu */ case 0x19: /* subu */ case 0x1a: /* divu */ case 0x1b: /* mulu */ case 0x1c: /* add */ case 0x1d: /* sub */ case 0x1e: /* div */ case 0x1f: /* cmp */ if (iw == 0x00000000) { result.push_back("-"); } else { // Two registers (d, s1) and an immediate. result.push_back(opcode_names[op26]); stringstream ss; ss << "r" << d << ",r" << s1; ss.flags(std::ios::hex | std::ios::showbase); ss << "," << imm16; result.push_back(ss.str()); } break; case 0x20: if ((iw & 0x001ff81f) == 0x00004000) { result.push_back("ldcr"); stringstream ss; ss << "r" << d << ",cr" << cr6; result.push_back(ss.str()); stringstream comment; comment << "; cr" << cr6 << " = " << m88k_cr_name(cr6); result.push_back(comment.str()); } else if ((iw & 0x001ff81f) == 0x00004800) { result.push_back("fldcr"); stringstream ss; ss << "r" << d << ",fcr" << cr6; result.push_back(ss.str()); } else if ((iw & 0x03e0f800) == 0x00008000) { result.push_back("stcr"); stringstream ss; ss << "r" << s1 << ",cr" << cr6; result.push_back(ss.str()); if (s1 != s2) result.push_back("; Weird encoding: s1 != s2"); stringstream comment; comment << "; cr" << cr6 << " = " << m88k_cr_name(cr6); result.push_back(comment.str()); } else if ((iw & 0x03e0f800) == 0x00008800) { result.push_back("fstcr"); stringstream ss; ss << "r" << s1 << ",fcr" << cr6; result.push_back(ss.str()); if (s1 != s2) result.push_back("; Weird encoding: s1 != s2"); } else if ((iw & 0x0000f800) == 0x0000c000) { result.push_back("xcr"); stringstream ss; ss << "r" << d << ",r" << s1 << ",cr" << cr6; result.push_back(ss.str()); if (s1 != s2) result.push_back("; Weird encoding: s1 != s2"); stringstream comment; comment << "; cr" << cr6 << " = " << m88k_cr_name(cr6); result.push_back(comment.str()); } else if ((iw & 0x0000f800) == 0x0000c800) { result.push_back("fxcr"); stringstream ss; ss << "r" << d << ",r" << s1 << ",fcr" << cr6; result.push_back(ss.str()); if (s1 != s2) result.push_back("; Weird encoding: s1 != s2"); } else { result.push_back("unimpl_0x20_variant"); } break; case 0x21: switch (op11) { case 0x00: /* fmul */ case 0x05: /* fadd */ case 0x06: /* fsub */ case 0x07: /* fcmp */ case 0x0e: /* fdiv */ { stringstream ss; switch (op11) { case 0x00: ss << "fmul"; break; case 0x05: ss << "fadd"; break; case 0x06: ss << "fsub"; break; case 0x07: ss << "fcmp"; break; case 0x0e: ss << "fdiv"; break; } ss << "." << (((iw >> 5) & 1)? "d" : "s") << (((iw >> 9) & 1)? "d" : "s") << (((iw >> 7) & 1)? "d" : "s"); result.push_back(ss.str()); stringstream ss2; ss2 << "r" << d << ",r" << s1 << ",r" << s2; result.push_back(ss2.str()); } break; case 0x04: /* flt */ { stringstream ss; switch (op11) { case 0x04: ss << "flt"; break; } ss << "." << (((iw >> 5) & 1)? "d" : "s") << "s"; result.push_back(ss.str()); stringstream ss2; ss2 << "r" << d << ",r" << s2; result.push_back(ss2.str()); } break; case 0x09: /* int */ case 0x0a: /* nint */ case 0x0b: /* trnc */ { stringstream ss; switch (op11) { case 0x09: ss << "int"; break; case 0x0a: ss << "nint"; break; case 0x0b: ss << "trnc"; break; } ss << ".s" << (((iw >> 7) & 1)? "d" : "s"); result.push_back(ss.str()); stringstream ss2; ss2 << "r" << d << ",r" << s2; result.push_back(ss2.str()); } break; default:{ stringstream ss; ss << "unimpl_0x21, op11=" << op11; result.push_back(ss.str()); } } break; case 0x30: /* br */ case 0x31: /* br.n */ case 0x32: /* bsr */ case 0x33: /* bsr.n */ { result.push_back(opcode_names[op26]); stringstream ss; ss.flags(std::ios::hex | std::ios::showbase); ss << ((uint32_t) (vaddr + d26)); result.push_back(ss.str()); string symbol = GetSymbolRegistry().LookupAddress( (uint32_t) (vaddr + d26), true); if (symbol != "") result.push_back("; <" + symbol + ">"); } break; case 0x34: /* bb0 */ case 0x35: /* bb0.n */ case 0x36: /* bb1 */ case 0x37: /* bb1.n */ case 0x3a: /* bcnd */ case 0x3b: /* bcnd.n */ { result.push_back(opcode_names[op26]); stringstream ss; if (op26 == 0x3a || op26 == 0x3b) { /* Attempt to decode bcnd condition: */ switch (d) { case 0x1: ss << "gt0"; break; case 0x2: ss << "eq0"; break; case 0x3: ss << "ge0"; break; case 0x7: ss << "not_maxneg"; break; case 0x8: ss << "maxneg"; break; case 0xc: ss << "lt0"; break; case 0xd: ss << "ne0"; break; case 0xe: ss << "le0"; break; default: ss << "unk_" << d; } } else { ss << d; } ss << ",r" << s1 << ","; ss.flags(std::ios::hex | std::ios::showbase); ss << ((uint32_t) (vaddr + d16)); result.push_back(ss.str()); string symbol = GetSymbolRegistry().LookupAddress( (uint32_t) (vaddr + d16), true); if (symbol != "") result.push_back("; <" + symbol + ">"); } break; case 0x3c: if ((iw & 0x0000f000)==0x1000 || (iw & 0x0000f000)==0x2000) { /* Load/store: */ stringstream ss; ss << ((iw & 0x0000f000) == 0x1000? "ld" : "st"); switch (iw & 0x00000c00) { case 0x000: ss << ".d"; break; case 0x400: break; case 0x800: ss << ".x"; break; default: ss << ".UNIMPLEMENTED"; } if (iw & 0x100) ss << ".usr"; if (iw & 0x80) ss << ".wt"; result.push_back(ss.str()); stringstream ss2; ss2 << "r" << d << ",r" << s1; if (iw & 0x200) ss2 << "[r" << s2 << "]"; else ss2 << ",r" << s2; result.push_back(ss2.str()); } else switch (op10) { case 0x20: /* clr */ case 0x22: /* set */ case 0x24: /* ext */ case 0x26: /* extu */ case 0x28: /* mak */ case 0x2a: /* rot */ /* Two-register plus bit position/length: */ { result.push_back(opcode_names_3c[op10]); stringstream ss; ss << "r" << d << ",r" << s1 << ","; /* Don't include w5 for the rot instruction: */ if (op10 != 0x2a) ss << w5; /* Note: o5 = s2: */ ss << "<" << s2 << ">"; result.push_back(ss.str()); } break; case 0x34: /* tb0 */ case 0x36: /* tb1 */ /* B5 bit index, register, plus 9-bit immediate vector: */ { result.push_back(opcode_names_3c[op10]); stringstream ss; ss << d << ",r" << s1 << ","; ss.flags(std::ios::hex | std::ios::showbase); ss << (iw & 0x1ff); result.push_back(ss.str()); } break; default:{ stringstream ss; ss << "unimpl_" << opcode_names_3c[op10]; result.push_back(ss.str()); } } break; case 0x3d: if ((iw & 0xf000) <= 0x3fff) { /* Load, Store, xmem, and lda: */ stringstream op; switch (iw & 0xf000) { case 0x2000: op << "st"; break; case 0x3000: op << "lda"; break; default: if ((iw & 0xf800) >= 0x0800) op << "ld"; else op << "xmem"; } if ((iw & 0xf000) >= 0x1000) { /* ld, st, lda */ op << memop[(iw >> 10) & 3]; } else if ((iw & 0xf800) == 0x0000) { /* xmem */ if (!(iw & 0x400)) op << ".bu"; } else { /* ld */ if ((iw & 0xf00) < 0xc00) op << ".hu"; else op << ".bu"; } if (iw & 0x100) op << ".usr"; if (iw & 0x80) op << ".wt"; result.push_back(op.str()); stringstream ss; ss << "r" << d << ",r" << s1; if (iw & 0x200) ss << "[r" << s2 << "]"; else ss << ",r" << s2; result.push_back(ss.str()); } else switch (op3d) { case 0x40: /* and */ case 0x44: /* and.c */ case 0x50: /* xor */ case 0x54: /* xor.c */ case 0x58: /* or */ case 0x5c: /* or.c */ case 0x60: /* addu */ case 0x61: /* addu.co */ case 0x62: /* addu.ci */ case 0x63: /* addu.cio */ case 0x64: /* subu */ case 0x65: /* subu.co */ case 0x66: /* subu.ci */ case 0x67: /* subu.cio */ case 0x68: /* divu */ case 0x69: /* divu.d */ case 0x6c: /* mul */ case 0x6d: /* mulu.d */ case 0x6e: /* muls */ case 0x70: /* add */ case 0x71: /* add.co */ case 0x72: /* add.ci */ case 0x73: /* add.cio */ case 0x74: /* sub */ case 0x75: /* sub.co */ case 0x76: /* sub.ci */ case 0x77: /* sub.cio */ case 0x78: /* div */ case 0x7c: /* cmp */ case 0x80: /* clr */ case 0x88: /* set */ case 0x90: /* ext */ case 0x98: /* extu */ case 0xa0: /* mak */ case 0xa8: /* rot */ /* Three-register opcodes: */ { result.push_back(opcode_names_3d[op3d]); stringstream ss; ss << "r" << d << ",r" << s1 << ",r" << s2; result.push_back(ss.str()); } break; case 0xc0: /* jmp */ case 0xc4: /* jmp.n */ case 0xc8: /* jsr */ case 0xcc: /* jsr.n */ /* One-register jump opcodes: */ { result.push_back(opcode_names_3d[op3d]); stringstream ss; ss << "(r" << s2 << ")"; result.push_back(ss.str()); } break; case 0xe8: /* ff1 */ case 0xec: /* ff0 */ /* Two-register opcodes d,s2: */ { result.push_back(opcode_names_3d[op3d]); stringstream ss; ss << "r" << d << ",r" << s2; result.push_back(ss.str()); } break; case 0xf8: /* tbnd */ /* Two-register opcodes s1,s2: */ { result.push_back(opcode_names_3d[op3d]); stringstream ss; ss << "r" << s1 << ",r" << s2; result.push_back(ss.str()); } break; case 0xfc: switch (iw & 0xff) { case 0x00: result.push_back("rte"); break; case 0x01: case 0x02: case 0x03: { stringstream ss; ss << "illop" << (iw & 0xff); result.push_back(ss.str()); } break; case (M88K_PROM_INSTR & 0xff): result.push_back("gxemul_prom_call"); break; case (M88K_FAIL_EARLY_INSTR & 0xff): result.push_back("gxemul_fail_early"); break; case (M88K_FAIL_LATE_INSTR & 0xff): result.push_back("gxemul_fail_late"); break; default:{ stringstream ss; ss << "unimpl_3d_0xfc_" << (iw & 0xff); result.push_back(ss.str()); } } break; default:{ stringstream ss; ss << "unimpl_" << opcode_names_3d[op3d]; result.push_back(ss.str()); } } break; case 0x3e: /* tbnd */ { result.push_back(opcode_names[op26]); stringstream ss; ss << "r" << s1; ss.flags(std::ios::hex | std::ios::showbase); ss << "," << imm16; result.push_back(ss.str()); } break; default: { stringstream ss; ss << "unimpl_" << opcode_names[op26]; result.push_back(ss.str()); } break; } return instrSize; } string M88K_CPUComponent::GetAttribute(const string& attributeName) { if (attributeName == "stable") return "yes"; if (attributeName == "description") return "Motorola 88000 processor."; return Component::GetAttribute(attributeName); } /*****************************************************************************/ void M88K_CPUComponent::stcr(int cr, uint32_t value, bool is_rte) { uint32_t old = m_cr[cr]; switch (cr) { case M88K_CR_PSR: /* Processor Status Regoster */ if ((!m_isBigEndian && !(value & M88K_PSR_BO)) || (m_isBigEndian && (value & M88K_PSR_BO))) { std::cerr << "TODO: attempt to change endianness by flipping" " the endianness bit in the PSR. How should this" " be handled? Aborting.\n"; std::cerr << "TODO: abort in a nicer way\n"; throw std::exception(); } if (!is_rte && (old & M88K_PSR_MODE) && !(value & M88K_PSR_MODE)) { UI* ui = GetUI(); if (ui != NULL) { ui->ShowDebugMessage(this, "m88k stcr: WARNING! the PSR_MODE bit is being" " cleared; this should be done using the RTE " "instruction only, according to the M88100 " "manual! Continuing anyway.\n"); } } if (value & M88K_PSR_MXM) { std::cerr << "m88k stcr: TODO: MXM support\n"; std::cerr << "TODO: abort in a nicer way\n"; throw std::exception(); } if ((old & M88K_PSR_MODE) != (value & M88K_PSR_MODE)) { // cpu->invalidate_translation_caches( // cpu, 0, INVALIDATE_ALL); std::cerr << "m88k stcr: TODO: PSR mode switch.\n"; std::cerr << "TODO: abort in a nicer way\n"; throw std::exception(); } m_cr[cr] = value; break; case M88K_CR_EPSR: m_cr[cr] = value; break; case M88K_CR_SXIP: case M88K_CR_SNIP: case M88K_CR_SFIP: m_cr[cr] = value; break; case M88K_CR_SSBR: /* Shadow ScoreBoard Register */ if (value & 1) { UI* ui = GetUI(); if (ui != NULL) ui->ShowDebugMessage(this, "WARNING! bit 0 non-zero when writing to SSBR\n"); } m_cr[cr] = value; break; case M88K_CR_VBR: if (value & 0x00000fff) { UI* ui = GetUI(); if (ui != NULL) ui->ShowDebugMessage(this, "WARNING! bits 0..11 non-zero when writing to VBR\n"); } m_cr[cr] = value; break; case M88K_CR_DMT0: case M88K_CR_DMT1: case M88K_CR_DMT2: m_cr[cr] = value; break; case M88K_CR_SR0: /* Supervisor Storage Registers 0..3 */ case M88K_CR_SR1: case M88K_CR_SR2: case M88K_CR_SR3: m_cr[cr] = value; break; default:std::cerr << "m88k stcr: UNIMPLEMENTED cr = " << cr << "\n"; std::cerr << "TODO: abort in a nicer way\n"; throw std::exception(); } } /* * cmp_imm: Compare S1 with immediate value. * cmp: Compare S1 with S2. * * arg[0] = pointer to register d * arg[1] = pointer to register s1 * arg[2] = pointer to register s2 or imm */ void M88K_CPUComponent::m88k_cmp(struct DyntransIC *ic, uint32_t y) { uint32_t x = REG32(ic->arg[1]); uint32_t r; if (x == y) { r = M88K_CMP_HS | M88K_CMP_LS | M88K_CMP_GE | M88K_CMP_LE | M88K_CMP_EQ; } else { if (x > y) r = M88K_CMP_NE | M88K_CMP_HS | M88K_CMP_HI; else r = M88K_CMP_NE | M88K_CMP_LO | M88K_CMP_LS; if ((int32_t)x > (int32_t)y) r |= M88K_CMP_GE | M88K_CMP_GT; else r |= M88K_CMP_LT | M88K_CMP_LE; } REG32(ic->arg[0]) = r; } DYNTRANS_INSTR(M88K_CPUComponent,cmp) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) cpu->m88k_cmp(ic, REG32(ic->arg[2])); } DYNTRANS_INSTR(M88K_CPUComponent,cmp_imm) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) cpu->m88k_cmp(ic, ic->arg[2].u32); } /* * extu_imm: Extract bits, unsigned, immediate W. * extu: Extract bits, unsigned, W taken from register s2. * ext_imm: Extract bits, signed, immediate W. * ext: Extract bits, signed, W taken from register s2. * * arg[0] = pointer to register d * arg[1] = pointer to register s1 * arg[2] = pointer to register s2 or 10 bits wwwwwooooo */ void M88K_CPUComponent::m88k_extu(struct DyntransIC *ic, int w, int o) { uint32_t x = REG32(ic->arg[1]) >> o; if (w != 0) { x <<= (32-w); x >>= (32-w); } REG32(ic->arg[0]) = x; } void M88K_CPUComponent::m88k_ext(struct DyntransIC *ic, int w, int o) { int32_t x = REG32(ic->arg[1]); x >>= o; /* signed (arithmetic) shift */ if (w != 0) { x <<= (32-w); x >>= (32-w); } REG32(ic->arg[0]) = x; } DYNTRANS_INSTR(M88K_CPUComponent,extu_imm) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) cpu->m88k_extu(ic, ic->arg[2].u32 >> 5, ic->arg[2].u32 & 0x1f); } DYNTRANS_INSTR(M88K_CPUComponent,extu) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) cpu->m88k_extu(ic, (REG32(ic->arg[2]) >> 5) & 0x1f, REG32(ic->arg[2]) & 0x1f); } DYNTRANS_INSTR(M88K_CPUComponent,ext_imm) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) cpu->m88k_ext(ic, ic->arg[2].u32 >> 5, ic->arg[2].u32 & 0x1f); } DYNTRANS_INSTR(M88K_CPUComponent,ext) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) cpu->m88k_ext(ic, (REG32(ic->arg[2]) >> 5) & 0x1f, REG32(ic->arg[2]) & 0x1f); } /* * mak: Make bit field, W taken from register s2. * mak_imm: Make bit field, immediate W. * * arg[0] = pointer to register d * arg[1] = pointer to register s1 * arg[2] = pointer to register s2 or immediate. */ void M88K_CPUComponent::m88k_mak(struct DyntransIC *ic, int w, int o) { uint32_t x = REG32(ic->arg[1]); if (w != 0) { x <<= (32-w); x >>= (32-w); } REG32(ic->arg[0]) = x << o; } DYNTRANS_INSTR(M88K_CPUComponent,mak) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) cpu->m88k_mak(ic, (REG32(ic->arg[2]) >> 5) & 0x1f, REG32(ic->arg[2]) & 0x1f); } DYNTRANS_INSTR(M88K_CPUComponent,mak_imm) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) cpu->m88k_mak(ic, ic->arg[2].u32 >> 5, ic->arg[2].u32 & 0x1f); } /* * divu_imm: d = s1 / immediate * mulu_imm: d = s1 * immediate * * arg[0] = pointer to register d * arg[1] = pointer to register s1 * arg[2] = immediate. */ DYNTRANS_INSTR(M88K_CPUComponent,divu_imm) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) // TODO: 88100 only, not 88110: if (cpu->m_cr[M88K_CR_PSR] & M88K_PSR_SFD1) { DYNTRANS_SYNCH_PC; cpu->m_fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; cpu->Exception(M88K_EXCEPTION_SFU1_PRECISE, 0); } else if (ic->arg[2].u32 == 0) { DYNTRANS_SYNCH_PC; cpu->Exception(M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0); } else { REG32(ic->arg[0]) = REG32(ic->arg[1]) / ic->arg[2].u32; } } DYNTRANS_INSTR(M88K_CPUComponent,mulu_imm) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) // TODO: 88100 only, not 88110: if (cpu->m_cr[M88K_CR_PSR] & M88K_PSR_SFD1) { DYNTRANS_SYNCH_PC; cpu->m_fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; cpu->Exception(M88K_EXCEPTION_SFU1_PRECISE, 0); } else { REG32(ic->arg[0]) = REG32(ic->arg[1]) * ic->arg[2].u32; } } DYNTRANS_INSTR(M88K_CPUComponent,bsr) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) cpu->m_pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->m_r[M88K_RETURN_REG] = cpu->m_pc + ic->arg[2].u32; cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[1].u32); cpu->DyntransPCtoPointers(); } DYNTRANS_INSTR(M88K_CPUComponent,bsr_samepage) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) cpu->m_r[M88K_RETURN_REG] = (cpu->m_pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT)) + ic->arg[2].u32; cpu->m_nextIC = (struct DyntransIC *) ic->arg[0].p; } DYNTRANS_INSTR(M88K_CPUComponent,bsr_functioncalltrace) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) cpu->m_pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->m_r[M88K_RETURN_REG] = cpu->m_pc + ic->arg[2].u32; cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[1].u32); bool continueExecution = cpu->FunctionTraceCall(); cpu->DyntransPCtoPointers(); if (!continueExecution) cpu->m_nextIC = &cpu->m_abortIC; } DYNTRANS_INSTR(M88K_CPUComponent,bsr_n) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) uint32_t startOfPage = cpu->m_pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->m_r[M88K_RETURN_REG] = startOfPage + ic->arg[2].u32; // Prepare for the branch. cpu->m_exceptionOrAbortInDelaySlot = false; cpu->m_inDelaySlot = true; cpu->m_delaySlotTarget = (uint32_t) (startOfPage + ic->arg[1].u32); // Execute the next instruction: ic[1].f(cpu, ic+1); cpu->m_executedCycles ++; // If there was no exception, then branch: if (!cpu->m_exceptionOrAbortInDelaySlot) { cpu->m_pc = (uint32_t) (startOfPage + ic->arg[1].u32); cpu->DyntransPCtoPointers(); cpu->m_inDelaySlot = false; } // The next instruction is now either the target of the branch // instruction, or the first instruction of an exception handler. cpu->m_exceptionOrAbortInDelaySlot = false; } DYNTRANS_INSTR(M88K_CPUComponent,bsr_n_functioncalltrace) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) uint32_t startOfPage = cpu->m_pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->m_r[M88K_RETURN_REG] = startOfPage + ic->arg[2].u32; // Prepare for the branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; // Execute the next instruction: ic[1].f(cpu, ic+1); cpu->m_executedCycles ++; // If there was no exception, then branch: if (!cpu->m_exceptionOrAbortInDelaySlot) { cpu->m_pc = (uint32_t) (startOfPage + ic->arg[1].u32); bool continueExecution = cpu->FunctionTraceCall(); cpu->DyntransPCtoPointers(); cpu->m_inDelaySlot = false; if (!continueExecution) cpu->m_nextIC = &cpu->m_abortIC; } // The next instruction is now either the target of the branch // instruction, or the first instruction of an exception handler. cpu->m_exceptionOrAbortInDelaySlot = false; } // Note: This IC function is used both when function call trace is enabled // and disabled. (Ok, since it is only used when singlestepping.) DYNTRANS_INSTR(M88K_CPUComponent,bsr_n_functioncalltrace_singlestep) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) // Prepare for the delayed branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; cpu->m_pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->m_r[M88K_RETURN_REG] = cpu->m_pc + ic->arg[2].u32; uint32_t old_pc = cpu->m_pc; cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[1].u32); if (cpu->m_showFunctionTraceCall) cpu->FunctionTraceCall(); cpu->m_delaySlotTarget = cpu->m_pc; // make m_nextIC (and pc!) point to the next instruction: cpu->m_nextIC = ic + 1; cpu->m_pc = old_pc; // at least the same page... not necessarily more correct than that. } /* * bcnd, bcnd.n: Branch on condition * * arg[0] = pointer to register s1 * arg[2] = offset from start of current page to branch to _OR_ pointer to new instr_call */ template void M88K_CPUComponent::instr_bcnd(CPUDyntransComponent* cpubase, DyntransIC* ic) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) bool cond; if (op == 1) cond = ((int32_t)REG32(ic->arg[0]) > 0); // gt0 else if (op == 2) cond = ((int32_t)REG32(ic->arg[0]) == 0); // eq0 else if (op == 3) cond = ((int32_t)REG32(ic->arg[0]) >= 0); // ge0 else if (op == 7) cond = ((uint32_t)REG32(ic->arg[0]) != 0x80000000UL); // not_maxneg else if (op == 8) cond = ((uint32_t)REG32(ic->arg[0]) == 0x80000000UL); // maxneg else if (op == 12) cond = ((int32_t)REG32(ic->arg[0]) < 0); // lt0 else if (op == 13) cond = ((int32_t)REG32(ic->arg[0]) != 0); // ne0 else /* op == 14 */ cond = ((int32_t)REG32(ic->arg[0]) <= 0); // le0 if (n) { if (singlestep) { DYNTRANS_SYNCH_PC; // Prepare for the branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; if (cond) { cpu->m_delaySlotTarget = cpu->m_pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->m_delaySlotTarget = (uint32_t) (cpu->m_delaySlotTarget + ic->arg[2].u32); } else { cpu->m_delaySlotTarget = cpu->m_pc + 8; } cpu->m_nextIC = ic + 1; } else { // Prepare for the branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; // Execute the next instruction: ic[1].f(cpu, ic+1); cpu->m_executedCycles ++; // If there was no exception, then branch: if (!cpu->m_exceptionOrAbortInDelaySlot) { if (cond) { cpu->m_pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[2].u32); cpu->DyntransPCtoPointers(); } else { cpu->m_nextIC = ic + 2; } cpu->m_inDelaySlot = false; } // The next instruction is now either the target of the branch // instruction, the instruction 2 steps after this one, // or the first instruction of an exception handler. cpu->m_exceptionOrAbortInDelaySlot = false; } } else { // bcnd without the .n flag: if (cond) { cpu->m_pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[2].u32); cpu->DyntransPCtoPointers(); } else { // m_nextIC should already point to the next ic. } } } /* * bb0, bb1: Branch if a bit in a register is 0 or 1 * bb0.n, bb1.n: Branch if a bit in a register is 0 or 1 with delay slot * * arg[0] = pointer to register s1 * arg[1] = uint32_t bitmask to test * arg[2] = offset from start of current page to branch to _OR_ pointer to new instr_call */ template void M88K_CPUComponent::instr_bb(CPUDyntransComponent* cpubase, DyntransIC* ic) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) bool bit = REG32(ic->arg[0]) & ic->arg[1].u32; if (bit == one) { if (samepage) { cpu->m_nextIC = (DyntransIC*) ic->arg[2].p; } else { cpu->m_pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[2].u32); cpu->DyntransPCtoPointers(); } } } template void M88K_CPUComponent::instr_bb_n(CPUDyntransComponent* cpubase, DyntransIC* ic) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) bool bit = REG32(ic->arg[0]) & ic->arg[1].u32; // Prepare for the branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; // Execute the next instruction: ic[1].f(cpu, ic+1); cpu->m_executedCycles ++; // If there was no exception, then branch: if (!cpu->m_exceptionOrAbortInDelaySlot) { if (bit == one) { cpu->m_pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->m_pc = (uint32_t) (cpu->m_pc + ic->arg[2].u32); cpu->DyntransPCtoPointers(); } else { cpu->m_nextIC = ic + 2; } cpu->m_inDelaySlot = false; } // The next instruction is now either the target of the branch // instruction, the instruction 2 steps after this one, // or the first instruction of an exception handler. cpu->m_exceptionOrAbortInDelaySlot = false; } template void M88K_CPUComponent::instr_bb_n_singlestep(CPUDyntransComponent* cpubase, DyntransIC* ic) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) bool bit = REG32(ic->arg[0]) & ic->arg[1].u32; DYNTRANS_SYNCH_PC; // Prepare for the branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; if (bit == one) { cpu->m_delaySlotTarget = cpu->m_pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->m_delaySlotTarget = (uint32_t) (cpu->m_delaySlotTarget + ic->arg[2].u32); } else { cpu->m_delaySlotTarget = cpu->m_pc + 8; } cpu->m_nextIC = ic + 1; } DYNTRANS_INSTR(M88K_CPUComponent,jmp) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) bool continueExecution = true; if (cpu->m_showFunctionTraceCall && ic->arg[2].p == &cpu->m_r[M88K_RETURN_REG]) continueExecution = cpu->FunctionTraceReturn(); cpu->m_pc = REG32(ic->arg[2]); cpu->DyntransPCtoPointers(); if (!continueExecution) cpu->m_nextIC = &cpu->m_abortIC; } DYNTRANS_INSTR(M88K_CPUComponent,jmp_n) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) // Prepare for the branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; uint32_t branchTarget = REG32(ic->arg[2]); // Execute the next instruction: ic[1].f(cpu, ic+1); cpu->m_executedCycles ++; // If there was no exception, then branch: if (!cpu->m_exceptionOrAbortInDelaySlot) { cpu->m_pc = branchTarget; cpu->DyntransPCtoPointers(); cpu->m_inDelaySlot = false; } // The next instruction is now either the target of the branch // instruction, the instruction 2 steps after this one, // or the first instruction of an exception handler. cpu->m_exceptionOrAbortInDelaySlot = false; } DYNTRANS_INSTR(M88K_CPUComponent,jmp_n_functioncalltrace) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) // Prepare for the branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; uint32_t branchTarget = REG32(ic->arg[2]); // Execute the next instruction: ic[1].f(cpu, ic+1); cpu->m_executedCycles ++; // If there was no exception, then branch: if (!cpu->m_exceptionOrAbortInDelaySlot) { bool continueExecution = true; if (cpu->m_showFunctionTraceCall && ic->arg[2].p == &cpu->m_r[M88K_RETURN_REG]) continueExecution = cpu->FunctionTraceReturn(); cpu->m_pc = branchTarget; cpu->DyntransPCtoPointers(); cpu->m_inDelaySlot = false; if (!continueExecution) cpu->m_nextIC = &cpu->m_abortIC; } // The next instruction is now either the target of the branch // instruction, the instruction 2 steps after this one, // or the first instruction of an exception handler. cpu->m_exceptionOrAbortInDelaySlot = false; } // Note: This IC function is used both when function call trace is enabled // and disabled. (Ok, since it is only used when singlestepping.) DYNTRANS_INSTR(M88K_CPUComponent,jmp_n_functioncalltrace_singlestep) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) if (cpu->m_showFunctionTraceCall && ic->arg[2].p == &cpu->m_r[M88K_RETURN_REG]) cpu->FunctionTraceReturn(); // Prepare for the delayed branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; cpu->m_delaySlotTarget = REG32(ic->arg[2]); // m_nextIC already points to the next instruction } /* * ldcr: Load value from a control register, store in register d. * * arg[0] = pointer to register d * arg[1] = 6-bit control register number */ DYNTRANS_INSTR(M88K_CPUComponent,ldcr) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) if (cpu->m_cr[M88K_CR_PSR] & M88K_PSR_MODE) { int cr = ic->arg[1].u32; REG32(ic->arg[0]) = cpu->m_cr[cr]; } else { DYNTRANS_SYNCH_PC; cpu->Exception(M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0); } } /* * stcr: Store value from register s1 into a control register. * * arg[0] = pointer to register s1 * arg[1] = 6-bit control register number */ DYNTRANS_INSTR(M88K_CPUComponent,stcr) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) DYNTRANS_SYNCH_PC; if (!(cpu->m_cr[M88K_CR_PSR] & M88K_PSR_MODE)) { cpu->Exception(M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0); return; } cpu->stcr(ic->arg[1].u32, REG32(ic->arg[0]), false); cpu->m_nextIC = ic + 1; } /* * tb0, tb1: Trap on bit Clear/Set * * arg[0] = bitmask to check (e.g. 0x00020000 for bit 17) * arg[1] = pointer to register s1 * arg[2] = 9-bit vector number */ template void M88K_CPUComponent::instr_tb(CPUDyntransComponent* cpubase, DyntransIC* ic) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) if (!(cpu->m_cr[M88K_CR_PSR] & M88K_PSR_MODE) && ic->arg[2].u32 < M88K_EXCEPTION_USER_TRAPS_START) { DYNTRANS_SYNCH_PC; cpu->Exception(M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0); return; } bool bit = (REG32(ic->arg[1]) & ic->arg[0].u32) > 0; if (bit == one) { DYNTRANS_SYNCH_PC; cpu->Exception(ic->arg[2].u32, 1); } } /* * lda: d = s1 + s2 * scaleFactor * * arg[0] = pointer to register d * arg[1] = pointer to register s1 * arg[2] = pointer to register s2 */ template void M88K_CPUComponent::instr_lda(CPUDyntransComponent* cpubase, DyntransIC* ic) { REG32(ic->arg[0]) = REG32(ic->arg[1]) + scaleFactor * REG32(ic->arg[2]); } /* * Loads and stores: * * arg[0] = pointer to register d * arg[1] = pointer to register s1 * arg[2] = pointer to register s2 or uint16_t offset */ template void M88K_CPUComponent::instr_loadstore(CPUDyntransComponent* cpubase, DyntransIC* ic) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) // TODO: fast lookups // TODO: usr access // TODO: place in M88K's "ongoing memory transaction" registers! uint32_t addr = REG32(ic->arg[1]) + (scaled? (doubleword? sizeof(uint64_t) : sizeof(T)) : 1) * (regofs? REG32(ic->arg[2]) : ic->arg[2].u32); if (sizeof(T) > 1 && (addr & (sizeof(T)-1))) { DYNTRANS_SYNCH_PC; cpu->Exception(M88K_EXCEPTION_MISALIGNED_ACCESS, 0); return; } cpu->AddressSelect(addr); if (store) { T data = REG32(ic->arg[0]); if (!cpu->WriteData(data, cpu->m_isBigEndian? BigEndian : LittleEndian)) { // TODO: failed to access memory was probably an exception. Handle this! } } else { T data; if (!cpu->ReadData(data, cpu->m_isBigEndian? BigEndian : LittleEndian)) { // TODO: failed to access memory was probably an exception. Handle this! } if (signedLoad) { if (sizeof(T) == sizeof(uint16_t)) data = (int16_t)data; if (sizeof(T) == sizeof(uint8_t)) data = (int8_t)data; } REG32(ic->arg[0]) = data; } // Special handling of second word in a double-word read or write: if (doubleword) { if (store) { uint32_t data2 = (* (((uint32_t*)(ic->arg[0].p)) + 1) ); cpu->AddressSelect(addr + sizeof(uint32_t)); if (!cpu->WriteData(data2, cpu->m_isBigEndian? BigEndian : LittleEndian)) { // TODO: failed to access memory was probably an exception. Handle this! } } else { uint32_t data2; cpu->AddressSelect(addr + sizeof(uint32_t)); if (!cpu->ReadData(data2, cpu->m_isBigEndian? BigEndian : LittleEndian)) { // TODO: failed to access memory was probably an exception. Handle this! } (* (((uint32_t*)(ic->arg[0].p)) + 1) ) = data2; } } } /*****************************************************************************/ /* * For unit tests: * * fail_early: Results in an abort before doing anything. * fail_late: Results in an abort after increasing r1. */ DYNTRANS_INSTR(M88K_CPUComponent,fail_early) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) // Point to this instruction... DYNTRANS_SYNCH_PC; // We didn't actually do anything in this instruction. cpu->m_executedCycles --; // ... and then abort. cpu->m_nextIC = &cpu->m_abortIC; if (cpu->m_inDelaySlot) cpu->m_exceptionOrAbortInDelaySlot = true; } DYNTRANS_INSTR(M88K_CPUComponent,fail_late) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) // Do something... cpu->m_r[1] ++; // Point to next instruction... DYNTRANS_SYNCH_PC; cpu->m_pc += sizeof(uint32_t); // ... and abort. cpu->m_nextIC = &cpu->m_abortIC; if (cpu->m_inDelaySlot) cpu->m_exceptionOrAbortInDelaySlot = true; } /*****************************************************************************/ void M88K_CPUComponent::Translate(uint32_t iw, struct DyntransIC* ic) { bool singleInstructionLeft = (m_executedCycles == m_nrOfCyclesToExecute - 1); UI* ui = GetUI(); // for debug messages uint32_t op26 = (iw >> 26) & 0x3f; // uint32_t op11 = (iw >> 11) & 0x1f; uint32_t op10 = (iw >> 10) & 0x3f; uint32_t d = (iw >> 21) & 0x1f; uint32_t s1 = (iw >> 16) & 0x1f; uint32_t s2 = iw & 0x1f; // uint32_t op3d = (iw >> 8) & 0xff; uint32_t imm16 = iw & 0xffff; // uint32_t w5 = (iw >> 5) & 0x1f; uint32_t cr6 = (iw >> 5) & 0x3f; int32_t d16 = ((int16_t) (iw & 0xffff)) * 4; int32_t d26 = ((int32_t)((iw & 0x03ffffff) << 6)) >> 4; switch (op26) { case 0x02: /* ld.hu */ case 0x03: /* ld.bu */ case 0x04: /* ld.d */ case 0x05: /* ld */ case 0x06: /* ld.h */ case 0x07: /* ld.b */ case 0x08: /* st.d */ case 0x09: /* st */ case 0x0a: /* st.h */ case 0x0b: /* st.b */ { bool store = op26 >= 0x08; int opsize = 0; ic->arg[0].p = &m_r[d]; ic->arg[1].p = &m_r[s1]; ic->arg[2].u32 = imm16; switch (op26) { case 0x02: ic->f = instr_loadstore; opsize = 1; break; case 0x03: ic->f = instr_loadstore; opsize = 0; break; case 0x04: ic->f = instr_loadstore; opsize = 3; break; case 0x05: ic->f = instr_loadstore; opsize = 2; break; case 0x06: ic->f = instr_loadstore; opsize = 1; break; case 0x07: ic->f = instr_loadstore; opsize = 0; break; case 0x08: ic->f = instr_loadstore; opsize = 3; break; case 0x09: ic->f = instr_loadstore; opsize = 2; break; case 0x0a: ic->f = instr_loadstore; opsize = 1; break; case 0x0b: ic->f = instr_loadstore; opsize = 0; break; } if (opsize == 3 && d == 31) { // m88k load/store of register pair r31/r0 is not // yet implemented: TODO: figure out how to deal with this. ic->f = NULL; break; } // Loads into the zero register => load into scratch register. // According to the MC88110 manual: special cache operation // "(touch, allocate, or flush) may be performed". (TODO) if (!store && d == M88K_ZERO_REG && ic->f != NULL) ic->arg[0].p = &m_zero_scratch; } break; case 0x10: /* and immu32 */ case 0x11: /* and.u immu32 */ case 0x12: /* mask immu32 */ case 0x13: /* mask.u immu32 */ case 0x14: /* xor immu32 */ case 0x15: /* xor.u immu32 */ case 0x16: /* or immu32 */ case 0x17: /* or.u immu32 */ case 0x18: /* addu immu32 */ case 0x19: /* subu immu32 */ case 0x1a: /* divu immu32 */ case 0x1b: /* mulu immu32 */ case 0x1f: /* cmp immu32 */ { int shift = 0; switch (op26) { case 0x10: ic->f = instr_and_u32_u32_immu32; break; // Note (see below): and only ands upper or lower part! case 0x11: ic->f = instr_and_u32_u32_immu32; shift = 16; break; case 0x12: ic->f = instr_and_u32_u32_immu32; break; // Note: mask is implemented using and case 0x13: ic->f = instr_and_u32_u32_immu32; shift = 16; break; case 0x14: ic->f = instr_xor_u32_u32_immu32; break; case 0x15: ic->f = instr_xor_u32_u32_immu32; shift = 16; break; case 0x16: ic->f = instr_or_u32_u32_immu32; break; case 0x17: ic->f = instr_or_u32_u32_immu32; shift = 16; break; case 0x18: ic->f = instr_add_u32_u32_immu32; break; case 0x19: ic->f = instr_sub_u32_u32_immu32; break; case 0x1a: ic->f = instr_divu_imm; break; case 0x1b: ic->f = instr_mulu_imm; break; // case 0x1c: ic->f = instr(add_imm); break; // case 0x1d: ic->f = instr(sub_imm); break; // case 0x1e: ic->f = instr(div_imm); break; case 0x1f: ic->f = instr_cmp_imm; break; } ic->arg[0].p = &m_r[d]; ic->arg[1].p = &m_r[s1]; ic->arg[2].u32 = imm16 << shift; // The 'and' instruction only ands bits in the upper or // lower parts of the word; the 'mask' instruction works // on the whole register. if (op26 == 0x10) ic->arg[2].u32 |= 0xffff0000; if (op26 == 0x11) ic->arg[2].u32 |= 0x0000ffff; if (d == M88K_ZERO_REG) ic->f = instr_nop; } break; case 0x20: if ((iw & 0x001ff81f) == 0x00004000) { ic->f = instr_ldcr; ic->arg[0].p = &m_r[d]; ic->arg[1].u32 = cr6; if (d == M88K_ZERO_REG) ic->arg[0].p = &m_zero_scratch; // } else if ((iword & 0x001ff81f) == 0x00004800) { // ic->f = instr(fldcr); // ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; // ic->arg[1] = cr6; // if (d == M88K_ZERO_REG) // ic->arg[0] = (size_t) // &cpu->cd.m88k.zero_scratch; } else if ((iw & 0x03e0f800) == 0x00008000) { ic->f = instr_stcr; ic->arg[0].p = &m_r[s1]; ic->arg[1].u32 = cr6; if (s1 != s2) { ic->f = NULL; if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "stcr with s1 != s2? TODO: how " "should this be handled? s1=0x" << s1 << ", s2=0x" << s2; ui->ShowDebugMessage(this, ss.str()); } } // } else if ((iword & 0x03e0f800) == 0x00008800) { // ic->f = instr(fstcr); // ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1]; // ic->arg[1] = cr6; // if (s1 != s2) // goto bad; // } else if ((iword & 0x0000f800) == 0x0000c000) { // ic->f = instr(xcr); // ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; // ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1]; // ic->arg[2] = cr6; // if (s1 != s2) // goto bad; } else if (ui != NULL) { ui->ShowDebugMessage(this, "unimplemented variant of opcode 0x20"); } break; case 0x30: /* br */ // case 0x31: /* br.n */ case 0x32: /* bsr */ case 0x33: /* bsr.n */ { void (*f_singleStepping)(CPUDyntransComponent*, struct DyntransIC*) = NULL; void (*samepage_function)(CPUDyntransComponent*, struct DyntransIC*) = NULL; switch (op26) { case 0x30: ic->f = NULL; // instr(br); samepage_function = instr_branch_samepage; break; // case 0x31: // ic->f = instr(br_n); // if (cpu->translation_readahead > 2) // cpu->translation_readahead = 2; // break; case 0x32: ic->f = instr_bsr; samepage_function = instr_bsr_samepage; break; case 0x33: ic->f = instr_bsr_n; // TODO samepage_function = instr_bsr_samepage; f_singleStepping = instr_bsr_n_functioncalltrace_singlestep; break; } if (singleInstructionLeft && (op26 == 0x31 || op26 == 0x33)) { ic->f = f_singleStepping; samepage_function = NULL; } int offset = (m_pc & 0xffc) + d26; /* Prepare both samepage and offset style args. (Only one will be used in the actual instruction.) */ ic->arg[0].p = ( m_firstIConPage + (offset >> M88K_INSTR_ALIGNMENT_SHIFT) ); ic->arg[1].u32 = offset; /* Return offset for bsr and bsr.n (stored in m_r[M88K_RETURN_REG]): */ ic->arg[2].u32 = (m_pc & 0xffc) + ((op26 & 1)? 8 : 4); if (offset >= 0 && offset <= 0xffc && samepage_function != NULL) ic->f = samepage_function; if (m_showFunctionTraceCall) { if (op26 == 0x32) ic->f = instr_bsr_functioncalltrace; if (op26 == 0x33) { if (singleInstructionLeft) ic->f = instr_bsr_n_functioncalltrace_singlestep; else ic->f = instr_bsr_n_functioncalltrace; } } } break; case 0x34: /* bb0 */ case 0x35: /* bb0.n */ case 0x36: /* bb1 */ case 0x37: /* bb1.n */ { void (*samepage_function)(CPUDyntransComponent*, struct DyntransIC*) = NULL; void (*singlestep_function)(CPUDyntransComponent*, struct DyntransIC*) = NULL; switch (op26) { case 0x34: ic->f = instr_bb; samepage_function = instr_bb; break; case 0x35: ic->f = instr_bb_n; singlestep_function = instr_bb_n_singlestep; break; case 0x36: ic->f = instr_bb; samepage_function = instr_bb; break; case 0x37: ic->f = instr_bb_n; singlestep_function = instr_bb_n_singlestep; break; } ic->arg[0].p = &m_r[s1]; ic->arg[1].u32 = (1 << d); int offset = (m_pc & 0xffc) + d16; ic->arg[2].u32 = offset; if (singleInstructionLeft && singlestep_function != NULL) ic->f = singlestep_function; else if (offset >= 0 && offset <= 0xffc && samepage_function != NULL) { ic->f = samepage_function; ic->arg[2].p = ( m_firstIConPage + (offset >> M88K_INSTR_ALIGNMENT_SHIFT) ); } } break; case 0x3a: /* bcnd */ case 0x3b: /* bcnd.n */ { void (*samepage_function)(CPUDyntransComponent*, struct DyntransIC*) = NULL; void (*singlestep_f)(CPUDyntransComponent*, struct DyntransIC*) = NULL; if (op26 & 1) { switch (d) { case 1: ic->f = instr_bcnd; singlestep_f = instr_bcnd; break; case 2: ic->f = instr_bcnd; singlestep_f = instr_bcnd; break; case 3: ic->f = instr_bcnd; singlestep_f = instr_bcnd; break; case 7: ic->f = instr_bcnd; singlestep_f = instr_bcnd; break; case 8: ic->f = instr_bcnd; singlestep_f = instr_bcnd; break; case 12: ic->f = instr_bcnd; singlestep_f = instr_bcnd; break; case 13: ic->f = instr_bcnd; singlestep_f = instr_bcnd; break; case 14: ic->f = instr_bcnd; singlestep_f = instr_bcnd; break; } } else { switch (d) { case 1: ic->f = instr_bcnd; break; case 2: ic->f = instr_bcnd; break; case 3: ic->f = instr_bcnd; break; case 7: ic->f = instr_bcnd; break; case 8: ic->f = instr_bcnd; break; case 12: ic->f = instr_bcnd; break; case 13: ic->f = instr_bcnd; break; case 14: ic->f = instr_bcnd; break; } } // TODO: samepage optimization: probably easiest to do using // another template bit... // samepage_function = m88k_bcnd[64 + d + 32 * (op26 & 1)]; if (ic->f == NULL) { if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "unimplemented bcnd condition code d = " << d; ui->ShowDebugMessage(this, ss.str()); } break; } ic->arg[0].p = &m_r[s1]; int offset = (m_pc & 0xffc) + d16; ic->arg[2].u32 = offset; if (singleInstructionLeft && singlestep_f != NULL) { ic->f = singlestep_f; } else if (offset >= 0 && offset <= 0xffc && samepage_function != NULL) { ic->f = samepage_function; ic->arg[2].p = ( m_firstIConPage + (offset >> M88K_INSTR_ALIGNMENT_SHIFT) ); } } break; case 0x3c: switch (op10) { // case 0x20: /* clr */ // case 0x22: /* set */ case 0x24: /* ext */ case 0x26: /* extu */ case 0x28: /* mak */ ic->arg[0].p = &m_r[d]; ic->arg[1].p = &m_r[s1]; ic->arg[2].u32 = iw & 0x3ff; switch (op10) { // case 0x20: ic->f = instr(mask_imm); // { // int w = ic->arg[2] >> 5; // int o = ic->arg[2] & 0x1f; // uint32_t x = w == 0? 0xffffffff // : ((uint32_t)1 << w) - 1; // x <<= o; // ic->arg[2] = ~x; // } // break; // case 0x22: ic->f = instr(or_imm); // { // int w = ic->arg[2] >> 5; // int o = ic->arg[2] & 0x1f; // uint32_t x = w == 0? 0xffffffff // : ((uint32_t)1 << w) - 1; // x <<= o; // ic->arg[2] = x; // } // break; case 0x24: ic->f = instr_ext_imm; break; case 0x26: ic->f = instr_extu_imm; break; case 0x28: ic->f = instr_mak_imm; break; } if (d == M88K_ZERO_REG) ic->f = instr_nop; break; case 0x34: /* tb0 */ case 0x36: /* tb1 */ ic->arg[0].u32 = 1 << d; // d is called B5 in the manual ic->arg[1].p = &m_r[s1]; ic->arg[2].u32 = iw & 0x1ff; switch (op10) { case 0x34: ic->f = instr_tb; break; case 0x36: ic->f = instr_tb; break; } break; default: if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "unimplemented opcode 0x" << op26 << ",0x" << op10; ui->ShowDebugMessage(this, ss.str()); } } break; case 0x3d: if ((iw & 0xf000) <= 0x3fff ) { // Load, Store, xmem, and lda: int op = 0, opsize, user = 0, wt = 0; int signedness = 1, scaled = 0; switch (iw & 0xf000) { case 0x2000: op = 1; /* st */ break; case 0x3000: op = 2; /* lda */ break; default: if ((iw & 0xf800) >= 0x0800) op = 0; /* ld */ else op = 3; /* xmem */ } /* for (most) ld, st, lda: */ opsize = (iw >> 10) & 3; /* Turn opsize into x, where size = 1 << x: */ opsize = 3 - opsize; if (op == 3) { /* xmem: */ opsize = -1; switch ((iw >> 10) & 3) { case 0: opsize = 0; break; case 1: opsize = 2; break; default:// Weird xmem opsize/type? TODO break; } if (opsize < 0) break; } else { if ((iw & 0xf800) == 0x800) { signedness = 0; if ((iw & 0xf00) < 0xc00) opsize = 1; else opsize = 0; } else { if (opsize >= 2 || op == 1) signedness = 0; } } if (iw & 0x100) user = 1; if (iw & 0x80) wt = 1; if (iw & 0x200) scaled = 1; if (wt) { // wt bit not yet implemented! TODO ic->f = NULL; break; } ic->arg[0].p = &m_r[d]; ic->arg[1].p = &m_r[s1]; ic->arg[2].p = &m_r[s2]; if (op == 0 || op == 1) { /* ld or st: */ int n = opsize + ((op == 1)? 4 : 0) + (signedness? 8 : 0) + (m_isBigEndian? 16 : 0) + (scaled? 32 : 0) + (user? 64 : 0); // // 4 , 0123 , 3 , true , 32 , 8 , user (TODO) switch (n) { // load = 0 case 0 + 0 + 0 + 0 + 0 + 0: ic->f = instr_loadstore; break; case 0 + 0 + 0 + 0 + 32 + 0: ic->f = instr_loadstore; break; case 0 + 0 + 0 + 16 + 0 + 0: ic->f = instr_loadstore; break; case 0 + 0 + 0 + 16 + 32 + 0: ic->f = instr_loadstore; break; case 1 + 0 + 0 + 0 + 0 + 0: ic->f = instr_loadstore; break; case 1 + 0 + 0 + 0 + 32 + 0: ic->f = instr_loadstore; break; case 1 + 0 + 0 + 16 + 0 + 0: ic->f = instr_loadstore; break; case 1 + 0 + 0 + 16 + 32 + 0: ic->f = instr_loadstore; break; case 2 + 0 + 0 + 0 + 0 + 0: ic->f = instr_loadstore; break; case 2 + 0 + 0 + 0 + 32 + 0: ic->f = instr_loadstore; break; case 2 + 0 + 0 + 16 + 0 + 0: ic->f = instr_loadstore; break; case 2 + 0 + 0 + 16 + 32 + 0: ic->f = instr_loadstore; break; case 3 + 0 + 0 + 0 + 0 + 0: ic->f = instr_loadstore; break; case 3 + 0 + 0 + 0 + 32 + 0: ic->f = instr_loadstore; break; case 3 + 0 + 0 + 16 + 0 + 0: ic->f = instr_loadstore; break; case 3 + 0 + 0 + 16 + 32 + 0: ic->f = instr_loadstore; break; // store = 4 case 0 + 4 + 0 + 0 + 0 + 0: ic->f = instr_loadstore; break; case 0 + 4 + 0 + 0 + 32 + 0: ic->f = instr_loadstore; break; case 0 + 4 + 0 + 16 + 0 + 0: ic->f = instr_loadstore; break; case 0 + 4 + 0 + 16 + 32 + 0: ic->f = instr_loadstore; break; case 1 + 4 + 0 + 0 + 0 + 0: ic->f = instr_loadstore; break; case 1 + 4 + 0 + 0 + 32 + 0: ic->f = instr_loadstore; break; case 1 + 4 + 0 + 16 + 0 + 0: ic->f = instr_loadstore; break; case 1 + 4 + 0 + 16 + 32 + 0: ic->f = instr_loadstore; break; case 2 + 4 + 0 + 0 + 0 + 0: ic->f = instr_loadstore; break; case 2 + 4 + 0 + 0 + 32 + 0: ic->f = instr_loadstore; break; case 2 + 4 + 0 + 16 + 0 + 0: ic->f = instr_loadstore; break; case 2 + 4 + 0 + 16 + 32 + 0: ic->f = instr_loadstore; break; case 3 + 4 + 0 + 0 + 0 + 0: ic->f = instr_loadstore; break; case 3 + 4 + 0 + 0 + 32 + 0: ic->f = instr_loadstore; break; case 3 + 4 + 0 + 16 + 0 + 0: ic->f = instr_loadstore; break; case 3 + 4 + 0 + 16 + 32 + 0: ic->f = instr_loadstore; break; default: std::cerr << "TODO generalize! scaled="<f != NULL) ic->arg[0].p = &m_zero_scratch; if (opsize == 3 && d == 31) { // m88k load/store of register pair r31/r0 is not // yet implemented: TODO: figure out how to deal with this. ic->f = NULL; break; } } else if (op == 2) { /* lda: */ if (scaled) { switch (opsize) { // case 0: // TODO: 88110 vs 88100 etc. ic->f = instr(addu); break; case 1: ic->f = instr_lda<2>; break; case 2: ic->f = instr_lda<4>; break; case 3: ic->f = instr_lda<8>; break; } } else { // TODO: 88110 vs 88100 etc. // ic->f = instr(addu); } // TODO: Perhaps 88110 loads into 0 are not nops, but cache ops? Look in docs. if (d == M88K_ZERO_REG && ic->f != NULL) ic->f = instr_nop; } else { /* xmem: */ // TODO // ic->f = instr(xmem_slow); // ic->arg[0] = iw; // if (d == M88K_ZERO_REG) // ic->f = instr(nop); } } else switch ((iw >> 8) & 0xff) { // case 0x40: /* and */ // case 0x44: /* and.c */ case 0x50: /* xor */ // case 0x54: /* xor.c */ case 0x58: /* or */ // case 0x5c: /* or.c */ case 0x60: /* addu */ // case 0x61: /* addu.co */ // case 0x62: /* addu.ci */ case 0x64: /* subu */ // case 0x65: /* subu.co */ // case 0x66: /* subu.ci */ // case 0x68: /* divu */ // case 0x6c: /* mul */ // case 0x70: /* add */ // case 0x78: /* div */ case 0x7c: /* cmp */ // case 0x80: /* clr */ // case 0x88: /* set */ case 0x90: /* ext */ case 0x98: /* extu */ case 0xa0: /* mak */ // case 0xa8: /* rot */ ic->arg[0].p = &m_r[d]; ic->arg[1].p = &m_r[s1]; ic->arg[2].p = &m_r[s2]; switch ((iw >> 8) & 0xff) { // case 0x40: ic->f = instr(and); break; // case 0x44: ic->f = instr(and_c); break; case 0x50: ic->f = instr_xor_u32_u32_u32; break; // case 0x54: ic->f = instr(xor_c); break; case 0x58: ic->f = instr_or_u32_u32_u32; break; // case 0x5c: ic->f = instr(or_c); break; case 0x60: ic->f = instr_add_u32_u32_u32; break; // case 0x61: ic->f = instr(addu_co); break; // case 0x62: ic->f = instr(addu_ci); break; case 0x64: ic->f = instr_sub_u32_u32_u32; break; // case 0x65: ic->f = instr(subu_co); break; // case 0x66: ic->f = instr(subu_ci); break; // case 0x68: ic->f = instr(divu); break; // case 0x6c: ic->f = instr(mul); break; // case 0x70: ic->f = instr(add); break; // case 0x78: ic->f = instr(div); break; case 0x7c: ic->f = instr_cmp; break; // case 0x80: ic->f = instr(clr); break; // case 0x88: ic->f = instr(set); break; case 0x90: ic->f = instr_ext; break; case 0x98: ic->f = instr_extu; break; case 0xa0: ic->f = instr_mak; break; // case 0xa8: ic->f = instr(rot); break; } /* * Handle the case when the destination register is r0: * * If there is NO SIDE-EFFECT! (i.e. no carry out, no possibility * of exceptions, etc), then replace the instruction with a nop. * If there is a possible side-effect, we still have to run the * instruction, so replace the destination register with the * scratch register. */ if (d == M88K_ZERO_REG && ic->f != NULL) { int opc = (iw >> 8) & 0xff; if (opc != 0x61 /* addu.co */ && opc != 0x63 /* addu.cio */ && opc != 0x65 /* subu.co */ && opc != 0x67 /* subu.cio */ && opc != 0x71 /* add.co */ && opc != 0x73 /* add.cio */ && opc != 0x75 /* sub.co */ && opc != 0x77 /* sub.cio */ && opc != 0x68 /* divu */ && opc != 0x69 /* divu.d */ && opc != 0x6c /* mul */ && opc != 0x6d /* mulu.d */ && opc != 0x6e /* muls */ && opc != 0x78 /* div */) ic->f = instr_nop; else ic->arg[0].p = &m_zero_scratch; } if (ic->f == NULL && ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "unimplemented opcode 0x3d,0x" << ((iw >> 8) & 0xff); ui->ShowDebugMessage(this, ss.str()); } break; case 0xc0: /* jmp */ case 0xc4: /* jmp.n */ // case 0xc8: /* jsr */ // case 0xcc: /* jsr.n */ { void (*f_ss)(CPUDyntransComponent*, struct DyntransIC*) = NULL; switch ((iw >> 8) & 0xff) { case 0xc0: ic->f = instr_jmp; break; case 0xc4: ic->f = instr_jmp_n; f_ss = instr_jmp_n_functioncalltrace_singlestep; break; // case 0xc8: ic->f = instr(jsr); break; // case 0xcc: ic->f = instr(jsr_n); break; } ic->arg[1].u32 = (m_pc & 0xffc) + 4; ic->arg[2].p = &m_r[s2]; if (((iw >> 8) & 0x04) == 0x04) ic->arg[1].u32 = (m_pc & 0xffc) + 8; if (m_showFunctionTraceCall && s2 == M88K_RETURN_REG) { if (ic->f == instr_jmp_n) { ic->f = instr_jmp_n_functioncalltrace; f_ss = instr_jmp_n_functioncalltrace_singlestep; } } // if (m_showFunctionTraceCall) { // if (ic->f == instr(jsr)) // ic->f = instr(jsr_trace); // TODO f_ss // if (ic->f == instr(jsr_n)) // ic->f = instr(jsr_n_trace); // TODO f_ss // } if (singleInstructionLeft && f_ss != NULL) ic->f = f_ss; } break; // case 0xe8: /* ff1 */ // case 0xec: /* ff0 */ // TODO case 0xfc: switch (iw & 0xff) { // case 0x00: /* rte */ // case 0x01: /* illop1 */ // case 0x02: /* illop2 */ // case 0x03: /* illop3 */ // case (M88K_PROM_INSTR & 0xff): case (M88K_FAIL_EARLY_INSTR & 0xff): ic->f = instr_fail_early; break; // case (M88K_FAIL_LATE_INSTR & 0xff): // break; default:if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "unimplemented opcode 0x3d,0xfc,0x" << (iw & 0xff); ui->ShowDebugMessage(this, ss.str()); } } break; default: if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "unimplemented opcode 0x3d,0x" << ((iw >> 8) & 0xff); ui->ShowDebugMessage(this, ss.str()); } } break; default: if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "unimplemented opcode 0x" << op26; ui->ShowDebugMessage(this, ss.str()); } } } DYNTRANS_INSTR(M88K_CPUComponent,ToBeTranslated) { DYNTRANS_INSTR_HEAD(M88K_CPUComponent) cpu->DyntransToBeTranslatedBegin(ic); uint32_t iword; if (cpu->DyntransReadInstruction(iword)) cpu->Translate(iword, ic); if (cpu->m_inDelaySlot && ic->f == NULL) ic->f = instr_abort; cpu->DyntransToBeTranslatedDone(ic); } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_M88K_CPUComponent_IsStable() { UnitTest::Assert("the M88K_CPUComponent should be stable", ComponentFactory::HasAttribute("m88k_cpu", "stable")); } static void Test_M88K_CPUComponent_Create() { refcount_ptr cpu = ComponentFactory::CreateComponent("m88k_cpu"); UnitTest::Assert("component was not created?", !cpu.IsNULL()); const StateVariable * p = cpu->GetVariable("pc"); UnitTest::Assert("cpu has no pc state variable?", p != NULL); UnitTest::Assert("initial pc", p->ToString(), "0"); const StateVariable * r31 = cpu->GetVariable("r31"); UnitTest::Assert("cpu has no r31 state variable?", r31 != NULL); UnitTest::Assert("initial r31", r31->ToString(), "0"); } static void Test_M88K_CPUComponent_Create_with_r31() { refcount_ptr cpu = ComponentFactory::CreateComponent("m88k_cpu(r31=0x12345678)"); UnitTest::Assert("component was not created?", !cpu.IsNULL()); const StateVariable * p = cpu->GetVariable("pc"); UnitTest::Assert("cpu has no pc state variable?", p != NULL); UnitTest::Assert("initial pc", p->ToString(), "0"); const StateVariable * r31 = cpu->GetVariable("r31"); UnitTest::Assert("cpu has no r31 state variable?", r31 != NULL); UnitTest::Assert("initial r31", r31->ToString(), "0x12345678"); cpu->SetVariableValue("r31", "0xf00"); const StateVariable * r31_updated = cpu->GetVariable("r31"); UnitTest::Assert("could not update r31?", r31_updated->ToString(), "0xf00"); cpu->Reset(); const StateVariable * r31_after_reset = cpu->GetVariable("r31"); UnitTest::Assert("r31 after reset should have been reset", r31_after_reset->ToString(), "0x12345678"); } static void Test_M88K_CPUComponent_IsCPU() { refcount_ptr m88k_cpu = ComponentFactory::CreateComponent("m88k_cpu"); CPUComponent* cpu = m88k_cpu->AsCPUComponent(); UnitTest::Assert("m88k_cpu is not a CPUComponent?", cpu != NULL); } static void Test_M88K_CPUComponent_DefaultModel() { refcount_ptr cpu = ComponentFactory::CreateComponent("m88k_cpu"); // Suitable default models would be 88100 and 88110 (the only two // implementations there were of the 88K architecture). However, // right now (2009-07-27), 88110 emulation isn't implemented yet. UnitTest::Assert("wrong default model", cpu->GetVariable("model")->ToString(), "88100"); } static void Test_M88K_CPUComponent_Disassembly_Basic() { refcount_ptr m88k_cpu = ComponentFactory::CreateComponent("m88k_cpu"); CPUComponent* cpu = m88k_cpu->AsCPUComponent(); vector result; size_t len; unsigned char instruction[sizeof(uint32_t)]; // This assumes that the default endianness is BigEndian... instruction[0] = 0x63; instruction[1] = 0xdf; instruction[2] = 0x00; instruction[3] = 0x10; len = cpu->DisassembleInstruction(0x12345678, sizeof(uint32_t), instruction, result); UnitTest::Assert("disassembled instruction was wrong length?", len, 4); UnitTest::Assert("disassembly result incomplete?", result.size(), 3); UnitTest::Assert("disassembly result[0]", result[0], "63df0010"); UnitTest::Assert("disassembly result[1]", result[1], "addu"); UnitTest::Assert("disassembly result[2]", result[2], "r30,r31,0x10"); } static void Test_M88K_CPUComponent_Execute_Basic() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testm88k"); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0"); UnitTest::Assert("huh? no cpu?", !cpu.IsNULL()); AddressDataBus* bus = cpu->AsAddressDataBus(); UnitTest::Assert("cpu should be addressable", bus != NULL); // Place a hardcoded instruction in memory, and try to execute it. // addu r30, r31, 0x10 uint32_t data32 = 0x63df0010; bus->AddressSelect(48); bus->WriteData(data32, BigEndian); bus->AddressSelect(52); bus->WriteData(data32, BigEndian); cpu->SetVariableValue("pc", "48"); cpu->SetVariableValue("r30", "1234"); cpu->SetVariableValue("r31", "5678"); gxemul.SetRunState(GXemul::Running); gxemul.Execute(1); UnitTest::Assert("pc should have increased", cpu->GetVariable("pc")->ToInteger(), 52); UnitTest::Assert("r30 should have been modified", cpu->GetVariable("r30")->ToInteger(), 5678 + 0x10); UnitTest::Assert("r31 should not have been modified", cpu->GetVariable("r31")->ToInteger(), 5678); cpu->SetVariableValue("r31", "1111"); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(1); UnitTest::Assert("pc should have increased again", cpu->GetVariable("pc")->ToInteger(), 56); UnitTest::Assert("r30 should have been modified again", cpu->GetVariable("r30")->ToInteger(), 1111 + 0x10); } static void Test_M88K_CPUComponent_Execute_DelayBranchWithValidInstruction() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testm88k"); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0"); UnitTest::Assert("huh? no cpu?", !cpu.IsNULL()); AddressDataBus* bus = cpu->AsAddressDataBus(); UnitTest::Assert("cpu should be addressable", bus != NULL); uint32_t data32 = 0xcc000010; // bsr.n 0x1000 + 10*4, i.e. 0x1040 bus->AddressSelect(0x1000ULL); bus->WriteData(data32, BigEndian); data32 = 0x63df0010; // Something valid, addu r30, r31, 0x10 bus->AddressSelect(0x1004ULL); bus->WriteData(data32, BigEndian); cpu->SetVariableValue("pc", "0x1000"); UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0x1000); UnitTest::Assert("r30 before execute", cpu->GetVariable("r30")->ToInteger(), 0); UnitTest::Assert("r31 before execute", cpu->GetVariable("r31")->ToInteger(), 0xff0); // This tests that execute 2 steps will execute both the delay branch // and the delay slot instruction. gxemul.SetRunState(GXemul::Running); gxemul.Execute(2); UnitTest::Assert("pc should have changed", cpu->GetVariable("pc")->ToInteger(), 0x1040); UnitTest::Assert("delay slot after execute", cpu->GetVariable("inDelaySlot")->ToString(), "false"); UnitTest::Assert("r30 after execute", cpu->GetVariable("r30")->ToInteger(), 0x1000); UnitTest::Assert("r31 after execute", cpu->GetVariable("r31")->ToInteger(), 0xff0); } static void Test_M88K_CPUComponent_Execute_DelayBranchWithValidInstruction_SingleStepping() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testm88k"); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0"); UnitTest::Assert("huh? no cpu?", !cpu.IsNULL()); AddressDataBus* bus = cpu->AsAddressDataBus(); UnitTest::Assert("cpu should be addressable", bus != NULL); uint32_t data32 = 0xcc000010; // bsr.n 0x1000 + 10*4, i.e. 0x1040 bus->AddressSelect(0x1000ULL); bus->WriteData(data32, BigEndian); data32 = 0x63df0010; // Something valid, addu r30, r31, 0x10 bus->AddressSelect(0x1004ULL); bus->WriteData(data32, BigEndian); cpu->SetVariableValue("pc", "0x1000"); UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0x1000); UnitTest::Assert("r30 before execute", cpu->GetVariable("r30")->ToInteger(), 0); UnitTest::Assert("r31 before execute", cpu->GetVariable("r31")->ToInteger(), 0xff0); // This tests that execute 2 steps (using single-stepping) will execute both // the delay branch and the delay slot instruction. gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(1); // Should now be in the delay slot. UnitTest::Assert("pc should have changed 1", cpu->GetVariable("pc")->ToInteger(), 0x1004); UnitTest::Assert("delay slot after execute 1", cpu->GetVariable("inDelaySlot")->ToString(), "true"); UnitTest::Assert("r30 after execute 1", cpu->GetVariable("r30")->ToInteger(), 0); UnitTest::Assert("r31 after execute 1", cpu->GetVariable("r31")->ToInteger(), 0xff0); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(1); UnitTest::Assert("delay slot after execute 2", cpu->GetVariable("inDelaySlot")->ToString(), "false"); UnitTest::Assert("pc should have changed 2", cpu->GetVariable("pc")->ToInteger(), 0x1040); UnitTest::Assert("r30 after execute 2", cpu->GetVariable("r30")->ToInteger(), 0x1000); UnitTest::Assert("r31 after execute 2", cpu->GetVariable("r31")->ToInteger(), 0xff0); } static void Test_M88K_CPUComponent_Execute_DelayBranchWithValidInstruction_RunTwoTimes() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testm88k"); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0"); UnitTest::Assert("huh? no cpu?", !cpu.IsNULL()); AddressDataBus* bus = cpu->AsAddressDataBus(); UnitTest::Assert("cpu should be addressable", bus != NULL); uint32_t data32 = 0xcc000010; // bsr.n 0x1000 + 10*4, i.e. 0x1040 bus->AddressSelect(0x1000ULL); bus->WriteData(data32, BigEndian); data32 = 0x63df0010; // Something valid, addu r30, r31, 0x10 bus->AddressSelect(0x1004ULL); bus->WriteData(data32, BigEndian); cpu->SetVariableValue("pc", "0x1000"); UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0x1000); UnitTest::Assert("r30 before execute", cpu->GetVariable("r30")->ToInteger(), 0); UnitTest::Assert("r31 before execute", cpu->GetVariable("r31")->ToInteger(), 0xff0); // This tests that execute 2 steps (using single-stepping) will execute both // the delay branch and the delay slot instruction. gxemul.SetRunState(GXemul::Running); gxemul.Execute(1); // Should now be in the delay slot. UnitTest::Assert("pc should have changed 1", cpu->GetVariable("pc")->ToInteger(), 0x1004); UnitTest::Assert("delay slot after execute 1", cpu->GetVariable("inDelaySlot")->ToString(), "true"); UnitTest::Assert("r30 after execute 1", cpu->GetVariable("r30")->ToInteger(), 0); UnitTest::Assert("r31 after execute 1", cpu->GetVariable("r31")->ToInteger(), 0xff0); gxemul.SetRunState(GXemul::Running); gxemul.Execute(1); UnitTest::Assert("delay slot after execute 2", cpu->GetVariable("inDelaySlot")->ToString(), "false"); UnitTest::Assert("pc should have changed 2", cpu->GetVariable("pc")->ToInteger(), 0x1040); UnitTest::Assert("r30 after execute 2", cpu->GetVariable("r30")->ToInteger(), 0x1000); UnitTest::Assert("r31 after execute 2", cpu->GetVariable("r31")->ToInteger(), 0xff0); } static void Test_M88K_CPUComponent_Execute_DelayBranchWithFault() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testm88k"); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0"); UnitTest::Assert("huh? no cpu?", !cpu.IsNULL()); AddressDataBus* bus = cpu->AsAddressDataBus(); UnitTest::Assert("cpu should be addressable", bus != NULL); uint32_t data32 = 0xcc000010; // bsr.n 0x1000 + 10*4, i.e. 0x1040 bus->AddressSelect(0x1000ULL); bus->WriteData(data32, BigEndian); data32 = 0xffffffff; // Something invalid bus->AddressSelect(0x1004ULL); bus->WriteData(data32, BigEndian); cpu->SetVariableValue("pc", "0x1000"); UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0x1000); UnitTest::Assert("r30 before execute", cpu->GetVariable("r30")->ToInteger(), 0); UnitTest::Assert("r31 before execute", cpu->GetVariable("r31")->ToInteger(), 0xff0); // This tests that execute 100 steps will only execute 1, if the instruction // in the delay slot fails. gxemul.SetRunState(GXemul::Running); gxemul.Execute(100); UnitTest::Assert("pc should have increased one step", cpu->GetVariable("pc")->ToInteger(), 0x1004ULL); UnitTest::Assert("should be in delay slot after execution", cpu->GetVariable("inDelaySlot")->ToString(), "true"); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(1); UnitTest::Assert("pc should not have increased", cpu->GetVariable("pc")->ToInteger(), 0x1004ULL); UnitTest::Assert("should still be in delay slot", cpu->GetVariable("inDelaySlot")->ToString(), "true"); } static void Test_M88K_CPUComponent_Execute_EarlyAbortDuringRuntime_Singlestep() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testm88k"); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0"); UnitTest::Assert("huh? no cpu?", !cpu.IsNULL()); AddressDataBus* bus = cpu->AsAddressDataBus(); UnitTest::Assert("cpu should be addressable", bus != NULL); uint32_t data32 = 0xcc000010; // bsr.n 0x1000 + 10*4, i.e. 0x1040 bus->AddressSelect(0x1000ULL); bus->WriteData(data32, BigEndian); data32 = 0xf400fc93; // Something which is valid during interpretation, // but invalid during runtime (i.e. aborts). bus->AddressSelect(0x1004ULL); bus->WriteData(data32, BigEndian); cpu->SetVariableValue("pc", "0x1000"); UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0x1000); // This tests that execute 100 steps will only execute 1, if the // instruction in the delay slot aborts early. gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(100); UnitTest::Assert("1 step should have executed", cpu->GetVariable("step")->ToInteger(), 1); UnitTest::Assert("pc should have increased one step", cpu->GetVariable("pc")->ToInteger(), 0x1004ULL); UnitTest::Assert("should be in delay slot after execution", cpu->GetVariable("inDelaySlot")->ToString(), "true"); UnitTest::Assert("delay target should have been updated", cpu->GetVariable("delaySlotTarget")->ToInteger(), 0x1040); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(1); UnitTest::Assert("no more steps should have executed", cpu->GetVariable("step")->ToInteger(), 1); UnitTest::Assert("pc should not have increased", cpu->GetVariable("pc")->ToInteger(), 0x1004ULL); UnitTest::Assert("should still be in delay slot", cpu->GetVariable("inDelaySlot")->ToString(), "true"); UnitTest::Assert("delay target should not have been updated", cpu->GetVariable("delaySlotTarget")->ToInteger(), 0x1040); } static void Test_M88K_CPUComponent_Execute_EarlyAbortDuringRuntime_Running() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testm88k"); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0"); UnitTest::Assert("huh? no cpu?", !cpu.IsNULL()); AddressDataBus* bus = cpu->AsAddressDataBus(); UnitTest::Assert("cpu should be addressable", bus != NULL); uint32_t data32 = 0xcc000010; // bsr.n 0x1000 + 10*4, i.e. 0x1040 bus->AddressSelect(0x1000ULL); bus->WriteData(data32, BigEndian); data32 = 0xf400fc93; // Something which is valid during interpretation, // but invalid during runtime (i.e. aborts). bus->AddressSelect(0x1004ULL); bus->WriteData(data32, BigEndian); cpu->SetVariableValue("pc", "0x1000"); UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0x1000); // This tests that execute 100 steps will only execute 1, if the // instruction in the delay slot aborts early. gxemul.SetRunState(GXemul::Running); gxemul.Execute(100); UnitTest::Assert("1 step should have executed", cpu->GetVariable("step")->ToInteger(), 1); UnitTest::Assert("pc should have increased one step", cpu->GetVariable("pc")->ToInteger(), 0x1004ULL); UnitTest::Assert("should be in delay slot after execution", cpu->GetVariable("inDelaySlot")->ToString(), "true"); UnitTest::Assert("delay target should have been updated", cpu->GetVariable("delaySlotTarget")->ToInteger(), 0x1040); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(1); UnitTest::Assert("no more steps should have executed", cpu->GetVariable("step")->ToInteger(), 1); UnitTest::Assert("pc should not have increased", cpu->GetVariable("pc")->ToInteger(), 0x1004ULL); UnitTest::Assert("should still be in delay slot", cpu->GetVariable("inDelaySlot")->ToString(), "true"); UnitTest::Assert("delay target should not have been updated", cpu->GetVariable("delaySlotTarget")->ToInteger(), 0x1040); } UNITTESTS(M88K_CPUComponent) { UNITTEST(Test_M88K_CPUComponent_IsStable); UNITTEST(Test_M88K_CPUComponent_Create); UNITTEST(Test_M88K_CPUComponent_Create_with_r31); UNITTEST(Test_M88K_CPUComponent_IsCPU); UNITTEST(Test_M88K_CPUComponent_DefaultModel); // Disassembly: UNITTEST(Test_M88K_CPUComponent_Disassembly_Basic); // Dyntrans execution: UNITTEST(Test_M88K_CPUComponent_Execute_Basic); UNITTEST(Test_M88K_CPUComponent_Execute_DelayBranchWithValidInstruction); UNITTEST(Test_M88K_CPUComponent_Execute_DelayBranchWithValidInstruction_SingleStepping); UNITTEST(Test_M88K_CPUComponent_Execute_DelayBranchWithValidInstruction_RunTwoTimes); UNITTEST(Test_M88K_CPUComponent_Execute_DelayBranchWithFault); UNITTEST(Test_M88K_CPUComponent_Execute_EarlyAbortDuringRuntime_Singlestep); UNITTEST(Test_M88K_CPUComponent_Execute_EarlyAbortDuringRuntime_Running); // UNITTEST(Test_M88K_CPUComponent_Execute_LateAbortDuringRuntime); } #endif gxemul-0.6.1/src/components/cpu/CPUComponent.cc000644 001750 001750 00000042655 13402411502 021625 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "AddressDataBus.h" #include "components/CPUComponent.h" #include "GXemul.h" CPUComponent::CPUComponent(const string& className, const string& cpuArchitecture) : Component(className, "cpu") // all cpus have "cpu" as their // visible class name, regardless of // their actual class name , m_frequency(33.0e6) , m_paused(false) , m_cpuArchitecture(cpuArchitecture) , m_pageSize(0) , m_pc(0) , m_lastDumpAddr(0) , m_lastUnassembleVaddr(0) , m_hasUsedUnassemble(false) , m_isBigEndian(true) , m_showFunctionTraceCall(false) , m_showFunctionTraceReturn(false) , m_functionCallTraceDepth(0) , m_nrOfTracedFunctionCalls(0) , m_addressDataBus(NULL) { AddVariable("architecture", &m_cpuArchitecture); AddVariable("pc", &m_pc); AddVariable("lastDumpAddr", &m_lastDumpAddr); AddVariable("lastUnassembleVaddr", &m_lastUnassembleVaddr); AddVariable("hasUsedUnassemble", &m_hasUsedUnassemble); AddVariable("frequency", &m_frequency); AddVariable("paused", &m_paused); AddVariable("bigendian", &m_isBigEndian); AddVariable("showFunctionTraceCall", &m_showFunctionTraceCall); AddVariable("showFunctionTraceReturn", &m_showFunctionTraceReturn); AddVariable("functionCallTraceDepth", &m_functionCallTraceDepth); AddVariable("nrOfTracedFunctionCalls", &m_nrOfTracedFunctionCalls); } double CPUComponent::GetCurrentFrequency() const { return m_frequency; } CPUComponent * CPUComponent::AsCPUComponent() { return this; } void CPUComponent::ResetState() { m_hasUsedUnassemble = false; m_exceptionOrAbortInDelaySlot = false; m_inDelaySlot = false; m_delaySlotTarget = 0; // Don't reset m_showFunctionTraceCall and Return here? m_functionCallTraceDepth = 0; m_nrOfTracedFunctionCalls = 0; m_symbolRegistry.Clear(); Component::ResetState(); } bool CPUComponent::FunctionTraceCall() { stringstream ss; for (int i=0; i -1000 && arg < 1000) { ss << arg; } else { ss.flags(std::ios::hex); ss << "0x" << (uint64_t)arg; } // TODO: String and/or symbol lookup! ss << ","; } ss << "...)\n"; GetUI()->ShowDebugMessage(this, ss.str()); ++ m_nrOfTracedFunctionCalls; ++ m_functionCallTraceDepth; if (m_functionCallTraceDepth > 100) m_functionCallTraceDepth = 100; GXemul* gxemul = GetRunningGXemulInstance(); if (gxemul != NULL && gxemul->IsInterrupting()) return false; return true; } bool CPUComponent::FunctionTraceReturn() { -- m_functionCallTraceDepth; if (m_functionCallTraceDepth < 0) m_functionCallTraceDepth = 0; if (m_showFunctionTraceReturn) { int64_t retval; bool traceReturnValid = FunctionTraceReturnImpl(retval); if (traceReturnValid) { stringstream ss; for (int i=0; i -1000 && retval < 1000) { ss << "= " << retval; } else { ss.flags(std::ios::hex); ss << "= 0x" << (uint64_t)retval; } // TODO: String and/or symbol lookup! GetUI()->ShowDebugMessage(this, ss.str()); } GXemul* gxemul = GetRunningGXemulInstance(); if (gxemul != NULL && gxemul->IsInterrupting()) return false; } return true; } void CPUComponent::GetMethodNames(vector& names) const { // Add our method names... names.push_back("dump"); names.push_back("registers"); names.push_back("unassemble"); // ... and make sure to call the base class implementation: Component::GetMethodNames(names); } bool CPUComponent::MethodMayBeReexecutedWithoutArgs(const string& methodName) const { if (methodName == "dump") return true; if (methodName == "unassemble") return true; // ... and make sure to call the base class implementation: return Component::MethodMayBeReexecutedWithoutArgs(methodName); } void CPUComponent::ExecuteMethod(GXemul* gxemul, const string& methodName, const vector& arguments) { if (methodName == "dump") { uint64_t vaddr = m_lastDumpAddr; if (arguments.size() > 1) { gxemul->GetUI()->ShowDebugMessage("syntax: .dump [addr]\n"); return; } if (arguments.size() == 1) { gxemul->GetUI()->ShowDebugMessage("TODO: parse address expression\n"); gxemul->GetUI()->ShowDebugMessage("(for now, only hex immediate values are supported!)\n"); stringstream ss; ss << arguments[0]; ss.flags(std::ios::hex); ss >> vaddr; } const int nRows = 16; for (int i=0; i 0xffffffff) ss << std::setw(16); else ss << std::setw(8); ss << std::setfill('0') << vaddr; size_t k; for (k=0; k= 32 && data[k] < 127? data[k] : '.'; s[1] = '\0'; if (readable[k]) ss << s; else ss << "-"; } ss << "\n"; gxemul->GetUI()->ShowDebugMessage(ss.str()); vaddr += len; } m_lastDumpAddr = vaddr; return; } if (methodName == "registers") { ShowRegisters(gxemul, arguments); return; } if (methodName == "unassemble") { uint64_t vaddr = m_lastUnassembleVaddr; if (!m_hasUsedUnassemble) vaddr = PCtoInstructionAddress(m_pc); if (arguments.size() > 1) { gxemul->GetUI()->ShowDebugMessage("syntax: .unassemble [addr]\n"); return; } if (arguments.size() == 1) { gxemul->GetUI()->ShowDebugMessage("TODO: parse address expression\n"); gxemul->GetUI()->ShowDebugMessage("(for now, only hex immediate values are supported!)\n"); stringstream ss; ss << arguments[0]; ss.flags(std::ios::hex); ss >> vaddr; } const int nRows = 20; stringstream output; vaddr = Unassemble(nRows, true, vaddr, output); gxemul->GetUI()->ShowDebugMessage(output.str()); m_hasUsedUnassemble = true; m_lastUnassembleVaddr = vaddr; return; } // Call base... Component::ExecuteMethod(gxemul, methodName, arguments); } uint64_t CPUComponent::Unassemble(int nRows, bool indicatePC, uint64_t vaddr, ostream& output) { vector< vector > outputRows; for (int i=0; i()); // TODO: GENERALIZE! Some archs will have longer // instructions, or unaligned, or over page boundaries! size_t maxLen = sizeof(uint32_t); maxLen += sizeof(uint32_t); // i960 experimentation hack unsigned char instruction[maxLen]; bool readOk = true; for (size_t k=0; k"); outputRows.push_back(vector()); } stringstream ss; ss.flags(std::ios::hex | std::ios::showbase); ss << VirtualAddressAsString(vaddr); if (indicatePC && PCtoInstructionAddress(m_pc) == vaddr) ss << " <- "; else ss << " "; outputRows[outputRows.size()-1].push_back(ss.str()); if (!readOk) { stringstream ss2; ss2 << "\tmemory could not be read"; if (m_addressDataBus == NULL) ss2 << "; no address/data bus connected to the CPU"; ss2 << "\n"; outputRows[outputRows.size()-1].push_back(ss2.str()); break; } else { vector result; size_t len = DisassembleInstruction(vaddr, maxLen, instruction, result); vaddr += len; for (size_t j=0; j columnWidths; size_t row; for (row=0; row" on empty lines, when // calculating column width. if (nColumns <= 1) continue; if (columnWidths.size() < nColumns) columnWidths.resize(nColumns); for (size_t col=0; col columnWidths[col]) columnWidths[col] = s.length(); } } for (row=0; row& rowVector = outputRows[row]; for (size_t i=0; i=2 because: // index 0 is the first column, no spaces before that one, // but also: index 1 because the spaces after the vaddr // is a special case ("<-" pc indicator). if (i >= 2) output << " "; size_t len = rowVector[i].length(); output << rowVector[i]; int nspaces = columnWidths[i] - len; for (int j=0; jGetUI()->ShowDebugMessage(this, "this CPU" " has neither any child components nor any parent component" " that can act as address/data bus, so there is no place" " to read instructions from\n"); return false; } return true; } bool CPUComponent::LookupAddressDataBus(GXemul* gxemul) { if (m_addressDataBus != NULL) return true; // Find a suitable address data bus. AddressDataBus *bus = NULL; // 1) A direct first-level decendant of the CPU is probably a // cache. Use this if it exists. // If there are multiple AddressDataBus capable children, // print a debug warning, and just choose any of the children // (the last one). Components& children = GetChildren(); Component* choosenChild = NULL; bool multipleChildBussesFound = false; for (size_t i=0; iAsAddressDataBus(); if (childBus != NULL) { if (bus != NULL) multipleChildBussesFound = true; bus = childBus; choosenChild = children[i]; } } if (multipleChildBussesFound && gxemul != NULL) gxemul->GetUI()->ShowDebugMessage(this, "warning: this CPU has " "multiple child components that can act as address/data busses; " "using " + choosenChild->GenerateShortestPossiblePath() + "\n"); // 2) If no cache exists, go to a parent bus (usually a mainbus). if (bus == NULL) { refcount_ptr component = GetParent(); while (!component.IsNULL()) { bus = component->AsAddressDataBus(); if (bus != NULL) break; component = component->GetParent(); } } m_addressDataBus = bus; return m_addressDataBus != NULL; } void CPUComponent::ShowRegisters(GXemul* gxemul, const vector& arguments) const { gxemul->GetUI()->ShowDebugMessage("The registers method has not yet " "been implemented for this CPU type. TODO.\n"); } void CPUComponent::AddressSelect(uint64_t address) { m_addressSelect = address; } bool CPUComponent::ReadData(uint8_t& data, Endianness endianness) { if (!LookupAddressDataBus()) return false; uint64_t paddr; bool writable; VirtualToPhysical(m_addressSelect, paddr, writable); m_addressDataBus->AddressSelect(paddr); return m_addressDataBus->ReadData(data, endianness); } bool CPUComponent::ReadData(uint16_t& data, Endianness endianness) { assert((m_addressSelect & 1) == 0); if (!LookupAddressDataBus()) return false; uint64_t paddr; bool writable; VirtualToPhysical(m_addressSelect, paddr, writable); m_addressDataBus->AddressSelect(paddr); return m_addressDataBus->ReadData(data, endianness); } bool CPUComponent::ReadData(uint32_t& data, Endianness endianness) { assert((m_addressSelect & 3) == 0); if (!LookupAddressDataBus()) return false; uint64_t paddr; bool writable; VirtualToPhysical(m_addressSelect, paddr, writable); m_addressDataBus->AddressSelect(paddr); return m_addressDataBus->ReadData(data, endianness); } bool CPUComponent::ReadData(uint64_t& data, Endianness endianness) { assert((m_addressSelect & 7) == 0); if (!LookupAddressDataBus()) return false; uint64_t paddr; bool writable; VirtualToPhysical(m_addressSelect, paddr, writable); m_addressDataBus->AddressSelect(paddr); return m_addressDataBus->ReadData(data, endianness); } bool CPUComponent::WriteData(const uint8_t& data, Endianness endianness) { if (!LookupAddressDataBus()) return false; uint64_t paddr; bool writable; VirtualToPhysical(m_addressSelect, paddr, writable); m_addressDataBus->AddressSelect(paddr); return m_addressDataBus->WriteData(data, endianness); } bool CPUComponent::WriteData(const uint16_t& data, Endianness endianness) { assert((m_addressSelect & 1) == 0); if (!LookupAddressDataBus()) return false; uint64_t paddr; bool writable; VirtualToPhysical(m_addressSelect, paddr, writable); m_addressDataBus->AddressSelect(paddr); return m_addressDataBus->WriteData(data, endianness); } bool CPUComponent::WriteData(const uint32_t& data, Endianness endianness) { assert((m_addressSelect & 3) == 0); if (!LookupAddressDataBus()) return false; uint64_t paddr; bool writable; VirtualToPhysical(m_addressSelect, paddr, writable); m_addressDataBus->AddressSelect(paddr); return m_addressDataBus->WriteData(data, endianness); } bool CPUComponent::WriteData(const uint64_t& data, Endianness endianness) { assert((m_addressSelect & 7) == 0); if (!LookupAddressDataBus()) return false; uint64_t paddr; bool writable; VirtualToPhysical(m_addressSelect, paddr, writable); m_addressDataBus->AddressSelect(paddr); return m_addressDataBus->WriteData(data, endianness); } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_CPUComponent_IsStable() { UnitTest::Assert("the CPUComponent should not have attributes", !ComponentFactory::HasAttribute("cpu", "stable")); } static void Test_CPUComponent_Create() { // CPUComponent is abstract, and should not be possible to create. refcount_ptr cpu = ComponentFactory::CreateComponent("cpu"); UnitTest::Assert("component was created?", cpu.IsNULL()); } static void Test_CPUComponent_PreRunCheck() { GXemul gxemul; // Attempting to run a cpu with nothing connected to it should FAIL! gxemul.GetCommandInterpreter().RunCommand("add mips_cpu"); UnitTest::Assert("preruncheck should fail", gxemul.GetRootComponent()->PreRunCheck(&gxemul) == false); // Running a CPU with RAM should however succeed: gxemul.GetCommandInterpreter().RunCommand("add ram cpu0"); UnitTest::Assert("preruncheck should succeed", gxemul.GetRootComponent()->PreRunCheck(&gxemul) == true); } static void Test_CPUComponent_Methods_Reexecutableness() { refcount_ptr cpu = ComponentFactory::CreateComponent("mips_cpu"); UnitTest::Assert("dump method SHOULD be re-executable" " without args", cpu->MethodMayBeReexecutedWithoutArgs("dump") == true); UnitTest::Assert("registers method should NOT be re-executable" " without args", cpu->MethodMayBeReexecutedWithoutArgs("registers") == false); UnitTest::Assert("unassemble method SHOULD be re-executable" " without args", cpu->MethodMayBeReexecutedWithoutArgs("unassemble") == true); UnitTest::Assert("nonexistant method should NOT be re-executable" " without args", cpu->MethodMayBeReexecutedWithoutArgs("nonexistant") == false); } UNITTESTS(CPUComponent) { UNITTEST(Test_CPUComponent_IsStable); UNITTEST(Test_CPUComponent_Create); UNITTEST(Test_CPUComponent_PreRunCheck); UNITTEST(Test_CPUComponent_Methods_Reexecutableness); } #endif gxemul-0.6.1/src/components/cpu/CPUDyntransComponent.cc000644 001750 001750 00000052170 13402411502 023341 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "AddressDataBus.h" #include "components/CPUDyntransComponent.h" #include "GXemul.h" CPUDyntransComponent::CPUDyntransComponent(const string& className, const string& cpuArchitecture) : CPUComponent(className, cpuArchitecture) { m_abortIC.f = instr_abort; } void CPUDyntransComponent::DyntransInit() { m_nextIC = NULL; m_firstIConPage = NULL; m_dyntransICshift = GetDyntransICshift(); m_dyntransICentriesPerPage = m_pageSize >> m_dyntransICshift; m_dyntransPageMask = (m_pageSize - 1) - ((1 << m_dyntransICshift) - 1); int pageShift = 0; while (pageShift < 32 && (1 << pageShift) != m_pageSize) pageShift ++; if (pageShift >= 32) { std::cerr << "Non-power-of-2 page size?\n"; throw std::exception(); } // 32 MB translation cache (per emulated CPU): m_translationCache.Reinit(32 * 1024 * 1024, m_dyntransICentriesPerPage + DYNTRANS_PAGE_NSPECIALENTRIES, pageShift); } /* * Dynamic translation core * ------------------------ * * The core of GXemul's dynamic translation is a simple function call to * an entry in an array of pointers. Each call also moves the pointer of the * next function call to the next entry in the array. For most simple * instruction implementations, the instruction call pointer (m_nextIC) does * not have to be modified, because it is assumed that an instruction will * change the program counter to the next instruction. * * Before starting the main loop, the pc is used to look up the correct * m_nextIC value, by calling DyntransPCtoPointers(). * * During the loop, the pc value is _not_ necessarily updated for each * instruction call. Instead, the low bits of the pc value should be considered * meaningless, and the offset of the m_nextIC pointer within the current * code page (pointed to by m_firstIConPage) defines the lowest pc bits. * * After completing the main loop, the pc value is resynched by calling * DyntransResyncPC(). */ int CPUDyntransComponent::Execute(GXemul* gxemul, int nrOfCycles) { DyntransInit(); DyntransPCtoPointers(); struct DyntransIC *ic = m_nextIC; if (m_nextIC == NULL || m_firstIConPage == NULL) { std::cerr << "Internal error: m_nextIC or m_firstIConPage is NULL.\n"; throw std::exception(); } if (gxemul->GetRunState() == GXemul::SingleStepping) { if (nrOfCycles != 1) { std::cerr << "Internal error: Single stepping," " but nrOfCycles = " << nrOfCycles << ".\n"; throw std::exception(); } stringstream disasm; Unassemble(1, false, PCtoInstructionAddress(m_pc), disasm); gxemul->GetUI()->ShowDebugMessage(this, disasm.str()); m_nextIC->f = GetDyntransToBeTranslated(); } /* * The normal instruction execution core: Get the instruction call pointer * (and move the nextIC to the following instruction in advance), then * execute the instruction call by calling its f. */ #define IC ic = m_nextIC ++; ic->f(this, ic); m_nrOfCyclesToExecute = nrOfCycles; m_executedCycles = 0; // Starting inside a delay slot? Then execute it carefully: if (m_inDelaySlot) { m_nextIC->f = GetDyntransToBeTranslated(); m_executedCycles = m_nrOfCyclesToExecute - 1; IC m_executedCycles -= (m_nrOfCyclesToExecute - 1); m_executedCycles ++; // Fault in delay slot: return immediately. if (m_nextIC->f == instr_abort) { m_nextIC->f = GetDyntransToBeTranslated(); return 0; } } // If possible, do some optimized loops of multiple inlined IC calls... const int ICsPerLoop = 60; const int maxICcycles = 2; // TODO: Longer when instr combos are reimplemented if (nrOfCycles > ICsPerLoop * maxICcycles) { int hazard = nrOfCycles - ICsPerLoop * maxICcycles; for (;;) { IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC IC m_executedCycles += ICsPerLoop; if (m_executedCycles >= hazard || m_nextIC->f == instr_abort) break; } } // ... then slowly execute the last few instructions. // Note: -1, because the last thing we execute may be an instruction // with a delay slot (which is automatically executed). for (; m_executedCyclesf != instr_abort) { m_nextIC->f = GetDyntransToBeTranslated(); IC m_executedCycles ++; } DyntransResyncPC(); // If execution aborted, then reset the aborting instruction slot // to the to-be-translated function: if (m_nextIC->f == instr_abort) m_nextIC->f = GetDyntransToBeTranslated(); return m_executedCycles; } void CPUDyntransComponent::DyntransClearICPage(struct DyntransIC* icpage) { // Fill the page with "to be translated" entries, which when executed // will read the instruction from memory, attempt to translate it, and // then execute it. void (*f)(CPUDyntransComponent*, DyntransIC*) = GetDyntransToBeTranslated(); for (int i=0; if == instr_abort) { // Already aborted, let's not update m_nextIC. std::cerr << "TODO: Already aborted, let's not update m_nextIC." " Is this correct behavior?\n"; return; } m_firstIConPage = DyntransGetICPage(m_pc); assert(m_firstIConPage != NULL); // Here, m_firstIConPage points to a valid page. Calculate m_nextIC from // the low bits of m_pc: int offsetWithinPage = (m_pc & m_dyntransPageMask) >> m_dyntransICshift; m_nextIC = m_firstIConPage + offsetWithinPage; } void CPUDyntransComponent::DyntransResyncPC() { // Special case during aborts: if (m_nextIC == &m_abortIC) { // The situation which caused m_nextIC to be set to an abort // IC must have synched PC just before that. So we don't need // to do anything here. return; } std::ptrdiff_t instructionIndex = m_nextIC - m_firstIConPage; // On a page with e.g. 1024 instruction slots, instructionIndex is usually // between 0 and 1023. This means that the PC points to within this // page. // // We synchronize the PC by clearing out the bits within the IC page, // and then adding the offset to the instruction. if (instructionIndex >= 0 && instructionIndex < m_dyntransICentriesPerPage) { m_pc &= ~m_dyntransPageMask; m_pc += (instructionIndex << m_dyntransICshift); return; } // However, the instruction index may point outside the IC page. // This happens when synching the PC just after the last instruction // on a page has been executed. This means that we set the PC to // the start of the next page. if (instructionIndex == m_dyntransICentriesPerPage) { m_pc &= ~m_dyntransPageMask; m_pc += (m_dyntransPageMask + (1 << m_dyntransICshift)); return; } if (instructionIndex == m_dyntransICentriesPerPage + 1) { std::cerr << "TODO: DyntransResyncPC: Second end-of-page slot.\n"; // This may happen for delay-slot architectures. throw std::exception(); } std::cerr << "TODO: DyntransResyncPC: next ic outside of page?!\n"; throw std::exception(); } void CPUDyntransComponent::DyntransToBeTranslatedBegin(struct DyntransIC* ic) { // Resynchronize the PC to the instruction currently being translated. // (m_nextIC should already have been increased, to point to the _next_ // instruction slot.) m_nextIC = ic; DyntransResyncPC(); // TODO: Check for m_pc breakpoints etc. // First, let's assume that the translation will fail. ic->f = NULL; } bool CPUDyntransComponent::DyntransReadInstruction(uint16_t& iword) { // TODO: Fast lookup. AddressSelect(PCtoInstructionAddress(m_pc)); bool readable = ReadData(iword, m_isBigEndian? BigEndian : LittleEndian); if (!readable) { UI* ui = GetUI(); if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "instruction at 0x" << PCtoInstructionAddress(m_pc) << " could not be read!"; ui->ShowDebugMessage(this, ss.str()); } return false; } return true; } bool CPUDyntransComponent::DyntransReadInstruction(uint32_t& iword, int offset) { // TODO: Fast lookup. AddressSelect(PCtoInstructionAddress(m_pc + offset)); bool readable = ReadData(iword, m_isBigEndian? BigEndian : LittleEndian); if (!readable) { UI* ui = GetUI(); if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "instruction at 0x" << PCtoInstructionAddress(m_pc + offset) << " could not be read!"; ui->ShowDebugMessage(this, ss.str()); } return false; } return true; } void CPUDyntransComponent::DyntransToBeTranslatedDone(struct DyntransIC* ic) { bool abort = false; if (ic->f == NULL || ic->f == instr_abort) { abort = true; // Instruction translation failed. If we were running in // quiet mode, then simply dropping into the GXemul> prompt // with no good explanation would be bad, so we always turn // off quiet mode on Aborts: GetRunningGXemulInstance()->SetQuietMode(false); UI* ui = GetUI(); if (ui != NULL) { bool isSingleStepping = GetRunningGXemulInstance()->GetRunState() == GXemul::SingleStepping; stringstream ss; ss.flags(std::ios::hex); ss << "instruction translation failed"; // If we were single-stepping, then the instruction // disassembly has already been displayed. If we were // running in continuous mode, then we need to display // it now: if (!isSingleStepping) { ss << " at"; string symbol = GetSymbolRegistry().LookupAddress( PCtoInstructionAddress(m_pc), true); if (symbol != "") ss << " " << symbol; ss << ":\n"; Unassemble(1, false, PCtoInstructionAddress(m_pc), ss); } ui->ShowDebugMessage(this, ss.str()); } if (ic->f == NULL) ic->f = instr_abort; } // Finally, execute the translated instruction. bool ds = m_inDelaySlot; bool dsExceptionOrAbort = m_exceptionOrAbortInDelaySlot; bool singleInstructionLeft = m_executedCycles == m_nrOfCyclesToExecute - 1; m_nextIC = ic + 1; ic->f(this, ic); if (m_nextIC == &m_abortIC) abort = true; if (singleInstructionLeft && !abort) { // If this instruction was in the delay slot of another instruction, // and we are running a single instruction, then manually branch to // the branch target: if (ds && !dsExceptionOrAbort) { m_pc = m_delaySlotTarget; DyntransPCtoPointers(); m_inDelaySlot = false; m_exceptionOrAbortInDelaySlot = false; } // Don't leave any "single instruction left" instructions // in any of the slots: ic->f = GetDyntransToBeTranslated(); } } /*****************************************************************************/ /* * A do-nothing instruction. (It still counts as a cylce, though.) */ DYNTRANS_INSTR(CPUDyntransComponent,nop) { } /* * A break-out-of-dyntrans function. Setting ic->f to this function will * cause dyntrans execution to be aborted. The cycle counter will _not_ * count this as executed cycles. */ DYNTRANS_INSTR(CPUDyntransComponent,abort) { // Cycle reduction: -- cpubase->m_executedCycles; // Are we in a delay slot? if (cpubase->m_inDelaySlot) cpubase->m_exceptionOrAbortInDelaySlot = true; cpubase->m_nextIC = ic; } DYNTRANS_INSTR(CPUDyntransComponent,endOfPage) { std::cerr << "TODO: endOfPage\n"; throw std::exception(); } DYNTRANS_INSTR(CPUDyntransComponent,endOfPage2) { std::cerr << "TODO: endOfPage2\n"; throw std::exception(); } /* * arg 0: pointer to the new IC * * Branches within a dyntrans page. */ DYNTRANS_INSTR(CPUDyntransComponent,branch_samepage) { cpubase->m_nextIC = (struct DyntransIC *) ic->arg[0].p; } /* * arg 0: 64-bit register * arg 1: 32-bit signed immediate * * Sets the register at arg 0 to the immediate value in arg 1. */ DYNTRANS_INSTR(CPUDyntransComponent,set_u64_imms32) { REG64(ic->arg[0]) = (int32_t) ic->arg[1].u32; } /* * arg 0: 64-bit register * arg 1: 64-bit register * * Moves (copies) the contents of arg 1 to arg 0. */ DYNTRANS_INSTR(CPUDyntransComponent,mov_u64_u64) { REG64(ic->arg[0]) = REG64(ic->arg[1]); } /* * arg 0: 32-bit register * arg 1: 32-bit register * arg 2: 32-bit unsigned immediate * * Adds the unsigned immediate to arg 1, and stores the result in arg 0. */ DYNTRANS_INSTR(CPUDyntransComponent,add_u32_u32_immu32) { REG32(ic->arg[0]) = REG32(ic->arg[1]) + (uint32_t)ic->arg[2].u32; } /* * arg 0: 32-bit register * arg 1: 32-bit register * arg 2: 32-bit register * * Adds arg 1 and arg 2, and stores the result in arg 0. */ DYNTRANS_INSTR(CPUDyntransComponent,add_u32_u32_u32) { REG32(ic->arg[0]) = REG32(ic->arg[1]) + REG32(ic->arg[2]); } /* * arg 0: 64-bit register * arg 1: 64-bit register * arg 2: 32-bit signed immediate * * Adds the signed immediate to arg 1, and stores the result in arg 0, truncated * to a signed 32-bit value. */ DYNTRANS_INSTR(CPUDyntransComponent,add_u64_u64_imms32_truncS32) { REG64(ic->arg[0]) = (int32_t) (REG64(ic->arg[1]) + (int32_t)ic->arg[2].u32); } /* * arg 0: 64-bit register * arg 1: 64-bit register * arg 2: 64-bit register * * Adds the the registers in arg 1 and arg 2, and stores the result in arg 0 * (truncated to a signed 32-bit value). */ DYNTRANS_INSTR(CPUDyntransComponent,add_u64_u64_u64_truncS32) { REG64(ic->arg[0]) = (int32_t) (REG64(ic->arg[1]) + REG64(ic->arg[2])); } /* * arg 0: 64-bit register * arg 1: 64-bit register * arg 2: 32-bit signed immediate * * Adds the signed immediate to arg 1, and stores the result in arg 0. */ DYNTRANS_INSTR(CPUDyntransComponent,add_u64_u64_imms32) { REG64(ic->arg[0]) = REG64(ic->arg[1]) + (int64_t)(int32_t)ic->arg[2].u32; } /* * arg 0: 32-bit register * arg 1: 32-bit register * arg 2: 32-bit unsigned immediate * * Subtracts the unsigned immediate from arg 1, and stores the result in arg 0. */ DYNTRANS_INSTR(CPUDyntransComponent,sub_u32_u32_immu32) { REG32(ic->arg[0]) = REG32(ic->arg[1]) - (uint32_t)ic->arg[2].u32; } /* * arg 0: 32-bit register * arg 1: 32-bit register * arg 2: 32-bit register * * Subtracts arg 2 from arg 1, and stores the result in arg 0. */ DYNTRANS_INSTR(CPUDyntransComponent,sub_u32_u32_u32) { REG32(ic->arg[0]) = REG32(ic->arg[1]) - REG32(ic->arg[2]); } /* * arg 0: 64-bit register * arg 1: 64-bit register * arg 2: 64-bit register * * Subtracts arg2 from arg1, and stores the result in arg0 * (truncated to a signed 32-bit value). */ DYNTRANS_INSTR(CPUDyntransComponent,sub_u64_u64_u64_truncS32) { REG64(ic->arg[0]) = (int32_t) (REG64(ic->arg[1]) - REG64(ic->arg[2])); } /* * arg 0: 32-bit register * arg 1: 32-bit register * arg 2: 32-bit unsigned immediate * * ANDs the 32-bit immediate into arg 1, storing the result in arg 0. */ DYNTRANS_INSTR(CPUDyntransComponent,and_u32_u32_immu32) { REG32(ic->arg[0]) = REG32(ic->arg[1]) & ic->arg[2].u32; } /* * arg 0: 64-bit register * arg 1: 64-bit register * arg 2: 32-bit unsigned immediate * * ANDs the 32-bit immediate into arg 1, storing the result in arg 0. * * Note: No sign truncation is performed, i.e. if arg 1 is 0xffffffff80001234 * and arg 2 is 0x80001200, then arg 0 becomes 0x0000000080001200 (note: the * upper bits are not sign-extended from bit 31). */ DYNTRANS_INSTR(CPUDyntransComponent,and_u64_u64_immu32) { REG64(ic->arg[0]) = REG64(ic->arg[1]) & (uint32_t)ic->arg[2].u32; } /* * arg 0: 32-bit register * arg 1: 32-bit register * arg 2: 32-bit unsigned immediate * * ORs arg 1 and arg 2 together, and stores the result in arg 0. */ DYNTRANS_INSTR(CPUDyntransComponent,or_u32_u32_immu32) { REG32(ic->arg[0]) = REG32(ic->arg[1]) | ic->arg[2].u32; } /* * arg 0: 32-bit register * arg 1: 32-bit register * arg 2: 32-bit register * * ORs arg 1 and arg 2 together, and stores the result in arg 0. */ DYNTRANS_INSTR(CPUDyntransComponent,or_u32_u32_u32) { REG32(ic->arg[0]) = REG32(ic->arg[1]) | REG32(ic->arg[2]); } /* * arg 0: 64-bit register * arg 1: 64-bit register * arg 2: 32-bit unsigned immediate * * ORs the 32-bit immediate into arg 1, storing the result in arg 0. * * Note: No sign truncation is performed, i.e. if arg 1 is 0x0000000000001234 * and arg 2 is 0x80001200, then arg 0 becomes 0x0000000080001234 (note: the * upper bits are not sign extended from bit 31). */ DYNTRANS_INSTR(CPUDyntransComponent,or_u64_u64_immu32) { REG64(ic->arg[0]) = REG64(ic->arg[1]) | (uint32_t)ic->arg[2].u32; } /* * arg 0: 32-bit register * arg 1: 32-bit register * arg 2: 32-bit unsigned immediate * * XORs arg 1 and arg 2, and stores the result in arg 0. */ DYNTRANS_INSTR(CPUDyntransComponent,xor_u32_u32_immu32) { REG32(ic->arg[0]) = REG32(ic->arg[1]) ^ ic->arg[2].u32; } /* * arg 0: 32-bit register * arg 1: 32-bit register * arg 2: 32-bit register * * XORs arg 1 and arg 2, and stores the result in arg 0. */ DYNTRANS_INSTR(CPUDyntransComponent,xor_u32_u32_u32) { REG32(ic->arg[0]) = REG32(ic->arg[1]) ^ REG32(ic->arg[2]); } /* * arg 0: 64-bit register * arg 1: 64-bit register * arg 2: 32-bit unsigned immediate * * XORs the 32-bit immediate into arg 1, storing the result in arg 0. * * Note: No sign truncation is performed, i.e. if arg 1 is 0xffffffff80001234 * and arg 2 is 0x80001200, then arg 0 becomes 0xffffffff00000034 (note: the * upper bits are not sign-extended from bit 31). */ DYNTRANS_INSTR(CPUDyntransComponent,xor_u64_u64_immu32) { REG64(ic->arg[0]) = REG64(ic->arg[1]) ^ (uint32_t)ic->arg[2].u32; } /* * arg 0: 64-bit register * arg 1: 64-bit register * arg 2: 64-bit register * * XORs the arg 1 and arg 2, storing the result in arg 0. * * Note: No sign truncation is performed, i.e. if arg 1 is 0xffffffff80001234 * and arg 2 is 0x80001200, then arg 0 becomes 0xffffffff00000034 (note: the * upper bits are not sign-extended from bit 31). */ DYNTRANS_INSTR(CPUDyntransComponent,xor_u64_u64_u64) { REG64(ic->arg[0]) = REG64(ic->arg[1]) ^ REG64(ic->arg[2]); } /* * arg 0: 64-bit register * arg 1: 64-bit register * arg 2: 5-bit immediate * * Left-shifts arg 1 the number of steps indicated by the immediate, storing * the result in arg 0 truncated to a signed 32-bit value. */ DYNTRANS_INSTR(CPUDyntransComponent,shift_left_u64_u64_imm5_truncS32) { REG64(ic->arg[0]) = (int32_t)(REG64(ic->arg[1]) << (ic->arg[2].u32 & 0x1f)); } /* * arg 0: 64-bit register * arg 1: 64-bit register * arg 2: 5-bit immediate * * Right-shifts arg 1 (truncated into an unsigned 32-bit) the number of steps * indicated by the immediate, storing the result in arg 0 truncated to a * signed 32-bit value. */ DYNTRANS_INSTR(CPUDyntransComponent,shift_right_u64_u64asu32_imm5_truncS32) { REG64(ic->arg[0]) = (int32_t)(((uint32_t)REG64(ic->arg[1])) >> (ic->arg[2].u32 & 0x1f)); } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_CPUDyntransComponent_Dyntrans_PreReq() { UnitTest::Assert("nr of dyntrans args too few", N_DYNTRANS_IC_ARGS >= 3); } UNITTESTS(CPUDyntransComponent) { UNITTEST(Test_CPUDyntransComponent_Dyntrans_PreReq); } #endif gxemul-0.6.1/src/components/cpu/MIPS_CPUComponent.cc000644 001750 001750 00000154460 13402411502 022453 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "ComponentFactory.h" #include "GXemul.h" #include "components/MIPS_CPUComponent.h" #include "mips_cpu_types.h" #include "opcodes_mips.h" static const char* hi6_names[] = HI6_NAMES; static const char* regnames_old[] = MIPS_OLDABI_REGISTER_NAMES; static const char* regnames[] = MIPS_REGISTER_NAMES; static const char* special_names[] = SPECIAL_NAMES; static const char* special_rot_names[] = SPECIAL_ROT_NAMES; static const char* regimm_names[] = REGIMM_NAMES; static mips_cpu_type_def cpu_type_defs[] = MIPS_CPU_TYPE_DEFS; static const char* regname(int i, const string& abi) { if (abi == "o32") return regnames_old[i]; else return regnames[i]; } MIPS_CPUComponent::MIPS_CPUComponent() : CPUDyntransComponent("mips_cpu", "MIPS") , m_mips_type("5KE") // defaults to a MIPS64 rev 2 cpu , m_abi("n64") { m_frequency = 100e6; // Find (and cache) the cpu type in m_type: memset((void*) &m_type, 0, sizeof(m_type)); for (size_t j=0; cpu_type_defs[j].name != NULL; j++) { if (m_mips_type == cpu_type_defs[j].name) { m_type = cpu_type_defs[j]; break; } } if (m_type.name == NULL) { std::cerr << "Internal error: Unimplemented MIPS type?\n"; throw std::exception(); } ResetState(); AddVariable("model", &m_mips_type); AddVariable("abi", &m_abi); AddVariable("hi", &m_hi); AddVariable("lo", &m_lo); // TODO: This only registers using the new ABI names. How should // this be handled? Custom "aliasing" variables? for (size_t i=0; i MIPS_CPUComponent::Create(const ComponentCreateArgs& args) { // Defaults: ComponentCreationSettings settings; settings["model"] = "5KE"; if (!ComponentFactory::GetCreationArgOverrides(settings, args)) return NULL; refcount_ptr cpu = new MIPS_CPUComponent(); if (!cpu->SetVariableValue("model", "\"" + settings["model"] + "\"")) return NULL; return cpu; } void MIPS_CPUComponent::ResetState() { // Most MIPS CPUs use 4 KB native page size. // However, a few use 1 KB pages; this should be supported as well. // TODO: Always use 1024 (worst case) on those CPUs? Or switch during // runtime from 4096 to 1024? (More complicated...) m_pageSize = 4096; m_hi = 0; m_lo = 0; m_scratch = 0; for (size_t i=0; iGetUI()->ShowDebugMessage(this, "the zero register (zr) " "must contain the value 0.\n"); return false; } if (m_pc & 0x2) { gxemul->GetUI()->ShowDebugMessage(this, "the pc register" " can not have bit 1 set!\n"); return false; } if (Is32Bit()) { // All registers must be sign-extended correctly. if ((int64_t)m_pc != (int64_t)(int32_t)m_pc) { gxemul->GetUI()->ShowDebugMessage(this, "The emulated " "CPU is 32-bit, but the pc register is not" " a correctly sign-extended 32-bit value!\n"); return false; } for (size_t i=1; iGetUI()->ShowDebugMessage(this, (string)"The emulated " "CPU is 32-bit, but the " + regname(i, m_abi) + " register is not" " a correctly sign-extended 32-bit value!\n"); return false; } } // TODO: Some more registers? } return CPUDyntransComponent::PreRunCheckForComponent(gxemul); } bool MIPS_CPUComponent::CheckVariableWrite(StateVariable& var, const string& oldValue) { UI* ui = GetUI(); if (m_gpr[MIPS_GPR_ZERO] != 0) { if (ui != NULL) { ui->ShowDebugMessage(this, "the zero register (zr) " "must contain the value 0.\n"); } return false; } if (m_mips_type != m_type.name) { bool found = false; for (size_t j=0; cpu_type_defs[j].name != NULL; j++) { if (m_mips_type == cpu_type_defs[j].name) { m_type = cpu_type_defs[j]; found = true; break; } } if (!found) { if (ui != NULL) { stringstream ss; ss << "Unknown model \"" + m_mips_type + "\". Available types are:\n"; for (size_t j=0; cpu_type_defs[j].name != NULL; j++) { if ((j % 6) != 0) ss << "\t"; ss << cpu_type_defs[j].name; if ((j % 6) == 5) ss << "\n"; } ui->ShowDebugMessage(this, ss.str()); } return false; } } return CPUDyntransComponent::CheckVariableWrite(var, oldValue); } bool MIPS_CPUComponent::Is32Bit() const { return m_type.isa_level == 32 || m_type.isa_level <= 2; } static uint64_t Trunc3264(uint64_t x, bool is32bit) { return is32bit? (uint32_t)x : x; } static uint64_t TruncSigned3264(uint64_t x, bool is32bit) { return is32bit? (int32_t)x : x; } void MIPS_CPUComponent::ShowRegisters(GXemul* gxemul, const vector& arguments) const { bool is32bit = Is32Bit(); stringstream ss; ss.flags(std::ios::hex); ss << std::setfill('0'); // Yuck, this is horrible. Is there some portable way to put e.g. // std::setw(16) into an object, and just pass that same object several // times? ss << "pc="; if (is32bit) ss << std::setw(8); else ss << std::setw(16); ss << Trunc3264(m_pc, is32bit); string symbol = GetSymbolRegistry().LookupAddress(TruncSigned3264(m_pc, is32bit), true); if (symbol != "") ss << " <" << symbol << ">"; ss << "\n"; ss << "hi="; if (is32bit) ss << std::setw(8); else ss << std::setw(16); ss << Trunc3264(m_hi, is32bit) << " lo="; if (is32bit) ss << std::setw(8); else ss << std::setw(16); ss << Trunc3264(m_lo, is32bit) << "\n"; for (size_t i=0; iGetUI()->ShowDebugMessage(ss.str()); } int MIPS_CPUComponent::FunctionTraceArgumentCount() { // On old 32-bit ABIs, registers 4..7 (a0..a3) are used. On newer // ABIs (both 32-bit and 64-bit), registers 4..11 are used (a0..a7). if (m_abi == "o32") return 4; return 8; } int64_t MIPS_CPUComponent::FunctionTraceArgument(int n) { // See comment for FunctionTraceArgumentCount above. return m_gpr[MIPS_GPR_A0 + n]; } bool MIPS_CPUComponent::FunctionTraceReturnImpl(int64_t& retval) { // v0 and v1 may hold return values. However, v1 is only used for // returning 64-bit values on old 32-bit ABIs, and 128-bit values // on newer ABIs, so for now I'll ignore it. retval = m_gpr[MIPS_GPR_V0]; return true; } int MIPS_CPUComponent::GetDyntransICshift() const { bool mips16 = m_pc & 1? true : false; // Normal encoding: 4 bytes per instruction, i.e. shift is 2 bits. // MIPS16 encoding: 2 bytes per instruction, i.e. shift is 1 bit. return mips16? 1 : 2; } void (*MIPS_CPUComponent::GetDyntransToBeTranslated())(CPUDyntransComponent*, DyntransIC*) { bool mips16 = m_pc & 1? true : false; return mips16? instr_ToBeTranslated_MIPS16 : instr_ToBeTranslated; } bool MIPS_CPUComponent::VirtualToPhysical(uint64_t vaddr, uint64_t& paddr, bool& writable) { if (Is32Bit()) vaddr = (int32_t)vaddr; // TODO. For now, just return the lowest 29 bits. if (vaddr >= 0xffffffff80000000ULL && vaddr < 0xffffffffc0000000ULL) { paddr = vaddr & 0x1fffffff; writable = true; return true; } // TODO ... or the lowest 44. if (vaddr >= 0xa800000000000000ULL && vaddr < 0xa8000fffffffffffULL) { paddr = vaddr & 0xfffffffffffULL; writable = true; return true; } return false; } uint64_t MIPS_CPUComponent::PCtoInstructionAddress(uint64_t pc) { // MIPS16 has the lowest bit set, but the instruction is aligned as // if the lowest bit was 0. return pc & ~1; } size_t MIPS_CPUComponent::DisassembleInstructionMIPS16(uint64_t vaddr, unsigned char *instruction, vector& result) { // Read the instruction word: uint16_t iword = *((uint16_t *)(void*) instruction); if (m_isBigEndian) iword = BE16_TO_HOST(iword); else iword = LE16_TO_HOST(iword); // ... and add it to the result: char tmp[5]; snprintf(tmp, sizeof(tmp), "%04x", iword); result.push_back(tmp); int hi5 = iword >> 11; int rx = (iword >> 8) & 7; int ry = (iword >> 5) & 7; // int rz = (iword >> 2) & 7; int imm5 = iword & 0x1f; // Registers are: 16 17 2 3 4 5 6 7, and T(24) and SP(29). if (rx <= 1) rx += 16; if (ry <= 1) ry += 16; switch (hi5) { case 0x14: /* lbu y,5(x) */ case 0x18: /* sb y,5(x) */ { stringstream ss; switch (hi5) { case 0x14: result.push_back("lbu"); break; case 0x18: result.push_back("sb"); break; } int ofs = imm5; // TODO: scaling? ss << regname(ry, m_abi) << "," << ofs << "(" << regname(rx, m_abi) << ")"; result.push_back(ss.str()); } break; default: { stringstream ss; ss.flags(std::ios::hex); ss << "unimplemented MIPS16 opcode 0x" << hi5; result.push_back(ss.str()); } break; } return sizeof(uint16_t); } size_t MIPS_CPUComponent::DisassembleInstruction(uint64_t vaddr, size_t maxLen, unsigned char *instruction, vector& result) { const bool mips16 = m_pc & 1? true : false; const size_t instrSize = mips16? sizeof(uint16_t) : sizeof(uint32_t); if (maxLen < instrSize) { assert(false); return 0; } if (mips16) return DisassembleInstructionMIPS16(vaddr, instruction, result); // Read the instruction word: uint32_t instructionWord = *((uint32_t *)(void*) instruction); if (m_isBigEndian) instructionWord = BE32_TO_HOST(instructionWord); else instructionWord = LE32_TO_HOST(instructionWord); const uint32_t iword = instructionWord; // ... and add it to the result: { stringstream ss; ss.flags(std::ios::hex); ss << std::setfill('0') << std::setw(8) << (uint32_t) iword; if (PCtoInstructionAddress(m_pc) == vaddr && m_inDelaySlot) ss << " (delayslot)"; result.push_back(ss.str()); } const int hi6 = iword >> 26; const int rs = (iword >> 21) & 31; const int rt = (iword >> 16) & 31; const int rd = (iword >> 11) & 31; const int sa = (iword >> 6) & 31; switch (hi6) { case HI6_SPECIAL: { int special6 = iword & 0x3f; int sub = rs; stringstream ss; switch (special6) { case SPECIAL_SLL: case SPECIAL_SRL: case SPECIAL_SRA: case SPECIAL_DSLL: case SPECIAL_DSRL: case SPECIAL_DSRA: case SPECIAL_DSLL32: case SPECIAL_DSRL32: case SPECIAL_DSRA32: if (rd == 0 && special6 == SPECIAL_SLL) { if (sa == 0) ss << "nop"; else if (sa == 1) ss << "ssnop"; else if (sa == 3) ss << "ehb"; else ss << "nop (weird, sa=" << sa << ")"; result.push_back(ss.str()); break; } switch (sub) { case 0x00: result.push_back( special_names[special6]); ss << regname(rd, m_abi) << "," << regname(rt, m_abi) << "," << sa; result.push_back(ss.str()); break; case 0x01: result.push_back( special_rot_names[special6]); ss << regname(rd, m_abi) << "," << regname(rt, m_abi) << "," << sa; result.push_back(ss.str()); break; default:ss << "unimpl special, sub=" << sub; result.push_back(ss.str()); } break; case SPECIAL_DSRLV: case SPECIAL_DSRAV: case SPECIAL_DSLLV: case SPECIAL_SLLV: case SPECIAL_SRAV: case SPECIAL_SRLV: sub = sa; switch (sub) { case 0x00: result.push_back( special_names[special6]); ss << regname(rd, m_abi) << "," << regname(rt, m_abi) << "," << regname(rs, m_abi); result.push_back(ss.str()); break; case 0x01: result.push_back( special_rot_names[special6]); ss << regname(rd, m_abi) << "," << regname(rt, m_abi) << "," << regname(rs, m_abi); result.push_back(ss.str()); break; default:ss << "unimpl special, sub=" << sub; result.push_back(ss.str()); } break; case SPECIAL_JR: /* .hb = hazard barrier hint on MIPS32/64 rev 2 */ if ((iword >> 10) & 1) result.push_back("jr.hb"); else result.push_back("jr"); ss << regname(rs, m_abi); result.push_back(ss.str()); break; case SPECIAL_JALR: /* .hb = hazard barrier hint on MIPS32/64 rev 2 */ if ((iword >> 10) & 1) result.push_back("jalr.hb"); else result.push_back("jalr"); ss << regname(rd, m_abi) << "," << regname(rs, m_abi); result.push_back(ss.str()); break; case SPECIAL_MFHI: case SPECIAL_MFLO: result.push_back(special_names[special6]); result.push_back(regname(rd, m_abi)); break; case SPECIAL_MTLO: case SPECIAL_MTHI: result.push_back(special_names[special6]); result.push_back(regname(rs, m_abi)); break; case SPECIAL_ADD: case SPECIAL_ADDU: case SPECIAL_SUB: case SPECIAL_SUBU: case SPECIAL_AND: case SPECIAL_OR: case SPECIAL_XOR: case SPECIAL_NOR: case SPECIAL_SLT: case SPECIAL_SLTU: case SPECIAL_DADD: case SPECIAL_DADDU: case SPECIAL_DSUB: case SPECIAL_DSUBU: case SPECIAL_MOVZ: case SPECIAL_MOVN: result.push_back(special_names[special6]); ss << regname(rd, m_abi) << "," << regname(rs, m_abi) << "," << regname(rt, m_abi); result.push_back(ss.str()); break; case SPECIAL_MULT: case SPECIAL_MULTU: case SPECIAL_DMULT: case SPECIAL_DMULTU: case SPECIAL_DIV: case SPECIAL_DIVU: case SPECIAL_DDIV: case SPECIAL_DDIVU: case SPECIAL_TGE: case SPECIAL_TGEU: case SPECIAL_TLT: case SPECIAL_TLTU: case SPECIAL_TEQ: case SPECIAL_TNE: result.push_back(special_names[special6]); if (rd != 0) { if (m_type.rev == MIPS_R5900) { if (special6 == SPECIAL_MULT || special6 == SPECIAL_MULTU) ss << regname(rd, m_abi)<<","; else ss << "WEIRD_R5900_RD,"; } else { ss << "WEIRD_R5900_RD,"; } } ss << regname(rs, m_abi) << "," << regname(rt, m_abi); result.push_back(ss.str()); break; case SPECIAL_SYNC: result.push_back(special_names[special6]); ss << ((iword >> 6) & 31); result.push_back(ss.str()); break; case SPECIAL_SYSCALL: case SPECIAL_BREAK: result.push_back(special_names[special6]); if (((iword >> 6) & 0xfffff) != 0) { ss << ((iword >> 6) & 0xfffff); result.push_back(ss.str()); } break; case SPECIAL_MFSA: if (m_type.rev == MIPS_R5900) { result.push_back("mfsa"); result.push_back(regname(rd, m_abi)); } else { result.push_back( "unimplemented special 0x28"); } break; case SPECIAL_MTSA: if (m_type.rev == MIPS_R5900) { result.push_back("mtsa"); result.push_back(regname(rs, m_abi)); } else { result.push_back( "unimplemented special 0x29"); } break; default: ss << "unimplemented: " << special_names[special6]; result.push_back(ss.str()); break; } } break; case HI6_BEQ: case HI6_BEQL: case HI6_BNE: case HI6_BNEL: case HI6_BGTZ: case HI6_BGTZL: case HI6_BLEZ: case HI6_BLEZL: { int imm = (int16_t) iword; uint64_t addr = vaddr + 4 + (imm << 2); stringstream ss; if (hi6 == HI6_BEQ && rt == MIPS_GPR_ZERO && rs == MIPS_GPR_ZERO) { result.push_back("b"); } else { result.push_back(hi6_names[hi6]); switch (hi6) { case HI6_BEQ: case HI6_BEQL: case HI6_BNE: case HI6_BNEL: ss << regname(rt, m_abi) << ","; } ss << regname(rs, m_abi) << ","; } ss.flags(std::ios::hex | std::ios::showbase); ss << addr; result.push_back(ss.str()); string symbol = GetSymbolRegistry().LookupAddress(addr, true); if (symbol != "") result.push_back("; <" + symbol + ">"); } break; case HI6_ADDI: case HI6_ADDIU: case HI6_DADDI: case HI6_DADDIU: case HI6_SLTI: case HI6_SLTIU: case HI6_ANDI: case HI6_ORI: case HI6_XORI: { result.push_back(hi6_names[hi6]); stringstream ss; ss << regname(rt, m_abi) << "," << regname(rs, m_abi) << ","; if (hi6 == HI6_ANDI || hi6 == HI6_ORI || hi6 == HI6_XORI) { ss.flags(std::ios::hex | std::ios::showbase); ss << (uint16_t) iword; } else { ss << (int16_t) iword; } result.push_back(ss.str()); } break; case HI6_LUI: { result.push_back(hi6_names[hi6]); stringstream ss; ss << regname(rt, m_abi) << ","; ss.flags(std::ios::hex | std::ios::showbase); ss << (uint16_t) iword; result.push_back(ss.str()); } break; case HI6_LB: case HI6_LBU: case HI6_LH: case HI6_LHU: case HI6_LW: case HI6_LWU: case HI6_LD: case HI6_LQ_MDMX: case HI6_LWC1: case HI6_LWC2: case HI6_LWC3: case HI6_LDC1: case HI6_LDC2: case HI6_LL: case HI6_LLD: case HI6_SB: case HI6_SH: case HI6_SW: case HI6_SD: case HI6_SQ_SPECIAL3: case HI6_SC: case HI6_SCD: case HI6_SWC1: case HI6_SWC2: case HI6_SWC3: case HI6_SDC1: case HI6_SDC2: case HI6_LWL: case HI6_LWR: case HI6_LDL: case HI6_LDR: case HI6_SWL: case HI6_SWR: case HI6_SDL: case HI6_SDR: { if (hi6 == HI6_LQ_MDMX && m_type.rev != MIPS_R5900) { result.push_back("mdmx (UNIMPLEMENTED)"); break; } if (hi6 == HI6_SQ_SPECIAL3 && m_type.rev!=MIPS_R5900) { result.push_back("special3 (UNIMPLEMENTED)"); break; } int imm = (int16_t) iword; stringstream ss; /* LWC3 is PREF in the newer ISA levels: */ /* TODO: Which ISAs? IV? V? 32? 64? */ if (m_type.isa_level >= 4 && hi6 == HI6_LWC3) { result.push_back("pref"); ss << rt << "," << imm << "(" << regname(rs, m_abi) << ")"; result.push_back(ss.str()); break; } result.push_back(hi6_names[hi6]); if (hi6 == HI6_SWC1 || hi6 == HI6_SWC2 || hi6 == HI6_SWC3 || hi6 == HI6_SDC1 || hi6 == HI6_SDC2 || hi6 == HI6_LWC1 || hi6 == HI6_LWC2 || hi6 == HI6_LWC3 || hi6 == HI6_LDC1 || hi6 == HI6_LDC2) ss << "r" << rt; else ss << regname(rt, m_abi); ss << "," << imm << "(" << regname(rs, m_abi) << ")"; result.push_back(ss.str()); } break; case HI6_J: case HI6_JAL: { result.push_back(hi6_names[hi6]); int imm = (iword & 0x03ffffff) << 2; uint64_t addr = (vaddr + 4) & ~((1 << 28) - 1); addr |= imm; stringstream ss; ss.flags(std::ios::hex | std::ios::showbase); ss << addr; result.push_back(ss.str()); string symbol = GetSymbolRegistry().LookupAddress(addr, true); if (symbol != "") result.push_back("; <" + symbol + ">"); } break; // CopX here. TODO // Cache // Special2 case HI6_REGIMM: { int regimm5 = (iword >> 16) & 0x1f; int imm = (int16_t) iword; uint64_t addr = (vaddr + 4) + (imm << 2); stringstream ss; ss.flags(std::ios::hex | std::ios::showbase); switch (regimm5) { case REGIMM_BLTZ: case REGIMM_BGEZ: case REGIMM_BLTZL: case REGIMM_BGEZL: case REGIMM_BLTZAL: case REGIMM_BLTZALL: case REGIMM_BGEZAL: case REGIMM_BGEZALL: result.push_back(regimm_names[regimm5]); ss << regname(rs, m_abi) << "," << addr; result.push_back(ss.str()); break; case REGIMM_SYNCI: result.push_back(regimm_names[regimm5]); ss << imm << "(" << regname(rs, m_abi) << ")"; result.push_back(ss.str()); break; default: { ss << "unimplemented: " << regimm_names[regimm5]; result.push_back(ss.str()); } } } break; default: { stringstream ss; ss << "unimplemented: " << hi6_names[hi6]; result.push_back(ss.str()); } break; } return instrSize; } string MIPS_CPUComponent::GetAttribute(const string& attributeName) { if (attributeName == "stable") return "yes"; if (attributeName == "description") return "MIPS processor."; return Component::GetAttribute(attributeName); } /*****************************************************************************/ /* * b*: Branch on condition * * op 0: beq rs == rt * op 1: bne rs != rt * op 2: blez rs <= 0 (signed) * op 3: bgtz rs > 0 (signed) * * arg[0] = pointer to register rs * arg[1] = pointer to register rt * arg[2] = signed offset from start of current page to branch to _OR_ pointer to new instr_call */ template void MIPS_CPUComponent::instr_b(CPUDyntransComponent* cpubase, DyntransIC* ic) { DYNTRANS_INSTR_HEAD(MIPS_CPUComponent) bool cond; if (op == 0) cond = REG64(ic->arg[0]) == REG64(ic->arg[1]); // beq else if (op == 1) cond = REG64(ic->arg[0]) != REG64(ic->arg[1]); // bne else if (op == 2) cond = (int64_t)REG64(ic->arg[0]) <= 0; // blez else /* op == 3 */ cond = (int64_t)REG64(ic->arg[0]) > 0; // bgtz if (singlestep) { DYNTRANS_SYNCH_PC; // Prepare for the branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; if (cond) { if (samepage) { std::cerr << "MIPS b instruction: samepage singlestep: should not happen.\n"; throw std::exception(); } else { cpu->m_delaySlotTarget = cpu->m_pc & ~cpu->m_dyntransPageMask; cpu->m_delaySlotTarget = cpu->m_delaySlotTarget + (int32_t)ic->arg[2].u32; } } else { cpu->m_delaySlotTarget = cpu->m_pc + 8; } cpu->m_nextIC = ic + 1; } else { // Prepare for the branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; // Execute the next instruction: ic[1].f(cpu, ic+1); cpu->m_executedCycles ++; // If there was no exception, then branch: if (!cpu->m_exceptionOrAbortInDelaySlot) { if (cond) { if (samepage) { cpu->m_nextIC = (DyntransIC*) ic->arg[2].p; } else { cpu->m_pc &= ~cpu->m_dyntransPageMask; cpu->m_pc = cpu->m_pc + (int32_t)ic->arg[2].u32; cpu->DyntransPCtoPointers(); } } else { cpu->m_nextIC = ic + 2; } cpu->m_inDelaySlot = false; } // The next instruction is now either the target of the branch // instruction, the instruction 2 steps after this one, // or the first instruction of an exception handler. cpu->m_exceptionOrAbortInDelaySlot = false; } } /* * j, jal: Jump [and link] * * arg[0] = lowest 28 bits of new pc */ template void MIPS_CPUComponent::instr_j(CPUDyntransComponent* cpubase, DyntransIC* ic) { DYNTRANS_INSTR_HEAD(MIPS_CPUComponent) if (link) { DYNTRANS_SYNCH_PC; cpu->m_gpr[MIPS_GPR_RA] = cpu->m_pc + 8; if (cpu->m_showFunctionTraceCall) { uint64_t saved_pc = cpu->m_pc; cpu->m_pc = cpu->m_pc & ~0x0fffffffUL; cpu->m_pc += ic->arg[0].u32; cpu->FunctionTraceCall(); cpu->m_pc = saved_pc; } } if (singlestep) { // Prepare for the branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; cpu->m_delaySlotTarget = cpu->m_pc & ~0x0fffffffUL; cpu->m_delaySlotTarget += ic->arg[0].u32; cpu->m_nextIC = ic + 1; } else { // Prepare for the branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; // Execute the next instruction: ic[1].f(cpu, ic+1); cpu->m_executedCycles ++; // If there was no exception, then branch: if (!cpu->m_exceptionOrAbortInDelaySlot) { cpu->m_pc = cpu->m_pc & ~0x0fffffffUL; cpu->m_pc += ic->arg[0].u32; cpu->DyntransPCtoPointers(); cpu->m_inDelaySlot = false; } // The next instruction is now either the target of the branch // instruction, the instruction 2 steps after this one, // or the first instruction of an exception handler. cpu->m_exceptionOrAbortInDelaySlot = false; } } /* * jr, jalr: Jump to register [and link] * * arg[0] = pointer to register rs (to jump to) * arg[1] = pointer to register rd (to store return address in; this is never the zero register) */ template void MIPS_CPUComponent::instr_jr(CPUDyntransComponent* cpubase, DyntransIC* ic) { DYNTRANS_INSTR_HEAD(MIPS_CPUComponent) if (link) { DYNTRANS_SYNCH_PC; REG32(ic->arg[1]) = cpu->m_pc + 8; if (cpu->m_showFunctionTraceCall && ic->arg[1].p == &cpu->m_gpr[MIPS_GPR_RA]) { uint64_t saved_pc = cpu->m_pc; cpu->m_pc = REG64(ic->arg[0]); cpu->FunctionTraceCall(); cpu->m_pc = saved_pc; } } if (!link && cpu->m_showFunctionTraceCall && ic->arg[0].p == &cpu->m_gpr[MIPS_GPR_RA]) cpu->FunctionTraceReturn(); if (singlestep) { // Prepare for the branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; cpu->m_delaySlotTarget = REG64(ic->arg[0]); cpu->m_nextIC = ic + 1; } else { // Prepare for the branch. cpu->m_inDelaySlot = true; cpu->m_exceptionOrAbortInDelaySlot = false; // Execute the next instruction: ic[1].f(cpu, ic+1); cpu->m_executedCycles ++; // If there was no exception, then branch: if (!cpu->m_exceptionOrAbortInDelaySlot) { cpu->m_pc = REG64(ic->arg[0]); cpu->DyntransPCtoPointers(); cpu->m_inDelaySlot = false; } // The next instruction is now either the target of the branch // instruction, the instruction 2 steps after this one, // or the first instruction of an exception handler. cpu->m_exceptionOrAbortInDelaySlot = false; } } DYNTRANS_INSTR(MIPS_CPUComponent,multu) { DYNTRANS_INSTR_HEAD(MIPS_CPUComponent) uint32_t a = REG64(ic->arg[1]), b = REG64(ic->arg[2]); uint64_t res = (uint64_t)a * (uint64_t)b; cpu->m_lo = (int32_t)res; cpu->m_hi = (int32_t)(res >> 32); } DYNTRANS_INSTR(MIPS_CPUComponent,slt) { REG64(ic->arg[0]) = (int64_t)REG64(ic->arg[1]) < (int64_t)REG64(ic->arg[2]); } DYNTRANS_INSTR(MIPS_CPUComponent,sltu) { REG64(ic->arg[0]) = (uint64_t)REG64(ic->arg[1]) < (uint64_t)REG64(ic->arg[2]); } template void MIPS_CPUComponent::instr_loadstore(CPUDyntransComponent* cpubase, DyntransIC* ic) { DYNTRANS_INSTR_HEAD(MIPS_CPUComponent) // TODO: fast lookups uint64_t addr; if (sizeof(addressType) == sizeof(uint64_t)) addr = REG64(ic->arg[1]) + (int32_t)ic->arg[2].u32; else addr = (int32_t) (REG64(ic->arg[1]) + (int32_t)ic->arg[2].u32); if (sizeof(T) > 1 && (addr & (sizeof(T)-1))) { std::cerr << "TODO: MIPS unaligned data access exception!\n"; throw std::exception(); // DYNTRANS_SYNCH_PC; // cpu->Exception(M88K_EXCEPTION_MISALIGNED_ACCESS, 0); return; } cpu->AddressSelect(addr); if (store) { T data = REG64(ic->arg[0]); if (!cpu->WriteData(data, cpu->m_isBigEndian? BigEndian : LittleEndian)) { // TODO: failed to access memory was probably an exception. Handle this! } } else { T data; if (!cpu->ReadData(data, cpu->m_isBigEndian? BigEndian : LittleEndian)) { // TODO: failed to access memory was probably an exception. Handle this! } if (signedLoad) { if (sizeof(T) == sizeof(uint32_t)) REG64(ic->arg[0]) = (int32_t)data; if (sizeof(T) == sizeof(uint16_t)) REG64(ic->arg[0]) = (int16_t)data; if (sizeof(T) == sizeof(uint8_t)) REG64(ic->arg[0]) = (int8_t)data; } else { REG64(ic->arg[0]) = data; } } } /*****************************************************************************/ void MIPS_CPUComponent::Translate(uint32_t iword, struct DyntransIC* ic) { bool singleInstructionLeft = (m_executedCycles == m_nrOfCyclesToExecute - 1); UI* ui = GetUI(); // for debug messages int requiredISA = 1; // 1, 2, 3, 4, 32, or 64 int requiredISArevision = 1; // 1 or 2 (for MIPS32/64) int hi6 = iword >> 26; int rs = (iword >> 21) & 31; int rt = (iword >> 16) & 31; int rd = (iword >> 11) & 31; int sa = (iword >> 6) & 31; int32_t imm = (int16_t)iword; int s6 = iword & 63; // int s10 = (rs << 5) | sa; switch (hi6) { case HI6_SPECIAL: switch (s6) { case SPECIAL_SLL: // case SPECIAL_SLLV: case SPECIAL_SRL: /* case SPECIAL_SRLV: case SPECIAL_SRA: case SPECIAL_SRAV: case SPECIAL_DSRL: case SPECIAL_DSRLV: case SPECIAL_DSRL32: case SPECIAL_DSLL: case SPECIAL_DSLLV: case SPECIAL_DSLL32: case SPECIAL_DSRA: case SPECIAL_DSRAV: case SPECIAL_DSRA32: */ switch (s6) { case SPECIAL_SLL: ic->f = instr_shift_left_u64_u64_imm5_truncS32; break; // case SPECIAL_SLLV: ic->f = instr(sllv); sa = -1; break; case SPECIAL_SRL: ic->f = instr_shift_right_u64_u64asu32_imm5_truncS32; break; /* case SPECIAL_SRLV: ic->f = instr(srlv); sa = -1; break; case SPECIAL_SRA: ic->f = instr(sra); break; case SPECIAL_SRAV: ic->f = instr(srav); sa = -1; break; case SPECIAL_DSRL: ic->f = instr(dsrl); x64=1; break; case SPECIAL_DSRLV:ic->f = instr(dsrlv); x64 = 1; sa = -1; break; case SPECIAL_DSRL32:ic->f= instr(dsrl); x64=1; sa += 32; break; case SPECIAL_DSLL: ic->f = instr(dsll); x64=1; break; case SPECIAL_DSLLV:ic->f = instr(dsllv); x64 = 1; sa = -1; break; case SPECIAL_DSLL32:ic->f= instr(dsll); x64=1; sa += 32; break; case SPECIAL_DSRA: ic->f = instr(dsra); x64=1; break; case SPECIAL_DSRAV:ic->f = instr(dsrav); x64 = 1; sa = -1; break; case SPECIAL_DSRA32:ic->f = instr(dsra); x64=1; sa += 32; break; */ } ic->arg[0].p = &m_gpr[rd]; ic->arg[1].p = &m_gpr[rt]; if (sa >= 0) ic->arg[2].u32 = sa; else ic->arg[2].p = &m_gpr[rs]; /* Special checks for MIPS32/64 revision 2 opcodes, such as rotation instructions: */ // if (sa >= 0 && rs != 0x00) { // if (m_type.isa_level < 32 || // m_type.isa_revision < 2) { // static int warning_rotate = 0; // if (!warning_rotate && // !cpu->translation_readahead) { // fatal("[ WARNING! MIPS32/64 " // "revision 2 rotate opcode" // " used, but the %s process" // "or does not implement " // "such instructions. Only " // "printing this " // "warning once. ]\n", // cpu->cd.mips.cpu_type.name); // warning_rotate = 1; // } // ic->f = NULL; // TODO instr(reserved); // break; // } // // switch (rs) { // case 0x01: // switch (s6) { // case SPECIAL_SRL: /* ror */ // ic->f = NULL; //TODO instr(ror); // break; // } // break; // } // } // if (sa < 0 && (s10 & 0x1f) != 0) { // switch (s10 & 0x1f) { // /* TODO: [d]rorv, etc. */ // } // } if (rd == MIPS_GPR_ZERO) ic->f = instr_nop; break; // case SPECIAL_ADD: case SPECIAL_ADDU: // case SPECIAL_SUB: case SPECIAL_SUBU: // case SPECIAL_DADD: // case SPECIAL_DADDU: // case SPECIAL_DSUB: // case SPECIAL_DSUBU: case SPECIAL_SLT: case SPECIAL_SLTU: // case SPECIAL_AND: // case SPECIAL_OR: case SPECIAL_XOR: // case SPECIAL_NOR: // case SPECIAL_MOVN: // case SPECIAL_MOVZ: case SPECIAL_MFHI: case SPECIAL_MFLO: case SPECIAL_MTHI: case SPECIAL_MTLO: // case SPECIAL_DIV: // case SPECIAL_DIVU: // case SPECIAL_DDIV: // case SPECIAL_DDIVU: // case SPECIAL_MULT: case SPECIAL_MULTU: // case SPECIAL_DMULT: // case SPECIAL_DMULTU: // case SPECIAL_TGE: // case SPECIAL_TGEU: // case SPECIAL_TLT: // case SPECIAL_TLTU: // case SPECIAL_TEQ: // case SPECIAL_TNE: switch (s6) { // case SPECIAL_ADD: ic->f = instr(add); break; case SPECIAL_ADDU: ic->f = instr_add_u64_u64_u64_truncS32; break; // case SPECIAL_SUB: ic->f = instr(sub); break; case SPECIAL_SUBU: ic->f = instr_sub_u64_u64_u64_truncS32; break; // case SPECIAL_DADD: ic->f = instr(dadd); x64=1; break; // case SPECIAL_DADDU: ic->f = instr(daddu); x64=1; break; // case SPECIAL_DSUB: ic->f = instr(dsub); x64=1; break; // case SPECIAL_DSUBU: ic->f = instr(dsubu); x64=1; break; case SPECIAL_SLT: ic->f = instr_slt; break; case SPECIAL_SLTU: ic->f = instr_sltu; break; // case SPECIAL_AND: ic->f = instr(and); break; // case SPECIAL_OR: ic->f = instr(or); break; case SPECIAL_XOR: ic->f = instr_xor_u64_u64_u64; break; // case SPECIAL_NOR: ic->f = instr(nor); break; case SPECIAL_MFHI: ic->f = instr_mov_u64_u64; break; case SPECIAL_MFLO: ic->f = instr_mov_u64_u64; break; case SPECIAL_MTHI: ic->f = instr_mov_u64_u64; break; case SPECIAL_MTLO: ic->f = instr_mov_u64_u64; break; // case SPECIAL_DIV: ic->f = instr(div); break; // case SPECIAL_DIVU: ic->f = instr(divu); break; // case SPECIAL_DDIV: ic->f = instr(ddiv); x64=1; break; // case SPECIAL_DDIVU: ic->f = instr(ddivu); x64=1; break; // case SPECIAL_MULT : ic->f = instr(mult); break; case SPECIAL_MULTU: ic->f = instr_multu; break; // case SPECIAL_DMULT: ic->f = instr(dmult); x64=1; break; // case SPECIAL_DMULTU:ic->f = instr(dmultu); x64=1; break; // case SPECIAL_TGE: ic->f = instr(tge); break; // case SPECIAL_TGEU: ic->f = instr(tgeu); break; // case SPECIAL_TLT: ic->f = instr(tlt); break; // case SPECIAL_TLTU: ic->f = instr(tltu); break; // case SPECIAL_TEQ: ic->f = instr(teq); break; // case SPECIAL_TNE: ic->f = instr(tne); break; // case SPECIAL_MOVN: ic->f = instr(movn); break; // case SPECIAL_MOVZ: ic->f = instr(movz); break; } // NOTE: When uncommenting instruction above, make sure they // use the same rd, rs, rt format! ic->arg[0].p = &m_gpr[rd]; ic->arg[1].p = &m_gpr[rs]; ic->arg[2].p = &m_gpr[rt]; switch (s6) { case SPECIAL_MFHI: ic->arg[1].p = &m_hi; break; case SPECIAL_MFLO: ic->arg[1].p = &m_lo; break; case SPECIAL_MTHI: ic->arg[0].p = &m_hi; break; case SPECIAL_MTLO: ic->arg[0].p = &m_lo; break; } // Special cases for rd: switch (s6) { case SPECIAL_MTHI: case SPECIAL_MTLO: case SPECIAL_DIV: case SPECIAL_DIVU: case SPECIAL_DDIV: case SPECIAL_DDIVU: case SPECIAL_MULT: case SPECIAL_MULTU: case SPECIAL_DMULT: case SPECIAL_DMULTU: if (s6 == SPECIAL_MULT && rd != MIPS_GPR_ZERO) { if (m_type.rev == MIPS_R5900) { // ic->f = instr(mult_r5900); ic->f = NULL; break; } break; } if (s6 == SPECIAL_MULTU && rd!=MIPS_GPR_ZERO) { if (m_type.rev == MIPS_R5900) { // ic->f = instr(multu_r5900); ic->f = NULL; break; } } if (rd != MIPS_GPR_ZERO) { std::cerr << "TODO: rd NON-zero\n"; ic->f = NULL; } // These instructions don't use rd. break; case SPECIAL_TGE: case SPECIAL_TGEU: case SPECIAL_TLT: case SPECIAL_TLTU: case SPECIAL_TEQ: case SPECIAL_TNE: // In these instructions, rd is a 'code', // only read by trap handling software. break; default:if (rd == MIPS_GPR_ZERO) ic->f = instr_nop; } break; case SPECIAL_JR: case SPECIAL_JALR: { void (*f_singleStepping)(CPUDyntransComponent*, struct DyntransIC*) = NULL; if (s6 == SPECIAL_JALR && rd == MIPS_GPR_ZERO) s6 = SPECIAL_JR; switch (s6) { case SPECIAL_JR: ic->f = instr_jr; f_singleStepping = instr_jr; break; case SPECIAL_JALR: ic->f = instr_jr; f_singleStepping = instr_jr; break; } // Only one instruction left, then we carefully single-step it. if (singleInstructionLeft) ic->f = f_singleStepping; ic->arg[0].p = &m_gpr[rs]; ic->arg[1].p = &m_gpr[rd]; if (m_inDelaySlot) { if (ui != NULL) ui->ShowDebugMessage(this, "branch in delay slot?!" " TODO: How should this be handled?"); ic->f = NULL; } } break; default: if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "unimplemented opcode HI6_SPECIAL, s6 = 0x" << s6; ui->ShowDebugMessage(this, ss.str()); } } break; case HI6_BEQ: case HI6_BNE: // case HI6_BEQL: // case HI6_BNEL: case HI6_BLEZ: // case HI6_BLEZL: case HI6_BGTZ: // case HI6_BGTZL: { void (*f_singleStepping)(CPUDyntransComponent*, struct DyntransIC*) = NULL; void (*samepage_function)(CPUDyntransComponent*, struct DyntransIC*) = NULL; bool warnAboutNonZeroRT = false; switch (hi6) { case HI6_BEQ: ic->f = instr_b<0, false, false>; samepage_function = instr_b<0, true, false>; f_singleStepping = instr_b<0, false, true>; break; case HI6_BNE: ic->f = instr_b<1, false, false>; samepage_function = instr_b<1, true, false>; f_singleStepping = instr_b<1, false, true>; break; case HI6_BLEZ: ic->f = instr_b<2, false, false>; samepage_function = instr_b<2, true, false>; f_singleStepping = instr_b<2, false, true>; warnAboutNonZeroRT = true; break; case HI6_BGTZ: ic->f = instr_b<3, false, false>; samepage_function = instr_b<3, true, false>; f_singleStepping = instr_b<3, false, true>; warnAboutNonZeroRT = true; break; } if (singleInstructionLeft) { // Only one instruction left, then we carefully single-step it. // (No need to optimize for samepage.) ic->f = f_singleStepping; samepage_function = NULL; } uint32_t mask = m_dyntransPageMask & ~3; // 0xffc for 4 KB pages ic->arg[0].p = &m_gpr[rs]; ic->arg[1].p = &m_gpr[rt]; // TODO: MIPS16 offset! ic->arg[2].u32 = (int32_t) ( (imm << m_dyntransICshift) + (m_pc & mask) + 4 ); if (rt != MIPS_GPR_ZERO && warnAboutNonZeroRT && ui != NULL) ui->ShowDebugMessage(this, "MIPS branch with rt non-zero, where it should have been zero?"); // Is the offset from the start of the current page still // within the same page? Then use the samepage_function: if (samepage_function != NULL && ic->arg[2].u32 < (uint32_t)((m_dyntransICentriesPerPage - 1) << m_dyntransICshift) && (m_pc & mask) < mask) { ic->arg[2].p = (m_firstIConPage + ((ic->arg[2].u32 >> m_dyntransICshift) & (m_dyntransICentriesPerPage - 1))); ic->f = samepage_function; } if (m_inDelaySlot) { if (ui != NULL) ui->ShowDebugMessage(this, "branch in delay slot?!" " TODO: How should this be handled?"); ic->f = NULL; } } break; // case HI6_ADDI: case HI6_ADDIU: // case HI6_SLTI: // case HI6_SLTIU: // case HI6_DADDI: case HI6_DADDIU: case HI6_ANDI: case HI6_ORI: case HI6_XORI: ic->arg[0].p = &m_gpr[rt]; ic->arg[1].p = &m_gpr[rs]; if (hi6 == HI6_ADDI || hi6 == HI6_ADDIU || hi6 == HI6_SLTI || hi6 == HI6_SLTIU || hi6 == HI6_DADDI || hi6 == HI6_DADDIU) ic->arg[2].u32 = (int16_t)iword; else ic->arg[2].u32 = (uint16_t)iword; switch (hi6) { // case HI6_ADDI: ic->f = instr(addi); break; case HI6_ADDIU: ic->f = instr_add_u64_u64_imms32_truncS32; break; // case HI6_SLTI: ic->f = instr(slti); break; // case HI6_SLTIU: ic->f = instr(sltiu); break; // case HI6_DADDI: ic->f = instr(daddi); requiredISA = 3; break; case HI6_DADDIU: ic->f = instr_add_u64_u64_imms32; requiredISA = 3; break; case HI6_ANDI: ic->f = instr_and_u64_u64_immu32; break; case HI6_ORI: ic->f = instr_or_u64_u64_immu32; break; case HI6_XORI: ic->f = instr_xor_u64_u64_immu32; break; } if (rt == MIPS_GPR_ZERO) ic->f = instr_nop; break; case HI6_LUI: ic->f = instr_set_u64_imms32; ic->arg[0].p = &m_gpr[rt]; ic->arg[1].u32 = (int32_t) (imm << 16); if (rt == MIPS_GPR_ZERO) ic->f = instr_nop; break; case HI6_J: case HI6_JAL: { void (*f_singleStepping)(CPUDyntransComponent*, struct DyntransIC*) = NULL; switch (hi6) { case HI6_J: ic->f = instr_j; f_singleStepping = instr_j; break; case HI6_JAL: ic->f = instr_j; f_singleStepping = instr_j; break; } // Only one instruction left, then we carefully single-step it. if (singleInstructionLeft) ic->f = f_singleStepping; ic->arg[0].u32 = (iword & 0x03ffffff) << 2; if (m_inDelaySlot) { if (ui != NULL) ui->ShowDebugMessage(this, "branch in delay slot?!" " TODO: How should this be handled?"); ic->f = NULL; } break; } // case HI6_LB: // case HI6_LBU: case HI6_SB: // case HI6_LH: // case HI6_LHU: // case HI6_SH: case HI6_LW: // case HI6_LWU: case HI6_SW: // case HI6_LD: // case HI6_SD: { ic->arg[0].p = &m_gpr[rt]; ic->arg[1].p = &m_gpr[rs]; ic->arg[2].u32 = (int32_t)imm; bool store = false; if (Is32Bit()) { switch (hi6) { case HI6_LW: ic->f = instr_loadstore; break; case HI6_SB: ic->f = instr_loadstore; store = true; break; case HI6_SW: ic->f = instr_loadstore; store = true; break; } } else { switch (hi6) { case HI6_LW: ic->f = instr_loadstore; break; case HI6_SB: ic->f = instr_loadstore; store = true; break; case HI6_SW: ic->f = instr_loadstore; store = true; break; } } /* Load into the dummy scratch register, if rt = zero */ if (!store && rt == MIPS_GPR_ZERO) ic->arg[0].p = &m_scratch; } break; default: if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "unimplemented opcode 0x" << hi6; ui->ShowDebugMessage(this, ss.str()); } } // Attempting a MIPS32 instruction on e.g. a MIPS IV CPU? if (requiredISA > m_type.isa_level) { // TODO: Cause MIPS "unimplemented instruction" exception instead. ic->f = NULL; // TODO: Only print the warning once; actual real-world code may // rely on this mechanism to detect cpu type, or similar. if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "instruction at 0x" << m_pc << " requires ISA level "; ss.flags(std::ios::dec); ss << requiredISA << "; this cpu supports only ISA level " << m_type.isa_level << "\n"; ui->ShowDebugMessage(this, ss.str()); } } // Attempting a MIPS III or IV instruction on e.g. a MIPS32 CPU? if ((requiredISA == 3 || requiredISA == 4) && Is32Bit()) { // TODO: Cause MIPS "unimplemented instruction" exception instead. ic->f = NULL; // TODO: Only print the warning once; actual real-world code may // rely on this mechanism to detect cpu type, or similar. if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "instruction at 0x" << m_pc << " is a 64-bit instruction," " which cannot be executed on this CPU\n"; ui->ShowDebugMessage(this, ss.str()); } } // Attempting a revision 2 opcode on a revision1 MIPS32/64 CPU? if (requiredISArevision > 1 && m_type.isa_revision) { // TODO: Cause MIPS "unimplemented instruction" exception instead. ic->f = NULL; // TODO: Only print the warning once; actual real-world code may // rely on this mechanism to detect cpu type, or similar. if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "instruction at 0x" << m_pc << " is a MIPS32/64 revision "; ss << requiredISArevision << " instruction; this cpu supports" " only revision " << m_type.isa_revision << "\n"; ui->ShowDebugMessage(this, ss.str()); } } } DYNTRANS_INSTR(MIPS_CPUComponent,ToBeTranslated) { DYNTRANS_INSTR_HEAD(MIPS_CPUComponent) cpu->DyntransToBeTranslatedBegin(ic); uint32_t iword; if (cpu->DyntransReadInstruction(iword)) cpu->Translate(iword, ic); if (cpu->m_inDelaySlot && ic->f == NULL) ic->f = instr_abort; cpu->DyntransToBeTranslatedDone(ic); } DYNTRANS_INSTR(MIPS_CPUComponent,ToBeTranslated_MIPS16) { DYNTRANS_INSTR_HEAD(MIPS_CPUComponent) cpu->DyntransToBeTranslatedBegin(ic); uint16_t iword; if (cpu->DyntransReadInstruction(iword)) { // TODO: Recode UI* ui = cpu->GetUI(); if (ui != NULL) { stringstream ss; ss.flags(std::ios::hex); ss << "TODO: recode MIPS16 => regular MIPS instruction\n"; ui->ShowDebugMessage(cpu, ss.str()); } //cpu->Translate(iword, ic); } cpu->DyntransToBeTranslatedDone(ic); } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_MIPS_CPUComponent_IsStable() { UnitTest::Assert("the MIPS_CPUComponent should be stable", ComponentFactory::HasAttribute("mips_cpu", "stable")); } static void Test_MIPS_CPUComponent_Create() { refcount_ptr cpu = ComponentFactory::CreateComponent("mips_cpu"); UnitTest::Assert("component was not created?", !cpu.IsNULL()); const StateVariable * p = cpu->GetVariable("pc"); UnitTest::Assert("cpu has no pc state variable?", p != NULL); UnitTest::Assert("initial pc", p->ToString(), "0xffffffffbfc00000"); } static void Test_MIPS_CPUComponent_IsCPU() { refcount_ptr mips_cpu = ComponentFactory::CreateComponent("mips_cpu"); CPUComponent* cpu = mips_cpu->AsCPUComponent(); UnitTest::Assert("mips_cpu is not a CPUComponent?", cpu != NULL); } static void Test_MIPS_CPUComponent_DefaultModel() { refcount_ptr cpu = ComponentFactory::CreateComponent("mips_cpu"); // 5KE is a good default model (MIPS64 rev 2 ISA) UnitTest::Assert("wrong default model", cpu->GetVariable("model")->ToString(), "5KE"); } static void Test_MIPS_CPUComponent_ModelChange() { refcount_ptr cpu = ComponentFactory::CreateComponent("mips_cpu"); cpu->SetVariableValue("model", "\"R2000\""); UnitTest::Assert("model change was not applied", cpu->GetVariable("model")->ToString(), "R2000"); cpu->SetVariableValue("model", "\"R1000\""); UnitTest::Assert("model change was applied when it should NOT have been", cpu->GetVariable("model")->ToString(), "R2000"); } static void Test_MIPS_CPUComponent_Disassembly_Basic() { refcount_ptr mips_cpu = ComponentFactory::CreateComponent("mips_cpu"); CPUComponent* cpu = mips_cpu->AsCPUComponent(); vector result; size_t len; unsigned char instruction[sizeof(uint32_t)]; // This assumes that the default endianness is BigEndian... instruction[0] = 0x27; instruction[1] = 0xbd; instruction[2] = 0xff; instruction[3] = 0xd8; len = cpu->DisassembleInstruction(0x12345678, sizeof(uint32_t), instruction, result); UnitTest::Assert("disassembled instruction was wrong length?", len, 4); UnitTest::Assert("disassembly result incomplete?", result.size(), 3); UnitTest::Assert("disassembly result[0]", result[0], "27bdffd8"); UnitTest::Assert("disassembly result[1]", result[1], "addiu"); UnitTest::Assert("disassembly result[2]", result[2], "sp,sp,-40"); } static void Test_MIPS_CPUComponent_Execute_DelayBranchWithValidInstruction() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testmips"); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0"); UnitTest::Assert("huh? no cpu?", !cpu.IsNULL()); AddressDataBus* bus = cpu->AsAddressDataBus(); UnitTest::Assert("cpu should be addressable", bus != NULL); uint32_t data32 = 0x10000111; // b 0xffffffff80004448 bus->AddressSelect(0xffffffff80004000ULL); bus->WriteData(data32, BigEndian); data32 = 0x27bdffd8; // Something valid, addiu sp,sp,-40 bus->AddressSelect(0xffffffff80004004ULL); bus->WriteData(data32, BigEndian); cpu->SetVariableValue("pc", "0xffffffff80004000"); UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004000ULL); UnitTest::Assert("sp before execute", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007f00ULL); // This tests that execute 2 steps will execute both the delay branch // and the delay slot instruction. gxemul.SetRunState(GXemul::Running); gxemul.Execute(2); UnitTest::Assert("pc should have changed", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004448ULL); UnitTest::Assert("sp should have changed", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007ed8ULL); } static void Test_MIPS_CPUComponent_Execute_DelayBranchWithValidInstruction_SingleStepping() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testmips"); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0"); UnitTest::Assert("huh? no cpu?", !cpu.IsNULL()); AddressDataBus* bus = cpu->AsAddressDataBus(); UnitTest::Assert("cpu should be addressable", bus != NULL); uint32_t data32 = 0x10000111; // b 0xffffffff80004448 bus->AddressSelect(0xffffffff80004000ULL); bus->WriteData(data32, BigEndian); data32 = 0x27bdffd8; // Something valid, addiu sp,sp,-40 bus->AddressSelect(0xffffffff80004004ULL); bus->WriteData(data32, BigEndian); cpu->SetVariableValue("pc", "0xffffffff80004000"); UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004000ULL); UnitTest::Assert("sp before execute", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007f00ULL); // This tests that execute 2 steps will execute both the delay branch // and the delay slot instruction. gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(1); // Should now be in the delay slot. UnitTest::Assert("pc should have changed 1", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004004ULL); UnitTest::Assert("delay slot", cpu->GetVariable("inDelaySlot")->ToString(), "true"); UnitTest::Assert("sp should not yet have changed", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007f00ULL); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(1); UnitTest::Assert("pc should have changed 2", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004448ULL); UnitTest::Assert("delay slot after branch", cpu->GetVariable("inDelaySlot")->ToString(), "false"); UnitTest::Assert("sp should have changed", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007ed8ULL); } static void Test_MIPS_CPUComponent_Execute_DelayBranchWithValidInstruction_RunTwoTimes() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testmips"); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0"); UnitTest::Assert("huh? no cpu?", !cpu.IsNULL()); AddressDataBus* bus = cpu->AsAddressDataBus(); UnitTest::Assert("cpu should be addressable", bus != NULL); uint32_t data32 = 0x10000111; // b 0xffffffff80004448 bus->AddressSelect(0xffffffff80004000ULL); bus->WriteData(data32, BigEndian); data32 = 0x27bdffd8; // Something valid, addiu sp,sp,-40 bus->AddressSelect(0xffffffff80004004ULL); bus->WriteData(data32, BigEndian); cpu->SetVariableValue("pc", "0xffffffff80004000"); UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004000ULL); UnitTest::Assert("sp before execute", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007f00ULL); // This tests that execute 1 step with normal running, two times, will // execute both the delay branch and the delay slot instruction correctly. gxemul.SetRunState(GXemul::Running); gxemul.Execute(1); // Should now be in the delay slot. UnitTest::Assert("pc should have changed 1", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004004ULL); UnitTest::Assert("delay slot", cpu->GetVariable("inDelaySlot")->ToString(), "true"); UnitTest::Assert("sp should not yet have changed", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007f00ULL); gxemul.SetRunState(GXemul::Running); gxemul.Execute(1); UnitTest::Assert("pc should have changed 2", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004448ULL); UnitTest::Assert("delay slot after branch", cpu->GetVariable("inDelaySlot")->ToString(), "false"); UnitTest::Assert("sp should have changed", cpu->GetVariable("sp")->ToInteger(), 0xffffffffa0007ed8ULL); } static void Test_MIPS_CPUComponent_Execute_DelayBranchWithFault() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testmips"); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("root.machine0.mainbus0.cpu0"); UnitTest::Assert("huh? no cpu?", !cpu.IsNULL()); AddressDataBus* bus = cpu->AsAddressDataBus(); UnitTest::Assert("cpu should be addressable", bus != NULL); uint32_t data32 = 0x10000111; // b 0xffffffff80004048 bus->AddressSelect(0xffffffff80004000ULL); bus->WriteData(data32, BigEndian); data32 = 0xffffffff; // Something invalid. bus->AddressSelect(0xffffffff80004004ULL); bus->WriteData(data32, BigEndian); cpu->SetVariableValue("pc", "0xffffffff80004000"); UnitTest::Assert("setting pc failed?", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004000ULL); UnitTest::Assert("should not be in delay slot before execution", cpu->GetVariable("inDelaySlot")->ToString(), "false"); // This tests that execute 100 steps will only execute 1, if the instruction // in the delay slot fails. gxemul.SetRunState(GXemul::Running); gxemul.Execute(100); UnitTest::Assert("pc should have increased one step", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004004ULL); UnitTest::Assert("should be in delay slot after execution", cpu->GetVariable("inDelaySlot")->ToString(), "true"); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(1); UnitTest::Assert("pc should not have increased", cpu->GetVariable("pc")->ToInteger(), 0xffffffff80004004ULL); UnitTest::Assert("should still be in delay slot", cpu->GetVariable("inDelaySlot")->ToString(), "true"); } UNITTESTS(MIPS_CPUComponent) { UNITTEST(Test_MIPS_CPUComponent_IsStable); UNITTEST(Test_MIPS_CPUComponent_Create); UNITTEST(Test_MIPS_CPUComponent_IsCPU); UNITTEST(Test_MIPS_CPUComponent_DefaultModel); UNITTEST(Test_MIPS_CPUComponent_ModelChange); // Disassembly: UNITTEST(Test_MIPS_CPUComponent_Disassembly_Basic); // Dyntrans execution: UNITTEST(Test_MIPS_CPUComponent_Execute_DelayBranchWithValidInstruction); UNITTEST(Test_MIPS_CPUComponent_Execute_DelayBranchWithValidInstruction_SingleStepping); UNITTEST(Test_MIPS_CPUComponent_Execute_DelayBranchWithValidInstruction_RunTwoTimes); UNITTEST(Test_MIPS_CPUComponent_Execute_DelayBranchWithFault); } #endif gxemul-0.6.1/src/components/busses/Makefile.skel000644 001750 001750 00000000361 13402411502 022102 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/components/busses # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(CPEDANTIC) $(INCLUDE2) LIBS=$(OTHERLIBS) OBJS=MainbusComponent.o all: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) clean_all: clean rm -f Makefile gxemul-0.6.1/src/components/busses/MainbusComponent.cc000644 001750 001750 00000037225 13402411502 023306 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "components/MainbusComponent.h" #include "GXemul.h" MainbusComponent::MainbusComponent() : Component("mainbus", "mainbus") , m_memoryMapFailed(false) , m_memoryMapValid(false) , m_currentAddressDataBus(NULL) { } MainbusComponent::~MainbusComponent() { } refcount_ptr MainbusComponent::Create(const ComponentCreateArgs& args) { return new MainbusComponent(); } string MainbusComponent::GetAttribute(const string& attributeName) { if (attributeName == "stable") return "yes"; if (attributeName == "description") return "A generic main bus."; return Component::GetAttribute(attributeName); } void MainbusComponent::FlushCachedStateForComponent() { m_memoryMap.clear(); m_memoryMapValid = false; m_memoryMapFailed = false; m_currentAddressDataBus = NULL; Component::FlushCachedStateForComponent(); } bool MainbusComponent::PreRunCheckForComponent(GXemul* gxemul) { FlushCachedStateForComponent(); if (!MakeSureMemoryMapExists(gxemul)) { gxemul->GetUI()->ShowDebugMessage(GenerateTreeDump("")); return false; } return true; } bool MainbusComponent::MakeSureMemoryMapExists(GXemul* gxemul) { if (m_memoryMapFailed) return false; if (m_memoryMapValid) return true; m_memoryMap.clear(); m_memoryMapValid = true; m_memoryMapFailed = false; // Build a memory map of all immediate children who implement the // AddressDataBus interface: Components children = GetChildren(); for (size_t i=0; iAsAddressDataBus(); if (bus == NULL) continue; MemoryMapEntry mmEntry; mmEntry.addressDataBus = bus; mmEntry.addrMul = 1; mmEntry.base = 0; const StateVariable* varBase = children[i]->GetVariable("memoryMappedBase"); const StateVariable* varSize = children[i]->GetVariable("memoryMappedSize"); const StateVariable* varAddrMul = children[i]->GetVariable("memoryMappedAddrMul"); if (varBase != NULL) mmEntry.base = varBase->ToInteger(); if (varSize != NULL) mmEntry.size = varSize->ToInteger(); if (varAddrMul != NULL) mmEntry.addrMul = varAddrMul->ToInteger(); // No base or size? Then skip this component. if (varSize == NULL || varBase == NULL) continue; // Treat the non-sensical addrMul value 0 as 1. if (mmEntry.addrMul == 0) mmEntry.addrMul = 1; // Empty memory mapped region? Then skip this component. if (mmEntry.size == 0) continue; // Check for overlaps against the already existing mappings. // // (Note: Current implementation results in O(n^2) time, // but if the number of memory-mapped immediate childs are // few, then this should not be a big problem.) for (size_t j=0; j= m_memoryMap[j].base + m_memoryMap[j].size) continue; // There is overlap! if (gxemul != NULL) gxemul->GetUI()->ShowDebugMessage(this, "Error: the base and/or size of " + children[i]->GenerateShortestPossiblePath() + " conflicts with another memory mapped " "component on this bus.\n"); m_memoryMap.clear(); m_memoryMapValid = false; m_memoryMapFailed = true; return false; } // Finally add the new mapping entry. m_memoryMap.push_back(mmEntry); } return true; } AddressDataBus* MainbusComponent::AsAddressDataBus() { return this; } void MainbusComponent::AddressSelect(uint64_t address) { MakeSureMemoryMapExists(); m_currentAddressDataBus = NULL; if (!m_memoryMapValid) return; // Note: This is a linear O(n) scan of the list of memory-mapped // components. For small n, this should be ok. // // In practice, my hope is that the bulk of all memory access will be // using direct-mapped pages anyway, so this should not be that much // of a problem. for (size_t i=0; i= mmEntry.base && address < mmEntry.base + mmEntry.size) { // ... tell the corresponding component which address // within it we wish to select. m_currentAddressDataBus = mmEntry.addressDataBus; m_currentAddressDataBus->AddressSelect( (address - mmEntry.base) / mmEntry.addrMul); break; } } } bool MainbusComponent::ReadData(uint8_t& data, Endianness endianness) { if (!MakeSureMemoryMapExists()) return false; if (m_currentAddressDataBus != NULL) return m_currentAddressDataBus->ReadData(data, endianness); else return false; } bool MainbusComponent::ReadData(uint16_t& data, Endianness endianness) { if (!MakeSureMemoryMapExists()) return false; if (m_currentAddressDataBus != NULL) return m_currentAddressDataBus->ReadData(data, endianness); else return false; } bool MainbusComponent::ReadData(uint32_t& data, Endianness endianness) { if (!MakeSureMemoryMapExists()) return false; if (m_currentAddressDataBus != NULL) return m_currentAddressDataBus->ReadData(data, endianness); else return false; } bool MainbusComponent::ReadData(uint64_t& data, Endianness endianness) { if (!MakeSureMemoryMapExists()) return false; if (m_currentAddressDataBus != NULL) return m_currentAddressDataBus->ReadData(data, endianness); else return false; } bool MainbusComponent::WriteData(const uint8_t& data, Endianness endianness) { if (!MakeSureMemoryMapExists()) return false; if (m_currentAddressDataBus != NULL) return m_currentAddressDataBus->WriteData(data, endianness); else return false; } bool MainbusComponent::WriteData(const uint16_t& data, Endianness endianness) { if (!MakeSureMemoryMapExists()) return false; if (m_currentAddressDataBus != NULL) return m_currentAddressDataBus->WriteData(data, endianness); else return false; } bool MainbusComponent::WriteData(const uint32_t& data, Endianness endianness) { if (!MakeSureMemoryMapExists()) return false; if (m_currentAddressDataBus != NULL) return m_currentAddressDataBus->WriteData(data, endianness); else return false; } bool MainbusComponent::WriteData(const uint64_t& data, Endianness endianness) { if (!MakeSureMemoryMapExists()) return false; if (m_currentAddressDataBus != NULL) return m_currentAddressDataBus->WriteData(data, endianness); else return false; } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_MainbusComponent_IsStable() { UnitTest::Assert("the MainbusComponent should be stable", ComponentFactory::HasAttribute("mainbus", "stable")); } static void Test_MainbusComponent_Creatable() { refcount_ptr mainbus = ComponentFactory::CreateComponent("mainbus"); UnitTest::Assert("The MainbusComponent should be " "instanciable", !mainbus.IsNULL()); } static void Test_MainbusComponent_AddressDataBus() { refcount_ptr mainbus = ComponentFactory::CreateComponent("mainbus"); AddressDataBus* bus = mainbus->AsAddressDataBus(); UnitTest::Assert("The MainbusComponent should implement the " "AddressDataBus interface", bus != NULL); } static void Test_MainbusComponent_Simple() { refcount_ptr mainbus = ComponentFactory::CreateComponent("mainbus"); refcount_ptr ram0 = ComponentFactory::CreateComponent("ram"); mainbus->AddChild(ram0); ram0->SetVariableValue("memoryMappedSize", "0x100000"); ram0->SetVariableValue("memoryMappedBase", "0"); AddressDataBus* bus = mainbus->AsAddressDataBus(); uint8_t dataByte = 42; bus->AddressSelect(128); bus->WriteData(dataByte); bus->AddressSelect(129); dataByte = 100; bus->WriteData(dataByte); bus->AddressSelect(128); bus->ReadData(dataByte); UnitTest::Assert("memory wasn't written to correctly?", dataByte, 42); bus->AddressSelect(129); bus->ReadData(dataByte); UnitTest::Assert("memory wasn't written to correctly?", dataByte, 100); } static void Test_MainbusComponent_Remapping() { refcount_ptr mainbus = ComponentFactory::CreateComponent("mainbus"); refcount_ptr ram0 = ComponentFactory::CreateComponent("ram"); mainbus->AddChild(ram0); ram0->SetVariableValue("memoryMappedSize", "0x10000"); ram0->SetVariableValue("memoryMappedBase", "0x1000"); AddressDataBus* bus = mainbus->AsAddressDataBus(); uint8_t dataByte = 123; bus->AddressSelect(0x1030); // offset 0x30 of ram0 bus->WriteData(dataByte); dataByte = 18; bus->AddressSelect(0x1050); // offset 0x50 of ram0 bus->WriteData(dataByte); // Set a new base for ram0, but do _NOT_ flush cached state yet! // (This is to assert that cached state is actually cached.) ram0->SetVariableValue("memoryMappedBase", "0x1020"); uint8_t dataByte2 = 99; bus->AddressSelect(0x1050); // offset 0x30 of ram0 bus->ReadData(dataByte2); UnitTest::Assert("remapping should NOT have taken place yet, " "cached state should still be in effect!", dataByte2, 18); // Now, flush the state and make sure the new mapping takes effect: mainbus->FlushCachedState(); dataByte2 = 99; bus->AddressSelect(0x1050); // offset 0x30 of ram0 bus->ReadData(dataByte2); UnitTest::Assert("remapping failed?", dataByte2, 123); } static void Test_MainbusComponent_Multiple_NonOverlapping() { refcount_ptr mainbus = ComponentFactory::CreateComponent("mainbus"); refcount_ptr ram0 = ComponentFactory::CreateComponent("ram"); refcount_ptr ram1 = ComponentFactory::CreateComponent("ram"); refcount_ptr ram2 = ComponentFactory::CreateComponent("ram"); mainbus->AddChild(ram0); mainbus->AddChild(ram1); mainbus->AddChild(ram2); ram0->SetVariableValue("memoryMappedSize", "0x100"); ram0->SetVariableValue("memoryMappedBase", "0x000"); ram1->SetVariableValue("memoryMappedSize", "0x100"); ram1->SetVariableValue("memoryMappedBase", "0x100"); ram2->SetVariableValue("memoryMappedSize", "0x100"); ram2->SetVariableValue("memoryMappedBase", "0x200"); AddressDataBus* bus = mainbus->AsAddressDataBus(); for (size_t i = 0; i < 0x300; i += sizeof(uint16_t)) { uint16_t data = (uint8_t) i; bus->AddressSelect(i); bus->WriteData(data, LittleEndian); } for (size_t i = 0; i < 0x300; i += sizeof(uint16_t)) { uint16_t data; bus->AddressSelect(i); bus->ReadData(data, BigEndian); UnitTest::Assert("memory wasn't written to correctly?", data, (uint16_t) (i << 8)); } } static void Test_MainbusComponent_Simple_With_AddrMul() { refcount_ptr mainbus = ComponentFactory::CreateComponent("mainbus"); refcount_ptr ram0 = ComponentFactory::CreateComponent("ram"); mainbus->AddChild(ram0); ram0->SetVariableValue("memoryMappedSize", "0x1000"); ram0->SetVariableValue("memoryMappedBase", "0x80"); ram0->SetVariableValue("memoryMappedAddrMul", "5"); AddressDataBus* bus = mainbus->AsAddressDataBus(); uint8_t dataByte = 42; bus->AddressSelect(128); bus->WriteData(dataByte); bus->AddressSelect(133); dataByte = 100; bus->WriteData(dataByte); bus->AddressSelect(128); bus->ReadData(dataByte); UnitTest::Assert("memory wasn't written to correctly?", dataByte, 42); bus->AddressSelect(133); bus->ReadData(dataByte); UnitTest::Assert("memory wasn't written to correctly?", dataByte, 100); ram0->SetVariableValue("memoryMappedAddrMul", "2"); mainbus->FlushCachedState(); bus->AddressSelect(128); bus->ReadData(dataByte); UnitTest::Assert("addr mul strangeness?", dataByte, 42); bus->AddressSelect(130); bus->ReadData(dataByte); UnitTest::Assert("offset 130 should have the same value as " "offset 133 had", dataByte, 100); bus->AddressSelect(133); bus->ReadData(dataByte); UnitTest::Assert("offset 133 should NOT have any value " "written to it yet!", dataByte, 0); ram0->SetVariableValue("memoryMappedAddrMul", "1"); mainbus->FlushCachedState(); bus->AddressSelect(128); bus->ReadData(dataByte); UnitTest::Assert("addr mul strangeness [2]", dataByte, 42); bus->AddressSelect(129); bus->ReadData(dataByte); UnitTest::Assert("offset 129 mismatch [2]", dataByte, 100); bus->AddressSelect(133); bus->ReadData(dataByte); UnitTest::Assert("offset 133 should NOT have any value " "written to it yet! [2]", dataByte, 0); // AddrMul "0" should be same as "1", because the user might think that // address multiplication is "turned off" by setting it to 0. ram0->SetVariableValue("memoryMappedAddrMul", "0"); mainbus->FlushCachedState(); bus->AddressSelect(128); bus->ReadData(dataByte); UnitTest::Assert("addr mul strangeness [3]", dataByte, 42); bus->AddressSelect(129); bus->ReadData(dataByte); UnitTest::Assert("offset 129 mismatch [3]", dataByte, 100); bus->AddressSelect(133); bus->ReadData(dataByte); UnitTest::Assert("offset 133 should NOT have any value " "written to it yet! [3]", dataByte, 0); } static void Test_MainbusComponent_PreRunCheck() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testmips"); UnitTest::Assert("preruncheck should initially succeed for testmips", gxemul.GetRootComponent()->PreRunCheck(&gxemul) == true); // Adding a second RAM component should succeed, since the initial size // is 0, and does not (yet) conflict. gxemul.GetCommandInterpreter().RunCommand("add ram mainbus0"); UnitTest::Assert("preruncheck should still succeed", gxemul.GetRootComponent()->PreRunCheck(&gxemul) == true); // By changing the size to 42, the new ram1 component will overlap // the ram0 component (at least partially). gxemul.GetCommandInterpreter().RunCommand("ram1.memoryMappedSize = 42"); UnitTest::Assert("preruncheck should now fail", gxemul.GetRootComponent()->PreRunCheck(&gxemul) == false); } UNITTESTS(MainbusComponent) { // Construction, etc.: UNITTEST(Test_MainbusComponent_IsStable); UNITTEST(Test_MainbusComponent_Creatable); UNITTEST(Test_MainbusComponent_AddressDataBus); // Memory mapping, ranges, overlaps, addrmul, etc.: UNITTEST(Test_MainbusComponent_Simple); UNITTEST(Test_MainbusComponent_Remapping); UNITTEST(Test_MainbusComponent_Multiple_NonOverlapping); UNITTEST(Test_MainbusComponent_Simple_With_AddrMul); // TODO: Write outside of mapped space // TODO: Write PARTIALLY outside of mapped space!!! e.g. 64-bit // into a 3-byte memory area??? UNITTEST(Test_MainbusComponent_PreRunCheck); } #endif gxemul-0.6.1/src/components/machines/TestMIPSMachine.cc000644 001750 001750 00000007703 13402411502 023203 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "components/TestMIPSMachine.h" #include "ComponentFactory.h" #include "GXemul.h" refcount_ptr TestMIPSMachine::Create(const ComponentCreateArgs& args) { // Defaults: ComponentCreationSettings settings; settings["cpu"] = "5KE"; settings["ram"] = "0x2000000"; settings["ncpus"] = "1"; if (!ComponentFactory::GetCreationArgOverrides(settings, args)) return NULL; refcount_ptr machine = ComponentFactory::CreateComponent("machine"); if (machine.IsNULL()) return NULL; machine->SetVariableValue("template", "\"testmips\""); refcount_ptr mainbus = ComponentFactory::CreateComponent("mainbus"); if (mainbus.IsNULL()) return NULL; machine->AddChild(mainbus); refcount_ptr ram = ComponentFactory::CreateComponent("ram"); if (ram.IsNULL()) return NULL; ram->SetVariableValue("memoryMappedSize", settings["ram"]); mainbus->AddChild(ram); refcount_ptr rom = ComponentFactory::CreateComponent("ram"); if (rom.IsNULL()) return NULL; stringstream tmpss2; tmpss2 << 16 * 1048576; rom->SetVariableValue("name", "\"rom0\""); rom->SetVariableValue("memoryMappedBase", "0x1fc00000"); rom->SetVariableValue("memoryMappedSize", tmpss2.str()); rom->SetVariableValue("writeProtect", "true"); mainbus->AddChild(rom); refcount_ptr fb_videoram = ComponentFactory::CreateComponent("ram"); if (fb_videoram.IsNULL()) return NULL; fb_videoram->SetVariableValue("name", "\"fb_videoram0\""); fb_videoram->SetVariableValue("memoryMappedBase", "0x12000000"); fb_videoram->SetVariableValue("memoryMappedSize", "0xf00000"); mainbus->AddChild(fb_videoram); int ncpus; stringstream tmpss3; tmpss3 << settings["ncpus"]; tmpss3 >> ncpus; if (ncpus < 1) { if (args.gxemul != NULL) args.gxemul->GetUI()->ShowDebugMessage("nr of cpus must be more than 0."); return NULL; } for (int i=0; i cpu = ComponentFactory::CreateComponent("mips_cpu(model=" + settings["cpu"] + ")"); if (cpu.IsNULL()) return NULL; if (i > 0) cpu->SetVariableValue("paused", "true"); mainbus->AddChild(cpu); } return machine; } string TestMIPSMachine::GetAttribute(const string& attributeName) { if (attributeName == "template") return "yes"; if (attributeName == "machine") return "yes"; if (attributeName == "stable") return "yes"; if (attributeName == "description") return "Experimental MIPS machine."; return ""; } gxemul-0.6.1/src/components/machines/Makefile.skel000644 001750 001750 00000000565 13402411502 022373 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/components/machines # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(CPEDANTIC) $(INCLUDE2) LIBS=$(OTHERLIBS) OBJS=MachineComponent.o MVME187Machine.o TestM88KMachine.o TestMIPSMachine.o \ HP700RXMachine.o CycloneVHMachine.o SGI_IP30_Machine.o SGI_IP32_Machine.o all: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) clean_all: clean rm -f Makefile gxemul-0.6.1/src/components/machines/HP700RXMachine.cc000644 001750 001750 00000006403 13402411502 022577 0ustar00debugdebug000000 000000 /* * Copyright (C) 2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * HP 700/RX X-terminal with an i960CA CPU. * * Bogus skeleton so far. * * My machine says: * * 2048 KB Base RAM * 8192 KB Expansion RAM * 2048 KB Video RAM */ #include "components/HP700RXMachine.h" #include "ComponentFactory.h" #include "GXemul.h" refcount_ptr HP700RXMachine::Create(const ComponentCreateArgs& args) { // Defaults: ComponentCreationSettings settings; settings["cpu"] = "i960CA"; settings["ram"] = "0x00200000"; if (!ComponentFactory::GetCreationArgOverrides(settings, args)) return NULL; refcount_ptr machine = ComponentFactory::CreateComponent("machine"); if (machine.IsNULL()) return NULL; machine->SetVariableValue("template", "\"hp700rx\""); refcount_ptr mainbus = ComponentFactory::CreateComponent("mainbus"); if (mainbus.IsNULL()) return NULL; machine->AddChild(mainbus); refcount_ptr cpu = ComponentFactory::CreateComponent("i960_cpu(model=" + settings["cpu"] + ")"); if (cpu.IsNULL()) return NULL; mainbus->AddChild(cpu); refcount_ptr ram = ComponentFactory::CreateComponent("ram"); if (ram.IsNULL()) return NULL; // DRAM (guess) ram->SetVariableValue("memoryMappedBase", "0x3fe00000"); ram->SetVariableValue("memoryMappedSize", settings["ram"]); mainbus->AddChild(ram); return machine; } string HP700RXMachine::GetAttribute(const string& attributeName) { if (attributeName == "template") return "yes"; if (attributeName == "machine") return "yes"; if (attributeName == "stable") return "yes"; if (attributeName == "description") return "HP 700/RX X-terminal (i960)."; if (attributeName == "comments") return "For experiments that could eventually lead up to " "running custom code on the HP 700/RX."; return ""; } gxemul-0.6.1/src/components/machines/SGI_IP32_Machine.cc000644 001750 001750 00000007317 13402411502 023112 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "components/SGI_IP32_Machine.h" #include "ComponentFactory.h" #include "GXemul.h" refcount_ptr SGI_IP32_Machine::Create(const ComponentCreateArgs& args) { // Defaults: ComponentCreationSettings settings; settings["cpu"] = "R5000"; // R5000, RM7000, R10000, R12000 settings["ram"] = "0x8000000"; if (!ComponentFactory::GetCreationArgOverrides(settings, args)) return NULL; refcount_ptr machine = ComponentFactory::CreateComponent("machine"); if (machine.IsNULL()) return NULL; machine->SetVariableValue("template", "\"sgi_ip32\""); refcount_ptr mainbus = ComponentFactory::CreateComponent("mainbus"); if (mainbus.IsNULL()) return NULL; machine->AddChild(mainbus); refcount_ptr ram = ComponentFactory::CreateComponent("ram"); if (ram.IsNULL()) return NULL; ram->SetVariableValue("memoryMappedBase", "0"); ram->SetVariableValue("memoryMappedSize", settings["ram"]); mainbus->AddChild(ram); refcount_ptr prom = ComponentFactory::CreateComponent("ram"); if (prom.IsNULL()) return NULL; prom->SetVariableValue("name", "\"prom0\""); prom->SetVariableValue("memoryMappedBase", "0x1fc00000"); prom->SetVariableValue("memoryMappedSize", "0x80000"); // The prom (or at least part of it) is flashable/writeable. mainbus->AddChild(prom); refcount_ptr cpu = ComponentFactory::CreateComponent( "mips_cpu(model=" + settings["cpu"] + ")"); if (cpu.IsNULL()) return NULL; mainbus->AddChild(cpu); return machine; } string SGI_IP32_Machine::GetAttribute(const string& attributeName) { if (attributeName == "template") return "yes"; if (attributeName == "machine") return "yes"; // if (attributeName == "stable") // return "yes"; if (attributeName == "comments") return "For experiments with NetBSD/sgimips," " OpenBSD/sgi, " "Linux for O2, and possibly also SGI O2 PROMs and/or" " IRIX in the future."; if (attributeName == "description") return "SGI IP32 (O2) machine."; return ""; } gxemul-0.6.1/src/components/machines/MVME187Machine.cc000644 001750 001750 00000010363 13402411502 022573 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "components/MVME187Machine.h" #include "ComponentFactory.h" /* * This is for experiments with OpenBSD/mvme88k. * * MVME187 according to http://mcg.motorola.com/us/products/docs/pdf/187igd.pdf * ("MVME187 RISC Single Board Computer Installation Guide"): * * 88100 MPU, two MC88200 or MC88204 CMMUs (one for data cache and * one for instruction cache). * 82596CA LAN Ethernet * 53C710 SCSI * CD2401 SCC SERIAL IO * PRINTER PORT * MK48T08 BBRAM & CLOCK * EPROM * VME bus * * ... and more details from OpenBSD/mvme88k sources: * * 0xff800000 .. 0xffbfffff = BUG PROM * 0xffe00000 .. 0xffe1ffff = BUG SRAM * 0xfff00000 = PCCTWO * 0xfff40000 = VME bus * 0xfff43000 = MEMC040 (Memory controller) * 0xfff45000 = CD2401 SCC SERIAL IO (cl0) * 0xfff46000 = 82596 Ethernet (ie0) * 0xfff47000 = 53C710 SCSI (osiop0) * 0xfffc0000 = MK48T08 (nvram0) * * Note: It may turn out to be easier to support Lance ethernet (via VME) * than to support the 82596 ethernet controller. */ refcount_ptr MVME187Machine::Create(const ComponentCreateArgs& args) { // Defaults: ComponentCreationSettings settings; settings["ram"] = "0x2000000"; if (!ComponentFactory::GetCreationArgOverrides(settings, args)) return NULL; refcount_ptr machine = ComponentFactory::CreateComponent("machine"); if (machine.IsNULL()) return NULL; machine->SetVariableValue("template", "\"mvme187\""); refcount_ptr mainbus = ComponentFactory::CreateComponent("mainbus"); if (mainbus.IsNULL()) return NULL; machine->AddChild(mainbus); refcount_ptr ram = ComponentFactory::CreateComponent("ram"); if (ram.IsNULL()) return NULL; ram->SetVariableValue("memoryMappedSize", settings["ram"]); mainbus->AddChild(ram); refcount_ptr rom = ComponentFactory::CreateComponent("ram"); if (rom.IsNULL()) return NULL; rom->SetVariableValue("name", "\"rom0\""); rom->SetVariableValue("memoryMappedBase", "0xff800000"); rom->SetVariableValue("memoryMappedSize", "0x400000"); mainbus->AddChild(rom); refcount_ptr cpu = ComponentFactory::CreateComponent("m88k_cpu(model=88100)"); if (cpu.IsNULL()) return NULL; mainbus->AddChild(cpu); return machine; } string MVME187Machine::GetAttribute(const string& attributeName) { if (attributeName == "template") return "yes"; if (attributeName == "machine") return "yes"; // if (attributeName == "stable") // return "yes"; if (attributeName == "description") return "MVME187 machine."; if (attributeName == "comments") return "For experiments with OpenBSD/mvme88k."; return ""; } gxemul-0.6.1/src/components/machines/CycloneVHMachine.cc000644 001750 001750 00000010046 13402411502 023417 0ustar00debugdebug000000 000000 /* * Copyright (C) 2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * For experiments with uClinux/i960. * * A binary (vmlinux) can be found on this page: * https://web.archive.org/web/20010417034914/http://www.cse.ogi.edu/~kma/uClinux.html * * NOTE!!! The binary at http://www.uclinux.org/pub/uClinux/ports/i960/ is corrupt; * it seems to have been uploaded/encoded with the wrong character encoding. * (At least it is broken as of 2016-04-18.) * * * See the following link for details about the Cyclone VH board: * * http://www.nj7p.org/Manuals/PDFs/Intel/273194-003.PDF * "EVAL80960VH Evaluation Platform Board Manual, December 1998" * * and for the CPU: * * http://www.nj7p.info/Manuals/PDFs/Intel/273173-001.PDF * "i960 VH Processor Developer's Manual, October 1998" */ #include "components/CycloneVHMachine.h" #include "ComponentFactory.h" #include "GXemul.h" refcount_ptr CycloneVHMachine::Create(const ComponentCreateArgs& args) { // Defaults: ComponentCreationSettings settings; settings["cpu"] = "i960CA"; // TODO: uClinux is compiled for i960Jx settings["ram"] = "0x00400000"; if (!ComponentFactory::GetCreationArgOverrides(settings, args)) return NULL; refcount_ptr machine = ComponentFactory::CreateComponent("machine"); if (machine.IsNULL()) return NULL; machine->SetVariableValue("template", "\"cyclonevh\""); refcount_ptr mainbus = ComponentFactory::CreateComponent("mainbus"); if (mainbus.IsNULL()) return NULL; machine->AddChild(mainbus); // TODO: CPU frequency is perhaps 100 MHz? refcount_ptr cpu = ComponentFactory::CreateComponent("i960_cpu(model=" + settings["cpu"] + ")"); if (cpu.IsNULL()) return NULL; mainbus->AddChild(cpu); refcount_ptr ram = ComponentFactory::CreateComponent("ram"); if (ram.IsNULL()) return NULL; // DRAM is at a3c0 0000 - a3ff ffff according to // https://groups.google.com/forum/#!topic/intel.microprocessors.i960/tgpjDcW5Dxc ram->SetVariableValue("memoryMappedBase", "0xa3c00000"); ram->SetVariableValue("memoryMappedSize", settings["ram"]); mainbus->AddChild(ram); // There is supposed to be a LED at e0040000 too. TODO. return machine; } string CycloneVHMachine::GetAttribute(const string& attributeName) { if (attributeName == "template") return "yes"; if (attributeName == "machine") return "yes"; if (attributeName == "stable") return "yes"; if (attributeName == "description") return "Cyclone/VH i960 evaluation board machine."; if (attributeName == "comments") return "For experiments with uClinux/i960."; return ""; } gxemul-0.6.1/src/components/machines/MachineComponent.cc000644 001750 001750 00000005173 13402411502 023534 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "components/MachineComponent.h" MachineComponent::MachineComponent() : Component("machine", "machine") { } refcount_ptr MachineComponent::Create(const ComponentCreateArgs& args) { return new MachineComponent(); } string MachineComponent::GetAttribute(const string& attributeName) { if (attributeName == "machine") return "yes"; if (attributeName == "stable") return "yes"; if (attributeName == "description") return "A generic machine container."; return Component::GetAttribute(attributeName); } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_MachineComponent_IsMachine() { UnitTest::Assert("the MachineComponent should be a machine", ComponentFactory::HasAttribute("machine", "machine")); } static void Test_MachineComponent_IsStable() { UnitTest::Assert("the MachineComponent should be stable", ComponentFactory::HasAttribute("machine", "stable")); } UNITTESTS(MachineComponent) { UNITTEST(Test_MachineComponent_IsMachine); UNITTEST(Test_MachineComponent_IsStable); } #endif gxemul-0.6.1/src/components/machines/TestM88KMachine.cc000644 001750 001750 00000007641 13402411502 023123 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "components/TestM88KMachine.h" #include "ComponentFactory.h" #include "GXemul.h" refcount_ptr TestM88KMachine::Create(const ComponentCreateArgs& args) { // Defaults: ComponentCreationSettings settings; settings["cpu"] = "88100"; settings["ram"] = "0x2000000"; settings["ncpus"] = "1"; if (!ComponentFactory::GetCreationArgOverrides(settings, args)) return NULL; refcount_ptr machine = ComponentFactory::CreateComponent("machine"); if (machine.IsNULL()) return NULL; machine->SetVariableValue("template", "\"testm88k\""); refcount_ptr mainbus = ComponentFactory::CreateComponent("mainbus"); if (mainbus.IsNULL()) return NULL; machine->AddChild(mainbus); int ncpus; stringstream tmpss3; tmpss3 << settings["ncpus"]; tmpss3 >> ncpus; if (ncpus < 1) { if (args.gxemul != NULL) args.gxemul->GetUI()->ShowDebugMessage("nr of cpus must be more than 0."); return NULL; } for (int i=0; i cpu = ComponentFactory::CreateComponent("m88k_cpu(r31=0xff0,model=" + settings["cpu"] + ")"); if (cpu.IsNULL()) return NULL; if (i > 0) cpu->SetVariableValue("paused", "true"); mainbus->AddChild(cpu); } refcount_ptr ram = ComponentFactory::CreateComponent("ram"); if (ram.IsNULL()) return NULL; ram->SetVariableValue("memoryMappedSize", settings["ram"]); mainbus->AddChild(ram); refcount_ptr fb_videoram = ComponentFactory::CreateComponent("ram"); if (fb_videoram.IsNULL()) return NULL; fb_videoram->SetVariableValue("name", "\"fb_videoram0\""); fb_videoram->SetVariableValue("memoryMappedBase", "0x12000000"); fb_videoram->SetVariableValue("memoryMappedSize", "0xf00000"); mainbus->AddChild(fb_videoram); refcount_ptr rom = ComponentFactory::CreateComponent("ram"); if (rom.IsNULL()) return NULL; rom->SetVariableValue("name", "\"rom0\""); rom->SetVariableValue("memoryMappedBase", "0xff800000"); rom->SetVariableValue("memoryMappedSize", "0x400000"); rom->SetVariableValue("writeProtect", "true"); mainbus->AddChild(rom); return machine; } string TestM88KMachine::GetAttribute(const string& attributeName) { if (attributeName == "template") return "yes"; if (attributeName == "machine") return "yes"; if (attributeName == "stable") return "yes"; if (attributeName == "description") return "Experimental M88K machine."; return ""; } gxemul-0.6.1/src/components/machines/SGI_IP30_Machine.cc000644 001750 001750 00000007634 13402411502 023112 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "components/SGI_IP30_Machine.h" #include "ComponentFactory.h" #include "GXemul.h" refcount_ptr SGI_IP30_Machine::Create(const ComponentCreateArgs& args) { // Defaults: ComponentCreationSettings settings; settings["cpu"] = "R10000"; // or R12000 or R14000 settings["ram"] = "0x8000000"; settings["ncpus"] = "1"; if (!ComponentFactory::GetCreationArgOverrides(settings, args)) return NULL; refcount_ptr machine = ComponentFactory::CreateComponent("machine"); if (machine.IsNULL()) return NULL; machine->SetVariableValue("template", "\"sgi_ip30\""); refcount_ptr mainbus = ComponentFactory::CreateComponent("mainbus"); if (mainbus.IsNULL()) return NULL; machine->AddChild(mainbus); refcount_ptr ram = ComponentFactory::CreateComponent("ram"); if (ram.IsNULL()) return NULL; ram->SetVariableValue("memoryMappedBase", "0x20000000"); ram->SetVariableValue("memoryMappedSize", settings["ram"]); mainbus->AddChild(ram); refcount_ptr rom = ComponentFactory::CreateComponent("ram"); if (rom.IsNULL()) return NULL; stringstream tmpss2; tmpss2 << 4 * 1048576; // TODO: Actual ROM size rom->SetVariableValue("name", "\"rom0\""); rom->SetVariableValue("memoryMappedBase", "0x1fc00000"); rom->SetVariableValue("memoryMappedSize", tmpss2.str()); rom->SetVariableValue("writeProtect", "true"); mainbus->AddChild(rom); int ncpus; stringstream tmpss3; tmpss3 << settings["ncpus"]; tmpss3 >> ncpus; if (ncpus < 1) { if (args.gxemul != NULL) args.gxemul->GetUI()->ShowDebugMessage("nr of cpus must be more than 0."); return NULL; } for (int i=0; i cpu = ComponentFactory::CreateComponent("mips_cpu(model=" + settings["cpu"] + ")"); if (cpu.IsNULL()) return NULL; if (i > 0) cpu->SetVariableValue("paused", "true"); mainbus->AddChild(cpu); } return machine; } string SGI_IP30_Machine::GetAttribute(const string& attributeName) { if (attributeName == "template") return "yes"; if (attributeName == "machine") return "yes"; // if (attributeName == "stable") // return "yes"; if (attributeName == "comments") return "For experiments with NetBSD/sgimips, and possibly" " also Linux for SGI Octane in the future."; if (attributeName == "description") return "SGI IP30 (Octane) machine."; return ""; } gxemul-0.6.1/src/components/special/DummyComponent.cc000644 001750 001750 00000117114 13402411502 023113 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "components/DummyComponent.h" #include "Checksum.h" #include "ComponentFactory.h" DummyComponent::DummyComponent(string className) : Component(className, className) { // The dummy component should have no additional state. } refcount_ptr DummyComponent::Create(const ComponentCreateArgs& args) { return new DummyComponent(); } string DummyComponent::GetAttribute(const string& attributeName) { if (attributeName == "stable") return "yes"; if (attributeName == "description") return "A dummy component, which does nothing."; return Component::GetAttribute(attributeName); } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "GXemul.h" static void Test_DummyComponent_CreateComponent() { refcount_ptr component; component = ComponentFactory::CreateComponent("dummy"); UnitTest::Assert("creating a dummy component should be possible", component.IsNULL() == false); UnitTest::Assert("the name should be 'dummy'", component->GetClassName() == "dummy"); } static void Test_DummyComponent_GetSetParent() { refcount_ptr dummyA = new DummyComponent; refcount_ptr dummyB = new DummyComponent; UnitTest::Assert("parent should initially be NULL", dummyA->GetParent() == NULL); dummyA->SetParent(dummyB); UnitTest::Assert("parent should be dummyB", dummyA->GetParent() == dummyB); dummyA->SetParent(NULL); UnitTest::Assert("parent should now be NULL", dummyA->GetParent() == NULL); } static void Test_DummyComponent_AddChild_Sets_Parent() { refcount_ptr dummy = new DummyComponent; refcount_ptr dummyChildA = new DummyComponent; UnitTest::Assert("child A's parent should initially be NULL", dummyChildA->GetParent() == NULL); dummy->AddChild(dummyChildA); UnitTest::Assert("child A's parent should now be dummy", dummyChildA->GetParent() == dummy); } static void Test_DummyComponent_AddChildren_Count() { refcount_ptr dummy = new DummyComponent; refcount_ptr dummyChildA = new DummyComponent; refcount_ptr dummyChildB = new DummyComponent; refcount_ptr dummyChildC = new DummyComponent; UnitTest::Assert("there should initially be no child components", dummy->GetChildren().size() == 0); dummy->AddChild(dummyChildA); dummy->AddChild(dummyChildB); dummy->AddChild(dummyChildC); UnitTest::Assert("there should be 3 child components", dummy->GetChildren().size() == 3); } static void Test_DummyComponent_Add_Tree_Of_Children() { refcount_ptr dummy = new DummyComponent; refcount_ptr dummyChildA = new DummyComponent; refcount_ptr dummyChildB = new DummyComponent; refcount_ptr dummyChildC = new DummyComponent; dummyChildA->AddChild(dummyChildB); dummyChildA->AddChild(dummyChildC); dummy->AddChild(dummyChildA); UnitTest::Assert("there should be 1 child component", dummy->GetChildren().size() == 1); UnitTest::Assert("there should be 2 child components in dummyChildA", dummyChildA->GetChildren().size() == 2); } static void Test_DummyComponent_RemoveChild() { refcount_ptr dummy = new DummyComponent; refcount_ptr dummyChildA = new DummyComponent; refcount_ptr dummyChildB = new DummyComponent; refcount_ptr dummyChildC = new DummyComponent; dummyChildA->AddChild(dummyChildB); dummyChildA->AddChild(dummyChildC); dummy->AddChild(dummyChildA); UnitTest::Assert("there should be 1 child component", dummy->GetChildren().size() == 1); UnitTest::Assert("child A's parent should be dummy", dummyChildA->GetParent() == dummy); UnitTest::Assert("there should be 2 child components in dummyChildA", dummyChildA->GetChildren().size() == 2); dummy->RemoveChild(dummyChildA); UnitTest::Assert("there should now be 0 child components", dummy->GetChildren().size() == 0); UnitTest::Assert( "there should still be 2 child components in dummyChildA", dummyChildA->GetChildren().size() == 2); UnitTest::Assert("child A should have no parent", dummyChildA->GetParent() == NULL); } static void Test_DummyComponent_AddChild_UniqueName() { refcount_ptr dummy = new DummyComponent; refcount_ptr dummyChildA = new DummyComponent; refcount_ptr dummyChildB = new DummyComponent; refcount_ptr dummyChildC = new DummyComponent; UnitTest::Assert("dummyChildA should have no initial name", dummyChildA->GetVariable("name")->ToString(), ""); dummy->AddChild(dummyChildA); const StateVariable* name = dummyChildA->GetVariable("name"); UnitTest::Assert("dummyChildA's name mismatch", name->ToString(), "dummy0"); dummy->AddChild(dummyChildB); name = dummyChildA->GetVariable("name"); UnitTest::Assert("dummyChildA should still have a name", name != NULL); UnitTest::Assert("dummyChildA's name changed unexpectedly?", name->ToString(), "dummy0"); name = dummyChildB->GetVariable("name"); UnitTest::Assert("dummyChildB should have a name now", name != NULL); UnitTest::Assert("dummyChildB's name mismatch", name->ToString(), "dummy1"); dummy->AddChild(dummyChildC); name = dummyChildC->GetVariable("name"); UnitTest::Assert("dummyChildC should have a name now", name != NULL); UnitTest::Assert("dummyChildC's name mismatch", name->ToString(), "dummy2"); dummy->RemoveChild(dummyChildA); name = dummyChildB->GetVariable("name"); UnitTest::Assert("dummyChildB should still have a name, after" " removing child A", name != NULL); UnitTest::Assert("dummyChildB's should not have changed", name->ToString(), "dummy1"); } static void Test_DummyComponent_GeneratePath() { refcount_ptr dummyA = new DummyComponent; refcount_ptr dummyB = new DummyComponent; refcount_ptr dummyC = new DummyComponent; UnitTest::Assert("generated path with no name", dummyA->GeneratePath(), "(dummy)"); dummyB->AddChild(dummyA); UnitTest::Assert("generated path with default name fallback", dummyA->GeneratePath(), "(dummy).dummy0"); dummyC->AddChild(dummyB); UnitTest::Assert("generated path with two parent levels", dummyA->GeneratePath(), "(dummy).dummy0.dummy0"); dummyC->RemoveChild(dummyB); UnitTest::Assert("generated path with one parent level again", dummyA->GeneratePath(), "dummy0.dummy0"); } static void Test_DummyComponent_GenerateShortestPossiblePath() { refcount_ptr dummyA = new DummyComponent; refcount_ptr dummyB = new DummyComponent; refcount_ptr dummyC = new DummyComponent; dummyA->SetVariableValue("name", "\"machine0\""); dummyB->SetVariableValue("name", "\"mainbus0\""); dummyC->SetVariableValue("name", "\"ram0\""); dummyA->AddChild(dummyB); dummyB->AddChild(dummyC); UnitTest::Assert("shortest path first", dummyC->GenerateShortestPossiblePath(), "ram0"); refcount_ptr dummyB2 = new DummyComponent; refcount_ptr dummyC2 = new DummyComponent; dummyB2->SetVariableValue("name", "\"mainbus1\""); dummyC2->SetVariableValue("name", "\"ram0\""); dummyA->AddChild(dummyB2); dummyB2->AddChild(dummyC2); UnitTest::Assert("shortest path C", dummyC->GenerateShortestPossiblePath(), "mainbus0.ram0"); UnitTest::Assert("shortest path C2", dummyC2->GenerateShortestPossiblePath(), "mainbus1.ram0"); } static void Test_DummyComponent_LookupPath() { refcount_ptr dummyA = new DummyComponent; dummyA->SetVariableValue("name", "\"hello\""); refcount_ptr component1 = dummyA->LookupPath("nonsense"); UnitTest::Assert("nonsense lookup should fail", component1.IsNULL() == true); refcount_ptr component2 = dummyA->LookupPath("hello"); UnitTest::Assert("lookup should have found the component itself", component2 == dummyA); refcount_ptr child = new DummyComponent; refcount_ptr childchild = new DummyComponent; child->SetVariableValue("name", "\"x\""); childchild->SetVariableValue("name", "\"y\""); dummyA->AddChild(child); child->AddChild(childchild); refcount_ptr component3 = dummyA->LookupPath("hello"); UnitTest::Assert("lookup should still succeed, when dummyA has" " children", component3 == dummyA); refcount_ptr component4 = dummyA->LookupPath("hello.z"); UnitTest::Assert("lookup of nonsense child of dummyA should fail", component4.IsNULL() == true); refcount_ptr component5 = dummyA->LookupPath("hello.x"); UnitTest::Assert("lookup of child of dummyA should succeed", component5 == child); refcount_ptr component6 = dummyA->LookupPath("hello.x.y"); UnitTest::Assert("lookup of grandchild of dummyA should succeed", component6 == childchild); } static void Test_DummyComponent_FindPathByPartialMatch() { refcount_ptr root = new DummyComponent; refcount_ptr machine0 = new DummyComponent; refcount_ptr machine1 = new DummyComponent; refcount_ptr machine2 = new DummyComponent; refcount_ptr machine3 = new DummyComponent; refcount_ptr m0isabus0 = new DummyComponent; refcount_ptr m1pcibus0 = new DummyComponent; refcount_ptr m1pcibus1 = new DummyComponent; refcount_ptr m2pcibus0 = new DummyComponent; refcount_ptr m3otherpci = new DummyComponent; root->GetVariable("name")->SetValue("\"root\""); machine0->GetVariable("name")->SetValue("\"machine0\""); machine1->GetVariable("name")->SetValue("\"machine1\""); machine2->GetVariable("name")->SetValue("\"machine2\""); machine3->GetVariable("name")->SetValue("\"machine3\""); m0isabus0->GetVariable("name")->SetValue("\"isabus0\""); m1pcibus0->GetVariable("name")->SetValue("\"pcibus0\""); m1pcibus1->GetVariable("name")->SetValue("\"pcibus1\""); m2pcibus0->GetVariable("name")->SetValue("\"pcibus0\""); m3otherpci->GetVariable("name")->SetValue("\"otherpci\""); root->AddChild(machine0); root->AddChild(machine1); root->AddChild(machine2); root->AddChild(machine3); machine0->AddChild(m0isabus0); machine1->AddChild(m1pcibus0); machine1->AddChild(m1pcibus1); machine2->AddChild(m2pcibus0); machine3->AddChild(m3otherpci); vector matches; matches = root->FindPathByPartialMatch("nonsense"); UnitTest::Assert("there should be no nonsense matches", matches.size(), 0); matches = root->FindPathByPartialMatch(""); UnitTest::Assert("empty string should return all components", matches.size(), 10); matches = root->FindPathByPartialMatch("pci"); UnitTest::Assert("pci matches mismatch", matches.size(), 3); UnitTest::Assert("pci match 0 mismatch", matches[0], "root.machine1.pcibus0"); UnitTest::Assert("pci match 1 mismatch", matches[1], "root.machine1.pcibus1"); UnitTest::Assert("pci match 2 mismatch", matches[2], "root.machine2.pcibus0"); matches = root->FindPathByPartialMatch("machine1"); UnitTest::Assert("machine1 match mismatch", matches.size(), 1); UnitTest::Assert("machine1 match 0 mismatch", matches[0], "root.machine1"); matches = root->FindPathByPartialMatch("machine2.pcibus"); UnitTest::Assert("machine2.pcibus match mismatch", matches.size(), 1); UnitTest::Assert("machine2.pcibus match 0 mismatch", matches[0], "root.machine2.pcibus0"); matches = root->FindPathByPartialMatch("machine.pcibus"); UnitTest::Assert("machine.pcibus should have no matches", matches.size(), 0); } static void Test_DummyComponent_GetUnknownVariable() { refcount_ptr dummy = new DummyComponent; UnitTest::Assert("variable variablename should not be set", dummy->GetVariable("variablename") == NULL); } static void Test_DummyComponent_NonexistantMethodNotReexecutable() { refcount_ptr dummy = new DummyComponent; UnitTest::Assert("by default, methods should NOT be re-executable" " without args", dummy->MethodMayBeReexecutedWithoutArgs("nonexistant") == false); } static void Test_DummyComponent_Clone_Basic() { refcount_ptr dummy = new DummyComponent; refcount_ptr dummyChildA = new DummyComponent; refcount_ptr dummyChildA1 = new DummyComponent; refcount_ptr dummyChildA2 = new DummyComponent; dummyChildA->AddChild(dummyChildA1); dummyChildA->AddChild(dummyChildA2); dummy->AddChild(dummyChildA); Checksum originalChecksum; dummy->AddChecksum(originalChecksum); refcount_ptr clone = dummy->Clone(); Checksum cloneChecksum; clone->AddChecksum(cloneChecksum); UnitTest::Assert("clone should have same checksum", originalChecksum == cloneChecksum); dummy->SetVariableValue("name", "\"modified\""); Checksum originalChecksumAfterModifyingOriginal; dummy->AddChecksum(originalChecksumAfterModifyingOriginal); Checksum cloneChecksumAfterModifyingOriginal; clone->AddChecksum(cloneChecksumAfterModifyingOriginal); UnitTest::Assert("original should have changed checksum", originalChecksum != originalChecksumAfterModifyingOriginal); UnitTest::Assert("clone should have same checksum", cloneChecksum == cloneChecksumAfterModifyingOriginal); clone->SetVariableValue("name", "\"modified\""); Checksum originalChecksumAfterModifyingClone; dummy->AddChecksum(originalChecksumAfterModifyingClone); Checksum cloneChecksumAfterModifyingClone; clone->AddChecksum(cloneChecksumAfterModifyingClone); UnitTest::Assert("original should have same checksum, after the " "clone has been modified", originalChecksumAfterModifyingClone == originalChecksumAfterModifyingOriginal); UnitTest::Assert("modified clone should have same checksum as " "modified original", cloneChecksumAfterModifyingClone == originalChecksumAfterModifyingOriginal); } class DummyComponentWithAllVariableTypes : public DummyComponent { public: DummyComponentWithAllVariableTypes() : DummyComponent("dummy2") { AddVariable("m_string", &m_string); AddVariable("m_uint8", &m_uint8); AddVariable("m_uint16", &m_uint16); AddVariable("m_uint32", &m_uint32); AddVariable("m_uint64", &m_uint64); AddVariable("m_sint8", &m_sint8); AddVariable("m_sint16", &m_sint16); AddVariable("m_sint32", &m_sint32); AddVariable("m_sint64", &m_sint64); // TODO: Custom // TODO: Bool ResetState(); } virtual void ResetState() { DummyComponent::ResetState(); m_string = "some value"; m_uint8 = 123; m_uint16 = 0xf9a2; m_uint32 = 0x98f8aa01; m_uint64 = ((uint64_t)0xf8192929 << 32) | 0x30300a0a; m_sint8 = -123; m_sint16 = -400; m_sint32 = -10000; m_sint64 = -42; } static refcount_ptr Create(const ComponentCreateArgs& args) { return new DummyComponentWithAllVariableTypes(); } private: string m_string; uint8_t m_uint8; uint16_t m_uint16; uint32_t m_uint32; uint64_t m_uint64; int8_t m_sint8; int16_t m_sint16; int32_t m_sint32; int64_t m_sint64; }; static void Test_DummyComponent_Clone_AllVariableTypes() { refcount_ptr dummy = new DummyComponentWithAllVariableTypes; refcount_ptr dA = new DummyComponentWithAllVariableTypes; refcount_ptr dA1 = new DummyComponentWithAllVariableTypes; refcount_ptr dA2 = new DummyComponentWithAllVariableTypes; dA->AddChild(dA1); dA->AddChild(dA2); dummy->AddChild(dA); Checksum originalChecksum; dummy->AddChecksum(originalChecksum); refcount_ptr clone = dummy->Clone(); Checksum cloneChecksum; clone->AddChecksum(cloneChecksum); UnitTest::Assert("clone should have same checksum", originalChecksum == cloneChecksum); dummy->SetVariableValue("name", "\"modified\""); Checksum originalChecksumAfterModifyingOriginal; dummy->AddChecksum(originalChecksumAfterModifyingOriginal); Checksum cloneChecksumAfterModifyingOriginal; clone->AddChecksum(cloneChecksumAfterModifyingOriginal); UnitTest::Assert("original should have changed checksum", originalChecksum != originalChecksumAfterModifyingOriginal); UnitTest::Assert("clone should have same checksum", cloneChecksum == cloneChecksumAfterModifyingOriginal); clone->SetVariableValue("name", "\"modified\""); Checksum originalChecksumAfterModifyingClone; dummy->AddChecksum(originalChecksumAfterModifyingClone); Checksum cloneChecksumAfterModifyingClone; clone->AddChecksum(cloneChecksumAfterModifyingClone); UnitTest::Assert("original should have same checksum, after the " "clone has been modified", originalChecksumAfterModifyingClone == originalChecksumAfterModifyingOriginal); UnitTest::Assert("modified clone should have same checksum as " "modified original", cloneChecksumAfterModifyingClone == originalChecksumAfterModifyingOriginal); } static void Test_DummyComponent_SerializeDeserialize() { refcount_ptr dummy = new DummyComponent; refcount_ptr dummyChildA = new DummyComponent; refcount_ptr dummyChildA1 = new DummyComponent; refcount_ptr dummyChildA2 = new DummyComponent; dummyChildA->AddChild(dummyChildA1); dummyChildA->AddChild(dummyChildA2); dummy->AddChild(dummyChildA); UnitTest::Assert("serialize/deserialize consistency failure", dummy->CheckConsistency() == true); } class DummyComponentWithCounter : public DummyComponent { public: DummyComponentWithCounter(ostream* os = NULL, char c = 'X') : DummyComponent("testcounter") , m_frequency(1e6) , m_os(os) , m_c(c) { ResetState(); AddVariable("frequency", &m_frequency); AddVariable("counter", &m_counter); } virtual void ResetState() { DummyComponent::ResetState(); m_counter = 42; } static refcount_ptr Create(const ComponentCreateArgs& args) { return new DummyComponentWithCounter(); } virtual int Execute(GXemul* gxemul, int nrOfCycles) { // Increase counter one per cycle. m_counter += nrOfCycles; if (m_os != NULL) { for (int i=0; iGetChildren().size(), 1); refcount_ptr counter = gxemul.GetRootComponent()->GetChildren()[0]; UnitTest::Assert("the component should be the counter", counter->GetVariable("name")->ToString(), "testcounter0"); // Step 0: UnitTest::Assert("the step should initially be 0", gxemul.GetStep(), 0); UnitTest::Assert("the counter should initially be 42", counter->GetVariable("counter")->ToInteger(), 42); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(); // Step 1: UnitTest::Assert("runstate wasn't reset after step 0?", gxemul.GetRunState() == GXemul::Paused); UnitTest::Assert("the step should now be 1", gxemul.GetStep(), 1); UnitTest::Assert("the counter should now be 43", counter->GetVariable("counter")->ToInteger(), 43); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(); // Step 2: UnitTest::Assert("runstate wasn't reset after step 1?", gxemul.GetRunState() == GXemul::Paused); UnitTest::Assert("the step should now be 2", gxemul.GetStep(), 2); UnitTest::Assert("the counter should now be 44", counter->GetVariable("counter")->ToInteger(), 44); } static void Test_DummyComponent_Execute_MultiSingleStep() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testcounter"); UnitTest::Assert("the testcounter should have been added", gxemul.GetRootComponent()->GetChildren().size(), 1); refcount_ptr counter = gxemul.GetRootComponent()->GetChildren()[0]; UnitTest::Assert("the component should be the counter", counter->GetVariable("name")->ToString(), "testcounter0"); const int nrOfStepsToRun = 23; gxemul.SetNrOfSingleStepsInARow(nrOfStepsToRun); gxemul.SetRunState(GXemul::SingleStepping); // Note: This should execute all nrOfStepsToRun steps, unless there // was some fatal abort condition. gxemul.Execute(); // Step n: UnitTest::Assert("runstate wasn't reset?", gxemul.GetRunState() == GXemul::Paused); UnitTest::Assert("the step should now be n", gxemul.GetStep(), nrOfStepsToRun); UnitTest::Assert("the counter should now be 42+nrOfStepsToRun", counter->GetVariable("counter")->ToInteger(), 42+nrOfStepsToRun); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(); // Step n+1: UnitTest::Assert("runstate wasn't reset after step 1?", gxemul.GetRunState() == GXemul::Paused); UnitTest::Assert("the step should now be n+1", gxemul.GetStep(), nrOfStepsToRun+1); UnitTest::Assert("the counter should now be 43+nrOfStepsToRun", counter->GetVariable("counter")->ToInteger(), 43+nrOfStepsToRun); } static void Test_DummyComponent_Execute_TwoComponentsSameSpeed() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testcounter"); gxemul.GetCommandInterpreter().RunCommand("add testcounter"); UnitTest::Assert("the testcounters should have been added", gxemul.GetRootComponent()->GetChildren().size(), 2); refcount_ptr counterA = gxemul.GetRootComponent()->GetChildren()[0]; refcount_ptr counterB = gxemul.GetRootComponent()->GetChildren()[1]; UnitTest::Assert("name A mismatch", counterA->GetVariable("name")->ToString(), "testcounter0"); UnitTest::Assert("name B mismatch", counterB->GetVariable("name")->ToString(), "testcounter1"); counterB->SetVariableValue("counter", "10042"); // Step 0: UnitTest::Assert("the step should initially be 0", gxemul.GetStep(), 0); UnitTest::Assert("counterA should initially be 42", counterA->GetVariable("counter")->ToInteger(), 42); UnitTest::Assert("counterB should initially be 10042", counterB->GetVariable("counter")->ToInteger(), 10042); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(); // Step 1: UnitTest::Assert("runstate wasn't reset after step 0?", gxemul.GetRunState() == GXemul::Paused); UnitTest::Assert("the step should now be 1", gxemul.GetStep(), 1); UnitTest::Assert("counter A should now be 43", counterA->GetVariable("counter")->ToInteger(), 43); UnitTest::Assert("counter B should now be 10043", counterB->GetVariable("counter")->ToInteger(), 10043); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(); // Step 2: UnitTest::Assert("runstate wasn't reset after step 1?", gxemul.GetRunState() == GXemul::Paused); UnitTest::Assert("the step should now be 2", gxemul.GetStep(), 2); UnitTest::Assert("counter A should now be 44", counterA->GetVariable("counter")->ToInteger(), 44); UnitTest::Assert("counter B should now be 10044", counterB->GetVariable("counter")->ToInteger(), 10044); } static void Test_DummyComponent_Execute_TwoComponentsDifferentSpeed() { GXemul gxemul; stringstream os; gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&os, 'A')); gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&os, 'B')); UnitTest::Assert("the testcounters should have been added", gxemul.GetRootComponent()->GetChildren().size(), 2); refcount_ptr counterA = gxemul.GetRootComponent()->GetChildren()[0]; refcount_ptr counterB = gxemul.GetRootComponent()->GetChildren()[1]; UnitTest::Assert("name A mismatch", counterA->GetVariable("name")->ToString(), "testcounter0"); UnitTest::Assert("name B mismatch", counterB->GetVariable("name")->ToString(), "testcounter1"); // Counter B should run twice as fast: counterA->SetVariableValue("frequency", "100000"); counterB->SetVariableValue("frequency", "200000"); counterB->SetVariableValue("counter", "10042"); // Step 0: UnitTest::Assert("the step should initially be 0", gxemul.GetStep(), 0); UnitTest::Assert("counterA should initially be 42", counterA->GetVariable("counter")->ToInteger(), 42); UnitTest::Assert("counterB should initially be 10042", counterB->GetVariable("counter")->ToInteger(), 10042); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(); // B executes in the first step. gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(); // A,B execute in the second step. // Step 2: UnitTest::Assert("the step should now be 2", gxemul.GetStep(), 2); UnitTest::Assert("counter A should now be 43", counterA->GetVariable("counter")->ToInteger(), 43); UnitTest::Assert("counter B should now be 10044", counterB->GetVariable("counter")->ToInteger(), 10044); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(); // Step 4: UnitTest::Assert("the step should now be 4", gxemul.GetStep(), 4); UnitTest::Assert("counter A should now be 44", counterA->GetVariable("counter")->ToInteger(), 44); UnitTest::Assert("counter B should now be 10046", counterB->GetVariable("counter")->ToInteger(), 10046); UnitTest::Assert("output stream mismatch?", os.str(), "BABBAB"); } static void Test_DummyComponent_Execute_Continuous_SingleComponent() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testcounter"); refcount_ptr counterA = gxemul.GetRootComponent()->GetChildren()[0]; counterA->SetVariableValue("counter", "10042"); // Step 0: UnitTest::Assert("the step should initially be 0", gxemul.GetStep(), 0); UnitTest::Assert("counterA should initially be 10042", counterA->GetVariable("counter")->ToInteger(), 10042); gxemul.SetRunState(GXemul::Running); gxemul.Execute(); // Step n: int n = gxemul.GetStep(); UnitTest::Assert("counter A should now be 10042 + n", counterA->GetVariable("counter")->ToInteger(), 10042 + n); gxemul.SetRunState(GXemul::SingleStepping); gxemul.Execute(); // Step n + 1: UnitTest::Assert("the step should now be n + 1", gxemul.GetStep(), n + 1); UnitTest::Assert("counter B should now be 10042 + n + 1", counterA->GetVariable("counter")->ToInteger(), 10042 + n + 1); } static void Test_DummyComponent_Execute_Continuous_TwoComponentsSameSpeed() { GXemul gxemul; stringstream os; gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&os, 'A')); gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&os, 'B')); UnitTest::Assert("accuracy should be cycle!", gxemul.GetRootComponent()->GetVariable("accuracy")->ToString(), "cycle"); refcount_ptr counterA = gxemul.GetRootComponent()->GetChildren()[0]; refcount_ptr counterB = gxemul.GetRootComponent()->GetChildren()[1]; counterA->SetVariableValue("counter", "123"); counterB->SetVariableValue("counter", "0"); // Step 0: UnitTest::Assert("counterA should initially be 123", counterA->GetVariable("counter")->ToInteger(), 123); UnitTest::Assert("counterB should initially be 0", counterB->GetVariable("counter")->ToInteger(), 0); // The two components have the same speed, which is a "worst case" // for cycle accurate emulation. They have to be interleaved one // cycle at a time. gxemul.SetRunState(GXemul::Running); gxemul.Execute(10000); // Step n: int n = gxemul.GetStep(); UnitTest::Assert("n very low?", n > 100); UnitTest::Assert("counter A should now be 123 + n", counterA->GetVariable("counter")->ToInteger(), 123 + n); UnitTest::Assert("counter B should now be 0 + n", counterB->GetVariable("counter")->ToInteger(), 0 + n); // After n steps, the stream should be ABABABAB... n times. stringstream correct; for (int i=0; iAddChild(new DummyComponentWithCounter(&os, 'A')); gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&os, 'B')); UnitTest::Assert("accuracy should be cycle!", gxemul.GetRootComponent()->GetVariable("accuracy")->ToString(), "cycle"); refcount_ptr counterA = gxemul.GetRootComponent()->GetChildren()[0]; refcount_ptr counterB = gxemul.GetRootComponent()->GetChildren()[1]; counterA->SetVariableValue("counter", "123"); counterB->SetVariableValue("counter", "0"); // Counter B should run three times as fast: counterA->SetVariableValue("frequency", "100000"); counterB->SetVariableValue("frequency", "300000"); // Step 0: UnitTest::Assert("counterA should initially be 123", counterA->GetVariable("counter")->ToInteger(), 123); UnitTest::Assert("counterB should initially be 0", counterB->GetVariable("counter")->ToInteger(), 0); // Step 0: B // Step 1: B // Step 2: A and B gxemul.SetRunState(GXemul::Running); gxemul.Execute(1000); // Step n: B should have executed 1 per cycle // but A only 1/3 of the cycles. int n = gxemul.GetStep(); int a = counterA->GetVariable("counter")->ToInteger(); UnitTest::Assert("counter A should now be approximately 123 + n/3", (a >= 122 + n/3) && (a <= 123 + n/3)); UnitTest::Assert("counter B should now be 0 + n", counterB->GetVariable("counter")->ToInteger(), 0 + n); // After n steps, the stream should be BBAB... n cycles. stringstream correct; for (int i=0; iAddChild(new DummyComponentWithCounter(&os, 'A')); gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&os, 'B')); gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&os, 'C')); UnitTest::Assert("accuracy should be cycle!", gxemul.GetRootComponent()->GetVariable("accuracy")->ToString(), "cycle"); refcount_ptr counterA = gxemul.GetRootComponent()->GetChildren()[0]; refcount_ptr counterB = gxemul.GetRootComponent()->GetChildren()[1]; refcount_ptr counterC = gxemul.GetRootComponent()->GetChildren()[2]; counterA->SetVariableValue("counter", "0"); counterB->SetVariableValue("counter", "0"); counterC->SetVariableValue("counter", "0"); counterA->SetVariableValue("frequency", "1"); counterB->SetVariableValue("frequency", "100"); counterC->SetVariableValue("frequency", "10"); gxemul.SetRunState(GXemul::Running); gxemul.Execute(2000); int n = gxemul.GetStep(); UnitTest::Assert("n very low?", n >= 2000); int a = counterA->GetVariable("counter")->ToInteger(); UnitTest::Assert("counter A should now be approximately n / 100", (a >= n / 100 - 1) && (a <= n / 100 + 1)); UnitTest::Assert("counter B should now be n", counterB->GetVariable("counter")->ToInteger(), n); int c = counterC->GetVariable("counter")->ToInteger(); UnitTest::Assert("counter C should now be approximately n / 10", (c >= n / 10 - 1) && (c <= n / 10 + 1)); // Compare with single-step stream: { GXemul gxemul2; stringstream singleStepStream; gxemul2.GetRootComponent()->AddChild(new DummyComponentWithCounter(&singleStepStream, 'A')); gxemul2.GetRootComponent()->AddChild(new DummyComponentWithCounter(&singleStepStream, 'B')); gxemul2.GetRootComponent()->AddChild(new DummyComponentWithCounter(&singleStepStream, 'C')); counterA = gxemul2.GetRootComponent()->GetChildren()[0]; counterB = gxemul2.GetRootComponent()->GetChildren()[1]; counterC = gxemul2.GetRootComponent()->GetChildren()[2]; counterA->SetVariableValue("counter", "0"); counterB->SetVariableValue("counter", "0"); counterC->SetVariableValue("counter", "0"); counterA->SetVariableValue("frequency", "1"); counterB->SetVariableValue("frequency", "100"); counterC->SetVariableValue("frequency", "10"); for (int i=0; iAddChild(new DummyComponentWithCounter(&os, 'A')); gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&os, 'B')); gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&os, 'C')); UnitTest::Assert("accuracy should be cycle!", gxemul.GetRootComponent()->GetVariable("accuracy")->ToString(), "cycle"); refcount_ptr counterA = gxemul.GetRootComponent()->GetChildren()[0]; refcount_ptr counterB = gxemul.GetRootComponent()->GetChildren()[1]; refcount_ptr counterC = gxemul.GetRootComponent()->GetChildren()[2]; counterA->SetVariableValue("counter", "0"); counterB->SetVariableValue("counter", "0"); counterC->SetVariableValue("counter", "0"); counterA->SetVariableValue("frequency", "7"); counterB->SetVariableValue("frequency", "101"); counterC->SetVariableValue("frequency", "18"); gxemul.SetRunState(GXemul::Running); gxemul.Execute(2000); int n = gxemul.GetStep(); UnitTest::Assert("n very low?", n >= 2000); // Compare with single-step stream: { GXemul gxemul2; stringstream singleStepStream; gxemul2.GetRootComponent()->AddChild(new DummyComponentWithCounter(&singleStepStream, 'A')); gxemul2.GetRootComponent()->AddChild(new DummyComponentWithCounter(&singleStepStream, 'B')); gxemul2.GetRootComponent()->AddChild(new DummyComponentWithCounter(&singleStepStream, 'C')); counterA = gxemul2.GetRootComponent()->GetChildren()[0]; counterB = gxemul2.GetRootComponent()->GetChildren()[1]; counterC = gxemul2.GetRootComponent()->GetChildren()[2]; counterA->SetVariableValue("counter", "0"); counterB->SetVariableValue("counter", "0"); counterC->SetVariableValue("counter", "0"); counterA->SetVariableValue("frequency", "7"); counterB->SetVariableValue("frequency", "101"); counterC->SetVariableValue("frequency", "18"); for (int i=0; iAddChild(new DummyComponentWithCounter(&os, 'A')); gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&os, 'B')); gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&os, 'C')); UnitTest::Assert("accuracy should be cycle!", gxemul.GetRootComponent()->GetVariable("accuracy")->ToString(), "cycle"); refcount_ptr counterA = gxemul.GetRootComponent()->GetChildren()[0]; refcount_ptr counterB = gxemul.GetRootComponent()->GetChildren()[1]; refcount_ptr counterC = gxemul.GetRootComponent()->GetChildren()[2]; counterA->SetVariableValue("counter", "0"); counterB->SetVariableValue("counter", "0"); counterC->SetVariableValue("counter", "0"); counterA->SetVariableValue("frequency", "183"); counterB->SetVariableValue("frequency", "191"); counterC->SetVariableValue("frequency", "194"); gxemul.SetRunState(GXemul::Running); gxemul.Execute(1000); int n = gxemul.GetStep(); UnitTest::Assert("n very low?", n >= 1000); // Compare with single-step stream: { GXemul gxemul; stringstream singleStepStream; gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&singleStepStream, 'A')); gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&singleStepStream, 'B')); gxemul.GetRootComponent()->AddChild(new DummyComponentWithCounter(&singleStepStream, 'C')); refcount_ptr counterA = gxemul.GetRootComponent()->GetChildren()[0]; refcount_ptr counterB = gxemul.GetRootComponent()->GetChildren()[1]; refcount_ptr counterC = gxemul.GetRootComponent()->GetChildren()[2]; counterA->SetVariableValue("counter", "0"); counterB->SetVariableValue("counter", "0"); counterC->SetVariableValue("counter", "0"); counterA->SetVariableValue("frequency", "183"); counterB->SetVariableValue("frequency", "191"); counterC->SetVariableValue("frequency", "194"); for (int i=0; iGetUI()->ShowDebugMessage(this, "accuracy must be \"cycle\" or \"sloppy\".\n"); return false; } return true; } void RootComponent::SetOwner(GXemul* owner) { m_gxemul = owner; } bool RootComponent::CheckVariableWrite(StateVariable& var, const string& oldValue) { UI* ui = GetUI(); const string& name = var.GetName(); if (name == "accuracy") { if (var.ToString() != "cycle" && var.ToString() != "sloppy") { if (ui != NULL) ui->ShowDebugMessage(this, "accuracy must be \"cycle\" or \"sloppy\".\n"); return false; } } return Component::CheckVariableWrite(var, oldValue); } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_RootComponent_CreateComponent() { refcount_ptr component; component = ComponentFactory::CreateComponent("root"); UnitTest::Assert("creating a root component with CreateComponent " "should NOT be possible", component.IsNULL() == true); } static void Test_RootComponent_InitialVariables() { refcount_ptr component = new RootComponent; StateVariable* name = component->GetVariable("name"); StateVariable* step = component->GetVariable("step"); StateVariable* accuracy = component->GetVariable("accuracy"); UnitTest::Assert("name should be root", name->ToString(), "root"); UnitTest::Assert("step should be 0", step->ToInteger(), 0); UnitTest::Assert("accuracy should be cycle", accuracy->ToString(), "cycle"); } static void Test_RootComponent_AccuracyValues() { GXemul dummyGXemul; refcount_ptr component = new RootComponent; StateVariable* accuracy = component->GetVariable("accuracy"); accuracy->SetValue("\"sloppy\""); UnitTest::Assert("sloppy should be ok", component->PreRunCheck(&dummyGXemul)); accuracy->SetValue("\"nonsense\""); UnitTest::Assert("nonsense should not be ok", !component->PreRunCheck(&dummyGXemul)); accuracy->SetValue("\"cycle\""); UnitTest::Assert("cycle should be ok", component->PreRunCheck(&dummyGXemul)); } UNITTESTS(RootComponent) { UNITTEST(Test_RootComponent_CreateComponent); UNITTEST(Test_RootComponent_InitialVariables); UNITTEST(Test_RootComponent_AccuracyValues); // TODO: Test owner } #endif gxemul-0.6.1/src/components/special/Makefile.skel000644 001750 001750 00000000400 13402411502 022210 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/components/special # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(CPEDANTIC) $(INCLUDE2) LIBS=$(OTHERLIBS) OBJS=DummyComponent.o RootComponent.o all: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) clean_all: clean rm -f Makefile gxemul-0.6.1/src/ui/Makefile.skel000644 001750 001750 00000000504 13402411502 017025 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/ui # all: do_console do_nullui $(OBJS): Makefile do_console: cd console; $(MAKE) do_nullui: cd nullui; $(MAKE) clean: cd console; $(MAKE) clean cd nullui; $(MAKE) clean rm -f $(OBJS) *core clean_all: clean cd console; $(MAKE) clean_all cd nullui; $(MAKE) clean_all rm -f Makefile gxemul-0.6.1/src/ui/nullui/000755 001750 001750 00000000000 13402411502 015741 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/ui/console/000755 001750 001750 00000000000 13402411502 016073 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/ui/console/ConsoleUI.cc000644 001750 001750 00000016530 13402411502 020247 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "misc.h" #include "ConsoleUI.h" #include "GXemul.h" ConsoleUI::ConsoleUI(GXemul *gxemul) : UI(gxemul) , m_consoleIsInitialized(false) { } ConsoleUI::~ConsoleUI() { // Restore the terminal mode: if (m_consoleIsInitialized) tcsetattr(STDIN_FILENO, TCSANOW, &m_oldTermios); } // Note: Use of global GXemul pointer! static GXemul* g_GXemul; static struct termios g_curTermios; static void ReshowCurrentCommandBuffer() { if (g_GXemul->GetRunState() == GXemul::Paused) { // Reshow the prompt and the current command line: g_GXemul->GetCommandInterpreter().ReshowCurrentCommandBuffer(); std::cout.flush(); } } /** * \brief CTRL-C handler which sets the run state to Paused. */ extern "C" void ConsoleUI_SIGINT_Handler(int n) { if (g_GXemul->IsInterrupting()) std::cout << "^C (already attempting to interrupt, please wait)\n"; else std::cout << "^C\n"; g_GXemul->Interrupt(); g_GXemul->GetCommandInterpreter().ClearCurrentCommandBuffer(); ReshowCurrentCommandBuffer(); signal(SIGINT, ConsoleUI_SIGINT_Handler); } /** * \brief Restore terminal settings after a CTRL-Z. * * If the user presses CTRL-Z (to stop the emulator process) and then * continues, the termios settings might have been invalidated. This * function restores them. */ extern "C" void ConsoleUI_SIGCONT_Handler(int n) { tcsetattr(STDIN_FILENO, TCSANOW, &g_curTermios); ReshowCurrentCommandBuffer(); signal(SIGCONT, ConsoleUI_SIGCONT_Handler); } void ConsoleUI::Initialize() { if (m_consoleIsInitialized) return; tcgetattr(STDIN_FILENO, &m_oldTermios); m_currentTermios = m_oldTermios; // Set the terminal mode: m_currentTermios.c_lflag &= ~ICANON; m_currentTermios.c_cc[VTIME] = 0; m_currentTermios.c_cc[VMIN] = 1; m_currentTermios.c_lflag &= ~ECHO; tcsetattr(STDIN_FILENO, TCSANOW, &m_currentTermios); // Signal handlers for CTRL-C and CTRL-Z. // Note: Using a global GXemul instance pointer! g_GXemul = m_gxemul; g_curTermios = m_currentTermios; signal(SIGINT, ConsoleUI_SIGINT_Handler); signal(SIGCONT, ConsoleUI_SIGCONT_Handler); m_consoleIsInitialized = true; } void ConsoleUI::UpdateUI() { // Empty. } void ConsoleUI::ShowStartupBanner() { std::cout << GXemul::Version() << "\n"; } static vector SplitIntoRows(const string &msg, bool addEmptyLines) { // This is slow and hackish, but works. vector result; string line; for (size_t i=0, n=msg.length(); i 0 || addEmptyLines) result.push_back(line); line = ""; } else { line += ch; } } if (line.length() > 0) result.push_back(line); return result; } void ConsoleUI::ShowDebugMessage(const string& msg) { vector lines = SplitIntoRows(msg, true); for (size_t i=0; iGetRunState() == GXemul::Running) std::cout << "[ " << m_indentationMsg << lines[i] << " ]\n"; else std::cout << m_indentationMsg << lines[i] << "\n"; // Replace indentation string with spaces after first // line of output: for (size_t j=m_indentationMsg.length(); j>0; --j) m_indentationMsg[j-1] = ' '; } std::cout.flush(); } void ConsoleUI::ShowDebugMessage(Component* component, const string& msg) { if (m_gxemul->GetQuietMode()) return; stringstream ss; string componentName = component->GenerateShortestPossiblePath(); vector lines = SplitIntoRows(msg, false); // cpu0: blahlonger // blahshort size_t i; string spaces = ""; for (i=0; i " << inputline << " \rGXemul> "; for (size_t pos = 0; pos < cursorPosition; pos++) std::cout << (string() + inputline[pos]); std::cout.flush(); } /** * \brief Read a key from stdin, blocking. * * @return The key read from stdin. */ static stringchar ReadKey() { return std::cin.get(); } void ConsoleUI::ReadAndExecuteCommand() { // Initial dummy addkey, to show the input line with the prompt, etc.: m_gxemul->GetCommandInterpreter().AddKey('\0'); while (!m_gxemul->GetCommandInterpreter().AddKey(ReadKey())) ; } void ConsoleUI::InputLineDone() { std::cout << "\n"; std::cout.flush(); } void ConsoleUI::Shutdown() { } int ConsoleUI::MainLoop() { GXemul::RunState oldRunState = m_gxemul->GetRunState(); while (m_gxemul->GetRunState() != GXemul::Quitting) { GXemul::RunState runState = m_gxemul->GetRunState(); switch (runState) { case GXemul::SingleStepping: case GXemul::Running: // Switching from Paused state to running? Then // we need to: // 1) flush old cached state // 2) perform pre-run checks. if (oldRunState == GXemul::Paused) { m_gxemul->GetRootComponent()->FlushCachedState(); if (!m_gxemul->GetRootComponent()->PreRunCheck(m_gxemul)) { FatalError("Pre-run check failed.\n"); m_gxemul->SetRunState(GXemul::Paused); runState = m_gxemul->GetRunState(); break; } } m_gxemul->Execute(); break; case GXemul::Quitting: break; case GXemul::Paused: // When issuing interactive commands, "anything" can // happen to the component tree, and thus any cached // state quickly becomes untrustworthy. Let's flush it. m_gxemul->GetRootComponent()->FlushCachedState(); ReadAndExecuteCommand(); break; } oldRunState = runState; } return 0; } gxemul-0.6.1/src/ui/console/Makefile.skel000644 001750 001750 00000000351 13402411502 020467 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/ui/console # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(CPEDANTIC) $(INCLUDE2) LIBS=$(OTHERLIBS) OBJS=ConsoleUI.o all: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) *core clean_all: clean rm -f Makefile gxemul-0.6.1/src/ui/nullui/NullUI.cc000644 001750 001750 00000004215 13402411502 017422 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "NullUI.h" #include "GXemul.h" NullUI::NullUI(GXemul *gxemul) : UI(gxemul) { } NullUI::~NullUI() { } void NullUI::Initialize() { } void NullUI::ShowStartupBanner() { } void NullUI::UpdateUI() { } void NullUI::ShowDebugMessage(const string& msg) { } void NullUI::ShowDebugMessage(Component* component, const string& msg) { } void NullUI::ShowCommandMessage(const string& command) { } void NullUI::FatalError(const string& msg) { } void NullUI::RedisplayInputLine(const string& inputline, size_t cursorPosition) { } void NullUI::InputLineDone() { } void NullUI::Shutdown() { } int NullUI::MainLoop() { return 0; } gxemul-0.6.1/src/ui/nullui/Makefile.skel000644 001750 001750 00000000345 13402411502 020340 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/ui/nullui # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(CPEDANTIC) $(INCLUDE2) LIBS=$(OTHERLIBS) OBJS=NullUI.o all: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) *core clean_all: clean rm -f Makefile gxemul-0.6.1/src/symbol/symbol_demangle.cc000644 001750 001750 00000015624 13402411502 021001 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * C++ symbol name demangling. * * For obvious performance reasons, the external c++filt utility cannot be * used. Also, the host's version of this utility might be incompatible with * the binary being emulated. * * TODO: Constructors, destructors, and lots of other stuff. See * http://www.codesourcery.com/cxx-abi/abi.html#mangling for details. */ #include #include #include #include #include "symbol.h" #define MAXLEN 1000 static void add_string(char *p, size_t *curlenp, const char *to_add) { size_t curlen = *curlenp; while (curlen < MAXLEN && *to_add) p[curlen++] = *to_add++; *curlenp = curlen; } /* * symbol_demangle_cplusplus_nested(): * * Try to demangle a nested cplusplus name. name points to the first character * after "_ZN". */ static char *symbol_demangle_cplusplus_nested(const char *name) { char *result; size_t result_len = 0, len; int first = 1, type_added = 0, pointercounter, reference; CHECK_ALLOCATION(result = (char *) malloc(MAXLEN + 1)); result[0] = '\0'; while (name[0] && name[0] != 'E' && result_len < MAXLEN) { /* Read length of the next part: */ len = 0; if (*name == '0') { name ++; } else { while (isdigit((int)*name)) { len *= 10; len += (*name - '0'); name ++; } } /* Add :: */ if (!first) add_string(result, &result_len, "::"); /* Read the part itself: */ while (len-- >= 1 && result_len < MAXLEN) result[result_len ++] = *name++; first = 0; } if (name[0] != 'E') goto fail; name ++; if (*name) add_string(result, &result_len, "{"); /* Type: */ pointercounter = reference = 0; while (*name) { int argument_done = 0; char t = *name++; switch (t) { case 'c': add_string(result, &result_len, "char"); argument_done = 1; break; case 'a': add_string(result, &result_len, "signed char"); argument_done = 1; break; case 'h': add_string(result, &result_len, "unsigned char"); argument_done = 1; break; case 'i': add_string(result, &result_len, "int"); argument_done = 1; break; case 'j': add_string(result, &result_len, "unsigned int"); argument_done = 1; break; case 'w': add_string(result, &result_len, "wchar_t"); argument_done = 1; break; case 'b': add_string(result, &result_len, "bool"); argument_done = 1; break; case 's': add_string(result, &result_len, "short"); argument_done = 1; break; case 't': add_string(result, &result_len, "unsigned short"); argument_done = 1; break; case 'l': add_string(result, &result_len, "long"); argument_done = 1; break; case 'm': add_string(result, &result_len, "unsigned long"); argument_done = 1; break; case 'x': add_string(result, &result_len, "long long"); argument_done = 1; break; case 'y': add_string(result, &result_len, "unsigned long long"); argument_done = 1; break; case 'n': add_string(result, &result_len, "__int128"); argument_done = 1; break; case 'o': add_string(result, &result_len, "unsigned __int128"); argument_done = 1; break; case 'f': add_string(result, &result_len, "float"); argument_done = 1; break; case 'd': add_string(result, &result_len, "double"); argument_done = 1; break; case 'e': add_string(result, &result_len, "__float80"); argument_done = 1; break; case 'g': add_string(result, &result_len, "__float128"); argument_done = 1; break; case 'z': add_string(result, &result_len, "..."); argument_done = 1; break; case 'P': pointercounter ++; break; case 'R': reference ++; break; case 'v': /* void */ break; default:/* Unknown */ goto fail; } if (argument_done) { while (pointercounter-- > 0) add_string(result, &result_len, "*"); while (reference-- > 0) add_string(result, &result_len, "&"); if (*name) add_string(result, &result_len, ","); } type_added = 1; } if (type_added) add_string(result, &result_len, "}"); if (result_len == MAXLEN) goto fail; result[result_len] = '\0'; return result; fail: free(result); return NULL; } /* * symbol_demangle_cplusplus(): * * Try to demangle name. If name was not a valid/known C++ symbol, then NULL * is returned. Otherwise, a newly allocated string is returned, containing * the demangled name. */ char *symbol_demangle_cplusplus(const char *name) { /* Only support _Z-style mangled names, for now: */ if (strlen(name) < 2 || name[0] != '_' || name[1] != 'Z') return NULL; name += 2; switch (name[0]) { case 'N': return symbol_demangle_cplusplus_nested(name + 1); break; } return NULL; } #ifdef TEST void test(char *mangled, char *result) { char *p = symbol_demangle_cplusplus(mangled); if (p == NULL) { if (result == NULL) { return; } else { printf("FAILURE for %s!\n", mangled); exit(1); } } if (strcmp(p, result) == 0) return; printf("FAILURE for %s! (result = %s)\n", mangled, p); exit(1); } int main(int argc, char *argv[]) { test("monkey", NULL); test("_monkey", NULL); test("_zmonkey", NULL); test("_Zmonkey", NULL); test("_ZQ5abcde", NULL); test("_ZN3abc5defghE", "abc::defgh"); test("_ZN05defghEv", "::defgh{}"); test("_ZN5defghEv", "defgh{}"); test("_ZN3abc5defghEv", "abc::defgh{}"); test("_ZN3abc5defghEc", "abc::defgh{char}"); test("_ZN1a2bcEjij", "a::bc{unsigned int,int,unsigned int}"); printf("OK\n"); return 0; } #endif gxemul-0.6.1/src/symbol/symbol.cc000644 001750 001750 00000024222 13402411502 017137 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Address to symbol translation routines. * * This module is (probably) independent from the rest of the emulator. * symbol_init() must be called before any other function in this file is used. */ #include #include #include #include "symbol.h" #define SYMBOLBUF_MAX 100 /* * symbol_nsymbols(): * * Return n_symbols. */ int symbol_nsymbols(struct symbol_context *sc) { return sc->n_symbols; } /* * get_symbol_addr(): * * Find a symbol by name. If addr is non-NULL, *addr is set to the symbol's * address. Return value is 1 if the symbol is found, 0 otherwise. * * NOTE: This is O(n). */ int get_symbol_addr(struct symbol_context *sc, const char *symbol, uint64_t *addr) { struct symbol *s; if (sc->sorted_array) { int i; for (i=0; in_symbols; i++) if (strcmp(symbol, sc->first_symbol[i].name) == 0) { if (addr != NULL) *addr = sc->first_symbol[i].addr; return 1; } } else { s = sc->first_symbol; while (s != NULL) { if (strcmp(symbol, s->name) == 0) { if (addr != NULL) *addr = s->addr; return 1; } s = s->next; } } return 0; } /* * get_symbol_name_and_n_args(): * * Translate an address into a symbol name. The return value is a pointer * to a static char array, containing the symbol name. (In other words, * this function is not reentrant. This removes the need for memory allocation * at the caller's side.) * * If offset is not a NULL pointer, *offset is set to the offset within * the symbol. For example, if there is a symbol at address 0x1000 with * length 0x100, and a caller wants to know the symbol name of address * 0x1008, the symbol's name will be found in the static char array, and * *offset will be set to 0x8. * * If n_argsp is non-NULL, *n_argsp is set to the symbol's n_args value. * * If no symbol was found, NULL is returned instead. */ static char symbol_buf[SYMBOLBUF_MAX+1]; char *get_symbol_name_and_n_args(struct symbol_context *sc, uint64_t addr, uint64_t *offset, int *n_argsp) { struct symbol *s; if (sc->n_symbols == 0) return NULL; if ((addr >> 32) == 0 && (addr & 0x80000000ULL)) addr |= 0xffffffff00000000ULL; symbol_buf[0] = symbol_buf[SYMBOLBUF_MAX] = '\0'; if (offset != NULL) *offset = 0; if (!sc->sorted_array) { /* Slow, linear O(n) search: */ s = sc->first_symbol; while (s != NULL) { /* Found a match? */ if (addr >= s->addr && addr < s->addr + s->len) { if (addr == s->addr) snprintf(symbol_buf, SYMBOLBUF_MAX, "%s", s->name); else snprintf(symbol_buf, SYMBOLBUF_MAX, "%s+0x%" PRIx64, s->name, (uint64_t) (addr - s->addr)); if (offset != NULL) *offset = addr - s->addr; if (n_argsp != NULL) *n_argsp = s->n_args; return symbol_buf; } s = s->next; } } else { /* Faster, O(log n) search: */ int lowest = 0, highest = sc->n_symbols - 1; while (lowest <= highest) { int ofs = (lowest + highest) / 2; s = sc->first_symbol + ofs; /* Found a match? */ if (addr >= s->addr && addr <= s->addr + (s->len - 1)) { if (addr == s->addr) snprintf(symbol_buf, SYMBOLBUF_MAX, "%s", s->name); else snprintf(symbol_buf, SYMBOLBUF_MAX, "%s+0x%" PRIx64, s->name, (uint64_t) (addr - s->addr)); if (offset != NULL) *offset = addr - s->addr; if (n_argsp != NULL) *n_argsp = s->n_args; return symbol_buf; } if (addr < s->addr) highest = ofs - 1; else lowest = ofs + 1; } } /* Not found? Then return NULL. */ return NULL; } /* * get_symbol_name(): * * See get_symbol_name_and_n_args(). */ char *get_symbol_name(struct symbol_context *sc, uint64_t addr, uint64_t *offs) { return get_symbol_name_and_n_args(sc, addr, offs, NULL); } /* * add_symbol_name(): * * Add a symbol to the symbol list. */ void add_symbol_name(struct symbol_context *sc, uint64_t addr, uint64_t len, const char *name, int type, int n_args) { struct symbol *s; if (sc->sorted_array) { fprintf(stderr, "add_symbol_name(): Internal error: the " "symbol array is already sorted\n"); exit(1); } if (name == NULL) { fprintf(stderr, "add_symbol_name(): name = NULL\n"); exit(1); } if (addr == 0 && strcmp(name, "_DYNAMIC_LINK") == 0) return; if (name[0] == '\0') return; /* TODO: Maybe this should be optional? */ if (name[0] == '.' || name[0] == '$') return; /* Quick test-hack: */ if (n_args < 0) { if (strcmp(name, "strlen") == 0) n_args = 1; if (strcmp(name, "strcmp") == 0) n_args = 2; if (strcmp(name, "strcpy") == 0) n_args = 2; if (strcmp(name, "strncpy") == 0) n_args = 3; if (strcmp(name, "strlcpy") == 0) n_args = 3; if (strcmp(name, "strlcat") == 0) n_args = 3; if (strcmp(name, "strncmp") == 0) n_args = 3; if (strcmp(name, "memset") == 0) n_args = 3; if (strcmp(name, "memcpy") == 0) n_args = 3; if (strcmp(name, "bzero") == 0) n_args = 2; if (strcmp(name, "bcopy") == 0) n_args = 3; } if ((addr >> 32) == 0 && (addr & 0x80000000ULL)) addr |= 0xffffffff00000000ULL; CHECK_ALLOCATION(s = (struct symbol *) malloc(sizeof(struct symbol))); memset(s, 0, sizeof(struct symbol)); s->name = symbol_demangle_cplusplus(name); if (s->name == NULL) CHECK_ALLOCATION(s->name = strdup(name)); s->addr = addr; s->len = len; s->type = type; s->n_args = n_args; sc->n_symbols ++; /* Add first in list: */ s->next = sc->first_symbol; sc->first_symbol = s; } /* * symbol_readfile(): * * Read 'nm -S' style symbols from a file. * * TODO: This function is an ugly hack, and should be replaced * with something that reads symbols directly from the executable * images. */ void symbol_readfile(struct symbol_context *sc, char *fname) { FILE *f; char b1[80]; uint64_t addr; char b2[80]; uint64_t len; char b3[80]; int type; char b4[80]; int cur_n_symbols = sc->n_symbols; f = fopen(fname, "r"); if (f == NULL) { perror(fname); exit(1); } while (!feof(f)) { memset(b1, 0, sizeof(b1)); memset(b2, 0, sizeof(b2)); memset(b3, 0, sizeof(b3)); memset(b4, 0, sizeof(b4)); if (fscanf(f, "%s %s\n", b1,b2) != 2) fprintf(stderr, "warning: symbol file parse error\n"); if (strlen(b2) < 2 && !(b2[0]>='0' && b2[0]<='9')) { strlcpy(b3, b2, sizeof(b3)); strlcpy(b2, "0", sizeof(b2)); if (fscanf(f, "%s\n", b4) != 1) fprintf(stderr, "warning: symbol file parse error\n"); } else { if (fscanf(f, "%s %s\n", b3,b4) != 2) fprintf(stderr, "warning: symbol file parse error\n"); } /* printf("b1='%s' b2='%s' b3='%s' b4='%s'\n", b1,b2,b3,b4); */ addr = strtoull(b1, NULL, 16); len = strtoull(b2, NULL, 16); type = b3[0]; /* printf("addr=%016" PRIx64" len=%016" PRIx64" type=%i\n", addr, len, type); */ if (type == 't' || type == 'r' || type == 'g') continue; add_symbol_name(sc, addr, len, b4, type, -1); } fclose(f); debug("%i symbols\n", sc->n_symbols - cur_n_symbols); } /* * sym_addr_compare(): * * Helper function for sorting symbols according to their address. */ int sym_addr_compare(const void *a, const void *b) { struct symbol *p1 = (struct symbol *) a; struct symbol *p2 = (struct symbol *) b; if (p1->addr < p2->addr) return -1; if (p1->addr > p2->addr) return 1; return 0; } /* * symbol_recalc_sizes(): * * Recalculate sizes of symbols that have size = 0, by creating an array * containing all symbols, qsort()-ing that array according to address, and * recalculating the size fields if necessary. */ void symbol_recalc_sizes(struct symbol_context *sc) { struct symbol *tmp_array; struct symbol *last_ptr; struct symbol *tmp_ptr; int i; CHECK_ALLOCATION(tmp_array = (struct symbol *) malloc(sizeof (struct symbol) * sc->n_symbols)); /* Copy first_symbol --> tmp_array, and remove the old first_symbol at the same time: */ tmp_ptr = sc->first_symbol; i = 0; while (tmp_ptr != NULL) { tmp_array[i] = *tmp_ptr; last_ptr = tmp_ptr; tmp_ptr = tmp_ptr->next; free(last_ptr); i++; } qsort(tmp_array, sc->n_symbols, sizeof(struct symbol), sym_addr_compare); sc->sorted_array = 1; /* Recreate the first_symbol chain: */ sc->first_symbol = NULL; for (i=0; in_symbols; i++) { /* Recalculate size, if 0: */ if (tmp_array[i].len == 0) { uint64_t len; if (i != sc->n_symbols-1) len = tmp_array[i+1].addr - tmp_array[i].addr; else len = 1; tmp_array[i].len = len; } tmp_array[i].next = &tmp_array[i+1]; } sc->first_symbol = tmp_array; } /* * symbol_init(): * * Initialize the symbol hashtables. */ void symbol_init(struct symbol_context *sc) { sc->first_symbol = NULL; sc->sorted_array = 0; sc->n_symbols = 0; } gxemul-0.6.1/src/symbol/Makefile.skel000644 001750 001750 00000000364 13402411502 017721 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/symbol # # Symbol handling support. # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(DINCLUDE) OBJS=symbol.o symbol_demangle.o all: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) *core clean_all: clean rm -f Makefile gxemul-0.6.1/src/main/commands/000755 001750 001750 00000000000 13402411502 016541 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/main/Component.cc000644 001750 001750 00000077372 13402411502 017231 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Note: See DummyComponent.cc for unit tests of the component framework. */ #include "assert.h" #include #include "components/RootComponent.h" #include "Component.h" #include "ComponentFactory.h" #include "EscapedString.h" #include "GXemul.h" #include "StringHelper.h" Component::Component(const string& className, const string& visibleClassName) : m_parentComponent(NULL) , m_className(className) , m_visibleClassName(visibleClassName) , m_step(0) { AddVariable("name", &m_name); AddVariable("template", &m_template); AddVariable("step", &m_step); } string Component::GetClassName() const { return m_className; } string Component::GetVisibleClassName() const { return m_visibleClassName; } string Component::GetAttribute(const string& attributeName) { // The Component base class always returns an empty string // for all attribute names. It is up to individual Component // implementations to return overrides. return ""; } refcount_ptr Component::Clone() const { refcount_ptr clone; if (GetClassName() == "root") clone = new RootComponent; else clone = ComponentFactory::CreateComponent(GetClassName()); if (clone.IsNULL()) { std::cerr << "INTERNAL ERROR in Component::Clone(): " "could not clone a '" << GetClassName() << "'\n"; throw std::exception(); } // Copy the value of each state variable to the clone: StateVariableMap::const_iterator varIt = m_stateVariables.begin(); for ( ; varIt != m_stateVariables.end(); ++varIt) { const string& varName = varIt->first; const StateVariable& variable = varIt->second; StateVariableMap::iterator cloneVarIt = clone->m_stateVariables.find(varName); if (cloneVarIt == clone->m_stateVariables.end()) { std::cerr << "INTERNAL ERROR in Component::Clone(): " "could not copy variable " << varName << "'s " << " value to the clone: clone is missing" " this variable?\n"; assert(false); } else if (!(cloneVarIt->second).CopyValueFrom(variable)) { std::cerr << "INTERNAL ERROR in Component::Clone(): " "could not copy variable " << varName << "'s " << " value to the clone.\n"; assert(false); } } for (Components::const_iterator it = m_childComponents.begin(); it != m_childComponents.end(); ++it) { refcount_ptr child = (*it)->Clone(); if (child.IsNULL()) { std::cerr << "INTERNAL ERROR in Component::Clone(): " "could not clone child of class '" << (*it)->GetClassName() << "'\n"; assert(false); } else { clone->AddChild(child); } } return clone; } refcount_ptr Component::LightCloneInternal() const { refcount_ptr clone; if (GetClassName() == "root") clone = new RootComponent; else clone = ComponentFactory::CreateComponent(GetClassName()); if (clone.IsNULL()) { std::cerr << "INTERNAL ERROR in Component::LightCloneInternal(): " "could not clone a '" << GetClassName() << "'\n"; throw std::exception(); } // Copy the value of each state variable to the clone: StateVariableMap::const_iterator varIt = m_stateVariables.begin(); for ( ; varIt != m_stateVariables.end(); ++varIt) { const string& varName = varIt->first; const StateVariable& variable = varIt->second; StateVariableMap::iterator cloneVarIt = clone->m_stateVariables.find(varName); if (cloneVarIt == clone->m_stateVariables.end()) { std::cerr << "INTERNAL ERROR in Component::LightCloneInternal(): " "could not copy variable " << varName << "'s " << " value to the clone: clone is missing" " this variable?\n"; throw std::exception(); } // Skip custom variables: if (variable.GetType() == StateVariable::Custom) continue; if (!(cloneVarIt->second).CopyValueFrom(variable)) { std::cerr << "INTERNAL ERROR in Component::LightCloneInternal(): " "could not copy variable " << varName << "'s " << " value to the clone.\n"; throw std::exception(); } } for (Components::const_iterator it = m_childComponents.begin(); it != m_childComponents.end(); ++it) { refcount_ptr child = (*it)->LightCloneInternal(); if (child.IsNULL()) { std::cerr << "INTERNAL ERROR in Component::LightCloneInternal(): " "could not clone child of class '" << (*it)->GetClassName() << "'\n"; throw std::exception(); } else { clone->AddChild(child); } } return clone; } const refcount_ptr Component::LightClone() const { return LightCloneInternal(); } void Component::DetectChanges(const refcount_ptr& oldClone, ostream& changeMessages) const { // Recursively look for changes in state. Compare the // oldClone component with this component first. if (oldClone->GetClassName() != GetClassName()) { changeMessages << oldClone->GenerateShortestPossiblePath() << " changed class from " << oldClone->GetClassName() << " to " << GetClassName() << "?\n"; return; } // Compare all state variables: StateVariableMap::const_iterator varIt = m_stateVariables.begin(); for ( ; varIt != m_stateVariables.end(); ++varIt) { const string& varName = varIt->first; // Don't output "step" changes, because they happen all // the time for all executable components. if (varName == "step") continue; const StateVariable& variable = varIt->second; const StateVariable* oldVariable = oldClone->GetVariable(varName); // NOTE: Custom types have a nonsense tostring, which // usually just says "(custom)" or something, so they // are quickly compared. // TODO: In the future, maybe RAM components and such (i.e. // custom data types) can be lazily reference counted or // similar, to detect changes in RAM as well. string var = variable.ToString(); string varOld = oldVariable->ToString(); if (var != varOld) changeMessages << "=> " << GenerateShortestPossiblePath() << "." << varName << ": " << varOld << " -> " << var << "\n"; } // Compare all children. const Components& oldChildren = oldClone->GetChildren(); for (size_t i = 0; i < m_childComponents.size(); ++ i) { string myName = m_childComponents[i]->GetVariable("name")->ToString(); // Find the corresponding child component in the oldClone: size_t j; bool found = false; for (j=0; jGetVariable("name")->ToString() == myName) { m_childComponents[i]->DetectChanges(oldChildren[j], changeMessages); found = true; break; } if (!found) changeMessages << m_childComponents[i]-> GenerateShortestPossiblePath() << " (appeared)\n"; } // ... and see if any disappeared (i.e. were in the old clone, // but not in the current tree): for (size_t j=0; jGetVariable("name")->ToString(); bool found = false; for (size_t k=0; kGetVariable("name")->ToString(); if (newName == oldName) { found = true; break; } } if (!found) changeMessages << oldChildren[j]-> GenerateShortestPossiblePath() << " (disappeared)\n"; } } void Component::Reset() { ResetState(); // Recurse: for (size_t i = 0; i < m_childComponents.size(); ++ i) m_childComponents[i]->Reset(); } void Component::ResetState() { // Base implementation. m_step = 0; } bool Component::PreRunCheck(GXemul* gxemul) { bool everythingOk = PreRunCheckForComponent(gxemul); // Recurse: for (size_t i = 0; i < m_childComponents.size(); ++ i) everythingOk &= m_childComponents[i]->PreRunCheck(gxemul); return everythingOk; } bool Component::PreRunCheckForComponent(GXemul* gxemul) { // Base implementation: Do nothing. Everything is Ok. return true; } void Component::FlushCachedState() { FlushCachedStateForComponent(); // Recurse: for (size_t i = 0; i < m_childComponents.size(); ++ i) m_childComponents[i]->FlushCachedState(); } void Component::FlushCachedStateForComponent() { // Base implementation: Do nothing. } int Component::Execute(GXemul* gxemul, int nrOfCycles) { // Base implementation: Do nothing, but pretend we executed // the instructions. Actual components that inherit from this // class should of course _do_ something here. return nrOfCycles; } double Component::GetCurrentFrequency() const { // The base component does not run at any frequency. Only components // that actually run something "per cycle" should return values // greater than 0.0. return 0.0; } RootComponent* Component::AsRootComponent() { // Default implementation (the base Component class) is not a RootComponent. return NULL; } CPUComponent* Component::AsCPUComponent() { // Default implementation (the base Component class) is not a CPU. return NULL; } AddressDataBus* Component::AsAddressDataBus() { // Default implementation (the base Component class) is not an // address data bus. return NULL; } void Component::SetParent(Component* parentComponent) { m_parentComponent = parentComponent; } Component* Component::GetParent() { return m_parentComponent; } const Component* Component::GetParent() const { return m_parentComponent; } void Component::GetMethodNames(vector& names) const { // The default component has no implemented methods. } bool Component::MethodMayBeReexecutedWithoutArgs(const string& methodName) const { // By default, methods are _not_ re-executable without args. return false; } void Component::ExecuteMethod(GXemul* gxemul, const string& methodName, const vector& arguments) { std::cerr << "Internal error: someone tried to execute " "method '" << methodName << "' on the Component base" " class. Perhaps you are missing an override?\n"; throw std::exception(); } string Component::GenerateDetails() const { stringstream ss; // If this component has a "model", then show that. const StateVariable* model = GetVariable("model"); if (model != NULL && !model->ToString().empty()) { if (!ss.str().empty()) ss << ", "; ss << model->ToString(); } // If this component has a frequency (i.e. it is runnable), then // show the frequency: double freq = GetCurrentFrequency(); if (freq != 0.0) { if (!ss.str().empty()) ss << ", "; if (freq >= 1e9) ss << freq/1e9 << " GHz"; else if (freq >= 1e6) ss << freq/1e6 << " MHz"; else if (freq >= 1e3) ss << freq/1e3 << " kHz"; else ss << freq << " Hz"; } const StateVariable* paused = GetVariable("paused"); // TODO: ToBool :) if (paused != NULL && paused->ToInteger() > 0) { if (!ss.str().empty()) ss << ", "; ss << "paused"; } return ss.str(); } string Component::GenerateTreeDump(const string& branchTemplate, bool htmlLinksForClassNames, string prefixForComponentUrls) const { // This generates an ASCII string which looks like: // // root // |-- child1 // | |-- child1's child1 // | \-- child1's child2 // \-- child2 // \-- child2's child string branch; for (size_t pos=0; posToString().empty()) name = value->ToString(); string str = branch; if (htmlLinksForClassNames) { // See if this class name has its own HTML page. std::ifstream documentationComponentFile(( "doc/components/component_" + className + ".html").c_str()); if (documentationComponentFile.is_open()) str += "" + name + ""; else str += name; } else { str += name; } // If this component was created by a template, then show the template // type in [ ]. const StateVariable* templateName; if ((templateName = GetVariable("template")) != NULL && !templateName->ToString().empty()) { string tName = templateName->ToString(); str += " ["; if (htmlLinksForClassNames) { // See if this class/template name has its own HTML page. // (Usually machines. TODO: also other components.) std::ifstream documentationMachineFile(( "doc/machines/machine_" + tName + ".html").c_str()); if (documentationMachineFile.is_open()) str += "" + tName + ""; else str += tName; } else { str += tName; } str += "]"; } // Get any additional details (CPU model, memory mapped address, etc.): string details = GenerateDetails(); if (!details.empty()) str += " (" + details + ")"; // Show the branch of the tree... string result = " " + str + "\n"; // ... and recurse to show children, if there are any: const Components& children = GetChildren(); for (size_t i=0, n=children.size(); iGenerateTreeDump(subBranch, htmlLinksForClassNames, prefixForComponentUrls); } return result; } GXemul* Component::GetRunningGXemulInstance() { Component* root = this; while (root->GetParent() != NULL) root = root->GetParent(); RootComponent* rootComponent = root->AsRootComponent(); if (rootComponent == NULL) return NULL; return rootComponent->GetOwner(); } UI* Component::GetUI() { GXemul* gxemul = GetRunningGXemulInstance(); if (gxemul == NULL) return NULL; // TODO: Return NULL if the UI has debug messages turned off. return gxemul->GetUI(); } void Component::AddChild(refcount_ptr childComponent, size_t insertPosition) { if (insertPosition == (size_t) -1) { insertPosition = m_childComponents.size(); m_childComponents.push_back(childComponent); } else { m_childComponents.insert( m_childComponents.begin() + insertPosition, childComponent); } // A component cannot have two parents. assert(childComponent->GetParent() == NULL); childComponent->SetParent(this); // Make sure that the child's "name" state variable is unique among // all children of this component. (Yes, this is O(n^2) and it may // need to be rewritten to cope with _lots_ of components.) size_t postfix = 0; bool collision = false; do { const StateVariable* name = childComponent->GetVariable("name"); if (name->ToString().empty() || collision) { // Set the default name: // visibleclassname + postfix number stringstream ss; ss << childComponent->GetVisibleClassName() << postfix; EscapedString escaped(ss.str()); childComponent->SetVariableValue("name", escaped.Generate()); name = childComponent->GetVariable("name"); } collision = false; for (size_t i=0; iGetVariable("name"); if (otherName != NULL) { if (name->ToString() == otherName->ToString()) { collision = true; ++ postfix; break; } } else { // Hm. All components should have a "name". assert(false); } } } while (collision); } size_t Component::RemoveChild(Component* childToRemove) { size_t index = 0; for (Components::iterator it = m_childComponents.begin(); it != m_childComponents.end(); ++it, ++index) { if (childToRemove == (*it)) { childToRemove->SetParent(NULL); m_childComponents.erase(it); return index; } } // Child not found? Should not happen. assert(false); return (size_t) -1; } Components& Component::GetChildren() { return m_childComponents; } const Components& Component::GetChildren() const { return m_childComponents; } string Component::GeneratePath() const { string path = GetVariable("name")->ToString(); if (path.empty()) path = "(" + GetClassName() + ")"; if (m_parentComponent != NULL) path = m_parentComponent->GeneratePath() + "." + path; return path; } static vector SplitPathStringIntoVector(const string &path) { // Split the path into a vector. This is slow and hackish, but works. vector pathStrings; string word; for (size_t i=0, n=path.length(); i allComponentPaths; const Component* root = this; while (root->GetParent() != NULL) root = root->GetParent(); root->AddAllComponentPaths(allComponentPaths); // Include as few as possible sub-parts of myPath (starting from the // end), to uniqely identify the component. vector myPathParts = SplitPathStringIntoVector(myPath); for (size_t n=1; n<=myPathParts.size(); ++n) { string attempt = ""; for (size_t i=myPathParts.size()-n; i 0) attempt += "."; attempt += myPathParts[i]; } // std::cerr << "attempt = " << attempt << "\n"; // attempt = ram0 // attempt = mainbus0.ram0 // attempt = machine0.mainbus0.ram0 // etc. // See if this substring is unique in allComponentPaths. int nHits = 0; string dotAttempt = "." + attempt; size_t dotAttemptLength = dotAttempt.length(); for (size_t j=0; j dotAttemptLength && s.substr(s.length() - dotAttemptLength, dotAttemptLength) == dotAttempt) nHits ++; } // Unique? Then we found a good short path. if (nHits == 1) return attempt; // Otherwise continue. } // Worst case: return full path. return myPath; } const refcount_ptr Component::LookupPath(string path) const { // Trim whitespace while (path.length() > 0 && path[path.length() - 1] == ' ') path = path.substr(0, path.length() - 1); refcount_ptr component = LookupPath(SplitPathStringIntoVector(path), 0); if (component.IsNULL()) { // Maybe it was a path starting from somewhere other than the // root. That is, if we find "." + path in the list of all // components' full names exactly 1 time, then we return that. vector allComponentPaths; AddAllComponentPaths(allComponentPaths); const Component* root = this; while (root->GetParent() != NULL) root = root->GetParent(); int nMatches = 0; string strToFind = "." + path; for (size_t i=0, n=allComponentPaths.size(); i strToFind.length()) { string subs = allComponentPaths[i].substr( allComponentPaths[i].length() - strToFind.length()); if (strToFind == subs) { nMatches ++; component = root->LookupPath(allComponentPaths[i]); } } } if (nMatches != 1) return NULL; } return component; } const refcount_ptr Component::LookupPath(const vector& path, size_t index) const { refcount_ptr component; if (index > path.size()) { // Huh? Lookup of empty path? Should not usually happen. assert(false); return component; } StateVariableMap::const_iterator it = m_stateVariables.find("name"); if (it == m_stateVariables.end()) { // Failure (return NULL) if we don't have a name. return component; } string nameOfThisComponent = (it->second).ToString(); bool match = (path[index] == nameOfThisComponent); // No match? Or was it the last part of the path? Then return. if (!match || index == path.size() - 1) { // (Successfully, if there was a match.) if (match) return const_cast(this); return component; } // If there are still parts left to check, look among all the children: const string& pathPartToLookup = path[index+1]; for (size_t i=0, n=m_childComponents.size(); iGetVariable("name"); if (childName != NULL) { if (childName->ToString() == pathPartToLookup) { component = m_childComponents[i]-> LookupPath(path, index+1); break; } } } return component; } void Component::AddAllComponentPaths(vector& allComponentPaths) const { // Add the component itself first: allComponentPaths.push_back(GeneratePath()); // Then all children: for (size_t i=0, n=m_childComponents.size(); iAddAllComponentPaths(allComponentPaths); } static bool PartialMatch(const string& partialPath, const string& path) { if (partialPath.empty()) return true; const size_t partialPathLength = partialPath.length(); const size_t pathLength = path.length(); size_t pathPos = 0; do { // Partial path too long? Then abort immediately. if (partialPathLength + pathPos > pathLength) break; // A substring match? Then we might have found it. if (path.substr(pathPos, partialPathLength) == partialPath) { // If the path has no tail (".subcomponent"), then // we found it: if (path.find('.', pathPos + partialPathLength) == string::npos) return true; } // Find next place in path to test: do { pathPos ++; } while (pathPos < pathLength && path[pathPos] != '.'); if (pathPos < pathLength) pathPos ++; } while (pathPos < pathLength); return false; } vector Component::FindPathByPartialMatch( const string& partialPath, bool shortestPossible) const { vector allComponentPaths; vector matches; AddAllComponentPaths(allComponentPaths); for (size_t i=0, n=allComponentPaths.size(); iGetParent() != NULL) root = root->GetParent(); refcount_ptr component = root->LookupPath(match); match = component->GenerateShortestPossiblePath(); } matches.push_back(match); } return matches; } void Component::GetVariableNames(vector& names) const { for (StateVariableMap::const_iterator it = m_stateVariables.begin(); it != m_stateVariables.end(); ++it) names.push_back(it->first); } StateVariable* Component::GetVariable(const string& name) { StateVariableMap::iterator it = m_stateVariables.find(name); if (it == m_stateVariables.end()) return NULL; else return &(it->second); } const StateVariable* Component::GetVariable(const string& name) const { StateVariableMap::const_iterator it = m_stateVariables.find(name); if (it == m_stateVariables.end()) return NULL; else return &(it->second); } bool Component::CheckVariableWrite(StateVariable& var, const string& oldValue) { GXemul* gxemul = GetRunningGXemulInstance(); UI* ui = GetUI(); if (gxemul != NULL) { const string& name = var.GetName(); if (name == "step") { // If we are the root component, then writing to step // has special meaning: if (GetParent() == NULL) { bool error = false; int64_t oldStep = StringHelper::ParseNumber(oldValue.c_str(), error); int64_t newStep = var.ToInteger(); // 0. Value is the same as before. Simply return. if (newStep == oldStep) return true; // 1. The new value is too low (less than 0). if (newStep < 0) { if (ui != NULL) ui->ShowDebugMessage("root.step can" " not be set to lower than zero.\n"); return false; } // 2. The value is lower; run backwards if possible. if (newStep < oldStep) { if (!gxemul->GetSnapshottingEnabled()) { if (ui != NULL) ui->ShowDebugMessage("root.step can" " not be decreased; snapshotting" " was not enabled prior to\nstarting" " the emulation. (-B command line" " option.)\n"); return false; } return gxemul->ModifyStep(oldStep, newStep); } // 3. The value is higher; run forwards. return gxemul->ModifyStep(oldStep, newStep); } else { // We are not the root component. Direct (interactive) // writes to the step variable is not allowed. if (ui != NULL) ui->ShowDebugMessage("The step variable of " "this component cannot be set manually.\n"); } return false; } } return true; } bool Component::SetVariableValue(const string& name, const string& expression) { UI* ui = GetUI(); StateVariableMap::iterator it = m_stateVariables.find(name); if (it == m_stateVariables.end()) { if (ui != NULL) ui->ShowDebugMessage((string) name + ": no such variable\n"); return false; } StateVariable& var = it->second; stringstream oldValue; var.SerializeValue(oldValue); bool success = var.SetValue(expression); if (!success) { if (ui != NULL) ui->ShowDebugMessage((string) name + ": expression could" " not be assigned; type mismatch?\n"); return false; } stringstream newValue; var.SerializeValue(newValue); if (oldValue.str() != newValue.str()) { success = CheckVariableWrite(var, oldValue.str()); if (!success) { // Revert to the previous: var.SetValue(oldValue.str()); return false; } } return true; } void Component::Serialize(ostream& ss, SerializationContext& context) const { SerializationContext subContext = context.Indented(); string tabs = context.Tabs(); ss << tabs << "component " << m_className << "\n" << tabs << "{\n"; for (StateVariableMap::const_iterator it = m_stateVariables.begin(); it != m_stateVariables.end(); ++it) (it->second).Serialize(ss, subContext); for (size_t i = 0, n = m_childComponents.size(); i < n; ++ i) m_childComponents[i]->Serialize(ss, subContext); ss << tabs << "}\n"; } static bool GetNextToken(const string& str, size_t& pos, string& token) { token = ""; size_t len = str.length(); // Skip initial whitespace: while (pos < len && (str[pos] == ' ' || str[pos] == '\t' || str[pos] == '\r' || str[pos] == '\n')) ++ pos; if (pos >= len) return false; // Get the token, until end-of-string or until whitespace is found: bool quoted = false; do { char ch = str[pos]; if (!quoted) { if (ch == '"') quoted = true; if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') break; token += ch; } else { if (ch == '"') quoted = false; token += ch; if (ch == '\\' && pos < len-1) token += str[++pos]; } ++ pos; } while (pos < len); return true; } refcount_ptr Component::Deserialize(ostream& messages, const string& str, size_t& pos) { refcount_ptr deserializedTree = NULL; string token; if (!GetNextToken(str, pos, token) || token != "component") { messages << "Expecting \"component\".\n"; return deserializedTree; } string className; if (!GetNextToken(str, pos, className)) { messages << "Expecting a class name.\n"; return deserializedTree; } if (!GetNextToken(str, pos, token) || token != "{") { messages << "Expecting {.\n"; return deserializedTree; } // root is a special case (cannot be created by the factory). All other // class types should be possible to create using the factory. if (className == "root") { deserializedTree = new RootComponent; } else { deserializedTree = ComponentFactory::CreateComponent(className); if (deserializedTree.IsNULL()) { messages << "Could not create a '" << className << "' component.\n"; return deserializedTree; } } while (pos < str.length()) { size_t savedPos = pos; // Either 1) } (end of current component) // or 2) component name { ... // or 3) variableType name "value" if (!GetNextToken(str, pos, token)) { // Failure. messages << "Failure. (0)\n"; deserializedTree = NULL; break; } // Case 1: if (token == "}") break; string name; if (!GetNextToken(str, pos, name)) { // Failure. messages << "Failure. (1)\n"; deserializedTree = NULL; break; } if (token == "component") { // Case 2: refcount_ptr child = Component::Deserialize(messages, str, savedPos); if (child.IsNULL()) { // Failure. messages << "Failure. (2)\n"; deserializedTree = NULL; break; } deserializedTree->AddChild(child); pos = savedPos; } else { // Case 3: string varType = token; string varValue; if (!GetNextToken(str, pos, varValue)) { // Failure. messages << "Failure. (3)\n"; deserializedTree = NULL; break; } if (!deserializedTree->SetVariableValue(name, varValue)) { messages << "Warning: variable '" << name << "' for component class " << className << " could not be deserialized; skipping.\n"; } } } return deserializedTree; } bool Component::CheckConsistency() const { // Serialize SerializationContext context; stringstream ss; Serialize(ss, context); string result = ss.str(); Checksum checksumOriginal; AddChecksum(checksumOriginal); // Deserialize size_t pos = 0; stringstream messages; refcount_ptr tmpDeserializedTree = Deserialize(messages, result, pos); if (tmpDeserializedTree.IsNULL()) return false; Checksum checksumDeserialized; tmpDeserializedTree->AddChecksum(checksumDeserialized); // ... and compare the checksums: return checksumOriginal == checksumDeserialized; } void Component::AddChecksum(Checksum& checksum) const { // Some random stuff is added between normal fields to the checksum. // This is to make it harder to get the same checksum for two different // objects, that just have some fields swapped, or such. (Yes, I know, // that is not a very scientific explanation :) but it will have to do.) checksum.Add(((uint64_t) 0x12491725 << 32) | 0xabcef011); checksum.Add(m_className); SerializationContext dummyContext; // Add all state variables. for (StateVariableMap::const_iterator it = m_stateVariables.begin(); it != m_stateVariables.end(); ++ it) { checksum.Add(((uint64_t) 0x019fb879 << 32) | 0x25addae1); stringstream ss; (it->second).Serialize(ss, dummyContext); checksum.Add(ss.str()); } // Add all child components. for (size_t i = 0; i < m_childComponents.size(); ++ i) { checksum.Add((((uint64_t) 0xf98a7c7c << 32) | 0x109f0000) + i * 0x98127417); m_childComponents[i]->AddChecksum(checksum); } checksum.Add(((uint64_t) 0x90a10224 << 32) | 0x97defa7a); } gxemul-0.6.1/src/main/fileloaders/000755 001750 001750 00000000000 13402411502 017231 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/main/StateVariable.cc000644 001750 001750 00000055601 13402411502 020004 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "EscapedString.h" #include "StateVariable.h" #include "StringHelper.h" StateVariable::StateVariable(const string& name, string* ptrToString) : m_name(name) , m_type(String) { m_value.pstr = ptrToString; } StateVariable::StateVariable(const string& name, bool* ptrToVar) : m_name(name) , m_type(Bool) { m_value.pbool = ptrToVar; } StateVariable::StateVariable(const string& name, double* ptrToVar) : m_name(name) , m_type(Double) { m_value.pdouble = ptrToVar; } StateVariable::StateVariable(const string& name, uint8_t* ptrToVar) : m_name(name) , m_type(UInt8) { m_value.puint8 = ptrToVar; } StateVariable::StateVariable(const string& name, uint16_t* ptrToVar) : m_name(name) , m_type(UInt16) { m_value.puint16 = ptrToVar; } StateVariable::StateVariable(const string& name, uint32_t* ptrToVar) : m_name(name) , m_type(UInt32) { m_value.puint32 = ptrToVar; } StateVariable::StateVariable(const string& name, uint64_t* ptrToVar) : m_name(name) , m_type(UInt64) { m_value.puint64 = ptrToVar; } StateVariable::StateVariable(const string& name, int8_t* ptrToVar) : m_name(name) , m_type(SInt8) { m_value.psint8 = ptrToVar; } StateVariable::StateVariable(const string& name, int16_t* ptrToVar) : m_name(name) , m_type(SInt16) { m_value.psint16 = ptrToVar; } StateVariable::StateVariable(const string& name, int32_t* ptrToVar) : m_name(name) , m_type(SInt32) { m_value.psint32 = ptrToVar; } StateVariable::StateVariable(const string& name, int64_t* ptrToVar) : m_name(name) , m_type(SInt64) { m_value.psint64 = ptrToVar; } StateVariable::StateVariable(const string& name, CustomStateVariableHandler* ptrToHandler) : m_name(name) , m_type(Custom) { m_value.phandler = ptrToHandler; } enum StateVariable::Type StateVariable::GetType() const { return m_type; } const string& StateVariable::GetName() const { return m_name; } string StateVariable::GetTypeString() const { switch (m_type) { case String: return "string"; case Bool: return "bool"; case Double: return "double"; case UInt8: return "uint8"; case UInt16: return "uint16"; case UInt32: return "uint32"; case UInt64: return "uint64"; case SInt8: return "sint8"; case SInt16: return "sint16"; case SInt32: return "sint32"; case SInt64: return "sint64"; case Custom: return "custom"; default: return "unknown"; } } bool StateVariable::CopyValueFrom(const StateVariable& otherVariable) { if (m_type != otherVariable.m_type) return false; switch (m_type) { case String: *m_value.pstr = *otherVariable.m_value.pstr; break; case Bool: *m_value.pbool = *otherVariable.m_value.pbool; break; case Double: *m_value.pdouble = *otherVariable.m_value.pdouble; break; case UInt8: *m_value.puint8 = *otherVariable.m_value.puint8; break; case UInt16: *m_value.puint16 = *otherVariable.m_value.puint16; break; case UInt32: *m_value.puint32 = *otherVariable.m_value.puint32; break; case UInt64: *m_value.puint64 = *otherVariable.m_value.puint64; break; case SInt8: *m_value.psint8 = *otherVariable.m_value.psint8; break; case SInt16: *m_value.psint16 = *otherVariable.m_value.psint16; break; case SInt32: *m_value.psint32 = *otherVariable.m_value.psint32; break; case SInt64: *m_value.psint64 = *otherVariable.m_value.psint64; break; case Custom: m_value.phandler->CopyValueFrom(otherVariable.m_value.phandler); break; default: // Unknown type? assert(false); return false; } return true; } string StateVariable::ToString() const { stringstream sstr; switch (m_type) { case String: return m_value.pstr == NULL? "" : *m_value.pstr; case Bool: sstr << (*m_value.pbool? "true" : "false"); return sstr.str(); case Double: sstr << *m_value.pdouble; return sstr.str(); case UInt8: sstr << (int) *m_value.puint8; return sstr.str(); case UInt16: sstr.flags(std::ios::hex | std::ios::showbase); sstr << *m_value.puint16; return sstr.str(); case UInt32: sstr.flags(std::ios::hex | std::ios::showbase); sstr << *m_value.puint32; return sstr.str(); case UInt64: sstr.flags(std::ios::hex | std::ios::showbase); sstr << *m_value.puint64; return sstr.str(); case SInt8: sstr << (int) *m_value.psint8; return sstr.str(); case SInt16: sstr << *m_value.psint16; return sstr.str(); case SInt32: sstr << *m_value.psint32; return sstr.str(); case SInt64: sstr << *m_value.psint64; return sstr.str(); case Custom: return "(custom)"; } // Unimplemented type? assert(false); return ""; } uint64_t StateVariable::ToInteger() const { switch (m_type) { case String: { uint64_t tmp; stringstream ss; ss << *m_value.pstr; ss >> tmp; return tmp; } case Bool: return (*m_value.pbool)? 1 : 0; case Double: return (uint64_t) *m_value.pdouble; case UInt8: return *m_value.puint8; case UInt16: return *m_value.puint16; case UInt32: return *m_value.puint32; case UInt64: return *m_value.puint64; case SInt8: return *m_value.psint8; case SInt16: return *m_value.psint16; case SInt32: return *m_value.psint32; case SInt64: return *m_value.psint64; case Custom: return 0; } // Unimplemented type. Let's abort. std::cerr << "StateVariable::ToDouble(): Unimplemented type.\n"; throw std::exception(); } double StateVariable::ToDouble() const { switch (m_type) { case String: { double tmp; stringstream ss; ss << *m_value.pstr; ss >> tmp; return tmp; } case Bool: return (*m_value.pbool)? 1.0 : 0.0; case Double: return *m_value.pdouble; case UInt8: return *m_value.puint8; case UInt16: return *m_value.puint16; case UInt32: return *m_value.puint32; case UInt64: return *m_value.puint64; case SInt8: return *m_value.psint8; case SInt16: return *m_value.psint16; case SInt32: return *m_value.psint32; case SInt64: return *m_value.psint64; case Custom: return 0.0; } // Unimplemented type. Let's abort. std::cerr << "StateVariable::ToDouble(): Unimplemented type.\n"; throw std::exception(); } void StateVariable::SerializeValue(ostream& ss) const { switch (m_type) { case String: { EscapedString escaped(ToString()); ss << escaped.Generate(); } break; case Custom: m_value.phandler->Serialize(ss); break; default: ss << ToString(); } } void StateVariable::Serialize(ostream& ss, SerializationContext& context) const { ss << context.Tabs() << GetTypeString() << " " << m_name + " "; SerializeValue(ss); ss << "\n"; } string StateVariable::EvaluateExpression(const string& expression, bool& success) const { success = false; string result = expression; // Remove leading and trailing spaces: while (result.size() > 0 && result[0] == ' ') result.erase((size_t) 0); while (result.size() > 0 && result[result.size() - 1] == ' ') result.erase(result.size()-1); // TODO success = true; return result; return ""; } bool StateVariable::SetValue(const string& expression) { // Nothing to assign to? if (m_value.pstr == NULL) return false; // Reduce the expression to a single value. bool success = false; string value = EvaluateExpression(expression, success); if (!success) return false; switch (m_type) { case String: { success = false; string newStr = EscapedString(value).Decode(success); if (success) *m_value.pstr = newStr; else return false; } return true; case Bool: { if (value == "true") *m_value.pbool = true; else if (value == "false") *m_value.pbool = false; else return false; } return true; case Double: { double doubleTmp; stringstream sstr; sstr << value; sstr >> doubleTmp; if (isnan(doubleTmp) || isinf(doubleTmp)) return false; *m_value.pdouble = doubleTmp; } return true; case UInt8: { bool error = true; uint64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); uint8_t tmp = tmp64; if (tmp == tmp64 && !error) *m_value.puint8 = tmp; else return false; } return true; case UInt16: { bool error = true; uint64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); uint16_t tmp = tmp64; if (tmp == tmp64 && !error) *m_value.puint16 = tmp; else return false; } return true; case UInt32: { bool error = true; uint64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); uint32_t tmp = tmp64; if (tmp == tmp64 && !error) *m_value.puint32 = tmp; else return false; } return true; case UInt64: { bool error = true; uint64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); if (!error) *m_value.puint64 = tmp64; else return false; } return true; case SInt8: { bool error = true; int64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); int8_t tmp = tmp64; if (tmp == tmp64 && !error) *m_value.psint8 = tmp; else return false; } return true; case SInt16: { bool error = true; int64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); int16_t tmp = tmp64; if (tmp == tmp64 && !error) *m_value.psint16 = tmp; else return false; } return true; case SInt32: { bool error = true; int64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); int32_t tmp = tmp64; if (tmp == tmp64 && !error) *m_value.psint32 = tmp; else return false; } return true; case SInt64: { bool error = true; int64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); if (!error) *m_value.psint64 = tmp64; else return false; } return true; case Custom: return m_value.phandler->Deserialize(value); default: // Unimplemented type. Let's abort. std::cerr << "StateVariable::SetValue: Unimplemented type.\n"; throw std::exception(); } } bool StateVariable::SetValue(uint64_t value) { // Nothing to assign to? if (m_value.pstr == NULL) return false; switch (m_type) { case String: { stringstream ss; ss << value; *m_value.pstr = ss.str(); } return true; case Bool: *m_value.pbool = value != 0; return true; case Double: *m_value.pdouble = value; return true; case UInt8: *m_value.puint8 = value; return true; case UInt16: *m_value.puint16 = value; return true; case UInt32: *m_value.puint32 = value; return true; case UInt64: *m_value.puint64 = value; return true; case SInt8: *m_value.psint8 = value; return true; case SInt16: *m_value.psint16 = value; return true; case SInt32: *m_value.psint32 = value; return true; case SInt64: *m_value.psint64 = value; return true; case Custom: return false; default: // Unimplemented type. Let's abort. std::cerr << "StateVariable::SetValue: Unimplemented type.\n"; throw std::exception(); } } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_StateVariable_String_Construct() { string myString = "hi"; StateVariable var("hello", &myString); UnitTest::Assert("name should be hello", var.GetName(), "hello"); UnitTest::Assert("type should be String", var.GetType() == StateVariable::String); UnitTest::Assert("value should be hi", var.ToString(), "hi"); } static void Test_StateVariable_String_SetValue() { string myString = "hi"; StateVariable var("hello", &myString); UnitTest::Assert("setting string value without quotes should not work", var.SetValue("value2") == false); UnitTest::Assert("setting string value with quotes should work", var.SetValue("\"value2\"") == true); UnitTest::Assert("type should still be String", var.GetType() == StateVariable::String); UnitTest::Assert("value should now be value2", var.ToString(), "value2"); UnitTest::Assert("myString should have been updated", myString, "value2"); } static void Test_StateVariable_String_CopyValueFrom() { string myString1 = "hi"; string myString2 = "something"; StateVariable var1("hello", &myString1); StateVariable var2("world", &myString2); UnitTest::Assert("value should initially be hi", var1.ToString(), "hi"); var1.CopyValueFrom(var2); UnitTest::Assert("name should still be hello", var1.GetName(), "hello"); UnitTest::Assert("type should still be String", var1.GetType() == StateVariable::String); UnitTest::Assert("value should be changed to something", var1.ToString(), "something"); UnitTest::Assert("myString1 should have been updated", myString1, "something"); } static void Test_StateVariable_String_Serialize() { string hi = "value world"; StateVariable var("hello", &hi); SerializationContext dummyContext; stringstream ss; var.Serialize(ss, dummyContext); UnitTest::Assert("variable serialization mismatch?", ss.str(), "string hello \"value world\"\n"); } static void Test_StateVariable_String_Serialize_WithEscapes() { string s = "a\\b\tc\nd\re\bf\"g'h"; StateVariable var("hello", &s); SerializationContext dummyContext; stringstream ss; var.Serialize(ss, dummyContext); UnitTest::Assert("variable serialization mismatch?", ss.str(), "string hello " + EscapedString(s).Generate() + "\n"); } static void Test_StateVariable_Bool_Construct() { bool myBool = true; StateVariable var("hello", &myBool); UnitTest::Assert("name should be hello", var.GetName(), "hello"); UnitTest::Assert("type should be Bool", var.GetType() == StateVariable::Bool); UnitTest::Assert("value should be true", var.ToString(), "true"); } static void Test_StateVariable_Bool_SetValue() { bool myBool = true; StateVariable var("hello", &myBool); UnitTest::Assert("changing to false should be possible", var.SetValue("false") == true); UnitTest::Assert("type should still be Bool", var.GetType() == StateVariable::Bool); UnitTest::Assert("value should now be changed", var.ToString(), "false"); UnitTest::Assert("myBool should have been updated", myBool == false); UnitTest::Assert("changing to true should be possible", var.SetValue("true") == true); UnitTest::Assert("value should now be changed again", var.ToString(), "true"); UnitTest::Assert("myBool should have been updated again", myBool == true); UnitTest::Assert("changing to non-bool value should not be possible", var.SetValue("hello") == false); UnitTest::Assert("value should not be changed", var.ToString(), "true"); } static void Test_StateVariable_Bool_CopyValueFrom() { bool myBool1 = false; bool myBool2 = true; StateVariable var1("hello", &myBool1); StateVariable var2("world", &myBool2); UnitTest::Assert("copying from bool to bool should be possible", var1.CopyValueFrom(var2) == true); UnitTest::Assert("name should still be hello", var1.GetName(), "hello"); UnitTest::Assert("type should still be Bool", var1.GetType() == StateVariable::Bool); UnitTest::Assert("value should be changed to true", var1.ToString(), "true"); UnitTest::Assert("myBool1 should have been updated", myBool1 == true); string myString = "hm"; StateVariable var3("test", &myString); UnitTest::Assert("copying from string to bool should not be possible", var1.CopyValueFrom(var3) == false); } static void Test_StateVariable_Bool_Serialize() { bool myBool = true; StateVariable var("hello", &myBool); SerializationContext dummyContext; stringstream ss; var.Serialize(ss, dummyContext); UnitTest::Assert("variable serialization mismatch (1)", ss.str(), "bool hello true\n"); myBool = false; stringstream ss2; var.Serialize(ss2, dummyContext); UnitTest::Assert("variable serialization mismatch (2)", ss2.str(), "bool hello false\n"); } static void Test_StateVariable_Numeric_Construct() { double varDouble = -12.345; uint8_t varUInt8 = 223; uint16_t varUInt16 = 55000; uint32_t varUInt32 = 3000000001UL; uint64_t varUInt64 = ((uint64_t) 0xfedc0102 << 32) | 0x03040506; int8_t varSInt8 = -120; int16_t varSInt16 = -22000; int32_t varSInt32 = -1000000001; int64_t varSInt64 = ((uint64_t) 0xfedc0102 << 32) | 0x03040506; StateVariable vdouble("vdouble", &varDouble); StateVariable vuint8 ("vuint8", &varUInt8); StateVariable vuint16("vuint16", &varUInt16); StateVariable vuint32("vuint32", &varUInt32); StateVariable vuint64("vuint64", &varUInt64); StateVariable vsint8 ("vsint8", &varSInt8); StateVariable vsint16("vsint16", &varSInt16); StateVariable vsint32("vsint32", &varSInt32); StateVariable vsint64("vsint64", &varSInt64); // Types UnitTest::Assert("Double", vdouble.GetType() == StateVariable::Double); UnitTest::Assert("UInt8", vuint8.GetType() == StateVariable::UInt8); UnitTest::Assert("UInt16", vuint16.GetType() == StateVariable::UInt16); UnitTest::Assert("UInt32", vuint32.GetType() == StateVariable::UInt32); UnitTest::Assert("UInt64", vuint64.GetType() == StateVariable::UInt64); UnitTest::Assert("SInt8", vsint8.GetType() == StateVariable::SInt8); UnitTest::Assert("SInt16", vsint16.GetType() == StateVariable::SInt16); UnitTest::Assert("SInt32", vsint32.GetType() == StateVariable::SInt32); UnitTest::Assert("SInt64", vsint64.GetType() == StateVariable::SInt64); // Values UnitTest::Assert("value Double", vdouble.ToString(), "-12.345"); UnitTest::Assert("value UInt8", vuint8.ToString(), "223"); UnitTest::Assert("value UInt16", vuint16.ToString(), "0xd6d8"); UnitTest::Assert("value UInt32", vuint32.ToString(), "0xb2d05e01"); UnitTest::Assert("value UInt64", vuint64.ToString(), "0xfedc010203040506"); UnitTest::Assert("value SInt8", vsint8.ToString(), "-120"); UnitTest::Assert("value SInt16", vsint16.ToString(), "-22000"); UnitTest::Assert("value SInt32", vsint32.ToString(), "-1000000001"); UnitTest::Assert("value SInt64", vsint64.ToString(), "-82189585047354106"); } static void Test_StateVariable_Numeric_SetValue() { double varDouble = -12.345; uint8_t varUInt8 = 223; uint16_t varUInt16 = 55000; uint32_t varUInt32 = 3000000001UL; uint64_t varUInt64 = ((uint64_t) 0xfedc0102 << 32) | 0x03040506; int8_t varSInt8 = -120; int16_t varSInt16 = -22000; int32_t varSInt32 = -1000000001; int64_t varSInt64 = ((uint64_t) 0xfedc0102 << 32) | 0x03040506; StateVariable vdouble("vdouble", &varDouble); StateVariable vuint8 ("vuint8", &varUInt8); StateVariable vuint16("vuint16", &varUInt16); StateVariable vuint32("vuint32", &varUInt32); StateVariable vuint64("vuint64", &varUInt64); StateVariable vsint8 ("vsint8", &varSInt8); StateVariable vsint16("vsint16", &varSInt16); StateVariable vsint32("vsint32", &varSInt32); StateVariable vsint64("vsint64", &varSInt64); UnitTest::Assert("changing to 'hello' should not be possible", vuint8.SetValue("hello") == false); // Double UnitTest::Assert("changing to 100 should be possible", vdouble.SetValue("100") == true); UnitTest::Assert("varDouble should have been updated", varDouble == 100); UnitTest::Assert("changing to -210.42 should be possible", vdouble.SetValue("-210.42") == true); UnitTest::Assert("varDouble should not have been updated", varDouble == -210.42); UnitTest::Assert("changing to 1e-100 should be possible (2)", vdouble.SetValue("1e-100") == true); UnitTest::Assert("varDouble should have been updated (2)", varDouble == 1e-100); // UInt8 UnitTest::Assert("changing to 100 should be possible", vuint8.SetValue("100") == true); UnitTest::Assert("varUInt8 should have been updated", varUInt8, 100); UnitTest::Assert("changing to 0x2f should be possible", vuint8.SetValue("0x2f") == true); UnitTest::Assert("varUInt8 should have been updated to 0x2f", varUInt8, 0x2f); UnitTest::Assert("changing to 300 should not be possible", vuint8.SetValue("300") == false); UnitTest::Assert("varUInt8 should not have been updated", varUInt8, 0x2f); UnitTest::Assert("changing to -110 should not be possible", vuint8.SetValue("-110") == false); UnitTest::Assert("varUInt8 should not have been updated", varUInt8, 0x2f); // SInt8 UnitTest::Assert("changing to 100 should be possible", vsint8.SetValue("100") == true); UnitTest::Assert("varSInt8 should have been updated", varSInt8, 100); UnitTest::Assert("changing to 200 should not be possible", vsint8.SetValue("200") == false); UnitTest::Assert("varSInt8 should not have been updated", varSInt8, 100); UnitTest::Assert("changing to -210 should not be possible", vsint8.SetValue("-210") == false); UnitTest::Assert("varSInt8 should not have been updated", varSInt8, 100); UnitTest::Assert("changing to -110 should be possible", vsint8.SetValue("-110") == true); UnitTest::Assert("varSInt8 should have been updated", varSInt8, (uint64_t) -110); UnitTest::Assert("changing to -0x1a should be possible", vsint8.SetValue("-0x1a") == true); UnitTest::Assert("varSInt8 should have been updated", varSInt8, (uint64_t) -0x1a); // Tests for other numeric types: TODO } UNITTESTS(StateVariable) { // String tests UNITTEST(Test_StateVariable_String_Construct); UNITTEST(Test_StateVariable_String_SetValue); UNITTEST(Test_StateVariable_String_CopyValueFrom); UNITTEST(Test_StateVariable_String_Serialize); UNITTEST(Test_StateVariable_String_Serialize_WithEscapes); // Bool tests UNITTEST(Test_StateVariable_Bool_Construct); UNITTEST(Test_StateVariable_Bool_SetValue); UNITTEST(Test_StateVariable_Bool_CopyValueFrom); UNITTEST(Test_StateVariable_Bool_Serialize); // Numeric tests UNITTEST(Test_StateVariable_Numeric_Construct); UNITTEST(Test_StateVariable_Numeric_SetValue); //UNITTEST(Test_StateVariable_Numeric_CopyValueFrom); //UNITTEST(Test_StateVariable_Numeric_Serialize); // TODO: ToInteger tests. // TODO: Custom tests. } #endif gxemul-0.6.1/src/main/ComponentFactory.cc000644 001750 001750 00000023120 13402411502 020537 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "ComponentFactory.h" #include "GXemul.h" #include "StringHelper.h" struct ComponentListEntry { const char* componentName; refcount_ptr (*Create)(const ComponentCreateArgs& args); string (*GetAttribute)(const string& attributeName); }; // Static list of components: // (Note: components*.h is autogenerated by the configure script.) #include "../../components_h.h" static struct ComponentListEntry componentList[] = { #include "../../components.h" { NULL, NULL, NULL } }; // List of components that are added dynamically at runtime: static vector* componentListRunTime = NULL; bool ComponentFactory::RegisterComponentClass(const char* name, refcount_ptr (*createFunc)(const ComponentCreateArgs& args), string (*getAttributeFunc)(const string& attributeName)) { // Attempt to create a component using this name first. // Don't add the new component class if the name is already in use. refcount_ptr component = CreateComponent(name); if (!component.IsNULL()) { assert(false); return false; } if (componentListRunTime == NULL) componentListRunTime = new vector(); ComponentListEntry cle; cle.componentName = name; cle.Create = createFunc; cle.GetAttribute = getAttributeFunc; componentListRunTime->push_back(cle); return true; } void ComponentFactory::UnregisterAllComponentClasses() { delete componentListRunTime; componentListRunTime = NULL; } refcount_ptr ComponentFactory::CreateComponent( const string& componentNameAndOptionalArgs, GXemul* gxemul) { ComponentCreateArgs args; args.gxemul = gxemul; string componentName = componentNameAndOptionalArgs; size_t p = componentName.find('('); if (p != string::npos && p > 0) { componentName = componentName.substr(0, p); string argstring = componentNameAndOptionalArgs.substr(p+1); // Arguments don't end with a )? Then something's wrong. if (argstring[argstring.length()-1] != ')') { if (gxemul != NULL) gxemul->GetUI()->ShowDebugMessage("Unmatched parenthesis?\n"); return NULL; } argstring = argstring.substr(0, argstring.length()-1); // argstring is now e.g. "cpu=R4400,ncpus=4" // Split into assignments: vector assignments = StringHelper::SplitStringIntoVector(argstring, ','); // Split each assignment into key and value: for (size_t i=0; i keyAndValue = StringHelper::SplitStringIntoVector(assignments[i], '='); if (keyAndValue.size() != 2) { if (gxemul != NULL) gxemul->GetUI()->ShowDebugMessage("Not a key=value pair: " + assignments[i]); return NULL; } args.componentCreationSettings[keyAndValue[0]] = keyAndValue[1]; } } // Find the className in the list of available components, and // call the corresponding create function, if found: size_t i = 0; while (componentList[i].componentName != NULL) { if (componentName == componentList[i].componentName #ifndef UNSTABLE_DEVEL && !componentList[i].GetAttribute("stable").empty() #endif ) return componentList[i].Create(args); ++ i; } for (i=0; componentListRunTime != NULL && isize(); ++i) { if (componentName == (*componentListRunTime)[i].componentName #ifndef UNSTABLE_DEVEL && !(*componentListRunTime)[i].GetAttribute("stable").empty() #endif ) return (*componentListRunTime)[i].Create(args); } return NULL; } bool ComponentFactory::GetCreationArgOverrides(ComponentCreationSettings& settings, const ComponentCreateArgs& createArgs) { // A copy of the default args (for helpful debug output): ComponentCreationSettings defaultSettings = settings; // Merge in the overrides: for (ComponentCreationSettings::const_iterator it = createArgs.componentCreationSettings.begin(); it != createArgs.componentCreationSettings.end(); ++it) { const string& key = it->first; const string& value = it->second; if (settings.find(key) == settings.end()) { if (createArgs.gxemul != NULL) { stringstream ss; ss << "Unknown setting '" << key << "'. " "Available settings (with default values) are:\n"; for (ComponentCreationSettings::const_iterator it2 = defaultSettings.begin(); it2 != defaultSettings.end(); ++it2) ss << " " << it2->first << " = " << it2->second << "\n"; createArgs.gxemul->GetUI()->ShowDebugMessage(ss.str()); } return false; } settings[key] = value; } return true; } string ComponentFactory::GetAttribute(const string& name, const string& attributeName) { size_t i = 0; while (componentList[i].componentName != NULL) { if (name == componentList[i].componentName) return componentList[i].GetAttribute(attributeName); ++ i; } for (i=0; componentListRunTime!=NULL && isize(); ++i) { if (name == (*componentListRunTime)[i].componentName) return (*componentListRunTime)[i].GetAttribute( attributeName); } return ""; } bool ComponentFactory::HasAttribute(const string& name, const string& attributeName) { return !GetAttribute(name, attributeName).empty(); } vector ComponentFactory::GetAllComponentNames(bool onlyTemplates) { vector result; size_t i = 0; while (componentList[i].componentName != NULL) { if ((!onlyTemplates || componentList[i].GetAttribute("template") == "yes") #ifndef UNSTABLE_DEVEL && !componentList[i].GetAttribute("stable").empty() #endif ) result.push_back(componentList[i].componentName); ++ i; } for (i=0; componentListRunTime!=NULL && isize(); ++i) { if ((!onlyTemplates || (*componentListRunTime)[i].GetAttribute("template") == "yes") #ifndef UNSTABLE_DEVEL && !(*componentListRunTime)[i].GetAttribute("stable").empty() #endif ) result.push_back((*componentListRunTime)[i].componentName); } return result; } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_ComponentFactory_Nonexistant() { refcount_ptr component = ComponentFactory::CreateComponent("NoNeXisT"); UnitTest::Assert("nonexistant component should not be created", component.IsNULL() == true); } static void Test_ComponentFactory_SimpleDummy() { refcount_ptr component = ComponentFactory::CreateComponent("dummy"); UnitTest::Assert("dummy component should be possible to create", component.IsNULL() == false); UnitTest::Assert("the class name should be 'dummy'", component->GetClassName(), "dummy"); UnitTest::Assert("the dummy component should have children", component->GetChildren().size(), 0); } static void Test_ComponentFactory_FromTemplate() { refcount_ptr component = ComponentFactory::CreateComponent("testmips"); UnitTest::Assert("component should be possible to create from template", component.IsNULL() == false); UnitTest::Assert("the class name should be 'machine'", component->GetClassName(), "machine"); UnitTest::Assert("the component should have children", component->GetChildren().size() > 0); refcount_ptr clone = component->Clone(); UnitTest::Assert("cloning should have been possible", clone.IsNULL() == false); UnitTest::Assert("clone: the class name should still be 'machine'", clone->GetClassName(), "machine"); UnitTest::Assert("clone: the clone should also have children", clone->GetChildren().size() > 0); } static void Test_ComponentFactory_HasAttribute() { UnitTest::Assert("nonexistantattr should not exist", !ComponentFactory::HasAttribute("testm88k", "nonexistantattr")); UnitTest::Assert("testm88k is a machine", ComponentFactory::HasAttribute("testm88k", "machine")); UnitTest::Assert("testm88k is stable", ComponentFactory::HasAttribute("testm88k", "stable")); UnitTest::Assert("testm88k has a description", ComponentFactory::HasAttribute("testm88k", "description")); } UNITTESTS(ComponentFactory) { UNITTEST(Test_ComponentFactory_Nonexistant); UNITTEST(Test_ComponentFactory_SimpleDummy); UNITTEST(Test_ComponentFactory_FromTemplate); UNITTEST(Test_ComponentFactory_HasAttribute); } #endif gxemul-0.6.1/src/main/UnitTest.cc000644 001750 001750 00000006610 13402411502 017031 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include "misc.h" #include "UnitTest.h" // The list of classes to test is detected by the configure script, and // placed in unittest.h, but the classes corresponding .h files also need // to be included. This is done by unittest_h.h (also generated by the // configure script). #include "../../unittest_h.h" void UnitTest::Assert(const string& strFailMessage, bool condition) { if (!condition) Fail(strFailMessage); } void UnitTest::Assert(const string& strFailMessage, uint64_t actualValue, uint64_t expectedValue) { if (actualValue != expectedValue) { stringstream ss; ss.flags(std::ios::hex | std::ios::showbase); ss << strFailMessage << "\n\tExpected: " << expectedValue << "\n\tbut was: " << actualValue; Fail(ss.str()); } } void UnitTest::Assert(const string& strFailMessage, const string& actualValue, const string& expectedValue) { if (actualValue != expectedValue) { size_t pos; for (pos = 0; pos < actualValue.length() && pos < expectedValue.length(); pos++) if (actualValue[pos] != expectedValue[pos]) break; stringstream mismatchPosition; mismatchPosition << "\n\tMismatch at position " << pos; Fail(strFailMessage + mismatchPosition.str() + "\n\tExpected: \"" + expectedValue + "\"" + "\n\tbut was: \"" + actualValue + "\""); } } void UnitTest::Fail(const string& strMessage) { throw UnitTestFailedException(strMessage); } #ifndef WITHUNITTESTS int UnitTest::RunTests() { std::cerr << "Skipping unit tests, because WITHUNITTESTS " "was not defined.\n"; return 0; } #else // WITHUNITTESTS int UnitTest::RunTests() { int nSucceeded = 0, nFailed = 0; #include "../../unittest.h" if (nFailed == 0) std::cerr << nSucceeded << " (all) tests passed.\n"; else std::cerr << "\n" << nFailed << " TESTS FAILED!\n"; // Returns 0 if there were no errors. return nFailed > 0; } #endif // WITHUNITTESTS gxemul-0.6.1/src/main/SymbolRegistry.cc000644 001750 001750 00000010400 13402411502 020240 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "SymbolRegistry.h" SymbolRegistry::SymbolRegistry() { } void SymbolRegistry::Clear() { m_map.clear(); } void SymbolRegistry::AddSymbol(const string& symbol, uint64_t vaddr) { m_map[vaddr] = symbol; } string SymbolRegistry::LookupAddress(uint64_t vaddr, bool allowOffset) const { // Must be an exact match? if (!allowOffset) { SymbolMap::const_iterator a = m_map.find(vaddr); return a == m_map.end()? "" : a->second; } // Try to find the symbol given the address, or at least some // symbol close to it: SymbolMap::const_iterator a = m_map.lower_bound(vaddr); if (a == m_map.end()) { if (m_map.empty()) return ""; a = m_map.end(); } // Exact match? Then just return the symbol. if (a != m_map.end() && vaddr == a->first) return a->second; if (a == m_map.begin()) return ""; // Return the symbol _before_ the address, plus an offset. --a; stringstream ss; ss.flags(std::ios::hex); ss << a->second << "+0x" << (vaddr - a->first); return ss.str(); } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_SymbolRegistry_Basic() { SymbolRegistry registry; registry.AddSymbol("symA", 0x1000); registry.AddSymbol("symB", 0x1020); registry.AddSymbol("symC", 0x1060); UnitTest::Assert("lookup failed 1?", registry.LookupAddress(0x1020, true), "symB"); UnitTest::Assert("lookup failed 2?", registry.LookupAddress(0x1020, false), "symB"); registry.Clear(); UnitTest::Assert("clear failed?", registry.LookupAddress(0x1020, true), ""); } static void Test_SymbolRegistry_BeforeFirst() { SymbolRegistry registry; registry.AddSymbol("symA", 0x1000); registry.AddSymbol("symB", 0x1020); UnitTest::Assert("lookup should have failed 1", registry.LookupAddress(0xffc, true), ""); UnitTest::Assert("lookup should have failed 2", registry.LookupAddress(0xffc, false), ""); } static void Test_SymbolRegistry_WithOffset() { SymbolRegistry registry; registry.AddSymbol("symA", 0x1000); registry.AddSymbol("symB", 0x1020); UnitTest::Assert("lookup failed?", registry.LookupAddress(0x1006, true), "symA+0x6"); UnitTest::Assert("lookup should have failed", registry.LookupAddress(0x1006, false), ""); } static void Test_SymbolRegistry_AfterLast() { SymbolRegistry registry; registry.AddSymbol("symA", 0x1000); registry.AddSymbol("symB", 0x1020); UnitTest::Assert("lookup failed?", registry.LookupAddress(0x1090, true), "symB+0x70"); UnitTest::Assert("lookup should have failed", registry.LookupAddress(0x1090, false), ""); } UNITTESTS(SymbolRegistry) { UNITTEST(Test_SymbolRegistry_Basic); UNITTEST(Test_SymbolRegistry_BeforeFirst); UNITTEST(Test_SymbolRegistry_WithOffset); UNITTEST(Test_SymbolRegistry_AfterLast); } #endif gxemul-0.6.1/src/main/Makefile.skel000644 001750 001750 00000001134 13402411502 017334 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/main # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(DINCLUDE) OBJS=Checksum.o Command.o CommandInterpreter.o Component.o ComponentFactory.o \ EscapedString.o FileLoader.o GXemul.o StateVariable.o \ StringHelper.o SymbolRegistry.o UnitTest.o debug_new.o all: $(OBJS) do_commands do_fileloaders $(OBJS): Makefile do_commands: cd commands; $(MAKE) do_fileloaders: cd fileloaders; $(MAKE) clean: cd commands; $(MAKE) clean cd fileloaders; $(MAKE) clean rm -f $(OBJS) *core clean_all: clean cd commands; $(MAKE) clean_all cd fileloaders; $(MAKE) clean_all rm -f Makefile gxemul-0.6.1/src/main/CommandInterpreter.cc000644 001750 001750 00000151770 13402411502 021064 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "assert.h" #include #include "GXemul.h" #include "CommandInterpreter.h" // Built-in commands (autogenerated list by the configure script): #include "../../commands_h.h" CommandInterpreter::CommandInterpreter(GXemul* owner) : m_GXemul(owner) , m_currentCommandCursorPosition(0) , m_inEscapeSequence(false) , m_historyEntryToCopyFrom(0) , m_commandHistoryInsertPosition(0) , m_commandHistoryMaxSize(100) { m_commandHistory.resize(m_commandHistoryMaxSize, ""); // It would be bad to run without a working GXemul instance. assert(m_GXemul != NULL); // Add the default built-in commands: // (This list is autogenerated by the configure script.) #include "../../commands.h" } void CommandInterpreter::AddCommand(refcount_ptr command) { m_commands[command->GetCommandName()] = command; } const Commands& CommandInterpreter::GetCommands() const { return m_commands; } int CommandInterpreter::AddLineToCommandHistory(const string& command) { if (command == "") return m_commandHistoryInsertPosition; size_t lastInsertedPosition = (m_commandHistoryInsertPosition - 1 + m_commandHistoryMaxSize) % m_commandHistoryMaxSize; if (m_commandHistory[lastInsertedPosition] == command) return m_commandHistoryInsertPosition; m_commandHistory[m_commandHistoryInsertPosition ++] = command; m_commandHistoryInsertPosition %= m_commandHistoryMaxSize; return m_commandHistoryInsertPosition; } string CommandInterpreter::GetHistoryLine(int nStepsBack) const { if (nStepsBack == 0) return ""; int index = (m_commandHistoryInsertPosition - nStepsBack + m_commandHistoryMaxSize) % m_commandHistoryMaxSize; return m_commandHistory[index]; } bool CommandInterpreter::TabComplete(string& commandString, size_t& cursorPosition, bool visibleShowAvailable) { string wordToComplete; bool firstWordOnLine = true; size_t pos = cursorPosition; while (pos > 0) { pos --; if (commandString[pos] == ' ') break; wordToComplete = commandString[pos] + wordToComplete; } while (pos > 0) { pos --; if (commandString[pos] != ' ') { firstWordOnLine = false; break; } } bool completeCommands = firstWordOnLine; if (wordToComplete == "") { if (!visibleShowAvailable) return false; // Show all available words: if (completeCommands) { // All available commands: vector allCommands; for (Commands::const_iterator it = m_commands.begin(); it != m_commands.end(); ++it) allCommands.push_back(it->first); ShowAvailableWords(allCommands); } ShowAvailableWords(m_GXemul->GetRootComponent()-> FindPathByPartialMatch("")); return false; } vector matches; matches = m_GXemul->GetRootComponent()-> FindPathByPartialMatch(wordToComplete, true); if (completeCommands) { Commands::const_iterator it = m_commands.begin(); for (; it != m_commands.end(); ++it) { const string& commandName = it->first; if (commandName.substr(0, wordToComplete.length()) == wordToComplete) { matches.push_back(commandName); } } } if (matches.size() == 0) return false; string completedWord; // Single match, or multiple matches? if (matches.size() == 1) { // Insert the rest of the command name into the input line: completedWord = matches[0]; } else { // Figure out the longest possible match, and add that: size_t i, n = matches.size(); for (size_t pos2 = 0; ; pos2 ++) { if (pos2 >= matches[0].length()) break; stringchar ch = matches[0][pos2]; for (i=1; ifirst; if (commandName == matches[0]) { isCommand = true; break; } } if (isCommand) { commandString += " "; cursorPosition ++; } } return matches.size() == 1; } bool CommandInterpreter::TabCompleteWithSubname(string& commandString, size_t& cursorPosition, bool visibleShowAvailable) { if (cursorPosition == 0) return false; int nStepsBack = 1; size_t pos = cursorPosition - 1; while (pos > 0 && commandString[pos] != '.') { pos --; nStepsBack ++; } if (pos == 0) return false; // Here, pos is the position of the dot: // // cpu.u // ^ bool success = TabComplete(commandString, pos, visibleShowAvailable); if (!success) return false; // pos is now the new position of the dot: // // root.machine0.mainbus0.cpu.u // ^ // Look up the component: int startOfComponentName = pos; while (startOfComponentName >= 0 && commandString[startOfComponentName] != ' ') -- startOfComponentName; if (startOfComponentName < 0) startOfComponentName = 0; string componentName = commandString.substr(startOfComponentName, pos - startOfComponentName); // std::cerr << "[" << componentName << "]\n"; refcount_ptr component = m_GXemul->GetRootComponent()-> LookupPath(componentName); cursorPosition = pos + nStepsBack; if (component.IsNULL()) return false; // Figure out the method or state name to expand: size_t startOfMethodName = pos + 1; size_t methodNameLen = 0; while (startOfMethodName + methodNameLen < cursorPosition && commandString[startOfMethodName+methodNameLen] != ' ') methodNameLen ++; string methodName = commandString.substr(startOfMethodName, methodNameLen); // std::cerr << "{" << methodName << "}\n"; vector names; vector matchingNames; component->GetMethodNames(names); component->GetVariableNames(names); int nrOfMatches = 0; if (methodName.length() != 0) { for (size_t i=0; i= matchingNames[0].length()) break; stringchar ch = matchingNames[0][pos2]; for (i=1; i allNames; vector matchingNames2; component->GetMethodNames(allNames); for (size_t j=0; j 0) { m_GXemul->GetUI()->ShowDebugMessage("\nMethods:"); ShowAvailableWords(matchingNames2); } } if (visibleShowAvailable) { vector allNames; vector matchingNames2; component->GetVariableNames(allNames); for (size_t j=0; j 0) { m_GXemul->GetUI()->ShowDebugMessage("\nVariables:"); ShowAvailableWords(matchingNames2); } } return false; } bool CommandInterpreter::AddKey(stringchar key) { if (m_inEscapeSequence) { m_escapeSequence += key; // Handle some common escape sequences, and convert // them into simpler 1-byte keys/characters: if (m_escapeSequence == "[C") { // right m_inEscapeSequence = false; AddKey('\6'); // CTRL-F } else if (m_escapeSequence == "[D") { // left m_inEscapeSequence = false; AddKey('\2'); // CTRL-B } else if (m_escapeSequence == "OH") { // home m_inEscapeSequence = false; AddKey('\1'); // CTRL-A } else if (m_escapeSequence == "[H") { // home m_inEscapeSequence = false; AddKey('\1'); // CTRL-A } else if (m_escapeSequence == "OF") { // end m_inEscapeSequence = false; AddKey('\5'); // CTRL-E } else if (m_escapeSequence == "[F") { // end m_inEscapeSequence = false; AddKey('\5'); // CTRL-E } else if (m_escapeSequence == "[A") { // up m_inEscapeSequence = false; AddKey('\20'); // CTRL-P } else if (m_escapeSequence == "[B") { // down m_inEscapeSequence = false; AddKey('\16'); // CTRL-N } else if (m_escapeSequence.length() > 2) { // Let's bail out of escape sequence handling... // // Note: If you trace execution here for some key that // you feel _should_ be handled, please send me a mail // about it. // m_inEscapeSequence = false; AddKey('?'); } return false; } switch (key) { case '\0': // Add nothing, just reshow/update the command buffer. break; case '\1': // CTRL-A: move to start of line m_currentCommandCursorPosition = 0; break; case '\2': // CTRL-B: move back (left) if (m_currentCommandCursorPosition > 0) m_currentCommandCursorPosition --; break; case '\4': // CTRL-D: remove the character to the right if (m_currentCommandCursorPosition < m_currentCommandString.length()) m_currentCommandString.erase( m_currentCommandCursorPosition, 1); break; case '\5': // CTRL-E: move to end of line m_currentCommandCursorPosition = m_currentCommandString.length(); break; case '\6': // CTRL-F: move forward (right) if (m_currentCommandCursorPosition < m_currentCommandString.length()) m_currentCommandCursorPosition ++; break; case '\13': // CTRL-K: kill to end of line ClearCurrentInputLineVisually(); m_currentCommandString.resize(m_currentCommandCursorPosition); break; case '\16': // CTRL-N: next in history (down) ClearCurrentInputLineVisually(); m_historyEntryToCopyFrom --; if (m_historyEntryToCopyFrom < 0) m_historyEntryToCopyFrom = 0; m_currentCommandString = GetHistoryLine(m_historyEntryToCopyFrom); m_currentCommandCursorPosition = m_currentCommandString.length(); break; case '\20': // CTRL-P: previous in history (up) ClearCurrentInputLineVisually(); m_historyEntryToCopyFrom ++; m_currentCommandString = GetHistoryLine(m_historyEntryToCopyFrom); // We went too far? Then back down. if (m_currentCommandString == "") { m_historyEntryToCopyFrom --; m_currentCommandString = GetHistoryLine(m_historyEntryToCopyFrom); } m_currentCommandCursorPosition = m_currentCommandString.length(); break; case '\24': // CTRL-T: show status m_GXemul->GetUI()->ShowDebugMessage("\n"); RunCommand("status"); break; case '\27': // CTRL-W: remove current word (backspacing) ClearCurrentInputLineVisually(); // 1. Remove any spaces left to the cursor. while (m_currentCommandCursorPosition > 0) { if (m_currentCommandString[ m_currentCommandCursorPosition-1] == ' ') { m_currentCommandCursorPosition --; m_currentCommandString.erase( m_currentCommandCursorPosition, 1); } else { break; } } // 2. Remove non-spaces left to the cusror, either until // the cursor is at position 0, or until there is a // space again. while (m_currentCommandCursorPosition > 0) { if (m_currentCommandString[ m_currentCommandCursorPosition-1] != ' ') { m_currentCommandCursorPosition --; m_currentCommandString.erase( m_currentCommandCursorPosition, 1); } else { break; } } break; case '\177': // ASCII 127 (octal 177) = del case '\b': // backspace if (m_currentCommandCursorPosition > 0) { m_currentCommandCursorPosition --; m_currentCommandString.erase( m_currentCommandCursorPosition, 1); } break; case '\33': // Escape key handling: m_inEscapeSequence = true; m_escapeSequence = ""; break; case '\t': // Tab completion, with visible word hints: { bool success = TabComplete(m_currentCommandString, m_currentCommandCursorPosition, true); // Attempt to expand component-name + "." + optional // method or variable name, "cpu.u", if the first // tab-completion failed. if (!success) { TabCompleteWithSubname(m_currentCommandString, m_currentCommandCursorPosition, true); } } break; case '\n': case '\r': // Newline executes the command, if it is non-empty: m_GXemul->GetUI()->InputLineDone(); if (!m_currentCommandString.empty()) { AddLineToCommandHistory(m_currentCommandString); RunCommand(m_currentCommandString); ClearCurrentCommandBuffer(); } else if (m_mayBeReexecuted != "") { RunCommand(m_mayBeReexecuted); } break; default: // Most other keys just add/insert a character into the command // string: if (key >= ' ') { m_currentCommandString.insert( m_currentCommandCursorPosition, 1, key); m_currentCommandCursorPosition ++; } } if (key != '\n' && key != '\r') ReshowCurrentCommandBuffer(); // Return value is true for newline/cr, false otherwise: return key == '\n' || key == '\r'; } void CommandInterpreter::ShowAvailableWords(const vector& words) { m_GXemul->GetUI()->ShowDebugMessage("\n"); const size_t n = words.size(); size_t i; // Find the longest word first: size_t maxLen = 0; for (i=0; i maxLen) maxLen = len; } maxLen += 4; // Generate msg: std::stringstream msg; size_t lineLen = 0; for (i=0; i= 77 - maxLen || i == n-1) { msg << "\n"; lineLen = 0; } } m_GXemul->GetUI()->ShowDebugMessage(msg.str()); } void CommandInterpreter::ReshowCurrentCommandBuffer() { m_GXemul->GetUI()->RedisplayInputLine( m_currentCommandString, m_currentCommandCursorPosition); } void CommandInterpreter::ClearCurrentInputLineVisually() { string clearString = ""; clearString.insert((size_t)0, m_currentCommandString.length(), ' '); m_GXemul->GetUI()->RedisplayInputLine( clearString, m_currentCommandCursorPosition); } void CommandInterpreter::ClearCurrentCommandBuffer() { m_currentCommandString = ""; m_currentCommandCursorPosition = 0; m_historyEntryToCopyFrom = 0; } static void SplitIntoWords(const string& commandOrig, string& commandName, vector& arguments) { string command = commandOrig; arguments.clear(); commandName = ""; size_t pos = 0; // Surround '=' with white spaces, except when inside parentheses... // NOTE/TODO: This will not be needed in the future (?), when a real // expression evaluator has been [re]implemented. int insideParenthesesCount = 0; while (pos < command.length()) { if (command[pos] == '(') insideParenthesesCount ++; if (command[pos] == ')') insideParenthesesCount --; if (command[pos] == '=' && insideParenthesesCount == 0) { command.replace(pos, 1, " = "); pos ++; } pos ++; } // Split command into words, ignoring all whitespace: pos = 0; while (pos < command.length()) { // Skip initial whitespace: while (pos < command.length() && command[pos] == ' ') pos ++; if (pos >= command.length()) break; // This is a new word. Add all characters, until // whitespace or end of string: string newWord = ""; while (pos < command.length() && command[pos] != ' ') { newWord += command[pos]; pos ++; } if (commandName.empty()) commandName = newWord; else arguments.push_back(newWord); } } void CommandInterpreter::VariableAssignment(const string& componentPath, const string& variableName, const string& expression) { refcount_ptr component = m_GXemul->GetRootComponent()-> LookupPath(componentPath); StateVariable* var = component->GetVariable(variableName); if (var == NULL) { m_GXemul->GetUI()->ShowDebugMessage("Unknown variable '" + variableName + "'? (Internal error.)\n"); throw std::exception(); } const refcount_ptr lightClone = m_GXemul->GetRootComponent()->LightClone(); // Attempt to assign the expression to the variable: if (!component->SetVariableValue(variableName, expression)) m_GXemul->GetUI()->ShowDebugMessage("Assignment failed.\n"); // ... and print all state change (in case a write to a variable had // side effects, then this makes sure that the user sees all such side // effects): stringstream changeMessages; m_GXemul->GetRootComponent()->DetectChanges(lightClone, changeMessages); string msg = changeMessages.str(); if (msg == "") msg = "(No state change.)\n"; m_GXemul->GetUI()->ShowDebugMessage(msg); } bool CommandInterpreter::RunComponentMethod( const string& componentPathAndMethod, const vector& arguments) { // Note: componentPathAndMethod may or may not have a method at // the end! // Make several "smart" guesses: refcount_ptr component; string componentPath; string methodName; do { // 1. Assume that componentPathAndMethod is a full component // path: component = m_GXemul->GetRootComponent()-> LookupPath(componentPathAndMethod); if (!component.IsNULL()) break; // 2. Assume that componentPathAndMethod is a component // path, but it is not tab-completed yet: string tabcompleted = componentPathAndMethod; size_t tmpLen = tabcompleted.length(); if (TabComplete(tabcompleted, tmpLen)) { component = m_GXemul->GetRootComponent()-> LookupPath(tabcompleted); if (!component.IsNULL()) break; } // If there is no period in the name, we can't continue // with the following guesses. if (componentPathAndMethod.find(".") == string::npos) break; size_t pos = componentPathAndMethod.find_last_of('.'); // 3. Assume full component path + ".method": componentPath = componentPathAndMethod.substr(0, pos); component = m_GXemul->GetRootComponent()-> LookupPath(componentPath); if (!component.IsNULL()) { methodName = componentPathAndMethod.substr(pos+1); break; } // 4. Assume non-tab-completed component path + ".method": tabcompleted = componentPath; tmpLen = tabcompleted.length(); if (TabComplete(tabcompleted, tmpLen)) { component = m_GXemul->GetRootComponent()-> LookupPath(tabcompleted); if (!component.IsNULL()) { methodName = componentPathAndMethod.substr(pos+1); break; } } } while (false); if (component.IsNULL()) return false; // No method given? Then show the component tree, and the component's // state variables, and return. if (methodName.empty()) { m_GXemul->GetUI()->ShowDebugMessage( component->GenerateTreeDump("")); // Retrieve the names of all the state variables: vector variableNames; component->GetVariableNames(variableNames); stringstream ss; ss << "\n"; size_t maxLen = 0; size_t i; for (i=0; i maxLen) maxLen = variableNames[i].length(); for (i=0; iGetVariable(name); if (var == NULL) ss << "= (unknown?)"; else ss << "= " << var->ToString(); ss << "\n"; } m_GXemul->GetUI()->ShowDebugMessage(ss.str()); return true; } // Now, it is possible that methodName is incomplete, so it has to // be looked up as well: vector names; component->GetMethodNames(names); int nrOfMatches = 0; string fullMatch; for (size_t i=0; iExecuteMethod(m_GXemul, fullMatch, arguments); if (component->MethodMayBeReexecutedWithoutArgs(fullMatch)) m_mayBeReexecuted = componentPathAndMethod; return true; } // Try variable names: names.clear(); component->GetVariableNames(names); nrOfMatches = 0; fullMatch = ""; for (size_t i=0; i 0) { if (arguments.size() == 1 || arguments[0] != "=") { // TODO: Printing expressions, such as // cpu.pc + 4 m_GXemul->GetUI()->ShowDebugMessage( "Syntax error. Variable assignment syntax" " is:\n = \n"); return true; } const StateVariable* var = component->GetVariable(fullMatch); if (var == NULL) { m_GXemul->GetUI()->ShowDebugMessage( "Unknown variable.\n"); return true; } string assignment; for (size_t i=1; iGeneratePath(), fullMatch, assignment); return true; } // Print the variable's name and value: ss << fullMatch; const StateVariable* var = component->GetVariable(fullMatch); if (var == NULL) ss << " = (unknown variable?)"; else ss << " = " << var->ToString(); ss << "\n"; m_GXemul->GetUI()->ShowDebugMessage(ss.str()); return true; } if (nrOfMatches > 1) ss << methodName << ": ambiguous method or variable name of " << component->GeneratePath() << ".\n"; else ss << methodName << ": not a method or variable of " << component->GeneratePath() << ".\n"; m_GXemul->GetUI()->ShowDebugMessage(ss.str()); return false; } bool CommandInterpreter::RunCommand(const string& command, bool* pSuccess) { string commandName; vector arguments; SplitIntoWords(command, commandName, arguments); m_mayBeReexecuted = ""; m_GXemul->GetUI()->ShowCommandMessage(command); // Find the command... Commands::iterator it = m_commands.find(commandName); if (it == m_commands.end()) { // Not found? Then try to tab-complete the name... string commandTabCompleted = commandName; size_t tmpCursorPos = commandTabCompleted.length(); TabComplete(commandTabCompleted, tmpCursorPos); // remove any trailing space(s): while (commandTabCompleted.length() > 0 && commandTabCompleted[commandTabCompleted.length()-1] == ' ') commandTabCompleted.erase( commandTabCompleted.length() - 1); // ... and try again: it = m_commands.find(commandTabCompleted); if (it == m_commands.end()) { // If this is a component name [with an optional // method name], then execute a method on it. if (RunComponentMethod(commandName, arguments)) return true; m_GXemul->GetUI()->ShowDebugMessage(commandName + ": unknown command. Type help for help.\n"); return false; } } if (arguments.size() != 0 && (it->second)->GetArgumentFormat() == "") { m_GXemul->GetUI()->ShowDebugMessage(commandName + " takes no arguments. Type help " + commandName + " for help on the syntax.\n"); return false; } // ... and execute it: bool success = (it->second)->Execute(*m_GXemul, arguments); if (pSuccess != NULL) *pSuccess = success; if ((it->second)->MayBeReexecutedWithoutArgs()) m_mayBeReexecuted = it->first; return true; } const string& CommandInterpreter::GetCurrentCommandBuffer() const { return m_currentCommandString; } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_CommandInterpreter_AddKey_ReturnValue() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); UnitTest::Assert("addkey of regular char should return false", ci.AddKey('a') == false); UnitTest::Assert("addkey of nul char should return false", ci.AddKey('\0') == false); UnitTest::Assert("addkey of newline should return true", ci.AddKey('\n') == true); UnitTest::Assert("addkey of carriage return should return true too", ci.AddKey('\r') == true); } static void Test_CommandInterpreter_KeyBuffer() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); UnitTest::Assert("buffer should initially be empty", ci.GetCurrentCommandBuffer() == ""); ci.AddKey('a'); // normal char UnitTest::Assert("buffer should contain 'a'", ci.GetCurrentCommandBuffer() == "a"); ci.AddKey('\0'); // nul char should have no effect UnitTest::Assert("buffer should still contain only 'a'", ci.GetCurrentCommandBuffer() == "a"); ci.AddKey('A'); // multiple chars ci.AddKey('B'); UnitTest::Assert("buffer should contain 'aAB'", ci.GetCurrentCommandBuffer() == "aAB"); ci.AddKey('\177'); // del UnitTest::Assert("buffer should contain 'aA' (del didn't work?)", ci.GetCurrentCommandBuffer() == "aA"); ci.AddKey('\b'); // backspace UnitTest::Assert("buffer should contain 'a' again (BS didn't work)", ci.GetCurrentCommandBuffer() == "a"); ci.AddKey('\b'); UnitTest::Assert("buffer should now be empty '' again", ci.GetCurrentCommandBuffer() == ""); ci.AddKey('\b'); // cannot be emptier than... well... empty :) UnitTest::Assert("buffer should still be empty", ci.GetCurrentCommandBuffer() == ""); ci.AddKey('a'); UnitTest::Assert("buffer should contain 'a' again", ci.GetCurrentCommandBuffer() == "a"); ci.AddKey('Q'); UnitTest::Assert("buffer should contain 'aQ'", ci.GetCurrentCommandBuffer() == "aQ"); ci.AddKey('\n'); // newline should execute the command UnitTest::Assert("buffer should be empty after executing '\\n'", ci.GetCurrentCommandBuffer() == ""); ci.AddKey('Z'); ci.AddKey('Q'); UnitTest::Assert("new command should have been possible", ci.GetCurrentCommandBuffer() == "ZQ"); ci.AddKey('\r'); // carriage return should work like newline UnitTest::Assert("buffer should be empty after executing '\\r'", ci.GetCurrentCommandBuffer() == ""); } static void Test_CommandInterpreter_KeyBuffer_CursorMovement() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.AddKey('A'); ci.AddKey('B'); ci.AddKey('C'); ci.AddKey('D'); ci.AddKey('E'); UnitTest::Assert("buffer should contain 'ABCDE'", ci.GetCurrentCommandBuffer(), "ABCDE"); ci.AddKey('\2'); // CTRL-B should move back (left) ci.AddKey('\2'); ci.AddKey('\2'); UnitTest::Assert("buffer should still contain 'ABCDE'", ci.GetCurrentCommandBuffer(), "ABCDE"); ci.AddKey('\b'); UnitTest::Assert("buffer should now contain 'ACDE'", ci.GetCurrentCommandBuffer(), "ACDE"); ci.AddKey('\6'); // CTRL-F should move forward (right) ci.AddKey('\6'); UnitTest::Assert("buffer should still contain 'ACDE'", ci.GetCurrentCommandBuffer(), "ACDE"); ci.AddKey('\b'); UnitTest::Assert("buffer should now contain 'ACE'", ci.GetCurrentCommandBuffer(), "ACE"); ci.AddKey('\1'); // CTRL-A should move to start of line UnitTest::Assert("buffer should still contain 'ACE'", ci.GetCurrentCommandBuffer(), "ACE"); ci.AddKey('1'); ci.AddKey('2'); UnitTest::Assert("buffer should now contain '12ACE'", ci.GetCurrentCommandBuffer(), "12ACE"); ci.AddKey('\5'); // CTRL-E should move to end of line UnitTest::Assert("buffer should still contain '12ACE'", ci.GetCurrentCommandBuffer(), "12ACE"); ci.AddKey('x'); ci.AddKey('y'); UnitTest::Assert("buffer should now contain '12ACExy'", ci.GetCurrentCommandBuffer(), "12ACExy"); ci.AddKey('\1'); // CTRL-A move to start of line again ci.AddKey('\6'); // CTRL-F move to the right ci.AddKey('\4'); // CTRL-D should remove character to the right UnitTest::Assert("buffer should now contain '1ACExy'", ci.GetCurrentCommandBuffer(), "1ACExy"); } static void Test_CommandInterpreter_KeyBuffer_CtrlK() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.AddKey('A'); ci.AddKey('B'); ci.AddKey('C'); ci.AddKey('D'); ci.AddKey('E'); UnitTest::Assert("buffer should contain 'ABCDE'", ci.GetCurrentCommandBuffer(), "ABCDE"); ci.AddKey('\2'); // CTRL-B should move back (left) ci.AddKey('\2'); UnitTest::Assert("buffer should still contain 'ABCDE'", ci.GetCurrentCommandBuffer(), "ABCDE"); ci.AddKey('\13'); // CTRL-K UnitTest::Assert("buffer should now contain 'ABC'", ci.GetCurrentCommandBuffer(), "ABC"); ci.AddKey('X'); ci.AddKey('\13'); // CTRL-K again, at end of line UnitTest::Assert("buffer should now contain 'ABCX'", ci.GetCurrentCommandBuffer(), "ABCX"); ci.AddKey('\1'); // CTRL-A to move to start of line ci.AddKey('\13'); // CTRL-K again, should erase everything UnitTest::Assert("buffer should now be empty", ci.GetCurrentCommandBuffer(), ""); } static void Test_CommandInterpreter_KeyBuffer_CtrlW() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); UnitTest::Assert("buffer should contain ''", ci.GetCurrentCommandBuffer(), ""); ci.AddKey('\27'); // CTRL-W UnitTest::Assert("buffer should still contain ''", ci.GetCurrentCommandBuffer(), ""); ci.AddKey('a'); ci.AddKey('b'); ci.AddKey('c'); UnitTest::Assert("buffer should contain abc", ci.GetCurrentCommandBuffer(), "abc"); ci.AddKey('\27'); // CTRL-W UnitTest::Assert("buffer should be empty again", ci.GetCurrentCommandBuffer(), ""); ci.AddKey(' '); ci.AddKey(' '); ci.AddKey('a'); ci.AddKey('b'); ci.AddKey('c'); UnitTest::Assert("buffer should contain ' abc'", ci.GetCurrentCommandBuffer(), " abc"); ci.AddKey('\27'); // CTRL-W UnitTest::Assert("buffer should contain only two spaces", ci.GetCurrentCommandBuffer(), " "); ci.AddKey('a'); ci.AddKey('b'); ci.AddKey('c'); ci.AddKey(' '); UnitTest::Assert("buffer should contain ' abc '", ci.GetCurrentCommandBuffer(), " abc "); ci.AddKey('\27'); // CTRL-W UnitTest::Assert("buffer should again contain only two spaces", ci.GetCurrentCommandBuffer(), " "); ci.AddKey('a'); ci.AddKey('b'); ci.AddKey('c'); ci.AddKey('d'); ci.AddKey(' '); ci.AddKey('e'); ci.AddKey('f'); ci.AddKey('g'); ci.AddKey('h'); ci.AddKey('i'); ci.AddKey(' '); ci.AddKey('\2'); // CTRL-B = move left ci.AddKey('\2'); ci.AddKey('\2'); UnitTest::Assert("buffer should contain ' abcd efghi '", ci.GetCurrentCommandBuffer(), " abcd efghi "); ci.AddKey('\27'); // CTRL-W UnitTest::Assert("buffer should now contain ' abcd hi '", ci.GetCurrentCommandBuffer(), " abcd hi "); } static void Test_CommandInterpreter_CommandHistory() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); UnitTest::Assert("history should still be empty (1)", ci.AddLineToCommandHistory(""), 0); UnitTest::Assert("history should still be empty (2)", ci.AddLineToCommandHistory(""), 0); UnitTest::Assert("A: history line 0", ci.GetHistoryLine(0), ""); UnitTest::Assert("A: history line 1 not set yet", ci.GetHistoryLine(1), ""); UnitTest::Assert("A: history line 2 not set yet", ci.GetHistoryLine(2), ""); UnitTest::Assert("history should contain one entry", ci.AddLineToCommandHistory("hello"), 1); UnitTest::Assert("B: history line 0", ci.GetHistoryLine(0), ""); UnitTest::Assert("B: history line 1", ci.GetHistoryLine(1), "hello"); UnitTest::Assert("B: history line 2 not set yet", ci.GetHistoryLine(2), ""); UnitTest::Assert("history should contain two entries", ci.AddLineToCommandHistory("world"), 2); UnitTest::Assert("history should still contain two entries", ci.AddLineToCommandHistory("world"), 2); UnitTest::Assert("C: history line 0", ci.GetHistoryLine(0), ""); UnitTest::Assert("C: history line 1", ci.GetHistoryLine(1), "world"); UnitTest::Assert("C: history line 2", ci.GetHistoryLine(2), "hello"); UnitTest::Assert("history should contain three entries", ci.AddLineToCommandHistory("hello"), 3); UnitTest::Assert("D: history line 0", ci.GetHistoryLine(0), ""); UnitTest::Assert("D: history line 1", ci.GetHistoryLine(1), "hello"); UnitTest::Assert("D: history line 2", ci.GetHistoryLine(2), "world"); UnitTest::Assert("history should still contain three entries", ci.AddLineToCommandHistory(""), 3); } /** * \brief A dummy Command, for unit testing purposes */ class DummyCommand2 : public Command { public: DummyCommand2(int& valueRef) : Command("dummycommand", "[args]") , m_value(valueRef) { } ~DummyCommand2() { } bool Execute(GXemul& gxemul, const vector& arguments) { m_value ++; return true; } string GetShortDescription() const { return "A dummy command used for unit testing."; } string GetLongDescription() const { return "This is just a dummy command used for unit testing."; } private: int& m_value; }; /** * \brief A dummy Command, for unit testing purposes */ class DummyCommand3 : public Command { public: DummyCommand3(int& valueRef) : Command("dummycmd", "[args]") , m_value(valueRef) { } ~DummyCommand3() { } bool Execute(GXemul& gxemul, const vector& arguments) { m_value ++; return true; } string GetShortDescription() const { return "A dummy command used for unit testing."; } string GetLongDescription() const { return "This is just a dummy command used for unit testing."; } private: int& m_value; }; static void Test_CommandInterpreter_AddCommand() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); size_t nCommands = ci.GetCommands().size(); UnitTest::Assert("there should be some commands already", nCommands > 0); ci.AddCommand(new VersionCommand); UnitTest::Assert("it should not be possible to have multiple commands" " with the same name", ci.GetCommands().size() == nCommands); int dummyInt = 42; ci.AddCommand(new DummyCommand2(dummyInt)); UnitTest::Assert("it should be possible to add new commands", ci.GetCommands().size() == nCommands + 1); } static void Test_CommandInterpreter_TabCompletion_EmptyLine() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.AddKey('\t'); UnitTest::Assert("tab completion should not have produced anything", ci.GetCurrentCommandBuffer(), ""); } static void Test_CommandInterpreter_TabCompletion_FullWord() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.AddKey('d'); ci.AddKey('u'); ci.AddKey('m'); ci.AddKey('m'); ci.AddKey('Z'); ci.AddKey('\2'); // CTRL-B = move left UnitTest::Assert("initial buffer contents mismatch", ci.GetCurrentCommandBuffer(), "dummZ"); ci.AddKey('\t'); UnitTest::Assert("tab completion should have failed", ci.GetCurrentCommandBuffer(), "dummZ"); int dummyInt = 42; ci.AddCommand(new DummyCommand2(dummyInt)); ci.AddKey('\t'); UnitTest::Assert("tab completion should have succeeded", ci.GetCurrentCommandBuffer(), "dummycommandZ"); ci.AddKey('X'); UnitTest::Assert("tab completion should have placed cursor at end of" " the tab-completed word", ci.GetCurrentCommandBuffer(), "dummycommandXZ"); } static void Test_CommandInterpreter_TabCompletion_SpacesFirstOnLine() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.AddKey(' '); ci.AddKey(' '); ci.AddKey('v'); ci.AddKey('e'); ci.AddKey('r'); ci.AddKey('s'); UnitTest::Assert("initial buffer contents mismatch", ci.GetCurrentCommandBuffer(), " vers"); ci.AddKey('\t'); UnitTest::Assert("tab completion should have succeeded", ci.GetCurrentCommandBuffer(), " version "); } static void Test_CommandInterpreter_TabCompletion_Partial() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.AddKey('d'); ci.AddKey('u'); ci.AddKey('m'); ci.AddKey('m'); ci.AddKey('Z'); ci.AddKey('\2'); // CTRL-B = move left UnitTest::Assert("initial buffer contents mismatch", ci.GetCurrentCommandBuffer(), "dummZ"); int dummyInt = 42; ci.AddCommand(new DummyCommand2(dummyInt)); ci.AddCommand(new DummyCommand3(dummyInt)); ci.AddKey('\t'); UnitTest::Assert("tab completion should have partially succeeded", ci.GetCurrentCommandBuffer(), "dummycZ"); } static void Test_CommandInterpreter_TabCompletion_C() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.AddKey('c'); UnitTest::Assert("initial buffer contents mismatch", ci.GetCurrentCommandBuffer(), "c"); ci.AddKey('\t'); UnitTest::Assert("tab completion should not have modified command", ci.GetCurrentCommandBuffer(), "c"); // ... because there are at least two possible commands on the // letter c: close and continue. } static void Test_CommandInterpreter_TabCompletion_OnlyCommandAsFirstWord() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.AddKey('v'); ci.AddKey('e'); ci.AddKey('r'); ci.AddKey('s'); UnitTest::Assert("initial buffer contents mismatch", ci.GetCurrentCommandBuffer(), "vers"); ci.AddKey('\t'); UnitTest::Assert("first tab completion should have succeeded", ci.GetCurrentCommandBuffer(), "version "); ci.AddKey('v'); ci.AddKey('e'); ci.AddKey('r'); ci.AddKey('s'); UnitTest::Assert("buffer contents mismatch", ci.GetCurrentCommandBuffer(), "version vers"); ci.AddKey('\t'); UnitTest::Assert("second tab completion should have failed", ci.GetCurrentCommandBuffer(), "version vers"); } static void Test_CommandInterpreter_TabCompletion_ComponentName() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add testmips"); UnitTest::Assert("initial buffer should be empty", ci.GetCurrentCommandBuffer(), ""); ci.AddKey('c'); ci.AddKey('p'); ci.AddKey('\t'); UnitTest::Assert("tab completion should have completed the " "component name", ci.GetCurrentCommandBuffer(), "cpu0"); // Note: No space after component tab completion. } static void Test_CommandInterpreter_TabCompletion_ComponentNameAlreadyComplete() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add testmips"); UnitTest::Assert("initial buffer should be empty", ci.GetCurrentCommandBuffer(), ""); ci.AddKey('c'); ci.AddKey('p'); ci.AddKey('u'); ci.AddKey('0'); ci.AddKey('\t'); UnitTest::Assert("tab completion should not have changed anything", ci.GetCurrentCommandBuffer(), "cpu0"); // Note: No space after component tab completion. } static void Test_CommandInterpreter_TabCompletion_ComponentNameMultiple() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add testmips"); ci.RunCommand("add mips_cpu mainbus0"); UnitTest::Assert("initial buffer should be empty", ci.GetCurrentCommandBuffer(), ""); ci.AddKey('c'); ci.AddKey('p'); ci.AddKey('\t'); UnitTest::Assert("there are both cpu0 and cpu1, so don't expand all the way", ci.GetCurrentCommandBuffer(), "cpu"); // Note: No space after component tab completion. } static void Test_CommandInterpreter_TabCompletion_ComponentNameMultipleParents() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add testmips"); // root.machine0 ci.RunCommand("add testmips"); // root.machine1 UnitTest::Assert("initial buffer should be empty", ci.GetCurrentCommandBuffer(), ""); ci.AddKey('c'); ci.AddKey('p'); ci.AddKey('\t'); UnitTest::Assert("there are cpu0 in both root.machine0 and root.machine1", ci.GetCurrentCommandBuffer(), "machine"); // Note: No space after component tab completion. } static void Test_CommandInterpreter_TabCompletion_ComponentNameNonexist() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add dummy"); UnitTest::Assert("initial buffer should be empty", ci.GetCurrentCommandBuffer(), ""); ci.AddKey('r'); ci.AddKey('o'); ci.AddKey('o'); ci.AddKey('t'); ci.AddKey('.'); ci.AddKey('X'); ci.AddKey('\t'); UnitTest::Assert("tab completion should not have succeeded", ci.GetCurrentCommandBuffer(), "root.X"); } static void Test_CommandInterpreter_TabCompletion_ComponentNameAsArgument() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add dummy root"); UnitTest::Assert("initial buffer should be empty", ci.GetCurrentCommandBuffer(), ""); ci.AddKey('a'); ci.AddKey('d'); ci.AddKey('d'); ci.AddKey(' '); ci.AddKey('d'); ci.AddKey('u'); ci.AddKey('m'); ci.AddKey('m'); ci.AddKey('y'); ci.AddKey(' '); ci.AddKey('d'); ci.AddKey('u'); UnitTest::Assert("buffer contents mismatch", ci.GetCurrentCommandBuffer(), "add dummy du"); ci.AddKey('\t'); UnitTest::Assert("tab completion should have completed the " "component name", ci.GetCurrentCommandBuffer(), "add dummy dummy0"); // Note: No space after component tab completion. } static void Test_CommandInterpreter_TabCompletion_CWithComponents() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add testmips"); ci.AddKey('c'); UnitTest::Assert("initial buffer contents mismatch", ci.GetCurrentCommandBuffer(), "c"); ci.AddKey('\t'); UnitTest::Assert("tab completion should not have modified command", ci.GetCurrentCommandBuffer(), "c"); // ... because there are at least two possible commands on the // letter c: close and continue. } static void Test_CommandInterpreter_TabCompletion_roWithComponents() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add testmips"); ci.AddKey('r'); ci.AddKey('o'); ci.AddKey('\t'); // there are both "rom0" and "root". UnitTest::Assert("tab completion should not have expanded", ci.GetCurrentCommandBuffer(), "ro"); ci.AddKey('o'); ci.AddKey('\t'); UnitTest::Assert("tab completion should have expanded to 'root'", ci.GetCurrentCommandBuffer(), "root"); } static void Test_CommandInterpreter_TabCompletion_ComponentMethods_Empty() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add testmips"); ci.AddKey('c'); ci.AddKey('p'); ci.AddKey('u'); ci.AddKey('.'); ci.AddKey('\t'); UnitTest::Assert("tab completion should have caused expansion", ci.GetCurrentCommandBuffer(), "cpu0."); } static void Test_CommandInterpreter_TabCompletion_ComponentMethods() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add testmips"); ci.AddKey('c'); ci.AddKey('p'); ci.AddKey('u'); ci.AddKey('.'); ci.AddKey('u'); ci.AddKey('\t'); UnitTest::Assert("tab completion should have caused expansion", ci.GetCurrentCommandBuffer(), "cpu0.unassemble"); } static void Test_CommandInterpreter_TabCompletion_ComponentMethods_Middle() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add testmips"); ci.AddKey('c'); ci.AddKey('p'); ci.AddKey('u'); ci.AddKey('.'); ci.AddKey('u'); ci.AddKey('n'); ci.AddKey('a'); ci.AddKey('b'); ci.AddKey('c'); ci.AddKey('d'); ci.AddKey('\2'); ci.AddKey('\2'); ci.AddKey('\2'); // cursor placed after "una" ci.AddKey('\t'); UnitTest::Assert("tab completion should have caused expansion", ci.GetCurrentCommandBuffer(), "cpu0.unassemblebcd"); } static void Test_CommandInterpreter_TabCompletion_ComponentMethods_Arg() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add testmips"); ci.AddKey('c'); ci.AddKey('p'); ci.AddKey('u'); ci.AddKey('.'); ci.AddKey('u'); ci.AddKey(' '); ci.AddKey('a'); ci.AddKey('d'); ci.AddKey('d'); ci.AddKey('r'); ci.AddKey('\2'); ci.AddKey('\2'); ci.AddKey('\2'); ci.AddKey('\2'); ci.AddKey('\2'); // cursor placed after "u" ci.AddKey('\t'); UnitTest::Assert("tab completion should have caused expansion", ci.GetCurrentCommandBuffer(), "cpu0.unassemble addr"); } static void Test_CommandInterpreter_TabCompletion_ComponentVariables() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add testmips"); ci.AddKey('c'); ci.AddKey('p'); ci.AddKey('u'); ci.AddKey('.'); ci.AddKey('g'); ci.AddKey('\t'); UnitTest::Assert("tab completion should have caused expansion cpu -> cpu0", ci.GetCurrentCommandBuffer(), "cpu0.gp"); } static void Test_CommandInterpreter_TabCompletion_ComponentVariables_Max() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add ram"); ci.AddKey('r'); ci.AddKey('a'); ci.AddKey('m'); ci.AddKey('.'); ci.AddKey('m'); ci.AddKey('e'); ci.AddKey('m'); ci.AddKey('o'); ci.AddKey('\t'); UnitTest::Assert("tab completion should have caused expansion ram -> ram0", ci.GetCurrentCommandBuffer(), "ram0.memoryMapped"); } static void Test_CommandInterpreter_TabCompletion_ComponentVariables_Max2() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); ci.RunCommand("add ram"); ci.AddKey('r'); ci.AddKey('a'); ci.AddKey('m'); ci.AddKey('.'); ci.AddKey('m'); ci.AddKey('e'); ci.AddKey('m'); ci.AddKey('o'); ci.AddKey(' '); ci.AddKey('2'); ci.AddKey('\2'); ci.AddKey('\2'); ci.AddKey('\t'); UnitTest::Assert("tab completion should have caused expansion ram -> ram0", ci.GetCurrentCommandBuffer(), "ram0.memoryMapped 2"); ci.AddKey('X'); UnitTest::Assert("cursor position after tab completion was wrong?", ci.GetCurrentCommandBuffer(), "ram0.memoryMappedX 2"); } static void Test_CommandInterpreter_NonExistingCommand() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); UnitTest::Assert("nonexisting (nonsense) command should fail", ci.RunCommand("nonexistingcommand") == false); } static void Test_CommandInterpreter_SimpleCommand() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); UnitTest::Assert("simple command should succeed", ci.RunCommand("version") == true); UnitTest::Assert("simple command with whitespace should succeed", ci.RunCommand(" version ") == true); } static void Test_CommandInterpreter_SimpleCommand_NoArgsAllowed() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); UnitTest::Assert("simple command should succeed", ci.RunCommand("version") == true); UnitTest::Assert("simple command which does not take arguments should" " fail when attempt is made to execute it with arguments", ci.RunCommand("version hello") == false); } static void Test_CommandInterpreter_ComponentMethods() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); UnitTest::Assert("Huh? Could not add testmips.", ci.RunCommand("add testmips") == true); UnitTest::Assert("component method 1", ci.RunCommand("cpu") == true); UnitTest::Assert("component method 2", ci.RunCommand("cpu.u") == true); UnitTest::Assert("component method 3", ci.RunCommand("cpu.urk") == false); UnitTest::Assert("component method 4", ci.RunCommand("cpu.unassemble") == true); UnitTest::Assert("component method 5", ci.RunCommand("root.machine0.mainbus0.cpu") == true); UnitTest::Assert("component method 6", ci.RunCommand("root.machine0.mainbus0.cpu0") == true); UnitTest::Assert("component method 7", ci.RunCommand("root.machine0.mainbus0.cpu.u") == true); UnitTest::Assert("component method 8", ci.RunCommand("root.machine0.mainbus0.cpu0.unassemble") == true); } static void Test_CommandInterpreter_ComponentVariables_NoArgs() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); UnitTest::Assert("Huh? Could not add testmips.", ci.RunCommand("add testmips") == true); UnitTest::Assert("component variable 1", ci.RunCommand("cpu.nonexistant") == false); UnitTest::Assert("component variable 2", ci.RunCommand("cpu.gp") == true); UnitTest::Assert("component variable 3", ci.RunCommand("root.machine0.mainbus0.cpu0.g") == true); } static void Test_CommandInterpreter_ComponentVariables_Ambiguous() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); UnitTest::Assert("Huh? Could not add testmips.", ci.RunCommand("add testmipsk") == true); UnitTest::Assert("cpu.t should not work, there should be multiple matches", ci.RunCommand("cpu.t") == false); } static void Test_CommandInterpreter_ComponentVariables_PartialIsOk() { GXemul gxemul; CommandInterpreter& ci = gxemul.GetCommandInterpreter(); UnitTest::Assert("Huh? Could not add testm88k.", ci.RunCommand("add testm88k") == true); // Make sure that r2 works, and doesn't complain about ambiguity. UnitTest::Assert("gpr 2", ci.RunCommand("cpu.r2") == true); UnitTest::Assert("gpr 29", ci.RunCommand("cpu.r29") == true); } UNITTESTS(CommandInterpreter) { // Key and current buffer: UNITTEST(Test_CommandInterpreter_AddKey_ReturnValue); UNITTEST(Test_CommandInterpreter_KeyBuffer); UNITTEST(Test_CommandInterpreter_KeyBuffer_CursorMovement); UNITTEST(Test_CommandInterpreter_KeyBuffer_CtrlK); UNITTEST(Test_CommandInterpreter_KeyBuffer_CtrlW); // Command History: UNITTEST(Test_CommandInterpreter_CommandHistory); // AddCommand / GetCommands: UNITTEST(Test_CommandInterpreter_AddCommand); // Tab completion: UNITTEST(Test_CommandInterpreter_TabCompletion_EmptyLine); UNITTEST(Test_CommandInterpreter_TabCompletion_FullWord); UNITTEST(Test_CommandInterpreter_TabCompletion_SpacesFirstOnLine); UNITTEST(Test_CommandInterpreter_TabCompletion_Partial); UNITTEST(Test_CommandInterpreter_TabCompletion_C); UNITTEST(Test_CommandInterpreter_TabCompletion_OnlyCommandAsFirstWord); UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentName); UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentNameAlreadyComplete); UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentNameMultiple); UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentNameMultipleParents); UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentNameNonexist); UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentNameAsArgument); UNITTEST(Test_CommandInterpreter_TabCompletion_CWithComponents); UNITTEST(Test_CommandInterpreter_TabCompletion_roWithComponents); UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentMethods_Empty); UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentMethods); UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentMethods_Middle); UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentMethods_Arg); UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentVariables); UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentVariables_Max); UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentVariables_Max2); // RunCommand: UNITTEST(Test_CommandInterpreter_NonExistingCommand); UNITTEST(Test_CommandInterpreter_SimpleCommand); UNITTEST(Test_CommandInterpreter_SimpleCommand_NoArgsAllowed); UNITTEST(Test_CommandInterpreter_ComponentMethods); UNITTEST(Test_CommandInterpreter_ComponentVariables_NoArgs); UNITTEST(Test_CommandInterpreter_ComponentVariables_Ambiguous); UNITTEST(Test_CommandInterpreter_ComponentVariables_PartialIsOk); } #endif gxemul-0.6.1/src/main/Checksum.cc000644 001750 001750 00000012753 13402411502 017021 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "Checksum.h" Checksum::Checksum() : m_value(0) { } uint64_t Checksum::Value() const { return m_value; } void Checksum::Add(uint64_t x) { m_value += x * (((uint64_t)0xc151429 << 32) | 0x517851bf); m_value ^= (((uint64_t)0x9183bfec << 32) | 0x01921947); } void Checksum::Add(const string& str) { size_t n = str.length(); Add(10000 + n); for (size_t i=0; i /* * GXemul specific changes to debug_new.cc: * * x) debug_new.cpp renamed debug_new.cc. * x) #include commented out. * x) (unsigned) added in some places to get rid of warnings. * x) a brief Doxygen section added to struct new_ptr_list_t's * comment * x) #print_position changed to print_position (removed the #), to * suppress a Doxygen warning * x) "@file" changed to "@ file" to suppress a Doxygen warning. * x) variable names in local scopes changed to allow usage of GCC's -Wshadow * x) a "catch point" added for catching specific (repeatable) allocations */ #ifndef NDEBUG // -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- // vim:tabstop=4:shiftwidth=4:expandtab: /* * Copyright (C) 2004-2005 Wu Yongwei * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any * damages arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute * it freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must * not claim that you wrote the original software. If you use this * software in a product, an acknowledgment in the product * documentation would be appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must * not be misrepresented as being the original software. * 3. This notice may not be removed or altered from any source * distribution. * * This file is part of Stones of Nvwa: * http://sourceforge.net/projects/nvwa * */ /** * @ file debug_new.cpp * * Implementation of debug versions of new and delete to check leakage. * * @version 3.16, 2005/11/22 * @author Wu Yongwei * */ #include #include #include #include #include #include #ifdef __unix__ // #include #endif #ifdef _WIN32 #include #endif #include "thirdparty/fast_mutex.h" #include "thirdparty/static_assert.h" #if !_FAST_MUTEX_CHECK_INITIALIZATION && !defined(_NOTHREADS) #error "_FAST_MUTEX_CHECK_INITIALIZATION not set: check_leaks may not work" #endif /** * @def _DEBUG_NEW_ALIGNMENT * * The alignment requirement of allocated memory blocks. It must be a * power of two. */ #ifndef _DEBUG_NEW_ALIGNMENT #define _DEBUG_NEW_ALIGNMENT 16 #endif /** * @def _DEBUG_NEW_CALLER_ADDRESS * * The expression to return the caller address. print_position will * later on use this address to print the position information of memory * operation points. */ #ifndef _DEBUG_NEW_CALLER_ADDRESS #ifdef __GNUC__ #define _DEBUG_NEW_CALLER_ADDRESS __builtin_return_address(0) #else #define _DEBUG_NEW_CALLER_ADDRESS NULL #endif #endif /** * @def _DEBUG_NEW_ERROR_ACTION * * The action to take when an error occurs. The default behaviour is to * call \e abort, unless \c _DEBUG_NEW_ERROR_CRASH is defined, in which * case a segmentation fault will be triggered instead (which can be * useful on platforms like Windows that do not generate a core dump * when \e abort is called). */ #ifndef _DEBUG_NEW_ERROR_ACTION #ifndef _DEBUG_NEW_ERROR_CRASH #define _DEBUG_NEW_ERROR_ACTION abort() #else #define _DEBUG_NEW_ERROR_ACTION do { *((char*)0) = 0; abort(); } while (0) #endif #endif /** * @def _DEBUG_NEW_FILENAME_LEN * * The length of file name stored if greater than zero. If it is zero, * only a const char pointer will be stored. Currently the default * behaviour is to copy the file name, because I found that the exit * leakage check cannot access the address of the file name sometimes * (in my case, a core dump will occur when trying to access the file * name in a shared library after a \c SIGINT). If the default value is * too small for you, try defining it to \c 52, which makes the size of * new_ptr_list_t 64 (it is 32 by default) on 32-bit platforms. */ #ifndef _DEBUG_NEW_FILENAME_LEN #define _DEBUG_NEW_FILENAME_LEN 20 #endif /** * @def _DEBUG_NEW_HASHTABLESIZE * * The size of the hash bucket for the table to store pointers to * allocated memory. To ensure good performance, always make it a power * of two. */ #ifndef _DEBUG_NEW_HASHTABLESIZE #define _DEBUG_NEW_HASHTABLESIZE 16384 #endif /** * @def _DEBUG_NEW_HASH * * The hash function for the pointers. This one has good performance in * test for me. */ #ifndef _DEBUG_NEW_HASH #define _DEBUG_NEW_HASH(p) (((size_t)(p) >> 8) % _DEBUG_NEW_HASHTABLESIZE) #endif /** * @def _DEBUG_NEW_PROGNAME * * The program (executable) name to be set at compile time. It is * better to assign the full program path to #new_progname in \e main * (at run time) than to use this (compile-time) macro, but this macro * serves well as a quick hack. Note also that double quotation marks * need to be used around the program name, i.e., one should specify a * command-line option like -D_DEBUG_NEW_PROGNAME=\"a.out\" * in \e bash, or -D_DEBUG_NEW_PROGNAME=\"a.exe\" in the * Windows command prompt. */ #ifndef _DEBUG_NEW_PROGNAME #define _DEBUG_NEW_PROGNAME NULL #endif /** * @def _DEBUG_NEW_USE_ADDR2LINE * * Whether to use \e addr2line to convert a caller address to file/line * information. Defining it to a non-zero value will enable the * conversion (automatically done if GCC is detected). Defining it to * zero will disable the conversion. */ #ifndef _DEBUG_NEW_USE_ADDR2LINE #ifdef __GNUC__ #define _DEBUG_NEW_USE_ADDR2LINE 1 #else #define _DEBUG_NEW_USE_ADDR2LINE 0 #endif #endif #ifdef _MSC_VER #pragma warning(disable: 4073) // #pragma init_seg(lib) used #pragma warning(disable: 4290) // C++ exception specification ignored #pragma init_seg(lib) #endif #undef _DEBUG_NEW_EMULATE_MALLOC #undef _DEBUG_NEW_REDEFINE_NEW /** * Macro to indicate whether redefinition of \c new is wanted. Here it * is defined to \c 0 to disable the redefinition of \c new. */ #define _DEBUG_NEW_REDEFINE_NEW 0 #include "thirdparty/debug_new.h" /** * Gets the aligned value of memory block size. */ #define align(s) \ (((s) + _DEBUG_NEW_ALIGNMENT - 1) & ~(_DEBUG_NEW_ALIGNMENT - 1)) /** * \brief Part of Wu Yongwei's new/delete debug * memory leak detector. * * Structure to store the position information where \c new occurs. */ struct new_ptr_list_t { new_ptr_list_t* next; union { #if _DEBUG_NEW_FILENAME_LEN == 0 const char* file; #else char file[_DEBUG_NEW_FILENAME_LEN]; #endif void* addr; }; int line; size_t size; }; /** * The extra memory allocated by operator new. */ const int aligned_list_item_size = align(sizeof(new_ptr_list_t)); /** * Array of pointer lists of a hash value. */ static new_ptr_list_t* new_ptr_list[_DEBUG_NEW_HASHTABLESIZE]; /** * Array of mutex guards to protect simultaneous access to the pointer * lists of a hash value. */ static fast_mutex new_ptr_lock[_DEBUG_NEW_HASHTABLESIZE]; /** * The mutex guard to protect simultaneous output to #new_output_fp. */ static fast_mutex new_output_lock; /** * Total memory allocated in bytes. */ static size_t total_mem_alloc = 0; /** * Flag to control whether #check_leaks will be automatically called on * program exit. */ bool new_autocheck_flag = true; /** * Flag to control whether verbose messages are output. */ bool new_verbose_flag = false; /** * Pointer to the output stream. The default output is \e stderr, and * one may change it to a user stream if needed (say, #new_verbose_flag * is \c true and there are a lot of (de)allocations). */ FILE* new_output_fp = stderr; /** * Pointer to the program name. Its initial value is the macro * #_DEBUG_NEW_PROGNAME. You should try to assign the program path to * it early in your application. Assigning argv[0] to it * in \e main is one way. If you use \e bash or \e ksh (or similar), * the following statement is probably what you want: * `new_progname = getenv("_");'. */ const char* new_progname = _DEBUG_NEW_PROGNAME; #if _DEBUG_NEW_USE_ADDR2LINE /** * Tries printing the position information from an instruction address. * This is the version that uses \e addr2line. * * @param addr the instruction address to convert and print * @return \c true if the address is converted successfully (and * the result is printed); \c false if no useful * information is got (and nothing is printed) */ static bool print_position_from_addr(const void* addr) { static const void* last_addr = NULL; static char last_info[256] = ""; if (addr == last_addr) { if (last_info[0] == '\0') return false; fprintf(new_output_fp, "%s", last_info); return true; } if (new_progname) { const char addr2line_cmd[] = "addr2line -e "; #if defined(__CYGWIN__) || defined(_WIN32) const int exeext_len = 4; #else const int exeext_len = 0; #endif #if !defined(__CYGWIN__) && defined(__unix__) const char ignore_err[] = " 2>/dev/null"; #elif defined(__CYGWIN__) || \ (defined(_WIN32) && defined(WINVER) && WINVER >= 0x0500) const char ignore_err[] = " 2>nul"; #else const char ignore_err[] = ""; #endif char* cmd = (char*)alloca(strlen(new_progname) + exeext_len + sizeof addr2line_cmd - 1 + sizeof ignore_err - 1 + sizeof(void*) * 2 + 4 /* SP + "0x" + null */); strcpy(cmd, addr2line_cmd); strcpy(cmd + sizeof addr2line_cmd - 1, new_progname); size_t len = strlen(cmd); #if defined(__CYGWIN__) || defined(_WIN32) if (len <= 4 || (strcmp(cmd + len - 4, ".exe") != 0 && strcmp(cmd + len - 4, ".EXE") != 0)) { strcpy(cmd + len, ".exe"); len += 4; } #endif sprintf(cmd + len, " %p%s", addr, ignore_err); FILE* fp = popen(cmd, "r"); if (fp) { char buffer[sizeof last_info] = ""; len = 0; if (fgets(buffer, sizeof buffer, fp)) { len = strlen(buffer); if (buffer[len - 1] == '\n') buffer[--len] = '\0'; } int res = pclose(fp); // Display the file/line information only if the command // is executed successfully and the output points to a // valid position, but the result will be cached if only // the command is executed successfully. if (res == 0 && len > 0) { last_addr = addr; if (buffer[len - 1] == '0' && buffer[len - 2] == ':') last_info[0] = '\0'; else { fprintf(new_output_fp, "%s", buffer); strcpy(last_info, buffer); return true; } } } } return false; } #else /** * Tries printing the position information from an instruction address. * This is the stub version that does nothing at all. * * @return \c false always */ static bool print_position_from_addr(const void*) { return false; } #endif // _DEBUG_NEW_USE_ADDR2LINE /** * Prints the position information of a memory operation point. When \c * _DEBUG_NEW_USE_ADDR2LINE is defined to a non-zero value, this * function will try to convert a given caller address to file/line * information with \e addr2line. * * @param ptr source file name if \e line is non-zero; caller address * otherwise * @param line source line number if non-zero; indication that \e ptr * is the caller address otherwise */ static void print_position(const void* ptr, int line) { line &= ~INT_MIN; // Result from new[] if highest bit set: Ignore if (line != 0) // Is file/line information present? { fprintf(new_output_fp, "%s:%d", (const char*)ptr, line); } else if (ptr != NULL) // Is caller address present? { if (!print_position_from_addr(ptr)) // Fail to get source position? fprintf(new_output_fp, "%p", ptr); } else // No information is present { fprintf(new_output_fp, ""); } } /** * Searches for the raw pointer given a user pointer. The term `raw * pointer' here refers to the pointer to the pointer to originally * malloc'd memory. * * @param pointer user pointer to search for * @param hash_index hash index of the user pointer * @return the raw pointer if searching is successful; or * \c NULL otherwise */ static new_ptr_list_t** search_pointer(void* pointer, size_t hash_index) { new_ptr_list_t** raw_ptr = &new_ptr_list[hash_index]; while (*raw_ptr) { if ((char*)*raw_ptr + aligned_list_item_size == pointer) { return raw_ptr; } raw_ptr = &(*raw_ptr)->next; } return NULL; } /** * Frees memory and adjusts pointers relating to a raw pointer. If the * highest bit of \c line (set from a previous new[] call) * does not agree with \c array_mode, program will abort with an error * message. * * @param raw_ptr raw pointer to free * @param addr pointer to the caller * @param array_mode flag indicating whether it is invoked by a * delete[] call */ static void free_pointer(new_ptr_list_t** raw_ptr, void* addr, bool array_mode) { new_ptr_list_t* ptr = *raw_ptr; int array_mode_mismatch = array_mode ^ ((ptr->line & INT_MIN) != 0); if (array_mode_mismatch) { const char* msg; if (array_mode) msg = "delete[] after new"; else msg = "delete after new[]"; fast_mutex_autolock lock(new_output_lock); fprintf(new_output_fp, "%s: pointer %p (size %u)\n\tat ", msg, (char*)ptr + aligned_list_item_size, (unsigned) ptr->size); print_position(addr, 0); fprintf(new_output_fp, "\n\toriginally allocated at "); if ((ptr->line & ~INT_MIN) != 0) print_position(ptr->file, ptr->line); else print_position(ptr->addr, ptr->line); fprintf(new_output_fp, "\n"); fflush(new_output_fp); _DEBUG_NEW_ERROR_ACTION; } total_mem_alloc -= ptr->size; if (new_verbose_flag) { fast_mutex_autolock lock(new_output_lock); fprintf(new_output_fp, "delete: freeing %p (size %u, %u bytes still allocated)\n", (char*)ptr + aligned_list_item_size, (unsigned) ptr->size, (unsigned) total_mem_alloc); } *raw_ptr = ptr->next; memset(ptr, 0xdd, ptr->size + aligned_list_item_size); free(ptr); return; } /** * Checks for memory leaks. * * @return zero if no leakage is found; the number of leaks otherwise */ int check_leaks() { int leak_cnt = 0; for (int i = 0; i < _DEBUG_NEW_HASHTABLESIZE; ++i) { fast_mutex_autolock lock(new_ptr_lock[i]); new_ptr_list_t* ptr = new_ptr_list[i]; if (ptr == NULL) continue; while (ptr) { fast_mutex_autolock lock2(new_output_lock); fprintf(new_output_fp, "Leaked object at %p (size %u, ", (char*)ptr + aligned_list_item_size, (unsigned) ptr->size); if ((ptr->line & ~INT_MIN) != 0) print_position(ptr->file, ptr->line); else print_position(ptr->addr, ptr->line); fprintf(new_output_fp, ")\n"); ptr = ptr->next; ++leak_cnt; } } return leak_cnt; } void* operator new(size_t size, const char* file, int line) { assert((line & INT_MIN) == 0); STATIC_ASSERT((_DEBUG_NEW_ALIGNMENT & (_DEBUG_NEW_ALIGNMENT - 1)) == 0, Alignment_must_be_power_of_two); size_t s = size + aligned_list_item_size; new_ptr_list_t* ptr = (new_ptr_list_t*)malloc(s); if (ptr == NULL) { fast_mutex_autolock lock(new_output_lock); fprintf(new_output_fp, "new: out of memory when allocating %u bytes\n", (unsigned) size); fflush(new_output_fp); _DEBUG_NEW_ERROR_ACTION; } void* pointer = (char*)ptr + aligned_list_item_size; // GXemul hack/addition: Crash on a specific allocation. Useful // for getting a call stack for a memory leak, at the point where the // actual allocation took place. (Only possible if the address is // stable over multiple runs.) if ((size_t)pointer == 0xfefefefecdcdcdcdULL) { static int counter = 0; counter ++; std::cerr << "--> MEMORY LEAK CATCH POINT, counter = " << counter << "\n"; if (counter == -42) { abort(); } } size_t hash_index = _DEBUG_NEW_HASH(pointer); #if _DEBUG_NEW_FILENAME_LEN == 0 ptr->file = file; #else if (line) strncpy(ptr->file, file, _DEBUG_NEW_FILENAME_LEN - 1) [_DEBUG_NEW_FILENAME_LEN - 1] = '\0'; else ptr->addr = (void*)file; #endif ptr->line = line; ptr->size = size; { fast_mutex_autolock lock(new_ptr_lock[hash_index]); ptr->next = new_ptr_list[hash_index]; new_ptr_list[hash_index] = ptr; } if (new_verbose_flag) { fast_mutex_autolock lock(new_output_lock); fprintf(new_output_fp, "new: allocated %p (size %u, ", pointer, (unsigned) size); if (line != 0) print_position(ptr->file, ptr->line); else print_position(ptr->addr, ptr->line); fprintf(new_output_fp, ")\n"); } total_mem_alloc += size; return pointer; } void* operator new[](size_t size, const char* file, int line) { void* pointer = operator new(size, file, line); new_ptr_list_t* ptr = (new_ptr_list_t*)((char*)pointer - aligned_list_item_size); assert((ptr->line & INT_MIN) == 0); ptr->line |= INT_MIN; // Result from new[] if highest bit set: Set return pointer; } void* operator new(size_t size) throw(std::bad_alloc) { return operator new(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); } void* operator new[](size_t size) throw(std::bad_alloc) { return operator new[](size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); } #if !defined(__BORLANDC__) || __BORLANDC__ > 0x551 void* operator new(size_t size, const std::nothrow_t&) throw() { return operator new(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); } void* operator new[](size_t size, const std::nothrow_t&) throw() { return operator new[](size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); } #endif void operator delete(void* pointer) throw() { if (pointer == NULL) return; size_t hash_index = _DEBUG_NEW_HASH(pointer); fast_mutex_autolock lock(new_ptr_lock[hash_index]); new_ptr_list_t** raw_ptr = search_pointer(pointer, hash_index); if (raw_ptr == NULL) { fast_mutex_autolock lock2(new_output_lock); fprintf(new_output_fp, "delete: invalid pointer %p at ", pointer); print_position(_DEBUG_NEW_CALLER_ADDRESS, 0); fprintf(new_output_fp, "\n"); fflush(new_output_fp); _DEBUG_NEW_ERROR_ACTION; } free_pointer(raw_ptr, _DEBUG_NEW_CALLER_ADDRESS, false); } void operator delete[](void* pointer) throw() { if (pointer == NULL) return; size_t hash_index = _DEBUG_NEW_HASH(pointer); fast_mutex_autolock lock(new_ptr_lock[hash_index]); new_ptr_list_t** raw_ptr = search_pointer(pointer, hash_index); if (raw_ptr == NULL) { fast_mutex_autolock lock2(new_output_lock); fprintf(new_output_fp, "delete[]: invalid pointer %p at ", pointer); print_position(_DEBUG_NEW_CALLER_ADDRESS, 0); fprintf(new_output_fp, "\n"); fflush(new_output_fp); _DEBUG_NEW_ERROR_ACTION; } free_pointer(raw_ptr, _DEBUG_NEW_CALLER_ADDRESS, true); } #if HAS_PLACEMENT_DELETE void operator delete(void* pointer, const char* file, int line) throw() { if (new_verbose_flag) { fast_mutex_autolock lock(new_output_lock); fprintf(new_output_fp, "info: exception thrown on initializing object at %p (", pointer); print_position(file, line); fprintf(new_output_fp, ")\n"); } operator delete(pointer); } void operator delete[](void* pointer, const char* file, int line) throw() { if (new_verbose_flag) { fast_mutex_autolock lock(new_output_lock); fprintf(new_output_fp, "info: exception thrown on initializing objects at %p (", pointer); print_position(file, line); fprintf(new_output_fp, ")\n"); } operator delete[](pointer); } void operator delete(void* pointer, const std::nothrow_t&) throw() { operator delete(pointer, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); } void operator delete[](void* pointer, const std::nothrow_t&) throw() { operator delete[](pointer, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); } #endif // HAS_PLACEMENT_DELETE int __debug_new_counter::_count = 0; /** * Constructor to increment the count. */ __debug_new_counter::__debug_new_counter() { ++_count; } /** * Destructor to decrement the count. When the count is zero, * #check_leaks will be called. */ __debug_new_counter::~__debug_new_counter() { if (--_count == 0 && new_autocheck_flag) if (check_leaks()) { new_verbose_flag = true; #if defined(__GNUC__) && __GNUC__ >= 3 if (!getenv("GLIBCPP_FORCE_NEW") && !getenv("GLIBCXX_FORCE_NEW")) fprintf(new_output_fp, "*** WARNING: GCC 3 or later is detected, please make sure the\n" " environment variable GLIBCPP_FORCE_NEW (GCC 3.2 and 3.3) or\n" " GLIBCXX_FORCE_NEW (GCC 3.4 and later) is defined. Check the\n" " README file for details.\n"); #endif } } #endif // NDEBUG gxemul-0.6.1/src/main/EscapedString.cc000644 001750 001750 00000011667 13402411502 020015 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "EscapedString.h" EscapedString::EscapedString(const string& str) : m_str(str) { } string EscapedString::Generate() const { string result = "\""; for (size_t i=0; imain documentation for more * information about this version of %GXemul. * * See GXemul's home page for more information about %GXemul in general: * http://gxemul.sourceforge.net/ * * (NOTE: There is a huge portion of code in * %GXemul which is legacy code. The documentation you will find on this page * is only about the new framework, which is available from release 0.6.0.) * * The main program creates a GXemul instance, and does one of two things: *
    *
  • Starts without any template %machine. (-V) *
  • Starts with a template %machine, and a list of additional * components and files * to attempt to attach (usually kernel binary to boot in the * emulated %machine). *
* * After letting the %GXemul instance load the files (or, in the more general * case, attach the components), GXemul::Run() is called. * This is the main loop. It doesn't really do much, it simply calls the UI's * main loop, i.e. ConsoleUI::MainLoop(). * * Most of the source code in %GXemul centers around a few core concepts. * An overview of these concepts are given below. Anyone who wishes to * delve into the source code should be familiar with them. * * * \section concepts_sec Core concepts * * See the end-user description of the framework * for information about how these concepts appear to the actual user. The * sections below describe how those concepts are implemented in the code. * * \subsection components_subsec Components * * The most important core concept in %GXemul is the Component. Examples of * components are processors, networks interface cards, video displays, RAM * %memory, busses, %interrupt controllers, and all other kinds of devices. * * Each component has a parent, so the full set of components in an emulation * are in fact a tree. A GXemul instance has one such tree. The root * component is a special RootComponent, which holds some basic state about * the emulation, such as the number of steps executed. * It also contains zero or more sub-components. * *
* * Starting from the root node, each component has a path, e.g. * root.machine1.mainbus0.ram0 for the RAM component in machine1 * in the example above. * * The state of each component is stored within that component. The state * consists of a number of variables (see StateVariable) such as strings, * integers, bools, and other more high-level types such as zero-filled %memory * arrays. Such %memory arrays are used e.g. by the RAMComponent to emulate * RAM, and can also be used to emulate video framebuffer %memory. * * Individual components are implemented in src/components/, with * header files in src/include/components/. The configure * script looks for the string COMPONENT(name) in the header files, * and automagically adds those to the list of components that will be * available at runtime. In addition, make documentation also builds * HTML pages with lists of available * components, and as a special case, * a list of available * template machines (because they have * special meaning to the end-user). * * \subsection commandinterpreter_subsec Command interpreter * * A GXemul instance has a CommandInterpreter, which is the part that parses a * command line, figures out which Command is to be executed, and executes it. * The %CommandInterpreter can be given a complete command line as a string, or * it can be given one character (or keypress) at a time. In the later case, * the TAB key either completes the word currently being written, or writes * out a list of possible completions. * * The %CommandInterpreter, via the ConsoleUI, is the user interface as seen * by the user. * * \subsection unittest_subsec Unit tests * * Wherever it makes sense, unit tests should be written to make sure * that the code is correct, and stays correct. The UnitTest class contains * static helper functions for writing unit tests, such as UnitTest::Assert. * To add unit tests to a class, the class should be UnitTestable, and in * particular, it should implement UnitTestable::RunUnitTests by using the * UNITTESTS(className) macro. Individual test cases are then called, as * static non-member functions, using the UNITTEST(testname) macro. * * Since test cases are non-member functions, they need to create instances * of the class they wish to test, and they can only call public member * functions on those objects, not private ones. Thus, the unit tests only * test the "public API" of all classes. (If the internal API needs to be * tested, then a workaround can be to add a ConsistencyCheck member function * which is public, but mentioning in the documentation for that function * that it is only meant for internal use and debugging.) * * Unit tests are normally executed by make test. This is implicitly * done when doing make install as well. * * It is recommended to run the configure script with the * --debug option during development; among other things, this enables * use of Wu Yongwei's new/debug %memory * leak detector (part of * Stones of NVWA). */ /*****************************************************************************/ #include "ConsoleUI.h" #include "NullUI.h" #include "GXemul.h" #include "components/RootComponent.h" #include "ComponentFactory.h" #include "UnitTest.h" #include #include #include #include #include #include #include GXemul::GXemul() : m_quietMode(false) , m_ui(new NullUI(this)) , m_commandInterpreter(this) , m_runState(Paused) , m_interrupting(false) , m_nrOfSingleStepsLeft(1) , m_rootComponent(new RootComponent(this)) , m_snapshottingEnabled(false) { gettimeofday(&m_lastOutputTime, NULL); m_lastOutputStep = 0; ClearEmulation(); } void GXemul::ClearEmulation() { if (GetRunState() == Running) SetRunState(Paused); m_rootComponent = new RootComponent(this); m_emulationFileName = ""; GetUI()->UpdateUI(); } bool GXemul::IsTemplateMachine(const string& templateName) const { string nameWithoutArgs = templateName; size_t p = nameWithoutArgs.find('('); if (p > 0) nameWithoutArgs = templateName.substr(0, p); if (!ComponentFactory::HasAttribute(nameWithoutArgs, "template")) return false; if (!ComponentFactory::HasAttribute(nameWithoutArgs, "machine")) return false; return true; } bool GXemul::CreateEmulationFromTemplateMachine(const string& templateName) { if (!IsTemplateMachine(templateName)) { std::cerr << templateName << " is not a known template machine name.\n" "Use gxemul -H to get a list of valid machine templates.\n"; return false; } refcount_ptr machine = ComponentFactory::CreateComponent(templateName, this); if (machine.IsNULL()) return false; GetRootComponent()->AddChild(machine); return true; } void GXemul::ListTemplates() { std::cout << "Available template machines:\n\n"; vector names = ComponentFactory::GetAllComponentNames(true); size_t maxNameLen = 0; for (size_t i=0; i maxNameLen) maxNameLen = names[i].length(); for (size_t i=0; i component = ComponentFactory::CreateComponent(machineName); if (!component.IsNULL() && component->GetChildren().size() != 0) std::cout << "
" <<
		    component->GenerateTreeDump("", true, "../")
		    << "
"; } void GXemul::GenerateHTMLListOfComponents(bool machines) { std::cout << "Available " << (machines? "template machines" : "components") << ":\n" "

\n" "\n" " \n"; if (machines) std::cout << " \n"; std::cout << #ifdef UNSTABLE_DEVEL " \n" #endif " \n" " \n" " \n" "\n"; bool everyOther = false; vector names = ComponentFactory::GetAllComponentNames(false); for (size_t i=0; i creatable = ComponentFactory::CreateComponent(componentName); if (creatable.IsNULL()) continue; bool isTemplateMachine = !ComponentFactory::GetAttribute( componentName, "machine").empty() && !ComponentFactory::GetAttribute( componentName, "template").empty(); if (machines) { if (!isTemplateMachine) continue; } else { // Other components: Don't include template machines. if (isTemplateMachine) continue; } // Include an ASCII tree dump for template components that // have children: if (!ComponentFactory::GetAttribute( componentName, "template").empty()) { refcount_ptr component = ComponentFactory::CreateComponent(componentName); if (!component.IsNULL() && component->GetChildren().size() != 0) treeDump = "
" +
				    component->GenerateTreeDump("", true)
				    + "
"; } // Some distance between table entries: std::cout << "
\n" " " "\n"; std::cout << "\n"; // Include a href link to a "full html page" for a component, // if it exists: std::ifstream documentationComponentFile(( "doc/components/component_" + componentName + ".html").c_str()); std::ifstream documentationMachineFile(( "doc/machines/machine_" + componentName + ".html").c_str()); if (documentationComponentFile.is_open()) std::cout << " \n"; else if (documentationMachineFile.is_open()) std::cout << " \n"; else std::cout << " \n"; if (machines) { // Include an img and a href link to a screenshot for a component, // if it exists: std::ifstream screenshotThumbFile(( "doc/machines/machine_" + componentName + "-thumb.png").c_str()); std::ifstream screenshotLargeFile(( "doc/machines/machine_" + componentName + ".png").c_str()); std::cout << " \n"; } std::cout << #ifdef UNSTABLE_DEVEL " \n" #endif " \n" " \n" " \n" "\n"; everyOther = !everyOther; } std::cout << "
" << (machines? "Machine name" : "Component name") << ":" "  Screenshot:  Status:  Description:  Comments:  Contributors:  
" "" << componentName << "" "" << componentName << "" << componentName << ""; if (screenshotLargeFile.is_open()) std::cout << ""; if (screenshotThumbFile.is_open()) std::cout << ""; else if (screenshotLargeFile.is_open()) std::cout << "(screenshot)"; if (screenshotLargeFile.is_open()) std::cout << ""; std::cout << "" << (ComponentFactory::HasAttribute( componentName, "stable")? "stable  " : "experimental  ") << "" << ComponentFactory::GetAttribute( componentName, "description") << treeDump << "" << ComponentFactory::GetAttribute( componentName, "comments") << "" << ComponentFactory::GetAttribute( componentName, "contributors") << "

\n"; } bool GXemul::ParseFilenames(string templateMachine, int filenameCount, char *filenames[]) { bool optionsEnoughToStartRunning = false; if (templateMachine != "") { if (CreateEmulationFromTemplateMachine(templateMachine)) { // A template is now being used. } else { std::cerr << "Failed to create configuration from " "template: " << templateMachine << "\n" << "Aborting." << "\n"; return false; } } // 1. If a machine template has been selected, then treat the following // arguments as arguments to the 'add' command. // // 2. Otherwise, treat the argument as a configuration file. if (filenameCount > 0) { if (templateMachine != "") { // Machine template. while (filenameCount > 0) { stringstream cmd; // TODO: Different syntax! // Use "add" with different syntax here... cmd << "load " << filenames[0] << " root.machine0.mainbus0.cpu0"; // TODO: Get rid of this onReset mechanism! m_onResetCommands.push_back(cmd.str()); filenameCount --; filenames ++; } optionsEnoughToStartRunning = true; } else { // Config file. if (filenameCount == 1) { string configfileName = filenames[0]; optionsEnoughToStartRunning = true; string cmd = "load " + configfileName; m_onResetCommands.push_back(cmd); } else { std::cerr << "More than one configfile name " "supplied on the command line?" << "\n" << "Aborting." << "\n"; return false; } } } if (optionsEnoughToStartRunning) { return true; } else { if (templateMachine != "") { if (GetRunState() == Paused) return true; std::cerr << "No binary specified. Usually when starting up an emulation based on a template\n" "machine, you need to supply one or more binaries. This could be an operating\n" "system kernel, a ROM image, or something similar.\n" "\n" "You can also use the -V option to start in paused mode, and load binaries\n" "interactively.\n" "\n" "(Run gxemul -h for more help on command line options.)\n"; return false; } PrintUsage(); return false; } } string GXemul::Version() { stringstream ss; ss << "GXemul " #ifdef VERSION << VERSION #else << "(unknown version)" #endif << " " COPYRIGHT_MSG"\n" SECONDARY_MSG; return ss.str(); } void GXemul::PrintUsage() const { std::cout << Version() << "\n"; std::cout << "Insufficient command line arguments given to" " start an emulation. You have\n" "the following alternatives:\n" << "\n" << " 1. Run gxemul with the machine selection option " "(-e), which creates\n" " a default emulation from a template machine.\n\n" " 2. Run gxemul with a configuration file (.gxemul).\n" " This is useful for more complicated setups.\n\n" " 3. Run gxemul -V with no other options, which causes" " gxemul to be started\n" " with no emulation loaded at all.\n\n" << "\n" << "Run gxemul -h for help on command line options.\n\n"; } void GXemul::InitUI() { // Default to the console UI: m_ui = new ConsoleUI(this); // Once a GUI has been implemented, this is the // place to call its constructor. TODO GetUI()->Initialize(); } int GXemul::Run() { // Not really running yet: RunState savedRunState = GetRunState(); SetRunState(Paused); if (!GetQuietMode()) { GetUI()->ShowStartupBanner(); // Dump (a suitable part of) the configuration tree at startup. const Component* component = GetRootComponent(); if (component->GetChildren().size() > 0) { while (true) { int nChildren = component->GetChildren().size(); if (nChildren == 0 || nChildren > 1) break; component = component->GetChildren()[0]; } GetUI()->ShowDebugMessage(component->GenerateTreeDump("") + "\n"); } } if (!Reset()) { GetUI()->ShowDebugMessage("Aborting.\n"); return 1; } if (!GetQuietMode()) { // A separator line, if we start emulating directly without dropping // into the interactive debugger. (To mimic pre-0.6.0 appearance.) if (savedRunState == Running) GetUI()->ShowDebugMessage("--------------------------------" "-----------------------------------------------\n\n"); } SetRunState(savedRunState); try { GetUI()->MainLoop(); } catch (std::exception& ex) { stringstream ss; ss << "\n### FATAL ERROR ###\n\n" << ex.what() << "\n\n" << "If you are able to reproduce this crash, " "please send detailed repro-steps to\n" "the author, to the gxemul-devel mailing list, or" " ask in #GXemul on the\n" "FreeNode IRC network.\n"; GetUI()->FatalError(ss.str()); return 1; } return 0; } const string& GXemul::GetEmulationFilename() const { return m_emulationFileName; } void GXemul::SetEmulationFilename(const string& filename) { m_emulationFileName = filename; GetUI()->UpdateUI(); } CommandInterpreter& GXemul::GetCommandInterpreter() { return m_commandInterpreter; } uint64_t GXemul::GetStep() const { const StateVariable* step = GetRootComponent()->GetVariable("step"); if (step == NULL) { std::cerr << "root component has no 'step' variable? aborting.\n"; throw std::exception(); } return step->ToInteger(); } void GXemul::SetStep(uint64_t step) { StateVariable* stepVariable = GetRootComponent()->GetVariable("step"); if (stepVariable == NULL) { std::cerr << "root component has no 'step' variable? aborting.\n"; throw std::exception(); } stepVariable->SetValue(step); } UI* GXemul::GetUI() { return m_ui; } refcount_ptr GXemul::GetRootComponent() { return m_rootComponent; } const refcount_ptr GXemul::GetRootComponent() const { return m_rootComponent; } void GXemul::SetRootComponent(refcount_ptr newRootComponent) { if (newRootComponent.IsNULL()) { std::cerr << "GXemul::SetRootComponent: NULL\n"; throw std::exception(); } RootComponent* rootComponent = newRootComponent->AsRootComponent(); if (rootComponent == NULL) { std::cerr << "GXemul::SetRootComponent: not a RootComponent\n"; throw std::exception(); } rootComponent->SetOwner(this); m_rootComponent = newRootComponent; GetUI()->UpdateUI(); } bool GXemul::Reset() { // 1. Reset all components in the tree. GetRootComponent()->Reset(); // 2. Run "on reset" commands. (These are usually commands to load // binaries into CPUs.) vector::const_iterator it = m_onResetCommands.begin(); for (; it != m_onResetCommands.end(); ++it) { string cmd = *it; bool success = false; GetCommandInterpreter().RunCommand(cmd, &success); if (!GetQuietMode()) GetUI()->ShowDebugMessage("\n"); if (!success) { GetUI()->ShowDebugMessage("Failing on-reset command:\n" " " + cmd + "\n"); return false; } } return true; } void GXemul::Interrupt() { switch (GetRunState()) { case SingleStepping: case Running: m_interrupting = true; break; default: m_interrupting = false; } } void GXemul::SetRunState(RunState newState) { m_runState = newState; GetUI()->UpdateUI(); } GXemul::RunState GXemul::GetRunState() const { return m_runState; } string GXemul::GetRunStateAsString() const { switch (m_runState) { case Paused: return "Paused"; case SingleStepping: return "Single-stepping"; case Running: return "Running"; case Quitting: return "Quitting"; } return "Unknown RunState"; } bool GXemul::GetSnapshottingEnabled() const { return m_snapshottingEnabled; } void GXemul::SetSnapshottingEnabled(bool enabled) { if (enabled) GetUI()->ShowDebugMessage("(Enabling " "snapshotting/reverse execution support.)\n"); m_snapshottingEnabled = enabled; } bool GXemul::GetQuietMode() const { return m_quietMode; } void GXemul::SetQuietMode(bool quietMode) { m_quietMode = quietMode; } void GXemul::SetNrOfSingleStepsInARow(uint64_t steps) { if (steps < 1) steps = 1; m_nrOfSingleStepsLeft = steps; } bool GXemul::ModifyStep(int64_t oldStep, int64_t newStep) { if (!GetSnapshottingEnabled()) return false; if (oldStep == newStep) return true; if (newStep < oldStep) { // Run in reverse, by running forward from the most suitable // snapshot. // TODO: Multiple snapshots! refcount_ptr newRoot = m_snapshot->Clone(); SetRootComponent(newRoot); // GetStep will now return the step count for the new root. int64_t nrOfStepsToRunFromSnapshot = newStep - GetStep(); RunState oldRunState = GetRunState(); SetRunState(Running); Execute(nrOfStepsToRunFromSnapshot); SetRunState(oldRunState); } else { // Run forward, by setting a step breakpoint. GetUI()->ShowDebugMessage("TODO: run forward by setting a step breakpoint!\n"); return false; } return true; } void GXemul::TakeSnapshot() { // TODO: Multiple snapshots! if (m_snapshot.IsNULL()) { stringstream ss; ss << "(snapshot at step " << GetStep() << ")\n"; GetUI()->ShowDebugMessage(ss.str()); m_snapshot = GetRootComponent()->Clone(); } } struct ComponentAndFrequency { refcount_ptr component; double frequency; StateVariable* step; uint64_t nextTimeToExecute; }; // Gathers a list of components and their frequencies. (Only components that // have a variable named "frequency" are executable.) static void GetComponentsAndFrequencies(refcount_ptr component, vector& componentsAndFrequencies) { const StateVariable* paused = component->GetVariable("paused"); const StateVariable* freq = component->GetVariable("frequency"); StateVariable* step = component->GetVariable("step"); if (freq != NULL && step != NULL && (paused == NULL || paused->ToInteger() == 0)) { struct ComponentAndFrequency caf; caf.component = component; caf.frequency = freq->ToDouble(); caf.step = step; caf.nextTimeToExecute = 0; componentsAndFrequencies.push_back(caf); } Components children = component->GetChildren(); for (size_t i=0; i componentsAndFrequencies; GetComponentsAndFrequencies(GetRootComponent(), componentsAndFrequencies); if (componentsAndFrequencies.size() == 0) { GetUI()->ShowDebugMessage("No executable components" " found in the configuration.\n"); SetRunState(Paused); return; } // Take an initial snapshot at step 0, if snapshotting is enabled: if (m_snapshottingEnabled && GetStep() == 0) TakeSnapshot(); // Find the fastest component: double fastestFrequency = componentsAndFrequencies[0].frequency; size_t fastestComponentIndex = 0; for (size_t i=0; i fastestFrequency) { fastestFrequency = componentsAndFrequencies[i].frequency; fastestComponentIndex = i; } bool printEmptyLineBetweenSteps = false; switch (GetRunState()) { case SingleStepping: if (m_nrOfSingleStepsLeft == 0) m_nrOfSingleStepsLeft = 1; // Note that setting run state to something else, OR // decreasing nr of single steps left to 0, will break the loop. while (!m_interrupting && m_nrOfSingleStepsLeft > 0 && GetRunState() == SingleStepping) { uint64_t step = GetStep(); if (printEmptyLineBetweenSteps) GetUI()->ShowDebugMessage("\n"); else printEmptyLineBetweenSteps = true; stringstream ss; ss << "step " << step << ": "; // Indent all debug output with message header "step X: ": UI::SetIndentationMessageHelper indentationHelper(GetUI(), ss.str()); ++ step; // Component X, using frequency fX, should have executed // nstepsX = steps * fX / fastestFrequency nr of steps. for (size_t k=0; kToInteger(); if (stepsExecutedSoFar > nsteps) { std::cerr << "Internal error: " << componentsAndFrequencies[k].component->GetVariable("name")->ToString() << " has executed " << stepsExecutedSoFar << " steps, goal is " << nsteps << ".\n"; throw std::exception(); } if (stepsExecutedSoFar < nsteps) { ++ stepsExecutedSoFar; const refcount_ptr lightClone = GetRootComponent()->LightClone(); // Execute one step... int n = componentsAndFrequencies[k].component->Execute(this, 1); if (n != 1) { GetUI()->ShowDebugMessage("Single-stepping aborted.\n"); SetRunState(Paused); return; } // ... and write back the number of executed steps: componentsAndFrequencies[k].step->SetValue(stepsExecutedSoFar); // Now, let's compare the clone of the component tree // before execution with what we have now. stringstream changeMessages; GetRootComponent()->DetectChanges(lightClone, changeMessages); string msg = changeMessages.str(); if (msg.length() > 0) GetUI()->ShowDebugMessage(msg); } } SetStep(step); -- m_nrOfSingleStepsLeft; } // Done. Let's pause again. SetRunState(Paused); m_nrOfSingleStepsLeft = 0; break; case Running: { uint64_t step = GetStep(); uint64_t startingStep = step; // TODO: sloppy vs cycle accuracy. if (GetRootComponent()->GetVariable("accuracy")->ToString() != "cycle") { std::cerr << "GXemul::Execute(): TODO: Only " "root.accuracy=\"cycle\" is currently supported\n"; SetRunState(Paused); return; } // The following code is for cycle accurate emulation: while (step < startingStep + longestTotalRun) { if (m_interrupting || GetRunState() != Running) break; int toExecute = -1; if (componentsAndFrequencies.size() == 1) { toExecute = longestTotalRun; componentsAndFrequencies[0].nextTimeToExecute = step; } else { // First, calculate the next time step when each // component k will execute. // // For n = 0,1,2,3, ... // n * fastestFrequency / componentsAndFrequencies[k].frequency // are the steps at which the component executes // (when rounded UP! i.e. executing at step 4.2 means that it // did not execute at step 4, but will at step 5). for (size_t k=0; kToInteger()+1) * q; componentsAndFrequencies[k].nextTimeToExecute = (uint64_t) ceil(c) - 1; } // std::cerr << "step " << step << " debug:\n"; for (size_t k=0; kGetVariable("name")->ToString() // << ": " << componentsAndFrequencies[k].nextTimeToExecute << "\n"; int diff = componentsAndFrequencies[k].nextTimeToExecute - componentsAndFrequencies[fastestComponentIndex].nextTimeToExecute; if (k != fastestComponentIndex) { if (toExecute == -1 || diff < toExecute) toExecute = diff; } } if (toExecute < 1) toExecute = 1; } if (step + toExecute > startingStep + longestTotalRun) toExecute = startingStep + longestTotalRun - step; // std::cerr << " toExecute = " << toExecute << "\n"; // Run the components. // If multiple components are to run at the same time (i.e. // same nextTimeToExecute), toExecute will be exactly 1. int maxExecuted = 0; bool abort = false; for (size_t k=0; kExecute(this, toExecute); // ... and write back the number of executed steps: uint64_t stepsExecutedSoFar = n + componentsAndFrequencies[k].step->ToInteger(); componentsAndFrequencies[k].step->SetValue(stepsExecutedSoFar); if (k == fastestComponentIndex) maxExecuted = n; if (n != toExecute) { abort = true; if (n > toExecute) { std::cerr << "Internal error: " << n << " steps executed, toExecute = " << toExecute << "\n"; throw std::exception(); } stringstream ss; ss << "only " << n << " steps of " << toExecute << " executed."; GetUI()->ShowDebugMessage(componentsAndFrequencies[k].component, ss.str()); } } if (abort) { GetUI()->ShowDebugMessage("Continuous execution aborted.\n"); SetRunState(Paused); } if (maxExecuted == 0 && GetRunState() == Running) { std::cerr << "maxExecuted=0. internal error\n"; throw std::exception(); } step += maxExecuted; SetStep(step); } // Output nr of steps (and speed) every second: struct timeval tvend; gettimeofday(&tvend, NULL); double secondsSinceLastOutput = ((double)tvend.tv_sec + tvend.tv_usec / 1000000.0) - ((double)m_lastOutputTime.tv_sec + m_lastOutputTime.tv_usec / 1000000.0); if (secondsSinceLastOutput > 1.0 && (step - m_lastOutputStep) > 10000) { m_lastOutputTime = tvend; int64_t stepsPerSecond = (int64_t) ( (double)(step - m_lastOutputStep) / secondsSinceLastOutput ); m_lastOutputStep = step; stringstream ss; ss << step << " steps"; if (stepsPerSecond > 0) ss << " (" << stepsPerSecond << " steps/second)"; GetUI()->ShowDebugMessage(ss.str()); } } break; default: std::cerr << "GXemul::Execute() called without being in a" " running state. Internal error?\n"; throw std::exception(); } if (m_interrupting) { m_interrupting = false; SetRunState(Paused); } } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_Construction() { GXemul gxemul; } UNITTESTS(GXemul) { UNITTEST(Test_Construction); // Note: Most execution tests are in DummyComponent.cc, because they // test component behavior. But they also test GXemul::Execute etc. } #endif gxemul-0.6.1/src/main/Command.cc000644 001750 001750 00000005503 13402411502 016630 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "Command.h" #include "GXemul.h" Command::Command(const string& name, const string& argumentFormat) : m_name(name) , m_argumentFormat(argumentFormat) { } Command::~Command() { } /*****************************************************************************/ #ifdef WITHUNITTESTS /** * \brief A dummy Command, for unit testing purposes */ class DummyCommand : public Command { public: DummyCommand(int& valueRef) : Command("dummycommand", "[args]") , m_value(valueRef) { } ~DummyCommand() { } bool Execute(GXemul& gxemul, const vector& arguments) { m_value ++; return true; } string GetShortDescription() const { return "A dummy command used for unit testing."; } string GetLongDescription() const { return "This is just a dummy command used for unit testing."; } private: int& m_value; }; static void Test_Command_DummyCommand() { GXemul gxemulDummy; vector dummyArgs; int dummyInt = 0; refcount_ptr cmd = new DummyCommand(dummyInt); dummyInt = 42; UnitTest::Assert("dummyInt should initially be 42", dummyInt == 42); UnitTest::Assert("command should have succeeded", cmd->Execute(gxemulDummy, dummyArgs)); UnitTest::Assert("dummyInt should now be 43", dummyInt == 43); } UNITTESTS(Command) { UNITTEST(Test_Command_DummyCommand); } #endif gxemul-0.6.1/src/main/FileLoader.cc000644 001750 001750 00000021426 13402411502 017262 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include using std::ifstream; #include "AddressDataBus.h" #include "Component.h" #include "FileLoader.h" #include "FileLoader_aout.h" #include "FileLoader_bout.h" #include "FileLoader_ELF.h" #include "FileLoader_raw.h" FileLoader::FileLoader(const string& filename) : m_filename(filename) { m_fileLoaders.push_back(new FileLoader_aout(filename)); m_fileLoaders.push_back(new FileLoader_bout(filename)); m_fileLoaders.push_back(new FileLoader_ELF(filename)); m_fileLoaders.push_back(new FileLoader_raw(filename)); } const string& FileLoader::GetFilename() const { return m_filename; } string FileLoader::DetectFileFormat(refcount_ptr& loader) const { loader = NULL; // TODO: Disk images? ifstream file(m_filename.c_str()); unsigned char buf[512]; memset(buf, 0, sizeof(buf)); size_t amountRead = 0; if (file.is_open()) { file.read((char *)buf, sizeof(buf)); amountRead = file.gcount(); } // Ask all file loaders about how well they handle the format. Return // the format string from the loader that had the highest score. float bestMatch = 0.0; string bestFormat = "Unknown"; FileLoaderImplVector::const_iterator it = m_fileLoaders.begin(); for (; it != m_fileLoaders.end(); ++it) { float match; string format = (*it)->DetectFileType(buf, amountRead, match); if (match > bestMatch) { bestMatch = match; bestFormat = format; loader = *it; } } if (bestMatch == 0.0 && !file.is_open()) return "Not accessible"; return bestFormat; } bool FileLoader::Load(refcount_ptr component, ostream& messages) const { AddressDataBus * bus = component->AsAddressDataBus(); if (bus == NULL) { // We cannot load into something that isn't an AddressDataBus. messages << "Error: " << component->GenerateShortestPossiblePath() << " is not an AddressDataBus.\n"; return false; } refcount_ptr loaderImpl; string fileFormat = DetectFileFormat(loaderImpl); if (!loaderImpl.IsNULL()) return loaderImpl->LoadIntoComponent(component, messages); messages << "Error: File format '" << fileFormat << "' not yet implemented. TODO\n"; return false; } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_FileLoader_Constructor() { FileLoader fileLoader("test/FileLoader_ELF_MIPS"); UnitTest::Assert("filename mismatch?", fileLoader.GetFilename(), "test/FileLoader_ELF_MIPS"); } static void Test_FileLoader_Constructor_NonExistingFile() { FileLoader fileLoader("test/Nonexisting"); UnitTest::Assert("filename mismatch?", fileLoader.GetFilename(), "test/Nonexisting"); } static void Test_FileLoader_DetectFileFormat_NonexistingFile() { FileLoader fileLoader("test/Nonexisting"); refcount_ptr loaderImpl; UnitTest::Assert("file format detection failure?", fileLoader.DetectFileFormat(loaderImpl), "Not accessible"); } static void Test_FileLoader_DetectFileFormat_NonsenseFile() { FileLoader fileLoader("test/FileLoader_NonsenseFile"); refcount_ptr loaderImpl; UnitTest::Assert("file format detection failure?", fileLoader.DetectFileFormat(loaderImpl), "Unknown"); } static void Test_FileLoader_DetectFileFormat_ELF32() { FileLoader fileLoader("test/FileLoader_ELF_MIPS"); refcount_ptr loaderImpl; UnitTest::Assert("file format detection failure?", fileLoader.DetectFileFormat(loaderImpl), "ELF32"); } static void Test_FileLoader_DetectFileFormat_ELF64() { FileLoader fileLoader("test/FileLoader_ELF_SH5"); refcount_ptr loaderImpl; UnitTest::Assert("file format detection failure?", fileLoader.DetectFileFormat(loaderImpl), "ELF64"); } static void Test_FileLoader_DetectFileFormat_aout_88K() { FileLoader fileLoader("test/FileLoader_A.OUT_M88K"); refcount_ptr loaderImpl; UnitTest::Assert("file format detection failure?", fileLoader.DetectFileFormat(loaderImpl), "a.out_M88K_fromBeginning"); } static void Test_FileLoader_DetectFileFormat_bout_i960() { FileLoader fileLoader("test/FileLoader_B.OUT_i960"); refcount_ptr loaderImpl; UnitTest::Assert("file format detection failure?", fileLoader.DetectFileFormat(loaderImpl), "b.out_i960_little"); } static refcount_ptr SetupTestMachineAndLoad( string machineName, string fileName) { FileLoader fileLoader(fileName); refcount_ptr machine = ComponentFactory::CreateComponent(machineName); machine->SetVariableValue("name", "\"machine\""); refcount_ptr component = machine->LookupPath("machine.mainbus0.cpu0"); UnitTest::Assert("could not look up CPU to load into?", !component.IsNULL()); stringstream messages; UnitTest::Assert("could not load the file " + fileName + " for" " machine " + machineName, fileLoader.Load(component, messages)); return machine; } static void Test_FileLoader_Load_ELF32() { refcount_ptr machine = SetupTestMachineAndLoad("testmips", "test/FileLoader_ELF_MIPS"); // Read from CPU, to make sure the file was loaded: refcount_ptr cpu = machine->LookupPath("machine.mainbus0.cpu0"); AddressDataBus * bus = cpu->AsAddressDataBus(); bus->AddressSelect((int32_t)0x80010000); uint32_t word = 0x12345678; bus->ReadData(word, BigEndian); UnitTest::Assert("memory (CPU) wasn't filled with data from the file?", word, 0x8f8b8008); // Read directly from RAM too, to make sure the file was loaded: refcount_ptr ram = machine->LookupPath("machine.mainbus0.ram0"); AddressDataBus * ramBus = ram->AsAddressDataBus(); ramBus->AddressSelect(0x1000c); uint32_t word2 = 0x12345678; ramBus->ReadData(word2, BigEndian); UnitTest::Assert("memory (RAM) wasn't filled with data from the file?", word2, 0x006b7021); } static void Test_FileLoader_Load_aout() { refcount_ptr machine = SetupTestMachineAndLoad("testm88k", "test/FileLoader_A.OUT_M88K"); // Read from CPU, to make sure the file was loaded: refcount_ptr cpu = machine->LookupPath("machine.mainbus0.cpu0"); AddressDataBus * bus = cpu->AsAddressDataBus(); bus->AddressSelect((int32_t)0x12b8); uint32_t word = 0x12345678; bus->ReadData(word, BigEndian); UnitTest::Assert("memory (CPU) wasn't filled with data from the file?", word, 0x67ff0020); // Read directly from RAM too, to make sure the file was loaded: refcount_ptr ram = machine->LookupPath("machine.mainbus0.ram0"); AddressDataBus * ramBus = ram->AsAddressDataBus(); ramBus->AddressSelect(0x12e0); uint32_t word2 = 0xfdecba98; ramBus->ReadData(word2, BigEndian); UnitTest::Assert("memory (RAM) wasn't filled with data from the file?", word2, 0xf6c05802); } UNITTESTS(FileLoader) { UNITTEST(Test_FileLoader_Constructor); UNITTEST(Test_FileLoader_Constructor_NonExistingFile); UNITTEST(Test_FileLoader_DetectFileFormat_NonexistingFile); UNITTEST(Test_FileLoader_DetectFileFormat_NonsenseFile); UNITTEST(Test_FileLoader_DetectFileFormat_ELF32); UNITTEST(Test_FileLoader_DetectFileFormat_ELF64); UNITTEST(Test_FileLoader_DetectFileFormat_aout_88K); UNITTEST(Test_FileLoader_DetectFileFormat_bout_i960); UNITTEST(Test_FileLoader_Load_ELF32); UNITTEST(Test_FileLoader_Load_aout); } #endif gxemul-0.6.1/src/main/StringHelper.cc000644 001750 001750 00000023443 13402411502 017663 0ustar00debugdebug000000 000000 /* * Copyright (C) 2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "StringHelper.h" // This is basically strtoull(), but it needs to be explicitly implemented // since some systems lack it. (Also, compiling with GNU C++ in ANSI mode // does not work with strtoull.) uint64_t StringHelper::ParseNumber(const char* str, bool& error) { bool baseSet = false; int base = 10; uint64_t result = 0; bool negative = false; error = false; if (str == NULL) return 0; while (*str == ' ') ++str; if (*str == '-') { negative = true; ++str; } while ((*str == 'x' || *str == 'X') || (*str >= '0' && *str <= '9') || (*str >= 'a' && *str <= 'f') || (*str >= 'A' && *str <= 'F')) { char c = *str; if (c == 'x' || c == 'X') { // Multiple base selections are not allowed. if (baseSet) break; // Only 0 prefix before base selection is allowed, // no other values. if (result != 0) break; base = 16; baseSet = true; } else { if (base == 10 && (c < '0' || c > '9')) break; int n = c - '0'; if (c >= 'a' && c <= 'f') n = *str - 'a' + 10; if (c >= 'A' && c <= 'F') n = *str - 'A' + 10; if (base == 16 && (n < 0 || n > 15)) break; result = result * base + n; } ++str; } if (*str) error = true; if (negative) return -result; else return result; } vector StringHelper::SplitStringIntoVector(const string &str, const char splitter) { // This is slow and hackish, but works. vector strings; string word; bool lastWasSplitter = false; for (size_t i=0, n=str.length(); i v = StringHelper::SplitStringIntoVector("A:B:C", ':'); UnitTest::Assert("Wrong number of strings?", v.size(), 3); UnitTest::Assert("Wrong string contents?", v[0], "A"); UnitTest::Assert("Wrong string contents?", v[1], "B"); UnitTest::Assert("Wrong string contents?", v[2], "C"); } static void Test_StringHelper_SplitStringIntoVector_EmptyInput() { vector v = StringHelper::SplitStringIntoVector("", ':'); UnitTest::Assert("Wrong number of strings?", v.size(), 0); } static void Test_StringHelper_SplitStringIntoVector_Simple2() { vector v = StringHelper::SplitStringIntoVector("A:B:C", 'B'); UnitTest::Assert("Wrong number of strings?", v.size(), 2); UnitTest::Assert("Wrong string contents?", v[0], "A:"); UnitTest::Assert("Wrong string contents?", v[1], ":C"); } static void Test_StringHelper_SplitStringIntoVector_WithZeroLengthParts() { vector v = StringHelper::SplitStringIntoVector("A::B:::C", ':'); UnitTest::Assert("Wrong number of strings?", v.size(), 6); UnitTest::Assert("Wrong string contents?", v[0], "A"); UnitTest::Assert("Wrong string contents?", v[1], ""); UnitTest::Assert("Wrong string contents?", v[2], "B"); UnitTest::Assert("Wrong string contents?", v[3], ""); UnitTest::Assert("Wrong string contents?", v[4], ""); UnitTest::Assert("Wrong string contents?", v[5], "C"); } static void Test_StringHelper_SplitStringIntoVector_WithTrailingZeroLengthParts() { vector v = StringHelper::SplitStringIntoVector("A::", ':'); UnitTest::Assert("Wrong number of strings?", v.size(), 3); UnitTest::Assert("Wrong string contents?", v[0], "A"); UnitTest::Assert("Wrong string contents?", v[1], ""); UnitTest::Assert("Wrong string contents?", v[2], ""); } static void Test_StringHelper_SplitStringIntoVector_WithHeadingZeroLengthParts() { vector v = StringHelper::SplitStringIntoVector("A::", 'A'); UnitTest::Assert("Wrong number of strings?", v.size(), 2); UnitTest::Assert("Wrong string contents?", v[0], ""); UnitTest::Assert("Wrong string contents?", v[1], "::"); } UNITTESTS(StringHelper) { UNITTEST(Test_StringHelper_ParseNumber_Simple); UNITTEST(Test_StringHelper_ParseNumber_SimpleError); UNITTEST(Test_StringHelper_ParseNumber_Negative); UNITTEST(Test_StringHelper_ParseNumber_LeadingSpaces); UNITTEST(Test_StringHelper_ParseNumber_LeadingSpacesAndNegative); UNITTEST(Test_StringHelper_ParseNumber_LeadingSpacesAndErrorNegative); UNITTEST(Test_StringHelper_ParseNumber_SimpleHexLowerCase); UNITTEST(Test_StringHelper_ParseNumber_SimpleHexUpperCase); UNITTEST(Test_StringHelper_ParseNumber_HexErrorDoubleX); UNITTEST(Test_StringHelper_ParseNumber_HexErrorNonZeroPrefix); UNITTEST(Test_StringHelper_ParseNumber_NumberFollowedByErrorValidHexChar); UNITTEST(Test_StringHelper_ParseNumber_NumberFollowedByError); UNITTEST(Test_StringHelper_SplitStringIntoVector_Simple); UNITTEST(Test_StringHelper_SplitStringIntoVector_EmptyInput); UNITTEST(Test_StringHelper_SplitStringIntoVector_Simple2); UNITTEST(Test_StringHelper_SplitStringIntoVector_WithZeroLengthParts); UNITTEST(Test_StringHelper_SplitStringIntoVector_WithTrailingZeroLengthParts); UNITTEST(Test_StringHelper_SplitStringIntoVector_WithHeadingZeroLengthParts); } #endif gxemul-0.6.1/src/main/fileloaders/FileLoader_bout.cc000644 001750 001750 00000021535 13402411502 022605 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include using std::setw; using std::setfill; using std::ifstream; #include "AddressDataBus.h" #include "components/CPUComponent.h" #include "FileLoader_bout.h" #include "thirdparty/exec_bout.h" FileLoader_bout::FileLoader_bout(const string& filename) : FileLoaderImpl(filename) { } string FileLoader_bout::DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const { matchness = 0.9; if (buflen >= 0x2c && buf[0] == 0x0d && buf[1] == 0x01 && buf[2] == 0x00 && buf[3] == 0x00) { return "b.out_i960_little"; } if (buflen >= 0x2c && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01 && buf[3] == 0x0d) { return "b.out_i960_big"; } matchness = 0.0; return ""; } static uint32_t unencode32(uint8_t *p, Endianness endianness) { uint32_t res; if (endianness == BigEndian) res = p[3] + (p[2] << 8) + (p[1] << 16) + (p[0] << 24); else res = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); return res; } bool FileLoader_bout::LoadIntoComponent(refcount_ptr component, ostream& messages) const { AddressDataBus* bus = component->AsAddressDataBus(); if (bus == NULL) { messages << "Target is not an AddressDataBus.\n"; return false; } ifstream file(Filename().c_str()); if (!file.is_open()) { messages << "Unable to read file.\n"; return false; } unsigned char buf[65536]; memset(buf, 0, sizeof(buf)); file.seekg(0, std::ios_base::end); uint64_t totalSize = file.tellg(); file.seekg(0, std::ios_base::beg); file.read((char *)buf, totalSize < sizeof(buf)? totalSize : sizeof(buf)); size_t amountRead = file.gcount(); float matchness; string format = DetectFileType(buf, amountRead, matchness); if (format == "") { messages << "Unknown b.out format.\n"; return false; } file.seekg(0, std::ios_base::beg); StateVariable* var = component->GetVariable("bigendian"); if (var == NULL) { messages << "Target does not have the 'bigendian' variable," " which is needed to\n" "load b.out files.\n"; return false; } Endianness endianness = LittleEndian; if (format == "b.out_i960_big") endianness = BigEndian; struct bout_exec header; uint32_t entry; file.read((char *)&header, sizeof(header)); if (file.gcount() != sizeof(header)) { messages << "The file is too small to be a b.out.\n"; return false; } entry = unencode32((unsigned char*)&header.a_entry, endianness); uint32_t textaddr = unencode32((unsigned char*)&header.a_tload, endianness); uint32_t textsize = unencode32((unsigned char*)&header.a_text, endianness); uint32_t dataaddr = unencode32((unsigned char*)&header.a_dload, endianness); uint32_t datasize = unencode32((unsigned char*)&header.a_data, endianness); int32_t symbsize = unencode32((unsigned char*)&header.a_syms, endianness); messages.flags(std::ios::hex); messages << "b.out: entry point 0x"; messages << setw(8) << setfill('0') << (uint32_t) entry << "\n"; messages.flags(std::ios::dec); messages << "text + data = " << textsize << " + " << datasize << " bytes\n"; // Load text: uint32_t vaddr = textaddr; while (textsize != 0) { int len = textsize > sizeof(buf) ? sizeof(buf) : textsize; file.read((char *)buf, len); len = file.gcount(); if (len < 1) break; // Write to the bus, one byte at a time. for (int k=0; kAddressSelect(vaddr); if (!bus->WriteData(buf[k])) { messages.flags(std::ios::hex); messages << "Failed to write data to virtual " "address 0x" << vaddr << "\n"; return false; } ++ vaddr; } textsize -= len; } if (textsize != 0) { messages << "Failed to read the entire file.\n"; return false; } // Load data: vaddr = dataaddr; while (datasize != 0) { int len = datasize > sizeof(buf) ? sizeof(buf) : datasize; file.read((char *)buf, len); len = file.gcount(); if (len < 1) break; // Write to the bus, one byte at a time. for (int k=0; kAddressSelect(vaddr); if (!bus->WriteData(buf[k])) { messages.flags(std::ios::hex); messages << "Failed to write data to virtual " "address 0x" << vaddr << "\n"; return false; } ++ vaddr; } datasize -= len; } if (datasize != 0) { messages << "Failed to read the entire file.\n"; return false; } #if 0 // TODO: Symbols. Similar to a.out? SymbolRegistry* symbolRegistry = NULL; CPUComponent* cpu = component->AsCPUComponent(); if (cpu != NULL) symbolRegistry = &cpu->GetSymbolRegistry(); // Symbols: if (symbolRegistry != NULL && symbsize > 0) { messages.flags(std::ios::dec); messages << "symbols: " << symbsize << " bytes at 0x"; messages.flags(std::ios::hex); messages << file.tellg() << "\n"; vector symbolData; symbolData.resize(symbsize); file.read(&symbolData[0], symbsize); if (file.gcount() != symbsize) { messages << "Failed to read all symbols.\n"; return false; } off_t oldpos = file.tellg(); file.seekg(0, std::ios_base::end); size_t strings_len = (off_t)file.tellg() - oldpos; file.seekg(oldpos, std::ios_base::beg); messages.flags(std::ios::dec); messages << "strings: " << strings_len << " bytes at 0x"; messages.flags(std::ios::hex); messages << file.tellg() << "\n"; vector symbolStrings; // Note: len + 1 for a nul terminator, for safety. symbolStrings.resize(strings_len + 1); file.read(&symbolStrings[0], strings_len); if (file.gcount() != strings_len) { messages << "Failed to read all strings.\n"; return false; } assert(sizeof(struct aout_symbol) == 12); int nsymbols = 0; struct aout_symbol* aout_symbol_ptr = (struct aout_symbol *) (void*) &symbolData[0]; int n_symbols = symbsize / sizeof(struct aout_symbol); for (int i = 0; i < n_symbols; i++) { uint32_t index = unencode32((unsigned char*)&aout_symbol_ptr[i].strindex, endianness); uint32_t type = unencode32((unsigned char*)&aout_symbol_ptr[i].type, endianness); uint32_t addr = unencode32((unsigned char*)&aout_symbol_ptr[i].addr, endianness); // TODO: These bits probably mean different things for // different b.out formats. For OpenBSD/m88k at least, // this bit (0x01000000) seems to mean "a normal symbol". if (!(type & 0x01000000)) continue; // ... and the rectangle drawing demo says // "_my_memset" at addr 1020, type 5020000 // "rectangles_m88k_O2.o" at addr 1020, type 1f000000 if ((type & 0x1f000000) == 0x1f000000) continue; if (index >= (uint32_t)strings_len) { messages << "symbol " << i << " has invalid string index\n"; continue; } string symbol = ((char*) &symbolStrings[0]) + index; if (symbol == "") continue; // messages << "\"" << symbol << "\" at addr " << addr // << ", type " << type << "\n"; // Add this symbol to the symbol registry: symbolRegistry->AddSymbol(symbol, addr); ++ nsymbols; } messages.flags(std::ios::dec); messages << nsymbols << " symbols read\n"; } #endif // Set the CPU's entry point. stringstream ss; ss << (int64_t)(int32_t)entry; component->SetVariableValue("pc", ss.str()); return true; } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_FileLoader_bout_Constructor() { FileLoader_bout boutLoader("test/FileLoader_B.OUT_i960"); } UNITTESTS(FileLoader_bout) { UNITTEST(Test_FileLoader_bout_Constructor); // TODO } #endif gxemul-0.6.1/src/main/fileloaders/FileLoader_raw.cc000644 001750 001750 00000012442 13402411502 022422 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include using std::setw; using std::setfill; using std::ifstream; #include "AddressDataBus.h" #include "components/CPUComponent.h" #include "FileLoader_raw.h" #include "StringHelper.h" FileLoader_raw::FileLoader_raw(const string& filename) : FileLoaderImpl(filename) { } string FileLoader_raw::DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const { matchness = 0.0; vector parts = StringHelper::SplitStringIntoVector(Filename(), ':'); // Possible variants: // // filename <-- NOT a raw file // raw:vaddr:filename // raw:vaddr:skiplen:filename // raw:vaddr:skiplen:initialpc:filename e.g. raw:0xbfc00000:0x100:0xbfc00884:rom.bin if (parts.size() < 3) return ""; if (parts[0] != "raw") return ""; matchness = 1.0; return "raw"; } bool FileLoader_raw::LoadIntoComponent(refcount_ptr component, ostream& messages) const { AddressDataBus* bus = component->AsAddressDataBus(); if (bus == NULL) { messages << "Target is not an AddressDataBus.\n"; return false; } // Possible variants: // // raw:vaddr:filename // raw:vaddr:skiplen:filename // raw:vaddr:skiplen:initialpc:filename e.g. 0xbfc00000:0x100:0xbfc00884:rom.bin vector parts = StringHelper::SplitStringIntoVector(Filename(), ':'); if (parts.size() < 3 || parts.size() > 5) { messages << "Syntax is raw:vaddr:[skiplen:[initialpc:]]filename.\n"; return false; } string strvaddr = parts[1]; string strskiplen = (parts.size() >= 4)? parts[2] : ""; string strinitialpc = (parts.size() >= 5)? parts[3] : ""; string fname = parts[parts.size() - 1]; bool error; uint64_t vaddr = StringHelper::ParseNumber(strvaddr.c_str(), error); if (error) { messages << "could not parse vaddr.\n"; return false; } uint64_t skiplen = 0; if (strskiplen != "") { skiplen = StringHelper::ParseNumber(strskiplen.c_str(), error); if (error) { messages << "could not parse skiplen\n"; return false; } } uint64_t initialpc = vaddr; if (strinitialpc != "") { initialpc = StringHelper::ParseNumber(strinitialpc.c_str(), error); if (error) { messages << "could not parse initialpc\n"; return false; } } ifstream file(fname.c_str()); if (!file.is_open()) { messages << "Unable to read file.\n"; return false; } file.seekg(0, std::ios_base::end); off_t totalSize = file.tellg(); file.seekg(skiplen, std::ios_base::beg); totalSize -= skiplen; // Read everything: vector data; data.resize(totalSize); file.read(&data[0], totalSize); if (file.gcount() != totalSize) { messages << "failed to read the whole file\n"; return false; } messages.flags(std::ios::hex); messages << "Raw file: entry point 0x" << initialpc << "\n"; messages << "loadable chunk"; if (skiplen != 0) { messages.flags(std::ios::dec); messages << " at offset " << skiplen; } messages.flags(std::ios::hex); messages << ": vaddr 0x" << vaddr; messages.flags(std::ios::dec); messages << ", " << totalSize << " bytes\n"; // Write to the bus, one byte at a time. for (size_t k=0; k<(size_t)totalSize; ++k) { bus->AddressSelect(vaddr); if (!bus->WriteData(data[k])) { messages.flags(std::ios::hex); messages << "Failed to write data to " "virtual address 0x" << vaddr << "\n"; return false; } ++ vaddr; } // Set the CPU's entry point. stringstream ss; ss << initialpc; component->SetVariableValue("pc", ss.str()); return true; } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_FileLoader_raw_Constructor() { // TODO: haha, better test. FileLoader_raw rawLoader("test/FileLoader_A.OUT_M88K"); } UNITTESTS(FileLoader_raw) { UNITTEST(Test_FileLoader_raw_Constructor); // TODO } #endif gxemul-0.6.1/src/main/fileloaders/FileLoader_aout.cc000644 001750 001750 00000024170 13402411502 022602 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include using std::setw; using std::setfill; using std::ifstream; #include "AddressDataBus.h" #include "components/CPUComponent.h" #include "FileLoader_aout.h" #include "thirdparty/exec_aout.h" struct aout_symbol { uint32_t strindex; uint32_t type; uint32_t addr; }; FileLoader_aout::FileLoader_aout(const string& filename) : FileLoaderImpl(filename) { } string FileLoader_aout::DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const { matchness = 0.9; if (buf[0]==0x00 && buf[1]==0x8b && buf[2]==0x01 && buf[3]==0x07) { /* MIPS a.out */ return "a.out_MIPS"; } if (buf[0]==0x00 && buf[1]==0x87 && buf[2]==0x01 && buf[3]==0x08) { /* M68K a.out */ // AOUT_FLAG_VADDR_ZERO_HACK for OpenBSD/mac68k return "a.out_M68K_vaddr0"; } // Luna88k a.out for OpenBSD is _almost_ like for MVME88K... just a difference // of entry point (?) // if (buf[0]==0x00 && buf[1]==0x99 && buf[2]==0x01 && buf[3]==0x07) { // /* OpenBSD/luna88k a.out */ // return "a.out_M88K_fromBeginningEntryAfterHeader"; // } if (buf[0]==0x00 && buf[1]==0x99 && buf[2]==0x01 && buf[3]==0x0b) { /* OpenBSD/M88K a.out */ return "a.out_M88K_fromBeginning"; } if (buf[0]==0x00 && buf[1]==0x8f && buf[2]==0x01 && buf[3]==0x0b) { /* ARM a.out */ return "a.out_ARM_fromBeginning"; } if (buf[0]==0x00 && buf[1]==0x86 && buf[2]==0x01 && buf[3]==0x0b) { /* i386 a.out (old OpenBSD and NetBSD etc) */ return "a.out_i386_fromBeginning"; } if (buf[0]==0x01 && buf[1]==0x03 && buf[2]==0x01 && buf[3]==0x07) { /* SPARC a.out (old 32-bit NetBSD etc) */ return "a.out_SPARC_noSizes"; } if (buf[0]==0x00 && buf[2]==0x00 && buf[8]==0x7a && buf[9]==0x75) { /* DEC OSF1 on MIPS: */ return "a.out_MIPS_osf1"; } matchness = 0.0; return ""; } static uint32_t unencode32(uint8_t *p, Endianness endianness) { uint32_t res; if (endianness == BigEndian) res = p[3] + (p[2] << 8) + (p[1] << 16) + (p[0] << 24); else res = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); return res; } bool FileLoader_aout::LoadIntoComponent(refcount_ptr component, ostream& messages) const { AddressDataBus* bus = component->AsAddressDataBus(); if (bus == NULL) { messages << "Target is not an AddressDataBus.\n"; return false; } ifstream file(Filename().c_str()); if (!file.is_open()) { messages << "Unable to read file.\n"; return false; } unsigned char buf[65536]; memset(buf, 0, sizeof(buf)); file.seekg(0, std::ios_base::end); uint64_t totalSize = file.tellg(); file.seekg(0, std::ios_base::beg); file.read((char *)buf, totalSize < sizeof(buf)? totalSize : sizeof(buf)); size_t amountRead = file.gcount(); float matchness; string format = DetectFileType(buf, amountRead, matchness); if (format == "") { messages << "Unknown a.out format.\n"; return false; } file.seekg(0, std::ios_base::beg); Endianness endianness = BigEndian; StateVariable* var = component->GetVariable("bigendian"); if (var == NULL) { messages << "Target does not have the 'bigendian' variable," " which is needed to\n" "load a.out files.\n"; return false; } endianness = var->ToInteger() == 0? LittleEndian : BigEndian; struct exec aout_header; uint32_t entry, datasize, textsize; int32_t symbsize = 0; uint32_t vaddr, total_len; if (format.substr(format.length()-5, 5) == "_osf1") { file.read((char *)buf, 32); if (file.gcount() != 32) { messages << "The file is too small to be an OSF1 a.out.\n"; return false; } vaddr = unencode32(buf + 16, endianness); entry = unencode32(buf + 20, endianness); symbsize = 0; file.seekg(0, std::ios_base::end); /* This is of course wrong, but should work anyway: */ textsize = (uint32_t) file.tellg() - 512; datasize = 0; file.seekg(512, std::ios_base::beg); } else if (format.substr(format.length()-8, 8) == "_noSizes") { file.seekg(0, std::ios_base::end); textsize = (uint32_t) file.tellg() - 32; datasize = 0; vaddr = entry = 0; file.seekg(32, std::ios_base::beg); } else { file.read((char *)&aout_header, sizeof(aout_header)); if (file.gcount() != sizeof(aout_header)) { messages << "The file is too small to be an a.out.\n"; return false; } entry = unencode32((unsigned char*)&aout_header.a_entry, endianness); vaddr = entry; if (format.substr(format.length()-7, 7) == "_vaddr0") vaddr = 0; textsize = unencode32((unsigned char*)&aout_header.a_text, endianness); datasize = unencode32((unsigned char*)&aout_header.a_data, endianness); symbsize = unencode32((unsigned char*)&aout_header.a_syms, endianness); } if (format.substr(format.length()-14, 14) == "_fromBeginning") { file.seekg(0, std::ios_base::beg); vaddr &= ~0xfff; } messages.flags(std::ios::hex); messages << "a.out: entry point 0x"; messages << setw(8) << setfill('0') << (uint32_t) entry << "\n"; messages.flags(std::ios::dec); messages << "text + data = " << textsize << " + " << datasize << " bytes\n"; // Load text and data: total_len = textsize + datasize; while (total_len != 0) { int len = total_len > sizeof(buf) ? sizeof(buf) : total_len; file.read((char *)buf, len); len = file.gcount(); if (len < 1) break; // Write to the bus, one byte at a time. for (int k=0; kAddressSelect(vaddr); if (!bus->WriteData(buf[k])) { messages.flags(std::ios::hex); messages << "Failed to write data to virtual " "address 0x" << vaddr << "\n"; return false; } ++ vaddr; } total_len -= len; } if (total_len != 0) { messages << "Failed to read the entire file.\n"; return false; } SymbolRegistry* symbolRegistry = NULL; CPUComponent* cpu = component->AsCPUComponent(); if (cpu != NULL) symbolRegistry = &cpu->GetSymbolRegistry(); // Symbols: if (symbolRegistry != NULL && symbsize > 0) { messages.flags(std::ios::dec); messages << "symbols: " << symbsize << " bytes at 0x"; messages.flags(std::ios::hex); messages << file.tellg() << "\n"; vector symbolData; symbolData.resize(symbsize); file.read(&symbolData[0], symbsize); if (file.gcount() != symbsize) { messages << "Failed to read all symbols.\n"; return false; } off_t oldpos = file.tellg(); file.seekg(0, std::ios_base::end); size_t strings_len = (off_t)file.tellg() - oldpos; file.seekg(oldpos, std::ios_base::beg); messages.flags(std::ios::dec); messages << "strings: " << strings_len << " bytes at 0x"; messages.flags(std::ios::hex); messages << file.tellg() << "\n"; vector symbolStrings; // Note: len + 1 for a nul terminator, for safety. symbolStrings.resize(strings_len + 1); file.read(&symbolStrings[0], strings_len); if (file.gcount() != strings_len) { messages << "Failed to read all strings.\n"; return false; } assert(sizeof(struct aout_symbol) == 12); int nsymbols = 0; struct aout_symbol* aout_symbol_ptr = (struct aout_symbol *) (void*) &symbolData[0]; int n_symbols = symbsize / sizeof(struct aout_symbol); for (int i = 0; i < n_symbols; i++) { uint32_t index = unencode32((unsigned char*)&aout_symbol_ptr[i].strindex, endianness); uint32_t type = unencode32((unsigned char*)&aout_symbol_ptr[i].type, endianness); uint32_t addr = unencode32((unsigned char*)&aout_symbol_ptr[i].addr, endianness); // TODO: These bits probably mean different things for // different a.out formats. For OpenBSD/m88k at least, // this bit (0x01000000) seems to mean "a normal symbol". if (!(type & 0x01000000)) continue; // ... and the rectangle drawing demo says // "_my_memset" at addr 1020, type 5020000 // "rectangles_m88k_O2.o" at addr 1020, type 1f000000 if ((type & 0x1f000000) == 0x1f000000) continue; if (index >= (uint32_t)strings_len) { messages << "symbol " << i << " has invalid string index\n"; continue; } string symbol = ((char*) &symbolStrings[0]) + index; if (symbol == "") continue; // messages << "\"" << symbol << "\" at addr " << addr // << ", type " << type << "\n"; // Add this symbol to the symbol registry: symbolRegistry->AddSymbol(symbol, addr); ++ nsymbols; } messages.flags(std::ios::dec); messages << nsymbols << " symbols read\n"; } // Set the CPU's entry point. stringstream ss; ss << (int64_t)(int32_t)entry; component->SetVariableValue("pc", ss.str()); return true; } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_FileLoader_aout_Constructor() { FileLoader_aout aoutLoader("test/FileLoader_A.OUT_M88K"); } UNITTESTS(FileLoader_aout) { UNITTEST(Test_FileLoader_aout_Constructor); // TODO } #endif gxemul-0.6.1/src/main/fileloaders/Makefile.skel000644 001750 001750 00000000443 13402411502 021627 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/main/fileloaders # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(CPEDANTIC) $(INCLUDE2) LIBS=$(OTHERLIBS) OBJS=FileLoader_aout.o FileLoader_bout.o FileLoader_ELF.o FileLoader_raw.o all: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) clean_all: clean rm -f Makefile gxemul-0.6.1/src/main/fileloaders/FileLoader_ELF.cc000644 001750 001750 00000043504 13402411502 022242 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include using std::setw; using std::setfill; using std::ifstream; #include "AddressDataBus.h" #include "components/CPUComponent.h" #include "FileLoader_ELF.h" #include "thirdparty/exec_elf.h" /* ELF machine types as strings: (same as exec_elf.h) */ #define N_ELF_MACHINE_TYPES 89 static const char *elf_machine_type[N_ELF_MACHINE_TYPES] = { "NONE", "M32", "SPARC", "386", /* 0..3 */ "68K", "88K", "486", "860", /* 4..7 */ "MIPS", "S370", "MIPS_RS3_LE", "RS6000", /* 8..11 */ "unknown12", "unknown13", "unknown14", "PARISC", /* 12..15 */ "NCUBE", "VPP500", "SPARC32PLUS", "960", /* 16..19 */ "PPC", "PPC64", "unknown22", "unknown23", /* 20..23 */ "unknown24", "unknown25", "unknown26", "unknown27", /* 24..27 */ "unknown28", "unknown29", "unknown30", "unknown31", /* 28..31 */ "unknown32", "unknown33", "unknown34", "unknown35", /* 32..35 */ "V800", "FR20", "RH32", "RCE", /* 36..39 */ "ARM", "ALPHA", "SH", "SPARCV9", /* 40..43 */ "TRICORE", "ARC", "H8_300", "H8_300H", /* 44..47 */ "H8S", "H8_500", "IA_64", "MIPS_X", /* 48..51 */ "COLDFIRE", "68HC12", "unknown54", "unknown55", /* 52..55 */ "unknown56", "unknown57", "unknown58", "unknown59", /* 56..59 */ "unknown60", "unknown61", "AMD64", "unknown63", /* 60..63 */ "unknown64", "unknown65", "unknown66", "unknown67", /* 64..67 */ "unknown68", "unknown69", "unknown70", "unknown71", /* 68..71 */ "unknown72", "unknown73", "unknown74", "unknown75", /* 72..75 */ "unknown76", "unknown77", "unknown78", "unknown79", /* 76..79 */ "unknown80", "unknown81", "unknown82", "AVR", /* 80..83 */ "unknown84", "unknown85", "unknown86", "unknown87", /* 84..87 */ "M32R" /* 88 */ }; FileLoader_ELF::FileLoader_ELF(const string& filename) : FileLoaderImpl(filename) { } string FileLoader_ELF::DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const { if (buflen < sizeof(Elf32_Ehdr)) return ""; // Note: The e_ident part of the 32-bit and the 64-bit variants have // the same layout, so it is safe to only check the 32-bit variant here. Elf32_Ehdr* elf32_ehdr = (Elf32_Ehdr*) buf; if (elf32_ehdr->e_ident[EI_MAG0] == ELFMAG0 && elf32_ehdr->e_ident[EI_MAG1] == ELFMAG1 && elf32_ehdr->e_ident[EI_MAG2] == ELFMAG2 && elf32_ehdr->e_ident[EI_MAG3] == ELFMAG3) { // We are here if this is either an ELF32 or ELF64. int elfClass = elf32_ehdr->e_ident[EI_CLASS]; matchness = 1.0; if (elfClass == ELFCLASS32) return "ELF32"; if (elfClass == ELFCLASS64) return "ELF64"; matchness = 0.0; stringstream ss; ss << "ELF Unknown class " << elfClass; return ss.str(); } return ""; } bool FileLoader_ELF::LoadIntoComponent(refcount_ptr component, ostream& messages) const { AddressDataBus* bus = component->AsAddressDataBus(); if (bus == NULL) { messages << "Target is not an AddressDataBus.\n"; return false; } ifstream file(Filename().c_str()); if (!file.is_open()) { messages << "Unable to read file.\n"; return false; } char buf[64]; // buf must be large enough for the largest possible header we wish // to examine to fit. assert(sizeof(buf) >= sizeof(Elf32_Ehdr)); assert(sizeof(buf) >= sizeof(Elf64_Ehdr)); memset(buf, 0, sizeof(buf)); file.read(buf, sizeof(buf)); // Note: The e_ident part of the 32-bit and the 64-bit variants have // the same layout, so it is safe to only use the 32-bit variant here. Elf32_Ehdr* ehdr32 = (Elf32_Ehdr*) buf; Elf64_Ehdr* ehdr64 = (Elf64_Ehdr*) buf; if (ehdr32->e_ident[EI_MAG0] != ELFMAG0 || ehdr32->e_ident[EI_MAG1] != ELFMAG1 || ehdr32->e_ident[EI_MAG2] != ELFMAG2 || ehdr32->e_ident[EI_MAG3] != ELFMAG3) { messages << "Not an ELF.\n"; return false; } int elfClass = ehdr32->e_ident[EI_CLASS]; int elfDataEncoding = ehdr32->e_ident[EI_DATA]; int elfVersion = ehdr32->e_ident[EI_VERSION]; if (elfClass != ELFCLASS32 && elfClass != ELFCLASS64) { messages << "Unknown ELF class.\n"; return false; } if (elfDataEncoding != ELFDATA2LSB && elfDataEncoding != ELFDATA2MSB) { messages << "Unknown ELF data encoding.\n"; return false; } if (elfVersion != EV_CURRENT) { messages << "Unknown ELF version.\n"; return false; } bool elf32 = elfClass == ELFCLASS32; #define ELF_HEADER_VAR(hdr32,hdr64,type,name) type name = elf32? hdr32->name \ : hdr64->name; \ if (elfDataEncoding == ELFDATA2LSB) { \ int size = elf32? sizeof(hdr32->name) : sizeof(hdr64->name); \ switch (size) { \ case 2: name = LE16_TO_HOST(name); break; \ case 4: name = LE32_TO_HOST(name); break; \ case 8: name = LE64_TO_HOST(name); break; \ } \ } else { \ int size = elf32? sizeof(hdr32->name) : sizeof(hdr64->name); \ switch (size) { \ case 2: name = BE16_TO_HOST(name); break; \ case 4: name = BE32_TO_HOST(name); break; \ case 8: name = BE64_TO_HOST(name); break; \ } \ } ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_type); if (e_type != ET_EXEC) { messages << "ELF file is not an Executable.\n"; return false; } ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_entry); ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_machine); ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_phoff); ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_phentsize); ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_phnum); ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_shoff); ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_shentsize); ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_shnum); size_t expectedPhentSize = (elf32? sizeof(Elf32_Phdr) : sizeof(Elf64_Phdr)); if (e_phentsize != expectedPhentSize) { messages << "Incorrect ELF phentsize? " << e_phentsize << ", should " "be " << expectedPhentSize << "\n" "Perhaps this is a dynamically linked " "binary (which isn't supported yet).\n"; return false; } size_t expectedShentSize = (elf32? sizeof(Elf32_Shdr) : sizeof(Elf64_Shdr)); if (e_shentsize != expectedShentSize) { messages << "Incorrect ELF shentsize? " << e_shentsize << ", should " "be " << expectedShentSize << "\n" "Perhaps this is a dynamically linked " "binary (which isn't supported yet).\n"; return false; } if (e_machine < N_ELF_MACHINE_TYPES) messages << elf_machine_type[e_machine]; else messages << "machine type '" << e_machine << "'"; messages << " ELF" << (elf32? 32 : 64) << " "; messages << (elfDataEncoding == ELFDATA2LSB? "LSB (LE)" : "MSB (BE)") << ": "; if (!elf32 && (e_machine == EM_PPC || e_machine == EM_PPC64)) messages << "PPC function descriptor at"; else messages << "entry point"; messages << " 0x"; messages.flags(std::ios::hex); // Special case for MIPS: 32-bit addresses are sign-extended. if (e_machine == EM_MIPS && elf32) e_entry = (int32_t) e_entry; uint64_t display_entry_point = e_entry; // MIPS16 encoding (16-bit words) is indicated by the lowest bit of the PC. bool mips16 = false; if (e_machine == EM_MIPS && (e_entry & 1)) { display_entry_point &= ~1; mips16 = true; } // SHmedia (SH64) 32-bit encoding is indicated by the lowest bit of the PC. bool shmedia = false; if (e_machine == EM_SH && (e_entry & 1)) { display_entry_point &= ~1; shmedia = true; } if (elf32) messages << setw(8) << setfill('0') << (uint32_t) display_entry_point; else messages << setw(16) << setfill('0') << (uint64_t) display_entry_point; if (mips16) messages << " (MIPS16 encoding)"; if (shmedia) messages << " (SHmedia encoding)"; messages << "\n"; // PROGRAM HEADERS size_t i; for (i=0; i= sizeof(Elf32_Phdr)); assert(sizeof(phdr_buf) >= sizeof(Elf64_Phdr)); Elf32_Phdr* phdr32 = (Elf32_Phdr*) phdr_buf; Elf64_Phdr* phdr64 = (Elf64_Phdr*) phdr_buf; memset(phdr_buf, 0, sizeof(phdr_buf)); int toRead = elf32? sizeof(Elf32_Phdr) : sizeof(Elf64_Phdr); file.read(phdr_buf, toRead); if (file.gcount() != toRead) { messages << "Unable to read Phdr.\n"; return false; } ELF_HEADER_VAR(phdr32, phdr64, uint64_t, p_type); ELF_HEADER_VAR(phdr32, phdr64, uint64_t, p_offset); ELF_HEADER_VAR(phdr32, phdr64, uint64_t, p_vaddr); ELF_HEADER_VAR(phdr32, phdr64, uint64_t, p_filesz); ELF_HEADER_VAR(phdr32, phdr64, uint64_t, p_memsz); // Skip non-loadable program segments: if (p_type != PT_LOAD) continue; if (p_memsz < p_filesz) { messages << "memsz < filesz. TODO: how" " to handle this? memsz = " << p_memsz << ", filesz = " << p_filesz << "\n"; return false; } // Special case for MIPS: 32-bit addresses are sign-extended. if (e_machine == EM_MIPS && elf32) p_vaddr = (int32_t) p_vaddr; messages.flags(std::ios::hex); messages << "loadable chunk: vaddr 0x"; if (elf32) messages << setw(8) << setfill('0') << (uint32_t) p_vaddr; else messages << setw(16) << setfill('0') << (uint64_t) p_vaddr; messages.flags(std::ios::dec); messages << ", " << p_filesz << " bytes\n"; file.seekg(p_offset, std::ios::beg); char databuf[65536]; uint64_t bytesRead = 0; uint64_t vaddrToWriteTo = p_vaddr; while (bytesRead < p_filesz) { int sizeToRead = sizeof(databuf); if (sizeToRead + bytesRead > p_filesz) sizeToRead = p_filesz - bytesRead; assert(sizeToRead != 0); memset(databuf, 0, sizeToRead); file.read(databuf, sizeToRead); int bytesReadThisTime = file.gcount(); bytesRead += bytesReadThisTime; // Write to the bus, one byte at a time. for (int k=0; kAddressSelect(vaddrToWriteTo); if (!bus->WriteData(databuf[k])) { messages.flags(std::ios::hex); messages << "Failed to write data to " "virtual address 0x" << vaddrToWriteTo << "\n"; return false; } ++ vaddrToWriteTo; } } } // SECTION HEADERS vector symtab; vector symstrings; for (i=0; i= sizeof(Elf32_Shdr)); assert(sizeof(shdr_buf) >= sizeof(Elf64_Shdr)); Elf32_Shdr* shdr32 = (Elf32_Shdr*) shdr_buf; Elf64_Shdr* shdr64 = (Elf64_Shdr*) shdr_buf; memset(shdr_buf, 0, sizeof(shdr_buf)); int toRead = elf32? sizeof(Elf32_Shdr) : sizeof(Elf64_Shdr); file.read(shdr_buf, toRead); if (file.gcount() != toRead) { messages << "Unable to read Shdr.\n"; return false; } ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_name); ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_type); ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_flags); ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_addr); ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_offset); ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_size); ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_link); ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_info); ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_addralign); ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_entsize); if (sh_type == SHT_SYMTAB) { if (symtab.size() > 0) { messages << "symtab: another symtab already loaded? TODO\n"; return false; } int entrySize = elf32? sizeof(Elf32_Sym) : sizeof(Elf64_Sym); int nEntries = sh_size / entrySize; messages.flags(std::ios::dec); messages << "symtab: " << nEntries << " symbols at 0x"; messages.flags(std::ios::hex); messages << sh_offset << "\n"; symtab.resize(sh_size); file.seekg(sh_offset, std::ios::beg); file.read(&symtab[0], sh_size); if ((uint64_t) file.gcount() != sh_size) { messages << "Failed to read all " << sh_size << " symbol bytes.\n"; return false; } } // TODO/HACK: Figure out which strtab to use. For now, simply // use the largest one! if (sh_type == SHT_STRTAB && sh_size > symstrings.size()) { messages.flags(std::ios::dec); messages << "strtab: " << sh_size << " bytes at 0x"; messages.flags(std::ios::hex); messages << sh_offset << "\n"; symstrings.resize(sh_size); file.seekg(sh_offset, std::ios::beg); file.read(&symstrings[0], sh_size); if ((uint64_t) file.gcount() != sh_size) { messages << "Failed to read all " << sh_size << " symbol string bytes.\n"; return false; } } } SymbolRegistry* symbolRegistry = NULL; CPUComponent* cpu = component->AsCPUComponent(); if (cpu != NULL) symbolRegistry = &cpu->GetSymbolRegistry(); // Symbols if (symbolRegistry != NULL && symtab.size() > 0 && symstrings.size() > 0) { int entrySize = elf32? sizeof(Elf32_Sym) : sizeof(Elf64_Sym); int nEntries = symtab.size() / entrySize; // For safety: symstrings.resize(symstrings.size() + 1); symstrings[symstrings.size() - 1] = '\0'; int nsymbols = 0; messages.flags(std::ios::hex); for (int j=0; j= symstrings.size() - 1) { messages << "symbol pointer mismatch?\n"; continue; } string symbol = &symstrings[st_name]; // Special case for MIPS: 32-bit addresses are sign-extended. if (e_machine == EM_MIPS && elf32) st_value = (int32_t) st_value; // Special case for MIPS: _gp symbol initiates the GP register. if (e_machine == EM_MIPS && symbol == "_gp") { messages << "found _gp address: 0x"; if (elf32) messages << setw(8) << setfill('0') << (uint32_t) st_value << "\n"; else messages << setw(16) << setfill('0') << (uint64_t) st_value << "\n"; stringstream ss; ss << st_value; component->SetVariableValue("gp", ss.str()); } // FOR DEBUGGING ONLY: // messages << "symbol name '" << symbol << "', addr 0x" << // st_value << ", size 0x" << st_size << "\n"; // Add this symbol to the symbol registry: symbolRegistry->AddSymbol(symbol, st_value); ++ nsymbols; } messages.flags(std::ios::dec); messages << nsymbols << " symbols read\n"; } // Set the CPU's entry point. #if 0 if (elf64 && arch == ARCH_PPC) { /* * Special case for 64-bit PPC ELFs: * * The ELF starting symbol points to a ".opd" section * which contains a function descriptor: * * uint64_t start; * uint64_t toc_base; * uint64_t something_else; (?) */ int res; unsigned char b[sizeof(uint64_t)]; uint64_t toc_base; debug("PPC64: "); res = m->cpus[0]->memory_rw(m->cpus[0], mem, eentry, b, sizeof(b), MEM_READ, NO_EXCEPTIONS); if (!res) debug(" [WARNING: could not read memory?] "); /* PPC are always big-endian: */ *entrypointp = ((uint64_t)b[0] << 56) + ((uint64_t)b[1] << 48) + ((uint64_t)b[2] << 40) + ((uint64_t)b[3] << 32) + ((uint64_t)b[4] << 24) + ((uint64_t)b[5] << 16) + ((uint64_t)b[6] << 8) + (uint64_t)b[7]; res = m->cpus[0]->memory_rw(m->cpus[0], mem, eentry + 8, b, sizeof(b), MEM_READ, NO_EXCEPTIONS); if (!res) fatal(" [WARNING: could not read memory?] "); toc_base = ((uint64_t)b[0] << 56) + ((uint64_t)b[1] << 48) + ((uint64_t)b[2] << 40) + ((uint64_t)b[3] << 32) + ((uint64_t)b[4] << 24) + ((uint64_t)b[5] << 16) + ((uint64_t)b[6] << 8) + (uint64_t)b[7]; debug("entrypoint 0x%016"PRIx64", toc_base 0x%016"PRIx64"\n", (uint64_t) *entrypointp, (uint64_t) toc_base); if (tocp != NULL) *tocp = toc_base; } #endif stringstream ss; ss << e_entry; component->SetVariableValue("pc", ss.str()); component->SetVariableValue("bigendian", elfDataEncoding == ELFDATA2LSB? "false" : "true"); return true; } /*****************************************************************************/ #ifdef WITHUNITTESTS #include "ComponentFactory.h" static void Test_FileLoader_ELF_Constructor() { FileLoader_ELF elfLoader("test/FileLoader_ELF_MIPS"); } UNITTESTS(FileLoader_ELF) { UNITTEST(Test_FileLoader_ELF_Constructor); // TODO } #endif gxemul-0.6.1/src/main/commands/QuitCommand.cc000644 001750 001750 00000005106 13402411502 021273 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/QuitCommand.h" #include "GXemul.h" QuitCommand::QuitCommand() : Command("quit", "") { } QuitCommand::~QuitCommand() { } bool QuitCommand::Execute(GXemul& gxemul, const vector& arguments) { gxemul.SetRunState(GXemul::Quitting); gxemul.GetUI()->Shutdown(); return true; } string QuitCommand::GetShortDescription() const { return "Quits the application."; } string QuitCommand::GetLongDescription() const { return "Quits the application."; } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_QuitCommand_Affect_RunState() { refcount_ptr cmd = new QuitCommand; vector dummyArguments; GXemul gxemul; UnitTest::Assert( "the default GXemul instance should be Paused", gxemul.GetRunState() == GXemul::Paused); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("runstate should have been changed to Quitting", gxemul.GetRunState() == GXemul::Quitting); } UNITTESTS(QuitCommand) { UNITTEST(Test_QuitCommand_Affect_RunState); } #endif gxemul-0.6.1/src/main/commands/VersionCommand.cc000644 001750 001750 00000004652 13402411502 022003 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/VersionCommand.h" #include "GXemul.h" VersionCommand::VersionCommand() : Command("version", "") { } VersionCommand::~VersionCommand() { } bool VersionCommand::Execute(GXemul& gxemul, const vector& arguments) { gxemul.GetUI()->ShowDebugMessage(gxemul.Version() + "\n"); return true; } string VersionCommand::GetShortDescription() const { return "Prints version information."; } string VersionCommand::GetLongDescription() const { return "Prints version information."; } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_VersionCommand_DontAcceptArgs() { refcount_ptr cmd = new VersionCommand; vector dummyArguments; UnitTest::Assert("version should not take any arguments", cmd->GetArgumentFormat() == ""); } UNITTESTS(VersionCommand) { UNITTEST(Test_VersionCommand_DontAcceptArgs); } #endif gxemul-0.6.1/src/main/commands/HelpCommand.cc000644 001750 001750 00000012621 13402411502 021241 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/HelpCommand.h" #include "GXemul.h" HelpCommand::HelpCommand() : Command("help", "[command-name]") { } HelpCommand::~HelpCommand() { } bool HelpCommand::Execute(GXemul& gxemul, const vector& arguments) { const Commands& commands = gxemul.GetCommandInterpreter().GetCommands(); Commands::const_iterator it; if (arguments.size() > 1) { gxemul.GetUI()->ShowDebugMessage("usage: help [cmd]\n"); return false; } if (arguments.size() == 1) { // Special case: root isn't really a command if (arguments[0] == "root") { gxemul.GetUI()->ShowDebugMessage( "\nroot\n----\n\n" "Shows the component tree which makes up the current emulation configuration.\n" "Technically, 'root' is not a command, but the name of the root node. Typing\n" "the name of any node in the configuration tree will dump the sub-tree starting\n" "at that node, followed by that node's own variables.\n\n"); return true; } it = commands.find(arguments[0]); if (it == commands.end()) { gxemul.GetUI()->ShowDebugMessage( "Command \"" + arguments[0] + "\" unknown.\n"); return false; } // command name + " " + argument format // ------------------------------------ // // Long description. string longhelp = arguments[0]; const string& argumentFormat = it->second->GetArgumentFormat(); if (argumentFormat != "") longhelp += " " + argumentFormat; int len = longhelp.length(); longhelp += "\n"; for (int i=0; isecond->GetLongDescription(); if (longhelp[longhelp.length() - 1] != '\n') longhelp += '\n'; gxemul.GetUI()->ShowDebugMessage("\n" + longhelp + "\n"); if (it->second->MayBeReexecutedWithoutArgs()) gxemul.GetUI()->ShowDebugMessage( "This command will be re-executed (without " "arguments), if an empty command\n" "line is issued.\n\n"); return true; } // Find the longest name + argument: size_t longest = 0; for (it = commands.begin(); it != commands.end(); ++ it) { const Command& command = *it->second; size_t len = command.GetCommandName().length(); if (command.GetArgumentFormat() != "") len += 1 + command.GetArgumentFormat().length(); if (len > longest) longest = len; } // Show all commands followed by their short descriptions: for (it = commands.begin(); it != commands.end(); ++ it) { const Command& command = *it->second; const string leadingSpaces = " "; const int nLeadingSpaces = 2; string str = leadingSpaces + command.GetCommandName(); if (command.GetArgumentFormat() != "") str += " " + command.GetArgumentFormat(); while (str.length() < longest + nLeadingSpaces) str += " "; str += " " + command.GetShortDescription(); gxemul.GetUI()->ShowDebugMessage(str + "\n"); } // ... followed by a short description of other possible commands: gxemul.GetUI()->ShowDebugMessage(" ------------------------------" "----------------------------------------------\n"); gxemul.GetUI()->ShowDebugMessage(" root " "Shows the entire component tree.\n"); gxemul.GetUI()->ShowDebugMessage(" " "Shows the component tree, from the named component.\n"); gxemul.GetUI()->ShowDebugMessage(" . " "Executes a method of a named component.\n"); gxemul.GetUI()->ShowDebugMessage(" . " "Prints the value of a variable of a named component.\n"); gxemul.GetUI()->ShowDebugMessage(" . = " "Assigns a value to a variable of a named component.\n"); return true; } string HelpCommand::GetShortDescription() const { return "Shows a help message."; } string HelpCommand::GetLongDescription() const { return "Shows a summary of all available commands, or, " "when given a specific command\n" "name as an argument, shows a detailed description about " "that command.\n"; } gxemul-0.6.1/src/main/commands/ContinueBackwardsCommand.cc000644 001750 001750 00000004533 13402411502 023762 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/ContinueBackwardsCommand.h" #include "GXemul.h" ContinueBackwardsCommand::ContinueBackwardsCommand() : Command("continue-backwards", "") { } ContinueBackwardsCommand::~ContinueBackwardsCommand() { } bool ContinueBackwardsCommand::Execute(GXemul& gxemul, const vector& arguments) { gxemul.GetUI()->ShowDebugMessage("TODO\n"); return false; } string ContinueBackwardsCommand::GetShortDescription() const { return "Runs the emulation backwards."; } string ContinueBackwardsCommand::GetLongDescription() const { return "Runs the emulation backwards."; } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_ContinueBackwardsCommand_Test() { // TODO } UNITTESTS(ContinueBackwardsCommand) { UNITTEST(Test_ContinueBackwardsCommand_Test); } #endif gxemul-0.6.1/src/main/commands/BackwardStepCommand.cc000644 001750 001750 00000026101 13402411502 022721 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/BackwardStepCommand.h" #include "GXemul.h" BackwardStepCommand::BackwardStepCommand() : Command("backward-step", "") { } BackwardStepCommand::~BackwardStepCommand() { } bool BackwardStepCommand::Execute(GXemul& gxemul, const vector& arguments) { StateVariable* stepvar = gxemul.GetRootComponent()->GetVariable("step"); uint64_t step = stepvar->ToInteger(); if (step == 0) { gxemul.GetUI()->ShowDebugMessage("Cannot go back further; " "already at step 0.\n"); return false; } stringstream stepss; stepss << (step - 1); const refcount_ptr lightClone = gxemul.GetRootComponent()->LightClone(); if (!gxemul.GetRootComponent()->SetVariableValue("step", stepss.str())) { gxemul.GetUI()->ShowDebugMessage("Failed to set root.step.\n"); return false; } // Indent all debug output with message header "step X -> step X-1: ": stringstream ss; ss << "step " << step << " -> " << (step-1) << ": "; UI::SetIndentationMessageHelper indentationHelper(gxemul.GetUI(), ss.str()); // Compare the clone of the component tree before changing the step // with what we have now. stringstream changeMessages; gxemul.GetRootComponent()->DetectChanges(lightClone, changeMessages); string msg = changeMessages.str(); if (msg == "") msg = "No state change.\n"; gxemul.GetUI()->ShowDebugMessage(msg); return true; } string BackwardStepCommand::GetShortDescription() const { return "Runs one step of the emulation backwards."; } string BackwardStepCommand::GetLongDescription() const { return "Runs one step of the emulation backwards. This command does the same as\n" "manually decreasing root.step by 1, except that all state changes are also\n" "displayed, e.g.:\n" "\n" "> backward-step\n" "step 3 -> 2: => cpu0.a1: 0 -> 0x2a\n" " => cpu0.pc: 0xffffffffbfc0004c -> 0xffffffffbfc00048\n" "\n" "This command requires that snapshotting support is enabled (using the\n" "-B command line option).\n"; } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_BackwardStepCommand_AlreadyAtStep0() { refcount_ptr cmd = new BackwardStepCommand; vector dummyArguments; GXemul gxemul; UnitTest::Assert("root.step should initially be zero", gxemul.GetStep(), 0); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("root.step should still be zero", gxemul.GetStep(), 0); } static void Test_BackwardStepCommand_NotWhenSnapshotsAreDisabled() { refcount_ptr cmd = new BackwardStepCommand; vector dummyArguments; GXemul gxemul; char filename[] = "test/FileLoader_ELF_MIPS"; char *filenames[] = { filename }; gxemul.ParseFilenames("testmips", 1, filenames); gxemul.Reset(); gxemul.SetSnapshottingEnabled(false); gxemul.GetCommandInterpreter().RunCommand("step 3"); gxemul.Execute(); UnitTest::Assert("root.step should initially be 3", gxemul.GetStep(), 3); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("cpu0"); UnitTest::Assert("3: cpu0.pc", cpu->GetVariable("pc")->ToString(), "0xffffffff80010104"); UnitTest::Assert("3: cpu0.sp", cpu->GetVariable("sp")->ToString(), "0xffffffffa0007ed0"); UnitTest::Assert("3: cpu0.v0", cpu->GetVariable("v0")->ToString(), "0xffffffff88880000"); UnitTest::Assert("3: cpu0.v1", cpu->GetVariable("v1")->ToString(), "0xffffffffcccc0000"); // This execute should FAIL, because snapshotting is disabled. cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("root.step should still be 3", gxemul.GetStep(), 3); } static void Test_BackwardStepCommand_Basic() { refcount_ptr cmd = new BackwardStepCommand; vector dummyArguments; GXemul gxemul; char filename[] = "test/FileLoader_ELF_MIPS"; char *filenames[] = { filename }; gxemul.ParseFilenames("testmips", 1, filenames); gxemul.Reset(); gxemul.SetSnapshottingEnabled(true); gxemul.GetCommandInterpreter().RunCommand("step 3"); gxemul.Execute(); UnitTest::Assert("root.step should initially be 3", gxemul.GetStep(), 3); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("cpu0"); UnitTest::Assert("3: cpu0.pc", cpu->GetVariable("pc")->ToString(), "0xffffffff80010104"); UnitTest::Assert("3: cpu0.sp", cpu->GetVariable("sp")->ToString(), "0xffffffffa0007ed0"); UnitTest::Assert("3: cpu0.v0", cpu->GetVariable("v0")->ToString(), "0xffffffff88880000"); UnitTest::Assert("3: cpu0.v1", cpu->GetVariable("v1")->ToString(), "0xffffffffcccc0000"); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("root.step should be 2", gxemul.GetStep(), 2); cpu = gxemul.GetRootComponent()->LookupPath("cpu0"); UnitTest::Assert("2: cpu0.pc", cpu->GetVariable("pc")->ToString(), "0xffffffff80010100"); UnitTest::Assert("2: cpu0.sp", cpu->GetVariable("sp")->ToString(), "0xffffffffa0007ed0"); UnitTest::Assert("2: cpu0.v0", cpu->GetVariable("v0")->ToString(), "0"); UnitTest::Assert("2: cpu0.v1", cpu->GetVariable("v1")->ToString(), "0xffffffffcccc0000"); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("root.step should be 1", gxemul.GetStep(), 1); cpu = gxemul.GetRootComponent()->LookupPath("cpu0"); UnitTest::Assert("1: cpu0.pc", cpu->GetVariable("pc")->ToString(), "0xffffffff800100fc"); UnitTest::Assert("1: cpu0.sp", cpu->GetVariable("sp")->ToString(), "0xffffffffa0007ed0"); UnitTest::Assert("1: cpu0.v0", cpu->GetVariable("v0")->ToString(), "0"); UnitTest::Assert("1: cpu0.v1", cpu->GetVariable("v1")->ToString(), "0"); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("root.step should be 0", gxemul.GetStep(), 0); cpu = gxemul.GetRootComponent()->LookupPath("cpu0"); UnitTest::Assert("0: cpu0.pc", cpu->GetVariable("pc")->ToString(), "0xffffffff800100f8"); UnitTest::Assert("0: cpu0.sp", cpu->GetVariable("sp")->ToString(), "0xffffffffa0007f00"); UnitTest::Assert("0: cpu0.v0", cpu->GetVariable("v0")->ToString(), "0"); UnitTest::Assert("0: cpu0.v1", cpu->GetVariable("v1")->ToString(), "0"); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("root.step should still be 0", gxemul.GetStep(), 0); cpu = gxemul.GetRootComponent()->LookupPath("cpu0"); UnitTest::Assert("X: cpu0.pc", cpu->GetVariable("pc")->ToString(), "0xffffffff800100f8"); UnitTest::Assert("X: cpu0.sp", cpu->GetVariable("sp")->ToString(), "0xffffffffa0007f00"); UnitTest::Assert("X: cpu0.v0", cpu->GetVariable("v0")->ToString(), "0"); UnitTest::Assert("X: cpu0.v1", cpu->GetVariable("v1")->ToString(), "0"); } // Reset resets the component tree, but does not load back the binary! static void Test_BackwardStepCommand_ManualAddAndLoad() { refcount_ptr cmd = new BackwardStepCommand; vector dummyArguments; GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testmips"); gxemul.GetCommandInterpreter().RunCommand("load test/FileLoader_ELF_MIPS cpu0"); gxemul.SetSnapshottingEnabled(true); gxemul.GetCommandInterpreter().RunCommand("step 3"); gxemul.Execute(); UnitTest::Assert("root.step should initially be 3", gxemul.GetStep(), 3); refcount_ptr cpu = gxemul.GetRootComponent()->LookupPath("cpu0"); UnitTest::Assert("3: cpu0.pc", cpu->GetVariable("pc")->ToString(), "0xffffffff80010104"); UnitTest::Assert("3: cpu0.sp", cpu->GetVariable("sp")->ToString(), "0xffffffffa0007ed0"); UnitTest::Assert("3: cpu0.v0", cpu->GetVariable("v0")->ToString(), "0xffffffff88880000"); UnitTest::Assert("3: cpu0.v1", cpu->GetVariable("v1")->ToString(), "0xffffffffcccc0000"); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("root.step should be 2", gxemul.GetStep(), 2); cpu = gxemul.GetRootComponent()->LookupPath("cpu0"); UnitTest::Assert("2: cpu0.pc", cpu->GetVariable("pc")->ToString(), "0xffffffff80010100"); UnitTest::Assert("2: cpu0.sp", cpu->GetVariable("sp")->ToString(), "0xffffffffa0007ed0"); UnitTest::Assert("2: cpu0.v0", cpu->GetVariable("v0")->ToString(), "0"); UnitTest::Assert("2: cpu0.v1", cpu->GetVariable("v1")->ToString(), "0xffffffffcccc0000"); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("root.step should be 1", gxemul.GetStep(), 1); cpu = gxemul.GetRootComponent()->LookupPath("cpu0"); UnitTest::Assert("1: cpu0.pc", cpu->GetVariable("pc")->ToString(), "0xffffffff800100fc"); UnitTest::Assert("1: cpu0.sp", cpu->GetVariable("sp")->ToString(), "0xffffffffa0007ed0"); UnitTest::Assert("1: cpu0.v0", cpu->GetVariable("v0")->ToString(), "0"); UnitTest::Assert("1: cpu0.v1", cpu->GetVariable("v1")->ToString(), "0"); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("root.step should be 0", gxemul.GetStep(), 0); cpu = gxemul.GetRootComponent()->LookupPath("cpu0"); UnitTest::Assert("0: cpu0.pc", cpu->GetVariable("pc")->ToString(), "0xffffffff800100f8"); UnitTest::Assert("0: cpu0.sp", cpu->GetVariable("sp")->ToString(), "0xffffffffa0007f00"); UnitTest::Assert("0: cpu0.v0", cpu->GetVariable("v0")->ToString(), "0"); UnitTest::Assert("0: cpu0.v1", cpu->GetVariable("v1")->ToString(), "0"); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("root.step should still be 0", gxemul.GetStep(), 0); cpu = gxemul.GetRootComponent()->LookupPath("cpu0"); UnitTest::Assert("X: cpu0.pc", cpu->GetVariable("pc")->ToString(), "0xffffffff800100f8"); UnitTest::Assert("X: cpu0.sp", cpu->GetVariable("sp")->ToString(), "0xffffffffa0007f00"); UnitTest::Assert("X: cpu0.v0", cpu->GetVariable("v0")->ToString(), "0"); UnitTest::Assert("X: cpu0.v1", cpu->GetVariable("v1")->ToString(), "0"); } UNITTESTS(BackwardStepCommand) { UNITTEST(Test_BackwardStepCommand_AlreadyAtStep0); UNITTEST(Test_BackwardStepCommand_NotWhenSnapshotsAreDisabled); UNITTEST(Test_BackwardStepCommand_Basic); UNITTEST(Test_BackwardStepCommand_ManualAddAndLoad); } #endif gxemul-0.6.1/src/main/commands/PauseCommand.cc000644 001750 001750 00000005362 13402411502 021432 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/PauseCommand.h" #include "GXemul.h" PauseCommand::PauseCommand() : Command("pause", "") { } PauseCommand::~PauseCommand() { } bool PauseCommand::Execute(GXemul& gxemul, const vector& arguments) { gxemul.SetRunState(GXemul::Paused); return true; } string PauseCommand::GetShortDescription() const { return "Pauses the current emulation."; } string PauseCommand::GetLongDescription() const { return "Pauses the emulation, by setting the " "current RunState to Paused."; } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_PauseCommand_Affect_RunState() { refcount_ptr cmd = new PauseCommand; vector dummyArguments; GXemul gxemul; UnitTest::Assert("the default GXemul instance should be Paused", gxemul.GetRunState() == GXemul::Paused); gxemul.SetRunState(GXemul::Running); UnitTest::Assert("the runstate should now be Running", gxemul.GetRunState() == GXemul::Running); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("runstate should have been changed to Paused", gxemul.GetRunState() == GXemul::Paused); } UNITTESTS(PauseCommand) { UNITTEST(Test_PauseCommand_Affect_RunState); } #endif gxemul-0.6.1/src/main/commands/CloseCommand.cc000644 001750 001750 00000004061 13402411502 021415 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/CloseCommand.h" #include "GXemul.h" CloseCommand::CloseCommand() : Command("close", "") { } CloseCommand::~CloseCommand() { } bool CloseCommand::Execute(GXemul& gxemul, const vector& arguments) { gxemul.ClearEmulation(); return true; } string CloseCommand::GetShortDescription() const { return "Discards (closes) the current emulation."; } string CloseCommand::GetLongDescription() const { return "Closes (discards) the current emulation.\n" "\n" "See also: load (to load an existing emulation)\n"; } gxemul-0.6.1/src/main/commands/MoveComponentCommand.cc000644 001750 001750 00000014443 13402411502 023146 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/MoveComponentCommand.h" #include "GXemul.h" MoveComponentCommand::MoveComponentCommand() : Command("move", "path-from path-to") { } MoveComponentCommand::~MoveComponentCommand() { } static void ShowMsg(GXemul& gxemul, const string& msg) { gxemul.GetUI()->ShowDebugMessage(msg); } bool MoveComponentCommand::Execute(GXemul& gxemul, const vector& arguments) { if (arguments.size() != 2) { ShowMsg(gxemul, "syntax: move path-from path-to\n"); return false; } string pathFrom = arguments[0]; string pathTo = arguments[1]; vector matchesFrom = gxemul.GetRootComponent()-> FindPathByPartialMatch(pathFrom); if (matchesFrom.size() == 0) { ShowMsg(gxemul, pathFrom + " is not a path to a known component.\n"); return false; } if (matchesFrom.size() > 1) { ShowMsg(gxemul, pathFrom + " matches multiple components:\n"); for (size_t i=0; i matchesTo = gxemul.GetRootComponent()-> FindPathByPartialMatch(pathTo); if (matchesTo.size() == 0) { ShowMsg(gxemul, pathTo + " is not a path to a known component.\n"); return false; } if (matchesTo.size() > 1) { ShowMsg(gxemul, pathTo + " matches multiple components:\n"); for (size_t i=0; i whatToMove = gxemul.GetRootComponent()->LookupPath(matchesFrom[0]); if (whatToMove.IsNULL()) { ShowMsg(gxemul, "Lookup of origin path " + pathFrom + " failed.\n"); return false; } refcount_ptr parent = whatToMove->GetParent(); if (parent.IsNULL()) { ShowMsg(gxemul, "Cannot find the component's parent.\n"); return false; } refcount_ptr whereToAddIt = gxemul.GetRootComponent()->LookupPath(matchesTo[0]); if (whereToAddIt.IsNULL()) { ShowMsg(gxemul, "Lookup of destination path " + pathTo + " failed.\n"); return false; } parent->RemoveChild(whatToMove); whereToAddIt->AddChild(whatToMove); return true; } string MoveComponentCommand::GetShortDescription() const { return "Moves a component within the tree."; } string MoveComponentCommand::GetLongDescription() const { return "Moves a component (given a path) from one place in the configuration\n" "tree to another. Example: Let's say a CPU component has by accident\n" "been added outside of the machine's mainbus0 (where it is supposed to\n" "be located). The move command fixes the problem:\n" "\n" "> add testmips\n" "> add mips_cpu \n" "> root\n" " root\n" " |-- machine0 [testmips]\n" " | \\-- mainbus0\n" " | |-- ram0 (32 MB at offset 0)\n" " | |-- rom0 (16 MB at offset 0x1fc00000)\n" " | \\-- cpu0 (MIPS, 100 MHz)\n" " \\-- cpu0 (MIPS, 100 MHz)\n" "> move root.cpu0 mainbus0 \n" "> root\n" " root\n" " \\-- machine0 [testmips]\n" " \\-- mainbus0\n" " |-- ram0 (32 MB at offset 0)\n" " |-- rom0 (16 MB at offset 0x1fc00000)\n" " |-- cpu0 (MIPS, 100 MHz)\n" " \\-- cpu1 (MIPS, 100 MHz)\n" "\n" "(Note that the moved cpu was automatically renamed to cpu1, to avoid a\n" "collision.)\n" "\n" "See also: add (to add new components)\n" " root (to inspect the current emulation setup)\n"; } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_MoveComponentCommand_Move() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testmips"); gxemul.GetCommandInterpreter().RunCommand("add ram"); refcount_ptr root = gxemul.GetRootComponent(); UnitTest::Assert("there should be 2 entries under root", root->GetChildren().size(), 2); gxemul.GetCommandInterpreter().RunCommand("move root.ram mainbus"); // The tree should now look like: // root // \-- machine0 [testmips] // \-- mainbus0 // |-- ram0 (32 MB at offset 0) // |-- rom0 (16 MB at offset 0x1fc00000) // |-- fb_videoram0 (15 MB at offset 0x12000000) // |-- cpu0 (MIPS, 100 MHz) // \-- ram1 (0 bytes at offset 0) UnitTest::Assert("there should now be 1 entry (machine0) under root", root->GetChildren().size(), 1); refcount_ptr machine0 = root->GetChildren()[0]; UnitTest::Assert("there should be 1 entry (mainbus0) under machine0", machine0->GetChildren().size(), 1); refcount_ptr mainbus0 = machine0->GetChildren()[0]; UnitTest::Assert("there should be 5 components on mainbus0", mainbus0->GetChildren().size(), 5); } UNITTESTS(MoveComponentCommand) { UNITTEST(Test_MoveComponentCommand_Move); } #endif gxemul-0.6.1/src/main/commands/SaveCommand.cc000644 001750 001750 00000010612 13402411502 021245 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/SaveCommand.h" #include "GXemul.h" #include SaveCommand::SaveCommand() : Command("save", "[filename [component-path]]") { } SaveCommand::~SaveCommand() { } static void ShowMsg(GXemul& gxemul, const string& msg) { gxemul.GetUI()->ShowDebugMessage(msg); } bool SaveCommand::Execute(GXemul& gxemul, const vector& arguments) { string filename = gxemul.GetEmulationFilename(); string path = "root"; if (arguments.size() > 2) { ShowMsg(gxemul, "Too many arguments.\n"); return false; } if (arguments.size() > 0) filename = arguments[0]; if (filename == "") { ShowMsg(gxemul, "No filename given.\n"); return false; } if (arguments.size() > 1) path = arguments[1]; vector matches = gxemul.GetRootComponent()-> FindPathByPartialMatch(path); if (matches.size() == 0) { ShowMsg(gxemul, path+" is not a path to a known component.\n"); return false; } if (matches.size() > 1) { ShowMsg(gxemul, path+" matches multiple components:\n"); for (size_t i=0; i component = gxemul.GetRootComponent()->LookupPath(matches[0]); if (component.IsNULL()) { ShowMsg(gxemul, "Lookup of " + path + " failed.\n"); return false; } const string extension = ".gxemul"; if (filename.length() < extension.length() || filename.substr( filename.length() - extension.length()) != extension) ShowMsg(gxemul, "Warning: the name "+filename+" does not have" " a .gxemul extension. Continuing anyway.\n"); // Write to the file: { std::fstream outputstream(filename.c_str(), std::ios::out | std::ios::trunc); if (outputstream.fail()) { ShowMsg(gxemul, "Error: Could not open " + filename + " for writing.\n"); return false; } SerializationContext context; component->Serialize(outputstream, context); } // Check that the file exists: { std::fstream inputstream(filename.c_str(), std::ios::in); if (inputstream.fail()) { ShowMsg(gxemul, "Error: Could not open " + filename + " for reading after writing to it; saving " " the emulation setup failed!\n"); return false; } } ShowMsg(gxemul, "Emulation setup saved to " + filename + "\n"); gxemul.SetEmulationFilename(filename); return true; } string SaveCommand::GetShortDescription() const { return "Saves the emulation to a file."; } string SaveCommand::GetLongDescription() const { return "Saves the entire emulation setup, or a part of it, to a file in the filesystem.\n" "The filename may be omitted, if it is known from an earlier save or load\n" "command. If the component path is omitted, the entire emulation setup, starting\n" "from the 'root' component, is saved.\n" "\n" "The filename extension should usually be .gxemul.\n" "\n" "See also: load (to load an emulation setup)\n"; } gxemul-0.6.1/src/main/commands/StatusCommand.cc000644 001750 001750 00000004455 13402411502 021642 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/StatusCommand.h" #include "GXemul.h" StatusCommand::StatusCommand() : Command("status", "") { } StatusCommand::~StatusCommand() { } bool StatusCommand::Execute(GXemul& gxemul, const vector& arguments) { stringstream ss; ss << "step " << gxemul.GetStep() << ", " << gxemul.GetRunStateAsString() << "\n"; gxemul.GetUI()->ShowDebugMessage(ss.str()); return true; } string StatusCommand::GetShortDescription() const { return "Shows the current status (runstate etc)."; } string StatusCommand::GetLongDescription() const { return "Shows the current status, which includes:\n\n" " * Number of emulated step\n" " * Runstate (Running or Paused)\n" "\n" "Typing CTRL-T at the command prompt also executes the 'status' command.\n"; } gxemul-0.6.1/src/main/commands/ResetCommand.cc000644 001750 001750 00000005434 13402411502 021437 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/ResetCommand.h" #include "GXemul.h" ResetCommand::ResetCommand() : Command("reset", "") { } ResetCommand::~ResetCommand() { } bool ResetCommand::Execute(GXemul& gxemul, const vector& arguments) { gxemul.SetRunState(GXemul::Paused); gxemul.Reset(); return true; } string ResetCommand::GetShortDescription() const { return "Resets the current emulation."; } string ResetCommand::GetLongDescription() const { return "Resets the emulation, by:\n\n" " 1) setting the current run state to Paused,\n" " 2) clearing the state of all components\n" " 3) reloading any binaries loaded on the command" " line (on-reset commands)\n"; } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_ResetCommand_RunState() { refcount_ptr cmd = new ResetCommand; vector dummyArguments; GXemul gxemul; UnitTest::Assert("the default GXemul instance should be Paused", gxemul.GetRunState() == GXemul::Paused); gxemul.SetRunState(GXemul::Running); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("runstate should now be Paused", gxemul.GetRunState() == GXemul::Paused); } UNITTESTS(ResetCommand) { UNITTEST(Test_ResetCommand_RunState); } #endif gxemul-0.6.1/src/main/commands/StepCommand.cc000644 001750 001750 00000010505 13402411502 021263 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/StepCommand.h" #include "GXemul.h" StepCommand::StepCommand() : Command("step", "[nsteps]") { } StepCommand::~StepCommand() { } bool StepCommand::Execute(GXemul& gxemul, const vector& arguments) { int64_t nsteps = 1; if (arguments.size() > 1) { gxemul.GetUI()->ShowDebugMessage("step: Too many arguments.\n"); return false; } if (arguments.size() > 0) { stringstream ss; ss << arguments[0]; ss >> nsteps; } if (nsteps < 1) { gxemul.GetUI()->ShowDebugMessage("nr of steps must be at least 1\n"); return false; } gxemul.SetRunState(GXemul::SingleStepping); gxemul.SetNrOfSingleStepsInARow(nsteps); return true; } string StepCommand::GetShortDescription() const { return "Runs one step of the emulation."; } string StepCommand::GetLongDescription() const { return "Runs one step (or multiple single-steps) in the emulation.\n" "\n" "See also: continue (to continue without single-stepping)\n"; } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_StepCommand_Affect_RunState() { refcount_ptr cmd = new StepCommand; vector dummyArguments; GXemul gxemul; UnitTest::Assert("the default GXemul instance should be Paused", gxemul.GetRunState() == GXemul::Paused); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("runstate should have been changed to SingleStepping", gxemul.GetRunState() == GXemul::SingleStepping); } static void Test_StepCommand_GoodArgs() { refcount_ptr cmd = new StepCommand; vector arguments; GXemul gxemul; arguments.push_back("42"); UnitTest::Assert("should have succeeded; good arguments", cmd->Execute(gxemul, arguments)); } static void Test_StepCommand_BadArgs_TooMany() { refcount_ptr cmd = new StepCommand; vector arguments; GXemul gxemul; arguments.push_back("42"); arguments.push_back("43"); UnitTest::Assert("should not have succeeded; noo many args", !cmd->Execute(gxemul, arguments)); } static void Test_StepCommand_BadArgs_Zero() { refcount_ptr cmd = new StepCommand; vector arguments; GXemul gxemul; arguments.push_back("0"); UnitTest::Assert("should not have succeeded; too few steps", !cmd->Execute(gxemul, arguments)); } static void Test_StepCommand_BadArgs_Negative() { refcount_ptr cmd = new StepCommand; vector arguments; GXemul gxemul; arguments.push_back("-42"); UnitTest::Assert("should not have succeeded; negative nr of steps", !cmd->Execute(gxemul, arguments)); } UNITTESTS(StepCommand) { UNITTEST(Test_StepCommand_Affect_RunState); UNITTEST(Test_StepCommand_GoodArgs); UNITTEST(Test_StepCommand_BadArgs_TooMany); UNITTEST(Test_StepCommand_BadArgs_Zero); UNITTEST(Test_StepCommand_BadArgs_Negative); } #endif gxemul-0.6.1/src/main/commands/ContinueCommand.cc000644 001750 001750 00000005243 13402411502 022137 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/ContinueCommand.h" #include "GXemul.h" ContinueCommand::ContinueCommand() : Command("continue", "") { } ContinueCommand::~ContinueCommand() { } bool ContinueCommand::Execute(GXemul& gxemul, const vector& arguments) { gxemul.SetRunState(GXemul::Running); return true; } string ContinueCommand::GetShortDescription() const { return "Continues the current emulation."; } string ContinueCommand::GetLongDescription() const { return "Continues the emulation.\n" "\n" "See also: step (to single-step forward)\n"; } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_ContinueCommand_Affect_RunState() { refcount_ptr cmd = new ContinueCommand; vector dummyArguments; GXemul gxemul; UnitTest::Assert("the default GXemul instance should be Paused", gxemul.GetRunState() == GXemul::Paused); cmd->Execute(gxemul, dummyArguments); UnitTest::Assert("runstate should have been changed to Running", gxemul.GetRunState() == GXemul::Running); } UNITTESTS(ContinueCommand) { UNITTEST(Test_ContinueCommand_Affect_RunState); } #endif gxemul-0.6.1/src/main/commands/Makefile.skel000644 001750 001750 00000001070 13402411502 021134 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/main/commands # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(CPEDANTIC) $(INCLUDE2) LIBS=$(OTHERLIBS) OBJS=AddComponentCommand.o BackwardStepCommand.o CloseCommand.o \ ContinueBackwardsCommand.o ContinueCommand.o CopyComponentCommand.o \ HelpCommand.o \ LoadCommand.o ListComponentsCommand.o MoveComponentCommand.o \ PauseCommand.o \ QuitCommand.o RemoveComponentCommand.o ResetCommand.o \ SaveCommand.o StatusCommand.o StepCommand.o VersionCommand.o all: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) clean_all: clean rm -f Makefile gxemul-0.6.1/src/main/commands/RemoveComponentCommand.cc000644 001750 001750 00000007567 13402411502 023506 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/RemoveComponentCommand.h" #include "GXemul.h" RemoveComponentCommand::RemoveComponentCommand() : Command("remove", "path") { } RemoveComponentCommand::~RemoveComponentCommand() { } static void ShowMsg(GXemul& gxemul, const string& msg) { gxemul.GetUI()->ShowDebugMessage(msg); } bool RemoveComponentCommand::Execute(GXemul& gxemul, const vector& arguments) { if (arguments.size() < 1) { ShowMsg(gxemul, "No path given.\n"); return false; } if (arguments.size() > 1) { ShowMsg(gxemul, "Too many arguments.\n"); return false; } string path = arguments[0]; vector matches = gxemul.GetRootComponent()-> FindPathByPartialMatch(path); if (matches.size() == 0) { ShowMsg(gxemul, path+" is not a path to a known component.\n"); return false; } if (matches.size() > 1) { ShowMsg(gxemul, path+" matches multiple components:\n"); for (size_t i=0; i whatToRemove = gxemul.GetRootComponent()->LookupPath(matches[0]); if (whatToRemove.IsNULL()) { ShowMsg(gxemul, "Lookup of " + path + " failed.\n"); return false; } refcount_ptr parent = whatToRemove->GetParent(); if (parent.IsNULL()) { ShowMsg(gxemul, "Cannot remove the root component.\n"); return false; } parent->RemoveChild(whatToRemove); return true; } string RemoveComponentCommand::GetShortDescription() const { return "Removes a component from the emulation."; } string RemoveComponentCommand::GetLongDescription() const { return "Removes a component (given a path) from the current emulation setup.\n" "The following example shows how to remove cpu1 from a particular machine:\n" "\n" "> root\n" " root\n" " \\-- machine0 [testmips]\n" " \\-- mainbus0\n" " |-- ram0 (32 MB at offset 0)\n" " |-- rom0 (16 MB at offset 0x1fc00000)\n" " |-- cpu0 (MIPS, 100 MHz)\n" " \\-- cpu1 (MIPS, 100 MHz)\n" "> remove cpu1 \n" "> root\n" " root\n" " \\-- machine0 [testmips]\n" " \\-- mainbus0\n" " |-- ram0 (32 MB at offset 0)\n" " |-- rom0 (16 MB at offset 0x1fc00000)\n" " \\-- cpu0 (MIPS, 100 MHz)\n" "\n" "See also: add (to add new components)\n" " root (to inspect the current emulation setup)\n"; } gxemul-0.6.1/src/main/commands/AddComponentCommand.cc000644 001750 001750 00000011216 13402411502 022723 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/AddComponentCommand.h" #include "ComponentFactory.h" #include "GXemul.h" AddComponentCommand::AddComponentCommand() : Command("add", "component-name [path]") { } AddComponentCommand::~AddComponentCommand() { } static void ShowMsg(GXemul& gxemul, const string& msg) { gxemul.GetUI()->ShowDebugMessage(msg); } bool AddComponentCommand::Execute(GXemul& gxemul, const vector& arguments) { if (arguments.size() < 1) { ShowMsg(gxemul, "No component-name given.\n"); return false; } if (arguments.size() > 2) { ShowMsg(gxemul, "Too many arguments.\n"); return false; } string componentName = arguments[0]; refcount_ptr componentToAdd = ComponentFactory::CreateComponent(componentName, &gxemul); if (componentToAdd.IsNULL()) { ShowMsg(gxemul, componentName + ": unknown component," " or invalid arguments given.\n"); return false; } string path = "root"; if (arguments.size() == 2) path = arguments[1]; vector matches = gxemul.GetRootComponent()-> FindPathByPartialMatch(path); if (matches.size() == 0) { ShowMsg(gxemul, path + ": not a path to a known component.\n"); return false; } if (matches.size() > 1) { ShowMsg(gxemul, path + " matches multiple components:\n"); for (size_t i=0; i whereToAddIt = gxemul.GetRootComponent()->LookupPath(matches[0]); if (whereToAddIt.IsNULL()) { ShowMsg(gxemul, path + ": lookup of path failed.\n"); return false; } whereToAddIt->AddChild(componentToAdd); return true; } string AddComponentCommand::GetShortDescription() const { return "Adds a component to the emulation."; } string AddComponentCommand::GetLongDescription() const { return "Adds a component (given by the component-name) to the current emulation\n" "setup. If path is omitted, the component is added at the root of the\n" "component tree. For example:\n" "\n" "> add testmips <-- this adds machine0\n" "> root\n" " root\n" " \\-- machine0 [testmips]\n" " \\-- mainbus0\n" " |-- ram0 (32 MB at offset 0)\n" " |-- rom0 (16 MB at offset 0x1fc00000)\n" " \\-- cpu0 (5KE, 100 MHz)\n" "...\n" "> add mips_cpu(model=R4400) mainbus0 <-- note that arguments\n" "> root can be given during\n" " root component creation\n" " \\-- machine0 [testmips]\n" " \\-- mainbus0\n" " |-- ram0 (32 MB at offset 0)\n" " |-- rom0 (16 MB at offset 0x1fc00000)\n" " |-- cpu0 (5KE, 100 MHz)\n" " \\-- cpu1 (R4400, 100 MHz)\n" "\n" "See also: copy (to copy/clone a component in the tree)\n" " list-components (to get a list of available component types)\n" " remove (to remove a component from the emulation)\n" " root (to inspect the current emulation setup)\n"; } gxemul-0.6.1/src/main/commands/CopyComponentCommand.cc000644 001750 001750 00000014224 13402411502 023147 0ustar00debugdebug000000 000000 /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/CopyComponentCommand.h" #include "GXemul.h" CopyComponentCommand::CopyComponentCommand() : Command("copy", "path-from path-to") { } CopyComponentCommand::~CopyComponentCommand() { } static void ShowMsg(GXemul& gxemul, const string& msg) { gxemul.GetUI()->ShowDebugMessage(msg); } bool CopyComponentCommand::Execute(GXemul& gxemul, const vector& arguments) { if (arguments.size() != 2) { ShowMsg(gxemul, "syntax: copy path-from path-to\n"); return false; } string pathFrom = arguments[0]; string pathTo = arguments[1]; vector matchesFrom = gxemul.GetRootComponent()-> FindPathByPartialMatch(pathFrom); if (matchesFrom.size() == 0) { ShowMsg(gxemul, pathFrom + " is not a path to a known component.\n"); return false; } if (matchesFrom.size() > 1) { ShowMsg(gxemul, pathFrom + " matches multiple components:\n"); for (size_t i=0; i matchesTo = gxemul.GetRootComponent()-> FindPathByPartialMatch(pathTo); if (matchesTo.size() == 0) { ShowMsg(gxemul, pathTo + " is not a path to a known component.\n"); return false; } if (matchesTo.size() > 1) { ShowMsg(gxemul, pathTo + " matches multiple components:\n"); for (size_t i=0; i whatToCopy = gxemul.GetRootComponent()->LookupPath(matchesFrom[0]); if (whatToCopy.IsNULL()) { ShowMsg(gxemul, "Lookup of origin path " + pathFrom + " failed.\n"); return false; } refcount_ptr clone = whatToCopy->Clone(); if (clone.IsNULL()) { ShowMsg(gxemul, "Failed to clone " + pathFrom + ".\n"); return false; } refcount_ptr whereToAddIt = gxemul.GetRootComponent()->LookupPath(matchesTo[0]); if (whereToAddIt.IsNULL()) { ShowMsg(gxemul, "Lookup of destination path " + pathTo + " failed.\n"); return false; } whereToAddIt->AddChild(clone); return true; } string CopyComponentCommand::GetShortDescription() const { return "Copies (clones) a component."; } string CopyComponentCommand::GetLongDescription() const { return "Copies a component (given a path) from one place in the configuration\n" "tree to another. The following example duplicates a CPU component:\n" "\n" "> root\n" " root\n" " \\-- machine0 [testmips]\n" " \\-- mainbus0\n" " |-- ram0 (32 MB at offset 0)\n" " |-- rom0 (16 MB at offset 0x1fc00000)\n" " \\-- cpu0 (MIPS, 100 MHz)\n" "> copy cpu0 mainbus\n" "> root\n" " root\n" " \\-- machine0 [testmips]\n" " \\-- mainbus0\n" " |-- ram0 (32 MB at offset 0)\n" " |-- rom0 (16 MB at offset 0x1fc00000)\n" " |-- cpu0 (MIPS, 100 MHz)\n" " \\-- cpu1 (MIPS, 100 MHz)\n" "\n" "(Note that the cloned CPU was automatically renamed to cpu1, to avoid a\n" "collision.)\n" "\n" "See also: add (to add new components)\n" " move (to move components within the tree)\n" " remove (to remove components)\n" " root (to inspect the current emulation setup)\n"; } /*****************************************************************************/ #ifdef WITHUNITTESTS static void Test_CopyComponentCommand_Copy() { GXemul gxemul; gxemul.GetCommandInterpreter().RunCommand("add testmips"); refcount_ptr root = gxemul.GetRootComponent(); UnitTest::Assert("there should initially be 1 entry under root", root->GetChildren().size(), 1); gxemul.GetCommandInterpreter().RunCommand("copy machine0 root"); // The tree should now look like: // root // |-- machine0 [testmips] // | \-- mainbus0 // | |-- ram0 (32 MB at offset 0) // | |-- rom0 (16 MB at offset 0x1fc00000) // | \-- cpu0 (MIPS, 100 MHz) // \-- machine1 [testmips] // \-- mainbus0 // |-- ram0 (32 MB at offset 0) // |-- rom0 (16 MB at offset 0x1fc00000) // \-- cpu0 (MIPS, 100 MHz) UnitTest::Assert("there should now be 2 entries (machine0 and machine1) under root", root->GetChildren().size(), 2); refcount_ptr machine0 = root->GetChildren()[0]; refcount_ptr machine1 = root->GetChildren()[1]; UnitTest::Assert("name 0 mismatch", machine0->GetVariable("name")->ToString(), "machine0"); UnitTest::Assert("name 1 mismatch", machine1->GetVariable("name")->ToString(), "machine1"); } UNITTESTS(CopyComponentCommand) { UNITTEST(Test_CopyComponentCommand_Copy); } #endif gxemul-0.6.1/src/main/commands/ListComponentsCommand.cc000644 001750 001750 00000005426 13402411502 023337 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "commands/ListComponentsCommand.h" #include "ComponentFactory.h" #include "GXemul.h" ListComponentsCommand::ListComponentsCommand() : Command("list-components", "") { } ListComponentsCommand::~ListComponentsCommand() { } bool ListComponentsCommand::Execute(GXemul& gxemul, const vector& arguments) { vector allComponents = ComponentFactory::GetAllComponentNames(false); size_t maxLen = 0; size_t i; for (i=0; i maxLen) maxLen = allComponents[i].length(); for (i=0; i creatable = ComponentFactory::CreateComponent(name); if (creatable.IsNULL()) { // msg << " (un-creatable)"; continue; } msg << " " + name; for (size_t j = 0; j < 3 + maxLen - name.length(); j++) msg << " "; msg << ComponentFactory::GetAttribute(name, "description"); msg << "\n"; gxemul.GetUI()->ShowDebugMessage(msg.str()); } return true; } string ListComponentsCommand::GetShortDescription() const { return "Displays all available components."; } string ListComponentsCommand::GetLongDescription() const { return "Displays a list of all available components."; } gxemul-0.6.1/src/main/commands/LoadCommand.cc000644 001750 001750 00000017417 13402411502 021240 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "commands/LoadCommand.h" #include "FileLoader.h" #include "GXemul.h" LoadCommand::LoadCommand() : Command("load", "[filename [component-path]]") { } LoadCommand::~LoadCommand() { } static void ShowMsg(GXemul& gxemul, const string& msg) { gxemul.GetUI()->ShowDebugMessage(msg); } bool LoadCommand::IsComponentTree(GXemul& gxemul, const string& filename) const { std::ifstream file(filename.c_str()); if (file.fail()) return false; char buf[256]; file.read(buf, sizeof(buf)); if (file.gcount() < 10) return false; // Saved component trees start with the string "component ". return (strncmp(buf, "component ", 10) == 0); } bool LoadCommand::LoadComponentTree(GXemul& gxemul, const string&filename, refcount_ptr specifiedComponent) const { const string extension = ".gxemul"; if (filename.length() < extension.length() || filename.substr( filename.length() - extension.length()) != extension) ShowMsg(gxemul, "Warning: the name " + filename + " does not have a .gxemul extension. Continuing anyway.\n"); refcount_ptr component; // Load from the file std::ifstream file(filename.c_str()); if (file.fail()) { ShowMsg(gxemul, "Unable to open " + filename + " for reading.\n"); return false; } // Figure out the file's size: file.seekg(0, std::ios::end); std::streampos fileSize = file.tellg(); file.seekg(0, std::ios::beg); // Read the entire file into a string. // TODO: This is wasteful, of course. It actually takes twice the // size of the file, since the string constructor generates a _copy_. // But string takes care of unicode and such (if compiled as ustring). vector buf; buf.resize((size_t)fileSize + 1); memset(&buf[0], 0, fileSize); file.read(&buf[0], fileSize); if (file.gcount() != fileSize) { ShowMsg(gxemul, "Loading from " + filename + " failed; " "could not read all of the file?\n"); return false; } string str(&buf[0], fileSize); file.close(); size_t strPos = 0; stringstream messages; component = Component::Deserialize(messages, str, strPos); if (messages.str().length() > 0) ShowMsg(gxemul, messages.str()); if (component.IsNULL()) { ShowMsg(gxemul, "Loading from " + filename + " failed; " "no component found?\n"); return false; } if (specifiedComponent.IsNULL()) { const StateVariable* name = component->GetVariable("name"); if (name == NULL || name->ToString() != "root") gxemul.GetRootComponent()->AddChild(component); else gxemul.SetRootComponent(component); gxemul.SetEmulationFilename(filename); ShowMsg(gxemul, filename + " loaded\n"); } else { specifiedComponent->AddChild(component); ShowMsg(gxemul, filename + " loaded into " + specifiedComponent->GenerateShortestPossiblePath() + "\n"); } return true; } bool LoadCommand::Execute(GXemul& gxemul, const vector& arguments) { string filename = gxemul.GetEmulationFilename(); string path = ""; if (arguments.size() > 2) { ShowMsg(gxemul, "Too many arguments.\n"); return false; } if (arguments.size() > 0) filename = arguments[0]; if (filename == "") { ShowMsg(gxemul, "No filename given.\n"); return false; } if (arguments.size() > 1) path = arguments[1]; // Figure out the component path, if it was specified. refcount_ptr specifiedComponent; if (path != "") { vector matches = gxemul.GetRootComponent()-> FindPathByPartialMatch(path); if (matches.size() == 0) { ShowMsg(gxemul, path + " is not a path to a known component.\n"); return false; } if (matches.size() > 1) { ShowMsg(gxemul, path + " matches multiple components:\n"); for (size_t i=0; iLookupPath(matches[0]); if (specifiedComponent.IsNULL()) { ShowMsg(gxemul, "Lookup of " + path + " failed.\n"); return false; } } // 1. Is it a component tree? if (IsComponentTree(gxemul, filename)) { if (specifiedComponent.IsNULL()) gxemul.ClearEmulation(); return LoadComponentTree(gxemul, filename, specifiedComponent); } if (specifiedComponent.IsNULL()) { ShowMsg(gxemul, "The specified file to load (" + filename + ") is not a configuration tree. If it is a binary to load," " you need to specify a component path where to load the" " binary.\n"); return false; } // 2. Is it a binary (ELF, a.out, ...)? FileLoader fileLoader(filename); stringstream messages; if (fileLoader.Load(specifiedComponent, messages)) { gxemul.GetUI()->ShowDebugMessage(specifiedComponent, filename + " loaded\n" + messages.str()); return true; } else { gxemul.GetUI()->ShowDebugMessage(specifiedComponent, "FAILED to load " + filename + "\n" + messages.str()); return false; } } string LoadCommand::GetShortDescription() const { return "Loads a file."; } string LoadCommand::GetLongDescription() const { return "Loads a file into a location in the component tree. There are two different\n" "uses, which all share the same general syntax but differ in meaning.\n" "\n" "1. Loads an emulation setup (.gxemul) which was previously saved with the\n" " 'save' command. For example, if a machine was previously saved into\n" " myMachine.gxemul, then\n" "\n" " load myMachine.gxemul root\n" "\n" " will add the machine to the current emulation tree, next to any other\n" " machines.\n" "\n" " load myMachine.gxemul\n" "\n" " will instead replace the whole configuration tree with what's in\n" " myMachine.gxemul. The filename may be omitted, if it is known from an\n" " earlier save or load command.\n" "\n" "2. Loads a binary (ELF, a.out, ...) into a CPU or data bus. E.g.:\n" "\n" " load netbsd-RAMDISK cpu0\n" "\n" " will load a NetBSD kernel into cpu0 (assuming that cpu0 is not ambiguous).\n" " The reason why files should be loaded into CPUs and not into RAM components\n" " is that binaries are often linked to virtual addresses, and the CPU does\n" " virtual to physical address translation.\n" "\n" "See also: save (to save an emulation to a file)\n"; } gxemul-0.6.1/src/debugger/Makefile.skel000644 001750 001750 00000000413 13402411502 020173 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/debugger # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(XINCLUDE) $(DINCLUDE) OBJS=debugger.o debugger_expr.o all: $(OBJS) $(OBJS): Makefile debugger.cc: debugger_cmds.cc clean: rm -f $(OBJS) *core tmp_*.*c clean_all: clean rm -f Makefile gxemul-0.6.1/src/debugger/debugger_cmds.cc000644 001750 001750 00000074561 13402411502 020716 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Debugger commands. Included from debugger.c. */ /* * debugger_cmd_allsettings(): */ static void debugger_cmd_allsettings(struct machine *m, char *cmd_line) { settings_debugdump(global_settings, GLOBAL_SETTINGS_NAME, 1); } /* * debugger_cmd_breakpoint(): * * TODO: automagic "expansion" for the subcommand names (s => show). */ static void debugger_cmd_breakpoint(struct machine *m, char *cmd_line) { int i, res; while (cmd_line[0] != '\0' && cmd_line[0] == ' ') cmd_line ++; if (cmd_line[0] == '\0') { printf("syntax: breakpoint subcmd [args...]\n"); printf("Available subcmds (and args) are:\n"); printf(" add addr add a breakpoint for address addr\n"); printf(" delete x delete breakpoint nr x\n"); printf(" show show current breakpoints\n"); return; } if (strcmp(cmd_line, "show") == 0) { if (m->breakpoints.n == 0) printf("No breakpoints set.\n"); for (i=0; ibreakpoints.n; i++) show_breakpoint(m, i); return; } if (strncmp(cmd_line, "delete ", 7) == 0) { int x = atoi(cmd_line + 7); if (m->breakpoints.n == 0) { printf("No breakpoints set.\n"); return; } if (x < 0 || x > m->breakpoints.n) { printf("Invalid breakpoint nr %i. Use 'breakpoint " "show' to see the current breakpoints.\n", x); return; } free(m->breakpoints.string[x]); for (i=x; ibreakpoints.n-1; i++) { m->breakpoints.addr[i] = m->breakpoints.addr[i+1]; m->breakpoints.string[i] = m->breakpoints.string[i+1]; } m->breakpoints.n --; /* Clear translations: */ for (i=0; incpus; i++) if (m->cpus[i]->translation_cache != NULL) cpu_create_or_reset_tc(m->cpus[i]); return; } if (strncmp(cmd_line, "add ", 4) == 0) { uint64_t tmp; size_t breakpoint_buf_len; i = m->breakpoints.n; res = debugger_parse_expression(m, cmd_line + 4, 0, &tmp); if (!res) { printf("Couldn't parse '%s'\n", cmd_line + 4); return; } CHECK_ALLOCATION(m->breakpoints.string = (char **) realloc( m->breakpoints.string, sizeof(char *) * (m->breakpoints.n + 1))); CHECK_ALLOCATION(m->breakpoints.addr = (uint64_t *) realloc( m->breakpoints.addr, sizeof(uint64_t) * (m->breakpoints.n + 1))); breakpoint_buf_len = strlen(cmd_line+4) + 1; CHECK_ALLOCATION(m->breakpoints.string[i] = (char *) malloc(breakpoint_buf_len)); strlcpy(m->breakpoints.string[i], cmd_line+4, breakpoint_buf_len); m->breakpoints.addr[i] = tmp; m->breakpoints.n ++; show_breakpoint(m, i); /* Clear translations: */ for (i=0; incpus; i++) if (m->cpus[i]->translation_cache != NULL) cpu_create_or_reset_tc(m->cpus[i]); return; } printf("Unknown breakpoint subcommand.\n"); } /* * debugger_cmd_continue(): */ static void debugger_cmd_continue(struct machine *m, char *cmd_line) { if (*cmd_line) { printf("syntax: continue\n"); return; } exit_debugger = 1; } /* * debugger_cmd_device(): */ static void debugger_cmd_device(struct machine *m, char *cmd_line) { int i; struct memory *mem; struct cpu *c; if (cmd_line[0] == '\0') goto return_help; if (m->cpus == NULL) { printf("No cpus (?)\n"); return; } c = m->cpus[m->bootstrap_cpu]; if (c == NULL) { printf("m->cpus[m->bootstrap_cpu] = NULL\n"); return; } mem = m->cpus[m->bootstrap_cpu]->mem; if (m->cpus == NULL) { printf("No cpus (?)\n"); return; } c = m->cpus[m->bootstrap_cpu]; if (c == NULL) { printf("m->cpus[m->bootstrap_cpu] = NULL\n"); return; } mem = m->cpus[m->bootstrap_cpu]->mem; if (strcmp(cmd_line, "all") == 0) { device_dumplist(); } else if (strncmp(cmd_line, "add ", 4) == 0) { device_add(m, cmd_line+4); } else if (strcmp(cmd_line, "consoles") == 0) { console_debug_dump(m); } else if (strncmp(cmd_line, "remove ", 7) == 0) { i = atoi(cmd_line + 7); if (i==0 && cmd_line[7]!='0') { printf("Weird device number. Use 'device list'.\n"); } else memory_device_remove(m->memory, i); } else if (strcmp(cmd_line, "list") == 0) { if (mem->n_mmapped_devices == 0) printf("No memory-mapped devices in this machine.\n"); for (i=0; in_mmapped_devices; i++) { printf("%2i: %25s @ 0x%011" PRIx64", len = 0x%" PRIx64, i, mem->devices[i].name, (uint64_t) mem->devices[i].baseaddr, (uint64_t) mem->devices[i].length); if (mem->devices[i].flags) { printf(" ("); if (mem->devices[i].flags & DM_DYNTRANS_OK) printf("DYNTRANS R"); if (mem->devices[i].flags &DM_DYNTRANS_WRITE_OK) printf("+W"); printf(")"); } printf("\n"); } } else goto return_help; return; return_help: printf("syntax: devices cmd [...]\n"); printf("Available cmds are:\n"); printf(" add name_and_params add a device to the current " "machine\n"); printf(" all list all registered devices\n"); printf(" consoles list all slave consoles\n"); printf(" list list memory-mapped devices in the" " current machine\n"); printf(" remove x remove device nr x from the " "current machine\n"); } /* * debugger_cmd_dump(): * * Dump emulated memory in hex and ASCII. * * syntax: dump [addr [endaddr]] */ static void debugger_cmd_dump(struct machine *m, char *cmd_line) { uint64_t addr, addr_start, addr_end; struct cpu *c; struct memory *mem; char *p = NULL; int x, r; if (cmd_line[0] != '\0') { uint64_t tmp; char *tmps; CHECK_ALLOCATION(tmps = strdup(cmd_line)); /* addr: */ p = strchr(tmps, ' '); if (p != NULL) *p = '\0'; r = debugger_parse_expression(m, tmps, 0, &tmp); free(tmps); if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) { printf("Unparsable address: %s\n", cmd_line); return; } else { last_dump_addr = tmp; } p = strchr(cmd_line, ' '); } if (m->cpus == NULL) { printf("No cpus (?)\n"); return; } c = m->cpus[m->bootstrap_cpu]; if (c == NULL) { printf("m->cpus[m->bootstrap_cpu] = NULL\n"); return; } mem = m->cpus[m->bootstrap_cpu]->mem; addr_start = last_dump_addr; if (addr_start == MAGIC_UNTOUCHED) addr_start = c->pc; addr_end = addr_start + 16 * 16; /* endaddr: */ if (p != NULL) { while (*p == ' ' && *p) p++; r = debugger_parse_expression(m, p, 0, &addr_end); if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) { printf("Unparsable address: %s\n", cmd_line); return; } } addr = addr_start & ~0xf; ctrl_c = 0; while (addr < addr_end) { unsigned char buf[16]; memset(buf, 0, sizeof(buf)); r = c->memory_rw(c, mem, addr, &buf[0], sizeof(buf), MEM_READ, CACHE_NONE | NO_EXCEPTIONS); if (c->is_32bit) printf("0x%08" PRIx32" ", (uint32_t) addr); else printf("0x%016" PRIx64" ", (uint64_t) addr); if (r == MEMORY_ACCESS_FAILED) printf("(memory access failed)\n"); else { for (x=0; x<16; x++) { if (addr + x >= addr_start && addr + x < addr_end) printf("%02x%s", buf[x], (x&3)==3? " " : ""); else printf(" %s", (x&3)==3? " " : ""); } printf(" "); for (x=0; x<16; x++) { if (addr + x >= addr_start && addr + x < addr_end) printf("%c", (buf[x]>=' ' && buf[x]<127)? buf[x] : '.'); else printf(" "); } printf("\n"); } if (ctrl_c) return; addr += sizeof(buf); } last_dump_addr = addr_end; strlcpy(repeat_cmd, "dump", MAX_CMD_BUFLEN); } /* * debugger_cmd_emul(): * * Dump info about the current emulation. */ static void debugger_cmd_emul(struct machine *m, char *cmd_line) { int iadd = DEBUG_INDENTATION; if (*cmd_line) { printf("syntax: emul\n"); return; } debug("emulation \"%s\":\n", debugger_emul->name == NULL? "(simple setup)" : debugger_emul->name); debug_indentation(iadd); emul_dumpinfo(debugger_emul); debug_indentation(-iadd); } /* * debugger_cmd_focus(): * * Changes focus to specific cpu, in a specific machine (in a specific * emulation). */ static void debugger_cmd_focus(struct machine *m, char *cmd_line) { int x = -1, y = -1; char *p, *p2; if (!cmd_line[0]) { printf("syntax: focus x[,y]\n"); printf("where x (cpu id) and y (machine number) " "are integers as\nreported by the 'emul'" " command.\n"); goto print_current_focus_and_return; } x = atoi(cmd_line); p = strchr(cmd_line, ','); if (p == cmd_line) { printf("No cpu number specified?\n"); return; } if (p != NULL) { y = atoi(p+1); p2 = strchr(p+1, ','); if (p2 == p+1) { printf("No machine number specified?\n"); return; } } if (y != -1) { /* Change machine: */ if (y < 0 || y >= debugger_emul->n_machines) { printf("Invalid machine number: %i\n", y); return; } debugger_cur_machine = y; debugger_machine = debugger_emul->machines[y]; } /* Change cpu: */ if (x < 0 || x >= debugger_machine->ncpus) { printf("Invalid cpu number: %i\n", x); return; } debugger_cur_cpu = x; print_current_focus_and_return: if (debugger_emul->n_machines > 1) printf("current machine (%i): \"%s\"\n", debugger_cur_machine, debugger_machine->name == NULL? "(no name)" : debugger_machine->name); printf("current cpu (%i)\n", debugger_cur_cpu); } /* This is defined below. */ static void debugger_cmd_help(struct machine *m, char *cmd_line); /* * debugger_cmd_itrace(): */ static void debugger_cmd_itrace(struct machine *m, char *cmd_line) { if (*cmd_line) { printf("syntax: itrace\n"); return; } old_instruction_trace = 1 - old_instruction_trace; printf("instruction_trace = %s\n", old_instruction_trace? "ON":"OFF"); /* TODO: how to preserve quiet_mode? */ old_quiet_mode = 0; printf("quiet_mode = %s\n", old_quiet_mode? "ON" : "OFF"); } /* * debugger_cmd_lookup(): */ static void debugger_cmd_lookup(struct machine *m, char *cmd_line) { uint64_t addr; int res; char *symbol; uint64_t offset; if (cmd_line[0] == '\0') { printf("syntax: lookup name|addr\n"); return; } /* Addresses never need to be given in decimal form anyway, so assuming hex here will be ok. */ addr = strtoull(cmd_line, NULL, 16); if (addr == 0) { uint64_t newaddr; res = get_symbol_addr(&m->symbol_context, cmd_line, &newaddr); if (!res) { printf("lookup for '%s' failed\n", cmd_line); return; } printf("%s = 0x", cmd_line); if (m->cpus[0]->is_32bit) printf("%08" PRIx32"\n", (uint32_t) newaddr); else printf("%016" PRIx64"\n", (uint64_t) newaddr); return; } symbol = get_symbol_name(&m->symbol_context, addr, &offset); if (symbol != NULL) { if (m->cpus[0]->is_32bit) printf("0x%08" PRIx32, (uint32_t) addr); else printf("0x%016" PRIx64, (uint64_t) addr); printf(" = %s\n", symbol); } else printf("lookup for '%s' failed\n", cmd_line); } /* * debugger_cmd_machine(): * * Dump info about the currently focused machine. */ static void debugger_cmd_machine(struct machine *m, char *cmd_line) { int iadd = 0; if (*cmd_line) { printf("syntax: machine\n"); return; } if (m->name != NULL) { debug("machine \"%s\":\n", m->name); iadd = DEBUG_INDENTATION; } debug_indentation(iadd); machine_dumpinfo(m); debug_indentation(-iadd); } /* * debugger_cmd_ninstrs(): */ static void debugger_cmd_ninstrs(struct machine *m, char *cmd_line) { int toggle = 1; int previous_mode = m->show_nr_of_instructions; if (cmd_line[0] != '\0') { while (cmd_line[0] != '\0' && cmd_line[0] == ' ') cmd_line ++; switch (cmd_line[0]) { case '0': toggle = 0; m->show_nr_of_instructions = 0; break; case '1': toggle = 0; m->show_nr_of_instructions = 1; break; case 'o': case 'O': toggle = 0; switch (cmd_line[1]) { case 'n': case 'N': m->show_nr_of_instructions = 1; break; default: m->show_nr_of_instructions = 0; } break; default: printf("syntax: trace [on|off]\n"); return; } } if (toggle) m->show_nr_of_instructions = !m->show_nr_of_instructions; printf("show_nr_of_instructions = %s", m->show_nr_of_instructions? "ON" : "OFF"); if (m->show_nr_of_instructions != previous_mode) printf(" (was: %s)", previous_mode? "ON" : "OFF"); printf("\n"); } /* * debugger_cmd_pause(): */ static void debugger_cmd_pause(struct machine *m, char *cmd_line) { int cpuid = -1; if (cmd_line[0] != '\0') cpuid = atoi(cmd_line); else { printf("syntax: pause cpuid\n"); return; } if (cpuid < 0 || cpuid >= m->ncpus) { printf("cpu%i doesn't exist.\n", cpuid); return; } m->cpus[cpuid]->running ^= 1; printf("cpu%i (%s) in machine \"%s\" is now %s\n", cpuid, m->cpus[cpuid]->name, m->name, m->cpus[cpuid]->running? "RUNNING" : "STOPPED"); } /* * debugger_cmd_print(): */ static void debugger_cmd_print(struct machine *m, char *cmd_line) { int res; uint64_t tmp; while (cmd_line[0] != '\0' && cmd_line[0] == ' ') cmd_line ++; if (cmd_line[0] == '\0') { printf("syntax: print expr\n"); return; } res = debugger_parse_expression(m, cmd_line, 0, &tmp); switch (res) { case PARSE_NOMATCH: printf("No match.\n"); break; case PARSE_MULTIPLE: printf("Multiple matches. Try prefixing with %%, $, or @.\n"); break; case PARSE_SETTINGS: printf("%s = 0x%" PRIx64"\n", cmd_line, (uint64_t)tmp); break; case PARSE_SYMBOL: if (m->cpus[0]->is_32bit) printf("%s = 0x%08" PRIx32"\n", cmd_line, (uint32_t)tmp); else printf("%s = 0x%016" PRIx64"\n", cmd_line,(uint64_t)tmp); break; case PARSE_NUMBER: printf("0x%" PRIx64"\n", (uint64_t) tmp); break; } } /* * debugger_cmd_put(): */ static void debugger_cmd_put(struct machine *m, char *cmd_line) { static char put_type = ' '; /* Remembered across multiple calls. */ char copy[200]; int res, syntax_ok = 0; char *p, *p2, *q = NULL; uint64_t addr, data; unsigned char a_byte; strncpy(copy, cmd_line, sizeof(copy)); copy[sizeof(copy)-1] = '\0'; /* syntax: put [b|h|w|d|q] addr, data */ p = strchr(copy, ','); if (p != NULL) { *p++ = '\0'; while (*p == ' ' && *p) p++; while (strlen(copy) >= 1 && copy[strlen(copy) - 1] == ' ') copy[strlen(copy) - 1] = '\0'; /* printf("L = '%s', R = '%s'\n", copy, p); */ q = copy; p2 = strchr(q, ' '); if (p2 != NULL) { *p2 = '\0'; if (strlen(q) != 1) { printf("Invalid type '%s'\n", q); return; } put_type = *q; q = p2 + 1; } /* printf("type '%c', L '%s', R '%s'\n", put_type, q, p); */ syntax_ok = 1; } if (!syntax_ok) { printf("syntax: put [b|h|w|d|q] addr, data\n"); printf(" b byte (8 bits)\n"); printf(" h half-word (16 bits)\n"); printf(" w word (32 bits)\n"); printf(" d doubleword (64 bits)\n"); printf(" q quad-word (128 bits)\n"); return; } if (put_type == ' ') { printf("No type specified.\n"); return; } /* here: q is the address, p is the data. */ res = debugger_parse_expression(m, q, 0, &addr); switch (res) { case PARSE_NOMATCH: printf("Couldn't parse the address.\n"); return; case PARSE_MULTIPLE: printf("Multiple matches for the address." " Try prefixing with %%, $, or @.\n"); return; case PARSE_SETTINGS: case PARSE_SYMBOL: case PARSE_NUMBER: break; default: printf("INTERNAL ERROR in debugger.c.\n"); return; } res = debugger_parse_expression(m, p, 0, &data); switch (res) { case PARSE_NOMATCH: printf("Couldn't parse the data.\n"); return; case PARSE_MULTIPLE: printf("Multiple matches for the data value." " Try prefixing with %%, $, or @.\n"); return; case PARSE_SETTINGS: case PARSE_SYMBOL: case PARSE_NUMBER: break; default: printf("INTERNAL ERROR in debugger.c.\n"); return; } /* TODO: haha, maybe this should be refactored */ switch (put_type) { case 'b': a_byte = data; if (m->cpus[0]->is_32bit) printf("0x%08" PRIx32, (uint32_t) addr); else printf("0x%016" PRIx64, (uint64_t) addr); printf(": %02x", a_byte); if (data > 255) printf(" (NOTE: truncating %0" PRIx64")", (uint64_t) data); res = m->cpus[0]->memory_rw(m->cpus[0], m->cpus[0]->mem, addr, &a_byte, 1, MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS); if (!res) printf(" FAILED!\n"); printf("\n"); return; case 'h': if ((addr & 1) != 0) printf("WARNING: address isn't aligned\n"); if (m->cpus[0]->is_32bit) printf("0x%08" PRIx32, (uint32_t) addr); else printf("0x%016" PRIx64, (uint64_t) addr); printf(": %04x", (int)data); if (data > 0xffff) printf(" (NOTE: truncating %0" PRIx64")", (uint64_t) data); res = store_16bit_word(m->cpus[0], addr, data); if (!res) printf(" FAILED!\n"); printf("\n"); return; case 'w': if ((addr & 3) != 0) printf("WARNING: address isn't aligned\n"); if (m->cpus[0]->is_32bit) printf("0x%08" PRIx32, (uint32_t) addr); else printf("0x%016" PRIx64, (uint64_t) addr); printf(": %08x", (int)data); if (data > 0xffffffff && (data >> 32) != 0 && (data >> 32) != 0xffffffff) printf(" (NOTE: truncating %0" PRIx64")", (uint64_t) data); res = store_32bit_word(m->cpus[0], addr, data); if (!res) printf(" FAILED!\n"); printf("\n"); return; case 'd': if ((addr & 7) != 0) printf("WARNING: address isn't aligned\n"); if (m->cpus[0]->is_32bit) printf("0x%08" PRIx32, (uint32_t) addr); else printf("0x%016" PRIx64, (uint64_t) addr); printf(": %016" PRIx64, (uint64_t) data); res = store_64bit_word(m->cpus[0], addr, data); if (!res) printf(" FAILED!\n"); printf("\n"); return; case 'q': printf("quad-words: TODO\n"); /* TODO */ return; default: printf("Unimplemented type '%c'\n", put_type); return; } } /* * debugger_cmd_quiet(): */ static void debugger_cmd_quiet(struct machine *m, char *cmd_line) { int toggle = 1; int previous_mode = old_quiet_mode; if (cmd_line[0] != '\0') { while (cmd_line[0] != '\0' && cmd_line[0] == ' ') cmd_line ++; switch (cmd_line[0]) { case '0': toggle = 0; old_quiet_mode = 0; break; case '1': toggle = 0; old_quiet_mode = 1; break; case 'o': case 'O': toggle = 0; switch (cmd_line[1]) { case 'n': case 'N': old_quiet_mode = 1; break; default: old_quiet_mode = 0; } break; default: printf("syntax: quiet [on|off]\n"); return; } } if (toggle) old_quiet_mode = 1 - old_quiet_mode; printf("quiet_mode = %s", old_quiet_mode? "ON" : "OFF"); if (old_quiet_mode != previous_mode) printf(" (was: %s)", previous_mode? "ON" : "OFF"); printf("\n"); } /* * debugger_cmd_quit(): */ static void debugger_cmd_quit(struct machine *m, char *cmd_line) { int j, k; if (*cmd_line) { printf("syntax: quit\n"); return; } single_step = NOT_SINGLE_STEPPING; force_debugger_at_exit = 0; for (j=0; jn_machines; j++) { struct machine *mp = debugger_emul->machines[j]; for (k=0; kncpus; k++) mp->cpus[k]->running = 0; mp->exit_without_entering_debugger = 1; } exit_debugger = 1; } /* * debugger_cmd_reg(): */ static void debugger_cmd_reg(struct machine *m, char *cmd_line) { int cpuid = debugger_cur_cpu, coprocnr = -1; int gprs, coprocs; char *p; /* [cpuid][,c] */ if (cmd_line[0] != '\0') { if (cmd_line[0] != ',') { cpuid = strtoull(cmd_line, NULL, 0); if (cpuid < 0 || cpuid >= m->ncpus) { printf("cpu%i doesn't exist.\n", cpuid); return; } } p = strchr(cmd_line, ','); if (p != NULL) { coprocnr = atoi(p + 1); if (coprocnr < 0 || coprocnr >= 4) { printf("Invalid coprocessor number.\n"); return; } } } gprs = (coprocnr == -1)? 1 : 0; coprocs = (coprocnr == -1)? 0x0 : (1 << coprocnr); cpu_register_dump(m, m->cpus[cpuid], gprs, coprocs); } /* * debugger_cmd_step(): */ static void debugger_cmd_step(struct machine *m, char *cmd_line) { int n = 1; if (cmd_line[0] != '\0') { n = strtoull(cmd_line, NULL, 0); if (n < 1) { printf("invalid nr of steps\n"); return; } } debugger_n_steps_left_before_interaction = n - 1; /* Special hack, see debugger() for more info. */ exit_debugger = -1; strlcpy(repeat_cmd, "step", MAX_CMD_BUFLEN); } /* * debugger_cmd_tlbdump(): * * Dump each CPU's TLB contents. */ static void debugger_cmd_tlbdump(struct machine *m, char *cmd_line) { int x = -1; int rawflag = 0; if (cmd_line[0] != '\0') { char *p; if (cmd_line[0] != ',') { x = strtoull(cmd_line, NULL, 0); if (x < 0 || x >= m->ncpus) { printf("cpu%i doesn't exist.\n", x); return; } } p = strchr(cmd_line, ','); if (p != NULL) { switch (p[1]) { case 'r': case 'R': rawflag = 1; break; default: printf("Unknown tlbdump flag.\n"); printf("syntax: tlbdump [cpuid][,r]\n"); return; } } } cpu_tlbdump(m, x, rawflag); } /* * debugger_cmd_trace(): */ static void debugger_cmd_trace(struct machine *m, char *cmd_line) { int toggle = 1; int previous_mode = old_show_trace_tree; if (cmd_line[0] != '\0') { while (cmd_line[0] != '\0' && cmd_line[0] == ' ') cmd_line ++; switch (cmd_line[0]) { case '0': toggle = 0; old_show_trace_tree = 0; break; case '1': toggle = 0; old_show_trace_tree = 1; break; case 'o': case 'O': toggle = 0; switch (cmd_line[1]) { case 'n': case 'N': old_show_trace_tree = 1; break; default: old_show_trace_tree = 0; } break; default: printf("syntax: trace [on|off]\n"); return; } } if (toggle) old_show_trace_tree = 1 - old_show_trace_tree; printf("show_trace_tree = %s", old_show_trace_tree? "ON" : "OFF"); if (old_show_trace_tree != previous_mode) printf(" (was: %s)", previous_mode? "ON" : "OFF"); printf("\n"); } /* * debugger_cmd_unassemble(): * * Dump emulated memory as instructions. * * syntax: unassemble [addr [endaddr]] */ static void debugger_cmd_unassemble(struct machine *m, char *cmd_line) { uint64_t addr, addr_start, addr_end; struct cpu *c; struct memory *mem; char *p = NULL; int r, lines_left = -1; if (cmd_line[0] != '\0') { uint64_t tmp; char *tmps; CHECK_ALLOCATION(tmps = strdup(cmd_line)); /* addr: */ p = strchr(tmps, ' '); if (p != NULL) *p = '\0'; r = debugger_parse_expression(m, tmps, 0, &tmp); free(tmps); if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) { printf("Unparsable address: %s\n", cmd_line); return; } else { last_unasm_addr = tmp; } p = strchr(cmd_line, ' '); } if (m->cpus == NULL) { printf("No cpus (?)\n"); return; } c = m->cpus[m->bootstrap_cpu]; if (c == NULL) { printf("m->cpus[m->bootstrap_cpu] = NULL\n"); return; } mem = m->cpus[m->bootstrap_cpu]->mem; addr_start = last_unasm_addr; if (addr_start == MAGIC_UNTOUCHED) addr_start = c->pc; addr_end = addr_start + 1000; /* endaddr: */ if (p != NULL) { while (*p == ' ' && *p) p++; r = debugger_parse_expression(m, p, 0, &addr_end); if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) { printf("Unparsable address: %s\n", cmd_line); return; } } else lines_left = 20; addr = addr_start; ctrl_c = 0; while (addr < addr_end) { unsigned int i, len; int failed = 0; unsigned char buf[17]; /* TODO: How long can an instruction be, on weird archs? */ memset(buf, 0, sizeof(buf)); for (i=0; iarch == ARCH_ARM) actualaddr &= ~1; if (c->memory_rw(c, mem, actualaddr+i, buf+i, 1, MEM_READ, CACHE_NONE | NO_EXCEPTIONS) == MEMORY_ACCESS_FAILED) failed ++; } if (failed == sizeof(buf)) { printf("(memory access failed)\n"); break; } len = cpu_disassemble_instr(m, c, buf, 0, addr); if (ctrl_c) return; if (len == 0) break; addr += len; if (lines_left != -1) { lines_left --; if (lines_left == 0) break; } } last_unasm_addr = addr; strlcpy(repeat_cmd, "unassemble", MAX_CMD_BUFLEN); } /* * debugger_cmd_version(): */ static void debugger_cmd_version(struct machine *m, char *cmd_line) { if (*cmd_line) { printf("syntax: version\n"); return; } printf("%s, %s\n", VERSION, COMPILE_DATE); } /****************************************************************************/ struct cmd { const char *name; const char *args; int tmp_flag; void (*f)(struct machine *, char *cmd_line); const char *description; }; static struct cmd cmds[] = { { "allsettings", "", 0, debugger_cmd_allsettings, "show all settings" }, { "breakpoint", "...", 0, debugger_cmd_breakpoint, "manipulate breakpoints" }, /* NOTE: Try to keep 'c' down to only one command. Having 'continue' available as a one-letter command is very convenient. */ { "continue", "", 0, debugger_cmd_continue, "continue execution" }, { "device", "...", 0, debugger_cmd_device, "show info about (or manipulate) devices" }, { "dump", "[addr [endaddr]]", 0, debugger_cmd_dump, "dump memory contents in hex and ASCII" }, { "emul", "", 0, debugger_cmd_emul, "Print a summary of the current emulation" }, { "focus", "x[,y[,z]]", 0, debugger_cmd_focus, "changes focus to cpu x, machine x, emul z" }, { "help", "", 0, debugger_cmd_help, "Print this help message" }, { "itrace", "", 0, debugger_cmd_itrace, "toggle instruction_trace on or off" }, { "lookup", "name|addr", 0, debugger_cmd_lookup, "lookup a symbol by name or address" }, { "machine", "", 0, debugger_cmd_machine, "Print a summary of the current machine" }, { "ninstrs", "[on|off]", 0, debugger_cmd_ninstrs, "toggle (set or unset) show_nr_of_instructions" }, { "pause", "cpuid", 0, debugger_cmd_pause, "pause (or unpause) a CPU" }, { "print", "expr", 0, debugger_cmd_print, "evaluate an expression without side-effects" }, { "put", "[b|h|w|d|q] addr, data", 0, debugger_cmd_put, "modify emulated memory contents" }, { "quiet", "[on|off]", 0, debugger_cmd_quiet, "toggle quiet_mode on or off" }, { "quit", "", 0, debugger_cmd_quit, "quit the emulator" }, /* NOTE: Try to keep 'r' down to only one command. Having 'reg' available as a one-letter command is very convenient. */ { "reg", "[cpuid][,c]", 0, debugger_cmd_reg, "show GPRs (or coprocessor c's registers)" }, /* NOTE: Try to keep 's' down to only one command. Having 'step' available as a one-letter command is very convenient. */ { "step", "[n]", 0, debugger_cmd_step, "single-step one (or n) instruction(s)" }, { "tlbdump", "[cpuid][,r]", 0, debugger_cmd_tlbdump, "dump TLB contents (add ',r' for raw data)" }, { "trace", "[on|off]", 0, debugger_cmd_trace, "toggle show_trace_tree on or off" }, /* NOTE: Try to keep 'u' down to only one command. Having 'unassemble' available as a one-letter command is very convenient. */ { "unassemble", "[addr [endaddr]]", 0, debugger_cmd_unassemble, "dump memory contents as instructions" }, { "version", "", 0, debugger_cmd_version, "Print version information" }, /* Note: NULL handler. */ { "x = expr", "", 0, NULL, "generic assignment" }, { NULL, NULL, 0, NULL, NULL } }; /* * debugger_cmd_help(): * * Print a list of available commands. * * NOTE: This is placed after the cmds[] array, because it needs to * access it. * * TODO: Command completion (ie just type "help s" for "help step"). */ static void debugger_cmd_help(struct machine *m, char *cmd_line) { int only_one = 0, only_one_match = 0; char *nlines_env = getenv("LINES"); int nlines = atoi(nlines_env != NULL? nlines_env : "999999"), curlines; size_t i, j, max_name_len = 0; if (cmd_line[0] != '\0') { only_one = 1; } i = 0; while (cmds[i].name != NULL) { size_t a = strlen(cmds[i].name); if (cmds[i].args != NULL) a += 1 + strlen(cmds[i].args); if (a > max_name_len) max_name_len = a; i++; } curlines = 0; if (!only_one) { printf("Available commands:\n"); curlines++; } i = 0; while (cmds[i].name != NULL) { char buf[100]; snprintf(buf, sizeof(buf), "%s", cmds[i].name); if (only_one) { if (strcmp(cmds[i].name, cmd_line) != 0) { i++; continue; } only_one_match = 1; } if (cmds[i].args != NULL) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %s", cmds[i].args); printf(" "); for (j=0; j= nlines - 1) { char ch; printf("-- more --"); fflush(stdout); ch = debugger_readchar(); printf("\n"); if (ch == 'q' || ch == 'Q') return; curlines = 0; } } if (only_one) { if (!only_one_match) printf("%s: no such command\n", cmd_line); return; } /* TODO: generalize/refactor */ curlines += 8; if (curlines > nlines - 1) { char ch; printf("-- more --"); fflush(stdout); ch = debugger_readchar(); printf("\n"); if (ch == 'q' || ch == 'Q') return; curlines = 0; } printf("\nIn generic assignments, x must be a register or other " "writable settings\nvariable, and expr can contain registers/" "settings, numeric values, or symbol\nnames, in combination with" " parenthesis and + - * / & %% ^ | operators.\nIn case there are" " multiple matches (i.e. a symbol that has the same name as a\n" "register), you may add a prefix character as a hint: '#' for" " registers, '@'\nfor symbols, and '$' for numeric values. Use" " 0x for hexadecimal values.\n"); } gxemul-0.6.1/src/debugger/debugger_expr.cc000644 001750 001750 00000023330 13402411502 020732 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Expression evaluator. * * * TODO: * Sign-extension is arch dependent (e.g. MIPS has it). * SPECIAL IMPORTANT CASE: Clear the delay_slot flag when writing * to the pc register. * TAB completion? :-) */ #include #include #include #include #include "cpu.h" #include "debugger.h" #include "machine.h" #include "misc.h" #include "settings.h" extern struct settings *global_settings; extern int debugger_cur_cpu; extern int debugger_cur_machine; /* * debugger_parse_name(): * * This function takes a string as input, and tries to match it to a register * name or a more general "setting", a hexadecimal or decimal numeric value, * or a registered symbol. * * Some examples: * * Settings (including register names): * verbose * pc * r5 * * Numeric values: * 12345 * 0x7fff1234 * * Symbols: * memcpy * * To force detection of different types, a character can be added in front of * the name: "$" for numeric values, "#" for registers or other settings, * and "@" for symbols. * * Return value is: * * PARSE_NOMATCH no match * PARSE_MULTIPLE multiple matches * * or one of these (and then *valuep is read or written, depending on * the writeflag): * * PARSE_SETTINGS a setting (e.g. a register) * PARSE_NUMBER a hex number * PARSE_SYMBOL a symbol */ int debugger_parse_name(struct machine *m, char *name, int writeflag, uint64_t *valuep) { int match_settings = 0, match_symbol = 0, match_numeric = 0; int skip_settings, skip_numeric, skip_symbol; if (m == NULL || name == NULL) { fprintf(stderr, "debugger_parse_name(): NULL ptr\n"); exit(1); } while (name[0] == '\t' || name[0] == ' ') name ++; /* Warn about non-signextended values: */ if (writeflag) { if (m->cpus[0]->is_32bit) { /* Automagically sign-extend. TODO: Is this good? */ if (((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL) (*valuep) |= 0xffffffff00000000ULL; } else { if (((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL) printf("WARNING: The value is not sign-extende" "d. Is this what you intended?\n"); } } skip_settings = name[0] == '$' || name[0] == '@'; skip_numeric = name[0] == '#' || name[0] == '@'; skip_symbol = name[0] == '$' || name[0] == '#'; if (!skip_settings) { char setting_name[400]; int res; res = settings_access(global_settings, name, writeflag, valuep); if (res == SETTINGS_OK) match_settings = 1; if (!match_settings) { snprintf(setting_name, sizeof(setting_name), GLOBAL_SETTINGS_NAME".%s", name); res = settings_access(global_settings, setting_name, writeflag, valuep); if (res == SETTINGS_OK) match_settings = 1; } if (!match_settings) { snprintf(setting_name, sizeof(setting_name), GLOBAL_SETTINGS_NAME".emul.%s", name); res = settings_access(global_settings, setting_name, writeflag, valuep); if (res == SETTINGS_OK) match_settings = 1; } if (!match_settings) { snprintf(setting_name, sizeof(setting_name), GLOBAL_SETTINGS_NAME".emul.machine[%i].%s", debugger_cur_machine, name); res = settings_access(global_settings, setting_name, writeflag, valuep); if (res == SETTINGS_OK) match_settings = 1; } if (!match_settings) { snprintf(setting_name, sizeof(setting_name), GLOBAL_SETTINGS_NAME".emul.machine[%i]." "cpu[%i].%s", debugger_cur_machine, debugger_cur_cpu, name); res = settings_access(global_settings, setting_name, writeflag, valuep); if (res == SETTINGS_OK) match_settings = 1; } } /* Check for a number match: */ if (!skip_numeric && isdigit((int)name[0])) { uint64_t x; x = strtoull(name, NULL, 0); if (writeflag) printf("You cannot assign like that.\n"); else *valuep = x; match_numeric = 1; } /* Check for a symbol match: */ if (!skip_symbol) { uint64_t newaddr; if (get_symbol_addr(&m->symbol_context, name, &newaddr)) { if (writeflag) printf("You cannot assign like that.\n"); else *valuep = newaddr; match_symbol = 1; } } if (match_settings + match_symbol + match_numeric > 1) return PARSE_MULTIPLE; if (match_settings) return PARSE_SETTINGS; if (match_numeric) return PARSE_NUMBER; if (match_symbol) return PARSE_SYMBOL; return PARSE_NOMATCH; } /* * debugger_parse_expression() * * Input: * writeflag = 0: expr = an expression to evaluate. The result is * returned in *valuep. * * writeflag = 1: expr = an lvalue name. *valuep is written to that * lvalue, using debugger_parse_name(). * * Parentheses always have precedence. * * / and % have second highest precedence. * + - & | ^ have lowest precedence. * * Return value on failure is: * * PARSE_NOMATCH one or more words in the expression didn't * match any known symbol/register/number * PARSE_MULTIPLE multiple matches within the expression * * Return value on success is PARSE_NUMBER (for now). * * * TODO: BETTER RETURN VALUE! * * NOTE: This is a quick hack, but hopefully it should work. The internal * mechanism is to split the expression into a left half and a right * half around an operator. This operator should be the operator * in the string which has the lowest precedence (except those that * are inside parentheses sub-expressions). E.g. if the expression * is a * (b + c * d) / e then the operator with the lowest * precedence is the first multiplication sign, and the split will * be: left = a * right = (b+c*d)/e */ int debugger_parse_expression(struct machine *m, char *expr, int writeflag, uint64_t *valuep) { int prec, res, i, nest; char *copy; if (writeflag) return debugger_parse_name(m, expr, writeflag, valuep); while (expr[0] == '\t' || expr[0] == ' ') expr ++; CHECK_ALLOCATION(copy = strdup(expr)); while (copy[0] && copy[strlen(copy)-1] == ' ') copy[strlen(copy)-1] = '\0'; /* Find the lowest operator precedence: */ i = 0; prec = 2; nest = 0; while (copy[i] != '\0') { switch (copy[i]) { case '(': nest ++; break; case ')': nest --; break; case '+': case '-': case '^': case '&': case '|': if (nest == 0) prec = 0; break; case '*': case '/': case '%': if (nest == 0 && prec > 1) prec = 1; break; } i++; } if (nest != 0) { printf("Unmatching parentheses.\n"); return PARSE_NOMATCH; } if (prec == 2 && copy[0] == '(' && copy[strlen(copy)-1] == ')') { int res2; copy[strlen(copy)-1] = '\0'; res2 = debugger_parse_expression(m, copy+1, 0, valuep); free(copy); return res2; } /* Split according to the first lowest priority operator: */ i = 0; nest = 0; while (copy[i] != '\0') { switch (copy[i]) { case '(': nest ++; break; case ')': nest --; break; case '*': case '/': case '%': if (prec == 0) break; /* Fallthrough. */ case '+': case '-': case '^': case '&': case '|': if (nest == 0) { uint64_t left, right; int res1, res2, j; char op = copy[i]; copy[i] = '\0'; j = i; while (j>0 && copy[j-1] == ' ') { copy[j-1] = '\0'; j --; } res1 = debugger_parse_expression( m, copy, 0, &left); res2 = debugger_parse_expression( m, copy + i + 1, 0, &right); if (res1 == PARSE_NOMATCH || res2 == PARSE_NOMATCH) { res = PARSE_NOMATCH; goto return_failure; } if (res1 == PARSE_MULTIPLE || res2 == PARSE_MULTIPLE) { res = PARSE_MULTIPLE; goto return_failure; } switch (op) { case '+': (*valuep) = left + right; break; case '-': (*valuep) = left - right; break; case '^': (*valuep) = left ^ right; break; case '&': (*valuep) = left & right; break; case '|': (*valuep) = left | right; break; case '*': (*valuep) = left * right; break; case '/': (*valuep) = left / right; break; case '%': (*valuep) = left % right; break; } goto return_ok; } break; } i ++; } res = debugger_parse_name(m, expr, writeflag, valuep); if (res == PARSE_NOMATCH || res == PARSE_MULTIPLE) goto return_failure; return_ok: free(copy); return PARSE_NUMBER; return_failure: free(copy); return res; } gxemul-0.6.1/src/debugger/debugger.cc000644 001750 001750 00000042571 13402411502 017704 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Single-step debugger. * * * This entire module is very much non-reentrant. :-/ TODO: Fix. */ #include #include #include #include #include #include #include "console.h" #include "cpu.h" #include "device.h" #include "debugger.h" #include "diskimage.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "net.h" #include "settings.h" #include "timer.h" #include "x11.h" extern int extra_argc; extern char **extra_argv; extern struct settings *global_settings; extern int quiet_mode; /* * Global debugger variables: * * TODO: Some of these should be moved to some other place! */ volatile int single_step = NOT_SINGLE_STEPPING; volatile int exit_debugger; int force_debugger_at_exit = 0; volatile int single_step_breakpoint = 0; int debugger_n_steps_left_before_interaction = 0; int old_instruction_trace = 0; int old_quiet_mode = 0; int old_show_trace_tree = 0; /* * Private (global) debugger variables: */ static volatile int ctrl_c; /* Currently focused CPU, machine, and emulation: */ int debugger_cur_cpu; int debugger_cur_machine; static struct machine *debugger_machine; static struct emul *debugger_emul; #define MAX_CMD_BUFLEN 72 #define N_PREVIOUS_CMDS 150 static char *last_cmd[N_PREVIOUS_CMDS]; static int last_cmd_index; static char repeat_cmd[MAX_CMD_BUFLEN]; #define MAGIC_UNTOUCHED 0x98ca76c2ffcc0011ULL static uint64_t last_dump_addr = MAGIC_UNTOUCHED; static uint64_t last_unasm_addr = MAGIC_UNTOUCHED; /* * debugger_readchar(): */ char debugger_readchar(void) { int ch; while ((ch = console_readchar(MAIN_CONSOLE)) < 0 && !exit_debugger) { /* Check for X11 events: */ x11_check_event(debugger_emul); /* Give up some CPU time: */ usleep(10000); } return ch; } /* * debugger_activate(): * * This is a signal handler for CTRL-C. It shouldn't be called directly, * but setup code in emul.c sets the CTRL-C signal handler to use this * function. */ void debugger_activate(int x) { ctrl_c = 1; if (single_step != NOT_SINGLE_STEPPING) { /* Already in the debugger. Do nothing. */ int i; for (i=0; icpus[0]->is_32bit) printf("%08" PRIx32, (uint32_t) m->breakpoints.addr[i]); else printf("%016" PRIx64, (uint64_t) m->breakpoints.addr[i]); if (m->breakpoints.string[i] != NULL) printf(" (%s)", m->breakpoints.string[i]); printf("\n"); } /****************************************************************************/ #include "debugger_cmds.cc" /****************************************************************************/ /* * debugger_assignment(): * * cmd contains something like "pc=0x80001000", or "r31=memcpy+0x40". */ void debugger_assignment(struct machine *m, char *cmd) { char *left, *right; int res_left, res_right; uint64_t tmp; uint64_t old_pc = m->cpus[0]->pc; /* TODO: multiple cpus? */ CHECK_ALLOCATION(left = (char *) malloc(MAX_CMD_BUFLEN)); strlcpy(left, cmd, MAX_CMD_BUFLEN); right = strchr(left, '='); if (right == NULL) { fprintf(stderr, "internal error in the debugger\n"); exit(1); } *right = '\0'; /* Remove trailing spaces in left: */ while (strlen(left) >= 1 && left[strlen(left)-1] == ' ') left[strlen(left)-1] = '\0'; /* Remove leading spaces in right: */ right++; while (*right == ' ' && *right != '\0') right++; /* printf("left = '%s'\nright = '%s'\n", left, right); */ res_right = debugger_parse_expression(m, right, 0, &tmp); switch (res_right) { case PARSE_NOMATCH: printf("No match for the right-hand side of the assignment.\n"); break; case PARSE_MULTIPLE: printf("Multiple matches for the right-hand side of the " "assignment.\n"); break; default: res_left = debugger_parse_expression(m, left, 1, &tmp); switch (res_left) { case PARSE_NOMATCH: printf("No match for the left-hand side of the " "assignment.\n"); break; case PARSE_MULTIPLE: printf("Multiple matches for the left-hand side " "of the assignment.\n"); break; default: debugger_cmd_print(m, left); } } /* * If the PC has changed, then release any breakpoint we were * currently stopped at. * * TODO: multiple cpus? */ if (old_pc != m->cpus[0]->pc) single_step_breakpoint = 0; free(left); } /* * debugger_execute_cmd(): */ void debugger_execute_cmd(char *cmd, int cmd_len) { int i, n, i_match, matchlen; /* * Is there a '=' on the command line? Then try to do an * assignment. (Only if there is just one word, followed * by the '=' sign. This makes it possible to use commands * such as "device add name addr=xyz".) */ if (strchr(cmd, '=') != NULL) { /* Count the nr of words: */ int nw = 0, inword = 0; char *p = cmd; while (*p) { if (*p == '=') break; if (*p != ' ') { if (!inword) nw ++; inword = 1; } else inword = 0; p++; } if (nw == 1) { debugger_assignment(debugger_machine, cmd); return; } } i = 0; while (cmds[i].name != NULL) cmds[i++].tmp_flag = 0; /* How many chars in cmd to match against: */ matchlen = 0; while (isalpha((int)cmd[matchlen])) matchlen ++; /* Check for a command name match: */ n = i = i_match = 0; while (cmds[i].name != NULL) { if (strncasecmp(cmds[i].name, cmd, matchlen) == 0 && cmds[i].f != NULL) { cmds[i].tmp_flag = 1; i_match = i; n++; } i++; } /* No match? */ if (n == 0) { printf("Unknown command '%s'. Type 'help' for help.\n", cmd); return; } /* More than one match? */ if (n > 1) { printf("Ambiguous command '%s': ", cmd); i = 0; while (cmds[i].name != NULL) { if (cmds[i].tmp_flag) printf(" %s", cmds[i].name); i++; } printf("\n"); return; } /* Exactly one match: */ if (cmds[i_match].f != NULL) { char *p = cmd + matchlen; /* Remove leading whitespace from the args... */ while (*p != '\0' && *p == ' ') p++; /* ... and run the command: */ cmds[i_match].f(debugger_machine, p); } else printf("FATAL ERROR: internal error in debugger.c:" " no handler for this command?\n"); } /* * debugger_readline(): * * Read a line from the terminal. */ static char *debugger_readline(void) { int ch, i, j, n, i_match, reallen, cmd_len, cursor_pos; int read_from_index = last_cmd_index; char *cmd = last_cmd[last_cmd_index]; cmd_len = 0; cmd[0] = '\0'; printf("GXemul> "); fflush(stdout); ch = '\0'; cmd_len = 0; cursor_pos = 0; while (ch != '\n' && !exit_debugger) { ch = debugger_readchar(); if ((ch == '\b' || ch == 127) && cursor_pos > 0) { /* Backspace. */ cursor_pos --; cmd_len --; memmove(cmd + cursor_pos, cmd + cursor_pos + 1, cmd_len); cmd[cmd_len] = '\0'; printf("\b"); for (i=cursor_pos; i 0 && cursor_pos < cmd_len) { /* CTRL-D: Delete. */ cmd_len --; memmove(cmd + cursor_pos, cmd + cursor_pos + 1, cmd_len); cmd[cmd_len] = '\0'; for (i=cursor_pos; i 0) { cursor_pos --; printf("\b"); } } else if (ch == 2) { /* CTRL-B: Backwards one character. */ if (cursor_pos > 0) { printf("\b"); cursor_pos --; } } else if (ch == 5) { /* CTRL-E: End of line. */ while (cursor_pos < cmd_len) { printf("%c", cmd[cursor_pos]); cursor_pos ++; } } else if (ch == 6) { /* CTRL-F: Forward one character. */ if (cursor_pos < cmd_len) { printf("%c", cmd[cursor_pos]); cursor_pos ++; } } else if (ch == 11) { /* CTRL-K: Kill to end of line. */ for (i=0; i= N_PREVIOUS_CMDS) i = 0; /* Special case: pressing 'down' to reach last_cmd_index: */ if (i == last_cmd_index) { read_from_index = i; for (i=cursor_pos; i=0; i--) printf("\b \b"); cmd[0] = '\0'; cmd_len = cursor_pos = 0; } else if (last_cmd[i][0] != '\0') { /* Copy from old line: */ read_from_index = i; for (i=cursor_pos; i=0; i--) printf("\b \b"); strlcpy(cmd, last_cmd[read_from_index], MAX_CMD_BUFLEN); cmd_len = strlen(cmd); printf("%s", cmd); cursor_pos = cmd_len; } } while (0); } else if (ch >= ' ' && cmd_len < MAX_CMD_BUFLEN-1) { /* Visible character: */ memmove(cmd + cursor_pos + 1, cmd + cursor_pos, cmd_len - cursor_pos); cmd[cursor_pos] = ch; cmd_len ++; cursor_pos ++; cmd[cmd_len] = '\0'; printf("%c", ch); for (i=cursor_pos; i "); for (i=0; i CTRL-P */ console_makeavail(MAIN_CONSOLE, 16); break; case 'B': /* Down. */ /* Down cursor ==> CTRL-N */ console_makeavail(MAIN_CONSOLE, 14); break; case 'C': /* Right cursor ==> CTRL-F */ console_makeavail(MAIN_CONSOLE, 6); break; case 'D': /* Left */ /* Left cursor ==> CTRL-B */ console_makeavail(MAIN_CONSOLE, 2); break; case 'F': /* End ==> CTRL-E */ console_makeavail(MAIN_CONSOLE, 5); break; case 'H': /* Home ==> CTRL-A */ console_makeavail(MAIN_CONSOLE, 1); break; } } } fflush(stdout); } if (exit_debugger) cmd[0] = '\0'; return cmd; } /* * debugger(): * * This is a loop, which reads a command from the terminal, and executes it. */ void debugger(void) { int i, cmd_len; char *cmd; if (debugger_n_steps_left_before_interaction > 0) { debugger_n_steps_left_before_interaction --; return; } /* * Clear all dyntrans translations, because otherwise things would * become to complex to keep in sync. */ /* TODO: In all machines */ for (i=0; incpus; i++) if (debugger_machine->cpus[i]->translation_cache != NULL) { cpu_create_or_reset_tc(debugger_machine->cpus[i]); debugger_machine->cpus[i]-> invalidate_translation_caches( debugger_machine->cpus[i], 0, INVALIDATE_ALL); } /* Stop timers while interacting with the user: */ timer_stop(); exit_debugger = 0; while (!exit_debugger) { /* Read a line from the terminal: */ cmd = debugger_readline(); cmd_len = strlen(cmd); /* Remove spaces: */ while (cmd_len > 0 && cmd[0]==' ') memmove(cmd, cmd+1, cmd_len --); while (cmd_len > 0 && cmd[cmd_len-1] == ' ') cmd[(cmd_len--)-1] = '\0'; /* No command? Then try reading another line. */ if (cmd_len == 0) { /* Special case for repeated commands: */ if (repeat_cmd[0] != '\0') strlcpy(cmd, repeat_cmd, MAX_CMD_BUFLEN); else continue; } else { last_cmd_index ++; if (last_cmd_index >= N_PREVIOUS_CMDS) last_cmd_index = 0; repeat_cmd[0] = '\0'; } debugger_execute_cmd(cmd, cmd_len); /* Special hack for the "step" command: */ if (exit_debugger == -1) return; } /* Start up timers again: */ timer_start(); /* ... and reset starttime, so that nr of instructions per second can be calculated correctly: */ for (i=0; incpus; i++) { gettimeofday(&debugger_machine->cpus[i]->starttime, NULL); debugger_machine->cpus[i]->ninstrs_since_gettimeofday = 0; } single_step = NOT_SINGLE_STEPPING; debugger_machine->instruction_trace = old_instruction_trace; debugger_machine->show_trace_tree = old_show_trace_tree; quiet_mode = old_quiet_mode; } /* * debugger_reset(): * * This function should be called before calling debugger(), when it is * absolutely necessary that debugger() is interactive. Otherwise, it might * return without doing anything, such as when single-stepping multiple * instructions at a time. */ void debugger_reset(void) { debugger_n_steps_left_before_interaction = 0; } /* * debugger_init(): * * Must be called before any other debugger function is used. */ void debugger_init(struct emul *emul) { int i; debugger_emul = emul; if (emul->n_machines < 1) { fprintf(stderr, "\nERROR: No machines, " "cannot handle this situation yet.\n\n"); exit(1); } debugger_machine = emul->machines[0]; debugger_cur_cpu = 0; debugger_cur_machine = 0; for (i=0; i #include #include #include #include "cpu.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "settings.h" #include "symbol.h" #define DYNTRANS_8K #define DYNTRANS_PAGESIZE 8192 #include "tmp_alpha_head.cc" /* Alpha symbolic register names: */ static const char *alpha_regname[N_ALPHA_REGS] = ALPHA_REG_NAMES; void alpha_irq_interrupt_assert(struct interrupt *interrupt); void alpha_irq_interrupt_deassert(struct interrupt *interrupt); /* * alpha_cpu_new(): * * Create a new Alpha CPU object by filling the CPU struct. * Return 1 on success, 0 if cpu_type_name isn't a valid Alpha processor. */ int alpha_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine, int cpu_id, char *cpu_type_name) { int i = 0; struct alpha_cpu_type_def cpu_type_defs[] = ALPHA_CPU_TYPE_DEFS; /* Scan the cpu_type_defs list for this cpu type: */ while (cpu_type_defs[i].name != NULL) { if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) { break; } i++; } if (cpu_type_defs[i].name == NULL) return 0; cpu->is_32bit = 0; cpu->byte_order = EMUL_LITTLE_ENDIAN; cpu->memory_rw = alpha_memory_rw; cpu->run_instr = alpha_run_instr; cpu->translate_v2p = alpha_translate_v2p; cpu->update_translation_table = alpha_update_translation_table; cpu->invalidate_translation_caches = alpha_invalidate_translation_caches; cpu->invalidate_code_translation = alpha_invalidate_code_translation; cpu->cd.alpha.cpu_type = cpu_type_defs[i]; /* Only show name and caches etc for CPU nr 0: */ if (cpu_id == 0) { debug("%s", cpu->name); } cpu->cd.alpha.r[ALPHA_SP] = 0xfffffc000000ff00ULL; /* Set up dummy kentry pointers to something which crashes the machine: */ store_32bit_word(cpu, 0x10010, 0x3fffffc); for (i=0; icd.alpha.kentry[i] = 0x10010; /* Bogus initial context (will be overwritten on first context switch): */ cpu->cd.alpha.ctx = 0x10100; CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc); for (i=0; icd.alpha.r[i]); /* Register the CPU interrupt pin: */ { struct interrupt templ; memset(&templ, 0, sizeof(templ)); templ.line = 0; templ.name = cpu->path; templ.extra = cpu; templ.interrupt_assert = alpha_irq_interrupt_assert; templ.interrupt_deassert = alpha_irq_interrupt_deassert; interrupt_handler_register(&templ); } return 1; } /* * alpha_cpu_dumpinfo(): */ void alpha_cpu_dumpinfo(struct cpu *cpu) { /* TODO */ debug("\n"); } /* * alpha_cpu_list_available_types(): * * Print a list of available Alpha CPU types. */ void alpha_cpu_list_available_types(void) { int i, j; struct alpha_cpu_type_def tdefs[] = ALPHA_CPU_TYPE_DEFS; i = 0; while (tdefs[i].name != NULL) { debug("%s", tdefs[i].name); for (j=13 - strlen(tdefs[i].name); j>0; j--) debug(" "); i++; if ((i % 4) == 0 || tdefs[i].name == NULL) debug("\n"); } } /* * alpha_cpu_register_dump(): * * Dump cpu registers in a relatively readable format. * * gprs: set to non-zero to dump GPRs and some special-purpose registers. * coprocs: set bit 0..3 to dump registers in coproc 0..3. */ void alpha_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs) { char *symbol; uint64_t offset; int i, x = cpu->cpu_id; if (gprs) { symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->pc, &offset); debug("cpu%i:\t pc = 0x%016" PRIx64, x, (uint64_t) cpu->pc); debug(" <%s>\n", symbol != NULL? symbol : " no symbol "); for (i=0; i> 1) + ((i & 1) << 4); if ((i % 2) == 0) debug("cpu%i:\t", x); if (r != ALPHA_ZERO) debug("%3s = 0x%016" PRIx64, alpha_regname[r], (uint64_t) cpu->cd.alpha.r[r]); if ((i % 2) == 1) debug("\n"); else debug(" "); } } } /* * alpha_cpu_tlbdump(): * * Called from the debugger to dump the TLB in a readable format. * x is the cpu number to dump, or -1 to dump all CPUs. * * If rawflag is nonzero, then the TLB contents isn't formated nicely, * just dumped. */ void alpha_cpu_tlbdump(struct machine *m, int x, int rawflag) { } /* * alpha_irq_interrupt_assert(): * alpha_irq_interrupt_deassert(): */ void alpha_irq_interrupt_assert(struct interrupt *interrupt) { struct cpu *cpu = (struct cpu *) interrupt->extra; cpu->cd.alpha.irq_asserted = 1; } void alpha_irq_interrupt_deassert(struct interrupt *interrupt) { struct cpu *cpu = (struct cpu *) interrupt->extra; cpu->cd.alpha.irq_asserted = 0; } /* * alpha_print_imm16_disp(): * * Used internally by alpha_cpu_disassemble_instr(). */ static void alpha_print_imm16_disp(int imm, int rb) { imm = (int16_t)imm; if (imm < 0) { debug("-"); imm = -imm; } if (imm <= 256) debug("%i", imm); else debug("0x%x", imm); if (rb != ALPHA_ZERO) debug("(%s)", alpha_regname[rb]); } /* * alpha_cpu_disassemble_instr(): * * Convert an instruction word into human readable format, for instruction * tracing. * * If running is 1, cpu->pc should be the address of the instruction. * * If running is 0, things that depend on the runtime environment (eg. * register contents) will not be shown, and addr will be used instead of * cpu->pc for relative addresses. */ int alpha_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib, int running, uint64_t dumpaddr) { uint32_t iw; uint64_t offset, tmp; int opcode, ra, rb, func, rc, imm, floating, rbrc = 0, indir = 0; const char *symbol, *mnem = NULL; char palcode_name[30]; if (running) dumpaddr = cpu->pc; symbol = get_symbol_name(&cpu->machine->symbol_context, dumpaddr, &offset); if (symbol != NULL && offset == 0) debug("<%s>\n", symbol); if (cpu->machine->ncpus > 1 && running) debug("cpu%i:\t", cpu->cpu_id); debug("%016" PRIx64": ", (uint64_t) dumpaddr); iw = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24); debug("%08x\t", (int)iw); opcode = iw >> 26; ra = (iw >> 21) & 31; rb = (iw >> 16) & 31; func = (iw >> 5) & 0x7ff; rc = iw & 31; imm = iw & 0xffff; switch (opcode) { case 0x00: alpha_palcode_name(iw & 0x3ffffff, palcode_name, sizeof(palcode_name)); debug("call_pal %s\n", palcode_name); break; case 0x08: case 0x09: debug("lda%s\t%s,", opcode == 9? "h" : "", alpha_regname[ra]); alpha_print_imm16_disp(imm, rb); debug("\n"); break; case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: floating = 0; switch (opcode) { case 0x0a: mnem = "ldbu"; break; case 0x0b: mnem = "ldq_u"; break; case 0x0c: mnem = "ldwu"; break; case 0x0d: mnem = "stw"; break; case 0x0e: mnem = "stb"; break; case 0x0f: mnem = "stq_u"; break; case 0x20: mnem = "ldf"; floating = 1; break; case 0x21: mnem = "ldg"; floating = 1; break; case 0x22: mnem = "lds"; floating = 1; break; case 0x23: mnem = "ldt"; floating = 1; break; case 0x24: mnem = "stf"; floating = 1; break; case 0x25: mnem = "stg"; floating = 1; break; case 0x26: mnem = "sts"; floating = 1; break; case 0x27: mnem = "stt"; floating = 1; break; case 0x28: mnem = "ldl"; break; case 0x29: mnem = "ldq"; break; case 0x2a: mnem = "ldl_l"; break; case 0x2b: mnem = "ldq_l"; break; case 0x2c: mnem = "stl"; break; case 0x2d: mnem = "stq"; break; case 0x2e: mnem = "stl_c"; break; case 0x2f: mnem = "stq_c"; break; } if (opcode == 0x0b && ra == ALPHA_ZERO) { debug("unop"); } else { debug("%s\t", mnem); if (floating) debug("f%i,", ra); else debug("%s,", alpha_regname[ra]); alpha_print_imm16_disp(imm, rb); } debug("\n"); break; case 0x10: switch (func & 0x7f) { case 0x00: mnem = "addl"; break; case 0x02: mnem = "s4addl"; break; case 0x09: mnem = "subl"; break; case 0x0b: mnem = "s4subl"; break; case 0x0f: mnem = "cmpbge"; break; case 0x12: mnem = "s8addl"; break; case 0x1b: mnem = "s8subl"; break; case 0x1d: mnem = "cmpult"; break; case 0x20: mnem = "addq"; break; case 0x22: mnem = "s4addq"; break; case 0x29: mnem = "subq"; break; case 0x2b: mnem = "s4subq"; break; case 0x2d: mnem = "cmpeq"; break; case 0x32: mnem = "s8addq"; break; case 0x3b: mnem = "s8subq"; break; case 0x3d: mnem = "cmpule"; break; case 0x40: mnem = "addl/v"; break; case 0x49: mnem = "subl/v"; break; case 0x4d: mnem = "cmplt"; break; case 0x60: mnem = "addq/v"; break; case 0x69: mnem = "subq/v"; break; case 0x6d: mnem = "cmple"; break; default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n", opcode, func); } if (mnem == NULL) break; if (func & 0x80) debug("%s\t%s,0x%x,%s\n", mnem, alpha_regname[ra], (rb << 3) + (func >> 8), alpha_regname[rc]); else debug("%s\t%s,%s,%s\n", mnem, alpha_regname[ra], alpha_regname[rb], alpha_regname[rc]); break; case 0x11: switch (func & 0x7f) { case 0x000: mnem = "and"; break; case 0x008: mnem = "andnot"; break; case 0x014: mnem = "cmovlbs"; break; case 0x016: mnem = "cmovlbc"; break; case 0x020: mnem = "or"; break; case 0x024: mnem = "cmoveq"; break; case 0x026: mnem = "cmovne"; break; case 0x028: mnem = "ornot"; break; case 0x040: mnem = "xor"; break; case 0x044: mnem = "cmovlt"; break; case 0x046: mnem = "cmovge"; break; case 0x048: mnem = "eqv"; break; case 0x061: mnem = "amask"; break; case 0x064: mnem = "cmovle"; break; case 0x066: mnem = "cmovgt"; break; case 0x06c: mnem = "implver"; break; default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n", opcode, func); } if (mnem == NULL) break; /* Special cases: "nop" etc: */ if (func == 0x020 && rc == ALPHA_ZERO) debug("nop\n"); else if (func == 0x020 && (ra == ALPHA_ZERO || rb == ALPHA_ZERO)) { if (ra == ALPHA_ZERO && rb == ALPHA_ZERO) debug("clr\t%s\n", alpha_regname[rc]); else if (ra == ALPHA_ZERO) debug("mov\t%s,%s\n", alpha_regname[rb], alpha_regname[rc]); else debug("mov\t%s,%s\n", alpha_regname[ra], alpha_regname[rc]); } else if (func == 0x1ec) { /* implver */ debug("%s\t%s\n", mnem, alpha_regname[rc]); } else if (func & 0x80) debug("%s\t%s,0x%x,%s\n", mnem, alpha_regname[ra], (rb << 3) + (func >> 8), alpha_regname[rc]); else debug("%s\t%s,%s,%s\n", mnem, alpha_regname[ra], alpha_regname[rb], alpha_regname[rc]); break; case 0x12: switch (func & 0x7f) { case 0x02: mnem = "mskbl"; break; case 0x06: mnem = "extbl"; break; case 0x0b: mnem = "insbl"; break; case 0x12: mnem = "mskwl"; break; case 0x16: mnem = "extwl"; break; case 0x1b: mnem = "inswl"; break; case 0x22: mnem = "mskll"; break; case 0x26: mnem = "extll"; break; case 0x2b: mnem = "insll"; break; case 0x30: mnem = "zap"; break; case 0x31: mnem = "zapnot"; break; case 0x32: mnem = "mskql"; break; case 0x34: mnem = "srl"; break; case 0x36: mnem = "extql"; break; case 0x39: mnem = "sll"; break; case 0x3b: mnem = "insql"; break; case 0x3c: mnem = "sra"; break; case 0x52: mnem = "mskwh"; break; case 0x57: mnem = "inswh"; break; case 0x5a: mnem = "extwh"; break; case 0x62: mnem = "msklh"; break; case 0x67: mnem = "inslh"; break; case 0x6a: mnem = "extlh"; break; case 0x72: mnem = "mskqh"; break; case 0x77: mnem = "insqh"; break; case 0x7a: mnem = "extqh"; break; default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n", opcode, func); } if (mnem == NULL) break; if (func & 0x80) debug("%s\t%s,0x%x,%s\n", mnem, alpha_regname[ra], (rb << 3) + (func >> 8), alpha_regname[rc]); else debug("%s\t%s,%s,%s\n", mnem, alpha_regname[ra], alpha_regname[rb], alpha_regname[rc]); break; case 0x13: switch (func & 0x7f) { case 0x00: mnem = "mull"; break; case 0x20: mnem = "mulq"; break; case 0x30: mnem = "umulh"; break; case 0x40: mnem = "mull/v"; break; case 0x60: mnem = "mulq/v"; break; default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n", opcode, func); } if (mnem == NULL) break; if (func & 0x80) debug("%s\t%s,0x%x,%s\n", mnem, alpha_regname[ra], (rb << 3) + (func >> 8), alpha_regname[rc]); else debug("%s\t%s,%s,%s\n", mnem, alpha_regname[ra], alpha_regname[rb], alpha_regname[rc]); break; case 0x16: switch (func & 0x7ff) { case 0x02f: mnem = "cvttq/c"; rbrc = 1; break; case 0x080: mnem = "adds"; break; case 0x081: mnem = "subs"; break; case 0x082: mnem = "muls"; break; case 0x083: mnem = "XXXx083"; break; case 0x0a0: mnem = "addt"; break; case 0x0a1: mnem = "subt"; break; case 0x0a2: mnem = "mult"; break; case 0x0a3: mnem = "divt"; break; case 0x0a5: mnem = "cmpteq"; break; case 0x0a6: mnem = "cmptlt"; break; case 0x0a7: mnem = "cmptle"; break; case 0x0be: mnem = "cvtqt"; rbrc = 1; break; default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n", opcode, func); } if (mnem == NULL) break; if (rbrc) debug("%s\tf%i,f%i\n", mnem, rb, rc); else debug("%s\tf%i,f%i,f%i\n", mnem, ra, rb, rc); break; case 0x17: switch (func & 0x7ff) { case 0x020: mnem = "fabs"; rbrc = 1; break; case 0x021: mnem = "fneg"; rbrc = 1; break; default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n", opcode, func); } if (mnem == NULL) break; if ((func & 0x7ff) == 0x020 && ra == 31 && rb == 31) debug("fclr\tf%i\n", rc); else if (rbrc) debug("%s\tf%i,f%i\n", mnem, rb, rc); else debug("%s\tf%i,f%i,f%i\n", mnem, ra, rb, rc); break; case 0x18: switch (iw & 0xffff) { case 0x0000: mnem = "trapb"; break; case 0x0400: mnem = "excb"; break; case 0x4000: mnem = "mb"; break; case 0x4400: mnem = "wmb"; break; case 0x8000: mnem = "fetch"; indir = 1; break; case 0xa000: mnem = "fetch_m"; indir = 1; break; case 0xc000: mnem = "rpcc"; break; case 0xe000: mnem = "rc"; break; case 0xe800: mnem = "ecb"; indir = 1; break; case 0xf000: mnem = "rs"; break; case 0xf800: mnem = "wh64"; indir = 1; break; default:debug("UNIMPLEMENTED opcode 0x%x func 0x%x\n", opcode, func); } if (mnem == NULL) break; debug("%s", mnem); if ((iw & 0xffff) >= 0x8000) { debug("\t"); if (indir) debug("(%s)", alpha_regname[rb]); else debug("%s", alpha_regname[ra]); } debug("\n"); break; case 0x1a: tmp = iw & 0x3fff; if (tmp & 0x2000) tmp |= 0xffffffffffffc000ULL; tmp <<= 2; tmp += dumpaddr + sizeof(uint32_t); switch ((iw >> 14) & 3) { case 0: case 1: if (((iw >> 14) & 3) == 0) debug("jmp"); else debug("jsr"); debug("\t%s,", alpha_regname[ra]); debug("(%s),", alpha_regname[rb]); debug("0x%" PRIx64, (uint64_t) tmp); symbol = get_symbol_name(&cpu->machine->symbol_context, tmp, &offset); if (symbol != NULL) debug("\t<%s>", symbol); break; case 2: debug("ret"); break; default:fatal("unimpl JSR!"); } debug("\n"); break; case 0x30: case 0x34: tmp = iw & 0x1fffff; if (tmp & 0x100000) tmp |= 0xffffffffffe00000ULL; tmp <<= 2; tmp += dumpaddr + sizeof(uint32_t); debug("%s\t", opcode==0x30? "br" : "bsr"); if (ra != ALPHA_ZERO) debug("%s,", alpha_regname[ra]); debug("0x%" PRIx64, (uint64_t) tmp); symbol = get_symbol_name(&cpu->machine->symbol_context, tmp, &offset); if (symbol != NULL) debug("\t<%s>", symbol); debug("\n"); break; case 0x31: case 0x35: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: floating = 0; switch (opcode) { case 0x31: mnem = "fbeq"; floating = 1; break; case 0x35: mnem = "fbne"; floating = 1; break; case 0x38: mnem = "blbc"; break; case 0x39: mnem = "beq"; break; case 0x3a: mnem = "blt"; break; case 0x3b: mnem = "ble"; break; case 0x3c: mnem = "blbs"; break; case 0x3d: mnem = "bne"; break; case 0x3e: mnem = "bge"; break; case 0x3f: mnem = "bgt"; break; } tmp = iw & 0x1fffff; if (tmp & 0x100000) tmp |= 0xffffffffffe00000ULL; tmp <<= 2; tmp += dumpaddr + sizeof(uint32_t); debug("%s\t", mnem); if (floating) debug("f%i,", ra); else debug("%s,", alpha_regname[ra]); debug("0x%" PRIx64, (uint64_t) tmp); symbol = get_symbol_name(&cpu->machine->symbol_context, tmp, &offset); if (symbol != NULL) debug("\t<%s>", symbol); debug("\n"); break; default:debug("UNIMPLEMENTED opcode 0x%x\n", opcode); } return sizeof(uint32_t); } #define MEMORY_RW alpha_userland_memory_rw #define MEM_ALPHA #define MEM_USERLAND #include "memory_rw.cc" #undef MEM_USERLAND #undef MEM_ALPHA #undef MEMORY_RW #include "tmp_alpha_tail.cc" gxemul-0.6.1/src/cpus/Makefile.skel000644 001750 001750 00000014143 13402411502 017366 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/cpus # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(DINCLUDE) OBJS=cpu.o $(CPU_ARCHS) $(CPU_BACKENDS) TOOLS=generate_head generate_tail $(CPU_TOOLS) all: $(TOOLS) $(MAKE) buildobjs buildobjs: $(OBJS) $(OBJS): Makefile ############################################################################### cpu_alpha.o: cpu_alpha.cc cpu_alpha_instr.cc cpu_dyntrans.cc memory_rw.cc \ tmp_alpha_head.cc tmp_alpha_tail.cc cpu_alpha_instr.cc: cpu_alpha_instr_alu.cc tmp_alpha_misc.cc tmp_alpha_misc.cc: cpu_alpha_instr_loadstore.cc generate_alpha_misc ./generate_alpha_misc > tmp_alpha_misc.cc tmp_alpha_head.cc: generate_head ./generate_head alpha Alpha > tmp_alpha_head.cc tmp_alpha_tail.cc: generate_tail ./generate_tail alpha Alpha > tmp_alpha_tail.cc ############################################################################### cpu_arm.o: cpu_arm.cc cpu_arm_instr.cc cpu_dyntrans.cc memory_rw.cc \ tmp_arm_head.cc tmp_arm_tail.cc cpu_arm_instr.cc: cpu_arm_instr_misc.cc tmp_arm_loadstore.cc: cpu_arm_instr_loadstore.cc generate_arm_loadstore ./generate_arm_loadstore > tmp_arm_loadstore.cc tmp_arm_loadstore_p0_u0_w0.cc: cpu_arm_instr_loadstore.cc generate_arm_loadstore ./generate_arm_loadstore 0 0 0 > tmp_arm_loadstore_p0_u0_w0.cc tmp_arm_loadstore_p0_u0_w1.cc: cpu_arm_instr_loadstore.cc generate_arm_loadstore ./generate_arm_loadstore 0 0 1 > tmp_arm_loadstore_p0_u0_w1.cc tmp_arm_loadstore_p0_u1_w0.cc: cpu_arm_instr_loadstore.cc generate_arm_loadstore ./generate_arm_loadstore 0 1 0 > tmp_arm_loadstore_p0_u1_w0.cc tmp_arm_loadstore_p0_u1_w1.cc: cpu_arm_instr_loadstore.cc generate_arm_loadstore ./generate_arm_loadstore 0 1 1 > tmp_arm_loadstore_p0_u1_w1.cc tmp_arm_loadstore_p1_u0_w0.cc: cpu_arm_instr_loadstore.cc generate_arm_loadstore ./generate_arm_loadstore 1 0 0 > tmp_arm_loadstore_p1_u0_w0.cc tmp_arm_loadstore_p1_u0_w1.cc: cpu_arm_instr_loadstore.cc generate_arm_loadstore ./generate_arm_loadstore 1 0 1 > tmp_arm_loadstore_p1_u0_w1.cc tmp_arm_loadstore_p1_u1_w0.cc: cpu_arm_instr_loadstore.cc generate_arm_loadstore ./generate_arm_loadstore 1 1 0 > tmp_arm_loadstore_p1_u1_w0.cc tmp_arm_loadstore_p1_u1_w1.cc: cpu_arm_instr_loadstore.cc generate_arm_loadstore ./generate_arm_loadstore 1 1 1 > tmp_arm_loadstore_p1_u1_w1.cc tmp_arm_multi.cc: generate_arm_multi cpu_arm_multi.txt ./generate_arm_multi `cat cpu_arm_multi.txt` > tmp_arm_multi.cc tmp_arm_dpi.cc: cpu_arm_instr_dpi.cc generate_arm_dpi ./generate_arm_dpi > tmp_arm_dpi.cc tmp_arm_r0.cc: generate_arm_r ./generate_arm_r 0x000 0x0ff > tmp_arm_r0.cc tmp_arm_r1.cc: generate_arm_r ./generate_arm_r 0x100 0x1ff > tmp_arm_r1.cc tmp_arm_r2.cc: generate_arm_r ./generate_arm_r 0x200 0x2ff > tmp_arm_r2.cc tmp_arm_r3.cc: generate_arm_r ./generate_arm_r 0x300 0x3ff > tmp_arm_r3.cc tmp_arm_r4.cc: generate_arm_r ./generate_arm_r 0x400 0x4ff > tmp_arm_r4.cc tmp_arm_r5.cc: generate_arm_r ./generate_arm_r 0x500 0x5ff > tmp_arm_r5.cc tmp_arm_r6.cc: generate_arm_r ./generate_arm_r 0x600 0x6ff > tmp_arm_r6.cc tmp_arm_r7.cc: generate_arm_r ./generate_arm_r 0x700 0x7ff > tmp_arm_r7.cc tmp_arm_r8.cc: generate_arm_r ./generate_arm_r 0x800 0x8ff > tmp_arm_r8.cc tmp_arm_r9.cc: generate_arm_r ./generate_arm_r 0x900 0x9ff > tmp_arm_r9.cc tmp_arm_ra.cc: generate_arm_r ./generate_arm_r 0xa00 0xaff > tmp_arm_ra.cc tmp_arm_rb.cc: generate_arm_r ./generate_arm_r 0xb00 0xbff > tmp_arm_rb.cc tmp_arm_rc.cc: generate_arm_r ./generate_arm_r 0xc00 0xcff > tmp_arm_rc.cc tmp_arm_rd.cc: generate_arm_r ./generate_arm_r 0xd00 0xdff > tmp_arm_rd.cc tmp_arm_re.cc: generate_arm_r ./generate_arm_r 0xe00 0xeff > tmp_arm_re.cc tmp_arm_rf.cc: generate_arm_r ./generate_arm_r 0xf00 0xfff > tmp_arm_rf.cc tmp_arm_r.cc: generate_arm_r ./generate_arm_r 0 0 > tmp_arm_r.cc tmp_arm_head.cc: generate_head ./generate_head arm ARM > tmp_arm_head.cc tmp_arm_tail.cc: generate_tail ./generate_tail arm ARM > tmp_arm_tail.cc ############################################################################### cpu_m88k.o: cpu_m88k.cc cpu_m88k_instr.cc cpu_dyntrans.cc memory_rw.cc \ tmp_m88k_loadstore.cc tmp_m88k_head.cc tmp_m88k_tail.cc tmp_m88k_bcnd.cc tmp_m88k_bcnd.cc: generate_m88k_bcnd ./generate_m88k_bcnd > tmp_m88k_bcnd.cc tmp_m88k_loadstore.cc: cpu_m88k_instr_loadstore.cc generate_m88k_loadstore ./generate_m88k_loadstore > tmp_m88k_loadstore.cc tmp_m88k_head.cc: generate_head ./generate_head m88k M88K > tmp_m88k_head.cc tmp_m88k_tail.cc: generate_tail ./generate_tail m88k M88K > tmp_m88k_tail.cc ############################################################################### cpu_mips.o: cpu_mips.cc cpu_dyntrans.cc memory_mips.cc \ cpu_mips_instr.cc tmp_mips_loadstore.cc tmp_mips_loadstore_multi.cc \ tmp_mips_head.cc tmp_mips_tail.cc memory_mips.cc: memory_rw.cc memory_mips_v2p.cc tmp_mips_loadstore.cc: cpu_mips_instr_loadstore.cc generate_mips_loadstore ./generate_mips_loadstore > tmp_mips_loadstore.cc tmp_mips_loadstore_multi.cc: generate_mips_loadstore_multi ./generate_mips_loadstore_multi > tmp_mips_loadstore_multi.cc tmp_mips_head.cc: generate_head ./generate_head mips MIPS > tmp_mips_head.cc tmp_mips_tail.cc: generate_tail ./generate_tail mips MIPS > tmp_mips_tail.cc ############################################################################### cpu_ppc.o: cpu_ppc.cc cpu_ppc_instr.cc cpu_dyntrans.cc memory_ppc.cc \ memory_rw.cc tmp_ppc_head.cc tmp_ppc_tail.cc tmp_ppc_loadstore.cc tmp_ppc_loadstore.cc: cpu_ppc_instr_loadstore.cc generate_ppc_loadstore ./generate_ppc_loadstore > tmp_ppc_loadstore.cc tmp_ppc_head.cc: generate_head ./generate_head ppc PPC > tmp_ppc_head.cc tmp_ppc_tail.cc: generate_tail ./generate_tail ppc PPC > tmp_ppc_tail.cc ############################################################################### cpu_sh.o: cpu_sh.cc cpu_sh_instr.cc cpu_dyntrans.cc memory_rw.cc \ tmp_sh_head.cc tmp_sh_tail.cc tmp_sh_head.cc: generate_head ./generate_head sh SH > tmp_sh_head.cc tmp_sh_tail.cc: generate_tail ./generate_tail sh SH > tmp_sh_tail.cc ############################################################################### clean: rm -f $(OBJS) $(TOOLS) *core tmp_*.c* *.gmon experiment_arm_multi clean_all: clean rm -f Makefile gxemul-0.6.1/src/cpus/memory_sh.cc000644 001750 001750 00000020770 13402411502 017305 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "cpu.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/sh4_exception.h" #include "thirdparty/sh4_mmu.h" /* * translate_via_mmu(): * * Scan the UTLB for a matching virtual address. If a match was found, then * check permission bits etc. If everything was ok, then return the physical * page address, otherwise cause an exception. * * The implementation should (hopefully) be quite complete, except for lack * of "Multiple matching entries" detection. (On a real CPU, these would * cause exceptions.) * * Same return values as sh_translate_v2p(). */ static int translate_via_mmu(struct cpu *cpu, uint32_t vaddr, uint64_t *return_paddr, int flags) { int wf = flags & FLAG_WRITEFLAG; int i, urb, urc, require_asid_match, cur_asid, expevt = 0; uint32_t hi, lo = 0, mask = 0; int sh; /* Shared */ int d; /* Dirty bit */ int v; /* Valid bit */ int pr; /* Protection */ int i_start; cur_asid = cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK; require_asid_match = !(cpu->cd.sh.mmucr & SH4_MMUCR_SV) || !(cpu->cd.sh.sr & SH_SR_MD); if (!(flags & FLAG_NOEXCEPTIONS)) { /* * Increase URC every time the UTLB is accessed. (Note: * According to the SH4 manual, the URC should not be * increased when running the ldtlb instruction. Perhaps this * is a good place? Perhaps it is better to just set it to a * random value? TODO: Find out. */ urb = (cpu->cd.sh.mmucr & SH4_MMUCR_URB_MASK) >> SH4_MMUCR_URB_SHIFT; urc = (cpu->cd.sh.mmucr & SH4_MMUCR_URC_MASK) >> SH4_MMUCR_URC_SHIFT; /* fatal("urc = %i ==> ", urc); */ urc ++; if (urc >= SH_N_UTLB_ENTRIES || (urb > 0 && urc == urb)) urc = 0; /* fatal("%i\n", urc); */ cpu->cd.sh.mmucr &= ~SH4_MMUCR_URC_MASK; cpu->cd.sh.mmucr |= (urc << SH4_MMUCR_URC_SHIFT); } /* * When doing Instruction lookups, the ITLB should be scanned first. * This is done by using negative i. (Ugly hack, but works.) */ if (flags & FLAG_INSTR) i_start = -SH_N_ITLB_ENTRIES; else i_start = 0; for (i=i_start; icd.sh.itlb_hi[i + SH_N_ITLB_ENTRIES]; lo = cpu->cd.sh.itlb_lo[i + SH_N_ITLB_ENTRIES]; } else { hi = cpu->cd.sh.utlb_hi[i]; lo = cpu->cd.sh.utlb_lo[i]; } mask = 0xfff00000; v = lo & SH4_PTEL_V; if (!v) continue; switch (lo & SH4_PTEL_SZ_MASK) { case SH4_PTEL_SZ_1K: mask = 0xfffffc00; break; case SH4_PTEL_SZ_4K: mask = 0xfffff000; break; case SH4_PTEL_SZ_64K: mask = 0xffff0000; break; /* case SH4_PTEL_SZ_1M: mask = 0xfff00000; break; */ } if ((hi & mask) != (vaddr & mask)) continue; sh = lo & SH4_PTEL_SH; if (!sh && require_asid_match) { int asid = hi & SH4_PTEH_ASID_MASK; if (asid != cur_asid) continue; } /* Note/TODO: Check for multiple matches is not implemented. */ break; } /* Virtual address not found? Then it's a TLB miss. */ if (i == SH_N_UTLB_ENTRIES) goto tlb_miss; /* Matching address found! Let's see whether it is readable/writable, etc.: */ d = lo & SH4_PTEL_D? 1 : 0; pr = (lo & SH4_PTEL_PR_MASK) >> SH4_PTEL_PR_SHIFT; *return_paddr = (vaddr & ~mask) | (lo & mask & 0x1fffffff); if (flags & FLAG_INSTR) { /* * Instruction access: */ #if 0 /* NOTE: Emulating the ITLB as exact as this is not necessary... so I'm disabling it for now. */ /* * If a matching entry wasn't found in the ITLB, but in the * UTLB, then copy it to a random place in the ITLB. */ if (i >= 0 && !(flags & FLAG_NOEXCEPTIONS)) { int r = random() % SH_N_ITLB_ENTRIES; /* NOTE: Make sure that the old mapping for that itlb entry is invalidated: */ cpu->invalidate_translation_caches(cpu, cpu->cd.sh.itlb_hi[r] & ~0xfff, INVALIDATE_VADDR); cpu->invalidate_code_translation(cpu, cpu->cd.sh.utlb_lo[i] & ~0xfff, INVALIDATE_PADDR); cpu->cd.sh.itlb_hi[r] = cpu->cd.sh.utlb_hi[i]; cpu->cd.sh.itlb_lo[r] = cpu->cd.sh.utlb_lo[i]; } #endif /* Permission checks: */ if (cpu->cd.sh.sr & SH_SR_MD) return 1; if (!(pr & 2)) goto protection_violation; return 1; } /* Data access: */ if (cpu->cd.sh.sr & SH_SR_MD) { /* Kernel access: */ switch (pr) { case 0: case 2: if (wf) goto protection_violation; return 1; case 1: case 3: if (wf && !d) goto initial_write_exception; return 1 + d; } } /* User access */ switch (pr) { case 0: case 1: goto protection_violation; case 2: if (wf) goto protection_violation; return 1; case 3: if (wf && !d) goto initial_write_exception; return 1 + d; } tlb_miss: expevt = wf? EXPEVT_TLB_MISS_ST : EXPEVT_TLB_MISS_LD; goto exception; protection_violation: expevt = wf? EXPEVT_TLB_PROT_ST : EXPEVT_TLB_PROT_LD; goto exception; initial_write_exception: expevt = EXPEVT_TLB_MOD; exception: if (flags & FLAG_NOEXCEPTIONS) { *return_paddr = 0; return 2; } sh_exception(cpu, expevt, 0, vaddr); return 0; } /* * sh_translate_v2p(): * * Return values: * * 0 No access to the virtual address. * 1 return_paddr contains the physical address, the page is * available as read-only. * 2 Same as 1, but the page is available as read/write. */ int sh_translate_v2p(struct cpu *cpu, uint64_t vaddr64, uint64_t *return_paddr, int flags) { int user = cpu->cd.sh.sr & SH_SR_MD? 0 : 1; uint32_t vaddr = vaddr64; /* U0/P0: Userspace addresses, or P3: Kernel virtual memory. */ if (!(vaddr & 0x80000000) || (vaddr >= 0xc0000000 && vaddr < 0xe0000000)) { /* Address translation turned off? */ if (!(cpu->cd.sh.mmucr & SH4_MMUCR_AT)) { /* Then return raw physical address: */ *return_paddr = vaddr & 0x1fffffff; return 2; } /* Perform translation via the MMU: */ return translate_via_mmu(cpu, vaddr, return_paddr, flags); } /* Store queue region: */ if (vaddr >= 0xe0000000 && vaddr < 0xe4000000) { /* Note/TODO: Take SH4_MMUCR_SQMD into account. */ *return_paddr = vaddr; return 2; } if (user) { if (flags & FLAG_NOEXCEPTIONS) { *return_paddr = 0; return 2; } // Hopefully correct behavior; nbjoerg on #GXemul (FreeNode) // noticed that this case was easily triggered inside a // guest OS, by: int main(void){ *(int *)-4 = 0; } sh_exception(cpu, (flags & FLAG_WRITEFLAG)? EXPEVT_TLB_MISS_ST : EXPEVT_TLB_MISS_LD, 0, vaddr); return 0; } /* P1,P2: Direct-mapped physical memory. */ if (vaddr >= 0x80000000 && vaddr < 0xc0000000) { *return_paddr = vaddr & 0x1fffffff; return 2; } if (flags & FLAG_INSTR) { fatal("TODO: instr at 0x%08" PRIx32"\n", (uint32_t)vaddr); exit(1); } /* P4: Special registers mapped at 0xf0000000 .. 0xffffffff: */ if ((vaddr & 0xf0000000) == 0xf0000000) { *return_paddr = vaddr; return 2; } if (flags & FLAG_NOEXCEPTIONS) { *return_paddr = 0; return 2; } /* TODO */ /* The ugly 'if' is just here to fool Compaq CC. */ if (!(flags & FLAG_NOEXCEPTIONS)) { fatal("Unimplemented SH vaddr 0x%08" PRIx32"\n", vaddr); exit(1); } return 0; } gxemul-0.6.1/src/cpus/memory_arm.cc000644 001750 001750 00000017053 13402411502 017452 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * TODO/NOTE: The B and/or C bits could also cause the return value to * be MEMORY_NOT_FULL_PAGE, to make sure it doesn't get entered into the * translation arrays. TODO: Find out if this is a good thing to do. */ #include #include #include #include "arm_cpu_types.h" #include "cpu.h" #include "memory.h" #include "misc.h" #include "thirdparty/armreg.h" extern int quiet_mode; /* * arm_translate_v2p(): * * Address translation with the MMU disabled. (Just treat the virtual address * as a physical address.) */ int arm_translate_v2p(struct cpu *cpu, uint64_t vaddr64, uint64_t *return_paddr, int flags) { *return_paddr = vaddr64 & 0xffffffff; return 2; } /* * arm_check_access(): * * Helper function. Returns 0 for no access, 1 for read-only, and 2 for * read/write. */ static int arm_check_access(struct cpu *cpu, int ap, int dav, int user) { int s, r; switch (dav) { case 0: /* No access at all. */ return 0; case 1: /* Normal access check. */ break; case 2: fatal("arm_check_access(): 1 shouldn't be used\n"); exit(1); case 3: /* Anything is allowed. */ return 2; } switch (ap) { case 0: s = (cpu->cd.arm.control & ARM_CONTROL_S)? 1 : 0; r = (cpu->cd.arm.control & ARM_CONTROL_R)? 2 : 0; switch (s + r) { case 0: return 0; case 1: return user? 0 : 1; case 2: return 1; } fatal("arm_check_access: UNPREDICTABLE s+r value!\n"); return 0; case 1: return user? 0 : 2; case 2: return user? 1 : 2; } /* "case 3": */ return 2; } /* * arm_translate_v2p_mmu(): * * Return values: * 0 Failure * 1 Success, the page is readable only * 2 Success, the page is read/write * * If this is a 1KB page access, then the return value is ORed with * MEMORY_NOT_FULL_PAGE. */ int arm_translate_v2p_mmu(struct cpu *cpu, uint64_t vaddr64, uint64_t *return_paddr, int flags) { unsigned char *q; uint32_t addr, d=0, d2 = (uint32_t)(int32_t)-1, ptba, vaddr = vaddr64; int instr = flags & FLAG_INSTR; int writeflag = (flags & FLAG_WRITEFLAG)? 1 : 0; int useraccess = flags & MEMORY_USER_ACCESS; int no_exceptions = flags & FLAG_NOEXCEPTIONS; int user = (cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32; int domain, dav, ap0,ap1,ap2,ap3, ap = 0, access = 0; int fs = 2; /* fault status (2 = terminal exception) */ int subpage = 0; if (useraccess) user = 1; addr = ((vaddr & 0xfff00000ULL) >> 18); if (cpu->cd.arm.translation_table == NULL || cpu->cd.arm.ttb != cpu->cd.arm.last_ttb) { cpu->cd.arm.translation_table = memory_paddr_to_hostaddr( cpu->mem, cpu->cd.arm.ttb & 0x0fffffff, 0); cpu->cd.arm.last_ttb = cpu->cd.arm.ttb; } if (cpu->cd.arm.translation_table != NULL) { d = *(uint32_t *)(cpu->cd.arm.translation_table + addr); #ifdef HOST_LITTLE_ENDIAN if (cpu->byte_order == EMUL_BIG_ENDIAN) #else if (cpu->byte_order == EMUL_LITTLE_ENDIAN) #endif d = ((d & 0xff) << 24) | ((d & 0xff00) << 8) | ((d & 0xff0000) >> 8) | ((d & 0xff000000) >> 24); } /* Get the domain from the descriptor, and the Domain Access Value: */ domain = (d >> 5) & 15; dav = (cpu->cd.arm.dacr >> (domain * 2)) & 3; switch (d & 3) { case 0: domain = 0; fs = FAULT_TRANS_S; goto exception_return; case 1: /* Course Pagetable: */ if (dav == 0) { fs = FAULT_DOMAIN_P; goto exception_return; } ptba = d & 0xfffffc00; addr = ptba + ((vaddr & 0x000ff000) >> 10); q = memory_paddr_to_hostaddr(cpu->mem, addr & 0x0fffffff, 0); if (q == NULL) { printf("arm memory blah blah adfh asfg asdgasdg\n"); exit(1); } d2 = *(uint32_t *)(q); #ifdef HOST_LITTLE_ENDIAN if (cpu->byte_order == EMUL_BIG_ENDIAN) #else if (cpu->byte_order == EMUL_LITTLE_ENDIAN) #endif d2 = ((d2 & 0xff) << 24) | ((d2 & 0xff00) << 8) | ((d2 & 0xff0000) >> 8) | ((d2 & 0xff000000) >> 24); switch (d2 & 3) { case 0: fs = FAULT_TRANS_P; goto exception_return; case 1: /* 16KB page: */ ap = (d2 >> 4) & 255; switch (vaddr & 0x0000c000) { case 0x4000: ap >>= 2; break; case 0x8000: ap >>= 4; break; case 0xc000: ap >>= 6; break; } ap &= 3; *return_paddr = (d2 & 0xffff0000)|(vaddr & 0x0000ffff); break; case 3: if (cpu->cd.arm.cpu_type.flags & ARM_XSCALE) { /* 4KB page (Xscale) */ subpage = 0; } else { /* 1KB page */ subpage = 1; ap = (d2 >> 4) & 3; *return_paddr = (d2 & 0xfffffc00) | (vaddr & 0x000003ff); break; } /* NOTE: Fall-through for XScale! */ case 2: /* 4KB page: */ ap3 = (d2 >> 10) & 3; ap2 = (d2 >> 8) & 3; ap1 = (d2 >> 6) & 3; ap0 = (d2 >> 4) & 3; switch (vaddr & 0x00000c00) { case 0x000: ap = ap0; break; case 0x400: ap = ap1; break; case 0x800: ap = ap2; break; default: ap = ap3; } /* NOTE: Ugly hack for XScale: */ if ((d2 & 3) == 3) { /* Treated as 4KB page: */ ap = ap0; } else { if (ap0 != ap1 || ap0 != ap2 || ap0 != ap3) subpage = 1; } *return_paddr = (d2 & 0xfffff000)|(vaddr & 0x00000fff); break; } access = arm_check_access(cpu, ap, dav, user); if (access > writeflag) return access | (subpage? MEMORY_NOT_FULL_PAGE : 0); fs = FAULT_PERM_P; goto exception_return; case 2: /* Section descriptor: */ if (dav == 0) { fs = FAULT_DOMAIN_S; goto exception_return; } *return_paddr = (d & 0xfff00000) | (vaddr & 0x000fffff); ap = (d >> 10) & 3; access = arm_check_access(cpu, ap, dav, user); if (access > writeflag) return access; fs = FAULT_PERM_S; goto exception_return; default:fatal("TODO: descriptor for vaddr 0x%08x: 0x%08x (" "unimplemented type %i)\n", vaddr, d, d&3); exit(1); } exception_return: if (no_exceptions) return 0; if (!quiet_mode) { fatal("{ arm memory fault: vaddr=0x%08x domain=%i dav=%i ap=%i " "access=%i user=%i", (int)vaddr, domain, dav, ap, access, user); fatal(" d=0x%08x d2=0x%08x pc=0x%08x }\n", d, d2, (int)cpu->pc); } if (instr) arm_exception(cpu, ARM_EXCEPTION_PREF_ABT); else { cpu->cd.arm.far = vaddr; cpu->cd.arm.fsr = (domain << 4) | fs; arm_exception(cpu, ARM_EXCEPTION_DATA_ABT); } return 0; } gxemul-0.6.1/src/cpus/cpu_mips_instr_unaligned.cc000644 001750 001750 00000011761 13402411502 022367 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * MIPS unaligned load/store instructions; the following args are used: * * arg[0] = pointer to the register to load to or store from * arg[1] = pointer to the base register * arg[2] = offset (as an int32_t) * * NOTE/TODO: This is a very slow generic implementation, from the * pre-Dyntrans emulation mode. It should be rewritten. */ #include "cop0.h" #include "cpu.h" #include "memory.h" #include "misc.h" void mips_unaligned_loadstore(struct cpu *cpu, struct mips_instr_call *ic, int is_left, int wlen, int store) { /* For L (Left): address is the most significant byte */ /* For R (Right): address is the least significant byte */ uint64_t addr = *((uint64_t *)ic->arg[1]) + (int32_t)ic->arg[2]; int i, dir, reg_dir, reg_ofs, ok; uint64_t result_value, tmpaddr; uint64_t aligned_addr = addr & ~(wlen-1); unsigned char aligned_word[8], databyte; int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); dir = 1; /* big endian, Left */ reg_dir = -1; reg_ofs = wlen - 1; /* byte offset in the register */ if (!is_left) { dir = -dir; reg_ofs = 0; reg_dir = 1; } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) dir = -dir; result_value = *((uint64_t *)ic->arg[0]); if (cpu->is_32bit) { result_value = (int32_t)result_value; aligned_addr = (int32_t)aligned_addr; addr = (int32_t)addr; } if (store) { /* Store: */ uint64_t oldpc = cpu->pc; /* * NOTE (this is ugly): The memory_rw() * call generates a TLBL exception, if there * is a tlb refill exception. However, since * this is a Store, the exception is converted * to a TLBS: */ ok = cpu->memory_rw(cpu, cpu->mem, aligned_addr, &aligned_word[0], wlen, MEM_READ, CACHE_DATA); if (!ok) { if (cpu->pc != oldpc) { cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] &= ~CAUSE_EXCCODE_MASK; cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] |= (EXCEPTION_TLBS << CAUSE_EXCCODE_SHIFT); } return; } for (i=0; i> (reg_ofs * 8)) & 255; reg_ofs += reg_dir; } ok = cpu->memory_rw(cpu, cpu->mem, aligned_addr, &aligned_word[0], wlen, MEM_WRITE, CACHE_DATA); return; } /* Load: */ ok = cpu->memory_rw(cpu, cpu->mem, aligned_addr, &aligned_word[0], wlen, MEM_READ, CACHE_DATA); if (!ok) return; for (i=0; iarg[0]) = result_value; } gxemul-0.6.1/src/cpus/README_DYNTRANS000644 001750 001750 00000004732 13402411502 017176 0ustar00debugdebug000000 000000 Dyntrans TODO ------------- Current state of dyntrans 2008-12-16 is: x) No native code generation, i.e. code is translated into function pointers (pointing to C code). An array contains one entry for each possible value of the program counter within a page (i.e. for 4 KB pages with 32-bit instruction words, that means 1024 entries), plus one or two entries signifying the "end of page". (Two are only necessary for architectures that have delay slots.) One way to support native code generation could be to _optionally_ generate new code in memory which is called using the already existing function pointers. However, this would not allow much optimization to take place. The big thing speaking _against_ native code generation is time! While native code generation may be fun and interesting, and produce very fast code in some cases, there are probably other things in the emulator that are bottlenecks as well, and the concept of instruction combinations (using host optimized C code for common code sequences) still has not been used to its limit. x) Variable-length ISAs are not yet emulated. There was some code for this before, but I removed it. The biggest problem is that of an instruction reaching past a page boundary. With virtual memory, the second page does not even have to exist! This needs to be solved some nice way. Long-term goal: Make sure that all of these could work, at least in theory: Instruction Word Delay Arch.: length: size: slot: ------ ------- ----- ----- Alpha 32-bit 64 no ARM 32-bit, 16-bit (Thumb) 32 no AVR 16-bit + variable 8 no AVR32 16-bit + variable 32 ? F-CPU ? ? ? H8 16-bit 8/16 no HPPA 32-bit 64/32 yes i860 ? ? yes (?) i960 32-bit + variable 32 ? IA64 128-bit 64 no M32R 32-bit (*2) 32 ? M68K 16-bit + variable 32 no M88K 32-bit 32 yes MIPS 32-bit, 16-bit (MIPS16) 64/32 yes OpenRISC ? ? ? PC532 ? 32 (?) ? POWER/PPC 32-bit 64/32 no RCA180x 8-bit (+ variable on 1805) 8-16 (?) no SH1..4 16-bit 32 yes SH5 32-bit, 16-bit (SHcompact) 64 yes (*1) SPARC 32-bit 64/32 yes Transputer 8-bit 32/16 no x86/AMD64 8-bit + variable 64/32/16 no Z80000 16-bit + variable 32 no (?) VAX 8-bit + variable 32 no (*1) Delay slot in SHcompact/32-bit-mode (*2) Sometmes multiple instructions are issued in the same instruction word. gxemul-0.6.1/src/cpus/generate_alpha_misc.c000644 001750 001750 00000026163 13402411502 021114 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include char *sizechar[4] = { "b", "w", "l", "q" }; #define N_CMPS 5 char *cmps[N_CMPS] = { "ult", "eq", "ule", "lt", "le" /*bge*/ }; #define N_CMOV 8 char *cmov[N_CMOV] = { "lbs", "lbc", "eq", "ne", "lt", "ge", "le", "gt" }; int main(int argc, char *argv[]) { int load, size, zero, n, msk, llsc; int ra, rc, lo, scale, imm, not, op, quad; printf("\n/* AUTOMATICALLY GENERATED! Do not edit. */\n\n"); n = 0; /* add and sub: */ for (imm = 0; imm <= 1; imm ++) for (quad = 0; quad <= 1; quad ++) for (scale = 0; scale <= 8; scale += 4) for (op = 0; op <= 1; op ++) { printf("#define ALU_N alpha_instr_"); if (scale) printf("s%i", scale); printf("%s%s", op? "sub" : "add", quad? "q" : "l"); if (imm) printf("_imm"); printf("\n"); if (imm) printf("#define ALU_IMM\n"); if (!quad) printf("#define ALU_LONG\n"); if (op) printf("#define ALU_SUB\n"); else printf("#define ALU_ADD\n"); if (scale) printf("#define ALU_S%i\n", scale); printf("#include \"cpu_alpha_instr_alu.cc\"\n"); if (imm) printf("#undef ALU_IMM\n"); if (!quad) printf("#undef ALU_LONG\n"); if (op) printf("#undef ALU_SUB\n"); else printf("#undef ALU_ADD\n"); if (scale) printf("#undef ALU_S%i\n", scale); printf("#undef ALU_N\n"); } /* and, or, xor, zap, sll, srl, sra: */ for (imm = 0; imm <= 1; imm ++) for (not = 0; not <= 1; not ++) for (op = 0; op < 7; op ++) { if (op >= 4 && not) continue; printf("#define ALU_N alpha_instr_"); switch (op) { case 0: printf("and"); break; case 1: printf("or"); break; case 2: printf("xor"); break; case 3: printf("zap"); break; case 4: printf("sll"); break; case 5: printf("srl"); break; case 6: printf("sra"); break; } if (not) printf("not"); if (imm) printf("_imm"); printf("\n"); if (imm) printf("#define ALU_IMM\n"); switch (op) { case 0: printf("#define ALU_AND\n"); break; case 1: printf("#define ALU_OR\n"); break; case 2: printf("#define ALU_XOR\n"); break; case 3: printf("#define ALU_ZAP\n"); break; case 4: printf("#define ALU_SLL\n"); break; case 5: printf("#define ALU_SRL\n"); break; case 6: printf("#define ALU_SRA\n"); break; } if (not) printf("#define ALU_NOT\n"); printf("#include \"cpu_alpha_instr_alu.cc\"\n"); if (imm) printf("#undef ALU_IMM\n"); if (not) printf("#undef ALU_NOT\n"); switch (op) { case 0: printf("#undef ALU_AND\n"); break; case 1: printf("#undef ALU_OR\n"); break; case 2: printf("#undef ALU_XOR\n"); break; case 3: printf("#undef ALU_ZAP\n"); break; case 4: printf("#undef ALU_SLL\n"); break; case 5: printf("#undef ALU_SRL\n"); break; case 6: printf("#undef ALU_SRA\n"); break; } printf("#undef ALU_N\n"); } printf("#define ALU_CMP\n"); for (imm = 0; imm <= 1; imm ++) for (op = 0; op < N_CMPS; op ++) { printf("#define ALU_N alpha_instr_cmp%s", cmps[op]); if (imm) printf("_imm"); printf("\n"); if (imm) printf("#define ALU_IMM\n"); if (cmps[op][0] == 'u') printf("#define ALU_UNSIGNED\n"); if (strcmp(cmps[op]+strlen(cmps[op])-2,"lt") == 0) printf("#define ALU_CMP_LT\n"); if (strcmp(cmps[op]+strlen(cmps[op])-2,"le") == 0) printf("#define ALU_CMP_LE\n"); if (strcmp(cmps[op]+strlen(cmps[op])-2,"eq") == 0) printf("#define ALU_CMP_EQ\n"); printf("#include \"cpu_alpha_instr_alu.cc\"\n"); if (cmps[op][0] == 'u') printf("#undef ALU_UNSIGNED\n"); if (strcmp(cmps[op]+strlen(cmps[op])-2,"lt") == 0) printf("#undef ALU_CMP_LT\n"); if (strcmp(cmps[op]+strlen(cmps[op])-2,"le") == 0) printf("#undef ALU_CMP_LE\n"); if (strcmp(cmps[op]+strlen(cmps[op])-2,"eq") == 0) printf("#undef ALU_CMP_EQ\n"); if (imm) printf("#undef ALU_IMM\n"); printf("#undef ALU_N\n"); } printf("#undef ALU_CMP\n"); printf("#define ALU_CMOV\n"); for (imm = 0; imm <= 1; imm ++) for (op = 0; op < N_CMOV; op ++) { printf("#define ALU_N alpha_instr_cmov%s", cmov[op]); if (imm) printf("_imm"); printf("\n"); if (imm) printf("#define ALU_IMM\n"); printf("#define ALU_CMOV_%s\n", cmov[op]); printf("#include \"cpu_alpha_instr_alu.cc\"\n"); printf("#undef ALU_CMOV_%s\n", cmov[op]); if (imm) printf("#undef ALU_IMM\n"); printf("#undef ALU_N\n"); } printf("#undef ALU_CMOV\n"); printf("#define ALU_CMPBGE\n"); for (imm = 0; imm <= 1; imm ++) { printf("#define ALU_N alpha_instr_cmpbge"); if (imm) printf("_imm"); printf("\n"); if (imm) printf("#define ALU_IMM\n"); printf("#include \"cpu_alpha_instr_alu.cc\"\n"); if (imm) printf("#undef ALU_IMM\n"); printf("#undef ALU_N\n"); } printf("#undef ALU_CMPBGE\n"); for (imm = 0; imm <= 1; imm ++) for (lo = 0; lo <= 1; lo ++) for (msk = 0; msk <= 2; msk ++) for (size=0; size<4; size++) { if (size==0 && lo==0) continue; switch (msk) { case 0: printf("#define ALU_MSK\n"); break; case 1: printf("#define ALU_EXT\n"); break; case 2: printf("#define ALU_INS\n"); break; } switch (msk) { case 0: printf("#define ALU_N alpha_instr_msk"); break; case 1: printf("#define ALU_N alpha_instr_ext"); break; case 2: printf("#define ALU_N alpha_instr_ins"); break; } printf("%s", sizechar[size]); if (lo) printf("l"); else printf("h"); if (imm) printf("_imm"); printf("\n"); if (imm) printf("#define ALU_IMM\n"); switch (size) { case 0: printf("#define ALU_B\n"); break; case 1: printf("#define ALU_W\n"); break; case 2: printf("#define ALU_L\n"); break; case 3: printf("#define ALU_Q\n"); break; } if (lo) printf("#define ALU_LO\n"); printf("#include \"cpu_alpha_instr_alu.cc\"\n"); switch (size) { case 0: printf("#undef ALU_B\n"); break; case 1: printf("#undef ALU_W\n"); break; case 2: printf("#undef ALU_L\n"); break; case 3: printf("#undef ALU_Q\n"); break; } switch (msk) { case 0: printf("#undef ALU_MSK\n"); break; case 1: printf("#undef ALU_EXT\n"); break; case 2: printf("#undef ALU_INS\n"); break; } if (lo) printf("#undef ALU_LO\n"); if (imm) printf("#undef ALU_IMM\n"); printf("#undef ALU_N\n"); } /* * Normal load/store: */ for (llsc=0; llsc<=1; llsc++) for (load=0; load<=1; load++) for (zero=0; zero<=1; zero++) for (size=0; size<4; size++) { if (llsc && size < 2) continue; if (zero) printf("#define LS_IGNORE_OFFSET\n"); if (load) printf("#define LS_LOAD\n"); if (llsc) printf("#define LS_LLSC\n"); switch (size) { case 0: printf("#define LS_B\n"); break; case 1: printf("#define LS_W\n"); break; case 2: printf("#define LS_L\n"); break; case 3: printf("#define LS_Q\n"); break; } printf("#define LS_GENERIC_N alpha_generic_"); if (load) printf("ld"); else printf("st"); printf("%s", sizechar[size]); if (llsc) printf("_llsc"); printf("\n"); printf("#define LS_N alpha_instr_"); if (load) printf("ld"); else printf("st"); printf("%s", sizechar[size]); if (zero) printf("_0"); if (llsc) printf("_llsc"); printf("\n"); printf("#include \"cpu_alpha_instr_loadstore.cc\"\n"); printf("#undef LS_N\n"); printf("#undef LS_GENERIC_N\n"); switch (size) { case 0: printf("#undef LS_B\n"); break; case 1: printf("#undef LS_W\n"); break; case 2: printf("#undef LS_L\n"); break; case 3: printf("#undef LS_Q\n"); break; } if (load) printf("#undef LS_LOAD\n"); if (llsc) printf("#undef LS_LLSC\n"); if (zero) printf("#undef LS_IGNORE_OFFSET\n"); } /* * Unaligned load/store: */ printf("#define LS_UNALIGNED\n"); for (load=0; load<=1; load++) { size = 3; if (load) printf("#define LS_LOAD\n"); printf("#define LS_Q\n"); printf("#define LS_GENERIC_N alpha_generic_"); if (load) printf("ld"); else printf("st"); printf("%s", sizechar[size]); printf("_u"); /* NOTE: unaligned */ printf("\n"); printf("#define LS_N alpha_instr_"); if (load) printf("ld"); else printf("st"); printf("%s", sizechar[size]); printf("_u"); /* NOTE: unaligned */ printf("\n"); printf("#include \"cpu_alpha_instr_loadstore.cc\"\n"); printf("#undef LS_N\n"); printf("#undef LS_GENERIC_N\n"); printf("#undef LS_Q\n"); if (load) printf("#undef LS_LOAD\n"); } printf("#undef LS_UNALIGNED\n"); /* Lookup table for most normal loads/stores: */ printf("\n\nvoid (*alpha_loadstore[32])(struct cpu *, struct " "alpha_instr_call *) = {\n"); for (llsc = 0; llsc <= 1; llsc ++) for (load=0; load<=1; load++) for (zero=0; zero<=1; zero++) for (size=0; size<4; size++) { printf("\talpha_instr_"); if (llsc && (size != 2 && size != 3)) { printf("nop"); } else { if (load) printf("ld"); else printf("st"); printf("%s", sizechar[size]); if (zero) printf("_0"); if (llsc) printf("_llsc"); } if (++n < 64) printf(","); printf("\n"); } printf("};\n\n"); for (ra = 0; ra < 32; ra ++) for (rc = 0; rc < 31; rc ++) if (ra != rc) { printf("static void alpha_instr_mov_%i_%i(struct cpu" " *cpu, struct alpha_instr_call *ic)\n", ra, rc); printf("{ cpu->cd.alpha.r[%i] = ", rc); if (ra == 31) printf("0"); else printf("cpu->cd.alpha.r[%i]", ra); printf("; }\n"); } printf("\n\nvoid (*alpha_mov_r_r[32*31])(struct cpu *, struct " "alpha_instr_call *) = {\n"); n = 0; for (rc = 0; rc < 31; rc ++) for (ra = 0; ra < 32; ra ++) { if (ra == rc) printf("\talpha_instr_nop"); else printf("\talpha_instr_mov_%i_%i", ra, rc); if (++n < 31*32) printf(","); printf("\n"); } printf("};\n\n"); return 0; } gxemul-0.6.1/src/cpus/cpu_mips_instr.cc000644 001750 001750 00000362463 13402411502 020351 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * MIPS instructions. * * Individual functions should keep track of cpu->n_translated_instrs. * (If no instruction was executed, then it should be decreased. If, say, 4 * instructions were combined into one function and executed, then it should * be increased by 3.) */ /* * COPROC_AVAILABILITY_CHECK(n) checks for the coprocessor available bit for * coprocessor number n, and causes a CoProcessor Unusable exception if it * is not set. (Note: For coprocessor 0 checks, use cop0_availability_check!) */ #ifndef COPROC_AVAILABILITY_CHECK #define COPROC_AVAILABILITY_CHECK(x) { \ const int cpnr = (x); \ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) \ / sizeof(struct mips_instr_call); \ cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) \ << MIPS_INSTR_ALIGNMENT_SHIFT); \ cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); \ if (!(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & \ ((1 << cpnr) << STATUS_CU_SHIFT)) ) { \ mips_cpu_exception(cpu, EXCEPTION_CPU, \ 0, 0, cpnr, 0, 0, 0); \ return; \ } \ } #endif #ifndef COP0_AVAILABILITY_CHECK_INCLUDED #define COP0_AVAILABILITY_CHECK_INCLUDED /* * cop0_availability_check() causes a CoProcessor Unusable exception if * we are currently running in usermode, and the coprocessor available bit * for coprocessor 0 is not set. * * Returns 1 if ok (i.e. if the coprocessor was usable), 0 on exceptions. */ int cop0_availability_check(struct cpu *cpu, struct mips_instr_call *ic) { int in_usermode = 0; struct mips_coproc *cp0 = cpu->cd.mips.coproc[0]; switch (cpu->cd.mips.cpu_type.exc_model) { case EXC3K: /* * NOTE: If the KU bit is checked, Linux crashes. * It is the PC that counts. * * TODO: Check whether this is true or not for R4000 as well. */ /* TODO: if (cp0->reg[COP0_STATUS] & MIPS1_SR_KU_CUR) */ if (cpu->pc <= 0x7fffffff) in_usermode = 1; break; default: /* R4000 etc: (TODO: How about supervisor mode?) */ if (((cp0->reg[COP0_STATUS] & STATUS_KSU_MASK) >> STATUS_KSU_SHIFT) != KSU_KERNEL) in_usermode = 1; if (cp0->reg[COP0_STATUS] & (STATUS_ERL | STATUS_EXL)) in_usermode = 0; break; } if (in_usermode) { int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); if (!(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & (1 << STATUS_CU_SHIFT)) ) { mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, /* cpnr */ 0, 0, 0, 0); return 0; } } return 1; } #endif /* * invalid: For catching bugs. */ X(invalid) { fatal("FATAL ERROR: An internal error occured in the MIPS" " dyntrans code. Please contact the author with detailed" " repro steps on how to trigger this bug.\n"); exit(1); } /* * reserved: Attempt to execute a reserved instruction (e.g. a 64-bit * instruction on an emulated 32-bit processor). */ X(reserved) { /* Synchronize the PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_RI, 0, 0, 0, 0, 0, 0); } /* * cpu: Cause a CoProcessor Unusable exception. * * arg[0] = the number of the coprocessor */ X(cpu) { /* Synchronize the PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, ic->arg[0], 0, 0, 0); } /* * nop: Do nothing. */ X(nop) { } /* * beq: Branch if equal * bne: Branch if not equal * b: Branch (comparing a register to itself, always true) * * arg[0] = pointer to rs * arg[1] = pointer to rt * arg[2] = (int32_t) relative offset from the next instruction */ X(beq) { MODE_int_t old_pc = cpu->pc; MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); int x = rs == rt; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(beq_samepage) { MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); int x = rs == rt; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } X(beq_samepage_addiu) { MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); cpu->n_translated_instrs ++; reg(ic[1].arg[1]) = (int32_t) ((int32_t)reg(ic[1].arg[0]) + (int32_t)ic[1].arg[2]); if (rs == rt) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } X(beq_samepage_nop) { MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); cpu->n_translated_instrs ++; if (rs == rt) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } X(bne) { MODE_int_t old_pc = cpu->pc; MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); int x = rs != rt; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bne_samepage) { MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); int x = rs != rt; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } X(bne_samepage_addiu) { MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); cpu->n_translated_instrs ++; reg(ic[1].arg[1]) = (int32_t) ((int32_t)reg(ic[1].arg[0]) + (int32_t)ic[1].arg[2]); if (rs != rt) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } X(bne_samepage_nop) { MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); cpu->n_translated_instrs ++; if (rs != rt) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } X(b) { MODE_int_t old_pc = cpu->pc; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(b_samepage) { cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; cpu->delay_slot = NOT_DELAYED; } /* * beql: Branch if equal likely * bnel: Branch if not equal likely * * arg[0] = pointer to rs * arg[1] = pointer to rt * arg[2] = (int32_t) relative offset from the next instruction */ X(beql) { MODE_int_t old_pc = cpu->pc; MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); int x = rs == rt; cpu->delay_slot = TO_BE_DELAYED; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(beql_samepage) { MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); int x = rs == rt; cpu->delay_slot = TO_BE_DELAYED; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } X(bnel) { MODE_int_t old_pc = cpu->pc; MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); int x = rs != rt; cpu->delay_slot = TO_BE_DELAYED; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bnel_samepage) { MODE_uint_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); int x = rs != rt; cpu->delay_slot = TO_BE_DELAYED; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } /* * blez: Branch if less than or equal * blezl: Branch if less than or equal likely * * arg[0] = pointer to rs * arg[2] = (int32_t) relative offset from the next instruction */ X(blez) { MODE_int_t old_pc = cpu->pc; MODE_int_t rs = reg(ic->arg[0]); int x = (rs <= 0); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(blez_samepage) { MODE_int_t rs = reg(ic->arg[0]); int x = (rs <= 0); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } X(blezl) { MODE_int_t old_pc = cpu->pc; MODE_int_t rs = reg(ic->arg[0]); int x = (rs <= 0); cpu->delay_slot = TO_BE_DELAYED; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(blezl_samepage) { MODE_int_t rs = reg(ic->arg[0]); int x = (rs <= 0); cpu->delay_slot = TO_BE_DELAYED; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } /* * bltz: Branch if less than * bltzl: Branch if less than likely * * arg[0] = pointer to rs * arg[2] = (int32_t) relative offset from the next instruction */ X(bltz) { MODE_int_t old_pc = cpu->pc; MODE_int_t rs = reg(ic->arg[0]); int x = (rs < 0); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bltz_samepage) { MODE_int_t rs = reg(ic->arg[0]); int x = (rs < 0); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } X(bltzl) { MODE_int_t old_pc = cpu->pc; MODE_int_t rs = reg(ic->arg[0]); int x = (rs < 0); cpu->delay_slot = TO_BE_DELAYED; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bltzl_samepage) { MODE_int_t rs = reg(ic->arg[0]); int x = (rs < 0); cpu->delay_slot = TO_BE_DELAYED; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } /* * bgez: Branch if greater than or equal * bgezl: Branch if greater than or equal likely * * arg[0] = pointer to rs * arg[2] = (int32_t) relative offset from the next instruction */ X(bgez) { MODE_int_t old_pc = cpu->pc; MODE_int_t rs = reg(ic->arg[0]); int x = (rs >= 0); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bgez_samepage) { MODE_int_t rs = reg(ic->arg[0]); int x = (rs >= 0); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } X(bgezl) { MODE_int_t old_pc = cpu->pc; MODE_int_t rs = reg(ic->arg[0]); int x = (rs >= 0); cpu->delay_slot = TO_BE_DELAYED; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bgezl_samepage) { MODE_int_t rs = reg(ic->arg[0]); int x = (rs >= 0); cpu->delay_slot = TO_BE_DELAYED; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } /* * bgezal: Branch if greater than or equal (and link) * bgezall: Branch if greater than or equal (and link) likely * * arg[0] = pointer to rs * arg[2] = (int32_t) relative offset from the next instruction */ X(bgezal) { MODE_int_t old_pc = cpu->pc; MODE_int_t rs = reg(ic->arg[0]); int x = (rs >= 0), low_pc; cpu->delay_slot = TO_BE_DELAYED; low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->cd.mips.gpr[MIPS_GPR_RA] = cpu->pc + 8; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bgezal_samepage) { MODE_int_t rs = reg(ic->arg[0]); int x = (rs >= 0), low_pc; cpu->delay_slot = TO_BE_DELAYED; low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->cd.mips.gpr[MIPS_GPR_RA] = cpu->pc + 8; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } X(bgezall) { MODE_int_t old_pc = cpu->pc; MODE_int_t rs = reg(ic->arg[0]); int x = (rs >= 0), low_pc; cpu->delay_slot = TO_BE_DELAYED; low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->cd.mips.gpr[MIPS_GPR_RA] = cpu->pc + 8; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bgezall_samepage) { MODE_int_t rs = reg(ic->arg[0]); int x = (rs >= 0), low_pc; cpu->delay_slot = TO_BE_DELAYED; low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->cd.mips.gpr[MIPS_GPR_RA] = cpu->pc + 8; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } /* * bltzal: Branch if less than zero (and link) * bltzall: Branch if less than zero (and link) likely * * arg[0] = pointer to rs * arg[2] = (int32_t) relative offset from the next instruction */ X(bltzal) { MODE_int_t old_pc = cpu->pc; MODE_int_t rs = reg(ic->arg[0]); int x = (rs < 0), low_pc; cpu->delay_slot = TO_BE_DELAYED; low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->cd.mips.gpr[MIPS_GPR_RA] = cpu->pc + 8; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bltzal_samepage) { MODE_int_t rs = reg(ic->arg[0]); int x = (rs < 0), low_pc; cpu->delay_slot = TO_BE_DELAYED; low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->cd.mips.gpr[MIPS_GPR_RA] = cpu->pc + 8; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } X(bltzall) { MODE_int_t old_pc = cpu->pc; MODE_int_t rs = reg(ic->arg[0]); int x = (rs < 0), low_pc; cpu->delay_slot = TO_BE_DELAYED; low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->cd.mips.gpr[MIPS_GPR_RA] = cpu->pc + 8; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bltzall_samepage) { MODE_int_t rs = reg(ic->arg[0]); int x = (rs < 0), low_pc; cpu->delay_slot = TO_BE_DELAYED; low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->cd.mips.gpr[MIPS_GPR_RA] = cpu->pc + 8; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } /* * bgtz: Branch if greater than zero * bgtzl: Branch if greater than zero likely * * arg[0] = pointer to rs * arg[2] = (int32_t) relative offset from the next instruction */ X(bgtz) { MODE_int_t old_pc = cpu->pc; MODE_int_t rs = reg(ic->arg[0]); int x = (rs > 0); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bgtz_samepage) { MODE_int_t rs = reg(ic->arg[0]); int x = (rs > 0); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } X(bgtzl) { MODE_int_t old_pc = cpu->pc; MODE_int_t rs = reg(ic->arg[0]); int x = (rs > 0); cpu->delay_slot = TO_BE_DELAYED; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bgtzl_samepage) { MODE_int_t rs = reg(ic->arg[0]); int x = (rs > 0); cpu->delay_slot = TO_BE_DELAYED; if (x) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { if (x) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; else cpu->cd.mips.next_ic ++; } cpu->delay_slot = NOT_DELAYED; } /* * jr, jalr: Jump to a register [and link]. * * arg[0] = ptr to rs * arg[1] = ptr to rd (for jalr) * arg[2] = (int32_t) relative offset of the next instruction */ X(jr) { MODE_int_t rs = reg(ic->arg[0]); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = rs; /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(jr_ra) { MODE_int_t rs = cpu->cd.mips.gpr[MIPS_GPR_RA]; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = rs; /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(jr_ra_addiu) { /* jr ra, followed by an addiu */ MODE_int_t rs = cpu->cd.mips.gpr[MIPS_GPR_RA]; reg(ic[1].arg[1]) = (int32_t) ((int32_t)reg(ic[1].arg[0]) + (int32_t)ic[1].arg[2]); cpu->pc = rs; quick_pc_to_pointers(cpu); cpu->n_translated_instrs ++; } X(jr_ra_trace) { MODE_int_t rs = cpu->cd.mips.gpr[MIPS_GPR_RA]; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = rs; cpu_functioncall_trace_return(cpu); /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(jalr) { MODE_int_t rs = reg(ic->arg[0]), rd; cpu->delay_slot = TO_BE_DELAYED; rd = cpu->pc & ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); rd += (int32_t)ic->arg[2]; reg(ic->arg[1]) = rd; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = rs; /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(jalr_trace) { MODE_int_t rs = reg(ic->arg[0]), rd; cpu->delay_slot = TO_BE_DELAYED; rd = cpu->pc & ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); rd += (int32_t)ic->arg[2]; reg(ic->arg[1]) = rd; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = rs; cpu_functioncall_trace(cpu, cpu->pc); /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } /* * j, jal: Jump [and link]. * * arg[0] = lowest 28 bits of new pc. * arg[1] = offset from start of page to the jal instruction + 8 */ X(j) { MODE_int_t old_pc = cpu->pc; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; old_pc &= ~0x03ffffff; cpu->pc = old_pc | (uint32_t)ic->arg[0]; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(jal) { MODE_int_t old_pc = cpu->pc; cpu->delay_slot = TO_BE_DELAYED; cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<cd.mips.gpr[31] = (MODE_int_t)cpu->pc + (int32_t)ic->arg[1]; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; old_pc &= ~0x03ffffff; cpu->pc = old_pc | (int32_t)ic->arg[0]; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(jal_trace) { MODE_int_t old_pc = cpu->pc; cpu->delay_slot = TO_BE_DELAYED; cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<cd.mips.gpr[31] = (MODE_int_t)cpu->pc + (int32_t)ic->arg[1]; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; old_pc &= ~0x03ffffff; cpu->pc = old_pc | (int32_t)ic->arg[0]; cpu_functioncall_trace(cpu, cpu->pc); quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } /* * cache: Cache operation. */ X(cache) { /* TODO: Implement cache operations. */ /* Make sure the rmw bit is cleared: */ cpu->cd.mips.rmw = 0; } /* * ins: Insert bitfield. * * arg[0] = pointer to rt * arg[1] = pointer to rs * arg[2] = (msb << 5) + lsb */ X(ins) { int msb = ic->arg[2] >> 5, pos = ic->arg[2] & 0x1f; int size = msb + 1 - pos; uint32_t rt = reg(ic->arg[0]); uint32_t rs = reg(ic->arg[1]); uint32_t mask = (-1) << pos; mask <<= (32 - pos - size); mask >>= (32 - pos - size); reg(ic->arg[0]) = (int32_t) ((rt & ~mask) | ((rs << pos) & mask)); } /* * ext: Extract bitfield. * * arg[0] = pointer to rt * arg[1] = pointer to rs * arg[2] = (msbd << 5) + lsb */ X(ext) { int msbd = ic->arg[2] >> 5, lsb = ic->arg[2] & 0x1f; int size = msbd + 1; uint32_t rs = reg(ic->arg[1]); uint32_t x = (rs << (32-lsb-size)) >> (32-lsb-size); reg(ic->arg[0]) = (int32_t) (x >> lsb); } /* * dext: Extract bitfield (64-bit). * * arg[0] = pointer to rt * arg[1] = pointer to rs * arg[2] = (msbd << 6) + lsb */ X(dext) { int msbd = ic->arg[2] >> 6, lsb = ic->arg[2] & 0x3f; int size = msbd + 1; uint64_t rs = reg(ic->arg[1]); uint64_t x = (rs << (uint64_t)(64-lsb-size)) >> (uint64_t)(64-lsb-size); reg(ic->arg[0]) = x >> lsb; } /* * dsbh: Doubleword swap bytes within half-word * dshd: Doubleword swap half-words within double-word * wsbh: Word swap bytes within half-word * seb: Sign-extend byte * seh: Sign-extend half-word * * arg[0] = pointer to rt * arg[1] = pointer to rd */ X(dsbh) { uint64_t x = reg(ic->arg[0]); x = ((x & 0x00ff00ff00ff00ffULL) << 8) | ((x & 0xff00ff00ff00ff00ULL) >> 8); reg(ic->arg[1]) = x; } X(dshd) { uint64_t x = reg(ic->arg[0]); x = ((x & 0x000000000000ffffULL) << 48) | ((x & 0x00000000ffff0000ULL) << 16) | ((x & 0x0000ffff00000000ULL) >> 16) | ((x & 0xffff000000000000ULL) >> 48); reg(ic->arg[1]) = x; } X(wsbh) { uint32_t x = reg(ic->arg[0]); x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8); reg(ic->arg[1]) = (int32_t) x; } X(seb) { reg(ic->arg[1]) = (int8_t)reg(ic->arg[0]); } X(seh) { reg(ic->arg[1]) = (int16_t)reg(ic->arg[0]); } /* * 2-register + immediate: * * arg[0] = pointer to rs * arg[1] = pointer to rt * arg[2] = uint32_t immediate value */ X(andi) { reg(ic->arg[1]) = reg(ic->arg[0]) & (uint32_t)ic->arg[2]; } X(ori) { reg(ic->arg[1]) = reg(ic->arg[0]) | (uint32_t)ic->arg[2]; } X(xori) { reg(ic->arg[1]) = reg(ic->arg[0]) ^ (uint32_t)ic->arg[2]; } /* * 2-register: * * arg[0] = ptr to rs * arg[1] = ptr to rt */ X(div) { int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); int32_t res, rem; if (b == 0) res = 0, rem = a; else if (a == (int32_t)0x80000000U && b == -1) res = 0, rem = 0; else res = a / b, rem = a - b*res; cpu->cd.mips.lo = (int32_t)res; cpu->cd.mips.hi = (int32_t)rem; } X(divu) { uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); uint32_t res, rem; if (b == 0) res = 0, rem = a; else res = a / b, rem = a - b*res; cpu->cd.mips.lo = (int32_t)res; cpu->cd.mips.hi = (int32_t)rem; } X(ddiv) { int64_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); int64_t res, rem; if (b == 0) res = 0; else if (a == (int64_t)0x8000000000000000ULL && b == -1) res = 0; else res = a / b; rem = a - b*res; cpu->cd.mips.lo = res; cpu->cd.mips.hi = rem; } X(ddivu) { uint64_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); uint64_t res, rem; if (b == 0) res = 0; else res = a / b; rem = a - b*res; cpu->cd.mips.lo = res; cpu->cd.mips.hi = rem; } X(mult) { int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); int64_t res = (int64_t)a * (int64_t)b; cpu->cd.mips.lo = (int32_t)res; cpu->cd.mips.hi = (int32_t)(res >> 32); } X(mult_r5900) { /* C790/TX79/R5900 multiplication, stores result in hi, lo, and a third register */ int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); int64_t res = (int64_t)a * (int64_t)b; cpu->cd.mips.lo = (int32_t)res; cpu->cd.mips.hi = (int32_t)(res >> 32); reg(ic->arg[2]) = (int32_t)res; } X(multu) { uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); uint64_t res = (uint64_t)a * (uint64_t)b; cpu->cd.mips.lo = (int32_t)res; cpu->cd.mips.hi = (int32_t)(res >> 32); } X(multu_r5900) { /* C790/TX79/R5900 multiplication, stores result in hi, lo, and a third register */ uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); uint64_t res = (uint64_t)a * (uint64_t)b; cpu->cd.mips.lo = (int32_t)res; cpu->cd.mips.hi = (int32_t)(res >> 32); reg(ic->arg[2]) = (int32_t)res; } X(dmult) { uint64_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = 0; uint64_t hi = 0, lo = 0; int neg = 0; if (a >> 63) neg = !neg, a = -a; if (b >> 63) neg = !neg, b = -b; for (; a; a >>= 1) { if (a & 1) { uint64_t old_lo = lo; hi += c; lo += b; if (lo < old_lo) hi ++; } c = (c << 1) | (b >> 63); b <<= 1; } if (neg) { if (lo == 0) hi --; lo --; hi ^= (int64_t) -1; lo ^= (int64_t) -1; } cpu->cd.mips.lo = lo; cpu->cd.mips.hi = hi; } X(dmultu) { uint64_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = 0; uint64_t hi = 0, lo = 0; for (; a; a >>= 1) { if (a & 1) { uint64_t old_lo = lo; hi += c; lo += b; if (lo < old_lo) hi ++; } c = (c << 1) | (b >> 63); b <<= 1; } cpu->cd.mips.lo = lo; cpu->cd.mips.hi = hi; } X(tge) { MODE_int_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); if (a >= b) { /* Synch. PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_TR, 0, 0, 0, 0, 0, 0); } } X(tgeu) { MODE_uint_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); if (a >= b) { /* Synch. PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_TR, 0, 0, 0, 0, 0, 0); } } X(tlt) { MODE_int_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); if (a < b) { /* Synch. PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_TR, 0, 0, 0, 0, 0, 0); } } X(tltu) { MODE_uint_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); if (a < b) { /* Synch. PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_TR, 0, 0, 0, 0, 0, 0); } } X(teq) { MODE_uint_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); if (a == b) { /* Synch. PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_TR, 0, 0, 0, 0, 0, 0); } } X(tne) { MODE_uint_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); if (a != b) { /* Synch. PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_TR, 0, 0, 0, 0, 0, 0); } } /* * 3-register arithmetic instructions: * * arg[0] = ptr to rs * arg[1] = ptr to rt * arg[2] = ptr to rd */ X(addu) { reg(ic->arg[2]) = (int32_t)(reg(ic->arg[0]) + reg(ic->arg[1])); } X(add) { int32_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); int32_t rd = rs + rt; if ((rs >= 0 && rt >= 0 && rd < 0) || (rs < 0 && rt < 0 && rd >= 0)) { /* Synch. PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_OV, 0, 0, 0, 0, 0, 0); } else reg(ic->arg[2]) = rd; } X(daddu){ reg(ic->arg[2]) = reg(ic->arg[0]) + reg(ic->arg[1]); } X(dadd) { int64_t rs = reg(ic->arg[0]), rt = reg(ic->arg[1]); int64_t rd = rs + rt; if ((rs >= 0 && rt >= 0 && rd < 0) || (rs < 0 && rt < 0 && rd >= 0)) { /* Synch. PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_OV, 0, 0, 0, 0, 0, 0); } else reg(ic->arg[2]) = rd; } X(subu) { reg(ic->arg[2]) = (int32_t)(reg(ic->arg[0]) - reg(ic->arg[1])); } X(sub) { /* NOTE: Negating rt and using addition. TODO: Is this correct? */ int32_t rs = reg(ic->arg[0]), rt = - reg(ic->arg[1]); int32_t rd = rs + rt; if ((rs >= 0 && rt >= 0 && rd < 0) || (rs < 0 && rt < 0 && rd >= 0)) { /* Synch. PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_OV, 0, 0, 0, 0, 0, 0); } else reg(ic->arg[2]) = rd; } X(dsubu){ reg(ic->arg[2]) = reg(ic->arg[0]) - reg(ic->arg[1]); } X(dsub) { /* NOTE: Negating rt and using addition. TODO: Is this correct? */ int64_t rs = reg(ic->arg[0]), rt = - reg(ic->arg[1]); int64_t rd = rs + rt; if ((rs >= 0 && rt >= 0 && rd < 0) || (rs < 0 && rt < 0 && rd >= 0)) { /* Synch. PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_OV, 0, 0, 0, 0, 0, 0); } else reg(ic->arg[2]) = rd; } X(slt) { reg(ic->arg[2]) = (MODE_int_t)reg(ic->arg[0]) < (MODE_int_t)reg(ic->arg[1]); } X(sltu) { reg(ic->arg[2]) = (MODE_uint_t)reg(ic->arg[0]) < (MODE_uint_t)reg(ic->arg[1]); } X(and) { reg(ic->arg[2]) = reg(ic->arg[0]) & reg(ic->arg[1]); } X(or) { reg(ic->arg[2]) = reg(ic->arg[0]) | reg(ic->arg[1]); } X(xor) { reg(ic->arg[2]) = reg(ic->arg[0]) ^ reg(ic->arg[1]); } X(nor) { reg(ic->arg[2]) = ~(reg(ic->arg[0]) | reg(ic->arg[1])); } X(sll) { reg(ic->arg[2]) = (int32_t)(reg(ic->arg[0]) << (int32_t)ic->arg[1]); } X(sllv){ int32_t sa = reg(ic->arg[1]) & 31; reg(ic->arg[2]) = (int32_t)(reg(ic->arg[0]) << sa); } X(srl) { reg(ic->arg[2]) = (int32_t)((uint32_t)reg(ic->arg[0]) >> ic->arg[1]); } X(srlv){ int32_t sa = reg(ic->arg[1]) & 31; reg(ic->arg[2]) = (int32_t)((uint32_t)reg(ic->arg[0]) >> sa); } X(sra) { reg(ic->arg[2]) = (int32_t)((int32_t)reg(ic->arg[0]) >> ic->arg[1]); } X(srav){ int32_t sa = reg(ic->arg[1]) & 31; reg(ic->arg[2]) = (int32_t)((int32_t)reg(ic->arg[0]) >> sa); } X(dsll) { reg(ic->arg[2]) = (int64_t)reg(ic->arg[0]) << (int64_t)ic->arg[1]; } X(dsllv){ int64_t sa = reg(ic->arg[1]) & 63; reg(ic->arg[2]) = reg(ic->arg[0]) << sa; } X(dsrl) { reg(ic->arg[2]) = (int64_t)((uint64_t)reg(ic->arg[0]) >> (uint64_t) ic->arg[1]);} X(dsrlv){ int64_t sa = reg(ic->arg[1]) & 63; reg(ic->arg[2]) = (uint64_t)reg(ic->arg[0]) >> sa; } X(dsra) { reg(ic->arg[2]) = (int64_t)reg(ic->arg[0]) >> (int64_t)ic->arg[1]; } X(dsrav){ int64_t sa = reg(ic->arg[1]) & 63; reg(ic->arg[2]) = (int64_t)reg(ic->arg[0]) >> sa; } X(mul) { reg(ic->arg[2]) = (int32_t) ( (int32_t)reg(ic->arg[0]) * (int32_t)reg(ic->arg[1]) ); } X(movn) { if (reg(ic->arg[1])) reg(ic->arg[2]) = reg(ic->arg[0]); } X(movz) { if (!reg(ic->arg[1])) reg(ic->arg[2]) = reg(ic->arg[0]); } X(ror) { uint32_t result = reg(ic->arg[0]); int sa = ic->arg[1]; result = (result >> sa) | (result << (32-sa)); reg(ic->arg[2]) = (int32_t) result; } X(rorv) { uint32_t result = reg(ic->arg[0]); int sa = reg(ic->arg[1]); result = (result >> sa) | (result << (32-sa)); reg(ic->arg[2]) = (int32_t) result; } /* * p*: 128-bit C790/TX79/R5900 stuff * * arg[0] = rs (note: not a pointer) * arg[1] = rt (note: not a pointer) * arg[2] = rd (note: not a pointer) */ X(por) { cpu->cd.mips.gpr[ic->arg[2]] = cpu->cd.mips.gpr[ic->arg[0]] | cpu->cd.mips.gpr[ic->arg[1]]; cpu->cd.mips.gpr_quadhi[ic->arg[2]] = cpu->cd.mips.gpr_quadhi[ic->arg[0]] | cpu->cd.mips.gpr_quadhi[ic->arg[1]]; } X(pextlw) { uint64_t lo, hi; lo = (uint32_t)cpu->cd.mips.gpr[ic->arg[1]] | (uint64_t)((uint64_t)cpu->cd.mips.gpr[ic->arg[0]] << 32); hi = (cpu->cd.mips.gpr[ic->arg[0]] & 0xffffffff00000000ULL) | (uint32_t)((uint64_t)cpu->cd.mips.gpr[ic->arg[1]] >> 32); cpu->cd.mips.gpr[ic->arg[2]] = lo; cpu->cd.mips.gpr_quadhi[ic->arg[2]] = hi; } /* * madd, maddu, msub, msubu: Multiply-and-add/subtract * * arg[0] = ptr to rs * arg[1] = ptr to rt * arg[2] = ptr to rd (only used on R5900/TX79) */ X(madd) { int64_t rs = (int32_t)reg(ic->arg[0]), rt = (int32_t)reg(ic->arg[1]); int64_t sum = rs * rt, hilo = (cpu->cd.mips.hi << 32) | (uint32_t)(cpu->cd.mips.lo); hilo += sum; cpu->cd.mips.hi = (int32_t)(hilo>>32); cpu->cd.mips.lo = (int32_t)hilo; } X(madd_rd) { int64_t rs = (int32_t)reg(ic->arg[0]), rt = (int32_t)reg(ic->arg[1]); int64_t sum = rs * rt, hilo = (cpu->cd.mips.hi << 32) | (uint32_t)(cpu->cd.mips.lo); hilo += sum; cpu->cd.mips.hi = (int32_t)(hilo>>32); cpu->cd.mips.lo = (int32_t)hilo; reg(ic->arg[2]) = (int32_t)hilo; } X(msub) { int64_t rs = (int32_t)reg(ic->arg[0]), rt = (int32_t)reg(ic->arg[1]); int64_t sum = rs * rt, hilo = (cpu->cd.mips.hi << 32) | (uint32_t)(cpu->cd.mips.lo); hilo -= sum; cpu->cd.mips.hi = (int32_t)(hilo>>32); cpu->cd.mips.lo = (int32_t)hilo; } X(maddu) { int64_t rs = (uint32_t)reg(ic->arg[0]), rt = (uint32_t)reg(ic->arg[1]); int64_t sum = rs * rt, hilo = (cpu->cd.mips.hi << 32) | (uint32_t)(cpu->cd.mips.lo); hilo += sum; cpu->cd.mips.hi = (int32_t)(hilo>>32); cpu->cd.mips.lo = (int32_t)hilo; } X(maddu_rd) { int64_t rs = (uint32_t)reg(ic->arg[0]), rt = (uint32_t)reg(ic->arg[1]); int64_t sum = rs * rt, hilo = (cpu->cd.mips.hi << 32) | (uint32_t)(cpu->cd.mips.lo); hilo += sum; cpu->cd.mips.hi = (int32_t)(hilo>>32); cpu->cd.mips.lo = (int32_t)hilo; reg(ic->arg[2]) = (int32_t)hilo; } X(msubu) { int64_t rs = (uint32_t)reg(ic->arg[0]), rt = (uint32_t)reg(ic->arg[1]); int64_t sum = rs * rt, hilo = (cpu->cd.mips.hi << 32) | (uint32_t)(cpu->cd.mips.lo); hilo -= sum; cpu->cd.mips.hi = (int32_t)(hilo>>32); cpu->cd.mips.lo = (int32_t)hilo; } /* * mov: Move one register into another. * * arg[0] = pointer to source * arg[2] = pointer to destination */ X(mov) { reg(ic->arg[2]) = reg(ic->arg[0]); } /* * clz, clo, dclz, dclo: Count leading zeroes/ones. * * arg[0] = pointer to rs * arg[1] = pointer to rd */ X(clz) { uint32_t x = reg(ic->arg[0]); int count; for (count=0; count<32; count++) { if (x & 0x80000000UL) break; x <<= 1; } reg(ic->arg[1]) = count; } X(clo) { uint32_t x = reg(ic->arg[0]); int count; for (count=0; count<32; count++) { if (!(x & 0x80000000UL)) break; x <<= 1; } reg(ic->arg[1]) = count; } X(dclz) { uint64_t x = reg(ic->arg[0]); int count; for (count=0; count<64; count++) { if (x & 0x8000000000000000ULL) break; x <<= 1; } reg(ic->arg[1]) = count; } X(dclo) { uint64_t x = reg(ic->arg[0]); int count; for (count=0; count<64; count++) { if (!(x & 0x8000000000000000ULL)) break; x <<= 1; } reg(ic->arg[1]) = count; } /* * addi, daddi: Add immediate, overflow detection. * addiu, daddiu: Add immediate. * slti: Set if less than immediate (signed 32-bit) * sltiu: Set if less than immediate (signed 32-bit, but unsigned compare) * * arg[0] = pointer to rs * arg[1] = pointer to rt * arg[2] = (int32_t) immediate value */ X(addi) { int32_t rs = reg(ic->arg[0]), imm = (int32_t)ic->arg[2]; int32_t rt = rs + imm; if ((rs >= 0 && imm >= 0 && rt < 0) || (rs < 0 && imm < 0 && rt >= 0)) { /* Synch. PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_OV, 0, 0, 0, 0, 0, 0); } else reg(ic->arg[1]) = rt; } X(addiu) { reg(ic->arg[1]) = (int32_t) ((int32_t)reg(ic->arg[0]) + (int32_t)ic->arg[2]); } X(daddi) { int64_t rs = reg(ic->arg[0]), imm = (int32_t)ic->arg[2]; int64_t rt = rs + imm; if ((rs >= 0 && imm >= 0 && rt < 0) || (rs < 0 && imm < 0 && rt >= 0)) { /* Synch. PC and cause an exception: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_OV, 0, 0, 0, 0, 0, 0); } else reg(ic->arg[1]) = rt; } X(daddiu) { reg(ic->arg[1]) = reg(ic->arg[0]) + (int32_t)ic->arg[2]; } X(slti) { reg(ic->arg[1]) = (MODE_int_t)reg(ic->arg[0]) < (int32_t)ic->arg[2]; } X(sltiu) { reg(ic->arg[1]) = (MODE_uint_t)reg(ic->arg[0]) < ((MODE_uint_t)(int32_t)ic->arg[2]); } /* * set: Set a register to an immediate (signed) 32-bit value. * (This is the actual implementation of the lui instruction.) * * arg[0] = pointer to the register * arg[1] = (int32_t) immediate value */ X(set) { reg(ic->arg[0]) = (int32_t)ic->arg[1]; } /* * cfc0: Copy from Coprocessor 0. * mfc0, dmfc0: Move from Coprocessor 0. * mtc0, dmtc0: Move to Coprocessor 0. * * arg[0] = pointer to GPR (rt) * arg[1] = coprocessor 0 register number | (select << 5) (or for the * cfc0 instruction, the coprocessor control register number) * arg[2] = relative addr of this instruction within the page */ X(cfc0) { int fs = ic->arg[1] & 31; cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<pc |= ic->arg[2]; /* TODO: cause exception if necessary */ reg(ic->arg[0]) = (int32_t)cpu->cd.mips.coproc[0]->fcr[fs]; } X(mfc0) { int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5; uint64_t tmp; cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<pc |= ic->arg[2]; /* TODO: cause exception if necessary */ coproc_register_read(cpu, cpu->cd.mips.coproc[0], rd, &tmp, select); reg(ic->arg[0]) = (int32_t)tmp; } X(mfc0_select0) { /* Fast int32_t read, with no side effects: */ int rd = ic->arg[1] & 31; #if 0 uint64_t tmp; cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<pc |= ic->arg[2]; /* TODO: cause exception if necessary */ #endif reg(ic->arg[0]) = (int32_t)cpu->cd.mips.coproc[0]->reg[rd]; } X(mtc0) { int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5; uint64_t tmp = (int32_t) reg(ic->arg[0]); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<pc |= ic->arg[2]; /* TODO: cause exception if necessary */ coproc_register_write(cpu, cpu->cd.mips.coproc[0], rd, &tmp, 0, select); /* * Interrupts enabled, and any interrupt pending? (Note/TODO: This * code is duplicated in cpu_dyntrans.c. Fix this?) */ if (rd == COP0_STATUS && !cpu->delay_slot) { uint32_t status = cpu->cd.mips.coproc[0]->reg[COP0_STATUS]; uint32_t cause = cpu->cd.mips.coproc[0]->reg[COP0_CAUSE]; /* NOTE: STATUS_IE happens to match the enable bit also on R2000/R3000, so this is ok. */ if (cpu->cd.mips.cpu_type.exc_model != EXC3K) { if (status & (STATUS_EXL | STATUS_ERL)) status &= ~STATUS_IE; } /* Ugly R5900 special case: (TODO: move this?) */ if (cpu->cd.mips.cpu_type.rev == MIPS_R5900 && !(status & R5900_STATUS_EIE)) status &= ~STATUS_IE; if (status & STATUS_IE && (status & cause & STATUS_IM_MASK)) { cpu->pc += sizeof(uint32_t); mips_cpu_exception(cpu, EXCEPTION_INT, 0, 0,0,0,0,0); } } } X(dmfc0) { int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5; cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<pc |= ic->arg[2]; /* TODO: cause exception if necessary */ coproc_register_read(cpu, cpu->cd.mips.coproc[0], rd, (uint64_t *)ic->arg[0], select); } X(dmfc0_select0) { /* Fast int64_t read, with no side effects: */ int rd = ic->arg[1] & 31; #if 0 uint64_t tmp; cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<pc |= ic->arg[2]; /* TODO: cause exception if necessary */ #endif reg(ic->arg[0]) = cpu->cd.mips.coproc[0]->reg[rd]; } X(dmtc0) { int rd = ic->arg[1] & 31, select = ic->arg[1] >> 5; cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<pc |= ic->arg[2]; /* TODO: cause exception if necessary */ coproc_register_write(cpu, cpu->cd.mips.coproc[0], rd, (uint64_t *)ic->arg[0], 1, select); } /* * cop1_bc: Floating point conditional branch. * * arg[0] = cc * arg[1] = nd (=2) and tf (=1) bits * arg[2] = offset (relative to start of this page) */ X(cop1_bc) { MODE_int_t old_pc = cpu->pc; int x, cc = ic->arg[0]; COPROC_AVAILABILITY_CHECK(1); /* Get the correct condition code bit: */ if (cc == 0) x = (cpu->cd.mips.coproc[1]->fcr[MIPS_FPU_FCSR] >> MIPS_FCSR_FCC0_SHIFT) & 1; else x = (cpu->cd.mips.coproc[1]->fcr[MIPS_FPU_FCSR] >> (MIPS_FCSR_FCC1_SHIFT + cc-1)) & 1; /* Branch on false? Then invert the truth value. */ if (!(ic->arg[1] & 1)) x ^= 1; /* Execute the delay slot (except if it is nullified): */ cpu->delay_slot = TO_BE_DELAYED; if (x || !(ic->arg[1] & 2)) ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (x) { old_pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = old_pc + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } else cpu->cd.mips.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } /* * cop1_slow: Fallback to legacy cop1 code. (Slow, but it should work.) */ X(cop1_slow) { COPROC_AVAILABILITY_CHECK(1); coproc_function(cpu, cpu->cd.mips.coproc[1], 1, ic->arg[0], 0, 1); } /* * syscall, break: Synchronize the PC and cause an exception. */ X(syscall) { int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<< MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_SYS, 0, 0, 0, 0, 0, 0); } X(break) { int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<< MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); mips_cpu_exception(cpu, EXCEPTION_BP, 0, 0, 0, 0, 0, 0); } X(reboot) { if (!cop0_availability_check(cpu, ic)) return; cpu->running = 0; debugger_n_steps_left_before_interaction = 0; cpu->cd.mips.next_ic = ¬hing_call; } /* * promemul: PROM software emulation. */ X(promemul) { /* Synchronize the PC and call the correct emulation layer: */ MODE_int_t old_pc; int res, low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<< MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); old_pc = cpu->pc; switch (cpu->machine->machine_type) { case MACHINE_PMAX: res = decstation_prom_emul(cpu); break; case MACHINE_PS2: res = playstation2_sifbios_emul(cpu); break; case MACHINE_ARC: case MACHINE_SGI: res = arcbios_emul(cpu); break; case MACHINE_EVBMIPS: res = yamon_emul(cpu); break; default:fatal("TODO: Unimplemented machine type for PROM magic trap\n"); exit(1); } if (res) { /* Return from the PROM call: */ cpu->pc = (MODE_int_t)cpu->cd.mips.gpr[MIPS_GPR_RA]; cpu->delay_slot = NOT_DELAYED; if (cpu->machine->show_trace_tree) cpu_functioncall_trace_return(cpu); } else { /* The PROM call blocks. */ cpu->n_translated_instrs += 10; cpu->pc = old_pc; } quick_pc_to_pointers(cpu); } /* * tlbw: TLB write indexed and random * * arg[0] = 1 for random, 0 for indexed * arg[2] = relative addr of this instruction within the page */ X(tlbw) { if (!cop0_availability_check(cpu, ic)) return; cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<pc |= ic->arg[2]; coproc_tlbwri(cpu, ic->arg[0]); } /* * tlbp: TLB probe * tlbr: TLB read * * arg[2] = relative addr of this instruction within the page */ X(tlbp) { if (!cop0_availability_check(cpu, ic)) return; cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<pc |= ic->arg[2]; coproc_tlbpr(cpu, 0); } X(tlbr) { if (!cop0_availability_check(cpu, ic)) return; cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<pc |= ic->arg[2]; coproc_tlbpr(cpu, 1); } /* * ei_or_di: MIPS32/64 rev 2, Enable or disable interrupts * * arg[0] = ptr to rt * arg[1] = non-zero to enable interrupts */ X(ei_or_di) { reg(ic->arg[0]) = cpu->cd.mips.coproc[0]->reg[COP0_STATUS]; if (ic->arg[1]) cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= STATUS_IE; else cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_IE; } /* * rfe: Return from exception handler (R2000/R3000) */ X(rfe) { if (!cop0_availability_check(cpu, ic)) return; /* Just rotate the interrupt/user bits: */ cpu->cd.mips.coproc[0]->reg[COP0_STATUS] = (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) | ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2); /* * Note: no pc to pointers conversion is necessary here. Usually the * rfe instruction resides in the delay slot of a jr k0/k1, and * it is up to that instruction to do the pointer conversion. */ } /* * eret: Return from exception handler (non-R3000 style) */ X(eret) { if (!cop0_availability_check(cpu, ic)) return; if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) { cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC]; cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL; } else { cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC]; cpu->delay_slot = 0; cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL; } quick_pc_to_pointers(cpu); cpu->cd.mips.rmw = 0; /* the "LL bit" */ } /* * deret: Return from debug (EJTAG) handler */ X(deret) { if (!cop0_availability_check(cpu, ic)) return; /* * According to the MIPS64 manual, deret loads PC from the DEPC cop0 * register, and jumps there immediately. No delay slot. * * TODO: This instruction is only available if the processor is in * debug mode. (What does that mean?) * * TODO: This instruction is undefined in a delay slot. */ cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_DEPC]; cpu->delay_slot = 0; cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL; quick_pc_to_pointers(cpu); } /* * idle: Called from the implementation of wait, or netbsd_pmax_idle. */ X(idle) { /* * If there is an interrupt, then just return. Otherwise * re-run the wait instruction (after a delay). */ uint32_t status = cpu->cd.mips.coproc[0]->reg[COP0_STATUS]; uint32_t cause = cpu->cd.mips.coproc[0]->reg[COP0_CAUSE]; if (cpu->cd.mips.cpu_type.exc_model != EXC3K) { if (status & (STATUS_EXL | STATUS_ERL)) status &= ~STATUS_IE; } /* Ugly R5900 special case: (TODO: move this?) */ if (cpu->cd.mips.cpu_type.rev == MIPS_R5900 && !(status & R5900_STATUS_EIE)) status &= ~STATUS_IE; if (status & STATUS_IE && (status & cause & STATUS_IM_MASK)) return; cpu->cd.mips.next_ic = ic; cpu->is_halted = 1; cpu->has_been_idling = 1; /* * There was no interrupt. Go to sleep. * * TODO: * * Think about how to actually implement this usleep stuff, * in an SMP and/or timing accurate environment. */ if (cpu->machine->ncpus == 1) { static int x = 0; if ((++x) == 300) { usleep(20); x = 0; } cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 6; } } /* * wait: Wait for external interrupt. */ X(wait) { if (!cop0_availability_check(cpu, ic)) return; instr(idle)(cpu, ic); } /* * rdhwr: Read CPUNum hardware register into gpr (MIPS32/64 rev 2). * * arg[0] = ptr to rt (destination register) */ X(rdhwr_cpunum) { reg(ic->arg[0]) = cpu->cpu_id; } /* * rdhwr: Read CC (cycle count) register into gpr (MIPS32/64 rev 2). * * arg[0] = ptr to rt (destination register) */ X(rdhwr_cc) { reg(ic->arg[0]) = cpu->cd.mips.coproc[0]->reg[COP0_COUNT]; } #include "tmp_mips_loadstore.cc" /* * Load linked / store conditional: * * A Load-linked instruction initiates a RMW (read-modify-write) sequence. * COP0_LLADDR is updated for diagnostic purposes, except for CPUs in the * R10000 family. * * A Store-conditional instruction ends the sequence. * * arg[0] = ptr to rt * arg[1] = ptr to rs * arg[2] = int32_t imm */ X(ll) { MODE_int_t addr = reg(ic->arg[1]) + (int32_t)ic->arg[2]; int low_pc; uint8_t word[sizeof(uint32_t)]; /* Synch. PC and load using slow memory_rw(): */ low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); if (addr & (sizeof(word)-1)) { fatal("TODO: load linked unaligned access: exception\n"); exit(1); } if (!cpu->memory_rw(cpu, cpu->mem, addr, word, sizeof(word), MEM_READ, CACHE_DATA)) { /* An exception occurred. */ return; } cpu->cd.mips.rmw = 1; cpu->cd.mips.rmw_addr = addr; cpu->cd.mips.rmw_len = sizeof(word); if (cpu->cd.mips.cpu_type.exc_model != MMU10K) cpu->cd.mips.coproc[0]->reg[COP0_LLADDR] = (addr >> 4) & 0xffffffffULL; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) reg(ic->arg[0]) = (int32_t) (word[0] + (word[1] << 8) + (word[2] << 16) + (word[3] << 24)); else reg(ic->arg[0]) = (int32_t) (word[3] + (word[2] << 8) + (word[1] << 16) + (word[0] << 24)); } X(lld) { MODE_int_t addr = reg(ic->arg[1]) + (int32_t)ic->arg[2]; int low_pc; uint8_t word[sizeof(uint64_t)]; /* Synch. PC and load using slow memory_rw(): */ low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); if (addr & (sizeof(word)-1)) { fatal("TODO: load linked unaligned access: exception\n"); exit(1); } if (!cpu->memory_rw(cpu, cpu->mem, addr, word, sizeof(word), MEM_READ, CACHE_DATA)) { /* An exception occurred. */ return; } cpu->cd.mips.rmw = 1; cpu->cd.mips.rmw_addr = addr; cpu->cd.mips.rmw_len = sizeof(word); if (cpu->cd.mips.cpu_type.exc_model != MMU10K) cpu->cd.mips.coproc[0]->reg[COP0_LLADDR] = (addr >> 4) & 0xffffffffULL; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) reg(ic->arg[0]) = word[0] + (word[1] << 8) + (word[2] << 16) + ((uint64_t)word[3] << 24) + + ((uint64_t)word[4] << 32) + ((uint64_t)word[5] << 40) + ((uint64_t)word[6] << 48) + ((uint64_t)word[7] << 56); else reg(ic->arg[0]) = word[7] + (word[6] << 8) + (word[5] << 16) + ((uint64_t)word[4] << 24) + + ((uint64_t)word[3] << 32) + ((uint64_t)word[2] << 40) + ((uint64_t)word[1] << 48) + ((uint64_t)word[0] << 56); } X(sc) { MODE_int_t addr = reg(ic->arg[1]) + (int32_t)ic->arg[2]; uint64_t r = reg(ic->arg[0]); int low_pc, i; uint8_t word[sizeof(uint32_t)]; /* Synch. PC and store using slow memory_rw(): */ low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); if (addr & (sizeof(word)-1)) { fatal("TODO: sc unaligned access: exception\n"); exit(1); } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { word[0]=r; word[1]=r>>8; word[2]=r>>16; word[3]=r>>24; } else { word[3]=r; word[2]=r>>8; word[1]=r>>16; word[0]=r>>24; } /* If rmw is 0, then the store failed. (This cache-line was written to by someone else.) */ if (cpu->cd.mips.rmw == 0 || (MODE_int_t)cpu->cd.mips.rmw_addr != addr || cpu->cd.mips.rmw_len != sizeof(word)) { reg(ic->arg[0]) = 0; cpu->cd.mips.rmw = 0; return; } if (!cpu->memory_rw(cpu, cpu->mem, addr, word, sizeof(word), MEM_WRITE, CACHE_DATA)) { /* An exception occurred. */ return; } /* We succeeded. Let's invalidate everybody else's store to this cache line: */ for (i=0; imachine->ncpus; i++) { if (cpu->machine->cpus[i]->cd.mips.rmw) { uint64_t yaddr = addr, xaddr = cpu->machine->cpus[i]-> cd.mips.rmw_addr; uint64_t mask = ~(cpu->machine->cpus[i]-> cd.mips.cache_linesize[CACHE_DATA] - 1); xaddr &= mask; yaddr &= mask; if (xaddr == yaddr) cpu->machine->cpus[i]->cd.mips.rmw = 0; } } reg(ic->arg[0]) = 1; cpu->cd.mips.rmw = 0; } X(scd) { MODE_int_t addr = reg(ic->arg[1]) + (int32_t)ic->arg[2]; uint64_t r = reg(ic->arg[0]); int low_pc, i; uint8_t word[sizeof(uint64_t)]; /* Synch. PC and store using slow memory_rw(): */ low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); if (addr & (sizeof(word)-1)) { fatal("TODO: sc unaligned access: exception\n"); exit(1); } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { word[0]=r; word[1]=r>>8; word[2]=r>>16; word[3]=r>>24; word[4]=r>>32; word[5]=r>>40; word[6]=r>>48; word[7]=r>>56; } else { word[7]=r; word[6]=r>>8; word[5]=r>>16; word[4]=r>>24; word[3]=r>>32; word[2]=r>>40; word[1]=r>>48; word[0]=r>>56; } /* If rmw is 0, then the store failed. (This cache-line was written to by someone else.) */ if (cpu->cd.mips.rmw == 0 || (MODE_int_t)cpu->cd.mips.rmw_addr != addr || cpu->cd.mips.rmw_len != sizeof(word)) { reg(ic->arg[0]) = 0; cpu->cd.mips.rmw = 0; return; } if (!cpu->memory_rw(cpu, cpu->mem, addr, word, sizeof(word), MEM_WRITE, CACHE_DATA)) { /* An exception occurred. */ return; } /* We succeeded. Let's invalidate everybody else's store to this cache line: */ for (i=0; imachine->ncpus; i++) { if (cpu->machine->cpus[i]->cd.mips.rmw) { uint64_t yaddr = addr, xaddr = cpu->machine->cpus[i]-> cd.mips.rmw_addr; uint64_t mask = ~(cpu->machine->cpus[i]-> cd.mips.cache_linesize[CACHE_DATA] - 1); xaddr &= mask; yaddr &= mask; if (xaddr == yaddr) cpu->machine->cpus[i]->cd.mips.rmw = 0; } } reg(ic->arg[0]) = 1; cpu->cd.mips.rmw = 0; } /* * lwc1, swc1: Coprocessor 1 load/store (32-bit) * ldc1, sdc1: Coprocessor 1 load/store (64-bit) * * arg[0] = ptr to coprocessor register * arg[1] = ptr to rs (base pointer register) * arg[2] = int32_t imm */ X(lwc1) { COPROC_AVAILABILITY_CHECK(1); #ifdef MODE32 mips32_loadstore #else mips_loadstore #endif [ (cpu->byte_order == EMUL_LITTLE_ENDIAN? 0 : 16) + 2 * 2 + 1] (cpu, ic); } X(swc1) { COPROC_AVAILABILITY_CHECK(1); #ifdef MODE32 mips32_loadstore #else mips_loadstore #endif [ (cpu->byte_order == EMUL_LITTLE_ENDIAN? 0 : 16) + 8 + 2 * 2] (cpu, ic); } X(ldc1) { int use_fp_pairs = !(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_FR); uint64_t fpr, *backup_ptr; COPROC_AVAILABILITY_CHECK(1); backup_ptr = (uint64_t *) ic->arg[0]; ic->arg[0] = (size_t) &fpr; #ifdef MODE32 mips32_loadstore #else mips_loadstore #endif [ (cpu->byte_order == EMUL_LITTLE_ENDIAN? 0 : 16) + 3 * 2 + 1] (cpu, ic); if (use_fp_pairs) { backup_ptr[0] = (int64_t)(int32_t) fpr; backup_ptr[1] = (int64_t)(int32_t) (fpr >> 32); } else { *backup_ptr = fpr; } ic->arg[0] = (size_t) backup_ptr; } X(sdc1) { int use_fp_pairs = !(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_FR); uint64_t fpr, *backup_ptr; COPROC_AVAILABILITY_CHECK(1); backup_ptr = (uint64_t *) ic->arg[0]; ic->arg[0] = (size_t) &fpr; if (use_fp_pairs) { uint32_t lo = backup_ptr[0]; uint32_t hi = backup_ptr[1]; fpr = (((uint64_t)hi) << 32) | lo; } else { fpr = *backup_ptr; } #ifdef MODE32 mips32_loadstore #else mips_loadstore #endif [ (cpu->byte_order == EMUL_LITTLE_ENDIAN? 0 : 16) + 8 + 3 * 2] (cpu, ic); ic->arg[0] = (size_t) backup_ptr; } /* * Unaligned loads/stores: * * arg[0] = ptr to rt * arg[1] = ptr to rs * arg[2] = int32_t imm */ X(lwl) { mips_unaligned_loadstore(cpu, ic, 1, sizeof(uint32_t), 0); } X(lwr) { mips_unaligned_loadstore(cpu, ic, 0, sizeof(uint32_t), 0); } X(ldl) { mips_unaligned_loadstore(cpu, ic, 1, sizeof(uint64_t), 0); } X(ldr) { mips_unaligned_loadstore(cpu, ic, 0, sizeof(uint64_t), 0); } X(swl) { mips_unaligned_loadstore(cpu, ic, 1, sizeof(uint32_t), 1); } X(swr) { mips_unaligned_loadstore(cpu, ic, 0, sizeof(uint32_t), 1); } X(sdl) { mips_unaligned_loadstore(cpu, ic, 1, sizeof(uint64_t), 1); } X(sdr) { mips_unaligned_loadstore(cpu, ic, 0, sizeof(uint64_t), 1); } /* * di, ei: R5900 interrupt enable/disable. * * TODO: check the R5900_STATUS_EDI bit in the status register. If it is * cleared, and we are not running in kernel mode, then both the EI and DI * instructions should be treated as NOPs! */ X(di_r5900) { if (!cop0_availability_check(cpu, ic)) return; cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE; } X(ei_r5900) { if (!cop0_availability_check(cpu, ic)) return; cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE; } /*****************************************************************************/ /* * sw_loop: * * s: addiu rX,rX,4 rX = arg[0] and arg[1] * bne rY,rX,s (or rX,rY,s) rt=arg[1], rs=arg[0] * sw rZ,-4(rX) rt=arg[0], rs=arg[1] */ X(sw_loop) { MODE_uint_t rX = reg(ic->arg[0]), rZ = reg(ic[2].arg[0]); uint64_t *rYp = (uint64_t *) ic[1].arg[0]; MODE_uint_t rY, bytes_to_write; unsigned char *page; int partial = 0; page = cpu->cd.mips.host_store[rX >> 12]; /* Fallback: */ if (cpu->delay_slot || page == NULL || (rX & 3) != 0 || rZ != 0) { instr(addiu)(cpu, ic); return; } if (rYp == (uint64_t *) ic->arg[0]) rYp = (uint64_t *) ic[1].arg[1]; rY = reg(rYp); bytes_to_write = rY - rX; if ((rX & 0xfff) + bytes_to_write > 0x1000) { bytes_to_write = 0x1000 - (rX & 0xfff); partial = 1; } /* printf("rX = %08x\n", (int)rX); printf("rY = %08x\n", (int)rY); printf("rZ = %08x\n", (int)rZ); printf("%i bytes\n", (int)bytes_to_write); */ memset(page + (rX & 0xfff), 0, bytes_to_write); reg(ic->arg[0]) = rX + bytes_to_write; cpu->n_translated_instrs += bytes_to_write / 4 * 3 - 1; cpu->cd.mips.next_ic = partial? (struct mips_instr_call *) &ic[0] : (struct mips_instr_call *) &ic[3]; } #ifdef MODE32 /* multi_{l,s}w_2, _3, etc. */ #include "tmp_mips_loadstore_multi.cc" #endif /* * multi_addu_3: */ X(multi_addu_3) { /* Fallback: */ if (cpu->delay_slot) { instr(addu)(cpu, ic); return; } reg(ic[0].arg[2]) = (int32_t)(reg(ic[0].arg[0]) + reg(ic[0].arg[1])); reg(ic[1].arg[2]) = (int32_t)(reg(ic[1].arg[0]) + reg(ic[1].arg[1])); reg(ic[2].arg[2]) = (int32_t)(reg(ic[2].arg[0]) + reg(ic[2].arg[1])); cpu->n_translated_instrs += 2; cpu->cd.mips.next_ic = ic + 3; } /* * netbsd_r3k_picache_do_inv: * * ic[0] mtc0 rV,status * 1 nop * 2 nop * 3 s: addiu rX,rX,4 * 4 bne rY,rX,s * 5 sb zr,-4(rX) * 6 nop * 7 nop * 8 mtc0 rT,status */ X(netbsd_r3k_picache_do_inv) { MODE_uint_t rx = reg(ic[3].arg[0]), ry = reg(ic[4].arg[1]); /* Fallback if the environment isn't exactly right: */ if (!(reg(ic[0].arg[0]) & MIPS1_ISOL_CACHES) || (rx & 3) || (ry & 3) || cpu->delay_slot) { instr(mtc0)(cpu, ic); return; } reg(ic[3].arg[0]) = ry; cpu->n_translated_instrs += (ry - rx + 4) / 4 * 3 + 4; /* Run the last mtc0 instruction: */ cpu->cd.mips.next_ic = ic + 8; } #ifdef MODE32 /* * netbsd_pmax_idle(): * * s: lui rX, hi * lw rY, lo(rX) * nop * beq zr, rY, s * nop */ X(netbsd_pmax_idle) { uint32_t addr, pageindex, i; int32_t *page; reg(ic[0].arg[0]) = (int32_t)ic[0].arg[1]; addr = reg(ic[0].arg[0]) + (int32_t)ic[1].arg[2]; pageindex = addr >> 12; i = (addr & 0xfff) >> 2; page = (int32_t *) cpu->cd.mips.host_load[pageindex]; /* Fallback: */ if (cpu->delay_slot || page == NULL || page[i] != 0) return; instr(idle)(cpu, ic); } /* * linux_pmax_idle(): * * s: lui rX, hi * lw rX, lo(rX) * nop * bne zr, rX, ... * nop * lw rX, ofs(gp) * nop * beq zr, rX, s * nop */ X(linux_pmax_idle) { uint32_t addr, addr2, pageindex, pageindex2, i, i2; int32_t *page, *page2; reg(ic[0].arg[0]) = (int32_t)ic[0].arg[1]; addr = reg(ic[0].arg[0]) + (int32_t)ic[1].arg[2]; pageindex = addr >> 12; i = (addr & 0xfff) >> 2; page = (int32_t *) cpu->cd.mips.host_load[pageindex]; addr2 = reg(ic[5].arg[1]) + (int32_t)ic[5].arg[2]; pageindex2 = addr2 >> 12; i2 = (addr2 & 0xfff) >> 2; page2 = (int32_t *) cpu->cd.mips.host_load[pageindex2]; /* Fallback: */ if (cpu->delay_slot || page == NULL || page[i] != 0 || page2[i2] != 0) return; instr(idle)(cpu, ic); } /* * netbsd_strlen(): * * lb rV,0(rX) * s: addiu rX,rX,1 * bne zr,rV,s * nop */ X(netbsd_strlen) { MODE_uint_t rx = reg(ic[0].arg[1]); MODE_int_t rv; signed char *page; uint32_t pageindex = rx >> 12; int i; page = (signed char *) cpu->cd.mips.host_load[pageindex]; /* Fallback: */ if (cpu->delay_slot || page == NULL) { /* * Normal lb: NOTE: It doesn't matter whether [1] or * [16+1] is called here, because endianness for 8-bit * loads is irrelevant. :-) */ mips32_loadstore[1](cpu, ic); return; } i = rx & 0xfff; /* * TODO: This loop can be optimized further for optimal * performance on the host, e.g. by reading full words... */ do { rv = page[i ++]; } while (i < 0x1000 && rv != 0); cpu->n_translated_instrs += (i - (rx & 0xfff)) * 4 - 1; reg(ic[0].arg[1]) = (rx & ~0xfff) + i; reg(ic[2].arg[0]) = rv; /* Done with the loop? Or continue on the next rx page? */ if (rv == 0) cpu->cd.mips.next_ic = ic + 4; else cpu->cd.mips.next_ic = ic; } #endif /* * addiu_bne_samepage_addiu: */ X(addiu_bne_samepage_addiu) { MODE_uint_t rs, rt; if (cpu->delay_slot) { instr(addiu)(cpu, ic); return; } cpu->n_translated_instrs += 2; reg(ic[0].arg[1]) = (int32_t) ((int32_t)reg(ic[0].arg[0]) + (int32_t)ic[0].arg[2]); rs = reg(ic[1].arg[0]); rt = reg(ic[1].arg[1]); reg(ic[2].arg[1]) = (int32_t) ((int32_t)reg(ic[2].arg[0]) + (int32_t)ic[2].arg[2]); if (rs != rt) cpu->cd.mips.next_ic = (struct mips_instr_call *) ic[1].arg[2]; else cpu->cd.mips.next_ic = ic + 3; } /* * xor_andi_sll: */ X(xor_andi_sll) { /* Fallback: */ if (cpu->delay_slot) { instr(xor)(cpu, ic); return; } reg(ic[0].arg[2]) = reg(ic[0].arg[0]) ^ reg(ic[0].arg[1]); reg(ic[1].arg[1]) = reg(ic[1].arg[0]) & (uint32_t)ic[1].arg[2]; reg(ic[2].arg[2]) = (int32_t)(reg(ic[2].arg[0])<<(int32_t)ic[2].arg[1]); cpu->n_translated_instrs += 2; cpu->cd.mips.next_ic = ic + 3; } /* * andi_sll: */ X(andi_sll) { /* Fallback: */ if (cpu->delay_slot) { instr(andi)(cpu, ic); return; } reg(ic[0].arg[1]) = reg(ic[0].arg[0]) & (uint32_t)ic[0].arg[2]; reg(ic[1].arg[2]) = (int32_t)(reg(ic[1].arg[0])<<(int32_t)ic[1].arg[1]); cpu->n_translated_instrs ++; cpu->cd.mips.next_ic = ic + 2; } /* * lui_ori: */ X(lui_ori) { /* Fallback: */ if (cpu->delay_slot) { instr(set)(cpu, ic); return; } reg(ic[0].arg[0]) = (int32_t)ic[0].arg[1]; reg(ic[1].arg[1]) = reg(ic[1].arg[0]) | (uint32_t)ic[1].arg[2]; cpu->n_translated_instrs ++; cpu->cd.mips.next_ic = ic + 2; } /* * lui_addiu: */ X(lui_addiu) { /* Fallback: */ if (cpu->delay_slot) { instr(set)(cpu, ic); return; } reg(ic[0].arg[0]) = (int32_t)ic[0].arg[1]; reg(ic[1].arg[1]) = (int32_t) ((int32_t)reg(ic[1].arg[0]) + (int32_t)ic[1].arg[2]); cpu->n_translated_instrs ++; cpu->cd.mips.next_ic = ic + 2; } /* * b_samepage_addiu: * * Combination of branch within the same page, followed by addiu. */ X(b_samepage_addiu) { reg(ic[1].arg[1]) = (int32_t) ( (int32_t)reg(ic[1].arg[0]) + (int32_t)ic[1].arg[2] ); cpu->n_translated_instrs ++; cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; } /* * b_samepage_daddiu: * * Combination of branch within the same page, followed by daddiu. */ X(b_samepage_daddiu) { *(uint64_t *)ic[1].arg[1] = *(uint64_t *)ic[1].arg[0] + (int32_t)ic[1].arg[2]; cpu->n_translated_instrs ++; cpu->cd.mips.next_ic = (struct mips_instr_call *) ic->arg[2]; } /*****************************************************************************/ X(end_of_page) { /* Update the PC: (offset 0, but on the next page) */ cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (MIPS_IC_ENTRIES_PER_PAGE << MIPS_INSTR_ALIGNMENT_SHIFT); /* end_of_page doesn't count as an executed instruction: */ cpu->n_translated_instrs --; /* * Find the new physpage and update translation pointers. * * Note: This may cause an exception, if e.g. the new page is * not accessible. */ quick_pc_to_pointers(cpu); /* Simple jump to the next page (if we are lucky): */ if (cpu->delay_slot == NOT_DELAYED) return; /* * If we were in a delay slot, and we got an exception while doing * quick_pc_to_pointers, then return. The function which called * end_of_page should handle this case. */ if (cpu->delay_slot == EXCEPTION_IN_DELAY_SLOT) return; /* * Tricky situation; the delay slot is on the next virtual page. * Calling to_be_translated will translate one instruction manually, * execute it, and then discard it. */ /* fatal("[ end_of_page: delay slot across page boundary! ]\n"); */ instr(to_be_translated)(cpu, cpu->cd.mips.next_ic); /* The instruction in the delay slot has now executed. */ /* fatal("[ end_of_page: back from executing the delay slot, %i ]\n", cpu->delay_slot); */ /* Find the physpage etc of the instruction in the delay slot (or, if there was an exception, the exception handler): */ quick_pc_to_pointers(cpu); } X(end_of_page2) { /* Synchronize PC on the _second_ instruction on the next page: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); /* This doesn't count as an executed instruction. */ cpu->n_translated_instrs --; quick_pc_to_pointers(cpu); if (cpu->delay_slot == NOT_DELAYED) return; fatal("end_of_page2: fatal error, we're in a delay slot\n"); exit(1); } /*****************************************************************************/ /* * Combine: Memory fill loop (addiu, bne, sw) * * s: addiu rX,rX,4 * bne rY,rX,s * sw rZ,-4(rX) */ void COMBINE(sw_loop)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) { int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1); /* Only for 32-bit virtual address translation so far. */ if (!cpu->is_32bit) return; if (n_back < 2) return; if (ic[-2].f == instr(addiu) && ic[-2].arg[0] == ic[-2].arg[1] && (int32_t)ic[-2].arg[2] == 4 && ic[-1].f == instr(bne_samepage) && (ic[-1].arg[0] == ic[-2].arg[0] || ic[-1].arg[1] == ic[-2].arg[0]) && ic[-1].arg[0] != ic[-1].arg[1] && ic[-1].arg[2] == (size_t) &ic[-2] && ic[0].arg[0] != ic[0].arg[1] && ic[0].arg[1] == ic[-2].arg[0] && (int32_t)ic[0].arg[2] == -4) { ic[-2].f = instr(sw_loop); } } /* Only for 32-bit virtual address translation so far. */ #ifdef MODE32 /* * Combine: Multiple SW in a row using the same base register * * sw r?,???(rX) * sw r?,???(rX) * sw r?,???(rX) * ... */ void COMBINE(multi_sw)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) { int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1); if (n_back < 3) return; /* Convert a multi_sw_3 to a multi_sw_4: */ if ((ic[-3].f == instr(multi_sw_3_be) || ic[-3].f == instr(multi_sw_3_le)) && ic[-3].arg[1] == ic[0].arg[1]) { if (cpu->byte_order == EMUL_LITTLE_ENDIAN) ic[-3].f = instr(multi_sw_4_le); else ic[-3].f = instr(multi_sw_4_be); } /* Convert a multi_sw_2 to a multi_sw_3: */ if ((ic[-2].f == instr(multi_sw_2_be) || ic[-2].f == instr(multi_sw_2_le)) && ic[-2].arg[1] == ic[0].arg[1]) { if (cpu->byte_order == EMUL_LITTLE_ENDIAN) ic[-2].f = instr(multi_sw_3_le); else ic[-2].f = instr(multi_sw_3_be); } if (ic[-1].f == ic[0].f && ic[-1].arg[1] == ic[0].arg[1]) { if (cpu->byte_order == EMUL_LITTLE_ENDIAN) ic[-1].f = instr(multi_sw_2_le); else ic[-1].f = instr(multi_sw_2_be); } } #endif /* Only for 32-bit virtual address translation so far. */ #ifdef MODE32 /* * Combine: Multiple LW in a row using the same base register * * lw r?,???(rX) * lw r?,???(rX) * lw r?,???(rX) * ... */ void COMBINE(multi_lw)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) { int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1); if (n_back < 3) return; /* Convert a multi_lw_3 to a multi_lw_4: */ if ((ic[-3].f == instr(multi_lw_3_be) || ic[-3].f == instr(multi_lw_3_le)) && ic[-3].arg[1] == ic[0].arg[1] && ic[-1].arg[0] != ic[0].arg[1]) { if (cpu->byte_order == EMUL_LITTLE_ENDIAN) ic[-3].f = instr(multi_lw_4_le); else ic[-3].f = instr(multi_lw_4_be); } /* Convert a multi_lw_2 to a multi_lw_3: */ if ((ic[-2].f == instr(multi_lw_2_be) || ic[-2].f == instr(multi_lw_2_le)) && ic[-2].arg[1] == ic[0].arg[1] && ic[-1].arg[0] != ic[0].arg[1]) { if (cpu->byte_order == EMUL_LITTLE_ENDIAN) ic[-2].f = instr(multi_lw_3_le); else ic[-2].f = instr(multi_lw_3_be); } /* Note: Loads to the base register are not allowed in slot -1. */ if (ic[-1].f == ic[0].f && ic[-1].arg[1] == ic[0].arg[1] && ic[-1].arg[0] != ic[0].arg[1]) { if (cpu->byte_order == EMUL_LITTLE_ENDIAN) ic[-1].f = instr(multi_lw_2_le); else ic[-1].f = instr(multi_lw_2_be); } } #endif /* * Combine: NetBSD/pmax 3.0 R2000/R3000 physical cache invalidation loop * * Instruction cache loop: * * ic[-8] mtc0 rV,status * -7 nop * -6 nop * -5 s: addiu rX,rX,4 * -4 bne rY,rX,s * -3 sb zr,-4(rX) * -2 nop * -1 nop * 0 mtc0 rT,status */ void COMBINE(netbsd_r3k_cache_inv)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) { int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1); if (n_back < 8) return; if (ic[-8].f == instr(mtc0) && ic[-8].arg[1] == COP0_STATUS && ic[-7].f == instr(nop) && ic[-6].f == instr(nop) && ic[-5].f == instr(addiu) && ic[-5].arg[0] == ic[-5].arg[1] && (int32_t)ic[-5].arg[2] == 4 && ic[-4].f == instr(bne_samepage) && ic[-4].arg[0] == ic[-5].arg[0] && ic[-4].arg[0] != ic[-4].arg[1] && ic[-4].arg[2] == (size_t) &ic[-5] && ic[-3].arg[1] == ic[-5].arg[0] && ic[-2].f == instr(nop) && ic[-1].f == instr(nop)) { ic[-8].f = instr(netbsd_r3k_picache_do_inv); } } /* * Combine: something ending with a nop. * * NetBSD's strlen core. * [Conditional] branch, followed by nop. * NetBSD/pmax' idle loop (and possibly others as well). * Linux/pmax' idle loop. */ void COMBINE(nop)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) { int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1); if (n_back < 8) return; #ifdef MODE32 if (ic[-8].f == instr(set) && ic[-7].f == mips32_loadstore[4 + 1] && ic[-7].arg[0] == ic[-1].arg[0] && ic[-7].arg[0] == ic[-3].arg[0] && ic[-7].arg[0] == ic[-5].arg[0] && ic[-7].arg[0] == ic[-7].arg[1] && ic[-7].arg[0] == ic[-8].arg[0] && ic[-6].f == instr(nop) && ic[-5].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && ic[-5].f == instr(bne_samepage_nop) && ic[-4].f == instr(nop) && ic[-3].f == mips32_loadstore[4 + 1] && ic[-2].f == instr(nop) && ic[-1].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && ic[-1].arg[2] == (size_t) &ic[-8] && ic[-1].f == instr(beq_samepage)) { ic[-8].f = instr(linux_pmax_idle); return; } if (ic[-4].f == instr(set) && ic[-3].f == mips32_loadstore[4 + 1] && ic[-3].arg[0] == ic[-1].arg[0] && ic[-3].arg[1] == ic[-4].arg[0] && ic[-2].f == instr(nop) && ic[-1].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && ic[-1].arg[2] == (size_t) &ic[-4] && ic[-1].f == instr(beq_samepage)) { ic[-4].f = instr(netbsd_pmax_idle); return; } if ((ic[-3].f == mips32_loadstore[1] || ic[-3].f == mips32_loadstore[16 + 1]) && ic[-3].arg[2] == 0 && ic[-3].arg[0] == ic[-1].arg[0] && ic[-3].arg[1] == ic[-2].arg[0] && ic[-2].arg[0] == ic[-2].arg[1] && ic[-2].arg[2] == 1 && ic[-2].f == instr(addiu) && ic[-1].arg[2] == (size_t) &ic[-3] && ic[-1].arg[1] == (size_t) &cpu->cd.mips.gpr[MIPS_GPR_ZERO] && ic[-1].f == instr(bne_samepage)) { ic[-3].f = instr(netbsd_strlen); return; } #endif if (ic[-1].f == instr(bne_samepage)) { ic[-1].f = instr(bne_samepage_nop); return; } if (ic[-1].f == instr(beq_samepage)) { ic[-1].f = instr(beq_samepage_nop); return; } /* TODO: other branches that are followed by nop should be here */ } /* * Combine: * * xor + andi + sll * andi + sll */ void COMBINE(sll)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) { int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1); if (n_back < 2) return; if (ic[-2].f == instr(xor) && ic[-1].f == instr(andi)) { ic[-2].f = instr(xor_andi_sll); return; } if (ic[-1].f == instr(andi)) { ic[-1].f = instr(andi_sll); return; } } /* * lui + ori */ void COMBINE(ori)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) { int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1); if (n_back < 1) return; if (ic[-1].f == instr(set)) { ic[-1].f = instr(lui_ori); return; } } /* * addu + addu + addu */ void COMBINE(addu)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) { int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1); if (n_back < 4) return; /* Avoid "overlapping" instruction combinations: */ if (ic[-4].f == instr(multi_addu_3) || ic[-3].f == instr(multi_addu_3)) return; if (ic[-2].f == instr(addu) && ic[-1].f == instr(addu)) { ic[-2].f = instr(multi_addu_3); return; } } /* * Combine: * * [Conditional] branch, followed by addiu. */ void COMBINE(addiu)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) { int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1); if (n_back < 2) return; if (ic[-2].f == instr(addiu) && ic[-1].f == instr(bne_samepage)) { ic[-2].f = instr(addiu_bne_samepage_addiu); return; } if (ic[-1].f == instr(set)) { ic[-1].f = instr(lui_addiu); return; } if (ic[-1].f == instr(b_samepage)) { ic[-1].f = instr(b_samepage_addiu); return; } if (ic[-1].f == instr(beq_samepage)) { ic[-1].f = instr(beq_samepage_addiu); return; } if (ic[-1].f == instr(bne_samepage)) { ic[-1].f = instr(bne_samepage_addiu); return; } if (ic[-1].f == instr(jr_ra)) { ic[-1].f = instr(jr_ra_addiu); return; } /* TODO: other branches that are followed by addiu should be here */ } /* * Combine: [Conditional] branch, followed by daddiu. */ void COMBINE(b_daddiu)(struct cpu *cpu, struct mips_instr_call *ic, int low_addr) { int n_back = (low_addr >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1); if (n_back < 1) return; if (ic[-1].f == instr(b_samepage)) { ic[-1].f = instr(b_samepage_daddiu); } /* TODO: other branches that are followed by daddiu should be here */ } /*****************************************************************************/ /* * mips_instr_to_be_translated(): * * Translate an instruction word into a mips_instr_call. ic is filled in with * valid data for the translated instruction, or a "nothing" instruction if * there was a translation failure. The newly translated instruction is then * executed. */ X(to_be_translated) { uint64_t addr, low_pc; uint32_t iword, imm; unsigned char *page; unsigned char ib[4]; int main_opcode, rt, rs, rd, sa, s6, x64 = 0, s10; int in_crosspage_delayslot = 0; void (*samepage_function)(struct cpu *, struct mips_instr_call *); int store, signedness, size; /* Figure out the (virtual) address of the instruction: */ low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); /* Special case for branch with delayslot on the next page: */ if (cpu->delay_slot == TO_BE_DELAYED && low_pc == 0) { /* fatal("[ delay-slot translation across page " "boundary ]\n"); */ in_crosspage_delayslot = 1; } addr = cpu->pc & ~((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT); addr += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); cpu->pc = (MODE_int_t)addr; addr &= ~((1 << MIPS_INSTR_ALIGNMENT_SHIFT) - 1); /* Read the instruction word from memory: */ #ifdef MODE32 page = cpu->cd.mips.host_load[(uint32_t)addr >> 12]; #else { const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; uint32_t x1 = (addr >> (64-DYNTRANS_L1N)) & mask1; uint32_t x2 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; uint32_t x3 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N- DYNTRANS_L3N)) & mask3; struct DYNTRANS_L2_64_TABLE *l2 = cpu->cd.mips.l1_64[x1]; struct DYNTRANS_L3_64_TABLE *l3 = l2->l3[x2]; page = l3->host_load[x3]; } #endif if (page != NULL) { /* fatal("TRANSLATION HIT!\n"); */ memcpy(ib, page + (addr & 0xffc), sizeof(ib)); } else { /* fatal("TRANSLATION MISS!\n"); */ if (!cpu->memory_rw(cpu, cpu->mem, addr, ib, sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) { fatal("to_be_translated(): read failed: TODO\n"); goto bad; } } { uint32_t *p = (uint32_t *) ib; iword = *p; } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) iword = LE32_TO_HOST(iword); else iword = BE32_TO_HOST(iword); #define DYNTRANS_TO_BE_TRANSLATED_HEAD #include "cpu_dyntrans.cc" #undef DYNTRANS_TO_BE_TRANSLATED_HEAD /* * Translate the instruction: * * NOTE: _NEVER_ allow writes to the zero register; all instructions * that use the zero register as their destination should be treated * as NOPs, except those that access memory (they should use the * scratch register instead). */ main_opcode = iword >> 26; rs = (iword >> 21) & 31; rt = (iword >> 16) & 31; rd = (iword >> 11) & 31; sa = (iword >> 6) & 31; imm = (int16_t)iword; s6 = iword & 63; s10 = (rs << 5) | sa; switch (main_opcode) { case HI6_SPECIAL: switch (s6) { case SPECIAL_SLL: case SPECIAL_SLLV: case SPECIAL_SRL: case SPECIAL_SRLV: case SPECIAL_SRA: case SPECIAL_SRAV: case SPECIAL_DSRL: case SPECIAL_DSRLV: case SPECIAL_DSRL32: case SPECIAL_DSLL: case SPECIAL_DSLLV: case SPECIAL_DSLL32: case SPECIAL_DSRA: case SPECIAL_DSRAV: case SPECIAL_DSRA32: switch (s6) { case SPECIAL_SLL: ic->f = instr(sll); break; case SPECIAL_SLLV: ic->f = instr(sllv); sa = -1; break; case SPECIAL_SRL: ic->f = instr(srl); break; case SPECIAL_SRLV: ic->f = instr(srlv); sa = -1; break; case SPECIAL_SRA: ic->f = instr(sra); break; case SPECIAL_SRAV: ic->f = instr(srav); sa = -1; break; case SPECIAL_DSRL: ic->f = instr(dsrl); x64=1; break; case SPECIAL_DSRLV:ic->f = instr(dsrlv); x64 = 1; sa = -1; break; case SPECIAL_DSRL32:ic->f= instr(dsrl); x64=1; sa += 32; break; case SPECIAL_DSLL: ic->f = instr(dsll); x64=1; break; case SPECIAL_DSLLV:ic->f = instr(dsllv); x64 = 1; sa = -1; break; case SPECIAL_DSLL32:ic->f= instr(dsll); x64=1; sa += 32; break; case SPECIAL_DSRA: ic->f = instr(dsra); x64=1; break; case SPECIAL_DSRAV:ic->f = instr(dsrav); x64 = 1; sa = -1; break; case SPECIAL_DSRA32:ic->f = instr(dsra); x64=1; sa += 32; break; } ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; if (sa >= 0) ic->arg[1] = sa; else ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[2] = (size_t)&cpu->cd.mips.gpr[rd]; /* Special checks for MIPS32/64 revision 2 opcodes, such as rotation instructions: */ if (sa >= 0 && rs != 0x00) { if (cpu->cd.mips.cpu_type.isa_level < 32 || cpu->cd.mips.cpu_type.isa_revision < 2) { static int warning_rotate = 0; if (!warning_rotate && !cpu->translation_readahead) { fatal("[ WARNING! MIPS32/64 " "revision 2 rotate opcode" " used, but the %s process" "or does not implement " "such instructions. Only " "printing this " "warning once. ]\n", cpu->cd.mips.cpu_type.name); warning_rotate = 1; } ic->f = instr(reserved); break; } switch (rs) { case 0x01: switch (s6) { case SPECIAL_SRL: /* ror (aka. rotr?) */ ic->f = instr(ror); break; default:goto bad; } break; default:goto bad; } } if (sa < 0 && (s10 & 0x1f) != 0) { int orig_sa = (iword >> 6) & 31; switch (s6) { case SPECIAL_SRLV: /* rorv (aka. rotrv?) */ if (orig_sa == 0x01) { ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; ic->f = instr(rorv); } break; default:goto bad; } break; } if (rd == MIPS_GPR_ZERO) ic->f = instr(nop); if (ic->f == instr(sll)) cpu->cd.mips.combination_check = COMBINE(sll); if (ic->f == instr(nop)) cpu->cd.mips.combination_check = COMBINE(nop); break; case SPECIAL_ADD: case SPECIAL_ADDU: case SPECIAL_SUB: case SPECIAL_SUBU: case SPECIAL_DADD: case SPECIAL_DADDU: case SPECIAL_DSUB: case SPECIAL_DSUBU: case SPECIAL_SLT: case SPECIAL_SLTU: case SPECIAL_AND: case SPECIAL_OR: case SPECIAL_XOR: case SPECIAL_NOR: case SPECIAL_MOVN: case SPECIAL_MOVZ: case SPECIAL_MFHI: case SPECIAL_MFLO: case SPECIAL_MTHI: case SPECIAL_MTLO: case SPECIAL_DIV: case SPECIAL_DIVU: case SPECIAL_DDIV: case SPECIAL_DDIVU: case SPECIAL_MULT: case SPECIAL_MULTU: case SPECIAL_DMULT: case SPECIAL_DMULTU: case SPECIAL_TGE: case SPECIAL_TGEU: case SPECIAL_TLT: case SPECIAL_TLTU: case SPECIAL_TEQ: case SPECIAL_TNE: switch (s6) { case SPECIAL_ADD: ic->f = instr(add); break; case SPECIAL_ADDU: ic->f = instr(addu); break; case SPECIAL_SUB: ic->f = instr(sub); break; case SPECIAL_SUBU: ic->f = instr(subu); break; case SPECIAL_DADD: ic->f = instr(dadd); x64=1; break; case SPECIAL_DADDU: ic->f = instr(daddu); x64=1; break; case SPECIAL_DSUB: ic->f = instr(dsub); x64=1; break; case SPECIAL_DSUBU: ic->f = instr(dsubu); x64=1; break; case SPECIAL_SLT: ic->f = instr(slt); break; case SPECIAL_SLTU: ic->f = instr(sltu); break; case SPECIAL_AND: ic->f = instr(and); break; case SPECIAL_OR: ic->f = instr(or); break; case SPECIAL_XOR: ic->f = instr(xor); break; case SPECIAL_NOR: ic->f = instr(nor); break; case SPECIAL_MFHI: ic->f = instr(mov); break; case SPECIAL_MFLO: ic->f = instr(mov); break; case SPECIAL_MTHI: ic->f = instr(mov); break; case SPECIAL_MTLO: ic->f = instr(mov); break; case SPECIAL_DIV: ic->f = instr(div); break; case SPECIAL_DIVU: ic->f = instr(divu); break; case SPECIAL_DDIV: ic->f = instr(ddiv); x64=1; break; case SPECIAL_DDIVU: ic->f = instr(ddivu); x64=1; break; case SPECIAL_MULT : ic->f = instr(mult); break; case SPECIAL_MULTU: ic->f = instr(multu); break; case SPECIAL_DMULT: ic->f = instr(dmult); x64=1; break; case SPECIAL_DMULTU:ic->f = instr(dmultu); x64=1; break; case SPECIAL_TGE: ic->f = instr(tge); break; case SPECIAL_TGEU: ic->f = instr(tgeu); break; case SPECIAL_TLT: ic->f = instr(tlt); break; case SPECIAL_TLTU: ic->f = instr(tltu); break; case SPECIAL_TEQ: ic->f = instr(teq); break; case SPECIAL_TNE: ic->f = instr(tne); break; case SPECIAL_MOVN: ic->f = instr(movn); break; case SPECIAL_MOVZ: ic->f = instr(movz); break; } ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[2] = (size_t)&cpu->cd.mips.gpr[rd]; switch (s6) { case SPECIAL_MFHI: ic->arg[0] = (size_t)&cpu->cd.mips.hi; break; case SPECIAL_MFLO: ic->arg[0] = (size_t)&cpu->cd.mips.lo; break; case SPECIAL_MTHI: ic->arg[2] = (size_t)&cpu->cd.mips.hi; break; case SPECIAL_MTLO: ic->arg[2] = (size_t)&cpu->cd.mips.lo; break; } /* Special cases for rd: */ switch (s6) { case SPECIAL_MTHI: case SPECIAL_MTLO: case SPECIAL_DIV: case SPECIAL_DIVU: case SPECIAL_DDIV: case SPECIAL_DDIVU: case SPECIAL_MULT: case SPECIAL_MULTU: case SPECIAL_DMULT: case SPECIAL_DMULTU: if (s6 == SPECIAL_MULT && rd != MIPS_GPR_ZERO) { if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { ic->f = instr(mult_r5900); break; } break; } if (s6 == SPECIAL_MULTU && rd!=MIPS_GPR_ZERO) { if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { ic->f = instr(multu_r5900); break; } } if (rd != MIPS_GPR_ZERO) { if (!cpu->translation_readahead) fatal("TODO: rd NON-zero\n"); goto bad; } /* These instructions don't use rd. */ break; case SPECIAL_TGE: case SPECIAL_TGEU: case SPECIAL_TLT: case SPECIAL_TLTU: case SPECIAL_TEQ: case SPECIAL_TNE: /* In these instructions, rd is a 'code', only read by trap handling software. */ break; default:if (rd == MIPS_GPR_ZERO) ic->f = instr(nop); } if (ic->f == instr(addu)) cpu->cd.mips.combination_check = COMBINE(addu); break; case SPECIAL_JR: case SPECIAL_JALR: ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rd]; if (s6 == SPECIAL_JALR && rd == MIPS_GPR_ZERO) s6 = SPECIAL_JR; ic->arg[2] = (addr & 0xffc) + 8; switch (s6) { case SPECIAL_JR: if (rs == MIPS_GPR_RA) { if (cpu->machine->show_trace_tree) ic->f = instr(jr_ra_trace); else ic->f = instr(jr_ra); } else { ic->f = instr(jr); } if (cpu->translation_readahead > 2) cpu->translation_readahead = 2; break; case SPECIAL_JALR: if (cpu->machine->show_trace_tree) ic->f = instr(jalr_trace); else ic->f = instr(jalr); break; } if (cpu->delay_slot) { if (!cpu->translation_readahead) fatal("TODO: branch in delay " "slot? (1)\n"); goto bad; } break; case SPECIAL_SYSCALL: if (((iword >> 6) & 0xfffff) == 0x30378) { /* "Magic trap" for PROM emulation: */ ic->f = instr(promemul); } else { ic->f = instr(syscall); } break; case SPECIAL_BREAK: if (((iword >> 6) & 0xfffff) == 0x30378) { /* "Magic trap" for REBOOT: */ ic->f = instr(reboot); } else { ic->f = instr(break); } break; case SPECIAL_SYNC: ic->f = instr(nop); break; default:goto bad; } break; case HI6_BEQ: case HI6_BNE: case HI6_BEQL: case HI6_BNEL: case HI6_BLEZ: case HI6_BLEZL: case HI6_BGTZ: case HI6_BGTZL: samepage_function = NULL; /* get rid of a compiler warning */ switch (main_opcode) { case HI6_BEQ: ic->f = instr(beq); samepage_function = instr(beq_samepage); /* Special case: comparing a register with itself: */ if (rs == rt) { ic->f = instr(b); samepage_function = instr(b_samepage); } break; case HI6_BNE: ic->f = instr(bne); samepage_function = instr(bne_samepage); break; case HI6_BEQL: ic->f = instr(beql); samepage_function = instr(beql_samepage); /* Special case: comparing a register with itself: */ if (rs == rt) { ic->f = instr(b); samepage_function = instr(b_samepage); } break; case HI6_BNEL: ic->f = instr(bnel); samepage_function = instr(bnel_samepage); break; case HI6_BLEZ: ic->f = instr(blez); samepage_function = instr(blez_samepage); break; case HI6_BLEZL: ic->f = instr(blezl); samepage_function = instr(blezl_samepage); break; case HI6_BGTZ: ic->f = instr(bgtz); samepage_function = instr(bgtz_samepage); break; case HI6_BGTZL: ic->f = instr(bgtzl); samepage_function = instr(bgtzl_samepage); break; } ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[2] = (int32_t) ( (imm << MIPS_INSTR_ALIGNMENT_SHIFT) + (addr & 0xffc) + 4 ); /* Is the offset from the start of the current page still within the same page? Then use the samepage_function: */ if ((uint32_t)ic->arg[2] < ((MIPS_IC_ENTRIES_PER_PAGE - 1) << MIPS_INSTR_ALIGNMENT_SHIFT) && (addr & 0xffc) < 0xffc) { ic->arg[2] = (size_t) (cpu->cd.mips.cur_ic_page + ((ic->arg[2] >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1))); ic->f = samepage_function; } if (cpu->delay_slot) { if (!cpu->translation_readahead) fatal("TODO: branch in delay slot? (2)\n"); goto bad; } break; case HI6_ADDI: case HI6_ADDIU: case HI6_SLTI: case HI6_SLTIU: case HI6_DADDI: case HI6_DADDIU: case HI6_ANDI: case HI6_ORI: case HI6_XORI: ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rt]; if (main_opcode == HI6_ADDI || main_opcode == HI6_ADDIU || main_opcode == HI6_SLTI || main_opcode == HI6_SLTIU || main_opcode == HI6_DADDI || main_opcode == HI6_DADDIU) ic->arg[2] = (int16_t)iword; else ic->arg[2] = (uint16_t)iword; switch (main_opcode) { case HI6_ADDI: ic->f = instr(addi); break; case HI6_ADDIU: ic->f = instr(addiu); break; case HI6_SLTI: ic->f = instr(slti); break; case HI6_SLTIU: ic->f = instr(sltiu); break; case HI6_DADDI: ic->f = instr(daddi); x64 = 1; break; case HI6_DADDIU: ic->f = instr(daddiu); x64 = 1; break; case HI6_ANDI: ic->f = instr(andi); break; case HI6_ORI: ic->f = instr(ori); break; case HI6_XORI: ic->f = instr(xori); break; } if (ic->arg[2] == 0) { if ((cpu->is_32bit && ic->f == instr(addiu)) || (!cpu->is_32bit && ic->f == instr(daddiu))) { ic->f = instr(mov); ic->arg[2] = ic->arg[1]; } } if (rt == MIPS_GPR_ZERO) ic->f = instr(nop); if (ic->f == instr(ori)) cpu->cd.mips.combination_check = COMBINE(ori); if (ic->f == instr(addiu)) cpu->cd.mips.combination_check = COMBINE(addiu); if (ic->f == instr(daddiu)) cpu->cd.mips.combination_check = COMBINE(b_daddiu); break; case HI6_LUI: ic->f = instr(set); ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[1] = (int32_t) (imm << 16); /* NOTE: Don't use arg[2] here. It can be used with instruction combinations, to do lui + addiu, etc. */ if (rt == MIPS_GPR_ZERO) ic->f = instr(nop); break; case HI6_J: case HI6_JAL: switch (main_opcode) { case HI6_J: ic->f = instr(j); if (cpu->translation_readahead > 2) cpu->translation_readahead = 2; break; case HI6_JAL: if (cpu->machine->show_trace_tree) ic->f = instr(jal_trace); else ic->f = instr(jal); break; } ic->arg[0] = (iword & 0x03ffffff) << 2; ic->arg[1] = (addr & 0xffc) + 8; if (cpu->delay_slot) { if (!cpu->translation_readahead) fatal("TODO: branch in delay slot (=%i)? (3);" " addr=%016" PRIx64" iword=%08" PRIx32"\n", cpu->delay_slot, (uint64_t)addr, iword); goto bad; } break; case HI6_COP0: /* TODO: Is checking bit 25 enough, or perhaps all bits 25..21 must be checked? */ if ((iword >> 25) & 1) { ic->arg[2] = addr & 0xffc; switch (iword & 0xff) { case COP0_TLBR: ic->f = instr(tlbr); break; case COP0_TLBWI: case COP0_TLBWR: ic->f = instr(tlbw); ic->arg[0] = (iword & 0xff) == COP0_TLBWR; break; case COP0_TLBP: ic->f = instr(tlbp); break; case COP0_RFE: ic->f = instr(rfe); break; case COP0_ERET: ic->f = instr(eret); break; case COP0_DERET: ic->f = instr(deret); break; case COP0_WAIT: ic->f = instr(wait); if (cpu->cd.mips.cpu_type.rev != MIPS_RM5200 && cpu->cd.mips.cpu_type.isa_level < 32) { static int warned = 0; ic->f = instr(reserved); if (!warned && !cpu->translation_readahead) { fatal("{ WARNING: Attempt to " "execute the WAIT instruct" "ion, but the emulated CPU " "is neither RM52xx, nor " "MIPS32/64! }\n"); warned = 1; } } break; case COP0_STANDBY: /* NOTE: Reusing the 'wait' instruction: */ ic->f = instr(wait); if (cpu->cd.mips.cpu_type.rev != MIPS_R4100) { static int warned = 0; ic->f = instr(reserved); if (!warned && !cpu->translation_readahead) { fatal("{ WARNING: Attempt to " "execute a R41xx instruct" "ion, but the emulated CPU " "doesn't support it! }\n"); warned = 1; } } break; case COP0_HIBERNATE: /* TODO */ goto bad; case COP0_SUSPEND: /* Used by NetBSD on HPCmips (VR41xx) to halt the machine. */ ic->f = instr(reboot); break; case COP0_EI: if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { ic->f = instr(ei_r5900); } else goto bad; break; case COP0_DI: if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { ic->f = instr(di_r5900); } else goto bad; break; default:if (!cpu->translation_readahead) fatal("UNIMPLEMENTED cop0 (func " "0x%02x)\n", iword & 0xff); goto bad; } break; } /* rs contains the coprocessor opcode! */ switch (rs) { case COPz_CFCz: ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[1] = rd + ((iword & 7) << 5); ic->arg[2] = addr & 0xffc; ic->f = instr(cfc0); if (rt == MIPS_GPR_ZERO) ic->f = instr(nop); break; case COPz_MFCz: case COPz_DMFCz: ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[1] = rd + ((iword & 7) << 5); ic->arg[2] = addr & 0xffc; ic->f = rs == COPz_MFCz? instr(mfc0) : instr(dmfc0); if (rs == COPz_MFCz && (iword & 7) == 0 && rd != COP0_COUNT) ic->f = instr(mfc0_select0); if (rs == COPz_DMFCz && (iword & 7) == 0 && rd != COP0_COUNT) ic->f = instr(dmfc0_select0); if (rt == MIPS_GPR_ZERO) ic->f = instr(nop); break; case COPz_MTCz: case COPz_DMTCz: ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[1] = rd + ((iword & 7) << 5); ic->arg[2] = addr & 0xffc; ic->f = rs == COPz_MTCz? instr(mtc0) : instr(dmtc0); if (cpu->cd.mips.cpu_type.exc_model == EXC3K && rs == COPz_MTCz && rd == COP0_STATUS) cpu->cd.mips.combination_check = COMBINE(netbsd_r3k_cache_inv); break; case COPz_MFMCz: if ((iword & 0xffdf) == 0x6000) { /* MIPS32/64 rev 2 "ei" or "di": */ if (cpu->cd.mips.cpu_type.isa_level < 32 || cpu->cd.mips.cpu_type.isa_revision < 2) { static int warning_ei_di = 0; if (!warning_ei_di && !cpu->translation_readahead) { fatal("[ WARNING! MIPS32/64 " "revision 2 di or ei opcode" " used, but the %s process" "or does not implement " "such instructions. Only " "printing this " "warning once. ]\n", cpu->cd.mips.cpu_type.name); warning_ei_di = 1; } ic->f = instr(reserved); break; } ic->f = instr(ei_or_di); ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; if (rt == MIPS_GPR_ZERO) ic->arg[0] = (size_t)&cpu->cd.mips.scratch; ic->arg[1] = iword & 0x20; } else { if (!cpu->translation_readahead) fatal("Unimplemented COP0_MFMCz\n"); goto bad; } break; case COPz_BCzc: if (iword == 0x4100ffff) { /* R2020 DECstation write-loop thingy. */ ic->f = instr(nop); } else { if (!cpu->translation_readahead) fatal("Unimplemented COP0_BCzc\n"); goto bad; } break; default:if (!cpu->translation_readahead) fatal("UNIMPLEMENTED cop0 (rs = %i)\n", rs); goto bad; } break; case HI6_COP1: /* Always cause a coprocessor unusable exception if there is no floating point coprocessor: */ if (cpu->cd.mips.cpu_type.flags & NOFPU || cpu->cd.mips.coproc[1] == NULL) { ic->f = instr(cpu); ic->arg[0] = 1; break; } /* Bits 25..21 are floating point main opcode: */ switch (rs) { case COPz_BCzc: /* Conditional branch: */ /* TODO: Reimplement this in a faster way. */ ic->f = instr(cop1_bc); ic->arg[0] = (iword >> 18) & 7; /* cc */ ic->arg[1] = (iword >> 16) & 3; /* nd, tf bits */ ic->arg[2] = (int32_t) ((imm << MIPS_INSTR_ALIGNMENT_SHIFT) + (addr & 0xffc) + 4); if (cpu->delay_slot) { if (!cpu->translation_readahead) fatal("TODO: branch in delay slot 4\n"); goto bad; } if (cpu->cd.mips.cpu_type.isa_level <= 3 && ic->arg[0] != 0) { if (!cpu->translation_readahead) fatal("Attempt to execute a non-cc-0 " "BC* instruction on an isa level " "%i cpu. TODO: How should this be " "handled?\n", cpu->cd.mips.cpu_type.isa_level); goto bad; } break; case COPz_DMFCz: case COPz_DMTCz: x64 = 1; /* FALL-THROUGH */ case COP1_FMT_S: case COP1_FMT_D: case COP1_FMT_W: case COP1_FMT_L: case COP1_FMT_PS: case COPz_CFCz: case COPz_CTCz: case COPz_MFCz: case COPz_MTCz: /* Fallback to slow pre-dyntrans code, for now. */ /* TODO: Fix/optimize/rewrite. */ ic->f = instr(cop1_slow); ic->arg[0] = (uint32_t)iword & ((1 << 26) - 1); break; default:if (!cpu->translation_readahead) fatal("COP1 floating point opcode = 0x%02x\n", rs); goto bad; } break; case HI6_COP2: /* Always cause a coprocessor unusable exception if there is no coprocessor 2: */ if (cpu->cd.mips.coproc[2] == NULL) { ic->f = instr(cpu); ic->arg[0] = 2; break; } if (!cpu->translation_readahead) fatal("COP2 functionality not yet implemented\n"); goto bad; break; case HI6_COP3: /* Always cause a coprocessor unusable exception if there is no coprocessor 3: */ if (cpu->cd.mips.coproc[3] == NULL) { ic->f = instr(cpu); ic->arg[0] = 3; break; } if (iword == 0x4d00ffff) { /* R2020 writeback thing, used by e.g. NetBSD/pmax on MIPSMATE. */ ic->f = instr(nop); } else { if (!cpu->translation_readahead) fatal("COP3 iword=0x%08x\n", iword); goto bad; } break; case HI6_SPECIAL2: if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { /* R5900, TX79/C790, have MMI instead of SPECIAL2: */ int mmi_subopcode = (iword >> 6) & 0x1f; switch (s6) { case MMI_MADD: ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[2] = (size_t)&cpu->cd.mips.gpr[rd]; if (rd == MIPS_GPR_ZERO) ic->f = instr(madd); else ic->f = instr(madd_rd); break; case MMI_MADDU: ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[2] = (size_t)&cpu->cd.mips.gpr[rd]; if (rd == MIPS_GPR_ZERO) ic->f = instr(maddu); else ic->f = instr(maddu_rd); break; case MMI_MMI0: switch (mmi_subopcode) { case MMI0_PEXTLW: ic->arg[0] = rs; ic->arg[1] = rt; ic->arg[2] = rd; if (rd == MIPS_GPR_ZERO) ic->f = instr(nop); else ic->f = instr(pextlw); break; default:goto bad; } break; case MMI_MMI3: switch (mmi_subopcode) { case MMI3_POR: ic->arg[0] = rs; ic->arg[1] = rt; ic->arg[2] = rd; if (rd == MIPS_GPR_ZERO) ic->f = instr(nop); else ic->f = instr(por); break; default:goto bad; } break; default:goto bad; } break; } /* TODO: is this correct? Or are there other non-MIPS32/64 MIPS processors that have support for SPECIAL2 opcodes? */ if (cpu->cd.mips.cpu_type.isa_level < 32) { ic->f = instr(reserved); break; } /* SPECIAL2: */ switch (s6) { case SPECIAL2_MADD: case SPECIAL2_MADDU: case SPECIAL2_MSUB: case SPECIAL2_MSUBU: ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rt]; switch (s6) { case SPECIAL2_MADD: ic->f = instr(madd); break; case SPECIAL2_MADDU:ic->f = instr(maddu); break; case SPECIAL2_MSUB: ic->f = instr(msub); break; case SPECIAL2_MSUBU:ic->f = instr(msubu); break; } break; case SPECIAL2_MUL: ic->f = instr(mul); ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[2] = (size_t)&cpu->cd.mips.gpr[rd]; if (rd == MIPS_GPR_ZERO) ic->f = instr(nop); break; case SPECIAL2_CLZ: case SPECIAL2_CLO: case SPECIAL2_DCLZ: case SPECIAL2_DCLO: switch (s6) { case SPECIAL2_CLZ: ic->f = instr(clz); break; case SPECIAL2_CLO: ic->f = instr(clo); break; case SPECIAL2_DCLZ: ic->f = instr(dclz); break; case SPECIAL2_DCLO: ic->f = instr(dclo); break; } ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rd]; if (rd == MIPS_GPR_ZERO) ic->f = instr(nop); break; default:goto bad; } break; case HI6_REGIMM: switch (rt) { case REGIMM_BGEZ: case REGIMM_BGEZL: case REGIMM_BLTZ: case REGIMM_BLTZL: case REGIMM_BGEZAL: case REGIMM_BGEZALL: case REGIMM_BLTZAL: case REGIMM_BLTZALL: samepage_function = NULL; switch (rt) { case REGIMM_BGEZ: ic->f = instr(bgez); samepage_function = instr(bgez_samepage); break; case REGIMM_BGEZL: ic->f = instr(bgezl); samepage_function = instr(bgezl_samepage); break; case REGIMM_BLTZ: ic->f = instr(bltz); samepage_function = instr(bltz_samepage); break; case REGIMM_BLTZL: ic->f = instr(bltzl); samepage_function = instr(bltzl_samepage); break; case REGIMM_BGEZAL: ic->f = instr(bgezal); samepage_function = instr(bgezal_samepage); break; case REGIMM_BGEZALL: ic->f = instr(bgezall); samepage_function = instr(bgezall_samepage); break; case REGIMM_BLTZAL: ic->f = instr(bltzal); samepage_function = instr(bltzal_samepage); break; case REGIMM_BLTZALL: ic->f = instr(bltzall); samepage_function = instr(bltzall_samepage); break; } ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[2] = (imm << MIPS_INSTR_ALIGNMENT_SHIFT) + (addr & 0xffc) + 4; /* Is the offset from the start of the current page still within the same page? Then use the samepage_function: */ if ((uint32_t)ic->arg[2] < ((MIPS_IC_ENTRIES_PER_PAGE-1) << MIPS_INSTR_ALIGNMENT_SHIFT) && (addr & 0xffc) < 0xffc) { ic->arg[2] = (size_t) (cpu->cd.mips.cur_ic_page+ ((ic->arg[2] >> MIPS_INSTR_ALIGNMENT_SHIFT) & (MIPS_IC_ENTRIES_PER_PAGE - 1))); ic->f = samepage_function; } if (cpu->delay_slot) { if (!cpu->translation_readahead) fatal("TODO: branch in delay slot:5\n"); goto bad; } break; default:if (!cpu->translation_readahead) fatal("UNIMPLEMENTED regimm rt=%i\n", rt); goto bad; } break; case HI6_LB: case HI6_LBU: case HI6_SB: case HI6_LH: case HI6_LHU: case HI6_SH: case HI6_LW: case HI6_LWU: case HI6_SW: case HI6_LD: case HI6_SD: /* TODO: LWU should probably also be x64=1? */ size = 2; signedness = 0; store = 0; switch (main_opcode) { case HI6_LB: size = 0; signedness = 1; break; case HI6_LBU: size = 0; break; case HI6_LH: size = 1; signedness = 1; break; case HI6_LHU: size = 1; break; case HI6_LW: signedness = 1; break; case HI6_LWU: break; case HI6_LD: size = 3; x64 = 1; break; case HI6_SB: store = 1; size = 0; break; case HI6_SH: store = 1; size = 1; break; case HI6_SW: store = 1; break; case HI6_SD: store = 1; size = 3; x64 = 1; break; } ic->f = #ifdef MODE32 mips32_loadstore #else mips_loadstore #endif [ (cpu->byte_order == EMUL_LITTLE_ENDIAN? 0 : 16) + store * 8 + size * 2 + signedness]; ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[2] = (int32_t)imm; /* Load into the dummy scratch register, if rt = zero */ if (!store && rt == MIPS_GPR_ZERO) ic->arg[0] = (size_t)&cpu->cd.mips.scratch; /* Check for multiple loads or stores in a row using the same base register: */ #ifdef MODE32 if (main_opcode == HI6_LW) cpu->cd.mips.combination_check = COMBINE(multi_lw); if (main_opcode == HI6_SW) cpu->cd.mips.combination_check = COMBINE(multi_sw); #endif break; case HI6_LL: case HI6_LLD: case HI6_SC: case HI6_SCD: /* 32-bit load-linked/store-condition for ISA II and up: */ /* (64-bit load-linked/store-condition for ISA III...) */ if (cpu->cd.mips.cpu_type.isa_level < 2) { ic->f = instr(reserved); break; } store = 0; switch (main_opcode) { case HI6_LL: ic->f = instr(ll); break; case HI6_LLD: ic->f = instr(lld); x64 = 1; break; case HI6_SC: ic->f = instr(sc); store = 1; break; case HI6_SCD: ic->f = instr(scd); store = 1; x64 = 1; break; } ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[2] = (int32_t)imm; if (!store && rt == MIPS_GPR_ZERO) { if (!cpu->translation_readahead) fatal("HM... unusual load linked\n"); goto bad; } break; case HI6_LWL: case HI6_LWR: case HI6_LDL: case HI6_LDR: case HI6_SWL: case HI6_SWR: case HI6_SDL: case HI6_SDR: /* TODO: replace these with faster versions... */ store = 0; switch (main_opcode) { case HI6_LWL: ic->f = instr(lwl); break; case HI6_LWR: ic->f = instr(lwr); break; case HI6_LDL: ic->f = instr(ldl); x64 = 1; break; case HI6_LDR: ic->f = instr(ldr); x64 = 1; break; case HI6_SWL: ic->f = instr(swl); store = 1; break; case HI6_SWR: ic->f = instr(swr); store = 1; break; case HI6_SDL: ic->f = instr(sdl); store = 1; x64 = 1; break; case HI6_SDR: ic->f = instr(sdr); store = 1; x64 = 1; break; } ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[2] = (int32_t)imm; /* Load into the dummy scratch register, if rt = zero */ if (!store && rt == MIPS_GPR_ZERO) ic->arg[0] = (size_t)&cpu->cd.mips.scratch; break; case HI6_LWC1: case HI6_SWC1: case HI6_LDC1: case HI6_SDC1: /* 64-bit floating-point load/store for ISA II and up... */ if ((main_opcode == HI6_LDC1 || main_opcode == HI6_SDC1) && cpu->cd.mips.cpu_type.isa_level < 2) { ic->f = instr(reserved); break; } ic->arg[0] = (size_t)&cpu->cd.mips.coproc[1]->reg[rt]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[2] = (int32_t)imm; switch (main_opcode) { case HI6_LWC1: ic->f = instr(lwc1); break; case HI6_LDC1: ic->f = instr(ldc1); break; case HI6_SWC1: ic->f = instr(swc1); break; case HI6_SDC1: ic->f = instr(sdc1); break; } /* Cause a coprocessor unusable exception if there is no floating point coprocessor: */ if (cpu->cd.mips.cpu_type.flags & NOFPU || cpu->cd.mips.coproc[1] == NULL) { ic->f = instr(cpu); ic->arg[0] = 1; } break; case HI6_LWC3: /* PREF (prefetch) on ISA IV and MIPS32/64: */ if (cpu->cd.mips.cpu_type.isa_level >= 4) { /* Treat as nop for now: */ ic->f = instr(nop); } else { if (!cpu->translation_readahead) fatal("TODO: lwc3 not implemented yet\n"); goto bad; } break; case HI6_LQ_MDMX: if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { if (!cpu->translation_readahead) fatal("TODO: R5900 128-bit loads\n"); goto bad; } if (!cpu->translation_readahead) fatal("TODO: MDMX\n"); goto bad; /* break */ case HI6_SQ_SPECIAL3: if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { if (!cpu->translation_readahead) fatal("TODO: R5900 128-bit stores\n"); goto bad; } if (cpu->cd.mips.cpu_type.isa_level < 32 || cpu->cd.mips.cpu_type.isa_revision < 2) { static int warning = 0; if (!warning && !cpu->translation_readahead) { fatal("[ WARNING! SPECIAL3 opcode used, but" " the %s processor does not implement " "such instructions. Only printing this " "warning once. ]\n", cpu->cd.mips.cpu_type.name); warning = 1; } ic->f = instr(reserved); break; } switch (s6) { case SPECIAL3_EXT: { int msbd = rd, lsb = (iword >> 6) & 0x1f; ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[2] = (msbd << 5) + lsb; ic->f = instr(ext); if (rt == MIPS_GPR_ZERO) ic->f = instr(nop); } break; case SPECIAL3_DEXT: case SPECIAL3_DEXTM: case SPECIAL3_DEXTU: { int msbd = rd, lsb = (iword >> 6) & 0x1f; if (s6 == SPECIAL3_DEXTM) msbd += 32; if (s6 == SPECIAL3_DEXTU) lsb += 32; ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[2] = (msbd << 6) + lsb; ic->f = instr(dext); if (rt == MIPS_GPR_ZERO) ic->f = instr(nop); } break; case SPECIAL3_INS: { int msb = rd, lsb = (iword >> 6) & 0x1f; ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rs]; ic->arg[2] = (msb << 5) + lsb; ic->f = instr(ins); if (rt == MIPS_GPR_ZERO) ic->f = instr(nop); } break; case SPECIAL3_BSHFL: ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rd]; switch (s10) { case BSHFL_WSBH: ic->f = instr(wsbh); break; case BSHFL_SEB: ic->f = instr(seb); break; case BSHFL_SEH: ic->f = instr(seh); break; default:goto bad; } break; case SPECIAL3_DBSHFL: ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; ic->arg[1] = (size_t)&cpu->cd.mips.gpr[rd]; switch (s10) { case BSHFL_DSBH: ic->f = instr(dsbh); break; case BSHFL_DSHD: ic->f = instr(dshd); break; default:goto bad; } break; case SPECIAL3_RDHWR: ic->arg[0] = (size_t)&cpu->cd.mips.gpr[rt]; switch (rd) { case 0: ic->f = instr(rdhwr_cpunum); if (rt == MIPS_GPR_ZERO) ic->f = instr(nop); break; case 2: ic->f = instr(rdhwr_cc); if (rt == MIPS_GPR_ZERO) ic->f = instr(nop); break; case 29: ic->f = instr(reserved); break; default:if (!cpu->translation_readahead) fatal("unimplemented rdhwr " "register rd=%i\n", rd); goto bad; } break; default:goto bad; } break; case HI6_CACHE: /* TODO: rt and op etc... */ ic->f = instr(cache); break; default:goto bad; } #ifdef MODE32 if (x64) { static int has_warned = 0; if (!has_warned && !cpu->translation_readahead) { fatal("[ WARNING/NOTE: attempt to execute a 64-bit" " instruction on an emulated 32-bit processor; " "pc=0x%08" PRIx32" ]\n", (uint32_t)cpu->pc); has_warned = 1; } if (cpu->translation_readahead) goto bad; else ic->f = instr(reserved); } #else (void)x64; // avoid compiler warning #endif #define DYNTRANS_TO_BE_TRANSLATED_TAIL #include "cpu_dyntrans.cc" #undef DYNTRANS_TO_BE_TRANSLATED_TAIL } gxemul-0.6.1/src/cpus/cpu_sh.cc000644 001750 001750 00000115461 13402411502 016566 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Hitachi SuperH ("SH") CPU emulation. * * TODO: It would be nice if this could encompass both 64-bit SH5, and * 32-bit SH encodings. Right now, it only really supports 32-bit mode. * * TODO: This actually only works or SH4 so far, not SH3. */ #include #include #include #include #include #include "cpu.h" #include "device.h" #include "float_emul.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "settings.h" #include "symbol.h" #include "thirdparty/sh4_exception.h" #include "thirdparty/sh4_mmu.h" #define DYNTRANS_32 #define DYNTRANS_DELAYSLOT #include "tmp_sh_head.cc" extern int quiet_mode; void sh_pc_to_pointers(struct cpu *); void sh3_cpu_interrupt_assert(struct interrupt *interrupt); void sh3_cpu_interrupt_deassert(struct interrupt *interrupt); /* * sh_cpu_new(): * * Create a new SH cpu object. * * Returns 1 on success, 0 if there was no matching SH processor with * this cpu_type_name. */ int sh_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine, int cpu_id, char *cpu_type_name) { int i = 0; struct sh_cpu_type_def cpu_type_defs[] = SH_CPU_TYPE_DEFS; /* Scan the cpu_type_defs list for this cpu type: */ while (cpu_type_defs[i].name != NULL) { if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) { break; } i++; } if (cpu_type_defs[i].name == NULL) return 0; cpu->memory_rw = sh_memory_rw; cpu->cd.sh.cpu_type = cpu_type_defs[i]; cpu->byte_order = EMUL_LITTLE_ENDIAN; cpu->is_32bit = cpu->cd.sh.cpu_type.bits == 32; if (!cpu->is_32bit) { fatal("SH64 emulation not implemented. Sorry.\n"); exit(1); } cpu->instruction_has_delayslot = sh_cpu_instruction_has_delayslot; cpu->translate_v2p = sh_translate_v2p; cpu->run_instr = sh_run_instr; cpu->update_translation_table = sh_update_translation_table; cpu->invalidate_translation_caches = sh_invalidate_translation_caches; cpu->invalidate_code_translation = sh_invalidate_code_translation; /* Only show name and caches etc for CPU nr 0 (in SMP machines): */ if (cpu_id == 0) { debug("%s", cpu->name); } /* Initial value of FPSCR (according to the SH4 manual): */ cpu->cd.sh.fpscr = 0x00040001; /* (Initial value of the program counter on reboot is 0xA0000000.) */ /* Start in Privileged Mode: */ cpu->cd.sh.sr = SH_SR_MD | SH_SR_IMASK; /* Stack pointer at end of physical RAM: */ cpu->cd.sh.r[15] = cpu->machine->physical_ram_in_mb * 1048576 - 64; CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc); CPU_SETTINGS_ADD_REGISTER32("sr", cpu->cd.sh.sr); CPU_SETTINGS_ADD_REGISTER32("pr", cpu->cd.sh.pr); CPU_SETTINGS_ADD_REGISTER32("vbr", cpu->cd.sh.vbr); CPU_SETTINGS_ADD_REGISTER32("sgr", cpu->cd.sh.sgr); CPU_SETTINGS_ADD_REGISTER32("gbr", cpu->cd.sh.gbr); CPU_SETTINGS_ADD_REGISTER32("dbr", cpu->cd.sh.dbr); CPU_SETTINGS_ADD_REGISTER32("macl", cpu->cd.sh.macl); CPU_SETTINGS_ADD_REGISTER32("mach", cpu->cd.sh.mach); CPU_SETTINGS_ADD_REGISTER32("expevt", cpu->cd.sh.expevt); CPU_SETTINGS_ADD_REGISTER32("intevt", cpu->cd.sh.intevt); CPU_SETTINGS_ADD_REGISTER32("tra", cpu->cd.sh.tra); CPU_SETTINGS_ADD_REGISTER32("fpscr", cpu->cd.sh.fpscr); CPU_SETTINGS_ADD_REGISTER32("fpul", cpu->cd.sh.fpul); for (i=0; icd.sh.r[i]); } for (i=0; icd.sh.r_bank[i]); } for (i=0; icd.sh.fr[i]); snprintf(tmpstr, sizeof(tmpstr), "xf%i", i); CPU_SETTINGS_ADD_REGISTER32(tmpstr, cpu->cd.sh.xf[i]); } for (i=0; icd.sh.itlb_hi[i]); snprintf(tmpstr, sizeof(tmpstr), "itlb_lo_%i", i); CPU_SETTINGS_ADD_REGISTER32(tmpstr, cpu->cd.sh.itlb_lo[i]); } for (i=0; icd.sh.utlb_hi[i]); snprintf(tmpstr, sizeof(tmpstr), "utlb_lo_%i", i); CPU_SETTINGS_ADD_REGISTER32(tmpstr, cpu->cd.sh.utlb_lo[i]); } /* Register the CPU's interrupts: */ if (cpu->cd.sh.cpu_type.arch == 4) { for (i=SH_INTEVT_NMI; i<0x1000; i+=0x20) { struct interrupt templ; char name[100]; snprintf(name, sizeof(name), "%s.irq[0x%x]", cpu->path, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = name; templ.extra = cpu; templ.interrupt_assert = sh_cpu_interrupt_assert; templ.interrupt_deassert = sh_cpu_interrupt_deassert; interrupt_handler_register(&templ); } } else { struct interrupt templ; memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = cpu->path; templ.extra = cpu; templ.interrupt_assert = sh3_cpu_interrupt_assert; templ.interrupt_deassert = sh3_cpu_interrupt_deassert; interrupt_handler_register(&templ); } /* SH4-specific memory mapped registers, TLBs, caches, etc: */ if (cpu->cd.sh.cpu_type.arch == 4) { cpu->cd.sh.pcic_pcibus = (struct pci_data *) device_add(machine, "sh4"); /* * Interrupt Controller initial values, according to the * SH7760 manual: */ cpu->cd.sh.intc_iprd = 0xda74; cpu->cd.sh.intc_intmsk00 = 0xf3ff7fff; cpu->cd.sh.intc_intmsk04 = 0x00ffffff; /* All others are zero. */ /* TODO: Initial priorities? */ cpu->cd.sh.intc_intpri00 = 0x33333333; cpu->cd.sh.intc_intpri04 = 0x33333333; cpu->cd.sh.intc_intpri08 = 0x33333333; cpu->cd.sh.intc_intpri0c = 0x33333333; } sh_update_interrupt_priorities(cpu); return 1; } /* * sh_update_interrupt_priorities(): * * SH interrupts are a bit complicated; there are several intc registers * controlling priorities for various peripherals: * * Register: Bits 15..12 11..8 7..4 3..0 * --------- ----------- ----- ---- ---- * ipra TMU0 TMU1 TMU2 Reserved * iprb WDT REF Reserved Reserved * iprc GPIO DMAC Reserved H-UDI * iprd IRL0 IRL1 IRL2 IRL3 * * Register: 31..28 27..24 23..20 19..16 15..12 11..8 7..4 3..0 * --------- ------ ------ ------ ------ ------ ----- ---- ---- * intpri00 IRQ4 IRQ5 IRQ6 IRQ7 Rsrvd. Rsrvd. Rsrvd. Reserved * intpri04 HCAN2,0 HCAN2,1 SSI(0) SSI(1) HAC(0) HAC(1) I2C(0) I2C(1) * intpri08 USB LCDC DMABRG SCIF(0) SCIF(1) SCIF(2) SIM HSPI * intpri0c Reserv. Reserv. MMCIF Reserv. MFI Rsrvd. ADC CMT */ void sh_update_interrupt_priorities(struct cpu *cpu) { int i; /* * Set priorities of known interrupts, without affecting the * SH_INT_ASSERTED bit: */ for (i=SH4_INTEVT_IRQ0; i<=SH4_INTEVT_IRQ14; i+=0x20) { cpu->cd.sh.int_prio_and_pending[i/0x20] &= ~SH_INT_PRIO_MASK; cpu->cd.sh.int_prio_and_pending[i/0x20] |= (15 - ((i - SH4_INTEVT_IRQ0) / 0x20)); } cpu->cd.sh.int_prio_and_pending[SH_INTEVT_TMU0_TUNI0 / 0x20] &= ~SH_INT_PRIO_MASK; cpu->cd.sh.int_prio_and_pending[SH_INTEVT_TMU0_TUNI0 / 0x20] |= (cpu->cd.sh.intc_ipra >> 12) & 0xf; cpu->cd.sh.int_prio_and_pending[SH_INTEVT_TMU1_TUNI1 / 0x20] &= ~SH_INT_PRIO_MASK; cpu->cd.sh.int_prio_and_pending[SH_INTEVT_TMU1_TUNI1 / 0x20] |= (cpu->cd.sh.intc_ipra >> 8) & 0xf; cpu->cd.sh.int_prio_and_pending[SH_INTEVT_TMU2_TUNI2 / 0x20] &= ~SH_INT_PRIO_MASK; cpu->cd.sh.int_prio_and_pending[SH_INTEVT_TMU2_TUNI2 / 0x20] |= (cpu->cd.sh.intc_ipra >> 4) & 0xf; for (i=SH4_INTEVT_SCIF_ERI; i<=SH4_INTEVT_SCIF_TXI; i+=0x20) { cpu->cd.sh.int_prio_and_pending[i/0x20] &= ~SH_INT_PRIO_MASK; cpu->cd.sh.int_prio_and_pending[i/0x20] |= ((cpu->cd.sh.intc_intpri08 >> 16) & 0xf); } } /* * sh3_cpu_interrupt_assert(): * sh3_cpu_interrupt_deassert(): */ void sh3_cpu_interrupt_assert(struct interrupt *interrupt) { /* TODO */ } void sh3_cpu_interrupt_deassert(struct interrupt *interrupt) { /* TODO */ } /* * sh_cpu_interrupt_assert(): */ void sh_cpu_interrupt_assert(struct interrupt *interrupt) { struct cpu *cpu = (struct cpu *) interrupt->extra; unsigned int irq_nr = interrupt->line; unsigned int index = irq_nr / 0x20; unsigned int prio; /* Assert the interrupt, and check its priority level: */ cpu->cd.sh.int_prio_and_pending[index] |= SH_INT_ASSERTED; prio = cpu->cd.sh.int_prio_and_pending[index] & SH_INT_PRIO_MASK; if (prio == 0) { /* Interrupt not implemented? Hm. */ fatal("[ SH interrupt 0x%x, prio 0 (?), aborting ]\n", irq_nr); exit(1); } if (cpu->cd.sh.int_to_assert == 0 || prio > cpu->cd.sh.int_level) { cpu->cd.sh.int_to_assert = irq_nr; cpu->cd.sh.int_level = prio; } } /* * sh_cpu_interrupt_deassert(): */ void sh_cpu_interrupt_deassert(struct interrupt *interrupt) { struct cpu *cpu = (struct cpu *) interrupt->extra; int irq_nr = interrupt->line; int index = irq_nr / 0x20; /* Deassert the interrupt: */ if (cpu->cd.sh.int_prio_and_pending[index] & SH_INT_ASSERTED) { cpu->cd.sh.int_prio_and_pending[index] &= ~SH_INT_ASSERTED; /* Calculate new interrupt assertion: */ cpu->cd.sh.int_to_assert = 0; cpu->cd.sh.int_level = 0; /* NOTE/TODO: This is slow, but should hopefully work: */ for (index=0; index<0x1000/0x20; index++) { uint8_t x = cpu->cd.sh.int_prio_and_pending[index]; uint8_t prio = x & SH_INT_PRIO_MASK; if (x & SH_INT_ASSERTED && prio > cpu->cd.sh.int_level) { cpu->cd.sh.int_to_assert = index * 0x20; cpu->cd.sh.int_level = prio; } } } } /* * sh_cpu_list_available_types(): * * Print a list of available SH CPU types. */ void sh_cpu_list_available_types(void) { int i = 0, j; struct sh_cpu_type_def tdefs[] = SH_CPU_TYPE_DEFS; while (tdefs[i].name != NULL) { debug("%s", tdefs[i].name); for (j=10 - strlen(tdefs[i].name); j>0; j--) debug(" "); i ++; if ((i % 6) == 0 || tdefs[i].name == NULL) debug("\n"); } } /* * sh_cpu_dumpinfo(): */ void sh_cpu_dumpinfo(struct cpu *cpu) { debug(" (%s-endian)\n", cpu->byte_order == EMUL_BIG_ENDIAN? "Big" : "Little"); } /* * sh_cpu_instruction_has_delayslot(): * * Return 1 if an opcode is a branch, 0 otherwise. */ int sh_cpu_instruction_has_delayslot(struct cpu *cpu, unsigned char *ib) { uint16_t iword = *((uint16_t *)&ib[0]); int hi4, lo8; // , lo4 if (!cpu->is_32bit) return 0; if (cpu->byte_order == EMUL_BIG_ENDIAN) iword = BE16_TO_HOST(iword); else iword = LE16_TO_HOST(iword); hi4 = iword >> 12; lo8 = iword & 255; // lo4 = iword & 15; switch (hi4) { case 0x0: if (iword == 0x000b) /* rts */ return 1; if (iword == 0x002b) /* rte */ return 1; if (lo8 == 0x03) /* bsrf */ return 1; if (lo8 == 0x23) /* braf */ return 1; break; case 0x4: switch (lo8) { case 0x0b: /* jsr */ case 0x2b: /* jmp */ return 1; } break; case 0x8: switch ((iword >> 8) & 0xf) { case 0xd: /* bt/s */ case 0xf: /* bf/s */ return 1; } break; case 0xa: /* bra */ case 0xb: /* bsr */ return 1; } return 0; } /* * sh_cpu_register_dump(): * * Dump cpu registers in a relatively readable format. * * gprs: set to non-zero to dump GPRs and some special-purpose registers. * coprocs: set bit 0..3 to dump registers in coproc 0..3. */ void sh_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs) { char *symbol; uint64_t offset; int i, x = cpu->cpu_id; if (gprs) { /* Special registers (pc, ...) first: */ symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->pc, &offset); debug("cpu%i: pc = 0x%08" PRIx32, x, (uint32_t)cpu->pc); debug(" <%s>\n", symbol != NULL? symbol : " no symbol "); debug("cpu%i: sr = 0x%08" PRIx32" (%s, %s, %s, %s, %s, %s," " imask=0x%x, %s, %s)\n", x, (int32_t)cpu->cd.sh.sr, (cpu->cd.sh.sr & SH_SR_MD)? "MD" : "!md", (cpu->cd.sh.sr & SH_SR_RB)? "RB" : "!rb", (cpu->cd.sh.sr & SH_SR_BL)? "BL" : "!bl", (cpu->cd.sh.sr & SH_SR_FD)? "FD" : "!fd", (cpu->cd.sh.sr & SH_SR_M)? "M" : "!m", (cpu->cd.sh.sr & SH_SR_Q)? "Q" : "!q", (cpu->cd.sh.sr & SH_SR_IMASK) >> SH_SR_IMASK_SHIFT, (cpu->cd.sh.sr & SH_SR_S)? "S" : "!s", (cpu->cd.sh.sr & SH_SR_T)? "T" : "!t"); symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->cd.sh.pr, &offset); debug("cpu%i: pr = 0x%08" PRIx32, x, (uint32_t)cpu->cd.sh.pr); debug(" <%s>\n", symbol != NULL? symbol : " no symbol "); debug("cpu%i: mach = 0x%08" PRIx32" macl = 0x%08" PRIx32 " gbr = 0x%08" PRIx32"\n", x, (uint32_t)cpu->cd.sh.mach, (uint32_t)cpu->cd.sh.macl, (uint32_t)cpu->cd.sh.gbr); for (i=0; icd.sh.r[i]); if ((i % 4) == 3) debug("\n"); } } if (coprocs & 1) { /* Floating point: */ debug("cpu%i: fpscr = 0x%08" PRIx32" (%s,%s,%s) fpul = 0x%08" PRIx32"\n", x, cpu->cd.sh.fpscr, cpu->cd.sh.fpscr & SH_FPSCR_PR? "PR" : "!pr", cpu->cd.sh.fpscr & SH_FPSCR_SZ? "SZ" : "!sz", cpu->cd.sh.fpscr & SH_FPSCR_FR? "FR" : "!fr", cpu->cd.sh.fpul); for (i=0; icd.sh.fr[i]); if ((i % 4) == 3) debug("\n"); } for (i=0; icd.sh.xf[i]); if ((i % 4) == 3) debug("\n"); } } if (coprocs & 2) { /* System registers, etc: */ debug("cpu%i: vbr = 0x%08" PRIx32" sgr = 0x%08" PRIx32 " dbr = 0x%08" PRIx32"\n", x, cpu->cd.sh.vbr, cpu->cd.sh.sgr, cpu->cd.sh.dbr); debug("cpu%i: spc = 0x%08" PRIx32" ssr = 0x%08" PRIx32"\n", x, cpu->cd.sh.spc, cpu->cd.sh.ssr); debug("cpu%i: expevt = 0x%" PRIx32" intevt = 0x%" PRIx32 " tra = 0x%" PRIx32"\n", x, cpu->cd.sh.expevt, cpu->cd.sh.intevt, cpu->cd.sh.tra); for (i=0; icd.sh.r_bank[i]); if ((i % 2) == 1) debug("\n"); } } } /* * sh_cpu_tlbdump(): * * Called from the debugger to dump the TLB in a readable format. * x is the cpu number to dump, or -1 to dump all CPUs. * * If rawflag is nonzero, then the TLB contents isn't formated nicely, * just dumped. */ void sh_cpu_tlbdump(struct machine *m, int x, int rawflag) { int i, j; for (j=0; jncpus; j++) { struct cpu *cpu = m->cpus[j]; if (x >= 0 && j != x) continue; for (i=0; icd.sh.itlb_hi[i], i, (uint32_t) cpu->cd.sh.itlb_lo[i]); for (i=0; icd.sh.utlb_hi[i], i, (uint32_t) cpu->cd.sh.utlb_lo[i]); } } /* * sh_update_sr(): * * Writes a new value to the status register. */ void sh_update_sr(struct cpu *cpu, uint32_t new_sr) { uint32_t old_sr = cpu->cd.sh.sr; if ((new_sr & SH_SR_RB) != (old_sr & SH_SR_RB)) { int i; for (i=0; icd.sh.r[i]; cpu->cd.sh.r[i] = cpu->cd.sh.r_bank[i]; cpu->cd.sh.r_bank[i] = tmp; } } cpu->cd.sh.sr = new_sr; } /* * sh_update_fpscr(): * * Writes a new value to the floating-point status/control register. */ void sh_update_fpscr(struct cpu *cpu, uint32_t new_fpscr) { uint32_t old_fpscr = cpu->cd.sh.fpscr; if ((new_fpscr & SH_FPSCR_FR) != (old_fpscr & SH_FPSCR_FR)) { int i; for (i=0; icd.sh.fr[i]; cpu->cd.sh.fr[i] = cpu->cd.sh.xf[i]; cpu->cd.sh.xf[i] = tmp; } } cpu->cd.sh.fpscr = new_fpscr; } /* * sh_exception(): * * Causes a transfer of control to an exception or interrupt handler. * If intevt > 0, then it is an interrupt, otherwise an exception. * * vaddr contains the faulting address, on TLB exceptions. */ void sh_exception(struct cpu *cpu, int expevt, int intevt, uint32_t vaddr) { uint32_t vbr = cpu->cd.sh.vbr; if (!quiet_mode) { if (intevt > 0) debug("[ interrupt 0x%03x", intevt); else debug("[ exception 0x%03x", expevt); debug(", pc=0x%08" PRIx32" ", (uint32_t)cpu->pc); if (intevt == 0) debug("vaddr=0x%08" PRIx32" ", vaddr); debug(" ]\n"); } if (cpu->cd.sh.sr & SH_SR_BL) { fatal("[ sh_exception(): BL bit already set. ]\n"); /* This is actually OK in two cases: a User Break, or on NMI interrupts if a special flag is set? */ /* TODO */ expevt = EXPEVT_RESET_POWER; } if (cpu->is_halted) { /* * If the exception occurred on a 'sleep' instruction, then let * the instruction following the sleep instruction be the one * where execution resumes when the interrupt service routine * returns. */ cpu->is_halted = 0; cpu->pc += sizeof(uint16_t); } if (cpu->delay_slot) { cpu->delay_slot = EXCEPTION_IN_DELAY_SLOT; cpu->pc -= sizeof(uint16_t); } /* * Stuff common to all exceptions: */ cpu->cd.sh.spc = cpu->pc; cpu->cd.sh.ssr = cpu->cd.sh.sr; cpu->cd.sh.sgr = cpu->cd.sh.r[15]; if (intevt > 0) { cpu->cd.sh.intevt = intevt; expevt = -1; } else { cpu->cd.sh.expevt = expevt; } sh_update_sr(cpu, cpu->cd.sh.sr | SH_SR_MD | SH_SR_RB | SH_SR_BL); /* Most exceptions set PC to VBR + 0x100. */ cpu->pc = vbr + 0x100; /* Specific cases: */ switch (expevt) { case -1: /* Interrupt */ cpu->pc = vbr + 0x600; break; case EXPEVT_RESET_POWER: case EXPEVT_RESET_MANUAL: cpu->pc = 0xa0000000; cpu->cd.sh.vbr = 0x00000000; sh_update_sr(cpu, (cpu->cd.sh.sr | SH_SR_IMASK) & ~SH_SR_FD); break; case EXPEVT_TLB_MISS_LD: case EXPEVT_TLB_MISS_ST: cpu->pc = vbr + 0x400; case EXPEVT_TLB_PROT_LD: case EXPEVT_TLB_PROT_ST: case EXPEVT_TLB_MOD: cpu->cd.sh.tea = vaddr; cpu->cd.sh.pteh &= ~SH4_PTEH_VPN_MASK; cpu->cd.sh.pteh |= (vaddr & SH4_PTEH_VPN_MASK); break; case EXPEVT_TRAPA: /* * Note: The TRA register is already set by the implementation * of the trapa instruction. See cpu_sh_instr.c for details. * Here, spc is incremented, so that a return from the trap * handler transfers control to the instruction _following_ * the trapa. */ cpu->cd.sh.spc += sizeof(uint16_t); break; case EXPEVT_RES_INST: /* * Note: Having this code here makes it possible to catch * reserved instructions; during normal instruction execution, * these are not very common. */ #if 1 printf("\nRESERVED SuperH instruction at spc=%08" PRIx32"\n", cpu->cd.sh.spc); exit(1); #else break; #endif case EXPEVT_FPU_DISABLE: break; default:fatal("sh_exception(): exception 0x%x is not yet " "implemented.\n", expevt); exit(1); } sh_pc_to_pointers(cpu); } /* * sh_cpu_disassemble_instr(): * * SHcompact instruction disassembly. The top 4 bits of each 16-bit * instruction word is used as the main opcode. For most instructions, the * lowest 4 or 8 bits then select sub-opcode. * * This function convert an instruction word into human readable format, * for instruction tracing. * * If running is 1, cpu->pc should be the address of the instruction. * * If running is 0, things that depend on the runtime environment (eg. * register contents) will not be shown, and addr will be used instead of * cpu->pc for relative addresses. */ int sh_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr, int running, uint64_t dumpaddr) { char *symbol; uint64_t offset, addr; uint16_t iword; if (running) dumpaddr = cpu->pc; symbol = get_symbol_name(&cpu->machine->symbol_context, dumpaddr, &offset); if (symbol != NULL && offset==0) debug("<%s>\n", symbol); if (cpu->machine->ncpus > 1 && running) debug("cpu%i: ", cpu->cpu_id); debug("%08" PRIx32, (uint32_t) dumpaddr); if (cpu->byte_order == EMUL_BIG_ENDIAN) iword = (instr[0] << 8) + instr[1]; else iword = (instr[1] << 8) + instr[0]; debug(": %04x %s\t", iword, cpu->delay_slot? "(d)" : ""); const int hi4 = iword >> 12, lo4 = iword & 15, lo8 = iword & 255; int r8 = (iword >> 8) & 15, r4 = (iword >> 4) & 15; /* * Decode the instruction: */ switch (hi4) { case 0x0: if (lo8 == 0x02) debug("stc\tsr,r%i\n", r8); else if (lo8 == 0x03) debug("bsrf\tr%i\n", r8); else if (lo4 >= 4 && lo4 <= 6) { if (lo4 == 0x4) debug("mov.b\tr%i,@(r0,r%i)", r4, r8); else if (lo4 == 0x5) debug("mov.w\tr%i,@(r0,r%i)", r4, r8); else if (lo4 == 0x6) debug("mov.l\tr%i,@(r0,r%i)", r4, r8); if (running) { addr = cpu->cd.sh.r[0] + cpu->cd.sh.r[r8]; debug("\t; r0+r%i = ", r8); symbol = get_symbol_name( &cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug("<%s>", symbol); else debug("0x%08" PRIx32, addr); } debug("\n"); } else if (lo4 == 0x7) debug("mul.l\tr%i,r%i\n", r4, r8); else if (iword == 0x0008) debug("clrt\n"); else if (iword == 0x0009) debug("nop\n"); else if (lo8 == 0x0a) debug("sts\tmach,r%i\n", r8); else if (iword == 0x000b) debug("rts\n"); else if (lo4 >= 0xc && lo4 <= 0xe) { if (lo4 == 0xc) debug("mov.b\t@(r0,r%i),r%i", r4, r8); else if (lo4 == 0xd) debug("mov.w\t@(r0,r%i),r%i", r4, r8); else if (lo4 == 0xe) debug("mov.l\t@(r0,r%i),r%i", r4, r8); if (running) { addr = cpu->cd.sh.r[0] + cpu->cd.sh.r[r4]; debug("\t; r0+r%i = ", r4); symbol = get_symbol_name( &cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug("<%s>", symbol); else debug("0x%08" PRIx32, addr); } debug("\n"); } else if (lo8 == 0x12) debug("stc\tgbr,r%i\n", r8); else if (iword == 0x0018) debug("sett\n"); else if (iword == 0x0019) debug("div0u\n"); else if (lo8 == 0x1a) debug("sts\tmacl,r%i\n", r8); else if (iword == 0x001b) debug("sleep\n"); else if (lo8 == 0x22) debug("stc\tvbr,r%i\n", r8); else if (lo8 == 0x23) debug("braf\tr%i\n", r8); else if (iword == 0x0028) debug("clrmac\n"); else if (lo8 == 0x29) debug("movt\tr%i\n", r8); else if (lo8 == 0x2a) debug("sts\tpr,r%i\n", r8); else if (iword == 0x002b) debug("rte\n"); else if (lo8 == 0x32) debug("stc\tssr,r%i\n", r8); else if (iword == 0x0038) debug("ldtlb\n"); else if (iword == 0x003b) debug("brk\n"); else if (lo8 == 0x42) debug("stc\tspc,r%i\n", r8); else if (iword == 0x0048) debug("clrs\n"); else if (iword == 0x0058) debug("sets\n"); else if (lo8 == 0x5a) debug("sts\tfpul,r%i\n", r8); else if (lo8 == 0x6a) debug("sts\tfpscr,r%i\n", r8); else if ((lo8 & 0x8f) == 0x82) debug("stc\tr%i_bank,r%i\n", (lo8 >> 4) & 7, r8); else if (lo8 == 0x83) debug("pref\t@r%i\n", r8); else if (lo8 == 0x93) debug("ocbi\t@r%i\n", r8); else if (lo8 == 0xa3) debug("ocbp\t@r%i\n", r8); else if (lo8 == 0xb3) debug("ocbwb\t@r%i\n", r8); else if (lo8 == 0xc3) debug("movca.l\tr0,@r%i\n", r8); else if (lo8 == 0xfa) debug("stc\tdbr,r%i\n", r8); else if (iword == SH_INVALID_INSTR) debug("gxemul_dreamcast_prom_emul\n"); else debug("UNIMPLEMENTED hi4=0x%x, lo8=0x%02x\n", hi4, lo8); break; case 0x1: debug("mov.l\tr%i,@(%i,r%i)", r4, lo4 * 4, r8); if (running) { addr = cpu->cd.sh.r[r8] + lo4 * 4; debug("\t; r%i+%i = ", r8, lo4 * 4); symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug("<%s>", symbol); else debug("0x%08" PRIx32, addr); } debug("\n"); break; case 0x2: if (lo4 == 0x0) debug("mov.b\tr%i,@r%i", r4, r8); else if (lo4 == 0x1) debug("mov.w\tr%i,@r%i", r4, r8); else if (lo4 == 0x2) debug("mov.l\tr%i,@r%i", r4, r8); else if (lo4 == 0x4) debug("mov.b\tr%i,@-r%i", r4, r8); else if (lo4 == 0x5) debug("mov.w\tr%i,@-r%i", r4, r8); else if (lo4 == 0x6) debug("mov.l\tr%i,@-r%i", r4, r8); else if (lo4 == 0x7) debug("div0s\tr%i,r%i", r4, r8); else if (lo4 == 0x8) debug("tst\tr%i,r%i", r4, r8); else if (lo4 == 0x9) debug("and\tr%i,r%i", r4, r8); else if (lo4 == 0xa) debug("xor\tr%i,r%i", r4, r8); else if (lo4 == 0xb) debug("or\tr%i,r%i", r4, r8); else if (lo4 == 0xc) debug("cmp/str\tr%i,r%i", r4, r8); else if (lo4 == 0xd) debug("xtrct\tr%i,r%i", r4, r8); else if (lo4 == 0xe) debug("mulu.w\tr%i,r%i", r4, r8); else if (lo4 == 0xf) debug("muls.w\tr%i,r%i", r4, r8); else debug("UNIMPLEMENTED hi4=0x%x, lo8=0x%02x", hi4, lo8); if (running && lo4 <= 6) { debug("\t; r%i = 0x%08" PRIx32, r8, cpu->cd.sh.r[r8]); } debug("\n"); break; case 0x3: if (lo4 == 0x0) debug("cmp/eq\tr%i,r%i\n", r4, r8); else if (lo4 == 0x2) debug("cmp/hs\tr%i,r%i\n", r4, r8); else if (lo4 == 0x3) debug("cmp/ge\tr%i,r%i\n", r4, r8); else if (lo4 == 0x4) debug("div1\tr%i,r%i\n", r4, r8); else if (lo4 == 0x5) debug("dmulu.l\tr%i,r%i\n", r4, r8); else if (lo4 == 0x6) debug("cmp/hi\tr%i,r%i\n", r4, r8); else if (lo4 == 0x7) debug("cmp/gt\tr%i,r%i\n", r4, r8); else if (lo4 == 0x8) debug("sub\tr%i,r%i\n", r4, r8); else if (lo4 == 0xa) debug("subc\tr%i,r%i\n", r4, r8); else if (lo4 == 0xb) debug("subv\tr%i,r%i\n", r4, r8); else if (lo4 == 0xc) debug("add\tr%i,r%i\n", r4, r8); else if (lo4 == 0xd) debug("dmuls.l\tr%i,r%i\n", r4, r8); else if (lo4 == 0xe) debug("addc\tr%i,r%i\n", r4, r8); else if (lo4 == 0xf) debug("addv\tr%i,r%i\n", r4, r8); else debug("UNIMPLEMENTED hi4=0x%x, lo8=0x%02x\n", hi4, lo8); break; case 0x4: if (lo8 == 0x00) debug("shll\tr%i\n", r8); else if (lo8 == 0x01) debug("shlr\tr%i\n", r8); else if (lo8 == 0x02) debug("sts.l\tmach,@-r%i\n", r8); else if (lo8 == 0x03) debug("stc.l\tsr,@-r%i\n", r8); else if (lo8 == 0x04) debug("rotl\tr%i\n", r8); else if (lo8 == 0x05) debug("rotr\tr%i\n", r8); else if (lo8 == 0x06) debug("lds.l\t@r%i+,mach\n", r8); else if (lo8 == 0x07) debug("ldc.l\t@r%i+,sr\n", r8); else if (lo8 == 0x08) debug("shll2\tr%i\n", r8); else if (lo8 == 0x09) debug("shlr2\tr%i\n", r8); else if (lo8 == 0x0a) debug("lds\tr%i,mach\n", r8); else if (lo8 == 0x0b) debug("jsr\t@r%i\n", r8); else if (lo4 == 0xc) debug("shad\tr%i,r%i\n", r4, r8); else if (lo4 == 0xd) debug("shld\tr%i,r%i\n", r4, r8); else if (lo8 == 0x0e) debug("ldc\tr%i,sr\n", r8); else if (lo8 == 0x10) debug("dt\tr%i\n", r8); else if (lo8 == 0x11) debug("cmp/pz\tr%i\n", r8); else if (lo8 == 0x12) debug("sts.l\tmacl,@-r%i\n", r8); else if (lo8 == 0x13) debug("stc.l\tgbr,@-r%i\n", r8); else if (lo8 == 0x15) debug("cmp/pl\tr%i\n", r8); else if (lo8 == 0x16) debug("lds.l\t@r%i+,macl\n", r8); else if (lo8 == 0x17) debug("ldc.l\t@r%i+,gbr\n", r8); else if (lo8 == 0x18) debug("shll8\tr%i\n", r8); else if (lo8 == 0x19) debug("shlr8\tr%i\n", r8); else if (lo8 == 0x1a) debug("lds\tr%i,macl\n", r8); else if (lo8 == 0x1b) debug("tas.b\t@r%i\n", r8); else if (lo8 == 0x1e) debug("ldc\tr%i,gbr\n", r8); else if (lo8 == 0x20) debug("shal\tr%i\n", r8); else if (lo8 == 0x21) debug("shar\tr%i\n", r8); else if (lo8 == 0x22) debug("sts.l\tpr,@-r%i\n", r8); else if (lo8 == 0x23) debug("stc.l\tvbr,@-r%i\n", r8); else if (lo8 == 0x24) debug("rotcl\tr%i\n", r8); else if (lo8 == 0x25) debug("rotcr\tr%i\n", r8); else if (lo8 == 0x26) debug("lds.l\t@r%i+,pr\n", r8); else if (lo8 == 0x27) debug("ldc.l\t@r%i+,vbr\n", r8); else if (lo8 == 0x28) debug("shll16\tr%i\n", r8); else if (lo8 == 0x29) debug("shlr16\tr%i\n", r8); else if (lo8 == 0x2a) debug("lds\tr%i,pr\n", r8); else if (lo8 == 0x2b) { debug("jmp\t@r%i", r8); if (running) { symbol = get_symbol_name( &cpu->machine->symbol_context, cpu->cd.sh.r[r8], &offset); if (symbol != NULL) debug("\t\t; <%s>", symbol); } debug("\n"); } else if (lo8 == 0x2e) debug("ldc\tr%i,vbr\n", r8); else if (lo8 == 0x33) debug("stc.l\tssr,@-r%i\n", r8); else if (lo8 == 0x37) debug("ldc.l\t@r%i+,ssr\n", r8); else if (lo8 == 0x3e) debug("ldc\tr%i,ssr\n", r8); else if (lo8 == 0x43) debug("stc.l\tspc,@-r%i\n", r8); else if (lo8 == 0x47) debug("ldc.l\t@r%i+,spc\n", r8); else if (lo8 == 0x4e) debug("ldc\tr%i,spc\n", r8); else if (lo8 == 0x52) debug("sts.l\tfpul,@-r%i\n", r8); else if (lo8 == 0x56) debug("lds.l\t@r%i+,fpul\n", r8); else if (lo8 == 0x5a) debug("lds\tr%i,fpul\n", r8); else if (lo8 == 0x62) debug("sts.l\tfpscr,@-r%i\n", r8); else if (lo8 == 0x66) debug("lds.l\t@r%i+,fpscr\n", r8); else if (lo8 == 0x6a) debug("lds\tr%i,fpscr\n", r8); else if ((lo8 & 0x8f) == 0x83) debug("stc.l\tr%i_bank,@-r%i\n", (lo8 >> 4) & 7, r8); else if ((lo8 & 0x8f) == 0x87) debug("ldc.l\t@r%i,r%i_bank\n", r8, (lo8 >> 4) & 7, r8); else if ((lo8 & 0x8f) == 0x8e) debug("ldc\tr%i,r%i_bank\n", r8, (lo8 >> 4) & 7); else if (lo8 == 0xfa) debug("ldc\tr%i,dbr\n", r8); else debug("UNIMPLEMENTED hi4=0x%x, lo8=0x%02x\n", hi4, lo8); break; case 0x5: debug("mov.l\t@(%i,r%i),r%i", lo4 * 4, r4, r8); if (running) { addr = cpu->cd.sh.r[r4] + lo4 * 4; symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug("\t; r%i+%i <%s>", r4, lo4 * 4, symbol); else debug("\t; r%i+%i = 0x%08" PRIx32, r4, lo4 * 4, (int)addr); } debug("\n"); break; case 0x6: if (lo4 == 0x0) debug("mov.b\t@r%i,r%i", r4, r8); else if (lo4 == 0x1) debug("mov.w\t@r%i,r%i", r4, r8); else if (lo4 == 0x2) debug("mov.l\t@r%i,r%i", r4, r8); else if (lo4 == 0x3) debug("mov\tr%i,r%i", r4, r8); else if (lo4 == 0x4) debug("mov.b\t@r%i+,r%i", r4, r8); else if (lo4 == 0x5) debug("mov.w\t@r%i+,r%i", r4, r8); else if (lo4 == 0x6) debug("mov.l\t@r%i+,r%i", r4, r8); else if (lo4 == 0x7) debug("not\tr%i,r%i", r4, r8); else if (lo4 == 0x8) debug("swap.b\tr%i,r%i", r4, r8); else if (lo4 == 0x9) debug("swap.w\tr%i,r%i", r4, r8); else if (lo4 == 0xa) debug("negc\tr%i,r%i", r4, r8); else if (lo4 == 0xb) debug("neg\tr%i,r%i", r4, r8); else if (lo4 == 0xc) debug("extu.b\tr%i,r%i", r4, r8); else if (lo4 == 0xd) debug("extu.w\tr%i,r%i", r4, r8); else if (lo4 == 0xe) debug("exts.b\tr%i,r%i", r4, r8); else if (lo4 == 0xf) debug("exts.w\tr%i,r%i", r4, r8); else debug("UNIMPLEMENTED hi4=0x%x, lo8=0x%02x", hi4, lo8); if (running && lo4 < 8 && (lo4 & 3) < 3) { debug("\t; r%i = 0x%08" PRIx32, r4, cpu->cd.sh.r[r4]); } debug("\n"); break; case 0x7: debug("add\t#%i,r%i\n", (int8_t)lo8, r8); break; case 0x8: if (r8 == 0 || r8 == 4) { if (r8 == 0x0) debug("mov.b\tr0,@(%i,r%i)", lo4, r4); else if (r8 == 0x4) debug("mov.b\t@(%i,r%i),r0", lo4, r4); if (running) { debug("\t; r%i+%i = 0x%08" PRIx32, r4, lo4, cpu->cd.sh.r[r4] + lo4); } debug("\n"); } else if (r8 == 1 || r8 == 5) { if (r8 == 0x1) debug("mov.w\tr0,@(%i,r%i)", lo4 * 2, r4); else if (r8 == 0x5) debug("mov.w\t@(%i,r%i),r0", lo4 * 2, r4); if (running) { debug("\t; r%i+%i = 0x%08" PRIx32, r4, lo4 * 2, cpu->cd.sh.r[r4] + lo4 * 2); } debug("\n"); } else if (r8 == 0x8) { debug("cmp/eq\t#%i,r0\n", (int8_t)lo8); } else if (r8 == 0x9 || r8 == 0xb || r8 == 0xd || r8 == 0xf) { addr = (int8_t)lo8; addr = dumpaddr + 4 + (addr << 1); debug("b%s%s\t0x%x", (r8 == 0x9 || r8 == 0xd)? "t" : "f", (r8 == 0x9 || r8 == 0xb)? "" : "/s", (int)addr); symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug("\t; <%s>", symbol); debug("\n"); } else debug("UNIMPLEMENTED hi4=0x%x,0x%x\n", hi4, r8); break; case 0x9: case 0xd: addr = lo8 * (hi4==9? 2 : 4); addr += (dumpaddr & ~(hi4==9? 1 : 3)) + 4; debug("mov.%s\t0x%x,r%i", hi4==9? "w":"l", (int)addr, r8); symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug("\t; <%s>", symbol); debug("\n"); break; case 0xa: case 0xb: addr = (int32_t)(int16_t)((iword & 0xfff) << 4); addr = ((int32_t)addr >> 3); addr += dumpaddr + 4; debug("%s\t0x%x", hi4==0xa? "bra":"bsr", (int)addr); symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug("\t; <%s>", symbol); debug("\n"); break; case 0xc: if (r8 == 0x0) debug("mov.b\tr0,@(%i,gbr)\n", lo8); else if (r8 == 0x1) debug("mov.w\tr0,@(%i,gbr)\n", lo8 * 2); else if (r8 == 0x2) debug("mov.l\tr0,@(%i,gbr)\n", lo8 * 4); else if (r8 == 0x3) debug("trapa\t#%i\n", (uint8_t)lo8); else if (r8 == 0x4) debug("mov.b\t(%i,gbr),r0\n", lo8); else if (r8 == 0x5) debug("mov.w\t(%i,gbr),r0\n", lo8 * 2); else if (r8 == 0x6) debug("mov.l\t(%i,gbr),r0\n", lo8 * 4); else if (r8 == 0x7) { addr = lo8 * 4 + (dumpaddr & ~3) + 4; debug("mova\t0x%x,r0\n", (int)addr); } else if (r8 == 0x8) debug("tst\t#%i,r0\n", (uint8_t)lo8); else if (r8 == 0x9) debug("and\t#%i,r0\n", (uint8_t)lo8); else if (r8 == 0xa) debug("xor\t#%i,r0\n", (uint8_t)lo8); else if (r8 == 0xb) debug("or\t#%i,r0\n", (uint8_t)lo8); else if (r8 == 0xc) debug("tst.b\t#%i,@(r0,gbr)\n", (uint8_t)lo8); else if (r8 == 0xd) debug("and.b\t#%i,@(r0,gbr)\n", (uint8_t)lo8); else if (r8 == 0xe) debug("xor.b\t#%i,@(r0,gbr)\n", (uint8_t)lo8); else if (r8 == 0xf) debug("or.b\t#%i,@(r0,gbr)\n", (uint8_t)lo8); else debug("UNIMPLEMENTED hi4=0x%x,0x%x\n", hi4, r8); break; case 0xe: debug("mov\t#%i,r%i\n", (int8_t)lo8, r8); break; case 0xf: if (lo4 == 0x0) debug("fadd\t%sr%i,%sr%i\n", cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r4, cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); else if (lo4 == 0x1) debug("fsub\t%sr%i,%sr%i\n", cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r4, cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); else if (lo4 == 0x2) debug("fmul\t%sr%i,%sr%i\n", cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r4, cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); else if (lo4 == 0x3) debug("fdiv\t%sr%i,%sr%i\n", cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r4, cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); else if (lo4 == 0x4) debug("fcmp/eq\t%sr%i,%sr%i\n", cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r4, cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); else if (lo4 == 0x5) debug("fcmp/gt\t%sr%i,%sr%i\n", cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r4, cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); else if (lo4 == 0x6) { const char *n = "fr"; if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { n = (r8 & 1)? "xd" : "dr"; r8 &= ~1; } debug("fmov\t@(r0,r%i),%s%i\n", r4, n, r8); } else if (lo4 == 0x7) { const char *n = "fr"; if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { n = (r4 & 1)? "xd" : "dr"; r4 &= ~1; } debug("fmov\t%s%i,@(r0,r%i)\n", n, r4, r8); } else if (lo4 == 0x8) { const char *n = "fr"; if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { n = (r8 & 1)? "xd" : "dr"; r8 &= ~1; } debug("fmov\t@r%i,%s%i\n", r4, n, r8); } else if (lo4 == 0x9) { const char *n = "fr"; if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { n = (r8 & 1)? "xd" : "dr"; r8 &= ~1; } debug("fmov\t@r%i+,%s%i\n", r4, n, r8); } else if (lo4 == 0xa) { const char *n = "fr"; if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { n = (r4 & 1)? "xd" : "dr"; r4 &= ~1; } debug("fmov\t%s%i,@r%i\n", n, r4, r8); } else if (lo4 == 0xb) { const char *n = "fr"; if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { n = (r4 & 1)? "xd" : "dr"; r4 &= ~1; } debug("fmov\t%s%i,@-r%i\n", n, r4, r8); } else if (lo4 == 0xc) { const char *n1 = "fr", *n2 = "fr"; if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { n1 = (r4 & 1)? "xd" : "dr"; n2 = (r8 & 1)? "xd" : "dr"; r4 &= ~1; r8 &= ~1; } debug("fmov\t%s%i,%s%i\n", n1, r4, n2, r8); } else if (lo8 == 0x0d) debug("fsts\tfpul,fr%i\n", r8); else if (lo8 == 0x1d) debug("flds\tfr%i,fpul\n", r8); else if (lo8 == 0x2d) debug("float\tfpul,%sr%i\n", cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); else if (lo8 == 0x3d) debug("ftrc\t%sr%i,fpul\n", cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); else if (lo8 == 0x4d) debug("fneg\t%sr%i\n", cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); else if (lo8 == 0x5d) debug("fabs\t%sr%i\n", cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); else if (lo8 == 0x6d) debug("fsqrt\t%sr%i\n", cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); else if (lo8 == 0x7d) debug("fsrra\tfr%i\n", r8); else if (lo8 == 0x8d) debug("fldi0\tfr%i\n", r8); else if (lo8 == 0x9d) debug("fldi1\tfr%i\n", r8); else if (lo8 == 0xad) debug("fcnvsd\tfpul,dr%i\n", r8); else if (lo8 == 0xbd) debug("fcnvds\tdr%i,fpul\n", r8); else if (lo8 == 0xed) debug("fipr\tfv%i,fv%i\n", (r8 & 3) << 2, r8 & 0xc); else if ((iword & 0x01ff) == 0x00fd) debug("fsca\tfpul,dr%i\n", r8); else if (iword == 0xf3fd) debug("fschg\n"); else if (iword == 0xfbfd) debug("frchg\n"); else if ((iword & 0xf3ff) == 0xf1fd) debug("ftrv\txmtrx,fv%i\n", r8 & 0xc); else if (lo4 == 0xe) debug("fmac\tfr0,fr%i,fr%i\n", r4, r8); else debug("UNIMPLEMENTED hi4=0x%x,0x%x\n", hi4, lo8); break; default:debug("UNIMPLEMENTED hi4=0x%x\n", hi4); } return sizeof(iword); } #include "tmp_sh_tail.cc" gxemul-0.6.1/src/cpus/generate_arm_dpi.c000644 001750 001750 00000011666 13402411502 020431 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include char *cond[16] = { "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "", "" }; char *op[16] = { "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn" }; static char *uppercase(char *l) { static char staticbuf[1000]; size_t i = 0; while (*l && i < sizeof(staticbuf)) { char u = *l++; if (u >= 'a' && u <= 'z') u -= 32; staticbuf[i++] = u; } if (i == sizeof(staticbuf)) i--; staticbuf[i] = 0; return staticbuf; } int main(int argc, char *argv[]) { int n, a, reg, pc, s, c; printf("\n/* AUTOMATICALLY GENERATED! Do not edit. */\n\n"); printf("#include \n#include \n" "#include \"cpu.h\"\n" "#include \"misc.h\"\n" "#define DYNTRANS_PC_TO_POINTERS arm_pc_to_pointers\n" "#include \"quick_pc_to_pointers.h\"\n" "#define reg(x) (*((uint32_t *)(x)))\n"); printf("extern void arm_instr_nop(struct cpu *, " "struct arm_instr_call *);\n"); printf("extern void arm_instr_invalid(struct cpu *, " "struct arm_instr_call *);\n"); printf("extern void arm_pc_to_pointers(struct cpu *);\n"); for (reg=0; reg<=2; reg++) for (pc=0; pc<=1; pc++) for (s=0; s<=1; s++) for (a=0; a<16; a++) { if (a >= 8 && a <= 11 && s == 0) continue; if (reg == 2 && pc) continue; printf("#define A__NAME arm_instr_%s%s%s%s\n", op[a], s? "s" : "", pc? "_pc" : "", reg? (reg==2? "_regshort" : "_reg") : ""); for (c=0; c<14; c++) printf("#define A__NAME__%s arm_instr_%s%s%s%s__%s\n", cond[c], op[a], s? "s" : "", pc? "_pc" : "", reg? (reg==2? "_regshort" : "_reg") : "", cond[c]); if (s) printf("#define A__S\n"); switch (reg) { case 1: printf("#define A__REG\n"); break; case 2: printf("#define A__REGSHORT\n"); break; } if (pc) printf("#define A__PC\n"); printf("#define A__%s\n", uppercase(op[a])); printf("#include \"cpu_arm_instr_dpi.cc\"\n"); printf("#undef A__%s\n", uppercase(op[a])); if (s) printf("#undef A__S\n"); switch (reg) { case 1: printf("#undef A__REG\n"); break; case 2: printf("#undef A__REGSHORT\n"); break; } if (pc) printf("#undef A__PC\n"); for (c=0; c<14; c++) printf("#undef A__NAME__%s\n", cond[c]); printf("#undef A__NAME\n"); } printf("\n\tvoid (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *,\n" "\t\tstruct arm_instr_call *) = {\n"); n = 0; for (reg=0; reg<=1; reg++) for (pc=0; pc<=1; pc++) for (s=0; s<=1; s++) for (a=0; a<16; a++) for (c=0; c<16; c++) { if (c == 15) printf("\tarm_instr_nop"); else if (a >= 8 && a <= 11 && s == 0) printf("\tarm_instr_invalid"); else printf("\tarm_instr_%s%s%s%s%s%s", op[a], s? "s" : "", pc? "_pc" : "", reg? "_reg" : "", c!=14? "__" : "", cond[c]); n++; if (n != 2 * 2 * 2 * 16 * 16) printf(","); printf("\n"); } printf("};\n\n"); printf("\n\tvoid (*arm_dpi_instr_regshort[2 * 16 * 16])(struct cpu *,\n" "\t\tstruct arm_instr_call *) = {\n"); n = 0; for (s=0; s<=1; s++) for (a=0; a<16; a++) for (c=0; c<16; c++) { if (c == 15) printf("\tarm_instr_nop"); else if (a >= 8 && a <= 11 && s == 0) printf("\tarm_instr_invalid"); else printf("\tarm_instr_%s%s_regshort%s%s", op[a], s? "s" : "", c!=14? "__" : "", cond[c]); n++; if (n != 2 * 16 * 16) printf(","); printf("\n"); } printf("};\n\n"); return 0; } gxemul-0.6.1/src/cpus/cpu_arm_instr_misc.cc000644 001750 001750 00000007766 13402411502 021175 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Misc ARM instructions. Included from cpu_arm_instr.c. */ /* * clear_rX: Move #0 into a register. (Optimization hack.) */ X(clear_r0) { cpu->cd.arm.r[ 0] = 0; } Y(clear_r0) X(clear_r1) { cpu->cd.arm.r[ 1] = 0; } Y(clear_r1) X(clear_r2) { cpu->cd.arm.r[ 2] = 0; } Y(clear_r2) X(clear_r3) { cpu->cd.arm.r[ 3] = 0; } Y(clear_r3) X(clear_r4) { cpu->cd.arm.r[ 4] = 0; } Y(clear_r4) X(clear_r5) { cpu->cd.arm.r[ 5] = 0; } Y(clear_r5) X(clear_r6) { cpu->cd.arm.r[ 6] = 0; } Y(clear_r6) X(clear_r7) { cpu->cd.arm.r[ 7] = 0; } Y(clear_r7) X(clear_r8) { cpu->cd.arm.r[ 8] = 0; } Y(clear_r8) X(clear_r9) { cpu->cd.arm.r[ 9] = 0; } Y(clear_r9) X(clear_r10) { cpu->cd.arm.r[10] = 0; } Y(clear_r10) X(clear_r11) { cpu->cd.arm.r[11] = 0; } Y(clear_r11) X(clear_r12) { cpu->cd.arm.r[12] = 0; } Y(clear_r12) X(clear_r13) { cpu->cd.arm.r[13] = 0; } Y(clear_r13) X(clear_r14) { cpu->cd.arm.r[14] = 0; } Y(clear_r14) /* * mov1_rX: Move #1 into a register. (Optimization hack.) */ X(mov1_r0) { cpu->cd.arm.r[ 0] = 1; } Y(mov1_r0) X(mov1_r1) { cpu->cd.arm.r[ 1] = 1; } Y(mov1_r1) X(mov1_r2) { cpu->cd.arm.r[ 2] = 1; } Y(mov1_r2) X(mov1_r3) { cpu->cd.arm.r[ 3] = 1; } Y(mov1_r3) X(mov1_r4) { cpu->cd.arm.r[ 4] = 1; } Y(mov1_r4) X(mov1_r5) { cpu->cd.arm.r[ 5] = 1; } Y(mov1_r5) X(mov1_r6) { cpu->cd.arm.r[ 6] = 1; } Y(mov1_r6) X(mov1_r7) { cpu->cd.arm.r[ 7] = 1; } Y(mov1_r7) X(mov1_r8) { cpu->cd.arm.r[ 8] = 1; } Y(mov1_r8) X(mov1_r9) { cpu->cd.arm.r[ 9] = 1; } Y(mov1_r9) X(mov1_r10) { cpu->cd.arm.r[10] = 1; } Y(mov1_r10) X(mov1_r11) { cpu->cd.arm.r[11] = 1; } Y(mov1_r11) X(mov1_r12) { cpu->cd.arm.r[12] = 1; } Y(mov1_r12) X(mov1_r13) { cpu->cd.arm.r[13] = 1; } Y(mov1_r13) X(mov1_r14) { cpu->cd.arm.r[14] = 1; } Y(mov1_r14) /* * add1_rX: Add #1 to a register. (Optimization hack.) */ X(add1_r0) { cpu->cd.arm.r[ 0] ++; } Y(add1_r0) X(add1_r1) { cpu->cd.arm.r[ 1] ++; } Y(add1_r1) X(add1_r2) { cpu->cd.arm.r[ 2] ++; } Y(add1_r2) X(add1_r3) { cpu->cd.arm.r[ 3] ++; } Y(add1_r3) X(add1_r4) { cpu->cd.arm.r[ 4] ++; } Y(add1_r4) X(add1_r5) { cpu->cd.arm.r[ 5] ++; } Y(add1_r5) X(add1_r6) { cpu->cd.arm.r[ 6] ++; } Y(add1_r6) X(add1_r7) { cpu->cd.arm.r[ 7] ++; } Y(add1_r7) X(add1_r8) { cpu->cd.arm.r[ 8] ++; } Y(add1_r8) X(add1_r9) { cpu->cd.arm.r[ 9] ++; } Y(add1_r9) X(add1_r10) { cpu->cd.arm.r[10] ++; } Y(add1_r10) X(add1_r11) { cpu->cd.arm.r[11] ++; } Y(add1_r11) X(add1_r12) { cpu->cd.arm.r[12] ++; } Y(add1_r12) X(add1_r13) { cpu->cd.arm.r[13] ++; } Y(add1_r13) X(add1_r14) { cpu->cd.arm.r[14] ++; } Y(add1_r14) gxemul-0.6.1/src/cpus/memory_ppc.cc000644 001750 001750 00000017543 13402411502 017461 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Included from cpu_ppc.c. */ /* * ppc_bat(): * * BAT translation. Returns -1 if there was no BAT hit, >= 0 for a hit. * (0 for access denied, 1 for read-only, and 2 for read-write access allowed.) */ int ppc_bat(struct cpu *cpu, uint64_t vaddr, uint64_t *return_paddr, int flags, int user) { int i, istart = 0, iend = 8, pp; if (flags & FLAG_INSTR) iend = 4; else istart = 4; if (cpu->cd.ppc.bits != 32) { fatal("TODO: ppc_bat() for non-32-bit\n"); exit(1); } if (cpu->cd.ppc.cpu_type.flags & PPC_601) { fatal("TODO: ppc_bat() for PPC 601\n"); exit(1); } /* Scan either the 4 instruction BATs or the 4 data BATs: */ for (i=istart; icd.ppc.spr[regnr]; uint32_t lower = cpu->cd.ppc.spr[regnr + 1]; uint32_t phys = lower & BAT_RPN, ebs = upper & BAT_EPI; uint32_t mask = ((upper & BAT_BL) << 15) | 0x1ffff; /* Not valid in either supervisor or user mode? */ if (user && !(upper & BAT_Vu)) continue; if (!user && !(upper & BAT_Vs)) continue; /* Virtual address mismatch? Then skip. */ if ((vaddr & ~mask) != (ebs & ~mask)) continue; *return_paddr = (vaddr & mask) | (phys & ~mask); pp = lower & BAT_PP; switch (pp) { case BAT_PP_NONE: return 0; case BAT_PP_RO_S: case BAT_PP_RO: return (flags & FLAG_WRITEFLAG)? 0 : 1; default:/* BAT_PP_RW: */ return 2; } } return -1; } /* * get_pte_low(): * * Scan a PTE group for a cmp (compare) value. * * Returns 1 if the value was found, and *lowp is set to the low PTE word. * Returns 0 if no match was found. */ static int get_pte_low(struct cpu *cpu, uint64_t pteg_select, uint32_t *lowp, uint32_t cmp) { unsigned char *d = memory_paddr_to_hostaddr(cpu->mem, pteg_select, 1); int i; for (i=0; i<8; i++) { uint32_t *ep = (uint32_t *) (d + (i << 3)), upper; upper = *ep; upper = BE32_TO_HOST(upper); /* Valid PTE, and correct api and vsid? */ if (upper == cmp) { uint32_t lo = ep[1]; lo = BE32_TO_HOST(lo); *lowp = lo; return 1; } } return 0; } /* * ppc_vtp32(): * * Virtual to physical address translation (32-bit mode). * * Returns 1 if a translation was found, 0 if none was found. However, finding * a translation does not mean that it should be returned; there can be * a permission violation. *resp is set to 0 for no access, 1 for read-only * access, or 2 for read/write access. */ static int ppc_vtp32(struct cpu *cpu, uint32_t vaddr, uint64_t *return_paddr, int *resp, uint64_t msr, int writeflag, int instr) { int srn = (vaddr >> 28) & 15, api = (vaddr >> 22) & PTE_API; int access, key, match; uint32_t vsid = cpu->cd.ppc.sr[srn] & 0x00ffffff; uint64_t sdr1 = cpu->cd.ppc.spr[SPR_SDR1], htaborg; uint32_t hash1, hash2, pteg_select, tmp; uint32_t lower_pte = 0, cmp; htaborg = sdr1 & 0xffff0000UL; /* Primary hash: */ hash1 = (vsid & 0x7ffff) ^ ((vaddr >> 12) & 0xffff); tmp = (hash1 >> 10) & (sdr1 & 0x1ff); pteg_select = htaborg & 0xfe000000; pteg_select |= ((hash1 & 0x3ff) << 6); pteg_select |= (htaborg & 0x01ff0000) | (tmp << 16); cpu->cd.ppc.spr[SPR_HASH1] = pteg_select; cmp = cpu->cd.ppc.spr[instr? SPR_ICMP : SPR_DCMP] = PTE_VALID | api | (vsid << PTE_VSID_SHFT); match = get_pte_low(cpu, pteg_select, &lower_pte, cmp); /* Secondary hash: */ hash2 = hash1 ^ 0x7ffff; tmp = (hash2 >> 10) & (sdr1 & 0x1ff); pteg_select = htaborg & 0xfe000000; pteg_select |= ((hash2 & 0x3ff) << 6); pteg_select |= (htaborg & 0x01ff0000) | (tmp << 16); cpu->cd.ppc.spr[SPR_HASH2] = pteg_select; if (!match) { cmp |= PTE_HID; match = get_pte_low(cpu, pteg_select, &lower_pte, cmp); } *resp = 0; if (!match) return 0; /* Non-executable, or Guarded page? */ if (instr && cpu->cd.ppc.sr[srn] & SR_NOEXEC) return 1; if (instr && lower_pte & PTE_G) return 1; access = lower_pte & PTE_PP; *return_paddr = (lower_pte & PTE_RPGN) | (vaddr & ~PTE_RPGN); key = (cpu->cd.ppc.sr[srn] & SR_PRKEY && msr & PPC_MSR_PR) || (cpu->cd.ppc.sr[srn] & SR_SUKEY && !(msr & PPC_MSR_PR)); if (key) { switch (access) { case 1: case 3: *resp = writeflag? 0 : 1; break; case 2: *resp = 2; break; } } else { switch (access) { case 3: *resp = writeflag? 0 : 1; break; default:*resp = 2; } } return 1; } /* * ppc_translate_v2p(): * * Return values: * 0 Failure * 1 Success, the page is readable only * 2 Success, the page is read/write */ int ppc_translate_v2p(struct cpu *cpu, uint64_t vaddr, uint64_t *return_paddr, int flags) { int instr = flags & FLAG_INSTR, res = 0, match, user; int writeflag = flags & FLAG_WRITEFLAG? 1 : 0; uint64_t msr; reg_access_msr(cpu, &msr, 0, 0); user = msr & PPC_MSR_PR? 1 : 0; if (cpu->cd.ppc.bits == 32) vaddr &= 0xffffffff; if ((instr && !(msr & PPC_MSR_IR)) || (!instr && !(msr & PPC_MSR_DR))) { *return_paddr = vaddr; return 2; } if (cpu->cd.ppc.cpu_type.flags & PPC_601) { fatal("ppc_translate_v2p(): TODO: 601\n"); exit(1); } /* Try the BATs first: */ if (cpu->cd.ppc.bits == 32) { res = ppc_bat(cpu, vaddr, return_paddr, flags, user); if (res > 0) return res; if (res == 0) { fatal("[ TODO: BAT exception ]\n"); exit(1); } } /* Virtual to physical translation: */ if (cpu->cd.ppc.bits == 32) { match = ppc_vtp32(cpu, vaddr, return_paddr, &res, msr, writeflag, instr); if (match && res > 0) return res; } else { /* htaborg = sdr1 & 0xfffffffffffc0000ULL; */ fatal("TODO: ppc 64-bit translation\n"); exit(1); } /* * No match? Then cause an exception. * * PPC603: cause a software TLB reload exception. * All others: cause a DSI or ISI. */ if (flags & FLAG_NOEXCEPTIONS) return 0; if (!quiet_mode) fatal("[ memory_ppc: exception! vaddr=0x%" PRIx64" pc=0x%" PRIx64 " instr=%i user=%i wf=%i ]\n", (uint64_t) vaddr, (uint64_t) cpu->pc, instr, user, writeflag); if (cpu->cd.ppc.cpu_type.flags & PPC_603) { cpu->cd.ppc.spr[instr? SPR_IMISS : SPR_DMISS] = vaddr; msr |= PPC_MSR_TGPR; reg_access_msr(cpu, &msr, 1, 0); ppc_exception(cpu, instr? 0x10 : (writeflag? 0x12 : 0x11)); } else { if (!instr) { cpu->cd.ppc.spr[SPR_DAR] = vaddr; cpu->cd.ppc.spr[SPR_DSISR] = match? DSISR_PROTECT : DSISR_NOTFOUND; if (writeflag) cpu->cd.ppc.spr[SPR_DSISR] |= DSISR_STORE; } ppc_exception(cpu, instr? PPC_EXCEPTION_ISI : PPC_EXCEPTION_DSI); } return 0; } gxemul-0.6.1/src/cpus/generate_m88k_loadstore.c000644 001750 001750 00000015472 13402411502 021660 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Automatic generation of M88K loads and stores: * * 2 bits size (0=byte, 1=halfword, 2=word, 3=doubleword) * 1 bit load/store * 1 bit signedness (for byte and halfword loads only!) * 1 bit endianness * 1 bit scaledness (for halfword, word, and doublewords only, * and only when using register offset) * 1 bit ".usr" (only when using register offset) * 1 bit registeroffset */ #include #include #define M88K_LOADSTORE_STORE 4 #define M88K_LOADSTORE_SIGNEDNESS 8 #define M88K_LOADSTORE_ENDIANNESS 16 #define M88K_LOADSTORE_SCALEDNESS 32 #define M88K_LOADSTORE_USR 64 #define M88K_LOADSTORE_REGISTEROFFSET 128 int generated_functions = 0; void print_function_name(int size, int store, int signedness, int endianness, int scaledness, int usr, int registeroffset) { if (store) printf("st"); else { printf("ld"); if (!signedness) printf("_u"); } printf("_%i", 1 << size); if (endianness >= 0) { /* Special case so that Byte loads/stores are only included ones (for little endian): */ if (size == 0 && endianness) printf("_le"); else printf(endianness? "_be" : "_le"); } if (scaledness && size > 0) printf("_scaled"); if (usr) printf("_usr"); if (registeroffset) printf("_regofs"); } void loadstore(int size, int store, int signedness, int endianness, int scaledness, int usr, int registeroffset) { if (store && signedness) return; if (size == 0 && endianness) return; if (size == 0 && scaledness) return; if (!registeroffset && usr) return; if (!registeroffset && scaledness) return; if (store) printf("#define LS_STORE\n"); else printf("#define LS_LOAD\n"); printf("#define LS_N m88k_instr_"); print_function_name(size, store, signedness, endianness, scaledness, usr, registeroffset); printf("\n"); printf("#define LS_GENERIC_N m88k_generic_"); print_function_name(size, store, signedness, -1, scaledness, usr, registeroffset); printf("\n"); printf("#define LS_%i\n", 1 << size); printf("#define LS_SIZE %i\n", 1 << size); if (signedness && !store) printf("#define LS_SIGNED\n"); if (endianness) printf("#define LS_BE\n"); else printf("#define LS_LE\n"); if (endianness == 0) printf("#define LS_INCLUDE_GENERIC\n"); if (scaledness) printf("#define LS_SCALED\n"); if (usr) printf("#define LS_USR\n"); if (registeroffset) printf("#define LS_REGOFS\n"); printf("#include \"cpu_m88k_instr_loadstore.cc\"\n"); generated_functions ++; if (registeroffset) printf("#undef LS_REGOFS\n"); if (usr) printf("#undef LS_USR\n"); if (scaledness) printf("#undef LS_SCALED\n"); if (endianness == 0) printf("#undef LS_INCLUDE_GENERIC\n"); if (endianness) printf("#undef LS_BE\n"); else printf("#undef LS_LE\n"); if (signedness && !store) printf("#undef LS_SIGNED\n"); printf("#undef LS_SIZE\n"); printf("#undef LS_%i\n", 1 << size); printf("#undef LS_GENERIC_N\n"); printf("#undef LS_N\n"); if (store) printf("#undef LS_STORE\n"); else printf("#undef LS_LOAD\n"); } int main(int argc, char *argv[]) { int size, store, signedness, endianness, scaledness, usr, registeroffset; printf("\n/* AUTOMATICALLY GENERATED! Do not edit. */\n\n"); for (registeroffset=0; registeroffset<=M88K_LOADSTORE_REGISTEROFFSET; registeroffset+=M88K_LOADSTORE_REGISTEROFFSET) for (usr=0; usr<=M88K_LOADSTORE_USR; usr+=M88K_LOADSTORE_USR) for (scaledness=0; scaledness<=M88K_LOADSTORE_SCALEDNESS; scaledness+=M88K_LOADSTORE_SCALEDNESS) for (endianness=0; endianness<=M88K_LOADSTORE_ENDIANNESS; endianness+=M88K_LOADSTORE_ENDIANNESS) for (signedness=0; signedness<=M88K_LOADSTORE_SIGNEDNESS; signedness+=M88K_LOADSTORE_SIGNEDNESS) for (store=0; store<=M88K_LOADSTORE_STORE; store+=M88K_LOADSTORE_STORE) for (size=0; size<=3; size++) loadstore(size, store, signedness, endianness, scaledness, usr, registeroffset); /* Array of pointers to fast load/store functions: */ printf("\n\nvoid (*m88k_loadstore[256])(struct cpu *, struct " "m88k_instr_call *) = {\n"); for (registeroffset=0; registeroffset<=M88K_LOADSTORE_REGISTEROFFSET; registeroffset+=M88K_LOADSTORE_REGISTEROFFSET) for (usr=0; usr<=M88K_LOADSTORE_USR; usr+=M88K_LOADSTORE_USR) for (scaledness=0; scaledness<=M88K_LOADSTORE_SCALEDNESS; scaledness+=M88K_LOADSTORE_SCALEDNESS) for (endianness=0; endianness<=M88K_LOADSTORE_ENDIANNESS; endianness+=M88K_LOADSTORE_ENDIANNESS) for (signedness=0; signedness<=M88K_LOADSTORE_SIGNEDNESS; signedness+=M88K_LOADSTORE_SIGNEDNESS) for (store=0; store<=M88K_LOADSTORE_STORE; store+=M88K_LOADSTORE_STORE) for (size=0; size<=3; size++) { if (store || size || signedness || endianness || scaledness || usr || registeroffset) printf(",\n"); if (store && signedness) { printf("\tNULL"); continue; } if (!registeroffset && usr) { printf("\tNULL"); continue; } if (!registeroffset && scaledness) { printf("\tNULL"); continue; } if (size == 0 && scaledness) { printf("\tNULL"); continue; } printf("\tm88k_instr_"); print_function_name(size, store, signedness, endianness, scaledness, usr, registeroffset); } printf(" };\n"); fprintf(stderr, "%s: generated_functions = %i\n", argv[0], generated_functions); return 0; } gxemul-0.6.1/src/cpus/cpu_arm_coproc.cc000644 001750 001750 00000033253 13402411502 020276 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * ARM coprocessor emulation. */ #include #include #include #include #include #include "cpu.h" #include "machine.h" #include "misc.h" #include "symbol.h" #include "thirdparty/i80321reg.h" /* * arm_coproc_15(): * * The system control coprocessor. */ void arm_coproc_15(struct cpu *cpu, int opcode1, int opcode2, int l_bit, int crn, int crm, int rd) { uint32_t old_control; /* Some sanity checks: */ if (opcode1 != 0) { fatal("arm_coproc_15: opcode1 = %i, should be 0\n", opcode1); exit(1); } if (rd == ARM_PC) { fatal("arm_coproc_15: rd = PC\n"); exit(1); } switch (crn) { case 0: /* * Main ID register (and Cache Type register, on XScale) * * Writes are supposed to be ignored, according to Intel docs. */ switch (opcode2) { case 0: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.cpu_type.cpu_id; else fatal("[ arm_coproc_15: attempt to write " "to the Main ID register? ]\n"); break; case 1: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.cachetype; else fatal("[ arm_coproc_15: attempt to write " "to the Cache Type register? ]\n"); break; default:fatal("[ arm_coproc_15: TODO: cr0, opcode2=%i ]\n", opcode2); exit(1); } break; case 1: /* Control Register: */ if (l_bit) { /* Load from the normal/aux control register: */ switch (opcode2) { case 0: cpu->cd.arm.r[rd] = cpu->cd.arm.control; break; case 1: cpu->cd.arm.r[rd] = cpu->cd.arm.auxctrl; break; default:fatal("Unimplemented opcode2 = %i\n", opcode2); fatal("(opcode1=%i crn=%i crm=%i rd=%i l=%i)\n", opcode1, crn, crm, rd, l_bit); exit(1); } return; } if (opcode2 == 1) { /* Write to auxctrl: */ old_control = cpu->cd.arm.auxctrl; cpu->cd.arm.auxctrl = cpu->cd.arm.r[rd]; if ((old_control & ARM_AUXCTRL_MD) != (cpu->cd.arm.auxctrl & ARM_AUXCTRL_MD)) { debug("[ setting the minidata cache attribute" " to 0x%x ]\n", (cpu->cd.arm.auxctrl & ARM_AUXCTRL_MD) >> ARM_AUXCTRL_MD_SHIFT); } if ((old_control & ARM_AUXCTRL_K) != (cpu->cd.arm.auxctrl & ARM_AUXCTRL_K)) { debug("[ %s write buffer coalescing ]\n", cpu->cd.arm.auxctrl & ARM_AUXCTRL_K? "Disabling" : "Enabling"); } return; } else if (opcode2 != 0) { fatal("Unimplemented write, opcode2 = %i\n", opcode2); fatal("(opcode1=%i crn=%i crm=%i rd=%i l=%i)\n", opcode1, crn, crm, rd, l_bit); exit(1); } /* * Write to control: Check each bit individually: */ old_control = cpu->cd.arm.control; cpu->cd.arm.control = cpu->cd.arm.r[rd]; if ((old_control & ARM_CONTROL_MMU) != (cpu->cd.arm.control & ARM_CONTROL_MMU)) { debug("[ %s the MMU ]\n", cpu->cd.arm.control & ARM_CONTROL_MMU? "enabling" : "disabling"); cpu->translate_v2p = cpu->cd.arm.control & ARM_CONTROL_MMU? arm_translate_v2p_mmu : arm_translate_v2p; } if ((old_control & ARM_CONTROL_ALIGN) != (cpu->cd.arm.control & ARM_CONTROL_ALIGN)) debug("[ %s alignment checks ]\n", cpu->cd.arm.control & ARM_CONTROL_ALIGN? "enabling" : "disabling"); if ((old_control & ARM_CONTROL_CACHE) != (cpu->cd.arm.control & ARM_CONTROL_CACHE)) debug("[ %s the [data] cache ]\n", cpu->cd.arm.control & ARM_CONTROL_CACHE? "enabling" : "disabling"); if ((old_control & ARM_CONTROL_WBUFFER) != (cpu->cd.arm.control & ARM_CONTROL_WBUFFER)) debug("[ %s the write buffer ]\n", cpu->cd.arm.control & ARM_CONTROL_WBUFFER? "enabling" : "disabling"); old_control &= ~ARM_CONTROL_BIG; if (cpu->byte_order == EMUL_BIG_ENDIAN) old_control |= ARM_CONTROL_BIG; if ((old_control & ARM_CONTROL_BIG) != (cpu->cd.arm.control & ARM_CONTROL_BIG)) { fatal("ERROR: Trying to switch endianness. Not " "supported yet.\n"); exit(1); } if ((old_control & ARM_CONTROL_ICACHE) != (cpu->cd.arm.control & ARM_CONTROL_ICACHE)) debug("[ %s the icache ]\n", cpu->cd.arm.control & ARM_CONTROL_ICACHE? "enabling" : "disabling"); /* TODO: More bits. */ break; case 2: /* Translation Table Base register: */ /* NOTE: 16 KB aligned. */ if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.ttb & 0xffffc000; else { cpu->cd.arm.ttb = cpu->cd.arm.r[rd]; if (cpu->cd.arm.ttb & 0x3fff) fatal("[ WARNING! low bits of new TTB non-" "zero? 0x%08x ]\n", cpu->cd.arm.ttb); cpu->cd.arm.ttb &= 0xffffc000; } break; case 3: /* Domain Access Control Register: */ if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.dacr; else cpu->cd.arm.dacr = cpu->cd.arm.r[rd]; break; case 5: /* Fault Status Register: */ /* Note: Only the lowest 8 bits are defined. */ if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.fsr & 0xff; else cpu->cd.arm.fsr = cpu->cd.arm.r[rd] & 0xff; break; case 6: /* Fault Address Register: */ if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.far; else cpu->cd.arm.far = cpu->cd.arm.r[rd]; break; case 7: /* Cache functions: */ if (l_bit) { fatal("[ arm_coproc_15: attempt to read cr7? ]\n"); return; } /* debug("[ arm_coproc_15: cache op: TODO ]\n"); */ /* TODO: */ break; case 8: /* TLB functions: */ if (l_bit) { fatal("[ arm_coproc_15: attempt to read cr8? ]\n"); return; } /* fatal("[ arm_coproc_15: TLB: op2=%i crm=%i rd=0x%08x ]\n", opcode2, crm, cpu->cd.arm.r[rd]); */ if (opcode2 == 0) cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); else cpu->invalidate_translation_caches(cpu, cpu->cd.arm.r[rd], INVALIDATE_VADDR); break; case 9: /* Cache lockdown: */ fatal("[ arm_coproc_15: cache lockdown: TODO ]\n"); /* TODO */ break; case 13:/* Process ID Register: */ if (opcode2 != 0) fatal("[ arm_coproc_15: PID access, but opcode2 " "= %i? (should be 0) ]\n", opcode2); if (crm != 0) fatal("[ arm_coproc_15: PID access, but crm " "= %i? (should be 0) ]\n", crm); if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.pid; else cpu->cd.arm.pid = cpu->cd.arm.r[rd]; if (cpu->cd.arm.pid != 0) { fatal("ARM TODO: pid!=0. Fast Context Switch" " Extension not implemented yet\n"); exit(1); } break; /* case 14: */ /* Breakpoint registers on XScale (possibly others?) */ /* TODO */ /* break; */ case 15:/* IMPLEMENTATION DEPENDENT! */ switch (crm) { case 1: /* * On XScale (and others? TODO), this is the * CoProcessor Access Register. Note/TODO: This isn't * really used throughout the rest of the code yet. */ if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.cpar; else cpu->cd.arm.cpar = cpu->cd.arm.r[rd]; break; default:fatal("[ arm_coproc_15: TODO: IMPLEMENTATION " "DEPENDENT! ]\n"); exit(1); } break; default:fatal("arm_coproc_15: unimplemented crn = %i\n", crn); fatal("(opcode1=%i opcode2=%i crm=%i rd=%i l=%i)\n", opcode1, opcode2, crm, rd, l_bit); exit(1); } } /* * arm_coproc_i80321_6(): * * Intel 80321 coprocessor 6. */ void arm_coproc_i80321_6(struct cpu *cpu, int opcode1, int opcode2, int l_bit, int crn, int crm, int rd) { switch (crm) { case 0: switch (crn) { case 0: if (l_bit) { cpu->cd.arm.r[rd] = cpu->cd.arm.i80321_inten; fatal("TODO: XScale read from inten?\n"); exit(1); } else cpu->cd.arm.i80321_inten = cpu->cd.arm.r[rd]; break; case 4: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.i80321_isteer; else { cpu->cd.arm.i80321_isteer = cpu->cd.arm.r[rd]; if (cpu->cd.arm.r[rd] != 0) { fatal("ARM xscale interrupt steering" " is not yet implemented\n"); exit(1); } } break; case 8: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.i80321_isrc; else { cpu->cd.arm.i80321_isrc = cpu->cd.arm.r[rd]; fatal("TODO: XScale int ack?\n"); exit(1); } break; default:goto unknown; } break; case 1: /* fatal("TIMER opcode1=%i opcode2=%i crn=" "%i crm=%i rd=%i l=%i)\n", opcode1, opcode2, crn, crm, rd, l_bit); */ switch (crn) { case 0: /* tmr0: */ if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.tmr0; else cpu->cd.arm.tmr0 = cpu->cd.arm.r[rd]; break; case 1: /* tmr1: */ if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.tmr1; else cpu->cd.arm.tmr1 = cpu->cd.arm.r[rd]; break; case 2: /* tcr0: */ if (l_bit) { /* NOTE/TODO: Ugly hack: timer increment */ cpu->cd.arm.tcr0 ++; cpu->cd.arm.r[rd] = cpu->cd.arm.tcr0; } else { cpu->cd.arm.tcr0 = cpu->cd.arm.r[rd]; } break; case 3: /* tcr1: */ if (l_bit) { /* NOTE/TODO: Ugly hack: timer increment */ cpu->cd.arm.tcr1 ++; cpu->cd.arm.r[rd] = cpu->cd.arm.tcr1; } else { cpu->cd.arm.tcr1 = cpu->cd.arm.r[rd]; } break; case 4: /* trr0: */ if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.trr0; else cpu->cd.arm.trr0 = cpu->cd.arm.r[rd]; break; case 5: /* trr1: */ if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.trr1; else cpu->cd.arm.trr1 = cpu->cd.arm.r[rd]; break; case 6: /* tisr: */ if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.tisr; else { /* Writing clears interrupts: */ cpu->cd.arm.tisr &= ~cpu->cd.arm.r[rd]; if (!(cpu->cd.arm.tisr & TISR_TMR0)) INTERRUPT_DEASSERT( cpu->cd.arm.tmr0_irq); if (!(cpu->cd.arm.tisr & TISR_TMR1)) INTERRUPT_DEASSERT( cpu->cd.arm.tmr1_irq); } break; case 7: /* wdtcr: */ if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.wdtcr; else cpu->cd.arm.wdtcr = cpu->cd.arm.r[rd]; break; default:goto unknown; } break; default:goto unknown; } return; unknown: fatal("arm_coproc_i80321_6: unimplemented opcode1=%i opcode2=%i crn=" "%i crm=%i rd=%i l=%i)\n", opcode1, opcode2, crn, crm, rd, l_bit); exit(1); } /* * arm_coproc_xscale_14(): * * XScale coprocessor 14, Performance Monitoring Unit. */ void arm_coproc_xscale_14(struct cpu *cpu, int opcode1, int opcode2, int l_bit, int crn, int crm, int rd) { if (opcode2 != 0) { fatal("TODO: opcode2 = %i\n", opcode2); goto unknown; } switch (crm) { case 0: switch (crn) { case 0: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.xsc1_pmnc; else cpu->cd.arm.xsc1_pmnc = cpu->cd.arm.r[rd]; break; case 1: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.xsc1_ccnt; else cpu->cd.arm.xsc1_ccnt = cpu->cd.arm.r[rd]; break; case 2: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.xsc1_pmn0; else cpu->cd.arm.xsc1_pmn0 = cpu->cd.arm.r[rd]; break; case 3: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.xsc1_pmn1; else cpu->cd.arm.xsc1_pmn1 = cpu->cd.arm.r[rd]; break; case 7: /* UNIMPLEMENTED!!! TODO */ /* Possibly some kind of idle or sleep function. */ break; default:goto unknown; } break; case 1: switch (crn) { case 0: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmnc; else cpu->cd.arm.xsc2_pmnc = cpu->cd.arm.r[rd]; break; case 1: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_ccnt; else cpu->cd.arm.xsc2_ccnt = cpu->cd.arm.r[rd]; break; case 4: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_inten; else cpu->cd.arm.xsc2_inten = cpu->cd.arm.r[rd]; break; case 5: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_flag; else cpu->cd.arm.xsc2_flag = cpu->cd.arm.r[rd]; break; case 8: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_evtsel; else cpu->cd.arm.xsc2_evtsel = cpu->cd.arm.r[rd]; break; default:goto unknown; } break; case 2: switch (crn) { case 0: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmn0; else cpu->cd.arm.xsc2_pmn0 = cpu->cd.arm.r[rd]; break; case 1: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmn1; else cpu->cd.arm.xsc2_pmn1 = cpu->cd.arm.r[rd]; break; case 2: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmn2; else cpu->cd.arm.xsc2_pmn2 = cpu->cd.arm.r[rd]; break; case 3: if (l_bit) cpu->cd.arm.r[rd] = cpu->cd.arm.xsc2_pmn3; else cpu->cd.arm.xsc2_pmn3 = cpu->cd.arm.r[rd]; break; default:goto unknown; } break; default:goto unknown; } return; unknown: fatal("arm_coproc_xscale_14: unimplemented opcode1=%i opcode2=" "%i crn=%i crm=%i rd=%i l=%i)\n", opcode1, opcode2, crn, crm, rd, l_bit); exit(1); } gxemul-0.6.1/src/cpus/generate_arm_multi.c000644 001750 001750 00000024776 13402411502 021015 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Generation of commonly used ARM load/store multiple instructions. * * The main idea is to first check whether a load/store would be possible * without going outside a page, and if so, use the host_load or _store * arrays for quick access to emulated RAM. Otherwise, fall back to using * the generic bdt_load() or bdt_store(). */ #include #include #include /* * generate_opcode(): * * Given an ARM load/store multiple opcode, produce equivalent "hardcoded" * C code which emulates the opcode. * * TODO: * * o) On 64-bit hosts, load/store two registers at a time. This * feature depends both on the alignment of the base register, * and the specific set of registers being loaded/stored. * * o) Alignment checks. (Optional?) * * o) For accesses that cross page boundaries, use two pages using * the fast method instead of calling the generic function? */ void generate_opcode(uint32_t opcode) { int p, u, s, w, load, r, n_regs, i, x; if ((opcode & 0x0e000000) != 0x08000000) { fprintf(stderr, "opcode 0x%08"PRIx32" is not an ldm/stm\n", opcode); exit(1); } r = (opcode >> 16) & 15; p = opcode & 0x01000000? 1 : 0; u = opcode & 0x00800000? 1 : 0; s = opcode & 0x00400000? 1 : 0; w = opcode & 0x00200000? 1 : 0; load = opcode & 0x00100000? 1 : 0; n_regs = 0; for (i=0; i<16; i++) if (opcode & (1 << i)) n_regs ++; /* TODO: Check for register pairs, for 64-bit load/stores */ if (n_regs == 0) { fprintf(stderr, "opcode 0x%08"PRIx32" has no registers set\n", opcode); exit(1); } if (s) { fprintf(stderr, "opcode 0x%08"PRIx32" has s-bit set\n", opcode); exit(1); } if (r == 15) { fprintf(stderr, "opcode 0x%08"PRIx32" has r=15\n", opcode); exit(1); } printf("\nvoid arm_instr_multi_0x%08"PRIx32"(struct cpu *cpu," " struct arm_instr_call *ic) {\n", opcode); printf("\tunsigned char *page;\n"); printf("\tuint32_t addr = cpu->cd.arm.r[%i];\n", r); if (!load && opcode & 0x8000) { printf("\tuint32_t tmp_pc = ((size_t)ic - (size_t)\n\t" " cpu->cd.arm.cur_ic_page) / sizeof(struct " "arm_instr_call);\n" "\ttmp_pc = ((cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1)" "\n\t << ARM_INSTR_ALIGNMENT_SHIFT)))\n" "\t + (tmp_pc << ARM_INSTR_ALIGNMENT_SHIFT) + 12;\n"); } if (p) printf("\taddr %s 4;\n", u? "+=" : "-="); printf("\tpage = cpu->cd.arm.host_%s[addr >> 12];\n", load? "load" : "store"); printf("\taddr &= 0xffc;\n"); printf("\tif ("); switch (p*2 + u) { case 0: /* post-decrement */ if (n_regs > 1) printf("addr >= 0x%x && ", 4*(n_regs-1)); break; case 1: /* post-increment */ if (n_regs > 1) printf("addr <= 0x%x && ", 0x1000 - 4*n_regs); break; case 2: /* pre-decrement */ if (n_regs > 1) printf("addr >= 0x%x && ", 4*(n_regs-1)); break; case 3: /* pre-increment */ if (n_regs > 1) printf("addr <= 0x%x && ", 0x1000 - 4*n_regs); break; } printf("page != NULL) {\n"); printf("\t\tuint32_t *p = (uint32_t *) (page + addr);\n"); if (u) { x = 0; for (i=0; i<=15; i++) { if (!(opcode & (1 << i))) continue; if (load && w && i == r) { /* Skip the load if we're using writeback. */ } else if (load) { if (i == 15) printf("\t\tcpu->pc = p[%i];\n", x); else printf("\t\tcpu->cd.arm.r[%i] = " "p[%i];\n", i, x); } else { if (i == 15) printf("\t\tp[%i] = tmp_pc;\n", x); else printf("\t\tp[%i] = cpu->cd.arm.r" "[%i];\n", x, i); } x ++; } } else { /* Decrementing, but do it incrementing anyway: */ x = -n_regs; for (i=0; i<=15; i++) { if (!(opcode & (1 << i))) continue; x ++; if (load && w && i == r) { /* Skip the load if we're using writeback. */ } else if (load) { if (i == 15) printf("\t\tcpu->pc = p[%i];\n", x); else printf("\t\tcpu->cd.arm.r[%i] = " "p[%i];\n", i, x); } else { if (i == 15) printf("\t\tp[%i] = tmp_pc;\n", x); else printf("\t\tp[%i] = " "cpu->cd.arm.r[%i];\n", x, i); } } } if (w) printf("\t\tcpu->cd.arm.r[%i] %s %i;\n", r, u? "+=" : "-=", 4*n_regs); if (load && opcode & 0x8000) { printf("\t\tquick_pc_to_pointers(cpu);\n"); } printf("\t} else\n"); printf("\t\tinstr(bdt_%s)(cpu, ic);\n", load? "load" : "store"); printf("}\nY(multi_0x%08"PRIx32")\n", opcode); } /* * main(): * * Normal ARM code seems to only use about a few hundred of the 1^24 possible * load/store multiple instructions. (I'm not counting the s-bit now.) * Instead of having a linear array of 100s of entries, we can select a list * to scan based on a few bits (*), and those lists will be shorter. * * (*) By running experiment_arm_multi.c on statistics gathered from running * NetBSD/cats, it seems that choosing the following 8 bits results in * the shortest linear lists: * * xxxx100P USWLnnnn llllllll llllllll * ^ ^ ^ ^ ^ ^ ^ ^ (0x00950154) */ int main(int argc, char *argv[]) { int i, j; int n_used[256]; if (argc < 2) { fprintf(stderr, "usage: %s opcode [..]\n", argv[0]); exit(1); } printf("\n/* AUTOMATICALLY GENERATED! Do not edit. */\n\n" "#include \n" "#include \n" "#include \"cpu.h\"\n" "#include \"misc.h\"\n" "#define DYNTRANS_PC_TO_POINTERS arm_pc_to_pointers\n" "#include \"quick_pc_to_pointers.h\"\n" "#include \"arm_tmphead_1.h\"\n" "\n#define instr(x) arm_instr_ ## x\n"); printf("extern void arm_pc_to_pointers(struct cpu *);\n"); printf("extern void arm_instr_nop(struct cpu *, " "struct arm_instr_call *);\n"); printf("extern void arm_instr_bdt_load(struct cpu *, " "struct arm_instr_call *);\n"); printf("extern void arm_instr_bdt_store(struct cpu *, " "struct arm_instr_call *);\n"); printf("\n\n"); /* Generate the opcode functions: */ for (i=1; i> 16) |((zz & 0x00100000) >> 14) |((zz & 0x00040000) >> 13) |((zz & 0x00010000) >> 12) |((zz & 0x00000100) >> 5) |((zz & 0x00000040) >> 4) |((zz & 0x00000010) >> 3) |((zz & 0x00000004) >> 2); if (zz == j) n++; } printf("\nuint32_t multi_opcode_%i[%i] = {\n", j, n+1); for (i=1; i> 16) |((zz & 0x00100000) >> 14) |((zz & 0x00040000) >> 13) |((zz & 0x00010000) >> 12) |((zz & 0x00000100) >> 5) |((zz & 0x00000040) >> 4) |((zz & 0x00000010) >> 3) |((zz & 0x00000004) >> 2); if (zz == j) printf("\t0x%08x,\n", zz0); } printf("0 };\n"); } /* Generate 256 tables with function pointers: */ for (j=0; j<256; j++) { int n = 0, zz, zz0; for (i=1; i> 16) |((zz & 0x00100000) >> 14) |((zz & 0x00040000) >> 13) |((zz & 0x00010000) >> 12) |((zz & 0x00000100) >> 5) |((zz & 0x00000040) >> 4) |((zz & 0x00000010) >> 3) |((zz & 0x00000004) >> 2); if (zz == j) n++; } n_used[j] = n; if (n == 0) continue; printf("void (*multi_opcode_f_%i[%i])(struct cpu *," " struct arm_instr_call *) = {\n", j, n*16); for (i=1; i> 16) |((zz & 0x00100000) >> 14) |((zz & 0x00040000) >> 13) |((zz & 0x00010000) >> 12) |((zz & 0x00000100) >> 5) |((zz & 0x00000040) >> 4) |((zz & 0x00000010) >> 3) |((zz & 0x00000004) >> 2); if (zz == j) { printf("\tarm_instr_multi_0x%08x__eq,\n", zz0); printf("\tarm_instr_multi_0x%08x__ne,\n", zz0); printf("\tarm_instr_multi_0x%08x__cs,\n", zz0); printf("\tarm_instr_multi_0x%08x__cc,\n", zz0); printf("\tarm_instr_multi_0x%08x__mi,\n", zz0); printf("\tarm_instr_multi_0x%08x__pl,\n", zz0); printf("\tarm_instr_multi_0x%08x__vs,\n", zz0); printf("\tarm_instr_multi_0x%08x__vc,\n", zz0); printf("\tarm_instr_multi_0x%08x__hi,\n", zz0); printf("\tarm_instr_multi_0x%08x__ls,\n", zz0); printf("\tarm_instr_multi_0x%08x__ge,\n", zz0); printf("\tarm_instr_multi_0x%08x__lt,\n", zz0); printf("\tarm_instr_multi_0x%08x__gt,\n", zz0); printf("\tarm_instr_multi_0x%08x__le,\n", zz0); printf("\tarm_instr_multi_0x%08x,\n", zz0); printf("\tarm_instr_nop,\n"); } } printf("};\n"); } printf("\nuint32_t *multi_opcode[256] = {\n"); for (i=0; i<256; i++) { printf(" multi_opcode_%i,", i); if ((i % 4) == 0) printf("\n"); } printf("};\n"); printf("\nvoid (**multi_opcode_f[256])(struct cpu *," " struct arm_instr_call *) = {\n"); for (i=0; i<256; i++) { if (n_used[i] > 0) printf(" multi_opcode_f_%i,", i); else printf(" NULL,"); if ((i % 4) == 0) printf("\n"); } printf("};\n"); return 0; } gxemul-0.6.1/src/cpus/memory_m88k.cc000644 001750 001750 00000027733 13402411502 017470 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Virtual to physical memory translation for M88K emulation. * * (This is where the actual work of the M8820x chips is emulated.) * * * TODO: * M88204 stuff, where it differs from the M88200. */ #include #include #include #include "cpu.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/m8820x.h" #include "thirdparty/m8820x_pte.h" /* #define M8820X_TABLE_SEARCH_DEBUG */ /* * m8820x_mark_page_as_modified(): * * Helper function which traverses the page table structure in emulated * memory, and marks a page as Modified and Used. */ void m8820x_mark_page_as_modified(struct cpu *cpu, struct m8820x_cmmu *cmmu, uint32_t apr, uint32_t vaddr) { int seg_nr = vaddr >> 22, page_nr = (vaddr >> 12) & 0x3ff; uint32_t *seg_base, *page_base; sdt_entry_t seg_descriptor; pt_entry_t page_descriptor; /* Read the segment descriptor from memory: */ seg_base = (uint32_t *) memory_paddr_to_hostaddr( cpu->mem, apr & 0xfffff000, 1); seg_descriptor = seg_base[seg_nr]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) seg_descriptor = LE32_TO_HOST(seg_descriptor); else seg_descriptor = BE32_TO_HOST(seg_descriptor); /* ... and the page descriptor: */ page_base = (uint32_t *) memory_paddr_to_hostaddr( cpu->mem, seg_descriptor & 0xfffff000, 1); page_descriptor = page_base[page_nr]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) page_descriptor = LE32_TO_HOST(page_descriptor); else page_descriptor = BE32_TO_HOST(page_descriptor); /* ... set the Modified and Used bits: */ page_descriptor |= PG_M | PG_U; /* ... and write it back: */ if (cpu->byte_order == EMUL_LITTLE_ENDIAN) page_descriptor = LE32_TO_HOST(page_descriptor); else page_descriptor = BE32_TO_HOST(page_descriptor); page_base[page_nr] = page_descriptor; } /* * m88k_translate_v2p(): * * Returns 0 for translation failure (access denied), 1 for read access * (success), or 2 for read/write access (success). */ int m88k_translate_v2p(struct cpu *cpu, uint64_t vaddr64, uint64_t *return_paddr, int flags) { int instr = flags & FLAG_INSTR; int writeflag = (flags & FLAG_WRITEFLAG)? 1 : 0; int no_exceptions = flags & FLAG_NOEXCEPTIONS; int exception_type = instr? M88K_EXCEPTION_INSTRUCTION_ACCESS : M88K_EXCEPTION_DATA_ACCESS; int supervisor = cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE; struct m8820x_cmmu *cmmu = cpu->cd.m88k.cmmu[instr? 0 : 1]; uint32_t vaddr = vaddr64; uint32_t apr; uint32_t *seg_base, *page_base; sdt_entry_t seg_descriptor; pt_entry_t page_descriptor; int pfsr_status = CMMU_PFSR_SUCCESS; uint32_t pfar = 0; int accumulated_flags; int i, seg_nr = vaddr >> 22, page_nr = (vaddr >> 12) & 0x3ff; if (flags & MEMORY_USER_ACCESS) supervisor = 0; /* * Is the CMMU not yet initialized? Then return physical = virtual. */ *return_paddr = vaddr; if (cmmu == NULL) return 2; if (supervisor) apr = cmmu->reg[CMMU_SAPR]; else apr = cmmu->reg[CMMU_UAPR]; /* * Address translation not enabled? Then return physical = virtual. */ if (!(apr & APR_V)) return 2; /* * BATC lookup: * * The BATC is a 10-entry array of virtual to physical mappings, * where the top 13 bits of the virtual address must match. */ for (i=0; ibatc[i]; /* The batc entry must be valid: */ if (!(batc & BATC_V)) continue; /* ... and have a matching supervisor/user bit: */ if ((supervisor && !(batc & BATC_SO)) || (!supervisor && (batc & BATC_SO))) continue; /* ... and matching virtual address: */ if ((vaddr & 0xfff80000) != (batc & 0xfff80000)) continue; /* A matching BATC entry was found! */ /* Is it write protected? */ if ((batc & BATC_PROT) && writeflag) { pfsr_status = CMMU_PFSR_WRITE; goto exception; } *return_paddr = ((batc & 0x0007ffc0) << 13) | (vaddr & 0x0007ffff); return batc & BATC_PROT? 1 : 2; } /* * PATC lookup: * * The PATC is a 56-entry array of virtual to physical mappings for * 4 KB pages. If writeflag is set, and a PATC entry is found without * the Modified bit set, a page table search must be performed to * set the Modified bit in emulated memory. */ for (i=0; ipatc_v_and_control[i]; uint32_t paddr_and_sbit = cmmu->patc_p_and_supervisorbit[i]; /* Skip this entry if the valid bit isn't set: */ if (!(vaddr_and_control & PG_V)) continue; /* ... or the virtual addresses don't match: */ if ((vaddr & 0xfffff000) != (vaddr_and_control & 0xfffff000)) continue; /* ... or if the supervisor bit doesn't match: */ if (((paddr_and_sbit & M8820X_PATC_SUPERVISOR_BIT) && !supervisor) || (supervisor && !(paddr_and_sbit & M8820X_PATC_SUPERVISOR_BIT))) continue; /* A matching PATC entry was found! */ /* Is it write protected? */ if ((vaddr_and_control & PG_PROT) && writeflag) { pfsr_status = CMMU_PFSR_WRITE; goto exception; } /* On writes: Is the page not yet marked as modified? */ if (!(vaddr_and_control & PG_M) && writeflag && !no_exceptions) { /* Then perform a page table search and mark it as Modified (and used): */ m8820x_mark_page_as_modified(cpu, cmmu, apr, vaddr); /* ... and mark the PATC entry too: */ cmmu->patc_v_and_control[i] |= PG_M; } /* Set the Used bit of the PATC entry: */ if (!no_exceptions) cmmu->patc_v_and_control[i] |= PG_U; /* ... and finally return the physical address: */ *return_paddr = (paddr_and_sbit & 0xfffff000) | (vaddr & 0xfff); return vaddr_and_control & PG_PROT? 1 : 2; } /* * The address was neither found in the BATC, nor the PATC. */ /* * Attempt a search through page tables, to refill the PATC: */ seg_base = (uint32_t *) memory_paddr_to_hostaddr( cpu->mem, apr & 0xfffff000, 1); seg_descriptor = seg_base[seg_nr]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) seg_descriptor = LE32_TO_HOST(seg_descriptor); else seg_descriptor = BE32_TO_HOST(seg_descriptor); #ifdef M8820X_TABLE_SEARCH_DEBUG printf("+--- M8820x page table search debug:\n"); printf("| vaddr 0x%08"PRIx32"\n", vaddr); printf("| apr 0x%08"PRIx32"\n", apr); printf("| seg_base %p (on the host)\n", seg_base); printf("| seg_nr 0x%03x\n", seg_nr); printf("| page_nr 0x%03x\n", page_nr); printf("| sd 0x%08"PRIx32"\n", seg_descriptor); #endif /* Segment descriptor invalid? Then cause a segfault exception. */ if (!(seg_descriptor & SG_V)) { /* PFAR = physical address of faulting segment descriptor: */ pfar = (apr & 0xfffff000) + seg_nr * sizeof(uint32_t); pfsr_status = CMMU_PFSR_SFAULT; goto exception; } /* Usermode attempted to access a supervisor segment? */ if ((seg_descriptor & SG_SO) && !supervisor) { /* PFAR = physical address of faulting segment descriptor: */ pfar = (apr & 0xfffff000) + seg_nr * sizeof(uint32_t); pfsr_status = CMMU_PFSR_SUPER; goto exception; } accumulated_flags = seg_descriptor & SG_RO; page_base = (uint32_t *) memory_paddr_to_hostaddr( cpu->mem, seg_descriptor & 0xfffff000, 1); page_descriptor = page_base[page_nr]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) page_descriptor = LE32_TO_HOST(page_descriptor); else page_descriptor = BE32_TO_HOST(page_descriptor); #ifdef M8820X_TABLE_SEARCH_DEBUG printf("| page_base %p (on the host)\n", page_base); printf("| pd 0x%08"PRIx32"\n", page_descriptor); #endif /* Page descriptor invalid? Then cause a page fault exception. */ if (!(page_descriptor & PG_V)) { /* PFAR = physical address of faulting page descriptor: */ pfar = (seg_descriptor & 0xfffff000) + page_nr * sizeof(uint32_t); pfsr_status = CMMU_PFSR_PFAULT; goto exception; } /* Usermode attempted to access a supervisor page? */ if ((page_descriptor & PG_SO) && !supervisor) { /* PFAR = physical address of faulting page descriptor: */ pfar = (seg_descriptor & 0xfffff000) + page_nr * sizeof(uint32_t); pfsr_status = CMMU_PFSR_SUPER; goto exception; } accumulated_flags |= (page_descriptor & PG_RO); /* * Overwrite the next entry in the PATC with a new entry: */ if (!no_exceptions) { i = cmmu->patc_update_index; /* Invalidate the current entry, if it is valid: */ if (cmmu->patc_v_and_control[i] & PG_V) cpu->invalidate_translation_caches(cpu, cmmu->patc_v_and_control[i] & 0xfffff000, INVALIDATE_VADDR); /* ... and write the new one: */ cmmu->patc_update_index ++; cmmu->patc_update_index %= N_M88200_PATC_ENTRIES; cmmu->patc_v_and_control[i] = (vaddr & 0xfffff000) | accumulated_flags | PG_V; cmmu->patc_p_and_supervisorbit[i] = (page_descriptor & 0xfffff000) | (supervisor? M8820X_PATC_SUPERVISOR_BIT : 0); } /* Check for writes to read-only pages: */ if (writeflag && (accumulated_flags & PG_RO)) { pfsr_status = CMMU_PFSR_WRITE; goto exception; } if (!no_exceptions) { uint32_t tmp; /* We now know that the page is in use. */ cmmu->patc_v_and_control[i] |= PG_U; if (writeflag) cmmu->patc_v_and_control[i] |= PG_M; /* * Write back the U bit (and possibly the M bit) to the page * descriptor in emulated memory: */ tmp = page_descriptor | PG_U; if (writeflag) tmp |= PG_M; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) tmp = LE32_TO_HOST(tmp); else tmp = BE32_TO_HOST(tmp); page_base[page_nr] = tmp; } /* Now finally return with the translated page address: */ *return_paddr = (page_descriptor & 0xfffff000) | (vaddr & 0xfff); return (accumulated_flags & PG_RO)? 1 : 2; exception: if (no_exceptions) return 0; /* * Update the Page Fault Status Register of the CMMU which this fault * was associated with, but also clear the PFSR of the _other_ CMMU: */ cmmu->reg[CMMU_PFSR] = pfsr_status << 16; cpu->cd.m88k.cmmu[instr? 1 : 0]->reg[CMMU_PFSR] = CMMU_PFSR_SUCCESS << 16; /* ... and (if necessary) update the Page Fault Address Register: */ switch (pfsr_status) { case CMMU_PFSR_SUCCESS: fatal("HUH? CMMU_PFSR_SUCCESS:, but exception? TODO\n"); exit(1); break; case CMMU_PFSR_WRITE: /* Note: The PFAR is "destroyed"/undefined on write faults. */ cmmu->reg[CMMU_PFAR] = 0; break; case CMMU_PFSR_SUPER: case CMMU_PFSR_SFAULT: case CMMU_PFSR_PFAULT: cmmu->reg[CMMU_PFAR] = pfar; break; default: fatal("Internal error in memory_m88k? pfsr_status = %i\n", pfsr_status); exit(1); } /* ... and finally cause the exception: */ m88k_exception(cpu, exception_type, 0); return 0; } gxemul-0.6.1/src/cpus/experiment_arm_multi.cc000644 001750 001750 00000010573 13402411502 021534 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Given a list of common ARM load/store multiple opcodes, figure out (using * simple brute force), which n bits (where n is low, e.g. 7) that cause the * best separation of the 24 bit opcode space into linear lists, where "best" * means to optimize the length of the longest such linear list. * * The result is a set of bits, such as this: * * xxxx100P USWLnnnn llllllll llllllll * ^ ^ ^^ ^^ (in this case, n = 6) * * (it's a 24-bit space, because the s-bit isn't used). */ #include #include int bit_count(unsigned int x) { static const int c[16] = { 0,1,1,2, 1,2,2,3, 1,2,2,3, 2,3,3,4 }; return c[x & 15] + c[(x>>4) & 15] + c[(x>>8) & 15] + c[(x>>12) & 15] + c[(x>>16) & 15] + c[(x>>20) & 15] + c[(x>>24) & 15] + c[(x>>28) & 15]; } int cmpfunc(const void *a, const void *b) { int *pa = (int *) a, *pb = (int *) b; if (*pa < *pb) return -1; if (*pa > *pb) return 1; return 0; } int calc_max_list_length(int *opcodes, int *tmp_table, int n_opcodes, int bit_mask) { int i, maxlen, curlen; for (i=0; i maxlen) maxlen = curlen; } else curlen = 1; return maxlen; } int main(int argc, char *argv[]) { FILE *f = fopen("cpu_arm_multi.txt", "r"); int n; const int max = 10000; int opcode[max]; int tmp_table[max]; int n_opcodes = 0; int *max_len; int bit_mask, best_bit_mask, best_bit_mask_len; if (argc < 2) { fprintf(stderr, "usage: %s n\n", argv[0]); fprintf(stderr, "where n=6 might be a good choice\n"); exit(1); } n = atoi(argv[1]); if (f == NULL) { fprintf(stderr, "could not open cpu_arm_multi.txt\n"); exit(1); } /* Read the opcodes: */ while (!feof(f)) { char s[100]; s[0] = s[sizeof(s)-1] = '\0'; fgets(s, sizeof(s), f); if (s[0] == '0') { if (n_opcodes > max) { fprintf(stderr, "too many opcodes\n"); exit(1); } opcode[n_opcodes++] = strtol(s, NULL, 0); } } printf("nr of opcodes = %i\n", n_opcodes); max_len = malloc(sizeof(int) * (1 << 25)); if (max_len == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } best_bit_mask_len = -1; for (bit_mask = 0; bit_mask <= 0x01ffffff; bit_mask ++) { /* Skip the s-bit: */ if (bit_mask & 0x00400000) continue; if (bit_count(bit_mask) != n) continue; /* Calculate the max list length for this bit_mask: */ max_len[bit_mask] = calc_max_list_length(opcode, tmp_table, n_opcodes, bit_mask); if (best_bit_mask_len == -1 || max_len[bit_mask] < best_bit_mask_len) { best_bit_mask_len = max_len[bit_mask]; best_bit_mask = bit_mask; printf("best bit_mask so far: 0x%08x: %i\n", best_bit_mask, best_bit_mask_len); } } return 0; } gxemul-0.6.1/src/cpus/cpu_ppc.cc000644 001750 001750 00000141237 13402411502 016736 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * PowerPC/POWER CPU emulation. */ #include #include #include #include #include "cpu.h" #include "devices.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "of.h" #include "opcodes_ppc.h" #include "ppc_spr_strings.h" #include "settings.h" #include "symbol.h" #include "thirdparty/ppc_bat.h" #include "thirdparty/ppc_pte.h" #include "thirdparty/ppc_spr.h" #define DYNTRANS_DUALMODE_32 #include "tmp_ppc_head.cc" void ppc_pc_to_pointers(struct cpu *); void ppc32_pc_to_pointers(struct cpu *); void ppc_irq_interrupt_assert(struct interrupt *interrupt); void ppc_irq_interrupt_deassert(struct interrupt *interrupt); /* * ppc_cpu_new(): * * Create a new PPC cpu object. * * Returns 1 on success, 0 if there was no matching PPC processor with * this cpu_type_name. */ int ppc_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine, int cpu_id, char *cpu_type_name) { int any_cache = 0; int i, found; struct ppc_cpu_type_def cpu_type_defs[] = PPC_CPU_TYPE_DEFS; /* Scan the cpu_type_defs list for this cpu type: */ i = 0; found = -1; while (i >= 0 && cpu_type_defs[i].name != NULL) { if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) { found = i; break; } i++; } if (found == -1) return 0; cpu->memory_rw = ppc_memory_rw; cpu->cd.ppc.cpu_type = cpu_type_defs[found]; cpu->name = strdup(cpu->cd.ppc.cpu_type.name); cpu->byte_order = EMUL_BIG_ENDIAN; cpu->cd.ppc.mode = MODE_PPC; /* TODO */ /* Current operating mode: */ cpu->cd.ppc.bits = cpu->cd.ppc.cpu_type.bits; cpu->cd.ppc.spr[SPR_PVR] = cpu->cd.ppc.cpu_type.pvr; /* cpu->cd.ppc.msr = PPC_MSR_IR | PPC_MSR_DR | PPC_MSR_SF | PPC_MSR_FP; */ cpu->cd.ppc.spr[SPR_IBAT0U] = 0x00001ffc | BAT_Vs; cpu->cd.ppc.spr[SPR_IBAT0L] = 0x00000000 | BAT_PP_RW; cpu->cd.ppc.spr[SPR_IBAT1U] = 0xc0001ffc | BAT_Vs; cpu->cd.ppc.spr[SPR_IBAT1L] = 0x00000000 | BAT_PP_RW; cpu->cd.ppc.spr[SPR_IBAT3U] = 0xf0001ffc | BAT_Vs; cpu->cd.ppc.spr[SPR_IBAT3L] = 0xf0000000 | BAT_PP_RW; cpu->cd.ppc.spr[SPR_DBAT0U] = 0x00001ffc | BAT_Vs; cpu->cd.ppc.spr[SPR_DBAT0L] = 0x00000000 | BAT_PP_RW; cpu->cd.ppc.spr[SPR_DBAT1U] = 0xc0001ffc | BAT_Vs; cpu->cd.ppc.spr[SPR_DBAT1L] = 0x00000000 | BAT_PP_RW; cpu->cd.ppc.spr[SPR_DBAT2U] = 0xe0001ffc | BAT_Vs; cpu->cd.ppc.spr[SPR_DBAT2L] = 0xe0000000 | BAT_PP_RW; cpu->cd.ppc.spr[SPR_DBAT3U] = 0xf0001ffc | BAT_Vs; cpu->cd.ppc.spr[SPR_DBAT3L] = 0xf0000000 | BAT_PP_RW; cpu->is_32bit = (cpu->cd.ppc.bits == 32)? 1 : 0; if (cpu->is_32bit) { cpu->run_instr = ppc32_run_instr; cpu->update_translation_table = ppc32_update_translation_table; cpu->invalidate_translation_caches = ppc32_invalidate_translation_caches; cpu->invalidate_code_translation = ppc32_invalidate_code_translation; } else { cpu->run_instr = ppc_run_instr; cpu->update_translation_table = ppc_update_translation_table; cpu->invalidate_translation_caches = ppc_invalidate_translation_caches; cpu->invalidate_code_translation = ppc_invalidate_code_translation; } cpu->translate_v2p = ppc_translate_v2p; /* Only show name and caches etc for CPU nr 0 (in SMP machines): */ if (cpu_id == 0) { debug("%s", cpu->cd.ppc.cpu_type.name); if (cpu->cd.ppc.cpu_type.icache_shift != 0) any_cache = 1; if (cpu->cd.ppc.cpu_type.dcache_shift != 0) any_cache = 1; if (cpu->cd.ppc.cpu_type.l2cache_shift != 0) any_cache = 1; if (any_cache) { debug(" (I+D = %i+%i KB", (int)(1 << (cpu->cd.ppc.cpu_type.icache_shift-10)), (int)(1 << (cpu->cd.ppc.cpu_type.dcache_shift-10))); if (cpu->cd.ppc.cpu_type.l2cache_shift != 0) { debug(", L2 = %i KB", (int)(1 << (cpu->cd.ppc.cpu_type. l2cache_shift-10))); } debug(")"); } } cpu->cd.ppc.spr[SPR_PIR] = cpu_id; /* Some default stack pointer value. TODO: move this? */ cpu->cd.ppc.gpr[1] = machine->physical_ram_in_mb * 1048576 - 4096; /* * NOTE/TODO: Ugly hack for OpenFirmware emulation: */ if (cpu->machine->prom_emulation) cpu->cd.ppc.of_emul_addr = 0xfff00000; /* Add all register names to the settings: */ CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc); CPU_SETTINGS_ADD_REGISTER64("msr", cpu->cd.ppc.msr); CPU_SETTINGS_ADD_REGISTER64("ctr", cpu->cd.ppc.spr[SPR_CTR]); CPU_SETTINGS_ADD_REGISTER64("xer", cpu->cd.ppc.spr[SPR_XER]); CPU_SETTINGS_ADD_REGISTER64("dec", cpu->cd.ppc.spr[SPR_DEC]); CPU_SETTINGS_ADD_REGISTER64("hdec", cpu->cd.ppc.spr[SPR_HDEC]); CPU_SETTINGS_ADD_REGISTER64("srr0", cpu->cd.ppc.spr[SPR_SRR0]); CPU_SETTINGS_ADD_REGISTER64("srr1", cpu->cd.ppc.spr[SPR_SRR1]); CPU_SETTINGS_ADD_REGISTER64("sdr1", cpu->cd.ppc.spr[SPR_SDR1]); CPU_SETTINGS_ADD_REGISTER64("ibat0u", cpu->cd.ppc.spr[SPR_IBAT0U]); CPU_SETTINGS_ADD_REGISTER64("ibat0l", cpu->cd.ppc.spr[SPR_IBAT0L]); CPU_SETTINGS_ADD_REGISTER64("ibat1u", cpu->cd.ppc.spr[SPR_IBAT1U]); CPU_SETTINGS_ADD_REGISTER64("ibat1l", cpu->cd.ppc.spr[SPR_IBAT1L]); CPU_SETTINGS_ADD_REGISTER64("ibat2u", cpu->cd.ppc.spr[SPR_IBAT2U]); CPU_SETTINGS_ADD_REGISTER64("ibat2l", cpu->cd.ppc.spr[SPR_IBAT2L]); CPU_SETTINGS_ADD_REGISTER64("ibat3u", cpu->cd.ppc.spr[SPR_IBAT3U]); CPU_SETTINGS_ADD_REGISTER64("ibat3l", cpu->cd.ppc.spr[SPR_IBAT3L]); CPU_SETTINGS_ADD_REGISTER64("dbat0u", cpu->cd.ppc.spr[SPR_DBAT0U]); CPU_SETTINGS_ADD_REGISTER64("dbat0l", cpu->cd.ppc.spr[SPR_DBAT0L]); CPU_SETTINGS_ADD_REGISTER64("dbat1u", cpu->cd.ppc.spr[SPR_DBAT1U]); CPU_SETTINGS_ADD_REGISTER64("dbat1l", cpu->cd.ppc.spr[SPR_DBAT1L]); CPU_SETTINGS_ADD_REGISTER64("dbat2u", cpu->cd.ppc.spr[SPR_DBAT2U]); CPU_SETTINGS_ADD_REGISTER64("dbat2l", cpu->cd.ppc.spr[SPR_DBAT2L]); CPU_SETTINGS_ADD_REGISTER64("dbat3u", cpu->cd.ppc.spr[SPR_DBAT3U]); CPU_SETTINGS_ADD_REGISTER64("dbat3l", cpu->cd.ppc.spr[SPR_DBAT3L]); CPU_SETTINGS_ADD_REGISTER64("lr", cpu->cd.ppc.spr[SPR_LR]); CPU_SETTINGS_ADD_REGISTER32("cr", cpu->cd.ppc.cr); CPU_SETTINGS_ADD_REGISTER32("fpscr", cpu->cd.ppc.fpscr); /* Integer GPRs, floating point registers, and segment registers: */ for (i=0; icd.ppc.gpr[i]); } for (i=0; icd.ppc.fpr[i]); } for (i=0; i<16; i++) { char tmpstr[5]; snprintf(tmpstr, sizeof(tmpstr), "sr%i", i); CPU_SETTINGS_ADD_REGISTER32(tmpstr, cpu->cd.ppc.sr[i]); } /* Register the CPU as an interrupt handler: */ { struct interrupt templ; char name[150]; snprintf(name, sizeof(name), "%s", cpu->path); memset(&templ, 0, sizeof(templ)); templ.line = 0; templ.name = name; templ.extra = cpu; templ.interrupt_assert = ppc_irq_interrupt_assert; templ.interrupt_deassert = ppc_irq_interrupt_deassert; interrupt_handler_register(&templ); } return 1; } /* * ppc_cpu_list_available_types(): * * Print a list of available PPC CPU types. */ void ppc_cpu_list_available_types(void) { int i, j; struct ppc_cpu_type_def tdefs[] = PPC_CPU_TYPE_DEFS; i = 0; while (tdefs[i].name != NULL) { debug("%s", tdefs[i].name); for (j=10 - strlen(tdefs[i].name); j>0; j--) debug(" "); i++; if ((i % 6) == 0 || tdefs[i].name == NULL) debug("\n"); } } /* * ppc_cpu_dumpinfo(): */ void ppc_cpu_dumpinfo(struct cpu *cpu) { struct ppc_cpu_type_def *ct = &cpu->cd.ppc.cpu_type; debug(" (%i-bit ", cpu->cd.ppc.bits); switch (cpu->cd.ppc.mode) { case MODE_PPC: debug("PPC"); break; case MODE_POWER: debug("POWER"); break; default: debug("_INTERNAL ERROR_"); } debug(", I+D = %i+%i KB", (1 << ct->icache_shift) / 1024, (1 << ct->dcache_shift) / 1024); if (ct->l2cache_shift) { int kb = (1 << ct->l2cache_shift) / 1024; debug(", L2 = %i %cB", kb >= 1024? kb / 1024 : kb, kb >= 1024? 'M' : 'K'); } debug(")\n"); } /* * reg_access_msr(): */ void reg_access_msr(struct cpu *cpu, uint64_t *valuep, int writeflag, int check_for_interrupts) { uint64_t old = cpu->cd.ppc.msr; if (valuep == NULL) { fatal("reg_access_msr(): NULL\n"); return; } if (writeflag) { cpu->cd.ppc.msr = *valuep; /* Switching between temporary and real gpr 0..3? */ if ((old & PPC_MSR_TGPR) != (cpu->cd.ppc.msr & PPC_MSR_TGPR)) { int i; for (i=0; icd.ppc.gpr[i]; cpu->cd.ppc.gpr[i] = cpu->cd.ppc.tgpr[i]; cpu->cd.ppc.tgpr[i] = t; } } if (cpu->cd.ppc.msr & PPC_MSR_IP) { fatal("\n[ Reboot hack for NetBSD/prep. TODO: " "fix this. ]\n"); cpu->running = 0; } } /* TODO: Is the little-endian bit writable? */ cpu->cd.ppc.msr &= ~PPC_MSR_LE; if (cpu->byte_order != EMUL_BIG_ENDIAN) cpu->cd.ppc.msr |= PPC_MSR_LE; if (!writeflag) *valuep = cpu->cd.ppc.msr; if (check_for_interrupts && cpu->cd.ppc.msr & PPC_MSR_EE) { if (cpu->cd.ppc.dec_intr_pending && !(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC)) { ppc_exception(cpu, PPC_EXCEPTION_DEC); cpu->cd.ppc.dec_intr_pending = 0; } else if (cpu->cd.ppc.irq_asserted) ppc_exception(cpu, PPC_EXCEPTION_EI); } } /* * ppc_exception(): */ void ppc_exception(struct cpu *cpu, int exception_nr) { /* Save PC and MSR: */ cpu->cd.ppc.spr[SPR_SRR0] = cpu->pc; if (exception_nr >= 0x10 && exception_nr <= 0x13) cpu->cd.ppc.spr[SPR_SRR1] = (cpu->cd.ppc.msr & 0xffff) | (cpu->cd.ppc.cr & 0xf0000000); else cpu->cd.ppc.spr[SPR_SRR1] = (cpu->cd.ppc.msr & 0x87c0ffff); if (!quiet_mode) fatal("[ PPC Exception 0x%x; pc=0x%" PRIx64" ]\n", exception_nr, cpu->pc); /* Disable External Interrupts, Recoverable Interrupt Mode, and go to Supervisor mode */ cpu->cd.ppc.msr &= ~(PPC_MSR_EE | PPC_MSR_RI | PPC_MSR_PR); cpu->pc = exception_nr * 0x100; if (cpu->cd.ppc.msr & PPC_MSR_IP) cpu->pc += 0xfff00000ULL; if (cpu->is_32bit) ppc32_pc_to_pointers(cpu); else ppc_pc_to_pointers(cpu); } /* * ppc_cpu_register_dump(): * * Dump cpu registers in a relatively readable format. * * gprs: set to non-zero to dump GPRs and some special-purpose registers. * coprocs: if bit i is set, then we should dump registers from coproc i. */ void ppc_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs) { char *symbol; uint64_t offset, tmp; int i, x = cpu->cpu_id; int bits32 = cpu->cd.ppc.bits == 32; if (gprs) { /* Special registers (pc, ...) first: */ symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->pc, &offset); debug("cpu%i: pc = 0x", x); if (bits32) debug("%08" PRIx32, (uint32_t)cpu->pc); else debug("%016" PRIx64, (uint64_t)cpu->pc); debug(" <%s>\n", symbol != NULL? symbol : " no symbol "); debug("cpu%i: lr = 0x", x); if (bits32) debug("%08" PRIx32, (uint32_t)cpu->cd.ppc.spr[SPR_LR]); else debug("%016" PRIx64, (uint64_t)cpu->cd.ppc.spr[SPR_LR]); debug(" cr = 0x%08" PRIx32, (uint32_t)cpu->cd.ppc.cr); if (bits32) debug(" "); else debug("\ncpu%i: ", x); debug("ctr = 0x", x); if (bits32) debug("%08" PRIx32, (uint32_t)cpu->cd.ppc.spr[SPR_CTR]); else debug("%016" PRIx64, (uint64_t)cpu->cd.ppc.spr[SPR_CTR]); debug(" xer = 0x", x); if (bits32) debug("%08" PRIx32, (uint32_t)cpu->cd.ppc.spr[SPR_XER]); else debug("%016" PRIx64, (uint64_t)cpu->cd.ppc.spr[SPR_XER]); debug("\n"); if (bits32) { /* 32-bit: */ for (i=0; icd.ppc.gpr[i]); if ((i % 4) == 3) debug("\n"); } } else { /* 64-bit: */ for (i=0; i> 1) + ((i & 1) << 4); if ((i % 2) == 0) debug("cpu%i:", x); debug(" r%02i = 0x%016" PRIx64" ", r, (uint64_t) cpu->cd.ppc.gpr[r]); if ((i % 2) == 1) debug("\n"); } } /* Other special registers: */ if (bits32) { debug("cpu%i: srr0 = 0x%08" PRIx32 " srr1 = 0x%08" PRIx32"\n", x, (uint32_t) cpu->cd.ppc.spr[SPR_SRR0], (uint32_t) cpu->cd.ppc.spr[SPR_SRR1]); } else { debug("cpu%i: srr0 = 0x%016" PRIx64 " srr1 = 0x%016" PRIx64"\n", x, (uint64_t) cpu->cd.ppc.spr[SPR_SRR0], (uint64_t) cpu->cd.ppc.spr[SPR_SRR1]); } debug("cpu%i: msr = ", x); reg_access_msr(cpu, &tmp, 0, 0); if (bits32) debug("0x%08" PRIx32, (uint32_t) tmp); else debug("0x%016" PRIx64, (uint64_t) tmp); debug(" tb = 0x%08" PRIx32"%08" PRIx32"\n", (uint32_t) cpu->cd.ppc.spr[SPR_TBU], (uint32_t) cpu->cd.ppc.spr[SPR_TBL]); debug("cpu%i: dec = 0x%08" PRIx32, x, (uint32_t) cpu->cd.ppc.spr[SPR_DEC]); if (!bits32) debug(" hdec = 0x%08" PRIx32"\n", (uint32_t) cpu->cd.ppc.spr[SPR_HDEC]); debug("\n"); } if (coprocs & 1) { debug("cpu%i: fpscr = 0x%08" PRIx32"\n", x, (uint32_t) cpu->cd.ppc.fpscr); /* TODO: show floating-point values :-) */ /* TODO: 32-bit fprs on 32-bit PPC cpus? */ for (i=0; icd.ppc.fpr[i]); if ((i % 2) == 1) debug("\n"); } } if (coprocs & 2) { debug("cpu%i: sdr1 = 0x%" PRIx64"\n", x, (uint64_t) cpu->cd.ppc.spr[SPR_SDR1]); if (cpu->cd.ppc.cpu_type.flags & PPC_601) debug("cpu%i: PPC601-style, TODO!\n"); else { for (i=0; i<8; i++) { int spr = SPR_IBAT0U + i*2; uint32_t upper = cpu->cd.ppc.spr[spr]; uint32_t lower = cpu->cd.ppc.spr[spr+1]; uint32_t len = (((upper & BAT_BL) << 15) | 0x1ffff) + 1; debug("cpu%i: %sbat%i: u=0x%08" PRIx32 " l=0x%08" PRIx32" ", x, i<4? "i" : "d", i&3, upper, lower); if (!(upper & BAT_V)) { debug(" (not valid)\n"); continue; } if (len < 1048576) debug(" (%i KB, ", len >> 10); else debug(" (%i MB, ", len >> 20); if (upper & BAT_Vu) debug("user, "); if (upper & BAT_Vs) debug("supervisor, "); if (lower & (BAT_W | BAT_I | BAT_M | BAT_G)) debug("%s%s%s%s, ", lower & BAT_W? "W" : "", lower & BAT_I? "I" : "", lower & BAT_M? "M" : "", lower & BAT_G? "G" : ""); switch (lower & BAT_PP) { case BAT_PP_NONE: debug("NO access"); break; case BAT_PP_RO_S: debug("read-only, soft"); break; case BAT_PP_RO: debug("read-only"); break; case BAT_PP_RW: debug("read/write"); break; } debug(")\n"); } } } if (coprocs & 4) { for (i=0; i<16; i++) { uint32_t s = cpu->cd.ppc.sr[i]; debug("cpu%i:", x); debug(" sr%-2i = 0x%08" PRIx32, i, s); s &= (SR_TYPE | SR_SUKEY | SR_PRKEY | SR_NOEXEC); if (s != 0) { debug(" ("); if (s & SR_TYPE) { debug("NON-memory type"); s &= ~SR_TYPE; if (s != 0) debug(", "); } if (s & SR_SUKEY) { debug("supervisor-key"); s &= ~SR_SUKEY; if (s != 0) debug(", "); } if (s & SR_PRKEY) { debug("user-key"); s &= ~SR_PRKEY; if (s != 0) debug(", "); } if (s & SR_NOEXEC) debug("NOEXEC"); debug(")"); } debug("\n"); } } } /* * ppc_cpu_tlbdump(): * * Not currently used for PPC. */ void ppc_cpu_tlbdump(struct machine *m, int x, int rawflag) { } /* * ppc_irq_interrupt_assert(): */ void ppc_irq_interrupt_assert(struct interrupt *interrupt) { struct cpu *cpu = (struct cpu *) interrupt->extra; cpu->cd.ppc.irq_asserted = 1; } /* * ppc_irq_interrupt_deassert(): */ void ppc_irq_interrupt_deassert(struct interrupt *interrupt) { struct cpu *cpu = (struct cpu *) interrupt->extra; cpu->cd.ppc.irq_asserted = 0; } /* * ppc_cpu_disassemble_instr(): * * Convert an instruction word into human readable format, for instruction * tracing. * * If running is 1, cpu->pc should be the address of the instruction. * * If running is 0, things that depend on the runtime environment (eg. * register contents) will not be shown, and addr will be used instead of * cpu->pc for relative addresses. */ int ppc_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr, int running, uint64_t dumpaddr) { int hi6, xo, lev, rt, rs, ra, rb, imm, sh, me, rc, l_bit; //, oe_bit; int spr, aa_bit, lk_bit, bf, bh, bi, bo, mb, nb, bt, ba, bb, fpreg; int bfa, to, load, wlen, no_rb = 0; uint64_t offset, addr; uint32_t iword; const char *symbol, *mnem = "ERROR"; int power = cpu->cd.ppc.mode == MODE_POWER; if (running) dumpaddr = cpu->pc; symbol = get_symbol_name(&cpu->machine->symbol_context, dumpaddr, &offset); if (symbol != NULL && offset==0) debug("<%s>\n", symbol); if (cpu->machine->ncpus > 1 && running) debug("cpu%i: ", cpu->cpu_id); if (cpu->cd.ppc.bits == 32) debug("%08" PRIx32, (uint32_t) dumpaddr); else debug("%016" PRIx64, (uint64_t) dumpaddr); /* NOTE: Fixed to big-endian. */ iword = (instr[0] << 24) + (instr[1] << 16) + (instr[2] << 8) + instr[3]; debug(": %08" PRIx32"\t", iword); /* * Decode the instruction: */ hi6 = iword >> 26; switch (hi6) { case 0x4: debug("ALTIVEC TODO"); /* vxor etc */ break; case PPC_HI6_MULLI: case PPC_HI6_SUBFIC: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; imm = (int16_t)(iword & 0xffff); switch (hi6) { case PPC_HI6_MULLI: mnem = power? "muli":"mulli"; break; case PPC_HI6_SUBFIC: mnem = power? "sfi":"subfic"; break; } debug("%s\tr%i,r%i,%i", mnem, rt, ra, imm); break; case PPC_HI6_CMPLI: case PPC_HI6_CMPI: bf = (iword >> 23) & 7; l_bit = (iword >> 21) & 1; ra = (iword >> 16) & 31; if (hi6 == PPC_HI6_CMPLI) { imm = iword & 0xffff; mnem = "cmpl"; } else { imm = (int16_t)(iword & 0xffff); mnem = "cmp"; } debug("%s%si\t", mnem, l_bit? "d" : "w"); if (bf != 0) debug("cr%i,", bf); debug("r%i,%i", ra, imm); break; case PPC_HI6_ADDIC: case PPC_HI6_ADDIC_DOT: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; rc = hi6 == PPC_HI6_ADDIC_DOT; imm = (int16_t)(iword & 0xffff); mnem = power? "ai":"addic"; if (imm < 0 && !power) { mnem = "subic"; imm = -imm; } debug("%s%s\tr%i,r%i,%i", mnem, rc?".":"", rt, ra, imm); break; case PPC_HI6_ADDI: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; imm = (int16_t)(iword & 0xffff); if (ra == 0) debug("li\tr%i,%i", rt, imm); else { mnem = power? "cal":"addi"; if (imm < 0 && !power) { mnem = "subi"; imm = -imm; } debug("%s\tr%i,r%i,%i", mnem, rt, ra, imm); } break; case PPC_HI6_ADDIS: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; imm = (int16_t)(iword & 0xffff); if (ra == 0) debug("lis\tr%i,%i", rt, imm); else debug("%s\tr%i,r%i,%i", power? "cau":"addis", rt, ra, imm); break; case PPC_HI6_BC: aa_bit = (iword & 2) >> 1; lk_bit = iword & 1; bo = (iword >> 21) & 31; bi = (iword >> 16) & 31; /* Sign-extend addr: */ addr = (int64_t)(int16_t)(iword & 0xfffc); debug("bc"); if (lk_bit) debug("l"); if (aa_bit) debug("a"); else addr += dumpaddr; debug("\t%i,%i,", bo, bi); if (cpu->cd.ppc.bits == 32) addr &= 0xffffffff; if (cpu->cd.ppc.bits == 32) debug("0x%" PRIx32, (uint32_t) addr); else debug("0x%" PRIx64, (uint64_t) addr); symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug("\t<%s>", symbol); break; case PPC_HI6_SC: lev = (iword >> 5) & 0x7f; debug("sc"); if (lev != 0) { debug("\t%i", lev); if (lev > 1) debug(" (WARNING! reserved value)"); } break; case PPC_HI6_B: aa_bit = (iword & 2) >> 1; lk_bit = iword & 1; /* Sign-extend addr: */ addr = (int64_t)(int32_t)((iword & 0x03fffffc) << 6); addr = (int64_t)addr >> 6; debug("b"); if (lk_bit) debug("l"); if (aa_bit) debug("a"); else addr += dumpaddr; if (cpu->cd.ppc.bits == 32) addr &= 0xffffffff; if (cpu->cd.ppc.bits == 32) debug("\t0x%" PRIx32, (uint32_t) addr); else debug("\t0x%" PRIx64, (uint64_t) addr); symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug("\t<%s>", symbol); break; case PPC_HI6_19: xo = (iword >> 1) & 1023; switch (xo) { case PPC_19_MCRF: bf = (iword >> 23) & 7; bfa = (iword >> 18) & 7; debug("mcrf\tcr%i,cr%i", bf, bfa); break; case PPC_19_RFI: debug("rfi"); break; case PPC_19_RFID: debug("rfid"); break; case PPC_19_RFSVC: debug("rfsvc%s", power?"":"\t(INVALID for PowerPC)"); break; case PPC_19_BCLR: case PPC_19_BCCTR: bo = (iword >> 21) & 31; bi = (iword >> 16) & 31; bh = (iword >> 11) & 3; lk_bit = iword & 1; switch (xo) { case PPC_19_BCLR: mnem = power? "bcr" : "bclr"; break; case PPC_19_BCCTR: mnem = power? "bcc" : "bcctr"; break; } debug("%s%s%s\t%i,%i,%i", mnem, lk_bit? "l" : "", bh? (bh==3? "+" : (bh==2? "-" : "?")) : "", bo, bi, bh); break; case PPC_19_ISYNC: debug("%s", power? "ics" : "isync"); break; case PPC_19_CRAND: case PPC_19_CRXOR: case PPC_19_CROR: case PPC_19_CRNAND: case PPC_19_CRNOR: case PPC_19_CRANDC: case PPC_19_CREQV: case PPC_19_CRORC: bt = (iword >> 21) & 31; ba = (iword >> 16) & 31; bb = (iword >> 11) & 31; switch (xo) { case PPC_19_CRAND: mnem = "crand"; break; case PPC_19_CRXOR: mnem = "crxor"; break; case PPC_19_CROR: mnem = "cror"; break; case PPC_19_CRNAND: mnem = "crnand"; break; case PPC_19_CRNOR: mnem = "crnor"; break; case PPC_19_CRANDC: mnem = "crandc"; break; case PPC_19_CREQV: mnem = "creqv"; break; case PPC_19_CRORC: mnem = "crorc"; break; } debug("%s\t%i,%i,%i", mnem, bt, ba, bb); break; default: debug("unimplemented hi6_19, xo = 0x%x", xo); } break; case PPC_HI6_RLWNM: case PPC_HI6_RLWIMI: case PPC_HI6_RLWINM: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; sh = (iword >> 11) & 31; /* actually rb for rlwnm */ mb = (iword >> 6) & 31; me = (iword >> 1) & 31; rc = iword & 1; switch (hi6) { case PPC_HI6_RLWNM: mnem = power? "rlnm" : "rlwnm"; break; case PPC_HI6_RLWIMI: mnem = power? "rlimi" : "rlwimi"; break; case PPC_HI6_RLWINM: mnem = power? "rlinm" : "rlwinm"; break; } debug("%s%s\tr%i,r%i,%s%i,%i,%i", mnem, rc?".":"", ra, rs, hi6 == PPC_HI6_RLWNM? "r" : "", sh, mb, me); break; case PPC_HI6_ORI: case PPC_HI6_ORIS: case PPC_HI6_XORI: case PPC_HI6_XORIS: case PPC_HI6_ANDI_DOT: case PPC_HI6_ANDIS_DOT: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; imm = iword & 0xffff; switch (hi6) { case PPC_HI6_ORI: mnem = power? "oril":"ori"; break; case PPC_HI6_ORIS: mnem = power? "oriu":"oris"; break; case PPC_HI6_XORI: mnem = power? "xoril":"xori"; break; case PPC_HI6_XORIS: mnem = power? "xoriu":"xoris"; break; case PPC_HI6_ANDI_DOT: mnem = power? "andil.":"andi."; break; case PPC_HI6_ANDIS_DOT: mnem = power? "andiu.":"andis."; break; } if (hi6 == PPC_HI6_ORI && rs == 0 && ra == 0 && imm == 0) debug("nop"); else debug("%s\tr%i,r%i,0x%04x", mnem, ra, rs, imm); break; case PPC_HI6_30: xo = (iword >> 2) & 7; switch (xo) { case PPC_30_RLDICL: case PPC_30_RLDICR: case PPC_30_RLDIMI: /* mb, not me */ mnem = NULL; switch (xo) { case PPC_30_RLDICL: mnem = "rldicl"; break; case PPC_30_RLDICR: mnem = "rldicr"; break; case PPC_30_RLDIMI: mnem = "rldimi"; break; } rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; sh = ((iword >> 11) & 31) | ((iword & 2) << 4); me = ((iword >> 6) & 31) | (iword & 0x20); rc = iword & 1; debug("%s%s\tr%i,r%i,%i,%i", mnem, rc?".":"", ra, rs, sh, me); break; default: debug("unimplemented hi6_30, xo = 0x%x", xo); } break; case PPC_HI6_31: xo = (iword >> 1) & 1023; switch (xo) { case PPC_31_CMP: case PPC_31_CMPL: bf = (iword >> 23) & 7; l_bit = (iword >> 21) & 1; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; if (xo == PPC_31_CMPL) mnem = "cmpl"; else mnem = "cmp"; debug("%s%s\t", mnem, l_bit? "d" : "w"); if (bf != 0) debug("cr%i,", bf); debug("r%i,r%i", ra, rb); break; case PPC_31_MFCR: rt = (iword >> 21) & 31; debug("mfcr\tr%i", rt); break; case PPC_31_MFMSR: rt = (iword >> 21) & 31; debug("mfmsr\tr%i", rt); break; case PPC_31_MTCRF: rs = (iword >> 21) & 31; mb = (iword >> 12) & 255; /* actually fxm, not mb */ debug("mtcrf\t%i,r%i", mb, rs); break; case PPC_31_MTMSR: rs = (iword >> 21) & 31; l_bit = (iword >> 16) & 1; debug("mtmsr\tr%i", rs); if (l_bit) debug(",%i", l_bit); break; case PPC_31_TW: case PPC_31_TD: to = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; switch (xo) { case PPC_31_TW: mnem = power? "t" : "tw"; break; case PPC_31_TD: mnem = "td"; break; } debug("%s\t%i,r%i,r%i", mnem, to, ra, rb); break; case PPC_31_LWARX: case PPC_31_LDARX: case PPC_31_LBZX: case PPC_31_LBZUX: case PPC_31_LHAX: case PPC_31_LHAUX: case PPC_31_LHZX: case PPC_31_LHZUX: case PPC_31_LWZX: case PPC_31_LWZUX: case PPC_31_LHBRX: case PPC_31_LWBRX: case PPC_31_LFDX: case PPC_31_LFSX: case PPC_31_STWCX_DOT: case PPC_31_STDCX_DOT: case PPC_31_STBX: case PPC_31_STBUX: case PPC_31_STHX: case PPC_31_STHUX: case PPC_31_STWX: case PPC_31_STWUX: case PPC_31_STDX: case PPC_31_STDUX: case PPC_31_STHBRX: case PPC_31_STWBRX: case PPC_31_STFDX: case PPC_31_STFSX: /* rs for stores, rt for loads, actually */ load = 0; wlen = 0; fpreg = 0; rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; switch (xo) { case PPC_31_LWARX: wlen=4;load=1; mnem = "lwarx"; break; case PPC_31_LDARX: wlen=8;load=1; mnem = "ldarx"; break; case PPC_31_LBZX: wlen=1;load=1; mnem = "lbzx"; break; case PPC_31_LBZUX: wlen=1;load=1; mnem = "lbzux"; break; case PPC_31_LHAX: wlen=2;load=1; mnem = "lhax"; break; case PPC_31_LHAUX: wlen=2;load=1; mnem = "lhaux"; break; case PPC_31_LHZX: wlen=2;load=1; mnem = "lhzx"; break; case PPC_31_LHZUX: wlen=2;load=1; mnem = "lhzux"; break; case PPC_31_LWZX: wlen = 4; load = 1; mnem = power? "lx" : "lwzx"; break; case PPC_31_LWZUX: wlen = 4; load = 1; mnem = power? "lux":"lwzux"; break; case PPC_31_LFDX: fpreg = 1; wlen = 8; load = 1; mnem = "lfdx"; break; case PPC_31_LFSX: fpreg = 1; wlen = 4; load = 1; mnem = "lfsx"; break; case PPC_31_STWCX_DOT: wlen=4; mnem = "stwcx."; break; case PPC_31_STDCX_DOT: wlen=8; mnem = "stdcx."; break; case PPC_31_STBX: wlen=1; mnem = "stbx"; break; case PPC_31_STBUX: wlen=1; mnem = "stbux"; break; case PPC_31_STHX: wlen=2; mnem = "sthx"; break; case PPC_31_STHUX: wlen=2; mnem = "sthux"; break; case PPC_31_STWX: wlen = 4; mnem = power? "stx" : "stwx"; break; case PPC_31_STWUX: wlen = 4; mnem = power? "stux" : "stwux"; break; case PPC_31_STDX: wlen = 8; mnem = "stdx"; break; case PPC_31_STDUX: wlen = 8; mnem = "stdux"; break; case PPC_31_LHBRX: wlen = 2; mnem = "lhbrx"; break; case PPC_31_LWBRX: wlen = 4; mnem = power? "lbrx" : "lwbrx"; break; case PPC_31_STHBRX: wlen = 2; mnem = "sthbrx"; break; case PPC_31_STWBRX: wlen = 4; mnem = power? "stbrx" : "stwbrx"; break; case PPC_31_STFDX: fpreg = 1; wlen = 8; mnem = "stfdx"; break; case PPC_31_STFSX: fpreg = 1; wlen = 4; mnem = "stfsx"; break; } debug("%s\t%s%i,r%i,r%i", mnem, fpreg? "f" : "r", rs, ra, rb); if (!running) break; addr = (ra==0? 0 : cpu->cd.ppc.gpr[ra]) + cpu->cd.ppc.gpr[rb]; if (cpu->cd.ppc.bits == 32) addr &= 0xffffffff; symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug(" \t<%s", symbol); else debug(" \t<0x%" PRIx64, (uint64_t) addr); if (wlen > 0 && !fpreg /* && !reverse */) { /* TODO */ } debug(">"); break; case PPC_31_NEG: case PPC_31_NEGO: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; // oe_bit = (iword >> 10) & 1; rc = iword & 1; switch (xo) { case PPC_31_NEG: mnem = "neg"; break; case PPC_31_NEGO: mnem = "nego"; break; } debug("%s%s\tr%i,r%i", mnem, rc? "." : "", rt, ra); break; case PPC_31_WRTEEI: debug("wrteei\t%i", iword & 0x8000? 1 : 0); break; case PPC_31_MTMSRD: /* TODO: Just a guess based on MTMSR */ rs = (iword >> 21) & 31; l_bit = (iword >> 16) & 1; debug("mtmsrd\tr%i", rs); if (l_bit) debug(",%i", l_bit); break; case PPC_31_ADDZE: case PPC_31_ADDZEO: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; // oe_bit = (iword >> 10) & 1; rc = iword & 1; switch (xo) { case PPC_31_ADDZE: mnem = power? "aze" : "addze"; break; case PPC_31_ADDZEO: mnem = power? "azeo" : "addzeo"; break; } debug("%s%s\tr%i,r%i", mnem, rc? "." : "", rt, ra); break; case PPC_31_MTSR: case PPC_31_MFSR: /* Move to/from segment register */ rt = (iword >> 21) & 31; ra = (iword >> 16) & 15; /* actually: sr */ switch (xo) { case PPC_31_MTSR: mnem = "mtsr"; break; case PPC_31_MFSR: mnem = "mfsr"; break; } debug("%s\tr%i,%i", mnem, rt, ra); break; case PPC_31_MTSRIN: case PPC_31_MFSRIN: /* Move to/from segment register indirect */ rt = (iword >> 21) & 31; rb = (iword >> 11) & 31; switch (xo) { case PPC_31_MTSRIN: mnem = "mtsrin"; break; case PPC_31_MFSRIN: mnem = "mfsrin"; break; } debug("%s\tr%i,r%i", mnem, rt, rb); break; case PPC_31_ADDC: case PPC_31_ADDCO: case PPC_31_ADDE: case PPC_31_ADDEO: case PPC_31_ADDME: case PPC_31_ADDMEO: case PPC_31_ADD: case PPC_31_ADDO: case PPC_31_MULHW: case PPC_31_MULHWU: case PPC_31_MULLW: case PPC_31_MULLWO: case PPC_31_SUBF: case PPC_31_SUBFO: case PPC_31_SUBFC: case PPC_31_SUBFCO: case PPC_31_SUBFE: case PPC_31_SUBFEO: case PPC_31_SUBFME: case PPC_31_SUBFMEO: case PPC_31_SUBFZE: case PPC_31_SUBFZEO: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; // oe_bit = (iword >> 10) & 1; rc = iword & 1; switch (xo) { case PPC_31_ADDC: mnem = power? "a" : "addc"; break; case PPC_31_ADDCO: mnem = power? "ao" : "addco"; break; case PPC_31_ADDE: mnem = power? "ae" : "adde"; break; case PPC_31_ADDEO: mnem = power? "aeo" : "addeo"; break; case PPC_31_ADDME: mnem = power? "ame" : "addme"; no_rb = 1; break; case PPC_31_ADDMEO: mnem = power? "ameo" : "addmeo"; no_rb = 1; break; case PPC_31_ADD: mnem = power? "cax" : "add"; break; case PPC_31_ADDO: mnem = power? "caxo" : "addo"; break; case PPC_31_MULHW: mnem = "mulhw"; break; case PPC_31_MULHWU: mnem = "mulhwu"; break; case PPC_31_MULLW: mnem = power? "muls" : "mullw"; break; case PPC_31_MULLWO: mnem = power? "mulso" : "mullwo"; break; case PPC_31_SUBF: mnem = "subf"; break; case PPC_31_SUBFO: mnem = "subfo"; break; case PPC_31_SUBFC: mnem = power? "sf" : "subfc"; break; case PPC_31_SUBFCO: mnem = power? "sfo" : "subfco"; break; case PPC_31_SUBFE: mnem = power? "sfe" : "subfe"; break; case PPC_31_SUBFEO: mnem = power? "sfeo" : "subfeo"; break; case PPC_31_SUBFME: mnem = power? "sfme" : "subfme"; break; case PPC_31_SUBFMEO: mnem = power? "sfmeo" : "subfmeo"; break; case PPC_31_SUBFZE: mnem = power? "sfze" : "subfze"; no_rb = 1; break; case PPC_31_SUBFZEO: mnem = power? "sfzeo" : "subfzeo"; no_rb = 1; break; } debug("%s%s\tr%i,r%i", mnem, rc? "." : "", rt, ra); if (!no_rb) debug(",r%i", rb); break; case PPC_31_MFSPR: rt = (iword >> 21) & 31; spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); switch (spr) { /* Some very common ones: */ case 8: debug("mflr\tr%i", rt); break; case 9: debug("mfctr\tr%i", rt); break; default:debug("mfspr\tr%i,spr%i", rt, spr); } if (spr == 8 || spr == 9) debug("\t"); debug("\t<%s%s", running? "read from " : "", ppc_spr_names[spr]==NULL? "?" : ppc_spr_names[spr]); if (running) { if (cpu->cd.ppc.bits == 32) debug(": 0x%" PRIx32, (uint32_t) cpu->cd.ppc.spr[spr]); else debug(": 0x%" PRIx64, (uint64_t) cpu->cd.ppc.spr[spr]); } debug(">"); break; case PPC_31_TLBIA: debug("tlbia"); break; case PPC_31_SLBIA: debug("slbia"); break; case PPC_31_TLBLD: case PPC_31_TLBLI: rb = (iword >> 11) & 31; debug("tlbl%s\tr%i", xo == PPC_31_TLBLD? "d" : "i", rb); break; case PPC_31_TLBIE: /* TODO: what is ra? The IBM online docs didn't say */ ra = 0; rb = (iword >> 11) & 31; if (power) debug("tlbi\tr%i,r%i", ra, rb); else debug("tlbie\tr%i", rb); break; case PPC_31_TLBSX_DOT: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; debug("tlbsx.\tr%i,r%i,r%i", rs, ra, rb); break; case PPC_31_TLBSYNC: debug("tlbsync"); break; case PPC_31_MFTB: rt = (iword >> 21) & 31; spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); debug("mftb%s\tr%i", spr==268? "" : (spr==269? "u" : "?"), rt); break; case PPC_31_CNTLZW: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; rc = iword & 1; mnem = power? "cntlz" : "cntlzw"; debug("%s%s\tr%i,r%i", mnem, rc? "." : "", ra, rs); break; case PPC_31_CLF: /* POWER only */ case PPC_31_CLI: /* POWER only */ case PPC_31_DCLST: /* POWER only */ case PPC_31_DCBF: /* PowerPC only */ case PPC_31_DCBI: /* PowerPC only */ case PPC_31_DCBST: /* PowerPC only */ case PPC_31_DCBTST: /* PowerPC only */ case PPC_31_DCBT: /* PowerPC only */ case PPC_31_ICBI: /* PowerPC only */ case PPC_31_DCBZ: /* POWER/PowerPC */ ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; switch (xo) { case PPC_31_CLF: mnem = "clf"; break; case PPC_31_CLI: mnem = "cli"; break; case PPC_31_DCLST: mnem = "dclst"; break; case PPC_31_DCBF: mnem = "dcbf"; break; case PPC_31_DCBI: mnem = "dcbi"; break; case PPC_31_DCBST: mnem = "dcbst"; break; case PPC_31_DCBTST:mnem = "dcbtst"; break; case PPC_31_DCBT: mnem = "dcbt"; break; case PPC_31_ICBI: mnem = "icbi"; break; case PPC_31_DCBZ: mnem = power ? "dclz" : "dcbz"; break; } debug("%s\tr%i,r%i", mnem, ra, rb); break; case PPC_31_SLW: case PPC_31_SLD: case PPC_31_SRAW: case PPC_31_SRW: case PPC_31_AND: case PPC_31_ANDC: case PPC_31_NOR: case PPC_31_EQV: case PPC_31_OR: case PPC_31_ORC: case PPC_31_XOR: case PPC_31_NAND: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; rc = iword & 1; if (rs == rb && xo == PPC_31_OR) debug("mr%s\tr%i,r%i", rc? "." : "", ra, rs); else { switch (xo) { case PPC_31_SLW: mnem = power? "sl" : "slw"; break; case PPC_31_SLD: mnem = "sld"; break; case PPC_31_SRAW: mnem = power? "sra" : "sraw"; break; case PPC_31_SRW: mnem = power? "sr" : "srw"; break; case PPC_31_AND: mnem = "and"; break; case PPC_31_NAND: mnem = "nand"; break; case PPC_31_ANDC: mnem = "andc"; break; case PPC_31_NOR: mnem = "nor"; break; case PPC_31_EQV: mnem = "eqv"; break; case PPC_31_OR: mnem = "or"; break; case PPC_31_ORC: mnem = "orc"; break; case PPC_31_XOR: mnem = "xor"; break; } debug("%s%s\tr%i,r%i,r%i", mnem, rc? "." : "", ra, rs, rb); } break; case PPC_31_DCCCI: ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; debug("dccci\tr%i,r%i", ra, rb); break; case PPC_31_ICCCI: ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; debug("iccci\tr%i,r%i", ra, rb); break; case PPC_31_DIVW: case PPC_31_DIVWO: case PPC_31_DIVWU: case PPC_31_DIVWUO: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; // oe_bit = (iword >> 10) & 1; rc = iword & 1; switch (xo) { case PPC_31_DIVWU: mnem = "divwu"; break; case PPC_31_DIVWUO: mnem = "divwuo"; break; case PPC_31_DIVW: mnem = "divw"; break; case PPC_31_DIVWO: mnem = "divwo"; break; } debug("%s%s\tr%i,r%i,r%i", mnem, rc? "." : "", rt, ra, rb); break; case PPC_31_MTSPR: rs = (iword >> 21) & 31; spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); switch (spr) { /* Some very common ones: */ case 8: debug("mtlr\tr%i", rs); break; case 9: debug("mtctr\tr%i", rs); break; default:debug("mtspr\tspr%i,r%i", spr, rs); } if (spr == 8 || spr == 9) debug("\t"); debug("\t<%s%s", running? "write to " : "", ppc_spr_names[spr]==NULL? "?" : ppc_spr_names[spr]); if (running) { if (cpu->cd.ppc.bits == 32) debug(": 0x%" PRIx32, (uint32_t) cpu->cd.ppc.gpr[rs]); else debug(": 0x%" PRIx64, (uint64_t) cpu->cd.ppc.gpr[rs]); } debug(">"); break; case PPC_31_SYNC: debug("%s", power? "dcs" : "sync"); break; case PPC_31_LSWI: case PPC_31_STSWI: rs = (iword >> 21) & 31; /* lwsi uses rt */ ra = (iword >> 16) & 31; nb = (iword >> 11) & 31; switch (xo) { case PPC_31_LSWI: mnem = power? "lsi" : "lswi"; break; case PPC_31_STSWI: mnem = power? "stsi" : "stswi"; break; } debug("%s\tr%i,r%i,%i", mnem, rs, ra, nb); break; case PPC_31_SRAWI: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; sh = (iword >> 11) & 31; rc = iword & 1; mnem = power? "srai" : "srawi"; debug("%s%s\tr%i,r%i,%i", mnem, rc? "." : "", ra, rs, sh); break; case PPC_31_DSSALL: debug("dssall"); break; case PPC_31_EIEIO: debug("%s", power? "eieio?" : "eieio"); break; case PPC_31_EXTSB: case PPC_31_EXTSH: case PPC_31_EXTSW: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; rc = iword & 1; switch (xo) { case PPC_31_EXTSB: mnem = power? "exts" : "extsb"; break; case PPC_31_EXTSH: mnem = "extsh"; break; case PPC_31_EXTSW: mnem = "extsw"; break; } debug("%s%s\tr%i,r%i", mnem, rc? "." : "", ra, rs); break; case PPC_31_LVX: case PPC_31_LVXL: case PPC_31_STVX: case PPC_31_STVXL: rs = (iword >> 21) & 31; /* vs for stores, */ ra = (iword >> 16) & 31; /* rs=vl for loads */ rb = (iword >> 11) & 31; rc = iword & 1; switch (xo) { case PPC_31_LVX: mnem = "lvx"; break; case PPC_31_LVXL: mnem = "lvxl"; break; case PPC_31_STVX: mnem = "stvx"; break; case PPC_31_STVXL: mnem = "stvxl"; break; } debug("%s%s\tv%i,r%i,r%i", mnem, rc? "." : "", rs, ra, rb); break; default: debug("unimplemented hi6_31, xo = 0x%x", xo); } break; case PPC_HI6_LD: case PPC_HI6_LWZ: case PPC_HI6_LWZU: case PPC_HI6_LHZ: case PPC_HI6_LHZU: case PPC_HI6_LHA: case PPC_HI6_LHAU: case PPC_HI6_LBZ: case PPC_HI6_LBZU: case PPC_HI6_LFD: case PPC_HI6_LFS: case PPC_HI6_LMW: case PPC_HI6_STD: case PPC_HI6_STW: case PPC_HI6_STWU: case PPC_HI6_STH: case PPC_HI6_STHU: case PPC_HI6_STB: case PPC_HI6_STBU: case PPC_HI6_STMW: case PPC_HI6_STFD: case PPC_HI6_STFS: /* NOTE: Loads use rt, not rs, but are otherwise similar to stores */ load = 0; wlen = 0; rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; imm = (int16_t)(iword & 0xffff); fpreg = 0; switch (hi6) { case PPC_HI6_LD: load=1; wlen = 8; mnem = "ld"; break; case PPC_HI6_LWZ: load=1; wlen = 4; mnem = power? "l" : "lwz"; break; case PPC_HI6_LWZU: load=1; wlen = 4; mnem = power? "lu" : "lwzu"; break; case PPC_HI6_LHZ: load=1; wlen = 2; mnem = "lhz"; break; case PPC_HI6_LHZU: load=1; wlen = 2; mnem = "lhzu"; break; case PPC_HI6_LHA: load=2; wlen = 2; mnem = "lha"; break; case PPC_HI6_LHAU: load=2; wlen = 2; mnem = "lhau"; break; case PPC_HI6_LBZ: load=1; wlen = 1; mnem = "lbz"; break; case PPC_HI6_LBZU: load=1; wlen = 1; mnem = "lbzu"; break; case PPC_HI6_LFD: load=1; fpreg=1; wlen=8; mnem = "lfd"; break; case PPC_HI6_LFS: load=1; fpreg=1; wlen=4; mnem = "lfs"; break; case PPC_HI6_STD: wlen=8; mnem = "std"; break; case PPC_HI6_STW: wlen=4; mnem = power? "st" : "stw"; break; case PPC_HI6_STWU: wlen=4; mnem = power? "stu" : "stwu"; break; case PPC_HI6_STH: wlen=2; mnem = "sth"; break; case PPC_HI6_STHU: wlen=2; mnem = "sthu"; break; case PPC_HI6_STB: wlen=1; mnem = "stb"; break; case PPC_HI6_STBU: wlen=1; mnem = "stbu"; break; case PPC_HI6_LMW: load=1; mnem = power? "lm" : "lmw"; break; case PPC_HI6_STMW: mnem = power? "stm" : "stmw"; break; case PPC_HI6_STFD: fpreg=1; wlen=8; mnem = "stfd"; break; case PPC_HI6_STFS: fpreg=1; wlen=4; mnem = "stfs"; break; } debug("%s\t", mnem); if (fpreg) debug("f"); else debug("r"); debug("%i,%i(r%i)", rs, imm, ra); if (!running) break; addr = (ra==0? 0 : cpu->cd.ppc.gpr[ra]) + imm; if (cpu->cd.ppc.bits == 32) addr &= 0xffffffff; symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug(" \t<%s", symbol); else debug(" \t<0x%" PRIx64, (uint64_t) addr); if (wlen > 0 && load && wlen > 0) { unsigned char tw[8]; uint64_t tdata = 0; int i, res = cpu->memory_rw(cpu, cpu->mem, addr, tw, wlen, MEM_READ, NO_EXCEPTIONS); if (res) { if (cpu->byte_order == EMUL_LITTLE_ENDIAN) for (i=0; i= 4) { symbol = get_symbol_name(&cpu->machine-> symbol_context, tdata, &offset); if (symbol != NULL) debug("%s", symbol); else debug("0x%" PRIx64, (uint64_t) tdata); } else { /* TODO: if load==2, then this is a _signed_ load. */ debug("0x%" PRIx64, (uint64_t) tdata); } } else debug(": unreadable"); } if (wlen > 0 && !load && wlen > 0) { int64_t tdata = 0; int i; for (i=0; icd.ppc.gpr[rs] & ((uint64_t)0xff << (i*8))); debug(": "); if (wlen >= 4) { symbol = get_symbol_name(&cpu->machine-> symbol_context, tdata, &offset); if (symbol != NULL) debug("%s", symbol); else debug("0x%" PRIx64, (uint64_t) tdata); } else { if (tdata > -256 && tdata < 256) debug("%i", (int)tdata); else debug("0x%" PRIx64, (uint64_t) tdata); } } debug(">"); break; case PPC_HI6_59: xo = (iword >> 1) & 1023; /* NOTE: Some floating point instructions only use the lowest 5 bits of xo, some use all 10 bits! */ switch (xo & 31) { case PPC_59_FDIVS: case PPC_59_FSUBS: case PPC_59_FADDS: case PPC_59_FMULS: case PPC_59_FMADDS: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; rs = (iword >> 6) & 31; /* actually frc */ rc = iword & 1; switch (xo & 31) { case PPC_59_FDIVS: mnem = "fdivs"; break; case PPC_59_FSUBS: mnem = "fsubs"; break; case PPC_59_FADDS: mnem = "fadds"; break; case PPC_59_FMULS: mnem = "fmuls"; break; case PPC_59_FMADDS: mnem = "fmadds"; break; } debug("%s%s\t", mnem, rc? "." : ""); switch (xo & 31) { case PPC_59_FMULS: debug("f%i,f%i,f%i", rt, ra, rs); break; case PPC_59_FMADDS: debug("f%i,f%i,f%i,f%i", rt, ra, rs, rb); break; default:debug("f%i,f%i,f%i", rt, ra, rb); } break; default:/* TODO: similar to hi6_63 */ debug("unimplemented hi6_59, xo = 0x%x", xo); } break; case PPC_HI6_63: xo = (iword >> 1) & 1023; /* NOTE: Some floating point instructions only use the lowest 5 bits of xo, some use all 10 bits! */ switch (xo & 31) { case PPC_63_FDIV: case PPC_63_FSUB: case PPC_63_FADD: case PPC_63_FMUL: case PPC_63_FMSUB: case PPC_63_FMADD: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; rs = (iword >> 6) & 31; /* actually frc */ rc = iword & 1; switch (xo & 31) { case PPC_63_FDIV: mnem = power? "fd" : "fdiv"; break; case PPC_63_FSUB: mnem = power? "fs" : "fsub"; break; case PPC_63_FADD: mnem = power? "fa" : "fadd"; break; case PPC_63_FMUL: mnem = power? "fm" : "fmul"; break; case PPC_63_FMSUB: mnem = power? "fms" : "fmsub"; break; case PPC_63_FMADD: mnem = power? "fma" : "fmadd"; break; } debug("%s%s\t", mnem, rc? "." : ""); switch (xo & 31) { case PPC_63_FMUL: debug("f%i,f%i,f%i", rt, ra, rs); break; case PPC_63_FMADD: debug("f%i,f%i,f%i,f%i", rt, ra, rs, rb); break; default:debug("f%i,f%i,f%i", rt, ra, rb); } break; default:rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; rc = iword & 1; switch (xo) { case PPC_63_FCMPU: case PPC_63_FRSP: case PPC_63_FCTIWZ: case PPC_63_FNEG: case PPC_63_FMR: case PPC_63_FNABS: case PPC_63_FABS: switch (xo) { case PPC_63_FCMPU: mnem = "fcmpu"; break; case PPC_63_FCTIWZ: mnem = power? "fcirz" : "fctiwz"; break; case PPC_63_FRSP: mnem = "frsp"; break; case PPC_63_FNEG: mnem = "fneg"; break; case PPC_63_FMR: mnem = "fmr"; break; case PPC_63_FNABS: mnem = "fnabs"; break; case PPC_63_FABS: mnem = "fabs"; break; } debug("%s%s\t", mnem, rc? "." : ""); switch (xo) { case PPC_63_FCMPU: debug("%i,f%i,f%i", rt >> 2, ra, rb); break; case PPC_63_FCTIWZ: case PPC_63_FRSP: case PPC_63_FNEG: case PPC_63_FMR: case PPC_63_FNABS: case PPC_63_FABS: debug("f%i,f%i", rt, rb); break; default:debug("f%i,f%i,f%i", rt, ra, rb); } break; case PPC_63_MFFS: debug("mffs%s\tf%i", rc?".":"", rt); break; case PPC_63_MTFSF: ra = (iword >> 17) & 255; /* flm */ debug("mtfsf%s\t0x%02x,f%i", rc?".":"", ra, rb); break; default:debug("unimplemented hi6_63, xo = 0x%x", xo); } } break; default: /* TODO */ debug("unimplemented hi6 = 0x%02x", hi6); } debug("\n"); return sizeof(iword); } /* * debug_spr_usage(): * * Helper function. To speed up overall development speed of the emulator, * all SPR accesses are allowed. This function causes unknown/unimplemented * SPRs to give a warning. */ static void debug_spr_usage(uint64_t pc, int spr) { static uint32_t spr_used[1024 / sizeof(uint32_t)]; static int initialized = 0; if (!initialized) { memset(spr_used, 0, sizeof(spr_used)); initialized = 1; } spr &= 1023; if (spr_used[spr >> 2] & (1 << (spr & 3))) return; switch (spr) { /* Known/implemented SPRs: */ case SPR_XER: case SPR_LR: case SPR_CTR: case SPR_DSISR: case SPR_DAR: case SPR_DEC: case SPR_SDR1: case SPR_SRR0: case SPR_SRR1: case SPR_SPRG0: case SPR_SPRG1: case SPR_SPRG2: case SPR_SPRG3: case SPR_PVR: case SPR_DMISS: case SPR_DCMP: case SPR_HASH1: case SPR_HASH2: case SPR_IMISS: case SPR_ICMP: case SPR_DBSR: case SPR_PIR: break; default:if (spr >= SPR_IBAT0U && spr <= SPR_DBAT3L) { break; } else fatal("[ using UNIMPLEMENTED spr %i (%s), pc = " "0x%" PRIx64" ]\n", spr, ppc_spr_names[spr] == NULL? "UNKNOWN" : ppc_spr_names[spr], (uint64_t) pc); } spr_used[spr >> 2] |= (1 << (spr & 3)); } /* * update_cr0(): * * Sets the top 4 bits of the CR register. */ void update_cr0(struct cpu *cpu, uint64_t value) { int c; if (cpu->cd.ppc.bits == 64) { if ((int64_t)value < 0) c = 8; else if ((int64_t)value > 0) c = 4; else c = 2; } else { if ((int32_t)value < 0) c = 8; else if ((int32_t)value > 0) c = 4; else c = 2; } /* SO bit, copied from XER: */ c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); cpu->cd.ppc.cr &= ~((uint32_t)0xf << 28); cpu->cd.ppc.cr |= ((uint32_t)c << 28); } #include "memory_ppc.cc" #include "tmp_ppc_tail.cc" gxemul-0.6.1/src/cpus/cpu_sh_instr.cc000644 001750 001750 00000323603 13402411502 020004 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * SH instructions. * * Individual functions should keep track of cpu->n_translated_instrs. * (If no instruction was executed, then it should be decreased. If, say, 4 * instructions were combined into one function and executed, then it should * be increased by 3.) */ #define SYNCH_PC { \ int low_pc = ((size_t)ic - (size_t)cpu->cd.sh.cur_ic_page) \ / sizeof(struct sh_instr_call); \ cpu->pc &= ~((SH_IC_ENTRIES_PER_PAGE-1) \ << SH_INSTR_ALIGNMENT_SHIFT); \ cpu->pc += (low_pc << SH_INSTR_ALIGNMENT_SHIFT); \ } #define ABORT_EXECUTION { SYNCH_PC; \ fatal("Execution aborted at: pc = 0x%08x\n", (int)cpu->pc); \ cpu->cd.sh.next_ic = ¬hing_call; \ cpu->running = 0; \ debugger_n_steps_left_before_interaction = 0; } #define RES_INST_IF_NOT_MD \ if (!(cpu->cd.sh.sr & SH_SR_MD)) { \ SYNCH_PC; \ sh_exception(cpu, EXPEVT_RES_INST, 0, 0); \ return; \ } #define FLOATING_POINT_AVAILABLE_CHECK \ if (cpu->cd.sh.sr & SH_SR_FD) { \ /* FPU disabled: Cause exception. */ \ SYNCH_PC; \ if (cpu->delay_slot) \ sh_exception(cpu, EXPEVT_FPU_SLOT_DISABLE, 0, 0);\ else \ sh_exception(cpu, EXPEVT_FPU_DISABLE, 0, 0); \ return; \ } /* * nop: Nothing */ X(nop) { } /* * sleep: Wait for interrupt */ X(sleep) { RES_INST_IF_NOT_MD; /* * If there is an interrupt, then just return. Otherwise * re-run the sleep instruction (after a delay). */ if (cpu->cd.sh.int_to_assert > 0 && !(cpu->cd.sh.sr & SH_SR_BL) && ((cpu->cd.sh.sr & SH_SR_IMASK) >> SH_SR_IMASK_SHIFT) < cpu->cd.sh.int_level) return; cpu->cd.sh.next_ic = ic; cpu->is_halted = 1; cpu->has_been_idling = 1; /* * There was no interrupt. Let the host sleep for a while. * * TODO: * * Think about how to actually implement this usleep stuff, * in an SMP and/or timing accurate environment. */ if (cpu->machine->ncpus == 1) { static int x = 0; if ((++x) == 600) { usleep(10); x = 0; } cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 6; } } /* * sett: t = 1 * sets: s = 1 * clrt: t = 1 * clrs: s = 1 * movt_rn: rn = t * clrmac: mach = macl = 0 * * arg[1] = ptr to rn */ X(sett) { cpu->cd.sh.sr |= SH_SR_T; } X(sets) { cpu->cd.sh.sr |= SH_SR_S; } X(clrt) { cpu->cd.sh.sr &= ~SH_SR_T; } X(clrs) { cpu->cd.sh.sr &= ~SH_SR_S; } X(movt_rn) { reg(ic->arg[1]) = cpu->cd.sh.sr & SH_SR_T? 1 : 0; } X(clrmac) { cpu->cd.sh.macl = cpu->cd.sh.mach = 0; } /* * mov_rm_rn: rn = rm * neg_rm_rn: rn = -rm * negc_rm_rn: rn = -rm - t, t = borrow * not_rm_rn: rn = ~rm * swap_b_rm_rn: rn = rm with lowest 2 bytes swapped * swap_w_rm_rn: rn = rm with high and low 16-bit words swapped * exts_b_rm_rn: rn = (int8_t) rm * extu_b_rm_rn: rn = (uint8_t) rm * exts_w_rm_rn: rn = (int16_t) rm * extu_w_rm_rn: rn = (uint16_t) rm * * arg[0] = ptr to rm * arg[1] = ptr to rn */ X(mov_rm_rn) { reg(ic->arg[1]) = reg(ic->arg[0]); } X(not_rm_rn) { reg(ic->arg[1]) = ~reg(ic->arg[0]); } X(neg_rm_rn) { reg(ic->arg[1]) = -reg(ic->arg[0]); } X(negc_rm_rn) { uint64_t res = 0; res -= (uint64_t) reg(ic->arg[0]); if (cpu->cd.sh.sr & SH_SR_T) res --; if ((res >> 32) & 1) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; reg(ic->arg[1]) = (uint32_t) res; } X(swap_b_rm_rn) { uint32_t r = reg(ic->arg[0]); reg(ic->arg[1]) = (r & 0xffff0000) | ((r >> 8)&0xff) | ((r&0xff) << 8); } X(swap_w_rm_rn) { uint32_t r = reg(ic->arg[0]); reg(ic->arg[1]) = (r >> 16) | (r << 16); } X(exts_b_rm_rn) { reg(ic->arg[1]) = (int8_t)reg(ic->arg[0]); } X(extu_b_rm_rn) { reg(ic->arg[1]) = (uint8_t)reg(ic->arg[0]); } X(exts_w_rm_rn) { reg(ic->arg[1]) = (int16_t)reg(ic->arg[0]); } X(extu_w_rm_rn) { reg(ic->arg[1]) = (uint16_t)reg(ic->arg[0]); } /* Note: rm and rn are the same on these: */ X(extu_b_rm) { reg(ic->arg[1]) = (uint8_t)reg(ic->arg[1]); } X(extu_w_rm) { reg(ic->arg[1]) = (uint16_t)reg(ic->arg[1]); } /* * and_imm_r0: r0 &= imm * xor_imm_r0: r0 ^= imm * tst_imm_r0: t = (r0 & imm) == 0 * or_imm_r0: r0 |= imm * * arg[0] = imm */ X(and_imm_r0) { cpu->cd.sh.r[0] &= ic->arg[0]; } X(xor_imm_r0) { cpu->cd.sh.r[0] ^= ic->arg[0]; } X(or_imm_r0) { cpu->cd.sh.r[0] |= ic->arg[0]; } X(tst_imm_r0) { if (cpu->cd.sh.r[0] & ic->arg[0]) cpu->cd.sh.sr &= ~SH_SR_T; else cpu->cd.sh.sr |= SH_SR_T; } /* * xor_b_imm_r0_gbr: mem[r0+gbr] |= imm * or_b_imm_r0_gbr: mem[r0+gbr] ^= imm * and_b_imm_r0_gbr: mem[r0+gbr] &= imm * * arg[0] = imm */ X(xor_b_imm_r0_gbr) { uint32_t addr = cpu->cd.sh.gbr + cpu->cd.sh.r[0]; uint8_t *p = (uint8_t *) cpu->cd.sh.host_store[addr >> 12]; if (p != NULL) { p[addr & 0xfff] ^= ic->arg[0]; } else { uint8_t data; SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } data ^= ic->arg[0]; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(or_b_imm_r0_gbr) { uint32_t addr = cpu->cd.sh.gbr + cpu->cd.sh.r[0]; uint8_t *p = (uint8_t *) cpu->cd.sh.host_store[addr >> 12]; if (p != NULL) { p[addr & 0xfff] |= ic->arg[0]; } else { uint8_t data; SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } data |= ic->arg[0]; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(and_b_imm_r0_gbr) { uint32_t addr = cpu->cd.sh.gbr + cpu->cd.sh.r[0]; uint8_t *p = (uint8_t *) cpu->cd.sh.host_store[addr >> 12]; if (p != NULL) { p[addr & 0xfff] &= ic->arg[0]; } else { uint8_t data; SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } data &= ic->arg[0]; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } /* * mov_imm_rn: Set rn to a signed 8-bit value * add_imm_rn: Add a signed 8-bit value to Rn * * arg[0] = int8_t imm, extended to at least int32_t * arg[1] = ptr to rn */ X(mov_imm_rn) { reg(ic->arg[1]) = ic->arg[0]; } X(mov_0_rn) { reg(ic->arg[1]) = 0; } X(add_imm_rn) { reg(ic->arg[1]) += ic->arg[0]; } X(inc_rn) { reg(ic->arg[1]) ++; } X(add_4_rn) { reg(ic->arg[1]) += 4; } X(sub_4_rn) { reg(ic->arg[1]) -= 4; } X(dec_rn) { reg(ic->arg[1]) --; } /* * mov_b_rm_predec_rn: mov.b reg,@-Rn * mov_w_rm_predec_rn: mov.w reg,@-Rn * mov_l_rm_predec_rn: mov.l reg,@-Rn * stc_l_rm_predec_rn_md: mov.l reg,@-Rn, with MD status bit check * * arg[0] = ptr to rm (or other register) * arg[1] = ptr to rn */ X(mov_b_rm_predec_rn) { uint32_t addr = reg(ic->arg[1]) - sizeof(uint8_t); int8_t *p = (int8_t *) cpu->cd.sh.host_store[addr >> 12]; int8_t data = reg(ic->arg[0]); if (p != NULL) { p[addr & 0xfff] = data; reg(ic->arg[1]) = addr; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } /* The store was ok: */ reg(ic->arg[1]) = addr; } } X(mov_w_rm_predec_rn) { uint32_t addr = reg(ic->arg[1]) - sizeof(uint16_t); uint16_t *p = (uint16_t *) cpu->cd.sh.host_store[addr >> 12]; uint16_t data = reg(ic->arg[0]); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE16_TO_HOST(data); else data = BE16_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 1] = data; reg(ic->arg[1]) = addr; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } /* The store was ok: */ reg(ic->arg[1]) = addr; } } X(mov_l_rm_predec_rn) { uint32_t addr = reg(ic->arg[1]) - sizeof(uint32_t); uint32_t *p = (uint32_t *) cpu->cd.sh.host_store[addr >> 12]; uint32_t data = reg(ic->arg[0]); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 2] = data; reg(ic->arg[1]) = addr; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } /* The store was ok: */ reg(ic->arg[1]) = addr; } } X(stc_l_rm_predec_rn_md) { uint32_t addr = reg(ic->arg[1]) - sizeof(uint32_t); uint32_t *p = (uint32_t *) cpu->cd.sh.host_store[addr >> 12]; uint32_t data = reg(ic->arg[0]); RES_INST_IF_NOT_MD; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 2] = data; reg(ic->arg[1]) = addr; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } /* The store was ok: */ reg(ic->arg[1]) = addr; } } /* * mov_l_disp_pc_rn: Load a 32-bit value into a register, * from an immediate address relative to the pc. * * arg[0] = offset from beginning of the current pc's page * arg[1] = ptr to rn */ X(mov_l_disp_pc_rn) { uint32_t addr = ic->arg[0] + (cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT)); uint32_t *p = (uint32_t *) cpu->cd.sh.host_load[addr >> 12]; uint32_t data; if (p != NULL) { data = p[(addr & 0xfff) >> 2]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); reg(ic->arg[1]) = data; } /* * mova_r0: Set r0 to an address close to the program counter. * * arg[0] = relative offset from beginning of the current pc's page */ X(mova_r0) { cpu->cd.sh.r[0] = ic->arg[0] + (cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT)); } /* * mov_w_disp_pc_rn: Load a 16-bit value into a register, * from an immediate address relative to the pc. * * arg[0] = offset from beginning of the current pc's page * arg[1] = ptr to rn */ X(mov_w_disp_pc_rn) { uint32_t addr = ic->arg[0] + (cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT)); uint16_t *p = (uint16_t *) cpu->cd.sh.host_load[addr >> 12]; uint16_t data; if (p != NULL) { data = p[(addr & 0xfff) >> 1]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE16_TO_HOST(data); else data = BE16_TO_HOST(data); reg(ic->arg[1]) = (int16_t)data; } /* * load_b_rm_rn: Load an int8_t value into Rn from address Rm. * load_w_rm_rn: Load an int16_t value into Rn from address Rm. * load_l_rm_rn: Load a 32-bit value into Rn from address Rm. * fmov_rm_frn: Load a floating point value into FRn from address Rm. * fmov_r0_rm_frn: Load a floating point value into FRn from address R0+Rm. * fmov_rm_postinc_frn: Load a floating point value into FRn from address Rm. * mov_b_r0_rm_rn: Load an int8_t value into Rn from address Rm + R0. * mov_w_r0_rm_rn: Load an int16_t value into Rn from address Rm + R0. * mov_l_r0_rm_rn: Load a 32-bit value into Rn from address Rm + R0. * mov_l_disp_rm_rn: Load a 32-bit value into Rn from address Rm + disp. * mov_b_disp_rn_r0: Load an int8_t from Rn+disp into R0. * mov_w_disp_rn_r0: Load an int16_t from Rn+disp into R0. * mov_b_disp_gbr_r0: Load an int8_t from GBR+disp into R0. * mov_w_disp_gbr_r0: Load an int16_t from GBR+disp into R0. * mov_l_disp_gbr_r0: Load an int32_t from GBR+disp into R0. * mov_b_arg1_postinc_to_arg0: * mov_w_arg1_postinc_to_arg0: * mov_l_arg1_postinc_to_arg0: * mov_l_arg1_postinc_to_arg0_md: With MD (privilege level) check. * mov_l_arg1_postinc_to_arg0_fp: With FP check. * * arg[0] = ptr to rm (or rm + (lo4 << 4) for disp) * arg[1] = ptr to rn */ X(load_b_rm_rn) { uint32_t addr = reg(ic->arg[0]); uint8_t *p = (uint8_t *) cpu->cd.sh.host_load[addr >> 12]; uint8_t data; if (p != NULL) { data = p[addr & 0xfff]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } reg(ic->arg[1]) = (int8_t) data; } X(load_w_rm_rn) { uint32_t addr = reg(ic->arg[0]); int16_t *p = (int16_t *) cpu->cd.sh.host_load[addr >> 12]; int16_t data; if (p != NULL) { data = p[(addr & 0xfff) >> 1]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE16_TO_HOST(data); else data = BE16_TO_HOST(data); reg(ic->arg[1]) = data; } X(load_l_rm_rn) { uint32_t addr = reg(ic->arg[0]); uint32_t *p = (uint32_t *) cpu->cd.sh.host_load[addr >> 12]; uint32_t data; if (p != NULL) { data = p[(addr & 0xfff) >> 2]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); reg(ic->arg[1]) = data; } X(fmov_rm_frn) { uint32_t addr = reg(ic->arg[0]); uint32_t *p = (uint32_t *) cpu->cd.sh.host_load[addr >> 12]; uint32_t data; FLOATING_POINT_AVAILABLE_CHECK; uint32_t data2 = 0; if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { // Register pair. Read second word first, then fallback // to read the first word. // Check if it is to an odd register first. size_t r1 = ic->arg[1]; int ofs = (r1 - (size_t)&cpu->cd.sh.fr[0]) / sizeof(uint32_t); if (ofs & 1) { fatal("ODD fmov_rm_frn: TODO"); exit(1); r1 = (size_t)&cpu->cd.sh.xf[ofs & ~1]; } SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr + 4, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } data2 = data; // fall-through to read the first word in the pair: } if (p != NULL) { data = p[(addr & 0xfff) >> 2]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); reg(ic->arg[1]) = data; // TODO: How about little endian: read words in opposite order? if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data2 = LE32_TO_HOST(data2); else data2 = BE32_TO_HOST(data2); reg(ic->arg[1] + 4) = data2; } } X(fmov_r0_rm_frn) { uint32_t data, addr = reg(ic->arg[0]) + cpu->cd.sh.r[0]; uint32_t *p = (uint32_t *) cpu->cd.sh.host_load[addr >> 12]; FLOATING_POINT_AVAILABLE_CHECK; if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { fatal("fmov_r0_rm_frn: sz=1 (register pair): TODO\n"); ABORT_EXECUTION; return; } if (p != NULL) { data = p[(addr & 0xfff) >> 2]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); reg(ic->arg[1]) = data; } X(fmov_rm_postinc_frn) { int d = cpu->cd.sh.fpscr & SH_FPSCR_SZ; uint32_t data, data2, addr = reg(ic->arg[0]); uint32_t *p = (uint32_t *) cpu->cd.sh.host_load[addr >> 12]; size_t r1 = ic->arg[1]; if (d) { /* xd instead of dr? */ int ofs = (r1 - (size_t)&cpu->cd.sh.fr[0]) / sizeof(uint32_t); if (ofs & 1) r1 = (size_t)&cpu->cd.sh.xf[ofs & ~1]; } FLOATING_POINT_AVAILABLE_CHECK; if (p != NULL) { data = p[(addr & 0xfff) >> 2]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); if (d) { /* Double-precision load: */ addr += 4; SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data2, sizeof(data2), MEM_READ, CACHE_DATA)) return; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data2 = LE32_TO_HOST(data2); else data2 = BE32_TO_HOST(data2); reg(r1 + 4) = data2; } reg(r1) = data; reg(ic->arg[0]) = addr + sizeof(uint32_t); } X(mov_b_disp_gbr_r0) { uint32_t addr = cpu->cd.sh.gbr + ic->arg[1]; int8_t *p = (int8_t *) cpu->cd.sh.host_load[addr >> 12]; int8_t data; if (p != NULL) { data = p[addr & 0xfff]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } cpu->cd.sh.r[0] = data; } X(mov_w_disp_gbr_r0) { uint32_t addr = cpu->cd.sh.gbr + ic->arg[1]; int16_t *p = (int16_t *) cpu->cd.sh.host_load[addr >> 12]; int16_t data; if (p != NULL) { data = p[(addr & 0xfff) >> 1]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE16_TO_HOST(data); else data = BE16_TO_HOST(data); cpu->cd.sh.r[0] = data; } X(mov_l_disp_gbr_r0) { uint32_t addr = cpu->cd.sh.gbr + ic->arg[1]; uint32_t *p = (uint32_t *) cpu->cd.sh.host_load[addr >> 12]; uint32_t data; if (p != NULL) { data = p[(addr & 0xfff) >> 2]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); cpu->cd.sh.r[0] = data; } X(mov_b_arg1_postinc_to_arg0) { uint32_t addr = reg(ic->arg[1]); int8_t *p = (int8_t *) cpu->cd.sh.host_load[addr >> 12]; int8_t data; if (p != NULL) { data = p[addr & 0xfff]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } /* The load was ok: */ reg(ic->arg[1]) = addr + sizeof(int8_t); reg(ic->arg[0]) = data; } X(mov_w_arg1_postinc_to_arg0) { uint32_t addr = reg(ic->arg[1]); uint16_t *p = (uint16_t *) cpu->cd.sh.host_load[addr >> 12]; uint16_t data; if (p != NULL) { data = p[(addr & 0xfff) >> 1]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE16_TO_HOST(data); else data = BE16_TO_HOST(data); reg(ic->arg[1]) = addr + sizeof(data); reg(ic->arg[0]) = (int16_t)data; } X(mov_l_arg1_postinc_to_arg0) { uint32_t addr = reg(ic->arg[1]); uint32_t *p = (uint32_t *) cpu->cd.sh.host_load[addr >> 12]; uint32_t data; if (p != NULL) { data = p[(addr & 0xfff) >> 2]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } /* The load was ok: */ if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); reg(ic->arg[1]) = addr + sizeof(data); reg(ic->arg[0]) = data; } X(mov_l_arg1_postinc_to_arg0_md) { uint32_t addr = reg(ic->arg[1]); uint32_t *p = (uint32_t *) cpu->cd.sh.host_load[addr >> 12]; uint32_t data; RES_INST_IF_NOT_MD; if (p != NULL) { data = p[(addr & 0xfff) >> 2]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } /* The load was ok: */ if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); reg(ic->arg[1]) = addr + sizeof(data); /* Special case when loading into the SR register: */ if (ic->arg[0] == (size_t)&cpu->cd.sh.sr) sh_update_sr(cpu, data); else reg(ic->arg[0]) = data; } X(mov_l_arg1_postinc_to_arg0_fp) { uint32_t addr = reg(ic->arg[1]); uint32_t *p = (uint32_t *) cpu->cd.sh.host_load[addr >> 12]; uint32_t data; FLOATING_POINT_AVAILABLE_CHECK; if (p != NULL) { data = p[(addr & 0xfff) >> 2]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } /* The load was ok: */ if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); reg(ic->arg[1]) = addr + sizeof(data); /* Ugly special case for FPSCR: */ if (ic->arg[0] == (size_t)&cpu->cd.sh.fpscr) sh_update_fpscr(cpu, data); else reg(ic->arg[0]) = data; } X(mov_b_r0_rm_rn) { uint32_t addr = reg(ic->arg[0]) + cpu->cd.sh.r[0]; int8_t *p = (int8_t *) cpu->cd.sh.host_load[addr >> 12]; int8_t data; if (p != NULL) { data = p[addr & 0xfff]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } reg(ic->arg[1]) = data; } X(mov_w_r0_rm_rn) { uint32_t addr = reg(ic->arg[0]) + cpu->cd.sh.r[0]; int16_t *p = (int16_t *) cpu->cd.sh.host_load[addr >> 12]; int16_t data; if (p != NULL) { data = p[(addr & 0xfff) >> 1]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE16_TO_HOST(data); else data = BE16_TO_HOST(data); reg(ic->arg[1]) = data; } X(mov_l_r0_rm_rn) { uint32_t addr = reg(ic->arg[0]) + cpu->cd.sh.r[0]; uint32_t *p = (uint32_t *) cpu->cd.sh.host_load[addr >> 12]; uint32_t data; if (p != NULL) { data = p[(addr & 0xfff) >> 2]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); reg(ic->arg[1]) = data; } X(mov_l_disp_rm_rn) { uint32_t addr = cpu->cd.sh.r[ic->arg[0] & 0xf] + ((ic->arg[0] >> 4) << 2); uint32_t *p = (uint32_t *) cpu->cd.sh.host_load[addr >> 12]; uint32_t data; if (p != NULL) { data = p[(addr & 0xfff) >> 2]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); reg(ic->arg[1]) = data; } X(mov_b_disp_rn_r0) { uint32_t addr = reg(ic->arg[0]) + ic->arg[1]; uint8_t *p = (uint8_t *) cpu->cd.sh.host_load[addr >> 12]; uint8_t data; if (p != NULL) { data = p[addr & 0xfff]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } cpu->cd.sh.r[0] = (int8_t) data; } X(mov_w_disp_rn_r0) { uint32_t addr = reg(ic->arg[0]) + ic->arg[1]; uint16_t *p = (uint16_t *) cpu->cd.sh.host_load[addr >> 12]; uint16_t data; if (p != NULL) { data = p[(addr & 0xfff) >> 1]; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE16_TO_HOST(data); else data = BE16_TO_HOST(data); cpu->cd.sh.r[0] = (int16_t) data; } /* * mov_b_store_rm_rn: Store Rm to address Rn (8-bit). * mov_w_store_rm_rn: Store Rm to address Rn (16-bit). * mov_l_store_rm_rn: Store Rm to address Rn (32-bit). * fmov_frm_rn: Store FRm to address Rn. * fmov_frm_r0_rn: Store FRm to address R0 + Rn. * fmov_frm_predec_rn: Store FRm to address Rn - 4 (or 8), update Rn. * mov_b_rm_r0_rn: Store Rm to address Rn + R0 (8-bit). * mov_w_rm_r0_rn: Store Rm to address Rn + R0 (16-bit). * mov_l_rm_r0_rn: Store Rm to address Rn + R0 (32-bit). * mov_b_r0_disp_gbr: Store R0 to address disp + GBR (8-bit). * mov_w_r0_disp_gbr: Store R0 to address disp + GBR (16-bit). * mov_l_r0_disp_gbr: Store R0 to address disp + GBR (32-bit). * mov_l_rm_disp_rn: Store Rm to address disp + Rn. * mov_b_r0_disp_rn: Store R0 to address disp + Rn (8-bit). * mov_w_r0_disp_rn: Store R0 to address disp + Rn (16-bit). * * arg[0] = ptr to rm * arg[1] = ptr to rn (or Rn+(disp<<4) for mov_l_rm_disp_rn) * (or disp for mov_*_r0_disp_gbr) */ X(mov_b_store_rm_rn) { uint32_t addr = reg(ic->arg[1]); uint8_t *p = (uint8_t *) cpu->cd.sh.host_store[addr >> 12]; uint8_t data = reg(ic->arg[0]); if (p != NULL) { p[addr & 0xfff] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, &data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(mov_w_store_rm_rn) { uint32_t addr = reg(ic->arg[1]); uint16_t *p = (uint16_t *) cpu->cd.sh.host_store[addr >> 12]; uint16_t data = reg(ic->arg[0]); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE16_TO_HOST(data); else data = BE16_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 1] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(mov_l_store_rm_rn) { uint32_t addr = reg(ic->arg[1]); uint32_t *p = (uint32_t *) cpu->cd.sh.host_store[addr >> 12]; uint32_t data = reg(ic->arg[0]); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 2] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(fmov_frm_rn) { uint32_t addr = reg(ic->arg[1]); uint32_t *p = (uint32_t *) cpu->cd.sh.host_store[addr >> 12]; uint32_t data = reg(ic->arg[0]); FLOATING_POINT_AVAILABLE_CHECK; if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { // Register pair. Store second word first, then fallback // to store the first word. // Check if it is to an odd register first. size_t r0 = ic->arg[1]; int ofs = (r0 - (size_t)&cpu->cd.sh.fr[0]) / sizeof(uint32_t); if (ofs & 1) { fatal("ODD fmov_frm_rn: TODO"); exit(1); r0 = (size_t)&cpu->cd.sh.xf[ofs & ~1]; } uint32_t data2 = reg(ic->arg[0] + 4); SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr + 4, (unsigned char *)&data2, sizeof(data2), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } // fall-through to write the first word in the pair: } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 2] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(fmov_frm_r0_rn) { uint32_t addr = reg(ic->arg[1]) + cpu->cd.sh.r[0]; uint32_t *p = (uint32_t *) cpu->cd.sh.host_store[addr >> 12]; uint32_t data = reg(ic->arg[0]); FLOATING_POINT_AVAILABLE_CHECK; if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { fatal("fmov_frm_r0_rn: sz=1 (register pair): TODO\n"); ABORT_EXECUTION; return; } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 2] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(fmov_frm_predec_rn) { int d = cpu->cd.sh.fpscr & SH_FPSCR_SZ? 1 : 0; uint32_t data, addr = reg(ic->arg[1]) - (d? 8 : 4); uint32_t *p = (uint32_t *) cpu->cd.sh.host_store[addr >> 12]; size_t r0 = ic->arg[0]; if (d) { /* xd instead of dr? */ int ofs0 = (r0 - (size_t)&cpu->cd.sh.fr[0]) / sizeof(uint32_t); if (ofs0 & 1) r0 = (size_t)&cpu->cd.sh.xf[ofs0 & ~1]; } data = reg(r0); FLOATING_POINT_AVAILABLE_CHECK; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 2] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } if (d) { /* Store second single-precision floating point word: */ data = reg(r0 + 4); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr + 4, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) return; } reg(ic->arg[1]) = addr; } X(mov_b_rm_r0_rn) { uint32_t addr = reg(ic->arg[1]) + cpu->cd.sh.r[0]; int8_t *p = (int8_t *) cpu->cd.sh.host_store[addr >> 12]; int8_t data = reg(ic->arg[0]); if (p != NULL) { p[addr & 0xfff] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(mov_w_rm_r0_rn) { uint32_t addr = reg(ic->arg[1]) + cpu->cd.sh.r[0]; uint16_t *p = (uint16_t *) cpu->cd.sh.host_store[addr >> 12]; uint16_t data = reg(ic->arg[0]); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE16_TO_HOST(data); else data = BE16_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 1] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(mov_l_rm_r0_rn) { uint32_t addr = reg(ic->arg[1]) + cpu->cd.sh.r[0]; uint32_t *p = (uint32_t *) cpu->cd.sh.host_store[addr >> 12]; uint32_t data = reg(ic->arg[0]); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 2] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(mov_b_r0_disp_gbr) { uint32_t addr = cpu->cd.sh.gbr + ic->arg[1]; uint8_t *p = (uint8_t *) cpu->cd.sh.host_store[addr >> 12]; uint8_t data = cpu->cd.sh.r[0]; if (p != NULL) { p[addr & 0xfff] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(mov_w_r0_disp_gbr) { uint32_t addr = cpu->cd.sh.gbr + ic->arg[1]; uint16_t *p = (uint16_t *) cpu->cd.sh.host_store[addr >> 12]; uint16_t data = cpu->cd.sh.r[0]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE16_TO_HOST(data); else data = BE16_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 1] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(mov_l_r0_disp_gbr) { uint32_t addr = cpu->cd.sh.gbr + ic->arg[1]; uint32_t *p = (uint32_t *) cpu->cd.sh.host_store[addr >> 12]; uint32_t data = cpu->cd.sh.r[0]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 2] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(mov_l_rm_disp_rn) { uint32_t addr = cpu->cd.sh.r[ic->arg[1] & 0xf] + ((ic->arg[1] >> 4) << 2); uint32_t *p = (uint32_t *) cpu->cd.sh.host_store[addr >> 12]; uint32_t data = reg(ic->arg[0]); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 2] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(mov_b_r0_disp_rn) { uint32_t addr = reg(ic->arg[0]) + ic->arg[1]; uint8_t *p = (uint8_t *) cpu->cd.sh.host_store[addr >> 12]; uint8_t data = cpu->cd.sh.r[0]; if (p != NULL) { p[addr & 0xfff] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } X(mov_w_r0_disp_rn) { uint32_t addr = reg(ic->arg[0]) + ic->arg[1]; uint16_t *p = (uint16_t *) cpu->cd.sh.host_store[addr >> 12]; uint16_t data = cpu->cd.sh.r[0]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE16_TO_HOST(data); else data = BE16_TO_HOST(data); if (p != NULL) { p[(addr & 0xfff) >> 1] = data; } else { SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)&data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } } } /* * add_rm_rn: rn = rn + rm * addc_rm_rn: rn = rn + rm + t * and_rm_rn: rn = rn & rm * xor_rm_rn: rn = rn ^ rm * or_rm_rn: rn = rn | rm * sub_rm_rn: rn = rn - rm * subc_rm_rn: rn = rn - rm - t; t = borrow * tst_rm_rn: t = ((rm & rn) == 0) * tst_rm: t = (rm == 0) * xtrct_rm_rn: rn = (rn >> 16) | (rm << 16) * * arg[0] = ptr to rm * arg[1] = ptr to rn */ X(add_rm_rn) { reg(ic->arg[1]) += reg(ic->arg[0]); } X(addc_rm_rn) { uint64_t res = reg(ic->arg[1]); res += (uint64_t) reg(ic->arg[0]); if (cpu->cd.sh.sr & SH_SR_T) res ++; if ((res >> 32) & 1) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; reg(ic->arg[1]) = (uint32_t) res; } X(and_rm_rn) { reg(ic->arg[1]) &= reg(ic->arg[0]); } X(xor_rm_rn) { reg(ic->arg[1]) ^= reg(ic->arg[0]); } X(or_rm_rn) { reg(ic->arg[1]) |= reg(ic->arg[0]); } X(sub_rm_rn) { reg(ic->arg[1]) -= reg(ic->arg[0]); } X(subc_rm_rn) { uint64_t res = reg(ic->arg[1]); res -= (uint64_t) reg(ic->arg[0]); if (cpu->cd.sh.sr & SH_SR_T) res --; if ((res >> 32) & 1) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; reg(ic->arg[1]) = (uint32_t) res; } X(tst_rm_rn) { if (reg(ic->arg[1]) & reg(ic->arg[0])) cpu->cd.sh.sr &= ~SH_SR_T; else cpu->cd.sh.sr |= SH_SR_T; } X(tst_rm) { if (reg(ic->arg[0])) cpu->cd.sh.sr &= ~SH_SR_T; else cpu->cd.sh.sr |= SH_SR_T; } X(xtrct_rm_rn) { uint32_t rn = reg(ic->arg[1]), rm = reg(ic->arg[0]); reg(ic->arg[1]) = (rn >> 16) | (rm << 16); } /* * div0u: Division step 0; prepare for unsigned division. * div0s_rm_rn: Division step 0; prepare for signed division. * div1_rm_rn: Division step 1. * * arg[0] = ptr to rm * arg[1] = ptr to rn */ X(div0u) { cpu->cd.sh.sr &= ~(SH_SR_Q | SH_SR_M | SH_SR_T); } X(div0s_rm_rn) { int q = reg(ic->arg[1]) & 0x80000000; int m = reg(ic->arg[0]) & 0x80000000; uint32_t new_sr = cpu->cd.sh.sr & ~(SH_SR_Q | SH_SR_M | SH_SR_T); if (q) new_sr |= SH_SR_Q; if (m) new_sr |= SH_SR_M; if (m ^ q) new_sr |= SH_SR_T; cpu->cd.sh.sr = new_sr; } X(div1_rm_rn) { uint32_t q, old_q = (cpu->cd.sh.sr & SH_SR_Q)? 1 : 0; uint32_t m = (cpu->cd.sh.sr & SH_SR_M)? 1 : 0; uint32_t t = (cpu->cd.sh.sr & SH_SR_T)? 1 : 0; uint32_t op1 = reg(ic->arg[0]), op2 = reg(ic->arg[1]); uint64_t op2_64; q = op2 >> 31; op2_64 = (uint32_t) ((op2 << 1) + t); if (old_q == m) op2_64 -= (uint64_t)op1; else op2_64 += (uint64_t)op1; q ^= m ^ ((op2_64 >> 32) & 1); t = 1 - (q ^ m); cpu->cd.sh.sr &= ~(SH_SR_Q | SH_SR_T); if (q) cpu->cd.sh.sr |= SH_SR_Q; if (t) cpu->cd.sh.sr |= SH_SR_T; reg(ic->arg[1]) = (uint32_t) op2_64; } /* * mul_l_rm_rn: MACL = Rm * Rn (32-bit) * muls_w_rm_rn: MACL = Rm * Rn (signed 16-bit * 16-bit ==> 32-bit) * mulu_w_rm_rn: MACL = Rm * Rn (unsigned 16-bit * 16-bit ==> 32-bit) * dmuls_l_rm_rn: MACH:MACL = Rm * Rn (signed, 64-bit result) * dmulu_l_rm_rn: MACH:MACL = Rm * Rn (unsigned, 64-bit result) * * arg[0] = ptr to rm * arg[1] = ptr to rn */ X(mul_l_rm_rn) { cpu->cd.sh.macl = reg(ic->arg[0]) * reg(ic->arg[1]); } X(muls_w_rm_rn) { cpu->cd.sh.macl = (int32_t)(int16_t)reg(ic->arg[0]) * (int32_t)(int16_t)reg(ic->arg[1]); } X(mulu_w_rm_rn) { cpu->cd.sh.macl = (int32_t)(uint16_t)reg(ic->arg[0]) * (int32_t)(uint16_t)reg(ic->arg[1]); } X(dmuls_l_rm_rn) { uint64_t rm = (int32_t)reg(ic->arg[0]), rn = (int32_t)reg(ic->arg[1]); uint64_t res = rm * rn; cpu->cd.sh.mach = (uint32_t) (res >> 32); cpu->cd.sh.macl = (uint32_t) res; } X(dmulu_l_rm_rn) { uint64_t rm = reg(ic->arg[0]), rn = reg(ic->arg[1]), res; res = rm * rn; cpu->cd.sh.mach = (uint32_t) (res >> 32); cpu->cd.sh.macl = (uint32_t) res; } /* * cmpeq_imm_r0: rn == int8_t immediate * cmpeq_rm_rn: rn == rm * cmphs_rm_rn: rn >= rm, unsigned * cmpge_rm_rn: rn >= rm, signed * cmphi_rm_rn: rn > rm, unsigned * cmpgt_rm_rn: rn > rm, signed * cmppz_rn: rn >= 0, signed * cmppl_rn: rn > 0, signed * cmp_str_rm_rn: t=1 if any bytes in rm and rn match, 0 otherwise * * arg[0] = ptr to rm (or imm, for cmpeq_imm_r0) * arg[1] = ptr to rn */ X(cmpeq_imm_r0) { if (cpu->cd.sh.r[0] == (uint32_t)ic->arg[0]) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; } X(cmpeq_rm_rn) { if (reg(ic->arg[1]) == reg(ic->arg[0])) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; } X(cmphs_rm_rn) { if (reg(ic->arg[1]) >= reg(ic->arg[0])) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; } X(cmpge_rm_rn) { if ((int32_t)reg(ic->arg[1]) >= (int32_t)reg(ic->arg[0])) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; } X(cmphi_rm_rn) { if (reg(ic->arg[1]) > reg(ic->arg[0])) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; } X(cmpgt_rm_rn) { if ((int32_t)reg(ic->arg[1]) > (int32_t)reg(ic->arg[0])) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; } X(cmppz_rn) { if ((int32_t)reg(ic->arg[1]) >= 0) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; } X(cmppl_rn) { if ((int32_t)reg(ic->arg[1]) > 0) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; } X(cmp_str_rm_rn) { uint32_t r0 = reg(ic->arg[0]), r1 = reg(ic->arg[1]); int t = 0; if ((r0 & 0xff000000) == (r1 & 0xff000000)) t = 1; else if ((r0 & 0xff0000) == (r1 & 0xff0000)) t = 1; else if ((r0 & 0xff00) == (r1 & 0xff00)) t = 1; else if ((r0 & 0xff) == (r1 & 0xff)) t = 1; if (t) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; } /* * shll_rn: Shift rn left by 1 (t = bit that was shifted out) * shlr_rn: Shift rn right by 1 (t = bit that was shifted out) * rotl_rn: Shift rn left by 1 (t = bit that was shifted out) * rotr_rn: Shift rn right by 1 (t = bit that was shifted out) * shar_rn: Shift rn right arithmetically by 1 (t = bit that was shifted out) * shllX_rn: Shift rn left logically by X bits * shlrX_rn: Shift rn right logically by X bits * rotcl_rn: Rotate rn left via the t bit * rotcr_rn: Rotate rn right via the t bit * dt_rn: Decrease rn; t = (rn == 0) * * arg[1] = ptr to rn */ X(shll_rn) { uint32_t rn = reg(ic->arg[1]); if (rn & 0x80000000) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; reg(ic->arg[1]) = rn << 1; } X(shlr_rn) { uint32_t rn = reg(ic->arg[1]); if (rn & 1) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; reg(ic->arg[1]) = rn >> 1; } X(rotl_rn) { uint32_t rn = reg(ic->arg[1]), x; if (rn & 0x80000000) { x = 1; cpu->cd.sh.sr |= SH_SR_T; } else { x = 0; cpu->cd.sh.sr &= ~SH_SR_T; } reg(ic->arg[1]) = (rn << 1) | x; } X(rotr_rn) { uint32_t rn = reg(ic->arg[1]); if (rn & 1) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; reg(ic->arg[1]) = (rn >> 1) | (rn << 31); } X(shar_rn) { int32_t rn = reg(ic->arg[1]); if (rn & 1) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; reg(ic->arg[1]) = rn >> 1; } X(rotcl_rn) { uint32_t rn = reg(ic->arg[1]), top; top = rn & 0x80000000; rn <<= 1; if (cpu->cd.sh.sr & SH_SR_T) rn ++; if (top) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; reg(ic->arg[1]) = rn; } X(rotcr_rn) { uint32_t rn = reg(ic->arg[1]), bottom; bottom = rn & 1; rn >>= 1; if (cpu->cd.sh.sr & SH_SR_T) rn |= 0x80000000; if (bottom) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; reg(ic->arg[1]) = rn; } X(dt_rn) { uint32_t rn = reg(ic->arg[1]) - 1; if (rn == 0) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; reg(ic->arg[1]) = rn; } X(shll2_rn) { reg(ic->arg[1]) <<= 2; } X(shll8_rn) { reg(ic->arg[1]) <<= 8; } X(shll16_rn) { reg(ic->arg[1]) <<= 16; } X(shlr2_rn) { reg(ic->arg[1]) >>= 2; } X(shlr8_rn) { reg(ic->arg[1]) >>= 8; } X(shlr16_rn) { reg(ic->arg[1]) >>= 16; } /* * shad: Shift Rn arithmetic left/right, as indicated by Rm. Result in Rn. * shld: Shift Rn logically left/right, as indicated by Rm. Result in Rn. * * arg[0] = ptr to rm * arg[1] = ptr to rn */ X(shad) { int32_t rn = reg(ic->arg[1]); int32_t rm = reg(ic->arg[0]); int sa = rm & 0x1f; if (rm >= 0) rn <<= sa; else if (sa != 0) rn >>= (32 - sa); else if (rn < 0) rn = -1; else rn = 0; reg(ic->arg[1]) = rn; } X(shld) { uint32_t rn = reg(ic->arg[1]); int32_t rm = reg(ic->arg[0]); int sa = rm & 0x1f; if (rm >= 0) rn <<= sa; else if (sa != 0) rn >>= (32 - sa); else rn = 0; reg(ic->arg[1]) = rn; } /* * bra: Branch using PC relative immediace displacement (with delay-slot) * bsr: Like bra, but also sets PR to the return address * braf: Like bra, but using a register instead of an immediate * bsrf: Like braf, but also sets PR to the return address * * arg[0] = immediate offset relative to start of page, * or ptr to target instruction, for samepage branches * arg[1] = ptr to Rn (for braf/bsrf) */ X(bra) { MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); target += ic->arg[0]; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = target; cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(bra_samepage) { cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) cpu->cd.sh.next_ic = (struct sh_instr_call *) ic->arg[0]; cpu->delay_slot = NOT_DELAYED; } X(bsr) { MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); uint32_t old_pc; SYNCH_PC; old_pc = cpu->pc; target += ic->arg[0]; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->cd.sh.pr = old_pc + 4; cpu->pc = target; cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(bsr_trace) { MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); uint32_t old_pc; SYNCH_PC; old_pc = cpu->pc; target += ic->arg[0]; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->cd.sh.pr = old_pc + 4; cpu->pc = target; cpu_functioncall_trace(cpu, cpu->pc); cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(bsr_samepage) { uint32_t old_pc; SYNCH_PC; old_pc = cpu->pc; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->cd.sh.pr = old_pc + 4; cpu->cd.sh.next_ic = (struct sh_instr_call *) ic->arg[0]; } cpu->delay_slot = NOT_DELAYED; } X(braf_rn) { MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); target += ic->arg[0] + reg(ic->arg[1]); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = target; cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(bsrf_rn) { MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); uint32_t old_pc; SYNCH_PC; old_pc = cpu->pc; target += ic->arg[0] + reg(ic->arg[1]); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->cd.sh.pr = old_pc + 4; cpu->pc = target; cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(bsrf_rn_trace) { MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); uint32_t old_pc; SYNCH_PC; old_pc = cpu->pc; target += ic->arg[0] + reg(ic->arg[1]); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->cd.sh.pr = old_pc + 4; cpu->pc = target; cpu_functioncall_trace(cpu, cpu->pc); cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } /* * bt: Branch if true * bf: Branch if false * bt/s: Branch if true (with delay-slot) * bf/s: Branch if false (with delay-slot) * * arg[0] = immediate offset relative to start of page * arg[1] = for samepage functions, the new instruction pointer */ X(bt) { if (cpu->cd.sh.sr & SH_SR_T) { cpu->pc &= ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); cpu->pc += ic->arg[0]; quick_pc_to_pointers(cpu); } } X(bf) { if (!(cpu->cd.sh.sr & SH_SR_T)) { cpu->pc &= ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); cpu->pc += ic->arg[0]; quick_pc_to_pointers(cpu); } } X(bt_samepage) { if (cpu->cd.sh.sr & SH_SR_T) cpu->cd.sh.next_ic = (struct sh_instr_call *) ic->arg[1]; } X(bf_samepage) { if (!(cpu->cd.sh.sr & SH_SR_T)) cpu->cd.sh.next_ic = (struct sh_instr_call *) ic->arg[1]; } X(bt_s) { MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); int cond = cpu->cd.sh.sr & SH_SR_T; target += ic->arg[0]; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->delay_slot = NOT_DELAYED; if (cond) { cpu->pc = target; quick_pc_to_pointers(cpu); } else cpu->cd.sh.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bf_s) { MODE_int_t target = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); int cond = !(cpu->cd.sh.sr & SH_SR_T); target += ic->arg[0]; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->delay_slot = NOT_DELAYED; if (cond) { cpu->pc = target; quick_pc_to_pointers(cpu); } else cpu->cd.sh.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bt_s_samepage) { int cond = cpu->cd.sh.sr & SH_SR_T; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->delay_slot = NOT_DELAYED; if (cond) cpu->cd.sh.next_ic = (struct sh_instr_call *) ic->arg[1]; else cpu->cd.sh.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bf_s_samepage) { int cond = !(cpu->cd.sh.sr & SH_SR_T); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->delay_slot = NOT_DELAYED; if (cond) cpu->cd.sh.next_ic = (struct sh_instr_call *) ic->arg[1]; else cpu->cd.sh.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } /* * jmp_rn: Jump to Rn * jsr_rn: Jump to Rn, store return address in PR. * * arg[0] = ptr to rn */ X(jmp_rn) { MODE_int_t target = reg(ic->arg[0]); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = target; cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(jmp_rn_trace) { MODE_int_t target = reg(ic->arg[0]); cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = target; #if 0 /* NOTE: Jmp works like both a return, and a subroutine call. */ cpu_functioncall_trace_return(cpu); cpu_functioncall_trace(cpu, cpu->pc); #endif cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(jsr_rn) { MODE_int_t target = reg(ic->arg[0]), retaddr; cpu->delay_slot = TO_BE_DELAYED; retaddr = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; cpu->cd.sh.pr = retaddr + (int32_t)ic->arg[1]; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = target; cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(jsr_rn_trace) { MODE_int_t target = reg(ic->arg[0]), retaddr; cpu->delay_slot = TO_BE_DELAYED; retaddr = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; cpu->cd.sh.pr = retaddr + (int32_t)ic->arg[1]; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = target; cpu_functioncall_trace(cpu, cpu->pc); cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } /* * rts: Jump to PR. */ X(rts) { MODE_int_t target = cpu->cd.sh.pr; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = target; cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(rts_trace) { MODE_int_t target = cpu->cd.sh.pr; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = target; cpu_functioncall_trace_return(cpu); cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } /* * rte: Return from exception. */ X(rte) { RES_INST_IF_NOT_MD; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->pc = cpu->cd.sh.spc; cpu->delay_slot = NOT_DELAYED; sh_update_sr(cpu, cpu->cd.sh.ssr); quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } /* * ldtlb: Load UTLB entry. */ X(ldtlb) { uint32_t old_hi, old_lo; int urc = (cpu->cd.sh.mmucr & SH4_MMUCR_URC_MASK) >> SH4_MMUCR_URC_SHIFT; RES_INST_IF_NOT_MD; old_hi = cpu->cd.sh.utlb_hi[urc]; old_lo = cpu->cd.sh.utlb_lo[urc]; cpu->cd.sh.utlb_hi[urc] = cpu->cd.sh.pteh; cpu->cd.sh.utlb_lo[urc] = cpu->cd.sh.ptel; /* Invalidate the old mapping, if it belonged to the same ASID: */ if ((old_hi & SH4_PTEH_ASID_MASK) == (cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK)) { if ((old_lo & SH4_PTEL_SZ_MASK) == SH4_PTEL_SZ_4K) cpu->invalidate_translation_caches(cpu, old_hi & 0xfffff000, INVALIDATE_VADDR); else cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); } } /* * copy_privileged_register: Copy normal into privileged register, or vice * versa, after checking the MD status bit. * * arg[0] = ptr to source register * arg[1] = ptr to destination register */ X(copy_privileged_register) { RES_INST_IF_NOT_MD; reg(ic->arg[1]) = reg(ic->arg[0]); } /* * ldc_rm_sr: Copy Rm into SR, after checking the MD status bit. * * arg[1] = ptr to rm */ X(ldc_rm_sr) { RES_INST_IF_NOT_MD; sh_update_sr(cpu, reg(ic->arg[1])); #if 0 /* NOTE: This code causes NetBSD/landisk to get past a point where it otherwise hangs, but it causes Linux/Dreamcast to bug out instead. :/ */ if (!(cpu->cd.sh.sr & SH_SR_BL) && cpu->cd.sh.int_to_assert > 0 && ( (cpu->cd.sh.sr & SH_SR_IMASK) >> SH_SR_IMASK_SHIFT) < cpu->cd.sh.int_level) { /* Cause interrupt immediately, by dropping out of the main dyntrans loop: */ cpu->cd.sh.next_ic = ¬hing_call; } #endif } /* * trapa: Immediate trap. * * arg[0] = imm << 2 */ X(trapa) { SYNCH_PC; if (cpu->delay_slot) { sh_exception(cpu, EXPEVT_SLOT_INST, 0, 0); return; } cpu->cd.sh.tra = ic->arg[0]; sh_exception(cpu, EXPEVT_TRAPA, 0, 0); } /* * copy_fp_register: Copy a register into another, with FP avail check. * lds_rm_fpscr: Copy Rm into FPSCR. * * arg[0] = ptr to source * arg[1] = ptr to destination */ X(copy_fp_register) { FLOATING_POINT_AVAILABLE_CHECK; reg(ic->arg[1]) = reg(ic->arg[0]); } X(lds_rm_fpscr) { FLOATING_POINT_AVAILABLE_CHECK; sh_update_fpscr(cpu, reg(ic->arg[1])); } /* * fmov_frm_frn: Copy one floating-point register (or pair) to another. * * arg[0] = ptr to source float register or pair * arg[1] = ptr to destination float register or pair */ X(fmov_frm_frn) { size_t r0, r1; int ofs0, ofs1; FLOATING_POINT_AVAILABLE_CHECK; /* Simplest case, single-precision: */ if (!(cpu->cd.sh.fpscr & SH_FPSCR_SZ)) { reg(ic->arg[1]) = reg(ic->arg[0]); return; } /* Double-precision: */ r0 = ic->arg[0]; r1 = ic->arg[1]; ofs0 = (r0 - (size_t)&cpu->cd.sh.fr[0]) / sizeof(uint32_t); ofs1 = (r1 - (size_t)&cpu->cd.sh.fr[0]) / sizeof(uint32_t); if (ofs0 & 1) r0 = (size_t)&cpu->cd.sh.xf[ofs0 & ~1]; if (ofs1 & 1) r1 = (size_t)&cpu->cd.sh.xf[ofs1 & ~1]; reg(r1) = reg(r0); reg(r1 + 4) = reg(r0 + 4); } /* * float_fpul_frn: Load FPUL into float register. * * arg[0] = ptr to float register, or float register pair */ X(float_fpul_frn) { int32_t fpul = cpu->cd.sh.fpul; FLOATING_POINT_AVAILABLE_CHECK; if (cpu->cd.sh.fpscr & SH_FPSCR_PR) { /* Double-precision, using a pair of registers: */ uint64_t ieee = ieee_store_float_value(fpul, IEEE_FMT_D); reg(ic->arg[0]) = (uint32_t) (ieee >> 32); reg(ic->arg[0] + sizeof(uint32_t)) = (uint32_t) ieee; } else { /* Single-precision: */ uint32_t ieee = ieee_store_float_value(fpul, IEEE_FMT_S); reg(ic->arg[0]) = (uint32_t) ieee; } } /* * ftrc_frm_fpul: Truncate a float register into FPUL. * * arg[0] = ptr to float register, or float register pair */ X(ftrc_frm_fpul) { struct ieee_float_value op1; FLOATING_POINT_AVAILABLE_CHECK; if (cpu->cd.sh.fpscr & SH_FPSCR_PR) { /* Double-precision, using a pair of registers: */ int64_t r1 = ((uint64_t)reg(ic->arg[0]) << 32) + reg(ic->arg[0] + sizeof(uint32_t)); ieee_interpret_float_value(r1, &op1, IEEE_FMT_D); cpu->cd.sh.fpul = (int32_t) op1.f; } else { /* Single-precision: */ ieee_interpret_float_value(reg(ic->arg[0]), &op1, IEEE_FMT_S); cpu->cd.sh.fpul = (int32_t) op1.f; } } /* * fcnvsd_fpul_drn: Convert single-precision to double-precision. * fcnvds_drm_fpul: Convert double-precision to single-precision. * * arg[0] = ptr to destination (double- or single-precision float) */ X(fcnvsd_fpul_drn) { struct ieee_float_value op1; int64_t ieee; FLOATING_POINT_AVAILABLE_CHECK; ieee_interpret_float_value(cpu->cd.sh.fpul, &op1, IEEE_FMT_S); cpu->cd.sh.fpul = (int32_t) op1.f; /* Store double-precision result: */ ieee = ieee_store_float_value(op1.f, IEEE_FMT_D); reg(ic->arg[0]) = (uint32_t) (ieee >> 32); reg(ic->arg[0] + sizeof(uint32_t)) = (uint32_t) ieee; } X(fcnvds_drm_fpul) { struct ieee_float_value op1; int64_t r1; FLOATING_POINT_AVAILABLE_CHECK; r1 = reg(ic->arg[0] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[0]) << 32); ieee_interpret_float_value(r1, &op1, IEEE_FMT_D); cpu->cd.sh.fpul = ieee_store_float_value(op1.f, IEEE_FMT_S); } /* * fsca_fpul_drn: Sinus/cosinus approximation. * * Note: This is an interesting instruction. It is not included in the SH4 * manual. Some googling indicated that this might be an SH4X instruction. * On the other hand, it is used by Dreamcast code (and the Dreamcast has an * SH4), and a cvs comment for gdb said that this is an SH4 instruction, not * an SH4A instruction. Well well... * * arg[0] = ptr to single-precision float register pair */ X(fsca_fpul_drn) { double fpulAngle = ((double)cpu->cd.sh.fpul) * 2.0 * M_PI / 65536.0; FLOATING_POINT_AVAILABLE_CHECK; reg(ic->arg[0]) = ieee_store_float_value(sin(fpulAngle), IEEE_FMT_S); reg(ic->arg[0] + sizeof(uint32_t)) = ieee_store_float_value(cos(fpulAngle), IEEE_FMT_S); } /* * fipr_fvm_fvn: Vector * vector => scalar * * arg[0] = ptr to FVm * arg[1] = ptr to FVn * * Result of adding all FR{m+i} * FR{n+i} where i=0..3 * is stored in FR{n+3}. */ X(fipr_fvm_fvn) { struct ieee_float_value frn0, frn1, frn2, frn3; struct ieee_float_value frm0, frm1, frm2, frm3; FLOATING_POINT_AVAILABLE_CHECK; ieee_interpret_float_value(reg(ic->arg[0] + 0), &frm0, IEEE_FMT_S); ieee_interpret_float_value(reg(ic->arg[0] + 4), &frm1, IEEE_FMT_S); ieee_interpret_float_value(reg(ic->arg[0] + 8), &frm2, IEEE_FMT_S); ieee_interpret_float_value(reg(ic->arg[0] + 12), &frm3, IEEE_FMT_S); ieee_interpret_float_value(reg(ic->arg[1] + 0), &frn0, IEEE_FMT_S); ieee_interpret_float_value(reg(ic->arg[1] + 4), &frn1, IEEE_FMT_S); ieee_interpret_float_value(reg(ic->arg[1] + 8), &frn2, IEEE_FMT_S); ieee_interpret_float_value(reg(ic->arg[1] + 12), &frn3, IEEE_FMT_S); frn3.f = frm0.f * frn0.f + frm1.f * frn1.f + frm2.f * frn2.f + frm3.f * frn3.f; reg(ic->arg[1] + 12) = ieee_store_float_value(frn3.f, IEEE_FMT_S); } /* * ftrv_xmtrx_fvn: Matrix * vector ==> vector * * arg[0] = ptr to FVn */ X(ftrv_xmtrx_fvn) { int i; struct ieee_float_value xmtrx[16], frn[4]; double frnp0 = 0.0, frnp1 = 0.0, frnp2 = 0.0, frnp3 = 0.0; FLOATING_POINT_AVAILABLE_CHECK; // TODO: FPSCR.EN.V = 1 should cause invalid operation exception? ieee_interpret_float_value(reg(ic->arg[0] + 0), &frn[0], IEEE_FMT_S); ieee_interpret_float_value(reg(ic->arg[0] + 4), &frn[1], IEEE_FMT_S); ieee_interpret_float_value(reg(ic->arg[0] + 8), &frn[2], IEEE_FMT_S); ieee_interpret_float_value(reg(ic->arg[0] + 12), &frn[3], IEEE_FMT_S); for (i=0; i<16; i++) ieee_interpret_float_value(cpu->cd.sh.xf[i], &xmtrx[i], IEEE_FMT_S); for (i=0; i<4; i++) frnp0 += xmtrx[i*4].f * frn[i].f; for (i=0; i<4; i++) frnp1 += xmtrx[i*4 + 1].f * frn[i].f; for (i=0; i<4; i++) frnp2 += xmtrx[i*4 + 2].f * frn[i].f; for (i=0; i<4; i++) frnp3 += xmtrx[i*4 + 3].f * frn[i].f; reg(ic->arg[0] + 0) = ieee_store_float_value(frnp0, IEEE_FMT_S); reg(ic->arg[0] + 4) = ieee_store_float_value(frnp1, IEEE_FMT_S); reg(ic->arg[0] + 8) = ieee_store_float_value(frnp2, IEEE_FMT_S); reg(ic->arg[0] + 12) = ieee_store_float_value(frnp3, IEEE_FMT_S); } /* * fldi: Load immediate (0.0 or 1.0) into floating point register. * fneg: Negate a floating point register * fabs: Get the absolute value of a floating point register * fsqrt: Calculate square root * fsrra: Calculate 1 / (square root) * * arg[0] = ptr to fp register * arg[1] = (uint32_t) immediate value (for fldi) */ X(fldi_frn) { FLOATING_POINT_AVAILABLE_CHECK; reg(ic->arg[0]) = ic->arg[1]; } X(fneg_frn) { FLOATING_POINT_AVAILABLE_CHECK; // Hm. If in double register mode... and the register is pointing to // an _odd_ register, what happens then? if (cpu->cd.sh.fpscr & SH_FPSCR_PR) { int ofs0 = (ic->arg[0] - (size_t)&cpu->cd.sh.fr[0]) / sizeof(uint32_t); if (ofs0 & 1) { fatal("TODO: fneg_frn odd register in double prec. mode.\n"); exit(1); } } /* Note: This also works for double-precision. */ reg(ic->arg[0]) ^= 0x80000000; } X(fabs_frn) { FLOATING_POINT_AVAILABLE_CHECK; // Hm. If in double register mode... and the register is pointing to // an _odd_ register, what happens then? if (cpu->cd.sh.fpscr & SH_FPSCR_PR) { int ofs0 = (ic->arg[0] - (size_t)&cpu->cd.sh.fr[0]) / sizeof(uint32_t); if (ofs0 & 1) { fatal("TODO: fneg_frn odd register in double prec. mode.\n"); exit(1); } } /* Note: This also works for double-precision. */ reg(ic->arg[0]) &= 0x7fffffff; } X(fsqrt_frn) { struct ieee_float_value op1; FLOATING_POINT_AVAILABLE_CHECK; if (cpu->cd.sh.fpscr & SH_FPSCR_PR) { /* Double-precision: */ int64_t r1, ieee; r1 = reg(ic->arg[0] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[0]) << 32); ieee_interpret_float_value(r1, &op1, IEEE_FMT_D); ieee = ieee_store_float_value(sqrt(op1.f), IEEE_FMT_D); reg(ic->arg[0]) = (uint32_t) (ieee >> 32); reg(ic->arg[0] + sizeof(uint32_t)) = (uint32_t) ieee; } else { /* Single-precision: */ int32_t ieee, r1 = reg(ic->arg[0]); ieee_interpret_float_value(r1, &op1, IEEE_FMT_S); ieee = ieee_store_float_value(sqrt(op1.f), IEEE_FMT_S); reg(ic->arg[0]) = ieee; } } X(fsrra_frn) { // I'm guessing that this is 1/sqrt. That's how it is described at // http://yam.20to4.net/dreamcast/hints/index.html at least. struct ieee_float_value op1; FLOATING_POINT_AVAILABLE_CHECK; if (cpu->cd.sh.fpscr & SH_FPSCR_PR) { /* Double-precision: */ fatal("Double-precision fsrra? TODO\n"); ABORT_EXECUTION; return; } else { /* Single-precision: */ int32_t ieee, r1 = reg(ic->arg[0]); ieee_interpret_float_value(r1, &op1, IEEE_FMT_S); ieee = ieee_store_float_value(1.0f / sqrt(op1.f), IEEE_FMT_S); reg(ic->arg[0]) = ieee; } } /* * fadd_frm_frn: Floating point addition. * fsub_frm_frn: Floating point subtraction. * fmul_frm_frn: Floating point multiplication. * fdiv_frm_frn: Floating point division. * fmac_fr0_frm_frn: Multiply-and-accumulate. * fcmp_eq_frm_frn: Floating point greater-than comparison. * fcmp_gt_frm_frn: Floating point greater-than comparison. * * arg[0] = ptr to float register FRm * arg[1] = ptr to float register FRn */ X(fadd_frm_frn) { struct ieee_float_value op1, op2; FLOATING_POINT_AVAILABLE_CHECK; if (cpu->cd.sh.fpscr & SH_FPSCR_PR) { /* Double-precision, using a pair of registers: */ int64_t r1, r2, ieee; double result; r1 = reg(ic->arg[0] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[0]) << 32); r2 = reg(ic->arg[1] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[1]) << 32); ieee_interpret_float_value(r1, &op1, IEEE_FMT_D); ieee_interpret_float_value(r2, &op2, IEEE_FMT_D); result = op2.f + op1.f; ieee = ieee_store_float_value(result, IEEE_FMT_D); reg(ic->arg[1]) = (uint32_t) (ieee >> 32); reg(ic->arg[1] + sizeof(uint32_t)) = (uint32_t) ieee; } else { /* Single-precision: */ uint32_t r1, r2, ieee; double result; r1 = reg(ic->arg[0]); r2 = reg(ic->arg[1]); ieee_interpret_float_value(r1, &op1, IEEE_FMT_S); ieee_interpret_float_value(r2, &op2, IEEE_FMT_S); result = op2.f + op1.f; ieee = ieee_store_float_value(result, IEEE_FMT_S); reg(ic->arg[1]) = (uint32_t) ieee; } } X(fsub_frm_frn) { struct ieee_float_value op1, op2; FLOATING_POINT_AVAILABLE_CHECK; if (cpu->cd.sh.fpscr & SH_FPSCR_PR) { /* Double-precision, using a pair of registers: */ int64_t r1, r2, ieee; double result; r1 = reg(ic->arg[0] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[0]) << 32); r2 = reg(ic->arg[1] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[1]) << 32); ieee_interpret_float_value(r1, &op1, IEEE_FMT_D); ieee_interpret_float_value(r2, &op2, IEEE_FMT_D); result = op2.f - op1.f; ieee = ieee_store_float_value(result, IEEE_FMT_D); reg(ic->arg[1]) = (uint32_t) (ieee >> 32); reg(ic->arg[1] + sizeof(uint32_t)) = (uint32_t) ieee; } else { /* Single-precision: */ uint32_t r1, r2, ieee; double result; r1 = reg(ic->arg[0]); r2 = reg(ic->arg[1]); ieee_interpret_float_value(r1, &op1, IEEE_FMT_S); ieee_interpret_float_value(r2, &op2, IEEE_FMT_S); result = op2.f - op1.f; ieee = ieee_store_float_value(result, IEEE_FMT_S); reg(ic->arg[1]) = (uint32_t) ieee; } } X(fmul_frm_frn) { struct ieee_float_value op1, op2; FLOATING_POINT_AVAILABLE_CHECK; if (cpu->cd.sh.fpscr & SH_FPSCR_PR) { /* Double-precision, using a pair of registers: */ int64_t r1, r2, ieee; double result; r1 = reg(ic->arg[0] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[0]) << 32); r2 = reg(ic->arg[1] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[1]) << 32); ieee_interpret_float_value(r1, &op1, IEEE_FMT_D); ieee_interpret_float_value(r2, &op2, IEEE_FMT_D); result = op2.f * op1.f; ieee = ieee_store_float_value(result, IEEE_FMT_D); reg(ic->arg[1]) = (uint32_t) (ieee >> 32); reg(ic->arg[1] + sizeof(uint32_t)) = (uint32_t) ieee; } else { /* Single-precision: */ uint32_t r1, r2, ieee; double result; r1 = reg(ic->arg[0]); r2 = reg(ic->arg[1]); ieee_interpret_float_value(r1, &op1, IEEE_FMT_S); ieee_interpret_float_value(r2, &op2, IEEE_FMT_S); result = op2.f * op1.f; ieee = ieee_store_float_value(result, IEEE_FMT_S); reg(ic->arg[1]) = (uint32_t) ieee; } } X(fdiv_frm_frn) { struct ieee_float_value op1, op2; FLOATING_POINT_AVAILABLE_CHECK; if (cpu->cd.sh.fpscr & SH_FPSCR_PR) { /* Double-precision, using a pair of registers: */ int64_t r1, r2, ieee; double result; r1 = reg(ic->arg[0] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[0]) << 32); r2 = reg(ic->arg[1] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[1]) << 32); ieee_interpret_float_value(r1, &op1, IEEE_FMT_D); ieee_interpret_float_value(r2, &op2, IEEE_FMT_D); if (op1.f != 0.0) result = op2.f / op1.f; else result = 0.0; ieee = ieee_store_float_value(result, IEEE_FMT_D); reg(ic->arg[1]) = (uint32_t) (ieee >> 32); reg(ic->arg[1] + sizeof(uint32_t)) = (uint32_t) ieee; } else { /* Single-precision: */ uint32_t r1, r2, ieee; double result; r1 = reg(ic->arg[0]); r2 = reg(ic->arg[1]); ieee_interpret_float_value(r1, &op1, IEEE_FMT_S); ieee_interpret_float_value(r2, &op2, IEEE_FMT_S); if (op1.f != 0.0) result = op2.f / op1.f; else result = 0.0; ieee = ieee_store_float_value(result, IEEE_FMT_S); reg(ic->arg[1]) = (uint32_t) ieee; } } X(fmac_fr0_frm_frn) { struct ieee_float_value op1, op2, op0; int32_t r1, r2, fr0 = cpu->cd.sh.fr[0], ieee; FLOATING_POINT_AVAILABLE_CHECK; r1 = reg(ic->arg[0]), r2 = reg(ic->arg[1]); ieee_interpret_float_value(fr0, &op0, IEEE_FMT_S); ieee_interpret_float_value(r1, &op1, IEEE_FMT_S); ieee_interpret_float_value(r2, &op2, IEEE_FMT_S); ieee = ieee_store_float_value(op0.f * op1.f + op2.f, IEEE_FMT_S); reg(ic->arg[1]) = ieee; } X(fcmp_eq_frm_frn) { struct ieee_float_value op1, op2; FLOATING_POINT_AVAILABLE_CHECK; if (cpu->cd.sh.fpscr & SH_FPSCR_PR) { /* Double-precision, using a pair of registers: */ int64_t r1, r2; r1 = reg(ic->arg[0] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[0]) << 32); r2 = reg(ic->arg[1] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[1]) << 32); ieee_interpret_float_value(r1, &op1, IEEE_FMT_D); ieee_interpret_float_value(r2, &op2, IEEE_FMT_D); } else { /* Single-precision: */ uint32_t r1 = reg(ic->arg[0]), r2 = reg(ic->arg[1]); ieee_interpret_float_value(r1, &op1, IEEE_FMT_S); ieee_interpret_float_value(r2, &op2, IEEE_FMT_S); } if (op2.f == op1.f) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; } X(fcmp_gt_frm_frn) { struct ieee_float_value op1, op2; FLOATING_POINT_AVAILABLE_CHECK; if (cpu->cd.sh.fpscr & SH_FPSCR_PR) { /* Double-precision, using a pair of registers: */ int64_t r1, r2; r1 = reg(ic->arg[0] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[0]) << 32); r2 = reg(ic->arg[1] + sizeof(uint32_t)) + ((uint64_t)reg(ic->arg[1]) << 32); ieee_interpret_float_value(r1, &op1, IEEE_FMT_D); ieee_interpret_float_value(r2, &op2, IEEE_FMT_D); } else { /* Single-precision: */ uint32_t r1 = reg(ic->arg[0]), r2 = reg(ic->arg[1]); ieee_interpret_float_value(r1, &op1, IEEE_FMT_S); ieee_interpret_float_value(r2, &op2, IEEE_FMT_S); } if (op2.f > op1.f) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; } /* * frchg: Change floating-point register banks. * fschg: Change floating-point register size. */ X(frchg) { FLOATING_POINT_AVAILABLE_CHECK; sh_update_fpscr(cpu, cpu->cd.sh.fpscr ^ SH_FPSCR_FR); } X(fschg) { FLOATING_POINT_AVAILABLE_CHECK; sh_update_fpscr(cpu, cpu->cd.sh.fpscr ^ SH_FPSCR_SZ); } /* * pref_rn: Prefetch. * * TODO: According to the SH4 manual, "OTLBMULTIHIT or RADDERR may be * delivered", so those things should be checked for. Not implemented yet. * * arg[1] = ptr to Rn */ X(pref_rn) { uint32_t addr = reg(ic->arg[1]), extaddr; int sq_nr, ofs; if (addr < 0xe0000000U || addr >= 0xe4000000U) { // printf("[ SH4 pref 0x%08x (pc = 0x%08x) ]\n", addr, (int)cpu->pc); return; } SYNCH_PC; // Calculate the external address: extaddr = addr & 0x03ffffe0; sq_nr = addr & 0x20? 1 : 0; // if (addr & 0x0000001f) // debug("[ WARNING: SH4 Store Queue, addr = 0x%08x... lowest 5 " // "bits are non-zero. Ignoring. ]\n", addr); if (sq_nr == 0) extaddr |= (((cpu->cd.sh.qacr0 >> 2) & 7) << 26); else extaddr |= (((cpu->cd.sh.qacr1 >> 2) & 7) << 26); // fatal("[ SH4 pref: SQ extaddr = 0x%08x (pc = 0x%08x) ]\n", extaddr, (int)cpu->pc); // Is the MMU turned on? if (cpu->cd.sh.mmucr & SH4_MMUCR_AT) { // When the SQMD bit in MMUCR is set, user access is prohibited // if the MMU is enabled. if (cpu->cd.sh.mmucr & SH4_MMUCR_SQMD) { bool inUserMode = (cpu->cd.sh.sr & SH_SR_MD) ? false : true; if (inUserMode) { sh_exception(cpu, EXPEVT_RES_INST, 0, 0); return; } } fatal("Store Queue to external memory, when " "MMU enabled: Not yet implemented... TODO\n"); ABORT_EXECUTION; return; } for (ofs = 0; ofs < 32; ofs += sizeof(uint32_t)) { uint32_t word; cpu->memory_rw(cpu, cpu->mem, 0xe0000000UL + ofs + sq_nr * 0x20, (unsigned char *) &word, sizeof(word), MEM_READ, PHYSICAL); // fatal(" addr %08x: %08x\n", (extaddr + ofs), word); cpu->memory_rw(cpu, cpu->mem, extaddr+ofs, (unsigned char *) &word, sizeof(word), MEM_WRITE, PHYSICAL); } } /* * tas_b_rn: Test-and-Set. * * arg[1] = ptr to Rn */ X(tas_b_rn) { uint32_t addr = reg(ic->arg[1]); uint8_t byte, newbyte; SYNCH_PC; if (!cpu->memory_rw(cpu, cpu->mem, addr, &byte, 1, MEM_READ, CACHE_DATA)) { /* Exception. */ return; } newbyte = byte | 0x80; if (!cpu->memory_rw(cpu, cpu->mem, addr, &newbyte, 1, MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } if (byte == 0) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; } /* * prom_emul: */ X(prom_emul) { uint32_t old_pc; SYNCH_PC; old_pc = cpu->pc; switch (cpu->machine->machine_type) { case MACHINE_DREAMCAST: dreamcast_emul(cpu); break; case MACHINE_LANDISK: sh_ipl_g_emul(cpu); break; default: fatal("SH prom_emul: unimplemented machine type.\n"); exit(1); } if (!cpu->running) { cpu->n_translated_instrs --; cpu->cd.sh.next_ic = ¬hing_call; } else if ((uint32_t)cpu->pc != old_pc) { /* The PC value was changed by the PROM call. */ quick_pc_to_pointers(cpu); } } /*****************************************************************************/ /* * bt_samepage_wait_for_variable: * * Loop which reads a variable in memory forever until it changes state, * can most likely only change state if an interrupt occurs. Simulate speed * by skipping ahead quickly, until the next interrupt occurs. * * z: mov.l (X,gbr),r0 mov_l_disp_gbr_r0 with arg[1] = X * cmp/eq r0,rY cmpeq_rm_rn with args 0 and 1 being r0 and rY * bt x bt_samepage with arg[1] = z */ X(bt_samepage_wait_for_variable) { if (cpu->delay_slot) { instr(mov_l_disp_gbr_r0)(cpu, ic); return; } // mov_l_disp_gbr_r0: // Bail out quickly if the memory is not on a readable page. uint32_t addr = cpu->cd.sh.gbr + ic->arg[1]; uint32_t *p = (uint32_t *) cpu->cd.sh.host_load[addr >> 12]; if (p == NULL) { instr(mov_l_disp_gbr_r0)(cpu, ic); return; } uint32_t data = p[(addr & 0xfff) >> 2]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); cpu->cd.sh.r[0] = data; // cmpeq_rm_rn: if (reg(ic[1].arg[1]) == reg(ic[1].arg[0])) cpu->cd.sh.sr |= SH_SR_T; else cpu->cd.sh.sr &= ~SH_SR_T; // Loop for a "long time" if the two registered were equal. if (cpu->cd.sh.sr & SH_SR_T) { // Some bogus amount of instructions. // TODO: Make nicer? cpu->n_translated_instrs += 500; cpu->cd.sh.next_ic = ic; // "jump to z" } else { // otherwise, get out of the loop. cpu->n_translated_instrs += 2; cpu->cd.sh.next_ic = ic + 3; } } /*****************************************************************************/ /* * Combine: something ending with a bt_samepage. * * See comment for bt_samepage_wait_for_variable above for details. */ void COMBINE(bt_samepage)(struct cpu *cpu, struct sh_instr_call *ic, int low_addr) { int n_back = (low_addr >> SH_INSTR_ALIGNMENT_SHIFT) & (SH_IC_ENTRIES_PER_PAGE - 1); if (n_back < 2) return; if (ic[-2].f == instr(mov_l_disp_gbr_r0) && ic[-1].f == instr(cmpeq_rm_rn) && (ic[-1].arg[0] == (size_t) &cpu->cd.sh.r[0] || ic[-1].arg[1] == (size_t) &cpu->cd.sh.r[0]) && ic[0].arg[1] == (size_t) &ic[-2]) { ic[-2].f = instr(bt_samepage_wait_for_variable); } } /*****************************************************************************/ X(end_of_page) { /* Update the PC: (offset 0, but on the next page) */ cpu->pc &= ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); cpu->pc += (SH_IC_ENTRIES_PER_PAGE << SH_INSTR_ALIGNMENT_SHIFT); /* end_of_page doesn't count as an executed instruction: */ cpu->n_translated_instrs --; /* * Find the new physpage and update translation pointers. * * Note: This may cause an exception, if e.g. the new page is * not accessible. */ quick_pc_to_pointers(cpu); /* Simple jump to the next page (if we are lucky): */ if (cpu->delay_slot == NOT_DELAYED) return; /* * If we were in a delay slot, and we got an exception while doing * quick_pc_to_pointers, then return. The function which called * end_of_page should handle this case. */ if (cpu->delay_slot == EXCEPTION_IN_DELAY_SLOT) return; /* * Tricky situation; the delay slot is on the next virtual page. * Calling to_be_translated will translate one instruction manually, * execute it, and then discard it. */ /* fatal("[ end_of_page: delay slot across page boundary! ]\n"); */ instr(to_be_translated)(cpu, cpu->cd.sh.next_ic); /* The instruction in the delay slot has now executed. */ /* fatal("[ end_of_page: back from executing the delay slot, %i ]\n", cpu->delay_slot); */ /* Find the physpage etc of the instruction in the delay slot (or, if there was an exception, the exception handler): */ quick_pc_to_pointers(cpu); } X(end_of_page2) { /* Synchronize PC on the _second_ instruction on the next page: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.sh.cur_ic_page) / sizeof(struct sh_instr_call); cpu->pc &= ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << SH_INSTR_ALIGNMENT_SHIFT); /* This doesn't count as an executed instruction. */ cpu->n_translated_instrs --; quick_pc_to_pointers(cpu); if (cpu->delay_slot == NOT_DELAYED) return; fatal("end_of_page2: fatal error, we're in a delay slot\n"); exit(1); } /*****************************************************************************/ /* * sh_instr_to_be_translated(): * * Translate an instruction word into an sh_instr_call. ic is filled in with * valid data for the translated instruction, or a "nothing" instruction if * there was a translation failure. The newly translated instruction is then * executed. */ X(to_be_translated) { uint32_t addr, low_pc, iword; unsigned char *page; unsigned char ib[2]; int main_opcode, isize = sizeof(ib); int in_crosspage_delayslot = 0, r8, r4, lo4, lo8; void (*samepage_function)(struct cpu *, struct sh_instr_call *); /* Figure out the (virtual) address of the instruction: */ low_pc = ((size_t)ic - (size_t)cpu->cd.sh.cur_ic_page) / sizeof(struct sh_instr_call); /* Special case for branch with delayslot on the next page: */ if (cpu->delay_slot == TO_BE_DELAYED && low_pc == 0) { /* fatal("[ delay-slot translation across page " "boundary ]\n"); */ in_crosspage_delayslot = 1; } addr = cpu->pc & ~((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT); addr += (low_pc << SH_INSTR_ALIGNMENT_SHIFT); cpu->pc = (MODE_int_t)addr; addr &= ~((1 << SH_INSTR_ALIGNMENT_SHIFT) - 1); /* Read the instruction word from memory: */ page = cpu->cd.sh.host_load[(uint32_t)addr >> 12]; if (page != NULL) { /* fatal("TRANSLATION HIT!\n"); */ memcpy(ib, page + (addr & 0xfff), isize); } else { /* fatal("TRANSLATION MISS!\n"); */ if (!cpu->memory_rw(cpu, cpu->mem, addr, ib, isize, MEM_READ, CACHE_INSTRUCTION)) { fatal("to_be_translated(): read failed: TODO\n"); goto bad; } } { uint16_t *p = (uint16_t *) ib; iword = *p; } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) iword = LE16_TO_HOST(iword); else iword = BE16_TO_HOST(iword); main_opcode = iword >> 12; r8 = (iword >> 8) & 0xf; r4 = (iword >> 4) & 0xf; lo8 = iword & 0xff; lo4 = iword & 0xf; #define DYNTRANS_TO_BE_TRANSLATED_HEAD #include "cpu_dyntrans.cc" #undef DYNTRANS_TO_BE_TRANSLATED_HEAD /* * Translate the instruction: */ /* Default args. for many instructions: */ ic->arg[0] = (size_t)&cpu->cd.sh.r[r4]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ switch (main_opcode) { case 0x0: if (lo4 == 0x4) { /* MOV.B Rm,@(R0,Rn) */ ic->f = instr(mov_b_rm_r0_rn); } else if (lo4 == 0x5) { /* MOV.W Rm,@(R0,Rn) */ ic->f = instr(mov_w_rm_r0_rn); } else if (lo4 == 0x6) { /* MOV.L Rm,@(R0,Rn) */ ic->f = instr(mov_l_rm_r0_rn); } else if (lo4 == 0x7) { /* MUL.L Rm,Rn */ ic->f = instr(mul_l_rm_rn); } else if (iword == 0x000b) { if (cpu->machine->show_trace_tree) ic->f = instr(rts_trace); else ic->f = instr(rts); } else if (lo4 == 0xc) { /* MOV.B @(R0,Rm),Rn */ ic->f = instr(mov_b_r0_rm_rn); } else if (lo4 == 0xd) { /* MOV.W @(R0,Rm),Rn */ ic->f = instr(mov_w_r0_rm_rn); } else if (lo4 == 0xe) { /* MOV.L @(R0,Rm),Rn */ ic->f = instr(mov_l_r0_rm_rn); } else if (iword == 0x0008) { /* CLRT */ ic->f = instr(clrt); } else if (iword == 0x0018) { /* SETT */ ic->f = instr(sett); } else if (iword == 0x0019) { /* DIV0U */ ic->f = instr(div0u); } else if (iword == 0x001b) { /* SLEEP */ ic->f = instr(sleep); } else if (iword == 0x0028) { /* CLRMAC */ ic->f = instr(clrmac); } else if (iword == 0x002b) { /* RTE */ ic->f = instr(rte); } else if (iword == 0x0038) { /* LDTLB */ ic->f = instr(ldtlb); } else if (iword == 0x0048) { /* CLRS */ ic->f = instr(clrs); } else if (iword == 0x0058) { /* SETS */ ic->f = instr(sets); } else if ((lo8 & 0x8f) == 0x82) { /* STC Rm_BANK, Rn */ ic->f = instr(copy_privileged_register); ic->arg[0] = (size_t)&cpu->cd.sh.r_bank[(lo8 >> 4) & 7]; } else if (iword == SH_INVALID_INSTR) { /* PROM emulation (GXemul specific) */ ic->f = instr(prom_emul); } else { switch (lo8) { case 0x02: /* STC SR,Rn */ ic->f = instr(copy_privileged_register); ic->arg[0] = (size_t)&cpu->cd.sh.sr; break; case 0x03: /* BSRF Rn */ if (cpu->machine->show_trace_tree) ic->f = instr(bsrf_rn_trace); else ic->f = instr(bsrf_rn); ic->arg[0] = (int32_t) (addr & ((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT) & ~1) + 4; /* arg[1] is Rn */ break; case 0x09: /* NOP */ ic->f = instr(nop); if (iword & 0x0f00) { if (!cpu->translation_readahead) fatal("Unimplemented NOP" " variant?\n"); goto bad; } break; case 0x0a: /* STS MACH,Rn */ ic->f = instr(mov_rm_rn); ic->arg[0] = (size_t)&cpu->cd.sh.mach; break; case 0x12: /* STC GBR,Rn */ ic->f = instr(mov_rm_rn); ic->arg[0] = (size_t)&cpu->cd.sh.gbr; break; case 0x1a: /* STS MACL,Rn */ ic->f = instr(mov_rm_rn); ic->arg[0] = (size_t)&cpu->cd.sh.macl; break; case 0x22: /* STC VBR,Rn */ ic->f = instr(copy_privileged_register); ic->arg[0] = (size_t)&cpu->cd.sh.vbr; break; case 0x23: /* BRAF Rn */ ic->f = instr(braf_rn); ic->arg[0] = (int32_t) (addr & ((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT) & ~1) + 4; /* arg[1] is Rn */ break; case 0x29: /* MOVT Rn */ ic->f = instr(movt_rn); break; case 0x2a: /* STS PR,Rn */ ic->f = instr(mov_rm_rn); ic->arg[0] = (size_t)&cpu->cd.sh.pr; break; case 0x32: /* STC SSR,Rn */ ic->f = instr(copy_privileged_register); ic->arg[0] = (size_t)&cpu->cd.sh.ssr; break; case 0x42: /* STC SPC,Rn */ ic->f = instr(copy_privileged_register); ic->arg[0] = (size_t)&cpu->cd.sh.spc; break; case 0x5a: /* STS FPUL,Rn */ ic->f = instr(copy_fp_register); ic->arg[0] = (size_t)&cpu->cd.sh.fpul; ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; break; case 0x6a: /* STS FPSCR,Rn */ ic->f = instr(copy_fp_register); ic->arg[0] = (size_t)&cpu->cd.sh.fpscr; ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; break; case 0x83: /* PREF @Rn */ ic->f = instr(pref_rn); break; case 0x93: /* OCBI @Rn */ /* Treat as nop for now: */ /* TODO: Implement this. */ ic->f = instr(nop); break; case 0xa3: /* OCBP @Rn */ /* Treat as nop for now: */ /* TODO: Implement this. */ ic->f = instr(nop); break; case 0xb3: /* OCBWB @Rn */ /* Treat as nop for now: */ /* TODO: Implement this. */ ic->f = instr(nop); break; case 0xc3: /* MOVCA.L R0,@Rn */ /* Treat as nop for now: */ /* TODO: Implement this. */ ic->f = instr(nop); break; case 0xfa: /* STC DBR,Rn */ ic->f = instr(copy_privileged_register); ic->arg[0] = (size_t)&cpu->cd.sh.dbr; ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; break; default:if (!cpu->translation_readahead) fatal("Unimplemented opcode 0x%x," "0x%03x\n", main_opcode, iword & 0xfff); goto bad; } } break; case 0x1: ic->f = instr(mov_l_rm_disp_rn); ic->arg[1] = r8 + (lo4 << 4); break; case 0x2: switch (lo4) { case 0x0: /* MOV.B Rm,@Rn */ ic->f = instr(mov_b_store_rm_rn); break; case 0x1: /* MOV.W Rm,@Rn */ ic->f = instr(mov_w_store_rm_rn); break; case 0x2: /* MOV.L Rm,@Rn */ ic->f = instr(mov_l_store_rm_rn); break; case 0x4: /* MOV.B Rm,@-Rn */ ic->f = instr(mov_b_rm_predec_rn); break; case 0x5: /* MOV.W Rm,@-Rn */ ic->f = instr(mov_w_rm_predec_rn); break; case 0x6: /* MOV.L Rm,@-Rn */ ic->f = instr(mov_l_rm_predec_rn); break; case 0x7: /* DIV0S Rm,Rn */ ic->f = instr(div0s_rm_rn); break; case 0x8: /* TST Rm,Rn */ ic->f = instr(tst_rm_rn); if (r8 == r4) ic->f = instr(tst_rm); break; case 0x9: /* AND Rm,Rn */ ic->f = instr(and_rm_rn); break; case 0xa: /* XOR Rm,Rn */ ic->f = instr(xor_rm_rn); break; case 0xb: /* OR Rm,Rn */ ic->f = instr(or_rm_rn); break; case 0xc: /* CMP/STR Rm,Rn */ ic->f = instr(cmp_str_rm_rn); break; case 0xd: /* XTRCT Rm,Rn */ ic->f = instr(xtrct_rm_rn); break; case 0xe: /* MULU.W Rm,Rn */ ic->f = instr(mulu_w_rm_rn); break; case 0xf: /* MULS.W Rm,Rn */ ic->f = instr(muls_w_rm_rn); break; default:if (!cpu->translation_readahead) fatal("Unimplemented opcode 0x%x,0x%x\n", main_opcode, lo4); goto bad; } break; case 0x3: switch (lo4) { case 0x0: /* CMP/EQ Rm,Rn */ ic->f = instr(cmpeq_rm_rn); break; case 0x2: /* CMP/HS Rm,Rn */ ic->f = instr(cmphs_rm_rn); break; case 0x3: /* CMP/GE Rm,Rn */ ic->f = instr(cmpge_rm_rn); break; case 0x4: /* DIV1 Rm,Rn */ ic->f = instr(div1_rm_rn); break; case 0x5: /* DMULU.L Rm,Rn */ ic->f = instr(dmulu_l_rm_rn); break; case 0x6: /* CMP/HI Rm,Rn */ ic->f = instr(cmphi_rm_rn); break; case 0x7: /* CMP/GT Rm,Rn */ ic->f = instr(cmpgt_rm_rn); break; case 0x8: /* SUB Rm,Rn */ ic->f = instr(sub_rm_rn); break; case 0xa: /* SUBC Rm,Rn */ ic->f = instr(subc_rm_rn); break; case 0xc: /* ADD Rm,Rn */ ic->f = instr(add_rm_rn); break; case 0xd: /* DMULS.L Rm,Rn */ ic->f = instr(dmuls_l_rm_rn); break; case 0xe: /* ADDC Rm,Rn */ ic->f = instr(addc_rm_rn); break; default:if (!cpu->translation_readahead) fatal("Unimplemented opcode 0x%x,0x%x\n", main_opcode, lo4); goto bad; } break; case 0x4: if (lo4 == 0xc) { ic->f = instr(shad); } else if (lo4 == 0xd) { ic->f = instr(shld); } else if ((lo8 & 0x8f) == 0x83) { /* STC.L Rm_BANK,@-Rn */ ic->f = instr(stc_l_rm_predec_rn_md); ic->arg[0] = (size_t)&cpu->cd.sh.r_bank[ (lo8 >> 4) & 7]; /* m */ } else if ((lo8 & 0x8f) == 0x87) { /* LDC.L @Rm+,Rn_BANK */ ic->f = instr(mov_l_arg1_postinc_to_arg0_md); ic->arg[0] = (size_t)&cpu->cd.sh.r_bank[(lo8 >> 4) & 7]; } else if ((lo8 & 0x8f) == 0x8e) { /* LDC Rm, Rn_BANK */ ic->f = instr(copy_privileged_register); ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; ic->arg[1] = (size_t)&cpu->cd.sh.r_bank[(lo8 >> 4) & 7]; } else { switch (lo8) { case 0x00: /* SHLL Rn */ ic->f = instr(shll_rn); break; case 0x01: /* SHLR Rn */ ic->f = instr(shlr_rn); break; case 0x02: /* STS.L MACH,@-Rn */ ic->f = instr(mov_l_rm_predec_rn); ic->arg[0] = (size_t)&cpu->cd.sh.mach; break; case 0x03: /* STC.L SR,@-Rn */ ic->f = instr(stc_l_rm_predec_rn_md); ic->arg[0] = (size_t)&cpu->cd.sh.sr; break; case 0x04: /* ROTL Rn */ ic->f = instr(rotl_rn); break; case 0x05: /* ROTR Rn */ ic->f = instr(rotr_rn); break; case 0x06: /* LDS.L @Rm+,MACH */ ic->f = instr(mov_l_arg1_postinc_to_arg0); ic->arg[0] = (size_t)&cpu->cd.sh.mach; break; case 0x07: /* LDC.L @Rm+,SR */ ic->f = instr(mov_l_arg1_postinc_to_arg0_md); ic->arg[0] = (size_t)&cpu->cd.sh.sr; break; case 0x08: /* SHLL2 Rn */ ic->f = instr(shll2_rn); break; case 0x09: /* SHLR2 Rn */ ic->f = instr(shlr2_rn); break; case 0x0a: /* LDS Rm,MACH */ ic->f = instr(mov_rm_rn); ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.mach; break; case 0x0b: /* JSR @Rn */ if (cpu->machine->show_trace_tree) ic->f = instr(jsr_rn_trace); else ic->f = instr(jsr_rn); ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* n */ ic->arg[1] = (addr & 0xffe) + 4; break; case 0x0e: /* LDC Rm,SR */ ic->f = instr(ldc_rm_sr); break; case 0x10: /* DT Rn */ ic->f = instr(dt_rn); break; case 0x11: /* CMP/PZ Rn */ ic->f = instr(cmppz_rn); break; case 0x12: /* STS.L MACL,@-Rn */ ic->f = instr(mov_l_rm_predec_rn); ic->arg[0] = (size_t)&cpu->cd.sh.macl; break; case 0x13: /* STC.L GBR,@-Rn */ ic->f = instr(mov_l_rm_predec_rn); ic->arg[0] = (size_t)&cpu->cd.sh.gbr; break; case 0x15: /* CMP/PL Rn */ ic->f = instr(cmppl_rn); break; case 0x16: /* LDS.L @Rm+,MACL */ ic->f = instr(mov_l_arg1_postinc_to_arg0); ic->arg[0] = (size_t)&cpu->cd.sh.macl; break; case 0x17: /* LDC.L @Rm+,GBR */ ic->f = instr(mov_l_arg1_postinc_to_arg0); ic->arg[0] = (size_t)&cpu->cd.sh.gbr; break; case 0x18: /* SHLL8 Rn */ ic->f = instr(shll8_rn); break; case 0x19: /* SHLR8 Rn */ ic->f = instr(shlr8_rn); break; case 0x1a: /* LDS Rm,MACL */ ic->f = instr(mov_rm_rn); ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.macl; break; case 0x1b: /* TAS.B @Rn */ ic->f = instr(tas_b_rn); break; case 0x1e: /* LDC Rm,GBR */ ic->f = instr(mov_rm_rn); ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.gbr; break; case 0x20: /* SHAL Rn */ ic->f = instr(shll_rn); /* NOTE: shll */ break; case 0x21: /* SHAR Rn */ ic->f = instr(shar_rn); break; case 0x22: /* STS.L PR,@-Rn */ ic->f = instr(mov_l_rm_predec_rn); ic->arg[0] = (size_t)&cpu->cd.sh.pr; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ break; case 0x23: /* STC.L VBR,@-Rn */ ic->f = instr(stc_l_rm_predec_rn_md); ic->arg[0] = (size_t)&cpu->cd.sh.vbr; break; case 0x24: /* ROTCL Rn */ ic->f = instr(rotcl_rn); break; case 0x25: /* ROTCR Rn */ ic->f = instr(rotcr_rn); break; case 0x26: /* LDS.L @Rm+,PR */ ic->f = instr(mov_l_arg1_postinc_to_arg0); ic->arg[0] = (size_t)&cpu->cd.sh.pr; break; case 0x27: /* LDC.L @Rm+,VBR */ ic->f = instr(mov_l_arg1_postinc_to_arg0_md); ic->arg[0] = (size_t)&cpu->cd.sh.vbr; break; case 0x28: /* SHLL16 Rn */ ic->f = instr(shll16_rn); break; case 0x29: /* SHLR16 Rn */ ic->f = instr(shlr16_rn); break; case 0x2a: /* LDS Rm,PR */ ic->f = instr(mov_rm_rn); ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.pr; break; case 0x2b: /* JMP @Rn */ if (cpu->machine->show_trace_tree) ic->f = instr(jmp_rn_trace); else ic->f = instr(jmp_rn); ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* n */ ic->arg[1] = (addr & 0xffe) + 4; break; case 0x2e: /* LDC Rm,VBR */ ic->f = instr(copy_privileged_register); ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.vbr; break; case 0x33: /* STC.L SSR,@-Rn */ ic->f = instr(stc_l_rm_predec_rn_md); ic->arg[0] = (size_t)&cpu->cd.sh.ssr; break; case 0x37: /* LDC.L @Rm+,SSR */ ic->f = instr(mov_l_arg1_postinc_to_arg0_md); ic->arg[0] = (size_t)&cpu->cd.sh.ssr; break; case 0x3e: /* LDC rm,SSR */ ic->f = instr(copy_privileged_register); ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.ssr; break; case 0x43: /* STC.L SPC,@-Rn */ ic->f = instr(stc_l_rm_predec_rn_md); ic->arg[0] = (size_t)&cpu->cd.sh.spc; break; case 0x47: /* LDC.L @Rm+,SPC */ ic->f = instr(mov_l_arg1_postinc_to_arg0_md); ic->arg[0] = (size_t)&cpu->cd.sh.spc; break; case 0x4e: /* LDC rm,SPC */ ic->f = instr(copy_privileged_register); ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.spc; break; case 0x52: /* STS.L FPUL,@-Rn */ ic->f = instr(mov_l_rm_predec_rn); ic->arg[0] = (size_t)&cpu->cd.sh.fpul; ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ break; case 0x56: /* LDS.L @Rm+,FPUL */ ic->f = instr(mov_l_arg1_postinc_to_arg0_fp); ic->arg[0] = (size_t)&cpu->cd.sh.fpul; break; case 0x5a: /* LDS Rm,FPUL */ ic->f = instr(copy_fp_register); ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.fpul; break; case 0x62: /* STS.L FPSCR,@-Rn */ ic->f = instr(mov_l_rm_predec_rn); ic->arg[0] = (size_t)&cpu->cd.sh.fpscr; ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ break; case 0x66: /* LDS.L @Rm+,FPSCR */ /* Note: Loading into FPSCR is a specia case (need to call sh_update_fpsrc()). */ ic->f = instr(mov_l_arg1_postinc_to_arg0_fp); ic->arg[0] = (size_t)&cpu->cd.sh.fpscr; break; case 0x6a: /* LDS Rm,FPSCR */ ic->f = instr(lds_rm_fpscr); /* arg 1 = R8 = Rm */ break; case 0xfa: /* LDC Rm,DBR */ ic->f = instr(copy_privileged_register); ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; ic->arg[1] = (size_t)&cpu->cd.sh.dbr; break; default:if (!cpu->translation_readahead) fatal("Unimplemented opcode 0x%x," "0x%02x\n", main_opcode, lo8); goto bad; } } break; case 0x5: ic->f = instr(mov_l_disp_rm_rn); ic->arg[0] = r4 + (lo4 << 4); break; case 0x6: switch (lo4) { case 0x0: /* MOV.B @Rm,Rn */ ic->f = instr(load_b_rm_rn); break; case 0x1: /* MOV.W @Rm,Rn */ ic->f = instr(load_w_rm_rn); break; case 0x2: /* MOV.L @Rm,Rn */ ic->f = instr(load_l_rm_rn); break; case 0x3: /* MOV Rm,Rn */ ic->f = instr(mov_rm_rn); break; case 0x4: /* MOV.B @Rm+,Rn */ ic->f = instr(mov_b_arg1_postinc_to_arg0); /* Note: Order */ ic->arg[1] = (size_t)&cpu->cd.sh.r[r4]; /* m */ ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* n */ break; case 0x5: /* MOV.W @Rm+,Rn */ ic->f = instr(mov_w_arg1_postinc_to_arg0); /* Note: Order */ ic->arg[1] = (size_t)&cpu->cd.sh.r[r4]; /* m */ ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* n */ break; case 0x6: /* MOV.L @Rm+,Rn */ ic->f = instr(mov_l_arg1_postinc_to_arg0); /* Note: Order */ ic->arg[1] = (size_t)&cpu->cd.sh.r[r4]; /* m */ ic->arg[0] = (size_t)&cpu->cd.sh.r[r8]; /* n */ break; case 0x7: /* NOT Rm,Rn */ ic->f = instr(not_rm_rn); break; case 0x8: /* SWAP.B Rm,Rn */ ic->f = instr(swap_b_rm_rn); break; case 0x9: /* SWAP.W Rm,Rn */ ic->f = instr(swap_w_rm_rn); break; case 0xa: /* NEGC Rm,Rn */ ic->f = instr(negc_rm_rn); break; case 0xb: /* NEG Rm,Rn */ ic->f = instr(neg_rm_rn); break; case 0xc: /* EXTU.B Rm,Rn */ ic->f = instr(extu_b_rm_rn); if (r8 == r4) ic->f = instr(extu_b_rm); break; case 0xd: /* EXTU.W Rm,Rn */ ic->f = instr(extu_w_rm_rn); if (r8 == r4) ic->f = instr(extu_w_rm); break; case 0xe: /* EXTS.B Rm,Rn */ ic->f = instr(exts_b_rm_rn); break; case 0xf: /* EXTS.W Rm,Rn */ ic->f = instr(exts_w_rm_rn); break; default:if (!cpu->translation_readahead) fatal("Unimplemented opcode 0x%x,0x%x\n", main_opcode, lo4); goto bad; } break; case 0x7: /* ADD #imm,Rn */ ic->f = instr(add_imm_rn); ic->arg[0] = (int8_t)lo8; ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ if (lo8 == 1) ic->f = instr(inc_rn); if (lo8 == 4) ic->f = instr(add_4_rn); if (lo8 == 0xfc) ic->f = instr(sub_4_rn); if (lo8 == 0xff) ic->f = instr(dec_rn); break; case 0x8: /* Displacement from beginning of page = default arg 0. */ ic->arg[0] = (int8_t)lo8 * 2 + (addr & ((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT) & ~1) + 4; samepage_function = NULL; switch (r8) { case 0x0: /* MOV.B R0,@(disp,Rn) */ ic->f = instr(mov_b_r0_disp_rn); ic->arg[0] = (size_t)&cpu->cd.sh.r[r4]; /* n */ ic->arg[1] = lo4; break; case 0x1: /* MOV.W R0,@(disp,Rn) */ ic->f = instr(mov_w_r0_disp_rn); ic->arg[0] = (size_t)&cpu->cd.sh.r[r4]; /* n */ ic->arg[1] = lo4 * 2; break; case 0x4: /* MOV.B @(disp,Rn),R0 */ ic->f = instr(mov_b_disp_rn_r0); ic->arg[0] = (size_t)&cpu->cd.sh.r[r4]; /* n */ ic->arg[1] = lo4; break; case 0x5: /* MOV.W @(disp,Rn),R0 */ ic->f = instr(mov_w_disp_rn_r0); ic->arg[0] = (size_t)&cpu->cd.sh.r[r4]; /* n */ ic->arg[1] = lo4 * 2; break; case 0x8: /* CMP/EQ #imm,R0 */ ic->f = instr(cmpeq_imm_r0); ic->arg[0] = (int8_t)lo8; break; case 0x9: /* BT (disp,PC) */ ic->f = instr(bt); samepage_function = instr(bt_samepage); break; case 0xb: /* BF (disp,PC) */ ic->f = instr(bf); samepage_function = instr(bf_samepage); break; case 0xd: /* BT/S (disp,PC) */ ic->f = instr(bt_s); samepage_function = instr(bt_s_samepage); break; case 0xf: /* BF/S (disp,PC) */ ic->f = instr(bf_s); samepage_function = instr(bf_s_samepage); break; default:if (!cpu->translation_readahead) fatal("Unimplemented opcode 0x%x,0x%x\n", main_opcode, r8); goto bad; } /* samepage branches: */ if (samepage_function != NULL && ic->arg[0] < 0x1000 && (addr & 0xfff) < 0xffe) { ic->arg[1] = (size_t) (cpu->cd.sh.cur_ic_page + (ic->arg[0] >> SH_INSTR_ALIGNMENT_SHIFT)); ic->f = samepage_function; } if (ic->f == instr(bt_samepage)) cpu->cd.sh.combination_check = COMBINE(bt_samepage); break; case 0x9: /* MOV.W @(disp,PC),Rn */ ic->f = instr(mov_w_disp_pc_rn); ic->arg[0] = lo8 * 2 + (addr & ((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT) & ~1) + 4; /* If the word is reachable from the same page as the current address, then optimize it as a mov_imm_rn: */ if (ic->arg[0] < 0x1000 && page != NULL) { uint16_t *p = (uint16_t *) page; uint16_t data = p[ic->arg[0] >> 1]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE16_TO_HOST(data); else data = BE16_TO_HOST(data); ic->f = instr(mov_imm_rn); ic->arg[0] = (int16_t) data; } break; case 0xa: /* BRA disp */ case 0xb: /* BSR disp */ samepage_function = NULL; switch (main_opcode) { case 0xa: ic->f = instr(bra); samepage_function = instr(bra_samepage); break; case 0xb: if (cpu->machine->show_trace_tree) ic->f = instr(bsr_trace); else { ic->f = instr(bsr); samepage_function = instr(bsr_samepage); } break; } ic->arg[0] = (int32_t) ( (addr & ((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT) & ~1) + 4 + (((int32_t)(int16_t)((iword & 0xfff) << 4)) >> 3) ); /* samepage branches: */ if (samepage_function != NULL && ic->arg[0] < 0x1000 && (addr & 0xfff) < 0xffe) { ic->arg[0] = (size_t) (cpu->cd.sh.cur_ic_page + (ic->arg[0] >> SH_INSTR_ALIGNMENT_SHIFT)); ic->f = samepage_function; } break; case 0xc: switch (r8) { case 0x0: ic->f = instr(mov_b_r0_disp_gbr); ic->arg[1] = lo8; break; case 0x1: ic->f = instr(mov_w_r0_disp_gbr); ic->arg[1] = lo8 << 1; break; case 0x2: ic->f = instr(mov_l_r0_disp_gbr); ic->arg[1] = lo8 << 2; break; case 0x3: ic->f = instr(trapa); ic->arg[0] = lo8 << 2; break; case 0x4: ic->f = instr(mov_b_disp_gbr_r0); ic->arg[1] = lo8; break; case 0x5: ic->f = instr(mov_w_disp_gbr_r0); ic->arg[1] = lo8 << 1; break; case 0x6: ic->f = instr(mov_l_disp_gbr_r0); ic->arg[1] = lo8 << 2; break; case 0x7: /* MOVA @(disp,pc),R0 */ ic->f = instr(mova_r0); ic->arg[0] = lo8 * 4 + (addr & ((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT) & ~3) + 4; break; case 0x8: /* TST #imm,R0 */ ic->f = instr(tst_imm_r0); ic->arg[0] = lo8; break; case 0x9: /* AND #imm,R0 */ ic->f = instr(and_imm_r0); ic->arg[0] = lo8; break; case 0xa: /* XOR #imm,R0 */ ic->f = instr(xor_imm_r0); ic->arg[0] = lo8; break; case 0xb: /* OR #imm,R0 */ ic->f = instr(or_imm_r0); ic->arg[0] = lo8; break; case 0xd: /* AND.B #imm,@(R0,GBR) */ ic->f = instr(and_b_imm_r0_gbr); ic->arg[0] = lo8; break; case 0xe: /* XOR.B #imm,@(R0,GBR) */ ic->f = instr(xor_b_imm_r0_gbr); ic->arg[0] = lo8; break; case 0xf: /* OR.B #imm,@(R0,GBR) */ ic->f = instr(or_b_imm_r0_gbr); ic->arg[0] = lo8; break; default:if (!cpu->translation_readahead) fatal("Unimplemented opcode 0x%x,0x%x\n", main_opcode, r8); goto bad; } break; case 0xd: /* MOV.L @(disp,PC),Rn */ ic->f = instr(mov_l_disp_pc_rn); ic->arg[0] = lo8 * 4 + (addr & ((SH_IC_ENTRIES_PER_PAGE-1) << SH_INSTR_ALIGNMENT_SHIFT) & ~3) + 4; /* If the word is reachable from the same page as the current address, then optimize it as a mov_imm_rn: */ if (ic->arg[0] < 0x1000 && page != NULL) { uint32_t *p = (uint32_t *) page; uint32_t data = p[ic->arg[0] >> 2]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) data = LE32_TO_HOST(data); else data = BE32_TO_HOST(data); ic->f = instr(mov_imm_rn); ic->arg[0] = data; } break; case 0xe: /* MOV #imm,Rn */ ic->f = instr(mov_imm_rn); ic->arg[0] = (int8_t)lo8; ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; /* n */ if (lo8 == 0) ic->f = instr(mov_0_rn); break; case 0xf: if (lo4 == 0x0) { /* FADD FRm,FRn */ ic->f = instr(fadd_frm_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r4]; ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo4 == 0x1) { /* FSUB FRm,FRn */ ic->f = instr(fsub_frm_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r4]; ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo4 == 0x2) { /* FMUL FRm,FRn */ ic->f = instr(fmul_frm_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r4]; ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo4 == 0x3) { /* FDIV FRm,FRn */ ic->f = instr(fdiv_frm_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r4]; ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo4 == 0x4) { /* FCMP/EQ FRm,FRn */ ic->f = instr(fcmp_eq_frm_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r4]; ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo4 == 0x5) { /* FCMP/GT FRm,FRn */ ic->f = instr(fcmp_gt_frm_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r4]; ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo4 == 0x6) { /* FMOV @(R0,Rm),FRn */ ic->f = instr(fmov_r0_rm_frn); ic->arg[0] = (size_t)&cpu->cd.sh.r[r4]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo4 == 0x7) { /* FMOV FRm,@(R0,Rn) */ ic->f = instr(fmov_frm_r0_rn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r4]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; } else if (lo4 == 0x8) { /* FMOV @Rm,FRn */ ic->f = instr(fmov_rm_frn); ic->arg[0] = (size_t)&cpu->cd.sh.r[r4]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo4 == 0x9) { /* FMOV @Rm+,FRn */ ic->f = instr(fmov_rm_postinc_frn); ic->arg[0] = (size_t)&cpu->cd.sh.r[r4]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo4 == 0xa) { /* FMOV FRm,@Rn */ ic->f = instr(fmov_frm_rn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r4]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; } else if (lo4 == 0xb) { /* FMOV FRm,@-Rn */ ic->f = instr(fmov_frm_predec_rn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r4]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.r[r8]; } else if (lo4 == 0xc) { /* FMOV FRm,FRn */ ic->f = instr(fmov_frm_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r4]; ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo8 == 0x0d) { /* FSTS FPUL,FRn */ ic->f = instr(copy_fp_register); ic->arg[0] = (size_t)&cpu->cd.sh.fpul; ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo8 == 0x1d) { /* FLDS FRn,FPUL */ ic->f = instr(copy_fp_register); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; ic->arg[1] = (size_t)&cpu->cd.sh.fpul; } else if (lo8 == 0x2d) { /* FLOAT FPUL,FRn */ ic->f = instr(float_fpul_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo8 == 0x3d) { /* FTRC FRm,FPUL */ ic->f = instr(ftrc_frm_fpul); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo8 == 0x4d) { /* FNEG FRn */ ic->f = instr(fneg_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo8 == 0x5d) { /* FABS FRn */ ic->f = instr(fabs_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo8 == 0x6d) { /* FSQRT FRn */ ic->f = instr(fsqrt_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo8 == 0x7d) { /* FSRRA FRn */ ic->f = instr(fsrra_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo8 == 0x8d) { /* FLDI0 FRn */ ic->f = instr(fldi_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; ic->arg[1] = 0x00000000; } else if (lo8 == 0x9d) { /* FLDI1 FRn */ ic->f = instr(fldi_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; ic->arg[1] = 0x3f800000; } else if ((iword & 0x01ff) == 0x00ad) { /* FCNVSD FPUL,DRn */ ic->f = instr(fcnvsd_fpul_drn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; } else if ((iword & 0x01ff) == 0x00bd) { /* FCNVDS DRm,FPUL */ ic->f = instr(fcnvds_drm_fpul); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; } else if (lo8 == 0xed) { /* FIPR FVm,FVn */ ic->f = instr(fipr_fvm_fvn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[(r8<<2) & 0xc]; /* m */ ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8 & 0xc]; /* n */ } else if ((iword & 0x01ff) == 0x00fd) { /* FSCA FPUL,DRn */ ic->f = instr(fsca_fpul_drn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8]; } else if (iword == 0xf3fd) { /* FSCHG */ ic->f = instr(fschg); } else if (iword == 0xfbfd) { /* FRCHG */ ic->f = instr(frchg); } else if ((iword & 0xf3ff) == 0xf1fd) { /* FTRV XMTRX, FVn */ ic->f = instr(ftrv_xmtrx_fvn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r8 & 0xc]; } else if (lo4 == 0xe) { /* FMAC FR0,FRm,FRn */ ic->f = instr(fmac_fr0_frm_frn); ic->arg[0] = (size_t)&cpu->cd.sh.fr[r4]; ic->arg[1] = (size_t)&cpu->cd.sh.fr[r8]; } else { if (!cpu->translation_readahead) fatal("Unimplemented opcode 0x%x,0x%02x\n", main_opcode, lo8); goto bad; } break; default:if (!cpu->translation_readahead) fatal("Unimplemented main opcode 0x%x\n", main_opcode); goto bad; } #define DYNTRANS_TO_BE_TRANSLATED_TAIL #include "cpu_dyntrans.cc" #undef DYNTRANS_TO_BE_TRANSLATED_TAIL } gxemul-0.6.1/src/cpus/generate_mips_loadstore.c000644 001750 001750 00000012327 13402411502 022035 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include void print_function_name(int store, int size, int signedness, int endianness) { if (store) printf("s"); else { printf("l"); if (!signedness) printf("u"); } printf("%i", 1 << size); if (endianness >= 0) { /* Special case so that Byte loads/stores are only included ones (for little endian): */ if (size == 0 && endianness) printf("_le"); else printf(endianness? "_be" : "_le"); } } void loadstore(int mode32, int store, int size, int signedness, int endianness) { if (store && signedness) return; if (size == 0 && endianness) return; printf("#if%sdef MODE32\n", mode32? "" : "n"); if (store) printf("#define LS_STORE\n"); else printf("#define LS_LOAD\n"); printf("#define LS_N mips%s_instr_", mode32? "32" : ""); print_function_name(store, size, signedness, endianness); printf("\n"); printf("#define LS_GENERIC_N mips%s_generic_", mode32? "32" : ""); print_function_name(store, size, signedness, -1); printf("\n"); printf("#define LS_%i\n", 1 << size); printf("#define LS_SIZE %i\n", 1 << size); if (signedness && !store) printf("#define LS_SIGNED\n"); if (endianness) printf("#define LS_BE\n"); else printf("#define LS_LE\n"); if (endianness == 0) printf("#define LS_INCLUDE_GENERIC\n"); printf("#include \"cpu_mips_instr_loadstore.cc\"\n"); if (endianness == 0) printf("#undef LS_INCLUDE_GENERIC\n"); if (endianness) printf("#undef LS_BE\n"); else printf("#undef LS_LE\n"); if (signedness && !store) printf("#undef LS_SIGNED\n"); printf("#undef LS_SIZE\n"); printf("#undef LS_%i\n", 1 << size); printf("#undef LS_GENERIC_N\n"); printf("#undef LS_N\n"); if (store) printf("#undef LS_STORE\n"); else printf("#undef LS_LOAD\n"); printf("#endif\n"); } int main(int argc, char *argv[]) { int store, mode32, size, signedness, endianness; printf("\n/* AUTOMATICALLY GENERATED! Do not edit. */\n\n"); for (mode32=0; mode32<=1; mode32++) for (endianness=0; endianness<=1; endianness++) for (store=0; store<=1; store++) for (size=0; size<=3; size++) for (signedness=0; signedness<=1; signedness++) loadstore(mode32, store, size, signedness, endianness); /* Array of pointers to fast load/store functions: */ for (mode32=0; mode32<=1; mode32++) { printf("#if%sdef MODE32\n", mode32? "" : "n"); printf("\n\nvoid (*mips%s_loadstore[32])(struct cpu *, struct " "mips_instr_call *) = {\n", mode32? "32" : ""); for (endianness=0; endianness<=1; endianness++) for (store=0; store<=1; store++) for (size=0; size<=3; size++) for (signedness=0; signedness<=1; signedness++) { if (store || size || signedness || endianness) printf(",\n"); if (store && signedness) { printf("\tmips%s_instr_invalid", mode32? "32" : ""); continue; } printf("\tmips%s_instr_", mode32? "32" : ""); print_function_name(store, size, signedness, endianness); } printf(" };\n"); printf("#endif\n"); } /* Array of pointers to the generic functions: */ for (mode32=0; mode32<=1; mode32++) { printf("#if%sdef MODE32\n", mode32? "" : "n"); printf("\n\nvoid (*mips%s_loadstore_generic[16])(" "struct cpu *, struct mips_instr_call *) = {\n", mode32? "32" : ""); for (store=0; store<=1; store++) for (size=0; size<=3; size++) for (signedness=0; signedness<=1; signedness++) { if (store || size || signedness) printf(",\n"); if (store && signedness) { printf("\tmips%s_instr_invalid", mode32? "32" : ""); continue; } printf("\tmips%s_generic_", mode32? "32" : ""); print_function_name(store, size, signedness, -1); } printf(" };\n"); printf("#endif\n"); } return 0; } gxemul-0.6.1/src/cpus/memory_mips.cc000644 001750 001750 00000011007 13402411502 017634 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * MIPS-specific memory routines. Included from cpu_mips.c. */ #include #include /* * memory_cache_R3000(): * * R2000/R3000 specific cache handling. * * Return value is 1 if a jump to do_return_ok is supposed to happen directly * after this routine is finished, 0 otherwise. */ int memory_cache_R3000(struct cpu *cpu, int cache, uint64_t paddr, int writeflag, size_t len, unsigned char *data) { unsigned int i; int cache_isolated = 0, addr, hit, which_cache = cache; if (len > 4 || cache == CACHE_NONE) return 0; /* * R2000/R3000 without correct cache emulation: * * TODO: This is just enough to trick NetBSD/pmax and Ultrix into * being able to detect the cache sizes and think that the caches * are actually working, but they are not. */ if (cache != CACHE_DATA) return 0; /* Is this a cache hit or miss? */ hit = (cpu->cd.mips.cache_last_paddr[which_cache] & ~cpu->cd.mips.cache_mask[which_cache]) == (paddr & ~(cpu->cd.mips.cache_mask[which_cache])); /* * The cache miss bit is only set on cache reads, and only to the * data cache. (?) * * (TODO: is this correct? I don't remember where I got this from.) */ if (cache == CACHE_DATA && writeflag==MEM_READ) { cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~MIPS1_CACHE_MISS; if (!hit) cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= MIPS1_CACHE_MISS; } /* * Is the Data cache isolated? Then don't access main memory: */ if (cache == CACHE_DATA && cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_ISOL_CACHES) cache_isolated = 1; addr = paddr & cpu->cd.mips.cache_mask[which_cache]; /* Data cache isolated? Then don't access main memory: */ if (cache_isolated) { /* debug("ISOLATED write=%i cache=%i vaddr=%016"PRIx64" " "paddr=%016"PRIx64" => addr in cache = 0x%lx\n", writeflag, cache, (uint64_t) vaddr, (uint64_t) paddr, addr); */ if (writeflag==MEM_READ) { for (i=0; icd.mips.cache[cache][(addr+i) & cpu->cd.mips.cache_mask[cache]]; } else { for (i=0; icd.mips.cache[cache][(addr+i) & cpu->cd.mips.cache_mask[cache]] = data[i]; } return 1; } else { /* Reload caches if necessary: */ /* No! Not when not emulating caches fully. (TODO?) */ cpu->cd.mips.cache_last_paddr[cache] = paddr; } return 0; } #define TRANSLATE_ADDRESS translate_v2p_mmu3k #define V2P_MMU3K #include "memory_mips_v2p.cc" #undef TRANSLATE_ADDRESS #undef V2P_MMU3K #define TRANSLATE_ADDRESS translate_v2p_mmu8k #define V2P_MMU8K #include "memory_mips_v2p.cc" #undef TRANSLATE_ADDRESS #undef V2P_MMU8K #define TRANSLATE_ADDRESS translate_v2p_mmu10k #define V2P_MMU10K #include "memory_mips_v2p.cc" #undef TRANSLATE_ADDRESS #undef V2P_MMU10K /* Almost generic :-) */ #define TRANSLATE_ADDRESS translate_v2p_mmu4100 #define V2P_MMU4100 #include "memory_mips_v2p.cc" #undef TRANSLATE_ADDRESS #undef V2P_MMU4100 #define TRANSLATE_ADDRESS translate_v2p_generic #include "memory_mips_v2p.cc" gxemul-0.6.1/src/cpus/generate_ppc_loadstore.c000644 001750 001750 00000020551 13402411502 021645 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include char *sizechar[4] = { "b", "h", "w", "d" }; char *modes[2] = { "", "32" }; void do_it(int mode) { int n, load, size, zero, ignoreofs, update; n = 0; for (update=0; update<=1; update++) for (ignoreofs=0; ignoreofs<=1; ignoreofs++) for (load=0; load<=1; load++) for (zero=0; zero<=1; zero++) for (size=0; size<4; size++) { if (!zero && !load) continue; if (load && !zero && size == 3) continue; switch (size) { case 0: printf("#define LS_B\n"); break; case 1: printf("#define LS_H\n"); break; case 2: printf("#define LS_W\n"); break; case 3: printf("#define LS_D\n"); break; } printf("#define LS_SIZE %i\n", 1 << size); if (zero) printf("#define LS_ZERO\n"); if (load) printf("#define LS_LOAD\n"); if (ignoreofs) printf("#define LS_IGNOREOFS\n"); if (update) printf("#define LS_UPDATE\n"); printf("#define LS_GENERIC_N ppc%s_generic_", modes[mode]); if (load) printf("l"); else printf("st"); printf("%s", sizechar[size]); if (load) { if (zero) printf("z"); else printf("a"); } if (update) printf("u"); printf("\n"); printf("#define LS_N ppc%s_instr_", modes[mode]); if (load) printf("l"); else printf("st"); printf("%s", sizechar[size]); if (load && size < 3) { if (zero) printf("z"); else printf("a"); } if (update) printf("u"); if (ignoreofs) printf("_0"); printf("\n"); printf("#include \"cpu_ppc_instr_loadstore.cc\"\n"); printf("#undef LS_N\n"); printf("#undef LS_GENERIC_N\n"); switch (size) { case 0: printf("#undef LS_B\n"); break; case 1: printf("#undef LS_H\n"); break; case 2: printf("#undef LS_W\n"); break; case 3: printf("#undef LS_D\n"); break; } printf("#undef LS_SIZE\n"); if (load) printf("#undef LS_LOAD\n"); if (update) printf("#undef LS_UPDATE\n"); if (zero) printf("#undef LS_ZERO\n"); if (ignoreofs) printf("#undef LS_IGNOREOFS\n"); } /* Indexed loads/stores: */ printf("#define LS_INDEXED\n"); for (update=0; update<=1; update++) for (load=0; load<=1; load++) for (zero=0; zero<=1; zero++) for (size=0; size<4; size++) { if (!zero && !load) continue; if (load && !zero && size == 3) continue; switch (size) { case 0: printf("#define LS_B\n"); break; case 1: printf("#define LS_H\n"); break; case 2: printf("#define LS_W\n"); break; case 3: printf("#define LS_D\n"); break; } printf("#define LS_SIZE %i\n", 1 << size); if (zero) printf("#define LS_ZERO\n"); if (load) printf("#define LS_LOAD\n"); if (update) printf("#define LS_UPDATE\n"); printf("#define LS_GENERIC_N ppc%s_generic_", modes[mode]); if (load) printf("l"); else printf("st"); printf("%s", sizechar[size]); if (load) { if (zero) printf("z"); else printf("a"); } if (update) printf("u"); printf("x"); printf("\n"); printf("#define LS_N ppc%s_instr_", modes[mode]); if (load) printf("l"); else printf("st"); printf("%s", sizechar[size]); if (load && size < 3) { if (zero) printf("z"); else printf("a"); } if (update) printf("u"); printf("x"); printf("\n"); printf("#include \"cpu_ppc_instr_loadstore.cc\"\n"); printf("#undef LS_N\n"); printf("#undef LS_GENERIC_N\n"); switch (size) { case 0: printf("#undef LS_B\n"); break; case 1: printf("#undef LS_H\n"); break; case 2: printf("#undef LS_W\n"); break; case 3: printf("#undef LS_D\n"); break; } printf("#undef LS_SIZE\n"); if (load) printf("#undef LS_LOAD\n"); if (update) printf("#undef LS_UPDATE\n"); if (zero) printf("#undef LS_ZERO\n"); } printf("#undef LS_INDEXED\n"); /* Lookup tables for loads/stores: */ printf("\n\nvoid (*ppc%s_loadstore[64])(struct cpu *, struct " "ppc_instr_call *) = {\n", modes[mode]); n = 0; for (update=0; update<=1; update++) for (ignoreofs=0; ignoreofs<=1; ignoreofs++) for (load=0; load<=1; load++) for (zero=0; zero<=1; zero++) for (size=0; size<4; size++) { printf("\tppc%s_instr_", modes[mode]); if (load && !zero && size == 3) { printf("invalid"); goto cont; } if (load) printf("l"); else printf("st"); printf("%s", sizechar[size]); if (load && size < 3) { if (zero) printf("z"); else printf("a"); } if (update) printf("u"); if (ignoreofs) printf("_0"); cont: if (++n < 64) printf(","); printf("\n"); } printf("};\n\n"); printf("\n\nvoid (*ppc%s_loadstore_indexed[32])(struct cpu *, struct " "ppc_instr_call *) = {\n", modes[mode]); n = 0; for (update=0; update<=1; update++) for (load=0; load<=1; load++) for (zero=0; zero<=1; zero++) for (size=0; size<4; size++) { printf("\tppc%s_instr_", modes[mode]); if (load && !zero && size == 3) { printf("invalid"); goto cont_x; } if (load) printf("l"); else printf("st"); printf("%s", sizechar[size]); if (load && size < 3) { if (zero) printf("z"); else printf("a"); } if (update) printf("u"); printf("x"); cont_x: if (++n < 32) printf(","); printf("\n"); } printf("};\n\n"); /* Non-standard loads/stores: */ printf("#define LS_BYTEREVERSE\n" "#define LS_INDEXED\n" "#define LS_SIZE 2\n" "#define LS_H\n" "#define LS_GENERIC_N ppc%s_generic_lhbrx\n" "#define LS_N ppc%s_instr_lhbrx\n" "#define LS_LOAD\n" "#include \"cpu_ppc_instr_loadstore.cc\"\n" "#undef LS_LOAD\n" "#undef LS_N\n" "#undef LS_GENERIC_N\n" "#define LS_GENERIC_N ppc%s_generic_sthbrx\n" "#define LS_N ppc%s_instr_sthbrx\n" "#include \"cpu_ppc_instr_loadstore.cc\"\n" "#undef LS_N\n" "#undef LS_GENERIC_N\n" "#undef LS_H\n" "#undef LS_SIZE\n" "#define LS_SIZE 4\n" "#define LS_W\n" "#define LS_GENERIC_N ppc%s_generic_lwbrx\n" "#define LS_N ppc%s_instr_lwbrx\n" "#define LS_LOAD\n" "#include \"cpu_ppc_instr_loadstore.cc\"\n" "#undef LS_LOAD\n" "#undef LS_N\n" "#undef LS_GENERIC_N\n" "#define LS_GENERIC_N ppc%s_generic_stwbrx\n" "#define LS_N ppc%s_instr_stwbrx\n" "#include \"cpu_ppc_instr_loadstore.cc\"\n" "#undef LS_N\n" "#undef LS_GENERIC_N\n" "#undef LS_W\n" "#undef LS_SIZE\n" "#undef LS_INDEXED\n" "#undef LS_BYTEREVERSE\n", modes[mode], modes[mode], modes[mode], modes[mode], modes[mode], modes[mode], modes[mode], modes[mode]); } int main(int argc, char *argv[]) { int mode; printf("\n/* AUTOMATICALLY GENERATED! Do not edit. */\n\n"); for (mode = 0; mode <= 1; mode ++) { if (mode == 0) printf("#ifndef MODE32\n"); else printf("#ifdef MODE32\n"); do_it(mode); printf("#endif\n"); } return 0; } gxemul-0.6.1/src/cpus/cpu_m88k_instr.cc000644 001750 001750 00000216257 13402411502 020167 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * M88K instructions. * * Individual functions should keep track of cpu->n_translated_instrs. * (If no instruction was executed, then it should be decreased. If, say, 4 * instructions were combined into one function and executed, then it should * be increased by 3.) */ #define SYNCH_PC { \ int low_pc = ((size_t)ic - (size_t)cpu->cd.m88k.cur_ic_page) \ / sizeof(struct m88k_instr_call); \ cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) \ << M88K_INSTR_ALIGNMENT_SHIFT); \ cpu->pc += (low_pc << M88K_INSTR_ALIGNMENT_SHIFT); \ } #define ABORT_EXECUTION { SYNCH_PC; \ fatal("Execution aborted at: pc = 0x%08x\n", (int)cpu->pc); \ cpu->cd.m88k.next_ic = ¬hing_call; \ cpu->running = 0; \ debugger_n_steps_left_before_interaction = 0; } /* * nop: Do nothing. */ X(nop) { } /* * br_samepage: Branch (to within the same translated page) * bsr_samepage: Branch to subroutine (to within the same translated page) * * arg[0] = pointer to new instr_call * arg[2] = offset to return address, from start of page */ X(br_samepage) { cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[0]; } X(bsr_samepage) { cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT)) + ic->arg[2]; cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[0]; } /* * br: Branch (to a different translated page) * br.n: Branch (to a different translated page) with delay slot * bsr: Branch to subroutine (to a different translated page) * bsr.n: Branch to subroutine (to a different page) with delay slot * * arg[1] = relative offset from start of page * arg[2] = offset to return address, from start of page */ X(br) { cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[1]); quick_pc_to_pointers(cpu); } X(br_n) { cpu->cd.m88k.delay_target = (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[1]; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; cpu->pc = cpu->cd.m88k.delay_target; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(bsr) { cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + ic->arg[2]; cpu->pc = (uint32_t) (cpu->pc + ic->arg[1]); quick_pc_to_pointers(cpu); } X(bsr_n) { cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + ic->arg[2] + 4; cpu->cd.m88k.delay_target = cpu->pc + ic->arg[1]; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; cpu->pc = cpu->cd.m88k.delay_target; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(bsr_trace) { cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + ic->arg[2]; cpu->pc = (uint32_t) (cpu->pc + ic->arg[1]); cpu_functioncall_trace(cpu, cpu->pc); quick_pc_to_pointers(cpu); } X(bsr_n_trace) { cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->cd.m88k.r[M88K_RETURN_REG] = cpu->pc + ic->arg[2] + 4; cpu->cd.m88k.delay_target = cpu->pc + ic->arg[1]; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; cpu->pc = cpu->cd.m88k.delay_target; cpu_functioncall_trace(cpu, cpu->pc); quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } /* * bb? Branch if a bit in a register is 0 or 1. * bb?_samepage: Branch within the same translated page. * bb?_n_*: With delay slot. * * arg[0] = pointer to source register to test (s1). * arg[1] = uint32_t mask to test (e.g. 0x00010000 to test bit 16) * arg[2] = offset from start of current page _OR_ pointer to new instr_call */ X(bb0) { if (!(reg(ic->arg[0]) & ic->arg[1])) { cpu->pc = (cpu->pc & 0xfffff000) + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } } X(bb0_samepage) { if (!(reg(ic->arg[0]) & ic->arg[1])) cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[2]; } X(bb0_n) { int cond = !(reg(ic->arg[0]) & (uint32_t)ic->arg[1]); SYNCH_PC; if (cond) cpu->cd.m88k.delay_target = (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[2]; else cpu->cd.m88k.delay_target = cpu->pc + 8; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (cond) { cpu->pc = cpu->cd.m88k.delay_target; quick_pc_to_pointers(cpu); } else cpu->cd.m88k.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } X(bb1) { if (reg(ic->arg[0]) & ic->arg[1]) { cpu->pc = (cpu->pc & 0xfffff000) + (int32_t)ic->arg[2]; quick_pc_to_pointers(cpu); } } X(bb1_samepage) { if (reg(ic->arg[0]) & ic->arg[1]) cpu->cd.m88k.next_ic = (struct m88k_instr_call *) ic->arg[2]; } X(bb1_n) { int cond = reg(ic->arg[0]) & ic->arg[1]; SYNCH_PC; if (cond) cpu->cd.m88k.delay_target = (cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT)) + (int32_t)ic->arg[2]; else cpu->cd.m88k.delay_target = cpu->pc + 8; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; if (cond) { cpu->pc = cpu->cd.m88k.delay_target; quick_pc_to_pointers(cpu); } else cpu->cd.m88k.next_ic ++; } else cpu->delay_slot = NOT_DELAYED; } /* * ff0, ff1: Find first cleared/set bit in a register * * arg[0] = pointer to register d * arg[2] = pointer to register s2 */ X(ff0) { uint32_t mask = 0x80000000, s2 = reg(ic->arg[2]); int n = 31; for (;;) { if (!(s2 & mask)) { reg(ic->arg[0]) = n; return; } mask >>= 1; n--; if (mask == 0) { reg(ic->arg[0]) = 32; return; } } } X(ff1) { uint32_t mask = 0x80000000, s2 = reg(ic->arg[2]); int n = 31; for (;;) { if (s2 & mask) { reg(ic->arg[0]) = n; return; } mask >>= 1; n--; if (mask == 0) { reg(ic->arg[0]) = 32; return; } } } /* Include all automatically generated bcnd and bcnd.n instructions: */ #include "tmp_m88k_bcnd.cc" /* Include all automatically generated load/store instructions: */ #include "tmp_m88k_loadstore.cc" #define M88K_LOADSTORE_STORE 4 #define M88K_LOADSTORE_SIGNEDNESS 8 #define M88K_LOADSTORE_ENDIANNESS 16 #define M88K_LOADSTORE_SCALEDNESS 32 #define M88K_LOADSTORE_USR 64 #define M88K_LOADSTORE_REGISTEROFFSET 128 /* * jmp: Jump to register * jmp.n: Jump to register, with delay slot * jsr: Jump to register, set r1 to return address * jsr.n: Jump to register, set r1 to return address, with delay slot * * arg[1] = offset to return address, from start of current page * arg[2] = pointer to register s2 */ X(jmp) { cpu->pc = reg(ic->arg[2]) & ~3; quick_pc_to_pointers(cpu); } X(jmp_n) { cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; cpu->pc = cpu->cd.m88k.delay_target; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(jmp_trace) { cpu->pc = reg(ic->arg[2]) & ~3; cpu_functioncall_trace_return(cpu); quick_pc_to_pointers(cpu); } X(jmp_n_trace) { cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; cpu->pc = cpu->cd.m88k.delay_target; cpu_functioncall_trace_return(cpu); quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(jsr) { cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1]; cpu->pc = reg(ic->arg[2]) & ~3; quick_pc_to_pointers(cpu); } X(jsr_n) { cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3; cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1]; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; cpu->pc = cpu->cd.m88k.delay_target; quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } X(jsr_trace) { cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1]; cpu->pc = reg(ic->arg[2]) & ~3; cpu_functioncall_trace(cpu, cpu->pc); quick_pc_to_pointers(cpu); } X(jsr_n_trace) { cpu->cd.m88k.delay_target = reg(ic->arg[2]) & ~3; cpu->cd.m88k.r[M88K_RETURN_REG] = (cpu->pc & 0xfffff000) + ic->arg[1]; cpu->delay_slot = TO_BE_DELAYED; ic[1].f(cpu, ic+1); cpu->n_translated_instrs ++; if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { /* Note: Must be non-delayed when jumping to the new pc: */ cpu->delay_slot = NOT_DELAYED; cpu->pc = cpu->cd.m88k.delay_target; cpu_functioncall_trace(cpu, cpu->pc); quick_pc_to_pointers(cpu); } else cpu->delay_slot = NOT_DELAYED; } /* * cmp_imm: Compare S1 with immediate value. * cmp: Compare S1 with S2. * * arg[0] = pointer to register d * arg[1] = pointer to register s1 * arg[2] = pointer to register s2 or imm */ static void m88k_cmp(struct cpu *cpu, struct m88k_instr_call *ic, uint32_t y) { uint32_t x = reg(ic->arg[1]); uint32_t r; if (x == y) { r = M88K_CMP_HS | M88K_CMP_LS | M88K_CMP_GE | M88K_CMP_LE | M88K_CMP_EQ; } else { if (x > y) r = M88K_CMP_NE | M88K_CMP_HS | M88K_CMP_HI; else r = M88K_CMP_NE | M88K_CMP_LO | M88K_CMP_LS; if ((int32_t)x > (int32_t)y) r |= M88K_CMP_GE | M88K_CMP_GT; else r |= M88K_CMP_LT | M88K_CMP_LE; } reg(ic->arg[0]) = r; } X(cmp_imm) { m88k_cmp(cpu, ic, ic->arg[2]); } X(cmp) { m88k_cmp(cpu, ic, reg(ic->arg[2])); } /* * extu_imm: Extract bits, unsigned, immediate W. * extu: Extract bits, unsigned, W taken from register s2. * ext_imm: Extract bits, signed, immediate W. * ext: Extract bits, signed, W taken from register s2. * mak_imm: Make bit field, immediate W. * mak: Make bit field, W taken from register s2. * rot: Rotate s1 right, nr of steps taken from s2. * clr: Clear bits, W taken from register s2. * set: Set bits, W taken from register s2. * * arg[0] = pointer to register d * arg[1] = pointer to register s1 * arg[2] = pointer to register s2 or 10 bits wwwwwooooo */ static void m88k_extu(struct cpu *cpu, struct m88k_instr_call *ic, int w, int o) { uint32_t x = reg(ic->arg[1]) >> o; if (w != 0) { x <<= (32-w); x >>= (32-w); } reg(ic->arg[0]) = x; } static void m88k_ext(struct cpu *cpu, struct m88k_instr_call *ic, int w, int o) { int32_t x = reg(ic->arg[1]); x >>= o; /* signed (arithmetic) shift */ if (w != 0) { x <<= (32-w); x >>= (32-w); } reg(ic->arg[0]) = x; } static void m88k_mak(struct cpu *cpu, struct m88k_instr_call *ic, int w, int o) { uint32_t x = reg(ic->arg[1]); if (w != 0) { x <<= (32-w); x >>= (32-w); } reg(ic->arg[0]) = x << o; } X(extu_imm) { m88k_extu(cpu, ic, ic->arg[2] >> 5, ic->arg[2] & 0x1f); } X(extu) { m88k_extu(cpu, ic, (reg(ic->arg[2]) >> 5) & 0x1f, reg(ic->arg[2]) & 0x1f); } X(ext_imm) { m88k_ext(cpu, ic, ic->arg[2] >> 5, ic->arg[2] & 0x1f); } X(ext) { m88k_ext(cpu, ic, (reg(ic->arg[2]) >> 5) & 0x1f, reg(ic->arg[2]) & 0x1f); } X(mak_imm) { m88k_mak(cpu, ic, ic->arg[2] >> 5, ic->arg[2] & 0x1f); } X(mak) { m88k_mak(cpu, ic, (reg(ic->arg[2]) >> 5) & 0x1f, reg(ic->arg[2]) & 0x1f); } static void m88k_rot(struct cpu *cpu, struct m88k_instr_call *ic, int n) { uint32_t x = reg(ic->arg[1]); if (n != 0) { uint32_t mask = (1 << n) - 1; uint32_t bits = x & mask; x >>= n; x |= (bits << (32-n)); } reg(ic->arg[0]) = x; } X(rot) { m88k_rot(cpu, ic, reg(ic->arg[2]) & 0x1f); } X(clr) { int w = (reg(ic->arg[2]) >> 5) & 0x1f, o = reg(ic->arg[2]) & 0x1f; uint32_t x = w == 0? 0xffffffff : ((uint32_t)1 << w) - 1; x <<= o; reg(ic->arg[0]) = reg(ic->arg[1]) & ~x; } X(set) { int w = (reg(ic->arg[2]) >> 5) & 0x1f, o = reg(ic->arg[2]) & 0x1f; uint32_t x = w == 0? 0xffffffff : ((uint32_t)1 << w) - 1; x <<= o; reg(ic->arg[0]) = reg(ic->arg[1]) | x; } /* * or_r0_imm0: d = 0 (optimized case when s1 = r0, imm = 0) * or_r0_imm: d = imm (optimized case when s1 = r0) * or_imm: d = s1 | imm * xor_imm: d = s1 ^ imm * and_imm: d = (s1 & imm) | (s1 & 0xffff0000) * and_u_imm: d = (s1 & imm) | (s1 & 0xffff) * mask_imm: d = s1 & imm * add_imm: d = s1 - imm (addition with overflow exception) * addu_imm: d = s1 + imm * subu_imm: d = s1 - imm * inc_reg: d ++; (addu special case; d = d + 1) * dec_reg: d --; (subu special case; d = d - 1) * mulu_imm: d = s1 * imm * divu_imm: d = s1 / imm (unsigned) * div_imm: d = s1 / imm (signed) * sub_imm: d = s1 - imm (subtraction with overflow exception) * * arg[0] = pointer to register d * arg[1] = pointer to register s1 * arg[2] = imm */ X(or_r0_imm0) { reg(ic->arg[0]) = 0; } X(or_r0_imm) { reg(ic->arg[0]) = ic->arg[2]; } X(or_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) | ic->arg[2]; } X(xor_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) ^ ic->arg[2]; } X(and_imm) { reg(ic->arg[0]) = (reg(ic->arg[1]) & ic->arg[2]) | (reg(ic->arg[1]) & 0xffff0000); } X(and_u_imm) { reg(ic->arg[0]) = (reg(ic->arg[1]) & ic->arg[2]) | (reg(ic->arg[1]) & 0xffff); } X(mask_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) & ic->arg[2]; } X(add_imm) { uint64_t a = (int32_t) reg(ic->arg[1]); uint64_t b = ic->arg[2]; uint64_t res = a + b; uint64_t res2 = (int32_t) res; if (res != res2) { SYNCH_PC; m88k_exception(cpu, M88K_EXCEPTION_INTEGER_OVERFLOW, 0); return; } reg(ic->arg[0]) = res; } X(addu_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) + ic->arg[2]; } X(subu_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) - ic->arg[2]; } X(inc_reg) { reg(ic->arg[0]) ++; } X(dec_reg) { reg(ic->arg[0]) --; } X(mulu_imm) { if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); } else reg(ic->arg[0]) = reg(ic->arg[1]) * ic->arg[2]; } X(divu_imm) { if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); } else if (ic->arg[2] == 0) { SYNCH_PC; m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0); } else reg(ic->arg[0]) = (uint32_t) reg(ic->arg[1]) / (uint32_t) ic->arg[2]; } X(div_imm) { if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); } else if (ic->arg[2] == 0) { SYNCH_PC; m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0); } else { int32_t res = (int32_t) reg(ic->arg[1]) / (int32_t) ic->arg[2]; reg(ic->arg[0]) = res; } } X(sub_imm) { uint64_t a = (int32_t) reg(ic->arg[1]); uint64_t b = ic->arg[2]; uint64_t res = a - b; uint64_t res2 = (int32_t) res; if (res != res2) { SYNCH_PC; m88k_exception(cpu, M88K_EXCEPTION_INTEGER_OVERFLOW, 0); return; } reg(ic->arg[0]) = res; } /* * or: d = s1 | s2 * or_c: d = s1 | ~s2 * or_r0: d = s2 * xor: d = s1 ^ s2 * xor_c: d = s1 ^ ~s2 * and: d = s1 & s2 * and_c: d = s1 & ~s2 * add: d = s1 + s2 with trap on overflow * addu: d = s1 + s2 * addu_co: d = s1 + s2 carry out * addu_ci: d = s1 + s2 + carry carry in * lda_reg_X: same as addu, but s2 is scaled by 2, 4, or 8 * subu: d = s1 - s2 * subu_co: d = s1 - s2 carry/borrow out * subu_ci: d = s1 - s2 - (carry? 0 : 1) carry in * mul: d = s1 * s2 * divu: d = s1 / s2 (unsigned) * div: d = s1 / s2 (signed) * * arg[0] = pointer to register d * arg[1] = pointer to register s1 * arg[2] = pointer to register s2 */ X(or) { reg(ic->arg[0]) = reg(ic->arg[1]) | reg(ic->arg[2]); } X(or_c) { reg(ic->arg[0]) = reg(ic->arg[1]) | ~(reg(ic->arg[2])); } X(or_r0){ reg(ic->arg[0]) = reg(ic->arg[2]); } X(xor) { reg(ic->arg[0]) = reg(ic->arg[1]) ^ reg(ic->arg[2]); } X(xor_c){ reg(ic->arg[0]) = reg(ic->arg[1]) ^ ~(reg(ic->arg[2])); } X(and) { reg(ic->arg[0]) = reg(ic->arg[1]) & reg(ic->arg[2]); } X(and_c){ reg(ic->arg[0]) = reg(ic->arg[1]) & ~(reg(ic->arg[2])); } X(addu) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]); } X(addu_s2r0) { reg(ic->arg[0]) = reg(ic->arg[1]); } X(lda_reg_2) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]) * 2; } X(lda_reg_4) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]) * 4; } X(lda_reg_8) { reg(ic->arg[0]) = reg(ic->arg[1]) + reg(ic->arg[2]) * 8; } X(subu) { reg(ic->arg[0]) = reg(ic->arg[1]) - reg(ic->arg[2]); } X(add) { uint64_t s1 = (int32_t) reg(ic->arg[1]); uint64_t s2 = (int32_t) reg(ic->arg[2]); uint64_t d = s1 + s2; uint64_t dx = (int32_t) d; /* "If the result cannot be represented as a signed 32-bit integer" then there should be an exception. */ if (d != dx) { SYNCH_PC; m88k_exception(cpu, M88K_EXCEPTION_INTEGER_OVERFLOW, 0); } else { reg(ic->arg[0]) = d; } } X(mul) { if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); } else reg(ic->arg[0]) = reg(ic->arg[1]) * reg(ic->arg[2]); } X(divu) { if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); } else if (reg(ic->arg[2]) == 0) { SYNCH_PC; m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0); } else reg(ic->arg[0]) = (uint32_t) reg(ic->arg[1]) / (uint32_t) reg(ic->arg[2]); } X(div) { if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); } else if (reg(ic->arg[2]) == 0) { SYNCH_PC; m88k_exception(cpu, M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE, 0); } else { int32_t res = (int32_t) reg(ic->arg[1]) / (int32_t) reg(ic->arg[2]); reg(ic->arg[0]) = res; } } X(addu_co) { uint64_t a = reg(ic->arg[1]), b = reg(ic->arg[2]); a += b; reg(ic->arg[0]) = a; cpu->cd.m88k.cr[M88K_CR_PSR] &= ~M88K_PSR_C; if ((a >> 32) & 1) cpu->cd.m88k.cr[M88K_CR_PSR] |= M88K_PSR_C; } X(addu_ci) { uint32_t result = reg(ic->arg[1]) + reg(ic->arg[2]); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_C) result ++; reg(ic->arg[0]) = result; } X(subu_co) { uint64_t a = reg(ic->arg[1]), b = reg(ic->arg[2]); a -= b; reg(ic->arg[0]) = a; cpu->cd.m88k.cr[M88K_CR_PSR] &= ~M88K_PSR_C; if ((a >> 32) & 1) cpu->cd.m88k.cr[M88K_CR_PSR] |= M88K_PSR_C; } X(subu_ci) { uint32_t result = reg(ic->arg[1]) - reg(ic->arg[2]); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_C) result --; reg(ic->arg[0]) = result; } /* * ldcr: Load value from a control register, store in register d. * fldcr: Load value from a floating point control register, store in reg d. * * arg[0] = pointer to register d * arg[1] = 6-bit control register number */ X(ldcr) { SYNCH_PC; if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE) m88k_ldcr(cpu, (uint32_t *) (void *) ic->arg[0], ic->arg[1]); else m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0); } X(fldcr) { SYNCH_PC; if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE || ic->arg[1] >= 62) reg(ic->arg[0]) = cpu->cd.m88k.fcr[ic->arg[1]]; else { /* TODO: The manual says "floating point privilege violation", not just "privilege violation"! */ m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0); } } /* * stcr: Store a value into a control register. * fstcr: Store a value into a floating point control register. * * arg[0] = pointer to source register * arg[1] = 6-bit control register number */ X(stcr) { SYNCH_PC; if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE) m88k_stcr(cpu, reg(ic->arg[0]), ic->arg[1], 0); else m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0); } X(fstcr) { SYNCH_PC; if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE || ic->arg[1] >= 62) m88k_fstcr(cpu, reg(ic->arg[0]), ic->arg[1]); else { /* TODO: The manual says "floating point privilege violation", not just "privilege violation"! */ m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0); } } /* * fadd.xxx: Floating point addition * fsub.xxx: Floating point subtraction * fmul.xxx: Floating point multiplication * fdiv.xxx: Floating point multiplication * * arg[0] = pointer to destination register * arg[1] = pointer to source register s1 * arg[2] = pointer to source register s2 * * Note: For 'd' variants, arg[x] points to a _pair_ of registers! */ X(fadd_sss) { struct ieee_float_value f1; struct ieee_float_value f2; uint32_t d; uint32_t s2 = reg(ic->arg[2]); uint32_t s1 = reg(ic->arg[1]); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_S); ieee_interpret_float_value(s2, &f2, IEEE_FMT_S); d = ieee_store_float_value(f1.f + f2.f, IEEE_FMT_S); reg(ic->arg[0]) = d; } X(fadd_dsd) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t d; uint64_t s2 = reg(ic->arg[2]); uint32_t s1 = reg(ic->arg[1]); s2 = (s2 << 32) + reg(ic->arg[2] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_S); ieee_interpret_float_value(s2, &f2, IEEE_FMT_D); d = ieee_store_float_value(f1.f + f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = d; /* and low word. */ } X(fadd_dds) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t d; uint32_t s2 = reg(ic->arg[2]); uint64_t s1 = reg(ic->arg[1]); s1 = (s1 << 32) + reg(ic->arg[1] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_D); ieee_interpret_float_value(s2, &f2, IEEE_FMT_S); d = ieee_store_float_value(f1.f + f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = d; /* and low word. */ } X(fadd_ddd) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t d; uint64_t s1 = reg(ic->arg[1]); uint64_t s2 = reg(ic->arg[2]); s1 = (s1 << 32) + reg(ic->arg[1] + 4); s2 = (s2 << 32) + reg(ic->arg[2] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_D); ieee_interpret_float_value(s2, &f2, IEEE_FMT_D); d = ieee_store_float_value(f1.f + f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = d; /* and low word. */ } X(fsub_sds) { struct ieee_float_value f1; struct ieee_float_value f2; uint32_t d; uint32_t s2 = reg(ic->arg[2]); uint64_t s1 = reg(ic->arg[1]); s1 = (s1 << 32) + reg(ic->arg[1] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_D); ieee_interpret_float_value(s2, &f2, IEEE_FMT_S); d = ieee_store_float_value(f1.f - f2.f, IEEE_FMT_S); reg(ic->arg[0]) = d; } X(fsub_dss) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t d; uint32_t s2 = reg(ic->arg[2]); uint32_t s1 = reg(ic->arg[1]); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_S); ieee_interpret_float_value(s2, &f2, IEEE_FMT_S); d = ieee_store_float_value(f1.f - f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = d; /* and low word. */ } X(fsub_dsd) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t d; uint64_t s2 = reg(ic->arg[2]); uint32_t s1 = reg(ic->arg[1]); s2 = (s2 << 32) + reg(ic->arg[2] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_S); ieee_interpret_float_value(s2, &f2, IEEE_FMT_D); d = ieee_store_float_value(f1.f - f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = d; /* and low word. */ } X(fsub_dds) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t d; uint32_t s2 = reg(ic->arg[2]); uint64_t s1 = reg(ic->arg[1]); s1 = (s1 << 32) + reg(ic->arg[1] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_D); ieee_interpret_float_value(s2, &f2, IEEE_FMT_S); d = ieee_store_float_value(f1.f - f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = d; /* and low word. */ } X(fsub_ddd) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t d; uint64_t s1 = reg(ic->arg[1]); uint64_t s2 = reg(ic->arg[2]); s1 = (s1 << 32) + reg(ic->arg[1] + 4); s2 = (s2 << 32) + reg(ic->arg[2] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_D); ieee_interpret_float_value(s2, &f2, IEEE_FMT_D); d = ieee_store_float_value(f1.f - f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = d; /* and low word. */ } X(fmul_sss) { struct ieee_float_value f1; struct ieee_float_value f2; uint32_t d; uint32_t s2 = reg(ic->arg[2]); uint32_t s1 = reg(ic->arg[1]); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_S); ieee_interpret_float_value(s2, &f2, IEEE_FMT_S); d = ieee_store_float_value(f1.f * f2.f, IEEE_FMT_S); reg(ic->arg[0]) = d; } X(fmul_dss) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t d; uint32_t s2 = reg(ic->arg[2]); uint32_t s1 = reg(ic->arg[1]); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_S); ieee_interpret_float_value(s2, &f2, IEEE_FMT_S); d = ieee_store_float_value(f1.f * f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = d; /* and low word. */ } X(fmul_dsd) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t d; uint64_t s2 = reg(ic->arg[2]); uint32_t s1 = reg(ic->arg[1]); s2 = (s2 << 32) + reg(ic->arg[2] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_S); ieee_interpret_float_value(s2, &f2, IEEE_FMT_D); d = ieee_store_float_value(f1.f * f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = d; /* and low word. */ } X(fmul_dds) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t d; uint32_t s2 = reg(ic->arg[2]); uint64_t s1 = reg(ic->arg[1]); s1 = (s1 << 32) + reg(ic->arg[1] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_D); ieee_interpret_float_value(s2, &f2, IEEE_FMT_S); d = ieee_store_float_value(f1.f * f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = d; /* and low word. */ } X(fmul_ddd) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t d; uint64_t s1 = reg(ic->arg[1]); uint64_t s2 = reg(ic->arg[2]); s1 = (s1 << 32) + reg(ic->arg[1] + 4); s2 = (s2 << 32) + reg(ic->arg[2] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_D); ieee_interpret_float_value(s2, &f2, IEEE_FMT_D); d = ieee_store_float_value(f1.f * f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = d; /* and low word. */ } X(fdiv_sss) { struct ieee_float_value f1; struct ieee_float_value f2; uint32_t d; uint32_t s1 = reg(ic->arg[1]); uint32_t s2 = reg(ic->arg[2]); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_S); ieee_interpret_float_value(s2, &f2, IEEE_FMT_S); if (f2.f == 0) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FDVZ; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } d = ieee_store_float_value(f1.f / f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d; } X(fdiv_dsd) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t d; uint32_t s1 = reg(ic->arg[1]); uint64_t s2 = reg(ic->arg[2]); s2 = (s2 << 32) + reg(ic->arg[2] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_S); ieee_interpret_float_value(s2, &f2, IEEE_FMT_D); if (f2.f == 0) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FDVZ; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } d = ieee_store_float_value(f1.f / f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = d; /* and low word. */ } X(fdiv_ddd) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t d; uint64_t s1 = reg(ic->arg[1]); uint64_t s2 = reg(ic->arg[2]); s1 = (s1 << 32) + reg(ic->arg[1] + 4); s2 = (s2 << 32) + reg(ic->arg[2] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_D); ieee_interpret_float_value(s2, &f2, IEEE_FMT_D); if (f2.f == 0) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FDVZ; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } d = ieee_store_float_value(f1.f / f2.f, IEEE_FMT_D); reg(ic->arg[0]) = d >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = d; /* and low word. */ } /* * fcmp.sXX: Floating point comparison * * arg[0] = pointer to destination register * arg[1] = pointer to source register s1 * arg[2] = pointer to source register s2 * * Note: For 'd' variants, arg[x] points to a _pair_ of registers! */ static uint32_t m88k_fcmp_common(struct ieee_float_value *f1, struct ieee_float_value *f2) { uint32_t d; /* TODO: Implement all bits correctly, e.g. "in range" bits. */ d = 0; if (isnan(f1->f) || isnan(f2->f)) d |= (1 << 0); else { d |= (1 << 1); if (f1->f == f2->f) d |= (1 << 2); else d |= (1 << 3); if (f1->f > f2->f) d |= (1 << 4); else d |= (1 << 5); if (f1->f < f2->f) d |= (1 << 6); else d |= (1 << 7); } return d; } X(fcmp_sds) { struct ieee_float_value f1; struct ieee_float_value f2; uint32_t s2 = reg(ic->arg[2]); uint64_t s1 = reg(ic->arg[1]); s1 = (s1 << 32) + reg(ic->arg[1] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_D); ieee_interpret_float_value(s2, &f2, IEEE_FMT_S); reg(ic->arg[0]) = m88k_fcmp_common(&f1, &f2); } X(fcmp_sdd) { struct ieee_float_value f1; struct ieee_float_value f2; uint64_t s1 = reg(ic->arg[1]); uint64_t s2 = reg(ic->arg[2]); s1 = (s1 << 32) + reg(ic->arg[1] + 4); s2 = (s2 << 32) + reg(ic->arg[2] + 4); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } ieee_interpret_float_value(s1, &f1, IEEE_FMT_D); ieee_interpret_float_value(s2, &f2, IEEE_FMT_D); reg(ic->arg[0]) = m88k_fcmp_common(&f1, &f2); } /* * flt.ss and flt.ds: Convert integer to floating point. * * arg[0] = pointer to destination register * arg[1] = pointer to source register s2 * * Note: For flt.ds, arg[0] points to a _pair_ of registers! */ X(flt_ss) { int32_t x = reg(ic->arg[1]); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } reg(ic->arg[0]) = ieee_store_float_value((double)x, IEEE_FMT_S); } X(flt_ds) { int32_t x = reg(ic->arg[1]); uint64_t result; if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } result = ieee_store_float_value((double)x, IEEE_FMT_D); reg(ic->arg[0]) = result >> 32; /* High 32-bit word, */ reg(ic->arg[0] + 4) = result; /* and low word. */ } /* * trnc.ss and trnc.sd: Truncate floating point to interger. * * arg[0] = pointer to destination register * arg[1] = pointer to source register s2 * * Note: For trnc.sd, arg[1] points to a _pair_ of registers! */ X(trnc_ss) { struct ieee_float_value f1; ieee_interpret_float_value(reg(ic->arg[1]), &f1, IEEE_FMT_S); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } reg(ic->arg[0]) = (int32_t) f1.f; } X(trnc_sd) { struct ieee_float_value f1; uint64_t x = reg(ic->arg[1]); x = (x << 32) + reg(ic->arg[1] + 4); ieee_interpret_float_value(x, &f1, IEEE_FMT_D); if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFD1) { SYNCH_PC; cpu->cd.m88k.fcr[M88K_FPCR_FPECR] = M88K_FPECR_FUNIMP; m88k_exception(cpu, M88K_EXCEPTION_SFU1_PRECISE, 0); return; } reg(ic->arg[0]) = (int32_t) f1.f; } /* * xcr: Exchange (load + store) control register. * * arg[0] = pointer to register d * arg[1] = pointer to register s1 * arg[2] = 6-bit control register number */ X(xcr) { uint32_t tmp, tmp2; SYNCH_PC; if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE) { tmp = reg(ic->arg[1]); m88k_ldcr(cpu, &tmp2, ic->arg[2]); m88k_stcr(cpu, tmp, ic->arg[2], 0); reg(ic->arg[0]) = tmp2; } else m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0); } /* * rte: Return from exception */ X(rte) { /* If executed from user mode, then cause an exception: */ if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) { SYNCH_PC; m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0); return; } m88k_stcr(cpu, cpu->cd.m88k.cr[M88K_CR_EPSR], M88K_CR_PSR, 1); if (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_E) { fatal("rte: NIP: TODO: single-step support\n"); goto abort_dump; } if (cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_E) { fatal("rte: TODO: FIP single-step support\n"); goto abort_dump; } /* First try the NIP, if it is Valid: */ cpu->pc = cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_ADDR; /* If the NIP is not valid, then try the FIP: */ if (!(cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_V)) { /* Neither the NIP nor the FIP valid? */ if (!(cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_V)) { if ((cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_ADDR) != (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_ADDR) + 4) { fatal("[ TODO: Neither FIP nor NIP has the " "Valid bit set?! ]\n"); goto abort_dump; } /* For now, continue anyway, using NIP. */ } else { cpu->pc = cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_ADDR; } } else if (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_V && cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_V && (cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_ADDR) != (cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_ADDR) + 4) { /* * The NIP instruction should first be executed (this * is the one the exception handler choose to return to), * and then the FIP instruction should run (the target * of a delayed branch). */ uint32_t nip = cpu->cd.m88k.cr[M88K_CR_SNIP] & M88K_NIP_ADDR; uint32_t fip = cpu->cd.m88k.cr[M88K_CR_SFIP] & M88K_FIP_ADDR; cpu->pc = nip; cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); if (cpu->pc != nip) { fatal("NIP execution caused exception?! TODO\n"); goto abort_dump; } instr(to_be_translated)(cpu, cpu->cd.m88k.next_ic); if ((cpu->pc & 0xfffff000) != (nip & 0xfffff000)) { fatal("instruction in delay slot when returning via" " rte caused an exception?! nip=0x%08x, but pc " "changed to 0x%08x! TODO\n", nip, (int)cpu->pc); goto abort_dump; } cpu->pc = fip; cpu->delay_slot = NOT_DELAYED; quick_pc_to_pointers(cpu); return; } /* fatal("RTE: NIP=0x%08" PRIx32", FIP=0x%08" PRIx32"\n", cpu->cd.m88k.cr[M88K_CR_SNIP], cpu->cd.m88k.cr[M88K_CR_SFIP]); */ quick_pc_to_pointers(cpu); return; abort_dump: fatal("RTE failed. NIP=0x%08" PRIx32", FIP=0x%08" PRIx32"\n", cpu->cd.m88k.cr[M88K_CR_SNIP], cpu->cd.m88k.cr[M88K_CR_SFIP]); ABORT_EXECUTION; } /* * xmem_slow: Unoptimized xmem (exchange register with memory) * * arg[0] = copy of the instruction word */ X(xmem_slow) { uint32_t iword = ic->arg[0], addr; uint8_t tmp[4]; uint8_t data[4]; int d = (iword >> 21) & 0x1f; int s1 = (iword >> 16) & 0x1f; int s2 = iword & 0x1f; int imm16 = iword & 0xffff; int scaled = iword & 0x200; int size = iword & 0x400; int user = iword & 0x80; SYNCH_PC; if (user) { fatal("xmem_slow: user: not yet (TODO)\n"); exit(1); } if ((iword & 0xf0000000) == 0) { /* immediate offset: */ addr = imm16; scaled = 0; size = (iword >> 26) & 1; user = 0; } else { /* register offset: */ addr = cpu->cd.m88k.r[s2]; if (scaled && size) addr *= sizeof(uint32_t); } addr += cpu->cd.m88k.r[s1]; if (size) { uint32_t x = cpu->cd.m88k.r[d]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) x = LE32_TO_HOST(x); else x = BE32_TO_HOST(x); { uint32_t *p = (uint32_t *) tmp; *p = x; } if (addr & 3) { m88k_exception(cpu, M88K_EXCEPTION_MISALIGNED_ACCESS, 0); return; } } else tmp[0] = cpu->cd.m88k.r[d]; if (!cpu->memory_rw(cpu, cpu->mem, addr, (uint8_t *) &data, size? 4 : 1, MEM_READ, CACHE_DATA)) { /* Exception. */ fatal("XMEM exception: TODO: update the transaction" " registers!\n"); exit(1); /* return; */ } if (!cpu->memory_rw(cpu, cpu->mem, addr, (uint8_t *) &tmp, size? 4 : 1, MEM_WRITE, CACHE_DATA)) { /* Exception. */ fatal("XMEM exception: TODO: update the transaction" " registers!\n"); exit(1); /* return; */ } if (size) { uint32_t x; uint32_t *p = (uint32_t *) data; x = *p; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) x = LE32_TO_HOST(x); else x = BE32_TO_HOST(x); cpu->cd.m88k.r[d] = x; } else cpu->cd.m88k.r[d] = data[0]; } /* * prom-call: */ X(prom_call) { /* If executed from user mode, then cause an exception: */ if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) { SYNCH_PC; m88k_exception(cpu, M88K_EXCEPTION_UNIMPLEMENTED_OPCODE, 0); return; } switch (cpu->machine->machine_type) { case MACHINE_LUNA88K: luna88kprom_emul(cpu); break; case MACHINE_MVME88K: mvmeprom_emul(cpu); break; default:fatal("m88k prom_call: unimplemented machine type\n"); ABORT_EXECUTION; } if (!cpu->running) { cpu->n_translated_instrs --; cpu->cd.m88k.next_ic = ¬hing_call; } } /* * tb0, tb1: Trap on bit Clear/Set * * arg[0] = bitmask to check (e.g. 0x00020000 for bit 17) * arg[1] = pointer to register s1 * arg[2] = 9-bit vector number */ X(tb0) { SYNCH_PC; if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE) && ic->arg[2] < M88K_EXCEPTION_USER_TRAPS_START) { m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0); return; } if (!(reg(ic->arg[1]) & ic->arg[0])) m88k_exception(cpu, ic->arg[2], 1); } X(tb1) { SYNCH_PC; if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE) && ic->arg[2] < M88K_EXCEPTION_USER_TRAPS_START) { m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0); return; } if (reg(ic->arg[1]) & ic->arg[0]) m88k_exception(cpu, ic->arg[2], 1); } /* * idle: * * s: ld rX,rY,ofs * bcnd eq0,rX,s */ X(idle) { uint32_t rY = reg(ic[0].arg[1]) + ic[0].arg[2]; uint32_t index = rY >> 12; unsigned char *p = cpu->cd.m88k.host_load[index]; uint32_t *p32 = (uint32_t *) p; uint32_t v; /* Fallback: */ if (p == NULL || (rY & 3)) { instr(ld_u_4_be)(cpu, ic); return; } v = p32[(rY & 0xfff) >> 2]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) v = LE32_TO_HOST(v); else v = BE32_TO_HOST(v); reg(ic[0].arg[0]) = v; if (v == 0) { SYNCH_PC; usleep(50); cpu->has_been_idling = 1; cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 2; cpu->cd.m88k.next_ic = ¬hing_call; } else { cpu->n_translated_instrs ++; cpu->cd.m88k.next_ic = &ic[2]; } } /* * idle_with_tb1: * * s: tb1 bit,r0,vector * ld rX,rY,ofs * bcnd eq0,rX,s */ X(idle_with_tb1) { uint32_t rY = reg(ic[1].arg[1]) + ic[1].arg[2]; uint32_t index = rY >> 12; unsigned char *p = cpu->cd.m88k.host_load[index]; uint32_t *p32 = (uint32_t *) p; uint32_t v; /* Fallback: */ if (p == NULL || (rY & 3)) { instr(tb1)(cpu, ic); return; } v = p32[(rY & 0xfff) >> 2]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) v = LE32_TO_HOST(v); else v = BE32_TO_HOST(v); reg(ic[1].arg[0]) = v; if (v == 0) { SYNCH_PC; usleep(50); cpu->has_been_idling = 1; cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 2; cpu->cd.m88k.next_ic = ¬hing_call; } else { cpu->n_translated_instrs += 2; cpu->cd.m88k.next_ic = &ic[3]; } } /*****************************************************************************/ X(end_of_page) { /* Update the PC: (offset 0, but on the next page) */ cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->pc += (M88K_IC_ENTRIES_PER_PAGE << M88K_INSTR_ALIGNMENT_SHIFT); /* end_of_page doesn't count as an executed instruction: */ cpu->n_translated_instrs --; /* * Find the new physpage and update translation pointers. * * Note: This may cause an exception, if e.g. the new page is * not accessible. */ quick_pc_to_pointers(cpu); /* Simple jump to the next page (if we are lucky): */ if (cpu->delay_slot == NOT_DELAYED) return; /* * If we were in a delay slot, and we got an exception while doing * quick_pc_to_pointers, then return. The function which called * end_of_page should handle this case. */ if (cpu->delay_slot == EXCEPTION_IN_DELAY_SLOT) return; /* * Tricky situation; the delay slot is on the next virtual page. * Calling to_be_translated will translate one instruction manually, * execute it, and then discard it. */ /* fatal("[ end_of_page: delay slot across page boundary! ]\n"); */ instr(to_be_translated)(cpu, cpu->cd.m88k.next_ic); /* The instruction in the delay slot has now executed. */ /* fatal("[ end_of_page: back from executing the delay slot, %i ]\n", cpu->delay_slot); */ /* Find the physpage etc of the instruction in the delay slot (or, if there was an exception, the exception handler): */ quick_pc_to_pointers(cpu); } X(end_of_page2) { /* Synchronize PC on the _second_ instruction on the next page: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.m88k.cur_ic_page) / sizeof(struct m88k_instr_call); cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << M88K_INSTR_ALIGNMENT_SHIFT); if (low_pc < 0 || low_pc > ((M88K_IC_ENTRIES_PER_PAGE+1) << M88K_INSTR_ALIGNMENT_SHIFT)) { printf("[ end_of_page2: HUH? low_pc=%i, cpu->pc = %08" PRIx32" ]\n", low_pc, (uint32_t) cpu->pc); } /* This doesn't count as an executed instruction. */ cpu->n_translated_instrs --; quick_pc_to_pointers(cpu); if (cpu->delay_slot == NOT_DELAYED) return; fatal("end_of_page2: fatal error, we're in a delay slot\n"); exit(1); } /*****************************************************************************/ /* * Idle loop detection, e.g.: * * s00028d44: 15b7d650 ld r13,r23,0xd650 ; [<_sched_whichqs>] * s00028d48: e84dffff bcnd eq0,r13,0x00028d44 ; <_sched_idle+0xc4> * * or * * s00079d78: f020d8ff tb1 1,r0,0xff * s00079d7c: 15ac7320 ld r13,r12,0x7320 ; [<_sched_whichqs>] * s00079d80: e84dfffe bcnd eq0,r13,0x00079d78 ; <_sched_idle+0x158> */ void COMBINE(idle)(struct cpu *cpu, struct m88k_instr_call *ic, int low_addr) { int n_back = (low_addr >> M88K_INSTR_ALIGNMENT_SHIFT) & (M88K_IC_ENTRIES_PER_PAGE-1); if (n_back < 2) return; if (ic[0].f == instr(bcnd_samepage_eq0) && ic[0].arg[2] == (size_t) &ic[-1] && ic[-1].f == instr(ld_u_4_be) && ic[0].arg[0] == ic[-1].arg[0] && ic[0].arg[0] != (size_t) &cpu->cd.m88k.r[M88K_ZERO_REG]) { ic[-1].f = instr(idle); return; } if (ic[0].f == instr(bcnd_samepage_eq0) && ic[0].arg[2] == (size_t) &ic[-2] && ic[-2].f == instr(tb1) && ic[-2].arg[1] == (size_t) &cpu->cd.m88k.r[M88K_ZERO_REG] && ic[-1].f == instr(ld_u_4_be) && ic[0].arg[0] == ic[-1].arg[0] && ic[0].arg[0] != (size_t) &cpu->cd.m88k.r[M88K_ZERO_REG]) { ic[-2].f = instr(idle_with_tb1); return; } } /*****************************************************************************/ /* * m88k_instr_to_be_translated(): * * Translate an instruction word into a m88k_instr_call. ic is filled in with * valid data for the translated instruction, or a "nothing" instruction if * there was a translation failure. The newly translated instruction is then * executed. */ X(to_be_translated) { uint32_t addr, low_pc, iword; unsigned char *page; unsigned char ib[4]; uint32_t op26, op10, op11, d, s1, s2, cr6, imm16; int32_t d16, d26; //, simm16; int offset, shift; int in_crosspage_delayslot = 0; void (*samepage_function)(struct cpu *, struct m88k_instr_call *)=NULL; /* Figure out the (virtual) address of the instruction: */ low_pc = ((size_t)ic - (size_t)cpu->cd.m88k.cur_ic_page) / sizeof(struct m88k_instr_call); /* Special case for branch with delayslot on the next page: */ if (cpu->delay_slot == TO_BE_DELAYED && low_pc == 0) { /* fatal("[ delay-slot translation across page " "boundary ]\n"); */ in_crosspage_delayslot = 1; } addr = cpu->pc & ~((M88K_IC_ENTRIES_PER_PAGE-1) << M88K_INSTR_ALIGNMENT_SHIFT); addr += (low_pc << M88K_INSTR_ALIGNMENT_SHIFT); cpu->pc = (MODE_int_t)addr; addr &= ~((1 << M88K_INSTR_ALIGNMENT_SHIFT) - 1); /* Read the instruction word from memory: */ page = cpu->cd.m88k.host_load[(uint32_t)addr >> 12]; if (page != NULL) { /* fatal("TRANSLATION HIT!\n"); */ memcpy(ib, page + (addr & 0xffc), sizeof(ib)); } else { /* fatal("TRANSLATION MISS!\n"); */ if (!cpu->memory_rw(cpu, cpu->mem, addr, ib, sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) { fatal("to_be_translated(): read failed: TODO\n"); goto bad; } } { uint32_t *p = (uint32_t *) ib; iword = *p; } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) iword = LE32_TO_HOST(iword); else iword = BE32_TO_HOST(iword); #define DYNTRANS_TO_BE_TRANSLATED_HEAD #include "cpu_dyntrans.cc" #undef DYNTRANS_TO_BE_TRANSLATED_HEAD /* * Translate the instruction: * * NOTE: _NEVER_ allow writes to the zero register; all instructions * that use the zero register as their destination should be treated * as NOPs, except those that access memory (they should use the * scratch register instead). */ if (cpu->cd.m88k.r[M88K_ZERO_REG] != 0) { fatal("INTERNAL ERROR! M88K_ZERO_REG != 0?\n"); exit(1); } op26 = (iword >> 26) & 0x3f; op11 = (iword >> 11) & 0x1f; op10 = (iword >> 10) & 0x3f; d = (iword >> 21) & 0x1f; s1 = (iword >> 16) & 0x1f; s2 = iword & 0x1f; imm16 = iword & 0xffff; // simm16 = (int16_t) (iword & 0xffff); cr6 = (iword >> 5) & 0x3f; d16 = ((int16_t) (iword & 0xffff)) * 4; d26 = ((int32_t)((iword & 0x03ffffff) << 6)) >> 4; switch (op26) { case 0x00: case 0x01: ic->f = instr(xmem_slow); ic->arg[0] = iword; if (d == M88K_ZERO_REG) ic->f = instr(nop); if (iword == 0) goto bad; break; case 0x02: /* ld.hu */ case 0x03: /* ld.bu */ case 0x04: /* ld.d */ case 0x05: /* ld */ case 0x06: /* ld.h */ case 0x07: /* ld.b */ case 0x08: /* st.d */ case 0x09: /* st */ case 0x0a: /* st.h */ case 0x0b: /* st.b */ { int store = 0, signedness = 0, opsize = 0; ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[2] = imm16; switch (op26) { case 0x02: opsize = 1; break; case 0x03: opsize = 0; break; case 0x04: opsize = 3; break; case 0x05: opsize = 2; break; case 0x06: opsize = 1; signedness = 1; break; case 0x07: opsize = 0; signedness = 1; break; case 0x08: store = 1; opsize = 3; break; case 0x09: store = 1; opsize = 2; break; case 0x0a: store = 1; opsize = 1; break; case 0x0b: store = 1; opsize = 0; break; } if (opsize == 3 && d == 31) { fatal("m88k load/store of register pair r31/r0" " is not yet implemented\n"); goto bad; } ic->f = m88k_loadstore[ opsize + (store? M88K_LOADSTORE_STORE : 0) + (signedness? M88K_LOADSTORE_SIGNEDNESS:0) + (cpu->byte_order == EMUL_BIG_ENDIAN? M88K_LOADSTORE_ENDIANNESS : 0) ]; if (!store && d == 0) ic->arg[0] = (size_t) &cpu->cd.m88k.zero_scratch; } break; case 0x10: /* and imm */ case 0x11: /* and.u imm */ case 0x12: /* mask imm */ case 0x13: /* mask.u imm */ case 0x14: /* xor imm */ case 0x15: /* xor.u imm */ case 0x16: /* or imm */ case 0x17: /* or.u imm */ case 0x18: /* addu imm */ case 0x19: /* subu imm */ case 0x1a: /* divu imm */ case 0x1b: /* mulu imm */ case 0x1c: /* add imm */ case 0x1d: /* sub imm */ case 0x1e: /* div imm */ case 0x1f: /* cmp imm */ shift = 0; switch (op26) { case 0x10: ic->f = instr(and_imm); break; case 0x11: ic->f = instr(and_u_imm); shift = 16; break; case 0x12: ic->f = instr(mask_imm); break; case 0x13: ic->f = instr(mask_imm); shift = 16; break; case 0x14: ic->f = instr(xor_imm); break; case 0x15: ic->f = instr(xor_imm); shift = 16; break; case 0x16: ic->f = instr(or_imm); break; case 0x17: ic->f = instr(or_imm); shift = 16; break; case 0x18: ic->f = instr(addu_imm); break; case 0x19: ic->f = instr(subu_imm); break; case 0x1a: ic->f = instr(divu_imm); break; case 0x1b: ic->f = instr(mulu_imm); break; case 0x1c: ic->f = instr(add_imm); break; case 0x1d: ic->f = instr(sub_imm); break; case 0x1e: ic->f = instr(div_imm); break; case 0x1f: ic->f = instr(cmp_imm); break; } ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[2] = imm16 << shift; /* Optimization for or d,r0,imm and similar */ if (s1 == M88K_ZERO_REG && ic->f == instr(or_imm)) { if (ic->arg[2] == 0) ic->f = instr(or_r0_imm0); else ic->f = instr(or_r0_imm); } if (ic->arg[2] == 0 && ic->f == instr(addu_imm)) ic->f = instr(addu_s2r0); if (d == s1 && ic->arg[2] == 1) { if (ic->f == instr(addu_imm)) ic->f = instr(inc_reg); if (ic->f == instr(subu_imm)) ic->f = instr(dec_reg); } if (d == M88K_ZERO_REG) ic->f = instr(nop); break; case 0x20: if ((iword & 0x001ff81f) == 0x00004000) { ic->f = instr(ldcr); ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = cr6; if (d == M88K_ZERO_REG) ic->arg[0] = (size_t) &cpu->cd.m88k.zero_scratch; } else if ((iword & 0x001ff81f) == 0x00004800) { ic->f = instr(fldcr); ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = cr6; if (d == M88K_ZERO_REG) ic->arg[0] = (size_t) &cpu->cd.m88k.zero_scratch; } else if ((iword & 0x03e0f800) == 0x00008000) { ic->f = instr(stcr); ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[1] = cr6; if (s1 != s2) goto bad; } else if ((iword & 0x03e0f800) == 0x00008800) { ic->f = instr(fstcr); ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[1] = cr6; if (s1 != s2) goto bad; } else if ((iword & 0x0000f800) == 0x0000c000) { ic->f = instr(xcr); ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[2] = cr6; if (s1 != s2) goto bad; } else goto bad; break; case 0x21: switch (op11) { case 0x00: /* fmul */ if (d == 0) { /* d = 0 isn't allowed. for now, let's abort execution. */ fatal("TODO: exception for d = 0 in fmul.xxx instruction\n"); goto bad; } ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2]; switch ((iword >> 5) & 0x3f) { case 0x00: ic->f = instr(fmul_sss); break; case 0x01: ic->f = instr(fmul_dss); break; case 0x05: ic->f = instr(fmul_dsd); break; case 0x11: ic->f = instr(fmul_dds); break; case 0x15: ic->f = instr(fmul_ddd); break; default:if (!cpu->translation_readahead) fatal("Unimplemented fmul combination 0x%x.\n", (iword >> 5) & 0x3f); goto bad; } break; case 0x04: /* flt */ if (d == 0) { /* d = 0 isn't allowed. for now, let's abort execution. */ fatal("TODO: exception for d = 0 in flt.xx instruction\n"); goto bad; } ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s2]; if ((iword >> 5) & 1) { ic->f = instr(flt_ds); if (d & 1) { fatal("TODO: double precision load into uneven register r%i?\n", d); goto bad; } } else { ic->f = instr(flt_ss); } break; case 0x05: /* fadd */ if (d == 0) { /* d = 0 isn't allowed. for now, let's abort execution. */ fatal("TODO: exception for d = 0 in fadd.xxx instruction\n"); goto bad; } ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2]; switch ((iword >> 5) & 0x3f) { case 0x00: ic->f = instr(fadd_sss); break; case 0x05: ic->f = instr(fadd_dsd); break; case 0x11: ic->f = instr(fadd_dds); break; case 0x15: ic->f = instr(fadd_ddd); break; default:if (!cpu->translation_readahead) fatal("Unimplemented fadd combination 0x%x.\n", (iword >> 5) & 0x3f); goto bad; } break; case 0x06: /* fsub */ if (d == 0) { /* d = 0 isn't allowed. for now, let's abort execution. */ fatal("TODO: exception for d = 0 in fsub.xxx instruction\n"); goto bad; } ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2]; switch ((iword >> 5) & 0x3f) { case 0x01: ic->f = instr(fsub_dss); break; case 0x05: ic->f = instr(fsub_dsd); break; case 0x10: ic->f = instr(fsub_sds); break; case 0x11: ic->f = instr(fsub_dds); break; case 0x15: ic->f = instr(fsub_ddd); break; default:if (!cpu->translation_readahead) fatal("Unimplemented fsub combination 0x%x.\n", (iword >> 5) & 0x3f); goto bad; } break; case 0x07: /* fcmp */ if (d == 0) { /* d = 0 isn't allowed. for now, let's abort execution. */ fatal("TODO: exception for d = 0 in fcmp.xxx instruction\n"); goto bad; } ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2]; switch ((iword >> 5) & 0x3f) { case 0x10: ic->f = instr(fcmp_sds); break; case 0x14: ic->f = instr(fcmp_sdd); break; default:if (!cpu->translation_readahead) fatal("Unimplemented fcmp combination 0x%x.\n", (iword >> 5) & 0x3f); goto bad; } break; case 0x0b: /* trnc */ if (d == 0) { /* d = 0 isn't allowed. for now, let's abort execution. */ fatal("TODO: exception for d = 0 in trnc.xx instruction\n"); goto bad; } ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s2]; if ((iword >> 7) & 1) { ic->f = instr(trnc_sd); if (s2 & 1) { fatal("TODO: double precision truncation into uneven register r%i?\n", d); goto bad; } } else { ic->f = instr(trnc_ss); } break; case 0x0e: /* fdiv */ if (d == 0) { /* d = 0 isn't allowed. for now, let's abort execution. */ fatal("TODO: exception for d = 0 in fdiv.xxx instruction\n"); goto bad; } ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2]; switch ((iword >> 5) & 0x3f) { case 0x00: ic->f = instr(fdiv_sss); break; case 0x05: ic->f = instr(fdiv_dsd); break; case 0x15: ic->f = instr(fdiv_ddd); break; default:if (!cpu->translation_readahead) fatal("Unimplemented fdiv combination 0x%x.\n", (iword >> 5) & 0x3f); goto bad; } break; default:goto bad; } break; case 0x30: /* br */ case 0x31: /* br.n */ case 0x32: /* bsr */ case 0x33: /* bsr.n */ switch (op26) { case 0x30: ic->f = instr(br); samepage_function = instr(br_samepage); if (cpu->translation_readahead > 1) cpu->translation_readahead = 1; break; case 0x31: ic->f = instr(br_n); if (cpu->translation_readahead > 2) cpu->translation_readahead = 2; break; case 0x32: ic->f = instr(bsr); samepage_function = instr(bsr_samepage); break; case 0x33: ic->f = instr(bsr_n); break; } offset = (addr & 0xffc) + d26; /* Prepare both samepage and offset style args. (Only one will be used in the actual instruction.) */ ic->arg[0] = (size_t) ( cpu->cd.m88k.cur_ic_page + (offset >> M88K_INSTR_ALIGNMENT_SHIFT) ); ic->arg[1] = offset; ic->arg[2] = (addr & 0xffc) + 4; /* Return offset for bsr_samepage */ if (offset >= 0 && offset <= 0xffc && samepage_function != NULL) ic->f = samepage_function; if (cpu->machine->show_trace_tree) { if (op26 == 0x32) ic->f = instr(bsr_trace); if (op26 == 0x33) ic->f = instr(bsr_n_trace); } break; case 0x34: /* bb0 */ case 0x35: /* bb0.n */ case 0x36: /* bb1 */ case 0x37: /* bb1.n */ switch (op26) { case 0x34: ic->f = instr(bb0); samepage_function = instr(bb0_samepage); break; case 0x35: ic->f = instr(bb0_n); break; case 0x36: ic->f = instr(bb1); samepage_function = instr(bb1_samepage); break; case 0x37: ic->f = instr(bb1_n); break; } ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[1] = (uint32_t) (1 << d); offset = (addr & 0xffc) + d16; ic->arg[2] = offset; if (offset >= 0 && offset <= 0xffc && samepage_function != NULL) { ic->f = samepage_function; ic->arg[2] = (size_t) ( cpu->cd.m88k.cur_ic_page + (offset >> M88K_INSTR_ALIGNMENT_SHIFT) ); } break; case 0x3a: /* bcnd */ case 0x3b: /* bcnd.n */ ic->f = m88k_bcnd[d + 32 * (op26 & 1)]; samepage_function = m88k_bcnd[64 + d + 32 * (op26 & 1)]; if (ic->f == NULL) goto bad; ic->arg[0] = (size_t) &cpu->cd.m88k.r[s1]; offset = (addr & 0xffc) + d16; ic->arg[2] = offset; if (offset >= 0 && offset <= 0xffc && samepage_function != NULL) { ic->f = samepage_function; ic->arg[2] = (size_t) ( cpu->cd.m88k.cur_ic_page + (offset >> M88K_INSTR_ALIGNMENT_SHIFT) ); } if ((iword & 0xffe0ffff) == 0xe840ffff || (iword & 0xffe0ffff) == 0xe840fffe) cpu->cd.m88k.combination_check = COMBINE(idle); break; case 0x3c: switch (op10) { case 0x20: /* clr */ case 0x22: /* set */ case 0x24: /* ext */ case 0x26: /* extu */ case 0x28: /* mak */ ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[2] = iword & 0x3ff; switch (op10) { case 0x20: ic->f = instr(mask_imm); { int w = ic->arg[2] >> 5; int o = ic->arg[2] & 0x1f; uint32_t x = w == 0? 0xffffffff : ((uint32_t)1 << w) - 1; x <<= o; ic->arg[2] = ~x; } break; case 0x22: ic->f = instr(or_imm); { int w = ic->arg[2] >> 5; int o = ic->arg[2] & 0x1f; uint32_t x = w == 0? 0xffffffff : ((uint32_t)1 << w) - 1; x <<= o; ic->arg[2] = x; } break; case 0x24: ic->f = instr(ext_imm); break; case 0x26: ic->f = instr(extu_imm); break; case 0x28: ic->f = instr(mak_imm); break; } if (d == M88K_ZERO_REG) ic->f = instr(nop); break; case 0x34: /* tb0 */ case 0x36: /* tb1 */ ic->arg[0] = 1 << d; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[2] = iword & 0x1ff; switch (op10) { case 0x34: ic->f = instr(tb0); break; case 0x36: ic->f = instr(tb1); break; } break; default:goto bad; } break; case 0x3d: if ((iword & 0xf000) <= 0x3fff ) { /* Load, Store, xmem, and lda: */ int op = 0, opsize, user = 0, wt = 0; int signedness = 1, scaled = 0; switch (iword & 0xf000) { case 0x2000: op = 1; /* st */ break; case 0x3000: op = 2; /* lda */ break; default: if ((iword & 0xf800) >= 0x0800) op = 0; /* ld */ else op = 3; /* xmem */ } /* for (most) ld, st, lda: */ opsize = (iword >> 10) & 3; /* Turn opsize into x, where size = 1 << x: */ opsize = 3 - opsize; if (op == 3) { /* xmem: */ switch ((iword >> 10) & 3) { case 0: opsize = 0; break; case 1: opsize = 2; break; default:fatal("Weird xmem opsize/type?\n"); goto bad; } } else { if ((iword & 0xf800) == 0x800) { signedness = 0; if ((iword & 0xf00) < 0xc00) opsize = 1; else opsize = 0; } else { if (opsize >= 2 || op == 1) signedness = 0; } } if (iword & 0x100) user = 1; if (iword & 0x80) wt = 1; if (iword & 0x200) scaled = 1; if (wt) { fatal("wt bit not yet implemented! TODO\n"); goto bad; } ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2]; if (op == 0 || op == 1) { /* ld or st: */ ic->f = m88k_loadstore[ opsize + (op==1? M88K_LOADSTORE_STORE : 0) + (signedness? M88K_LOADSTORE_SIGNEDNESS:0) + (cpu->byte_order == EMUL_BIG_ENDIAN? M88K_LOADSTORE_ENDIANNESS : 0) + (scaled? M88K_LOADSTORE_SCALEDNESS : 0) + (user? M88K_LOADSTORE_USR : 0) + M88K_LOADSTORE_REGISTEROFFSET ]; if (d == M88K_ZERO_REG && op == 0) ic->arg[0] = (size_t)&cpu->cd.m88k.zero_scratch; if (opsize == 3 && d == 31) { fatal("m88k load/store of register " "pair r31/r0: TODO\n"); goto bad; } } else if (op == 2) { /* lda: */ if (scaled) { switch (opsize) { case 0: ic->f = instr(addu); break; case 1: ic->f = instr(lda_reg_2); break; case 2: ic->f = instr(lda_reg_4); break; case 3: ic->f = instr(lda_reg_8); break; } } else { ic->f = instr(addu); } if (d == M88K_ZERO_REG) ic->f = instr(nop); } else { /* xmem: */ ic->f = instr(xmem_slow); ic->arg[0] = iword; if (d == M88K_ZERO_REG) ic->f = instr(nop); } } else switch ((iword >> 8) & 0xff) { case 0x40: /* and */ case 0x44: /* and.c */ case 0x50: /* xor */ case 0x54: /* xor.c */ case 0x58: /* or */ case 0x5c: /* or.c */ case 0x60: /* addu */ case 0x61: /* addu.co */ case 0x62: /* addu.ci */ case 0x64: /* subu */ case 0x65: /* subu.co */ case 0x66: /* subu.ci */ case 0x68: /* divu */ case 0x6c: /* mul */ case 0x70: /* add */ case 0x78: /* div */ case 0x7c: /* cmp */ case 0x80: /* clr */ case 0x88: /* set */ case 0x90: /* ext */ case 0x98: /* extu */ case 0xa0: /* mak */ case 0xa8: /* rot */ ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[1] = (size_t) &cpu->cd.m88k.r[s1]; ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2]; switch ((iword >> 8) & 0xff) { case 0x40: ic->f = instr(and); break; case 0x44: ic->f = instr(and_c); break; case 0x50: ic->f = instr(xor); break; case 0x54: ic->f = instr(xor_c); break; case 0x58: ic->f = instr(or); break; case 0x5c: ic->f = instr(or_c); break; case 0x60: ic->f = instr(addu); break; case 0x61: ic->f = instr(addu_co); break; case 0x62: ic->f = instr(addu_ci); break; case 0x64: ic->f = instr(subu); break; case 0x65: ic->f = instr(subu_co); break; case 0x66: ic->f = instr(subu_ci); break; case 0x68: ic->f = instr(divu); break; case 0x6c: ic->f = instr(mul); break; case 0x70: ic->f = instr(add); break; case 0x78: ic->f = instr(div); break; case 0x7c: ic->f = instr(cmp); break; case 0x80: ic->f = instr(clr); break; case 0x88: ic->f = instr(set); break; case 0x90: ic->f = instr(ext); break; case 0x98: ic->f = instr(extu); break; case 0xa0: ic->f = instr(mak); break; case 0xa8: ic->f = instr(rot); break; } /* Optimization for or rX,r0,rY etc: */ if (s1 == M88K_ZERO_REG && ic->f == instr(or)) ic->f = instr(or_r0); if (s2 == M88K_ZERO_REG && ic->f == instr(addu)) ic->f = instr(addu_s2r0); /* * Handle the case when the destination register is r0: * * If there is NO SIDE-EFFECT! (i.e. no carry out), * then replace the instruction with a nop. If there is * a side-effect, we still have to run the instruction, * so replace the destination register with a scratch * register. */ if (d == M88K_ZERO_REG) { int opc = (iword >> 8) & 0xff; if (opc != 0x61 /* addu.co */ && opc != 0x63 /* addu.cio */ && opc != 0x65 /* subu.co */ && opc != 0x67 /* subu.cio */ && opc != 0x71 /* add.co */ && opc != 0x73 /* add.cio */ && opc != 0x75 /* sub.co */ && opc != 0x77 /* sub.cio */ && opc != 0x68 /* divu */ && opc != 0x69 /* divu.d */ && opc != 0x6c /* mul */ && opc != 0x6d /* mulu.d */ && opc != 0x6e /* muls */ && opc != 0x78 /* div */) ic->f = instr(nop); else ic->arg[0] = (size_t) &cpu->cd.m88k.zero_scratch; } break; case 0xc0: /* jmp */ case 0xc4: /* jmp.n */ case 0xc8: /* jsr */ case 0xcc: /* jsr.n */ switch ((iword >> 8) & 0xff) { case 0xc0: ic->f = instr(jmp); if (cpu->translation_readahead > 1) cpu->translation_readahead = 1; break; case 0xc4: ic->f = instr(jmp_n); if (cpu->translation_readahead > 2) cpu->translation_readahead = 2; break; case 0xc8: ic->f = instr(jsr); break; case 0xcc: ic->f = instr(jsr_n); break; } ic->arg[1] = (addr & 0xffc) + 4; ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2]; if (((iword >> 8) & 0x04) == 0x04) ic->arg[1] = (addr & 0xffc) + 8; if (cpu->machine->show_trace_tree && s2 == M88K_RETURN_REG) { if (ic->f == instr(jmp)) ic->f = instr(jmp_trace); if (ic->f == instr(jmp_n)) ic->f = instr(jmp_n_trace); } if (cpu->machine->show_trace_tree) { if (ic->f == instr(jsr)) ic->f = instr(jsr_trace); if (ic->f == instr(jsr_n)) ic->f = instr(jsr_n_trace); } break; case 0xe8: /* ff1 */ case 0xec: /* ff0 */ switch ((iword >> 8) & 0xff) { case 0xe8: ic->f = instr(ff1); break; case 0xec: ic->f = instr(ff0); break; } ic->arg[0] = (size_t) &cpu->cd.m88k.r[d]; ic->arg[2] = (size_t) &cpu->cd.m88k.r[s2]; if (d == M88K_ZERO_REG) ic->f = instr(nop); break; case 0xfc: switch (iword & 0xff) { case 0x00: if (iword == 0xf400fc00) ic->f = instr(rte); else { fatal("unimplemented rte variant: 0x%08" PRIx32"\n", iword); goto bad; } break; case (M88K_PROM_INSTR & 0xff): ic->f = instr(prom_call); break; default:fatal("Unimplemented 3d/fc instruction\n"); goto bad; } break; default:goto bad; } break; default:goto bad; } #define DYNTRANS_TO_BE_TRANSLATED_TAIL #include "cpu_dyntrans.cc" #undef DYNTRANS_TO_BE_TRANSLATED_TAIL } gxemul-0.6.1/src/cpus/cpu_arm.cc000644 001750 001750 00000174466 13402411502 016745 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * ARM CPU emulation. * * A good source of quick info on ARM instruction encoding: * http://www.pinknoise.demon.co.uk/ARMinstrs/ARMinstrs.html * * Another one, with details about THUMB: * http://engold.ui.ac.ir/~nikmehr/Appendix_B2.pdf * * and yet another one, with descriptions about THUMB semantics: * https://web.eecs.umich.edu/~prabal/teaching/eecs373-f10/readings/ARM_QRC0006_UAL16.pdf */ #include #include #include #include #include #include "arm_cpu_types.h" #include "cpu.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "of.h" #include "settings.h" #include "symbol.h" #define DYNTRANS_32 #include "tmp_arm_head.cc" /* ARM symbolic register names and condition strings: */ static const char *arm_regname[N_ARM_REGS] = ARM_REG_NAMES; static const char *arm_condition_string[16] = ARM_CONDITION_STRINGS; /* Data Processing Instructions: */ static const char *arm_dpiname[16] = ARM_DPI_NAMES; static int arm_dpi_uses_d[16] = { 1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1 }; static int arm_dpi_uses_n[16] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0 }; static const char *arm_thumb_dpiname[16] = ARM_THUMB_DPI_NAMES; static int arm_exception_to_mode[N_ARM_EXCEPTIONS] = ARM_EXCEPTION_TO_MODE; extern uint8_t condition_hi[16]; extern uint8_t condition_ge[16]; extern uint8_t condition_gt[16]; /* For quick_pc_to_pointers(): */ void arm_pc_to_pointers(struct cpu *cpu); #include "quick_pc_to_pointers.h" void arm_irq_interrupt_assert(struct interrupt *interrupt); void arm_irq_interrupt_deassert(struct interrupt *interrupt); /* * arm_cpu_new(): * * Create a new ARM cpu object by filling the CPU struct. * Return 1 on success, 0 if cpu_type_name isn't a valid ARM processor. */ int arm_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine, int cpu_id, char *cpu_type_name) { int i, found; struct arm_cpu_type_def cpu_type_defs[] = ARM_CPU_TYPE_DEFS; /* Scan the list for this cpu type: */ i = 0; found = -1; while (i >= 0 && cpu_type_defs[i].name != NULL) { if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) { found = i; break; } i++; } if (found == -1) return 0; cpu->run_instr = arm_run_instr; cpu->memory_rw = arm_memory_rw; cpu->update_translation_table = arm_update_translation_table; cpu->invalidate_translation_caches = arm_invalidate_translation_caches; cpu->invalidate_code_translation = arm_invalidate_code_translation; cpu->translate_v2p = arm_translate_v2p; cpu->cd.arm.cpu_type = cpu_type_defs[found]; cpu->name = strdup(cpu->cd.arm.cpu_type.name); cpu->is_32bit = 1; cpu->byte_order = EMUL_LITTLE_ENDIAN; cpu->cd.arm.cpsr = ARM_FLAG_I | ARM_FLAG_F; cpu->cd.arm.control = ARM_CONTROL_PROG32 | ARM_CONTROL_DATA32 | ARM_CONTROL_CACHE | ARM_CONTROL_ICACHE | ARM_CONTROL_ALIGN; /* TODO: default auxctrl contents */ if (cpu->machine->prom_emulation) { cpu->cd.arm.cpsr |= ARM_MODE_SVC32; cpu->cd.arm.control |= ARM_CONTROL_S; } else { cpu->cd.arm.cpsr |= ARM_MODE_SVC32; cpu->cd.arm.control |= ARM_CONTROL_R; } /* Only show name and caches etc for CPU nr 0: */ if (cpu_id == 0) { debug("%s", cpu->name); if (cpu->cd.arm.cpu_type.icache_shift != 0 || cpu->cd.arm.cpu_type.dcache_shift != 0) { int isize = cpu->cd.arm.cpu_type.icache_shift; int dsize = cpu->cd.arm.cpu_type.dcache_shift; if (isize != 0) isize = 1 << (isize - 10); if (dsize != 0) dsize = 1 << (dsize - 10); debug(" (I+D = %i+%i KB)", isize, dsize); } } /* TODO: Some of these values (iway and dway) aren't used yet: */ cpu->cd.arm.cachetype = (5 << ARM_CACHETYPE_CLASS_SHIFT) | (1 << ARM_CACHETYPE_HARVARD_SHIFT) | ((cpu->cd.arm.cpu_type.dcache_shift - 9) << ARM_CACHETYPE_DSIZE_SHIFT) | (5 << ARM_CACHETYPE_DASSOC_SHIFT) /* 32-way */ | (2 << ARM_CACHETYPE_DLINE_SHIFT) /* 8 words/line */ | ((cpu->cd.arm.cpu_type.icache_shift - 9) << ARM_CACHETYPE_ISIZE_SHIFT) | (5 << ARM_CACHETYPE_IASSOC_SHIFT) /* 32-way */ | (2 << ARM_CACHETYPE_ILINE_SHIFT); /* 8 words/line */ /* Coprocessor 15 = the system control coprocessor. */ cpu->cd.arm.coproc[15] = arm_coproc_15; /* Coprocessor 14 for XScale: */ if (cpu->cd.arm.cpu_type.flags & ARM_XSCALE) cpu->cd.arm.coproc[14] = arm_coproc_xscale_14; /* * NOTE/TODO: Ugly hack for OpenFirmware emulation: */ if (cpu->machine->prom_emulation) { cpu->cd.arm.of_emul_addr = cpu->machine->physical_ram_in_mb * 1048576 - 8; store_32bit_word(cpu, cpu->cd.arm.of_emul_addr, 0xef8c64be); } cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28; CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc); for (i=0; icd.arm.r[i]); CPU_SETTINGS_ADD_REGISTER32("cpsr", cpu->cd.arm.cpsr); /* Register the CPU's "IRQ" and "FIQ" interrupts: */ { struct interrupt templ; char name[50]; snprintf(name, sizeof(name), "%s.irq", cpu->path); memset(&templ, 0, sizeof(templ)); templ.line = 0; templ.name = name; templ.extra = cpu; templ.interrupt_assert = arm_irq_interrupt_assert; templ.interrupt_deassert = arm_irq_interrupt_deassert; interrupt_handler_register(&templ); /* FIQ: TODO */ } return 1; } /* * arm_setup_initial_translation_table(): * * When booting kernels (such as OpenBSD or NetBSD) directly, it is assumed * that the MMU is already enabled by the boot-loader. This function tries * to emulate that. */ void arm_setup_initial_translation_table(struct cpu *cpu, uint32_t ttb_addr) { unsigned char nothing[16384]; unsigned int i, j; cpu->cd.arm.control |= ARM_CONTROL_MMU; cpu->translate_v2p = arm_translate_v2p_mmu; cpu->cd.arm.dacr |= 0x00000003; cpu->cd.arm.ttb = ttb_addr; memset(nothing, 0, sizeof(nothing)); cpu->memory_rw(cpu, cpu->mem, cpu->cd.arm.ttb, nothing, sizeof(nothing), MEM_WRITE, PHYSICAL | NO_EXCEPTIONS); for (i=0; i<256; i++) for (j=0x0; j<=0xf; j++) { unsigned char descr[4]; uint32_t addr = cpu->cd.arm.ttb + (((j << 28) + (i << 20)) >> 18); uint32_t d = (1048576*i) | 0xc02; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { descr[0] = d; descr[1] = d >> 8; descr[2] = d >> 16; descr[3] = d >> 24; } else { descr[3] = d; descr[2] = d >> 8; descr[1] = d >> 16; descr[0] = d >> 24; } cpu->memory_rw(cpu, cpu->mem, addr, &descr[0], sizeof(descr), MEM_WRITE, PHYSICAL | NO_EXCEPTIONS); } } /* * arm_translation_table_set_l1(): */ void arm_translation_table_set_l1(struct cpu *cpu, uint32_t vaddr, uint32_t paddr) { unsigned int i, j, vhigh = vaddr >> 28, phigh = paddr >> 28; for (i=0; i<256; i++) for (j=vhigh; j<=vhigh; j++) { unsigned char descr[4]; uint32_t addr = cpu->cd.arm.ttb + (((j << 28) + (i << 20)) >> 18); uint32_t d = ((phigh << 28) + 1048576*i) | 0xc02; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { descr[0] = d; descr[1] = d >> 8; descr[2] = d >> 16; descr[3] = d >> 24; } else { descr[3] = d; descr[2] = d >> 8; descr[1] = d >> 16; descr[0] = d >> 24; } cpu->memory_rw(cpu, cpu->mem, addr, &descr[0], sizeof(descr), MEM_WRITE, PHYSICAL | NO_EXCEPTIONS); } } /* * arm_translation_table_set_l1_b(): */ void arm_translation_table_set_l1_b(struct cpu *cpu, uint32_t vaddr, uint32_t paddr) { unsigned int i, j, vhigh = vaddr >> 24, phigh = paddr >> 24; for (i=0; i<16; i++) for (j=vhigh; j<=vhigh; j++) { unsigned char descr[4]; uint32_t addr = cpu->cd.arm.ttb + (((j << 24) + (i << 20)) >> 18); uint32_t d = ((phigh << 24) + 1048576*i) | 0xc02; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { descr[0] = d; descr[1] = d >> 8; descr[2] = d >> 16; descr[3] = d >> 24; } else { descr[3] = d; descr[2] = d >> 8; descr[1] = d >> 16; descr[0] = d >> 24; } cpu->memory_rw(cpu, cpu->mem, addr, &descr[0], sizeof(descr), MEM_WRITE, PHYSICAL | NO_EXCEPTIONS); } } /* * arm_cpu_dumpinfo(): */ void arm_cpu_dumpinfo(struct cpu *cpu) { struct arm_cpu_type_def *ct = &cpu->cd.arm.cpu_type; debug(" (I+D = %i+%i KB)\n", (1 << ct->icache_shift) / 1024, (1 << ct->dcache_shift) / 1024); } /* * arm_cpu_list_available_types(): * * Print a list of available ARM CPU types. */ void arm_cpu_list_available_types(void) { int i, j; struct arm_cpu_type_def tdefs[] = ARM_CPU_TYPE_DEFS; i = 0; while (tdefs[i].name != NULL) { debug("%s", tdefs[i].name); for (j=13 - strlen(tdefs[i].name); j>0; j--) debug(" "); i++; if ((i % 5) == 0 || tdefs[i].name == NULL) debug("\n"); } } /* * arm_cpu_register_dump(): * * Dump cpu registers in a relatively readable format. * * gprs: set to non-zero to dump GPRs and some special-purpose registers. * coprocs: set bit 0..3 to dump registers in coproc 0..3. */ void arm_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs) { char *symbol; uint64_t offset; int mode = cpu->cd.arm.cpsr & ARM_FLAG_MODE; int i, x = cpu->cpu_id; cpu->cd.arm.cpsr &= 0x0fffffff; cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28); if (gprs) { symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->pc, &offset); debug("cpu%i: cpsr = ", x); debug("%s%s%s%s%s%s%s%s%s%s%s", (cpu->cd.arm.cpsr & ARM_FLAG_N)? "N" : "n", (cpu->cd.arm.cpsr & ARM_FLAG_Z)? "Z" : "z", (cpu->cd.arm.cpsr & ARM_FLAG_C)? "C" : "c", (cpu->cd.arm.cpsr & ARM_FLAG_V)? "V" : "v", (cpu->cd.arm.cpsr & ARM_FLAG_Q)? "Q" : "q", (cpu->cd.arm.cpsr & ARM_FLAG_J)? "J" : "j", (cpu->cd.arm.cpsr & ARM_FLAG_E)? "E" : "e", (cpu->cd.arm.cpsr & ARM_FLAG_A)? "A" : "a", (cpu->cd.arm.cpsr & ARM_FLAG_I)? "I" : "i", (cpu->cd.arm.cpsr & ARM_FLAG_F)? "F" : "f", (cpu->cd.arm.cpsr & ARM_FLAG_T)? "T" : "t"); if (mode < ARM_MODE_USR32) debug(" pc = 0x%07x", (int)(cpu->pc & 0x03ffffff)); else debug(" pc = 0x%08x", (int)cpu->pc); debug(" <%s>\n", symbol != NULL? symbol : " no symbol "); for (i=0; icd.arm.r[i]); if ((i % 4) == 3) debug("\n"); } } if (coprocs & 1) { int m = cpu->cd.arm.cpsr & ARM_FLAG_MODE; debug("cpu%i: cpsr = 0x%08x (", x, cpu->cd.arm.cpsr); switch (m) { case ARM_MODE_USR32: debug("USR32)\n"); break; case ARM_MODE_SYS32: debug("SYS32)\n"); break; case ARM_MODE_FIQ32: debug("FIQ32)\n"); break; case ARM_MODE_IRQ32: debug("IRQ32)\n"); break; case ARM_MODE_SVC32: debug("SVC32)\n"); break; case ARM_MODE_ABT32: debug("ABT32)\n"); break; case ARM_MODE_UND32: debug("UND32)\n"); break; default:debug("unimplemented)\n"); } if (m != ARM_MODE_USR32 && m != ARM_MODE_SYS32) { debug("cpu%i: usr r8-14:", x); for (i=0; i<7; i++) debug(" %08x", cpu->cd.arm.default_r8_r14[i]); debug("\n"); } if (m != ARM_MODE_FIQ32) { debug("cpu%i: fiq r8-14:", x); for (i=0; i<7; i++) debug(" %08x", cpu->cd.arm.fiq_r8_r14[i]); debug("\n"); } if (m != ARM_MODE_IRQ32) { debug("cpu%i: irq r13-14:", x); for (i=0; i<2; i++) debug(" %08x", cpu->cd.arm.irq_r13_r14[i]); debug("\n"); } if (m != ARM_MODE_SVC32) { debug("cpu%i: svc r13-14:", x); for (i=0; i<2; i++) debug(" %08x", cpu->cd.arm.svc_r13_r14[i]); debug("\n"); } if (m != ARM_MODE_ABT32) { debug("cpu%i: abt r13-14:", x); for (i=0; i<2; i++) debug(" %08x", cpu->cd.arm.abt_r13_r14[i]); debug("\n"); } if (m != ARM_MODE_UND32) { debug("cpu%i: und r13-14:", x); for (i=0; i<2; i++) debug(" %08x", cpu->cd.arm.und_r13_r14[i]); debug("\n"); } } if (coprocs & 2) { debug("cpu%i: control = 0x%08x\n", x, cpu->cd.arm.control); debug("cpu%i: MMU: %s\n", x, cpu->cd.arm.control & ARM_CONTROL_MMU? "enabled" : "disabled"); debug("cpu%i: alignment checks: %s\n", x, cpu->cd.arm.control & ARM_CONTROL_ALIGN? "enabled" : "disabled"); debug("cpu%i: [data] cache: %s\n", x, cpu->cd.arm.control & ARM_CONTROL_CACHE? "enabled" : "disabled"); debug("cpu%i: instruction cache: %s\n", x, cpu->cd.arm.control & ARM_CONTROL_ICACHE? "enabled" : "disabled"); debug("cpu%i: write buffer: %s\n", x, cpu->cd.arm.control & ARM_CONTROL_WBUFFER? "enabled" : "disabled"); debug("cpu%i: prog32: %s\n", x, cpu->cd.arm.control & ARM_CONTROL_PROG32? "yes" : "no (using prog26)"); debug("cpu%i: data32: %s\n", x, cpu->cd.arm.control & ARM_CONTROL_DATA32? "yes" : "no (using data26)"); debug("cpu%i: endianness: %s\n", x, cpu->cd.arm.control & ARM_CONTROL_BIG? "big endian" : "little endian"); debug("cpu%i: high vectors: %s\n", x, cpu->cd.arm.control & ARM_CONTROL_V? "yes (0xffff0000)" : "no"); /* TODO: auxctrl on which CPU types? */ if (cpu->cd.arm.cpu_type.flags & ARM_XSCALE) { debug("cpu%i: auxctrl = 0x%08x\n", x, cpu->cd.arm.auxctrl); debug("cpu%i: minidata cache attr = 0x%x\n", x, (cpu->cd.arm.auxctrl & ARM_AUXCTRL_MD) >> ARM_AUXCTRL_MD_SHIFT); debug("cpu%i: page table memory attr: %i\n", x, (cpu->cd.arm.auxctrl & ARM_AUXCTRL_P)? 1 : 0); debug("cpu%i: write buffer coalescing: %s\n", x, (cpu->cd.arm.auxctrl & ARM_AUXCTRL_K)? "disabled" : "enabled"); } debug("cpu%i: ttb = 0x%08x dacr = 0x%08x\n", x, cpu->cd.arm.ttb, cpu->cd.arm.dacr); debug("cpu%i: fsr = 0x%08x far = 0x%08x\n", x, cpu->cd.arm.fsr, cpu->cd.arm.far); } } /* * arm_save_register_bank(): */ void arm_save_register_bank(struct cpu *cpu) { /* Save away current registers: */ switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) { case ARM_MODE_USR32: case ARM_MODE_SYS32: memcpy(cpu->cd.arm.default_r8_r14, &cpu->cd.arm.r[8], sizeof(uint32_t) * 7); break; case ARM_MODE_FIQ32: memcpy(cpu->cd.arm.fiq_r8_r14, &cpu->cd.arm.r[8], sizeof(uint32_t) * 7); break; case ARM_MODE_IRQ32: memcpy(cpu->cd.arm.default_r8_r14, &cpu->cd.arm.r[8], sizeof(uint32_t) * 5); cpu->cd.arm.irq_r13_r14[0] = cpu->cd.arm.r[13]; cpu->cd.arm.irq_r13_r14[1] = cpu->cd.arm.r[14]; break; case ARM_MODE_SVC32: memcpy(cpu->cd.arm.default_r8_r14, &cpu->cd.arm.r[8], sizeof(uint32_t) * 5); cpu->cd.arm.svc_r13_r14[0] = cpu->cd.arm.r[13]; cpu->cd.arm.svc_r13_r14[1] = cpu->cd.arm.r[14]; break; case ARM_MODE_ABT32: memcpy(cpu->cd.arm.default_r8_r14, &cpu->cd.arm.r[8], sizeof(uint32_t) * 5); cpu->cd.arm.abt_r13_r14[0] = cpu->cd.arm.r[13]; cpu->cd.arm.abt_r13_r14[1] = cpu->cd.arm.r[14]; break; case ARM_MODE_UND32: memcpy(cpu->cd.arm.default_r8_r14, &cpu->cd.arm.r[8], sizeof(uint32_t) * 5); cpu->cd.arm.und_r13_r14[0] = cpu->cd.arm.r[13]; cpu->cd.arm.und_r13_r14[1] = cpu->cd.arm.r[14]; break; default:fatal("arm_save_register_bank: unimplemented mode %i\n", cpu->cd.arm.cpsr & ARM_FLAG_MODE); exit(1); } } /* * arm_load_register_bank(): */ void arm_load_register_bank(struct cpu *cpu) { /* Load new registers: */ switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) { case ARM_MODE_USR32: case ARM_MODE_SYS32: memcpy(&cpu->cd.arm.r[8], cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 7); break; case ARM_MODE_FIQ32: memcpy(&cpu->cd.arm.r[8], cpu->cd.arm.fiq_r8_r14, sizeof(uint32_t) * 7); break; case ARM_MODE_IRQ32: memcpy(&cpu->cd.arm.r[8], cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 5); cpu->cd.arm.r[13] = cpu->cd.arm.irq_r13_r14[0]; cpu->cd.arm.r[14] = cpu->cd.arm.irq_r13_r14[1]; break; case ARM_MODE_SVC32: memcpy(&cpu->cd.arm.r[8], cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 5); cpu->cd.arm.r[13] = cpu->cd.arm.svc_r13_r14[0]; cpu->cd.arm.r[14] = cpu->cd.arm.svc_r13_r14[1]; break; case ARM_MODE_ABT32: memcpy(&cpu->cd.arm.r[8], cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 5); cpu->cd.arm.r[13] = cpu->cd.arm.abt_r13_r14[0]; cpu->cd.arm.r[14] = cpu->cd.arm.abt_r13_r14[1]; break; case ARM_MODE_UND32: memcpy(&cpu->cd.arm.r[8], cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 5); cpu->cd.arm.r[13] = cpu->cd.arm.und_r13_r14[0]; cpu->cd.arm.r[14] = cpu->cd.arm.und_r13_r14[1]; break; default:fatal("arm_load_register_bank: unimplemented mode %i\n", cpu->cd.arm.cpsr & ARM_FLAG_MODE); exit(1); } } /* * arm_exception(): */ void arm_exception(struct cpu *cpu, int exception_nr) { int oldmode, newmode; uint32_t retaddr; if (exception_nr < 0 || exception_nr >= N_ARM_EXCEPTIONS) { fatal("arm_exception(): exception_nr = %i\n", exception_nr); exit(1); } retaddr = cpu->pc; if (!quiet_mode) { debug("[ arm_exception(): "); switch (exception_nr) { case ARM_EXCEPTION_RESET: fatal("RESET: TODO"); break; case ARM_EXCEPTION_UND: debug("UNDEFINED"); break; case ARM_EXCEPTION_SWI: debug("SWI"); break; case ARM_EXCEPTION_PREF_ABT: debug("PREFETCH ABORT"); break; case ARM_EXCEPTION_IRQ: debug("IRQ"); break; case ARM_EXCEPTION_FIQ: debug("FIQ"); break; case ARM_EXCEPTION_DATA_ABT: debug("DATA ABORT, far=0x%08x fsr=0x%02x", cpu->cd.arm.far, cpu->cd.arm.fsr); break; } debug(" ]\n"); } switch (exception_nr) { case ARM_EXCEPTION_RESET: cpu->running = 0; fatal("ARM RESET: TODO"); exit(1); case ARM_EXCEPTION_DATA_ABT: retaddr += 4; break; } retaddr += (cpu->cd.arm.cpsr & ARM_FLAG_T ? 2 : 4); arm_save_register_bank(cpu); cpu->cd.arm.cpsr &= 0x0fffffff; cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28); switch (arm_exception_to_mode[exception_nr]) { case ARM_MODE_SVC32: cpu->cd.arm.spsr_svc = cpu->cd.arm.cpsr; break; case ARM_MODE_ABT32: cpu->cd.arm.spsr_abt = cpu->cd.arm.cpsr; break; case ARM_MODE_UND32: cpu->cd.arm.spsr_und = cpu->cd.arm.cpsr; break; case ARM_MODE_IRQ32: cpu->cd.arm.spsr_irq = cpu->cd.arm.cpsr; break; case ARM_MODE_FIQ32: cpu->cd.arm.spsr_fiq = cpu->cd.arm.cpsr; break; default:fatal("arm_exception(): unimplemented exception nr\n"); exit(1); } /* * Disable Thumb mode (because exception handlers always execute * in ARM mode), set the exception mode, and disable interrupts: */ cpu->cd.arm.cpsr &= ~ARM_FLAG_T; oldmode = cpu->cd.arm.cpsr & ARM_FLAG_MODE; cpu->cd.arm.cpsr &= ~ARM_FLAG_MODE; cpu->cd.arm.cpsr |= arm_exception_to_mode[exception_nr]; /* * Usually, an exception should change modes (so that saved status * bits don't get lost). However, Linux on ARM seems to use floating * point instructions in the kernel (!), and it emulates those using * its own fp emulation code. This leads to a situation where we * sometimes change from SVC32 to SVC32. */ newmode = cpu->cd.arm.cpsr & ARM_FLAG_MODE; if (oldmode == newmode && oldmode != ARM_MODE_SVC32) { fatal("[ WARNING! Exception caused no mode change? " "mode 0x%02x (pc=0x%x) ]\n", newmode, (int)cpu->pc); /* exit(1); */ } cpu->cd.arm.cpsr |= ARM_FLAG_I; if (exception_nr == ARM_EXCEPTION_RESET || exception_nr == ARM_EXCEPTION_FIQ) cpu->cd.arm.cpsr |= ARM_FLAG_F; /* Load the new register bank, if we switched: */ arm_load_register_bank(cpu); /* * Set the return address and new PC. * * NOTE: r[ARM_PC] is also set; see cpu_arm_instr_loadstore.c for * details. (If an exception occurs during a load into the pc * register, the code in that file assumes that the r[ARM_PC] * was changed to the address of the exception handler.) */ cpu->cd.arm.r[ARM_LR] = retaddr; cpu->pc = cpu->cd.arm.r[ARM_PC] = exception_nr * 4 + ((cpu->cd.arm.control & ARM_CONTROL_V)? 0xffff0000 : 0); quick_pc_to_pointers(cpu); } /* * arm_cpu_tlbdump(): * * Called from the debugger to dump the TLB in a readable format. * x is the cpu number to dump, or -1 to dump all CPUs. * * If rawflag is nonzero, then the TLB contents isn't formated nicely, * just dumped. */ void arm_cpu_tlbdump(struct machine *m, int x, int rawflag) { } /* * arm_irq_interrupt_assert(): * arm_irq_interrupt_deassert(): */ void arm_irq_interrupt_assert(struct interrupt *interrupt) { struct cpu *cpu = (struct cpu *) interrupt->extra; cpu->cd.arm.irq_asserted = 1; } void arm_irq_interrupt_deassert(struct interrupt *interrupt) { struct cpu *cpu = (struct cpu *) interrupt->extra; cpu->cd.arm.irq_asserted = 0; } /* * arm_cpu_disassemble_instr_thumb(): * * Like arm_cpu_disassemble_instr below, but for THUMB encodings. * Note that the disassbmly uses regular ARM mnemonics, not "THUMB * assembly language". */ int arm_cpu_disassemble_instr_thumb(struct cpu *cpu, unsigned char *ib, int running, uint64_t dumpaddr) { uint16_t iw; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) iw = ib[0] + (ib[1]<<8); else iw = ib[1] + (ib[0]<<8); debug("%04x \t", (int)iw); int main_opcode = (iw >> 12) & 15; int r6 = (iw >> 6) & 7; int rs_rb = (iw >> 3) & 7; int rd = iw & 7; int offset5 = (iw >> 6) & 0x1f; int b_bit = (iw >> 12) & 1; int l_bit = (iw >> 11) & 1; int addsub_op = (iw >> 9) & 1; int addsub_immediate = (iw >> 10) & 1; int op11 = (iw >> 11) & 3; int op10 = (iw >> 10) & 3; int rd8 = (iw >> 8) & 7; int op8 = (iw >> 8) & 3; int h1 = (iw >> 7) & 1; int h2 = (iw >> 6) & 1; int condition_code = (iw >> 8) & 15; const char* condition = arm_condition_string[condition_code]; const char* symbol; uint64_t offset; int tmp; uint32_t tmp32; switch (main_opcode) { case 0x0: case 0x1: if (op11 <= 2) { // Move shifted register. debug("%ss\tr%i,r%i,#%i\n", op11 & 1 ? "lsr" : (op11 & 2 ? "asr" : "lsl"), rd, rs_rb, offset5); } else { // Add/subtract. debug("%s\tr%i,r%i,%s%i\n", addsub_op ? "subs" : "adds", rd, rs_rb, addsub_immediate ? "#" : "r", r6); } break; case 0x2: case 0x3: // Move/compare/add/subtract immediate. rd = (iw >> 8) & 7; if (op11 & 2) { debug("%s\tr%i,r%i,#%i\n", op11 & 1 ? "subs" : "adds", rd, rd, iw & 0xff); } else { debug("%s\tr%i,#%i\n", op11 & 1 ? "cmp" : "movs", rd, iw & 0xff); } break; case 0x4: switch (op10) { case 0: // ALU operations. debug("%s\t%s,%s", arm_thumb_dpiname[(iw >> 6) & 15], arm_regname[rd], arm_regname[rs_rb]); if (running) { debug("\t\t; %s = 0x%x", arm_regname[rd], cpu->cd.arm.r[rd]); debug(", %s = 0x%x", arm_regname[rs_rb], cpu->cd.arm.r[rs_rb]); } debug("\n"); break; case 1: // Hi register operations / branch exchange. if (h1) rd += 8; if (h2) rs_rb += 8; switch (op8) { case 0: case 1: case 2: if (h1 == 0 && h2 == 0) { debug("TODO main_opcode = %i, op10 = %i, h1 AND h2 are zero?!\n", main_opcode, op10); } else { if (op8 == 0) debug("add\tr%i,r%i,r%i\n", rd, rd, rs_rb); else { if (op8 == 2 && rd == rs_rb) debug("nop\n"); // mov rX,rX else { debug("%s\t%s,%s", op8 == 1 ? "cmp" : "mov", arm_regname[rd], arm_regname[rs_rb]); if (running) { debug("\t\t; %s = 0x%x", arm_regname[rd], cpu->cd.arm.r[rd]); debug(", %s = 0x%x", arm_regname[rs_rb], cpu->cd.arm.r[rs_rb]); } debug("\n"); } } } break; case 3: if (h1 == 1) { debug("TODO main_opcode = %i, op10 = %i, h1 set for BX?!\n", main_opcode, op10); } else { debug("bx\t%s\n", arm_regname[rs_rb]); // Extra newline when returning from function. // if (running && rs_rb == ARM_LR) // debug("\n"); } break; } break; case 2: case 3: // PC-relative load. debug("ldr\t%s,[pc,#%i]\t; ", arm_regname[rd8], (iw & 0xff) * 4); // Is this address calculation correct? // It works with real code, but is not the same as that of // http://engold.ui.ac.ir/~nikmehr/Appendix_B2.pdf tmp = (dumpaddr & ~3) + 4 + (iw & 0xff) * 4; debug("0x%x", (int)tmp); symbol = get_symbol_name(&cpu->machine->symbol_context, tmp, &offset); if (symbol != NULL) debug(" <%s>", symbol); debug("\n"); break; } break; case 0x5: // Load/Store with register offset. switch ((iw >> 9) & 7) { case 0: debug("str"); break; case 1: debug("strh"); break; case 2: debug("strb"); break; case 3: debug("ldrsb"); break; case 4: debug("ldr"); break; case 5: debug("ldrh"); break; case 6: debug("ldrb"); break; case 7: debug("ldrsh"); break; } debug("\t%s,[%s,%s]\n", arm_regname[rd], arm_regname[rs_rb], arm_regname[r6]); break; case 0x6: case 0x7: // Load/Store with immediate offset. debug("%s%s\tr%i,[r%i,#%i]\n", l_bit ? "ldr" : "str", b_bit ? "b" : "", rd, rs_rb, offset5 * (b_bit ? sizeof(uint8_t) : sizeof(uint32_t))); break; case 0x8: // Load/Store halfword. debug("%sh\tr%i,[r%i,#%i]\n", l_bit ? "ldr" : "str", rd, rs_rb, offset5 * sizeof(uint16_t)); break; case 0x9: // Load/Store stack pointer relative. debug("%s\t%s,[sp,#%i]\n", l_bit ? "ldr" : "str", arm_regname[rd8], 4 * (iw & 0xff)); break; case 0xa: // add rx, sp or pc plus imm debug("add\t%s,%s,#%i\n", arm_regname[rd8], iw & 0x0800 ? "sp" : "pc", 4 * (iw & 0xff)); break; case 0xb: /* Bits 11..8: */ switch (condition_code) { case 0x0: tmp = (iw & 0x7f) << 2; debug(iw & 0x80 ? "sub" : "add"); debug("\tsp,#%i\n", tmp); break; case 0x4: case 0x5: case 0xc: case 0xd: debug(condition_code & 8 ? "pop" : "push"); debug("\t{"); for (tmp=0; tmp<8; ++tmp) { if (iw & (1 << tmp)) debug("%s,", arm_regname[tmp]); } if (condition_code & 1) { if (condition_code & 8) debug("pc"); else debug("lr"); } debug("}\n"); // Extra newline when returning from function. // if (running && (condition_code & 8) && (condition_code & 1)) // debug("\n"); break; default: debug("TODO: unimplemented opcode 0x%x,0x%x\n", main_opcode, condition_code); } break; case 0xd: if (condition_code < 0xe) { // Conditional branch. debug("b%s\t", condition); tmp = (iw & 0xff) << 1; if (tmp & 0x100) tmp |= 0xfffffe00; tmp = (int32_t)(dumpaddr + 4 + tmp); debug("0x%x", (int)tmp); symbol = get_symbol_name(&cpu->machine->symbol_context, tmp, &offset); if (symbol != NULL) debug(" \t<%s>", symbol); debug("\n"); } else if (condition_code == 0xf) { debug("swi\t#0x%x\n", iw & 0xff); } else { debug("UNIMPLEMENTED\n"); } break; case 0xe: // Unconditional branch. if (iw & 0x0800) { uint32_t addr = (dumpaddr + 4 + (cpu->cd.arm.tmp_branch + (((iw >> 1) & 0x3ff) << 2))) & ~3; debug("blx\t"); if (running) { debug("0x%x", addr); symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug(" \t<%s>", symbol); debug("\n"); } else debug("offset depending on prefix at runtime\n"); } else { tmp = (iw & 0x7ff) << 1; if (tmp & 0x800) tmp |= 0xfffff000; tmp = (int32_t)(dumpaddr + 4 + tmp); debug("b\t0x%x", (int)tmp); symbol = get_symbol_name(&cpu->machine->symbol_context, tmp, &offset); if (symbol != NULL) debug(" \t<%s>", symbol); debug("\n"); } break; case 0xf: if (iw & 0x0800) { uint32_t addr = (dumpaddr + 2 + (cpu->cd.arm.tmp_branch + ((iw & 0x7ff) << 1))); debug("bl\t"); if (running) { debug("0x%x", addr); symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug(" \t<%s>", symbol); debug("\n"); } else debug("offset depending on prefix at runtime\n"); } else { tmp32 = iw & 0x07ff; if (tmp32 & 0x0400) tmp32 |= 0xfffff800; tmp32 <<= 12; debug("bprefix\t0x%x\n", tmp32); } break; default: debug("TODO: unimplemented opcode 0x%x\n", main_opcode); } return sizeof(uint16_t); } /* * arm_cpu_interpret_thumb_SLOW(): * * Slow interpretation of THUMB instructions. * * TODO: Either replace this with dyntrans in the old framework, or * implement ARM (including THUMB) in the new framework. :-) * For now, this is better than nothing. */ int arm_cpu_interpret_thumb_SLOW(struct cpu *cpu) { uint16_t iw; uint8_t ib[sizeof(uint16_t)]; uint32_t addr = cpu->pc & ~1; if (!(cpu->pc & 1) || !(cpu->cd.arm.cpsr & ARM_FLAG_T)) { fatal("arm_cpu_interpret_thumb_SLOW called when not in " "THUMB mode?\n"); cpu->running = 0; return 0; } if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0], sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) { fatal("arm_cpu_interpret_thumb_SLOW(): could not read " "the instruction\n"); cpu->running = 0; return 0; } if (cpu->machine->instruction_trace) { uint64_t offset; char* symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL && offset == 0) debug("<%s>\n", symbol); if (cpu->machine->ncpus > 1) debug("cpu%i:\t", cpu->cpu_id); debug("%08x: ", (int)addr & ~1); arm_cpu_disassemble_instr_thumb(cpu, ib, 1, cpu->pc); } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) iw = ib[0] + (ib[1]<<8); else iw = ib[1] + (ib[0]<<8); cpu->ninstrs ++; int main_opcode = (iw >> 12) & 15; int condition_code = (iw >> 8) & 15; int op10 = (iw >> 10) & 3; int op11_8 = (iw >> 8) & 15; int rd8 = (iw >> 8) & 7; int r6 = (iw >> 6) & 7; int r3 = (iw >> 3) & 7; int rd = (iw >> 0) & 7; int hd = (iw >> 7) & 1; int hm = (iw >> 6) & 1; int imm6 = (iw >> 6) & 31; uint8_t word[sizeof(uint32_t)]; uint32_t tmp; int t, len, isLoad; switch (main_opcode) { case 0x0: if (iw & 0x0800) { // lsr tmp = cpu->cd.arm.r[r3]; if (imm6 > 1) tmp >>= (imm6 - 1); cpu->cd.arm.r[rd] = cpu->cd.arm.r[r3] >> imm6; tmp &= 1; } else { // lsl tmp = cpu->cd.arm.r[r3]; if (imm6 > 1) tmp <<= (imm6 - 1); cpu->cd.arm.r[rd] = cpu->cd.arm.r[r3] << imm6; tmp >>= 31; } cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (cpu->cd.arm.r[rd] == 0) cpu->cd.arm.flags |= ARM_F_Z; if ((int32_t)cpu->cd.arm.r[rd] < 0) cpu->cd.arm.flags |= ARM_F_N; if (imm6 != 0) { // tmp is "last bit shifted out" cpu->cd.arm.flags &= ~ARM_F_C; if (tmp) cpu->cd.arm.flags |= ARM_F_C; } break; case 0x1: if (!(iw & 0x0800)) { // asr tmp = cpu->cd.arm.r[r3]; if (imm6 > 1) tmp = (int32_t)tmp >> (imm6 - 1); cpu->cd.arm.r[rd] = (int32_t)cpu->cd.arm.r[r3] >> imm6; tmp &= 1; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (cpu->cd.arm.r[rd8] == 0) cpu->cd.arm.flags |= ARM_F_Z; if ((int32_t)cpu->cd.arm.r[rd8] < 0) cpu->cd.arm.flags |= ARM_F_N; if (imm6 != 0) { // tmp is "last bit shifted out" cpu->cd.arm.flags &= ~ARM_F_C; if (tmp) cpu->cd.arm.flags |= ARM_F_C; } } else { // add or sub int isSub = iw & 0x0200; int isImm3 = iw & 0x0400; uint64_t old = cpu->cd.arm.r[r3]; uint64_t tmp64 = isImm3 ? r6 : cpu->cd.arm.r[r6]; tmp64 = (uint32_t)(isSub ? -tmp64 : tmp64); uint64_t result = old + tmp64; cpu->cd.arm.r[rd] = result; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N | ARM_F_C | ARM_F_V); if (result == 0) cpu->cd.arm.flags |= ARM_F_Z; if ((int32_t)result < 0) cpu->cd.arm.flags |= ARM_F_N; if (result & 0x100000000ULL) cpu->cd.arm.flags |= ARM_F_C; if (result & 0x80000000) { if ((tmp64 & 0x80000000) == 0 && (old & 0x80000000) == 0) cpu->cd.arm.flags |= ARM_F_V; } else { if ((tmp64 & 0x80000000) != 0 && (old & 0x80000000) != 0) cpu->cd.arm.flags |= ARM_F_V; } } break; case 0x2: // movs or cmp if (iw & 0x0800) { uint64_t old = cpu->cd.arm.r[rd8]; uint64_t tmp64 = (uint32_t)(-(iw & 0xff)); uint64_t result = old + tmp64; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N | ARM_F_C | ARM_F_V); if (result == 0) cpu->cd.arm.flags |= ARM_F_Z; if ((int32_t)result < 0) cpu->cd.arm.flags |= ARM_F_N; if (result & 0x100000000ULL) cpu->cd.arm.flags |= ARM_F_C; if (result & 0x80000000) { if ((tmp64 & 0x80000000) == 0 && (old & 0x80000000) == 0) cpu->cd.arm.flags |= ARM_F_V; } else { if ((tmp64 & 0x80000000) != 0 && (old & 0x80000000) != 0) cpu->cd.arm.flags |= ARM_F_V; } } else { cpu->cd.arm.r[rd8] = iw & 0xff; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (cpu->cd.arm.r[rd8] == 0) cpu->cd.arm.flags |= ARM_F_Z; } break; case 0x3: // adds or sub { uint64_t old = cpu->cd.arm.r[rd8]; uint64_t tmp64 = iw & 0xff; if (iw & 0x0800) tmp64 = (uint32_t)(-tmp64); uint64_t result = old + tmp64; cpu->cd.arm.r[rd8] = result; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N | ARM_F_C | ARM_F_V); if (result == 0) cpu->cd.arm.flags |= ARM_F_Z; if ((int32_t)result < 0) cpu->cd.arm.flags |= ARM_F_N; if (result & 0x100000000ULL) cpu->cd.arm.flags |= ARM_F_C; if (result & 0x80000000) { if ((tmp64 & 0x80000000) == 0 && (old & 0x80000000) == 0) cpu->cd.arm.flags |= ARM_F_V; } else { if ((tmp64 & 0x80000000) != 0 && (old & 0x80000000) != 0) cpu->cd.arm.flags |= ARM_F_V; } } break; case 0x4: switch (op10) { case 0: // "DPIs": switch ((iw >> 6) & 15) { case 0:// ands cpu->cd.arm.r[rd] &= cpu->cd.arm.r[r3]; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (cpu->cd.arm.r[rd] == 0) cpu->cd.arm.flags |= ARM_F_Z; if ((int32_t)cpu->cd.arm.r[rd] < 0) cpu->cd.arm.flags |= ARM_F_N; break; case 1:// eors cpu->cd.arm.r[rd] ^= cpu->cd.arm.r[r3]; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (cpu->cd.arm.r[rd] == 0) cpu->cd.arm.flags |= ARM_F_Z; if ((int32_t)cpu->cd.arm.r[rd] < 0) cpu->cd.arm.flags |= ARM_F_N; break; case 7:// rors { int amount = cpu->cd.arm.r[r3] & 0xff; for (int i = 0; i < (amount & 31); ++i) { int c = cpu->cd.arm.r[rd] & 1; cpu->cd.arm.r[rd] >>= 1; cpu->cd.arm.flags &= ~ARM_F_C; if (c) { cpu->cd.arm.flags |= ARM_F_C; cpu->cd.arm.r[rd] |= 0x80000000; } } // Rotating right by e.g. 32 means that the C flag // should be updated, but the register isn't // really rotated. if (amount != 0 && (amount & 31) == 0) { cpu->cd.arm.flags &= ~ARM_F_C; if (cpu->cd.arm.r[rd] & 0x80000000) cpu->cd.arm.flags |= ARM_F_C; } if (cpu->cd.arm.r[rd] == 0) cpu->cd.arm.flags |= ARM_F_Z; if ((int32_t)cpu->cd.arm.r[rd] < 0) cpu->cd.arm.flags |= ARM_F_N; } break; case 8:// tst tmp = cpu->cd.arm.r[rd] & cpu->cd.arm.r[r3]; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (tmp == 0) cpu->cd.arm.flags |= ARM_F_Z; if ((int32_t)tmp < 0) cpu->cd.arm.flags |= ARM_F_N; break; case 10: // cmp { uint64_t old = cpu->cd.arm.r[rd]; uint64_t tmp64 = (uint32_t) (-cpu->cd.arm.r[r3]); uint64_t result = old + tmp64; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N | ARM_F_C | ARM_F_V); if (result == 0) cpu->cd.arm.flags |= ARM_F_Z; if ((int32_t)result < 0) cpu->cd.arm.flags |= ARM_F_N; if (result & 0x100000000ULL) cpu->cd.arm.flags |= ARM_F_C; if (result & 0x80000000) { if ((tmp64 & 0x80000000) == 0 && (old & 0x80000000) == 0) cpu->cd.arm.flags |= ARM_F_V; } else { if ((tmp64 & 0x80000000) != 0 && (old & 0x80000000) != 0) cpu->cd.arm.flags |= ARM_F_V; } } break; case 12:// orrs cpu->cd.arm.r[rd] |= cpu->cd.arm.r[r3]; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (cpu->cd.arm.r[rd] == 0) cpu->cd.arm.flags |= ARM_F_Z; if ((int32_t)cpu->cd.arm.r[rd] < 0) cpu->cd.arm.flags |= ARM_F_N; break; case 13:// muls cpu->cd.arm.r[rd] *= cpu->cd.arm.r[r3]; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (cpu->cd.arm.r[rd] == 0) cpu->cd.arm.flags |= ARM_F_Z; if ((int32_t)cpu->cd.arm.r[rd] < 0) cpu->cd.arm.flags |= ARM_F_N; break; default: debug("TODO: unimplemented DPI %i at pc 0x%08x\n", (iw >> 6) & 15, (int)cpu->pc); cpu->running = 0; return 0; } break; case 1: switch (op11_8) { case 6: if (hd) rd += 8; if (hm) r3 += 8; cpu->cd.arm.r[rd] = cpu->cd.arm.r[r3]; if (r3 == ARM_PC) { if (cpu->pc & 1) { debug("TODO: double check with manual whether it is correct to use old pc + 8 here; at pc 0x%08x\n", (int)cpu->pc); cpu->running = 0; return 0; } cpu->cd.arm.r[rd] = cpu->pc + 8; } if (rd == ARM_PC) { cpu->pc = cpu->cd.arm.r[rd]; cpu->cd.arm.cpsr |= ARM_FLAG_T; if (!(cpu->pc & 1)) cpu->cd.arm.cpsr &= ~ARM_FLAG_T; cpu->pc = addr - sizeof(uint16_t); } break; case 7: if ((iw & 0xff87) == 0x4700) { // bx int rm = (iw >> 3) & 15; // Note: pc will be increased by 2 further down! cpu->pc = cpu->cd.arm.r[rm] - sizeof(uint16_t); if (!(cpu->pc & 1)) cpu->cd.arm.cpsr &= ~ARM_FLAG_T; if (rm == ARM_LR && cpu->machine->show_trace_tree) cpu_functioncall_trace_return(cpu); } else { debug("TODO: unimplemented opcode 0x%x,%i at pc 0x%08x\n", main_opcode, op11_8, (int)cpu->pc); cpu->running = 0; return 0; } break; default: debug("TODO: unimplemented opcode 0x%x,%i at pc 0x%08x\n", main_opcode, op11_8, (int)cpu->pc); cpu->running = 0; return 0; } break; case 2: case 3: // PC-relative load. // Is this address calculation correct? // It works with real code, but is not the same as that of // http://engold.ui.ac.ir/~nikmehr/Appendix_B2.pdf tmp = (addr & ~3) + 4 + (iw & 0xff) * 4; if (!cpu->memory_rw(cpu, cpu->mem, tmp, &word[0], sizeof(word), MEM_READ, CACHE_INSTRUCTION)) { fatal("arm_cpu_interpret_thumb_SLOW(): could not load pc-relative word\n"); cpu->running = 0; return 0; } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) tmp = word[0] + (word[1]<<8) + (word[2]<<16) + (word[3]<<24); else tmp = word[3] + (word[2]<<8) + (word[1]<<16) + (word[0]<<24); cpu->cd.arm.r[rd8] = tmp; break; default: debug("TODO: unimplemented opcode 0x%x,%i at pc 0x%08x\n", main_opcode, op10, (int)cpu->pc); cpu->running = 0; return 0; } break; case 0x6: case 0x7: case 0x8: // Load/Store with immediate offset. len = main_opcode == 6 ? 4 : (main_opcode == 7 ? 1 : 2); isLoad = iw & 0x0800; addr = (cpu->cd.arm.r[r3] + imm6 * len) & ~(len - 1); tmp = 0; if (!isLoad) { tmp = cpu->cd.arm.r[rd]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { for (int i = 0; i < len; ++i) word[i] = (tmp >> (8*i)); } else { for (int i = 0; i < len; ++i) word[len - 1 - i] = (tmp >> (8*i)); } } if (!cpu->memory_rw(cpu, cpu->mem, addr, &word[0], len, isLoad ? MEM_READ : MEM_WRITE, CACHE_DATA)) { fatal("arm_cpu_interpret_thumb_SLOW(): could not load with immediate offset\n"); cpu->running = 0; return 0; } if (isLoad) { tmp = 0; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { for (int i = 0; i < len; ++i) { tmp <<= 8; tmp |= word[len - 1 - i]; } } else { for (int i = 0; i < len; ++i) { tmp <<= 8; tmp |= word[i]; } } cpu->cd.arm.r[rd] = tmp; } break; case 0x9: // sp-relative load or store if (iw & 0x0800) { addr = (cpu->cd.arm.r[ARM_SP] + (iw & 0xff) * 4) & ~3; if (!cpu->memory_rw(cpu, cpu->mem, addr, &word[0], sizeof(word), MEM_READ, CACHE_DATA)) { fatal("arm_cpu_interpret_thumb_SLOW(): could not load sp-relative word\n"); cpu->running = 0; return 0; } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) tmp = word[0] + (word[1]<<8) + (word[2]<<16) + (word[3]<<24); else tmp = word[3] + (word[2]<<8) + (word[1]<<16) + (word[0]<<24); cpu->cd.arm.r[rd8] = tmp; } else { tmp = cpu->cd.arm.r[rd8]; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { for (size_t i = 0; i < sizeof(word); ++i) word[i] = (tmp >> (8*i)); } else { for (size_t i = 0; i < sizeof(word); ++i) word[sizeof(word) - 1 - i] = (tmp >> (8*i)); } addr = (cpu->cd.arm.r[ARM_SP] + (iw & 0xff) * 4) & ~3; if (!cpu->memory_rw(cpu, cpu->mem, addr, &word[0], sizeof(word), MEM_WRITE, CACHE_DATA)) { fatal("arm_cpu_interpret_thumb_SLOW(): could not store sp-relative word\n"); cpu->running = 0; return 0; } } break; case 0xb: switch (op11_8) { case 0: if (iw & 0x0080) cpu->cd.arm.r[ARM_SP] -= ((iw & 0x7f) << 2); else cpu->cd.arm.r[ARM_SP] += ((iw & 0x7f) << 2); break; case 4: case 5: /* push, i.e. stmdb sp!, reglist */ arm_push(cpu, &cpu->cd.arm.r[ARM_SP], 1, 0, 0, 1, (iw & 0xff) | (iw & 0x100 ? (1 << ARM_LR) : 0)); break; case 12: case 13: /* pop, i.e. ldmia sp!, reglist */ cpu->cd.arm.r[ARM_PC] = cpu->pc; arm_pop(cpu, &cpu->cd.arm.r[ARM_SP], 0, 1, 0, 1, (iw & 0xff) | (iw & 0x100 ? (1 << ARM_PC) : 0)); cpu->pc = cpu->cd.arm.r[ARM_PC]; if (cpu->pc & 1) cpu->cd.arm.cpsr |= ARM_FLAG_T; else cpu->cd.arm.cpsr &= ~ARM_FLAG_T; // If not popping pc, make sure to move to the next instruction: if (!(iw & 0x100)) cpu->pc += sizeof(uint16_t); return 1; default: debug("TODO: unimplemented opcode 0x%x,%i at pc 0x%08x\n", main_opcode, op11_8, (int)cpu->pc); cpu->running = 0; return 0; } break; case 0xd: if (condition_code < 0xe) { // Conditional branch. tmp = (iw & 0xff) << 1; if (tmp & 0x100) tmp |= 0xfffffe00; tmp = (int32_t)(cpu->pc + 4 + tmp); switch (condition_code) { case 0x0: // eq: t = cpu->cd.arm.flags & ARM_F_Z; break; case 0x1: // ne: t = !(cpu->cd.arm.flags & ARM_F_Z); break; case 0x2: // cs: t = cpu->cd.arm.flags & ARM_F_C; break; case 0x3: // cc: t = !(cpu->cd.arm.flags & ARM_F_C); break; case 0x4: // mi: t = cpu->cd.arm.flags & ARM_F_N; break; case 0x5: // pl: t = !(cpu->cd.arm.flags & ARM_F_N); break; case 0x6: // vs: t = cpu->cd.arm.flags & ARM_F_V; break; case 0x7: // vc: t = !(cpu->cd.arm.flags & ARM_F_V); break; case 0x8: // hi: t = condition_hi[cpu->cd.arm.flags]; break; case 0x9: // ls: t = !condition_hi[cpu->cd.arm.flags]; break; case 0xa: // ge: t = condition_ge[cpu->cd.arm.flags]; break; case 0xb: // lt: t = !condition_ge[cpu->cd.arm.flags]; break; case 0xc: // gt: t = condition_gt[cpu->cd.arm.flags]; break; case 0xd: // le: t = !condition_gt[cpu->cd.arm.flags]; break; } if (t) { cpu->pc = tmp; return 1; } } else if (condition_code == 0xf) { arm_exception(cpu, ARM_EXCEPTION_SWI); return 1; } else { debug("TODO: unimplemented opcode 0x%x, non-branch, at pc 0x%08x\n", main_opcode, (int)cpu->pc); cpu->running = 0; return 0; } break; case 0xe: if (iw & 0x0800) { // blx addr = (cpu->pc + 4 + (cpu->cd.arm.tmp_branch + (((iw >> 1) & 0x3ff) << 2))) & ~3; if (iw & 1) { fatal("lowest bit set in thumb blx instruction?\n"); cpu->running = 0; return 0; } cpu->cd.arm.r[ARM_LR] = cpu->pc + 2; cpu->pc = addr; if (cpu->machine->show_trace_tree) cpu_functioncall_trace(cpu, cpu->pc); cpu->cd.arm.cpsr &= ~ARM_FLAG_T; return 1; } else { // b tmp = (iw & 0x7ff) << 1; if (tmp & 0x800) tmp |= 0xfffff000; cpu->pc = (int32_t)(cpu->pc + 4 + tmp); return 1; } break; case 0xf: if (iw & 0x0800) { // bl addr = (cpu->pc + 2 + (cpu->cd.arm.tmp_branch + ((iw & 0x7ff) << 1))); cpu->cd.arm.r[ARM_LR] = cpu->pc + 2; cpu->pc = addr; if (cpu->machine->show_trace_tree) cpu_functioncall_trace(cpu, cpu->pc); return 1; } else { // "branch prefix". uint32_t tmp32 = iw & 0x07ff; if (tmp32 & 0x0400) tmp32 |= 0xfffff800; tmp32 <<= 12; cpu->cd.arm.tmp_branch = tmp32; } break; default: debug("TODO: unimplemented opcode 0x%x at pc 0x%08x\n", main_opcode, (int)cpu->pc); cpu->running = 0; return 0; } cpu->pc += sizeof(uint16_t); return 1; } /* * arm_cpu_disassemble_instr(): * * Convert an instruction word into human readable format, for instruction * tracing. * * If running is 1, cpu->pc should be the address of the instruction. * * If running is 0, things that depend on the runtime environment (eg. * register contents) will not be shown, and addr will be used instead of * cpu->pc for relative addresses. */ int arm_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib, int running, uint64_t dumpaddr) { uint32_t iw, tmp; int main_opcode, secondary_opcode, s_bit, r16, r12, r8; int i, n, p_bit, u_bit, b_bit, w_bit, l_bit; const char *symbol, *condition; uint64_t offset; if (running) dumpaddr = cpu->pc; symbol = get_symbol_name(&cpu->machine->symbol_context, dumpaddr, &offset); if (symbol != NULL && offset == 0) debug("<%s>\n", symbol); if (cpu->machine->ncpus > 1 && running) debug("cpu%i:\t", cpu->cpu_id); debug("%08x: ", (int)dumpaddr & ~1); if (dumpaddr & 1) return arm_cpu_disassemble_instr_thumb(cpu, ib, running, dumpaddr); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) iw = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24); else iw = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24); debug("%08x\t", (int)iw); condition = arm_condition_string[iw >> 28]; main_opcode = (iw >> 24) & 15; secondary_opcode = (iw >> 21) & 15; u_bit = (iw >> 23) & 1; b_bit = (iw >> 22) & 1; w_bit = (iw >> 21) & 1; s_bit = l_bit = (iw >> 20) & 1; r16 = (iw >> 16) & 15; r12 = (iw >> 12) & 15; r8 = (iw >> 8) & 15; if ((iw >> 28) == 0xf) { switch (main_opcode) { case 0xa: case 0xb: tmp = (iw & 0xffffff); if (tmp & 0x800000) tmp |= 0xff000000; tmp = (int32_t)(dumpaddr + 8 + 4*tmp + (main_opcode == 0xb? 2 : 0)) + 1; debug("blx\t0x%x", (int)tmp); symbol = get_symbol_name(&cpu->machine->symbol_context, tmp, &offset); if (symbol != NULL) debug(" \t<%s>", symbol); debug("\n"); break; default:debug("UNIMPLEMENTED\n"); } return sizeof(uint32_t); } switch (main_opcode) { case 0x0: case 0x1: case 0x2: case 0x3: /* * Special cases first: */ /* * Multiplication: * xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd, Rm, Rs [,Rn]) */ if ((iw & 0x0fc000f0) == 0x00000090) { int a_bit = (iw >> 21) & 1; debug("%s%s%s\t", a_bit? "mla" : "mul", condition, s_bit? "s" : ""); debug("%s,", arm_regname[r16]); debug("%s,", arm_regname[iw & 15]); debug("%s", arm_regname[r8]); if (a_bit) debug(",%s", arm_regname[r12]); debug("\n"); break; } /* * Long multiplication: * xxxx0000 1UAShhhh llllssss 1001mmmm (Rl,Rh,Rm,Rs) */ if ((iw & 0x0f8000f0) == 0x00800090) { int a_bit = (iw >> 21) & 1; u_bit = (iw >> 22) & 1; debug("%s%sl%s%s\t", u_bit? "s" : "u", a_bit? "mla" : "mul", condition, s_bit? "s" : ""); debug("%s,%s,", arm_regname[r12], arm_regname[r16]); debug("%s,%s\n", arm_regname[iw&15], arm_regname[r8]); break; } /* * xxxx0001 0000nnnn dddd0000 0101mmmm qadd Rd,Rm,Rn * xxxx0001 0010nnnn dddd0000 0101mmmm qsub Rd,Rm,Rn * xxxx0001 0100nnnn dddd0000 0101mmmm qdadd Rd,Rm,Rn * xxxx0001 0110nnnn dddd0000 0101mmmm qdsub Rd,Rm,Rn */ if ((iw & 0x0f900ff0) == 0x01000050) { debug("q%s%s%s\t", iw & 0x400000? "d" : "", iw & 0x200000? "sub" : "add", condition); debug("%s,%s,%s\n", arm_regname[r12], arm_regname[iw&15], arm_regname[r16]); break; } /* * xxxx0001 0010.... ........ 00L1mmmm bx/blx rm */ if ((iw & 0x0ff000d0) == 0x01200010) { l_bit = iw & 0x20; debug("b%sx%s\t%s\n", l_bit? "l" : "", condition, arm_regname[iw & 15]); break; } /* * xxxx0001 0s10aaaa 11110000 0000mmmm MSR Regform * xxxx0011 0s10aaaa 1111rrrr bbbbbbbb MSR Immform * xxxx0001 0s001111 dddd0000 00000000 MRS */ if ((iw & 0x0fb0fff0) == 0x0120f000 || (iw & 0x0fb0f000) == 0x0320f000) { debug("msr%s\t%s", condition, (iw&0x400000)? "S":"C"); debug("PSR_"); if (iw & (1<<19)) debug("f"); if (iw & (1<<18)) debug("s"); if (iw & (1<<17)) debug("x"); if (iw & (1<<16)) debug("c"); if (iw & 0x02000000) { int r = (iw >> 7) & 30; uint32_t b = iw & 0xff; while (r-- > 0) b = (b >> 1) | ((b & 1) << 31); debug(",#0x%x\n", b); } else debug(",%s\n", arm_regname[iw & 15]); break; } if ((iw & 0x0fbf0fff) == 0x010f0000) { debug("mrs%s\t", condition); debug("%s,%sPSR\n", arm_regname[r12], (iw&0x400000)? "S":"C"); break; } /* * xxxx0001 0B00nnnn dddd0000 1001mmmm SWP Rd,Rm,[Rn] */ if ((iw & 0x0fb00ff0) == 0x01000090) { debug("swp%s%s\t", condition, (iw&0x400000)? "b":""); debug("%s,%s,[%s]\n", arm_regname[r12], arm_regname[iw & 15], arm_regname[r16]); break; } /* * xxxx0001 0010iiii iiiiiiii 0111iiii BKPT immed16 */ if ((iw & 0x0ff000f0) == 0x01200070) { debug("bkpt%s\t0x%04x\n", condition, ((iw & 0x000fff00) >> 4) + (iw & 0xf)); break; } /* * xxxx0001 01101111 dddd1111 0001mmmm CLZ Rd,Rm */ if ((iw & 0x0fff0ff0) == 0x016f0f10) { debug("clz%s\t", condition); debug("%s,%s\n", arm_regname[r12], arm_regname[iw&15]); break; } /* * xxxx0001 0000dddd nnnnssss 1yx0mmmm SMLAxy Rd,Rm,Rs,Rn * xxxx0001 0100dddd DDDDssss 1yx0mmmm SMLALxy RdL,RdH,Rm,Rs * xxxx0001 0010dddd nnnnssss 1y00mmmm SMLAWy Rd,Rm,Rs,Rn * xxxx0001 0110dddd 0000ssss 1yx0mmmm SMULxy Rd,Rm,Rs * xxxx0001 0010dddd 0000ssss 1y10mmmm SMULWy Rd,Rm,Rs */ if ((iw & 0x0ff00090) == 0x01000080) { debug("smla%s%s%s\t", iw & 0x20? "t" : "b", iw & 0x40? "t" : "b", condition); debug("%s,%s,%s,%s\n", arm_regname[r16], arm_regname[iw&15], arm_regname[r8], arm_regname[r12]); break; } if ((iw & 0x0ff00090) == 0x01400080) { debug("smlal%s%s%s\t", iw & 0x20? "t" : "b", iw & 0x40? "t" : "b", condition); debug("%s,%s,%s,%s\n", arm_regname[r12], arm_regname[r16], arm_regname[iw&15], arm_regname[r8]); break; } if ((iw & 0x0ff000b0) == 0x01200080) { debug("smlaw%s%s\t", iw & 0x40? "t" : "b", condition); debug("%s,%s,%s,%s\n", arm_regname[r16], arm_regname[iw&15], arm_regname[r8], arm_regname[r12]); break; } if ((iw & 0x0ff0f090) == 0x01600080) { debug("smul%s%s%s\t", iw & 0x20? "t" : "b", iw & 0x40? "t" : "b", condition); debug("%s,%s,%s\n", arm_regname[r16], arm_regname[iw&15], arm_regname[r8]); break; } if ((iw & 0x0ff0f0b0) == 0x012000a0) { debug("smulw%s%s\t", iw & 0x40? "t" : "b", condition); debug("%s,%s,%s\n", arm_regname[r16], arm_regname[iw&15], arm_regname[r8]); break; } /* * xxxx000P U1WLnnnn ddddHHHH 1SH1LLLL load/store rd,imm(rn) */ if ((iw & 0x0e000090) == 0x00000090) { const char *op = "st"; int imm = ((iw >> 4) & 0xf0) | (iw & 0xf); int regform = !(iw & 0x00400000); p_bit = main_opcode & 1; /* * TODO: detect some illegal variants: * signed store, or unsigned byte load/store */ if (!l_bit && (iw & 0xd0) == 0xd0 && (r12 & 1)) { debug("TODO: r12 odd, not load/store\n"); break; } /* Semi-generic case: */ if (iw & 0x00100000) op = "ld"; if (!l_bit && (iw & 0xd0) == 0xd0) { if (iw & 0x20) op = "st"; else op = "ld"; } debug("%sr%s", op, condition); if (!l_bit && (iw & 0xd0) == 0xd0) { debug("d"); /* Double-register */ } else { if (iw & 0x40) debug("s"); /* signed */ if (iw & 0x20) debug("h"); /* half-word */ else debug("b"); /* byte */ } debug("\t%s,[%s", arm_regname[r12], arm_regname[r16]); if (p_bit) { /* Pre-index: */ if (regform) debug(",%s%s", u_bit? "" : "-", arm_regname[iw & 15]); else { if (imm != 0) debug(",#%s%i", u_bit? "" : "-", imm); } debug("]%s\n", w_bit? "!" : ""); } else { /* Post-index: */ debug("],"); if (regform) debug("%s%s\n", u_bit? "" : "-", arm_regname[iw & 15]); else debug("#%s%i\n", u_bit? "" : "-", imm); } break; } /* Other special cases: */ if (iw & 0x80 && !(main_opcode & 2) && iw & 0x10) { debug("UNIMPLEMENTED reg (c!=0), t odd\n"); break; } /* * Generic Data Processing Instructions: * * xxxx000a aaaSnnnn ddddcccc ctttmmmm Register form * xxxx001a aaaSnnnn ddddrrrr bbbbbbbb Immediate form */ debug("%s%s%s\t", arm_dpiname[secondary_opcode], condition, s_bit? "s" : ""); if (arm_dpi_uses_d[secondary_opcode]) debug("%s,", arm_regname[r12]); if (arm_dpi_uses_n[secondary_opcode]) debug("%s,", arm_regname[r16]); if (main_opcode & 2) { /* Immediate form: */ int r = (iw >> 7) & 30; uint32_t b = iw & 0xff; while (r-- > 0) b = (b >> 1) | ((b & 1) << 31); if (b < 15) debug("#%i", b); else debug("#0x%x", b); } else { /* Register form: */ int t = (iw >> 4) & 7; int c = (iw >> 7) & 31; debug("%s", arm_regname[iw & 15]); switch (t) { case 0: if (c != 0) debug(", lsl #%i", c); break; case 1: debug(", lsl %s", arm_regname[c >> 1]); break; case 2: debug(", lsr #%i", c? c : 32); break; case 3: debug(", lsr %s", arm_regname[c >> 1]); break; case 4: debug(", asr #%i", c? c : 32); break; case 5: debug(", asr %s", arm_regname[c >> 1]); break; case 6: if (c != 0) debug(", ror #%i", c); else debug(", rrx"); break; case 7: debug(", ror %s", arm_regname[c >> 1]); break; } /* mov pc,reg: */ if (running && t == 0 && c == 0 && secondary_opcode == 0xd && r12 == ARM_PC && (iw&15)!=ARM_PC) { symbol = get_symbol_name(&cpu->machine-> symbol_context, cpu->cd.arm.r[iw & 15], &offset); if (symbol != NULL) debug(" \t<%s>", symbol); } } debug("\n"); break; case 0x4: /* Single Data Transfer */ case 0x5: case 0x6: case 0x7: /* Special case first: */ if ((iw & 0xfc70f000) == 0xf450f000) { /* Preload: */ debug("pld\t[%s]\n", arm_regname[r16]); break; } /* * xxxx010P UBWLnnnn ddddoooo oooooooo Immediate form * xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register form */ p_bit = main_opcode & 1; if (main_opcode >= 6 && iw & 0x10) { debug("TODO: single data transf. but 0x10\n"); break; } debug("%s%s%s", l_bit? "ldr" : "str", condition, b_bit? "b" : ""); if (!p_bit && w_bit) debug("t"); debug("\t%s,[%s", arm_regname[r12], arm_regname[r16]); if ((iw & 0x0e000000) == 0x04000000) { /* Immediate form: */ uint32_t imm = iw & 0xfff; if (!p_bit) debug("]"); if (imm != 0) debug(",#%s%i", u_bit? "" : "-", imm); if (p_bit) debug("]"); } else if ((iw & 0x0e000010) == 0x06000000) { /* Register form: */ if (!p_bit) debug("]"); if ((iw & 0xfff) != 0) debug(",%s%s", u_bit? "" : "-", arm_regname[iw & 15]); if ((iw & 0xff0) != 0x000) { int c = (iw >> 7) & 31; int t = (iw >> 4) & 7; switch (t) { case 0: if (c != 0) debug(", lsl #%i", c); break; case 2: debug(", lsr #%i", c? c : 32); break; case 4: debug(", asr #%i", c? c : 32); break; case 6: if (c != 0) debug(", ror #%i", c); else debug(", rrx"); break; } } if (p_bit) debug("]"); } else { debug("UNKNOWN\n"); break; } debug("%s", (p_bit && w_bit)? "!" : ""); if ((iw & 0x0f000000) == 0x05000000 && (r16 == ARM_PC || running)) { unsigned char tmpw[4]; uint32_t imm = iw & 0xfff; uint32_t addr = (u_bit? imm : -imm); if (r16 == ARM_PC) addr += dumpaddr + 8; else addr += cpu->cd.arm.r[r16]; symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL) debug(" \t<%s", symbol); else debug(" \t<0x%08x", addr); if ((l_bit && cpu->memory_rw(cpu, cpu->mem, addr, tmpw, b_bit? 1 : sizeof(tmpw), MEM_READ, NO_EXCEPTIONS)) || (!l_bit && running)) { if (l_bit) { if (cpu->byte_order == EMUL_LITTLE_ENDIAN) addr = tmpw[0] +(tmpw[1] << 8) + (tmpw[2]<<16)+(tmpw[3]<<24); else addr = tmpw[3] + (tmpw[2]<<8) + (tmpw[1]<<16)+(tmpw[0]<<24); } else { tmpw[0] = addr = cpu->cd.arm.r[r12]; if (r12 == ARM_PC) addr = cpu->pc + 8; } debug(": "); if (b_bit) debug("%i", tmpw[0]); else { symbol = get_symbol_name(&cpu->machine-> symbol_context, addr, &offset); if (symbol != NULL) debug("%s", symbol); else if ((int32_t)addr > -256 && (int32_t)addr < 256) debug("%i", addr); else debug("0x%x", addr); } } debug(">"); } debug("\n"); break; case 0x8: /* Block Data Transfer */ case 0x9: /* xxxx100P USWLnnnn llllllll llllllll */ p_bit = main_opcode & 1; s_bit = b_bit; debug("%s%s", l_bit? "ldm" : "stm", condition); switch (u_bit * 2 + p_bit) { case 0: debug("da"); break; case 1: debug("db"); break; case 2: debug("ia"); break; case 3: debug("ib"); break; } debug("\t%s", arm_regname[r16]); if (w_bit) debug("!"); debug(",{"); n = 0; for (i=0; i<16; i++) if ((iw >> i) & 1) { debug("%s%s", (n > 0)? ",":"", arm_regname[i]); n++; } debug("}"); if (s_bit) debug("^"); debug("\n"); break; case 0xa: /* B: branch */ case 0xb: /* BL: branch and link */ debug("b%s%s\t", main_opcode == 0xa? "" : "l", condition); tmp = (iw & 0x00ffffff) << 2; if (tmp & 0x02000000) tmp |= 0xfc000000; tmp = (int32_t)(dumpaddr + tmp + 8); debug("0x%x", (int)tmp); symbol = get_symbol_name(&cpu->machine->symbol_context, tmp, &offset); if (symbol != NULL) debug(" \t<%s>", symbol); debug("\n"); break; case 0xc: /* Coprocessor */ case 0xd: /* LDC/STC */ /* * xxxx1100 0100nnnn ddddcccc oooommmm MCRR c,op,Rd,Rn,CRm * xxxx1100 0101nnnn ddddcccc oooommmm MRRC c,op,Rd,Rn,CRm */ if ((iw & 0x0fe00fff) == 0x0c400000) { debug("%s%s\t", iw & 0x100000? "mra" : "mar", condition); if (iw & 0x100000) debug("%s,%s,acc0\n", arm_regname[r12], arm_regname[r16]); else debug("acc0,%s,%s\n", arm_regname[r12], arm_regname[r16]); break; } if ((iw & 0x0fe00000) == 0x0c400000) { debug("%s%s\t", iw & 0x100000? "mrrc" : "mcrr", condition); debug("%i,%i,%s,%s,cr%i\n", r8, (iw >> 4) & 15, arm_regname[r12], arm_regname[r16], iw & 15); break; } /* xxxx110P UNWLnnnn DDDDpppp oooooooo LDC/STC */ debug("TODO: coprocessor LDC/STC\n"); break; case 0xe: /* CDP (Coprocessor Op) */ /* or MRC/MCR! * xxxx1110 oooonnnn ddddpppp qqq0mmmm CDP * xxxx1110 oooLNNNN ddddpppp qqq1MMMM MRC/MCR */ if ((iw & 0x0ff00ff0) == 0x0e200010) { /* Special case: mia* DSP instructions */ switch ((iw >> 16) & 0xf) { case 0: debug("mia"); break; case 8: debug("miaph"); break; case 12: debug("miaBB"); break; case 13: debug("miaTB"); break; case 14: debug("miaBT"); break; case 15: debug("miaTT"); break; default: debug("UNKNOWN mia vector instruction?"); } debug("%s\t", condition); debug("acc%i,%s,%s\n", ((iw >> 5) & 7), arm_regname[iw & 15], arm_regname[r12]); break; } if (iw & 0x10) { debug("%s%s\t", (iw & 0x00100000)? "mrc" : "mcr", condition); debug("%i,%i,r%i,cr%i,cr%i,%i", (int)((iw >> 8) & 15), (int)((iw >>21) & 7), (int)((iw >>12) & 15), (int)((iw >>16) & 15), (int)((iw >> 0) & 15), (int)((iw >> 5) & 7)); } else { debug("cdp%s\t", condition); debug("%i,%i,cr%i,cr%i,cr%i", (int)((iw >> 8) & 15), (int)((iw >>20) & 15), (int)((iw >>12) & 15), (int)((iw >>16) & 15), (int)((iw >> 0) & 15)); if ((iw >> 5) & 7) debug(",0x%x", (int)((iw >> 5) & 7)); } debug("\n"); break; case 0xf: /* SWI */ debug("swi%s\t", condition); debug("0x%x\n", (int)(iw & 0x00ffffff)); break; default:debug("UNIMPLEMENTED\n"); } return sizeof(uint32_t); } /*****************************************************************************/ /* * arm_mcr_mrc(): * * Coprocessor register move. * * The program counter should be synched before calling this function (to * make debug output with the correct PC value possible). */ void arm_mcr_mrc(struct cpu *cpu, uint32_t iword) { int opcode1 = (iword >> 21) & 7; int l_bit = (iword >> 20) & 1; int crn = (iword >> 16) & 15; int rd = (iword >> 12) & 15; int cp_num = (iword >> 8) & 15; int opcode2 = (iword >> 5) & 7; int crm = iword & 15; if (cpu->cd.arm.coproc[cp_num] != NULL) cpu->cd.arm.coproc[cp_num](cpu, opcode1, opcode2, l_bit, crn, crm, rd); else { fatal("[ arm_mcr_mrc: pc=0x%08x, iword=0x%08x: " "cp_num=%i ]\n", (int)cpu->pc, iword, cp_num); arm_exception(cpu, ARM_EXCEPTION_UND); /* exit(1); */ } } /* * arm_cdp(): * * Coprocessor operations. * * The program counter should be synched before calling this function (to * make debug output with the correct PC value possible). */ void arm_cdp(struct cpu *cpu, uint32_t iword) { fatal("[ arm_cdp: pc=0x%08x, iword=0x%08x ]\n", (int)cpu->pc, iword); arm_exception(cpu, ARM_EXCEPTION_UND); /* exit(1); */ } /*****************************************************************************/ #include "tmp_arm_tail.cc" gxemul-0.6.1/src/cpus/cpu_dyntrans.cc000644 001750 001750 00000152441 13402411502 020015 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Common dyntrans routines. Included from cpu_*.c. * * Note: This might be a bit hard to follow, if you are reading this source * code for the first time. It is basically a hack to implement "templates" * with normal C code, by using suitable defines/macros, and then including * this file. */ #ifndef STATIC_STUFF #define STATIC_STUFF /* * gather_statistics(): */ static void gather_statistics(struct cpu *cpu) { char ch, buf[60]; struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic; int i = 0; uint64_t a; int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t) cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC); if (cpu->machine->statistics.file == NULL) { fatal("statistics gathering with no filename set is" " meaningless\n"); return; } /* low_pc must be within the page! */ if (low_pc < 0 || low_pc > DYNTRANS_IC_ENTRIES_PER_PAGE) return; buf[0] = '\0'; while ((ch = cpu->machine->statistics.fields[i]) != '\0') { if (i != 0) strlcat(buf, " ", sizeof(buf)); switch (ch) { case 'i': snprintf(buf + strlen(buf), sizeof(buf), "%p", (void *)ic->f); break; case 'p': /* Physical program counter address: */ cpu->cd.DYNTRANS_ARCH.cur_physpage = (struct DYNTRANS_TC_PHYSPAGE *) cpu->cd.DYNTRANS_ARCH.cur_ic_page; a = cpu->cd.DYNTRANS_ARCH.cur_physpage->physaddr; a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << DYNTRANS_INSTR_ALIGNMENT_SHIFT); a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT; if (cpu->is_32bit) snprintf(buf + strlen(buf), sizeof(buf), "0x%08" PRIx32, (uint32_t)a); else snprintf(buf + strlen(buf), sizeof(buf), "0x%016" PRIx64, (uint64_t)a); break; case 'v': /* Virtual program counter address: */ a = cpu->pc; a &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << DYNTRANS_INSTR_ALIGNMENT_SHIFT); a += low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT; if (cpu->is_32bit) snprintf(buf + strlen(buf), sizeof(buf), "0x%08" PRIx32, (uint32_t)a); else snprintf(buf + strlen(buf), sizeof(buf), "0x%016" PRIx64, (uint64_t)a); break; } i++; } fprintf(cpu->machine->statistics.file, "%s\n", buf); } #define S gather_statistics(cpu) #if 1 /* The normal instruction execution core: */ #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic); #else /* For heavy debugging: */ #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; \ { \ int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - \ (size_t)cpu->cd.DYNTRANS_ARCH.cur_ic_page) / \ sizeof(struct DYNTRANS_IC); \ printf("cur_ic_page=%p ic=%p (low_pc=0x%x)\n", \ cpu->cd.DYNTRANS_ARCH.cur_ic_page, \ ic, low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT); \ } \ ic->f(cpu, ic); #endif /* static long long nr_of_I_calls = 0; */ /* Temporary hack for finding NULL bugs: */ /* #define I ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; \ nr_of_I_calls ++; \ if (ic->f == NULL) { \ int low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - \ (size_t)cpu->cd.DYNTRANS_ARCH.cur_ic_page) / \ sizeof(struct DYNTRANS_IC); \ cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << \ DYNTRANS_INSTR_ALIGNMENT_SHIFT); \ cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT);\ printf("Crash at %016" PRIx64"\n", cpu->pc); \ printf("nr of I calls: %lli\n", nr_of_I_calls); \ printf("Next ic = %p\n", cpu->cd. \ DYNTRANS_ARCH.next_ic); \ printf("cur ic page = %p\n", cpu->cd. \ DYNTRANS_ARCH.cur_ic_page); \ cpu->running = 0; \ return 0; \ } \ ic->f(cpu, ic); */ /* Temporary hack for MIPS, to hunt for 32-bit/64-bit sign-extension bugs: */ /* #define I { int k; for (k=1; k<=31; k++) \ cpu->cd.mips.gpr[k] = (int32_t)cpu->cd.mips.gpr[k];\ if (cpu->cd.mips.gpr[0] != 0) { \ fatal("NOOOOOO\n"); exit(1); \ } \ ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic); } */ #endif /* STATIC STUFF */ #ifdef DYNTRANS_RUN_INSTR_DEF /* * XXX_run_instr(): * * Execute one or more instructions on a specific CPU, using dyntrans. * (For dualmode archs, this function is included twice.) * * Return value is the number of instructions executed during this call, * 0 if no instructions were executed. */ int DYNTRANS_RUN_INSTR_DEF(struct cpu *cpu) { MODE_uint_t cached_pc; int low_pc, n_instrs; /* Ugly... fix this some day. */ #ifdef DYNTRANS_DUALMODE_32 #ifdef MODE32 DYNTRANS_PC_TO_POINTERS32(cpu); #else DYNTRANS_PC_TO_POINTERS(cpu); #endif #else DYNTRANS_PC_TO_POINTERS(cpu); #endif /* * Interrupt assertion? (This is _below_ the initial PC to pointer * conversion; if the conversion caused an exception of some kind * then interrupts are probably disabled, and the exception will get * priority over device interrupts.) * * TODO: Turn this into a family-specific function somewhere... */ /* Note: Do not cause interrupts while single-stepping. It is so horribly annoying. */ if (!single_step) { #ifdef DYNTRANS_ARM if (cpu->cd.arm.irq_asserted && !(cpu->cd.arm.cpsr & ARM_FLAG_I)) arm_exception(cpu, ARM_EXCEPTION_IRQ); #endif #ifdef DYNTRANS_M88K if (cpu->cd.m88k.irq_asserted && !(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_IND)) m88k_exception(cpu, M88K_EXCEPTION_INTERRUPT, 0); #endif #ifdef DYNTRANS_MIPS int enabled, mask; int status = cpu->cd.mips.coproc[0]->reg[COP0_STATUS]; if (cpu->cd.mips.cpu_type.exc_model == EXC3K) { /* R3000: */ enabled = status & MIPS_SR_INT_IE; } else { /* R4000 and others: */ enabled = (status & STATUS_IE) && !(status & STATUS_EXL) && !(status & STATUS_ERL); /* Special case for R5900/C790/TX79: */ if (cpu->cd.mips.cpu_type.rev == MIPS_R5900 && !(status & R5900_STATUS_EIE)) enabled = 0; } mask = status & cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] & STATUS_IM_MASK; if (enabled && mask) mips_cpu_exception(cpu, EXCEPTION_INT, 0, 0, 0, 0, 0,0); #endif #ifdef DYNTRANS_PPC if (cpu->cd.ppc.dec_intr_pending && cpu->cd.ppc.msr & PPC_MSR_EE) { if (!(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC)) ppc_exception(cpu, PPC_EXCEPTION_DEC); cpu->cd.ppc.dec_intr_pending = 0; } if (cpu->cd.ppc.irq_asserted && cpu->cd.ppc.msr & PPC_MSR_EE) ppc_exception(cpu, PPC_EXCEPTION_EI); #endif #ifdef DYNTRANS_SH if (cpu->cd.sh.int_to_assert > 0 && !(cpu->cd.sh.sr & SH_SR_BL) && ((cpu->cd.sh.sr & SH_SR_IMASK) >> SH_SR_IMASK_SHIFT) < cpu->cd.sh.int_level) sh_exception(cpu, 0, cpu->cd.sh.int_to_assert, 0); #endif } #ifdef DYNTRANS_ARM if (cpu->cd.arm.cpsr & ARM_FLAG_T) { // fatal("THUMB execution not implemented.\n"); // cpu->running = false; // return 0; arm_cpu_interpret_thumb_SLOW(cpu); return 1; } #endif cached_pc = cpu->pc; cpu->n_translated_instrs = 0; cpu->cd.DYNTRANS_ARCH.cur_physpage = (struct DYNTRANS_TC_PHYSPAGE *) cpu->cd.DYNTRANS_ARCH.cur_ic_page; if (single_step || cpu->machine->instruction_trace || cpu->machine->register_dump) { /* * Single-step: */ struct DYNTRANS_IC *ic = cpu->cd.DYNTRANS_ARCH.next_ic; if (cpu->machine->register_dump) { debug("\n"); cpu_register_dump(cpu->machine, cpu, 1, 0x1); } if (cpu->machine->instruction_trace) { /* TODO/Note: This must be large enough to hold any instruction for any ISA: */ unsigned char instr[1 << DYNTRANS_INSTR_ALIGNMENT_SHIFT]; if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0], sizeof(instr), MEM_READ, CACHE_INSTRUCTION)) { fatal("XXX_run_instr(): could not read " "the instruction\n"); } else { #ifdef DYNTRANS_DELAYSLOT int len = #endif cpu_disassemble_instr( cpu->machine, cpu, instr, 1, cpu->pc); #ifdef DYNTRANS_DELAYSLOT /* Show the instruction in the delay slot, if any: */ if (cpu->instruction_has_delayslot == NULL) fatal("WARNING: ihd func not yet" " implemented?\n"); else if (cpu->instruction_has_delayslot(cpu, instr)) { int saved_delayslot = cpu->delay_slot; cpu->memory_rw(cpu, cpu->mem, cached_pc + len, &instr[0], sizeof(instr), MEM_READ, CACHE_INSTRUCTION); cpu->delay_slot = DELAYED; cpu->pc += len; cpu_disassemble_instr(cpu->machine, cpu, instr, 1, cpu->pc); cpu->delay_slot = saved_delayslot; cpu->pc -= len; } #endif } } if (cpu->machine->statistics.enabled) S; /* Execute just one instruction: */ I; n_instrs = 1; } else if (cpu->machine->statistics.enabled) { /* Gather statistics while executing multiple instructions: */ n_instrs = 0; for (;;) { struct DYNTRANS_IC *ic; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; S; I; n_instrs += 24; if (n_instrs + cpu->n_translated_instrs >= N_SAFE_DYNTRANS_LIMIT) break; } } else { /* * Execute multiple instructions: * * (This is the core dyntrans loop.) */ n_instrs = 0; for (;;) { struct DYNTRANS_IC *ic; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; I; cpu->n_translated_instrs += 120; if (cpu->n_translated_instrs >= N_SAFE_DYNTRANS_LIMIT) break; } } n_instrs += cpu->n_translated_instrs; /* Synchronize the program counter: */ low_pc = ((size_t)cpu->cd.DYNTRANS_ARCH.next_ic - (size_t) cpu->cd.DYNTRANS_ARCH.cur_ic_page) / sizeof(struct DYNTRANS_IC); if (low_pc >= 0 && low_pc < DYNTRANS_IC_ENTRIES_PER_PAGE) { cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << DYNTRANS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << DYNTRANS_INSTR_ALIGNMENT_SHIFT); } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE) { /* Switch to next page: */ cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << DYNTRANS_INSTR_ALIGNMENT_SHIFT); cpu->pc += (DYNTRANS_IC_ENTRIES_PER_PAGE << DYNTRANS_INSTR_ALIGNMENT_SHIFT); } else if (low_pc == DYNTRANS_IC_ENTRIES_PER_PAGE + 1) { /* Switch to next page and skip an instruction which was already executed (in a delay slot): */ cpu->pc &= ~((DYNTRANS_IC_ENTRIES_PER_PAGE-1) << DYNTRANS_INSTR_ALIGNMENT_SHIFT); cpu->pc += ((DYNTRANS_IC_ENTRIES_PER_PAGE + 1) << DYNTRANS_INSTR_ALIGNMENT_SHIFT); } #ifdef DYNTRANS_MIPS /* Update the count register (on everything except EXC3K): */ if (cpu->cd.mips.cpu_type.exc_model != EXC3K) { uint32_t old; int32_t diff1, diff2; cpu->cd.mips.coproc[0]->reg[COP0_COUNT] -= cpu->cd.mips.count_register_read_count; cpu->cd.mips.count_register_read_count = 0; old = cpu->cd.mips.coproc[0]->reg[COP0_COUNT]; diff1 = cpu->cd.mips.coproc[0]->reg[COP0_COMPARE] - old; cpu->cd.mips.coproc[0]->reg[COP0_COUNT] = (int32_t) (old + n_instrs); diff2 = cpu->cd.mips.coproc[0]->reg[COP0_COMPARE] - cpu->cd.mips.coproc[0]->reg[COP0_COUNT]; if (cpu->cd.mips.compare_register_set) { #if 1 /* Not yet. TODO */ if (cpu->machine->emulated_hz > 0) { if (cpu->cd.mips.compare_interrupts_pending > 0) INTERRUPT_ASSERT( cpu->cd.mips.irq_compare); } else #endif { if (diff1 > 0 && diff2 <= 0) INTERRUPT_ASSERT( cpu->cd.mips.irq_compare); } } } #endif #ifdef DYNTRANS_PPC /* Update the Decrementer and Time base registers: */ { uint32_t old = cpu->cd.ppc.spr[SPR_DEC]; cpu->cd.ppc.spr[SPR_DEC] = (uint32_t) (old - n_instrs); if ((old >> 31) == 0 && (cpu->cd.ppc.spr[SPR_DEC] >> 31) == 1 && !(cpu->cd.ppc.cpu_type.flags & PPC_NO_DEC)) cpu->cd.ppc.dec_intr_pending = 1; old = cpu->cd.ppc.spr[SPR_TBL]; cpu->cd.ppc.spr[SPR_TBL] += n_instrs; if ((old >> 31) == 1 && (cpu->cd.ppc.spr[SPR_TBL] >> 31) == 0) cpu->cd.ppc.spr[SPR_TBU] ++; } #endif cpu->ninstrs += n_instrs; /* Return the nr of instructions executed: */ return n_instrs; } #endif /* DYNTRANS_RUN_INSTR */ #ifdef DYNTRANS_FUNCTION_TRACE_DEF /* * XXX_cpu_functioncall_trace(): * * Without this function, the main trace tree function prints something * like or <0x1234()> on a function call. It is up to this * function to print the arguments passed. */ void DYNTRANS_FUNCTION_TRACE_DEF(struct cpu *cpu, int n_args) { int show_symbolic_function_name = 1; char strbuf[55]; char *symbol; uint64_t ot; int x, print_dots = 1, n_args_to_print = #if defined(DYNTRANS_ALPHA) 6 #else #if defined(DYNTRANS_SH) || defined(DYNTRANS_M88K) 8 /* Both for 32-bit and 64-bit SuperH, and M88K */ #else 4 /* Default value for most archs */ #endif #endif ; if (n_args >= 0 && n_args <= n_args_to_print) { print_dots = 0; n_args_to_print = n_args; } #ifdef DYNTRANS_M88K /* Special hack for M88K userspace: */ if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) show_symbolic_function_name = 0; #endif /* * TODO: The type of each argument should be taken from the symbol * table, in some way. * * The code here does a kind of "heuristic guess" regarding what the * argument values might mean. Sometimes the output looks weird, but * usually it looks good enough. * * Print ".." afterwards to show that there might be more arguments * than were passed in register. */ for (x=0; xcd.DYNTRANS_ARCH. #ifdef DYNTRANS_ALPHA r[ALPHA_A0 #endif #ifdef DYNTRANS_ARM r[0 #endif #ifdef DYNTRANS_MIPS gpr[MIPS_GPR_A0 #endif #ifdef DYNTRANS_M88K r[2 /* r2..r9 */ #endif #ifdef DYNTRANS_PPC gpr[3 #endif #ifdef DYNTRANS_SH r[4 /* NetBSD seems to use 4? But 2 seems to be used by other code? TODO */ #endif + x]; symbol = get_symbol_name(&cpu->machine->symbol_context, d, &ot); if (d > -256 && d < 256) fatal("%i", (int)d); else if (memory_points_to_string(cpu, cpu->mem, d, 1)) { memset(strbuf, 0, sizeof(strbuf)); memory_conv_to_string(cpu, cpu->mem, d, strbuf, sizeof(strbuf)); fatal("\"%s\"", strbuf); // TODO: This shows "..." when the string is longer // _or exactly the max length_. An improvement would // be to detect the case where the string is exactly // the max length and not show "..." then. if (strlen(strbuf) >= sizeof(strbuf)-1) fatal("..."); } else if (symbol != NULL && ot == 0 && show_symbolic_function_name) fatal("&%s", symbol); else { if (cpu->is_32bit) fatal("0x%" PRIx32, (uint32_t)d); else fatal("0x%" PRIx64, (uint64_t)d); } if (x < n_args_to_print - 1) fatal(","); } if (print_dots) fatal(",.."); } #endif /* DYNTRANS_FUNCTION_TRACE_DEF */ #ifdef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE_DEF /* * XXX_tc_allocate_default_page(): * * Create a default page (with just pointers to instr(to_be_translated) * at cpu->translation_cache_cur_ofs. */ static void DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE_DEF(struct cpu *cpu, uint64_t physaddr) { struct DYNTRANS_TC_PHYSPAGE *ppp; ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache + cpu->translation_cache_cur_ofs); /* Copy the entire template page first: */ memcpy(ppp, cpu->cd.DYNTRANS_ARCH.physpage_template, sizeof( struct DYNTRANS_TC_PHYSPAGE)); ppp->physaddr = physaddr & ~(DYNTRANS_PAGESIZE - 1); cpu->translation_cache_cur_ofs += sizeof(struct DYNTRANS_TC_PHYSPAGE); cpu->translation_cache_cur_ofs --; cpu->translation_cache_cur_ofs |= 63; cpu->translation_cache_cur_ofs ++; } #endif /* DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE_DEF */ #ifdef DYNTRANS_PC_TO_POINTERS_FUNC /* * XXX_pc_to_pointers_generic(): * * Generic case. See DYNTRANS_PC_TO_POINTERS_FUNC below. */ void DYNTRANS_PC_TO_POINTERS_GENERIC(struct cpu *cpu) { #ifdef MODE32 uint32_t #else uint64_t #endif cached_pc = cpu->pc, physaddr = 0; uint32_t physpage_ofs; int ok, pagenr, table_index; uint32_t *physpage_entryp; struct DYNTRANS_TC_PHYSPAGE *ppp; #ifdef MODE32 int index = DYNTRANS_ADDR_TO_PAGENR(cached_pc); #else const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; uint32_t x1, x2, x3; struct DYNTRANS_L2_64_TABLE *l2; struct DYNTRANS_L3_64_TABLE *l3; x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1; x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) & mask3; /* fatal("X3: cached_pc=%016" PRIx64" x1=%x x2=%x x3=%x\n", (uint64_t)cached_pc, (int)x1, (int)x2, (int)x3); */ l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; /* fatal(" l2 = %p\n", l2); */ l3 = l2->l3[x2]; /* fatal(" l3 = %p\n", l3); */ #endif /* Virtual to physical address translation: */ ok = 0; #ifdef MODE32 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) { physaddr = cpu->cd.DYNTRANS_ARCH.phys_addr[index]; ok = 1; } #else if (l3->host_load[x3] != NULL) { physaddr = l3->phys_addr[x3]; ok = 1; } #endif if (!ok) { uint64_t paddr; if (cpu->translate_v2p != NULL) { uint64_t vaddr = #if defined(MODE32) && defined(DYNTRANS_MIPS) /* 32-bit MIPS is _sign_ extend, not zero. */ (int32_t) #endif cached_pc; ok = cpu->translate_v2p( cpu, vaddr, &paddr, FLAG_INSTR); } else { paddr = cached_pc; ok = 1; } if (!ok) { /* * The PC is now set to the exception handler. * Try to find the paddr in the translation arrays, * or if that fails, call translate_v2p for the * exception handler. */ /* fatal("TODO: instruction vaddr=>paddr translation " "failed. vaddr=0x%" PRIx64"\n", (uint64_t)cached_pc); fatal("!! cpu->pc=0x%" PRIx64"\n", (uint64_t)cpu->pc); */ /* If there was an exception, the PC has changed. Update cached_pc: */ cached_pc = cpu->pc; #ifdef MODE32 index = DYNTRANS_ADDR_TO_PAGENR(cached_pc); if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) { paddr = cpu->cd.DYNTRANS_ARCH.phys_addr[index]; ok = 1; } #else x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1; x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N - DYNTRANS_L3N)) & mask3; l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; l3 = l2->l3[x2]; if (l3->host_load[x3] != NULL) { paddr = l3->phys_addr[x3]; ok = 1; } #endif if (!ok) { ok = cpu->translate_v2p(cpu, cpu->pc, &paddr, FLAG_INSTR); } /* printf("EXCEPTION HANDLER: vaddr = 0x%x ==> " "paddr = 0x%x\n", (int)cpu->pc, (int)paddr); fatal("!? cpu->pc=0x%" PRIx64"\n", (uint64_t)cpu->pc); */ if (!ok) { fatal("FATAL: could not find physical" " address of the exception handler?"); exit(1); } } physaddr = paddr; } physaddr &= ~(DYNTRANS_PAGESIZE - 1); #ifdef MODE32 if (cpu->cd.DYNTRANS_ARCH.host_load[index] == NULL) { #else if (l3->host_load[x3] == NULL) { #endif int q = DYNTRANS_PAGESIZE - 1; unsigned char *host_page = memory_paddr_to_hostaddr(cpu->mem, physaddr, MEM_READ); if (host_page != NULL) { cpu->update_translation_table(cpu, cached_pc & ~q, host_page, 0, physaddr); } } if (cpu->translation_cache_cur_ofs >= dyntrans_cache_size) { #ifdef UNSTABLE_DEVEL fatal("[ dyntrans: resetting the translation cache ]\n"); #endif cpu_create_or_reset_tc(cpu); } pagenr = DYNTRANS_ADDR_TO_PAGENR(physaddr); table_index = PAGENR_TO_TABLE_INDEX(pagenr); physpage_entryp = &(((uint32_t *)cpu->translation_cache)[table_index]); physpage_ofs = *physpage_entryp; ppp = NULL; /* Traverse the physical page chain: */ while (physpage_ofs != 0) { ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache + physpage_ofs); /* If we found the page in the cache, then we're done: */ if (ppp->physaddr == physaddr) break; /* Try the next page in the chain: */ physpage_ofs = ppp->next_ofs; } /* * If the offset is 0, then no translation exists yet for this * physical address. Let's create a new page, and add it first in * the chain. */ if (physpage_ofs == 0) { uint32_t previous_first_page_in_chain; /* fatal("CREATING page %lli (physaddr 0x%" PRIx64"), table " "index %i\n", (long long)pagenr, (uint64_t)physaddr, (int)table_index); */ previous_first_page_in_chain = *physpage_entryp; /* Insert the new page first in the chain: */ *physpage_entryp = physpage_ofs = cpu->translation_cache_cur_ofs; /* Allocate a default page, with to_be_translated entries: */ DYNTRANS_TC_ALLOCATE(cpu, physaddr); ppp = (struct DYNTRANS_TC_PHYSPAGE *)(cpu->translation_cache + physpage_ofs); /* Point to the other pages in the same chain: */ ppp->next_ofs = previous_first_page_in_chain; } /* Here, ppp points to a valid physical page struct. */ #ifdef MODE32 if (cpu->cd.DYNTRANS_ARCH.host_load[index] != NULL) cpu->cd.DYNTRANS_ARCH.phys_page[index] = ppp; #else if (l3->host_load[x3] != NULL) l3->phys_page[x3] = ppp; #endif /* * If there are no translations yet on this page, then mark it * as non-writable. If there are already translations, then it * should already have been marked as non-writable. */ if (ppp->translations_bitmap == 0) { cpu->invalidate_translation_caches(cpu, physaddr, JUST_MARK_AS_NON_WRITABLE | INVALIDATE_PADDR); } cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0]; cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page + DYNTRANS_PC_TO_IC_ENTRY(cached_pc); /* printf("cached_pc=0x%016" PRIx64" pagenr=%lli table_index=%lli, " "physpage_ofs=0x%016" PRIx64"\n", (uint64_t)cached_pc, (long long) pagenr, (long long)table_index, (uint64_t)physpage_ofs); */ } /* * XXX_pc_to_pointers(): * * This function uses the current program counter (a virtual address) to * find out which physical translation page to use, and then sets the current * translation page pointers to that page. * * If there was no translation page for that physical page, then an empty * one is created. * * NOTE: This is the quick lookup version. See * DYNTRANS_PC_TO_POINTERS_GENERIC above for the generic case. */ void DYNTRANS_PC_TO_POINTERS_FUNC(struct cpu *cpu) { #ifdef MODE32 uint32_t #else uint64_t #endif cached_pc = cpu->pc; struct DYNTRANS_TC_PHYSPAGE *ppp; #ifdef MODE32 int index; index = DYNTRANS_ADDR_TO_PAGENR(cached_pc); ppp = cpu->cd.DYNTRANS_ARCH.phys_page[index]; if (ppp != NULL) goto have_it; #else const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; uint32_t x1, x2, x3; struct DYNTRANS_L2_64_TABLE *l2; struct DYNTRANS_L3_64_TABLE *l3; x1 = (cached_pc >> (64-DYNTRANS_L1N)) & mask1; x2 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; x3 = (cached_pc >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) & mask3; l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; l3 = l2->l3[x2]; ppp = l3->phys_page[x3]; if (ppp != NULL) goto have_it; #endif DYNTRANS_PC_TO_POINTERS_GENERIC(cpu); return; /* Quick return path: */ have_it: cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp->ics[0]; cpu->cd.DYNTRANS_ARCH.next_ic = cpu->cd.DYNTRANS_ARCH.cur_ic_page + DYNTRANS_PC_TO_IC_ENTRY(cached_pc); /* printf("cached_pc=0x%016" PRIx64" pagenr=%lli table_index=%lli, " "physpage_ofs=0x%016" PRIx64"\n", (uint64_t)cached_pc, (long long) pagenr, (long long)table_index, (uint64_t)physpage_ofs); */ } #endif /* DYNTRANS_PC_TO_POINTERS_FUNC */ #ifdef DYNTRANS_INIT_TABLES /* forward declaration of to_be_translated and end_of_page: */ static void instr(to_be_translated)(struct cpu *, struct DYNTRANS_IC *); static void instr(end_of_page)(struct cpu *,struct DYNTRANS_IC *); #ifdef DYNTRANS_DUALMODE_32 static void instr32(to_be_translated)(struct cpu *, struct DYNTRANS_IC *); static void instr32(end_of_page)(struct cpu *,struct DYNTRANS_IC *); #endif #ifdef DYNTRANS_DUALMODE_32 #define TO_BE_TRANSLATED ( cpu->is_32bit? instr32(to_be_translated) : \ instr(to_be_translated) ) #else #define TO_BE_TRANSLATED ( instr(to_be_translated) ) #endif #ifdef DYNTRANS_DELAYSLOT static void instr(end_of_page2)(struct cpu *,struct DYNTRANS_IC *); #ifdef DYNTRANS_DUALMODE_32 static void instr32(end_of_page2)(struct cpu *,struct DYNTRANS_IC *); #endif #endif /* * XXX_init_tables(): * * Initializes the default translation page (for newly allocated pages), and * for 64-bit emulation it also initializes 64-bit dummy tables and pointers. */ void DYNTRANS_INIT_TABLES(struct cpu *cpu) { #ifndef MODE32 struct DYNTRANS_L2_64_TABLE *dummy_l2; struct DYNTRANS_L3_64_TABLE *dummy_l3; int x1, x2; #endif int i; struct DYNTRANS_TC_PHYSPAGE *ppp; CHECK_ALLOCATION(ppp = (struct DYNTRANS_TC_PHYSPAGE *) malloc(sizeof(struct DYNTRANS_TC_PHYSPAGE))); ppp->next_ofs = 0; ppp->translations_bitmap = 0; ppp->translation_ranges_ofs = 0; /* ppp->physaddr is filled in by the page allocator */ for (i=0; iics[i].f = TO_BE_TRANSLATED; /* End-of-page: */ ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 0].f = #ifdef DYNTRANS_DUALMODE_32 cpu->is_32bit? instr32(end_of_page) : #endif instr(end_of_page); /* End-of-page-2, for delay-slot architectures: */ #ifdef DYNTRANS_DELAYSLOT ppp->ics[DYNTRANS_IC_ENTRIES_PER_PAGE + 1].f = #ifdef DYNTRANS_DUALMODE_32 cpu->is_32bit? instr32(end_of_page2) : #endif instr(end_of_page2); #endif cpu->cd.DYNTRANS_ARCH.physpage_template = ppp; /* Prepare 64-bit virtual address translation tables: */ #ifndef MODE32 if (cpu->is_32bit) return; dummy_l2 = (struct DYNTRANS_L2_64_TABLE *) zeroed_alloc(sizeof(struct DYNTRANS_L2_64_TABLE)); dummy_l3 = (struct DYNTRANS_L3_64_TABLE *) zeroed_alloc(sizeof(struct DYNTRANS_L3_64_TABLE)); cpu->cd.DYNTRANS_ARCH.l2_64_dummy = dummy_l2; cpu->cd.DYNTRANS_ARCH.l3_64_dummy = dummy_l3; for (x1 = 0; x1 < (1 << DYNTRANS_L1N); x1 ++) cpu->cd.DYNTRANS_ARCH.l1_64[x1] = dummy_l2; for (x2 = 0; x2 < (1 << DYNTRANS_L2N); x2 ++) dummy_l2->l3[x2] = dummy_l3; #endif } #endif /* DYNTRANS_INIT_TABLES */ #ifdef DYNTRANS_INVAL_ENTRY /* * XXX_invalidate_tlb_entry(): * * Invalidate one translation entry (based on virtual address). * * If the JUST_MARK_AS_NON_WRITABLE flag is set, then the translation entry * is just downgraded to non-writable (ie the host store page is set to * NULL). Otherwise, the entire translation is removed. */ static void DYNTRANS_INVALIDATE_TLB_ENTRY(struct cpu *cpu, #ifdef MODE32 uint32_t #else uint64_t #endif vaddr_page, int flags) { #ifdef MODE32 uint32_t index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page); #ifdef DYNTRANS_ARM cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] &= ~(1 << (index & 31)); #endif if (flags & JUST_MARK_AS_NON_WRITABLE) { /* printf("JUST MARKING NON-W: vaddr 0x%08x\n", (int)vaddr_page); */ cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL; } else { int tlbi = cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index]; cpu->cd.DYNTRANS_ARCH.host_load[index] = NULL; cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL; cpu->cd.DYNTRANS_ARCH.phys_addr[index] = 0; cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; if (tlbi > 0) cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[tlbi-1].valid = 0; cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = 0; } #else const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; uint32_t x1, x2, x3; struct DYNTRANS_L2_64_TABLE *l2; struct DYNTRANS_L3_64_TABLE *l3; x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1; x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N))& mask3; l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) return; l3 = l2->l3[x2]; if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) return; if (flags & JUST_MARK_AS_NON_WRITABLE) { l3->host_store[x3] = NULL; return; } #ifdef BUGHUNT { /* Consistency check, for debugging: */ int x1, x1b; // x2, x3; struct DYNTRANS_L2_64_TABLE *l2; //struct DYNTRANS_L3_64_TABLE *l3; for (x1 = 0; x1 <= mask1; x1 ++) { l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) continue; /* Make sure that this l2 isn't used more than 1 time! */ for (x1b = 0; x1b <= mask1; x1b ++) if (x1 != x1b && l2 == cpu->cd.DYNTRANS_ARCH.l1_64[x1b]) { fatal("L2 reuse: %p\n", l2); exit(1); } } } /* Count how many pages are actually in use: */ { int n=0, i; for (i=0; i<=mask3; i++) if (l3->vaddr_to_tlbindex[i]) n++; if (n != l3->refcount) { printf("Z: %i in use, but refcount = %i!\n", n, l3->refcount); exit(1); } n = 0; for (i=0; i<=mask3; i++) if (l3->host_load[i] != NULL) n++; if (n != l3->refcount) { printf("ZHL: %i in use, but refcount = %i!\n", n, l3->refcount); exit(1); } } #endif /* int found = -1; for (int q = 0; q < 192; ++q) { if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[q].vaddr_page == vaddr_page && cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[q].valid) { if (found >= 0) { printf("ALREADY FOUND = %i\n", found); int zz = found; printf("%03i: ", zz); printf("vaddr=%016llx\n", (long long)cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[zz].vaddr_page); printf("valid=%i\n", cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[zz].valid); zz = q; printf("%03i: ", zz); printf("vaddr=%016llx\n", (long long)cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[zz].vaddr_page); printf("valid=%i\n", cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[zz].valid); exit(1); } found = q; } } */ l3->host_load[x3] = NULL; l3->host_store[x3] = NULL; l3->phys_addr[x3] = 0; l3->phys_page[x3] = NULL; if (l3->vaddr_to_tlbindex[x3] != 0) { cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[ l3->vaddr_to_tlbindex[x3] - 1].valid = 0; l3->refcount --; } else {/* printf("APA: vaddr_page=%016llx l3->refcount = %i\n", (long long)vaddr_page, l3->refcount); for (int zz = 0; zz < 128; ++zz) { printf("%03i: ", zz); printf("vaddr=%016llx\n", (long long)cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[zz].vaddr_page); printf("valid=%i\n", cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[zz].valid); } exit(1);*/ } l3->vaddr_to_tlbindex[x3] = 0; if (l3->refcount < 0) { fatal("xxx_invalidate_tlb_entry(): huh? Refcount bug.\n"); exit(1); } if (l3->refcount == 0) { l3->next = cpu->cd.DYNTRANS_ARCH.next_free_l3; cpu->cd.DYNTRANS_ARCH.next_free_l3 = l3; l2->l3[x2] = cpu->cd.DYNTRANS_ARCH.l3_64_dummy; #ifdef BUGHUNT /* Make sure that we're placing a CLEAN page on the freelist: */ { int i; for (i=0; i<=mask3; i++) if (l3->host_load[i] != NULL) { fatal("TRYING TO RETURN A NON-CLEAN L3 PAGE!\n"); exit(1); } } #endif l2->refcount --; if (l2->refcount < 0) { fatal("xxx_invalidate_tlb_entry(): Refcount bug L2.\n"); exit(1); } if (l2->refcount == 0) { l2->next = cpu->cd.DYNTRANS_ARCH.next_free_l2; cpu->cd.DYNTRANS_ARCH.next_free_l2 = l2; cpu->cd.DYNTRANS_ARCH.l1_64[x1] = cpu->cd.DYNTRANS_ARCH.l2_64_dummy; } } #endif } #endif #ifdef DYNTRANS_INVALIDATE_TC /* * XXX_invalidate_translation_caches(): * * Invalidate all entries matching a specific physical address, a specific * virtual address, or ALL entries. * * flags should be one of * INVALIDATE_PADDR INVALIDATE_VADDR or INVALIDATE_ALL * * In addition, for INVALIDATE_ALL, INVALIDATE_VADDR_UPPER4 may be set and * bit 31..28 of addr are used to select the virtual addresses to invalidate. * (This is useful for PowerPC emulation, when segment registers are updated.) * * In the case when all translations are invalidated, paddr doesn't need * to be supplied. * * NOTE/TODO: When invalidating a virtual address, it is only cleared from * the quick translation array, not from the linear * vph_tlb_entry[] array. Hopefully this is enough anyway. */ void DYNTRANS_INVALIDATE_TC(struct cpu *cpu, uint64_t addr, int flags) { int r; #ifdef MODE32 uint32_t #else uint64_t #endif addr_page = addr & ~(DYNTRANS_PAGESIZE - 1); /* fatal("invalidate(): "); */ /* Quick case for _one_ virtual addresses: see note above. */ if (flags & INVALIDATE_VADDR) { /* fatal("vaddr 0x%08x\n", (int)addr_page); */ DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, addr_page, flags); return; } /* Invalidate everything: */ #ifdef DYNTRANS_PPC if (flags & INVALIDATE_ALL && flags & INVALIDATE_VADDR_UPPER4) { /* fatal("all, upper4 (PowerPC segment)\n"); */ for (r=0; rcd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page & 0xf0000000) == addr_page) { DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd. DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page, 0); cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0; } } return; } #endif if (flags & INVALIDATE_ALL) { /* fatal("all\n"); */ for (r=0; rcd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd. DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page, 0); cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid=0; } } return; } /* Invalidate a physical page: */ if (!(flags & INVALIDATE_PADDR)) fatal("HUH? Invalidate: Not vaddr, all, or paddr?\n"); /* fatal("addr 0x%08x\n", (int)addr_page); */ for (r=0; rcd.DYNTRANS_ARCH.vph_tlb_entry[r].valid && addr_page == cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page) { DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page, flags); if (flags & JUST_MARK_AS_NON_WRITABLE) cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r] .writeflag = 0; else cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r] .valid = 0; } } } #endif /* DYNTRANS_INVALIDATE_TC */ #ifdef DYNTRANS_INVALIDATE_TC_CODE /* * XXX_invalidate_code_translation(): * * Invalidate code translations for a specific physical address, a specific * virtual address, or for all entries in the cache. */ void DYNTRANS_INVALIDATE_TC_CODE(struct cpu *cpu, uint64_t addr, int flags) { int r; #ifdef MODE32 uint32_t #else uint64_t #endif vaddr_page, paddr_page; addr &= ~(DYNTRANS_PAGESIZE-1); /* printf("DYNTRANS_INVALIDATE_TC_CODE addr=0x%08x flags=%i\n", (int)addr, flags); */ if (flags & INVALIDATE_PADDR) { int pagenr, table_index; uint32_t physpage_ofs, *physpage_entryp; struct DYNTRANS_TC_PHYSPAGE *ppp, *prev_ppp; pagenr = DYNTRANS_ADDR_TO_PAGENR(addr); table_index = PAGENR_TO_TABLE_INDEX(pagenr); physpage_entryp = &(((uint32_t *)cpu-> translation_cache)[table_index]); physpage_ofs = *physpage_entryp; /* Return immediately if there is no code translation for this page. */ if (physpage_ofs == 0) return; prev_ppp = ppp = NULL; /* Traverse the physical page chain: */ while (physpage_ofs != 0) { prev_ppp = ppp; ppp = (struct DYNTRANS_TC_PHYSPAGE *) (cpu->translation_cache + physpage_ofs); /* If we found the page in the cache, then we're done: */ if (ppp->physaddr == addr) break; /* Try the next page in the chain: */ physpage_ofs = ppp->next_ofs; } /* If there is no translation, there is no need to go on and try to remove it from the vph_tlb_entry array: */ if (physpage_ofs == 0) return; #if 0 /* * "Bypass" the page, removing it from the code cache. * * NOTE/TODO: This gives _TERRIBLE_ performance with self- * modifying code, or when a single page is used for both * code and (writable) data. */ if (ppp != NULL) { if (prev_ppp != NULL) prev_ppp->next_ofs = ppp->next_ofs; else *physpage_entryp = ppp->next_ofs; } #else (void)prev_ppp; // shut up compiler warning /* * Instead of removing the page from the code cache, each * entry can be set to "to_be_translated". This is slow in * the general case, but in the case of self-modifying code, * it might be faster since we don't risk wasting cache * memory as quickly (which would force unnecessary Restarts). */ if (ppp != NULL && ppp->translations_bitmap != 0) { uint32_t x = ppp->translations_bitmap; /* TODO: urk Should be same type as the bitmap */ int i, j, n, m; #ifdef DYNTRANS_ARM /* * Note: On ARM, PC-relative load instructions are * implemented as immediate mov instructions. When * setting parts of the page to "to be translated", * we cannot keep track of which of the immediate * movs that were affected, so we need to clear * the entire page. (ARM only; not for the general * case.) */ x = 0xffffffff; #endif n = 8 * sizeof(x); m = DYNTRANS_IC_ENTRIES_PER_PAGE / n; for (i=0; iics[i*m + j].f = TO_BE_TRANSLATED; } x >>= 1; } ppp->translations_bitmap = 0; /* Clear the list of translatable ranges: */ if (ppp->translation_ranges_ofs != 0) { struct physpage_ranges *physpage_ranges = (struct physpage_ranges *) (cpu->translation_cache + ppp->translation_ranges_ofs); physpage_ranges->next_ofs = 0; physpage_ranges->n_entries_used = 0; } } #endif } /* Invalidate entries in the VPH table: */ for (r = 0; r < DYNTRANS_MAX_VPH_TLB_ENTRIES; r ++) { if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { vaddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r] .vaddr_page & ~(DYNTRANS_PAGESIZE-1); paddr_page = cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r] .paddr_page & ~(DYNTRANS_PAGESIZE-1); if (flags & INVALIDATE_ALL || (flags & INVALIDATE_PADDR && paddr_page == addr) || (flags & INVALIDATE_VADDR && vaddr_page == addr)) { #ifdef MODE32 uint32_t index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page); cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; #else const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; uint32_t x1, x2, x3; struct DYNTRANS_L2_64_TABLE *l2; struct DYNTRANS_L3_64_TABLE *l3; x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1; x2 = (vaddr_page >> (64-DYNTRANS_L1N - DYNTRANS_L2N)) & mask2; x3 = (vaddr_page >> (64-DYNTRANS_L1N - DYNTRANS_L2N - DYNTRANS_L3N)) & mask3; l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; l3 = l2->l3[x2]; l3->phys_page[x3] = NULL; #endif } } } } #endif /* DYNTRANS_INVALIDATE_TC_CODE */ #ifdef DYNTRANS_UPDATE_TRANSLATION_TABLE /* * XXX_update_translation_table(): * * Update the virtual memory translation tables. */ void DYNTRANS_UPDATE_TRANSLATION_TABLE(struct cpu *cpu, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page) { int found, r, useraccess = 0; #ifdef MODE32 uint32_t index; vaddr_page &= 0xffffffffULL; if (paddr_page > 0xffffffffULL) { fatal("update_translation_table(): v=0x%016" PRIx64", h=%p w=%i" " p=0x%016" PRIx64"\n", vaddr_page, host_page, writeflag, paddr_page); exit(1); } /* fatal("update_translation_table(): v=0x%x, h=%p w=%i" " p=0x%x\n", (int)vaddr_page, host_page, writeflag, (int)paddr_page); */ #else /* !MODE32 */ const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; uint32_t x1, x2, x3; struct DYNTRANS_L2_64_TABLE *l2; struct DYNTRANS_L3_64_TABLE *l3; /* fatal("update_translation_table(): v=0x%016" PRIx64", h=%p w=%i" " p=0x%016" PRIx64"\n", (uint64_t)vaddr_page, host_page, writeflag, (uint64_t)paddr_page); */ #endif assert((vaddr_page & (DYNTRANS_PAGESIZE-1)) == 0); assert((paddr_page & (DYNTRANS_PAGESIZE-1)) == 0); if (writeflag & MEMORY_USER_ACCESS) { writeflag &= ~MEMORY_USER_ACCESS; useraccess = 1; } (void)useraccess; // shut up compiler warning about unused var #ifdef DYNTRANS_M88K /* TODO */ if (useraccess) return; #endif /* Scan the current TLB entries: */ #ifdef MODE32 /* * NOTE 1: vaddr_to_tlbindex is one more than the index, so that * 0 becomes -1, which means a miss. * * NOTE 2: When a miss occurs, instead of scanning the entire tlb * for the entry with the lowest time stamp, just choosing * one at random will work as well. */ found = (int)cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[ DYNTRANS_ADDR_TO_PAGENR(vaddr_page)] - 1; #else x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1; x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) & mask3; l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) found = -1; else { l3 = l2->l3[x2]; if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) found = -1; else found = (int)l3->vaddr_to_tlbindex[x3] - 1; } #endif if (found < 0) { /* Create the new TLB entry, overwriting a "random" entry: */ static unsigned int x = 0; r = (x++) % DYNTRANS_MAX_VPH_TLB_ENTRIES; if (cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid) { /* This one has to be invalidated first: */ DYNTRANS_INVALIDATE_TLB_ENTRY(cpu, cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page, 0); } cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid = 1; cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].host_page = host_page; cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].paddr_page = paddr_page; cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].vaddr_page = vaddr_page; cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = writeflag & MEM_WRITE; /* Add the new translation to the table: */ #ifdef MODE32 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page); cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page; cpu->cd.DYNTRANS_ARCH.host_store[index] = writeflag? host_page : NULL; cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page; cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; cpu->cd.DYNTRANS_ARCH.vaddr_to_tlbindex[index] = r + 1; #ifdef DYNTRANS_ARM if (useraccess) cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] |= 1 << (index & 31); #endif #else /* !MODE32 */ l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) { if (cpu->cd.DYNTRANS_ARCH.next_free_l2 != NULL) { l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1] = cpu->cd.DYNTRANS_ARCH.next_free_l2; cpu->cd.DYNTRANS_ARCH.next_free_l2 = l2->next; } else { int i; CHECK_ALLOCATION(l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1] = (struct DYNTRANS_L2_64_TABLE *) malloc( sizeof(struct DYNTRANS_L2_64_TABLE))); l2->refcount = 0; for (i=0; i<(1 << DYNTRANS_L2N); i++) l2->l3[i] = cpu->cd.DYNTRANS_ARCH. l3_64_dummy; } if (l2->refcount != 0) { fatal("Huh? l2 Refcount problem.\n"); exit(1); } } if (l2 == cpu->cd.DYNTRANS_ARCH.l2_64_dummy) { fatal("INTERNAL ERROR L2 reuse\n"); exit(1); } l3 = l2->l3[x2]; if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) { if (cpu->cd.DYNTRANS_ARCH.next_free_l3 != NULL) { l3 = l2->l3[x2] = cpu->cd.DYNTRANS_ARCH.next_free_l3; cpu->cd.DYNTRANS_ARCH.next_free_l3 = l3->next; } else { l3 = l2->l3[x2] = (struct DYNTRANS_L3_64_TABLE *) zeroed_alloc(sizeof( struct DYNTRANS_L3_64_TABLE)); } if (l3->refcount != 0) { fatal("Huh? l3 Refcount problem.\n"); exit(1); } l2->refcount ++; } if (l3 == cpu->cd.DYNTRANS_ARCH.l3_64_dummy) { fatal("INTERNAL ERROR L3 reuse\n"); exit(1); } l3->host_load[x3] = host_page; l3->host_store[x3] = writeflag? host_page : NULL; l3->phys_addr[x3] = paddr_page; l3->phys_page[x3] = NULL; l3->vaddr_to_tlbindex[x3] = r + 1; l3->refcount ++; #ifdef BUGHUNT /* Count how many pages are actually in use: */ { int n=0, i; for (i=0; i<=mask3; i++) if (l3->vaddr_to_tlbindex[i]) n++; if (n != l3->refcount) { printf("X: %i in use, but refcount = %i!\n", n, l3->refcount); exit(1); } n = 0; for (i=0; i<=mask3; i++) if (l3->host_load[i] != NULL) n++; if (n != l3->refcount) { printf("XHL: %i in use, but refcount = %i!\n", n, l3->refcount); exit(1); } } #endif #endif /* !MODE32 */ } else { /* * The translation was already in the TLB. * Writeflag = 0: Do nothing. * Writeflag = 1: Make sure the page is writable. * Writeflag = MEM_DOWNGRADE: Downgrade to readonly. */ r = found; if (writeflag & MEM_WRITE) cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 1; if (writeflag & MEM_DOWNGRADE) cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].writeflag = 0; #ifdef MODE32 index = DYNTRANS_ADDR_TO_PAGENR(vaddr_page); cpu->cd.DYNTRANS_ARCH.phys_page[index] = NULL; #ifdef DYNTRANS_ARM cpu->cd.DYNTRANS_ARCH.is_userpage[index>>5] &= ~(1<<(index&31)); if (useraccess) cpu->cd.DYNTRANS_ARCH.is_userpage[index >> 5] |= 1 << (index & 31); #endif if (cpu->cd.DYNTRANS_ARCH.phys_addr[index] == paddr_page) { if (writeflag & MEM_WRITE) cpu->cd.DYNTRANS_ARCH.host_store[index] = host_page; if (writeflag & MEM_DOWNGRADE) cpu->cd.DYNTRANS_ARCH.host_store[index] = NULL; } else { /* Change the entire physical/host mapping: */ cpu->cd.DYNTRANS_ARCH.host_load[index] = host_page; cpu->cd.DYNTRANS_ARCH.host_store[index] = writeflag? host_page : NULL; cpu->cd.DYNTRANS_ARCH.phys_addr[index] = paddr_page; } #else /* !MODE32 */ x1 = (vaddr_page >> (64-DYNTRANS_L1N)) & mask1; x2 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; x3 = (vaddr_page >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) & mask3; l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; l3 = l2->l3[x2]; if (l3->phys_addr[x3] == paddr_page) { if (writeflag & MEM_WRITE) l3->host_store[x3] = host_page; if (writeflag & MEM_DOWNGRADE) l3->host_store[x3] = NULL; } else { /* Change the entire physical/host mapping: */ l3->host_load[x3] = host_page; l3->host_store[x3] = writeflag? host_page : NULL; l3->phys_addr[x3] = paddr_page; } /* HM! /2013-11-17 */ /* Should this be here? 2014-08-02 */ //l3->phys_page[x3] = NULL; #ifdef BUGHUNT /* Count how many pages are actually in use: */ { int n=0, i; for (i=0; i<=mask3; i++) if (l3->vaddr_to_tlbindex[i]) n++; if (n != l3->refcount) { printf("Y: %i in use, but refcount = %i!\n", n, l3->refcount); exit(1); } n = 0; for (i=0; i<=mask3; i++) if (l3->host_load[i] != NULL) n++; if (n != l3->refcount) { printf("YHL: %i in use, but refcount = %i!\n", n, l3->refcount); printf("Entry r = %i\n", r); printf("Valid = %i\n", cpu->cd.DYNTRANS_ARCH.vph_tlb_entry[r].valid); exit(1); } } #endif #endif /* !MODE32 */ } } #endif /* DYNTRANS_UPDATE_TRANSLATION_TABLE */ /*****************************************************************************/ #ifdef DYNTRANS_TO_BE_TRANSLATED_HEAD /* * Check for breakpoints. */ if (!single_step_breakpoint && !cpu->translation_readahead) { MODE_uint_t curpc = cpu->pc; int i; for (i=0; imachine->breakpoints.n; i++) if (curpc == (MODE_uint_t) cpu->machine->breakpoints.addr[i]) { if (!cpu->machine->instruction_trace) { int tmp_old_quiet_mode = quiet_mode; quiet_mode = 0; DISASSEMBLE(cpu, ib, 1, 0); quiet_mode = tmp_old_quiet_mode; } #ifdef MODE32 fatal("BREAKPOINT: pc = 0x%" PRIx32"\n(The " "instruction has not yet executed.)\n", (uint32_t)cpu->pc); #else fatal("BREAKPOINT: pc = 0x%" PRIx64"\n(The " "instruction has not yet executed.)\n", (uint64_t)cpu->pc); #endif #ifdef DYNTRANS_DELAYSLOT if (cpu->delay_slot != NOT_DELAYED) fatal("ERROR! Breakpoint in a delay" " slot! Not yet supported.\n"); #endif single_step_breakpoint = 1; single_step = ENTER_SINGLE_STEPPING; goto stop_running_translated; } } #endif /* DYNTRANS_TO_BE_TRANSLATED_HEAD */ /*****************************************************************************/ #ifdef DYNTRANS_TO_BE_TRANSLATED_TAIL /* * If we end up here, then an instruction was translated. Let's mark * the page as containing a translation at this part of the page. */ /* Make sure cur_physpage is in synch: */ cpu->cd.DYNTRANS_ARCH.cur_physpage = (struct DYNTRANS_TC_PHYSPAGE *) cpu->cd.DYNTRANS_ARCH.cur_ic_page; { int x = addr & (DYNTRANS_PAGESIZE - 1); int addr_per_translation_range = DYNTRANS_PAGESIZE / (8 * sizeof(cpu->cd.DYNTRANS_ARCH.cur_physpage-> translations_bitmap)); x /= addr_per_translation_range; cpu->cd.DYNTRANS_ARCH.cur_physpage-> translations_bitmap |= (1 << x); } /* * Now it is time to check for combinations of instructions that can * be converted into a single function call. * * Note: Single-stepping or instruction tracing doesn't work with * instruction combinations. For architectures with delay slots, * we also ignore combinations if the delay slot is across a page * boundary. */ if (!single_step && !cpu->machine->instruction_trace #ifdef DYNTRANS_DELAYSLOT && !in_crosspage_delayslot #endif && cpu->cd.DYNTRANS_ARCH.combination_check != NULL && cpu->machine->allow_instruction_combinations) { cpu->cd.DYNTRANS_ARCH.combination_check(cpu, ic, addr & (DYNTRANS_PAGESIZE - 1)); } cpu->cd.DYNTRANS_ARCH.combination_check = NULL; /* An additional check, to catch some bugs: */ if (ic->f == TO_BE_TRANSLATED) { fatal("INTERNAL ERROR: ic->f not set!\n"); goto bad; } if (ic->f == NULL) { fatal("INTERNAL ERROR: ic->f == NULL!\n"); goto bad; } /* * ... and finally execute the translated instruction: */ /* (Except when doing read-ahead!) */ if (cpu->translation_readahead) return; /* * Special case when single-stepping: Execute the translated * instruction, but then replace it with a "to be translated" * directly afterwards. */ if ((single_step_breakpoint && cpu->delay_slot == NOT_DELAYED) #ifdef DYNTRANS_DELAYSLOT || in_crosspage_delayslot #endif ) { single_step_breakpoint = 0; ic->f(cpu, ic); ic->f = TO_BE_TRANSLATED; return; } /* Translation read-ahead: */ if (!single_step && !cpu->machine->instruction_trace && cpu->machine->breakpoints.n == 0) { uint64_t baseaddr = cpu->pc; uint64_t pagenr = DYNTRANS_ADDR_TO_PAGENR(baseaddr); int i = 1; cpu->translation_readahead = MAX_DYNTRANS_READAHEAD; while (DYNTRANS_ADDR_TO_PAGENR(baseaddr + (i << DYNTRANS_INSTR_ALIGNMENT_SHIFT)) == pagenr && cpu->translation_readahead > 0) { void (*old_f)(struct cpu *, struct DYNTRANS_IC *) = ic[i].f; /* Already translated? Then abort: */ if (old_f != TO_BE_TRANSLATED) break; /* Translate the instruction: */ ic[i].f(cpu, ic+i); /* Translation failed? Then abort. */ if (ic[i].f == old_f) break; cpu->translation_readahead --; ++i; } cpu->translation_readahead = 0; } /* * Finally finally :-), execute the instruction. * * Note: The instruction might have changed during read-ahead, if * instruction combinations are used. */ ic->f(cpu, ic); return; bad: /* * Nothing was translated. (Unimplemented or illegal instruction.) */ /* Clear the translation, in case it was "half-way" done: */ ic->f = TO_BE_TRANSLATED; if (cpu->translation_readahead) return; quiet_mode = 0; fatal("to_be_translated(): TODO: unimplemented instruction"); if (cpu->machine->instruction_trace) { if (cpu->is_32bit) fatal(" at 0x%" PRIx32"\n", (uint32_t)cpu->pc); else fatal(" at 0x%" PRIx64"\n", (uint64_t)cpu->pc); } else { fatal(":\n"); DISASSEMBLE(cpu, ib, 1, 0); } cpu->running = 0; /* Note: Single-stepping can jump here. */ stop_running_translated: debugger_n_steps_left_before_interaction = 0; ic = cpu->cd.DYNTRANS_ARCH.next_ic = ¬hing_call; cpu->cd.DYNTRANS_ARCH.next_ic ++; #ifdef DYNTRANS_DELAYSLOT /* Special hack: If the bad instruction was in a delay slot, make sure that execution does not continue anyway: */ if (cpu->delay_slot) cpu->delay_slot |= EXCEPTION_IN_DELAY_SLOT; #endif /* Execute the "nothing" instruction: */ ic->f(cpu, ic); #endif /* DYNTRANS_TO_BE_TRANSLATED_TAIL */ gxemul-0.6.1/src/cpus/cpu_mips.cc000644 001750 001750 00000145574 13402411502 017134 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * MIPS core CPU emulation. */ #include #include #include #include #include #include #include "../../config.h" #include "arcbios.h" #include "cop0.h" #include "cpu.h" #include "cpu_mips.h" #include "debugger.h" #include "devices.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "mips_cpu_types.h" #include "opcodes_mips.h" #include "settings.h" #include "symbol.h" static const char *exception_names[] = EXCEPTION_NAMES; static const char *hi6_names[] = HI6_NAMES; static const char *regimm_names[] = REGIMM_NAMES; static const char *special_names[] = SPECIAL_NAMES; static const char *special_rot_names[] = SPECIAL_ROT_NAMES; static const char *special2_names[] = SPECIAL2_NAMES; static const char *mmi_names[] = MMI_NAMES; static const char *mmi0_names[] = MMI0_NAMES; static const char *mmi1_names[] = MMI1_NAMES; static const char *mmi2_names[] = MMI2_NAMES; static const char *mmi3_names[] = MMI3_NAMES; static const char *special3_names[] = SPECIAL3_NAMES; static const char *regnames[] = MIPS_REGISTER_NAMES; static const char *cop0_names[] = COP0_NAMES; #define DYNTRANS_DUALMODE_32 #define DYNTRANS_DELAYSLOT #include "tmp_mips_head.cc" void mips_pc_to_pointers(struct cpu *); void mips32_pc_to_pointers(struct cpu *); /* * mips_cpu_new(): * * Create a new MIPS cpu object. * * Returns 1 on success, 0 if there was no valid MIPS processor with * a matching name. */ int mips_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine, int cpu_id, char *cpu_type_name) { int i, found, j, tags_size, n_cache_lines, size_per_cache_line; struct mips_cpu_type_def cpu_type_defs[] = MIPS_CPU_TYPE_DEFS; int64_t secondary_cache_size; int x, linesize; /* Scan the cpu_type_defs list for this cpu type: */ i = 0; found = -1; while (i >= 0 && cpu_type_defs[i].name != NULL) { if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) { found = i; break; } i++; } if (found == -1) return 0; cpu->memory_rw = mips_memory_rw; cpu->cd.mips.cpu_type = cpu_type_defs[found]; cpu->name = strdup(cpu->cd.mips.cpu_type.name); cpu->byte_order = EMUL_LITTLE_ENDIAN; cpu->cd.mips.gpr[MIPS_GPR_SP] = INITIAL_STACK_POINTER; if (cpu->cd.mips.cpu_type.isa_level <= 2 || cpu->cd.mips.cpu_type.isa_level == 32) cpu->is_32bit = 1; if (cpu->is_32bit) { cpu->run_instr = mips32_run_instr; cpu->update_translation_table = mips32_update_translation_table; cpu->invalidate_translation_caches = mips32_invalidate_translation_caches; cpu->invalidate_code_translation = mips32_invalidate_code_translation; } else { cpu->run_instr = mips_run_instr; cpu->update_translation_table = mips_update_translation_table; cpu->invalidate_translation_caches = mips_invalidate_translation_caches; cpu->invalidate_code_translation = mips_invalidate_code_translation; } cpu->instruction_has_delayslot = mips_cpu_instruction_has_delayslot; if (cpu_id == 0) debug("%s", cpu->cd.mips.cpu_type.name); /* * CACHES: * * 1) Use DEFAULT_PCACHE_SIZE and DEFAULT_PCACHE_LINESIZE etc. * 2) If there are specific values defined for this type of cpu, * in its cpu_type substruct, then let's use those. * 3) Values in the emul struct override both of the above. * * Once we've decided which values to use, they are stored in * the emul struct so they can be used from src/machine.c etc. */ x = DEFAULT_PCACHE_SIZE; if (cpu->cd.mips.cpu_type.pdcache) x = cpu->cd.mips.cpu_type.pdcache; if (cpu->cd.mips.cache_pdcache == 0) cpu->cd.mips.cache_pdcache = x; x = DEFAULT_PCACHE_SIZE; if (cpu->cd.mips.cpu_type.picache) x = cpu->cd.mips.cpu_type.picache; if (cpu->cd.mips.cache_picache == 0) cpu->cd.mips.cache_picache = x; if (cpu->cd.mips.cache_secondary == 0) cpu->cd.mips.cache_secondary = cpu->cd.mips.cpu_type.scache; linesize = DEFAULT_PCACHE_LINESIZE; if (cpu->cd.mips.cpu_type.pdlinesize) linesize = cpu->cd.mips.cpu_type.pdlinesize; if (cpu->cd.mips.cache_pdcache_linesize == 0) cpu->cd.mips.cache_pdcache_linesize = linesize; linesize = DEFAULT_PCACHE_LINESIZE; if (cpu->cd.mips.cpu_type.pilinesize) linesize = cpu->cd.mips.cpu_type.pilinesize; if (cpu->cd.mips.cache_picache_linesize == 0) cpu->cd.mips.cache_picache_linesize = linesize; linesize = 0; if (cpu->cd.mips.cpu_type.slinesize) linesize = cpu->cd.mips.cpu_type.slinesize; if (cpu->cd.mips.cache_secondary_linesize == 0) cpu->cd.mips.cache_secondary_linesize = linesize; /* * Primary Data and Instruction caches: */ for (i=CACHE_DATA; i<=CACHE_INSTRUCTION; i++) { switch (i) { case CACHE_DATA: x = 1 << cpu->cd.mips.cache_pdcache; linesize = 1 << cpu->cd.mips.cache_pdcache_linesize; break; case CACHE_INSTRUCTION: x = 1 << cpu->cd.mips.cache_picache; linesize = 1 << cpu->cd.mips.cache_picache_linesize; break; } /* Primary cache size and linesize: */ cpu->cd.mips.cache_size[i] = x; cpu->cd.mips.cache_linesize[i] = linesize; switch (cpu->cd.mips.cpu_type.rev) { case MIPS_R2000: case MIPS_R3000: size_per_cache_line = sizeof(struct r3000_cache_line); break; default: size_per_cache_line = 32; /* TODO */ } cpu->cd.mips.cache_mask[i] = cpu->cd.mips.cache_size[i] - 1; CHECK_ALLOCATION(cpu->cd.mips.cache[i] = (unsigned char *) malloc(cpu->cd.mips.cache_size[i])); n_cache_lines = cpu->cd.mips.cache_size[i] / cpu->cd.mips.cache_linesize[i]; tags_size = n_cache_lines * size_per_cache_line; CHECK_ALLOCATION(cpu->cd.mips.cache_tags[i] = malloc(tags_size)); /* Initialize the cache tags: */ switch (cpu->cd.mips.cpu_type.rev) { case MIPS_R2000: case MIPS_R3000: for (j=0; jcd.mips.cache_tags[i]; rp[j].tag_paddr = 0; rp[j].tag_valid = 0; } break; default: ; } /* Set cache_last_paddr to something "impossible": */ cpu->cd.mips.cache_last_paddr[i] = IMPOSSIBLE_PADDR; } /* * Secondary cache: */ secondary_cache_size = 0; if (cpu->cd.mips.cache_secondary) secondary_cache_size = 1 << cpu->cd.mips.cache_secondary; /* TODO: linesize... */ if (cpu_id == 0) { debug(" (I+D = %i+%i KB", (int)(cpu->cd.mips.cache_size[CACHE_INSTRUCTION] / 1024), (int)(cpu->cd.mips.cache_size[CACHE_DATA] / 1024)); if (secondary_cache_size != 0) { debug(", L2 = "); if (secondary_cache_size >= 1048576) debug("%i MB", (int) (secondary_cache_size / 1048576)); else debug("%i KB", (int) (secondary_cache_size / 1024)); } debug(")"); } /* Register the CPU's interrupts: */ for (i=2; i<8; i++) { struct interrupt templ; char name[50]; snprintf(name, sizeof(name), "%s.%i", cpu->path, i); memset(&templ, 0, sizeof(templ)); templ.line = 1 << (STATUS_IM_SHIFT + i); templ.name = name; templ.extra = cpu; templ.interrupt_assert = mips_cpu_interrupt_assert; templ.interrupt_deassert = mips_cpu_interrupt_deassert; interrupt_handler_register(&templ); if (i == 7) INTERRUPT_CONNECT(name, cpu->cd.mips.irq_compare); } /* System coprocessor (0), and FPU (1): */ cpu->cd.mips.coproc[0] = mips_coproc_new(cpu, 0); cpu->cd.mips.coproc[1] = mips_coproc_new(cpu, 1); switch (cpu->cd.mips.cpu_type.mmu_model) { case MMU3K: cpu->translate_v2p = translate_v2p_mmu3k; break; case MMU8K: cpu->translate_v2p = translate_v2p_mmu8k; break; case MMU10K: cpu->translate_v2p = translate_v2p_mmu10k; break; default: if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) cpu->translate_v2p = translate_v2p_mmu4100; else cpu->translate_v2p = translate_v2p_generic; } // TODO: Consider moving to src/machine/machine_test.cc? // This is only here to make the floating point tests work out-of-the-box. if (!cpu->is_32bit) cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= STATUS_FR; if (cpu->machine->prom_emulation) { /* * Default behaviour of jumping to 0xbfc00000 should be * a reboot, unless machine-specific initialization code * overrides this. * * Note: Specifically big-endian machines should override * this, since the default MIPS CPU is little-endian! */ store_32bit_word(cpu, 0xffffffff9fc00000ULL, 0x00c0de0d); } /* Add all register names to the settings: */ CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc); CPU_SETTINGS_ADD_REGISTER64("hi", cpu->cd.mips.hi); CPU_SETTINGS_ADD_REGISTER64("lo", cpu->cd.mips.lo); for (i=0; icd.mips.gpr[i]); /* TODO: Write via special handler function! */ for (i=0; icd.mips.coproc[0]->reg[i]); return 1; } /* * mips_cpu_dumpinfo(): * * Debug dump of MIPS-specific CPU data for specific CPU. */ void mips_cpu_dumpinfo(struct cpu *cpu) { int iadd = DEBUG_INDENTATION; struct mips_cpu_type_def *ct = &cpu->cd.mips.cpu_type; debug_indentation(iadd); debug("\n%i-bit %s-endian (MIPS", cpu->is_32bit? 32 : 64, cpu->byte_order == EMUL_BIG_ENDIAN? "Big" : "Little"); switch (ct->isa_level) { case 1: debug(" ISA I"); break; case 2: debug(" ISA II"); break; case 3: debug(" ISA III"); break; case 4: debug(" ISA IV"); break; case 5: debug(" ISA V"); break; case 32: case 64:debug("%i, revision %i", ct->isa_level, ct->isa_revision); break; default:debug(" ISA level %i", ct->isa_level); } debug("), "); if (ct->nr_of_tlb_entries) debug("%i TLB entries", ct->nr_of_tlb_entries); else debug("no TLB"); debug("\n"); if (ct->picache) { debug("L1 I-cache: %i KB", (1 << ct->picache) / 1024); if (ct->pilinesize) debug(", %i bytes per line", 1 << ct->pilinesize); if (ct->piways > 1) debug(", %i-way", ct->piways); else debug(", direct-mapped"); debug("\n"); } if (ct->pdcache) { debug("L1 D-cache: %i KB", (1 << ct->pdcache) / 1024); if (ct->pdlinesize) debug(", %i bytes per line", 1 << ct->pdlinesize); if (ct->pdways > 1) debug(", %i-way", ct->pdways); else debug(", direct-mapped"); debug("\n"); } if (ct->scache) { int kb = (1 << ct->scache) / 1024; debug("L2 cache: %i %s", kb >= 1024? kb / 1024 : kb, kb >= 1024? "MB":"KB"); if (ct->slinesize) debug(", %i bytes per line", 1 << ct->slinesize); if (ct->sways > 1) debug(", %i-way", ct->sways); else debug(", direct-mapped"); debug("\n"); } debug_indentation(-iadd); } /* * mips_cpu_list_available_types(): * * Print a list of available MIPS CPU types. */ void mips_cpu_list_available_types(void) { int i, j; struct mips_cpu_type_def cpu_type_defs[] = MIPS_CPU_TYPE_DEFS; i = 0; while (cpu_type_defs[i].name != NULL) { debug("%s", cpu_type_defs[i].name); for (j=10 - strlen(cpu_type_defs[i].name); j>0; j--) debug(" "); i++; if ((i % 6) == 0 || cpu_type_defs[i].name == NULL) debug("\n"); } } /* * mips_cpu_instruction_has_delayslot(): * * Return 1 if an opcode is a branch, 0 otherwise. */ int mips_cpu_instruction_has_delayslot(struct cpu *cpu, unsigned char *ib) { uint32_t iword = *((uint32_t *)&ib[0]); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) iword = LE32_TO_HOST(iword); else iword = BE32_TO_HOST(iword); switch (iword >> 26) { case HI6_SPECIAL: switch (iword & 0x3f) { case SPECIAL_JR: case SPECIAL_JALR: return 1; } break; case HI6_REGIMM: switch ((iword >> 16) & 0x1f) { case REGIMM_BLTZ: case REGIMM_BGEZ: case REGIMM_BLTZL: case REGIMM_BGEZL: case REGIMM_BLTZAL: case REGIMM_BLTZALL: case REGIMM_BGEZAL: case REGIMM_BGEZALL: return 1; } break; case HI6_BEQ: case HI6_BEQL: case HI6_BNE: case HI6_BNEL: case HI6_BGTZ: case HI6_BGTZL: case HI6_BLEZ: case HI6_BLEZL: case HI6_J: case HI6_JAL: return 1; } return 0; } /* * mips_cpu_tlbdump(): * * Called from the debugger to dump the TLB in a readable format. * x is the cpu number to dump, or -1 to dump all CPUs. * * If rawflag is nonzero, then the TLB contents isn't formated nicely, * just dumped. */ void mips_cpu_tlbdump(struct machine *m, int x, int rawflag) { int i, j; /* Raw output: */ if (rawflag) { for (i=0; incpus; i++) { struct mips_coproc *cop0 = m->cpus[i]->cd.mips.coproc[0]; if (x >= 0 && i != x) continue; /* Print index, random, and wired: */ printf("cpu%i: (", i); if (m->cpus[i]->is_32bit) printf("index=0x%08x random=0x%08x", (int) cop0->reg[COP0_INDEX], (int) cop0->reg[COP0_RANDOM]); else printf("index=0x%016" PRIx64 " random=0x%016" PRIx64, (uint64_t) cop0->reg[COP0_INDEX], (uint64_t) cop0->reg[COP0_RANDOM]); if (m->cpus[i]->cd.mips.cpu_type.isa_level >= 3) printf(" wired=0x%" PRIx64, (uint64_t) cop0->reg[COP0_WIRED]); printf(")\n"); for (j=0; jcpus[i]->cd.mips.cpu_type. nr_of_tlb_entries; j++) { if (m->cpus[i]->cd.mips.cpu_type.mmu_model == MMU3K) printf(" %02x: hi=0x%08" PRIx32" lo=0x%08" PRIx32"\n", j, (uint32_t) cop0->tlbs[j].hi, (uint32_t) cop0->tlbs[j].lo0); else if (m->cpus[i]->is_32bit) printf(" %02x: hi=0x%08" PRIx32" mask=0x" "%08" PRIx32" lo0=0x%08" PRIx32 " lo1=0x%08" PRIx32"\n", j, (uint32_t) cop0->tlbs[j].hi, (uint32_t) cop0->tlbs[j].mask, (uint32_t) cop0->tlbs[j].lo0, (uint32_t) cop0->tlbs[j].lo1); else printf(" %02x: hi=0x%016" PRIx64" mask=" "0x%016" PRIx64" lo0=0x%016" PRIx64 " lo1=0x%016" PRIx64"\n", j, (uint64_t) cop0->tlbs[j].hi, (uint64_t) cop0->tlbs[j].mask, (uint64_t) cop0->tlbs[j].lo0, (uint64_t) cop0->tlbs[j].lo1); } } return; } /* Nicely formatted output: */ for (i=0; incpus; i++) { int pageshift = 12; struct mips_coproc *cop0 = m->cpus[i]->cd.mips.coproc[0]; if (x >= 0 && i != x) continue; if (m->cpus[i]->cd.mips.cpu_type.rev == MIPS_R4100) pageshift = 10; /* Print index, random, and wired: */ printf("cpu%i: (", i); switch (m->cpus[i]->cd.mips.cpu_type.isa_level) { case 1: case 2: printf("index=0x%x random=0x%x", (int) ((cop0->reg[COP0_INDEX] & R2K3K_INDEX_MASK) >> R2K3K_INDEX_SHIFT), (int) ((cop0->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK) >> R2K3K_RANDOM_SHIFT)); break; default:printf("index=0x%x random=0x%x", (int) (cop0->reg[COP0_INDEX] & INDEX_MASK), (int) (cop0->reg[COP0_RANDOM] & RANDOM_MASK)); printf(" wired=0x%" PRIx64, (uint64_t) cop0->reg[COP0_WIRED]); } printf(")\n"); for (j=0; jcpus[i]->cd.mips.cpu_type. nr_of_tlb_entries; j++) { uint64_t hi = cop0->tlbs[j].hi; uint64_t lo0 = cop0->tlbs[j].lo0; uint64_t lo1 = cop0->tlbs[j].lo1; uint64_t mask = cop0->tlbs[j].mask; uint64_t psize; mask |= (1 << (pageshift+1)) - 1; /* here mask = e.g. 0x1fff for 4KB pages */ printf(" %02x: ", j); switch (m->cpus[i]->cd.mips.cpu_type.mmu_model) { case MMU3K: if (!(lo0 & R2K3K_ENTRYLO_V)) { printf("(invalid)\n"); continue; } printf("vaddr=0x%08x ", (int) (hi&R2K3K_ENTRYHI_VPN_MASK)); if (lo0 & R2K3K_ENTRYLO_G) printf("(global), "); else printf("(asid %02x),", (int) ((hi & R2K3K_ENTRYHI_ASID_MASK) >> R2K3K_ENTRYHI_ASID_SHIFT)); printf(" paddr=0x%08x ", (int) (lo0&R2K3K_ENTRYLO_PFN_MASK)); if (lo0 & R2K3K_ENTRYLO_N) printf("N"); if (lo0 & R2K3K_ENTRYLO_D) printf("D"); printf("\n"); break; default:switch (m->cpus[i]->cd.mips.cpu_type.mmu_model){ case MMU32: printf("vaddr=0x%08" PRIx32" ", (uint32_t) (hi & ~mask)); break; default:/* R4x00, R1x000, MIPS64, etc. */ printf("vaddr=%016" PRIx64" ", (uint64_t) (hi & ~mask)); } if (hi & TLB_G) printf("(global): "); else printf("(asid %02x):", (int) (hi & ENTRYHI_ASID)); /* TODO: Coherency bits */ if (!(lo0 & ENTRYLO_V)) printf(" p0=(invalid) "); else { uint64_t paddr = lo0 & ENTRYLO_PFN_MASK; paddr >>= ENTRYLO_PFN_SHIFT; paddr <<= pageshift; paddr &= ~(mask >> 1); printf(" p0=0x%09" PRIx64" ", (uint64_t) paddr); } printf(lo0 & ENTRYLO_D? "D" : " "); if (!(lo1 & ENTRYLO_V)) printf(" p1=(invalid) "); else { uint64_t paddr = lo1 & ENTRYLO_PFN_MASK; paddr >>= ENTRYLO_PFN_SHIFT; paddr <<= pageshift; paddr &= ~(mask >> 1); printf(" p1=0x%09" PRIx64" ", (uint64_t) paddr); } printf(lo1 & ENTRYLO_D? "D" : " "); /* convert e.g. 0x1fff to 4096 */ psize = (mask + 1) >> 1; if (psize >= 1024 && psize <= 256*1024) printf(" (%iKB)", (int) (psize >> 10)); else if (psize >= 1024*1024 && psize <= 64*1024*1024) printf(" (%iMB)", (int) (psize >> 20)); else printf(" (?)"); printf("\n"); } } } } /* * mips_cpu_disassemble_instr(): * * Convert an instruction word into human readable format, for instruction * tracing. * * If running is 1, cpu->pc should be the address of the instruction. * * If running is 0, things that depend on the runtime environment (eg. * register contents) will not be shown, and addr will be used instead of * cpu->pc for relative addresses. * * NOTE 2: coprocessor instructions are not decoded nicely yet (TODO) */ int mips_cpu_disassemble_instr(struct cpu *cpu, unsigned char *originstr, int running, uint64_t dumpaddr) { int hi6, special6, regimm5, sub; int rt, rd, rs, sa, imm, copz, cache_op, which_cache, showtag; uint64_t addr, offset; uint32_t instrword; unsigned char instr[4]; char *symbol; if (running) dumpaddr = cpu->pc; if ((dumpaddr & 3) != 0) printf("WARNING: Unaligned address!\n"); symbol = get_symbol_name(&cpu->machine->symbol_context, dumpaddr, &offset); if (symbol != NULL && offset==0) debug("<%s>\n", symbol); if (cpu->machine->ncpus > 1 && running) debug("cpu%i: ", cpu->cpu_id); if (cpu->is_32bit) debug("%08" PRIx32, (uint32_t)dumpaddr); else debug("%016" PRIx64, (uint64_t)dumpaddr); memcpy(instr, originstr, sizeof(uint32_t)); /* * The rest of the code is written for little endian, * so swap if necessary: */ if (cpu->byte_order == EMUL_BIG_ENDIAN) { int tmp = instr[0]; instr[0] = instr[3]; instr[3] = tmp; tmp = instr[1]; instr[1] = instr[2]; instr[2] = tmp; } debug(": %02x%02x%02x%02x", instr[3], instr[2], instr[1], instr[0]); if (running && cpu->delay_slot) debug(" (d)"); debug("\t"); /* * Decode the instruction: */ hi6 = (instr[3] >> 2) & 0x3f; switch (hi6) { case HI6_SPECIAL: special6 = instr[0] & 0x3f; switch (special6) { case SPECIAL_SLL: case SPECIAL_SRL: case SPECIAL_SRA: case SPECIAL_DSLL: case SPECIAL_DSRL: case SPECIAL_DSRA: case SPECIAL_DSLL32: case SPECIAL_DSRL32: case SPECIAL_DSRA32: sub = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rt = instr[2] & 31; rd = (instr[1] >> 3) & 31; sa = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3); if (rd == 0 && special6 == SPECIAL_SLL) { if (sa == 0) debug("nop"); else if (sa == 1) debug("ssnop"); else if (sa == 3) debug("ehb"); else debug("nop (weird, sa=%i)", sa); break; } switch (sub) { case 0x00: debug("%s\t%s,", special_names[special6], regnames[rd]); debug("%s,%i", regnames[rt], sa); break; case 0x01: debug("%s\t%s,", special_rot_names[special6], regnames[rd]); debug("%s,%i", regnames[rt], sa); break; default:debug("UNIMPLEMENTED special, sub=0x%02x\n", sub); } break; case SPECIAL_DSRLV: case SPECIAL_DSRAV: case SPECIAL_DSLLV: case SPECIAL_SLLV: case SPECIAL_SRAV: case SPECIAL_SRLV: rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rt = instr[2] & 31; rd = (instr[1] >> 3) & 31; sub = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3); switch (sub) { case 0x00: debug("%s\t%s", special_names[special6], regnames[rd]); debug(",%s", regnames[rt]); debug(",%s", regnames[rs]); break; case 0x01: debug("%s\t%s", special_rot_names[special6], regnames[rd]); debug(",%s", regnames[rt]); debug(",%s", regnames[rs]); break; default:debug("UNIMPLEMENTED special, sub=0x%02x\n", sub); } break; case SPECIAL_JR: rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->cd.mips.gpr[rs], &offset); /* .hb = hazard barrier hint on MIPS32/64 rev 2 */ debug("jr%s\t%s", (instr[1] & 0x04) ? ".hb" : "", regnames[rs]); if (running && symbol != NULL) debug("\t<%s>", symbol); break; case SPECIAL_JALR: rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rd = (instr[1] >> 3) & 31; symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->cd.mips.gpr[rs], &offset); /* .hb = hazard barrier hint on MIPS32/64 rev 2 */ debug("jalr%s\t%s", (instr[1] & 0x04) ? ".hb" : "", regnames[rd]); debug(",%s", regnames[rs]); if (running && symbol != NULL) debug("\t<%s>", symbol); break; case SPECIAL_MFHI: case SPECIAL_MFLO: rd = (instr[1] >> 3) & 31; debug("%s\t%s", special_names[special6], regnames[rd]); break; case SPECIAL_MTLO: case SPECIAL_MTHI: rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); debug("%s\t%s", special_names[special6], regnames[rs]); break; case SPECIAL_ADD: case SPECIAL_ADDU: case SPECIAL_SUB: case SPECIAL_SUBU: case SPECIAL_AND: case SPECIAL_OR: case SPECIAL_XOR: case SPECIAL_NOR: case SPECIAL_SLT: case SPECIAL_SLTU: case SPECIAL_DADD: case SPECIAL_DADDU: case SPECIAL_DSUB: case SPECIAL_DSUBU: case SPECIAL_MOVZ: case SPECIAL_MOVN: rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rt = instr[2] & 31; rd = (instr[1] >> 3) & 31; if (cpu->is_32bit && (special6 == SPECIAL_ADDU || special6 == SPECIAL_SUBU) && rt == 0) { /* Special case 1: addu/subu with rt = the zero register ==> move */ debug("move\t%s", regnames[rd]); debug(",%s", regnames[rs]); } else if (special6 == SPECIAL_ADDU && cpu->is_32bit && rs == 0) { /* Special case 2: addu with rs = the zero register ==> move */ debug("move\t%s", regnames[rd]); debug(",%s", regnames[rt]); } else { debug("%s\t%s", special_names[special6], regnames[rd]); debug(",%s", regnames[rs]); debug(",%s", regnames[rt]); } break; case SPECIAL_MULT: case SPECIAL_MULTU: case SPECIAL_DMULT: case SPECIAL_DMULTU: case SPECIAL_DIV: case SPECIAL_DIVU: case SPECIAL_DDIV: case SPECIAL_DDIVU: rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rt = instr[2] & 31; rd = (instr[1] >> 3) & 31; debug("%s\t", special_names[special6]); if (rd != 0) { if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { if (special6 == SPECIAL_MULT || special6 == SPECIAL_MULTU) debug("%s,", regnames[rd]); else debug("WEIRD_R5900_RD,"); } else { debug("WEIRD_RD_NONZERO,"); } } debug("%s", regnames[rs]); debug(",%s", regnames[rt]); break; case SPECIAL_TGE: case SPECIAL_TGEU: case SPECIAL_TLT: case SPECIAL_TLTU: case SPECIAL_TEQ: case SPECIAL_TNE: rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rt = instr[2] & 31; rd = ((instr[1] << 8) + instr[0]) >> 6; // code, not rd debug("%s\t", special_names[special6]); debug("%s", regnames[rs]); debug(",%s", regnames[rt]); if (rd != 0) debug(",0x%x", rd); break; case SPECIAL_SYNC: imm = ((instr[1] & 7) << 2) + (instr[0] >> 6); debug("sync\t0x%02x", imm); break; case SPECIAL_SYSCALL: imm = (((instr[3] << 24) + (instr[2] << 16) + (instr[1] << 8) + instr[0]) >> 6) & 0xfffff; if (imm != 0) debug("syscall\t0x%05x", imm); else debug("syscall"); break; case SPECIAL_BREAK: imm = (((instr[3] << 24) + (instr[2] << 16) + (instr[1] << 8) + instr[0]) >> 6) & 0xfffff; if (imm != 0) debug("break\t0x%05x", imm); else debug("break"); break; case SPECIAL_MFSA: if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { rd = (instr[1] >> 3) & 31; debug("mfsa\t%s", regnames[rd]); } else { debug("unimplemented special 0x28"); } break; case SPECIAL_MTSA: if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); debug("mtsa\t%s", regnames[rs]); } else { debug("unimplemented special 0x29"); } break; default: debug("%s\t= UNIMPLEMENTED", special_names[special6]); } break; case HI6_BEQ: case HI6_BEQL: case HI6_BNE: case HI6_BNEL: case HI6_BGTZ: case HI6_BGTZL: case HI6_BLEZ: case HI6_BLEZL: rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rt = instr[2] & 31; imm = (instr[1] << 8) + instr[0]; if (imm >= 32768) imm -= 65536; addr = (dumpaddr + 4) + (imm << 2); if (hi6 == HI6_BEQ && rt == MIPS_GPR_ZERO && rs == MIPS_GPR_ZERO) debug("b\t"); else { debug("%s\t", hi6_names[hi6]); switch (hi6) { case HI6_BEQ: case HI6_BEQL: case HI6_BNE: case HI6_BNEL: debug("%s,", regnames[rt]); } debug("%s,", regnames[rs]); } if (cpu->is_32bit) debug("0x%08" PRIx32, (uint32_t)addr); else debug("0x%016" PRIx64, (uint64_t)addr); symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); if (symbol != NULL && offset != addr) debug("\t<%s>", symbol); break; case HI6_ADDI: case HI6_ADDIU: case HI6_DADDI: case HI6_DADDIU: case HI6_SLTI: case HI6_SLTIU: case HI6_ANDI: case HI6_ORI: case HI6_XORI: rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rt = instr[2] & 31; imm = (instr[1] << 8) + instr[0]; if (imm >= 32768) imm -= 65536; debug("%s\t%s,", hi6_names[hi6], regnames[rt]); debug("%s,", regnames[rs]); if (hi6 == HI6_ANDI || hi6 == HI6_ORI || hi6 == HI6_XORI) debug("0x%04x", imm & 0xffff); else debug("%i", imm); break; case HI6_LUI: rt = instr[2] & 31; imm = (instr[1] << 8) + instr[0]; debug("lui\t%s,0x%x", regnames[rt], imm); break; case HI6_LB: case HI6_LBU: case HI6_LH: case HI6_LHU: case HI6_LW: case HI6_LWU: case HI6_LD: case HI6_LQ_MDMX: case HI6_LWC1: case HI6_LWC2: case HI6_LWC3: case HI6_LDC1: case HI6_LDC2: case HI6_LL: case HI6_LLD: case HI6_SB: case HI6_SH: case HI6_SW: case HI6_SD: case HI6_SQ_SPECIAL3: case HI6_SC: case HI6_SCD: case HI6_SWC1: case HI6_SWC2: case HI6_SWC3: case HI6_SDC1: case HI6_SDC2: case HI6_LWL: case HI6_LWR: case HI6_LDL: case HI6_LDR: case HI6_SWL: case HI6_SWR: case HI6_SDL: case HI6_SDR: if (hi6 == HI6_LQ_MDMX && cpu->cd.mips.cpu_type.rev != MIPS_R5900) { debug("mdmx\t(UNIMPLEMENTED)"); break; } if (hi6 == HI6_SQ_SPECIAL3 && cpu->cd.mips.cpu_type.rev != MIPS_R5900) { int msbd, lsb, sub10; special6 = instr[0] & 0x3f; rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rt = instr[2] & 31; rd = msbd = (instr[1] >> 3) & 31; lsb = ((instr[1] & 7) << 2) | (instr[0] >> 6); sub10 = (rs << 5) | lsb; switch (special6) { case SPECIAL3_EXT: case SPECIAL3_DEXT: case SPECIAL3_DEXTM: case SPECIAL3_DEXTU: debug("%s", special3_names[special6]); if (special6 == SPECIAL3_DEXTM) msbd += 32; if (special6 == SPECIAL3_DEXTU) lsb += 32; debug("\t%s", regnames[rt]); debug(",%s", regnames[rs]); debug(",%i,%i", lsb, msbd + 1); break; case SPECIAL3_INS: case SPECIAL3_DINS: case SPECIAL3_DINSM: case SPECIAL3_DINSU: debug("%s", special3_names[special6]); if (special6 == SPECIAL3_DINSM) msbd += 32; if (special6 == SPECIAL3_DINSU) { lsb += 32; msbd += 32; } msbd -= lsb; debug("\t%s", regnames[rt]); debug(",%s", regnames[rs]); debug(",%i,%i", lsb, msbd + 1); break; case SPECIAL3_BSHFL: switch (sub10) { case BSHFL_WSBH: case BSHFL_SEB: case BSHFL_SEH: switch (sub10) { case BSHFL_WSBH: debug("wsbh"); break; case BSHFL_SEB: debug("seb"); break; case BSHFL_SEH: debug("seh"); break; } debug("\t%s", regnames[rd]); debug(",%s", regnames[rt]); break; default:debug("%s", special3_names[special6]); debug("\t(UNIMPLEMENTED)"); } break; case SPECIAL3_DBSHFL: switch (sub10) { case BSHFL_DSBH: case BSHFL_DSHD: switch (sub10) { case BSHFL_DSBH: debug("dsbh"); break; case BSHFL_DSHD: debug("dshd"); break; } debug("\t%s", regnames[rd]); debug(",%s", regnames[rt]); break; default:debug("%s", special3_names[special6]); debug("\t(UNIMPLEMENTED)"); } break; case SPECIAL3_RDHWR: debug("%s", special3_names[special6]); debug("\t%s", regnames[rt]); debug(",hwr%i", rd); break; default:debug("%s", special3_names[special6]); debug("\t(UNIMPLEMENTED)"); } break; } rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rt = instr[2] & 31; imm = (instr[1] << 8) + instr[0]; if (imm >= 32768) imm -= 65536; symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->cd.mips.gpr[rs] + imm, &offset); /* LWC3 is PREF in the newer ISA levels: */ /* TODO: Which ISAs? IV? V? 32? 64? */ if (cpu->cd.mips.cpu_type.isa_level >= 4 && hi6 == HI6_LWC3) { debug("pref\t0x%x,%i(%s)", rt, imm, regnames[rs]); if (running) { debug("\t[0x%016" PRIx64" = %s]", (uint64_t)(cpu->cd.mips.gpr[rs] + imm)); if (symbol != NULL) debug(" = %s", symbol); debug("]"); } goto disasm_ret; } debug("%s\t", hi6_names[hi6]); if (hi6 == HI6_SWC1 || hi6 == HI6_SWC2 || hi6 == HI6_SWC3 || hi6 == HI6_SDC1 || hi6 == HI6_SDC2 || hi6 == HI6_LWC1 || hi6 == HI6_LWC2 || hi6 == HI6_LWC3 || hi6 == HI6_LDC1 || hi6 == HI6_LDC2) debug("r%i", rt); else debug("%s", regnames[rt]); debug(",%i(%s)", imm, regnames[rs]); if (running) { debug("\t["); if (cpu->is_32bit) debug("0x%08" PRIx32, (uint32_t) (cpu->cd.mips.gpr[rs] + imm)); else debug("0x%016" PRIx64, (uint64_t) (cpu->cd.mips.gpr[rs] + imm)); if (symbol != NULL) debug(" = %s", symbol); /* TODO: In some cases, it is possible to peek into memory, and display that data here, like for the other emulation modes. */ debug("]"); } break; case HI6_J: case HI6_JAL: imm = (((instr[3] & 3) << 24) + (instr[2] << 16) + (instr[1] << 8) + instr[0]) << 2; addr = (dumpaddr + 4) & ~((1 << 28) - 1); addr |= imm; symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); debug("%s\t0x", hi6_names[hi6]); if (cpu->is_32bit) debug("%08" PRIx32, (uint32_t) addr); else debug("%016" PRIx64, (uint64_t) addr); if (symbol != NULL) debug("\t<%s>", symbol); break; case HI6_COP0: case HI6_COP1: case HI6_COP2: case HI6_COP3: imm = (instr[3] << 24) + (instr[2] << 16) + (instr[1] << 8) + instr[0]; imm &= ((1 << 26) - 1); /* Call coproc_function(), but ONLY disassembly, no exec: */ coproc_function(cpu, cpu->cd.mips.coproc[hi6 - HI6_COP0], hi6 - HI6_COP0, imm, 1, running); return sizeof(instrword); case HI6_CACHE: rt = ((instr[3] & 3) << 3) + (instr[2] >> 5); /* base */ copz = instr[2] & 31; imm = (instr[1] << 8) + instr[0]; cache_op = copz >> 2; which_cache = copz & 3; showtag = 0; debug("cache\t0x%02x,0x%04x(%s)", copz, imm, regnames[rt]); if (which_cache==0) debug(" [ primary I-cache"); if (which_cache==1) debug(" [ primary D-cache"); if (which_cache==2) debug(" [ secondary I-cache"); if (which_cache==3) debug(" [ secondary D-cache"); debug(", "); if (cache_op==0) debug("index invalidate"); if (cache_op==1) debug("index load tag"); if (cache_op==2) debug("index store tag"), showtag=1; if (cache_op==3) debug("create dirty exclusive"); if (cache_op==4) debug("hit invalidate"); if (cache_op==5) debug("fill OR hit writeback invalidate"); if (cache_op==6) debug("hit writeback"); if (cache_op==7) debug("hit set virtual"); if (running) debug(", addr 0x%016" PRIx64, (uint64_t)(cpu->cd.mips.gpr[rt] + imm)); if (showtag) debug(", taghi=%08lx lo=%08lx", (long)cpu->cd.mips.coproc[0]->reg[COP0_TAGDATA_HI], (long)cpu->cd.mips.coproc[0]->reg[COP0_TAGDATA_LO]); debug(" ]"); break; case HI6_SPECIAL2: special6 = instr[0] & 0x3f; instrword = (instr[3] << 24) + (instr[2] << 16) + (instr[1] << 8) + instr[0]; rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rt = instr[2] & 31; rd = (instr[1] >> 3) & 31; if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { int c790mmifunc = (instrword >> 6) & 0x1f; if (special6 != MMI_MMI0 && special6 != MMI_MMI1 && special6 != MMI_MMI2 && special6 != MMI_MMI3) debug("%s\t", mmi_names[special6]); switch (special6) { case MMI_MADD: case MMI_MADDU: if (rd != MIPS_GPR_ZERO) { debug("%s,", regnames[rd]); } debug("%s,%s", regnames[rs], regnames[rt]); break; case MMI_MMI0: debug("%s\t", mmi0_names[c790mmifunc]); switch (c790mmifunc) { case MMI0_PEXTLB: case MMI0_PEXTLH: case MMI0_PEXTLW: case MMI0_PMAXH: case MMI0_PMAXW: case MMI0_PPACB: case MMI0_PPACH: case MMI0_PPACW: debug("%s,%s,%s", regnames[rd], regnames[rs], regnames[rt]); break; default:debug("(UNIMPLEMENTED)"); } break; case MMI_MMI1: debug("%s\t", mmi1_names[c790mmifunc]); switch (c790mmifunc) { case MMI1_PEXTUB: case MMI1_PEXTUH: case MMI1_PEXTUW: case MMI1_PMINH: case MMI1_PMINW: debug("%s,%s,%s", regnames[rd], regnames[rs], regnames[rt]); break; default:debug("(UNIMPLEMENTED)"); } break; case MMI_MMI2: debug("%s\t", mmi2_names[c790mmifunc]); switch (c790mmifunc) { case MMI2_PMFHI: case MMI2_PMFLO: debug("%s", regnames[rd]); break; case MMI2_PHMADH: case MMI2_PHMSBH: case MMI2_PINTH: case MMI2_PMADDH: case MMI2_PMADDW: case MMI2_PMSUBH: case MMI2_PMSUBW: case MMI2_PMULTH: case MMI2_PMULTW: case MMI2_PSLLVW: debug("%s,%s,%s", regnames[rd], regnames[rs], regnames[rt]); break; default:debug("(UNIMPLEMENTED)"); } break; case MMI_MMI3: debug("%s\t", mmi3_names[c790mmifunc]); switch (c790mmifunc) { case MMI3_PMTHI: case MMI3_PMTLO: debug("%s", regnames[rs]); break; case MMI3_PINTEH: case MMI3_PMADDUW: case MMI3_PMULTUW: case MMI3_PNOR: case MMI3_POR: case MMI3_PSRAVW: debug("%s,%s,%s", regnames[rd], regnames[rs], regnames[rt]); break; default:debug("(UNIMPLEMENTED)"); } break; default:debug("(UNIMPLEMENTED)"); } break; } /* SPECIAL2: */ debug("%s\t", special2_names[special6]); switch (special6) { case SPECIAL2_MADD: case SPECIAL2_MADDU: case SPECIAL2_MSUB: case SPECIAL2_MSUBU: if (rd != MIPS_GPR_ZERO) { debug("WEIRD_NONZERO_RD(%s),", regnames[rd]); } debug("%s,%s", regnames[rs], regnames[rt]); break; case SPECIAL2_MUL: /* Apparently used both on R5900 and MIPS32: */ debug("%s,%s,%s", regnames[rd], regnames[rs], regnames[rt]); break; case SPECIAL2_CLZ: case SPECIAL2_CLO: case SPECIAL2_DCLZ: case SPECIAL2_DCLO: debug("%s,%s", regnames[rd], regnames[rs]); break; default: debug("(UNIMPLEMENTED)"); } break; case HI6_REGIMM: regimm5 = instr[2] & 0x1f; rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); imm = (instr[1] << 8) + instr[0]; if (imm >= 32768) imm -= 65536; switch (regimm5) { case REGIMM_BLTZ: case REGIMM_BGEZ: case REGIMM_BLTZL: case REGIMM_BGEZL: case REGIMM_BLTZAL: case REGIMM_BLTZALL: case REGIMM_BGEZAL: case REGIMM_BGEZALL: debug("%s\t%s,", regimm_names[regimm5], regnames[rs]); addr = (dumpaddr + 4) + (imm << 2); if (cpu->is_32bit) debug("0x%08" PRIx32, (uint32_t) addr); else debug("0x%016" PRIx64, (uint64_t) addr); break; case REGIMM_SYNCI: debug("%s\t%i(%s)", regimm_names[regimm5], imm, regnames[rs]); break; default: debug("unimplemented regimm5 = 0x%02x", regimm5); } break; default: debug("unimplemented hi6 = 0x%02x", hi6); } disasm_ret: debug("\n"); return sizeof(instrword); } /* * mips_cpu_register_dump(): * * Dump cpu registers in a relatively readable format. * * gprs: set to non-zero to dump GPRs and hi/lo/pc * coprocs: set bit 0..3 to dump registers in coproc 0..3. */ void mips_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs) { int coprocnr, i, bits32; uint64_t offset; char *symbol; int bits128 = cpu->cd.mips.cpu_type.rev == MIPS_R5900; bits32 = cpu->is_32bit; if (gprs) { /* Special registers (pc, hi/lo) first: */ symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->pc, &offset); if (bits32) debug("cpu%i: pc = %08" PRIx32, cpu->cpu_id, (uint32_t) cpu->pc); else if (bits128) debug("cpu%i: pc=%016" PRIx64, cpu->cpu_id, (uint64_t) cpu->pc); else debug("cpu%i: pc = 0x%016" PRIx64, cpu->cpu_id, (uint64_t) cpu->pc); debug(" <%s>\n", symbol != NULL? symbol : " no symbol "); if (bits32) debug("cpu%i: hi = %08" PRIx32" lo = %08" PRIx32"\n", cpu->cpu_id, (uint32_t) cpu->cd.mips.hi, (uint32_t) cpu->cd.mips.lo); else if (bits128) { debug("cpu%i: hi=%016" PRIx64"%016" PRIx64" lo=" "%016" PRIx64"%016" PRIx64"\n", cpu->cpu_id, cpu->cd.mips.hi1, cpu->cd.mips.hi, cpu->cd.mips.lo1, cpu->cd.mips.lo); } else { debug("cpu%i: hi = 0x%016" PRIx64" lo = 0x%016" PRIx64"\n", cpu->cpu_id, (uint64_t) cpu->cd.mips.hi, (uint64_t) cpu->cd.mips.lo); } /* General registers: */ if (bits128) { /* 128-bit: */ for (i=0; i<32; i++) { int r = (i >> 1) + ((i & 1) << 4); if ((i & 1) == 0) debug("cpu%i:", cpu->cpu_id); if (r == MIPS_GPR_ZERO) debug(" " " "); else debug(" %3s=%016" PRIx64"%016" PRIx64, regnames[r], (uint64_t) cpu->cd.mips.gpr_quadhi[r], (uint64_t)cpu->cd.mips.gpr[r]); if ((i & 1) == 1) debug("\n"); } } else if (bits32) { /* 32-bit: */ for (i=0; i<32; i++) { if ((i & 3) == 0) debug("cpu%i:", cpu->cpu_id); if (i == MIPS_GPR_ZERO) debug(" "); else debug(" %3s = %08" PRIx32, regnames[i], (uint32_t)cpu->cd.mips.gpr[i]); if ((i & 3) == 3) debug("\n"); } } else { /* 64-bit: */ for (i=0; i<32; i++) { int r = (i >> 1) + ((i & 1) << 4); if ((i & 1) == 0) debug("cpu%i:", cpu->cpu_id); if (r == MIPS_GPR_ZERO) debug(" "); else debug(" %3s = 0x%016" PRIx64, regnames[r], (uint64_t)cpu->cd.mips.gpr[r]); if ((i & 1) == 1) debug("\n"); } } } for (coprocnr=0; coprocnr<4; coprocnr++) { int nm1 = 1; if (bits32) nm1 = 3; if (!(coprocs & (1<cd.mips.coproc[coprocnr] == NULL) { debug("cpu%i: no coprocessor %i\n", cpu->cpu_id, coprocnr); continue; } /* Coprocessor registers: */ for (i=0; i<32; i++) { /* 32-bit: */ if ((i & nm1) == 0) debug("cpu%i:", cpu->cpu_id); if (coprocnr == 0) debug(" %8s", cop0_names[i]); else debug(" c%i,%02i", coprocnr, i); if (bits32) debug("=%08x", (int)cpu->cd.mips. coproc[coprocnr]->reg[i]); else { if (coprocnr == 0 && (i == COP0_COUNT || i == COP0_COMPARE || i == COP0_INDEX || i == COP0_RANDOM || i == COP0_WIRED)) debug(" = 0x%08x", (int) cpu->cd.mips.coproc[ coprocnr]->reg[i]); else debug(" = 0x%016" PRIx64, (uint64_t) cpu->cd.mips.coproc[ coprocnr]->reg[i]); } if ((i & nm1) == nm1) debug("\n"); /* Skip the last 16 cop0 registers on R3000 etc. */ if (coprocnr == 0 && cpu->cd.mips.cpu_type.isa_level < 3 && i == 15) i = 31; } if (coprocnr == 0 && cpu->cd.mips.cpu_type.isa_level >= 32) { debug("cpu%i: ", cpu->cpu_id); debug("config_select1 = 0x"); if (cpu->is_32bit) debug("%08" PRIx32, (uint32_t)cpu->cd.mips.cop0_config_select1); else debug("%016" PRIx64, (uint64_t)cpu->cd.mips.cop0_config_select1); debug("\n"); } /* Floating point control registers: */ if (coprocnr == 1) { for (i=0; i<32; i++) switch (i) { case MIPS_FPU_FCIR: printf("cpu%i: fcr0 (fcir) = 0x%08x\n", cpu->cpu_id, (int)cpu->cd.mips. coproc[coprocnr]->fcr[i]); break; case MIPS_FPU_FCCR: printf("cpu%i: fcr25 (fccr) = 0x%08x\n", cpu->cpu_id, (int)cpu->cd.mips. coproc[coprocnr]->fcr[i]); break; case MIPS_FPU_FCSR: printf("cpu%i: fcr31 (fcsr) = 0x%08x\n", cpu->cpu_id, (int)cpu->cd.mips. coproc[coprocnr]->fcr[i]); break; } } } if (cpu->cd.mips.rmw) { printf("cpu%i: Read-Modify-Write in progress, address " "0x%016" PRIx64"\n", cpu->cpu_id, cpu->cd.mips.rmw_addr); } } /* * mips_cpu_interrupt_assert(), mips_cpu_interrupt_deassert(): * * Assert or deassert a MIPS CPU interrupt by masking in or out bits * in the CAUSE register of coprocessor 0. */ void mips_cpu_interrupt_assert(struct interrupt *interrupt) { struct cpu *cpu = (struct cpu *) interrupt->extra; cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] |= interrupt->line; } void mips_cpu_interrupt_deassert(struct interrupt *interrupt) { struct cpu *cpu = (struct cpu *) interrupt->extra; cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] &= ~interrupt->line; } /* * mips_cpu_exception(): * * Cause an exception in a CPU. This sets a couple of coprocessor 0 * registers, and the program counter. * * exccode the exception code * tlb set to non-zero if the exception handler at * 0x80000000 should be used. (normal = 0x80000180) * vaddr virtual address (for some exceptions) * coproc_nr coprocessor number (for some exceptions) * vaddr_vpn2 vpn2 (for some exceptions) * vaddr_asid asid (for some exceptions) * x_64 non-zero for 64-bit mode for R4000-style tlb misses */ void mips_cpu_exception(struct cpu *cpu, int exccode, int tlb, uint64_t vaddr, int coproc_nr, uint64_t vaddr_vpn2, int vaddr_asid, int x_64) { uint64_t base; uint64_t *reg = &cpu->cd.mips.coproc[0]->reg[0]; int exc_model = cpu->cd.mips.cpu_type.exc_model; if (cpu->is_halted) { /* * If the exception occurred on a 'wait' instruction, then let * the instruction following the wait instruction be the one * we continue at when the interrupt service routine returns. */ cpu->is_halted = 0; cpu->pc += sizeof(uint32_t); } if (!quiet_mode) { uint64_t offset; int x; char *symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->pc, &offset); debug("[ "); if (cpu->machine->ncpus > 1) debug("cpu%i: ", cpu->cpu_id); debug("exception %s%s", exception_names[exccode], tlb? " " : ""); switch (exccode) { case EXCEPTION_INT: debug(" cause_im=0x%02x", (int) ((reg[COP0_CAUSE] & CAUSE_IP_MASK) >> CAUSE_IP_SHIFT)); break; case EXCEPTION_SYS: debug(" v0=%i", (int)cpu->cd.mips.gpr[MIPS_GPR_V0]); for (x=0; x<4; x++) { int64_t d = cpu->cd.mips.gpr[MIPS_GPR_A0 + x]; char strbuf[30]; if (d > -256 && d < 256) { debug(" a%i=%i", x, (int)d); } else if (memory_points_to_string(cpu, cpu->mem, d, 1)) { debug(" a%i=\"%s\"", x, memory_conv_to_string(cpu, cpu->mem, d, strbuf, sizeof(strbuf))); } else { if (cpu->is_32bit) debug(" a%i=0x%" PRIx32, x, (uint32_t)d); else debug(" a%i=0x%" PRIx64, x, (uint64_t)d); } } break; case EXCEPTION_CPU: debug(" coproc_nr=%i", coproc_nr); break; default: if (cpu->is_32bit) debug(" vaddr=0x%08x", (int)vaddr); else debug(" vaddr=0x%016" PRIx64, (uint64_t)vaddr); } if (cpu->is_32bit) debug(" pc=0x%08" PRIx32" ", (uint32_t)cpu->pc); else debug(" pc=0x%016" PRIx64" ", (uint64_t)cpu->pc); if (symbol != NULL) debug("<%s> ]\n", symbol); else debug("]\n"); } if (tlb && vaddr < 0x1000) { uint64_t offset; char *symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->pc, &offset); fatal("[ "); if (cpu->machine->ncpus > 1) fatal("cpu%i: ", cpu->cpu_id); fatal("warning: LOW reference: vaddr="); if (cpu->is_32bit) fatal("0x%08" PRIx32, (uint32_t) vaddr); else fatal("0x%016" PRIx64, (uint64_t) vaddr); fatal(", exception %s, pc=", exception_names[exccode]); if (cpu->is_32bit) fatal("0x%08" PRIx32, (uint32_t) cpu->pc); else fatal("0x%016" PRIx64, (uint64_t)cpu->pc); fatal(" <%s> ]\n", symbol? symbol : "(no symbol)"); } /* Clear the exception code bits of the cause register... */ if (exc_model == EXC3K) reg[COP0_CAUSE] &= ~R2K3K_CAUSE_EXCCODE_MASK; else reg[COP0_CAUSE] &= ~CAUSE_EXCCODE_MASK; /* ... and OR in the exception code: */ reg[COP0_CAUSE] |= (exccode << CAUSE_EXCCODE_SHIFT); /* Always set CE (according to the R5000 manual): */ reg[COP0_CAUSE] &= ~CAUSE_CE_MASK; reg[COP0_CAUSE] |= (coproc_nr << CAUSE_CE_SHIFT); if (tlb || (exccode >= EXCEPTION_MOD && exccode <= EXCEPTION_ADES) || exccode == EXCEPTION_VCEI || exccode == EXCEPTION_VCED) { reg[COP0_BADVADDR] = vaddr; if (cpu->is_32bit) reg[COP0_BADVADDR] = (int32_t)reg[COP0_BADVADDR]; if (exc_model == EXC3K) { reg[COP0_CONTEXT] &= ~R2K3K_CONTEXT_BADVPN_MASK; reg[COP0_CONTEXT] |= ((vaddr_vpn2 << R2K3K_CONTEXT_BADVPN_SHIFT) & R2K3K_CONTEXT_BADVPN_MASK); reg[COP0_ENTRYHI] = (vaddr & R2K3K_ENTRYHI_VPN_MASK) | (vaddr_asid << R2K3K_ENTRYHI_ASID_SHIFT); /* Sign-extend: */ reg[COP0_CONTEXT] = (int64_t)(int32_t)reg[COP0_CONTEXT]; reg[COP0_ENTRYHI] = (int64_t)(int32_t)reg[COP0_ENTRYHI]; } else { if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) { reg[COP0_CONTEXT] &= ~CONTEXT_BADVPN2_MASK_R4100; reg[COP0_CONTEXT] |= ((vaddr_vpn2 << CONTEXT_BADVPN2_SHIFT) & CONTEXT_BADVPN2_MASK_R4100); /* TODO: fix these */ reg[COP0_XCONTEXT] &= ~XCONTEXT_R_MASK; reg[COP0_XCONTEXT] &= ~XCONTEXT_BADVPN2_MASK; reg[COP0_XCONTEXT] |= (vaddr_vpn2 << XCONTEXT_BADVPN2_SHIFT) & XCONTEXT_BADVPN2_MASK; reg[COP0_XCONTEXT] |= ((vaddr >> 62) & 0x3) << XCONTEXT_R_SHIFT; /* reg[COP0_PAGEMASK] = cpu->cd.mips.coproc[0]->tlbs[0].mask & PAGEMASK_MASK; */ reg[COP0_ENTRYHI] = (vaddr & (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | 0x1800)) | vaddr_asid; } else { reg[COP0_CONTEXT] &= ~CONTEXT_BADVPN2_MASK; reg[COP0_CONTEXT] |= ((vaddr_vpn2 << CONTEXT_BADVPN2_SHIFT) & CONTEXT_BADVPN2_MASK); reg[COP0_XCONTEXT] &= ~XCONTEXT_R_MASK; reg[COP0_XCONTEXT] &= ~XCONTEXT_BADVPN2_MASK; reg[COP0_XCONTEXT] |= (vaddr_vpn2 << XCONTEXT_BADVPN2_SHIFT) & XCONTEXT_BADVPN2_MASK; reg[COP0_XCONTEXT] |= ((vaddr >> 62) & 0x3) << XCONTEXT_R_SHIFT; /* reg[COP0_PAGEMASK] = cpu->cd.mips.coproc[0]->tlbs[0].mask & PAGEMASK_MASK; */ if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) reg[COP0_ENTRYHI] = (vaddr & (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K)) | vaddr_asid; else reg[COP0_ENTRYHI] = (vaddr & (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK)) | vaddr_asid; } } } if (exc_model != EXC3K && reg[COP0_STATUS] & STATUS_EXL) { /* * Don't set EPC if STATUS_EXL is set, for R4000 and up. * This actually happens when running IRIX and Ultrix, when * they handle interrupts and/or tlb updates, I think, so * printing this with debug() looks better than with fatal(). */ /* debug("[ warning: cpu%i exception while EXL is set," " not setting EPC ]\n", cpu->cpu_id); */ } else { if (cpu->delay_slot) { reg[COP0_EPC] = cpu->pc - 4; reg[COP0_CAUSE] |= CAUSE_BD; } else { reg[COP0_EPC] = cpu->pc; reg[COP0_CAUSE] &= ~CAUSE_BD; } } if (cpu->delay_slot) cpu->delay_slot = EXCEPTION_IN_DELAY_SLOT; else cpu->delay_slot = NOT_DELAYED; /* TODO: This is true for MIPS64, but how about others? */ if (reg[COP0_STATUS] & STATUS_BEV) base = 0xffffffffbfc00200ULL; else base = 0xffffffff80000000ULL; switch (exc_model) { case EXC3K: /* Userspace tlb, vs others: */ if (tlb && !(vaddr & 0x80000000ULL) && (exccode == EXCEPTION_TLBL || exccode == EXCEPTION_TLBS) ) cpu->pc = base + 0x000; else cpu->pc = base + 0x080; break; default: /* * These offsets are according to the MIPS64 manual, but * should work with R4000 and the rest too (I hope). * * 0x000 TLB refill, if EXL=0 * 0x080 64-bit XTLB refill, if EXL=0 * 0x100 cache error (not implemented yet) * 0x180 general exception * 0x200 interrupt (if CAUSE_IV is set) */ if (tlb && (exccode == EXCEPTION_TLBL || exccode == EXCEPTION_TLBS) && !(reg[COP0_STATUS] & STATUS_EXL)) { if (x_64) cpu->pc = base + 0x080; else cpu->pc = base + 0x000; } else { if (exccode == EXCEPTION_INT && (reg[COP0_CAUSE] & CAUSE_IV)) cpu->pc = base + 0x200; else cpu->pc = base + 0x180; } } if (exc_model == EXC3K) { /* R{2,3}000: Shift the lowest 6 bits to the left two steps:*/ reg[COP0_STATUS] = (reg[COP0_STATUS] & ~0x3f) + ((reg[COP0_STATUS] & 0xf) << 2); } else { /* R4000: */ reg[COP0_STATUS] |= STATUS_EXL; } /* Sign-extend: */ reg[COP0_CAUSE] = (int64_t)(int32_t)reg[COP0_CAUSE]; reg[COP0_STATUS] = (int64_t)(int32_t)reg[COP0_STATUS]; if (cpu->is_32bit) { reg[COP0_EPC] = (int64_t)(int32_t)reg[COP0_EPC]; mips32_pc_to_pointers(cpu); } else { mips_pc_to_pointers(cpu); } } #include "memory_mips.cc" #include "tmp_mips_tail.cc" gxemul-0.6.1/src/cpus/cpu_alpha_palcode.cc000644 001750 001750 00000031243 13402411502 020723 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Alpha PALcode-related functionality. * * (See http://www.alphalinux.org/docs/alphaahb.html for good descriptions * of many PALcode functions.) */ #include #include #include #include #include "console.h" #include "cpu.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "symbol.h" #include "thirdparty/alpha_prom.h" /* * alpha_palcode_name(): * * Return the name of a PALcode number, as a string. */ void alpha_palcode_name(uint32_t palcode, char *buf, size_t buflen) { switch (palcode) { case 0x00: snprintf(buf, buflen, "PAL_halt"); break; case 0x01: snprintf(buf, buflen, "PAL_cflush"); break; case 0x02: snprintf(buf, buflen, "PAL_draina"); break; case 0x09: snprintf(buf, buflen, "PAL_cserve"); break; case 0x0a: snprintf(buf, buflen, "PAL_swppal"); break; case 0x0d: snprintf(buf, buflen, "PAL_ipir"); break; case 0x10: snprintf(buf, buflen, "PAL_OSF1_rdmces"); break; case 0x11: snprintf(buf, buflen, "PAL_OSF1_wrmces"); break; case 0x2b: snprintf(buf, buflen, "PAL_OSF1_wrfen"); break; case 0x2d: snprintf(buf, buflen, "PAL_OSF1_wrvptptr"); break; case 0x30: snprintf(buf, buflen, "PAL_OSF1_swpctx"); break; case 0x31: snprintf(buf, buflen, "PAL_OSF1_wrval"); break; case 0x32: snprintf(buf, buflen, "PAL_OSF1_rdval"); break; case 0x33: snprintf(buf, buflen, "PAL_OSF1_tbi"); break; case 0x34: snprintf(buf, buflen, "PAL_OSF1_wrent"); break; case 0x35: snprintf(buf, buflen, "PAL_OSF1_swpipl"); break; case 0x36: snprintf(buf, buflen, "PAL_rdps"); break; case 0x37: snprintf(buf, buflen, "PAL_OSF1_wrkgp"); break; case 0x38: snprintf(buf, buflen, "PAL_OSF1_wrusp"); break; case 0x39: snprintf(buf, buflen, "PAL_OSF1_wrperfmon"); break; case 0x3a: snprintf(buf, buflen, "PAL_OSF1_rdusp"); break; case 0x3c: snprintf(buf, buflen, "PAL_whami"); break; case 0x3d: snprintf(buf, buflen, "PAL_OSF1_retsys"); break; case 0x3e: snprintf(buf, buflen, "PAL_wtint"); break; case 0x3f: snprintf(buf, buflen, "PAL_OSF1_rti"); break; case 0x80: snprintf(buf, buflen, "PAL_bpt"); break; case 0x81: snprintf(buf, buflen, "PAL_bugchk"); break; case 0x83: snprintf(buf, buflen, "PAL_OSF1_callsys"); break; case 0x86: snprintf(buf, buflen, "PAL_imb"); break; case 0x92: snprintf(buf, buflen, "PAL_OSF1_urti"); break; case 0x9e: snprintf(buf, buflen, "PAL_rdunique"); break; case 0x9f: snprintf(buf, buflen, "PAL_wrunique"); break; case 0xaa: snprintf(buf, buflen, "PAL_gentrap"); break; case 0xae: snprintf(buf, buflen, "PAL_clrfen"); break; case 0x3fffffe: snprintf(buf, buflen, "GXemul_PROM"); break; default:snprintf(buf, buflen, "UNKNOWN 0x%" PRIx32, palcode); } } /* * alpha_prom_call(): */ void alpha_prom_call(struct cpu *cpu) { uint64_t addr, a1 = cpu->cd.alpha.r[ALPHA_A1]; uint64_t a2 = cpu->cd.alpha.r[ALPHA_A2], a3 = cpu->cd.alpha.r[ALPHA_A3]; uint64_t len; const char *s = ""; switch (cpu->cd.alpha.r[ALPHA_A0]) { case PROM_R_PUTS: /* a1 = channel, a2 = ptr to buf, a3 = len */ for (addr = a2; addr < a2 + a3; addr ++) { unsigned char ch; cpu->memory_rw(cpu, cpu->mem, addr, &ch, sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); console_putchar(cpu->machine->main_console_handle, ch); } cpu->cd.alpha.r[ALPHA_V0] = a3; break; case PROM_R_GETENV: /* a1 = variable id, a2 = char *buf, a3 = bufsize */ switch (a1) { case PROM_E_BOOTED_DEV: s = ""; /* TODO */ break; case PROM_E_BOOTED_FILE: s = cpu->machine->boot_kernel_filename; break; case PROM_E_BOOTED_OSFLAGS: s = cpu->machine->boot_string_argument; break; case PROM_E_TTY_DEV: s = ""; /* TODO */ break; default:fatal("[ Alpha PALcode: GXemul PROM getenv %i: TODO " "]\n", cpu->cd.alpha.r[ALPHA_A1]); cpu->running = 0; } /* Copy at most a3 bytes. */ len = a3; if (strlen(s) < len) len = strlen(s) + 1; store_buf(cpu, a2, s, len); break; default:fatal("[ Alpha PALcode: GXemul PROM call, a0=0x%" PRIx64" ]\n", (uint64_t) cpu->cd.alpha.r[ALPHA_A0]); cpu->running = 0; } /* Return from the PROM call. */ cpu->pc = cpu->cd.alpha.r[ALPHA_RA]; } /* * alpha_palcode(): * * Execute an Alpha PALcode instruction. (Most of these correspond to * OSF1 palcodes, used by for example NetBSD/alpha.) */ void alpha_palcode(struct cpu *cpu, uint32_t palcode) { uint64_t a0 = cpu->cd.alpha.r[ALPHA_A0], a1 = cpu->cd.alpha.r[ALPHA_A1]; bool userMode = cpu->cd.alpha.ps & ALPHA_PSL_USERMODE; /* * Only these are unprivileged, i.e. can be invoked in user mode, * according to the manual: * * bpt kernel and user * bugchk kernel and user * callsys user * clrfen user * gentrap kernel and user * imb kernel and user * rdunique kernel and user * urti user * wrunique kernel and user */ if (userMode && !( palcode == 0x80 || palcode == 0x81 || palcode == 0x83 || palcode == 0xae || palcode == 0xaa || palcode == 0x86 || palcode == 0x9e || palcode == 0x92 || palcode == 0x9f)) { // opDec fault. fatal("[ Privileged Alpha PALcode called from user mode: TODO ]"); cpu->running = 0; return; } switch (palcode) { #if 0 TODO: Uncomment more again, as I progress with the emulation... Make sure they are correct, as documented in the Manual. case 0x02: /* PAL_draina */ /* TODO? */ break; #endif case 0x10: /* PAL_OSF1_rdmces */ /* Return Machine Check status in v0. */ cpu->cd.alpha.r[ALPHA_V0] = cpu->cd.alpha.mces; break; case 0x11: /* PAL_OSF1_wrmces */ /* Clear bits 0, 1, and 2 of the Machine Check and Error status. */ cpu->cd.alpha.mces = ~(cpu->cd.alpha.r[ALPHA_A0] & 7); /* Set bits 3 and 4 of the Machine Check and Error status. */ cpu->cd.alpha.mces &= ~0x18; cpu->cd.alpha.mces |= (cpu->cd.alpha.r[ALPHA_A0] & 0x18); break; case 0x2b: /* PAL_OSF1_wrfen */ /* Floating point enable: a0 = 1 or 0. */ /* TODO. Since clrfen is documented as: FEN ← 0 (PCBB+40)<0> ← 0 then most likely wrfen should do the reverse. */ cpu->cd.alpha.pcb.apcb_flags = cpu->cd.alpha.r[ALPHA_A0]; store_64bit_word(cpu, cpu->cd.alpha.ctx + 40, cpu->cd.alpha.pcb.apcb_flags); break; case 0x2d: /* PAL_OSF1_wrvptptr */ /* Write Virtual Page Table Pointer. a0 = value */ cpu->cd.alpha.vptptr = a0; break; case 0x30: /* PAL_OSF1_swpctx */ /* Save old context: */ store_64bit_word(cpu, cpu->cd.alpha.ctx + 0, cpu->cd.alpha.pcb.apcb_ksp); store_64bit_word(cpu, cpu->cd.alpha.ctx + 8, cpu->cd.alpha.pcb.apcb_usp); store_64bit_word(cpu, cpu->cd.alpha.ctx + 16, cpu->cd.alpha.pcb.apcb_ptbr); store_32bit_word(cpu, cpu->cd.alpha.ctx + 24, cpu->cd.alpha.pcb.apcb_cpc); store_32bit_word(cpu, cpu->cd.alpha.ctx + 28, cpu->cd.alpha.pcb.apcb_asn); store_64bit_word(cpu, cpu->cd.alpha.ctx + 32, cpu->cd.alpha.pcb.apcb_unique); store_64bit_word(cpu, cpu->cd.alpha.ctx + 40, cpu->cd.alpha.pcb.apcb_flags); store_64bit_word(cpu, cpu->cd.alpha.ctx + 48, cpu->cd.alpha.pcb.apcb_decrsv0); store_64bit_word(cpu, cpu->cd.alpha.ctx + 56, cpu->cd.alpha.pcb.apcb_decrsv1); /* Return old context in v0. */ cpu->cd.alpha.r[ALPHA_A0] = cpu->cd.alpha.ctx; /* Load new context: */ { cpu->cd.alpha.ctx = a0; uint64_t new_ksp = load_64bit_word(cpu, cpu->cd.alpha.ctx + 0); uint64_t new_usp = load_64bit_word(cpu, cpu->cd.alpha.ctx + 8); uint64_t new_ptbr = load_64bit_word(cpu, cpu->cd.alpha.ctx + 16); uint64_t new_cpc = load_32bit_word(cpu, cpu->cd.alpha.ctx + 24); uint64_t new_asn = load_32bit_word(cpu, cpu->cd.alpha.ctx + 28); uint64_t new_unique = load_64bit_word(cpu, cpu->cd.alpha.ctx + 32); uint64_t new_flags = load_64bit_word(cpu, cpu->cd.alpha.ctx + 40); uint64_t new_decrsv0 = load_64bit_word(cpu, cpu->cd.alpha.ctx + 48); uint64_t new_decrsv1 = load_64bit_word(cpu, cpu->cd.alpha.ctx + 56); // Update all variables in the pcb simultaneously: cpu->cd.alpha.pcb.apcb_ksp = new_ksp; cpu->cd.alpha.pcb.apcb_usp = new_usp; cpu->cd.alpha.pcb.apcb_ptbr = new_ptbr; cpu->cd.alpha.pcb.apcb_cpc = new_cpc; cpu->cd.alpha.pcb.apcb_asn = new_asn; cpu->cd.alpha.pcb.apcb_unique = new_unique; cpu->cd.alpha.pcb.apcb_ptbr = new_flags; cpu->cd.alpha.pcb.apcb_decrsv0 = new_decrsv0; cpu->cd.alpha.pcb.apcb_decrsv1 = new_decrsv1; // TODO: Don't invalidate EVERYTHING! cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); } break; #if 0 case 0x31: /* PAL_OSF1_wrval */ /* a0 = value */ cpu->cd.alpha.sysvalue = a0; break; case 0x32: /* PAL_OSF1_rdval */ /* return: v0 = value */ cpu->cd.alpha.r[ALPHA_V0] = cpu->cd.alpha.sysvalue; break; #endif case 0x33: /* PAL_OSF1_tbi */ /* * a0 = op, a1 = vaddr * a0 is ignored for now. TODO. * a0 = 1: ITB invalidate * a0 = 2: DTB invalidate * a0 = 3: both ITB and DTB * a0 = -1: invalidate everything with ASM=0. * a0 = -2: invalidate everything */ // debug("[ Alpha PALcode: PAL_OSF1_tbi: a0=%" PRIi64" a1=0x%" // PRIx64" ]\n", (int64_t)a0, (uint64_t)a1); if (a0 >= 1) cpu->invalidate_translation_caches(cpu, a1, INVALIDATE_VADDR); else cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); break; case 0x34: /* PAL_OSF1_wrent (Write System Entry Address) */ /* a0 = new vector, a1 = vector selector */ if (a1 < N_ALPHA_KENTRY) cpu->cd.alpha.kentry[a1] = a0; else { fatal("[ Alpha PALcode: PAL_OSF1_wrent: attempt to " "write to non-implemented selector %i ]\n", (int)a1); cpu->running = 0; } break; case 0x35: /* PAL_OSF1_swpipl */ /* a0 = new ipl, v0 = return old ipl */ cpu->cd.alpha.r[ALPHA_V0] = cpu->cd.alpha.ps & ALPHA_PSL_IPL_MASK; cpu->cd.alpha.ps &= ~ALPHA_PSL_IPL_MASK; cpu->cd.alpha.ps |= (a0 & ALPHA_PSL_IPL_MASK); break; case 0x36: /* PAL_rdps */ cpu->cd.alpha.r[ALPHA_V0] = cpu->cd.alpha.ps; break; case 0x37: /* PAL_OSF1_wrkgp */ cpu->cd.alpha.kgp = a0; break; #if 0 case 0x38: /* PAL_OSF1_wrusp */ /* a0 = value */ cpu->cd.alpha.pcb.apcb_usp = a0; break; case 0x3a: /* PAL_OSF1_rdusp */ /* return: v0 = value */ cpu->cd.alpha.r[ALPHA_V0] = cpu->cd.alpha.pcb.apcb_usp; break; #endif case 0x3c: /* PAL_whami */ /* Returns CPU id in v0: */ cpu->cd.alpha.r[ALPHA_V0] = cpu->cpu_id; break; #if 0 case 0x81: /* PAL_bugchk */ cpu->running = 0; break; case 0x83: /* PAL_OSF1_syscall */ fatal("[ Alpha PALcode: syscall, but no syscall handler ]\n"); cpu->running = 0; break; #endif case 0x86: /* PAL_imb */ /* TODO */ break; #if 0 case 0x3fffffc: fatal("[ Alpha: KENTRY not set! Halting. ]"); cpu->running = 0; break; case 0x3fffffd: fatal("[ Alpha PALcode: Fixup: TODO ]\n"); /* Return from the fixup call. */ cpu->cd.alpha.r[ALPHA_V0] = 0; /* Success? */ cpu->pc = cpu->cd.alpha.r[ALPHA_RA]; break; #endif case 0x3fffffe: alpha_prom_call(cpu); break; default:fatal("[ Alpha PALcode 0x%x unimplemented! ]\n", palcode); cpu->running = 0; } /* * Many PALcode instructions in the Alpha manual (and in NetBSD/Alpha * source code) are described with "clobbers t0, t8-t11", some also * with a0, and some also with a1 included. * * However, it's easier to just leave the registers as they are. */ } gxemul-0.6.1/src/cpus/cpu_ppc_instr_loadstore.cc000644 001750 001750 00000016537 13402411502 022235 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * POWER/PowerPC load/store instructions. * * * Load/store instructions have the following arguments: * * arg[0] = pointer to the register to load to or store from * arg[1] = pointer to the base register * * arg[2] = offset (as an int32_t) * (or, for Indexed load/stores: pointer to index register) */ #ifndef LS_IGNOREOFS void LS_GENERIC_N(struct cpu *cpu, struct ppc_instr_call *ic) { #ifdef MODE32 uint32_t addr = #else uint64_t addr = #endif reg(ic->arg[1]) + #ifdef LS_INDEXED reg(ic->arg[2]); #else (int32_t)ic->arg[2]; #endif unsigned char data[LS_SIZE]; /* Synchronize the PC: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); #ifndef LS_B if ((addr & 0xfff) + LS_SIZE-1 > 0xfff) { fatal("PPC LOAD/STORE misalignment across page boundary: TODO" " (addr=0x%08x, LS_SIZE=%i)\n", (int)addr, LS_SIZE); exit(1); } #endif #ifdef LS_LOAD if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } #ifdef LS_B reg(ic->arg[0]) = #ifndef LS_ZERO (int8_t) #endif data[0]; #endif #ifdef LS_H reg(ic->arg[0]) = #ifdef LS_BYTEREVERSE ((data[1] << 8) + data[0]); #else #ifndef LS_ZERO (int16_t) #endif ((data[0] << 8) + data[1]); #endif /* !BYTEREVERSE */ #endif #ifdef LS_W reg(ic->arg[0]) = #ifdef LS_BYTEREVERSE ((data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0]); #else /* !LS_BYTEREVERSE */ #ifndef LS_ZERO (int32_t) #else (uint32_t) #endif ((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]); #endif /* !LS_BYTEREVERSE */ #endif #ifdef LS_D (*(uint64_t *)(ic->arg[0])) = ((uint64_t)data[0] << 56) + ((uint64_t)data[1] << 48) + ((uint64_t)data[2] << 40) + ((uint64_t)data[3] << 32) + ((uint64_t)data[4] << 24) + (data[5] << 16) + (data[6] << 8) + data[7]; #endif #else /* store: */ #ifdef LS_B data[0] = reg(ic->arg[0]); #endif #ifdef LS_H #ifdef LS_BYTEREVERSE data[0] = reg(ic->arg[0]); data[1] = reg(ic->arg[0]) >> 8; #else data[0] = reg(ic->arg[0]) >> 8; data[1] = reg(ic->arg[0]); #endif #endif #ifdef LS_W #ifdef LS_BYTEREVERSE data[0] = reg(ic->arg[0]); data[1] = reg(ic->arg[0]) >> 8; data[2] = reg(ic->arg[0]) >> 16; data[3] = reg(ic->arg[0]) >> 24; #else data[0] = reg(ic->arg[0]) >> 24; data[1] = reg(ic->arg[0]) >> 16; data[2] = reg(ic->arg[0]) >> 8; data[3] = reg(ic->arg[0]); #endif /* !LS_BYTEREVERSE */ #endif #ifdef LS_D { uint64_t x = *(uint64_t *)(ic->arg[0]); data[0] = x >> 56; data[1] = x >> 48; data[2] = x >> 40; data[3] = x >> 32; data[4] = x >> 24; data[5] = x >> 16; data[6] = x >> 8; data[7] = x; } #endif if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } #endif #ifdef LS_UPDATE reg(ic->arg[1]) = addr; #endif } #endif void LS_N(struct cpu *cpu, struct ppc_instr_call *ic) { #ifndef MODE32 /************************************************************/ /* For now, 64-bit access is done using the slow fallback. */ if (!cpu->is_32bit) { LS_GENERIC_N(cpu, ic); return; } #endif #ifdef MODE32 uint32_t addr = #else uint64_t addr = #endif reg(ic->arg[1]) #ifdef LS_INDEXED + reg(ic->arg[2]) #else #ifndef LS_IGNOREOFS + (int32_t)ic->arg[2] #endif #endif ; unsigned char *page = cpu->cd.ppc. #ifdef LS_LOAD host_load #else host_store #endif [addr >> 12]; #ifdef LS_UPDATE uint32_t new_addr = addr; #endif #ifndef LS_B if (addr & (LS_SIZE-1)) { LS_GENERIC_N(cpu, ic); return; } #endif if (page == NULL) { LS_GENERIC_N(cpu, ic); return; } else { addr &= 4095; #ifdef LS_LOAD /* Load: */ #ifdef LS_B reg(ic->arg[0]) = #ifndef LS_ZERO (int8_t) #endif page[addr]; #endif /* LS_B */ #ifdef LS_H reg(ic->arg[0]) = #ifdef LS_BYTEREVERSE ((page[addr+1] << 8) + page[addr]); #else #ifndef LS_ZERO (int16_t) #endif ((page[addr] << 8) + page[addr+1]); #endif /* !BYTEREVERSE */ #endif /* LS_H */ #ifdef LS_W reg(ic->arg[0]) = #ifdef LS_BYTEREVERSE ((page[addr+3] << 24) + (page[addr+2] << 16) + (page[addr+1] << 8) + page[addr]); #else /* !LS_BYTEREVERSE */ #ifndef LS_ZERO (int32_t) #else (uint32_t) #endif ((page[addr] << 24) + (page[addr+1] << 16) + (page[addr+2] << 8) + page[addr+3]); #endif /* !LS_BYTEREVERSE */ #endif /* LS_W */ #ifdef LS_D (*(uint64_t *)(ic->arg[0])) = ((uint64_t)page[addr+0] << 56) + ((uint64_t)page[addr+1] << 48) + ((uint64_t)page[addr+2] << 40) + ((uint64_t)page[addr+3] << 32) + ((uint64_t)page[addr+4] << 24) + (page[addr+5] << 16) + (page[addr+6] << 8) + page[addr+7]; #endif /* LS_D */ #else /* !LS_LOAD */ /* Store: */ #ifdef LS_B page[addr] = reg(ic->arg[0]); #endif #ifdef LS_H #ifdef LS_BYTEREVERSE page[addr] = reg(ic->arg[0]); page[addr+1] = reg(ic->arg[0]) >> 8; #else page[addr] = reg(ic->arg[0]) >> 8; page[addr+1] = reg(ic->arg[0]); #endif /* !BYTEREVERSE */ #endif #ifdef LS_W #ifdef LS_BYTEREVERSE page[addr] = reg(ic->arg[0]); page[addr+1] = reg(ic->arg[0]) >> 8; page[addr+2] = reg(ic->arg[0]) >> 16; page[addr+3] = reg(ic->arg[0]) >> 24; #else page[addr] = reg(ic->arg[0]) >> 24; page[addr+1] = reg(ic->arg[0]) >> 16; page[addr+2] = reg(ic->arg[0]) >> 8; page[addr+3] = reg(ic->arg[0]); #endif /* !LS_BYTEREVERSE */ #endif #ifdef LS_D { uint64_t x = *(uint64_t *)(ic->arg[0]); page[addr] = x >> 56; page[addr+1] = x >> 48; page[addr+2] = x >> 40; page[addr+3] = x >> 32; page[addr+4] = x >> 24; page[addr+5] = x >> 16; page[addr+6] = x >> 8; page[addr+7] = x; } #endif #endif /* !LS_LOAD */ } #ifdef LS_UPDATE reg(ic->arg[1]) = new_addr; #endif } gxemul-0.6.1/src/cpus/cpu_m88k.cc000644 001750 001750 00000114371 13402411502 016742 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Motorola M881x0 CPU emulation. * * M88100: Disassembly of (almost?) everything, and execution of most * instructions. Exception handling and virtual memory has also * been implemented. Exceptions while in delay slots may not work * fully yet, though. * * M88110: Not yet. */ #include #include #include #include #include #include "cpu.h" #include "float_emul.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "settings.h" #include "symbol.h" #include "thirdparty/m8820x_pte.h" #include "thirdparty/m88k_dmt.h" #include "thirdparty/mvmeprom.h" #define DYNTRANS_32 #define DYNTRANS_DELAYSLOT #include "tmp_m88k_head.cc" void m88k_pc_to_pointers(struct cpu *); void m88k_cpu_functioncall_trace(struct cpu *cpu, int n_args); static const char *memop[4] = { ".d", "", ".h", ".b" }; void m88k_irq_interrupt_assert(struct interrupt *interrupt); void m88k_irq_interrupt_deassert(struct interrupt *interrupt); static const char *m88k_cr_names[] = M88K_CR_NAMES; static const char *m88k_cr_197_names[] = M88K_CR_NAMES_197; static const char *m88k_cr_name(struct cpu *cpu, int i) { const char **cr_names = m88k_cr_names; /* Hm. Is this really MVME197 specific? TODO */ if (cpu->machine->machine_subtype == MACHINE_MVME88K_197) cr_names = m88k_cr_197_names; return cr_names[i]; } static char *m88k_fcr_name(struct cpu *cpu, int fi) { /* TODO */ static char fcr_name[10]; snprintf(fcr_name, sizeof(fcr_name), "FCR%i", fi); return fcr_name; } /* * m88k_cpu_new(): * * Create a new M88K cpu object by filling the CPU struct. * Return 1 on success, 0 if cpu_type_name isn't a valid M88K processor. */ int m88k_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine, int cpu_id, char *cpu_type_name) { int i, found; struct m88k_cpu_type_def cpu_type_defs[] = M88K_CPU_TYPE_DEFS; /* Scan the list for this cpu type: */ i = 0; found = -1; while (i >= 0 && cpu_type_defs[i].name != NULL) { if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) { found = i; break; } i++; } if (found == -1) return 0; cpu->run_instr = m88k_run_instr; cpu->memory_rw = m88k_memory_rw; cpu->update_translation_table = m88k_update_translation_table; cpu->invalidate_translation_caches = m88k_invalidate_translation_caches; cpu->invalidate_code_translation = m88k_invalidate_code_translation; cpu->translate_v2p = m88k_translate_v2p; cpu->cd.m88k.cpu_type = cpu_type_defs[found]; cpu->name = strdup(cpu->cd.m88k.cpu_type.name); cpu->is_32bit = 1; cpu->byte_order = EMUL_BIG_ENDIAN; cpu->instruction_has_delayslot = m88k_cpu_instruction_has_delayslot; /* Only show name and caches etc for CPU nr 0: */ if (cpu_id == 0) { debug("%s", cpu->name); } /* * Add register names as settings: */ CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc); for (i=0; icd.m88k.r[i]); } for (i=0; icd.m88k.cr[i]); } for (i=0; icd.m88k.fcr[i]); } /* Register the CPU interrupt pin: */ { struct interrupt templ; char name[50]; snprintf(name, sizeof(name), "%s", cpu->path); memset(&templ, 0, sizeof(templ)); templ.line = 0; templ.name = name; templ.extra = cpu; templ.interrupt_assert = m88k_irq_interrupt_assert; templ.interrupt_deassert = m88k_irq_interrupt_deassert; interrupt_handler_register(&templ); } /* Set the Processor ID: */ cpu->cd.m88k.cr[M88K_CR_PID] = cpu->cd.m88k.cpu_type.pid | M88K_PID_MC; /* Start in supervisor mode, with interrupts disabled. */ cpu->cd.m88k.cr[M88K_CR_PSR] = M88K_PSR_MODE | M88K_PSR_IND; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) cpu->cd.m88k.cr[M88K_CR_PSR] |= M88K_PSR_BO; /* Initial stack pointer: */ cpu->cd.m88k.r[31] = 1048576 * cpu->machine->physical_ram_in_mb - 1024; return 1; } /* * m88k_cpu_dumpinfo(): */ void m88k_cpu_dumpinfo(struct cpu *cpu) { /* struct m88k_cpu_type_def *ct = &cpu->cd.m88k.cpu_type; */ debug(", %s-endian", cpu->byte_order == EMUL_BIG_ENDIAN? "Big" : "Little"); debug("\n"); } /* * m88k_cpu_list_available_types(): * * Print a list of available M88K CPU types. */ void m88k_cpu_list_available_types(void) { int i, j; struct m88k_cpu_type_def tdefs[] = M88K_CPU_TYPE_DEFS; i = 0; while (tdefs[i].name != NULL) { debug("%s", tdefs[i].name); for (j=13 - strlen(tdefs[i].name); j>0; j--) debug(" "); i++; if ((i % 5) == 0 || tdefs[i].name == NULL) debug("\n"); } } /* * m88k_cpu_instruction_has_delayslot(): * * Returns 1 if an opcode has a delay slot after it, 0 otherwise. */ int m88k_cpu_instruction_has_delayslot(struct cpu *cpu, unsigned char *ib) { uint32_t iword = *((uint32_t *)&ib[0]); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) iword = LE32_TO_HOST(iword); else iword = BE32_TO_HOST(iword); switch (iword >> 26) { case 0x31: /* br.n */ case 0x33: /* bsr.n */ case 0x35: /* bb0.n */ case 0x37: /* bb1.n */ case 0x3b: /* bcnd.n */ return 1; case 0x3d: switch ((iword >> 8) & 0xff) { case 0xc4: /* jmp.n */ case 0xcc: /* jsr.n */ return 1; } } return 0; } /* * m88k_cpu_register_dump(): * * Dump cpu registers in a relatively readable format. * * gprs: set to non-zero to dump GPRs and some special-purpose registers. * coprocs: set bit 0..3 to dump registers in coproc 0..3. */ void m88k_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs) { char *symbol; uint64_t offset; int i, x = cpu->cpu_id; if (gprs) { symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->pc, &offset); debug("cpu%i: pc = 0x%08" PRIx32, x, (uint32_t)cpu->pc); debug(" <%s>\n", symbol != NULL? symbol : " no symbol "); for (i=0; icd.m88k.r[i]); if ((i % 4) == 3) debug("\n"); } } if (coprocs & 1) { int n_control_regs = 32; /* Hm. Is this really MVME197 specific? TODO */ if (cpu->machine->machine_subtype == MACHINE_MVME88K_197) n_control_regs = 64; for (i=0; icd.m88k.cr[i]); if ((i % 4) == 3) debug("\n"); } } if (coprocs & 2) { int n_fpu_control_regs = 64; for (i=0; icd.m88k.fcr[i]); if ((i % 4) == 3) debug("\n"); } } } /* * m88k_cpu_tlbdump(): * * Called from the debugger to dump the TLB in a readable format. * x is the cpu number to dump, or -1 to dump all CPUs. * * If rawflag is nonzero, then the TLB contents isn't formated nicely, * just dumped. */ void m88k_cpu_tlbdump(struct machine *m, int x, int rawflag) { int cpu_nr, cmmu_nr, i; for (cpu_nr = 0; cpu_nr < m->ncpus; cpu_nr++) { struct cpu *cpu = m->cpus[cpu_nr]; if (x != -1 && cpu_nr != x) continue; for (cmmu_nr = 0; cmmu_nr < MAX_M8820X_CMMUS; cmmu_nr++) { struct m8820x_cmmu *cmmu = cpu->cd.m88k.cmmu[cmmu_nr]; if (cmmu == NULL) continue; printf("cpu%i: CMMU %i (%s)\n", cpu_nr, cmmu_nr, cmmu_nr & 1? "data" : "instruction"); /* BATC: */ for (i = 0; i < N_M88200_BATC_REGS; i++) { uint32_t b = cmmu->batc[i]; printf("cpu%i: BATC[%2i]: ", cpu_nr, i); printf("v=0x%08" PRIx32, b & 0xfff80000); printf(", p=0x%08" PRIx32, (b << 13) & 0xfff80000); printf(", %s %s %s %s %s %s\n", b & BATC_SO? "SP " : "!sp", b & BATC_WT? "WT " : "!wt", b & BATC_GLOBAL? "G " : "!g ", b & BATC_INH? "CI " : "!ci", b & BATC_PROT? "WP " : "!wp", b & BATC_SO? "V " : "!v"); } /* PATC: */ for (i = 0; i < N_M88200_PATC_ENTRIES; i++) { uint32_t v = cmmu->patc_v_and_control[i]; uint32_t p = cmmu->patc_p_and_supervisorbit[i]; printf("cpu%i: patc[%2i]: ", cpu_nr, i); if (p & M8820X_PATC_SUPERVISOR_BIT) printf("superv"); else printf("user "); printf(" v=0x%08" PRIx32, v & 0xfffff000); printf(", p=0x%08" PRIx32, p & 0xfffff000); printf(" %s %s %s %s %s %s %s", v & PG_U1? "U1 " : "!u1", v & PG_U0? "U0 " : "!u0", v & PG_SO? "SP " : "!sp", v & PG_M? "M " : "!m", v & PG_U? "U " : "!u", v & PG_PROT? "WP " : "!wp", v & PG_V? "V " : "!v"); if (i == cmmu->patc_update_index) printf(" <--"); printf("\n"); } } } } /* * m88k_irq_interrupt_assert(): * m88k_irq_interrupt_deassert(): */ void m88k_irq_interrupt_assert(struct interrupt *interrupt) { struct cpu *cpu = (struct cpu *) interrupt->extra; cpu->cd.m88k.irq_asserted = 1; } void m88k_irq_interrupt_deassert(struct interrupt *interrupt) { struct cpu *cpu = (struct cpu *) interrupt->extra; cpu->cd.m88k.irq_asserted = 0; } /* * m88k_ldcr(): * * Read from a control register. Store the resulting value in a register * (pointed to by r32ptr). */ void m88k_ldcr(struct cpu *cpu, uint32_t *r32ptr, int cr) { uint32_t retval = cpu->cd.m88k.cr[cr]; switch (cr) { case M88K_CR_PID: case M88K_CR_PSR: case M88K_CR_EPSR: case M88K_CR_SSBR: case M88K_CR_SXIP: case M88K_CR_SNIP: case M88K_CR_SFIP: case M88K_CR_VBR: case M88K_CR_DMD0: case M88K_CR_DMD1: case M88K_CR_DMD2: case M88K_CR_SR0: case M88K_CR_SR1: case M88K_CR_SR2: case M88K_CR_SR3: break; case M88K_CR_DMT0: case M88K_CR_DMT1: case M88K_CR_DMT2: /* * Catch some possible internal errors in the emulator: * * For valid memory Load transactions, the Destination Register * should not be zero. * * The Byte Order bit should be the same as the CPU's. */ if (retval & DMT_VALID && !(retval & DMT_WRITE)) { if (DMT_DREGBITS(retval) == M88K_ZERO_REG) { fatal("DMT DREG = zero? Internal error.\n"); exit(1); } } if (!!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_BO) != !!(retval & DMT_BO) && retval & DMT_VALID) { fatal("DMT byte order not same as CPUs?\n"); exit(1); } break; case M88K_CR_DMA0: case M88K_CR_DMA1: case M88K_CR_DMA2: /* * Catch some possible internal errors in the emulator: * The lowest 2 bits of the transaction address registers * should always be zero. */ if (retval & 3) { fatal("DMAx not word-aligned? Internal error.\n"); exit(1); } break; default:fatal("m88k_ldcr: UNIMPLEMENTED cr = 0x%02x (%s)\n", cr, m88k_cr_name(cpu, cr)); exit(1); } *r32ptr = retval; } /* * m88k_stcr(): * * Write to a control register. * (Used by both the stcr and rte instructions.) */ void m88k_stcr(struct cpu *cpu, uint32_t value, int cr, int rte) { uint32_t old = cpu->cd.m88k.cr[cr]; switch (cr) { case M88K_CR_PSR: /* Processor Status Regoster */ if ((cpu->byte_order == EMUL_LITTLE_ENDIAN && !(value & M88K_PSR_BO)) || (cpu->byte_order == EMUL_BIG_ENDIAN && (value & M88K_PSR_BO))) { fatal("TODO: attempt to change endianness by flipping" " the endianness bit in the PSR. How should this" " be handled? Aborting.\n"); exit(1); } if (!rte && old & M88K_PSR_MODE && !(value & M88K_PSR_MODE)) fatal("[ m88k_stcr: WARNING! the PSR_MODE bit is being" " cleared; this should be done using the RTE " "instruction only, according to the M88100 " "manual! Continuing anyway. ]\n"); if (value & M88K_PSR_MXM) { fatal("m88k_stcr: TODO: MXM support\n"); exit(1); } if ((old & M88K_PSR_MODE) != (value & M88K_PSR_MODE)) cpu->invalidate_translation_caches( cpu, 0, INVALIDATE_ALL); cpu->cd.m88k.cr[cr] = value; break; case M88K_CR_EPSR: cpu->cd.m88k.cr[cr] = value; break; case M88K_CR_SXIP: case M88K_CR_SNIP: case M88K_CR_SFIP: cpu->cd.m88k.cr[cr] = value; break; case M88K_CR_SSBR: /* Shadow ScoreBoard Register */ if (value & 1) fatal("[ m88k_stcr: WARNING! bit 0 non-zero when" " writing to SSBR (?) ]\n"); cpu->cd.m88k.cr[cr] = value; break; case M88K_CR_VBR: if (value & 0x00000fff) fatal("[ m88k_stcr: WARNING! bits 0..11 non-zero when" " writing to VBR (?) ]\n"); cpu->cd.m88k.cr[cr] = value; break; case M88K_CR_DMT0: case M88K_CR_DMT1: case M88K_CR_DMT2: cpu->cd.m88k.cr[cr] = value; break; case M88K_CR_SR0: /* Supervisor Storage Registers 0..3 */ case M88K_CR_SR1: case M88K_CR_SR2: case M88K_CR_SR3: cpu->cd.m88k.cr[cr] = value; break; default:fatal("m88k_stcr: UNIMPLEMENTED cr = 0x%02x (%s)\n", cr, m88k_cr_name(cpu, cr)); exit(1); } } /* * m88k_fstcr(): * * Write to a floating-point control register. */ void m88k_fstcr(struct cpu *cpu, uint32_t value, int fcr) { #if 0 /* TODO (?) */ uint32_t old = cpu->cd.m88k.cr[fcr]; switch (fcr) { default:fatal("m88k_fstcr: UNIMPLEMENTED fcr = 0x%02x (%s)\n", fcr, m88k_fcr_name(cpu, fcr)); exit(1); } #else cpu->cd.m88k.cr[fcr] = value; #endif } /* * m88k_memory_transaction_debug_dump(): * * Debug dump of the memory transaction registers of a cpu. */ static void m88k_memory_transaction_debug_dump(struct cpu *cpu, int n) { uint32_t dmt = cpu->cd.m88k.dmt[n]; debug("[ DMT%i: ", n); if (dmt & DMT_VALID) { if (dmt & DMT_BO) debug("Little-Endian, "); else debug("Big-Endian, "); if (dmt & DMT_DAS) debug("Supervisor, "); else debug("User, "); if (dmt & DMT_DOUB1) debug("DOUB1, "); if (dmt & DMT_LOCKBAR) debug("LOCKBAR, "); if (dmt & DMT_WRITE) debug("store, "); else { debug("load.%c(r%i), ", dmt & DMT_SIGNED? 's' : 'u', DMT_DREGBITS(dmt)); } debug("bytebits=0x%x ]\n", DMT_ENBITS(dmt)); debug("[ DMD%i: 0x%08" PRIx32"; ", n, cpu->cd.m88k.dmd[n]); debug("DMA%i: 0x%08" PRIx32" ]\n", n, cpu->cd.m88k.dma[n]); } else debug("not valid ]\n"); } /* * m88k_exception(): * * Cause an exception. */ void m88k_exception(struct cpu *cpu, int vector, int is_trap) { int update_shadow_regs = 1; debug("[ EXCEPTION 0x%03x: ", vector); switch (vector) { case M88K_EXCEPTION_RESET: debug("RESET"); break; case M88K_EXCEPTION_INTERRUPT: debug("INTERRUPT"); break; case M88K_EXCEPTION_INSTRUCTION_ACCESS: debug("INSTRUCTION_ACCESS"); break; case M88K_EXCEPTION_DATA_ACCESS: debug("DATA_ACCESS"); break; case M88K_EXCEPTION_MISALIGNED_ACCESS: debug("MISALIGNED_ACCESS"); break; case M88K_EXCEPTION_UNIMPLEMENTED_OPCODE: debug("UNIMPLEMENTED_OPCODE"); break; case M88K_EXCEPTION_PRIVILEGE_VIOLATION: debug("PRIVILEGE_VIOLATION"); break; case M88K_EXCEPTION_BOUNDS_CHECK_VIOLATION: debug("BOUNDS_CHECK_VIOLATION"); break; case M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE: debug("ILLEGAL_INTEGER_DIVIDE"); break; case M88K_EXCEPTION_INTEGER_OVERFLOW: debug("INTEGER_OVERFLOW"); break; case M88K_EXCEPTION_ERROR: debug("ERROR"); break; case M88K_EXCEPTION_SFU1_PRECISE: debug("SFU1_PRECISE"); break; case M88K_EXCEPTION_SFU1_IMPRECISE: debug("SFU1_IMPRECISE"); break; case 0x80: /* up to OpenBSD 5.2 */ case 0x1c2: /* from OpenBSD 5.3 and forward... */ #if 0 fatal("[ syscall %i(", cpu->cd.m88k.r[13]); m88k_cpu_functioncall_trace(cpu, 8); fatal(") ]\n"); #endif debug("syscall, r13=%i", cpu->cd.m88k.r[13]); break; case MVMEPROM_VECTOR: debug("MVMEPROM_VECTOR"); break; default:debug("unknown"); break; } debug(" ]\n"); /* Stuff common for all exceptions: */ if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFRZ) { /* * Non-trap exceptions when the shadow freeze bit is already * set result in an Error exception: */ if (!is_trap) { vector = M88K_EXCEPTION_ERROR; fatal("[ SFRZ already set in PSR => ERROR ]\n"); } update_shadow_regs = 0; } else { /* Freeze shadow registers, and save the PSR: */ cpu->cd.m88k.cr[M88K_CR_EPSR] = cpu->cd.m88k.cr[M88K_CR_PSR]; } m88k_stcr(cpu, cpu->cd.m88k.cr[M88K_CR_PSR] | M88K_PSR_SFRZ /* Freeze shadow registers, */ | M88K_PSR_IND /* disable interrupts, */ | M88K_PSR_SFD1 /* disable the floating point unit, */ | M88K_PSR_MODE, /* and switch to supervisor mode. */ M88K_CR_PSR, 0); if (update_shadow_regs) { cpu->cd.m88k.cr[M88K_CR_SSBR] = 0; cpu->cd.m88k.cr[M88K_CR_SXIP] = cpu->pc | M88K_XIP_V; /* SNIP is the address to return to, when executing rte: */ if (cpu->delay_slot) { if (vector == M88K_EXCEPTION_DATA_ACCESS) { cpu->cd.m88k.cr[M88K_CR_SNIP] = cpu->cd.m88k.delay_target | M88K_NIP_V; cpu->cd.m88k.cr[M88K_CR_SFIP] = cpu->cd.m88k.cr[M88K_CR_SNIP]+4; } else if (vector == M88K_EXCEPTION_INSTRUCTION_ACCESS) { /* If we are in a delay slot, then pc is something like 0xc6000 here (not 0xc5ffc). */ cpu->cd.m88k.cr[M88K_CR_SNIP] = cpu->cd.m88k.delay_target | M88K_NIP_V; cpu->cd.m88k.cr[M88K_CR_SFIP] = 0; } else { /* Perhaps something like this could work: */ cpu->cd.m88k.cr[M88K_CR_SNIP] = (cpu->pc + 4) | M88K_NIP_V; cpu->cd.m88k.cr[M88K_CR_SFIP] = cpu->cd.m88k.delay_target | M88K_NIP_V; } } else { cpu->cd.m88k.cr[M88K_CR_SNIP] = (cpu->pc + 4) | M88K_NIP_V; cpu->cd.m88k.cr[M88K_CR_SFIP] = cpu->cd.m88k.cr[M88K_CR_SNIP]+4; } if (vector == M88K_EXCEPTION_INSTRUCTION_ACCESS) cpu->cd.m88k.cr[M88K_CR_SXIP] |= M88K_XIP_E; } cpu->pc = cpu->cd.m88k.cr[M88K_CR_VBR] + 8 * vector; if (cpu->delay_slot) cpu->delay_slot = EXCEPTION_IN_DELAY_SLOT; else cpu->delay_slot = NOT_DELAYED; /* Default to no memory transactions: */ cpu->cd.m88k.cr[M88K_CR_DMT0] = 0; cpu->cd.m88k.cr[M88K_CR_DMD0] = 0; cpu->cd.m88k.cr[M88K_CR_DMA0] = 0; cpu->cd.m88k.cr[M88K_CR_DMT1] = 0; cpu->cd.m88k.cr[M88K_CR_DMD1] = 0; cpu->cd.m88k.cr[M88K_CR_DMA1] = 0; cpu->cd.m88k.cr[M88K_CR_DMT2] = 0; cpu->cd.m88k.cr[M88K_CR_DMD2] = 0; cpu->cd.m88k.cr[M88K_CR_DMA2] = 0; /* Vector-specific handling: */ if (vector < M88K_EXCEPTION_USER_TRAPS_START) { switch (vector) { case M88K_EXCEPTION_RESET: fatal("[ m88k_exception: reset ]\n"); exit(1); case M88K_EXCEPTION_INTERRUPT: /* When returning with rte, we want to re- */ /* execute the interrupted instruction: */ cpu->cd.m88k.cr[M88K_CR_SNIP] -= 4; cpu->cd.m88k.cr[M88K_CR_SFIP] -= 4; break; case M88K_EXCEPTION_INSTRUCTION_ACCESS: /* When returning with rte, we want to re- */ /* execute the instruction in SXIP, not SNIP/SFIP, */ /* (unless the exception was in a delay-slot): */ if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) { cpu->cd.m88k.cr[M88K_CR_SNIP] = 0; cpu->cd.m88k.cr[M88K_CR_SFIP] = 0; } break; case M88K_EXCEPTION_DATA_ACCESS: /* Update the memory transaction registers: */ cpu->cd.m88k.cr[M88K_CR_DMT0] = cpu->cd.m88k.dmt[0]; cpu->cd.m88k.cr[M88K_CR_DMD0] = cpu->cd.m88k.dmd[0]; cpu->cd.m88k.cr[M88K_CR_DMA0] = cpu->cd.m88k.dma[0]; cpu->cd.m88k.cr[M88K_CR_DMT1] = cpu->cd.m88k.dmt[1]; cpu->cd.m88k.cr[M88K_CR_DMD1] = cpu->cd.m88k.dmd[1]; cpu->cd.m88k.cr[M88K_CR_DMA1] = cpu->cd.m88k.dma[1]; cpu->cd.m88k.cr[M88K_CR_DMT2] = 0; cpu->cd.m88k.cr[M88K_CR_DMD2] = 0; cpu->cd.m88k.cr[M88K_CR_DMA2] = 0; m88k_memory_transaction_debug_dump(cpu, 0); m88k_memory_transaction_debug_dump(cpu, 1); break; #if 0 case M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE: /* TODO: Is it correct to continue on the instruction _after_ the division by zero? Or should the PC be backed up one step? */ break; #endif default:fatal("m88k_exception(): 0x%x: TODO\n", vector); fflush(stdout); exit(1); } } m88k_pc_to_pointers(cpu); } /* * m88k_cpu_disassemble_instr(): * * Convert an instruction word into human readable format, for instruction * tracing. * * If running is 1, cpu->pc should be the address of the instruction. * * If running is 0, things that depend on the runtime environment (eg. * register contents) will not be shown, and dumpaddr will be used instead of * cpu->pc for relative addresses. */ int m88k_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib, int running, uint64_t dumpaddr) { int supervisor = cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE; uint32_t iw; const char *symbol, *mnem = NULL; uint64_t offset; uint32_t op26, op10, op11, d, s1, s2, w5, cr6, imm16; int32_t d16, d26; if (running) dumpaddr = cpu->pc; symbol = get_symbol_name(&cpu->machine->symbol_context, dumpaddr, &offset); if (symbol != NULL && offset == 0 && supervisor) debug("<%s>\n", symbol); if (cpu->machine->ncpus > 1 && running) debug("cpu%i:\t", cpu->cpu_id); debug("%c%08" PRIx32": ", cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE? 's' : 'u', (uint32_t) dumpaddr); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) iw = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24); else iw = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24); debug("%08" PRIx32, (uint32_t) iw); if (running && cpu->delay_slot) debug(" (d)"); debug("\t"); op26 = (iw >> 26) & 0x3f; op11 = (iw >> 11) & 0x1f; op10 = (iw >> 10) & 0x3f; d = (iw >> 21) & 0x1f; s1 = (iw >> 16) & 0x1f; s2 = iw & 0x1f; imm16 = iw & 0xffff; w5 = (iw >> 5) & 0x1f; cr6 = (iw >> 5) & 0x3f; d16 = ((int16_t) (iw & 0xffff)) * 4; d26 = ((int32_t)((iw & 0x03ffffff) << 6)) >> 4; switch (op26) { case 0x00: /* xmem.bu */ case 0x01: /* xmem */ case 0x02: /* ld.hu */ case 0x03: /* ld.bu */ case 0x04: /* ld.d */ case 0x05: /* ld */ case 0x06: /* ld.h */ case 0x07: /* ld.b */ case 0x08: /* st.d */ case 0x09: /* st */ case 0x0a: /* st.h */ case 0x0b: /* st.b */ if (iw == 0x00000000) { debug("-\n"); break; } switch (op26) { case 0x00: debug("xmem.bu"); break; case 0x01: debug("xmem"); break; case 0x02: debug("ld.hu"); break; case 0x03: debug("ld.bu"); break; default: debug("%s%s", op26 >= 0x08? "st" : "ld", memop[op26 & 3]); } debug("\tr%i,r%i,0x%x", d, s1, imm16); if (running) { uint32_t tmpaddr = cpu->cd.m88k.r[s1] + imm16; symbol = get_symbol_name(&cpu->machine->symbol_context, tmpaddr, &offset); if (symbol != NULL && supervisor) debug("\t; [<%s>]", symbol); else debug("\t; [0x%08" PRIx32"]", tmpaddr); if (op26 >= 0x08) { /* Store: */ debug(" = "); switch (op26 & 3) { case 0: debug("0x%016" PRIx64, (uint64_t) ((((uint64_t) cpu->cd.m88k.r[d]) << 32) + ((uint64_t) cpu->cd.m88k.r[d+1])) ); break; case 1: debug("0x%08" PRIx32, (uint32_t) cpu->cd.m88k.r[d]); break; case 2: debug("0x%04" PRIx16, (uint16_t) cpu->cd.m88k.r[d]); break; case 3: debug("0x%02" PRIx8, (uint8_t) cpu->cd.m88k.r[d]); break; } } else { /* Load: */ /* TODO */ } } else { /* * Not running, but the following instruction * sequence is quite common: * * or.u rX,r0,A * st_or_ld rY,rX,B */ /* Try loading the instruction before the current one. */ uint32_t iw2 = 0; cpu->memory_rw(cpu, cpu->mem, dumpaddr - sizeof(uint32_t), (unsigned char *)&iw2, sizeof(iw2), MEM_READ, CACHE_INSTRUCTION | NO_EXCEPTIONS); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) iw2 = LE32_TO_HOST(iw2); else iw2 = BE32_TO_HOST(iw2); if ((iw2 >> 26) == 0x17 && /* or.u */ ((iw2 >> 21) & 0x1f) == s1) { uint32_t tmpaddr = (iw2 << 16) + imm16; symbol = get_symbol_name( &cpu->machine->symbol_context, tmpaddr, &offset); if (symbol != NULL && supervisor) debug("\t; [<%s>]", symbol); else debug("\t; [0x%08" PRIx32"]", tmpaddr); } } debug("\n"); break; case 0x10: /* and */ case 0x11: /* and.u */ case 0x12: /* mask */ case 0x13: /* mask.u */ case 0x14: /* xor */ case 0x15: /* xor.u */ case 0x16: /* or */ case 0x17: /* or.u */ if (d == M88K_ZERO_REG) debug("nop"); switch (op26) { case 0x10: case 0x11: mnem = "and"; break; case 0x12: case 0x13: mnem = "mask"; break; case 0x14: case 0x15: mnem = "xor"; break; case 0x16: case 0x17: mnem = "or"; break; } if (d != M88K_ZERO_REG || op26 != 0x16 || s1 != M88K_ZERO_REG) { if (d == M88K_ZERO_REG) debug("\t\t; weird nop encoding: "); debug("%s%s\t", mnem, op26 & 1? ".u" : ""); debug("r%i,r%i,0x%x", d, s1, imm16); } if (op26 == 0x16 && d != M88K_ZERO_REG) { /* * The following instruction sequence is common: * * or.u rX,r0,A * or rY,rX,B ; rY = AAAABBBB */ /* Try loading the instruction before the current one. */ uint32_t iw2 = 0; cpu->memory_rw(cpu, cpu->mem, dumpaddr - sizeof(uint32_t), (unsigned char *)&iw2, sizeof(iw2), MEM_READ, CACHE_INSTRUCTION | NO_EXCEPTIONS); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) iw2 = LE32_TO_HOST(iw2); else iw2 = BE32_TO_HOST(iw2); if ((iw2 >> 26) == 0x17 && /* or.u */ ((iw2 >> 21) & 0x1f) == s1) { uint32_t tmpaddr = (iw2 << 16) + imm16; symbol = get_symbol_name( &cpu->machine->symbol_context, tmpaddr, &offset); debug("\t; "); if (symbol != NULL && supervisor) debug("<%s>", symbol); else debug("0x%08" PRIx32, tmpaddr); } } debug("\n"); break; case 0x18: /* addu */ case 0x19: /* subu */ case 0x1a: /* divu */ case 0x1b: /* mulu */ case 0x1c: /* add */ case 0x1d: /* sub */ case 0x1e: /* div */ case 0x1f: /* cmp */ switch (op26) { case 0x18: mnem = "addu"; break; case 0x19: mnem = "subu"; break; case 0x1a: mnem = "divu"; break; case 0x1b: mnem = "mulu"; break; case 0x1c: mnem = "add"; break; case 0x1d: mnem = "sub"; break; case 0x1e: mnem = "div"; break; case 0x1f: mnem = "cmp"; break; } debug("%s\tr%i,r%i,%i\n", mnem, d, s1, imm16); break; case 0x20: if ((iw & 0x001ff81f) == 0x00004000) { debug("ldcr\tr%i,%s", d, m88k_cr_name(cpu, cr6)); if (running) debug("\t\t; %s = 0x%08x", m88k_cr_name(cpu, cr6), cpu->cd.m88k.cr[cr6]); debug("\n"); } else if ((iw & 0x001ff81f) == 0x00004800) { debug("fldcr\tr%i,%s\n", d, m88k_fcr_name(cpu, cr6)); } else if ((iw & 0x03e0f800) == 0x00008000) { debug("stcr\tr%i,%s", s1, m88k_cr_name(cpu, cr6)); if (s1 != s2) debug("\t\t; NOTE: weird encoding: " "low 5 bits = 0x%02x", s2); if (running) debug("\t\t; r%i = 0x%08x", s1, cpu->cd.m88k.r[s1]); debug("\n"); } else if ((iw & 0x03e0f800) == 0x00008800) { debug("fstcr\tr%i,%s", s1, m88k_fcr_name(cpu, cr6)); if (s1 != s2) debug("\t\t; NOTE: weird encoding: " "low 5 bits = 0x%02x", s2); debug("\n"); } else if ((iw & 0x0000f800) == 0x0000c000) { debug("xcr\tr%i,r%i,%s", d, s1, m88k_cr_name(cpu, cr6)); if (s1 != s2) debug("\t\t; NOTE: weird encoding: " "low 5 bits = 0x%02x", s2); debug("\n"); } else if ((iw & 0x0000f800) == 0x0000c800) { debug("fxcr\tr%i,r%i,%s", d, s1, m88k_fcr_name(cpu, cr6)); if (s1 != s2) debug("\t\t; NOTE: weird encoding: " "low 5 bits = 0x%02x", s2); debug("\n"); } else { debug("UNIMPLEMENTED 0x20\n"); } break; case 0x21: switch (op11) { case 0x00: /* fmul */ case 0x05: /* fadd */ case 0x06: /* fsub */ case 0x07: /* fcmp */ case 0x0e: /* fdiv */ switch (op11) { case 0x00: mnem = "fmul"; break; case 0x05: mnem = "fadd"; break; case 0x06: mnem = "fsub"; break; case 0x07: mnem = "fcmp"; break; case 0x0e: mnem = "fdiv"; break; } debug("%s.%c%c%c r%i,r%i,r%i\n", mnem, ((iw >> 5) & 1)? 'd' : 's', ((iw >> 9) & 1)? 'd' : 's', ((iw >> 7) & 1)? 'd' : 's', d, s1, s2); break; case 0x04: /* flt */ switch (op11) { case 0x04: mnem = "flt"; break; } debug("%s.%cs\tr%i,r%i\n", mnem, ((iw >> 5) & 1)? 'd' : 's', d, s2); break; case 0x09: /* int */ case 0x0a: /* nint */ case 0x0b: /* trnc */ switch (op11) { case 0x09: mnem = "int"; break; case 0x0a: mnem = "nint"; break; case 0x0b: mnem = "trnc"; break; } debug("%s.s%c r%i,r%i\n", mnem, ((iw >> 7) & 1)? 'd' : 's', d, s2); break; default:debug("UNIMPLEMENTED 0x21, op11=0x%02x\n", op11); } break; case 0x30: case 0x31: case 0x32: case 0x33: debug("b%sr%s\t", op26 >= 0x32? "s" : "", op26 & 1? ".n" : ""); debug("0x%08" PRIx32, (uint32_t) (dumpaddr + d26)); symbol = get_symbol_name(&cpu->machine->symbol_context, dumpaddr + d26, &offset); if (symbol != NULL && supervisor) debug("\t; <%s>", symbol); debug("\n"); break; case 0x34: /* bb0 */ case 0x35: /* bb0.n */ case 0x36: /* bb1 */ case 0x37: /* bb1.n */ case 0x3a: /* bcnd */ case 0x3b: /* bcnd.n */ switch (op26) { case 0x34: case 0x35: mnem = "bb0"; break; case 0x36: case 0x37: mnem = "bb1"; break; case 0x3a: case 0x3b: mnem = "bcnd"; break; } debug("%s%s\t", mnem, op26 & 1? ".n" : ""); if (op26 == 0x3a || op26 == 0x3b) { /* Attempt to decode bcnd condition: */ switch (d) { case 0x1: debug("gt0"); break; case 0x2: debug("eq0"); break; case 0x3: debug("ge0"); break; case 0x7: debug("not_maxneg"); break; case 0x8: debug("maxneg"); break; case 0xc: debug("lt0"); break; case 0xd: debug("ne0"); break; case 0xe: debug("le0"); break; default: debug("unimplemented_%i", d); } } else { debug("%i", d); } debug(",r%i,0x%08" PRIx32, s1, (uint32_t) (dumpaddr + d16)); symbol = get_symbol_name(&cpu->machine->symbol_context, dumpaddr + d16, &offset); if (symbol != NULL && supervisor) debug("\t; <%s>", symbol); debug("\n"); break; case 0x3c: if ((iw & 0x0000f000)==0x1000 || (iw & 0x0000f000)==0x2000) { int scale = 0; /* Load/store: */ debug("%s", (iw & 0x0000f000) == 0x1000? "ld" : "st"); switch (iw & 0x00000c00) { case 0x000: scale = 8; debug(".d"); break; case 0x400: scale = 4; break; case 0x800: debug(".x"); break; default: debug(".UNIMPLEMENTED"); } if (iw & 0x100) debug(".usr"); if (iw & 0x80) debug(".wt"); debug("\tr%i,r%i", d, s1); if (iw & 0x200) debug("[r%i]", s2); else debug(",r%i", s2); if (running && scale >= 1) { uint32_t tmpaddr = cpu->cd.m88k.r[s1]; if (iw & 0x200) tmpaddr += scale * cpu->cd.m88k.r[s2]; else tmpaddr += cpu->cd.m88k.r[s2]; symbol = get_symbol_name(&cpu->machine-> symbol_context, tmpaddr, &offset); if (symbol != NULL && supervisor) debug("\t; [<%s>]", symbol); else debug("\t; [0x%08" PRIx32"]", tmpaddr); } debug("\n"); } else switch (op10) { case 0x20: /* clr */ case 0x22: /* set */ case 0x24: /* ext */ case 0x26: /* extu */ case 0x28: /* mak */ case 0x2a: /* rot */ switch (op10) { case 0x20: mnem = "clr"; break; case 0x22: mnem = "set"; break; case 0x24: mnem = "ext"; break; case 0x26: mnem = "extu"; break; case 0x28: mnem = "mak"; break; case 0x2a: mnem = "rot"; break; } debug("%s\tr%i,r%i,", mnem, d, s1); /* Don't include w5 for the rot instruction: */ if (op10 != 0x2a) debug("%i", w5); /* Note: o5 = s2: */ debug("<%i>\n", s2); break; case 0x34: /* tb0 */ case 0x36: /* tb1 */ switch (op10) { case 0x34: mnem = "tb0"; break; case 0x36: mnem = "tb1"; break; } debug("%s\t%i,r%i,0x%x\n", mnem, d, s1, iw & 0x1ff); break; default:debug("UNIMPLEMENTED 0x3c, op10=0x%02x\n", op10); } break; case 0x3d: if ((iw & 0xf000) <= 0x3fff) { int scale = 0; /* Load, Store, xmem, and lda: */ switch (iw & 0xf000) { case 0x2000: debug("st"); break; case 0x3000: debug("lda"); break; default: if ((iw & 0xf800) >= 0x0800) debug("ld"); else debug("xmem"); } if ((iw & 0xf000) >= 0x1000) { /* ld, st, lda */ scale = 1 << (3 - ((iw >> 10) & 3)); debug("%s", memop[(iw >> 10) & 3]); } else if ((iw & 0xf800) == 0x0000) { /* xmem */ if (iw & 0x400) scale = 4; else debug(".bu"), scale = 1; } else { /* ld */ if ((iw & 0xf00) < 0xc00) debug(".hu"), scale = 2; else debug(".bu"), scale = 1; } if (iw & 0x100) debug(".usr"); if (iw & 0x80) debug(".wt"); debug("\tr%i,r%i", d, s1); if (iw & 0x200) debug("[r%i]", s2); else debug(",r%i", s2); if (running && scale >= 1) { uint32_t tmpaddr = cpu->cd.m88k.r[s1]; if (iw & 0x200) tmpaddr += scale * cpu->cd.m88k.r[s2]; else tmpaddr += cpu->cd.m88k.r[s2]; symbol = get_symbol_name(&cpu->machine-> symbol_context, tmpaddr, &offset); if (symbol != NULL && supervisor) debug("\t; [<%s>]", symbol); else debug("\t; [0x%08" PRIx32"]", tmpaddr); } debug("\n"); } else switch ((iw >> 8) & 0xff) { case 0x40: /* and */ case 0x44: /* and.c */ case 0x50: /* xor */ case 0x54: /* xor.c */ case 0x58: /* or */ case 0x5c: /* or.c */ case 0x60: /* addu */ case 0x61: /* addu.co */ case 0x62: /* addu.ci */ case 0x63: /* addu.cio */ case 0x64: /* subu */ case 0x65: /* subu.co */ case 0x66: /* subu.ci */ case 0x67: /* subu.cio */ case 0x68: /* divu */ case 0x69: /* divu.d */ case 0x6c: /* mul */ case 0x6d: /* mulu.d */ case 0x6e: /* muls */ case 0x70: /* add */ case 0x71: /* add.co */ case 0x72: /* add.ci */ case 0x73: /* add.cio */ case 0x74: /* sub */ case 0x75: /* sub.co */ case 0x76: /* sub.ci */ case 0x77: /* sub.cio */ case 0x78: /* div */ case 0x7c: /* cmp */ case 0x80: /* clr */ case 0x88: /* set */ case 0x90: /* ext */ case 0x98: /* extu */ case 0xa0: /* mak */ case 0xa8: /* rot */ /* Three-register opcodes: */ switch ((iw >> 8) & 0xff) { case 0x40: mnem = "and"; break; case 0x44: mnem = "and.c"; break; case 0x50: mnem = "xor"; break; case 0x54: mnem = "xor.c"; break; case 0x58: mnem = "or"; break; case 0x5c: mnem = "or.c"; break; case 0x60: mnem = "addu"; break; case 0x61: mnem = "addu.co"; break; case 0x62: mnem = "addu.ci"; break; case 0x63: mnem = "addu.cio"; break; case 0x64: mnem = "subu"; break; case 0x65: mnem = "subu.co"; break; case 0x66: mnem = "subu.ci"; break; case 0x67: mnem = "subu.cio"; break; case 0x68: mnem = "divu"; break; case 0x69: mnem = "divu.d"; break; case 0x6c: mnem = "mul"; break; case 0x6d: mnem = "mulu.d"; break; case 0x6e: mnem = "muls"; break; case 0x70: mnem = "add"; break; case 0x71: mnem = "add.co"; break; case 0x72: mnem = "add.ci"; break; case 0x73: mnem = "add.cio"; break; case 0x74: mnem = "sub"; break; case 0x75: mnem = "sub.co"; break; case 0x76: mnem = "sub.ci"; break; case 0x77: mnem = "sub.cio"; break; case 0x78: mnem = "div"; break; case 0x7c: mnem = "cmp"; break; case 0x80: mnem = "clr"; break; case 0x88: mnem = "set"; break; case 0x90: mnem = "ext"; break; case 0x98: mnem = "extu"; break; case 0xa0: mnem = "mak"; break; case 0xa8: mnem = "rot"; break; } if (((iw >> 8) & 0xff) == 0x58 && d == M88K_ZERO_REG) debug("nop"); if (((iw >> 8) & 0xff) != 0x58 || d != M88K_ZERO_REG) { if (d == M88K_ZERO_REG) debug("\t\t; weird nop encoding: "); debug("%s\tr%i,r%i,r%i", mnem, d, s1, s2); } debug("\n"); break; case 0xc0: /* jmp */ case 0xc4: /* jmp.n */ case 0xc8: /* jsr */ case 0xcc: /* jsr.n */ debug("%s%s\t(r%i)", op11 & 1? "jsr" : "jmp", iw & 0x400? ".n" : "", s2); if (running) { uint32_t tmpaddr = cpu->cd.m88k.r[s2]; symbol = get_symbol_name(&cpu->machine-> symbol_context, tmpaddr, &offset); debug("\t\t; "); if (symbol != NULL && supervisor) debug("<%s>", symbol); else debug("0x%08" PRIx32, tmpaddr); } debug("\n"); break; case 0xe8: /* ff1 */ case 0xec: /* ff0 */ debug("%s\tr%i,r%i\n", ((iw >> 8) & 0xff) == 0xe8 ? "ff1" : "ff0", d, s2); break; case 0xf8: /* tbnd */ debug("tbnd\tr%i,r%i\n", s1, s2); break; case 0xfc: switch (iw & 0xff) { case 0x00: debug("rte\n"); break; case 0x01: case 0x02: case 0x03: debug("illop%i\n", iw & 0xff); break; case (M88K_PROM_INSTR & 0xff): debug("gxemul_prom_call\n"); break; default:debug("UNIMPLEMENTED 0x3d,0xfc: 0x%02x\n", iw & 0xff); } break; default:debug("UNIMPLEMENTED 0x3d, opbyte = 0x%02x\n", (iw >> 8) & 0xff); } break; case 0x3e: debug("tbnd\tr%i,0x%x\n", s1, imm16); break; default:debug("UNIMPLEMENTED op26=0x%02x\n", op26); } return sizeof(uint32_t); } #include "tmp_m88k_tail.cc" gxemul-0.6.1/src/cpus/generate_m88k_bcnd.c000644 001750 001750 00000011721 13402411502 020563 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include void print_function_name(int samepage, int n_bit, int m5) { printf("bcnd_"); if (n_bit) printf("n_"); if (samepage) printf("samepage_"); switch (m5) { case 0x1: printf("gt0"); break; case 0x2: printf("eq0"); break; case 0x3: printf("ge0"); break; case 0x7: printf("not_maxneg"); break; case 0x8: printf("maxneg"); break; case 0xc: printf("lt0"); break; case 0xd: printf("ne0"); break; case 0xe: printf("le0"); break; } } void print_operator(int m5) { switch (m5) { case 0x1: printf("> 0"); break; case 0x2: printf("== 0"); break; case 0x3: printf(">= 0"); break; case 0x7: printf("!= 0x80000000UL"); break; case 0x8: printf("== 0x80000000UL"); break; case 0xc: printf("< 0"); break; case 0xd: printf("!= 0"); break; case 0xe: printf("<= 0"); break; } } void bcnd(int samepage, int n_bit, int m5) { if (samepage && n_bit) return; printf("\nX("); print_function_name(samepage, n_bit, m5); printf(")\n{\n"); /* Easiest case is without the n_bit: */ if (!n_bit) { printf("\tif ((%sint32_t)reg(ic->arg[0]) ", (m5 == 7 || m5 == 8)? "u" : ""); print_operator(m5); printf(") {\n"); if (samepage) printf("\t\tcpu->cd.m88k.next_ic = (struct m88k_" "instr_call *) ic->arg[2];\n"); else printf("\t\tcpu->pc = (cpu->pc & 0xfffff000) + " "(int32_t)ic->arg[2];\n\t\tquick_pc_to_" "pointers(cpu);\n"); printf("\t}\n"); } else { /* n_bit, i.e. delay slot: */ printf("\tint cond = (%sint32_t)reg(ic->arg[0]) ", (m5 == 7 || m5 == 8)? "u" : ""); print_operator(m5); printf(";\n"); printf("\tSYNCH_PC;\n"); printf("\tif (cond)\n"); printf("\t\tcpu->cd.m88k.delay_target = (cpu->pc\n"); printf("\t\t\t& ~((M88K_IC_ENTRIES_PER_PAGE-1)" " << M88K_INSTR_ALIGNMENT_SHIFT))\n"); printf("\t\t\t+ ic->arg[2];\n"); printf("\telse\n"); printf("\t\tcpu->cd.m88k.delay_target = cpu->pc + 8;\n"); printf("\tcpu->delay_slot = TO_BE_DELAYED;\n"); printf("\tic[1].f(cpu, ic+1);\n"); printf("\tcpu->n_translated_instrs ++;\n"); printf("\tif (!(cpu->delay_slot & EXCEPTION_IN_" "DELAY_SLOT)) {\n"); printf("\t\tcpu->delay_slot = NOT_DELAYED;\n"); printf("\t\tif (cond) {\n"); printf("\t\t\tcpu->pc = cpu->cd.m88k.delay_target;\n"); printf("\t\t\tquick_pc_to_pointers(cpu);\n"); printf("\t\t} else\n"); printf("\t\t\tcpu->cd.m88k.next_ic ++;\n"); printf("\t} else\n"); printf("\t\tcpu->delay_slot = NOT_DELAYED;\n"); } printf("}\n\n"); } int main(int argc, char *argv[]) { int samepage, n_bit, m5; printf("\n/* AUTOMATICALLY GENERATED! Do not edit. */\n\n"); for (samepage=0; samepage<=1; samepage++) for (n_bit=0; n_bit<=1; n_bit++) for (m5=0; m5<=31; m5++) { if (m5 == 1 || m5 == 2 || m5 == 3 || m5 == 7 || m5 == 8 || m5 == 0xc || m5 == 0xd || m5 == 0xe) bcnd(samepage, n_bit, m5); } /* Array of pointers to all the functions: */ printf("\n\nvoid (*m88k_bcnd[32 * 2 * 2])(struct cpu *, struct " "m88k_instr_call *) = {\n"); for (samepage=0; samepage<=1; samepage++) for (n_bit=0; n_bit<=1; n_bit++) for (m5=0; m5<=31; m5++) { if (m5 || n_bit || samepage) printf(",\n"); if (m5 == 1 || m5 == 2 || m5 == 3 || m5 == 7 || m5 == 8 || m5 == 0xc || m5 == 0xd || m5 == 0xe) { if (samepage && n_bit) printf("NULL"); else { printf("m88k_instr_"); print_function_name( samepage, n_bit, m5); } } else printf("NULL"); } printf(" };\n"); return 0; } gxemul-0.6.1/src/cpus/cpu_mips_instr_loadstore.cc000644 001750 001750 00000017037 13402411502 022417 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * MIPS load/store instructions; the following args are used: * * arg[0] = pointer to the register to load to or store from * arg[1] = pointer to the base register * arg[2] = offset (as an int32_t) * * The GENERIC function always checks for alignment, and supports both big * and little endian byte order. * * The quick function is included twice (big/little endian) for each * GENERIC function. */ #ifdef LS_INCLUDE_GENERIC void LS_GENERIC_N(struct cpu *cpu, struct mips_instr_call *ic) { MODE_int_t addr = reg(ic->arg[1]) + (int32_t)ic->arg[2]; uint8_t data[LS_SIZE]; #ifdef LS_LOAD uint64_t x; #endif /* Synchronize the PC: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page) / sizeof(struct mips_instr_call); cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)<pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT); #ifndef LS_1 /* Check alignment: */ if (addr & (LS_SIZE - 1)) { #if 1 /* Cause an address alignment exception: */ mips_cpu_exception(cpu, #ifdef LS_LOAD EXCEPTION_ADEL, #else EXCEPTION_ADES, #endif 0, addr, 0, 0, 0, 0); #else fatal("{ mips dyntrans alignment exception, size = %i," " addr = %016"PRIx64", pc = %016"PRIx64" }\n", LS_SIZE, (uint64_t) addr, cpu->pc); /* TODO: Generalize this into a abort_call, or similar: */ cpu->running = 0; debugger_n_steps_left_before_interaction = 0; cpu->cd.mips.next_ic = ¬hing_call; #endif return; } #endif #ifdef LS_LOAD if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_READ, CACHE_DATA)) { /* Exception. */ return; } x = memory_readmax64(cpu, data, LS_SIZE); #ifdef LS_SIGNED #ifdef LS_1 x = (int8_t)x; #endif #ifdef LS_2 x = (int16_t)x; #endif #ifdef LS_4 x = (int32_t)x; #endif #endif reg(ic->arg[0]) = x; #else /* LS_STORE: */ memory_writemax64(cpu, data, LS_SIZE, reg(ic->arg[0])); if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* Exception. */ return; } #endif } #endif /* LS_INCLUDE_GENERIC */ void LS_N(struct cpu *cpu, struct mips_instr_call *ic) { MODE_uint_t addr = reg(ic->arg[1]) + (int32_t)ic->arg[2]; unsigned char *p; #ifdef MODE32 #ifdef LS_LOAD p = cpu->cd.mips.host_load[addr >> 12]; #else p = cpu->cd.mips.host_store[addr >> 12]; #endif #else /* !MODE32 */ const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; uint32_t x1, x2, x3; struct DYNTRANS_L2_64_TABLE *l2; struct DYNTRANS_L3_64_TABLE *l3; x1 = (addr >> (64-DYNTRANS_L1N)) & mask1; x2 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; x3 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) & mask3; /* fatal("X3: addr=%016"PRIx64" x1=%x x2=%x x3=%x\n", (uint64_t) addr, (int) x1, (int) x2, (int) x3); */ l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; /* fatal(" l2 = %p\n", l2); */ l3 = l2->l3[x2]; /* fatal(" l3 = %p\n", l3); */ #ifdef LS_LOAD p = l3->host_load[x3]; #else p = l3->host_store[x3]; #endif /* fatal(" p = %p\n", p); */ #endif if (p == NULL #ifndef LS_1 || addr & (LS_SIZE - 1) #endif ) { LS_GENERIC_N(cpu, ic); return; } addr &= 0xfff; #ifdef LS_LOAD /* Load: */ #ifdef LS_1 reg(ic->arg[0]) = #ifdef LS_SIGNED (int8_t) #endif p[addr]; #endif /* LS_1 */ #ifdef LS_2 reg(ic->arg[0]) = #ifdef LS_SIGNED (int16_t) #endif #ifdef LS_BE #ifdef HOST_BIG_ENDIAN ( *(uint16_t *)(p + addr) ); #else ((p[addr]<<8) + p[addr+1]); #endif #else #ifdef HOST_LITTLE_ENDIAN ( *(uint16_t *)(p + addr) ); #else (p[addr] + (p[addr+1]<<8)); #endif #endif #endif /* LS_2 */ #ifdef LS_4 reg(ic->arg[0]) = #ifdef LS_SIGNED (int32_t) #else (uint32_t) #endif #ifdef LS_BE #ifdef HOST_BIG_ENDIAN ( *(uint32_t *)(p + addr) ); #else ((p[addr]<<24) + (p[addr+1]<<16) + (p[addr+2]<<8) + p[addr+3]); #endif #else #ifdef HOST_LITTLE_ENDIAN ( *(uint32_t *)(p + addr) ); #else (p[addr] + (p[addr+1]<<8) + (p[addr+2]<<16) + (p[addr+3]<<24)); #endif #endif #endif /* LS_4 */ #ifdef LS_8 *((uint64_t *)ic->arg[0]) = #ifdef LS_BE #ifdef HOST_BIG_ENDIAN ( *(uint64_t *)(p + addr) ); #else ((uint64_t)p[addr] << 56) + ((uint64_t)p[addr+1] << 48) + ((uint64_t)p[addr+2] << 40) + ((uint64_t)p[addr+3] << 32) + ((uint64_t)p[addr+4] << 24) + (p[addr+5] << 16) + (p[addr+6] << 8) + p[addr+7]; #endif #else #ifdef HOST_LITTLE_ENDIAN ( *(uint64_t *)(p + addr) ); #else p[addr+0] + (p[addr+1] << 8) + (p[addr+2] << 16) + ((uint64_t)p[addr+3] << 24) + ((uint64_t)p[addr+4] << 32) + ((uint64_t)p[addr+5] << 40) + ((uint64_t)p[addr+6] << 48) + ((uint64_t)p[addr+7] << 56); #endif #endif #endif /* LS_8 */ #else /* Store: */ #ifdef LS_1 p[addr] = reg(ic->arg[0]); #endif #ifdef LS_2 { uint32_t x = reg(ic->arg[0]); #ifdef LS_BE #ifdef HOST_BIG_ENDIAN *((uint16_t *)(p+addr)) = x; } #else p[addr] = x >> 8; p[addr+1] = x; } #endif #else #ifdef HOST_LITTLE_ENDIAN *((uint16_t *)(p+addr)) = x; } #else p[addr] = x; p[addr+1] = x >> 8; } #endif #endif #endif /* LS_2 */ #ifdef LS_4 { uint32_t x = reg(ic->arg[0]); #ifdef LS_BE #ifdef HOST_BIG_ENDIAN *((uint32_t *)(p+addr)) = x; } #else p[addr] = x >> 24; p[addr+1] = x >> 16; p[addr+2] = x >> 8; p[addr+3] = x; } #endif #else #ifdef HOST_LITTLE_ENDIAN *((uint32_t *)(p+addr)) = x; } #else p[addr] = x; p[addr+1] = x >> 8; p[addr+2] = x >> 16; p[addr+3] = x >> 24; } #endif #endif #endif /* LS_4 */ #ifdef LS_8 { uint64_t x = *(uint64_t *)(ic->arg[0]); #ifdef LS_BE #ifdef HOST_BIG_ENDIAN *((uint64_t *)(p+addr)) = x; } #else p[addr] = x >> 56; p[addr+1] = x >> 48; p[addr+2] = x >> 40; p[addr+3] = x >> 32; p[addr+4] = x >> 24; p[addr+5] = x >> 16; p[addr+6] = x >> 8; p[addr+7] = x; } #endif #else #ifdef HOST_LITTLE_ENDIAN *((uint64_t *)(p+addr)) = x; } #else p[addr] = x; p[addr+1] = x >> 8; p[addr+2] = x >> 16; p[addr+3] = x >> 24; p[addr+4] = x >> 32; p[addr+5] = x >> 40; p[addr+6] = x >> 48; p[addr+7] = x >> 56; } #endif #endif #endif /* LS_8 */ #endif /* store */ } gxemul-0.6.1/src/cpus/cpu_alpha_instr_alu.cc000644 001750 001750 00000014501 13402411502 021312 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Alpha ALU instructions. (Included from tmp_alpha_misc.c.) * * * Most ALU instructions have the following arguments: * * arg[0] = pointer to destination uint64_t * arg[1] = pointer to source uint64_t nr 1 * arg[2] = pointer to source uint64_t nr 2 * * or, if ALU_IMM is set, arg[2] contains an 8-bit immediate value. * * The main function groups are: * * ALU_INS inserts * ALU_EXT extracts * ALU_MSK masks * ALU_CMOV conditional moves * ALU_CMP compares * ALU_CMPBGE byte compare * none of the above everything else (add, sub, ...) */ void ALU_N(struct cpu *cpu, struct alpha_instr_call *ic) { #ifdef ALU_INS uint64_t x = *((uint64_t *)ic->arg[1]); int r = ( #ifdef ALU_IMM ic->arg[2] #else (*((uint64_t *)ic->arg[2])) #endif & 7) * 8; #ifdef ALU_B x &= 0xff; #endif #ifdef ALU_W x &= 0xffff; #endif #ifdef ALU_L x &= 0xffffffffULL; #endif #ifdef ALU_LO x <<= r; #else r = 64 - r; if (r == 64) x = 0; else x >>= r; #endif *((uint64_t *)ic->arg[0]) = x; #else /* ! INS */ #ifdef ALU_EXT uint64_t x = *((uint64_t *)ic->arg[1]); int r = ( #ifdef ALU_IMM ic->arg[2] #else (*((uint64_t *)ic->arg[2])) #endif & 7) * 8; #ifdef ALU_LO x >>= r; #else r = 64 - r; if (r != 64) x <<= r; #endif #ifdef ALU_B x &= 0xff; #endif #ifdef ALU_W x &= 0xffff; #endif #ifdef ALU_L x &= 0xffffffffULL; #endif *((uint64_t *)ic->arg[0]) = x; #else /* ! EXT */ #ifdef ALU_MSK uint64_t x = *((uint64_t *)ic->arg[1]); #ifdef ALU_B uint64_t mask = 0x00000000000000ffULL; #endif #ifdef ALU_W uint64_t mask = 0x000000000000ffffULL; #endif #ifdef ALU_L uint64_t mask = 0x00000000ffffffffULL; #endif #ifdef ALU_Q uint64_t mask = 0xffffffffffffffffULL; #endif int r = ( #ifdef ALU_IMM ic->arg[2] #else (*((uint64_t *)ic->arg[2])) #endif & 7) * 8; #ifdef ALU_LO mask <<= r; #else if (r == 0) mask = 0; else mask >>= (64 - r); #endif *((uint64_t *)ic->arg[0]) = x & ~mask; #else /* !MSK */ #ifdef ALU_CMOV if ( #ifdef ALU_CMOV_lbc !( #endif (*((int64_t *)ic->arg[1])) #ifdef ALU_CMOV_eq == 0 #endif #ifdef ALU_CMOV_ne != 0 #endif #ifdef ALU_CMOV_le <= 0 #endif #ifdef ALU_CMOV_lt < 0 #endif #ifdef ALU_CMOV_ge >= 0 #endif #ifdef ALU_CMOV_gt > 0 #endif #ifdef ALU_CMOV_lbs & 1 #endif #ifdef ALU_CMOV_lbc & 1) #endif ) *((uint64_t *)ic->arg[0]) = #ifdef ALU_IMM (uint64_t)ic->arg[2] #else (*((uint64_t *)ic->arg[2])) #endif ; #else /* ! CMOV */ #ifdef ALU_CMPBGE uint64_t ra = *((uint64_t *)ic->arg[1]), rc = 0, rb = #ifdef ALU_IMM (uint64_t)ic->arg[2] #else (*((uint64_t *)ic->arg[2])) #endif ; int i; for (i=7; i>=0; i--) { if ((uint8_t)ra >= (uint8_t)rb) rc |= (1 << i); rb >>= 8; ra >>= 8; } *((uint64_t *)ic->arg[0]) = rc; #else /* ! CMPBGE */ #ifdef ALU_CMP uint64_t x; x = (*(( #ifdef ALU_UNSIGNED uint64_t #else int64_t #endif *)ic->arg[1])) #ifdef ALU_CMP_EQ == #endif #ifdef ALU_CMP_LE <= #endif #ifdef ALU_CMP_LT < #endif #ifdef ALU_IMM #ifdef ALU_UNSIGNED (uint64_t)ic->arg[2] #else (int64_t)ic->arg[2] #endif #else #ifdef ALU_UNSIGNED (*((uint64_t *)ic->arg[2])) #else (*((int64_t *)ic->arg[2])) #endif #endif ; #else /* !ALU_CMP */ #ifdef ALU_LONG /* Long */ int32_t x; #else /* Quad */ int64_t x; #endif #ifdef ALU_ZAP /* Prepare for zapping: */ uint64_t zapmask = 0xffffffffffffffffULL; int zapbytes = #ifdef ALU_NOT ~ #endif #ifdef ALU_IMM (int64_t)ic->arg[2] #else (*((uint64_t *)ic->arg[2])) #endif ; if (zapbytes & 0x80) zapmask &= ~0xff00000000000000ULL; if (zapbytes & 0x40) zapmask &= ~0xff000000000000ULL; if (zapbytes & 0x20) zapmask &= ~0xff0000000000ULL; if (zapbytes & 0x10) zapmask &= ~0xff00000000ULL; if (zapbytes & 0x08) zapmask &= ~0xff000000ULL; if (zapbytes & 0x04) zapmask &= ~0xff0000ULL; if (zapbytes & 0x02) zapmask &= ~0xff00ULL; if (zapbytes & 0x01) zapmask &= ~0xffULL; #endif /* ZAP */ x = ( #ifdef ALU_SRA (int64_t) #endif (*((uint64_t *)ic->arg[1])) #ifdef ALU_S4 * 4 #endif #ifdef ALU_S8 * 8 #endif ) #ifdef ALU_ADD + #endif #ifdef ALU_SUB - #endif #ifdef ALU_OR | #endif #ifdef ALU_XOR ^ #endif #ifdef ALU_AND & #endif #ifdef ALU_SLL << #endif #if defined(ALU_SRA) || defined(ALU_SRL) >> #endif #ifdef ALU_ZAP & zapmask #else /* !ZAP */ ( #ifdef ALU_NOT ~ #endif ( #ifdef ALU_IMM (int64_t)ic->arg[2] #else (*((uint64_t *)ic->arg[2])) #endif #if defined(ALU_SRA) || defined(ALU_SRL) || defined(ALU_SLL) & 63 #endif ) ) #endif /* !ZAP */ ; #endif /* !ALU_CMP */ *((uint64_t *)ic->arg[0]) = x; #endif /* ! CMPBGE */ #endif /* ! CMOV */ #endif /* ! MSK */ #endif /* ! EXT */ #endif /* ! INS */ } gxemul-0.6.1/src/cpus/cpu_alpha_instr.cc000644 001750 001750 00000102736 13402411502 020461 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Alpha instructions. * * Individual functions should keep track of cpu->n_translated_instrs. * (If no instruction was executed, then it should be decreased. If, say, 4 * instructions were combined into one function and executed, then it should * be increased by 3.) */ #include "float_emul.h" /* * nop: Do nothing. */ X(nop) { } /* * call_pal: PALcode call * * arg[0] = pal nr */ X(call_pal) { /* Synchronize PC first: */ uint64_t old_pc, low_pc = ((size_t)ic - (size_t) cpu->cd.alpha.cur_ic_page) / sizeof(struct alpha_instr_call); cpu->pc &= ~((ALPHA_IC_ENTRIES_PER_PAGE-1) << ALPHA_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ALPHA_INSTR_ALIGNMENT_SHIFT); old_pc = cpu->pc; alpha_palcode(cpu, ic->arg[0]); if (!cpu->running) { cpu->n_translated_instrs --; cpu->cd.alpha.next_ic = ¬hing_call; } else if (cpu->pc != old_pc) { /* The PC value was changed by the palcode call. */ /* Find the new physical page and update the translation pointers: */ alpha_pc_to_pointers(cpu); } } /* * jsr: Jump to SubRoutine * * arg[0] = ptr to uint64_t where to store return PC * arg[1] = ptr to uint64_t of new PC */ X(jsr) { uint64_t old_pc = cpu->pc, low_pc; uint64_t mask_within_page = ((ALPHA_IC_ENTRIES_PER_PAGE-1) << ALPHA_INSTR_ALIGNMENT_SHIFT) | ((1 << ALPHA_INSTR_ALIGNMENT_SHIFT) - 1); low_pc = ((size_t)ic - (size_t) cpu->cd.alpha.cur_ic_page) / sizeof(struct alpha_instr_call); cpu->pc &= ~((ALPHA_IC_ENTRIES_PER_PAGE-1) << ALPHA_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ALPHA_INSTR_ALIGNMENT_SHIFT) + 4; *((int64_t *)ic->arg[0]) = cpu->pc; cpu->pc = *((int64_t *)ic->arg[1]); /* * If this is a jump/return into the same code page as we were * already in, then just set cpu->cd.alpha.next_ic. */ if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) { cpu->cd.alpha.next_ic = cpu->cd.alpha.cur_ic_page + ((cpu->pc & mask_within_page) >> 2); } else { /* Find the new physical page and update pointers: */ alpha_pc_to_pointers(cpu); } } /* * jsr_trace: Jump to SubRoutine (with function call trace enabled) * * Arguments same as for jsr. */ X(jsr_trace) { cpu_functioncall_trace(cpu, *((int64_t *)ic->arg[1])); instr(jsr)(cpu, ic); } /* * jsr_0: JSR/RET, don't store return PC. * * arg[0] = ignored * arg[1] = ptr to uint64_t of new PC */ X(jsr_0) { uint64_t old_pc = cpu->pc; uint64_t mask_within_page = ((ALPHA_IC_ENTRIES_PER_PAGE-1) << ALPHA_INSTR_ALIGNMENT_SHIFT) | ((1 << ALPHA_INSTR_ALIGNMENT_SHIFT) - 1); cpu->pc = *((int64_t *)ic->arg[1]); /* * If this is a jump/return into the same code page as we were * already in, then just set cpu->cd.alpha.next_ic. */ if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) { cpu->cd.alpha.next_ic = cpu->cd.alpha.cur_ic_page + ((cpu->pc & mask_within_page) >> 2); } else { /* Find the new physical page and update pointers: */ alpha_pc_to_pointers(cpu); } } /* * jsr_0_trace: JSR/RET (with function call trace enabled) * * Arguments same as for jsr_0. */ X(jsr_0_trace) { cpu_functioncall_trace_return(cpu); instr(jsr_0)(cpu, ic); } /* * br: Branch (to a different translated page) * * arg[0] = relative offset (as an int32_t) */ X(br) { uint64_t low_pc; /* Calculate new PC from this instruction + arg[0] */ low_pc = ((size_t)ic - (size_t) cpu->cd.alpha.cur_ic_page) / sizeof(struct alpha_instr_call); cpu->pc &= ~((ALPHA_IC_ENTRIES_PER_PAGE-1) << ALPHA_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ALPHA_INSTR_ALIGNMENT_SHIFT); cpu->pc += (int32_t)ic->arg[0]; /* Find the new physical page and update the translation pointers: */ alpha_pc_to_pointers(cpu); } /* * br: Branch (to a different translated page), write return address * * arg[0] = relative offset (as an int32_t) * arg[1] = pointer to uint64_t where to write return address */ X(br_return) { uint64_t low_pc; /* Calculate new PC from this instruction + arg[0] */ low_pc = ((size_t)ic - (size_t) cpu->cd.alpha.cur_ic_page) / sizeof(struct alpha_instr_call); cpu->pc &= ~((ALPHA_IC_ENTRIES_PER_PAGE-1) << ALPHA_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ALPHA_INSTR_ALIGNMENT_SHIFT); /* ... but first, save away the return address: */ *((int64_t *)ic->arg[1]) = cpu->pc + 4; cpu->pc += (int32_t)ic->arg[0]; /* Find the new physical page and update the translation pointers: */ alpha_pc_to_pointers(cpu); } /* * beq: Branch (to a different translated page) if Equal * * arg[0] = relative offset (as an int32_t) * arg[1] = pointer to int64_t register */ X(beq) { if (*((int64_t *)ic->arg[1]) == 0) instr(br)(cpu, ic); } /* * blbs: Branch (to a different translated page) if Low Bit Set * * arg[0] = relative offset (as an int32_t) * arg[1] = pointer to int64_t register */ X(blbs) { if (*((int64_t *)ic->arg[1]) & 1) instr(br)(cpu, ic); } /* * blbc: Branch (to a different translated page) if Low Bit Clear * * arg[0] = relative offset (as an int32_t) * arg[1] = pointer to int64_t register */ X(blbc) { if (!(*((int64_t *)ic->arg[1]) & 1)) instr(br)(cpu, ic); } /* * bne: Branch (to a different translated page) if Not Equal * * arg[0] = relative offset (as an int32_t) * arg[1] = pointer to int64_t register */ X(bne) { if (*((int64_t *)ic->arg[1]) != 0) instr(br)(cpu, ic); } /* * ble: Branch (to a different translated page) if Less or Equal * * arg[0] = relative offset (as an int32_t) * arg[1] = pointer to int64_t register */ X(ble) { if (*((int64_t *)ic->arg[1]) <= 0) instr(br)(cpu, ic); } /* * blt: Branch (to a different translated page) if Less Than * * arg[0] = relative offset (as an int32_t) * arg[1] = pointer to int64_t register */ X(blt) { if (*((int64_t *)ic->arg[1]) < 0) instr(br)(cpu, ic); } /* * bge: Branch (to a different translated page) if Greater or Equal * * arg[0] = relative offset (as an int32_t) * arg[1] = pointer to int64_t register */ X(bge) { if (*((int64_t *)ic->arg[1]) >= 0) instr(br)(cpu, ic); } /* * bgt: Branch (to a different translated page) if Greater Than * * arg[0] = relative offset (as an int32_t) * arg[1] = pointer to int64_t register */ X(bgt) { if (*((int64_t *)ic->arg[1]) > 0) instr(br)(cpu, ic); } /* * br_samepage: Branch (to within the same translated page) * * arg[0] = pointer to new alpha_instr_call */ X(br_samepage) { cpu->cd.alpha.next_ic = (struct alpha_instr_call *) ic->arg[0]; } /* * br_return_samepage: Branch (to within the same translated page), * and save return address * * arg[0] = pointer to new alpha_instr_call * arg[1] = pointer to uint64_t where to store return address */ X(br_return_samepage) { uint64_t low_pc; low_pc = ((size_t)ic - (size_t) cpu->cd.alpha.cur_ic_page) / sizeof(struct alpha_instr_call); cpu->pc &= ~((ALPHA_IC_ENTRIES_PER_PAGE-1) << ALPHA_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ALPHA_INSTR_ALIGNMENT_SHIFT); *((int64_t *)ic->arg[1]) = cpu->pc + 4; cpu->cd.alpha.next_ic = (struct alpha_instr_call *) ic->arg[0]; } /* * beq_samepage: Branch (to within the same translated page) if Equal * * arg[0] = pointer to new alpha_instr_call * arg[1] = pointer to int64_t register */ X(beq_samepage) { if (*((int64_t *)ic->arg[1]) == 0) instr(br_samepage)(cpu, ic); } /* * blbs_samepage: Branch (to within the same translated page) if Low Bit Set * * arg[0] = pointer to new alpha_instr_call * arg[1] = pointer to int64_t register */ X(blbs_samepage) { if (*((int64_t *)ic->arg[1]) & 1) instr(br_samepage)(cpu, ic); } /* * blbc_samepage: Branch (to within the same translated page) if Low Bit Clear * * arg[0] = pointer to new alpha_instr_call * arg[1] = pointer to int64_t register */ X(blbc_samepage) { if (!(*((int64_t *)ic->arg[1]) & 1)) instr(br_samepage)(cpu, ic); } /* * bne_samepage: Branch (to within the same translated page) if Not Equal * * arg[0] = pointer to new alpha_instr_call * arg[1] = pointer to int64_t register */ X(bne_samepage) { if (*((int64_t *)ic->arg[1]) != 0) instr(br_samepage)(cpu, ic); } /* * ble_samepage: Branch (to within the same translated page) if Less or Equal * * arg[0] = pointer to new alpha_instr_call * arg[1] = pointer to int64_t register */ X(ble_samepage) { if (*((int64_t *)ic->arg[1]) <= 0) instr(br_samepage)(cpu, ic); } /* * blt_samepage: Branch (to within the same translated page) if Less Than * * arg[0] = pointer to new alpha_instr_call * arg[1] = pointer to int64_t register */ X(blt_samepage) { if (*((int64_t *)ic->arg[1]) < 0) instr(br_samepage)(cpu, ic); } /* * bge_samepage: Branch (to within the same translated page) * if Greater or Equal * * arg[0] = pointer to new alpha_instr_call * arg[1] = pointer to int64_t register */ X(bge_samepage) { if (*((int64_t *)ic->arg[1]) >= 0) instr(br_samepage)(cpu, ic); } /* * bgt_samepage: Branch (to within the same translated page) if Greater Than * * arg[0] = pointer to new alpha_instr_call * arg[1] = pointer to int64_t register */ X(bgt_samepage) { if (*((int64_t *)ic->arg[1]) > 0) instr(br_samepage)(cpu, ic); } /* * cvttq/c: Convert floating point to quad. * * arg[0] = pointer to rc (destination integer) * arg[2] = pointer to rb (source float) */ X(cvttq_c) { struct ieee_float_value fb; ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); reg(ic->arg[0]) = fb.nan? 0 : fb.f; } /* * cvtqt: Convert quad to floating point. * * arg[0] = pointer to rc (destination float) * arg[2] = pointer to rb (source quad integer) */ X(cvtqt) { reg(ic->arg[0]) = ieee_store_float_value(reg(ic->arg[2]), IEEE_FMT_D); } /* * fabs, fneg: Floating point absolute value, or negation. * * arg[0] = pointer to rc (destination float) * arg[2] = pointer to rb (source quad integer) */ X(fabs) { reg(ic->arg[0]) = reg(ic->arg[2]) & 0x7fffffffffffffffULL; } X(fneg) { reg(ic->arg[0]) = reg(ic->arg[2]) ^ 0x8000000000000000ULL; } /* * addt, subt, mult, divt: Floating point arithmetic. * * arg[0] = pointer to rc (destination) * arg[1] = pointer to ra (source) * arg[2] = pointer to rb (source) */ X(addt) { struct ieee_float_value fa, fb; ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); reg(ic->arg[0]) = ieee_store_float_value(fa.f + fb.f, IEEE_FMT_D); } X(subt) { struct ieee_float_value fa, fb; ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); reg(ic->arg[0]) = ieee_store_float_value(fa.f - fb.f, IEEE_FMT_D); } X(mult) { struct ieee_float_value fa, fb; ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); reg(ic->arg[0]) = ieee_store_float_value(fa.f * fb.f, IEEE_FMT_D); } X(divt) { struct ieee_float_value fa, fb; ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); reg(ic->arg[0]) = ieee_store_float_value(fa.f / fb.f, IEEE_FMT_D); } X(cmpteq) { struct ieee_float_value fa, fb; int res = 0; ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); if (fa.nan | fb.nan) res = 0; else res = fa.f == fb.f; reg(ic->arg[0]) = res; } X(cmptlt) { struct ieee_float_value fa, fb; int res = 0; ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); if (fa.nan | fb.nan) res = 0; else res = fa.f < fb.f; reg(ic->arg[0]) = res; } X(cmptle) { struct ieee_float_value fa, fb; int res = 0; ieee_interpret_float_value(reg(ic->arg[1]), &fa, IEEE_FMT_D); ieee_interpret_float_value(reg(ic->arg[2]), &fb, IEEE_FMT_D); if (fa.nan | fb.nan) res = 0; else res = fa.f <= fb.f; reg(ic->arg[0]) = res; } /* * implver: Return CPU implver value. * * arg[0] = pointer to destination uint64_t */ X(implver) { reg(ic->arg[0]) = cpu->cd.alpha.cpu_type.implver; } /* * mull, mull_imm: Signed Multiply 32x32 => 32. * * arg[0] = pointer to destination uint64_t * arg[1] = pointer to source uint64_t * arg[2] = pointer to source uint64_t or immediate */ X(mull) { int32_t a = reg(ic->arg[1]); int32_t b = reg(ic->arg[2]); reg(ic->arg[0]) = (int64_t)(int32_t)(a * b); } X(mull_imm) { int32_t a = reg(ic->arg[1]); int32_t b = ic->arg[2]; reg(ic->arg[0]) = (int64_t)(int32_t)(a * b); } /* * mulq, mulq_imm: Unsigned Multiply 64x64 => 64. * * arg[0] = pointer to destination uint64_t * arg[1] = pointer to source uint64_t * arg[2] = pointer to source uint64_t or immediate */ X(mulq) { reg(ic->arg[0]) = reg(ic->arg[1]) * reg(ic->arg[2]); } X(mulq_imm) { reg(ic->arg[0]) = reg(ic->arg[1]) * ic->arg[2]; } /* * umulh: Unsigned Multiply 64x64 => 128. Store high part in dest reg. * * arg[0] = pointer to destination uint64_t * arg[1] = pointer to source uint64_t * arg[2] = pointer to source uint64_t */ X(umulh) { uint64_t reshi = 0, reslo = 0; uint64_t s1 = reg(ic->arg[1]), s2 = reg(ic->arg[2]); int i, bit; for (i=0; i<64; i++) { bit = (s1 & 0x8000000000000000ULL)? 1 : 0; s1 <<= 1; /* If bit in s1 set, then add s2 to reshi/lo: */ if (bit) { uint64_t old_reslo = reslo; reslo += s2; if (reslo < old_reslo) reshi ++; } if (i != 63) { reshi <<= 1; reshi += (reslo & 0x8000000000000000ULL? 1 : 0); reslo <<= 1; } } reg(ic->arg[0]) = reshi; } /* * lda: Load address. * * arg[0] = pointer to destination uint64_t * arg[1] = pointer to source uint64_t * arg[2] = offset (possibly as an int32_t) */ X(lda) { reg(ic->arg[0]) = reg(ic->arg[1]) + (int64_t)(int32_t)ic->arg[2]; } /* * lda_0: Load address compared to the zero register. * * arg[0] = pointer to destination uint64_t * arg[1] = ignored * arg[2] = offset (possibly as an int32_t) */ X(lda_0) { reg(ic->arg[0]) = (int64_t)(int32_t)ic->arg[2]; } /* * clear: Clear a 64-bit register. * * arg[0] = pointer to destination uint64_t */ X(clear) { reg(ic->arg[0]) = 0; } /* * rdcc: Read the Cycle Counter into a 64-bit register. * * arg[0] = pointer to destination uint64_t */ X(rdcc) { reg(ic->arg[0]) = cpu->cd.alpha.pcc; /* TODO: actually keep the pcc updated! */ cpu->cd.alpha.pcc += 20; } #include "tmp_alpha_misc.cc" /*****************************************************************************/ X(end_of_page) { /* Update the PC: (offset 0, but on the next page) */ cpu->pc &= ~((ALPHA_IC_ENTRIES_PER_PAGE-1) << ALPHA_INSTR_ALIGNMENT_SHIFT); cpu->pc += (ALPHA_IC_ENTRIES_PER_PAGE << ALPHA_INSTR_ALIGNMENT_SHIFT); /* Find the new physical page and update the translation pointers: */ alpha_pc_to_pointers(cpu); /* end_of_page doesn't count as an executed instruction: */ cpu->n_translated_instrs --; } /*****************************************************************************/ /* * alpha_instr_to_be_translated(): * * Translate an instruction word into an alpha_instr_call. ic is filled in with * valid data for the translated instruction, or a "nothing" instruction if * there was a translation failure. The newly translated instruction is then * executed. */ X(to_be_translated) { uint64_t addr, low_pc; uint32_t iword; unsigned char *page; unsigned char ib[4]; void (*samepage_function)(struct cpu *, struct alpha_instr_call *); int opcode, ra, rb, func, rc, imm, load, loadstore_type, fp, llsc; /* Figure out the (virtual) address of the instruction: */ low_pc = ((size_t)ic - (size_t)cpu->cd.alpha.cur_ic_page) / sizeof(struct alpha_instr_call); addr = cpu->pc & ~((ALPHA_IC_ENTRIES_PER_PAGE-1) << ALPHA_INSTR_ALIGNMENT_SHIFT); addr += (low_pc << ALPHA_INSTR_ALIGNMENT_SHIFT); addr &= ~((1 << ALPHA_INSTR_ALIGNMENT_SHIFT) - 1); cpu->pc = addr; /* Read the instruction word from memory: */ { const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; uint32_t x1 = (addr >> (64-DYNTRANS_L1N)) & mask1; uint32_t x2 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; uint32_t x3 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N- DYNTRANS_L3N)) & mask3; struct DYNTRANS_L2_64_TABLE *l2 = cpu->cd.alpha.l1_64[x1]; struct DYNTRANS_L3_64_TABLE *l3 = l2->l3[x2]; page = l3->host_load[x3]; } if (page != NULL) { /* fatal("TRANSLATION HIT!\n"); */ memcpy(ib, page + (addr & 8191), sizeof(ib)); } else { /* fatal("TRANSLATION MISS!\n"); */ if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0], sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) { fatal("to_be_translated(): read failed: TODO\n"); goto bad; } } /* Alpha instruction words are always little-endian. Convert to host order: */ { uint32_t *p = (uint32_t *) ib; iword = LE32_TO_HOST( *p ); } #define DYNTRANS_TO_BE_TRANSLATED_HEAD #include "cpu_dyntrans.cc" #undef DYNTRANS_TO_BE_TRANSLATED_HEAD opcode = (iword >> 26) & 63; ra = (iword >> 21) & 31; rb = (iword >> 16) & 31; func = (iword >> 5) & 0x7ff; rc = iword & 31; imm = iword & 0xffff; switch (opcode) { case 0x00: /* CALL_PAL */ ic->f = instr(call_pal); ic->arg[0] = (size_t) (iword & 0x3ffffff); break; case 0x08: /* LDA */ case 0x09: /* LDAH */ if (ra == ALPHA_ZERO) { ic->f = instr(nop); break; } /* TODO: A special case which is common is to add or subtract a small offset from sp. */ ic->f = instr(lda); ic->arg[0] = (size_t) &cpu->cd.alpha.r[ra]; ic->arg[1] = (size_t) &cpu->cd.alpha.r[rb]; if (rb == ALPHA_ZERO) ic->f = instr(lda_0); ic->arg[2] = (ssize_t)(int16_t)imm; if (opcode == 0x09) ic->arg[2] <<= 16; break; case 0x0b: /* LDQ_U */ case 0x0f: /* STQ_U */ if (ra == ALPHA_ZERO && opcode == 0x0b) { ic->f = instr(nop); break; } if (opcode == 0x0b) ic->f = instr(ldq_u); else ic->f = instr(stq_u); ic->arg[0] = (size_t) &cpu->cd.alpha.r[ra]; ic->arg[1] = (size_t) &cpu->cd.alpha.r[rb]; ic->arg[2] = (ssize_t)(int16_t)imm; break; case 0x0a: case 0x0c: case 0x0d: case 0x0e: case 0x22: case 0x23: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: loadstore_type = 0; fp = 0; load = 0; llsc = 0; switch (opcode) { case 0x0a: loadstore_type = 0; load = 1; break; /* ldbu */ case 0x0c: loadstore_type = 1; load = 1; break; /* ldwu */ case 0x0d: loadstore_type = 1; break; /* stw */ case 0x0e: loadstore_type = 0; break; /* stb */ case 0x22: loadstore_type = 2; load = 1; fp = 1; break; /*lds*/ case 0x23: loadstore_type = 3; load = 1; fp = 1; break; /*ldt*/ case 0x26: loadstore_type = 2; fp = 1; break; /* sts */ case 0x27: loadstore_type = 3; fp = 1; break; /* stt */ case 0x28: loadstore_type = 2; load = 1; break; /* ldl */ case 0x29: loadstore_type = 3; load = 1; break; /* ldq */ case 0x2a: loadstore_type = 2; load = llsc = 1; break;/* ldl_l*/ case 0x2b: loadstore_type = 3; load = llsc = 1; break;/* ldq_l*/ case 0x2c: loadstore_type = 2; break; /* stl */ case 0x2d: loadstore_type = 3; break; /* stq */ case 0x2e: loadstore_type = 2; llsc = 1; break; /* stl_c */ case 0x2f: loadstore_type = 3; llsc = 1; break; /* stq_c */ } ic->f = alpha_loadstore[ loadstore_type + (imm==0? 4 : 0) + 8 * load + 16 * llsc]; /* Load to the zero register is treated as a prefetch hint. It is ignored here. */ if (load && ra == ALPHA_ZERO) { ic->f = instr(nop); break; } if (fp) ic->arg[0] = (size_t) &cpu->cd.alpha.f[ra]; else ic->arg[0] = (size_t) &cpu->cd.alpha.r[ra]; ic->arg[1] = (size_t) &cpu->cd.alpha.r[rb]; ic->arg[2] = (ssize_t)(int16_t)imm; break; case 0x10: if (rc == ALPHA_ZERO) { ic->f = instr(nop); break; } ic->arg[0] = (size_t) &cpu->cd.alpha.r[rc]; ic->arg[1] = (size_t) &cpu->cd.alpha.r[ra]; if (func & 0x80) ic->arg[2] = (size_t)((rb << 3) + (func >> 8)); else ic->arg[2] = (size_t) &cpu->cd.alpha.r[rb]; switch (func & 0xff) { case 0x00: ic->f = instr(addl); break; case 0x02: ic->f = instr(s4addl); break; case 0x09: ic->f = instr(subl); break; case 0x0b: ic->f = instr(s4subl); break; case 0x0f: ic->f = instr(cmpbge); break; case 0x12: ic->f = instr(s8addl); break; case 0x1b: ic->f = instr(s8subl); break; case 0x1d: ic->f = instr(cmpult); break; case 0x20: ic->f = instr(addq); break; case 0x22: ic->f = instr(s4addq); break; case 0x29: ic->f = instr(subq); break; case 0x2b: ic->f = instr(s4subq); break; case 0x2d: ic->f = instr(cmpeq); break; case 0x32: ic->f = instr(s8addq); break; case 0x3b: ic->f = instr(s8subq); break; case 0x3d: ic->f = instr(cmpule); break; case 0x4d: ic->f = instr(cmplt); break; // case 0x69: ic->f = instr(subq_v); break; case 0x6d: ic->f = instr(cmple); break; case 0x80: ic->f = instr(addl_imm); break; case 0x82: ic->f = instr(s4addl_imm); break; case 0x89: ic->f = instr(subl_imm); break; case 0x8b: ic->f = instr(s4subl_imm); break; case 0x8f: ic->f = instr(cmpbge_imm); break; case 0x92: ic->f = instr(s8addl_imm); break; case 0x9b: ic->f = instr(s8subl_imm); break; case 0x9d: ic->f = instr(cmpult_imm); break; case 0xa0: ic->f = instr(addq_imm); break; case 0xa2: ic->f = instr(s4addq_imm); break; case 0xa9: ic->f = instr(subq_imm); break; case 0xab: ic->f = instr(s4subq_imm); break; case 0xad: ic->f = instr(cmpeq_imm); break; case 0xb2: ic->f = instr(s8addq_imm); break; case 0xbb: ic->f = instr(s8subq_imm); break; case 0xbd: ic->f = instr(cmpule_imm); break; case 0xcd: ic->f = instr(cmplt_imm); break; case 0xed: ic->f = instr(cmple_imm); break; default:if (!cpu->translation_readahead) fatal("[ Alpha: unimplemented function 0x%03x " "for opcode 0x%02x ]\n", func, opcode); goto bad; } break; case 0x11: if (rc == ALPHA_ZERO) { ic->f = instr(nop); break; } ic->arg[0] = (size_t) &cpu->cd.alpha.r[rc]; ic->arg[1] = (size_t) &cpu->cd.alpha.r[ra]; if (func & 0x80) ic->arg[2] = (size_t)((rb << 3) + (func >> 8)); else ic->arg[2] = (size_t) &cpu->cd.alpha.r[rb]; switch (func & 0xff) { case 0x00: ic->f = instr(and); break; case 0x08: ic->f = instr(andnot); break; case 0x14: ic->f = instr(cmovlbs); break; case 0x16: ic->f = instr(cmovlbc); break; case 0x20: ic->f = instr(or); if (ra == ALPHA_ZERO || rb == ALPHA_ZERO) { if (ra == ALPHA_ZERO) ra = rb; ic->f = alpha_mov_r_r[ra + rc*32]; } break; case 0x24: ic->f = instr(cmoveq); break; case 0x26: ic->f = instr(cmovne); break; case 0x28: ic->f = instr(ornot); break; case 0x40: ic->f = instr(xor); break; case 0x44: ic->f = instr(cmovlt); break; case 0x46: ic->f = instr(cmovge); break; case 0x48: ic->f = instr(xornot); break; case 0x64: ic->f = instr(cmovle); break; case 0x66: ic->f = instr(cmovgt); break; case 0x80: ic->f = instr(and_imm); break; case 0x88: ic->f = instr(andnot_imm); break; case 0x94: ic->f = instr(cmovlbs_imm); break; case 0x96: ic->f = instr(cmovlbc_imm); break; case 0xa0: ic->f = instr(or_imm); break; case 0xa4: ic->f = instr(cmoveq_imm); break; case 0xa6: ic->f = instr(cmovne_imm); break; case 0xa8: ic->f = instr(ornot_imm); break; case 0xc0: ic->f = instr(xor_imm); break; case 0xc4: ic->f = instr(cmovlt_imm); break; case 0xc6: ic->f = instr(cmovge_imm); break; case 0xc8: ic->f = instr(xornot_imm); break; case 0xe4: ic->f = instr(cmovle_imm); break; case 0xe6: ic->f = instr(cmovgt_imm); break; case 0xec: ic->f = instr(implver); break; default:if (!cpu->translation_readahead) fatal("[ Alpha: unimplemented function 0x%03x " "for opcode 0x%02x ]\n", func, opcode); goto bad; } break; case 0x12: if (rc == ALPHA_ZERO) { ic->f = instr(nop); break; } ic->arg[0] = (size_t) &cpu->cd.alpha.r[rc]; ic->arg[1] = (size_t) &cpu->cd.alpha.r[ra]; if (func & 0x80) ic->arg[2] = (size_t)((rb << 3) + (func >> 8)); else ic->arg[2] = (size_t) &cpu->cd.alpha.r[rb]; switch (func & 0xff) { case 0x02: ic->f = instr(mskbl); break; case 0x06: ic->f = instr(extbl); break; case 0x0b: ic->f = instr(insbl); break; case 0x12: ic->f = instr(mskwl); break; case 0x16: ic->f = instr(extwl); break; case 0x1b: ic->f = instr(inswl); break; case 0x22: ic->f = instr(mskll); break; case 0x26: ic->f = instr(extll); break; case 0x2b: ic->f = instr(insll); break; case 0x30: ic->f = instr(zap); break; case 0x31: ic->f = instr(zapnot); break; case 0x32: ic->f = instr(mskql); break; case 0x34: ic->f = instr(srl); break; case 0x36: ic->f = instr(extql); break; case 0x39: ic->f = instr(sll); break; case 0x3b: ic->f = instr(insql); break; case 0x3c: ic->f = instr(sra); break; case 0x52: ic->f = instr(mskwh); break; case 0x57: ic->f = instr(inswh); break; case 0x5a: ic->f = instr(extwh); break; case 0x62: ic->f = instr(msklh); break; case 0x67: ic->f = instr(inslh); break; case 0x6a: ic->f = instr(extlh); break; case 0x72: ic->f = instr(mskqh); break; case 0x77: ic->f = instr(insqh); break; case 0x7a: ic->f = instr(extqh); break; case 0x82: ic->f = instr(mskbl_imm); break; case 0x86: ic->f = instr(extbl_imm); break; case 0x8b: ic->f = instr(insbl_imm); break; case 0x92: ic->f = instr(mskwl_imm); break; case 0x96: ic->f = instr(extwl_imm); break; case 0x9b: ic->f = instr(inswl_imm); break; case 0xa2: ic->f = instr(mskll_imm); break; case 0xa6: ic->f = instr(extll_imm); break; case 0xab: ic->f = instr(insll_imm); break; case 0xb0: ic->f = instr(zap_imm); break; case 0xb1: ic->f = instr(zapnot_imm); break; case 0xb2: ic->f = instr(mskql_imm); break; case 0xb4: ic->f = instr(srl_imm); break; case 0xb6: ic->f = instr(extql_imm); break; case 0xb9: ic->f = instr(sll_imm); break; case 0xbb: ic->f = instr(insql_imm); break; case 0xbc: ic->f = instr(sra_imm); break; case 0xd2: ic->f = instr(mskwh_imm); break; case 0xd7: ic->f = instr(inswh_imm); break; case 0xda: ic->f = instr(extwh_imm); break; case 0xe2: ic->f = instr(msklh_imm); break; case 0xe7: ic->f = instr(inslh_imm); break; case 0xea: ic->f = instr(extlh_imm); break; case 0xf2: ic->f = instr(mskqh_imm); break; case 0xf7: ic->f = instr(insqh_imm); break; case 0xfa: ic->f = instr(extqh_imm); break; default:if (!cpu->translation_readahead) fatal("[ Alpha: unimplemented function 0x%03x " "for opcode 0x%02x ]\n", func, opcode); goto bad; } break; case 0x13: if (rc == ALPHA_ZERO) { ic->f = instr(nop); break; } ic->arg[0] = (size_t) &cpu->cd.alpha.r[rc]; ic->arg[1] = (size_t) &cpu->cd.alpha.r[ra]; if (func & 0x80) ic->arg[2] = (size_t)((rb << 3) + (func >> 8)); else ic->arg[2] = (size_t) &cpu->cd.alpha.r[rb]; // TODO: mulq/v etc? overflow detection // bit 0..6 are function, but 7 is "imm" bit. switch (func & 0xff) { case 0x00: ic->f = instr(mull); break; case 0x20: ic->f = instr(mulq); break; case 0x30: ic->f = instr(umulh); break; case 0x80: ic->f = instr(mull_imm); break; case 0xa0: ic->f = instr(mulq_imm); break; default:if (!cpu->translation_readahead) fatal("[ Alpha: unimplemented function 0x%03x " "for opcode 0x%02x ]\n", func, opcode); goto bad; } break; case 0x16: if (rc == ALPHA_ZERO) { ic->f = instr(nop); break; } ic->arg[0] = (size_t) &cpu->cd.alpha.f[rc]; ic->arg[1] = (size_t) &cpu->cd.alpha.f[ra]; ic->arg[2] = (size_t) &cpu->cd.alpha.f[rb]; switch (func & 0x7ff) { case 0x02f: ic->f = instr(cvttq_c); break; case 0x0a0: ic->f = instr(addt); break; case 0x0a1: ic->f = instr(subt); break; case 0x0a2: ic->f = instr(mult); break; case 0x0a3: ic->f = instr(divt); break; case 0x0a5: ic->f = instr(cmpteq); break; case 0x0a6: ic->f = instr(cmptlt); break; case 0x0a7: ic->f = instr(cmptle); break; case 0x0be: ic->f = instr(cvtqt); break; default:if (!cpu->translation_readahead) fatal("[ Alpha: unimplemented function 0x%03x " "for opcode 0x%02x ]\n", func, opcode); goto bad; } break; case 0x17: if (rc == ALPHA_ZERO) { ic->f = instr(nop); break; } ic->arg[0] = (size_t) &cpu->cd.alpha.f[rc]; ic->arg[1] = (size_t) &cpu->cd.alpha.f[ra]; ic->arg[2] = (size_t) &cpu->cd.alpha.f[rb]; switch (func & 0x7ff) { case 0x020: /* fabs (or fclr): */ if (ra == 31 && rb == 31) ic->f = instr(clear); else ic->f = instr(fabs); break; case 0x021: ic->f = instr(fneg); break; default:if (!cpu->translation_readahead) fatal("[ Alpha: unimplemented function 0x%03x " "for opcode 0x%02x ]\n", func, opcode); goto bad; } break; case 0x18: switch (iword & 0xffff) { case 0x4000: /* mb */ case 0x4400: /* wmb */ ic->f = instr(nop); break; case 0xc000: /* rdcc ra */ if (ra == ALPHA_ZERO) { ic->f = instr(nop); break; } ic->arg[0] = (size_t) &cpu->cd.alpha.r[ra]; ic->f = instr(rdcc); break; default:if (!cpu->translation_readahead) fatal("[ Alpha: unimplemented function 0x%03x " "for opcode 0x%02x ]\n", func, opcode); goto bad; } break; case 0x1a: switch ((iword >> 14) & 3) { case 0: /* JMP */ case 1: /* JSR */ case 2: /* RET */ ic->arg[0] = (size_t) &cpu->cd.alpha.r[ra]; ic->arg[1] = (size_t) &cpu->cd.alpha.r[rb]; if (ra == ALPHA_ZERO) { if (cpu->machine->show_trace_tree && rb == ALPHA_RA) ic->f = instr(jsr_0_trace); else ic->f = instr(jsr_0); } else { if (cpu->machine->show_trace_tree) ic->f = instr(jsr_trace); else ic->f = instr(jsr); } break; default:if (!cpu->translation_readahead) fatal("[ Alpha: unimpl JSR type %i, ra=%i " "rb=%i ]\n", ((iword >> 14) & 3), ra, rb); goto bad; } break; case 0x30: /* BR */ case 0x31: /* FBEQ */ case 0x34: /* BSR */ case 0x35: /* FBNE */ case 0x38: /* BLBC */ case 0x39: /* BEQ */ case 0x3a: /* BLT */ case 0x3b: /* BLE */ case 0x3c: /* BLBS */ case 0x3d: /* BNE */ case 0x3e: /* BGE */ case 0x3f: /* BGT */ /* To avoid a GCC warning: */ samepage_function = instr(nop); fp = 0; switch (opcode) { case 0x30: case 0x34: ic->f = instr(br); samepage_function = instr(br_samepage); if (ra != ALPHA_ZERO) { ic->f = instr(br_return); samepage_function = instr(br_return_samepage); } break; case 0x38: ic->f = instr(blbc); samepage_function = instr(blbc_samepage); break; case 0x31: fp = 1; case 0x39: ic->f = instr(beq); samepage_function = instr(beq_samepage); break; case 0x3a: ic->f = instr(blt); samepage_function = instr(blt_samepage); break; case 0x3b: ic->f = instr(ble); samepage_function = instr(ble_samepage); break; case 0x3c: ic->f = instr(blbs); samepage_function = instr(blbs_samepage); break; case 0x35: fp = 1; case 0x3d: ic->f = instr(bne); samepage_function = instr(bne_samepage); break; case 0x3e: ic->f = instr(bge); samepage_function = instr(bge_samepage); break; case 0x3f: ic->f = instr(bgt); samepage_function = instr(bgt_samepage); break; } if (fp) ic->arg[1] = (size_t) &cpu->cd.alpha.f[ra]; else ic->arg[1] = (size_t) &cpu->cd.alpha.r[ra]; ic->arg[0] = (iword & 0x001fffff) << 2; /* Sign-extend: */ if (ic->arg[0] & 0x00400000) ic->arg[0] |= 0xffffffffff800000ULL; /* Branches are calculated as PC + 4 + offset. */ ic->arg[0] = (size_t)(ic->arg[0] + 4); /* Special case: branch within the same page: */ { uint64_t mask_within_page = ((ALPHA_IC_ENTRIES_PER_PAGE-1) << 2) | 3; uint64_t old_pc = addr; uint64_t new_pc = old_pc + (int32_t)ic->arg[0]; if ((old_pc & ~mask_within_page) == (new_pc & ~mask_within_page)) { ic->f = samepage_function; ic->arg[0] = (size_t) ( cpu->cd.alpha.cur_ic_page + ((new_pc & mask_within_page) >> 2)); } } break; default:if (!cpu->translation_readahead) fatal("[ UNIMPLEMENTED Alpha opcode 0x%x ]\n", opcode); goto bad; } #define DYNTRANS_TO_BE_TRANSLATED_TAIL #include "cpu_dyntrans.cc" #undef DYNTRANS_TO_BE_TRANSLATED_TAIL } gxemul-0.6.1/src/cpus/generate_arm_r.c000644 001750 001750 00000023063 13402411502 020110 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Generate functions for computing "reg" operands. */ #include #include void sync_pc(void) { printf("\tuint32_t tmp, low_pc = ((size_t)ic - (size_t)\n" "\t cpu->cd.arm.cur_ic_page)/sizeof(struct arm_instr_call);\n"); printf("\ttmp = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<\n" "\t ARM_INSTR_ALIGNMENT_SHIFT);\n"); printf("\ttmp += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT) + 8;\n"); } void f(int s, int func, int only_name) { int rm = func & 15; int c = (func >> 7) & 31; int t = (func >> 4) & 7; char name[200]; int pc = rm == 15, rc = c >> 1; snprintf(name, sizeof(name), "arm_r%s_r%i_t%i_c%i", s? "s" : "", rm, t, c); if (only_name) { printf("%s", name); return; } printf("uint32_t %s(struct cpu *cpu, struct arm_instr_call *ic)" " {\n", name); if (pc) sync_pc(); switch (t) { case 0: /* lsl c (Logical Shift Left by constant) */ if (s) { printf("{ uint32_t x = "); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]", rm); printf(";\n"); if (c != 0) { printf("cpu->cd.arm.flags &= ~ARM_F_C;\n"); printf("if (x & 0x%x)\n" "\tcpu->cd.arm.flags |= ARM_F_C;\n", (int)(0x80000000 >> (c-1))); printf("x <<= %i;\n", c); } printf(" return x; }\n"); } else { if (pc) printf("\treturn tmp"); else printf("\treturn cpu->cd.arm.r[%i]", rm); if (c != 0) printf(" << %i", c); printf(";\n"); } break; case 1: /* lsl Rc (Logical Shift Left by register) */ if (s) { printf("{ uint32_t x = "); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]", rm); printf(";\n"); printf(" uint32_t y = cpu->cd.arm.r[%i] & 255;\n", rc); printf(" if (y != 0) {\n"); printf(" cpu->cd.arm.flags &= ~ARM_F_C;\n"); printf(" if (y >= 32) return 0;\n"); printf(" x <<= (y - 1);\n"); printf(" if (x & 0x80000000)\n" "\tcpu->cd.arm.flags |= ARM_F_C;\n"); printf(" x <<= 1;\n"); printf(" }\n"); printf(" return x; }\n"); } else { printf("{ uint32_t y = cpu->cd.arm.r[%i] & 255;\n", rc); printf(" uint32_t x ="); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]", rm); printf(";\n"); printf("if (y > 31) return 0; else x <<= y;\n"); printf("return x; }\n"); } break; case 2: /* lsr c (Logical Shift Right by constant) */ /* 1..32 */ if (s) { printf("{ uint32_t x = "); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]", rm); printf(";\n"); if (c == 0) c = 32; printf("cpu->cd.arm.flags &= ~ARM_F_C;\n"); printf("if (x & 0x%x)\n" "\tcpu->cd.arm.flags |= ARM_F_C;\n", (int)(1 << (c-1))); if (c == 32) printf("x = 0;\n"); else printf("x >>= %i;\n", c); printf(" return x; }\n"); } else { if (c == 0) printf("\treturn 0;\n"); else { if (pc) printf("\treturn tmp"); else printf("\treturn cpu->cd.arm.r[%i]",rm); printf(" >> %i;\n", c); } } break; case 3: /* lsr Rc (Logical Shift Right by register) */ if (s) { printf("{ uint32_t x = "); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]", rm); printf(",y=cpu->cd.arm.r[%i]&255;\n", rc); printf("if(y==0) return x;\n"); printf("cpu->cd.arm.flags &= ~ARM_F_C;\n"); printf("if(y>31) y=32;\n"); printf("y--; x >>= y;\n"); printf("if (x & 1) " "cpu->cd.arm.flags |= ARM_F_C;\n"); printf(" return x >> 1; }\n"); } else { printf("{ uint32_t y=cpu->cd.arm.r[%i]&255;\n", rc); printf("uint32_t x="); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]",rm); printf("; "); printf("if (y>=32) return 0;\n"); printf("return x >> y; } "); } break; case 4: /* asr c (Arithmetic Shift Right by constant) */ /* 1..32 */ if (s) { printf("{ int32_t x = "); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]", rm); printf(";\n"); if (c == 0) c = 32; printf("cpu->cd.arm.flags &= ~ARM_F_C;\n"); printf("if (x & 0x%x)\n" "\tcpu->cd.arm.flags |= ARM_F_C;\n", (int)(1 << (c-1))); if (c == 32) printf("x = (x<0)? 0xffffffff : 0;\n"); else printf("x >>= %i;\n", c); printf(" return x; }\n"); } else { if (c == 0) { printf("\treturn "); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]",rm); printf(" & 0x80000000? 0xffffffff : 0;\n"); } else { printf("return (int32_t)"); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]",rm); printf(" >> %i;\n", c); } } break; case 5: /* asr Rc (Arithmetic Shift Right by register) */ if (s) { printf("{ int32_t x = "); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]", rm); printf(",y=cpu->cd.arm.r[%i]&255;\n", rc); printf("if(y==0) return x;\n"); printf("cpu->cd.arm.flags &= ~ARM_F_C;\n"); printf("if(y>31) y=31;\n"); printf("y--; x >>= y;\n"); printf("if (x & 1) " "cpu->cd.arm.flags |= ARM_F_C;\n"); printf(" return (int32_t)x >> 1; }\n"); } else { printf("{ int32_t y=cpu->cd.arm.r[%i]&255;\n", rc); printf("int32_t x="); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]",rm); printf("; "); printf("if (y>=31) return (x<0)?0xffffffff:0;\n"); printf("return (int32_t)x >> y; } "); } break; case 6: /* ror c OR rrx (Arithmetic Shift Right by constant) */ /* 0=rrx, 1..31=ror */ if (c == 0) { printf("{ uint64_t x="); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]",rm); printf("; if (cpu->cd.arm.flags & ARM_F_C)" " x |= 0x100000000ULL;"); if (s) { printf("cpu->cd.arm.flags &= ~ARM_F_C;" "if(x&1) cpu->cd.arm.flags |= " "ARM_F_C;"); } printf("return x >> 1; }\n"); } else if (s) { printf("{ uint64_t x = "); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]", rm); printf("; x |= (x << 32);\n"); printf("cpu->cd.arm.flags &= ~ARM_F_C;\n"); printf("if (x & 0x%x)\n" "\tcpu->cd.arm.flags |= ARM_F_C;\n", (int)(1 << (c-1))); printf(" return x >> %i; }\n", c); } else { printf("{ uint64_t x="); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]",rm); printf("; x |= (x << 32); "); printf("return x >> %i; }\n", c); } break; case 7: /* ror Rc (Rotate Right by register) */ if (s) { printf("{ uint64_t x = "); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]", rm); printf("; int y=cpu->cd.arm.r[%i]&255;\n", rc); printf("if(y==0) return x;\n"); printf("y --; y &= 31; x >>= y;\n"); printf("cpu->cd.arm.flags &= ~ARM_F_C;\n"); printf("if (x & 1) " "cpu->cd.arm.flags |= ARM_F_C;\n"); printf(" return x >> 1; }\n"); } else { printf("{ int y=cpu->cd.arm.r[%i]&31;\n", rc); printf("uint64_t x="); if (pc) printf("tmp"); else printf("cpu->cd.arm.r[%i]",rm); printf("; x |= (x << 32); "); printf("return (x >> y); } "); } break; default: printf("\tprintf(\"%s\\n\");\n", name); printf("\texit(1); /* TODO */\n\treturn 0;\n"); } printf("}\n"); } int main(int argc, char *argv[]) { int s, func, f_start, f_end; if (argc < 3) { fprintf(stderr, "usage: %s start end\n", argv[0]); exit(1); } f_start = strtol(argv[1], NULL, 0); f_end = strtol(argv[2], NULL, 0); printf("/*\n * DO NOT EDIT! AUTOMATICALLY GENERATED!\n */\n\n"); printf("#include \n"); printf("#include \n"); printf("#include \"cpu.h\"\n"); printf("#include \"misc.h\"\n"); printf("\n\n"); if (f_start != 0 || f_end != 0) { for (s=0; s<=1; s++) for (func=f_start; func<=f_end; func++) f(s, func, 0); } else { for (s=0; s<=1; s++) for (func=0; func<=0xfff; func++) { printf("extern uint32_t "); f(s, func, 1); printf("(struct cpu *, struct arm_" "instr_call *);\n"); } printf("\nuint32_t (*arm_r[8192])(struct cpu *," " struct arm_instr_call *) = {\n"); for (s=0; s<=1; s++) for (func=0; func<=0xfff; func++) { printf("\t"); f(s, func, 1); if (s!=1 || func!=0xfff) printf(","); printf("\n"); } printf("};\n\n"); } return 0; } gxemul-0.6.1/src/cpus/cpu_alpha_instr_loadstore.cc000644 001750 001750 00000015354 13402411502 022534 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Alpha load/store instructions. (Included from cpu_alpha_instr_inc.c.) * * * Load/store instructions have the following arguments: * * arg[0] = pointer to the register to load to or store from (uint64_t) * arg[1] = pointer to the base register (uint64_t) * arg[2] = offset (as an int32_t) * * NOTE: * Alpha byte and word loads (8- and 16-bit) are unsigned, while * 32-bit long words are sign-extended up to 64 bits during a load! */ #ifndef LS_IGNORE_OFFSET static void LS_GENERIC_N(struct cpu *cpu, struct alpha_instr_call *ic) { #ifdef LS_B unsigned char data[1]; #endif #ifdef LS_W unsigned char data[2]; #endif #ifdef LS_L unsigned char data[4]; #endif #ifdef LS_Q unsigned char data[8]; #endif uint64_t addr = *((uint64_t *)ic->arg[1]); uint64_t data_x; addr += (int32_t)ic->arg[2]; #ifdef LS_UNALIGNED addr &= ~7; #endif #ifdef LS_LOAD /* Load: */ if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_READ, CACHE_DATA)) { fatal("store failed: TODO\n"); exit(1); } data_x = data[0]; #ifndef LS_B data_x += (data[1] << 8); #ifndef LS_W data_x += (data[2] << 16); data_x += ((uint64_t)data[3] << 24); #ifdef LS_L data_x = (int64_t)(int32_t)data_x; #endif #ifndef LS_L data_x += ((uint64_t)data[4] << 32); data_x += ((uint64_t)data[5] << 40); data_x += ((uint64_t)data[6] << 48); data_x += ((uint64_t)data[7] << 56); #endif #endif #endif *((uint64_t *)ic->arg[0]) = data_x; #else /* Store: */ data_x = *((uint64_t *)ic->arg[0]); data[0] = data_x; #ifndef LS_B data[1] = data_x >> 8; #ifndef LS_W data[2] = data_x >> 16; data[3] = data_x >> 24; #ifndef LS_L data[4] = data_x >> 32; data[5] = data_x >> 40; data[6] = data_x >> 48; data[7] = data_x >> 56; #endif #endif #endif if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_WRITE, CACHE_DATA)) { fatal("store failed: TODO\n"); exit(1); } #ifdef LS_LLSC #ifndef LS_LOAD *((uint64_t *)ic->arg[0]) = 1; #endif #endif #endif } #endif static void LS_N(struct cpu *cpu, struct alpha_instr_call *ic) { unsigned char *page; uint64_t addr = (*((uint64_t *)ic->arg[1])) #ifndef LS_IGNORE_OFFSET + (int32_t)ic->arg[2] #endif ; const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; uint32_t x1, x2, x3, c; struct DYNTRANS_L2_64_TABLE *l2; struct DYNTRANS_L3_64_TABLE *l3; x1 = (addr >> (64-DYNTRANS_L1N)) & mask1; x2 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; x3 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N-DYNTRANS_L3N)) & mask3; /* fatal("X3: addr=%016" PRIx64" x1=%x x2=%x x3=%x\n", (uint64_t) addr, (int) x1, (int) x2, (int) x3); */ l2 = cpu->cd.DYNTRANS_ARCH.l1_64[x1]; /* fatal(" l2 = %p\n", l2); */ l3 = l2->l3[x2]; /* fatal(" l3 = %p\n", l3); */ #ifdef LS_LOAD page = l3->host_load[x3]; #else page = l3->host_store[x3]; #endif #ifdef LS_UNALIGNED addr &= ~7; #endif #ifdef LS_LLSC #ifdef LS_LOAD /* TODO: cache-line size! */ cpu->cd.alpha.load_linked_addr = addr & ~63; cpu->cd.alpha.ll_flag = 1; #else /* TODO: only invalidate per cache line, not everything! */ if (cpu->cd.alpha.ll_flag == 1) { int i; for (i=0; imachine->ncpus; i++) cpu->machine->cpus[i]->cd.alpha.ll_flag = 0; } else { *((uint64_t *)ic->arg[0]) = 0; return; } #endif #endif c = addr & 8191; #ifndef LS_B if (c & #ifdef LS_W 1 #endif #ifdef LS_L 3 #endif #ifdef LS_Q 7 #endif ) { LS_GENERIC_N(cpu, ic); return; } else #endif if (page != NULL) { #ifdef LS_LOAD #ifdef HOST_BIG_ENDIAN uint64_t data_x; data_x = page[c]; #ifndef LS_B data_x += (page[c+1] << 8); #ifndef LS_W data_x += (page[c+2] << 16); data_x += ((uint64_t)page[c+3] << 24); #ifndef LS_L data_x += ((uint64_t)page[c+4] << 32); data_x += ((uint64_t)page[c+5] << 40); data_x += ((uint64_t)page[c+6] << 48); data_x += ((uint64_t)page[c+7] << 56); #endif #endif #endif #ifdef LS_L *((uint64_t *)ic->arg[0]) = (int64_t)(int32_t)data_x; #else *((uint64_t *)ic->arg[0]) = data_x; #endif #else #ifdef LS_B *((uint64_t *)ic->arg[0]) = page[c]; #endif #ifdef LS_W uint16_t d = *((uint16_t *) (page + c)); *((uint64_t *)ic->arg[0]) = d; #endif #ifdef LS_L int32_t d = *((int32_t *) (page + c)); *((uint64_t *)ic->arg[0]) = (int64_t)d; #endif #ifdef LS_Q uint64_t d = *((uint64_t *) (page + c)); *((uint64_t *)ic->arg[0]) = d; #endif #endif #else /* Store: */ #ifdef HOST_BIG_ENDIAN uint64_t data_x = *((uint64_t *)ic->arg[0]); page[c] = data_x; #ifndef LS_B page[c+1] = data_x >> 8; #ifndef LS_W page[c+2] = data_x >> 16; page[c+3] = data_x >> 24; #ifndef LS_L page[c+4] = data_x >> 32; page[c+5] = data_x >> 40; page[c+6] = data_x >> 48; page[c+7] = data_x >> 56; #endif #endif #endif #else /* Native byte order: */ #ifdef LS_B page[c] = *((uint64_t *)ic->arg[0]); #endif #ifdef LS_W uint32_t d = *((uint64_t *)ic->arg[0]); *((uint16_t *) (page + c)) = d; #endif #ifdef LS_L uint32_t d = *((uint64_t *)ic->arg[0]); *((uint32_t *) (page + c)) = d; #endif #ifdef LS_Q uint64_t d = *((uint64_t *)ic->arg[0]); *((uint64_t *) (page + c)) = d; #endif #endif #ifdef LS_LLSC #ifndef LS_LOAD *((uint64_t *)ic->arg[0]) = 1; #endif #endif #endif /* !LS_LOAD */ } else LS_GENERIC_N(cpu, ic); } gxemul-0.6.1/src/cpus/generate_tail.c000644 001750 001750 00000016360 13402411502 017743 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include char *uppercase(char *l) { static char staticbuf[1000]; size_t i = 0; while (*l && i < sizeof(staticbuf)) { char u = *l++; if (u >= 'a' && u <= 'z') u -= 32; staticbuf[i++] = u; } if (i == sizeof(staticbuf)) i--; staticbuf[i] = 0; return staticbuf; } int main(int argc, char *argv[]) { char *a, *b; if (argc != 3) { fprintf(stderr, "usage: %s arch Arch\n", argv[0]); fprintf(stderr, "Example: %s alpha Alpha\n", argv[0]); fprintf(stderr, " or: %s arm ARM\n", argv[0]); exit(1); } a = argv[1]; b = argv[2]; printf("\n/*\n * AUTOMATICALLY GENERATED! Do not edit.\n */\n\n"); printf("extern size_t dyntrans_cache_size;\n"); printf("#ifdef DYNTRANS_32\n"); printf("#define MODE32\n"); printf("#endif\n"); printf("#define DYNTRANS_FUNCTION_TRACE_DEF " "%s_cpu_functioncall_trace\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_FUNCTION_TRACE_DEF\n\n"); printf("#define DYNTRANS_INIT_TABLES " "%s_cpu_init_tables\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_INIT_TABLES\n\n"); printf("#define DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE_DEF " "%s_tc_allocate_default_page\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_TC_ALLOCATE_DEFAULT_PAGE_DEF\n\n"); printf("#define DYNTRANS_INVAL_ENTRY\n"); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_INVAL_ENTRY\n\n"); printf("#define DYNTRANS_INVALIDATE_TC " "%s_invalidate_translation_caches\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_INVALIDATE_TC\n\n"); printf("#define DYNTRANS_INVALIDATE_TC_CODE " "%s_invalidate_code_translation\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_INVALIDATE_TC_CODE\n\n"); printf("#define DYNTRANS_UPDATE_TRANSLATION_TABLE " "%s_update_translation_table\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_UPDATE_TRANSLATION_TABLE\n\n"); printf("#define MEMORY_RW %s_memory_rw\n", a); printf("#define MEM_%s\n", uppercase(a)); printf("#include \"memory_rw.cc\"\n"); printf("#undef MEM_%s\n", uppercase(a)); printf("#undef MEMORY_RW\n\n"); printf("#define DYNTRANS_PC_TO_POINTERS_FUNC %s_pc_to_pointers\n", a); printf("#define DYNTRANS_PC_TO_POINTERS_GENERIC " "%s_pc_to_pointers_generic\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_PC_TO_POINTERS_FUNC\n\n"); printf("#undef DYNTRANS_PC_TO_POINTERS_GENERIC\n\n"); printf("#define COMBINE_INSTRUCTIONS %s_combine_instructions\n", a); printf("#ifndef DYNTRANS_32\n"); printf("#define reg(x) (*((uint64_t *)(x)))\n"); printf("#define MODE_uint_t uint64_t\n"); printf("#define MODE_int_t int64_t\n"); printf("#else\n"); printf("#define reg(x) (*((uint32_t *)(x)))\n"); printf("#define MODE_uint_t uint32_t\n"); printf("#define MODE_int_t int32_t\n"); printf("#endif\n"); printf("#define COMBINE(n) %s_combine_ ## n\n", a); printf("#include \"quick_pc_to_pointers.h\"\n"); printf("#include \"cpu_%s_instr.cc\"\n\n", a); printf("#define DYNTRANS_RUN_INSTR_DEF %s_run_instr\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_RUN_INSTR_DEF\n\n"); printf("#ifdef DYNTRANS_DUALMODE_32\n"); printf("#undef COMBINE_INSTRUCTIONS\n"); printf("#define COMBINE_INSTRUCTIONS %s32_combine_instructions\n", a); printf("#undef X\n#undef instr\n#undef reg\n" "#define X(n) void %s32_instr_ ## n(struct cpu *cpu, \\\n" "\tstruct %s_instr_call *ic)\n", a, a); printf("#define instr(n) %s32_instr_ ## n\n", a); printf("#ifdef HOST_LITTLE_ENDIAN\n"); printf("#define reg(x) ( *((uint32_t *)(x)) )\n"); printf("#else\n"); printf("#define reg(x) ( *((uint32_t *)(x)+1) )\n"); printf("#endif\n"); printf("#define MODE32\n"); printf("#undef MODE_uint_t\n#undef MODE_int_t\n"); printf("#define MODE_uint_t uint32_t\n"); printf("#define MODE_int_t int32_t\n"); printf("#define DYNTRANS_INVAL_ENTRY\n"); printf("#undef DYNTRANS_INVALIDATE_TLB_ENTRY\n" "#define DYNTRANS_INVALIDATE_TLB_ENTRY " "%s32_invalidate_tlb_entry\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_INVAL_ENTRY\n\n"); printf("#define DYNTRANS_INVALIDATE_TC " "%s32_invalidate_translation_caches\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_INVALIDATE_TC\n\n"); printf("#define DYNTRANS_INVALIDATE_TC_CODE " "%s32_invalidate_code_translation\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_INVALIDATE_TC_CODE\n\n"); printf("#define DYNTRANS_UPDATE_TRANSLATION_TABLE " "%s32_update_translation_table\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_UPDATE_TRANSLATION_TABLE\n\n"); printf("#define DYNTRANS_PC_TO_POINTERS_FUNC %s32_pc_to_pointers\n", a); printf("#define DYNTRANS_PC_TO_POINTERS_GENERIC " "%s32_pc_to_pointers_generic\n", a); printf("#undef DYNTRANS_PC_TO_POINTERS\n" "#define DYNTRANS_PC_TO_POINTERS %s32_pc_to_pointers\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_PC_TO_POINTERS_FUNC\n\n"); printf("#undef DYNTRANS_PC_TO_POINTERS_GENERIC\n\n"); printf("#undef COMBINE\n"); printf("#define COMBINE(n) %s32_combine_ ## n\n", a); printf("#include \"quick_pc_to_pointers.h\"\n"); printf("#include \"cpu_%s_instr.cc\"\n", a); printf("\n#undef DYNTRANS_PC_TO_POINTERS\n" "#define DYNTRANS_PC_TO_POINTERS %s_pc_to_pointers\n" "#define DYNTRANS_PC_TO_POINTERS32 %s32_pc_to_pointers\n\n", a, a); printf("#define DYNTRANS_RUN_INSTR_DEF %s32_run_instr\n", a); printf("#include \"cpu_dyntrans.cc\"\n"); printf("#undef DYNTRANS_RUN_INSTR_DEF\n\n"); printf("#endif /* DYNTRANS_DUALMODE_32 */\n\n\n"); printf("CPU_FAMILY_INIT(%s,\"%s\")\n\n", a, b); return 0; } gxemul-0.6.1/src/cpus/cpu_arm_instr_loadstore.cc000644 001750 001750 00000036130 13402411502 022221 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * TODO: Many things... * * o) Big-endian Double-Word loads/stores are likely INCORRECT. * * o) "Base Updated Abort Model", which updates the base register * even if the memory access failed. * * o) Some ARM implementations use pc+8, some use pc+12 for stores? * * o) All load/store variants with the PC register are not really * valid. (E.g. a byte load into the PC register. What should that * accomplish?) * * o) Perhaps an optimization for the case when offset = 0, because * that's quite common, and also when the Reg expression is just * a simple, non-rotated register (0..14). */ #if defined(A__SIGNED) && !defined(A__H) && !defined(A__L) #define A__LDRD #endif #if defined(A__SIGNED) && defined(A__H) && !defined(A__L) #define A__STRD #endif /* * General load/store, by using memory_rw(). If at all possible, memory_rw() * then inserts the page into the translation array, so that the fast * load/store routine below can be used for further accesses. */ void A__NAME__general(struct cpu *cpu, struct arm_instr_call *ic) { #if !defined(A__P) && defined(A__W) const int memory_rw_flags = CACHE_DATA | MEMORY_USER_ACCESS; #else const int memory_rw_flags = CACHE_DATA; #endif #ifdef A__REG uint32_t (*reg_func)(struct cpu *, struct arm_instr_call *) = (uint32_t (*)(struct cpu *, struct arm_instr_call *)) (void *)(size_t)ic->arg[1]; #endif #if defined(A__STRD) || defined(A__LDRD) unsigned char data[8]; const int datalen = 8; #else #ifdef A__B unsigned char data[1]; const int datalen = 1; #else #ifdef A__H unsigned char data[2]; const int datalen = 2; #else const int datalen = 4; #ifdef HOST_LITTLE_ENDIAN unsigned char *data = (unsigned char *) ic->arg[2]; #else unsigned char data[4]; #endif #endif #endif #endif uint32_t addr, low_pc, offset = #ifndef A__U - #endif #ifdef A__REG reg_func(cpu, ic); #else ic->arg[1]; #endif low_pc = ((size_t)ic - (size_t)cpu->cd.arm. cur_ic_page) / sizeof(struct arm_instr_call); cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); addr = reg(ic->arg[0]) #ifdef A__P + offset #endif ; addr &= ~(datalen - 1); #if defined(A__L) || defined(A__LDRD) /* Load: */ if (!cpu->memory_rw(cpu, cpu->mem, addr, data, datalen, MEM_READ, memory_rw_flags)) { /* load failed, an exception was generated */ return; } #if defined(A__B) && !defined(A__LDRD) reg(ic->arg[2]) = #ifdef A__SIGNED (int32_t)(int8_t) #endif data[0]; #else #if defined(A__H) && !defined(A__LDRD) reg(ic->arg[2]) = #ifdef A__SIGNED (int32_t)(int16_t) #endif (cpu->byte_order == EMUL_LITTLE_ENDIAN ? (data[0] + (data[1] << 8)) : (data[1] + (data[0] << 8))); #else #ifndef A__LDRD reg(ic->arg[2]) = cpu->byte_order == EMUL_LITTLE_ENDIAN ? data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24) : data[3] + (data[2] << 8) + (data[1] << 16) + (data[0] << 24); #else // TODO: Double-check if this is correct reg(ic->arg[2]) = cpu->byte_order == EMUL_LITTLE_ENDIAN ? data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24) : data[7] + (data[1] << 6) + (data[5] << 16) + (data[4] << 24); reg(((uint32_t *)ic->arg[2]) + 1) = cpu->byte_order == EMUL_LITTLE_ENDIAN ? data[4] + (data[5] << 8) + (data[6] << 16) + (data[7] << 24) : data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24); #endif #endif #endif #else /* Store: */ #if !defined(A__B) && !defined(A__H) && defined(HOST_LITTLE_ENDIAN) #ifdef A__STRD *(uint32_t *)data = reg(ic->arg[2]); *(uint32_t *)(data + 4) = reg(ic->arg[2] + 4); #endif #else int i = cpu->byte_order == EMUL_LITTLE_ENDIAN ? 0 : datalen - 1; data[i] = reg(ic->arg[2]); i += cpu->byte_order == EMUL_LITTLE_ENDIAN ? 1 : -1; #ifndef A__B data[i] = reg(ic->arg[2]) >> 8; i += cpu->byte_order == EMUL_LITTLE_ENDIAN ? 1 : -1; #if !defined(A__H) || defined(A__STRD) data[i] = reg(ic->arg[2]) >> 16; i += cpu->byte_order == EMUL_LITTLE_ENDIAN ? 1 : -1; data[i] = reg(ic->arg[2]) >> 24; i += cpu->byte_order == EMUL_LITTLE_ENDIAN ? 1 : -1; #ifdef A__STRD // TODO: Double-check if this is correct data[i] = reg(ic->arg[2] + 4); i += cpu->byte_order == EMUL_LITTLE_ENDIAN ? 1 : -1; data[i] = reg(ic->arg[2] + 4) >> 8; i += cpu->byte_order == EMUL_LITTLE_ENDIAN ? 1 : -1; data[i] = reg(ic->arg[2] + 4) >> 16; i += cpu->byte_order == EMUL_LITTLE_ENDIAN ? 1 : -1; data[i] = reg(ic->arg[2] + 4) >> 24; i += cpu->byte_order == EMUL_LITTLE_ENDIAN ? 1 : -1; #endif #endif #endif #endif if (!cpu->memory_rw(cpu, cpu->mem, addr, data, datalen, MEM_WRITE, memory_rw_flags)) { /* store failed, an exception was generated */ return; } #endif #ifdef A__P #ifdef A__W reg(ic->arg[0]) = addr; #endif #else /* post-index writeback */ reg(ic->arg[0]) = addr + offset; #endif } /* * Fast load/store, if the page is in the translation array. */ void A__NAME(struct cpu *cpu, struct arm_instr_call *ic) { #if defined(A__LDRD) || defined(A__STRD) /* Chicken out, let's do this unoptimized for now: */ A__NAME__general(cpu, ic); #else #ifdef A__REG uint32_t (*reg_func)(struct cpu *, struct arm_instr_call *) = (uint32_t (*)(struct cpu *, struct arm_instr_call *)) (void *)(size_t)ic->arg[1]; #endif uint32_t offset = #ifndef A__U - #endif #ifdef A__REG reg_func(cpu, ic); #else ic->arg[1]; #endif uint32_t addr = reg(ic->arg[0]) #ifdef A__P + offset #endif ; unsigned char *page = cpu->cd.arm. #ifdef A__L host_load #else host_store #endif [addr >> 12]; #if !defined(A__P) && defined(A__W) /* * T-bit: userland access: check the corresponding bit in the * is_userpage array. If it is set, then we're ok. Otherwise: use the * generic function. */ uint32_t x = cpu->cd.arm.is_userpage[addr >> 17]; if (!(x & (1 << ((addr >> 12) & 31)))) A__NAME__general(cpu, ic); else #endif if (page == NULL) { A__NAME__general(cpu, ic); } else { #ifdef A__L #ifdef A__B reg(ic->arg[2]) = #ifdef A__SIGNED (int32_t)(int8_t) #endif page[addr & 0xfff]; #else #ifdef A__H addr &= ~1; reg(ic->arg[2]) = #ifdef A__SIGNED (int32_t)(int16_t) #endif (cpu->byte_order == EMUL_LITTLE_ENDIAN ? (page[addr & 0xfff] + (page[(addr & 0xfff) + 1] << 8)) : ((page[addr & 0xfff] << 8) + page[(addr & 0xfff) + 1])); #else addr &= ~3; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) reg(ic->arg[2]) = page[addr & 0xfff] + (page[(addr & 0xfff) + 1] << 8) + (page[(addr & 0xfff) + 2] << 16) + (page[(addr & 0xfff) + 3] << 24); else reg(ic->arg[2]) = page[(addr & 0xfff) + 3] + (page[(addr & 0xfff) + 2] << 8) + (page[(addr & 0xfff) + 1] << 16) + (page[(addr & 0xfff) + 0] << 24); #endif #endif #else #ifdef A__B page[addr & 0xfff] = reg(ic->arg[2]); #else #ifdef A__H addr &= ~1; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { page[addr & 0xfff] = reg(ic->arg[2]); page[(addr & 0xfff)+1] = reg(ic->arg[2]) >> 8; } else { page[addr & 0xfff] = reg(ic->arg[2]) >> 8; page[(addr & 0xfff)+1] = reg(ic->arg[2]); } #else addr &= ~3; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { page[addr & 0xfff] = reg(ic->arg[2]); page[(addr & 0xfff)+1] = reg(ic->arg[2]) >> 8; page[(addr & 0xfff)+2] = reg(ic->arg[2]) >> 16; page[(addr & 0xfff)+3] = reg(ic->arg[2]) >> 24; } else { page[addr & 0xfff] = reg(ic->arg[2]) >> 24; page[(addr & 0xfff)+1] = reg(ic->arg[2]) >> 16; page[(addr & 0xfff)+2] = reg(ic->arg[2]) >> 8; page[(addr & 0xfff)+3] = reg(ic->arg[2]); } #endif #endif #endif /* Index Write-back: */ #ifdef A__P #ifdef A__W reg(ic->arg[0]) = addr; #endif #else /* post-index writeback */ reg(ic->arg[0]) = addr + offset; #endif } #endif /* not STRD */ } /* * Special case when loading or storing the ARM's PC register, or when the PC * register is used as the base address register. * * o) Loads into the PC register cause a branch. If an exception occured * during the load, then the PC register should already point to the * exception handler, in which case we simply recalculate the pointers a * second time (no harm is done by doing that). * * TODO: A tiny performance optimization would be to separate the two * cases: a load where arg[0] = PC, and the case where arg[2] = PC. * * o) Stores store "PC of the current instruction + 12". The solution I have * choosen is to calculate this value and place it into a temporary * variable (tmp_pc), which is then used for the store. */ void A__NAME_PC(struct cpu *cpu, struct arm_instr_call *ic) { #ifdef A__L /* Load: */ if (ic->arg[0] == (size_t)(&cpu->cd.arm.tmp_pc)) { /* tmp_pc = current PC + 8: */ uint32_t low_pc, tmp; low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); tmp = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); tmp += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); cpu->cd.arm.tmp_pc = tmp + 8; } A__NAME(cpu, ic); if (ic->arg[2] == (size_t)(&cpu->cd.arm.r[ARM_PC])) { cpu->pc = cpu->cd.arm.r[ARM_PC]; quick_pc_to_pointers(cpu); if (cpu->machine->show_trace_tree) cpu_functioncall_trace(cpu, cpu->pc); } #else /* Store: */ uint32_t low_pc, tmp; /* Calculate tmp from this instruction's PC + 12 */ low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); tmp = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); tmp += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); cpu->cd.arm.tmp_pc = tmp + 12; A__NAME(cpu, ic); #endif } #ifndef A__NOCONDITIONS /* Load/stores with all registers except the PC register: */ void A__NAME__eq(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_Z) A__NAME(cpu, ic); } void A__NAME__ne(struct cpu *cpu, struct arm_instr_call *ic) { if (!(cpu->cd.arm.flags & ARM_F_Z)) A__NAME(cpu, ic); } void A__NAME__cs(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_C) A__NAME(cpu, ic); } void A__NAME__cc(struct cpu *cpu, struct arm_instr_call *ic) { if (!(cpu->cd.arm.flags & ARM_F_C)) A__NAME(cpu, ic); } void A__NAME__mi(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_N) A__NAME(cpu, ic); } void A__NAME__pl(struct cpu *cpu, struct arm_instr_call *ic) { if (!(cpu->cd.arm.flags & ARM_F_N)) A__NAME(cpu, ic); } void A__NAME__vs(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_V) A__NAME(cpu, ic); } void A__NAME__vc(struct cpu *cpu, struct arm_instr_call *ic) { if (!(cpu->cd.arm.flags & ARM_F_V)) A__NAME(cpu, ic); } void A__NAME__hi(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_C && !(cpu->cd.arm.flags & ARM_F_Z)) A__NAME(cpu, ic); } void A__NAME__ls(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_Z || !(cpu->cd.arm.flags & ARM_F_C)) A__NAME(cpu, ic); } void A__NAME__ge(struct cpu *cpu, struct arm_instr_call *ic) { if (((cpu->cd.arm.flags & ARM_F_N)?1:0) == ((cpu->cd.arm.flags & ARM_F_V)?1:0)) A__NAME(cpu, ic); } void A__NAME__lt(struct cpu *cpu, struct arm_instr_call *ic) { if (((cpu->cd.arm.flags & ARM_F_N)?1:0) != ((cpu->cd.arm.flags & ARM_F_V)?1:0)) A__NAME(cpu, ic); } void A__NAME__gt(struct cpu *cpu, struct arm_instr_call *ic) { if (((cpu->cd.arm.flags & ARM_F_N)?1:0) == ((cpu->cd.arm.flags & ARM_F_V)?1:0) && !(cpu->cd.arm.flags & ARM_F_Z)) A__NAME(cpu, ic); } void A__NAME__le(struct cpu *cpu, struct arm_instr_call *ic) { if (((cpu->cd.arm.flags & ARM_F_N)?1:0) != ((cpu->cd.arm.flags & ARM_F_V)?1:0) || (cpu->cd.arm.flags & ARM_F_Z)) A__NAME(cpu, ic); } /* Load/stores with the PC register: */ void A__NAME_PC__eq(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_Z) A__NAME_PC(cpu, ic); } void A__NAME_PC__ne(struct cpu *cpu, struct arm_instr_call *ic) { if (!(cpu->cd.arm.flags & ARM_F_Z)) A__NAME_PC(cpu, ic); } void A__NAME_PC__cs(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_C) A__NAME_PC(cpu, ic); } void A__NAME_PC__cc(struct cpu *cpu, struct arm_instr_call *ic) { if (!(cpu->cd.arm.flags & ARM_F_C)) A__NAME_PC(cpu, ic); } void A__NAME_PC__mi(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_N) A__NAME_PC(cpu, ic); } void A__NAME_PC__pl(struct cpu *cpu, struct arm_instr_call *ic) { if (!(cpu->cd.arm.flags & ARM_F_N)) A__NAME_PC(cpu, ic); } void A__NAME_PC__vs(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_V) A__NAME_PC(cpu, ic); } void A__NAME_PC__vc(struct cpu *cpu, struct arm_instr_call *ic) { if (!(cpu->cd.arm.flags & ARM_F_V)) A__NAME_PC(cpu, ic); } void A__NAME_PC__hi(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_C && !(cpu->cd.arm.flags & ARM_F_Z)) A__NAME_PC(cpu, ic); } void A__NAME_PC__ls(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_Z || !(cpu->cd.arm.flags & ARM_F_C)) A__NAME_PC(cpu, ic); } void A__NAME_PC__ge(struct cpu *cpu, struct arm_instr_call *ic) { if (((cpu->cd.arm.flags & ARM_F_N)?1:0) == ((cpu->cd.arm.flags & ARM_F_V)?1:0)) A__NAME_PC(cpu, ic); } void A__NAME_PC__lt(struct cpu *cpu, struct arm_instr_call *ic) { if (((cpu->cd.arm.flags & ARM_F_N)?1:0) != ((cpu->cd.arm.flags & ARM_F_V)?1:0)) A__NAME_PC(cpu, ic); } void A__NAME_PC__gt(struct cpu *cpu, struct arm_instr_call *ic) { if (((cpu->cd.arm.flags & ARM_F_N)?1:0) == ((cpu->cd.arm.flags & ARM_F_V)?1:0) && !(cpu->cd.arm.flags & ARM_F_Z)) A__NAME_PC(cpu, ic); } void A__NAME_PC__le(struct cpu *cpu, struct arm_instr_call *ic) { if (((cpu->cd.arm.flags & ARM_F_N)?1:0) != ((cpu->cd.arm.flags & ARM_F_V)?1:0) || (cpu->cd.arm.flags & ARM_F_Z)) A__NAME_PC(cpu, ic); } #endif #ifdef A__LDRD #undef A__LDRD #endif #ifdef A__STRD #undef A__STRD #endif gxemul-0.6.1/src/cpus/memory_rw.cc000644 001750 001750 00000034145 13402411502 017324 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2014 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Generic memory_rw(), with special hacks for specific CPU families. * * Example for inclusion from memory_mips.c: * * MEMORY_RW should be mips_memory_rw * MEM_MIPS should be defined * * * TODO: Cleanup the "ok" variable usage! */ /* * memory_rw(): * * Read or write data from/to memory. * * cpu the cpu doing the read/write * mem the memory object to use * vaddr the virtual address * data a pointer to the data to be written to memory, or * a placeholder for data when reading from memory * len the length of the 'data' buffer * writeflag set to MEM_READ or MEM_WRITE * misc_flags CACHE_{NONE,DATA,INSTRUCTION} | other flags * * If the address indicates access to a memory mapped device, that device' * read/write access function is called. * * This function should not be called with cpu == NULL. * * Returns one of the following: * MEMORY_ACCESS_FAILED * MEMORY_ACCESS_OK * * (MEMORY_ACCESS_FAILED is 0.) */ int MEMORY_RW(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int misc_flags) { #ifdef MEM_ALPHA const int offset_mask = 0x1fff; #else const int offset_mask = 0xfff; #endif int ok = 2; uint64_t paddr; int cache, no_exceptions, offset; unsigned char *memblock; int dyntrans_device_danger = 0; no_exceptions = misc_flags & NO_EXCEPTIONS; cache = misc_flags & CACHE_FLAGS_MASK; if (misc_flags & PHYSICAL || cpu->translate_v2p == NULL) { paddr = vaddr; } else { ok = cpu->translate_v2p(cpu, vaddr, &paddr, (writeflag? FLAG_WRITEFLAG : 0) + (no_exceptions? FLAG_NOEXCEPTIONS : 0) + (misc_flags & MEMORY_USER_ACCESS) + (cache==CACHE_INSTRUCTION? FLAG_INSTR : 0)); /* * If the translation caused an exception, or was invalid in * some way, then simply return without doing the memory * access: */ if (!ok) return MEMORY_ACCESS_FAILED; } #if 0 /* * For quick-and-dirty debugging of 32-bit code, typically * unknown ROM code: Write out a summary of accessed memory ranges. */ if (cpu->running && paddr < 0x00300000) { static int swriteflag = -1, lastswriteflag; static int32_t start = -1, stop = -1; static int32_t laststart = -1, laststop = -1; if (start == -1) { start = stop = paddr; swriteflag = writeflag; } else { if (paddr == stop + len && writeflag == swriteflag) { stop = paddr; } else { if (start != laststart || stop != laststop || swriteflag != lastswriteflag) { printf("%s %08x -- %08x %i-bit\n", swriteflag ? "WRITE" : "READ ", (int)start, (int)(stop + len - 1), (int)len*8); } laststart = start; laststop = stop; lastswriteflag = swriteflag; start = stop = paddr; swriteflag = writeflag; } } // Make sure the access is not put into quick lookup tables: ok |= MEMORY_NOT_FULL_PAGE; } #endif #if 0 /* * For quick-and-dirty test to see which memory addresses are in use, * making a "waterfall spectrum"... */ if (cpu->running && (paddr < 0x200000 || (paddr >= 0x0c000000 && paddr < 0x0d000000))) { int64_t xsize = 1920, ysize = 1080; static int y = 0; static int count = 0; static uint8_t* buf = NULL; if (buf == NULL) { buf = (uint8_t*)malloc(xsize * ysize*3); memset(buf, 0xff, xsize * ysize*3); } uint64_t paddr2 = paddr - 0x0c000000; if (paddr < 0x200000) paddr2 = paddr + 16*1048576; int64_t max = 16*1048576 + (2*1048576); int64_t x = xsize * paddr2 / max; if (x >= 0 && x < xsize) { if (writeflag) { int c = buf[(x+y*xsize)*3+0]; if (c == 255) c = 128; else if (c > 0) { c = c - 8; } buf[(x+y*xsize)*3+1] = c; buf[(x+y*xsize)*3+2] = c; } else { int c = buf[(x+y*xsize)*3+1]; if (c == 255) c = 128; else if (c > 0) { c = c - 8; } buf[(x+y*xsize)*3+0] = c; buf[(x+y*xsize)*3+2] = c; } } for (int meg = 0; meg < 18; ++meg) buf[((xsize * (meg * 0x100000LL) / max) +y*xsize)*3+1] = 64; count ++; if (count >= 8192) { count = 0; y ++; if (y >= ysize) { static int n = 0; char name[40]; snprintf(name, sizeof(name), "memory_%05i.ppm", n++); FILE* f = fopen(name, "w"); printf("writing out %s\n", name); fprintf(f, "P6\n%i %i\n255\n", (int)xsize, (int)ysize); fwrite((char*)buf, 1, (int)(xsize*ysize*3), f); fclose(f); memset(buf, 0xff, xsize*ysize); y = 0; } } // Make sure the access is not put into quick lookup tables: ok |= MEMORY_NOT_FULL_PAGE; } #endif /* * Memory mapped device? * * TODO: if paddr < base, but len enough, then the device should * still be written to! */ if (paddr >= mem->mmap_dev_minaddr && paddr < mem->mmap_dev_maxaddr) { uint64_t orig_paddr = paddr; int i, start, end, res; #if 0 TODO: The correct solution for this is to add RAM devices _around_ the dangerous device. The solution below incurs a slowdown for _everything_, not just the device in question. /* * Really really slow, but unfortunately necessary. This is * to avoid the folowing scenario: * * a) offsets 0x000..0x123 are normal memory * b) offsets 0x124..0x777 are a device * * 1) a read is done from offset 0x100. the page is * added to the dyntrans system as a "RAM" page * 2) a dyntranslated read is done from offset 0x200, * which should access the device, but since the * entire page is added, it will access non-existant * RAM instead, without warning. * * Setting dyntrans_device_danger = 1 on accesses which are * on _any_ offset on pages that are device mapped avoids * this problem, but it is probably not very fast. * * TODO: Convert this into a quick (multi-level, 64-bit) * address space lookup, to find dangerous pages. */ for (i=0; in_mmapped_devices; i++) if (paddr >= (mem->devices[i].baseaddr & ~offset_mask)&& paddr <= ((mem->devices[i].endaddr-1)|offset_mask)){ dyntrans_device_danger = 1; break; } #endif start = 0; end = mem->n_mmapped_devices - 1; i = mem->last_accessed_device; /* Scan through all devices: */ do { if (paddr >= mem->devices[i].baseaddr && paddr < mem->devices[i].endaddr) { /* Found a device, let's access it: */ mem->last_accessed_device = i; paddr -= mem->devices[i].baseaddr; if (paddr + len > mem->devices[i].length) len = mem->devices[i].length - paddr; if (cpu->update_translation_table != NULL && !(ok & MEMORY_NOT_FULL_PAGE) && mem->devices[i].flags & DM_DYNTRANS_OK) { int wf = writeflag == MEM_WRITE? 1 : 0; unsigned char *host_addr; if (!(mem->devices[i].flags & DM_DYNTRANS_WRITE_OK)) wf = 0; if (writeflag && wf) { if (paddr < mem->devices[i]. dyntrans_write_low) mem->devices[i]. dyntrans_write_low = paddr &~offset_mask; if (paddr >= mem->devices[i]. dyntrans_write_high) mem->devices[i]. dyntrans_write_high = paddr | offset_mask; } if (mem->devices[i].flags & DM_EMULATED_RAM) { /* MEM_WRITE to force the page to be allocated, if it wasn't already */ uint64_t *pp = (uint64_t *)mem-> devices[i].dyntrans_data; uint64_t p = orig_paddr - *pp; host_addr = memory_paddr_to_hostaddr( mem, p & ~offset_mask, MEM_WRITE); } else { host_addr = mem->devices[i]. dyntrans_data + (paddr & ~offset_mask); } cpu->update_translation_table(cpu, vaddr & ~offset_mask, host_addr, wf, orig_paddr & ~offset_mask); } res = 0; if (!no_exceptions || (mem->devices[i].flags & DM_READS_HAVE_NO_SIDE_EFFECTS)) res = mem->devices[i].f(cpu, mem, paddr, data, len, writeflag, mem->devices[i].extra); if (res == 0) res = -1; /* * If accessing the memory mapped device * failed, then return with an exception. * (Architecture specific.) */ if (res <= 0 && !no_exceptions) { debug("[ %s device '%s' addr %08lx " "failed ]\n", writeflag? "writing to" : "reading from", mem->devices[i].name, (long)paddr); #ifdef MEM_MIPS mips_cpu_exception(cpu, cache == CACHE_INSTRUCTION? EXCEPTION_IBE : EXCEPTION_DBE, 0, vaddr, 0, 0, 0, 0); #endif #ifdef MEM_M88K /* TODO: This is enough for OpenBSD/mvme88k's badaddr() implementation... but the faulting address should probably be included somewhere too! */ m88k_exception(cpu, cache == CACHE_INSTRUCTION ? M88K_EXCEPTION_INSTRUCTION_ACCESS : M88K_EXCEPTION_DATA_ACCESS, 0); #endif return MEMORY_ACCESS_FAILED; } goto do_return_ok; } if (paddr < mem->devices[i].baseaddr) end = i - 1; if (paddr >= mem->devices[i].endaddr) start = i + 1; i = (start + end) >> 1; } while (start <= end); } #ifdef MEM_MIPS /* * Data and instruction cache emulation: */ switch (cpu->cd.mips.cpu_type.mmu_model) { case MMU3K: /* if not uncached addess (TODO: generalize this) */ if (!(misc_flags & PHYSICAL) && cache != CACHE_NONE && !((vaddr & 0xffffffffULL) >= 0xa0000000ULL && (vaddr & 0xffffffffULL) <= 0xbfffffffULL)) { if (memory_cache_R3000(cpu, cache, paddr, writeflag, len, data)) goto do_return_ok; } break; default: /* R4000 etc */ /* TODO */ ; } #endif /* MEM_MIPS */ /* Outside of physical RAM? */ if (paddr >= mem->physical_max) { #ifdef MEM_MIPS if ((paddr & 0xffffc00000ULL) == 0x1fc00000) { /* Ok, this is PROM stuff */ } else if ((paddr & 0xfffff00000ULL) == 0x1ff00000) { /* Sprite reads from this area of memory... */ /* TODO: is this still correct? */ if (writeflag == MEM_READ) memset(data, 0, len); goto do_return_ok; } else #endif /* MIPS */ { if (paddr >= mem->physical_max && !no_exceptions) memory_warn_about_unimplemented_addr (cpu, mem, writeflag, paddr, data, len); if (writeflag == MEM_READ) { /* Return all zeroes? (Or 0xff? TODO) */ memset(data, 0, len); #if 0 /* * NOTE: This code prevents a PROM image from a real 5000/200 from booting. * I think I introduced it because it was how some guest OS (NetBSD?) detected * the amount of RAM on some machine. * * TODO: Figure out if it is not needed anymore, and remove it completely. */ #ifdef MEM_MIPS /* * For real data/instruction accesses, cause * an exceptions on an illegal read: */ if (cache != CACHE_NONE && !no_exceptions && paddr >= mem->physical_max && paddr < mem->physical_max+1048576) { mips_cpu_exception(cpu, EXCEPTION_DBE, 0, vaddr, 0, 0, 0, 0); } #endif /* MEM_MIPS */ #endif } /* Hm? Shouldn't there be a DBE exception for invalid writes as well? TODO */ goto do_return_ok; } } /* * Uncached access: * * 1) Translate the physical address to a host address. * * 2) Insert this virtual->physical->host translation into the * fast translation arrays (using update_translation_table()). * * 3) If this was a Write, then invalidate any code translations * in that page. */ memblock = memory_paddr_to_hostaddr(mem, paddr & ~offset_mask, writeflag); if (memblock == NULL) { if (writeflag == MEM_READ) memset(data, 0, len); goto do_return_ok; } offset = paddr & offset_mask; if (cpu->update_translation_table != NULL && !dyntrans_device_danger #ifdef MEM_MIPS /* Ugly hack for R2000/R3000 caches: */ && (cpu->cd.mips.cpu_type.mmu_model != MMU3K || !(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_ISOL_CACHES)) #endif && !(ok & MEMORY_NOT_FULL_PAGE) && !no_exceptions) cpu->update_translation_table(cpu, vaddr & ~offset_mask, memblock, (misc_flags & MEMORY_USER_ACCESS) | (cache == CACHE_INSTRUCTION? (writeflag == MEM_WRITE? 1 : 0) : ok - 1), paddr & ~offset_mask); /* * If writing, or if mapping a page where writing is ok later on, * then invalidate code translations for the (physical) page address: */ if ((writeflag == MEM_WRITE || (ok == 2 && cache == CACHE_DATA) ) && cpu->invalidate_code_translation != NULL) cpu->invalidate_code_translation(cpu, paddr, INVALIDATE_PADDR); if ((paddr&((1< (1< #include #include /* NOTE: Static return buffer, so calling it multiple times in the same printf statement with the same argument works :-) but not with different args. Hahaha. Really ugly. */ char *uppercase(char *l) { static char staticbuf[1000]; size_t i = 0; while (*l && i < sizeof(staticbuf)) { char u = *l++; if (u >= 'a' && u <= 'z') u -= 32; staticbuf[i++] = u; } if (i == sizeof(staticbuf)) i--; staticbuf[i] = 0; return staticbuf; } int main(int argc, char *argv[]) { char *a, *b; if (argc != 3) { fprintf(stderr, "usage: %s arch Arch\n", argv[0]); fprintf(stderr, "Example: %s alpha Alpha\n", argv[0]); fprintf(stderr, " or: %s arm ARM\n", argv[0]); exit(1); } a = argv[1]; b = argv[2]; printf("\n/* AUTOMATICALLY GENERATED! Do not edit. */\n\n"); printf("#include \n"); printf("#include \"debugger.h\"\n"); printf("#define DYNTRANS_MAX_VPH_TLB_ENTRIES " "%s_MAX_VPH_TLB_ENTRIES\n", uppercase(a)); printf("#define DYNTRANS_ARCH %s\n", a); printf("#define DYNTRANS_%s\n", uppercase(a)); /* For 64-bit platforms, arch_L2N, and arch_L3N must be defined. */ printf("#ifndef DYNTRANS_32\n"); printf("#define DYNTRANS_L2N %s_L2N\n" "#define DYNTRANS_L3N %s_L3N\n" "#if !defined(%s_L2N) || !defined(%s_L3N)\n" "#error arch_L2N, and arch_L3N must be defined for this arch!\n" "#endif\n", uppercase(a), uppercase(a), uppercase(a), uppercase(a)); printf("#define DYNTRANS_L2_64_TABLE %s_l2_64_table\n" "#define DYNTRANS_L3_64_TABLE %s_l3_64_table\n", a, a); printf("#endif\n"); /* Default pagesize is 4KB. */ printf("#ifndef DYNTRANS_PAGESIZE\n" "#define DYNTRANS_PAGESIZE 4096\n" "#endif\n"); printf("#define DYNTRANS_IC %s_instr_call\n", a); printf("#define DYNTRANS_IC_ENTRIES_PER_PAGE " "%s_IC_ENTRIES_PER_PAGE\n", uppercase(a)); printf("#define DYNTRANS_INSTR_ALIGNMENT_SHIFT " "%s_INSTR_ALIGNMENT_SHIFT\n", uppercase(a)); printf("#define DYNTRANS_TC_PHYSPAGE %s_tc_physpage\n", a); printf("#define DYNTRANS_INVALIDATE_TLB_ENTRY " "%s_invalidate_tlb_entry\n", a); printf("#define DYNTRANS_ADDR_TO_PAGENR %s_ADDR_TO_PAGENR\n", uppercase(a)); printf("#define DYNTRANS_PC_TO_IC_ENTRY %s_PC_TO_IC_ENTRY\n", uppercase(a)); printf("#define DYNTRANS_TC_ALLOCATE " "%s_tc_allocate_default_page\n", a); printf("#define DYNTRANS_TC_PHYSPAGE %s_tc_physpage\n", a); printf("#define DYNTRANS_PC_TO_POINTERS %s_pc_to_pointers\n", a); printf("#define DYNTRANS_PC_TO_POINTERS_GENERIC " "%s_pc_to_pointers_generic\n", a); printf("#define COMBINE_INSTRUCTIONS %s_combine_instructions\n", a); printf("#define DISASSEMBLE %s_cpu_disassemble_instr\n", a); printf("\nextern volatile int single_step, single_step_breakpoint;" "\nextern int debugger_n_steps_left_before_interaction;\n" "extern int old_show_trace_tree;\n" "extern int old_instruction_trace;\n" "extern int old_quiet_mode;\n" "extern int quiet_mode;\n"); printf("\n/* instr uses the same names as in " "cpu_%s_instr.c */\n#define instr(n) %s_instr_ ## n\n\n", a, a); printf("#ifdef DYNTRANS_DUALMODE_32\n" "#define instr32(n) %s32_instr_ ## n\n\n", a); printf("#endif\n\n"); printf("\n#define X(n) void %s_instr_ ## n(struct cpu *cpu, \\\n" " struct %s_instr_call *ic)\n", a, a); printf("\n/*\n * nothing: Do nothing.\n *\n" " * The difference between this function and a \"nop\" " "instruction is that\n * this function does not increase " "the program counter. It is used to \"get out\" of running in " "translated\n * mode.\n */\n"); printf("X(nothing)\n{\n"); printf("\tcpu->cd.%s.next_ic --;\n", a); printf("}\n\n"); /* Ugly special hacks for SH[34]: */ if (strcasecmp(argv[1], "sh") == 0) { printf("static struct %s_instr_call nothing_call = { " "instr(nothing), {0,0} };\n", a); } else { printf("static struct %s_instr_call nothing_call = { " "instr(nothing), {0,0,0} };\n", a); } printf("\n"); return 0; } gxemul-0.6.1/src/cpus/cpu_m88k_instr_loadstore.cc000644 001750 001750 00000025162 13402411502 022234 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * M88K load/store instructions; the following args are used: * * arg[0] = pointer to the register to load to or store from (d) * arg[1] = pointer to the base register (s1) * arg[2] = pointer to the offset register (s2), or an uint32_t offset * * The GENERIC function always checks for alignment, and supports both big * and little endian byte order. * * The quick function is included twice (big/little endian) for each * GENERIC function. * * * Defines: * LS_LOAD or LS_STORE (only one) * LS_INCLUDE_GENERIC (to generate the generic function) * LS_GENERIC_N is defined as the name of the generic function * LS_N is defined as the name of the fast function * LS_1, LS_2, LS_4, or LS_8 (only one) * LS_SIZE is defined to 1, 2, 4, or 8 * LS_SIGNED is defined for signed loads * LS_LE or LS_BE (only one) * LS_SCALED for scaled accesses * LS_USR for usr accesses * LS_REGOFS is defined when arg[2] is a register pointer */ #ifdef LS_INCLUDE_GENERIC void LS_GENERIC_N(struct cpu *cpu, struct m88k_instr_call *ic) { #ifdef LS_USR const int memory_rw_flags = CACHE_DATA | MEMORY_USER_ACCESS; #else const int memory_rw_flags = CACHE_DATA; #endif uint32_t addr = reg(ic->arg[1]) + #ifdef LS_REGOFS #ifdef LS_SCALED LS_SIZE * #endif reg(ic->arg[2]); #else ic->arg[2]; #endif uint8_t data[LS_SIZE]; uint64_t x; /* Synchronize the PC: */ int low_pc = ((size_t)ic - (size_t)cpu->cd.m88k.cur_ic_page) / sizeof(struct m88k_instr_call); cpu->pc &= ~((M88K_IC_ENTRIES_PER_PAGE-1)<pc += (low_pc << M88K_INSTR_ALIGNMENT_SHIFT); /* * Update the memory transaction registers: */ cpu->cd.m88k.dmt[1] = 0; cpu->cd.m88k.dmt[0] = DMT_VALID; #ifdef LS_STORE cpu->cd.m88k.dmt[0] |= DMT_WRITE; #else { int dreg = (((uint32_t *)ic->arg[0]) - &cpu->cd.m88k.r[0]); if (dreg < 1 || dreg > 31) { fatal("HUH? dreg = %i in cpu_m88k_instr_loadstore.c." " Internal error.\n", dreg); exit(1); } cpu->cd.m88k.dmt[0] |= dreg << DMT_DREGSHIFT; } #ifdef LS_SIGNED cpu->cd.m88k.dmt[0] |= DMT_SIGNED; #endif #endif if (cpu->byte_order == EMUL_LITTLE_ENDIAN) cpu->cd.m88k.dmt[0] |= DMT_BO; #ifndef LS_USR if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE) cpu->cd.m88k.dmt[0] |= DMT_DAS; /* supervisor */ #endif /* EN bits: */ #ifdef LS_1 /* TODO: Is the EN offset only valid for Big-Endian? */ cpu->cd.m88k.dmt[0] |= 1 << DMT_ENSHIFT << (3 - (addr & 3)); #else #ifdef LS_2 cpu->cd.m88k.dmt[0] |= 3 << DMT_ENSHIFT << (2 - (addr & 2)); #else cpu->cd.m88k.dmt[0] |= 0xf << DMT_ENSHIFT; #endif #endif cpu->cd.m88k.dma[0] = addr & ~0x3; cpu->cd.m88k.dmd[0] = 0; #ifdef LS_8 cpu->cd.m88k.dmt[1] = cpu->cd.m88k.dmt[0]; cpu->cd.m88k.dmt[0] |= DMT_DOUB1; cpu->cd.m88k.dma[1] = cpu->cd.m88k.dma[0] + sizeof(uint32_t); cpu->cd.m88k.dmd[1] = 0; #ifdef LS_LOAD { int dreg = (((uint32_t *)ic->arg[0]) - &cpu->cd.m88k.r[0]); dreg ++; if (dreg < 1 || dreg > 31) { fatal("HUH? dreg = %i in cpu_m88k_instr_loadstore.c." " Internal error.\n", dreg); exit(1); } cpu->cd.m88k.dmt[1] &= ~((0x1f) << DMT_DREGSHIFT); cpu->cd.m88k.dmt[1] |= dreg << DMT_DREGSHIFT; } #endif #endif #ifdef LS_USR if (!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) { /* Cause a privilege violation exception: */ m88k_exception(cpu, M88K_EXCEPTION_PRIVILEGE_VIOLATION, 0); return; } #endif #ifndef LS_1 /* Check alignment: */ if (addr & (LS_SIZE - 1)) { #if 0 /* Cause an address alignment exception: */ m88k_exception(cpu, M88K_EXCEPTION_MISALIGNED_ACCESS, 0); #else fatal("{ m88k dyntrans alignment exception, size = %i," " addr = %08" PRIx32", pc = %08" PRIx32" }\n", LS_SIZE, (uint32_t) addr, (uint32_t) cpu->pc); /* TODO: Generalize this into a abort_call, or similar: */ cpu->running = 0; debugger_n_steps_left_before_interaction = 0; cpu->cd.m88k.next_ic = ¬hing_call; if (cpu->delay_slot) cpu->delay_slot |= EXCEPTION_IN_DELAY_SLOT; #endif return; } #endif #ifdef LS_LOAD if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_READ, memory_rw_flags)) { /* Exception. */ return; } x = memory_readmax64(cpu, data, LS_SIZE); #ifdef LS_8 if (cpu->byte_order == EMUL_BIG_ENDIAN) { reg(ic->arg[0]) = x >> 32; reg(ic->arg[0] + 4) = x; } else { reg(ic->arg[0]) = x; reg(ic->arg[0] + 4) = x >> 32; } #else #ifdef LS_SIGNED #ifdef LS_1 x = (int8_t)x; #endif #ifdef LS_2 x = (int16_t)x; #endif #ifdef LS_4 x = (int32_t)x; #endif #endif reg(ic->arg[0]) = x; #endif #else /* LS_STORE: */ #ifdef LS_8 if (cpu->byte_order == EMUL_BIG_ENDIAN) x = ((uint64_t)reg(ic->arg[0]) << 32) + reg(ic->arg[0] + 4); else x = ((uint64_t)reg(ic->arg[0] + 4) << 32) + reg(ic->arg[0]); cpu->cd.m88k.dmd[0] = reg(ic->arg[0]); cpu->cd.m88k.dmd[1] = reg(ic->arg[0] + 4); #else x = reg(ic->arg[0]); cpu->cd.m88k.dmd[0] = x; #endif memory_writemax64(cpu, data, LS_SIZE, x); if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_WRITE, memory_rw_flags)) { /* Exception. */ return; } #endif } #endif /* LS_INCLUDE_GENERIC */ void LS_N(struct cpu *cpu, struct m88k_instr_call *ic) { uint32_t addr = reg(ic->arg[1]) + #ifdef LS_REGOFS #ifdef LS_SCALED LS_SIZE * #endif reg(ic->arg[2]); #else ic->arg[2]; #endif #ifdef LS_USR #ifdef LS_LOAD uint8_t *p = cpu->cd.m88k.host_load_usr[addr >> 12]; #else uint8_t *p = cpu->cd.m88k.host_store_usr[addr >> 12]; #endif #else #ifdef LS_LOAD uint8_t *p = cpu->cd.m88k.host_load[addr >> 12]; #else uint8_t *p = cpu->cd.m88k.host_store[addr >> 12]; #endif #endif /* * Call the generic function, if things become too complicated: * * 1) .usr used in non-supervisor mode * 2) the page pointer is NULL * 3) unaligned access */ if ( #ifdef LS_USR !(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE) || #endif p == NULL #ifndef LS_1 || addr & (LS_SIZE - 1) #endif ) { LS_GENERIC_N(cpu, ic); return; } addr &= 0xfff; #ifdef LS_LOAD /* Load: */ #ifdef LS_1 reg(ic->arg[0]) = #ifdef LS_SIGNED (int8_t) #endif p[addr]; #endif /* LS_1 */ #ifdef LS_2 reg(ic->arg[0]) = #ifdef LS_SIGNED (int16_t) #endif #ifdef LS_BE #ifdef HOST_BIG_ENDIAN ( *(uint16_t *)(p + addr) ); #else ((p[addr]<<8) + p[addr+1]); #endif #else #ifdef HOST_LITTLE_ENDIAN ( *(uint16_t *)(p + addr) ); #else (p[addr] + (p[addr+1]<<8)); #endif #endif #endif /* LS_2 */ #ifdef LS_4 reg(ic->arg[0]) = #ifdef LS_SIGNED (int32_t) #else (uint32_t) #endif #ifdef LS_BE #ifdef HOST_BIG_ENDIAN ( *(uint32_t *)(p + addr) ); #else ((p[addr]<<24) + (p[addr+1]<<16) + (p[addr+2]<<8) + p[addr+3]); #endif #else #ifdef HOST_LITTLE_ENDIAN ( *(uint32_t *)(p + addr) ); #else (p[addr] + (p[addr+1]<<8) + (p[addr+2]<<16) + (p[addr+3]<<24)); #endif #endif #endif /* LS_4 */ #ifdef LS_8 /* Load first word in pair: */ reg(ic->arg[0]) = #ifdef LS_BE #ifdef HOST_BIG_ENDIAN ( *(uint32_t *)(p + addr) ); #else ((p[addr]<<24) + (p[addr+1]<<16) + (p[addr+2]<<8) + p[addr+3]); #endif #else #ifdef HOST_LITTLE_ENDIAN ( *(uint32_t *)(p + addr + 4) ); #else (p[addr+4] + (p[addr+5]<<8) + (p[addr+6]<<16) + (p[addr+7]<<24)); #endif #endif /* Load second word in pair: */ reg(ic->arg[0] + 4) = #ifdef LS_BE #ifdef HOST_BIG_ENDIAN ( *(uint32_t *)(p + addr + 4) ); #else ((p[addr+4]<<24) + (p[addr+5]<<16) + (p[addr+6]<<8) + p[addr+7]); #endif #else #ifdef HOST_LITTLE_ENDIAN ( *(uint32_t *)(p + addr) ); #else (p[addr] + (p[addr+1]<<8) + (p[addr+2]<<16) + (p[addr+3]<<24)); #endif #endif #endif /* LS_8 */ #else /* Store: */ #ifdef LS_1 p[addr] = reg(ic->arg[0]); #endif #ifdef LS_2 { uint32_t x = reg(ic->arg[0]); #ifdef LS_BE #ifdef HOST_BIG_ENDIAN *((uint16_t *)(p+addr)) = x; } #else p[addr] = x >> 8; p[addr+1] = x; } #endif #else #ifdef HOST_LITTLE_ENDIAN *((uint16_t *)(p+addr)) = x; } #else p[addr] = x; p[addr+1] = x >> 8; } #endif #endif #endif /* LS_2 */ #ifdef LS_4 { uint32_t x = reg(ic->arg[0]); #ifdef LS_BE #ifdef HOST_BIG_ENDIAN *((uint32_t *)(p+addr)) = x; } #else p[addr] = x >> 24; p[addr+1] = x >> 16; p[addr+2] = x >> 8; p[addr+3] = x; } #endif #else #ifdef HOST_LITTLE_ENDIAN *((uint32_t *)(p+addr)) = x; } #else p[addr] = x; p[addr+1] = x >> 8; p[addr+2] = x >> 16; p[addr+3] = x >> 24; } #endif #endif #endif /* LS_4 */ #ifdef LS_8 /* First word in pair: */ { uint32_t x = reg(ic->arg[0]); #ifdef LS_BE #ifdef HOST_BIG_ENDIAN *((uint32_t *)(p+addr)) = x; } #else p[addr] = x >> 24; p[addr+1] = x >> 16; p[addr+2] = x >> 8; p[addr+3] = x; } #endif #else #ifdef HOST_LITTLE_ENDIAN *((uint32_t *)(p+addr+4)) = x; } #else p[addr +4] = x; p[addr+1+4] = x >> 8; p[addr+2+4] = x >> 16; p[addr+3+4] = x >> 24; } #endif #endif /* Second word in pair: */ { uint32_t x = reg(ic->arg[0] + 4); #ifdef LS_BE #ifdef HOST_BIG_ENDIAN *((uint32_t *)(p+addr+4)) = x; } #else p[addr +4] = x >> 24; p[addr+1+4] = x >> 16; p[addr+2+4] = x >> 8; p[addr+3+4] = x; } #endif #else #ifdef HOST_LITTLE_ENDIAN *((uint32_t *)(p+addr)) = x; } #else p[addr ] = x; p[addr+1] = x >> 8; p[addr+2] = x >> 16; p[addr+3] = x >> 24; } #endif #endif #endif /* LS_8 */ #endif /* store */ } gxemul-0.6.1/src/cpus/memory_alpha.cc000644 001750 001750 00000012635 13402411502 017761 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "cpu.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/alpha_rpb.h" /* * alpha_translate_v2p(): */ int alpha_translate_v2p(struct cpu *cpu, uint64_t vaddr, uint64_t *return_paddr, int flags) { uint64_t base = cpu->cd.alpha.pcb.apcb_ptbr << ALPHA_PAGESHIFT; bool userMode = cpu->cd.alpha.ps & ALPHA_PSL_USERMODE; // uint64_t vptptr = cpu->cd.alpha.vptptr; // TODO: From the Alpha "arm_book.book": // IF {SEXT(VA<63:VA_SIZE>) NEQ SEXT(VA} THEN // {initiate Access Violation fault} // IF (VIRBND in use) THEN // IF (VA LTU VIRBND) THEN // ptbr_value <- PTBR // ELSE // ptbr_value <- SYSPTBR // ELSE // ptbr_value <- PTBR /* Kernel direct-mapped space (OSF/1, NetBSD): */ if (!userMode && (vaddr >= ALPHA_K0SEG_BASE && vaddr <= ALPHA_K0SEG_END)) { *return_paddr = vaddr & 0x000003ffffffffffULL; return 2; } /* * UGLY hack for now: * * Before virtual memory has been set up, ptbr is most likely zero. * In that case, simply map everything vaddr == paddr. */ if (!userMode && base == 0) { *return_paddr = vaddr & 0x000003ffffffffffULL; if (vaddr == 0xfffffffd80000000ULL) { fatal("Alpha kernel virtual memory seems to want to be used. Not yet implemented.\n"); exit(1); } #if 1 if ((vaddr & ~0x7fff) == 0x0000000010000000ULL) *return_paddr = (vaddr & 0x7fff) + HWRPB_PADDR; if ((vaddr & ~0xffffff) == 0xfffffe0000000000ULL) *return_paddr = 0x7efa000 + (vaddr & 0xffffff); /* At 0x20000000, NetBSD stores 8KB temp prom data */ if ((vaddr & ~0x1fff) == 0x0000000020000000ULL) *return_paddr = (vaddr & 0x1fff) + PROM_ARGSPACE_PADDR; #endif return 2; } // debug("base = 0x%016"PRIx64"\n", base); if (vaddr == 0xfffffffd80000000ULL) fatal("AYONA3\n"); uint64_t addr, pte1, pte2, pte3; int i1, i2, i3; unsigned char *pt_entry_ptr; const int pageSizeShift = 13; // const int pageSize = 1 << pageSizeShift; const int bitsPerLevel = 10; const int maskPerLevel = (1 << bitsPerLevel) - 1; i1 = (vaddr >> (pageSizeShift + 2 * bitsPerLevel)) & maskPerLevel; i2 = (vaddr >> (pageSizeShift + 1 * bitsPerLevel)) & maskPerLevel; i3 = (vaddr >> (pageSizeShift + 0 * bitsPerLevel)) & maskPerLevel; // debug("vaddr=%016llx i1=0x%x i2=0x%x i3=0x%x\n", (long long)vaddr, i1, i2, i3); addr = base + i1 * sizeof(uint64_t); pt_entry_ptr = memory_paddr_to_hostaddr(cpu->mem, addr, 0); if (pt_entry_ptr == NULL) goto not_found; pte1 = *(uint64_t *)(pt_entry_ptr); pte1 = LE64_TO_HOST(pte1); // debug("pte1 = 0x%016"PRIx64"\n", pte1); if (!(pte1 & ALPHA_PTE_VALID)) { // TODO: // IF level1_pte EQ 0 THEN // {initiate Access Violation fault} // ELSE // {initiate Translation Not Valid fault} // fatal("TODO: pte1 not valid.\n"); goto not_found; } addr = ((pte1 >> 32) << ALPHA_PAGESHIFT) + (i2 * sizeof(uint64_t)); pt_entry_ptr = memory_paddr_to_hostaddr(cpu->mem, addr, 0); if (pt_entry_ptr == NULL) goto not_found; pte2 = *(uint64_t *)(pt_entry_ptr); pte2 = LE64_TO_HOST(pte2); // debug("pte2 = 0x%016"PRIx64"\n", pte2); if (!(pte2 & ALPHA_PTE_VALID)) { // TODO: // IF level2_pte EQ 0 THEN // {initiate Access Violation fault} // ELSE // {initiate Translation Not Valid fault} fatal("TODO: pte2 not valid.\n"); goto not_found; } addr = ((pte2 >> 32) << ALPHA_PAGESHIFT) + (i3 * sizeof(uint64_t)); pt_entry_ptr = memory_paddr_to_hostaddr(cpu->mem, addr, 0); if (pt_entry_ptr == NULL) goto not_found; pte3 = *(uint64_t *)(pt_entry_ptr); pte3 = LE64_TO_HOST(pte3); // debug("pte3 = 0x%016"PRIx64"\n", pte3); if (!(pte3 & ALPHA_PTE_VALID)) { fatal("TODO: pte3 not valid.\n"); goto not_found; } (*return_paddr) = ALPHA_PTE_TO_PFN(pte3) << pageSizeShift; // TODO. return 2; not_found: /* No match. */ fatal("[ alpha_translate_v2p: 0x%016" PRIx64" wasn't found ]\n", vaddr); abort(); exit(1); return 0; } gxemul-0.6.1/src/cpus/cpu_mips_coproc.cc000644 001750 001750 00000201673 13402411502 020472 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Emulation of MIPS coprocessors. */ #include #include #include #include #include "cop0.h" #include "cpu.h" #include "cpu_mips.h" #include "emul.h" #include "float_emul.h" #include "machine.h" #include "memory.h" #include "mips_cpu_types.h" #include "misc.h" #include "opcodes_mips.h" #include "timer.h" extern volatile int single_step; static const char *cop0_names[] = COP0_NAMES; static const char *regnames[] = MIPS_REGISTER_NAMES; /* * initialize_cop0_config(): * * Helper function, called from mips_coproc_new(). */ static void initialize_cop0_config(struct cpu *cpu, struct mips_coproc *c) { const int m16 = 0; /* TODO: MIPS16 support */ int IB, DB, SB, IC, DC, SC, IA, DA; /* Generic case for MIPS32/64: */ if (cpu->cd.mips.cpu_type.isa_level == 32 || cpu->cd.mips.cpu_type.isa_level == 64) { /* According to the MIPS64 (5K) User's Manual: */ c->reg[COP0_CONFIG] = ( (uint32_t)1 << 31)/* Config 1 present bit */ | ( 0 << 20) /* ISD: instruction scheduling disable (=1) */ | ( 0 << 17) /* DID: dual issue disable */ | ( 0 << 16) /* BM: burst mode */ | ((cpu->byte_order == EMUL_BIG_ENDIAN? 1 : 0) << 15) /* endian mode */ | ((cpu->cd.mips.cpu_type.isa_level == 64? 2 : 0) << 13) /* 0=MIPS32, 1=64S, 2=64 */ | ( 0 << 10) /* Architecture revision */ | ( 1 << 7) /* MMU type: 1=TLB, 3=FMT */ | ( 2 << 0) /* kseg0 cache coherency algorithm */ ; /* Config select 1: caches etc. TODO: Don't use cpu->machine for this stuff! */ IB = cpu->cd.mips.cache_picache_linesize - 1; IB = IB < 0? 0 : (IB > 7? 7 : IB); DB = cpu->cd.mips.cache_pdcache_linesize - 1; DB = DB < 0? 0 : (DB > 7? 7 : DB); IC = cpu->cd.mips.cache_picache - cpu->cd.mips.cache_picache_linesize - 7; DC = cpu->cd.mips.cache_pdcache - cpu->cd.mips.cache_pdcache_linesize - 7; IA = cpu->cd.mips.cpu_type.piways - 1; DA = cpu->cd.mips.cpu_type.pdways - 1; cpu->cd.mips.cop0_config_select1 = ((cpu->cd.mips.cpu_type.nr_of_tlb_entries - 1) << 25) | (IC << 22) /* IS: I-cache sets per way */ | (IB << 19) /* IL: I-cache line-size */ | (IA << 16) /* IA: I-cache assoc. (ways-1) */ | (DC << 13) /* DS: D-cache sets per way */ | (DB << 10) /* DL: D-cache line-size */ | (DA << 7) /* DA: D-cache assoc. (ways-1) */ | (16 * 0) /* Existance of PerformanceCounters */ | ( 8 * 0) /* Existance of Watch Registers */ | ( 4 * m16) /* Existance of MIPS16 */ | ( 2 * 0) /* Existance of EJTAG */ | ( 1 * 1) /* Existance of FPU */ ; return; } switch (cpu->cd.mips.cpu_type.rev) { case MIPS_R2000: case MIPS_R3000: /* No config register. */ break; case MIPS_R4000: /* according to the R4000 manual */ case MIPS_R4600: IB = cpu->cd.mips.cache_picache_linesize - 4; IB = IB < 0? 0 : (IB > 1? 1 : IB); DB = cpu->cd.mips.cache_pdcache_linesize - 4; DB = DB < 0? 0 : (DB > 1? 1 : DB); SB = cpu->cd.mips.cache_secondary_linesize - 4; SB = SB < 0? 0 : (SB > 3? 3 : SB); IC = cpu->cd.mips.cache_picache - 12; IC = IC < 0? 0 : (IC > 7? 7 : IC); DC = cpu->cd.mips.cache_pdcache - 12; DC = DC < 0? 0 : (DC > 7? 7 : DC); SC = cpu->cd.mips.cache_secondary? 0 : 1; c->reg[COP0_CONFIG] = ( 0 << 31) /* Master/Checker present bit */ | (0x00 << 28) /* EC: system clock divisor, 0x00 = '2' */ | (0x00 << 24) /* EP */ | ( SB << 22) /* SB */ | (0x00 << 21) /* SS: 0 = mixed i/d scache */ | (0x00 << 20) /* SW */ | (0x00 << 18) /* EW: 0=64-bit */ | ( SC << 17) /* SC: 0=secondary cache present, 1=non-present */ | (0x00 << 16) /* SM: (todo) */ | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15) /* endian mode */ | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */ | (0x00 << 13) /* EB: (todo) */ | (0x00 << 12) /* 0 (resered) */ | ( IC << 9) /* IC: I-cache = 2^(12+IC) bytes (1 = 8KB, 4=64K) */ | ( DC << 6) /* DC: D-cache = 2^(12+DC) bytes (1 = 8KB, 4=64K) */ | ( IB << 5) /* IB: I-cache line size (0=16, 1=32) */ | ( DB << 4) /* DB: D-cache line size (0=16, 1=32) */ | ( 0 << 3) /* CU: todo */ | ( 0 << 0) /* kseg0 coherency algorithm (TODO) */ ; break; case MIPS_R4100: /* According to the VR4131 manual: */ IB = cpu->cd.mips.cache_picache_linesize - 4; IB = IB < 0? 0 : (IB > 1? 1 : IB); DB = cpu->cd.mips.cache_pdcache_linesize - 4; DB = DB < 0? 0 : (DB > 1? 1 : DB); IC = cpu->cd.mips.cache_picache - 10; IC = IC < 0? 0 : (IC > 7? 7 : IC); DC = cpu->cd.mips.cache_pdcache - 10; DC = DC < 0? 0 : (DC > 7? 7 : DC); c->reg[COP0_CONFIG] = ( 0 << 31) /* IS: Instruction Streaming bit */ | (0x01 << 28) /* EC: system clock divisor, 0x01 = 2 */ | (0x00 << 24) /* EP */ | (0x00 << 23) /* AD: Accelerate data mode (0=VR4000-compatible) */ | ( m16 << 20) /* M16: MIPS16 support */ | ( 1 << 17) /* '1' */ | (0x00 << 16) /* BP: 'Branch forecast' (0 = enabled) */ | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15) /* endian mode */ | ( 2 << 13) /* '2' hardcoded on VR4131 */ | ( 1 << 12) /* CS: Cache size mode (1 on VR4131) */ | ( IC << 9) /* IC: I-cache = 2^(10+IC) bytes (0 = 1KB, 4=16K) */ | ( DC << 6) /* DC: D-cache = 2^(10+DC) bytes (0 = 1KB, 4=16K) */ | ( IB << 5) /* IB: I-cache line size (0=16, 1=32) */ | ( DB << 4) /* DB: D-cache line size (0=16, 1=32) */ | ( 0 << 0) /* kseg0 coherency algorithm (TODO) */ ; break; case MIPS_R5000: case MIPS_RM5200: /* rm5200 is just a wild guess */ /* These are just guesses: (the comments are wrong) */ c->reg[COP0_CONFIG] = ( 0 << 31) /* Master/Checker present bit */ | (0x00 << 28) /* EC: system clock divisor, 0x00 = '2' */ | (0x00 << 24) /* EP */ | (0x00 << 22) /* SB */ | (0x00 << 21) /* SS */ | (0x00 << 20) /* SW */ | (0x00 << 18) /* EW: 0=64-bit */ | (0x01 << 17) /* SC: 0=secondary cache present, 1=non-present */ | (0x00 << 16) /* SM: (todo) */ | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15) /* endian mode */ | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */ | (0x00 << 13) /* EB: (todo) */ | (0x00 << 12) /* 0 (resered) */ | ( 3 << 9) /* IC: I-cache = 2^(12+IC) bytes (1 = 8KB, 4=64K) */ | ( 3 << 6) /* DC: D-cache = 2^(12+DC) bytes (1 = 8KB, 4=64K) */ | ( 1 << 5) /* IB: I-cache line size (0=16, 1=32) */ | ( 1 << 4) /* DB: D-cache line size (0=16, 1=32) */ | ( 0 << 3) /* CU: todo */ | ( 2 << 0) /* kseg0 coherency algorithm (TODO) */ ; break; case MIPS_R10000: case MIPS_R12000: case MIPS_R14000: IC = cpu->cd.mips.cache_picache - 12; IC = IC < 0? 0 : (IC > 7? 7 : IC); DC = cpu->cd.mips.cache_pdcache - 12; DC = DC < 0? 0 : (DC > 7? 7 : DC); SC = cpu->cd.mips.cache_secondary - 19; SC = SC < 0? 0 : (SC > 7? 7 : SC); /* According to the R10000 User's Manual: */ c->reg[COP0_CONFIG] = ( IC << 29) /* Primary instruction cache size (3 = 32KB) */ | ( DC << 26) /* Primary data cache size (3 = 32KB) */ | ( 0 << 19) /* SCClkDiv */ | ( SC << 16) /* SCSize, secondary cache size. 0 = 512KB. powers of two */ | ( 0 << 15) /* MemEnd */ | ( 0 << 14) /* SCCorEn */ | ( 1 << 13) /* SCBlkSize. 0=16 words, 1=32 words */ | ( 0 << 9) /* SysClkDiv */ | ( 0 << 7) /* PrcReqMax */ | ( 0 << 6) /* PrcElmReq */ | ( 0 << 5) /* CohPrcReqTar */ | ( 0 << 3) /* Device number */ | ( 2 << 0) /* Cache coherency algorithm for kseg0 */ ; break; case MIPS_R5900: /* * R5900 is supposed to have the following (according * to NetBSD/playstation2): * cpu0: 16KB/64B 2-way set-associative L1 Instruction * cache, 48 TLB entries * cpu0: 8KB/64B 2-way set-associative write-back L1 * Data cache * The following settings are just guesses: * (comments are incorrect) */ c->reg[COP0_CONFIG] = ( 0 << 31) /* Master/Checker present bit */ | (0x00 << 28) /* EC: system clock divisor, 0x00 = '2' */ | (0x00 << 24) /* EP */ | (0x00 << 22) /* SB */ | (0x00 << 21) /* SS */ | (0x00 << 20) /* SW */ | (0x00 << 18) /* EW: 0=64-bit */ | (0x01 << 17) /* SC: 0=secondary cache present, 1=non-present */ | (0x00 << 16) /* SM: (todo) */ | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15) /* endian mode */ | (0x01 << 14) /* ECC: 0=enabled, 1=disabled */ | (0x00 << 13) /* EB: (todo) */ | (0x00 << 12) /* 0 (resered) */ | ( 3 << 9) /* IC: I-cache = 2^(12+IC) bytes (1 = 8KB, 4=64K) */ | ( 3 << 6) /* DC: D-cache = 2^(12+DC) bytes (1 = 8KB, 4=64K) */ | ( 1 << 5) /* IB: I-cache line size (0=16, 1=32) */ | ( 1 << 4) /* DB: D-cache line size (0=16, 1=32) */ | ( 0 << 3) /* CU: todo */ | ( 0 << 0) /* kseg0 coherency algorithm (TODO) */ ; break; default:fatal("Internal error: No initialization code for" " config0? cpu rev = 0x%x", cpu->cd.mips.cpu_type.rev); exit(1); } } /* * initialize_cop1(): * * Helper function, called from mips_coproc_new(). */ static void initialize_cop1(struct cpu *cpu, struct mips_coproc *c) { int fpu_rev; uint64_t other_stuff = 0; switch (cpu->cd.mips.cpu_type.rev & 0xff) { case MIPS_R2000: fpu_rev = MIPS_R2010; break; case MIPS_R3000: fpu_rev = MIPS_R3010; other_stuff |= 0x40; /* or 0x30? TODO */ break; case MIPS_R6000: fpu_rev = MIPS_R6010; break; case MIPS_R4000: fpu_rev = MIPS_R4010; break; case MIPS_4Kc: /* TODO: Is this the same as 5Kc? */ case MIPS_5Kc: other_stuff = COP1_REVISION_DOUBLE | COP1_REVISION_SINGLE; case MIPS_R5000: case MIPS_RM5200: fpu_rev = cpu->cd.mips.cpu_type.rev; other_stuff |= 0x10; /* or cpu->cd.mips.cpu_type.sub ? TODO */ break; case MIPS_R10000: fpu_rev = MIPS_R10000; break; case MIPS_R12000: fpu_rev = 0x9; break; default: fpu_rev = MIPS_SOFT; } c->fcr[COP1_REVISION] = (fpu_rev << 8) | other_stuff; #if 0 /* These are mentioned in the MIPS64 documentation: */ + (1 << 16) /* single */ + (1 << 17) /* double */ + (1 << 18) /* paired-single */ + (1 << 19) /* 3d */ #endif } /* * mips_coproc_new(): * * Create a new MIPS coprocessor object. */ struct mips_coproc *mips_coproc_new(struct cpu *cpu, int coproc_nr) { struct mips_coproc *c; CHECK_ALLOCATION(c = (struct mips_coproc *) malloc(sizeof(struct mips_coproc))); memset(c, 0, sizeof(struct mips_coproc)); c->coproc_nr = coproc_nr; if (coproc_nr == 0) { c->nr_of_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries; c->tlbs = (struct mips_tlb *) zeroed_alloc(c->nr_of_tlbs * sizeof(struct mips_tlb)); /* * Start with nothing in the status register. This makes sure * that we are running in kernel mode with all interrupts * disabled. */ c->reg[COP0_STATUS] = 0; /* Hm. Enable coprocessors 0 and 1 even if we're not just emulating userland? TODO: Think about this. */ /* if (cpu->machine->prom_emulation) */ c->reg[COP0_STATUS] |= ((uint32_t)0x3 << STATUS_CU_SHIFT); if (!cpu->machine->prom_emulation) c->reg[COP0_STATUS] |= STATUS_BEV; /* Ugly hack for R5900/TX79/C790: */ if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) c->reg[COP0_STATUS] |= R5900_STATUS_EIE; /* Default pagesize = 4 KB (i.e. dualpage = 8KB) */ c->reg[COP0_PAGEMASK] = 0x1fff; /* Note: .rev may contain the company ID as well! */ c->reg[COP0_PRID] = (0x00 << 24) /* Company Options */ | (0x00 << 16) /* Company ID */ | (cpu->cd.mips.cpu_type.rev << 8) /* Processor ID */ | (cpu->cd.mips.cpu_type.sub) /* Revision */ ; c->reg[COP0_WIRED] = 0; initialize_cop0_config(cpu, c); /* Make sure the status register is sign-extended nicely: */ c->reg[COP0_STATUS] = (int32_t)c->reg[COP0_STATUS]; } if (coproc_nr == 1) initialize_cop1(cpu, c); return c; } /* * mips_timer_tick(): */ static void mips_timer_tick(struct timer *timer, void *extra) { struct cpu *cpu = (struct cpu *) extra; cpu->cd.mips.compare_interrupts_pending ++; if ((int32_t) (cpu->cd.mips.coproc[0]->reg[COP0_COUNT] - cpu->cd.mips.coproc[0]->reg[COP0_COMPARE]) < 0) { cpu->cd.mips.coproc[0]->reg[COP0_COUNT] = cpu->cd.mips.coproc[0]->reg[COP0_COMPARE]; } } /* * mips_coproc_tlb_set_entry(): * * Used by machine setup code, if a specific machine emulation starts up * with hardcoded virtual to physical mappings. */ void mips_coproc_tlb_set_entry(struct cpu *cpu, int entrynr, int size, uint64_t vaddr, uint64_t paddr0, uint64_t paddr1, int valid0, int valid1, int dirty0, int dirty1, int global, int asid, int cachealgo0, int cachealgo1) { if (entrynr < 0 || entrynr >= cpu->cd.mips.coproc[0]->nr_of_tlbs) { printf("mips_coproc_tlb_set_entry(): invalid entry nr: %i\n", entrynr); exit(1); } switch (cpu->cd.mips.cpu_type.mmu_model) { case MMU3K: if (size != 4096) { printf("mips_coproc_tlb_set_entry(): invalid pagesize " "(%i) for MMU3K\n", size); exit(1); } cpu->cd.mips.coproc[0]->tlbs[entrynr].hi = (vaddr & R2K3K_ENTRYHI_VPN_MASK) | ((asid << R2K3K_ENTRYHI_ASID_SHIFT) & R2K3K_ENTRYHI_ASID_MASK); cpu->cd.mips.coproc[0]->tlbs[entrynr].lo0 = (paddr0 & R2K3K_ENTRYLO_PFN_MASK) | (cachealgo0? R2K3K_ENTRYLO_N : 0) | (dirty0? R2K3K_ENTRYLO_D : 0) | (valid0? R2K3K_ENTRYLO_V : 0) | (global? R2K3K_ENTRYLO_G : 0); break; default: /* MMU4K and MMU10K, etc: */ if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) cpu->cd.mips.coproc[0]->tlbs[entrynr].hi = (vaddr & ENTRYHI_VPN2_MASK_R10K) | (vaddr & ENTRYHI_R_MASK) | (asid & ENTRYHI_ASID) | (global? TLB_G : 0); else cpu->cd.mips.coproc[0]->tlbs[entrynr].hi = (vaddr & ENTRYHI_VPN2_MASK) | (vaddr & ENTRYHI_R_MASK) | (asid & ENTRYHI_ASID) | (global? TLB_G : 0); /* NOTE: The pagemask size is for a "dual" page: */ cpu->cd.mips.coproc[0]->tlbs[entrynr].mask = (2*size - 1) & ~0x1fff; cpu->cd.mips.coproc[0]->tlbs[entrynr].lo0 = (((paddr0 >> 12) << ENTRYLO_PFN_SHIFT) & ENTRYLO_PFN_MASK) | (dirty0? ENTRYLO_D : 0) | (valid0? ENTRYLO_V : 0) | (global? ENTRYLO_G : 0) | ((cachealgo0 << ENTRYLO_C_SHIFT) & ENTRYLO_C_MASK); cpu->cd.mips.coproc[0]->tlbs[entrynr].lo1 = (((paddr1 >> 12) << ENTRYLO_PFN_SHIFT) & ENTRYLO_PFN_MASK) | (dirty1? ENTRYLO_D : 0) | (valid1? ENTRYLO_V : 0) | (global? ENTRYLO_G : 0) | ((cachealgo1 << ENTRYLO_C_SHIFT) & ENTRYLO_C_MASK); /* TODO: R4100, 1KB pages etc */ } } /* * invalidate_asid(): * * Go through all entries in the TLB. If an entry has a matching asid, is * valid, and is not global (i.e. the ASID matters), then its virtual address * translation is invalidated. * * Note: In the R3000 case, the asid argument is shifted 6 bits. */ static void invalidate_asid(struct cpu *cpu, unsigned int asid) { struct mips_coproc *cp = cpu->cd.mips.coproc[0]; unsigned int i, ntlbs = cp->nr_of_tlbs; struct mips_tlb *tlb = cp->tlbs; if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) { for (i = 0; i < ntlbs; i++) if ((tlb[i].hi & R2K3K_ENTRYHI_ASID_MASK) == asid && (tlb[i].lo0 & R2K3K_ENTRYLO_V) && !(tlb[i].lo0 & R2K3K_ENTRYLO_G)) { cpu->invalidate_translation_caches(cpu, tlb[i].hi & R2K3K_ENTRYHI_VPN_MASK, INVALIDATE_VADDR); } } else { for (i = 0; i < ntlbs; i++) { if ((tlb[i].hi & ENTRYHI_ASID) != asid || (tlb[i].hi & TLB_G)) continue; uint64_t mask = cp->tlbs[i].mask; uint64_t pagesize = 0x1000; uint64_t tmp = mask >> 13; while ((tmp & 1)) { tmp >>= 1; pagesize <<= 1; } uint64_t oldvaddr; if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) { oldvaddr = cp->tlbs[i].hi & (ENTRYHI_VPN2_MASK_R10K | ENTRYHI_R_MASK); /* 44 addressable bits: */ if (oldvaddr & 0x80000000000ULL) oldvaddr |= 0x3ffff00000000000ULL; } else if (cpu->is_32bit) { /* MIPS32 etc.: */ oldvaddr = cp->tlbs[i].hi & ENTRYHI_VPN2_MASK; oldvaddr = (int32_t)oldvaddr; } else { /* Assume MMU4K */ oldvaddr = cp->tlbs[i].hi & (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK); /* 40 addressable bits: */ if (oldvaddr & 0x8000000000ULL) oldvaddr |= 0x3fffff0000000000ULL; } mask |= 0x1fff; oldvaddr &= ~mask; // printf("pagesize = %016llx mask = %016llx\n", pagesize, mask); if (cp->tlbs[i].lo0 & ENTRYLO_V) for (uint64_t ofs = 0; ofs < pagesize; ofs += 0x1000) cpu->invalidate_translation_caches(cpu, oldvaddr + ofs, INVALIDATE_VADDR); if (cp->tlbs[i].lo1 & ENTRYLO_V) for (uint64_t ofs = 0; ofs < pagesize; ofs += 0x1000) cpu->invalidate_translation_caches(cpu, oldvaddr + ofs + pagesize, INVALIDATE_VADDR); } } } /* * coproc_register_read(); * * Read a value from a MIPS coprocessor register. */ void coproc_register_read(struct cpu *cpu, struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int select) { int unimpl = 1; if (cp->coproc_nr==0 && reg_nr==COP0_INDEX) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_RANDOM) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYLO0) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYLO1) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_CONTEXT) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_WIRED) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) { /* TODO: Increase count in a more meaningful way! */ cp->reg[COP0_COUNT] = (int32_t) (cp->reg[COP0_COUNT] + 1); cpu->cd.mips.count_register_read_count ++; unimpl = 0; } if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_STATUS) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_CAUSE) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_EPC) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_PRID) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_CONFIG) { if (select > 0) { switch (select) { case 1: *ptr = cpu->cd.mips.cop0_config_select1; break; default:fatal("coproc_register_read(): unimplemented" " config register select %i\n", select); exit(1); } return; } unimpl = 0; } if (cp->coproc_nr==0 && reg_nr==COP0_LLADDR) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_WATCHLO) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_WATCHHI) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_XCONTEXT) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_ERRCTL) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_CACHEERR) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_TAGDATA_LO) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_TAGDATA_HI) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_ERROREPC) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_RESERV22) { /* Used by Linux on Linksys WRT54G */ unimpl = 0; } if (cp->coproc_nr==0 && reg_nr==COP0_DEBUG) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_PERFCNT) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_DESAVE) unimpl = 0; if (cp->coproc_nr==1) unimpl = 0; if (unimpl) { fatal("cpu%i: warning: read from unimplemented coproc%i" " register %i (%s)\n", cpu->cpu_id, cp->coproc_nr, reg_nr, cp->coproc_nr==0? cop0_names[reg_nr] : "?"); mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cp->coproc_nr, 0, 0, 0); return; } *ptr = cp->reg[reg_nr]; } /* * coproc_register_write(); * * Write a value to a MIPS coprocessor register. */ void coproc_register_write(struct cpu *cpu, struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int flag64, int select) { int unimpl = 1; int readonly = 0; uint64_t tmp = *ptr; uint64_t tmp2 = 0, old; int inval = 0; unsigned int old_asid; uint64_t oldmode; switch (cp->coproc_nr) { case 0: /* COPROC 0: */ switch (reg_nr) { case COP0_INDEX: case COP0_RANDOM: unimpl = 0; break; case COP0_ENTRYLO0: unimpl = 0; if (cpu->cd.mips.cpu_type.mmu_model == MMU3K && (tmp & 0xff)!=0) { /* char *symbol; uint64_t offset; symbol = get_symbol_name(cpu->pc, &offset); fatal("YO! pc = 0x%08llx <%s> " "lo=%016llx\n", (long long) cpu->pc, symbol? symbol : "no symbol", (long long)tmp); */ tmp &= (R2K3K_ENTRYLO_PFN_MASK | R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D | R2K3K_ENTRYLO_V | R2K3K_ENTRYLO_G); } else if (cpu->cd.mips.cpu_type.mmu_model == MMU4K) { tmp &= (ENTRYLO_PFN_MASK | ENTRYLO_C_MASK | ENTRYLO_D | ENTRYLO_V | ENTRYLO_G); } break; case COP0_BADVADDR: /* Hm. Irix writes to this register. (Why?) */ unimpl = 0; break; case COP0_ENTRYLO1: unimpl = 0; if (cpu->cd.mips.cpu_type.mmu_model == MMU4K) { tmp &= (ENTRYLO_PFN_MASK | ENTRYLO_C_MASK | ENTRYLO_D | ENTRYLO_V | ENTRYLO_G); } break; case COP0_CONTEXT: old = cp->reg[COP0_CONTEXT]; cp->reg[COP0_CONTEXT] = tmp; if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) { cp->reg[COP0_CONTEXT] &= ~R2K3K_CONTEXT_BADVPN_MASK; cp->reg[COP0_CONTEXT] |= (old & R2K3K_CONTEXT_BADVPN_MASK); } else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) { cp->reg[COP0_CONTEXT] &= ~CONTEXT_BADVPN2_MASK_R4100; cp->reg[COP0_CONTEXT] |= (old & CONTEXT_BADVPN2_MASK_R4100); } else { cp->reg[COP0_CONTEXT] &= ~CONTEXT_BADVPN2_MASK; cp->reg[COP0_CONTEXT] |= (old & CONTEXT_BADVPN2_MASK); } return; case COP0_PAGEMASK: tmp2 = tmp >> PAGEMASK_SHIFT; if (tmp2 != 0x000 && tmp2 != 0x003 && tmp2 != 0x00f && tmp2 != 0x03f && tmp2 != 0x0ff && tmp2 != 0x3ff && tmp2 != 0xfff && tmp2 != 0x3fff && tmp2 != 0xffff) fatal("[ cpu%i: trying to write an invalid" " pagemask 0x%08lx to COP0_PAGEMASK ]\n", cpu->cpu_id, (long)tmp); unimpl = 0; break; case COP0_WIRED: if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) { fatal("[ cpu%i: r2k/r3k wired register must " "always be 8 ]\n", cpu->cpu_id); tmp = 8; } cp->reg[COP0_RANDOM] = cp->nr_of_tlbs-1; tmp &= INDEX_MASK; unimpl = 0; break; case COP0_COUNT: if (tmp != (uint64_t)(int64_t)(int32_t)tmp) fatal("[ WARNING: trying to write a 64-bit value" " to the COUNT register! ]\n"); tmp = (int64_t)(int32_t)tmp; unimpl = 0; break; case COP0_COMPARE: if (cpu->machine->emulated_hz > 0) { int32_t compare_diff = tmp - cp->reg[COP0_COMPARE]; double hz; if (compare_diff < 0) hz = tmp - cp->reg[COP0_COUNT]; if (compare_diff == 0) hz = 0; else hz = (double)cpu->machine->emulated_hz / (double)compare_diff; /* Initialize or re-set the periodic timer: */ if (hz > 0) { if (cpu->cd.mips.timer == NULL) cpu->cd.mips.timer = timer_add( hz, mips_timer_tick, cpu); else timer_update_frequency( cpu->cd.mips.timer, hz); } } /* Ack the periodic timer, if it was asserted: */ if (cp->reg[COP0_CAUSE] & 0x8000 && cpu->cd.mips.compare_interrupts_pending > 0) cpu->cd.mips.compare_interrupts_pending --; /* Clear the timer interrupt assertion (bit 7): */ cp->reg[COP0_CAUSE] &= ~0x8000; if (tmp != (uint64_t)(int64_t)(int32_t)tmp) fatal("[ WARNING: trying to write a 64-bit value" " to the COMPARE register! ]\n"); tmp = (int64_t)(int32_t)tmp; cpu->cd.mips.compare_register_set = 1; unimpl = 0; break; case COP0_ENTRYHI: /* * Translation caches must be invalidated if the * ASID changes: */ switch (cpu->cd.mips.cpu_type.mmu_model) { case MMU3K: old_asid = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK; if ((cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK) != (tmp & R2K3K_ENTRYHI_ASID_MASK)) inval = 1; break; default: old_asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID; if ((cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID) != (tmp & ENTRYHI_ASID)) inval = 1; break; } if (inval) invalidate_asid(cpu, old_asid); unimpl = 0; if (cpu->cd.mips.cpu_type.mmu_model == MMU3K && (tmp & 0x3f)!=0) { /* char *symbol; uint64_t offset; symbol = get_symbol_name(cpu->pc, &offset); fatal("YO! pc = 0x%08llx <%s> " "hi=%016llx\n", (long long)cpu->pc, symbol? symbol : "no symbol", (long long)tmp); */ tmp &= ~0x3f; } if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) tmp &= (R2K3K_ENTRYHI_VPN_MASK | R2K3K_ENTRYHI_ASID_MASK); else if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) tmp &= (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K | ENTRYHI_ASID); else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) tmp &= (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | 0x1800 | ENTRYHI_ASID); else tmp &= (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | ENTRYHI_ASID); break; case COP0_EPC: unimpl = 0; break; case COP0_PRID: readonly = 1; break; case COP0_CONFIG: if (select > 0) { switch (select) { case 1: cpu->cd.mips.cop0_config_select1 = tmp; break; default:fatal("[ coproc_register_write(): unimpl" "emented config register select " "%i ]\n", select); exit(1); } return; } /* fatal("COP0_CONFIG: modifying K0 bits: " "0x%08x => ", cp->reg[reg_nr]); */ tmp = *ptr; tmp &= 0x3; /* only bits 2..0 can be written */ cp->reg[reg_nr] &= ~(0x3); cp->reg[reg_nr] |= tmp; /* fatal("0x%08x\n", cp->reg[reg_nr]); */ return; case COP0_STATUS: oldmode = cp->reg[COP0_STATUS]; tmp &= ~(1 << 21); /* bit 21 is read-only */ /* * When isolating caches, invalidate all translations. * During the isolation, a special hack in memory_rw.c * prevents translation tables from being updated, so * the translation caches don't have to be invalidated * when switching back to normal mode. */ if (cpu->cd.mips.cpu_type.mmu_model == MMU3K && (oldmode & MIPS1_ISOL_CACHES) != (tmp & MIPS1_ISOL_CACHES)) { /* Invalidate everything if we are switching to isolated mode: */ if (tmp & MIPS1_ISOL_CACHES) { cpu->invalidate_translation_caches( cpu, 0, INVALIDATE_ALL); } } unimpl = 0; break; case COP0_CAUSE: /* A write to the cause register only affects IM bits 0 and 1: */ cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT); cp->reg[reg_nr] |= (tmp & (0x3 << STATUS_IM_SHIFT)); return; case COP0_FRAMEMASK: /* TODO: R10000 */ unimpl = 0; break; case COP0_TAGDATA_LO: case COP0_TAGDATA_HI: /* TODO: R4300 and others? */ unimpl = 0; break; case COP0_LLADDR: unimpl = 0; break; case COP0_WATCHLO: case COP0_WATCHHI: unimpl = 0; break; case COP0_XCONTEXT: /* * TODO: According to the R10000 manual, the R4400 * shares the PTEbase portion of the context registers * (that is, xcontext and context). On R10000, they * are separate registers. */ /* debug("[ xcontext 0x%016llx ]\n", tmp); */ unimpl = 0; break; /* Most of these are actually TODOs: */ case COP0_ERROREPC: case COP0_DEPC: case COP0_RESERV22: /* Used by Linux on Linksys WRT54G */ case COP0_DESAVE: case COP0_PERFCNT: case COP0_ERRCTL: /* R10000 */ unimpl = 0; break; } break; case 1: /* COPROC 1: */ unimpl = 0; break; } if (unimpl) { fatal("[ cpu%i: warning: write to unimplemented coproc%i " "register %i (%s), data = 0x%016llx ]\n", cpu->cpu_id, cp->coproc_nr, reg_nr, cp->coproc_nr==0? cop0_names[reg_nr] : "?", (long long)tmp); /* mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cp->coproc_nr, 0, 0, 0); return; */ } if (readonly) { fatal("[ cpu%i: warning: write to READONLY coproc%i register " "%i ignored ]\n", cpu->cpu_id, cp->coproc_nr, reg_nr); return; } cp->reg[reg_nr] = tmp; if (!flag64) cp->reg[reg_nr] = (int64_t)(int32_t)cp->reg[reg_nr]; } /* * MIPS floating-point stuff: * * TODO: Move this to some other file? */ static int mips_fmt_to_ieee_fmt[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, IEEE_FMT_S, IEEE_FMT_D, 0, 0, IEEE_FMT_W, IEEE_FMT_L, /* PS (Paired Single) */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const char *fmtname[32] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "s", "d", "18", "19", "w", "l", "ps", "23", "24", "25", "26", "27", "28", "29", "30", "31" }; static const char *ccname[16] = { "f", "un", "eq", "ueq", "olt", "ult", "ole", "ule", "sf", "ngle", "seq", "ngl", "lt", "nge", "le", "ngt" }; #define FPU_OP_ADD 1 #define FPU_OP_SUB 2 #define FPU_OP_MUL 3 #define FPU_OP_DIV 4 #define FPU_OP_SQRT 5 #define FPU_OP_MOV 6 #define FPU_OP_CVT 7 #define FPU_OP_C 8 #define FPU_OP_ABS 9 #define FPU_OP_NEG 10 /* TODO: CEIL.L, CEIL.W, FLOOR.L, FLOOR.W, RECIP, ROUND.L, ROUND.W, RSQRT */ /* * fpu_store_float_value(): * * Stores a float value (actually a double) in fmt format. */ static void fpu_store_float_value(bool fr, struct mips_coproc *cp, int fd, double nf, int fmt, int nan) { int ieee_fmt = mips_fmt_to_ieee_fmt[fmt]; uint64_t r = ieee_store_float_value(nf, ieee_fmt); /* * TODO: This is for 32-bit mode. It has to be updated later * for 64-bit coprocessor functionality! */ if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) { if (fr) cp->reg[fd] = r; else { cp->reg[fd] = r & 0xffffffffULL; cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL; if (cp->reg[fd] & 0x80000000ULL) cp->reg[fd] |= 0xffffffff00000000ULL; if (cp->reg[fd+1] & 0x80000000ULL) cp->reg[fd+1] |= 0xffffffff00000000ULL; } } else { cp->reg[fd] = r & 0xffffffffULL; if (cp->reg[fd] & 0x80000000ULL) cp->reg[fd] |= 0xffffffff00000000ULL; } } /* * fpu_op(): * * Perform a floating-point operation. For those of fs and ft that are >= 0, * those numbers are interpreted into local variables. * * Only FPU_OP_C (compare) returns anything of interest, 1 for true, 0 for * false. */ static int fpu_op(struct cpu *cpu, struct mips_coproc *cp, int op, int fmt, int ft, int fs, int fd, int cond, int output_fmt) { /* Potentially two input registers, fs and ft */ struct ieee_float_value float_value[2]; int unordered, nan, ieee_fmt = mips_fmt_to_ieee_fmt[fmt]; uint64_t fs_v = 0; double nf; bool fr = cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_FR ? true : false; // printf("op %x (fmt %i):\n", op, fmt); if (fs >= 0) { fs_v = cp->reg[fs]; if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) { if (!fr) fs_v = (fs_v & 0xffffffffULL) + (cp->reg[(fs + 1) & 31] << 32); } // printf(" fs_v = 0x%016llx\n", (long long)fs_v); ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt); } if (ft >= 0) { uint64_t v = cp->reg[ft]; if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) { if (!fr) v = (v & 0xffffffffULL) + (cp->reg[(ft + 1) & 31] << 32); } // printf(" ft_v = 0x%016llx\n", (long long)v); ieee_interpret_float_value(v, &float_value[1], ieee_fmt); } switch (op) { case FPU_OP_ADD: nf = float_value[0].f + float_value[1].f; /* debug(" add: %f + %f = %f\n", float_value[0].f, float_value[1].f, nf); */ fpu_store_float_value(fr, cp, fd, nf, output_fmt, float_value[0].nan || float_value[1].nan); break; case FPU_OP_SUB: nf = float_value[0].f - float_value[1].f; /* debug(" sub: %f - %f = %f\n", float_value[0].f, float_value[1].f, nf); */ fpu_store_float_value(fr, cp, fd, nf, output_fmt, float_value[0].nan || float_value[1].nan); break; case FPU_OP_MUL: nf = float_value[0].f * float_value[1].f; /* debug(" mul: %f * %f = %f\n", float_value[0].f, float_value[1].f, nf); */ fpu_store_float_value(fr, cp, fd, nf, output_fmt, float_value[0].nan || float_value[1].nan); break; case FPU_OP_DIV: nan = float_value[0].nan || float_value[1].nan; if (fabs(float_value[1].f) > 0.00000000001) nf = float_value[0].f / float_value[1].f; else { fatal("DIV by zero !!!! TODO\n"); nf = 0.0; /* TODO */ nan = 1; // mips_cpu_exception(cpu, EXCEPTION_FPE, 0, 0, 1, 0, 0, 0); return 0; } /* debug(" div: %f / %f = %f\n", float_value[0].f, float_value[1].f, nf); */ fpu_store_float_value(fr, cp, fd, nf, output_fmt, nan); break; case FPU_OP_SQRT: nan = float_value[0].nan; if (float_value[0].f >= 0.0) nf = sqrt(float_value[0].f); else { fatal("SQRT by less than zero, %f !!!!\n", float_value[0].f); nf = 0.0; /* TODO */ nan = 1; } /* debug(" sqrt: %f => %f\n", float_value[0].f, nf); */ fpu_store_float_value(fr, cp, fd, nf, output_fmt, nan); break; case FPU_OP_ABS: nf = fabs(float_value[0].f); /* debug(" abs: %f => %f\n", float_value[0].f, nf); */ fpu_store_float_value(fr, cp, fd, nf, output_fmt, float_value[0].nan); break; case FPU_OP_NEG: nf = - float_value[0].f; /* debug(" neg: %f => %f\n", float_value[0].f, nf); */ fpu_store_float_value(fr, cp, fd, nf, output_fmt, float_value[0].nan); break; case FPU_OP_CVT: nf = float_value[0].f; /* debug(" mov: %f => %f\n", float_value[0].f, nf); */ fpu_store_float_value(fr, cp, fd, nf, output_fmt, float_value[0].nan); break; case FPU_OP_MOV: /* Non-arithmetic move: */ /* * TODO: this is for 32-bit mode. It has to be updated later * for 64-bit coprocessor stuff. */ if (output_fmt == COP1_FMT_D || output_fmt == COP1_FMT_L) { if (fr) cp->reg[fd] = fs_v; else { cp->reg[fd] = fs_v & 0xffffffffULL; cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL; if (cp->reg[fd] & 0x80000000ULL) cp->reg[fd] |= 0xffffffff00000000ULL; if (cp->reg[fd+1] & 0x80000000ULL) cp->reg[fd+1] |= 0xffffffff00000000ULL; } } else { cp->reg[fd] = fs_v & 0xffffffffULL; if (cp->reg[fd] & 0x80000000ULL) cp->reg[fd] |= 0xffffffff00000000ULL; } break; case FPU_OP_C: /* debug(" c: cond=%i\n", cond); */ unordered = 0; if (float_value[0].nan || float_value[1].nan) unordered = 1; switch (cond) { case 2: /* Equal */ return (float_value[0].f == float_value[1].f); case 4: /* Ordered or Less than */ return (float_value[0].f < float_value[1].f) || !unordered; case 5: /* Unordered or Less than */ return (float_value[0].f < float_value[1].f) || unordered; case 6: /* Ordered or Less than or Equal */ return (float_value[0].f <= float_value[1].f) || !unordered; case 7: /* Unordered or Less than or Equal */ return (float_value[0].f <= float_value[1].f) || unordered; case 12:/* Less than */ return (float_value[0].f < float_value[1].f); case 14:/* Less than or equal */ return (float_value[0].f <= float_value[1].f); /* The following are not commonly used, so I'll move these out of the if-0 on a case-by-case basis. */ #if 0 case 0: return 0; /* False */ case 1: return 0; /* Unordered */ case 3: return (float_value[0].f == float_value[1].f); /* Unordered or Equal */ case 8: return 0; /* Signaling false */ case 9: return 0; /* Not Greater than or Less than or Equal */ case 10:return (float_value[0].f == float_value[1].f); /* Signaling Equal */ case 11:return (float_value[0].f == float_value[1].f); /* Not Greater than or Less than */ case 13:return !(float_value[0].f >= float_value[1].f); /* Not greater than or equal */ case 15:return !(float_value[0].f > float_value[1].f); /* Not greater than */ #endif default: fatal("fpu_op(): unimplemented condition " "code %i. see cpu_mips_coproc.c\n", cond); } break; default: fatal("fpu_op(): unimplemented op %i\n", op); } return 0; } /* * fpu_function(): * * Returns 1 if function was implemented, 0 otherwise. * Debug trace should be printed for known instructions. */ static int fpu_function(struct cpu *cpu, struct mips_coproc *cp, uint32_t function, int unassemble_only) { int fd, fs, ft, fmt, cond, cc; fmt = (function >> 21) & 31; ft = (function >> 16) & 31; fs = (function >> 11) & 31; cc = (function >> 8) & 7; fd = (function >> 6) & 31; cond = (function >> 0) & 15; /* bc1f, bc1t, bc1fl, bc1tl: */ if ((function & 0x03e00000) == 0x01000000) { int nd, tf, imm; const char *instr_mnem; /* cc are bits 20..18: */ cc = (function >> 18) & 7; nd = (function >> 17) & 1; tf = (function >> 16) & 1; imm = function & 65535; if (imm >= 32768) imm -= 65536; instr_mnem = NULL; if (nd == 0 && tf == 0) instr_mnem = "bc1f"; if (nd == 0 && tf == 1) instr_mnem = "bc1t"; if (nd == 1 && tf == 0) instr_mnem = "bc1fl"; if (nd == 1 && tf == 1) instr_mnem = "bc1tl"; if (cpu->machine->instruction_trace || unassemble_only) debug("%s\t%i,0x%016llx\n", instr_mnem, cc, (long long) (cpu->pc + 4 + (imm << 2))); if (unassemble_only) return 1; fatal("INTERNAL ERROR: MIPS coprocessor branches should not" " be implemented in cpu_mips_coproc.c, but in" " cpu_mips_instr.c!\n"); exit(1); } /* add.fmt: Floating-point add */ if ((function & 0x0000003f) == 0x00000000) { if (cpu->machine->instruction_trace || unassemble_only) debug("add.%s\tr%i,r%i,r%i\n", fmtname[fmt], fd, fs, ft); if (unassemble_only) return 1; fpu_op(cpu, cp, FPU_OP_ADD, fmt, ft, fs, fd, -1, fmt); return 1; } /* sub.fmt: Floating-point subtract */ if ((function & 0x0000003f) == 0x00000001) { if (cpu->machine->instruction_trace || unassemble_only) debug("sub.%s\tr%i,r%i,r%i\n", fmtname[fmt], fd, fs, ft); if (unassemble_only) return 1; fpu_op(cpu, cp, FPU_OP_SUB, fmt, ft, fs, fd, -1, fmt); return 1; } /* mul.fmt: Floating-point multiply */ if ((function & 0x0000003f) == 0x00000002) { if (cpu->machine->instruction_trace || unassemble_only) debug("mul.%s\tr%i,r%i,r%i\n", fmtname[fmt], fd, fs, ft); if (unassemble_only) return 1; fpu_op(cpu, cp, FPU_OP_MUL, fmt, ft, fs, fd, -1, fmt); return 1; } /* div.fmt: Floating-point divide */ if ((function & 0x0000003f) == 0x00000003) { if (cpu->machine->instruction_trace || unassemble_only) debug("div.%s\tr%i,r%i,r%i\n", fmtname[fmt], fd, fs, ft); if (unassemble_only) return 1; fpu_op(cpu, cp, FPU_OP_DIV, fmt, ft, fs, fd, -1, fmt); return 1; } /* sqrt.fmt: Floating-point square-root */ if ((function & 0x001f003f) == 0x00000004) { if (cpu->machine->instruction_trace || unassemble_only) debug("sqrt.%s\tr%i,r%i\n", fmtname[fmt], fd, fs); if (unassemble_only) return 1; fpu_op(cpu, cp, FPU_OP_SQRT, fmt, -1, fs, fd, -1, fmt); return 1; } /* abs.fmt: Floating-point absolute value */ if ((function & 0x001f003f) == 0x00000005) { if (cpu->machine->instruction_trace || unassemble_only) debug("abs.%s\tr%i,r%i\n", fmtname[fmt], fd, fs); if (unassemble_only) return 1; fpu_op(cpu, cp, FPU_OP_ABS, fmt, -1, fs, fd, -1, fmt); return 1; } /* mov.fmt: Floating-point (non-arithmetic) move */ if ((function & 0x0000003f) == 0x00000006) { if (cpu->machine->instruction_trace || unassemble_only) debug("mov.%s\tr%i,r%i\n", fmtname[fmt], fd, fs); if (unassemble_only) return 1; fpu_op(cpu, cp, FPU_OP_MOV, fmt, -1, fs, fd, -1, fmt); return 1; } /* neg.fmt: Floating-point negate */ if ((function & 0x001f003f) == 0x00000007) { if (cpu->machine->instruction_trace || unassemble_only) debug("neg.%s\tr%i,r%i\n", fmtname[fmt], fd, fs); if (unassemble_only) return 1; fpu_op(cpu, cp, FPU_OP_NEG, fmt, -1, fs, fd, -1, fmt); return 1; } /* trunc.l.fmt: Truncate */ if ((function & 0x001f003f) == 0x00000009) { if (cpu->machine->instruction_trace || unassemble_only) debug("trunc.l.%s\tr%i,r%i\n", fmtname[fmt], fd, fs); if (unassemble_only) return 1; /* TODO: not CVT? */ fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_L); return 1; } /* trunc.w.fmt: Truncate */ if ((function & 0x001f003f) == 0x0000000d) { if (cpu->machine->instruction_trace || unassemble_only) debug("trunc.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs); if (unassemble_only) return 1; /* TODO: not CVT? */ fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W); return 1; } /* c.cond.fmt: Floating-point compare */ if ((function & 0x000000f0) == 0x00000030) { int cond_true; int bit; if (cpu->machine->instruction_trace || unassemble_only) debug("c.%s.%s\tcc%i,r%i,r%i\n", ccname[cond], fmtname[fmt], cc, fs, ft); if (unassemble_only) return 1; cond_true = fpu_op(cpu, cp, FPU_OP_C, fmt, ft, fs, -1, cond, fmt); /* * Both the FCCR and FCSR contain condition code bits: * FCCR: bits 7..0 * FCSR: bits 31..25 and 23 */ cp->fcr[MIPS_FPU_FCCR] &= ~(1 << cc); if (cond_true) cp->fcr[MIPS_FPU_FCCR] |= (1 << cc); if (cc == 0) { bit = 1 << MIPS_FCSR_FCC0_SHIFT; cp->fcr[MIPS_FPU_FCSR] &= ~bit; if (cond_true) cp->fcr[MIPS_FPU_FCSR] |= bit; } else { bit = 1 << (MIPS_FCSR_FCC1_SHIFT + cc-1); cp->fcr[MIPS_FPU_FCSR] &= ~bit; if (cond_true) cp->fcr[MIPS_FPU_FCSR] |= bit; } return 1; } /* cvt.s.fmt: Convert to single floating-point */ if ((function & 0x001f003f) == 0x00000020) { if (cpu->machine->instruction_trace || unassemble_only) debug("cvt.s.%s\tr%i,r%i\n", fmtname[fmt], fd, fs); if (unassemble_only) return 1; fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_S); return 1; } /* cvt.d.fmt: Convert to double floating-point */ if ((function & 0x001f003f) == 0x00000021) { if (cpu->machine->instruction_trace || unassemble_only) debug("cvt.d.%s\tr%i,r%i\n", fmtname[fmt], fd, fs); if (unassemble_only) return 1; fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_D); return 1; } /* cvt.w.fmt: Convert to word fixed-point */ if ((function & 0x001f003f) == 0x00000024) { if (cpu->machine->instruction_trace || unassemble_only) debug("cvt.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs); if (unassemble_only) return 1; fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W); return 1; } return 0; } /* * coproc_tlbpr(): * * 'tlbp' and 'tlbr'. */ void coproc_tlbpr(struct cpu *cpu, int readflag) { struct mips_coproc *cp = cpu->cd.mips.coproc[0]; int i, found, g_bit; uint64_t vpn2, xmask; /* Read: */ if (readflag) { if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) { i = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK) >> R2K3K_INDEX_SHIFT; if (i >= cp->nr_of_tlbs) { /* TODO: exception? */ fatal("[ warning: tlbr from index %i (too " "high) ]\n", i); return; } cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi; cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0; } else { /* R4000: */ i = cp->reg[COP0_INDEX] & INDEX_MASK; if (i >= cp->nr_of_tlbs) { /* TODO: exception? */ fatal("[ warning: tlbr from index %i (too " "high) ]\n", i); return; } cp->reg[COP0_PAGEMASK] = cp->tlbs[i].mask; cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi; cp->reg[COP0_ENTRYLO1] = cp->tlbs[i].lo1; cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0; if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) { /* R4100 don't have the G bit in entryhi */ } else { /* R4000 etc: */ cp->reg[COP0_ENTRYHI] &= ~TLB_G; g_bit = cp->tlbs[i].hi & TLB_G; cp->reg[COP0_ENTRYLO0] &= ~ENTRYLO_G; cp->reg[COP0_ENTRYLO1] &= ~ENTRYLO_G; if (g_bit) { cp->reg[COP0_ENTRYLO0] |= ENTRYLO_G; cp->reg[COP0_ENTRYLO1] |= ENTRYLO_G; } } } return; } /* Probe: */ if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) { vpn2 = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK; found = -1; for (i=0; inr_of_tlbs; i++) if ( ((cp->tlbs[i].hi & R2K3K_ENTRYHI_ASID_MASK) == (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK)) || cp->tlbs[i].lo0 & R2K3K_ENTRYLO_G) if ((cp->tlbs[i].hi & R2K3K_ENTRYHI_VPN_MASK) == vpn2) { found = i; break; } } else { /* R4000 and R10000: */ if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K; else if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | 0x1800; else xmask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK; vpn2 = cp->reg[COP0_ENTRYHI] & xmask; found = -1; for (i=0; inr_of_tlbs; i++) { int gbit = cp->tlbs[i].hi & TLB_G; if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) gbit = (cp->tlbs[i].lo0 & ENTRYLO_G) && (cp->tlbs[i].lo1 & ENTRYLO_G); if ( ((cp->tlbs[i].hi & ENTRYHI_ASID) == (cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID)) || gbit) { uint64_t a = vpn2 & ~cp->tlbs[i].mask; uint64_t b = (cp->tlbs[i].hi & xmask) & ~cp->tlbs[i].mask; if (a == b) { found = i; break; } } } } if (found == -1) cp->reg[COP0_INDEX] = INDEX_P; else { if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) cp->reg[COP0_INDEX] = found << R2K3K_INDEX_SHIFT; else cp->reg[COP0_INDEX] = found; } /* Sign extend the index register: */ if ((cp->reg[COP0_INDEX] >> 32) == 0 && cp->reg[COP0_INDEX] & 0x80000000) cp->reg[COP0_INDEX] |= 0xffffffff00000000ULL; } /* * coproc_tlbwri(): * * MIPS TLB write random (tlbwr) and write indexed (tlbwi) instructions. */ void coproc_tlbwri(struct cpu *cpu, int randomflag) { struct mips_coproc *cp = cpu->cd.mips.coproc[0]; int index, g_bit; uint64_t oldvaddr; if (randomflag) { if (cpu->cd.mips.cpu_type.exc_model == EXC3K) { index = ((cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK) >> R2K3K_RANDOM_SHIFT) - 1; /* R3000 always has 8 wired entries: */ if (index < 8) index = cp->nr_of_tlbs - 1; cp->reg[COP0_RANDOM] = index << R2K3K_RANDOM_SHIFT; } else { cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random() % (cp->nr_of_tlbs - cp->reg[COP0_WIRED])); index = cp->reg[COP0_RANDOM] & RANDOM_MASK; } } else { if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) index = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK) >> R2K3K_INDEX_SHIFT; else index = cp->reg[COP0_INDEX] & INDEX_MASK; } if (index >= cp->nr_of_tlbs) { fatal("warning: tlb index %i too high (max is %i)\n", index, cp->nr_of_tlbs - 1); /* TODO: cause an exception? */ return; } #if 0 /* Debug dump of the previous entry at that index: */ fatal("{ old TLB entry at index %02x:", index); if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) { fatal(" hi=%08" PRIx32, (uint32_t)cp->tlbs[index].hi); fatal(" lo=%08" PRIx32, (uint32_t)cp->tlbs[index].lo0); } else { if (cpu->is_32bit) { fatal(" mask=%08" PRIx32,(uint32_t)cp->tlbs[index].mask); fatal(" hi=%08" PRIx32, (uint32_t)cp->tlbs[index].hi); fatal(" lo0=%08" PRIx32, (uint32_t)cp->tlbs[index].lo0); fatal(" lo1=%08" PRIx32, (uint32_t)cp->tlbs[index].lo1); } else { fatal(" mask=%016" PRIx64, cp->tlbs[index].mask); fatal(" hi=%016" PRIx64, cp->tlbs[index].hi); fatal(" lo0=%016" PRIx64, cp->tlbs[index].lo0); fatal(" lo1=%016" PRIx64, cp->tlbs[index].lo1); } } fatal(" }\n"); #endif /* * Any virtual address translation for the old TLB entry must be * invalidated first: * * (Only Valid entries need to be invalidated, and only those that * are either Global, or have the same ASID as the new entry will * have. No other address translations should be active anyway.) */ switch (cpu->cd.mips.cpu_type.mmu_model) { case MMU3K: oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK; oldvaddr = (int32_t) oldvaddr; if (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_V && (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_G || (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK) == (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK) )) cpu->invalidate_translation_caches(cpu, oldvaddr, INVALIDATE_VADDR); break; default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) { oldvaddr = cp->tlbs[index].hi & (ENTRYHI_VPN2_MASK_R10K | ENTRYHI_R_MASK); /* 44 addressable bits: */ if (oldvaddr & 0x80000000000ULL) oldvaddr |= 0x3ffff00000000000ULL; } else if (cpu->is_32bit) { /* MIPS32 etc.: */ oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK; oldvaddr = (int32_t)oldvaddr; } else { /* Assume MMU4K */ oldvaddr = cp->tlbs[index].hi & (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK); /* 40 addressable bits: */ if (oldvaddr & 0x8000000000ULL) oldvaddr |= 0x3fffff0000000000ULL; } { uint64_t mask = cp->tlbs[index].mask; uint64_t pagesize = 0x1000; uint64_t tmp = mask >> 13; while ((tmp & 1)) { tmp >>= 1; pagesize <<= 1; } mask |= 0x1fff; oldvaddr &= ~mask; // printf("pagesize = %016llx mask = %016llx\n", pagesize, mask); if (cp->tlbs[index].lo0 & ENTRYLO_V) for (uint64_t ofs = 0; ofs < pagesize; ofs += 0x1000) cpu->invalidate_translation_caches(cpu, oldvaddr + ofs, INVALIDATE_VADDR); if (cp->tlbs[index].lo1 & ENTRYLO_V) for (uint64_t ofs = 0; ofs < pagesize; ofs += 0x1000) cpu->invalidate_translation_caches(cpu, oldvaddr + ofs + pagesize, INVALIDATE_VADDR); } } #if 0 /* * Check for duplicate entries. (There should not be two mappings * from one virtual address to physical addresses.) * * TODO: Do this for MMU3K and R4100 too. * * TODO: Make this detection more robust. */ if (cpu->cd.mips.cpu_type.mmu_model != MMU3K && cpu->cd.mips.cpu_type.rev != MIPS_R4100) { uint64_t vaddr1, vaddr2; int i; unsigned int asid; vaddr1 = cp->reg[COP0_ENTRYHI] & (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K); asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID; /* Since this is just a warning, it's probably not necessary to use R4000 masks etc. */ for (i=0; inr_of_tlbs; i++) { if (i == index && !randomflag) continue; if (!(cp->tlbs[i].hi & TLB_G) && (cp->tlbs[i].hi & ENTRYHI_ASID) != asid) continue; vaddr2 = cp->tlbs[i].hi & (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K); if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 & ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V))) fatal("\n[ WARNING! tlbw%s to index 0x%02x " "vaddr=0x%llx (asid 0x%02x) is already in" " the TLB (entry 0x%02x) ! ]\n\n", randomflag? "r" : "i", index, (long long)vaddr1, asid, i); } } #endif /* Write the new entry: */ if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) { uint32_t vaddr, paddr; int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0; unsigned char *memblock = NULL; cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI]; cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0]; vaddr = cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK; paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK; memblock = memory_paddr_to_hostaddr(cpu->mem, paddr, 0); /* Invalidate any code translation, if we are writing a Dirty page to the TLB: */ if (wf) { cpu->invalidate_code_translation(cpu, paddr, INVALIDATE_PADDR); } /* Set new last_written_tlb_index hint: */ cpu->cd.mips.last_written_tlb_index = index; if (cp->reg[COP0_STATUS] & MIPS1_ISOL_CACHES) { fatal("Wow! Interesting case; tlbw* while caches" " are isolated. TODO\n"); /* Don't update the translation table in this case... */ exit(1); } /* If we have a memblock (host page) for the physical page, then add a translation for it immediately: */ if (memblock != NULL && cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) cpu->update_translation_table(cpu, vaddr, memblock, wf, paddr); } else { /* R4000 etc.: */ unsigned char *memblock = NULL; int pfn_shift = 12, vpn_shift = 12; int wf0, wf1, mask; uint64_t vaddr0, vaddr1, paddr0, paddr1, ptmp; uint64_t psize; cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK]; cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI]; cp->tlbs[index].lo1 = cp->reg[COP0_ENTRYLO1]; cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0]; wf0 = cp->tlbs[index].lo0 & ENTRYLO_D; wf1 = cp->tlbs[index].lo1 & ENTRYLO_D; mask = cp->reg[COP0_PAGEMASK]; if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) { pfn_shift = 10; mask |= 0x07ff; } else { mask |= 0x1fff; } switch (mask) { case 0x00007ff: if (cp->tlbs[index].lo0 & ENTRYLO_V || cp->tlbs[index].lo1 & ENTRYLO_V) { fatal("1KB pages don't work with dyntrans.\n"); exit(1); } vpn_shift = 10; break; case 0x0001fff: break; case 0x0007fff: vpn_shift = 14; break; case 0x001ffff: vpn_shift = 16; break; case 0x007ffff: vpn_shift = 18; break; case 0x01fffff: vpn_shift = 20; break; case 0x07fffff: vpn_shift = 22; break; case 0x1ffffff: vpn_shift = 24; break; case 0x7ffffff: vpn_shift = 26; break; default:fatal("Unimplemented MASK = 0x%016x\n", mask); exit(1); } pfn_shift = vpn_shift; paddr0 = ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << pfn_shift >> vpn_shift << vpn_shift; paddr1 = ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << pfn_shift >> vpn_shift << vpn_shift; if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) { vaddr0 = cp->tlbs[index].hi & (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K); /* 44 addressable bits: */ if (vaddr0 & 0x80000000000ULL) vaddr0 |= 0x3ffff00000000000ULL; } else if (cpu->is_32bit) { /* MIPS32 etc.: */ vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK; vaddr0 = (int32_t)vaddr0; } else { /* Assume MMU4K */ vaddr0 = cp->tlbs[index].hi & (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK); /* 40 addressable bits: */ if (vaddr0 & 0x8000000000ULL) vaddr0 |= 0x3fffff0000000000ULL; } vaddr1 = vaddr0 | (1 << vpn_shift); g_bit = (cp->reg[COP0_ENTRYLO0] & cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G; if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) { /* NOTE: The VR4131 (and possibly others) don't have a Global bit in entryhi */ cp->tlbs[index].hi &= ~cp->reg[COP0_PAGEMASK]; } else { cp->tlbs[index].lo0 &= ~ENTRYLO_G; cp->tlbs[index].lo1 &= ~ENTRYLO_G; cp->tlbs[index].hi &= ~TLB_G; if (g_bit) cp->tlbs[index].hi |= TLB_G; } /* * Invalidate any code translations, if we are writing Dirty * pages to the TLB: */ psize = 1 << pfn_shift; if (wf0) { for (ptmp = 0; ptmp < psize; ptmp += 0x1000) cpu->invalidate_code_translation(cpu, paddr0 + ptmp, INVALIDATE_PADDR); } if (wf1) { for (ptmp = 0; ptmp < psize; ptmp += 0x1000) cpu->invalidate_code_translation(cpu, paddr1 + ptmp, INVALIDATE_PADDR); } /* * If we have a memblock (host page) for the physical page, * then add a translation for it immediately, to save some * time. (It would otherwise be added later on anyway, * because of a translation miss.) * * NOTE/TODO: This is only for 4KB pages so far. It would * be too expensive to add e.g. 16MB pages like * this. */ if (psize == 0x1000) { memblock = memory_paddr_to_hostaddr(cpu->mem, paddr0, 0); if (memblock != NULL && cp->reg[COP0_ENTRYLO0] & ENTRYLO_V) cpu->update_translation_table(cpu, vaddr0, memblock, wf0, paddr0); memblock = memory_paddr_to_hostaddr(cpu->mem, paddr1, 0); if (memblock != NULL && cp->reg[COP0_ENTRYLO1] & ENTRYLO_V) cpu->update_translation_table(cpu, vaddr1, memblock, wf1, paddr1); } /* Set new last_written_tlb_index hint: */ cpu->cd.mips.last_written_tlb_index = index; } } /* * coproc_eret(): * * Return from exception. (R4000 etc.) */ void coproc_eret(struct cpu *cpu) { if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) { cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC]; cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL; } else { cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC]; cpu->delay_slot = 0; cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL; } cpu->cd.mips.rmw = 0; /* the "LL bit" */ } /* * coproc_function(): * * Execute a coprocessor specific instruction. cp must be != NULL. * Debug trace should be printed for known instructions, if * unassemble_only is non-zero. (This will NOT execute the instruction.) * * TODO: This is a mess and should be restructured (again). */ void coproc_function(struct cpu *cpu, struct mips_coproc *cp, int cpnr, uint32_t function, int unassemble_only, int running) { int co_bit, op, rt, rd, fs, copz; uint64_t tmpvalue; if (cp == NULL) { if (unassemble_only) { debug("cop%i\t0x%08x (coprocessor not available)\n", cpnr, (int)function); return; } fatal("[ pc=0x%016llx cop%i\t0x%08x (coprocessor not " "available)\n", (long long)cpu->pc, cpnr, (int)function); return; } /* No FPU? */ if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) { mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0); return; } /* For quick reference: */ copz = (function >> 21) & 31; rt = (function >> 16) & 31; rd = (function >> 11) & 31; if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MFCz << 21)) || ((function & 0x03e007f8) == (COPz_DMFCz << 21)))) { if (unassemble_only) { debug("%s%i\t%s,", copz==COPz_DMFCz? "dmfc" : "mfc", cpnr, regnames[rt]); if (cpnr == 0) debug("%s", cop0_names[rd]); else debug("r%i", rd); if (function & 7) debug(",%i", (int)(function & 7)); debug("\n"); return; } coproc_register_read(cpu, cpu->cd.mips.coproc[cpnr], rd, &tmpvalue, function & 7); cpu->cd.mips.gpr[rt] = tmpvalue; if (copz == COPz_MFCz) { /* Sign-extend: */ cpu->cd.mips.gpr[rt] &= 0xffffffffULL; if (cpu->cd.mips.gpr[rt] & 0x80000000ULL) cpu->cd.mips.gpr[rt] |= 0xffffffff00000000ULL; } return; } if (cpnr < 2 && (((function & 0x03e007f8) == (COPz_MTCz << 21)) || ((function & 0x03e007f8) == (COPz_DMTCz << 21)))) { if (unassemble_only) { debug("%s%i\t%s,", copz==COPz_DMTCz? "dmtc" : "mtc", cpnr, regnames[rt]); if (cpnr == 0) debug("%s", cop0_names[rd]); else debug("r%i", rd); if (function & 7) debug(",%i", (int)(function & 7)); debug("\n"); return; } tmpvalue = cpu->cd.mips.gpr[rt]; if (copz == COPz_MTCz) { /* Sign-extend: */ tmpvalue &= 0xffffffffULL; if (tmpvalue & 0x80000000ULL) tmpvalue |= 0xffffffff00000000ULL; } coproc_register_write(cpu, cpu->cd.mips.coproc[cpnr], rd, &tmpvalue, copz == COPz_DMTCz, function & 7); return; } if (cpnr <= 1 && (((function & 0x03e007ff) == (COPz_CFCz << 21)) || ((function & 0x03e007ff) == (COPz_CTCz << 21)))) { switch (copz) { case COPz_CFCz: /* Copy from FPU control register */ rt = (function >> 16) & 31; fs = (function >> 11) & 31; if (unassemble_only) { debug("cfc%i\t%s,r%i\n", cpnr, regnames[rt], fs); return; } cpu->cd.mips.gpr[rt] = (int32_t)cp->fcr[fs]; /* TODO: implement delay for gpr[rt] (for MIPS I,II,III only) */ return; case COPz_CTCz: /* Copy to FPU control register */ rt = (function >> 16) & 31; fs = (function >> 11) & 31; if (unassemble_only) { debug("ctc%i\t%s,r%i\n", cpnr, regnames[rt], fs); return; } switch (cpnr) { case 0: /* System coprocessor */ fatal("[ warning: unimplemented ctc%i, " "0x%08x -> ctl reg %i ]\n", cpnr, (int)cpu->cd.mips.gpr[rt], fs); break; case 1: /* FPU */ if (fs == 0) fatal("[ Attempt to write to FPU " "control register 0 (?) ]\n"); else { uint64_t tmp = cpu->cd.mips.gpr[rt]; cp->fcr[fs] = tmp; /* TODO: writing to control register 31 should cause exceptions, depending on status bits! */ switch (fs) { case MIPS_FPU_FCCR: cp->fcr[MIPS_FPU_FCSR] = (cp->fcr[MIPS_FPU_FCSR] & 0x017fffffULL) | ((tmp & 1) << MIPS_FCSR_FCC0_SHIFT) | (((tmp & 0xfe) >> 1) << MIPS_FCSR_FCC1_SHIFT); break; case MIPS_FPU_FCSR: cp->fcr[MIPS_FPU_FCCR] = (cp->fcr[MIPS_FPU_FCCR] & 0xffffff00ULL) | ((tmp >> MIPS_FCSR_FCC0_SHIFT) & 1) | (((tmp >> MIPS_FCSR_FCC1_SHIFT) & 0x7f) << 1); break; default: ; } } break; } /* TODO: implement delay for gpr[rt] (for MIPS I,II,III only) */ return; default: ; } } /* Math (Floating point) coprocessor calls: */ if (cpnr==1) { if (fpu_function(cpu, cp, function, unassemble_only)) return; } /* Ugly R5900 hacks: */ if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { if ((function & 0xfffff) == COP0_EI) { if (unassemble_only) { debug("ei\n"); return; } cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE; return; } if ((function & 0xfffff) == COP0_DI) { if (unassemble_only) { debug("di\n"); return; } cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE; return; } } co_bit = (function >> 25) & 1; /* TLB operations and other things: */ if (cp->coproc_nr == 0) { if (!unassemble_only) { fatal("FATAL INTERNAL ERROR: Should be implemented" " with dyntrans instead.\n"); exit(1); } switch (co_bit) { case 0: if ((function & 0x03e0ffdf) == 0x01606000) { debug("%ci", function & 0x20? 'e' : 'd'); if (rt != MIPS_GPR_ZERO) debug("\t%s", regnames[rt]); debug("\n"); return; } break; case 1: op = (function) & 0xff; switch (op) { case COP0_TLBR: /* Read indexed TLB entry */ debug("tlbr\n"); return; case COP0_TLBWI: /* Write indexed */ case COP0_TLBWR: /* Write random */ if (op == COP0_TLBWI) debug("tlbwi"); else debug("tlbwr"); if (!running) { debug("\n"); return; } debug("\tindex=%08llx", (long long)cp->reg[COP0_INDEX]); debug(", random=%08llx", (long long)cp->reg[COP0_RANDOM]); debug(", mask=%016llx", (long long)cp->reg[COP0_PAGEMASK]); debug(", hi=%016llx", (long long)cp->reg[COP0_ENTRYHI]); debug(", lo0=%016llx", (long long)cp->reg[COP0_ENTRYLO0]); debug(", lo1=%016llx\n", (long long)cp->reg[COP0_ENTRYLO1]); return; case COP0_TLBP: /* Probe TLB for matching entry */ debug("tlbp\n"); return; case COP0_RFE: /* R2000/R3000 only: Return from Exception */ debug("rfe\n"); return; case COP0_ERET: /* R4000: Return from exception */ debug("eret\n"); return; case COP0_DERET: debug("deret\n"); return; case COP0_WAIT: { int code = (function >> 6) & 0x7ffff; debug("wait"); if (code > 0) debug("\t0x%x", code); debug("\n"); } return; case COP0_STANDBY: debug("standby\n"); return; case COP0_SUSPEND: debug("suspend\n"); return; case COP0_HIBERNATE: debug("hibernate\n"); return; default: ; } break; } } /* TODO: coprocessor R2020 on DECstation? */ if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x0100ffff) { if (unassemble_only) { debug("decstation_r2020_writeback\n"); return; } /* TODO */ return; } if (unassemble_only) { debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function); return; } fatal("cpu%i: UNIMPLEMENTED coproc%i function %08" PRIx32" " "(pc = %016" PRIx64")\n", cpu->cpu_id, cp->coproc_nr, (uint32_t)function, cpu->pc); mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cp->coproc_nr, 0, 0, 0); } gxemul-0.6.1/src/cpus/cpu.cc000644 001750 001750 00000034043 13402411502 016070 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Common routines for CPU emulation. (Not specific to any CPU type.) */ #include #include #include #include #include #include "cpu.h" #include "machine.h" #include "memory.h" #include "settings.h" #include "timer.h" extern size_t dyntrans_cache_size; static struct cpu_family *first_cpu_family = NULL; /* * cpu_new(): * * Create a new cpu object. Each family is tried in sequence until a * CPU family recognizes the cpu_type_name. * * If there was no match, NULL is returned. Otherwise, a pointer to an * initialized cpu struct is returned. */ struct cpu *cpu_new(struct memory *mem, struct machine *machine, int cpu_id, char *name) { struct cpu *cpu; struct cpu_family *fp; char *cpu_type_name; char tmpstr[30]; if (name == NULL) { fprintf(stderr, "cpu_new(): cpu name = NULL?\n"); exit(1); } CHECK_ALLOCATION(cpu_type_name = strdup(name)); cpu = (struct cpu *) zeroed_alloc(sizeof(struct cpu)); CHECK_ALLOCATION(cpu->path = (char *) malloc(strlen(machine->path) + 15)); snprintf(cpu->path, strlen(machine->path) + 15, "%s.cpu[%i]", machine->path, cpu_id); cpu->memory_rw = NULL; cpu->name = cpu_type_name; cpu->mem = mem; cpu->machine = machine; cpu->cpu_id = cpu_id; cpu->byte_order = EMUL_UNDEFINED_ENDIAN; cpu->running = 0; /* Create settings, and attach to the machine: */ cpu->settings = settings_new(); snprintf(tmpstr, sizeof(tmpstr), "cpu[%i]", cpu_id); settings_add(machine->settings, tmpstr, 1, SETTINGS_TYPE_SUBSETTINGS, 0, cpu->settings); settings_add(cpu->settings, "name", 0, SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING, (void *) &cpu->name); settings_add(cpu->settings, "running", 0, SETTINGS_TYPE_UINT8, SETTINGS_FORMAT_YESNO, (void *) &cpu->running); cpu_create_or_reset_tc(cpu); fp = first_cpu_family; while (fp != NULL) { if (fp->cpu_new != NULL) { if (fp->cpu_new(cpu, mem, machine, cpu_id, cpu_type_name)) { /* Sanity check: */ if (cpu->memory_rw == NULL) { fatal("\ncpu_new(): memory_rw == " "NULL\n"); exit(1); } break; } } fp = fp->next; } if (fp == NULL) { fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name); return NULL; } fp->init_tables(cpu); if (cpu->byte_order == EMUL_UNDEFINED_ENDIAN) { fatal("\ncpu_new(): Internal bug: Endianness not set.\n"); exit(1); } return cpu; } /* * cpu_destroy(): * * Destroy a cpu object. */ void cpu_destroy(struct cpu *cpu) { settings_remove(cpu->settings, "name"); settings_remove(cpu->settings, "running"); /* Remove any remaining level-1 settings: */ settings_remove_all(cpu->settings); settings_destroy(cpu->settings); if (cpu->path != NULL) free(cpu->path); /* TODO: This assumes that zeroed_alloc() actually succeeded with using mmap(), and not malloc()! */ munmap((void *)cpu, sizeof(struct cpu)); } /* * cpu_tlbdump(): * * Called from the debugger to dump the TLB in a readable format. * x is the cpu number to dump, or -1 to dump all CPUs. * * If rawflag is nonzero, then the TLB contents isn't formated nicely, * just dumped. */ void cpu_tlbdump(struct machine *m, int x, int rawflag) { if (m->cpu_family == NULL || m->cpu_family->tlbdump == NULL) fatal("cpu_tlbdump(): NULL\n"); else m->cpu_family->tlbdump(m, x, rawflag); } /* * cpu_disassemble_instr(): * * Convert an instruction word into human readable format, for instruction * tracing. */ int cpu_disassemble_instr(struct machine *m, struct cpu *cpu, unsigned char *instr, int running, uint64_t addr) { if (m->cpu_family == NULL || m->cpu_family->disassemble_instr == NULL) { fatal("cpu_disassemble_instr(): NULL\n"); return 0; } else return m->cpu_family->disassemble_instr(cpu, instr, running, addr); } /* * cpu_register_dump(): * * Dump cpu registers in a relatively readable format. * * gprs: set to non-zero to dump GPRs. (CPU dependent.) * coprocs: set bit 0..x to dump registers in coproc 0..x. (CPU dependent.) */ void cpu_register_dump(struct machine *m, struct cpu *cpu, int gprs, int coprocs) { if (m->cpu_family == NULL || m->cpu_family->register_dump == NULL) fatal("cpu_register_dump(): NULL\n"); else m->cpu_family->register_dump(cpu, gprs, coprocs); } /* * cpu_functioncall_trace(): * * This function should be called if machine->show_trace_tree is enabled, and * a function call is being made. f contains the address of the function. */ void cpu_functioncall_trace(struct cpu *cpu, uint64_t f) { int show_symbolic_function_name = 1; int i, n_args = -1; char *symbol; uint64_t offset; /* Special hack for M88K userspace: */ if (cpu->machine->arch == ARCH_M88K && !(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) show_symbolic_function_name = 0; if (cpu->machine->ncpus > 1) fatal("cpu%i:\t", cpu->cpu_id); if (cpu->trace_tree_depth > 100) cpu->trace_tree_depth = 100; for (i=0; itrace_tree_depth; i++) fatal(" "); cpu->trace_tree_depth ++; fatal("<"); symbol = get_symbol_name_and_n_args(&cpu->machine->symbol_context, f, &offset, &n_args); if (symbol != NULL && show_symbolic_function_name && offset == 0) fatal("%s", symbol); else { if (cpu->is_32bit) fatal("0x%" PRIx32, (uint32_t) f); else fatal("0x%" PRIx64, (uint64_t) f); } fatal("("); if (cpu->machine->cpu_family->functioncall_trace != NULL) cpu->machine->cpu_family->functioncall_trace(cpu, n_args); fatal(")>\n"); #ifdef PRINT_MEMORY_CHECKSUM /* Temporary hack for finding bugs: */ fatal("call chksum=%016" PRIx64"\n", memory_checksum(cpu->mem)); #endif } /* * cpu_functioncall_trace_return(): * * This function should be called if machine->show_trace_tree is enabled, and * a function is being returned from. * * TODO: Print return value? This could be implemented similar to the * cpu->functioncall_trace function call above. */ void cpu_functioncall_trace_return(struct cpu *cpu) { cpu->trace_tree_depth --; if (cpu->trace_tree_depth < 0) cpu->trace_tree_depth = 0; } /* * cpu_create_or_reset_tc(): * * Create the translation cache in memory (ie allocate memory for it), if * necessary, and then reset it to an initial state. */ void cpu_create_or_reset_tc(struct cpu *cpu) { size_t s = dyntrans_cache_size + DYNTRANS_CACHE_MARGIN; if (cpu->translation_cache == NULL) cpu->translation_cache = (unsigned char *) zeroed_alloc(s); /* Create an empty table at the beginning of the translation cache: */ memset(cpu->translation_cache, 0, sizeof(uint32_t) * N_BASE_TABLE_ENTRIES); cpu->translation_cache_cur_ofs = N_BASE_TABLE_ENTRIES * sizeof(uint32_t); /* * There might be other translation pointers that still point to * within the translation_cache region. Let's invalidate those too: */ if (cpu->invalidate_code_translation != NULL) cpu->invalidate_code_translation(cpu, 0, INVALIDATE_ALL); } /* * cpu_dumpinfo(): * * Dumps info about a CPU using debug(). "cpu0: CPUNAME, running" (or similar) * is outputed, and it is up to CPU dependent code to complete the line. */ void cpu_dumpinfo(struct machine *m, struct cpu *cpu) { debug("cpu%i: %s, %s", cpu->cpu_id, cpu->name, cpu->running? "running" : "stopped"); if (m->cpu_family == NULL || m->cpu_family->dumpinfo == NULL) fatal("cpu_dumpinfo(): NULL\n"); else m->cpu_family->dumpinfo(cpu); } /* * cpu_list_available_types(): * * Print a list of available CPU types for each cpu family. */ void cpu_list_available_types(void) { struct cpu_family *fp; int iadd = DEBUG_INDENTATION; fp = first_cpu_family; if (fp == NULL) { debug("No CPUs defined!\n"); return; } while (fp != NULL) { debug("%s:\n", fp->name); debug_indentation(iadd); if (fp->list_available_types != NULL) fp->list_available_types(); else debug("(internal error: list_available_types" " = NULL)\n"); debug_indentation(-iadd); fp = fp->next; } } /* * cpu_run_deinit(): * * Shuts down all CPUs in a machine when ending a simulation. (This function * should only need to be called once for each machine.) */ void cpu_run_deinit(struct machine *machine) { int te; /* * Two last ticks of every hardware device. This will allow e.g. * framebuffers to draw the last updates to the screen before halting. * * TODO: This should be refactored when redesigning the mainbus * concepts! */ for (te=0; tetick_functions.n_entries; te++) { machine->tick_functions.f[te](machine->cpus[0], machine->tick_functions.extra[te]); machine->tick_functions.f[te](machine->cpus[0], machine->tick_functions.extra[te]); } if (machine->show_nr_of_instructions) cpu_show_cycles(machine, 1); fflush(stdout); } /* * cpu_show_cycles(): * * If show_nr_of_instructions is on, then print a line to stdout about how * many instructions/cycles have been executed so far. */ void cpu_show_cycles(struct machine *machine, int forced) { uint64_t offset, pc; char *symbol; int64_t mseconds, ninstrs, is, avg; struct timeval tv; struct cpu *cpu = machine->cpus[machine->bootstrap_cpu]; static int64_t mseconds_last = 0; static int64_t ninstrs_last = -1; pc = cpu->pc; gettimeofday(&tv, NULL); mseconds = (tv.tv_sec - cpu->starttime.tv_sec) * 1000 + (tv.tv_usec - cpu->starttime.tv_usec) / 1000; if (mseconds == 0) mseconds = 1; if (mseconds - mseconds_last == 0) mseconds ++; ninstrs = cpu->ninstrs_since_gettimeofday; /* RETURN here, unless show_nr_of_instructions (-N) is turned on: */ if (!machine->show_nr_of_instructions && !forced) goto do_return; printf("[ %" PRIi64" instrs", (int64_t) cpu->ninstrs); /* Instructions per second, and average so far: */ is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last); avg = (long long)1000 * ninstrs / mseconds; if (is < 0) is = 0; if (avg < 0) avg = 0; if (cpu->has_been_idling) { printf("; idling"); cpu->has_been_idling = 0; } else printf("; i/s=%" PRIi64" avg=%" PRIi64, is, avg); symbol = get_symbol_name(&machine->symbol_context, pc, &offset); if (machine->ncpus == 1) { if (cpu->is_32bit) printf("; pc=0x%08" PRIx32, (uint32_t) pc); else printf("; pc=0x%016" PRIx64, (uint64_t) pc); } /* Special hack for M88K userland: (Don't show symbols.) */ if (cpu->machine->arch == ARCH_M88K && !(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE)) symbol = NULL; if (symbol != NULL) printf(" <%s>", symbol); printf(" ]\n"); do_return: ninstrs_last = ninstrs; mseconds_last = mseconds; } /* * cpu_run_init(): * * Prepare to run instructions on all CPUs in this machine. (This function * should only need to be called once for each machine.) */ void cpu_run_init(struct machine *machine) { int i; if (machine->ncpus == 0) { printf("Machine with no CPUs? TODO.\n"); exit(1); } for (i=0; incpus; i++) { struct cpu *cpu = machine->cpus[i]; cpu->ninstrs_flush = 0; cpu->ninstrs = 0; cpu->ninstrs_show = 0; /* For performance measurement: */ gettimeofday(&cpu->starttime, NULL); cpu->ninstrs_since_gettimeofday = 0; } } /* * add_cpu_family(): * * Allocates a cpu_family struct and calls an init function for the * family to fill in reasonable data and pointers. */ static void add_cpu_family(int (*family_init)(struct cpu_family *), int arch) { struct cpu_family *fp, *tmp; int res; CHECK_ALLOCATION(fp = (struct cpu_family *) malloc(sizeof(struct cpu_family))); memset(fp, 0, sizeof(struct cpu_family)); /* * family_init() returns 1 if the struct has been filled with * valid data, 0 if suppor for the cpu family isn't compiled * into the emulator. */ res = family_init(fp); if (!res) { free(fp); return; } fp->arch = arch; fp->next = NULL; /* Add last in family chain: */ tmp = first_cpu_family; if (tmp == NULL) { first_cpu_family = fp; } else { while (tmp->next != NULL) tmp = tmp->next; tmp->next = fp; } } /* * cpu_family_ptr_by_number(): * * Returns a pointer to a CPU family based on the ARCH_* integers. */ struct cpu_family *cpu_family_ptr_by_number(int arch) { struct cpu_family *fp; fp = first_cpu_family; /* YUCK! This is too hardcoded! TODO */ while (fp != NULL) { if (arch == fp->arch) return fp; fp = fp->next; } return NULL; } /* * cpu_init(): * * Should be called before any other cpu_*() function. * * This function calls add_cpu_family() for each processor architecture. * ADD_ALL_CPU_FAMILIES is defined in the config.h file generated by the * configure script. */ void cpu_init(void) { ADD_ALL_CPU_FAMILIES; } gxemul-0.6.1/src/cpus/cpu_ppc_instr.cc000644 001750 001750 00000265071 13402411502 020160 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * POWER/PowerPC instructions. * * Individual functions should keep track of cpu->n_translated_instrs. * (If no instruction was executed, then it should be decreased. If, say, 4 * instructions were combined into one function and executed, then it should * be increased by 3.) */ #include "float_emul.h" #define DOT0(n) X(n ## _dot) { instr(n)(cpu,ic); \ update_cr0(cpu, reg(ic->arg[0])); } #define DOT1(n) X(n ## _dot) { instr(n)(cpu,ic); \ update_cr0(cpu, reg(ic->arg[1])); } #define DOT2(n) X(n ## _dot) { instr(n)(cpu,ic); \ update_cr0(cpu, reg(ic->arg[2])); } #ifndef CHECK_FOR_FPU_EXCEPTION #define CHECK_FOR_FPU_EXCEPTION { if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { \ /* Synchronize the PC, and cause an FPU exception: */ \ uint64_t low_pc = ((size_t)ic - \ (size_t)cpu->cd.ppc.cur_ic_page) \ / sizeof(struct ppc_instr_call); \ cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << \ PPC_INSTR_ALIGNMENT_SHIFT)) + (low_pc << \ PPC_INSTR_ALIGNMENT_SHIFT); \ ppc_exception(cpu, PPC_EXCEPTION_FPU); \ return; } } #endif /* * nop: Do nothing. */ X(nop) { } /* * invalid: To catch bugs. */ X(invalid) { fatal("PPC: invalid(): INTERNAL ERROR\n"); exit(1); } /* * addi: Add immediate. * * arg[0] = pointer to source uint64_t * arg[1] = immediate value (int32_t or larger) * arg[2] = pointer to destination uint64_t */ X(addi) { reg(ic->arg[2]) = reg(ic->arg[0]) + (int32_t)ic->arg[1]; } X(li) { reg(ic->arg[2]) = (int32_t)ic->arg[1]; } X(li_0) { reg(ic->arg[2]) = 0; } /* * andi_dot: AND immediate, update CR. * * arg[0] = pointer to source uint64_t * arg[1] = immediate value (uint32_t) * arg[2] = pointer to destination uint64_t */ X(andi_dot) { MODE_uint_t tmp = reg(ic->arg[0]) & (uint32_t)ic->arg[1]; reg(ic->arg[2]) = tmp; update_cr0(cpu, tmp); } /* * addic: Add immediate, Carry. * * arg[0] = pointer to source register * arg[1] = immediate value (int32_t or larger) * arg[2] = pointer to destination register */ X(addic) { /* TODO/NOTE: Only for 32-bit mode, so far! */ uint64_t tmp = (uint32_t)reg(ic->arg[0]); uint64_t tmp2 = tmp; cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; tmp2 += (uint32_t)ic->arg[1]; if ((tmp2 >> 32) != (tmp >> 32)) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp2; } /* * subfic: Subtract from immediate, Carry. * * arg[0] = pointer to source uint64_t * arg[1] = immediate value (int32_t or larger) * arg[2] = pointer to destination uint64_t */ X(subfic) { MODE_uint_t tmp = (int64_t)(int32_t)ic->arg[1]; cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (tmp >= reg(ic->arg[0])) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = tmp - reg(ic->arg[0]); } /* * addic_dot: Add immediate, Carry. * * arg[0] = pointer to source uint64_t * arg[1] = immediate value (int32_t or larger) * arg[2] = pointer to destination uint64_t */ X(addic_dot) { /* TODO/NOTE: Only for 32-bit mode, so far! */ uint64_t tmp = (uint32_t)reg(ic->arg[0]); uint64_t tmp2 = tmp; cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; tmp2 += (uint32_t)ic->arg[1]; if ((tmp2 >> 32) != (tmp >> 32)) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp2; update_cr0(cpu, (uint32_t)tmp2); } /* * bclr: Branch Conditional to Link Register * * arg[0] = bo * arg[1] = 31 - bi * arg[2] = bh */ X(bclr) { unsigned int bo = ic->arg[0], bi31m = ic->arg[1]; int ctr_ok, cond_ok; uint64_t old_pc = cpu->pc; MODE_uint_t tmp, addr = cpu->cd.ppc.spr[SPR_LR]; if (!(bo & 4)) cpu->cd.ppc.spr[SPR_CTR] --; ctr_ok = (bo >> 2) & 1; tmp = cpu->cd.ppc.spr[SPR_CTR]; ctr_ok |= ( (tmp == 0) == ((bo >> 1) & 1) ); cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> bi31m) & 1) ); if (ctr_ok && cond_ok) { uint64_t mask_within_page = ((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT) | ((1 << PPC_INSTR_ALIGNMENT_SHIFT) - 1); cpu->pc = addr & ~((1 << PPC_INSTR_ALIGNMENT_SHIFT) - 1); /* TODO: trace in separate (duplicate) function? */ if (cpu->machine->show_trace_tree) cpu_functioncall_trace_return(cpu); if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) { cpu->cd.ppc.next_ic = cpu->cd.ppc.cur_ic_page + ((cpu->pc & mask_within_page) >> PPC_INSTR_ALIGNMENT_SHIFT); } else { /* Find the new physical page and update pointers: */ quick_pc_to_pointers(cpu); } } } X(bclr_20) { cpu->pc = cpu->cd.ppc.spr[SPR_LR]; quick_pc_to_pointers(cpu); } X(bclr_l) { uint64_t low_pc, old_pc = cpu->pc; unsigned int bo = ic->arg[0], bi31m = ic->arg[1] /* ,bh = ic->arg[2]*/; int ctr_ok, cond_ok; MODE_uint_t tmp, addr = cpu->cd.ppc.spr[SPR_LR]; if (!(bo & 4)) cpu->cd.ppc.spr[SPR_CTR] --; ctr_ok = (bo >> 2) & 1; tmp = cpu->cd.ppc.spr[SPR_CTR]; ctr_ok |= ( (tmp == 0) == ((bo >> 1) & 1) ); cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> bi31m) & 1) ); /* Calculate return PC: */ low_pc = ((size_t)ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->cd.ppc.spr[SPR_LR] += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); if (ctr_ok && cond_ok) { uint64_t mask_within_page = ((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT) | ((1 << PPC_INSTR_ALIGNMENT_SHIFT) - 1); cpu->pc = addr & ~((1 << PPC_INSTR_ALIGNMENT_SHIFT) - 1); /* TODO: trace in separate (duplicate) function? */ if (cpu->machine->show_trace_tree) cpu_functioncall_trace_return(cpu); if (cpu->machine->show_trace_tree) cpu_functioncall_trace(cpu, cpu->pc); if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) { cpu->cd.ppc.next_ic = cpu->cd.ppc.cur_ic_page + ((cpu->pc & mask_within_page) >> PPC_INSTR_ALIGNMENT_SHIFT); } else { /* Find the new physical page and update pointers: */ quick_pc_to_pointers(cpu); } } } /* * bcctr: Branch Conditional to Count register * * arg[0] = bo * arg[1] = 31 - bi * arg[2] = bh */ X(bcctr) { unsigned int bo = ic->arg[0], bi31m = ic->arg[1]; uint64_t old_pc = cpu->pc; MODE_uint_t addr = cpu->cd.ppc.spr[SPR_CTR]; int cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> bi31m) & 1) ); if (cond_ok) { uint64_t mask_within_page = ((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT) | ((1 << PPC_INSTR_ALIGNMENT_SHIFT) - 1); cpu->pc = addr & ~((1 << PPC_INSTR_ALIGNMENT_SHIFT) - 1); /* TODO: trace in separate (duplicate) function? */ if (cpu->machine->show_trace_tree) cpu_functioncall_trace_return(cpu); if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) { cpu->cd.ppc.next_ic = cpu->cd.ppc.cur_ic_page + ((cpu->pc & mask_within_page) >> PPC_INSTR_ALIGNMENT_SHIFT); } else { /* Find the new physical page and update pointers: */ quick_pc_to_pointers(cpu); } } } X(bcctr_l) { uint64_t low_pc, old_pc = cpu->pc; unsigned int bo = ic->arg[0], bi31m = ic->arg[1] /*,bh = ic->arg[2] */; MODE_uint_t addr = cpu->cd.ppc.spr[SPR_CTR]; int cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> bi31m) & 1) ); /* Calculate return PC: */ low_pc = ((size_t)ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->cd.ppc.spr[SPR_LR] += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); if (cond_ok) { uint64_t mask_within_page = ((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT) | ((1 << PPC_INSTR_ALIGNMENT_SHIFT) - 1); cpu->pc = addr & ~((1 << PPC_INSTR_ALIGNMENT_SHIFT) - 1); /* TODO: trace in separate (duplicate) function? */ if (cpu->machine->show_trace_tree) cpu_functioncall_trace(cpu, cpu->pc); if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) { cpu->cd.ppc.next_ic = cpu->cd.ppc.cur_ic_page + ((cpu->pc & mask_within_page) >> PPC_INSTR_ALIGNMENT_SHIFT); } else { /* Find the new physical page and update pointers: */ quick_pc_to_pointers(cpu); } } } /* * b: Branch (to a different translated page) * * arg[0] = relative offset (as an int32_t) from start of page */ X(b) { cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->pc += (int32_t)ic->arg[0]; /* Find the new physical page and update the translation pointers: */ quick_pc_to_pointers(cpu); } X(ba) { cpu->pc = (int32_t)ic->arg[0]; quick_pc_to_pointers(cpu); } /* * bc: Branch Conditional (to a different translated page) * * arg[0] = relative offset (as an int32_t) from start of page * arg[1] = bo * arg[2] = 31-bi */ X(bc) { MODE_uint_t tmp; unsigned int ctr_ok, cond_ok, bi31m = ic->arg[2], bo = ic->arg[1]; if (!(bo & 4)) cpu->cd.ppc.spr[SPR_CTR] --; ctr_ok = (bo >> 2) & 1; tmp = cpu->cd.ppc.spr[SPR_CTR]; ctr_ok |= ( (tmp == 0) == ((bo >> 1) & 1) ); cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> (bi31m)) & 1) ); if (ctr_ok && cond_ok) instr(b)(cpu,ic); } X(bcl) { MODE_uint_t tmp; unsigned int ctr_ok, cond_ok, bi31m = ic->arg[2], bo = ic->arg[1]; int low_pc; /* Calculate LR: */ low_pc = ((size_t)ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->cd.ppc.spr[SPR_LR] += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); if (!(bo & 4)) cpu->cd.ppc.spr[SPR_CTR] --; ctr_ok = (bo >> 2) & 1; tmp = cpu->cd.ppc.spr[SPR_CTR]; ctr_ok |= ( (tmp == 0) == ((bo >> 1) & 1) ); cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> bi31m) & 1) ); if (ctr_ok && cond_ok) instr(b)(cpu,ic); } /* * b_samepage: Branch (to within the same translated page) * * arg[0] = pointer to new ppc_instr_call */ X(b_samepage) { cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; } /* * bc_samepage: Branch Conditional (to within the same page) * * arg[0] = new ic ptr * arg[1] = bo * arg[2] = 31-bi */ X(bc_samepage) { MODE_uint_t tmp; unsigned int ctr_ok, cond_ok, bi31m = ic->arg[2], bo = ic->arg[1]; if (!(bo & 4)) cpu->cd.ppc.spr[SPR_CTR] --; ctr_ok = (bo >> 2) & 1; tmp = cpu->cd.ppc.spr[SPR_CTR]; ctr_ok |= ( (tmp == 0) == ((bo >> 1) & 1) ); cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> bi31m) & 1) ); if (ctr_ok && cond_ok) cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; } X(bc_samepage_simple0) { int bi31m = ic->arg[2]; if (!((cpu->cd.ppc.cr >> bi31m) & 1)) cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; } X(bc_samepage_simple1) { int bi31m = ic->arg[2]; if ((cpu->cd.ppc.cr >> bi31m) & 1) cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; } X(bcl_samepage) { MODE_uint_t tmp; unsigned int ctr_ok, cond_ok, bi31m = ic->arg[2], bo = ic->arg[1]; int low_pc; /* Calculate LR: */ low_pc = ((size_t)ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->cd.ppc.spr[SPR_LR] += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); if (!(bo & 4)) cpu->cd.ppc.spr[SPR_CTR] --; ctr_ok = (bo >> 2) & 1; tmp = cpu->cd.ppc.spr[SPR_CTR]; ctr_ok |= ( (tmp == 0) == ((bo >> 1) & 1) ); cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> bi31m) & 1) ); if (ctr_ok && cond_ok) cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; } /* * bl: Branch and Link (to a different translated page) * * arg[0] = relative offset (as an int32_t) from start of page * arg[1] = lr offset (relative to start of current page) */ X(bl) { /* Calculate LR and new PC: */ cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->cd.ppc.spr[SPR_LR] = cpu->pc + ic->arg[1]; cpu->pc += (int32_t)ic->arg[0]; /* Find the new physical page and update the translation pointers: */ quick_pc_to_pointers(cpu); } X(bla) { /* Calculate LR: */ cpu->cd.ppc.spr[SPR_LR] = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT)) + ic->arg[1]; cpu->pc = (int32_t)ic->arg[0]; quick_pc_to_pointers(cpu); } /* * bl_trace: Branch and Link (to a different translated page) (with trace) * * arg[0] = relative offset (as an int32_t) from start of page * arg[1] = lr offset (relative to start of current page) */ X(bl_trace) { /* Calculate LR: */ cpu->cd.ppc.spr[SPR_LR] = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT)) + ic->arg[1]; /* Calculate new PC from start of page + arg[0] */ cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->pc += (int32_t)ic->arg[0]; cpu_functioncall_trace(cpu, cpu->pc); /* Find the new physical page and update the translation pointers: */ quick_pc_to_pointers(cpu); } X(bla_trace) { /* Calculate LR: */ cpu->cd.ppc.spr[SPR_LR] = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT)) + ic->arg[1]; cpu->pc = (int32_t)ic->arg[0]; cpu_functioncall_trace(cpu, cpu->pc); quick_pc_to_pointers(cpu); } /* * bl_samepage: Branch and Link (to within the same translated page) * * arg[0] = pointer to new ppc_instr_call * arg[1] = lr offset (relative to start of current page) */ X(bl_samepage) { /* Calculate LR: */ cpu->cd.ppc.spr[SPR_LR] = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT)) + ic->arg[1]; cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; } /* * bl_samepage_trace: Branch and Link (to within the same translated page) * * arg[0] = pointer to new ppc_instr_call * arg[1] = lr offset (relative to start of current page) */ X(bl_samepage_trace) { uint32_t low_pc; /* Calculate LR: */ cpu->cd.ppc.spr[SPR_LR] = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT)) + ic->arg[1]; cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; /* Calculate new PC (for the trace) */ low_pc = ((size_t)cpu->cd.ppc.next_ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); cpu_functioncall_trace(cpu, cpu->pc); } /* * cntlzw: Count leading zeroes (32-bit word). * * arg[0] = ptr to rs * arg[1] = ptr to ra */ X(cntlzw) { uint32_t tmp = reg(ic->arg[0]); int i; for (i=0; i<32; i++) { if (tmp & 0x80000000) break; tmp <<= 1; } reg(ic->arg[1]) = i; } /* * cmpd: Compare Doubleword * * arg[0] = ptr to ra * arg[1] = ptr to rb * arg[2] = 28 - 4*bf */ X(cmpd) { int64_t tmp = reg(ic->arg[0]), tmp2 = reg(ic->arg[1]); int bf_shift = ic->arg[2], c; if (tmp < tmp2) c = 8; else if (tmp > tmp2) c = 4; else c = 2; /* SO bit, copied from XER */ c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); cpu->cd.ppc.cr &= ~(0xf << bf_shift); cpu->cd.ppc.cr |= (c << bf_shift); } /* * cmpld: Compare Doubleword, unsigned * * arg[0] = ptr to ra * arg[1] = ptr to rb * arg[2] = 28 - 4*bf */ X(cmpld) { uint64_t tmp = reg(ic->arg[0]), tmp2 = reg(ic->arg[1]); int bf_shift = ic->arg[2], c; if (tmp < tmp2) c = 8; else if (tmp > tmp2) c = 4; else c = 2; /* SO bit, copied from XER */ c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); cpu->cd.ppc.cr &= ~(0xf << bf_shift); cpu->cd.ppc.cr |= (c << bf_shift); } /* * cmpdi: Compare Doubleword immediate * * arg[0] = ptr to ra * arg[1] = int32_t imm * arg[2] = 28 - 4*bf */ X(cmpdi) { int64_t tmp = reg(ic->arg[0]), imm = (int32_t)ic->arg[1]; int bf_shift = ic->arg[2], c; if (tmp < imm) c = 8; else if (tmp > imm) c = 4; else c = 2; /* SO bit, copied from XER */ c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); cpu->cd.ppc.cr &= ~(0xf << bf_shift); cpu->cd.ppc.cr |= (c << bf_shift); } /* * cmpldi: Compare Doubleword immediate, logical * * arg[0] = ptr to ra * arg[1] = int32_t imm * arg[2] = 28 - 4*bf */ X(cmpldi) { uint64_t tmp = reg(ic->arg[0]), imm = (uint32_t)ic->arg[1]; int bf_shift = ic->arg[2], c; if (tmp < imm) c = 8; else if (tmp > imm) c = 4; else c = 2; /* SO bit, copied from XER */ c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); cpu->cd.ppc.cr &= ~(0xf << bf_shift); cpu->cd.ppc.cr |= (c << bf_shift); } /* * cmpw: Compare Word * * arg[0] = ptr to ra * arg[1] = ptr to rb * arg[2] = 28 - 4*bf */ X(cmpw) { int32_t tmp = reg(ic->arg[0]), tmp2 = reg(ic->arg[1]); int bf_shift = ic->arg[2], c; if (tmp < tmp2) c = 8; else if (tmp > tmp2) c = 4; else c = 2; /* SO bit, copied from XER */ c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); cpu->cd.ppc.cr &= ~(0xf << bf_shift); cpu->cd.ppc.cr |= (c << bf_shift); } X(cmpw_cr0) { /* arg[2] is assumed to be 28 */ int32_t tmp = reg(ic->arg[0]), tmp2 = reg(ic->arg[1]); cpu->cd.ppc.cr &= ~(0xf0000000); if (tmp < tmp2) cpu->cd.ppc.cr |= 0x80000000; else if (tmp > tmp2) cpu->cd.ppc.cr |= 0x40000000; else cpu->cd.ppc.cr |= 0x20000000; cpu->cd.ppc.cr |= ((cpu->cd.ppc.spr[SPR_XER] >> 3) & 0x10000000); } /* * cmplw: Compare Word, unsigned * * arg[0] = ptr to ra * arg[1] = ptr to rb * arg[2] = 28 - 4*bf */ X(cmplw) { uint32_t tmp = reg(ic->arg[0]), tmp2 = reg(ic->arg[1]); int bf_shift = ic->arg[2], c; if (tmp < tmp2) c = 8; else if (tmp > tmp2) c = 4; else c = 2; /* SO bit, copied from XER */ c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); cpu->cd.ppc.cr &= ~(0xf << bf_shift); cpu->cd.ppc.cr |= (c << bf_shift); } /* * cmpwi: Compare Word immediate * * arg[0] = ptr to ra * arg[1] = int32_t imm * arg[2] = 28 - 4*bf */ X(cmpwi) { int32_t tmp = reg(ic->arg[0]), imm = ic->arg[1]; int bf_shift = ic->arg[2], c; if (tmp < imm) c = 8; else if (tmp > imm) c = 4; else c = 2; /* SO bit, copied from XER */ c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); cpu->cd.ppc.cr &= ~(0xf << bf_shift); cpu->cd.ppc.cr |= (c << bf_shift); } X(cmpwi_cr0) { /* arg[2] is assumed to be 28 */ int32_t tmp = reg(ic->arg[0]), imm = ic->arg[1]; cpu->cd.ppc.cr &= ~(0xf0000000); if (tmp < imm) cpu->cd.ppc.cr |= 0x80000000; else if (tmp > imm) cpu->cd.ppc.cr |= 0x40000000; else cpu->cd.ppc.cr |= 0x20000000; cpu->cd.ppc.cr |= ((cpu->cd.ppc.spr[SPR_XER] >> 3) & 0x10000000); } /* * cmplwi: Compare Word immediate, logical * * arg[0] = ptr to ra * arg[1] = int32_t imm * arg[2] = 28 - 4*bf */ X(cmplwi) { uint32_t tmp = reg(ic->arg[0]), imm = ic->arg[1]; int bf_shift = ic->arg[2], c; if (tmp < imm) c = 8; else if (tmp > imm) c = 4; else c = 2; /* SO bit, copied from XER */ c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); cpu->cd.ppc.cr &= ~(0xf << bf_shift); cpu->cd.ppc.cr |= (c << bf_shift); } /* * dcbz: Data-Cache Block Zero * * arg[0] = ptr to ra (or zero) * arg[1] = ptr to rb */ X(dcbz) { MODE_uint_t addr = reg(ic->arg[0]) + reg(ic->arg[1]); unsigned char cacheline[128]; size_t cacheline_size = 1 << cpu->cd.ppc.cpu_type.dlinesize; size_t cleared = 0; /* Synchronize the PC first: */ cpu->pc = (cpu->pc & ~0xfff) + ic->arg[2]; addr &= ~(cacheline_size - 1); memset(cacheline, 0, sizeof(cacheline)); while (cleared < cacheline_size) { int to_clear = cacheline_size < sizeof(cacheline)? cacheline_size : sizeof(cacheline); #ifdef MODE32 unsigned char *page = cpu->cd.ppc.host_store[addr >> 12]; if (page != NULL) { memset(page + (addr & 0xfff), 0, to_clear); } else #endif if (cpu->memory_rw(cpu, cpu->mem, addr, cacheline, to_clear, MEM_WRITE, CACHE_DATA) != MEMORY_ACCESS_OK) { /* exception */ return; } cleared += to_clear; addr += to_clear; } } /* * mtfsf: Copy FPR into the FPSCR. * * arg[0] = ptr to frb * arg[1] = mask */ X(mtfsf) { CHECK_FOR_FPU_EXCEPTION; cpu->cd.ppc.fpscr &= ~ic->arg[1]; cpu->cd.ppc.fpscr |= (ic->arg[1] & (*(uint64_t *)ic->arg[0])); } /* * mffs: Copy FPSCR into a FPR. * * arg[0] = ptr to frt */ X(mffs) { CHECK_FOR_FPU_EXCEPTION; (*(uint64_t *)ic->arg[0]) = cpu->cd.ppc.fpscr; } /* * fmr: Floating-point Move * * arg[0] = ptr to frb * arg[1] = ptr to frt */ X(fmr) { /* * This works like a normal register to register copy, but * a) it can cause an FPU exception, and b) the move is always * 64-bit, even when running in 32-bit mode. */ CHECK_FOR_FPU_EXCEPTION; *(uint64_t *)ic->arg[1] = *(uint64_t *)ic->arg[0]; } /* * fabs: Floating-point Absulute Value * * arg[0] = ptr to frb * arg[1] = ptr to frt */ X(fabs) { uint64_t v; CHECK_FOR_FPU_EXCEPTION; v = *(uint64_t *)ic->arg[0]; *(uint64_t *)ic->arg[1] = v & 0x7fffffffffffffffULL; } /* * fneg: Floating-point Negate * * arg[0] = ptr to frb * arg[1] = ptr to frt */ X(fneg) { uint64_t v; CHECK_FOR_FPU_EXCEPTION; v = *(uint64_t *)ic->arg[0]; *(uint64_t *)ic->arg[1] = v ^ 0x8000000000000000ULL; } /* * fcmpu: Floating-point Compare Unordered * * arg[0] = 28 - 4*bf (bitfield shift) * arg[1] = ptr to fra * arg[2] = ptr to frb */ X(fcmpu) { struct ieee_float_value fra, frb; int bf_shift = ic->arg[0], c = 0; CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &fra, IEEE_FMT_D); ieee_interpret_float_value(*(uint64_t *)ic->arg[2], &frb, IEEE_FMT_D); if (fra.nan | frb.nan) { c = 1; } else { if (fra.f < frb.f) c = 8; else if (fra.f > frb.f) c = 4; else c = 2; } /* TODO: Signaling vs Quiet NaN */ cpu->cd.ppc.cr &= ~(0xf << bf_shift); cpu->cd.ppc.cr |= ((c&0xe) << bf_shift); cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); cpu->cd.ppc.fpscr |= (c << PPC_FPSCR_FPCC_SHIFT); } /* * frsp: Floating-point Round to Single Precision * * arg[0] = ptr to frb * arg[1] = ptr to frt */ X(frsp) { struct ieee_float_value frb; float fl = 0.0; int c = 0; CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &frb, IEEE_FMT_D); if (frb.nan) { c = 1; } else { fl = frb.f; if (fl < 0.0) c = 8; else if (fl > 0.0) c = 4; else c = 2; } /* TODO: Signaling vs Quiet NaN */ cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); cpu->cd.ppc.fpscr |= (c << PPC_FPSCR_FPCC_SHIFT); (*(uint64_t *)ic->arg[1]) = ieee_store_float_value(fl, IEEE_FMT_D); } /* * fctiwz: Floating-point Convert to Integer Word, Round to Zero * * arg[0] = ptr to frb * arg[1] = ptr to frt */ X(fctiwz) { struct ieee_float_value frb; uint32_t res = 0; CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &frb, IEEE_FMT_D); if (!frb.nan) { if (frb.f >= 2147483647.0) res = 0x7fffffff; else if (frb.f <= -2147483648.0) res = 0x80000000; else res = (int32_t) frb.f; } *(uint64_t *)ic->arg[1] = (uint32_t)res; } /* * fmul: Floating-point Multiply * * arg[0] = ptr to frt * arg[1] = ptr to fra * arg[2] = ptr to frc */ X(fmul) { struct ieee_float_value fra; struct ieee_float_value frc; double result = 0.0; int c; CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &fra, IEEE_FMT_D); ieee_interpret_float_value(*(uint64_t *)ic->arg[2], &frc, IEEE_FMT_D); result = fra.f * frc.f; if (isnan(result)) c = 1; else { if (result < 0.0) c = 8; else if (result > 0.0) c = 4; else c = 2; } /* TODO: Signaling vs Quiet NaN */ cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); cpu->cd.ppc.fpscr |= (c << PPC_FPSCR_FPCC_SHIFT); (*(uint64_t *)ic->arg[0]) = ieee_store_float_value(result, IEEE_FMT_D); } X(fmuls) { /* TODO */ instr(fmul)(cpu, ic); } /* * fmadd: Floating-point Multiply and Add * * arg[0] = ptr to frt * arg[1] = ptr to fra * arg[2] = copy of the instruction word */ X(fmadd) { uint32_t iw = ic->arg[2]; int b = (iw >> 11) & 31, c = (iw >> 6) & 31; struct ieee_float_value fra; struct ieee_float_value frb; struct ieee_float_value frc; double result = 0.0; int cc; CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &fra, IEEE_FMT_D); ieee_interpret_float_value(cpu->cd.ppc.fpr[b], &frb, IEEE_FMT_D); ieee_interpret_float_value(cpu->cd.ppc.fpr[c], &frc, IEEE_FMT_D); result = fra.f * frc.f + frb.f; if (isnan(result)) cc = 1; else { if (result < 0.0) cc = 8; else if (result > 0.0) cc = 4; else cc = 2; } /* TODO: Signaling vs Quiet NaN */ cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); cpu->cd.ppc.fpscr |= (cc << PPC_FPSCR_FPCC_SHIFT); (*(uint64_t *)ic->arg[0]) = ieee_store_float_value(result, IEEE_FMT_D); } /* * fmsub: Floating-point Multiply and Sub * * arg[0] = ptr to frt * arg[1] = ptr to fra * arg[2] = copy of the instruction word */ X(fmsub) { uint32_t iw = ic->arg[2]; int b = (iw >> 11) & 31, c = (iw >> 6) & 31; struct ieee_float_value fra; struct ieee_float_value frb; struct ieee_float_value frc; double result = 0.0; int cc; CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &fra, IEEE_FMT_D); ieee_interpret_float_value(cpu->cd.ppc.fpr[b], &frb, IEEE_FMT_D); ieee_interpret_float_value(cpu->cd.ppc.fpr[c], &frc, IEEE_FMT_D); result = fra.f * frc.f - frb.f; if (isnan(result)) cc = 1; else { if (result < 0.0) cc = 8; else if (result > 0.0) cc = 4; else cc = 2; } /* TODO: Signaling vs Quiet NaN */ cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); cpu->cd.ppc.fpscr |= (cc << PPC_FPSCR_FPCC_SHIFT); (*(uint64_t *)ic->arg[0]) = ieee_store_float_value(result, IEEE_FMT_D); } /* * fadd, fsub, fdiv: Various Floating-point operationgs * * arg[0] = ptr to fra * arg[1] = ptr to frb * arg[2] = ptr to frt */ X(fadd) { struct ieee_float_value fra; struct ieee_float_value frb; double result = 0.0; int c; CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &fra, IEEE_FMT_D); ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &frb, IEEE_FMT_D); result = fra.f + frb.f; if (isnan(result)) c = 1; else { if (result < 0.0) c = 8; else if (result > 0.0) c = 4; else c = 2; } /* TODO: Signaling vs Quiet NaN */ cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); cpu->cd.ppc.fpscr |= (c << PPC_FPSCR_FPCC_SHIFT); (*(uint64_t *)ic->arg[2]) = ieee_store_float_value(result, IEEE_FMT_D); } X(fadds) { /* TODO */ instr(fadd)(cpu, ic); } X(fsub) { struct ieee_float_value fra; struct ieee_float_value frb; double result = 0.0; int c; CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &fra, IEEE_FMT_D); ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &frb, IEEE_FMT_D); result = fra.f - frb.f; if (isnan(result)) c = 1; else { if (result < 0.0) c = 8; else if (result > 0.0) c = 4; else c = 2; } /* TODO: Signaling vs Quiet NaN */ cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); cpu->cd.ppc.fpscr |= (c << PPC_FPSCR_FPCC_SHIFT); (*(uint64_t *)ic->arg[2]) = ieee_store_float_value(result, IEEE_FMT_D); } X(fsubs) { /* TODO */ instr(fsub)(cpu, ic); } X(fdiv) { struct ieee_float_value fra; struct ieee_float_value frb; double result = 0.0; int c; CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &fra, IEEE_FMT_D); ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &frb, IEEE_FMT_D); result = fra.f / frb.f; if (isnan(result)) c = 1; else { if (result < 0.0) c = 8; else if (result > 0.0) c = 4; else c = 2; } /* TODO: Signaling vs Quiet NaN */ cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); cpu->cd.ppc.fpscr |= (c << PPC_FPSCR_FPCC_SHIFT); (*(uint64_t *)ic->arg[2]) = ieee_store_float_value(result, IEEE_FMT_D); } X(fdivs) { /* TODO */ instr(fdiv)(cpu, ic); } /* * llsc: Load-linked and store conditional * * arg[0] = copy of the instruction word. */ X(llsc) { int iw = ic->arg[0], len = 4, load = 0, xo = (iw >> 1) & 1023; int i, rc = iw & 1, rt, ra, rb; uint64_t addr = 0, value; unsigned char d[8]; switch (xo) { case PPC_31_LDARX: len = 8; case PPC_31_LWARX: load = 1; break; case PPC_31_STDCX_DOT: len = 8; case PPC_31_STWCX_DOT: break; } rt = (iw >> 21) & 31; ra = (iw >> 16) & 31; rb = (iw >> 11) & 31; if (ra != 0) addr = cpu->cd.ppc.gpr[ra]; addr += cpu->cd.ppc.gpr[rb]; if (load) { if (rc) { fatal("ll: rc-bit set?\n"); exit(1); } if (cpu->memory_rw(cpu, cpu->mem, addr, d, len, MEM_READ, CACHE_DATA) != MEMORY_ACCESS_OK) { fatal("ll: error: TODO\n"); exit(1); } value = 0; for (i=0; ibyte_order == EMUL_BIG_ENDIAN) value |= d[i]; else value |= d[len - 1 - i]; } cpu->cd.ppc.gpr[rt] = value; cpu->cd.ppc.ll_addr = addr; cpu->cd.ppc.ll_bit = 1; } else { uint32_t old_so = cpu->cd.ppc.spr[SPR_XER] & PPC_XER_SO; if (!rc) { fatal("sc: rc-bit not set?\n"); exit(1); } value = cpu->cd.ppc.gpr[rt]; /* "If the store is performed, bits 0-2 of Condition Register Field 0 are set to 0b001, otherwise, they are set to 0b000. The SO bit of the XER is copied to to bit 4 of Condition Register Field 0. */ if (!cpu->cd.ppc.ll_bit || cpu->cd.ppc.ll_addr != addr) { cpu->cd.ppc.cr &= 0x0fffffff; if (old_so) cpu->cd.ppc.cr |= 0x10000000; cpu->cd.ppc.ll_bit = 0; return; } for (i=0; ibyte_order == EMUL_BIG_ENDIAN) d[len - 1 - i] = value >> (8*i); else d[i] = value >> (8*i); } if (cpu->memory_rw(cpu, cpu->mem, addr, d, len, MEM_WRITE, CACHE_DATA) != MEMORY_ACCESS_OK) { fatal("sc: error: TODO\n"); exit(1); } cpu->cd.ppc.cr &= 0x0fffffff; cpu->cd.ppc.cr |= 0x20000000; /* success! */ if (old_so) cpu->cd.ppc.cr |= 0x10000000; /* Clear _all_ CPUs' ll_bits: */ for (i=0; imachine->ncpus; i++) cpu->machine->cpus[i]->cd.ppc.ll_bit = 0; } } /* * mtsr, mtsrin: Move To Segment Register [Indirect] * * arg[0] = sr number, or for indirect mode: ptr to rb * arg[1] = ptr to rt * * TODO: These only work for 32-bit mode! */ X(mtsr) { int sr_num = ic->arg[0]; uint32_t old = cpu->cd.ppc.sr[sr_num]; cpu->cd.ppc.sr[sr_num] = reg(ic->arg[1]); if (cpu->cd.ppc.sr[sr_num] != old) cpu->invalidate_translation_caches(cpu, ic->arg[0] << 28, INVALIDATE_ALL | INVALIDATE_VADDR_UPPER4); } X(mtsrin) { int sr_num = reg(ic->arg[0]) >> 28; uint32_t old = cpu->cd.ppc.sr[sr_num]; cpu->cd.ppc.sr[sr_num] = reg(ic->arg[1]); if (cpu->cd.ppc.sr[sr_num] != old) cpu->invalidate_translation_caches(cpu, sr_num << 28, INVALIDATE_ALL | INVALIDATE_VADDR_UPPER4); } /* * mfsrin, mtsrin: Move From/To Segment Register Indirect * * arg[0] = sr number, or for indirect mode: ptr to rb * arg[1] = ptr to rt */ X(mfsr) { /* TODO: This only works for 32-bit mode */ reg(ic->arg[1]) = cpu->cd.ppc.sr[ic->arg[0]]; } X(mfsrin) { /* TODO: This only works for 32-bit mode */ uint32_t sr_num = reg(ic->arg[0]) >> 28; reg(ic->arg[1]) = cpu->cd.ppc.sr[sr_num]; } /* * rldicl: * * arg[0] = copy of the instruction word */ X(rldicl) { int rs = (ic->arg[0] >> 21) & 31; int ra = (ic->arg[0] >> 16) & 31; int sh = ((ic->arg[0] >> 11) & 31) | ((ic->arg[0] & 2) << 4); int mb = ((ic->arg[0] >> 6) & 31) | (ic->arg[0] & 0x20); int rc = ic->arg[0] & 1; uint64_t tmp = cpu->cd.ppc.gpr[rs], tmp2; /* TODO: Fix this, its performance is awful: */ while (sh-- != 0) { int b = (tmp >> 63) & 1; tmp = (tmp << 1) | b; } tmp2 = 0; while (mb <= 63) { tmp |= ((uint64_t)1 << (63-mb)); mb ++; } cpu->cd.ppc.gpr[ra] = tmp & tmp2; if (rc) update_cr0(cpu, cpu->cd.ppc.gpr[ra]); } /* * rldicr: * * arg[0] = copy of the instruction word */ X(rldicr) { int rs = (ic->arg[0] >> 21) & 31; int ra = (ic->arg[0] >> 16) & 31; int sh = ((ic->arg[0] >> 11) & 31) | ((ic->arg[0] & 2) << 4); int me = ((ic->arg[0] >> 6) & 31) | (ic->arg[0] & 0x20); int rc = ic->arg[0] & 1; uint64_t tmp = cpu->cd.ppc.gpr[rs]; /* TODO: Fix this, its performance is awful: */ while (sh-- != 0) { int b = (tmp >> 63) & 1; tmp = (tmp << 1) | b; } while (me++ < 63) tmp &= ~((uint64_t)1 << (63-me)); cpu->cd.ppc.gpr[ra] = tmp; if (rc) update_cr0(cpu, tmp); } /* * rldimi: * * arg[0] = copy of the instruction word */ X(rldimi) { uint32_t iw = ic->arg[0]; int rs = (iw >> 21) & 31, ra = (iw >> 16) & 31; int sh = ((iw >> 11) & 31) | ((iw & 2) << 4); int mb = ((iw >> 6) & 31) | (iw & 0x20); int rc = ic->arg[0] & 1; int m; uint64_t tmp, s = cpu->cd.ppc.gpr[rs]; /* TODO: Fix this, its performance is awful: */ while (sh-- != 0) { int b = (s >> 63) & 1; s = (s << 1) | b; } m = mb; tmp = 0; do { tmp |= ((uint64_t)1 << (63-m)); m ++; } while (m != 63 - sh); cpu->cd.ppc.gpr[ra] &= ~tmp; cpu->cd.ppc.gpr[ra] |= (tmp & s); if (rc) update_cr0(cpu, cpu->cd.ppc.gpr[ra]); } /* * rlwnm: * * arg[0] = ptr to ra * arg[1] = mask * arg[2] = copy of the instruction word */ X(rlwnm) { uint32_t tmp, iword = ic->arg[2]; int rs = (iword >> 21) & 31; int rb = (iword >> 11) & 31; int sh = cpu->cd.ppc.gpr[rb] & 0x1f; tmp = (uint32_t)cpu->cd.ppc.gpr[rs]; tmp = (tmp << sh) | (tmp >> (32-sh)); tmp &= (uint32_t)ic->arg[1]; reg(ic->arg[0]) = tmp; } DOT0(rlwnm) /* * rlwinm: * * arg[0] = ptr to ra * arg[1] = mask * arg[2] = copy of the instruction word */ X(rlwinm) { uint32_t tmp, iword = ic->arg[2]; int rs = (iword >> 21) & 31; int sh = (iword >> 11) & 31; tmp = (uint32_t)cpu->cd.ppc.gpr[rs]; tmp = (tmp << sh) | (tmp >> (32-sh)); tmp &= (uint32_t)ic->arg[1]; reg(ic->arg[0]) = tmp; } DOT0(rlwinm) /* * rlwimi: * * arg[0] = ptr to rs * arg[1] = ptr to ra * arg[2] = copy of the instruction word */ X(rlwimi) { MODE_uint_t tmp = reg(ic->arg[0]), ra = reg(ic->arg[1]); uint32_t iword = ic->arg[2]; int sh = (iword >> 11) & 31; int mb = (iword >> 6) & 31; int me = (iword >> 1) & 31; int rc = iword & 1; tmp = (tmp << sh) | (tmp >> (32-sh)); for (;;) { uint64_t mask; mask = (uint64_t)1 << (31-mb); ra &= ~mask; ra |= (tmp & mask); if (mb == me) break; mb ++; if (mb == 32) mb = 0; } reg(ic->arg[1]) = ra; if (rc) update_cr0(cpu, ra); } /* * srawi: * * arg[0] = ptr to rs * arg[1] = ptr to ra * arg[2] = sh (shift amount) */ X(srawi) { uint32_t tmp = reg(ic->arg[0]); int i = 0, j = 0, sh = ic->arg[2]; cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (tmp & 0x80000000) i = 1; while (sh-- > 0) { if (tmp & 1) j ++; tmp >>= 1; if (tmp & 0x40000000) tmp |= 0x80000000; } if (i && j>0) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[1]) = (int64_t)(int32_t)tmp; } DOT1(srawi) /* * mcrf: Move inside condition register * * arg[0] = 28-4*bf, arg[1] = 28-4*bfa */ X(mcrf) { int bf_shift = ic->arg[0], bfa_shift = ic->arg[1]; uint32_t tmp = (cpu->cd.ppc.cr >> bfa_shift) & 0xf; cpu->cd.ppc.cr &= ~(0xf << bf_shift); cpu->cd.ppc.cr |= (tmp << bf_shift); } /* * crand, crxor etc: Condition Register operations * * arg[0] = copy of the instruction word */ X(crand) { uint32_t iword = ic->arg[0]; int bt = (iword >> 21) & 31; int ba = (iword >> 16) & 31, bb = (iword >> 11) & 31; ba = (cpu->cd.ppc.cr >> (31-ba)) & 1; bb = (cpu->cd.ppc.cr >> (31-bb)) & 1; cpu->cd.ppc.cr &= ~(1 << (31-bt)); if (ba & bb) cpu->cd.ppc.cr |= (1 << (31-bt)); } X(crandc) { uint32_t iword = ic->arg[0]; int bt = (iword >> 21) & 31; int ba = (iword >> 16) & 31, bb = (iword >> 11) & 31; ba = (cpu->cd.ppc.cr >> (31-ba)) & 1; bb = (cpu->cd.ppc.cr >> (31-bb)) & 1; cpu->cd.ppc.cr &= ~(1 << (31-bt)); if (!(ba & bb)) cpu->cd.ppc.cr |= (1 << (31-bt)); } X(creqv) { uint32_t iword = ic->arg[0]; int bt = (iword >> 21) & 31; int ba = (iword >> 16) & 31, bb = (iword >> 11) & 31; ba = (cpu->cd.ppc.cr >> (31-ba)) & 1; bb = (cpu->cd.ppc.cr >> (31-bb)) & 1; cpu->cd.ppc.cr &= ~(1 << (31-bt)); if (!(ba ^ bb)) cpu->cd.ppc.cr |= (1 << (31-bt)); } X(cror) { uint32_t iword = ic->arg[0]; int bt = (iword >> 21) & 31; int ba = (iword >> 16) & 31, bb = (iword >> 11) & 31; ba = (cpu->cd.ppc.cr >> (31-ba)) & 1; bb = (cpu->cd.ppc.cr >> (31-bb)) & 1; cpu->cd.ppc.cr &= ~(1 << (31-bt)); if (ba | bb) cpu->cd.ppc.cr |= (1 << (31-bt)); } X(crorc) { uint32_t iword = ic->arg[0]; int bt = (iword >> 21) & 31; int ba = (iword >> 16) & 31, bb = (iword >> 11) & 31; ba = (cpu->cd.ppc.cr >> (31-ba)) & 1; bb = (cpu->cd.ppc.cr >> (31-bb)) & 1; cpu->cd.ppc.cr &= ~(1 << (31-bt)); if (!(ba | bb)) cpu->cd.ppc.cr |= (1 << (31-bt)); } X(crnor) { uint32_t iword = ic->arg[0]; int bt = (iword >> 21) & 31; int ba = (iword >> 16) & 31, bb = (iword >> 11) & 31; ba = (cpu->cd.ppc.cr >> (31-ba)) & 1; bb = (cpu->cd.ppc.cr >> (31-bb)) & 1; cpu->cd.ppc.cr &= ~(1 << (31-bt)); if (!(ba | bb)) cpu->cd.ppc.cr |= (1 << (31-bt)); } X(crxor) { uint32_t iword = ic->arg[0]; int bt = (iword >> 21) & 31; int ba = (iword >> 16) & 31, bb = (iword >> 11) & 31; ba = (cpu->cd.ppc.cr >> (31-ba)) & 1; bb = (cpu->cd.ppc.cr >> (31-bb)) & 1; cpu->cd.ppc.cr &= ~(1 << (31-bt)); if (ba ^ bb) cpu->cd.ppc.cr |= (1 << (31-bt)); } /* * mfspr: Move from SPR * * arg[0] = pointer to destination register * arg[1] = pointer to source SPR */ X(mfspr) { /* TODO: Check permission */ reg(ic->arg[0]) = reg(ic->arg[1]); } X(mfspr_pmc1) { /* * TODO: This is a temporary hack to make NetBSD/ppc detect * a CPU of the correct (emulated) speed. */ reg(ic->arg[0]) = cpu->machine->emulated_hz / 10; } X(mftb) { /* NOTE/TODO: This increments the time base (slowly) if it is being polled. */ if (++cpu->cd.ppc.spr[SPR_TBL] == 0) cpu->cd.ppc.spr[SPR_TBU] ++; reg(ic->arg[0]) = cpu->cd.ppc.spr[SPR_TBL]; } X(mftbu) { reg(ic->arg[0]) = cpu->cd.ppc.spr[SPR_TBU]; } /* * mtspr: Move to SPR. * * arg[0] = pointer to source register * arg[1] = pointer to the SPR */ X(mtspr) { /* TODO: Check permission */ reg(ic->arg[1]) = reg(ic->arg[0]); } X(mtspr_sprg2) { if (cpu->cd.ppc.bits == 32) { // Ignore for now. FreeBSD/powerpc seems to write 0xffffffe0 // here, and read it back. If it is non-zero, it assumes a 64-bit // cpu. } else { reg(ic->arg[1]) = reg(ic->arg[0]); } } X(mtlr) { cpu->cd.ppc.spr[SPR_LR] = reg(ic->arg[0]); } X(mtctr) { cpu->cd.ppc.spr[SPR_CTR] = reg(ic->arg[0]); } /* * rfi[d]: Return from Interrupt */ X(rfi) { uint64_t tmp; reg_access_msr(cpu, &tmp, 0, 0); tmp &= ~0xffff; tmp |= (cpu->cd.ppc.spr[SPR_SRR1] & 0xffff); reg_access_msr(cpu, &tmp, 1, 0); cpu->pc = cpu->cd.ppc.spr[SPR_SRR0]; quick_pc_to_pointers(cpu); } X(rfid) { uint64_t tmp, mask = 0x800000000000ff73ULL; reg_access_msr(cpu, &tmp, 0, 0); tmp &= ~mask; tmp |= (cpu->cd.ppc.spr[SPR_SRR1] & mask); reg_access_msr(cpu, &tmp, 1, 0); cpu->pc = cpu->cd.ppc.spr[SPR_SRR0]; if (!(tmp & PPC_MSR_SF)) cpu->pc = (uint32_t)cpu->pc; quick_pc_to_pointers(cpu); } /* * mfcr: Move From Condition Register * * arg[0] = pointer to destination register */ X(mfcr) { reg(ic->arg[0]) = cpu->cd.ppc.cr; } /* * mfmsr: Move From MSR * * arg[0] = pointer to destination register */ X(mfmsr) { reg_access_msr(cpu, (uint64_t*)ic->arg[0], 0, 0); } /* * mtmsr: Move To MSR * * arg[0] = pointer to source register * arg[1] = page offset of the next instruction * arg[2] = 0 for 32-bit (mtmsr), 1 for 64-bit (mtmsrd) */ X(mtmsr) { MODE_uint_t old_pc; uint64_t x = reg(ic->arg[0]); /* TODO: check permission! */ /* Synchronize the PC (pointing to _after_ this instruction) */ cpu->pc = (cpu->pc & ~0xfff) + ic->arg[1]; old_pc = cpu->pc; if (!ic->arg[2]) { uint64_t y; reg_access_msr(cpu, &y, 0, 0); x = (y & 0xffffffff00000000ULL) | (x & 0xffffffffULL); } reg_access_msr(cpu, &x, 1, 1); /* * Super-ugly hack: If the pc wasn't changed (i.e. if there was no * exception while accessing the msr), then we _decrease_ the PC by 4 * again. This is because the next ic could be an end_of_page. */ if ((MODE_uint_t)cpu->pc == old_pc) cpu->pc -= 4; } /* * wrteei: Write EE immediate (on PPC405GP) * * arg[0] = either 0 or 0x8000 */ X(wrteei) { /* TODO: check permission! */ uint64_t x; /* Synchronize the PC (pointing to _after_ this instruction) */ cpu->pc = (cpu->pc & ~0xfff) + ic->arg[1]; reg_access_msr(cpu, &x, 0, 0); x = (x & ~0x8000) | ic->arg[0]; reg_access_msr(cpu, &x, 1, 1); } /* * mtcrf: Move To Condition Register Fields * * arg[0] = pointer to source register */ X(mtcrf) { cpu->cd.ppc.cr &= ~ic->arg[1]; cpu->cd.ppc.cr |= (reg(ic->arg[0]) & ic->arg[1]); } /* * mulli: Multiply Low Immediate. * * arg[0] = pointer to source register ra * arg[1] = int32_t immediate * arg[2] = pointer to destination register rt */ X(mulli) { reg(ic->arg[2]) = (uint32_t)(reg(ic->arg[0]) * (int32_t)ic->arg[1]); } /* * Load/Store Multiple: * * arg[0] = rs (or rt for loads) NOTE: not a pointer * arg[1] = ptr to ra * arg[2] = int32_t immediate offset */ X(lmw) { MODE_uint_t addr = reg(ic->arg[1]) + (int32_t)ic->arg[2]; unsigned char d[4]; int rs = ic->arg[0]; int low_pc = ((size_t)ic - (size_t)cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->pc |= (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); while (rs <= 31) { if (cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ, CACHE_DATA) != MEMORY_ACCESS_OK) { /* exception */ return; } if (cpu->byte_order == EMUL_BIG_ENDIAN) cpu->cd.ppc.gpr[rs] = (d[0] << 24) + (d[1] << 16) + (d[2] << 8) + d[3]; else cpu->cd.ppc.gpr[rs] = (d[3] << 24) + (d[2] << 16) + (d[1] << 8) + d[0]; rs ++; addr += sizeof(uint32_t); } } X(stmw) { MODE_uint_t addr = reg(ic->arg[1]) + (int32_t)ic->arg[2]; unsigned char d[4]; int rs = ic->arg[0]; int low_pc = ((size_t)ic - (size_t)cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); while (rs <= 31) { uint32_t tmp = cpu->cd.ppc.gpr[rs]; if (cpu->byte_order == EMUL_BIG_ENDIAN) { d[3] = tmp; d[2] = tmp >> 8; d[1] = tmp >> 16; d[0] = tmp >> 24; } else { d[0] = tmp; d[1] = tmp >> 8; d[2] = tmp >> 16; d[3] = tmp >> 24; } if (cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE, CACHE_DATA) != MEMORY_ACCESS_OK) { /* exception */ return; } rs ++; addr += sizeof(uint32_t); } } /* * Load/store string: * * arg[0] = rs (well, rt for lswi) * arg[1] = ptr to ra (or ptr to zero) * arg[2] = nb */ X(lswi) { MODE_uint_t addr = reg(ic->arg[1]); int rt = ic->arg[0], nb = ic->arg[2]; int sub = 0; int low_pc = ((size_t)ic - (size_t)cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); while (nb > 0) { unsigned char d; if (cpu->memory_rw(cpu, cpu->mem, addr, &d, 1, MEM_READ, CACHE_DATA) != MEMORY_ACCESS_OK) { /* exception */ return; } if (cpu->cd.ppc.mode == MODE_POWER && sub == 0) cpu->cd.ppc.gpr[rt] = 0; cpu->cd.ppc.gpr[rt] &= ~(0xff << (24-8*sub)); cpu->cd.ppc.gpr[rt] |= (d << (24-8*sub)); sub ++; if (sub == 4) { rt = (rt + 1) & 31; sub = 0; } addr ++; nb --; } } X(stswi) { MODE_uint_t addr = reg(ic->arg[1]); int rs = ic->arg[0], nb = ic->arg[2]; uint32_t cur = cpu->cd.ppc.gpr[rs]; int sub = 0; int low_pc = ((size_t)ic - (size_t)cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); while (nb > 0) { unsigned char d = cur >> 24; if (cpu->memory_rw(cpu, cpu->mem, addr, &d, 1, MEM_WRITE, CACHE_DATA) != MEMORY_ACCESS_OK) { /* exception */ return; } cur <<= 8; sub ++; if (sub == 4) { rs = (rs + 1) & 31; sub = 0; cur = cpu->cd.ppc.gpr[rs]; } addr ++; nb --; } } /* * Shifts, and, or, xor, etc. * * arg[0] = pointer to source register rs * arg[1] = pointer to source register rb * arg[2] = pointer to destination register ra */ X(extsb) { #ifdef MODE32 reg(ic->arg[2]) = (int32_t)(int8_t)reg(ic->arg[0]); #else reg(ic->arg[2]) = (int64_t)(int8_t)reg(ic->arg[0]); #endif } DOT2(extsb) X(extsh) { #ifdef MODE32 reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]); #else reg(ic->arg[2]) = (int64_t)(int16_t)reg(ic->arg[0]); #endif } DOT2(extsh) X(extsw) { #ifdef MODE32 fatal("TODO: extsw: invalid instruction\n"); #else reg(ic->arg[2]) = (int64_t)(int32_t)reg(ic->arg[0]); #endif } DOT2(extsw) X(slw) { reg(ic->arg[2]) = (uint64_t)reg(ic->arg[0]) << (reg(ic->arg[1]) & 31); } DOT2(slw) X(sld) {int sa = reg(ic->arg[1]) & 127; if (sa >= 64) reg(ic->arg[2]) = 0; else reg(ic->arg[2]) = (uint64_t)reg(ic->arg[0]) << (sa & 63); } DOT2(sld) X(sraw) { uint32_t tmp = reg(ic->arg[0]); int i = 0, j = 0, sh = reg(ic->arg[1]) & 31; cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (tmp & 0x80000000) i = 1; while (sh-- > 0) { if (tmp & 1) j ++; tmp >>= 1; if (tmp & 0x40000000) tmp |= 0x80000000; } if (i && j>0) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (int64_t)(int32_t)tmp; } DOT2(sraw) X(srw) { reg(ic->arg[2]) = (uint64_t)reg(ic->arg[0]) >> (reg(ic->arg[1]) & 31); } DOT2(srw) X(and) { reg(ic->arg[2]) = reg(ic->arg[0]) & reg(ic->arg[1]); } DOT2(and) X(nand) { reg(ic->arg[2]) = ~(reg(ic->arg[0]) & reg(ic->arg[1])); } DOT2(nand) X(andc) { reg(ic->arg[2]) = reg(ic->arg[0]) & (~reg(ic->arg[1])); } DOT2(andc) X(nor) { reg(ic->arg[2]) = ~(reg(ic->arg[0]) | reg(ic->arg[1])); } DOT2(nor) X(mr) { reg(ic->arg[2]) = reg(ic->arg[1]); } X(or) { reg(ic->arg[2]) = reg(ic->arg[0]) | reg(ic->arg[1]); } DOT2(or) X(orc) { reg(ic->arg[2]) = reg(ic->arg[0]) | (~reg(ic->arg[1])); } DOT2(orc) X(xor) { reg(ic->arg[2]) = reg(ic->arg[0]) ^ reg(ic->arg[1]); } DOT2(xor) X(eqv) { reg(ic->arg[2]) = ~(reg(ic->arg[0]) ^ reg(ic->arg[1])); } DOT2(eqv) /* * neg: * * arg[0] = pointer to source register ra * arg[1] = pointer to destination register rt */ X(neg) { reg(ic->arg[1]) = -reg(ic->arg[0]); } DOT1(neg) /* * mullw, mulhw[u], divw[u]: * * arg[0] = pointer to source register ra * arg[1] = pointer to source register rb * arg[2] = pointer to destination register rt */ X(mullw) { int32_t sum = (int32_t)reg(ic->arg[0]) * (int32_t)reg(ic->arg[1]); reg(ic->arg[2]) = (int32_t)sum; } DOT2(mullw) X(mulhw) { int64_t sum; sum = (int64_t)(int32_t)reg(ic->arg[0]) * (int64_t)(int32_t)reg(ic->arg[1]); reg(ic->arg[2]) = sum >> 32; } DOT2(mulhw) X(mulhwu) { uint64_t sum; sum = (uint64_t)(uint32_t)reg(ic->arg[0]) * (uint64_t)(uint32_t)reg(ic->arg[1]); reg(ic->arg[2]) = sum >> 32; } DOT2(mulhwu) X(divw) { int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); int32_t sum; if (b == 0) sum = 0; else sum = a / b; reg(ic->arg[2]) = (uint32_t)sum; } DOT2(divw) X(divwu) { uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); uint32_t sum; if (b == 0) sum = 0; else sum = a / b; reg(ic->arg[2]) = sum; } DOT2(divwu) /* * add: Add. * * arg[0] = pointer to source register ra * arg[1] = pointer to source register rb * arg[2] = pointer to destination register rt */ X(add) { reg(ic->arg[2]) = reg(ic->arg[0]) + reg(ic->arg[1]); } DOT2(add) /* * addc: Add carrying. * * arg[0] = pointer to source register ra * arg[1] = pointer to source register rb * arg[2] = pointer to destination register rt */ X(addc) { /* TODO: this only works in 32-bit mode */ uint64_t tmp = (uint32_t)reg(ic->arg[0]); uint64_t tmp2 = tmp; cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; tmp += (uint32_t)reg(ic->arg[1]); if ((tmp >> 32) != (tmp2 >> 32)) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp; } /* * adde: Add extended, etc. * * arg[0] = pointer to source register ra * arg[1] = pointer to source register rb * arg[2] = pointer to destination register rt */ X(adde) { /* TODO: this only works in 32-bit mode */ int old_ca = cpu->cd.ppc.spr[SPR_XER] & PPC_XER_CA; uint64_t tmp = (uint32_t)reg(ic->arg[0]); uint64_t tmp2 = tmp; cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; tmp += (uint32_t)reg(ic->arg[1]); if (old_ca) tmp ++; if ((tmp >> 32) != (tmp2 >> 32)) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp; } DOT2(adde) X(addme) { /* TODO: this only works in 32-bit mode */ int old_ca = cpu->cd.ppc.spr[SPR_XER] & PPC_XER_CA; uint64_t tmp = (uint32_t)reg(ic->arg[0]); uint64_t tmp2 = tmp; cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (old_ca) tmp ++; tmp += 0xffffffffULL; if ((tmp >> 32) != (tmp2 >> 32)) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp; } DOT2(addme) X(addze) { /* TODO: this only works in 32-bit mode */ int old_ca = cpu->cd.ppc.spr[SPR_XER] & PPC_XER_CA; uint64_t tmp = (uint32_t)reg(ic->arg[0]); uint64_t tmp2 = tmp; cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (old_ca) tmp ++; if ((tmp >> 32) != (tmp2 >> 32)) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp; } DOT2(addze) /* * subf: Subf, etc. * * arg[0] = pointer to source register ra * arg[1] = pointer to source register rb * arg[2] = pointer to destination register rt */ X(subf) { reg(ic->arg[2]) = reg(ic->arg[1]) - reg(ic->arg[0]); } DOT2(subf) X(subfc) { cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (reg(ic->arg[1]) >= reg(ic->arg[0])) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = reg(ic->arg[1]) - reg(ic->arg[0]); } DOT2(subfc) X(subfe) { int old_ca = (cpu->cd.ppc.spr[SPR_XER] & PPC_XER_CA)? 1 : 0; cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (reg(ic->arg[1]) == reg(ic->arg[0])) { if (old_ca) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; } else if (reg(ic->arg[1]) >= reg(ic->arg[0])) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; /* * TODO: The register value calculation should be correct, * but the CA bit calculation above is probably not. */ reg(ic->arg[2]) = reg(ic->arg[1]) - reg(ic->arg[0]) - (old_ca? 0 : 1); } DOT2(subfe) X(subfme) { int old_ca = cpu->cd.ppc.spr[SPR_XER] & PPC_XER_CA; uint64_t tmp = (uint32_t)(~reg(ic->arg[0])); tmp += 0xffffffffULL; cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (old_ca) tmp ++; if ((tmp >> 32) != 0) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp; } DOT2(subfme) X(subfze) { int old_ca = cpu->cd.ppc.spr[SPR_XER] & PPC_XER_CA; uint64_t tmp = (uint32_t)(~reg(ic->arg[0])); uint64_t tmp2 = tmp; cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (old_ca) tmp ++; if ((tmp >> 32) != (tmp2 >> 32)) cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp; } DOT2(subfze) /* * ori, xori etc.: * * arg[0] = pointer to source uint64_t * arg[1] = immediate value (uint32_t or larger) * arg[2] = pointer to destination uint64_t */ X(ori) { reg(ic->arg[2]) = reg(ic->arg[0]) | (uint32_t)ic->arg[1]; } X(xori) { reg(ic->arg[2]) = reg(ic->arg[0]) ^ (uint32_t)ic->arg[1]; } #include "tmp_ppc_loadstore.cc" /* * lfs, stfs: Load/Store Floating-point Single precision */ X(lfs) { /* Sync. PC in case of an exception, and remember it: */ uint64_t old_pc, low_pc = ((size_t)ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); old_pc = cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT)) + (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { ppc_exception(cpu, PPC_EXCEPTION_FPU); return; } /* Perform a 32-bit load: */ #ifdef MODE32 ppc32_loadstore #else ppc_loadstore #endif [2 + 4 + 8](cpu, ic); if (old_pc == cpu->pc) { /* The load succeeded. Let's convert the value: */ struct ieee_float_value val; (*(uint64_t *)ic->arg[0]) &= 0xffffffff; ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &val, IEEE_FMT_S); (*(uint64_t *)ic->arg[0]) = ieee_store_float_value(val.f, IEEE_FMT_D); } } X(lfsx) { /* Sync. PC in case of an exception, and remember it: */ uint64_t old_pc, low_pc = ((size_t)ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); old_pc = cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT)) + (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { ppc_exception(cpu, PPC_EXCEPTION_FPU); return; } /* Perform a 32-bit load: */ #ifdef MODE32 ppc32_loadstore_indexed #else ppc_loadstore_indexed #endif [2 + 4 + 8](cpu, ic); if (old_pc == cpu->pc) { /* The load succeeded. Let's convert the value: */ struct ieee_float_value val; (*(uint64_t *)ic->arg[0]) &= 0xffffffff; ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &val, IEEE_FMT_S); (*(uint64_t *)ic->arg[0]) = ieee_store_float_value(val.f, IEEE_FMT_D); } } X(lfd) { CHECK_FOR_FPU_EXCEPTION; /* Perform a 64-bit load: */ #ifdef MODE32 ppc32_loadstore #else ppc_loadstore #endif [3 + 4 + 8](cpu, ic); } X(lfdx) { CHECK_FOR_FPU_EXCEPTION; /* Perform a 64-bit load: */ #ifdef MODE32 ppc32_loadstore_indexed #else ppc_loadstore_indexed #endif [3 + 4 + 8](cpu, ic); } X(stfs) { uint64_t *old_arg0 = (uint64_t *) ic->arg[0]; struct ieee_float_value val; uint64_t tmp_val; CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*old_arg0, &val, IEEE_FMT_D); tmp_val = ieee_store_float_value(val.f, IEEE_FMT_S); ic->arg[0] = (size_t)&tmp_val; /* Perform a 32-bit store: */ #ifdef MODE32 ppc32_loadstore #else ppc_loadstore #endif [2 + 4](cpu, ic); ic->arg[0] = (size_t)old_arg0; } X(stfsx) { uint64_t *old_arg0 = (uint64_t *)ic->arg[0]; struct ieee_float_value val; uint64_t tmp_val; CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*old_arg0, &val, IEEE_FMT_D); tmp_val = ieee_store_float_value(val.f, IEEE_FMT_S); ic->arg[0] = (size_t)&tmp_val; /* Perform a 32-bit store: */ #ifdef MODE32 ppc32_loadstore_indexed #else ppc_loadstore_indexed #endif [2 + 4](cpu, ic); ic->arg[0] = (size_t)old_arg0; } X(stfd) { CHECK_FOR_FPU_EXCEPTION; /* Perform a 64-bit store: */ #ifdef MODE32 ppc32_loadstore #else ppc_loadstore #endif [3 + 4](cpu, ic); } X(stfdx) { CHECK_FOR_FPU_EXCEPTION; /* Perform a 64-bit store: */ #ifdef MODE32 ppc32_loadstore_indexed #else ppc_loadstore_indexed #endif [3 + 4](cpu, ic); } /* * lvx, stvx: Vector (16-byte) load/store (slow implementation) * * arg[0] = v-register nr of rs * arg[1] = pointer to ra * arg[2] = pointer to rb */ X(lvx) { MODE_uint_t addr = reg(ic->arg[1]) + reg(ic->arg[2]); uint8_t data[16]; uint64_t hi, lo; int rs = ic->arg[0]; if (cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_READ, CACHE_DATA) != MEMORY_ACCESS_OK) { /* exception */ return; } hi = ((uint64_t)data[0] << 56) + ((uint64_t)data[1] << 48) + ((uint64_t)data[2] << 40) + ((uint64_t)data[3] << 32) + ((uint64_t)data[4] << 24) + ((uint64_t)data[5] << 16) + ((uint64_t)data[6] << 8) + ((uint64_t)data[7]); lo = ((uint64_t)data[8] << 56) + ((uint64_t)data[9] << 48) + ((uint64_t)data[10] << 40) + ((uint64_t)data[11] << 32) + ((uint64_t)data[12] << 24) + ((uint64_t)data[13] << 16) + ((uint64_t)data[14] << 8) + ((uint64_t)data[15]); cpu->cd.ppc.vr_hi[rs] = hi; cpu->cd.ppc.vr_lo[rs] = lo; } X(stvx) { uint8_t data[16]; MODE_uint_t addr = reg(ic->arg[1]) + reg(ic->arg[2]); int rs = ic->arg[0]; uint64_t hi = cpu->cd.ppc.vr_hi[rs], lo = cpu->cd.ppc.vr_lo[rs]; data[0] = hi >> 56; data[1] = hi >> 48; data[2] = hi >> 40; data[3] = hi >> 32; data[4] = hi >> 24; data[5] = hi >> 16; data[6] = hi >> 8; data[7] = hi; data[8] = lo >> 56; data[9] = lo >> 48; data[10] = lo >> 40; data[11] = lo >> 32; data[12] = lo >> 24; data[13] = lo >> 16; data[14] = lo >> 8; data[15] = lo; cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_WRITE, CACHE_DATA); } /* * vxor: Vector (16-byte) XOR * * arg[0] = v-register nr of source 1 * arg[1] = v-register nr of source 2 * arg[2] = v-register nr of destination */ X(vxor) { cpu->cd.ppc.vr_hi[ic->arg[2]] = cpu->cd.ppc.vr_hi[ic->arg[0]] ^ cpu->cd.ppc.vr_hi[ic->arg[1]]; cpu->cd.ppc.vr_lo[ic->arg[2]] = cpu->cd.ppc.vr_lo[ic->arg[0]] ^ cpu->cd.ppc.vr_lo[ic->arg[1]]; } /* * tlbia: TLB invalidate all */ X(tlbia) { fatal("[ tlbia ]\n"); cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); } /* * tlbie: TLB invalidate */ X(tlbie) { /* fatal("[ tlbie ]\n"); */ cpu->invalidate_translation_caches(cpu, reg(ic->arg[0]), INVALIDATE_VADDR); } /* * sc: Syscall. */ X(sc) { /* Synchronize the PC (pointing to _after_ this instruction) */ cpu->pc = (cpu->pc & ~0xfff) + ic->arg[1]; ppc_exception(cpu, PPC_EXCEPTION_SC); /* This caused an update to the PC register, so there is no need to worry about the next instruction being an end_of_page. */ } /* * openfirmware: */ X(openfirmware) { of_emul(cpu); if (cpu->running == 0) { cpu->n_translated_instrs --; cpu->cd.ppc.next_ic = ¬hing_call; debugger_n_steps_left_before_interaction = 0; } cpu->pc = cpu->cd.ppc.spr[SPR_LR]; if (cpu->machine->show_trace_tree) cpu_functioncall_trace_return(cpu); quick_pc_to_pointers(cpu); } /* * tlbsx_dot: TLB scan */ X(tlbsx_dot) { /* TODO */ cpu->cd.ppc.cr &= ~(0xf0000000); cpu->cd.ppc.cr |= 0x20000000; cpu->cd.ppc.cr |= ((cpu->cd.ppc.spr[SPR_XER] >> 3) & 0x10000000); } /* * tlbli: */ X(tlbli) { fatal("tlbli\n"); cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); } /* * tlbld: */ X(tlbld) { /* MODE_uint_t vaddr = reg(ic->arg[0]); MODE_uint_t paddr = cpu->cd.ppc.spr[SPR_RPA]; */ fatal("tlbld\n"); cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); } /*****************************************************************************/ X(end_of_page) { /* Update the PC: (offset 0, but on the next page) */ cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->pc += (PPC_IC_ENTRIES_PER_PAGE << PPC_INSTR_ALIGNMENT_SHIFT); /* Find the new physical page and update the translation pointers: */ quick_pc_to_pointers(cpu); /* end_of_page doesn't count as an executed instruction: */ cpu->n_translated_instrs --; } /*****************************************************************************/ /* * ppc_instr_to_be_translated(): * * Translate an instruction word into a ppc_instr_call. ic is filled in with * valid data for the translated instruction, or a "nothing" instruction if * there was a translation failure. The newly translated instruction is then * executed. */ X(to_be_translated) { uint64_t addr, low_pc, tmp_addr; uint32_t iword, mask; unsigned char *page; unsigned char ib[4]; int main_opcode, rt, rs, ra, rb, rc, aa_bit, l_bit, lk_bit, spr, sh, xo, imm, load, size, update, zero, bf, bo, bi, bh, oe_bit, n64=0, bfa, fp, byterev, nb, mb, me; void (*samepage_function)(struct cpu *, struct ppc_instr_call *); void (*rc_f)(struct cpu *, struct ppc_instr_call *); /* Figure out the (virtual) address of the instruction: */ low_pc = ((size_t)ic - (size_t)cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); addr = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); addr += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); cpu->pc = addr; addr &= ~((1 << PPC_INSTR_ALIGNMENT_SHIFT) - 1); /* Read the instruction word from memory: */ #ifdef MODE32 page = cpu->cd.ppc.host_load[((uint32_t)addr) >> 12]; #else { const uint32_t mask1 = (1 << DYNTRANS_L1N) - 1; const uint32_t mask2 = (1 << DYNTRANS_L2N) - 1; const uint32_t mask3 = (1 << DYNTRANS_L3N) - 1; uint32_t x1 = (addr >> (64-DYNTRANS_L1N)) & mask1; uint32_t x2 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N)) & mask2; uint32_t x3 = (addr >> (64-DYNTRANS_L1N-DYNTRANS_L2N- DYNTRANS_L3N)) & mask3; struct DYNTRANS_L2_64_TABLE *l2 = cpu->cd.ppc.l1_64[x1]; struct DYNTRANS_L3_64_TABLE *l3 = l2->l3[x2]; page = l3->host_load[x3]; } #endif if (page != NULL) { /* fatal("TRANSLATION HIT!\n"); */ memcpy(ib, page + (addr & 0xfff), sizeof(ib)); } else { /* fatal("TRANSLATION MISS!\n"); */ if (!cpu->memory_rw(cpu, cpu->mem, addr, ib, sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) { fatal("PPC to_be_translated(): " "read failed: TODO\n"); exit(1); /* goto bad; */ } } { uint32_t *p = (uint32_t *) ib; iword = *p; iword = BE32_TO_HOST(iword); } #define DYNTRANS_TO_BE_TRANSLATED_HEAD #include "cpu_dyntrans.cc" #undef DYNTRANS_TO_BE_TRANSLATED_HEAD /* * Translate the instruction: */ main_opcode = iword >> 26; switch (main_opcode) { case 0x04: if (iword == 0x12739cc4) { /* vxor v19,v19,v19 */ ic->f = instr(vxor); ic->arg[0] = 19; ic->arg[1] = 19; ic->arg[2] = 19; } else { if (!cpu->translation_readahead) fatal("[ TODO: Unimplemented ALTIVEC, iword" " = 0x%08" PRIx32"x ]\n", iword); goto bad; } break; case PPC_HI6_MULLI: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; imm = (int16_t)(iword & 0xffff); ic->f = instr(mulli); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (ssize_t)imm; ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[rt]); break; case PPC_HI6_SUBFIC: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; imm = (int16_t)(iword & 0xffff); ic->f = instr(subfic); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (ssize_t)imm; ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[rt]); break; case PPC_HI6_CMPLI: case PPC_HI6_CMPI: bf = (iword >> 23) & 7; l_bit = (iword >> 21) & 1; ra = (iword >> 16) & 31; if (main_opcode == PPC_HI6_CMPLI) { imm = iword & 0xffff; if (l_bit) ic->f = instr(cmpldi); else ic->f = instr(cmplwi); } else { imm = (int16_t)(iword & 0xffff); if (l_bit) ic->f = instr(cmpdi); else { if (bf == 0) ic->f = instr(cmpwi_cr0); else ic->f = instr(cmpwi); } } ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (ssize_t)imm; ic->arg[2] = 28 - 4 * bf; break; case PPC_HI6_ADDIC: case PPC_HI6_ADDIC_DOT: if (cpu->cd.ppc.bits == 64) { if (!cpu->translation_readahead) fatal("addic for 64-bit: TODO\n"); goto bad; } rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; imm = (int16_t)(iword & 0xffff); if (main_opcode == PPC_HI6_ADDIC) ic->f = instr(addic); else ic->f = instr(addic_dot); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = imm; ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[rt]); break; case PPC_HI6_ADDI: case PPC_HI6_ADDIS: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; ic->f = instr(addi); if (ra == 0) ic->f = instr(li); else ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (int16_t)(iword & 0xffff); if (main_opcode == PPC_HI6_ADDIS) ic->arg[1] <<= 16; if (ra == 0 && ic->arg[1] == 0) ic->f = instr(li_0); ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[rt]); break; case PPC_HI6_ANDI_DOT: case PPC_HI6_ANDIS_DOT: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; ic->f = instr(andi_dot); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); ic->arg[1] = iword & 0xffff; if (main_opcode == PPC_HI6_ANDIS_DOT) ic->arg[1] <<= 16; ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[ra]); break; case PPC_HI6_ORI: case PPC_HI6_ORIS: case PPC_HI6_XORI: case PPC_HI6_XORIS: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; if (main_opcode == PPC_HI6_ORI || main_opcode == PPC_HI6_ORIS) ic->f = instr(ori); else ic->f = instr(xori); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); ic->arg[1] = iword & 0xffff; if (main_opcode == PPC_HI6_ORIS || main_opcode == PPC_HI6_XORIS) ic->arg[1] <<= 16; ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[ra]); break; case PPC_HI6_LBZ: case PPC_HI6_LBZU: case PPC_HI6_LHZ: case PPC_HI6_LHZU: case PPC_HI6_LHA: case PPC_HI6_LHAU: case PPC_HI6_LWZ: case PPC_HI6_LWZU: case PPC_HI6_LD: case PPC_HI6_LFD: case PPC_HI6_LFS: case PPC_HI6_STB: case PPC_HI6_STBU: case PPC_HI6_STH: case PPC_HI6_STHU: case PPC_HI6_STW: case PPC_HI6_STWU: case PPC_HI6_STD: case PPC_HI6_STFD: case PPC_HI6_STFS: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; imm = (int16_t)iword; load = 0; zero = 1; size = 0; update = 0; fp = 0; ic->f = NULL; switch (main_opcode) { case PPC_HI6_LBZ: load=1; break; case PPC_HI6_LBZU: load=1; update=1; break; case PPC_HI6_LHA: load=1; size=1; zero=0; break; case PPC_HI6_LHAU: load=1; size=1; zero=0; update=1; break; case PPC_HI6_LHZ: load=1; size=1; break; case PPC_HI6_LHZU: load=1; size=1; update=1; break; case PPC_HI6_LWZ: load=1; size=2; break; case PPC_HI6_LWZU: load=1; size=2; update=1; break; case PPC_HI6_LD: load=1; size=3; break; case PPC_HI6_LFD: load=1; size=3; fp=1;ic->f=instr(lfd);break; case PPC_HI6_LFS: load=1; size=2; fp=1;ic->f=instr(lfs);break; case PPC_HI6_STB: break; case PPC_HI6_STBU: update=1; break; case PPC_HI6_STH: size=1; break; case PPC_HI6_STHU: size=1; update=1; break; case PPC_HI6_STW: size=2; break; case PPC_HI6_STWU: size=2; update=1; break; case PPC_HI6_STD: size=3; break; case PPC_HI6_STFD: size=3; fp=1; ic->f = instr(stfd); break; case PPC_HI6_STFS: size=2; fp=1; ic->f = instr(stfs); break; } if (ic->f == NULL) { ic->f = #ifdef MODE32 ppc32_loadstore #else ppc_loadstore #endif [size + 4*zero + 8*load + (imm==0? 16 : 0) + 32*update]; } if (ra == 0 && update) { if (!cpu->translation_readahead) fatal("TODO: ra=0 && update?\n"); goto bad; } if (fp) ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rs]); else ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); if (ra == 0) ic->arg[1] = (size_t)(&cpu->cd.ppc.zero); else ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[2] = (ssize_t)imm; break; case PPC_HI6_BC: aa_bit = (iword >> 1) & 1; lk_bit = iword & 1; bo = (iword >> 21) & 31; bi = (iword >> 16) & 31; tmp_addr = (int64_t)(int16_t)(iword & 0xfffc); if (aa_bit) { if (!cpu->translation_readahead) fatal("aa_bit: NOT YET\n"); goto bad; } if (lk_bit) { ic->f = instr(bcl); samepage_function = instr(bcl_samepage); } else { ic->f = instr(bc); if ((bo & 0x14) == 0x04) { samepage_function = bo & 8? instr(bc_samepage_simple1) : instr(bc_samepage_simple0); } else samepage_function = instr(bc_samepage); } ic->arg[0] = (ssize_t)(tmp_addr + (addr & 0xffc)); ic->arg[1] = bo; ic->arg[2] = 31-bi; /* Branches are calculated as cur PC + offset. */ /* Special case: branch within the same page: */ { uint64_t mask_within_page = ((PPC_IC_ENTRIES_PER_PAGE-1) << 2) | 3; uint64_t old_pc = addr; uint64_t new_pc = old_pc + (int32_t)tmp_addr; if ((old_pc & ~mask_within_page) == (new_pc & ~mask_within_page)) { ic->f = samepage_function; ic->arg[0] = (size_t) ( cpu->cd.ppc.cur_ic_page + ((new_pc & mask_within_page) >> 2)); } } break; case PPC_HI6_SC: ic->arg[0] = (iword >> 5) & 0x7f; ic->arg[1] = (addr & 0xfff) + 4; if (iword == 0x44ee0002) { /* Special case/magic hack for OpenFirmware emul: */ ic->f = instr(openfirmware); } else ic->f = instr(sc); break; case PPC_HI6_B: aa_bit = (iword & 2) >> 1; lk_bit = iword & 1; tmp_addr = (int64_t)(int32_t)((iword & 0x03fffffc) << 6); tmp_addr = (int64_t)tmp_addr >> 6; if (lk_bit) { if (cpu->machine->show_trace_tree) { ic->f = instr(bl_trace); samepage_function = instr(bl_samepage_trace); } else { ic->f = instr(bl); samepage_function = instr(bl_samepage); } } else { ic->f = instr(b); samepage_function = instr(b_samepage); } ic->arg[0] = (ssize_t)(tmp_addr + (addr & 0xffc)); ic->arg[1] = (addr & 0xffc) + 4; /* Branches are calculated as cur PC + offset. */ /* Special case: branch within the same page: */ { uint64_t mask_within_page = ((PPC_IC_ENTRIES_PER_PAGE-1) << 2) | 3; uint64_t old_pc = addr; uint64_t new_pc = old_pc + (int32_t)tmp_addr; if ((old_pc & ~mask_within_page) == (new_pc & ~mask_within_page)) { ic->f = samepage_function; ic->arg[0] = (size_t) ( cpu->cd.ppc.cur_ic_page + ((new_pc & mask_within_page) >> 2)); } } if (aa_bit) { if (lk_bit) { if (cpu->machine->show_trace_tree) { ic->f = instr(bla_trace); } else { ic->f = instr(bla); } } else { ic->f = instr(ba); } ic->arg[0] = (ssize_t)tmp_addr; } break; case PPC_HI6_19: xo = (iword >> 1) & 1023; switch (xo) { case PPC_19_BCLR: case PPC_19_BCCTR: bo = (iword >> 21) & 31; bi = (iword >> 16) & 31; bh = (iword >> 11) & 3; lk_bit = iword & 1; if (xo == PPC_19_BCLR) { if (lk_bit) ic->f = instr(bclr_l); else { ic->f = instr(bclr); if (!cpu->machine->show_trace_tree && (bo & 0x14) == 0x14) ic->f = instr(bclr_20); } } else { if (!(bo & 4)) { if (!cpu->translation_readahead) fatal("TODO: bclr/bcctr " "bo bit 2 clear!\n"); goto bad; } if (lk_bit) ic->f = instr(bcctr_l); else ic->f = instr(bcctr); } ic->arg[0] = bo; ic->arg[1] = 31 - bi; ic->arg[2] = bh; break; case PPC_19_ISYNC: /* TODO */ ic->f = instr(nop); break; case PPC_19_RFI: ic->f = instr(rfi); break; case PPC_19_RFID: ic->f = instr(rfid); break; case PPC_19_MCRF: bf = (iword >> 23) & 7; bfa = (iword >> 18) & 7; ic->arg[0] = 28 - 4*bf; ic->arg[1] = 28 - 4*bfa; ic->f = instr(mcrf); break; case PPC_19_CRAND: case PPC_19_CRANDC: case PPC_19_CREQV: case PPC_19_CROR: case PPC_19_CRORC: case PPC_19_CRNOR: case PPC_19_CRXOR: switch (xo) { case PPC_19_CRAND: ic->f = instr(crand); break; case PPC_19_CRANDC: ic->f = instr(crandc); break; case PPC_19_CREQV: ic->f = instr(creqv); break; case PPC_19_CROR: ic->f = instr(cror); break; case PPC_19_CRORC: ic->f = instr(crorc); break; case PPC_19_CRNOR: ic->f = instr(crnor); break; case PPC_19_CRXOR: ic->f = instr(crxor); break; } ic->arg[0] = iword; break; default:goto bad; } break; case PPC_HI6_RLWNM: case PPC_HI6_RLWINM: ra = (iword >> 16) & 31; mb = (iword >> 6) & 31; me = (iword >> 1) & 31; rc = iword & 1; mask = 0; for (;;) { mask |= ((uint32_t)0x80000000 >> mb); if (mb == me) break; mb ++; mb &= 31; } switch (main_opcode) { case PPC_HI6_RLWNM: ic->f = rc? instr(rlwnm_dot) : instr(rlwnm); break; case PPC_HI6_RLWINM: ic->f = rc? instr(rlwinm_dot) : instr(rlwinm); break; } ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = mask; ic->arg[2] = (uint32_t)iword; break; case PPC_HI6_RLWIMI: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; ic->f = instr(rlwimi); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[2] = (uint32_t)iword; break; case PPC_HI6_LMW: case PPC_HI6_STMW: /* NOTE: Loads use rt, not rs. */ rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; ic->arg[0] = rs; if (ra == 0) ic->arg[1] = (size_t)(&cpu->cd.ppc.zero); else ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[2] = (int32_t)(int16_t)iword; switch (main_opcode) { case PPC_HI6_LMW: ic->f = instr(lmw); break; case PPC_HI6_STMW: ic->f = instr(stmw); break; } break; case PPC_HI6_30: xo = (iword >> 2) & 7; switch (xo) { case PPC_30_RLDICL: case PPC_30_RLDICR: case PPC_30_RLDIMI: switch (xo) { case PPC_30_RLDICL: ic->f = instr(rldicl); break; case PPC_30_RLDICR: ic->f = instr(rldicr); break; case PPC_30_RLDIMI: ic->f = instr(rldimi); break; } ic->arg[0] = iword; if (cpu->cd.ppc.bits == 32) { if (!cpu->translation_readahead) fatal("TODO: rld* in 32-bit mode?\n"); goto bad; } break; default:goto bad; } break; case PPC_HI6_31: xo = (iword >> 1) & 1023; switch (xo) { case PPC_31_CMPL: case PPC_31_CMP: bf = (iword >> 23) & 7; l_bit = (iword >> 21) & 1; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; if (xo == PPC_31_CMPL) { if (l_bit) ic->f = instr(cmpld); else ic->f = instr(cmplw); } else { if (l_bit) ic->f = instr(cmpd); else { if (bf == 0) ic->f = instr(cmpw_cr0); else ic->f = instr(cmpw); } } ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[rb]); ic->arg[2] = 28 - 4*bf; break; case PPC_31_CNTLZW: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; rc = iword & 1; if (rc) { if (!cpu->translation_readahead) fatal("TODO: rc\n"); goto bad; } ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->f = instr(cntlzw); break; case PPC_31_MFSPR: rt = (iword >> 21) & 31; spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); debug_spr_usage(cpu->pc, spr); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rt]); ic->arg[1] = (size_t)(&cpu->cd.ppc.spr[spr]); switch (spr) { // Reuse SPR_TB* for TBR_TB*: case TBR_TBL: ic->f = instr(mftb); break; case TBR_TBU: ic->f = instr(mftbu); break; case SPR_PMC1: ic->f = instr(mfspr_pmc1); break; default: ic->f = instr(mfspr); } break; case PPC_31_MTSPR: rs = (iword >> 21) & 31; spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); debug_spr_usage(cpu->pc, spr); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); ic->arg[1] = (size_t)(&cpu->cd.ppc.spr[spr]); switch (spr) { case SPR_LR: ic->f = instr(mtlr); break; case SPR_CTR: ic->f = instr(mtctr); break; case SPR_SPRG2: ic->f = instr(mtspr_sprg2); break; default:ic->f = instr(mtspr); } break; case PPC_31_MFCR: rt = (iword >> 21) & 31; ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rt]); ic->f = instr(mfcr); break; case PPC_31_MFMSR: rt = (iword >> 21) & 31; ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rt]); ic->f = instr(mfmsr); break; case PPC_31_MTMSR: case PPC_31_MTMSRD: rs = (iword >> 21) & 31; l_bit = (iword >> 16) & 1; if (l_bit) { if (!cpu->translation_readahead) fatal("TODO: mtmsr l-bit\n"); goto bad; } ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); ic->arg[1] = (addr & 0xfff) + 4; ic->arg[2] = xo == PPC_31_MTMSRD; ic->f = instr(mtmsr); break; case PPC_31_MTCRF: rs = (iword >> 21) & 31; { int i, fxm = (iword >> 12) & 255; uint32_t tmp = 0; for (i=0; i<8; i++, fxm <<= 1) { tmp <<= 4; if (fxm & 128) tmp |= 0xf; } ic->arg[1] = (uint32_t)tmp; } ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); ic->f = instr(mtcrf); break; case PPC_31_MFSRIN: case PPC_31_MTSRIN: rt = (iword >> 21) & 31; rb = (iword >> 11) & 31; ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rb]); ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[rt]); switch (xo) { case PPC_31_MFSRIN: ic->f = instr(mfsrin); break; case PPC_31_MTSRIN: ic->f = instr(mtsrin); break; } if (cpu->cd.ppc.bits == 64) { if (!cpu->translation_readahead) fatal("Not yet for 64-bit mode\n"); goto bad; } break; case PPC_31_MFSR: case PPC_31_MTSR: rt = (iword >> 21) & 31; ic->arg[0] = (iword >> 16) & 15; ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[rt]); switch (xo) { case PPC_31_MFSR: ic->f = instr(mfsr); break; case PPC_31_MTSR: ic->f = instr(mtsr); break; } if (cpu->cd.ppc.bits == 64) { if (!cpu->translation_readahead) fatal("Not yet for 64-bit mode\n"); goto bad; } break; case PPC_31_SRAWI: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; sh = (iword >> 11) & 31; rc = iword & 1; ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[2] = sh; if (rc) ic->f = instr(srawi_dot); else ic->f = instr(srawi); break; case PPC_31_SYNC: case PPC_31_DSSALL: case PPC_31_EIEIO: case PPC_31_DCBST: case PPC_31_DCBTST: case PPC_31_DCBF: case PPC_31_DCBT: case PPC_31_ICBI: ic->f = instr(nop); break; case PPC_31_DCBZ: ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; if (ra == 0) ic->arg[0] = (size_t)(&cpu->cd.ppc.zero); else ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[rb]); ic->arg[2] = addr & 0xfff; ic->f = instr(dcbz); break; case PPC_31_TLBIA: ic->f = instr(tlbia); break; case PPC_31_TLBSYNC: /* According to IBM, "Ensures that a tlbie and tlbia instruction executed by one processor has completed on all other processors.", which in GXemul means a nop :-) */ ic->f = instr(nop); break; case PPC_31_TLBIE: /* TODO: POWER also uses ra? */ rb = (iword >> 11) & 31; ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rb]); ic->f = instr(tlbie); break; case PPC_31_TLBLD: /* takes an arg */ rb = (iword >> 11) & 31; ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rb]); ic->f = instr(tlbld); break; case PPC_31_TLBLI: /* takes an arg */ rb = (iword >> 11) & 31; ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rb]); ic->f = instr(tlbli); break; case PPC_31_TLBSX_DOT: /* TODO */ ic->f = instr(tlbsx_dot); break; case PPC_31_MFTB: rt = (iword >> 21) & 31; spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rt]); switch (spr) { case 268: ic->f = instr(mftb); break; case 269: ic->f = instr(mftbu); break; default:if (!cpu->translation_readahead) fatal("mftb spr=%i?\n", spr); goto bad; } break; case PPC_31_NEG: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; rc = iword & 1; ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[rt]); if (rc) ic->f = instr(neg_dot); else ic->f = instr(neg); break; case PPC_31_LWARX: case PPC_31_LDARX: case PPC_31_STWCX_DOT: case PPC_31_STDCX_DOT: ic->arg[0] = iword; ic->f = instr(llsc); break; case PPC_31_LSWI: case PPC_31_STSWI: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; nb = (iword >> 11) & 31; ic->arg[0] = rs; if (ra == 0) ic->arg[1] = (size_t)(&cpu->cd.ppc.zero); else ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[2] = nb == 0? 32 : nb; switch (xo) { case PPC_31_LSWI: ic->f = instr(lswi); break; case PPC_31_STSWI: ic->f = instr(stswi); break; } break; case PPC_31_WRTEEI: ic->arg[0] = iword & 0x8000; ic->f = instr(wrteei); break; case 0x1c3: fatal("[ mtdcr: TODO ]\n"); ic->f = instr(nop); break; case PPC_31_LBZX: case PPC_31_LBZUX: case PPC_31_LHAX: case PPC_31_LHAUX: case PPC_31_LHZX: case PPC_31_LHZUX: case PPC_31_LWZX: case PPC_31_LWZUX: case PPC_31_LHBRX: case PPC_31_LWBRX: case PPC_31_LFDX: case PPC_31_LFSX: case PPC_31_STBX: case PPC_31_STBUX: case PPC_31_STHX: case PPC_31_STHUX: case PPC_31_STWX: case PPC_31_STWUX: case PPC_31_STDX: case PPC_31_STDUX: case PPC_31_STHBRX: case PPC_31_STWBRX: case PPC_31_STFDX: case PPC_31_STFSX: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; if (ra == 0) ic->arg[1] = (size_t)(&cpu->cd.ppc.zero); else ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[rb]); load = 0; zero = 1; size = 0; update = 0; byterev = 0; fp = 0; ic->f = NULL; switch (xo) { case PPC_31_LBZX: load = 1; break; case PPC_31_LBZUX: load=update=1; break; case PPC_31_LHAX: size=1; load=1; zero=0; break; case PPC_31_LHAUX: size=1; load=update=1; zero=0; break; case PPC_31_LHZX: size=1; load=1; break; case PPC_31_LHZUX: size=1; load=update = 1; break; case PPC_31_LWZX: size=2; load=1; break; case PPC_31_LWZUX: size=2; load=update = 1; break; case PPC_31_LHBRX: size=1; load=1; byterev=1; ic->f = instr(lhbrx); break; case PPC_31_LWBRX: size=2; load=1; byterev=1; ic->f = instr(lwbrx); break; case PPC_31_LFDX: size=3; load=1; fp=1; ic->f = instr(lfdx); break; case PPC_31_LFSX: size=2; load=1; fp=1; ic->f = instr(lfsx); break; case PPC_31_STBX: break; case PPC_31_STBUX: update = 1; break; case PPC_31_STHX: size=1; break; case PPC_31_STHUX: size=1; update = 1; break; case PPC_31_STWX: size=2; break; case PPC_31_STWUX: size=2; update = 1; break; case PPC_31_STDX: size=3; break; case PPC_31_STDUX: size=3; update = 1; break; case PPC_31_STHBRX:size=1; byterev = 1; ic->f = instr(sthbrx); break; case PPC_31_STWBRX:size=2; byterev = 1; ic->f = instr(stwbrx); break; case PPC_31_STFDX: size=3; fp=1; ic->f = instr(stfdx); break; case PPC_31_STFSX: size=2; fp=1; ic->f = instr(stfsx); break; } if (fp) ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rs]); else ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); if (!byterev && ic->f == NULL) { ic->f = #ifdef MODE32 ppc32_loadstore_indexed #else ppc_loadstore_indexed #endif [size + 4*zero + 8*load + 16*update]; } if (ra == 0 && update) { if (!cpu->translation_readahead) fatal("TODO: ra=0 && update?\n"); goto bad; } break; case PPC_31_EXTSB: case PPC_31_EXTSH: case PPC_31_EXTSW: case PPC_31_SLW: case PPC_31_SLD: case PPC_31_SRAW: case PPC_31_SRW: case PPC_31_AND: case PPC_31_NAND: case PPC_31_ANDC: case PPC_31_NOR: case PPC_31_OR: case PPC_31_ORC: case PPC_31_XOR: case PPC_31_EQV: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; rc = iword & 1; rc_f = NULL; switch (xo) { case PPC_31_EXTSB:ic->f = instr(extsb); rc_f = instr(extsb_dot); break; case PPC_31_EXTSH:ic->f = instr(extsh); rc_f = instr(extsh_dot); break; case PPC_31_EXTSW:ic->f = instr(extsw); rc_f = instr(extsw_dot); break; case PPC_31_SLW: ic->f = instr(slw); rc_f = instr(slw_dot); break; case PPC_31_SLD: ic->f = instr(sld); rc_f = instr(sld_dot); break; case PPC_31_SRAW: ic->f = instr(sraw); rc_f = instr(sraw_dot); break; case PPC_31_SRW: ic->f = instr(srw); rc_f = instr(srw_dot); break; case PPC_31_AND: ic->f = instr(and); rc_f = instr(and_dot); break; case PPC_31_NAND: ic->f = instr(nand); rc_f = instr(nand_dot); break; case PPC_31_ANDC: ic->f = instr(andc); rc_f = instr(andc_dot); break; case PPC_31_NOR: ic->f = instr(nor); rc_f = instr(nor_dot); break; case PPC_31_OR: ic->f = rs == rb? instr(mr) : instr(or); rc_f = instr(or_dot); break; case PPC_31_ORC: ic->f = instr(orc); rc_f = instr(orc_dot); break; case PPC_31_XOR: ic->f = instr(xor); rc_f = instr(xor_dot); break; case PPC_31_EQV: ic->f = instr(eqv); rc_f = instr(eqv_dot); break; } ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[rb]); ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[ra]); if (rc) ic->f = rc_f; break; case PPC_31_MULLW: case PPC_31_MULHW: case PPC_31_MULHWU: case PPC_31_DIVW: case PPC_31_DIVWU: case PPC_31_ADD: case PPC_31_ADDC: case PPC_31_ADDE: case PPC_31_ADDME: case PPC_31_ADDZE: case PPC_31_SUBF: case PPC_31_SUBFC: case PPC_31_SUBFE: case PPC_31_SUBFME: case PPC_31_SUBFZE: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; oe_bit = (iword >> 10) & 1; rc = iword & 1; if (oe_bit) { if (!cpu->translation_readahead) fatal("oe_bit not yet implemented\n"); goto bad; } switch (xo) { case PPC_31_MULLW: ic->f = instr(mullw); break; case PPC_31_MULHW: ic->f = instr(mulhw); break; case PPC_31_MULHWU: ic->f = instr(mulhwu); break; case PPC_31_DIVW: ic->f = instr(divw); n64=1; break; case PPC_31_DIVWU: ic->f = instr(divwu); n64=1; break; case PPC_31_ADD: ic->f = instr(add); break; case PPC_31_ADDC: ic->f = instr(addc); n64=1; break; case PPC_31_ADDE: ic->f = instr(adde); n64=1; break; case PPC_31_ADDME: ic->f = instr(addme); n64=1; break; case PPC_31_ADDZE: ic->f = instr(addze); n64=1; break; case PPC_31_SUBF: ic->f = instr(subf); break; case PPC_31_SUBFC: ic->f = instr(subfc); break; case PPC_31_SUBFE: ic->f = instr(subfe); n64=1; break; case PPC_31_SUBFME: ic->f = instr(subfme); n64=1; break; case PPC_31_SUBFZE: ic->f = instr(subfze); n64=1;break; } if (rc) { switch (xo) { case PPC_31_ADD: ic->f = instr(add_dot); break; case PPC_31_ADDE: ic->f = instr(adde_dot); break; case PPC_31_ADDME: ic->f = instr(addme_dot); break; case PPC_31_ADDZE: ic->f = instr(addze_dot); break; case PPC_31_DIVW: ic->f = instr(divw_dot); break; case PPC_31_DIVWU: ic->f = instr(divwu_dot); break; case PPC_31_MULLW: ic->f = instr(mullw_dot); break; case PPC_31_MULHW: ic->f = instr(mulhw_dot); break; case PPC_31_MULHWU: ic->f = instr(mulhwu_dot); break; case PPC_31_SUBF: ic->f = instr(subf_dot); break; case PPC_31_SUBFC: ic->f = instr(subfc_dot); break; case PPC_31_SUBFE: ic->f = instr(subfe_dot); break; case PPC_31_SUBFME: ic->f = instr(subfme_dot); break; case PPC_31_SUBFZE: ic->f = instr(subfze_dot); break; default:if (!cpu->translation_readahead) fatal("RC bit not yet " "implemented\n"); goto bad; } } ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[rb]); ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[rt]); if (cpu->cd.ppc.bits == 64 && n64) { if (!cpu->translation_readahead) fatal("Not yet for 64-bit mode\n"); goto bad; } break; case PPC_31_LVX: case PPC_31_LVXL: case PPC_31_STVX: case PPC_31_STVXL: load = 0; switch (xo) { case PPC_31_LVX: case PPC_31_LVXL: load = 1; break; } rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; ic->arg[0] = rs; if (ra == 0) ic->arg[1] = (size_t)(&cpu->cd.ppc.zero); else ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[rb]); ic->f = load? instr(lvx) : instr(stvx); break; default:goto bad; } break; case PPC_HI6_59: xo = (iword >> 1) & 1023; rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; rs = (iword >> 6) & 31; /* actually frc */ rc = iword & 1; if (rc) { if (!cpu->translation_readahead) fatal("Floating point (59) " "with rc bit! TODO\n"); goto bad; } /* NOTE: Some floating-point instructions are selected using only the lowest 5 bits, not all 10! */ switch (xo & 31) { case PPC_59_FDIVS: case PPC_59_FSUBS: case PPC_59_FADDS: switch (xo & 31) { case PPC_59_FDIVS: ic->f = instr(fdivs); break; case PPC_59_FSUBS: ic->f = instr(fsubs); break; case PPC_59_FADDS: ic->f = instr(fadds); break; } ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[ra]); ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[rb]); ic->arg[2] = (size_t)(&cpu->cd.ppc.fpr[rt]); break; case PPC_59_FMULS: ic->f = instr(fmuls); ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rt]); ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[ra]); ic->arg[2] = (size_t)(&cpu->cd.ppc.fpr[rs]); /* frc */ break; default:/* Use all 10 bits of xo: */ switch (xo) { default:goto bad; } } break; case PPC_HI6_63: xo = (iword >> 1) & 1023; rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; rs = (iword >> 6) & 31; /* actually frc */ rc = iword & 1; if (rc) { if (!cpu->translation_readahead) fatal("Floating point (63) " "with rc bit! TODO\n"); goto bad; } /* NOTE: Some floating-point instructions are selected using only the lowest 5 bits, not all 10! */ switch (xo & 31) { case PPC_63_FDIV: case PPC_63_FSUB: case PPC_63_FADD: switch (xo & 31) { case PPC_63_FDIV: ic->f = instr(fdiv); break; case PPC_63_FSUB: ic->f = instr(fsub); break; case PPC_63_FADD: ic->f = instr(fadd); break; } ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[ra]); ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[rb]); ic->arg[2] = (size_t)(&cpu->cd.ppc.fpr[rt]); break; case PPC_63_FMUL: ic->f = instr(fmul); ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rt]); ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[ra]); ic->arg[2] = (size_t)(&cpu->cd.ppc.fpr[rs]); /* frc */ break; case PPC_63_FMSUB: case PPC_63_FMADD: switch (xo & 31) { case PPC_63_FMSUB: ic->f = instr(fmsub); break; case PPC_63_FMADD: ic->f = instr(fmadd); break; } ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rt]); ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[ra]); ic->arg[2] = iword; break; default:/* Use all 10 bits of xo: */ switch (xo) { case PPC_63_FCMPU: ic->f = instr(fcmpu); ic->arg[0] = 28 - 4*(rt >> 2); ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[ra]); ic->arg[2] = (size_t)(&cpu->cd.ppc.fpr[rb]); break; case PPC_63_FRSP: case PPC_63_FCTIWZ: case PPC_63_FNEG: case PPC_63_FABS: case PPC_63_FMR: switch (xo) { case PPC_63_FRSP: ic->f = instr(frsp); break; case PPC_63_FCTIWZ: ic->f = instr(fctiwz);break; case PPC_63_FNEG: ic->f = instr(fneg); break; case PPC_63_FABS: ic->f = instr(fabs); break; case PPC_63_FMR: ic->f = instr(fmr); break; } ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rb]); ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[rt]); break; case PPC_63_MFFS: ic->f = instr(mffs); ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rt]); break; case PPC_63_MTFSF: ic->f = instr(mtfsf); ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rb]); ic->arg[1] = 0; for (bi=7; bi>=0; bi--) { ic->arg[1] <<= 8; if (iword & (1 << (17+bi))) ic->arg[1] |= 0xf; } break; default:goto bad; } } break; default:goto bad; } #define DYNTRANS_TO_BE_TRANSLATED_TAIL #include "cpu_dyntrans.cc" #undef DYNTRANS_TO_BE_TRANSLATED_TAIL } gxemul-0.6.1/src/cpus/generate_mips_loadstore_multi.c000644 001750 001750 00000006713 13402411502 023251 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include void generate_multi(int store, int endianness, int n) { int i, nr; printf("X(multi_%cw_%i_%ce)\n{\n", store? 's' : 'l', n, endianness? 'b' : 'l'); printf("\tuint32_t *page;\n" "\tMODE_uint_t rX = reg(ic[0].arg[1])"); for (i=0; i> 12;\n", i, i); printf("\tpage = (uint32_t *) cpu->cd.mips.host_%s[index0];\n", store? "store" : "load"); printf("\tif (cpu->delay_slot ||\n" "\t page == NULL"); for (i=0; i> 2) & 0x3ff;\n", i, i); if (store) { for (i=0; in_translated_instrs += %i;\n", n - 1); printf("\tcpu->cd.mips.next_ic += %i;\n", n - 1); printf("}\n\n"); } int main(int argc, char *argv[]) { int store, endianness, n; printf("\n/* AUTOMATICALLY GENERATED! Do not edit. */\n\n"); for (endianness=0; endianness<=1; endianness++) for (store=0; store<=1; store++) for (n=2; n<=4; n++) generate_multi(store, endianness, n); return 0; } gxemul-0.6.1/src/cpus/generate_arm_loadstore.c000644 001750 001750 00000027633 13402411502 021652 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include char *cond[16] = { "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "", "" }; int main(int argc, char *argv[]) { int l, b, w=0, h, s, u=0, p=0, reg, c, n; int only_array = 0; if (argc == 1) { only_array = 1; } else { if (argc != 4) { fprintf(stderr, "puw missing?\n"); exit(1); } p = atoi(argv[1]); u = atoi(argv[2]); w = atoi(argv[3]); } printf("\n/* AUTOMATICALLY GENERATED! Do not edit. */\n\n"); printf("#include \n#include \n" "#include \"cpu.h\"\n" "#include \"machine.h\"\n" "#include \"memory.h\"\n" "#include \"misc.h\"\n" "#define DYNTRANS_PC_TO_POINTERS arm_pc_to_pointers\n" "#include \"quick_pc_to_pointers.h\"\n" "#define reg(x) (*((uint32_t *)(x)))\n"); printf("extern void arm_instr_nop(struct cpu *, " "struct arm_instr_call *);\n"); printf("extern void arm_instr_invalid(struct cpu *, " "struct arm_instr_call *);\n"); printf("extern void arm_pc_to_pointers(struct cpu *);\n"); if (!only_array) for (reg=0; reg<=1; reg++) for (b=0; b<=1; b++) for (l=0; l<=1; l++) { printf("#define A__NAME__general arm_instr_%s_" "%s_%s_%s_%s_%s__general\n", l?"load":"store", w? "w1" : "w0", b? "byte" : "word", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm"); printf("#define A__NAME arm_instr_%s_%s_%s_%s_%s_%s\n", l? "load" : "store", w? "w1" : "w0", b? "byte" : "word", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm"); for (c=0; c<14; c++) printf("#define A__NAME__%s arm_instr_%s_" "%s_%s_%s_%s_%s__%s\n", cond[c], l?"load":"store", w? "w1" : "w0", b? "byte" : "word", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm",cond[c]); printf("#define A__NAME_PC arm_instr_%s_%s_%s_%s_" "%s_%s_pc\n", l? "load" : "store", w? "w1" : "w0", b? "byte" : "word", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm"); for (c=0; c<14; c++) printf("#define A__NAME_PC__%s arm_instr_%s_" "%s_%s_%s_%s_%s_pc__%s\n", cond[c], l?"load":"store", w? "w1" : "w0", b? "byte" : "word", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm",cond[c]); if (l) printf("#define A__L\n"); if (w) printf("#define A__W\n"); if (b) printf("#define A__B\n"); if (u) printf("#define A__U\n"); if (p) printf("#define A__P\n"); if (reg)printf("#define A__REG\n"); printf("#include \"cpu_arm_instr_loadstore.cc\"\n"); if (l) printf("#undef A__L\n"); if (w) printf("#undef A__W\n"); if (b) printf("#undef A__B\n"); if (u) printf("#undef A__U\n"); if (p) printf("#undef A__P\n"); if (reg)printf("#undef A__REG\n"); for (c=0; c<14; c++) printf("#undef A__NAME__%s\n", cond[c]); for (c=0; c<14; c++) printf("#undef A__NAME_PC__%s\n", cond[c]); printf("#undef A__NAME__general\n"); printf("#undef A__NAME_PC\n"); printf("#undef A__NAME\n"); } if (only_array) { for (reg=0; reg<=1; reg++) for (p=0; p<=1; p++) for (u=0; u<=1; u++) for (b=0; b<=1; b++) for (w=0; w<=1; w++) for (l=0; l<=1; l++) for (c=0; c<16; c++) { if (c == 15) continue; printf("void arm_instr_%s_%s_%s" "_%s_%s_%s%s%s(struct cpu *, struct " "arm_instr_call *);", l? "load" : "store", w? "w1" : "w0", b? "byte" : "word", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm", c!=14? "__" : "", cond[c]); printf("void arm_instr_%s_%s_%s_%s_%s_%s_pc%s%s" "(struct cpu *, struct " "arm_instr_call *);\n", l? "load" : "store", w? "w1" : "w0", b? "byte" : "word", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm", c!=14? "__" : "", cond[c]); } printf("\n\tvoid (*arm_load_store_instr[1024])(struct cpu *,\n" "\t\tstruct arm_instr_call *) = {\n"); n = 0; for (reg=0; reg<=1; reg++) for (p=0; p<=1; p++) for (u=0; u<=1; u++) for (b=0; b<=1; b++) for (w=0; w<=1; w++) for (l=0; l<=1; l++) for (c=0; c<16; c++) { if (c == 15) printf("\tarm_instr_nop"); else printf("\tarm_instr_%s_%s_%s" "_%s_%s_%s%s%s", l? "load" : "store", w? "w1" : "w0", b? "byte" : "word", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm", c!=14? "__" : "", cond[c]); n++; if (n!=2*2*2*2*2*2*16) printf(","); printf("\n"); } printf("};\n\n"); /* Load/store with the pc register: */ printf("\n\tvoid (*arm_load_store_instr_pc[1024])" "(struct cpu *,\n\t\tstruct arm_instr_call *) = {\n"); n = 0; for (reg=0; reg<=1; reg++) for (p=0; p<=1; p++) for (u=0; u<=1; u++) for (b=0; b<=1; b++) for (w=0; w<=1; w++) for (l=0; l<=1; l++) for (c=0; c<16; c++) { if (c == 15) printf("\tarm_instr_nop"); else printf("\tarm_instr_%s_%s_%s_" "%s_%s_%s_pc%s%s", l? "load" : "store", w? "w1" : "w0", b? "byte" : "word", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm", c!=14? "__" : "", cond[c]); n++; if (n!=2*2*2*2*2*2*16) printf(","); printf("\n"); } printf("};\n\n"); } /* "Addressing mode 3": */ if (!only_array) for (reg=0; reg<=1; reg++) for (h=0; h<=1; h++) for (s=0; s<=1; s++) for (l=0; l<=1; l++) { if (s==0 && h==0) continue; /* l=0, s=1, h=0 means LDRD */ /* l=0, s=1, h=1 means STRD */ printf("#define A__NAME__general arm_instr_%s_" "%s_%s_%s_%s_%s_%s__general\n", l?"load":"store", w? "w1" : "w0", s? "signed" : "unsigned", h? "halfword" : "byte", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm"); printf("#define A__NAME arm_instr_%s_%s_%s_%s_" "%s_%s_%s\n", l? "load" : "store", w? "w1" : "w0", s? "signed" : "unsigned", h? "halfword" : "byte", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm"); for (c=0; c<14; c++) printf("#define A__NAME__%s arm_instr_%s_" "%s_%s_%s_%s_%s_%s__%s\n", cond[c], l?"load":"store", w? "w1" : "w0", s? "signed" : "unsigned", h? "halfword" : "byte", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm",cond[c]); printf("#define A__NAME_PC arm_instr_%s_%s_%s_%s_%s_" "%s_%s_pc\n", l? "load" : "store", w? "w1" : "w0", s? "signed" : "unsigned", h? "halfword" : "byte", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm"); for (c=0; c<14; c++) printf("#define A__NAME_PC__%s arm_instr_%s_" "%s_%s_%s_%s_%s_%s_pc__%s\n", cond[c], l?"load":"store", w? "w1" : "w0", s? "signed" : "unsigned", h? "halfword" : "byte", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm",cond[c]); if (s) printf("#define A__SIGNED\n"); if (l) printf("#define A__L\n"); if (w) printf("#define A__W\n"); if (h) printf("#define A__H\n"); else printf("#define A__B\n"); if (u) printf("#define A__U\n"); if (p) printf("#define A__P\n"); if (reg)printf("#define A__REG\n"); printf("#include \"cpu_arm_instr_loadstore.cc\"\n"); if (s) printf("#undef A__SIGNED\n"); if (l) printf("#undef A__L\n"); if (w) printf("#undef A__W\n"); if (h) printf("#undef A__H\n"); else printf("#undef A__B\n"); if (u) printf("#undef A__U\n"); if (p) printf("#undef A__P\n"); if (reg)printf("#undef A__REG\n"); for (c=0; c<14; c++) printf("#undef A__NAME__%s\n", cond[c]); for (c=0; c<14; c++) printf("#undef A__NAME_PC__%s\n", cond[c]); printf("#undef A__NAME__general\n"); printf("#undef A__NAME_PC\n"); printf("#undef A__NAME\n"); } if (only_array) { for (reg=0; reg<=1; reg++) for (p=0; p<=1; p++) for (u=0; u<=1; u++) for (h=0; h<=1; h++) for (w=0; w<=1; w++) for (s=0; s<=1; s++) for (l=0; l<=1; l++) for (c=0; c<16; c++) { if (c == 15) continue; else if (s==0 && h==0) continue; printf("void arm_instr_%s_%s_%s_%s_%s_%s_%s%s%s" "(struct cpu *, struct arm_instr_call *);\n", l? "load" : "store", w? "w1" : "w0", s? "signed" : "unsigned", h? "halfword" : "byte", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm", c!=14? "__" : "", cond[c]); printf("void arm_instr_%s_%s_%s_%s_%s_%s_" "%s_pc%s%s(struct cpu *, struct " "arm_instr_call *);\n", l? "load" : "store", w? "w1" : "w0", s? "signed" : "unsigned", h? "halfword" : "byte", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm", c!=14? "__" : "", cond[c]); } printf("\n\tvoid (*arm_load_store_instr_3[2048])" "(struct cpu *,\n\t\tstruct arm_instr_call *) = {\n"); n = 0; for (reg=0; reg<=1; reg++) for (p=0; p<=1; p++) for (u=0; u<=1; u++) for (h=0; h<=1; h++) for (w=0; w<=1; w++) for (s=0; s<=1; s++) for (l=0; l<=1; l++) for (c=0; c<16; c++) { if (c == 15) printf("\tarm_instr_nop"); else if (s==0 && h==0) printf("\tarm_instr_invalid"); else printf("\tarm_instr_%s_%s_%s_%s_" "%s_%s_%s%s%s", l? "load" : "store", w? "w1" : "w0", s? "signed" : "unsigned", h? "halfword" : "byte", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm", c!=14? "__" : "", cond[c]); n++; if (n!=2*2*2*2*2*2*2*16) printf(","); printf("\n"); } printf("};\n\n"); /* Load/store with the pc register: */ printf("\n\tvoid (*arm_load_store_instr_3_pc[2048])" "(struct cpu *,\n\t\tstruct arm_instr_call *) = {\n"); n = 0; for (reg=0; reg<=1; reg++) for (p=0; p<=1; p++) for (u=0; u<=1; u++) for (h=0; h<=1; h++) for (w=0; w<=1; w++) for (s=0; s<=1; s++) for (l=0; l<=1; l++) for (c=0; c<16; c++) { if (c == 15) printf("\tarm_instr_nop"); else if (s==0 && h==0) printf("\tarm_instr_invalid"); else printf("\tarm_instr_%s_%s_%s_%s_%s_%s_" "%s_pc%s%s", l? "load" : "store", w? "w1" : "w0", s? "signed" : "unsigned", h? "halfword" : "byte", u? "u1" : "u0", p? "p1" : "p0", reg? "reg" : "imm", c!=14? "__" : "", cond[c]); n++; if (n!=2*2*2*2*2*2*2*16) printf(","); printf("\n"); } printf("};\n\n"); } return 0; } gxemul-0.6.1/src/cpus/cpu_arm_instr_dpi.cc000644 001750 001750 00000024212 13402411502 020777 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2012 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * ARM Data Processing Instructions * -------------------------------- * * xxxx000a aaaSnnnn ddddcccc ctttmmmm Register form * xxxx001a aaaSnnnn ddddrrrr bbbbbbbb Immediate form * * 4 bits to select which instruction, one of the following: * * 0000 and 1000 tst * 0001 eor 1001 teq * 0010 sub 1010 cmp * 0011 rsb 1011 cmn * 0100 add 1100 orr * 0101 adc 1101 mov * 0110 sbc 1110 bic * 0111 rsc 1111 mvn * * 1 bit to select Status flag update. * * 1 bit to select Register form or Immediate form. * * 1 bit to select if the PC register is used. * * Each function must also (as always) be repeated for each possible ARM * condition code (15 in total). Total: 1920 functions. * * NOTE: This does not include any special common cases, which might be * nice to have. Examples: comparing against zero, moving common * constants. * * See src/tools/generate_arm_dpi.c for more details. */ #ifndef NOTHING #define NOTHING // Used to break out of dyntrans. TODO: Duplicate of arm_instr_nothing // code in tmp_arm_head.cc. void abortdyntrans(struct cpu* cpu, struct arm_instr_call* ic) { cpu->cd.arm.next_ic --; } static struct arm_instr_call abortdyntrans_call = { abortdyntrans, {0,0,0} }; #endif // NOTHING /* * arg[0] = pointer to rn * arg[1] = int32_t immediate value OR ptr to a reg_func() function * arg[2] = pointer to rd */ void A__NAME(struct cpu *cpu, struct arm_instr_call *ic) { #if defined(A__RSB) || defined(A__RSC) #define VAR_A b #define VAR_B a #else #define VAR_A a #define VAR_B b #endif #ifdef A__REG uint32_t (*reg_func)(struct cpu *, struct arm_instr_call *) = (uint32_t (*)(struct cpu *, struct arm_instr_call *)) (void *)(size_t)ic->arg[1]; #endif #ifdef A__S uint32_t c32; #endif #if defined(A__CMP) || defined(A__CMN) || defined(A__ADC) || defined(A__ADD) \ || defined(A__RSC) || defined(A__RSB) || defined(A__SBC) || defined(A__SUB) #ifdef A__S uint64_t #else uint32_t #endif #else uint32_t #endif VAR_B = #ifdef A__REG reg_func(cpu, ic) #else #ifdef A__REGSHORT reg(ic->arg[1]) #else ic->arg[1] #endif #endif , c64 #if !defined(A__MOV) && !defined(A__MVN) , VAR_A = reg(ic->arg[0]) #endif ; #if defined(A__MOV) || defined(A__MVN) || defined(A__TST) || defined(A__TEQ) \ || defined(A__AND) || defined(A__BIC) || defined(A__EOR) || defined(A__ORR) #if !defined(A__REG) && !defined(A__REGSHORT) && defined(A__S) /* * TODO: This is not 100% correct, but should work with "recommended" * ARM code: Immediate values larger than 255 are encoded with * rotation. If the S-bit is set, then the carry bit is set to the * highest bit of the operand. * * TODO 2: Perhaps this check should be moved out from here, and into * cpu_arm_instr.c. (More correct, and higher performance.) */ if (VAR_B > 255) { if (VAR_B & 0x80000000) cpu->cd.arm.flags |= ARM_F_C; else cpu->cd.arm.flags &= ~ARM_F_C; } #endif #endif #if !defined(A__MOV) && !defined(A__MVN) #ifdef A__PC if (ic->arg[0] == (size_t)&cpu->cd.arm.r[ARM_PC]) { uint32_t low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); VAR_A = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); VAR_A += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT) + 8; } #endif #endif /* * Perform the operation: */ #if defined(A__AND) || defined(A__TST) c64 = a & b; #endif #if defined(A__EOR) || defined(A__TEQ) c64 = a ^ b; #endif #if defined(A__SUB) || defined(A__CMP) || defined(A__RSB) c64 = a - b; #endif #if defined(A__ADD) || defined(A__CMN) c64 = a + b; #endif #if defined(A__ADC) c64 = a + b + (cpu->cd.arm.flags & ARM_F_C? 1 : 0); #endif #if defined(A__SBC) || defined(A__RSC) b += (cpu->cd.arm.flags & ARM_F_C? 0 : 1); c64 = a - b; #endif #if defined(A__ORR) c64 = a | b; #endif #if defined(A__MOV) c64 = b; #endif #if defined(A__BIC) c64 = a & ~b; #endif #if defined(A__MVN) c64 = ~b; #endif #if defined(A__CMP) || defined(A__CMN) || defined(A__TST) || defined(A__TEQ) /* No write to rd for compare/test. */ #else #ifdef A__PC if (ic->arg[2] == (size_t)&cpu->cd.arm.r[ARM_PC]) { #ifndef A__S uint32_t old_pc = cpu->pc; uint32_t mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT) | ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1); #endif cpu->pc = (uint32_t)c64; #ifdef A__S /* Copy the right SPSR into CPSR: */ arm_save_register_bank(cpu); switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) { case ARM_MODE_FIQ32: cpu->cd.arm.cpsr = cpu->cd.arm.spsr_fiq; break; case ARM_MODE_IRQ32: cpu->cd.arm.cpsr = cpu->cd.arm.spsr_irq; break; case ARM_MODE_SVC32: cpu->cd.arm.cpsr = cpu->cd.arm.spsr_svc; break; case ARM_MODE_ABT32: cpu->cd.arm.cpsr = cpu->cd.arm.spsr_abt; break; case ARM_MODE_UND32: cpu->cd.arm.cpsr = cpu->cd.arm.spsr_und; break; } cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28; arm_load_register_bank(cpu); #else if ((old_pc & ~mask_within_page) == ((uint32_t)cpu->pc & ~mask_within_page)) { cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page + ((cpu->pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT); } else #endif quick_pc_to_pointers(cpu); if (cpu->pc & 1) { // Switch to THUMB and break out of the dyntrans loop. cpu->cd.arm.cpsr |= ARM_FLAG_T; cpu->cd.arm.next_ic = &abortdyntrans_call; } return; } else reg(ic->arg[2]) = c64; #else reg(ic->arg[2]) = c64; #endif #endif /* * Status flag update (if the S-bit is set): */ #ifdef A__S c32 = c64; cpu->cd.arm.flags #if defined(A__CMP) || defined(A__CMN) || defined(A__ADC) || defined(A__ADD) \ || defined(A__RSB) || defined(A__RSC) || defined(A__SBC) || defined(A__SUB) &= ~(ARM_F_V | ARM_F_C | ARM_F_Z | ARM_F_N); #else &= ~(ARM_F_Z | ARM_F_N); #endif #if defined(A__CMP) || defined(A__RSB) || defined(A__SUB) || \ defined(A__RSC) || defined(A__SBC) if ((uint32_t)a >= (uint32_t)b) cpu->cd.arm.flags |= ARM_F_C; #else #if defined(A__ADC) || defined(A__ADD) || defined(A__CMN) if (c32 != c64) cpu->cd.arm.flags |= ARM_F_C; #endif #endif if (c32 == 0) cpu->cd.arm.flags |= ARM_F_Z; if ((int32_t)c32 < 0) cpu->cd.arm.flags |= ARM_F_N; /* Calculate the Overflow bit: */ #if defined(A__CMP) || defined(A__CMN) || defined(A__ADC) || defined(A__ADD) \ || defined(A__RSB) || defined(A__RSC) || defined(A__SBC) || defined(A__SUB) { int v = 0; #if defined(A__ADD) || defined(A__CMN) if (((int32_t)a >= 0 && (int32_t)b >= 0 && (int32_t)c32 < 0) || ((int32_t)a < 0 && (int32_t)b < 0 && (int32_t)c32 >= 0)) v = 1; #else #if defined(A__SUB) || defined(A__RSB) || defined(A__CMP) || \ defined(A__RSC) || defined(A__SBC) if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c32 < 0) || ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c32 >= 0)) v = 1; #endif #endif if (v) cpu->cd.arm.flags |= ARM_F_V; } #endif #endif /* A__S */ #undef VAR_A #undef VAR_B } void A__NAME__eq(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_Z) A__NAME(cpu, ic); } void A__NAME__ne(struct cpu *cpu, struct arm_instr_call *ic) { if (!(cpu->cd.arm.flags & ARM_F_Z)) A__NAME(cpu, ic); } void A__NAME__cs(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_C) A__NAME(cpu, ic); } void A__NAME__cc(struct cpu *cpu, struct arm_instr_call *ic) { if (!(cpu->cd.arm.flags & ARM_F_C)) A__NAME(cpu, ic); } void A__NAME__mi(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_N) A__NAME(cpu, ic); } void A__NAME__pl(struct cpu *cpu, struct arm_instr_call *ic) { if (!(cpu->cd.arm.flags & ARM_F_N)) A__NAME(cpu, ic); } void A__NAME__vs(struct cpu *cpu, struct arm_instr_call *ic) { if (cpu->cd.arm.flags & ARM_F_V) A__NAME(cpu, ic); } void A__NAME__vc(struct cpu *cpu, struct arm_instr_call *ic) { if (!(cpu->cd.arm.flags & ARM_F_V)) A__NAME(cpu, ic); } #ifndef BLAHURG #define BLAHURG extern uint8_t condition_hi[16]; extern uint8_t condition_ge[16]; extern uint8_t condition_gt[16]; #endif void A__NAME__hi(struct cpu *cpu, struct arm_instr_call *ic) { if (condition_hi[cpu->cd.arm.flags]) A__NAME(cpu, ic); } void A__NAME__ls(struct cpu *cpu, struct arm_instr_call *ic) { if (!condition_hi[cpu->cd.arm.flags]) A__NAME(cpu, ic); } void A__NAME__ge(struct cpu *cpu, struct arm_instr_call *ic) { if (condition_ge[cpu->cd.arm.flags]) A__NAME(cpu, ic); } void A__NAME__lt(struct cpu *cpu, struct arm_instr_call *ic) { if (!condition_ge[cpu->cd.arm.flags]) A__NAME(cpu, ic); } void A__NAME__gt(struct cpu *cpu, struct arm_instr_call *ic) { if (condition_gt[cpu->cd.arm.flags]) A__NAME(cpu, ic); } void A__NAME__le(struct cpu *cpu, struct arm_instr_call *ic) { if (!condition_gt[cpu->cd.arm.flags]) A__NAME(cpu, ic); } gxemul-0.6.1/src/cpus/memory_mips_v2p.cc000644 001750 001750 00000033034 13402411502 020427 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * translate_v2p(): * * Translate a virtual MIPS address to a physical address, by looking up the * address in the TLB. On failure, an exception is generated (except for the * case when FLAG_NOEXCEPTIONS is used). * * Note: This function is long and hairy, it is included several times with * various defines set, to produce more or less optimized versions of * the function for different emulated CPU types. * * V2P_MMU3K Defined for R2000/R3000 emulation. If it is not defined, * R4000+/MIPS32/MIPS64 is presumed. * V2P_MMU10K This enables the use of 44 userspace bits, instead of 40. * V2P_MMU4100 VR41xx processors support 1 KB pages, so their page mask * is slightly different. (The emulator only supports 4 KB * pages, though.) * V2P_MMU8K Not yet. (TODO.) * * * Note: Unfortunately, the variable name vpn2 is poorly choosen for R2K/R3K, * since it actual contains the vpn. * * Return values: * 0 Failure * 1 Success, the page is readable only * 2 Success, the page is read/write */ int TRANSLATE_ADDRESS(struct cpu *cpu, uint64_t vaddr, uint64_t *return_paddr, int flags) { int writeflag = flags & FLAG_WRITEFLAG? MEM_WRITE : MEM_READ; int no_exceptions = flags & FLAG_NOEXCEPTIONS; int ksu, use_tlb, status, i; uint64_t vaddr_vpn2=0, vaddr_asid=0; int exccode, tlb_refill; struct mips_coproc *cp0; #ifdef V2P_MMU3K const int x_64 = 0; const int n_tlbs = 64; const uint32_t pmask = 0xfff; uint64_t xuseg_top; /* Well, useg actually. */ #else #ifdef V2P_MMU10K const uint64_t vpn2_mask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K; uint64_t xuseg_top = ENTRYHI_VPN2_MASK_R10K | 0x1fffULL; #else #ifdef V2P_MMU4100 const uint64_t vpn2_mask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | 0x1800; #else const uint64_t vpn2_mask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK; #endif uint64_t xuseg_top = ENTRYHI_VPN2_MASK | 0x1fffULL; #endif int x_64; /* non-zero for 64-bit address space accesses */ int pageshift, n_tlbs; uint32_t pmask; #ifdef V2P_MMU4100 const int pagemask_mask = PAGEMASK_MASK_R4100; const int pagemask_shift = PAGEMASK_SHIFT_R4100; const int pfn_shift = 10; #else const int pagemask_mask = PAGEMASK_MASK; const int pagemask_shift = PAGEMASK_SHIFT; const int pfn_shift = 12; #endif #endif /* !V2P_MMU3K */ exccode = -1; tlb_refill = 1; /* Cached values: */ cp0 = cpu->cd.mips.coproc[0]; status = cp0->reg[COP0_STATUS]; /* * MIPS R4000+ and MIPS64 Address Translation: * * An address may be in one of the kernel segments, that are directly * mapped to physical addresses, or the address needs to be looked up * in the TLB entries. * * KSU: EXL: ERL: X: Name: Range: * ---- ---- ---- -- ----- ------ * * 10 0 0 0 useg 0 - 0x7fffffff (2GB) (via TLB) * 10 0 0 1 xuseg 0 - 0xffffffffff (1TB) (via TLB) * * 01 0 0 0 suseg 0 - 0x7fffffff (2GB via TLB) * 01 0 0 0 ssseg 0xc0000000 - 0xdfffffff (0.5 GB via TLB) * 01 0 0 1 xsuseg 0 - 0xffffffffff (1TB) (via TLB) * 01 0 0 1 xsseg 0x4000000000000000 - 0x400000ffffffffff * (1TB) (via TLB) * 01 0 0 1 csseg 0xffffffffc0000000 - 0xffffffffdfffffff * (0.5TB) (via TLB) * * 00 x x 0 kuseg 0 - 0x7fffffff (2GB) (via TLB) (*) * 00 x x 0 kseg0 0x80000000 - 0x9fffffff (0.5GB) * unmapped, cached * 00 x x 0 kseg1 0xa0000000 - 0xbfffffff (0.5GB) * unmapped, uncached * 00 x x 0 ksseg 0xc0000000 - 0xdfffffff (0.5GB) (via TLB) * 00 x x 0 kseg3 0xe0000000 - 0xffffffff (0.5GB) (via TLB) * 00 x x 1 xksuseg 0 - 0xffffffffff (1TB) (via TLB) (*) * 00 x x 1 xksseg 0x4000000000000000 - 0x400000ffffffffff * (1TB) (via TLB) * 00 x x 1 xkphys 0x8000000000000000 - 0xbfffffffffffffff * 00 x x 1 xkseg 0xc000000000000000 - 0xc00000ff7fffffff * 00 x x 1 ckseg0 0xffffffff80000000 - 0xffffffff9fffffff * 00 x x 1 ckseg1 0xffffffffa0000000 - 0xffffffffbfffffff * 00 x x 1 cksseg 0xffffffffc0000000 - 0xffffffffdfffffff * 00 x x 1 ckseg3 0xffffffffe0000000 - 0xffffffffffffffff * like 0x80000000 - 0xffffffff * * (*) = if ERL=1 then kuseg is not via TLB, but unmapped, * uncached physical memory. * * (KSU==0 or EXL=1 or ERL=1 is enough to use k*seg*.) * * An invalid address causes an Address Error. * * See chapter 4, page 96, in the R4000 manual for more info! */ #ifdef V2P_MMU3K if (status & MIPS1_SR_KU_CUR) ksu = KSU_USER; else ksu = KSU_KERNEL; /* These are needed later: */ vaddr_asid = cp0->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK; vaddr_vpn2 = vaddr & R2K3K_ENTRYHI_VPN_MASK; #else /* kx,sx,ux = 0 for 32-bit addressing, 1 for 64-bit addressing. */ ksu = (status & STATUS_KSU_MASK) >> STATUS_KSU_SHIFT; if (status & (STATUS_EXL | STATUS_ERL)) ksu = KSU_KERNEL; switch (ksu) { case KSU_USER: x_64 = status & STATUS_UX; break; case KSU_KERNEL: x_64 = status & STATUS_KX; break; case KSU_SUPERVISOR: x_64 = status & STATUS_SX; /* FALLTHROUGH, since supervisor address spaces are not really implemented yet. */ default:fatal("memory_mips_v2p.c: ksu=%i not yet implemented yet\n", ksu); exit(1); } n_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries; /* Having this here suppresses a compiler warning: */ pageshift = 12; /* KUSEG: 0x00000000 - 0x7fffffff if ERL = 1 and KSU = kernel: */ if (ksu == KSU_KERNEL && (status & STATUS_ERL) && vaddr <= 0x7fffffff) { *return_paddr = vaddr & 0x7fffffff; return 2; } /* * XKPHYS: 0x8000000000000000 - 0xbfffffffffffffff * * TODO: Is the correct error generated if accessing XKPHYS from * usermode? * * TODO: Magic on SGI machines... Cache control, NUMA, etc.: * 0x9000000080000000 = disable L2 cache (?) * 0x90000000a0000000 = something on IP30? * 0x92.... and 0x96... = NUMA on IP27 */ if (ksu == KSU_KERNEL && (vaddr & ENTRYHI_R_MASK) == ENTRYHI_R_XKPHYS) { *return_paddr = vaddr & (((uint64_t)1 << 44) - 1); return 2; } /* This is needed later: */ vaddr_asid = cp0->reg[COP0_ENTRYHI] & ENTRYHI_ASID; /* vpn2 depends on pagemask, which is not fixed on R4000 */ #endif /* If 32-bit, truncate address and sign extend: */ if (x_64 == 0) { vaddr = (int32_t) vaddr; xuseg_top = 0x7fffffff; /* (Actually useg for R2000/R3000) */ } if (vaddr <= xuseg_top) { use_tlb = 1; } else { if (ksu == KSU_KERNEL) { /* kseg0, kseg1: */ if (vaddr >= (uint64_t)0xffffffff80000000ULL && vaddr <= (uint64_t)0xffffffffbfffffffULL) { *return_paddr = vaddr & 0x1fffffff; return 2; } /* other segments: */ use_tlb = 1; } else { use_tlb = 0; } } if (use_tlb) { #ifndef V2P_MMU3K int odd = 0; uint64_t cached_lo1 = 0; #endif int g_bit, v_bit, d_bit; uint64_t cached_hi, cached_lo0; uint64_t entry_vpn2 = 0, entry_asid, pfn; int i_end; i = cpu->cd.mips.last_written_tlb_index; i_end = i == 0? n_tlbs-1 : i - 1; /* Scan all TLB entries: */ for (;;) { #ifdef V2P_MMU3K /* R3000 or similar: */ cached_hi = cp0->tlbs[i].hi; cached_lo0 = cp0->tlbs[i].lo0; entry_vpn2 = cached_hi & R2K3K_ENTRYHI_VPN_MASK; entry_asid = cached_hi & R2K3K_ENTRYHI_ASID_MASK; g_bit = cached_lo0 & R2K3K_ENTRYLO_G; v_bit = cached_lo0 & R2K3K_ENTRYLO_V; d_bit = cached_lo0 & R2K3K_ENTRYLO_D; #else /* R4000 or similar: */ pmask = cp0->tlbs[i].mask & pagemask_mask; cached_hi = cp0->tlbs[i].hi; cached_lo0 = cp0->tlbs[i].lo0; cached_lo1 = cp0->tlbs[i].lo1; /* Optimized for minimum page size: */ if (pmask == 0) { pageshift = pagemask_shift - 1; entry_vpn2 = (cached_hi & vpn2_mask) >> pagemask_shift; vaddr_vpn2 = (vaddr & vpn2_mask) >> pagemask_shift; pmask = (1 << (pagemask_shift-1)) - 1; odd = (vaddr >> (pagemask_shift-1)) & 1; } else { /* Non-standard page mask: */ switch (pmask | ((1 << pagemask_shift) - 1)) { case 0x00007ff: pageshift = 10; break; case 0x0001fff: pageshift = 12; break; case 0x0007fff: pageshift = 14; break; case 0x001ffff: pageshift = 16; break; case 0x007ffff: pageshift = 18; break; case 0x01fffff: pageshift = 20; break; case 0x07fffff: pageshift = 22; break; case 0x1ffffff: pageshift = 24; break; case 0x7ffffff: pageshift = 26; break; default:fatal("pmask=%08" PRIx32"\n", pmask); exit(1); } entry_vpn2 = (cached_hi & vpn2_mask) >> (pageshift + 1); vaddr_vpn2 = (vaddr & vpn2_mask) >> (pageshift + 1); pmask = (1 << pageshift) - 1; odd = (vaddr >> pageshift) & 1; } /* Assume even virtual page... */ v_bit = cached_lo0 & ENTRYLO_V; d_bit = cached_lo0 & ENTRYLO_D; #ifdef V2P_MMU8K /* * TODO: I don't really know anything about the R8000. * http://futuretech.mirror.vuurwerk.net/i2sec7.html * says that it has a three-way associative TLB with * 384 entries, 16KB page size, and some other things. * * It feels like things like the valid bit (ala R4000) * and dirty bit are not implemented the same on R8000. * * http://sgistuff.tastensuppe.de/documents/ * R8000_chipset.html * also has some info, but no details. */ v_bit = 1; /* Big TODO */ d_bit = 1; #endif entry_asid = cached_hi & ENTRYHI_ASID; /* ... reload pfn, v_bit, d_bit if it was the odd virtual page: */ if (odd) { v_bit = cached_lo1 & ENTRYLO_V; d_bit = cached_lo1 & ENTRYLO_D; } #ifdef V2P_MMU4100 g_bit = cached_lo1 & cached_lo0 & ENTRYLO_G; #else g_bit = cached_hi & TLB_G; #endif #endif /* Is there a VPN and ASID match? */ if (entry_vpn2 == vaddr_vpn2 && (entry_asid == vaddr_asid || g_bit)) { /* debug("OK MAP 1, i=%i { vaddr=%016" PRIx64" " "==> paddr %016" PRIx64" v=%i d=%i " "asid=0x%02x }\n", i, (uint64_t) vaddr, (uint64_t) *return_paddr, v_bit?1:0, d_bit?1:0, vaddr_asid); */ if (v_bit) { if (d_bit || (!d_bit && writeflag == MEM_READ)) { uint64_t paddr; /* debug("OK MAP 2!!! { w=%i " "vaddr=%016" PRIx64" ==> " "d=%i v=%i paddr %016" PRIx64" ", writeflag, (uint64_t)vaddr, d_bit?1:0, v_bit?1:0, (uint64_t) *return_paddr); debug(", tlb entry %2i: ma" "sk=%016" PRIx64" hi=%016" PRIx64" lo0=%016" PRIx64 " lo1=%016" PRIx64"\n", i, cp0->tlbs[i].mask, cp0-> tlbs[i].hi, cp0->tlbs[i]. lo0, cp0->tlbs[i].lo1); */ #ifdef V2P_MMU3K pfn = cached_lo0 & R2K3K_ENTRYLO_PFN_MASK; paddr = pfn | (vaddr & pmask); #else pfn = ((odd? cached_lo1 : cached_lo0) & ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT; paddr = ((pfn << pfn_shift) & ~pmask) | (vaddr & pmask); #endif *return_paddr = paddr; return d_bit? 2 : 1; } else { /* TLB modif. exception */ tlb_refill = 0; exccode = EXCEPTION_MOD; goto exception; } } else { /* TLB invalid exception */ tlb_refill = 0; goto exception; } } if (i == i_end) break; /* Go to the next TLB entry: */ i ++; if (i == n_tlbs) i = 0; } } /* * We are here if for example userland code tried to access * kernel memory, OR if there was a TLB refill. */ if (!use_tlb) { tlb_refill = 0; if (writeflag == MEM_WRITE) exccode = EXCEPTION_ADES; else exccode = EXCEPTION_ADEL; } exception: if (no_exceptions) return 0; /* TLB Load or Store exception: */ if (exccode == -1) { if (writeflag == MEM_WRITE) exccode = EXCEPTION_TLBS; else exccode = EXCEPTION_TLBL; } #ifdef V2P_MMU3K vaddr_asid >>= R2K3K_ENTRYHI_ASID_SHIFT; vaddr_vpn2 >>= 12; #endif mips_cpu_exception(cpu, exccode, tlb_refill, vaddr, 0, vaddr_vpn2, vaddr_asid, x_64); /* Return failure: */ return 0; } gxemul-0.6.1/src/cpus/cpu_arm_multi.txt000644 001750 001750 00000005400 13402411502 020366 0ustar00debugdebug000000 000000 0x092ddff0 0x091baff0 0x08110003 0x092dd8f0 0x091ba8f0 0x092d4000 0x08bd8000 0x08ac000c 0x092dd830 0x092dddf0 0x092dd9f0 0x091badf0 0x091ba830 0x091ba9f0 0x08930003 0x09040003 0x08b051f8 0x08a151f8 0x092dd810 0x091ba810 0x08930006 0x092d4010 0x092dd800 0x08830006 0x08920018 0x08a051f8 0x08820018 0x08bd8010 0x08a05018 0x08b15018 0x092dd870 0x091ba870 0x092d41f0 0x08bd81f0 0x08971040 0x08040006 0x08130018 0x091ba800 0x088d1fff 0x091b6800 0x08950006 0x0911000f 0x090d000f 0x08850006 0x092d4070 0x08bd8070 0x08900006 0x08800006 0x089e0018 0x08870006 0x088e0018 0x08b00fc0 0x08b000c0 0x08970006 0x08930060 0x091b6ff0 0x092d4030 0x08bd8030 0x091b6830 0x092ddc30 0x091bac30 0x092d4001 0x08bd8001 0x09205018 0x09315018 0x092ddbf0 0x091babf0 0x091bac70 0x092ddc70 0x080c0030 0x092ddcf0 0x091bacf0 0x0892000c 0x08930180 0x08150003 0x08020003 0x08920006 0x0817000c 0x09870018 0x099c0180 0x091b69f0 0x08950003 0x088c0060 0x0891000e 0x08bd0400 0x092d0030 0x08bd0030 0x08810018 0x08880018 0x08820003 0x08980060 0x08bd0010 0x092d0010 0x08bd4010 0x08100009 0x08910003 0x08830030 0x08980018 0x08930018 0x08880006 0x088c0018 0x08910006 0x08940003 0x08850003 0x08890006 0x092d40f0 0x08840003 0x08820030 0x09160060 0x08930600 0x092d0ff0 0x08bd0ff0 0x089e000a 0x09930006 0x080c0003 0x0804000c 0x08830060 0x08130003 0x09830006 0x08b00300 0x088e1002 0x0894000c 0x0885000c 0x08840600 0x091b6df0 0x088c0006 0x092d47f0 0x08bd87f0 0x08800018 0x099b0030 0x08a100c0 0x089c0006 0x099b0180 0x08910030 0x09150018 0x091a0600 0x090a0300 0x08bd40f0 0x089c0300 0x09150006 0x08a10300 0x08a01008 0x08b11008 0x08bd80f0 0x08a05008 0x08b15008 0x08900018 0x092ddc00 0x088c0003 0x08830600 0x08920003 0x088d1100 0x09900120 0x091bac00 0x092d45f0 0x08bd85f0 0x09940018 0x09850014 0x08860006 0x09120006 0x089c0018 0x091b6870 0x08950030 0x09900018 0x098d0030 0x088d0088 0x08900060 0x08900003 0x08990018 0x08810600 0x092d0c1f 0x08bd4c1f 0x088d1010 0x09311008 0x09201008 0x08a10f00 0x08931008 0x098b0003 0x08820180 0x08830300 0x08800030 0x09315008 0x09205008 0x08970300 0x08970030 0x08920030 0x08970600 0x08160060 0x08807ff0 0x092d0070 0x08bd0070 0x08800180 0x088e000c 0x088d0030 0x08830003 0x089e0030 0x091b6810 0x08970180 0x0896000c 0x089200c0 0x088e00c0 0x08940012 0x089100c0 0x0813000c 0x089c000c 0x09920003 0x08950060 0x09860006 0x088d4010 0x09160006 0x08990600 0x08980006 0x091c0006 0x080c0600 0x0894000a 0x09311038 0x09205030 0x08850018 0x09190300 0x088d0180 0x08980003 0x098d000e 0x098c0006 0x09010018 0x09860030 0x092d4400 0x08bd8400 0x089e0060 0x088c00c8 0x0893000c 0x09110003 0x08ac000f 0x08be000f 0x08940018 0x091b68f0 0x09140018 0x08940009 0x08bd41f0 0x08a20600 0x08990003 0x09904008 0x098c0003 0x088900c0 0x088200c0 0x088300c0 0x089300c0 0x092d00f0 0x08bd00f0 0x08960030 0x08980300 0x089c5000 0x088d1020 0x08990006 0x08890030 0x099a0003 0x0989000c gxemul-0.6.1/src/cpus/arm_tmphead_1.h000644 001750 001750 00000004767 13402411502 017656 0ustar00debugdebug000000 000000 #ifndef ARM_TMPHEAD_1 #define ARM_TMPHEAD_1 /* $Id: arm_tmphead_1.h,v 1.3 2006-02-19 08:04:13 debug Exp $ */ extern uint8_t condition_hi[16]; extern uint8_t condition_ge[16]; extern uint8_t condition_gt[16]; #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (cpu->cd.arm.flags & ARM_F_Z) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __ne(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!(cpu->cd.arm.flags & ARM_F_Z)) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __cs(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (cpu->cd.arm.flags & ARM_F_C) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __cc(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!(cpu->cd.arm.flags & ARM_F_C)) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __mi(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (cpu->cd.arm.flags & ARM_F_N) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __pl(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!(cpu->cd.arm.flags & ARM_F_N)) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __vs(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (cpu->cd.arm.flags & ARM_F_V) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __vc(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!(cpu->cd.arm.flags & ARM_F_V)) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __hi(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (condition_hi[cpu->cd.arm.flags]) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __ls(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!condition_hi[cpu->cd.arm.flags]) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __ge(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (condition_ge[cpu->cd.arm.flags]) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __lt(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!condition_ge[cpu->cd.arm.flags]) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __gt(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (condition_gt[cpu->cd.arm.flags]) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __le(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!condition_gt[cpu->cd.arm.flags]) \ arm_instr_ ## n (cpu, ic); } #endif /* ARM_TMPHEAD_1 */ gxemul-0.6.1/src/cpus/cpu_arm_instr.cc000644 001750 001750 00000247570 13402411502 020161 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * ARM instructions. * * Individual functions should keep track of cpu->n_translated_instrs. * (If no instruction was executed, then it should be decreased. If, say, 4 * instructions were combined into one function and executed, then it should * be increased by 3.) * * Note: cpu->pc is prefered over r[ARM_PC]. r[ARM_PC] is only used in a * few places, and should always be kept in synch with the real * program counter. */ /* #define GATHER_BDT_STATISTICS */ #ifdef GATHER_BDT_STATISTICS /* * update_bdt_statistics(): * * Gathers statistics about load/store multiple instructions. * * NOTE/TODO: Perhaps it would be more memory efficient to swap the high * and low parts of the instruction word, so that the lllllll bits become * the high bits; this would cause fewer host pages to be used. Anyway, the * current implementation works on hosts with lots of RAM. * * The resulting file, bdt_statistics.txt, should then be processed like * this to give a new cpu_arm_multi.txt: * * uniq -c bdt_statistics.txt|sort -nr|head -256|cut -f 2 > cpu_arm_multi.txt */ static void update_bdt_statistics(uint32_t iw) { static FILE *f = NULL; static long long *counts; static char *counts_used; static long long n = 0; if (f == NULL) { size_t s = (1 << 24) * sizeof(long long); f = fopen("bdt_statistics.txt", "w"); if (f == NULL) { fprintf(stderr, "update_bdt_statistics(): :-(\n"); exit(1); } counts = zeroed_alloc(s); counts_used = zeroed_alloc(65536); } /* Drop the s-bit: xxxx100P USWLnnnn llllllll llllllll */ iw = ((iw & 0x01800000) >> 1) | (iw & 0x003fffff); counts_used[iw & 0xffff] = 1; counts[iw] ++; n ++; if ((n % 500000) == 0) { int i; long long j; fatal("[ update_bdt_statistics(): n = %lli ]\n", (long long) n); fseek(f, 0, SEEK_SET); for (i=0; i<0x1000000; i++) if (counts_used[i & 0xffff] && counts[i] != 0) { /* Recreate the opcode: */ uint32_t opcode = ((i & 0x00c00000) << 1) | (i & 0x003fffff) | 0x08000000; for (j=0; jcd.arm.flags & ARM_F_Z) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __ne(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!(cpu->cd.arm.flags & ARM_F_Z)) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __cs(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (cpu->cd.arm.flags & ARM_F_C) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __cc(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!(cpu->cd.arm.flags & ARM_F_C)) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __mi(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (cpu->cd.arm.flags & ARM_F_N) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __pl(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!(cpu->cd.arm.flags & ARM_F_N)) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __vs(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (cpu->cd.arm.flags & ARM_F_V) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __vc(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!(cpu->cd.arm.flags & ARM_F_V)) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __hi(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (condition_hi[cpu->cd.arm.flags]) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __ls(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!condition_hi[cpu->cd.arm.flags]) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __ge(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (condition_ge[cpu->cd.arm.flags]) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __lt(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!condition_ge[cpu->cd.arm.flags]) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __gt(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (condition_gt[cpu->cd.arm.flags]) \ arm_instr_ ## n (cpu, ic); } \ void arm_instr_ ## n ## __le(struct cpu *cpu, \ struct arm_instr_call *ic) \ { if (!condition_gt[cpu->cd.arm.flags]) \ arm_instr_ ## n (cpu, ic); } \ void (*arm_cond_instr_ ## n [16])(struct cpu *, \ struct arm_instr_call *) = { \ arm_instr_ ## n ## __eq, arm_instr_ ## n ## __ne, \ arm_instr_ ## n ## __cs, arm_instr_ ## n ## __cc, \ arm_instr_ ## n ## __mi, arm_instr_ ## n ## __pl, \ arm_instr_ ## n ## __vs, arm_instr_ ## n ## __vc, \ arm_instr_ ## n ## __hi, arm_instr_ ## n ## __ls, \ arm_instr_ ## n ## __ge, arm_instr_ ## n ## __lt, \ arm_instr_ ## n ## __gt, arm_instr_ ## n ## __le, \ arm_instr_ ## n , arm_instr_never }; #define cond_instr(n) ( arm_cond_instr_ ## n [condition_code] ) /*****************************************************************************/ /* * invalid: Invalid instructions end up here. */ X(invalid) { uint32_t low_pc; low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); fatal("FATAL ERROR: An internal error occured in the ARM" " dyntrans code. Please contact the author with detailed" " repro steps on how to trigger this bug. pc = 0x%08" PRIx32"\n", (uint32_t)cpu->pc); cpu->cd.arm.next_ic = ¬hing_call; } /* * never: So far unimplemented "never" instructions end up here. * (Those are the ones using the "0xf" condition prefix.) */ X(never) { uint32_t low_pc; low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); fatal("[ ARM: unimplemented 0xf instruction at pc = 0x%08" PRIx32" ]\n", (uint32_t)cpu->pc); cpu->cd.arm.next_ic = ¬hing_call; } /* * nop: Do nothing. */ X(nop) { } /* * b: Branch (to a different translated page) * * arg[0] = relative offset from start of page */ X(b) { cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[0]); /* Find the new physical page and update the translation pointers: */ quick_pc_to_pointers_arm(cpu); } Y(b) /* * b_samepage: Branch (to within the same translated page) * * arg[0] = pointer to new arm_instr_call * arg[1] = pointer to the next instruction. * * NOTE: This instruction is manually inlined. */ X(b_samepage) { cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0]; } X(b_samepage__eq) { cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[cpu->cd.arm.flags & ARM_F_Z? 0 : 1]; } X(b_samepage__ne) { cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[cpu->cd.arm.flags & ARM_F_Z? 1 : 0]; } X(b_samepage__cs) { cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[cpu->cd.arm.flags & ARM_F_C? 0 : 1]; } X(b_samepage__cc) { cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[cpu->cd.arm.flags & ARM_F_C? 1 : 0]; } X(b_samepage__mi) { cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[cpu->cd.arm.flags & ARM_F_N? 0 : 1]; } X(b_samepage__pl) { cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[cpu->cd.arm.flags & ARM_F_N? 1 : 0]; } X(b_samepage__vs) { cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[cpu->cd.arm.flags & ARM_F_V? 0 : 1]; } X(b_samepage__vc) { cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[cpu->cd.arm.flags & ARM_F_V? 1 : 0]; } X(b_samepage__hi) { cpu->cd.arm.next_ic = (condition_hi[cpu->cd.arm.flags])? (struct arm_instr_call *) ic->arg[0] : (struct arm_instr_call *) ic->arg[1]; } X(b_samepage__ls) { cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[condition_hi[cpu->cd.arm.flags]]; } X(b_samepage__ge) { cpu->cd.arm.next_ic = (condition_ge[cpu->cd.arm.flags])? (struct arm_instr_call *) ic->arg[0] : (struct arm_instr_call *) ic->arg[1]; } X(b_samepage__lt) { cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[condition_ge[cpu->cd.arm.flags]]; } X(b_samepage__gt) { cpu->cd.arm.next_ic = (condition_gt[cpu->cd.arm.flags])? (struct arm_instr_call *) ic->arg[0] : (struct arm_instr_call *) ic->arg[1]; } X(b_samepage__le) { cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[condition_gt[cpu->cd.arm.flags]]; } void (*arm_cond_instr_b_samepage[16])(struct cpu *, struct arm_instr_call *) = { arm_instr_b_samepage__eq, arm_instr_b_samepage__ne, arm_instr_b_samepage__cs, arm_instr_b_samepage__cc, arm_instr_b_samepage__mi, arm_instr_b_samepage__pl, arm_instr_b_samepage__vs, arm_instr_b_samepage__vc, arm_instr_b_samepage__hi, arm_instr_b_samepage__ls, arm_instr_b_samepage__ge, arm_instr_b_samepage__lt, arm_instr_b_samepage__gt, arm_instr_b_samepage__le, arm_instr_b_samepage, arm_instr_nop }; /* * bx: Branch, potentially exchanging Thumb/ARM encoding * * arg[0] = ptr to rm */ X(bx) { uint32_t old_cpsr = cpu->cd.arm.cpsr; cpu->pc = reg(ic->arg[0]); if (cpu->pc & 1) cpu->cd.arm.cpsr |= ARM_FLAG_T; else cpu->cd.arm.cpsr &= ~ARM_FLAG_T; if (cpu->cd.arm.cpsr != old_cpsr) cpu->cd.arm.next_ic = ¬hing_call; if (cpu->pc & 2 && ((cpu->pc & 1) == 0)) { fatal("[ ARM pc misaligned? 0x%08x ]\n", (int)cpu->pc); cpu->running = 0; cpu->n_translated_instrs --; cpu->cd.arm.next_ic = ¬hing_call; return; } /* Find the new physical page and update the translation pointers: */ quick_pc_to_pointers_arm(cpu); } Y(bx) /* * bx_trace: As bx, but with trace enabled, arg[0] = the link register. * * arg[0] = ignored */ X(bx_trace) { uint32_t old_cpsr = cpu->cd.arm.cpsr; cpu->pc = cpu->cd.arm.r[ARM_LR]; if (cpu->pc & 1) cpu->cd.arm.cpsr |= ARM_FLAG_T; else cpu->cd.arm.cpsr &= ~ARM_FLAG_T; if (cpu->cd.arm.cpsr != old_cpsr) cpu->cd.arm.next_ic = ¬hing_call; if (cpu->pc & 2 && ((cpu->pc & 1) == 0)) { fatal("[ ARM pc misaligned? 0x%08x ]\n", (int)cpu->pc); cpu->running = 0; cpu->n_translated_instrs --; cpu->cd.arm.next_ic = ¬hing_call; return; } cpu_functioncall_trace_return(cpu); /* Find the new physical page and update the translation pointers: */ quick_pc_to_pointers_arm(cpu); } Y(bx_trace) /* * bl: Branch and Link (to a different translated page) * * arg[0] = relative address * arg[1] = offset within current page to the instruction */ X(bl) { uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1]; cpu->cd.arm.r[ARM_LR] = pc + 4; /* Calculate new PC from this instruction + arg[0] */ cpu->pc = pc + (int32_t)ic->arg[0]; /* Find the new physical page and update the translation pointers: */ quick_pc_to_pointers_arm(cpu); } Y(bl) /* * blx_imm: Branch and Link, always switching to THUMB encoding * * arg[0] = relative address * arg[1] = offset within current page to the current instruction */ X(blx_imm) { uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1]; uint32_t old_cpsr = cpu->cd.arm.cpsr; cpu->cd.arm.r[ARM_LR] = pc + 4; /* Calculate new PC from this instruction + arg[0] */ cpu->pc = pc + (int32_t)ic->arg[0]; if (cpu->pc & 1) cpu->cd.arm.cpsr |= ARM_FLAG_T; else { fatal("[ blx_imm internal error. Should have switched to THUMB! 0x%08x ]\n", (int)cpu->pc); cpu->running = 0; cpu->n_translated_instrs --; cpu->cd.arm.next_ic = ¬hing_call; return; } if (cpu->cd.arm.cpsr != old_cpsr) cpu->cd.arm.next_ic = ¬hing_call; if (cpu->pc & 2 && ((cpu->pc & 1) == 0)) { fatal("[ ARM pc misaligned? 0x%08x ]\n", (int)cpu->pc); cpu->running = 0; cpu->n_translated_instrs --; cpu->cd.arm.next_ic = ¬hing_call; return; } if (cpu->machine->show_trace_tree) cpu_functioncall_trace(cpu, cpu->pc); /* Find the new physical page and update the translation pointers: */ quick_pc_to_pointers_arm(cpu); } /* * blx_reg: Branch and Link, potentially exchanging Thumb/ARM encoding * * arg[0] = ptr to rm * arg[2] = offset within current page to the instruction to return to */ X(blx_reg) { uint32_t lr = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2]; cpu->cd.arm.r[ARM_LR] = lr; cpu->pc = reg(ic->arg[0]); uint32_t old_cpsr = cpu->cd.arm.cpsr; if (cpu->pc & 1) cpu->cd.arm.cpsr |= ARM_FLAG_T; else cpu->cd.arm.cpsr &= ~ARM_FLAG_T; if (cpu->cd.arm.cpsr != old_cpsr) cpu->cd.arm.next_ic = ¬hing_call; if (cpu->pc & 2 && ((cpu->pc & 1) == 0)) { fatal("[ ARM pc misaligned? 0x%08x ]\n", (int)cpu->pc); cpu->running = 0; cpu->n_translated_instrs --; cpu->cd.arm.next_ic = ¬hing_call; return; } /* Find the new physical page and update the translation pointers: */ quick_pc_to_pointers_arm(cpu); } Y(blx_reg) /* * bl_trace: Branch and Link (to a different translated page), with trace * * Same as for bl. */ X(bl_trace) { uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1]; cpu->cd.arm.r[ARM_LR] = pc + 4; /* Calculate new PC from this instruction + arg[0] */ cpu->pc = pc + (int32_t)ic->arg[0]; cpu_functioncall_trace(cpu, cpu->pc); /* Find the new physical page and update the translation pointers: */ quick_pc_to_pointers_arm(cpu); } Y(bl_trace) /* * bl_samepage: A branch + link within the same page * * arg[0] = pointer to new arm_instr_call */ X(bl_samepage) { cpu->cd.arm.r[ARM_LR] = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2]; cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0]; } Y(bl_samepage) /* * bl_samepage_trace: Branch and Link (to the same page), with trace * * Same as for bl_samepage. */ X(bl_samepage_trace) { uint32_t low_pc, lr = (cpu->pc & 0xfffff000) + ic->arg[2]; /* Link and branch: */ cpu->cd.arm.r[ARM_LR] = lr; cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0]; /* Synchronize the program counter: */ low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); /* ... and show trace: */ cpu_functioncall_trace(cpu, cpu->pc); } Y(bl_samepage_trace) /* * clz: Count leading zeroes. * * arg[0] = ptr to rm * arg[1] = ptr to rd */ X(clz) { uint32_t rm = reg(ic->arg[0]); int i = 32, n = 0, j; while (i>0) { if (rm & 0xff000000) { for (j=0; j<8; j++) { if (rm & 0x80000000) break; n ++; rm <<= 1; } break; } else { rm <<= 8; i -= 8; n += 8; } } reg(ic->arg[1]) = n; } Y(clz) /* * mul: Multiplication * * arg[0] = ptr to rd * arg[1] = ptr to rm * arg[2] = ptr to rs */ X(mul) { reg(ic->arg[0]) = reg(ic->arg[1]) * reg(ic->arg[2]); } Y(mul) X(muls) { uint32_t result; result = reg(ic->arg[1]) * reg(ic->arg[2]); cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (result == 0) cpu->cd.arm.flags |= ARM_F_Z; if (result & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; reg(ic->arg[0]) = result; } Y(muls) /* * mla: Multiplication with addition * * arg[0] = copy of instruction word */ X(mla) { /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */ uint32_t iw = ic->arg[0]; int rd, rs, rn, rm; rd = (iw >> 16) & 15; rn = (iw >> 12) & 15, rs = (iw >> 8) & 15; rm = iw & 15; cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs] + cpu->cd.arm.r[rn]; } Y(mla) X(mlas) { /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */ uint32_t iw = ic->arg[0]; int rd, rs, rn, rm; rd = (iw >> 16) & 15; rn = (iw >> 12) & 15, rs = (iw >> 8) & 15; rm = iw & 15; cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs] + cpu->cd.arm.r[rn]; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (cpu->cd.arm.r[rd] == 0) cpu->cd.arm.flags |= ARM_F_Z; if (cpu->cd.arm.r[rd] & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; } Y(mlas) /* * mull: Long multiplication * * arg[0] = copy of instruction word */ X(mull) { /* xxxx0000 1UAShhhh llllssss 1001mmmm */ uint32_t iw; uint64_t tmp; int u_bit, a_bit; iw = ic->arg[0]; u_bit = iw & 0x00400000; a_bit = iw & 0x00200000; tmp = cpu->cd.arm.r[iw & 15]; if (u_bit) tmp = (int64_t)(int32_t)tmp * (int64_t)(int32_t)cpu->cd.arm.r[(iw >> 8) & 15]; else tmp *= (uint64_t)cpu->cd.arm.r[(iw >> 8) & 15]; if (a_bit) { uint64_t x = ((uint64_t)cpu->cd.arm.r[(iw >> 16) & 15] << 32) | cpu->cd.arm.r[(iw >> 12) & 15]; x += tmp; cpu->cd.arm.r[(iw >> 16) & 15] = (x >> 32); cpu->cd.arm.r[(iw >> 12) & 15] = x; } else { cpu->cd.arm.r[(iw >> 16) & 15] = (tmp >> 32); cpu->cd.arm.r[(iw >> 12) & 15] = tmp; } } Y(mull) /* * smulXY: 16-bit * 16-bit multiplication (32-bit result) * * arg[0] = ptr to rm * arg[1] = ptr to rs * arg[2] = ptr to rd */ X(smulbb) { reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) * (int32_t)(int16_t)reg(ic->arg[1]); } Y(smulbb) X(smultb) { reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) * (int32_t)(int16_t)reg(ic->arg[1]); } Y(smultb) X(smulbt) { reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) * (int32_t)(int16_t)(reg(ic->arg[1]) >> 16); } Y(smulbt) X(smultt) { reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) * (int32_t)(int16_t)(reg(ic->arg[1]) >> 16); } Y(smultt) /* * mov_reg_reg: Move a register to another. * * arg[0] = ptr to source register * arg[1] = ptr to destination register */ X(mov_reg_reg) { reg(ic->arg[1]) = reg(ic->arg[0]); } Y(mov_reg_reg) /* * mov_reg_pc: Move the PC register to a normal register. * * arg[0] = offset compared to start of current page + 8 * arg[1] = ptr to destination register */ X(mov_reg_pc) { reg(ic->arg[1]) = ((uint32_t)cpu->pc&0xfffff000) + (int32_t)ic->arg[0]; } Y(mov_reg_pc) /* * ret_trace: "mov pc,lr" with trace enabled * ret: "mov pc,lr" without trace enabled * * arg[0] = ignored */ X(ret_trace) { uint32_t old_pc, mask_within_page; old_pc = cpu->pc; mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT) | ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1); /* Update the PC register: */ cpu->pc = cpu->cd.arm.r[ARM_LR]; cpu_functioncall_trace_return(cpu); /* * Is this a return to code within the same page? Then there is no * need to update all pointers, just next_ic. */ if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) { cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page + ((cpu->pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT); } else { /* Find the new physical page and update pointers: */ quick_pc_to_pointers_arm(cpu); } } Y(ret_trace) X(ret) { cpu->pc = cpu->cd.arm.r[ARM_LR]; quick_pc_to_pointers_arm(cpu); } Y(ret) /* * msr: Move to status register from a normal register or immediate value. * * arg[0] = immediate value * arg[1] = mask * arg[2] = pointer to rm * * msr_imm and msr_imm_spsr use arg[1] and arg[0]. * msr and msr_spsr use arg[1] and arg[2]. */ X(msr_imm) { uint32_t mask = ic->arg[1]; if ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32) { mask &= 0xff000000; } int switch_register_banks = (mask & ARM_FLAG_MODE) && ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) != (ic->arg[0] & ARM_FLAG_MODE)); uint32_t new_value = ic->arg[0]; cpu->cd.arm.cpsr &= 0x0fffffff; cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28); if (switch_register_banks) arm_save_register_bank(cpu); cpu->cd.arm.cpsr &= ~mask; cpu->cd.arm.cpsr |= (new_value & mask); cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28; if (switch_register_banks) arm_load_register_bank(cpu); } Y(msr_imm) X(msr) { ic->arg[0] = reg(ic->arg[2]); instr(msr_imm)(cpu, ic); } Y(msr) X(msr_imm_spsr) { uint32_t mask = ic->arg[1]; uint32_t new_value = ic->arg[0]; switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) { case ARM_MODE_FIQ32: cpu->cd.arm.spsr_fiq &= ~mask; cpu->cd.arm.spsr_fiq |= (new_value & mask); break; case ARM_MODE_ABT32: cpu->cd.arm.spsr_abt &= ~mask; cpu->cd.arm.spsr_abt |= (new_value & mask); break; case ARM_MODE_UND32: cpu->cd.arm.spsr_und &= ~mask; cpu->cd.arm.spsr_und |= (new_value & mask); break; case ARM_MODE_IRQ32: cpu->cd.arm.spsr_irq &= ~mask; cpu->cd.arm.spsr_irq |= (new_value & mask); break; case ARM_MODE_SVC32: cpu->cd.arm.spsr_svc &= ~mask; cpu->cd.arm.spsr_svc |= (new_value & mask); break; default:fatal("msr_spsr: unimplemented mode %i\n", cpu->cd.arm.cpsr & ARM_FLAG_MODE); { /* Synchronize the program counter: */ uint32_t old_pc, low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); old_pc = cpu->pc; printf("msr_spsr: old pc = 0x%08" PRIx32"\n", old_pc); } exit(1); } } Y(msr_imm_spsr) X(msr_spsr) { ic->arg[0] = reg(ic->arg[2]); instr(msr_imm_spsr)(cpu, ic); } Y(msr_spsr) /* * mrs: Move from status/flag register to a normal register. * * arg[0] = pointer to rd */ X(mrs) { cpu->cd.arm.cpsr &= 0x0fffffff; cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28); reg(ic->arg[0]) = cpu->cd.arm.cpsr; } Y(mrs) /* * mrs: Move from saved status/flag register to a normal register. * * arg[0] = pointer to rd */ X(mrs_spsr) { switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) { case ARM_MODE_FIQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_fiq; break; case ARM_MODE_ABT32: reg(ic->arg[0]) = cpu->cd.arm.spsr_abt; break; case ARM_MODE_UND32: reg(ic->arg[0]) = cpu->cd.arm.spsr_und; break; case ARM_MODE_IRQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_irq; break; case ARM_MODE_SVC32: reg(ic->arg[0]) = cpu->cd.arm.spsr_svc; break; case ARM_MODE_USR32: case ARM_MODE_SYS32: reg(ic->arg[0]) = 0; break; default:fatal("mrs_spsr: unimplemented mode %i\n", cpu->cd.arm.cpsr & ARM_FLAG_MODE); exit(1); } } Y(mrs_spsr) /* * mcr_mrc: Coprocessor move * cdp: Coprocessor operation * * arg[0] = copy of the instruction word */ X(mcr_mrc) { uint32_t low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); arm_mcr_mrc(cpu, ic->arg[0]); } Y(mcr_mrc) X(cdp) { uint32_t low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); arm_cdp(cpu, ic->arg[0]); } Y(cdp) /* * openfirmware: */ X(openfirmware) { /* TODO: sync pc? */ of_emul(cpu); cpu->pc = cpu->cd.arm.r[ARM_LR]; if (cpu->machine->show_trace_tree) cpu_functioncall_trace_return(cpu); quick_pc_to_pointers_arm(cpu); } /* * reboot: */ X(reboot) { cpu->running = 0; cpu->n_translated_instrs --; cpu->cd.arm.next_ic = ¬hing_call; } /* * swi: Software interrupt. */ X(swi) { /* Synchronize the program counter first: */ cpu->pc &= 0xfffff000; cpu->pc += ic->arg[0]; arm_exception(cpu, ARM_EXCEPTION_SWI); } Y(swi) /* * bkpt: Breakpoint instruction. */ X(bkpt) { /* Synchronize the program counter first: */ cpu->pc &= 0xfffff000; cpu->pc += ic->arg[0]; arm_exception(cpu, ARM_EXCEPTION_PREF_ABT); } Y(bkpt) /* * und: Undefined instruction. */ X(und) { /* Synchronize the program counter first: */ cpu->pc &= 0xfffff000; cpu->pc += ic->arg[0]; arm_exception(cpu, ARM_EXCEPTION_UND); } Y(und) /* * swp, swpb: Swap (word or byte). * * arg[0] = ptr to rd * arg[1] = ptr to rm * arg[2] = ptr to rn */ X(swp) { uint32_t addr = reg(ic->arg[2]), data, data2; unsigned char d[4]; /* Synchronize the program counter: */ uint32_t low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ, CACHE_DATA)) { fatal("swp: load failed\n"); return; } data = d[0] + (d[1] << 8) + (d[2] << 16) + (d[3] << 24); data2 = reg(ic->arg[1]); d[0] = data2; d[1] = data2 >> 8; d[2] = data2 >> 16; d[3] = data2 >> 24; if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE, CACHE_DATA)) { fatal("swp: store failed\n"); return; } reg(ic->arg[0]) = data; } Y(swp) X(swpb) { uint32_t addr = reg(ic->arg[2]), data; unsigned char d[1]; /* Synchronize the program counter: */ uint32_t low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ, CACHE_DATA)) { fatal("swp: load failed\n"); return; } data = d[0]; d[0] = reg(ic->arg[1]); if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE, CACHE_DATA)) { fatal("swp: store failed\n"); return; } reg(ic->arg[0]) = data; } Y(swpb) extern void (*arm_load_store_instr[1024])(struct cpu *, struct arm_instr_call *); X(store_w1_word_u1_p0_imm); X(store_w0_byte_u1_p0_imm); X(store_w0_word_u1_p0_imm); X(store_w0_word_u1_p1_imm); X(load_w0_word_u1_p0_imm); X(load_w0_word_u1_p1_imm); X(load_w1_word_u1_p0_imm); X(load_w0_byte_u1_p1_imm); X(load_w0_byte_u1_p1_reg); X(load_w1_byte_u1_p1_imm); extern void (*arm_load_store_instr_pc[1024])(struct cpu *, struct arm_instr_call *); extern void (*arm_load_store_instr_3[2048])(struct cpu *, struct arm_instr_call *); extern void (*arm_load_store_instr_3_pc[2048])(struct cpu *, struct arm_instr_call *); extern uint32_t (*arm_r[8192])(struct cpu *, struct arm_instr_call *); extern uint32_t arm_r_r3_t0_c0(struct cpu *cpu, struct arm_instr_call *ic); extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *, struct arm_instr_call *); extern void (*arm_dpi_instr_regshort[2 * 16 * 16])(struct cpu *, struct arm_instr_call *); X(cmps); X(teqs); X(tsts); X(sub); X(add); X(subs); X(eor_regshort); X(cmps_regshort); #include "cpu_arm_instr_misc.cc" /* * Shared between regular ARM and the THUMB encoded 'pop'. */ void arm_pop(struct cpu* cpu, uint32_t* np, int p_bit, int u_bit, int s_bit, int w_bit, uint32_t iw) { uint32_t addr = *np; unsigned char data[4]; unsigned char *page; int i, return_flag = 0; uint32_t new_values[16]; if (s_bit) { /* Load to USR registers: */ if ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32) { fatal("[ bdt_load: s-bit: in usermode? ]\n"); s_bit = 0; } if (iw & 0x8000) { s_bit = 0; return_flag = 1; } } for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) { uint32_t value; if (!((iw >> i) & 1)) { /* Skip register i: */ continue; } if (p_bit) { if (u_bit) addr += sizeof(uint32_t); else addr -= sizeof(uint32_t); } page = cpu->cd.arm.host_load[addr >> 12]; if (page != NULL) { uint32_t *p32 = (uint32_t *) page; value = p32[(addr & 0xfff) >> 2]; /* Change byte order of value if host and emulated endianness differ: */ #ifdef HOST_LITTLE_ENDIAN if (cpu->byte_order == EMUL_BIG_ENDIAN) #else if (cpu->byte_order == EMUL_LITTLE_ENDIAN) #endif value = ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | ((value & 0xff000000) >> 24); } else { if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_READ, CACHE_DATA)) { /* load failed */ return; } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { value = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24); } else { value = data[3] + (data[2] << 8) + (data[1] << 16) + (data[0] << 24); } } new_values[i] = value; if (!p_bit) { if (u_bit) addr += sizeof(uint32_t); else addr -= sizeof(uint32_t); } } for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) { if (!((iw >> i) & 1)) { /* Skip register i: */ continue; } if (!s_bit) { cpu->cd.arm.r[i] = new_values[i]; } else { switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) { case ARM_MODE_USR32: case ARM_MODE_SYS32: cpu->cd.arm.r[i] = new_values[i]; break; case ARM_MODE_FIQ32: if (i >= 8 && i <= 14) cpu->cd.arm.default_r8_r14[i-8] = new_values[i]; else cpu->cd.arm.r[i] = new_values[i]; break; case ARM_MODE_SVC32: case ARM_MODE_ABT32: case ARM_MODE_UND32: case ARM_MODE_IRQ32: if (i >= 13 && i <= 14) cpu->cd.arm.default_r8_r14[i-8] = new_values[i]; else cpu->cd.arm.r[i] = new_values[i]; break; } } } if (w_bit) *np = addr; if (return_flag) { uint32_t new_cpsr; int switch_register_banks; switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) { case ARM_MODE_FIQ32: new_cpsr = cpu->cd.arm.spsr_fiq; break; case ARM_MODE_ABT32: new_cpsr = cpu->cd.arm.spsr_abt; break; case ARM_MODE_UND32: new_cpsr = cpu->cd.arm.spsr_und; break; case ARM_MODE_IRQ32: new_cpsr = cpu->cd.arm.spsr_irq; break; case ARM_MODE_SVC32: new_cpsr = cpu->cd.arm.spsr_svc; break; default:fatal("bdt_load: unimplemented mode %i\n", cpu->cd.arm.cpsr & ARM_FLAG_MODE); exit(1); } switch_register_banks = (cpu->cd.arm.cpsr & ARM_FLAG_MODE) != (new_cpsr & ARM_FLAG_MODE); if (switch_register_banks) arm_save_register_bank(cpu); cpu->cd.arm.cpsr = new_cpsr; cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28; if (switch_register_banks) arm_load_register_bank(cpu); } /* NOTE: Special case: Loading the PC */ if (iw & 0x8000) { cpu->pc = cpu->cd.arm.r[ARM_PC] & 0xfffffffc; if (cpu->machine->show_trace_tree) cpu_functioncall_trace_return(cpu); /* TODO: There is no need to update the pointers if this is a return to the same page! */ /* Find the new physical page and update the translation pointers: */ quick_pc_to_pointers_arm(cpu); } } /* * Shared between regular ARM and the THUMB encoded 'push'. */ void arm_push(struct cpu* cpu, uint32_t* np, int p_bit, int u_bit, int s_bit, int w_bit, uint16_t regs) { int i; uint32_t value, addr = *np; unsigned char data[4]; unsigned char *page; for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) { if (!((regs >> i) & 1)) { /* Skip register i: */ continue; } value = cpu->cd.arm.r[i]; if (s_bit) { switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) { case ARM_MODE_FIQ32: if (i >= 8 && i <= 14) value = cpu->cd.arm.default_r8_r14[i-8]; break; case ARM_MODE_ABT32: case ARM_MODE_UND32: case ARM_MODE_IRQ32: case ARM_MODE_SVC32: if (i >= 13 && i <= 14) value = cpu->cd.arm.default_r8_r14[i-8]; break; case ARM_MODE_USR32: case ARM_MODE_SYS32: break; } } /* NOTE/TODO: 8 vs 12 on some ARMs */ if (i == ARM_PC) value = cpu->pc + 12; if (p_bit) { if (u_bit) addr += sizeof(uint32_t); else addr -= sizeof(uint32_t); } page = cpu->cd.arm.host_store[addr >> 12]; if (page != NULL) { uint32_t *p32 = (uint32_t *) page; /* Change byte order of value if host and emulated endianness differ: */ #ifdef HOST_LITTLE_ENDIAN if (cpu->byte_order == EMUL_BIG_ENDIAN) #else if (cpu->byte_order == EMUL_LITTLE_ENDIAN) #endif value = ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | ((value & 0xff000000) >> 24); p32[(addr & 0xfff) >> 2] = value; } else { if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { data[0] = value; data[1] = value >> 8; data[2] = value >> 16; data[3] = value >> 24; } else { data[0] = value >> 24; data[1] = value >> 16; data[2] = value >> 8; data[3] = value; } if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_WRITE, CACHE_DATA)) { /* store failed */ return; } } if (!p_bit) { if (u_bit) addr += sizeof(uint32_t); else addr -= sizeof(uint32_t); } } if (w_bit) *np = addr; } /* * bdt_load: Block Data Transfer, Load * * arg[0] = pointer to uint32_t in host memory, pointing to the base register * arg[1] = 32-bit instruction word. Most bits are read from this. */ X(bdt_load) { uint32_t *np = (uint32_t *)ic->arg[0]; uint32_t low_pc; uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */ int p_bit = iw & 0x01000000; int u_bit = iw & 0x00800000; int s_bit = iw & 0x00400000; int w_bit = iw & 0x00200000; #ifdef GATHER_BDT_STATISTICS if (!s_bit) update_bdt_statistics(iw); #endif /* Synchronize the program counter: */ low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); arm_pop(cpu, np, p_bit, u_bit, s_bit, w_bit, (uint16_t)iw); } Y(bdt_load) /* * bdt_store: Block Data Transfer, Store * * arg[0] = pointer to uint32_t in host memory, pointing to the base register * arg[1] = 32-bit instruction word. Most bits are read from this. */ X(bdt_store) { uint32_t *np = (uint32_t *)ic->arg[0]; uint32_t low_pc; uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */ int p_bit = iw & 0x01000000; int u_bit = iw & 0x00800000; int s_bit = iw & 0x00400000; int w_bit = iw & 0x00200000; #ifdef GATHER_BDT_STATISTICS if (!s_bit) update_bdt_statistics(iw); #endif /* Synchronize the program counter: */ low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); arm_push(cpu, np, p_bit, u_bit, s_bit, w_bit, (uint16_t)iw); } Y(bdt_store) /* Various load/store multiple instructions: */ extern uint32_t *multi_opcode[256]; extern void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *); X(multi_0x08b15018); X(multi_0x08ac000c__ge); X(multi_0x08a05018); /*****************************************************************************/ /* * netbsd_memset: * * The core of a NetBSD/arm memset. * * f01bc420: e25XX080 subs rX,rX,#0x80 * f01bc424: a8ac000c stmgeia ip!,{r2,r3} (16 of these) * .. * f01bc464: caffffed bgt 0xf01bc420 */ X(netbsd_memset) { unsigned char *page; uint32_t addr; do { addr = cpu->cd.arm.r[ARM_IP]; instr(subs)(cpu, ic); if (((cpu->cd.arm.flags & ARM_F_N)?1:0) != ((cpu->cd.arm.flags & ARM_F_V)?1:0)) { cpu->n_translated_instrs += 16; /* Skip the store multiples: */ cpu->cd.arm.next_ic = &ic[17]; return; } /* Crossing a page boundary? Then continue non-combined. */ if ((addr & 0xfff) + 128 > 0x1000) return; /* R2/R3 non-zero? Not allowed here. */ if (cpu->cd.arm.r[2] != 0 || cpu->cd.arm.r[3] != 0) return; /* printf("addr = 0x%08x\n", addr); */ page = cpu->cd.arm.host_store[addr >> 12]; /* No page translation? Continue non-combined. */ if (page == NULL) return; /* Clear: */ memset(page + (addr & 0xfff), 0, 128); cpu->cd.arm.r[ARM_IP] = addr + 128; cpu->n_translated_instrs += 16; /* Branch back if greater: */ cpu->n_translated_instrs += 1; } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) == ((cpu->cd.arm.flags & ARM_F_V)?1:0) && !(cpu->cd.arm.flags & ARM_F_Z)); /* Continue at the instruction after the bgt: */ cpu->cd.arm.next_ic = &ic[18]; } /* * netbsd_memcpy: * * The core of a NetBSD/arm memcpy. * * f01bc530: e8b15018 ldmia r1!,{r3,r4,ip,lr} * f01bc534: e8a05018 stmia r0!,{r3,r4,ip,lr} * f01bc538: e8b15018 ldmia r1!,{r3,r4,ip,lr} * f01bc53c: e8a05018 stmia r0!,{r3,r4,ip,lr} * f01bc540: e2522020 subs r2,r2,#0x20 * f01bc544: aafffff9 bge 0xf01bc530 */ X(netbsd_memcpy) { unsigned char *page_0, *page_1; uint32_t addr_r0, addr_r1; do { addr_r0 = cpu->cd.arm.r[0]; addr_r1 = cpu->cd.arm.r[1]; /* printf("addr_r0 = %08x r1 = %08x\n", addr_r0, addr_r1); */ /* Crossing a page boundary? Then continue non-combined. */ if ((addr_r0 & 0xfff) + 32 > 0x1000 || (addr_r1 & 0xfff) + 32 > 0x1000) { instr(multi_0x08b15018)(cpu, ic); return; } page_0 = cpu->cd.arm.host_store[addr_r0 >> 12]; page_1 = cpu->cd.arm.host_store[addr_r1 >> 12]; /* No page translations? Continue non-combined. */ if (page_0 == NULL || page_1 == NULL) { instr(multi_0x08b15018)(cpu, ic); return; } memcpy(page_0 + (addr_r0 & 0xfff), page_1 + (addr_r1 & 0xfff), 32); cpu->cd.arm.r[0] = addr_r0 + 32; cpu->cd.arm.r[1] = addr_r1 + 32; cpu->n_translated_instrs += 4; instr(subs)(cpu, ic + 4); cpu->n_translated_instrs ++; /* Loop while greater or equal: */ cpu->n_translated_instrs ++; } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) == ((cpu->cd.arm.flags & ARM_F_V)?1:0)); /* Continue at the instruction after the bge: */ cpu->cd.arm.next_ic = &ic[6]; cpu->n_translated_instrs --; } /* * netbsd_cacheclean: * * The core of a NetBSD/arm cache clean routine, variant 1: * * f015f88c: e4902020 ldr r2,[r0],#32 * f015f890: e2511020 subs r1,r1,#0x20 * f015f894: 1afffffc bne 0xf015f88c * f015f898: ee070f9a mcr 15,0,r0,cr7,cr10,4 */ X(netbsd_cacheclean) { uint32_t r1 = cpu->cd.arm.r[1]; cpu->n_translated_instrs += ((r1 >> 5) * 3); cpu->cd.arm.r[0] += r1; cpu->cd.arm.r[1] = 0; cpu->cd.arm.next_ic = &ic[4]; } /* * netbsd_cacheclean2: * * The core of a NetBSD/arm cache clean routine, variant 2: * * f015f93c: ee070f3a mcr 15,0,r0,cr7,cr10,1 * f015f940: ee070f36 mcr 15,0,r0,cr7,cr6,1 * f015f944: e2800020 add r0,r0,#0x20 * f015f948: e2511020 subs r1,r1,#0x20 * f015f94c: 8afffffa bhi 0xf015f93c */ X(netbsd_cacheclean2) { cpu->n_translated_instrs += ((cpu->cd.arm.r[1] >> 5) * 5) - 1; cpu->cd.arm.next_ic = &ic[5]; } /* * netbsd_scanc: * * f01bccbc: e5d13000 ldrb r3,[r1] * f01bccc0: e7d23003 ldrb r3,[r2,r3] * f01bccc4: e113000c tsts r3,ip */ X(netbsd_scanc) { unsigned char *page = cpu->cd.arm.host_load[cpu->cd.arm.r[1] >> 12]; uint32_t t; if (page == NULL) { instr(load_w0_byte_u1_p1_imm)(cpu, ic); return; } t = page[cpu->cd.arm.r[1] & 0xfff]; t += cpu->cd.arm.r[2]; page = cpu->cd.arm.host_load[t >> 12]; if (page == NULL) { instr(load_w0_byte_u1_p1_imm)(cpu, ic); return; } cpu->cd.arm.r[3] = page[t & 0xfff]; t = cpu->cd.arm.r[3] & cpu->cd.arm.r[ARM_IP]; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (t == 0) cpu->cd.arm.flags |= ARM_F_Z; cpu->n_translated_instrs += 2; cpu->cd.arm.next_ic = &ic[3]; } /* * netbsd_idle: * * L: ldr rX,[rY] * teqs rX,#0 * bne X (samepage) * teqs rZ,#0 * beq L (samepage) * .... * X: somewhere else on the same page */ X(netbsd_idle) { uint32_t rY = reg(ic[0].arg[0]); uint32_t rZ = reg(ic[3].arg[0]); uint32_t *p; uint32_t rX; p = (uint32_t *) cpu->cd.arm.host_load[rY >> 12]; if (p == NULL) { instr(load_w0_word_u1_p1_imm)(cpu, ic); return; } rX = p[(rY & 0xfff) >> 2]; /* No need to convert endianness, since it's only a 0-test. */ /* This makes execution continue on the first teqs instruction, which is fine. */ if (rX != 0) { instr(load_w0_word_u1_p1_imm)(cpu, ic); return; } if (rZ == 0) { static int x = 0; /* Synch the program counter. */ uint32_t low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); /* Quasi-idle for a while: */ cpu->has_been_idling = 1; if (cpu->machine->ncpus == 1 && (++x) == 100) { usleep(50); x = 0; } cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 6; cpu->cd.arm.next_ic = ¬hing_call; return; } cpu->cd.arm.next_ic = &ic[5]; } /* * strlen: * * S: e5f03001 ldrb rY,[rX,#1]! * e3530000 cmps rY,#0 * 1afffffc bne S */ X(strlen) { unsigned int n_loops = 0; uint32_t rY, rX = reg(ic[0].arg[0]); unsigned char *p; do { rX ++; p = cpu->cd.arm.host_load[rX >> 12]; if (p == NULL) { cpu->n_translated_instrs += (n_loops * 3); instr(load_w1_byte_u1_p1_imm)(cpu, ic); return; } rY = reg(ic[0].arg[2]) = p[rX & 0xfff]; /* load */ reg(ic[0].arg[0]) = rX; /* writeback */ n_loops ++; /* Compare rY to zero: */ cpu->cd.arm.flags = ARM_F_C; if (rY == 0) cpu->cd.arm.flags |= ARM_F_Z; } while (rY != 0); cpu->n_translated_instrs += (n_loops * 3) - 1; cpu->cd.arm.next_ic = &ic[3]; } /* * xchg: * * e02YX00X eor rX,rY,rX * e02XY00Y eor rY,rX,rY * e02YX00X eor rX,rY,rX */ X(xchg) { uint32_t tmp = reg(ic[0].arg[0]); cpu->n_translated_instrs += 2; cpu->cd.arm.next_ic = &ic[3]; reg(ic[0].arg[0]) = reg(ic[1].arg[0]); reg(ic[1].arg[0]) = tmp; } /* * netbsd_copyin: * * e4b0a004 ldrt sl,[r0],#4 * e4b0b004 ldrt fp,[r0],#4 * e4b06004 ldrt r6,[r0],#4 * e4b07004 ldrt r7,[r0],#4 * e4b08004 ldrt r8,[r0],#4 * e4b09004 ldrt r9,[r0],#4 */ X(netbsd_copyin) { uint32_t r0 = cpu->cd.arm.r[0], ofs = (r0 & 0xffc), index = r0 >> 12; unsigned char *p = cpu->cd.arm.host_load[index]; uint32_t *p32 = (uint32_t *) p, *q32; int ok = cpu->cd.arm.is_userpage[index >> 5] & (1 << (index & 31)); if (ofs > 0x1000 - 6*4 || !ok || p == NULL) { instr(load_w1_word_u1_p0_imm)(cpu, ic); return; } q32 = &cpu->cd.arm.r[6]; ofs >>= 2; q32[0] = p32[ofs+2]; q32[1] = p32[ofs+3]; q32[2] = p32[ofs+4]; q32[3] = p32[ofs+5]; q32[4] = p32[ofs+0]; q32[5] = p32[ofs+1]; cpu->cd.arm.r[0] = r0 + 24; cpu->n_translated_instrs += 5; cpu->cd.arm.next_ic = &ic[6]; } /* * netbsd_copyout: * * e4a18004 strt r8,[r1],#4 * e4a19004 strt r9,[r1],#4 * e4a1a004 strt sl,[r1],#4 * e4a1b004 strt fp,[r1],#4 * e4a16004 strt r6,[r1],#4 * e4a17004 strt r7,[r1],#4 */ X(netbsd_copyout) { uint32_t r1 = cpu->cd.arm.r[1], ofs = (r1 & 0xffc), index = r1 >> 12; unsigned char *p = cpu->cd.arm.host_store[index]; uint32_t *p32 = (uint32_t *) p, *q32; int ok = cpu->cd.arm.is_userpage[index >> 5] & (1 << (index & 31)); if (ofs > 0x1000 - 6*4 || !ok || p == NULL) { instr(store_w1_word_u1_p0_imm)(cpu, ic); return; } q32 = &cpu->cd.arm.r[6]; ofs >>= 2; p32[ofs ] = q32[2]; p32[ofs+1] = q32[3]; p32[ofs+2] = q32[4]; p32[ofs+3] = q32[5]; p32[ofs+4] = q32[0]; p32[ofs+5] = q32[1]; cpu->cd.arm.r[1] = r1 + 24; cpu->n_translated_instrs += 5; cpu->cd.arm.next_ic = &ic[6]; } /* * cmps by 0, followed by beq (inside the same page): */ X(cmps0_beq_samepage) { uint32_t a = reg(ic->arg[0]); cpu->n_translated_instrs ++; if (a == 0) { cpu->cd.arm.flags = ARM_F_Z | ARM_F_C; } else { /* Semi-ugly hack which sets the negative-bit if a < 0: */ cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8); } if (a == 0) cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; else cpu->cd.arm.next_ic = &ic[2]; } /* * cmps followed by beq (inside the same page): */ X(cmps_beq_samepage) { uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b; cpu->n_translated_instrs ++; cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0; if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) || ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0)) cpu->cd.arm.flags |= ARM_F_V; if (c == 0) { cpu->cd.arm.flags |= ARM_F_Z; cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; } else { cpu->cd.arm.next_ic = &ic[2]; if (c & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; } } /* * cmps followed by beq (not the same page): */ X(cmps_0_beq) { uint32_t a = reg(ic->arg[0]); cpu->n_translated_instrs ++; if (a == 0) { cpu->cd.arm.flags = ARM_F_Z | ARM_F_C; cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic[1].arg[0]); quick_pc_to_pointers_arm(cpu); } else { /* Semi-ugly hack which sets the negative-bit if a < 0: */ cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8); cpu->cd.arm.next_ic = &ic[2]; } } X(cmps_pos_beq) { uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b; cpu->n_translated_instrs ++; cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0; if ((int32_t)a < 0 && (int32_t)c >= 0) cpu->cd.arm.flags |= ARM_F_V; if (c == 0) { cpu->cd.arm.flags |= ARM_F_Z; cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic[1].arg[0]); quick_pc_to_pointers_arm(cpu); } else { cpu->cd.arm.next_ic = &ic[2]; if (c & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; } } X(cmps_neg_beq) { uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b; cpu->n_translated_instrs ++; cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0; if ((int32_t)a >= 0 && (int32_t)c < 0) cpu->cd.arm.flags |= ARM_F_V; if (c == 0) { cpu->cd.arm.flags |= ARM_F_Z; cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic[1].arg[0]); quick_pc_to_pointers_arm(cpu); } else { cpu->cd.arm.next_ic = &ic[2]; if (c & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; } } /* * cmps by 0, followed by bne (inside the same page): */ X(cmps0_bne_samepage) { uint32_t a = reg(ic->arg[0]); cpu->n_translated_instrs ++; if (a == 0) { cpu->cd.arm.flags = ARM_F_Z | ARM_F_C; } else { /* Semi-ugly hack which sets the negative-bit if a < 0: */ cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8); } if (a == 0) cpu->cd.arm.next_ic = &ic[2]; else cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; } /* * cmps followed by bne (inside the same page): */ X(cmps_bne_samepage) { uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b; cpu->n_translated_instrs ++; cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0; if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) || ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0)) cpu->cd.arm.flags |= ARM_F_V; if (c == 0) { cpu->cd.arm.flags |= ARM_F_Z; cpu->cd.arm.next_ic = &ic[2]; } else { if (c & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; } } /* * cmps followed by bcc (inside the same page): */ X(cmps_bcc_samepage) { uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b; cpu->n_translated_instrs ++; cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0; if (c & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; else if (c == 0) cpu->cd.arm.flags |= ARM_F_Z; if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) || ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0)) cpu->cd.arm.flags |= ARM_F_V; if (a >= b) cpu->cd.arm.next_ic = &ic[2]; else cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; } /* * cmps (reg) followed by bcc (inside the same page): */ X(cmps_reg_bcc_samepage) { uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = a - b; cpu->n_translated_instrs ++; cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0; if (c & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; else if (c == 0) cpu->cd.arm.flags |= ARM_F_Z; if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) || ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0)) cpu->cd.arm.flags |= ARM_F_V; if (a >= b) cpu->cd.arm.next_ic = &ic[2]; else cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; } /* * cmps followed by bhi (inside the same page): */ X(cmps_bhi_samepage) { uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b; cpu->n_translated_instrs ++; cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0; if (c & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; else if (c == 0) cpu->cd.arm.flags |= ARM_F_Z; if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) || ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0)) cpu->cd.arm.flags |= ARM_F_V; if (a > b) cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; else cpu->cd.arm.next_ic = &ic[2]; } /* * cmps (reg) followed by bhi (inside the same page): */ X(cmps_reg_bhi_samepage) { uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = a - b; cpu->n_translated_instrs ++; cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0; if (c & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; else if (c == 0) cpu->cd.arm.flags |= ARM_F_Z; if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) || ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0)) cpu->cd.arm.flags |= ARM_F_V; if (a > b) cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; else cpu->cd.arm.next_ic = &ic[2]; } /* * cmps followed by bgt (inside the same page): */ X(cmps_bgt_samepage) { uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b; cpu->n_translated_instrs ++; cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0; if (c & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; else if (c == 0) cpu->cd.arm.flags |= ARM_F_Z; if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) || ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0)) cpu->cd.arm.flags |= ARM_F_V; if ((int32_t)a > (int32_t)b) cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; else cpu->cd.arm.next_ic = &ic[2]; } /* * cmps followed by ble (inside the same page): */ X(cmps_ble_samepage) { uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b; cpu->n_translated_instrs ++; cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0; if (c & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; else if (c == 0) cpu->cd.arm.flags |= ARM_F_Z; if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) || ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0)) cpu->cd.arm.flags |= ARM_F_V; if ((int32_t)a <= (int32_t)b) cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; else cpu->cd.arm.next_ic = &ic[2]; } /* * teqs followed by beq (inside the same page): */ X(teqs_beq_samepage) { uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a ^ b; cpu->n_translated_instrs ++; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (c == 0) { cpu->cd.arm.flags |= ARM_F_Z; cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; } else { if (c & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; cpu->cd.arm.next_ic = &ic[2]; } } /* * tsts followed by beq (inside the same page): * (arg[1] must not have its highest bit set)) */ X(tsts_lo_beq_samepage) { uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a & b; cpu->n_translated_instrs ++; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (c == 0) cpu->cd.arm.flags |= ARM_F_Z; if (c == 0) cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; else cpu->cd.arm.next_ic = &ic[2]; } /* * teqs followed by bne (inside the same page): */ X(teqs_bne_samepage) { uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a ^ b; cpu->n_translated_instrs ++; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (c == 0) { cpu->cd.arm.flags |= ARM_F_Z; } else { if (c & 0x80000000) cpu->cd.arm.flags |= ARM_F_N; } if (c == 0) cpu->cd.arm.next_ic = &ic[2]; else cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; } /* * tsts followed by bne (inside the same page): * (arg[1] must not have its highest bit set)) */ X(tsts_lo_bne_samepage) { uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a & b; cpu->n_translated_instrs ++; cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N); if (c == 0) cpu->cd.arm.flags |= ARM_F_Z; if (c == 0) cpu->cd.arm.next_ic = &ic[2]; else cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0]; } /*****************************************************************************/ X(end_of_page) { /* Update the PC: (offset 0, but on the next page) */ cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc += (ARM_IC_ENTRIES_PER_PAGE << ARM_INSTR_ALIGNMENT_SHIFT); /* Find the new physical page and update the translation pointers: */ quick_pc_to_pointers_arm(cpu); /* end_of_page doesn't count as an executed instruction: */ cpu->n_translated_instrs --; } /*****************************************************************************/ /* * Combine: netbsd_memset(): * * Check for the core of a NetBSD/arm memset; large memsets use a sequence * of 16 store-multiple instructions, each storing 2 registers at a time. */ void COMBINE(netbsd_memset)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { #ifdef HOST_LITTLE_ENDIAN int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) & (ARM_IC_ENTRIES_PER_PAGE-1); if (n_back >= 17) { int i; for (i=-16; i<=-1; i++) if (ic[i].f != instr(multi_0x08ac000c__ge)) return; if (ic[-17].f == instr(subs) && ic[-17].arg[0]==ic[-17].arg[2] && ic[-17].arg[1] == 128 && ic[ 0].f == instr(b_samepage__gt) && ic[ 0].arg[0] == (size_t)&ic[-17]) { ic[-17].f = instr(netbsd_memset); } } #endif } /* * Combine: netbsd_memcpy(): * * Check for the core of a NetBSD/arm memcpy; large memcpys use a * sequence of ldmia instructions. */ void COMBINE(netbsd_memcpy)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { #ifdef HOST_LITTLE_ENDIAN int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) & (ARM_IC_ENTRIES_PER_PAGE-1); if (n_back >= 5) { if (ic[-5].f==instr(multi_0x08b15018) && ic[-4].f==instr(multi_0x08a05018) && ic[-3].f==instr(multi_0x08b15018) && ic[-2].f==instr(multi_0x08a05018) && ic[-1].f == instr(subs) && ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20 && ic[ 0].f == instr(b_samepage__ge) && ic[ 0].arg[0] == (size_t)&ic[-5]) { ic[-5].f = instr(netbsd_memcpy); } } #endif } /* * Combine: netbsd_cacheclean(): * * Check for the core of a NetBSD/arm cache clean. (There are two variants.) */ void COMBINE(netbsd_cacheclean)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) & (ARM_IC_ENTRIES_PER_PAGE-1); if (n_back >= 3) { if (ic[-3].f==instr(load_w0_word_u1_p0_imm) && ic[-2].f == instr(subs) && ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 && ic[-1].f == instr(b_samepage__ne) && ic[-1].arg[0] == (size_t)&ic[-3]) { ic[-3].f = instr(netbsd_cacheclean); } } } /* * Combine: netbsd_cacheclean2(): * * Check for the core of a NetBSD/arm cache clean. (Second variant.) */ void COMBINE(netbsd_cacheclean2)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) & (ARM_IC_ENTRIES_PER_PAGE-1); if (n_back >= 4) { if (ic[-4].f == instr(mcr_mrc) && ic[-4].arg[0] == 0xee070f3a && ic[-3].f == instr(mcr_mrc) && ic[-3].arg[0] == 0xee070f36 && ic[-2].f == instr(add) && ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 && ic[-1].f == instr(subs) && ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20) { ic[-4].f = instr(netbsd_cacheclean2); } } } /* * Combine: netbsd_scanc(): */ void COMBINE(netbsd_scanc)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) & (ARM_IC_ENTRIES_PER_PAGE-1); if (n_back < 2) return; if (ic[-2].f == instr(load_w0_byte_u1_p1_imm) && ic[-2].arg[0] == (size_t)(&cpu->cd.arm.r[1]) && ic[-2].arg[1] == 0 && ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[3]) && ic[-1].f == instr(load_w0_byte_u1_p1_reg) && ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[2]) && ic[-1].arg[1] == (size_t)arm_r_r3_t0_c0 && ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[3])) { ic[-2].f = instr(netbsd_scanc); } } /* * Combine: strlen(): */ void COMBINE(strlen)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) & (ARM_IC_ENTRIES_PER_PAGE-1); if (n_back < 2) return; if (ic[-2].f == instr(load_w1_byte_u1_p1_imm) && ic[-2].arg[1] == 1 && ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[3]) && ic[-1].f == instr(cmps) && ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[3]) && ic[-1].arg[1] == 0) { ic[-2].f = instr(strlen); } } /* * Combine: xchg(): */ void COMBINE(xchg)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) & (ARM_IC_ENTRIES_PER_PAGE-1); size_t a, b; if (n_back < 2) return; a = ic[-2].arg[0]; b = ic[-1].arg[0]; if (ic[-2].f == instr(eor_regshort) && ic[-1].f == instr(eor_regshort) && ic[-2].arg[0] == a && ic[-2].arg[1] == b && ic[-2].arg[2] == b && ic[-1].arg[0] == b && ic[-1].arg[1] == a && ic[-1].arg[2] == a && ic[ 0].arg[0] == a && ic[ 0].arg[1] == b && ic[ 0].arg[2] == b) { ic[-2].f = instr(xchg); } } /* * Combine: netbsd_copyin(): */ void COMBINE(netbsd_copyin)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { #ifdef HOST_LITTLE_ENDIAN int i, n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) & (ARM_IC_ENTRIES_PER_PAGE-1); if (n_back < 5) return; for (i=-5; i<0; i++) { if (ic[i].f != instr(load_w1_word_u1_p0_imm) || ic[i].arg[0] != (size_t)(&cpu->cd.arm.r[0]) || ic[i].arg[1] != 4) return; } if (ic[-5].arg[2] == (size_t)(&cpu->cd.arm.r[10]) && ic[-4].arg[2] == (size_t)(&cpu->cd.arm.r[11]) && ic[-3].arg[2] == (size_t)(&cpu->cd.arm.r[6]) && ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[7]) && ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[8])) { ic[-5].f = instr(netbsd_copyin); } #endif } /* * Combine: netbsd_copyout(): */ void COMBINE(netbsd_copyout)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { #ifdef HOST_LITTLE_ENDIAN int i, n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) & (ARM_IC_ENTRIES_PER_PAGE-1); if (n_back < 5) return; for (i=-5; i<0; i++) { if (ic[i].f != instr(store_w1_word_u1_p0_imm) || ic[i].arg[0] != (size_t)(&cpu->cd.arm.r[1]) || ic[i].arg[1] != 4) return; } if (ic[-5].arg[2] == (size_t)(&cpu->cd.arm.r[8]) && ic[-4].arg[2] == (size_t)(&cpu->cd.arm.r[9]) && ic[-3].arg[2] == (size_t)(&cpu->cd.arm.r[10]) && ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[11]) && ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[6])) { ic[-5].f = instr(netbsd_copyout); } #endif } /* * Combine: cmps + beq, etc: */ void COMBINE(beq_etc)(struct cpu *cpu, struct arm_instr_call *ic, int low_addr) { int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT) & (ARM_IC_ENTRIES_PER_PAGE-1); if (n_back < 1) return; if (ic[0].f == instr(b__eq)) { if (ic[-1].f == instr(cmps)) { if (ic[-1].arg[1] == 0) ic[-1].f = instr(cmps_0_beq); else if (ic[-1].arg[1] & 0x80000000) ic[-1].f = instr(cmps_neg_beq); else ic[-1].f = instr(cmps_pos_beq); } return; } if (ic[0].f == instr(b_samepage__eq)) { if (ic[-1].f == instr(cmps)) { if (ic[-1].arg[1] == 0) ic[-1].f = instr(cmps0_beq_samepage); else ic[-1].f = instr(cmps_beq_samepage); } if (ic[-1].f == instr(tsts) && !(ic[-1].arg[1] & 0x80000000)) { ic[-1].f = instr(tsts_lo_beq_samepage); } if (n_back >= 4 && ic[-4].f == instr(load_w0_word_u1_p1_imm) && ic[-4].arg[0] != ic[-4].arg[2] && ic[-4].arg[1] == 0 && ic[-4].arg[2] == ic[-3].arg[0] && /* Note: The teqs+bne is already combined! */ ic[-3].f == instr(teqs_bne_samepage) && ic[-3].arg[1] == 0 && ic[-2].f == instr(b_samepage__ne) && ic[-1].f == instr(teqs) && ic[-1].arg[0] != ic[-4].arg[0] && ic[-1].arg[1] == 0) { ic[-4].f = instr(netbsd_idle); } if (ic[-1].f == instr(teqs)) { ic[-1].f = instr(teqs_beq_samepage); } return; } if (ic[0].f == instr(b_samepage__ne)) { if (ic[-1].f == instr(cmps)) { if (ic[-1].arg[1] == 0) ic[-1].f = instr(cmps0_bne_samepage); else ic[-1].f = instr(cmps_bne_samepage); } if (ic[-1].f == instr(tsts) && !(ic[-1].arg[1] & 0x80000000)) { ic[-1].f = instr(tsts_lo_bne_samepage); } if (ic[-1].f == instr(teqs)) { ic[-1].f = instr(teqs_bne_samepage); } return; } if (ic[0].f == instr(b_samepage__cc)) { if (ic[-1].f == instr(cmps)) { ic[-1].f = instr(cmps_bcc_samepage); } if (ic[-1].f == instr(cmps_regshort)) { ic[-1].f = instr(cmps_reg_bcc_samepage); } return; } if (ic[0].f == instr(b_samepage__hi)) { if (ic[-1].f == instr(cmps)) { ic[-1].f = instr(cmps_bhi_samepage); } if (ic[-1].f == instr(cmps_regshort)) { ic[-1].f = instr(cmps_reg_bhi_samepage); } return; } if (ic[0].f == instr(b_samepage__gt)) { if (ic[-1].f == instr(cmps)) { ic[-1].f = instr(cmps_bgt_samepage); } return; } if (ic[0].f == instr(b_samepage__le)) { if (ic[-1].f == instr(cmps)) { ic[-1].f = instr(cmps_ble_samepage); } return; } } /*****************************************************************************/ static void arm_switch_clear(struct arm_instr_call *ic, int rd, int condition_code) { switch (rd) { case 0: ic->f = cond_instr(clear_r0); break; case 1: ic->f = cond_instr(clear_r1); break; case 2: ic->f = cond_instr(clear_r2); break; case 3: ic->f = cond_instr(clear_r3); break; case 4: ic->f = cond_instr(clear_r4); break; case 5: ic->f = cond_instr(clear_r5); break; case 6: ic->f = cond_instr(clear_r6); break; case 7: ic->f = cond_instr(clear_r7); break; case 8: ic->f = cond_instr(clear_r8); break; case 9: ic->f = cond_instr(clear_r9); break; case 10: ic->f = cond_instr(clear_r10); break; case 11: ic->f = cond_instr(clear_r11); break; case 12: ic->f = cond_instr(clear_r12); break; case 13: ic->f = cond_instr(clear_r13); break; case 14: ic->f = cond_instr(clear_r14); break; } } static void arm_switch_mov1(struct arm_instr_call *ic, int rd, int condition_code) { switch (rd) { case 0: ic->f = cond_instr(mov1_r0); break; case 1: ic->f = cond_instr(mov1_r1); break; case 2: ic->f = cond_instr(mov1_r2); break; case 3: ic->f = cond_instr(mov1_r3); break; case 4: ic->f = cond_instr(mov1_r4); break; case 5: ic->f = cond_instr(mov1_r5); break; case 6: ic->f = cond_instr(mov1_r6); break; case 7: ic->f = cond_instr(mov1_r7); break; case 8: ic->f = cond_instr(mov1_r8); break; case 9: ic->f = cond_instr(mov1_r9); break; case 10: ic->f = cond_instr(mov1_r10); break; case 11: ic->f = cond_instr(mov1_r11); break; case 12: ic->f = cond_instr(mov1_r12); break; case 13: ic->f = cond_instr(mov1_r13); break; case 14: ic->f = cond_instr(mov1_r14); break; } } static void arm_switch_add1(struct arm_instr_call *ic, int rd, int condition_code) { switch (rd) { case 0: ic->f = cond_instr(add1_r0); break; case 1: ic->f = cond_instr(add1_r1); break; case 2: ic->f = cond_instr(add1_r2); break; case 3: ic->f = cond_instr(add1_r3); break; case 4: ic->f = cond_instr(add1_r4); break; case 5: ic->f = cond_instr(add1_r5); break; case 6: ic->f = cond_instr(add1_r6); break; case 7: ic->f = cond_instr(add1_r7); break; case 8: ic->f = cond_instr(add1_r8); break; case 9: ic->f = cond_instr(add1_r9); break; case 10: ic->f = cond_instr(add1_r10); break; case 11: ic->f = cond_instr(add1_r11); break; case 12: ic->f = cond_instr(add1_r12); break; case 13: ic->f = cond_instr(add1_r13); break; case 14: ic->f = cond_instr(add1_r14); break; } } /*****************************************************************************/ /* * arm_instr_to_be_translated(): * * Translate an instruction word into an arm_instr_call. ic is filled in with * valid data for the translated instruction, or a "nothing" instruction if * there was a translation failure. The newly translated instruction is then * executed. */ X(to_be_translated) { uint32_t addr, low_pc, iword, imm = 0; unsigned char *page; unsigned char ib[4]; int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8; int p_bit, u_bit, w_bit, l_bit, regform, rm, any_pc_reg; // , c, t void (*samepage_function)(struct cpu *, struct arm_instr_call *); /* Figure out the address of the instruction: */ low_pc = ((size_t)ic - (size_t)cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); addr = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); cpu->pc = addr; addr &= ~((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1); /* Read the instruction word from memory: */ page = cpu->cd.arm.host_load[addr >> 12]; if (page != NULL) { /* fatal("TRANSLATION HIT! 0x%08x\n", addr); */ memcpy(ib, page + (addr & 0xfff), sizeof(ib)); } else { /* fatal("TRANSLATION MISS! 0x%08x\n", addr); */ if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0], sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) { fatal("to_be_translated(): " "read failed: TODO\n"); return; } } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) iword = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24); else iword = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24); #define DYNTRANS_TO_BE_TRANSLATED_HEAD #include "cpu_dyntrans.cc" #undef DYNTRANS_TO_BE_TRANSLATED_HEAD /* The idea of taking bits 27..24 was found here: http://armphetamine.sourceforge.net/oldinfo.html */ condition_code = iword >> 28; main_opcode = (iword >> 24) & 15; secondary_opcode = (iword >> 21) & 15; u_bit = iword & 0x00800000; w_bit = iword & 0x00200000; s_bit = l_bit = iword & 0x00100000; rn = (iword >> 16) & 15; rd = (iword >> 12) & 15; r8 = (iword >> 8) & 15; // c = (iword >> 7) & 31; // t = (iword >> 4) & 7; rm = iword & 15; /* * Translate the instruction: */ if ((iword >> 28) == 0xf) { /* The "never" condition is nowadays used for special encodings. */ if ((iword & 0xfc70f000) == 0xf450f000) { /* Preload: TODO. Treat as NOP for now. */ ic->f = instr(nop); goto okay; } switch (main_opcode) { case 0xa: case 0xb: ic->f = instr(blx_imm); /* arg 1 = offset of current instruction */ ic->arg[1] = addr & 0xffc; /* arg 0 = relative jump distance + 1 (to enable THUMB) */ ic->arg[0] = (iword & 0x00ffffff) << 2; /* Sign-extend: */ if (ic->arg[0] & 0x02000000) ic->arg[0] |= 0xfc000000; if (main_opcode == 0xb) ic->arg[0] += 2; ic->arg[0] = (int32_t)(ic->arg[0] + 8 + 1); break; default: goto bad; } goto okay; } switch (main_opcode) { case 0x0: case 0x1: case 0x2: case 0x3: /* Check special cases first: */ if ((iword & 0x0fc000f0) == 0x00000090) { /* * Multiplication: * xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */ if (iword & 0x00200000) { if (s_bit) ic->f = cond_instr(mlas); else ic->f = cond_instr(mla); ic->arg[0] = iword; } else { if (s_bit) ic->f = cond_instr(muls); else ic->f = cond_instr(mul); /* NOTE: rn means rd in this case: */ ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]); ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]); ic->arg[2] = (size_t)(&cpu->cd.arm.r[r8]); } break; } if ((iword & 0x0f8000f0) == 0x00800090) { /* Long multiplication: */ if (s_bit) { if (!cpu->translation_readahead) fatal("TODO: sbit mull\n"); goto bad; } ic->f = cond_instr(mull); ic->arg[0] = iword; break; } if ((iword & 0x0f900ff0) == 0x01000050) { if (!cpu->translation_readahead) fatal("TODO: q{,d}{add,sub}\n"); goto bad; } if ((iword & 0x0ff000d0) == 0x01200010) { /* bx or blx */ if (iword & 0x20) ic->f = cond_instr(blx_reg); else { if (cpu->machine->show_trace_tree && rm == ARM_LR) ic->f = cond_instr(bx_trace); else ic->f = cond_instr(bx); } ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]); ic->arg[2] = (addr & 0xffc) + 4; break; } if ((iword & 0x0fb00ff0) == 0x1000090) { if (iword & 0x00400000) ic->f = cond_instr(swpb); else ic->f = cond_instr(swp); ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]); ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]); ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]); break; } if ((iword & 0x0fff0ff0) == 0x016f0f10) { ic->f = cond_instr(clz); ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]); ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]); break; } if ((iword & 0x0ff00090) == 0x01000080) { /* TODO: smlaXX */ goto bad; } if ((iword & 0x0ff00090) == 0x01400080) { /* TODO: smlalY */ goto bad; } if ((iword & 0x0ff000b0) == 0x01200080) { /* TODO: smlawY */ goto bad; } if ((iword & 0x0ff0f090) == 0x01600080) { /* smulXY (16-bit * 16-bit => 32-bit) */ switch (iword & 0x60) { case 0x00: ic->f = cond_instr(smulbb); break; case 0x20: ic->f = cond_instr(smultb); break; case 0x40: ic->f = cond_instr(smulbt); break; default: ic->f = cond_instr(smultt); break; } ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]); ic->arg[1] = (size_t)(&cpu->cd.arm.r[r8]); ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]); /* Rd */ break; } if ((iword & 0x0ff0f0b0) == 0x012000a0) { /* TODO: smulwY */ goto bad; } if ((iword & 0x0fb0fff0) == 0x0120f000 || (iword & 0x0fb0f000) == 0x0320f000) { /* msr: move to [S|C]PSR from a register or immediate value */ if (iword & 0x02000000) { if (iword & 0x00400000) ic->f = cond_instr(msr_imm_spsr); else ic->f = cond_instr(msr_imm); } else { if (rm == ARM_PC) { if (!cpu->translation_readahead) fatal("msr PC?\n"); goto bad; } if (iword & 0x00400000) ic->f = cond_instr(msr_spsr); else ic->f = cond_instr(msr); } imm = iword & 0xff; while (r8-- > 0) imm = (imm >> 2) | ((imm & 3) << 30); ic->arg[0] = imm; ic->arg[2] = (size_t)(&cpu->cd.arm.r[rm]); { uint32_t arg1 = 0; if (iword & (1<<16)) arg1 |= 0x000000ff; if (iword & (1<<17)) arg1 |= 0x0000ff00; if (iword & (1<<18)) arg1 |= 0x00ff0000; if (iword & (1<<19)) arg1 |= 0xff000000; if (arg1 == 0) { if (!cpu->translation_readahead) fatal("msr no fields\n"); goto bad; } ic->arg[1] = arg1; } break; } if ((iword & 0x0fbf0fff) == 0x010f0000) { /* mrs: move from CPSR/SPSR to a register: */ if (rd == ARM_PC) { if (!cpu->translation_readahead) fatal("mrs PC?\n"); goto bad; } if (iword & 0x00400000) ic->f = cond_instr(mrs_spsr); else ic->f = cond_instr(mrs); ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]); break; } if ((iword & 0x0e000090) == 0x00000090) { regform = !(iword & 0x00400000); imm = ((iword >> 4) & 0xf0) | (iword & 0xf); p_bit = main_opcode & 1; ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]); ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]); if (rd == ARM_PC || rn == ARM_PC) { ic->f = arm_load_store_instr_3_pc[ condition_code + (l_bit? 16 : 0) + (iword & 0x40? 32 : 0) + (w_bit? 64 : 0) + (iword & 0x20? 128 : 0) + (u_bit? 256 : 0) + (p_bit? 512 : 0) + (regform? 1024 : 0)]; if (rn == ARM_PC) ic->arg[0] = (size_t) (&cpu->cd.arm.tmp_pc); if (!l_bit && rd == ARM_PC) ic->arg[2] = (size_t) (&cpu->cd.arm.tmp_pc); } else ic->f = arm_load_store_instr_3[ condition_code + (l_bit? 16 : 0) + (iword & 0x40? 32 : 0) + (w_bit? 64 : 0) + (iword & 0x20? 128 : 0) + (u_bit? 256 : 0) + (p_bit? 512 : 0) + (regform? 1024 : 0)]; if (regform) ic->arg[1] = (size_t)(void *)arm_r[iword & 0xf]; else ic->arg[1] = imm; break; } if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) { if (!cpu->translation_readahead) fatal("reg form blah blah\n"); goto bad; } /* "bkpt", ARMv5 and above */ if ((iword & 0x0ff000f0) == 0x01200070) { ic->f = cond_instr(bkpt); ic->arg[0] = addr & 0xfff; break; } /* "mov pc,lr": */ if ((iword & 0x0fffffff) == 0x01a0f00e) { if (cpu->machine->show_trace_tree) ic->f = cond_instr(ret_trace); else ic->f = cond_instr(ret); break; } /* "mov reg,reg" or "mov reg,pc": */ if ((iword & 0x0fff0ff0) == 0x01a00000 && rd != ARM_PC) { if (rm != ARM_PC) { ic->f = cond_instr(mov_reg_reg); ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]); } else { ic->f = cond_instr(mov_reg_pc); ic->arg[0] = (addr & 0xfff) + 8; } ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]); break; } /* "mov reg,#0": */ if ((iword & 0x0fff0fff) == 0x03a00000 && rd != ARM_PC) { arm_switch_clear(ic, rd, condition_code); break; } /* "mov reg,#1": */ if ((iword & 0x0fff0fff) == 0x03a00001 && rd != ARM_PC) { arm_switch_mov1(ic, rd, condition_code); break; } /* "add reg,reg,#1": */ if ((iword & 0x0ff00fff) == 0x02800001 && rd != ARM_PC && rn == rd) { arm_switch_add1(ic, rd, condition_code); break; } /* * Generic Data Processing Instructions: */ if ((main_opcode & 2) == 0) regform = 1; else regform = 0; if (regform) { /* 0x1000 signifies Carry bit update on rotation, which is not necessary for add,adc,sub,sbc, rsb,rsc,cmp, or cmn, because they update the Carry bit manually anyway. */ int q = 0x1000; if (s_bit == 0) q = 0; if ((secondary_opcode >= 2 && secondary_opcode <= 7) || secondary_opcode==0xa || secondary_opcode==0xb) q = 0; ic->arg[1] = (size_t)(void *)arm_r[(iword & 0xfff) + q]; } else { int steps = r8; imm = iword & 0xff; while (r8-- > 0) imm = (imm >> 2) | ((imm & 3) << 30); if (steps != 0 && (imm != 0 && imm < 256)) { if (!cpu->translation_readahead) fatal("TODO: see cpu_arm_instr_dpi; non-zero steps but still under 256 is not implemented yet\n"); goto bad; } ic->arg[1] = imm; } /* mvn #imm ==> mov #~imm */ if (secondary_opcode == 0xf && !regform) { secondary_opcode = 0xd; ic->arg[1] = ~ic->arg[1]; } ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]); ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]); any_pc_reg = 0; if (rn == ARM_PC || rd == ARM_PC) any_pc_reg = 1; if (!any_pc_reg && regform && (iword & 0xfff) < ARM_PC) { ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]); ic->f = arm_dpi_instr_regshort[condition_code + 16 * secondary_opcode + (s_bit? 256 : 0)]; } else ic->f = arm_dpi_instr[condition_code + 16 * secondary_opcode + (s_bit? 256 : 0) + (any_pc_reg? 512 : 0) + (regform? 1024 : 0)]; if (ic->f == instr(eor_regshort)) cpu->cd.arm.combination_check = COMBINE(xchg); if (iword == 0xe113000c) cpu->cd.arm.combination_check = COMBINE(netbsd_scanc); break; case 0x4: /* Load and store... */ case 0x5: /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate */ case 0x6: /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register */ case 0x7: ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]); ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]); if (rd == ARM_PC || rn == ARM_PC) { ic->f = arm_load_store_instr_pc[((iword >> 16) & 0x3f0) + condition_code]; if (rn == ARM_PC) ic->arg[0] = (size_t)(&cpu->cd.arm.tmp_pc); if (!l_bit && rd == ARM_PC) ic->arg[2] = (size_t)(&cpu->cd.arm.tmp_pc); } else { ic->f = arm_load_store_instr[((iword >> 16) & 0x3f0) + condition_code]; } imm = iword & 0xfff; if (main_opcode < 6) ic->arg[1] = imm; else ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff]; if ((iword & 0x0e000010) == 0x06000010) { /* GDB uses this for breakpoints. */ ic->f = cond_instr(und); ic->arg[0] = addr & 0xfff; } /* Special case: pc-relative load within the same page: */ if (rn == ARM_PC && rd != ARM_PC && main_opcode < 6 && l_bit) { unsigned char *p = page; int ofs = (addr & 0xfff) + 8, max = 0xffc; int b_bit = iword & 0x00400000; if (b_bit) max = 0xfff; if (u_bit) ofs += (iword & 0xfff); else ofs -= (iword & 0xfff); /* NOTE/TODO: This assumes 4KB pages, it will not work with 1KB pages. */ if (ofs >= 0 && ofs <= max && p != NULL) { unsigned char cbuf[4]; int len = b_bit? 1 : 4; uint32_t x, a = (addr & 0xfffff000) | ofs; /* ic->f = cond_instr(mov); */ ic->f = arm_dpi_instr[condition_code + 16*0xd]; ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]); memcpy(cbuf, p + (a & 0xfff), len); if (b_bit) { x = cbuf[0]; } else { if (cpu->byte_order == EMUL_LITTLE_ENDIAN) x = cbuf[0] + (cbuf[1]<<8) + (cbuf[2]<<16) + (cbuf[3]<<24); else x = cbuf[3] + (cbuf[2]<<8) + (cbuf[1]<<16) + (cbuf[0]<<24); } ic->arg[1] = x; } } if (iword == 0xe4b09004) cpu->cd.arm.combination_check = COMBINE(netbsd_copyin); if (iword == 0xe4a17004) cpu->cd.arm.combination_check = COMBINE(netbsd_copyout); break; case 0x8: /* Multiple load/store... (Block data transfer) */ case 0x9: /* xxxx100P USWLnnnn llllllll llllllll */ ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]); ic->arg[1] = (size_t)iword; /* Generic case: */ if (l_bit) ic->f = cond_instr(bdt_load); else ic->f = cond_instr(bdt_store); #if defined(HOST_LITTLE_ENDIAN) && !defined(GATHER_BDT_STATISTICS) /* * Check for availability of optimized implementation: * xxxx100P USWLnnnn llllllll llllllll * ^ ^ ^ ^ ^ ^ ^ ^ (0x00950154) * These bits are used to select which list to scan, and then * the list is scanned linearly. * * The optimized functions do not support show_trace_tree, * but it's ok to use the unoptimized version in that case. */ if (!cpu->machine->show_trace_tree) { int i = 0, j = iword; j = ((j & 0x00800000) >> 16) | ((j & 0x00100000) >> 14) | ((j & 0x00040000) >> 13) | ((j & 0x00010000) >> 12) | ((j & 0x00000100) >> 5) | ((j & 0x00000040) >> 4) | ((j & 0x00000010) >> 3) | ((j & 0x00000004) >> 2); while (multi_opcode[j][i] != 0) { if ((iword & 0x0fffffff) == multi_opcode[j][i]) { ic->f = multi_opcode_f[j] [i*16 + condition_code]; break; } i ++; } } #endif if (rn == ARM_PC) { if (!cpu->translation_readahead) fatal("TODO: bdt with PC as base\n"); goto bad; } break; case 0xa: /* B: branch */ case 0xb: /* BL: branch+link */ if (main_opcode == 0x0a) { ic->f = cond_instr(b); samepage_function = cond_instr(b_samepage); /* Abort read-ahead on unconditional branches: */ if (condition_code == 0xe && cpu->translation_readahead > 1) cpu->translation_readahead = 1; if (iword == 0xcaffffed) cpu->cd.arm.combination_check = COMBINE(netbsd_memset); if (iword == 0xaafffff9) cpu->cd.arm.combination_check = COMBINE(netbsd_memcpy); } else { if (cpu->machine->show_trace_tree) { ic->f = cond_instr(bl_trace); samepage_function = cond_instr(bl_samepage_trace); } else { ic->f = cond_instr(bl); samepage_function = cond_instr(bl_samepage); } } /* arg 1 = offset of current instruction */ /* arg 2 = offset of the following instruction */ ic->arg[1] = addr & 0xffc; ic->arg[2] = (addr & 0xffc) + 4; ic->arg[0] = (iword & 0x00ffffff) << 2; /* Sign-extend: */ if (ic->arg[0] & 0x02000000) ic->arg[0] |= 0xfc000000; /* * Branches are calculated as PC + 8 + offset. */ ic->arg[0] = (int32_t)(ic->arg[0] + 8); /* * Special case: branch within the same page: * * arg[0] = addr of the arm_instr_call of the target * arg[1] = addr of the next arm_instr_call. */ { uint32_t mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT) | ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1); uint32_t old_pc = addr; uint32_t new_pc = old_pc + (int32_t)ic->arg[0]; if ((old_pc & ~mask_within_page) == (new_pc & ~mask_within_page)) { ic->f = samepage_function; ic->arg[0] = (size_t) ( cpu->cd.arm.cur_ic_page + ((new_pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT)); ic->arg[1] = (size_t) ( cpu->cd.arm.cur_ic_page + (((addr & mask_within_page) + 4) >> ARM_INSTR_ALIGNMENT_SHIFT)); } else if (main_opcode == 0x0a) { /* Special hack for a plain "b": */ ic->arg[0] += ic->arg[1]; } } if (main_opcode == 0xa && (condition_code <= 1 || condition_code == 3 || condition_code == 8 || condition_code == 12 || condition_code == 13)) cpu->cd.arm.combination_check = COMBINE(beq_etc); if (iword == 0x1afffffc) cpu->cd.arm.combination_check = COMBINE(strlen); /* Hm. Does this really increase performance? */ if (iword == 0x8afffffa) cpu->cd.arm.combination_check = COMBINE(netbsd_cacheclean2); break; case 0xc: case 0xd: /* * xxxx1100 0100nnnn ddddcccc oooommmm MCRR c,op,Rd,Rn,CRm * xxxx1100 0101nnnn ddddcccc oooommmm MRRC c,op,Rd,Rn,CRm */ if ((iword & 0x0fe00fff) == 0x0c400000) { /* Special case: mar/mra DSP instructions */ if (!cpu->translation_readahead) fatal("TODO: mar/mra DSP instructions!\n"); /* Perhaps these are actually identical to MCRR/MRRC */ goto bad; } if ((iword & 0x0fe00000) == 0x0c400000) { if (!cpu->translation_readahead) fatal("MCRR/MRRC: TODO\n"); goto bad; } /* * TODO: LDC/STC * * For now, treat as Undefined instructions. This causes e.g. * Linux/ARM to emulate these instructions (floating point). */ #if 1 ic->f = cond_instr(und); ic->arg[0] = addr & 0xfff; #else if (!cpu->translation_readahead) fatal("LDC/STC: TODO\n"); goto bad; #endif break; case 0xe: if ((iword & 0x0ff00ff0) == 0x0e200010) { /* Special case: mia* DSP instructions */ /* See Intel's 27343601.pdf, page 16-20 */ if (!cpu->translation_readahead) fatal("TODO: mia* DSP instructions!\n"); goto bad; } if (iword & 0x10) { /* xxxx1110 oooLNNNN ddddpppp qqq1MMMM MCR/MRC */ ic->arg[0] = iword; ic->f = cond_instr(mcr_mrc); } else { /* xxxx1110 oooonnnn ddddpppp qqq0mmmm CDP */ ic->arg[0] = iword; ic->f = cond_instr(cdp); } if (iword == 0xee070f9a) cpu->cd.arm.combination_check = COMBINE(netbsd_cacheclean); break; case 0xf: /* SWI: */ /* Default handler: */ ic->f = cond_instr(swi); ic->arg[0] = addr & 0xfff; if (iword == 0xef8c64eb) { /* Hack for rebooting a machine: */ ic->f = instr(reboot); } else if (iword == 0xef8c64be) { /* Hack for openfirmware prom emulation: */ ic->f = instr(openfirmware); } break; default:goto bad; } okay: #define DYNTRANS_TO_BE_TRANSLATED_TAIL #include "cpu_dyntrans.cc" #undef DYNTRANS_TO_BE_TRANSLATED_TAIL } gxemul-0.6.1/src/console/console.cc000644 001750 001750 00000057442 13402411502 017443 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2014 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Generic console support functions. * * This module is used by individual device drivers, for example serial * controllers, keyboards, or other devices which need to attach to the * emulator's real stdin/stdout. * * The idea is that several input and output streams (console handles) are * allowed. As long as the number of input streams is <= 1, then everything * can be done in the emulator's default terminal window. * * If the number of inputs is more than 1, it is necessary to open up slave * xterm windows for each input. (Otherwise the behaviour is undefined; i.e. * which of two emulated serial controllers would get keyboard input?) * * (If the -x command line option is NOT used, then slaves are not opened up. * Instead, a warning message is printed, and input is not allowed.) * * Note that console handles that _allow_ input but are not yet used for * output are not counted. This allows a machine to have, say, 2 serial ports * which can be used for both input and output, and it will still be possible * to run in the default terminal window as long as only one of those serial * ports is actually used. * * xterms are opened up "on demand", when output is sent to them. * * The MAIN console handle (fixed as handle nr 0) is the one used by the * default terminal window. A machine which registers a serial controller, * which should be used as the main way of communicating with guest operating * systems running on that machine, should set machine->main_console_handle * to the handle of the correct port on that controller. * * * NOTE: The code in this module is mostly non-reentrant. */ #include #include #include #include #include #include #include #include #include #include #include "console.h" #include "emul.h" #include "machine.h" #include "settings.h" extern char *progname; extern int verbose; extern struct settings *global_settings; static struct termios console_oldtermios; static struct termios console_curtermios; /* For 'slave' mode: */ static struct termios console_slave_tios; static int console_slave_outputd; static int console_initialized = 0; static struct settings *console_settings = NULL; static int console_stdout_pending; #define CONSOLE_FIFO_LEN 4096 static int console_mouse_x; /* absolute x, 0-based */ static int console_mouse_y; /* absolute y, 0-based */ static int console_mouse_fb_nr; /* framebuffer number of host movement, 0-based */ static int console_mouse_buttons; /* left=4, middle=2, right=1 */ static int allow_slaves = 0; struct console_handle { int in_use; int in_use_for_input; int using_xterm; int inputonly; int outputonly; int warning_printed; char *machine_name; char *name; int w_descriptor; int r_descriptor; unsigned char fifo[CONSOLE_FIFO_LEN]; int fifo_head; int fifo_tail; }; #define NOT_USING_XTERM 0 #define USING_XTERM_BUT_NOT_YET_OPEN 1 #define USING_XTERM 2 /* A simple array of console_handles */ static struct console_handle *console_handles = NULL; static int n_console_handles = 0; /* * console_deinit_main(): * * Restore host's console settings. */ void console_deinit_main(void) { if (!console_initialized) return; tcsetattr(STDIN_FILENO, TCSANOW, &console_oldtermios); console_initialized = 0; } /* * console_sigcont(): * * If the user presses CTRL-Z (to stop the emulator process) and then * continues, the termios settings might have been invalidated. This * function restores them. * * (This function should be set as the SIGCONT signal handler in src/emul.c.) */ void console_sigcont(int x) { if (!console_initialized) return; /* Make sure that the correct (current) termios setting is active: */ tcsetattr(STDIN_FILENO, TCSANOW, &console_curtermios); /* Reset the signal handler: */ signal(SIGCONT, console_sigcont); } /* * start_xterm(): * * When using X11 (well, when allow_slaves is set), this routine tries to * start up an xterm, with another copy of gxemul inside. The other gxemul * copy is given arguments that will cause it to run console_slave(). * * TODO: This is ugly and hardcoded. Clean it up. */ static void start_xterm(int handle) { int filedes[2]; int filedesB[2]; int res; size_t mlen; char **a; pid_t p; res = pipe(filedes); if (res) { printf("[ start_xterm(): pipe(): %i ]\n", errno); exit(1); } res = pipe(filedesB); if (res) { printf("[ start_xterm(): pipe(): %i ]\n", errno); exit(1); } /* printf("filedes = %i,%i\n", filedes[0], filedes[1]); */ /* printf("filedesB = %i,%i\n", filedesB[0], filedesB[1]); */ /* NOTE/warning: Hardcoded max nr of args! */ CHECK_ALLOCATION(a = (char **) malloc(sizeof(char *) * 20)); a[0] = getenv("XTERM"); if (a[0] == NULL) a[0] = strdup("xterm"); a[1] = strdup("-geometry"); a[2] = strdup("80x25"); a[3] = strdup("-title"); mlen = strlen(console_handles[handle].name) + strlen(console_handles[handle].machine_name) + 30; CHECK_ALLOCATION(a[4] = (char *) malloc(mlen)); snprintf(a[4], mlen, "GXemul: %s %s", console_handles[handle].machine_name, console_handles[handle].name); a[5] = strdup("-e"); a[6] = progname; CHECK_ALLOCATION(a[7] = (char *) malloc(80)); snprintf(a[7], 80, "-WW@S%i,%i", filedes[0], filedesB[1]); a[8] = NULL; p = fork(); if (p == -1) { printf("[ start_xterm(): ERROR while trying to " "fork(): %i ]\n", errno); exit(1); } else if (p == 0) { close(filedes[1]); close(filedesB[0]); p = setsid(); if (p < 0) printf("[ start_xterm(): ERROR while trying " "to do a setsid(): %i ]\n", errno); res = execvp(a[0], a); printf("[ start_xterm(): ERROR while trying to " "execvp(\""); while (a[0] != NULL) { printf("%s", a[0]); if (a[1] != NULL) printf(" "); a++; } printf("\"): %i ]\n", errno); if (errno == ENOENT) printf("[ Most probably you don't have xterm" " in your PATH. Try again. ]\n"); exit(1); } /* TODO: free a and a[*] */ close(filedes[0]); close(filedesB[1]); console_handles[handle].using_xterm = USING_XTERM; /* * write to filedes[1], read from filedesB[0] */ console_handles[handle].w_descriptor = filedes[1]; console_handles[handle].r_descriptor = filedesB[0]; } /* * d_avail(): * * Returns 1 if anything is available on a descriptor. */ static int d_avail(int d) { fd_set rfds; struct timeval tv; FD_ZERO(&rfds); FD_SET(d, &rfds); tv.tv_sec = 0; tv.tv_usec = 0; return select(d+1, &rfds, NULL, NULL, &tv); } /* * console_makeavail(): * * Put a character in the queue, so that it will be avaiable, * by inserting it into the char fifo. */ void console_makeavail(int handle, char ch) { console_handles[handle].fifo[ console_handles[handle].fifo_head] = ch; console_handles[handle].fifo_head = ( console_handles[handle].fifo_head + 1) % CONSOLE_FIFO_LEN; if (console_handles[handle].fifo_head == console_handles[handle].fifo_tail) fatal("[ WARNING: console fifo overrun, handle %i ]\n", handle); } /* * console_stdin_avail(): * * Returns 1 if a char is available from a handle's read descriptor, * 0 otherwise. */ static int console_stdin_avail(int handle) { if (!console_handles[handle].in_use_for_input) return 0; if (!allow_slaves) return d_avail(STDIN_FILENO); if (console_handles[handle].using_xterm == USING_XTERM_BUT_NOT_YET_OPEN) return 0; return d_avail(console_handles[handle].r_descriptor); } /* * console_charavail(): * * Returns 1 if a char is available in the fifo, 0 otherwise. */ int console_charavail(int handle) { while (console_stdin_avail(handle)) { unsigned char ch[100]; /* = getchar(); */ ssize_t len; int i, d; // If adding more would lead to a full FIFO, then let's // wait. int roomLeftInFIFO = console_handles[handle].fifo_tail - console_handles[handle].fifo_head; if (roomLeftInFIFO <= 0) roomLeftInFIFO += CONSOLE_FIFO_LEN; if (roomLeftInFIFO < (int)sizeof(ch) + 1) break; if (!allow_slaves) d = STDIN_FILENO; else d = console_handles[handle].r_descriptor; len = read(d, ch, sizeof(ch)); for (i=0; iin_use = 1; chp->machine_name = strdup(""); CHECK_ALLOCATION(chp->name = strdup(name)); *handlep = found_free; return chp; } /* * console_start_slave(): * * When using X11: * * This routine tries to start up an xterm, with another copy of gxemul * inside. The other gxemul copy is given arguments that will cause it * to run console_slave(). * * When not using X11: Things will seem to work the same way without X11, * but no xterm will actually be started. * * consolename should be something like "serial 0". * * If use_for_input is 1, input is allowed right from the start. (This * can be upgraded later from 0 to 1 using the console_change_inputability() * function.) * * If use_for_input is CONSOLE_OUTPUT_ONLY, then this is an output-only stream. * * On success, an integer >= 0 is returned. This can then be used as a * 'handle' when writing to or reading from an emulated console. * * On failure, -1 is returned. */ int console_start_slave(struct machine *machine, const char *consolename, int use_for_input) { struct console_handle *chp; int handle; if (machine == NULL || consolename == NULL) { printf("console_start_slave(): NULL ptr\n"); exit(1); } chp = console_new_handle(consolename, &handle); chp->in_use_for_input = use_for_input; if (use_for_input == CONSOLE_OUTPUT_ONLY) { chp->outputonly = 1; chp->in_use_for_input = 0; } if (machine->machine_name != NULL) { CHECK_ALLOCATION(chp->machine_name = strdup(machine->machine_name)); } else { CHECK_ALLOCATION(chp->machine_name = strdup("")); } CHECK_ALLOCATION(chp->name = strdup(consolename)); if (allow_slaves) chp->using_xterm = USING_XTERM_BUT_NOT_YET_OPEN; return handle; } /* * console_start_slave_inputonly(): * * Similar to console_start_slave(), but doesn't open an xterm. This is * useful for devices such as keyboard controllers, that need to have an * input queue, but no xterm window associated with it. * * On success, an integer >= 0 is returned. This can then be used as a * 'handle' when writing to or reading from an emulated console. * * On failure, -1 is returned. */ int console_start_slave_inputonly(struct machine *machine, const char *consolename, int use_for_input) { struct console_handle *chp; int handle; if (machine == NULL || consolename == NULL) { printf("console_start_slave(): NULL ptr\n"); exit(1); } chp = console_new_handle(consolename, &handle); chp->inputonly = 1; chp->in_use_for_input = use_for_input; if (machine->name != NULL) { CHECK_ALLOCATION(chp->machine_name = strdup(machine->name)); } else { CHECK_ALLOCATION(chp->machine_name = strdup("")); } CHECK_ALLOCATION(chp->name = strdup(consolename)); return handle; } /* * console_change_inputability(): * * Sets whether or not a console handle can be used for input. Return value * is 1 if the change took place, 0 otherwise. */ int console_change_inputability(int handle, int inputability) { int old; if (handle < 0 || handle >= n_console_handles) { fatal("console_change_inputability(): bad handle %i\n", handle); exit(1); } old = console_handles[handle].in_use_for_input; console_handles[handle].in_use_for_input = inputability; if (inputability != 0) { if (console_warn_if_slaves_are_needed(0)) { console_handles[handle].in_use_for_input = old; if (!console_handles[handle].warning_printed) { fatal("%%\n%% WARNING! Input to console ha" "ndle \"%s\" wasn't enabled,\n%% because " "it", console_handles[handle].name); fatal(" would interfere with other inputs,\n" "%% and you did not use the -x command " "line option!\n%%\n"); } console_handles[handle].warning_printed = 1; return 0; } } return 1; } /* * console_init_main(): * * Puts the host's console into single-character (non-canonical) mode. */ void console_init_main(struct emul *emul) { int i, tra; if (console_initialized) return; tcgetattr(STDIN_FILENO, &console_oldtermios); memcpy(&console_curtermios, &console_oldtermios, sizeof (struct termios)); console_curtermios.c_lflag &= ~ICANON; console_curtermios.c_cc[VTIME] = 0; console_curtermios.c_cc[VMIN] = 1; console_curtermios.c_lflag &= ~ECHO; /* * Most guest OSes seem to work ok without ~ICRNL, but Linux on * DECstation requires it to be usable. Unfortunately, clearing * out ICRNL makes tracing with '-t ... |more' akward, as you * might need to use CTRL-J instead of the enter key. Hence, * this bit is only cleared if we're not tracing: */ tra = 0; for (i=0; in_machines; i++) if (emul->machines[i]->show_trace_tree || emul->machines[i]->instruction_trace || emul->machines[i]->register_dump) tra = 1; if (!tra) console_curtermios.c_iflag &= ~ICRNL; tcsetattr(STDIN_FILENO, TCSANOW, &console_curtermios); console_stdout_pending = 1; console_handles[MAIN_CONSOLE].fifo_head = 0; console_handles[MAIN_CONSOLE].fifo_tail = 0; console_mouse_x = 0; console_mouse_y = 0; console_mouse_buttons = 0; console_initialized = 1; } /* * console_debug_dump(): * * Dump debug info, if verbose >= 2. */ void console_debug_dump(struct machine *machine) { int i, iadd = DEBUG_INDENTATION, listed_main = 0; if (verbose < 2) return; debug("console slaves (xterms): %s\n", allow_slaves? "yes" : "no"); debug("console handles:\n"); debug_indentation(iadd); for (i=0; imain_console_handle) { debug(" [MAIN CONSOLE]"); listed_main = 1; } debug("\n"); } debug_indentation(-iadd); if (!listed_main) fatal("WARNING! no main console handle?\n"); } /* * console_allow_slaves(): * * This function tells the console subsystem whether or not to open up * slave xterms for each emulated serial controller. */ void console_allow_slaves(int allow) { allow_slaves = allow; } /* * console_are_slaves_allowed(): * * Returns the value of allow_slaves. */ int console_are_slaves_allowed(void) { return allow_slaves; } /* * console_warn_if_slaves_are_needed(): * * Prints an error (during startup of the emulator) if slave xterms are needed * (i.e. there is more than one console handle in use which is used for * INPUT), but they are not currently allowed. * * This function should be called during startup (with init = 1), and every * time a console handle changes/upgrades its in_use_for_input from 0 to 1. * * If init is non-zero, this function doesn't return if there was a warning. * * If init is zero, no warning is printed. 1 is returned if there were more * than one input, 0 otherwise. */ int console_warn_if_slaves_are_needed(int init) { int i, n = 0; if (allow_slaves) return 0; for (i=MAIN_CONSOLE+1; i 1) { if (init) { fatal("#\n# ERROR! More than one console input is " "in use,\n# but xterm slaves are not enabled.\n" "#\n"); fatal("# Use -x to enable slave xterms.)\n#\n"); for (i=MAIN_CONSOLE+1; iin_use_for_input = 1; } /* * console_deinit(): * * Unregister settings registered by console_init(). */ void console_deinit(void) { settings_remove(console_settings, "allow_slaves"); settings_remove(global_settings, "console"); } gxemul-0.6.1/src/console/Makefile.skel000644 001750 001750 00000000462 13402411502 020055 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/console # # This directory contains code that is related to console and framebuffer # handling. # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(XINCLUDE) $(DINCLUDE) OBJS=console.o x11.o all: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) *core clean_all: clean rm -f Makefile gxemul-0.6.1/src/console/x11.cc000644 001750 001750 00000055013 13402411502 016402 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * X11-related functions. */ #include #include #include #include "console.h" #include "emul.h" #include "machine.h" #include "misc.h" #include "x11.h" #ifndef WITH_X11 /* Dummy functions: */ void x11_redraw_cursor(struct machine *m, int i) { } void x11_redraw(struct machine *m, int x) { } void x11_putpixel_fb(struct machine *m, int fb, int x, int y, int color) { } void x11_init(struct machine *machine) { } struct fb_window *x11_fb_init(int xsize, int ysize, char *name, int scaledown, struct machine *machine) { return NULL; } void x11_check_event(struct emul *emul) { } #else /* WITH_X11 */ #include #include #include /* * x11_redraw_cursor(): * * Redraw a framebuffer's X11 cursor. * * NOTE: It is up to the caller to call XFlush. */ void x11_redraw_cursor(struct machine *m, int i) { int last_color_used = 0; int n_colors_used = 0; struct fb_window *fbwin = m->x11_md.fb_windows[i]; /* Remove old cursor, if any: */ if (fbwin->x11_display != NULL && fbwin->OLD_cursor_on) { XPutImage(fbwin->x11_display, fbwin->x11_fb_window, fbwin->x11_fb_gc, fbwin->fb_ximage, fbwin->OLD_cursor_x/fbwin->scaledown, fbwin->OLD_cursor_y/fbwin->scaledown, fbwin->OLD_cursor_x/fbwin->scaledown, fbwin->OLD_cursor_y/fbwin->scaledown, fbwin->OLD_cursor_xsize/fbwin->scaledown + 1, fbwin->OLD_cursor_ysize/fbwin->scaledown + 1); } if (fbwin->x11_display != NULL && fbwin->cursor_on) { int x, y, subx, suby; XImage *xtmp; CHECK_ALLOCATION(xtmp = XSubImage(fbwin->fb_ximage, fbwin->cursor_x/fbwin->scaledown, fbwin->cursor_y/fbwin->scaledown, fbwin->cursor_xsize/fbwin->scaledown + 1, fbwin->cursor_ysize/fbwin->scaledown + 1)); for (y=0; ycursor_ysize; y+=fbwin->scaledown) for (x=0; xcursor_xsize; x+=fbwin->scaledown) { int px = x/fbwin->scaledown; int py = y/fbwin->scaledown; int p = 0, n = 0, c = 0; unsigned long oldcol; for (suby=0; subyscaledown; suby++) for (subx=0; subx scaledown; subx++) { c = fbwin-> cursor_pixels[y+suby] [x+subx]; if (c >= 0) { p += c; n++; } } if (n > 0) p /= n; else p = c; if (n_colors_used == 0) { last_color_used = p; n_colors_used = 1; } else if (p != last_color_used) n_colors_used = 2; switch (p) { case CURSOR_COLOR_TRANSPARENT: break; case CURSOR_COLOR_INVERT: oldcol = XGetPixel(xtmp, px, py); if (oldcol != fbwin-> x11_graycolor[N_GRAYCOLORS-1].pixel) oldcol = fbwin-> x11_graycolor[N_GRAYCOLORS -1].pixel; else oldcol = fbwin-> x11_graycolor[0].pixel; XPutPixel(xtmp, px, py, oldcol); break; default: /* Normal grayscale: */ XPutPixel(xtmp, px, py, fbwin-> x11_graycolor[p].pixel); } } XPutImage(fbwin->x11_display, fbwin->x11_fb_window, fbwin->x11_fb_gc, xtmp, 0, 0, fbwin->cursor_x/fbwin->scaledown, fbwin->cursor_y/fbwin->scaledown, fbwin->cursor_xsize/fbwin->scaledown, fbwin->cursor_ysize/fbwin->scaledown); XDestroyImage(xtmp); fbwin->OLD_cursor_on = fbwin->cursor_on; fbwin->OLD_cursor_x = fbwin->cursor_x; fbwin->OLD_cursor_y = fbwin->cursor_y; fbwin->OLD_cursor_xsize = fbwin->cursor_xsize; fbwin->OLD_cursor_ysize = fbwin->cursor_ysize; } /* printf("n_colors_used = %i\n", n_colors_used); */ if (fbwin->host_cursor != 0 && n_colors_used < 2) { /* Remove the old X11 host cursor: */ XUndefineCursor(fbwin->x11_display, fbwin->x11_fb_window); XFreeCursor(fbwin->x11_display, fbwin->host_cursor); fbwin->host_cursor = 0; } if (n_colors_used >= 2 && fbwin->host_cursor == 0) { GC tmpgc; /* Create a new X11 host cursor: */ /* cursor = XCreateFontCursor(fbwin->x11_display, XC_coffee_mug); :-) */ if (fbwin->host_cursor_pixmap != 0) { XFreePixmap(fbwin->x11_display, fbwin->host_cursor_pixmap); fbwin->host_cursor_pixmap = 0; } fbwin->host_cursor_pixmap = XCreatePixmap(fbwin->x11_display, fbwin->x11_fb_window, 1, 1, 1); XSetForeground(fbwin->x11_display, fbwin->x11_fb_gc, fbwin->x11_graycolor[0].pixel); tmpgc = XCreateGC(fbwin->x11_display, fbwin->host_cursor_pixmap, 0,0); XDrawPoint(fbwin->x11_display, fbwin->host_cursor_pixmap, tmpgc, 0, 0); XFreeGC(fbwin->x11_display, tmpgc); fbwin->host_cursor = XCreatePixmapCursor(fbwin->x11_display, fbwin->host_cursor_pixmap, fbwin->host_cursor_pixmap, &fbwin->x11_graycolor[N_GRAYCOLORS-1], &fbwin->x11_graycolor[N_GRAYCOLORS-1], 0, 0); if (fbwin->host_cursor != 0) { XDefineCursor(fbwin->x11_display, fbwin->x11_fb_window, fbwin->host_cursor); } } } /* * x11_redraw(): * * Redraw X11 windows. */ void x11_redraw(struct machine *m, int i) { if (i < 0 || i >= m->x11_md.n_fb_windows || m->x11_md.fb_windows[i]->x11_fb_winxsize <= 0) return; x11_putimage_fb(m, i); x11_redraw_cursor(m, i); XFlush(m->x11_md.fb_windows[i]->x11_display); } /* * x11_putpixel_fb(): * * Output a framebuffer pixel. i is the framebuffer number. */ void x11_putpixel_fb(struct machine *m, int i, int x, int y, int color) { struct fb_window *fbwin; if (i < 0 || i >= m->x11_md.n_fb_windows) return; fbwin = m->x11_md.fb_windows[i]; if (fbwin->x11_fb_winxsize <= 0) return; if (color) XSetForeground(fbwin->x11_display, fbwin->x11_fb_gc, fbwin->fg_color); else XSetForeground(fbwin->x11_display, fbwin->x11_fb_gc, fbwin->bg_color); XDrawPoint(fbwin->x11_display, fbwin->x11_fb_window, fbwin->x11_fb_gc, x, y); XFlush(fbwin->x11_display); } /* * x11_putimage_fb(): * * Output an entire XImage to a framebuffer window. i is the * framebuffer number. */ void x11_putimage_fb(struct machine *m, int i) { struct fb_window *fbwin; if (i < 0 || i >= m->x11_md.n_fb_windows) return; fbwin = m->x11_md.fb_windows[i]; if (fbwin->x11_fb_winxsize <= 0) return; XPutImage(fbwin->x11_display, fbwin->x11_fb_window, fbwin->x11_fb_gc, fbwin->fb_ximage, 0,0, 0,0, fbwin->x11_fb_winxsize, fbwin->x11_fb_winysize); XFlush(fbwin->x11_display); } /* * x11_init(): * * Initialize X11 stuff (but doesn't create any windows). * * It is then up to individual drivers, for example framebuffer devices, * to initialize their own windows. */ void x11_init(struct machine *m) { m->x11_md.n_fb_windows = 0; if (m->x11_md.n_display_names > 0) { int i; for (i=0; ix11_md.n_display_names; i++) fatal("Using X11 display: %s\n", m->x11_md.display_names[i]); } m->x11_md.current_display_name_nr = 0; } /* * x11_fb_resize(): * * Set a new size for an X11 framebuffer window. (NOTE: I didn't think of * this kind of functionality during the initial design, so it is probably * buggy. It also needs some refactoring.) */ void x11_fb_resize(struct fb_window *win, int new_xsize, int new_ysize) { int alloc_depth; if (win == NULL) { fatal("x11_fb_resize(): win == NULL\n"); return; } win->x11_fb_winxsize = new_xsize; win->x11_fb_winysize = new_ysize; alloc_depth = win->x11_screen_depth; if (alloc_depth == 24) alloc_depth = 32; if (alloc_depth == 15) alloc_depth = 16; /* Note: ximage_data seems to be freed by XDestroyImage below. */ /* if (win->ximage_data != NULL) free(win->ximage_data); */ CHECK_ALLOCATION(win->ximage_data = (unsigned char *) malloc( new_xsize * new_ysize * alloc_depth / 8)); /* TODO: clear for non-truecolor modes */ memset(win->ximage_data, 0, new_xsize * new_ysize * alloc_depth / 8); if (win->fb_ximage != NULL) XDestroyImage(win->fb_ximage); win->fb_ximage = XCreateImage(win->x11_display, CopyFromParent, win->x11_screen_depth, ZPixmap, 0, (char *)win->ximage_data, new_xsize, new_ysize, 8, new_xsize * alloc_depth / 8); CHECK_ALLOCATION(win->fb_ximage); XResizeWindow(win->x11_display, win->x11_fb_window, new_xsize, new_ysize); } /* * x11_set_standard_properties(): * * Right now, this only sets the title of a window. */ void x11_set_standard_properties(struct fb_window *fb_window, char *name) { XSetStandardProperties(fb_window->x11_display, fb_window->x11_fb_window, name, "GXemul " VERSION, None, NULL, 0, NULL); } /* * x11_fb_init(): * * Initialize a framebuffer window. */ struct fb_window *x11_fb_init(int xsize, int ysize, char *name, int scaledown, struct machine *m) { Display *x11_display; int x, y, fb_number = 0; size_t alloclen, alloc_depth; XColor tmpcolor; struct fb_window *fbwin; int i; char fg[80], bg[80]; char *display_name; fb_number = m->x11_md.n_fb_windows; CHECK_ALLOCATION(m->x11_md.fb_windows = (struct fb_window **) realloc(m->x11_md.fb_windows, sizeof(struct fb_window *) * (m->x11_md.n_fb_windows + 1))); CHECK_ALLOCATION(fbwin = m->x11_md.fb_windows[fb_number] = (struct fb_window *) malloc(sizeof(struct fb_window))); m->x11_md.n_fb_windows ++; memset(fbwin, 0, sizeof(struct fb_window)); fbwin->x11_fb_winxsize = xsize; fbwin->x11_fb_winysize = ysize; /* Which display name? */ display_name = NULL; if (m->x11_md.n_display_names > 0) { display_name = m->x11_md.display_names[ m->x11_md.current_display_name_nr]; m->x11_md.current_display_name_nr ++; m->x11_md.current_display_name_nr %= m->x11_md.n_display_names; } if (display_name != NULL) debug("[ x11_fb_init(): framebuffer window %i, %ix%i, DISPLAY" "=%s ]\n", fb_number, xsize, ysize, display_name); x11_display = XOpenDisplay(display_name); if (x11_display == NULL) { fatal("x11_fb_init(\"%s\"): couldn't open display\n", name); if (display_name != NULL) fatal("display_name = '%s'\n", display_name); exit(1); } fbwin->x11_screen = DefaultScreen(x11_display); fbwin->x11_screen_depth = DefaultDepth(x11_display, fbwin->x11_screen); if (fbwin->x11_screen_depth != 8 && fbwin->x11_screen_depth != 15 && fbwin->x11_screen_depth != 16 && fbwin->x11_screen_depth != 24) { fatal("\n***\n*** WARNING! Your X server is running %i-bit " "color mode. This is not really\n", fbwin->x11_screen_depth); fatal("*** supported yet. 8, 15, 16, and 24 bits should " "work.\n*** 24-bit server gives color. Any other bit " "depth gives undefined result!\n***\n\n"); } if (fbwin->x11_screen_depth <= 8) debug("WARNING! X11 screen depth is not enough for color; " "using only 16 grayscales instead\n"); strlcpy(bg, "Black", sizeof(bg)); strlcpy(fg, "White", sizeof(fg)); XParseColor(x11_display, DefaultColormap(x11_display, fbwin->x11_screen), fg, &tmpcolor); XAllocColor(x11_display, DefaultColormap(x11_display, fbwin->x11_screen), &tmpcolor); fbwin->fg_color = tmpcolor.pixel; XParseColor(x11_display, DefaultColormap(x11_display, fbwin->x11_screen), bg, &tmpcolor); XAllocColor(x11_display, DefaultColormap(x11_display, fbwin->x11_screen), &tmpcolor); fbwin->bg_color = tmpcolor.pixel; for (i=0; ix11_screen), cname, &fbwin->x11_graycolor[i]); XAllocColor(x11_display, DefaultColormap(x11_display, fbwin->x11_screen), &fbwin->x11_graycolor[i]); } XFlush(x11_display); alloc_depth = fbwin->x11_screen_depth; if (alloc_depth == 24) alloc_depth = 32; if (alloc_depth == 15) alloc_depth = 16; fbwin->x11_fb_window = XCreateWindow( x11_display, DefaultRootWindow(x11_display), 0, 0, fbwin->x11_fb_winxsize, fbwin->x11_fb_winysize, 0, CopyFromParent, InputOutput, CopyFromParent, 0,0); fbwin->x11_display = x11_display; x11_set_standard_properties(fbwin, name); XSelectInput(x11_display, fbwin->x11_fb_window, StructureNotifyMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask); fbwin->x11_fb_gc = XCreateGC(x11_display, fbwin->x11_fb_window, 0,0); /* Make sure the window is mapped: */ XMapRaised(x11_display, fbwin->x11_fb_window); XSetBackground(x11_display, fbwin->x11_fb_gc, fbwin->bg_color); XSetForeground(x11_display, fbwin->x11_fb_gc, fbwin->bg_color); XFillRectangle(x11_display, fbwin->x11_fb_window, fbwin->x11_fb_gc, 0,0, fbwin->x11_fb_winxsize, fbwin->x11_fb_winysize); fbwin->scaledown = scaledown; fbwin->fb_number = fb_number; alloclen = xsize * ysize * alloc_depth / 8; CHECK_ALLOCATION(fbwin->ximage_data = (unsigned char *) malloc(alloclen)); fbwin->fb_ximage = XCreateImage(fbwin->x11_display, CopyFromParent, fbwin->x11_screen_depth, ZPixmap, 0, (char *)fbwin->ximage_data, xsize, ysize, 8, xsize * alloc_depth / 8); CHECK_ALLOCATION(fbwin->fb_ximage); /* Fill the ximage with black pixels: */ if (fbwin->x11_screen_depth > 8) memset(fbwin->ximage_data, 0, alloclen); else { debug("x11_fb_init(): clearing the XImage\n"); for (y=0; yfb_ximage, x, y, fbwin->x11_graycolor[0].pixel); } x11_putimage_fb(m, fb_number); /* Fill the 64x64 "hardware" cursor with white pixels: */ xsize = ysize = 64; /* Fill the cursor ximage with white pixels: */ for (y=0; ycursor_pixels[y][x] = N_GRAYCOLORS-1; return fbwin; } /* * x11_check_events_machine(): * * Check for X11 events on a specific machine. * * TODO: Yuck! This has to be rewritten. Each display should be checked, * and _then_ only those windows that are actually exposed should * be redrawn! */ static void x11_check_events_machine(struct emul *emul, struct machine *m) { int fb_nr; for (fb_nr = 0; fb_nr < m->x11_md.n_fb_windows; fb_nr ++) { struct fb_window *fbwin = m->x11_md.fb_windows[fb_nr]; XEvent event; int need_redraw = 0, found, i, j; while (XPending(fbwin->x11_display)) { XNextEvent(fbwin->x11_display, &event); if (event.type==ConfigureNotify) { need_redraw = 1; } if (event.type==Expose && event.xexpose.count==0) { /* * TODO: the xexpose struct has x,y,width, * height. Those could be used to only redraw * the part of the framebuffer that was * exposed. Note that the (mouse) cursor must * be redrawn too. */ /* x11_winxsize = event.xexpose.width; x11_winysize = event.xexpose.height; */ need_redraw = 1; } if (event.type == MotionNotify) { /* debug("[ X11 MotionNotify: %i,%i ]\n", event.xmotion.x, event.xmotion.y); */ /* Which window in which machine in which emulation? */ found = -1; for (j=0; jn_machines; j++) { struct machine *m2 = emul->machines[j]; for (i=0; ix11_md. n_fb_windows; i++) if (m->x11_md. fb_windows[fb_nr]-> x11_display == m2-> x11_md. fb_windows[i]-> x11_display && event.xmotion. window == m2-> x11_md. fb_windows[i]-> x11_fb_window) found = i; } if (found < 0) { printf("Internal error in x11.c.\n"); exit(1); } console_mouse_coordinates(event.xmotion.x * m->x11_md.fb_windows[found]->scaledown, event.xmotion.y * m->x11_md.fb_windows[ found]->scaledown, found); } if (event.type == ButtonPress) { debug("[ X11 ButtonPress: %i ]\n", event.xbutton.button); /* button = 1,2,3 = left,middle,right */ console_mouse_button(event.xbutton.button, 1); } if (event.type == ButtonRelease) { debug("[ X11 ButtonRelease: %i ]\n", event.xbutton.button); /* button = 1,2,3 = left,middle,right */ console_mouse_button(event.xbutton.button, 0); } if (event.type==KeyPress) { char text[15]; KeySym key; XKeyPressedEvent *ke = &event.xkey; memset(text, 0, sizeof(text)); if (XLookupString(&event.xkey, text, sizeof(text), &key, 0) == 1) { console_makeavail( m->main_console_handle, text[0]); } else { int x = ke->keycode; /* * Special key codes: * * NOTE/TODO: I'm hardcoding these to * work with my key map. Maybe they * should be read from some file... * * Important TODO 2: It would be MUCH * better if these were converted into * 'native scancodes', for example for * the DECstation's keyboard or the * PC-style 8042 controller. */ switch (x) { case 9: /* Escape */ console_makeavail(m-> main_console_handle, 27); break; #if 0 /* TODO */ /* The numeric keypad: */ 90=Ins('0') 91=Del(',') /* Above the cursor keys: */ 106=Ins 107=Del #endif /* F1..F4: */ case 67: /* F1 */ case 68: /* F2 */ case 69: /* F3 */ case 70: /* F4 */ console_makeavail(m-> main_console_handle, 27); console_makeavail(m-> main_console_handle, '['); console_makeavail(m-> main_console_handle, 'O'); console_makeavail(m-> main_console_handle, 'P' + x - 67); break; case 71: /* F5 */ console_makeavail(m-> main_console_handle, 27); console_makeavail(m-> main_console_handle, '['); console_makeavail(m-> main_console_handle, '1'); console_makeavail(m-> main_console_handle, '5'); break; case 72: /* F6 */ case 73: /* F7 */ case 74: /* F8 */ console_makeavail(m-> main_console_handle, 27); console_makeavail(m-> main_console_handle, '['); console_makeavail(m-> main_console_handle, '1'); console_makeavail(m-> main_console_handle, '7' + x - 72); break; case 75: /* F9 */ case 76: /* F10 */ console_makeavail(m-> main_console_handle, 27); console_makeavail(m-> main_console_handle, '['); console_makeavail(m-> main_console_handle, '2'); console_makeavail(m-> main_console_handle, '1' + x - 68); break; case 95: /* F11 */ case 96: /* F12 */ console_makeavail(m-> main_console_handle, 27); console_makeavail(m-> main_console_handle, '['); console_makeavail(m-> main_console_handle, '2'); console_makeavail(m-> main_console_handle, '3' + x - 95); break; /* Cursor keys: */ case 98: /* Up */ case 104: /* Down */ case 100: /* Left */ case 102: /* Right */ console_makeavail(m-> main_console_handle, 27); console_makeavail(m-> main_console_handle, '['); console_makeavail(m-> main_console_handle, x == 98? 'A' : ( x == 104? 'B' : ( x == 102? 'C' : ( 'D')))); break; /* Numeric keys: */ case 80: /* Up */ case 88: /* Down */ case 83: /* Left */ case 85: /* Right */ console_makeavail(m-> main_console_handle, 27); console_makeavail(m-> main_console_handle, '['); console_makeavail(m-> main_console_handle, x == 80? 'A' : ( x == 88? 'B' : ( x == 85? 'C' : ( 'D')))); break; case 97: /* Cursor Home */ case 79: /* Numeric Home */ console_makeavail(m-> main_console_handle, 27); console_makeavail(m-> main_console_handle, '['); console_makeavail(m-> main_console_handle, 'H'); break; case 103: /* Cursor End */ case 87: /* Numeric End */ console_makeavail(m-> main_console_handle, 27); console_makeavail(m-> main_console_handle, '['); console_makeavail(m-> main_console_handle, 'F'); break; case 99: /* Cursor PgUp */ case 81: /* Numeric PgUp */ console_makeavail(m-> main_console_handle, 27); console_makeavail(m-> main_console_handle, '['); console_makeavail(m-> main_console_handle, '5'); console_makeavail(m-> main_console_handle, '~'); break; case 105: /* Cursor PgUp */ case 89: /* Numeric PgDn */ console_makeavail(m-> main_console_handle, 27); console_makeavail(m-> main_console_handle, '['); console_makeavail(m-> main_console_handle, '6'); console_makeavail(m-> main_console_handle, '~'); break; default: debug("[ unimplemented X11 " "keycode %i ]\n", x); } } } } if (need_redraw) x11_redraw(m, fb_nr); } } /* * x11_check_event(): * * Check for X11 events. */ void x11_check_event(struct emul *emul) { int i; for (i=0; in_machines; i++) x11_check_events_machine(emul, emul->machines[i]); } #endif /* WITH_X11 */ gxemul-0.6.1/src/disk/bootblock.cc000644 001750 001750 00000024041 13402411502 017234 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Bootblock handling: * * o) For some machines (e.g. DECstation or the Dreamcast), it is * possible to load a bootblock from a fixed location on disk, and * simply execute it in memory. * * o) For booting from generic CDROM ISO9660 images, a filename of * a file to load must be supplied (the kernel filename). It is * loaded, possibly gunzipped, and then executed as if it was a * separate file. * * TODO: This module needs some cleanup. */ #include #include #include #include "cpu.h" #include "diskimage.h" #include "emul.h" #include "machine.h" #include "memory.h" static const char *diskimage_types[] = DISKIMAGE_TYPES; /* * load_bootblock(): * * For some emulation modes, it is possible to boot from a harddisk image by * loading a bootblock from a specific disk offset into memory, and executing * that, instead of requiring a separate kernel file. It is then up to the * bootblock to load a kernel. * * Returns 1 on success, 0 on failure. */ int load_bootblock(struct machine *m, struct cpu *cpu, int *n_loadp, char ***load_namesp) { int boot_disk_id, boot_disk_type = 0, n_blocks, res, readofs, iso_type, retval = 0; unsigned char minibuf[0x20]; unsigned char *bootblock_buf; uint64_t bootblock_offset, base_offset; uint64_t bootblock_loadaddr, bootblock_pc; boot_disk_id = diskimage_bootdev(m, &boot_disk_type); if (boot_disk_id < 0) return 0; base_offset = diskimage_get_baseoffset(m, boot_disk_id, boot_disk_type); switch (m->machine_type) { case MACHINE_DREAMCAST: if (!diskimage_is_a_cdrom(cpu->machine, boot_disk_id, boot_disk_type)) { fatal("The Dreamcast emulation mode can only boot" " from CD images, not from other disk types.\n"); exit(1); } CHECK_ALLOCATION(bootblock_buf = (unsigned char *) malloc(32768)); debug("loading Dreamcast IP.BIN from %s id %i to 0x8c008000\n", diskimage_types[boot_disk_type], boot_disk_id); res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, base_offset, bootblock_buf, 0x8000); if (!res) { fatal("Couldn't read the first 32 KB from the disk image. Aborting.\n"); return 0; } if (strncmp((char *)bootblock_buf, "SEGA ", 5) != 0) { fatal("This is not a Dreamcast IP.BIN header.\n"); free(bootblock_buf); return 0; } /* * Store IP.BIN at 0x8c008000, and set entry point. * * Note: The boot block contains several executable parts: * Offset 0x0300-36ff: SEGA logo code * Offset 0x3800-5FFF: Bootstrap code 1 * Offset 0x6000-7FFF: Bootstrap code 2 * * (See http://mc.pp.se/dc/ip.bin.html for details.) * * So one way to boot could be to set initial PC to 0x8c008300, * but that would only run the SEGA logo code and then return * to... well, to nothing. * * Instead, initial PC is set to 0x8c000140, which triggers * software PROM emulation, which in turn: * a) calls 0x8c008300 to show the logo, and * b) calls 0x8c00b800 to set up registers etc and * this code will hopefully jump to 0x8c010000. * * This mimics the behavior of the real Dreamcast. */ store_buf(cpu, 0x8c008000, (char *)bootblock_buf, 32768); cpu->pc = 0x8c000140; // see src/promemul/dreamcast.cc for details /* Remember the name of the file to boot (1ST_READ.BIN): */ if (cpu->machine->boot_kernel_filename == NULL || cpu->machine->boot_kernel_filename[0] == '\0') { int i = 0x60; while (i < 0x70) { if (bootblock_buf[i] == ' ') bootblock_buf[i] = 0; i ++; } CHECK_ALLOCATION(cpu->machine->boot_kernel_filename = strdup((char *)bootblock_buf + 0x60)); } debug("Dreamcast boot filename: %s (to be loaded to 0x8c010000)\n", cpu->machine->boot_kernel_filename); free(bootblock_buf); break; case MACHINE_PMAX: /* * The first few bytes of a disk contains information about * where the bootblock(s) are located. (These are all 32-bit * little-endian words.) * * Offset 0x10 = load address * 0x14 = initial PC value * 0x18 = nr of 512-byte blocks to read * 0x1c = offset on disk to where the bootblocks * are (in 512-byte units) * 0x20 = nr of blocks to read... * 0x24 = offset... * * nr of blocks to read and offset are repeated until nr of * blocks to read is zero. */ res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0, minibuf, sizeof(minibuf)); bootblock_loadaddr = minibuf[0x10] + (minibuf[0x11] << 8) + (minibuf[0x12] << 16) + ((uint64_t)minibuf[0x13] << 24); /* Convert loadaddr to uncached: */ if ((bootblock_loadaddr & 0xf0000000ULL) != 0x80000000 && (bootblock_loadaddr & 0xf0000000ULL) != 0xa0000000) { fatal("\nWARNING! Weird load address 0x%08" PRIx32 " for SCSI id %i.\n\n", (uint32_t)bootblock_loadaddr, boot_disk_id); if (bootblock_loadaddr == 0) { fatal("I'm assuming that this is _not_ a " "DEC bootblock.\nAre you sure you are" " booting from the correct disk?\n"); exit(1); } } bootblock_loadaddr &= 0x0fffffffULL; bootblock_loadaddr |= 0xffffffffa0000000ULL; bootblock_pc = minibuf[0x14] + (minibuf[0x15] << 8) + (minibuf[0x16] << 16) + ((uint64_t)minibuf[0x17] << 24); bootblock_pc &= 0x0fffffffULL; bootblock_pc |= 0xffffffffa0000000ULL; cpu->pc = bootblock_pc; debug("DEC boot: loadaddr=0x%08" PRIx32", pc=0x%08" PRIx32, (uint32_t) bootblock_loadaddr, (uint32_t) bootblock_pc); readofs = 0x18; for (;;) { res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, readofs, minibuf, sizeof(minibuf)); if (!res) { fatal("Couldn't read the disk image. " "Aborting.\n"); return 0; } n_blocks = minibuf[0] + (minibuf[1] << 8) + (minibuf[2] << 16) + ((uint64_t)minibuf[3] << 24); bootblock_offset = (minibuf[4] + (minibuf[5] << 8) + (minibuf[6]<<16) + ((uint64_t)minibuf[7]<<24)) * 512; if (n_blocks < 1) break; debug(readofs == 0x18? ": %i" : " + %i", n_blocks); if (n_blocks * 512 > 65536) fatal("\nWARNING! Unusually large bootblock " "(%i bytes)\n\n", n_blocks * 512); CHECK_ALLOCATION(bootblock_buf = (unsigned char *) malloc(n_blocks*512)); res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, bootblock_offset, bootblock_buf, n_blocks * 512); if (!res) { fatal("WARNING: could not load bootblocks from" " disk offset 0x%llx\n", (long long)bootblock_offset); } store_buf(cpu, bootblock_loadaddr, (char *)bootblock_buf, n_blocks * 512); bootblock_loadaddr += 512*n_blocks; free(bootblock_buf); readofs += 8; } debug(readofs == 0x18? ": no blocks?\n" : " blocks\n"); return 1; } /* * Try reading a kernel manually from the disk. The code here * does not rely on machine-dependent boot blocks etc. */ /* ISO9660: (0x800 bytes at 0x8000 + base_offset) */ CHECK_ALLOCATION(bootblock_buf = (unsigned char *) malloc(0x800)); res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, base_offset + 0x8000, bootblock_buf, 0x800); if (!res) { fatal("Couldn't read the ISO header from the disk image. Aborting.\n"); return 0; } iso_type = 0; if (strncmp((char *)bootblock_buf+1, "CD001", 5) == 0) iso_type = 1; if (strncmp((char *)bootblock_buf+1, "CDW01", 5) == 0) iso_type = 2; if (strncmp((char *)bootblock_buf+1, "CDROM", 5) == 0) iso_type = 3; if (iso_type != 0) { /* * If the user specified a kernel name, then load it from * disk. */ if (cpu->machine->boot_kernel_filename == NULL || cpu->machine->boot_kernel_filename[0] == '\0') fatal("\nISO9660 filesystem, but no kernel " "specified? (Use the -j option.)\n"); else retval = iso_load_bootblock(m, cpu, boot_disk_id, boot_disk_type, iso_type, bootblock_buf, n_loadp, load_namesp); } if (retval != 0) goto ret_ok; /* Apple parition table: */ res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0x0, bootblock_buf, 0x800); if (!res) { fatal("Couldn't read the disk image. Aborting.\n"); return 0; } if (bootblock_buf[0x000] == 'E' && bootblock_buf[0x001] == 'R' && bootblock_buf[0x200] == 'P' && bootblock_buf[0x201] == 'M') { if (cpu->machine->boot_kernel_filename == NULL || cpu->machine->boot_kernel_filename[0] == '\0') fatal("\nApple partition table, but no kernel " "specified? (Use the -j option.)\n"); else retval = apple_load_bootblock(m, cpu, boot_disk_id, boot_disk_type, n_loadp, load_namesp); } ret_ok: free(bootblock_buf); return retval; } gxemul-0.6.1/src/disk/diskimage.cc000644 001750 001750 00000066062 13402411502 017224 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Disk image support. * * TODO: diskimage_remove()? This would be useful for floppies in PC-style * machines, where disks may need to be swapped during boot etc. */ #include #include #include #include #include #include #include "cpu.h" #include "diskimage.h" #include "machine.h" #include "misc.h" /* #define debug fatal */ extern int single_step; static const char *diskimage_types[] = DISKIMAGE_TYPES; /**************************************************************************/ /* * my_fseek(): * * A helper function, like fseek() but takes off_t. If the system has * fseeko, then that is used. Otherwise I try to fake off_t offsets here. * * The correct position is reached by seeking 2 billion bytes at a time * (or less). Note: This method is only used for SEEK_SET, for SEEK_CUR * and SEEK_END, normal fseek() is used! * * TODO: It seemed to work on Linux/i386, but not on Solaris/sparc (?). * Anyway, most modern systems have fseeko(), so it shouldn't be a problem. */ static int my_fseek(FILE *f, off_t offset, int whence) { #ifdef HACK_FSEEKO if (whence == SEEK_SET) { int res = 0; off_t curoff = 0; off_t cur_step; fseek(f, 0, SEEK_SET); while (curoff < offset) { /* How far to seek? */ cur_step = offset - curoff; if (cur_step > 2000000000) cur_step = 2000000000; res = fseek(f, cur_step, SEEK_CUR); if (res) return res; curoff += cur_step; } return 0; } else return fseek(f, offset, whence); #else return fseeko(f, offset, whence); #endif } /**************************************************************************/ /* * diskimage_exist(): * * Returns 1 if the specified disk id (for a specific type) exists, 0 * otherwise. */ int diskimage_exist(struct machine *machine, int id, int type) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { if (d->type == type && d->id == id) return 1; d = d->next; } return 0; } /* * diskimage_add_overlay(): * * Opens an overlay data file and its corresponding bitmap file, and adds * the overlay to a disk image. */ void diskimage_add_overlay(struct diskimage *d, char *overlay_basename) { struct diskimage_overlay overlay; size_t bitmap_name_len = strlen(overlay_basename) + 20; char *bitmap_name; CHECK_ALLOCATION(bitmap_name = (char *) malloc(bitmap_name_len)); snprintf(bitmap_name, bitmap_name_len, "%s.map", overlay_basename); CHECK_ALLOCATION(overlay.overlay_basename = strdup(overlay_basename)); overlay.f_data = fopen(overlay_basename, d->writable? "r+" : "r"); if (overlay.f_data == NULL) { perror(overlay_basename); exit(1); } overlay.f_bitmap = fopen(bitmap_name, d->writable? "r+" : "r"); if (overlay.f_bitmap == NULL) { perror(bitmap_name); fprintf(stderr, "Please create the map file first.\n"); exit(1); } d->nr_of_overlays ++; CHECK_ALLOCATION(d->overlays = (struct diskimage_overlay *) realloc(d->overlays, sizeof(struct diskimage_overlay) * d->nr_of_overlays)); d->overlays[d->nr_of_overlays - 1] = overlay; free(bitmap_name); } /* * diskimage_recalc_size(): * * Recalculate a disk's size by stat()-ing it. * d is assumed to be non-NULL. */ void diskimage_recalc_size(struct diskimage *d) { struct stat st; int res; off_t size = 0; res = stat(d->fname, &st); if (res) { fprintf(stderr, "[ diskimage_recalc_size(): could not stat " "'%s' ]\n", d->fname); return; } size = st.st_size; /* * TODO: CD-ROM devices, such as /dev/cd0c, how can one * check how much data is on that cd-rom without reading it? * For now, assume some large number, hopefully it will be * enough to hold any cd-rom image. */ if (d->is_a_cdrom && size == 0) size = 762048000; d->total_size = size; d->ncyls = d->total_size / 1048576; /* TODO: There is a mismatch between d->ncyls and d->cylinders, SCSI-based stuff usually doesn't care. TODO: Fix this. */ } /* * diskimage_getsize(): * * Returns -1 if the specified disk id/type does not exists, otherwise * the size of the disk image is returned. */ int64_t diskimage_getsize(struct machine *machine, int id, int type) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { if (d->type == type && d->id == id) return d->total_size; d = d->next; } return -1; } /* * diskimage_get_baseoffset(): * * Returns -1 if the specified disk id/type does not exists, otherwise * the base offset of the disk image is returned. */ int64_t diskimage_get_baseoffset(struct machine *machine, int id, int type) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { if (d->type == type && d->id == id) return d->override_base_offset; d = d->next; } return -1; } /* * diskimage_set_baseoffset(): * * Sets the base offset for a disk image. Useful e.g. when booting directly * from NetBSD/dreamcast or Linux/dreamcast ISO images. */ void diskimage_set_baseoffset(struct machine *machine, int id, int type, int64_t offset) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { if (d->type == type && d->id == id) { d->override_base_offset = offset; return; } d = d->next; } fatal("diskimage_set_baseoffset(): disk id %i (type %i) not found?\n", id, diskimage_types[type]); exit(1); } /* * diskimage_getchs(): * * Returns the current CHS values of a disk image. */ void diskimage_getchs(struct machine *machine, int id, int type, int *c, int *h, int *s) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { if (d->type == type && d->id == id) { *c = d->cylinders; *h = d->heads; *s = d->sectors_per_track; return; } d = d->next; } fatal("diskimage_getchs(): disk id %i (type %i) not found?\n", id, diskimage_types[type]); exit(1); } /* * diskimage_access__cdrom(): * * This is a special-case function, called from diskimage__internal_access(). * On my FreeBSD 4.9 system, the cdrom device /dev/cd0c seems to not be able * to handle something like "fseek(512); fread(512);" but it handles * "fseek(2048); fread(512);" just fine. So, if diskimage__internal_access() * fails in reading a block of data, this function is called as an attempt to * align reads at 2048-byte sectors instead. * * (Ugly hack. TODO: how to solve this cleanly?) * * NOTE: Returns the number of bytes read, 0 if nothing was successfully * read. (These are not the same as diskimage_access()). */ #define CDROM_SECTOR_SIZE 2048 static size_t diskimage_access__cdrom(struct diskimage *d, off_t offset, unsigned char *buf, size_t len) { off_t aligned_offset; size_t bytes_read, total_copied = 0; unsigned char cdrom_buf[CDROM_SECTOR_SIZE]; off_t buf_ofs, i = 0; /* printf("diskimage_access__cdrom(): offset=0x%llx size=%lli\n", (long long)offset, (long long)len); */ aligned_offset = (offset / CDROM_SECTOR_SIZE) * CDROM_SECTOR_SIZE; my_fseek(d->f, aligned_offset, SEEK_SET); while (len != 0) { bytes_read = fread(cdrom_buf, 1, CDROM_SECTOR_SIZE, d->f); if (bytes_read != CDROM_SECTOR_SIZE) return 0; /* Copy (part of) cdrom_buf into buf: */ buf_ofs = offset - aligned_offset; while (buf_ofs < CDROM_SECTOR_SIZE && len != 0) { buf[i ++] = cdrom_buf[buf_ofs ++]; total_copied ++; len --; } aligned_offset += CDROM_SECTOR_SIZE; offset = aligned_offset; } return total_copied; } /* Helper function. */ static void overlay_set_block_in_use(struct diskimage *d, int overlay_nr, off_t ofs) { off_t bit_nr = ofs / OVERLAY_BLOCK_SIZE; off_t bitmap_file_offset = bit_nr / 8; int res; unsigned char data; res = my_fseek(d->overlays[overlay_nr].f_bitmap, bitmap_file_offset, SEEK_SET); if (res) { perror("my_fseek"); fprintf(stderr, "Could not seek in bitmap file?" " offset = %lli, read\n", (long long)bitmap_file_offset); exit(1); } /* Read the original bitmap data, and OR in the new bit: */ res = fread(&data, 1, 1, d->overlays[overlay_nr].f_bitmap); if (res != 1) data = 0x00; data |= (1 << (bit_nr & 7)); /* Write it back: */ res = my_fseek(d->overlays[overlay_nr].f_bitmap, bitmap_file_offset, SEEK_SET); if (res) { perror("my_fseek"); fprintf(stderr, "Could not seek in bitmap file?" " offset = %lli, write\n", (long long)bitmap_file_offset); exit(1); } res = fwrite(&data, 1, 1, d->overlays[overlay_nr].f_bitmap); if (res != 1) { fprintf(stderr, "Could not write to bitmap file. Aborting.\n"); exit(1); } } /* Helper function. */ static int overlay_has_block(struct diskimage *d, int overlay_nr, off_t ofs) { off_t bit_nr = ofs / OVERLAY_BLOCK_SIZE; off_t bitmap_file_offset = bit_nr / 8; int res; unsigned char data; res = my_fseek(d->overlays[overlay_nr].f_bitmap, bitmap_file_offset, SEEK_SET); if (res != 0) return 0; /* The seek succeeded, now read the bit: */ res = fread(&data, 1, 1, d->overlays[overlay_nr].f_bitmap); if (res != 1) return 0; if (data & (1 << (bit_nr & 7))) return 1; return 0; } /* * fwrite_helper(): * * Internal helper function. Writes to a disk image file, or if the * disk image has overlays, to the last overlay. */ static size_t fwrite_helper(off_t offset, unsigned char *buf, size_t len, struct diskimage *d) { off_t curofs; /* Fast return-path for the case when no overlays are used: */ if (d->nr_of_overlays == 0) { int res = my_fseek(d->f, offset, SEEK_SET); if (res != 0) { fatal("[ diskimage__internal_access(): fseek() failed" " on disk id %i \n", d->id); return 0; } return fwrite(buf, 1, len, d->f); } if ((len & (OVERLAY_BLOCK_SIZE-1)) != 0) { fatal("TODO: overlay access (write), len not multiple of " "overlay block size. not yet implemented.\n"); fatal("len = %lli\n", (long long) len); abort(); } if ((offset & (OVERLAY_BLOCK_SIZE-1)) != 0) { fatal("TODO: unaligned overlay access\n"); fatal("offset = %lli\n", (long long) offset); abort(); } /* Split the write into OVERLAY_BLOCK_SIZE writes: */ for (curofs = offset; curofs < (off_t) (offset+len); curofs += OVERLAY_BLOCK_SIZE) { /* Always write to the last overlay: */ int overlay_nr = d->nr_of_overlays-1; off_t lenwritten; int res = my_fseek(d->overlays[overlay_nr].f_data, curofs, SEEK_SET); if (res != 0) { fatal("[ diskimage__internal_access(): fseek()" " failed on disk id %i \n", d->id); return 0; } lenwritten = fwrite(buf, 1, OVERLAY_BLOCK_SIZE, d->overlays[overlay_nr].f_data); buf += OVERLAY_BLOCK_SIZE; /* Mark this block in the last overlay as in use: */ overlay_set_block_in_use(d, overlay_nr, curofs); } return len; } /* * fread_helper(): * * Internal helper function. Reads from a disk image file, or if the * disk image has overlays, from the last overlay that has the specific * data (or the disk image file itself). */ static size_t fread_helper(off_t offset, unsigned char *buf, size_t len, struct diskimage *d) { off_t curofs; size_t totallenread = 0; /* Fast return-path for the case when no overlays are used: */ if (d->nr_of_overlays == 0) { int res = my_fseek(d->f, offset, SEEK_SET); if (res != 0) { fatal("[ diskimage__internal_access(): fseek() failed" " on disk id %i \n", d->id); return 0; } return fread(buf, 1, len, d->f); } /* Split the read into OVERLAY_BLOCK_SIZE reads: */ for (curofs=offset; len != 0; curofs = (curofs | (OVERLAY_BLOCK_SIZE-1)) + 1) { /* Find the overlay, if any, that has this block: */ off_t lenread, lentoread; int overlay_nr; for (overlay_nr = d->nr_of_overlays-1; overlay_nr >= 0; overlay_nr --) { if (overlay_has_block(d, overlay_nr, curofs)) break; } lentoread = len > OVERLAY_BLOCK_SIZE? OVERLAY_BLOCK_SIZE : len; if (overlay_nr >= 0) { /* Read from overlay: */ int res = my_fseek(d->overlays[overlay_nr].f_data, curofs, SEEK_SET); if (res != 0) { fatal("[ diskimage__internal_access(): fseek()" " failed on disk id %i \n", d->id); return 0; } lenread = fread(buf, 1, lentoread, d->overlays[overlay_nr].f_data); } else { /* Read from the base disk image: */ int res = my_fseek(d->f, curofs, SEEK_SET); if (res != 0) { fatal("[ diskimage__internal_access(): fseek()" " failed on disk id %i \n", d->id); return 0; } lenread = fread(buf, 1, lentoread, d->f); } if (lenread != lentoread) { fatal("[ INCOMPLETE READ from disk id %i, offset" " %lli ]\n", d->id, (long long)curofs); } len -= lentoread; totallenread += lenread; buf += OVERLAY_BLOCK_SIZE; } return totallenread; } /* * diskimage__internal_access(): * * Read from or write to a struct diskimage. * * Returns 1 if the access completed successfully, 0 otherwise. */ int diskimage__internal_access(struct diskimage *d, int writeflag, off_t offset, unsigned char *buf, size_t len) { ssize_t lendone; if (buf == NULL) { fprintf(stderr, "diskimage__internal_access(): buf = NULL\n"); exit(1); } if (len == 0) return 1; if (d->f == NULL) return 0; if (writeflag) { if (!d->writable) return 0; lendone = fwrite_helper(offset, buf, len, d); } else { /* * Special case for CD-ROMs. Actually, this is not needed * for .iso images, only for physical CDROMS on some OSes, * such as FreeBSD. */ if (d->is_a_cdrom) lendone = diskimage_access__cdrom(d, offset, buf, len); else lendone = fread_helper(offset, buf, len, d); if (lendone < (ssize_t)len) memset(buf + lendone, 0, len - lendone); } /* Incomplete data transfer? Then return failure: */ if (lendone != (ssize_t)len) { #ifdef UNSTABLE_DEVEL fatal #else debug #endif ("[ diskimage__internal_access(): disk_id %i, offset %lli" ", transfer not completed. len=%i, len_done=%i ]\n", d->id, (long long)offset, (int)len, (int)lendone); return 0; } return 1; } /* * diskimage_access(): * * Read from or write to a disk image on a machine. * * Returns 1 if the access completed successfully, 0 otherwise. */ int diskimage_access(struct machine *machine, int id, int type, int writeflag, off_t offset, unsigned char *buf, size_t len) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { if (d->type == type && d->id == id) break; d = d->next; } if (d == NULL) { fatal("[ diskimage_access(): ERROR: trying to access a " "non-existant %s disk image (id %i)\n", diskimage_types[type], id); return 0; } offset -= d->override_base_offset; if (offset < 0 && offset + d->override_base_offset >= 0) { debug("[ reading before start of disk image ]\n"); /* Returning zeros. */ memset(buf, 0, len); return 1; } return diskimage__internal_access(d, writeflag, offset, buf, len); } /* * diskimage_add(): * * Add a disk image. fname is the filename of the disk image. * The filename may be prefixed with one or more modifiers, followed * by a colon. * * b specifies that this is a bootable device * c CD-ROM (instead of a normal DISK) * d DISK (this is the default) * f FLOPPY (instead of SCSI) * gH;S; set geometry (H=heads, S=sectors per track, cylinders are * automatically calculated). (This is ignored for floppies.) * i IDE (instead of SCSI) * oOFS; set base offset in bytes, when booting from an ISO9660 fs * r read-only (don't allow changes to the file) * s SCSI (this is the default) * t tape * V add an overlay to a disk image * 0-7 force a specific SCSI ID number * * machine is assumed to be non-NULL. * Returns an integer >= 0 identifying the disk image. */ int diskimage_add(struct machine *machine, char *fname) { struct diskimage *d, *d2; int id = 0, override_heads=0, override_spt=0; int64_t bytespercyl, override_base_offset=0; char *cp; int prefix_b=0, prefix_c=0, prefix_d=0, prefix_f=0, prefix_g=0; int prefix_i=0, prefix_r=0, prefix_s=0, prefix_t=0, prefix_id=-1; int prefix_o=0, prefix_V=0; if (fname == NULL) { fprintf(stderr, "diskimage_add(): NULL ptr\n"); return 0; } /* Get prefix from fname: */ cp = strchr(fname, ':'); if (cp != NULL) { while (fname <= cp) { char c = *fname++; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': prefix_id = c - '0'; break; case 'b': prefix_b = 1; break; case 'c': prefix_c = 1; break; case 'd': prefix_d = 1; break; case 'f': prefix_f = 1; break; case 'g': prefix_g = 1; override_heads = atoi(fname); while (*fname != '\0' && *fname != ';') fname ++; if (*fname == ';') fname ++; override_spt = atoi(fname); while (*fname != '\0' && *fname != ';' && *fname != ':') fname ++; if (*fname == ';') fname ++; if (override_heads < 1 || override_spt < 1) { fatal("Bad geometry: heads=%i " "spt=%i\n", override_heads, override_spt); exit(1); } break; case 'i': prefix_i = 1; break; case 'o': prefix_o = 1; override_base_offset = atoi(fname); while (*fname != '\0' && *fname != ':' && *fname != ';') fname ++; if (*fname == ':' || *fname == ';') fname ++; if (override_base_offset < 0) { fatal("Bad base offset: %" PRIi64 "\n", override_base_offset); exit(1); } break; case 'r': prefix_r = 1; break; case 's': prefix_s = 1; break; case 't': prefix_t = 1; break; case 'V': prefix_V = 1; break; case ':': break; default: fprintf(stderr, "diskimage_add(): invalid " "prefix char '%c'\n", c); exit(1); } } } /* Allocate a new diskimage struct: */ CHECK_ALLOCATION(d = (struct diskimage *) malloc(sizeof(struct diskimage))); memset(d, 0, sizeof(struct diskimage)); /* Default to IDE disks... */ d->type = DISKIMAGE_IDE; /* ... but some machines use SCSI by default: */ if (machine->machine_type == MACHINE_PMAX || machine->machine_type == MACHINE_ARC || machine->machine_type == MACHINE_SGI || machine->machine_type == MACHINE_MVME88K) d->type = DISKIMAGE_SCSI; if (prefix_i + prefix_f + prefix_s > 1) { fprintf(stderr, "Invalid disk image prefix(es). You can" "only use one of i, f, and s\nfor each disk image.\n"); exit(1); } if (prefix_i) d->type = DISKIMAGE_IDE; if (prefix_f) d->type = DISKIMAGE_FLOPPY; if (prefix_s) d->type = DISKIMAGE_SCSI; /* Special case: Add an overlay for an already added disk image: */ if (prefix_V) { struct diskimage *dx = machine->first_diskimage; if (prefix_id < 0) { fprintf(stderr, "The 'V' disk image prefix requires" " a disk ID to also be supplied.\n"); exit(1); } while (dx != NULL) { if (d->type == dx->type && prefix_id == dx->id) break; dx = dx->next; } if (dx == NULL) { fprintf(stderr, "Bad ID supplied for overlay?\n"); exit(1); } diskimage_add_overlay(dx, fname); /* Free the preliminary d struct: */ free(d); /* Don't add any disk image. This is an overlay! */ return -1; } /* Add the new disk image in the disk image chain: */ d2 = machine->first_diskimage; if (d2 == NULL) { machine->first_diskimage = d; } else { while (d2->next != NULL) d2 = d2->next; d2->next = d; } if (prefix_o) d->override_base_offset = override_base_offset; CHECK_ALLOCATION(d->fname = strdup(fname)); d->logical_block_size = 512; /* * Is this a tape, CD-ROM or a normal disk? * * An intelligent guess, if no prefixes are used, would be that * filenames ending with .iso or .cdr are CD-ROM images. */ if (prefix_t) { d->is_a_tape = 1; } else { if (prefix_c || ((strlen(d->fname) > 4 && (strcasecmp(d->fname + strlen(d->fname) - 4, ".cdr") == 0 || strcasecmp(d->fname + strlen(d->fname) - 4, ".iso") == 0)) && !prefix_d) ) { d->is_a_cdrom = 1; /* * This is tricky. Should I use 512 or 2048 here? * NetBSD/pmax 1.6.2 and Ultrix likes 512 bytes * per sector, but NetBSD 2.0_BETA suddenly ignores * this value and uses 2048 instead. * * OpenBSD/arc doesn't like 2048, it requires 512 * to work correctly. * * TODO */ #if 0 if (machine->machine_type == MACHINE_PMAX) d->logical_block_size = 512; else d->logical_block_size = 2048; #endif d->logical_block_size = 512; } } diskimage_recalc_size(d); if ((d->total_size == 720*1024 || d->total_size == 1474560 || d->total_size == 2949120 || d->total_size == 1228800) && !prefix_i && !prefix_s) d->type = DISKIMAGE_FLOPPY; switch (d->type) { case DISKIMAGE_FLOPPY: if (d->total_size < 737280) { fatal("\nTODO: small (non-80-cylinder) floppies?\n\n"); exit(1); } d->cylinders = 80; d->heads = 2; d->sectors_per_track = d->total_size / (d->cylinders * d->heads * 512); break; default:/* Non-floppies: */ d->heads = 16; d->sectors_per_track = 63; if (prefix_g) { d->chs_override = 1; d->heads = override_heads; d->sectors_per_track = override_spt; } bytespercyl = d->heads * d->sectors_per_track * 512; d->cylinders = d->total_size / bytespercyl; if (d->cylinders * bytespercyl < d->total_size) d->cylinders ++; } d->rpms = 3600; if (prefix_b) d->is_boot_device = 1; d->writable = access(fname, W_OK) == 0? 1 : 0; if (d->is_a_cdrom || prefix_r) { d->writable = 0; } else { if (!d->writable) { debug("NOTE: '%s' is read-only in the host file system, but 'r:' was not used.\n\n", d->fname); } } d->f = fopen(fname, d->writable? "r+" : "r"); if (d->f == NULL) { char *errmsg = (char *) malloc(200 + strlen(fname)); snprintf(errmsg, 200+strlen(fname), "could not fopen %s for reading%s", fname, d->writable? " and writing" : ""); perror(errmsg); exit(1); } /* Calculate which ID to use: */ if (prefix_id == -1) { int free = 0, collision = 1; while (collision) { collision = 0; d2 = machine->first_diskimage; while (d2 != NULL) { /* (don't compare against ourselves :) */ if (d2 == d) { d2 = d2->next; continue; } if (d2->id == free && d2->type == d->type) { collision = 1; break; } d2 = d2->next; } if (!collision) id = free; else free ++; } } else { id = prefix_id; d2 = machine->first_diskimage; while (d2 != NULL) { /* (don't compare against ourselves :) */ if (d2 == d) { d2 = d2->next; continue; } if (d2->id == id && d2->type == d->type) { fprintf(stderr, "disk image id %i " "already in use\n", id); exit(1); } d2 = d2->next; } } d->id = id; return id; } /* * diskimage_bootdev(): * * Returns the disk id of the device which we're booting from. If typep is * non-NULL, the type is returned as well. * * If no disk was used as boot device, then -1 is returned. (In practice, * this is used to fake network (tftp) boot.) */ int diskimage_bootdev(struct machine *machine, int *typep) { struct diskimage *d; d = machine->first_diskimage; while (d != NULL) { if (d->is_boot_device) { if (typep != NULL) *typep = d->type; return d->id; } d = d->next; } d = machine->first_diskimage; if (d != NULL) { if (typep != NULL) *typep = d->type; return d->id; } return -1; } /* * diskimage_getname(): * * Returns 1 if a valid disk image name was returned, 0 otherwise. */ int diskimage_getname(struct machine *machine, int id, int type, char *buf, size_t bufsize) { struct diskimage *d = machine->first_diskimage; if (buf == NULL) return 0; while (d != NULL) { if (d->type == type && d->id == id) { char *p = strrchr(d->fname, '/'); if (p == NULL) p = d->fname; else p ++; snprintf(buf, bufsize, "%s", p); return 1; } d = d->next; } return 0; } /* * diskimage_is_a_cdrom(): * * Returns 1 if a disk image is a CDROM, 0 otherwise. */ int diskimage_is_a_cdrom(struct machine *machine, int id, int type) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { if (d->type == type && d->id == id) return d->is_a_cdrom; d = d->next; } return 0; } /* * diskimage_is_a_tape(): * * Returns 1 if a disk image is a tape, 0 otherwise. * * (Used in src/machine.c, to select 'rz' vs 'tz' for DECstation * boot strings.) */ int diskimage_is_a_tape(struct machine *machine, int id, int type) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { if (d->type == type && d->id == id) return d->is_a_tape; d = d->next; } return 0; } /* * diskimage_dump_info(): * * Debug dump of all diskimages that are loaded for a specific machine. */ void diskimage_dump_info(struct machine *machine) { int i, iadd = DEBUG_INDENTATION; struct diskimage *d = machine->first_diskimage; while (d != NULL) { debug("diskimage: %s\n", d->fname); debug_indentation(iadd); switch (d->type) { case DISKIMAGE_SCSI: debug("SCSI"); break; case DISKIMAGE_IDE: debug("IDE"); break; case DISKIMAGE_FLOPPY: debug("FLOPPY"); break; default: debug("UNKNOWN type %i", d->type); } debug(" %s", d->is_a_tape? "TAPE" : (d->is_a_cdrom? "CD-ROM" : "DISK")); debug(" id %i, ", d->id); debug("%s, ", d->writable? "read/write" : "read-only"); if (d->type == DISKIMAGE_FLOPPY) debug("%lli KB", (long long) (d->total_size / 1024)); else debug("%lli MB", (long long) (d->total_size / 1048576)); if (d->type == DISKIMAGE_FLOPPY || d->chs_override) debug(" (CHS=%i,%i,%i)", d->cylinders, d->heads, d->sectors_per_track); else debug(" (%lli sectors)", (long long) (d->total_size / 512)); if (d->is_boot_device) debug(" (BOOT)"); debug("\n"); for (i=0; inr_of_overlays; i++) { debug("overlay %i: %s\n", i, d->overlays[i].overlay_basename); } debug_indentation(-iadd); d = d->next; } } gxemul-0.6.1/src/disk/diskimage_scsicmd.cc000644 001750 001750 00000076305 13402411502 020732 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Disk image support: SCSI command emulation. * * TODO: There are LOTS of ugly magic values in this module. These should * be replaced by proper defines. * * TODO: There's probably a bug in the tape support: * Let's say there are 10240 bytes left in a file, and 10240 * bytes are read. Then feof() is not true yet (?), so the next * read will also return 10240 bytes (but all zeroes), and then after * that return feof (which results in a filemark). This is probably * trivial to fix, but I don't feel like it right now. */ #include #include #include #include #include "cpu.h" #include "diskimage.h" #include "machine.h" #include "misc.h" static const char *diskimage_types[] = DISKIMAGE_TYPES; static struct scsi_transfer *first_free_scsi_transfer_alloc = NULL; /* * scsi_transfer_alloc(): * * Allocates memory for a new scsi_transfer struct, and fills it with * sane data (NULL pointers). * The return value is a pointer to the new struct. If allocation * failed, the program exits. */ struct scsi_transfer *scsi_transfer_alloc(void) { struct scsi_transfer *p; if (first_free_scsi_transfer_alloc != NULL) { p = first_free_scsi_transfer_alloc; first_free_scsi_transfer_alloc = p->next_free; } else { p = (struct scsi_transfer *) malloc(sizeof(struct scsi_transfer)); if (p == NULL) { fprintf(stderr, "scsi_transfer_alloc(): out " "of memory\n"); exit(1); } } memset(p, 0, sizeof(struct scsi_transfer)); return p; } /* * scsi_transfer_free(): * * Frees the space used by a scsi_transfer struct. All buffers refered * to by the scsi_transfer struct are freed. */ void scsi_transfer_free(struct scsi_transfer *p) { if (p == NULL) { fprintf(stderr, "scsi_transfer_free(): p == NULL\n"); exit(1); } if (p->msg_out != NULL) free(p->msg_out); if (p->cmd != NULL) free(p->cmd); if (p->data_out != NULL) free(p->data_out); if (p->data_in != NULL) free(p->data_in); if (p->msg_in != NULL) free(p->msg_in); if (p->status != NULL) free(p->status); p->next_free = first_free_scsi_transfer_alloc; first_free_scsi_transfer_alloc = p; } /* * scsi_transfer_allocbuf(): * * Helper function, used by diskimage_scsicommand(), and SCSI controller * devices. Example of usage: * * scsi_transfer_allocbuf(&xferp->msg_in_len, &xferp->msg_in, 1); */ void scsi_transfer_allocbuf(size_t *lenp, unsigned char **pp, size_t want_len, int clearflag) { unsigned char *p = (*pp); if (p != NULL) { printf("WARNING! scsi_transfer_allocbuf(): old pointer " "was not NULL, freeing it now\n"); free(p); } (*lenp) = want_len; if ((p = (unsigned char *) malloc(want_len)) == NULL) { fprintf(stderr, "scsi_transfer_allocbuf(): out of " "memory trying to allocate %li bytes\n", (long)want_len); exit(1); } if (clearflag) memset(p, 0, want_len); (*pp) = p; } /**************************************************************************/ /* * diskimage__return_default_status_and_message(): * * Set the status and msg_in parts of a scsi_transfer struct * to default values (msg_in = 0x00, status = 0x00). */ static void diskimage__return_default_status_and_message( struct scsi_transfer *xferp) { scsi_transfer_allocbuf(&xferp->status_len, &xferp->status, 1, 0); xferp->status[0] = 0x00; scsi_transfer_allocbuf(&xferp->msg_in_len, &xferp->msg_in, 1, 0); xferp->msg_in[0] = 0x00; } /* * diskimage__switch_tape(): * * Used by the SPACE command. (d is assumed to be non-NULL.) */ static void diskimage__switch_tape(struct diskimage *d) { char tmpfname[1000]; snprintf(tmpfname, sizeof(tmpfname), "%s.%i", d->fname, d->tape_filenr); tmpfname[sizeof(tmpfname)-1] = '\0'; if (d->f != NULL) fclose(d->f); d->f = fopen(tmpfname, d->writable? "r+" : "r"); if (d->f == NULL) { fprintf(stderr, "[ diskimage__switch_tape(): could not " "(re)open '%s' ]\n", tmpfname); /* TODO: return error */ } d->tape_offset = 0; } /**************************************************************************/ /* * diskimage_scsicommand(): * * Perform a SCSI command on a disk image. * * The xferp points to a scsi_transfer struct, containing msg_out, command, * and data_out coming from the SCSI controller device. This function * interprets the command, and (if necessary) creates responses in * data_in, msg_in, and status. * * Returns: * 2 if the command expects data from the DATA_OUT phase, * 1 if otherwise ok, * 0 on error. */ int diskimage_scsicommand(struct cpu *cpu, int id, int type, struct scsi_transfer *xferp) { char namebuf[16]; int retlen, i, q; uint64_t size; int64_t ofs; int pagecode; struct machine *machine = cpu->machine; struct diskimage *d; if (machine == NULL) { fatal("[ diskimage_scsicommand(): machine == NULL ]\n"); return 0; } d = machine->first_diskimage; while (d != NULL) { if (d->type == type && d->id == id) break; d = d->next; } if (d == NULL) { fprintf(stderr, "[ diskimage_scsicommand(): %s " " id %i not connected? ]\n", diskimage_types[type], id); } if (xferp->cmd == NULL) { fatal("[ diskimage_scsicommand(): cmd == NULL ]\n"); return 0; } if (xferp->cmd_len < 1) { fatal("[ diskimage_scsicommand(): cmd_len == %i ]\n", xferp->cmd_len); return 0; } debug("[ diskimage_scsicommand(id=%i) cmd=0x%02x: ", id, xferp->cmd[0]); #if 0 fatal("[ diskimage_scsicommand(id=%i) cmd=0x%02x len=%i:", id, xferp->cmd[0], xferp->cmd_len); for (i=0; icmd_len; i++) fatal(" %02x", xferp->cmd[i]); fatal("\n"); if (xferp->cmd_len > 7 && xferp->cmd[5] == 0x11) single_step = ENTER_SINGLE_STEPPING; #endif #if 0 { static FILE *f = NULL; if (f == NULL) f = fopen("scsi_log.txt", "w"); if (f != NULL) { int i; fprintf(f, "id=%i cmd =", id); for (i=0; icmd_len; i++) fprintf(f, " %02x", xferp->cmd[i]); fprintf(f, "\n"); fflush(f); } } #endif switch (xferp->cmd[0]) { case SCSICMD_TEST_UNIT_READY: debug("TEST_UNIT_READY"); if (xferp->cmd_len != 6) debug(" (weird len=%i)", xferp->cmd_len); /* TODO: bits 765 of buf[1] contains the LUN */ if (xferp->cmd[1] != 0x00) fatal("WARNING: TEST_UNIT_READY with cmd[1]=0x%02x" " not yet implemented\n", (int)xferp->cmd[1]); diskimage__return_default_status_and_message(xferp); break; case SCSICMD_INQUIRY: debug("INQUIRY"); if (xferp->cmd_len != 6) debug(" (weird len=%i)", xferp->cmd_len); if (xferp->cmd[1] != 0x00) { debug("WARNING: INQUIRY with cmd[1]=0x%02x not yet " "implemented\n", (int)xferp->cmd[1]); break; } /* Return values: */ retlen = xferp->cmd[4]; if (retlen < 36) { fatal("WARNING: SCSI inquiry len=%i, <36!\n", retlen); retlen = 36; } /* Return data: */ scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in, retlen, 1); xferp->data_in[0] = 0x00; /* 0x00 = Direct-access disk */ xferp->data_in[1] = 0x00; /* 0x00 = non-removable */ xferp->data_in[2] = 0x02; /* SCSI-2 */ #if 0 xferp->data_in[3] = 0x02; /* Response data format = SCSI-2 */ #endif xferp->data_in[4] = retlen - 4; /* Additional length */ xferp->data_in[4] = 0x2c - 4; /* Additional length */ xferp->data_in[6] = 0x04; /* ACKREQQ */ xferp->data_in[7] = 0x60; /* WBus32, WBus16 */ /* These are padded with spaces: */ memcpy(xferp->data_in+8, "GXemul ", 8); if (diskimage_getname(cpu->machine, id, type, namebuf, sizeof(namebuf))) { for (size_t j=0; jdata_in+16, namebuf, 16); } else memcpy(xferp->data_in+16, "DISK ", 16); memcpy(xferp->data_in+32, "0 ", 4); /* * Some Ultrix kernels want specific responses from * the drives. */ if (machine->machine_type == MACHINE_PMAX) { /* DEC, RZ25 (rev 0900) = 832527 sectors */ /* DEC, RZ58 (rev 2000) = 2698061 sectors */ memcpy(xferp->data_in+8, "DEC ", 8); memcpy(xferp->data_in+16, "RZ58 (C) DEC", 16); memcpy(xferp->data_in+32, "2000", 4); } /* Some data is different for CD-ROM drives: */ if (d->is_a_cdrom) { xferp->data_in[0] = 0x05; /* 0x05 = CD-ROM */ xferp->data_in[1] = 0x80; /* 0x80 = removable */ /* memcpy(xferp->data_in+16, "CD-ROM ", 16);*/ if (machine->machine_type == MACHINE_PMAX) { /* SONY, CD-ROM: */ memcpy(xferp->data_in+8, "SONY ", 8); memcpy(xferp->data_in+16, "CD-ROM ", 16); /* ... or perhaps this: */ memcpy(xferp->data_in+8, "DEC ", 8); memcpy(xferp->data_in+16, "RRD42 (C) DEC ", 16); memcpy(xferp->data_in+32, "4.5d", 4); } else if (machine->machine_type == MACHINE_ARC) { /* NEC, CD-ROM: */ memcpy(xferp->data_in+8, "NEC ", 8); memcpy(xferp->data_in+16, "CD-ROM CDR-210P ", 16); memcpy(xferp->data_in+32, "1.0 ", 4); } } /* Data for tape devices: */ if (d->is_a_tape) { xferp->data_in[0] = 0x01; /* 0x01 = tape */ xferp->data_in[1] = 0x80; /* 0x80 = removable */ memcpy(xferp->data_in+16, "TAPE ", 16); if (machine->machine_type == MACHINE_PMAX) { /* * TODO: find out if these are correct. * * The name might be TZK10, TSZ07, or TLZ04, * or something completely different. */ memcpy(xferp->data_in+8, "DEC ", 8); memcpy(xferp->data_in+16, "TK50 (C) DEC", 16); memcpy(xferp->data_in+32, "2000", 4); } } diskimage__return_default_status_and_message(xferp); break; case SCSIBLOCKCMD_READ_CAPACITY: debug("READ_CAPACITY"); if (xferp->cmd_len != 10) fatal(" [ weird READ_CAPACITY len=%i, should be 10 ] ", xferp->cmd_len); else { if (xferp->cmd[8] & 1) { /* Partial Medium Indicator bit... TODO */ fatal("WARNING: READ_CAPACITY with PMI bit" " set not yet implemented\n"); } } /* Return data: */ scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in, 8, 1); diskimage_recalc_size(d); size = d->total_size / d->logical_block_size; if (d->total_size & (d->logical_block_size-1)) size ++; xferp->data_in[0] = (size >> 24) & 255; xferp->data_in[1] = (size >> 16) & 255; xferp->data_in[2] = (size >> 8) & 255; xferp->data_in[3] = size & 255; xferp->data_in[4] = (d->logical_block_size >> 24) & 255; xferp->data_in[5] = (d->logical_block_size >> 16) & 255; xferp->data_in[6] = (d->logical_block_size >> 8) & 255; xferp->data_in[7] = d->logical_block_size & 255; diskimage__return_default_status_and_message(xferp); break; case SCSICMD_MODE_SENSE: case SCSICMD_MODE_SENSE10: debug("MODE_SENSE"); q = 4; retlen = xferp->cmd[4]; switch (xferp->cmd_len) { case 6: break; case 10:q = 8; retlen = xferp->cmd[7] * 256 + xferp->cmd[8]; break; default:fatal(" (unimplemented mode_sense len=%i)", xferp->cmd_len); } /* * NOTE/TODO: This code doesn't handle too short retlens * very well. A quick hack around this is that I allocate * a bit too much memory, so that nothing is actually * written outside of xferp->data_in[]. */ retlen += 100; /* Should be enough. (Ugly.) */ if ((xferp->cmd[2] & 0xc0) != 0) fatal("WARNING: mode sense, cmd[2] = 0x%02x\n", xferp->cmd[2]); /* Return data: */ scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in, retlen, 1); xferp->data_in_len -= 100; /* Restore size. */ pagecode = xferp->cmd[2] & 0x3f; debug("[ MODE SENSE id %i, pagecode=%i ]\n", id, pagecode); /* 4 bytes of header for 6-byte command, 8 bytes of header for 10-byte command. */ xferp->data_in[0] = retlen; /* 0: mode data length */ xferp->data_in[1] = d->is_a_cdrom? 0x05 : 0x00; /* 1: medium type */ xferp->data_in[2] = 0x00; /* device specific parameter */ xferp->data_in[3] = 8 * 1; /* block descriptor length: 1 page (?) */ xferp->data_in[q+0] = 0x00; /* density code */ xferp->data_in[q+1] = 0; /* nr of blocks, high */ xferp->data_in[q+2] = 0; /* nr of blocks, mid */ xferp->data_in[q+3] = 0; /* nr of blocks, low */ xferp->data_in[q+4] = 0x00; /* reserved */ xferp->data_in[q+5] = (d->logical_block_size >> 16) & 255; xferp->data_in[q+6] = (d->logical_block_size >> 8) & 255; xferp->data_in[q+7] = d->logical_block_size & 255; q += 8; diskimage__return_default_status_and_message(xferp); /* descriptors, 8 bytes (each) */ /* page, n bytes (each) */ switch (pagecode) { case 0: /* TODO: Nothing here? */ break; case 1: /* read-write error recovery page */ xferp->data_in[q + 0] = pagecode; xferp->data_in[q + 1] = 10; break; case 3: /* format device page */ xferp->data_in[q + 0] = pagecode; xferp->data_in[q + 1] = 22; /* 10,11 = sectors per track */ xferp->data_in[q + 10] = 0; xferp->data_in[q + 11] = d->sectors_per_track; /* 12,13 = physical sector size */ xferp->data_in[q + 12] = (d->logical_block_size >> 8) & 255; xferp->data_in[q + 13] = d->logical_block_size & 255; break; case 4: /* rigid disk geometry page */ xferp->data_in[q + 0] = pagecode; xferp->data_in[q + 1] = 22; xferp->data_in[q + 2] = (d->ncyls >> 16) & 255; xferp->data_in[q + 3] = (d->ncyls >> 8) & 255; xferp->data_in[q + 4] = d->ncyls & 255; xferp->data_in[q + 5] = d->heads; xferp->data_in[q + 20] = (d->rpms >> 8) & 255; xferp->data_in[q + 21] = d->rpms & 255; break; case 5: /* flexible disk page */ xferp->data_in[q + 0] = pagecode; xferp->data_in[q + 1] = 0x1e; /* 2,3 = transfer rate */ xferp->data_in[q + 2] = ((5000) >> 8) & 255; xferp->data_in[q + 3] = (5000) & 255; xferp->data_in[q + 4] = d->heads; xferp->data_in[q + 5] = d->sectors_per_track; /* 6,7 = data bytes per sector */ xferp->data_in[q + 6] = (d->logical_block_size >> 8) & 255; xferp->data_in[q + 7] = d->logical_block_size & 255; xferp->data_in[q + 8] = (d->ncyls >> 8) & 255; xferp->data_in[q + 9] = d->ncyls & 255; xferp->data_in[q + 28] = (d->rpms >> 8) & 255; xferp->data_in[q + 29] = d->rpms & 255; break; default: fatal("[ MODE_SENSE for page %i is not yet " "implemented! ]\n", pagecode); } break; case SCSICMD_READ: case SCSICMD_READ_10: debug("READ"); /* * For tape devices, read data at the current position. * For disk and CDROM devices, the command bytes contain * an offset telling us where to read from the device. */ if (d->is_a_tape) { /* bits 7..5 of cmd[1] are the LUN bits... TODO */ size = (xferp->cmd[2] << 16) + (xferp->cmd[3] << 8) + xferp->cmd[4]; /* Bit 1 of cmd[1] is the SILI bit (TODO), and bit 0 is the "use fixed length" bit. */ if (xferp->cmd[1] & 0x01) { /* Fixed block length: */ size *= d->logical_block_size; } if (d->filemark) { /* At end of file, switch to the next automagically: */ d->tape_filenr ++; diskimage__switch_tape(d); d->filemark = 0; } ofs = d->tape_offset; fatal("[ READ tape, id=%i file=%i, cmd[1]=%02x size=%i" ", ofs=%lli ]\n", id, d->tape_filenr, xferp->cmd[1], (int)size, (long long)ofs); } else { if (xferp->cmd[0] == SCSICMD_READ) { if (xferp->cmd_len != 6) debug(" (weird len=%i)", xferp->cmd_len); /* * bits 4..0 of cmd[1], and cmd[2] and cmd[3] * hold the logical block address. * * cmd[4] holds the number of logical blocks * to transfer. (Special case if the value is * 0, actually means 256.) */ ofs = ((xferp->cmd[1] & 0x1f) << 16) + (xferp->cmd[2] << 8) + xferp->cmd[3]; retlen = xferp->cmd[4]; if (retlen == 0) retlen = 256; } else { if (xferp->cmd_len != 10) debug(" (weird len=%i)", xferp->cmd_len); /* * cmd[2..5] hold the logical block address. * cmd[7..8] holds the number of logical * blocks to transfer. (NOTE: If the value is * 0, this means 0, not 65536. :-) */ ofs = ((uint64_t)xferp->cmd[2] << 24) + (xferp->cmd[3] << 16) + (xferp->cmd[4] << 8) + xferp->cmd[5]; retlen = (xferp->cmd[7] << 8) + xferp->cmd[8]; } size = retlen * d->logical_block_size; ofs *= d->logical_block_size; } /* Return data: */ scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in, size, 0); debug(" READ ofs=%lli size=%i\n", (long long)ofs, (int)size); diskimage__return_default_status_and_message(xferp); d->filemark = 0; /* * Failure? Then set check condition. * For tapes, error should only occur at the end of a file. * * "If the logical unit encounters a filemark during * a READ command, CHECK CONDITION status shall be * returned and the filemark and valid bits shall be * set to one in the sense data. The sense key shall * be set to NO SENSE".. */ if (d->is_a_tape && d->f != NULL && feof(d->f)) { debug(" feof id=%i\n", id); xferp->status[0] = 0x02; /* CHECK CONDITION */ d->filemark = 1; } else diskimage__internal_access(d, 0, ofs, xferp->data_in, size); if (d->is_a_tape && d->f != NULL) d->tape_offset = ftello(d->f); /* TODO: other errors? */ break; case SCSICMD_WRITE: case SCSICMD_WRITE_10: debug("WRITE"); /* TODO: tape */ if (xferp->cmd[0] == SCSICMD_WRITE) { if (xferp->cmd_len != 6) debug(" (weird len=%i)", xferp->cmd_len); /* * bits 4..0 of cmd[1], and cmd[2] and cmd[3] hold the * logical block address. * * cmd[4] holds the number of logical blocks to * transfer. (Special case if the value is 0, actually * means 256.) */ ofs = ((xferp->cmd[1] & 0x1f) << 16) + (xferp->cmd[2] << 8) + xferp->cmd[3]; retlen = xferp->cmd[4]; if (retlen == 0) retlen = 256; } else { if (xferp->cmd_len != 10) debug(" (weird len=%i)", xferp->cmd_len); /* * cmd[2..5] hold the logical block address. * cmd[7..8] holds the number of logical blocks to * transfer. (NOTE: If the value is 0 this means 0, * not 65536.) */ ofs = ((uint64_t)xferp->cmd[2] << 24) + (xferp->cmd[3] << 16) + (xferp->cmd[4] << 8) + xferp->cmd[5]; retlen = (xferp->cmd[7] << 8) + xferp->cmd[8]; } size = retlen * d->logical_block_size; ofs *= d->logical_block_size; if (xferp->data_out_offset != size) { debug(", data_out == NULL, wanting %i bytes, \n\n", (int)size); xferp->data_out_len = size; return 2; } debug(", data_out != NULL, OK :-)"); debug("WRITE ofs=%i size=%i offset=%i\n", (int)ofs, (int)size, (int)xferp->data_out_offset); diskimage__internal_access(d, 1, ofs, xferp->data_out, size); /* TODO: how about return code? */ /* Is this really necessary? */ /* fsync(fileno(d->f)); */ diskimage__return_default_status_and_message(xferp); break; case SCSICMD_SYNCHRONIZE_CACHE: debug("SYNCHRONIZE_CACHE"); if (xferp->cmd_len != 10) debug(" (weird len=%i)", xferp->cmd_len); /* TODO: actualy care about cmd[] */ fsync(fileno(d->f)); diskimage__return_default_status_and_message(xferp); break; case SCSICMD_START_STOP_UNIT: debug("START_STOP_UNIT"); if (xferp->cmd_len != 6) debug(" (weird len=%i)", xferp->cmd_len); for (i=0; i<(ssize_t)xferp->cmd_len; i++) debug(" %02x", xferp->cmd[i]); /* TODO: actualy care about cmd[] */ diskimage__return_default_status_and_message(xferp); break; case SCSICMD_REQUEST_SENSE: debug("REQUEST_SENSE"); retlen = xferp->cmd[4]; /* TODO: bits 765 of buf[1] contains the LUN */ if (xferp->cmd[1] != 0x00) fatal("WARNING: REQUEST_SENSE with cmd[1]=0x%02x not" " yet implemented\n", (int)xferp->cmd[1]); if (retlen < 18) { fatal("WARNING: SCSI request sense len=%i, <18!\n", (int)retlen); retlen = 18; } /* Return data: */ scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in, retlen, 1); xferp->data_in[0] = 0x80 + 0x70;/* 0x80 = valid, 0x70 = "current errors" */ xferp->data_in[2] = 0x00; /* SENSE KEY! */ if (d->filemark) { xferp->data_in[2] = 0x80; } debug(": [2]=0x%02x ", xferp->data_in[2]); printf(" XXX(!) \n"); /* TODO */ xferp->data_in[7] = retlen - 7; /* additional sense length */ /* TODO */ diskimage__return_default_status_and_message(xferp); break; case SCSICMD_READ_BLOCK_LIMITS: debug("READ_BLOCK_LIMITS"); retlen = 6; /* TODO: bits 765 of buf[1] contains the LUN */ if (xferp->cmd[1] != 0x00) fatal("WARNING: READ_BLOCK_LIMITS with cmd[1]=" "0x%02x not yet implemented\n", (int)xferp->cmd[1]); /* Return data: */ scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in, retlen, 1); /* * data[0] is reserved, data[1..3] contain the maximum block * length limit, data[4..5] contain the minimum limit. */ { int max_limit = 32768; int min_limit = 128; xferp->data_in[1] = (max_limit >> 16) & 255; xferp->data_in[2] = (max_limit >> 8) & 255; xferp->data_in[3] = max_limit & 255; xferp->data_in[4] = (min_limit >> 8) & 255; xferp->data_in[5] = min_limit & 255; } diskimage__return_default_status_and_message(xferp); break; case SCSICMD_REWIND: debug("REWIND"); /* TODO: bits 765 of buf[1] contains the LUN */ if ((xferp->cmd[1] & 0xe0) != 0x00) fatal("WARNING: REWIND with cmd[1]=0x%02x not yet " "implemented\n", (int)xferp->cmd[1]); /* Close and reopen. */ if (d->f != NULL) fclose(d->f); d->f = fopen(d->fname, d->writable? "r+" : "r"); if (d->f == NULL) { fprintf(stderr, "[ diskimage: could not (re)open " "'%s' ]\n", d->fname); /* TODO: return error */ } d->tape_offset = 0; d->tape_filenr = 0; d->filemark = 0; diskimage__return_default_status_and_message(xferp); break; case SCSICMD_SPACE: debug("SPACE"); /* TODO: bits 765 of buf[1] contains the LUN */ if ((xferp->cmd[1] & 0xe0) != 0x00) fatal("WARNING: SPACE with cmd[1]=0x%02x not yet " "implemented\n", (int)xferp->cmd[1]); /* * Bits 2..0 of buf[1] contain the 'code' which describes how * spacing should be done, and buf[2..4] contain the number of * operations. */ debug("[ SPACE: buf[] = %02x %02x %02x %02x %02x %02x ]\n", xferp->cmd[0], xferp->cmd[1], xferp->cmd[2], xferp->cmd[3], xferp->cmd[4], xferp->cmd[5]); switch (xferp->cmd[1] & 7) { case 1: /* Seek to a different file nr: */ { int diff = (xferp->cmd[2] << 16) + (xferp->cmd[3] << 8) + xferp->cmd[4]; /* Negative seek offset: */ if (diff & (1 << 23)) diff = - (16777216 - diff); d->tape_filenr += diff; } /* At end of file, switch to the next tape file: */ if (d->filemark) { d->tape_filenr ++; d->filemark = 0; } debug("{ switching to tape file %i }", d->tape_filenr); diskimage__switch_tape(d); d->filemark = 0; break; default: fatal("[ diskimage.c: unimplemented SPACE type %i ]\n", xferp->cmd[1] & 7); } diskimage__return_default_status_and_message(xferp); break; case SCSICDROM_READ_SUBCHANNEL: /* * According to * http://mail-index.netbsd.org/port-i386/1997/03/03/0010.html: * * "The READ_CD_CAPACITY, READ_SUBCHANNEL, and MODE_SELECT * commands have the same opcode in SCSI or ATAPI, but don't * have the same command structure"... * * TODO: This still doesn't work. Hm. */ retlen = 48; debug("CDROM_READ_SUBCHANNEL/READ_CD_CAPACITY, cmd[1]=0x%02x", xferp->cmd[1]); /* Return data: */ scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in, retlen, 1); diskimage_recalc_size(d); size = d->total_size / d->logical_block_size; if (d->total_size & (d->logical_block_size-1)) size ++; xferp->data_in[0] = (size >> 24) & 255; xferp->data_in[1] = (size >> 16) & 255; xferp->data_in[2] = (size >> 8) & 255; xferp->data_in[3] = size & 255; xferp->data_in[4] = (d->logical_block_size >> 24) & 255; xferp->data_in[5] = (d->logical_block_size >> 16) & 255; xferp->data_in[6] = (d->logical_block_size >> 8) & 255; xferp->data_in[7] = d->logical_block_size & 255; diskimage__return_default_status_and_message(xferp); break; case SCSICDROM_READ_TOC: debug("(CDROM_READ_TOC: "); debug("lun=%i msf=%i ", xferp->cmd[1] >> 5, (xferp->cmd[1] >> 1) & 1); debug("starting_track=%i ", xferp->cmd[6]); retlen = xferp->cmd[7] * 256 + xferp->cmd[8]; debug("allocation_len=%i)\n", retlen); /* Return data: */ scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in, retlen, 1); xferp->data_in[0] = 0; xferp->data_in[1] = 10; xferp->data_in[2] = 0; /* First track. */ xferp->data_in[3] = 0; /* Last track. */ /* Track 0 data: */ xferp->data_in[4] = 0x00; /* Reserved. */ xferp->data_in[5] = 0x04; /* ADR + CTRL: Data, not audio */ xferp->data_in[6] = 0x00; /* Track nr */ xferp->data_in[7] = 0x00; /* Reserved */ /* 8..11 = absolute CDROM address */ diskimage__return_default_status_and_message(xferp); break; case SCSICDROM_READ_DISCINFO: /* (Patch from Hvard Eidnes.) */ debug("CDROM_READ_DISCINFO, cmd[1]=0x%02x", xferp->cmd[1]); retlen = 34; scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in, retlen, 1); /* TODO: Make this more generic! */ xferp->data_in[0] = retlen-2; /* length of info, excl len */ xferp->data_in[1] = 0; /* length of info-(len field), msb */ xferp->data_in[2] = 0xE; /* 11=complete ses., 10=fin disc */ xferp->data_in[3] = 0; /* First track on disc */ xferp->data_in[4] = 1; /* Number of sessions, lsb */ xferp->data_in[5] = 0; /* first_track_last_session_lsb */ xferp->data_in[6] = 0; /* last_track_last_session_lsb */ xferp->data_in[7] = 0x20;/* various flags */ xferp->data_in[8] = 0; /* CD-ROM disc */ xferp->data_in[9] = 1; /* num sessions, msb */ xferp->data_in[10] = 0; /* first_track_last_session_msb */ xferp->data_in[11] = 0; /* last_track_last_session_msb */ /* Lead-in data, for completed cd-rom: */ for (size_t j=16; j<=23; j++) xferp->data_in[j] = 0xff; diskimage__return_default_status_and_message(xferp); break; case SCSICDROM_READ_TRACKINFO: /* (Patch from Hvard Eidnes.) */ debug("CDROM_READ_TRACKINFO"); retlen = 36; scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in, retlen, 1); diskimage_recalc_size(d); size = d->total_size / d->logical_block_size; if (d->total_size & (d->logical_block_size-1)) size ++; /* TODO: Make more generic? */ /* TODO: Don't use magic values. */ xferp->data_in[0] = retlen-2; /* length of info, excl len */ xferp->data_in[1] = 0; /* length of info, msb */ xferp->data_in[2] = 1; /* track#, lsb */ xferp->data_in[3] = 1; /* session#, lsb */ xferp->data_in[4] = 0; /* reserved */ xferp->data_in[5] = 0x6; /* trk mode: unintr. data, copyable */ xferp->data_in[6] = 0x81; /* trk info: RT + trk mode */ xferp->data_in[7] = 0x2; /* last rec=valid, next w=not valid */ /* * track start, next writable, free blcks, * blocking factor */ for(size_t j=8; j<=23; j++) xferp->data_in[j] = 0; /* Track size: */ xferp->data_in[24] = (size >> 24) & 0xff; xferp->data_in[25] = (size >> 16) & 0xff; xferp->data_in[26] = (size >> 8) & 0xff; xferp->data_in[27] = size & 0xff; /* Last recorded address, only for dvd; zero out the rest: */ for (size_t k=28; k<=35; k++) xferp->data_in[k] = 0; diskimage__return_default_status_and_message(xferp); break; case SCSICMD_MODE_SELECT: debug("[ SCSI MODE_SELECT: "); /* * TODO: * * This is super-hardcoded for NetBSD's usage of mode_select * to set the size of CDROM sectors to 2048. */ if (xferp->data_out_offset == 0) { xferp->data_out_len = 12; /* TODO */ debug("data_out == NULL, wanting %i bytes ]\n", (int)xferp->data_out_len); return 2; } debug("data_out!=NULL (OK), "); /* TODO: Care about cmd? */ /* Set sector size to 2048: */ /* 00 05 00 08 00 03 ca 40 00 00 08 00 */ if (xferp->data_out[0] == 0x00 && xferp->data_out[1] == 0x05 && xferp->data_out[2] == 0x00 && xferp->data_out[3] == 0x08) { d->logical_block_size = (xferp->data_out[9] << 16) + (xferp->data_out[10] << 8) + xferp->data_out[11]; debug("[ setting logical_block_size to %i ]\n", d->logical_block_size); } else { int j; fatal("[ unknown MODE_SELECT: cmd ="); for (j=0; j<(ssize_t)xferp->cmd_len; j++) fatal(" %02x", xferp->cmd[j]); fatal(", data_out ="); for (j=0; j<(ssize_t)xferp->data_out_len; j++) fatal(" %02x", xferp->data_out[j]); fatal(" ]"); } debug(" ]\n"); diskimage__return_default_status_and_message(xferp); break; case SCSICMD_PREVENT_ALLOW_REMOVE: debug("[ SCSI 0x%02x Prevent/allow medium removal: " "TODO ]\n", xferp->cmd[0]); diskimage__return_default_status_and_message(xferp); break; case 0xbd: fatal("[ SCSI 0x%02x (len %i), TODO: ", xferp->cmd[0], xferp->cmd_len); for (i=0; i<(ssize_t)xferp->cmd_len; i++) fatal(" %02x", xferp->cmd[i]); fatal(" ]\n"); /* * Used by Windows NT? * * Not documented in http://www.danbbs.dk/~dino/ * SCSI/SCSI2-D.html. * Google gave the answer "MECHANISM_STATUS" for ATAPI. Hm. */ if (xferp->cmd_len < 12) { fatal("WEIRD LEN?\n"); retlen = 8; } else { retlen = xferp->cmd[8] * 256 + xferp->cmd[9]; } /* Return data: */ scsi_transfer_allocbuf(&xferp->data_in_len, &xferp->data_in, retlen, 1); diskimage__return_default_status_and_message(xferp); break; default: fatal("[ UNIMPLEMENTED SCSI command 0x%02x, disk id=%i ]\n", xferp->cmd[0], id); exit(1); } debug(" ]\n"); return 1; } gxemul-0.6.1/src/disk/bootblock_iso9660.cc000644 001750 001750 00000026143 13402411502 020440 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * ISO9660 CD-ROM "bootblock" handling. * * Despite the name, there is actually no bootblock; instead, the file which * is to be booted is extracted into a temporary file, and started as if it * was given as a normal file argument on the command line. * * TODO: This is really ugly. It's a quick hack. All the magic constants * need to be replaced with real code! * * Instead of the current "could not find" message, it should really * be more helpful, and print out the files found in the current * directory, so that one can more easily choose the correct file. */ #include #include #include #include #include #include "cpu.h" #include "diskimage.h" #include "machine.h" #include "misc.h" /* #define ISO_DEBUG */ static void debug_print_volume_id_and_filename(int iso_type, unsigned char *buf, char *filename) { /* Volume ID: */ char str[35]; int i, ofs = iso_type == 3? 48 : 40; memcpy(str, buf + ofs, sizeof(str)); str[32] = '\0'; i = 31; while (i >= 0 && str[i]==' ') str[i--] = '\0'; if (str[0]) debug("\"%s\"", str); else { /* System ID: */ ofs = iso_type == 3? 16 : 8; memcpy(str, buf + ofs, sizeof(str)); str[32] = '\0'; i = 31; while (i >= 0 && str[i]==' ') str[i--] = '\0'; if (str[0]) debug("\"%s\"", str); else debug("(no ID)"); } debug(":%s\n", filename); } /* * iso_load_bootblock(): * * Try to load a kernel from an ISO 9660 disk image. iso_type is 1 for * "CD001" (standard), 2 for "CDW01" (ECMA), and 3 for "CDROM" (Sierra). * * TODO: This function uses too many magic offsets and so on; it should be * cleaned up some day. * * Returns 1 on success, 0 on failure. */ int iso_load_bootblock(struct machine *m, struct cpu *cpu, int disk_id, int disk_type, int iso_type, unsigned char *buf, int *n_loadp, char ***load_namesp) { int filenr, dirlen, res = 0, res2, iadd = DEBUG_INDENTATION, found_dir; uint64_t dirofs, fileofs; ssize_t filelen; unsigned char *dirbuf = NULL, *dp, *match_entry = NULL, *filebuf = NULL; char *p, *filename_orig, *filename, *tmpfname = NULL; char **new_array; const char *tmpdir = getenv("TMPDIR"); int tmpfile_handle; if (tmpdir == NULL) tmpdir = DEFAULT_TMP_DIR; CHECK_ALLOCATION(filename = strdup(cpu->machine->boot_kernel_filename)); filename_orig = filename; debug("ISO9660 boot:\n"); debug_indentation(iadd); debug_print_volume_id_and_filename(iso_type, buf, filename); /* * Hack: If there is something like this at offset 0x9000: * * "MKI Wed Nov 29 17:56:55 2000\n" * "mkisofs 1.13 -r -l -C 0,11702 /home/LC2000-CDR" * * and the disk offset is zero, then it can PROBABLY be assumed that * offset 11702 is better. (This is counted in 2048 byte sectors.) */ { unsigned char tmpbuf[0x800]; uint64_t base_offset = diskimage_get_baseoffset(m, disk_id, disk_type); res2 = diskimage_access(m, disk_id, disk_type, 0, base_offset + 0x9000, tmpbuf, 0x800); if (!res2) { fatal("Couldn't read MKI part after the ISO header of the disk image. Aborting.\n"); goto ret; } int64_t suggestedBaseOffset = 0; tmpbuf[sizeof(tmpbuf)-1] = '\0'; char* found = strstr((char*)tmpbuf, "MKI "); if (found != NULL) { found = strstr(found, " -C 0,"); if (found != NULL) { suggestedBaseOffset = strtoll(found + 6, NULL, 0); } } int64_t currentBaseOffset = diskimage_get_baseoffset(m, disk_id, disk_type); suggestedBaseOffset *= 2048; if (currentBaseOffset == 0 && suggestedBaseOffset != currentBaseOffset) { debug("NOTE: automagically adjusting to use base offset %lli\n", (long long)suggestedBaseOffset); diskimage_set_baseoffset(m, disk_id, disk_type, suggestedBaseOffset); } } /* * Traverse the directory structure to find the kernel. */ dirlen = buf[0x84] + 256*buf[0x85] + 65536*buf[0x86]; if (dirlen != buf[0x8b] + 256*buf[0x8a] + 65536*buf[0x89]) fatal("WARNING: Root directory length mismatch?\n"); dirofs = (int64_t)(buf[0x8c] + (buf[0x8d] << 8) + (buf[0x8e] << 16) + ((uint64_t)buf[0x8f] << 24)) * 2048; #ifdef ISO_DEBUG debug("root = %i bytes at 0x%llx\n", dirlen, (long long)dirofs); #endif CHECK_ALLOCATION(dirbuf = (unsigned char *) malloc(dirlen)); res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs, dirbuf, dirlen); if (!res2) { fatal("Couldn't read the disk image. Aborting.\n"); goto ret; } found_dir = 1; /* Assume root dir */ dp = dirbuf; filenr = 1; p = NULL; while (dp < dirbuf + dirlen) { size_t i, nlen = dp[0]; int x = dp[2] + (dp[3] << 8) + (dp[4] << 16) + ((uint64_t)dp[5] << 24); int y = dp[6] + (dp[7] << 8); char direntry[65]; dp += 8; /* * As long as there is an \ or / in the filename, then we * have not yet found the directory. */ p = strchr(filename, '/'); if (p == NULL) p = strchr(filename, '\\'); #ifdef ISO_DEBUG debug("%i%s: %i, %i, \"", filenr, filenr == found_dir? " [CURRENT]" : "", x, y); #endif for (i=0; i 2047) { dirofs = (dirofs | 2047) + 1; /* debug("realign dirofs = 0x%llx\n", dirofs); */ } // debug("dirofs = %lli\n", (long long)dirofs); res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs, dirbuf, 256); if (!res2) { fatal("Couldn't read the disk image. Aborting.\n"); goto ret; } dp = dirbuf; len = dp[0]; if (len < 2) { // debug("dir too short\n"); break; } /* * TODO: Actually parse the directory entry! * * Haha, this must be rewritten. */ #ifdef ISO_DEBUG /* hahahaha */ printf("filename = '%s'\n", filename); { size_t j; for (j=32; j= ' ' && dp[j] < 128? dp[j] : '.'); printf("\n"); } // Hahaha. Yes, it's horrible. (Updated 2011-06-09.) // Yes it is. (2018-06-18.) :-( #endif for (i=32; i #include #include #include "diskimage.h" #include "misc.h" /* * apple_load_bootblock(): * * Try to load a kernel from a disk image with an Apple Partition Table. * * TODO: This function uses too many magic offsets and so on; it should be * cleaned up some day. See http://www.awprofessional.com/articles/ * article.asp?p=376123&seqNum=3&rl=1 for some info on the Apple * partition format. * * Returns 1 on success, 0 on failure. */ int apple_load_bootblock(struct machine *m, struct cpu *cpu, int disk_id, int disk_type, int *n_loadp, char ***load_namesp) { unsigned char buf[0x8000]; int res, partnr, n_partitions = 0, n_hfs_partitions = 0; uint64_t hfs_start, hfs_length; res = diskimage_access(m, disk_id, disk_type, 0, 0x0, buf, sizeof(buf)); if (!res) { fatal("apple_load_bootblock: couldn't read the disk " "image. Aborting.\n"); return 0; } partnr = 0; do { int start, length; int ofs = 0x200 * (partnr + 1); if (partnr == 0) n_partitions = buf[ofs + 7]; start = ((uint64_t)buf[ofs + 8] << 24) + (buf[ofs + 9] << 16) + (buf[ofs + 10] << 8) + buf[ofs + 11]; length = ((uint64_t)buf[ofs+12] << 24) + (buf[ofs + 13] << 16) + (buf[ofs + 14] << 8) + buf[ofs + 15]; debug("partition %i: '%s', type '%s', start %i, length %i\n", partnr, buf + ofs + 0x10, buf + ofs + 0x30, start, length); if (strcmp((char *)buf + ofs + 0x30, "Apple_HFS") == 0) { n_hfs_partitions ++; hfs_start = 512 * start; hfs_length = 512 * length; } /* Any more partitions? */ partnr ++; } while (partnr < n_partitions); if (n_hfs_partitions == 0) { fatal("Error: No HFS partition found! TODO\n"); return 0; } if (n_hfs_partitions >= 2) { fatal("Error: Too many HFS partitions found! TODO\n"); return 0; } return 0; } gxemul-0.6.1/src/promemul/of.cc000644 001750 001750 00000076603 13402411502 016603 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2012 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: OpenFirmware emulation * * NOTE: This module is/was a quick hack, with the purpose of getting * NetBSD/macppc to boot. If anything else boots using this hackish * implementation of OpenFirmware, then that is a bonus. * ****************************************************************************** * * NOTE: OpenFirmware is used on quite a variety of different hardware archs, * at least POWER/PowerPC, ARM, and SPARC, so the code in this module * must always remain architecture agnostic. * * NOTE: Some things, e.g. 32-bit integers as returned by the "getprop" * service, are always fixed to big-endian. (According to the standard.) * * TODO: o) 64-bit OpenFirmware? * o) More devices... */ #include #include #include #include #define OF_C #include "console.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "diskimage.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "of.h" /* #define debug fatal */ extern int quiet_mode; extern int verbose; /* * readstr(): * * Helper function to read a string from emulated memory. */ static void readstr(struct cpu *cpu, uint64_t addr, char *strbuf, int bufsize) { int i; for (i=0; imemory_rw(cpu, cpu->mem, addr + i, &ch, sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); strbuf[i] = '\0'; if (ch >= 1 && ch < 32) ch = 0; strbuf[i] = ch; if (strbuf[i] == '\0') break; } strbuf[bufsize - 1] = '\0'; } /* * of_store_32bit_in_host(): * * Store big-endian. OpenFirmware properties returned by getprop etc are * always big-endian, even on little-endian machines. */ static void of_store_32bit_in_host(unsigned char *d, uint32_t x) { d[0] = x >> 24; d[1] = x >> 16; d[2] = x >> 8; d[3] = x; } /* * find_device_handle(): * * name may consist of multiple names, separated with slashes. */ static int find_device_handle(struct of_data *ofd, const char *name) { int handle = 1, cur_parent = 1; if (name[0] == 0) return 0; for (;;) { struct of_device *od = ofd->of_devices; char tmp[200]; int i; while (name[0] == '/') name++; if (name[0] == '\0') break; snprintf(tmp, sizeof(tmp), "%s", name); i = 0; while (tmp[i] != '\0' && tmp[i] != '/') i++; tmp[i] = '\0'; OF_FIND(od, strcmp(od->name, tmp) == 0 && od->parent == cur_parent); if (od == NULL) return -1; handle = cur_parent = od->handle; name += strlen(tmp); } return handle; } /*****************************************************************************/ OF_SERVICE(call_method_2_2) { fatal("[ of: call_method_2_2('%s'): TODO ]\n", arg[0]); return -1; } OF_SERVICE(call_method_3_4) { fatal("[ of: call_method_3_4('%s'): TODO ]\n", arg[0]); return -1; } OF_SERVICE(call_method_5_2) { if (strcmp(arg[0], "set-colors") == 0) { /* Used by OpenBSD/macppc: */ struct vfb_data *v = cpu->machine->md.of_data->vfb_data; int color = OF_GET_ARG(3); uint64_t ptr = OF_GET_ARG(4); unsigned char rgb[3]; cpu->memory_rw(cpu, cpu->mem, ptr, rgb, 3, MEM_READ, CACHE_DATA | NO_EXCEPTIONS); if (v != NULL) { memcpy(v->rgb_palette + 3 * color, rgb, 3); v->update_x1 = v->update_y1 = 0; v->update_x2 = v->xsize - 1; v->update_y2 = v->ysize - 1; } } else { fatal("[ of: call_method_5_2('%s'): TODO ]\n", arg[0]); return -1; } return 0; } OF_SERVICE(call_method_6_1) { fatal("[ of: call_method_6_1('%s'): TODO ]\n", arg[0]); return -1; } OF_SERVICE(call_method_6_2) { fatal("[ of: call_method_6_2('%s'): TODO ]\n", arg[0]); return -1; } OF_SERVICE(child) { struct of_device *od = cpu->machine->md.of_data->of_devices; int handle = OF_GET_ARG(0); OF_FIND(od, od->parent == handle); store_32bit_word(cpu, base + retofs, od == NULL? 0 : od->handle); return 0; } OF_SERVICE(claim) { // Arguments: virtualaddr, size, alignment // Returns: pointer to claimed memory // TODO: This is just a dummy. fatal("[ of: claim(0x%x,0x%x,0x%x): TODO ]\n", OF_GET_ARG(0), OF_GET_ARG(1), OF_GET_ARG(2)); store_32bit_word(cpu, base + retofs, OF_GET_ARG(0)); return 0; } OF_SERVICE(exit) { cpu->running = 0; return 0; } OF_SERVICE(finddevice) { int h = find_device_handle(cpu->machine->md.of_data, arg[0]); store_32bit_word(cpu, base + retofs, h); return h>0? 0 : -1; } OF_SERVICE(getprop) { struct of_device *od = cpu->machine->md.of_data->of_devices; struct of_device_property *pr; int handle = OF_GET_ARG(0), i, len_returned = 0; uint64_t buf = OF_GET_ARG(2); uint64_t max = OF_GET_ARG(3); OF_FIND(od, od->handle == handle); if (od == NULL) { fatal("[ of: WARNING: getprop handle=%i; no such handle ]\n", handle); return -1; } pr = od->properties; OF_FIND(pr, strcmp(pr->name, arg[1]) == 0); if (pr == NULL) { fatal("[ of: WARNING: getprop: no property '%s' at handle" " %i (device '%s') ]\n", arg[1], handle, od->name); return -1; } if (pr->data == NULL) { fatal("[ of: WARNING: property '%s' of '%s' has no data! ]\n", arg[1], od->name); goto ret; } /* Return the property into emulated RAM: */ len_returned = pr->len <= max? pr->len : max; for (i=0; imemory_rw(cpu, cpu->mem, buf + i, pr->data + i, 1, MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS)) { fatal("[ of: getprop memory_rw() error ]\n"); exit(1); } } ret: store_32bit_word(cpu, base + retofs, len_returned); return 0; } OF_SERVICE(getproplen) { struct of_device *od = cpu->machine->md.of_data->of_devices; struct of_device_property *pr; int handle = OF_GET_ARG(0); OF_FIND(od, od->handle == handle); if (od == NULL) { fatal("[ of: TODO: getproplen handle=%i; no such handle ]\n", handle); return -1; } pr = od->properties; OF_FIND(pr, strcmp(pr->name, arg[1]) == 0); if (pr == NULL) { fatal("[ of: TODO: getproplen: no property '%s' at handle" " %i (device '%s') ]\n", arg[1], handle, od->name); return -1; } store_32bit_word(cpu, base + retofs, pr->len); return 0; } OF_SERVICE(instance_to_package) { int handle = OF_GET_ARG(0); /* TODO: actually do something here? :-) */ store_32bit_word(cpu, base + retofs, handle); return 0; } OF_SERVICE(interpret_1) { if (strcmp(arg[0], "#lines 2 - to line#") == 0) { } else { fatal("[ of: interpret_1('%s'): TODO ]\n", arg[0]); return -1; } return 0; } OF_SERVICE(interpret_2) { store_32bit_word(cpu, base + retofs, 0); /* ? TODO */ if (strcmp(arg[0], "#columns") == 0) { store_32bit_word(cpu, base + retofs + 4, 80); } else if (strcmp(arg[0], "#lines") == 0) { store_32bit_word(cpu, base + retofs + 4, 40); } else if (strcmp(arg[0], "char-height") == 0) { store_32bit_word(cpu, base + retofs + 4, 15); } else if (strcmp(arg[0], "char-width") == 0) { store_32bit_word(cpu, base + retofs + 4, 10); } else if (strcmp(arg[0], "line#") == 0) { store_32bit_word(cpu, base + retofs + 4, 0); } else if (strcmp(arg[0], "font-adr") == 0) { store_32bit_word(cpu, base + retofs + 4, 0); } else { fatal("[ of: interpret_2('%s'): TODO ]\n", arg[0]); return -1; } return 0; } OF_SERVICE(package_to_path) { fatal("[ of: package-to-path: TODO ]\n"); return -1; } OF_SERVICE(parent) { struct of_device *od = cpu->machine->md.of_data->of_devices; int handle = OF_GET_ARG(0); OF_FIND(od, od->handle == handle); store_32bit_word(cpu, base + retofs, od == NULL? 0 : od->parent); return 0; } OF_SERVICE(peer) { struct of_device *od = cpu->machine->md.of_data->of_devices; int handle = OF_GET_ARG(0), parent = 0, peer = 0, seen_self = 1; if (handle == 0) { /* Return the handle of the root node (1): */ store_32bit_word(cpu, base + retofs, 1); return 0; } OF_FIND(od, od->handle == handle); if (od == NULL) { fatal("[ of: TODO: peer(): can't find handle %i ]\n", handle); exit(1); } parent = od->parent; seen_self = 0; od = cpu->machine->md.of_data->of_devices; while (od != NULL) { if (od->parent == parent) { if (seen_self) { peer = od->handle; break; } if (od->handle == handle) seen_self = 1; } od = od->next; } store_32bit_word(cpu, base + retofs, peer); return 0; } OF_SERVICE(open) { // TODO. uint64_t ptr = OF_GET_ARG(0); string s; int i = 0; while (true) { unsigned char ch; if (!cpu->memory_rw(cpu, cpu->mem, ptr + i, &ch, 1, MEM_READ, CACHE_DATA | NO_EXCEPTIONS)) { fatal("[ of: TODO: write: memory_rw() error ]\n"); exit(1); } if (ch == 0) break; s += ch; ++ i; } if (s != "") { cout << "Unimplemented OF_SERVICE(open) with name: '" << s << "'\n"; exit(1); } return 0; } OF_SERVICE(read) { /* int handle = OF_GET_ARG(0); */ uint64_t ptr = OF_GET_ARG(1); /* int len = OF_GET_ARG(2); */ int c; unsigned char ch; /* TODO: check handle! This just reads chars from the console! */ /* TODO: This is blocking! */ c = console_readchar(cpu->machine->main_console_handle); ch = c; if (!cpu->memory_rw(cpu, cpu->mem, ptr, &ch, 1, MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS)) { fatal("[ of: TODO: read: memory_rw() error ]\n"); exit(1); } store_32bit_word(cpu, base + retofs, c == -1? 0 : 1); return c == -1? -1 : 0; } OF_SERVICE(write) { /* int handle = OF_GET_ARG(0); */ uint64_t ptr = OF_GET_ARG(1); int n_written = 0, i, len = OF_GET_ARG(2); /* TODO: check handle! This just dumps the data to the console! */ for (i=0; imemory_rw(cpu, cpu->mem, ptr + i, &ch, 1, MEM_READ, CACHE_DATA | NO_EXCEPTIONS)) { fatal("[ of: TODO: write: memory_rw() error ]\n"); exit(1); } if (ch != 7) console_putchar(cpu->machine->main_console_handle, ch); n_written ++; } store_32bit_word(cpu, base + retofs, n_written); return 0; } /*****************************************************************************/ /* * of_get_unused_device_handle(): * * Returns an unused device handle number (1 or higher). */ static int of_get_unused_device_handle(struct of_data *of_data) { int max_handle = 0; struct of_device *od = of_data->of_devices; while (od != NULL) { if (od->handle > max_handle) max_handle = od->handle; od = od->next; } return max_handle + 1; } /* * of_add_device(): * * Adds a device. */ static struct of_device *of_add_device(struct of_data *of_data, const char *name, const char *parentname) { struct of_device *od; CHECK_ALLOCATION(od = (struct of_device *) malloc(sizeof(struct of_device))); memset(od, 0, sizeof(struct of_device)); CHECK_ALLOCATION(od->name = strdup(name)); od->handle = of_get_unused_device_handle(of_data); od->parent = find_device_handle(of_data, parentname); if (od->parent < 0) { fatal("of_add_device(): adding '%s' to parent '%s' failed: " "parent not found!\n", name, parentname); exit(1); } od->next = of_data->of_devices; of_data->of_devices = od; return od; } /* * of_add_prop(): * * Adds a property to a device. */ static void of_add_prop(struct of_data *of_data, const char *devname, const char *propname, unsigned char *data, uint32_t len, int flags) { struct of_device_property *pr; struct of_device *od = of_data->of_devices; int h = find_device_handle(of_data, devname); CHECK_ALLOCATION(pr = (struct of_device_property *) malloc(sizeof(struct of_device_property))); memset(pr, 0, sizeof(struct of_device_property)); OF_FIND(od, od->handle == h); if (od == NULL) { fatal("of_add_prop(): device '%s' not registered\n", devname); exit(1); } CHECK_ALLOCATION(pr->name = strdup(propname)); pr->data = data; pr->len = len; pr->flags = flags; pr->next = od->properties; od->properties = pr; } /* * of_add_service(): * * Adds a service. */ static void of_add_service(struct of_data *of_data, const char *name, int (*f)(OF_SERVICE_ARGS), int n_args, int n_ret_args) { struct of_service *os; CHECK_ALLOCATION(os = (struct of_service *) malloc(sizeof(struct of_service))); memset(os, 0, sizeof(struct of_service)); CHECK_ALLOCATION(os->name = strdup(name)); os->f = f; os->n_args = n_args; os->n_ret_args = n_ret_args; os->next = of_data->of_services; of_data->of_services = os; } /* * of_dump_devices(): * * Debug dump helper. */ static void of_dump_devices(struct of_data *ofd, int parent) { int iadd = DEBUG_INDENTATION; struct of_device *od = ofd->of_devices; while (od != NULL) { struct of_device_property *pr = od->properties; if (od->parent != parent) { od = od->next; continue; } debug("\"%s\"", od->name); debug(" (handle %i)\n", od->handle); debug_indentation(iadd); while (pr != NULL) { debug("(%s: ", pr->name); if (pr->flags == OF_PROP_STRING) debug("\"%s\"", pr->data); else debug("%i bytes", pr->len); debug(")\n"); pr = pr->next; } of_dump_devices(ofd, od->handle); debug_indentation(-iadd); od = od->next; } } /* * of_dump_all(): * * Debug dump. */ static void of_dump_all(struct of_data *ofd) { int iadd = DEBUG_INDENTATION; struct of_service *os; debug("openfirmware debug dump:\n"); debug_indentation(iadd); /* Devices: */ of_dump_devices(ofd, 0); /* Services: */ os = ofd->of_services; while (os != NULL) { debug("service '%s'", os->name); if (os->n_ret_args > 0 || os->n_args > 0) { debug(" ("); if (os->n_args > 0) { debug("%i arg%s", os->n_args, os->n_args > 1? "s" : ""); if (os->n_ret_args > 0) debug(", "); } if (os->n_ret_args > 0) debug("%i return value%s", os->n_ret_args, os->n_ret_args > 1? "s" : ""); debug(")"); } debug("\n"); os = os->next; } debug_indentation(-iadd); } /* * of_add_prop_int32(): * * Helper function. */ static void of_add_prop_int32(struct of_data *ofd, const char *devname, const char *propname, uint32_t x) { unsigned char *p; CHECK_ALLOCATION(p = (unsigned char *) malloc(sizeof(int32_t))); of_store_32bit_in_host(p, x); of_add_prop(ofd, devname, propname, p, sizeof(int32_t), OF_PROP_INT); } /* * of_add_prop_str(): * * Helper function. */ static void of_add_prop_str(struct machine *machine, struct of_data *ofd, const char *devname, const char *propname, const char *data) { char *p; CHECK_ALLOCATION(p = strdup(data)); of_add_prop(ofd, devname, propname, (unsigned char *)p, strlen(p) + 1, OF_PROP_STRING); } /* * of_emul_init_isa(): */ void of_emul_init_isa(struct machine *machine) { struct of_data *ofd = machine->md.of_data; unsigned char *isa_ranges; of_add_device(ofd, "isa", "/"); CHECK_ALLOCATION(isa_ranges = (unsigned char *) malloc(32)); memset(isa_ranges, 0, 32); /* 2 *: isa_phys_hi, isa_phys_lo, parent_phys_start, size */ /* MEM space: */ of_store_32bit_in_host(isa_ranges + 0, 0); of_store_32bit_in_host(isa_ranges + 4, 0xc0000000); /* I/O space: low bit if isa_phys_hi set */ of_store_32bit_in_host(isa_ranges + 16, 1); of_store_32bit_in_host(isa_ranges + 20, 0xd0000000); of_add_prop(ofd, "/isa", "ranges", isa_ranges, 32, 0); } /* * of_emul_init_adb(): */ void of_emul_init_adb(struct machine *machine) { struct of_data *ofd = machine->md.of_data; unsigned char *adb_interrupts, *adb_reg; CHECK_ALLOCATION(adb_interrupts = (unsigned char *) malloc(4 * sizeof(uint32_t))); CHECK_ALLOCATION(adb_reg = (unsigned char *) malloc(8 * sizeof(uint32_t))); of_add_device(ofd, "adb", "/bandit/gc"); of_add_prop_str(machine, ofd, "/bandit/gc/adb", "name", "via-cuda"); of_store_32bit_in_host(adb_interrupts + 0, 25); of_store_32bit_in_host(adb_interrupts + 4, 0); of_store_32bit_in_host(adb_interrupts + 8, 0); of_store_32bit_in_host(adb_interrupts + 12, 0); of_add_prop(ofd, "/bandit/gc/adb", "interrupts", adb_interrupts, 4*sizeof(uint32_t), 0); of_store_32bit_in_host(adb_reg + 0, 0x16000); of_store_32bit_in_host(adb_reg + 4, 0x2000); of_store_32bit_in_host(adb_reg + 8, 0); of_store_32bit_in_host(adb_reg + 12, 0); of_store_32bit_in_host(adb_reg + 16, 0); of_store_32bit_in_host(adb_reg + 20, 0); of_store_32bit_in_host(adb_reg + 24, 0); of_store_32bit_in_host(adb_reg + 28, 0); of_add_prop(ofd, "/bandit/gc/adb", "reg", adb_reg, 8*sizeof(uint32_t), 0); } /* * of_emul_init_zs(): */ void of_emul_init_zs(struct machine *machine) { struct of_data *ofd = machine->md.of_data; unsigned char *zs_interrupts, *zs_reg; CHECK_ALLOCATION(zs_reg = (unsigned char *) malloc(6 * sizeof(uint32_t))); /* The controller: */ of_add_device(ofd, "zs", "/bandit/gc"); of_add_prop_str(machine, ofd, "/bandit/gc/zs", "device_type", "serial"); of_add_prop_str(machine, ofd, "/bandit/gc/zs", "name", "escc"); of_store_32bit_in_host(zs_reg + 0, 0x13000); of_store_32bit_in_host(zs_reg + 4, 0x40); of_store_32bit_in_host(zs_reg + 8, 0x100); of_store_32bit_in_host(zs_reg + 12, 0x100); of_store_32bit_in_host(zs_reg + 16, 0x200); of_store_32bit_in_host(zs_reg + 20, 0x100); of_add_prop(ofd, "/bandit/gc/zs", "reg", zs_reg, 6*sizeof(uint32_t), 0); /* Port 1: */ CHECK_ALLOCATION(zs_interrupts = (unsigned char *) malloc(3 * sizeof(uint32_t))); CHECK_ALLOCATION(zs_reg = (unsigned char *) malloc(6 * sizeof(uint32_t))); of_add_device(ofd, "zstty1", "/bandit/gc/zs"); of_add_prop_str(machine, ofd, "/bandit/gc/zs/zstty1", "name", "ch-a"); of_store_32bit_in_host(zs_interrupts + 0, 16); of_store_32bit_in_host(zs_interrupts + 4, 0); of_store_32bit_in_host(zs_interrupts + 8, 0); of_add_prop(ofd, "/bandit/gc/zs/zstty1", "interrupts", zs_interrupts, 3*sizeof(uint32_t), 0); of_store_32bit_in_host(zs_reg + 0, 0x13800); of_store_32bit_in_host(zs_reg + 4, 0x100); of_store_32bit_in_host(zs_reg + 8, 0x100); of_store_32bit_in_host(zs_reg + 12, 0x100); of_store_32bit_in_host(zs_reg + 16, 0x200); of_store_32bit_in_host(zs_reg + 20, 0x100); of_add_prop(ofd, "/bandit/gc/zs/zstty1", "reg", zs_reg, 6*sizeof(uint32_t), 0); /* Port 0: */ CHECK_ALLOCATION(zs_interrupts = (unsigned char *) malloc(3 * sizeof(uint32_t))); CHECK_ALLOCATION(zs_reg = (unsigned char *) malloc(6 * sizeof(uint32_t))); of_add_device(ofd, "zstty0", "/bandit/gc/zs"); of_add_prop_str(machine, ofd, "/bandit/gc/zs/zstty0", "name", "ch-b"); of_store_32bit_in_host(zs_interrupts + 0, 15); of_store_32bit_in_host(zs_interrupts + 4, 0); of_store_32bit_in_host(zs_interrupts + 8, 0); of_add_prop(ofd, "/bandit/gc/zs/zstty0", "interrupts", zs_interrupts, 3*sizeof(uint32_t), 0); of_store_32bit_in_host(zs_reg + 0, 0x13400); of_store_32bit_in_host(zs_reg + 4, 0x100); of_store_32bit_in_host(zs_reg + 8, 0x100); of_store_32bit_in_host(zs_reg + 12, 0x100); of_store_32bit_in_host(zs_reg + 16, 0x200); of_store_32bit_in_host(zs_reg + 20, 0x100); of_add_prop(ofd, "/bandit/gc/zs/zstty0", "reg", zs_reg, 6*sizeof(uint32_t), 0); } /* * of_emul_init_uninorth(): */ void of_emul_init_uninorth(struct machine *machine) { struct of_data *ofd = machine->md.of_data; unsigned char *uninorth_reg, *uninorth_bus_range, *uninorth_ranges; unsigned char *macio_aa, *ata_interrupts, *ata_reg; struct of_device *ic; const char *n = "pci@e2000000"; const char *macio = "mac-io"; of_add_device(ofd, n, "/"); of_add_prop_str(machine, ofd, n, "name", "pci"); of_add_prop_str(machine, ofd, n, "device_type", "pci"); of_add_prop_str(machine, ofd, n, "compatible", "uni-north"); CHECK_ALLOCATION(uninorth_reg = (unsigned char *) malloc(2 * sizeof(uint32_t))); CHECK_ALLOCATION(uninorth_bus_range = (unsigned char *) malloc(2 * sizeof(uint32_t))); CHECK_ALLOCATION(uninorth_ranges = (unsigned char *) malloc(12 * sizeof(uint32_t))); CHECK_ALLOCATION(macio_aa = (unsigned char *) malloc(5 * sizeof(uint32_t))); CHECK_ALLOCATION(ata_interrupts = (unsigned char *) malloc(6 * sizeof(uint32_t))); CHECK_ALLOCATION(ata_reg = (unsigned char *) malloc(8 * sizeof(uint32_t))); of_store_32bit_in_host(uninorth_reg + 0, 0xe2000000); of_store_32bit_in_host(uninorth_reg + 4, 0); /* not used? */ of_add_prop(ofd, n, "reg", uninorth_reg, 2*sizeof(uint32_t), 0); of_store_32bit_in_host(uninorth_bus_range + 0, 0); of_store_32bit_in_host(uninorth_bus_range + 4, 0); of_add_prop(ofd, n, "bus-range", uninorth_bus_range, 2*sizeof(uint32_t), 0); /* MEM: */ of_store_32bit_in_host(uninorth_ranges + 0, 0x02000000); of_store_32bit_in_host(uninorth_ranges + 4, 0); of_store_32bit_in_host(uninorth_ranges + 8, 0); of_store_32bit_in_host(uninorth_ranges + 12, 0xd0000000); of_store_32bit_in_host(uninorth_ranges + 16, 0); of_store_32bit_in_host(uninorth_ranges + 20, 0x04000000); /* IO: */ of_store_32bit_in_host(uninorth_ranges + 24, 0x01000000); of_store_32bit_in_host(uninorth_ranges + 28, 0); of_store_32bit_in_host(uninorth_ranges + 32, 0); of_store_32bit_in_host(uninorth_ranges + 36, 0xe2000000); of_store_32bit_in_host(uninorth_ranges + 40, 0); of_store_32bit_in_host(uninorth_ranges + 44, 0x01000000); of_add_prop(ofd, n, "ranges", uninorth_ranges, 12*sizeof(uint32_t), 0); ic = of_add_device(ofd, macio, "/"); memset(macio_aa, 0, 20); of_store_32bit_in_host(macio_aa + 0, 15 << 11); /* pci tag */ of_store_32bit_in_host(macio_aa + 8, 0xf3000000); of_add_prop(ofd, macio, "assigned-addresses", macio_aa, 5*sizeof(uint32_t), 0); /* of_add_prop(ofd, n, "assigned-addresses", macio_aa, 5*sizeof(uint32_t), 0); */ of_add_prop_int32(ofd, "/chosen", "interrupt-controller", ic->handle); of_add_device(ofd, "bandit", "/"); of_add_device(ofd, "gc", "/bandit"); of_add_prop(ofd, "/bandit/gc", "assigned-addresses", macio_aa, 5*sizeof(uint32_t), 0); if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { char tmpstr[400]; of_add_device(ofd, "ata", "/bandit/gc"); of_add_prop_str(machine, ofd, "/bandit/gc/ata", "name", "ata"); of_add_prop_str(machine, ofd, "/bandit/gc/ata", "compatible", "heathrow-ata"); of_store_32bit_in_host(ata_interrupts + 0, 13); of_store_32bit_in_host(ata_interrupts + 4, 0); of_store_32bit_in_host(ata_interrupts + 8, 0); of_store_32bit_in_host(ata_interrupts + 12, 0); of_store_32bit_in_host(ata_interrupts + 16, 0); of_store_32bit_in_host(ata_interrupts + 20, 0); of_add_prop(ofd, "/bandit/gc/ata", "interrupts", ata_interrupts, 6*sizeof(uint32_t), 0); of_store_32bit_in_host(ata_reg + 0, 0x20000); of_store_32bit_in_host(ata_reg + 4, 0); of_store_32bit_in_host(ata_reg + 8, 0x21000); of_store_32bit_in_host(ata_reg + 12, 0x22000); of_store_32bit_in_host(ata_reg + 16, 0); of_store_32bit_in_host(ata_reg + 20, 0); of_store_32bit_in_host(ata_reg + 24, 0); of_store_32bit_in_host(ata_reg + 28, 0); of_add_prop(ofd, "/bandit/gc/ata", "reg", ata_reg, 8*sizeof(uint32_t), 0); snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0xf3020000 " "irq=%s.cpu[%i].gc.lo.21 addr_mult=0x10", machine->path, machine->bootstrap_cpu); device_add(machine, tmpstr); } } /* * of_emul_init(): * * This function creates an OpenFirmware emulation instance. */ struct of_data *of_emul_init(struct machine *machine, struct vfb_data *vfb_data, uint64_t fb_addr, int fb_xsize, int fb_ysize) { unsigned char *memory_reg, *memory_av; unsigned char *root_address_cells, *root_size_cells; unsigned char *zs_assigned_addresses; struct of_device *memory_dev, *mmu, *devstdout, *devstdin; struct of_data *ofd; int i; CHECK_ALLOCATION(ofd = (struct of_data *) malloc(sizeof(struct of_data))); memset(ofd, 0, sizeof(struct of_data)); ofd->vfb_data = vfb_data; /* Devices: */ /* Root = device 1 */ of_add_device(ofd, "", ""); of_add_prop_str(machine, ofd, "/", "model", "GXemul OpenFirmware machine"); CHECK_ALLOCATION(root_address_cells = (unsigned char *) malloc(1 * sizeof(uint32_t))); of_store_32bit_in_host(root_address_cells, 0); of_add_prop(ofd, "/", "#address-cells", root_address_cells, 1 * sizeof(uint32_t), 0); CHECK_ALLOCATION(root_size_cells = (unsigned char *) malloc(1 * sizeof(uint32_t))); of_store_32bit_in_host(root_size_cells, 0); of_add_prop(ofd, "/", "#size-cells", root_size_cells, 1 * sizeof(uint32_t), 0); of_add_device(ofd, "io", "/"); devstdin = of_add_device(ofd, "stdin", "/io"); devstdout = of_add_device(ofd, "stdout", "/io"); if (machine->x11_md.in_use) { fatal("!\n! TODO: keyboard + framebuffer for MacPPC\n!\n"); of_add_prop_str(machine, ofd, "/io/stdin", "name", "keyboard"); of_add_prop_str(machine, ofd, "/io", "name", "adb"); of_add_prop_str(machine, ofd, "/io/stdout", "device_type", "display"); of_add_prop_int32(ofd, "/io/stdout", "width", fb_xsize); of_add_prop_int32(ofd, "/io/stdout", "height", fb_ysize); of_add_prop_int32(ofd, "/io/stdout", "linebytes", fb_xsize * 1); of_add_prop_int32(ofd, "/io/stdout", "depth", 8); of_add_prop_int32(ofd, "/io/stdout", "address", fb_addr); } else { CHECK_ALLOCATION(zs_assigned_addresses = (unsigned char *) malloc(12)); memset(zs_assigned_addresses, 0, 12); of_add_prop_str(machine, ofd, "/io/stdin", "name", "ch-b"); of_add_prop_str(machine, ofd, "/io/stdin", "device_type", "serial"); of_add_prop_int32(ofd, "/io/stdin", "reg", 0xf3013000); of_add_prop(ofd, "/io/stdin", "assigned-addresses", zs_assigned_addresses, 12, 0); of_add_prop_str(machine, ofd, "/io/stdout", "device_type", "serial"); } of_add_device(ofd, "cpus", "/"); for (i=0; incpus; i++) { char tmp[50]; snprintf(tmp, sizeof(tmp), "@%x", i); of_add_device(ofd, tmp, "/cpus"); snprintf(tmp, sizeof(tmp), "/cpus/@%x", i); of_add_prop_str(machine, ofd, tmp, "device_type", "cpu"); of_add_prop_int32(ofd, tmp, "timebase-frequency", machine->emulated_hz / 4); of_add_prop_int32(ofd, tmp, "clock-frequency", machine->emulated_hz); of_add_prop_int32(ofd, tmp, "reg", i); } mmu = of_add_device(ofd, "mmu", "/"); /* TODO: */ of_add_prop(ofd, "/mmu", "translations", NULL, 0, 0); of_add_device(ofd, "chosen", "/"); of_add_prop_int32(ofd, "/chosen", "mmu", mmu->handle); of_add_prop_int32(ofd, "/chosen", "stdin", devstdin->handle); of_add_prop_int32(ofd, "/chosen", "stdout", devstdout->handle); memory_dev = of_add_device(ofd, "memory", "/"); CHECK_ALLOCATION(memory_reg = (unsigned char *) malloc(2 * sizeof(uint32_t))); CHECK_ALLOCATION(memory_av = (unsigned char *) malloc(2 * sizeof(uint32_t))); of_store_32bit_in_host(memory_reg + 0, 0); of_store_32bit_in_host(memory_reg + 4, machine->physical_ram_in_mb<<20); of_store_32bit_in_host(memory_av + 0, 10 << 20); of_store_32bit_in_host(memory_av + 4, (machine->physical_ram_in_mb - 10) << 20); of_add_prop(ofd, "/memory", "reg", memory_reg, 2 * sizeof(uint32_t), 0); of_add_prop(ofd, "/memory", "available", memory_av, 2*sizeof(uint32_t),0); of_add_prop_str(machine, ofd, "/memory", "name", "memory"); of_add_prop_str(machine, ofd, "/memory","device_type","memory"/*?*/); of_add_prop_int32(ofd, "/chosen", "memory", memory_dev->handle); /* Services: */ of_add_service(ofd, "call-method", of__call_method_2_2, 2, 2); of_add_service(ofd, "call-method", of__call_method_3_4, 3, 4); of_add_service(ofd, "call-method", of__call_method_5_2, 5, 2); of_add_service(ofd, "call-method", of__call_method_6_1, 6, 1); of_add_service(ofd, "call-method", of__call_method_6_2, 6, 2); of_add_service(ofd, "child", of__child, 1, 1); of_add_service(ofd, "claim", of__claim, 3, 1); of_add_service(ofd, "exit", of__exit, 0, 0); of_add_service(ofd, "finddevice", of__finddevice, 1, 1); of_add_service(ofd, "getprop", of__getprop, 4, 1); of_add_service(ofd, "getproplen", of__getproplen, 2, 1); of_add_service(ofd, "instance-to-package", of__instance_to_package, 1, 1); of_add_service(ofd, "interpret", of__interpret_1, 1, 1); of_add_service(ofd, "interpret", of__interpret_2, 1, 2); of_add_service(ofd, "package-to-path", of__package_to_path, 3, 1); of_add_service(ofd, "parent", of__parent, 1, 1); of_add_service(ofd, "peer", of__peer, 1, 1); of_add_service(ofd, "open", of__open, 1, 1); of_add_service(ofd, "read", of__read, 3, 1); of_add_service(ofd, "write", of__write, 3, 1); if (verbose >= 2) of_dump_all(ofd); machine->md.of_data = ofd; return ofd; } /* * of_emul(): * * OpenFirmware call emulation. */ int of_emul(struct cpu *cpu) { int i, nargs, nret, ofs, retval = 0; char service[50]; char *arg[OF_N_MAX_ARGS]; uint64_t base, ptr; struct of_service *os; struct of_data *of_data = cpu->machine->md.of_data; if (of_data == NULL) { fatal("of_emul(): no of_data struct?\n"); exit(1); } /* * The first argument register points to "prom_args": * * char *service; (probably 32 bit) * int nargs; * int nret; * char *args[10]; */ switch (cpu->machine->arch) { case ARCH_ARM: base = cpu->cd.arm.r[0]; break; case ARCH_PPC: base = cpu->cd.ppc.gpr[3]; break; default:fatal("of_emul(): unimplemented arch (TODO)\n"); exit(1); } /* TODO: how about 64-bit OpenFirmware? */ ptr = load_32bit_word(cpu, base); nargs = load_32bit_word(cpu, base + 4); nret = load_32bit_word(cpu, base + 8); readstr(cpu, ptr, service, sizeof(service)); debug("[ of: %s(", service); ofs = 12; for (i=0; i 0) debug(", "); if (i >= OF_N_MAX_ARGS) { fatal("TOO MANY ARGS!"); continue; } ptr = load_32bit_word(cpu, base + ofs); CHECK_ALLOCATION(arg[i] = (char *) malloc(OF_ARG_MAX_LEN + 1)); memset(arg[i], 0, OF_ARG_MAX_LEN + 1); x = ptr; if (x > -256 && x < 256) { debug("%i", x); } else { readstr(cpu, ptr, arg[i], OF_ARG_MAX_LEN); if (arg[i][0]) debug("\"%s\"", arg[i]); else debug("0x%x", x); } ofs += sizeof(uint32_t); } debug(") ]\n"); /* Note: base + ofs points to the first return slot. */ os = of_data->of_services; while (os != NULL) { if (strcmp(service, os->name) == 0 && nargs == os->n_args && nret == os->n_ret_args) { retval = os->f(cpu, arg, base, ofs); break; } os = os->next; } if (os == NULL) { quiet_mode = 0; cpu_register_dump(cpu->machine, cpu, 1, 0); printf("\n"); fatal("[ of: unimplemented service \"%s\" with %i input " "args and %i output values ]\n", service, nargs, nret); cpu->running = 0; exit(1); } for (i=0; imachine->arch) { case ARCH_ARM: cpu->cd.arm.r[0] = retval; break; case ARCH_PPC: cpu->cd.ppc.gpr[3] = retval; break; default:fatal("of_emul(): TODO: unimplemented arch (Retval)\n"); exit(1); } return 1; } gxemul-0.6.1/src/promemul/ps2_bios.cc000644 001750 001750 00000016400 13402411502 017704 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Playstation 2 SIFBIOS emulation */ #include #include #include #include #include #include #include "console.h" #include "cpu.h" #include "cpu_mips.h" #include "machine.h" #include "memory.h" extern int quiet_mode; /* * playstation2_sifbios_emul(): */ int playstation2_sifbios_emul(struct cpu *cpu) { int callnr; callnr = cpu->cd.mips.gpr[MIPS_GPR_A0]; switch (callnr) { case 0: /* getver() */ cpu->cd.mips.gpr[MIPS_GPR_V0] = 0x200; /* TODO */ break; case 1: /* halt(int mode) */ debug("[ SIFBIOS halt(0x%" PRIx64") ]\n", (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1]); cpu->running = 0; break; case 2: /* setdve(int mode) */ debug("[ SIFBIOS setdve(0x%" PRIx64") ]\n", (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1]); break; case 3: /* putchar(int ch) */ /* debug("[ SIFBIOS putchar(0x%x) ]\n", (char)cpu->cd.mips.gpr[MIPS_GPR_A1]); */ console_putchar(cpu->machine->main_console_handle, cpu->cd.mips.gpr[MIPS_GPR_A1]); break; case 4: /* getchar() */ /* This is untested. TODO */ /* debug("[ SIFBIOS getchar() ]\n"; */ cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; if (console_charavail(cpu->machine->main_console_handle)) cpu->cd.mips.gpr[MIPS_GPR_V0] = console_readchar( cpu->machine->main_console_handle); break; case 16: /* dma_init() */ debug("[ SIFBIOS dma_init() ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ break; case 17: /* dma_exit() */ debug("[ SIFBIOS dma_exit() ]\n"); break; case 32: /* cmd_init() */ debug("[ SIFBIOS cmd_init() ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ break; case 33: /* cmd_exit() */ debug("[ SIFBIOS cmd_exit() ]\n"); break; case 48: debug("[ SIFBIOS rpc_init(): TODO ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ break; case 49: debug("[ SIFBIOS rpc_exit(): TODO ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ break; case 51: debug("[ SIFBIOS rpc_bind(): TODO ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; /* TODO */ break; case 64: fatal("[ SIFBIOS SBR_IOPH_INIT(0x%" PRIx32",0x%" PRIx32",0x%" PRIx32"): TODO ]\n", (uint32_t) cpu->cd.mips.gpr[MIPS_GPR_A1], (uint32_t) cpu->cd.mips.gpr[MIPS_GPR_A2], (uint32_t) cpu->cd.mips.gpr[MIPS_GPR_A3]); /* * This is really really ugly: TODO * * Linux and NetBSD seem to work, but it's an ugly hack. * This should really be a callback thingy... * * NetBSD has a done-word which should be set to 1. * Linux has one done-word which should be set to 1, and * one which should be set to 0. * * The code as it is right now probably overwrites stuff in * memory that shouldn't be touched. Not good. * * Linux: err = sbios_rpc(SBR_IOPH_INIT, NULL, &result); * err should be 0 (just as NetBSD), * and result should be set to 0 as well. */ { uint32_t tmpaddr; tmpaddr = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1] + 0); fatal(" +0: %08x\n", tmpaddr); tmpaddr = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1] + 4); fatal(" +4: %08x\n", tmpaddr); tmpaddr = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1] + 8); fatal(" +8: %08x\n", tmpaddr); tmpaddr = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1] + 12); fatal(" +12: %08x\n", tmpaddr); /* TODO: This is probably netbsd specific */ tmpaddr = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1] + 12); fatal("tmpaddr 1 = 0x%08x\n", tmpaddr); /* "done" word for NetBSD: */ store_32bit_word(cpu, tmpaddr, 1); /* "done" word A for Linux: */ store_32bit_word(cpu, tmpaddr + 4, 1); /* "done" word B for Linux: */ store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1] + 0, 0); } cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 65: fatal("[ SIFBIOS alloc iop heap(0x" PRIx32") ]\n", (uint32_t)cpu->cd.mips.gpr[MIPS_GPR_A1]); /* * Linux uses this to allocate "heap" for the OHCI USB * controller. * * TODO: This nave implementation does not allow for a * "free iop heap" function: :-/ */ { uint32_t tmpaddr; static uint32_t return_addr = 0x1000; /* 0xbc000000; */ uint32_t size; tmpaddr = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1] + 0); fatal(" +0: %08x (result should be placed here)\n", tmpaddr); tmpaddr = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1] + 4); fatal(" +4: %08x (*arg)\n", tmpaddr); size = load_32bit_word(cpu, tmpaddr + 0); fatal(" size = %08x\n", size); tmpaddr = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1] + 8); fatal(" +8: %08x (*func (void *, int))\n", tmpaddr); tmpaddr = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1] + 12); fatal(" +12: %08x (*para)\n", tmpaddr); /* TODO: This is probably netbsd specific */ tmpaddr = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1] + 12); fatal("tmpaddr 1 = 0x%08x\n", tmpaddr); /* "done" word for NetBSD: */ store_32bit_word(cpu, tmpaddr, 1); /* "done" word A for Linux: */ store_32bit_word(cpu, tmpaddr + 4, 1); /* Result: */ store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1] + 0, return_addr); return_addr += size; /* Round up to next page: */ return_addr += 4095; return_addr &= ~4095; } cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 66: debug("[ SIFBIOS iopmem_free(): TODO ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ break; default: quiet_mode = 0; cpu_register_dump(cpu->machine, cpu, 1, 0x1); printf("\n"); fatal("Playstation 2 SIFBIOS emulation: " "unimplemented call nr 0x%x\n", callnr); cpu->running = 0; } return 1; } gxemul-0.6.1/src/promemul/yamon.cc000644 001750 001750 00000014771 13402411502 017320 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: YAMON emulation * * (Very basic, only what is needed to get NetBSD booting.) */ #include #include #include #include #include "console.h" #include "cpu.h" #include "cpu_mips.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "net.h" #include "thirdparty/yamon.h" /* * yamon_machine_setup(): */ void yamon_machine_setup(struct machine *machine, uint64_t env) { char tmps[200]; char macaddr[6]; uint64_t tmpptr = env + 0x400; struct cpu *cpu = machine->cpus[0]; /* * Standard YAMON environment variables: * * baseboardserial * bootfile TODO * bootprot TODO: Non-tftp boot * bootserport * bootserver * cpuconfig TODO * ethaddr * fpu TODO * gateway * ipaddr TODO: Don't hardcode! * memsize * modetty0 * modetty1 * prompt * start TODO * startdelay TODO * subnetmask TODO: Real subnet mask * yamonrev */ add_environment_string_dual(cpu, &env, &tmpptr, "baseboardserial", "0000000000"); /* TODO: Disk boot! */ add_environment_string_dual(cpu, &env, &tmpptr, "bootprot", "tftp"); add_environment_string_dual(cpu, &env, &tmpptr, "bootserport", "tty0"); add_environment_string_dual(cpu, &env, &tmpptr, "bootserver", "10.0.0.254"); net_generate_unique_mac(machine, (unsigned char *) macaddr); snprintf(tmps, sizeof(tmps), "%02x.%02x.%02x.%02x.%02x.%02x", macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]); add_environment_string_dual(cpu, &env, &tmpptr, "ethaddr", tmps); add_environment_string_dual(cpu, &env, &tmpptr, "gateway", "10.0.0.254"); /* TODO: Don't hardcode! */ add_environment_string_dual(cpu, &env, &tmpptr, "ipaddr", "10.0.0.1"); snprintf(tmps, sizeof(tmps), "0x%08x", machine->physical_ram_in_mb<<20); add_environment_string_dual(cpu, &env, &tmpptr, "memsize", tmps); add_environment_string_dual(cpu, &env, &tmpptr, "modetty0", "38400,n,8,1,none"); add_environment_string_dual(cpu, &env, &tmpptr, "modetty1", "38400,n,8,1,none"); add_environment_string_dual(cpu, &env, &tmpptr, "prompt", "YAMON"); add_environment_string_dual(cpu, &env, &tmpptr, "yamonrev", "02.06"); /* TODO: Real subnet mask: */ add_environment_string_dual(cpu, &env, &tmpptr, "subnetmask", "255.0.0.0"); /* FreeBSD development specific: */ snprintf(tmps, sizeof(tmps), "%i", machine->emulated_hz / 1000); add_environment_string_dual(cpu, &env, &tmpptr, "khz", tmps); /* NULL terminate: */ tmpptr = 0; add_environment_string_dual(cpu, &env, &tmpptr, NULL, NULL); } /* * yamon_emul(): * * YAMON emulation (for evbmips). */ int yamon_emul(struct cpu *cpu) { uint32_t ofs = (cpu->pc & 0xff) + YAMON_FUNCTION_BASE; uint8_t ch; int n; uint32_t oid; uint64_t paddr, psize; switch (ofs) { case YAMON_PRINT_COUNT_OFS: /* * print count: * a1 = string * a2 = count */ n = 0; while (n < (int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2]) { cpu->memory_rw(cpu, cpu->mem, (int32_t)cpu->cd.mips.gpr [MIPS_GPR_A1] + n, &ch, sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); console_putchar(cpu->machine->main_console_handle, ch); n++; } break; case YAMON_EXIT_OFS: /* * exit */ debug("[ yamon_emul(): exit ]\n"); cpu->running = 0; break; /* YAMON_FLUSH_CACHE_OFS: TODO */ /* YAMON_PRINT_OFS: TODO */ /* YAMON_REG_CPU_ISR_OFS: TODO */ /* YAMON_DEREG_CPU_ISR_OFS: TODO */ /* YAMON_REG_IC_ISR_OFS: TODO */ /* YAMON_DEREG_IC_ISR_OFS: TODO */ /* YAMON_REG_ESR_OFS: TODO */ /* YAMON_DEREG_ESR_OFS: TODO */ case YAMON_GETCHAR_OFS: n = console_readchar(cpu->machine->main_console_handle); /* Note: -1 (if no char was available) becomes 0xff: */ ch = n; cpu->memory_rw(cpu, cpu->mem, (int32_t)cpu->cd.mips.gpr[ MIPS_GPR_A1], &ch, sizeof(ch), MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS); break; case YAMON_SYSCON_READ_OFS: /* * syscon_read(oid [a0], addr [a1], size [a2]) */ oid = cpu->cd.mips.gpr[MIPS_GPR_A0]; paddr = cpu->cd.mips.gpr[MIPS_GPR_A1]; psize = cpu->cd.mips.gpr[MIPS_GPR_A2]; switch (oid) { case SYSCON_BOARD_CPU_CLOCK_FREQ_ID: if (psize == sizeof(uint32_t)) { uint32_t freq = cpu->machine->emulated_hz; debug("[ yamon_emul(): reporting CPU " "frequency of %u ]\n", (unsigned int) freq); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) freq = LE32_TO_HOST(freq); else freq = BE32_TO_HOST(freq); cpu->memory_rw(cpu, cpu->mem, (int32_t)paddr, (unsigned char *) (void *) &freq, sizeof(freq), MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; } else { cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; } break; default: fatal("[ yamon_emul(): unimplemented object id 0x%" PRIx32" ]\n", oid); cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; } break; default: cpu_register_dump(cpu->machine, cpu, 1, 0); printf("\n"); fatal("[ yamon_emul(): unimplemented yamon function 0x%" PRIx32" ]\n", ofs); cpu->running = 0; } return 1; } gxemul-0.6.1/src/promemul/dec_prom.cc000644 001750 001750 00000046022 13402411502 017757 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: DECstation PROM emulation * * Implementation note: Remember that only the lowest 32 bits of GPRs are * actually valid when using dyntrans with e.g. R3000 CPUs. */ #include #include #include #include #include #include #include "console.h" #include "cpu.h" #include "cpu_mips.h" #include "diskimage.h" #include "machine.h" #include "machine_pmax.h" #include "memory.h" #include "misc.h" #include "thirdparty/dec_prom.h" #include "thirdparty/dec_5100.h" #include "thirdparty/dec_kn01.h" #include "thirdparty/dec_kn02.h" #include "thirdparty/dec_kn03.h" extern int quiet_mode; /* * mem_readchar(): * * Reads a byte from emulated RAM, using a MIPS register as a base address. * (Helper function.) */ static unsigned char mem_readchar(struct cpu *cpu, int regbase, int offset) { unsigned char ch; cpu->memory_rw(cpu, cpu->mem, (int32_t)cpu->cd.mips.gpr[regbase] + offset, &ch, sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); return ch; } /* * dec_jumptable_func(): * * The jumptable is located at the beginning of the PROM, at 0xbfc00000 + i*8, * where i is the decimal function number. Many of these can be converted to * an identical callback function. * * Return value is non-zero if the vector number was converted into a callback * function number, otherwise 0. * * Vector (dec) Function * 0x0 0 reset() * 0x10 2 restart() * 0x18 3 reinit() * 0x30 6 open() * 0x38 7 read() * 0x58 11 lseek() * 0x68 13 putchar() * 0x88 17 printf() * 0x108 33 getenv2() */ int dec_jumptable_func(struct cpu *cpu, int vector) { int i; static int file_opened = 0; static int current_file_offset = 0; switch (vector) { case 0x0: /* reset() */ /* TODO */ cpu->machine->exit_without_entering_debugger = 1; cpu->running = 0; break; case 0x10: /* restart() */ /* TODO */ cpu->machine->exit_without_entering_debugger = 1; cpu->running = 0; break; case 0x18: /* reinit() */ /* TODO */ cpu->machine->exit_without_entering_debugger = 1; cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 0x30: /* open() */ /* * TODO: This is just a hack to allow Sprite/pmax' bootblock * code to load /vmsprite. The filename argument (in A0) * is ignored, and a file handle value of 1 is returned. */ if (file_opened) { fatal("\ndec_jumptable_func(): opening more than one " "file isn't supported yet.\n"); cpu->running = 0; } file_opened = 1; cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; break; case 0x38: /* read(handle, ptr, length) */ cpu->cd.mips.gpr[MIPS_GPR_V0] = (uint64_t) -1; if ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2] > 0) { int disk_id = diskimage_bootdev(cpu->machine, NULL); int res; unsigned char *tmp_buf; CHECK_ALLOCATION(tmp_buf = (unsigned char *) malloc(cpu->cd.mips.gpr[MIPS_GPR_A2])); res = diskimage_access(cpu->machine, disk_id, DISKIMAGE_SCSI, 0, current_file_offset, tmp_buf, cpu->cd.mips.gpr[MIPS_GPR_A2]); /* If the transfer was successful, transfer the data to emulated memory: */ if (res) { uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1]; store_buf(cpu, dst, (char *)tmp_buf, cpu->cd.mips.gpr[MIPS_GPR_A2]); cpu->cd.mips.gpr[MIPS_GPR_V0] = cpu->cd.mips.gpr[MIPS_GPR_A2]; current_file_offset += cpu->cd.mips.gpr[MIPS_GPR_A2]; } free(tmp_buf); } break; case 0x58: /* lseek(handle, offset[, whence]) */ /* TODO */ if (cpu->cd.mips.gpr[MIPS_GPR_A2] == 0) current_file_offset = cpu->cd.mips.gpr[MIPS_GPR_A1]; else fatal("WARNING! Unimplemented whence in " "dec_jumptable_func()\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 0x68: /* putchar() */ console_putchar(cpu->machine->main_console_handle, cpu->cd.mips.gpr[MIPS_GPR_A0]); break; case 0x88: /* printf() */ return 0x30; case 0x108: /* getenv2() */ return 0x64; default: cpu_register_dump(cpu->machine, cpu, 1, 0x1); printf("a0 points to: "); for (i=0; i<40; i++) { unsigned char ch = '\0'; cpu->memory_rw(cpu, cpu->mem, (int32_t)cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &ch, sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); if (ch >= ' ' && ch < 126) printf("%c", ch); else printf("[%02x]", ch); } printf("\n"); fatal("PROM emulation: unimplemented JUMP TABLE vector " "0x%x (decimal function %i)\n", vector, vector/8); cpu->running = 0; } return 0; } /* * decstation_prom_emul(): * * DECstation PROM emulation. * * Callback functions: * 0x0c strcmp() * 0x14 strlen() * 0x24 getchar() * 0x28 gets() * 0x2c puts() * 0x30 printf() * 0x38 iopoll() * 0x54 bootinit() * 0x58 bootread() * 0x64 getenv() * 0x6c slot_address() * 0x70 wbflush() * 0x7c clear_cache() * 0x80 getsysid() * 0x84 getbitmap() * 0x88 disableintr() * 0x8c enableintr() * 0x9c halt() * 0xa4 gettcinfo() * 0xa8 execute_cmd() * 0xac rex() */ int decstation_prom_emul(struct cpu *cpu) { int i, j, ch, argreg, argdata; int vector = cpu->pc & 0xfff; int callback = (cpu->pc & 0xf000)? 1 : 0; unsigned char buf[100]; unsigned char ch1, ch2, ch3; uint64_t tmpaddr, slot_base = 0x10000000, slot_size = 0; if (!callback) { vector = dec_jumptable_func(cpu, vector); if (vector == 0) return 1; } else { /* Vector number is n*4, PC points to n*8. */ vector /= 2; } switch (vector) { case 0x0c: /* strcmp(): */ i = j = 0; do { ch1 = mem_readchar(cpu, MIPS_GPR_A0, i++); ch2 = mem_readchar(cpu, MIPS_GPR_A1, j++); } while (ch1 == ch2 && ch1 != '\0'); /* If ch1=='\0', then strings are equal. */ if (ch1 == '\0') cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; if ((signed char)ch1 > (signed char)ch2) cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; if ((signed char)ch1 < (signed char)ch2) cpu->cd.mips.gpr[MIPS_GPR_V0] = (uint64_t) -1; break; case 0x14: /* strlen(): */ i = 0; do { ch2 = mem_readchar(cpu, MIPS_GPR_A0, i++); } while (ch2 != 0); cpu->cd.mips.gpr[MIPS_GPR_V0] = i - 1; break; case 0x24: /* getchar() */ /* debug("[ DEC PROM getchar() ]\n"); */ cpu->cd.mips.gpr[MIPS_GPR_V0] = console_readchar( cpu->machine->main_console_handle); break; case 0x28: /* gets() */ /* debug("[ DEC PROM gets() ]\n"); */ tmpaddr = cpu->cd.mips.gpr[MIPS_GPR_A0]; i = 0; /* TODO: Make this not hang (block) the entire emulator */ do { while ((ch = console_readchar( cpu->machine->main_console_handle)) < 1) ; if (ch == '\r') ch = '\n'; ch2 = ch; if (ch == '\b') { if (i > 0) { console_putchar(cpu->machine-> main_console_handle, ch2); console_putchar(cpu->machine-> main_console_handle, ' '); console_putchar(cpu->machine-> main_console_handle, ch2); } } else console_putchar(cpu->machine-> main_console_handle, ch2); fflush(stdout); if (ch == '\n') { /* It seems that trailing newlines are not included in the buffer. */ } else if (ch != '\b') { cpu->memory_rw(cpu, cpu->mem, (int32_t) cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &ch2, sizeof(ch2), MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS); i++; } else { if (i > 0) i--; } } while (ch2 != '\n'); /* Trailing nul-byte: */ ch2 = '\0'; cpu->memory_rw(cpu, cpu->mem, (int32_t) cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &ch2, sizeof(ch2), MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS); /* Return the input argument: */ cpu->cd.mips.gpr[MIPS_GPR_V0] = cpu->cd.mips.gpr[MIPS_GPR_A0]; break; case 0x2c: /* puts() */ i = 0; while ((ch = mem_readchar(cpu, MIPS_GPR_A0, i++)) != '\0') console_putchar(cpu->machine->main_console_handle, ch); console_putchar(cpu->machine->main_console_handle, '\n'); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 0x30: /* printf() */ if (cpu->machine->register_dump || cpu->machine->instruction_trace) debug("PROM printf(0x%08lx): \n", (long)cpu->cd.mips.gpr[MIPS_GPR_A0]); i = 0; ch = -1; argreg = MIPS_GPR_A1; while (ch != '\0') { char printfbuf[8000]; size_t x; printfbuf[0] = printfbuf[sizeof(printfbuf)-1] = '\0'; ch = mem_readchar(cpu, MIPS_GPR_A0, i++); switch (ch) { case '%': ch = '0'; while (ch >= '0' && ch <= '9') ch = mem_readchar(cpu, MIPS_GPR_A0, i++); switch (ch) { case '%': strlcpy(printfbuf, "%%", sizeof(printfbuf)); break; case 'c': case 'd': case 's': case 'x': /* Get argument: */ if (argreg > MIPS_GPR_A3) { #if 1 /* Linux booters seem to go over the edge sometimes: */ ch = '\0'; strlcpy(printfbuf, "[...]\n", sizeof(printfbuf)); #else printf("[ decstation_prom_emul" "(): too many arguments ]"); /* This reuses the last arg, which is utterly incorrect. (TODO) */ argreg = MIPS_GPR_A3; #endif } ch2 = argdata = cpu->cd.mips.gpr[argreg]; switch (ch) { case 'c': snprintf(printfbuf, sizeof( printfbuf), "%c", ch2); break; case 'd': snprintf(printfbuf, sizeof( printfbuf), "%d", argdata); break; case 'x': snprintf(printfbuf, sizeof( printfbuf), "%x", argdata); break; case 's': /* Print a "%s" string. */ j = 0; ch3 = '\n'; while (ch2) { ch2 = mem_readchar(cpu, argreg, j++); if (ch2) { snprintf( printfbuf + strlen( printfbuf), sizeof( printfbuf)- 1-strlen( printfbuf), "%c", ch2); ch3 = ch2; } } break; } argreg ++; break; default: printf("[ unknown printf format char" " '%c' ]", ch); } break; case '\0': break; default: snprintf(printfbuf, sizeof(printfbuf), "%c", ch); } printfbuf[sizeof(printfbuf)-1] = '\0'; for (x=0; xmachine-> main_console_handle, printfbuf[x]); } if (cpu->machine->register_dump || cpu->machine->instruction_trace) debug("\n"); fflush(stdout); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 0x54: /* bootinit() */ /* debug("[ DEC PROM bootinit(0x%08x): TODO ]\n", (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); */ cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 0x58: /* bootread(int b, void *buffer, int n) */ /* * Read data from the boot device. * b is a sector number (512 bytes per sector), * buffer is the destination address, and n * is the number of _bytes_ to read. * * TODO: Return value? NetBSD thinks that 0 is ok. */ debug("[ DEC PROM bootread(0x%x, 0x%08x, 0x%x) ]\n", (int)cpu->cd.mips.gpr[MIPS_GPR_A0], (int)cpu->cd.mips.gpr[MIPS_GPR_A1], (int)cpu->cd.mips.gpr[MIPS_GPR_A2]); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; if ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2] > 0) { int disk_id = diskimage_bootdev(cpu->machine, NULL); int res; unsigned char *tmp_buf; CHECK_ALLOCATION(tmp_buf = (unsigned char *) malloc(cpu->cd.mips.gpr[MIPS_GPR_A2])); res = diskimage_access(cpu->machine, disk_id, DISKIMAGE_SCSI, 0, cpu->cd.mips.gpr[MIPS_GPR_A0] * 512, tmp_buf, cpu->cd.mips.gpr[MIPS_GPR_A2]); /* If the transfer was successful, transfer the data to emulated memory: */ if (res) { uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1]; if (dst < 0x80000000ULL) dst |= 0x80000000; store_buf(cpu, dst, (char *)tmp_buf, cpu->cd.mips.gpr[MIPS_GPR_A2]); cpu->cd.mips.gpr[MIPS_GPR_V0] = cpu->cd.mips.gpr[MIPS_GPR_A2]; } free(tmp_buf); } break; case 0x64: /* getenv() */ /* Find the environment variable given by a0: */ for (i=0; i<(int)sizeof(buf); i++) cpu->memory_rw(cpu, cpu->mem, (int32_t) cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &buf[i], sizeof(char), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); buf[sizeof(buf)-1] = '\0'; debug("[ DEC PROM getenv(\"%s\") ]\n", buf); for (i=0; i<0x1000; i++) { /* Matching string at offset i? */ int nmatches = 0; for (j=0; j<(int32_t)strlen((char *)buf); j++) { cpu->memory_rw(cpu, cpu->mem, (int32_t) (DEC_PROM_STRINGS + i + j), &ch2, sizeof(char), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); if (ch2 == buf[j]) nmatches++; } cpu->memory_rw(cpu, cpu->mem, (int32_t)(DEC_PROM_STRINGS + i + strlen((char *)buf)), &ch2, sizeof(char), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); if (nmatches == (int)strlen((char *)buf) && ch2=='=') { cpu->cd.mips.gpr[MIPS_GPR_V0] = DEC_PROM_STRINGS + i + strlen((char *)buf) + 1; return 1; } } /* Return NULL if string wasn't found. */ fatal("[ DEC PROM getenv(\"%s\"): WARNING: Not in " "environment! ]\n", buf); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 0x6c: /* ulong slot_address(int sn) */ debug("[ DEC PROM slot_address(%i) ]\n", (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); /* TODO: This is too hardcoded. */ /* TODO 2: Should these be physical or virtual addresses? */ switch (cpu->machine->machine_subtype) { case MACHINE_DEC_3MAX_5000: slot_base = KN02_PHYS_TC_0_START;/* 0x1e000000 */ slot_size = 4*1048576; /* 4 MB */ break; case MACHINE_DEC_3MIN_5000: slot_base = 0x10000000; slot_size = 0x4000000; /* 64 MB */ break; case MACHINE_DEC_3MAXPLUS_5000: slot_base = 0x1e000000; slot_size = 0x800000; /* 8 MB */ break; case MACHINE_DEC_MAXINE_5000: slot_base = 0x10000000; slot_size = 0x4000000; /* 64 MB */ break; default: fatal("warning: DEC PROM slot_address() " "unimplemented for this machine type\n"); } cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t)(int32_t) (0x80000000 + slot_base + slot_size * cpu->cd.mips.gpr[MIPS_GPR_A0]); break; case 0x70: /* wbflush() */ debug("[ DEC PROM wbflush(): TODO ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 0x7c: /* clear_cache(addr, len) */ debug("[ DEC PROM clear_cache(0x%x,%i) ]\n", (uint32_t)cpu->cd.mips.gpr[MIPS_GPR_A0], (int)cpu->cd.mips.gpr[MIPS_GPR_A1]); /* TODO */ cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* ? */ break; case 0x80: /* getsysid() */ /* debug("[ DEC PROM getsysid() ]\n"); */ /* TODO: why did I add the 0x82 stuff??? */ cpu->cd.mips.gpr[MIPS_GPR_V0] = ((uint32_t)0x82 << 24) + (cpu->machine->machine_subtype << 16) + (0x3 << 8); cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t)(int32_t)cpu->cd.mips.gpr[MIPS_GPR_V0]; break; case 0x84: /* getbitmap() */ debug("[ DEC PROM getbitmap(0x%08x) ]\n", (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); store_buf(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0], (char *)cpu->machine->md.pmax->memmap, sizeof(struct dec_memmap)); cpu->cd.mips.gpr[MIPS_GPR_V0] = sizeof(cpu->machine->md.pmax->memmap->bitmap); break; case 0x88: /* disableintr() */ debug("[ DEC PROM disableintr(): TODO ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 0x8c: /* enableintr() */ debug("[ DEC PROM enableintr(): TODO ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 0x9c: /* halt() */ debug("[ DEC PROM halt() ]\n"); cpu->machine->exit_without_entering_debugger = 1; cpu->running = 0; break; case 0xa4: /* gettcinfo() */ /* * These are just bogus values... TODO * * 0: revision * 4: clock period in nano seconds * 8: slot size in megabytes TODO: not same for all models! * 12: I/O timeout in cycles * 16: DMA address range in megabytes * 20: maximum DMA burst length * 24: turbochannel parity (yes = 1) * 28: reserved */ store_32bit_word(cpu, DEC_PROM_TCINFO + 0, 0); store_32bit_word(cpu, DEC_PROM_TCINFO + 4, 50); store_32bit_word(cpu, DEC_PROM_TCINFO + 8, 4); store_32bit_word(cpu, DEC_PROM_TCINFO + 12, 10); store_32bit_word(cpu, DEC_PROM_TCINFO + 16, 1); store_32bit_word(cpu, DEC_PROM_TCINFO + 20, 100); store_32bit_word(cpu, DEC_PROM_TCINFO + 24, 0); store_32bit_word(cpu, DEC_PROM_TCINFO + 28, 0); cpu->cd.mips.gpr[MIPS_GPR_V0] = DEC_PROM_TCINFO; break; case 0xa8: /* int execute_cmd(char *) */ i = 0; while ((ch = mem_readchar(cpu, MIPS_GPR_A0, i++)) != '\0') console_putchar(cpu->machine->main_console_handle, ch); console_putchar(cpu->machine->main_console_handle, '\n'); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 0xac: /* rex() */ debug("[ DEC PROM rex('%c') ]\n", (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); switch ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A0]) { case 'h': debug("DEC PROM: rex('h') ==> halt\n"); cpu->machine->exit_without_entering_debugger = 1; cpu->running = 0; break; case 'b': debug("DEC PROM: rex('b') ==> reboot: TODO " "(halting CPU instead)\n"); cpu->machine->exit_without_entering_debugger = 1; cpu->running = 0; break; default: fatal("DEC prom emulation: unknown rex() a0=0x%" PRIx64 " ('%c')\n", (int64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], (char) cpu->cd.mips.gpr[MIPS_GPR_A0]); cpu->running = 0; } break; default: cpu_register_dump(cpu->machine, cpu, 1, 0x1); printf("a0 points to: "); for (i=0; i<40; i++) { unsigned char chTmp = '\0'; cpu->memory_rw(cpu, cpu->mem, (int32_t) cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &chTmp, sizeof(chTmp), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); if (chTmp >= ' ' && chTmp < 126) printf("%c", chTmp); else printf("[%02x]", chTmp); } printf("\n"); fatal("PROM emulation: unimplemented callback vector 0x%x\n", vector); cpu->running = 0; } return 1; } gxemul-0.6.1/src/promemul/sh_ipl_g.cc000644 001750 001750 00000006547 13402411502 017763 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SH-IPL+G emulation * * Very basic, only what is needed to get OpenBSD/landisk booting. * (SH-IPL+G stands for SuperH Initial Program Loader + GDB stub.) */ #include #include #include #include #include "cpu.h" #include "cpu_sh.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/sh4_exception.h" /* * sh_ipl_g_emul_init(): */ void sh_ipl_g_emul_init(struct machine *machine) { struct cpu *cpu = machine->cpus[0]; cpu->cd.sh.vbr = 0x8c000000; store_16bit_word(cpu, 0x8c000100, SH_INVALID_INSTR); store_16bit_word(cpu, 0x8c000102, 0x002b); /* rte */ store_16bit_word(cpu, 0x8c000104, 0x0009); /* nop */ } /* * sh_ipl_g_promcall(): * * SH-IPL+G PROM call emulation. */ static int sh_ipl_g_promcall(struct cpu *cpu) { /* * SH-IPL+G call numbers are in R0: * * NOTE: r_bank[0], since this is in a trap handler! */ switch (cpu->cd.sh.r_bank[0]) { case 4: /* Get memory size. */ cpu->cd.sh.r_bank[0] = 64 * 1048576; /* Note: cpu->machine->physical_ram_in_mb * 1048576 would be more correct, but physical_ram_in_mb is set to 2 for landisk emulation... */ break; default:cpu_register_dump(cpu->machine, cpu, 1, 0); printf("\n"); fatal("[ SH-IPL+G PROM emulation: unimplemented function 0x%" PRIx32" ]\n", cpu->cd.sh.r_bank[0]); cpu->running = 0; return 0; } return 1; } /* * sh_ipl_g_emul(): */ int sh_ipl_g_emul(struct cpu *cpu) { /* SH-IPL+G calls are "trapa #63": */ if (cpu->cd.sh.expevt == EXPEVT_TRAPA && cpu->cd.sh.tra == 0xfc) { return sh_ipl_g_promcall(cpu); } else { cpu_register_dump(cpu->machine, cpu, 1, 0); printf("\n"); fatal("[ SH-IPL+G PROM emulation: expevt=0x%x, " " tra=0x%x ]\n", (int)cpu->cd.sh.expevt, (int)cpu->cd.sh.tra); cpu->running = 0; return 0; } } gxemul-0.6.1/src/promemul/luna88kprom.cc000644 001750 001750 00000006751 13402411502 020364 0ustar00debugdebug000000 000000 /* * Copyright (C) 2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: LUNA 88K PROM emulation * * For LUNA 88K emulation. */ #include #include #include #include #include "console.h" #include "cpu.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/luna88k_board.h" /* * luna88kprom_init(): */ void luna88kprom_init(struct machine *machine) { struct cpu *cpu = machine->cpus[0]; /* * Memory layout according to OpenBSD's locore0.S: * * 0x00000 - 0x00fff = trap vectors * 0x01000 - 0x1ffff = ROM monitor work area * 0x20000 - ... = Boot loader jumps here * * The boot loader stage before loading OpenBSD's kernel seems * to be loaded at 0x00700000. */ /* 0x00001100: ROM function table. See OpenBSD's machdep.c */ store_32bit_word(cpu, 0x1100 + sizeof(uint32_t) * 3, 0x2030); /* ROM console getch */ store_32bit_word(cpu, 0x1100 + sizeof(uint32_t) * 4, 0x2040); /* ROM console putch */ store_32bit_word(cpu, 0x2030, M88K_PROM_INSTR); store_32bit_word(cpu, 0x2034, 0xf400c001); /* jmp (r1) */ store_32bit_word(cpu, 0x2040, M88K_PROM_INSTR); store_32bit_word(cpu, 0x2044, 0xf400c001); /* jmp (r1) */ /* 0x00001114: Framebuffer depth */ store_32bit_word(cpu, 0x1114, machine->x11_md.in_use ? 8 : 0); } /* * luna88kprom_emul(): * * Input: * pc is used to figure out function number * r2 = first argument (for functions that take arguments) * * Output: * r2 = result */ int luna88kprom_emul(struct cpu *cpu) { int func = (cpu->pc & 0xf0) >> 4; switch (func) { case 4: console_putchar(cpu->machine->main_console_handle, cpu->cd.m88k.r[2]); break; default: cpu_register_dump(cpu->machine, cpu, 1, 0); cpu_register_dump(cpu->machine, cpu, 0, 1); fatal("[ LUNA88K PROM emulation: unimplemented function 0x%" PRIx32" ]\n", func); cpu->running = 0; return 0; } return 1; } gxemul-0.6.1/src/promemul/README000644 001750 001750 00000001217 13402411502 016535 0ustar00debugdebug000000 000000 $Id: README,v 1.2 2007-02-21 17:05:05 debug Exp $ (P)ROM and BIOS emulation in GXemul: ------------------------------------ The general philosophy that applies to PROM/BIOS emulation is that no raw binary dumps of real ROMs should be included in GXemul. It is nicer to emulate in software only those parts of a machine's ROM or BIOS that are actually necessary to boot an operating system. This directory contains software emulation of various PROMs and BIOSes. (Note: Running actual PROM dumps is also possible, and of course has several advantages over software simulated PROM call handling. That is what GXemul's -Q command line option is for.) gxemul-0.6.1/src/promemul/arcbios.cc000644 001750 001750 00000270135 13402411502 017615 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: ARCBIOS and ARCS emulation */ #include #include #include #include #include #include #include #include #include "arcbios.h" #include "console.h" #include "cpu.h" #include "cpu_mips.h" #include "diskimage.h" #include "machine.h" #include "machine_arc.h" #include "memory.h" #include "misc.h" #include "thirdparty/arcbios_other.h" extern int quiet_mode; /* * arcbios_add_string_to_component(): */ void arcbios_add_string_to_component(struct machine *machine, char *str, uint64_t component) { if (machine->md.arc->n_string_to_components >= MAX_STRING_TO_COMPONENT) { printf("Too many string-to-component mappings.\n"); exit(1); } CHECK_ALLOCATION(machine->md.arc->string_to_component[machine-> md.arc->n_string_to_components] = strdup(str)); debug("adding ARC component mapping: 0x%08x = %s\n", (int)component, str); machine->md.arc->string_to_component_value[ machine->md.arc->n_string_to_components] = component; machine->md.arc->n_string_to_components ++; } /* * arcbios_get_dsp_stat(): * * Fills in an arcbios_dsp_stat struct with valid data. */ static void arcbios_get_dsp_stat(struct cpu *cpu, struct arcbios_dsp_stat *dspstat) { memset(dspstat, 0, sizeof(struct arcbios_dsp_stat)); store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> CursorXPosition, cpu->machine->md.arc->console_curx + 1); store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> CursorYPosition, cpu->machine->md.arc->console_cury + 1); store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> CursorMaxXPosition, ARC_CONSOLE_MAX_X); store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> CursorMaxYPosition, ARC_CONSOLE_MAX_Y); dspstat->ForegroundColor = cpu->machine->md.arc->console_curcolor; dspstat->HighIntensity = cpu->machine->md.arc->console_curcolor ^ 0x08; } /* * arcbios_putcell(): */ static void arcbios_putcell(struct cpu *cpu, int ch, int x, int y) { unsigned char buf[2]; buf[0] = ch; buf[1] = cpu->machine->md.arc->console_curcolor; if (cpu->machine->md.arc->console_reverse) buf[1] = ((buf[1] & 0x70) >> 4) | ((buf[1] & 7) << 4) | (buf[1] & 0x88); cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc->console_vram + 2*(x + cpu->machine->md.arc->console_maxx * y), &buf[0], sizeof(buf), MEM_WRITE, CACHE_NONE | PHYSICAL); } /* * handle_esc_seq(): * * Used by arcbios_putchar(). */ static void handle_esc_seq(struct cpu *cpu) { int i, len = strlen(cpu->machine->md.arc->escape_sequence); int row, col, color, code, start, stop; char *p; if (cpu->machine->md.arc->escape_sequence[0] != '[') return; code = cpu->machine->md.arc->escape_sequence[len-1]; cpu->machine->md.arc->escape_sequence[len-1] = '\0'; switch (code) { case 'm': color = atoi(cpu->machine->md.arc->escape_sequence + 1); switch (color) { case 0: /* Default. */ cpu->machine->md.arc->console_curcolor = 0x1f; cpu->machine->md.arc->console_reverse = 0; break; case 1: /* "Bold". */ cpu->machine->md.arc->console_curcolor |= 0x08; break; case 7: /* "Reverse". */ cpu->machine->md.arc->console_reverse = 1; break; case 30: /* Black foreground. */ cpu->machine->md.arc->console_curcolor &= 0xf0; cpu->machine->md.arc->console_curcolor |= 0x00; break; case 31: /* Red foreground. */ cpu->machine->md.arc->console_curcolor &= 0xf0; cpu->machine->md.arc->console_curcolor |= 0x04; break; case 32: /* Green foreground. */ cpu->machine->md.arc->console_curcolor &= 0xf0; cpu->machine->md.arc->console_curcolor |= 0x02; break; case 33: /* Yellow foreground. */ cpu->machine->md.arc->console_curcolor &= 0xf0; cpu->machine->md.arc->console_curcolor |= 0x06; break; case 34: /* Blue foreground. */ cpu->machine->md.arc->console_curcolor &= 0xf0; cpu->machine->md.arc->console_curcolor |= 0x01; break; case 35: /* Red-blue foreground. */ cpu->machine->md.arc->console_curcolor &= 0xf0; cpu->machine->md.arc->console_curcolor |= 0x05; break; case 36: /* Green-blue foreground. */ cpu->machine->md.arc->console_curcolor &= 0xf0; cpu->machine->md.arc->console_curcolor |= 0x03; break; case 37: /* White foreground. */ cpu->machine->md.arc->console_curcolor &= 0xf0; cpu->machine->md.arc->console_curcolor |= 0x07; break; case 40: /* Black background. */ cpu->machine->md.arc->console_curcolor &= 0x0f; cpu->machine->md.arc->console_curcolor |= 0x00; break; case 41: /* Red background. */ cpu->machine->md.arc->console_curcolor &= 0x0f; cpu->machine->md.arc->console_curcolor |= 0x40; break; case 42: /* Green background. */ cpu->machine->md.arc->console_curcolor &= 0x0f; cpu->machine->md.arc->console_curcolor |= 0x20; break; case 43: /* Yellow background. */ cpu->machine->md.arc->console_curcolor &= 0x0f; cpu->machine->md.arc->console_curcolor |= 0x60; break; case 44: /* Blue background. */ cpu->machine->md.arc->console_curcolor &= 0x0f; cpu->machine->md.arc->console_curcolor |= 0x10; break; case 45: /* Red-blue background. */ cpu->machine->md.arc->console_curcolor &= 0x0f; cpu->machine->md.arc->console_curcolor |= 0x50; break; case 46: /* Green-blue background. */ cpu->machine->md.arc->console_curcolor &= 0x0f; cpu->machine->md.arc->console_curcolor |= 0x30; break; case 47: /* White background. */ cpu->machine->md.arc->console_curcolor &= 0x0f; cpu->machine->md.arc->console_curcolor |= 0x70; break; default:fatal("{ handle_esc_seq: color %i }\n", color); } return; case 'H': p = strchr(cpu->machine->md.arc->escape_sequence, ';'); if (p == NULL) return; /* TODO */ row = atoi(cpu->machine->md.arc->escape_sequence + 1); col = atoi(p + 1); if (col < 1) col = 1; if (row < 1) row = 1; cpu->machine->md.arc->console_curx = col - 1; cpu->machine->md.arc->console_cury = row - 1; return; case 'J': /* * J = clear screen below cursor, and the rest of the * current line, * 2J = clear whole screen. */ i = atoi(cpu->machine->md.arc->escape_sequence + 1); if (i != 0 && i != 2) fatal("{ handle_esc_seq(): %iJ }\n", i); if (i == 0) for (col = cpu->machine->md.arc->console_curx; col < cpu->machine->md.arc->console_maxx; col++) arcbios_putcell(cpu, ' ', col, cpu->machine->md.arc->console_cury); for (col = 0; col < cpu->machine->md.arc->console_maxx; col++) for (row = i? 0 : cpu->machine->md.arc->console_cury+1; row < cpu->machine->md.arc->console_maxy; row++) arcbios_putcell(cpu, ' ', col, row); return; case 'K': col = atoi(cpu->machine->md.arc->escape_sequence + 1); /* 2 = clear line to the right. 1 = to the left (?) */ start = 0; stop = cpu->machine->md.arc->console_curx; if (col == 2) { start = cpu->machine->md.arc->console_curx; stop = cpu->machine->md.arc->console_maxx - 1; } for (i=start; i<=stop; i++) arcbios_putcell(cpu, ' ', i, cpu->machine->md.arc->console_cury); return; } fatal("{ handle_esc_seq(): unimplemented escape sequence: "); for (i=0; imachine->md.arc->escape_sequence[i]; if (i == len-1) x = code; if (x >= ' ' && x < 127) fatal("%c", x); else fatal("[0x%02x]", x); } fatal(" }\n"); } /* * scroll_if_necessary(): */ static void scroll_if_necessary(struct cpu *cpu) { /* Scroll? */ if (cpu->machine->md.arc->console_cury >= cpu->machine->md.arc->console_maxy) { unsigned char buf[2]; int x, y; for (y=0; ymachine->md.arc->console_maxy-1; y++) for (x=0; xmachine->md.arc->console_maxx; x++) { cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc->console_vram + 2*(x + cpu->machine->md.arc-> console_maxx * (y+1)), &buf[0], sizeof(buf), MEM_READ, CACHE_NONE | PHYSICAL); cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc->console_vram + 2*(x + cpu->machine->md.arc-> console_maxx * y), &buf[0], sizeof(buf), MEM_WRITE, CACHE_NONE | PHYSICAL); } cpu->machine->md.arc->console_cury = cpu->machine->md.arc->console_maxy - 1; for (x=0; xmachine->md.arc->console_maxx; x++) arcbios_putcell(cpu, ' ', x, cpu->machine->md.arc->console_cury); } } /* * arcbios_putchar(): * * If we're using X11 with VGA-style console, then output to that console. * Otherwise, use console_putchar(). */ static void arcbios_putchar(struct cpu *cpu, int ch) { int addr; unsigned char byte; if (!cpu->machine->md.arc->vgaconsole) { /* Text console output: */ /* Hack for Windows NT, which uses 0x9b instead of ESC + [ */ if (ch == 0x9b) { console_putchar(cpu->machine->main_console_handle, 27); ch = '['; } console_putchar(cpu->machine->main_console_handle, ch); return; } if (cpu->machine->md.arc->in_escape_sequence) { int len = strlen(cpu->machine->md.arc->escape_sequence); cpu->machine->md.arc->escape_sequence[len] = ch; len++; if (len >= ARC_MAX_ESC) len = ARC_MAX_ESC; cpu->machine->md.arc->escape_sequence[len] = '\0'; if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || len >= ARC_MAX_ESC) { handle_esc_seq(cpu); cpu->machine->md.arc->in_escape_sequence = 0; } } else { if (ch == 27) { cpu->machine->md.arc->in_escape_sequence = 1; cpu->machine->md.arc->escape_sequence[0] = '\0'; } else if (ch == 0x9b) { cpu->machine->md.arc->in_escape_sequence = 1; cpu->machine->md.arc->escape_sequence[0] = '['; cpu->machine->md.arc->escape_sequence[1] = '\0'; } else if (ch == '\b') { if (cpu->machine->md.arc->console_curx > 0) cpu->machine->md.arc->console_curx --; } else if (ch == '\r') { cpu->machine->md.arc->console_curx = 0; } else if (ch == '\n') { cpu->machine->md.arc->console_cury ++; } else if (ch == '\t') { cpu->machine->md.arc->console_curx = ((cpu->machine->md.arc->console_curx - 1) | 7) + 1; /* TODO: Print spaces? */ } else { /* Put char: */ if (cpu->machine->md.arc->console_curx >= cpu->machine->md.arc->console_maxx) { cpu->machine->md.arc->console_curx = 0; cpu->machine->md.arc->console_cury ++; scroll_if_necessary(cpu); } arcbios_putcell(cpu, ch, cpu->machine->md.arc->console_curx, cpu->machine->md.arc->console_cury); cpu->machine->md.arc->console_curx ++; } } scroll_if_necessary(cpu); /* Update cursor position: */ addr = (cpu->machine->md.arc->console_curx >= cpu->machine->md.arc->console_maxx? cpu->machine->md.arc->console_maxx - 1 : cpu->machine->md.arc->console_curx) + cpu->machine->md.arc->console_cury * cpu->machine->md.arc->console_maxx; byte = 0x0e; cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc-> console_ctrlregs + 0x14, &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); byte = (addr >> 8) & 255; cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc-> console_ctrlregs + 0x15, &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); byte = 0x0f; cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc-> console_ctrlregs + 0x14, &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); byte = addr & 255; cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc-> console_ctrlregs + 0x15, &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); } /* * arcbios_putstring(): */ static void arcbios_putstring(struct cpu *cpu, const char *s) { while (*s) { if (*s == '\n') arcbios_putchar(cpu, '\r'); arcbios_putchar(cpu, *s++); } } /* * arcbios_register_scsicontroller(): */ void arcbios_register_scsicontroller(struct machine *machine, uint64_t scsicontroller_component) { machine->md.arc->scsicontroller = scsicontroller_component; } /* * arcbios_get_scsicontroller(): */ uint64_t arcbios_get_scsicontroller(struct machine *machine) { return machine->md.arc->scsicontroller; } /* * arcbios_add_memory_descriptor(): * * NOTE: arctype is the ARC type, not the SGI type. This function takes * care of converting, when necessary. */ void arcbios_add_memory_descriptor(struct cpu *cpu, uint64_t base, uint64_t len, int arctype) { uint64_t memdesc_addr; int s; struct arcbios_mem arcbios_mem; struct arcbios_mem64 arcbios_mem64; base /= 4096; len /= 4096; /* * TODO: Huh? Why isn't it necessary to convert from arc to sgi types? * * TODO 2: It seems that it _is_ necessary, but NetBSD's arcdiag * doesn't handle the sgi case separately. */ #if 1 if (cpu->machine->machine_type == MACHINE_SGI) { /* arctype is SGI style */ /* printf("%i => ", arctype); */ switch (arctype) { case 0: arctype = 0; break; case 1: arctype = 1; break; case 2: arctype = 3; break; case 3: arctype = 4; break; case 4: arctype = 5; break; case 5: arctype = 6; break; case 6: arctype = 7; break; case 7: arctype = 2; break; } /* printf("%i\n", arctype); */ } #endif if (cpu->machine->md.arc->arc_64bit) s = sizeof(arcbios_mem64); else s = sizeof(arcbios_mem); memdesc_addr = cpu->machine->md.arc->memdescriptor_base + cpu->machine->md.arc->n_memdescriptors * s; if (cpu->machine->md.arc->arc_64bit) { memset(&arcbios_mem64, 0, s); store_32bit_word_in_host(cpu, (unsigned char *)&arcbios_mem64.Type, arctype); store_64bit_word_in_host(cpu, (unsigned char *)&arcbios_mem64.BasePage, base); store_64bit_word_in_host(cpu, (unsigned char *)&arcbios_mem64.PageCount, len); store_buf(cpu, memdesc_addr, (char *)&arcbios_mem64, s); } else { memset(&arcbios_mem, 0, s); store_32bit_word_in_host(cpu, (unsigned char *)&arcbios_mem.Type, arctype); store_32bit_word_in_host(cpu, (unsigned char *)&arcbios_mem.BasePage, base); store_32bit_word_in_host(cpu, (unsigned char *)&arcbios_mem.PageCount, len); store_buf(cpu, memdesc_addr, (char *)&arcbios_mem, s); } cpu->machine->md.arc->n_memdescriptors ++; } /* * arcbios_addchild(): * * host_tmp_component is a temporary component, with data formated for * the host system. It needs to be translated/copied into emulated RAM. * * Return value is the virtual (emulated) address of the added component. * * TODO: This function doesn't care about memory management, but simply * stores the new child after the last stored child. * TODO: This stuff is really ugly. */ static uint64_t arcbios_addchild(struct cpu *cpu, struct arcbios_component *host_tmp_component, const char *identifier, uint32_t parent) { struct machine *machine = cpu->machine; uint64_t a = machine->md.arc->next_component_address; uint32_t peer=0; uint32_t child=0; int n_left; uint64_t peeraddr = FIRST_ARC_COMPONENT; /* * This component has no children yet, but it may have peers (that is, * other components that share this component's parent) so we have to * set the peer value correctly. * * Also, if this is the first child of some parent, the parent's child * pointer should be set to point to this component. (But only if it * is the first.) * * This is really ugly: scan through all components, starting from * FIRST_ARC_COMPONENT, to find a component with the same parent as * this component will have. If such a component is found, and its * 'peer' value is NULL, then set it to this component's address (a). * * TODO: make this nicer */ n_left = machine->md.arc->n_components; while (n_left > 0) { /* Load parent, child, and peer values: */ uint32_t eparent, echild, epeer, tmp; unsigned char buf[4]; /* debug("[ addchild: peeraddr = 0x%08x ]\n", (int)peeraddr); */ cpu->memory_rw(cpu, cpu->mem, peeraddr + 0 * machine->md.arc->wordlen, &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp2; tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; } epeer = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); cpu->memory_rw(cpu, cpu->mem, peeraddr + 1 * machine->md.arc->wordlen, &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp2; tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; } echild = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); cpu->memory_rw(cpu, cpu->mem, peeraddr + 2 * machine->md.arc->wordlen, &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp2; tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; } eparent = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); /* debug(" epeer=%x echild=%x eparent=%x\n", (int)epeer,(int)echild,(int)eparent); */ if ((uint32_t)eparent == (uint32_t)parent && (uint32_t)epeer == 0) { epeer = a; store_32bit_word(cpu, peeraddr + 0x00, epeer); /* debug("[ addchild: adding 0x%08x as peer " "to 0x%08x ]\n", (int)a, (int)peeraddr); */ } if ((uint32_t)peeraddr == (uint32_t)parent && (uint32_t)echild == 0) { echild = a; store_32bit_word(cpu, peeraddr + 0x04, echild); /* debug("[ addchild: adding 0x%08x as " "child to 0x%08x ]\n", (int)a, (int)peeraddr); */ } /* Go to the next component: */ cpu->memory_rw(cpu, cpu->mem, peeraddr + 0x28, &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp2; tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; } tmp = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); peeraddr += 0x30; peeraddr += tmp + 1; peeraddr = ((peeraddr - 1) | 3) + 1; n_left --; } store_32bit_word(cpu, a + 0x00, peer); store_32bit_word(cpu, a + 0x04, child); store_32bit_word(cpu, a + 0x08, parent); store_32bit_word(cpu, a+ 0x0c, host_tmp_component->Class); store_32bit_word(cpu, a+ 0x10, host_tmp_component->Type); store_32bit_word(cpu, a+ 0x14, host_tmp_component->Flags + 65536 * host_tmp_component->Version); store_32bit_word(cpu, a+ 0x18, host_tmp_component->Revision); store_32bit_word(cpu, a+ 0x1c, host_tmp_component->Key); store_32bit_word(cpu, a+ 0x20, host_tmp_component->AffinityMask); store_32bit_word(cpu, a+ 0x24, host_tmp_component-> ConfigurationDataSize); store_32bit_word(cpu, a+ 0x28, host_tmp_component->IdentifierLength); store_32bit_word(cpu, a+ 0x2c, host_tmp_component->Identifier); machine->md.arc->next_component_address += 0x30; if (host_tmp_component->IdentifierLength != 0) { store_32bit_word(cpu, a + 0x2c, a + 0x30); store_string(cpu, a + 0x30, identifier); if (identifier != NULL) machine->md.arc->next_component_address += strlen(identifier) + 1; } machine->md.arc->next_component_address ++; /* Round up to next 0x4 bytes: */ machine->md.arc->next_component_address = ((machine->md.arc->next_component_address - 1) | 3) + 1; machine->md.arc->n_components ++; return a; } /* * arcbios_addchild64(): * * host_tmp_component is a temporary component, with data formated for * the host system. It needs to be translated/copied into emulated RAM. * * Return value is the virtual (emulated) address of the added component. * * TODO: This function doesn't care about memory management, but simply * stores the new child after the last stored child. * TODO: This stuff is really ugly. */ static uint64_t arcbios_addchild64(struct cpu *cpu, struct arcbios_component64 *host_tmp_component, const char *identifier, uint64_t parent) { struct machine *machine = cpu->machine; uint64_t a = machine->md.arc->next_component_address; uint64_t peer=0; uint64_t child=0; int n_left; uint64_t peeraddr = FIRST_ARC_COMPONENT; /* * This component has no children yet, but it may have peers (that is, * other components that share this component's parent) so we have to * set the peer value correctly. * * Also, if this is the first child of some parent, the parent's child * pointer should be set to point to this component. (But only if it * is the first.) * * This is really ugly: scan through all components, starting from * FIRST_ARC_COMPONENT, to find a component with the same parent as * this component will have. If such a component is found, and its * 'peer' value is NULL, then set it to this component's address (a). * * TODO: make this nicer */ n_left = machine->md.arc->n_components; while (n_left > 0) { /* Load parent, child, and peer values: */ uint64_t eparent, echild, epeer, tmp; unsigned char buf[8]; /* debug("[ addchild: peeraddr = 0x%016" PRIx64" ]\n", (uint64_t) peeraddr); */ cpu->memory_rw(cpu, cpu->mem, peeraddr + 0 * machine->md.arc->wordlen, &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp2; tmp2 = buf[0]; buf[0] = buf[7]; buf[7] = tmp2; tmp2 = buf[1]; buf[1] = buf[6]; buf[6] = tmp2; tmp2 = buf[2]; buf[2] = buf[5]; buf[5] = tmp2; tmp2 = buf[3]; buf[3] = buf[4]; buf[4] = tmp2; } epeer = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24) + ((uint64_t)buf[4] << 32) + ((uint64_t)buf[5] << 40) + ((uint64_t)buf[6] << 48) + ((uint64_t)buf[7] << 56); cpu->memory_rw(cpu, cpu->mem, peeraddr + 1 * machine->md.arc->wordlen, &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp2; tmp2 = buf[0]; buf[0] = buf[7]; buf[7] = tmp2; tmp2 = buf[1]; buf[1] = buf[6]; buf[6] = tmp2; tmp2 = buf[2]; buf[2] = buf[5]; buf[5] = tmp2; tmp2 = buf[3]; buf[3] = buf[4]; buf[4] = tmp2; } echild = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24) + ((uint64_t)buf[4] << 32) + ((uint64_t)buf[5] << 40) + ((uint64_t)buf[6] << 48) + ((uint64_t)buf[7] << 56); cpu->memory_rw(cpu, cpu->mem, peeraddr + 2 * machine->md.arc->wordlen, &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp2; tmp2 = buf[0]; buf[0] = buf[7]; buf[7] = tmp2; tmp2 = buf[1]; buf[1] = buf[6]; buf[6] = tmp2; tmp2 = buf[2]; buf[2] = buf[5]; buf[5] = tmp2; tmp2 = buf[3]; buf[3] = buf[4]; buf[4] = tmp2; } eparent = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24) + ((uint64_t)buf[4] << 32) + ((uint64_t)buf[5] << 40) + ((uint64_t)buf[6] << 48) + ((uint64_t)buf[7] << 56); /* debug(" epeer=%" PRIx64" echild=%" PRIx64" eparent=%" PRIx64 "\n", (uint64_t) epeer, (uint64_t) echild, (uint64_t) eparent); */ if (eparent == parent && epeer == 0) { epeer = a; store_64bit_word(cpu, peeraddr + 0 * machine->md.arc->wordlen, epeer); /* debug("[ addchild: adding 0x%016" PRIx64" as peer " "to 0x%016" PRIx64" ]\n", (uint64_t) a, (uint64_t) peeraddr); */ } if (peeraddr == parent && echild == 0) { echild = a; store_64bit_word(cpu, peeraddr + 1 * machine->md.arc->wordlen, echild); /* debug("[ addchild: adding 0x%016" PRIx64" as child " "to 0x%016" PRIx64" ]\n", (uint64_t) a, (uint64_t) peeraddr); */ } /* Go to the next component: */ cpu->memory_rw(cpu, cpu->mem, peeraddr + 0x34, &buf[0], sizeof(uint32_t), MEM_READ, CACHE_NONE); if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp2; tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; } tmp = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); tmp &= 0xfffff; peeraddr += 0x50; peeraddr += tmp + 1; peeraddr = ((peeraddr - 1) | 3) + 1; n_left --; } store_64bit_word(cpu, a + 0x00, peer); store_64bit_word(cpu, a + 0x08, child); store_64bit_word(cpu, a + 0x10, parent); store_32bit_word(cpu, a+ 0x18, host_tmp_component->Class); store_32bit_word(cpu, a+ 0x1c, host_tmp_component->Type); store_32bit_word(cpu, a+ 0x20, host_tmp_component->Flags); store_32bit_word(cpu, a+ 0x24, host_tmp_component->Version + ((uint64_t)host_tmp_component->Revision << 16)); store_32bit_word(cpu, a+ 0x28, host_tmp_component->Key); store_64bit_word(cpu, a+ 0x30, host_tmp_component->AffinityMask); store_64bit_word(cpu, a+ 0x38, host_tmp_component-> ConfigurationDataSize); store_64bit_word(cpu, a+ 0x40, host_tmp_component->IdentifierLength); store_64bit_word(cpu, a+ 0x48, host_tmp_component->Identifier); /* TODO: Find out how a REAL ARCS64 implementation does it. */ machine->md.arc->next_component_address += 0x50; if (host_tmp_component->IdentifierLength != 0) { store_64bit_word(cpu, a + 0x48, a + 0x50); store_string(cpu, a + 0x50, identifier); if (identifier != NULL) machine->md.arc->next_component_address += strlen(identifier) + 1; } machine->md.arc->next_component_address ++; /* Round up to next 0x8 bytes: */ machine->md.arc->next_component_address = ((machine->md.arc->next_component_address - 1) | 7) + 1; machine->md.arc->n_components ++; return a; } /* * arcbios_addchild_manual(): * * Used internally to set up component structures. * Parent may only be NULL for the first (system) component. * * Return value is the virtual (emulated) address of the added component. */ uint64_t arcbios_addchild_manual(struct cpu *cpu, uint64_t cclass, uint64_t type, uint64_t flags, uint64_t version, uint64_t revision, uint64_t key, uint64_t affinitymask, const char *identifier, uint64_t parent, void *config_data, size_t config_len) { struct machine *machine = cpu->machine; /* This component is only for temporary use: */ struct arcbios_component component; struct arcbios_component64 component64; if (config_data != NULL) { unsigned char *p = (unsigned char *) config_data; size_t i; if (machine->md.arc->n_configuration_data >= MAX_CONFIG_DATA) { printf("fatal error: you need to increase " "MAX_CONFIG_DATA\n"); exit(1); } for (i=0; imemory_rw(cpu, cpu->mem, machine->md.arc->configuration_data_next_addr + i, &ch, 1, MEM_WRITE, CACHE_NONE); } machine->md.arc->configuration_data_len[ machine->md.arc->n_configuration_data] = config_len; machine->md.arc->configuration_data_configdata[ machine->md.arc->n_configuration_data] = machine->md.arc->configuration_data_next_addr; machine->md.arc->configuration_data_next_addr += config_len; machine->md.arc->configuration_data_component[ machine->md.arc->n_configuration_data] = machine->md.arc->next_component_address + (cpu->machine->md.arc->arc_64bit? 0x18 : 0x0c); /* printf("& ADDING %i: configdata=0x%016" PRIx64" " "component=0x%016" PRIx64"\n", machine->md.arc->n_configuration_data, (uint64_t) machine->md.arc->configuration_data_configdata[ machine->md.arc->n_configuration_data], (uint64_t) machine->md.arc->configuration_data_component[ machine->md.arc->n_configuration_data]); */ machine->md.arc->n_configuration_data ++; } if (!cpu->machine->md.arc->arc_64bit) { component.Class = cclass; component.Type = type; component.Flags = flags; component.Version = version; component.Revision = revision; component.Key = key; component.AffinityMask = affinitymask; component.ConfigurationDataSize = config_len; component.IdentifierLength = 0; component.Identifier = 0; if (identifier != NULL) { component.IdentifierLength = strlen(identifier) + 1; } return arcbios_addchild(cpu, &component, identifier, parent); } else { component64.Class = cclass; component64.Type = type; component64.Flags = flags; component64.Version = version; component64.Revision = revision; component64.Key = key; component64.AffinityMask = affinitymask; component64.ConfigurationDataSize = config_len; component64.IdentifierLength = 0; component64.Identifier = 0; if (identifier != NULL) { component64.IdentifierLength = strlen(identifier) + 1; } return arcbios_addchild64(cpu, &component64, identifier, parent); } } /* * arcbios_get_msdos_partition_size(): * * This function tries to parse MSDOS-style partition tables on a disk * image, and return the starting offset (counted in bytes), and the * size, of a specific partition. * * NOTE: partition_nr is 1-based! * * TODO: This is buggy, it doesn't really handle extended partitions. * * See http://www.nondot.org/sabre/os/files/Partitions/Partitions.html * for more info. */ static void arcbios_get_msdos_partition_size(struct machine *machine, int disk_id, int disk_type, int partition_nr, uint64_t *start, uint64_t *size) { int res, i, partition_type, cur_partition = 0; unsigned char sector[512]; unsigned char buf[16]; uint64_t offset = 0, st; /* Partition 0 is the entire disk image: */ *start = 0; *size = diskimage_getsize(machine, disk_id, disk_type); if (partition_nr == 0) return; ugly_goto: *start = 0; *size = 0; /* printf("reading MSDOS partition from offset 0x%" PRIx64"\n", (uint64_t) offset); */ res = diskimage_access(machine, disk_id, disk_type, 0, offset, sector, sizeof(sector)); if (!res) { fatal("[ arcbios_get_msdos_partition_size(): couldn't " "read the disk image, id %i, offset 0x%" PRIx64" ]\n", disk_id, (uint64_t) offset); return; } if (sector[510] != 0x55 || sector[511] != 0xaa) { fatal("[ arcbios_get_msdos_partition_size(): not an " "MSDOS partition table ]\n"); } #if 0 /* Debug dump: */ for (i=0; i<4; i++) { int j; printf(" partition %i: ", i+1); for (j=0; j<16; j++) printf(" %02x", sector[446 + i*16 + j]); printf("\n"); } #endif for (i=0; i<4; i++) { memmove(buf, sector + 446 + 16*i, 16); partition_type = buf[4]; if (partition_type == 0) continue; st = (buf[8] + (buf[9] << 8) + (buf[10] << 16) + (buf[11] << 24)) * 512; if (start != NULL) *start = st; if (size != NULL) *size = (buf[12] + (buf[13] << 8) + (buf[14] << 16) + (buf[15] << 24)) * 512; /* Extended DOS partition: */ if (partition_type == 5) { offset += st; goto ugly_goto; } /* Found the right partition? Then return. */ cur_partition ++; if (cur_partition == partition_nr) return; } fatal("[ partition(%i) NOT found ]\n", partition_nr); } /* * arcbios_handle_to_disk_id_and_type(): */ static int arcbios_handle_to_disk_id_and_type(struct machine *machine, int handle, int *typep) { int id, cdrom; const char *s; if (handle < 0 || handle >= ARC_MAX_HANDLES) return -1; s = machine->md.arc->file_handle_string[handle]; if (s == NULL) return -1; /* * s is something like "scsi(0)disk(0)rdisk(0)partition(0)". * TODO: This is really ugly and hardcoded. */ if (strncmp(s, "scsi(", 5) != 0 || strlen(s) < 13) return -1; *typep = DISKIMAGE_SCSI; cdrom = (s[7] == 'c'); id = cdrom? atoi(s + 13) : atoi(s + 12); return id; } /* * arcbios_handle_to_start_and_size(): */ static void arcbios_handle_to_start_and_size(struct machine *machine, int handle, uint64_t *start, uint64_t *size) { const char *s = machine->md.arc->file_handle_string[handle]; const char *s2; int disk_id, disk_type; disk_id = arcbios_handle_to_disk_id_and_type(machine, handle, &disk_type); if (disk_id < 0) return; /* This works for "partition(0)": */ *start = 0; *size = diskimage_getsize(machine, disk_id, disk_type); s2 = strstr(s, "partition("); if (s2 != NULL) { int partition_nr = atoi(s2 + 10); /* printf("partition_nr = %i\n", partition_nr); */ if (partition_nr != 0) arcbios_get_msdos_partition_size(machine, disk_id, disk_type, partition_nr, start, size); } } /* * arcbios_getfileinformation(): * * Fill in a GetFileInformation struct in emulated memory, * for a specific file handle. (This is used to get the size * and offsets of partitions on disk images.) */ static int arcbios_getfileinformation(struct cpu *cpu) { int handle = cpu->cd.mips.gpr[MIPS_GPR_A0]; uint64_t addr = cpu->cd.mips.gpr[MIPS_GPR_A1]; uint64_t start, size; arcbios_handle_to_start_and_size(cpu->machine, handle, &start, &size); store_64bit_word(cpu, addr + 0, 0); store_64bit_word(cpu, addr + 8, size); store_64bit_word(cpu, addr + 16, 0); store_32bit_word(cpu, addr + 24, 1); store_32bit_word(cpu, addr + 28, 0); store_32bit_word(cpu, addr + 32, 0); /* printf("\n!!! size=0x%x start=0x%x\n", (int)size, (int)start); */ return ARCBIOS_ESUCCESS; } /* * arcbios_private_emul(): * * TODO: This is probably SGI specific. (?) * * 0x04 get nvram table */ void arcbios_private_emul(struct cpu *cpu) { int vector = cpu->pc & 0xfff; switch (vector) { case 0x04: debug("[ ARCBIOS PRIVATE get nvram table(): TODO ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; default: cpu_register_dump(cpu->machine, cpu, 1, 0x1); debug("a0 points to: "); dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); debug("\n"); fatal("ARCBIOS: unimplemented PRIVATE vector 0x%x\n", vector); cpu->running = 0; } } /* * arcbios_emul(): ARCBIOS emulation * * 0x0c Halt() * 0x10 PowerDown() * 0x14 Restart() * 0x18 Reboot() * 0x1c EnterInteractiveMode() * 0x20 ReturnFromMain() * 0x24 GetPeer(node) * 0x28 GetChild(node) * 0x2c GetParent(node) * 0x30 GetConfigurationData(config_data, node) * 0x3c GetComponent(name) * 0x44 GetSystemId() * 0x48 GetMemoryDescriptor(void *) * 0x50 GetTime() * 0x54 GetRelativeTime() * 0x5c Open(path, mode, &fileid) * 0x60 Close(handle) * 0x64 Read(handle, &buf, len, &actuallen) * 0x6c Write(handle, buf, len, &returnlen) * 0x70 Seek(handle, &offset, len) * 0x78 GetEnvironmentVariable(char *) * 0x7c SetEnvironmentVariable(char *, char *) * 0x80 GetFileInformation(handle, buf) * 0x88 FlushAllCaches() * 0x90 GetDisplayStatus(uint32_t handle) * 0x100 undocumented IRIX (?) */ int arcbios_emul(struct cpu *cpu) { struct machine *machine = cpu->machine; int vector = cpu->pc & 0xfff; int i, j, handle; unsigned char ch2; unsigned char buf[40]; if (cpu->pc >= ARC_PRIVATE_ENTRIES && cpu->pc < ARC_PRIVATE_ENTRIES + 100*sizeof(uint32_t)) { arcbios_private_emul(cpu); return 1; } if (machine->md.arc->arc_64bit) vector /= 2; /* Special case for reboot by jumping to 0xbfc00000: */ if (vector == 0 && (cpu->pc & 0xffffffffULL) == 0xbfc00000ULL) vector = 0x18; switch (vector) { case 0x0c: /* Halt() */ case 0x10: /* PowerDown() */ case 0x14: /* Restart() */ case 0x18: /* Reboot() */ case 0x1c: /* EnterInteractiveMode() */ case 0x20: /* ReturnFromMain() */ debug("[ ARCBIOS Halt() or similar ]\n"); /* Halt all CPUs. */ for (i=0; incpus; i++) { machine->cpus[i]->running = 0; } machine->exit_without_entering_debugger = 1; break; case 0x24: /* GetPeer(node) */ if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) { /* NULL ptr argument: return NULL. */ cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; } else { uint64_t peer; cpu->memory_rw(cpu, cpu->mem, cpu->cd.mips.gpr[MIPS_GPR_A0] - 3 * machine->md.arc->wordlen, &buf[0], machine->md.arc->wordlen, MEM_READ, CACHE_NONE); if (machine->md.arc->arc_64bit) { if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp; tmp = buf[0]; buf[0] = buf[7]; buf[7] = tmp; tmp = buf[1]; buf[1] = buf[6]; buf[6] = tmp; tmp = buf[2]; buf[2] = buf[5]; buf[5] = tmp; tmp = buf[3]; buf[3] = buf[4]; buf[4] = tmp; } peer = (uint64_t)buf[0] + ((uint64_t)buf[1]<<8) + ((uint64_t)buf[2]<<16) + ((uint64_t)buf[3]<<24) + ((uint64_t)buf[4]<<32) + ((uint64_t)buf[5]<<40) + ((uint64_t)buf[6]<<48) + ((uint64_t)buf[7]<<56); } else { if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp; tmp = buf[0]; buf[0] = buf[3]; buf[3] = tmp; tmp = buf[1]; buf[1] = buf[2]; buf[2] = tmp; } peer = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); } cpu->cd.mips.gpr[MIPS_GPR_V0] = peer? (peer + 3 * machine->md.arc->wordlen) : 0; if (!machine->md.arc->arc_64bit) cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t) (int32_t) cpu->cd.mips.gpr[MIPS_GPR_V0]; } debug("[ ARCBIOS GetPeer(node 0x%016" PRIx64"): 0x%016" PRIx64 " ]\n", (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_V0]); break; case 0x28: /* GetChild(node) */ /* 0 for the root, non-0 for children: */ if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) cpu->cd.mips.gpr[MIPS_GPR_V0] = FIRST_ARC_COMPONENT + machine->md.arc->wordlen * 3; else { uint64_t child = 0; cpu->memory_rw(cpu, cpu->mem, cpu->cd.mips.gpr[MIPS_GPR_A0] - 2 * machine->md.arc->wordlen, &buf[0], machine-> md.arc->wordlen, MEM_READ, CACHE_NONE); if (machine->md.arc->arc_64bit) { if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp; tmp = buf[0]; buf[0] = buf[7]; buf[7] = tmp; tmp = buf[1]; buf[1] = buf[6]; buf[6] = tmp; tmp = buf[2]; buf[2] = buf[5]; buf[5] = tmp; tmp = buf[3]; buf[3] = buf[4]; buf[4] = tmp; } child = (uint64_t)buf[0] + ((uint64_t)buf[1]<<8) + ((uint64_t)buf[2]<<16) + ((uint64_t)buf[3]<<24) + ((uint64_t)buf[4]<<32) + ((uint64_t)buf[5]<<40) + ((uint64_t)buf[6]<<48) + ((uint64_t)buf[7]<<56); } else { if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp; tmp = buf[0]; buf[0] = buf[3]; buf[3] = tmp; tmp = buf[1]; buf[1] = buf[2]; buf[2] = tmp; } child = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); } cpu->cd.mips.gpr[MIPS_GPR_V0] = child? (child + 3 * machine->md.arc->wordlen) : 0; if (!machine->md.arc->arc_64bit) cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t) (int32_t)cpu->cd.mips.gpr[MIPS_GPR_V0]; } debug("[ ARCBIOS GetChild(node 0x%016" PRIx64"): 0x%016" PRIx64" ]\n", (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_V0]); break; case 0x2c: /* GetParent(node) */ { uint64_t parent; cpu->memory_rw(cpu, cpu->mem, cpu->cd.mips.gpr[MIPS_GPR_A0] - 1 * machine-> md.arc->wordlen, &buf[0], machine->md.arc->wordlen, MEM_READ, CACHE_NONE); if (machine->md.arc->arc_64bit) { if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp; tmp = buf[0]; buf[0] = buf[7]; buf[7] = tmp; tmp = buf[1]; buf[1] = buf[6]; buf[6] = tmp; tmp = buf[2]; buf[2] = buf[5]; buf[5] = tmp; tmp = buf[3]; buf[3] = buf[4]; buf[4] = tmp; } parent = (uint64_t)buf[0] + ((uint64_t)buf[1]<<8) + ((uint64_t)buf[2]<<16) + ((uint64_t)buf[3]<<24) + ((uint64_t)buf[4]<<32) + ((uint64_t)buf[5]<<40) + ((uint64_t)buf[6]<<48) + ((uint64_t)buf[7]<<56); } else { if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp; tmp = buf[0]; buf[0] = buf[3]; buf[3] = tmp; tmp = buf[1]; buf[1] = buf[2]; buf[2] = tmp; } parent = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); } cpu->cd.mips.gpr[MIPS_GPR_V0] = parent? (parent + 3 * machine->md.arc->wordlen) : 0; if (!machine->md.arc->arc_64bit) cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t) (int32_t) cpu->cd.mips.gpr[MIPS_GPR_V0]; } debug("[ ARCBIOS GetParent(node 0x%016" PRIx64"): 0x%016" PRIx64" ]\n", (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_V0]); break; case 0x30: /* GetConfigurationData(void *configdata, void *node) */ /* fatal("[ ARCBIOS GetConfigurationData(0x%016" PRIx64"," "0x%016" PRIx64") ]\n", (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1]); */ cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EINVAL; for (i=0; imd.arc->n_configuration_data; i++) { /* fatal("configuration_data_component[%i] = " "0x%016" PRIx64"\n", i, (uint64_t) machine-> md.arc->configuration_data_component[i]); */ if (cpu->cd.mips.gpr[MIPS_GPR_A1] == machine->md.arc->configuration_data_component[i]) { cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; for (j=0; j md.arc->configuration_data_len[i]; j++) { unsigned char ch; cpu->memory_rw(cpu, cpu->mem, machine->md.arc-> configuration_data_configdata[i] + j, &ch, 1, MEM_READ, CACHE_NONE); cpu->memory_rw(cpu, cpu->mem, cpu->cd.mips.gpr[MIPS_GPR_A0] + j, &ch, 1, MEM_WRITE, CACHE_NONE); } break; } } break; case 0x3c: /* GetComponent(char *name) */ debug("[ ARCBIOS GetComponent(\""); dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); debug("\") ]\n"); if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) { fatal("[ ARCBIOS GetComponent: NULL ptr ]\n"); } else { unsigned char buf2[500]; int match_index = -1; int match_len = 0; memset(buf2, 0, sizeof(buf2)); for (i=0; i<(ssize_t)sizeof(buf2); i++) { cpu->memory_rw(cpu, cpu->mem, cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &buf2[i], 1, MEM_READ, CACHE_NONE); if (buf2[i] == '\0') i = sizeof(buf); } buf2[sizeof(buf2) - 1] = '\0'; /* "scsi(0)disk(0)rdisk(0)partition(0)" and such. */ /* printf("GetComponent(\"%s\")\n", buf2); */ /* Default to NULL return value. */ cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* Scan the string to component table: */ for (i=0; imd.arc->n_string_to_components; i++) { int m = 0; while (buf2[m] && machine->md.arc-> string_to_component[i][m] && machine->md.arc->string_to_component[i][m] == buf2[m]) m++; if (m > match_len) { match_len = m; match_index = i; } } if (match_index >= 0) { /* printf("Longest match: '%s'\n", machine->md.arc->string_to_component[ match_index]); */ cpu->cd.mips.gpr[MIPS_GPR_V0] = machine->md.arc->string_to_component_value[ match_index]; } } break; case 0x44: /* GetSystemId() */ debug("[ ARCBIOS GetSystemId() ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = SGI_SYSID_ADDR; break; case 0x48: /* void *GetMemoryDescriptor(void *ptr) */ debug("[ ARCBIOS GetMemoryDescriptor(0x%08x) ]\n", (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); /* If a0=NULL, then return the first descriptor: */ if ((uint32_t)cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) cpu->cd.mips.gpr[MIPS_GPR_V0] = machine->md.arc->memdescriptor_base; else { int s = machine->md.arc->arc_64bit? sizeof(struct arcbios_mem64) : sizeof(struct arcbios_mem); int nr = cpu->cd.mips.gpr[MIPS_GPR_A0] - machine->md.arc->memdescriptor_base; nr /= s; nr ++; cpu->cd.mips.gpr[MIPS_GPR_V0] = machine->md.arc->memdescriptor_base + s * nr; if (nr >= machine->md.arc->n_memdescriptors) cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; } break; case 0x50: /* GetTime() */ debug("[ ARCBIOS GetTime() ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0xffffffff80001000ULL; /* TODO! */ break; case 0x54: /* GetRelativeTime() */ debug("[ ARCBIOS GetRelativeTime() ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t)(int32_t)time(NULL); break; case 0x5c: /* Open(char *path, uint32_t mode, uint32_t *fileID) */ debug("[ ARCBIOS Open(\""); dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); debug("\",0x%x,0x%x)", (int)cpu->cd.mips.gpr[MIPS_GPR_A0], (int)cpu->cd.mips.gpr[MIPS_GPR_A1], (int)cpu->cd.mips.gpr[MIPS_GPR_A2]); cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ENOENT; handle = 3; /* TODO: Starting at 0 would require some updates... */ while (machine->md.arc->file_handle_in_use[handle]) { handle ++; if (handle >= ARC_MAX_HANDLES) { cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EMFILE; break; } } if (handle >= ARC_MAX_HANDLES) { fatal("[ ARCBIOS Open: out of file handles ]\n"); } else if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) { fatal("[ ARCBIOS Open: NULL ptr ]\n"); } else { /* * TODO: This is hardcoded to successfully open * anything. It is used by the Windows NT SETUPLDR * program to load stuff from the boot partition. */ unsigned char *buf2; CHECK_ALLOCATION(buf2 = (unsigned char *) malloc(MAX_OPEN_STRINGLEN)); memset(buf2, 0, MAX_OPEN_STRINGLEN); for (i=0; imemory_rw(cpu, cpu->mem, cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &buf2[i], 1, MEM_READ, CACHE_NONE); if (buf2[i] == '\0') i = MAX_OPEN_STRINGLEN; } buf2[MAX_OPEN_STRINGLEN - 1] = '\0'; machine->md.arc->file_handle_string[handle] = (char *)buf2; machine->md.arc->current_seek_offset[handle] = 0; cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ESUCCESS; } if (cpu->cd.mips.gpr[MIPS_GPR_V0] == ARCBIOS_ESUCCESS) { debug(" = handle %i ]\n", (int)handle); store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A2], handle); machine->md.arc->file_handle_in_use[handle] = 1; } else debug(" = ERROR %i ]\n", (int)cpu->cd.mips.gpr[MIPS_GPR_V0]); break; case 0x60: /* Close(uint32_t handle) */ debug("[ ARCBIOS Close(%i) ]\n", (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); if (!machine->md.arc->file_handle_in_use[cpu->cd.mips.gpr[ MIPS_GPR_A0]]) { fatal("ARCBIOS Close(%i): bad handle\n", (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EBADF; } else { machine->md.arc->file_handle_in_use[ cpu->cd.mips.gpr[MIPS_GPR_A0]] = 0; // TODO: Yes, this is a memory leak. But it will be // scrapped in favor of real code after the rewrite (I // hope). //if (machine->md.arc->file_handle_string[ // cpu->cd.mips.gpr[MIPS_GPR_A0]] != NULL) // free(machine->md.arc->file_handle_string[ // cpu->cd.mips.gpr[MIPS_GPR_A0]]); machine->md.arc->file_handle_string[cpu->cd.mips. gpr[MIPS_GPR_A0]] = NULL; cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ESUCCESS; } break; case 0x64: /* Read(handle, void *buf, length, uint32_t *count) */ if (cpu->cd.mips.gpr[MIPS_GPR_A0] == ARCBIOS_STDIN) { int j2, nread = 0, a2; /* * Before going into the loop, make sure stdout * is flushed. If we're using an X11 VGA console, * then it needs to be flushed as well. */ fflush(stdin); fflush(stdout); /* NOTE/TODO: This gives a tick to _everything_ */ for (j2=0; j2tick_functions.n_entries; j2++) machine->tick_functions.f[j2](cpu, machine->tick_functions.extra[j2]); a2 = cpu->cd.mips.gpr[MIPS_GPR_A2]; for (j2=0; j2main_console_handle); if (x < 0) return 0; /* * ESC + '[' should be transformed into 0x9b: * * NOTE/TODO: This makes the behaviour of just * pressing ESC a bit harder to define. */ if (x == 27) { x = console_readchar(cpu-> machine->main_console_handle); if (x == '[' || x == 'O') x = 0x9b; } ch = x; nread ++; cpu->memory_rw(cpu, cpu->mem, cpu->cd.mips.gpr[MIPS_GPR_A1] + j2, &ch, 1, MEM_WRITE, CACHE_NONE); /* NOTE: Only one char, from STDIN: */ j2 = cpu->cd.mips.gpr[MIPS_GPR_A2]; /* :-) */ } store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A3], nread); /* TODO: not EAGAIN? */ cpu->cd.mips.gpr[MIPS_GPR_V0] = nread? ARCBIOS_ESUCCESS: ARCBIOS_EAGAIN; } else { int handleTmp = cpu->cd.mips.gpr[MIPS_GPR_A0]; int disk_type = 0; int disk_id = arcbios_handle_to_disk_id_and_type( machine, handleTmp, &disk_type); uint64_t partition_offset = 0; int res; uint64_t size; /* dummy */ unsigned char *tmp_buf; arcbios_handle_to_start_and_size(machine, handleTmp, &partition_offset, &size); debug("[ ARCBIOS Read(%i,0x%08x,0x%08x,0x%08x) ]\n", (int)cpu->cd.mips.gpr[MIPS_GPR_A0], (int)cpu->cd.mips.gpr[MIPS_GPR_A1], (int)cpu->cd.mips.gpr[MIPS_GPR_A2], (int)cpu->cd.mips.gpr[MIPS_GPR_A3]); CHECK_ALLOCATION(tmp_buf = (unsigned char *) malloc(cpu->cd.mips.gpr[MIPS_GPR_A2])); res = diskimage_access(machine, disk_id, disk_type, 0, partition_offset + machine->md.arc-> current_seek_offset[handleTmp], tmp_buf, cpu->cd.mips.gpr[MIPS_GPR_A2]); /* If the transfer was successful, transfer the data to emulated memory: */ if (res) { uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1]; store_buf(cpu, dst, (char *)tmp_buf, cpu->cd.mips.gpr[MIPS_GPR_A2]); store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A3], cpu->cd.mips.gpr[MIPS_GPR_A2]); machine->md.arc->current_seek_offset[handleTmp] += cpu->cd.mips.gpr[MIPS_GPR_A2]; cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; } else cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EIO; free(tmp_buf); } break; case 0x68: /* GetReadStatus(handle) */ /* * According to arcbios_tty_getchar() in NetBSD's * dev/arcbios/arcbios_tty.c, GetReadStatus should * return 0 if there is something available. * * TODO: Error codes are things like ARCBIOS_EAGAIN. */ if (cpu->cd.mips.gpr[MIPS_GPR_A0] == ARCBIOS_STDIN) { cpu->cd.mips.gpr[MIPS_GPR_V0] = console_charavail( machine->main_console_handle)? 0 : 1; } else { fatal("[ ARCBIOS GetReadStatus(%i) from " "something other than STDIN: TODO ]\n", (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); /* TODO */ cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; } break; case 0x6c: /* Write(handle, buf, len, &returnlen) */ if (cpu->cd.mips.gpr[MIPS_GPR_A0] != ARCBIOS_STDOUT) { /* * TODO: this is just a test */ int handleTmp = cpu->cd.mips.gpr[MIPS_GPR_A0]; int disk_type = 0; int disk_id = arcbios_handle_to_disk_id_and_type( machine, handleTmp, &disk_type); uint64_t partition_offset = 0; int res, tmpi; uint64_t size; /* dummy */ unsigned char *tmp_buf; arcbios_handle_to_start_and_size(machine, handleTmp, &partition_offset, &size); debug("[ ARCBIOS Write(%i,0x%08" PRIx64",%i,0x%08" PRIx64") ]\n", (int) cpu->cd.mips.gpr[MIPS_GPR_A0], (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1], (int) cpu->cd.mips.gpr[MIPS_GPR_A2], (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A3]); CHECK_ALLOCATION(tmp_buf = (unsigned char *) malloc(cpu->cd.mips.gpr[MIPS_GPR_A2])); for (tmpi=0; tmpi<(int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2]; tmpi++) cpu->memory_rw(cpu, cpu->mem, cpu->cd.mips.gpr[MIPS_GPR_A1] + tmpi, &tmp_buf[tmpi], sizeof(char), MEM_READ, CACHE_NONE); res = diskimage_access(machine, disk_id, disk_type, 1, partition_offset + machine->md.arc-> current_seek_offset[handleTmp], tmp_buf, cpu->cd.mips.gpr[MIPS_GPR_A2]); if (res) { store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A3], cpu->cd.mips.gpr[MIPS_GPR_A2]); machine->md.arc->current_seek_offset[handleTmp] += cpu->cd.mips.gpr[MIPS_GPR_A2]; cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; } else cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EIO; free(tmp_buf); } else { for (i=0; i<(int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2]; i++) { unsigned char ch = '\0'; cpu->memory_rw(cpu, cpu->mem, cpu->cd.mips.gpr[MIPS_GPR_A1] + i, &ch, sizeof(ch), MEM_READ, CACHE_NONE); arcbios_putchar(cpu, ch); } } store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A3], cpu->cd.mips.gpr[MIPS_GPR_A2]); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* Success. */ break; case 0x70: /* Seek(uint32_t handle, int64_t *ofs, uint32_t whence): uint32_t */ debug("[ ARCBIOS Seek(%i,0x%08" PRIx64",%i): ", (int) cpu->cd.mips.gpr[MIPS_GPR_A0], (uint64_t)cpu->cd.mips.gpr[MIPS_GPR_A1], (int) cpu->cd.mips.gpr[MIPS_GPR_A2]); if (cpu->cd.mips.gpr[MIPS_GPR_A2] != 0) { fatal("[ ARCBIOS Seek(%i,0x%08" PRIx64",%i): " "UNIMPLEMENTED whence=%i ]\n", (int) cpu->cd.mips.gpr[MIPS_GPR_A0], (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1], (int) cpu->cd.mips.gpr[MIPS_GPR_A2], (int) cpu->cd.mips.gpr[MIPS_GPR_A2]); } { unsigned char bufTmp[8]; uint64_t ofs; cpu->memory_rw(cpu, cpu->mem, cpu->cd.mips.gpr[MIPS_GPR_A1], &bufTmp[0], sizeof(bufTmp), MEM_READ, CACHE_NONE); if (cpu->byte_order == EMUL_BIG_ENDIAN) { unsigned char tmp; tmp = bufTmp[0]; bufTmp[0] = bufTmp[7]; bufTmp[7] = tmp; tmp = bufTmp[1]; bufTmp[1] = bufTmp[6]; bufTmp[6] = tmp; tmp = bufTmp[2]; bufTmp[2] = bufTmp[5]; bufTmp[5] = tmp; tmp = bufTmp[3]; bufTmp[3] = bufTmp[4]; bufTmp[4] = tmp; } ofs = bufTmp[0] + (bufTmp[1] << 8) + (bufTmp[2] << 16) + (bufTmp[3] << 24) + ((uint64_t)bufTmp[4] << 32) + ((uint64_t)bufTmp[5] << 40) + ((uint64_t)bufTmp[6] << 48) + ((uint64_t)bufTmp[7] << 56); machine->md.arc->current_seek_offset[ cpu->cd.mips.gpr[MIPS_GPR_A0]] = ofs; debug("%016" PRIx64" ]\n", (uint64_t) ofs); } cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* Success. */ break; case 0x78: /* GetEnvironmentVariable(char *) */ /* Find the environment variable given by a0: */ for (i=0; i<(ssize_t)sizeof(buf); i++) cpu->memory_rw(cpu, cpu->mem, cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &buf[i], sizeof(char), MEM_READ, CACHE_NONE); buf[sizeof(buf)-1] = '\0'; debug("[ ARCBIOS GetEnvironmentVariable(\"%s\") ]\n", buf); for (i=0; i<0x1000; i++) { /* Matching string at offset i? */ int nmatches = 0; uint64_t envptr = machine->machine_type == MACHINE_SGI ? ARC_ENV_STRINGS_SGI : ARC_ENV_STRINGS; for (j=0; j<(ssize_t)strlen((char *)buf); j++) { cpu->memory_rw(cpu, cpu->mem, (uint64_t)(envptr + i + j), &ch2, sizeof(char), MEM_READ, CACHE_NONE); if (ch2 == buf[j]) nmatches++; } cpu->memory_rw(cpu, cpu->mem, (uint64_t)(envptr + i + strlen((char *)buf)), &ch2, sizeof(char), MEM_READ, CACHE_NONE); if (nmatches == (int)strlen((char *)buf) && ch2=='=') { cpu->cd.mips.gpr[MIPS_GPR_V0] = envptr + i + strlen((char *)buf) + 1; return 1; } } /* Return NULL if string wasn't found. */ cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 0x7c: /* SetEnvironmentVariable(char *, char *) */ debug("[ ARCBIOS SetEnvironmentVariable(\""); dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); debug("\",\""); dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1]); debug("\") ]\n"); /* TODO: This is a dummy. */ cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ESUCCESS; break; case 0x80: /* GetFileInformation() */ debug("[ ARCBIOS GetFileInformation(%i,0x%x): ", (int)cpu->cd.mips.gpr[MIPS_GPR_A0], (int)cpu->cd.mips.gpr[MIPS_GPR_A1]); if (cpu->cd.mips.gpr[MIPS_GPR_A0] >= ARC_MAX_HANDLES) { debug("invalid file handle ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EINVAL; } else if (!machine->md.arc->file_handle_in_use[cpu->cd. mips.gpr[MIPS_GPR_A0]]) { debug("file handle not in use! ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EBADF; } else { debug("'%s' ]\n", machine->md.arc->file_handle_string[ cpu->cd.mips.gpr[MIPS_GPR_A0]]); cpu->cd.mips.gpr[MIPS_GPR_V0] = arcbios_getfileinformation(cpu); } break; case 0x88: /* FlushAllCaches() */ debug("[ ARCBIOS FlushAllCaches(): TODO ]\n"); cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 0x90: /* void *GetDisplayStatus(handle) */ debug("[ ARCBIOS GetDisplayStatus(%i) ]\n", (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); /* TODO: handle different values of 'handle'? */ cpu->cd.mips.gpr[MIPS_GPR_V0] = ARC_DSPSTAT_ADDR; break; case 0x100: /* * Undocumented, used by IRIX. */ debug("[ ARCBIOS: IRIX 0x100 (?) ]\n"); /* TODO */ cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; break; case 0x888: /* * Magical crash if there is no exception handling code. */ fatal("EXCEPTION, but no exception handler installed yet.\n"); quiet_mode = 0; cpu_register_dump(machine, cpu, 1, 0x1); cpu->running = 0; break; default: quiet_mode = 0; cpu_register_dump(machine, cpu, 1, 0x1); debug("a0 points to: "); dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); debug("\n"); fatal("ARCBIOS: unimplemented vector 0x%x\n", vector); cpu->running = 0; } return 1; } /* * arcbios_set_default_exception_handler(): */ void arcbios_set_default_exception_handler(struct cpu *cpu) { /* * The default exception handlers simply jump to 0xbfc88888, * which is then taken care of in arcbios_emul() above. * * 3c1abfc8 lui k0,0xbfc8 * 375a8888 ori k0,k0,0x8888 * 03400008 jr k0 * 00000000 nop */ store_32bit_word(cpu, 0xffffffff80000000ULL, 0x3c1abfc8); store_32bit_word(cpu, 0xffffffff80000004ULL, 0x375a8888); store_32bit_word(cpu, 0xffffffff80000008ULL, 0x03400008); store_32bit_word(cpu, 0xffffffff8000000cULL, 0x00000000); store_32bit_word(cpu, 0xffffffff80000080ULL, 0x3c1abfc8); store_32bit_word(cpu, 0xffffffff80000084ULL, 0x375a8888); store_32bit_word(cpu, 0xffffffff80000088ULL, 0x03400008); store_32bit_word(cpu, 0xffffffff8000008cULL, 0x00000000); store_32bit_word(cpu, 0xffffffff80000180ULL, 0x3c1abfc8); store_32bit_word(cpu, 0xffffffff80000184ULL, 0x375a8888); store_32bit_word(cpu, 0xffffffff80000188ULL, 0x03400008); store_32bit_word(cpu, 0xffffffff8000018cULL, 0x00000000); } /* * arcbios_add_other_components(): * * TODO: How should this be synched with the hardware devices * added in machine.c? */ static void arcbios_add_other_components(struct machine *machine, uint64_t system) { struct cpu *cpu = machine->cpus[0]; if (machine->machine_type == MACHINE_ARC && (machine->machine_subtype == MACHINE_ARC_JAZZ_PICA || machine->machine_subtype == MACHINE_ARC_JAZZ_MAGNUM)) { uint64_t jazzbus, ali_s3, vxl; uint64_t diskcontroller, floppy, kbdctl, kbd; uint64_t ptrctl, ptr, paral, audio; uint64_t eisa, scsi; /* uint64_t serial1, serial2; */ jazzbus = arcbios_addchild_manual(cpu, COMPONENT_CLASS_AdapterClass, COMPONENT_TYPE_MultiFunctionAdapter, 0, 1, 2, 0, 0xffffffff, "Jazz-Internal Bus", system, NULL, 0); /* * DisplayController, needed by NetBSD: * TODO: NetBSD still doesn't use it :( */ switch (machine->machine_subtype) { case MACHINE_ARC_JAZZ_PICA: /* Default TLB entries on PICA-61: */ /* 7: 256K, asid: 0x0, v: 0xe1000000, p0: 0xfff00000(2.VG), p1: 0x0(0..G) */ mips_coproc_tlb_set_entry(cpu, 7, 262144, 0xffffffffe1000000ULL, 0x0fff00000ULL, 0, 1, 0, 0, 0, 1, 0, 2, 0); /* 8: 64K, asid: 0x0, v: 0xe0000000, p0: 0x80000000(2DVG), p1: 0x0(0..G) */ mips_coproc_tlb_set_entry(cpu, 8, 65536, 0xffffffffe0000000ULL, 0x080000000ULL, 0, 1, 0, 1, 0, 1, 0, 2, 0); /* 9: 64K, asid: 0x0, v: 0xe00e0000, p0: 0x800e0000(2DVG), p1: 0x800f0000(2DVG) */ mips_coproc_tlb_set_entry(cpu, 9, 65536, (uint64_t)0xffffffffe00e0000ULL, (uint64_t)0x0800e0000ULL, (uint64_t)0x0800f0000ULL, 1, 1, 1, 1, 1, 0, 2, 2); /* 10: 4K, asid: 0x0, v: 0xe0100000, p0: 0xf0000000(2DVG), p1: 0x0(0..G) */ mips_coproc_tlb_set_entry(cpu, 10, 4096, (uint64_t)0xffffffffe0100000ULL, (uint64_t)0x0f0000000ULL, 0,1, 0, 1, 0, 1, 0, 2, 0); /* 11: 1M, asid: 0x0, v: 0xe0200000, p0: 0x60000000(2DVG), p1: 0x60100000(2DVG) */ mips_coproc_tlb_set_entry(cpu, 11, 1048576, 0xffffffffe0200000ULL, 0x060000000ULL, 0x060100000ULL,1,1,1,1,1, 0, 2, 2); /* 12: 1M, asid: 0x0, v: 0xe0400000, p0: 0x60200000(2DVG), p1: 0x60300000(2DVG) */ mips_coproc_tlb_set_entry(cpu, 12, 1048576, 0xffffffffe0400000ULL, 0x060200000ULL, 0x060300000ULL, 1, 1, 1, 1, 1, 0, 2, 2); /* 13: 4M, asid: 0x0, v: 0xe0800000, p0: 0x40000000(2DVG), p1: 0x40400000(2DVG) */ mips_coproc_tlb_set_entry(cpu, 13, 1048576*4, 0xffffffffe0800000ULL, 0x040000000ULL, 0x040400000ULL, 1, 1, 1, 1, 1, 0, 2, 2); /* 14: 16M, asid: 0x0, v: 0xe2000000, p0: 0x90000000(2DVG), p1: 0x91000000(2DVG) */ mips_coproc_tlb_set_entry(cpu, 14, 1048576*16, 0xffffffffe2000000ULL, 0x090000000ULL, 0x091000000ULL, 1, 1, 1, 1, 1, 0, 2, 2); if (machine->x11_md.in_use) { ali_s3 = arcbios_addchild_manual(cpu, COMPONENT_CLASS_ControllerClass, COMPONENT_TYPE_DisplayController, COMPONENT_FLAG_ConsoleOut | COMPONENT_FLAG_Output, 1, 2, 0, 0xffffffff, "ALI_S3", jazzbus, NULL, 0); arcbios_addchild_manual(cpu, COMPONENT_CLASS_PeripheralClass, COMPONENT_TYPE_MonitorPeripheral, COMPONENT_FLAG_ConsoleOut | COMPONENT_FLAG_Output, 1, 2, 0, 0xffffffff, "1024x768", ali_s3, NULL, 0); } break; case MACHINE_ARC_JAZZ_MAGNUM: if (machine->x11_md.in_use) { vxl = arcbios_addchild_manual(cpu, COMPONENT_CLASS_ControllerClass, COMPONENT_TYPE_DisplayController, COMPONENT_FLAG_ConsoleOut | COMPONENT_FLAG_Output, 1, 2, 0, 0xffffffff, "VXL", jazzbus, NULL, 0); arcbios_addchild_manual(cpu, COMPONENT_CLASS_PeripheralClass, COMPONENT_TYPE_MonitorPeripheral, COMPONENT_FLAG_ConsoleOut | COMPONENT_FLAG_Output, 1, 2, 0, 0xffffffff, "1024x768", vxl, NULL, 0); } break; } diskcontroller = arcbios_addchild_manual(cpu, COMPONENT_CLASS_ControllerClass, COMPONENT_TYPE_DiskController, COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, 1, 2, 0, 0xffffffff, "I82077", jazzbus, NULL, 0); floppy = arcbios_addchild_manual(cpu, COMPONENT_CLASS_PeripheralClass, COMPONENT_TYPE_FloppyDiskPeripheral, COMPONENT_FLAG_Removable | COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, 1, 2, 0, 0xffffffff, NULL, diskcontroller, NULL, 0); kbdctl = arcbios_addchild_manual(cpu, COMPONENT_CLASS_ControllerClass, COMPONENT_TYPE_KeyboardController, COMPONENT_FLAG_ConsoleIn | COMPONENT_FLAG_Input, 1, 2, 0, 0xffffffff, "I8742", jazzbus, NULL, 0); kbd = arcbios_addchild_manual(cpu, COMPONENT_CLASS_PeripheralClass, COMPONENT_TYPE_KeyboardPeripheral, COMPONENT_FLAG_ConsoleIn | COMPONENT_FLAG_Input, 1, 2, 0, 0xffffffff, "PCAT_ENHANCED", kbdctl, NULL, 0); ptrctl = arcbios_addchild_manual(cpu, COMPONENT_CLASS_ControllerClass, COMPONENT_TYPE_PointerController, COMPONENT_FLAG_Input, 1, 2, 0, 0xffffffff, "I8742", jazzbus, NULL, 0); ptr = arcbios_addchild_manual(cpu, COMPONENT_CLASS_PeripheralClass, COMPONENT_TYPE_PointerPeripheral, COMPONENT_FLAG_Input, 1, 2, 0, 0xffffffff, "PS2 MOUSE", ptrctl, NULL, 0); /* These cause Windows NT to bug out. */ #if 0 serial1 = arcbios_addchild_manual(cpu, COMPONENT_CLASS_ControllerClass, COMPONENT_TYPE_SerialController, COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, 1, 2, 0, 0xffffffff, "COM1", jazzbus, NULL, 0); serial2 = arcbios_addchild_manual(cpu, COMPONENT_CLASS_ControllerClass, COMPONENT_TYPE_SerialController, COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, 1, 2, 0, 0xffffffff, "COM1", jazzbus, NULL, 0); #endif paral = arcbios_addchild_manual(cpu, COMPONENT_CLASS_ControllerClass, COMPONENT_TYPE_ParallelController, COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, 1, 2, 0, 0xffffffff, "LPT1", jazzbus, NULL, 0); audio = arcbios_addchild_manual(cpu, COMPONENT_CLASS_ControllerClass, COMPONENT_TYPE_AudioController, COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, 1, 2, 0, 0xffffffff, "MAGNUM", jazzbus, NULL, 0); eisa = arcbios_addchild_manual(cpu, COMPONENT_CLASS_AdapterClass, COMPONENT_TYPE_EISAAdapter, 0, 1, 2, 0, 0xffffffff, "EISA", system, NULL, 0); { unsigned char config[78]; memset(config, 0, sizeof(config)); /* config data version: 1, revision: 2, count: 4 */ config[0] = 0x01; config[1] = 0x00; config[2] = 0x02; config[3] = 0x00; config[4] = 0x04; config[5] = 0x00; config[6] = 0x00; config[7] = 0x00; /* type: Interrupt share_disposition: DeviceExclusive, flags: LevelSensitive level: 4, vector: 22, reserved1: 0 */ config[8] = arc_CmResourceTypeInterrupt; config[9] = arc_CmResourceShareDeviceExclusive; config[10] = arc_CmResourceInterruptLevelSensitive; config[12] = 4; config[16] = 22; config[20] = 0; /* type: Memory share_disposition: DeviceExclusive, flags: ReadWrite start: 0x 0 80002000, length: 0x1000 */ config[24] = arc_CmResourceTypeMemory; config[25] = arc_CmResourceShareDeviceExclusive; config[26] = arc_CmResourceMemoryReadWrite; config[28] = 0x00; config[29] = 0x20; config[30] = 0x00; config[31] = 0x80; config[32] = 0x00; config[33] = 0x00; config[34] = 0x00; config[35] = 0x00; config[36] = 0x00; config[37] = 0x10; config[38] = 0x00; config[39] = 0x00; /* type: DMA share_disposition: DeviceExclusive, flags: 0x0 channel: 0, port: 0, reserved1: 0 */ config[40] = arc_CmResourceTypeDMA; config[41] = arc_CmResourceShareDeviceExclusive; /* 42..43 = flags, 44,45,46,47 = channel, 48,49,50,51 = port, 52,53,54,55 = reserved */ /* type: DeviceSpecific share_disposition: DeviceExclusive, flags: 0x0 datasize: 6, reserved1: 0, reserved2: 0 data: [0x1:0x0:0x2:0x0:0x7:0x30] */ config[56] = arc_CmResourceTypeDeviceSpecific; config[57] = arc_CmResourceShareDeviceExclusive; /* 58,59 = flags 60,61,62,63 = data size, 64..71 = reserved */ config[60] = 6; /* 72..77 = the data */ config[72] = 0x01; config[73] = 0x00; config[74] = 0x02; config[75] = 0x00; config[76] = 0x07; config[77] = 0x30; scsi = arcbios_addchild_manual(cpu, COMPONENT_CLASS_AdapterClass, COMPONENT_TYPE_SCSIAdapter, 0, 1, 2, 0, 0xffffffff, "ESP216", system, config, sizeof(config)); arcbios_register_scsicontroller(machine, scsi); } } } /* * arcbios_console_init(): * * Called from machine.c whenever an ARC-based machine is running with * a graphical VGA-style framebuffer, which can be used as console. */ void arcbios_console_init(struct machine *machine, uint64_t vram, uint64_t ctrlregs) { if (machine->md.arc == NULL) { CHECK_ALLOCATION(machine->md.arc = (struct machine_arcbios *) malloc(sizeof(struct machine_arcbios))); memset(machine->md.arc, 0, sizeof(struct machine_arcbios)); } machine->md.arc->vgaconsole = 1; machine->md.arc->console_vram = vram; machine->md.arc->console_ctrlregs = ctrlregs; machine->md.arc->console_maxx = ARC_CONSOLE_MAX_X; machine->md.arc->console_maxy = ARC_CONSOLE_MAX_Y; machine->md.arc->in_escape_sequence = 0; machine->md.arc->escape_sequence[0] = '\0'; } /* * arc_environment_setup(): * * Initialize the emulated environment variables. */ static void arc_environment_setup(struct machine *machine, int is64bit, const char *primary_ether_addr) { size_t bootpath_len = 500; char *init_bootpath; uint64_t addr, addr2; struct cpu *cpu = machine->cpus[0]; /* * Boot string in ARC format: * * TODO: How about floppies? multi()disk()fdisk() * Is tftp() good for netbooting? */ CHECK_ALLOCATION(init_bootpath = (char *) malloc(bootpath_len)); init_bootpath[0] = '\0'; if (machine->bootdev_id < 0 || machine->force_netboot) { snprintf(init_bootpath, bootpath_len, "tftp()"); } else { /* TODO: Make this nicer. */ if (machine->machine_type == MACHINE_SGI) { if (machine->machine_subtype == 30) strlcat(init_bootpath, "xio(0)pci(15)", bootpath_len); if (machine->machine_subtype == 32) strlcat(init_bootpath, "pci(0)", bootpath_len); } if (diskimage_is_a_cdrom(machine, machine->bootdev_id, machine->bootdev_type)) snprintf(init_bootpath + strlen(init_bootpath), bootpath_len - strlen(init_bootpath), "scsi(0)cdrom(%i)fdisk(0)", machine->bootdev_id); else snprintf(init_bootpath + strlen(init_bootpath), bootpath_len - strlen(init_bootpath), "scsi(0)disk(%i)rdisk(0)partition(1)", machine->bootdev_id); } if (machine->machine_type == MACHINE_ARC) strlcat(init_bootpath, "\\", bootpath_len); CHECK_ALLOCATION(machine->bootstr = (char *) malloc(ARC_BOOTSTR_BUFLEN)); strlcpy(machine->bootstr, init_bootpath, ARC_BOOTSTR_BUFLEN); if (strlcat(machine->bootstr, machine->boot_kernel_filename, ARC_BOOTSTR_BUFLEN) >= ARC_BOOTSTR_BUFLEN) { fprintf(stderr, "boot string too long?\n"); exit(1); } /* Boot args., eg "-a" */ machine->bootarg = machine->boot_string_argument; /* argc, argv, envp in a0, a1, a2: */ cpu->cd.mips.gpr[MIPS_GPR_A0] = 0; /* note: argc is increased later */ /* TODO: not needed? */ cpu->cd.mips.gpr[MIPS_GPR_SP] = (int64_t)(int32_t) (machine->physical_ram_in_mb * 1048576 + 0x80000000 - 0x2080); /* Set up argc/argv: */ addr = ARC_ENV_STRINGS; addr2 = ARC_ARGV_START; cpu->cd.mips.gpr[MIPS_GPR_A1] = addr2; /* bootstr: */ store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, machine->bootstr, &addr); cpu->cd.mips.gpr[MIPS_GPR_A0] ++; /* bootarg: */ if (machine->bootarg[0] != '\0') { store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, machine->bootarg, &addr); cpu->cd.mips.gpr[MIPS_GPR_A0] ++; } store_pointer_and_advance(cpu, &addr2, 0, is64bit); cpu->cd.mips.gpr[MIPS_GPR_A2] = addr2; if (machine->machine_type == MACHINE_SGI) { /* * The SGI O2 PROM contains an "env" section header like this: * * 00004000 00 00 00 00 00 00 00 00 53 48 44 52 00 00 04 00 |........SHDR....| * 00004010 03 03 00 00 65 6e 76 00 00 00 00 00 00 00 00 00 |....env.........| * 00004020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00004030 00 00 00 00 31 2e 30 00 00 00 00 00 13 18 11 ae |....1.0.........| * * followed by environment variables at 0x4000. It is not required * by NetBSD/OpenBSD/Linux, but Irix seems to hardcodedly look into * the PROM address space for this header. */ store_32bit_word(cpu, ARC_ENV_SGI + 0x08, 0x53484452); store_32bit_word(cpu, ARC_ENV_SGI + 0x0c, 0x00000400); store_32bit_word(cpu, ARC_ENV_SGI + 0x10, 0x03030000); store_32bit_word(cpu, ARC_ENV_SGI + 0x14, 0x656e7600); store_32bit_word(cpu, ARC_ENV_SGI + 0x34, 0x312e3000); store_32bit_word(cpu, ARC_ENV_SGI + 0x3c, 0x131811ae); addr = ARC_ENV_STRINGS_SGI; } /* * Add environment variables. For each variable, add it * as a string using add_environment_string(), and add a * pointer to it to the ARC_ENV_POINTERS array. */ if (machine->machine_type == MACHINE_SGI) { if (machine->x11_md.in_use) { store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "ConsoleIn=keyboard()", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "ConsoleOut=video()", &addr); /* g for graphical mode. G for graphical mode with SGI logo visible on Irix? */ store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "console=g", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "gfx=alive", &addr); } else { store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "ConsoleIn=serial(0)", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "ConsoleOut=serial(0)", &addr); /* 'd' or 'd2' in Irix, 'ttyS0' in Linux? */ store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "console=d", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "gfx=dead", &addr); } store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "AutoLoad=No", &addr); if (machine->bootdev_id < 0 || machine->force_netboot) { /* * diskless=1 means boot from network disk? (nfs?) * diskless=2 means boot from network tape? */ store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "diskless=1", &addr); // store_pointer_and_advance(cpu, &addr2, addr, is64bit); // add_environment_string(cpu, "tapedevice=bootp()10.0.0.2:/dev/tape", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "bootfile=bootp()10.0.0.2:/var/boot/client/unix", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "SystemPartition=bootp()10.0.0.2:/var/boot/client", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "root=xyz", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "OSLoadPartition=bootp()10.0.0.2:/var/boot/client", &addr); } else { store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "diskless=0", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "SystemPartition=pci(0)scsi(0)disk(2)rdisk(0)partition(8)", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "OSLoadPartition=pci(0)scsi(0)disk(2)rdisk(0)partition(0)", &addr); } store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "volume=80", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "sgilogo=y", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "monitor=h", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "TimeZone=GMT", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "nogfxkbd=1", &addr); /* TODO IP30: 'xio(0)pci(15)scsi(0)disk(1)rdisk(0)partition(0)' */ store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "OSLoadFilename=/unix", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "OSLoader=sash", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "kernname=unix", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "rbaud=9600", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "rebound=y", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "crt_option=1", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "netaddr=10.0.0.1", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "netmask=255.0.0.0", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "dlserver=10.0.0.2", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "srvaddr=10.0.0.2", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "keybd=US", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "cpufreq=3", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "dbaud=9600", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, primary_ether_addr, &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "verbose=1", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); // showconfig 0 means don't show. 1 means show some. // 2 means show more. TODO: higher values? add_environment_string(cpu, "showconfig=255", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "diagmode=v", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "debug_bigmem=1", &addr); } else { char *tmp; size_t mlen = ARC_BOOTSTR_BUFLEN; CHECK_ALLOCATION(tmp = (char *) malloc(mlen)); snprintf(tmp, mlen, "OSLOADOPTIONS=%s", machine->bootarg); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, tmp, &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); snprintf(tmp, mlen, "OSLOADPARTITION=scsi(0)disk(%d)rdisk(0)partition(1)", machine->bootdev_id); add_environment_string(cpu, tmp, &addr); free(tmp); if (machine->x11_md.in_use) { store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "CONSOLEIN=multi()key()keyboard()console()", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "CONSOLEOUT=multi()video()monitor()console()", &addr); } else { /* TODO: serial console for ARC? */ store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "CONSOLEIN=multi()serial(0)", &addr); store_pointer_and_advance(cpu, &addr2, addr, is64bit); add_environment_string(cpu, "CONSOLEOUT=multi()serial(0)", &addr); } } /* End the environment strings with an empty zero-terminated string, and the envp array with a NULL pointer. */ add_environment_string(cpu, "", &addr); /* the end */ store_pointer_and_advance(cpu, &addr2, 0, is64bit); /* Return address: (0x20 = ReturnFromMain()) */ cpu->cd.mips.gpr[MIPS_GPR_RA] = ARC_FIRMWARE_ENTRIES + 0x20; } /* * arcbios_init(): * * Should be called before any other arcbios function is used. An exception * is arcbios_console_init(), which may be called before this function. * * TODO: Refactor; this is too long. */ void arcbios_init(struct machine *machine, int is64bit, uint64_t sgi_ram_offset, const char *primary_ether_addr, uint8_t *primary_ether_macaddr) { int i, alloclen = 20; char *name; uint64_t arc_reserved, mem_base, mem_count; struct cpu *cpu = machine->cpus[0]; struct arcbios_sysid arcbios_sysid; struct arcbios_dsp_stat arcbios_dsp_stat; uint64_t system = 0; struct arcbios_spb arcbios_spb; struct arcbios_spb_64 arcbios_spb_64; if (machine->md.arc == NULL) { CHECK_ALLOCATION(machine->md.arc = (struct machine_arcbios *) malloc(sizeof(struct machine_arcbios))); memset(machine->md.arc, 0, sizeof(struct machine_arcbios)); } machine->md.arc->arc_64bit = is64bit; machine->md.arc->wordlen = is64bit? sizeof(uint64_t) : sizeof(uint32_t); machine->md.arc->next_component_address = FIRST_ARC_COMPONENT; machine->md.arc->configuration_data_next_addr = ARC_CONFIG_DATA_ADDR; if (machine->physical_ram_in_mb < 16) fprintf(stderr, "WARNING! The ARC platform specification " "doesn't allow less than 16 MB of RAM. Continuing " "anyway.\n"); /* File handles 0, 1, and 2 are stdin, stdout, and stderr. */ for (i=0; imd.arc->file_handle_in_use[i] = i<3? 1 : 0; machine->md.arc->file_handle_string[i] = i>=3? NULL : (i==0? "(stdin)" : (i==1? "(stdout)" : "(stderr)")); machine->md.arc->current_seek_offset[i] = 0; } if (!machine->x11_md.in_use) machine->md.arc->vgaconsole = 0; if (machine->md.arc->vgaconsole) { char tmpstr[100]; int x, y; machine->md.arc->console_curcolor = 0x1f; for (y=0; ymd.arc->console_maxy; y++) for (x=0; xmd.arc->console_maxx; x++) arcbios_putcell(cpu, ' ', x, y); machine->md.arc->console_curx = 0; machine->md.arc->console_cury = 0; arcbios_putstring(cpu, "GXemul " VERSION" ARCBIOS emulation\n"); snprintf(tmpstr, sizeof(tmpstr), "%i cpu%s (%s), %i MB " "memory\n\n", machine->ncpus, machine->ncpus > 1? "s" : "", cpu->cd.mips.cpu_type.name, machine->physical_ram_in_mb); arcbios_putstring(cpu, tmpstr); } arcbios_set_default_exception_handler(cpu); memset(&arcbios_sysid, 0, sizeof(arcbios_sysid)); if (machine->machine_type == MACHINE_SGI) { /* Vendor ID, max 8 chars: */ strncpy(arcbios_sysid.VendorId, "SGI", 3); switch (machine->machine_subtype) { case 22: strncpy(arcbios_sysid.ProductId, "87654321", 8); /* some kind of ID? */ break; case 32: strncpy(arcbios_sysid.ProductId, "8", 1); /* 6 or 8 (?) */ break; default: snprintf(arcbios_sysid.ProductId, 8, "IP%i", machine->machine_subtype); } } else { switch (machine->machine_subtype) { case MACHINE_ARC_JAZZ_PICA: strncpy(arcbios_sysid.VendorId, "MIPS MAG", 8); strncpy(arcbios_sysid.ProductId, "ijkl", 4); break; case MACHINE_ARC_JAZZ_MAGNUM: strncpy(arcbios_sysid.VendorId, "MIPS MAG", 8); strncpy(arcbios_sysid.ProductId, "ijkl", 4); break; default: fatal("error in machine.c sysid\n"); exit(1); } } store_buf(cpu, SGI_SYSID_ADDR, (char *)&arcbios_sysid, sizeof(arcbios_sysid)); arcbios_get_dsp_stat(cpu, &arcbios_dsp_stat); store_buf(cpu, ARC_DSPSTAT_ADDR, (char *)&arcbios_dsp_stat, sizeof(arcbios_dsp_stat)); /* * The first 12 MBs of RAM are simply reserved... this simplifies * things a lot. If there's more than 512MB of RAM, it has to be * split in two, according to the ARC spec. This code creates a * number of chunks of at most 512MB each. * * NOTE: The region of physical address space between 0x10000000 and * 0x1fffffff (256 - 512 MB) is usually occupied by memory mapped * devices, so that portion is "lost". */ machine->md.arc->memdescriptor_base = ARC_MEMDESC_ADDR; arc_reserved = 0x2000; if (machine->machine_type == MACHINE_SGI) arc_reserved = 0x4000; arcbios_add_memory_descriptor(cpu, 0, arc_reserved, ARCBIOS_MEM_FirmwarePermanent); arcbios_add_memory_descriptor(cpu, sgi_ram_offset + arc_reserved, 0x60000-arc_reserved, ARCBIOS_MEM_FirmwareTemporary); mem_base = 12; mem_base += sgi_ram_offset / 1048576; while (mem_base < machine->physical_ram_in_mb+sgi_ram_offset/1048576) { mem_count = machine->physical_ram_in_mb+sgi_ram_offset/1048576 - mem_base; /* Skip the 256-512MB region (for devices) */ if (mem_base < 256 && mem_base + mem_count > 256) { mem_count = 256-mem_base; } /* At most 512MB per descriptor (at least the first 512MB must be separated this way, according to the ARC spec) */ if (mem_count > 512) mem_count = 512; arcbios_add_memory_descriptor(cpu, mem_base * 1048576, mem_count * 1048576, ARCBIOS_MEM_FreeMemory); mem_base += mem_count; /* Skip the devices: */ if (mem_base == 256) mem_base = 512; } /* * Components: (this is an example of what a system could look like) * * [System] * [CPU] (one for each cpu) * [FPU] (one for each cpu) * [CPU Caches] * [Memory] * [Ethernet] * [Serial] * [SCSI] * [Disk] * * Here's a good list of what hardware is in different IP-models: * http://www.linux-mips.org/archives/linux-mips/2001-03/msg00101.html */ if (machine->machine_name == NULL) fatal("ERROR: machine_name == NULL\n"); /* Add the root node: */ switch (machine->machine_type) { case MACHINE_SGI: CHECK_ALLOCATION(name = (char *) malloc(alloclen)); snprintf(name, alloclen, "SGI-IP%i", machine->machine_subtype); /* A very special case for IP24 (which identifies itself as an IP22): */ if (machine->machine_subtype == 24) snprintf(name, alloclen, "SGI-IP22"); break; case MACHINE_ARC: /* ARC: */ switch (machine->machine_subtype) { case MACHINE_ARC_JAZZ_PICA: name = strdup("PICA-61"); break; case MACHINE_ARC_JAZZ_MAGNUM: name = strdup("Microsoft-Jazz"); break; default: fatal("Unimplemented ARC machine type %i\n", machine->machine_subtype); exit(1); } break; default: fatal("ERROR: non-SGI and non-ARC?\n"); exit(1); } system = arcbios_addchild_manual(cpu, COMPONENT_CLASS_SystemClass, COMPONENT_TYPE_ARC, 0,1,2,0, 0xffffffff, name, 0/*ROOT*/, NULL, 0); debug("ARC system @ 0x%" PRIx64" (\"%s\")\n", (uint64_t) system, name); /* * Add tree nodes for CPUs and their caches: */ for (i=0; incpus; i++) { uint64_t cpuaddr, fpu=0, picache, pdcache, sdcache=0; int cache_size, cache_line_size; unsigned int jj; char arc_cpu_name[100]; char arc_fpc_name[105]; snprintf(arc_cpu_name, sizeof(arc_cpu_name), "MIPS-%s", machine->cpu_name); arc_cpu_name[sizeof(arc_cpu_name)-1] = 0; for (jj=0; jj= 'a' && arc_cpu_name[jj] <= 'z') arc_cpu_name[jj] += ('A' - 'a'); strlcpy(arc_fpc_name, arc_cpu_name, sizeof(arc_fpc_name)); strlcat(arc_fpc_name, "FPC", sizeof(arc_fpc_name)); cpuaddr = arcbios_addchild_manual(cpu, COMPONENT_CLASS_ProcessorClass, COMPONENT_TYPE_CPU, 0, 1, 2, i, 0xffffffff, arc_cpu_name, system, NULL, 0); /* * TODO: This was in the ARC specs, but it isn't really used * by ARC implementations? At least SGI-IP32 uses it. */ if (machine->machine_type == MACHINE_SGI) fpu = arcbios_addchild_manual(cpu, COMPONENT_CLASS_ProcessorClass, COMPONENT_TYPE_FPU, 0, 1, 2, 0, 0xffffffff, arc_fpc_name, cpuaddr, NULL, 0); cache_size = DEFAULT_PCACHE_SIZE - 12; if (cpu->cd.mips.cache_picache) cache_size = cpu->cd.mips.cache_picache - 12; if (cache_size < 0) cache_size = 0; cache_line_size = DEFAULT_PCACHE_LINESIZE; if (cpu->cd.mips.cache_picache_linesize) cache_line_size = cpu->cd.mips.cache_picache_linesize; if (cache_line_size < 0) cache_line_size = 0; picache = arcbios_addchild_manual(cpu, COMPONENT_CLASS_CacheClass, COMPONENT_TYPE_PrimaryICache, 0, 1, 2, /* * Key bits: 0xXXYYZZZZ * XX is refill-size. * Cache line size is 1 << YY, * Cache size is 4KB << ZZZZ. */ 0x01000000 + (cache_line_size << 16) + cache_size, /* 32 bytes per line, default = 32 KB total */ 0xffffffff, NULL, cpuaddr, NULL, 0); cache_size = DEFAULT_PCACHE_SIZE - 12; if (cpu->cd.mips.cache_pdcache) cache_size = cpu->cd.mips.cache_pdcache - 12; if (cache_size < 0) cache_size = 0; cache_line_size = DEFAULT_PCACHE_LINESIZE; if (cpu->cd.mips.cache_pdcache_linesize) cache_line_size = cpu->cd.mips.cache_pdcache_linesize; if (cache_line_size < 0) cache_line_size = 0; pdcache = arcbios_addchild_manual(cpu, COMPONENT_CLASS_CacheClass, COMPONENT_TYPE_PrimaryDCache, 0, 1, 2, /* * Key bits: 0xYYZZZZ * Cache line size is 1 << YY, * Cache size is 4KB << ZZZZ. */ 0x01000000 + (cache_line_size << 16) + cache_size, /* 32 bytes per line, default = 32 KB total */ 0xffffffff, NULL, cpuaddr, NULL, 0); if (cpu->cd.mips.cache_secondary >= 12) { cache_size = cpu->cd.mips.cache_secondary - 12; cache_line_size = 6; /* 64 bytes default */ if (cpu->cd.mips.cache_secondary_linesize) cache_line_size = cpu->cd.mips. cache_secondary_linesize; if (cache_line_size < 0) cache_line_size = 0; sdcache = arcbios_addchild_manual(cpu, COMPONENT_CLASS_CacheClass, COMPONENT_TYPE_SecondaryDCache, 0, 1, 2, /* * Key bits: 0xYYZZZZ * Cache line size is 1 << YY, * Cache size is 4KB << ZZZZ. */ 0x01000000 + (cache_line_size << 16) + cache_size, /* 64 bytes per line, default = 1 MB total */ 0xffffffff, NULL, cpuaddr, NULL, 0); } debug("ARC cpu%i @ 0x%" PRIx64, i, (uint64_t) cpuaddr); if (fpu != 0) debug(" (fpu @ 0x%" PRIx64")\n", (uint64_t) fpu); else debug("\n"); debug(" picache @ 0x%" PRIx64", pdcache @ 0x%" PRIx64"\n", (uint64_t) picache, (uint64_t) pdcache); if (cpu->cd.mips.cache_secondary >= 12) debug(" sdcache @ 0x%" PRIx64"\n", (uint64_t) sdcache); if (machine->machine_type == MACHINE_SGI) { /* TODO: Memory amount (and base address?)! */ uint64_t memory = arcbios_addchild_manual(cpu, COMPONENT_CLASS_MemoryClass, COMPONENT_TYPE_MemoryUnit, 0, 1, 2, 0, 0xffffffff, "memory", cpuaddr, NULL, 0); debug("ARC memory @ 0x%" PRIx64"\n", (uint64_t) memory); } } /* * Add other components: * * TODO: How should this be synched with the hardware devices * added in machine.c? */ arcbios_add_other_components(machine, system); /* * Defalt TLB entry for 64-bit SGI machines: */ if (machine->machine_type == MACHINE_SGI && machine->machine_subtype != 12 /* TODO: ugly */ ) { /* TODO: On which models is this required? */ mips_coproc_tlb_set_entry(cpu, 0, 1048576*16, 0xc000000000000000ULL, 0, 1048576*16, 1,1,1,1,1, 0, 2, 2); } /* * Set up Firmware Vectors: */ add_symbol_name(&machine->symbol_context, ARC_FIRMWARE_ENTRIES, 0x10000, "[ARCBIOS entry]", 0, 1); for (i=0; i<100; i++) { if (is64bit) { store_64bit_word(cpu, ARC_FIRMWARE_VECTORS + i*8, ARC_FIRMWARE_ENTRIES + i*8); store_64bit_word(cpu, ARC_PRIVATE_VECTORS + i*8, ARC_PRIVATE_ENTRIES + i*8); /* "Magic trap" instruction: */ store_32bit_word(cpu, ARC_FIRMWARE_ENTRIES + i*8, 0x00c0de0c); store_32bit_word(cpu, ARC_PRIVATE_ENTRIES + i*8, 0x00c0de0c); } else { store_32bit_word(cpu, ARC_FIRMWARE_VECTORS + i*4, ARC_FIRMWARE_ENTRIES + i*4); store_32bit_word(cpu, ARC_PRIVATE_VECTORS + i*4, ARC_PRIVATE_ENTRIES + i*4); /* "Magic trap" instruction: */ store_32bit_word(cpu, ARC_FIRMWARE_ENTRIES + i*4, 0x00c0de0c); store_32bit_word(cpu, ARC_PRIVATE_ENTRIES + i*4, 0x00c0de0c); } } /* * Set up the ARC SPD: */ if (is64bit) { /* ARCS64 SPD (TODO: This is just a guess) */ memset(&arcbios_spb_64, 0, sizeof(arcbios_spb_64)); store_64bit_word_in_host(cpu, (unsigned char *) &arcbios_spb_64.SPBSignature, ARCBIOS_SPB_SIGNATURE); store_16bit_word_in_host(cpu, (unsigned char *) &arcbios_spb_64.Version, 64); store_16bit_word_in_host(cpu, (unsigned char *) &arcbios_spb_64.Revision, 0); store_64bit_word_in_host(cpu, (unsigned char *) &arcbios_spb_64.FirmwareVector, ARC_FIRMWARE_VECTORS); store_buf(cpu, SGI_SPB_ADDR, (char *)&arcbios_spb_64, sizeof(arcbios_spb_64)); } else { /* ARCBIOS SPB: (For ARC and 32-bit SGI modes) */ memset(&arcbios_spb, 0, sizeof(arcbios_spb)); store_32bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.SPBSignature, ARCBIOS_SPB_SIGNATURE); store_32bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.SPBLength, sizeof(arcbios_spb)); store_16bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.Version, 1); store_16bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.Revision, machine->machine_type == MACHINE_SGI? 10 : 2); store_32bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.FirmwareVector, ARC_FIRMWARE_VECTORS); store_32bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.FirmwareVectorLength, 100 * 4); /* ? */ store_32bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.PrivateVector, ARC_PRIVATE_VECTORS); store_32bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.PrivateVectorLength, 100 * 4); /* ? */ store_buf(cpu, SGI_SPB_ADDR, (char *)&arcbios_spb, sizeof(arcbios_spb)); } /* * TODO: How to build the component tree intermixed with * the rest of device initialization? */ arc_environment_setup(machine, is64bit, primary_ether_addr); } gxemul-0.6.1/src/promemul/Makefile.skel000644 001750 001750 00000000523 13402411502 020251 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/promemul # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(DINCLUDE) OBJS=arcbios.o dec_prom.o dreamcast.o dreamcast_scramble.o \ luna88kprom.o mvmeprom.o of.o ps2_bios.o sh_ipl_g.o yamon.o all: $(OBJS) ../../experiments/make_index.sh $(OBJS): Makefile clean: rm -f $(OBJS) *core clean_all: clean rm -f Makefile gxemul-0.6.1/src/promemul/.index000644 001750 001750 00000000576 13402411502 016774 0ustar00debugdebug000000 000000 arcbios.cc ARCBIOS and ARCS emulation dec_prom.cc DECstation PROM emulation dreamcast.cc Dreamcast PROM emulation dreamcast_scramble.cc Dreamcast emulation (helper module) luna88kprom.cc LUNA 88K PROM emulation mvmeprom.cc MVME PROM emulation of.cc OpenFirmware emulation ps2_bios.cc Playstation 2 SIFBIOS emulation sh_ipl_g.cc SH-IPL+G emulation yamon.cc YAMON emulation gxemul-0.6.1/src/promemul/dreamcast_scramble.cc000644 001750 001750 00000012515 13402411502 022002 0ustar00debugdebug000000 000000 /* * COMMENT: Dreamcast emulation (helper module) * * This is from Marcus Comstedt's Dreamcast development files * (http://mc.pp.se/dc/files/scramble.c). Public Domain, according to * Marcus software page. * * The only modification done to make it fit into the emulator is that * it is executed internally from src/file.c. */ /* #define STAND_ALONE */ #include #include #include #define MAXCHUNK (2048*1024) static unsigned int seed; void my_srand(unsigned int n) { seed = n & 0xffff; } unsigned int my_rand(void) { seed = (seed * 2109 + 9273) & 0x7fff; return (seed + 0xc000) & 0xffff; } void load(FILE *fh, unsigned char *ptr, unsigned long sz) { if(fread(ptr, 1, sz, fh) != sz) { fprintf(stderr, "Read error!\n"); exit(1); } } void load_chunk(FILE *fh, unsigned char *ptr, unsigned long sz) { static int idx[MAXCHUNK/32]; int i; /* Convert chunk size to number of slices */ sz /= 32; /* Initialize index table with unity, so that each slice gets loaded exactly once */ for(i = 0; i < (int)sz; i++) idx[i] = i; for(i = sz-1; i >= 0; --i) { /* Select a replacement index */ int x = (my_rand() * i) >> 16; /* Swap */ int tmp = idx[i]; idx[i] = idx[x]; idx[x] = tmp; /* Load resulting slice */ load(fh, ptr+32*idx[i], 32); } } void load_file(FILE *fh, unsigned char *ptr, unsigned long filesz) { unsigned long chunksz; my_srand(filesz); /* Descramble 2 meg blocks for as long as possible, then gradually reduce the window down to 32 bytes (1 slice) */ for(chunksz = MAXCHUNK; chunksz >= 32; chunksz >>= 1) while(filesz >= chunksz) { load_chunk(fh, ptr, chunksz); filesz -= chunksz; ptr += chunksz; } /* Load final incomplete slice */ if(filesz) load(fh, ptr, filesz); } void read_file(char *filename, unsigned char **ptr, unsigned long *sz) { FILE *fh = fopen(filename, "rb"); if(fh == NULL) { fprintf(stderr, "Can't open \"%s\".\n", filename); exit(1); } if(fseek(fh, 0, SEEK_END)<0) { fprintf(stderr, "Seek error.\n"); exit(1); } *sz = ftell(fh); *ptr = (unsigned char *) malloc(*sz); if( *ptr == NULL ) { fprintf(stderr, "Out of memory.\n"); exit(1); } if(fseek(fh, 0, SEEK_SET)<0) { fprintf(stderr, "Seek error.\n"); exit(1); } load_file(fh, *ptr, *sz); fclose(fh); } void save(FILE *fh, unsigned char *ptr, unsigned long sz) { if(fwrite(ptr, 1, sz, fh) != sz) { fprintf(stderr, "Write error!\n"); exit(1); } } void save_chunk(FILE *fh, unsigned char *ptr, unsigned long sz) { static int idx[MAXCHUNK/32]; int i; /* Convert chunk size to number of slices */ sz /= 32; /* Initialize index table with unity, so that each slice gets saved exactly once */ for(i = 0; i < (int)sz; i++) idx[i] = i; for(i = sz-1; i >= 0; --i) { /* Select a replacement index */ int x = (my_rand() * i) >> 16; /* Swap */ int tmp = idx[i]; idx[i] = idx[x]; idx[x] = tmp; /* Save resulting slice */ save(fh, ptr+32*idx[i], 32); } } void save_file(FILE *fh, unsigned char *ptr, unsigned long filesz) { unsigned long chunksz; my_srand(filesz); /* Descramble 2 meg blocks for as long as possible, then gradually reduce the window down to 32 bytes (1 slice) */ for(chunksz = MAXCHUNK; chunksz >= 32; chunksz >>= 1) while(filesz >= chunksz) { save_chunk(fh, ptr, chunksz); filesz -= chunksz; ptr += chunksz; } /* Save final incomplete slice */ if(filesz) save(fh, ptr, filesz); } void write_file(char *filename, unsigned char *ptr, unsigned long sz) { FILE *fh = fopen(filename, "wb"); if(fh == NULL) { fprintf(stderr, "Can't open \"%s\".\n", filename); exit(1); } save_file(fh, ptr, sz); fclose(fh); } void dreamcast_descramble(char *src, char *dst) { unsigned char *ptr = NULL; unsigned long sz = 0; FILE *fh; read_file(src, &ptr, &sz); fh = fopen(dst, "wb"); if(fh == NULL) { fprintf(stderr, "Can't open \"%s\".\n", dst); exit(1); } if( fwrite(ptr, 1, sz, fh) != sz ) { fprintf(stderr, "Write error.\n"); exit(1); } fclose(fh); free(ptr); } void scramble(char *src, char *dst) { unsigned char *ptr = NULL; unsigned long sz = 0; FILE *fh; fh = fopen(src, "rb"); if(fh == NULL) { fprintf(stderr, "Can't open \"%s\".\n", src); exit(1); } if(fseek(fh, 0, SEEK_END)<0) { fprintf(stderr, "Seek error.\n"); exit(1); } sz = ftell(fh); ptr = (unsigned char *) malloc(sz); if( ptr == NULL ) { fprintf(stderr, "Out of memory.\n"); exit(1); } if(fseek(fh, 0, SEEK_SET)<0) { fprintf(stderr, "Seek error.\n"); exit(1); } if( fread(ptr, 1, sz, fh) != sz ) { fprintf(stderr, "Read error.\n"); exit(1); } fclose(fh); write_file(dst, ptr, sz); free(ptr); } #ifdef STAND_ALONE int main(int argc, char *argv[]) { int opt = 0; if(argc > 1 && !strcmp(argv[1], "-d")) opt ++; if(argc != 3+opt) { fprintf(stderr, "Usage: %s [-d] from to\n", argv[0]); exit(1); } if(opt) dreamcast_descramble(argv[2], argv[3]); else scramble(argv[1], argv[2]); return 0; } #endif gxemul-0.6.1/src/promemul/dreamcast.cc000644 001750 001750 00000026127 13402411502 020136 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2014 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Dreamcast PROM emulation * * NOTE: This module probably only emulates enough system/BIOS calls to let * NetBSD/dreamcast, Linux/dreamcast, and various KOS demos run. Don't expect * it do be fully functional. * * Dreamcast memory layout during startup: * * 0xa0000000: 2 MB ROM/BIOS. This is copied into RAM (0x8c000000) during * bootup by the real BIOS. In GXemul's fake PROM implementation, * the only thing present at 0xa0000000 is an opcode which * triggers a reboot/shutdown of the emulator. * * 0x8c000000 - 0x8c0000ff: Various variables and vectors. * pointer (32-bit word) at 0x8c0000b0: SYSINFO * pointer (32-bit word) at 0x8c0000b4: ROMFONT * pointer (32-bit word) at 0x8c0000b8: FLASHROM * pointer (32-bit word) at 0x8c0000bc: GDROM * pointer (32-bit word) at 0x8c0000c0: (?) something * pointer (32-bit word) at 0x8c0000e0: "main menu" call, or "continue * booting" (?) or something. * * 0x8c000100: Not on a real Dreamcast, but in GXemul: This area is filled with * a special invalid instruction. Each instruction slot corresponds * to one of the pointers above (SYSINFO, ROMFONT, etc). * * 0x8c008000: This is where the first 32KB of the data track of a CDROM * gets loaded, also known as the "IP.BIN" part. * * 0x8c010000: This is where the first binary executable gets loaded. The name * of the executable is given in IP.BIN, and refers to the ISO9660 * filename on the CDROM. A common file name is "1ST_READ.BIN". * * See http://mc.pp.se/dc/syscalls.html for a description of what the * PROM syscalls do. The symbolic names in this module are the same as on * that page. */ #include #include #include #include #include "cpu.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/dreamcast_pvr.h" /* The ROM FONT seems to be located just after 1MB, in a real Dreamcast: */ #define DREAMCAST_ROMFONT_BASE 0x80100020 extern unsigned char font8x16[]; /* Where the machine ID (64-bit) is stored. */ #define DREAMCAST_MACHINE_ID_ADDRESS 0x80000068 static int booting_from_cdrom = 0; /* * dreamcast_romfont_init() * * Initialize the ROM font. */ static void dreamcast_romfont_init(struct machine *machine) { struct cpu *cpu = machine->cpus[0]; int i, y, v; uint64_t d = DREAMCAST_ROMFONT_BASE; /* * 288 narrow glyphs (12 x 24 pixels): * * Glyphs 1-94 are ASCII characters 33-126, according to * http://mc.pp.se/dc/syscalls.html#vecB4 * * syscalls.html says "(As there is no glyph for ASCII space, use * glyph 96 = ISO-8859-1 unbreakable space instead.)", but this does * not seem to work. Marcus Comstedt's own example (video.s) uses * char 288 for space instead (but the comment says char 72). * * TODO: A better looking font. This simply reuses the standard 8x16 * font, which looks odd in Dreamcast programs. */ for (i=0; i<288; i++) { for (y=0; y<24; y+=2) { if (y <= 1 || y >= 22) v = 0; else v = random(); store_byte(cpu, d++, v & 0x3f); store_byte(cpu, d++, v & 0xc3); store_byte(cpu, d++, v & 0xfc); } } for (i=1; i<=94; i++) { d = DREAMCAST_ROMFONT_BASE + i * (24 * 3 / 2); int c = 32 + i; int u; for (y=0; y<24; y+=2) { if (y < 4 || y >= 20) u = v = 0x00; else u = font8x16[c*16 + (y-4)], v = font8x16[c*16 + (y-4+1)]; // 00 00 u7 u6 u5 u4 u3 u2 u1 u0 00 00 // 00 00 v7 v6 v5 v4 v3 v2 v1 v0 00 00 // becomes: // first byte: 00 00 u7 u6 u5 u4 u3 u2 // second byte: u1 u0 00 00 00 00 v7 v6 // third byte: v5 v4 v3 v2 v1 v0 00 00 store_byte(cpu, d++, u >> 2); store_byte(cpu, d++, (u << 6) | (v >> 6)); store_byte(cpu, d++, v << 2); } } // "ISO-8859-1 characters 160-255" (at pos 96..191): for (i=96; i<=191; i++) { d = DREAMCAST_ROMFONT_BASE + i * (24 * 3 / 2); int c = i - 96 + 160; int u; for (y=0; y<24; y+=2) { if (y < 4 || y >= 20) u = v = 0; else u = font8x16[c*16 + (y-4)], v = font8x16[c*16 + (y-4+1)]; store_byte(cpu, d++, u >> 2); store_byte(cpu, d++, (u << 6) | (v >> 6)); store_byte(cpu, d++, v << 2); } } d = DREAMCAST_ROMFONT_BASE + 289 * (24 * 3 / 2); /* 7078 wide glyphs (24 x 24 pixels): */ for (i=1; i<7078; i++) { for (y=0; y<24; y++) { if (y <= 1 || y >= 22) v = 0; else v = 0xff; store_byte(cpu, d++, v & 0x3f); store_byte(cpu, d++, v); store_byte(cpu, d++, v & 0xfc); } } /* 129 VME icons (32 x 32 pixels): */ for (i=0; i<129; i++) { for (y=0; y<32; y++) { if (y <= 1 || y >= 30) v = 0; else v = random(); store_byte(cpu, d++, v & 0x3f); store_byte(cpu, d++, v); store_byte(cpu, d++, v); store_byte(cpu, d++, v & 0xfc); } } } /* * dreamcast_machine_setup(): * * Initializes pointers to Dreamcast PROM syscalls. */ void dreamcast_machine_setup(struct machine *machine) { int i; struct cpu *cpu = machine->cpus[0]; for (i=0; i<0x50; i+=sizeof(uint32_t)) { /* Store pointer to PROM routine... */ store_32bit_word(cpu, 0x8c0000b0 + i, 0x8c000100 + i); /* ... which contains only 1 instruction, a special opcode which triggers PROM emulation: */ store_16bit_word(cpu, 0x8c000100 + i, SH_INVALID_INSTR); } /* PROM reboot, in case someone jumps to 0xa0000000: */ store_16bit_word(cpu, 0xa0000000, SH_INVALID_INSTR); /* Machine ID (64-bit): */ store_64bit_word(cpu, DREAMCAST_MACHINE_ID_ADDRESS, 0x0000000000000000ULL); dreamcast_romfont_init(machine); /* Return address, if the user program returns: exit. */ cpu->cd.sh.pr = 0x8c0000e0 + (0x100 - 0xb0); /* Stack starting at end of RAM. */ cpu->cd.sh.r[15] = 0x8c000000 + 16 * 1048576; } /* * dreamcast_emul(): * * We end up here if someone branched or called to 0x8c000100 + ofs, * where ofs is a small number. These addresses correspond to the code reading * a pointer from 0x8c0000b0 + ofs and calling it. * * See http://mc.pp.se/dc/syscalls.html for more details. */ void dreamcast_emul(struct cpu *cpu) { // cpu->pc is the address where PROM emulation was triggered, but // what we are after is the indirect vector that was used to fetch // that address. uint32_t vectorAddr = ((cpu->pc & 0x00ffffff) - 0x100 + 0xb0) | 0x8c000000; int r1 = cpu->cd.sh.r[1]; int r6 = cpu->cd.sh.r[6]; int r7 = cpu->cd.sh.r[7]; /* Special case: Reboot */ if ((uint32_t)cpu->pc == 0x80000000 || (uint32_t)cpu->pc == 0xa0000000) { fatal("[ dreamcast reboot ]\n"); cpu->running = 0; return; } switch (vectorAddr) { case 0x8c0000b0: /* SYSINFO */ switch (r7) { case 0: /* SYSINFO_INIT: Ignored for now. */ break; case 3: /* SYSINFO_ID: */ cpu->cd.sh.r[0] = (uint32_t)DREAMCAST_MACHINE_ID_ADDRESS; break; default:fatal("[ SYSINFO: Unimplemented r7=%i ]\n", r7); goto bad; } break; case 0x8c0000b4: /* ROMFONT */ switch (r1) { case 0: /* ROMFONT_ADDRESS */ cpu->cd.sh.r[0] = DREAMCAST_ROMFONT_BASE; break; default:fatal("[ ROMFONT: Unimplemented r1=%i ]\n", r1); goto bad; } break; case 0x8c0000b8: /* FLASHROM */ switch (r7) { case 0: /* FLASHROM_INFO */ /* TODO */ cpu->cd.sh.r[0] = (uint32_t) -1; break; case 1: /* FLASHROM_READ */ /* TODO */ cpu->cd.sh.r[0] = (uint32_t) -1; break; default:fatal("[ FLASHROM: Unimplemented r7=%i ]\n", r7); goto bad; } break; case 0x8c0000bc: switch ((int32_t)r6) { case 0: /* GD-ROM emulation */ switch (r7) { case 0: /* GDROM_SEND_COMMAND */ /* TODO */ cpu->cd.sh.r[0] = (uint32_t) -1; break; case 1: /* GDROM_CHECK_COMMAND */ /* TODO */ cpu->cd.sh.r[0] = 0; break; case 2: /* GDROM_MAINLOOP */ /* TODO */ break; case 3: /* GDROM_INIT */ /* TODO: Do something here? */ break; case 4: /* GDROM_CHECK_DRIVE */ /* TODO: Return status words */ break; default:fatal("[ GDROM: Unimplemented r7=%i ]\n", r7); goto bad; } break; default:fatal("[ 0xbc: Unimplemented r6=0x%x ]\n", r6); goto bad; } break; case 0x8c0000e0: /* * This seems to have two uses: * * 1. KallistiOS calls this from arch_menu(), i.e. to return * from a running program. * 2. The "licence code" in the IP.BIN code when booting from * a bootable CD image calls this once the license screen * has been displayed, and it wants the ROM to jump to * 0x8c00b800 ("Bootstrap 1"). * * The easiest way to support both is probably to keep track * of whether the IP.BIN code was started by the (software) * ROM emulation code, or not. */ if (booting_from_cdrom) { debug("[ dreamcast: Switching to bootstrap 1 ]\n"); booting_from_cdrom = 0; // Jump to bootstrap 1 cpu->pc = 0x8c00b800; return; } else { fatal("[ dreamcast: Returning to main menu. ]\n"); cpu->running = 0; } break; case 0x8c0000f0: /* * GXemul hack: * * The vector (word) at 0x8c0000f0 contains the value 0x8c000140. * * By jumping to this address (0x8c000140), a "boot from * CDROM" is simulated. Control is transfered to the license * code in the loaded IP.BIN file. */ debug("[ dreamcast boot from CDROM ]\n"); booting_from_cdrom = 1; cpu->pc = 0x8c008300; return; default:goto bad; } /* Return from subroutine: */ cpu->pc = cpu->cd.sh.pr; return; bad: cpu_register_dump(cpu->machine, cpu, 1, 0); printf("\n"); fatal("[ dreamcast_emul(): unimplemented dreamcast PROM call, " "pc=0x%08" PRIx32" (vectorAddr=0x%08" PRIx32") ]\n", (uint32_t)cpu->pc, vectorAddr); cpu->running = 0; return; } gxemul-0.6.1/src/promemul/mvmeprom.cc000644 001750 001750 00000007513 13402411502 020033 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: MVME PROM emulation * * For mvme88k emulation. * * TODO: Perhaps this could be reused for mvme68k emulation too? */ #include #include #include #include #include "console.h" #include "cpu.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/mvmeprom.h" #define MVMEPROM_BRDID_ADDR 0x1100 /* * mvmeprom_init(): */ void mvmeprom_init(struct machine *machine) { struct cpu *cpu = machine->cpus[0]; struct mvmeprom_brdid mvmeprom_brdid; uint32_t vbr = 0x00000000; int model = 0x187; switch (machine->machine_subtype) { case MACHINE_MVME88K_187: model = 0x187; break; case MACHINE_MVME88K_188: model = 0x188; break; case MACHINE_MVME88K_197: model = 0x197; break; } cpu->cd.m88k.cr[M88K_CR_VBR] = vbr; /* A magic prom call instruction, followed by an 'rte': */ store_32bit_word(cpu, vbr + 8 * MVMEPROM_VECTOR, M88K_PROM_INSTR); store_32bit_word(cpu, vbr + 8 * MVMEPROM_VECTOR + 4, 0xf400fc00); /* brdid struct: */ memset(&mvmeprom_brdid, 0, sizeof(mvmeprom_brdid)); store_16bit_word_in_host(cpu, (unsigned char *) &(mvmeprom_brdid.model), model); mvmeprom_brdid.speed[0] = '3'; /* 33 MHz, for now */ mvmeprom_brdid.speed[1] = '3'; mvmeprom_brdid.speed[2] = '0'; mvmeprom_brdid.speed[3] = '0'; store_buf(cpu, MVMEPROM_BRDID_ADDR, (char *)&mvmeprom_brdid, sizeof(struct mvmeprom_brdid)); } /* * mvmeprom_emul(): * * For MVME88K: * * Input: * r9 = requested function number * r2 = first argument (for functions that take arguments) * * Output: * r2 = result */ int mvmeprom_emul(struct cpu *cpu) { int func = cpu->cd.m88k.r[9]; switch (func) { case MVMEPROM_OUTCHR: console_putchar(cpu->machine->main_console_handle, cpu->cd.m88k.r[2]); break; case MVMEPROM_OUTCRLF: console_putchar(cpu->machine->main_console_handle, '\n'); break; case MVMEPROM_EXIT: fatal("[ MVME PROM: exit ]\n"); cpu->running = 0; break; case MVMEPROM_GETBRDID: /* Return a pointer in r2 to a mvmeprom_brdid struct. */ cpu->cd.m88k.r[2] = MVMEPROM_BRDID_ADDR; break; default: cpu_register_dump(cpu->machine, cpu, 1, 0); cpu_register_dump(cpu->machine, cpu, 0, 1); fatal("[ MVME PROM emulation: unimplemented function 0x%" PRIx32" ]\n", func); cpu->running = 0; return 0; } return 1; } gxemul-0.6.1/src/include/symbol.h000644 001750 001750 00000005116 13402411502 017120 0ustar00debugdebug000000 000000 #ifndef SYMBOL_H #define SYMBOL_H /* * Copyright (C) 2004-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Symbol handling routines. */ #include "misc.h" /* This should actually only be used within symbol.c: */ struct symbol { struct symbol *next; uint64_t addr; uint64_t len; char *name; int type; int n_args; /* TODO: argument types */ }; struct symbol_context { struct symbol *first_symbol; int sorted_array; int n_symbols; }; /* symbol.c: */ int symbol_nsymbols(struct symbol_context *); int get_symbol_addr(struct symbol_context *, const char *symbol, uint64_t *addr); char *get_symbol_name_and_n_args(struct symbol_context *, uint64_t addr, uint64_t *offset, int *n_argsp); char *get_symbol_name(struct symbol_context *, uint64_t addr, uint64_t *offset); void add_symbol_name(struct symbol_context *, uint64_t addr, uint64_t len, const char *name, int type, int n_args); void symbol_readfile(struct symbol_context *, char *fname); void symbol_recalc_sizes(struct symbol_context *); void symbol_init(struct symbol_context *); /* symbol_demangle.c: */ char *symbol_demangle_cplusplus(const char *name); #endif /* SYMBOL_H */ gxemul-0.6.1/src/include/float_emul.h000644 001750 001750 00000004106 13402411502 017740 0ustar00debugdebug000000 000000 #ifndef FLOAT_EMUL_H #define FLOAT_EMUL_H /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Floating point emulation. See src/float_emul.c for the details. */ #include #include "misc.h" struct ieee_float_value { double f; int nan; }; #define IEEE_FMT_S 1 /* single, 32-bit float */ #define IEEE_FMT_D 2 /* double, 64-bit float */ #define IEEE_FMT_W 3 /* word, 32-bit integer */ #define IEEE_FMT_L 4 /* long, 64-bit integer */ void ieee_interpret_float_value(uint64_t x, struct ieee_float_value *fvp, int fmt); uint64_t ieee_store_float_value(double nf, int fmt); #endif /* FLOAT_EMUL_H */ gxemul-0.6.1/src/include/StringHelper.h000644 001750 001750 00000005511 13402411502 020220 0ustar00debugdebug000000 000000 #ifndef STRINGHELPER_H #define STRINGHELPER_H /* * Copyright (C) 2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "UnitTest.h" /** * \brief A helper class, with static functions for common string operations. */ class StringHelper : public UnitTestable { private: /** * \brief No constructor. */ StringHelper(); public: /** * \brief Parses a string into a 64-bit number. * * @param str A pointer to a character string. * @param error Set to false if a parsed value is returned, true on * parse errors. * @return A uint64_t, representing the parsed value. */ static uint64_t ParseNumber(const char* str, bool& error); /** * \brief Splits a string with a certain delimiter into a vector of strings. * * E.g. if the input string is "A:B:C" and the splitter is ':', then * the resulting vector consists of 3 strings: "A", "B", and "C". * * NOTE: The current implementation is very slow, but it at least it works. * * @param str A string to split. * @param splitter Set to false if a parsed value is returned, true on * parse errors. * @return A vector of strings (without the splitter char). */ static vector SplitStringIntoVector(const string &str, const char splitter); /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // STRINGHELPER_H gxemul-0.6.1/src/include/net.h000644 001750 001750 00000015007 13402411502 016401 0ustar00debugdebug000000 000000 #ifndef NET_H #define NET_H /* * Copyright (C) 2004-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Emulated network support. (See net.c for more info.) */ #include #include #include struct emul; struct ethernet_packet_link; struct remote_net; /* Default emulated "simple" IPv4 network, if nothing else is specified: */ #define NET_DEFAULT_IPV4_MASK "10.0.0.0" #define NET_DEFAULT_IPV4_LEN 8 /*****************************************************************************/ /* * NOTE: These are already defined in on e.g. FreeBSD, * but they are missing in some systems (at least in Linux). */ #define ETHERTYPE_SPRITE 0x0500 #define ETHERTYPE_IP 0x0800 #define ETHERTYPE_ARP 0x0806 #define ETHERTYPE_REVARP 0x8035 #define ETHERTYPE_IPV6 0x86DD /*****************************************************************************/ /* NOTE: udp_connection and tcp_connection are actually for internal use only. */ struct udp_connection { int in_use; int64_t last_used_timestamp; /* Inside: */ unsigned char ethernet_address[6]; unsigned char inside_ip_address[4]; int inside_udp_port; /* TODO: Fragment support for outgoing packets! */ int fake_ns; /* Outside: */ int udp_id; int socket; unsigned char outside_ip_address[4]; int outside_udp_port; }; struct tcp_connection { int in_use; int64_t last_used_timestamp; /* Inside: */ unsigned char ethernet_address[6]; unsigned char inside_ip_address[4]; int inside_tcp_port; uint32_t inside_timestamp; /* TODO: tx and rx buffers? */ unsigned char *incoming_buf; int incoming_buf_rounds; int incoming_buf_len; uint32_t incoming_buf_seqnr; uint32_t inside_seqnr; uint32_t inside_acknr; uint32_t outside_seqnr; uint32_t outside_acknr; /* Outside: */ int state; int tcp_id; int socket; unsigned char outside_ip_address[4]; int outside_tcp_port; uint32_t outside_timestamp; }; /*****************************************************************************/ #define MAX_TCP_CONNECTIONS 100 #define MAX_UDP_CONNECTIONS 100 struct net { /* The emul struct which this net belong to: */ struct emul *emul; /* The network's addresses: */ struct in_addr netmask_ipv4; int netmask_ipv4_len; /* NICs connected to this network: */ int n_nics; void **nic_extra; /* one void * per NIC */ /* The "special machine": */ unsigned char gateway_ipv4_addr[4]; unsigned char gateway_ethernet_addr[6]; /* Read from /etc/resolv.conf: */ char *domain_name; int nameserver_known; struct in_addr nameserver_ipv4; int64_t timestamp; struct ethernet_packet_link *first_ethernet_packet; struct ethernet_packet_link *last_ethernet_packet; struct udp_connection udp_connections[MAX_UDP_CONNECTIONS]; struct tcp_connection tcp_connections[MAX_TCP_CONNECTIONS]; /* Distributed network: */ int local_port; int local_port_socket; struct remote_net *remote_nets; }; /* net_misc.c: */ void net_debugaddr(void *addr, int type); void net_generate_unique_mac(struct machine *, unsigned char *macbuf); void send_udp(struct in_addr *addrp, int portnr, unsigned char *packet, size_t len); /* net_ip.c: */ void net_ip_checksum(unsigned char *ip_header, int chksumoffset, int len); void net_ip_tcp_checksum(unsigned char *tcp_header, int chksumoffset, int tcp_len, unsigned char *srcaddr, unsigned char *dstaddr, int udpflag); void net_ip_tcp_connectionreply(struct net *net, void *extra, int con_id, int connecting, unsigned char *data, int datalen, int rst); void net_ip_broadcast(struct net *net, void *extra, unsigned char *packet, int len); void net_ip(struct net *net, void *extra, unsigned char *packet, int len); void net_udp_rx_avail(struct net *net, void *extra); void net_tcp_rx_avail(struct net *net, void *extra); /* net.c: */ struct ethernet_packet_link *net_allocate_ethernet_packet_link( struct net *net, void *extra, size_t len); int net_ethernet_rx_avail(struct net *net, void *extra); int net_ethernet_rx(struct net *net, void *extra, unsigned char **packetp, int *lenp); void net_ethernet_tx(struct net *net, void *extra, unsigned char *packet, int len); void net_dumpinfo(struct net *net); void net_add_nic(struct net *net, void *extra, unsigned char *macaddr); struct net *net_init(struct emul *emul, int init_flags, const char *ipv4addr, int netipv4len, char **remote, int n_remote, int local_port, const char *settings_prefix); /* Flag used to signify that this net should have a gateway: */ #define NET_INIT_FLAG_GATEWAY 1 /* * This is for internal use in src/net.c: */ struct ethernet_packet_link { struct ethernet_packet_link *prev; struct ethernet_packet_link *next; void *extra; unsigned char *data; int len; }; struct remote_net { struct remote_net *next; char *name; struct in_addr ipv4_addr; int portnr; }; #define TCP_OUTSIDE_TRYINGTOCONNECT 1 #define TCP_OUTSIDE_CONNECTED 2 #define TCP_OUTSIDE_DISCONNECTED 3 #define TCP_OUTSIDE_DISCONNECTED2 4 #define TCP_INCOMING_BUF_LEN 2000 #define NET_ADDR_IPV4 1 #define NET_ADDR_IPV6 2 #define NET_ADDR_ETHERNET 3 #endif /* NET_H */ gxemul-0.6.1/src/include/timer.h000644 001750 001750 00000003620 13402411502 016731 0ustar00debugdebug000000 000000 #ifndef TIMER_H #define TIMER_H /* * Copyright (C) 2006-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ struct timer; #define TIMER_BASE_FREQUENCY 65.0 /* Hz */ struct timer *timer_add(double freq, void (*timer_tick)(struct timer *timer, void *extra), void *extra); void timer_remove(struct timer *t); void timer_update_frequency(struct timer *t, double new_freq); void timer_start(void); void timer_stop(void); void timer_init(void); #endif /* TIMER_H */ gxemul-0.6.1/src/include/cpu_ppc.h000644 001750 001750 00000017602 13402411502 017247 0ustar00debugdebug000000 000000 #ifndef CPU_PPC_H #define CPU_PPC_H /* * Copyright (C) 2005-2012 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * POWER and PowerPC CPU definitions. */ #include "misc.h" struct cpu_family; #define MODE_PPC 0 #define MODE_POWER 1 /* PPC CPU types: */ struct ppc_cpu_type_def { const char *name; int pvr; int bits; int flags; int icache_shift; int ilinesize; int iway; int dcache_shift; int dlinesize; int dway; int l2cache_shift; int l2linesize; int l2way; int altivec; /* TODO: POWER vs PowerPC? */ }; /* Flags: */ #define PPC_NOFP 1 #define PPC_601 2 #define PPC_603 4 #define PPC_NO_DEC 8 /* No DEC (decrementer) SPR */ /* * TODO: Most of these just bogus */ #define PPC_CPU_TYPE_DEFS { \ { "PPC405GP", 0x40110000, 32, PPC_NOFP|PPC_NO_DEC, \ 13,5,2, 13,5,2, 0,5,1, 0 }, \ { "PPC601", 0, 32, PPC_601, 14,5,4, 14,5,4, 0,0,0, 0 },\ { "PPC603", 0x00030302, 32, PPC_603, 14,5,4, 14,5,4, 0,0,0, 0 },\ { "PPC603e", 0x00060104, 32, PPC_603, 14,5,4, 14,5,4, 0,0,0, 0 },\ { "PPC604", 0x00040304, 32, 0, 15,5,4, 15,5,4, 0,0,0, 0 }, \ { "PPC620", 0x00140000, 64, 0, 15,5,4, 15,5,4, 0,0,0, 0 }, \ { "MPC7400", 0x000c0000, 32, 0, 15,5,2, 15,5,2, 19,5,1, 1 }, \ { "PPC750", 0x00084202, 32, 0, 15,5,2, 15,5,2, 20,5,1, 0 }, \ { "G4e", 0, 32, 0, 15,5,8, 15,5,8, 18,5,8, 1 }, \ { "PPC970", 0x00390000, 64, 0, 16,7,1, 15,7,2, 19,7,1, 1 }, \ { NULL, 0, 0,0,0,0,0,0,0,0,0,0,0,0 } \ } #define PPC_NGPRS 32 #define PPC_NFPRS 32 #define PPC_NVRS 32 #define PPC_N_TGPRS 4 #define PPC_N_IC_ARGS 3 #define PPC_INSTR_ALIGNMENT_SHIFT 2 #define PPC_IC_ENTRIES_SHIFT 10 #define PPC_IC_ENTRIES_PER_PAGE (1 << PPC_IC_ENTRIES_SHIFT) #define PPC_PC_TO_IC_ENTRY(a) (((a)>>PPC_INSTR_ALIGNMENT_SHIFT) \ & (PPC_IC_ENTRIES_PER_PAGE-1)) #define PPC_ADDR_TO_PAGENR(a) ((a) >> (PPC_IC_ENTRIES_SHIFT \ + PPC_INSTR_ALIGNMENT_SHIFT)) #define PPC_L2N 17 #define PPC_L3N 18 DYNTRANS_MISC_DECLARATIONS(ppc,PPC,uint64_t) DYNTRANS_MISC64_DECLARATIONS(ppc,PPC,uint8_t) #define PPC_MAX_VPH_TLB_ENTRIES 128 struct ppc_cpu { struct ppc_cpu_type_def cpu_type; uint64_t of_emul_addr; int mode; /* MODE_PPC or MODE_POWER */ int bits; /* 32 or 64 */ int irq_asserted; /* External Interrupt flag */ int dec_intr_pending;/* Decrementer interrupt pending */ uint64_t zero; /* A zero register */ uint32_t cr; /* Condition Register */ uint32_t fpscr; /* FP Status and Control Register */ uint64_t gpr[PPC_NGPRS]; /* General Purpose Registers */ uint64_t fpr[PPC_NFPRS]; /* Floating-Point Registers */ uint64_t vr_hi[PPC_NVRS];/* 128-bit Vector registers */ uint64_t vr_lo[PPC_NVRS];/* (Hi and lo 64-bit parts) */ uint64_t msr; /* Machine state register */ uint64_t tgpr[PPC_N_TGPRS];/*Temporary gpr 0..3 */ uint32_t sr[16]; /* Segment registers. */ uint64_t spr[1024]; uint64_t ll_addr; /* Load-linked / store-conditional */ int ll_bit; /* * Instruction translation cache and Virtual->Physical->Host * address translation: */ DYNTRANS_ITC(ppc) VPH_TLBS(ppc,PPC) VPH32(ppc,PPC) VPH64(ppc,PPC) }; /* Machine status word bits: (according to Book 3) */ #define PPC_MSR_SF (1ULL << 63) /* Sixty-Four-Bit Mode */ /* bits 62..61 are reserved */ #define PPC_MSR_HV (1ULL << 60) /* Hypervisor */ /* bits 59..17 are reserved */ #define PPC_MSR_VEC (1 << 25) /* Altivec Enable */ #define PPC_MSR_TGPR (1 << 17) /* Temporary gpr0..3 */ #define PPC_MSR_ILE (1 << 16) /* Interrupt Little-Endian Mode */ #define PPC_MSR_EE (1 << 15) /* External Interrupt Enable */ #define PPC_MSR_PR (1 << 14) /* Problem/Privilege State */ #define PPC_MSR_FP (1 << 13) /* Floating-Point Available */ #define PPC_MSR_ME (1 << 12) /* Machine Check Interrupt Enable */ #define PPC_MSR_FE0 (1 << 11) /* Floating-Point Exception Mode 0 */ #define PPC_MSR_SE (1 << 10) /* Single-Step Trace Enable */ #define PPC_MSR_BE (1 << 9) /* Branch Trace Enable */ #define PPC_MSR_FE1 (1 << 8) /* Floating-Point Exception Mode 1 */ #define PPC_MSR_IP (1 << 6) /* Vector Table at 0xfff00000 */ #define PPC_MSR_IR (1 << 5) /* Instruction Relocate */ #define PPC_MSR_DR (1 << 4) /* Data Relocate */ #define PPC_MSR_PMM (1 << 2) /* Performance Monitor Mark */ #define PPC_MSR_RI (1 << 1) /* Recoverable Interrupt */ #define PPC_MSR_LE (1) /* Little-Endian Mode */ /* Floating-point Status: */ #define PPC_FPSCR_FX (1 << 31) /* Exception summary */ #define PPC_FPSCR_FEX (1 << 30) /* Enabled Exception summary */ #define PPC_FPSCR_VX (1 << 29) /* Invalid Operation summary */ /* .. TODO */ #define PPC_FPSCR_VXNAN (1 << 24) /* .. TODO */ #define PPC_FPSCR_FPCC 0x0000f000 #define PPC_FPSCR_FPCC_SHIFT 12 #define PPC_FPSCR_FL (1 << 15) /* Less than */ #define PPC_FPSCR_FG (1 << 14) /* Greater than */ #define PPC_FPSCR_FE (1 << 13) /* Equal or Zero */ #define PPC_FPSCR_FU (1 << 12) /* Unordered or NaN */ /* Exceptions: */ #define PPC_EXCEPTION_DSI 0x3 /* Data Storage Interrupt */ #define PPC_EXCEPTION_ISI 0x4 /* Instruction Storage Interrupt */ #define PPC_EXCEPTION_EI 0x5 /* External interrupt */ #define PPC_EXCEPTION_FPU 0x8 /* Floating-Point unavailable */ #define PPC_EXCEPTION_DEC 0x9 /* Decrementer */ #define PPC_EXCEPTION_SC 0xc /* Syscall */ /* XER bits: */ #define PPC_XER_SO (1UL << 31) /* Summary Overflow */ #define PPC_XER_OV (1 << 30) /* Overflow */ #define PPC_XER_CA (1 << 29) /* Carry */ /* cpu_ppc.c: */ int ppc_run_instr(struct cpu *cpu); int ppc32_run_instr(struct cpu *cpu); void ppc_exception(struct cpu *cpu, int exception_nr); void ppc_update_translation_table(struct cpu *cpu, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page); void ppc32_update_translation_table(struct cpu *cpu, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page); void ppc_invalidate_translation_caches(struct cpu *cpu, uint64_t, int); void ppc32_invalidate_translation_caches(struct cpu *cpu, uint64_t, int); void ppc_invalidate_code_translation(struct cpu *cpu, uint64_t, int); void ppc32_invalidate_code_translation(struct cpu *cpu, uint64_t, int); void ppc_init_64bit_dummy_tables(struct cpu *cpu); int ppc_memory_rw(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags); int ppc_cpu_family_init(struct cpu_family *); /* memory_ppc.c: */ int ppc_translate_v2p(struct cpu *cpu, uint64_t vaddr, uint64_t *return_addr, int flags); #endif /* CPU_PPC_H */ gxemul-0.6.1/src/include/machine_arc.h000644 001750 001750 00000006024 13402411502 020043 0ustar00debugdebug000000 000000 #ifndef MACHINE_ARC_H #define MACHINE_ARC_H /* * Copyright (C) 2004-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * ARC machine specific structure. */ #include #define ARC_CONSOLE_MAX_X 80 #define ARC_CONSOLE_MAX_Y 25 #define ARC_MAX_ESC 16 #define MAX_OPEN_STRINGLEN 200 #define ARC_MAX_HANDLES 10 #define MAX_STRING_TO_COMPONENT 20 #define MAX_CONFIG_DATA 50 struct machine_arcbios { /* General stuff: */ int arc_64bit; int wordlen; /* cached */ /* VGA Console I/O: */ int vgaconsole; /* 1 or 0 */ uint64_t console_vram; uint64_t console_ctrlregs; char escape_sequence[ARC_MAX_ESC+1]; int in_escape_sequence; int console_maxx; int console_maxy; int console_curx; int console_cury; int console_reverse; int console_curcolor; /* File handles: */ int file_handle_in_use[ARC_MAX_HANDLES]; const char *file_handle_string[ARC_MAX_HANDLES]; uint64_t current_seek_offset[ARC_MAX_HANDLES]; /* Memory: */ int n_memdescriptors; uint64_t memdescriptor_base; /* Component tree: */ uint64_t next_component_address; int n_components; char *string_to_component[MAX_STRING_TO_COMPONENT]; uint64_t string_to_component_value[MAX_STRING_TO_COMPONENT]; int n_string_to_components; /* Configuration data: */ int n_configuration_data; uint64_t configuration_data_next_addr; uint64_t configuration_data_component[MAX_CONFIG_DATA]; int configuration_data_len[MAX_CONFIG_DATA]; uint64_t configuration_data_configdata[MAX_CONFIG_DATA]; /* SCSI: */ uint64_t scsicontroller; /* component addr */ }; #endif /* MACHINE_ARC_H */ gxemul-0.6.1/src/include/FileLoader_ELF.h000644 001750 001750 00000004270 13402411502 020307 0ustar00debugdebug000000 000000 #ifndef FILELOADER_ELF_H #define FILELOADER_ELF_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Component.h" #include "FileLoaderImpl.h" #include "UnitTest.h" /** * \brief ELF binary loader. * * TODO: Longer comment. */ class FileLoader_ELF : public UnitTestable , public FileLoaderImpl { public: FileLoader_ELF(const string& filename); ~FileLoader_ELF() { } string DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const; bool LoadIntoComponent(refcount_ptr component, ostream& messages) const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // FILELOADER_ELF_H gxemul-0.6.1/src/include/of.h000644 001750 001750 00000006276 13402411502 016227 0ustar00debugdebug000000 000000 #ifndef OF_H #define OF_H /* * Copyright (C) 2005-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * OpenFirmware emulation. (See src/promemul/of.c for details.) */ struct machine; struct cpu; struct vfb_data; #ifdef OF_C #define OF_N_MAX_ARGS 10 #define OF_ARG_MAX_LEN 4096 struct of_device_property { struct of_device_property *next; char *name; unsigned char *data; uint32_t len; int flags; }; #define OF_PROP_STRING 1 #define OF_PROP_INT 2 struct of_device { struct of_device *next; int handle; int parent; char *name; struct of_device_property *properties; }; #define OF_FIND(ptr,cond) for (; ptr != NULL; ptr = ptr->next) \ if (cond) \ break; #define OF_SERVICE_ARGS struct cpu *, char **, uint64_t, uint64_t /* * OpenFirmare service 'name' is defined by a OF_SERVICE(name). The code * implementing the service should use OF_GET_ARG to read numerical arguments * and use arg[] for strings. */ #define OF_SERVICE(n) static int of__ ## n (struct cpu *cpu, \ char **arg, uint64_t base, uint64_t retofs) #define OF_GET_ARG(i) load_32bit_word(cpu, base + 12 + \ sizeof(uint32_t) * (i)) struct of_service { struct of_service *next; char *name; int (*f)(OF_SERVICE_ARGS); int n_args; int n_ret_args; }; struct of_data { struct of_device *of_devices; struct of_service *of_services; /* For framebuffers: */ struct vfb_data *vfb_data; }; #endif /* OF_C */ struct of_data *of_emul_init(struct machine *machine, struct vfb_data *, uint64_t fb_addr, int fb_xsize, int fb_ysize); void of_emul_init_uninorth(struct machine *); void of_emul_init_isa(struct machine *); void of_emul_init_adb(struct machine *); void of_emul_init_zs(struct machine *); int of_emul(struct cpu *cpu); #endif /* OF_H */ gxemul-0.6.1/src/include/ComponentFactory.h000644 001750 001750 00000012705 13402411502 021107 0ustar00debugdebug000000 000000 #ifndef COMPONENTFACTORY_H #define COMPONENTFACTORY_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Component.h" #include "UnitTest.h" /** * \brief A factory which creates Component objects. * * The main usage of the %ComponentFactory is simply: * "Hey, give me an XYZ component." * and the %ComponentFactory returns a reference counted pointer to something. * This can be a single Component, or it can be something more complex (a * %Component with children, etc). * * This mechanism is also used for templates. If the user wishes to create * a "testmips" machine, what actually happens is that CreateComponent() is * called with "testmips" as the argument, and it returns an entire tree, * which may contain something like:

 * machine0  [testmips]
 * |-- cpu0
 * |-- ram0
 * \-- framebuffer0
 * 
* * (The example above is semi-bogus, but should illustrate the point of * CreateComponent().) */ class ComponentFactory : public UnitTestable { public: /** * \brief Creates a component given a short component name. * * componentNameAndOptionalArgs may be e.g. * "testmips(cpu=R4400,cpus=4)". * * @param componentNameAndOptionalArgs The component name, e.g. "dummy", * optionally followed by arguments in parentheses. * @param gxemul A pointer to a GXemul instance. May be NULL. * @return A reference counted Component pointer. This is set to the * newly created component on success. On failure it is set to * NULL. */ static refcount_ptr CreateComponent( const string& componentNameAndOptionalArgs, GXemul* gxemul = NULL); /** * \brief Gets a specific attribute value for a component. * * @param name The name of a component, e.g. "testmips". * @param attributeName The attribute, e.g. "template" or "machine". * @return A string containing the attribute value. This is an * empty string if the component does not exist, or if the * attribute was not set for the component. */ static string GetAttribute(const string& name, const string& attributeName); /** * \brief Checks if a component has a specific attribute. * * @param name The name of a component, e.g. "testmips". * @param attributeName The attribute, e.g. "template" or "machine". * @return True if the name exists and the attribute is not an * empty string, false otherwise * (both if the name is not known, and if it is known but * the attribute was not set). */ static bool HasAttribute(const string& name, const string& attributeName); /** * \brief Returns a vector of all available component names. * * @param onlyTemplates If true, only those component names that * are templates are returned. * @return A vector of all available component names. */ static vector GetAllComponentNames(bool onlyTemplates); /** * \brief Adds a new component class to the factory at runtime. * * Component classes added using this function are then available * when using e.g. CreateComponent. * * @param name The name of the component class. Must be a const char* * which lives for the lifetime of the program. * @param createFunc A pointer to the component's Create function. * @param getAttributeFunc A pointer to the component's GetAttribute * function. * @return True if the component class was registered, false * if the name was already in use. */ static bool RegisterComponentClass(const char* name, refcount_ptr (*createFunc)(const ComponentCreateArgs& args), string (*getAttributeFunc)(const string& attributeName)); /** * \brief Get override arguments for component creation. */ static bool GetCreationArgOverrides(ComponentCreationSettings& settings, const ComponentCreateArgs& createArgs); /** * \brief Unregisters all manually registered component classes. */ static void UnregisterAllComponentClasses(); /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // COMPONENTFACTORY_H gxemul-0.6.1/src/include/Command.h000644 001750 001750 00000010345 13402411502 017171 0ustar00debugdebug000000 000000 #ifndef COMMAND_H #define COMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "UnitTest.h" class GXemul; /** * \brief A %Command is a named function, executed by the CommandInterpreter. * * To implement a new %Command, simply create the corresponding .h file * in src/include/commands/ and a .cc file in src/main/commands/ (e.g. by * copying from a similar command), and add the name of the command's .o * file to src/main/commands/Makefile.skel. (The configure script takes care * of adding all commands to the CommandInterpreter, so there is no need * to manually "register" the command anywhere.) */ class Command : public ReferenceCountable , public UnitTestable { public: /** * \brief Constructs a %Command. * * @param name The command's name. This should be a unique lower-case * string, consisting only of letters a-z. * @param argumentFormat A string describing the command's arguments. * May be empty, if the command takes no arguments. */ Command(const string& name, const string& argumentFormat); virtual ~Command() = 0; /** * \brief Gets the name of the command. * * @return The name of the command. */ const string& GetCommandName() const { return m_name; } /** * \brief Gets the argument format for the command. * * @return The argument format for the command. */ const string& GetArgumentFormat() const { return m_argumentFormat; } /** * \brief Executes the command on a given GXemul instance. * * @param gxemul A reference to the GXemul instance. * @param arguments A vector of zero or more string arguments. * @return true if the command succeeded, false if it failed. */ virtual bool Execute(GXemul& gxemul, const vector& arguments) = 0; /** * \brief Returns whether the command can be quickly re-executed using * an empty command line. * * Typical examples are: step, cpu disassembly, and memory dump, * where re-executing the command without arguments is very natural. * * @return true if the command may be re-executed without arguments, * false otherwise. */ virtual bool MayBeReexecutedWithoutArgs() const { return false; } /** * \brief Returns a short (one-line) description of the command. * * @return A short description of the command. */ virtual string GetShortDescription() const = 0; /** * \brief Returns a long description/help message for the command. * * @return A long description/help message for the command. */ virtual string GetLongDescription() const = 0; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); private: string m_name; string m_argumentFormat; }; typedef map< string,refcount_ptr > Commands; #endif // COMMAND_H gxemul-0.6.1/src/include/quick_pc_to_pointers.h000644 001750 001750 00000001512 13402411502 022032 0ustar00debugdebug000000 000000 #ifdef quick_pc_to_pointers #undef quick_pc_to_pointers #endif #ifdef MODE32 #define quick_pc_to_pointers(cpu) { \ uint32_t pc_tmp32 = cpu->pc; \ struct DYNTRANS_TC_PHYSPAGE *ppp_tmp; \ ppp_tmp = cpu->cd.DYNTRANS_ARCH.phys_page[pc_tmp32 >> 12]; \ if (ppp_tmp != NULL) { \ cpu->cd.DYNTRANS_ARCH.cur_ic_page = &ppp_tmp->ics[0]; \ cpu->cd.DYNTRANS_ARCH.next_ic = \ cpu->cd.DYNTRANS_ARCH.cur_ic_page + \ DYNTRANS_PC_TO_IC_ENTRY(pc_tmp32); \ } else \ DYNTRANS_PC_TO_POINTERS(cpu); \ } #ifndef quick_pc_to_pointers_arm #define quick_pc_to_pointers_arm(cpu) { \ if (cpu->cd.arm.cpsr & ARM_FLAG_T) { \ cpu->cd.arm.next_ic = ¬hing_call; \ } else \ quick_pc_to_pointers(cpu); \ } #endif #else #define quick_pc_to_pointers(cpu) DYNTRANS_PC_TO_POINTERS(cpu) #endif gxemul-0.6.1/src/include/ScopedTemporaryValue.h000644 001750 001750 00000005673 13402411502 021740 0ustar00debugdebug000000 000000 #ifndef SCOPEDTEMPORARYVALUE_H #define SCOPEDTEMPORARYVALUE_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /** * \brief Scoped temporary variable template. * * Usage:
 * SomeType var = A;
 * {
 *	ScopedTemporaryValue holder(var);
 *	var = B;
 *	...
 * }
 * // var will here be reset to A.
 * 
* or *
 * SomeType var = A;
 * {
 *	ScopedTemporaryValue holder(var, B);
 *	// Here,  var is B.
 *	...
 * }
 * // var will here be reset to A.
 * 
* * Implementation note: This is just a schoolbook-style implementation * of a class which holds a variable, and then restores the original value * when going out of scope. */ template class ScopedTemporaryValue { private: // Prevent construction without reference. ScopedTemporaryValue(); public: /** * \brief Constructor, which reads the old value from T, but * does not change it. * * @param var The variable. */ ScopedTemporaryValue(T& var) : m_var(var) { m_origValue = m_var; } /** * \brief Constructor, which reads the old value from T, and sets * it to a new (temporary) value. * * @param var The variable. * @param newValue The new (temporary) value. */ ScopedTemporaryValue(T& var, T newValue) : m_var(var) { m_origValue = m_var; m_var = newValue; } /** * \brief Destructor, which restores the original value. */ ~ScopedTemporaryValue() { m_var = m_origValue; } private: T& m_var; T m_origValue; }; #endif // SCOPEDTEMPORARYVALUE_H gxemul-0.6.1/src/include/FileLoader.h000644 001750 001750 00000007634 13402411502 017630 0ustar00debugdebug000000 000000 #ifndef FILELOADER_H #define FILELOADER_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Component.h" #include "FileLoaderImpl.h" #include "UnitTest.h" /** * \brief A class used to load binary files into emulated memory. * * A %FileLoader is given a name of a binary file, e.g. an ELF file, and * attempts to load it into emulated memory. * * Binary files may be loaded to either physical or virtual memory addresses. * To load to a physical address, we want to write to a component which * is an AddressDataBus directly. To load to virtual addresses, we need to go * via a particular CPU, because it is the CPU which does the virtual to * physical address translation. * * The type of the file is normally auto-detected by reading magic sequences * at the start of the file. */ class FileLoader : public UnitTestable { public: /** * \brief Constructs a %FileLoader object. * * \param filename The name of the file to open. */ FileLoader(const string& filename); /** * \brief Retrieves the filename of this %FileLoader. * * \return The filename. */ const string& GetFilename() const; /** * \brief Attempt to detect the file format of the file. * * \param loader On return from the function, if the file format has * been detected, this is set to a pointer to a FileLoaderImpl. * Otherwise (if no format was detected), it is NULL. * \return A string representing the file format. */ string DetectFileFormat(refcount_ptr& loader) const; /** * \brief Loads the file into a CPU or an AddressDataBus. * * Note: The file is usually loaded into a virtual address space. * It is therefore necessary to load it into a CPU, and not directly * into RAM. * * @param component A CPUComponent (or any other * component which implements the AddressDataBus interface), * into which the file will be loaded. * @param messages An output stream where debug messages can be put. * @return True if loading succeeded, false otherwise. */ bool Load(refcount_ptr component, ostream& messages) const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); private: // Disallow construction without arguments. FileLoader(); private: typedef vector< refcount_ptr > FileLoaderImplVector; const string m_filename; FileLoaderImplVector m_fileLoaders; }; #endif // FILELOADER_H gxemul-0.6.1/src/include/cpu_arm.h000644 001750 001750 00000025773 13402411502 017254 0ustar00debugdebug000000 000000 #ifndef CPU_ARM_H #define CPU_ARM_H /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * ARM CPU definitions. */ #include "misc.h" #include "interrupt.h" struct cpu_family; /* ARM CPU types: */ struct arm_cpu_type_def { const char *name; uint32_t cpu_id; int flags; int icache_shift; int iway; int dcache_shift; int dway; }; #define ARM_SL 10 #define ARM_FP 11 #define ARM_IP 12 #define ARM_SP 13 #define ARM_LR 14 #define ARM_PC 15 #define N_ARM_REGS 16 #define ARM_REG_NAMES { \ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" } #define ARM_CONDITION_STRINGS { \ "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", \ "hi", "ls", "ge", "lt", "gt", "le", "" /*Always*/ , "(INVALID)" } /* Names of Data Processing Instructions: */ #define ARM_DPI_NAMES { \ "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", \ "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn" } #define ARM_THUMB_DPI_NAMES { \ "ands", "eors", "lsls", "lsrs", "asrs", "adcs", "sbcs", "rors", \ "tst", "negs", "cmp", "cmn", "orrs", "muls", "bics", "mvns" } #define ARM_IC_ENTRIES_SHIFT 10 #define ARM_N_IC_ARGS 3 #define ARM_INSTR_ALIGNMENT_SHIFT 2 #define ARM_IC_ENTRIES_PER_PAGE (1 << ARM_IC_ENTRIES_SHIFT) #define ARM_PC_TO_IC_ENTRY(a) (((a)>>ARM_INSTR_ALIGNMENT_SHIFT) \ & (ARM_IC_ENTRIES_PER_PAGE-1)) #define ARM_ADDR_TO_PAGENR(a) ((a) >> (ARM_IC_ENTRIES_SHIFT \ + ARM_INSTR_ALIGNMENT_SHIFT)) #define ARM_F_N 8 /* Same as ARM_FLAG_*, but */ #define ARM_F_Z 4 /* for the 'flags' field instead */ #define ARM_F_C 2 /* of cpsr. */ #define ARM_F_V 1 #define ARM_FLAG_N 0x80000000 /* Negative flag */ #define ARM_FLAG_Z 0x40000000 /* Zero flag */ #define ARM_FLAG_C 0x20000000 /* Carry flag */ #define ARM_FLAG_V 0x10000000 /* Overflow flag */ #define ARM_FLAG_Q 0x08000000 /* DSP saturation overflow */ #define ARM_FLAG_J 0x01000000 /* Java flag (BXJ instruction ARMv5J) */ #define ARM_FLAG_E 0x00000200 /* Data Endianness (SETEND instruction ARMv6) */ #define ARM_FLAG_A 0x00000100 /* A = 1 disables Imprecise Data Aborts (ARMv6) */ #define ARM_FLAG_I 0x00000080 /* Interrupt disable */ #define ARM_FLAG_F 0x00000040 /* Fast Interrupt disable */ #define ARM_FLAG_T 0x00000020 /* Thumb mode */ #define ARM_FLAG_MODE 0x0000001f #define ARM_MODE_USR26 0x00 #define ARM_MODE_FIQ26 0x01 #define ARM_MODE_IRQ26 0x02 #define ARM_MODE_SVC26 0x03 #define ARM_MODE_USR32 0x10 #define ARM_MODE_FIQ32 0x11 #define ARM_MODE_IRQ32 0x12 #define ARM_MODE_SVC32 0x13 #define ARM_MODE_ABT32 0x17 #define ARM_MODE_UND32 0x1b #define ARM_MODE_SYS32 0x1f #define ARM_EXCEPTION_TO_MODE { \ ARM_MODE_SVC32, ARM_MODE_UND32, ARM_MODE_SVC32, ARM_MODE_ABT32, \ ARM_MODE_ABT32, 0, ARM_MODE_IRQ32, ARM_MODE_FIQ32 } #define N_ARM_EXCEPTIONS 8 #define ARM_EXCEPTION_RESET 0 #define ARM_EXCEPTION_UND 1 #define ARM_EXCEPTION_SWI 2 #define ARM_EXCEPTION_PREF_ABT 3 #define ARM_EXCEPTION_DATA_ABT 4 /* 5 was address exception in 26-bit ARM */ #define ARM_EXCEPTION_IRQ 6 #define ARM_EXCEPTION_FIQ 7 DYNTRANS_MISC_DECLARATIONS(arm,ARM,uint32_t) #define ARM_MAX_VPH_TLB_ENTRIES 384 struct arm_cpu { /* * Misc.: */ struct arm_cpu_type_def cpu_type; uint32_t of_emul_addr; void (*coproc[16])(struct cpu *, int opcode1, int opcode2, int l_bit, int crn, int crm, int rd); /* * General Purpose Registers (including the program counter): * * r[] always contains the current register set. The others are * only used to swap to/from when changing modes. (An exception is * r[0..7], which are never swapped out, they are always present.) */ uint32_t r[N_ARM_REGS]; uint32_t default_r8_r14[7]; /* usr and sys */ uint32_t fiq_r8_r14[7]; uint32_t irq_r13_r14[2]; uint32_t svc_r13_r14[2]; uint32_t abt_r13_r14[2]; uint32_t und_r13_r14[2]; uint32_t tmp_pc; /* Used for load/stores */ uint32_t tmp_branch; /* Set by THUMB branch prefix instruction */ /* * Flag/status registers: * * NOTE: 'flags' just contains the 4 flag bits. When cpsr is read, * the flags should be copied from 'flags', and when cpsr is written * to, 'flags' should be updated as well. */ size_t flags; uint32_t cpsr; uint32_t spsr_svc; uint32_t spsr_abt; uint32_t spsr_und; uint32_t spsr_irq; uint32_t spsr_fiq; /* * System Control Coprocessor registers: */ uint32_t cachetype; /* Cache Type Register */ uint32_t control; /* Control Register */ uint32_t auxctrl; /* Aux. Control Register */ uint32_t ttb; /* Translation Table Base */ uint32_t dacr; /* Domain Access Control */ uint32_t fsr; /* Fault Status Register */ uint32_t far; /* Fault Address Register */ uint32_t pid; /* Process Id Register */ uint32_t cpar; /* CoProcessor Access Reg. */ /* i80321 Coprocessor 6: ICU (Interrupt controller) */ uint32_t i80321_inten; /* enable */ uint32_t i80321_isteer; uint32_t i80321_isrc; /* current assertions */ uint32_t tmr0; uint32_t tmr1; struct interrupt tmr0_irq; struct interrupt tmr1_irq; uint32_t tcr0; uint32_t tcr1; uint32_t trr0; uint32_t trr1; uint32_t tisr; uint32_t wdtcr; /* XScale Coprocessor 14: (Performance Monitoring Unit) */ /* XSC1 access style: */ uint32_t xsc1_pmnc; /* Perf. Monitor Ctrl Reg. */ uint32_t xsc1_ccnt; /* Clock Counter */ uint32_t xsc1_pmn0; /* Perf. Counter Reg. 0 */ uint32_t xsc1_pmn1; /* Perf. Counter Reg. 1 */ /* XSC2 access style: */ uint32_t xsc2_pmnc; /* Perf. Monitor Ctrl Reg. */ uint32_t xsc2_ccnt; /* Clock Counter */ uint32_t xsc2_inten; /* Interrupt Enable */ uint32_t xsc2_flag; /* Overflow Flag Register */ uint32_t xsc2_evtsel; /* Event Selection Register */ uint32_t xsc2_pmn0; /* Perf. Counter Reg. 0 */ uint32_t xsc2_pmn1; /* Perf. Counter Reg. 1 */ uint32_t xsc2_pmn2; /* Perf. Counter Reg. 2 */ uint32_t xsc2_pmn3; /* Perf. Counter Reg. 3 */ /* For caching the host address of the L1 translation table: */ unsigned char *translation_table; uint32_t last_ttb; /* * Interrupts: */ int irq_asserted; /* * Instruction translation cache, and 32-bit virtual -> physical -> * host address translation: */ DYNTRANS_ITC(arm) VPH_TLBS(arm,ARM) VPH32_16BITVPHENTRIES(arm,ARM) /* ARM specific: */ uint32_t is_userpage[N_VPH32_ENTRIES/32]; }; /* System Control Coprocessor, control bits: */ #define ARM_CONTROL_MMU 0x0001 #define ARM_CONTROL_ALIGN 0x0002 #define ARM_CONTROL_CACHE 0x0004 #define ARM_CONTROL_WBUFFER 0x0008 #define ARM_CONTROL_PROG32 0x0010 #define ARM_CONTROL_DATA32 0x0020 #define ARM_CONTROL_BIG 0x0080 #define ARM_CONTROL_S 0x0100 #define ARM_CONTROL_R 0x0200 #define ARM_CONTROL_F 0x0400 #define ARM_CONTROL_Z 0x0800 #define ARM_CONTROL_ICACHE 0x1000 #define ARM_CONTROL_V 0x2000 #define ARM_CONTROL_RR 0x4000 #define ARM_CONTROL_L4 0x8000 /* Auxiliary Control Register bits: */ #define ARM_AUXCTRL_MD 0x30 /* MiniData Cache Attribute */ #define ARM_AUXCTRL_MD_SHIFT 4 #define ARM_AUXCTRL_P 0x02 /* Page Table Memory Attribute */ #define ARM_AUXCTRL_K 0x01 /* Write Buffer Coalescing Disable */ /* Cache Type register bits: */ #define ARM_CACHETYPE_CLASS 0x1e000000 #define ARM_CACHETYPE_CLASS_SHIFT 25 #define ARM_CACHETYPE_HARVARD 0x01000000 #define ARM_CACHETYPE_HARVARD_SHIFT 24 #define ARM_CACHETYPE_DSIZE 0x001c0000 #define ARM_CACHETYPE_DSIZE_SHIFT 18 #define ARM_CACHETYPE_DASSOC 0x00038000 #define ARM_CACHETYPE_DASSOC_SHIFT 15 #define ARM_CACHETYPE_DLINE 0x00003000 #define ARM_CACHETYPE_DLINE_SHIFT 12 #define ARM_CACHETYPE_ISIZE 0x000001c0 #define ARM_CACHETYPE_ISIZE_SHIFT 6 #define ARM_CACHETYPE_IASSOC 0x00000038 #define ARM_CACHETYPE_IASSOC_SHIFT 3 #define ARM_CACHETYPE_ILINE 0x00000003 #define ARM_CACHETYPE_ILINE_SHIFT 0 /* cpu_arm.c: */ void arm_setup_initial_translation_table(struct cpu *cpu, uint32_t ttb_addr); void arm_translation_table_set_l1(struct cpu *cpu, uint32_t vaddr, uint32_t paddr); void arm_translation_table_set_l1_b(struct cpu *cpu, uint32_t vaddr, uint32_t paddr); void arm_exception(struct cpu *, int); int arm_cpu_interpret_thumb_SLOW(struct cpu*); int arm_run_instr(struct cpu *cpu); void arm_update_translation_table(struct cpu *cpu, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page); void arm_invalidate_translation_caches(struct cpu *cpu, uint64_t, int); void arm_invalidate_code_translation(struct cpu *cpu, uint64_t, int); void arm_load_register_bank(struct cpu *cpu); void arm_save_register_bank(struct cpu *cpu); int arm_memory_rw(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags); int arm_cpu_family_init(struct cpu_family *); /* cpu_arm_coproc.c: */ void arm_coproc_15(struct cpu *cpu, int opcode1, int opcode2, int l_bit, int crn, int crm, int rd); void arm_coproc_i80321_6(struct cpu *cpu, int opcode1, int opcode2, int l_bit, int crn, int crm, int rd); void arm_coproc_xscale_14(struct cpu *cpu, int opcode1, int opcode2, int l_bit, int crn, int crm, int rd); /* cpu_arm_instr.c: */ void arm_push(struct cpu* cpu, uint32_t* np, int p_bit, int u_bit, int s_bit, int w_bit, uint16_t regs); void arm_pop(struct cpu* cpu, uint32_t* np, int p_bit, int u_bit, int s_bit, int w_bit, uint32_t iw); /* memory_arm.c: */ int arm_translate_v2p(struct cpu *cpu, uint64_t vaddr, uint64_t *return_addr, int flags); int arm_translate_v2p_mmu(struct cpu *cpu, uint64_t vaddr, uint64_t *return_addr, int flags); #endif /* CPU_ARM_H */ gxemul-0.6.1/src/include/device.h000644 001750 001750 00000005741 13402411502 017056 0ustar00debugdebug000000 000000 #ifndef DEVICE_H #define DEVICE_H /* * Copyright (C) 2005-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Device registry. (See device.c for more info.) */ #include "misc.h" struct machine; struct pci_device; struct devinit { struct machine *machine; char *name; /* e.g. "cons" */ char *name2; /* e.g. "secondary serial port" */ uint64_t addr; /* Device base address */ uint64_t addr2; /* Secondary address (optional) */ uint64_t len; char *interrupt_path; int in_use; int addr_mult; int pci_little_endian; void *return_ptr; }; struct device_entry { char *name; int (*initf)(struct devinit *); }; struct pci_entry { char *name; void (*initf)(struct machine *, struct memory *, struct pci_device *); }; #define DEVINIT(name) int devinit_ ## name (struct devinit *devinit) /* autodev.c: (built automatically in the devices/ directory): */ void autodev_init(void); /* device.c: */ int device_register(const char *name, int (*initf)(struct devinit *)); struct device_entry *device_lookup(char *name); int device_unregister(char *name); void *device_add(struct machine *machine, const char *name_and_params); void device_dumplist(void); void device_set_exit_on_error(int exit_on_error); void device_init(void); /* PCI stuff: (TODO: move somewhere else?) */ int pci_register(const char *name, void (*initf)(struct machine *, struct memory *, struct pci_device *)); void (*pci_lookup_initf(const char *name))(struct machine *machine, struct memory *mem, struct pci_device *pd); #endif /* DEVICE_H */ gxemul-0.6.1/src/include/Makefile.skel000644 001750 001750 00000000460 13402411502 020034 0ustar00debugdebug000000 000000 # # Makefile for GXemul include files # all: ppc_spr_strings.h ppc_spr_strings.h: make_ppc_spr_strings grep '#define.SPR_' thirdparty/ppc_spr.h |cut -d _ -f 2- | ./make_ppc_spr_strings > ppc_spr_strings.h clean: rm -f *core ppc_spr_strings.h make_ppc_spr_strings clean_all: clean rm -f Makefile gxemul-0.6.1/src/include/cpu_alpha.h000644 001750 001750 00000013575 13402411502 017557 0ustar00debugdebug000000 000000 #ifndef CPU_ALPHA_H #define CPU_ALPHA_H /* * Copyright (C) 2005-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Alpha CPU definitions. */ #include "misc.h" #include "thirdparty/alpha_cpu.h" /* ALPHA CPU types: */ struct alpha_cpu_type_def { const char *name; uint64_t pcs_type; /* See alpha_rpb.h */ int features; int implver; int icache_shift; int ilinesize; int iway; int dcache_shift; int dlinesize; int dway; int l2cache_shift; int l2linesize; int l2way; }; /* TODO: More features */ #define ALPHA_FEATURE_BWX 1 #define ALPHA_CPU_TYPE_DEFS { \ { "21064", 0x000000002ULL, 0, 0, 16,5,2, 16,5,2, 0,0,0 }, \ { "21066", 0x200000004ULL, 0, 0, 16,5,2, 16,5,2, 0,0,0 }, \ { "21164", 0x000000005ULL, 0, 1, 16,5,2, 16,5,2, 0,0,0 }, \ { "21164A-2", 0x000000007ULL, 0, 1, 16,5,2, 16,5,2, 0,0,0 }, \ { "21164PC", 0x000000009ULL, 0, 1, 16,5,2, 16,5,2, 0,0,0 }, \ { "21264", 0x00000000dULL, 0, 2, 16,5,2, 16,5,2, 0,0,0 }, \ { "21364", 0x000000000ULL, 0, 3, 16,5,2, 16,5,2, 0,0,0 }, \ { NULL, 0x000000000ULL, 0, 0, 0,0,0, 0,0,0, 0,0,0 } } struct cpu_family; /* ALPHA_KENTRY_INT .. ALPHA_KENTRY_SYS */ #define N_ALPHA_KENTRY 6 #define ALPHA_V0 0 #define ALPHA_T0 1 #define ALPHA_T1 2 #define ALPHA_T2 3 #define ALPHA_T3 4 #define ALPHA_T4 5 #define ALPHA_T5 6 #define ALPHA_T6 7 #define ALPHA_T7 8 #define ALPHA_S0 9 #define ALPHA_S1 10 #define ALPHA_S2 11 #define ALPHA_S3 12 #define ALPHA_S4 13 #define ALPHA_S5 14 #define ALPHA_FP 15 #define ALPHA_A0 16 #define ALPHA_A1 17 #define ALPHA_A2 18 #define ALPHA_A3 19 #define ALPHA_A4 20 #define ALPHA_A5 21 #define ALPHA_T8 22 #define ALPHA_T9 23 #define ALPHA_T10 24 #define ALPHA_T11 25 #define ALPHA_RA 26 #define ALPHA_T12 27 #define ALPHA_AT 28 #define ALPHA_GP 29 #define ALPHA_SP 30 #define ALPHA_ZERO 31 #define N_ALPHA_REGS 32 #define ALPHA_REG_NAMES { \ "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", \ "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", \ "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", \ "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero" } /* Dyntrans definitions: */ #define ALPHA_N_IC_ARGS 3 #define ALPHA_INSTR_ALIGNMENT_SHIFT 2 #define ALPHA_IC_ENTRIES_SHIFT 11 #define ALPHA_IC_ENTRIES_PER_PAGE (1 << ALPHA_IC_ENTRIES_SHIFT) #define ALPHA_PC_TO_IC_ENTRY(a) (((a)>>ALPHA_INSTR_ALIGNMENT_SHIFT) \ & (ALPHA_IC_ENTRIES_PER_PAGE-1)) #define ALPHA_ADDR_TO_PAGENR(a) ((a) >> (ALPHA_IC_ENTRIES_SHIFT \ + ALPHA_INSTR_ALIGNMENT_SHIFT)) #define ALPHA_MAX_VPH_TLB_ENTRIES 128 #define ALPHA_L2N 17 #define ALPHA_L3N 17 DYNTRANS_MISC_DECLARATIONS(alpha,ALPHA,uint64_t) DYNTRANS_MISC64_DECLARATIONS(alpha,ALPHA,uint8_t) #define ALPHA_PAGESHIFT 13 struct alpha_cpu { struct alpha_cpu_type_def cpu_type; /* * General Purpose Registers: */ uint64_t r[N_ALPHA_REGS]; /* Integer */ uint64_t f[N_ALPHA_REGS]; /* Floating Point */ uint64_t fpcr; /* FP Control Reg. */ /* Misc.: */ uint64_t pcc; /* Cycle Counter */ uint64_t load_linked_addr; int ll_flag; int irq_asserted; /* OSF1 PALcode specific: */ uint64_t ps; /* Processor Status */ uint64_t vptptr; /* Virtual Page Table Ptr */ uint64_t sysvalue; uint64_t mces; /* Machine Check Error Summary */ uint64_t kgp; /* Kernel GP */ uint64_t kentry[N_ALPHA_KENTRY]; uint64_t ctx; /* Ptr to current PCB (?) */ struct alpha_pcb pcb; /* Process Control Block */ /* * Instruction translation cache and Virtual->Physical->Host * address translation: */ DYNTRANS_ITC(alpha) VPH_TLBS(alpha,ALPHA) VPH64(alpha,ALPHA) }; /* cpu_alpha.c: */ void alpha_update_translation_table(struct cpu *cpu, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page); void alpha_invalidate_translation_caches(struct cpu *cpu, uint64_t, int); void alpha_invalidate_code_translation(struct cpu *cpu, uint64_t, int); void alpha_init_64bit_dummy_tables(struct cpu *cpu); int alpha_run_instr(struct cpu *cpu); int alpha_memory_rw(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags); int alpha_cpu_family_init(struct cpu_family *); /* cpu_alpha_palcode.c: */ void alpha_palcode_name(uint32_t palcode, char *buf, size_t buflen); void alpha_palcode(struct cpu *cpu, uint32_t palcode); /* memory_alpha.c: */ int alpha_translate_v2p(struct cpu *cpu, uint64_t vaddr, uint64_t *return_addr, int flags); #endif /* CPU_ALPHA_H */ gxemul-0.6.1/src/include/FileLoader_bout.h000644 001750 001750 00000004336 13402411502 020655 0ustar00debugdebug000000 000000 #ifndef FILELOADER_BOUT_H #define FILELOADER_BOUT_H /* * Copyright (C) 2009-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Component.h" #include "FileLoaderImpl.h" #include "UnitTest.h" /** * \brief b.out binary loader. * * This file loader is used for reading i960 binaries. */ class FileLoader_bout : public UnitTestable , public FileLoaderImpl { public: FileLoader_bout(const string& filename); ~FileLoader_bout() { } string DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const; bool LoadIntoComponent(refcount_ptr component, ostream& messages) const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // FILELOADER_BOUT_H gxemul-0.6.1/src/include/components/000755 001750 001750 00000000000 13402411502 017624 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/include/bus_pci.h000644 001750 001750 00000012016 13402411502 017234 0ustar00debugdebug000000 000000 #ifndef BUS_PCI_H #define BUS_PCI_H /* * Copyright (C) 2004-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * PCI bus. */ #include "misc.h" #include "thirdparty/pcireg.h" struct machine; struct memory; struct pci_device; #ifndef BUS_PCI_C struct pci_data; #else struct pci_data { /* * IRQ paths: * * irq_path Path of the controller itself. * irq_path_isa Path base of ISA interrupts. * irq_path_pci Path base of PCI interrupts. */ char *irq_path; char *irq_path_isa; char *irq_path_pci; /* * Default I/O port, memory, and irq bases for PCI and legacy ISA * devices, and the base address for actual (emulated) devices: * * pci_portbase etc are what is stored in the device configuration * registers. This address + pci_actual_{io,mem}_offset is where the * emulated device should be registered. */ uint64_t pci_actual_io_offset; uint64_t pci_actual_mem_offset; uint64_t pci_portbase; uint64_t pci_membase; uint64_t isa_portbase; uint64_t isa_membase; /* Current base when allocating space for PCI devices: */ uint64_t cur_pci_portbase; uint64_t cur_pci_membase; /* Current register access: */ int cur_bus, cur_device, cur_func, cur_reg; int last_was_write_ffffffff; struct pci_device *first_device; }; #define PCI_CFG_MEM_SIZE 0x100 struct pci_device { /* Pointer to the next PCI device on this bus: */ struct pci_device *next; /* Pointer back to the bus this device is connected to: */ struct pci_data *pcibus; /* Short device name, and bus/device/function value: */ char *name; int bus, device, function; /* Configuration memory: */ unsigned char cfg_mem[PCI_CFG_MEM_SIZE]; unsigned char cfg_mem_size[PCI_CFG_MEM_SIZE]; /* Used when setting up the configuration registers: */ int cur_mapreg_offset; /* Function to handle device-specific cfg register writes: */ int (*cfg_reg_write)(struct pci_device *pd, int reg, uint32_t value); void *extra; }; #define PCIINIT(name) void pciinit_ ## name(struct machine *machine, \ struct memory *mem, struct pci_device *pd) /* * Store little-endian config data in the pci_data struct's cfg_mem[] * or cfg_mem_size[], respectively. */ #define PCI_SET_DATA(ofs,value) { \ pd->cfg_mem[(ofs)] = (value) & 255; \ pd->cfg_mem[(ofs) + 1] = ((value) >> 8) & 255; \ pd->cfg_mem[(ofs) + 2] = ((value) >> 16) & 255; \ pd->cfg_mem[(ofs) + 3] = ((value) >> 24) & 255; \ } #define PCI_SET_DATA_SIZE(ofs,value) { \ pd->cfg_mem_size[(ofs)] = (value) & 255; \ pd->cfg_mem_size[(ofs) + 1] = ((value) >> 8) & 255; \ pd->cfg_mem_size[(ofs) + 2] = ((value) >> 16) & 255; \ pd->cfg_mem_size[(ofs) + 3] = ((value) >> 24) & 255; \ } #endif #define BUS_PCI_ADDR 0xcf8 #define BUS_PCI_DATA 0xcfc /* * bus_pci.c: */ /* Run-time access: */ void bus_pci_decompose_1(uint32_t t, int *bus, int *dev, int *func, int *reg); void bus_pci_setaddr(struct cpu *cpu, struct pci_data *pci_data, int bus, int device, int function, int reg); void bus_pci_data_access(struct cpu *cpu, struct pci_data *pci_data, uint64_t *data, int len, int writeflag); /* Initialization: */ struct pci_data *bus_pci_init(struct machine *machine, const char *irq_path, uint64_t pci_actual_io_offset, uint64_t pci_actual_mem_offset, uint64_t pci_portbase, uint64_t pci_membase, const char *pci_irqbase, uint64_t isa_portbase, uint64_t isa_membase, const char *isa_irqbase); /* Add a PCI device to a PCI bus: */ void bus_pci_add(struct machine *machine, struct pci_data *pci_data, struct memory *mem, int bus, int device, int function, const char *name); #endif /* BUS_PCI_H */ gxemul-0.6.1/src/include/GXemul.h000644 001750 001750 00000022045 13402411502 017014 0ustar00debugdebug000000 000000 #ifndef GXEMUL_H #define GXEMUL_H /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include #include "CommandInterpreter.h" #include "Component.h" #include "UI.h" /** * \brief The main emulator class. * * A %GXemul instance basically has the following member variables: * *
    *
  1. a tree of components, which make up the full * state of the current emulation setup *
  2. a UI, which runs the main [interactive] loop *
  3. a CommandInterpreter *
  4. a RunState *
  5. a list of "on reset commands", which are executed on Reset(). *
*/ class GXemul { public: enum RunState { Paused, SingleStepping, // Single-step execution Running, // Continuous execution Quitting }; public: /** * \brief Creates a GXemul instance. */ GXemul(); /** * \brief Parses command line arguments (file names). * * @param templateMachine The template machine to use. * @param filenameCount for parsing command line options. * @param filenames for parsing command line options. * @return true if options were parsable, false if there was * some error. */ bool ParseFilenames(string templateMachine, int filenameCount, char *filenames[]); /** * \brief Discards the current emulation, and starts anew with just * an empty root component. */ void ClearEmulation(); /** * \brief Initializes the %UI. */ void InitUI(); /** * \brief Runs GXemul's main loop. * * @return Zero on success, non-zero on error. */ int Run(); /** * \brief Gets the current emulation setup's filename. * * @return The name of the file that is used for the current emulation * setup. If no filename is defined yet, this is an empty string. */ const string& GetEmulationFilename() const; /** * \brief Sets the current emulation setup's filename. * * @param filename This is the name of the file that is used * for the current emulation setup. */ void SetEmulationFilename(const string& filename); /** * \brief Gets a reference to the CommandInterpreter. * * @return A reference to the %GXemul instance' CommandInterpreter. */ CommandInterpreter& GetCommandInterpreter(); /** * \brief Gets a pointer to the %GXemul instance' active UI. * * Note: Never NULL. The UI may be the NullUI, or another UI (such * as the ConsoleUI). * * @return A pointer to the UI in use. */ UI* GetUI(); /** * \brief Gets a pointer to the root configuration component. * * @return A pointer to the root component. If no configuration tree * is loaded, then this is at least an empty dummy component. * (The return value is never NULL.) */ refcount_ptr GetRootComponent(); const refcount_ptr GetRootComponent() const; /** * \brief Sets the root component, discarding the previous one. * * This function should not be used to set the root component * to NULL. Use ClearEmulation() instead. * * @param newRootComponent A reference counted pointer to the new * root component. It may not be a NULL pointer. */ void SetRootComponent(refcount_ptr newRootComponent); /** * \brief Resets the emulation. * * This function recursively resets all components in the tree, and * then executes the "on reset" commands (usually commands to load * files into CPUs). * * @return false if any of the reset commands failed. */ bool Reset(); /** * \brief Interrupts emulation. * * Only meaningful if RunState is Running or SingleStepping. */ void Interrupt(); /** * \brief Returns whether or not the current emulation is being * interrupted. * * Only meaningful if RunState is Running or SingleStepping. */ bool IsInterrupting() const { return m_interrupting; } /** * \brief Sets the RunState. * * @param newState The new RunState. */ void SetRunState(RunState newState); /** * \brief Gets the current RunState. * * @return The current RunState. */ RunState GetRunState() const; /** * \brief Gets the current RunState as a string. * * @return The current RunState, formatted as a string. */ string GetRunStateAsString() const; /** * \brief Gets the current step of the emulation. * * @return The nr of steps that the emulation has been executing, * since the start. */ uint64_t GetStep() const; /** * \brief Checks whether snapshots are currently enabled or not. * * @return True if running in quiet mode, false for normal operation. */ bool GetSnapshottingEnabled() const; /** * \brief Sets whether or not to use snapshots. * * @param enabled true to enable snapshotting, false to disable it. */ void SetSnapshottingEnabled(bool enabled); /** * \brief Gets the current quiet mode setting. * * @return True if running in quiet mode, false for normal operation. */ bool GetQuietMode() const; /** * \brief Sets whether or not to run in quiet mode. * * @param quietMode true to run in quiet mode, false otherwise. */ void SetQuietMode(bool quietMode); /** * \brief Sets the nr of single-steps to perform in a row. * * @param steps The number of steps, at least 1. */ void SetNrOfSingleStepsInARow(uint64_t steps); /** * \brief Change step either forwards or backwards. * * @param oldStep The old step count. * @param newStep The new step count. * @return True if changing step worked, false if there was a failure. */ bool ModifyStep(int64_t oldStep, int64_t newStep); /** * \brief Run the emulation for "a while". * * When single-stepping, this function will: *
    *
  • execute one step, *
  • set the run state to Paused, *
  • and then return. *
* * When not single-stepping, components will execute multiple steps at * once, if possible. In the most common case (no breakpoints or other * special cases), when this function returns, the run state will not * have been affected. * * @param longestTotalRun Maximum number of steps to execute. */ void Execute(const int longestTotalRun = 100000); /** * \brief Dump a list to stdout with all available machine templates. */ static void ListTemplates(); /** * \brief Returns the GXemul version string. * * @return A string describing the GXemul version. */ static string Version(); bool IsTemplateMachine(const string& templateName) const; static void DumpMachineAsHTML(const string& machineName); static void GenerateHTMLListOfComponents(bool machines); private: /** * \brief Creates an emulation setup from a template machine name. * * @param templateName The name of the template machine. * @return True if the emulation was created, false otherwise. */ bool CreateEmulationFromTemplateMachine(const string& templateName); /** * \brief Prints help message to std::cout. */ void PrintUsage() const; /** * \brief Sets the current step of the emulation. * * @param step The number of steps. */ void SetStep(uint64_t step); /** * \brief Takes a snapshot of the full emulation state. */ void TakeSnapshot(); /********************************************************************/ public: static void RunUnitTests(int& nSucceeded, int& nFailures); private: // Base: bool m_quietMode; refcount_ptr m_ui; CommandInterpreter m_commandInterpreter; vector m_onResetCommands; // Runtime: RunState m_runState; bool m_interrupting; uint64_t m_nrOfSingleStepsLeft; // Performance measurement: struct timeval m_lastOutputTime; uint64_t m_lastOutputStep; // Model: string m_emulationFileName; refcount_ptr m_rootComponent; // Snapshotting: TODO: Multiple snapshots! bool m_snapshottingEnabled; refcount_ptr m_snapshot; }; #endif // GXEMUL_H gxemul-0.6.1/src/include/cpu_mips.h000644 001750 001750 00000026154 13402411502 017437 0ustar00debugdebug000000 000000 #ifndef CPU_MIPS_H #define CPU_MIPS_H /* * Copyright (C) 2003-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * MIPS CPU definitions. */ #include "interrupt.h" #include "misc.h" struct cpu_family; struct emul; struct machine; struct timer; /* * CPU type definitions: See mips_cpu_types.h. */ struct mips_cpu_type_def { const char *name; int rev; int sub; char flags; char exc_model; /* EXC3K or EXC4K */ char mmu_model; /* MMU3K or MMU4K */ char isa_level; /* 1, 2, 3, 4, 5, 32, 64 */ char isa_revision; /* 1 or 2 (for MIPS32/64) */ int nr_of_tlb_entries; /* 32, 48, 64, ... */ char instrs_per_cycle; /* simplified, 1, 2, or 4 */ int picache; int pilinesize; int piways; int pdcache; int pdlinesize; int pdways; int scache; int slinesize; int sways; }; #define INITIAL_PC 0xffffffffbfc00000ULL #define INITIAL_STACK_POINTER (0xffffffffa0008000ULL - 256) /* * Coproc 0: * * NOTE: * On R3000, only hi and lo0 are used, and then only the lowest 32 bits. */ #define N_MIPS_COPROC_REGS 32 struct mips_tlb { uint64_t hi; uint64_t lo0; uint64_t lo1; uint64_t mask; }; /* * Coproc 1: */ /* FPU control registers: */ #define N_MIPS_FCRS 32 #define MIPS_FPU_FCIR 0 #define MIPS_FPU_FCCR 25 #define MIPS_FPU_FCSR 31 #define MIPS_FCSR_FCC0_SHIFT 23 #define MIPS_FCSR_FCC1_SHIFT 25 #define N_VADDR_TO_TLB_INDEX_ENTRIES (1 << 20) struct mips_coproc { int coproc_nr; uint64_t reg[N_MIPS_COPROC_REGS]; /* Only for COP0: */ struct mips_tlb *tlbs; int nr_of_tlbs; /* Only for COP1: floating point control registers */ /* (Maybe also for COP0?) */ uint64_t fcr[N_MIPS_FCRS]; }; #define N_MIPS_COPROCS 4 #define N_MIPS_GPRS 32 /* General purpose registers */ #define N_MIPS_FPRS 32 /* Floating point registers */ /* * These should all be 2 characters wide: * * NOTE: These are for 32-bit ABIs. For the 64-bit ABI, registers 8..11 * are used to pass arguments and are then called "a4".."a7". * * TODO: Should there be two different variants of this? It's not really * possible to figure out in some easy way if the code running was * written for a 32-bit or 64-bit ABI. */ #define MIPS_REGISTER_NAMES { \ "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3", \ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", \ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \ "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" } #define MIPS_GPR_ZERO 0 /* zero */ #define MIPS_GPR_AT 1 /* at */ #define MIPS_GPR_V0 2 /* v0 */ #define MIPS_GPR_V1 3 /* v1 */ #define MIPS_GPR_A0 4 /* a0 */ #define MIPS_GPR_A1 5 /* a1 */ #define MIPS_GPR_A2 6 /* a2 */ #define MIPS_GPR_A3 7 /* a3 */ #define MIPS_GPR_T0 8 /* t0 */ #define MIPS_GPR_T1 9 /* t1 */ #define MIPS_GPR_T2 10 /* t2 */ #define MIPS_GPR_T3 11 /* t3 */ #define MIPS_GPR_T4 12 /* t4 */ #define MIPS_GPR_T5 13 /* t5 */ #define MIPS_GPR_T6 14 /* t6 */ #define MIPS_GPR_T7 15 /* t7 */ #define MIPS_GPR_S0 16 /* s0 */ #define MIPS_GPR_S1 17 /* s1 */ #define MIPS_GPR_S2 18 /* s2 */ #define MIPS_GPR_S3 19 /* s3 */ #define MIPS_GPR_S4 20 /* s4 */ #define MIPS_GPR_S5 21 /* s5 */ #define MIPS_GPR_S6 22 /* s6 */ #define MIPS_GPR_S7 23 /* s7 */ #define MIPS_GPR_T8 24 /* t8 */ #define MIPS_GPR_T9 25 /* t9 */ #define MIPS_GPR_K0 26 /* k0 */ #define MIPS_GPR_K1 27 /* k1 */ #define MIPS_GPR_GP 28 /* gp */ #define MIPS_GPR_SP 29 /* sp */ #define MIPS_GPR_FP 30 /* fp */ #define MIPS_GPR_RA 31 /* ra */ #define N_HI6 64 #define N_SPECIAL 64 #define N_REGIMM 32 /* An "impossible" paddr: */ #define IMPOSSIBLE_PADDR 0x1212343456566767ULL #define DEFAULT_PCACHE_SIZE 15 /* 32 KB */ #define DEFAULT_PCACHE_LINESIZE 5 /* 32 bytes */ struct r3000_cache_line { uint32_t tag_paddr; int tag_valid; }; #define R3000_TAG_VALID 1 #define R3000_TAG_DIRTY 2 #define MIPS_IC_ENTRIES_SHIFT 10 #define MIPS_N_IC_ARGS 3 #define MIPS_INSTR_ALIGNMENT_SHIFT 2 #define MIPS_IC_ENTRIES_PER_PAGE (1 << MIPS_IC_ENTRIES_SHIFT) #define MIPS_PC_TO_IC_ENTRY(a) (((a)>>MIPS_INSTR_ALIGNMENT_SHIFT) \ & (MIPS_IC_ENTRIES_PER_PAGE-1)) #define MIPS_ADDR_TO_PAGENR(a) ((a) >> (MIPS_IC_ENTRIES_SHIFT \ + MIPS_INSTR_ALIGNMENT_SHIFT)) #define MIPS_L2N 17 #define MIPS_L3N 18 #define MIPS_MAX_VPH_TLB_ENTRIES 192 DYNTRANS_MISC_DECLARATIONS(mips,MIPS,uint64_t) DYNTRANS_MISC64_DECLARATIONS(mips,MIPS,uint8_t) struct mips_cpu { struct mips_cpu_type_def cpu_type; /* General purpose registers: */ uint64_t gpr[N_MIPS_GPRS]; /* Dummy destination register when writing to the zero register: */ uint64_t scratch; /* Special purpose registers: */ uint64_t hi; uint64_t lo; /* Coprocessors: */ struct mips_coproc *coproc[N_MIPS_COPROCS]; uint64_t cop0_config_select1; int last_written_tlb_index; /* Count/compare timer: */ int compare_register_set; int compare_interrupts_pending; int32_t count_register_read_count; struct interrupt irq_compare; struct timer *timer; int rmw; /* Read-Modify-Write */ uint64_t rmw_len; /* Length of rmw modification */ uint64_t rmw_addr; /* Address of rmw modification */ /* * NOTE: The R5900 has 128-bit registers. I'm not really sure * whether they are used a lot or not, at least with code produced * with gcc they are not. An important case however is lq and sq * (load and store of 128-bit values). These "upper halves" of R5900 * quadwords can be used in those cases. * * hi1 and lo1 are the high 64-bit parts of the hi and lo registers. * sa is a 32-bit "shift amount" register. * * TODO: Generalize this. */ uint64_t gpr_quadhi[N_MIPS_GPRS]; uint64_t hi1; uint64_t lo1; uint32_t r5900_sa; /* * Data and Instruction caches: */ /* Cache sizes: (1 << x) x=0 for default values */ /* This is legacy stuff. TODO: Clean up! */ int cache_picache; int cache_pdcache; int cache_secondary; int cache_picache_linesize; int cache_pdcache_linesize; int cache_secondary_linesize; unsigned char *cache[2]; void *cache_tags[2]; uint64_t cache_last_paddr[2]; int cache_size[2]; int cache_linesize[2]; int cache_mask[2]; /* * Instruction translation cache and Virtual->Physical->Host * address translation: */ DYNTRANS_ITC(mips) VPH_TLBS(mips,MIPS) VPH32(mips,MIPS) VPH64(mips,MIPS) }; /* cpu_mips.c: */ void mips_cpu_interrupt_assert(struct interrupt *interrupt); void mips_cpu_interrupt_deassert(struct interrupt *interrupt); int mips_cpu_instruction_has_delayslot(struct cpu *cpu, unsigned char *ib); void mips_cpu_tlbdump(struct machine *m, int x, int rawflag); void mips_cpu_register_match(struct machine *m, char *name, int writeflag, uint64_t *valuep, int *match_register); void mips_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs); int mips_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr, int running, uint64_t addr); void mips_cpu_exception(struct cpu *cpu, int exccode, int tlb, uint64_t vaddr, /* uint64_t pagemask, */ int coproc_nr, uint64_t vaddr_vpn2, int vaddr_asid, int x_64); int mips_cpu_run(struct emul *emul, struct machine *machine); void mips_cpu_dumpinfo(struct cpu *cpu); void mips_cpu_list_available_types(void); int mips_cpu_family_init(struct cpu_family *); /* cpu_mips_coproc.c: */ struct mips_coproc *mips_coproc_new(struct cpu *cpu, int coproc_nr); void mips_coproc_tlb_set_entry(struct cpu *cpu, int entrynr, int size, uint64_t vaddr, uint64_t paddr0, uint64_t paddr1, int valid0, int valid1, int dirty0, int dirty1, int global, int asid, int cachealgo0, int cachealgo1); void coproc_register_read(struct cpu *cpu, struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int select); void coproc_register_write(struct cpu *cpu, struct mips_coproc *cp, int reg_nr, uint64_t *ptr, int flag64, int select); void coproc_tlbpr(struct cpu *cpu, int readflag); void coproc_tlbwri(struct cpu *cpu, int randomflag); void coproc_rfe(struct cpu *cpu); void coproc_eret(struct cpu *cpu); void coproc_function(struct cpu *cpu, struct mips_coproc *cp, int cpnr, uint32_t function, int unassemble_only, int running); /* memory_mips.c: */ int memory_cache_R3000(struct cpu *cpu, int cache, uint64_t paddr, int writeflag, size_t len, unsigned char *data); int mips_memory_rw(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags); int translate_v2p_mmu3k(struct cpu *cpu, uint64_t vaddr, uint64_t *return_addr, int flags); int translate_v2p_mmu8k(struct cpu *cpu, uint64_t vaddr, uint64_t *return_addr, int flags); int translate_v2p_mmu10k(struct cpu *cpu, uint64_t vaddr, uint64_t *return_addr, int flags); int translate_v2p_mmu4100(struct cpu *cpu, uint64_t vaddr, uint64_t *return_addr, int flags); int translate_v2p_generic(struct cpu *cpu, uint64_t vaddr, uint64_t *return_addr, int flags); /* Dyntrans unaligned load/store: */ void mips_unaligned_loadstore(struct cpu *cpu, struct mips_instr_call *ic, int is_left, int wlen, int store); int mips_run_instr(struct cpu *cpu); void mips_update_translation_table(struct cpu *cpu, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page); void mips_invalidate_translation_caches(struct cpu *cpu, uint64_t, int); void mips_invalidate_code_translation(struct cpu *cpu, uint64_t, int); int mips32_run_instr(struct cpu *cpu); void mips32_update_translation_table(struct cpu *cpu, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page); void mips32_invalidate_translation_caches(struct cpu *cpu, uint64_t, int); void mips32_invalidate_code_translation(struct cpu *cpu, uint64_t, int); #endif /* CPU_MIPS_H */ gxemul-0.6.1/src/include/SymbolRegistry.h000644 001750 001750 00000005414 13402411502 020612 0ustar00debugdebug000000 000000 #ifndef SYMBOLREGISTRY_H #define SYMBOLREGISTRY_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "UnitTest.h" /** * \brief A registry for loaded symbols. */ class SymbolRegistry : public UnitTestable { public: /** * \brief Constructs a SymbolRegistry. */ SymbolRegistry(); /** * \brief Clears the registry. */ void Clear(); /** * \brief Adds a symbol to the registry. * * @param symbol The symbol name. * @param vaddr The virtual address. */ void AddSymbol(const string& symbol, uint64_t vaddr); /** * \brief Looks up an address. * * The returned address may be of the format "symbol+offset", where * offset is a hexadecimal number, if allowOffset is true. * * @param vaddr The virtual address. * @param allowOffset If false, the address must be found exactly. * If true, a symbol which almost matches the address, plus an * offset, may be returned. * @return A string representing the address, or an empty string * if no suitable match was found. */ string LookupAddress(uint64_t vaddr, bool allowOffset) const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); private: typedef map SymbolMap; SymbolMap m_map; }; #endif // SYMBOLREGISTRY_H gxemul-0.6.1/src/include/ConsoleUI.h000644 001750 001750 00000010524 13402411502 017452 0ustar00debugdebug000000 000000 #ifndef CONSOLEUI_H #define CONSOLEUI_H /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include "UI.h" /** * \brief Text-terminal based User Interface. */ class ConsoleUI : public UI { public: /** * \brief Constructs a text console %UI instance. * * @param gxemul Pointer to the owning GXemul instance. */ ConsoleUI(GXemul *gxemul); virtual ~ConsoleUI(); /** * \brief Initializes the terminal for blocking, non-echo I/O. */ virtual void Initialize(); /** * \brief Updates UI items. Not used for %ConsoleUI. */ virtual void UpdateUI(); /** * \brief Prints the text console startup banner. */ virtual void ShowStartupBanner(); /** * \brief Shows a debug message, by printing it to stdout. * * @param msg The message to show. */ virtual void ShowDebugMessage(const string& msg); /** * \brief Shows a debug message for a Component, by printing it to * stdout. * * See UI::ShowDebugMessage(Component*,const string&) for * a longer comment. * * @param component A pointer to the Component. * @param msg The message to show. */ virtual void ShowDebugMessage(Component* component, const string& msg); /** * \brief Does nothing for the %ConsoleUI. * * @param command The command being executed. */ virtual void ShowCommandMessage(const string& command); /** * \brief Shows a fatal error message, by printing it to stderr. * * @param msg The error message to show. */ virtual void FatalError(const string& msg); /** * \brief Redisplays the interactive command input line. * * For the %ConsoleUI, this function displays a prompt ("GXemul> ") * followed by the input line, placing the cursor position at * the correct position on the input line. * * @param inputline The entire input line. * @param cursorPosition The current cursor position. 0 is at the * leftmost position. */ virtual void RedisplayInputLine(const string& inputline, size_t cursorPosition); /** * \brief Executed by the CommandInterpreter when a line has been * completed (with a newline). * * For the %ConsoleUI, this simply outputs a newline character. */ virtual void InputLineDone(); /** * \brief Runs the text console main loop. * * As long as the RunState is not Quitting: *
    *
  • If an emulation is Running, the main loop lets the * emulation run, until Ctrl-C is pressed. *
  • Otherwise, if the RunState is Paused, the main loop shows * a prompt and lets the user input commands. *
*/ virtual int MainLoop(); virtual void Shutdown(); private: /** * \brief Shows the %GXemul> prompt, reads characters from stdin * until a newline char, and executes the resulting command. * * This function is blocking. */ void ReadAndExecuteCommand(); private: bool m_consoleIsInitialized; struct termios m_oldTermios; struct termios m_currentTermios; }; #endif // CONSOLEUI_H gxemul-0.6.1/src/include/cpu_m88k.h000644 001750 001750 00000022750 13402411502 017254 0ustar00debugdebug000000 000000 #ifndef CPU_M88K_H #define CPU_M88K_H /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Motorola 88x00 CPU definitions. */ #include "misc.h" #include "interrupt.h" #include "thirdparty/m88k_psl.h" struct cpu_family; /* M88K CPU types: */ struct m88k_cpu_type_def { const char *name; int type; uint32_t pid; }; #define M88K_PID(arn,vn) ((arn << M88K_ARN_SHIFT) | (vn << M88K_VN_SHIFT)) #define M88K_CPU_TYPE_DEFS { \ { "88100", 88100, M88K_PID(M88K_ARN_88100,3) }, \ { "88110", 88110, M88K_PID(M88K_ARN_88110,0) }, \ { NULL, 0, 0 } \ } /* Control register names: */ #define N_M88K_CONTROL_REGS 64 #define M88K_CR_NAMES { \ "PID", "PSR", "EPSR", "SSBR", /* 0 .. 3 */ \ "SXIP", "SNIP", "SFIP", "VBR", /* 4 .. 7 */ \ "DMT0", "DMD0", "DMA0", "DMT1", /* 8 .. 11 */ \ "DMD1", "DMA1", "DMT2", "DMD2", /* 12 .. 15 */ \ "DMA2", "SR0", "SR1", "SR2", /* 16 .. 19 */ \ "SR3", "CR21", "CR22", "CR23", /* 20 .. 23 */ \ "CR24", "CR25", "CR26", "CR27", /* 24 .. 27 */ \ "CR28", "CR29", "CR30", "CR31", /* 28 .. 31 */ \ "CR32", "CR33", "CR34", "CR35", /* 32 .. 35 */ \ "CR36", "CR37", "CR38", "CR39", /* 36 .. 39 */ \ "CR40", "CR41", "CR42", "CR43", /* 40 .. 43 */ \ "CR44", "CR45", "CR46", "CR47", /* 44 .. 47 */ \ "CR48", "CR49", "CR50", "CR51", /* 48 .. 51 */ \ "CR52", "CR53", "CR54", "CR55", /* 52 .. 55 */ \ "CR56", "CR57", "CR58", "CR59", /* 56 .. 59 */ \ "CR60", "CR61", "CR62", "CR63" /* 60 .. 63 */ } #define M88K_CR_PID 0 #define M88K_CR_PSR 1 #define M88K_CR_EPSR 2 #define M88K_CR_SSBR 3 #define M88K_CR_SXIP 4 #define M88K_CR_SNIP 5 #define M88K_CR_SFIP 6 #define M88K_CR_VBR 7 #define M88K_CR_DMT0 8 #define M88K_CR_DMD0 9 #define M88K_CR_DMA0 10 #define M88K_CR_DMT1 11 #define M88K_CR_DMD1 12 #define M88K_CR_DMA1 13 #define M88K_CR_DMT2 14 #define M88K_CR_DMD2 15 #define M88K_CR_DMA2 16 #define M88K_CR_SR0 17 #define M88K_CR_SR1 18 #define M88K_CR_SR2 19 #define M88K_CR_SR3 20 /* MVME197 extended control registers: */ #define M88K_CR_NAMES_197 { \ "PID", "PSR", "EPSR", "SSBR", /* 0 .. 3 */ \ "EXIP", "ENIP", "SFIP", "VBR", /* 4 .. 7 */ \ "DMT0", "DMD0", "DMA0", "DMT1", /* 8 .. 11 */ \ "DMD1", "DMA1", "DMT2", "DMD2", /* 12 .. 15 */ \ "SRX", "SR0", "SR1", "SR2", /* 16 .. 19 */ \ "SR3", "CR21", "CR22", "CR23", /* 20 .. 23 */ \ "CR24", "ICMD", "ICTL", "ISAR", /* 24 .. 27 */ \ "ISAP", "IUAP", "IIR", "IBP", /* 28 .. 31 */ \ "IPPU", "IPPL", "ISR", "ILAR", /* 32 .. 35 */ \ "IPAR", "CR37", "CR38", "CR39", /* 36 .. 39 */ \ "DCMD", "DCTL", "DSAR", "DSAP", /* 40 .. 43 */ \ "DUAP", "DIR", "DBP", "DPPU", /* 44 .. 47 */ \ "DPPL", "DSR", "DLAR", "DPAR", /* 48 .. 51 */ \ "CR52", "CR53", "CR54", "CR55", /* 52 .. 55 */ \ "CR56", "CR57", "CR58", "CR59", /* 56 .. 59 */ \ "CR60", "CR61", "CR62", "CR63" /* 60 .. 63 */ } #define M88K_CR_EXIP 4 #define M88K_CR_ENIP 5 #define M88K_CR_SRX 16 #define M88K_CR_ICMD 25 #define M88K_CR_ICTL 26 #define M88K_CR_ISAR 27 #define M88K_CR_ISAP 28 #define M88K_CR_IUAP 29 #define M88K_CR_IIR 30 #define M88K_CR_IBP 31 #define M88K_CR_IPPU 32 #define M88K_CR_IPPL 33 #define M88K_CR_ISR 34 #define M88K_CR_ILAR 35 #define M88K_CR_IPAR 36 #define M88K_CR_DCMD 40 #define M88K_CR_DCTL 41 #define M88K_CR_DSAR 42 #define M88K_CR_DSAP 43 #define M88K_CR_DUAP 44 #define M88K_CR_DIR 45 #define M88K_CR_DBP 46 #define M88K_CR_DPPU 47 #define M88K_CR_DPPL 48 #define M88K_CR_DSR 49 #define M88K_CR_DLAR 50 #define M88K_CR_DPAR 51 #define N_M88K_FPU_CONTROL_REGS 64 #define M88K_FPCR_FPECR 0 #define M88K_FPECR_FDVZ (1 << 3) #define M88K_FPECR_FUNIMP (1 << 6) /* ... TODO: more */ #define M88K_N_IC_ARGS 3 #define M88K_INSTR_ALIGNMENT_SHIFT 2 #define M88K_IC_ENTRIES_SHIFT 10 #define M88K_IC_ENTRIES_PER_PAGE (1 << M88K_IC_ENTRIES_SHIFT) #define M88K_PC_TO_IC_ENTRY(a) (((a)>>M88K_INSTR_ALIGNMENT_SHIFT) \ & (M88K_IC_ENTRIES_PER_PAGE-1)) #define M88K_ADDR_TO_PAGENR(a) ((a) >> (M88K_IC_ENTRIES_SHIFT \ + M88K_INSTR_ALIGNMENT_SHIFT)) DYNTRANS_MISC_DECLARATIONS(m88k,M88K,uint32_t) #define M88K_MAX_VPH_TLB_ENTRIES 128 #define N_M88K_REGS 32 /* Register r0 is always zero, r1 is the return address on function calls. */ #define M88K_ZERO_REG 0 #define M88K_RETURN_REG 1 #define M88K_CMP_HS 0x00000800 #define M88K_CMP_LO 0x00000400 #define M88K_CMP_LS 0x00000200 #define M88K_CMP_HI 0x00000100 #define M88K_CMP_GE 0x00000080 #define M88K_CMP_LT 0x00000040 #define M88K_CMP_LE 0x00000020 #define M88K_CMP_GT 0x00000010 #define M88K_CMP_NE 0x00000008 #define M88K_CMP_EQ 0x00000004 /* Exception numbers: */ #define M88K_EXCEPTION_RESET 0 #define M88K_EXCEPTION_INTERRUPT 1 #define M88K_EXCEPTION_INSTRUCTION_ACCESS 2 #define M88K_EXCEPTION_DATA_ACCESS 3 #define M88K_EXCEPTION_MISALIGNED_ACCESS 4 #define M88K_EXCEPTION_UNIMPLEMENTED_OPCODE 5 #define M88K_EXCEPTION_PRIVILEGE_VIOLATION 6 #define M88K_EXCEPTION_BOUNDS_CHECK_VIOLATION 7 #define M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE 8 #define M88K_EXCEPTION_INTEGER_OVERFLOW 9 #define M88K_EXCEPTION_ERROR 10 #define M88K_EXCEPTION_SFU1_PRECISE 114 #define M88K_EXCEPTION_SFU1_IMPRECISE 115 #define M88K_EXCEPTION_USER_TRAPS_START 128 /* A reserved/unimplemented instruction, used for PROM calls: */ #define M88K_PROM_INSTR 0xf400fc92 /* * M88200/88204 CMMU: */ #define MAX_M8820X_CMMUS 8 #define M8820X_LENGTH 0x1000 #define N_M88200_BATC_REGS 10 #define N_M88200_PATC_ENTRIES 56 #define M8820X_PATC_SUPERVISOR_BIT 0x00000001 struct m8820x_cmmu { uint32_t reg[M8820X_LENGTH / sizeof(uint32_t)]; uint32_t batc[N_M88200_BATC_REGS]; uint32_t patc_v_and_control[N_M88200_PATC_ENTRIES]; uint32_t patc_p_and_supervisorbit[N_M88200_PATC_ENTRIES]; int patc_update_index; }; struct m88k_cpu { struct m88k_cpu_type_def cpu_type; /* * General-Purpose Registers: * * 32 (N_M88K_REGS) registers, plus one which is always zero. (This * is to support st.d with d = r31. ld.d with d=r31 is converted to * just ld. TODO) */ uint32_t r[N_M88K_REGS+1]; /* Destination scratch register for non-nop instructions with d=r0: */ uint32_t zero_scratch; /* Control Registers: */ uint32_t cr[N_M88K_CONTROL_REGS]; /* Floating Point Control registers: */ uint32_t fcr[N_M88K_FPU_CONTROL_REGS]; /* Current interrupt assertion: */ int irq_asserted; /* CMMUs (Cache/Memory Management Units): */ struct m8820x_cmmu *cmmu[MAX_M8820X_CMMUS]; /* Current memory transaction fault registers: */ uint32_t dmt[2]; uint32_t dmd[2]; uint32_t dma[2]; /* Delayed-branch target (for exception handling): */ uint32_t delay_target; /* * Instruction translation cache, internal TLB structure, and 32-bit * virtual -> physical -> host address translation arrays for both * normal access and for the special .usr access mode (available in * supervisor mode). */ DYNTRANS_ITC(m88k) VPH_TLBS(m88k,M88K) VPH32(m88k,M88K) VPH32EXTENDED(m88k,M88K,usr) }; /* cpu_m88k.c: */ int m88k_cpu_instruction_has_delayslot(struct cpu *cpu, unsigned char *ib); int m88k_run_instr(struct cpu *cpu); void m88k_update_translation_table(struct cpu *cpu, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page); void m88k_invalidate_translation_caches(struct cpu *cpu, uint64_t, int); void m88k_invalidate_code_translation(struct cpu *cpu, uint64_t, int); int m88k_memory_rw(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags); int m88k_cpu_family_init(struct cpu_family *); void m88k_ldcr(struct cpu *cpu, uint32_t *r32ptr, int cr); void m88k_stcr(struct cpu *cpu, uint32_t value, int cr, int rte); void m88k_fstcr(struct cpu *cpu, uint32_t value, int fcr); void m88k_exception(struct cpu *cpu, int vector, int is_trap); /* memory_m88k.c: */ int m88k_translate_v2p(struct cpu *cpu, uint64_t vaddr, uint64_t *return_addr, int flags); #endif /* CPU_M88K_H */ gxemul-0.6.1/src/include/arm_cpu_types.h000644 001750 001750 00000011566 13402411502 020473 0ustar00debugdebug000000 000000 #ifndef ARM_CPU_TYPES_H #define ARM_CPU_TYPES_H /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* See cpu_arm.h for struct arm_cpu_type_def. */ /* See arm_cputypes.h for CPU_ID_xxx defines. */ /* TODO: Refactor these flags */ /* TODO: Include "ARM level", i.e. ARMv5 */ /* Flags: */ #define ARM_NO_MMU 1 #define ARM_DUAL_ENDIAN 2 #define ARM_XSCALE 4 #include "thirdparty/arm_cputypes.h" /* * NOTE: Most of these are bogus! */ #define ARM_CPU_TYPE_DEFS { \ { "ARM3", CPU_ID_ARM3, ARM_DUAL_ENDIAN,12, 1, 0, 1 }, \ { "ARM610", CPU_ID_ARM600, ARM_DUAL_ENDIAN,12, 1, 0, 1 }, \ { "ARM610", CPU_ID_ARM610, ARM_DUAL_ENDIAN,12, 1, 0, 1 }, \ { "ARM620", CPU_ID_ARM620, ARM_DUAL_ENDIAN,12, 1, 0, 1 }, \ \ { "ARM700", CPU_ID_ARM700, 0, 12, 1, 0, 1 }, \ { "ARM710", CPU_ID_ARM710, 0, 12, 1, 0, 1 }, \ { "ARM710A", CPU_ID_ARM710A, 0, 12, 1, 0, 1 }, \ { "ARM720T", CPU_ID_ARM720T, 0, 12, 1, 0, 1 }, \ { "ARM740T4K", CPU_ID_ARM740T4K,ARM_NO_MMU, 12, 1, 0, 1 }, \ { "ARM740T8K", CPU_ID_ARM740T8K,ARM_NO_MMU, 13, 1, 0, 1 }, \ { "ARM7500", CPU_ID_ARM7500, 0, 12, 1, 0, 1 }, \ { "ARM7500FE", CPU_ID_ARM7500FE,0, 12, 1, 0, 1 }, \ \ { "ARM810", CPU_ID_ARM810, 0, 12, 1, 0, 1 }, \ { "ARM920T", CPU_ID_ARM920T, 0, 14, 1, 14, 1 }, \ { "ARM922T", CPU_ID_ARM922T, 0, 12, 1, 0, 1 }, \ { "ARM940T", CPU_ID_ARM940T, ARM_NO_MMU, 12, 1, 0, 1 }, \ \ { "ARM946ES", CPU_ID_ARM946ES,ARM_NO_MMU, 12, 1, 0, 1 }, \ { "ARM966ES", CPU_ID_ARM966ES,ARM_NO_MMU, 12, 1, 0, 1 }, \ { "ARM966ESR1", CPU_ID_ARM966ESR1,ARM_NO_MMU, 12, 1, 0, 1 }, \ \ { "ARM1020E", CPU_ID_ARM1020E,0, 12, 1, 0, 1 }, \ { "ARM1022ES", CPU_ID_ARM1022ES,0, 12, 1, 0, 1 }, \ { "ARM1026EJS", CPU_ID_ARM1026EJS,0, 12, 1, 0, 1 }, \ { "ARM1136JS", CPU_ID_ARM1136JS,0, 12, 1, 0, 1 }, \ { "ARM1136JSR1",CPU_ID_ARM1136JSR1,0, 12, 1, 0, 1 }, \ \ { "SA110", CPU_ID_SA110 | 3, 0, 14, 1, 14, 1 }, \ { "SA1100", CPU_ID_SA1100, 0, 14, 1, 14, 1 }, \ { "SA1110", CPU_ID_SA1110, 0, 14, 1, 14, 1 }, \ \ { "TI925T", CPU_ID_TI925T, 0, 14, 1, 14, 1 }, \ { "IXP1200", CPU_ID_IXP1200, 0, 14, 1, 14, 1 }, \ { "80200", CPU_ID_80200, 0, 14, 1, 14, 1 }, \ \ { "PXA210", CPU_ID_PXA210, ARM_XSCALE, 16, 1, 0, 1 }, \ { "PXA210A", CPU_ID_PXA210A, ARM_XSCALE, 16, 1, 0, 1 }, \ { "PXA210B", CPU_ID_PXA210B, ARM_XSCALE, 16, 1, 0, 1 }, \ { "PXA210C", CPU_ID_PXA210C, ARM_XSCALE, 16, 1, 0, 1 }, \ { "PXA250", CPU_ID_PXA250, ARM_XSCALE, 16, 1, 0, 1 }, \ { "PXA250A", CPU_ID_PXA250A, ARM_XSCALE, 16, 1, 0, 1 }, \ { "PXA250B", CPU_ID_PXA250B, ARM_XSCALE, 16, 1, 0, 1 }, \ { "PXA250C", CPU_ID_PXA250C, ARM_XSCALE, 16, 1, 0, 1 }, \ { "PXA27X", CPU_ID_PXA27X, ARM_XSCALE, 16, 1, 0, 1 }, \ \ { "IXP425_255", CPU_ID_IXP425_266,ARM_XSCALE, 15, 1, 15, 1 }, \ { "IXP425_400", CPU_ID_IXP425_400,ARM_XSCALE, 15, 1, 15, 1 }, \ { "IXP425_533", CPU_ID_IXP425_533,ARM_XSCALE, 15, 1, 15, 1 }, \ \ { "CORTEX-A5", CPU_ID_CORTEXA5R0,0/*TODO*/, 15, 1, 15, 1 }, \ \ { "80219_400", CPU_ID_80219_400,ARM_XSCALE, 15, 1, 15, 1 }, \ { "80219_600", CPU_ID_80219_600,ARM_XSCALE, 15, 1, 15, 1 }, \ { "80321_400", CPU_ID_80321_400,ARM_XSCALE, 15, 1, 15, 1 }, \ { "80321_400_B0",CPU_ID_80321_400_B0,ARM_XSCALE,15, 1, 15, 1 }, \ { "80321_600", CPU_ID_80321_600,ARM_XSCALE, 15, 1, 15, 1 }, \ { "80321_600_B0",CPU_ID_80321_600_B0,ARM_XSCALE,15, 1, 15, 1 }, \ { "80321_600_2",CPU_ID_80321_600_2,ARM_XSCALE,15, 1, 15, 1 }, \ \ { NULL, 0, 0, 0,0, 0,0 } } #endif /* ARM_CPU_TYPES_H */ gxemul-0.6.1/src/include/devices.h000644 001750 001750 00000050045 13402411502 017236 0ustar00debugdebug000000 000000 #ifndef DEVICES_H #define DEVICES_H /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * _LEGACY_ memory mapped devices. * * NOTE: Many of these devices are legacy devices, that are here for one * of these two reasons: * * A) Devices introduced before the DEVINIT system had to * be declared somewhere. * * B) The way interrupt controllers and such were implemented * up until release 0.4.3 requires that several parts of * the program access internal fields of interrupt * controllers' structs. * * Both A and B need to be solved. */ #include #include #include "interrupt.h" struct cpu; struct machine; struct memory; struct pci_data; struct timer; /* #ifdef WITH_X11 #include #endif */ /* dev_8259.c: */ struct pic8259_data { struct interrupt irq; int irq_base; int current_command; int init_state; int priority_reg; uint8_t irr; /* interrupt request register */ uint8_t isr; /* interrupt in-service register */ uint8_t ier; /* interrupt enable register */ }; /* dev_dec_ioasic.c: */ #define DEV_DEC_IOASIC_LENGTH 0xc0000 #define MAX_IOASIC_DMA_FUNCTIONS 8 struct dec_ioasic_data { uint32_t scsi_dmaptr; /* 0x000 */ uint32_t scsi_nextptr; /* 0x010 */ uint32_t lance_dmaptr; /* 0x020 */ uint32_t floppy_dmaptr; /* 0x070 */ uint32_t isdn_x_dmaptr; /* 0x080 */ uint32_t isdn_x_nextptr; /* 0x090 */ uint32_t isdn_r_dmaptr; /* 0x0a0 */ uint32_t isdn_r_nextptr; /* 0x0b0 */ uint32_t csr; /* 0x100 */ uint32_t intr; /* 0x110 */ uint32_t imsk; /* 0x120 */ uint32_t isdn_x_data; /* 0x140 */ uint32_t isdn_r_data; /* 0x150 */ uint32_t lance_decode; /* 0x160 */ uint32_t scsi_decode; /* 0x170 */ uint32_t scc0_decode; /* 0x180 */ uint32_t scc1_decode; /* 0x190 */ uint32_t floppy_decode; /* 0x1a0 */ uint32_t scsi_scr; /* 0x1b0 */ uint32_t scsi_sdr0; /* 0x1c0 */ uint32_t scsi_sdr1; /* 0x1d0 */ int (*dma_func[MAX_IOASIC_DMA_FUNCTIONS])(struct cpu *, void *, uint64_t addr, size_t dma_len, int tx); void *dma_func_extra[MAX_IOASIC_DMA_FUNCTIONS]; int rackmount_flag; struct interrupt *irq; int int_asserted; }; void dec_ioasic_reassert(struct dec_ioasic_data*); int dev_dec_ioasic_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); struct dec_ioasic_data *dev_dec_ioasic_init(struct cpu *cpu, struct memory *mem, uint64_t baseaddr, int rackmount_flag, struct interrupt* irq); /* dev_asc.c: */ #define DEV_ASC_DEC_LENGTH 0x40000 #define DEV_ASC_PICA_LENGTH 0x1000 #define DEV_ASC_DEC 1 #define DEV_ASC_PICA 2 int dev_asc_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_asc_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, const char *irq_path, void *turbochannel, int mode, size_t (*dma_controller)(void *dma_controller_data, unsigned char *data, size_t len, int writeflag), void *dma_controller_data); /* dev_bt431.c: */ #define DEV_BT431_LENGTH 0x20 #define DEV_BT431_NREGS 0x800 /* ? */ int dev_bt431_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); struct vfb_data; void dev_bt431_init(struct memory *mem, uint64_t baseaddr, struct vfb_data *vfb_data, int color_fb_flag); /* dev_bt455.c: */ #define DEV_BT455_LENGTH 0x20 int dev_bt455_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); struct vfb_data; void dev_bt455_init(struct memory *mem, uint64_t baseaddr, struct vfb_data *vfb_data); /* dev_bt459.c: */ #define DEV_BT459_LENGTH 0x20 #define DEV_BT459_NREGS 0x1000 #define BT459_PX 1 /* px[g] */ #define BT459_BA 2 /* cfb */ #define BT459_BBA 3 /* sfb */ int dev_bt459_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); struct vfb_data; void dev_bt459_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, uint64_t baseaddr_irq, struct vfb_data *vfb_data, int color_fb_flag, const char *irq_path, int type); /* dev_colorplanemask.c: */ #define DEV_COLORPLANEMASK_LENGTH 0x0000000000000010 int dev_colorplanemask_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_colorplanemask_init(struct memory *mem, uint64_t baseaddr, unsigned char *color_plane_mask); /* dev_dc7085.c: */ #define DEV_DC7085_LENGTH 0x0000000000000080 /* see dc7085.h for more info */ void dev_dc7085_tick(struct cpu *cpu, void *); int dev_dc7085_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); int dev_dc7085_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, char *irq_path, int use_fb); /* dev_dec5800.c: */ #define DEV_DECCCA_LENGTH 0x10000 /* ? */ #define DEC_DECCCA_BASEADDR 0x19000000 /* ? I just made this up */ int dev_deccca_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_deccca_init(struct memory *mem, uint64_t baseaddr); #define DEV_DECXMI_LENGTH 0x800000 int dev_decxmi_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_decxmi_init(struct memory *mem, uint64_t baseaddr); /* dev_fb.c: */ #define DEV_FB_LENGTH 0x3c0000 /* 3c0000 to not colide with */ /* turbochannel rom, */ /* otherwise size = 4MB */ /* Type: */ #define VFB_GENERIC 0 #define VFB_HPC 1 #define VFB_DEC_VFB01 2 #define VFB_DEC_VFB02 3 #define VFB_DEC_MAXINE 4 #define VFB_PLAYSTATION2 5 /* Extra flags: */ #define VFB_REVERSE_START 0x10000 struct vfb_data { struct memory *memory; int vfb_type; int vfb_scaledown; int xsize; int ysize; int bit_depth; int color32k; /* hack for 16-bit HPCmips */ int psp_15bit; /* playstation portable hack */ unsigned char color_plane_mask; int bytes_per_line; /* cached */ int visible_xsize; int visible_ysize; size_t framebuffer_size; int x11_xsize, x11_ysize; int update_x1, update_y1, update_x2, update_y2; /* RGB palette for <= 8 bit modes: (r,g,b bytes for each) */ unsigned char rgb_palette[256 * 3]; char *name; char title[100]; void (*redraw_func)(struct vfb_data *, int, int); /* These should always be in sync: */ unsigned char *framebuffer; struct fb_window *fb_window; }; #define VFB_MFB_BT455 0x100000 #define VFB_MFB_BT431 0x180000 #define VFB_MFB_VRAM 0x200000 #define VFB_CFB_BT459 0x200000 void set_grayscale_palette(struct vfb_data *d, int ncolors); void dev_fb_resize(struct vfb_data *d, int new_xsize, int new_ysize); void dev_fb_setcursor(struct vfb_data *d, int cursor_x, int cursor_y, int on, int cursor_xsize, int cursor_ysize); void framebuffer_blockcopyfill(struct vfb_data *d, int fillflag, int fill_r, int fill_g, int fill_b, int x1, int y1, int x2, int y2, int from_x, int from_y); void dev_fb_tick(struct cpu *, void *); int dev_fb_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); struct vfb_data *dev_fb_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize, int xsize, int ysize, int bit_depth, const char *name); /* dev_gt.c: */ #define DEV_GT_LENGTH 0x1000 int dev_gt_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); struct pci_data *dev_gt_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, const char *timer_irq_path, const char *isa_irq_path, int type); /* dev_jazz.c: */ size_t dev_jazz_dma_controller(void *dma_controller_data, unsigned char *data, size_t len, int writeflag); /* dev_kn01.c: */ #define DEV_KN01_LENGTH 4 int dev_kn01_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_kn01_init(struct memory *mem, uint64_t baseaddr, int color_fb); #define DEV_VDAC_LENGTH 0x20 #define DEV_VDAC_MAPWA 0x00 #define DEV_VDAC_MAP 0x04 #define DEV_VDAC_MASK 0x08 #define DEV_VDAC_MAPRA 0x0c #define DEV_VDAC_OVERWA 0x10 #define DEV_VDAC_OVER 0x14 #define DEV_VDAC_OVERRA 0x1c int dev_vdac_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_vdac_init(struct memory *mem, uint64_t baseaddr, unsigned char *rgb_palette, int color_fb_flag); /* dev_kn220.c: */ #define DEV_DEC5500_IOBOARD_LENGTH 0x100000 int dev_dec5500_ioboard_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); struct dec5500_ioboard_data *dev_dec5500_ioboard_init(struct cpu *cpu, struct memory *mem, uint64_t baseaddr); #define DEV_SGEC_LENGTH 0x1000 int dev_sgec_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_sgec_init(struct memory *mem, uint64_t baseaddr, int irq_nr); /* dev_le.c: */ #define DEV_LE_LENGTH 0x1c0200 int dev_le_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_le_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, uint64_t buf_start, uint64_t buf_end, const char *irq_path, int len); /* dev_mc146818.c: */ #define DEV_MC146818_LENGTH 0x0000000000000100 #define MC146818_DEC 0 #define MC146818_PC_CMOS 1 #define MC146818_ARC_NEC 2 #define MC146818_ARC_JAZZ 3 #define MC146818_SGI 4 #define MC146818_CATS 5 #define MC146818_ALGOR 6 #define MC146818_PMPPC 7 /* see mc146818reg.h for more info */ void dev_mc146818_tick(struct cpu *cpu, void *); int dev_mc146818_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_mc146818_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, char *irq_path, int access_style, int addrdiv); /* dev_pckbc.c: */ #define DEV_PCKBC_LENGTH 0x10 #define PCKBC_8042 0 #define PCKBC_8242 1 #define PCKBC_JAZZ 3 int dev_pckbc_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); int dev_pckbc_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, int type, char *keyboard_irqpath, char *mouse_irqpath, int in_use, int pc_style_flag); /* dev_pmagja.c: */ #define DEV_PMAGJA_LENGTH 0x3c0000 int dev_pmagja_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_pmagja_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, const char *irq_path); /* dev_px.c: */ struct px_data { struct memory *fb_mem; struct vfb_data *vfb_data; int type; const char *px_name; struct interrupt irq; int bitdepth; int xconfig; int yconfig; uint32_t intr; unsigned char sram[128 * 1024]; }; /* TODO: perhaps these types are wrong? */ #define DEV_PX_TYPE_PX 0 #define DEV_PX_TYPE_PXG 1 #define DEV_PX_TYPE_PXGPLUS 2 #define DEV_PX_TYPE_PXGPLUSTURBO 3 #define DEV_PX_LENGTH 0x3c0000 int dev_px_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_px_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, int px_type, const char *irq_path); /* dev_ram.c: */ #define DEV_RAM_RAM 0 #define DEV_RAM_MIRROR 1 #define DEV_RAM_MIGHT_POINT_TO_DEVICES 0x10 #define DEV_RAM_TRACE_ALL_ACCESSES 0x20 int dev_ram_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_ram_init(struct machine *machine, uint64_t baseaddr, uint64_t length, int mode, uint64_t otheraddr, const char* name = NULL); /* dev_scc.c: */ #define DEV_SCC_LENGTH 0x1000 int dev_scc_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); int dev_scc_dma_func(struct cpu *cpu, void *extra, uint64_t addr, size_t dma_len, int tx); void *dev_scc_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, char* irq_path, int use_fb, int scc_nr, int addrmul); /* dev_sfb.c: */ #define DEV_SFB_LENGTH 0x400000 int dev_sfb_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_sfb_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, struct vfb_data *vfb_data); /* dev_sgi_gbe.c: */ #define DEV_SGI_GBE_LENGTH 0x1000000 int dev_sgi_gbe_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_sgi_gbe_init(struct machine *machine, struct memory *mem, uint64_t baseaddr); /* dev_sgi_re.cc: */ // SGI O2 Rendering Engine: #define DEV_SGI_RE_LENGTH 0x1000 int dev_sgi_re_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_sgi_re_init(struct machine *machine, struct memory *mem, uint64_t baseaddr); // SGI O2 Drawing Engine: #define DEV_SGI_DE_LENGTH 0x1000 int dev_sgi_de_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_sgi_de_init(struct memory *mem, uint64_t baseaddr, struct sgi_re_data *); // SGI O2 Memory Transfer Engine: #define DEV_SGI_MTE_LENGTH 0x1000 int dev_sgi_re_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr, struct sgi_re_data *); // SGI O2 Rendering Engine: #define DEV_SGI_DE_STATUS_LENGTH 0x1000 int dev_sgi_de_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_sgi_de_status_init(struct memory *mem, uint64_t baseaddr, struct sgi_re_data *); /* dev_sgi_ip20.c: */ #define DEV_SGI_IP20_LENGTH 0x40 #define DEV_SGI_IP20_BASE 0x1fb801c0 struct sgi_ip20_data { int dummy; }; int dev_sgi_ip20_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); struct sgi_ip20_data *dev_sgi_ip20_init(struct cpu *cpu, struct memory *mem, uint64_t baseaddr); /* dev_sgi_ip22.c: */ #define DEV_SGI_IP22_LENGTH 0x100 #define DEV_SGI_IP22_IMC_LENGTH 0x100 #define DEV_SGI_IP22_UNKNOWN2_LENGTH 0x100 #define IP22_IMC_BASE 0x1fa00000 #define IP22_UNKNOWN2_BASE 0x1fb94000 struct sgi_ip22_data { int guiness_flag; uint32_t reg[DEV_SGI_IP22_LENGTH / 4]; uint32_t imc_reg[DEV_SGI_IP22_IMC_LENGTH / 4]; uint32_t unknown2_reg[DEV_SGI_IP22_UNKNOWN2_LENGTH / 4]; uint32_t unknown_timer; }; int dev_sgi_ip22_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); struct sgi_ip22_data *dev_sgi_ip22_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, int guiness_flag); /* dev_sgi_ip32.c: */ void dev_crime_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, char *irq_path, int use_fb); #define DEV_MACEPCI_LENGTH 0x1000 int dev_macepci_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); struct pci_data *dev_macepci_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, char *irq_path); #define DEV_SGI_MEC_LENGTH 0x1000 int dev_sgi_mec_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_sgi_mec_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, char *irq_path, unsigned char *macaddr); #define DEV_SGI_UST_LENGTH 0x10000 int dev_sgi_ust_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_sgi_ust_init(struct memory *mem, uint64_t baseaddr); /* dev_sii.c: */ #define DEV_SII_LENGTH 0x100 void dev_sii_tick(struct cpu *cpu, void *); int dev_sii_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_sii_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, uint64_t buf_start, uint64_t buf_end, char *irq_path); /* dev_ssc.c: */ #define DEV_SSC_LENGTH 0x1000 int dev_ssc_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_ssc_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, const char *irq_path, int use_fb); /* dev_turbochannel.c: */ #define DEV_TURBOCHANNEL_LEN 0x0470 int dev_turbochannel_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_turbochannel_init(struct machine *machine, struct memory *mem, int slot_nr, uint64_t baseaddr, uint64_t endaddr, const char *device_name, const char *irq_path); /* dev_uninorth.c: */ struct pci_data *dev_uninorth_init(struct machine *machine, struct memory *mem, uint64_t addr, int irqbase, int pciirq); /* dev_vga.c: */ int dev_vga_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *); void dev_vga_init(struct machine *machine, struct memory *mem, uint64_t videomem_base, uint64_t control_base, const char *name); /* dev_vr41xx.c: */ struct vr41xx_data *dev_vr41xx_init(struct machine *machine, struct memory *mem, int cpumodel); /* lk201.c: */ struct lk201_data { int use_fb; int console_handle; void (*add_to_rx_queue)(void *,int,int); void *add_data; unsigned char keyb_buf[8]; int keyb_buf_pos; int mouse_mode; int mouse_revision; /* 0..15 */ int mouse_x, mouse_y, mouse_buttons; }; void lk201_tick(struct machine *, struct lk201_data *); void lk201_tx_data(struct lk201_data *, int port, int idata); void lk201_init(struct lk201_data *d, int use_fb, void (*add_to_rx_queue)(void *,int,int), int console_handle, void *); #endif /* DEVICES_H */ gxemul-0.6.1/src/include/machine.h000644 001750 001750 00000025451 13402411502 017223 0ustar00debugdebug000000 000000 #ifndef MACHINE_H #define MACHINE_H /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include "symbol.h" struct cpu_family; struct diskimage; struct emul; struct fb_window; struct machine_arcbios; struct machine_pmax; struct memory; struct of_data; struct settings; /* TODO: This should probably go away... */ struct isa_pic_data { struct pic8259_data *pic1; struct pic8259_data *pic2; int *pending_timer_interrupts; int last_int; }; struct breakpoints { int n; /* Arrays, with one element for each entry: */ char **string; uint64_t *addr; }; struct statistics { char *filename; FILE *file; int enabled; char *fields; /* "vpi" etc. */ }; struct tick_functions { int n_entries; /* Arrays, with one element for each entry: */ int *ticks_till_next; int *ticks_reset_value; void (**f)(struct cpu *, void *); void **extra; }; struct x11_md { /* X11/framebuffer stuff: */ int in_use; int scaledown; int scaleup; int n_display_names; char **display_names; int current_display_name_nr; /* updated by x11.c */ int n_fb_windows; struct fb_window **fb_windows; }; /* * The machine struct: */ struct machine { /* Pointer back to the emul struct we are in: */ struct emul *emul; /* Settings: */ struct settings *settings; /* Name as choosen by the user: */ const char *name; /* Full "path" to the machine, e.g. "machine[0]": */ char *path; int arch; /* ARCH_MIPS, ARCH_PPC, .. */ int machine_type; /* MACHINE_PMAX, .. */ int machine_subtype; /* MACHINE_DEC_3MAX_5000, .. */ /* Name set by code in src/machines/machine_*.c: */ const char *machine_name; /* The serial number is mostly used when emulating multiple machines in a network. nr_of_nics is the current nr of network cards, which is useful when emulating multiple cards in one machine: */ int serial_nr; int nr_of_nics; /* TODO: How about multiple cpu familys in one machine? */ struct cpu_family *cpu_family; struct memory *memory; int main_console_handle; /* Tick functions (e.g. hardware devices): */ struct tick_functions tick_functions; char *cpu_name; /* TODO: remove this, there could be several cpus with different names in a machine */ int byte_order_override; int bootstrap_cpu; int use_random_bootstrap_cpu; int start_paused; int ncpus; struct cpu **cpus; struct diskimage *first_diskimage; struct symbol_context symbol_context; int random_mem_contents; int physical_ram_in_mb; int memory_offset_in_mb; int prom_emulation; int register_dump; int arch_pagesize; int bootdev_type; int bootdev_id; char *bootstr; char *bootarg; /* Breakpoints: */ struct breakpoints breakpoints; int halt_on_nonexistant_memaccess; int instruction_trace; int show_nr_of_instructions; int show_trace_tree; int emulated_hz; int allow_instruction_combinations; int force_netboot; int slow_serial_interrupts_hack_for_linux; uint64_t file_loaded_end_addr; char *boot_kernel_filename; char *boot_string_argument; int exit_without_entering_debugger; int n_gfx_cards; /* Instruction statistics: */ struct statistics statistics; /* X11/framebuffer stuff (per machine): */ struct x11_md x11_md; /* Machine-dependent: (PROM stuff, etc.) */ union { struct machine_arcbios *arc; struct machine_pmax *pmax; struct of_data *of_data; } md; /* Bus-specific interrupt data: */ /* TODO: Remove! */ struct isa_pic_data isa_pic_data; }; /* Tick function "prototype": */ #define DEVICE_TICK(x) void dev_ ## x ## _tick(struct cpu *cpu, void *extra) /* * Machine emulation types: */ #define ARCH_NOARCH 0 #define ARCH_MIPS 1 #define ARCH_PPC 2 #define ARCH_ALPHA 4 #define ARCH_ARM 5 #define ARCH_SH 6 #define ARCH_M88K 7 /* MIPS: */ #define MACHINE_BAREMIPS 1000 #define MACHINE_TESTMIPS 1001 #define MACHINE_PMAX 1002 #define MACHINE_COBALT 1003 #define MACHINE_HPCMIPS 1004 #define MACHINE_PS2 1005 #define MACHINE_SGI 1006 #define MACHINE_ARC 1007 #define MACHINE_EVBMIPS 1008 #define MACHINE_ALGOR 1009 #define MACHINE_QEMU_MIPS 1010 #define MACHINE_VOCORE 1011 /* PPC: */ #define MACHINE_BAREPPC 2000 #define MACHINE_TESTPPC 2001 #define MACHINE_PMPPC 2002 #define MACHINE_PREP 2003 #define MACHINE_MACPPC 2004 #define MACHINE_MVMEPPC 2005 /* Alpha: */ #define MACHINE_BAREALPHA 4000 #define MACHINE_TESTALPHA 4001 #define MACHINE_ALPHA 4002 /* ARM: */ #define MACHINE_BAREARM 5000 #define MACHINE_TESTARM 5001 #define MACHINE_CATS 5002 #define MACHINE_HPCARM 5003 #define MACHINE_NETWINDER 5004 #define MACHINE_IQ80321 5005 #define MACHINE_IYONIX 5006 #define MACHINE_QEMU_ARM 5007 #define MACHINE_RPI 5008 /* SH: */ #define MACHINE_BARESH 6000 #define MACHINE_TESTSH 6001 #define MACHINE_HPCSH 6002 #define MACHINE_DREAMCAST 6003 #define MACHINE_LANDISK 6004 /* M88K: */ #define MACHINE_BAREM88K 7000 #define MACHINE_TESTM88K 7001 #define MACHINE_MVME88K 7002 #define MACHINE_LUNA88K 7003 /* Other "pseudo"-machines: */ #define MACHINE_NONE 0 /* DEC: */ #define MACHINE_DEC_PMAX_3100 1 #define MACHINE_DEC_3MAX_5000 2 #define MACHINE_DEC_3MIN_5000 3 #define MACHINE_DEC_3MAXPLUS_5000 4 #define MACHINE_DEC_5800 5 #define MACHINE_DEC_5400 6 #define MACHINE_DEC_MAXINE_5000 7 #define MACHINE_DEC_5500 11 #define MACHINE_DEC_MIPSMATE_5100 12 #define DEC_PROM_CALLBACK_STRUCT 0xffffffffbfc04000ULL #define DEC_PROM_EMULATION 0xffffffffbfc08000ULL #define DEC_PROM_INITIAL_ARGV (INITIAL_STACK_POINTER + 0x80) #define DEC_PROM_STRINGS 0xffffffffbfc20000ULL #define DEC_PROM_TCINFO 0xffffffffbfc2c000ULL #define DEC_MEMMAP_ADDR 0xffffffffbfc30000ULL /* HPCmips: */ #define MACHINE_HPCMIPS_CASIO_BE300 1 #define MACHINE_HPCMIPS_CASIO_E105 2 #define MACHINE_HPCMIPS_NEC_MOBILEPRO_770 3 #define MACHINE_HPCMIPS_NEC_MOBILEPRO_780 4 #define MACHINE_HPCMIPS_NEC_MOBILEPRO_800 5 #define MACHINE_HPCMIPS_NEC_MOBILEPRO_880 6 #define MACHINE_HPCMIPS_AGENDA_VR3 7 #define MACHINE_HPCMIPS_IBM_WORKPAD_Z50 8 /* HPCarm: */ #define MACHINE_HPCARM_IPAQ 1 #define MACHINE_HPCARM_JORNADA720 2 #define MACHINE_HPCARM_JORNADA728 3 /* HPCsh: */ #define MACHINE_HPCSH_JORNADA680 1 #define MACHINE_HPCSH_JORNADA690 2 /* SGI and ARC: */ #define MACHINE_ARC_JAZZ_PICA 1 #define MACHINE_ARC_JAZZ_MAGNUM 2 /* Algor: */ #define MACHINE_ALGOR_P4032 1 #define MACHINE_ALGOR_P5064 2 /* EVBMIPS: */ #define MACHINE_EVBMIPS_MALTA 1 #define MACHINE_EVBMIPS_MALTA_BE 2 /* PReP: */ #define MACHINE_PREP_IBM6050 1 #define MACHINE_PREP_MVME2400 2 /* MacPPC: TODO: Real model names */ #define MACHINE_MACPPC_G3 1 #define MACHINE_MACPPC_G4 2 #define MACHINE_MACPPC_G5 3 /* MVMEPPC */ #define MACHINE_MVMEPPC_1600 1 #define MACHINE_MVMEPPC_2100 2 #define MACHINE_MVMEPPC_5500 3 /* MVME88K */ #define MACHINE_MVME88K_187 1 #define MACHINE_MVME88K_188 2 #define MACHINE_MVME88K_197 3 /* LUNA88K */ #define MACHINE_LUNA_88K 1 #define MACHINE_LUNA_88K2 2 /* For the automachine system: */ struct machine_entry_subtype { int machine_subtype;/* Old-style subtype */ const char *name; /* Official name */ int n_aliases; char **aliases; /* Aliases */ }; struct machine_entry { struct machine_entry *next; /* Machine type: */ int arch; int machine_type; /* Old-style type */ const char *name; /* Official name */ int n_aliases; char **aliases; /* Aliases */ void (*setup)(struct machine *, struct cpu *); void (*set_default_cpu)(struct machine *); void (*set_default_ram)(struct machine *); /* Machine subtypes: */ int n_subtypes; struct machine_entry_subtype **subtype; }; #define MACHINE_SETUP_TYPE(n) void (*n)(struct machine *, struct cpu *) #define MACHINE_SETUP(x) void machine_setup_ ## x(struct machine *machine, \ struct cpu *cpu) #define MACHINE_DEFAULT_CPU(x) void machine_default_cpu_ ## x(struct machine *machine) #define MACHINE_DEFAULT_RAM(x) void machine_default_ram_ ## x(struct machine *machine) #define MACHINE_REGISTER(x) void machine_register_ ## x(void) #define MR_DEFAULT(x,name,arch,type) struct machine_entry \ *me = machine_entry_new(name,arch,type); \ me->setup = machine_setup_ ## x; \ me->set_default_cpu = machine_default_cpu_ ## x; \ machine_entry_register(me, arch); void automachine_init(void); /* machine.c: */ struct machine *machine_new(char *name, struct emul *emul, int id); void machine_destroy(struct machine *machine); int machine_name_to_type(char *stype, char *ssubtype, int *type, int *subtype, int *arch); void machine_add_breakpoint_string(struct machine *machine, char *str); void machine_add_tickfunction(struct machine *machine, void (*func)(struct cpu *, void *), void *extra, int clockshift); void machine_statistics_init(struct machine *, char *fname); void machine_register(char *name, MACHINE_SETUP_TYPE(setup)); void machine_setup(struct machine *); void machine_memsize_fix(struct machine *); void machine_default_cputype(struct machine *); void machine_dumpinfo(struct machine *); int machine_run(struct machine *machine); void machine_list_available_types_and_cpus(void); struct machine_entry *machine_entry_new(const char *name, int arch, int oldstyle_type); void machine_entry_add_alias(struct machine_entry *me, const char *name); void machine_entry_add_subtype(struct machine_entry *me, const char *name, int oldstyle_subtype, ...); void machine_entry_register(struct machine_entry *me, int arch); void machine_init(void); #endif /* MACHINE_H */ gxemul-0.6.1/src/include/EscapedString.h000644 001750 001750 00000005314 13402411502 020346 0ustar00debugdebug000000 000000 #ifndef ESCAPEDSTRING_H #define ESCAPEDSTRING_H /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "UnitTest.h" /** * \brief A helper class for escaping strings using C-style escapes. * * TODO: It is ugly to use this for conversions in both directions! Should * be fixed some day. */ class EscapedString : public UnitTestable { public: /** * \brief Constructs an EscapedString helper. * * @param str A string, either escaped or not escaped. */ EscapedString(const string& str); /** * \brief Generates an escaped string, from the original string. * * @return an escaped string */ string Generate() const; /** * \brief Decodes an escaped string, from the original string. * * The original string should be a C-style escaped string, with * or without surrounding quote (") characters. * * @param success Set to true if decoding was successful, false * if there was an error. * @return A decoded (unescaped) string. (Only valid if * success was set to true.) */ string Decode(bool& success) const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); private: string m_str; }; #endif // ESCAPEDSTRING_H gxemul-0.6.1/src/include/FileLoaderImpl.h000644 001750 001750 00000005542 13402411502 020446 0ustar00debugdebug000000 000000 #ifndef FILELOADERIMPL_H #define FILELOADERIMPL_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Component.h" #include "UnitTest.h" /** * \brief A file loader. */ class FileLoaderImpl : public ReferenceCountable { public: /** * \brief Constructs a file loader. * * @param filename The filename to load. */ FileLoaderImpl(const string& filename) : m_filename(filename) { } virtual ~FileLoaderImpl() { } /** * \brief Attempt to detect file type. * * @param buf A buffer containing the header of the file. * @param buflen The length of the buffer. * @param matchness Set to a value between 0.0 and 1.0, indicating the * match certainty. * @return A file type description, if there was a match; otherwise * an empty string. */ virtual string DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const = 0; /** * \brief Loads the file into a Component. * * @param component The AddressDataBus component to load the file * into. (This is usually a CPUComponent.) * @param messages An output stream where debug messages can be put. * @return True if loading succeeded, false otherwise. */ virtual bool LoadIntoComponent(refcount_ptr component, ostream& messages) const = 0; protected: const string& Filename() const { return m_filename; } private: const string m_filename; }; #endif // FILELOADERIMPL_H gxemul-0.6.1/src/include/make_ppc_spr_strings.c000644 001750 001750 00000004660 13402411502 022025 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include int main(int argc, char *argv[]) { char *names[1024]; unsigned int i; memset(names, 0, sizeof(names)); while (!feof(stdin)) { char tmps[100]; tmps[0] = '\0'; fgets(tmps, sizeof(tmps), stdin); if (tmps[0] < ' ') break; for (i=0; i= 'A' && tmps[i] <= 'Z') tmps[i] += 32; if (tmps[i] == ' ' || tmps[i] == '\t') { int j = i, n; while (tmps[i]==' ' || tmps[i]=='\t') i++; n = strtol(tmps + i, NULL, 0); tmps[j] = '\0'; names[n] = strdup(tmps); break; } } } printf("/*\n * AUTOMATICALLY GENERATED from ppc_spr.h! Do " "not edit.\n */\n\nstatic const char *ppc_spr_names[1024] = {\n"); for (i=0; i<1024; i++) printf(" \"%s\"%s%s", names[i]? names[i] : "(unknown)", i<1023? "," : "", (i & 3) == 3? "\n" : ""); printf("};\n\n"); return 0; } gxemul-0.6.1/src/include/opcodes_ppc.h000644 001750 001750 00000017053 13402411502 020114 0ustar00debugdebug000000 000000 #ifndef OPCODES_PPC_H #define OPCODES_PPC_H /* * Copyright (C) 2005-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * POWER and PowerPC opcodes. These are gathered from various sources. * * Note: The define uses the PowerPC name, not the POWER name, when they * differ. */ #define PPC_HI6_MULLI 0x07 #define PPC_HI6_SUBFIC 0x08 #define PPC_HI6_CMPLI 0x0a #define PPC_HI6_CMPI 0x0b #define PPC_HI6_ADDIC 0x0c #define PPC_HI6_ADDIC_DOT 0x0d #define PPC_HI6_ADDI 0x0e #define PPC_HI6_ADDIS 0x0f #define PPC_HI6_BC 0x10 #define PPC_HI6_SC 0x11 #define PPC_HI6_B 0x12 #define PPC_HI6_19 0x13 #define PPC_19_MCRF 0 #define PPC_19_BCLR 16 #define PPC_19_RFID 18 #define PPC_19_CRNOR 33 #define PPC_19_RFI 50 #define PPC_19_RFSVC 82 #define PPC_19_CRANDC 129 #define PPC_19_ISYNC 150 #define PPC_19_CRXOR 193 #define PPC_19_CRNAND 225 #define PPC_19_CRAND 257 #define PPC_19_CREQV 289 #define PPC_19_CRORC 417 #define PPC_19_CROR 449 #define PPC_19_BCCTR 528 #define PPC_HI6_RLWIMI 0x14 #define PPC_HI6_RLWINM 0x15 #define PPC_HI6_RLWNM 0x17 #define PPC_HI6_ORI 0x18 #define PPC_HI6_ORIS 0x19 #define PPC_HI6_XORI 0x1a #define PPC_HI6_XORIS 0x1b #define PPC_HI6_ANDI_DOT 0x1c #define PPC_HI6_ANDIS_DOT 0x1d #define PPC_HI6_30 0x1e #define PPC_30_RLDICL 0x0 #define PPC_30_RLDICR 0x1 #define PPC_30_RLDIMI 0x3 #define PPC_HI6_31 0x1f #define PPC_31_CMP 0 #define PPC_31_TW 4 #define PPC_31_SUBFC 8 #define PPC_31_ADDC 10 #define PPC_31_MULHWU 11 #define PPC_31_MFCR 19 #define PPC_31_LWARX 20 #define PPC_31_LWZX 23 #define PPC_31_SLW 24 #define PPC_31_CNTLZW 26 #define PPC_31_SLD 27 #define PPC_31_AND 28 #define PPC_31_CMPL 32 #define PPC_31_SUBF 40 #define PPC_31_DCBST 54 #define PPC_31_LWZUX 55 #define PPC_31_ANDC 60 #define PPC_31_TD 68 #define PPC_31_MULHW 75 #define PPC_31_MFMSR 83 #define PPC_31_LDARX 84 #define PPC_31_DCBF 86 #define PPC_31_LBZX 87 #define PPC_31_LVX 103 #define PPC_31_NEG 104 #define PPC_31_CLF 118 #define PPC_31_LBZUX 119 #define PPC_31_NOR 124 #define PPC_31_SUBFE 136 #define PPC_31_ADDE 138 #define PPC_31_MTCRF 144 #define PPC_31_MTMSR 146 #define PPC_31_STDX 149 #define PPC_31_STWCX_DOT 150 #define PPC_31_STWX 151 #define PPC_31_WRTEEI 163 #define PPC_31_MTMSRD 178 #define PPC_31_STDUX 181 #define PPC_31_STWUX 183 #define PPC_31_SUBFZE 200 #define PPC_31_ADDZE 202 #define PPC_31_MTSR 210 #define PPC_31_STDCX_DOT 214 #define PPC_31_STBX 215 #define PPC_31_STVX 231 #define PPC_31_SUBFME 232 #define PPC_31_ADDME 234 #define PPC_31_MULLW 235 #define PPC_31_MTSRIN 242 #define PPC_31_DCBTST 246 #define PPC_31_STBUX 247 #define PPC_31_ADD 266 #define PPC_31_DCBT 278 #define PPC_31_LHZX 279 #define PPC_31_EQV 284 #define PPC_31_TLBIE 306 #define PPC_31_LHZUX 311 #define PPC_31_XOR 316 #define PPC_31_MFSPR 339 #define PPC_31_LHAX 343 #define PPC_31_LVXL 359 #define PPC_31_TLBIA 370 #define PPC_31_MFTB 371 #define PPC_31_LHAUX 375 #define PPC_31_STHX 407 #define PPC_31_ORC 412 #define PPC_31_SLBIE 434 #define PPC_31_STHUX 439 #define PPC_31_OR 444 #define PPC_31_DCCCI 454 #define PPC_31_DIVWU 459 #define PPC_31_MTSPR 467 #define PPC_31_DCBI 470 #define PPC_31_NAND 476 #define PPC_31_STVXL 487 #define PPC_31_DIVW 491 #define PPC_31_SLBIA 498 #define PPC_31_CLI 502 #define PPC_31_SUBFCO 520 #define PPC_31_ADDCO 522 #define PPC_31_LWBRX 534 #define PPC_31_LFSX 535 #define PPC_31_SRW 536 #define PPC_31_SUBFO 552 #define PPC_31_TLBSYNC 566 #define PPC_31_MFSR 595 #define PPC_31_LSWI 597 #define PPC_31_SYNC 598 #define PPC_31_LFDX 599 #define PPC_31_NEGO 616 #define PPC_31_DCLST 630 #define PPC_31_SUBFEO 648 #define PPC_31_ADDEO 650 #define PPC_31_MFSRIN 659 #define PPC_31_STWBRX 662 #define PPC_31_STFSX 663 #define PPC_31_SUBFZEO 712 #define PPC_31_ADDZEO 714 #define PPC_31_STSWI 725 #define PPC_31_STFDX 727 #define PPC_31_SUBFMEO 744 #define PPC_31_ADDMEO 746 #define PPC_31_MULLWO 747 #define PPC_31_ADDO 778 #define PPC_31_LHBRX 790 #define PPC_31_SRAW 792 #define PPC_31_DSSALL 822 #define PPC_31_SRAWI 824 #define PPC_31_EIEIO 854 #define PPC_31_TLBSX_DOT 914 #define PPC_31_STHBRX 918 #define PPC_31_EXTSH 922 #define PPC_31_EXTSB 954 #define PPC_31_ICCCI 966 #define PPC_31_DIVWUO 971 #define PPC_31_TLBLD 978 #define PPC_31_ICBI 982 #define PPC_31_EXTSW 986 #define PPC_31_DIVWO 1003 #define PPC_31_TLBLI 1010 #define PPC_31_DCBZ 1014 #define PPC_HI6_LWZ 0x20 #define PPC_HI6_LWZU 0x21 #define PPC_HI6_LBZ 0x22 #define PPC_HI6_LBZU 0x23 #define PPC_HI6_STW 0x24 #define PPC_HI6_STWU 0x25 #define PPC_HI6_STB 0x26 #define PPC_HI6_STBU 0x27 #define PPC_HI6_LHZ 0x28 #define PPC_HI6_LHZU 0x29 #define PPC_HI6_LHA 0x2a #define PPC_HI6_LHAU 0x2b #define PPC_HI6_STH 0x2c #define PPC_HI6_STHU 0x2d #define PPC_HI6_LMW 0x2e #define PPC_HI6_STMW 0x2f #define PPC_HI6_LFS 0x30 #define PPC_HI6_LFD 0x32 #define PPC_HI6_STFS 0x34 #define PPC_HI6_STFD 0x36 #define PPC_HI6_LD 0x3a #define PPC_HI6_59 0x3b #define PPC_59_FDIVS 18 #define PPC_59_FSUBS 20 #define PPC_59_FADDS 21 #define PPC_59_FMULS 25 #define PPC_59_FMADDS 29 #define PPC_HI6_STD 0x3e #define PPC_HI6_63 0x3f #define PPC_63_FCMPU 0 #define PPC_63_FRSP 12 #define PPC_63_FCTIWZ 15 #define PPC_63_FDIV 18 #define PPC_63_FSUB 20 #define PPC_63_FADD 21 #define PPC_63_FMUL 25 #define PPC_63_FMSUB 28 #define PPC_63_FMADD 29 #define PPC_63_FNEG 40 #define PPC_63_FMR 72 #define PPC_63_FNABS 136 #define PPC_63_FABS 264 #define PPC_63_MFFS 583 #define PPC_63_MTFSF 711 #endif /* OPCODES_PPC_H */ gxemul-0.6.1/src/include/commands/000755 001750 001750 00000000000 13402411502 017240 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/include/misc.h000644 001750 001750 00000017713 13402411502 016554 0ustar00debugdebug000000 000000 #ifndef MISC_H #define MISC_H /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Misc. definitions for GXemul. */ #include #include /* * ../../config.h contains #defines set by the configure script. Some of these * might reduce speed of the emulator, so don't enable them unless you * need them. */ #include "../../config.h" #define COPYRIGHT_MSG "Copyright (C) 2003-2018 Anders Gavare" // The recommended way to add a specific message to the startup banner or // about box is to use the SECONDARY_MSG. This should end with a newline // character, unless it is completely empty. // // Example: "Modified by XYZ to include support for machine type UVW.\n" // #define SECONDARY_MSG "" #include using std::string; typedef char stringchar; #include using std::map; using std::pair; #include using std::list; #include using std::vector; #include using std::stringstream; #include using std::ostream; #include using std::cout; using std::cerr; #ifndef NDEBUG #include "thirdparty/debug_new.h" #endif #include "refcount_ptr.h" #ifdef NO_C99_PRINTF_DEFINES /* * This is a SUPER-UGLY HACK which happens to work on some machines. * The correct solution is to upgrade your compiler to C99. */ #ifdef NO_C99_64BIT_LONGLONG #define PRIi8 "i" #define PRIi16 "i" #define PRIi32 "i" #define PRIi64 "lli" #define PRIx8 "x" #define PRIx16 "x" #define PRIx32 "x" #define PRIx64 "llx" #else #define PRIi8 "i" #define PRIi16 "i" #define PRIi32 "i" #define PRIi64 "li" #define PRIx8 "x" #define PRIx16 "x" #define PRIx32 "x" #define PRIx64 "lx" #endif #endif #ifdef NO_MAP_ANON #ifdef mmap #undef mmap #endif #include #include #include static void *no_map_anon_mmap(void *addr, size_t len, int prot, int flags, int nonsense_fd, off_t offset) { void *p; int fd = open("/dev/zero", O_RDWR); if (fd < 0) { fprintf(stderr, "Could not open /dev/zero\n"); exit(1); } printf("addr=%p len=%lli prot=0x%x flags=0x%x nonsense_fd=%i " "offset=%16lli\n", addr, (long long) len, prot, flags, nonsense_fd, (long long) offset); p = mmap(addr, len, prot, flags, fd, offset); printf("p = %p\n", p); /* TODO: Close the descriptor? */ return p; } #define mmap no_map_anon_mmap #endif /* tmp dir to use if the TMPDIR environment variable isn't set: */ #define DEFAULT_TMP_DIR "/tmp" struct cpu; struct emul; struct machine; struct memory; enum Endianness { BigEndian = 0, LittleEndian }; #define NO_BYTE_ORDER_OVERRIDE -1 #define EMUL_UNDEFINED_ENDIAN 0 #define EMUL_LITTLE_ENDIAN 1 #define EMUL_BIG_ENDIAN 2 #define SWAP32(x) ((((x) & 0xff000000) >> 24) | (((x)&0xff) << 24) | \ (((x) & 0xff0000) >> 8) | (((x) & 0xff00) << 8)) #define SWAP16(x) ((((x) & 0xff00) >> 8) | (((x)&0xff) << 8)) #ifdef HOST_LITTLE_ENDIAN #define LE16_TO_HOST(x) (x) #define BE16_TO_HOST(x) (SWAP16(x)) #else #define LE16_TO_HOST(x) (SWAP16(x)) #define BE16_TO_HOST(x) (x) #endif #ifdef HOST_LITTLE_ENDIAN #define LE32_TO_HOST(x) (x) #define BE32_TO_HOST(x) (SWAP32(x)) #else #define LE32_TO_HOST(x) (SWAP32(x)) #define BE32_TO_HOST(x) (x) #endif #ifdef HOST_LITTLE_ENDIAN #define LE64_TO_HOST(x) (x) #define BE64_TO_HOST(x) ( (((x) >> 56) & 0xff) + \ ((((x) >> 48) & 0xff) << 8) + \ ((((x) >> 40) & 0xff) << 16) + \ ((((x) >> 32) & 0xff) << 24) + \ ((((x) >> 24) & 0xff) << 32) + \ ((((x) >> 16) & 0xff) << 40) + \ ((((x) >> 8) & 0xff) << 48) + \ (((x) & 0xff) << 56) ) #else #define BE64_TO_HOST(x) (x) #define LE64_TO_HOST(x) ( (((x) >> 56) & 0xff) + \ ((((x) >> 48) & 0xff) << 8) + \ ((((x) >> 40) & 0xff) << 16) + \ ((((x) >> 32) & 0xff) << 24) + \ ((((x) >> 24) & 0xff) << 32) + \ ((((x) >> 16) & 0xff) << 40) + \ ((((x) >> 8) & 0xff) << 48) + \ (((x) & 0xff) << 56) ) #endif /* Debug stuff: */ #define DEBUG_BUFSIZE 1024 #define DEBUG_INDENTATION 4 #ifdef HAVE___FUNCTION__ #define FAILURE(error_msg) { \ char where_msg[400]; \ snprintf(where_msg, sizeof(where_msg), \ "%s, line %i, function %s().\n", \ __FILE__, __LINE__, __FUNCTION__); \ fprintf(stderr, "\n%s, in %s\n", error_msg, where_msg); \ exit(1); \ } #else #define FAILURE(error_msg) { \ char where_msg[400]; \ snprintf(where_msg, sizeof(where_msg), \ "%s, line %i\n", __FILE__, __LINE__); \ fprintf(stderr, "\n%s, in %s.\n", error_msg, where_msg);\ exit(1); \ } #endif /* !HAVE___FUNCTION__ */ #define CHECK_ALLOCATION(ptr) { \ if ((ptr) == NULL) \ FAILURE("Out of memory"); \ } /* bootblock.c: */ int load_bootblock(struct machine *m, struct cpu *cpu, int *n_loadp, char ***load_namesp); /* bootblock_apple.c: */ int apple_load_bootblock(struct machine *m, struct cpu *cpu, int disk_id, int disk_type, int *n_loadp, char ***load_namesp); /* bootblock_iso9660.c: */ int iso_load_bootblock(struct machine *m, struct cpu *cpu, int disk_id, int disk_type, int iso_type, unsigned char *buf, int *n_loadp, char ***load_namesp); /* dec_prom.c: */ int decstation_prom_emul(struct cpu *cpu); /* dreamcast.c: */ void dreamcast_machine_setup(struct machine *); void dreamcast_emul(struct cpu *cpu); /* dreamcast_scramble.c: */ void dreamcast_descramble(char *from, char *to); /* file.c: */ int file_n_executables_loaded(void); void file_load(struct machine *machine, struct memory *mem, char *filename, uint64_t *entrypointp, int arch, uint64_t *gpp, int *byte_order, uint64_t *tocp); /* luna88kprom.c: */ void luna88kprom_init(struct machine *machine); int luna88kprom_emul(struct cpu *cpu); /* main.c: */ void debug_indentation(int diff); void debug(const char *fmt, ...); void fatal(const char *fmt, ...); /* misc.c: */ unsigned long long mystrtoull(const char *s, char **endp, int base); int mymkstemp(char *templ); #ifdef USE_STRLCPY_REPLACEMENTS size_t mystrlcpy(char *dst, const char *src, size_t size); size_t mystrlcat(char *dst, const char *src, size_t size); #endif void print_separator_line(void); /* mvmeprom.c: */ void mvmeprom_init(struct machine *machine); int mvmeprom_emul(struct cpu *cpu); /* ps2_bios.c: */ int playstation2_sifbios_emul(struct cpu *cpu); /* sh_ipl_g.c: */ void sh_ipl_g_emul_init(struct machine *machine); int sh_ipl_g_emul(struct cpu *); /* yamon.c: */ void yamon_machine_setup(struct machine *machine, uint64_t env); int yamon_emul(struct cpu *); #endif /* MISC_H */ gxemul-0.6.1/src/include/thirdparty/000755 001750 001750 00000000000 13402411502 017631 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/include/refcount_ptr.h000644 001750 001750 00000015265 13402411502 020333 0ustar00debugdebug000000 000000 #ifndef REFCOUNT_PTR_H #define REFCOUNT_PTR_H /* * Copyright (C) 2007-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ template class refcount_ptr; /** * \brief Base class for reference countable objects. * * Usage:
 * refcount_ptr myPtr = new MyClass(...);
 * 
* where MyClass should have increase_refcount() and * decrease_refcount(), e.g.
 * class MyClass : public ReferenceCountable
 * {
 *	...
 * }
* * Note: Although MyClass objects can be created using the following * syntax:
 * MyClass myobject(...);
 * 
* this causes the object to have a reference count of 0. That is, the * address should not be taken of such an object and exposed to the * outside. * * Implementation note: The counter itself is mutable, and the * increase_refcount() and decrease_refcount() member functions are marked as * const. This is because const objects also need to be properly * reference counted. */ class ReferenceCountable { public: /** * \brief Default constructor, which initializes the reference * count to zero. */ ReferenceCountable() : m_refCount(0) { } ~ReferenceCountable() { if (m_refCount != 0) { std::cerr << "TODO: ~ReferenceCountable count != 0!\n"; std::terminate(); } } private: template friend class refcount_ptr; /** * \brief Increases the reference count of the object. * * @return The reference count after increasing it. */ int increase_refcount() const { return (++ m_refCount); } /** * \brief Decreases the reference count of the object. * * @return The reference count after decreasing it. If the * value is zero, the caller should delete the object. */ int decrease_refcount() const { return (-- m_refCount); } private: mutable int m_refCount; }; /** * \brief A template class representing a reference counted pointer. * * Basically, when a pointer assigned to the reference counted pointer, * it increases the reference count of the pointed-to object. * When the reference counted pointer is destroyed (or NULL is * assigned to it), it decreases the reference count of the pointed-to * object. If the reference count reaches zero, the object is deleted. */ template class refcount_ptr { public: /** * Constructor for a reference counted pointer. * * @param p Pointer to an object; default is NULL. */ refcount_ptr(T* p = NULL) : m_p(p) { if (m_p != NULL) m_p->increase_refcount(); } /** * The destructor causes the reference count to be decreased * by one. If the reference count of the object reaches zero, * it is deleted (freed). */ ~refcount_ptr() { release(); } /** * Copy constructor, which causes the reference count of the * pointed-to object to be increased. * * @param other The reference counted pointer to copy from. */ refcount_ptr(const refcount_ptr& other) : m_p(other.m_p) { if (m_p != NULL) m_p->increase_refcount(); } /** * Assignment operator. If an object is already referenced, * it is released (i.e. its reference is decreased, and if it * is zero, it is freed). The object referenced to by the * other reference counted pointer then gets its reference * count increased. * * @param other The reference counted pointer to assign from. */ refcount_ptr& operator = (const refcount_ptr& other) { if (this != &other) { release(); if ((m_p = other.m_p) != NULL) m_p->increase_refcount(); } return *this; } operator T* () { return m_p; } T& operator *() { return *m_p; } T* operator ->() { return m_p; } operator const T* () const { return m_p; } const T& operator *() const { return *m_p; } const T* operator ->() const { return m_p; } /** * \brief Checks whether or not an object is referenced * by the reference counted pointer. * * @return true if the reference counted pointer is not * referencing any object, false otherwise. */ bool IsNULL() const { return m_p == NULL; } /** * \brief Less-than operator, e.g. for sorting. * * @param other The reference counted pointer to * compare this object to. * @return true if the plain pointer of this object is * less than the plain pointer of the other object. */ bool operator < (const refcount_ptr& other) const { std::ptrdiff_t diff = m_p - other.m_p; return diff < 0; } /** * \brief Equals operator. * * @param other The reference counted pointer to * compare this object to. * @return true if the pointed to objects have the same * address, false otherwise. */ bool operator == (const refcount_ptr& other) const { return m_p == other.m_p; } /** * \brief Not-Equals operator. * * @param other The reference counted pointer to * compare this object to. * @return true if the pointed to objects have * different address, false otherwise. */ bool operator != (const refcount_ptr& other) const { return m_p != other.m_p; } private: /** * Releases the currently references object, if any, by * decreasing its reference count. If the count reaches zero, * that means that no others have pointers to the object, * and it is freed. */ void release() { if (m_p != NULL) { if (m_p->decrease_refcount() <= 0) delete m_p; m_p = NULL; } } private: T* m_p; }; #endif // REFCOUNT_PTR_H gxemul-0.6.1/src/include/debugger.h000644 001750 001750 00000004313 13402411502 017375 0ustar00debugdebug000000 000000 #ifndef DEBUGGER_H #define DEBUGGER_H /* * Copyright (C) 2004-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * See src/debugger/debugger.c. */ #include "misc.h" struct emul; struct machine; /* debugger.c: */ void debugger_activate(int x); void debugger_execute_cmd(char *cmd, int cmd_len); void debugger(void); void debugger_reset(void); void debugger_init(struct emul *emul); /* single_step values: */ #define NOT_SINGLE_STEPPING 0 #define ENTER_SINGLE_STEPPING 1 #define SINGLE_STEPPING 2 /* debugger_expr.c: */ #define PARSE_NOMATCH 0 #define PARSE_MULTIPLE 1 #define PARSE_SETTINGS 2 #define PARSE_NUMBER 3 #define PARSE_SYMBOL 4 int debugger_parse_expression(struct machine *m, char *expr, int writeflag, uint64_t *valuep); #endif /* DEBUGGER_H */ gxemul-0.6.1/src/include/testmachine/000755 001750 001750 00000000000 13402411502 017743 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/include/sh4_dmacreg.h000644 001750 001750 00000013561 13402411502 017776 0ustar00debugdebug000000 000000 #ifndef SH4_DMACREG_H #define SH4_DMACREG_H /* * Copyright (C) 2006-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * SH4 DMAC (DMA Controller) registers, as listed in the SH-7750 and * SH-7760 manuals. */ #define N_SH4_DMA_CHANNELS 8 /* 4 on 7750, 8 on 7760 */ #define SH4_SAR0 0xffa00000 /* Source Address Register */ #define SH4_DAR0 0xffa00004 /* Destination Address Register */ #define SH4_DMATCR0 0xffa00008 /* Transfer Count Register */ #define SH4_CHCR0 0xffa0000c /* Channel Control Register */ #define SH4_SAR1 0xffa00010 #define SH4_DAR1 0xffa00014 #define SH4_DMATCR1 0xffa00018 #define SH4_CHCR1 0xffa0001c #define SH4_SAR2 0xffa00020 #define SH4_DAR2 0xffa00024 #define SH4_DMATCR2 0xffa00028 #define SH4_CHCR2 0xffa0002c #define SH4_SAR3 0xffa00030 #define SH4_DAR3 0xffa00034 #define SH4_DMATCR3 0xffa00038 #define SH4_CHCR3 0xffa0003c #define SH4_DMAOR 0xffa00040 /* DMA operation register */ #define DMAOR_DDT 0x00008000 /* On-Demand Data Transfer */ #define DMAOR_PR1 0x00000200 /* Priority Mode 1 */ #define DMAOR_PR0 0x00000100 /* Priority Mode 0 */ #define DMAOR_AE 0x00000004 /* Address Error flag */ #define DMAOR_NMIF 0x00000002 /* NMI flag */ #define DMAOR_DME 0x00000001 /* DMAC master enable */ /* NOTE: Channel 4 doesn't start at 0xffa00040, but 0xffa00050! */ #define SH4_SAR4 0xffa00050 #define SH4_DAR4 0xffa00054 #define SH4_DMATCR4 0xffa00058 #define SH4_CHCR4 0xffa0005c #define SH4_SAR5 0xffa00060 #define SH4_DAR5 0xffa00064 #define SH4_DMATCR5 0xffa00068 #define SH4_CHCR5 0xffa0006c #define SH4_SAR6 0xffa00070 #define SH4_DAR6 0xffa00074 #define SH4_DMATCR6 0xffa00078 #define SH4_CHCR6 0xffa0007c #define SH4_SAR7 0xffa00080 #define SH4_DAR7 0xffa00084 #define SH4_DMATCR7 0xffa00088 #define SH4_CHCR7 0xffa0008c /* * CHCR (Channel Control Register) bit definitions: */ #define CHCR_SSA_MASK 0xe0000000 /* Source Address Space Attribute Specification */ /* (Only valid for PCMCIA access, in areas 5 and 6.) */ #define CHCR_SSA_RESERVED (0 << 29) #define CHCR_SSA_DYNAMIC_BUS_SIZING (1 << 29) #define CHCR_SSA_8BIT_IO_SPACE (2 << 29) #define CHCR_SSA_16BIT_IO_SPACE (3 << 29) #define CHCR_SSA_8BIT_COMMON_MEMORY_SPACE (4 << 29) #define CHCR_SSA_16BIT_COMMON_MEMORY_SPACE (5 << 29) #define CHCR_SSA_8BIT_ATTRIBUTE_MEMORY_SPACE (6 << 29) #define CHCR_SSA_16BIT_ATTRIBUTE_MEMORY_SPACE (7 << 29) #define CHCR_STC 0x10000000 /* Source Address Wait Control Select */ #define CHCR_DSA_MASK 0x0e000000 /* Destination Address Space Attribute Specification */ #define CHCR_DSA_RESERVED (0 << 25) #define CHCR_DSA_DYNAMIC_BUS_SIZING (1 << 25) #define CHCR_DSA_8BIT_IO_SPACE (2 << 25) #define CHCR_DSA_16BIT_IO_SPACE (3 << 25) #define CHCR_DSA_8BIT_COMMON_MEMORY_SPACE (4 << 25) #define CHCR_DSA_16BIT_COMMON_MEMORY_SPACE (5 << 25) #define CHCR_DSA_8BIT_ATTRIBUTE_MEMORY_SPACE (6 << 25) #define CHCR_DSA_16BIT_ATTRIBUTE_MEMORY_SPACE (7 << 25) #define CHCR_DTC 0x01000000 /* Destination Address Wait Control Select */ #define CHCR_DS 0x00080000 /* DREQ Select */ #define CHCR_RL 0x00040000 /* Request Check Level */ #define CHCR_AM 0x00020000 /* Acknowledge Mode */ #define CHCR_AL 0x00010000 /* Acknowledge Level */ #define CHCR_DM 0x0000c000 /* Destination Address Mode 1 and 0 */ #define CHCR_DM_FIXED (0 << 14) /* Destination Address Fixed */ #define CHCR_DM_INCREMENTED (1 << 14) /* Destination Address Incremented */ #define CHCR_DM_DECREMENTED (2 << 14) /* Destination Address Decremented */ #define CHCR_SM 0x00003000 /* Source Address Mode 1 and 0 */ #define CHCR_SM_FIXED (0 << 12) /* Source Address Fixed */ #define CHCR_SM_INCREMENTED (1 << 12) /* Source Address Incremented */ #define CHCR_SM_DECREMENTED (2 << 12) /* Source Address Decremented */ #define CHCR_RS 0x00000f00 /* Resource Select */ #define CHCR_TM 0x00000080 /* Transmit Mode (0=cycle steal, 1=burst) */ #define CHCR_TS 0x00000070 /* Transmit Size */ #define CHCR_TS_8BYTE (0 << 4) #define CHCR_TS_1BYTE (1 << 4) #define CHCR_TS_2BYTE (2 << 4) #define CHCR_TS_4BYTE (3 << 4) #define CHCR_TS_32BYTE (4 << 4) #define CHCR_CHSET 0x00000008 /* Channel Setting */ #define CHCR_IE 0x00000004 /* Interrupt Enable */ #define CHCR_TE 0x00000002 /* Transfer End */ #define CHCR_TD 0x00000001 /* DMAC Enable */ #endif /* SH4_DMACREG_H */ gxemul-0.6.1/src/include/arcbios.h000644 001750 001750 00000010263 13402411502 017234 0ustar00debugdebug000000 000000 #ifndef ARCBIOS_H #define ARCBIOS_H /* * Copyright (C) 2004-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Headerfile for src/arcbios.c. * * (Note: There are also files in the thirdparty directory called * arcbios_other.h and sgi_arcbios.h, which are from NetBSD.) */ #include "misc.h" #include "thirdparty/sgi_arcbios.h" struct cpu; /* arcbios.c: */ void arcbios_add_string_to_component(struct machine *machine, char *string, uint64_t component); void arcbios_register_scsicontroller(struct machine *machine, uint64_t scsicontroller_component); uint64_t arcbios_get_scsicontroller(struct machine *machine); void arcbios_add_memory_descriptor(struct cpu *cpu, uint64_t base, uint64_t len, int arctype); uint64_t arcbios_addchild_manual(struct cpu *cpu, uint64_t cclass, uint64_t type, uint64_t flags, uint64_t version, uint64_t revision, uint64_t key, uint64_t affinitymask, const char *identifier, uint64_t parent, void *config_data, size_t config_len); int arcbios_emul(struct cpu *cpu); void arcbios_set_default_exception_handler(struct cpu *cpu); void arcbios_console_init(struct machine *machine, uint64_t vram, uint64_t ctrlregs); void arcbios_init(struct machine *machine, int is64bit, uint64_t sgi_ram_offset, const char *primary_ether_string, uint8_t *primary_ether_macaddr); /* For internal use in arcbios.c: */ struct emul_arc_child { uint32_t ptr_peer; uint32_t ptr_child; uint32_t ptr_parent; struct arcbios_component component; }; struct emul_arc_child64 { uint64_t ptr_peer; uint64_t ptr_child; uint64_t ptr_parent; struct arcbios_component64 component; }; #define ARC_BOOTSTR_BUFLEN 1000 /* * Problem: kernels seem to be loaded at low addresses in RAM, so * storing environment strings and memory descriptors there is a bad * idea. They are stored at 0xbfc..... instead. The ARC SPB must * be at physical address 0x1000 though. */ #define SGI_SPB_ADDR 0xffffffff80001000ULL /* 0xbfc10000 is firmware callback vector stuff */ #define ARC_FIRMWARE_VECTORS 0xffffffffbfc80000ULL #define ARC_FIRMWARE_ENTRIES 0xffffffffbfc88000ULL #define ARC_ARGV_START 0xffffffffbfc90000ULL #define ARC_ENV_STRINGS 0xffffffffbfc98000ULL #define ARC_ENV_SGI 0xffffffffbfc04000ULL #define ARC_ENV_STRINGS_SGI 0xffffffffbfc04040ULL #define ARC_ENV_POINTERS 0xffffffffbfc9d000ULL #define SGI_SYSID_ADDR 0xffffffffbfca1800ULL #define ARC_DSPSTAT_ADDR 0xffffffffbfca1c00ULL #define ARC_MEMDESC_ADDR 0xffffffffbfca1c80ULL #define ARC_CONFIG_DATA_ADDR 0xffffffffbfca2000ULL #define FIRST_ARC_COMPONENT 0xffffffffbfca8000ULL #define ARC_PRIVATE_VECTORS 0xffffffffbfcb0000ULL #define ARC_PRIVATE_ENTRIES 0xffffffffbfcb8000ULL #endif /* ARCBIOS_H */ gxemul-0.6.1/src/include/Component.h000644 001750 001750 00000057670 13402411502 017571 0ustar00debugdebug000000 000000 #ifndef COMPONENT_H #define COMPONENT_H /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Checksum.h" #include "SerializationContext.h" #include "StateVariable.h" class AddressDataBus; class Component; class CPUComponent; class GXemul; class RootComponent; class UI; typedef vector< refcount_ptr > Components; typedef map< string,string > ComponentCreationSettings; struct ComponentCreateArgs { GXemul* gxemul; ComponentCreationSettings componentCreationSettings; }; /** * \brief A %Component is a node in the configuration tree that * makes up an emulation setup. * * The %Component is the core concept in %GXemul. All devices, * CPUs, networks, and so on are components. */ class Component : public ReferenceCountable { protected: /** * \brief Base constructor for a %Component. * * See also: the Create() function. * * @param className The name of the component class. * It should be a short, descriptive name. * For e.g. a PCI bus class, it can be "pcibus". * For a MIPS CPU, it can be "mips_cpu". * @param visibleClassName The visible name of the component class. * It should be a short, descriptive name. * For e.g. a PCI bus class, it can be "pcibus". * For a MIPS CPU, it can be "cpu". */ Component(const string& className, const string& visibleClassName); public: virtual ~Component() { } /** * \brief Gets the class name of the component. * * @return the class name of the component, e.g. "pcibus" for a PCI * bus component class, or "mips_cpu" for a MIPS CPU. */ string GetClassName() const; /** * \brief Gets the visible class name of the component. * * @return the class name of the component, e.g. "pcibus" for a PCI * bus component class, or "cpu" for a MIPS CPU. */ string GetVisibleClassName() const; /** * \brief Creates a Component. * * The reason for having this helper, instead of simply calling the * constructor of a specific %Component, is to make templates work * in a reasonable and straight-forward manner. (Note: This concept * of templates is unrelated to the C++ concept of templates. It just * happens to be the same word.) * * E.g. DummyComponent::Create() returns a new DummyComponent, but * TestMIPSMachine::Create() returns a new MachineComponent * (with some pre-defined child components), not a TestMIPS component. */ // static refcount_ptr Create(const ComponentCreateArgs& args); /** * \brief Get attribute information about a Component. * * @param attributeName The attribute name. * @return A string representing the attribute value. The base * implementation returns an empty string; it is up to individual * Components to return other values. */ static string GetAttribute(const string& attributeName); /** * \brief Clones the component and all its children. * * The new copy is a complete copy; modifying either the copy or the * original will not affect the other. * * @return A reference counted pointer to the clone. */ refcount_ptr Clone() const; /** * \brief Makes a light clone of the component and all its children. * * Modifying the original component will not affect the component * returned by this function. * * The new copy is not a complete copy. Expensive data * structures are not copied, only "light" data structures. For * example, RAM memory cell contents is not cloned. * * The main purpose of this function is to allow e.g. a single * stepper to take a light clone, run one step, and the compare * the current component tree with the light clone, to see what * was modified in the step. * * @return A const reference counted pointer to the light clone. */ const refcount_ptr LightClone() const; /** * \brief Compare an older clone to the current tree, to find changes. * * Any changes found are written as messages to changeMessages. * Typical use of this function is to input a "light clone" which * is taken before running a single execution step, to find out * any side effects of that execution step. * * @param oldClone The original component tree to compare to. * @param changeMessages An output stream where to send messages. */ void DetectChanges(const refcount_ptr& oldClone, ostream& changeMessages) const; /** * \brief Generates an ASCII tree dump of a component tree. * * @param branchTemplate Used for recursion. Start with an empty * string (""). * @param htmlLinksForClassNames Used to generate HTML links * by 'make documentation'. * @param prefixForComponentUrls Placed before * component/xyz.html in html links to components. * @return An ASCII string containing the tree. */ string GenerateTreeDump(const string& branchTemplate, bool htmlLinksForClassNames = false, string prefixForComponentUrls = "") const; /** * \brief Generate details about the component. * * @return A string containing details about the component. */ virtual string GenerateDetails() const; /** * \brief Resets the state of this component and all its children. */ void Reset(); /** * \brief Checks the state of this component and all its children, * before starting execution. * * @return true if the component and all its children are ready to run, * false otherwise. */ bool PreRunCheck(GXemul* gxemul); /** * \brief Resets the cached state of this component and all its * children. * * For performance reasons, while an emulation is running, it is usually * a good idea to cache e.g. pointers to various things. However, * after pausing an emulation, and continuing again, these pointers * may not be valid. FlushCachedState() should be called before * Run() is called. */ void FlushCachedState(); /** * \brief Execute one or more cycles. * * Note 1: A component must attempt to execute exactly the number of * specified cycles. * * Note 2: If e.g. a breakpoint is reached, or some fatal error occurs * (such as an unimplemented feature in the emulation of the component * is triggered), then it is ok to return fewer than the requested * number of cycles. Execution will then stop (or the breakpoint will * be handled, etc). * * Note 3: The framework will only call this function if the component * has a StateVariable named "frequency". Components that do not have * any frequency do not execute anything periodically by themselves. * * @param gxemul A pointer to the GXemul instance. * @param nrOfCycles The requested number of cycles to run. * @return The number of cycles actually executed. */ virtual int Execute(GXemul* gxemul, int nrOfCycles); /** * \brief Returns the current frequency (in Hz) that the component * runs at. * * @return The component's frequency in Hz. */ virtual double GetCurrentFrequency() const; /** * \brief Returns the component's RootComponent interface. * * @return A pointer to the component as a %RootComponent, or * NULL if the component isn't a %RootComponent. */ virtual RootComponent* AsRootComponent(); /** * \brief Returns the component's CPUComponent interface. * * @return A pointer to the component as a %CPUComponent, or * NULL if the component isn't a CPU. */ virtual CPUComponent* AsCPUComponent(); /** * \brief Returns the component's AddressDataBus interface, if any. * * @return A pointer to an AddressDataBus, or NULL if the * component does not support that interface. */ virtual AddressDataBus* AsAddressDataBus(); /** * \brief Sets the parent component of this component. * * Note: Not reference counted. * * @param parentComponent a pointer to the parent component. */ void SetParent(Component* parentComponent); /** * \brief Gets this component's parent component, if any. * * Note: Not reference counted. * * Returns NULL if there is no parent component. * * @return the pointer to the parent component, or NULL */ Component* GetParent(); const Component* GetParent() const; /** * \brief Retrieves a component's implemented method names. * * Note that a component's implementation should call its * base class' GetMethodNames(vector&) too. However, when * methods are executed, the most specific implementation (i.e. * not the base class) will get a chance first to execute the method. * * @param names A vector of strings, where method names * should be added. */ virtual void GetMethodNames(vector& names) const; /** * \brief Returns whether a method name may be re-executed without args. * * Typical examples may be a RAMComponent which has a "dump" method, * or a CPUComponent which has "dump" and "unassemble" methods. * * Note that a component's implementation should call its * base class' MethodMayBeReexecutedWithoutArgs(cosnt string&) too. * * @param methodName The name of the method. * @return true if the method may be re-executed without arguments, * false otherwise. */ virtual bool MethodMayBeReexecutedWithoutArgs(const string& methodName) const; /** * \brief Executes a method on the component. * * Note 1: The method name must be one of those returned * by GetMethodNames(vector&), either in the class itself * or by one of the base implementations. * * Note 2: The base class' member function should only be called * if this class does not handle the method. * * @param gxemul A reference to the GXemul instance. * @param methodName The name of the method. * @param arguments A vector of arguments to the method. */ virtual void ExecuteMethod(GXemul* gxemul, const string& methodName, const vector& arguments); /** * \brief Generates a string representation of the path to the * %Component. * * The path consists of "name.name...name.name" where the last name * is the name of this component, and the preceding names are names * of parents. * * If a component does not have a "name" state variable, then the * class name in parentheses is used instead (which may make the path * non-unique). * * @return A path to the component, as a string. */ string GeneratePath() const; /** * \brief Generates a short string representation of the path to the * %Component. * * This function generates a string which is the shortest possible * sub-path required to uniqely identify a component in the tree. * (Actually, not really the shortest. For example if a component is * called root.machine0.mainbus0.ram0, then the shortest string may * be "ra". This function will return "ram0".) * * If there are components a.b.x, a.b.y, and a.c.x, then the shortest * possible paths for the three components are "b.x", "y", and "c.x" * respectively. * * @return A string which is part of the path of the component. */ string GenerateShortestPossiblePath() const; /** * \brief Looks up a path from this %Component, * and returns a pointer to the found %Component, if any * * The first name in the path should match the name of this component. * If so, this function moves on to the next part of the path (if there * are more parts) and looks up a child with that name, and so on. * * Alternatively, the path may be a partial match. * * @param path The path to the component, consisting of names with * "." (period) between names. * @return A reference counted pointer to the looked up component, * which is set to NULL if the path was not found. */ const refcount_ptr LookupPath(string path) const; /** * \brief Finds complete component paths, given a partial path. * * E.g. if the following components are available:
	 *	root.machine0.isabus0
	 *	root.machine1.pcibus0
	 *	root.machine1.pcibus1
	 *	root.machine2.pcibus0
 	 *	root.machine3.otherpci
	 * 
* * then a search for "pci" would return
	 *	root.machine1.pcibus0
	 *	root.machine1.pcibus1
	 *	root.machine2.pcibus0
	 * 
* (note: not otherpci) * * A search for machine1 would return
	 *	root.machine1
	 * 
* * Multiple words separated by "." should also be possible, so * "machine2.pcibus" will find "root.machine2.pcibus0", but * "machine.pcibus" will not match anything. * * Searching for an empty string ("") returns a vector of all * component paths. * * @param partialPath The partial path to complete. * @param shortestPossible Return shortest possible paths, instead of * full paths. * @return A vector of possible complete paths. */ vector FindPathByPartialMatch(const string& partialPath, bool shortestPossible = false) const; /** * \brief Adds a reference to a child component. * * @param childComponent A reference counted pointer to the child * component to add. * @param insertPosition If specified, this is the position in the * vector of child components where the child will be inserted. * If not specified (or -1), then the child will be added to * the end of the vector. */ void AddChild(refcount_ptr childComponent, size_t insertPosition = (size_t) -1); /** * \brief Removes a reference to a child component. * * @param childToRemove A pointer to the child to remove. * @return A zero-based index, which is the position in the vector * of children where the child was. (Needed for e.g. Undo * functionality.) */ size_t RemoveChild(Component* childToRemove); /** * \brief Gets pointers to child components. * * @return Reference counted pointers to child components. */ Components& GetChildren(); /** * \brief Gets pointers to child components, as a const reference. * * @return Reference counted pointers to child components. */ const Components& GetChildren() const; /** * \brief Retrieves a component's state variable names. * * @param names A vector of strings, where method names * should be added. */ void GetVariableNames(vector& names) const; /** * \brief Gets a pointer to a state variable. * * NOTE: The returned pointer should be used immediately after the * call. It will in general not be valid after e.g. an * AddVariable call. * * @param name The variable name. * @return A pointer to the variable, it the name was * known; NULL otherwise. */ StateVariable* GetVariable(const string& name); /** * \brief Gets a pointer to a state variable. * * NOTE: The returned pointer should be used immediately after the * call. It will in general not be valid after e.g. an * AddVariable call. * * @param name The variable name. * @return A pointer to the variable, it the name was * known; NULL otherwise. */ const StateVariable* GetVariable(const string& name) const; /** * \brief Sets a variable to a new value. * * @param name The variable name. * @param expression The new value. * @return True if the value was set, false otherwise. (E.g. if * the name was not known, or if there was a parse error * when parsing the value expression.) */ bool SetVariableValue(const string& name, const string& expression); /** * \brief Serializes the %Component into a string stream. * * @param ss An ostream which the %Component will be serialized to. * @param context A serialization context (used for TAB indentation). */ void Serialize(ostream& ss, SerializationContext& context) const; /** * \brief Deserializes a string into a component tree. * * @param messages A stream where errors/warnings may be reported. * @param str The string to deserialize. * @param pos Initial deserialization position in the string; should * be 0 when invoked manually. (Used for recursion, to avoid * copying.) * @return If deserialization was successful, the * reference counted pointer will point to a component tree; * on error, it will be set to NULL */ static refcount_ptr Deserialize(ostream& messages, const string& str, size_t& pos); /** * \brief Checks consistency by serializing and deserializing the * component (including all its child components), and comparing * the checksum of the original tree with the deserialized tree. * * @return true if the serialization/deserialization was correct, * false if there was some inconsistency */ bool CheckConsistency() const; /** * \brief Adds this component's state, including children, to * a checksum. * * @param checksum The checksum to add to. */ void AddChecksum(Checksum& checksum) const; protected: /** * \brief Adds a state variable of type T to the %Component. * * This function is only meant to be called from the component's * constructor. * * @param name The variable name. * @param variablePointer A pointer to the variable that the name should * be connected to. * @return True if the state variable was added, false if the name * was already in use. */ template bool AddVariable(const string& name, T* variablePointer) { StateVariableMap::iterator it = m_stateVariables.find(name); if (it != m_stateVariables.end()) return false; m_stateVariables.insert(pair (name, StateVariable(name, variablePointer))); return true; } /** * \brief Adds a custom state variable to the %Component. * * This function is only meant to be called from the component's * constructor. * * @param name The variable name. * @param variableHandler A pointer to the handler that knows how * to serialize/deserialize the variable. * @return True if the state variable was added, false if the name * was already in use. */ bool AddCustomVariable(const string& name, CustomStateVariableHandler* variableHandler) { StateVariableMap::iterator it = m_stateVariables.find(name); if (it != m_stateVariables.end()) return false; m_stateVariables.insert(pair (name, StateVariable(name, variableHandler))); return true; } /** * \brief Checks whether a write to a variable is OK. * * This function is called after the variable has been written. * By returning false, the component indicates that the value which * was written is invalid, and the write will be undone. * * An implementation should first check variables defined for the * implementation class, and then call its base class' function. * * The implementation in the base Component class handles the variables * that are defined for all components, and returns true for anything * else. * * @param var The variable to check. * @param oldValue The serialized previous value. * @return true if the write was ok, false otherwise. */ virtual bool CheckVariableWrite(StateVariable& var, const string& oldValue); /** * \brief Resets the state variables of this component. * * Note 1: This function is not recursive, so children should not be * traversed. * * Note 2: After a component's state variables have been reset, the * base class' ResetState() function should also be called. * * The implementation of this function ususally takes the form of a * number of assignment of values to member variables, and then * the call to the base class' ResetState() function. */ virtual void ResetState(); /** * \brief Checks the state of this component, before starting execution. * * Note 1: This function is not recursive, so children should not be * traversed. * * Note 2: After a component's state variables have been checked, the * base class' PreRunCheckForComponent(GXemul*) function should also be * called. * * The implementation of this function may choose to print warning * messages but still return true, or it can print error messages and * return false. * * Typical examples of pre-run-check failures are: *
    *
  • collision of MemoryMappedComponent on an AddressDataBus *
  • a CPUComponent that can not reach any kind of AddressDataBus *
* * @return true if the component is ready to run, false otherwise. */ virtual bool PreRunCheckForComponent(GXemul* gxemul); /** * \brief Resets the cached state of this component. * * Note 1: This function is not recursive, so children should not be * traversed. * * Note 2: After a component's state variables have been reset, the * base class' FlushCachedStateForComponent() function should also be * called. * * The implementation of this function ususally takes the form of * setting a number of pointers to NULL, and then * the call to the base class' FlushCachedStateForComponent() function. */ virtual void FlushCachedStateForComponent(); /** * \brief Returns a reference to the current GXemul instance. * * @return NULL if there was no currently running instance, otherwise * a pointer to the currently running GXemul instance. */ GXemul* GetRunningGXemulInstance(); /** * \brief Gets an UI reference for outputting debug messages during * runtime. * * @return NULL if debug messages are turned off, or if there is no * owning GXemul instance. Otherwise, a pointer to an UI. */ UI* GetUI(); private: /** * \brief Looks up a path from this %Component, * and returns a pointer to the found %Component, if any * * The first name in the path should match the name of this component. * If so, this function moves on to the next part of the path (if there * are more parts) and looks up a child with that name, and so on. * * @param path The path to the component, split into separate names. * This vector should contain at least 1 element. * @param index The index into the path vector, where the current * lookup should start. (This is to avoid copying.) * @return A reference counted pointer to the looked up component, * which is set to NULL if the path was not found. */ const refcount_ptr LookupPath(const vector& path, size_t index) const; /** * \brief Internal helper, which gathers a list of all component paths. * * @param allComponentPaths A vector which will be filled with all * components' paths. */ void AddAllComponentPaths(vector& allComponentPaths) const; /** * \brief Internal helper for LightClone. * * See LightClone() for details. */ refcount_ptr LightCloneInternal() const; /** * \brief Disallow creation of %Component objects using the * default constructor. */ Component(); private: Component* m_parentComponent; Components m_childComponents; string m_className; string m_visibleClassName; StateVariableMap m_stateVariables; // The following are this component's variables. Components that // inherit from this class add their own instance variables. string m_name; // This Component's instance name. string m_template; // Set if this Component // was based on a template. uint64_t m_step; // Nr of executed steps. }; #endif // COMPONENT_H gxemul-0.6.1/src/include/Checksum.h000644 001750 001750 00000006110 13402411502 017350 0ustar00debugdebug000000 000000 #ifndef CHECKSUM_H #define CHECKSUM_H /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "UnitTest.h" /** * \brief A checksum accumulator. * * The main purpose of this class is as a helper in unit tests, where * objects such as trees are hard to compare to each other. A checksum * of the first tree can then be compared with a checksum of the second * tree. * * Note: This is not scientifically correct in any way. It is just something * I made up, for unit testing purposes. (2007-12-27) */ class Checksum : public UnitTestable { public: /** * \brief Constructs a zeroed checksum. */ Checksum(); /** * \brief Retrieves the value of the checksum, as a uint64_t. * * @return the checksum value */ uint64_t Value() const; /** * \brief Add a uint64_t to the checksum. * * @param x Value to add. */ void Add(uint64_t x); /** * \brief Add a string to the checksum. * * @param str The string to add. */ void Add(const string& str); /** * \brief Compares one %Checksum to another for equality. * * @param other The %Checksum to compare to. * @return true if the checksums match, false otherwise. */ bool operator == (const Checksum& other) const; /** * \brief Compares one %Checksum to another for inequality. * * @param other The %Checksum to compare to. * @return false if the checksums match, true otherwise. */ bool operator != (const Checksum& other) const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); private: uint64_t m_value; }; #endif // CHECKSUM_H gxemul-0.6.1/src/include/mips_cpu_types.h000644 001750 001750 00000017201 13402411502 020654 0ustar00debugdebug000000 000000 #ifndef MIPS_CPU_TYPES_H #define MIPS_CPU_TYPES_H /* * Copyright (C) 2003-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * MIPS CPU types. */ #include /* MIPS CPU types: */ #include "thirdparty/mips_cpuregs.h" #define EXC3K 3 #define EXC4K 4 #define EXC32 32 #define EXC64 64 #define MMU3K 3 #define MMU4K 4 #define MMU8K 8 #define MMU10K 10 #define MMU32 32 #define MMU64 64 /* Bit-field values for the flags field: */ #define NOLLSC 1 #define DCOUNT 2 #define NOFPU 4 /* * --------------------------------------------------------------------------- * Please do NOT use this list as a definite source for * PrID numbers, cache sizes, or anything like that! * --------------------------------------------------------------------------- * * These numbers are gathered from various other places (manuals, mailing list * posts, and from source code from various operating systems), and are not * necessarily correct. */ #define MIPS_CPU_TYPE_DEFS { \ { "R2000", MIPS_R2000, 0x00, NOLLSC, EXC3K, MMU3K, 1, 0, 64, 1,13,2,1,13,2,1, 0, 0, 0 }, \ { "R2000A", MIPS_R2000, 0x10, NOLLSC, EXC3K, MMU3K, 1, 0, 64, 1,13,2,1,13,2,1, 0, 0, 0 }, \ { "R3000", MIPS_R3000, 0x20, NOLLSC, EXC3K, MMU3K, 1, 0, 64, 1,12,2,1,12,2,1, 0, 0, 0 }, \ { "R3000A", MIPS_R3000, 0x30, NOLLSC, EXC3K, MMU3K, 1, 0, 64, 1,13,2,1,13,2,1, 0, 0, 0 }, \ { "R6000", MIPS_R6000, 0x00, 0, EXC3K, MMU3K, 2, 0, 32, 1,16,2,2,16,2,2, 0, 0, 0 }, /* instrs/cycle? */ \ { "R4000", MIPS_R4000, 0x00, DCOUNT, EXC4K, MMU4K, 3, 0, 48, 2,13,4,2,13,4,2,19, 6, 1 }, \ { "R4000PC", MIPS_R4000, 0x00, DCOUNT, EXC4K, MMU4K, 3, 0, 48, 2,13,4,2,13,4,2, 0, 6, 1 }, \ { "R10000", MIPS_R10000,0x26, 0, EXC4K, MMU10K, 4, 0, 64, 4,15,6,2,15,5,2,20, 6, 1 }, \ { "R4200", MIPS_R4200, 0x00, 0, EXC4K, MMU4K, 3, 0, 32, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* No DCOUNT? */ \ { "R4300", MIPS_R4300, 0x00, 0, EXC4K, MMU4K, 3, 0, 32, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* No DCOUNT? */ \ { "R4100", MIPS_R4100, 0x00, 0, EXC4K, MMU4K, 3, 0, 32, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* No DCOUNT? */ \ { "VR4102", MIPS_R4100, 0x40, NOFPU, EXC4K, MMU4K, 3, 0, 32, 2,12,0,0,10,0,0, 0, 0, 0 }, /* TODO: Bogus? */ \ { "VR4181", MIPS_R4100, 0x50, NOFPU, EXC4K, MMU4K, 3, 0, 32, 2,14,4,0,13,4,0, 0, 0, 0 }, \ { "VR4121", MIPS_R4100, 0x60, NOFPU, EXC4K, MMU4K, 3, 0, 32, 2,14,4,0,13,4,0, 0, 0, 0 }, \ { "VR4122", MIPS_R4100, 0x70, NOFPU, EXC4K, MMU4K, 3, 0, 32, 2,15,5,0,14,4,0, 0, 0, 0 }, \ { "VR4131", MIPS_R4100, 0x80, NOFPU, EXC4K, MMU4K, 3, 0, 32, 2,14,5,0,14,5,0, 0, 0, 0 }, \ { "R4400", MIPS_R4000, 0x40, DCOUNT, EXC4K, MMU4K, 3, 0, 48, 2,14,4,1,14,4,1,20, 6, 1 }, \ { "R4600", MIPS_R4600, 0x00, DCOUNT, EXC4K, MMU4K, 3, 0, 48, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \ { "R4700", MIPS_R4700, 0x00, 0, EXC4K, MMU4K, 3, 0, 48, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* No DCOUNT? */ \ { "R4650", MIPS_R4650, 0x00, 0, EXC4K, MMU4K, 3, 0, 48, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* No DCOUNT? */ \ { "R8000", MIPS_R8000, 0, 0, EXC4K, MMU8K, 4, 0, 192, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 192 tlb entries? or 384? instrs/cycle? */ \ { "R12000", MIPS_R12000,0x23, 0, EXC4K, MMU10K, 4, 0, 64, 4,15,6,2,15,5,2,23, 6, 1 }, \ { "R14000", MIPS_R14000,0, 0, EXC4K, MMU10K, 4, 0, 64, 4,15,6,2,15,5,2,22, 6, 1 }, \ { "R5000", MIPS_R5000, 0x21, DCOUNT, EXC4K, MMU4K, 4, 0, 48, 4,15,5,2,15,5,2, 0, 0, 0 }, /* 2way I,D; instrs/cycle? */ \ { "R5900", MIPS_R5900, 0x20, 0, EXC4K, MMU4K, 3, 0, 48, 4,14,6,2,13,6,2, 0, 0, 0 }, /* instrs/cycle? */ \ { "TX3920", MIPS_TX3900,0x30, 0, EXC32, MMU32, 1, 0, 32, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* TODO: bogus? */ \ { "TX7901", MIPS_TX7900,0x01, 0, EXC4K, MMU4K, 3, 1, 48, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* TODO: bogus? */ \ { "VR5432", MIPS_R5400, 13, 0, EXC4K, MMU4K, 4, 0, 48, 4,15,0,0,15,0,0, 0, 0, 0 }, /* DCOUNT? instrs/cycle? linesize? etc */ \ { "RM5200", MIPS_RM5200,0xa0, 0, EXC4K, MMU4K, 4, 0, 48, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* DCOUNT? instrs/cycle? */ \ { "RM7000", MIPS_RM7000,0x0 /* ? */,DCOUNT, EXC4K, MMU4K, 4, 0, 48, 4,14,5,1,14,5,1,18, 6, 1 }, /* instrs/cycle? cachelinesize & assoc.? RM7000A? */ \ { "RM7900", 0x34 /*?*/, 0x0 /* ? */,DCOUNT,EXC4K, MMU4K, 4, 0, 64, 4,14,5,1,14,5,1,18, 6, 1 }, /* instrs/cycle? cachelinesize? assoc = 4ways for all */ \ { "RM9000", 0x34 /*?*/, 0x0 /* ? */,DCOUNT,EXC4K, MMU4K, 4, 0, 48, 4,14,5,1,14,5,1,18, 6, 1 }, /* This is totally bogus */ \ { "RC32334", MIPS_RC32300,0x00, 0, EXC32, MMU4K, 32, 1, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \ { "4Kc", 0x100+MIPS_4Kc, 1, 0, EXC32, MMU32, 32, 1, 16, 4,14,4,2,14,4,2, 0, 0, 0 }, /* DCOUNT? instrs/cycle? BOGUS, TODO */ \ { "4KEc", 0x100+MIPS_4KEc_R2, 1, 0, EXC32, MMU32, 32, 2, 16, 4,14,4,2,14,4,2, 0, 0, 0 }, /* DCOUNT? instrs/cycle? BOGUS, TODO */ \ { "5Kc", 0x100+MIPS_5Kc, 1, 0, EXC64, MMU64, 64, 1, 48, 4,15,5,2,15,5,2, 0, 0, 0 }, /* DCOUNT? instrs/cycle? BOGUS, TODO */ \ { "5KE", 0x100+MIPS_5KE, 1, 0, EXC64, MMU64, 64, 2, 48, 4,15,5,2,15,5,2, 0, 0, 0 }, /* DCOUNT? instrs/cycle? BOGUS, TODO */ \ { "24KEc", 0x100+MIPS_24KE, 1, 0, EXC32, MMU32, 32, 2, 32, 4,15,5,2,15,5,2, 0, 0, 0 }, /* revision level? DCOUNT? instrs/cycle? cache? BOGUS, TODO */ \ { "BCM4710", 0x000240, 0x00, 0, EXC32, MMU32, 32, 1, 32, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* TODO: this is just bogus */ \ { "BCM4712", 0x000290, 0x07, 0, EXC32, MMU32, 32, 1, 32, 2,13,4,1,12,4,1, 0, 0, 0 }, /* 2ways I, 2ways D */ \ { "AU1000", 0x00302, 0x01, 0, EXC32, MMU32, 32, 1, 32, 2,14,5,2,14,5,2, 0, 0, 0 }, /* TODO: this is just bogus */ \ { "AU1500", 0x10302, 0x02, 0, EXC32, MMU32, 32, 1, 32, 2,14,5,4,14,5,4, 0, 0, 0 }, \ { "AU1100", 0x20302, 0x01, 0, EXC32, MMU32, 32, 1, 32, 2,14,5,2,14,5,2, 0, 0, 0 }, /* TODO: this is just bogus */ \ { "SB1", 0x000401, 0x00, 0, EXC64, MMU64, 64, 1, 32, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* TODO: this is just bogus */ \ { "SR7100", 0x000504, 0x00, 0, EXC64, MMU64, 64, 1, 32, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* TODO: this is just bogus */ \ { "Allegrex", 0x000000, 0x00, 0, EXC32, MMU32, 2, 0, 4, 1,14,6,2,14,6,2, 0, 0, 0 }, \ { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } #endif /* MIPS_CPU_TYPES_H */ gxemul-0.6.1/src/include/opcodes_mips.h000644 001750 001750 00000062774 13402411502 020314 0ustar00debugdebug000000 000000 #ifndef OPCODES_MIPS_H #define OPCODES_MIPS_H /* * Copyright (C) 2003-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * MIPS opcodes, gathered from various sources. * * There are quite a number of different MIPS instruction sets, some are * subsets/supersets of others, but not all of them. * * MIPS ISA I, II, III, IV: Backward-compatible ISAs used in R2000/R3000 * (ISA I), R6000 (ISA II), R4000 (ISA III), * and R5000/R1x000 (ISA IV). * * MIPS ISA V: Never implemented in hardware? * * MIPS32 and MIPS64: The "modern" version of the ISA. These exist * in a revision 1, and a revision 2 (the latest * at the time of writing this). * * MIPS16: A special encoding form for MIPS32/64 which * uses 16-bit instruction words instead of * 32-bit. * * MDMX: MIPS Digital Media Extension. * * MIPS 3D: 3D instructions. * * MIPS MT: Multi-Threaded stuff. */ /* Opcodes: */ #define HI6_NAMES { \ "special", "regimm", "j", "jal", "beq", "bne", "blez", "bgtz", /* 0x00 - 0x07 */ \ "addi", "addiu", "slti", "sltiu", "andi", "ori", "xori", "lui", /* 0x08 - 0x0f */ \ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl", "bgtzl", /* 0x10 - 0x17 */ \ "daddi", "daddiu", "ldl", "ldr", "special2", "hi6_1d","lq" /*mdmx*/, "sq" /*special3*/, /* 0x18 - 0x1f */\ "lb", "lh", "lwl", "lw", "lbu", "lhu", "lwr", "lwu", /* 0x20 - 0x27 */ \ "sb", "sh", "swl", "sw", "sdl", "sdr", "swr", "cache", /* 0x28 - 0x2f */ \ "ll", "lwc1", "lwc2", "lwc3", "lld", "ldc1", "ldc2", "ld", /* 0x30 - 0x37 */ \ "sc", "swc1", "swc2", "swc3", "scd", "sdc1", "sdc2", "sd" /* 0x38 - 0x3f */ } #define REGIMM_NAMES { \ "bltz", "bgez", "bltzl", "bgezl", "regimm_04", "regimm_05", "regimm_06", "regimm_07", /* 0x00 - 0x07 */ \ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "regimm_0d", "tnei", "regimm_0f", /* 0x08 - 0x0f */ \ "bltzal", "bgezal", "bltzall", "bgezall", "regimm_14", "regimm_15", "regimm_16", "regimm_17", /* 0x10 - 0x17 */ \ "mtsab", "mtsah", "regimm_1a", "regimm_1b", "regimm_1c", "regimm_1d", "regimm_1e", "synci" /* 0x18 - 0x1f */ } #define SPECIAL_NAMES { \ "sll", "special_01", "srl", "sra", "sllv", "special_05", "srlv", "srav", /* 0x00 - 0x07 */ \ "jr", "jalr", "movz", "movn", "syscall","break", "special_0e", "sync", /* 0x08 - 0x0f */ \ "mfhi", "mthi", "mflo", "mtlo", "dsllv", "special_15", "dsrlv", "dsrav", /* 0x10 - 0x17 */ \ "mult", "multu", "div", "divu", "dmult", "dmultu", "ddiv", "ddivu", /* 0x18 - 0x1f */ \ "add", "addu", "sub", "subu", "and", "or", "xor", "nor", /* 0x20 - 0x27 */ \ "special_28","special_29","slt", "sltu", "dadd", "daddu", "dsub", "dsubu", /* 0x28 - 0x2f */ \ "tge", "tgeu", "tlt", "tltu", "teq", "special_35", "tne", "special_37",/* 0x30 - 0x37 */ \ "dsll", "special_39", "dsrl", "dsra", "dsll32", "special_3d", "dsrl32", "dsra32" /* 0x38 - 0x3f */ } /* SPECIAL opcodes, when the rotate bit is set: */ #define SPECIAL_ROT_NAMES { \ "rot_00", "rot_01", "ror", "rot_03", "rot_04", "rot_05", "rorv", "rot_07", /* 0x00 - 0x07 */ \ "rot_08", "rot_09", "rot_0a", "rot_0b", "rot_0c", "rot_0d", "rot_0e", "rot_0f", /* 0x08 - 0x0f */ \ "rot_10", "rot_11", "rot_12", "rot_13", "rot_14", "rot_15", "drorv", "rot_17", /* 0x10 - 0x17 */ \ "rot_18", "rot_19", "rot_1a", "rot_1b", "rot_1c", "rot_1d", "rot_1e", "rot_1f", /* 0x18 - 0x1f */ \ "rot_20", "rot_21", "rot_22", "rot_23", "rot_24", "rot_25", "rot_26", "rot_27", /* 0x20 - 0x27 */ \ "rot_28", "rot_29", "rot_2a", "rot_2b", "rot_2c", "rot_2d", "rot_2e", "rot_2f", /* 0x28 - 0x2f */ \ "rot_30", "rot_31", "rot_32", "rot_33", "rot_34", "rot_35", "rot_36", "rot_37", /* 0x30 - 0x37 */ \ "rot_38", "rot_39", "dror", "rot_3b", "rot_3c", "rot_3d", "dror32", "rot_3f" /* 0x38 - 0x3f */ } #define SPECIAL2_NAMES { \ "madd", "maddu", "mul", "special2_03", "msub", "msubu", "special2_06", "special2_07", /* 0x00 - 0x07 */ \ "special2_08", "special2_09", "special2_0a", "special2_0b", "special2_0c", "special2_0d", "special2_0e", "special2_0f", /* 0x08 - 0x0f */ \ "special2_10", "special2_11", "special2_12", "special2_13", "special2_14", "special2_15", "special2_16", "special2_17", /* 0x10 - 0x17 */ \ "special2_18", "special2_19", "special2_1a", "special2_1b", "special2_1c", "special2_1d", "special2_1e", "special2_1f", /* 0x18 - 0x1f */ \ "clz", "clo", "special2_22", "special2_23", "dclz", "dclo", "special2_26", "special2_27", /* 0x20 - 0x27 */ \ "special2_28", "special2_29", "special2_2a", "special2_2b", "special2_2c", "special2_2d", "special2_2e", "special2_2f", /* 0x28 - 0x2f */ \ "special2_30", "special2_31", "special2_32", "special2_33", "special2_34", "special2_35", "special2_36", "special2_37", /* 0x30 - 0x37 */ \ "special2_38", "special2_39", "special2_3a", "special2_3b", "special2_3c", "special2_3d", "special2_3e", "sdbbp" /* 0x38 - 0x3f */ } /* MMI (on R5900, TX79/C790) occupies the same space as SPECIAL2 */ #define MMI_NAMES { \ "madd", "maddu", "mmi_02", "mmi_03", "plzcw", "mmi_05", "mmi_06", "mmi_07", /* 0x00 - 0x07 */ \ "mmi0", "mmi2", "mmi_0a", "mmi_0b", "mmi_0c", "mmi_0d", "mmi_0e", "mmi_0f", /* 0x08 - 0x0f */ \ "mfhi1", "mthi1", "mflo1", "mtlo1", "mmi_14", "mmi_15", "mmi_16", "mmi_17", /* 0x10 - 0x17 */ \ "mult1", "multu1", "div1", "divu1", "mmi_1c", "mmi_1d", "mmi_1e", "mmi_1f", /* 0x18 - 0x1f */ \ "madd1", "maddu1", "mmi_22", "mmi_23", "mmi_24", "mmi_25", "mmi_26", "mmi_27", /* 0x20 - 0x27 */ \ "mmi1", "mmi3", "mmi_2a", "mmi_2b", "mmi_2c", "mmi_2d", "mmi_2e", "mmi_2f", /* 0x28 - 0x2f */ \ "pmfhl", "pmthl", "mmi_32", "mmi_33", "psllh", "mmi_35", "psrlh", "psrah", /* 0x30 - 0x37 */ \ "mmi_38", "mmi_39", "mmi_3a", "mmi_3b", "psllw", "mmi_3d", "psrlw", "psraw" /* 0x38 - 0x3f */ } #define MMI0_NAMES { \ "paddw", "psubw", "pcgtw", "pmaxw", /* 0x00 - 0x03 */ \ "paddh", "psubh", "pcgth", "pmaxh", /* 0x04 - 0x07 */ \ "paddb", "psubb", "pcgtb", "mmi0_0b", /* 0x08 - 0x0b */ \ "mmi0_0c", "mmi0_0d", "mmi0_0e", "mmi0_0f", /* 0x0c - 0x0f */ \ "paddsw", "psubsw", "pextlw", "ppacw", /* 0x10 - 0x13 */ \ "paddsh", "psubsh", "pextlh", "ppach", /* 0x14 - 0x17 */ \ "paddsb", "psubsb", "pextlb", "ppacb", /* 0x18 - 0x1b */ \ "mmi0_1c", "mmi0_1d", "pext5", "ppac5" /* 0x1c - 0x1f */ } #define MMI1_NAMES { \ "mmi1_00", "pabsw", "pceqw", "pminw", /* 0x00 - 0x03 */ \ "padsbh", "pabsh", "pceqh", "pminh", /* 0x04 - 0x07 */ \ "mmi1_08", "mmi1_09", "pceqb", "mmi1_0b", /* 0x08 - 0x0b */ \ "mmi1_0c", "mmi1_0d", "mmi1_0e", "mmi1_0f", /* 0x0c - 0x0f */ \ "padduw", "psubuw", "pextuw", "mmi1_13", /* 0x10 - 0x13 */ \ "padduh", "psubuh", "pextuh", "mmi1_17", /* 0x14 - 0x17 */ \ "paddub", "psubub", "pextub", "qfsrv", /* 0x18 - 0x1b */ \ "mmi1_1c", "mmi1_1d", "mmi1_1e", "mmi1_1f" /* 0x1c - 0x1f */ } #define MMI2_NAMES { \ "pmaddw", "mmi2_01", "psllvw", "psrlvw", /* 0x00 - 0x03 */ \ "pmsubw", "mmi2_05", "mmi2_06", "mmi2_07", /* 0x04 - 0x07 */ \ "pmfhi", "pmflo", "pinth", "mmi2_0b", /* 0x08 - 0x0b */ \ "pmultw", "pdivw", "pcpyld" , "mmi2_0f", /* 0x0c - 0x0f */ \ "pmaddh", "phmadh", "pand", "pxor", /* 0x10 - 0x13 */ \ "pmsubh", "phmsbh", "mmi2_16", "mmi2_17", /* 0x14 - 0x17 */ \ "mmi2_18", "mmi2_19", "pexeh", "prevh", /* 0x18 - 0x1b */ \ "pmulth", "pdivbw", "pexew", "prot3w" /* 0x1c - 0x1f */ } #define MMI3_NAMES { \ "pmadduw", "mmi3_01", "mmi3_02", "psravw", /* 0x00 - 0x03 */ \ "mmi3_04", "mmi3_05", "mmi3_06", "mmi3_07", /* 0x04 - 0x07 */ \ "pmthi", "pmtlo", "pinteh", "mmi3_0b", /* 0x08 - 0x0b */ \ "pmultuw", "pdivuw", "pcpyud" , "mmi3_0f", /* 0x0c - 0x0f */ \ "mmi3_10", "mmi3_11", "por", "pnor", /* 0x10 - 0x13 */ \ "mmi3_14", "mmi3_15", "mmi3_16", "mmi3_17", /* 0x14 - 0x17 */ \ "mmi3_18", "mmi3_19", "pexch", "pcpyh", /* 0x18 - 0x1b */ \ "mmi3_1c", "mmi3_1d", "pexcw", "mmi3_1f" /* 0x1c - 0x1f */ } #define SPECIAL3_NAMES { \ "ext", "dextm", "dextu", "dext", "ins", "dinsm", "dinsu", "dins", /* 0x00 - 0x07 */ \ "special3_08", "special3_09", "special3_0a", "special3_0b", "special3_0c", "special3_0d", "special3_0e", "special3_0f", /* 0x08 - 0x0f */ \ "special3_10", "special3_11", "special3_12", "special3_13", "special3_14", "special3_15", "special3_16", "special3_17", /* 0x10 - 0x17 */ \ "special3_18", "special3_19", "special3_1a", "special3_1b", "special3_1c", "special3_1d", "special3_1e", "special3_1f", /* 0x18 - 0x1f */ \ "bshfl", "special3_21", "special3_22", "special3_23", "dbshfl", "special3_25", "special3_26", "special3_27", /* 0x20 - 0x27 */ \ "special3_28", "special3_29", "special3_2a", "special3_2b", "special3_2c", "special3_2d", "special3_2e", "special3_2f", /* 0x28 - 0x2f */ \ "special3_30", "special3_31", "special3_32", "special3_33", "special3_34", "special3_35", "special3_36", "special3_37", /* 0x30 - 0x37 */ \ "special3_38", "special3_39", "special3_3a", "rdhwr", "special3_3c", "special3_3d", "special3_3e", "special3_3f" /* 0x38 - 0x3f */ } #define HI6_SPECIAL 0x00 /* 000000 */ #define SPECIAL_SLL 0x00 /* 000000 */ /* MIPS I */ /* 0x01 000001 */ #define SPECIAL_SRL 0x02 /* 000010 */ /* MIPS I */ #define SPECIAL_SRA 0x03 /* 000011 */ /* MIPS I */ #define SPECIAL_SLLV 0x04 /* 000100 */ /* MIPS I */ /* 0x05 000101 */ #define SPECIAL_SRLV 0x06 /* 000110 */ #define SPECIAL_SRAV 0x07 /* 000111 */ /* MIPS I */ #define SPECIAL_JR 0x08 /* 001000 */ /* MIPS I */ #define SPECIAL_JALR 0x09 /* 001001 */ /* MIPS I */ #define SPECIAL_MOVZ 0x0a /* 001010 */ /* MIPS IV */ #define SPECIAL_MOVN 0x0b /* 001011 */ /* MIPS IV */ #define SPECIAL_SYSCALL 0x0c /* 001100 */ /* MIPS I */ #define SPECIAL_BREAK 0x0d /* 001101 */ /* MIPS I */ /* 0x0e 001110 */ #define SPECIAL_SYNC 0x0f /* 001111 */ /* MIPS II */ #define SPECIAL_MFHI 0x10 /* 010000 */ /* MIPS I */ #define SPECIAL_MTHI 0x11 /* 010001 */ /* MIPS I */ #define SPECIAL_MFLO 0x12 /* 010010 */ /* MIPS I */ #define SPECIAL_MTLO 0x13 /* 010011 */ /* MIPS I */ #define SPECIAL_DSLLV 0x14 /* 010100 */ /* 0x15 010101 */ #define SPECIAL_DSRLV 0x16 /* 010110 */ /* MIPS III */ #define SPECIAL_DSRAV 0x17 /* 010111 */ /* MIPS III */ #define SPECIAL_MULT 0x18 /* 011000 */ /* MIPS I */ #define SPECIAL_MULTU 0x19 /* 011001 */ /* MIPS I */ #define SPECIAL_DIV 0x1a /* 011010 */ /* MIPS I */ #define SPECIAL_DIVU 0x1b /* 011011 */ /* MIPS I */ #define SPECIAL_DMULT 0x1c /* 011100 */ /* MIPS III */ #define SPECIAL_DMULTU 0x1d /* 011101 */ /* MIPS III */ #define SPECIAL_DDIV 0x1e /* 011110 */ /* MIPS III */ #define SPECIAL_DDIVU 0x1f /* 011111 */ /* MIPS III */ #define SPECIAL_ADD 0x20 /* 100000 */ /* MIPS I */ #define SPECIAL_ADDU 0x21 /* 100001 */ /* MIPS I */ #define SPECIAL_SUB 0x22 /* 100010 */ /* MIPS I */ #define SPECIAL_SUBU 0x23 /* 100011 */ /* MIPS I */ #define SPECIAL_AND 0x24 /* 100100 */ /* MIPS I */ #define SPECIAL_OR 0x25 /* 100101 */ /* MIPS I */ #define SPECIAL_XOR 0x26 /* 100110 */ /* MIPS I */ #define SPECIAL_NOR 0x27 /* 100111 */ /* MIPS I */ #define SPECIAL_MFSA 0x28 /* 101000 */ /* R5900/TX79/C790 */ #define SPECIAL_MTSA 0x29 /* 101001 */ /* R5900/TX79/C790 */ #define SPECIAL_SLT 0x2a /* 101010 */ /* MIPS I */ #define SPECIAL_SLTU 0x2b /* 101011 */ /* MIPS I */ #define SPECIAL_DADD 0x2c /* 101100 */ /* MIPS III */ #define SPECIAL_DADDU 0x2d /* 101101 */ /* MIPS III */ #define SPECIAL_DSUB 0x2e /* 101110 */ #define SPECIAL_DSUBU 0x2f /* 101111 */ /* MIPS III */ #define SPECIAL_TGE 0x30 /* 110000 */ #define SPECIAL_TGEU 0x31 /* 110001 */ #define SPECIAL_TLT 0x32 /* 110010 */ #define SPECIAL_TLTU 0x33 /* 110011 */ #define SPECIAL_TEQ 0x34 /* 110100 */ /* 0x35 110101 */ #define SPECIAL_TNE 0x36 /* 110110 */ /* 0x37 110111 */ #define SPECIAL_DSLL 0x38 /* 111000 */ /* MIPS III */ /* 0x39 111001 */ #define SPECIAL_DSRL 0x3a /* 111010 */ /* MIPS III */ #define SPECIAL_DSRA 0x3b /* 111011 */ /* MIPS III */ #define SPECIAL_DSLL32 0x3c /* 111100 */ /* MIPS III */ /* 0x3d 111101 */ #define SPECIAL_DSRL32 0x3e /* 111110 */ /* MIPS III */ #define SPECIAL_DSRA32 0x3f /* 111111 */ /* MIPS III */ #define HI6_REGIMM 0x01 /* 000001 */ #define REGIMM_BLTZ 0x00 /* 00000 */ /* MIPS I */ #define REGIMM_BGEZ 0x01 /* 00001 */ /* MIPS I */ #define REGIMM_BLTZL 0x02 /* 00010 */ /* MIPS II */ #define REGIMM_BGEZL 0x03 /* 00011 */ /* MIPS II */ #define REGIMM_TGEI 0x08 /* 01000 */ #define REGIMM_TGEIU 0x09 /* 01001 */ #define REGIMM_TLTI 0x0a /* 01010 */ #define REGIMM_TLTIU 0x0b /* 01011 */ #define REGIMM_TEQI 0x0c /* 01100 */ #define REGIMM_TNEI 0x0e /* 01110 */ #define REGIMM_BLTZAL 0x10 /* 10000 */ #define REGIMM_BGEZAL 0x11 /* 10001 */ #define REGIMM_BLTZALL 0x12 /* 10010 */ #define REGIMM_BGEZALL 0x13 /* 10011 */ #define REGIMM_MTSAB 0x18 /* 11000 */ /* R5900/TX79/C790 */ #define REGIMM_MTSAH 0x19 /* 11001 */ /* R5900/TX79/C790 */ #define REGIMM_SYNCI 0x1f /* 11111 */ /* regimm ............... */ #define HI6_J 0x02 /* 000010 */ /* MIPS I */ #define HI6_JAL 0x03 /* 000011 */ /* MIPS I */ #define HI6_BEQ 0x04 /* 000100 */ /* MIPS I */ #define HI6_BNE 0x05 /* 000101 */ #define HI6_BLEZ 0x06 /* 000110 */ /* MIPS I */ #define HI6_BGTZ 0x07 /* 000111 */ /* MIPS I */ #define HI6_ADDI 0x08 /* 001000 */ /* MIPS I */ #define HI6_ADDIU 0x09 /* 001001 */ /* MIPS I */ #define HI6_SLTI 0x0a /* 001010 */ /* MIPS I */ #define HI6_SLTIU 0x0b /* 001011 */ /* MIPS I */ #define HI6_ANDI 0x0c /* 001100 */ /* MIPS I */ #define HI6_ORI 0x0d /* 001101 */ /* MIPS I */ #define HI6_XORI 0x0e /* 001110 */ /* MIPS I */ #define HI6_LUI 0x0f /* 001111 */ /* MIPS I */ #define HI6_COP0 0x10 /* 010000 */ #define COPz_MFCz 0x00 /* 00000 */ #define COPz_DMFCz 0x01 /* 00001 */ #define COPz_MTCz 0x04 /* 00100 */ #define COPz_DMTCz 0x05 /* 00101 */ /* * For cop1 (the floating point coprocessor), if bits 25..21 are * a valid format, then bits 5..0 are the math opcode. * * Otherwise, bits 25..21 are the main coprocessor opcode. */ #define COPz_CFCz 0x02 /* 00010 */ /* MIPS I */ #define COPz_CTCz 0x06 /* 00110 */ /* MIPS I */ #define COPz_BCzc 0x08 /* 01000 */ #define COPz_MFMCz 0x0b /* 01011 */ #define COP1_FMT_S 0x10 /* 10000 */ #define COP1_FMT_D 0x11 /* 10001 */ #define COP1_FMT_W 0x14 /* 10100 */ #define COP1_FMT_L 0x15 /* 10101 */ #define COP1_FMT_PS 0x16 /* 10110 */ /* COP0 opcodes = bits 7..0 (only if COP0 and CO=1): */ #define COP0_TLBR 0x01 /* 000001 */ #define COP0_TLBWI 0x02 /* 000010 */ #define COP0_TLBWR 0x06 /* 000110 */ #define COP0_TLBP 0x08 /* 001000 */ #define COP0_RFE 0x10 /* 010000 */ #define COP0_ERET 0x18 /* 011000 */ #define COP0_DERET 0x1f /* 011111 */ /* EJTAG */ #define COP0_WAIT 0x20 /* 100000 */ /* MIPS32/64 */ #define COP0_STANDBY 0x21 /* 100001 */ #define COP0_SUSPEND 0x22 /* 100010 */ #define COP0_HIBERNATE 0x23 /* 100011 */ #define COP0_EI 0x38 /* 111000 */ /* R5900/TX79/C790 */ #define COP0_DI 0x39 /* 111001 */ /* R5900/TX79/C790 */ #define HI6_COP1 0x11 /* 010001 */ #define HI6_COP2 0x12 /* 010010 */ #define HI6_COP3 0x13 /* 010011 */ #define HI6_BEQL 0x14 /* 010100 */ /* MIPS II */ #define HI6_BNEL 0x15 /* 010101 */ #define HI6_BLEZL 0x16 /* 010110 */ /* MIPS II */ #define HI6_BGTZL 0x17 /* 010111 */ /* MIPS II */ #define HI6_DADDI 0x18 /* 011000 */ /* MIPS III */ #define HI6_DADDIU 0x19 /* 011001 */ /* MIPS III */ #define HI6_LDL 0x1a /* 011010 */ /* MIPS III */ #define HI6_LDR 0x1b /* 011011 */ /* MIPS III */ #define HI6_SPECIAL2 0x1c /* 011100 */ #define SPECIAL2_MADD 0x00 /* 000000 */ /* MIPS32 (?) TODO */ #define SPECIAL2_MADDU 0x01 /* 000001 */ /* MIPS32 (?) TODO */ #define SPECIAL2_MUL 0x02 /* 000010 */ /* MIPS32 (?) TODO */ #define SPECIAL2_MSUB 0x04 /* 000100 */ /* MIPS32 (?) TODO */ #define SPECIAL2_MSUBU 0x05 /* 000001 */ /* MIPS32 (?) TODO */ #define SPECIAL2_CLZ 0x20 /* 100100 */ /* MIPS32 */ #define SPECIAL2_CLO 0x21 /* 100101 */ /* MIPS32 */ #define SPECIAL2_DCLZ 0x24 /* 100100 */ /* MIPS64 */ #define SPECIAL2_DCLO 0x25 /* 100101 */ /* MIPS64 */ #define SPECIAL2_SDBBP 0x3f /* 111111 */ /* EJTAG (?) TODO */ /* MMI (R5900, TX79/C790) occupies the same opcode space as SPECIAL2: */ #define MMI_MADD 0x00 #define MMI_MADDU 0x01 #define MMI_PLZCW 0x04 #define MMI_MMI0 0x08 #define MMI0_PADDW 0x00 #define MMI0_PSUBW 0x01 #define MMI0_PCGTW 0x02 #define MMI0_PMAXW 0x03 #define MMI0_PADDH 0x04 #define MMI0_PSUBH 0x05 #define MMI0_PCGTH 0x06 #define MMI0_PMAXH 0x07 #define MMI0_PADDB 0x08 #define MMI0_PSUBB 0x09 #define MMI0_PCGTB 0x0a #define MMI0_PADDSW 0x10 #define MMI0_PSUBSW 0x11 #define MMI0_PEXTLW 0x12 #define MMI0_PPACW 0x13 #define MMI0_PADDSH 0x14 #define MMI0_PSUBSH 0x15 #define MMI0_PEXTLH 0x16 #define MMI0_PPACH 0x17 #define MMI0_PADDSB 0x18 #define MMI0_PSUBSB 0x19 #define MMI0_PEXTLB 0x1a #define MMI0_PPACB 0x1b #define MMI0_PEXT5 0x1e #define MMI0_PPAC5 0x1f #define MMI_MMI2 0x09 #define MMI2_PMADDW 0x00 #define MMI2_PSLLVW 0x02 #define MMI2_PSRLVW 0x03 #define MMI2_PMSUBW 0x04 #define MMI2_PMFHI 0x08 #define MMI2_PMFLO 0x09 #define MMI2_PINTH 0x0a #define MMI2_PMULTW 0x0c #define MMI2_PDIVW 0x0d #define MMI2_PCPYLD 0x0e #define MMI2_PMADDH 0x10 #define MMI2_PHMADH 0x11 #define MMI2_PAND 0x12 #define MMI2_PXOR 0x13 #define MMI2_PMSUBH 0x14 #define MMI2_PHMSBH 0x15 #define MMI2_PEXEH 0x1a #define MMI2_PREVH 0x1b #define MMI2_PMULTH 0x1c #define MMI2_PDIVBW 0x1d #define MMI2_PEXEW 0x1e #define MMI2_PROT3W 0x1f #define MMI_MFHI1 0x10 #define MMI_MTHI1 0x11 #define MMI_MFLO1 0x12 #define MMI_MTLO1 0x13 #define MMI_MULT1 0x18 #define MMI_MULTU1 0x19 #define MMI_DIV1 0x1a #define MMI_DIVU1 0x1b #define MMI_MADD1 0x20 #define MMI_MADDU1 0x21 #define MMI_MMI1 0x28 #define MMI1_PABSW 0x01 #define MMI1_PCEQW 0x02 #define MMI1_PMINW 0x03 #define MMI1_PADSBH 0x04 #define MMI1_PABSH 0x05 #define MMI1_PCEQH 0x06 #define MMI1_PMINH 0x07 #define MMI1_PCEQB 0x0a #define MMI1_PADDUW 0x10 #define MMI1_PSUBUW 0x11 #define MMI1_PEXTUW 0x12 #define MMI1_PADDUH 0x14 #define MMI1_PSUBUH 0x15 #define MMI1_PEXTUH 0x16 #define MMI1_PADDUB 0x18 #define MMI1_PSUBUB 0x19 #define MMI1_PEXTUB 0x1a #define MMI1_QFSRV 0x1b #define MMI_MMI3 0x29 #define MMI3_PMADDUW 0x00 #define MMI3_PSRAVW 0x03 #define MMI3_PMTHI 0x08 #define MMI3_PMTLO 0x09 #define MMI3_PINTEH 0x0a #define MMI3_PMULTUW 0x0c #define MMI3_PDIVUW 0x0d #define MMI3_PCPYUD 0x0e #define MMI3_POR 0x12 #define MMI3_PNOR 0x13 #define MMI3_PEXCH 0x1a #define MMI3_PCPYH 0x1b #define MMI3_PEXCW 0x1e #define MMI_PMFHL 0x30 #define MMI_PMTHL 0x31 #define MMI_PSLLH 0x34 #define MMI_PSRLH 0x36 #define MMI_PSRAH 0x37 #define MMI_PSLLW 0x3c #define MMI_PSRLW 0x3e #define MMI_PSRAW 0x3f /* JALX (TODO) 0x1d 011101 */ #define HI6_LQ_MDMX 0x1e /* 011110 */ /* lq on R5900, MDMX on others? */ /* TODO: MDMX opcodes */ #define HI6_SQ_SPECIAL3 0x1f /* 011111 */ /* sq on R5900, SPECIAL3 on MIPS32/64 rev 2 */ #define SPECIAL3_EXT 0x00 /* 000000 */ #define SPECIAL3_DEXTM 0x01 /* 000001 */ #define SPECIAL3_DEXTU 0x02 /* 000010 */ #define SPECIAL3_DEXT 0x03 /* 000011 */ #define SPECIAL3_INS 0x04 /* 000100 */ #define SPECIAL3_DINSM 0x05 /* 000101 */ #define SPECIAL3_DINSU 0x06 /* 000110 */ #define SPECIAL3_DINS 0x07 /* 000111 */ #define SPECIAL3_BSHFL 0x20 /* 100000 */ #define BSHFL_WSBH 0x002 /* 00000..00010 */ #define BSHFL_SEB 0x010 /* 00000..10000 */ #define BSHFL_SEH 0x018 /* 00000..11000 */ #define SPECIAL3_DBSHFL 0x24 /* 100100 */ #define BSHFL_DSBH 0x002 /* 00000..00010 */ #define BSHFL_DSHD 0x005 /* 00000..00101 */ #define SPECIAL3_RDHWR 0x3b /* 111011 */ #define HI6_LB 0x20 /* 100000 */ /* MIPS I */ #define HI6_LH 0x21 /* 100001 */ /* MIPS I */ #define HI6_LWL 0x22 /* 100010 */ /* MIPS I */ #define HI6_LW 0x23 /* 100011 */ /* MIPS I */ #define HI6_LBU 0x24 /* 100100 */ /* MIPS I */ #define HI6_LHU 0x25 /* 100101 */ /* MIPS I */ #define HI6_LWR 0x26 /* 100110 */ /* MIPS I */ #define HI6_LWU 0x27 /* 100111 */ /* MIPS III */ #define HI6_SB 0x28 /* 101000 */ /* MIPS I */ #define HI6_SH 0x29 /* 101001 */ /* MIPS I */ #define HI6_SWL 0x2a /* 101010 */ /* MIPS I */ #define HI6_SW 0x2b /* 101011 */ /* MIPS I */ #define HI6_SDL 0x2c /* 101100 */ /* MIPS III */ #define HI6_SDR 0x2d /* 101101 */ /* MIPS III */ #define HI6_SWR 0x2e /* 101110 */ /* MIPS I */ #define HI6_CACHE 0x2f /* 101111 */ /* ??? R4000 */ #define HI6_LL 0x30 /* 110000 */ /* MIPS II */ #define HI6_LWC1 0x31 /* 110001 */ /* MIPS I */ #define HI6_LWC2 0x32 /* 110010 */ /* MIPS I */ #define HI6_LWC3 0x33 /* 110011 */ /* MIPS I */ #define HI6_LLD 0x34 /* 110100 */ /* MIPS III */ #define HI6_LDC1 0x35 /* 110101 */ /* MIPS II */ #define HI6_LDC2 0x36 /* 110110 */ /* MIPS II */ #define HI6_LD 0x37 /* 110111 */ /* MIPS III */ #define HI6_SC 0x38 /* 111000 */ /* MIPS II */ #define HI6_SWC1 0x39 /* 111001 */ /* MIPS I */ #define HI6_SWC2 0x3a /* 111010 */ /* MIPS I */ #define HI6_SWC3 0x3b /* 111011 */ /* MIPS I */ #define HI6_SCD 0x3c /* 111100 */ /* MIPS III */ #define HI6_SDC1 0x3d /* 111101 */ /* MIPS II */ #define HI6_SDC2 0x3e /* 111110 */ /* MIPS II */ #define HI6_SD 0x3f /* 111111 */ /* MIPS III */ #endif /* OPCODES_MIPS_H */ gxemul-0.6.1/src/include/StateVariable.h000644 001750 001750 00000021020 13402411502 020331 0ustar00debugdebug000000 000000 #ifndef STATEVARIABLE_H #define STATEVARIABLE_H /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Note/TODO: This class could perhaps be rewritten in a nicer way by * using C++ templates. */ #include "misc.h" #include "SerializationContext.h" #include "UnitTest.h" class StateVariable; typedef map StateVariableMap; class CustomStateVariableHandler { public: CustomStateVariableHandler() { } virtual ~CustomStateVariableHandler() { } virtual void Serialize(ostream& ss) const = 0; virtual bool Deserialize(const string& value) = 0; virtual void CopyValueFrom(CustomStateVariableHandler* other) = 0; }; /** * \brief StateVariables make up the persistent state of Component objects. * * A %StateVariable has a name, and a value. */ class StateVariable : public UnitTestable { public: /** * \brief An enumeration of the possible types of a %StateVariable. */ enum Type { String = 0, Bool, Double, UInt8, UInt16, UInt32, UInt64, SInt8, SInt16, SInt32, SInt64, Custom }; private: /* Disable construction without name. */ StateVariable(); public: /** * \brief Constructor for a String StateVariable. * * @param name The variable's name. * @param ptrToString A pointer to the string which this * variable refers to. */ StateVariable(const string& name, string* ptrToString); /** * \brief Constructor for a Bool StateVariable. * * @param name The variable's name. * @param ptrToVar A pointer to the variable. */ StateVariable(const string& name, bool* ptrToVar); /** * \brief Constructor for a Double StateVariable. * * @param name The variable's name. * @param ptrToVar A pointer to the variable. */ StateVariable(const string& name, double* ptrToVar); /** * \brief Constructor for a UInt8 StateVariable. * * @param name The variable's name. * @param ptrToVar A pointer to the variable. */ StateVariable(const string& name, uint8_t* ptrToVar); /** * \brief Constructor for a UInt16 StateVariable. * * @param name The variable's name. * @param ptrToVar A pointer to the variable. */ StateVariable(const string& name, uint16_t* ptrToVar); /** * \brief Constructor for a UInt32 StateVariable. * * @param name The variable's name. * @param ptrToVar A pointer to the variable. */ StateVariable(const string& name, uint32_t* ptrToVar); /** * \brief Constructor for a UInt64 StateVariable. * * @param name The variable's name. * @param ptrToVar A pointer to the variable. */ StateVariable(const string& name, uint64_t* ptrToVar); /** * \brief Constructor for a SInt8 StateVariable. * * @param name The variable's name. * @param ptrToVar A pointer to the variable. */ StateVariable(const string& name, int8_t* ptrToVar); /** * \brief Constructor for a SInt16 StateVariable. * * @param name The variable's name. * @param ptrToVar A pointer to the variable. */ StateVariable(const string& name, int16_t* ptrToVar); /** * \brief Constructor for a SInt32 StateVariable. * * @param name The variable's name. * @param ptrToVar A pointer to the variable. */ StateVariable(const string& name, int32_t* ptrToVar); /** * \brief Constructor for a SInt64 StateVariable. * * @param name The variable's name. * @param ptrToVar A pointer to the variable. */ StateVariable(const string& name, int64_t* ptrToVar); /** * \brief Constructor for a custom StateVariable. * * @param name The variable's name. * @param ptrToHandler A pointer to the custom handler. */ StateVariable(const string& name, CustomStateVariableHandler* ptrToHandler); /** * \brief Gets the name of the variable. * * @return The name of the variable. */ const string& GetName() const; /** * \brief Gets the type of the variable. * * @return The type of the variable. */ enum Type GetType() const; /** * \brief Serializes the variable value into a string. * * Strings are serialized as quoted strings; most other types without * quoting. * * @param ss A stream where the variable value will be appended. */ void SerializeValue(ostream& ss) const; /** * \brief Serializes the variable into a string. * * @param ss A stream where the variable (type, name, and value) * will be appended. * @param context Serialization context (tab indentation, etc). */ void Serialize(ostream& ss, SerializationContext& context) const; /** * \brief Copy the value from another variable into this variable. * * @param otherVariable The variable to copy from. * @return True if the value was copied, false if copying was not * possible (i.e. the types differed). */ bool CopyValueFrom(const StateVariable& otherVariable); /** * \brief Returns the variable as a readable string. * * @return A string, representing the variable's value. */ string ToString() const; /** * \brief Returns the variable as an unsignedinteger value. * * @return A uint64_t, representing the variable's value. */ uint64_t ToInteger() const; /** * \brief Returns the variable as a double value. * * @return A double, representing the variable's value. */ double ToDouble() const; /** * \brief Set the variable's value, using a string expression. * * Note that the expression may be a single value (e.g. 42), * or something more complex (e.g. 123 + cpu0.pc * 4). * * When setting string values, the expression should be a C-style * escaped string, e.g.: "This is a string with a \" inside * it." * * @param expression The new value. * @return True if the value was set, false if e.g. there was a * parse error. */ bool SetValue(const string& expression); /** * \brief Set the variable's value to an integer. * * @param value The new value. * @return True if the value was set, false if e.g. there was a * type error. */ bool SetValue(uint64_t value); /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); private: /** * \brief Evaluates an expression, and returns it as a single value. * * @param expression The expression to evaluate. * @param success Set to true if the expression could be evaluated, * false otherwise. * @return A string representation of the evaluated expression. * (Only valid if success was set to true.) */ string EvaluateExpression(const string& expression, bool &success) const; /** * \brief Returns the type of the variable, as a string. * * @return A string representation of the variable's type. */ string GetTypeString() const; /** * \brief Returns a string representation of the variable's value. * * @return A string representation of the variable's value. */ string ValueToString() const; private: string m_name; enum Type m_type; union { string* pstr; bool* pbool; double* pdouble; uint8_t* puint8; uint16_t* puint16; uint32_t* puint32; uint64_t* puint64; int8_t* psint8; int16_t* psint16; int32_t* psint32; int64_t* psint64; CustomStateVariableHandler *phandler; } m_value; }; #endif // STATEVARIABLE_H gxemul-0.6.1/src/include/UnitTest.h000644 001750 001750 00000015674 13402411502 017404 0ustar00debugdebug000000 000000 #ifndef UNITTEST_H #define UNITTEST_H /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include /** * \brief An exception thrown by unit test cases that fail. */ class UnitTestFailedException : public std::exception { public: UnitTestFailedException(const string& strMessage) : m_strMessage(strMessage) { } virtual ~UnitTestFailedException() throw () { } /** * \brief Retrieves the error message associated with the exception. * * @return a const reference to the error message string */ const string& GetMessage() const { return m_strMessage; } private: string m_strMessage; }; /** * \brief Base class for unit testable classes. * * A class which inherits from the UnitTestable class exposes a function, * RunUnitTests(int&, int&), which runs unit tests, and returns the number * of failed test cases. */ class UnitTestable { public: /** * \brief Runs unit test cases. * * @param nSucceeded A reference to a variable which keeps count * of the number of succeeded test cases. * @param nFailures A reference to a variable which keeps count * of the number of failed test cases. */ static void RunUnitTests(int& nSucceeded, int& nFailures); }; /** * \brief A collection of helper functions, for writing simple unit tests. */ class UnitTest { public: /** * \brief Runs all unit tests in %GXemul. * * If WITHUNITTESTS was not defined in config.h, nothing is tested, * and zero is returned. * * Otherwise, unit tests for all classes that the configure * script detected as using UNITTESTS(classname) are executed. * * If a test fails, the UNITTEST(testname) macro in the unit testing * framework takes care of outputting a line identifying that test to * std::cerr. * * @return zero if no unit tests failed, 1 otherwise. */ static int RunTests(); /*******************************************************************/ /* Helper functions, used by unit test cases */ /*******************************************************************/ /** * \brief Asserts that a boolean condition is correct. * * If the condition is not true, then Fail is called with the failure * message. * * The failure message can be something like "expected xyz", * or "the list should be empty at this point". * * @param strFailMessage failure message to print to std::cerr * @param condition The result of some operation, which should be true. */ static void Assert(const string& strFailMessage, bool condition); /** * \brief Asserts that two uint64_t values are equal. * * If the values are not equal, Fail is called with the failure message. * * The failure message can be something like "expected xyz", * or "the list should be empty at this point". * * @param strFailMessage Failure message to print to std::cerr. * @param actualValue The actual value. * @param expectedValue The expected value. */ static void Assert(const string& strFailMessage, uint64_t actualValue, uint64_t expectedValue); /** * \brief Asserts that two string values are equal. * * If the values are not equal, Fail is called with the failure message. * * The failure message can be something like "expected xyz", * or "the list should be empty at this point". * * @param strFailMessage Failure message to print to std::cerr. * @param actualValue The actual value. * @param expectedValue The expected value. */ static void Assert(const string& strFailMessage, const string& actualValue, const string& expectedValue); /** * \brief Fails a unit test unconditionally, by throwing a * UnitTestFailedException. * * @param strMessage failure message */ static void Fail(const string& strMessage); }; #ifdef WITHUNITTESTS #include /** * \brief Helper for unit test case execution. * * The main purpose, appart from making the code look more compact, * of having a macro for this is that the configure script finds * all .cc files that use this macro, and generates lists of header files * to include and lists of RunUnitTests functions to call. These are then * included and run from UnitTest::RunTests. * * See the comment for UNITTEST for details on how to use it. */ #define UNITTESTS(class) \ void class::RunUnitTests(int& nSucceeded, int& nFailures) /** * \brief Helper for unit test case execution. * * For each test case that throws a UnitTestFailedException, the number * of failures is increased. For test cases that don't fail, the number * of successful test cases is increased instead. * * Usage: (usually at the end of a class implementation file)
 *	\#ifdef WITHUNITTESTS
 *
 *	static void MyClass::Test_MyClass_SomeTest()
 *	{
 *		UnitTest::Assert("expected blah blah", bool_condition);
 *		... more asserts here ...
 *	}
 *
 *	...
 *
 *	UNITTESTS(MyClass)
 *	{
 *		UNITTEST(Test_MyClass_SomeTest);
 *		UNITTEST(Test_MyClass_AnotherTest);
 *		... more test cases here ...
 *	}
 *
 *	\#endif // WITHUNITTESTS
* * Note that MyClass (in the example above) should inherit from the * UnitTestable class. */ #define UNITTEST(functionname) try { \ std::cout << "### " #functionname "\n"; \ (functionname)(); \ ++ (nSucceeded); \ } catch (UnitTestFailedException& ex) { \ std::cout.flush(); \ std::cerr << "\n### " #functionname " (" __FILE__ " line " \ << __LINE__ << ") failed!\n" \ " > " << ex.GetMessage() << "\n"; \ std::cerr.flush(); \ ++ (nFailures); \ } #endif #endif // UNITTEST_H gxemul-0.6.1/src/include/CommandInterpreter.h000644 001750 001750 00000020754 13402411502 021422 0ustar00debugdebug000000 000000 #ifndef COMMANDINTERPRETER_H #define COMMANDINTERPRETER_H /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" class GXemul; /** * \brief An interactive command interpreter, which run Commands. * * A command interpreter can execute commands in the form of complete strings, * or it can be given one character (keypress) at a time to build up a command. * When given individual keypresses, the command interpreter echoes back * what is to be printed. It also supports TAB completion. */ class CommandInterpreter : public UnitTestable { public: /** * \brief Constructs a %CommandInterpreter. * * @param owner the GXemul instance that owns the %CommandInterpreter */ CommandInterpreter(GXemul* owner); /** * \brief Adds a character (keypress) to the current command buffer. * * Most normal keys are added at the end of the buffer. Some exceptions * are: *
    *
  • nul char: does not change the input line buffer, * but forces it to be visually redrawn/updated *
  • backspace: removes the last character (if any) *
  • tab: attempts TAB completion of the last word *
  • newline or cr: calls RunCommand, and then clears * the current buffer *
  • escape: special handling *
* * @param key the character/key to add * @return true if this was a complete command line (i.e. the key * was a newline), false otherwise */ bool AddKey(stringchar key); /** * \brief Clears the current command buffer. */ void ClearCurrentCommandBuffer(); /** * \brief Re-displays the current command buffer. * * Useful e.g. when running in text console mode, and the user has * pressed CTRL-Z. When returning to %GXemul, the current command * buffer can be showed again by calling this function. */ void ReshowCurrentCommandBuffer(); /** * \brief Runs a command, given as a string. * * The return value from the function is true if the command was run. * However, the command may run and fail, and that's what pSuccess is * for. * * @param command the command to run * @param pSuccess a pointer to a bool, which (if pSuccess is non-NULL) * will be set to whether the command succeeded or not. * @return true if the command was run, false if the command was * not known */ bool RunCommand(const string& command, bool* pSuccess = NULL); /** * \brief Retrieves the current command buffer. * * @return a string representing the current command buffer */ const string& GetCurrentCommandBuffer() const; /** * \brief Adds a new Command to the command interpreter. * * @param command A reference counter pointer to the Command. */ void AddCommand(refcount_ptr command); /** * \brief Gets a collection of all commands. * * @return A const reference to the collection of commands. */ const Commands& GetCommands() const; /** * \brief Adds a command line to the command history. * * If the command is empty, or the same as the last command in the * command history, it is ignored. * * The command history buffer only holds a small fixed number of * entries. * * @param command The command line to add to the command history. * @return The next insert position in the command history. Useful * for unit testing purposes; should otherwise be ignored. */ int AddLineToCommandHistory(const string& command); /** * \brief Retrieves a line from the command history. * * @param nStepsBack The number of steps back into the history. 0 * means return an empty line, 1 means the last history line, * 2 means the second last, and so on. * @return The line from the history, or an empty string if * nStepsBack was zero. */ string GetHistoryLine(int nStepsBack) const; private: /** * \brief Internal helper which clears a line by outputting spaces. */ void ClearCurrentInputLineVisually(); /** * \brief Completes the word at the current position in the input line. * * @param commandString A reference to the string to * tab-complete. * @param cursorPosition A refernce to a size_t, which * indicates the current cursor position within the string. * @param visibleShowAvailable True if available words should be * echoed back via the UI. * @return True if there was a single match, false otherwise. */ bool TabComplete(string& commandString, size_t& cursorPosition, bool visibleShowAvailable = false); /** * \brief Tab-completes; takes optional method or state variable * name into account. * * Strings such as "cpu." and "cpu.u" should e.g. be expanded to * "root.machine0.mainbus0.cpu." and * "root.machine0.mainbus0.cpu.unassemble", respectively. * * @param commandString A reference to the string to * tab-complete. * @param cursorPosition A refernce to a size_t, which * indicates the current cursor position within the string. * @param visibleShowAvailable True if available words should be * echoed back via the UI. * @return True if there was a single match, false otherwise. */ bool TabCompleteWithSubname(string& commandString, size_t& cursorPosition, bool visibleShowAvailable = false); /** * \brief Runs a method on a Component. * * Note: The componentPathAndMethod argument may contain an optional * ".method" suffix. The part before the method may need to be * tab-completed. * * Some examples of componentPathAndMethod: *
    *
  • cpu *
  • cpu.u *
  • cpu.unassemble *
  • root.machine0.mainbus0.cpu *
  • root.machine0.mainbus0.cpu0 *
  • root.machine0.mainbus0.cpu.u *
  • root.machine0.mainbus0.cpu0.unassemble *
* * If the method name is missing, a default method will be executed. * * @param componentPathAndMethod The path to the component, plus a * possible ".method" suffix. * @param arguments A vector of string arguments. * @return True if a component method was executed, false otherwise. */ bool RunComponentMethod(const string& componentPathAndMethod, const vector& arguments); /** * \brief Prints a list of available words (for tab completion). * * @param words A vector of all available words. */ void ShowAvailableWords(const vector& words); void VariableAssignment(const string& componentPath, const string& variableName, const string& expression); /********************************************************************/ public: static void RunUnitTests(int& nSucceeded, int& nFailures); private: // Pointer to the owning GXemul instance: GXemul* m_GXemul; // A collection of all available commands that can be executed: Commands m_commands; // The current input line: string m_currentCommandString; size_t m_currentCommandCursorPosition; bool m_inEscapeSequence; string m_escapeSequence; int m_historyEntryToCopyFrom; // Command history (usually accessed by cursor up/down keys): vector m_commandHistory; size_t m_commandHistoryInsertPosition; size_t m_commandHistoryMaxSize; // If non-empty, a command which may be reexecuted if an empty // command line is given: string m_mayBeReexecuted; }; #endif // COMMANDINTERPRETER_H gxemul-0.6.1/src/include/FileLoader_raw.h000644 001750 001750 00000004315 13402411502 020472 0ustar00debugdebug000000 000000 #ifndef FILELOADER_RAW_H #define FILELOADER_RAW_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Component.h" #include "FileLoaderImpl.h" #include "UnitTest.h" /** * \brief Raw binary loader (no specific format). * * TODO: Longer comment. */ class FileLoader_raw : public UnitTestable , public FileLoaderImpl { public: FileLoader_raw(const string& filename); ~FileLoader_raw() { } string DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const; bool LoadIntoComponent(refcount_ptr component, ostream& messages) const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // FILELOADER_RAW_H gxemul-0.6.1/src/include/AddressDataBus.h000644 001750 001750 00000012445 13402411502 020447 0ustar00debugdebug000000 000000 #ifndef ADDRESSDATABUS_H #define ADDRESSDATABUS_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" /** * \brief An interface for implementing components that read/write data via an * address bus. * * Any component which allows data to be read or written by using an address * as an index/offset should implement this interface. * * A typical example of a Component which implements the functions * of this class is the RAMComponent. */ class AddressDataBus { public: /** * \brief Constructs an AddressDataBus instance. */ AddressDataBus() { } virtual ~AddressDataBus() { } /** * \brief Place an address on the bus. * * \param address The address to select. */ virtual void AddressSelect(uint64_t address) = 0; /** * \brief Reads 8-bit data from the currently selected address. * * \param data A reference to a variable which will receive the data. * \param endianness Selects the endianness of the operation. Ignored * for 8-bit reads and writes. * \return True if the access was successful, false otherwise (e.g. * because of a timeout). */ virtual bool ReadData(uint8_t& data, Endianness endianness = BigEndian) = 0; /** * \brief Reads 16-bit data from the currently selected address. * * \param data A reference to a variable which will receive the data. * \param endianness Selects the endianness of the operation. * \return True if the access was successful, false otherwise (e.g. * because of a timeout). */ virtual bool ReadData(uint16_t& data, Endianness endianness) = 0; /** * \brief Reads 32-bit data from the currently selected address. * * \param data A reference to a variable which will receive the data. * \param endianness Selects the endianness of the operation. * \return True if the access was successful, false otherwise (e.g. * because of a timeout). */ virtual bool ReadData(uint32_t& data, Endianness endianness) = 0; /** * \brief Reads 64-bit data from the currently selected address. * * \param data A reference to a variable which will receive the data. * \param endianness Selects the endianness of the operation. * \return True if the access was successful, false otherwise (e.g. * because of a timeout). */ virtual bool ReadData(uint64_t& data, Endianness endianness) = 0; /** * \brief Writes 8-bit data to the currently selected address. * * \param data A reference to a variable which contains the data. * \param endianness Selects the endianness of the operation. Ignored * for 8-bit reads and writes. * \return True if the access was successful, false otherwise (e.g. * because of a timeout). */ virtual bool WriteData(const uint8_t& data, Endianness endianness = BigEndian) = 0; /** * \brief Writes 16-bit data to the currently selected address. * * \param data A reference to a variable which contains the data. * \param endianness Selects the endianness of the operation. * \return True if the access was successful, false otherwise (e.g. * because of a timeout). */ virtual bool WriteData(const uint16_t& data, Endianness endianness) = 0; /** * \brief Writes 32-bit data to the currently selected address. * * \param data A reference to a variable which contains the data. * \param endianness Selects the endianness of the operation. * \return True if the access was successful, false otherwise (e.g. * because of a timeout). */ virtual bool WriteData(const uint32_t& data, Endianness endianness) = 0; /** * \brief Writes 64-bit data to the currently selected address. * * \param data A reference to a variable which contains the data. * \param endianness Selects the endianness of the operation. * \return True if the access was successful, false otherwise (e.g. * because of a timeout). */ virtual bool WriteData(const uint64_t& data, Endianness endianness) = 0; }; #endif // ADDRESSDATABUS_H gxemul-0.6.1/src/include/SerializationContext.h000644 001750 001750 00000005377 13402411502 022006 0ustar00debugdebug000000 000000 #ifndef SERIALIZATIONCONTEXT_H #define SERIALIZATIONCONTEXT_H /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" /** * \brief A context used during serialization of objects. */ class SerializationContext { public: /** * \brief Constructs a default SerializationContext. */ SerializationContext() : m_indentation(0) { } /** * \brief Gets the indentation level of the context. * * @return the indentation level */ int GetIndentation() const { return m_indentation; } /** * \brief Sets the indentation level. * * @param indentation The new indentation level. */ void SetIndentation(int indentation) { m_indentation = indentation; } /** * \brief Constructs a SerializationContext which is indented (1 * step) compared to the current context. * * @return An indented context. */ SerializationContext Indented() { SerializationContext newContext; newContext.SetIndentation(GetIndentation() + 1); return newContext; } /** * \brief Generates a string of Tab characters, based on the * indentation level. * * @return a string of tab characters */ string Tabs() const { string retValue; for (int i=0; i>SH_INSTR_ALIGNMENT_SHIFT) \ & (SH_IC_ENTRIES_PER_PAGE-1)) #define SH_ADDR_TO_PAGENR(a) ((a) >> (SH_IC_ENTRIES_SHIFT \ + SH_INSTR_ALIGNMENT_SHIFT)) DYNTRANS_MISC_DECLARATIONS(sh,SH,uint32_t) #define SH_MAX_VPH_TLB_ENTRIES 128 #define SH_N_GPRS 16 #define SH_N_GPRS_BANKED 8 #define SH_N_FPRS 16 #define SH_N_ITLB_ENTRIES 4 #define SH_N_UTLB_ENTRIES 64 /* An instruction with an invalid encoding; used for software emulation of PROM calls within GXemul: */ #define SH_INVALID_INSTR 0x00fb struct sh_cpu { struct sh_cpu_type_def cpu_type; /* General Purpose Registers: */ uint32_t r[SH_N_GPRS]; uint32_t r_bank[SH_N_GPRS_BANKED]; /* Floating-Point Registers: */ uint32_t fr[SH_N_FPRS]; uint32_t xf[SH_N_FPRS]; /* "Other bank." */ uint32_t mach; /* Multiply-Accumulate High */ uint32_t macl; /* Multiply-Accumulate Low */ uint32_t pr; /* Procedure Register */ uint32_t fpscr; /* Floating-point Status/Control */ uint32_t fpul; /* Floating-point Communication Reg */ uint32_t sr; /* Status Register */ uint32_t ssr; /* Saved Status Register */ uint32_t spc; /* Saved PC */ uint32_t gbr; /* Global Base Register */ uint32_t vbr; /* Vector Base Register */ uint32_t sgr; /* Saved General Register */ uint32_t dbr; /* Debug Base Register */ /* Cache control: */ uint32_t ccr; /* Cache Control Register */ uint32_t qacr0; /* Queue Address Control Register 0 */ uint32_t qacr1; /* Queue Address Control Register 1 */ /* MMU/TLB registers: */ uint32_t pteh; /* Page Table Entry High */ uint32_t ptel; /* Page Table Entry Low */ uint32_t ptea; /* Page Table Entry A */ uint32_t ttb; /* Translation Table Base */ uint32_t tea; /* TLB Exception Address Register */ uint32_t mmucr; /* MMU Control Register */ uint32_t itlb_hi[SH_N_ITLB_ENTRIES]; uint32_t itlb_lo[SH_N_ITLB_ENTRIES]; uint32_t utlb_hi[SH_N_UTLB_ENTRIES]; uint32_t utlb_lo[SH_N_UTLB_ENTRIES]; /* Exception handling: */ uint32_t tra; /* TRAPA Exception Register */ uint32_t expevt; /* Exception Event Register */ uint32_t intevt; /* Interrupt Event Register */ /* Interrupt controller: */ uint16_t intc_ipra; /* Interrupt Priority Registers */ uint16_t intc_iprb; uint16_t intc_iprc; uint16_t intc_iprd; uint32_t intc_intpri00; uint32_t intc_intpri04; uint32_t intc_intpri08; uint32_t intc_intpri0c; uint32_t intc_intreq00; uint32_t intc_intreq04; uint32_t intc_intmsk00; uint32_t intc_intmsk04; /* Cached and calculated values: */ uint8_t int_prio_and_pending[0x1000 / 0x20]; int16_t int_to_assert; /* Calculated int to assert */ unsigned int int_level; /* Calculated int level */ /* Timer/clock functionality: */ int pclock; /* DMA Controller: (4 channels) */ uint32_t dmac_sar[N_SH4_DMA_CHANNELS]; uint32_t dmac_dar[N_SH4_DMA_CHANNELS]; uint32_t dmac_tcr[N_SH4_DMA_CHANNELS]; uint32_t dmac_chcr[N_SH4_DMA_CHANNELS]; uint32_t dmaor; /* DMA operation register */ /* PCI controller: */ struct pci_data *pcic_pcibus; /* * Instruction translation cache and Virtual->Physical->Host * address translation: */ DYNTRANS_ITC(sh) VPH_TLBS(sh,SH) VPH32(sh,SH) }; /* Status register bits: */ #define SH_SR_T 0x00000001 /* True/false */ #define SH_SR_S 0x00000002 /* Saturation */ #define SH_SR_IMASK 0x000000f0 /* Interrupt mask */ #define SH_SR_IMASK_SHIFT 4 #define SH_SR_Q 0x00000100 /* State for Divide Step */ #define SH_SR_M 0x00000200 /* State for Divide Step */ #define SH_SR_FD 0x00008000 /* FPU Disable */ #define SH_SR_BL 0x10000000 /* Exception/Interrupt Block */ #define SH_SR_RB 0x20000000 /* Register Bank 0/1 */ #define SH_SR_MD 0x40000000 /* Privileged Mode */ /* Floating-point status/control register bits: */ #define SH_FPSCR_RM_MASK 0x00000003 /* Rounding Mode */ #define SH_FPSCR_RM_NEAREST 0x0 /* Round to nearest */ #define SH_FPSCR_RM_ZERO 0x1 /* Round to zero */ #define SH_FPSCR_INEXACT 0x00000004 /* Inexact exception */ #define SH_FPSCR_UNDERFLOW 0x00000008 /* Underflow exception */ #define SH_FPSCR_OVERFLOW 0x00000010 /* Overflow exception */ #define SH_FPSCR_DIV_BY_ZERO 0x00000020 /* Div by zero exception */ #define SH_FPSCR_INVALID 0x00000040 /* Invalid exception */ #define SH_FPSCR_EN_INEXACT 0x00000080 /* Inexact enable */ #define SH_FPSCR_EN_UNDERFLOW 0x00000100 /* Underflow enable */ #define SH_FPSCR_EN_OVERFLOW 0x00000200 /* Overflow enable */ #define SH_FPSCR_EN_DIV_BY_ZERO 0x00000400 /* Div by zero enable */ #define SH_FPSCR_EN_INVALID 0x00000800 /* Invalid enable */ #define SH_FPSCR_CAUSE_INEXACT 0x00001000 /* Cause Inexact */ #define SH_FPSCR_CAUSE_UNDERFLOW 0x00002000 /* Cause Underflow */ #define SH_FPSCR_CAUSE_OVERFLOW 0x00004000 /* Cause Overflow */ #define SH_FPSCR_CAUSE_DIVBY0 0x00008000 /* Cause Div by 0 */ #define SH_FPSCR_CAUSE_INVALID 0x00010000 /* Cause Invalid */ #define SH_FPSCR_CAUSE_ERROR 0x00020000 /* Cause Error */ #define SH_FPSCR_DN_ZERO 0x00040000 /* Denormalization Mode */ #define SH_FPSCR_PR 0x00080000 /* Double-Precision Mode */ #define SH_FPSCR_SZ 0x00100000 /* Double-Precision Size */ #define SH_FPSCR_FR 0x00200000 /* Register Bank Select */ /* int_prio_and_pending bits: */ #define SH_INT_ASSERTED 0x10 #define SH_INT_PRIO_MASK 0x0f /* cpu_sh.c: */ void sh_cpu_interrupt_assert(struct interrupt *interrupt); void sh_cpu_interrupt_deassert(struct interrupt *interrupt); int sh_cpu_instruction_has_delayslot(struct cpu *cpu, unsigned char *ib); int sh_run_instr(struct cpu *cpu); void sh_update_translation_table(struct cpu *cpu, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page); void sh_invalidate_translation_caches(struct cpu *cpu, uint64_t, int); void sh_invalidate_code_translation(struct cpu *cpu, uint64_t, int); void sh_init_64bit_dummy_tables(struct cpu *cpu); int sh_memory_rw(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags); int sh_cpu_family_init(struct cpu_family *); void sh_update_interrupt_priorities(struct cpu *cpu); void sh_update_sr(struct cpu *cpu, uint32_t new_sr); void sh_exception(struct cpu *cpu, int expevt, int intevt, uint32_t vaddr); /* memory_sh.c: */ int sh_translate_v2p(struct cpu *cpu, uint64_t vaddr, uint64_t *return_addr, int flags); #endif /* CPU_SH_H */ gxemul-0.6.1/src/include/x11.h000644 001750 001750 00000006256 13402411502 016232 0ustar00debugdebug000000 000000 #ifndef X11_H #define X11_H /* * Copyright (C) 2003-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Headerfile for src/x11.c. */ #include "misc.h" struct emul; #ifdef WITH_X11 #include #endif /* x11.c: */ #define N_GRAYCOLORS 16 #define CURSOR_COLOR_TRANSPARENT -1 #define CURSOR_COLOR_INVERT -2 #define CURSOR_MAXY 64 #define CURSOR_MAXX 64 /* Framebuffer windows: */ struct fb_window { int fb_number; #ifdef WITH_X11 /* x11_fb_winxsize > 0 for a valid fb_window */ int x11_fb_winxsize, x11_fb_winysize; int scaledown; Display *x11_display; int x11_screen; int x11_screen_depth; unsigned long fg_color; unsigned long bg_color; XColor x11_graycolor[N_GRAYCOLORS]; Window x11_fb_window; GC x11_fb_gc; XImage *fb_ximage; unsigned char *ximage_data; /* -1 means transparent, 0 and up are grayscales */ int cursor_pixels[CURSOR_MAXY][CURSOR_MAXX]; int cursor_x; int cursor_y; int cursor_xsize; int cursor_ysize; int cursor_on; int OLD_cursor_x; int OLD_cursor_y; int OLD_cursor_xsize; int OLD_cursor_ysize; int OLD_cursor_on; /* Host's X11 cursor: */ Cursor host_cursor; Pixmap host_cursor_pixmap; #endif }; void x11_redraw_cursor(struct machine *, int); void x11_redraw(struct machine *, int); void x11_putpixel_fb(struct machine *, int, int x, int y, int color); #ifdef WITH_X11 void x11_putimage_fb(struct machine *, int); #endif void x11_init(struct machine *); void x11_fb_resize(struct fb_window *win, int new_xsize, int new_ysize); void x11_set_standard_properties(struct fb_window *fb_window, char *name); struct fb_window *x11_fb_init(int xsize, int ysize, char *name, int scaledown, struct machine *); void x11_check_event(struct emul *emul); #endif /* X11_H */ gxemul-0.6.1/src/include/machine_pmax.h000644 001750 001750 00000003337 13402411502 020247 0ustar00debugdebug000000 000000 #ifndef MACHINE_PMAX_H #define MACHINE_PMAX_H /* * Copyright (C) 2006-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Machine-specific data for MIPS-based DECstation machines. */ #include "misc.h" struct machine_pmax { struct dec_memmap *memmap; }; #endif /* MACHINE_PMAX_H */ gxemul-0.6.1/src/include/wdc.h000644 001750 001750 00000003447 13402411502 016375 0ustar00debugdebug000000 000000 #ifndef WDC_H #define WDC_H /* * Copyright (C) 2006-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * NOTE: The "wdc" device is normally added using the device_add functionality. * This include file is only necessary to access additional wdc routines. */ struct wdc_data; int wdc_set_io_enabled(struct wdc_data *d, int io_enabled); #endif /* WDC_H */ gxemul-0.6.1/src/include/vga.h000644 001750 001750 00000006716 13402411502 016377 0ustar00debugdebug000000 000000 #ifndef GXEMUL_VGA_H #define GXEMUL_VGA_H /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * VGA register definitions, used by src/devices/dev_vga.c. */ /* * Registers (offset from 0x3C0): */ #define VGA_ATTRIBUTE_ADDR 0 /* R/W */ #define VGA_ATTRIBUTE_DATA_WRITE 0 /* W */ #define VGA_ATTRIBUTE_DATA_READ 1 /* R */ #define VGA_INPUT_STATUS_0 2 /* R */ #define VGA_MISC_OUTPUT_W 2 /* W */ #define VGA_MISC_OUTPUT_CS360 0x04 #define VGA_MISC_OUTPUT_REN 0x02 #define VGA_MISC_OUTPUT_IOAS 0x01 #define VGA_SEQUENCER_ADDR 4 /* R/W */ #define VGA_SEQUENCER_DATA 5 /* R/W */ #define VGA_SEQ_RESET 0 #define VGA_SEQ_CLOCKING_MODE 1 #define VGA_SEQ_MAP_MASK 2 #define VGA_SEQ_CHARACTER_MAP_SELECT 3 #define VGA_SEQ_SEQUENCER_MEMORY_MODE 4 #define VGA_DAC_STATE 7 /* R */ #define VGA_DAC_ADDR_READ 7 /* W */ #define VGA_DAC_ADDR_WRITE 8 /* W */ #define VGA_DAC_DATA 9 /* R/W */ #define VGA_FEATURE_CONTROL 0xA /* R/W? */ #define VGA_MISC_OUTPUT_R 0xC /* R */ #define VGA_GRAPHCONTR_ADDR 0xE /* R/W */ #define VGA_GRAPHCONTR_DATA 0xF /* R/W */ #define VGA_GRAPHCONTR_SETRESET 0 #define VGA_GRAPHCONTR_ENABLE 1 #define VGA_GRAPHCONTR_COLORCMP 2 #define VGA_GRAPHCONTR_DATAROTATE 3 #define VGA_GRAPHCONTR_READMAPSELECT 4 #define VGA_GRAPHCONTR_GRAPHICSMODE 5 #define VGA_GRAPHCONTR_MISC 6 #define VGA_GRAPHCONTR_COLORDONTCARE 7 #define VGA_GRAPHCONTR_MASK 8 #define VGA_CRTC_ADDR 0x14 /* R/W */ #define VGA_CRTC_DATA 0x15 /* R/W */ #define VGA_CRTC_CURSOR_SCANLINE_START 0x0a #define VGA_CRTC_CURSOR_SCANLINE_END 0x0b #define VGA_CRTC_START_ADDR_HIGH 0x0c #define VGA_CRTC_START_ADDR_LOW 0x0d #define VGA_CRTC_CURSOR_LOCATION_HIGH 0x0e #define VGA_CRTC_CURSOR_LOCATION_LOW 0x0f #define VGA_INPUT_STATUS_1 0x1A /* R */ #define VGA_IS1_DISPLAY_VRETRACE 0x08 #define VGA_IS1_DISPLAY_DISPLAY_DISABLE 0x01 #endif /* GXEMUL_VGA_H */ gxemul-0.6.1/src/include/cop0.h000644 001750 001750 00000021346 13402411502 016457 0ustar00debugdebug000000 000000 #ifndef COP0_H #define COP0_H /* * Copyright (C) 2003-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Misc. definitions for MIPS coprocessor 0. */ /* TODO: Coproc registers are actually CPU dependent, so an R4000 has other bits/registers than an R3000... TODO 2: CPUs like the R10000 are probably even a bit more different. */ /* Coprocessor 0's registers' names: (max 8 characters long) */ #define COP0_NAMES { \ "index", "random", "entrylo0", "entrylo1", \ "context", "pagemask", "wired", "reserv7", \ "badvaddr", "count", "entryhi", "compare", \ "status", "cause", "epc", "prid", \ "config", "lladdr", "watchlo", "watchhi", \ "xcontext", "reserv21", "reserv22", "debug", \ "depc", "perfcnt", "errctl", "cacheerr", \ "tagdatlo", "tagdathi", "errorepc", "desave" } #define COP0_INDEX 0 #define INDEX_P 0x80000000UL /* Probe failure bit. Set by tlbp */ #define INDEX_MASK 0x3f #define R2K3K_INDEX_P 0x80000000UL #define R2K3K_INDEX_MASK 0x3f00 #define R2K3K_INDEX_SHIFT 8 #define COP0_RANDOM 1 #define RANDOM_MASK 0x3f #define R2K3K_RANDOM_MASK 0x3f00 #define R2K3K_RANDOM_SHIFT 8 #define COP0_ENTRYLO0 2 #define COP0_ENTRYLO1 3 /* R4000 ENTRYLO: */ #define ENTRYLO_PFN_MASK 0x3fffffc0 #define ENTRYLO_PFN_SHIFT 6 #define ENTRYLO_C_MASK 0x00000038 /* Coherency attribute */ #define ENTRYLO_C_SHIFT 3 #define ENTRYLO_D 0x04 /* Dirty bit */ #define ENTRYLO_V 0x02 /* Valid bit */ #define ENTRYLO_G 0x01 /* Global bit */ /* R2000/R3000 ENTRYLO: */ #define R2K3K_ENTRYLO_PFN_MASK 0xfffff000UL #define R2K3K_ENTRYLO_PFN_SHIFT 12 #define R2K3K_ENTRYLO_N 0x800 #define R2K3K_ENTRYLO_D 0x400 #define R2K3K_ENTRYLO_V 0x200 #define R2K3K_ENTRYLO_G 0x100 #define COP0_CONTEXT 4 #define CONTEXT_BADVPN2_MASK 0x007ffff0 #define CONTEXT_BADVPN2_MASK_R4100 0x01fffff0 #define CONTEXT_BADVPN2_SHIFT 4 #define R2K3K_CONTEXT_BADVPN_MASK 0x001ffffc #define R2K3K_CONTEXT_BADVPN_SHIFT 2 #define COP0_PAGEMASK 5 #define PAGEMASK_MASK 0x01ffe000 #define PAGEMASK_SHIFT 13 #define PAGEMASK_MASK_R4100 0x0007f800 /* TODO: At least VR4131, */ /* how about others? */ #define PAGEMASK_SHIFT_R4100 11 #define COP0_WIRED 6 #define COP0_RESERV7 7 #define COP0_BADVADDR 8 #define COP0_COUNT 9 #define COP0_ENTRYHI 10 /* R4000 ENTRYHI: */ #define ENTRYHI_R_MASK 0xc000000000000000ULL #define ENTRYHI_R_XKPHYS 0x8000000000000000ULL #define ENTRYHI_R_SHIFT 62 #define ENTRYHI_VPN2_MASK_R10K 0x00000fffffffe000ULL #define ENTRYHI_VPN2_MASK 0x000000ffffffe000ULL #define ENTRYHI_VPN2_SHIFT 13 #define ENTRYHI_ASID 0xff #define TLB_G (1 << 12) /* R2000/R3000 ENTRYHI: */ #define R2K3K_ENTRYHI_VPN_MASK 0xfffff000UL #define R2K3K_ENTRYHI_VPN_SHIFT 12 #define R2K3K_ENTRYHI_ASID_MASK 0xfc0 #define R2K3K_ENTRYHI_ASID_SHIFT 6 #define COP0_COMPARE 11 #define COP0_STATUS 12 #define STATUS_CU_MASK 0xf0000000UL /* coprocessor usable bits */ #define STATUS_CU_SHIFT 28 #define STATUS_RP 0x08000000 /* reduced power */ #define STATUS_FR 0x04000000 /* 1=32 float regs, 0=16 */ #define STATUS_RE 0x02000000 /* reverse endian bit */ #define STATUS_BEV 0x00400000 /* boot exception vectors (?) */ /* STATUS_DS: TODO */ #define STATUS_IM_MASK 0xff00 #define STATUS_IM_SHIFT 8 #define STATUS_KX 0x80 #define STATUS_SX 0x40 #define STATUS_UX 0x20 #define STATUS_KSU_MASK 0x18 #define STATUS_KSU_SHIFT 3 #define STATUS_ERL 0x04 #define STATUS_EXL 0x02 #define STATUS_IE 0x01 #define R5900_STATUS_EDI 0x20000 /* EI/DI instruction enable */ #define R5900_STATUS_EIE 0x10000 /* Enable Interrupt Enable */ #define COP0_CAUSE 13 #define CAUSE_BD 0x80000000UL /* branch delay flag */ #define CAUSE_CE_MASK 0x30000000 /* which coprocessor */ #define CAUSE_CE_SHIFT 28 #define CAUSE_IV 0x00800000UL /* interrupt vector at offset 0x200 instead of 0x180 */ #define CAUSE_WP 0x00400000UL /* watch exception ... */ #define CAUSE_IP_MASK 0xff00 /* interrupt pending */ #define CAUSE_IP_SHIFT 8 #define CAUSE_EXCCODE_MASK 0x7c /* exception code */ #define R2K3K_CAUSE_EXCCODE_MASK 0x3c #define CAUSE_EXCCODE_SHIFT 2 #define COP0_EPC 14 #define COP0_PRID 15 #define COP0_CONFIG 16 #define COP0_LLADDR 17 #define COP0_WATCHLO 18 #define COP0_WATCHHI 19 #define COP0_XCONTEXT 20 #define XCONTEXT_R_MASK 0x180000000ULL #define XCONTEXT_R_SHIFT 31 #define XCONTEXT_BADVPN2_MASK 0x7ffffff0 #define XCONTEXT_BADVPN2_SHIFT 4 #define COP0_FRAMEMASK 21 /* R10000 */ #define COP0_RESERV22 22 #define COP0_DEBUG 23 #define COP0_DEPC 24 #define COP0_PERFCNT 25 #define COP0_ERRCTL 26 #define COP0_CACHEERR 27 #define COP0_TAGDATA_LO 28 #define COP0_TAGDATA_HI 29 #define COP0_ERROREPC 30 #define COP0_DESAVE 31 /* Coprocessor 1's registers: */ #define COP1_REVISION 0 #define COP1_REVISION_MIPS3D 0x80000 /* MIPS3D support */ #define COP1_REVISION_PS 0x40000 /* Paired-single support */ #define COP1_REVISION_DOUBLE 0x20000 /* double precision support */ #define COP1_REVISION_SINGLE 0x10000 /* single precision support */ #define COP1_CONTROLSTATUS 31 /* CP0's STATUS KSU values: */ #define KSU_KERNEL 0 #define KSU_SUPERVISOR 1 #define KSU_USER 2 #define EXCEPTION_NAMES { \ "INT", "MOD", "TLBL", "TLBS", "ADEL", "ADES", "IBE", "DBE", \ "SYS", "BP", "RI", "CPU", "OV", "TR", "VCEI", "FPE", \ "16?", "17?", "C2E", "19?", "20?", "21?", "MDMX", "WATCH", \ "MCHECK", "25?", "26?", "27?", "28?", "29?", "CACHEERR", "VCED" } /* CP0's CAUSE exception codes: */ #define EXCEPTION_INT 0 /* Interrupt */ #define EXCEPTION_MOD 1 /* TLB modification exception */ #define EXCEPTION_TLBL 2 /* TLB exception (load or instruction fetch) */ #define EXCEPTION_TLBS 3 /* TLB exception (store) */ #define EXCEPTION_ADEL 4 /* Address Error Exception (load/instr. fetch) */ #define EXCEPTION_ADES 5 /* Address Error Exception (store) */ #define EXCEPTION_IBE 6 /* Bus Error Exception (instruction fetch) */ #define EXCEPTION_DBE 7 /* Bus Error Exception (data: load or store) */ #define EXCEPTION_SYS 8 /* Syscall */ #define EXCEPTION_BP 9 /* Breakpoint */ #define EXCEPTION_RI 10 /* Reserved instruction */ #define EXCEPTION_CPU 11 /* CoProcessor Unusable */ #define EXCEPTION_OV 12 /* Arithmetic Overflow */ #define EXCEPTION_TR 13 /* Trap exception */ #define EXCEPTION_VCEI 14 /* Virtual Coherency Exception, Instruction */ #define EXCEPTION_FPE 15 /* Floating point exception */ /* 16..17: Available for "implementation dependent use" */ #define EXCEPTION_C2E 18 /* MIPS64 C2E (precise coprocessor 2 exception) */ /* 19..21: Reserved */ #define EXCEPTION_MDMX 22 /* MIPS64 MDMX unusable */ #define EXCEPTION_WATCH 23 /* Reference to WatchHi/WatchLo address */ #define EXCEPTION_MCHECK 24 /* MIPS64 Machine Check */ /* 25..29: Reserved */ #define EXCEPTION_CACHEERR 30 /* MIPS64 Cache Error */ #define EXCEPTION_VCED 31 /* Virtual Coherency Exception, Data */ #endif /* COP0_H */ gxemul-0.6.1/src/include/diskimage.h000644 001750 001750 00000013272 13402411502 017552 0ustar00debugdebug000000 000000 #ifndef DISKIMAGE_H #define DISKIMAGE_H /* * Copyright (C) 2003-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Generic disk image functions. (See diskimage.c for more info.) */ #include #include #include "misc.h" /* Diskimage types: */ #define DISKIMAGE_SCSI 1 #define DISKIMAGE_IDE 2 #define DISKIMAGE_FLOPPY 3 #define DISKIMAGE_TYPES { "(NONE)", "SCSI", "IDE", "FLOPPY" } /* 512 bytes per overlay block. Don't change this. */ #define OVERLAY_BLOCK_SIZE 512 struct diskimage_overlay { char *overlay_basename; FILE *f_data; FILE *f_bitmap; }; struct diskimage { struct diskimage *next; int type; /* DISKIMAGE_SCSI, etc */ int id; /* SCSI id */ /* Filename in host's file system: */ char *fname; FILE *f; /* Overlays: */ int nr_of_overlays; struct diskimage_overlay *overlays; int chs_override; int cylinders; int heads; int sectors_per_track; off_t total_size; int64_t override_base_offset; int logical_block_size; int writable; int is_a_cdrom; int is_boot_device; int is_a_tape; uint64_t tape_offset; int tape_filenr; int filemark; int rpms; int ncyls; }; /* Transfer command, sent from a SCSI controller device to a disk: */ struct scsi_transfer { struct scsi_transfer *next_free; /* These should be set by the SCSI controller before the call: */ unsigned char *msg_out; size_t msg_out_len; unsigned char *cmd; size_t cmd_len; /* data_out_len is set by the SCSI disk, if it needs data_out, which is then filled in during a second pass in the controller. */ unsigned char *data_out; size_t data_out_len; size_t data_out_offset; /* These should be set by the SCSI (disk) device before returning: */ unsigned char *data_in; size_t data_in_len; unsigned char *msg_in; size_t msg_in_len; unsigned char *status; size_t status_len; }; struct machine; /* diskimage_scsicmd.c: */ struct scsi_transfer *scsi_transfer_alloc(void); void scsi_transfer_free(struct scsi_transfer *); void scsi_transfer_allocbuf(size_t *lenp, unsigned char **pp, size_t want_len, int clearflag); int diskimage_scsicommand(struct cpu *cpu, int id, int type, struct scsi_transfer *); /* diskimage.c: */ int64_t diskimage_getsize(struct machine *machine, int id, int type); int64_t diskimage_get_baseoffset(struct machine *machine, int id, int type); void diskimage_set_baseoffset(struct machine *machine, int id, int type, int64_t offset); void diskimage_getchs(struct machine *machine, int id, int type, int *c, int *h, int *s); int diskimage__internal_access(struct diskimage *d, int writeflag, off_t offset, unsigned char *buf, size_t len); int diskimage_access(struct machine *machine, int id, int type, int writeflag, off_t offset, unsigned char *buf, size_t len); void diskimage_add_overlay(struct diskimage *d, char *overlay_basename); void diskimage_recalc_size(struct diskimage *d); int diskimage_exist(struct machine *machine, int id, int type); int diskimage_bootdev(struct machine *machine, int *typep); int diskimage_add(struct machine *machine, char *fname); int diskimage_getname(struct machine *machine, int id, int type, char *buf, size_t bufsize); int diskimage_is_a_cdrom(struct machine *machine, int id, int type); int diskimage_is_a_tape(struct machine *machine, int id, int type); void diskimage_dump_info(struct machine *machine); /* * SCSI commands: */ #define SCSICMD_TEST_UNIT_READY 0x00 /* Mandatory */ #define SCSICMD_REQUEST_SENSE 0x03 /* Mandatory */ #define SCSICMD_INQUIRY 0x12 /* Mandatory */ #define SCSICMD_READ 0x08 #define SCSICMD_READ_10 0x28 #define SCSICMD_WRITE 0x0a #define SCSICMD_WRITE_10 0x2a #define SCSICMD_MODE_SELECT 0x15 #define SCSICMD_MODE_SENSE 0x1a #define SCSICMD_START_STOP_UNIT 0x1b #define SCSICMD_PREVENT_ALLOW_REMOVE 0x1e #define SCSICMD_MODE_SENSE10 0x5a #define SCSICMD_SYNCHRONIZE_CACHE 0x35 /* SCSI block device commands: */ #define SCSIBLOCKCMD_READ_CAPACITY 0x25 /* SCSI CD-ROM commands: */ #define SCSICDROM_READ_SUBCHANNEL 0x42 #define SCSICDROM_READ_TOC 0x43 #define SCSICDROM_READ_DISCINFO 0x51 #define SCSICDROM_READ_TRACKINFO 0x52 /* SCSI tape commands: */ #define SCSICMD_REWIND 0x01 #define SCSICMD_READ_BLOCK_LIMITS 0x05 #define SCSICMD_SPACE 0x11 #endif /* DISKIMAGE_H */ gxemul-0.6.1/src/include/FileLoader_aout.h000644 001750 001750 00000004300 13402411502 020643 0ustar00debugdebug000000 000000 #ifndef FILELOADER_AOUT_H #define FILELOADER_AOUT_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Component.h" #include "FileLoaderImpl.h" #include "UnitTest.h" /** * \brief a.out binary loader. * * TODO: Longer comment. */ class FileLoader_aout : public UnitTestable , public FileLoaderImpl { public: FileLoader_aout(const string& filename); ~FileLoader_aout() { } string DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const; bool LoadIntoComponent(refcount_ptr component, ostream& messages) const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // FILELOADER_AOUT_H gxemul-0.6.1/src/include/NullUI.h000644 001750 001750 00000006614 13402411502 016767 0ustar00debugdebug000000 000000 #ifndef NULLUI_H #define NULLUI_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "UI.h" /** * \brief Dummy UI, which does not do anything. */ class NullUI : public UI { public: /** * \brief Constructs a %NullUI. * * @param gxemul Pointer to the owning GXemul instance. */ NullUI(GXemul *gxemul); virtual ~NullUI(); /** * \brief Does nothing, for the dummy UI. */ virtual void Initialize(); /** * \brief Does nothing, for the dummy UI. */ virtual void UpdateUI(); /** * \brief Does nothing, for the dummy UI. */ virtual void ShowStartupBanner(); /** * \brief Does nothing, for the dummy UI. * * @param msg The message to show. (Ignored.) */ virtual void ShowDebugMessage(const string& msg); /** * \brief Does nothing, for the dummy UI. * * @param component A pointer to the Component. (Ignored.) * @param msg The message to show. (Ignored.) */ virtual void ShowDebugMessage(Component* component, const string& msg); /** * \brief Does nothing, for the dummy UI. * * @param command The command to show. (Ignored.) */ virtual void ShowCommandMessage(const string& command); /** * \brief Does nothing, for the dummy UI. * * @param msg The error message to show. (Ignored.) */ virtual void FatalError(const string& msg); /** * \brief Does nothing, for the dummy UI. * * @param inputline The entire input line. (Ignored.) * @param cursorPosition The current cursor position. 0 is at the * leftmost position. (Ignored.) */ virtual void RedisplayInputLine(const string& inputline, size_t cursorPosition); /** * \brief Executed by the CommandInterpreter when a line has been * completed (with a newline). * * For the %NullUI, this is ignored. */ virtual void InputLineDone(); /** * \brief Runs the main loop. Ignored by the NullUI. * * The NullUI returns 0 immediately. */ virtual int MainLoop(); virtual void Shutdown(); }; #endif // NULLUI_H gxemul-0.6.1/src/include/UI.h000644 001750 001750 00000012700 13402411502 016125 0ustar00debugdebug000000 000000 #ifndef UI_H #define UI_H /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" class Component; class GXemul; /** * \brief Base class for a User Interface. */ class UI : public ReferenceCountable { public: class SetIndentationMessageHelper { public: SetIndentationMessageHelper(UI* ui, const string& msg) : m_UI(ui) { m_oldMsg = m_UI->GetIndentationMessage(); m_UI->SetIndentationMessage(msg); } ~SetIndentationMessageHelper() { m_UI->SetIndentationMessage(m_oldMsg); } private: UI * m_UI; string m_oldMsg; }; public: /** * \brief Constructs a User Interface. * * @param gxemul A pointer to the GXemul owner instance. */ UI(GXemul* gxemul) : m_gxemul(gxemul) { } virtual ~UI() { } /** * \brief Initializes the UI. */ virtual void Initialize() = 0; /** * \brief Shows a startup banner. */ virtual void ShowStartupBanner() = 0; /** * \brief Updates various UI elements. * * Called whenever: *
    *
  • the undo/redo-applicability changes *
  • the name of the emulation changes *
  • the RunState changes *
*/ virtual void UpdateUI() = 0; /** * \brief Sets an indentation message, which indents all debug output. * * Note: An UI implementation may change the indentation string. E.g. * from "step X: " to " ". * * @param msg The indentation message. If the message is an empty * string, indentation is not used. */ void SetIndentationMessage(const string& msg) { m_indentationMsg = msg; } /** * \brief Gets the indentation message. * * @return The indentation message. If the message is an empty * string, indentation is not used. */ string GetIndentationMessage() const { return m_indentationMsg; } /** * \brief Shows a debug message. * * @param msg The message to show. */ virtual void ShowDebugMessage(const string& msg) = 0; /** * \brief Shows a debug message for a Component. * * Usually, this involves formatting the debug message using * Component::GenerateShortestPossiblePath(). * * If the runstate is GXemul::Running, the debug message * is encapsulated by "[ ]" brackets, making the debug message very * similar to pre-0.6.0 debug output style. * * @param component A pointer to the Component. * @param msg The message to show. */ virtual void ShowDebugMessage(Component* component, const string& msg) = 0; /** * \brief Shows a command being executed. * * @param command The command being executed. */ virtual void ShowCommandMessage(const string& command) = 0; /** * \brief Shows a fatal error message. * * After showing the fatal error message, the application * is expected to terminate. In a GUI implementation, it * is therefore good to wait for the user to acknowledge * the error message before returning. * * @param msg The message to show. */ virtual void FatalError(const string& msg) = 0; /** * \brief Redisplays the interactive command input line. * * This function generally displays a prompt (e.g. "GXemul> ") * followed by the input line, placing the cursor position at * the correct position on the input line. * * @param inputline The entire input line. * @param cursorPosition The current cursor position. 0 is at the * leftmost position. */ virtual void RedisplayInputLine(const string& inputline, size_t cursorPosition) = 0; /** * \brief Executed by the CommandInterpreter when a line has been * completed (with a newline). * * Usually this clears the current line, and (if possible) moves * down to a new line. */ virtual void InputLineDone() = 0; /** * \brief Runs the UI's main loop. * * The return code should be the exit code that the gxemul binary * should return. * * @return 0 on success, non-zero on failure. */ virtual int MainLoop() = 0; /** * \brief Shuts down the UI. * * Called from e.g. the "quit" command. */ virtual void Shutdown() = 0; protected: GXemul* m_gxemul; string m_indentationMsg; }; #endif // UI_H gxemul-0.6.1/src/include/interrupt.h000644 001750 001750 00000007777 13402411502 017666 0ustar00debugdebug000000 000000 #ifndef INTERRUPT_H #define INTERRUPT_H /* * Copyright (C) 2006-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Definitions related to the Interrupt subsystem. */ #include "misc.h" struct interrupt { /* Functions used to assert and deassert the interrupt. */ void (*interrupt_assert)(struct interrupt *); void (*interrupt_deassert)(struct interrupt *); /* * The interrupt "line" number, or "pin" number, is an internal number * used by interrupt_assert() and interrupt_deassert(). It may * correspond to a physical interrupt number, or it may be ignored * completely. * * This can either be a small integer corresponding to the interrupt * pin number, or an entire interrupt mask (for controllers with at * most 32 interrupts). */ uint32_t line; /* * The extra pointer is a pointer to the (conceptual) interrupt * handler. For a CPU interrupt, this is a pointer to the CPU. For * e.g. a 8259 interrupt, it is a pointer to the dev_8259 which will * handle it. */ void *extra; /* * Actual name of the interrupt. This is a complete "path", e.g. * "machine[0].cpu[1].irq[3].isa[14]". It is used for * connecting/disconnecting, and debug output. */ char *name; }; /* * Macros to make code using the interrupt struct a bit more consise: */ #define INTERRUPT_ASSERT(istruct) (istruct).interrupt_assert(&(istruct)) #define INTERRUPT_DEASSERT(istruct) (istruct).interrupt_deassert(&(istruct)) #define INTERRUPT_CONNECT(name,istruct) { \ interrupt_handler_lookup(name, &(istruct)); \ interrupt_connect(&(istruct), 0); \ } #define INTERRUPT_CONNECT_EXCLUSIVE(name,istruct) { \ interrupt_handler_lookup(name, &(istruct)); \ interrupt_connect(&(istruct), 1); \ } /* * Registration of interrupt handlers: * * Each interrupt handler (i.e. CPUs, interrupt controllers, various bus * controllers) should call interrupt_handler_register() to register itself. */ void interrupt_handler_register(struct interrupt *templ); void interrupt_handler_remove(const char *name); int interrupt_handler_lookup(const char *name, struct interrupt *templ); /* * Functions used to keep track of exclusive and non-exclusive users, * respectively, of an interrupt. * * If interrupt_connect() returns, it means it succeeded. On failure, the * emulator exits. There may be up to 1 exclusive user and no non-exclusive * users, or 0 exclusive users and any number of non-exclusive users. */ void interrupt_connect(struct interrupt *i, int exclusive); void interrupt_disconnect(struct interrupt *i, int exclusive); #endif /* INTERRUPT_H */ gxemul-0.6.1/src/include/cpu.h000644 001750 001750 00000043310 13402411502 016400 0ustar00debugdebug000000 000000 #ifndef CPU_H #define CPU_H /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * CPU-related definitions. */ #include #include #include /* This is needed for undefining 'mips', 'ppc' etc. on weird systems: */ #include "../../config.h" #include "timer.h" /* * Dyntrans misc declarations, used throughout the dyntrans code. * * Note that there is space for all instruction calls within a page, and then * two more. The first one of these "extra" instruction slots is the end-of- * page slot. It transfers control to the first instruction slot on the next * (virtual) page. * * The second of these extra instruction slots is an additional end-of-page * slot for delay-slot architectures. On e.g. MIPS, a branch instruction can * "nullify" (skip) the delay-slot. If the end-of-page slot is skipped, then * we end up one step after that. That's where the end_of_page2 slot is. :) * * next_ofs points to the next page in a chain of possible pages. (Several * pages can be in the same chain, but only one matches the specific physaddr.) * * translations_bitmap is a tiny bitmap indicating which parts of the page have * actual translations. Bit 0 corresponds to the lowest 1/32th of the page, bit * 1 to the second-lowest 1/32th, and so on. This speeds up page invalidations, * since only part of the page need to be reset. * * translation_ranges_ofs is an offset within the translation cache to a short * list of ranges for this physpage which contain code. The list is of fixed * length; to extend the list, the list should be made to point to another * list, and so forth. (Bad, O(n) find/insert complexity. Should be fixed some * day. TODO) See definition of physpage_ranges below. */ #define DYNTRANS_MISC_DECLARATIONS(arch,ARCH,addrtype) struct \ arch ## _instr_call { \ void (*f)(struct cpu *, struct arch ## _instr_call *); \ size_t arg[ARCH ## _N_IC_ARGS]; \ }; \ \ /* Translation cache struct for each physical page: */ \ struct arch ## _tc_physpage { \ struct arch ## _instr_call ics[ARCH ## _IC_ENTRIES_PER_PAGE+2];\ uint32_t next_ofs; /* (0 for end of chain) */ \ uint32_t translations_bitmap; \ uint32_t translation_ranges_ofs; \ addrtype physaddr; \ }; \ \ struct arch ## _vpg_tlb_entry { \ uint8_t valid; \ uint8_t writeflag; \ addrtype vaddr_page; \ addrtype paddr_page; \ unsigned char *host_page; \ }; #define DYNTRANS_MISC64_DECLARATIONS(arch,ARCH,tlbindextype) \ struct arch ## _l3_64_table { \ unsigned char *host_load[1 << ARCH ## _L3N]; \ unsigned char *host_store[1 << ARCH ## _L3N]; \ uint64_t phys_addr[1 << ARCH ## _L3N]; \ tlbindextype vaddr_to_tlbindex[1 << ARCH ## _L3N]; \ struct arch ## _tc_physpage *phys_page[1 << ARCH ## _L3N]; \ struct arch ## _l3_64_table *next; \ int refcount; \ }; \ struct arch ## _l2_64_table { \ struct arch ## _l3_64_table *l3[1 << ARCH ## _L2N]; \ struct arch ## _l2_64_table *next; \ int refcount; \ }; /* * This structure contains a list of ranges within an emulated * physical page that contain translatable code. */ #define PHYSPAGE_RANGES_ENTRIES_PER_LIST 20 struct physpage_ranges { uint32_t next_ofs; /* 0 for end of chain */ uint32_t n_entries_used; uint16_t base[PHYSPAGE_RANGES_ENTRIES_PER_LIST]; uint16_t length[PHYSPAGE_RANGES_ENTRIES_PER_LIST]; uint16_t count[PHYSPAGE_RANGES_ENTRIES_PER_LIST]; }; /* * Dyntrans "Instruction Translation Cache": * * cur_physpage is a pointer to the current physpage. (It _HAPPENS_ to * be the same as cur_ic_page, because all the instrcalls should be placed * first in the physpage struct!) * * cur_ic_page is a pointer to an array of xxx_IC_ENTRIES_PER_PAGE * instruction call entries. * * next_ic points to the next such instruction call to be executed. * * combination_check, when set to non-NULL, is executed automatically after * an instruction has been translated. (It check for combinations of * instructions; low_addr is the offset of the translated instruction in the * current page, NOT shifted right.) */ #define DYNTRANS_ITC(arch) struct arch ## _tc_physpage *cur_physpage; \ struct arch ## _instr_call *cur_ic_page; \ struct arch ## _instr_call *next_ic; \ struct arch ## _tc_physpage *physpage_template;\ void (*combination_check)(struct cpu *, \ struct arch ## _instr_call *, int low_addr); /* * Virtual -> physical -> host address translation TLB entries: * ------------------------------------------------------------ * * Regardless of whether 32-bit or 64-bit address translation is used, the * same TLB entry structure is used. */ #define VPH_TLBS(arch,ARCH) \ struct arch ## _vpg_tlb_entry \ vph_tlb_entry[ARCH ## _MAX_VPH_TLB_ENTRIES]; /* * 32-bit dyntrans emulated Virtual -> physical -> host address translation: * ------------------------------------------------------------------------- * * This stuff assumes that 4 KB pages are used. 20 bits to select a page * means just 1 M entries needed. This is small enough that a couple of * full-size tables can fit in virtual memory on modern hosts (both 32-bit * and 64-bit hosts). :-) * * Usage: e.g. VPH32(arm,ARM) * or VPH32(sparc,SPARC) * * The vph_tlb_entry entries are cpu dependent tlb entries. * * The host_load and host_store entries point to host pages; the phys_addr * entries are uint32_t (emulated physical addresses). * * phys_page points to translation cache physpages. * * vaddr_to_tlbindex is a virtual address to tlb index hint table. * The values in this array are the tlb index plus 1, so a value of, say, * 3 means tlb index 2. A value of 0 would mean a tlb index of -1, which * is not a valid index. (I.e. no hit.) * * The VPH32EXTENDED variant adds an additional postfix to the array * names. Used so far only for usermode addresses in M88K emulation. */ #define N_VPH32_ENTRIES 1048576 #define VPH32(arch,ARCH) \ unsigned char *host_load[N_VPH32_ENTRIES]; \ unsigned char *host_store[N_VPH32_ENTRIES]; \ uint32_t phys_addr[N_VPH32_ENTRIES]; \ struct arch ## _tc_physpage *phys_page[N_VPH32_ENTRIES]; \ uint8_t vaddr_to_tlbindex[N_VPH32_ENTRIES]; #define VPH32_16BITVPHENTRIES(arch,ARCH) \ unsigned char *host_load[N_VPH32_ENTRIES]; \ unsigned char *host_store[N_VPH32_ENTRIES]; \ uint32_t phys_addr[N_VPH32_ENTRIES]; \ struct arch ## _tc_physpage *phys_page[N_VPH32_ENTRIES]; \ uint16_t vaddr_to_tlbindex[N_VPH32_ENTRIES]; #define VPH32EXTENDED(arch,ARCH,ex) \ unsigned char *host_load_ ## ex[N_VPH32_ENTRIES]; \ unsigned char *host_store_ ## ex[N_VPH32_ENTRIES]; \ uint32_t phys_addr_ ## ex[N_VPH32_ENTRIES]; \ struct arch ## _tc_physpage *phys_page_ ## ex[N_VPH32_ENTRIES];\ uint8_t vaddr_to_tlbindex_ ## ex[N_VPH32_ENTRIES]; /* * 64-bit dyntrans emulated Virtual -> physical -> host address translation: * ------------------------------------------------------------------------- * * Usage: e.g. VPH64(alpha,ALPHA) * or VPH64(sparc,SPARC) * * l1_64 is an array containing poiners to l2 tables. * * l2_64_dummy is a pointer to a "dummy l2 table". Instead of having NULL * pointers in l1_64 for unused slots, a pointer to the dummy table can be * used. */ #define DYNTRANS_L1N 17 #define VPH64(arch,ARCH) \ struct arch ## _l3_64_table *l3_64_dummy; \ struct arch ## _l3_64_table *next_free_l3; \ struct arch ## _l2_64_table *l2_64_dummy; \ struct arch ## _l2_64_table *next_free_l2; \ struct arch ## _l2_64_table *l1_64[1 << DYNTRANS_L1N]; /* Include all CPUs' header files here: */ #include "cpu_alpha.h" #include "cpu_arm.h" #include "cpu_m88k.h" #include "cpu_mips.h" #include "cpu_ppc.h" #include "cpu_sh.h" struct cpu; struct emul; struct machine; struct memory; struct settings; /* * cpu_family * ---------- * * This structure consists of various pointers to functions, performing * architecture-specific functions. * * Except for the next and arch fields at the top, all fields in the * cpu_family struct are filled in by ecah CPU family's init function. */ struct cpu_family { struct cpu_family *next; int arch; /* Familty name, e.g. "MIPS", "Alpha" etc. */ char *name; /* Fill in architecture specific parts of a struct cpu. */ int (*cpu_new)(struct cpu *cpu, struct memory *mem, struct machine *machine, int cpu_id, char *cpu_type_name); /* Initialize various translation tables. */ void (*init_tables)(struct cpu *cpu); /* List available CPU types for this architecture. */ void (*list_available_types)(void); /* Disassemble an instruction. */ int (*disassemble_instr)(struct cpu *cpu, unsigned char *instr, int running, uint64_t dumpaddr); /* Dump CPU registers in readable format. */ void (*register_dump)(struct cpu *cpu, int gprs, int coprocs); /* Dump generic CPU info in readable format. */ void (*dumpinfo)(struct cpu *cpu); /* Dump TLB data for CPU id x. */ void (*tlbdump)(struct machine *m, int x, int rawflag); /* Print architecture-specific function call arguments. (This is called for each function call, if running with -t.) */ void (*functioncall_trace)(struct cpu *, int n_args); }; /* * More dyntrans stuff: * * The translation cache begins with N_BASE_TABLE_ENTRIES uint32_t offsets * into the cache, for possible translation cache structs for physical pages. */ /* Meaning of delay_slot: */ #define NOT_DELAYED 0 #define DELAYED 1 #define TO_BE_DELAYED 2 #define EXCEPTION_IN_DELAY_SLOT 8 #define N_SAFE_DYNTRANS_LIMIT_SHIFT 14 #define N_SAFE_DYNTRANS_LIMIT ((1 << (N_SAFE_DYNTRANS_LIMIT_SHIFT - 1)) - 1) #define MAX_DYNTRANS_READAHEAD 128 #define DEFAULT_DYNTRANS_CACHE_SIZE (96*1048576) #define DYNTRANS_CACHE_MARGIN 200000 #define N_BASE_TABLE_ENTRIES 65536 #define PAGENR_TO_TABLE_INDEX(a) ((a) & (N_BASE_TABLE_ENTRIES-1)) /* * The generic CPU struct: */ struct cpu { /* Pointer back to the machine this CPU is in: */ struct machine *machine; /* Settings: */ struct settings *settings; /* CPU-specific name, e.g. "R2000", "21164PC", etc. */ char *name; /* Full "path" to the CPU, e.g. "machine[0].cpu[0]": */ char *path; /* Nr of instructions executed, etc.: */ int64_t ninstrs; int64_t ninstrs_show; int64_t ninstrs_flush; int64_t ninstrs_since_gettimeofday; struct timeval starttime; /* EMUL_LITTLE_ENDIAN or EMUL_BIG_ENDIAN. */ uint8_t byte_order; /* 0 for emulated 64-bit CPUs, 1 for 32-bit. */ uint8_t is_32bit; /* 1 while running, 0 when paused/stopped. */ uint8_t running; /* See comment further up. */ uint8_t delay_slot; /* 0-based CPU id, in an emulated SMP system. */ int cpu_id; /* A pointer to the main memory connected to this CPU. */ struct memory *mem; int (*run_instr)(struct cpu *cpu); int (*memory_rw)(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags); int (*translate_v2p)(struct cpu *, uint64_t vaddr, uint64_t *return_paddr, int flags); void (*update_translation_table)(struct cpu *, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page); void (*invalidate_translation_caches)(struct cpu *, uint64_t paddr, int flags); void (*invalidate_code_translation)(struct cpu *, uint64_t paddr, int flags); void (*useremul_syscall)(struct cpu *cpu, uint32_t code); int (*instruction_has_delayslot)(struct cpu *cpu, unsigned char *ib); /* The program counter. (For 32-bit modes, not all bits are used.) */ uint64_t pc; /* The current depth of function call tracing. */ int trace_tree_depth; /* * If is_halted is true when an interrupt trap occurs, the pointer * to the next instruction to execute will be the instruction * following the halt instruction, not the halt instrucion itself. * * If has_been_idling is true when printing the number of executed * instructions per second, "idling" is printed instead. (The number * of instrs per second when idling is meaningless anyway.) */ char is_halted; char has_been_idling; /* * Dynamic translation: * * The number of translated instructions is assumed to be 1 per * instruction call. For each case where this differs from the * truth, n_translated_instrs should be modified. E.g. if 1000 * instruction calls are done, and n_translated_instrs is 50, then * 1050 emulated instructions were actually executed. * * Note that it can also be adjusted negatively, that is, the way * to "get out" of a dyntrans loop is to set the current instruction * call pointer to the "nothing" instruction. This instruction * _decreases_ n_translated_instrs by 1. That way, once the dyntrans * loop exits, only real instructions will be counted, and not the * "nothing" instructions. * * The translation cache is a relative large chunk of memory (say, * 32 MB) which is used for translations. When it has been used up, * everything restarts from scratch. * * translation_readahead is non-zero when translating instructions * ahead of the current (emulated) instruction pointer. */ int translation_readahead; /* Instruction translation cache: */ int n_translated_instrs; unsigned char *translation_cache; size_t translation_cache_cur_ofs; /* * CPU-family dependent: * * These contain everything ranging from general purpose registers, * control registers, memory management, status words, interrupt * specifics, etc. */ union { struct alpha_cpu alpha; struct arm_cpu arm; struct m88k_cpu m88k; struct mips_cpu mips; struct ppc_cpu ppc; struct sh_cpu sh; } cd; }; /* cpu.c: */ struct cpu *cpu_new(struct memory *mem, struct machine *machine, int cpu_id, char *cpu_type_name); void cpu_destroy(struct cpu *cpu); void cpu_tlbdump(struct machine *m, int x, int rawflag); void cpu_register_dump(struct machine *m, struct cpu *cpu, int gprs, int coprocs); int cpu_disassemble_instr(struct machine *m, struct cpu *cpu, unsigned char *instr, int running, uint64_t addr); void cpu_functioncall_trace(struct cpu *cpu, uint64_t f); void cpu_functioncall_trace_return(struct cpu *cpu); void cpu_create_or_reset_tc(struct cpu *cpu); void cpu_run_init(struct machine *machine); void cpu_run_deinit(struct machine *machine); void cpu_dumpinfo(struct machine *m, struct cpu *cpu); void cpu_list_available_types(void); void cpu_show_cycles(struct machine *machine, int forced); struct cpu_family *cpu_family_ptr_by_number(int arch); void cpu_init(void); #define JUST_MARK_AS_NON_WRITABLE 1 #define INVALIDATE_ALL 2 #define INVALIDATE_PADDR 4 #define INVALIDATE_VADDR 8 #define INVALIDATE_VADDR_UPPER4 16 /* useful for PPC emulation */ /* Note: 64-bit processors running in 32-bit mode use a 32-bit display format, even though the underlying data is 64-bits. */ #define CPU_SETTINGS_ADD_REGISTER64(name, var) \ settings_add(cpu->settings, name, 1, SETTINGS_TYPE_UINT64, \ cpu->is_32bit? SETTINGS_FORMAT_HEX32 : SETTINGS_FORMAT_HEX64, \ (void *) &(var)); #define CPU_SETTINGS_ADD_REGISTER32(name, var) \ settings_add(cpu->settings, name, 1, SETTINGS_TYPE_UINT32, \ SETTINGS_FORMAT_HEX32, (void *) &(var)); #define CPU_SETTINGS_ADD_REGISTER16(name, var) \ settings_add(cpu->settings, name, 1, SETTINGS_TYPE_UINT16, \ SETTINGS_FORMAT_HEX16, (void *) &(var)); #define CPU_SETTINGS_ADD_REGISTER8(name, var) \ settings_add(cpu->settings, name, 1, SETTINGS_TYPE_UINT8, \ SETTINGS_FORMAT_HEX8, (void *) &(var)); #define CPU_FAMILY_INIT(n,s) int n ## _cpu_family_init( \ struct cpu_family *fp) { \ /* Fill in the cpu_family struct with valid data for this arch. */ \ fp->name = strdup(s); \ fp->cpu_new = n ## _cpu_new; \ fp->list_available_types = n ## _cpu_list_available_types; \ fp->disassemble_instr = n ## _cpu_disassemble_instr; \ fp->register_dump = n ## _cpu_register_dump; \ fp->dumpinfo = n ## _cpu_dumpinfo; \ fp->functioncall_trace = n ## _cpu_functioncall_trace; \ fp->tlbdump = n ## _cpu_tlbdump; \ fp->init_tables = n ## _cpu_init_tables; \ return 1; \ } #endif /* CPU_H */ gxemul-0.6.1/src/include/memory.h000644 001750 001750 00000014113 13402411502 017120 0ustar00debugdebug000000 000000 #ifndef MEMORY_H #define MEMORY_H /* * Copyright (C) 2004-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Memory related functions. */ #include #include #include "misc.h" #define DEFAULT_RAM_IN_MB 32 struct cpu; /* * Memory mapped device */ struct memory_device { uint64_t baseaddr; uint64_t endaddr; /* NOTE: after the last byte! */ uint64_t length; int flags; const char *name; int (*f)(struct cpu *,struct memory *, uint64_t,unsigned char *,size_t,int,void *); void *extra; unsigned char *dyntrans_data; uint64_t dyntrans_write_low; uint64_t dyntrans_write_high; }; /* * Memory * ------ * * This struct defines a memory object. Most machines only use one memory * object (the main memory), but if necessary, multiple memories can be * used. */ struct memory { uint64_t physical_max; void *pagetable; int dev_dyntrans_alignment; int n_mmapped_devices; int last_accessed_device; /* The following two might speed up things a little bit. */ /* (actually maxaddr is the addr after the last address) */ uint64_t mmap_dev_minaddr; uint64_t mmap_dev_maxaddr; struct memory_device *devices; }; #define BITS_PER_PAGETABLE 20 #define BITS_PER_MEMBLOCK 20 #define MAX_BITS 40 /* memory.c: */ #define MEM_PCI_LITTLE_ENDIAN 128 uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len); void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, uint64_t data); void *zeroed_alloc(size_t s); struct memory *memory_new(uint64_t physical_max, int arch); int memory_points_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr, int min_string_length); char *memory_conv_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr, char *buf, int bufsize); unsigned char *memory_paddr_to_hostaddr(struct memory *mem, uint64_t paddr, int writeflag); /* Writeflag: */ #define MEM_READ 0 #define MEM_WRITE 1 #define MEM_DOWNGRADE 128 /* Misc. flags: */ #define CACHE_DATA 0 #define CACHE_INSTRUCTION 1 #define CACHE_NONE 2 #define CACHE_FLAGS_MASK 0x3 #define NO_EXCEPTIONS 16 #define PHYSICAL 32 #define MEMORY_USER_ACCESS 64 /* for ARM and M88K */ /* Dyntrans Memory flags: */ #define DM_DEFAULT 0 #define DM_DYNTRANS_OK 1 #define DM_DYNTRANS_WRITE_OK 2 #define DM_READS_HAVE_NO_SIDE_EFFECTS 4 #define DM_EMULATED_RAM 8 #define FLAG_WRITEFLAG 1 #define FLAG_NOEXCEPTIONS 2 #define FLAG_INSTR 4 #define MEMORY_ACCESS_FAILED 0 #define MEMORY_ACCESS_OK 1 #define MEMORY_ACCESS_OK_WRITE 2 #define MEMORY_NOT_FULL_PAGE 256 void memory_device_dyntrans_access(struct cpu *, struct memory *mem, void *extra, uint64_t *low, uint64_t *high); #define DEVICE_ACCESS(x) int dev_ ## x ## _access(struct cpu *cpu, \ struct memory *mem, uint64_t relative_addr, unsigned char *data, \ size_t len, int writeflag, void *extra) void memory_device_update_data(struct memory *mem, void *extra, unsigned char *data); void memory_device_register(struct memory *mem, const char *, uint64_t baseaddr, uint64_t len, int (*f)(struct cpu *, struct memory *,uint64_t,unsigned char *,size_t,int,void *), void *extra, int flags, unsigned char *dyntrans_data); void memory_device_remove(struct memory *mem, int i); uint64_t memory_checksum(struct memory *mem); void dump_mem_string(struct cpu *cpu, uint64_t addr); void store_string(struct cpu *cpu, uint64_t addr, const char *s); int store_64bit_word(struct cpu *cpu, uint64_t addr, uint64_t data64); int store_32bit_word(struct cpu *cpu, uint64_t addr, uint64_t data32); int store_16bit_word(struct cpu *cpu, uint64_t addr, uint64_t data16); void store_byte(struct cpu *cpu, uint64_t addr, uint8_t data); void store_64bit_word_in_host(struct cpu *cpu, unsigned char *data, uint64_t data32); void store_32bit_word_in_host(struct cpu *cpu, unsigned char *data, uint64_t data32); void store_16bit_word_in_host(struct cpu *cpu, unsigned char *data, uint16_t data16); uint64_t load_64bit_word(struct cpu *cpu, uint64_t addr); uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr); uint16_t load_16bit_word(struct cpu *cpu, uint64_t addr); void store_buf(struct cpu *cpu, uint64_t addr, const char *s, size_t len); void add_environment_string(struct cpu *cpu, const char *s, uint64_t *addr); void add_environment_string_dual(struct cpu *cpu, uint64_t *ptrp, uint64_t *addrp, const char *s1, const char *s2); void store_pointer_and_advance(struct cpu *cpu, uint64_t *addrp, uint64_t data, int flag64); void memory_warn_about_unimplemented_addr(struct cpu *cpu, struct memory *mem, int writeflag, uint64_t paddr, uint8_t *data, size_t len); #endif /* MEMORY_H */ gxemul-0.6.1/src/include/settings.h000644 001750 001750 00000006167 13402411502 017462 0ustar00debugdebug000000 000000 #ifndef SETTINGS_H #define SETTINGS_H /* * Copyright (C) 2006-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #define GLOBAL_SETTINGS_NAME "settings" struct settings; /* Storage types: */ #define SETTINGS_TYPE_SUBSETTINGS 1 #define SETTINGS_TYPE_STRING 2 #define SETTINGS_TYPE_INT 3 #define SETTINGS_TYPE_INT8 4 #define SETTINGS_TYPE_INT16 5 #define SETTINGS_TYPE_INT32 6 #define SETTINGS_TYPE_INT64 7 #define SETTINGS_TYPE_UINT 8 #define SETTINGS_TYPE_UINT8 9 #define SETTINGS_TYPE_UINT16 10 #define SETTINGS_TYPE_UINT32 11 #define SETTINGS_TYPE_UINT64 12 /* Presentation formats: */ #define SETTINGS_FORMAT_DECIMAL 1 /* -123 */ #define SETTINGS_FORMAT_HEX8 2 /* 0x12 */ #define SETTINGS_FORMAT_HEX16 3 /* 0x1234 */ #define SETTINGS_FORMAT_HEX32 4 /* 0x80000000 */ #define SETTINGS_FORMAT_HEX64 5 /* 0xffffffff80000000 */ #define SETTINGS_FORMAT_BOOL 6 /* true, false */ #define SETTINGS_FORMAT_YESNO 7 /* yes, no */ #define SETTINGS_FORMAT_STRING 8 /* %s */ /* * settings.c: */ struct settings *settings_new(void); void settings_destroy(struct settings *settings); void settings_debugdump(struct settings *settings, const char *prefix, int recurse); void settings_add(struct settings *settings, const char *name, int writable, int type, int format, void *ptr); void settings_remove(struct settings *settings, const char *name); void settings_remove_all(struct settings *settings); int settings_access(struct settings *settings, const char *fullname, int writeflag, uint64_t *valuep); /* Result codes from settings_access: */ #define SETTINGS_OK 1 #define SETTINGS_NAME_NOT_FOUND 2 #define SETTINGS_READONLY 3 #endif /* SETTINGS_H */ gxemul-0.6.1/src/include/testmachine/dev_fb.h000644 001750 001750 00000002510 13402411502 021337 0ustar00debugdebug000000 000000 #ifndef TESTMACHINE_FB_H #define TESTMACHINE_FB_H /* * Definitions used by the framebuffer device in GXemul. * * This file is in the public domain. */ /* Physical base address for linear framebuffer memory: */ #define DEV_FB_ADDRESS 0x12000000 /* Physical base address for the framebuffer controller: */ #define DEV_FBCTRL_ADDRESS 0x12f00000 #define DEV_FBCTRL_LENGTH 0x20 /* * First choose the port by writing the port index to DEV_FBCTRL_PORT, * then read or write DEV_FBCTRL_DATA. */ #define DEV_FBCTRL_PORT 0x00 #define DEV_FBCTRL_DATA 0x10 #define DEV_FBCTRL_PORT_COMMAND 0 #define DEV_FBCTRL_PORT_X1 1 #define DEV_FBCTRL_PORT_Y1 2 #define DEV_FBCTRL_PORT_X2 3 #define DEV_FBCTRL_PORT_Y2 4 #define DEV_FBCTRL_PORT_COLOR_R 5 #define DEV_FBCTRL_PORT_COLOR_G 6 #define DEV_FBCTRL_PORT_COLOR_B 7 #define DEV_FBCTRL_NPORTS 8 /* * Controller commands: */ /* Do nothing. */ #define DEV_FBCTRL_COMMAND_NOP 0 /* Set resolution to X1 x Y1. */ #define DEV_FBCTRL_COMMAND_SET_RESOLUTION 1 /* Get current resolution into X1, Y1. */ #define DEV_FBCTRL_COMMAND_GET_RESOLUTION 2 /* TODO: */ #define DEV_FBCTRL_COMMAND_FILL 3 #define DEV_FBCTRL_COMMAND_COPY 4 #define DEV_FBCTRL_MAXY(x) (((DEV_FBCTRL_ADDRESS-DEV_FB_ADDRESS) / 3) / x) #endif /* TESTMACHINE_FB_H */ gxemul-0.6.1/src/include/testmachine/dev_cons.h000644 001750 001750 00000000557 13402411502 021723 0ustar00debugdebug000000 000000 #ifndef TESTMACHINE_CONS_H #define TESTMACHINE_CONS_H /* * Definitions used by the "cons" device in GXemul. * * This file is in the public domain. */ #define DEV_CONS_ADDRESS 0x0000000010000000 #define DEV_CONS_LENGTH 0x0000000000000020 #define DEV_CONS_PUTGETCHAR 0x0000 #define DEV_CONS_HALT 0x0010 #endif /* TESTMACHINE_CONS_H */ gxemul-0.6.1/src/include/testmachine/dev_mp.h000644 001750 001750 00000002057 13402411502 021372 0ustar00debugdebug000000 000000 #ifndef TESTMACHINE_MP_H #define TESTMACHINE_MP_H /* * Definitions used by the "mp" device in GXemul. * * This file is in the public domain. */ /* * Architecture-specific interrupt definitions: */ #define MIPS_IPI_INT 6 /* * Default (physical) base address and length: */ #define DEV_MP_ADDRESS 0x0000000011000000ULL #define DEV_MP_LENGTH 0x0000000000000100ULL /* * Offsets from the base address to reach the MP device' registers: */ #define DEV_MP_WHOAMI 0x0000 #define DEV_MP_NCPUS 0x0010 #define DEV_MP_STARTUPCPU 0x0020 #define DEV_MP_STARTUPADDR 0x0030 #define DEV_MP_PAUSE_ADDR 0x0040 #define DEV_MP_PAUSE_CPU 0x0050 #define DEV_MP_UNPAUSE_CPU 0x0060 #define DEV_MP_STARTUPSTACK 0x0070 #define DEV_MP_HARDWARE_RANDOM 0x0080 #define DEV_MP_MEMORY 0x0090 #define DEV_MP_IPI_ONE 0x00a0 #define DEV_MP_IPI_MANY 0x00b0 #define DEV_MP_IPI_READ 0x00c0 #define DEV_MP_NCYCLES 0x00d0 #endif /* TESTMACHINE_MP_H */ gxemul-0.6.1/src/include/testmachine/dev_ether.h000644 001750 001750 00000001324 13402411502 022061 0ustar00debugdebug000000 000000 #ifndef TESTMACHINE_ETHER_H #define TESTMACHINE_ETHER_H /* * Definitions used by the "ether" device in GXemul. * * This file is in the public domain. */ #define DEV_ETHER_ADDRESS 0x14000000 #define DEV_ETHER_LENGTH 0x8000 #define DEV_ETHER_BUFFER 0x0000 #define DEV_ETHER_BUFFER_SIZE 0x4000 #define DEV_ETHER_STATUS 0x4000 #define DEV_ETHER_PACKETLENGTH 0x4010 #define DEV_ETHER_COMMAND 0x4020 #define DEV_ETHER_MAC 0x4040 /* Status bits: */ #define DEV_ETHER_STATUS_PACKET_RECEIVED 1 #define DEV_ETHER_STATUS_MORE_PACKETS_AVAILABLE 2 /* Commands: */ #define DEV_ETHER_COMMAND_RX 0 #define DEV_ETHER_COMMAND_TX 1 #endif /* TESTMACHINE_ETHER_H */ gxemul-0.6.1/src/include/testmachine/dev_irqc.h000644 001750 001750 00000000537 13402411502 021715 0ustar00debugdebug000000 000000 #ifndef TESTMACHINE_IRQC_H #define TESTMACHINE_IRQC_H /* * Definitions used by the "irqc" device in GXemul. * * This file is in the public domain. */ #define DEV_IRQC_ADDRESS 0x0000000016000000 #define DEV_IRQC_LENGTH 0x12 #define DEV_IRQC_IRQ 0x0 #define DEV_IRQC_MASK 0x4 #define DEV_IRQC_UNMASK 0x8 #endif /* TESTMACHINE_IRQC_H */ gxemul-0.6.1/src/include/testmachine/README000644 001750 001750 00000002772 13402411502 020633 0ustar00debugdebug000000 000000 $Id: README,v 1.4 2007-06-16 01:12:32 debug Exp $ The files in this directory describe the devices found in GXemul's "test machines". These machines do not match any real-world machines, but they have devices that are similar to those found in real machines: o) console (dev_cons): A simple console device, with putchar() and getchar() functionality. It also has a halt() function, to make it easy to exit from the emulator. o) disk (dev_disk): Used for reading and writing 512-byte sectors from/to disk images. o) ethernet (dev_ether): A very simple ethernet NIC, capable of sending and receiving ethernet frames on the simulated network. o) framebuffer (dev_fb): 640 x 480 pixels, 3 bytes per pixel, red-green-blue o) interrupt controller (dev_irqc): A generic interrupt controller. (Not used by the MIPS test machine.) o) mp (dev_mp): A multiprocessor inter-processor communication device. It also contains other useful functionality, such as retrieving the amount of "physical" RAM installed in the emulated machine. o) rtc (dev_rtc): A Real-Time Clock device. Used to retrieve the current time, and to cause periodic interrupts at a specific frequency. These include files are not released under the same license as GXemul itself. The include files are released as public domain, so they can be reused also in projects that have BSD-incompatible licenses. Please read the GXemul documentation for more details on how to use the testmachine devices, and study the demo programs. gxemul-0.6.1/src/include/testmachine/dev_disk.h000644 001750 001750 00000001146 13402411502 021706 0ustar00debugdebug000000 000000 #ifndef TESTMACHINE_DISK_H #define TESTMACHINE_DISK_H /* * Definitions used by the "disk" device in GXemul. * * This file is in the public domain. */ #define DEV_DISK_ADDRESS 0x13000000 #define DEV_DISK_OFFSET 0x0000 #define DEV_DISK_OFFSET_HIGH32 0x0008 #define DEV_DISK_ID 0x0010 #define DEV_DISK_START_OPERATION 0x0020 #define DEV_DISK_STATUS 0x0030 #define DEV_DISK_BUFFER 0x4000 #define DEV_DISK_BUFFER_LEN 0x200 /* Operations: */ #define DEV_DISK_OPERATION_READ 0 #define DEV_DISK_OPERATION_WRITE 1 #endif /* TESTMACHINE_DISK_H */ gxemul-0.6.1/src/include/testmachine/dev_rtc.h000644 001750 001750 00000000740 13402411502 021543 0ustar00debugdebug000000 000000 #ifndef TESTMACHINE_RTC_H #define TESTMACHINE_RTC_H /* * Definitions used by the "rtc" device in GXemul. * * This file is in the public domain. */ #define DEV_RTC_ADDRESS 0x0000000015000000 #define DEV_RTC_LENGTH 0x0000000000000200 #define DEV_RTC_TRIGGER_READ 0x0000 #define DEV_RTC_SEC 0x0010 #define DEV_RTC_USEC 0x0020 #define DEV_RTC_HZ 0x0100 #define DEV_RTC_INTERRUPT_ACK 0x0110 #endif /* TESTMACHINE_RTC_H */ gxemul-0.6.1/src/include/thirdparty/dc21285reg.h000644 001750 001750 00000026347 13402411502 021504 0ustar00debugdebug000000 000000 /* GXemul: $Id: dc21285reg.h,v 1.1 2005-09-13 20:56:54 debug Exp $ */ /* $NetBSD: dc21285reg.h,v 1.4 2003/01/17 22:29:43 thorpej Exp $ */ #ifndef DC21285REG_H #define DC21285REG_H /* * Copyright (c) 1997,1998 Mark Brinicombe. * Copyright (c) 1997,1998 Causality Limited * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Mark Brinicombe * for the NetBSD Project. * 4. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * DC21285 register definitions */ /* PCI registers in CSR space */ #define VENDOR_ID 0x00 #define DC21285_VENDOR_ID 0x1011 #define DEVICE_ID 0x02 #define DC21285_DEVICE_ID 0x1065 #define REVISION 0x08 #define CLASS 0x0A /* Other PCI control / status registers */ #define OUTBOUND_INT_STATUS 0x030 #define OUTBOUND_INT_MASK 0x034 #define I2O_INBOUND_FIFO 0x040 #define I2O_OUTBOUND_FIFO 0x044 /* Mailbox registers */ #define MAILBOX_0 0x050 #define MAILBOX_1 0x054 #define MAILBOX_2 0x058 #define MAILBOX_3 0x05C #define DOORBELL 0x060 #define DOORBELL_SETUP 0x064 #define ROM_WRITE_BYTE_ADDRESS 0x068 /* DMA Channel registers */ #define DMA_CHAN_1_BYTE_COUNT 0x80 #define DMA_CHAN_1_PCI_ADDR 0x84 #define DMA_CHAN_1_SDRAM_ADDR 0x88 #define DMA_CHAN_1_DESCRIPT 0x8C #define DMA_CHAN_1_CONTROL 0x90 #define DMA_CHAN_2_BYTE_COUNT 0xA0 #define DMA_CHAN_2_PCI_ADDR 0xA4 #define DMA_CHAN_2_SDRAM_ADDR 0xA8 #define DMA_CHAN_2_DESCRIPTOR 0xAC #define DMA_CHAN_2_CONTROL 0xB0 /* Offsets into DMA descriptor */ #define DMA_BYTE_COUNT 0 #define DMA_PCI_ADDRESS 4 #define DMA_SDRAM_ADDRESS 8 #define DMA_NEXT_DESCRIPTOR 12 /* DMA byte count register bits */ #define DMA_INTERBURST_SHIFT 24 #define DMA_PCI_TO_SDRAM 0 #define DMA_SDRAM_TO_PCI (1 << 30) #define DMA_END_CHAIN (1 << 31) /* DMA control bits */ #define DMA_ENABLE (1 << 0) #define DMA_TRANSFER_DONE (1 << 2) #define DMA_ERROR (1 << 3) #define DMA_REGISTOR_DESCRIPTOR (1 << 4) #define DMA_PCI_MEM_READ (0 << 5) #define DMA_PCI_MEM_READ_LINE (1 << 5) #define DMA_PCI_MEM_READ_MULTI1 (2 << 5) #define DMA_PCI_MEM_READ_MULTI2 (3 << 5) #define DMA_CHAIN_DONE (1 << 7) #define DMA_INTERBURST_4 (0 << 8) #define DMA_INTERBURST_8 (1 << 8) #define DMA_INTERBURST_16 (2 << 8) #define DMA_INTERBURST_32 (3 << 8) #define DMA_PCI_LENGTH_8 0 #define DMA_PCI_LENGTH_16 (1 << 15) #define DMA_SDRAM_LENGTH_1 (0 << 16) #define DMA_SDRAM_LENGTH_2 (1 << 16) #define DMA_SDRAM_LENGTH_4 (2 << 16) #define DMA_SDRAM_LENGTH_8 (3 << 16) #define DMA_SDRAM_LENGTH_16 (4 << 16) /* CSR Base Address Mask */ #define CSR_BA_MASK 0x0F8 #define CSR_MASK_128B 0x00000000 #define CSR_MASK_512KB 0x00040000 #define CSR_MASK_1MB 0x000C0000 #define CSR_MASK_2MB 0x001C0000 #define CSR_MASK_4MB 0x003C0000 #define CSR_MASK_8MB 0x007C0000 #define CSR_MASK_16MB 0x00FC0000 #define CSR_MASK_32MB 0x01FC0000 #define CSR_MASK_64MB 0x03FC0000 #define CSR_MASK_128MB 0x07FC0000 #define CSR_MASK_256MB 0x0FFC0000 #define CSR_BA_OFFSET 0x0FC /* SDRAM Base Address Mask */ #define SDRAM_BA_MASK 0x100 #define SDRAM_MASK_256KB 0x00000000 #define SDRAM_MASK_512KB 0x00040000 #define SDRAM_MASK_1MB 0x000C0000 #define SDRAM_MASK_2MB 0x001C0000 #define SDRAM_MASK_4MB 0x003C0000 #define SDRAM_MASK_8MB 0x007C0000 #define SDRAM_MASK_16MB 0x00FC0000 #define SDRAM_MASK_32MB 0x01FC0000 #define SDRAM_MASK_64MB 0x03FC0000 #define SDRAM_MASK_128MB 0x07FC0000 #define SDRAM_MASK_256MB 0x0FFC0000 #define SDRAM_WINDOW_DISABLE (1 << 31) #define SDRAM_BA_OFFSET 0x104 /* Expansion ROM Base Address Mask */ #define EXPANSION_ROM_BA_MASK 0x108 #define ROM_MASK_1MB 0x00000000 #define ROM_MASK_2MB 0x00100000 #define ROM_MASK_4MB 0x00300000 #define ROM_MASK_8MB 0x00700000 #define ROM_MASK_16MB 0x00F00000 #define ROM_WINDOW_DISABLE (1 << 31) /* SDRAM configuration */ #define SDRAM_TIMING 0x10C #define SDRAM_ARRAY_SIZE_0 0x0 #define SDRAM_ARRAY_SIZE_1MB 0x1 #define SDRAM_ARRAY_SIZE_2MB 0x2 #define SDRAM_ARRAY_SIZE_4MB 0x3 #define SDRAM_ARRAY_SIZE_8MB 0x4 #define SDRAM_ARRAY_SIZE_16MB 0x5 #define SDRAM_ARRAY_SIZE_32MB 0x6 #define SDRAM_ARRAY_SIZE_64MB 0x7 #define SDRAM_2_BANKS 0 #define SDRAM_4_BANKS (1 << 3) #define SDRAM_ADDRESS_MUX_SHIFT 4 #define SDRAM_ARRAY_BASE_SHIFT 20 #define SDRAM_ADDRESS_SIZE_0 0x110 #define SDRAM_ADDRESS_SIZE_1 0x114 #define SDRAM_ADDRESS_SIZE_2 0x118 #define SDRAM_ADDRESS_SIZE_3 0x11C /* I2O registers */ #define I2O_INBOUND_FREE_HEAD 0x120 #define I2O_INBOUND_POST_TAIL 0x124 #define I2O_OUTBOUND_POST_HEAD 0x128 #define I2O_OUTBOUND_FREE_TAIL 0x12c #define I2O_INBOUND_FREE_COUNT 0x130 #define I2O_OUTBOUND_POST_COUNT 0x134 #define I2O_INBOUND_POST_COUNT 0x138 /* Control register */ #define SA_CONTROL 0x13C #define INITIALIZE_COMPLETE (1 << 0) #define ASSERT_SERR (1 << 1) #define RECEIVED_SERR (1 << 3) #define SA_SDRAM_PARITY_ERROR (1 << 4) #define PCI_SDRAM_PARITY_ERROR (1 << 5) #define DMA_SDRAM_PARITY_ERROR (1 << 6) #define DISCARD_TIMER_EXPIRED (1 << 8) #define PCI_NOT_RESET (1 << 9) #define WATCHDOG_ENABLE (1 << 13) #define I2O_SIZE_256 (0 << 10) #define I2O_SIZE_512 (1 << 10) #define I2O_SIZE_1024 (2 << 10) #define I2O_SIZE_2048 (3 << 10) #define I2O_SIZE_4096 (4 << 10) #define I2O_SIZE_8192 (5 << 10) #define I2O_SIZE_16384 (6 << 10) #define I2O_SIZE_32768 (7 << 10) #define ROM_WIDTH_8 (3 << 14) #define ROM_WIDTH_16 (1 << 14) #define ROM_WIDTH_32 (2 << 14) #define ROM_ACCESS_TIME_SHIFT 16 #define ROM_BURST_TIME_SHIFT 20 #define ROM_TRISTATE_TIME_SHIFT 24 #define XCS_DIRECTION_SHIFT 28 #define PCI_CENTRAL_FUNCTION (1 << 31) #define PCI_ADDRESS_EXTENSION 0x140 #define PREFETCHABLE_MEM_RANGE 0x144 /* XBUS / PCI Arbiter registers */ #define XBUS_CYCLE_ARBITER 0x148 #define XBUS_CYCLE_0_SHIFT 0 #define XBUS_CYCLE_1_SHIFT 3 #define XBUS_CYCLE_2_SHIFT 6 #define XBUS_CYCLE_3_SHIFT 9 #define XBUS_CYCLE_STROBE_SHIFT 12 #define XBUS_PCI_ARBITER (1 << 23) #define XBUS_INT_IN_L0_LOW 0 #define XBUS_INT_IN_L0_HIGH (1 << 24) #define XBUS_INT_IN_L1_LOW 0 #define XBUS_INT_IN_L1_HIGH (1 << 25) #define XBUS_INT_IN_L2_LOW 0 #define XBUS_INT_IN_L2_HIGH (1 << 26) #define XBUS_INT_IN_L3_LOW 0 #define XBUS_INT_IN_L3_HIGH (1 << 27) #define XBUS_INT_XCS0_LOW 0 #define XBUS_INT_XCS0_HIGH (1 << 28) #define XBUS_INT_XCS1_LOW 0 #define XBUS_INT_XCS1_HIGH (1 << 29) #define XBUS_INT_XCS2_LOW 0 #define XBUS_INT_XCS2_HIGH (1 << 30) #define XBUS_PCI_INT_REQUEST (1 << 31) #define XBUS_IO_STROBE_MASK 0x14C #define XBUS_IO_STROBE_0_SHIFT 0 #define XBUS_IO_STROBE_2_SHIFT 8 #define XBUS_IO_STROBE_3_SHIFT 16 #define XBUS_IO_STROBE_4_SHIFT 24 #define DOORBELL_PCI_MASK 0x150 #define DOORBELL_SA_MASK 0x154 /* UART registers */ #define UART_DATA 0x160 #define UART_RX_STAT 0x164 #define UART_PARITY_ERROR 0x01 #define UART_FRAME_ERROR 0x02 #define UART_OVERRUN_ERROR 0x04 #define UART_RX_ERROR (UART_PARITY_ERROR | UART_FRAME_ERROR \ | UART_OVERRUN_ERROR) #define UART_H_UBRLCR 0x168 #define UART_BREAK 0x01 #define UART_PARITY_ENABLE 0x02 #define UART_ODD_PARITY 0x00 #define UART_EVEN_PARITY 0x04 #define UART_STOP_BITS_1 0x00 #define UART_STOP_BITS_2 0x08 #define UART_ENABLE_FIFO 0x10 #define UART_DATA_BITS_5 0x00 #define UART_DATA_BITS_6 0x20 #define UART_DATA_BITS_7 0x40 #define UART_DATA_BITS_8 0x60 #define UART_M_UBRLCR 0x16C #define UART_L_UBRLCR 0x170 #define UART_BRD(fclk, x) (((fclk) / 4 / 16 / x) - 1) #define UART_CONTROL 0x174 #define UART_ENABLE 0x01 #define UART_SIR_ENABLE 0x02 #define UART_IRDA_ENABLE 0x04 #define UART_FLAGS 0x178 #define UART_TX_BUSY 0x08 #define UART_RX_FULL 0x10 #define UART_TX_EMPTY 0x20 /* Interrupt numbers for IRQ and FIQ registers */ #define IRQ_RESERVED0 0x00 #define IRQ_SOFTINT 0x01 #define IRQ_SERIAL_RX 0x02 #define IRQ_SERIAL_TX 0x03 #define IRQ_TIMER_1 0x04 #define IRQ_TIMER_2 0x05 #define IRQ_TIMER_3 0x06 #define IRQ_TIMER_4 0x07 #define IRQ_IN_L0 0x08 #define IRQ_IN_L1 0x09 #define IRQ_IN_L2 0x0A #define IRQ_IN_L3 0x0B #define IRQ_XCS_L0 0x0C #define IRQ_XCS_L1 0x0D #define IRQ_XCS_L2 0x0E #define IRQ_DOORBELL 0x0F #define IRQ_DMA_1 0x10 #define IRQ_DMA_2 0x11 #define IRQ_PCI 0x12 #define IRQ_PMCSR 0x13 #define IRQ_RESERVED1 0x14 #define IRQ_RESERVED2 0x15 #define IRQ_BIST 0x16 #define IRQ_SERR 0x17 #define IRQ_SDRAM_PARITY 0x18 #define IRQ_I2O 0x19 #define IRQ_RESERVED3 0x1A #define IRQ_DISCARD_TIMER 0x1B #define IRQ_DATA_PARITY 0x1C #define IRQ_MASTER_ABORT 0x1D #define IRQ_TARGET_ABORT 0x1E #define IRQ_PARITY 0x1F /* IRQ and FIQ status / enable registers */ #define IRQ_STATUS 0x180 #define IRQ_RAW_STATUS 0x184 #define IRQ_ENABLE 0x188 #define IRQ_ENABLE_SET 0x188 #define IRQ_ENABLE_CLEAR 0x18c #define IRQ_SOFT 0x190 #define FIQ_STATUS 0x280 #define FIQ_RAW_STATUS 0x284 #define FIQ_ENABLE 0x288 #define FIQ_ENABLE_SET 0x288 #define FIQ_ENABLE_CLEAR 0x28c #define FIQ_SOFT 0x290 /* Timer registers */ /* Relative offsets and bases */ #define TIMER_LOAD 0x00 #define TIMER_VALUE 0x04 #define TIMER_CONTROL 0x08 #define TIMER_CLEAR 0x0C #define TIMER_1_BASE 0x300 #define TIMER_2_BASE 0x320 #define TIMER_3_BASE 0x340 #define TIMER_4_BASE 0x360 /* Control register bits */ #define TIMER_FCLK 0x00 #define TIMER_FCLK_16 0x04 #define TIMER_FCLK_256 0x08 #define TIMER_EXTERNAL 0x0C #define TIMER_MODE_FREERUN 0x00 #define TIMER_MODE_PERIODIC 0x40 #define TIMER_ENABLE 0x80 /* Maximum timer value */ #define TIMER_MAX_VAL 0x00FFFFFF /* Specific registers */ #define TIMER_1_LOAD 0x300 #define TIMER_1_VALUE 0x304 #define TIMER_1_CONTROL 0x308 #define TIMER_1_CLEAR 0x30C #define TIMER_2_LOAD 0x320 #define TIMER_2_VALUE 0x324 #define TIMER_2_CONTROL 0x328 #define TIMER_2_CLEAR 0x32C #define TIMER_3_LOAD 0x340 #define TIMER_3_VALUE 0x344 #define TIMER_3_CONTROL 0x348 #define TIMER_3_CLEAR 0x34C #define TIMER_4_LOAD 0x360 #define TIMER_4_VALUE 0x364 #define TIMER_4_CONTROL 0x368 #define TIMER_4_CLEAR 0x36C /* Miscellaneous definitions */ #ifndef FCLK #define FCLK 50000000 #endif #endif /* DC21285REG_H */ gxemul-0.6.1/src/include/thirdparty/mvme187.h000644 001750 001750 00000006270 13402411502 021213 0ustar00debugdebug000000 000000 /* $OpenBSD: mvme187.h,v 1.9 2006/11/18 22:53:11 miod Exp $ */ /* * Copyright (c) 1996 Nivas Madhur * Copyright (c) 1999 Steve Murphree, Jr. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Nivas Madhur. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* * Mach Operating System * Copyright (c) 1991 Carnegie Mellon University * Copyright (c) 1991 OMRON Corporation * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * */ #ifndef __MACHINE_MVME187_H__ #define __MACHINE_MVME187_H__ #define BUG187_START 0xff800000 /* start of BUG PROM */ #define BUG187_SIZE 0x00400000 /* size of BUG PROM */ #define MVME187_SRAM_START 0xffe00000 /* start of sram used by bug */ #define MVME187_SRAM_SIZE 0x00020000 /* size of sram */ #define OBIO187_START 0xfff40000 /* start of local IO */ #define OBIO187_SIZE 0x000b0000 /* size of obio space */ #define MVME187_SBC_CMMU_I 0xfff77000 /* Single Board Computer code CMMU */ #define MVME187_SBC_CMMU_D 0xfff7f000 /* Single Board Computer data CMMU */ #define M187_ILEVEL 0xfff4203e /* interrupt priority level */ #define M187_IMASK 0xfff4203f /* interrupt mask level */ #define M187_ISRC 0x00000000 /* interrupt mask src (NULL) */ #define M187_IACK 0xfffe0000 /* interrupt ACK base */ #define MVME187_MEM_CTLR 0xfff43000 /* MEMC040 mem controller */ #if defined(_KERNEL) && !defined(_LOCORE) extern u_int32_t pfsr_save_187[]; #endif #endif /* __MACHINE_MVME187_H__ */ gxemul-0.6.1/src/include/thirdparty/hpc_bootinfo.h000644 001750 001750 00000006673 13402411502 022467 0ustar00debugdebug000000 000000 /* gxemul: $Id: hpc_bootinfo.h,v 1.5 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: bootinfo.h,v 1.2 2002/04/14 06:07:40 takemura Exp $ */ /*- * Copyright (c) 1999-2001 * Shin Takemura and PocketBSD Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the PocketBSD project * and its contributors. * 4. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifndef _HPC_BOOTINFO_H_ #define _HPC_BOOTINFO_H_ struct hpc_bootinfo { int16_t length; /* short */ int16_t reserved; /* short */ int32_t magic; /* int */ uint32_t fb_addr; /* void * */ int16_t fb_line_bytes; /* short */ int16_t fb_width; /* short */ int16_t fb_height; /* short */ int16_t fb_type; /* short */ int16_t bi_cnuse; /* short */ uint32_t platid_cpu; /* unsigned long */ uint32_t platid_machine; /* unsigned long */ int32_t timezone; /* long */ }; #define BI_CNUSE_BUILTIN (1<<0) #define BI_CNUSE_SERIAL (1<<1) /* extern struct bootinfo *bootinfo; */ #define HPC_BOOTINFO_MAGIC 0x13536135ULL #define BIFB_D2_M2L_3 0 #define BIFBN_D2_M2L_3 "D2_M2L_3" #define BIFB_D2_M2L_3x2 1 #define BIFBN_D2_M2L_3x2 "D2_M2L_3x2" #define BIFB_D2_M2L_0 2 #define BIFBN_D2_M2L_0 "D2_M2L_0" #define BIFB_D8_00 3 #define BIFBN_D8_00 "D8_00" #define BIFB_D8_FF 4 #define BIFBN_D8_FF "D8_FF" #define BIFB_D16_0000 5 #define BIFBN_D16_0000 "D16_0000" #define BIFB_D16_FFFF 6 #define BIFBN_D16_FFFF "D16_FFFF" #define BIFB_D2_M2L_0x2 7 #define BIFBN_D2_M2L_0x2 "D2_M2L_0x2" #define BIFB_D4_M2L_F 8 #define BIFBN_D4_M2L_F "D4_M2L_F" #define BIFB_D4_M2L_Fx2 9 #define BIFBN_D4_M2L_Fx2 "D4_M2L_Fx2" #define BIFB_D4_M2L_0 10 #define BIFBN_D4_M2L_0 "D4_M2L_0" #define BIFB_D4_M2L_0x2 11 #define BIFBN_D4_M2L_0x2 "D4_M2L_0x2" #define BIFB_D1_M2L_0 12 #define BIFBN_D1_M2L_0 "D1_M2L_0" #define BIFB_D1_M2L_1 13 #define BIFBN_D1_M2L_1 "D1_M2L_1" #endif /* _HPC_BOOTINFO_H_ */ gxemul-0.6.1/src/include/thirdparty/dreamcast_pvr.h000644 001750 001750 00000031777 13402411502 022653 0ustar00debugdebug000000 000000 /* GXemul: $Id: dreamcast_pvr.h,v 1.6 2006-10-31 08:27:26 debug Exp $ */ /* $NetBSD: pvr.c,v 1.22 2006/04/12 19:38:22 jmmv Exp $ */ #ifndef DREAMCAST_PVR_H #define DREAMCAST_PVR_H /* * Note: This was pvr.c in NetBSD. It has been extended with reasonably * similar symbolnames from http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt. * * There are still many things missing. */ /*- * Copyright (c) 2001 Marcus Comstedt. * Copyright (c) 2001 Jason R. Thorpe. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Marcus Comstedt. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1998, 1999 Tohru Nishimura. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Tohru Nishimura * for the NetBSD Project. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define PVRREG_FBSTART 0x05000000 #define PVRREG_REGSTART 0x005f8000 #define PVRREG_REGSIZE 0x00002000 #define PVRREG_ID 0x00 #define PVRREG_REVISION 0x04 #define PVR_REVISION_MINOR_MASK 0xf #define PVR_REVISION_MAJOR_MASK 0xf0 #define PVR_REVISION_MAJOR_SHIFT 4 #define PVRREG_RESET 0x08 #define PVR_RESET_TA 0x00000001 #define PVR_RESET_PVR 0x00000002 #define PVR_RESET_BUS 0x00000004 #define PVRREG_STARTRENDER 0x14 #define PVRREG_OB_ADDR 0x20 /* Object Buffer start address. Bits 0..19 should always be zero. */ // #define PVR_OB_ADDR_MASK 0x00f00000 // GXemul change: In order to get Marcus Comstedt's "tatest" demo to // run, which uses bit 19, I've had to change this: #define PVR_OB_ADDR_MASK 0x00f80000 #define PVRREG_TILEBUF_ADDR 0x2c #define PVR_TILEBUF_ADDR_MASK 0x00fffff8 #define PVRREG_SPANSORT 0x30 #define PVR_SPANSORT_SPAN0 0x00000001 #define PVR_SPANSORT_SPAN1 0x00000100 #define PVR_SPANSORT_TSP_CACHE_ENABLE 0x00010000 #define PVRREG_BRDCOLR 0x40 #define BRDCOLR_BLUE(x) ((x) << 0) #define BRDCOLR_GREEN(x) ((x) << 8) #define BRDCOLR_RED(x) ((x) << 16) #define PVRREG_DIWMODE 0x44 #define DIWMODE_DE (1U << 0) /* display enable */ #define DIWMODE_SD (1U << 1) /* scan double enable */ #define DIWMODE_COL(x) ((x) << 2) #define DIWMODE_COL_RGB555 DIWMODE_COL(0) /* RGB555, 16-bit */ #define DIWMODE_COL_RGB565 DIWMODE_COL(1) /* RGB565, 16-bit */ #define DIWMODE_COL_RGB888 DIWMODE_COL(2) /* RGB888, 24-bit */ #define DIWMODE_COL_ARGB888 DIWMODE_COL(3) /* RGB888, 32-bit */ #define DIWMODE_C (1U << 23) /* 2x clock enable (VGA) */ #define DIWMODE_DE_MASK 0x00000001 #define DIWMODE_SD_MASK 0x00000002 /* Line double */ #define DIWMODE_COL_MASK 0x0000000c /* Pixel mode */ #define DIWMODE_COL_SHIFT 2 #define DIWMODE_EX_MASK 0x00000070 /* Extend bits */ #define DIWMODE_EX_SHIFT 4 #define DIWMODE_TH_MASK 0x0000ff00 /* ARGB8888 threshold */ #define DIWMODE_TH_SHIFT 8 #define DIWMODE_SL_MASK 0x003f0000 /* Strip Length */ #define DIWMODE_SL_SHIFT 16 #define DIWMODE_SE_MASK 0x00400000 /* Strip Buffer enabled */ #define DIWMODE_C_MASK 0x00800000 /* Clock double */ #define PVRREG_FB_RENDER_CFG 0x48 #define FB_RENDER_CFG_RENDER_MODE_MASK 0x07 /* render mode: 0: RGB0555 (2 bytes/pixel, alpha is inserted into bit15) 1: RGB565 (2 bytes/pixel) 2: ARGB4444 (2 bytes/pixel) 3: ARGB1555 (2 bytes/pixel, alpha is determined by threshold) 4: RGB888 (3 bytes/pixel) 5: RGB0888 (4 bytes/pixel, alpha is inserted into bit24-31) 6: ARGB8888 (4 bytes/pixel) 7: ARGB4444 (2 bytes/pixel, same as 2?) */ #define FB_RENDER_CFG_DITHER (1 << 3) #define FB_RENDER_CFG_ALPHA_MASK 0x0000ff00 #define FB_RENDER_CFG_ALPHA_SHFIT 8 #define FB_RENDER_CFG_THRESHOLD_MASK 0x00ff0000 #define FB_RENDER_CFG_THRESHOLD_SHFIT 8 #define PVRREG_FB_RENDER_MODULO 0x4c #define FB_RENDER_MODULO_MASK 0x000001ff /* TODO */ #define PVRREG_DIWADDRL 0x50 #define PVRREG_DIWADDRS 0x54 #define PVRREG_DIWSIZE 0x5c #define DIWSIZE_DPL(x) ((x) << 0) /* pixel data per line */ #define DIWSIZE_LPF(x) ((x) << 10) /* lines per field */ #define DIWSIZE_MODULO(x) ((x) << 20) /* words to skip + 1 */ #define DIWSIZE_MASK 0x3ff /* All fields are 10 bits. */ #define DIWSIZE_DPL_SHIFT 0 #define DIWSIZE_LPF_SHIFT 10 #define DIWSIZE_MODULO_SHIFT 20 #define PVRREG_FB_RENDER_ADDR1 0x60 /* Odd interlace lines */ #define PVRREG_FB_RENDER_ADDR2 0x64 /* Even interlace lines */ #define PVRREG_FB_CLIP_X 0x68 /* horizontal pixel clipping area - 1 */ #define PVRREG_FB_CLIP_Y 0x6c /* vertical pixel clipping area - 1 */ #define FB_CLIP_XY_MIN_MASK 0x000007ff #define FB_CLIP_XY_MAX_MASK 0x07ff0000 /* e.g. 640 for x */ #define FB_CLIP_XY_MAX_SHIFT 16 #define PVRREG_SHADOW 0x74 #define SHADOW_INTENSITY_MASK 0x000000ff #define SHADOW_ENABLE (1 << 8) #define PVRREG_OBJECT_CLIP 0x78 /* float, position of polygon culling */ #define PVRREG_OB_CFG 0x7c /* TODO */ #define PVRREG_UNKNOWN_80 0x80 #define PVRREG_UNKNOWN_84 0x84 #define PVRREG_BGPLANE_Z 0x88 /* float */ #define PVRREG_BGPLANE_CFG 0x8c /* TODO */ #define PVRREG_ISP_CFG 0x98 /* TODO */ #define PVRREG_VRAM_CFG1 0xa0 #define VRAM_CFG1_GOOD_REFRESH_VALUE 0x20 #define PVRREG_VRAM_CFG2 0xa4 #define VRAM_CFG2_UNKNOWN_MAGIC 0x0000001f #define PVRREG_VRAM_CFG3 0xa8 #define VRAM_CFG3_UNKNOWN_MAGIC 0x15d1c951 #define PVRREG_FOG_TABLE_COL 0xb0 #define PVRREG_FOG_VERTEX_COL 0xb4 #define PVRREG_FOG_DENSITY 0xb8 /* TODO */ #define PVRREG_CLAMP_MAX 0xbc /* maximum color */ #define PVRREG_CLAMP_MIN 0xc0 /* minimum color */ #define PVRREG_HPOS_IRQ 0xc8 /* http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt */ #define PVRREG_RASEVTPOS 0xcc /* vpos_irq according to powervr-reg.txt */ #define RASEVTPOS_POS2_MASK 0x000003ff #define RASEVTPOS_POS1_MASK 0x03ff0000 #define RASEVTPOS_POS1_SHIFT 16 #define RASEVTPOS_BOTTOM(x) ((x) << 0) #define RASEVTPOS_TOP(x) ((x) << 16) #define PVRREG_SYNCCONF 0xd0 #define SYNCCONF_VP (1U << 0) /* V-sync polarity */ #define SYNCCONF_HP (1U << 1) /* H-sync polarity */ #define SYNCCONF_I (1U << 4) /* interlace */ #define SYNCCONF_BC(x) (1U << 6) /* broadcast standard */ #define SYNCCONF_VO (1U << 8) /* video output enable */ #define SYNCCONF_VO_MASK 0x00000100 #define SYNCCONF_BC_MASK 0x000000c0 #define SYNCCONF_BC_SHIFT 6 #define SYNCCONF_BC_VGA 0 #define SYNCCONF_BC_NTSC 1 #define SYNCCONF_BC_PAL 2 #define SYNCCONF_I_MASK 0x00000010 #define SYNCCONF_HP_MASK 0x00000004 /* Positive H-sync */ #define SYNCCONF_VP_MASK 0x00000002 /* Positive V-sync */ #define PVRREG_BRDHORZ 0xd4 #define BRDHORZ_STOP_MASK 0x0000ffff #define BRDHORZ_START_MASK 0xffff0000 #define BRDHORZ_START_SHIFT 16 #define BRDHORZ_STOP(x) ((x) << 0) #define BRDHORZ_START(x) ((x) << 16) #define PVRREG_SYNCSIZE 0xd8 #define SYNCSIZE_H_MASK 0x0000ffff #define SYNCSIZE_V_MASK 0xffff0000 #define SYNCSIZE_V_SHIFT 16 #define SYNCSIZE_H(x) ((x) << 0) #define SYNCSIZE_V(x) ((x) << 16) #define PVRREG_BRDVERT 0xdc #define BRDVERT_STOP_MASK 0x0000ffff #define BRDVERT_START_MASK 0xffff0000 #define BRDVERT_START_SHIFT 16 #define BRDVERT_STOP(x) ((x) << 0) #define BRDVERT_START(x) ((x) << 16) #define PVRREG_SYNCH_WIDTH 0xe0 /* http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt */ #define PVRREG_TSP_CFG 0xe4 /* http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt */ #define TSP_CFG_CBE (1 << 17) /* codebook enable */ #define TSP_CFG_IE (1 << 16) /* index enable */ #define TSP_CFG_MODULO_MASK 0x1f /* modulo */ #define PVRREG_DIWCONF 0xe8 #define DIWCONF_BLANK (1U << 3) /* blank screen */ #define DIWCONF_LR (1U << 8) /* low-res (320 horizontal) */ #define DIWCONF_MAGIC_MASK 0x003f0000 #define DIWCONF_MAGIC (22 << 16) #define PVRREG_DIWHSTRT 0xec #define DIWVSTRT_HPOS_MASK 0x000003ff #define PVRREG_DIWVSTRT 0xf0 #define DIWVSTRT_V1_MASK 0x000003ff #define DIWVSTRT_V2_MASK 0x03ff0000 #define DIWVSTRT_V2_SHIFT 16 #define DIWVSTRT_V1(x) ((x) << 0) #define DIWVSTRT_V2(x) ((x) << 16) #define PVRREG_SCALER_CFG 0xf4 #define PVRREG_PALETTE_CFG 0x108 #define PVR_PALETTE_CFG_MODE_MASK 0x3 #define PVR_PALETTE_CFG_MODE_ARGB1555 0x0 #define PVR_PALETTE_CFG_MODE_RGB565 0x1 #define PVR_PALETTE_CFG_MODE_ARGB4444 0x2 #define PVR_PALETTE_CFG_MODE_ARGB8888 0x3 #define PVRREG_SYNC_STAT 0x10c #define PVR_SYNC_STAT_VPOS_MASK 0x000003ff #define PVR_SYNC_STAT_INTERLACE_FIELD_EVEN 0x00000400 #define PVR_SYNC_STAT_HBLANK 0x00001000 #define PVR_SYNC_STAT_VBLANK 0x00002000 #define PVRREG_MAGIC_110 0x110 #define MAGIC_110_VALUE 0x93f39 #define PVRREG_TA_LUMINANCE 0x118 /* todo */ #define PVRREG_TA_OPB_START 0x124 #define TA_OPB_START_MASK 0x00ffff80 #define PVRREG_TA_OB_START 0x128 #define TA_OB_START_MASK 0x00fffff8 #define PVRREG_TA_OPB_END 0x12c #define TA_OPB_END_MASK 0x00ffff80 #define PVRREG_TA_OB_END 0x130 #define TA_OB_END_MASK 0x00fffff8 #define PVRREG_TA_OPB_POS 0x134 #define TA_OPB_POS_MASK 0x00ffff80 #define PVRREG_TA_OB_POS 0x138 #define TA_OB_POS_MASK 0x00fffff8 #define PVRREG_TILEBUF_SIZE 0x13c #define TILEBUF_SIZE_HEIGHT_MASK 0xffff0000 #define TILEBUF_SIZE_HEIGHT_SHIFT 16 #define TILEBUF_SIZE_WIDTH_MASK 0x0000ffff #define PVRREG_TA_OPB_CFG 0x140 #define TA_OPB_CFG_OPAQUEPOLY_MASK 0x00000003 #define TA_OPB_CFG_OPAQUEMOD_MASK 0x00000030 #define TA_OPB_CFG_OPAQUEMOD_SHIFT 4 #define TA_OPB_CFG_TRANSPOLY_MASK 0x00000300 #define TA_OPB_CFG_TRANSPOLY_SHIFT 8 #define TA_OPB_CFG_TRANSMOD_MASK 0x00003000 #define TA_OPB_CFG_TRANSMOD_SHIFT 12 #define TA_OPB_CFG_PUNCHTHROUGH_MASK 0x00030000 #define TA_OPB_CFG_PUNCHTHROUGH_SHIFT 16 #define TA_OPB_CFG_OPBDIR 0x00100000 #define PVRREG_TA_INIT 0x144 #define PVR_TA_INIT 0x80000000 #define PVRREG_YUV_ADDR 0x148 #define PVR_YUV_ADDR_MASK 0x00ffffe0 #define PVRREG_YUV_CFG1 0x14c /* TODO */ #define PVRREG_YUV_STAT 0x150 /* Nr of currently converted 16x16 macro blocks. */ #define PVR_YUV_STAT_BLOCKS_MASK 0x1fff #define PVRREG_TA_OPL_REINIT 0x160 #define PVR_TA_OPL_REINIT 0x80000000 #define PVRREG_TA_OPL_INIT 0x164 /* Start of Object Pointer List allocation in VRAM. */ #define PVR_TA_OPL_INIT_MASK 0x00ffff80 #define PVRREG_FOG_TABLE 0x0200 #define PVR_FOG_TABLE_SIZE 0x0200 #define PVRREG_PALETTE 0x1000 #define PVR_PALETTE_SIZE 0x1000 #endif /* DREAMCAST_PVR_H */ gxemul-0.6.1/src/include/thirdparty/alpha_cpu.h000644 001750 001750 00000037463 13402411502 021753 0ustar00debugdebug000000 000000 /* GXemul: $Id: alpha_cpu.h,v 1.2 2006-09-01 16:40:57 debug Exp $ */ /* $NetBSD: alpha_cpu.h,v 1.48 2006/02/16 20:17:13 perry Exp $ */ #ifndef __ALPHA_ALPHA_CPU_H__ #define __ALPHA_ALPHA_CPU_H__ /* * Copyright (c) 1996 Carnegie-Mellon University. * All rights reserved. * * Author: Chris G. Demetriou * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * Alpha CPU + OSF/1 PALcode definitions for use by the kernel. * * Definitions for: * * Process Control Block * Interrupt/Exception/Syscall Stack Frame * Processor Status Register * Machine Check Error Summary Register * Machine Check Logout Area * Per CPU state Management of Machine Check Handling * Virtual Memory Management * Kernel Entry Vectors * MMCSR Fault Type Codes * Translation Buffer Invalidation * * and miscellaneous PALcode operations. */ /* * Process Control Block definitions [OSF/1 PALcode Specific] * * GXemul note: all of these uint64_t were 'unsigned long' in the original * NetBSD header file, and the uint32_t were 'unsigned int'. */ struct alpha_pcb { uint64_t apcb_ksp; /* kernel stack ptr */ uint64_t apcb_usp; /* user stack ptr */ uint64_t apcb_ptbr; /* page table base reg */ uint32_t apcb_cpc; /* charged process cycles */ uint32_t apcb_asn; /* address space number */ uint64_t apcb_unique; /* process unique value */ #define apcb_backup_ksp apcb_unique /* backup kernel stack ptr */ uint64_t apcb_flags; /* flags; see below */ uint64_t apcb_decrsv0; /* DEC reserved */ uint64_t apcb_decrsv1; /* DEC reserved */ }; #define ALPHA_PCB_FLAGS_FEN 0x0000000000000001 #define ALPHA_PCB_FLAGS_PME 0x4000000000000000 /* * Interrupt/Exception/Syscall "Hardware" (really PALcode) * Stack Frame definitions * * These are quadword offsets from the sp on kernel entry, i.e. * to get to the value in question you access (sp + (offset * 8)). * * On syscall entry, A0-A2 aren't written to memory but space * _is_ reserved for them. */ #define ALPHA_HWFRAME_PS 0 /* processor status register */ #define ALPHA_HWFRAME_PC 1 /* program counter */ #define ALPHA_HWFRAME_GP 2 /* global pointer */ #define ALPHA_HWFRAME_A0 3 /* a0 */ #define ALPHA_HWFRAME_A1 4 /* a1 */ #define ALPHA_HWFRAME_A2 5 /* a2 */ #define ALPHA_HWFRAME_SIZE 6 /* 6 8-byte words */ /* * Processor Status Register [OSF/1 PALcode Specific] * * Includes user/kernel mode bit, interrupt priority levels, etc. */ #define ALPHA_PSL_USERMODE 0x0008 /* set -> user mode */ #define ALPHA_PSL_IPL_MASK 0x0007 /* interrupt level mask */ #define ALPHA_PSL_IPL_0 0x0000 /* all interrupts enabled */ #define ALPHA_PSL_IPL_SOFT 0x0001 /* software ints disabled */ #define ALPHA_PSL_IPL_IO 0x0004 /* I/O dev ints disabled */ #define ALPHA_PSL_IPL_CLOCK 0x0005 /* clock ints disabled */ #define ALPHA_PSL_IPL_HIGH 0x0006 /* all but mchecks disabled */ #define ALPHA_PSL_MUST_BE_ZERO 0xfffffffffffffff0 /* Convenience constants: what must be set/clear in user mode */ #define ALPHA_PSL_USERSET ALPHA_PSL_USERMODE #define ALPHA_PSL_USERCLR (ALPHA_PSL_MUST_BE_ZERO | ALPHA_PSL_IPL_MASK) /* * Interrupt Type Code Definitions [OSF/1 PALcode Specific] */ #define ALPHA_INTR_XPROC 0 /* interprocessor interrupt */ #define ALPHA_INTR_CLOCK 1 /* clock interrupt */ #define ALPHA_INTR_ERROR 2 /* correctable error or mcheck */ #define ALPHA_INTR_DEVICE 3 /* device interrupt */ #define ALPHA_INTR_PERF 4 /* performance counter */ #define ALPHA_INTR_PASSIVE 5 /* passive release */ /* * Machine Check Error Summary Register definitions [OSF/1 PALcode Specific] * * The following bits are values as read. On write, _PCE, _SCE, and * _MIP are "write 1 to clear." */ #define ALPHA_MCES_IMP \ 0xffffffff00000000 /* impl. dependent */ #define ALPHA_MCES_RSVD \ 0x00000000ffffffe0 /* reserved */ #define ALPHA_MCES_DSC \ 0x0000000000000010 /* disable system correctable error reporting */ #define ALPHA_MCES_DPC \ 0x0000000000000008 /* disable processor correctable error reporting */ #define ALPHA_MCES_PCE \ 0x0000000000000004 /* processor correctable error in progress */ #define ALPHA_MCES_SCE \ 0x0000000000000002 /* system correctable error in progress */ #define ALPHA_MCES_MIP \ 0x0000000000000001 /* machine check in progress */ /* * Machine Check Error Summary Register definitions [OSF/1 PALcode Specific] * * Note that these are *generic* OSF/1 PALcode specific defines. There are * platform variations to these entities. * * GXemul note: These uint32_t were 'unsigned int' in the original NetBSD * header file. */ struct alpha_logout_area { uint32_t la_frame_size; /* frame size */ uint32_t la_flags; /* flags; see below */ uint32_t la_cpu_offset; /* offset to cpu area */ uint32_t la_system_offset; /* offset to system area */ }; #define ALPHA_LOGOUT_FLAGS_RETRY 0x80000000 /* OK to continue */ #define ALPHA_LOGOUT_FLAGS_SE 0x40000000 /* second error */ #define ALPHA_LOGOUT_FLAGS_SBZ 0x3fffffff /* should be zero */ #define ALPHA_LOGOUT_NOT_BUILT \ (struct alpha_logout_area *)0xffffffffffffffff) #define ALPHA_LOGOUT_PAL_AREA(lap) \ (unsigned long *)((unsigned char *)(lap) + 16) #define ALPHA_LOGOUT_PAL_SIZE(lap) \ ((lap)->la_cpu_offset - 16) #define ALPHA_LOGOUT_CPU_AREA(lap) \ (unsigned long *)((unsigned char *)(lap) + (lap)->la_cpu_offset) #define ALPHA_LOGOUT_CPU_SIZE(lap) \ ((lap)->la_system_offset - (lap)->la_cpu_offset) #define ALPHA_LOGOUT_SYSTEM_AREA(lap) \ (unsigned long *)((unsigned char *)(lap) + (lap)->la_system_offset) #define ALPHA_LOGOUT_SYSTEM_SIZE(lap) \ ((lap)->la_frame_size - (lap)->la_system_offset) /* types of machine checks */ #define ALPHA_SYS_ERROR 0x620 /* System correctable error */ #define ALPHA_PROC_ERROR 0x630 /* Processor correctable error */ #define ALPHA_SYS_MCHECK 0x660 /* System machine check */ #define ALPHA_PROC_MCHECK 0x670 /* Processor machine check */ /* * Virtual Memory Management definitions [OSF/1 PALcode Specific] * * Includes user and kernel space addresses and information, * page table entry definitions, etc. * * NOTE THAT THESE DEFINITIONS MAY CHANGE IN FUTURE ALPHA CPUS! */ #define ALPHA_PGSHIFT 13 #define ALPHA_PGBYTES (1 << ALPHA_PGSHIFT) #define ALPHA_USEG_BASE 0 /* virtual */ #define ALPHA_USEG_END 0x000003ffffffffffULL #define ALPHA_K0SEG_BASE 0xfffffc0000000000ULL /* direct-mapped */ #define ALPHA_K0SEG_END 0xfffffdffffffffffULL #define ALPHA_K1SEG_BASE 0xfffffe0000000000ULL /* virtual */ #define ALPHA_K1SEG_END 0xffffffffffffffffULL #define ALPHA_K0SEG_TO_PHYS(x) ((x) & ~ALPHA_K0SEG_BASE) #define ALPHA_PHYS_TO_K0SEG(x) ((x) | ALPHA_K0SEG_BASE) #define ALPHA_PTE_VALID 0x0001 #define ALPHA_PTE_FAULT_ON_READ 0x0002 #define ALPHA_PTE_FAULT_ON_WRITE 0x0004 #define ALPHA_PTE_FAULT_ON_EXECUTE 0x0008 #define ALPHA_PTE_ASM 0x0010 /* addr. space match */ #define ALPHA_PTE_GRANULARITY 0x0060 /* granularity hint */ #define ALPHA_PTE_PROT 0xff00 #define ALPHA_PTE_KR 0x0100 #define ALPHA_PTE_UR 0x0200 #define ALPHA_PTE_KW 0x1000 #define ALPHA_PTE_UW 0x2000 #define ALPHA_PTE_WRITE (ALPHA_PTE_KW | ALPHA_PTE_UW) #define ALPHA_PTE_SOFTWARE 0x00000000ffff0000 #define ALPHA_PTE_PALCODE (~ALPHA_PTE_SOFTWARE) /* shorthand */ #define ALPHA_PTE_PFN 0xffffffff00000000 #define ALPHA_PTE_TO_PFN(pte) ((pte) >> 32) #define ALPHA_PTE_FROM_PFN(pfn) ((pfn) << 32) typedef unsigned long alpha_pt_entry_t; /* * Kernel Entry Vectors. [OSF/1 PALcode Specific] */ #define ALPHA_KENTRY_INT 0 #define ALPHA_KENTRY_ARITH 1 #define ALPHA_KENTRY_MM 2 #define ALPHA_KENTRY_IF 3 #define ALPHA_KENTRY_UNA 4 #define ALPHA_KENTRY_SYS 5 /* * MMCSR Fault Type Codes. [OSF/1 PALcode Specific] */ #define ALPHA_MMCSR_INVALTRANS 0 #define ALPHA_MMCSR_ACCESS 1 #define ALPHA_MMCSR_FOR 2 #define ALPHA_MMCSR_FOE 3 #define ALPHA_MMCSR_FOW 4 /* * Instruction Fault Type Codes. [OSF/1 PALcode Specific] */ #define ALPHA_IF_CODE_BPT 0 #define ALPHA_IF_CODE_BUGCHK 1 #define ALPHA_IF_CODE_GENTRAP 2 #define ALPHA_IF_CODE_FEN 3 #define ALPHA_IF_CODE_OPDEC 4 #ifdef _KERNEL /* * Translation Buffer Invalidation definitions [OSF/1 PALcode Specific] */ #define ALPHA_TBIA() alpha_pal_tbi(-2, 0) /* all TB entries */ #define ALPHA_TBIAP() alpha_pal_tbi(-1, 0) /* all per-process */ #define ALPHA_TBISI(va) alpha_pal_tbi(1, (va)) /* ITB entry for va */ #define ALPHA_TBISD(va) alpha_pal_tbi(2, (va)) /* DTB entry for va */ #define ALPHA_TBIS(va) alpha_pal_tbi(3, (va)) /* all for va */ #endif /* _KERNEL */ /* * Bits used in the amask instruction [EV56 and later] */ #define ALPHA_AMASK_BWX 0x0001 /* byte/word extension */ #define ALPHA_AMASK_FIX 0x0002 /* floating point conv. ext. */ #define ALPHA_AMASK_CIX 0x0004 /* count extension */ #define ALPHA_AMASK_MVI 0x0100 /* multimedia extension */ #define ALPHA_AMASK_PAT 0x0200 /* precise arith. traps */ #define ALPHA_AMASK_PMI 0x1000 /* prefetch w/ modify intent */ #define ALPHA_AMASK_ALL (ALPHA_AMASK_BWX|ALPHA_AMASK_FIX| \ ALPHA_AMASK_CIX|ALPHA_AMASK_MVI| \ ALPHA_AMASK_PAT|ALPHA_AMASK_PMI) #define ALPHA_AMASK_BITS \ "\20\17PMI\12PAT\11MVI\3CIX\2FIX\1BWX" /* * Chip family IDs returned by implver instruction */ #define ALPHA_IMPLVER_EV4 0 /* LCA/EV4/EV45 */ #define ALPHA_IMPLVER_EV5 1 /* EV5/EV56/PCA56 */ #define ALPHA_IMPLVER_EV6 2 /* EV6 */ #define ALPHA_IMPLVER_EV7 3 /* EV7/EV79 */ #ifdef _KERNEL /* * Maximum processor ID we allow from `whami', and related constants. * * XXX This is not really processor or PALcode specific, but this is * a convenient place to put these definitions. * * XXX This is clipped at 63 so that we can use `long's for proc bitmasks. */ #define ALPHA_WHAMI_MAXID 63 #define ALPHA_MAXPROCS (ALPHA_WHAMI_MAXID + 1) /* * Misc. support routines. */ const char *alpha_dsr_sysname(void); /* * Stubs for Alpha instructions normally inaccessible from C. */ unsigned long alpha_amask(unsigned long); unsigned long alpha_implver(void); #endif /* _KERNEL */ #if 0 /* XXX Expose the insn wrappers to userspace, for now. */ static __inline unsigned long alpha_rpcc(void) { unsigned long v0; __asm volatile("rpcc %0" : "=r" (v0)); return (v0); } #define alpha_mb() __asm volatile("mb" : : : "memory") #define alpha_wmb() __asm volatile("mb" : : : "memory") /* XXX */ #endif #if defined(_KERNEL) || defined(_STANDALONE) /* * Stubs for OSF/1 PALcode operations. */ #include void alpha_pal_cflush(unsigned long); void alpha_pal_halt(void) __attribute__((__noreturn__)); unsigned long _alpha_pal_swpipl(unsigned long); /* for profiling */ void alpha_pal_wrent(void *, unsigned long); void alpha_pal_wrvptptr(unsigned long); #define alpha_pal_draina() __asm volatile("call_pal %0 # PAL_draina" \ : : "i" (PAL_draina) : "memory") #define alpha_pal_imb() __asm volatile("call_pal %0 # PAL_imb" \ : : "i" (PAL_imb) : "memory") static __inline unsigned long alpha_pal_rdmces(void) { register unsigned long v0 __asm("$0"); __asm volatile("call_pal %1 # PAL_OSF1_rdmces" : "=r" (v0) : "i" (PAL_OSF1_rdmces) /* clobbers t0, t8..t11 */ : "$1", "$22", "$23", "$24", "$25"); return (v0); } static __inline unsigned long alpha_pal_rdps(void) { register unsigned long v0 __asm("$0"); __asm volatile("call_pal %1 # PAL_OSF1_rdps" : "=r" (v0) : "i" (PAL_OSF1_rdps) /* clobbers t0, t8..t11 */ : "$1", "$22", "$23", "$24", "$25"); return (v0); } static __inline unsigned long alpha_pal_rdunique(void) { register unsigned long v0 __asm("$0"); __asm volatile("call_pal %1 # PAL_rdunique" : "=r" (v0) : "i" (PAL_rdunique)); return (v0); } static __inline unsigned long alpha_pal_rdusp(void) { register unsigned long v0 __asm("$0"); __asm volatile("call_pal %1 # PAL_OSF1_rdusp" : "=r" (v0) : "i" (PAL_OSF1_rdusp) /* clobbers t0, t8..t11 */ : "$1", "$22", "$23", "$24", "$25"); return (v0); } static __inline unsigned long alpha_pal_rdval(void) { register unsigned long v0 __asm("$0"); __asm volatile("call_pal %1 # PAL_OSF1_rdval" : "=r" (v0) : "i" (PAL_OSF1_rdval) /* clobbers t0, t8..t11 */ : "$1", "$22", "$23", "$24", "$25"); return (v0); } static __inline unsigned long alpha_pal_swpctx(unsigned long ctx) { register unsigned long a0 __asm("$16") = ctx; register unsigned long v0 __asm("$0"); __asm volatile("call_pal %2 # PAL_OSF1_swpctx" : "=r" (a0), "=r" (v0) : "i" (PAL_OSF1_swpctx), "0" (a0) /* clobbers t0, t8..t11, a0 (above) */ : "$1", "$22", "$23", "$24", "$25", "memory"); return (v0); } static __inline unsigned long alpha_pal_swpipl(unsigned long ipl) { register unsigned long a0 __asm("$16") = ipl; register unsigned long v0 __asm("$0"); __asm volatile("call_pal %2 # PAL_OSF1_swpipl" : "=r" (a0), "=r" (v0) : "i" (PAL_OSF1_swpipl), "0" (a0) /* clobbers t0, t8..t11, a0 (above) */ : "$1", "$22", "$23", "$24", "$25", "memory"); return (v0); } static __inline void alpha_pal_tbi(unsigned long op, vaddr_t va) { register unsigned long a0 __asm("$16") = op; register unsigned long a1 __asm("$17") = va; __asm volatile("call_pal %2 # PAL_OSF1_tbi" : "=r" (a0), "=r" (a1) : "i" (PAL_OSF1_tbi), "0" (a0), "1" (a1) /* clobbers t0, t8..t11, a0 (above), a1 (above) */ : "$1", "$22", "$23", "$24", "$25"); } static __inline unsigned long alpha_pal_whami(void) { register unsigned long v0 __asm("$0"); __asm volatile("call_pal %1 # PAL_OSF1_whami" : "=r" (v0) : "i" (PAL_OSF1_whami) /* clobbers t0, t8..t11 */ : "$1", "$22", "$23", "$24", "$25"); return (v0); } static __inline void alpha_pal_wrfen(unsigned long onoff) { register unsigned long a0 __asm("$16") = onoff; __asm volatile("call_pal %1 # PAL_OSF1_wrfen" : "=r" (a0) : "i" (PAL_OSF1_wrfen), "0" (a0) /* clobbers t0, t8..t11, a0 (above) */ : "$1", "$22", "$23", "$24", "$25"); } static __inline void alpha_pal_wripir(unsigned long cpu_id) { register unsigned long a0 __asm("$16") = cpu_id; __asm volatile("call_pal %1 # PAL_ipir" : "=r" (a0) : "i" (PAL_ipir), "0" (a0) /* clobbers t0, t8..t11, a0 (above) */ : "$1", "$22", "$23", "$24", "$25"); } static __inline void alpha_pal_wrunique(unsigned long unique) { register unsigned long a0 __asm("$16") = unique; __asm volatile("call_pal %1 # PAL_wrunique" : "=r" (a0) : "i" (PAL_wrunique), "0" (a0)); } static __inline void alpha_pal_wrusp(unsigned long usp) { register unsigned long a0 __asm("$16") = usp; __asm volatile("call_pal %1 # PAL_OSF1_wrusp" : "=r" (a0) : "i" (PAL_OSF1_wrusp), "0" (a0) /* clobbers t0, t8..t11, a0 (above) */ : "$1", "$22", "$23", "$24", "$25"); } static __inline void alpha_pal_wrmces(unsigned long mces) { register unsigned long a0 __asm("$16") = mces; __asm volatile("call_pal %1 # PAL_OSF1_wrmces" : "=r" (a0) : "i" (PAL_OSF1_wrmces), "0" (a0) /* clobbers t0, t8..t11 */ : "$1", "$22", "$23", "$24", "$25"); } static __inline void alpha_pal_wrval(unsigned long val) { register unsigned long a0 __asm("$16") = val; __asm volatile("call_pal %1 # PAL_OSF1_wrval" : "=r" (a0) : "i" (PAL_OSF1_wrval), "0" (a0) /* clobbers t0, t8..t11, a0 (above) */ : "$1", "$22", "$23", "$24", "$25"); } #endif /* _KERNEL */ #endif /* __ALPHA_ALPHA_CPU_H__ */ gxemul-0.6.1/src/include/thirdparty/dec_bootinfo.h000644 001750 001750 00000005315 13402411502 022440 0ustar00debugdebug000000 000000 /* gxemul: $Id: dec_bootinfo.h,v 1.4 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: bootinfo.h,v 1.5 2000/01/09 15:34:41 ad Exp $ */ /* * Copyright (c) 1997 * Matthias Drochner. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project * by Matthias Drochner. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef _PMAX_BOOTINFO_H_ #define _PMAX_BOOTINFO_H_ #define BOOTINFO_MAGIC 0xb007babeULL #define BOOTINFO_SIZE 1024 /* * The bootinfo structure is at the end of the 64kB hole between * 0x80010000 to 0x8001ffff that neither NetBSD nor the PROM uses. */ #define BOOTINFO_ADDR 0x8001fc00 /* gxemul: these 'uint32_t' were 'int' in NetBSD: */ struct btinfo_common { uint32_t next; /* offset of next item, or zero */ uint32_t type; }; #define BTINFO_MAGIC 1 #define BTINFO_BOOTPATH 2 #define BTINFO_SYMTAB 3 struct btinfo_magic { struct btinfo_common common; uint32_t magic; /* gxemul, was 'int' in NetBSD */ }; #define BTINFO_BOOTPATH_LEN 80 struct btinfo_bootpath { struct btinfo_common common; char bootpath[BTINFO_BOOTPATH_LEN]; }; struct btinfo_symtab { struct btinfo_common common; int nsym; int ssym; int esym; }; #ifdef _KERNEL void *lookup_bootinfo __P((int)); #endif #endif /* !_PMAX_BOOTINFO_H_ */ gxemul-0.6.1/src/include/thirdparty/arcbios_other.h000644 001750 001750 00000032664 13402411502 022640 0ustar00debugdebug000000 000000 /* gxemul: $Id: arcbios_other.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: arcbios.h,v 1.2 2000/01/23 21:01:50 soda Exp $ */ /* $OpenBSD: arcbios.h,v 1.4 1997/05/01 15:13:30 pefo Exp $ */ #ifndef ARCBIOS_OTHER_H #define ARCBIOS_OTHER_H /*- * Copyright (c) 1996 M. Warner Losh. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include typedef struct arc_sid { char vendor[8]; char prodid[8]; } arc_sid_t; /* struct arc_config::class */ #define arc_SystemClass 0 #define arc_ProcessorClass 1 #define arc_CacheClass 2 #define arc_AdapterClass 3 #define arc_ControllerClass 4 #define arc_PeripheralClass 5 #define arc_MemoryClass 6 /* struct arc_config::type */ #define arc_System #define arc_CentralProcessor #define arc_FloatingPointProcessor #define arc_PrimaryIcache #define arc_PrimaryDcache #define arc_SecondaryIcache #define arc_SecondaryDcache #define arc_SecondaryCache #define arc_EisaAdapter /* Eisa adapter */ #define arc_TcAdapter /* Turbochannel adapter */ #define arc_ScsiAdapter /* SCSI adapter */ #define arc_DtiAdapter /* AccessBus adapter */ #define arc_MultiFunctionAdapter #define arc_DiskController 0 #define arc_TapeController 1 #define arc_CdromController 2 #define arc_WormController 3 #define arc_SerialController 4 #define arc_NetworkController 5 #define arc_DisplayController 6 #define arc_ParallelController 7 #define arc_PointerController 8 #define arc_KeyboardController 9 #define arc_AudioController 10 #define arc_OtherController 11 /* denotes a controller not otherwise defined */ #define arc_DiskPeripheral 12 #define arc_FloppyDiskPeripheral 13 #define arc_TapePeripheral 14 #define arc_ModemPeripheral 15 #define arc_MonitorPeripheral 16 #define arc_PrinterPeripheral 17 #define arc_PointerPeripheral 18 #define arc_KeyboardPeripheral 19 #define arc_TerminalPeripheral 20 #define arc_OtherPeripheral 21 /* denotes a peripheral not otherwise defined */ #define arc_LinePeripheral 22 #define arc_NetworkPeripheral 23 #define arc_SystemMemory 24 /* struct arc_config::flag */ #define arc_PeripheralFailed 0x01 #define arc_PeripheralReadOnly 0x02 #define arc_PeripheralRemovable 0x04 #define arc_PeripheralConsoleIn 0x08 #define arc_PeripheralConsoleOut 0x10 #define arc_PeripheralInput 0x20 #define arc_PeripheralOutput 0x40 /* Wonder how this is aligned... */ typedef struct arc_config { u_int32_t cclass; // class u_int32_t type; u_int32_t flags; u_int16_t version; u_int16_t revision; u_int32_t key; u_int32_t affinity_mask; u_int32_t config_data_len; u_int32_t id_len; char *id; } arc_config_t; typedef enum arc_cm_resource_type { arc_CmResourceTypeNull, arc_CmResourceTypePort, arc_CmResourceTypeInterrupt, arc_CmResourceTypeMemory, arc_CmResourceTypeDMA, arc_CmResourceTypeDeviceSpecific, arc_CmResourceTypeVendor, arc_CmResourceTypeProductName, arc_CmResourceTypeSerialNumber } arc_cm_resource_type_t; /* do not use u_int64_t to avoid alignment problem */ typedef struct { u_int32_t loword; u_int32_t hiword; } arc_paddr_t; typedef struct arc_cm_partial_resource { u_int8_t type; u_int8_t share_disposition; u_int16_t flags; union { struct { arc_paddr_t start; u_int32_t length; } port; struct { u_int32_t level; u_int32_t vector; u_int32_t reserved1; } interrupt; struct { arc_paddr_t start; u_int32_t length; } memory; struct { u_int32_t channel; u_int32_t port; u_int32_t reserved1; } dma; struct { u_int8_t vendor[12]; } vendor; struct { u_int8_t product_name[12]; } product_name; struct { u_int8_t serial_number[12]; } serial_number; struct { u_int32_t data_size; u_int32_t reserved1; u_int32_t reserved2; /* the data is followed */ } device_specific_data; } u; } arc_cm_partial_resource_t; typedef struct arc_cm_partial_resource_list { u_int16_t version; u_int16_t revision; u_int32_t count; arc_cm_partial_resource_t partial_descriptors[1]; } arc_cm_partial_resource_list_t; typedef enum arc_cm_share_disposition { arc_CmResourceShareUndetermined, arc_CmResourceShareDeviceExclusive, arc_CmResourceShareDriverExclusive, arc_CmResourceShareShared } arc_cm_share_disposition_t; /* arc_cm_partial_resource_t::flags when type == arc_CmResourceTypeInterrupt */ typedef enum arc_cm_flags_interrupt { arc_CmResourceInterruptLevelSensitive, arc_CmResourceInterruptLatched } arc_cm_flags_interrupt_t; /* arc_cm_partial_resource_t::flags when type == arc_CmResourceTypeMemory */ typedef enum arc_cm_flags_memory { arc_CmResourceMemoryReadWrite, arc_CmResourceMemoryReadOnly, arc_CmResourceMemoryWriteOnly } arc_cm_flags_memory_t; /* arc_cm_partial_resource_t::flags when type == arc_CmResourceTypePort */ typedef enum arc_cm_flags_port { arc_CmResourcePortMemory, arc_CmResourcePortIO } arc_cm_flags_port; typedef enum arc_status { arc_ESUCCESS, /* Success */ arc_E2BIG, /* Arg list too long */ arc_EACCES, /* No such file or directory */ arc_EAGAIN, /* Try again */ arc_EBADF, /* Bad file number */ arc_EBUSY, /* Device or resource busy */ arc_EFAULT, /* Bad address */ arc_EINVAL, /* Invalid argument */ arc_EIO, /* I/O error */ arc_EISDIR, /* Is a directory */ arc_EMFILE, /* Too many open files */ arc_EMLINK, /* Too many links */ arc_ENAMETOOLONG, /* File name too long */ arc_ENODEV, /* No such device */ arc_ENOENT, /* No such file or directory */ arc_ENOEXEC, /* Exec format error */ arc_ENOMEM, /* Out of memory */ arc_ENOSPC, /* No space left on device */ arc_ENOTDIR, /* Not a directory */ arc_ENOTTY, /* Not a typewriter */ arc_ENXIO, /* No such device or address */ arc_EROFS, /* Read-only file system */ } arc_status_t; typedef enum { ExeceptionBlock, SystemParameterBlock, FreeMemory, BadMemory, LoadedProgram, FirmwareTemporary, FirmwarePermanent, FreeContigous } arc_mem_type_t; typedef struct arc_mem { arc_mem_type_t Type; /* Memory chunk type */ u_int32_t BasePage; /* Page no, first page */ u_int32_t PageCount; /* Number of pages */ } arc_mem_t; typedef caddr_t arc_time_t; /* XXX */ typedef struct arc_dsp_stat { u_int16_t CursorXPosition; u_int16_t CursorYPosition; u_int16_t CursorMaxXPosition; u_int16_t CursorMaxYPosition; u_int8_t ForegroundColor; u_int8_t BackgroundColor; u_int8_t HighIntensity; u_int8_t Underscored; u_int8_t ReverseVideo; } arc_dsp_stat_t; typedef caddr_t arc_dirent_t; /* XXX */ typedef u_int32_t arc_seek_mode_t; /* XXX */ typedef u_int32_t arc_mount_t; /* XXX */ typedef enum arc_open_mode { arc_OpenReadOnly, arc_OpenWriteOnly, arc_OpenReadWrite, arc_CreateWriteOnly, arc_CreateReadWrite, arc_SupersedeWriteOnly, arc_SupersedeReadWrite, arc_OpenDirectory, arc_createDirectory } arc_open_mode_t; typedef struct arc_calls { arc_status_t (*load)( /* Load 1 */ char *, /* Image to load */ u_int32_t, /* top address */ u_int32_t *, /* Entry address */ u_int32_t *); /* Low address */ arc_status_t (*invoke)( /* Invoke 2 */ u_int32_t, /* Entry Address */ u_int32_t, /* Stack Address */ u_int32_t, /* Argc */ char **, /* argv */ char **); /* envp */ arc_status_t (*execute)( /* Execute 3 */ char *, /* Image path */ u_int32_t, /* Argc */ char **, /* argv */ char **); /* envp */ void (*halt)(void); /* Halt 4 */ void (*power_down)(void); /* PowerDown 5 */ void (*restart)(void); /* Restart 6 */ void (*reboot)(void); /* Reboot 7 */ void (*enter_interactive_mode)(void); /* EnterInteractiveMode 8 */ void (*return_from_main)(void); /* ReturnFromMain 9 */ arc_config_t *(*get_peer)( /* GetPeer 10 */ arc_config_t *); /* Component */ arc_config_t *(*get_child)( /* GetChild 11 */ arc_config_t *); /* Component */ arc_config_t *(*get_parent)( /* GetParent 12 */ arc_config_t *); /* Component */ arc_status_t (*get_config_data)( /* GetConfigurationData 13 */ caddr_t, /* Configuration Data */ arc_config_t *); /* Component */ arc_config_t *(*add_child)( /* AddChild 14 */ arc_config_t *, /* Component */ arc_config_t *); /* New Component */ arc_status_t (*delete_component)( /* DeleteComponent 15 */ arc_config_t *); /* Component */ arc_config_t *(*get_component)( /* GetComponent 16 */ char *); /* Path */ arc_status_t (*save_config)(void); /* SaveConfiguration 17 */ arc_sid_t *(*get_system_id)(void); /* GetSystemId 18 */ arc_mem_t *(*get_memory_descriptor)( /* GetMemoryDescriptor 19 */ arc_mem_t *); /* MemoryDescriptor */ void (*signal)( /* Signal 20 */ u_int32_t, /* Signal number */ /**/ caddr_t); /* Handler */ arc_time_t *(*get_time)(void); /* GetTime 21 */ u_int32_t (*get_relative_time)(void); /* GetRelativeTime 22 */ arc_status_t (*get_dir_entry)( /* GetDirectoryEntry 23 */ u_int32_t, /* FileId */ arc_dirent_t *, /* Directory entry */ u_int32_t, /* Length */ u_int32_t *); /* Count */ arc_status_t (*open)( /* Open 24 */ char *, /* Path */ arc_open_mode_t, /* Open mode */ u_int32_t *); /* FileId */ arc_status_t (*close)( /* Close 25 */ u_int32_t); /* FileId */ arc_status_t (*read)( /* Read 26 */ u_int32_t, /* FileId */ caddr_t, /* Buffer */ u_int32_t, /* Length */ u_int32_t *); /* Count */ arc_status_t (*get_read_status)( /* GetReadStatus 27 */ u_int32_t); /* FileId */ arc_status_t (*write)( /* Write 28 */ u_int32_t, /* FileId */ caddr_t, /* Buffer */ u_int32_t, /* Length */ u_int32_t *); /* Count */ arc_status_t (*seek)( /* Seek 29 */ u_int32_t, /* FileId */ int64_t *, /* Offset */ arc_seek_mode_t); /* Mode */ arc_status_t (*mount)( /* Mount 30 */ char *, /* Path */ arc_mount_t); /* Operation */ char *(*getenv)( /* GetEnvironmentVariable 31 */ char *); /* Variable */ arc_status_t (*putenv)( /* SetEnvironmentVariable 32 */ char *, /* Variable */ char *); /* Value */ arc_status_t (*get_file_info)(void); /* GetFileInformation 33 */ arc_status_t (*set_file_info)(void); /* SetFileInformation 34 */ void (*flush_all_caches)(void); /* FlushAllCaches 35 */ arc_status_t (*test_unicode)( /* TestUnicodeCharacter 36 */ u_int32_t, /* FileId */ u_int16_t); /* UnicodeCharacter */ arc_dsp_stat_t *(*get_display_status)( /* GetDisplayStatus 37 */ u_int32_t); /* FileId */ } arc_calls_t; #define ARC_PARAM_BLK_MAGIC 0x53435241 /* "ARCS" in little endian */ #define ARC_PARAM_BLK_MAGIC_BUG 0x41524353 /* This is wrong... but req */ typedef struct arc_param_blk { u_int32_t magic; /* Magic Number */ u_int32_t length; /* Length of parameter block */ u_int16_t version; /* ?? */ u_int16_t revision; /* ?? */ /**/ caddr_t restart_block; /* ?? */ /**/ caddr_t debug_block; /* Debugging info -- unused */ /**/ caddr_t general_exp_vect; /* ?? */ /**/ caddr_t tlb_miss_exp_vect; /* ?? */ u_int32_t firmware_length; /* Size of Firmware jumptable in bytes */ arc_calls_t *firmware_vect; /* Firmware jumptable */ u_int32_t vendor_length; /* Size of Vendor specific jumptable */ /**/ caddr_t vendor_vect; /* Vendor specific jumptable */ u_int32_t adapter_count; /* ?? */ struct arc_adapter_param { u_int32_t adapter_type; /* ?? */ u_int32_t adapter_length; /* ?? */ /**/ caddr_t adapter_vect; /* ?? */ } adapters[1]; } arc_param_blk_t; #define ArcBiosBase ((arc_param_blk_t *) 0x80001000) #define ArcBios (ArcBiosBase->firmware_vect) #if 0 arc_status_t Bios_Read __P((int, void *, int, int *)); arc_status_t Bios_Write __P((int, void *, int, int *)); arc_status_t Bios_Open __P((char *, int, u_int *)); arc_status_t Bios_Close __P((u_int)); arc_mem_t *Bios_GetMemoryDescriptor __P((arc_mem_t *)); arc_sid_t *Bios_GetSystemId __P((void)); arc_config_t *Bios_GetChild __P((arc_config_t *)); arc_config_t *Bios_GetPeer __P((arc_config_t *)); int Bios_GetConfigurationData __P((void *, arc_config_t *)); arc_dsp_stat_t *Bios_GetDisplayStatus __P((int)); const char *const arc_strerror __P((int error)); int biosgetc __P((dev_t)); void biosputc __P((dev_t, int)); #endif #endif /* ARCBIOS_OTHER_H */ gxemul-0.6.1/src/include/thirdparty/vrkiureg.h000644 001750 001750 00000004756 13402411502 021654 0ustar00debugdebug000000 000000 /* $NetBSD: vrkiureg.h,v 1.2 2000/09/21 14:17:36 takemura Exp $ */ #ifndef VRKIUREG_H #define VRKIUREG_H /*- * Copyright (c) 1999 SASAKI Takesi * Copyright (c) 1999 PocketBSD Project. All rights reserved. * All rights reserved. * * This code is a part of the PocketBSD. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the PocketBSD project * and its contributors. * 4. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #define KIUDAT0 0x00 #define KIUDAT1 0x02 #define KIUDAT2 0x04 #define KIUDAT3 0x06 #define KIUDAT4 0x08 #define KIUDAT5 0x0a #define KIUSCANREP 0x10 #define KIUSCANS 0x12 # define KIUSCANS_SSTAT_MASK 0x0003 # define KIUSCANS_SSTAT_SCANNING 0x0003 # define KIUSCANS_SSTAT_INTERVAL 0x0002 # define KIUSCANS_SSTAT_WAIT 0x0001 # define KIUSCANS_SSTAT_STOP 0x0000 #define KIUWKS 0x14 #define KIUWKI 0x16 #define KIUINT 0x18 #define KIURST 0x1a #define KIUSCANLINE 0x1e #define KIU_NSCANLINE 12 #define KIUDATP 0x00 #endif /* VRKIUREG_H */ gxemul-0.6.1/src/include/thirdparty/ppc_spr.h000644 001750 001750 00000067525 13402411502 021467 0ustar00debugdebug000000 000000 /* * The NetBSD file ($NetBSD: spr.h,v 1.35 2005/01/20 21:26:49 matt Exp $) * has no explicit Copyright notice, but the initial message in the NetBSD CVS * log for this file says * * Add a port to IBM's PPC405GP Reference Board (the "walnut") * by Eduardo Horvath and Simon Burge of Wasabi Systems. * * so presumably it is under the same license as those files. */ #ifndef _POWERPC_SPR_H_ #define _POWERPC_SPR_H_ #if 0 #ifndef _LOCORE #define mtspr(reg, val) \ __asm __volatile("mtspr %0,%1" : : "K"(reg), "r"(val)) #ifdef __GNUC__ #define mfspr(reg) \ ( { register_t val; \ __asm __volatile("mfspr %0,%1" : "=r"(val) : "K"(reg)); \ val; } ) #endif #endif /* _LOCORE */ #endif /* * Special Purpose Register declarations. * * The first column in the comments indicates which PowerPC * architectures the SPR is valid on - 4 for 4xx series, * 6 for 6xx/7xx series and 8 for 8xx and 8xxx series. */ #define SPR_MQ 0x000 /* .6. 601 MQ register */ #define SPR_XER 0x001 /* 468 Fixed Point Exception Register */ #define SPR_RTCU_R 0x004 /* .6. 601 RTC Upper - Read */ #define SPR_RTCL_R 0x005 /* .6. 601 RTC Lower - Read */ #define SPR_LR 0x008 /* 468 Link Register */ #define SPR_CTR 0x009 /* 468 Count Register */ #define SPR_DSISR 0x012 /* .68 DSI exception source */ #define DSISR_DIRECT 0x80000000 /* Direct-store error exception */ #define DSISR_NOTFOUND 0x40000000 /* Translation not found */ #define DSISR_PROTECT 0x08000000 /* Memory access not permitted */ #define DSISR_INVRX 0x04000000 /* Reserve-indexed insn direct-store access */ #define DSISR_STORE 0x02000000 /* Store operation */ #define DSISR_DABR 0x00400000 /* DABR match */ #define DSISR_SEGMENT 0x00200000 /* XXX; not in 6xx PEM */ #define DSISR_EAR 0x00100000 /* eciwx/ecowx && EAR[E] == 0 */ #define SPR_DAR 0x013 /* .68 Data Address Register */ #define SPR_RTCU_W 0x014 /* .6. 601 RTC Upper - Write */ #define SPR_RTCL_W 0x015 /* .6. 601 RTC Lower - Write */ #define SPR_DEC 0x016 /* .68 DECrementer register */ #define SPR_SDR1 0x019 /* .68 Page table base address register */ #define SPR_SRR0 0x01a /* 468 Save/Restore Register 0 */ #define SPR_SRR1 0x01b /* 468 Save/Restore Register 1 */ #define SPR_EIE 0x050 /* ..8 Exception Interrupt ??? */ #define SPR_EID 0x051 /* ..8 Exception Interrupt ??? */ #define SPR_NRI 0x052 /* ..8 Exception Interrupt ??? */ #define SPR_USPRG0 0x100 /* 4.. User SPR General 0 */ #define SPR_VRSAVE 0x100 /* .6. AltiVec VRSAVE */ #define SPR_SPRG0 0x110 /* 468 SPR General 0 */ #define SPR_SPRG1 0x111 /* 468 SPR General 1 */ #define SPR_SPRG2 0x112 /* 468 SPR General 2 */ #define SPR_SPRG3 0x113 /* 468 SPR General 3 */ #define SPR_SPRG4 0x114 /* 4.. SPR General 4 */ #define SPR_SPRG5 0x115 /* 4.. SPR General 5 */ #define SPR_SPRG6 0x116 /* 4.. SPR General 6 */ #define SPR_SPRG7 0x117 /* 4.. SPR General 7 */ #define SPR_ASR 0x118 /* ... Address Space Register (PPC64) */ #define SPR_EAR 0x11a /* .68 External Access Register */ #define SPR_TBL 0x11c /* 468 Time Base Lower */ #define SPR_TBU 0x11d /* 468 Time Base Upper */ #define SPR_PVR 0x11f /* 468 Processor Version Register */ #define MPC601 0x0001 #define MPC603 0x0003 #define MPC604 0x0004 #define MPC602 0x0005 #define MPC603e 0x0006 #define MPC603ev 0x0007 #define MPC750 0x0008 #define MPC604e 0x0009 #define MPC604ev 0x000a #define MPC7400 0x000c #define MPC620 0x0014 #define IBM403 0x0020 #define IBM401A1 0x0021 #define IBM401B2 0x0022 #define IBM401C2 0x0023 #define IBM401D2 0x0024 #define IBM401E2 0x0025 #define IBM401F2 0x0026 #define IBM401G2 0x0027 #define IBMPOWER3 0x0041 #define MPC860 0x0050 #define MPC8240 0x0081 #define IBM405GP 0x4011 #define IBM405GPR 0x5091 #define IBM405L 0x4161 #define IBM750FX 0x7000 #define MPC7450 0x8000 #define MPC7455 0x8001 #define MPC7457 0x8002 #define MPC7447A 0x8003 #define MPC7448 0x8004 #define MPC745X_P(v) ((v & 0xFFF8) == 0x8000) #define MPC7410 0x800c #define MPC8245 0x8081 #define SPR_HSPRG0 0x130 #define SPR_HSPRG1 0x131 #define SPR_HDEC 0x136 #define SPR_HIOR 0x137 #define SPR_RMOR 0x138 #define SPR_HRMOR 0x139 #define SPR_HSRR0 0x13a #define SPR_HSRR1 0x13b #define SPR_IBAT0U 0x210 /* .68 Instruction BAT Reg 0 Upper */ #define SPR_IBAT0L 0x211 /* .6. Instruction BAT Reg 0 Lower */ #define SPR_IBAT1U 0x212 /* .6. Instruction BAT Reg 1 Upper */ #define SPR_IBAT1L 0x213 /* .6. Instruction BAT Reg 1 Lower */ #define SPR_IBAT2U 0x214 /* .6. Instruction BAT Reg 2 Upper */ #define SPR_IBAT2L 0x215 /* .6. Instruction BAT Reg 2 Lower */ #define SPR_IBAT3U 0x216 /* .6. Instruction BAT Reg 3 Upper */ #define SPR_IBAT3L 0x217 /* .6. Instruction BAT Reg 3 Lower */ #define SPR_DBAT0U 0x218 /* .6. Data BAT Reg 0 Upper */ #define SPR_DBAT0L 0x219 /* .6. Data BAT Reg 0 Lower */ #define SPR_DBAT1U 0x21a /* .6. Data BAT Reg 1 Upper */ #define SPR_DBAT1L 0x21b /* .6. Data BAT Reg 1 Lower */ #define SPR_DBAT2U 0x21c /* .6. Data BAT Reg 2 Upper */ #define SPR_DBAT2L 0x21d /* .6. Data BAT Reg 2 Lower */ #define SPR_DBAT3U 0x21e /* .6. Data BAT Reg 3 Upper */ #define SPR_DBAT3L 0x21f /* .6. Data BAT Reg 3 Lower */ #define SPR_IC_CST 0x230 /* ..8 Instruction Cache CSR */ #define IC_CST_IEN 0x80000000 /* I cache is ENabled (RO) */ #define IC_CST_CMD_INVALL 0x0c000000 /* I cache invalidate all */ #define IC_CST_CMD_UNLOCKALL 0x0a000000 /* I cache unlock all */ #define IC_CST_CMD_UNLOCK 0x08000000 /* I cache unlock block */ #define IC_CST_CMD_LOADLOCK 0x06000000 /* I cache load & lock block */ #define IC_CST_CMD_DISABLE 0x04000000 /* I cache disable */ #define IC_CST_CMD_ENABLE 0x02000000 /* I cache enable */ #define IC_CST_CCER1 0x00200000 /* I cache error type 1 (RO) */ #define IC_CST_CCER2 0x00100000 /* I cache error type 2 (RO) */ #define IC_CST_CCER3 0x00080000 /* I cache error type 3 (RO) */ #define SPR_IBAT4U 0x230 /* .6. Instruction BAT Reg 4 Upper */ #define SPR_IC_ADR 0x231 /* ..8 Instruction Cache Address */ #define SPR_IBAT4L 0x231 /* .6. Instruction BAT Reg 4 Lower */ #define SPR_IC_DAT 0x232 /* ..8 Instruction Cache Data */ #define SPR_IBAT5U 0x232 /* .6. Instruction BAT Reg 5 Upper */ #define SPR_IBAT5L 0x233 /* .6. Instruction BAT Reg 5 Lower */ #define SPR_IBAT6U 0x234 /* .6. Instruction BAT Reg 6 Upper */ #define SPR_IBAT6L 0x235 /* .6. Instruction BAT Reg 6 Lower */ #define SPR_IBAT7U 0x236 /* .6. Instruction BAT Reg 7 Upper */ #define SPR_IBAT7L 0x237 /* .6. Instruction BAT Reg 7 Lower */ #define SPR_DC_CST 0x238 /* ..8 Data Cache CSR */ #define DC_CST_DEN 0x80000000 /* D cache ENabled (RO) */ #define DC_CST_DFWT 0x40000000 /* D cache Force Write-Thru (RO) */ #define DC_CST_LES 0x20000000 /* D cache Little Endian Swap (RO) */ #define DC_CST_CMD_FLUSH 0x0e000000 /* D cache invalidate all */ #define DC_CST_CMD_INVALL 0x0c000000 /* D cache invalidate all */ #define DC_CST_CMD_UNLOCKALL 0x0a000000 /* D cache unlock all */ #define DC_CST_CMD_UNLOCK 0x08000000 /* D cache unlock block */ #define DC_CST_CMD_CLRLESWAP 0x07000000 /* D cache clr little-endian swap */ #define DC_CST_CMD_LOADLOCK 0x06000000 /* D cache load & lock block */ #define DC_CST_CMD_SETLESWAP 0x05000000 /* D cache set little-endian swap */ #define DC_CST_CMD_DISABLE 0x04000000 /* D cache disable */ #define DC_CST_CMD_CLRFWT 0x03000000 /* D cache clear forced write-thru */ #define DC_CST_CMD_ENABLE 0x02000000 /* D cache enable */ #define DC_CST_CMD_SETFWT 0x01000000 /* D cache set forced write-thru */ #define DC_CST_CCER1 0x00200000 /* D cache error type 1 (RO) */ #define DC_CST_CCER2 0x00100000 /* D cache error type 2 (RO) */ #define DC_CST_CCER3 0x00080000 /* D cache error type 3 (RO) */ #define SPR_DBAT4U 0x238 /* .6. Data BAT Reg 4 Upper */ #define SPR_DC_ADR 0x231 /* ..8 Data Cache Address */ #define SPR_DBAT4L 0x239 /* .6. Data BAT Reg 4 Lower */ #define SPR_DC_DAT 0x232 /* ..8 Data Cache Data */ #define SPR_DBAT5U 0x23a /* .6. Data BAT Reg 5 Upper */ #define SPR_DBAT5L 0x23b /* .6. Data BAT Reg 5 Lower */ #define SPR_DBAT6U 0x23c /* .6. Data BAT Reg 6 Upper */ #define SPR_DBAT6L 0x23d /* .6. Data BAT Reg 6 Lower */ #define SPR_DBAT7U 0x23e /* .6. Data BAT Reg 7 Upper */ #define SPR_DBAT7L 0x23f /* .6. Data BAT Reg 7 Lower */ #define SPR_MI_CTR 0x310 /* ..8 IMMU control */ #define Mx_CTR_GPM 0x80000000 /* Group Protection Mode */ #define Mx_CTR_PPM 0x40000000 /* Page Protection Mode */ #define Mx_CTR_CIDEF 0x20000000 /* Cache-Inhibit DEFault */ #define MD_CTR_WTDEF 0x20000000 /* Write-Through DEFault */ #define Mx_CTR_RSV4 0x08000000 /* Reserve 4 TLB entries */ #define MD_CTR_TWAM 0x04000000 /* TableWalk Assist Mode */ #define Mx_CTR_PPCS 0x02000000 /* Priv/user state compare mode */ #define Mx_CTR_TLB_INDX 0x000001f0 /* TLB index mask */ #define Mx_CTR_TLB_INDX_BITPOS 8 /* TLB index shift */ #define SPR_MI_AP 0x312 /* ..8 IMMU access protection */ #define Mx_GP_SUPER(n) (0 << (2*(15-(n)))) /* access is supervisor */ #define Mx_GP_PAGE (1 << (2*(15-(n)))) /* access is page protect */ #define Mx_GP_SWAPPED (2 << (2*(15-(n)))) /* access is swapped */ #define Mx_GP_USER (3 << (2*(15-(n)))) /* access is user */ #define SPR_MI_EPN 0x313 /* ..8 IMMU effective number */ #define Mx_EPN_EPN 0xfffff000 /* Effective Page Number mask */ #define Mx_EPN_EV 0x00000020 /* Entry Valid */ #define Mx_EPN_ASID 0x0000000f /* Address Space ID */ #define SPR_MI_TWC 0x315 /* ..8 IMMU tablewalk control */ #define MD_TWC_L2TB 0xfffff000 /* Level-2 Tablewalk Base */ #define Mx_TWC_APG 0x000001e0 /* Access Protection Group */ #define Mx_TWC_G 0x00000010 /* Guarded memory */ #define Mx_TWC_PS 0x0000000c /* Page Size (L1) */ #define MD_TWC_WT 0x00000002 /* Write-Through */ #define Mx_TWC_V 0x00000001 /* Entry Valid */ #define SPR_MI_RPN 0x316 /* ..8 IMMU real (phys) page number */ #define Mx_RPN_RPN 0xfffff000 /* Real Page Number */ #define Mx_RPN_PP 0x00000ff0 /* Page Protection */ #define Mx_RPN_SPS 0x00000008 /* Small Page Size */ #define Mx_RPN_SH 0x00000004 /* SHared page */ #define Mx_RPN_CI 0x00000002 /* Cache Inhibit */ #define Mx_RPN_V 0x00000001 /* Valid */ #define SPR_MD_CTR 0x318 /* ..8 DMMU control */ #define SPR_M_CASID 0x319 /* ..8 CASID */ #define M_CASID 0x0000000f /* Current AS Id */ #define SPR_MD_AP 0x31a /* ..8 DMMU access protection */ #define SPR_MD_EPN 0x31b /* ..8 DMMU effective number */ #define SPR_M_TWB 0x31c /* ..8 MMU tablewalk base */ #define M_TWB_L1TB 0xfffff000 /* level-1 translation base */ #define M_TWB_L1INDX 0x00000ffc /* level-1 index */ #define SPR_MD_TWC 0x31d /* ..8 DMMU tablewalk control */ #define SPR_MD_RPN 0x31e /* ..8 DMMU real (phys) page number */ #define SPR_MD_TW 0x31f /* ..8 MMU tablewalk scratch */ #define SPR_MI_CAM 0x330 /* ..8 IMMU CAM entry read */ #define SPR_MI_RAM0 0x331 /* ..8 IMMU RAM entry read reg 0 */ #define SPR_MI_RAM1 0x332 /* ..8 IMMU RAM entry read reg 1 */ #define SPR_MD_CAM 0x338 /* ..8 IMMU CAM entry read */ #define SPR_MD_RAM0 0x339 /* ..8 IMMU RAM entry read reg 0 */ #define SPR_MD_RAM1 0x33a /* ..8 IMMU RAM entry read reg 1 */ #define SPR_UMMCR2 0x3a0 /* .6. User Monitor Mode Control Register 2 */ #define SPR_UMMCR0 0x3a8 /* .6. User Monitor Mode Control Register 0 */ #define SPR_USIA 0x3ab /* .6. User Sampled Instruction Address */ #define SPR_UMMCR1 0x3ac /* .6. User Monitor Mode Control Register 1 */ #define SPR_ZPR 0x3b0 /* 4.. Zone Protection Register */ #define SPR_MMCR2 0x3b0 /* .6. Monitor Mode Control Register 2 */ #define SPR_MMCR2_THRESHMULT_32 0x80000000 /* Multiply MMCR0 threshold by 32 */ #define SPR_MMCR2_THRESHMULT_2 0x00000000 /* Multiply MMCR0 threshold by 2 */ #define SPR_PID 0x3b1 /* 4.. Process ID */ #define SPR_PMC5 0x3b1 /* .6. Performance Counter Register 5 */ #define SPR_PMC6 0x3b2 /* .6. Performance Counter Register 6 */ #define SPR_CCR0 0x3b3 /* 4.. Core Configuration Register 0 */ #define SPR_IAC3 0x3b4 /* 4.. Instruction Address Compare 3 */ #define SPR_IAC4 0x3b5 /* 4.. Instruction Address Compare 4 */ #define SPR_DVC1 0x3b6 /* 4.. Data Value Compare 1 */ #define SPR_DVC2 0x3b7 /* 4.. Data Value Compare 2 */ #define SPR_MMCR0 0x3b8 /* .6. Monitor Mode Control Register 0 */ #define MMCR0_FC 0x80000000 /* Freeze counters */ #define MMCR0_FCS 0x40000000 /* Freeze counters in supervisor mode */ #define MMCR0_FCP 0x20000000 /* Freeze counters in user mode */ #define MMCR0_FCM1 0x10000000 /* Freeze counters when mark=1 */ #define MMCR0_FCM0 0x08000000 /* Freeze counters when mark=0 */ #define MMCR0_PMXE 0x04000000 /* Enable PM interrupt */ #define MMCR0_FCECE 0x02000000 /* Freeze counters after event */ #define MMCR0_TBSEL_15 0x01800000 /* Count bit 15 of TBL */ #define MMCR0_TBSEL_19 0x01000000 /* Count bit 19 of TBL */ #define MMCR0_TBSEL_23 0x00800000 /* Count bit 23 of TBL */ #define MMCR0_TBSEL_31 0x00000000 /* Count bit 31 of TBL */ #define MMCR0_TBEE 0x00400000 /* Time-base event enable */ #define MMCRO_THRESHOLD(x) ((x) << 16) /* Threshold value */ #define MMCR0_PMC1CE 0x00008000 /* PMC1 condition enable */ #define MMCR0_PMCNCE 0x00004000 /* PMCn condition enable */ #define MMCR0_TRIGGER 0x00002000 /* Trigger */ #define MMCR0_PMC1SEL(x) ((x) << 6) /* PMC1 selector */ #define MMCR0_PMC2SEL(x) ((x) << 0) /* PMC2 selector */ #define SPR_SGR 0x3b9 /* 4.. Storage Guarded Register */ #define SPR_PMC1 0x3b9 /* .6. Performance Counter Register 1 */ #define SPR_DCWR 0x3ba /* 4.. Data Cache Write-through Register */ #define SPR_PMC2 0x3ba /* .6. Performance Counter Register 2 */ #define SPR_SLER 0x3bb /* 4.. Storage Little Endian Register */ #define SPR_SIA 0x3bb /* .6. Sampled Instruction Address */ #define SPR_MMCR1 0x3bc /* .6. Monitor Mode Control Register 2 */ #define MMCR1_PMC3SEL(x) ((x) << 27) /* PMC 3 selector */ #define MMCR1_PMC4SEL(x) ((x) << 22) /* PMC 4 selector */ #define MMCR1_PMC5SEL(x) ((x) << 17) /* PMC 5 selector */ #define MMCR1_PMC6SEL(x) ((x) << 11) /* PMC 6 selector */ #define SPR_SU0R 0x3bc /* 4.. Storage User-defined 0 Register */ #define SPR_DBCR1 0x3bd /* 4.. Debug Control Register 1 */ #define SPR_PMC3 0x3bd /* .6. Performance Counter Register 3 */ #define SPR_PMC4 0x3be /* .6. Performance Counter Register 4 */ #define SPR_DMISS 0x3d0 /* .68 Data TLB Miss Address Register */ #define SPR_DCMP 0x3d1 /* .68 Data TLB Compare Register */ #define SPR_HASH1 0x3d2 /* .68 Primary Hash Address Register */ #define SPR_ICDBDR 0x3d3 /* 4.. Instruction Cache Debug Data Register */ #define SPR_HASH2 0x3d3 /* .68 Secondary Hash Address Register */ #define SPR_ESR 0x3d4 /* 4.. Exception Syndrome Register */ #define ESR_MCI 0x80000000 /* Machine check - instruction */ #define ESR_PIL 0x08000000 /* Program interrupt - illegal */ #define ESR_PPR 0x04000000 /* Program interrupt - privileged */ #define ESR_PTR 0x02000000 /* Program interrupt - trap */ #define ESR_DST 0x00800000 /* Data storage interrupt - store fault */ #define ESR_DIZ 0x00800000 /* Data/instruction storage interrupt - zone fault */ #define ESR_U0F 0x00008000 /* Data storage interrupt - U0 fault */ #define SPR_IMISS 0x3d4 /* .68 Instruction TLB Miss Address Register */ #define SPR_TLBMISS 0x3d4 /* .6. TLB Miss Address Register */ #define SPR_DEAR 0x3d5 /* 4.. Data Error Address Register */ #define SPR_ICMP 0x3d5 /* .68 Instruction TLB Compare Register */ #define SPR_PTEHI 0x3d5 /* .6. Instruction TLB Compare Register */ #define SPR_EVPR 0x3d6 /* 4.. Exception Vector Prefix Register */ #define SPR_RPA 0x3d6 /* .68 Required Physical Address Register */ #define SPR_PTELO 0x3d6 /* .6. Required Physical Address Register */ #define SPR_TSR 0x3d8 /* 4.. Timer Status Register */ #define TSR_ENW 0x80000000 /* Enable Next Watchdog */ #define TSR_WIS 0x40000000 /* Watchdog Interrupt Status */ #define TSR_WRS_MASK 0x30000000 /* Watchdog Reset Status */ #define TSR_WRS_NONE 0x00000000 /* No watchdog reset has occurred */ #define TSR_WRS_CORE 0x10000000 /* Core reset was forced by the watchdog */ #define TSR_WRS_CHIP 0x20000000 /* Chip reset was forced by the watchdog */ #define TSR_WRS_SYSTEM 0x30000000 /* System reset was forced by the watchdog */ #define TSR_PIS 0x08000000 /* PIT Interrupt Status */ #define TSR_FIS 0x04000000 /* FIT Interrupt Status */ #define SPR_TCR 0x3da /* 4.. Timer Control Register */ #define TCR_WP_MASK 0xc0000000 /* Watchdog Period mask */ #define TCR_WP_2_17 0x00000000 /* 2**17 clocks */ #define TCR_WP_2_21 0x40000000 /* 2**21 clocks */ #define TCR_WP_2_25 0x80000000 /* 2**25 clocks */ #define TCR_WP_2_29 0xc0000000 /* 2**29 clocks */ #define TCR_WRC_MASK 0x30000000 /* Watchdog Reset Control mask */ #define TCR_WRC_NONE 0x00000000 /* No watchdog reset */ #define TCR_WRC_CORE 0x10000000 /* Core reset */ #define TCR_WRC_CHIP 0x20000000 /* Chip reset */ #define TCR_WRC_SYSTEM 0x30000000 /* System reset */ #define TCR_WIE 0x08000000 /* Watchdog Interrupt Enable */ #define TCR_PIE 0x04000000 /* PIT Interrupt Enable */ #define TCR_FP_MASK 0x03000000 /* FIT Period */ #define TCR_FP_2_9 0x00000000 /* 2**9 clocks */ #define TCR_FP_2_13 0x01000000 /* 2**13 clocks */ #define TCR_FP_2_17 0x02000000 /* 2**17 clocks */ #define TCR_FP_2_21 0x03000000 /* 2**21 clocks */ #define TCR_FIE 0x00800000 /* FIT Interrupt Enable */ #define TCR_ARE 0x00400000 /* Auto Reload Enable */ #define SPR_PIT 0x3db /* 4.. Programmable Interval Timer */ #define SPR_SRR2 0x3de /* 4.. Save/Restore Register 2 */ #define SPR_SRR3 0x3df /* 4.. Save/Restore Register 3 */ #define SPR_DBSR 0x3f0 /* 4.. Debug Status Register */ #define DBSR_IC 0x80000000 /* Instruction completion debug event */ #define DBSR_BT 0x40000000 /* Branch Taken debug event */ #define DBSR_EDE 0x20000000 /* Exception debug event */ #define DBSR_TIE 0x10000000 /* Trap Instruction debug event */ #define DBSR_UDE 0x08000000 /* Unconditional debug event */ #define DBSR_IA1 0x04000000 /* IAC1 debug event */ #define DBSR_IA2 0x02000000 /* IAC2 debug event */ #define DBSR_DR1 0x01000000 /* DAC1 Read debug event */ #define DBSR_DW1 0x00800000 /* DAC1 Write debug event */ #define DBSR_DR2 0x00400000 /* DAC2 Read debug event */ #define DBSR_DW2 0x00200000 /* DAC2 Write debug event */ #define DBSR_IDE 0x00100000 /* Imprecise debug event */ #define DBSR_IA3 0x00080000 /* IAC3 debug event */ #define DBSR_IA4 0x00040000 /* IAC4 debug event */ #define DBSR_MRR 0x00000300 /* Most recent reset */ #define SPR_HID0 0x3f0 /* ..8 Hardware Implementation Register 0 */ #define SPR_HID1 0x3f1 /* ..8 Hardware Implementation Register 1 */ #define SPR_DBCR0 0x3f2 /* 4.. Debug Control Register 0 */ #define DBCR0_EDM 0x80000000 /* External Debug Mode */ #define DBCR0_IDM 0x40000000 /* Internal Debug Mode */ #define DBCR0_RST_MASK 0x30000000 /* ReSeT */ #define DBCR0_RST_NONE 0x00000000 /* No action */ #define DBCR0_RST_CORE 0x10000000 /* Core reset */ #define DBCR0_RST_CHIP 0x20000000 /* Chip reset */ #define DBCR0_RST_SYSTEM 0x30000000 /* System reset */ #define DBCR0_IC 0x08000000 /* Instruction Completion debug event */ #define DBCR0_BT 0x04000000 /* Branch Taken debug event */ #define DBCR0_EDE 0x02000000 /* Exception Debug Event */ #define DBCR0_TDE 0x01000000 /* Trap Debug Event */ #define DBCR0_IA1 0x00800000 /* IAC (Instruction Address Compare) 1 debug event */ #define DBCR0_IA2 0x00400000 /* IAC 2 debug event */ #define DBCR0_IA12 0x00200000 /* Instruction Address Range Compare 1-2 */ #define DBCR0_IA12X 0x00100000 /* IA12 eXclusive */ #define DBCR0_IA3 0x00080000 /* IAC 3 debug event */ #define DBCR0_IA4 0x00040000 /* IAC 4 debug event */ #define DBCR0_IA34 0x00020000 /* Instruction Address Range Compare 3-4 */ #define DBCR0_IA34X 0x00010000 /* IA34 eXclusive */ #define DBCR0_IA12T 0x00008000 /* Instruction Address Range Compare 1-2 range Toggle */ #define DBCR0_IA34T 0x00004000 /* Instruction Address Range Compare 3-4 range Toggle */ #define DBCR0_FT 0x00000001 /* Freeze Timers on debug event */ #define SPR_IABR 0x3f2 /* ..8 Instruction Address Breakpoint Register 0 */ #define SPR_HID2 0x3f3 /* ..8 Hardware Implementation Register 2 */ #define SPR_IAC1 0x3f4 /* 4.. Instruction Address Compare 1 */ #define SPR_IAC2 0x3f5 /* 4.. Instruction Address Compare 2 */ #define SPR_DABR 0x3f5 /* .6. Data Address Breakpoint Register */ #define SPR_DAC1 0x3f6 /* 4.. Data Address Compare 1 */ #define SPR_MSSCR0 0x3f6 /* .6. Memory SubSystem Control Register */ #define MSSCR0_SHDEN 0x80000000 /* 0: Shared-state enable */ #define MSSCR0_SHDPEN3 0x40000000 /* 1: ~SHD[01] signal enable in MEI mode */ #define MSSCR0_L1INTVEN 0x38000000 /* 2-4: L1 data cache ~HIT intervention enable */ #define MSSCR0_L2INTVEN 0x07000000 /* 5-7: L2 data cache ~HIT intervention enable */ #define MSSCR0_DL1HWF 0x00800000 /* 8: L1 data cache hardware flush */ #define MSSCR0_MBO 0x00400000 /* 9: must be one */ #define MSSCR0_EMODE 0x00200000 /* 10: MPX bus mode (read-only) */ #define MSSCR0_ABD 0x00100000 /* 11: address bus driven (read-only) */ #define MSSCR0_BMODE 0x0000c000 /* 16-17: Bus Mode (read-only) (7450) */ #define MSSCR0_ID 0x00000040 /* 26: Processor ID */ #define MSSCR0_L2PFE 0x00000003 /* 30-31: L2 prefetching enabled (7450) */ #define SPR_DAC2 0x3f7 /* 4.. Data Address Compare 2 */ #define SPR_L2PM 0x3f8 /* .6. L2 Private Memory Control Register */ #define SPR_L2CR 0x3f9 /* .6. L2 Control Register */ #define L2CR_L2E 0x80000000 /* 0: L2 enable */ #define L2CR_L2PE 0x40000000 /* 1: L2 data parity enable */ #define L2CR_L2SIZ 0x30000000 /* 2-3: L2 size */ #define L2SIZ_2M 0x00000000 #define L2SIZ_256K 0x10000000 #define L2SIZ_512K 0x20000000 #define L2SIZ_1M 0x30000000 #define L2CR_L2CLK 0x0e000000 /* 4-6: L2 clock ratio */ #define L2CLK_DIS 0x00000000 /* disable L2 clock */ #define L2CLK_10 0x02000000 /* core clock / 1 */ #define L2CLK_15 0x04000000 /* / 1.5 */ #define L2CLK_35 0x06000000 /* / 3.5 */ #define L2CLK_20 0x08000000 /* / 2 */ #define L2CLK_25 0x0a000000 /* / 2.5 */ #define L2CLK_30 0x0c000000 /* / 3 */ #define L2CLK_40 0x0e000000 /* / 4 */ #define L2CR_L2RAM 0x01800000 /* 7-8: L2 RAM type */ #define L2RAM_FLOWTHRU_BURST 0x00000000 #define L2RAM_PIPELINE_BURST 0x01000000 #define L2RAM_PIPELINE_LATE 0x01800000 #define L2CR_L2DO 0x00400000 /* 9: L2 data-only. Setting this bit disables instruction caching. */ #define L2CR_L2I 0x00200000 /* 10: L2 global invalidate. */ #define L2CR_L2CTL 0x00100000 /* 11: L2 RAM control (ZZ enable). Enables automatic operation of the L2ZZ (low-power mode) signal. */ #define L2CR_L2WT 0x00080000 /* 12: L2 write-through. */ #define L2CR_L2TS 0x00040000 /* 13: L2 test support. */ #define L2CR_L2OH 0x00030000 /* 14-15: L2 output hold. */ #define L2CR_L2SL 0x00008000 /* 16: L2 DLL slow. */ #define L2CR_L2DF 0x00004000 /* 17: L2 differential clock. */ #define L2CR_L2BYP 0x00002000 /* 18: L2 DLL bypass. */ #define L2CR_L2FA 0x00001000 /* 19: L2 flush assist (for software flush). */ #define L2CR_L2HWF 0x00000800 /* 20: L2 hardware flush. */ #define L2CR_L2IO 0x00000400 /* 21: L2 instruction-only. */ #define L2CR_L2CLKSTP 0x00000200 /* 22: L2 clock stop. */ #define L2CR_L2DRO 0x00000100 /* 23: L2DLL rollover checkstop enable. */ #define L2CR_L2IP 0x00000001 /* 31: L2 global invalidate in */ /* progress (read only). */ #define SPR_L3CR 0x3fa /* .6. L3 Control Register */ #define L3CR_RESERVED 0x0438003a /* Reserved bits in L3CR */ #define L3CR_L3E 0x80000000 /* 0: L3 enable */ #define L3CR_L3PE 0x40000000 /* 1: L3 data parity checking enable */ #define L3CR_L3APE 0x20000000 /* 2: L3 address parity checking enable */ #define L3CR_L3SIZ 0x10000000 /* 3: L3 size (0=1MB, 1=2MB) */ #define L3SIZ_1M 0x00000000 #define L3SIZ_2M 0x10000000 #define L3CR_L3CLKEN 0x08000000 /* 4: Enables the L3_CLK[0:1] signals */ #define L3CR_L3CLK 0x03800000 /* 6-8: L3 clock ratio */ #define L3CLK_60 0x00000000 /* core clock / 6 */ #define L3CLK_20 0x01000000 /* / 2 */ #define L3CLK_25 0x01800000 /* / 2.5 */ #define L3CLK_30 0x02000000 /* / 3 */ #define L3CLK_35 0x02800000 /* / 3.5 */ #define L3CLK_40 0x03000000 /* / 4 */ #define L3CLK_50 0x03800000 /* / 5 */ #define L3CR_L3IO 0x00400000 /* 9: L3 instruction-only mode */ #define L3CR_L3SPO 0x00040000 /* 13: L3 sample point override */ #define L3CR_L3CKSP 0x00030000 /* 14-15: L3 clock sample point */ #define L3CKSP_2 0x00000000 /* 2 clocks */ #define L3CKSP_3 0x00010000 /* 3 clocks */ #define L3CKSP_4 0x00020000 /* 4 clocks */ #define L3CKSP_5 0x00030000 /* 5 clocks */ #define L3CR_L3PSP 0x0000e000 /* 16-18: L3 P-clock sample point */ #define L3PSP_0 0x00000000 /* 0 clocks */ #define L3PSP_1 0x00002000 /* 1 clocks */ #define L3PSP_2 0x00004000 /* 2 clocks */ #define L3PSP_3 0x00006000 /* 3 clocks */ #define L3PSP_4 0x00008000 /* 4 clocks */ #define L3PSP_5 0x0000a000 /* 5 clocks */ #define L3CR_L3REP 0x00001000 /* 19: L3 replacement algorithm (0=default, 1=alternate) */ #define L3CR_L3HWF 0x00000800 /* 20: L3 hardware flush */ #define L3CR_L3I 0x00000400 /* 21: L3 global invalidate */ #define L3CR_L3RT 0x00000300 /* 22-23: L3 SRAM type */ #define L3RT_MSUG2_DDR 0x00000000 /* MSUG2 DDR SRAM */ #define L3RT_PIPELINE_LATE 0x00000100 /* Pipelined (register-register) synchronous late-write SRAM */ #define L3RT_PB2_SRAM 0x00000300 /* PB2 SRAM */ #define L3CR_L3NIRCA 0x00000080 /* 24: L3 non-integer ratios clock adjustment for the SRAM */ #define L3CR_L3DO 0x00000040 /* 25: L3 data-only mode */ #define L3CR_PMEN 0x00000004 /* 29: Private memory enable */ #define L3CR_PMSIZ 0x00000004 /* 31: Private memory size (0=1MB, 1=2MB) */ #define SPR_DCCR 0x3fa /* 4.. Data Cache Cachability Register */ #define SPR_ICCR 0x3fb /* 4.. Instruction Cache Cachability Register */ #define SPR_THRM1 0x3fc /* .6. Thermal Management Register */ #define SPR_THRM2 0x3fd /* .6. Thermal Management Register */ #define SPR_THRM_TIN 0x80000000 /* Thermal interrupt bit (RO) */ #define SPR_THRM_TIV 0x40000000 /* Thermal interrupt valid (RO) */ #define SPR_THRM_THRESHOLD(x) ((x) << 23) /* Thermal sensor threshold */ #define SPR_THRM_TID 0x00000004 /* Thermal interrupt direction */ #define SPR_THRM_TIE 0x00000002 /* Thermal interrupt enable */ #define SPR_THRM_VALID 0x00000001 /* Valid bit */ #define SPR_THRM3 0x3fe /* .6. Thermal Management Register */ #define SPR_THRM_TIMER(x) ((x) << 1) /* Sampling interval timer */ #define SPR_THRM_ENABLE 0x00000001 /* TAU Enable */ #define SPR_FPECR 0x3fe /* .6. Floating-Point Exception Cause Register */ #define SPR_PIR 0x3ff /* .6. Processor Identification Register */ /* Time Base Register declarations */ #define TBR_TBL 0x10c /* 468 Time Base Lower */ #define TBR_TBU 0x10d /* 468 Time Base Upper */ /* Performance counter declarations */ #define PMC_OVERFLOW 0x80000000 /* Counter has overflowed */ /* The first five countable [non-]events are common to all the PMC's */ #define PMCN_NONE 0 /* Count nothing */ #define PMCN_CYCLES 1 /* Processor cycles */ #define PMCN_ICOMP 2 /* Instructions completed */ #define PMCN_TBLTRANS 3 /* TBL bit transitions */ #define PCMN_IDISPATCH 4 /* Instructions dispatched */ #endif /* !_POWERPC_SPR_H_ */ gxemul-0.6.1/src/include/thirdparty/i8253reg.h000644 001750 001750 00000011176 13402411502 021260 0ustar00debugdebug000000 000000 /* GXemul: $Id: i8253reg.h,v 1.1 2006-07-18 19:48:03 debug Exp $ */ /* $NetBSD: i8253reg.h,v 1.9 2005/12/11 12:21:26 christos Exp $ */ #ifndef I8253REG_H #define I8253REG_H /*- * Copyright (c) 1993 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Register definitions for the Intel 8253 Programmable Interval Timer. * * This chip has three independent 16-bit down counters that can be * read on the fly. There are three mode registers and three countdown * registers. The countdown registers are addressed directly, via the * first three I/O ports. The three mode registers are accessed via * the fourth I/O port, with two bits in the mode byte indicating the * register. (Why are hardware interfaces always so braindead?). * * To write a value into the countdown register, the mode register * is first programmed with a command indicating the which byte of * the two byte register is to be modified. The three possibilities * are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then * msb (TMR_MR_BOTH). * * To read the current value ("on the fly") from the countdown register, * you write a "latch" command into the mode register, then read the stable * value from the corresponding I/O port. For example, you write * TMR_MR_LATCH into the corresponding mode register. Presumably, * after doing this, a write operation to the I/O port would result * in undefined behavior (but hopefully not fry the chip). * Reading in this manner has no side effects. * * The outputs of the three timers are connected as follows: * * timer 0 -> irq 0 * timer 1 -> DMA chan 0 (for dram refresh) * timer 2 -> speaker (via keyboard controller) * * Timer 0 is used to call hardclock. * Timer 2 is used to generate console beeps. */ /* * Frequency of all three count-down timers; (I8253_TIMER_FREQ/freq) is the * appropriate count to generate a frequency of freq Hz. */ #ifndef I8253_TIMER_FREQ #define I8253_TIMER_FREQ 1193182 #endif #define I8253_TIMER_DIV(x) ((I8253_TIMER_FREQ+(x)/2)/(x)) /* * Macros for specifying values to be written into a mode register. */ #define I8253_TIMER_CNTR0 0 /* timer 0 counter port */ #define I8253_TIMER_CNTR1 1 /* timer 1 counter port */ #define I8253_TIMER_CNTR2 2 /* timer 2 counter port */ #define I8253_TIMER_MODE 3 /* timer mode port */ #define I8253_TIMER_SEL0 0x00 /* select counter 0 */ #define I8253_TIMER_SEL1 0x40 /* select counter 1 */ #define I8253_TIMER_SEL2 0x80 /* select counter 2 */ #define I8253_TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */ #define I8253_TIMER_ONESHOT 0x02 /* mode 1, one shot */ #define I8253_TIMER_RATEGEN 0x04 /* mode 2, rate generator */ #define I8253_TIMER_SQWAVE 0x06 /* mode 3, square wave */ #define I8253_TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */ #define I8253_TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */ #define I8253_TIMER_LATCH 0x00 /* latch counter for reading */ #define I8253_TIMER_LSB 0x10 /* r/w counter LSB */ #define I8253_TIMER_MSB 0x20 /* r/w counter MSB */ #define I8253_TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */ #define I8253_TIMER_BCD 0x01 /* count in BCD */ #endif /* I8253REG_H */ gxemul-0.6.1/src/include/thirdparty/bcureg.h000644 001750 001750 00000055005 13402411502 021256 0ustar00debugdebug000000 000000 /* gxemul: $Id: bcureg.h,v 1.2 2005-03-05 12:34:02 debug Exp $ */ #ifndef BCUREG_H #define BCUREG_H /* $NetBSD: bcureg.h,v 1.8 2001/09/05 16:08:46 sato Exp $ */ /*- * Copyright (c) 1999-2001 SATO Kazumi. All rights reserved. * Copyright (c) 1999 PocketBSD Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the PocketBSD project * and its contributors. * 4. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * BCU (Bus Control Unit) Registers definitions. * start 0xB000000 (vr4101,4102,4111,4121) * start 0xA000000 (vr4181) * start 0xF000000 (vr4122, vr4131) */ #define BCUCNT1_REG_W 0x000 /* BCU Control Register 1 */ #define BCUCNT1_ROMMASK (1<<15) /* ROM SIZE (<= 4121,>= 4102) */ #define BCUCNT1_ROM64M (1<<15) /* ROM SIZE 64Mbit*/ #define BCUCNT1_ROM32M (0<<15) /* ROM SIZE 32Mbit*/ #define BCUCNT1_DRAMMASK (1<<14) /* DRAM SIZE (<= 4121,>= 4102) */ #define BCUCNT1_DRAM64M (1<<14) /* DRAM SIZE 64Mbit*/ #define BCUCNT1_DRAM32M (0<<14) /* DRAM SIZE 32Mbit*/ #define BCUCNT1_ROMSMASK (0x3<<14) /* ROM SIZE (=4181) */ #define BCUCNT1_ROMS64M (0x2<<14) /* ROM SIZE 64Mbit */ #define BCUCNT1_ROMS32M (0x1<<14) /* ROM SIZE 32Mbit */ #define BCUCNT1_ISAMLCD (1<<13) /* ISAM/LCD 0x0a000000 to 0xaffffff(>= 4102) */ #define BCUCNT1_ISA (1<<13) /* ISA memory space */ #define BCUCNT1_LCD (0<<13) /* LCD space*/ #define BCUCNT1_PAGEMASK (1<<12) /* Maximum burst access size for Page Rom (<= 4121,>= 4102) */ #define BCUCNT1_PAGE128 (1<<12) /* 128bit */ #define BCUCNT1_PAGE64 (0<<12) /* 64bit */ #define BCUCNT1_PAGESIZEMASK (3<<12) /* PageROM PAGESIZE (= 4122, 4131) */ #define BCUCNT1_PASESIZE32 (2<<12) /* 32 byte */ #define BCUCNT1_PASESIZE16 (1<<12) /* 16 byte */ #define BCUCNT1_PASESIZE8 (0<<12) /* 8 byte */ #define BCUCNT1_PAGE2MASK (1<<10) /* (<= 4131,>= 4102) */ #define BCUCNT1_PAGE2PAGE (1<<10) /* Page ROM */ #define BCUCNT1_PAGE2ORD (0<<10) /* Prginary ROM */ #define BCUCNT1_PAGE0MASK (1<<8) /* (<= 4131,>= 4102) */ #define BCUCNT1_PAGE0PAGE (1<<8) /* Page ROM */ #define BCUCNT1_PAGE0ORD (0<<8) /* Prginary ROM */ #define BCUCNT1_REFMASK (1<<7) /* DRAM refresh interval (= 4101) */ #define BCUCNT1_REF1024 (1<<7) /* 1024 cycles/128ms */ #define BCUCNT1_REF4096 (0<<7) /* 4096 cycles/128ms */ #define BCUCNT1_ROMWEN2 (1<<6) /* Enable Flash memory write ROM 2 (<= 4131,>= 4102) */ #define BCUCNT1_ROMWEN2EN (1<<6) /* Enable */ #define BCUCNT1_ROMWEN2DS (0<<6) /* Prohibit */ #define BCUCNT1_PAGEROM (1<<6) /* Enable page ROM access (= 4101) */ #define BCUCNT1_PAGEROMEN (1<<6) /* Page ROM */ #define BCUCNT1_PAGEROMDIS (0<<6) /* not Page ROM */ #define BCUCNT1_ROMWEN (1<<5) /* Enable Flash memory write ROM 0 (= 4101) */ #define BCUCNT1_ROMWENEN (1<<5) /* Enable */ #define BCUCNT1_ROMWENDS (0<<5) /* Prohibit */ #define BCUCNT1_ROMWEN0 (1<<4) /* Enable Flash memory write ROM 0 (<= 4131,>= 4102, =4181) */ #define BCUCNT1_ROMWEN0EN (1<<4) /* Enable */ #define BCUCNT1_ROMWEN0DS (0<<4) /* Prohibit */ #define BCUCNT1_SRFSTAT (1<<4) /* DRAM refresh mode (= 4101) */ #define BCUCNT1_SRFSTATSRF (1<<4) /* self refresh */ #define BCUCNT1_SRFSTATCBR (0<<4) /* CBR refresh */ #define BCUCNT1_BCPUR (1<<3) /* CPU bus cycle control (= 4101) */ #define BCUCNT1_BCPUREN (1<<3) /* CPU bus cycle control enable */ #define BCUCNT1_BCPURDIS (0<<3) /* CPU bus cycle control disable */ #define BCUCNT1_HLD (1<<2) /* Bus hold enable (= 4122, 4131) */ #define BCUCNT1_HLDEN (1<<2) /* enable */ #define BCUCNT1_HLDDIS (1<<2) /* disable */ #define BCUCNT1_BUSHERR (1<<1) /* Bus Timeout detection enable (<= 4121,>= 4102) */ #define BCUCNT1_BUSHERREN (1<<1) /* Enable */ #define BCUCNT1_BUSHERRDS (0<<1) /* Prohibit */ #define BCUCNT1_RTYPE (0x3<<1) /* ROM type (=4181) */ #define BCUCNT1_RTOROM (0<<1) /* Odinary ROM */ #define BCUCNT1_RTFLASH (1<<1) /* flash ROM */ #define BCUCNT1_RTPAGEROM (2<<1) /* Page ROM */ #define BCUCNT1_RSTOUT (1) /* RSTOUT control bit */ #define BCUCNT1_RSTOUTH (1) /* RSTOUT high level*/ #define BCUCNT1_RSTOUTL (0) /* RSTOUT low level*/ #define BCUCNT2_REG_W 0x002 /* BCU Control Register 2 (<= 4121,>= 4102, =4181) */ #define BCUCNT2_GMODE (1) /* LCD access control */ #define BCUCNT2_GMODENOM (1) /* not invert LCD */ #define BCUCNT2_GMODEINV (0) /* invert LCD */ #define BCUBR_REG_W 0x002 /* BCU Bus Restrain Register (= 4101) */ #define BCUROMSIZE_REG_W 0x004 /* ROM size setting register (= 4122, 4131) */ #define BCUROMSIZE_SIZE3 (7<<12) /* Bank3 size */ #define BCUROMSIZE_SIZE3_64 (5<<12) /* 64MB */ #define BCUROMSIZE_SIZE3_32 (4<<12) /* 32MB */ #define BCUROMSIZE_SIZE3_16 (3<<12) /* 16MB */ #define BCUROMSIZE_SIZE3_8 (2<<12) /* 8MB */ #define BCUROMSIZE_SIZE3_4 (1<<12) /* 4MB */ #define BCUROMSIZE_SIZE2 (7<<8) /* Bank2 size */ #define BCUROMSIZE_SIZE2_64 (5<<8) /* 64MB */ #define BCUROMSIZE_SIZE2_32 (4<<8) /* 32MB */ #define BCUROMSIZE_SIZE2_16 (3<<8) /* 16MB */ #define BCUROMSIZE_SIZE2_8 (2<<8) /* 8MB */ #define BCUROMSIZE_SIZE2_4 (1<<8) /* 4MB */ #define BCUROMSIZE_SIZE1 (7<<4) /* Bank1 size */ #define BCUROMSIZE_SIZE1_64 (5<<4) /* 64MB */ #define BCUROMSIZE_SIZE1_32 (4<<4) /* 32MB */ #define BCUROMSIZE_SIZE1_16 (3<<4) /* 16MB */ #define BCUROMSIZE_SIZE1_8 (2<<4) /* 8MB */ #define BCUROMSIZE_SIZE1_4 (1<<4) /* 4MB */ #define BCUROMSIZE_SIZE0 (7) /* Bank0 size */ #define BCUROMSIZE_SIZE0_64 (5) /* 64MB */ #define BCUROMSIZE_SIZE0_32 (4) /* 32MB */ #define BCUROMSIZE_SIZE0_16 (3) /* 16MB */ #define BCUROMSIZE_SIZE0_8 (2) /* 8MB */ #define BCUROMSIZE_SIZE0_4 (1) /* 4MB */ #define BCUBRCNT_REG_W 0x004 /* BCU Bus Restrain Count Register (= 4101) */ #define BCUROMSPEED_REG_W 0x006 /* BCU ROM Speed Register (=4122, 4131) */ #define BCUROMSPEED_PATIME (0x3<<12) /* Page Access time */ #define BCUROMSPEED_PATIME_5VT (0x3<<12) /* 5VTClock */ #define BCUROMSPEED_PATIME_4VT (0x2<<12) /* 4VTClock */ #define BCUROMSPEED_PATIME_3VT (0x1<<12) /* 3VTClock */ #define BCUROMSPEED_PATIME_2VT (0x0<<12) /* 2VTClock */ #define BCUROMSPEED_ATIME (0xf) /* Access time */ #define BCUROMSPEED_ATIME_18VT (0xf) /* 18VTClock */ #define BCUROMSPEED_ATIME_17VT (0xe) /* 17VTClock */ #define BCUROMSPEED_ATIME_16VT (0xd) /* 16VTClock */ #define BCUROMSPEED_ATIME_15VT (0xc) /* 15VTClock */ #define BCUROMSPEED_ATIME_14VT (0xb) /* 14VTClock */ #define BCUROMSPEED_ATIME_13VT (0xa) /* 13VTClock */ #define BCUROMSPEED_ATIME_12VT (0x9) /* 12VTClock */ #define BCUROMSPEED_ATIME_11VT (0x8) /* 11VTClock */ #define BCUROMSPEED_ATIME_10VT (0x7) /* 10VTClock */ #define BCUROMSPEED_ATIME_9VT (0x6) /* 9VTClock */ #define BCUROMSPEED_ATIME_8VT (0x5) /* 8VTClock */ #define BCUROMSPEED_ATIME_7VT (0x4) /* 7VTClock */ #define BCUROMSPEED_ATIME_6VT (0x3) /* 6VTClock */ #define BCUROMSPEED_ATIME_5VT (0x2) /* 5VTClock */ #define BCUROMSPEED_ATIME_4VT (0x1) /* 4VTClock */ #define BCUROMSPEED_ATIME_3VT (0x0) /* 3VTClock */ #define BCUBCL_REG_W 0x006 /* BCU CPU Restrain Disable Register (= 4101) */ #define BCUIO0SPEED_REG_W 0x008 /* BCU IO0 Speed Register (=4122, 4131) */ #define BCUIO0SPEED_RWCS (0x3<<12) /* R/W - CS time */ #define BCUIO0SPEED_RWCS_5VT (0x3<<12) /* 5VTClock */ #define BCUIO0SPEED_RWCS_4VT (0x2<<12) /* 4VTClock */ #define BCUIO0SPEED_RWCS_3VT (0x1<<12) /* 3VTClock */ #define BCUIO0SPEED_RWCS_2VT (0x0<<12) /* 2VTClock */ #define BCUIO0SPEED_RDYRW (0xf<<8) /* IORDY-R/W time */ #define BCUIO0SPEED_RDYRW_18VT (0xf) /* 18VTClock */ #define BCUIO0SPEED_RDYRW_17VT (0xe) /* 17VTClock */ #define BCUIO0SPEED_RDYRW_16VT (0xd) /* 16VTClock */ #define BCUIO0SPEED_RDYRW_15VT (0xc) /* 15VTClock */ #define BCUIO0SPEED_RDYRW_14VT (0xb) /* 14VTClock */ #define BCUIO0SPEED_RDYRW_13VT (0xa) /* 13VTClock */ #define BCUIO0SPEED_RDYRW_12VT (0x9) /* 12VTClock */ #define BCUIO0SPEED_RDYRW_11VT (0x8) /* 11VTClock */ #define BCUIO0SPEED_RDYRW_10VT (0x7) /* 10VTClock */ #define BCUIO0SPEED_RDYRW_9VT (0x6) /* 9VTClock */ #define BCUIO0SPEED_RDYRW_8VT (0x5) /* 8VTClock */ #define BCUIO0SPEED_RDYRW_7VT (0x4) /* 7VTClock */ #define BCUIO0SPEED_RDYRW_6VT (0x3) /* 6VTClock */ #define BCUIO0SPEED_RDYRW_5VT (0x2) /* 5VTClock */ #define BCUIO0SPEED_RDYRW_4VT (0x1) /* 4VTClock */ #define BCUIO0SPEED_RDYRW_3VT (0x0) /* 3VTClock */ #define BCUIO0SPEED_RWRDY (0xf<<4) /* R/W-IORDY time */ #define BCUIO0SPEED_RWRDY_14VT (0xf) /* 14VTClock */ #define BCUIO0SPEED_RWRDY_13VT (0xe) /* 13VTClock */ #define BCUIO0SPEED_RWRDY_12VT (0xd) /* 12VTClock */ #define BCUIO0SPEED_RWRDY_11VT (0xc) /* 11VTClock */ #define BCUIO0SPEED_RWRDY_10VT (0xb) /* 10VTClock */ #define BCUIO0SPEED_RWRDY_9VT (0xa) /* 9VTClock */ #define BCUIO0SPEED_RWRDY_8VT (0x9) /* 8VTClock */ #define BCUIO0SPEED_RWRDY_7VT (0x8) /* 7VTClock */ #define BCUIO0SPEED_RWRDY_6VT (0x7) /* 6VTClock */ #define BCUIO0SPEED_RWRDY_5VT (0x6) /* 5VTClock */ #define BCUIO0SPEED_RWRDY_4VT (0x5) /* 4VTClock */ #define BCUIO0SPEED_RWRDY_3VT (0x4) /* 3VTClock */ #define BCUIO0SPEED_RWRDY_2VT (0x3) /* 2VTClock */ #define BCUIO0SPEED_RWRDY_1VT (0x2) /* 1VTClock */ #define BCUIO0SPEED_RWRDY_0VT (0x1) /* 0VTClock */ #define BCUIO0SPEED_RWRDY_M1VT (0x0) /* -1VTClock */ #define BCUIO0SPEED_CSRW (0xf<<0) /* IORDY-R/W time */ #define BCUIO0SPEED_CSRW_16VT (0xf) /* 16VTClock */ #define BCUIO0SPEED_CSRW_15VT (0xe) /* 15VTClock */ #define BCUIO0SPEED_CSRW_14VT (0xd) /* 14VTClock */ #define BCUIO0SPEED_CSRW_13VT (0xc) /* 13VTClock */ #define BCUIO0SPEED_CSRW_12VT (0xb) /* 12VTClock */ #define BCUIO0SPEED_CSRW_11VT (0xa) /* 11VTClock */ #define BCUIO0SPEED_CSRW_10VT (0x9) /* 10VTClock */ #define BCUIO0SPEED_CSRW_9VT (0x8) /* 9VTClock */ #define BCUIO0SPEED_CSRW_8VT (0x7) /* 8VTClock */ #define BCUIO0SPEED_CSRW_7VT (0x6) /* 7VTClock */ #define BCUIO0SPEED_CSRW_6VT (0x5) /* 6VTClock */ #define BCUIO0SPEED_CSRW_5VT (0x4) /* 5VTClock */ #define BCUIO0SPEED_CSRW_4VT (0x3) /* 4VTClock */ #define BCUIO0SPEED_CSRW_3VT (0x2) /* 3VTClock */ #define BCUIO0SPEED_CSRW_2VT (0x1) /* 2VTClock */ #define BCUIO0SPEED_CSRW_1VT (0x0) /* 1VTClock */ #define BCUBCLCNT_REG_W 0x008 /* BCU CPU Restrain Disable Count Register (= 4101) */ #define BCUIO1SPEED_REG_W 0x00A /* BCU IO1 Speed Register (=4122, 4131) */ #define BCUIO1SPEED_RWCS (0x3<<12) /* R/W - CS time */ #define BCUIO1SPEED_RWCS_5VT (0x3<<12) /* 5VTClock */ #define BCUIO1SPEED_RWCS_4VT (0x2<<12) /* 4VTClock */ #define BCUIO1SPEED_RWCS_3VT (0x1<<12) /* 3VTClock */ #define BCUIO1SPEED_RWCS_2VT (0x0<<12) /* 2VTClock */ #define BCUIO1SPEED_RDYRW (0xf<<8) /* IORDY-R/W time */ #define BCUIO1SPEED_RDYRW_18VT (0xf) /* 18VTClock */ #define BCUIO1SPEED_RDYRW_17VT (0xe) /* 17VTClock */ #define BCUIO1SPEED_RDYRW_16VT (0xd) /* 16VTClock */ #define BCUIO1SPEED_RDYRW_15VT (0xc) /* 15VTClock */ #define BCUIO1SPEED_RDYRW_14VT (0xb) /* 14VTClock */ #define BCUIO1SPEED_RDYRW_13VT (0xa) /* 13VTClock */ #define BCUIO1SPEED_RDYRW_12VT (0x9) /* 12VTClock */ #define BCUIO1SPEED_RDYRW_11VT (0x8) /* 11VTClock */ #define BCUIO1SPEED_RDYRW_10VT (0x7) /* 10VTClock */ #define BCUIO1SPEED_RDYRW_9VT (0x6) /* 9VTClock */ #define BCUIO1SPEED_RDYRW_8VT (0x5) /* 8VTClock */ #define BCUIO1SPEED_RDYRW_7VT (0x4) /* 7VTClock */ #define BCUIO1SPEED_RDYRW_6VT (0x3) /* 6VTClock */ #define BCUIO1SPEED_RDYRW_5VT (0x2) /* 5VTClock */ #define BCUIO1SPEED_RDYRW_4VT (0x1) /* 4VTClock */ #define BCUIO1SPEED_RDYRW_3VT (0x0) /* 3VTClock */ #define BCUIO1SPEED_RWRDY (0xf<<4) /* R/W-IORDY time */ #define BCUIO1SPEED_RWRDY_14VT (0xf) /* 14VTClock */ #define BCUIO1SPEED_RWRDY_13VT (0xe) /* 13VTClock */ #define BCUIO1SPEED_RWRDY_12VT (0xd) /* 12VTClock */ #define BCUIO1SPEED_RWRDY_11VT (0xc) /* 11VTClock */ #define BCUIO1SPEED_RWRDY_10VT (0xb) /* 10VTClock */ #define BCUIO1SPEED_RWRDY_9VT (0xa) /* 9VTClock */ #define BCUIO1SPEED_RWRDY_8VT (0x9) /* 8VTClock */ #define BCUIO1SPEED_RWRDY_7VT (0x8) /* 7VTClock */ #define BCUIO1SPEED_RWRDY_6VT (0x7) /* 6VTClock */ #define BCUIO1SPEED_RWRDY_5VT (0x6) /* 5VTClock */ #define BCUIO1SPEED_RWRDY_4VT (0x5) /* 4VTClock */ #define BCUIO1SPEED_RWRDY_3VT (0x4) /* 3VTClock */ #define BCUIO1SPEED_RWRDY_2VT (0x3) /* 2VTClock */ #define BCUIO1SPEED_RWRDY_1VT (0x2) /* 1VTClock */ #define BCUIO1SPEED_RWRDY_0VT (0x1) /* 0VTClock */ #define BCUIO1SPEED_RWRDY_M1VT (0x0) /* -1VTClock */ #define BCUIO1SPEED_CSRW (0xf<<0) /* IORDY-R/W time */ #define BCUIO1SPEED_CSRW_16VT (0xf) /* 16VTClock */ #define BCUIO1SPEED_CSRW_15VT (0xe) /* 15VTClock */ #define BCUIO1SPEED_CSRW_14VT (0xd) /* 14VTClock */ #define BCUIO1SPEED_CSRW_13VT (0xc) /* 13VTClock */ #define BCUIO1SPEED_CSRW_12VT (0xb) /* 12VTClock */ #define BCUIO1SPEED_CSRW_11VT (0xa) /* 11VTClock */ #define BCUIO1SPEED_CSRW_10VT (0x9) /* 10VTClock */ #define BCUIO1SPEED_CSRW_9VT (0x8) /* 9VTClock */ #define BCUIO1SPEED_CSRW_8VT (0x7) /* 8VTClock */ #define BCUIO1SPEED_CSRW_7VT (0x6) /* 7VTClock */ #define BCUIO1SPEED_CSRW_6VT (0x5) /* 6VTClock */ #define BCUIO1SPEED_CSRW_5VT (0x4) /* 5VTClock */ #define BCUIO1SPEED_CSRW_4VT (0x3) /* 4VTClock */ #define BCUIO1SPEED_CSRW_3VT (0x2) /* 3VTClock */ #define BCUIO1SPEED_CSRW_2VT (0x1) /* 2VTClock */ #define BCUIO1SPEED_CSRW_1VT (0x0) /* 1VTClock */ #define BCUSPEED_REG_W 0x00A /* BCU Access Cycle Change Register (4121>=4102)*/ #define BCUSPD_WPROM (0x3<<12) /* Page ROM access speed */ #define BCUSPD_WPROMRFU (0x3<<12) /* RFU */ #define BCUSPD_WPROM1T (0x2<<12) /* 1TClock */ #define BCUSPD_WPROM2T (0x1<<12) /* 2TClock */ #define BCUSPD_WPROM3T (0x0<<12) /* 3TClock */ #define BCUSPD_WLCDM (0x7<<8) /* access speed 0x0a000000-0affffff */ /* BCUCNT1_ISAMLCD == BCUCNT1_LCD */ #define BCUSPD_WLCDRFU (0x7<<8) /* LCD RFU */ #define BCUSPD_WLCDRFU1 (0x6<<8) /* LCD RFU */ #define BCUSPD_WLCDRFU2 (0x5<<8) /* LCD RFU */ #define BCUSPD_WLCDRFU3 (0x4<<8) /* LCD RFU */ #define BCUSPD_WLCD2T (0x3<<8) /* LCD 2TClock */ #define BCUSPD_WLCD4T (0x2<<8) /* LCD 4TClock */ #define BCUSPD_WLCD6T (0x1<<8) /* LCD 6TClock */ #define BCUSPD_WLCD8T (0x0<<8) /* LCD 8TClock */ /* BCUCNT1_ISAMLCD == BCUCNT1_ISAM */ #define BCUSPD_ISAM1T (0x7<<8) /* ISAM 1TClock */ #define BCUSPD_ISAM2T (0x6<<8) /* ISAM 2TClock */ #define BCUSPD_ISAM3T (0x5<<8) /* ISAM 3TClock */ #define BCUSPD_ISAM4T (0x4<<8) /* ISAM 4TClock */ #define BCUSPD_ISAM5T (0x3<<8) /* ISAM 5TClock */ #define BCUSPD_ISAM6T (0x2<<8) /* ISAM 6TClock */ #define BCUSPD_ISAM7T (0x1<<8) /* ISAM 7TClock */ #define BCUSPD_ISAM8T (0x0<<8) /* ISAM 8TClock */ #define BCUSPD_WISAA (0x7<<4) /* System Bus Access Speed */ #define BCUSPD_WISAA3T (0x5<<4) /* 3TClock */ #define BCUSPD_WISAA4T (0x4<<4) /* 4TClock */ #define BCUSPD_WISAA5T (0x3<<4) /* 5TClock */ #define BCUSPD_WISAA6T (0x2<<4) /* 6TClock */ #define BCUSPD_WISAA7T (0x1<<4) /* 7TClock */ #define BCUSPD_WISAA8T (0x0<<4) /* 8TClock */ #define BCUSPD_WROMA (0x7<<0) /* System Bus Access Speed */ #define BCUSPD_WROMA2T (0x7<<0) /* 2TClock */ #define BCUSPD_WROMA3T (0x6<<0) /* 3TClock */ #define BCUSPD_WROMA4T (0x5<<0) /* 4TClock */ #define BCUSPD_WROMA5T (0x4<<0) /* 5TClock */ #define BCUSPD_WROMA6T (0x3<<0) /* 6TClock */ #define BCUSPD_WROMA7T (0x2<<0) /* 7TClock */ #define BCUSPD_WROMA8T (0x1<<0) /* 8TClock */ #define BCUSPD_WROMA9T (0x0<<0) /* 9TClock */ #define BCUERRST_REG_W 0x00C /* BCU BUS ERROR Status Register (4121>=4102)*/ #define BCUERRST_BUSERRMASK (1) /* Bus error, clear to 0 when 1 is written */ #define BCUERRST_BUSERR (1) /* Bus error */ #define BCUERRST_BUSNORM (0) /* Normal */ #define BCU81SPEED_REG_W 0x00C /* BCU Access Cycle Change Register (=4181)*/ #define BCU81SPD_WPROM (0x7<<12) /* Page ROM access speed */ #define BCU81SPD_WPROM8T (0x7<<12) /* 8TClock */ #define BCU81SPD_WPROM7T (0x6<<12) /* 7TClock */ #define BCU81SPD_WPROM6T (0x5<<12) /* 6TClock */ #define BCU81SPD_WPROM5T (0x4<<12) /* 5TClock */ #define BCU81SPD_WPROM4T (0x3<<12) /* 4TClock */ #define BCU81SPD_WPROM3T (0x2<<12) /* 3TClock */ #define BCU81SPD_WPROM2T (0x1<<12) /* 2TClock */ #define BCU81SPD_WPROM1T (0x0<<12) /* 1TClock */ #define BCU81SPD_WROMA (0xf<<0) /* System Bus Access Speed */ #define BCU81SPD_WROMA16T (0xf<<0) /* 16TClock */ #define BCU81SPD_WROMA15T (0xe<<0) /* 15TClock */ #define BCU81SPD_WROMA14T (0xd<<0) /* 14TClock */ #define BCU81SPD_WROMA13T (0xc<<0) /* 13TClock */ #define BCU81SPD_WROMA12T (0xb<<0) /* 12TClock */ #define BCU81SPD_WROMA11T (0xa<<0) /* 11TClock */ #define BCU81SPD_WROMA10T (0x9<<0) /* 10TClock */ #define BCU81SPD_WROMA9T (0x8<<0) /* 9TClock */ #define BCU81SPD_WROMA8T (0x7<<0) /* 8TClock */ #define BCU81SPD_WROMA7T (0x6<<0) /* 7TClock */ #define BCU81SPD_WROMA6T (0x5<<0) /* 6TClock */ #define BCU81SPD_WROMA5T (0x4<<0) /* 5TClock */ #define BCU81SPD_WROMA4T (0x3<<0) /* 4TClock */ #define BCU81SPD_WROMA3T (0x2<<0) /* 3TClock */ #define BCU81SPD_WROMA2T (0x1<<0) /* 2TClock */ #define BCU81SPD_WROMA1T (0x0<<0) /* 1TClock */ #define BCURFCNT_REG_W 0x00E /* BCU Refresh Control Register(4121>=4102) */ #define BCU81RFCNT_REG_W 0x010 /* BCU Refresh Control Register(=4181) */ #define BCURFCNT_MASK 0x3fff /* refresh interval MASK */ #define BCUREVID_REG_W 0x010 /* BCU Revision ID Register (4122>=4101)*/ #define BCU81REVID_REG_W 0x014 /* BCU Revision ID Register (=4181)*/ #define BCUREVID_RIDMASK (0xf<<12) /* Revision ID */ #define BCUREVID_RIDSHFT (12) /* Revision ID */ #define BCUREVID_RID_4131 (0x5) /* VR4131 */ #define BCUREVID_RID_4122 (0x4) /* VR4122 */ #define BCUREVID_RID_4121 (0x3) /* VR4121 */ #define BCUREVID_RID_4111 (0x2) /* VR4111 */ #define BCUREVID_RID_4102 (0x1) /* VR4102 */ #define BCUREVID_RID_4101 (0x0) /* VR4101 */ #define BCUREVID_RID_4181 (0x0) /* VR4181 conflict VR4101 */ #define BCUREVID_FIXRID_OFF (0x10) /* conflict offset */ #define BCUREVID_FIXRID_4181 (0x10) /* VR4181 for kernel */ #define BCUREVID_MJREVMASK (0xf<<8) /* Major Revision */ #define BCUREVID_MJREVSHFT (8) /* Major Revision */ #define BCUREVID_MNREVMASK (0xf) /* Minor Revision */ #define BCUREVID_MNREVSHFT (0) /* Minor Revision */ #define BCUREFCOUNT_REG_W 0x012 /* BCU Refresh Count Register (>= 4102) */ #define BCUREFCOUNT_MASK 0x3fff /* refresh count MASK */ #define BCUCLKSPEED_REG_W 0x014 /* Clock Speed Register (>= 4102) */ #define BCU81CLKSPEED_REG_W 0x018 /* Clock Speed Register (= 4181) */ #define BCUCLKSPEED_DIVT2B (1<<15) /* (= 4102, 4111) */ #define BCUCLKSPEED_DIVT3B (1<<14) /* (= 4111) */ #define BCUCLKSPEED_DIVT4B (1<<13) /* (= 4111) */ #define BCUCLKSPEED_DIVTMASK (0xf<<12) /* (= 4121) */ #define BCUCLKSPEED_DIVT3 0x3 #define BCUCLKSPEED_DIVT4 0x4 #define BCUCLKSPEED_DIVT5 0x5 #define BCUCLKSPEED_DIVT6 0x6 #define BCUCLKSPEED_DIVTSHFT (12) #define BCUCLKSPEED_TDIVMODE (0x1<<12) /* (= 4122, 4131) */ #define BCUCLKSPEED_TDIV4 0x1 #define BCUCLKSPEED_TDIV2 0x0 #define BCUCLKSPEED_TDIVSHFT (12) #define BCU81CLKSPEED_DIVTMASK (0x7<<12) /* (=4181) */ #define BCU81CLKSPEED_DIVT1 0x7 #define BCU81CLKSPEED_DIVT2 0x3 #define BCU81CLKSPEED_DIVT3 0x5 #define BCU81CLKSPEED_DIVT4 0x6 #define BCU81CLKSPEED_DIVTSHFT (12) #define BCUCLKSPEED_DIVVTMASK (0xf<<8) /* (= 4121) */ #define BCUCLKSPEED_DIVVT1 0x1 #define BCUCLKSPEED_DIVVT2 0x2 #define BCUCLKSPEED_DIVVT3 0x3 #define BCUCLKSPEED_DIVVT4 0x4 #define BCUCLKSPEED_DIVVT5 0x5 #define BCUCLKSPEED_DIVVT6 0x6 #define BCUCLKSPEED_DIVVT1_5 0x9 #define BCUCLKSPEED_DIVVT2_5 0xa #define BCUCLKSPEED_DIVVTSHFT (8) #define BCUCLKSPEED_VTDIVMODE (0x7<<8) /* (= 4122, 4131) */ #define BCUCLKSPEED_VTDIV6 0x6 #define BCUCLKSPEED_VTDIVT5 0x5 #define BCUCLKSPEED_VTDIVT4 0x4 #define BCUCLKSPEED_VTDIVT3 0x3 #define BCUCLKSPEED_VTDIVT2 0x2 #define BCUCLKSPEED_VTDIVT1 0x1 #define BCUCLKSPEED_VTDIVSHFT (8) #define BCUCLKSPEED_CLKSPMASK (0x1f) /* calculate for Clock */ #define BCUCLKSPEED_CLKSPSHFT (0) #define BCUCNT3_REG_W 0x016 /* BCU Control Register 3 (>= 4111) */ #define BCUCNT3_EXTROMMASK (1<<15) /* ROM SIZE (4111,4121)*/ #define BCUCNT3_EXTROM64M (1<<15) /* 64Mbit DRAM */ #define BCUCNT3_EXTROM32M (0<<15) /* 32Mbit DRAM */ #define BCUCNT3_EXTDRAMMASK (1<<14) /* DRAM SIZE (4111,4121)*/ #define BCUCNT3_EXTDRAM64M (1<<14) /* 64Mbit DRAM */ #define BCUCNT3_EXTDRAM16M (0<<14) /* 16Mbit DRAM */ #define BCUCNT3_EXTROMCS (0x3<<12) /* Bank3,2 */ #define BCUCNT3_ROMROM (0x3<<12) /* Bank3 ROM ,2 ROM */ #define BCUCNT3_ROMRAM (0x2<<12) /* Bank3 ROM ,2 RAM */ #define BCUCNT3_RAMRAM (0x0<<12) /* Bank3 RAM ,2 RAM */ #define BCUCNT3_EXTMEM (1<<11) /* EXT MEN enable (4111,4121)*/ #define BCUCNT3_EXTMEMEN (1<<11) /* EXT MEN enable */ #define BCUCNT3_EXTMEMDS (0<<11) /* EXT MEN disable */ #define BCUCNT3_LCDSIZE (1<<7) /* LCD bus size */ #define BCUCNT3_LCD32 (1<<7) /* LCD bus 32bit */ #define BCUCNT3_LCD16 (0<<7) /* LCD bus 16bit */ #define BCUCNT3_SYSDIREN (1<<3) /* SYSDIR or GPIO6(=4122, 4131)*/ #define BCUCNT3_SYSDIR (1<<3) /* SYSDIR */ #define BCUCNT3_GPIO6 (0<<3) /* GPIO6 */ #define BCUCNT3_LCDSEL1 (1<<1) /* 0xc00-0xdff area buffer (=4122)*/ #define BCUCNT3_LCDSEL1_NOBUF (1<<1) /* nobuffer */ #define BCUCNT3_LCDSEL1_BUF (0<<1) /* buffer */ #define BCUCNT3_LCDSEL0 (1<<1) /* 0xa00-0xbff area buffer (=4122)*/ #define BCUCNT3_LCDSEL0_NOBUF (1<<1) /* nobuffer */ #define BCUCNT3_LCDSEL0_BUF (0<<1) /* buffer */ #endif /* BCUREG_H */ gxemul-0.6.1/src/include/thirdparty/alpha_autoconf.h000644 001750 001750 00000010007 13402411502 022763 0ustar00debugdebug000000 000000 /* GXemul: $Id: alpha_autoconf.h,v 1.2 2006-06-17 09:35:37 debug Exp $ */ /* $NetBSD: autoconf.h,v 1.22 2005/12/11 12:16:16 christos Exp $ */ #ifndef ALPHA_AUTOCONF_H #define ALPHA_AUTOCONF_H #include "misc.h" /* * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. * All rights reserved. * * Author: Chris G. Demetriou * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * Machine-dependent structures for autoconfiguration */ #if 0 /* not in gxemul */ struct mainbus_attach_args { const char *ma_name; /* device name */ int ma_slot; /* CPU "slot" number; only meaningful when attaching CPUs */ }; struct bootdev_data { char *protocol; int bus; int slot; int channel; char *remote_address; int unit; int boot_dev_type; char *ctrl_dev_type; }; #endif /* * The boot program passes a pointer (in the boot environment virtual * address address space; "BEVA") to a bootinfo to the kernel using * the following convention: * * a0 contains first free page frame number * a1 contains page number of current level 1 page table * if a2 contains BOOTINFO_MAGIC and a4 is nonzero: * a3 contains pointer (BEVA) to bootinfo * a4 contains bootinfo version number * if a2 contains BOOTINFO_MAGIC and a4 contains 0 (backward compat): * a3 contains pointer (BEVA) to bootinfo version * (u_long), then the bootinfo */ #define ALPHA_BOOTINFO_MAGIC 0xdeadbeeffeedfaceULL struct bootinfo_v1 { u_long ssym; /* 0: start of kernel sym table */ u_long esym; /* 8: end of kernel sym table */ char boot_flags[64]; /* 16: boot flags */ char booted_kernel[64]; /* 80: name of booted kernel */ void *hwrpb; /* 144: hwrpb pointer (BEVA) */ u_long hwrpbsize; /* 152: size of hwrpb data */ int (*cngetc)(void); /* 160: console getc pointer */ void (*cnputc)(int); /* 168: console putc pointer */ void (*cnpollc)(int); /* 176: console pollc pointer */ u_long pad[9]; /* 184: rsvd for future use */ /* 256: total size */ }; /* * Kernel-internal structure used to hold important bits of boot * information. NOT to be used by boot blocks. * * Note that not all of the fields from the bootinfo struct(s) * passed by the boot blocks aren't here (because they're not currently * used by the kernel!). Fields here which aren't supplied by the * bootinfo structure passed by the boot blocks are supposed to be * filled in at startup with sane contents. */ struct bootinfo_kernel { u_long ssym; /* start of syms */ u_long esym; /* end of syms */ u_long hwrpb_phys; /* hwrpb physical address */ u_long hwrpb_size; /* size of hwrpb data */ char boot_flags[64]; /* boot flags */ char booted_kernel[64]; /* name of booted kernel */ char booted_dev[64]; /* name of booted device */ }; /* * Lookup table entry for Alpha system variations. */ struct alpha_variation_table { u_int64_t avt_variation; /* variation, from HWRPB */ const char *avt_model; /* model string */ }; #ifdef _KERNEL extern struct bootdev_data *bootdev_data; extern struct bootinfo_kernel bootinfo; const char *alpha_variation_name(u_int64_t, const struct alpha_variation_table *); const char *alpha_unknown_sysname(void); #endif /* _KERNEL */ #endif /* ALPHA_AUTOCONF_H */ gxemul-0.6.1/src/include/thirdparty/sh4_pcicreg.h000644 001750 001750 00000013637 13402411502 022206 0ustar00debugdebug000000 000000 /* $OpenBSD: pcicreg.h,v 1.1.1.1 2006/10/06 21:02:55 miod Exp $ */ /* $NetBSD: pcicreg.h,v 1.2 2005/12/11 12:18:58 christos Exp $ */ #ifndef SH4_PCICREG_H #define SH4_PCICREG_H /*- * Copyright (c) 2005 NONAKA Kimihiro * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* #include */ /* * PCI Controller */ #define SH4_PCIC 0xfe200000 #define SH4_PCIC_IO 0xfe240000 #define SH4_PCIC_IO_SIZE 0x00040000 #define SH4_PCIC_IO_MASK (SH4_PCIC_IO_SIZE-1) #define SH4_PCIC_MEM 0xfd000000 #define SH4_PCIC_MEM_SIZE 0x01000000 #define SH4_PCIC_MEM_MASK (SH4_PCIC_MEM_SIZE-1) #define SH4_PCICONF (SH4_PCIC+0x000) /* 32bit */ #define SH4_PCICONF0 (SH4_PCICONF+0x00) /* 32bit */ #define SH4_PCICONF1 (SH4_PCICONF+0x04) /* 32bit */ #define SH4_PCICONF2 (SH4_PCICONF+0x08) /* 32bit */ #define SH4_PCICONF3 (SH4_PCICONF+0x0c) /* 32bit */ #define SH4_PCICONF4 (SH4_PCICONF+0x10) /* 32bit */ #define SH4_PCICONF5 (SH4_PCICONF+0x14) /* 32bit */ #define SH4_PCICONF6 (SH4_PCICONF+0x18) /* 32bit */ #define SH4_PCICONF7 (SH4_PCICONF+0x1c) /* 32bit */ #define SH4_PCICONF8 (SH4_PCICONF+0x20) /* 32bit */ #define SH4_PCICONF9 (SH4_PCICONF+0x24) /* 32bit */ #define SH4_PCICONF10 (SH4_PCICONF+0x28) /* 32bit */ #define SH4_PCICONF11 (SH4_PCICONF+0x2c) /* 32bit */ #define SH4_PCICONF12 (SH4_PCICONF+0x30) /* 32bit */ #define SH4_PCICONF13 (SH4_PCICONF+0x34) /* 32bit */ #define SH4_PCICONF14 (SH4_PCICONF+0x38) /* 32bit */ #define SH4_PCICONF15 (SH4_PCICONF+0x3c) /* 32bit */ #define SH4_PCICONF16 (SH4_PCICONF+0x40) /* 32bit */ #define SH4_PCICONF17 (SH4_PCICONF+0x44) /* 32bit */ #define SH4_PCICR (SH4_PCIC+0x100) /* 32bit */ #define SH4_PCILSR0 (SH4_PCIC+0x104) /* 32bit */ #define SH4_PCILSR1 (SH4_PCIC+0x108) /* 32bit */ #define SH4_PCILAR0 (SH4_PCIC+0x10c) /* 32bit */ #define SH4_PCILAR1 (SH4_PCIC+0x110) /* 32bit */ #define SH4_PCIINT (SH4_PCIC+0x114) /* 32bit */ #define SH4_PCIINTM (SH4_PCIC+0x118) /* 32bit */ #define SH4_PCIALR (SH4_PCIC+0x11c) /* 32bit */ #define SH4_PCICLR (SH4_PCIC+0x120) /* 32bit */ #define SH4_PCIAINT (SH4_PCIC+0x130) /* 32bit */ #define SH4_PCIAINTM (SH4_PCIC+0x134) /* 32bit */ #define SH4_PCIDMABT (SH4_PCIC+0x140) /* 32bit */ #define SH4_PCIDPA0 (SH4_PCIC+0x180) /* 32bit */ #define SH4_PCIDLA0 (SH4_PCIC+0x184) /* 32bit */ #define SH4_PCIDTC0 (SH4_PCIC+0x188) /* 32bit */ #define SH4_PCIDCR0 (SH4_PCIC+0x18c) /* 32bit */ #define SH4_PCIDPA1 (SH4_PCIC+0x190) /* 32bit */ #define SH4_PCIDLA1 (SH4_PCIC+0x194) /* 32bit */ #define SH4_PCIDTC1 (SH4_PCIC+0x198) /* 32bit */ #define SH4_PCIDCR1 (SH4_PCIC+0x19c) /* 32bit */ #define SH4_PCIDPA2 (SH4_PCIC+0x1a0) /* 32bit */ #define SH4_PCIDLA2 (SH4_PCIC+0x1a4) /* 32bit */ #define SH4_PCIDTC2 (SH4_PCIC+0x1a8) /* 32bit */ #define SH4_PCIDCR2 (SH4_PCIC+0x1ac) /* 32bit */ #define SH4_PCIDPA3 (SH4_PCIC+0x1b0) /* 32bit */ #define SH4_PCIDLA3 (SH4_PCIC+0x1b4) /* 32bit */ #define SH4_PCIDTC3 (SH4_PCIC+0x1b8) /* 32bit */ #define SH4_PCIDCR3 (SH4_PCIC+0x1bc) /* 32bit */ #define SH4_PCIPAR (SH4_PCIC+0x1c0) /* 32bit */ #define SH4_PCIMBR (SH4_PCIC+0x1c4) /* 32bit */ #define SH4_PCIIOBR (SH4_PCIC+0x1c8) /* 32bit */ #define SH4_PCIPINT (SH4_PCIC+0x1cc) /* 32bit */ #define SH4_PCIPINTM (SH4_PCIC+0x1d0) /* 32bit */ #define SH4_PCICLKR (SH4_PCIC+0x1d4) /* 32bit */ #define SH4_PCIBCR1 (SH4_PCIC+0x1e0) /* 32bit */ #define SH4_PCIBCR2 (SH4_PCIC+0x1e4) /* 32bit */ #define SH4_PCIWCR1 (SH4_PCIC+0x1e8) /* 32bit */ #define SH4_PCIWCR2 (SH4_PCIC+0x1ec) /* 32bit */ #define SH4_PCIWCR3 (SH4_PCIC+0x1f0) /* 32bit */ #define SH4_PCIMCR (SH4_PCIC+0x1f4) /* 32bit */ #define SH4_PCIBCR3 (SH4_PCIC+0x1f8) /* 32bit: SH7751R */ #define SH4_PCIPCTR (SH4_PCIC+0x200) /* 32bit */ #define SH4_PCIPDTR (SH4_PCIC+0x204) /* 32bit */ #define SH4_PCIPDR (SH4_PCIC+0x220) /* 32bit */ #define PCICR_BASE 0xa5000000 #define PCICR_TRDSGL 0x00000200 #define PCICR_BYTESWAP 0x00000100 #define PCICR_PCIPUP 0x00000080 #define PCICR_BMABT 0x00000040 #define PCICR_MD10 0x00000020 #define PCICR_MD9 0x00000010 #define PCICR_SERR 0x00000008 #define PCICR_INTA 0x00000004 #define PCICR_RSTCTL 0x00000002 #define PCICR_CFINIT 0x00000001 #define PCIINT_M_LOCKON 0x00008000 #define PCIINT_T_TGT_ABORT 0x00004000 #define PCIINT_TGT_RETRY 0x00000200 #define PCIINT_MST_DIS 0x00000100 #define PCIINT_ADRPERR 0x00000080 #define PCIINT_SERR_DET 0x00000040 #define PCIINT_T_DPERR_WT 0x00000020 #define PCIINT_T_PERR_DET 0x00000010 #define PCIINT_M_TGT_ABORT 0x00000008 #define PCIINT_M_MST_ABORT 0x00000004 #define PCIINT_M_DPERR_WT 0x00000002 #define PCIINT_M_DPERR_RD 0x00000001 #define PCIINT_ALL 0x0000c3ff #define PCIINT_CLEAR_ALL PCIINT_ALL #define PCIINTM_MASK_ALL 0x00000000 #define PCIINTM_UNMASK_ALL PCIINT_ALL #define PCIMBR_MASK 0xff000000 #define PCIIOBR_MASK 0xffc00000 #endif /* SH4_PCICREG_H */ gxemul-0.6.1/src/include/thirdparty/tgareg.h000644 001750 001750 00000014767 13402411502 021272 0ustar00debugdebug000000 000000 /* $NetBSD: tgareg.h,v 1.4 2000/03/12 05:32:30 nathanw Exp $ */ #ifndef _ALPHA_INCLUDE_TGAREG_H_ #define _ALPHA_INCLUDE_TGAREG_H_ /* * Copyright (c) 1995, 1996 Carnegie-Mellon University. * All rights reserved. * * Author: Chris G. Demetriou * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * Device-specific PCI register offsets and contents. */ #define TGA_PCIREG_PVRR 0x40 /* PCI Address Extension Register */ #define TGA_PCIREG_PAER 0x44 /* PCI VGA Redirect Register */ /* * TGA Memory Space offsets */ #define TGA_MEM_ALTROM 0x0000000 /* 0MB -- Alternate ROM space */ #define TGA2_MEM_EXTDEV 0x0000000 /* 0MB -- External Device Access */ #define TGA_MEM_CREGS 0x0100000 /* 1MB -- Core Registers */ #define TGA_CREGS_SIZE 0x0100000 /* Core registers occupy 1MB */ #define TGA_CREGS_ALIAS 0x0000400 /* Register copies every 1kB */ #define TGA2_MEM_CLOCK 0x0060000 /* TGA2 Clock access */ #define TGA2_MEM_RAMDAC 0x0080000 /* TGA2 RAMDAC access */ /* Display and Back Buffers mapped at config-dependent addresses */ /* * TGA Core Space register numbers and contents. */ typedef u_int32_t tga_reg_t; #define TGA_REG_GCBR0 0x000 /* Copy buffer 0 */ #define TGA_REG_GCBR1 0x001 /* Copy buffer 1 */ #define TGA_REG_GCBR2 0x002 /* Copy buffer 2 */ #define TGA_REG_GCBR3 0x003 /* Copy buffer 3 */ #define TGA_REG_GCBR4 0x004 /* Copy buffer 4 */ #define TGA_REG_GCBR5 0x005 /* Copy buffer 5 */ #define TGA_REG_GCBR6 0x006 /* Copy buffer 6 */ #define TGA_REG_GCBR7 0x007 /* Copy buffer 7 */ #define TGA_REG_GFGR 0x008 /* Foreground */ #define TGA_REG_GBGR 0x009 /* Background */ #define TGA_REG_GPMR 0x00a /* Plane Mask */ #define TGA_REG_GPXR_S 0x00b /* Pixel Mask (one-shot) */ #define TGA_REG_GMOR 0x00c /* Mode */ #define TGA_REG_GOPR 0x00d /* Raster Operation */ #define TGA_REG_GPSR 0x00e /* Pixel Shift */ #define TGA_REG_GADR 0x00f /* Address */ #define TGA_REG_GB1R 0x010 /* Bresenham 1 */ #define TGA_REG_GB2R 0x011 /* Bresenham 2 */ #define TGA_REG_GB3R 0x012 /* Bresenham 3 */ #define TGA_REG_GCTR 0x013 /* Continue */ #define TGA_REG_GDER 0x014 /* Deep */ #define TGA_REG_GREV 0x015 /* Start/Version on TGA, * Revision on TGA2 */ #define TGA_REG_GSMR 0x016 /* Stencil Mode */ #define TGA_REG_GPXR_P 0x017 /* Pixel Mask (persistent) */ #define TGA_REG_CCBR 0x018 /* Cursor Base Address */ #define TGA_REG_VHCR 0x019 /* Horizontal Control */ #define TGA_REG_VVCR 0x01a /* Vertical Control */ #define TGA_REG_VVBR 0x01b /* Video Base Address */ #define TGA_REG_VVVR 0x01c /* Video Valid */ #define TGA_REG_CXYR 0x01d /* Cursor XY */ #define TGA_REG_VSAR 0x01e /* Video Shift Address */ #define TGA_REG_SISR 0x01f /* Interrupt Status */ #define TGA_REG_GDAR 0x020 /* Data */ #define TGA_REG_GRIR 0x021 /* Red Increment */ #define TGA_REG_GGIR 0x022 /* Green Increment */ #define TGA_REG_GBIR 0x023 /* Blue Increment */ #define TGA_REG_GZIR_L 0x024 /* Z-increment Low */ #define TGA_REG_GZIR_H 0x025 /* Z-Increment High */ #define TGA_REG_GDBR 0x026 /* DMA Base Address */ #define TGA_REG_GBWR 0x027 /* Bresenham Width */ #define TGA_REG_GZVR_L 0x028 /* Z-value Low */ #define TGA_REG_GZVR_H 0x029 /* Z-value High */ #define TGA_REG_GZBR 0x02a /* Z-base address */ /* GADR alias 0x02b */ #define TGA_REG_GRVR 0x02c /* Red Value */ #define TGA_REG_GGVR 0x02d /* Green Value */ #define TGA_REG_GBVR 0x02e /* Blue Value */ #define TGA_REG_GSWR 0x02f /* Span Width */ #define TGA_REG_EPSR 0x030 /* Pallete and DAC Setup */ /* reserved 0x031 - 0x3f */ #define TGA_REG_GSNR0 0x040 /* Slope-no-go 0 */ #define TGA_REG_GSNR1 0x041 /* Slope-no-go 1 */ #define TGA_REG_GSNR2 0x042 /* Slope-no-go 2 */ #define TGA_REG_GSNR3 0x043 /* Slope-no-go 3 */ #define TGA_REG_GSNR4 0x044 /* Slope-no-go 4 */ #define TGA_REG_GSNR5 0x045 /* Slope-no-go 5 */ #define TGA_REG_GSNR6 0x046 /* Slope-no-go 6 */ #define TGA_REG_GSNR7 0x047 /* Slope-no-go 7 */ #define TGA_REG_GSLR0 0x048 /* Slope 0 */ #define TGA_REG_GSLR1 0x049 /* Slope 1 */ #define TGA_REG_GSLR2 0x04a /* Slope 2 */ #define TGA_REG_GSLR3 0x04b /* Slope 3 */ #define TGA_REG_GSLR4 0x04c /* Slope 4 */ #define TGA_REG_GSLR5 0x04d /* Slope 5 */ #define TGA_REG_GSLR6 0x04e /* Slope 6 */ #define TGA_REG_GSLR7 0x04f /* Slope 7 */ #define TGA_REG_GBCR0 0x050 /* Block Color 0 */ #define TGA_REG_GBCR1 0x051 /* Block Color 1 */ #define TGA_REG_GBCR2 0x052 /* Block Color 2 */ #define TGA_REG_GBCR3 0x053 /* Block Color 3 */ #define TGA_REG_GBCR4 0x054 /* Block Color 4 */ #define TGA_REG_GBCR5 0x055 /* Block Color 5 */ #define TGA_REG_GBCR6 0x056 /* Block Color 6 */ #define TGA_REG_GBCR7 0x057 /* Block Color 7 */ #define TGA_REG_GCSR 0x058 /* Copy 64 Source */ #define TGA_REG_GCDR 0x059 /* Copy 64 Destination */ /* GC[SD]R aliases 0x05a - 0x05f */ /* reserved 0x060 - 0x077 */ #define TGA_REG_ERWR 0x078 /* EEPROM write */ /* reserved 0x079 */ #define TGA_REG_ECGR 0x07a /* Clock */ /* reserved 0x07b */ #define TGA_REG_EPDR 0x07c /* Pallete and DAC Data */ /* reserved 0x07d */ #define TGA_REG_SCSR 0x07e /* Command Status */ /* reserved 0x07f */ /* * Video Valid Register */ #define VVR_VIDEOVALID 0x00000001 /* 0 VGA, 1 TGA2 (TGA2 only) */ #define VVR_BLANK 0x00000002 /* 0 active, 1 blank */ #define VVR_CURSOR 0x00000004 /* 0 disable, 1 enable (TGA2 R/O) */ #define VVR_INTERLACE 0x00000008 /* 0 N/Int, 1 Int. (TGA2 R/O) */ #define VVR_DPMS_MASK 0x00000030 /* See "DMPS mask" below */ #define VVR_DPMS_SHIFT 4 #define VVR_DDC 0x00000040 /* DDC-in pin value (R/O) */ #define VVR_TILED 0x00000400 /* 0 linear, 1 tiled (not on TGA2) */ #define VVR_LDDLY_MASK 0x01ff0000 /* load delay in quad pixel clock ticks (not on TGA2) */ #define VVR_LDDLY_SHIFT 16 #endif /* _ALPHA_INCLUDE_TGAREG_H_ */ gxemul-0.6.1/src/include/thirdparty/algor_p5064reg.h000644 001750 001750 00000013130 13402411502 022440 0ustar00debugdebug000000 000000 /* GXemul: $Id: algor_p5064reg.h,v 1.1 2006-02-18 17:55:25 debug Exp $ */ /* $NetBSD: algor_p5064reg.h,v 1.2 2002/02/20 01:34:19 simonb Exp $ */ #ifndef P5064_H #define P5064_H /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Memory map and register definitions for the Algorithmics P-5064. */ #define P5064_MEMORY 0x00000000UL /* onboard DRAM memory */ /* 256 MB */ #define P5064_ISAMEM 0x10000000UL /* ISA window of PCI memory */ /* 8MB */ #define P5064_PCIMEM 0x11000000UL /* PCI memory window */ /* 112MB */ #define P5064_PCIIO 0x1d000000UL /* PCI I/O window */ /* 16MB */ #define P5064_PCICFG 0x1ee00000UL /* PCI config space */ /* 1MB */ #define P5064_V360EPC 0x1ef00000UL /* V360EPC PCI controller */ /* 64KB */ #define P5064_CFGBOOT_W 0x1f800000UL /* configured bootstrap (W) */ /* 512KB */ #define P5064_SOCKET_W 0x1f900000UL /* socket EPROM (W) */ /* 512KB */ #define P5064_FLASH_W 0x1fa00000UL /* flash (W) */ /* 1MB */ #define P5064_CFBOOT 0x1fc00000UL /* configured bootstrap */ /* 512KB */ #define P5064_SOCKET 0x1fd00000UL /* socket EPROM */ /* 512KB */ #define P5064_FLASH 0x1fe00000UL /* flash */ /* 1MB */ #define P5064_LED0 0x1ff00000UL /* LED (1reg) */ #define P5064_LED1 0x1ff20010UL /* LED (4reg) */ #define P5064_LCD 0x1ff30000UL /* LCD display */ #define P5064_Z80GPIO 0x1ff40000UL /* Z80 GPIO (rev B only) */ #define P5064_Z80GPIO_IACK 0x1ff50000UL /* intr. ack. for Z80 */ #define P5064_DBG_UART 0x1ff60000UL /* UART on debug board */ #define P5064_LOCINT 0x1ff90000UL /* local interrupts */ #define P5064_PANIC 0x1ff90004UL /* panic interrupts */ #define P5064_PCIINT 0x1ff90008UL /* PCI interrupts */ #define P5064_ISAINT 0x1ff9000cUL /* ISA interrupts */ #define P5064_XBAR0 0x1ff90010UL /* Int. xbar 0 */ #define P5064_XBAR1 0x1ff90014UL /* Int. xbar 1 */ #define P5064_XBAR2 0x1ff90018UL /* Int. xbar 2 */ #define P5064_XBAR3 0x1ff9001cUL /* Int. xbar 3 */ #define P5064_XBAR4 0x1ff90020UL /* Int. xbar 4 */ #define P5064_KBDINT 0x1ff90024UL /* keyboard interrupts */ #define P5064_LOGICREV 0x1ff9003cUL /* logic revision */ #define P5064_CFG0 0x1ffa0000UL /* board configuration 0 */ #define P5064_CFG1 0x1ffb0000UL /* board configuration 1 */ #define P5064_DRAMCFG 0x1ffc0000UL /* DRAM configuration */ #define P5064_BOARDREV 0x1ffd0000UL /* board revision */ #define P5064_PCIMEM_HI 0x20000000UL /* PCI memory high window */ /* 3.5GB */ /* P5064_LOCINT */ #define LOCINT_PCIBR 0x01 #define LOCINT_FLP 0x02 #define LOCINT_MKBD 0x04 #define LOCINT_COM1 0x08 #define LOCINT_COM2 0x10 #define LOCINT_CENT 0x20 #define LOCINT_RTC 0x80 /* P5064_PANIC */ #define PANIC_DEBUG 0x01 #define PANIC_PFAIL 0x02 #define PANIC_BERR 0x04 #define PANIC_ISANMI 0x08 #define PANIC_IOPERR 0x10 #define PANIC_CENT 0x20 #define PANIC_EWAKE 0x40 #define PANIC_ECODERR 0x80 /* P5064_PCIINT */ #define PCIINT_EMDINT 0x01 #define PCIINT_ETH 0x02 #define PCIINT_SCSI 0x04 #define PCIINT_USB 0x08 #define PCIINT_PCI0 0x10 #define PCIINT_PCI1 0x20 #define PCIINT_PCI2 0x40 #define PCIINT_PCI3 0x80 /* P5064_ISAINT */ #define ISAINT_ISABR 0x01 #define ISAINT_IDE0 0x02 #define ISAINT_IDE1 0x04 /* P5064_KBDINT */ #define KBDINT_KBD 0x01 #define KBDINT_MOUSE 0x02 /* * The Algorithmics PMON initializes two DMA windows: * * THE MANUAL CLAIMS THIS: * PCI 0080.0000 -> Phys 0080.0000 (8MB) * * THE PMON FIRMWARE DOES THIS: * PCI 0080.0000 -> Phys 0000.0000 (8MB) * * PCI 8000.0000 -> Phys 0000.0000 (256MB) */ #define P5064_DMA_ISA_PCIBASE 0x00800000UL #define P5064_DMA_ISA_PHYSBASE 0x00000000UL #define P5064_DMA_ISA_SIZE (8 * 1024 * 1024) #define P5064_DMA_PCI_PCIBASE 0x80000000UL #define P5064_DMA_PCI_PHYSBASE 0x00000000UL #define P5064_DMA_PCI_SIZE (256 * 1024 * 1024) #endif /* P5064 */ gxemul-0.6.1/src/include/thirdparty/exec_ecoff_mips.h000644 001750 001750 00000010515 13402411502 023122 0ustar00debugdebug000000 000000 /* gxemul: $Id: exec_ecoff_mips.h,v 1.7 2005-03-05 12:34:02 debug Exp $ * Addition of some ECOFF magin numbers, and ECOFF_BADMAG has been commented * out to avoid warnings on Solaris. */ #ifndef EXEC_ECOFF_MIPS_H #define EXEC_ECOFF_MIPS_H /* $NetBSD: ecoff_machdep.h,v 1.18 2002/03/05 14:12:29 simonb Exp $ */ /* * Copyright (c) 1997 Jonathan Stone * All rights reserved. * * Copyright (c) 1994 Adam Glass * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Adam Glass. * 4. The name of the Author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Adam Glass BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define ECOFF_LDPGSZ 4096 #define ECOFF_PAD /* gxemul NOTE: Original types in NetBSD were 'u_long', not uint32_t */ #define ECOFF_MACHDEP \ uint32_t gprmask; \ uint32_t cprmask[4]; \ uint32_t gp_value #ifdef _KERNEL #include /* mips CPU architecture levels */ #define _MIPS3_OK() CPUISMIPS3 #else #define _MIPS3_OK() 1 #endif #define ECOFF_MAGIC_MIPSEB 0x0160 /* mips1, big-endian */ #define ECOFF_MAGIC_MIPSEL 0x0162 /* mips1, little-endian */ #define ECOFF_MAGIC_MIPSEB2 0x0163 /* mips2, big-endian (gxemul addition) */ #define ECOFF_MAGIC_MIPSEL2 0x0166 /* mips2, little-endian (gxemul addition) */ #define ECOFF_MAGIC_MIPSEB3 0x0140 /* mips3, big-endian (gxemul addition) */ #define ECOFF_MAGIC_MIPSEL3 0x0142 /* mips3, little-endian */ #if 0 /* commented out in gxemul, to avoid warnings on Solaris */ #if BYTE_ORDER == LITTLE_ENDIAN #define ECOFF_BADMAG(ep) \ (! \ ((ep)->f.f_magic == ECOFF_MAGIC_MIPSEL || \ (_MIPS3_OK() && (ep)->f.f_magic == ECOFF_MAGIC_MIPSEL3)) \ ) #endif #if BYTE_ORDER == BIG_ENDIAN #define ECOFF_BADMAG(ep) ((ep)->f.f_magic != ECOFF_MAGIC_MIPSEB) #endif #endif /* gxemul */ #define ECOFF_SEGMENT_ALIGNMENT(ep) ((ep)->a.vstamp < 23 ? 8 : 16) #ifdef _KERNEL struct proc; struct exec_package; void cpu_exec_ecoff_setregs(struct proc *, struct exec_package *, u_long); #endif /* _KERNEL */ /* * ECOFF symbol definitions for 32-bit mips. * XXX 64-bit (mips3?) may be different. */ struct ecoff_symhdr { int16_t magic; int16_t vstamp; int32_t ilineMax; int32_t cbLine; int32_t cbLineOffset; int32_t idnMax; int32_t cbDnOffset; int32_t ipdMax; int32_t cbPdOffset; int32_t isymMax; int32_t cbSymOffset; int32_t ioptMax; int32_t cbOptOffset; int32_t iauxMax; int32_t cbAuxOffset; int32_t issMax; int32_t cbSsOffset; int32_t issExtMax; int32_t cbSsExtOffset; int32_t ifdMax; int32_t cbFdOffset; int32_t crfd; int32_t cbRfdOffset; int32_t iextMax; int32_t cbExtOffset; }; #define MIPS_MAGIC_SYM 0x7009 /* gxemul addition */ /* Macro for field name used by cgd's Alpha-derived code */ #define esymMax iextMax struct ecoff_extsym { uint16_t es_flags; uint16_t es_ifd; int32_t es_strindex; int32_t es_value; unsigned es_type:6; unsigned es_class:5; unsigned :1; unsigned es_symauxindex:20; }; #endif /* EXEC_ECOFF_MIPS_H */ gxemul-0.6.1/src/include/thirdparty/alpha_lcareg.h000644 001750 001750 00000010356 13402411502 022411 0ustar00debugdebug000000 000000 /* GXemul: $Id: alpha_lcareg.h,v 1.2 2006-06-16 18:31:26 debug Exp $ */ /* $NetBSD: lcareg.h,v 1.8 1997/09/05 02:14:31 thorpej Exp $ */ #ifndef ALPHA_LCAREG_H #define ALPHA_LCAREG_H /* * Copyright (c) 1995 Carnegie-Mellon University. * All rights reserved. * * Authors: Jeffrey Hsu, Jason R. Thorpe * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * 21066 chip registers */ #define REGVAL(r) (*(volatile int32_t *)ALPHA_PHYS_TO_K0SEG(r)) #define REGVAL64(r) (*(volatile int64_t *)ALPHA_PHYS_TO_K0SEG(r)) /* * Base addresses */ #define LCA_IOC_BASE 0x180000000ULL /* LCA IOC Regs */ #define LCA_PCI_SIO 0x1c0000000ULL /* PCI Sp. I/O Space */ #define LCA_PCI_CONF 0x1e0000000ULL /* PCI Conf. Space */ #define LCA_PCI_SPARSE 0x200000000ULL /* PCI Sparse Space */ #define LCA_PCI_DENSE 0x300000000ULL /* PCI Dense Space */ #define LCA_IOC_HAE LCA_IOC_BASE /* Host Address Ext. (64) */ #define IOC_HAE_ADDREXT 0x00000000f8000000ULL #define IOC_HAE_RSVSD 0xffffffff07ffffffULL #define LCA_IOC_CONF (LCA_IOC_BASE + 0x020) /* Configuration Cycle Type */ #define LCA_IOC_STAT0 (LCA_IOC_BASE + 0x040) /* Status 0 */ #define IOC_STAT0_CMD 0x000000000000000fULL /* PCI command mask */ #define IOC_STAT0_ERR 0x0000000000000010ULL /* IOC error indicator R/W1C */ #define IOC_STAT0_LOST 0x0000000000000020ULL /* IOC lose error info R/W1C */ #define IOC_STAT0_THIT 0x0000000000000040ULL /* test hit */ #define IOC_STAT0_TREF 0x0000000000000080ULL /* test reference */ #define IOC_STAT0_CODE 0x0000000000000700ULL /* code mask */ #define IOC_STAT0_CODESHIFT 8 #define IOC_STAT0_P_NBR 0x00000000ffffe000ULL /* page number mask */ #define LCA_IOC_STAT1 (LCA_IOC_BASE + 0x060) /* Status 1 */ #define IOC_STAT1_ADDR 0x00000000ffffffffULL /* PCI address mask */ #define LCA_IOC_TBIA (LCA_IOC_BASE + 0x080) /* TLB Invalidate All */ #define LCA_IOC_TB_ENA (LCA_IOC_BASE + 0x0a0) /* TLB Enable */ #define IOC_TB_ENA_TEN 0x0000000000000080ULL #define LCA_IOC_W_BASE0 (LCA_IOC_BASE + 0x100) /* Window Base */ #define LCA_IOC_W_MASK0 (LCA_IOC_BASE + 0x140) /* Window Mask */ #define LCA_IOC_W_T_BASE0 (LCA_IOC_BASE + 0x180) /* Translated Base */ #define LCA_IOC_W_BASE1 (LCA_IOC_BASE + 0x120) /* Window Base */ #define LCA_IOC_W_MASK1 (LCA_IOC_BASE + 0x160) /* Window Mask */ #define LCA_IOC_W_T_BASE1 (LCA_IOC_BASE + 0x1a0) /* Translated Base */ #define IOC_W_BASE_W_BASE 0x00000000fff00000ULL /* Window base value */ #define IOC_W_BASE_SG 0x0000000100000000ULL /* Window uses SGMAPs */ #define IOC_W_BASE_WEN 0x0000000200000000ULL /* Window enable */ #define IOC_W_MASK_1M 0x0000000000000000ULL /* 1MB window */ #define IOC_W_MASK_2M 0x0000000000100000ULL /* 2MB window */ #define IOC_W_MASK_4M 0x0000000000300000ULL /* 4MB window */ #define IOC_W_MASK_8M 0x0000000000700000ULL /* 8MB window */ #define IOC_W_MASK_16M 0x0000000000f00000ULL /* 16MB window */ #define IOC_W_MASK_32M 0x0000000001f00000ULL /* 32MB window */ #define IOC_W_MASK_64M 0x0000000003f00000ULL /* 64MB window */ #define IOC_W_MASK_128M 0x0000000007f00000ULL /* 128M window */ #define IOC_W_MASK_256M 0x000000000ff00000ULL /* 256M window */ #define IOC_W_MASK_512M 0x000000001ff00000ULL /* 512M window */ #define IOC_W_MASK_1G 0x000000003ff00000ULL /* 1GB window */ #define IOC_W_MASK_2G 0x000000007ff00000ULL /* 2GB window */ #define IOC_W_MASK_4G 0x00000000fff00000ULL /* 4GB window */ #define IOC_W_T_BASE 0x00000000fffffc00ULL /* page table base */ #endif /* ALPHA_LCAREG_H */ gxemul-0.6.1/src/include/thirdparty/fast_mutex.h000644 001750 001750 00000022620 13402411502 022163 0ustar00debugdebug000000 000000 /* * Modified for GXemul: * * 1. Classes have Doxygen brief sections, indicating that they are * part of Wu Yongwei's debug new/delete package. */ // -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- // vim:tabstop=4:shiftwidth=4:expandtab: /* * Copyright (C) 2004-2005 Wu Yongwei * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any * damages arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute * it freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must * not claim that you wrote the original software. If you use this * software in a product, an acknowledgment in the product * documentation would be appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must * not be misrepresented as being the original software. * 3. This notice may not be removed or altered from any source * distribution. * * This file is part of Stones of Nvwa: * http://sourceforge.net/projects/nvwa * */ /** * @file fast_mutex.h * * A fast mutex implementation for POSIX and Win32. * * @version 1.18, 2005/05/06 * @author Wu Yongwei * */ #ifndef _FAST_MUTEX_H #define _FAST_MUTEX_H # if !defined(_NOTHREADS) # if !defined(_WIN32THREADS) && \ (defined(_WIN32) && defined(_MT)) // Automatically use _WIN32THREADS when specifying -MT/-MD in MSVC, // or -mthreads in MinGW GCC. # define _WIN32THREADS # elif !defined(_PTHREADS) && \ defined(_REENTRANT) // Automatically use _PTHREADS when specifying -pthread in GCC. // N.B. I do not detect on _PTHREAD_H since libstdc++-v3 under // Linux will silently include anyway. # define _PTHREADS # endif # endif # if !defined(_PTHREADS) && !defined(_WIN32THREADS) && !defined(_NOTHREADS) # define _NOTHREADS # endif # if defined(_NOTHREADS) # if defined(_PTHREADS) || defined(_WIN32THREADS) # undef _NOTHREADS # error "Cannot define multi-threaded mode with -D_NOTHREADS" # if defined(__MINGW32__) && defined(_WIN32THREADS) && !defined(_MT) # error "Be sure to specify -mthreads with -D_WIN32THREADS" # endif # endif # endif # ifndef _FAST_MUTEX_CHECK_INITIALIZATION /** * Macro to control whether to check for initialization status for each * lock/unlock operation. Defining it to a non-zero value will enable * the check, so that the construction/destruction of a static object * using a static fast_mutex not yet constructed or already destroyed * will work (with lock/unlock operations ignored). Defining it to zero * will disable to check. */ # define _FAST_MUTEX_CHECK_INITIALIZATION 1 # endif # if defined(_PTHREADS) && defined(_WIN32THREADS) // Some C++ libraries have _PTHREADS defined even on Win32 platforms. // Thus this hack. # undef _PTHREADS # endif # ifdef _DEBUG # include # include /** Macro for fast_mutex assertions. Real version (for debug mode). */ # define _FAST_MUTEX_ASSERT(_Expr, _Msg) \ if (!(_Expr)) { \ fprintf(stderr, "fast_mutex::%s\n", _Msg); \ abort(); \ } # else /** Macro for fast_mutex assertions. Fake version (for release mode). */ # define _FAST_MUTEX_ASSERT(_Expr, _Msg) \ ((void)0) # endif # ifdef _PTHREADS # include /** * Macro alias to `volatile' semantics. Here it is truly volatile since * it is in a multi-threaded (POSIX threads) environment. */ # define __VOLATILE volatile /** * \brief Part of Wu Yongwei's new/delete debug * memory leak detector. * * Class for non-reentrant fast mutexes. This is the implementation * for POSIX threads. */ class fast_mutex { pthread_mutex_t _M_mtx_impl; # if _FAST_MUTEX_CHECK_INITIALIZATION bool _M_initialized; # endif # ifdef _DEBUG bool _M_locked; # endif public: fast_mutex() # ifdef _DEBUG : _M_locked(false) # endif { ::pthread_mutex_init(&_M_mtx_impl, NULL); # if _FAST_MUTEX_CHECK_INITIALIZATION _M_initialized = true; # endif } ~fast_mutex() { _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked"); # if _FAST_MUTEX_CHECK_INITIALIZATION _M_initialized = false; # endif ::pthread_mutex_destroy(&_M_mtx_impl); } void lock() { # if _FAST_MUTEX_CHECK_INITIALIZATION if (!_M_initialized) return; # endif ::pthread_mutex_lock(&_M_mtx_impl); # ifdef _DEBUG // The following assertion should _always_ be true for a // real `fast' pthread_mutex. However, this assertion can // help sometimes, when people forget to use `-lpthread' and // glibc provides an empty implementation. Having this // assertion is also more consistent. _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked"); _M_locked = true; # endif } void unlock() { # if _FAST_MUTEX_CHECK_INITIALIZATION if (!_M_initialized) return; # endif # ifdef _DEBUG _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked"); _M_locked = false; # endif ::pthread_mutex_unlock(&_M_mtx_impl); } private: fast_mutex(const fast_mutex&); fast_mutex& operator=(const fast_mutex&); }; # endif // _PTHREADS # ifdef _WIN32THREADS # include /** * Macro alias to `volatile' semantics. Here it is truly volatile since * it is in a multi-threaded (Win32 threads) environment. */ # define __VOLATILE volatile /** * \brief Part of Wu Yongwei's new/delete debug * memory leak detector. * * Class for non-reentrant fast mutexes. This is the implementation * for Win32 threads. */ class fast_mutex { CRITICAL_SECTION _M_mtx_impl; # if _FAST_MUTEX_CHECK_INITIALIZATION bool _M_initialized; # endif # ifdef _DEBUG bool _M_locked; # endif public: fast_mutex() # ifdef _DEBUG : _M_locked(false) # endif { ::InitializeCriticalSection(&_M_mtx_impl); # if _FAST_MUTEX_CHECK_INITIALIZATION _M_initialized = true; # endif } ~fast_mutex() { _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked"); # if _FAST_MUTEX_CHECK_INITIALIZATION _M_initialized = false; # endif ::DeleteCriticalSection(&_M_mtx_impl); } void lock() { # if _FAST_MUTEX_CHECK_INITIALIZATION if (!_M_initialized) return; # endif ::EnterCriticalSection(&_M_mtx_impl); # ifdef _DEBUG _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked"); _M_locked = true; # endif } void unlock() { # if _FAST_MUTEX_CHECK_INITIALIZATION if (!_M_initialized) return; # endif # ifdef _DEBUG _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked"); _M_locked = false; # endif ::LeaveCriticalSection(&_M_mtx_impl); } private: fast_mutex(const fast_mutex&); fast_mutex& operator=(const fast_mutex&); }; # endif // _WIN32THREADS # ifdef _NOTHREADS /** * Macro alias to `volatile' semantics. Here it is not truly volatile * since it is in a single-threaded environment. */ # define __VOLATILE /** * \brief Part of Wu Yongwei's new/delete debug * memory leak detector. * * Class for non-reentrant fast mutexes. This is the null * implementation for single-threaded environments. */ class fast_mutex { # ifdef _DEBUG bool _M_locked; # endif public: fast_mutex() # ifdef _DEBUG : _M_locked(false) # endif { } ~fast_mutex() { _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked"); } void lock() { # ifdef _DEBUG _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked"); _M_locked = true; # endif } void unlock() { # ifdef _DEBUG _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked"); _M_locked = false; # endif } private: fast_mutex(const fast_mutex&); fast_mutex& operator=(const fast_mutex&); }; # endif // _NOTHREADS /** * \brief Part of Wu Yongwei's new/delete debug * memory leak detector. * * An acquistion-on-initialization lock class based on fast_mutex. */ class fast_mutex_autolock { fast_mutex& _M_mtx; public: explicit fast_mutex_autolock(fast_mutex& __mtx) : _M_mtx(__mtx) { _M_mtx.lock(); } ~fast_mutex_autolock() { _M_mtx.unlock(); } private: fast_mutex_autolock(const fast_mutex_autolock&); fast_mutex_autolock& operator=(const fast_mutex_autolock&); }; #endif // _FAST_MUTEX_H gxemul-0.6.1/src/include/thirdparty/mb86960reg.h000644 001750 001750 00000032066 13402411502 021522 0ustar00debugdebug000000 000000 /* $NetBSD: mb86960reg.h,v 1.10 2005/12/11 12:21:27 christos Exp $ */ #ifndef MB86960REG_H #define MB86960REG_H #define MB8696X_NREGS 32 /* * All Rights Reserved, Copyright (C) Fujitsu Limited 1995 * * This software may be used, modified, copied, distributed, and sold, in * both source and binary form provided that the above copyright, these * terms and the following disclaimer are retained. The name of the author * and/or the contributor may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Registers of Fujitsu MB86960A/MB86965A Ethernet controller. * Written and contributed by M.S. */ /* * Notes on register naming: * * Fujitsu documents for MB86960A/MB86965A use no mnemonic names * for their registers. They defined only three names for 32 * registers and appended numbers to distinguish registers of * same name. Surprisingly, the numbers represent I/O address * offsets of the registers from the base addresses, and their * names correspond to the "bank" the registers are allocated. * All this means that, for example, to say "read DLCR8" has no more * than to say "read a register at offset 8 on bank DLCR." * * The following definitions may look silly, but that's what Fujitsu * did, and it is necessary to know these names to read Fujitsu * documents.. */ /* Data Link Control Registers, on invaliant port addresses. */ #define FE_DLCR0 0 #define FE_DLCR1 1 #define FE_DLCR2 2 #define FE_DLCR3 3 #define FE_DLCR4 4 #define FE_DLCR5 5 #define FE_DLCR6 6 #define FE_DLCR7 7 /* More DLCRs, on register bank #0. */ #define FE_DLCR8 8 #define FE_DLCR9 9 #define FE_DLCR10 10 #define FE_DLCR11 11 #define FE_DLCR12 12 #define FE_DLCR13 13 #define FE_DLCR14 14 #define FE_DLCR15 15 /* Multicast Address Registers. On register bank #1. */ #define FE_MAR8 8 #define FE_MAR9 9 #define FE_MAR10 10 #define FE_MAR11 11 #define FE_MAR12 12 #define FE_MAR13 13 #define FE_MAR14 14 #define FE_MAR15 15 /* Buffer Memory Port Registers. On register bank #2. */ #define FE_BMPR8 8 #define FE_BMPR9 9 #define FE_BMPR10 10 #define FE_BMPR11 11 #define FE_BMPR12 12 #define FE_BMPR13 13 #define FE_BMPR14 14 #define FE_BMPR15 15 /* More BMPRs, only on MB86965A, accessible only when JLI mode. */ #define FE_BMPR16 16 #define FE_BMPR17 17 #define FE_BMPR18 18 #define FE_BMPR19 19 #define FE_RESET 31 /* * Definitions of registers. * I don't have Fujitsu documents of MB86960A/MB86965A, so I don't * know the official names for the flags and fields. The following * names are assigned by me (the author of this file), since I cannot * memorize hexadecimal constants for all of these functions. * Comments? FIXME. */ /* DLCR0 -- transmitter status */ #define FE_D0_BUSERR 0x01 /* Bus write error */ #define FE_D0_COLL16 0x02 /* Collision limit (16) encountered */ #define FE_D0_COLLID 0x04 /* Collision on last transmission */ #define FE_D0_JABBER 0x08 /* Jabber */ #define FE_D0_CRLOST 0x10 /* Carrier lost on last transmission */ #define FE_D0_PKTRCD 0x20 /* No collision on last transmission */ #define FE_D0_NETBSY 0x40 /* Network Busy (Carrier Detected) */ #define FE_D0_TXDONE 0x80 /* Transmission complete */ /* DLCR1 -- receiver status */ #define FE_D1_OVRFLO 0x01 /* Receiver buffer overflow */ #define FE_D1_CRCERR 0x02 /* CRC error on last packet */ #define FE_D1_ALGERR 0x04 /* Alignment error on last packet */ #define FE_D1_SRTPKT 0x08 /* Short (RUNT) packet is received */ #define FE_D1_RMTRST 0x10 /* Remote reset packet (type = 0x0900) */ #define FE_D1_DMAEOP 0x20 /* Host asserted End of DMA OPeration */ #define FE_D1_BUSERR 0x40 /* Bus read error */ #define FE_D1_PKTRDY 0x80 /* Packet(s) ready on receive buffer */ #define FE_D1_ERRBITS "\20\4SRTPKT\3ALGERR\2CRCERR\1OVRFLO" /* DLCR2 -- transmitter interrupt control; same layout as DLCR0 */ #define FE_D2_BUSERR FE_D0_BUSERR #define FE_D2_COLL16 FE_D0_COLL16 #define FE_D2_COLLID FE_D0_COLLID #define FE_D2_JABBER FE_D0_JABBER #define FE_D2_TXDONE FE_D0_TXDONE #define FE_D2_RESERVED 0x70 /* DLCR3 -- receiver interrupt control; same layout as DLCR1 */ #define FE_D3_OVRFLO FE_D1_OVRFLO #define FE_D3_CRCERR FE_D1_CRCERR #define FE_D3_ALGERR FE_D1_ALGERR #define FE_D3_SRTPKT FE_D1_SRTPKT #define FE_D3_RMTRST FE_D1_RMTRST #define FE_D3_DMAEOP FE_D1_DMAEOP #define FE_D3_BUSERR FE_D1_BUSERR #define FE_D3_PKTRDY FE_D1_PKTRDY /* DLCR4 -- transmitter operation mode */ #define FE_D4_DSC 0x01 /* Disable carrier sense on trans. */ #define FE_D4_LBC 0x02 /* Loop back test control */ #define FE_D4_CNTRL 0x04 /* - ??? */ #define FE_D4_TEST1 0x08 /* Test output #1 */ #define FE_D4_COL 0xF0 /* Collision counter */ #define FE_D4_LBC_ENABLE 0x00 /* Perform loop back test */ #define FE_D4_LBC_DISABLE 0x02 /* Normal operation */ #define FE_D4_COL_SHIFT 4 /* DLCR5 -- receiver operation mode */ #define FE_D5_AFM0 0x01 /* Receive packets for other stations */ #define FE_D5_AFM1 0x02 /* Receive packets for this station */ #define FE_D5_RMTRST 0x04 /* Enable remote reset operation */ #define FE_D5_SRTPKT 0x08 /* Accept short (RUNT) packets */ #define FE_D5_SRTADR 0x10 /* Short (16 bits?) MAC address */ #define FE_D5_BADPKT 0x20 /* Accept packets with error */ #define FE_D5_BUFEMP 0x40 /* Receive buffer is empty */ #define FE_D5_TEST2 0x80 /* Test output #2 */ /* DLCR6 -- hardware configuration #0 */ #define FE_D6_BUFSIZ 0x03 /* Size of NIC buffer SRAM */ #define FE_D6_TXBSIZ 0x0C /* Size (and config)of trans. buffer */ #define FE_D6_BBW 0x10 /* Buffer SRAM bus width */ #define FE_D6_SBW 0x20 /* System bus width */ #define FE_D6_SRAM 0x40 /* Buffer SRAM access time */ #define FE_D6_DLC 0x80 /* Disable DLC (receiver/transmitter) */ #define FE_D6_BUFSIZ_8KB 0x00 /* The board has 8KB SRAM */ #define FE_D6_BUFSIZ_16KB 0x01 /* The board has 16KB SRAM */ #define FE_D6_BUFSIZ_32KB 0x02 /* The board has 32KB SRAM */ #define FE_D6_BUFSIZ_64KB 0x03 /* The board has 64KB SRAM */ #define FE_D6_TXBSIZ_1x2KB 0x00 /* Single 2KB buffer for trans. */ #define FE_D6_TXBSIZ_2x2KB 0x04 /* Double 2KB buffers */ #define FE_D6_TXBSIZ_2x4KB 0x08 /* Double 4KB buffers */ #define FE_D6_TXBSIZ_2x8KB 0x0C /* Double 8KB buffers */ #define FE_D6_BBW_WORD 0x00 /* SRAM has 16 bit data line */ #define FE_D6_BBW_BYTE 0x10 /* SRAM has 8 bit data line */ #define FE_D6_SBW_WORD 0x00 /* Access with 16 bit (AT) bus */ #define FE_D6_SBW_BYTE 0x20 /* Access with 8 bit (XT) bus */ #define FE_D6_SRAM_150ns 0x00 /* The board has slow SRAM */ #define FE_D6_SRAM_100ns 0x40 /* The board has fast SRAM */ #define FE_D6_DLC_ENABLE 0x00 /* Normal operation */ #define FE_D6_DLC_DISABLE 0x80 /* Stop sending/receiving */ /* DLC7 -- hardware configuration #1 */ #define FE_D7_BYTSWP 0x01 /* Host byte order control */ #define FE_D7_EOPPOL 0x02 /* Polarity of DMA EOP signal */ #define FE_D7_RBS 0x0C /* Register bank select */ #define FE_D7_RDYPNS 0x10 /* Senses RDYPNSEL input signal */ #define FE_D7_POWER 0x20 /* Stand-by (power down) mode control */ #define FE_D7_ED 0xC0 /* Encoder/Decoder config (for MB86960) */ #define FE_D7_IDENT 0xC0 /* Chip identification */ #define FE_D7_BYTSWP_LH 0x00 /* DEC/Intel byte order */ #define FE_D7_BYTSWP_HL 0x01 /* IBM/Motorolla byte order */ #define FE_D7_RBS_DLCR 0x00 /* Select DLCR8-15 */ #define FE_D7_RBS_MAR 0x04 /* Select MAR8-15 */ #define FE_D7_RBS_BMPR 0x08 /* Select BMPR8-15 */ #define FE_D7_POWER_DOWN 0x00 /* Power down (stand-by) mode */ #define FE_D7_POWER_UP 0x20 /* Normal operation */ #define FE_D7_ED_NORMAL 0x00 /* Normal NICE */ #define FE_D7_ED_MON 0x40 /* NICE + Monitor */ #define FE_D7_ED_BYPASS 0x80 /* Encoder/Decorder Bypass */ #define FE_D7_ED_TEST 0xC0 /* Encoder/Decorder Test */ #define FE_D7_IDENT_86960 0x00 /* MB86960 (NICE) */ #define FE_D7_IDENT_86964 0x40 /* MB86964 */ #define FE_D7_IDENT_86967 0x80 /* MB86967 */ #define FE_D7_IDENT_86965 0xC0 /* MB86965 (EtherCoupler) */ /* DLCR8 thru DLCR13 are for Ethernet station address. */ /* DLCR14 and DLCR15 are for TDR (Time Domain Reflectometry). */ /* MAR8 thru MAR15 are for Multicast address filter. */ /* BMPR8 and BMPR9 are for packet data. */ /* BMPR10 -- transmitter start trigger */ #define FE_B10_START 0x80 /* Start transmitter */ #define FE_B10_COUNT 0x7F /* Packet count */ /* BMPR11 -- 16 collisions control */ #define FE_B11_CTRL 0x01 /* Skip or resend errored packets */ #define FE_B11_MODE1 0x02 /* Restart transmitter after COLL16 */ #define FE_B11_MODE2 0x04 /* Automatic restart enable */ #define FE_B11_CTRL_RESEND 0x00 /* Re-send the collided packet */ #define FE_B11_CTRL_SKIP 0x01 /* Skip the collided packet */ /* BMPR12 -- DMA enable */ #define FE_B12_TXDMA 0x01 /* Enable transmitter DMA */ #define FE_B12_RXDMA 0x02 /* Enable receiver DMA */ /* BMPR13 -- DMA control */ #define FE_B13_BSTCTL 0x03 /* DMA burst mode control */ #define FE_B13_TPTYPE 0x04 /* Twisted pair cable impedance */ #define FE_B13_PORT 0x18 /* Port (TP/AUI) selection */ #define FE_B13_LNKTST 0x20 /* Link test enable */ #define FE_B13_SQTHLD 0x40 /* Lower squelch threshold */ #define FE_B13_IOUNLK 0x80 /* Change I/O base address */ #define FE_B13_BSTCTL_1 0x00 #define FE_B13_BSTCTL_4 0x01 #define FE_B13_BSTCTL_8 0x02 #define FE_B13_BSTCLT_12 0x03 #define FE_B13_TPTYPE_UTP 0x00 /* Unshielded (standard) cable */ #define FE_B13_TPTYPE_STP 0x04 /* Shielded (IBM) cable */ #define FE_B13_PORT_AUTO 0x00 /* Auto detected */ #define FE_B13_PORT_TP 0x08 /* Force TP */ #define FE_B13_PORT_AUI 0x18 /* Force AUI */ /* BMPR14 -- More receiver control and more transmission interrupts */ #define FE_B14_FILTER 0x01 /* Filter out self-originated packets */ #define FE_B14_SQE 0x02 /* SQE interrupt enable */ #define FE_B14_SKIP 0x04 /* Skip a received packet */ #define FE_B14_RJAB 0x20 /* RJAB interrupt enable */ #define FE_B14_LLD 0x40 /* Local-link-down interrupt enable */ #define FE_B14_RLD 0x80 /* Remote-link-down interrupt enable */ /* BMPR15 -- More transmitter status; basically same layout as BMPR14 */ #define FE_B15_SQE FE_B14_SQE #define FE_B15_RCVPOL 0x08 /* Reversed receive line polarity */ #define FE_B15_RMTPRT 0x10 /* ??? */ #define FE_B15_RAJB FE_B14_RJAB #define FE_B15_LLD FE_B14_LLD #define FE_B15_RLD FE_B14_RLD /* BMPR16 -- EEPROM control */ #define FE_B16_DOUT 0x04 /* EEPROM Data in (CPU to EEPROM) */ #define FE_B16_SELECT 0x20 /* EEPROM chip select */ #define FE_B16_CLOCK 0x40 /* EEPROM shift clock */ #define FE_B16_DIN 0x80 /* EEPROM data out (EEPROM to CPU) */ /* BMPR17 -- EEPROM data */ #define FE_B17_DATA 0x80 /* EEPROM data bit */ /* BMPR18 I/O Base Address (Only JLI mode) */ /* BMPR19 -- Jumperless Setting (Only JLI mode) */ #define FE_B19_IRQ 0xC0 #define FE_B19_IRQ_SHIFT 6 #define FE_B19_ROM 0x38 #define FE_B19_ROM_SHIFT 3 #define FE_B19_ADDR 0x07 #define FE_B19_ADDR_SHIFT 0 /* * EEPROM specification (of JLI mode). */ /* Number of bytes in an EEPROM accessible through 86965. */ #define FE_EEPROM_SIZE 32 /* Offset for JLI config; automatically copied into BMPR19 at startup. */ #define FE_EEPROM_CONF 0x00 /* Delay for 93c06 EEPROM access */ #define FE_EEPROM_DELAY() DELAY(4) /* * EEPROM allocation of AT1700/RE2000. */ #define FE_ATI_EEP_ADDR 0x08 /* Station address (0x08-0x0d) */ #define FE_ATI_EEP_MEDIA 0x18 /* Media type */ #define FE_ATI_EEP_MAGIC 0x19 /* XXX Magic */ #define FE_ATI_EEP_MODEL 0x1e /* Hardware type */ #define FE_ATI_MODEL_AT1700T 0x00 #define FE_ATI_MODEL_AT1700BT 0x01 #define FE_ATI_MODEL_AT1700FT 0x02 #define FE_ATI_MODEL_AT1700AT 0x03 #define FE_ATI_EEP_REVISION 0x1f /* Hardware revision */ /* * Some 86960 specific constants. */ /* Length (in bytes) of a Multicast Address Filter. */ #define FE_FILTER_LEN 8 /* How many packets we can put in the transmission buffer on NIC memory. */ #define FE_QUEUEING_MAX 127 /* Size (in bytes) of a "packet length" word in transmission buffer. */ #define FE_TXLEN_SIZE 2 /* receive packet status in the receive packet header. */ #define FE_RXSTAT_GOODPKT 0x20 #define FE_RXSTAT_RMT0900 0x10 #define FE_RXSTAT_SHORTPKT 0x08 #define FE_RXSTAT_ALIGNERR 0x04 #define FE_RXSTAT_CRCERR 0x02 /* * FUJITSU MBH10302 specific Registers. */ #define FE_MBH0 0x10 /* Master interrupt register */ #define FE_MBH_ENADDR 0x1A /* Mac address */ #define FE_MBH0_MASK 0x0D #define FE_MBH0_INTR_ENABLE 0x10 /* Enable interrupts */ #endif /* MB86960REG_H */ gxemul-0.6.1/src/include/thirdparty/xmireg.h000644 001750 001750 00000004641 13402411502 021302 0ustar00debugdebug000000 000000 /* $NetBSD: xmireg.h,v 1.1 2000/07/06 17:45:53 ragge Exp $ */ /* * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed at Ludd, University of * Lule}, Sweden and its contributors. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * XMI node definitions. */ /* * XMI node addresses */ #define XMI_NODESIZE 0x80000 /* Size of one XMI node (512k) */ #define XMI_NODE(node) (XMI_NODESIZE * (node)) #define NNODEXMI 16 /* 16 nodes per BI */ /* XMI generic register offsets */ #define XMI_TYPE 0 #define XMI_BUSERR 4 #define XMI_FAIL 8 /* Types of devices that may exist */ #define XMIDT_KA62 0x8001 /* VAX 6200 CPU */ #define XMIDT_KA64 0x8082 /* VAX 6400 CPU */ #define XMIDT_KA65 0x8080 /* VAX 6500 CPU */ #define XMIDT_KA66 0x8083 /* VAX 6600 CPU */ #define XMIDT_ISIS 0x8081 /* MIPS R3000 CPU */ #define XMIDT_MS62 0x4001 /* Memory */ #define XMIDT_DWMBA 0x2001 /* XMI to BI adapter */ gxemul-0.6.1/src/include/thirdparty/errno_netbsd.h000644 001750 001750 00000021140 13402411502 022464 0ustar00debugdebug000000 000000 /* GXemul: $Id: errno_netbsd.h,v 1.1 2007-06-15 01:08:13 debug Exp $ */ /* $NetBSD: errno.h,v 1.39 2006/10/31 00:38:07 cbiere NETBSD_Exp $ */ #ifndef ERRNO_NETBSD_H #define ERRNO_NETBSD_H /* * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)errno.h 8.5 (Berkeley) 1/21/94 */ #define NETBSD_EPERM 1 /* Operation not permitted */ #define NETBSD_ENOENT 2 /* No such file or directory */ #define NETBSD_ESRCH 3 /* No such process */ #define NETBSD_EINTR 4 /* Interrupted system call */ #define NETBSD_EIO 5 /* Input/output error */ #define NETBSD_ENXIO 6 /* Device not configured */ #define NETBSD_E2BIG 7 /* Argument list too long */ #define NETBSD_ENOEXEC 8 /* Exec format error */ #define NETBSD_EBADF 9 /* Bad file descriptor */ #define NETBSD_ECHILD 10 /* No child processes */ #define NETBSD_EDEADLK 11 /* Resource deadlock avoided */ /* 11 was EAGAIN */ #define NETBSD_ENOMEM 12 /* Cannot allocate memory */ #define NETBSD_EACCES 13 /* Permission denied */ #define NETBSD_EFAULT 14 /* Bad address */ #define NETBSD_ENOTBLK 15 /* Block device required */ #define NETBSD_EBUSY 16 /* Device busy */ #define NETBSD_EEXIST 17 /* File exists */ #define NETBSD_EXDEV 18 /* Cross-device link */ #define NETBSD_ENODEV 19 /* Operation not supported by device */ #define NETBSD_ENOTDIR 20 /* Not a directory */ #define NETBSD_EISDIR 21 /* Is a directory */ #define NETBSD_EINVAL 22 /* Invalid argument */ #define NETBSD_ENFILE 23 /* Too many open files in system */ #define NETBSD_EMFILE 24 /* Too many open files */ #define NETBSD_ENOTTY 25 /* Inappropriate ioctl for device */ #define NETBSD_ETXTBSY 26 /* Text file busy */ #define NETBSD_EFBIG 27 /* File too large */ #define NETBSD_ENOSPC 28 /* No space left on device */ #define NETBSD_ESPIPE 29 /* Illegal seek */ #define NETBSD_EROFS 30 /* Read-only file system */ #define NETBSD_EMLINK 31 /* Too many links */ #define NETBSD_EPIPE 32 /* Broken pipe */ /* math software */ #define NETBSD_EDOM 33 /* Numerical argument out of domain */ #define NETBSD_ERANGE 34 /* Result too large or too small */ /* non-blocking and interrupt i/o */ #define NETBSD_EAGAIN 35 /* Resource temporarily unavailable */ #define NETBSD_EWOULDBLOCK EAGAIN /* Operation would block */ #define NETBSD_EINPROGRESS 36 /* Operation now in progress */ #define NETBSD_EALREADY 37 /* Operation already in progress */ /* ipc/network software -- argument errors */ #define NETBSD_ENOTSOCK 38 /* Socket operation on non-socket */ #define NETBSD_EDESTADDRREQ 39 /* Destination address required */ #define NETBSD_EMSGSIZE 40 /* Message too long */ #define NETBSD_EPROTOTYPE 41 /* Protocol wrong type for socket */ #define NETBSD_ENOPROTOOPT 42 /* Protocol option not available */ #define NETBSD_EPROTONOSUPPORT 43 /* Protocol not supported */ #define NETBSD_ESOCKTNOSUPPORT 44 /* Socket type not supported */ #define NETBSD_EOPNOTSUPP 45 /* Operation not supported */ #define NETBSD_EPFNOSUPPORT 46 /* Protocol family not supported */ #define NETBSD_EAFNOSUPPORT 47 /* Address family not supported by protocol family */ #define NETBSD_EADDRINUSE 48 /* Address already in use */ #define NETBSD_EADDRNOTAVAIL 49 /* Can't assign requested address */ /* ipc/network software -- operational errors */ #define NETBSD_ENETDOWN 50 /* Network is down */ #define NETBSD_ENETUNREACH 51 /* Network is unreachable */ #define NETBSD_ENETRESET 52 /* Network dropped connection on reset */ #define NETBSD_ECONNABORTED 53 /* Software caused connection abort */ #define NETBSD_ECONNRESET 54 /* Connection reset by peer */ #define NETBSD_ENOBUFS 55 /* No buffer space available */ #define NETBSD_EISCONN 56 /* Socket is already connected */ #define NETBSD_ENOTCONN 57 /* Socket is not connected */ #define NETBSD_ESHUTDOWN 58 /* Can't send after socket shutdown */ #define NETBSD_ETOOMANYREFS 59 /* Too many references: can't splice */ #define NETBSD_ETIMEDOUT 60 /* Operation timed out */ #define NETBSD_ECONNREFUSED 61 /* Connection refused */ #define NETBSD_ELOOP 62 /* Too many levels of symbolic links */ #define NETBSD_ENAMETOOLONG 63 /* File name too long */ /* should be rearranged */ #define NETBSD_EHOSTDOWN 64 /* Host is down */ #define NETBSD_EHOSTUNREACH 65 /* No route to host */ #define NETBSD_ENOTEMPTY 66 /* Directory not empty */ /* quotas & mush */ #define NETBSD_EPROCLIM 67 /* Too many processes */ #define NETBSD_EUSERS 68 /* Too many users */ #define NETBSD_EDQUOT 69 /* Disc quota exceeded */ /* Network File System */ #define NETBSD_ESTALE 70 /* Stale NFS file handle */ #define NETBSD_EREMOTE 71 /* Too many levels of remote in path */ #define NETBSD_EBADRPC 72 /* RPC struct is bad */ #define NETBSD_ERPCMISMATCH 73 /* RPC version wrong */ #define NETBSD_EPROGUNAVAIL 74 /* RPC prog. not avail */ #define NETBSD_EPROGMISMATCH 75 /* Program version wrong */ #define NETBSD_EPROCUNAVAIL 76 /* Bad procedure for program */ #define NETBSD_ENOLCK 77 /* No locks available */ #define NETBSD_ENOSYS 78 /* Function not implemented */ #define NETBSD_EFTYPE 79 /* Inappropriate file type or format */ #define NETBSD_EAUTH 80 /* Authentication error */ #define NETBSD_ENEEDAUTH 81 /* Need authenticator */ /* SystemV IPC */ #define NETBSD_EIDRM 82 /* Identifier removed */ #define NETBSD_ENOMSG 83 /* No message of desired type */ #define NETBSD_EOVERFLOW 84 /* Value too large to be stored in data type */ /* Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995 */ #define NETBSD_EILSEQ 85 /* Illegal byte sequence */ /* From IEEE Std 1003.1-2001 */ /* Base, Realtime, Threads or Thread Priority Scheduling option errors */ #define NETBSD_ENOTSUP 86 /* Not supported */ /* Realtime option errors */ #define NETBSD_ECANCELED 87 /* Operation canceled */ /* Realtime, XSI STREAMS option errors */ #define NETBSD_EBADMSG 88 /* Bad or Corrupt message */ /* XSI STREAMS option errors */ #define NETBSD_ENODATA 89 /* No message available */ #define NETBSD_ENOSR 90 /* No STREAM resources */ #define NETBSD_ENOSTR 91 /* Not a STREAM */ #define NETBSD_ETIME 92 /* STREAM ioctl timeout */ /* File system extended attribute errors */ #define NETBSD_ENOATTR 93 /* Attribute not found */ /* Realtime, XSI STREAMS option errors */ #define NETBSD_EMULTIHOP 94 /* Multihop attempted */ #define NETBSD_ENOLINK 95 /* Link has been severed */ #define NETBSD_EPROTO 96 /* Protocol error */ #define NETBSD_ELAST 96 /* Must equal largest errno */ #ifdef _KERNEL /* pseudo-errors returned inside kernel to modify return to process */ #define NETBSD_EJUSTRETURN -2 /* don't modify regs, just return */ #define NETBSD_ERESTART -3 /* restart syscall */ #define NETBSD_EPASSTHROUGH -4 /* ioctl not handled by this layer */ #define NETBSD_EDUPFD -5 /* Dup given fd */ #define NETBSD_EMOVEFD -6 /* Move given fd */ #endif #endif /* ERRNO_NETBSD_H */ gxemul-0.6.1/src/include/thirdparty/tc_ioasicreg.h000644 001750 001750 00000021665 13402411502 022447 0ustar00debugdebug000000 000000 #ifndef TC_IOASICREG_H #define TC_IOASICREG_H /* $NetBSD: ioasicreg.h,v 1.6 2000/07/17 02:18:17 thorpej Exp $ */ /* * Copyright (c) 1991,1990,1989,1994,1995 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * The Mach Operating System project at Carnegie-Mellon University, * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)asic.h 8.1 (Berkeley) 6/10/93 */ /* * Slot definitions */ #define IOASIC_SLOT_0_START 0x000000 #define IOASIC_SLOT_1_START 0x040000 #define IOASIC_SLOT_2_START 0x080000 #define IOASIC_SLOT_3_START 0x0c0000 #define IOASIC_SLOT_4_START 0x100000 #define IOASIC_SLOT_5_START 0x140000 #define IOASIC_SLOT_6_START 0x180000 #define IOASIC_SLOT_7_START 0x1c0000 #define IOASIC_SLOT_8_START 0x200000 #define IOASIC_SLOT_9_START 0x240000 #define IOASIC_SLOT_10_START 0x280000 #define IOASIC_SLOT_11_START 0x2c0000 #define IOASIC_SLOT_12_START 0x300000 #define IOASIC_SLOT_13_START 0x340000 #define IOASIC_SLOT_14_START 0x380000 #define IOASIC_SLOT_15_START 0x3c0000 #define IOASIC_SLOTS_END 0x3fffff /* * Register offsets (slot 1) */ #define IOASIC_SCSI_DMAPTR IOASIC_SLOT_1_START+0x000 #define IOASIC_SCSI_NEXTPTR IOASIC_SLOT_1_START+0x010 #define IOASIC_LANCE_DMAPTR IOASIC_SLOT_1_START+0x020 #define IOASIC_SCC_T1_DMAPTR IOASIC_SLOT_1_START+0x030 #define IOASIC_SCC_R1_DMAPTR IOASIC_SLOT_1_START+0x040 #define IOASIC_SCC_T2_DMAPTR IOASIC_SLOT_1_START+0x050 #define IOASIC_SCC_R2_DMAPTR IOASIC_SLOT_1_START+0x060 #define IOASIC_FLOPPY_DMAPTR IOASIC_SLOT_1_START+0x070 #define IOASIC_ISDN_X_DMAPTR IOASIC_SLOT_1_START+0x080 #define IOASIC_ISDN_X_NEXTPTR IOASIC_SLOT_1_START+0x090 #define IOASIC_ISDN_R_DMAPTR IOASIC_SLOT_1_START+0x0a0 #define IOASIC_ISDN_R_NEXTPTR IOASIC_SLOT_1_START+0x0b0 #define IOASIC_BUFF0 IOASIC_SLOT_1_START+0x0c0 #define IOASIC_BUFF1 IOASIC_SLOT_1_START+0x0d0 #define IOASIC_BUFF2 IOASIC_SLOT_1_START+0x0e0 #define IOASIC_BUFF3 IOASIC_SLOT_1_START+0x0f0 #define IOASIC_CSR IOASIC_SLOT_1_START+0x100 #define IOASIC_INTR IOASIC_SLOT_1_START+0x110 #define IOASIC_IMSK IOASIC_SLOT_1_START+0x120 #define IOASIC_CURADDR IOASIC_SLOT_1_START+0x130 #define IOASIC_ISDN_X_DATA IOASIC_SLOT_1_START+0x140 #define IOASIC_ISDN_R_DATA IOASIC_SLOT_1_START+0x150 #define IOASIC_LANCE_DECODE IOASIC_SLOT_1_START+0x160 #define IOASIC_SCSI_DECODE IOASIC_SLOT_1_START+0x170 #define IOASIC_SCC0_DECODE IOASIC_SLOT_1_START+0x180 #define IOASIC_SCC1_DECODE IOASIC_SLOT_1_START+0x190 #define IOASIC_FLOPPY_DECODE IOASIC_SLOT_1_START+0x1a0 #define IOASIC_SCSI_SCR IOASIC_SLOT_1_START+0x1b0 #define IOASIC_SCSI_SDR0 IOASIC_SLOT_1_START+0x1c0 #define IOASIC_SCSI_SDR1 IOASIC_SLOT_1_START+0x1d0 #define IOASIC_CTR IOASIC_SLOT_1_START+0x1e0 /*3max+/3000*/ /* System Status and control Register (SSR). */ #define IOASIC_CSR_DMAEN_T1 0x80000000 /* rw */ #define IOASIC_CSR_DMAEN_R1 0x40000000 /* rw */ #define IOASIC_CSR_DMAEN_T2 0x20000000 /* rw */ #define IOASIC_CSR_DMAEN_R2 0x10000000 /* rw */ #define IOASIC_CSR_FASTMODE 0x08000000 /* rw - 3000 */ #define IOASIC_CSR_xxx 0x07800000 /* reserved - 3000 */ #define IOASIC_CSR_DS_xxx 0x0f800000 /* reserved - DS */ #define IOASIC_CSR_FLOPPY_DIR 0x00400000 /* rw - maxine */ #define IOASIC_CSR_DMAEN_FLOPPY 0x00200000 /* rw - maxine */ #define IOASIC_CSR_DMAEN_ISDN_T 0x00100000 /* rw */ #define IOASIC_CSR_DMAEN_ISDN_R 0x00080000 /* rw */ #define IOASIC_CSR_SCSI_DIR 0x00040000 /* rw - DS */ #define IOASIC_CSR_DMAEN_SCSI 0x00020000 /* rw - DS */ #define IOASIC_CSR_DMAEN_LANCE 0x00010000 /* rw - DS */ /* low 16 bits are rw gp outputs */ #define IOASIC_CSR_DIAGDN 0x00008000 /* rw */ #define IOASIC_CSR_TXDIS_2 0x00004000 /* rw - 3min,3max+ */ #define IOASIC_CSR_TXDIS_1 0x00002000 /* rw - 3min,3max+ */ #define IOASIC_CSR_ISDN_ENABLE 0x00001000 /* rw - 3000/maxine */ #define IOASIC_CSR_SCC_ENABLE 0x00000800 /* rw */ #define IOASIC_CSR_RTC_ENABLE 0x00000400 /* rw */ #define IOASIC_CSR_SCSI_ENABLE 0x00000200 /* rw - DS */ #define IOASIC_CSR_LANCE_ENABLE 0x00000100 /* rw */ /* System Interrupt Register (and Interrupt Mask Register). */ #define IOASIC_INTR_T1_PAGE_END 0x80000000 /* rz */ #define IOASIC_INTR_T1_READ_E 0x40000000 /* rz */ #define IOASIC_INTR_R1_HALF_PAGE 0x20000000 /* rz */ #define IOASIC_INTR_R1_DMA_OVRUN 0x10000000 /* rz */ #define IOASIC_INTR_T2_PAGE_END 0x08000000 /* rz */ #define IOASIC_INTR_T2_READ_E 0x04000000 /* rz */ #define IOASIC_INTR_R2_HALF_PAGE 0x02000000 /* rz */ #define IOASIC_INTR_R2_DMA_OVRUN 0x01000000 /* rz */ #define IOASIC_INTR_FLOPPY_DMA_E 0x00800000 /* rz - maxine */ #define IOASIC_INTR_ISDN_TXLOAD 0x00400000 /* rz - 3000/maxine */ #define IOASIC_INTR_ISDN_RXLOAD 0x00200000 /* rz - 3000/maxine */ #define IOASIC_INTR_ISDN_OVRUN 0x00100000 /* rz - 3000/maxine */ #define IOASIC_INTR_SCSI_PTR_LOAD 0x00080000 /* rz - DS */ #define IOASIC_INTR_SCSI_OVRUN 0x00040000 /* rz - DS */ #define IOASIC_INTR_SCSI_READ_E 0x00020000 /* rz - DS */ #define IOASIC_INTR_LANCE_READ_E 0x00010000 /* rz - DS */ /* low 16 bits are model-dependent; see also model specific *.h */ #define IOASIC_INTR_NVR_JUMPER 0x00004000 /* ro */ #define IOASIC_INTR_ISDN 0x00002000 /* ro - 3000 */ #define IOASIC_INTR_NRMOD_JUMPER 0x00000400 /* ro */ #define IOASIC_INTR_SEC_CON 0x00000200 /* ro */ #define IOASIC_INTR_SCSI 0x00000200 /* ro - DS */ #define IOASIC_INTR_LANCE 0x00000100 /* ro */ #define IOASIC_INTR_SCC_1 0x00000080 /* ro */ #define IOASIC_INTR_SCC_0 0x00000040 /* ro */ #define IOASIC_INTR_ALT_CON 0x00000008 /* ro - 3000/500 */ #define IOASIC_INTR_300_OPT1 0x00000008 /* ro - 3000/300 */ #define IOASIC_INTR_300_OPT0 0x00000004 /* ro - 3000/300 */ /* DMA pointer registers (SCSI, Comm, ...) */ #define IOASIC_DMA_ADDR(p) \ ((((p) << 3) & ~0x1f) | (((p) >> 29) & 0x1f)) #define IOASIC_DMA_BLOCKSIZE 0x1000 /* For the LANCE DMA pointer register initialization the above suffices */ /* More SCSI DMA registers */ #define IOASIC_SCR_STATUS 0x00000004 #define IOASIC_SCR_WORD 0x00000003 /* Various Decode registers */ #define IOASIC_DECODE_HW_ADDRESS 0x000003f0 #define IOASIC_DECODE_CHIP_SELECT 0x0000000f /* * And slot assignments. */ #define IOASIC_SYS_ETHER_ADDRESS(base) ((base) + IOASIC_SLOT_2_START) #define IOASIC_SYS_LANCE(base) ((base) + IOASIC_SLOT_3_START) #endif /* TC_IOASICREG_H */ gxemul-0.6.1/src/include/thirdparty/bt459.h000644 001750 001750 00000013512 13402411502 020653 0ustar00debugdebug000000 000000 /* gxemul: $Id: bt459.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ #ifndef BT459_H #define BT459_H /* $NetBSD: bt459.h,v 1.6 2000/01/08 01:02:35 simonb Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)cfbreg.h 8.1 (Berkeley) 6/10/93 */ /* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * HISTORY * Log: bt459.h,v * Revision 2.4 91/02/05 17:39:43 mrt * Added author notices * [91/02/04 11:11:57 mrt] * * Changed to use new Mach copyright * [91/02/02 12:09:39 mrt] * * Revision 2.3 90/12/05 23:30:26 af * Cursor color register are supported, contrary to specs. * [90/12/03 23:07:22 af] * * Revision 2.1.1.1 90/11/01 03:36:40 af * Created, from Brooktree specs: * "Product Databook 1989" * "Bt459 135 MHz Monolithic CMOS 256x64 Color Palette RAMDAC" * Brooktree Corp. San Diego, CA * LA59001 Rev. J * [90/09/03 af] */ /* * File: bt459.h * Author: Alessandro Forin, Carnegie Mellon University * Date: 9/90 * * Defines for the bt459 Cursor/RAMDAC chip */ typedef struct { unsigned char addr_lo; char pad0[3]; unsigned char addr_hi; char pad1[3]; unsigned char addr_reg; char pad2[3]; unsigned char addr_cmap; char pad3[3]; } bt459_regmap_t; /* * Additional registers addressed indirectly */ /* 0000-00ff Color Map entries */ /* 0100-010f Overlay color regs, unsupp */ #define BT459_REG_CCOLOR_1 0x0181 /* Cursor color regs */ #define BT459_REG_CCOLOR_2 0x0182 #define BT459_REG_CCOLOR_3 0x0183 #define BT459_REG_ID 0x0200 /* read-only, gives "4a" */ #define BT459_REG_CMD0 0x0201 #define BT459_REG_CMD1 0x0202 #define BT459_REG_CMD2 0x0203 #define BT459_REG_PRM 0x0204 /* 0205 reserved */ #define BT459_REG_PBM 0x0206 /* 0207 reserved */ #define BT459_REG_ORM 0x0208 #define BT459_REG_OBM 0x0209 #define BT459_REG_ILV 0x020a #define BT459_REG_TEST 0x020b #define BT459_REG_RSIG 0x020c #define BT459_REG_GSIG 0x020d #define BT459_REG_BSIG 0x020e /* 020f-02ff reserved */ #define BT459_REG_CCR 0x0300 #define BT459_REG_CXLO 0x0301 #define BT459_REG_CXHI 0x0302 #define BT459_REG_CYLO 0x0303 #define BT459_REG_CYHI 0x0304 #define BT459_REG_WXLO 0x0305 #define BT459_REG_WXHI 0x0306 #define BT459_REG_WYLO 0x0307 #define BT459_REG_WYHI 0x0308 #define BT459_REG_WWLO 0x0309 #define BT459_REG_WWHI 0x030a #define BT459_REG_WHLO 0x030b #define BT459_REG_WHHI 0x030c /* 030d-03ff reserved */ #define BT459_REG_CRAM_BASE 0x0400 #define BT459_REG_CRAM_END 0x07ff #ifdef _KERNEL int bt459init __P((struct fbinfo *)); void bt459RestoreCursorColor __P((struct fbinfo *)); void bt459CursorColor __P((struct fbinfo *, unsigned int [])); void bt459PosCursor __P((struct fbinfo *, int, int)); void bt459InitColorMap __P((struct fbinfo *)); int bt459LoadColorMap __P((struct fbinfo *, const u_char *, int, int)); int bt459GetColorMap __P((struct fbinfo *, u_char *, int, int)); void bt459LoadCursor __P((struct fbinfo *, u_short *)); int bt459_video_on __P((struct fbinfo *)); int bt459_video_off __P((struct fbinfo *)); #endif /* _KERNEL */ #endif /* BT459_H */ gxemul-0.6.1/src/include/thirdparty/crmfbreg.h000644 001750 001750 00000040676 13402411502 021606 0ustar00debugdebug000000 000000 /* Imported into GXemul 2018-10-08 from NetBSD-current */ /* $NetBSD: crmfbreg.h,v 1.16 2015/01/20 12:13:04 macallan Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill * 2008 Michael Lorenz * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * SGI-CRM (O2) Framebuffer driver, register definitions */ #ifndef CRMFBREG_H #define CRMFBREG_H #define CRMFB_CTRLSTAT 0x00000000 #define CRMFB_CTRLSTAT_CHIPID_MASK 0x0000000f #define CRMFB_CTRLSTAT_SENSE 0x00000010 /* monitor sense pin */ #define CRMFB_CTRLSTAT_GPIO0_SENSE 0x00000040 #define CRMFB_CTRLSTAT_GPIO0_INPUT 0x00000080 #define CRMFB_CTRLSTAT_GPIO1_SENSE 0x00000100 #define CRMFB_CTRLSTAT_GPIO1_INPUT 0x00000200 #define CRMFB_CTRLSTAT_GPIO2_SENSE 0x00000400 #define CRMFB_CTRLSTAT_GPIO2_INPUT 0x00000800 #define CRMFB_CTRLSTAT_GPIO3_SENSE 0x00001000 #define CRMFB_CTRLSTAT_GPIO3_INPUT 0x00002000 #define CRMFB_CTRLSTAT_GPIO4_SENSE 0x00004000 #define CRMFB_CTRLSTAT_GPIO4_INPUT 0x00008000 #define CRMFB_CTRLSTAT_GPIO5_SENSE 0x00010000 #define CRMFB_CTRLSTAT_GPIO5_INPUT 0x00020000 #define CRMFB_CTRLSTAT_GPIO6_SENSE 0x00040000 #define CRMFB_CTRLSTAT_GPIO6_INPUT 0x00080000 #define CRMFB_CTRLSTAT_GPIO7_SENSE 0x00100000 #define CRMFB_CTRLSTAT_GPIO7_INPUT 0x00200000 #define CRMFB_CTRLSTAT_GPIO8_SENSE 0x00400000 #define CRMFB_CTRLSTAT_GPIO8_INPUT 0x00800000 #define CRMFB_CTRLSTAT_GPIO9_SENSE 0x01000000 #define CRMFB_CTRLSTAT_GPIO9_INPUT 0x02000000 #define CRMFB_CTRLSTAT_HALF_PHASE 0x04000000 /* for flat panel */ #define CRMFB_CTRLSTAT_CSYNC_ALOW 0x08000000 /* csync active low */ #define CRMFB_CTRLSTAT_EXTERNAL_PCLK 0x00000000 #define CRMFB_CTRLSTAT_DIFF_PCLK 0x10000000 /* differential pclock */ #define CRMFB_CTRLSTAT_INTERNAL_PCLK 0x30000000 #define CRMFB_DOTCLOCK 0x00000004 #define CRMFB_DOTCLOCK_M_MASK 0x000000ff #define CRMFB_DOTCLOCK_N_MASK 0x00003f00 #define CRMFB_DOTCLOCK_P_MASK 0x0000c000 #define CRMFB_DOTCLOCK_CLKRUN_SHIFT 20 #define CRMFB_DOTCLOCK_BYPASS 0x00100000 /* turn the clock off */ #define CRMFB_DOTCLOCK_OUT_OF_RANGE 0x00400000 #define CRMFB_DOTCLOCK_OUT_OF_LOCK 0x00800000 #define CRMFB_DOTCLOCK_TDWNI 0x01000000 /* ? */ #define CRMFB_DOTCLOCK_TUPI 0x02000000 /* ? */ #define CRMFB_I2C_VGA 0x00000008 #define CRMFB_I2C_SDA 0x00000001 /* these bits are */ #define CRMFB_I2C_SCL 0x00000002 /* low active */ #define CRMFB_SYSCLK 0x0000000c #define CRMFB_I2C_FP 0x00000010 /* same bits as CRMFB_I2C_VGA */ #define CRMFB_DEVICE_ID 0x00000014 #define CRMFB_DEVICE_ID_DEF 0x00000666 /* this chip is EVIL */ #define CRMFB_VT_XY 0x00010000 /* pixel / line counters */ #define CRMFB_VT_XY_X_MASK 0x00000fff #define CRMFB_VT_XY_Y_MASK 0x00fff000 #define CRMFB_VT_XY_FREEZE_SHIFT 31 #define CRMFB_VT_XYMAX 0x00010004 /* same masks as CRMFB_VT_XY, counters in * CRMFB_VT_XY reset when reaching max */ #define CRMFB_VT_VSYNC 0x00010008 #define CRMFB_VT_VSYNC_OFF_MASK 0x00000fff #define CRMFB_VT_VSYNC_ON_MASK 0x00fff000 #define CRMFB_VT_HSYNC 0x0001000c #define CRMFB_VT_HSYNC_OFF_MASK 0x00000fff #define CRMFB_VT_HSYNC_ON_MASK 0x00fff000 #define CRMFB_VT_VBLANK 0x00010010 #define CRMFB_VT_VBLANK_OFF_MASK 0x00000fff #define CRMFB_VT_VBLANK_ON_MASK 0x00fff000 #define CRMFB_VT_HBLANK 0x00010014 #define CRMFB_VT_HBLANK_OFF_MASK 0x00000fff #define CRMFB_VT_HBLANK_ON_MASK 0x00fff000 #define CRMFB_VT_FLAGS 0x00010018 #define CRMFB_VT_FLAGS_VDRV_INVERT 0x00000001 #define CRMFB_VT_FLAGS_VDRV_LOW 0x00000002 #define CRMFB_VT_FLAGS_HDRV_INVERT 0x00000004 #define CRMFB_VT_FLAGS_HDRV_LOW 0x00000008 /* put monitor to sleep */ #define CRMFB_VT_FLAGS_SYNC_HIGH 0x00000010 #define CRMFB_VT_FLAGS_SYNC_LOW 0x00000020 #define CRMFB_VT_FLAGS_SYNC_LOW_MSB 5 #define CRMFB_VT_FLAGS_SYNC_LOW_LSB 5 #define CRMFB_VT_FLAGS_F2RF_HIGH 0x00000040 /* sync left/right ? */ #define CRMFB_VT_FRAMELOCK 0x0001001c #define CRMFB_VT_FRAMELOCK_F2RF_MASK 0x00000fff /* f2rf toggles when y * reaches this */ #define CRMFB_VT_FRAMELOCK_LOCK_MASK 0x00fff000 /* scanline interrupts! */ #define CRMFB_VT_INTR01 0x00010020 #define CRMFB_INTR_1_MASK 0x00000fff /* intr1 when y == this */ #define CRMFB_INTR_0_MASK 0x00fff000 /* intr0 when y == this */ #define CRMFB_VT_INTR23 0x00010024 #define CRMFB_INTR_3_MASK 0x00000fff /* intr3 when y == this */ #define CRMFB_INTR_2_MASK 0x00fff000 /* intr2 when y == this */ #define CRMFB_VT_HPIX_EN 0x00010034 #define CRMFB_HPIXEN_OFF_MASK 0x00000fff #define CRMFB_HPIXEN_ON_MASK 0x00fff000 #define CRMFB_VT_VPIX_EN 0x00010038 #define CRMFB_VT_VPIX_EN_OFF_SHIFT 0 #define CRMFB_VPIXEN_OFF_MASK 0x00000fff #define CRMFB_VPIXEN_ON_MASK 0x00fff000 #define CRMFB_VT_HCMAP 0x0001003c #define CRMFB_HCMAP_OFF_MASK 0x00000fff #define CRMFB_HCMAP_ON_MASK 0x00fff000 #define CRMFB_VT_HCMAP_ON_SHIFT 12 #define CRMFB_VT_VCMAP 0x00010040 #define CRMFB_VCMAP_OFF_MASK 0x00000fff #define CRMFB_VCMAP_ON_MASK 0x00fff000 #define CRMFB_VT_VCMAP_ON_SHIFT 12 #define CRMFB_VT_DID_STARTXY 0x00010044 #define CRMFB_VT_DID_START_X_MASK 0x00000fff #define CRMFB_VT_DID_START_Y_MASK 0x00fff000 #define CRMFB_VT_CRS_STARTXY 0x00010048 #define CRMFB_VT_CRS_START_X_MASK 0x00000fff #define CRMFB_VT_CRS_START_Y_MASK 0x00fff000 #define CRMFB_VT_VC_STARTXY 0x0001004c #define CRMFB_VT_VC_START_X_MASK 0x00000fff #define CRMFB_VT_VC_START_Y_MASK 0x00fff000 #define CRMFB_OVR_WIDTH_TILE 0x00020000 #define CRMFB_OVR_WIDTH_TILE_RHS_MASK 0x0000001f /* width of rightmost tile * in 32 byte units */ #define CRMFB_OVR_WIDTH_TILES_MASK 0x00001fe0 /* width in whole tiles */ #define CRMFB_OVR_TILE_PTR 0x00020004 #define CRMFB_OVR_TILE_LIST_MASK 0xfffff000 #define CRMFB_OVR_DMA_ENABLE 0x00000001 #define CRMFB_OVR_CONTROL 0x00020008 /* same bits as CRMFB_OVR_TILE_PTR, copied * from here when blanking */ #define CRMFB_OVR_CONTROL_DMAEN_SHIFT 0 #define CRMFB_FRM_TILESIZE 0x00030000 #define CRMFB_FRM_TILESIZE_RHS_SHIFT 0 /* width of a partial tile * on the right in 32 BYTES */ #define CRMFB_FRM_TILESIZE_WIDTH_SHIFT 5 /* width in tiles */ #define CRMFB_FRM_TILESIZE_DEPTH_SHIFT 13 #define CRMFB_FRM_TILESIZE_DEPTH_8 0 #define CRMFB_FRM_TILESIZE_DEPTH_16 1 #define CRMFB_FRM_TILESIZE_DEPTH_32 2 #define CRMFB_FRM_TILESIZE_FIFOR_SHIFT 15 #define CRMFB_FRM_PIXSIZE 0x00030004 #define CRMFB_FRM_PIXSIZE_HEIGHT_SHIFT 16 #define CRMFB_TILE_PTR 0x00020008 #define CRMFB_TILE_LIST_MASK 0xfffff000 #define CRMFB_DMA_ENABLE 0x00000001 #define CRMFB_FRM_CONTROL 0x0003000c #define CRMFB_FRM_CONTROL_DMAEN_SHIFT 0 #define CRMFB_FRM_CONTROL_LINEAR_SHIFT 1 #define CRMFB_FRM_CONTROL_TILEPTR_SHIFT 9 #define CRMFB_DID_PTR 0x00040000 #define CRMFB_DID_BASE_MASK 0x0000ffff #define CRMFB_DID_DMA_ENABLE 0x00010000 #define CRMFB_DID_CONTROL 0x00040004 #define CRMFB_DID_CONTROL_DMAEN_SHIFT 0 #define CRMFB_WID 0x00048000 /* 32 WIDs */ #define CRMFB_MODE 0x00048000 #define CRMFB_MODE_TYP_SHIFT 2 #define CRMFB_MODE_TYP_I8 0 #define CRMFB_MODE_TYP_I12 1 #define CRMFB_MODE_TYP_RG3B2 2 #define CRMFB_MODE_TYP_RGB4 3 #define CRMFB_MODE_TYP_ARGB5 4 #define CRMFB_MODE_TYP_RGB8 5 #define CRMFB_MODE_BUF_SHIFT 0 #define CRMFB_MODE_BUF_BOTH 3 #define CRMFB_MODE_CMAP_SELECT_SHIFT 5 /* upper 5 bit */ #define CRMFB_MODE_GAMMA_ENABLE_SHIFT 10 #define CRMFB_MODE_FP_ENABLE_SHIFT 11 /* two bits */ #define CRMFB_CMAP 0x00050000 /* 32*256 entries */ #define CRMFB_CMAP_OVL 0x00051400 #define CRMFB_CMAP_FIFO 0x00058000 #define CRMFB_GMAP 0x00060000 /* gamma map */ #define CRMFB_CURSOR_POS 0x00070000 /* * upper 16 bit are Y, lower 16 bit are X - both signed so there's no need for * a hotspot register */ #define CRMFB_CURSOR_CONTROL 0x00070004 #define CRMFB_CURSOR_ON 0x00000001 #define CRMFB_CURSOR_CROSSHAIR 0x00000002 #define CRMFB_CURSOR_CMAP0 0x00070008 #define CRMFB_CURSOR_CMAP1 0x0007000c #define CRMFB_CURSOR_CMAP2 0x00070010 #define CRMFB_CURSOR_BITMAP 0x00078000 /* two bit deep cursor image, zero is transparent */ /* rendering engine registers */ /* these TLBs define 16x16 tiles, 64kB each, upper 16 bit only */ #define CRIME_RE_TLB_A 0x1000 #define CRIME_RE_TLB_B 0x1200 #define CRIME_RE_TLB_C 0x1400 #define CRIME_RE_TEX 0x1600 #define CRIME_RE_CLIP_IDS 0x16e0 /* 32bit entries, 4kB page address >> 12 | 0x80000000 */ #define CRIME_RE_LINEAR_A 0x1700 #define CRIME_RE_LINEAR_B 0x1780 /* memory transfer engine from 0x3000*/ #define CRIME_MTE_MODE 0x3000 #define CRIME_MTE_BYTEMASK 0x3008 #define CRIME_MTE_STIPPLEMASK 0x3010 #define CRIME_MTE_BG 0x3018 #define CRIME_MTE_SRC0 0x3020 /* start */ #define CRIME_MTE_SRC1 0x3028 /* end */ #define CRIME_MTE_DST0 0x3030 /* start */ #define CRIME_MTE_DST1 0x3038 /* end */ #define CRIME_MTE_SRC_Y_STEP 0x3040 #define CRIME_MTE_DST_Y_STEP 0x3048 #define CRIME_MTE_NULL 0x3070 #define CRIME_MTE_FLUSH 0x3078 /* CRIME_MTE_MODE */ #define MTE_MODE_DST_ECC 0x00000001 /* enable ECC in DST */ #define MTE_MODE_SRC_ECC 0x00000002 /* enable ECC in SRC */ #define MTE_MODE_DST_BUF_MASK 0x0000001c #define MTE_TLB_A 0 #define MTE_TLB_B 1 #define MTE_TLB_C 2 #define MTE_TLB_TEX 3 #define MTE_TLB_LIN_A 4 #define MTE_TLB_LIN_B 5 #define MTE_TLB_CLIP 6 #define MTE_DST_TLB_SHIFT 2 #define MTE_MODE_SRC_BUF_MASK 0x000000e0 #define MTE_SRC_TLB_SHIFT 5 #define MTE_MODE_DEPTH_MASK 0x00000300 #define MTE_DEPTH_8 0 #define MTE_DEPTH_16 1 #define MTE_DEPTH_32 2 #define MTE_DEPTH_SHIFT 8 #define MTE_MODE_STIPPLE 0x00000400 #define MTE_MODE_COPY 0x00000800 /* 1 - copy, 0 - clear dst */ /* drawing engine from 0x2000 */ #define CRIME_DE_MODE_SRC 0x2000 #define CRIME_DE_MODE_DST 0x2008 #define CRIME_DE_CLIPMODE 0x2010 #define CRIME_DE_DRAWMODE 0x2018 #define CRIME_DE_SCRMASK0 0x2020 #define CRIME_DE_SCRMASK1 0x2028 #define CRIME_DE_SCRMASK2 0x2030 #define CRIME_DE_SCRMASK3 0x2038 #define CRIME_DE_SCRMASK4 0x2040 #define CRIME_DE_SCISSOR 0x2048 #define CRIME_DE_WINOFFSET_SRC 0x2050 /* x in upper, y in lower 16 bit */ #define CRIME_DE_WINOFFSET_DST 0x2058 #define CRIME_DE_PRIMITIVE 0x2060 #define CRIME_DE_X_VERTEX_0 0x2070 #define CRIME_DE_X_VERTEX_1 0x2074 #define CRIME_DE_X_VERTEX_2 0x2078 #define CRIME_DE_GL_VERTEX_0_X 0x2080 #define CRIME_DE_GL_VERTEX_0_Y 0x2084 #define CRIME_DE_GL_VERTEX_1_X 0x2088 #define CRIME_DE_GL_VERTEX_1_Y 0x208c #define CRIME_DE_GL_VERTEX_2_X 0x2090 #define CRIME_DE_GL_VERTEX_2_Y 0x2094 #define CRIME_DE_XFER_ADDR_SRC 0x20a0 #define CRIME_DE_XFER_STRD_SRC 0x20a4 #define CRIME_DE_XFER_STEP_X 0x20a8 #define CRIME_DE_XFER_STEP_Y 0x20ac #define CRIME_DE_XFER_ADDR_DST 0x20b0 #define CRIME_DE_XFER_STRD_DST 0x20b4 #define CRIME_DE_STIPPLE_MODE 0x20c0 #define CRIME_DE_STIPPLE_PAT 0x20c4 #define CRIME_DE_FG 0x20d0 #define CRIME_DE_BG 0x20d8 #define CRIME_DE_ALPHA_COLOR 0x21a0 /* constant colour for alpha */ #define CRIME_DE_ALPHA_FUNC 0x21a8 /* blend function */ #define CRIME_DE_ROP 0x21b0 #define CRIME_DE_PLANEMASK 0x21b8 #define CRIME_DE_NULL 0x21f0 #define CRIME_DE_FLUSH 0x21f8 #define CRIME_DE_START 0x0800 /* OR this to a register address in * order to start a command */ /* CRIME_DE_MODE_* */ #define DE_MODE_TLB_A 0x00000000 #define DE_MODE_TLB_B 0x00000400 #define DE_MODE_TLB_C 0x00000800 #define DE_MODE_LIN_A 0x00001000 #define DE_MODE_LIN_B 0x00001400 #define DE_MODE_BUFDEPTH_8 0x00000000 #define DE_MODE_BUFDEPTH_16 0x00000100 #define DE_MODE_BUFDEPTH_32 0x00000200 #define DE_MODE_TYPE_CI 0x00000000 #define DE_MODE_TYPE_RGB 0x00000010 #define DE_MODE_TYPE_RGBA 0x00000020 #define DE_MODE_TYPE_ABGR 0x00000030 #define DE_MODE_TYPE_YCRCB 0x000000f0 #define DE_MODE_TYPE_MASK 0x000000f0 #define DE_MODE_PIXDEPTH_8 0x00000000 #define DE_MODE_PIXDEPTH_16 0x00000004 #define DE_MODE_PIXDEPTH_32 0x00000008 #define DE_MODE_DOUBLE_PIX 0x00000002 #define DE_MODE_DOUBLE_SELECT 0x00000001 /* clip mode */ #define DE_CLIPMODE_ENABLE 0x00000800 /* enable testing against mask register n */ #define DE_CLIPMODE_MASK0_EN 0x00000200 #define DE_CLIPMODE_MASK1_EN 0x00000100 #define DE_CLIPMODE_MASK2_EN 0x00000080 #define DE_CLIPMODE_MASK3_EN 0x00000040 #define DE_CLIPMODE_MASK4_EN 0x00000020 /* let pixels pass if inside mask n, otherwise outside */ #define DE_CLIPMODE_MASK0_IN 0x00000010 #define DE_CLIPMODE_MASK1_IN 0x00000008 #define DE_CLIPMODE_MASK2_IN 0x00000004 #define DE_CLIPMODE_MASK3_IN 0x00000002 #define DE_CLIPMODE_MASK4_IN 0x00000001 /* draw mode */ #define DE_DRAWMODE_NO_CONF 0x00800000 /* disable coherency testing */ #define DE_DRAWMODE_X11 0x00000000 #define DE_DRAWMODE_GL 0x00400000 #define DE_DRAWMODE_XFER_EN 0x00200000 #define DE_DRAWMODE_SCISSOR_EN 0x00100000 #define DE_DRAWMODE_LINE_STIP 0x00080000 #define DE_DRAWMODE_POLY_STIP 0x00040000 #define DE_DRAWMODE_OPAQUE_STIP 0x00020000 #define DE_DRAWMODE_SHADE 0x00010000 /* smooth shading enable */ #define DE_DRAWMODE_TEXTURE 0x00008000 #define DE_DRAWMODE_FOG 0x00004000 #define DE_DRAWMODE_COVERAGE 0x00002000 #define DE_DRAWMODE_LINE_AA 0x00001000 #define DE_DRAWMODE_ALPHA_TEST 0x00000800 #define DE_DRAWMODE_ALPHA_BLEND 0x00000400 #define DE_DRAWMODE_ROP 0x00000200 #define DE_DRAWMODE_DITHER 0x00000100 #define DE_DRAWMODE_PLANEMASK 0x00000080 #define DE_DRAWMODE_BYTEMASK 0x00000078 #define DE_DRAWMODE_DEPTH_TEST 0x00000004 #define DE_DRAWMODE_DEPTH_MASK 0x00000002 #define DE_DRAWMODE_STENCIL 0x00000001 /* primitive */ #define DE_PRIM_POINT 0x00000000 #define DE_PRIM_LINE 0x01000000 #define DE_PRIM_TRIANGLE 0x02000000 #define DE_PRIM_RECTANGLE 0x03000000 #define DE_PRIM_LINE_SKIP_END 0x00040000 #define DE_PRIM_LR 0x00000000 /* left to right */ #define DE_PRIM_RL 0x00010000 /* right to left */ #define DE_PRIM_BT 0x00000000 /* bottom to top */ #define DE_PRIM_TB 0x00020000 /* top to bottom */ #define DE_PRIM_LINE_WIDTH_MASK 0x0000ffff /* in half pixels */ /* CRIME_DE_STIPPLE_MODE */ #define DE_STIP_MAXREP_SHIFT 0 /* max. repeats 8 bit */ #define DE_STIP_REPCNT_SHIFT 8 /* repeat count, 8 bit */ #define DE_STIP_MAXIDX_SHIFT 16 /* max. index, 5 bit */ #define DE_STIP_STRTIDX_SHIFT 24 /* start index, 5 bit */ /* alpha function register */ #define DE_ALPHA_ADD 0x00000000 #define DE_ALPHA_MIN 0x00000100 #define DE_ALPHA_MAX 0x00000200 #define DE_ALPHA_SUB 0x00000300 #define DE_ALPHA_REV_SUB 0x00000400 #define DE_ALPHA_OP_ZERO 0 #define DE_ALPHA_OP_ONE 1 #define DE_ALPHA_OP_DST_COLOR 2 #define DE_ALPHA_OP_1_MINUS_DST_COLOR 3 #define DE_ALPHA_OP_SRC_ALPHA 4 #define DE_ALPHA_OP_1_MINUS_SRC_ALPHA 5 #define DE_ALPHA_OP_DST_ALPHA 6 #define DE_ALPHA_OP_1_MINUS_DST_APLHA 7 #define DE_ALPHA_OP_CONSTANT_COLOR 8 #define DE_ALPHA_OP_1_MINUS_CONST_COLOR 9 #define DE_ALPHA_OP_CONSTANT_ALPHA 10 #define DE_ALPHA_OP_1_MINUS_CONST_ALPHA 11 #define DE_ALPHA_OP_SRC_ALPHA_SATURATE 12 #define DE_ALPHA_OP_SRC_SHIFT 4 #define DE_ALPHA_OP_DST_SHIFT 0 /* status register */ #define CRIME_DE_STATUS 0x4000 #define CRIME_DE_IDLE 0x10000000 #define CRIME_DE_SETUP_IDLE 0x08000000 #define CRIME_DE_PIXPIPE_IDLE 0x04000000 #define CRIME_DE_MTE_IDLE 0x02000000 #define CRIME_DE_LEVEL_MASK 0x01fc0000 #define CRIME_DE_RD_PTR_MASK 0x0003f000 #define CRIME_DE_WR_PTR_MASK 0x00000fc0 #define CRIME_DE_BUF_START 0x0000003f #define CRIME_DE_LEVEL_SHIFT 18 /* * XXX * The manual claims that the pipeline is 128 deep, in reality it seems to be * 64, at least on my O2. Might be 128 deep on O2+ */ #define CRIME_DE_LEVEL_MAX 0x3f #define CRIME_PIPE_LEVEL(x) ((x & CRIME_DE_LEVEL_MASK) >> \ CRIME_DE_LEVEL_SHIFT) #endif /* CRMFBREG_H */ gxemul-0.6.1/src/include/thirdparty/armreg.h000644 001750 001750 00000133360 13402411502 021265 0ustar00debugdebug000000 000000 /* $NetBSD: armreg.h,v 1.124 2018/08/15 06:13:56 skrll Exp $ */ /* * Copyright (c) 1998, 2001 Ben Harris * Copyright (c) 1994-1996 Mark Brinicombe. * Copyright (c) 1994 Brini. * All rights reserved. * * This code is derived from software written for Brini by Mark Brinicombe * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Brini. * 4. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _ARM_ARMREG_H #define _ARM_ARMREG_H // #include #include "thirdparty/arm_cputypes.h" // #ifdef __arm__ /* * ARM Process Status Register * * The picture in the ARM manuals looks like this: * 3 3 2 2 2 2 * 1 0 9 8 7 6 8 7 6 5 4 0 * +-+-+-+-+-+-------------------------------------+-+-+-+---------+ * |N|Z|C|V|Q| reserved |I|F|T|M M M M M| * | | | | | | | | | |4 3 2 1 0| * +-+-+-+-+-+-------------------------------------+-+-+-+---------+ */ #define PSR_FLAGS 0xf0000000 /* flags */ #define PSR_N_bit (1 << 31) /* negative */ #define PSR_Z_bit (1 << 30) /* zero */ #define PSR_C_bit (1 << 29) /* carry */ #define PSR_V_bit (1 << 28) /* overflow */ #define PSR_Q_bit (1 << 27) /* saturation */ #define PSR_IT1_bit (1 << 26) #define PSR_IT0_bit (1 << 25) #define PSR_J_bit (1 << 24) /* Jazelle mode */ #define PSR_GE_bits (15 << 16) /* SIMD GE bits */ #define PSR_IT7_bit (1 << 15) #define PSR_IT6_bit (1 << 14) #define PSR_IT5_bit (1 << 13) #define PSR_IT4_bit (1 << 12) #define PSR_IT3_bit (1 << 11) #define PSR_IT2_bit (1 << 10) #define PSR_E_BIT (1 << 9) /* Endian state */ #define PSR_A_BIT (1 << 8) /* Async abort disable */ #define I32_bit (1 << 7) /* IRQ disable */ #define F32_bit (1 << 6) /* FIQ disable */ #define IF32_bits (3 << 6) /* IRQ/FIQ disable */ #define PSR_T_bit (1 << 5) /* Thumb state */ #define PSR_MODE 0x0000001f /* mode mask */ #define PSR_USR32_MODE 0x00000010 #define PSR_FIQ32_MODE 0x00000011 #define PSR_IRQ32_MODE 0x00000012 #define PSR_SVC32_MODE 0x00000013 #define PSR_MON32_MODE 0x00000016 #define PSR_ABT32_MODE 0x00000017 #define PSR_HYP32_MODE 0x0000001a #define PSR_UND32_MODE 0x0000001b #define PSR_SYS32_MODE 0x0000001f #define PSR_32_MODE 0x00000010 #define R15_FLAGS 0xf0000000 #define R15_FLAG_N 0x80000000 #define R15_FLAG_Z 0x40000000 #define R15_FLAG_C 0x20000000 #define R15_FLAG_V 0x10000000 /* * Co-processor 15: The system control co-processor. */ #define ARM_CP15_CPU_ID 0 /* CPUID registers */ #define ARM_ISA3_SYNCHPRIM_MASK 0x0000f000 #define ARM_ISA4_SYNCHPRIM_MASK 0x00f00000 #define ARM_ISA3_SYNCHPRIM_LDREX 0x10 // LDREX #define ARM_ISA3_SYNCHPRIM_LDREXPLUS 0x13 // +CLREX/LDREXB/LDREXH #define ARM_ISA3_SYNCHPRIM_LDREXD 0x20 // +LDREXD #define ARM_PFR0_THUMBEE_MASK 0x0000f000 #define ARM_PFR1_GTIMER_MASK 0x000f0000 #define ARM_PFR1_VIRT_MASK 0x0000f000 #define ARM_PFR1_SEC_MASK 0x000000f0 /* Media and VFP Feature registers */ #define ARM_MVFR0_ROUNDING_MASK 0xf0000000 #define ARM_MVFR0_SHORTVEC_MASK 0x0f000000 #define ARM_MVFR0_SQRT_MASK 0x00f00000 #define ARM_MVFR0_DIVIDE_MASK 0x000f0000 #define ARM_MVFR0_EXCEPT_MASK 0x0000f000 #define ARM_MVFR0_DFLOAT_MASK 0x00000f00 #define ARM_MVFR0_SFLOAT_MASK 0x000000f0 #define ARM_MVFR0_ASIMD_MASK 0x0000000f #define ARM_MVFR1_ASIMD_FMACS_MASK 0xf0000000 #define ARM_MVFR1_VFP_HPFP_MASK 0x0f000000 #define ARM_MVFR1_ASIMD_HPFP_MASK 0x00f00000 #define ARM_MVFR1_ASIMD_SPFP_MASK 0x000f0000 #define ARM_MVFR1_ASIMD_INT_MASK 0x0000f000 #define ARM_MVFR1_ASIMD_LDST_MASK 0x00000f00 #define ARM_MVFR1_D_NAN_MASK 0x000000f0 #define ARM_MVFR1_FTZ_MASK 0x0000000f /* ARM3-specific coprocessor 15 registers */ #define ARM3_CP15_FLUSH 1 #define ARM3_CP15_CONTROL 2 #define ARM3_CP15_CACHEABLE 3 #define ARM3_CP15_UPDATEABLE 4 #define ARM3_CP15_DISRUPTIVE 5 /* ARM3 Control register bits */ #define ARM3_CTL_CACHE_ON 0x00000001 #define ARM3_CTL_SHARED 0x00000002 #define ARM3_CTL_MONITOR 0x00000004 /* * Post-ARM3 CP15 registers: * * 1 Control register * * 2 Translation Table Base * * 3 Domain Access Control * * 4 Reserved * * 5 Fault Status * * 6 Fault Address * * 7 Cache/write-buffer Control * * 8 TLB Control * * 9 Cache Lockdown * * 10 TLB Lockdown * * 11 Reserved * * 12 Reserved * * 13 Process ID (for FCSE) * * 14 Reserved * * 15 Implementation Dependent */ /* Some of the definitions below need cleaning up for V3/V4 architectures */ /* CPU control register (CP15 register 1) */ #define CPU_CONTROL_MMU_ENABLE 0x00000001 /* M: MMU/Protection unit enable */ #define CPU_CONTROL_AFLT_ENABLE 0x00000002 /* A: Alignment fault enable */ #define CPU_CONTROL_DC_ENABLE 0x00000004 /* C: IDC/DC enable */ #define CPU_CONTROL_WBUF_ENABLE 0x00000008 /* W: Write buffer enable */ #define CPU_CONTROL_32BP_ENABLE 0x00000010 /* P: 32-bit exception handlers */ #define CPU_CONTROL_32BD_ENABLE 0x00000020 /* D: 32-bit addressing */ #define CPU_CONTROL_LABT_ENABLE 0x00000040 /* L: Late abort enable */ #define CPU_CONTROL_BEND_ENABLE 0x00000080 /* B: Big-endian mode */ #define CPU_CONTROL_SYST_ENABLE 0x00000100 /* S: System protection bit */ #define CPU_CONTROL_ROM_ENABLE 0x00000200 /* R: ROM protection bit */ #define CPU_CONTROL_CPCLK 0x00000400 /* F: Implementation defined */ #define CPU_CONTROL_SWP_ENABLE 0x00000400 /* SW: SWP{B} perform normally. */ #define CPU_CONTROL_BPRD_ENABLE 0x00000800 /* Z: Branch prediction enable */ #define CPU_CONTROL_IC_ENABLE 0x00001000 /* I: IC enable */ #define CPU_CONTROL_VECRELOC 0x00002000 /* V: Vector relocation */ #define CPU_CONTROL_ROUNDROBIN 0x00004000 /* RR: Predictable replacement */ #define CPU_CONTROL_V4COMPAT 0x00008000 /* L4: ARMv4 compat LDR R15 etc */ #define CPU_CONTROL_HA_ENABLE 0x00020000 /* HA: Hardware Access flag enable */ #define CPU_CONTROL_WXN_ENABLE 0x00080000 /* WXN: Write Execute Never */ #define CPU_CONTROL_UWXN_ENABLE 0x00100000 /* UWXN: User Write eXecute Never */ #define CPU_CONTROL_FI_ENABLE 0x00200000 /* FI: Low interrupt latency */ #define CPU_CONTROL_UNAL_ENABLE 0x00400000 /* U: unaligned data access */ #define CPU_CONTROL_XP_ENABLE 0x00800000 /* XP: extended page table */ #define CPU_CONTROL_V_ENABLE 0x01000000 /* VE: Interrupt vectors enable */ #define CPU_CONTROL_EX_BEND 0x02000000 /* EE: exception endianness */ #define CPU_CONTROL_NMFI 0x08000000 /* NMFI: Non maskable FIQ */ #define CPU_CONTROL_TR_ENABLE 0x10000000 /* TRE: */ #define CPU_CONTROL_AF_ENABLE 0x20000000 /* AFE: Access flag enable */ #define CPU_CONTROL_TE_ENABLE 0x40000000 /* TE: Thumb Exception enable */ #define CPU_CONTROL_IDC_ENABLE CPU_CONTROL_DC_ENABLE /* ARMv6/ARMv7 Co-Processor Access Control Register (CP15, 0, c1, c0, 2) */ #define CPACR_V7_ASEDIS 0x80000000 /* Disable Advanced SIMD Ext. */ #define CPACR_V7_D32DIS 0x40000000 /* Disable VFP regs 15-31 */ #define CPACR_CPn(n) (3 << (2*n)) #define CPACR_NOACCESS 0 /* reset value */ #define CPACR_PRIVED 1 /* Privileged mode access */ #define CPACR_RESERVED 2 #define CPACR_ALL 3 /* Privileged and User mode access */ /* ARMv6/ARMv7 Non-Secure Access Control Register (CP15, 0, c1, c1, 2) */ #define NSACR_SMP 0x00040000 /* ACTRL.SMP is writeable (!A8) */ #define NSACR_L2ERR 0x00020000 /* L2ECTRL is writeable (!A8) */ #define NSACR_ASEDIS 0x00008000 /* Deny Advanced SIMD Ext. */ #define NSACR_D32DIS 0x00004000 /* Deny VFP regs 15-31 */ #define NSACR_CPn(n) (1 << (n)) /* NonSecure access allowed */ /* ARM11x6 Auxiliary Control Register (CP15 register 1, opcode2 1) */ #define ARM11X6_AUXCTL_RS 0x00000001 /* return stack */ #define ARM11X6_AUXCTL_DB 0x00000002 /* dynamic branch prediction */ #define ARM11X6_AUXCTL_SB 0x00000004 /* static branch prediction */ #define ARM11X6_AUXCTL_TR 0x00000008 /* MicroTLB replacement strat. */ #define ARM11X6_AUXCTL_EX 0x00000010 /* exclusive L1/L2 cache */ #define ARM11X6_AUXCTL_RA 0x00000020 /* clean entire cache disable */ #define ARM11X6_AUXCTL_RV 0x00000040 /* block transfer cache disable */ #define ARM11X6_AUXCTL_CZ 0x00000080 /* restrict cache size */ /* ARM1136 Auxiliary Control Register (CP15 register 1, opcode2 1) */ #define ARM1136_AUXCTL_PFI 0x80000000 /* PFI: partial FI mode. */ /* This is an undocumented flag * used to work around a cache bug * in r0 steppings. See errata * 364296. */ /* ARM1176 Auxiliary Control Register (CP15 register 1, opcode2 1) */ #define ARM1176_AUXCTL_PHD 0x10000000 /* inst. prefetch halting disable */ #define ARM1176_AUXCTL_BFD 0x20000000 /* branch folding disable */ #define ARM1176_AUXCTL_FSD 0x40000000 /* force speculative ops disable */ #define ARM1176_AUXCTL_FIO 0x80000000 /* low intr latency override */ /* XScale Auxiliary Control Register (CP15 register 1, opcode2 1) */ #define XSCALE_AUXCTL_K 0x00000001 /* dis. write buffer coalescing */ #define XSCALE_AUXCTL_P 0x00000002 /* ECC protect page table access */ #define XSCALE_AUXCTL_MD_WB_RA 0x00000000 /* mini-D$ wb, read-allocate */ #define XSCALE_AUXCTL_MD_WB_RWA 0x00000010 /* mini-D$ wb, read/write-allocate */ #define XSCALE_AUXCTL_MD_WT 0x00000020 /* mini-D$ wt, read-allocate */ #define XSCALE_AUXCTL_MD_MASK 0x00000030 /* ARM11 MPCore Auxiliary Control Register (CP15 register 1, opcode2 1) */ #define MPCORE_AUXCTL_RS 0x00000001 /* return stack */ #define MPCORE_AUXCTL_DB 0x00000002 /* dynamic branch prediction */ #define MPCORE_AUXCTL_SB 0x00000004 /* static branch prediction */ #define MPCORE_AUXCTL_F 0x00000008 /* instruction folding enable */ #define MPCORE_AUXCTL_EX 0x00000010 /* exclusive L1/L2 cache */ #define MPCORE_AUXCTL_SA 0x00000020 /* SMP/AMP */ /* Marvell PJ4B Auxillary Control Register (CP15.0.R1.c0.1) */ #define PJ4B_AUXCTL_FW __BIT(0) /* Cache and TLB updates broadcast */ #define PJ4B_AUXCTL_SMPNAMP __BIT(6) /* 0 = AMP, 1 = SMP */ #define PJ4B_AUXCTL_L1PARITY __BIT(9) /* L1 parity checking */ /* Marvell PJ4B Auxialiary Function Modes Control 0 (CP15.1.R15.c2.0) */ #define PJ4B_AUXFMC0_L2EN __BIT(0) /* Tightly-Coupled L2 cache enable */ #define PJ4B_AUXFMC0_SMPNAMP __BIT(1) /* 0 = AMP, 1 = SMP */ #define PJ4B_AUXFMC0_L1PARITY __BIT(2) /* alias of PJ4B_AUXCTL_L1PARITY */ #define PJ4B_AUXFMC0_DCSLFD __BIT(2) /* Disable DC Speculative linefill */ #define PJ4B_AUXFMC0_FW __BIT(8) /* alias of PJ4B_AUXCTL_FW*/ /* Cortex-A5 Auxiliary Control Register (CP15 register 1, opcode 1) */ #define CORTEXA5_ACTLR_FW __BIT(0) #define CORTEXA5_ACTLR_SMP __BIT(6) /* Inner Cache Shared is cacheable */ #define CORTEXA5_ACTLR_EXCL __BIT(7) /* Exclusive L1/L2 cache control */ /* Cortex-A7 Auxiliary Control Register (CP15 register 1, opcode 1) */ #define CORTEXA7_ACTLR_L1ALIAS __BIT(0) /* Enables L1 cache alias checks */ #define CORTEXA7_ACTLR_L2EN __BIT(1) /* Enables L2 cache */ #define CORTEXA7_ACTLR_SMP __BIT(6) /* SMP */ /* Cortex-A8 Auxiliary Control Register (CP15 register 1, opcode 1) */ #define CORTEXA8_ACTLR_L1ALIAS __BIT(0) /* Enables L1 cache alias checks */ #define CORTEXA8_ACTLR_L2EN __BIT(1) /* Enables L2 cache */ /* Cortex-A9 Auxiliary Control Register (CP15 register 1, opcode 1) */ #define CORTEXA9_AUXCTL_FW 0x00000001 /* Cache and TLB updates broadcast */ #define CORTEXA9_AUXCTL_L2PE 0x00000002 /* Prefetch hint enable */ #define CORTEXA9_AUXCTL_L1PE 0x00000004 /* Data prefetch hint enable */ #define CORTEXA9_AUXCTL_WR_ZERO 0x00000008 /* Ena. write full line of 0s mode */ #define CORTEXA9_AUXCTL_SMP 0x00000040 /* Coherency is active */ #define CORTEXA9_AUXCTL_EXCL 0x00000080 /* Exclusive cache bit */ #define CORTEXA9_AUXCTL_ONEWAY 0x00000100 /* Allocate in on cache way only */ #define CORTEXA9_AUXCTL_PARITY 0x00000200 /* Support parity checking */ /* Cortex-A15 Auxiliary Control Register (CP15 register 1, opcode 1) */ #define CORTEXA15_ACTLR_BTB __BIT(0) /* Cache and TLB updates broadcast */ #define CORTEXA15_ACTLR_SMP __BIT(6) /* SMP */ #define CORTEXA15_ACTLR_IOBEU __BIT(15) /* In order issue in Branch Exec Unit */ #define CORTEXA15_ACTLR_SDEH __BIT(31) /* snoop-delayed exclusive handling */ /* Marvell Feroceon Extra Features Register (CP15 register 1, opcode2 0) */ #define FC_DCACHE_REPL_LOCK 0x80000000 /* Replace DCache Lock */ #define FC_DCACHE_STREAM_EN 0x20000000 /* DCache Streaming Switch */ #define FC_WR_ALLOC_EN 0x10000000 /* Enable Write Allocate */ #define FC_L2_PREF_DIS 0x01000000 /* L2 Cache Prefetch Disable */ #define FC_L2_INV_EVICT_LINE 0x00800000 /* L2 Invalidates Uncorrectable Error Line Eviction */ #define FC_L2CACHE_EN 0x00400000 /* L2 enable */ #define FC_ICACHE_REPL_LOCK 0x00080000 /* Replace ICache Lock */ #define FC_GLOB_HIST_REG_EN 0x00040000 /* Branch Global History Register Enable */ #define FC_BRANCH_TARG_BUF_DIS 0x00020000 /* Branch Target Buffer Disable */ #define FC_L1_PAR_ERR_EN 0x00010000 /* L1 Parity Error Enable */ /* Cache type register definitions 0 */ #define CPU_CT_FORMAT(x) (((x) >> 29) & 0x7) /* reg format */ #define CPU_CT_ISIZE(x) ((x) & 0xfff) /* I$ info */ #define CPU_CT_DSIZE(x) (((x) >> 12) & 0xfff) /* D$ info */ #define CPU_CT_S (1U << 24) /* split cache */ #define CPU_CT_CTYPE(x) (((x) >> 25) & 0xf) /* cache type */ #define CPU_CT_CTYPE_WT 0 /* write-through */ #define CPU_CT_CTYPE_WB1 1 /* write-back, clean w/ read */ #define CPU_CT_CTYPE_WB2 2 /* w/b, clean w/ cp15,7 */ #define CPU_CT_CTYPE_WB6 6 /* w/b, cp15,7, lockdown fmt A */ #define CPU_CT_CTYPE_WB7 7 /* w/b, cp15,7, lockdown fmt B */ #define CPU_CT_CTYPE_WB14 14 /* w/b, cp15,7, lockdown fmt C */ #define CPU_CT_xSIZE_LEN(x) ((x) & 0x3) /* line size */ #define CPU_CT_xSIZE_M (1U << 2) /* multiplier */ #define CPU_CT_xSIZE_ASSOC(x) (((x) >> 3) & 0x7) /* associativity */ #define CPU_CT_xSIZE_SIZE(x) (((x) >> 6) & 0x7) /* size */ #define CPU_CT_xSIZE_P (1U << 11) /* need to page-color */ /* format 4 definitions */ #define CPU_CT4_ILINE(x) ((x) & 0xf) /* I$ line size */ #define CPU_CT4_DLINE(x) (((x) >> 16) & 0xf) /* D$ line size */ #define CPU_CT4_L1IPOLICY(x) (((x) >> 14) & 0x3) /* I$ policy */ #define CPU_CT4_L1_AIVIVT 1 /* ASID tagged VIVT */ #define CPU_CT4_L1_VIPT 2 /* VIPT */ #define CPU_CT4_L1_PIPT 3 /* PIPT */ #define CPU_CT4_ERG(x) (((x) >> 20) & 0xf) /* Cache WriteBack Granule */ #define CPU_CT4_CWG(x) (((x) >> 24) & 0xf) /* Exclusive Resv. Granule */ /* Cache size identifaction register definitions 1, Rd, c0, c0, 0 */ #define CPU_CSID_CTYPE_WT 0x80000000 /* write-through avail */ #define CPU_CSID_CTYPE_WB 0x40000000 /* write-back avail */ #define CPU_CSID_CTYPE_RA 0x20000000 /* read-allocation avail */ #define CPU_CSID_CTYPE_WA 0x10000000 /* write-allocation avail */ #define CPU_CSID_NUMSETS(x) (((x) >> 13) & 0x7fff) #define CPU_CSID_ASSOC(x) (((x) >> 3) & 0x1ff) #define CPU_CSID_LEN(x) ((x) & 0x07) /* Cache size selection register definitions 2, Rd, c0, c0, 0 */ #define CPU_CSSR_L2 0x00000002 #define CPU_CSSR_L1 0x00000000 #define CPU_CSSR_InD 0x00000001 /* Fault status register definitions */ #define FAULT_TYPE_MASK 0x0f #define FAULT_USER 0x10 #define FAULT_WRTBUF_0 0x00 /* Vector Exception */ #define FAULT_WRTBUF_1 0x02 /* Terminal Exception */ #define FAULT_BUSERR_0 0x04 /* External Abort on Linefetch -- Section */ #define FAULT_BUSERR_1 0x06 /* External Abort on Linefetch -- Page */ #define FAULT_BUSERR_2 0x08 /* External Abort on Non-linefetch -- Section */ #define FAULT_BUSERR_3 0x0a /* External Abort on Non-linefetch -- Page */ #define FAULT_BUSTRNL1 0x0c /* External abort on Translation -- Level 1 */ #define FAULT_BUSTRNL2 0x0e /* External abort on Translation -- Level 2 */ #define FAULT_ALIGN_0 0x01 /* Alignment */ #define FAULT_ALIGN_1 0x03 /* Alignment */ #define FAULT_TRANS_S 0x05 /* Translation -- Section */ #define FAULT_TRANS_P 0x07 /* Translation -- Page */ #define FAULT_DOMAIN_S 0x09 /* Domain -- Section */ #define FAULT_DOMAIN_P 0x0b /* Domain -- Page */ #define FAULT_PERM_S 0x0d /* Permission -- Section */ #define FAULT_PERM_P 0x0f /* Permission -- Page */ #define FAULT_LPAE 0x0200 /* (SW) used long descriptors */ #define FAULT_IMPRECISE 0x0400 /* Imprecise exception (XSCALE) */ #define FAULT_WRITE 0x0800 /* fault was due to write (ARMv6+) */ #define FAULT_EXT 0x1000 /* fault was due to external abort (ARMv6+) */ #define FAULT_CM 0x2000 /* fault was due to cache maintenance (ARMv7+) */ /* * Address of the vector page, low and high versions. */ #define ARM_VECTORS_LOW 0x00000000U #define ARM_VECTORS_HIGH 0xffff0000U /* * ARM Instructions * * 3 3 2 2 2 * 1 0 9 8 7 0 * +-------+-------------------------------------------------------+ * | cond | instruction dependent | * |c c c c| | * +-------+-------------------------------------------------------+ */ #define INSN_SIZE 4 /* Always 4 bytes */ #define INSN_COND_MASK 0xf0000000 /* Condition mask */ #define INSN_COND_EQ 0 /* Z == 1 */ #define INSN_COND_NE 1 /* Z == 0 */ #define INSN_COND_CS 2 /* C == 1 */ #define INSN_COND_CC 3 /* C == 0 */ #define INSN_COND_MI 4 /* N == 1 */ #define INSN_COND_PL 5 /* N == 0 */ #define INSN_COND_VS 6 /* V == 1 */ #define INSN_COND_VC 7 /* V == 0 */ #define INSN_COND_HI 8 /* C == 1 && Z == 0 */ #define INSN_COND_LS 9 /* C == 0 || Z == 1 */ #define INSN_COND_GE 10 /* N == V */ #define INSN_COND_LT 11 /* N != V */ #define INSN_COND_GT 12 /* Z == 0 && N == V */ #define INSN_COND_LE 13 /* Z == 1 || N != V */ #define INSN_COND_AL 14 /* Always condition */ #define THUMB_INSN_SIZE 2 /* Some are 4 bytes. */ /* * Defines and such for arm11 Performance Monitor Counters (p15, c15, c12, 0) */ #define ARM11_PMCCTL_E __BIT(0) /* enable all three counters */ #define ARM11_PMCCTL_P __BIT(1) /* reset both Count Registers to zero */ #define ARM11_PMCCTL_C __BIT(2) /* reset the Cycle Counter Register to zero */ #define ARM11_PMCCTL_D __BIT(3) /* cycle count divide by 64 */ #define ARM11_PMCCTL_EC0 __BIT(4) /* Enable Counter Register 0 interrupt */ #define ARM11_PMCCTL_EC1 __BIT(5) /* Enable Counter Register 1 interrupt */ #define ARM11_PMCCTL_ECC __BIT(6) /* Enable Cycle Counter interrupt */ #define ARM11_PMCCTL_SBZa __BIT(7) /* UNP/SBZ */ #define ARM11_PMCCTL_CR0 __BIT(8) /* Count Register 0 overflow flag */ #define ARM11_PMCCTL_CR1 __BIT(9) /* Count Register 1 overflow flag */ #define ARM11_PMCCTL_CCR __BIT(10) /* Cycle Count Register overflow flag */ #define ARM11_PMCCTL_X __BIT(11) /* Enable Export of the events to the event bus */ #define ARM11_PMCCTL_EVT1 __BITS(19,12) /* source of events for Count Register 1 */ #define ARM11_PMCCTL_EVT0 __BITS(27,20) /* source of events for Count Register 0 */ #define ARM11_PMCCTL_SBZb __BITS(31,28) /* UNP/SBZ */ #define ARM11_PMCCTL_SBZ \ (ARM11_PMCCTL_SBZa | ARM11_PMCCTL_SBZb) #define ARM11_PMCEVT_ICACHE_MISS 0 /* Instruction Cache Miss */ #define ARM11_PMCEVT_ISTREAM_STALL 1 /* Instruction Stream Stall */ #define ARM11_PMCEVT_IUTLB_MISS 2 /* Instruction uTLB Miss */ #define ARM11_PMCEVT_DUTLB_MISS 3 /* Data uTLB Miss */ #define ARM11_PMCEVT_BRANCH 4 /* Branch Inst. Executed */ #define ARM11_PMCEVT_BRANCH_MISS 6 /* Branch mispredicted */ #define ARM11_PMCEVT_INST_EXEC 7 /* Instruction Executed */ #define ARM11_PMCEVT_DCACHE_ACCESS0 9 /* Data Cache Access */ #define ARM11_PMCEVT_DCACHE_ACCESS1 10 /* Data Cache Access */ #define ARM11_PMCEVT_DCACHE_MISS 11 /* Data Cache Miss */ #define ARM11_PMCEVT_DCACHE_WRITEBACK 12 /* Data Cache Writeback */ #define ARM11_PMCEVT_PC_CHANGE 13 /* Software PC change */ #define ARM11_PMCEVT_TLB_MISS 15 /* Main TLB Miss */ #define ARM11_PMCEVT_DATA_ACCESS 16 /* non-cached data access */ #define ARM11_PMCEVT_LSU_STALL 17 /* Load/Store Unit stall */ #define ARM11_PMCEVT_WBUF_DRAIN 18 /* Write buffer drained */ #define ARM11_PMCEVT_ETMEXTOUT0 32 /* ETMEXTOUT[0] asserted */ #define ARM11_PMCEVT_ETMEXTOUT1 33 /* ETMEXTOUT[1] asserted */ #define ARM11_PMCEVT_ETMEXTOUT 34 /* ETMEXTOUT[0 & 1] */ #define ARM11_PMCEVT_CALL_EXEC 35 /* Procedure call executed */ #define ARM11_PMCEVT_RETURN_EXEC 36 /* Return executed */ #define ARM11_PMCEVT_RETURN_HIT 37 /* return address predicted */ #define ARM11_PMCEVT_RETURN_MISS 38 /* return addr. mispredicted */ #define ARM11_PMCEVT_CYCLE 255 /* Increment each cycle */ /* Defines for ARM CORTEX performance counters */ #define CORTEX_CNTENS_C __BIT(31) /* Enables the cycle counter */ #define CORTEX_CNTENC_C __BIT(31) /* Disables the cycle counter */ #define CORTEX_CNTOFL_C __BIT(31) /* Cycle counter overflow flag */ /* Defines for ARM Cortex A7/A15 L2CTRL */ #define L2CTRL_NUMCPU __BITS(25,24) // numcpus - 1 #define L2CTRL_ICPRES __BIT(23) // Interrupt Controller is present /* Translation Table Base Register */ #define TTBR_C __BIT(0) /* without MPE */ #define TTBR_S __BIT(1) #define TTBR_IMP __BIT(2) #define TTBR_RGN_MASK __BITS(4,3) #define TTBR_RGN_NC __SHIFTIN(0, TTBR_RGN_MASK) #define TTBR_RGN_WBWA __SHIFTIN(1, TTBR_RGN_MASK) #define TTBR_RGN_WT __SHIFTIN(2, TTBR_RGN_MASK) #define TTBR_RGN_WBNWA __SHIFTIN(3, TTBR_RGN_MASK) #define TTBR_NOS __BIT(5) #define TTBR_IRGN_MASK (__BIT(6) | __BIT(0)) #define TTBR_IRGN_NC 0 #define TTBR_IRGN_WBWA __BIT(6) #define TTBR_IRGN_WT __BIT(0) #define TTBR_IRGN_WBNWA (__BIT(0) | __BIT(6)) /* Translate Table Base Control Register */ #define TTBCR_S_EAE __BIT(31) // Extended Address Extension #define TTBCR_S_PD1 __BIT(5) // Don't use TTBR1 #define TTBCR_S_PD0 __BIT(4) // Don't use TTBR0 #define TTBCR_S_N __BITS(2,0) // Width of base address in TTB0 #define TTBCR_L_EAE __BIT(31) // Extended Address Extension #define TTBCR_L_SH1 __BITS(29,28) // TTBR1 Shareability #define TTBCR_L_ORGN1 __BITS(27,26) // TTBR1 Outer cacheability #define TTBCR_L_IRGN1 __BITS(25,24) // TTBR1 inner cacheability #define TTBCR_L_EPD1 __BIT(23) // Don't use TTBR1 #define TTBCR_L_A1 __BIT(22) // ASID is in TTBR1 #define TTBCR_L_T1SZ __BITS(18,16) // TTBR1 size offset #define TTBCR_L_SH0 __BITS(13,12) // TTBR0 Shareability #define TTBCR_L_ORGN0 __BITS(11,10) // TTBR0 Outer cacheability #define TTBCR_L_IRGN0 __BITS(9,8) // TTBR0 inner cacheability #define TTBCR_L_EPD0 __BIT(7) // Don't use TTBR0 #define TTBCR_L_T0SZ __BITS(2,0) // TTBR0 size offset #define NRRR_ORn(n) __BITS(17+2*(n),16+2*(n)) // Outer Cacheable mappings #define NRRR_IRn(n) __BITS(1+2*(n),0+2*(n)) // Inner Cacheable mappings #define NRRR_NC 0 // non-cacheable #define NRRR_WB_WA 1 // write-back write-allocate #define NRRR_WT 2 // write-through #define NRRR_WB 3 // write-back #define PRRR_NOSn(n) __BITS(24+2*(n))// Memory region is Inner Shareable #define PRRR_NS1 __BIT(19) // Normal Shareable S=1 is Shareable #define PRRR_NS0 __BIT(18) // Normal Shareable S=0 is Shareable #define PRRR_DS1 __BIT(17) // Device Shareable S=1 is Shareable #define PRRR_DS0 __BIT(16) // Device Shareable S=0 is Shareable #define PRRR_TRn(n) __BITS(1+2*(n),0+2*(n)) #define PRRR_TR_STRONG 0 // Strongly Ordered #define PRRR_TR_DEVICE 1 // Device #define PRRR_TR_NORMAL 2 // Normal Memory /* ARMv7 MPIDR, Multiprocessor Affinity Register generic format */ #define MPIDR_MP __BIT(31) /* 1 = Have MP Extention */ #define MPIDR_U __BIT(30) /* 1 = Uni-Processor System */ #define MPIDR_MT __BIT(24) /* 1 = SMT(AFF0 is logical) */ #define MPIDR_AFF2 __BITS(23,16) /* Affinity Level 2 */ #define MPIDR_AFF1 __BITS(15,8) /* Affinity Level 1 */ #define MPIDR_AFF0 __BITS(7,0) /* Affinity Level 0 */ /* MPIDR implementation of ARM Cortex A9: SMT and AFF2 is not used */ #define CORTEXA9_MPIDR_MP MPIDR_MP #define CORTEXA9_MPIDR_U MPIDR_U #define CORTEXA9_MPIDR_CLID __BITS(11,8) /* AFF1 = cluster id */ #define CORTEXA9_MPIDR_CPUID __BITS(0,1) /* AFF0 = physical core id */ /* MPIDR implementation of Marvell PJ4B-MP: AFF2 is not used */ #define PJ4B_MPIDR_MP MPIDR_MP #define PJ4B_MPIDR_U MPIDR_U #define PJ4B_MPIDR_MT MPIDR_MT /* 1 = SMT(AFF0 is logical) */ #define PJ4B_MPIDR_CLID __BITS(11,8) /* AFF1 = cluster id */ #define PJ4B_MPIDR_CPUID __BITS(0,3) /* AFF0 = core id */ /* Defines for ARM Generic Timer */ #define CNTCTL_ISTATUS __BIT(2) // Interrupt is pending #define CNTCTL_IMASK __BIT(1) // Mask Interrupt #define CNTCTL_ENABLE __BIT(0) // Timer Enabled #define CNTKCTL_PL0PTEN __BIT(9) /* PL0 Physical Timer Enable */ #define CNTKCTL_PL0VTEN __BIT(8) /* PL0 Virtual Timer Enable */ #define CNTKCTL_EVNTI __BITS(7,4) /* CNTVCT Event Bit Select */ #define CNTKCTL_EVNTDIR __BIT(3) /* CNTVCT Event Dir (1->0) */ #define CNTKCTL_EVNTEN __BIT(2) /* CNTVCT Event Enable */ #define CNTKCTL_PL0VCTEN __BIT(1) /* PL0 Virtual Counter Enable */ #define CNTKCTL_PL0PCTEN __BIT(0) /* PL0 Physical Counter Enable */ /* CNCHCTL, Timer PL2 Control register, Virtualization Extensions */ #define CNTHCTL_EVNTI __BITS(7,4) #define CNTHCTL_EVNTDIR __BIT(3) #define CNTHCTL_EVNTEN __BIT(2) #define CNTHCTL_PL1PCEN __BIT(1) #define CNTHCTL_PL1PCTEN __BIT(0) #define ARM_A5_TLBDATA_DOM __BITS(62,59) #define ARM_A5_TLBDATA_AP __BITS(58,56) #define ARM_A5_TLBDATA_NS_WALK __BIT(55) #define ARM_A5_TLBDATA_NS_PAGE __BIT(54) #define ARM_A5_TLBDATA_XN __BIT(53) #define ARM_A5_TLBDATA_TEX __BITS(52,50) #define ARM_A5_TLBDATA_B __BIT(49) #define ARM_A5_TLBDATA_C __BIT(48) #define ARM_A5_TLBDATA_S __BIT(47) #define ARM_A5_TLBDATA_ASID __BITS(46,39) #define ARM_A5_TLBDATA_SIZE __BITS(38,37) #define ARM_A5_TLBDATA_SIZE_4KB 0 #define ARM_A5_TLBDATA_SIZE_16KB 1 #define ARM_A5_TLBDATA_SIZE_1MB 2 #define ARM_A5_TLBDATA_SIZE_16MB 3 #define ARM_A5_TLBDATA_VA __BITS(36,22) #define ARM_A5_TLBDATA_PA __BITS(21,2) #define ARM_A5_TLBDATA_nG __BIT(1) #define ARM_A5_TLBDATA_VALID __BIT(0) #define ARM_A7_TLBDATA2_S2_LEVEL __BITS(85-64,84-64) #define ARM_A7_TLBDATA2_S1_SIZE __BITS(83-64,82-64) #define ARM_A7_TLBDATA2_S1_SIZE_4KB 0 #define ARM_A7_TLBDATA2_S1_SIZE_64KB 1 #define ARM_A7_TLBDATA2_S1_SIZE_1MB 2 #define ARM_A7_TLBDATA2_S1_SIZE_16MB 3 #define ARM_A7_TLBDATA2_DOM __BITS(81-64,78-64) #define ARM_A7_TLBDATA2_IS __BITS(77-64,76-64) #define ARM_A7_TLBDATA2_IS_NC 0 #define ARM_A7_TLBDATA2_IS_WB_WA 1 #define ARM_A7_TLBDATA2_IS_WT 2 #define ARM_A7_TLBDATA2_IS_DSO 3 #define ARM_A7_TLBDATA2_S2OVR __BIT(75-64) #define ARM_A7_TLBDATA2_SDO_MT __BITS(74-64,72-64) #define ARM_A7_TLBDATA2_SDO_MT_D 2 #define ARM_A7_TLBDATA2_SDO_MT_SO 6 #define ARM_A7_TLBDATA2_OS __BITS(75-64,74-64) #define ARM_A7_TLBDATA2_OS_NC 0 #define ARM_A7_TLBDATA2_OS_WB_WA 1 #define ARM_A7_TLBDATA2_OS_WT 2 #define ARM_A7_TLBDATA2_OS_WB 3 #define ARM_A7_TLBDATA2_SH __BITS(73-64,72-64) #define ARM_A7_TLBDATA2_SH_NONE 0 #define ARM_A7_TLBDATA2_SH_UNUSED 1 #define ARM_A7_TLBDATA2_SH_OS 2 #define ARM_A7_TLBDATA2_SH_IS 3 #define ARM_A7_TLBDATA2_XN2 __BIT(71-64) #define ARM_A7_TLBDATA2_XN1 __BIT(70-64) #define ARM_A7_TLBDATA2_PXN __BIT(69-64) #define ARM_A7_TLBDATA12_PA __BITS(68-32,41-32) #define ARM_A7_TLBDATA1_NS __BIT(40-32) #define ARM_A7_TLBDATA1_HAP __BITS(39-32,38-32) #define ARM_A7_TLBDATA1_AP __BITS(37-32,35-32) #define ARM_A7_TLBDATA1_nG __BIT(34-32) #define ARM_A7_TLBDATA01_ASID __BITS(33,26) #define ARM_A7_TLBDATA0_VMID __BITS(25,18) #define ARM_A7_TLBDATA0_VA __BITS(17,5) #define ARM_A7_TLBDATA0_NS_WALK __BIT(4) #define ARM_A7_TLBDATA0_SIZE __BITS(3,1) #define ARM_A7_TLBDATA0_SIZE_V7_4KB 0 #define ARM_A7_TLBDATA0_SIZE_LPAE_4KB 1 #define ARM_A7_TLBDATA0_SIZE_V7_64KB 2 #define ARM_A7_TLBDATA0_SIZE_LPAE_64KB 3 #define ARM_A7_TLBDATA0_SIZE_V7_1MB 4 #define ARM_A7_TLBDATA0_SIZE_LPAE_2MB 5 #define ARM_A7_TLBDATA0_SIZE_V7_16MB 6 #define ARM_A7_TLBDATA0_SIZE_LPAE_1GB 7 #define ARM_TLBDATA_VALID __BIT(0) #define ARM_TLBDATAOP_WAY __BIT(31) #define ARM_A5_TLBDATAOP_INDEX __BITS(5,0) #define ARM_A7_TLBDATAOP_INDEX __BITS(6,0) #if !defined(__ASSEMBLER__) && defined(_KERNEL) static inline bool arm_cond_ok_p(uint32_t insn, uint32_t psr) { const uint32_t __cond = __SHIFTOUT(insn, INSN_COND_MASK); bool __ok; const bool __z = (psr & PSR_Z_bit); const bool __n = (psr & PSR_N_bit); const bool __c = (psr & PSR_C_bit); const bool __v = (psr & PSR_V_bit); switch (__cond & ~1) { case INSN_COND_EQ: // Z == 1 __ok = __z; break; case INSN_COND_CS: // C == 1 __ok = __c; break; case INSN_COND_MI: // N == 1 __ok = __n; break; case INSN_COND_VS: // V == 1 __ok = __v; break; case INSN_COND_HI: // C == 1 && Z == 0 __ok = __c && !__z; break; case INSN_COND_GE: // N == V __ok = __n == __v; break; case INSN_COND_GT: // N == V && Z == 0 __ok = __n == __v && !__z; break; default: /* INSN_COND_AL or unconditional */ return true; } return (__cond & 1) ? !__ok : __ok; } #endif /* !__ASSEMBLER && _KERNEL */ #if !defined(__ASSEMBLER__) && !defined(_RUMPKERNEL) #define ARMREG_READ_INLINE(name, __insnstring) \ static inline uint32_t armreg_##name##_read(void) \ { \ uint32_t __rv; \ __asm __volatile("mrc " __insnstring : "=r"(__rv)); \ return __rv; \ } #define ARMREG_WRITE_INLINE(name, __insnstring) \ static inline void armreg_##name##_write(uint32_t __val) \ { \ __asm __volatile("mcr " __insnstring :: "r"(__val)); \ } #define ARMREG_READ_INLINE2(name, __insnstring) \ static inline uint32_t armreg_##name##_read(void) \ { \ uint32_t __rv; \ __asm __volatile(".fpu vfp"); \ __asm __volatile(__insnstring : "=r"(__rv)); \ return __rv; \ } #define ARMREG_WRITE_INLINE2(name, __insnstring) \ static inline void armreg_##name##_write(uint32_t __val) \ { \ __asm __volatile(".fpu vfp"); \ __asm __volatile(__insnstring :: "r"(__val)); \ } #define ARMREG_READ64_INLINE(name, __insnstring) \ static inline uint64_t armreg_##name##_read(void) \ { \ uint64_t __rv; \ __asm __volatile("mrrc " __insnstring : "=r"(__rv)); \ return __rv; \ } #define ARMREG_WRITE64_INLINE(name, __insnstring) \ static inline void armreg_##name##_write(uint64_t __val) \ { \ __asm __volatile("mcrr " __insnstring :: "r"(__val)); \ } /* cp10 registers */ ARMREG_READ_INLINE2(fpsid, "vmrs\t%0, fpsid") /* VFP System ID */ ARMREG_READ_INLINE2(fpscr, "vmrs\t%0, fpscr") /* VFP Status/Control Register */ ARMREG_WRITE_INLINE2(fpscr, "vmsr\tfpscr, %0") /* VFP Status/Control Register */ ARMREG_READ_INLINE2(mvfr1, "vmrs\t%0, mvfr1") /* Media and VFP Feature Register 1 */ ARMREG_READ_INLINE2(mvfr0, "vmrs\t%0, mvfr0") /* Media and VFP Feature Register 0 */ ARMREG_READ_INLINE2(fpexc, "vmrs\t%0, fpexc") /* VFP Exception Register */ ARMREG_WRITE_INLINE2(fpexc, "vmsr\tfpexc, %0") /* VFP Exception Register */ ARMREG_READ_INLINE2(fpinst, "fmrx\t%0, fpinst") /* VFP Exception Instruction */ ARMREG_WRITE_INLINE2(fpinst, "fmxr\tfpinst, %0") /* VFP Exception Instruction */ ARMREG_READ_INLINE2(fpinst2, "fmrx\t%0, fpinst2") /* VFP Exception Instruction 2 */ ARMREG_WRITE_INLINE2(fpinst2, "fmxr\tfpinst2, %0") /* VFP Exception Instruction 2 */ /* cp15 c0 registers */ ARMREG_READ_INLINE(midr, "p15,0,%0,c0,c0,0") /* Main ID Register */ ARMREG_READ_INLINE(ctr, "p15,0,%0,c0,c0,1") /* Cache Type Register */ ARMREG_READ_INLINE(tlbtr, "p15,0,%0,c0,c0,3") /* TLB Type Register */ ARMREG_READ_INLINE(mpidr, "p15,0,%0,c0,c0,5") /* Multiprocess Affinity Register */ ARMREG_READ_INLINE(revidr, "p15,0,%0,c0,c0,6") /* Revision ID Register */ ARMREG_READ_INLINE(pfr0, "p15,0,%0,c0,c1,0") /* Processor Feature Register 0 */ ARMREG_READ_INLINE(pfr1, "p15,0,%0,c0,c1,1") /* Processor Feature Register 1 */ ARMREG_READ_INLINE(mmfr0, "p15,0,%0,c0,c1,4") /* Memory Model Feature Register 0 */ ARMREG_READ_INLINE(mmfr1, "p15,0,%0,c0,c1,5") /* Memory Model Feature Register 1 */ ARMREG_READ_INLINE(mmfr2, "p15,0,%0,c0,c1,6") /* Memory Model Feature Register 2 */ ARMREG_READ_INLINE(mmfr3, "p15,0,%0,c0,c1,7") /* Memory Model Feature Register 3 */ ARMREG_READ_INLINE(isar0, "p15,0,%0,c0,c2,0") /* Instruction Set Attribute Register 0 */ ARMREG_READ_INLINE(isar1, "p15,0,%0,c0,c2,1") /* Instruction Set Attribute Register 1 */ ARMREG_READ_INLINE(isar2, "p15,0,%0,c0,c2,2") /* Instruction Set Attribute Register 2 */ ARMREG_READ_INLINE(isar3, "p15,0,%0,c0,c2,3") /* Instruction Set Attribute Register 3 */ ARMREG_READ_INLINE(isar4, "p15,0,%0,c0,c2,4") /* Instruction Set Attribute Register 4 */ ARMREG_READ_INLINE(isar5, "p15,0,%0,c0,c2,5") /* Instruction Set Attribute Register 5 */ ARMREG_READ_INLINE(ccsidr, "p15,1,%0,c0,c0,0") /* Cache Size ID Register */ ARMREG_READ_INLINE(clidr, "p15,1,%0,c0,c0,1") /* Cache Level ID Register */ ARMREG_READ_INLINE(csselr, "p15,2,%0,c0,c0,0") /* Cache Size Selection Register */ ARMREG_WRITE_INLINE(csselr, "p15,2,%0,c0,c0,0") /* Cache Size Selection Register */ /* cp15 c1 registers */ ARMREG_READ_INLINE(sctlr, "p15,0,%0,c1,c0,0") /* System Control Register */ ARMREG_WRITE_INLINE(sctlr, "p15,0,%0,c1,c0,0") /* System Control Register */ ARMREG_READ_INLINE(auxctl, "p15,0,%0,c1,c0,1") /* Auxiliary Control Register */ ARMREG_WRITE_INLINE(auxctl, "p15,0,%0,c1,c0,1") /* Auxiliary Control Register */ ARMREG_READ_INLINE(cpacr, "p15,0,%0,c1,c0,2") /* Co-Processor Access Control Register */ ARMREG_WRITE_INLINE(cpacr, "p15,0,%0,c1,c0,2") /* Co-Processor Access Control Register */ ARMREG_READ_INLINE(scr, "p15,0,%0,c1,c1,0") /* Secure Configuration Register */ ARMREG_READ_INLINE(nsacr, "p15,0,%0,c1,c1,2") /* Non-Secure Access Control Register */ /* cp15 c2 registers */ ARMREG_READ_INLINE(ttbr, "p15,0,%0,c2,c0,0") /* Translation Table Base Register 0 */ ARMREG_WRITE_INLINE(ttbr, "p15,0,%0,c2,c0,0") /* Translation Table Base Register 0 */ ARMREG_READ_INLINE(ttbr1, "p15,0,%0,c2,c0,1") /* Translation Table Base Register 1 */ ARMREG_WRITE_INLINE(ttbr1, "p15,0,%0,c2,c0,1") /* Translation Table Base Register 1 */ ARMREG_READ_INLINE(ttbcr, "p15,0,%0,c2,c0,2") /* Translation Table Base Register */ ARMREG_WRITE_INLINE(ttbcr, "p15,0,%0,c2,c0,2") /* Translation Table Base Register */ /* cp15 c3 registers */ ARMREG_READ_INLINE(dacr, "p15,0,%0,c3,c0,0") /* Domain Access Control Register */ ARMREG_WRITE_INLINE(dacr, "p15,0,%0,c3,c0,0") /* Domain Access Control Register */ /* cp15 c5 registers */ ARMREG_READ_INLINE(dfsr, "p15,0,%0,c5,c0,0") /* Data Fault Status Register */ ARMREG_READ_INLINE(ifsr, "p15,0,%0,c5,c0,1") /* Instruction Fault Status Register */ /* cp15 c6 registers */ ARMREG_READ_INLINE(dfar, "p15,0,%0,c6,c0,0") /* Data Fault Address Register */ ARMREG_READ_INLINE(ifar, "p15,0,%0,c6,c0,2") /* Instruction Fault Address Register */ /* cp15 c7 registers */ ARMREG_WRITE_INLINE(icialluis, "p15,0,%0,c7,c1,0") /* Instruction Inv All (IS) */ ARMREG_WRITE_INLINE(bpiallis, "p15,0,%0,c7,c1,6") /* Branch Predictor Invalidate All (IS) */ ARMREG_READ_INLINE(par, "p15,0,%0,c7,c4,0") /* Physical Address Register */ ARMREG_WRITE_INLINE(iciallu, "p15,0,%0,c7,c5,0") /* Instruction Invalidate All */ ARMREG_WRITE_INLINE(icimvau, "p15,0,%0,c7,c5,1") /* Instruction Invalidate MVA */ ARMREG_WRITE_INLINE(isb, "p15,0,%0,c7,c5,4") /* Instruction Synchronization Barrier */ ARMREG_WRITE_INLINE(bpiall, "p15,0,%0,c7,c5,6") /* Branch Predictor Invalidate All */ ARMREG_WRITE_INLINE(bpimva, "p15,0,%0,c7,c5,7") /* Branch Predictor invalidate by MVA */ ARMREG_WRITE_INLINE(dcimvac, "p15,0,%0,c7,c6,1") /* Data Invalidate MVA to PoC */ ARMREG_WRITE_INLINE(dcisw, "p15,0,%0,c7,c6,2") /* Data Invalidate Set/Way */ ARMREG_WRITE_INLINE(ats1cpr, "p15,0,%0,c7,c8,0") /* AddrTrans CurState PL1 Read */ ARMREG_WRITE_INLINE(ats1cpw, "p15,0,%0,c7,c8,1") /* AddrTrans CurState PL1 Write */ ARMREG_WRITE_INLINE(ats1cur, "p15,0,%0,c7,c8,2") /* AddrTrans CurState PL0 Read */ ARMREG_WRITE_INLINE(ats1cuw, "p15,0,%0,c7,c8,3") /* AddrTrans CurState PL0 Write */ ARMREG_WRITE_INLINE(dccmvac, "p15,0,%0,c7,c10,1") /* Data Clean MVA to PoC */ ARMREG_WRITE_INLINE(dccsw, "p15,0,%0,c7,c10,2") /* Data Clean Set/Way */ ARMREG_WRITE_INLINE(dsb, "p15,0,%0,c7,c10,4") /* Data Synchronization Barrier */ ARMREG_WRITE_INLINE(dmb, "p15,0,%0,c7,c10,5") /* Data Memory Barrier */ ARMREG_WRITE_INLINE(dccmvau, "p15,0,%0,c7,c11,1") /* Data Clean MVA to PoU */ ARMREG_WRITE_INLINE(dccimvac, "p15,0,%0,c7,c14,1") /* Data Clean&Inv MVA to PoC */ ARMREG_WRITE_INLINE(dccisw, "p15,0,%0,c7,c14,2") /* Data Clean&Inv Set/Way */ /* cp15 c8 registers */ ARMREG_WRITE_INLINE(tlbiallis, "p15,0,%0,c8,c3,0") /* Invalidate entire unified TLB, inner shareable */ ARMREG_WRITE_INLINE(tlbimvais, "p15,0,%0,c8,c3,1") /* Invalidate unified TLB by MVA, inner shareable */ ARMREG_WRITE_INLINE(tlbiasidis, "p15,0,%0,c8,c3,2") /* Invalidate unified TLB by ASID, inner shareable */ ARMREG_WRITE_INLINE(tlbimvaais, "p15,0,%0,c8,c3,3") /* Invalidate unified TLB by MVA, all ASID, inner shareable */ ARMREG_WRITE_INLINE(itlbiall, "p15,0,%0,c8,c5,0") /* Invalidate entire instruction TLB */ ARMREG_WRITE_INLINE(itlbimva, "p15,0,%0,c8,c5,1") /* Invalidate instruction TLB by MVA */ ARMREG_WRITE_INLINE(itlbiasid, "p15,0,%0,c8,c5,2") /* Invalidate instruction TLB by ASID */ ARMREG_WRITE_INLINE(dtlbiall, "p15,0,%0,c8,c6,0") /* Invalidate entire data TLB */ ARMREG_WRITE_INLINE(dtlbimva, "p15,0,%0,c8,c6,1") /* Invalidate data TLB by MVA */ ARMREG_WRITE_INLINE(dtlbiasid, "p15,0,%0,c8,c6,2") /* Invalidate data TLB by ASID */ ARMREG_WRITE_INLINE(tlbiall, "p15,0,%0,c8,c7,0") /* Invalidate entire unified TLB */ ARMREG_WRITE_INLINE(tlbimva, "p15,0,%0,c8,c7,1") /* Invalidate unified TLB by MVA */ ARMREG_WRITE_INLINE(tlbiasid, "p15,0,%0,c8,c7,2") /* Invalidate unified TLB by ASID */ ARMREG_WRITE_INLINE(tlbimvaa, "p15,0,%0,c8,c7,3") /* Invalidate unified TLB by MVA, all ASID */ /* cp15 c9 registers */ ARMREG_READ_INLINE(pmcr, "p15,0,%0,c9,c12,0") /* PMC Control Register */ ARMREG_WRITE_INLINE(pmcr, "p15,0,%0,c9,c12,0") /* PMC Control Register */ ARMREG_READ_INLINE(pmcntenset, "p15,0,%0,c9,c12,1") /* PMC Count Enable Set */ ARMREG_WRITE_INLINE(pmcntenset, "p15,0,%0,c9,c12,1") /* PMC Count Enable Set */ ARMREG_READ_INLINE(pmcntenclr, "p15,0,%0,c9,c12,2") /* PMC Count Enable Clear */ ARMREG_WRITE_INLINE(pmcntenclr, "p15,0,%0,c9,c12,2") /* PMC Count Enable Clear */ ARMREG_READ_INLINE(pmovsr, "p15,0,%0,c9,c12,3") /* PMC Overflow Flag Status */ ARMREG_WRITE_INLINE(pmovsr, "p15,0,%0,c9,c12,3") /* PMC Overflow Flag Status */ ARMREG_READ_INLINE(pmselr, "p15,0,%0,c9,c12,5") /* PMC Event Counter Selection */ ARMREG_WRITE_INLINE(pmselr, "p15,0,%0,c9,c12,5") /* PMC Event Counter Selection */ ARMREG_READ_INLINE(pmceid0, "p15,0,%0,c9,c12,6") /* PMC Event ID 0 */ ARMREG_READ_INLINE(pmceid1, "p15,0,%0,c9,c12,7") /* PMC Event ID 1 */ ARMREG_READ_INLINE(pmccntr, "p15,0,%0,c9,c13,0") /* PMC Cycle Counter */ ARMREG_WRITE_INLINE(pmccntr, "p15,0,%0,c9,c13,0") /* PMC Cycle Counter */ ARMREG_READ_INLINE(pmxevtyper, "p15,0,%0,c9,c13,1") /* PMC Event Type Select */ ARMREG_WRITE_INLINE(pmxevtyper, "p15,0,%0,c9,c13,1") /* PMC Event Type Select */ ARMREG_READ_INLINE(pmxevcntr, "p15,0,%0,c9,c13,2") /* PMC Event Count */ ARMREG_WRITE_INLINE(pmxevcntr, "p15,0,%0,c9,c13,2") /* PMC Event Count */ ARMREG_READ_INLINE(pmuserenr, "p15,0,%0,c9,c14,0") /* PMC User Enable */ ARMREG_WRITE_INLINE(pmuserenr, "p15,0,%0,c9,c14,0") /* PMC User Enable */ ARMREG_READ_INLINE(pmintenset, "p15,0,%0,c9,c14,1") /* PMC Interrupt Enable Set */ ARMREG_WRITE_INLINE(pmintenset, "p15,0,%0,c9,c14,1") /* PMC Interrupt Enable Set */ ARMREG_READ_INLINE(pmintenclr, "p15,0,%0,c9,c14,2") /* PMC Interrupt Enable Clear */ ARMREG_WRITE_INLINE(pmintenclr, "p15,0,%0,c9,c14,2") /* PMC Interrupt Enable Clear */ ARMREG_READ_INLINE(l2ctrl, "p15,1,%0,c9,c0,2") /* A7/A15 L2 Control Register */ /* cp10 c10 registers */ ARMREG_READ_INLINE(prrr, "p15,0,%0,c10,c2,0") /* Primary Region Remap Register */ ARMREG_WRITE_INLINE(prrr, "p15,0,%0,c10,c2,0") /* Primary Region Remap Register */ ARMREG_READ_INLINE(nrrr, "p15,0,%0,c10,c2,1") /* Normal Region Remap Register */ ARMREG_WRITE_INLINE(nrrr, "p15,0,%0,c10,c2,1") /* Normal Region Remap Register */ /* cp15 c13 registers */ ARMREG_READ_INLINE(contextidr, "p15,0,%0,c13,c0,1") /* Context ID Register */ ARMREG_WRITE_INLINE(contextidr, "p15,0,%0,c13,c0,1") /* Context ID Register */ ARMREG_READ_INLINE(tpidrurw, "p15,0,%0,c13,c0,2") /* User read-write Thread ID Register */ ARMREG_WRITE_INLINE(tpidrurw, "p15,0,%0,c13,c0,2") /* User read-write Thread ID Register */ ARMREG_READ_INLINE(tpidruro, "p15,0,%0,c13,c0,3") /* User read-only Thread ID Register */ ARMREG_WRITE_INLINE(tpidruro, "p15,0,%0,c13,c0,3") /* User read-only Thread ID Register */ ARMREG_READ_INLINE(tpidrprw, "p15,0,%0,c13,c0,4") /* PL1 only Thread ID Register */ ARMREG_WRITE_INLINE(tpidrprw, "p15,0,%0,c13,c0,4") /* PL1 only Thread ID Register */ /* cp14 c12 registers */ ARMREG_READ_INLINE(vbar, "p15,0,%0,c12,c0,0") /* Vector Base Address Register */ ARMREG_WRITE_INLINE(vbar, "p15,0,%0,c12,c0,0") /* Vector Base Address Register */ /* cp15 c14 registers */ /* cp15 Global Timer Registers */ ARMREG_READ_INLINE(cnt_frq, "p15,0,%0,c14,c0,0") /* Counter Frequency Register */ ARMREG_WRITE_INLINE(cnt_frq, "p15,0,%0,c14,c0,0") /* Counter Frequency Register */ ARMREG_READ_INLINE(cntk_ctl, "p15,0,%0,c14,c1,0") /* Timer PL1 Control Register */ ARMREG_WRITE_INLINE(cntk_ctl, "p15,0,%0,c14,c1,0") /* Timer PL1 Control Register */ ARMREG_READ_INLINE(cntp_tval, "p15,0,%0,c14,c2,0") /* PL1 Physical TimerValue Register */ ARMREG_WRITE_INLINE(cntp_tval, "p15,0,%0,c14,c2,0") /* PL1 Physical TimerValue Register */ ARMREG_READ_INLINE(cntp_ctl, "p15,0,%0,c14,c2,1") /* PL1 Physical Timer Control Register */ ARMREG_WRITE_INLINE(cntp_ctl, "p15,0,%0,c14,c2,1") /* PL1 Physical Timer Control Register */ ARMREG_READ_INLINE(cntv_tval, "p15,0,%0,c14,c3,0") /* Virtual TimerValue Register */ ARMREG_WRITE_INLINE(cntv_tval, "p15,0,%0,c14,c3,0") /* Virtual TimerValue Register */ ARMREG_READ_INLINE(cntv_ctl, "p15,0,%0,c14,c3,1") /* Virtual Timer Control Register */ ARMREG_WRITE_INLINE(cntv_ctl, "p15,0,%0,c14,c3,1") /* Virtual Timer Control Register */ ARMREG_READ64_INLINE(cntp_ct, "p15,0,%Q0,%R0,c14") /* Physical Count Register */ ARMREG_WRITE64_INLINE(cntp_ct, "p15,0,%Q0,%R0,c14") /* Physical Count Register */ ARMREG_READ64_INLINE(cntv_ct, "p15,1,%Q0,%R0,c14") /* Virtual Count Register */ ARMREG_WRITE64_INLINE(cntv_ct, "p15,1,%Q0,%R0,c14") /* Virtual Count Register */ ARMREG_READ64_INLINE(cntp_cval, "p15,2,%Q0,%R0,c14") /* PL1 Physical Timer CompareValue Register */ ARMREG_WRITE64_INLINE(cntp_cval, "p15,2,%Q0,%R0,c14") /* PL1 Physical Timer CompareValue Register */ ARMREG_READ64_INLINE(cntv_cval, "p15,3,%Q0,%R0,c14") /* PL1 Virtual Timer CompareValue Register */ ARMREG_WRITE64_INLINE(cntv_cval, "p15,3,%Q0,%R0,c14") /* PL1 Virtual Timer CompareValue Register */ ARMREG_READ64_INLINE(cntvoff, "p15,4,%Q0,%R0,c14") /* Virtual Offset Register */ ARMREG_WRITE64_INLINE(cntvoff, "p15,4,%Q0,%R0,c14") /* Virtual Offset Register */ /* cp15 c15 registers */ ARMREG_READ_INLINE(cbar, "p15,4,%0,c15,c0,0") /* Configuration Base Address Register */ ARMREG_READ_INLINE(pmcrv6, "p15,0,%0,c15,c12,0") /* PMC Control Register (armv6) */ ARMREG_WRITE_INLINE(pmcrv6, "p15,0,%0,c15,c12,0") /* PMC Control Register (armv6) */ ARMREG_READ_INLINE(pmccntrv6, "p15,0,%0,c15,c12,1") /* PMC Cycle Counter (armv6) */ ARMREG_WRITE_INLINE(pmccntrv6, "p15,0,%0,c15,c12,1") /* PMC Cycle Counter (armv6) */ ARMREG_READ_INLINE(tlbdata0, "p15,3,%0,c15,c0,0") /* TLB Data Register 0 (cortex) */ ARMREG_READ_INLINE(tlbdata1, "p15,3,%0,c15,c0,1") /* TLB Data Register 1 (cortex) */ ARMREG_READ_INLINE(tlbdata2, "p15,3,%0,c15,c0,2") /* TLB Data Register 2 (cortex) */ ARMREG_WRITE_INLINE(tlbdataop, "p15,3,%0,c15,c4,2") /* TLB Data Read Operation (cortex) */ ARMREG_READ_INLINE(sheeva_xctrl, "p15,1,%0,c15,c1,0") /* Sheeva eXtra Control register */ ARMREG_WRITE_INLINE(sheeva_xctrl, "p15,1,%0,c15,c1,0") /* Sheeva eXtra Control register */ #if defined(_KERNEL) static inline uint64_t cpu_mpidr_aff_read(void) { return armreg_mpidr_read() & (MPIDR_AFF2|MPIDR_AFF1|MPIDR_AFF0); } /* * GENERIC TIMER register access */ static inline uint32_t gtmr_cntfrq_read(void) { return armreg_cnt_frq_read(); } static inline uint32_t gtmr_cntk_ctl_read(void) { return armreg_cntk_ctl_read(); } static inline void gtmr_cntk_ctl_write(uint32_t val) { armreg_cntk_ctl_write(val); } static inline uint64_t gtmr_cntpct_read(void) { return armreg_cntp_ct_read(); } /* * Counter-timer Virtual Count timer */ static inline uint64_t gtmr_cntvct_read(void) { return armreg_cntv_ct_read(); } /* * Counter-timer Virtual Timer Control register */ static inline uint32_t gtmr_cntv_ctl_read(void) { return armreg_cntv_ctl_read(); } static inline void gtmr_cntv_ctl_write(uint32_t val) { armreg_cntv_ctl_write(val); } static inline void gtmr_cntp_ctl_write(uint32_t val) { armreg_cntp_ctl_write(val); } /* * Counter-timer Virtual Timer TimerValue register */ static inline uint32_t gtmr_cntv_tval_read(void) { return armreg_cntv_tval_read(); } static inline void gtmr_cntv_tval_write(uint32_t val) { armreg_cntv_tval_write(val); } /* * Counter-timer Virtual Timer CompareValue register */ static inline uint64_t gtmr_cntv_cval_read(void) { return armreg_cntv_cval_read(); } #endif /* _KERNEL */ #endif /* !__ASSEMBLER && !_RUMPKERNEL */ #elif defined(__aarch64__) #include // #endif /* __arm__/__aarch64__ */ #endif /* _ARM_ARMREG_H */ gxemul-0.6.1/src/include/thirdparty/sfbreg.h000644 001750 001750 00000007754 13402411502 021267 0ustar00debugdebug000000 000000 #ifndef SFBREG_H #define SFBREG_H /*- * Copyright (c) 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)sfb.c 8.1 (Berkeley) 6/10/93 * $NetBSD: sfbreg.h,v 1.2 1997/10/13 14:22:41 lukem Exp $ */ #define SFB_OFFSET_VRAM 0x201000 /* from module's base */ #define SFB_OFFSET_BT459 0x1C0000 /* Bt459 registers */ #define SFB_ASIC_OFFSET 0x100000 /* SFB ASIC registers... */ #define SFB_COPY_REG0 0x100000 /* Copy Buffer Register0 */ #define SFB_COPY_REG1 0x100004 /* Copy Buffer Register1 */ #define SFB_COPY_REG2 0x100008 /* Copy Buffer Register2 */ #define SFB_COPY_REG3 0x10000C /* Copy Buffer Register3 */ #define SFB_COPY_REG4 0x100010 /* Copy Buffer Register4 */ #define SFB_COPY_REG5 0x100014 /* Copy Buffer Register5 */ #define SFB_COPY_REG6 0x100018 /* Copy Buffer Register6 */ #define SFB_COPY_REG7 0x10001C /* Copy Buffer Register7 */ #define SFB_FOREGROUND 0x100020 /* Foreground */ #define SFB_BACKGROUND 0x100024 /* Background */ #define SFB_PLANEMASK 0x100028 /* PlaneMask */ #define SFB_PIXELMASK 0x10002C /* PixelMask Register */ #define SFB_MODE 0x100030 /* Mode Register */ #define SFB_BOOL_OP 0x100034 /* Boolean Op Register */ #define SFB_PIXELSHIFT 0x100038 /* PixelShift Register */ #define SFB_ADDRESS 0x10003C /* Address Register */ #define SFB_BRESENHAM1 0x100040 /* Bresenham Register 1 */ #define SFB_BRESENHAM2 0x100044 /* Bresenham Register 2 */ #define SFB_BRESENHAM3 0x100048 /* Bresenham Register 3 */ #define SFB_BCONT 0x10004C /* BCont */ #define SFB_DEEP 0x100050 /* Deep Register */ #define SFB_START 0x100054 /* Start Register */ #define SFB_CLEAR 0x100058 /* Clear Interrupt */ #define SFB_VREFRESH_COUNT 0x100060 /* Video Refresh Count */ #define SFB_VHORIZONTAL 0x100064 /* Video Horizontal Setup */ #define SFB_VVERTICAL 0x100068 /* Video Vertical Setup */ #define SFB_VBASE 0x10006C /* Video Base Address */ #define SFB_VVALID 0x100070 /* Video Valid */ #define SFB_INTERRUPT_ENABLE 0x100074 /* Enable/disable interrupts */ #define SFB_TCCLK 0x100078 /* TCCLK count */ #define SFB_VIDCLK 0x10007C /* VIDCLK count */ #define SFB_FB_SIZE 0x1FF000 /* frame buffer size */ #endif /* SFBREG_H */ gxemul-0.6.1/src/include/thirdparty/crimereg.h000644 001750 001750 00000013574 13402411502 021611 0ustar00debugdebug000000 000000 /* $NetBSD: crimereg.h,v 1.10 2005/12/11 12:18:52 christos Exp $ */ /* * Copyright (c) 2000 Soren S. Jorvang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the * NetBSD Project. See http://www.NetBSD.org/ for * information about NetBSD. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * O2 CRIME register definitions */ #define CRIME_BASE 0x14000000 /* all registers 64-bit access */ /* Offset 0x00 -- revision register */ #define CRIME_REV 0x00 #define CRIME_ID_IDBITS 0x000000f0 #define CRIME_ID_IDSHIFT 4 #define CRIME_ID_REV 0x0000000f #define CRIME_REV_PETTY 0x00 #define CRIME_REV_11 0x11 #define CRIME_REV_13 0x13 #define CRIME_REV_14 0x14 /* offset 0x08 -- control register. Only lower 14 bits are valid */ #define CRIME_CONTROL 0x08 #define CRIME_CONTROL_TRITON_SYSADC 0x2000 #define CRIME_CONTROL_CRIME_SYSADC 0x1000 #define CRIME_CONTROL_HARD_RESET 0x0800 #define CRIME_CONTROL_SOFT_RESET 0x0400 #define CRIME_CONTROL_DOG_ENABLE 0x0200 #define CRIME_CONTROL_ENDIANESS 0x0100 /* assert for BE */ #define CRIME_CONTROL_CQUEUE_HWM 0x000f #define CRIME_CONTROL_CQUEUE_SHFT 0 #define CRIME_CONTROL_WBUF_HWM 0x00f0 #define CRIME_CONTROL_WBUF_SHFT 8 /* * macros to manipulate CRIME High Water Mark bits in * the CRIME control register. Examples: * * foo = CRM_CONTROL_GET_CQUEUE_HWM(*(__uint64_t *)CRM_CONTROL) * CRM_CONTROL_SET_CQUEUE_HWM(*(__uint64_t *)CRM_CONTROL, 4) * * foo = CRM_CONTROL_GET_WBUF_HWM(*(__uint64_t *)CRM_CONTROL) * CRM_CONTROL_SET_WBUF_HWM(*(__uint64_t *)CRM_CONTROL, 4) */ #define CRM_CONTROL_GET_CQUEUE_HWM(x) \ (((x) & CRM_CONTROL_CQUEUE_HWM) >> CRM_CONTROL_CQUEUE_SHFT) #define CRM_CONTROL_SET_CQUEUE_HWM(x,v) \ (((v) << CRM_CONTROL_CQUEUE_SHFT) | ((x) & ~CRM_CONTROL_CQUEUE_HWM)) #define CRM_CONTROL_GET_WBUF_HWM(x) \ (((x) & CRM_CONTROL_WBUF_HWM) >> CRM_CONTROL_WBUF_SHFT) #define CRM_CONTROL_SET_WBUF_HWM(x,v) \ (((v) << CRM_CONTROL_WBUF_SHFT) | ((x) & ~CRM_CONTROL_WBUF_HWM)) /* Offset 0x010 -- interrupt status register. All 32 bits valid */ #define CRIME_INTSTAT 0x10 #define CRIME_INT_VICE 0x80000000 #define CRIME_INT_SOFT2 0x40000000 /* Also CPU_SysCorErr */ #define CRIME_INT_SOFT1 0x20000000 #define CRIME_INT_SOFT0 0x10000000 #define CRIME_INT_RE5 0x08000000 #define CRIME_INT_RE4 0x04000000 #define CRIME_INT_RE3 0x02000000 #define CRIME_INT_RE2 0x01000000 #define CRIME_INT_RE1 0x00800000 #define CRIME_INT_RE0 0x00400000 #define CRIME_INT_MEMERR 0x00200000 #define CRIME_INT_CRMERR 0x00100000 #define CRIME_INT_GBE3 0x00080000 #define CRIME_INT_GBE2 0x00040000 #define CRIME_INT_GBE1 0x00020000 #define CRIME_INT_GBE0 0x00010000 #define CRIME_INT_PCI_SHARED2 0x00008000 /* from here, actually mace irqs */ #define CRIME_INT_PCI_SHARED1 0x00004000 #define CRIME_INT_PCI_SHARED0 0x00002000 #define CRIME_INT_PCI_SLOT2 0x00001000 #define CRIME_INT_PCI_SLOT1 0x00000800 #define CRIME_INT_PCI_SLOT0 0x00000400 #define CRIME_INT_PCI_SCSI1 0x00000200 #define CRIME_INT_PCI_SCSI0 0x00000100 #define CRIME_INT_PCI_BRIDGE 0x00000080 #define CRIME_INT_PERIPH_AUD 0x00000040 #define CRIME_INT_PERIPH_MISC 0x00000020 #define CRIME_INT_PERIPH_SERIAL 0x00000010 #define CRIME_INT_ETHERNET 0x00000008 #define CRIME_INT_VID_OUT 0x00000004 #define CRIME_INT_VID_IN2 0x00000002 #define CRIME_INT_VID_IN1 0x00000001 /* Masks, hard interrupts, soft interrupts. */ #define CRIME_INTMASK 0x18 #define CRIME_SOFTINT 0x20 #define CRIME_HARDINT 0x28 /* * Offset 0x030 -- watchdog register. 33 bits are valid * Bit 32: power on reset * Bit 31: warm reset * Write zero here to reset watchdog */ #define CRIME_DOG 0x30 #define CRIME_WATCHDOG CRIME_DOG #define CRIME_TIME 0x38 #define CRIME_TIME_MASK 0x0000ffffffffffffULL #define CRIME_CPU_ERROR_ADDR 0x40 #define CRIME_CPU_ERROR_STAT 0x48 #define CRIME_CPU_ERROR_ENA 0x50 #define CRIME_VICE_ERROR_ADDR 0x58 #define CRIME_MEM_CONTROL 0x0200 #define CRIME_MEM_BANK_CTRL0 0x0208 #define CRIME_MEM_BANK_CTRL1 0x0218 #define CRIME_MEM_BANK_CTRL2 0x0210 #define CRIME_MEM_BANK_CTRL3 0x0228 #define CRIME_MEM_BANK_CTRL4 0x0220 #define CRIME_MEM_BANK_CTRL5 0x0238 #define CRIME_MEM_BANK_CTRL6 0x0230 #define CRIME_MEM_BANK_CTRL7 0x0248 #define CRIME_MEM_REFRESH_CNTR 0x0248 #define CRIME_MEM_ERROR_STAT 0x0250 #define CRIME_MEM_ERROR_ADDR 0x0258 #define CRIME_MEM_ERROR_ECC_SYN 0x0260 #define CRIME_MEM_ERROR_ECC_CHK 0x0268 #define CRIME_MEM_ERROR_ECC_REPL 0x0270 #define McGriff CRIME_DOG /* Baseball compatibility */ gxemul-0.6.1/src/include/thirdparty/ppc_bat.h000644 001750 001750 00000017570 13402411502 021424 0ustar00debugdebug000000 000000 /* GXemul: $Id: ppc_bat.h,v 1.1 2005-11-17 21:26:07 debug Exp $ */ /* $NetBSD: bat.h,v 1.5 2003/03/14 06:21:19 matt Exp $ */ #ifndef _POWERPC_OEA_BAT_H_ #define _POWERPC_OEA_BAT_H_ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (C) 1995, 1996 Wolfgang Solfrank. * Copyright (C) 1995, 1996 TooLs GmbH. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if 0 #ifndef _LOCORE struct bat { register_t batu; register_t batl; }; #endif #endif /* Lower BAT bits (all but PowerPC 601): */ #define BAT_RPN (~0x1ffff) /* physical block start */ #define BAT_XPN 0x00000e00 /* eXtended physical page number (0-2) */ #define BAT_W 0x00000040 /* 1 = write-through, 0 = write-back */ #define BAT_I 0x00000020 /* cache inhibit */ #define BAT_M 0x00000010 /* memory coherency enable */ #define BAT_G 0x00000008 /* guarded region (not on 601) */ #define BAT_X 0x00000004 /* eXtended physical page number (3) */ /* * BAT_XPN and BAT_X are only used when HID0[XAEN] == 1 and are used * to generate the 4 MSB of physical address */ #define BAT_PP 0x00000003 /* PP mask */ #define BAT_PP_NONE 0x00000000 /* no access permission */ #define BAT_PP_RO_S 0x00000001 /* read-only (soft) */ #define BAT_PP_RW 0x00000002 /* read/write */ #define BAT_PP_RO 0x00000003 /* read-only */ /* Upper BAT bits (all but PowerPC 601): */ #define BAT_EPI (~0x1ffffL) /* effective block start */ #define BAT_BL 0x00001ffc /* block length */ #define BAT_Vs 0x00000002 /* valid in supervisor mode */ #define BAT_Vu 0x00000001 /* valid in user mode */ #define BAT_XBL 0x0001e000 /* eXtended Block Length (*) */ #define BAT_XBL_512M 0x00002000 /* XBL for 512MB */ #define BAT_XBL_1G 0x00006000 /* XBL for 1GB */ #define BAT_XBL_2G 0x0000e000 /* XBL for 2GB */ #define BAT_XBL_4G 0x0001e000 /* XBL for 4GB */ #define BAT_V (BAT_Vs|BAT_Vu) /* Block Length encoding (all but PowerPC 601): */ #define BAT_BL_128K 0x00000000 #define BAT_BL_256K 0x00000004 #define BAT_BL_512K 0x0000000c #define BAT_BL_1M 0x0000001c #define BAT_BL_2M 0x0000003c #define BAT_BL_4M 0x0000007c #define BAT_BL_8M 0x000000fc #define BAT_BL_16M 0x000001fc #define BAT_BL_32M 0x000003fc #define BAT_BL_64M 0x000007fc #define BAT_BL_128M 0x00000ffc #define BAT_BL_256M 0x00001ffc #define BATU(va, len, v) \ (((va) & BAT_EPI) | ((len) & BAT_BL) | ((v) & BAT_V)) #define BATL(pa, wimg, pp) \ (((pa) & BAT_RPN) | (wimg) | (pp)) #define BAT_VA_MATCH_P(batu,va) \ (((~(((batu)&BAT_BL)<<15))&(va)&BAT_EPI)==((batu)&BAT_EPI)) #define BAT_PA_MATCH_P(batu,batl,pa) \ (((~(((batu)&BAT_BL)<<15))&(pa)&BAT_RPN)==((batl)&BAT_RPN)) #define BAT_VALID_P(batu, msr) \ (((msr)&PSL_PR)?(((batu)&BAT_Vu)==BAT_Vu):(((batu)&BAT_Vs)==BAT_Vs)) /* Lower BAT bits (PowerPC 601): */ #define BAT601_PBN 0xfffe0000 /* physical block number */ #define BAT601_V 0x00000040 /* valid */ #define BAT601_BSM 0x0000003f /* block size mask */ /* Upper BAT bits (PowerPC 601): */ #define BAT601_BLPI 0xfffe0000 /* block logical page index */ #define BAT601_W 0x00000040 /* 1 = write-through, 0 = write-back */ #define BAT601_I 0x00000020 /* cache inhibit */ #define BAT601_M 0x00000010 /* memory coherency enable */ #define BAT601_Ks 0x00000008 /* key-supervisor */ #define BAT601_Ku 0x00000004 /* key-user */ /* * Permission bits on the PowerPC 601 are modified by the appropriate * Key bit: * * Key PP Access * 0 NONE read/write * 0 RO_S read/write * 0 RW read/write * 0 RO read-only * * 1 NONE none * 1 RO_S read-only * 1 RW read/write * 1 RO read-only */ #define BAT601_PP 0x00000003 #define BAT601_PP_NONE 0x00000000 /* no access permission */ #define BAT601_PP_RO_S 0x00000001 /* read-only (soft) */ #define BAT601_PP_RW 0x00000002 /* read/write */ #define BAT601_PP_RO 0x00000003 /* read-only */ /* Block Size Mask encoding (PowerPC 601): */ #define BAT601_BSM_128K 0x00000000 #define BAT601_BSM_256K 0x00000001 #define BAT601_BSM_512K 0x00000003 #define BAT601_BSM_1M 0x00000007 #define BAT601_BSM_2M 0x0000000f #define BAT601_BSM_4M 0x0000001f #define BAT601_BSM_8M 0x0000003f #define BATU601(va, wim, key, pp) \ (((va) & BAT601_BLPI) | (wim) | (key) | (pp)) #define BATL601(pa, size, v) \ (((pa) & BAT601_PBN) | (v) | (size)) #define BAT601_VA_MATCH_P(batu, batl, va) \ (((~(((batl)&BAT601_BSM)<<17))&(va)&BAT601_BLPI)==((batu)&BAT601_BLPI)) #define BAT601_VALID_P(batl) \ ((batl) & BAT601_V) #ifdef _KERNEL #ifndef _LOCORE void oea_batinit(paddr_t, ...); void oea_iobat_add(paddr_t, register_t); void oea_iobat_remove(paddr_t); extern struct bat battable[]; #endif #endif #endif /* _POWERPC_OEA_BAT_H_ */ gxemul-0.6.1/src/include/thirdparty/mk48txxreg.h000644 001750 001750 00000011557 13402411502 022040 0ustar00debugdebug000000 000000 /* $NetBSD: mk48txxreg.h,v 1.7 2003/11/01 22:41:42 tsutsui Exp $ */ #ifndef MK48TXXREG_H #define MK48TXXREG_H /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Paul Kranenburg. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Mostek MK48Txx clocks. * * The MK48T02 has 2KB of non-volatile memory. The time-of-day clock * registers start at offset 0x7f8. * * The MK48T08 and MK48T18 have 8KB of non-volatile memory * * The MK48T59 also has 8KB of non-volatile memory but in addition it * has a battery low detection bit and a power supply wakeup alarm for * power management. It's at offset 0x1ff0 in the NVRAM. */ /* * Mostek MK48TXX register definitions */ /* * The first bank of eight registers at offset (nvramsz - 16) is * available only on more recent (which??) MK48Txx models. */ #define MK48TXX_IFLAGS 0 /* flags */ /* 1 unused on MK48T59 */ #define MK48TXX_IASEC 2 /* alarm seconds (0..59; BCD) */ #define MK48TXX_IAMIN 3 /* alarm minutes (0..59; BCD) */ #define MK48TXX_IAHOUR 4 /* alarm hour (0..23; BCD) */ #define MK48TXX_IADAY 5 /* alarm day (1..31; BCD) */ #define MK48TXX_IINTR 6 /* interrupts */ #define MK48TXX_IWDOG 7 /* watchdog */ #define MK48TXX_ICSR 8 /* control register */ #define MK48TXX_ISEC 9 /* seconds (0..59; BCD) */ #define MK48TXX_IMIN 10 /* minutes (0..59; BCD) */ #define MK48TXX_IHOUR 11 /* hour (0..23; BCD) */ #define MK48TXX_IWDAY 12 /* weekday (1..7) */ #define MK48TXX_IDAY 13 /* day in month (1..31; BCD) */ #define MK48TXX_IMON 14 /* month (1..12; BCD) */ #define MK48TXX_IYEAR 15 /* year (0..99; BCD) */ /* Bits in the flags register */ #define MK48TXX_FLAGS_WDF 0x80 /* watchdog flag */ #define MK48TXX_FLAGS_ALARM 0x40 /* alarm flag */ #define MK48TXX_FLAGS_BATTLOW 0x10 /* battery low */ /* Bits in the interrupt register */ #define MK48TXX_INTR_AFE 0x80 /* alarm flag enable */ #define MK48TXX_INTR_ABE 0x20 /* alarm in battery backup enable */ /* Bits in the watchdog register */ #define MK48TXX_WDOG_WDS 0x80 /* watchdog steering */ #define MK48TXX_WDOG_BMB_MASK 0x7c /* watchdog multiplier bits */ #define MK48TXX_WDOG_BMB_SHIFT 2 #define MK48TXX_WDOG_RES_MASK 0x03 /* watchdog resolution bits */ #define MK48TXX_WDOG_RES_1_16S 0x00 /* 1/16 seconds */ #define MK48TXX_WDOG_RES_1_4S 0x01 /* 1/4 seconds */ #define MK48TXX_WDOG_RES_1S 0x02 /* 1 second */ #define MK48TXX_WDOG_RES_4S 0x03 /* 4 seconds */ /* Bits in the control register */ #define MK48TXX_CSR_WRITE 0x80 /* want to write */ #define MK48TXX_CSR_READ 0x40 /* want to read (freeze clock) */ /* Bit in the weekday register */ #define MK48TXX_WDAY_FT 0x40 /* freq test: toggle sec[0] at 512Hz */ /* next two are on MK48T59 only */ #define MK48TXX_WDAY_CEB 0x20 /* century enable */ #define MK48TXX_WDAY_CB 0x10 /* century bit */ /* Bit in the seconds register */ #define MK48TXX_SEC_STOP 0x80 /* stop the oscillator */ #define MK48T02_CLKSZ 2048 #define MK48T02_CLKOFF 0x7f0 #define MK48T08_CLKSZ 8192 #define MK48T08_CLKOFF 0x1ff0 #define MK48T18_CLKSZ 8192 #define MK48T18_CLKOFF 0x1ff0 #define MK48T59_CLKSZ 8192 #define MK48T59_CLKOFF 0x1ff0 #endif /* MK48TXXREG_H */ gxemul-0.6.1/src/include/thirdparty/exec_aout.h000644 001750 001750 00000016273 13402411502 021767 0ustar00debugdebug000000 000000 /* gxemul: $Id: exec_aout.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ #ifndef __EXEC_AOUT_H #define __EXEC_AOUT_H /* $OpenBSD: exec_aout.h,v 1.9 1998/04/25 06:28:14 niklas Exp $ */ /* $NetBSD: exec_aout.h,v 1.15 1996/05/18 17:20:54 christos Exp $ */ /* * Copyright (c) 1993, 1994 Christopher G. Demetriou * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Christopher G. Demetriou. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef N_PAGSIZ #define N_PAGSIZ(ex) (__LDPGSZ) #endif /* * Header prepended to each a.out file. * only manipulate the a_midmag field via the * N_SETMAGIC/N_GET{MAGIC,MID,FLAG} macros below. */ struct exec { uint32_t a_midmag; /* htonl(flags<<26|mid<<16|magic) */ uint32_t a_text; /* text segment size */ uint32_t a_data; /* initialized data size */ uint32_t a_bss; /* uninitialized data size */ uint32_t a_syms; /* symbol table size */ uint32_t a_entry; /* entry point */ uint32_t a_trsize; /* text relocation size */ uint32_t a_drsize; /* data relocation size */ }; /* a_magic */ #define OMAGIC 0407 /* old impure format */ #define NMAGIC 0410 /* read-only text */ #define ZMAGIC 0413 /* demand load format */ #define QMAGIC 0314 /* "compact" demand load format; deprecated */ /* * a_mid - keep sorted in numerical order for sanity's sake * ensure that: 0 < mid < 0x3ff */ #define MID_ZERO 0 /* unknown - implementation dependent */ #define MID_SUN010 1 /* sun 68010/68020 binary */ #define MID_SUN020 2 /* sun 68020-only binary */ #define MID_PC386 100 /* 386 PC binary. (so quoth BFD) */ #define MID_ROMPAOS 104 /* old IBM RT */ #define MID_I386 134 /* i386 BSD binary */ #define MID_M68K 135 /* m68k BSD binary with 8K page sizes */ #define MID_M68K4K 136 /* DO NOT USE: m68k BSD binary with 4K page sizes */ #define MID_NS32532 137 /* ns32532 */ #define MID_SPARC 138 /* sparc */ #define MID_PMAX 139 /* pmax */ #define MID_VAX 140 /* vax */ #define MID_ALPHA 141 /* Alpha BSD binary */ #define MID_MIPS 142 /* big-endian MIPS */ #define MID_ARM6 143 /* ARM6 */ #define MID_ROMP 149 /* IBM RT */ #define MID_M88K 151 /* m88k BSD binary */ #define MID_HP200 200 /* hp200 (68010) BSD binary */ #define MID_HP300 300 /* hp300 (68020+68881) BSD binary */ #define MID_HPUX 0x20C /* hp200/300 HP-UX binary */ #define MID_HPUX800 0x20B /* hp800 HP-UX binary */ /* * a_flags */ #define EX_DYNAMIC 0x20 #define EX_PIC 0x10 #define EX_DPMASK 0x30 /* * Interpretation of the (a_flags & EX_DPMASK) bits: * * 00 traditional executable or object file * 01 object file contains PIC code (set by `as -k') * 10 dynamic executable * 11 position independent executable image * (eg. a shared library) * */ /* * The a.out structure's a_midmag field is a network-byteorder encoding * of this int * FFFFFFmmmmmmmmmmMMMMMMMMMMMMMMMM * Where `F' is 6 bits of flag like EX_DYNAMIC, * `m' is 10 bits of machine-id like MID_I386, and * `M' is 16 bits worth of magic number, ie. ZMAGIC. * The macros below will set/get the needed fields. */ #define N_GETMAGIC(ex) \ ( (((ex).a_midmag)&0xffff0000) ? (ntohl(((ex).a_midmag))&0xffff) : ((ex).a_midmag)) #define N_GETMAGIC2(ex) \ ( (((ex).a_midmag)&0xffff0000) ? (ntohl(((ex).a_midmag))&0xffff) : \ (((ex).a_midmag) | 0x10000) ) #define N_GETMID(ex) \ ( (((ex).a_midmag)&0xffff0000) ? ((ntohl(((ex).a_midmag))>>16)&0x03ff) : MID_ZERO ) #define N_GETFLAG(ex) \ ( (((ex).a_midmag)&0xffff0000) ? ((ntohl(((ex).a_midmag))>>26)&0x3f) : 0 ) #define N_SETMAGIC(ex,mag,mid,flag) \ ( (ex).a_midmag = htonl( (((flag)&0x3f)<<26) | (((mid)&0x03ff)<<16) | \ (((mag)&0xffff)) ) ) #define N_ALIGN(ex,x) \ (N_GETMAGIC(ex) == ZMAGIC || N_GETMAGIC(ex) == QMAGIC ? \ ((x) + __LDPGSZ - 1) & ~(__LDPGSZ - 1) : (x)) /* Valid magic number check. */ #define N_BADMAG(ex) \ (N_GETMAGIC(ex) != NMAGIC && N_GETMAGIC(ex) != OMAGIC && \ N_GETMAGIC(ex) != ZMAGIC && N_GETMAGIC(ex) != QMAGIC) /* Address of the bottom of the text segment. */ #define N_TXTADDR(ex) (N_GETMAGIC2(ex) == (ZMAGIC|0x10000) ? 0 : __LDPGSZ) /* Address of the bottom of the data segment. */ #define N_DATADDR(ex) \ (N_GETMAGIC(ex) == OMAGIC ? N_TXTADDR(ex) + (ex).a_text : \ (N_TXTADDR(ex) + (ex).a_text + __LDPGSZ - 1) & ~(__LDPGSZ - 1)) /* Address of the bottom of the bss segment. */ #define N_BSSADDR(ex) \ (N_DATADDR(ex) + (ex).a_data) /* Text segment offset. */ #define N_TXTOFF(ex) \ ( N_GETMAGIC2(ex)==ZMAGIC || N_GETMAGIC2(ex)==(QMAGIC|0x10000) ? \ 0 : (N_GETMAGIC2(ex)==(ZMAGIC|0x10000) ? __LDPGSZ : \ sizeof(struct exec)) ) /* Data segment offset. */ #define N_DATOFF(ex) \ N_ALIGN(ex, N_TXTOFF(ex) + (ex).a_text) /* Text relocation table offset. */ #define N_TRELOFF(ex) \ (N_DATOFF(ex) + (ex).a_data) /* Data relocation table offset. */ #define N_DRELOFF(ex) \ (N_TRELOFF(ex) + (ex).a_trsize) /* Symbol table offset. */ #define N_SYMOFF(ex) \ (N_DRELOFF(ex) + (ex).a_drsize) /* String table offset. */ #define N_STROFF(ex) \ (N_SYMOFF(ex) + (ex).a_syms) #ifdef _KERNEL /* the "a.out" format's entry in the exec switch */ int exec_aout_makecmds __P((struct proc *, struct exec_package *)); /* functions which prepare various a.out executable types */ /* * MI portion */ int exec_aout_prep_zmagic __P((struct proc *, struct exec_package *)); int exec_aout_prep_nmagic __P((struct proc *, struct exec_package *)); int exec_aout_prep_omagic __P((struct proc *, struct exec_package *)); /* For compatibility modules */ int exec_aout_prep_oldzmagic __P((struct proc *, struct exec_package *)); int exec_aout_prep_oldnmagic __P((struct proc *, struct exec_package *)); int exec_aout_prep_oldomagic __P((struct proc *, struct exec_package *)); /* * MD portion */ int cpu_exec_aout_makecmds __P((struct proc *, struct exec_package *)); #endif /* _KERNEL */ #endif /* __EXEC_AOUT_H */ gxemul-0.6.1/src/include/thirdparty/rtl81x9reg.h000644 001750 001750 00000070776 13402411502 021754 0ustar00debugdebug000000 000000 /* $OpenBSD: rtl81x9reg.h,v 1.36 2006/12/12 10:24:38 reyk Exp $ */ #ifndef RTL81X9REG_H #define RTL81X9REG_H /* * Copyright (c) 1997, 1998 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/pci/if_rlreg.h,v 1.14 1999/10/21 19:42:03 wpaul Exp $ */ /* * RealTek 8129/8139 register offsets */ #define RL_IDR0 0x0000 /* ID register 0 (station addr) */ #define RL_IDR1 0x0001 /* Must use 32-bit accesses (?) */ #define RL_IDR2 0x0002 #define RL_IDR3 0x0003 #define RL_IDR4 0x0004 #define RL_IDR5 0x0005 /* 0006-0007 reserved */ #define RL_MAR0 0x0008 /* Multicast hash table */ #define RL_MAR1 0x0009 #define RL_MAR2 0x000A #define RL_MAR3 0x000B #define RL_MAR4 0x000C #define RL_MAR5 0x000D #define RL_MAR6 0x000E #define RL_MAR7 0x000F #define RL_TXSTAT0 0x0010 /* status of TX descriptor 0 */ #define RL_TXSTAT1 0x0014 /* status of TX descriptor 1 */ #define RL_TXSTAT2 0x0018 /* status of TX descriptor 2 */ #define RL_TXSTAT3 0x001C /* status of TX descriptor 3 */ #define RL_TXADDR0 0x0020 /* address of TX descriptor 0 */ #define RL_TXADDR1 0x0024 /* address of TX descriptor 1 */ #define RL_TXADDR2 0x0028 /* address of TX descriptor 2 */ #define RL_TXADDR3 0x002C /* address of TX descriptor 3 */ #define RL_RXADDR 0x0030 /* RX ring start address */ #define RL_RX_EARLY_BYTES 0x0034 /* RX early byte count */ #define RL_RX_EARLY_STAT 0x0036 /* RX early status */ #define RL_COMMAND 0x0037 /* command register */ #define RL_CURRXADDR 0x0038 /* current address of packet read */ #define RL_CURRXBUF 0x003A /* current RX buffer address */ #define RL_IMR 0x003C /* interrupt mask register */ #define RL_ISR 0x003E /* interrupt status register */ #define RL_TXCFG 0x0040 /* transmit config */ #define RL_RXCFG 0x0044 /* receive config */ #define RL_TIMERCNT 0x0048 /* timer count register */ #define RL_MISSEDPKT 0x004C /* missed packet counter */ #define RL_EECMD 0x0050 /* EEPROM command register */ #define RL_CFG0 0x0051 /* config register #0 */ #define RL_CFG1 0x0052 /* config register #1 */ /* 0053-0057 reserved */ #define RL_MEDIASTAT 0x0058 /* media status register (8139) */ /* 0059-005A reserved */ #define RL_MII 0x005A /* 8129 chip only */ #define RL_HALTCLK 0x005B #define RL_MULTIINTR 0x005C /* multiple interrupt */ #define RL_PCIREV 0x005E /* PCI revision value */ /* 005F reserved */ #define RL_TXSTAT_ALL 0x0060 /* TX status of all descriptors */ /* Direct PHY access registers only available on 8139 */ #define RL_BMCR 0x0062 /* PHY basic mode control */ #define RL_BMSR 0x0064 /* PHY basic mode status */ #define RL_ANAR 0x0066 /* PHY autoneg advert */ #define RL_LPAR 0x0068 /* PHY link partner ability */ #define RL_ANER 0x006A /* PHY autoneg expansion */ #define RL_DISCCNT 0x006C /* disconnect counter */ #define RL_FALSECAR 0x006E /* false carrier counter */ #define RL_NWAYTST 0x0070 /* NWAY test register */ #define RL_RX_ER 0x0072 /* RX_ER counter */ #define RL_CSCFG 0x0074 /* CS configuration register */ /* * When operating in special C+ mode, some of the registers in an * 8139C+ chip have different definitions. These are also used for * the 8169 gigE chip. */ #define RL_DUMPSTATS_LO 0x0010 /* counter dump command register */ #define RL_DUMPSTATS_HI 0x0014 /* counter dump command register */ #define RL_TXLIST_ADDR_LO 0x0020 /* 64 bits, 256 byte alignment */ #define RL_TXLIST_ADDR_HI 0x0024 /* 64 bits, 256 byte alignment */ #define RL_TXLIST_ADDR_HPRIO_LO 0x0028 /* 64 bits, 256 byte aligned */ #define RL_TXLIST_ADDR_HPRIO_HI 0x002C /* 64 bits, 256 byte aligned */ #define RL_CFG2 0x0053 #define RL_TIMERINT 0x0054 /* interrupt on timer expire */ #define RL_TXSTART 0x00D9 /* 8 bits */ #define RL_CPLUS_CMD 0x00E0 /* 16 bits */ #define RL_RXLIST_ADDR_LO 0x00E4 /* 64 bits, 256 byte alignment */ #define RL_RXLIST_ADDR_HI 0x00E8 /* 64 bits, 256 byte alignment */ #define RL_EARLY_TX_THRESH 0x00EC /* 8 bits */ /* * Registers specific to the 8169 gigE chip */ #define RL_TIMERINT_8169 0x0058 /* different offset than 8139 */ #define RL_PHYAR 0x0060 #define RL_TBICSR 0x0064 #define RL_TBI_ANAR 0x0068 #define RL_TBI_LPAR 0x006A #define RL_GMEDIASTAT 0x006C /* 8 bits */ #define RL_MAXRXPKTLEN 0x00DA /* 16 bits, chip multiplies by 8 */ #define RL_GTXSTART 0x0038 /* 16 bits */ /* * TX config register bits */ #define RL_TXCFG_CLRABRT 0x00000001 /* retransmit aborted pkt */ #define RL_TXCFG_MAXDMA 0x00000700 /* max DMA burst size */ #define RL_TXCFG_CRCAPPEND 0x00010000 /* CRC append (0 = yes) */ #define RL_TXCFG_LOOPBKTST 0x00060000 /* loopback test */ #define RL_TXCFG_IFG2 0x00080000 /* 8169 only */ #define RL_TXCFG_IFG 0x03000000 /* interframe gap */ #define RL_TXCFG_HWREV 0x7C800000 #define RL_LOOPTEST_OFF 0x00000000 #define RL_LOOPTEST_ON 0x00020000 #define RL_LOOPTEST_ON_CPLUS 0x00060000 /* Known revision codes. */ #define RL_HWREV_8169 0x00000000 #define RL_HWREV_8110S 0x00800000 #define RL_HWREV_8169S 0x04000000 #define RL_HWREV_8169_8110SB 0x10000000 #define RL_HWREV_8169_8110SC 0x18000000 #define RL_HWREV_8168_SPIN1 0x30000000 #define RL_HWREV_8100E_SPIN1 0x30800000 #define RL_HWREV_8101E 0x34000000 #define RL_HWREV_8168_SPIN2 0x38000000 #define RL_HWREV_8100E_SPIN2 0x38800000 #define RL_HWREV_8139 0x60000000 #define RL_HWREV_8139A 0x70000000 #define RL_HWREV_8139AG 0x70800000 #define RL_HWREV_8139B 0x78000000 #define RL_HWREV_8130 0x7C000000 #define RL_HWREV_8139C 0x74000000 #define RL_HWREV_8139D 0x74400000 #define RL_HWREV_8139CPLUS 0x74800000 #define RL_HWREV_8101 0x74c00000 #define RL_HWREV_8100 0x78800000 #define RL_TXDMA_16BYTES 0x00000000 #define RL_TXDMA_32BYTES 0x00000100 #define RL_TXDMA_64BYTES 0x00000200 #define RL_TXDMA_128BYTES 0x00000300 #define RL_TXDMA_256BYTES 0x00000400 #define RL_TXDMA_512BYTES 0x00000500 #define RL_TXDMA_1024BYTES 0x00000600 #define RL_TXDMA_2048BYTES 0x00000700 /* * Transmit descriptor status register bits. */ #define RL_TXSTAT_LENMASK 0x00001FFF #define RL_TXSTAT_OWN 0x00002000 #define RL_TXSTAT_TX_UNDERRUN 0x00004000 #define RL_TXSTAT_TX_OK 0x00008000 #define RL_TXSTAT_EARLY_THRESH 0x003F0000 #define RL_TXSTAT_COLLCNT 0x0F000000 #define RL_TXSTAT_CARR_HBEAT 0x10000000 #define RL_TXSTAT_OUTOFWIN 0x20000000 #define RL_TXSTAT_TXABRT 0x40000000 #define RL_TXSTAT_CARRLOSS 0x80000000 /* * Interrupt status register bits. */ #define RL_ISR_RX_OK 0x0001 #define RL_ISR_RX_ERR 0x0002 #define RL_ISR_TX_OK 0x0004 #define RL_ISR_TX_ERR 0x0008 #define RL_ISR_RX_OVERRUN 0x0010 #define RL_ISR_PKT_UNDERRUN 0x0020 #define RL_ISR_LINKCHG 0x0020 /* 8169 only */ #define RL_ISR_FIFO_OFLOW 0x0040 /* 8139 only */ #define RL_ISR_TX_DESC_UNAVAIL 0x0080 /* C+ only */ #define RL_ISR_SWI 0x0100 /* C+ only */ #define RL_ISR_CABLE_LEN_CHGD 0x2000 #define RL_ISR_PCS_TIMEOUT 0x4000 /* 8129 only */ #define RL_ISR_TIMEOUT_EXPIRED 0x4000 #define RL_ISR_SYSTEM_ERR 0x8000 #define RL_INTRS \ (RL_ISR_TX_OK|RL_ISR_RX_OK|RL_ISR_RX_ERR|RL_ISR_TX_ERR| \ RL_ISR_RX_OVERRUN|RL_ISR_PKT_UNDERRUN|RL_ISR_FIFO_OFLOW| \ RL_ISR_PCS_TIMEOUT|RL_ISR_SYSTEM_ERR) #define RL_INTRS_CPLUS \ (RL_ISR_RX_OK|RL_ISR_RX_ERR|RL_ISR_TX_ERR| \ RL_ISR_RX_OVERRUN|RL_ISR_PKT_UNDERRUN|RL_ISR_FIFO_OFLOW| \ RL_ISR_PCS_TIMEOUT|RL_ISR_SYSTEM_ERR|RL_ISR_TIMEOUT_EXPIRED) /* * Media status register. (8139 only) */ #define RL_MEDIASTAT_RXPAUSE 0x01 #define RL_MEDIASTAT_TXPAUSE 0x02 #define RL_MEDIASTAT_LINK 0x04 #define RL_MEDIASTAT_SPEED10 0x08 #define RL_MEDIASTAT_RXFLOWCTL 0x40 /* duplex mode */ #define RL_MEDIASTAT_TXFLOWCTL 0x80 /* duplex mode */ /* * Receive config register. */ #define RL_RXCFG_RX_ALLPHYS 0x00000001 /* accept all nodes */ #define RL_RXCFG_RX_INDIV 0x00000002 /* match filter */ #define RL_RXCFG_RX_MULTI 0x00000004 /* accept all multicast */ #define RL_RXCFG_RX_BROAD 0x00000008 /* accept all broadcast */ #define RL_RXCFG_RX_RUNT 0x00000010 #define RL_RXCFG_RX_ERRPKT 0x00000020 #define RL_RXCFG_WRAP 0x00000080 #define RL_RXCFG_MAXDMA 0x00000700 #define RL_RXCFG_BURSZ 0x00001800 #define RL_RXCFG_FIFOTHRESH 0x0000E000 #define RL_RXCFG_EARLYTHRESH 0x07000000 #define RL_RXDMA_16BYTES 0x00000000 #define RL_RXDMA_32BYTES 0x00000100 #define RL_RXDMA_64BYTES 0x00000200 #define RL_RXDMA_128BYTES 0x00000300 #define RL_RXDMA_256BYTES 0x00000400 #define RL_RXDMA_512BYTES 0x00000500 #define RL_RXDMA_1024BYTES 0x00000600 #define RL_RXDMA_UNLIMITED 0x00000700 #define RL_RXBUF_8 0x00000000 #define RL_RXBUF_16 0x00000800 #define RL_RXBUF_32 0x00001000 #define RL_RXBUF_64 0x00001800 #define RL_RXFIFO_16BYTES 0x00000000 #define RL_RXFIFO_32BYTES 0x00002000 #define RL_RXFIFO_64BYTES 0x00004000 #define RL_RXFIFO_128BYTES 0x00006000 #define RL_RXFIFO_256BYTES 0x00008000 #define RL_RXFIFO_512BYTES 0x0000A000 #define RL_RXFIFO_1024BYTES 0x0000C000 #define RL_RXFIFO_NOTHRESH 0x0000E000 /* * Bits in RX status header (included with RX'ed packet * in ring buffer). */ #define RL_RXSTAT_RXOK 0x00000001 #define RL_RXSTAT_ALIGNERR 0x00000002 #define RL_RXSTAT_CRCERR 0x00000004 #define RL_RXSTAT_GIANT 0x00000008 #define RL_RXSTAT_RUNT 0x00000010 #define RL_RXSTAT_BADSYM 0x00000020 #define RL_RXSTAT_BROAD 0x00002000 #define RL_RXSTAT_INDIV 0x00004000 #define RL_RXSTAT_MULTI 0x00008000 #define RL_RXSTAT_LENMASK 0xFFFF0000 #define RL_RXSTAT_UNFINISHED 0xFFF0 /* DMA still in progress */ /* * Command register. */ #define RL_CMD_EMPTY_RXBUF 0x0001 #define RL_CMD_TX_ENB 0x0004 #define RL_CMD_RX_ENB 0x0008 #define RL_CMD_RESET 0x0010 /* * EEPROM control register */ #define RL_EE_DATAOUT 0x01 /* Data out */ #define RL_EE_DATAIN 0x02 /* Data in */ #define RL_EE_CLK 0x04 /* clock */ #define RL_EE_SEL 0x08 /* chip select */ #define RL_EE_MODE (0x40|0x80) #define RL_EEMODE_OFF 0x00 #define RL_EEMODE_AUTOLOAD 0x40 #define RL_EEMODE_PROGRAM 0x80 #define RL_EEMODE_WRITECFG (0x80|0x40) /* 9346/9356 EEPROM commands */ #define RL_9346_WRITE 0x5 #define RL_9346_READ 0x6 #define RL_9346_ERASE 0x7 #define RL_9346_EWEN 0x4 #define RL_9346_EWEN_ADDR 0x30 #define RL_9456_EWDS 0x4 #define RL_9346_EWDS_ADDR 0x00 #define RL_EECMD_WRITE 0x5 /* 0101b */ #define RL_EECMD_READ 0x6 /* 0110b */ #define RL_EECMD_ERASE 0x7 /* 0111b */ #define RL_EECMD_LEN 4 #define RL_EEADDR_LEN0 6 /* 9346 */ #define RL_EEADDR_LEN1 8 /* 9356 */ #define RL_EECMD_READ_6BIT 0x180 /* XXX */ #define RL_EECMD_READ_8BIT 0x600 /* EECMD_READ above maybe wrong? */ #define RL_EE_ID 0x00 #define RL_EE_PCI_VID 0x01 #define RL_EE_PCI_DID 0x02 /* Location of station address inside EEPROM */ #define RL_EE_EADDR 0x07 /* * MII register (8129 only) */ #define RL_MII_CLK 0x01 #define RL_MII_DATAIN 0x02 #define RL_MII_DATAOUT 0x04 #define RL_MII_DIR 0x80 /* 0 == input, 1 == output */ /* * Config 0 register */ #define RL_CFG0_ROM0 0x01 #define RL_CFG0_ROM1 0x02 #define RL_CFG0_ROM2 0x04 #define RL_CFG0_PL0 0x08 #define RL_CFG0_PL1 0x10 #define RL_CFG0_10MBPS 0x20 /* 10 Mbps internal mode */ #define RL_CFG0_PCS 0x40 #define RL_CFG0_SCR 0x80 /* * Config 1 register */ #define RL_CFG1_PWRDWN 0x01 #define RL_CFG1_SLEEP 0x02 #define RL_CFG1_IOMAP 0x04 #define RL_CFG1_MEMMAP 0x08 #define RL_CFG1_RSVD 0x10 #define RL_CFG1_DRVLOAD 0x20 #define RL_CFG1_LED0 0x40 #define RL_CFG1_FULLDUPLEX 0x40 /* 8129 only */ #define RL_CFG1_LED1 0x80 /* * 8139C+ register definitions */ /* RL_DUMPSTATS_LO register */ #define RL_DUMPSTATS_START 0x00000008 /* Transmit start register */ #define RL_TXSTART_SWI 0x01 /* generate TX interrupt */ #define RL_TXSTART_START 0x40 /* start normal queue transmit */ #define RL_TXSTART_HPRIO_START 0x80 /* start hi prio queue transmit */ /* * Config 2 register, 8139C+/8169/8169S/8110S only */ #define RL_CFG2_BUSFREQ 0x07 #define RL_CFG2_BUSWIDTH 0x08 #define RL_CFG2_AUXPWRSTS 0x10 #define RL_BUSFREQ_33MHZ 0x00 #define RL_BUSFREQ_66MHZ 0x01 #define RL_BUSWIDTH_32BITS 0x00 #define RL_BUSWIDTH_64BITS 0x08 /* C+ mode command register */ #define RL_CPLUSCMD_TXENB 0x0001 /* enable C+ transmit mode */ #define RL_CPLUSCMD_RXENB 0x0002 /* enable C+ receive mode */ #define RL_CPLUSCMD_PCI_MRW 0x0008 /* enable PCI multi-read/write */ #define RL_CPLUSCMD_PCI_DAC 0x0010 /* PCI dual-address cycle only */ #define RL_CPLUSCMD_RXCSUM_ENB 0x0020 /* enable RX checksum offload */ #define RL_CPLUSCMD_VLANSTRIP 0x0040 /* enable VLAN tag stripping */ /* C+ early transmit threshold */ #define RL_EARLYTXTHRESH_CNT 0x003F /* byte count times 8 */ /* * Gigabit PHY access register (8169 only) */ #define RL_PHYAR_PHYDATA 0x0000FFFF #define RL_PHYAR_PHYREG 0x001F0000 #define RL_PHYAR_BUSY 0x80000000 /* * Gigabit media status (8169 only) */ #define RL_GMEDIASTAT_FDX 0x01 /* full duplex */ #define RL_GMEDIASTAT_LINK 0x02 /* link up */ #define RL_GMEDIASTAT_10MBPS 0x04 /* 10mps link */ #define RL_GMEDIASTAT_100MBPS 0x08 /* 100mbps link */ #define RL_GMEDIASTAT_1000MBPS 0x10 /* gigE link */ #define RL_GMEDIASTAT_RXFLOW 0x20 /* RX flow control on */ #define RL_GMEDIASTAT_TXFLOW 0x40 /* TX flow control on */ #define RL_GMEDIASTAT_TBI 0x80 /* TBI enabled */ /* * The RealTek doesn't use a fragment-based descriptor mechanism. * Instead, there are only four register sets, each or which represents * one 'descriptor.' Basically, each TX descriptor is just a contiguous * packet buffer (32-bit aligned!) and we place the buffer addresses in * the registers so the chip knows where they are. * * We can sort of kludge together the same kind of buffer management * used in previous drivers, but we have to do buffer copies almost all * the time, so it doesn't really buy us much. * * For reception, there's just one large buffer where the chip stores * all received packets. */ #define RL_RX_BUF_SZ RL_RXBUF_64 #define RL_RXBUFLEN (1 << ((RL_RX_BUF_SZ >> 11) + 13)) #define RL_TX_LIST_CNT 4 #define RL_MIN_FRAMELEN 60 #define RL_TXTHRESH(x) ((x) << 11) #define RL_TX_THRESH_INIT 96 #define RL_RX_FIFOTHRESH RL_RXFIFO_256BYTES #define RL_RX_MAXDMA RL_RXDMA_UNLIMITED #define RL_TX_MAXDMA RL_TXDMA_2048BYTES #define RL_RXCFG_CONFIG (RL_RX_FIFOTHRESH|RL_RX_MAXDMA|RL_RX_BUF_SZ) #define RL_TXCFG_CONFIG (RL_TXCFG_IFG|RL_TX_MAXDMA) #if 0 struct rl_chain_data { u_int16_t cur_rx; caddr_t rl_rx_buf; caddr_t rl_rx_buf_ptr; bus_addr_t rl_rx_buf_pa; struct mbuf *rl_tx_chain[RL_TX_LIST_CNT]; bus_dmamap_t rl_tx_dmamap[RL_TX_LIST_CNT]; u_int8_t last_tx; u_int8_t cur_tx; }; #endif /* * The 8139C+ and 8160 gigE chips support descriptor-based TX * and RX. In fact, they even support TCP large send. Descriptors * must be allocated in contiguous blocks that are aligned on a * 256-byte boundary. The rings can hold a maximum of 64 descriptors. */ /* * RX/TX descriptor definition. When large send mode is enabled, the * lower 11 bits of the TX rl_cmd word are used to hold the MSS, and * the checksum offload bits are disabled. The structure layout is * the same for RX and TX descriptors */ struct rl_desc { volatile u_int32_t rl_cmdstat; volatile u_int32_t rl_vlanctl; volatile u_int32_t rl_bufaddr_lo; volatile u_int32_t rl_bufaddr_hi; }; #define RL_TDESC_CMD_FRAGLEN 0x0000FFFF #define RL_TDESC_CMD_TCPCSUM 0x00010000 /* TCP checksum enable */ #define RL_TDESC_CMD_UDPCSUM 0x00020000 /* UDP checksum enable */ #define RL_TDESC_CMD_IPCSUM 0x00040000 /* IP header checksum enable */ #define RL_TDESC_CMD_MSSVAL 0x07FF0000 /* Large send MSS value */ #define RL_TDESC_CMD_LGSEND 0x08000000 /* TCP large send enb */ #define RL_TDESC_CMD_EOF 0x10000000 /* end of frame marker */ #define RL_TDESC_CMD_SOF 0x20000000 /* start of frame marker */ #define RL_TDESC_CMD_EOR 0x40000000 /* end of ring marker */ #define RL_TDESC_CMD_OWN 0x80000000 /* chip owns descriptor */ #define RL_TDESC_VLANCTL_TAG 0x00020000 /* Insert VLAN tag */ #define RL_TDESC_VLANCTL_DATA 0x0000FFFF /* TAG data */ /* * Error bits are valid only on the last descriptor of a frame * (i.e. RL_TDESC_CMD_EOF == 1) */ #define RL_TDESC_STAT_COLCNT 0x000F0000 /* collision count */ #define RL_TDESC_STAT_EXCESSCOL 0x00100000 /* excessive collisions */ #define RL_TDESC_STAT_LINKFAIL 0x00200000 /* link faulure */ #define RL_TDESC_STAT_OWINCOL 0x00400000 /* out-of-window collision */ #define RL_TDESC_STAT_TXERRSUM 0x00800000 /* transmit error summary */ #define RL_TDESC_STAT_UNDERRUN 0x02000000 /* TX underrun occured */ #define RL_TDESC_STAT_OWN 0x80000000 /* * RX descriptor cmd/vlan definitions */ #define RL_RDESC_CMD_EOR 0x40000000 #define RL_RDESC_CMD_OWN 0x80000000 #define RL_RDESC_CMD_BUFLEN 0x00001FFF #define RL_RDESC_STAT_OWN 0x80000000 #define RL_RDESC_STAT_EOR 0x40000000 #define RL_RDESC_STAT_SOF 0x20000000 #define RL_RDESC_STAT_EOF 0x10000000 #define RL_RDESC_STAT_FRALIGN 0x08000000 /* frame alignment error */ #define RL_RDESC_STAT_MCAST 0x04000000 /* multicast pkt received */ #define RL_RDESC_STAT_UCAST 0x02000000 /* unicast pkt received */ #define RL_RDESC_STAT_BCAST 0x01000000 /* broadcast pkt received */ #define RL_RDESC_STAT_BUFOFLOW 0x00800000 /* out of buffer space */ #define RL_RDESC_STAT_FIFOOFLOW 0x00400000 /* FIFO overrun */ #define RL_RDESC_STAT_GIANT 0x00200000 /* pkt > 4096 bytes */ #define RL_RDESC_STAT_RXERRSUM 0x00100000 /* RX error summary */ #define RL_RDESC_STAT_RUNT 0x00080000 /* runt packet received */ #define RL_RDESC_STAT_CRCERR 0x00040000 /* CRC error */ #define RL_RDESC_STAT_PROTOID 0x00030000 /* Protocol type */ #define RL_RDESC_STAT_IPSUMBAD 0x00008000 /* IP header checksum bad */ #define RL_RDESC_STAT_UDPSUMBAD 0x00004000 /* UDP checksum bad */ #define RL_RDESC_STAT_TCPSUMBAD 0x00002000 /* TCP checksum bad */ #define RL_RDESC_STAT_FRAGLEN 0x00001FFF /* RX'ed frame/frag len */ #define RL_RDESC_STAT_GFRAGLEN 0x00003FFF /* RX'ed frame/frag len */ #define RL_RDESC_STAT_ERRS (RL_RDESC_STAT_GIANT|RL_RDESC_STAT_RUNT| \ RL_RDESC_STAT_CRCERR) #define RL_RDESC_VLANCTL_TAG 0x00010000 /* VLAN tag available (rl_vlandata valid)*/ #define RL_RDESC_VLANCTL_DATA 0x0000FFFF /* TAG data */ #define RL_PROTOID_NONIP 0x00000000 #define RL_PROTOID_TCPIP 0x00010000 #define RL_PROTOID_UDPIP 0x00020000 #define RL_PROTOID_IP 0x00030000 #define RL_TCPPKT(x) (((x) & RL_RDESC_STAT_PROTOID) == \ RL_PROTOID_TCPIP) #define RL_UDPPKT(x) (((x) & RL_RDESC_STAT_PROTOID) == \ RL_PROTOID_UDPIP) /* * Statistics counter structure (8139C+ and 8169 only) */ struct rl_stats { u_int32_t rl_tx_pkts_lo; u_int32_t rl_tx_pkts_hi; u_int32_t rl_tx_errs_lo; u_int32_t rl_tx_errs_hi; u_int32_t rl_tx_errs; u_int16_t rl_missed_pkts; u_int16_t rl_rx_framealign_errs; u_int32_t rl_tx_onecoll; u_int32_t rl_tx_multicolls; u_int32_t rl_rx_ucasts_hi; u_int32_t rl_rx_ucasts_lo; u_int32_t rl_rx_bcasts_lo; u_int32_t rl_rx_bcasts_hi; u_int32_t rl_rx_mcasts; u_int16_t rl_tx_aborts; u_int16_t rl_rx_underruns; }; #define RL_RX_DESC_CNT 64 #define RL_TX_DESC_CNT_8139 64 #define RL_TX_DESC_CNT_8169 1024 #define RL_TX_QLEN 64 #define RL_NTXDESC_RSVD 4 #define RL_RX_LIST_SZ (RL_RX_DESC_CNT * sizeof(struct rl_desc)) #define RL_RING_ALIGN 256 #define RL_PKTSZ(x) ((x)/* >> 3*/) #ifdef __STRICT_ALIGNMENT #define RE_ETHER_ALIGN 2 #define RE_RX_DESC_BUFLEN (MCLBYTES - RE_ETHER_ALIGN) #else #define RE_ETHER_ALIGN 0 #define RE_RX_DESC_BUFLEN MCLBYTES #endif #define RL_TX_DESC_CNT(sc) \ ((sc)->rl_ldata.rl_tx_desc_cnt) #define RL_TX_LIST_SZ(sc) \ (RL_TX_DESC_CNT(sc) * sizeof(struct rl_desc)) #define RL_NEXT_TX_DESC(sc, x) \ (((x) + 1) % RL_TX_DESC_CNT(sc)) #define RL_NEXT_RX_DESC(sc, x) \ (((x) + 1) % RL_RX_DESC_CNT) #define RL_NEXT_TXQ(sc, x) \ (((x) + 1) % RL_TX_QLEN) #define RL_TXDESCSYNC(sc, idx, ops) \ bus_dmamap_sync((sc)->sc_dmat, \ (sc)->rl_ldata.rl_tx_list_map, \ sizeof(struct rl_desc) * (idx), \ sizeof(struct rl_desc), \ (ops)) #define RL_RXDESCSYNC(sc, idx, ops) \ bus_dmamap_sync((sc)->sc_dmat, \ (sc)->rl_ldata.rl_rx_list_map, \ sizeof(struct rl_desc) * (idx), \ sizeof(struct rl_desc), \ (ops)) #define RL_ADDR_LO(y) ((u_int64_t) (y) & 0xFFFFFFFF) #define RL_ADDR_HI(y) ((u_int64_t) (y) >> 32) /* see comment in dev/ic/re.c */ #define RL_JUMBO_FRAMELEN 7440 #define RL_JUMBO_MTU (RL_JUMBO_FRAMELEN-ETHER_HDR_LEN-ETHER_CRC_LEN) #define MAX_NUM_MULTICAST_ADDRESSES 128 #define RL_INC(x) (x = (x + 1) % RL_TX_LIST_CNT) #define RL_CUR_TXADDR(x) ((x->rl_cdata.cur_tx * 4) + RL_TXADDR0) #define RL_CUR_TXSTAT(x) ((x->rl_cdata.cur_tx * 4) + RL_TXSTAT0) #define RL_CUR_TXMBUF(x) (x->rl_cdata.rl_tx_chain[x->rl_cdata.cur_tx]) #define RL_CUR_TXMAP(x) (x->rl_cdata.rl_tx_dmamap[x->rl_cdata.cur_tx]) #define RL_LAST_TXADDR(x) ((x->rl_cdata.last_tx * 4) + RL_TXADDR0) #define RL_LAST_TXSTAT(x) ((x->rl_cdata.last_tx * 4) + RL_TXSTAT0) #define RL_LAST_TXMBUF(x) (x->rl_cdata.rl_tx_chain[x->rl_cdata.last_tx]) #define RL_LAST_TXMAP(x) (x->rl_cdata.rl_tx_dmamap[x->rl_cdata.last_tx]) struct rl_type { u_int16_t rl_vid; u_int16_t rl_did; }; struct rl_mii_frame { u_int8_t mii_stdelim; u_int8_t mii_opcode; u_int8_t mii_phyaddr; u_int8_t mii_regaddr; u_int8_t mii_turnaround; u_int16_t mii_data; }; /* * MII constants */ #define RL_MII_STARTDELIM 0x01 #define RL_MII_READOP 0x02 #define RL_MII_WRITEOP 0x01 #define RL_MII_TURNAROUND 0x02 #define RL_UNKNOWN 0 #define RL_8129 1 #define RL_8139 2 #define RL_8139CPLUS 3 #define RL_8169 4 #define RL_ISCPLUS(x) ((x)->rl_type == RL_8139CPLUS || \ (x)->rl_type == RL_8169) #if 0 struct rl_rxsoft { struct mbuf *rxs_mbuf; bus_dmamap_t rxs_dmamap; }; struct rl_txq { struct mbuf *txq_mbuf; bus_dmamap_t txq_dmamap; int txq_descidx; int txq_nsegs; }; struct rl_list_data { struct rl_txq rl_txq[RL_TX_QLEN]; int rl_txq_considx; int rl_txq_prodidx; bus_dmamap_t rl_tx_list_map; struct rl_desc *rl_tx_list; int rl_tx_free; /* # of free descriptors */ int rl_tx_nextfree; /* next descriptor to use */ int rl_tx_desc_cnt; /* # of descriptors */ bus_dma_segment_t rl_tx_listseg; int rl_tx_listnseg; struct rl_rxsoft rl_rxsoft[RL_RX_DESC_CNT]; bus_dmamap_t rl_rx_list_map; struct rl_desc *rl_rx_list; int rl_rx_prodidx; bus_dma_segment_t rl_rx_listseg; int rl_rx_listnseg; }; struct rl_softc { struct device sc_dev; /* us, as a device */ void * sc_ih; /* interrupt vectoring */ bus_space_handle_t rl_bhandle; /* bus space handle */ bus_space_tag_t rl_btag; /* bus space tag */ bus_dma_tag_t sc_dmat; bus_dma_segment_t sc_rx_seg; bus_dmamap_t sc_rx_dmamap; struct arpcom sc_arpcom; /* interface info */ struct mii_data sc_mii; /* MII information */ u_int8_t rl_type; int rl_eecmd_read; int rl_eewidth; void *sc_sdhook; /* shutdownhook */ void *sc_pwrhook; int rl_txthresh; int sc_flags; /* misc flags */ struct rl_chain_data rl_cdata; struct timeout sc_tick_tmo; int if_flags; struct rl_list_data rl_ldata; struct mbuf *rl_head; struct mbuf *rl_tail; u_int32_t rl_rxlenmask; int rl_testmode; struct timeout timer_handle; int rl_txstart; int rl_link; }; #endif /* * re(4) hardware ip4csum-tx could be mangled with 28 byte or less IP packets */ #define RL_IP4CSUMTX_MINLEN 28 #define RL_IP4CSUMTX_PADLEN (ETHER_HDR_LEN + RL_IP4CSUMTX_MINLEN) /* * XXX * We are allocating pad DMA buffer after RX DMA descs for now * because RL_TX_LIST_SZ(sc) always occupies whole page but * RL_RX_LIST_SZ is less than PAGE_SIZE so there is some unused region. */ #define RL_RX_DMAMEM_SZ (RL_RX_LIST_SZ + RL_IP4CSUMTX_PADLEN) #define RL_TXPADOFF RL_RX_LIST_SZ #define RL_TXPADDADDR(sc) \ ((sc)->rl_ldata.rl_rx_list_map->dm_segs[0].ds_addr + RL_TXPADOFF) #define RL_ATTACHED 0x00000001 /* attach has succeeded */ #define RL_ENABLED 0x00000002 /* chip is enabled */ #define RL_IS_ENABLED(sc) ((sc)->sc_flags & RL_ENABLED) /* * register space access macros */ #define CSR_WRITE_RAW_4(sc, csr, val) \ bus_space_write_raw_region_4(sc->rl_btag, sc->rl_bhandle, csr, val, 4) #define CSR_WRITE_4(sc, csr, val) \ bus_space_write_4(sc->rl_btag, sc->rl_bhandle, csr, val) #define CSR_WRITE_2(sc, csr, val) \ bus_space_write_2(sc->rl_btag, sc->rl_bhandle, csr, val) #define CSR_WRITE_1(sc, csr, val) \ bus_space_write_1(sc->rl_btag, sc->rl_bhandle, csr, val) #define CSR_READ_4(sc, csr) \ bus_space_read_4(sc->rl_btag, sc->rl_bhandle, csr) #define CSR_READ_2(sc, csr) \ bus_space_read_2(sc->rl_btag, sc->rl_bhandle, csr) #define CSR_READ_1(sc, csr) \ bus_space_read_1(sc->rl_btag, sc->rl_bhandle, csr) #define CSR_SETBIT_1(sc, offset, val) \ CSR_WRITE_1(sc, offset, CSR_READ_1(sc, offset) | (val)) #define CSR_CLRBIT_1(sc, offset, val) \ CSR_WRITE_1(sc, offset, CSR_READ_1(sc, offset) & ~(val)) #define CSR_SETBIT_2(sc, offset, val) \ CSR_WRITE_2(sc, offset, CSR_READ_2(sc, offset) | (val)) #define CSR_CLRBIT_2(sc, offset, val) \ CSR_WRITE_2(sc, offset, CSR_READ_2(sc, offset) & ~(val)) #define CSR_SETBIT_4(sc, offset, val) \ CSR_WRITE_4(sc, offset, CSR_READ_4(sc, offset) | (val)) #define CSR_CLRBIT_4(sc, offset, val) \ CSR_WRITE_4(sc, offset, CSR_READ_4(sc, offset) & ~(val)) #define RL_TIMEOUT 1000 /* * General constants that are fun to know. * * RealTek PCI vendor ID */ #define RT_VENDORID 0x10EC /* * RealTek chip device IDs. */ #define RT_DEVICEID_8129 0x8129 #define RT_DEVICEID_8101E 0x8136 #define RT_DEVICEID_8138 0x8138 #define RT_DEVICEID_8139 0x8139 #define RT_DEVICEID_8169SC 0x8167 #define RT_DEVICEID_8168 0x8168 #define RT_DEVICEID_8169 0x8169 #define RT_DEVICEID_8100 0x8100 /* * Accton PCI vendor ID */ #define ACCTON_VENDORID 0x1113 /* * Accton MPX 5030/5038 device ID. */ #define ACCTON_DEVICEID_5030 0x1211 /* * Delta Electronics Vendor ID. */ #define DELTA_VENDORID 0x1500 /* * Delta device IDs. */ #define DELTA_DEVICEID_8139 0x1360 /* * Addtron vendor ID. */ #define ADDTRON_VENDORID 0x4033 /* * Addtron device IDs. */ #define ADDTRON_DEVICEID_8139 0x1360 /* D-Link Vendor ID */ #define DLINK_VENDORID 0x1186 /* D-Link device IDs */ #define DLINK_DEVICEID_8139 0x1300 #define DLINK_DEVICEID_8139_2 0x1340 /* Abocom device IDs */ #define ABOCOM_DEVICEID_8139 0xab06 /* * PCI low memory base and low I/O base register, and * other PCI registers. Note: some are only available on * the 3c905B, in particular those that related to power management. */ #define RL_PCI_VENDOR_ID 0x00 #define RL_PCI_DEVICE_ID 0x02 #define RL_PCI_COMMAND 0x04 #define RL_PCI_STATUS 0x06 #define RL_PCI_CLASSCODE 0x09 #define RL_PCI_LATENCY_TIMER 0x0D #define RL_PCI_HEADER_TYPE 0x0E #define RL_PCI_LOIO 0x10 #define RL_PCI_LOMEM 0x14 #define RL_PCI_BIOSROM 0x30 #define RL_PCI_INTLINE 0x3C #define RL_PCI_INTPIN 0x3D #define RL_PCI_MINGNT 0x3E #define RL_PCI_MINLAT 0x0F #define RL_PCI_RESETOPT 0x48 #define RL_PCI_EEPROM_DATA 0x4C #define RL_PCI_CAPID 0x50 /* 8 bits */ #define RL_PCI_NEXTPTR 0x51 /* 8 bits */ #define RL_PCI_PWRMGMTCAP 0x52 /* 16 bits */ #define RL_PCI_PWRMGMTCTRL 0x54 /* 16 bits */ #define RL_PSTATE_MASK 0x0003 #define RL_PSTATE_D0 0x0000 #define RL_PSTATE_D1 0x0002 #define RL_PSTATE_D2 0x0002 #define RL_PSTATE_D3 0x0003 #define RL_PME_EN 0x0010 #define RL_PME_STATUS 0x8000 #if 0 extern int rl_attach(struct rl_softc *); extern int rl_detach(struct rl_softc *); extern int rl_intr(void *); extern void rl_setmulti(struct rl_softc *); #endif #endif /* RTL81X9REG_H */ gxemul-0.6.1/src/include/thirdparty/pxreg.h000644 001750 001750 00000030320 13402411502 021125 0ustar00debugdebug000000 000000 /* $NetBSD: pxreg.h,v 1.8 2000/06/13 13:39:12 ad Exp $ */ #ifndef _PMAX_DEV_PXREG_H_ #define _PMAX_DEV_PXREG_H_ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Andrew Doran. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Definitions for the PixelStamp on Digital's 2D and 3D TurboChannel * graphics accelerators. Stamp command packets take this general format: * * command word * * per-packet context (optional): * line width * xy mask * cliping rectangle min & max * rgb constant * z constant * * per-primitive context (optional): * xy mask * xy mask address * primitive data (vertices, spans info, video) * line width * halfspace equals conditions * rgb flat, or rgb{1,2,3} smooth * z flat, or z{1,2,3} smooth */ /* * These definitions are for the stamp command word, the first in * each packet. This is a 32-bit word on all architectures. */ /* opcode type */ #define STAMP_CMD_POINTS (0x0000) #define STAMP_CMD_LINES (0x0001) #define STAMP_CMD_TRIANGLES (0x0002) #define STAMP_CMD_COPYSPANS (0x0005) #define STAMP_CMD_READSPANS (0x0006) #define STAMP_CMD_WRITESPANS (0x0007) #define STAMP_CMD_VIDEO (0x0008) /* RGB format */ #define STAMP_RGB_NONE (0x0000) #define STAMP_RGB_CONST (0x0010) #define STAMP_RGB_FLAT (0x0020) #define STAMP_RGB_SMOOTH (0x0030) /* Z format */ #define STAMP_Z_NONE (0x0000) #define STAMP_Z_CONST (0x0040) #define STAMP_Z_FLAT (0x0080) #define STAMP_Z_SMOOTH (0x00c0) /* XY mask format */ #define STAMP_XY_NONE (0x0000) #define STAMP_XY_PERPACKET (0x0100) #define STAMP_XY_PERPRIMATIVE (0x0200) /* line width format */ #define STAMP_LW_NONE (0x0000) #define STAMP_LW_PERPACKET (0x0400) #define STAMP_LW_PERPRIMATIVE (0x0800) /* misc. */ #define STAMP_CLIPRECT (0x00080000) #define STAMP_MESH (0x00200000) #define STAMP_AALINE (0x00800000) #define STAMP_HS_EQUALS (0x80000000) /* * These definitions are for the stamp update word, also part of * each packet. */ /* plane */ #define STAMP_PLANE_8X3 (0 << 5) #define STAMP_PLANE_24 (1 << 5) /* when to write enable the stamp */ #define STAMP_WE_SIGN (0x04 << 8) #define STAMP_WE_XYMASK (0x02 << 8) #define STAMP_WE_CLIPRECT (0x01 << 8) #define STAMP_WE_NONE (0x00 << 8) /* update method */ #define STAMP_METHOD_CLEAR (0x60 << 12) #define STAMP_METHOD_AND (0x14 << 12) #define STAMP_METHOD_ANDREV (0x15 << 12) #define STAMP_METHOD_COPY (0x20 << 12) #define STAMP_METHOD_ANDINV (0x16 << 12) #define STAMP_METHOD_NOOP (0x40 << 12) #define STAMP_METHOD_XOR (0x11 << 12) #define STAMP_METHOD_OR (0x0f << 12) #define STAMP_METHOD_NOR (0x17 << 12) #define STAMP_METHOD_EQUIV (0x10 << 12) #define STAMP_METHOD_INV (0x4e << 12) #define STAMP_METHOD_ORREV (0x0e << 12) #define STAMP_METHOD_COPYINV (0x2d << 12) #define STAMP_METHOD_ORINV (0x0d << 12) #define STAMP_METHOD_NAND (0x0c << 12) #define STAMP_METHOD_SET (0x6c << 12) #define STAMP_METHOD_SUM (0x00 << 12) #define STAMP_METHOD_DIFF (0x02 << 12) #define STAMP_METHOD_REVDIFF (0x01 << 12) /* double buffering */ #define STAMP_DB_NONE (0x00 << 28) #define STAMP_DB_01 (0x01 << 28) #define STAMP_DB_12 (0x02 << 28) #define STAMP_DB_02 (0x04 << 28) /* misc */ #define STAMP_UPDATE_ENABLE (1) #define STAMP_SAVE_SIGN (1<<6) #define STAMP_SAVE_ALPHA (1<<7) #define STAMP_SUPERSAMPLE (1<<11) #define STAMP_SPAN (1<<19) #define STAMP_COPYSPAN_ALIGNED (1<<20) #define STAMP_MINMAX (1<<21) #define STAMP_MULT (1<<22) #define STAMP_MULTACC (1<<23) #define STAMP_HALF_BUFF (1<27) #define STAMP_INITIALIZE (1<<31) #ifdef _KERNEL #define STAMP_WIDTH (pxi->pxi_stampw) #define STAMP_HEIGHT (pxi->pxi_stamph) #endif #define XMASKADDR(__sx, __a) (((__a)-((__sx) % STAMP_WIDTH)) & 0xF) #define YMASKADDR(__sy, __b) (((__b)-((__sy) % STAMP_HEIGHT)) & 0xF) #define XYMASKADDR(_x,_y,_a,_b) (XMASKADDR(_x,_a) << 16 | YMASKADDR(_y,_b)) /* * For the poll register. Don't mess with the # of retries or the delay * unless you know what you're doing. According to OSF header files, * the delay on Alpha is 20us, and the # of retries should be 4000. This is * inadequate, particularly on the PXG which seems to run at a higher * frequency. The STIC gets wedged while scrolling quite a lot. */ #define STAMP_OK (0) #define STAMP_BUSY (1) #define STAMP_RETRIES (7000) #define STAMP_DELAY (20) #if 0 /* was: #ifdef alpha in NetBSD */ #define __PXS(n) ((n) << 1) #else #define __PXS(n) (n) #endif /* * Hardware offsets within PX board's TC slot. */ #define PX_STIC_POLL_OFFSET __PXS(0x000000) /* STIC DMA poll space */ #define PX_STAMP_OFFSET __PXS(0x0c0000) /* pixelstamp space on STIC */ #define PX_STIC_OFFSET __PXS(0x180000) /* STIC registers */ #define PX_VDAC_OFFSET __PXS(0x200000) /* VDAC registers (bt459) */ #define PX_VDAC_RESET_OFFSET __PXS(0x300000) /* VDAC reset register */ #define PX_ROM_OFFSET __PXS(0x300000) /* ROM code */ /* * Hardware offsets within PXG board's TC slot. */ #define PXG_STIC_POLL_OFFSET __PXS(0x000000) /* STIC DMA poll space */ #define PXG_STAMP_OFFSET __PXS(0x0c0000) /* pixelstamp space on STIC */ #define PXG_STIC_OFFSET __PXS(0x180000) /* STIC registers */ #define PXG_SRAM_OFFSET __PXS(0x200000) /* N10 SRAM */ #define PXG_HOST_INTR_OFFSET __PXS(0x280000) /* N10 host interrupt */ #define PXG_COPROC_INTR_OFFSET __PXS(0x2c0000) /* N10 coprocessor interrupt */ #define PXG_VDAC_OFFSET __PXS(0x300000) /* VDAC registers (bt459) */ #define PXG_VDAC_RESET_OFFSET __PXS(0x340000) /* VDAC reset register */ #define PXG_ROM_OFFSET __PXS(0x380000) /* ROM code */ #define PXG_N10_START_OFFSET __PXS(0x380000) /* N10 start register */ #define PXG_N10_RESET_OFFSET __PXS(0x3c0000) /* N10 reset (stop?) register */ /* * STIC registers */ struct stic_regs { #if 0 /* was: ifdef __alpha in NetBSD */ volatile int32_t __pad0; volatile int32_t __pad1; volatile int32_t __pad2; volatile int32_t __pad3; volatile int32_t hsync; volatile int32_t __pad4; volatile int32_t hsync2; volatile int32_t __pad5; volatile int32_t hblank; volatile int32_t __pad6; volatile int32_t vsync; volatile int32_t __pad7; volatile int32_t vblank; volatile int32_t __pad8; volatile int32_t vtest; volatile int32_t __pad9; volatile int32_t ipdvint; volatile int32_t __pad10; volatile int32_t __pad11; volatile int32_t __pad12; volatile int32_t sticsr; volatile int32_t __pad13; volatile int32_t busdat; volatile int32_t __pad14; volatile int32_t busadr; volatile int32_t __pad15; volatile int32_t __pad16; volatile int32_t __pad17; volatile int32_t buscsr; volatile int32_t __pad18; volatile int32_t modcl; volatile int32_t __pad19; #else /* __alpha */ volatile int32_t __pad0; volatile int32_t __pad1; volatile int32_t hsync; volatile int32_t hsync2; volatile int32_t hblank; volatile int32_t vsync; volatile int32_t vblank; volatile int32_t vtest; volatile int32_t ipdvint; volatile int32_t __pad2; volatile int32_t sticsr; volatile int32_t busdat; volatile int32_t busadr; volatile int32_t __pad3; volatile int32_t buscsr; volatile int32_t modcl; #endif /* __alpha */ }; /* * Bit definitions for px_stic_regs.stic_csr. * these appear to exactly what the PROM tests use. */ #define STIC_CSR_TSTFNC 0x00000003 # define STIC_CSR_TSTFNC_NORMAL 0 # define STIC_CSR_TSTFNC_PARITY 1 # define STIC_CSR_TSTFNC_CNTPIX 2 # define STIC_CSR_TSTFNC_TSTDAC 3 #define STIC_CSR_CHECKPAR 0x00000004 #define STIC_CSR_STARTVT 0x00000010 #define STIC_CSR_START 0x00000020 #define STIC_CSR_RESET 0x00000040 #define STIC_CSR_STARTST 0x00000080 /* * Bit definitions for stic_regs.int. * Three four-bit wide fields, for error (E), vertical-blank (V), and * packetbuf-done (P) intererupts, respectively. * The low-order three bits of each field are enable, requested, * and acknowledge bits. The top bit of each field is unused. */ #define STIC_INT_E_EN 0x00000001 #define STIC_INT_E 0x00000002 #define STIC_INT_E_WE 0x00000004 #define STIC_INT_V_EN 0x00000100 #define STIC_INT_V 0x00000200 #define STIC_INT_V_WE 0x00000400 #define STIC_INT_P_EN 0x00010000 #define STIC_INT_P 0x00020000 #define STIC_INT_P_WE 0x00040000 #define STIC_INT_E_MASK (STIC_INT_E_EN | STIC_INT_E | STIC_INT_E_WE) #define STIC_INT_V_MASK (STIC_INT_V_EN | STIC_INT_V | STIC_INT_V_WE) #define STIC_INT_P_MASK (STIC_INT_P_EN | STIC_INT_P | STIC_INT_P_WE) #define STIC_INT_MASK (STIC_INT_E_MASK | STIC_INT_P_MASK | STIC_INT_V_MASK) #define STIC_INT_WE (STIC_INT_E_WE | STIC_INT_V_WE | STIC_INT_P_WE) #define STIC_INT_CLR (STIC_INT_E_EN | STIC_INT_V_EN | STIC_INT_P_EN) /* * Convert a system physical address to STIC poll offset. Polling the offset * returned will initiate DMA at the provided address. For the PX, the STIC * only sees 23-bits (8MB) of address space. Also, bits 21-22 in physical * address space map to bits 27-28 in the STIC's warped view of the world. * This is also true for bits 15-20, which map to bits 18-23. Bits 0 and 1 * are meaningless, because everything is word aligned. * * The final shift-right-by-9 is to map the address to poll register offset. * These begin at px_softc.poll (which should obviously be added to the * return value of this function to get a vaild poll address). * * This shift right gives us a granularity of 512 bytes when DMAing. The * holes in STIC address space mean that DMAs can never cross a 32kB * boundary. The maximum size for a DMA AFAIK is about 4kB. * * For the PXG, the PA is relative to SRAM (i.e. i860) address space, not * system address space. The poll address will either return STAMP_OK, or * STAMP_BUSY. */ #if 0 static __inline__ u_long px_sys2stic __P((void *)); static __inline__ u_long px_sys2dma __P((void *)); static __inline__ volatile int32_t *px_poll_addr __P((caddr_t, void *)); static __inline__ u_long px_sys2stic(addr) void *addr; { u_long v; v = (u_long)addr; v = ((v & ~0x7fff) << 3) | (v & 0x7fff); return (v & 0x1ffff800); } static __inline__ u_long px_sys2dma(addr) void *addr; { return px_sys2stic(addr) >> 9; } /* * This is simply a wrapper for the above that returns a proper VA to * poll when given a px_softc. */ static __inline__ volatile int32_t * px_poll_addr(slotbase, addr) caddr_t slotbase; void *addr; { return (volatile int32_t *)(slotbase + px_sys2dma(addr)); } #endif #endif /* !_PMAX_DEV_PXREG_H_ */ gxemul-0.6.1/src/include/thirdparty/i80321reg.h000644 001750 001750 00000044730 13402411502 021336 0ustar00debugdebug000000 000000 /* GXemul: $Id: i80321reg.h,v 1.1 2005-10-17 05:32:21 debug Exp $ */ /* $NetBSD: i80321reg.h,v 1.14 2003/12/19 10:08:11 gavan Exp $ */ /* * Copyright (c) 2002 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _ARM_XSCALE_I80321REG_H_ #define _ARM_XSCALE_I80321REG_H_ /* * Register definitions for the Intel 80321 (``Verde'') I/O processor, * based on the XScale core. */ /* * Base i80321 memory map: * * 0x0000.0000 - 0x7fff.ffff ATU Outbound Direct Addressing Window * 0x8000.0000 - 0x9001.ffff ATU Outbound Translation Windows * 0x9002.0000 - 0xffff.dfff External Memory * 0xffff.e000 - 0xffff.e8ff Peripheral Memory Mapped Registers * 0xffff.e900 - 0xffff.ffff Reserved */ #define VERDE_OUT_DIRECT_WIN_BASE 0x00000000UL #define VERDE_OUT_DIRECT_WIN_SIZE 0x80000000UL #define VERDE_OUT_XLATE_MEM_WIN_SIZE 0x04000000UL #define VERDE_OUT_XLATE_IO_WIN_SIZE 0x00010000UL #define VERDE_OUT_XLATE_MEM_WIN0_BASE 0x80000000UL #define VERDE_OUT_XLATE_MEM_WIN1_BASE 0x84000000UL #define VERDE_OUT_XLATE_IO_WIN0_BASE 0x90000000UL #define VERDE_EXTMEM_BASE 0x90020000UL #define VERDE_PMMR_BASE 0xffffe000UL #define VERDE_PMMR_SIZE 0x00001700UL /* * Peripheral Memory Mapped Registers. Defined as offsets * from the VERDE_PMMR_BASE. */ #define VERDE_ATU_BASE 0x0100 #define VERDE_ATU_SIZE 0x0100 #define VERDE_MU_BASE 0x0300 #define VERDE_MU_SIZE 0x0100 #define VERDE_DMA_BASE 0x0400 #define VERDE_DMA_BASE0 (VERDE_DMA_BASE + 0x00) #define VERDE_DMA_BASE1 (VERDE_DMA_BASE + 0x40) #define VERDE_DMA_SIZE 0x0100 #define VERDE_DMA_CHSIZE 0x0040 #define VERDE_MCU_BASE 0x0500 #define VERDE_MCU_SIZE 0x0100 #define VERDE_SSP_BASE 0x0600 #define VERDE_SSP_SIZE 0x0080 #define VERDE_PBIU_BASE 0x0680 #define VERDE_PBIU_SIZE 0x0080 #define VERDE_AAU_BASE 0x0800 #define VERDE_AAU_SIZE 0x0100 #define VERDE_I2C_BASE 0x1680 #define VERDE_I2C_BASE0 (VERDE_I2C_BASE + 0x00) #define VERDE_I2C_BASE1 (VERDE_I2C_BASE + 0x20) #define VERDE_I2C_SIZE 0x0080 #define VERDE_I2C_CHSIZE 0x0020 /* * Address Translation Unit */ /* 0x00 - 0x38 -- PCI configuration space header */ #define ATU_IALR0 0x40 /* Inbound ATU Limit 0 */ #define ATU_IATVR0 0x44 /* Inbound ATU Xlate Value 0 */ #define ATU_ERLR 0x48 /* Expansion ROM Limit */ #define ATU_ERTVR 0x4c /* Expansion ROM Xlate Value */ #define ATU_IALR1 0x50 /* Inbound ATU Limit 1 */ #define ATU_IALR2 0x54 /* Inbound ATU Limit 2 */ #define ATU_IATVR2 0x58 /* Inbound ATU Xlate Value 2 */ #define ATU_OIOWTVR 0x5c /* Outbound I/O Window Xlate Value */ #define ATU_OMWTVR0 0x60 /* Outbound Mem Window Xlate Value 0 */ #define ATU_OUMWTVR0 0x64 /* Outbound Mem Window Xlate Value 0 Upper */ #define ATU_OMWTVR1 0x68 /* Outbound Mem Window Xlate Value 1 */ #define ATU_OUMWTVR1 0x6c /* Outbound Mem Window Xlate Value 1 Upper */ #define ATU_OUDWTVR 0x78 /* Outbound Mem Direct Xlate Value Upper */ #define ATU_ATUCR 0x80 /* ATU Configuration */ #define ATU_PCSR 0x84 /* PCI Configuration and Status */ #define ATU_ATUISR 0x88 /* ATU Interrupt Status */ #define ATU_ATUIMR 0x8c /* ATU Interrupt Mask */ #define ATU_IABAR3 0x90 /* Inbound ATU Base Address 3 */ #define ATU_IAUBAR3 0x94 /* Inbound ATU Base Address 3 Upper */ #define ATU_IALR3 0x98 /* Inbound ATU Limit 3 */ #define ATU_IATVR3 0x9c /* Inbound ATU Xlate Value 3 */ #define ATU_OCCAR 0xa4 /* Outbound Configuration Cycle Address */ #define ATU_OCCDR 0xac /* Outbound Configuration Cycle Data */ #define ATU_MSI_PORT 0xb4 /* MSI port */ #define ATU_PDSCR 0xbc /* PCI Bus Drive Strength Control */ #define ATU_PCI_X_CAP_ID 0xe0 /* (1) */ #define ATU_PCI_X_NEXT 0xe1 /* (1) */ #define ATU_PCIXCMD 0xe2 /* PCI-X Command Register (2) */ #define ATU_PCIXSR 0xe4 /* PCI-X Status Register */ #define ATUCR_DRC_ALIAS (1U << 19) #define ATUCR_DAU2GXEN (1U << 18) #define ATUCR_P_SERR_MA (1U << 16) #define ATUCR_DTS (1U << 15) #define ATUCR_P_SERR_DIE (1U << 9) #define ATUCR_DAE (1U << 8) #define ATUCR_BIST_IE (1U << 3) #define ATUCR_OUT_EN (1U << 1) #define PCSR_DAAAPE (1U << 18) #define PCSR_PCI_X_CAP (3U << 16) #define PCSR_PCI_X_CAP_BORING (0 << 16) #define PCSR_PCI_X_CAP_66 (1U << 16) #define PCSR_PCI_X_CAP_100 (2U << 16) #define PCSR_PCI_X_CAP_133 (3U << 16) #define PCSR_OTQB (1U << 15) #define PCSR_IRTQB (1U << 14) #define PCSR_DTV (1U << 12) #define PCSR_BUS66 (1U << 10) #define PCSR_BUS64 (1U << 8) #define PCSR_RIB (1U << 5) #define PCSR_RPB (1U << 4) #define PCSR_CCR (1U << 2) #define PCSR_CPR (1U << 1) #define ATUISR_IMW1BU (1U << 14) #define ATUISR_ISCEM (1U << 13) #define ATUISR_RSCEM (1U << 12) #define ATUISR_PST (1U << 11) #define ATUISR_P_SERR_ASRT (1U << 10) #define ATUISR_DPE (1U << 9) #define ATUISR_BIST (1U << 8) #define ATUISR_IBMA (1U << 7) #define ATUISR_P_SERR_DET (1U << 4) #define ATUISR_PMA (1U << 3) #define ATUISR_PTAM (1U << 2) #define ATUISR_PTAT (1U << 1) #define ATUISR_PMPE (1U << 0) #define ATUIMR_IMW1BU (1U << 11) #define ATUIMR_ISCEM (1U << 10) #define ATUIMR_RSCEM (1U << 9) #define ATUIMR_PST (1U << 8) #define ATUIMR_DPE (1U << 7) #define ATUIMR_P_SERR_ASRT (1U << 6) #define ATUIMR_PMA (1U << 5) #define ATUIMR_PTAM (1U << 4) #define ATUIMR_PTAT (1U << 3) #define ATUIMR_PMPE (1U << 2) #define ATUIMR_IE_SERR_EN (1U << 1) #define ATUIMR_ECC_TAE (1U << 0) #define PCIXCMD_MOST_1 (0 << 4) #define PCIXCMD_MOST_2 (1 << 4) #define PCIXCMD_MOST_3 (2 << 4) #define PCIXCMD_MOST_4 (3 << 4) #define PCIXCMD_MOST_8 (4 << 4) #define PCIXCMD_MOST_12 (5 << 4) #define PCIXCMD_MOST_16 (6 << 4) #define PCIXCMD_MOST_32 (7 << 4) #define PCIXCMD_MOST_MASK (7 << 4) #define PCIXCMD_MMRBC_512 (0 << 2) #define PCIXCMD_MMRBC_1024 (1 << 2) #define PCIXCMD_MMRBC_2048 (2 << 2) #define PCIXCMD_MMRBC_4096 (3 << 2) #define PCIXCMD_MMRBC_MASK (3 << 2) #define PCIXCMD_ERO (1U << 1) #define PCIXCMD_DPERE (1U << 0) #define PCIXSR_RSCEM (1U << 29) #define PCIXSR_DMCRS_MASK (7 << 26) #define PCIXSR_DMOST_MASK (7 << 23) #define PCIXSR_COMPLEX (1U << 20) #define PCIXSR_USC (1U << 19) #define PCIXSR_SCD (1U << 18) #define PCIXSR_133_CAP (1U << 17) #define PCIXSR_32PCI (1U << 16) /* 0 = 32, 1 = 64 */ #define PCIXSR_BUSNO(x) (((x) & 0xff00) >> 8) #define PCIXSR_DEVNO(x) (((x) & 0xf8) >> 3) #define PCIXSR_FUNCNO(x) ((x) & 0x7) /* * Memory Controller Unit */ #define MCU_SDIR 0x00 /* DDR SDRAM Init. Register */ #define MCU_SDCR 0x04 /* DDR SDRAM Control Register */ #define MCU_SDBR 0x08 /* SDRAM Base Register */ #define MCU_SBR0 0x0c /* SDRAM Boundary 0 */ #define MCU_SBR1 0x10 /* SDRAM Boundary 1 */ #define MCU_ECCR 0x34 /* ECC Control Register */ #define MCU_ELOG0 0x38 /* ECC Log 0 */ #define MCU_ELOG1 0x3c /* ECC Log 1 */ #define MCU_ECAR0 0x40 /* ECC address 0 */ #define MCU_ECAR1 0x44 /* ECC address 1 */ #define MCU_ECTST 0x48 /* ECC test register */ #define MCU_MCISR 0x4c /* MCU Interrupt Status Register */ #define MCU_RFR 0x50 /* Refresh Frequency Register */ #define MCU_DBUDSR 0x54 /* Data Bus Pull-up Drive Strength */ #define MCU_DBDDSR 0x58 /* Data Bus Pull-down Drive Strength */ #define MCU_CUDSR 0x5c /* Clock Pull-up Drive Strength */ #define MCU_CDDSR 0x60 /* Clock Pull-down Drive Strength */ #define MCU_CEUDSR 0x64 /* Clock En Pull-up Drive Strength */ #define MCU_CEDDSR 0x68 /* Clock En Pull-down Drive Strength */ #define MCU_CSUDSR 0x6c /* Chip Sel Pull-up Drive Strength */ #define MCU_CSDDSR 0x70 /* Chip Sel Pull-down Drive Strength */ #define MCU_REUDSR 0x74 /* Rx En Pull-up Drive Strength */ #define MCU_REDDSR 0x78 /* Rx En Pull-down Drive Strength */ #define MCU_ABUDSR 0x7c /* Addr Bus Pull-up Drive Strength */ #define MCU_ABDDSR 0x80 /* Addr Bus Pull-down Drive Strength */ #define MCU_DSDR 0x84 /* Data Strobe Delay Register */ #define MCU_REDR 0x88 /* Rx Enable Delay Register */ #define SDCR_DIMMTYPE (1U << 1) /* 0 = unbuf, 1 = reg */ #define SDCR_BUSWIDTH (1U << 2) /* 0 = 64, 1 = 32 */ #define SBRx_TECH (1U << 31) #define SBRx_BOUND 0x0000003f #define ECCR_SBERE (1U << 0) #define ECCR_MBERE (1U << 1) #define ECCR_SBECE (1U << 2) #define ECCR_ECCEN (1U << 3) #define ELOGx_SYNDROME 0x000000ff #define ELOGx_ERRTYPE (1U << 8) /* 1 = multi-bit */ #define ELOGx_RW (1U << 12) /* 1 = write error */ /* * Dev ID Func Requester * 2 0 XScale core * 2 1 ATU * 13 0 DMA channel 0 * 13 1 DMA channel 1 * 26 0 ATU */ #define ELOGx_REQ_DEV(x) (((x) >> 19) & 0x1f) #define ELOGx_REQ_FUNC(x) (((x) >> 16) & 0x3) #define MCISR_ECC_ERR0 (1U << 0) #define MCISR_ECC_ERR1 (1U << 1) #define MCISR_ECC_ERRN (1U << 2) /* * Timers * * The i80321 timer registers are available in both memory-mapped * and coprocessor spaces. Most of the registers are read-only * if memory-mapped, so we access them via coprocessor space. * * TMR0 cp6 c0,1 0xffffe7e0 * TMR1 cp6 c1,1 0xffffe7e4 * TCR0 cp6 c2,1 0xffffe7e8 * TCR1 cp6 c3,1 0xffffe7ec * TRR0 cp6 c4,1 0xffffe7f0 * TRR1 cp6 c5,1 0xffffe7f4 * TISR cp6 c6,1 0xffffe7f8 * WDTCR cp6 c7,1 0xffffe7fc */ #define TMRx_TC (1U << 0) #define TMRx_ENABLE (1U << 1) #define TMRx_RELOAD (1U << 2) #define TMRx_CSEL_CORE (0 << 4) #define TMRx_CSEL_CORE_div4 (1 << 4) #define TMRx_CSEL_CORE_div8 (2 << 4) #define TMRx_CSEL_CORE_div16 (3 << 4) #define TISR_TMR0 (1U << 0) #define TISR_TMR1 (1U << 1) #define WDTCR_ENABLE1 0x1e1e1e1e #define WDTCR_ENABLE2 0xe1e1e1e1 /* * Interrupt Controller Unit. * * INTCTL cp6 c0,0 0xffffe7d0 * INTSTR cp6 c4,0 0xffffe7d4 * IINTSRC cp6 c8,0 0xffffe7d8 * FINTSRC cp6 c9,0 0xffffe7dc * PIRSR 0xffffe1ec */ #define ICU_PIRSR 0x01ec #define ICU_GPOE 0x07c4 #define ICU_GPID 0x07c8 #define ICU_GPOD 0x07cc /* * NOTE: WE USE THE `bitXX' BITS TO INDICATE PENDING SOFTWARE * INTERRUPTS. See i80321_icu.c */ #define ICU_INT_HPI 31 /* high priority interrupt */ #define ICU_INT_XINT0 27 /* external interrupts */ #define ICU_INT_XINT(x) ((x) + ICU_INT_XINT0) #define ICU_INT_bit26 26 #define ICU_INT_SSP 25 /* SSP serial port */ #define ICU_INT_MUE 24 /* msg unit error */ #define ICU_INT_AAUE 23 /* AAU error */ #define ICU_INT_bit22 22 #define ICU_INT_DMA1E 21 /* DMA Ch 1 error */ #define ICU_INT_DMA0E 20 /* DMA Ch 0 error */ #define ICU_INT_MCUE 19 /* memory controller error */ #define ICU_INT_ATUE 18 /* ATU error */ #define ICU_INT_BIUE 17 /* bus interface unit error */ #define ICU_INT_PMU 16 /* XScale PMU */ #define ICU_INT_PPM 15 /* peripheral PMU */ #define ICU_INT_BIST 14 /* ATU Start BIST */ #define ICU_INT_MU 13 /* messaging unit */ #define ICU_INT_I2C1 12 /* i2c unit 1 */ #define ICU_INT_I2C0 11 /* i2c unit 0 */ #define ICU_INT_TMR1 10 /* timer 1 */ #define ICU_INT_TMR0 9 /* timer 0 */ #define ICU_INT_CPPM 8 /* core processor PMU */ #define ICU_INT_AAU_EOC 7 /* AAU end-of-chain */ #define ICU_INT_AAU_EOT 6 /* AAU end-of-transfer */ #define ICU_INT_bit5 5 #define ICU_INT_bit4 4 #define ICU_INT_DMA1_EOC 3 /* DMA1 end-of-chain */ #define ICU_INT_DMA1_EOT 2 /* DMA1 end-of-transfer */ #define ICU_INT_DMA0_EOC 1 /* DMA0 end-of-chain */ #define ICU_INT_DMA0_EOT 0 /* DMA0 end-of-transfer */ #define ICU_INT_HWMASK (0xffffffff & \ ~((1 << ICU_INT_bit26) | \ (1 << ICU_INT_bit22) | \ (1 << ICU_INT_bit5) | \ (1 << ICU_INT_bit4))) /* * SSP Serial Port */ #define SSP_SSCR0 0x00 /* SSC control 0 */ #define SSP_SSCR1 0x04 /* SSC control 1 */ #define SSP_SSSR 0x08 /* SSP status */ #define SSP_SSITR 0x0c /* SSP interrupt test */ #define SSP_SSDR 0x10 /* SSP data */ #define SSP_SSCR0_DSIZE(x) ((x) - 1)/* data size: 4..16 */ #define SSP_SSCR0_FRF_SPI (0 << 4) /* Motorola Serial Periph Iface */ #define SSP_SSCR0_FRF_SSP (1U << 4)/* TI Sync. Serial Protocol */ #define SSP_SSCR0_FRF_UWIRE (2U << 4)/* NatSemi Microwire */ #define SSP_SSCR0_FRF_rsvd (3U << 4)/* reserved */ #define SSP_SSCR0_ECS (1U << 6)/* external clock select */ #define SSP_SSCR0_SSE (1U << 7)/* sync. serial port enable */ #define SSP_SSCR0_SCR(x) ((x) << 8)/* serial clock rate */ /* bit rate = 3.6864 * 10e6 / (2 * (SCR + 1)) */ #define SSP_SSCR1_RIE (1U << 0)/* Rx FIFO interrupt enable */ #define SSP_SSCR1_TIE (1U << 1)/* Tx FIFO interrupt enable */ #define SSP_SSCR1_LBM (1U << 2)/* loopback mode enable */ #define SSP_SSCR1_SPO (1U << 3)/* Moto SPI SSCLK pol. (1 = high) */ #define SSP_SSCR1_SPH (1U << 4)/* Moto SPI SSCLK phase: 0 = inactive full at start, 1/2 at end of frame 1 = inactive 1/2 at start, full at end of frame */ #define SSP_SSCR1_MWDS (1U << 5)/* Microwire data size: 0 = 8 bit 1 = 16 bit */ #define SSP_SSCR1_TFT (((x) - 1) << 6) /* Tx FIFO threshold */ #define SSP_SSCR1_RFT (((x) - 1) << 10)/* Rx FIFO threshold */ #define SSP_SSCR1_EFWR (1U << 14)/* enab. FIFO write/read */ #define SSP_SSCR1_STRF (1U << 15)/* FIFO write/read FIFO select: 0 = Tx FIFO 1 = Rx FIFO */ #define SSP_SSSR_TNF (1U << 2)/* Tx FIFO not full */ #define SSP_SSSR_RNE (1U << 3)/* Rx FIFO not empty */ #define SSP_SSSR_BSY (1U << 4)/* SSP is busy */ #define SSP_SSSR_TFS (1U << 5)/* Tx FIFO service request */ #define SSP_SSSR_RFS (1U << 6)/* Rx FIFO service request */ #define SSP_SSSR_ROR (1U << 7)/* Rx FIFO overrun */ #define SSP_SSSR_TFL(x) (((x) >> 8) & 0xf) /* Tx FIFO level */ #define SSP_SSSR_RFL(x) (((x) >> 12) & 0xf)/* Rx FIFO level */ #define SSP_SSITR_TTFS (1U << 5)/* Test Tx FIFO service */ #define SSP_SSITR_TRFS (1U << 6)/* Test Rx FIFO service */ #define SSP_SSITR_TROR (1U << 7)/* Test Rx overrun */ /* * Peripheral Bus Interface Unit */ #define PBIU_PBCR 0x00 /* PBIU Control Register */ #define PBIU_PBBAR0 0x08 /* PBIU Base Address Register 0 */ #define PBIU_PBLR0 0x0c /* PBIU Limit Register 0 */ #define PBIU_PBBAR1 0x10 /* PBIU Base Address Register 1 */ #define PBIU_PBLR1 0x14 /* PBIU Limit Register 1 */ #define PBIU_PBBAR2 0x18 /* PBIU Base Address Register 2 */ #define PBIU_PBLR2 0x1c /* PBIU Limit Register 2 */ #define PBIU_PBBAR3 0x20 /* PBIU Base Address Register 3 */ #define PBIU_PBLR3 0x24 /* PBIU Limit Register 3 */ #define PBIU_PBBAR4 0x28 /* PBIU Base Address Register 4 */ #define PBIU_PBLR4 0x2c /* PBIU Limit Register 4 */ #define PBIU_PBBAR5 0x30 /* PBIU Base Address Register 5 */ #define PBIU_PBLR5 0x34 /* PBIU Limit Register 5 */ #define PBIU_DSCR 0x38 /* PBIU Drive Strength Control Reg. */ #define PBIU_MBR0 0x40 /* PBIU Memory-less Boot Reg. 0 */ #define PBIU_MBR1 0x60 /* PBIU Memory-less Boot Reg. 1 */ #define PBIU_MBR2 0x64 /* PBIU Memory-less Boot Reg. 2 */ #define PBIU_PBCR_PBIEN (1 << 0) #define PBIU_PBCR_PBI100 (1 << 1) #define PBIU_PBCR_PBI66 (2 << 1) #define PBIU_PBCR_PBI33 (3 << 1) #define PBIU_PBCR_PBBEN (1 << 3) #define PBIU_PBARx_WIDTH8 (0 << 0) #define PBIU_PBARx_WIDTH16 (1 << 0) #define PBIU_PBARx_WIDTH32 (2 << 0) #define PBIU_PBARx_ADWAIT4 (0 << 2) #define PBIU_PBARx_ADWAIT8 (1 << 2) #define PBIU_PBARx_ADWAIT12 (2 << 2) #define PBIU_PBARx_ADWAIT16 (3 << 2) #define PBIU_PBARx_ADWAIT20 (4 << 2) #define PBIU_PBARx_RCWAIT1 (0 << 6) #define PBIU_PBARx_RCWAIT4 (1 << 6) #define PBIU_PBARx_RCWAIT8 (2 << 6) #define PBIU_PBARx_RCWAIT12 (3 << 6) #define PBIU_PBARx_RCWAIT16 (4 << 6) #define PBIU_PBARx_RCWAIT20 (5 << 6) #define PBIU_PBARx_FWE (1 << 9) #define PBIU_BASE_MASK 0xfffff000U #define PBIU_PBLRx_SIZE(x) (~((x) - 1)) /* * Messaging Unit */ #define MU_IMR0 0x0010 /* MU Inbound Message Register 0 */ #define MU_IMR1 0x0014 /* MU Inbound Message Register 1 */ #define MU_OMR0 0x0018 /* MU Outbound Message Register 0 */ #define MU_OMR1 0x001c /* MU Outbound Message Register 1 */ #define MU_IDR 0x0020 /* MU Inbound Doorbell Register */ #define MU_IISR 0x0024 /* MU Inbound Interrupt Status Reg */ #define MU_IIMR 0x0028 /* MU Inbound Interrupt Mask Reg */ #define MU_ODR 0x002c /* MU Outbound Doorbell Register */ #define MU_OISR 0x0030 /* MU Outbound Interrupt Status Reg */ #define MU_OIMR 0x0034 /* MU Outbound Interrupt Mask Reg */ #define MU_MUCR 0x0050 /* MU Configuration Register */ #define MU_QBAR 0x0054 /* MU Queue Base Address Register */ #define MU_IFHPR 0x0060 /* MU Inbound Free Head Pointer Reg */ #define MU_IFTPR 0x0064 /* MU Inbound Free Tail Pointer Reg */ #define MU_IPHPR 0x0068 /* MU Inbound Post Head Pointer Reg */ #define MU_IPTPR 0x006c /* MU Inbound Post Tail Pointer Reg */ #define MU_OFHPR 0x0070 /* MU Outbound Free Head Pointer Reg */ #define MU_OFTPR 0x0074 /* MU Outbound Free Tail Pointer Reg */ #define MU_OPHPR 0x0078 /* MU Outbound Post Head Pointer Reg */ #define MU_OPTPR 0x007c /* MU Outbound Post Tail Pointer Reg */ #define MU_IAR 0x0080 /* MU Index Address Register */ #define MU_IIMR_IRI (1 << 6) /* Index Register Interrupt */ #define MU_IIMR_OFQFI (1 << 5) /* Outbound Free Queue Full Int. */ #define MU_IIMR_IPQI (1 << 4) /* Inbound Post Queue Interrupt */ #define MU_IIMR_EDI (1 << 3) /* Error Doorbell Interrupt */ #define MU_IIMR_IDI (1 << 2) /* Inbound Doorbell Interrupt */ #define MU_IIMR_IM1I (1 << 1) /* Inbound Message 1 Interrupt */ #define MU_IIMR_IM0I (1 << 0) /* Inbound Message 0 Interrupt */ #endif /* _ARM_XSCALE_I80321REG_H_ */ gxemul-0.6.1/src/include/thirdparty/sh4_cpu.h000644 001750 001750 00000015660 13402411502 021357 0ustar00debugdebug000000 000000 /* $NetBSD: cpu.h,v 1.41 2006/01/21 04:24:12 uwe Exp $ */ #ifndef SH4_CPU_H #define SH4_CPU_H /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. All rights reserved. * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)cpu.h 5.4 (Berkeley) 5/9/91 */ /* * SH3/SH4 support. * * T.Horiuchi Brains Corp. 5/22/98 */ #if defined(_KERNEL_OPT) #include "opt_lockdebug.h" #endif #if 0 #include #include #endif #ifdef _KERNEL #include struct cpu_info { struct cpu_data ci_data; /* MI per-cpu data */ }; extern struct cpu_info cpu_info_store; #define curcpu() (&cpu_info_store) /* * definitions of cpu-dependent requirements * referenced in generic code */ #define cpu_number() 0 /* * Can't swapout u-area, (__SWAP_BROKEN) * since we use P1 converted address for trapframe. */ #define cpu_swapin(p) /* nothing */ #define cpu_swapout(p) panic("cpu_swapout: can't get here"); #define cpu_proc_fork(p1, p2) /* nothing */ /* * Arguments to hardclock and gatherstats encapsulate the previous * machine state in an opaque clockframe. */ struct clockframe { int spc; /* program counter at time of interrupt */ int ssr; /* status register at time of interrupt */ int ssp; /* stack pointer at time of interrupt */ }; #define CLKF_USERMODE(cf) (!KERNELMODE((cf)->ssr)) #define CLKF_BASEPRI(cf) (((cf)->ssr & 0xf0) == 0) #define CLKF_PC(cf) ((cf)->spc) #define CLKF_INTR(cf) 0 /* XXX */ /* * This is used during profiling to integrate system time. It can safely * assume that the process is resident. */ #define PROC_PC(p) \ (((struct trapframe *)(p)->p_md.md_regs)->tf_spc) /* * Preempt the current process if in interrupt from user mode, * or after the current trap/syscall if in system mode. */ #define need_resched(ci) \ do { \ want_resched = 1; \ if (curproc != NULL) \ aston(curproc); \ } while (/*CONSTCOND*/0) /* * Give a profiling tick to the current process when the user profiling * buffer pages are invalid. On the MIPS, request an ast to send us * through trap, marking the proc as needing a profiling tick. */ #define need_proftick(p) \ do { \ (p)->p_flag |= P_OWEUPC; \ aston(p); \ } while (/*CONSTCOND*/0) /* * Notify the current process (p) that it has a signal pending, * process as soon as possible. */ #define signotify(p) aston(p) #define aston(p) ((p)->p_md.md_astpending = 1) extern int want_resched; /* need_resched() was called */ /* * We need a machine-independent name for this. */ #define DELAY(x) delay(x) #endif /* _KERNEL */ /* * Logical address space of SH3/SH4 CPU. */ #define SH3_PHYS_MASK 0x1fffffff #define SH3_P0SEG_BASE 0x00000000 /* TLB mapped, also U0SEG */ #define SH3_P0SEG_END 0x7fffffff #define SH3_P1SEG_BASE 0x80000000 /* pa == va */ #define SH3_P1SEG_END 0x9fffffff #define SH3_P2SEG_BASE 0xa0000000 /* pa == va, non-cacheable */ #define SH3_P2SEG_END 0xbfffffff #define SH3_P3SEG_BASE 0xc0000000 /* TLB mapped, kernel mode */ #define SH3_P3SEG_END 0xdfffffff #define SH3_P4SEG_BASE 0xe0000000 /* peripheral space */ #define SH3_P4SEG_END 0xffffffff #define SH3_P1SEG_TO_PHYS(x) ((uint32_t)(x) & SH3_PHYS_MASK) #define SH3_P2SEG_TO_PHYS(x) ((uint32_t)(x) & SH3_PHYS_MASK) #define SH3_PHYS_TO_P1SEG(x) ((uint32_t)(x) | SH3_P1SEG_BASE) #define SH3_PHYS_TO_P2SEG(x) ((uint32_t)(x) | SH3_P2SEG_BASE) #define SH3_P1SEG_TO_P2SEG(x) ((uint32_t)(x) | 0x20000000) #define SH3_P2SEG_TO_P1SEG(x) ((uint32_t)(x) & ~0x20000000) #ifndef __lint__ /* switch from P1 to P2 */ #define RUN_P2 do { \ void *p; \ p = &&P2; \ goto *(void *)SH3_P1SEG_TO_P2SEG(p); \ P2: (void)0; \ } while (0) /* switch from P2 to P1 */ #define RUN_P1 do { \ void *p; \ p = &&P1; \ __asm volatile("nop;nop;nop;nop;nop;nop;nop;nop"); \ goto *(void *)SH3_P2SEG_TO_P1SEG(p); \ P1: (void)0; \ } while (0) #else /* __lint__ */ #define RUN_P2 do {} while (/* CONSTCOND */ 0) #define RUN_P1 do {} while (/* CONSTCOND */ 0) #endif /* #if defined(SH4) */ /* SH4 Processor Version Register */ #define SH4_PVR_ADDR 0xff000030 /* P4 address */ #define SH4_PVR (*(volatile uint32_t *) SH4_PVR_ADDR) #define SH4_PRR_ADDR 0xff000044 /* P4 address */ #define SH4_PRR (*(volatile uint32_t *) SH4_PRR_ADDR) #define SH4_PVR_MASK 0xffffff00 #define SH4_PVR_SH7750 0x04020500 /* SH7750 */ #define SH4_PVR_SH7750S 0x04020600 /* SH7750S */ #define SH4_PVR_SH775xR 0x04050000 /* SH775xR */ #define SH4_PVR_SH7751 0x04110000 /* SH7751 */ #define SH4_PRR_MASK 0xfffffff0 #define SH4_PRR_7750R 0x00000100 /* SH7750R */ #define SH4_PRR_7751R 0x00000110 /* SH7751R */ /* #endif */ /* * pull in #defines for kinds of processors */ /* #include */ /* * CTL_MACHDEP definitions. */ #define CPU_CONSDEV 1 /* dev_t: console terminal device */ #define CPU_LOADANDRESET 2 /* load kernel image and reset */ #define CPU_MAXID 3 /* number of valid machdep ids */ #define CTL_MACHDEP_NAMES { \ { 0, 0 }, \ { "console_device", CTLTYPE_STRUCT }, \ { "load_and_reset", CTLTYPE_INT }, \ } #ifdef _KERNEL void sh_cpu_init(int, int); void sh_startup(void); void cpu_reset(void) __attribute__((__noreturn__)); /* soft reset */ void _cpu_spin(uint32_t); /* for delay loop. */ void delay(int); struct pcb; void savectx(struct pcb *); void dumpsys(void); #endif /* _KERNEL */ #endif /* SH4_CPU_H */ gxemul-0.6.1/src/include/thirdparty/dec_kn01.h000644 001750 001750 00000015122 13402411502 021367 0ustar00debugdebug000000 000000 /* gxemul: $Id: dec_kn01.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ #ifndef DEC_KN01_H #define DEC_KN01_H #define IP_LEV7 7 #define IP_LEV6 6 #define IP_LEV5 5 #define IP_LEV4 4 #define IP_LEV3 3 #define IP_LEV2 2 #define IP_LEV1 1 #define IP_LEV0 0 /* $NetBSD: kn01.h,v 1.6 2000/02/29 04:41:56 nisimura Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * The Mach Operating System project at Carnegie-Mellon University, * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)kn01.h 8.1 (Berkeley) 6/10/93 */ /* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * HISTORY * Log: kn01.h,v * Revision 2.5 91/05/14 17:23:14 mrt * Correcting copyright * * Revision 2.4 91/02/05 17:41:54 mrt * Added author notices * [91/02/04 11:14:12 mrt] * * Changed to use new Mach copyright * [91/02/02 12:12:45 mrt] * * Revision 2.3 90/12/05 23:31:50 af * Cleanups. * [90/12/04 16:38:21 af] * * Created, from the DEC specs: * "DECstation 3100 Desktop Workstation Functional Specification" * Workstation Systems Engineering, Palo Alto, CA. Aug 28, 1990. * [90/09/03 af] */ /* * File: kn01.h * Author: Alessandro Forin, Carnegie Mellon University * Date: 9/90 * * Definitions specific to the KN01 processor (pmax) */ /* * KN01's Physical address space */ #define KN01_PHYS_MIN 0x00000000 /* 512 Meg */ #define KN01_PHYS_MAX 0x1fffffff /* * Memory map */ #define KN01_PHYS_MEMORY_START 0x00000000 #define KN01_PHYS_MEMORY_END 0x01800000 /* 24 Meg in 8 slots */ #define KN01_PHYS_FBUF_START 0x0fc00000 /* frame buffer memory */ #define KN01_PHYS_FBUF_M_END 0x0fc20000 /* mono */ #define KN01_PHYS_FBUF_C_END 0x0fd00000 /* color */ #define KN01_PHYS_COLMASK_START 0x10000000 /* Color Plane mask */ #define KN01_PHYS_COLMASK_END 0x11000000 /* Color Plane mask */ /* * I/O map */ #define KN01_SYS_PCC 0x11000000 /* Progr. Cursor Chip */ #define KN01_SYS_VDAC 0x12000000 /* Color map */ #define KN01_SYS_ERRADR 0x17000000 /* Write error address */ #define KN01_SYS_LANCE 0x18000000 /* LANCE chip */ #define KN01_SYS_LANCE_B_START 0x19000000 /* 64 KB LANCE Buffer */ #define KN01_SYS_LANCE_B_END 0x19010000 #define KN01_SYS_SII 0x1a000000 /* SCSI SII chip */ #define KN01_SYS_SII_B_START 0x1b000000 /* 128 KB SCSI buffer */ #define KN01_SYS_SII_B_END 0x1b020000 #define KN01_SYS_DZ 0x1c000000 /* Serial lines (DZ) */ #define KN01_SYS_CLOCK 0x1d000000 /* RTC chip */ #define KN01_SYS_CSR 0x1e000000 /* System control register */ #define KN01_SYS_ROM_START 0x1f000000 /* System ROM */ #define KN01_SYS_ROM_END 0x1f07ffff /* * Interrupts */ #define KN01_INT_FPA IP_LEV7 /* Floating Point coproc */ #define KN01_INT_MEM IP_LEV6 /* memory controller */ #define KN01_INT_CLOCK IP_LEV5 /* RTC chip */ #define KN01_INT_DZ IP_LEV4 /* serial line chip */ #define KN01_INT_LANCE IP_LEV3 /* Ether */ #define KN01_INT_SII IP_LEV2 /* SCSI interface */ /* * System board registers */ /* system Status and Control register */ #define KN01_CSR_LEDS_MASK 0x00ff /* wo - Diagnostic leds mask */ #define KN01_CSR_VRGTRB 0x0001 /* ro - Red VoltageLev > Blue */ #define KN01_CSR_VRGTRG 0x0002 /* ro - Red VoltageLev > Green */ #define KN01_CSR_VBGTRG 0x0004 /* ro - Blue VoltageLev > Green */ #define KN01_CSR_TXDIS 0x0100 /* rw - Disable DZ xmit */ #define KN01_CSR_VINT 0x0200 /* rc - Vertical retrace intr. */ #define KN01_CSR_MERR 0x0400 /* rc - Memory write error intr */ #define KN01_CSR_MONO 0x0800 /* ro - Mono Framebuf (or none) */ #define KN01_CSR_CRSRTST 0x1000 /* ro - Cursor test output */ #define KN01_CSR_PARDIS 0x2000 /* rw - Disable mem parity chks */ #define KN01_CSR_SELFTEST 0x4000 /* rw - Self-test ok pinout */ #define KN01_CSR_MNFMOD 0x8000 /* ro - Manifacturer MOD jumper */ #define KN01_CSR_MBZ 0x9800 /* Error address status register */ #define KN01_ERR_ADDRESS 0x07ffffff /* phys address mask ? */ #endif gxemul-0.6.1/src/include/thirdparty/sh4_tmureg.h000644 001750 001750 00000007252 13402411502 022071 0ustar00debugdebug000000 000000 /* $NetBSD: tmureg.h,v 1.11 2006/03/04 01:55:03 uwe Exp $ */ #ifndef _SH3_TMUREG_H_ #define _SH3_TMUREG_H_ /*- * Copyright (C) 1999 SAITOH Masanobu. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* #include */ /* * TMU */ #define SH3_TOCR 0xfffffe90 #define SH3_TSTR 0xfffffe92 #define SH3_TCOR0 0xfffffe94 #define SH3_TCNT0 0xfffffe98 #define SH3_TCR0 0xfffffe9c #define SH3_TCOR1 0xfffffea0 #define SH3_TCNT1 0xfffffea4 #define SH3_TCR1 0xfffffea8 #define SH3_TCOR2 0xfffffeac #define SH3_TCNT2 0xfffffeb0 #define SH3_TCR2 0xfffffeb4 #define SH3_TCPR2 0xfffffeb8 #define SH4_TOCR 0xffd80000 #define SH4_TSTR 0xffd80004 #define SH4_TCOR0 0xffd80008 #define SH4_TCNT0 0xffd8000c #define SH4_TCR0 0xffd80010 #define SH4_TCOR1 0xffd80014 #define SH4_TCNT1 0xffd80018 #define SH4_TCR1 0xffd8001c #define SH4_TCOR2 0xffd80020 #define SH4_TCNT2 0xffd80024 #define SH4_TCR2 0xffd80028 #define SH4_TCPR2 0xffd8002c #define SH4_TSTR2 0xfe100004 #define SH4_TCOR3 0xfe100008 #define SH4_TCNT3 0xfe10000c #define SH4_TCR3 0xfe100010 #define SH4_TCOR4 0xfe100014 #define SH4_TCNT4 0xfe100018 #define SH4_TCR4 0xfe10001c #define TOCR_TCOE 0x01 #define TSTR_STR2 0x04 #define TSTR_STR1 0x02 #define TSTR_STR0 0x01 #define TCR_ICPF 0x0200 #define TCR_UNF 0x0100 #define TCR_ICPE1 0x0080 #define TCR_ICPE0 0x0040 #define TCR_UNIE 0x0020 #define TCR_CKEG1 0x0010 #define TCR_CKEG0 0x0008 #define TCR_TPSC2 0x0004 #define TCR_TPSC1 0x0002 #define TCR_TPSC0 0x0001 #define TCR_TPSC_P4 0x0000 #define TCR_TPSC_P16 0x0001 #define TCR_TPSC_P64 0x0002 #define TCR_TPSC_P256 0x0003 #define SH3_TCR_TPSC_RTC 0x0004 #define SH3_TCR_TPSC_TCLK 0x0005 #define SH4_TCR_TPSC_P1024 0x0004 #define SH4_TCR_TPSC_RTC 0x0006 #define SH4_TCR_TPSC_TCLK 0x0007 #define SH4_TSTR2_STR4 0x02 #define SH4_TSTR2_STR3 0x01 #ifndef _LOCORE #if defined(SH3) && defined(SH4) extern uint32_t __sh_TOCR; extern uint32_t __sh_TSTR; extern uint32_t __sh_TCOR0; extern uint32_t __sh_TCNT0; extern uint32_t __sh_TCR0; extern uint32_t __sh_TCOR1; extern uint32_t __sh_TCNT1; extern uint32_t __sh_TCR1; extern uint32_t __sh_TCOR2; extern uint32_t __sh_TCNT2; extern uint32_t __sh_TCR2; extern uint32_t __sh_TCPR2; #endif /* SH3 && SH4 */ #endif /* !_LOCORE */ #endif /* !_SH3_TMUREG_H_ */ gxemul-0.6.1/src/include/thirdparty/kbdreg.h000644 001750 001750 00000010071 13402411502 021237 0ustar00debugdebug000000 000000 /* $NetBSD: kbdreg.h,v 1.4 2000/01/23 21:01:57 soda Exp $ */ /* $OpenBSD: kbdreg.h,v 1.3 1996/09/04 21:18:24 pefo Exp $ */ #ifndef __KBDREG_H #define __KBDREG_H /* * Copyright (c) 1996 Per Fogelstrom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Per Fogelstrom. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Keyboard definitions * */ #define KBSTATP (0x61) /* controller status port (I) */ #define KBS_DIB 0x01 /* data in buffer */ #define KBS_IBF 0x02 /* input buffer low */ #define KBS_WARM 0x04 /* input buffer low */ #define KBS_OCMD 0x08 /* output buffer has command */ #define KBS_NOSEC 0x10 /* security lock not engaged */ #define KBS_TERR 0x20 /* transmission error */ #define KBS_RERR 0x40 /* receive error */ #define KBS_PERR 0x80 /* parity error */ #define KBCMDP (0x61) /* controller port (O) */ #define KBDATAP (0x60) /* data port (I) */ #define KBOUTP (0x60) /* data port (O) */ #define K_RDCMDBYTE 0x20 #define K_LDCMDBYTE 0x60 #define KC8_TRANS 0x40 /* convert to old scan codes */ #define KC8_MDISABLE 0x20 /* disable mouse */ #define KC8_KDISABLE 0x10 /* disable keyboard */ #define KC8_IGNSEC 0x08 /* ignore security lock */ #define KC8_CPU 0x04 /* exit from protected mode reset */ #define KC8_MENABLE 0x02 /* enable mouse interrupt */ #define KC8_KENABLE 0x01 /* enable keyboard interrupt */ #define CMDBYTE (KC8_TRANS|KC8_CPU|KC8_MENABLE|KC8_KENABLE) /* keyboard commands */ #define KBC_RESET 0xFF /* reset the keyboard */ #define KBC_RESEND 0xFE /* request the keyboard resend the last byte */ #define KBC_ONEKEY_MB 0xFC /* make one key make/break */ #define KBC_ALLKEYS_TMB 0xFA /* make all keys typematic/make/break */ #define KBC_SETDEFAULT 0xF6 /* resets keyboard to its power-on defaults */ #define KBC_DISABLE 0xF5 /* as per KBC_SETDEFAULT, but also disable key scanning */ #define KBC_ENABLE 0xF4 /* enable key scanning */ #define KBC_TYPEMATIC 0xF3 /* set typematic rate and delay */ #define KBC_GETID 0xF2 /* get keyboard id */ #define KBC_SETTABLE 0xF0 /* set scancode translation table */ #define KBC_ECHO 0xEE /* request an echo from the keyboard */ #define KBC_MODEIND 0xED /* set mode indicators (i.e. LEDs) */ /* keyboard responses */ #define KBR_EXTENDED 0xE0 /* extended key sequence */ #define KBR_RESEND 0xFE /* needs resend of command */ #define KBR_ACK 0xFA /* received a valid command */ #define KBR_OVERRUN 0x00 /* flooded */ #define KBR_FAILURE 0xFD /* diagnosic failure */ #define KBR_BREAK 0xF0 /* break code prefix - sent on key release */ #define KBR_RSTDONE 0xAA /* reset complete */ #define KBR_ECHO 0xEE /* echo response */ #endif /* __KBDREG_H */ gxemul-0.6.1/src/include/thirdparty/wdcreg.h000644 001750 001750 00000020635 13402411502 021263 0ustar00debugdebug000000 000000 /* $NetBSD: wdcreg.h,v 1.25 2002/03/31 19:47:39 bouyer Exp $ */ #ifndef WDCREG_H #define WDCREG_H /*- * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)wdreg.h 7.1 (Berkeley) 5/9/91 */ /* * Disk Controller register definitions. */ /* offsets of registers in the 'regular' register region */ #define wd_data 0 /* data register (R/W - 16 bits) */ #define wd_error 1 /* error register (R) */ #define wd_precomp 1 /* write precompensation (W) */ #define wd_features 1 /* features (W), same as wd_precomp */ #define wd_seccnt 2 /* sector count (R/W) */ #define wd_ireason 2 /* interrupt reason (R/W) (for atapi) */ #define wd_sector 3 /* first sector number (R/W) */ #define wd_cyl_lo 4 /* cylinder address, low byte (R/W) */ #define wd_cyl_hi 5 /* cylinder address, high byte (R/W) */ #define wd_sdh 6 /* sector size/drive/head (R/W) */ #define wd_command 7 /* command register (W) */ #define wd_status 7 /* immediate status (R) */ #define wd_lba_lo 3 /* lba address, low byte (RW) */ #define wd_lba_mi 4 /* lba address, middle byte (RW) */ #define wd_lba_hi 5 /* lba address, high byte (RW) */ /* offsets of registers in the auxiliary register region */ #define wd_aux_altsts 0 /* alternate fixed disk status (R) */ #define wd_aux_ctlr 0 /* fixed disk controller control (W) */ #define WDCTL_4BIT 0x08 /* use four head bits (wd1003) */ #define WDCTL_RST 0x04 /* reset the controller */ #define WDCTL_IDS 0x02 /* disable controller interrupts */ #if 0 /* NOT MAPPED; fd uses this register on PCs */ #define wd_digin 1 /* disk controller input (R) */ #endif /* * Status bits. */ #define WDCS_BSY 0x80 /* busy */ #define WDCS_DRDY 0x40 /* drive ready */ #define WDCS_DWF 0x20 /* drive write fault */ #define WDCS_DSC 0x10 /* drive seek complete */ #define WDCS_DRQ 0x08 /* data request */ #define WDCS_CORR 0x04 /* corrected data */ #define WDCS_IDX 0x02 /* index */ #define WDCS_ERR 0x01 /* error */ #define WDCS_BITS \ "\020\010bsy\007drdy\006dwf\005dsc\004drq\003corr\002idx\001err" /* * Error bits. */ #define WDCE_BBK 0x80 /* bad block detected */ #define WDCE_CRC 0x80 /* CRC error (Ultra-DMA only) */ #define WDCE_UNC 0x40 /* uncorrectable data error */ #define WDCE_MC 0x20 /* media changed */ #define WDCE_IDNF 0x10 /* id not found */ #define WDCE_MCR 0x08 /* media change requested */ #define WDCE_ABRT 0x04 /* aborted command */ #define WDCE_TK0NF 0x02 /* track 0 not found */ #define WDCE_AMNF 0x01 /* address mark not found */ /* * Commands for Disk Controller. */ #define WDCC_NOP 0x00 /* Always fail with "aborted command" */ #define WDCC_RECAL 0x10 /* disk restore code -- resets cntlr */ #define WDCC_READ 0x20 /* disk read code */ #define WDCC_WRITE 0x30 /* disk write code */ #define WDCC__LONG 0x02 /* modifier -- access ecc bytes */ #define WDCC__NORETRY 0x01 /* modifier -- no retrys */ #define WDCC_FORMAT 0x50 /* disk format code */ #define WDCC_DIAGNOSE 0x90 /* controller diagnostic */ #define WDCC_IDP 0x91 /* initialize drive parameters */ #define WDCC_SMART 0xb0 /* Self Mon, Analysis, Reporting Tech */ #define WDCC_READMULTI 0xc4 /* read multiple */ #define WDCC_WRITEMULTI 0xc5 /* write multiple */ #define WDCC_SETMULTI 0xc6 /* set multiple mode */ #define WDCC_READDMA 0xc8 /* read with DMA */ #define WDCC_WRITEDMA 0xca /* write with DMA */ #define WDCC_ACKMC 0xdb /* acknowledge media change */ #define WDCC_LOCK 0xde /* lock drawer */ #define WDCC_UNLOCK 0xdf /* unlock drawer */ #define WDCC_FLUSHCACHE 0xe7 /* Flush cache */ #define WDCC_IDENTIFY 0xec /* read parameters from controller */ #define SET_FEATURES 0xef /* set features */ #define WDCC_IDLE 0xe3 /* set idle timer & enter idle mode */ #define WDCC_IDLE_IMMED 0xe1 /* enter idle mode */ #define WDCC_SLEEP 0xe6 /* enter sleep mode */ #define WDCC_STANDBY 0xe2 /* set standby timer & enter standby */ #define WDCC_STANDBY_IMMED 0xe0 /* enter standby mode */ #define WDCC_CHECK_PWR 0xe5 /* check power mode */ #define WDCC_SEC_SET_PASSWORD 0xf1 /* set user or master password */ #define WDCC_SEC_UNLOCK 0xf2 /* authenticate */ #define WDCC_SEC_ERASE_PREPARE 0xf3 /* enable device erasing */ #define WDCC_SEC_ERASE_UNIT 0xf4 /* erase all user data */ #define WDCC_SEC_FREEZE_LOCK 0xf5 /* prevent password changes */ #define WDCC_SEC_DISABLE_PASSWORD 0xf6 /* disable lock mode */ /* * Big Drive support */ #define WDCC_READ_EXT 0x24 /* read 48-bit addressing */ #define WDCC_WRITE_EXT 0x34 /* write 48-bit addressing */ #define WDCC_READMULTI_EXT 0x29 /* read multiple 48-bit addressing */ #define WDCC_WRITEMULTI_EXT 0x39 /* write multiple 48-bit addressing */ #define WDCC_READDMA_EXT 0x25 /* read 48-bit addressing with DMA */ #define WDCC_WRITEDMA_EXT 0x35 /* write 48-bit addressing with DMA */ /* Subcommands for SET_FEATURES (features register) */ #define WDSF_EN_WR_CACHE 0x02 #define WDSF_SET_MODE 0x03 #define WDSF_REASSIGN_EN 0x04 #define WDSF_RETRY_DS 0x33 #define WDSF_SET_CACHE_SGMT 0x54 #define WDSF_READAHEAD_DS 0x55 #define WDSF_POD_DS 0x66 #define WDSF_ECC_DS 0x77 #define WDSF_WRITE_CACHE_DS 0x82 #define WDSF_REASSIGN_DS 0x84 #define WDSF_ECC_EN 0x88 #define WDSF_RETRY_EN 0x99 #define WDSF_SET_CURRENT 0x9a #define WDSF_READAHEAD_EN 0xaa #define WDSF_PREFETCH_SET 0xab #define WDSF_POD_EN 0xcc /* Subcommands for SMART (features register) */ #define WDSM_RD_DATA 0xd0 #define WDSM_ATTR_AUTOSAVE_EN 0xd2 #define WDSM_SAVE_ATTR 0xd3 #define WDSM_EXEC_OFFL_IMM 0xd4 #define WDSM_ENABLE_OPS 0xd8 #define WDSM_DISABLE_OPS 0xd9 #define WDSM_STATUS 0xda #define WDSMART_CYL_LO 0x4f #define WDSMART_CYL_HI 0xc2 /* parameters uploaded to device/heads register */ #define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */ #define WDSD_CHS 0x00 /* cylinder/head/sector addressing */ #define WDSD_LBA 0x40 /* logical block addressing */ /* Commands for ATAPI devices */ #define ATAPI_CHECK_POWER_MODE 0xe5 #define ATAPI_EXEC_DRIVE_DIAGS 0x90 #define ATAPI_IDLE_IMMEDIATE 0xe1 #define ATAPI_NOP 0x00 #define ATAPI_PKT_CMD 0xa0 #define ATAPI_IDENTIFY_DEVICE 0xa1 #define ATAPI_SOFT_RESET 0x08 #define ATAPI_SLEEP 0xe6 #define ATAPI_STANDBY_IMMEDIATE 0xe0 /* Bytes used by ATAPI_PACKET_COMMAND ( feature register) */ #define ATAPI_PKT_CMD_FTRE_DMA 0x01 #define ATAPI_PKT_CMD_FTRE_OVL 0x02 /* ireason */ #define WDCI_CMD 0x01 /* command(1) or data(0) */ #define WDCI_IN 0x02 /* transfer to(1) or from(0) the host */ #define WDCI_RELEASE 0x04 /* bus released until completion */ #define PHASE_CMDOUT (WDCS_DRQ | WDCI_CMD) #define PHASE_DATAIN (WDCS_DRQ | WDCI_IN) #define PHASE_DATAOUT (WDCS_DRQ) #define PHASE_COMPLETED (WDCI_IN | WDCI_CMD) #define PHASE_ABORTED (0) #endif /* WDCREG_H */ gxemul-0.6.1/src/include/thirdparty/dec_kn03.h000644 001750 001750 00000022356 13402411502 021400 0ustar00debugdebug000000 000000 /* gxemul: $Id: dec_kn03.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ /* The IOASIC stuff below seems to be using 0x40000 per slot */ /* $NetBSD: kn03.h,v 1.10 2000/02/29 04:41:57 nisimura Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * The Mach Operating System project at Carnegie-Mellon University, * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)kn03.h 8.1 (Berkeley) 6/10/93 */ /* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * Definitions specific to the KN03GA processors and 3MAX+ * DECstation 5000/240 mother board. */ #ifndef MIPS_KN03_H #define MIPS_KN03_H 1 /* * 3MAX+'s Physical address space */ #define KN03_PHYS_MIN 0x00000000 /* 512 Meg */ #define KN03_PHYS_MAX 0x1fffffff /* * Memory map */ #define KN03_PHYS_MEMORY_START 0x00000000 #define KN03_PHYS_MEMORY_END 0x1dffffff /* 480 Meg */ /* * I/O map */ #define KN03_PHYS_TC_0_START 0x1e000000 /* TURBOchannel, slot 0 */ #define KN03_PHYS_TC_0_END 0x1e7fffff /* 8 Meg, option0 */ #define KN03_PHYS_TC_1_START 0x1e800000 /* TURBOchannel, slot 1 */ #define KN03_PHYS_TC_1_END 0x1effffff /* 8 Meg, option1 */ #define KN03_PHYS_TC_2_START 0x1f000000 /* TURBOchannel, slot 2 */ #define KN03_PHYS_TC_2_END 0x1f7fffff /* 8 Meg, option2 */ #define KN03_PHYS_TC_3_START 0x1f800000 /* TURBOchannel, slot 3 */ #define KN03_PHYS_TC_3_END 0x1fffffff /* 8 Meg, system devices */ #define KN03_PHYS_TC_START KN03_PHYS_TC_0_START #define KN03_PHYS_TC_END KN03_PHYS_TC_3_END #define KN03_TC_NSLOTS 4 #define KN03_TC_MIN 0 #define KN03_TC_MAX 2 /* don't look at system slot */ /* * System module space (IOASIC) */ #define KN03_SYS_ASIC ( KN03_PHYS_TC_3_START + 0x0000000 ) #define KN03_SYS_ROM_START ( KN03_SYS_ASIC + IOASIC_SLOT_0_START ) #define KN03_SYS_ASIC_REGS ( KN03_SYS_ASIC + IOASIC_SLOT_1_START ) #define KN03_SYS_ETHER_ADDRESS ( KN03_SYS_ASIC + IOASIC_SLOT_2_START ) #define KN03_SYS_LANCE ( KN03_SYS_ASIC + IOASIC_SLOT_3_START ) #define KN03_SYS_SCC_0 ( KN03_SYS_ASIC + IOASIC_SLOT_4_START ) #define KN03_SYS_SCC_1 ( KN03_SYS_ASIC + IOASIC_SLOT_6_START ) #define KN03_SYS_CLOCK ( KN03_SYS_ASIC + IOASIC_SLOT_8_START ) #define KN03_SYS_ERRADR ( KN03_SYS_ASIC + IOASIC_SLOT_9_START ) #define KN03_SYS_ERRSYN ( KN03_SYS_ASIC + IOASIC_SLOT_10_START ) #define KN03_SYS_CSR ( KN03_SYS_ASIC + IOASIC_SLOT_11_START ) #define KN03_SYS_SCSI ( KN03_SYS_ASIC + IOASIC_SLOT_12_START ) #define KN03_SYS_SCSI_DMA ( KN03_SYS_ASIC + IOASIC_SLOT_14_START ) #define KN03_SYS_BOOT_ROM_START ( KN03_PHYS_TC_3_START + 0x400000 ) #define KN03_SYS_BOOT_ROM_END ( KN03_PHYS_TC_3_START + 0x43ffff ) /* * Interrupts */ #define KN03_INT_FPA IP_LEV7 /* Floating Point coproc */ #define KN03_INT_HALTB IP_LEV6 /* Halt button */ #define KN03_INT_MEM IP_LEV5 /* Memory Errors */ #define KN03_INT_RTC IP_LEV3 /* RTC clock */ #define KN03_INT_ASIC IP_LEV2 /* All turbochannel */ #define KN03_REG_SCSI_DMAPTR ( KN03_SYS_ASIC + IOASIC_SCSI_DMAPTR ) #define KN03_REG_SCSI_DMANPTR ( KN03_SYS_ASIC + IOASIC_SCSI_NEXTPTR ) #define KN03_REG_LANCE_DMAPTR ( KN03_SYS_ASIC + IOASIC_LANCE_DMAPTR ) #define KN03_REG_SCC_T1_DMAPTR ( KN03_SYS_ASIC + IOASIC_SCC_T1_DMAPTR ) #define KN03_REG_SCC_R1_DMAPTR ( KN03_SYS_ASIC + IOASIC_SCC_R1_DMAPTR ) #define KN03_REG_SCC_T2_DMAPTR ( KN03_SYS_ASIC + IOASIC_SCC_T2_DMAPTR ) #define KN03_REG_SCC_R2_DMAPTR ( KN03_SYS_ASIC + IOASIC_SCC_R2_DMAPTR ) #define KN03_REG_CSR ( KN03_SYS_ASIC + IOASIC_CSR ) #define KN03_REG_INTR ( KN03_SYS_ASIC + IOASIC_INTR ) #define KN03_REG_IMSK ( KN03_SYS_ASIC + IOASIC_IMSK ) #define KN03_REG_CURADDR ( KN03_SYS_ASIC + IOASIC_CURADDR ) #define KN03_REG_LANCE_DECODE ( KN03_SYS_ASIC + IOASIC_LANCE_DECODE ) #define KN03_REG_SCSI_DECODE ( KN03_SYS_ASIC + IOASIC_SCSI_DECODE ) #define KN03_REG_SCC0_DECODE ( KN03_SYS_ASIC + IOASIC_SCC0_DECODE ) #define KN03_REG_SCC1_DECODE ( KN03_SYS_ASIC + IOASIC_SCC1_DECODE ) # define KN03_LANCE_CONFIG 3 # define KN03_SCSI_CONFIG 14 # define KN03_SCC0_CONFIG (0x10|4) # define KN03_SCC1_CONFIG (0x10|6) #define KN03_REG_SCSI_SCR ( KN03_SYS_ASIC + IOASIC_SCSI_SCR ) #define KN03_REG_SCSI_SDR0 ( KN03_SYS_ASIC + IOASIC_SCSI_SDR0 ) #define KN03_REG_SCSI_SDR1 ( KN03_SYS_ASIC + IOASIC_SCSI_SDR1 ) /* NOTES Memory access priority is, from higher to lower: - DRAM refresh - IO DMA (IO Control ASIC) - Slot 2 DMA - Slot 1 DMA - Slot 0 DMA - Processor */ /* * More system registers defines (IO Control ASIC) */ /* (re)defines for the system Status and Control register (SSR) */ /* high-order 16 bits 0xFFFF0000 same on all DECstation IOASICs */ #define KN03_CSR_LEDS 0x000000ff /* rw */ #define KN03_CSR_BNK32M 0x00000400 /* rw Memory bank stride */ #define KN03_CSR_CORRECT 0x00002000 /* rw ECC corrects single bit */ #define KN03_CSR_ECCMD 0x0000c000 /* rw ECC logic mode */ /* (re)defines for the System Interrupt and Mask Registers */ /* high-order 16 bits 0xFFFF0000 same on all DECstation IOASICs */ #define KN03_INTR_PBNO 0x00000001 /* ro */ #define KN03_INTR_PBNC 0x00000002 /* ro */ #define KN03_INTR_SCSI_FIFO 0x00000004 /* ro */ #define KN03_INTR_PSWARN 0x00000010 /* ro */ #define KN03_INTR_CLOCK 0x00000020 /* ro */ #define KN03_INTR_SCC_0 0x00000040 /* ro */ #define KN03_INTR_SCC_1 0x00000080 /* ro */ #define KN03_INTR_LANCE 0x00000100 /* ro */ #define KN03_INTR_SCSI 0x00000200 /* ro */ #define KN03_INTR_NRMOD_JUMPER 0x00000400 /* ro */ #define KN03_INTR_TC_0 0x00000800 /* ro */ #define KN03_INTR_TC_1 0x00001000 /* ro */ #define KN03_INTR_TC_2 0x00002000 /* ro */ #define KN03_INTR_NVR_JUMPER 0x00004000 /* ro */ #define KN03_INTR_PROD_JUMPER 0x00008000 /* ro */ #define KN03_INTR_ASIC 0xff0f0004 #define KN03_IM0 0xff0f3bf0 /* all good ones enabled */ /* * Error Address Register Bit Definitions */ #define KN03_ERR_ADDRESS 0x07ffffff /* phys address */ #define KN03_ERR_RESERVED 0x08000000 /* unused */ #define KN03_ERR_ECCERR 0x10000000 /* ECC error */ #define KN03_ERR_WRITE 0x20000000 /* read/write transaction */ #define KN03_ERR_CPU 0x40000000 /* CPU or device initiator */ #define KN03_ERR_VALID 0x80000000 /* Info is valid */ /* ECC check/syndrome status register */ #define KN03_ECC_SYNLO 0x0000007f /* syndrome, even bank */ #define KN03_ECC_SNGLO 0x00000080 /* single bit err, " */ #define KN03_ECC_CHKLO 0x00007f00 /* check bits, " " */ #define KN03_ECC_VLDLO 0x00008000 /* info valid for " */ #define KN03_ECC_SYNHI 0x007f0000 /* syndrome, odd bank */ #define KN03_ECC_SNGHI 0x00800000 /* single bit err, " */ #define KN03_ECC_CHKHI 0x7f000000 /* check bits, " " */ #define KN03_ECC_VLDHI 0x80000000 /* info valid for " */ #endif /* MIPS_KN03_H */ gxemul-0.6.1/src/include/thirdparty/debug_new.h000644 001750 001750 00000011055 13402411502 021743 0ustar00debugdebug000000 000000 /* * Modified for GXemul: * * 1. Better Doxygen comment for class __debug_new_counter. */ // -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- // vim:tabstop=4:shiftwidth=4:expandtab: /* * Copyright (C) 2004-2005 Wu Yongwei * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any * damages arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute * it freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must * not claim that you wrote the original software. If you use this * software in a product, an acknowledgment in the product * documentation would be appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must * not be misrepresented as being the original software. * 3. This notice may not be removed or altered from any source * distribution. * * This file is part of Stones of Nvwa: * http://sourceforge.net/projects/nvwa * */ /** * @file debug_new.h * * Header file for checking leaks caused by unmatched new/delete. * * @version 3.4, 2005/09/13 * @author Wu Yongwei * */ #ifndef _DEBUG_NEW_H #define _DEBUG_NEW_H #include #include /** * @def HAS_PLACEMENT_DELETE * * Macro to indicate whether placement delete operators are supported on * a certain compiler. Some compilers, like Borland C++ Compiler 5.5.1 * and Digital Mars Compiler 8.42, do not support them, and the user * must define this macro to \c 0 to make the program compile. Also * note that in that case memory leakage will occur if an exception is * thrown in the initialization (constructor) of a dynamically created * object. */ #ifndef HAS_PLACEMENT_DELETE #define HAS_PLACEMENT_DELETE 1 #endif /** * @def _DEBUG_NEW_REDEFINE_NEW * * Macro to indicate whether redefinition of \c new is wanted. If one * wants to define one's own operator new, to call * operator new directly, or to call placement \c new, it * should be defined to \c 0 to alter the default behaviour. Unless, of * course, one is willing to take the trouble to write something like: * @code * # ifdef new * # define _NEW_REDEFINED * # undef new * # endif * * // Code that uses new is here * * # ifdef _NEW_REDEFINED * # ifdef DEBUG_NEW * # define new DEBUG_NEW * # endif * # undef _NEW_REDEFINED * # endif * @endcode */ #ifndef _DEBUG_NEW_REDEFINE_NEW #define _DEBUG_NEW_REDEFINE_NEW 1 #endif /* Prototypes */ int check_leaks(); void* operator new(size_t size, const char* file, int line); void* operator new[](size_t size, const char* file, int line); #if HAS_PLACEMENT_DELETE void operator delete(void* pointer, const char* file, int line) throw(); void operator delete[](void* pointer, const char* file, int line) throw(); #endif #if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC 6 requires the following declarations; or the non-placement // new[]/delete[] will not compile. void* operator new[](size_t) throw(std::bad_alloc); void operator delete[](void*) throw(); #endif /* Control variables */ extern bool new_autocheck_flag; // default to true: call check_leaks() on exit extern bool new_verbose_flag; // default to false: no verbose information extern FILE* new_output_fp; // default to stderr: output to console extern const char* new_progname;// default to NULL; should be assigned argv[0] /** * @def DEBUG_NEW * * The macro to catch file/line information on allocation. If * #_DEBUG_NEW_REDEFINE_NEW is not defined, one can use this macro * directly; otherwise \c new will be defined to it, and one must use * \c new instead. */ #define DEBUG_NEW new(__FILE__, __LINE__) # if _DEBUG_NEW_REDEFINE_NEW # define new DEBUG_NEW # endif # ifdef _DEBUG_NEW_EMULATE_MALLOC # include # ifdef new # define malloc(s) ((void*)(new char[s])) # else # define malloc(s) ((void*)(DEBUG_NEW char[s])) # endif # define free(p) delete[] (char*)(p) # endif /** * \brief Part of Wu Yongwei's new/delete debug * memory leak detector. * * Counter class for on-exit leakage check. */ class __debug_new_counter { static int _count; public: __debug_new_counter(); ~__debug_new_counter(); }; /** Counting object for each file including debug_new.h. */ static __debug_new_counter __debug_new_count; #endif // _DEBUG_NEW_H gxemul-0.6.1/src/include/thirdparty/dec_maxine.h000644 001750 001750 00000031152 13402411502 022100 0ustar00debugdebug000000 000000 /* gxemul: $Id: dec_maxine.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: maxine.h,v 1.8 2000/02/29 04:41:57 nisimura Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * The Mach Operating System project at Carnegie-Mellon University, * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)maxine.h 8.1 (Berkeley) 6/10/93 */ /* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * HISTORY * Log: maxine.h,v * Revision 2.3 92/04/01 15:14:52 rpd * Defined pseudo slot for mappable timer. * [92/03/11 02:37:41 af] * * Revision 2.2 92/03/02 18:34:28 rpd * Created, from the DEC specs: * "MAXine System Module Functional Specification" Revision 1.2 * Workstation Systems Engineering, Palo Alto, CA. July 15, 1991. * [92/01/17 af] * */ /* * File: maxine.h * Author: Alessandro Forin, Carnegie Mellon University * Date: 1/92 * * Definitions specific to the MAXine system module (54-21325-01) * and compatible processors (KN02BA). */ #ifndef MIPS_XINE_H #define MIPS_XINE_H 1 /* * MAXine's Physical address space */ #define XINE_PHYS_MIN 0x00000000 /* 512 Meg */ #define XINE_PHYS_MAX 0x1fffffff /* * Memory map */ #define XINE_PHYS_MEMORY_START 0x00000000 #define XINE_PHYS_MEMORY_END 0x027fffff /* 40 Meg in 2 slots and baseboard */ /* * I/O map */ #define XINE_PHYS_CFB_START 0x08000000 /* Color Frame Buffer */ #define XINE_PHYS_CFB_END 0x0bffffff /* 64 Meg */ #define XINE_PHYS_MREGS_START 0x0c000000 /* Memory control registers */ #define XINE_PHYS_MREGS_END 0x0dffffff /* 32 Meg */ #define XINE_PHYS_CREGS_START 0x0e000000 /* CPU ASIC control regs */ #define XINE_PHYS_CREGS_END 0x0fffffff /* 32 Meg */ #define XINE_PHYS_TC_0_START 0x10000000 /* TURBOchannel, slot 0 */ #define XINE_PHYS_TC_0_END 0x13ffffff /* 64 Meg, option0 */ #define XINE_PHYS_TC_1_START 0x14000000 /* TURBOchannel, slot 1 */ #define XINE_PHYS_TC_1_END 0x17ffffff /* 64 Meg, option1 */ #define XINE_PHYS_TC_RESERVED 0x18000000 /* Unused slot 2 */ /* 64 Meg */ #define XINE_PHYS_TC_3_START 0x1c000000 /* TURBOchannel, slot 3 */ #define XINE_PHYS_TC_3_END 0x1fffffff /* 64 Meg, system devices */ #define XINE_PHYS_TC_START XINE_PHYS_TC_0_START #define XINE_PHYS_TC_END XINE_PHYS_TC_3_END /* 256 Meg */ #define XINE_TC_NSLOTS 4 #define XINE_TC_MIN 0 #define XINE_TC_MAX 1 /* only option slots */ /* * System module space */ #define XINE_SYS_ASIC (XINE_PHYS_TC_3_START + 0x0000000) #define XINE_SYS_ROM_START (XINE_SYS_ASIC + IOASIC_SLOT_0_START) #define XINE_SYS_ASIC_REGS (XINE_SYS_ASIC + IOASIC_SLOT_1_START) #define XINE_SYS_ETHER_ADDRESS (XINE_SYS_ASIC + IOASIC_SLOT_2_START) #define XINE_SYS_LANCE (XINE_SYS_ASIC + IOASIC_SLOT_3_START) #define XINE_SYS_SCC_0 (XINE_SYS_ASIC + IOASIC_SLOT_4_START) #define XINE_SYS_VDAC_HI (XINE_SYS_ASIC + IOASIC_SLOT_5_START) #define XINE_SYS_VDAC_LO (XINE_SYS_ASIC + IOASIC_SLOT_7_START) #define XINE_SYS_CLOCK (XINE_SYS_ASIC + IOASIC_SLOT_8_START) #define XINE_SYS_ISDN (XINE_SYS_ASIC + IOASIC_SLOT_9_START) #define XINE_SYS_DTOP (XINE_SYS_ASIC + IOASIC_SLOT_10_START) #define XINE_SYS_FLOPPY (XINE_SYS_ASIC + IOASIC_SLOT_11_START) #define XINE_SYS_SCSI (XINE_SYS_ASIC + IOASIC_SLOT_12_START) #define XINE_SYS_FLOPPY_DMA (XINE_SYS_ASIC + IOASIC_SLOT_13_START) #define XINE_SYS_SCSI_DMA (XINE_SYS_ASIC + IOASIC_SLOT_14_START) #define XINE_SYS_BOOT_ROM_START (XINE_PHYS_TC_3_START + 0x3c00000) #define XINE_SYS_BOOT_ROM_END (XINE_PHYS_TC_3_START + 0x3c40000) /* * Interrupts */ #define XINE_INT_FPA IP_LEV7 /* Floating Point coproc */ #define XINE_INT_HALTB IP_LEV6 /* Halt keycode (DTOP) */ #define XINE_INT_TC3 IP_LEV5 /* TC slot 3, system */ #define XINE_INT_TIMEOUT IP_LEV4 /* Timeout on I/O write */ #define XINE_INT_TOY IP_LEV3 /* Clock chip */ #define XINE_INT_1_10_MS IP_LEV2 /* Periodic interrupt */ /* * System registers addresses (MREG and CREG space, and IO Control ASIC) */ #define XINE_REG_CMR 0x0c000000 /* Color mask register */ #define XINE_REG_MER 0x0c400000 /* Memory error register */ #define XINE_REG_MSR 0x0c800000 /* Memory size register */ #define XINE_REG_FCTR 0x0ca00000 /* 1us free running counter */ #define XINE_REG_FI 0x0cc00000 /* FI signal polarity (1!) */ #define XINE_REG_CNFG 0x0e000000 /* Config mem timeouts */ #define XINE_REG_AER 0x0e000004 /* Address error register */ #define XINE_REG_TIMEOUT 0x0e00000c /* I/O write timeout reg */ #define XINE_REG_SCSI_DMAPTR ( XINE_SYS_ASIC + IOASIC_SCSI_DMAPTR ) #define XINE_REG_SCSI_DMANPTR ( XINE_SYS_ASIC + IOASIC_SCSI_NEXTPTR ) #define XINE_REG_LANCE_DMAPTR ( XINE_SYS_ASIC + IOASIC_LANCE_DMAPTR ) #define XINE_REG_SCC_T1_DMAPTR ( XINE_SYS_ASIC + IOASIC_SCC_T1_DMAPTR ) #define XINE_REG_SCC_R1_DMAPTR ( XINE_SYS_ASIC + IOASIC_SCC_R1_DMAPTR ) #define XINE_REG_DTOP_T_DMAPTR ( XINE_SYS_ASIC + IOASIC_SCC_T2_DMAPTR ) #define XINE_REG_DTOP_R_DMAPTR ( XINE_SYS_ASIC + IOASIC_SCC_R2_DMAPTR ) #define XINE_FLOPPY_DMAPTR ( XINE_SYS_ASIC + IOASIC_FLOPPY_DMAPTR ) #define XINE_ISDN_X_DMAPTR ( XINE_SYS_ASIC + IOASIC_ISDN_X_DMAPTR ) #define XINE_ISDN_X_NEXTPTR ( XINE_SYS_ASIC + IOASIC_ISDN_X_NEXTPTR ) #define XINE_ISDN_R_DMAPTR ( XINE_SYS_ASIC + IOASIC_ISDN_R_DMAPTR ) #define XINE_ISDN_R_NEXTPTR ( XINE_SYS_ASIC + IOASIC_ISDN_R_NEXTPTR ) #define XINE_REG_CSR ( XINE_SYS_ASIC + IOASIC_CSR ) #define XINE_REG_INTR ( XINE_SYS_ASIC + IOASIC_INTR ) #define XINE_REG_IMSK ( XINE_SYS_ASIC + IOASIC_IMSK ) #define XINE_REG_CURADDR ( XINE_SYS_ASIC + IOASIC_CURADDR ) #define XINE_ISDN_X_DATA ( XINE_SYS_ASIC + IOASIC_ISDN_X_DATA ) #define XINE_ISDN_R_DATA ( XINE_SYS_ASIC + IOASIC_ISDN_R_DATA ) #define XINE_REG_LANCE_DECODE ( XINE_SYS_ASIC + IOASIC_LANCE_DECODE ) #define XINE_REG_SCSI_DECODE ( XINE_SYS_ASIC + IOASIC_SCSI_DECODE ) #define XINE_REG_SCC0_DECODE ( XINE_SYS_ASIC + IOASIC_SCC0_DECODE ) #define XINE_REG_DTOP_DECODE ( XINE_SYS_ASIC + IOASIC_SCC1_DECODE ) #define XINE_REG_FLOPPY_DECODE ( XINE_SYS_ASIC + IOASIC_FLOPPY_DECODE ) # define XINE_LANCE_CONFIG 3 # define XINE_SCSI_CONFIG 14 # define XINE_SCC0_CONFIG (0x10|4) # define XINE_DTOP_CONFIG 10 # define XINE_FLOPPY_CONFIG 13 #define XINE_REG_SCSI_SCR ( XINE_SYS_ASIC + IOASIC_SCSI_SCR ) #define XINE_REG_SCSI_SDR0 ( XINE_SYS_ASIC + IOASIC_SCSI_SDR0 ) #define XINE_REG_SCSI_SDR1 ( XINE_SYS_ASIC + IOASIC_SCSI_SDR1 ) /* * System registers defines (MREG and CREG) */ /* Memory error register */ #define XINE_MER_xxx 0xf7fe30ff /* undefined */ #define XINE_MER_10_1_MS_IP 0x08000000 /* rw: Periodic interrupt */ #define XINE_MER_PAGE_BRY 0x00010000 /* rw: Page boundary error */ #define XINE_MER_TLEN 0x00008000 /* rw: Xfer length error */ #define XINE_MER_PARDIS 0x00004000 /* rw: Dis parity err intr */ #define XINE_MER_LASTBYTE 0x00000f00 /* rz: Last byte in error: */ # define XINE_LASTB31 0x00000800 /* upper byte of word */ # define XINE_LASTB23 0x00000400 /* .. through .. */ # define XINE_LASTB15 0x00000200 /* .. the .. */ # define XINE_LASTB07 0x00000100 /* .. lower byte */ /* Memory size register */ #define XINE_MSR_xxx 0xffffdfff /* undefined */ #define XINE_MSR_10_1_MS_EN 0x04000000 /* rw: enable periodic intr */ #define XINE_MSR_10_1_MS 0x02000000 /* rw: intr. freq. (0->1ms) */ #define XINE_MSR_PFORCE 0x01e00000 /* rw: force parity errors */ #define XINE_MSR_MABEN 0x00100000 /* rw: VRAM ignores SIZE */ #define XINE_MSR_LAST_BANK 0x000e0000 /* rw: map baseboard mem */ # define XINE_BANK_0 0x00020000 /* .. at bank 0, .. */ # define XINE_BANK_1 0x00040000 /* .. at bank 1, .. */ # define XINE_BANK_2 0x00080000 /* .. or at bank 2 */ #define XINE_MSR_SIZE_16Mb 0x00002000 /* rw: using 16Mb mem banks */ /* FI register */ #define XINE_FI_VALUE 0x00001000 /* NOTES Memory access priority is, from higher to lower: - VRAM/DRAM refresh - IO DMA (IO Control ASIC) - Slot 0 DMA - Processor - Slot 1 DMA Memory performance is (with 80ns mem cycles) - single word read 5 cyc 10.0 Mb/s - word write 3 cyc 16.7 Mb/s - single byte write 3 cyc 4.2 Mb/s - 64w DMA read 68 cyc 47.1 Mb/s - 64w DMA write 66 cyc 48.5 Mb/s - Refresh 5 cyc N/A */ /* Timeout config register */ #define XINE_CNFG_VALUE 121 /* Address error register */ #define XINE_AER_ADDR_MASK 0x1ffffffc /* ro: phys addr in error */ /* Memory access timeout interrupt register */ #define XINE_TIMEO_INTR 0x00000001 /* rc: intr pending */ /* * More system registers defines (IO Control ASIC) */ /* (re)defines for the system Status and Control register (SSR) */ /* high-order 16 bits 0xFFFF0000 same on all DECstation IOASICs */ #define XINE_CSR_DIAGDN 0x00008000 /* rw */ #define XINE_CSR_ISDN_ENABLE 0x00001000 /* rw */ #define XINE_CSR_SCC_ENABLE 0x00000800 /* rw */ #define XINE_CSR_RTC_ENABLE 0x00000400 /* rw */ #define XINE_CSR_SCSI_ENABLE 0x00000200 /* rw */ #define XINE_CSR_LANCE_ENABLE 0x00000100 /* rw */ #define XINE_CSR_FLOPPY_ENABLE 0x00000080 /* rw */ #define XINE_CSR_VDAC_ENABLE 0x00000040 /* rw */ #define XINE_CSR_DTOP_ENABLE 0x00000020 /* rw */ #define XINE_CSR_LED 0x00000001 /* rw */ /* (re)defines for the System Interrupt and Mask Registers */ /* high-order 16 bits 0xFFFF0000 same on all DECstation IOASICs */ #define XINE_INTR_xxxx 0x00002808 /* ro */ #define XINE_INTR_FLOPPY 0x00008000 /* ro */ #define XINE_INTR_NVR_JUMPER 0x00004000 /* ro */ #define XINE_INTR_POWERUP 0x00002000 /* ro */ #define XINE_INTR_TC_0 0x00001000 /* ro */ #define XINE_INTR_ISDN 0x00000800 /* ro */ #define XINE_INTR_NRMOD_JUMPER 0x00000400 /* ro */ #define XINE_INTR_SCSI 0x00000200 /* ro */ #define XINE_INTR_LANCE 0x00000100 /* ro */ #define XINE_INTR_FLOPPY_HDS 0x00000080 /* ro */ #define XINE_INTR_SCC_0 0x00000040 /* ro */ #define XINE_INTR_TC_1 0x00000020 /* ro */ #define XINE_INTR_FLOPPY_XDS 0x00000010 /* ro */ #define XINE_INTR_VINT 0x00000008 /* ro */ #define XINE_INTR_N_VINT 0x00000004 /* ro */ #define XINE_INTR_DTOP_TX 0x00000002 /* ro */ #define XINE_INTR_DTOP_RX 0x00000001 /* ro */ #define XINE_INTR_ASIC 0xffff0000 #define XINE_INTR_DTOP 0x00000003 #define XINE_IM0 0xffff9b6b /* all good ones enabled */ #endif /* MIPS_XINE_H */ gxemul-0.6.1/src/include/thirdparty/mvmeprom.h000644 001750 001750 00000011242 13402411502 021644 0ustar00debugdebug000000 000000 /* $OpenBSD: prom.h,v 1.16 2006/05/16 22:51:28 miod Exp $ */ /* * Copyright (c) 1998 Steve Murphree, Jr. * Copyright (c) 1996 Nivas Madhur * Copyright (c) 1995 Theo de Raadt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __MACHINE_PROM_H__ #define __MACHINE_PROM_H__ /* BUG trap vector */ #define MVMEPROM_VECTOR 496 #define MVMEPROM_INCHR 0x00 #define MVMEPROM_INSTAT 0x01 #define MVMEPROM_INLN 0x02 #define MVMEPROM_READSTR 0x03 #define MVMEPROM_READLN 0x04 #define MVMEPROM_DSKRD 0x10 #define MVMEPROM_DSKWR 0x11 #define MVMEPROM_DSKCFIG 0x12 #define MVMEPROM_DSKFMT 0x14 #define MVMEPROM_DSKCTRL 0x15 #define MVMEPROM_NETFOPEN 0x1b #define MVMEPROM_NETFREAD 0x1c #define MVMEPROM_NETCTRL 0x1d #define MVMEPROM_OUTCHR 0x20 #define MVMEPROM_OUTSTR 0x21 #define MVMEPROM_OUTSTRCRLF 0x22 #define MVMEPROM_WRITE 0x23 #define MVMEPROM_WRITELN 0x24 #define MVMEPROM_OUTCRLF 0x26 #define MVMEPROM_DELAY 0x43 #define MVMEPROM_RTC_RD 0x53 #define MVMEPROM_EXIT 0x63 #define MVMEPROM_GETBRDID 0x70 #define MVMEPROM_ENVIRON 0x71 #define MVMEPROM_FORKMPU 0x100 #define NETCTRLCMD_GETETHER 1 #define ENVIRONCMD_WRITE 1 #define ENVIRONCMD_READ 2 #define ENVIRONTYPE_EOL 0 #define ENVIRONTYPE_START 1 #define ENVIRONTYPE_DISKBOOT 2 #define ENVIRONTYPE_ROMBOOT 3 #define ENVIRONTYPE_NETBOOT 4 #define ENVIRONTYPE_MEMSIZE 5 #define FORKMPU_NOT_IDLE -1 #define FORKMPU_BAD_ADDRESS -2 #define FORKMPU_NO_MPU -3 struct mvmeprom_netctrl { uint8_t ctrl; uint8_t dev; uint16_t status; uint32_t cmd; uint32_t addr; uint32_t len; uint32_t flags; }; struct mvmeprom_netfopen { uint8_t ctrl; uint8_t dev; uint16_t status; char filename[64]; }; struct mvmeprom_netfread { uint8_t ctrl; uint8_t dev; uint16_t status; uint32_t addr; uint16_t bytes; uint16_t blk; uint32_t timeout; }; struct prom_environ_hdr { uint8_t type; uint8_t len; }; struct mvmeprom_brdid { uint32_t eye_catcher; uint8_t rev; uint8_t month; uint8_t day; uint8_t year; uint16_t size; uint16_t rsv1; uint16_t model; uint8_t suffix[2]; uint16_t options; uint8_t family; uint8_t cpu; uint16_t ctrlun; uint16_t devlun; uint16_t devtype; uint16_t devnum; uint32_t bug; uint8_t version[4]; uint8_t serial[12]; /* SBC serial number */ uint8_t id[16]; /* SBC id */ uint8_t pwa[16]; /* printed wiring assembly number */ uint8_t speed[4]; /* cpu speed */ uint8_t etheraddr[6]; /* mac address, all zero if no ether */ uint8_t fill[2]; uint8_t scsiid[2]; /* local SCSI id */ uint8_t sysid[8]; /* system id - nothing on mvme187 */ uint8_t brd1_pwb[8]; /* memory board 1 pwb */ uint8_t brd1_serial[8]; /* memory board 1 serial */ uint8_t brd2_pwb[8]; /* memory board 2 pwb */ uint8_t brd2_serial[8]; /* memory board 2 serial */ uint8_t reserved[153]; uint8_t cksum[1]; }; struct mvmeprom_time { uint8_t year_BCD; uint8_t month_BCD; uint8_t day_BCD; uint8_t wday_BCD; uint8_t hour_BCD; uint8_t min_BCD; uint8_t sec_BCD; uint8_t cal_BCD; }; struct mvmeprom_dskio { uint8_t ctrl_lun; uint8_t dev_lun; uint16_t status; uint32_t pbuffer; uint32_t blk_num; uint16_t blk_cnt; uint8_t flag; #define BUG_FILE_MARK 0x80 #define IGNORE_FILENUM 0x02 #define END_OF_FILE 0x01 uint8_t addr_mod; }; #define MVMEPROM_BLOCK_SIZE 256 #endif /* __MACHINE_PROM_H__ */ gxemul-0.6.1/src/include/thirdparty/ps2_dmacreg.h000644 001750 001750 00000043220 13402411502 022171 0ustar00debugdebug000000 000000 #ifndef PS2_DMACREG_H #define PS2_DMACREG_H /* gxemul: MIPS_PHYS_TO_KSEG1 has been changed to PS2_PHYS_TO_KSEG1. */ #define PS2_PHYS_TO_KSEG1(x) (x - 0x10008000) /* $NetBSD: dmacreg.h,v 1.1 2001/10/16 15:38:36 uch Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by UCHIYAMA Yasushi. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ typedef uint64_t dmatag_t; #define DMAC_BLOCK_SIZE 16 #define DMAC_SLICE_SIZE 128 #define DMAC_TRANSFER_QWCMAX 0xffff /* all register length are 32bit */ #define DMAC_REGBASE PS2_PHYS_TO_KSEG1(0x10008000) #define DMAC_REGSIZE 0x00010000 /* * DMAC common registers. */ #define D_CTRL_REG PS2_PHYS_TO_KSEG1(0x1000e000) /* DMA control */ #define D_STAT_REG PS2_PHYS_TO_KSEG1(0x1000e010) /* interrupt status */ #define D_PCR_REG PS2_PHYS_TO_KSEG1(0x1000e020) /* priority control */ #define D_SQWC_REG PS2_PHYS_TO_KSEG1(0x1000e030) /* interleave size */ #define D_RBOR_REG PS2_PHYS_TO_KSEG1(0x1000e040) /* ring buffer addr */ #define D_RBSR_REG PS2_PHYS_TO_KSEG1(0x1000e050) /* ring buffer size */ #define D_STADR_REG PS2_PHYS_TO_KSEG1(0x1000e060) /* stall address */ #define D_ENABLER_REG PS2_PHYS_TO_KSEG1(0x1000f520) /* DMA enable (r) */ #define D_ENABLEW_REG PS2_PHYS_TO_KSEG1(0x1000f590) /* DMA enable (w) */ /* * Channel registers. (10ch) */ #define DMA_CH_VIF0 0 /* to (priority 0) */ #define DMA_CH_VIF1 1 /* both */ #define DMA_CH_GIF 2 /* to */ #define DMA_CH_FROMIPU 3 #define DMA_CH_TOIPU 4 #define DMA_CH_SIF0 5 /* from */ #define DMA_CH_SIF1 6 /* to */ #define DMA_CH_SIF2 7 /* both (priority 1) */ #define DMA_CH_FROMSPR 8 /* burst channel */ #define DMA_CH_TOSPR 9 /* burst channel */ #define DMA_CH_VALID(x) (((x) >= 0) && ((x) <= 9)) #define D_CHCR_OFS 0x00 #define D_MADR_OFS 0x10 #define D_QWC_OFS 0x20 #define D_TADR_OFS 0x30 #define D_ASR0_OFS 0x40 #define D_ASR1_OFS 0x50 #define D_SADR_OFS 0x80 #define D0_REGBASE PS2_PHYS_TO_KSEG1(0x10008000) #define D1_REGBASE PS2_PHYS_TO_KSEG1(0x10009000) #define D2_REGBASE PS2_PHYS_TO_KSEG1(0x1000a000) #define D3_REGBASE PS2_PHYS_TO_KSEG1(0x1000b000) #define D4_REGBASE PS2_PHYS_TO_KSEG1(0x1000b400) #define D5_REGBASE PS2_PHYS_TO_KSEG1(0x1000c000) #define D6_REGBASE PS2_PHYS_TO_KSEG1(0x1000c400) #define D7_REGBASE PS2_PHYS_TO_KSEG1(0x1000c800) #define D8_REGBASE PS2_PHYS_TO_KSEG1(0x1000d000) #define D9_REGBASE PS2_PHYS_TO_KSEG1(0x1000d400) #define D_CHCR_REG(base) (base) #define D_MADR_REG(base) (base + D_MADR_OFS) #define D_QWC_REG(base) (base + D_QWC_OFS) #define D_TADR_REG(base) (base + D_TADR_OFS) #define D_ASR0_REG(base) (base + D_ASR0_OFS) #define D_ASR1_REG(base) (base + D_ASR1_OFS) #define D_SADR_REG(base) (base + D_SADR_OFS) #define D0_CHCR_REG PS2_PHYS_TO_KSEG1(0x10008000) #define D0_MADR_REG PS2_PHYS_TO_KSEG1(0x10008010) #define D0_QWC_REG PS2_PHYS_TO_KSEG1(0x10008020) #define D0_TADR_REG PS2_PHYS_TO_KSEG1(0x10008030) #define D0_ASR0_REG PS2_PHYS_TO_KSEG1(0x10008040) #define D0_ASR1_REG PS2_PHYS_TO_KSEG1(0x10008050) #define D1_CHCR_REG PS2_PHYS_TO_KSEG1(0x10009000) #define D1_MADR_REG PS2_PHYS_TO_KSEG1(0x10009010) #define D1_QWC_REG PS2_PHYS_TO_KSEG1(0x10009020) #define D1_TADR_REG PS2_PHYS_TO_KSEG1(0x10009030) #define D1_ASR0_REG PS2_PHYS_TO_KSEG1(0x10009040) #define D1_ASR1_REG PS2_PHYS_TO_KSEG1(0x10009050) #define D2_CHCR_REG PS2_PHYS_TO_KSEG1(0x1000a000) #define D2_MADR_REG PS2_PHYS_TO_KSEG1(0x1000a010) #define D2_QWC_REG PS2_PHYS_TO_KSEG1(0x1000a020) #define D2_TADR_REG PS2_PHYS_TO_KSEG1(0x1000a030) #define D2_ASR0_REG PS2_PHYS_TO_KSEG1(0x1000a040) #define D2_ASR1_REG PS2_PHYS_TO_KSEG1(0x1000a050) #define D3_CHCR_REG PS2_PHYS_TO_KSEG1(0x1000b000) #define D3_MADR_REG PS2_PHYS_TO_KSEG1(0x1000b010) #define D3_QWC_REG PS2_PHYS_TO_KSEG1(0x1000b020) #define D4_CHCR_REG PS2_PHYS_TO_KSEG1(0x1000b400) #define D4_MADR_REG PS2_PHYS_TO_KSEG1(0x1000b410) #define D4_QWC_REG PS2_PHYS_TO_KSEG1(0x1000b420) #define D4_TADR_REG PS2_PHYS_TO_KSEG1(0x1000b430) #define D5_CHCR_REG PS2_PHYS_TO_KSEG1(0x1000c000) #define D5_MADR_REG PS2_PHYS_TO_KSEG1(0x1000c010) #define D5_QWC_REG PS2_PHYS_TO_KSEG1(0x1000c020) #define D6_CHCR_REG PS2_PHYS_TO_KSEG1(0x1000c400) #define D6_MADR_REG PS2_PHYS_TO_KSEG1(0x1000c410) #define D6_QWC_REG PS2_PHYS_TO_KSEG1(0x1000c420) #define D6_TADR_REG PS2_PHYS_TO_KSEG1(0x1000c430) #define D7_CHCR_REG PS2_PHYS_TO_KSEG1(0x1000c800) #define D7_MADR_REG PS2_PHYS_TO_KSEG1(0x1000c810) #define D7_QWC_REG PS2_PHYS_TO_KSEG1(0x1000c820) #define D8_CHCR_REG PS2_PHYS_TO_KSEG1(0x1000d000) #define D8_MADR_REG PS2_PHYS_TO_KSEG1(0x1000d010) #define D8_QWC_REG PS2_PHYS_TO_KSEG1(0x1000d020) #define D8_SADR_REG PS2_PHYS_TO_KSEG1(0x1000d080) #define D9_CHCR_REG PS2_PHYS_TO_KSEG1(0x1000d400) #define D9_MADR_REG PS2_PHYS_TO_KSEG1(0x1000d410) #define D9_QWC_REG PS2_PHYS_TO_KSEG1(0x1000d420) #define D9_TADR_REG PS2_PHYS_TO_KSEG1(0x1000d430) #define D9_SADR_REG PS2_PHYS_TO_KSEG1(0x1000d480) /* * DMA control */ #define D_CTRL_DMAE 0x00000001 /* all DMA enable/disable */ #define D_CTRL_RELE 0x00000002 /* Cycle stealing on/off */ /* Memory FIFO drain control */ #define D_CTRL_MFD_MASK 0x3 #define D_CTRL_MFD_SHIFT 2 #define D_CTRL_MFD(x) \ (((x) >> D_CTRL_MFD_SHIFT) & D_CTRL_MFD_MASK) #define D_CTRL_MFD_CLR(x) \ ((x) & ~(D_CTRL_MFD_MASK << D_CTRL_MFD_SHIFT)) #define D_CTRL_MFD_SET(x, val) \ ((x) | (((val) << D_CTRL_MFD_SHIFT) & \ (D_CTRL_MFD_MASK << D_CTRL_MFD_SHIFT))) #define D_CTRL_MFD_DISABLE 0 #define D_CTRL_MFD_VIF1 2 #define D_CTRL_MFD_GIF 3 /* Stall control source channel */ #define D_CTRL_STS_MASK 0x3 #define D_CTRL_STS_SHIFT 4 #define D_CTRL_STS(x) \ (((x) >> D_CTRL_STS_SHIFT) & D_CTRL_STS_MASK) #define D_CTRL_STS_CLR(x) \ ((x) & ~(D_CTRL_STS_MASK << D_CTRL_STS_SHIFT)) #define D_CTRL_STS_SET(x, val) \ ((x) | (((val) << D_CTRL_STS_SHIFT) & \ (D_CTRL_STS_MASK << D_CTRL_STS_SHIFT))) #define D_CTRL_STS_NONE 0 #define D_CTRL_STS_SIF0 1 #define D_CTRL_STS_FROMSPR 2 #define D_CTRL_STS_FROMIPU 3 /* Stall control drain channel */ #define D_CTRL_STD_MASK 0x3 #define D_CTRL_STD_SHIFT 6 #define D_CTRL_STD(x) \ (((x) >> D_CTRL_STD_SHIFT) & D_CTRL_STD_MASK) #define D_CTRL_STD_CLR(x) \ ((x) & ~(D_CTRL_STD_MASK << D_CTRL_STD_SHIFT)) #define D_CTRL_STD_SET(x, val) \ ((x) | (((val) << D_CTRL_STD_SHIFT) & \ (D_CTRL_STD_MASK << D_CTRL_STD_SHIFT))) #define D_CTRL_STD_NONE 0 #define D_CTRL_STD_VIF1 1 #define D_CTRL_STD_GIF 2 #define D_CTRL_STD_SIF1 3 /* * Release cycle * for burst channel Cycle steanling on mode only. */ #define D_CTRL_RCYC_MASK 0x7 #define D_CTRL_RCYC_SHIFT 8 #define D_CTRL_RCYC(x) \ (((x) >> D_CTRL_RCYC_SHIFT) & D_CTRL_RCYC_MASK) #define D_CTRL_RCYC_CLR(x) \ ((x) & ~(D_CTRL_RCYC_MASK << D_CTRL_RCYC_SHIFT)) #define D_CTRL_RCYC_SET(x, val) \ ((x) | (((val) << D_CTRL_RCYC_SHIFT) & \ (D_CTRL_RCYC_MASK << D_CTRL_RCYC_SHIFT))) #define D_CTRL_RCYC_CYCLE(x) (8 << (x)) /* * Interrupt status register (write clear/invert) * DMAC interrupt line connected to MIPS HwINT1 */ /* MFIFO empty interrupt enable */ #define D_STAT_MEIM 0x40000000 /* DMA stall interrupt enable */ #define D_STAT_SIM 0x20000000 /* Channel interrupt enable */ #define D_STAT_CIM_MASK 0x3ff #define D_STAT_CIM_SHIFT 16 #define D_STAT_CIM(x) (((x) >> D_STAT_CIM_SHIFT) & D_STAT_CIM_MASK) #define D_STAT_CIM_BIT(x) ((1 << (x)) << D_STAT_CIM_SHIFT) #define D_STAT_CIM9 0x02000000 #define D_STAT_CIM8 0x01000000 #define D_STAT_CIM7 0x00800000 #define D_STAT_CIM6 0x00400000 #define D_STAT_CIM5 0x00200000 #define D_STAT_CIM4 0x00100000 #define D_STAT_CIM3 0x00080000 #define D_STAT_CIM2 0x00040000 #define D_STAT_CIM1 0x00020000 #define D_STAT_CIM0 0x00010000 /* BUSERR interrupt status */ #define D_STAT_BEIS 0x00008000 /* MFIFO empty interrupt status */ #define D_STAT_MEIS 0x00004000 /* DMA stall interrupt status */ #define D_STAT_SIS 0x00002000 /* Channel interrupt status */ #define D_STAT_CIS_MASK 0x3ff #define D_STAT_CIS_SHIFT 0 #define D_STAT_CIS_BIT(x) (1 << (x)) #define D_STAT_CIS9 0x00000200 #define D_STAT_CIS8 0x00000100 #define D_STAT_CIS7 0x00000080 #define D_STAT_CIS6 0x00000040 #define D_STAT_CIS5 0x00000020 #define D_STAT_CIS4 0x00000010 #define D_STAT_CIS3 0x00000008 #define D_STAT_CIS2 0x00000004 #define D_STAT_CIS1 0x00000002 #define D_STAT_CIS0 0x00000001 /* * Priority control register. */ /* Priority control enable */ #define D_PCR_PCE 0x80000000 /* Channel DMA enable (packet priority control enable) */ #define D_PCR_CDE_MASK 0x3ff #define D_PCR_CDE_SHIFT 16 #define D_PCR_CDE(x) \ (((x) >> D_PCR_CDE_SHIFT) & D_PCR_CDE_MASK) #define D_PCR_CDE_CLR(x) \ ((x) & ~(D_PCR_CDE_MASK << D_PCR_CDE_SHIFT)) #define D_PCR_CDE_SET(x, val) \ ((x) | (((val) << D_PCR_CDE_SHIFT) & \ (D_PCR_CDE_MASK << D_PCR_CDE_SHIFT))) #define D_PCR_CDE9 0x02000000 #define D_PCR_CDE8 0x01000000 #define D_PCR_CDE7 0x00800000 #define D_PCR_CDE6 0x00400000 #define D_PCR_CDE5 0x00200000 #define D_PCR_CDE4 0x00100000 #define D_PCR_CDE3 0x00080000 #define D_PCR_CDE2 0x00040000 #define D_PCR_CDE1 0x00020000 #define D_PCR_CDE0 0x00010000 /* COP control (interrupt status connect to CPCOND[0] or not) */ #define D_PCR_CPC_MASK 0x3ff #define D_PCR_CPC_SHIFT 0 #define D_PCR_CPC(x) ((x) & D_PCR_CPC_MASK) #define D_PCR_CPC_CLR(x) ((x) & ~D_PCR_CPC_MASK) #define D_PCR_CPC_SET(x, val) ((x) | ((val) & D_PCR_CPC_MASK)) #define D_PCR_CPC_BIT(x) (1 << (x)) #define D_PCR_CPC9 0x00000200 #define D_PCR_CPC8 0x00000100 #define D_PCR_CPC7 0x00000080 #define D_PCR_CPC6 0x00000040 #define D_PCR_CPC5 0x00000020 #define D_PCR_CPC4 0x00000010 #define D_PCR_CPC3 0x00000008 #define D_PCR_CPC2 0x00000004 #define D_PCR_CPC1 0x00000002 #define D_PCR_CPC0 0x00000001 /* * Interleave size register */ /* Transfer quadword counter */ #define D_SQWC_TQWC_MASK 0xff #define D_SQWC_TQWC_SHIFT 16 #define D_SQWC_TQWC(x) \ (((x) >> D_SQWC_TQWC_SHIFT) & D_SQWC_TQWC_MASK) #define D_SQWC_TQWC_CLR(x) \ ((x) & ~(D_SQWC_TQWC_MASK << D_SQWC_TQWC_SHIFT)) #define D_SQWC_TQWC_SET(x, val) \ ((x) | (((val) << D_SQWC_TQWC_SHIFT) & \ (D_SQWC_TQWC_MASK << D_SQWC_TQWC_SHIFT))) /* Skip quadword counter */ #define D_SQWC_SQWC_MASK 0xff #define D_SQWC_SQWC_SHIFT 0 #define D_SQWC_SQWC(x) \ (((x) >> D_SQWC_SQWC_SHIFT) & D_SQWC_SQWC_MASK) #define D_SQWC_SQWC_CLR(x) \ ((x) & ~(D_SQWC_SQWC_MASK << D_SQWC_SQWC_SHIFT)) #define D_SQWC_SQWC_SET(x, val) \ ((x) | (((val) << D_SQWC_SQWC_SHIFT) & \ (D_SQWC_SQWC_MASK << D_SQWC_SQWC_SHIFT))) /* * Ring buffer address register * 16byte alignment address [30:4] */ /* * Ring buffer size register * must be 2 ** n qword. [30:4] */ /* * Stall address register * [30:0] (qword alignment) */ /* * DMA suspend register */ #define D_ENABLE_SUSPEND 0x00010000 /* * Channel specific register. */ /* CHANNEL CONTROL REGISTER */ /* upper 16bit of DMA tag last read. */ #define D_CHCR_TAG_MASK 0xff #define D_CHCR_TAG_SHIFT 16 #define D_CHCR_TAG(x) \ (((x) >> D_CHCR_TAG_SHIFT) & D_CHCR_TAG_MASK) #define D_CHCR_TAG_CLR(x) \ ((x) & ~(D_CHCR_TAG_MASK << D_CHCR_TAG_SHIFT)) #define D_CHCR_TAG_SET(x, val) \ ((x) | (((val) << D_CHCR_TAG_SHIFT) & \ (D_CHCR_TAG_MASK << D_CHCR_TAG_SHIFT))) /* DMA start */ #define D_CHCR_STR 0x00000100 /* Tag interrupt enable (IRQ bit of DMAtag) */ #define D_CHCR_TIE 0x00000080 /* Tag transfer enable (Source chain mode only) */ #define D_CHCR_TTE 0x00000040 /* Address stack pointer */ #define D_CHCR_ASP_MASK 0x3 #define D_CHCR_ASP_SHIFT 4 #define D_CHCR_ASP(x) \ (((x) >> D_CHCR_ASP_SHIFT) & D_CHCR_ASP_MASK) #define D_CHCR_ASP_CLR(x) \ ((x) & ~(D_CHCR_ASP_MASK << D_CHCR_ASP_SHIFT)) #define D_CHCR_ASP_SET(x, val) \ ((x) | (((val) << D_CHCR_ASP_SHIFT) & \ (D_CHCR_ASP_MASK << D_CHCR_ASP_SHIFT))) #define D_CHCR_ASP_PUSHED_NONE 0 #define D_CHCR_ASP_PUSHED_1 1 #define D_CHCR_ASP_PUSHED_2 2 /* Logical transfer mode */ #define D_CHCR_MOD_MASK 0x3 #define D_CHCR_MOD_SHIFT 2 #define D_CHCR_MOD(x) \ (((x) >> D_CHCR_MOD_SHIFT) & D_CHCR_MOD_MASK) #define D_CHCR_MOD_CLR(x) \ ((x) & ~(D_CHCR_MOD_MASK << D_CHCR_MOD_SHIFT)) #define D_CHCR_MOD_SET(x, val) \ ((x) | (((val) << D_CHCR_MOD_SHIFT) & \ (D_CHCR_MOD_MASK << D_CHCR_MOD_SHIFT))) #define D_CHCR_MOD_NORMAL 0 #define D_CHCR_MOD_CHAIN 1 #define D_CHCR_MOD_INTERLEAVE 2 /* * DMA transfer direction (1 ... from Memory, 0 ... to Memory) * (VIF1, SIF2 only. i.e. `both'-direction channel requires this) */ #define D_CHCR_DIR 0x00000001 /* * TRANSFER ADDRESS REGISTER (D-RAM address) * 16 byte alignment. In FROMSPR, TOSPR channel, D_MADR_SPR always 0 */ #define D_MADR_SPR 0x80000000 /* * TAG ADDRESS REGISTER (next tag address) * 16 byte alignment. */ #define D_TADR_SPR 0x80000000 /* * TAG ADDRESS STACK REGISTER (2 stage) * 16 byte alignment. */ #define D_ASR_SPR 0x80000000 /* * SPR TRANSFER ADDRESS REGISTER (SPR address) * 16 byte alignment. FROMSPR, TOSPR only. */ #define D_SADR_MASK 0x3fff #define D_SADR_SHIFT 0 #define D_SADR(x) \ ((uint32_t)(x) & D_SADR_MASK) /* * TRANSFER SIZE REGISTER * min 16 byte to max 1 Mbyte. */ #define D_QWC_MASK 0xffff #define D_QWC_SHIFT 0 #define D_QWC(x) (((x) >> D_QWC_SHIFT) & D_QWC_MASK) #define D_QWC_CLR(x) ((x) & ~(D_QWC_MASK << D_QWC_SHIFT)) #define D_QWC_SET(x, val) \ ((x) | (((val) << D_QWC_SHIFT) & D_QWC_MASK << D_QWC_SHIFT)) /* * Source/Destination Chain Tag definition. * SC ... VIF0, VIF1, GIF, toIPU, SIF1, toSPR * DC ... SIF0, fromSPR */ /* * DMA address * At least, 16byte align. * but 64byte align is recommended. because EE D-cash line size is 64byte. * To gain maximum DMA speed, use 128 byte align. */ #define DMATAG_ADDR_MASK 0xffffffff #define DMATAG_ADDR_SHIFT 32 #define DMATAG_ADDR(x) \ ((uint32_t)(((x) >> DMATAG_ADDR_SHIFT) & DMATAG_ADDR_MASK)) #define DMATAG_ADDR_SET(x, val) \ ((dmatag_t)(x) | (((dmatag_t)(val)) << DMATAG_ADDR_SHIFT)) #define DMATAG_ADDR32_INVALID(x) ((x) & 0xf) /* 16byte alignment */ /* * DMA controller command */ #define DMATAG_CMD_MASK 0xffffffff #define DMATAG_CMD_SHIFT 0 #define DMATAG_CMD(x) \ ((uint32_t)((x) & DMATAG_CMD_MASK)) #define DMATAG_CMD_IRQ 0x80000000 #define DMATAG_CMD_ID_MASK 0x7 #define DMATAG_CMD_ID_SHIFT 28 #define DMATAG_CMD_ID(x) \ (((x) >> DMATAG_CMD_ID_SHIFT) & DMATAG_CMD_ID_MASK) #define DMATAG_CMD_ID_CLR(x) \ ((x) & ~(DMATAG_CMD_ID_MASK << DMATAG_CMD_ID_SHIFT)) #define DMATAG_CMD_ID_SET(x, val) \ ((x) | (((val) << DMATAG_CMD_ID_SHIFT) & \ (DMATAG_CMD_ID_MASK << DMATAG_CMD_ID_SHIFT))) #define DMATAG_CMD_SCID_REFE 0 #define DMATAG_CMD_SCID_CNT 1 #define DMATAG_CMD_SCID_NEXT 2 #define DMATAG_CMD_SCID_REF 3 #define DMATAG_CMD_SCID_REFS 4 /* VIF1, GIF, SIF1 only */ #define DMATAG_CMD_SCID_CALL 5 /* VIF0, VIF1, GIF only */ #define DMATAG_CMD_SCID_RET 6 /* VIF0, VIF1, GIF only */ #define DMATAG_CMD_SCID_END 7 #define DMATAG_CMD_DCID_CNTS 0 /* SIF0, fromSPR only */ #define DMATAG_CMD_DCID_CNT 1 #define DMATAG_CMD_DCID_END 7 #define DMATAG_CMD_PCE_MASK 0x3 #define DMATAG_CMD_PCE_SHIFT 26 #define DMATAG_CMD_PCE(x) \ (((x) >> DMATAG_CMD_PCE_SHIFT) & DMATAG_CMD_PCE_MASK) #define DMATAG_CMD_PCE_CLR(x) \ ((x) & ~(DMATAG_CMD_PCE_MASK << DMATAG_CMD_PCE_SHIFT)) #define DMATAG_CMD_PCE_SET(x, val) \ ((x) | (((val) << DMATAG_CMD_PCE_SHIFT) & \ (DMATAG_CMD_PCE_MASK << DMATAG_CMD_PCE_SHIFT))) #define DMATAG_CMD_PCE_NONE 0 #define DMATAG_CMD_PCE_DISABLE 2 #define DMATAG_CMD_PCE_ENABLE 3 #define DMATAG_CMD_QWC_MASK 0xffff #define DMATAG_CMD_QWC_SHIFT 0 #define DMATAG_CMD_QWC(x) \ (((x) >> DMATAG_CMD_QWC_SHIFT) & DMATAG_CMD_QWC_MASK) #define DMATAG_CMD_QWC_CLR(x) \ ((x) & ~(DMATAG_CMD_QWC_MASK << DMATAG_CMD_QWC_SHIFT)) #define DMATAG_CMD_QWC_SET(x, val) \ ((x) | (((val) << DMATAG_CMD_QWC_SHIFT) & \ (DMATAG_CMD_QWC_MASK << DMATAG_CMD_QWC_SHIFT))) #endif /* PS2_DMACREG_H */ gxemul-0.6.1/src/include/thirdparty/arm_cputypes.h000644 001750 001750 00000022160 13402411502 022516 0ustar00debugdebug000000 000000 /* Imported into GXemul from NetBSD, 2018-09-25 */ /* $NetBSD: cputypes.h,v 1.2 2018/05/01 10:10:31 ryo Exp $ */ /* * Copyright (c) 1998, 2001 Ben Harris * Copyright (c) 1994-1996 Mark Brinicombe. * Copyright (c) 1994 Brini. * All rights reserved. * * This code is derived from software written for Brini by Mark Brinicombe * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Brini. * 4. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _ARM_CPUTYPES_H_ #define _ARM_CPUTYPES_H_ /* * The CPU ID register is theoretically structured, but the definitions of * the fields keep changing. */ /* The high-order byte is always the implementor */ #define CPU_ID_IMPLEMENTOR_MASK 0xff000000 #define CPU_ID_ARM_LTD 0x41000000 /* 'A' */ #define CPU_ID_BROADCOM 0x42000000 /* 'B' */ #define CPU_ID_CAVIUM 0x43000000 /* 'C' */ #define CPU_ID_DEC 0x44000000 /* 'D' */ #define CPU_ID_INFINEON 0x49000000 /* 'I' */ #define CPU_ID_MOTOROLA 0x4d000000 /* 'M' */ #define CPU_ID_NVIDIA 0x4e000000 /* 'N' */ #define CPU_ID_APM 0x50000000 /* 'P' */ #define CPU_ID_QUALCOMM 0x51000000 /* 'Q' */ #define CPU_ID_SAMSUNG 0x53000000 /* 'S' */ #define CPU_ID_TI 0x54000000 /* 'T' */ #define CPU_ID_MARVELL 0x56000000 /* 'V' */ #define CPU_ID_APPLE 0x61000000 /* 'a' */ #define CPU_ID_FARADAY 0x66000000 /* 'f' */ #define CPU_ID_INTEL 0x69000000 /* 'i' */ /* How to decide what format the CPUID is in. */ #define CPU_ID_ISOLD(x) (((x) & 0x0000f000) == 0x00000000) #define CPU_ID_IS7(x) (((x) & 0x0000f000) == 0x00007000) #define CPU_ID_ISNEW(x) (!CPU_ID_ISOLD(x) && !CPU_ID_IS7(x)) /* On ARM3 and ARM6, this byte holds the foundry ID. */ #define CPU_ID_FOUNDRY_MASK 0x00ff0000 #define CPU_ID_FOUNDRY_VLSI 0x00560000 /* On ARM7 it holds the architecture and variant (sub-model) */ #define CPU_ID_7ARCH_MASK 0x00800000 #define CPU_ID_7ARCH_V3 0x00000000 #define CPU_ID_7ARCH_V4T 0x00800000 #define CPU_ID_7VARIANT_MASK 0x007f0000 /* On more recent ARMs, it does the same, but in a different format */ #define CPU_ID_ARCH_MASK 0x000f0000 #define CPU_ID_ARCH_V3 0x00000000 #define CPU_ID_ARCH_V4 0x00010000 #define CPU_ID_ARCH_V4T 0x00020000 #define CPU_ID_ARCH_V5 0x00030000 #define CPU_ID_ARCH_V5T 0x00040000 #define CPU_ID_ARCH_V5TE 0x00050000 #define CPU_ID_ARCH_V5TEJ 0x00060000 #define CPU_ID_ARCH_V6 0x00070000 #define CPU_ID_VARIANT_MASK 0x00f00000 /* Next three nybbles are part number */ #define CPU_ID_PARTNO_MASK 0x0000fff0 /* Intel XScale has sub fields in part number */ #define CPU_ID_XSCALE_COREGEN_MASK 0x0000e000 /* core generation */ #define CPU_ID_XSCALE_COREREV_MASK 0x00001c00 /* core revision */ #define CPU_ID_XSCALE_PRODUCT_MASK 0x000003f0 /* product number */ /* And finally, the revision number. */ #define CPU_ID_REVISION_MASK 0x0000000f /* Individual CPUs are probably best IDed by everything but the revision. */ #define CPU_ID_CPU_MASK 0xfffffff0 /* Fake CPU IDs for ARMs without CP15 */ #define CPU_ID_ARM2 0x41560200 #define CPU_ID_ARM250 0x41560250 /* Pre-ARM7 CPUs -- [15:12] == 0 */ #define CPU_ID_ARM3 0x41560300 #define CPU_ID_ARM600 0x41560600 #define CPU_ID_ARM610 0x41560610 #define CPU_ID_ARM620 0x41560620 /* ARM7 CPUs -- [15:12] == 7 */ #define CPU_ID_ARM700 0x41007000 /* XXX This is a guess. */ #define CPU_ID_ARM710 0x41007100 #define CPU_ID_ARM7500 0x41027100 #define CPU_ID_ARM710A 0x41067100 #define CPU_ID_ARM7500FE 0x41077100 #define CPU_ID_ARM710T 0x41807100 #define CPU_ID_ARM720T 0x41807200 #define CPU_ID_ARM740T8K 0x41807400 /* XXX no MMU, 8KB cache */ #define CPU_ID_ARM740T4K 0x41817400 /* XXX no MMU, 4KB cache */ /* Post-ARM7 CPUs */ #define CPU_ID_ARM810 0x41018100 #define CPU_ID_ARM920T 0x41129200 #define CPU_ID_ARM922T 0x41029220 #define CPU_ID_ARM926EJS 0x41069260 #define CPU_ID_ARM940T 0x41029400 /* XXX no MMU */ #define CPU_ID_ARM946ES 0x41049460 /* XXX no MMU */ #define CPU_ID_ARM966ES 0x41049660 /* XXX no MMU */ #define CPU_ID_ARM966ESR1 0x41059660 /* XXX no MMU */ #define CPU_ID_ARM1020E 0x4115a200 /* (AKA arm10 rev 1) */ #define CPU_ID_ARM1022ES 0x4105a220 #define CPU_ID_ARM1026EJS 0x4106a260 #define CPU_ID_ARM11MPCORE 0x410fb020 #define CPU_ID_ARM1136JS 0x4107b360 #define CPU_ID_ARM1136JSR1 0x4117b360 #define CPU_ID_ARM1156T2S 0x4107b560 /* MPU only */ #define CPU_ID_ARM1176JZS 0x410fb760 #define CPU_ID_ARM11_P(n) ((n & 0xff07f000) == 0x4107b000) #define CPU_ID_CORTEXA5R0 0x410fc050 #define CPU_ID_CORTEXA7R0 0x410fc070 #define CPU_ID_CORTEXA8R1 0x411fc080 #define CPU_ID_CORTEXA8R2 0x412fc080 #define CPU_ID_CORTEXA8R3 0x413fc080 #define CPU_ID_CORTEXA9R1 0x411fc090 #define CPU_ID_CORTEXA9R2 0x412fc090 #define CPU_ID_CORTEXA9R3 0x413fc090 #define CPU_ID_CORTEXA9R4 0x414fc090 #define CPU_ID_CORTEXA15R2 0x412fc0f0 #define CPU_ID_CORTEXA15R3 0x413fc0f0 #define CPU_ID_CORTEXA17R1 0x411fc0e0 #define CPU_ID_CORTEXA35R0 0x410fd040 #define CPU_ID_CORTEXA53R0 0x410fd030 #define CPU_ID_CORTEXA55R1 0x411fd050 #define CPU_ID_CORTEXA57R0 0x410fd070 #define CPU_ID_CORTEXA57R1 0x411fd070 #define CPU_ID_CORTEXA72R0 0x410fd080 #define CPU_ID_CORTEXA73R0 0x410fd090 #define CPU_ID_CORTEXA75R2 0x412fd0a0 #define CPU_ID_CORTEX_P(n) ((n & 0xff0fe000) == 0x410fc000) #define CPU_ID_CORTEX_A5_P(n) ((n & 0xff0ff0f0) == 0x410fc050) #define CPU_ID_CORTEX_A7_P(n) ((n & 0xff0ff0f0) == 0x410fc070) #define CPU_ID_CORTEX_A8_P(n) ((n & 0xff0ff0f0) == 0x410fc080) #define CPU_ID_CORTEX_A9_P(n) ((n & 0xff0ff0f0) == 0x410fc090) #define CPU_ID_CORTEX_A15_P(n) ((n & 0xff0ff0f0) == 0x410fc0f0) #define CPU_ID_CORTEX_A35_P(n) ((n & 0xff0ff0f0) == 0x410fd040) #define CPU_ID_CORTEX_A53_P(n) ((n & 0xff0ff0f0) == 0x410fd030) #define CPU_ID_CORTEX_A55_P(n) ((n & 0xff0ff0f0) == 0x410fd050) #define CPU_ID_CORTEX_A57_P(n) ((n & 0xff0ff0f0) == 0x410fd070) #define CPU_ID_CORTEX_A72_P(n) ((n & 0xff0ff0f0) == 0x410fd080) #define CPU_ID_CORTEX_A73_P(n) ((n & 0xff0ff0f0) == 0x410fd090) #define CPU_ID_CORTEX_A75_P(n) ((n & 0xff0ff0f0) == 0x410fd0a0) #define CPU_ID_SA110 0x4401a100 #define CPU_ID_SA1100 0x4401a110 #define CPU_ID_TI925T 0x54029250 #define CPU_ID_MV88FR571_VD 0x56155710 #define CPU_ID_MV88SV131 0x56251310 #define CPU_ID_FA526 0x66015260 #define CPU_ID_SA1110 0x6901b110 #define CPU_ID_IXP1200 0x6901c120 #define CPU_ID_80200 0x69052000 #define CPU_ID_PXA250 0x69052100 /* sans core revision */ #define CPU_ID_PXA210 0x69052120 #define CPU_ID_PXA250A 0x69052100 /* 1st version Core */ #define CPU_ID_PXA210A 0x69052120 /* 1st version Core */ #define CPU_ID_PXA250B 0x69052900 /* 3rd version Core */ #define CPU_ID_PXA210B 0x69052920 /* 3rd version Core */ #define CPU_ID_PXA250C 0x69052d00 /* 4th version Core */ #define CPU_ID_PXA210C 0x69052d20 /* 4th version Core */ #define CPU_ID_PXA27X 0x69054110 #define CPU_ID_80321_400 0x69052420 #define CPU_ID_80321_600 0x69052430 #define CPU_ID_80321_400_B0 0x69052c20 #define CPU_ID_80321_600_B0 0x69052c30 #define CPU_ID_80321_600_2 0x69052c32 #define CPU_ID_80219_400 0x69052e20 #define CPU_ID_80219_600 0x69052e30 #define CPU_ID_IXP425_533 0x690541c0 #define CPU_ID_IXP425_400 0x690541d0 #define CPU_ID_IXP425_266 0x690541f0 #define CPU_ID_MV88SV58XX_P(n) ((n & 0xff0fff00) == 0x560f5800) #define CPU_ID_MV88SV581X_V6 0x560f5810 /* Marvell Sheeva 88SV581x v6 Core */ #define CPU_ID_MV88SV581X_V7 0x561f5810 /* Marvell Sheeva 88SV581x v7 Core */ #define CPU_ID_MV88SV584X_V6 0x561f5840 /* Marvell Sheeva 88SV584x v6 Core */ #define CPU_ID_MV88SV584X_V7 0x562f5840 /* Marvell Sheeva 88SV584x v7 Core */ /* Marvell's CPUIDs with ARM ID in implementor field */ #define CPU_ID_ARM_88SV581X_V6 0x410fb760 /* Marvell Sheeva 88SV581x v6 Core */ #define CPU_ID_ARM_88SV581X_V7 0x413fc080 /* Marvell Sheeva 88SV581x v7 Core */ #define CPU_ID_ARM_88SV584X_V6 0x410fb020 /* Marvell Sheeva 88SV584x v6 Core */ #endif /* _ARM_CPUTYPES_H_ */ gxemul-0.6.1/src/include/thirdparty/cpc700reg.h000644 001750 001750 00000014753 13402411502 021506 0ustar00debugdebug000000 000000 /* GXemul: $Id: cpc700reg.h,v 1.2 2005-11-23 23:31:37 debug Exp $ */ /* $NetBSD: cpc700reg.h,v 1.3 2003/11/07 17:03:42 augustss Exp $ */ #ifndef CPC700REG_H #define CPC700REG_H /* * Copyright (c) 2002 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Lennart Augustsson (lennart@augustsson.net) at Sandburst Corp. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* PCI memory space */ #define CPC_PCI_MEM_BASE 0x80000000 #define CPC_PCI_MEM_END 0xf7ffffff /* PCI IO space */ #define CPC_PCI_IO_BASE 0xf8000000 #define CPC_PCI_IO_START 0xf8800000 /* for allocation */ #define CPC_PCI_IO_END 0xfbffffff /* PCI config space */ #define CPC_PCICFGADR 0xfec00000 #define CPC_PCI_CONFIG_ENABLE 0x80000000 #define CPC_PCICFGDATA 0xfec00004 /* Config space regs */ #define CPC_PCI_BRDGERR 0x48 #define CPC_PCI_CLEARERR 0x0000ff00 #define CPC_BRIDGE_OPTIONS2 0x60 #define CPC_BRIDGE_O2_ILAT_MASK 0x00f8 #define CPC_BRIDGE_O2_ILAT_SHIFT 3 #define CPC_BRIDGE_O2_ILAT_PRIM_ASYNC 18 #define CPC_BRIDGE_O2_SLAT_MASK 0x0f00 #define CPC_BRIDGE_O2_SLAT_SHIFT 8 #define CPC_BRIDGE_O2_2LAT_PRIM_ASYNC 2 /* PCI interrupt acknowledge & special cycle */ #define CPC_INTR_ACK 0xfed00000 #define CPC_PMM0_LOCAL 0xff400000 #define CPC_PMM0_MASK_ATTR 0xff400004 #define CPC_PMM0_PCI_LOW 0xff400008 #define CPC_PMM0_PCI_HIGH 0xff40000c #define CPC_PMM1_LOCAL 0xff400010 #define CPC_PMM1_MASK_ATTR 0xff400014 #define CPC_PMM1_PCI_LOW 0xff400018 #define CPC_PMM1_PCI_HIGH 0xff40001c #define CPC_PMM2_LOCAL 0xff400020 #define CPC_PMM2_MASK_ATTR 0xff400024 #define CPC_PMM2_PCI_LOW 0xff400028 #define CPC_PMM2_PCI_HIGH 0xff40002c #define CPC_PTM1_LOCAL 0xff400030 #define CPC_PTM1_MEMSIZE 0xff400034 #define CPC_PTM2_LOCAL 0xff400038 #define CPC_PTM2_MEMSIZE 0xff40003c /* serial ports */ #define CPC_COM0 0xff600300ULL #define CPC_COM1 0xff600400ULL #define CPC_COM_SPEED(bus) ((bus) / (2 * 4)) /* processor interface registers */ #define CPC_PIF_CFGADR 0xff500000 #define CPC_PIF_CFG_PRIFOPT1 0x00 #define CPC_PIF_CFG_ERRDET1 0x04 #define CPC_PIF_CFG_ERREN1 0x08 #define CPC_PIF_CFG_CPUERAD 0x0c #define CPC_PIF_CFG_CPUERAT 0x10 #define CPC_PIF_CFG_PLBMIFOPT 0x18 #define CPC_PIF_CFG_PLBMTLSA1 0x20 #define CPC_PIF_CFG_PLBMTLEA1 0x24 #define CPC_PIF_CFG_PLBMTLSA2 0x28 #define CPC_PIF_CFG_PLBMTLEA2 0x2c #define CPC_PIF_CFG_PLBMTLSA3 0x30 #define CPC_PIF_CFG_PLBMTLEA3 0x34 #define CPC_PIF_CFG_PLBSNSSA0 0x38 #define CPC_PIF_CFG_PLBSNSEA0 0x3c #define CPC_PIF_CFG_BESR 0x40 #define CPC_PIF_CFG_BESRSET 0x44 #define CPC_PIF_CFG_BEAR 0x4c #define CPC_PIF_CFG_PLBSWRINT 0x80 #define CPC_PIF_CFGDATA 0xff500004 /* interrupt controller */ #define CPC_UIC_BASE 0xff500880 #define CPC_UIC_SIZE 0x00000024 #define CPC_UIC_SR 0x00000000 /* UIC status (read/clear) */ #define CPC_UIC_SRS 0x00000004 /* UIC status (set) */ #define CPC_UIC_ER 0x00000008 /* UIC enable */ #define CPC_UIC_CR 0x0000000c /* UIC critical */ #define CPC_UIC_PR 0x00000010 /* UIC polarity 0=low, 1=high*/ #define CPC_UIC_TR 0x00000014 /* UIC trigger 0=level; 1=edge */ #define CPC_UIC_MSR 0x00000018 /* UIC masked status */ #define CPC_UIC_VR 0x0000001c /* UIC vector */ #define CPC_UIC_VCR 0x00000020 /* UIC vector configuration */ #define CPC_UIC_CVR_PRI 0x00000001 /* 0=intr31 high, 1=intr0 high */ /* * if intr0 high then interrupt vector at (vcr&~3) + N*512 * if intr31 high then interrupt vector at (vcr&~3) + (31-N)*512 */ /* UIC interrupt bits. Note, MSB is bit 0 */ /* Internal */ #define CPC_IB_ECC 0 #define CPC_IB_PCI_WR_RANGE 1 #define CPC_IB_PCI_WR_CMD 2 #define CPC_IB_UART_0 3 #define CPC_IB_UART_1 4 #define CPC_IB_IIC_0 5 #define CPC_IB_IIC_1 6 /* 6-16 GPT compare&capture */ /* 20-31 external */ #define CPC_IB_EXT0 20 #define CPC_IB_EXT1 21 #define CPC_IB_EXT2 22 #define CPC_IB_EXT3 23 #define CPC_IB_EXT4 24 #define CPC_IB_EXT5 25 #define CPC_IB_EXT6 26 #define CPC_IB_EXT7 27 #define CPC_IB_EXT8 28 #define CPC_IB_EXT9 29 #define CPC_IB_EXT10 30 #define CPC_IB_EXT11 31 #define CPC_INTR_MASK(irq) (0x80000000 >> (irq)) /* IIC */ #define CPC_IIC0 0xff620000 #define CPC_IIC1 0xff630000 #define CPC_IIC_SIZE 0x00000014 /* offsets from base */ #define CPC_IIC_MDBUF 0x00000000 #define CPC_IIC_SDBUF 0x00000002 #define CPC_IIC_LMADR 0x00000004 #define CPC_IIC_HNADR 0x00000005 #define CPC_IIC_CNTL 0x00000006 #define CPC_IIC_MDCNTL 0x00000007 #define CPC_IIC_STS 0x00000008 #define CPC_IIC_EXTSTS 0x00000009 #define CPC_IIC_LSADR 0x0000000a #define CPC_IIC_HSADR 0x0000000b #define CPC_IIC_CLKDIV 0x0000000c #define CPC_IIC_INTRMSK 0x0000000d #define CPC_IIC_FRCNT 0x0000000e #define CPC_IIC_TCNTLSS 0x0000000f #define CPC_IIC_DIRECTCNTL 0x00000010 /* timer */ #define CPC_TIMER 0xff650000 #define CPC_GPTTBC 0x00000000 #endif /* CPC700REG_H */ gxemul-0.6.1/src/include/thirdparty/pcmciareg.h000644 001750 001750 00000023073 13402411502 021741 0ustar00debugdebug000000 000000 /* gxemul: $Id: pcmciareg.h,v 1.1 2005-03-15 09:54:06 debug Exp $ */ /* $NetBSD: pcmciareg.h,v 1.7 1998/10/29 09:45:52 enami Exp $ */ #ifndef PCMCIAREG_H #define PCMCIAREG_H /* * Copyright (c) 1997 Marc Horowitz. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Marc Horowitz. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* most of this is from the PCMCIA PC Card Standard, Release 2.1 */ /* Note: the weird indenting here is to make the constants more readable. Please don't normalize it. --marc */ /* * CIS Tuples */ /* Layer 1 Basic Compatibility Tuples */ #define PCMCIA_CISTPL_NULL 0x00 #define PCMCIA_CISTPL_DEVICE 0x01 #define PCMCIA_DTYPE_MASK 0xF0 #define PCMCIA_DTYPE_NULL 0x00 #define PCMCIA_DTYPE_ROM 0x10 #define PCMCIA_DTYPE_OTPROM 0x20 #define PCMCIA_DTYPE_EPROM 0x30 #define PCMCIA_DTYPE_EEPROM 0x40 #define PCMCIA_DTYPE_FLASH 0x50 #define PCMCIA_DTYPE_SRAM 0x60 #define PCMCIA_DTYPE_DRAM 0x70 #define PCMCIA_DTYPE_FUNCSPEC 0xD0 #define PCMCIA_DTYPE_EXTEND 0xE0 #define PCMCIA_DSPEED_MASK 0x07 #define PCMCIA_DSPEED_NULL 0x00 #define PCMCIA_DSPEED_250NS 0x01 #define PCMCIA_DSPEED_200NS 0x02 #define PCMCIA_DSPEED_150NS 0x03 #define PCMCIA_DSPEED_100NS 0x04 #define PCMCIA_DSPEED_EXT 0x07 /* * the 2.1 docs have 0x02-0x07 as reserved, but the linux drivers list the * follwing tuple code values. I have at least one card (3com 3c562 * lan+modem) which has a code 0x06 tuple, so I'm going to assume that these * are for real */ #define PCMCIA_CISTPL_LONGLINK_CB 0x02 #define PCMCIA_CISTPL_INDIRECT 0x03 #define PCMCIA_CISTPL_CONFIG_CB 0x04 #define PCMCIA_CISTPL_CFTABLE_ENTRY_CB 0x05 #define PCMCIA_CISTPL_LONGLINK_MFC 0x06 #define PCMCIA_MFC_MEM_ATTR 0x00 #define PCMCIA_MFC_MEM_COMMON 0x01 #define PCMCIA_CISTPL_BAR 0x07 #define PCMCIA_CISTPL_PWR_MGMNT 0x08 #define PCMCIA_CISTPL_CHECKSUM 0x10 #define PCMCIA_CISTPL_LONGLINK_A 0x11 #define PCMCIA_CISTPL_LONGLINK_C 0x12 #define PCMCIA_CISTPL_LINKTARGET 0x13 #define PCMCIA_CISTPL_NO_LINK 0x14 #define PCMCIA_CISTPL_VERS_1 0x15 #define PCMCIA_CISTPL_ALTSTR 0x16 #define PCMCIA_CISTPL_DEVICE_A 0x17 #define PCMCIA_CISTPL_JEDEC_C 0x18 #define PCMCIA_CISTPL_JEDEC_A 0x19 #define PCMCIA_CISTPL_CONFIG 0x1A #define PCMCIA_TPCC_RASZ_MASK 0x03 #define PCMCIA_TPCC_RASZ_SHIFT 0 #define PCMCIA_TPCC_RMSZ_MASK 0x3C #define PCMCIA_TPCC_RMSZ_SHIFT 2 #define PCMCIA_TPCC_RFSZ_MASK 0xC0 #define PCMCIA_TPCC_RFSZ_SHIFT 6 #define PCMCIA_CISTPL_CFTABLE_ENTRY 0x1B #define PCMCIA_TPCE_INDX_INTFACE 0x80 #define PCMCIA_TPCE_INDX_DEFAULT 0x40 #define PCMCIA_TPCE_INDX_NUM_MASK 0x3F #define PCMCIA_TPCE_IF_MWAIT 0x80 #define PCMCIA_TPCE_IF_RDYBSY 0x40 #define PCMCIA_TPCE_IF_WP 0x20 #define PCMCIA_TPCE_IF_BVD 0x10 #define PCMCIA_TPCE_IF_IFTYPE 0x0F #define PCMCIA_IFTYPE_MEMORY 0 #define PCMCIA_IFTYPE_IO 1 #define PCMCIA_TPCE_FS_MISC 0x80 #define PCMCIA_TPCE_FS_MEMSPACE_MASK 0x60 #define PCMCIA_TPCE_FS_MEMSPACE_NONE 0x00 #define PCMCIA_TPCE_FS_MEMSPACE_LENGTH 0x20 #define PCMCIA_TPCE_FS_MEMSPACE_LENGTHADDR 0x40 #define PCMCIA_TPCE_FS_MEMSPACE_TABLE 0x60 #define PCMCIA_TPCE_FS_IRQ 0x10 #define PCMCIA_TPCE_FS_IOSPACE 0x08 #define PCMCIA_TPCE_FS_TIMING 0x04 #define PCMCIA_TPCE_FS_POWER_MASK 0x03 #define PCMCIA_TPCE_FS_POWER_NONE 0x00 #define PCMCIA_TPCE_FS_POWER_VCC 0x01 #define PCMCIA_TPCE_FS_POWER_VCCVPP1 0x02 #define PCMCIA_TPCE_FS_POWER_VCCVPP1VPP2 0x03 #define PCMCIA_TPCE_TD_RESERVED_MASK 0xE0 #define PCMCIA_TPCE_TD_RDYBSY_MASK 0x1C #define PCMCIA_TPCE_TD_WAIT_MASK 0x03 #define PCMCIA_TPCE_IO_HASRANGE 0x80 #define PCMCIA_TPCE_IO_BUSWIDTH_16BIT 0x40 #define PCMCIA_TPCE_IO_BUSWIDTH_8BIT 0x20 #define PCMCIA_TPCE_IO_IOADDRLINES_MASK 0x1F #define PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_MASK 0xC0 #define PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_NONE 0x00 #define PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_ONE 0x40 #define PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_TWO 0x80 #define PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_FOUR 0xC0 #define PCMCIA_TPCE_IO_RANGE_ADDRSIZE_MASK 0x30 #define PCMCIA_TPCE_IO_RANGE_ADDRSIZE_NONE 0x00 #define PCMCIA_TPCE_IO_RANGE_ADDRSIZE_ONE 0x10 #define PCMCIA_TPCE_IO_RANGE_ADDRSIZE_TWO 0x20 #define PCMCIA_TPCE_IO_RANGE_ADDRSIZE_FOUR 0x30 #define PCMCIA_TPCE_IO_RANGE_COUNT 0x0F #define PCMCIA_TPCE_IR_SHARE 0x80 #define PCMCIA_TPCE_IR_PULSE 0x40 #define PCMCIA_TPCE_IR_LEVEL 0x20 #define PCMCIA_TPCE_IR_HASMASK 0x10 #define PCMCIA_TPCE_IR_IRQ 0x0F #define PCMCIA_TPCE_MS_HOSTADDR 0x80 #define PCMCIA_TPCE_MS_CARDADDR_SIZE_MASK 0x60 #define PCMCIA_TPCE_MS_CARDADDR_SIZE_SHIFT 5 #define PCMCIA_TPCE_MS_LENGTH_SIZE_MASK 0x18 #define PCMCIA_TPCE_MS_LENGTH_SIZE_SHIFT 3 #define PCMCIA_TPCE_MS_COUNT 0x07 #define PCMCIA_TPCE_MI_EXT 0x80 #define PCMCIA_TPCE_MI_RESERVED 0x40 #define PCMCIA_TPCE_MI_PWRDOWN 0x20 #define PCMCIA_TPCE_MI_READONLY 0x10 #define PCMCIA_TPCE_MI_AUDIO 0x08 #define PCMCIA_TPCE_MI_MAXTWINS 0x07 #define PCMCIA_CISTPL_DEVICE_OC 0x1C #define PCMCIA_CISTPL_DEVICE_OA 0x1D #define PCMCIA_CISTPL_DEVICE_GEO 0x1E #define PCMCIA_CISTPL_DEVICE_GEO_A 0x1F #define PCMCIA_CISTPL_MANFID 0x20 #define PCMCIA_CISTPL_FUNCID 0x21 #define PCMCIA_FUNCTION_UNSPEC -1 #define PCMCIA_FUNCTION_MULTIFUNCTION 0 #define PCMCIA_FUNCTION_MEMORY 1 #define PCMCIA_FUNCTION_SERIAL 2 #define PCMCIA_FUNCTION_PARALLEL 3 #define PCMCIA_FUNCTION_DISK 4 #define PCMCIA_FUNCTION_VIDEO 5 #define PCMCIA_FUNCTION_NETWORK 6 #define PCMCIA_FUNCTION_AIMS 7 #define PCMCIA_FUNCTION_SCSI 8 #define PCMCIA_FUNCTION_SECURITY 9 #define PCMCIA_FUNCTION_INSTRUMENT 10 #define PCMCIA_CISTPL_FUNCE 0x22 #define PCMCIA_TPLFE_TYPE_LAN_TECH 0x01 #define PCMCIA_TPLFE_TYPE_LAN_SPEED 0x02 #define PCMCIA_TPLFE_TYPE_LAN_MEDIA 0x03 #define PCMCIA_TPLFE_TYPE_LAN_NID 0x04 #define PCMCIA_TPLFE_TYPE_LAN_CONN 0x05 #define PCMCIA_TPLFE_TYPE_DISK_DEVICE_INTERFACE 0x01 #define PCMCIA_TPLFE_DDI_PCCARD_ATA 0x01 #define PCMCIA_CISTPL_END 0xFF /* Layer 2 Data Recording Format Tuples */ #define PCMCIA_CISTPL_SWIL 0x23 /* #define PCMCIA_CISTPL_RESERVED 0x24-0x3F */ #define PCMCIA_CISTPL_VERS_2 0x40 #define PCMCIA_CISTPL_FORMAT 0x41 #define PCMCIA_CISTPL_GEOMETRY 0x42 #define PCMCIA_CISTPL_BYTEORDER 0x43 #define PCMCIA_CISTPL_DATE 0x44 #define PCMCIA_CISTPL_BATTERY 0x45 #define PCMCIA_CISTPL_FORAMT_A 0x47 /* Layer 3 Data Organization Tuples */ #define PCMCIA_CISTPL_ORG 0x46 /* #define PCMCIA_CISTPL_RESERVED 0x47-0x7F */ /* Layer 4 System-Specific Standard Tuples */ /* #define PCMCIA_CISTPL_RESERVED 0x80-0x8F */ #define PCMCIA_CISTPL_SPCL 0x90 /* #define PCMCIA_CISTPL_RESERVED 0x90-0xFE */ /* * Card Configuration Registers */ #define PCMCIA_CCR_OPTION 0x00 #define PCMCIA_CCR_OPTION_SRESET 0x80 #define PCMCIA_CCR_OPTION_LEVIREQ 0x40 #define PCMCIA_CCR_OPTION_CFINDEX 0x3F #define PCMCIA_CCR_OPTION_IREQ_ENABLE 0x04 #define PCMCIA_CCR_OPTION_ADDR_DECODE 0x02 #define PCMCIA_CCR_OPTION_FUNC_ENABLE 0x01 #define PCMCIA_CCR_STATUS 0x02 #define PCMCIA_CCR_STATUS_PINCHANGED 0x80 #define PCMCIA_CCR_STATUS_SIGCHG 0x40 #define PCMCIA_CCR_STATUS_IOIS8 0x20 #define PCMCIA_CCR_STATUS_RESERVED1 0x10 #define PCMCIA_CCR_STATUS_AUDIO 0x08 #define PCMCIA_CCR_STATUS_PWRDWN 0x04 #define PCMCIA_CCR_STATUS_INTR 0x02 #define PCMCIA_CCR_STATUS_INTRACK 0x01 #define PCMCIA_CCR_PIN 0x04 #define PCMCIA_CCR_PIN_CBVD1 0x80 #define PCMCIA_CCR_PIN_CBVD2 0x40 #define PCMCIA_CCR_PIN_CRDYBSY 0x20 #define PCMCIA_CCR_PIN_CWPROT 0x10 #define PCMCIA_CCR_PIN_RBVD1 0x08 #define PCMCIA_CCR_PIN_RBVD2 0x04 #define PCMCIA_CCR_PIN_RRDYBSY 0x02 #define PCMCIA_CCR_PIN_RWPROT 0x01 #define PCMCIA_CCR_SOCKETCOPY 0x06 #define PCMCIA_CCR_SOCKETCOPY_RESERVED 0x80 #define PCMCIA_CCR_SOCKETCOPY_COPY_MASK 0x70 #define PCMCIA_CCR_SOCKETCOPY_COPY_SHIFT 4 #define PCMCIA_CCR_SOCKETCOPY_SOCKET_MASK 0x0F #define PCMCIA_CCR_EXTSTATUS 0x08 #define PCMCIA_CCR_IOBASE0 0x0A #define PCMCIA_CCR_IOBASE1 0x0C #define PCMCIA_CCR_IOBASE2 0x0E #define PCMCIA_CCR_IOBASE3 0x10 #define PCMCIA_CCR_IOSIZE 0x12 #define PCMCIA_CCR_SIZE 0x14 #endif /* PCMCIAREG_H */ gxemul-0.6.1/src/include/thirdparty/exec_elf.h000644 001750 001750 00000055552 13402411502 021570 0ustar00debugdebug000000 000000 /* gxemul: $Id: exec_elf.h,v 1.7 2007-07-20 09:03:33 debug Exp $ */ #ifndef __EXEC_ELF_H #define __EXEC_ELF_H #include /* $NetBSD: exec_elf.h,v 1.37.4.2 2001/05/01 12:05:43 he Exp $ */ /*- * Copyright (c) 1994 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Christos Zoulas. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ typedef uint8_t Elf_Byte; typedef uint32_t Elf32_Addr; #define ELF32_FSZ_ADDR 4 typedef uint32_t Elf32_Off; #define ELF32_FSZ_OFF 4 typedef int32_t Elf32_Sword; #define ELF32_FSZ_SWORD 4 typedef uint32_t Elf32_Word; #define ELF32_FSZ_WORD 4 typedef uint16_t Elf32_Half; #define ELF32_FSZ_HALF 2 typedef uint64_t Elf64_Addr; #define ELF64_FSZ_ADDR 8 typedef uint64_t Elf64_Off; #define ELF64_FSZ_OFF 8 typedef int32_t Elf64_Shalf; #define ELF64_FSZ_SHALF 4 #ifdef __sparc_v9__ /* #error weird */ typedef int32_t Elf64_Sword; #define ELF64_FSZ_SWORD 4 typedef uint32_t Elf64_Word; #define ELF64_FSZ_WORD 4 #else typedef int64_t Elf64_Sword; #define ELF64_FSZ_SWORD 8 typedef uint64_t Elf64_Word; #define ELF64_FSZ_WORD 8 #endif typedef int64_t Elf64_Sxword; #define ELF64_FSZ_XWORD 8 typedef uint64_t Elf64_Xword; #define ELF64_FSZ_XWORD 8 typedef uint32_t Elf64_Half; #define ELF64_FSZ_HALF 4 typedef uint16_t Elf64_Quarter; #define ELF64_FSZ_QUARTER 2 /* * ELF Header */ #define ELF_NIDENT 16 typedef struct { unsigned char e_ident[ELF_NIDENT]; /* Id bytes */ Elf32_Half e_type; /* file type */ Elf32_Half e_machine; /* machine type */ Elf32_Word e_version; /* version number */ Elf32_Addr e_entry; /* entry point */ Elf32_Off e_phoff; /* Program hdr offset */ Elf32_Off e_shoff; /* Section hdr offset */ Elf32_Word e_flags; /* Processor flags */ Elf32_Half e_ehsize; /* sizeof ehdr */ Elf32_Half e_phentsize; /* Program header entry size */ Elf32_Half e_phnum; /* Number of program headers */ Elf32_Half e_shentsize; /* Section header entry size */ Elf32_Half e_shnum; /* Number of section headers */ Elf32_Half e_shstrndx; /* String table index */ } Elf32_Ehdr; typedef struct { unsigned char e_ident[ELF_NIDENT]; /* Id bytes */ Elf64_Quarter e_type; /* file type */ Elf64_Quarter e_machine; /* machine type */ Elf64_Half e_version; /* version number */ Elf64_Addr e_entry; /* entry point */ Elf64_Off e_phoff; /* Program hdr offset */ Elf64_Off e_shoff; /* Section hdr offset */ Elf64_Half e_flags; /* Processor flags */ Elf64_Quarter e_ehsize; /* sizeof ehdr */ Elf64_Quarter e_phentsize; /* Program header entry size */ Elf64_Quarter e_phnum; /* Number of program headers */ Elf64_Quarter e_shentsize; /* Section header entry size */ Elf64_Quarter e_shnum; /* Number of section headers */ Elf64_Quarter e_shstrndx; /* String table index */ } Elf64_Ehdr; /* e_ident offsets */ #define EI_MAG0 0 /* '\177' */ #define EI_MAG1 1 /* 'E' */ #define EI_MAG2 2 /* 'L' */ #define EI_MAG3 3 /* 'F' */ #define EI_CLASS 4 /* File class */ #define EI_DATA 5 /* Data encoding */ #define EI_VERSION 6 /* File version */ #define EI_OSABI 7 /* Operating system/ABI identification */ #define EI_ABIVERSION 8 /* ABI version */ #define EI_PAD 9 /* Start of padding bytes up to EI_NIDENT*/ /* e_ident[ELFMAG0,ELFMAG3] */ #define ELFMAG0 0x7f #define ELFMAG1 'E' #define ELFMAG2 'L' #define ELFMAG3 'F' #define ELFMAG "\177ELF" #define SELFMAG 4 /* e_ident[EI_CLASS] */ #define ELFCLASSNONE 0 /* Invalid class */ #define ELFCLASS32 1 /* 32-bit objects */ #define ELFCLASS64 2 /* 64-bit objects */ #define ELFCLASSNUM 3 /* e_ident[EI_DATA] */ #define ELFDATANONE 0 /* Invalid data encoding */ #define ELFDATA2LSB 1 /* 2's complement values, LSB first */ #define ELFDATA2MSB 2 /* 2's complement values, MSB first */ /* e_ident[EI_VERSION] */ #define EV_NONE 0 /* Invalid version */ #define EV_CURRENT 1 /* Current version */ #define EV_NUM 2 /* e_ident[EI_OSABI] */ #define ELFOSABI_SYSV 0 /* UNIX System V ABI */ #define ELFOSABI_HPUX 1 /* HP-UX operating system */ #define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ /* e_type */ #define ET_NONE 0 /* No file type */ #define ET_REL 1 /* Relocatable file */ #define ET_EXEC 2 /* Executable file */ #define ET_DYN 3 /* Shared object file */ #define ET_CORE 4 /* Core file */ #define ET_NUM 5 #define ET_LOOS 0xfe00 /* Operating system specific range */ #define ET_HIOS 0xfeff #define ET_LOPROC 0xff00 /* Processor-specific range */ #define ET_HIPROC 0xffff /* e_machine */ #define EM_NONE 0 /* No machine */ #define EM_M32 1 /* AT&T WE 32100 */ #define EM_SPARC 2 /* SPARC */ #define EM_386 3 /* Intel 80386 */ #define EM_68K 4 /* Motorola 68000 */ #define EM_88K 5 /* Motorola 88000 */ #define EM_486 6 /* Intel 80486 */ #define EM_860 7 /* Intel 80860 */ #define EM_MIPS 8 /* MIPS I Architecture */ #define EM_S370 9 /* Amdahl UTS on System/370 */ #define EM_MIPS_RS3_LE 10 /* MIPS RS3000 Little-endian */ #define EM_RS6000 11 /* IBM RS/6000 XXX reserved */ #define EM_PARISC 15 /* Hewlett-Packard PA-RISC */ #define EM_NCUBE 16 /* NCube XXX reserved */ #define EM_VPP500 17 /* Fujitsu VPP500 */ #define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ #define EM_960 19 /* Intel 80960 */ #define EM_PPC 20 /* PowerPC */ #define EM_PPC64 21 /* PowerPC 64-bit (GXemul addition) */ #define EM_V800 36 /* NEC V800 */ #define EM_FR20 37 /* Fujitsu FR20 */ #define EM_RH32 38 /* TRW RH-32 */ #define EM_RCE 39 /* Motorola RCE */ #define EM_ARM 40 /* Advanced RISC Machines ARM */ #define EM_ALPHA 41 /* DIGITAL Alpha */ #define EM_SH 42 /* Hitachi Super-H */ #define EM_SPARCV9 43 /* SPARC Version 9 */ #define EM_TRICORE 44 /* Siemens Tricore */ #define EM_ARC 45 /* Argonaut RISC Core */ #define EM_H8_300 46 /* Hitachi H8/300 */ #define EM_H8_300H 47 /* Hitachi H8/300H */ #define EM_H8S 48 /* Hitachi H8S */ #define EM_H8_500 49 /* Hitachi H8/500 */ #define EM_IA_64 50 /* Intel Merced Processor */ #define EM_MIPS_X 51 /* Stanford MIPS-X */ #define EM_COLDFIRE 52 /* Motorola Coldfire */ #define EM_68HC12 53 /* Motorola MC68HC12 */ #define EM_AMD64 62 /* AMD64 (GXemul addition) */ #define EM_VAX 75 /* DIGITAL VAX */ #define EM_AVR 83 /* Atmel AVR (GXemul addition) */ #define EM_M32R 88 /* Renesas M32R (GXemul addition) */ #define EM_ALPHA_EXP 36902 /* used by NetBSD/alpha; obsolete */ #define EM_NUM 36903 /* * Program Header */ typedef struct { Elf32_Word p_type; /* entry type */ Elf32_Off p_offset; /* offset */ Elf32_Addr p_vaddr; /* virtual address */ Elf32_Addr p_paddr; /* physical address */ Elf32_Word p_filesz; /* file size */ Elf32_Word p_memsz; /* memory size */ Elf32_Word p_flags; /* flags */ Elf32_Word p_align; /* memory & file alignment */ } Elf32_Phdr; typedef struct { Elf64_Half p_type; /* entry type */ Elf64_Half p_flags; /* flags */ Elf64_Off p_offset; /* offset */ Elf64_Addr p_vaddr; /* virtual address */ Elf64_Addr p_paddr; /* physical address */ Elf64_Xword p_filesz; /* file size */ Elf64_Xword p_memsz; /* memory size */ Elf64_Xword p_align; /* memory & file alignment */ } Elf64_Phdr; /* p_type */ #define PT_NULL 0 /* Program header table entry unused */ #define PT_LOAD 1 /* Loadable program segment */ #define PT_DYNAMIC 2 /* Dynamic linking information */ #define PT_INTERP 3 /* Program interpreter */ #define PT_NOTE 4 /* Auxiliary information */ #define PT_SHLIB 5 /* Reserved, unspecified semantics */ #define PT_PHDR 6 /* Entry for header table itself */ #define PT_NUM 7 /* p_flags */ #define PF_R 0x4 /* Segment is readable */ #define PF_W 0x2 /* Segment is writable */ #define PF_X 0x1 /* Segment is executable */ #define PF_MASKOS 0x0ff00000 /* Opersting system specific values */ #define PF_MASKPROC 0xf0000000 /* Processor-specific values */ #define PT_LOPROC 0x70000000 /* Processor-specific range */ #define PT_HIPROC 0x7fffffff #define PT_MIPS_REGINFO 0x70000000 /* * Section Headers */ typedef struct { Elf32_Word sh_name; /* section name (.shstrtab index) */ Elf32_Word sh_type; /* section type */ Elf32_Word sh_flags; /* section flags */ Elf32_Addr sh_addr; /* virtual address */ Elf32_Off sh_offset; /* file offset */ Elf32_Word sh_size; /* section size */ Elf32_Word sh_link; /* link to another */ Elf32_Word sh_info; /* misc info */ Elf32_Word sh_addralign; /* memory alignment */ Elf32_Word sh_entsize; /* table entry size */ } Elf32_Shdr; typedef struct { Elf64_Half sh_name; /* section name (.shstrtab index) */ Elf64_Half sh_type; /* section type */ Elf64_Xword sh_flags; /* section flags */ Elf64_Addr sh_addr; /* virtual address */ Elf64_Off sh_offset; /* file offset */ Elf64_Xword sh_size; /* section size */ Elf64_Half sh_link; /* link to another */ Elf64_Half sh_info; /* misc info */ Elf64_Xword sh_addralign; /* memory alignment */ Elf64_Xword sh_entsize; /* table entry size */ } Elf64_Shdr; /* sh_type */ #define SHT_NULL 0 #define SHT_PROGBITS 1 #define SHT_SYMTAB 2 #define SHT_STRTAB 3 #define SHT_RELA 4 #define SHT_HASH 5 #define SHT_DYNAMIC 6 #define SHT_NOTE 7 #define SHT_NOBITS 8 #define SHT_REL 9 #define SHT_SHLIB 10 #define SHT_DYNSYM 11 #define SHT_NUM 12 #define SHT_LOOS 0x60000000 /* Operating system specific range */ #define SHT_HIOS 0x6fffffff #define SHT_LOPROC 0x70000000 /* Processor-specific range */ #define SHT_HIPROC 0x7fffffff #define SHT_LOUSER 0x80000000 /* Application-specific range */ #define SHT_HIUSER 0xffffffff /* sh_flags */ #define SHF_WRITE 0x1 /* Section contains writable data */ #define SHF_ALLOC 0x2 /* Section occupies memory */ #define SHF_EXECINSTR 0x4 /* Section contains executable insns */ #define SHF_MASKOS 0x0f000000 /* Operating system specific values */ #define SHF_MASKPROC 0xf0000000 /* Processor-specific values */ /* * Symbol Table */ typedef struct { Elf32_Word st_name; /* Symbol name (.symtab index) */ Elf32_Word st_value; /* value of symbol */ Elf32_Word st_size; /* size of symbol */ Elf_Byte st_info; /* type / binding attrs */ Elf_Byte st_other; /* unused */ Elf32_Half st_shndx; /* section index of symbol */ } Elf32_Sym; typedef struct { Elf64_Half st_name; /* Symbol name (.symtab index) */ Elf_Byte st_info; /* type / binding attrs */ Elf_Byte st_other; /* unused */ Elf64_Quarter st_shndx; /* section index of symbol */ Elf64_Addr st_value; /* value of symbol */ Elf64_Xword st_size; /* size of symbol */ } Elf64_Sym; /* Symbol Table index of the undefined symbol */ #define ELF_SYM_UNDEFINED 0 /* st_info: Symbol Bindings */ #define STB_LOCAL 0 /* local symbol */ #define STB_GLOBAL 1 /* global symbol */ #define STB_WEAK 2 /* weakly defined global symbol */ #define STB_NUM 3 #define STB_LOOS 10 /* Operating system specific range */ #define STB_HIOS 12 #define STB_LOPROC 13 /* Processor-specific range */ #define STB_HIPROC 15 /* st_info: Symbol Types */ #define STT_NOTYPE 0 /* Type not specified */ #define STT_OBJECT 1 /* Associated with a data object */ #define STT_FUNC 2 /* Associated with a function */ #define STT_SECTION 3 /* Associated with a section */ #define STT_FILE 4 /* Associated with a file name */ #define STT_NUM 5 #define STT_LOOS 10 /* Operating system specific range */ #define STT_HIOS 12 #define STT_LOPROC 13 /* Processor-specific range */ #define STT_HIPROC 15 /* st_info utility macros */ #define ELF32_ST_BIND(info) ((Elf32_Word)(info) >> 4) #define ELF32_ST_TYPE(info) ((Elf32_Word)(info) & 0xf) #define ELF32_ST_INFO(bind,type) ((Elf_Byte)(((bind) << 4) | ((type) & 0xf))) #define ELF64_ST_BIND(info) ((Elf64_Xword)(info) >> 4) #define ELF64_ST_TYPE(info) ((Elf64_Xword)(info) & 0xf) #define ELF64_ST_INFO(bind,type) ((Elf_Byte)(((bind) << 4) | ((type) & 0xf))) /* * Special section indexes */ #define SHN_UNDEF 0 /* Undefined section */ #define SHN_LORESERVE 0xff00 /* Reserved range */ #define SHN_ABS 0xfff1 /* Absolute symbols */ #define SHN_COMMON 0xfff2 /* Common symbols */ #define SHN_HIRESERVE 0xffff #define SHN_LOPROC 0xff00 /* Processor-specific range */ #define SHN_HIPROC 0xff1f #define SHN_LOOS 0xff20 /* Operating system specific range */ #define SHN_HIOS 0xff3f #define SHN_MIPS_ACOMMON 0xff00 #define SHN_MIPS_TEXT 0xff01 #define SHN_MIPS_DATA 0xff02 #define SHN_MIPS_SCOMMON 0xff03 /* * Relocation Entries */ typedef struct { Elf32_Word r_offset; /* where to do it */ Elf32_Word r_info; /* index & type of relocation */ } Elf32_Rel; typedef struct { Elf32_Word r_offset; /* where to do it */ Elf32_Word r_info; /* index & type of relocation */ Elf32_Sword r_addend; /* adjustment value */ } Elf32_Rela; /* r_info utility macros */ #define ELF32_R_SYM(info) ((info) >> 8) #define ELF32_R_TYPE(info) ((info) & 0xff) #define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) typedef struct { Elf64_Addr r_offset; /* where to do it */ Elf64_Xword r_info; /* index & type of relocation */ } Elf64_Rel; typedef struct { Elf64_Addr r_offset; /* where to do it */ Elf64_Xword r_info; /* index & type of relocation */ Elf64_Sxword r_addend; /* adjustment value */ } Elf64_Rela; /* r_info utility macros */ #define ELF64_R_SYM(info) ((info) >> 32) #define ELF64_R_TYPE(info) ((info) & 0xffffffff) #define ELF64_R_INFO(sym,type) (((sym) << 32) + (type)) /* * Dynamic Section structure array */ typedef struct { Elf32_Word d_tag; /* entry tag value */ union { Elf32_Addr d_ptr; Elf32_Word d_val; } d_un; } Elf32_Dyn; typedef struct { Elf64_Xword d_tag; /* entry tag value */ union { Elf64_Addr d_ptr; Elf64_Xword d_val; } d_un; } Elf64_Dyn; /* d_tag */ #define DT_NULL 0 /* Marks end of dynamic array */ #define DT_NEEDED 1 /* Name of needed library (DT_STRTAB offset) */ #define DT_PLTRELSZ 2 /* Size, in bytes, of relocations in PLT */ #define DT_PLTGOT 3 /* Address of PLT and/or GOT */ #define DT_HASH 4 /* Address of symbol hash table */ #define DT_STRTAB 5 /* Address of string table */ #define DT_SYMTAB 6 /* Address of symbol table */ #define DT_RELA 7 /* Address of Rela relocation table */ #define DT_RELASZ 8 /* Size, in bytes, of DT_RELA table */ #define DT_RELAENT 9 /* Size, in bytes, of one DT_RELA entry */ #define DT_STRSZ 10 /* Size, in bytes, of DT_STRTAB table */ #define DT_SYMENT 11 /* Size, in bytes, of one DT_SYMTAB entry */ #define DT_INIT 12 /* Address of initialization function */ #define DT_FINI 13 /* Address of termination function */ #define DT_SONAME 14 /* Shared object name (DT_STRTAB offset) */ #define DT_RPATH 15 /* Library search path (DT_STRTAB offset) */ #define DT_SYMBOLIC 16 /* Start symbol search within local object */ #define DT_REL 17 /* Address of Rel relocation table */ #define DT_RELSZ 18 /* Size, in bytes, of DT_REL table */ #define DT_RELENT 19 /* Size, in bytes, of one DT_REL entry */ #define DT_PLTREL 20 /* Type of PLT relocation entries */ #define DT_DEBUG 21 /* Used for debugging; unspecified */ #define DT_TEXTREL 22 /* Relocations might modify non-writable seg */ #define DT_JMPREL 23 /* Address of relocations associated with PLT */ #define DT_BIND_NOW 24 /* Process all relocations at load-time */ #define DT_INIT_ARRAY 25 /* Address of initialization function array */ #define DT_FINI_ARRAY 26 /* Size, in bytes, of DT_INIT_ARRAY array */ #define DT_INIT_ARRAYSZ 27 /* Address of termination function array */ #define DT_FINI_ARRAYSZ 28 /* Size, in bytes, of DT_FINI_ARRAY array*/ #define DT_NUM 29 #define DT_LOOS 0x60000000 /* Operating system specific range */ #define DT_HIOS 0x6fffffff #define DT_LOPROC 0x70000000 /* Processor-specific range */ #define DT_HIPROC 0x7fffffff /* * Auxiliary Vectors */ typedef struct { Elf32_Word a_type; /* 32-bit id */ Elf32_Word a_v; /* 32-bit id */ } Aux32Info; typedef struct { Elf64_Half a_type; /* 32-bit id */ Elf64_Xword a_v; /* 64-bit id */ } Aux64Info; /* a_type */ #define AT_NULL 0 /* Marks end of array */ #define AT_IGNORE 1 /* No meaning, a_un is undefined */ #define AT_EXECFD 2 /* Open file descriptor of object file */ #define AT_PHDR 3 /* &phdr[0] */ #define AT_PHENT 4 /* sizeof(phdr[0]) */ #define AT_PHNUM 5 /* # phdr entries */ #define AT_PAGESZ 6 /* PAGESIZE */ #define AT_BASE 7 /* Interpreter base addr */ #define AT_FLAGS 8 /* Processor flags */ #define AT_ENTRY 9 /* Entry address of executable */ #define AT_DCACHEBSIZE 10 /* Data cache block size */ #define AT_ICACHEBSIZE 11 /* Instruction cache block size */ #define AT_UCACHEBSIZE 12 /* Unified cache block size */ /* Vendor specific */ #define AT_MIPS_NOTELF 10 /* XXX a_val != 0 -> MIPS XCOFF executable */ #define AT_SUN_UID 2000 /* euid */ #define AT_SUN_RUID 2001 /* ruid */ #define AT_SUN_GID 2002 /* egid */ #define AT_SUN_RGID 2003 /* rgid */ /* Solaris kernel specific */ #define AT_SUN_LDELF 2004 /* dynamic linker's ELF header */ #define AT_SUN_LDSHDR 2005 /* dynamic linker's section header */ #define AT_SUN_LDNAME 2006 /* dynamic linker's name */ #define AT_SUN_LPGSIZE 2007 /* large pagesize */ /* Other information */ #define AT_SUN_PLATFORM 2008 /* sysinfo(SI_PLATFORM) */ #define AT_SUN_HWCAP 2009 /* process hardware capabilities */ #define AT_SUN_IFLUSH 2010 /* do we need to flush the instruction cache? */ #define AT_SUN_CPU 2011 /* cpu name */ /* ibcs2 emulation band aid */ #define AT_SUN_EMUL_ENTRY 2012 /* coff entry point */ #define AT_SUN_EMUL_EXECFD 2013 /* coff file descriptor */ /* Executable's fully resolved name */ #define AT_SUN_EXECNAME 2014 /* * Note Headers */ typedef struct { Elf32_Word n_namesz; Elf32_Word n_descsz; Elf32_Word n_type; } Elf32_Nhdr; typedef struct { Elf64_Half n_namesz; Elf64_Half n_descsz; Elf64_Half n_type; } Elf64_Nhdr; #define ELF_NOTE_TYPE_OSVERSION 1 /* NetBSD-specific note type: OS Version. desc is 4-byte NetBSD integer. */ #define ELF_NOTE_NETBSD_TYPE_OSVERSION ELF_NOTE_TYPE_OSVERSION /* NetBSD-specific note type: Emulation name. desc is emul name string. */ #define ELF_NOTE_NETBSD_TYPE_EMULNAME 2 /* NetBSD-specific note name and description sizes */ #define ELF_NOTE_NETBSD_NAMESZ 7 #define ELF_NOTE_NETBSD_DESCSZ 4 /* NetBSD-specific note name */ #define ELF_NOTE_NETBSD_NAME "NetBSD\0\0" /* GNU-specific note name and description sizes */ #define ELF_NOTE_GNU_NAMESZ 4 #define ELF_NOTE_GNU_DESCSZ 4 /* GNU-specific note name */ #define ELF_NOTE_GNU_NAME "GNU\0" /* GNU-specific OS/version value stuff */ #define ELF_NOTE_GNU_OSMASK (u_int32_t)0xff000000 #define ELF_NOTE_GNU_OSLINUX (u_int32_t)0x01000000 #define ELF_NOTE_GNU_OSMACH (u_int32_t)0x00000000 #if defined(ELFSIZE) #define CONCAT(x,y) __CONCAT(x,y) #define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x))) #define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y)))) #define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE)) #define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x))) #endif /* #include */ #if defined(ELFSIZE) && (ELFSIZE == 32) #define Elf_Ehdr Elf32_Ehdr #define Elf_Phdr Elf32_Phdr #define Elf_Shdr Elf32_Shdr #define Elf_Sym Elf32_Sym #define Elf_Rel Elf32_Rel #define Elf_Rela Elf32_Rela #define Elf_Dyn Elf32_Dyn #define Elf_Word Elf32_Word #define Elf_Sword Elf32_Sword #define Elf_Addr Elf32_Addr #define Elf_Off Elf32_Off #define Elf_Nhdr Elf32_Nhdr #define ELF_R_SYM ELF32_R_SYM #define ELF_R_TYPE ELF32_R_TYPE #define ELFCLASS ELFCLASS32 #define ELF_ST_BIND ELF32_ST_BIND #define ELF_ST_TYPE ELF32_ST_TYPE #define ELF_ST_INFO ELF32_ST_INFO #define AuxInfo Aux32Info #elif defined(ELFSIZE) && (ELFSIZE == 64) #define Elf_Ehdr Elf64_Ehdr #define Elf_Phdr Elf64_Phdr #define Elf_Shdr Elf64_Shdr #define Elf_Sym Elf64_Sym #define Elf_Rel Elf64_Rel #define Elf_Rela Elf64_Rela #define Elf_Dyn Elf64_Dyn #define Elf_Word Elf64_Word #define Elf_Sword Elf64_Sword #define Elf_Addr Elf64_Addr #define Elf_Off Elf64_Off #define Elf_Nhdr Elf64_Nhdr #define ELF_R_SYM ELF64_R_SYM #define ELF_R_TYPE ELF64_R_TYPE #define ELFCLASS ELFCLASS64 #define ELF_ST_BIND ELF64_ST_BIND #define ELF_ST_TYPE ELF64_ST_TYPE #define ELF_ST_INFO ELF64_ST_INFO #define AuxInfo Aux64Info #endif #ifdef _KERNEL #define ELF_AUX_ENTRIES 8 /* Size of aux array passed to loader */ #define ELF32_NO_ADDR (~(Elf32_Addr)0) /* Indicates addr. not yet filled in */ #define ELF64_NO_ADDR (~(Elf64_Addr)0) /* Indicates addr. not yet filled in */ #if defined(ELFSIZE) && (ELFSIZE == 64) #define ELF_NO_ADDR ELF64_NO_ADDR #elif defined(ELFSIZE) && (ELFSIZE == 32) #define ELF_NO_ADDR ELF32_NO_ADDR #endif #if defined(ELFSIZE) struct elf_args { Elf_Addr arg_entry; /* program entry point */ Elf_Addr arg_interp; /* Interpreter load address */ Elf_Addr arg_phaddr; /* program header address */ Elf_Addr arg_phentsize; /* Size of program header */ Elf_Addr arg_phnum; /* Number of program headers */ }; #endif #ifndef _LKM #include "opt_execfmt.h" #endif #ifdef EXEC_ELF32 int exec_elf32_makecmds __P((struct proc *, struct exec_package *)); int elf32_read_from __P((struct proc *, struct vnode *, u_long, caddr_t, int)); void *elf32_copyargs __P((struct exec_package *, struct ps_strings *, void *, void *)); #endif #ifdef EXEC_ELF64 int exec_elf64_makecmds __P((struct proc *, struct exec_package *)); int elf64_read_from __P((struct proc *, struct vnode *, u_long, caddr_t, int)); void *elf64_copyargs __P((struct exec_package *, struct ps_strings *, void *, void *)); #endif /* common */ int exec_elf_setup_stack __P((struct proc *, struct exec_package *)); #endif /* _KERNEL */ #endif /* __EXEC_ELF_H */ gxemul-0.6.1/src/include/thirdparty/vripreg.h000644 001750 001750 00000026730 13402411502 021470 0ustar00debugdebug000000 000000 /* $NetBSD: vripreg.h,v 1.8 2003/04/01 02:33:52 igy Exp $ */ #ifndef VRIPREG_H #define VRIPREG_H /*- * Copyright (c) 1999 * Shin Takemura and PocketBSD Project. All rights reserved. * Copyright (c) 2001 SATO Kazumi, All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the PocketBSD project * and its contributors. * 4. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #define VRIP_NO_ADDR 0x00000000 /* * VR4181 registers */ #define VR4181_BCU_ADDR 0x0a000000 #define VR4181_DMAAU_ADDR VRIP_NO_ADDR #define VR4181_DCU_ADDR VRIP_NO_ADDR #define VR4181_CMU_ADDR 0x0a000004 #define VR4181_ICU_ADDR 0x0a000080 #define VR4181_PMU_ADDR 0x0a0000a0 #define VR4181_RTC_ADDR 0x0a0000c0 #define VR4181_DSU_ADDR 0x0a0000e0 #define VR4181_GIU_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4181_PIU_ADDR 0x0a000122 #define VR4181_AIU_ADDR 0x0a000160 #define VR4181_KIU_ADDR 0x0a000180 #define VR4181_DSIU_ADDR 0x0a0001a0 #define VR4181_LED_ADDR 0x0a000240 #define VR4181_SIU_ADDR 0x0c000010 #define VR4181_HSP_ADDR 0x0a000020 #define VR4181_FIR_ADDR 0x0a000000 /* XXX */ #define VR4181_MEMCON_ADDR 0x0a000300 #define VR4181_ISABRG_ADDR 0x0b0002c0 #define VR4181_ECU_ADDR 0x0b0008e0 #define VR4181_DCU81_ADDR 0x0a000020 #define VR4181_CSI81_ADDR 0x0b000900 #define VR4181_GIU81_ADDR 0x0b000300 #define VR4181_LCD_ADDR 0x0a000400 #define VR4181_SIU1_ADDR 0x0c000000 #define VR4181_SCU_ARR VRIP_NO_ADDR /* XXX: no register */ #define VR4181_SDRAMU_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4181_PCI_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4181_PCICONF_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4181_CSI_ADDR VRIP_NO_ADDR /* XXX: no register */ /* * VR4101-4121 registers */ #define VR4102_BCU_ADDR 0x0b000000 #define VR4102_DMAAU_ADDR 0x0b000020 #define VR4102_DCU_ADDR 0x0b000040 #define VR4102_CMU_ADDR 0x0b000060 #define VR4102_ICU_ADDR 0x0b000080 #define VR4102_PMU_ADDR 0x0b0000a0 #define VR4102_RTC_ADDR 0x0b0000c0 #define VR4102_DSU_ADDR 0x0b0000e0 #define VR4102_GIU_ADDR 0x0b000100 #define VR4102_PIU_ADDR 0x0b000120 #define VR4102_AIU_ADDR 0x0b000160 #define VR4102_KIU_ADDR 0x0b000180 #define VR4102_DSIU_ADDR 0x0b0001a0 #define VR4102_LED_ADDR 0x0b000240 #define VR4102_SIU_ADDR 0x0c000000 #define VR4102_HSP_ADDR 0x0c000020 #define VR4102_FIR_ADDR 0x0b000000 /* XXX */ #define VR4102_MEMCON_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4102_ISABRG_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4102_ECU_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4102_DCU81_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4102_CSI81_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4102_GIU81_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4102_SIU1_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4102_SCU_ARR VRIP_NO_ADDR /* XXX: no register */ #define VR4102_SDRAMU_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4102_PCI_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4102_PCICONF_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4102_CSI_ADDR VRIP_NO_ADDR /* XXX: no register */ /* * VR4122 registers */ #define VR4122_BCU_ADDR 0x0f000000 #define VR4122_DMAAU_ADDR 0x0f000020 #define VR4122_DCU_ADDR 0x0f000040 #define VR4122_CMU_ADDR 0x0f000060 #define VR4122_ICU_ADDR 0x0f000080 #define VR4122_PMU_ADDR 0x0f0000c0 #define VR4122_RTC_ADDR 0x0f000100 #define VR4122_DSU_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4122_GIU_ADDR 0x0f000140 #define VR4122_PIU_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4122_AIU_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4122_KIU_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4122_DSIU_ADDR 0x0f000820 #define VR4122_LED_ADDR 0x0f000180 #define VR4122_SIU_ADDR 0x0f000800 #define VR4122_HSP_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4122_FIR_ADDR 0x0f000840 /* XXX */ #define VR4122_MEMCON_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4122_ISABRG_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4122_ECU_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4122_DCU81_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4122_CSI81_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4122_GIU81_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4122_SIU1_ADDR VRIP_NO_ADDR /* XXX: no register */ #define VR4122_SCU_ARR 0x0f001000 #define VR4122_SDRAMU_ADDR 0x0f000400 #define VR4122_PCI_ADDR 0x0f000c00 #define VR4122_PCICONF_ADDR 0x0f000d00 #define VR4122_CSI_ADDR 0x0f0001a0 /* * VRIP base address * * REQUIRE: opt_vr41xx.h, vrcpudef.h */ #if 0 #include "opt_vr41xx.h" #include #endif #if defined SINGLE_VRIP_BASE #if defined VRGROUP_4181 #define VRIP_BASE_ADDR 0x0a000000 #define VRIP_BCU_ADDR VR4181_BCU_ADDR #define VRIP_DMAAU_ADDR VR4181_DMAAU_ADDR #define VRIP_DCU_ADDR VR4181_DCU_ADDR #define VRIP_CMU_ADDR VR4181_CMU_ADDR #define VRIP_ICU_ADDR VR4181_ICU_ADDR #define VRIP_PMU_ADDR VR4181_PMU_ADDR #define VRIP_RTC_ADDR VR4181_RTC_ADDR #define VRIP_DSU_ADDR VR4181_DSU_ADDR #define VRIP_GIU_ADDR VR4181_GIU_ADDR #define VRIP_PIU_ADDR VR4181_PIU_ADDR #define VRIP_AIU_ADDR VR4181_AIU_ADDR #define VRIP_KIU_ADDR VR4181_KIU_ADDR #define VRIP_DSIU_ADDR VR4181_DSIU_ADDR #define VRIP_LED_ADDR VR4181_LED_ADDR #define VRIP_SIU_ADDR VR4181_SIU_ADDR #define VRIP_HSP_ADDR VR4181_HSP_ADDR #define VRIP_FIR_ADDR VR4181_FIR_ADDR #define VRIP_MEMCON_ADDR VR4181_MEMCON_ADDR #define VRIP_ISABRG_ADDR VR4181_ISABRG_ADDR #define VRIP_ECU_ADDR VR4181_ECU_ADDR #define VRIP_DCU81_ADDR VR4181_DCU81_ADDR #define VRIP_CSI81_ADDR VR4181_CSI81_ADDR #define VRIP_GIU81_ADDR VR4181_GIU81_ADDR #define VRIP_LCD_ADDR VR4181_LCD_ADDR #define VRIP_SIU1_ADDR VR4181_SIU1_ADDR #define VRIP_SCU_ARR VR4181_SCU_ARR /* XXX: no register */ #define VRIP_SDRAMU_ADDR VR4181_SDRAMU_ADDR /* XXX: no register */ #define VRIP_PCI_ADDR VR4181_PCI_ADDR /* XXX: no register */ #define VRIP_PCICONF_ADDR VR4181_PCICONF_ADDR /* XXX: no register */ #define VRIP_CSI_ADDR VR4181_CSI_ADDR /* XXX: no register */ #endif /* VRGROUP_4181 */ #if defined VRGROUP_4122_4131 #define VRIP_BASE_ADDR 0x0f000000 #define VRIP_BCU_ADDR VR4122_BCU_ADDR #define VRIP_DMAAU_ADDR VR4122_DMAAU_ADDR #define VRIP_DCU_ADDR VR4122_DCU_ADDR #define VRIP_CMU_ADDR VR4122_CMU_ADDR #define VRIP_ICU_ADDR VR4122_ICU_ADDR #define VRIP_PMU_ADDR VR4122_PMU_ADDR #define VRIP_RTC_ADDR VR4122_RTC_ADDR #define VRIP_DSU_ADDR VR4122_DSU_ADDR #define VRIP_GIU_ADDR VR4122_GIU_ADDR #define VRIP_PIU_ADDR VR4122_PIU_ADDR #define VRIP_AIU_ADDR VR4122_AIU_ADDR #define VRIP_KIU_ADDR VR4122_KIU_ADDR #define VRIP_DSIU_ADDR VR4122_DSIU_ADDR #define VRIP_LED_ADDR VR4122_LED_ADDR #define VRIP_SIU_ADDR VR4122_SIU_ADDR #define VRIP_HSP_ADDR VR4122_HSP_ADDR #define VRIP_FIR_ADDR VR4122_FIR_ADDR #define VRIP_MEMCON_ADDR VR4122_MEMCON_ADDR /* XXX: no register */ #define VRIP_ISABRG_ADDR VR4122_ISABRG_ADDR /* XXX: no register */ #define VRIP_ECU_ADDR VR4122_ECU_ADDR /* XXX: no register */ #define VRIP_DCU81_ADDR VR4122_DCU81_ADDR /* XXX: no register */ #define VRIP_CSI81_ADDR VR4122_CSI81_ADDR /* XXX: no register */ #define VRIP_GIU81_ADDR VR4122_CSI81_ADDR /* XXX: no register */ #define VRIP_SIU1_ADDR VR4122_SIU1_ADDR /* XXX: no register */ #define VRIP_SCU_ARR VR4122_SCU_ARR /* XXX: no register */ #define VRIP_SDRAMU_ADDR VR4122_SDRAMU_ADDR /* XXX: no register */ #define VRIP_PCI_ADDR VR4122_PCI_ADDR /* XXX: no register */ #define VRIP_PCICONF_ADDR VR4122_PCICONF_ADDR /* XXX: no register */ #define VRIP_CSI_ADDR VR4122_CSI_ADDR /* XXX: no register */ #endif /* VRGROUP_4122_4131 */ #if defined VRGROUP_4102_4121 #define VRIP_BASE_ADDR 0x0b000000 #define VRIP_BCU_ADDR VR4102_BCU_ADDR #define VRIP_DMAAU_ADDR VR4102_DMAAU_ADDR #define VRIP_DCU_ADDR VR4102_DCU_ADDR #define VRIP_CMU_ADDR VR4102_CMU_ADDR #define VRIP_ICU_ADDR VR4102_ICU_ADDR #define VRIP_PMU_ADDR VR4102_PMU_ADDR #define VRIP_RTC_ADDR VR4102_RTC_ADDR #define VRIP_DSU_ADDR VR4102_DSU_ADDR #define VRIP_GIU_ADDR VR4102_GIU_ADDR #define VRIP_PIU_ADDR VR4102_PIU_ADDR #define VRIP_AIU_ADDR VR4102_AIU_ADDR #define VRIP_KIU_ADDR VR4102_KIU_ADDR #define VRIP_DSIU_ADDR VR4102_DSIU_ADDR #define VRIP_LED_ADDR VR4102_LED_ADDR #define VRIP_SIU_ADDR VR4102_SIU_ADDR #define VRIP_HSP_ADDR VR4102_HSP_ADDR #define VRIP_FIR_ADDR VR4102_FIR_ADDR #define VRIP_MEMCON_ADDR VR4102_MEMCON_ADDR /* XXX: no register */ #define VRIP_ISABRG_ADDR VR4102_ISABRG_ADDR /* XXX: no register */ #define VRIP_ECU_ADDR VR4102_ECU_ADDR /* XXX: no register */ #define VRIP_DCU81_ADDR VR4102_DCU81_ADDR /* XXX: no register */ #define VRIP_CSI81_ADDR VR4102_CSI81_ADDR /* XXX: no register */ #define VRIP_GIU81_ADDR VR4102_GIU81_ADDR /* XXX: no register */ #define VRIP_SIU1_ADDR VR4102_SIU1_ADDR /* XXX: no register */ #define VRIP_SCU_ARR VR4102_SCU_ARR /* XXX: no register */ #define VRIP_SDRAMU_ADDR VR4102_SDRAMU_ADDR /* XXX: no register */ #define VRIP_PCI_ADDR VR4102_PCI_ADDR /* XXX: no register */ #define VRIP_PCICONF_ADDR VR4102_PCICONF_ADDR /* XXX: no register */ #define VRIP_CSI_ADDR VR4102_CSI_ADDR /* XXX: no register */ #endif /* VRGROUP_4102_4121 */ #endif /* SINGLE_VRIP_BASE */ /* * ICU interrupt level */ /* reserved 62-31 */ #define VRIP_INTR_BCU 25 #define VRIP_INTR_CSI 24 #define VRIP_INTR_SCU 23 #define VRIP_INTR_PCI 22 #define VRIP_INTR_LCD 22 /* 4181 */ #define VRIP_INTR_DSIU 21 #define VRIP_INTR_DCU81 21 /* 4181 */ #define VRIP_INTR_FIR 20 #define VRIP_INTR_TCLK 19 #define VRIP_INTR_CSI81 19 /* 4181 */ #define VRIP_INTR_HSP 18 #define VRIP_INTR_ECU 18 /* 4181 */ #define VRIP_INTR_LED 17 #define VRIP_INTR_RTCL2 16 /* reserved 15,14 */ #define VRIP_INTR_DOZEPIU 13 #define VRIP_INTR_CLKRUN 12 #define VRIP_INTR_SOFT 11 #define VRIP_INTR_WRBERR 10 #define VRIP_INTR_SIU 9 #define VRIP_INTR_GIU 8 #define VRIP_INTR_KIU 7 #define VRIP_INTR_AIU 6 #define VRIP_INTR_PIU 5 /* reserved 4 VRC4171 use this ??? */ #define VRIP_INTR_ETIMER 3 #define VRIP_INTR_RTCL1 2 #define VRIP_INTR_POWER 1 #define VRIP_INTR_BAT 0 #endif /* VRIPREG_H */ gxemul-0.6.1/src/include/thirdparty/dc7085.h000644 001750 001750 00000012573 13402411502 020724 0ustar00debugdebug000000 000000 /* gxemul: $Id: dc7085.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: dc7085cons.h,v 1.6 2000/01/09 15:34:42 ad Exp $ */ /* * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)dc7085cons.h 8.1 (Berkeley) 6/10/93 * * dc7085.h -- * * Definitions for the dc7085 chip. * * Copyright (C) 1989 Digital Equipment Corporation. * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies. * Digital Equipment Corporation makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * from: Header: /sprite/src/kernel/dev/ds3100.md/RCS/dc7085.h, * * v 1.4 89/08/15 19:52:46 rab Exp SPRITE (DECWRL) */ #ifndef _PMAX_DC7085CONS_H_ #define _PMAX_DC7085CONS_H_ typedef volatile struct dc7085regs { u_short dc_csr; /* control and status (R/W) */ u_short pad0[3]; short dc_rbuf_lpr; /* receiver data (R), line params (W) */ u_short pad1[3]; u_short dc_tcr; /* transmitter control (R/W) */ u_short pad2[3]; u_short dc_msr_tdr; /* modem status (R), transmit data (W) */ } dcregs; #define dc_rbuf dc_rbuf_lpr #define dc_lpr dc_rbuf_lpr #define dc_msr dc_msr_tdr #define dc_tdr dc_msr_tdr /* * Control status register bits. */ #define CSR_TRDY 0x8000 #define CSR_TIE 0x4000 #define CSR_TX_LINE_NUM 0x0300 #define CSR_RDONE 0x0080 #define CSR_RIE 0x0040 #define CSR_MSE 0x0020 #define CSR_CLR 0x0010 #define CSR_MAINT 0x0008 /* * Receiver buffer register bits. */ #define RBUF_DVAL 0x8000 #define RBUF_OERR 0x4000 #define RBUF_FERR 0x2000 #define RBUF_PERR 0x1000 #define RBUF_LINE_NUM 0x0300 #define RBUF_LINE_NUM_SHIFT 8 #define RBUF_CHAR 0x00FF /* * Transmit control register values. */ #define TCR_DTR2 0x400 #define TCR_EN3 0x008 #define TCR_EN2 0x004 #define TCR_EN1 0x002 #define TCR_EN0 0x001 #define TCR_RTS2 0x800 #define TCR_RTS3 0x200 #define TCR_DTR3 0x100 /* * Line parameter register bits. */ #define LPR_RXENAB 0x1000 #define LPR_B50 0x0000 #define LPR_B75 0x0100 #define LPR_B110 0x0200 #define LPR_B134 0x0300 #define LPR_B150 0x0400 #define LPR_B300 0x0500 #define LPR_B600 0x0600 #define LPR_B1200 0x0700 #define LPR_B1800 0x0800 #define LPR_B2000 0x0900 #define LPR_B2400 0x0A00 #define LPR_B3600 0x0B00 #define LPR_B4800 0x0C00 #define LPR_B7200 0x0D00 #define LPR_B9600 0x0E00 #define LPR_B19200 0x0F00 #define LPR_B38400 0x0F00 #define LPR_OPAR 0x0080 #define LPR_PARENB 0x0040 #define LPR_2_STOP 0x0020 #define LPR_8_BIT_CHAR 0x0018 #define LPR_7_BIT_CHAR 0x0010 #define LPR_6_BIT_CHAR 0x0008 #define LPR_5_BIT_CHAR 0x0000 /* * Modem status register bits. */ #define MSR_DSR2 0x0200 #define MSR_RI2 0x0800 #define MSR_CD2 0x0400 #define MSR_CTS2 0x0100 #define MSR_RI3 0x0008 #define MSR_CD3 0x0004 #define MSR_DSR3 0x0002 #define MSR_CTS3 0x0001 /* * The four serial ports. */ #define DCKBD_PORT 0 #define DCMOUSE_PORT 1 #define DCCOMM_PORT 2 #define DCPRINTER_PORT 3 /* bits in dm lsr, copied from dmreg.h */ #define DML_DSR 0000400 /* data set ready, not a real DM bit */ #define DML_RNG 0000200 /* ring */ #define DML_CAR 0000100 /* carrier detect */ #define DML_CTS 0000040 /* clear to send */ #define DML_SR 0000020 /* secondary receive */ #define DML_ST 0000010 /* secondary transmit */ #define DML_RTS 0000004 /* request to send */ #define DML_DTR 0000002 /* data terminal ready */ #define DML_LE 0000001 /* line enable */ #endif /* !_PMAX_DC7085CONS_H_ */ gxemul-0.6.1/src/include/thirdparty/i82365reg.h000644 001750 001750 00000032011 13402411502 021335 0ustar00debugdebug000000 000000 /* gxemul: $Id: i82365reg.h,v 1.1 2005-03-13 10:32:14 debug Exp $ */ /* $NetBSD: i82365reg.h,v 1.9 2004/07/06 14:04:51 mycroft Exp $ */ #ifndef I82365REG_H #define I82365REG_H /* * Copyright (c) 1997 Marc Horowitz. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Marc Horowitz. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * All information is from the intel 82365sl PC Card Interface Controller * (PCIC) data sheet, marked "preliminary". Order number 290423-002, January * 1993. */ #define PCIC_IOSIZE 2 #define PCIC_REG_INDEX 0 #define PCIC_REG_DATA 1 /* * The PCIC allows two chips to share the same address. In order not to run * afoul of the netbsd device model, this driver will treat those chips as * the same device. */ /* pcic can have 2 controllers offset by 0x80 and 2 sockets offset by 0x40 */ #define PCIC_CHIP_OFFSET 0x80 #define PCIC_SOCKET_OFFSET 0x40 /* general setup registers */ #define PCIC_IDENT 0x00 /* RO */ #define PCIC_IDENT_IFTYPE_MASK 0xC0 #define PCIC_IDENT_IFTYPE_IO_ONLY 0x00 #define PCIC_IDENT_IFTYPE_MEM_ONLY 0x40 #define PCIC_IDENT_IFTYPE_MEM_AND_IO 0x80 #define PCIC_IDENT_IFTYPE_RESERVED 0xC0 #define PCIC_IDENT_ZERO 0x30 #define PCIC_IDENT_REV_MASK 0x0F #define PCIC_IDENT_REV_I82365SLR0 0x02 #define PCIC_IDENT_REV_I82365SLR1 0x03 #define PCIC_IDENT_ID_INTEL0 0x82 #define PCIC_IDENT_ID_INTEL1 0x83 #define PCIC_IDENT_ID_INTEL2 0x84 #define PCIC_IDENT_ID_IBM1 0x88 #define PCIC_IDENT_ID_IBM2 0x89 #define PCIC_IDENT_ID_IBM3 0x8A #define PCIC_IF_STATUS 0x01 /* RO */ #define PCIC_IF_STATUS_GPI 0x80 /* General Purpose Input */ #define PCIC_IF_STATUS_POWERACTIVE 0x40 #define PCIC_IF_STATUS_READY 0x20 /* really READY/!BUSY */ #define PCIC_IF_STATUS_MEM_WP 0x10 #define PCIC_IF_STATUS_CARDDETECT_MASK 0x0C #define PCIC_IF_STATUS_CARDDETECT_PRESENT 0x0C #define PCIC_IF_STATUS_BATTERY_MASK 0x03 #define PCIC_IF_STATUS_BATTERY_DEAD1 0x00 #define PCIC_IF_STATUS_BATTERY_DEAD2 0x01 #define PCIC_IF_STATUS_BATTERY_WARNING 0x02 #define PCIC_IF_STATUS_BATTERY_GOOD 0x03 #define PCIC_PWRCTL 0x02 /* RW */ #define PCIC_PWRCTL_OE 0x80 /* output enable */ #define PCIC_PWRCTL_DISABLE_RESETDRV 0x40 #define PCIC_PWRCTL_AUTOSWITCH_ENABLE 0x20 #define PCIC_PWRCTL_PWR_ENABLE 0x10 #define PCIC_PWRCTL_VPP2_MASK 0x0C #define PCIC_PWRCTL_VPP2_RESERVED 0x0C #define PCIC_PWRCTL_VPP2_12V 0x08 #define PCIC_PWRCTL_VPP2_VCC 0x04 #define PCIC_PWRCTL_VPP2_OFF 0x00 #define PCIC_PWRCTL_VPP1_MASK 0x03 #define PCIC_PWRCTL_VPP1_RESERVED 0x03 #define PCIC_PWRCTL_VPP1_12V 0x02 #define PCIC_PWRCTL_VPP1_VCC 0x01 #define PCIC_PWRCTL_VPP1_OFF 0x00 #define PCIC_CSC 0x04 /* RO */ #define PCIC_CSC_ZERO 0xE0 #define PCIC_CSC_GPI 0x10 #define PCIC_CSC_CD 0x08 /* Card Detect Change */ #define PCIC_CSC_READY 0x04 #define PCIC_CSC_BATTWARN 0x02 #define PCIC_CSC_BATTDEAD 0x01 /* for memory cards */ #define PCIC_CSC_RI 0x01 /* for i/o cards */ #define PCIC_ADDRWIN_ENABLE 0x06 /* RW */ #define PCIC_ADDRWIN_ENABLE_IO1 0x80 #define PCIC_ADDRWIN_ENABLE_IO0 0x40 #define PCIC_ADDRWIN_ENABLE_MEMCS16 0x20 /* rtfds if you care */ #define PCIC_ADDRWIN_ENABLE_MEM4 0x10 #define PCIC_ADDRWIN_ENABLE_MEM3 0x08 #define PCIC_ADDRWIN_ENABLE_MEM2 0x04 #define PCIC_ADDRWIN_ENABLE_MEM1 0x02 #define PCIC_ADDRWIN_ENABLE_MEM0 0x01 /* this is _not_ available on cirrus chips */ #define PCIC_CARD_DETECT 0x16 /* RW */ #define PCIC_CARD_DETECT_RESERVED 0xC0 #define PCIC_CARD_DETECT_SW_INTR 0x20 #define PCIC_CARD_DETECT_RESUME_ENABLE 0x10 #define PCIC_CARD_DETECT_GPI_TRANSCTL 0x08 #define PCIC_CARD_DETECT_GPI_ENABLE 0x04 #define PCIC_CARD_DETECT_CFGRST_ENABLE 0x02 #define PCIC_CARD_DETECT_MEMDLY_INHIBIT 0x01 /* interrupt registers */ #define PCIC_INTR 0x03 /* RW */ #define PCIC_INTR_RI_ENABLE 0x80 #define PCIC_INTR_RESET 0x40 /* active low (zero) */ #define PCIC_INTR_CARDTYPE_MASK 0x20 #define PCIC_INTR_CARDTYPE_IO 0x20 #define PCIC_INTR_CARDTYPE_MEM 0x00 #define PCIC_INTR_ENABLE 0x10 #define PCIC_INTR_IRQ_MASK 0x0F #define PCIC_INTR_IRQ_SHIFT 0 #define PCIC_INTR_IRQ_NONE 0x00 #define PCIC_INTR_IRQ_RESERVED1 0x01 #define PCIC_INTR_IRQ_RESERVED2 0x02 #define PCIC_INTR_IRQ3 0x03 #define PCIC_INTR_IRQ4 0x04 #define PCIC_INTR_IRQ5 0x05 #define PCIC_INTR_IRQ_RESERVED6 0x06 #define PCIC_INTR_IRQ7 0x07 #define PCIC_INTR_IRQ_RESERVED8 0x08 #define PCIC_INTR_IRQ9 0x09 #define PCIC_INTR_IRQ10 0x0A #define PCIC_INTR_IRQ11 0x0B #define PCIC_INTR_IRQ12 0x0C #define PCIC_INTR_IRQ_RESERVED13 0x0D #define PCIC_INTR_IRQ14 0x0E #define PCIC_INTR_IRQ15 0x0F #define PCIC_INTR_IRQ_VALIDMASK 0xDEB8 /* 1101 1110 1011 1000 */ #define PCIC_CSC_INTR 0x05 /* RW */ #define PCIC_CSC_INTR_IRQ_MASK 0xF0 #define PCIC_CSC_INTR_IRQ_SHIFT 4 #define PCIC_CSC_INTR_IRQ_NONE 0x00 #define PCIC_CSC_INTR_IRQ_RESERVED1 0x10 #define PCIC_CSC_INTR_IRQ_RESERVED2 0x20 #define PCIC_CSC_INTR_IRQ3 0x30 #define PCIC_CSC_INTR_IRQ4 0x40 #define PCIC_CSC_INTR_IRQ5 0x50 #define PCIC_CSC_INTR_IRQ_RESERVED6 0x60 #define PCIC_CSC_INTR_IRQ7 0x70 #define PCIC_CSC_INTR_IRQ_RESERVED8 0x80 #define PCIC_CSC_INTR_IRQ9 0x90 #define PCIC_CSC_INTR_IRQ10 0xA0 #define PCIC_CSC_INTR_IRQ11 0xB0 #define PCIC_CSC_INTR_IRQ12 0xC0 #define PCIC_CSC_INTR_IRQ_RESERVED13 0xD0 #define PCIC_CSC_INTR_IRQ14 0xE0 #define PCIC_CSC_INTR_IRQ15 0xF0 #define PCIC_CSC_INTR_CD_ENABLE 0x08 #define PCIC_CSC_INTR_READY_ENABLE 0x04 #define PCIC_CSC_INTR_BATTWARN_ENABLE 0x02 #define PCIC_CSC_INTR_BATTDEAD_ENABLE 0x01 /* for memory cards */ #define PCIC_CSC_INTR_RI_ENABLE 0x01 /* for I/O cards */ #define PCIC_CSC_INTR_FORMAT "\177\020" "f\4\4CSC_INTR_IRQ\0" \ "b\0RI\0" \ "b\1BATTWARN\0" \ "b\2READY\0" \ "b\3CD\0" #define PCIC_CSC_INTR_IRQ_VALIDMASK 0xDEB8 /* 1101 1110 1011 1000 */ /* I/O registers */ #define PCIC_IO_WINS 2 #define PCIC_IOCTL 0x07 /* RW */ #define PCIC_IOCTL_IO1_WAITSTATE 0x80 #define PCIC_IOCTL_IO1_ZEROWAIT 0x40 #define PCIC_IOCTL_IO1_IOCS16SRC_MASK 0x20 #define PCIC_IOCTL_IO1_IOCS16SRC_CARD 0x20 #define PCIC_IOCTL_IO1_IOCS16SRC_DATASIZE 0x00 #define PCIC_IOCTL_IO1_DATASIZE_MASK 0x10 #define PCIC_IOCTL_IO1_DATASIZE_16BIT 0x10 #define PCIC_IOCTL_IO1_DATASIZE_8BIT 0x00 #define PCIC_IOCTL_IO0_WAITSTATE 0x08 #define PCIC_IOCTL_IO0_ZEROWAIT 0x04 #define PCIC_IOCTL_IO0_IOCS16SRC_MASK 0x02 #define PCIC_IOCTL_IO0_IOCS16SRC_CARD 0x02 #define PCIC_IOCTL_IO0_IOCS16SRC_DATASIZE 0x00 #define PCIC_IOCTL_IO0_DATASIZE_MASK 0x01 #define PCIC_IOCTL_IO0_DATASIZE_16BIT 0x01 #define PCIC_IOCTL_IO0_DATASIZE_8BIT 0x00 #define PCIC_IOADDR0_START_LSB 0x08 #define PCIC_IOADDR0_START_MSB 0x09 #define PCIC_IOADDR0_STOP_LSB 0x0A #define PCIC_IOADDR0_STOP_MSB 0x0B #define PCIC_IOADDR1_START_LSB 0x0C #define PCIC_IOADDR1_START_MSB 0x0D #define PCIC_IOADDR1_STOP_LSB 0x0E #define PCIC_IOADDR1_STOP_MSB 0x0F /* memory registers */ /* * memory window addresses refer to bits A23-A12 of the ISA system memory * address. This is a shift of 12 bits. The LSB contains A19-A12, and the * MSB contains A23-A20, plus some other bits. */ #define PCIC_MEM_WINS 5 #define PCIC_MEM_SHIFT 12 #define PCIC_MEM_PAGESIZE (1< use SDLC) */ #define ZSWR5_RTS 0x02 /* assert RTS */ #define ZSWR5_TXCRC_ENABLE 0x01 /* enable xmit crc calculation */ #ifdef not_done_here /* * Bits in Write Register 7 when the chip is in SDLC mode. */ #define ZSWR7_SDLCFLAG 0x7e /* this value makes SDLC mode work */ #endif /* * Bits in Write Register 7' (ZSWR_ENHANCED above). This register is * only available on the 85230. Dispite the fact it contains flags * and not a single value, the register was named as it is read * via RR14. Weird. */ /* 0x80 unused */ #define ZSWR7P_EXTEND_READ 0x40 /* modify read map; make most regs readable */ #define ZSWR7P_TX_FIFO 0x20 /* change level for Tx FIFO empty int */ #define ZSWR7P_DTR_TIME 0x10 /* modifies deact. speed of /DTR//REQ */ #define ZSWR7P_RX_FIFO 0x08 /* Rx FIFO int on 1/2 full? */ #define ZSWR7P_RTS_DEACT 0x04 /* automatically deassert RTS */ #define ZSWR7P_AUTO_EOM_RESET 0x02 /* automatically reset EMO/Tx Underrun */ #define ZSWR7P_AUTO_TX_FLAG 0x01 /* Auto send SDLC flag at transmit start */ /* * Bits in Write Register 9 (`Master Interrupt Control'). Bits 7 & 6 * are taken as a unit and indicate the type of reset; 00 means no reset * (and is not defined here). */ #define ZSWR9_HARD_RESET 0xc0 /* force hardware reset */ #define ZSWR9_A_RESET 0x80 /* reset channel A (0) */ #define ZSWR9_B_RESET 0x40 /* reset channel B (1) */ #define ZSWR9_SOFT_INTAC 0x20 /* Not in NMOS version */ #define ZSWR9_STATUS_HIGH 0x10 /* status in high bits of intr vec */ #define ZSWR9_MASTER_IE 0x08 /* master interrupt enable */ #define ZSWR9_DLC 0x04 /* disable lower chain */ #define ZSWR9_NO_VECTOR 0x02 /* no vector */ #define ZSWR9_VECTOR_INCL_STAT 0x01 /* vector includes status */ /* * Bits in Write Register 10 (`Miscellaneous Transmitter/Receiver Control * Bits'). Bits 6 & 5 are taken as a unit, and some of the bits are * meaningful only in certain modes. Bleah. */ #define ZSWR10_PRESET_ONES 0x80 /* preset CRC to all 1 (else all 0) */ #define ZSWR10_NRZ 0x00 /* NRZ encoding */ #define ZSWR10_NRZI 0x20 /* NRZI encoding */ #define ZSWR10_FM1 0x40 /* FM1 encoding */ #define ZSWR10_FM0 0x60 /* FM0 encoding */ #define ZSWR10_GA_ON_POLL 0x10 /* go active on poll (loop mode) */ #define ZSWR10_MARK_IDLE 0x08 /* all 1s (vs flag) when idle (SDLC) */ #define ZSWR10_ABORT_ON_UNDERRUN 0x4 /* abort on xmit underrun (SDLC) */ #define ZSWR10_LOOP_MODE 0x02 /* loop mode (SDLC) */ #define ZSWR10_6_BIT_SYNC 0x01 /* 6 bits per sync char (sync modes) */ /* * Bits in Write Register 11 (`Clock Mode Control'). Bits 6&5, 4&3, and * 1&0 are taken as units. Various bits depend on other bits in complex * ways; see the Zilog manual. */ #define ZSWR11_XTAL 0x80 /* have xtal between RTxC* and SYNC* */ /* (else have TTL oscil. on RTxC*) */ #define ZSWR11_RXCLK_RTXC 0x00 /* recv clock taken from RTxC* pin */ #define ZSWR11_RXCLK_TRXC 0x20 /* recv clock taken from TRxC* pin */ #define ZSWR11_RXCLK_BAUD 0x40 /* recv clock taken from BRG */ #define ZSWR11_RXCLK_DPLL 0x60 /* recv clock taken from DPLL */ #define ZSWR11_TXCLK_RTXC 0x00 /* xmit clock taken from RTxC* pin */ #define ZSWR11_TXCLK_TRXC 0x08 /* xmit clock taken from TRxC* pin */ #define ZSWR11_TXCLK_BAUD 0x10 /* xmit clock taken from BRG */ #define ZSWR11_TXCLK_DPLL 0x18 /* xmit clock taken from DPLL */ #define ZSWR11_TRXC_OUT_ENA 0x04 /* TRxC* pin will be an output */ /* (unless it is being used above) */ #define ZSWR11_TRXC_XTAL 0x00 /* TRxC output from xtal oscillator */ #define ZSWR11_TRXC_XMIT 0x01 /* TRxC output from xmit clock */ #define ZSWR11_TRXC_BAUD 0x02 /* TRxC output from BRG */ #define ZSWR11_TRXC_DPLL 0x03 /* TRxC output from DPLL */ /* * Formula for Write Registers 12 and 13 (`Lower Byte of Baud Rate * Generator Time Constant' and `Upper Byte of ...'). Inputs: * * f BRG input clock frequency (in Hz) AFTER division * by 1, 16, 32, or 64 (per clock divisor in WR4) * bps desired rate in bits per second (9600, etc) * * We want * * f * ----- + 0.5 - 2 * 2 bps * * rounded down to an integer. This can be computed entirely * in integer arithmetic as: * * f + bps * ------- - 2 * 2 bps */ #define BPS_TO_TCONST(f, bps) ((((f) + (bps)) / (2 * (bps))) - 2) /* inverse of above: given a BRG Time Constant, return Bits Per Second */ #define TCONST_TO_BPS(f, tc) ((f) / 2 / ((tc) + 2)) /* * Bits in Write Register 14 (`Miscellaneous Control Bits'). * Bits 7 through 5 are taken as a unit and make up a `DPLL command'. */ #define ZSWR14_DPLL_NOOP 0x00 /* leave DPLL alone */ #define ZSWR14_DPLL_SEARCH 0x20 /* enter search mode */ #define ZSWR14_DPLL_RESET_CM 0x40 /* reset `clock missing' in RR10 */ #define ZSWR14_DPLL_DISABLE 0x60 /* disable DPLL (continuous search) */ #define ZSWR14_DPLL_SRC_BAUD 0x80 /* set DPLL src = BRG */ #define ZSWR14_DPLL_SRC_RTXC 0xa0 /* set DPLL src = RTxC* or xtal osc */ #define ZSWR14_DPLL_FM 0xc0 /* operate in FM mode */ #define ZSWR14_DPLL_NRZI 0xe0 /* operate in NRZI mode */ #define ZSWR14_LOCAL_LOOPBACK 0x10 /* set local loopback mode */ #define ZSWR14_AUTO_ECHO 0x08 /* set auto echo mode */ #define ZSWR14_DTR_REQ 0x04 /* DTR* / REQ* pin gives REQ* */ #define ZSWR14_BAUD_FROM_PCLK 0x02 /* BRG clock taken from PCLK */ /* (else from RTxC* pin or xtal osc) */ #define ZSWR14_BAUD_ENA 0x01 /* enable BRG countdown */ /* * Bits in Write Register 15 (`External/Status Interrupt Control'). * Most of these cause status interrupts whenever the corresponding * bit or pin changes state (i.e., any rising or falling edge). * * NOTE: ZSWR15_SDLC_FIFO & ZSWR15_ENABLE_ENHANCED should not be * set on an NMOS 8530. Also, ZSWR15_ENABLE_ENHANCED is only * available on the 85230. */ #define ZSWR15_BREAK_IE 0x80 /* enable break/abort status int */ #define ZSWR15_TXUEOM_IE 0x40 /* enable TX underrun/EOM status int */ #define ZSWR15_CTS_IE 0x20 /* enable CTS* pin status int */ #define ZSWR15_SYNCHUNT_IE 0x10 /* enable SYNC* pin/hunt status int */ #define ZSWR15_DCD_IE 0x08 /* enable DCD* pin status int */ #define ZSWR15_SDLC_FIFO 0x04 /* enable SDLC FIFO enhancements */ #define ZSWR15_ZERO_COUNT_IE 0x02 /* enable BRG-counter = 0 status int */ #define ZSWR15_ENABLE_ENHANCED 0x01 /* enable writing WR7' at reg 7 */ /* * Bits in Read Register 0 (`Transmit/Receive Buffer Status and External * Status'). */ #define ZSRR0_BREAK 0x80 /* break/abort detected */ #define ZSRR0_TXUNDER 0x40 /* transmit underrun/EOM (sync) */ #define ZSRR0_CTS 0x20 /* clear to send */ #define ZSRR0_SYNC_HUNT 0x10 /* sync/hunt (sync mode) */ #define ZSRR0_DCD 0x08 /* data carrier detect */ #define ZSRR0_TX_READY 0x04 /* transmit buffer empty */ #define ZSRR0_ZERO_COUNT 0x02 /* zero count in baud clock */ #define ZSRR0_RX_READY 0x01 /* received character ready */ /* * Bits in Read Register 1 (the Zilog book does not name this one). */ #define ZSRR1_EOF 0x80 /* end of frame (SDLC mode) */ #define ZSRR1_FE 0x40 /* CRC/framing error */ #define ZSRR1_DO 0x20 /* data (receiver) overrun */ #define ZSRR1_PE 0x10 /* parity error */ #define ZSRR1_RC0 0x08 /* residue code 0 (SDLC mode) */ #define ZSRR1_RC1 0x04 /* residue code 1 (SDLC mode) */ #define ZSRR1_RC2 0x02 /* residue code 2 (SDLC mode) */ #define ZSRR1_ALL_SENT 0x01 /* all chars out of xmitter (async) */ /* * Read Register 2 in B channel contains status bits if VECTOR_INCL_STAT * is set. */ /* * Bits in Read Register 3 (`Interrupt Pending'). Only channel A * has an RR3. */ /* 0x80 unused, returned as 0 */ /* 0x40 unused, returned as 0 */ #define ZSRR3_IP_A_RX 0x20 /* channel A recv int pending */ #define ZSRR3_IP_A_TX 0x10 /* channel A xmit int pending */ #define ZSRR3_IP_A_STAT 0x08 /* channel A status int pending */ #define ZSRR3_IP_B_RX 0x04 /* channel B recv int pending */ #define ZSRR3_IP_B_TX 0x02 /* channel B xmit int pending */ #define ZSRR3_IP_B_STAT 0x01 /* channel B status int pending */ /* * Bits in Read Register 10 (`contains some miscellaneous status bits'). */ #define ZSRR10_1_CLOCK_MISSING 0x80 /* 1 clock edge missing (FM mode) */ #define ZSRR10_2_CLOCKS_MISSING 0x40 /* 2 clock edges missing (FM mode) */ /* 0x20 unused */ #define ZSRR10_LOOP_SENDING 0x10 /* xmitter controls loop (SDLC loop) */ /* 0x08 unused */ /* 0x04 unused */ #define ZSRR10_ON_LOOP 0x02 /* SCC is on loop (SDLC/X.21 modes) */ /* * Bits in Read Register 15. This register is one of the few that * simply reads back the corresponding Write Register. */ #define ZSRR15_BREAK_IE 0x80 /* break/abort status int enable */ #define ZSRR15_TXUEOM_IE 0x40 /* TX underrun/EOM status int enable */ #define ZSRR15_CTS_IE 0x20 /* CTS* pin status int enable */ #define ZSRR15_SYNCHUNT_IE 0x10 /* SYNC* pin/hunt status int enable */ #define ZSRR15_DCD_IE 0x08 /* DCD* pin status int enable */ /* 0x04 unused, returned as zero */ #define ZSRR15_ZERO_COUNT_IE 0x02 /* BRG-counter = 0 status int enable */ /* 0x01 unused, returned as zero */ #endif /* Z8530REG_H */ gxemul-0.6.1/src/include/thirdparty/gtreg.h000644 001750 001750 00000012561 13402411502 021117 0ustar00debugdebug000000 000000 /* * This is basically malta/dev/gtreg.h from NetBSD, with additional * defines that Linux uses. Symbol names are practically the same in * NetBSD and Linux, which simplifies things. * * Also a few defines are from cobalt/dev/gtreg.h from NetBSD. * * TODO: Find a better gtreg.h. * * Originally imported from NetBSD into GXemul 2006-09-23, when this * file did not have a copyright text in NetBSD's tree. The following * copyright text was found in a FreeBSD tree instead but mentions * NetBSD, so most likely it is valid. */ /*- * Copyright (c) 1997, 1998, 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef GTREG_H #define GTREG_H #define GT_REGVAL(x) *((volatile u_int32_t *) \ (MIPS_PHYS_TO_KSEG1(MALTA_CORECTRL_BASE + (x)))) /* CPU Configuration Register Map */ #define GT_CPU_INT 0x000 #define GT_MULTIGT 0x120 /* CPU Address Decode Register Map */ #define GT_PCI0IOLD_OFS 0x048 #define GT_PCI0IOHD_OFS 0x050 #define GT_PCI0M0LD_OFS 0x058 #define GT_PCI0M0HD_OFS 0x060 #define GT_PCI0M1LD_OFS 0x080 #define GT_PCI0M1HD_OFS 0x088 #define GT_PCI0IOREMAP_OFS 0x0f0 #define GT_PCI0M0REMAP_OFS 0x0f8 #define GT_PCI0M1REMAP_OFS 0x100 #define GT_N_DECODE_REGS (0x108 / 8) /* CPU Error Report Register Map */ /* CPU Sync Barrier Register Map */ /* SDRAM and Device Address Decode Register Map */ /* SDRAM Configuration Register Map */ /* SDRAM Parameters Register Map */ /* ECC Register Map */ /* Device Parameters Register Map */ /* DMA Record Register Map */ /* DMA Arbiter Register Map */ /* Timer/Counter Register Map */ //#define GT_TC_0 0x850 //#define GT_TC_1 0x854 //#define GT_TC_2 0x858 //#define GT_TC_3 0x85c //#define GT_TC_CONTROL 0x864 #define GT_TIMER_COUNTER0 0x850 #define GT_TIMER_COUNTER1 0x854 #define GT_TIMER_COUNTER2 0x858 #define GT_TIMER_COUNTER3 0x85c #define GT_TIMER_CTRL 0x864 #define ENTC0 0x01 #define TCSEL0 0x02 #define ENTC1 0x04 #define TCSEL1 0x08 #define ENTC2 0x10 #define TCSEL2 0x20 #define ENTC3 0x40 #define TCSEL3 0x80 /* PCI Internal Register Map */ #define GT_PCI0_CMD_OFS 0xc00 #define GT_PCI0_CFG_ADDR 0xcf8 #define GT_PCI0_CFG_DATA 0xcfc #define GT_PCI0_INTR_ACK 0xc34 /* Interrupts Register Map */ #define GT_INTR_CAUSE 0xc18 #define GTIC_INTSUM 0x00000001 #define GTIC_MEMOUT 0x00000002 #define GTIC_DMAOUT 0x00000004 #define GTIC_CPUOUT 0x00000008 #define GTIC_DMA0COMP 0x00000010 #define GTIC_DMA1COMP 0x00000020 #define GTIC_DMA2COMP 0x00000040 #define GTIC_DMA3COMP 0x00000080 #define GTIC_T0EXP 0x00000100 #define GTIC_T1EXP 0x00000200 #define GTIC_T2EXP 0x00000400 #define GTIC_T3EXP 0x00000800 #define GTIC_MASRDERR0 0x00001000 #define GTIC_SLVWRERR0 0x00002000 #define GTIC_MASWRERR0 0x00004000 #define GTIC_SLVRDERR0 0x00008000 #define GTIC_ADDRERR0 0x00010000 #define GTIC_MEMERR 0x00020000 #define GTIC_MASABORT0 0x00040000 #define GTIC_TARABORT0 0x00080000 #define GTIC_RETRYCNT0 0x00100000 #define GTIC_PMCINT_0 0x00200000 #define GTIC_CPUINT 0x0c300000 #define GTIC_PCINT 0xc3000000 #define GTIC_CPUINTSUM 0x40000000 #define GTIC_PCIINTSUM 0x80000000 /* PCI Configuration Register Map */ //#define GT_PCICONFIGBASE 0 //#define GT_PCIDID BONITO(GT_PCICONFIGBASE + 0x00) //#define GT_PCICMD BONITO(GT_PCICONFIGBASE + 0x04) //#define GT_PCICLASS BONITO(GT_PCICONFIGBASE + 0x08) //#define GT_PCILTIMER BONITO(GT_PCICONFIGBASE + 0x0c) //#define GT_PCIBASE0 BONITO(GT_PCICONFIGBASE + 0x10) //#define GT_PCIBASE1 BONITO(GT_PCICONFIGBASE + 0x14) //#define GT_PCIBASE2 BONITO(GT_PCICONFIGBASE + 0x18) //#define GT_PCIEXPRBASE BONITO(GT_PCICONFIGBASE + 0x30) //#define GT_PCIINT BONITO(GT_PCICONFIGBASE + 0x3c) /* PCI Configuration, Function 1, Register Map */ /* I2O Support Register Map */ #endif /* !GTREG_H */ gxemul-0.6.1/src/include/thirdparty/mc146818reg.h000644 001750 001750 00000016613 13402411502 021602 0ustar00debugdebug000000 000000 #ifndef MC146818_REG_H #define MC146818_REG_H #ifndef __P #define __P(x) x #endif /* $NetBSD: mc146818reg.h,v 1.2 1997/03/12 06:53:42 cgd Exp $ */ /* * Copyright (c) 1995 Carnegie-Mellon University. * All rights reserved. * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * Definitions for the Motorola MC146818A Real Time Clock. * They also apply for the (compatible) Dallas Semicontuctor DS1287A RTC. * * Though there are undoubtedly other (better) sources, this material was * culled from the DEC "KN121 System Module Programmer's Reference * Information." * * The MC146818A has 16 registers. The first 10 contain time-of-year * and alarm data. The rest contain various control and status bits. * * To read or write the registers, one writes the register number to * the RTC's control port, then either reads from or writes the new * data to the RTC's data port. Since the locations of these ports * and the method used to access them can be machine-dependent, the * low-level details of reading and writing the RTC's registers are * handled by machine-specific functions. * * The time-of-year and alarm data can be expressed in either binary * or BCD, and they are selected by a bit in register B. * * The "hour" time-of-year and alarm fields can either be expressed in * AM/PM format, or in 24-hour format. If AM/PM format is chosen, the * hour fields can have the values: 1-12 and 81-92 (the latter being * PM). If the 24-hour format is chosen, they can have the values * 0-24. The hour format is selectable by a bit in register B. * (XXX IS AM/PM MODE DESCRIPTION CORRECT?) * * It is assumed the if systems are going to use BCD (rather than * binary) mode, or AM/PM hour format, they'll do the appropriate * conversions in machine-dependent code. Also, if the clock is * switched between BCD and binary mode, or between AM/PM mode and * 24-hour mode, the time-of-day and alarm registers are NOT * automatically reset; they must be reprogrammed with correct values. */ /* * The registers, and the bits within each register. */ #define MC_SEC 0x0 /* Time of year: seconds (0-59) */ #define MC_ASEC 0x1 /* Alarm: seconds */ #define MC_MIN 0x2 /* Time of year: minutes (0-59) */ #define MC_AMIN 0x3 /* Alarm: minutes */ #define MC_HOUR 0x4 /* Time of year: hour (see above) */ #define MC_AHOUR 0x5 /* Alarm: hour */ #define MC_DOW 0x6 /* Time of year: day of week (1-7) */ #define MC_DOM 0x7 /* Time of year: day of month (1-31) */ #define MC_MONTH 0x8 /* Time of year: month (1-12) */ #define MC_YEAR 0x9 /* Time of year: year in century (0-99) */ #define MC_REGA 0xa /* Control register A */ #define MC_REGA_RSMASK 0x0f /* Interrupt rate select mask (see below) */ #define MC_REGA_DVMASK 0x70 /* Divisor select mask (see below) */ #define MC_REGA_UIP 0x80 /* Update in progress; read only. */ #define MC_REGB 0xb /* Control register B */ #define MC_REGB_DSE 0x01 /* Daylight Savings Enable */ #define MC_REGB_24HR 0x02 /* 24-hour mode (AM/PM mode when clear) */ #define MC_REGB_BINARY 0x04 /* Binary mode (BCD mode when clear) */ #define MC_REGB_SQWE 0x08 /* Square Wave Enable */ #define MC_REGB_UIE 0x10 /* Update End interrupt enable */ #define MC_REGB_AIE 0x20 /* Alarm interrupt enable */ #define MC_REGB_PIE 0x40 /* Periodic interrupt enable */ #define MC_REGB_SET 0x80 /* Allow time to be set; stops updates */ #define MC_REGC 0xc /* Control register C */ /* MC_REGC_UNUSED 0x0f UNUSED */ #define MC_REGC_UF 0x10 /* Update End interrupt flag */ #define MC_REGC_AF 0x20 /* Alarm interrupt flag */ #define MC_REGC_PF 0x40 /* Periodic interrupt flag */ #define MC_REGC_IRQF 0x80 /* Interrupt request pending flag */ #define MC_REGD 0xd /* Control register D */ /* MC_REGD_UNUSED 0x7f UNUSED */ #define MC_REGD_VRT 0x80 /* Valid RAM and Time bit */ #define MC_NREGS 0xe /* 14 registers; CMOS follows */ #define MC_NTODREGS 0xa /* 10 of those regs are for TOD and alarm */ #define MC_NVRAM_START 0xe /* start of NVRAM: offset 14 */ #define MC_NVRAM_SIZE 50 /* 50 bytes of NVRAM */ /* * Periodic Interrupt Rate Select constants (Control register A) */ #define MC_RATE_NONE 0x0 /* No periodic interrupt */ #define MC_RATE_1 0x1 /* 256 Hz if MC_BASE_32_KHz, else 32768 Hz */ #define MC_RATE_2 0x2 /* 128 Hz if MC_BASE_32_KHz, else 16384 Hz */ #define MC_RATE_8192_Hz 0x3 /* 122.070 us period */ #define MC_RATE_4096_Hz 0x4 /* 244.141 us period */ #define MC_RATE_2048_Hz 0x5 /* 488.281 us period */ #define MC_RATE_1024_Hz 0x6 /* 976.562 us period */ #define MC_RATE_512_Hz 0x7 /* 1.953125 ms period */ #define MC_RATE_256_Hz 0x8 /* 3.90625 ms period */ #define MC_RATE_128_Hz 0x9 /* 7.8125 ms period */ #define MC_RATE_64_Hz 0xa /* 15.625 ms period */ #define MC_RATE_32_Hz 0xb /* 31.25 ms period */ #define MC_RATE_16_Hz 0xc /* 62.5 ms period */ #define MC_RATE_8_Hz 0xd /* 125 ms period */ #define MC_RATE_4_Hz 0xe /* 250 ms period */ #define MC_RATE_2_Hz 0xf /* 500 ms period */ /* * Time base (divisor select) constants (Control register A) */ #define MC_BASE_4_MHz 0x00 /* 4MHz crystal */ #define MC_BASE_1_MHz 0x10 /* 1MHz crystal */ #define MC_BASE_32_KHz 0x20 /* 32KHz crystal */ #define MC_BASE_NONE 0x60 /* actually, both of these reset */ #define MC_BASE_RESET 0x70 /* * RTC register/NVRAM read and write functions -- machine-dependent. * Appropriately manipulate RTC registers to get/put data values. */ u_int mc146818_read __P((void *sc, u_int reg)); void mc146818_write __P((void *sc, u_int reg, u_int datum)); /* * A collection of TOD/Alarm registers. */ typedef u_int mc_todregs[MC_NTODREGS]; /* * Get all of the TOD/Alarm registers * Must be called at splhigh(), and with the RTC properly set up. */ #define MC146818_GETTOD(sc, regs) \ do { \ int i; \ \ /* update in progress; spin loop */ \ while (mc146818_read(sc, MC_REGA) & MC_REGA_UIP) \ ; \ \ /* read all of the tod/alarm regs */ \ for (i = 0; i < MC_NTODREGS; i++) \ (*regs)[i] = mc146818_read(sc, i); \ } while (0); /* * Set all of the TOD/Alarm registers * Must be called at splhigh(), and with the RTC properly set up. */ #define MC146818_PUTTOD(sc, regs) \ do { \ int i; \ \ /* stop updates while setting */ \ mc146818_write(sc, MC_REGB, \ mc146818_read(sc, MC_REGB) | MC_REGB_SET); \ \ /* write all of the tod/alarm regs */ \ for (i = 0; i < MC_NTODREGS; i++) \ mc146818_write(sc, i, (*regs)[i]); \ \ /* reenable updates */ \ mc146818_write(sc, MC_REGB, \ mc146818_read(sc, MC_REGB) & ~MC_REGB_SET); \ } while (0); #endif gxemul-0.6.1/src/include/thirdparty/mii.h000644 001750 001750 00000024503 13402411502 020564 0ustar00debugdebug000000 000000 /* $NetBSD: mii.h,v 1.20 2016/10/28 05:47:16 msaitoh Exp $ */ #ifndef _DEV_MII_MII_H_ #define _DEV_MII_MII_H_ /* * Copyright (c) 1997 Manuel Bouyer. All rights reserved. * * Modification to match BSD/OS 3.0 MII interface by Jason R. Thorpe, * Numerical Aerospace Simulation Facility, NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Registers common to all PHYs. */ #define MII_NPHY 32 /* max # of PHYs per MII */ #define MII_ADDRBITS 5 /* Register address bits (0x00..0x1f) */ #define MII_ADDRMASK 0x1f /* Address mask */ /* * MII commands, used if a device must drive the MII lines * manually. */ #define MII_COMMAND_START 0x01 #define MII_COMMAND_READ 0x02 #define MII_COMMAND_WRITE 0x01 #define MII_COMMAND_ACK 0x02 #define MII_BMCR 0x00 /* Basic mode control register (rw) */ #define BMCR_RESET 0x8000 /* reset */ #define BMCR_LOOP 0x4000 /* loopback */ #define BMCR_SPEED0 0x2000 /* speed selection (LSB) */ #define BMCR_AUTOEN 0x1000 /* autonegotiation enable */ #define BMCR_PDOWN 0x0800 /* power down */ #define BMCR_ISO 0x0400 /* isolate */ #define BMCR_STARTNEG 0x0200 /* restart autonegotiation */ #define BMCR_FDX 0x0100 /* Set duplex mode */ #define BMCR_CTEST 0x0080 /* collision test */ #define BMCR_SPEED1 0x0040 /* speed selection (MSB) */ #define BMCR_S10 0x0000 /* 10 Mb/s */ #define BMCR_S100 BMCR_SPEED0 /* 100 Mb/s */ #define BMCR_S1000 BMCR_SPEED1 /* 1000 Mb/s */ #define BMCR_SPEED(x) ((x) & (BMCR_SPEED0|BMCR_SPEED1)) #define MII_BMSR 0x01 /* Basic mode status register (ro) */ #define BMSR_100T4 0x8000 /* 100 base T4 capable */ #define BMSR_100TXFDX 0x4000 /* 100 base Tx full duplex capable */ #define BMSR_100TXHDX 0x2000 /* 100 base Tx half duplex capable */ #define BMSR_10TFDX 0x1000 /* 10 base T full duplex capable */ #define BMSR_10THDX 0x0800 /* 10 base T half duplex capable */ #define BMSR_100T2FDX 0x0400 /* 100 base T2 full duplex capable */ #define BMSR_100T2HDX 0x0200 /* 100 base T2 half duplex capable */ #define BMSR_EXTSTAT 0x0100 /* Extended status in register 15 */ #define BMSR_MFPS 0x0040 /* MII Frame Preamble Suppression */ #define BMSR_ACOMP 0x0020 /* Autonegotiation complete */ #define BMSR_RFAULT 0x0010 /* Link partner fault */ #define BMSR_ANEG 0x0008 /* Autonegotiation capable */ #define BMSR_LINK 0x0004 /* Link status */ #define BMSR_JABBER 0x0002 /* Jabber detected */ #define BMSR_EXTCAP 0x0001 /* Extended capability */ /* * Note that the EXTSTAT bit indicates that there is extended status * info available in register 15, but 802.3 section 22.2.4.3 also * states that all 1000 Mb/s capable PHYs will set this bit to 1. */ #define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX| \ BMSR_10TFDX|BMSR_10THDX|BMSR_100T2FDX|BMSR_100T2HDX) /* * Convert BMSR media capabilities to ANAR bits for autonegotiation. * Note the shift chopps off the BMSR_ANEG bit. */ #define BMSR_MEDIA_TO_ANAR(x) (((x) & BMSR_MEDIAMASK) >> 6) #define MII_PHYIDR1 0x02 /* ID register 1 (ro) */ #define MII_PHYIDR2 0x03 /* ID register 2 (ro) */ #define IDR2_OUILSB 0xfc00 /* OUI LSB */ #define IDR2_MODEL 0x03f0 /* vendor model */ #define IDR2_REV 0x000f /* vendor revision */ #define MII_ANAR 0x04 /* Autonegotiation advertisement (rw) */ /* section 28.2.4.1 and 37.2.6.1 */ #define ANAR_NP 0x8000 /* Next page (ro) */ #define ANAR_ACK 0x4000 /* link partner abilities acknowledged (ro) */ #define ANAR_RF 0x2000 /* remote fault (ro) */ /* Annex 28B.2 */ #define ANAR_FC 0x0400 /* local device supports PAUSE */ #define ANAR_T4 0x0200 /* local device supports 100bT4 */ #define ANAR_TX_FD 0x0100 /* local device supports 100bTx FD */ #define ANAR_TX 0x0080 /* local device supports 100bTx */ #define ANAR_10_FD 0x0040 /* local device supports 10bT FD */ #define ANAR_10 0x0020 /* local device supports 10bT */ #define ANAR_CSMA 0x0001 /* protocol selector CSMA/CD */ #define ANAR_PAUSE_NONE (0 << 10) #define ANAR_PAUSE_SYM (1 << 10) #define ANAR_PAUSE_ASYM (2 << 10) #define ANAR_PAUSE_TOWARDS (3 << 10) /* Annex 28D */ #define ANAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */ #define ANAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */ #define ANAR_X_PAUSE_NONE (0 << 7) #define ANAR_X_PAUSE_SYM (1 << 7) #define ANAR_X_PAUSE_ASYM (2 << 7) #define ANAR_X_PAUSE_TOWARDS (3 << 7) #define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */ /* section 28.2.4.1 and 37.2.6.1 */ #define ANLPAR_NP 0x8000 /* Next page (ro) */ #define ANLPAR_ACK 0x4000 /* link partner accepted ACK (ro) */ #define ANLPAR_RF 0x2000 /* remote fault (ro) */ #define ANLPAR_FC 0x0400 /* link partner supports PAUSE */ #define ANLPAR_T4 0x0200 /* link partner supports 100bT4 */ #define ANLPAR_TX_FD 0x0100 /* link partner supports 100bTx FD */ #define ANLPAR_TX 0x0080 /* link partner supports 100bTx */ #define ANLPAR_10_FD 0x0040 /* link partner supports 10bT FD */ #define ANLPAR_10 0x0020 /* link partner supports 10bT */ #define ANLPAR_CSMA 0x0001 /* protocol selector CSMA/CD */ #define ANLPAR_PAUSE_MASK (3 << 10) #define ANLPAR_PAUSE_NONE (0 << 10) #define ANLPAR_PAUSE_SYM (1 << 10) #define ANLPAR_PAUSE_ASYM (2 << 10) #define ANLPAR_PAUSE_TOWARDS (3 << 10) #define ANLPAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */ #define ANLPAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */ #define ANLPAR_X_PAUSE_MASK (3 << 7) #define ANLPAR_X_PAUSE_NONE (0 << 7) #define ANLPAR_X_PAUSE_SYM (1 << 7) #define ANLPAR_X_PAUSE_ASYM (2 << 7) #define ANLPAR_X_PAUSE_TOWARDS (3 << 7) #define MII_ANER 0x06 /* Autonegotiation expansion (ro) */ /* section 28.2.4.1 and 37.2.6.1 */ #define ANER_MLF 0x0010 /* multiple link detection fault */ #define ANER_LPNP 0x0008 /* link parter next page-able */ #define ANER_NP 0x0004 /* next page-able */ #define ANER_PAGE_RX 0x0002 /* Page received */ #define ANER_LPAN 0x0001 /* link parter autoneg-able */ #define MII_ANNP 0x07 /* Autonegotiation next page */ /* section 28.2.4.1 and 37.2.6.1 */ #define MII_ANLPRNP 0x08 /* Autonegotiation link partner rx next page */ /* section 32.5.1 and 37.2.6.1 */ /* This is also the 1000baseT control register */ #define MII_100T2CR 0x09 /* 100base-T2 control register */ #define GTCR_TEST_MASK 0xe000 /* see 802.3ab ss. 40.6.1.1.2 */ #define GTCR_MAN_MS 0x1000 /* enable manual master/slave control */ #define GTCR_ADV_MS 0x0800 /* 1 = adv. master, 0 = adv. slave */ #define GTCR_PORT_TYPE 0x0400 /* 1 = DCE, 0 = DTE (NIC) */ #define GTCR_ADV_1000TFDX 0x0200 /* adv. 1000baseT FDX */ #define GTCR_ADV_1000THDX 0x0100 /* adv. 1000baseT HDX */ /* This is also the 1000baseT status register */ #define MII_100T2SR 0x0a /* 100base-T2 status register */ #define GTSR_MAN_MS_FLT 0x8000 /* master/slave config fault */ #define GTSR_MS_RES 0x4000 /* result: 1 = master, 0 = slave */ #define GTSR_LRS 0x2000 /* local rx status, 1 = ok */ #define GTSR_RRS 0x1000 /* remote rx status, 1 = ok */ #define GTSR_LP_1000TFDX 0x0800 /* link partner 1000baseT FDX capable */ #define GTSR_LP_1000THDX 0x0400 /* link partner 1000baseT HDX capable */ #define GTSR_LP_ASM_DIR 0x0200 /* link partner asym. pause dir. capable */ #define GTSR_IDLE_ERR 0x00ff /* IDLE error count */ #define MII_PSECR 0x0b /* PSE control register */ #define PSECR_PACTLMASK 0x000c /* pair control mask */ #define PSECR_PSEENMASK 0x0003 /* PSE enable mask */ #define PSECR_PINOUTB 0x0008 /* PSE pinout Alternative B */ #define PSECR_PINOUTA 0x0004 /* PSE pinout Alternative A */ #define PSECR_FOPOWTST 0x0002 /* Force Power Test Mode */ #define PSECR_PSEEN 0x0001 /* PSE Enabled */ #define PSECR_PSEDIS 0x0000 /* PSE Disabled */ #define MII_PSESR 0x0c /* PSE status register */ #define PSESR_PWRDENIED 0x1000 /* Power Denied */ #define PSESR_VALSIG 0x0800 /* Valid PD signature detected */ #define PSESR_INVALSIG 0x0400 /* Invalid PD signature detected */ #define PSESR_SHORTCIRC 0x0200 /* Short circuit condition detected */ #define PSESR_OVERLOAD 0x0100 /* Overload condition detected */ #define PSESR_MPSABSENT 0x0080 /* MPS absent condition detected */ #define PSESR_PDCLMASK 0x0070 /* PD Class mask */ #define PSESR_STATMASK 0x000e /* PSE Status mask */ #define PSESR_PAIRCTABL 0x0001 /* PAIR Control Ability */ #define PSESR_PDCL_4 (4 << 4) /* Class 4 */ #define PSESR_PDCL_3 (3 << 4) /* Class 3 */ #define PSESR_PDCL_2 (2 << 4) /* Class 2 */ #define PSESR_PDCL_1 (1 << 4) /* Class 1 */ #define PSESR_PDCL_0 (0 << 4) /* Class 0 */ #define MII_MMDACR 0x0d /* MMD access control register */ #define MMDACR_FUNCMASK 0xc000 /* function */ #define MMDACR_DADDRMASK 0x001f /* device address */ #define MMDACR_FN_ADDRESS (0 << 14) /* address */ #define MMDACR_FN_DATANPI (1 << 14) /* data, no post increment */ #define MMDACR_FN_DATAPIRW (2 << 14) /* data, post increment on r/w */ #define MMDACR_FN_DATAPIW (3 << 14) /* data, post increment on wr only */ #define MII_MMDAADR 0x0e /* MMD access address data register */ #define MII_EXTSR 0x0f /* Extended status register */ #define EXTSR_1000XFDX 0x8000 /* 1000X full-duplex capable */ #define EXTSR_1000XHDX 0x4000 /* 1000X half-duplex capable */ #define EXTSR_1000TFDX 0x2000 /* 1000T full-duplex capable */ #define EXTSR_1000THDX 0x1000 /* 1000T half-duplex capable */ #define EXTSR_MEDIAMASK (EXTSR_1000XFDX|EXTSR_1000XHDX| \ EXTSR_1000TFDX|EXTSR_1000THDX) #endif /* _DEV_MII_MII_H_ */ gxemul-0.6.1/src/include/thirdparty/dec_kn02.h000644 001750 001750 00000021176 13402411502 021376 0ustar00debugdebug000000 000000 /* gxemul: $Id: dec_kn02.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: kn02.h,v 1.8 2000/02/29 04:41:56 nisimura Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * The Mach Operating System project at Carnegie-Mellon University, * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)kn02.h 8.1 (Berkeley) 6/10/93 */ /* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * HISTORY * Log: kn02.h,v * Revision 2.5 91/05/14 17:23:30 mrt * Correcting copyright * * Revision 2.4 91/02/05 17:42:03 mrt * Added author notices * [91/02/04 11:14:23 mrt] * * Changed to use new Mach copyright * [91/02/02 12:12:58 mrt] * * Revision 2.3 90/12/05 23:32:04 af * * * Revision 2.1.1.2 90/11/01 02:48:10 af * Reworked a bit, made reentrant. * * Revision 2.1.1.1 90/10/03 11:48:22 af * Created, from the DEC specs: * "DECstation 5000/200 KN02 System Module Functional Specification" * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990. * [90/09/03 af] */ /* * File: kn02.h * Author: Alessandro Forin, Carnegie Mellon University * Date: 9/90 * * Definitions specific to the KN02 processor (3max) */ #ifndef MIPS_KN02_H #define MIPS_KN02_H 1 /* * KN02's Physical address space */ #define KN02_PHYS_MIN 0x00000000 /* 512 Meg */ #define KN02_PHYS_MAX 0x1fffffff /* * Memory map */ #define KN02_PHYS_MEMORY_START 0x00000000 #define KN02_PHYS_MEMORY_END 0x1dffffff /* 480 Meg in 15 slots */ /* * I/O map */ #define KN02_PHYS_TC_0_START 0x1e000000 /* TURBOchannel, slot 0 */ #define KN02_PHYS_TC_0_END 0x1e3fffff /* 4 Meg, option0 */ #define KN02_PHYS_TC_1_START 0x1e400000 /* TURBOchannel, slot 1 */ #define KN02_PHYS_TC_1_END 0x1e7fffff /* 4 Meg, option1 */ #define KN02_PHYS_TC_2_START 0x1e800000 /* TURBOchannel, slot 2 */ #define KN02_PHYS_TC_2_END 0x1ebfffff /* 4 Meg, option2 */ #define KN02_PHYS_TC_3_START 0x1ec00000 /* TURBOchannel, slot 3 */ #define KN02_PHYS_TC_3_END 0x1effffff /* 4 Meg, reserved*/ #define KN02_PHYS_TC_4_START 0x1f000000 /* TURBOchannel, slot 4 */ #define KN02_PHYS_TC_4_END 0x1f3fffff /* 4 Meg, reserved*/ #define KN02_PHYS_TC_5_START 0x1f400000 /* TURBOchannel, slot 5 */ #define KN02_PHYS_TC_5_END 0x1f7fffff /* 4 Meg, SCSI */ #define KN02_PHYS_TC_6_START 0x1f800000 /* TURBOchannel, slot 6 */ #define KN02_PHYS_TC_6_END 0x1fbfffff /* 4 Meg, ether */ #define KN02_PHYS_TC_7_START 0x1fc00000 /* TURBOchannel, slot 7 */ #define KN02_PHYS_TC_7_END 0x1fffffff /* 4 Meg, system devices */ #define KN02_PHYS_TC_START KN02_PHYS_TC_0_START #define KN02_PHYS_TC_END KN02_PHYS_TC_7_END /* 32 Meg */ #define KN02_TC_NSLOTS 8 #define KN02_TC_MIN 0 #define KN02_TC_MAX 6 /* don't look at system slot */ /* * System devices */ #define KN02_SYS_ROM_START KN02_PHYS_TC_7_START+0x000000 #define KN02_SYS_ROM_END KN02_PHYS_TC_7_START+0x07ffff #define KN02_SYS_RESERVED KN02_PHYS_TC_7_START+0x080000 #define KN02_SYS_CHKSYN KN02_PHYS_TC_7_START+0x100000 #define KN02_SYS_ERRADR KN02_PHYS_TC_7_START+0x180000 #define KN02_SYS_DZ KN02_PHYS_TC_7_START+0x200000 #define KN02_SYS_CLOCK KN02_PHYS_TC_7_START+0x280000 #define KN02_SYS_CSR KN02_PHYS_TC_7_START+0x300000 #define KN02_SYS_ROM1_START KN02_PHYS_TC_7_START+0x380000 #define KN02_SYS_ROM1_END KN02_PHYS_TC_7_START+0x3fffff /* * Interrupts */ #define KN02_INT_FPA IP_LEV7 /* Floating Point coproc */ #define KN02_INT_RES1 IP_LEV6 /* reserved, unused */ #define KN02_INT_MEM IP_LEV5 /* memory controller */ #define KN02_INT_RES2 IP_LEV4 /* reserved, unused */ #define KN02_INT_CLOCK IP_LEV3 /* RTC chip */ #define KN02_INT_IO IP_LEV2 /* I/O slots */ /* * System board registers */ /* system Status and Control register */ #define KN02_CSR_IOINT 0x000000ff /* ro Interrupt pending */ # define KN02_IP_DZ 0x00000080 /* serial lines */ # define KN02_IP_LANCE 0x00000040 /* thin ethernet */ # define KN02_IP_SCSI 0x00000020 /* ASC scsi controller */ # define KN02_IP_XXXX 0x00000018 /* unused */ # define KN02_IP_SLOT2 0x00000004 /* option slot 2 */ # define KN02_IP_SLOT1 0x00000002 /* option slot 1 */ # define KN02_IP_SLOT0 0x00000001 /* option slot 0 */ #define KN02_CSR_BAUD38 0x00000100 /* rw Max DZ baud rate */ #define KN02_CSR_DIAGDN 0x00000200 /* rw Diag jumper */ #define KN02_CSR_BNK32M 0x00000400 /* rw Memory bank stride */ #define KN02_CSR_TXDIS 0x00000800 /* rw Disable DZ xmit */ #define KN02_CSR_LEDIAG 0x00001000 /* rw Latch ECC */ #define KN02_CSR_CORRECT 0x00002000 /* rw ECC corrects single bit */ #define KN02_CSR_ECCMD 0x0000c000 /* rw ECC logic mode */ #define KN02_CSR_IOINTEN 0x00ff0000 /* rw Interrupt enable */ #define KN02_CSR_IOINTEN_SHIFT 16 #define KN02_CSR_NRMMOD 0x01000000 /* ro Diag jumper state */ #define KN02_CSR_REFEVEN 0x02000000 /* ro Refreshing even mem bank */ #define KN02_CSR_PRSVNVR 0x04000000 /* ro Preserve NVR jumper */ #define KN02_CSR_PSWARN 0x08000000 /* ro PS overheating */ #define KN02_CSR_RRESERVED 0xf0000000 /* rz */ #define KN02_CSR_LEDS 0x000000ff /* wo Diag LEDs */ #define KN02_CSR_WRESERVED 0xff000000 /* wz */ /* Error address status register */ #define KN02_ERR_ADDRESS 0x07ffffff /* phys address */ #define KN02_ERR_RESERVED 0x08000000 /* unused */ #define KN02_ERR_ECCERR 0x10000000 /* ECC error */ #define KN02_ERR_WRITE 0x20000000 /* read/write transaction */ #define KN02_ERR_CPU 0x40000000 /* CPU or device initiator */ #define KN02_ERR_VALID 0x80000000 /* Info is valid */ /* ECC check/syndrome status register */ #define KN02_ECC_SYNLO 0x0000007f /* syndrome, even bank */ #define KN02_ECC_SNGLO 0x00000080 /* single bit err, " */ #define KN02_ECC_CHKLO 0x00007f00 /* check bits, " " */ #define KN02_ECC_VLDLO 0x00008000 /* info valid for " */ #define KN02_ECC_SYNHI 0x007f0000 /* syndrome, odd bank */ #define KN02_ECC_SNGHI 0x00800000 /* single bit err, " */ #define KN02_ECC_CHKHI 0x7f000000 /* check bits, " " */ #define KN02_ECC_VLDHI 0x80000000 /* info valid for " */ #endif /* MIPS_KN02_H */ gxemul-0.6.1/src/include/thirdparty/maltareg.h000644 001750 001750 00000021320 13402411502 021574 0ustar00debugdebug000000 000000 /* $NetBSD: maltareg.h,v 1.1 2002/03/07 14:44:04 simonb Exp $ */ #ifndef MALTAREG_H #define MALTAREG_H /* * Copyright 2002 Wasabi Systems, Inc. * All rights reserved. * * Written by Simon Burge for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* Memory Map 0000.0000 * 128MB Typically SDRAM (on Core Board) 0800.0000 * 256MB Typically PCI 1800.0000 * 62MB Typically PCI 1be0.0000 * 2MB Typically System controller's internal registers 1c00.0000 * 32MB Typically not used 1e00.0000 4MB Monitor Flash 1e40.0000 12MB reserved 1f00.0000 12MB Switches LEDs ASCII display Soft reset FPGA revision number CBUS UART (tty2) General Purpose I/O I2C controller 1f10.0000 * 11MB Typically System Controller specific 1fc0.0000 4MB Maps to Monitor Flash 1fd0.0000 * 3MB Typically System Controller specific * depends on implementation of the Core Board and of software */ /* CPU interrupts NMI South Bridge or NMI button 0 South Bridge INTR 1 South Bridge SMI 2 CBUS UART (tty2) 3 COREHI (Core Card) 4 CORELO (Core Card) 5 Not used, driven inactive (typically CPU internal timer interrupt IRQ mapping (as used by YAMON) 0 Timer South Bridge 1 Keyboard SuperIO 2 Reserved by South Bridge (for cascading) 3 UART (tty1) SuperIO 4 UART (tty0) SuperIO 5 Not used 6 Floppy Disk SuperIO 7 Parallel Port SuperIO 8 Real Time Clock South Bridge 9 I2C bus South Bridge 10 PCI A,B,eth PCI slot 1..4, Ethernet 11 PCI C,audio PCI slot 1..4, Audio, USB (South Bridge) PCI D,USB 12 Mouse SuperIO 13 Reserved by South Bridge 14 Primary IDE Primary IDE slot 15 Secondary IDE Secondary IDE slot/Compact flash connector */ #define MALTA_SYSTEMRAM_BASE 0x00000000 /* System RAM: */ #define MALTA_SYSTEMRAM_SIZE 0x08000000 /* 128 MByte */ #define MALTA_PCIMEM1_BASE 0x08000000 /* PCI 1 memory: */ #define MALTA_PCIMEM1_SIZE 0x08000000 /* 128 MByte */ #define MALTA_PCIMEM2_BASE 0x10000000 /* PCI 2 memory: */ #define MALTA_PCIMEM2_SIZE 0x08000000 /* 128 MByte */ #define MALTA_PCIMEM3_BASE 0x18000000 /* PCI 3 memory */ #define MALTA_PCIMEM3_SIZE 0x03e00000 /* 62 MByte */ #define MALTA_CORECTRL_BASE 0x1be00000 /* Core control: */ #define MALTA_CORECTRL_SIZE 0x00200000 /* 2 MByte */ #define MALTA_RESERVED_BASE1 0x1c000000 /* Reserved: */ #define MALTA_RESERVED_SIZE1 0x02000000 /* 32 MByte */ #define MALTA_MONITORFLASH_BASE 0x1e000000 /* Monitor Flash: */ #define MALTA_MONITORFLASH_SIZE 0x003e0000 /* 4 MByte */ #define MALTA_MONITORFLASH_SECTORSIZE 0x00010000 /* Sect. = 64 KB */ #define MALTA_FILEFLASH_BASE 0x1e3e0000 /* File Flash (for monitor): */ #define MALTA_FILEFLASH_SIZE 0x00020000 /* 128 KByte */ #define MALTA_FILEFLASH_SECTORSIZE 0x00010000 /* Sect. = 64 KB */ #define MALTA_RESERVED_BASE2 0x1e400000 /* Reserved: */ #define MALTA_RESERVED_SIZE2 0x00c00000 /* 12 MByte */ #define MALTA_FPGA_BASE 0x1f000000 /* FPGA: */ #define MALTA_FPGA_SIZE 0x00c00000 /* 12 MByte */ #define MALTA_NMISTATUS (MALTA_FPGA_BASE + 0x24) #define MALTA_NMI_SB 0x2 /* Pending NMI from the South Bridge */ #define MALTA_NMI_ONNMI 0x1 /* Pending NMI from the ON/NMI push button */ #define MALTA_NMIACK (MALTA_FPGA_BASE + 0x104) #define MALTA_NMIACK_ONNMI 0x1 /* Write 1 to acknowledge ON/NMI */ #define MALTA_SWITCH (MALTA_FPGA_BASE + 0x200) #define MALTA_SWITCH_MASK 0xff /* settings of DIP switch S2 */ #define MALTA_STATUS (MALTA_FPGA_BASE + 0x208) #define MALTA_ST_MFWR 0x10 /* Monitor Flash is write protected (JP1) */ #define MALTA_S54 0x08 /* switch S5-4 - set YAMON factory default mode */ #define MALTA_S53 0x04 /* switch S5-3 */ #define MALTA_BIGEND 0x02 /* switch S5-2 - big endian mode */ #define MALTA_JMPRS (MALTA_FPGA_BASE + 0x210) #define MALTA_JMPRS_PCICLK 0x1c /* PCI clock frequency */ #define MALTA_JMPRS_EELOCK 0x02 /* I2C EEPROM is write protected */ #define MALTA_LEDBAR (MALTA_FPGA_BASE + 0x408) #define MALTA_ASCIIWORD (MALTA_FPGA_BASE + 0x410) #define MALTA_ASCII_BASE (MALTA_FPGA_BASE + 0x418) #define MALTA_ASCIIPOS0 0x00 #define MALTA_ASCIIPOS1 0x08 #define MALTA_ASCIIPOS2 0x10 #define MALTA_ASCIIPOS3 0x18 #define MALTA_ASCIIPOS4 0x20 #define MALTA_ASCIIPOS5 0x28 #define MALTA_ASCIIPOS6 0x30 #define MALTA_ASCIIPOS7 0x38 #define MALTA_SOFTRES (MALTA_FPGA_BASE + 0x500) #define MALTA_GORESET 0x42 /* write this to MALTA_SOFTRES for board reset */ /* * BRKRES is the number of milliseconds before a "break" on tty will * trigger a reset. A value of 0 will disable the reset. */ #define MALTA_BRKRES (MALTA_FPGA_BASE + 0x508) #define MALTA_BRKRES_MASK 0xff #define MALTA_CBUSUART (MALTA_FPGA_BASE + 0x900) /* 16C550C UART, 8 bit registers on 8 byte boundaries */ /* RXTX 0x00 */ /* INTEN 0x08 */ /* IIFIFO 0x10 */ /* LCTRL 0x18 */ /* MCTRL 0x20 */ /* LSTAT 0x28 */ /* MSTAT 0x30 */ /* SCRATCH 0x38 */ #define MALTA_CBUSUART_INTR 2 #define MALTA_GPIO_BASE (MALTA_FPGA_BASE + 0xa00) #define MALTA_GPOUT 0x0 #define MALTA_GPINP 0x8 #define MALTA_I2C_BASE (MALTA_FPGA_BASE + 0xb00) #define MALTA_I2CINP 0x00 #define MALTA_I2COE 0x08 #define MALTA_I2COUT 0x10 #define MALTA_I2CSEL 0x18 #define MALTA_BOOTROM_BASE 0x1fc00000 /* Boot ROM: */ #define MALTA_BOOTROM_SIZE 0x00400000 /* 4 MByte */ #define MALTA_REVISION 0x1fc00010 #define MALTA_REV_FPGRV 0xff0000 /* CBUS FPGA revision */ #define MALTA_REV_CORID 0x00fc00 /* Core Board ID */ #define MALTA_REV_CORRV 0x000300 /* Core Board Revision */ #define MALTA_REV_PROID 0x0000f0 /* Product ID */ #define MALTA_REV_PRORV 0x00000f /* Product Revision */ /* PCI definitions */ #define MALTA_SOUTHBRIDGE_INTR 0 #define MALTA_PCI0_IO_BASE MALTA_PCIMEM3_BASE #define MALTA_PCI0_ADDR( addr ) (MALTA_PCI0_IO_BASE + (addr)) #define MALTA_RTCADR 0x70 // MALTA_PCI_IO_ADDR8(0x70) #define MALTA_RTCDAT 0x71 // MALTA_PCI_IO_ADDR8(0x71) #define MALTA_SMSC_COM1_ADR 0x3f8 #define MALTA_SMSC_COM2_ADR 0x2f8 #define MALTA_UART0ADR MALTA_SMSC_COM1_ADR // MALTA_PCI0_ADDR(MALTA_SMSC_COM1_ADR) #define MALTA_UART1ADR MALTA_SMSC_COM2_ADR // MALTA_PCI0_ADDR(MALTA_SMSC_COM2_ADR) #define MALTA_SMSC_1284_ADR 0x378 #define MALTA_1284ADR MALTA_SMSC_1284_ADR // MALTA_PCI0_ADDR(MALTA_SMSC_1284_ADR) #define MALTA_SMSC_FDD_ADR 0x3f0 #define MALTA_FDDADR MALTA_SMSC_FDD_ADR // MALTA_PCI0_ADDR(MALTA_SMSC_FDD_ADR) #define MALTA_SMSC_KYBD_ADR 0x60 /* Fixed 0x60, 0x64 */ #define MALTA_KYBDADR MALTA_SMSC_KYBD_ADR // MALTA_PCI0_ADDR(MALTA_SMSC_KYBD_ADR) #define MALTA_SMSC_MOUSE_ADR MALTA_SMSC_KYBD_ADR #define MALTA_MOUSEADR MALTA_KYBDADR #define MALTA_DMA_PCI_PCIBASE 0x00000000UL #define MALTA_DMA_PCI_PHYSBASE 0x00000000UL #define MALTA_DMA_PCI_SIZE (256 * 1024 * 1024) #define MALTA_DMA_ISA_PCIBASE 0x00800000UL #define MALTA_DMA_ISA_PHYSBASE 0x00000000UL #define MALTA_DMA_ISA_SIZE (8 * 1024 * 1024) #ifndef _LOCORE void led_bar(uint8_t); void led_display_word(uint32_t); void led_display_str(const char *); void led_display_char(int, uint8_t); #endif #endif /* MALTAREG_H */ gxemul-0.6.1/src/include/thirdparty/pmppc.h000644 001750 001750 00000007155 13402411502 021131 0ustar00debugdebug000000 000000 /* gxemul: $Id: pmppc.h,v 1.2 2005-03-05 12:34:03 debug Exp $ */ /* $NetBSD: pmppc.h,v 1.2 2002/07/05 18:45:20 matt Exp $ */ #ifndef PMPPC_H #define PMPPC_H /* * Copyright (c) 2002 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Lennart Augustsson (lennart@augustsson.net) at Sandburst Corp. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* SDRAM */ #define PMPPC_SDRAM_BASE 0x00000000 /* Flash */ #define PMPPC_FLASH_BASE 0x70000000 #define PMPPC_IO_START 0x7fe00000 /* CS8900A ethernet */ #define PMPPC_CS_IO_BASE 0x7fe00000 #define PMPPC_CS_IO 0x7fe00c00 #define PMPPC_CS_MEM 0x7fe04000 /* time-of-day clock */ #define PMPPC_RTC 0x7ff00000 #define PMPPC_RTC_SIZE 0x00002000 /* board config regs */ #define PMPPC_CONFIG0 0x7ff40000 #define PMPPC_CONFIG1 0x7ff40001 #define PMPPC_LEDS 0x7ff40002 #define PMPPC_RESET 0x7ff40003 #define PMPPC_RESET_SEQ_STEP1 0xac #define PMPPC_RESET_SEQ_STEP2 0x1d #define PMPPC_INTR 0x7ff40004 /* ROM */ #define PMPPC_ROM_BASE 0x7ff80000 void setleds(int leds); /* Interrupts */ #define PMPPC_I_BPMC_INTA CPC_IB_EXT0 /* PCI INTA */ #define PMPPC_I_BPMC_INTB CPC_IB_EXT1 /* PCI INTB */ #define PMPPC_I_BPMC_INTC CPC_IB_EXT2 /* PCI INTC */ #define PMPPC_I_BPMC_INTD CPC_IB_EXT3 /* PCI INTD */ #define PMPPC_I_ETH_INT CPC_IB_EXT4 /* ethernet */ #define PMPPC_I_RTC_INT CPC_IB_EXT5 /* rtc */ /* * The variables below are extracted from the config register located * at PMPPC_CONFIG. */ struct a_config { int a_boot_device; #define A_BOOT_ROM 0 #define A_BOOT_FLASH 1 int a_has_ecc; uint a_mem_size; /* in bytes */ uint a_l2_cache; #define A_CACHE_PARITY 0 #define A_CACHE_NO_PARITY 1 #define A_CACHE_NONE 3 uint a_bus_freq; /* in hz */ int a_is_monarch; int a_has_eth; int a_has_rtc; uint a_flash_size; /* in bytes */ uint a_flash_width; /* in bits */ }; extern struct a_config a_config; #endif /* PMPPC_H */ gxemul-0.6.1/src/include/thirdparty/hitachi_hm53462_rop.h000644 001750 001750 00000004503 13402411502 023365 0ustar00debugdebug000000 000000 #ifndef HITACHI_HM53462_ROP_H #define HITACHI_HM53462_ROP_H /* Imported into GXemul 2018-02-14, from OpenBSD 6.2. */ /* * Copyright (c) 2013 Kenji Aoyama * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Helper macros */ #define W(addr) ((u_int32_t *)(addr)) #define R(addr) ((u_int32_t *)((u_int8_t *)(addr) + 0x40000)) #define P0(addr) ((u_int32_t *)((u_int8_t *)(addr) + 0x40000)) #define P1(addr) ((u_int32_t *)((u_int8_t *)(addr) + 0x80000)) #define P2(addr) ((u_int32_t *)((u_int8_t *)(addr) + 0xC0000)) #define P3(addr) ((u_int32_t *)((u_int8_t *)(addr) + 0x100000)) /* * Replacement Rules (rops) (derived from hp300) */ #define RR_CLEAR 0x0 #define RR_COPY 0x3 /* * ROP function * * LUNA's frame buffer uses Hitach HM53462 video RAM, which has raster * (logic) operation, or ROP, function. To use ROP function on LUNA, write * a 32bit `mask' value to the specified address corresponding to each ROP * logic. * * D: the data writing to the video RAM * M: the data already stored on the video RAM */ /* operation index the video RAM contents will be */ #define ROP_ZERO 0 /* all 0 */ #define ROP_AND1 1 /* D & M */ #define ROP_AND2 2 /* ~D & M */ /* Not used on LUNA 3 */ #define ROP_AND3 4 /* D & ~M */ #define ROP_THROUGH 5 /* D */ #define ROP_EOR 6 /* (~D & M) | (D & ~M) */ #define ROP_OR1 7 /* D | M */ #define ROP_NOR 8 /* ~D | ~M */ #define ROP_ENOR 9 /* (D & M) | (~D & ~M) */ #define ROP_INV1 10 /* ~D */ #define ROP_OR2 11 /* ~D | M */ #define ROP_INV2 12 /* ~M */ #define ROP_OR3 13 /* D | ~M */ #define ROP_NAND 14 /* ~D | ~M */ #define ROP_ONE 15 /* all 1 */ #endif /* HITACHI_HM53462_ROP_H */ gxemul-0.6.1/src/include/thirdparty/lptreg.h000644 001750 001750 00000006167 13402411502 021311 0ustar00debugdebug000000 000000 /* $NetBSD: lptreg.h,v 1.8 2005/02/27 00:27:02 perry Exp $ */ #ifndef LPTREG_H #define LPTREG_H /*- * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)lptreg.h 1.1 (Berkeley) 12/19/90 */ /* * AT Parallel Port (for lineprinter) * Interface port and bit definitions * Written by William Jolitz 12/18/90 * Copyright (C) William Jolitz 1990 */ /* * On a standard DB25 parallel port, the bits show up as follows: * * 13 12 11 10 9 8 7 6 5 4 3 2 1 * ~S7 S6 S5 S4 D7 D6 D5 D4 D3 D2 D1 D0 ~C0 * * G G G G G G G G ~C3 C2 S3 ~C1 * 25 24 23 22 21 20 19 18 17 16 15 14 * * D7-D0 are output bits from the data register * S7-S3 are input bits read at the status register * C3-C0 are output bits from the control register */ #define LPT_DATA 0 /* Data to/from printer (R/W) */ #define LPT_STATUS 1 /* Status of printer (R) */ #define LPS_NERR 0x08 /* printer no error */ #define LPS_SELECT 0x10 /* printer selected */ #define LPS_NOPAPER 0x20 /* printer out of paper */ #define LPS_NACK 0x40 /* printer no ack of data */ #define LPS_NBSY 0x80 /* printer no ack of data */ #define LPT_CONTROL 2 /* Control printer (R/W) */ #define LPC_STROBE 0x01 /* strobe data to printer */ #define LPC_AUTOLF 0x02 /* automatic linefeed */ #define LPC_NINIT 0x04 /* initialize printer */ #define LPC_SELECT 0x08 /* printer selected */ #define LPC_IENABLE 0x10 /* printer out of paper */ #define LPT_NPORTS 4 #endif /* LPTREG_H */ gxemul-0.6.1/src/include/thirdparty/jazz_r4030_dma.h000644 001750 001750 00000012254 13402411502 022435 0ustar00debugdebug000000 000000 /* $NetBSD: dma.h,v 1.2 2001/07/24 16:26:53 tsutsui Exp $ */ /* $OpenBSD: dma.h,v 1.3 1997/04/19 17:19:51 pefo Exp $ */ #ifndef __JAZZ_R4030_DMA #define __JAZZ_R4030_DMA #ifndef GXEMUL #define GXEMUL #endif /* * Copyright (c) 1996 Per Fogelstrom * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Per Fogelstrom. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Hardware dma registers. */ typedef volatile struct { int32_t dma_mode; int32_t pad1; int32_t dma_enab; int32_t pad2; int32_t dma_count; int32_t pad3; int32_t dma_addr; int32_t pad4; } DmaReg, *pDmaReg; #define R4030_DMA_MODE_40NS 0x00 /* Device dma timing */ #define R4030_DMA_MODE_80NS 0x01 /* Device dma timing */ #define R4030_DMA_MODE_120NS 0x02 /* Device dma timing */ #define R4030_DMA_MODE_160NS 0x03 /* Device dma timing */ #define R4030_DMA_MODE_200NS 0x04 /* Device dma timing */ #define R4030_DMA_MODE_240NS 0x05 /* Device dma timing */ #define R4030_DMA_MODE_280NS 0x06 /* Device dma timing */ #define R4030_DMA_MODE_320NS 0x07 /* Device dma timing */ #define R4030_DMA_MODE_8 0x08 /* Device 8 bit */ #define R4030_DMA_MODE_16 0x10 /* Device 16 bit */ #define R4030_DMA_MODE_32 0x18 /* Device 32 bit */ #define R4030_DMA_MODE_INT 0x20 /* Interrupt when done */ #define R4030_DMA_MODE_BURST 0x40 /* Burst mode (Rev 2 only) */ #define R4030_DMA_MODE_FAST 0x80 /* Fast dma cycle (Rev 2 only) */ #define R4030_DMA_MODE 0xff /* Mode register bits */ #define DMA_DIR_WRITE 0x100 /* Software direction status */ #define DMA_DIR_READ 0x000 /* Software direction status */ #define R4030_DMA_ENAB_RUN 0x01 /* Enable dma */ #define R4030_DMA_ENAB_READ 0x00 /* Read from device */ #define R4030_DMA_ENAB_WRITE 0x02 /* Write to device */ #define R4030_DMA_ENAB_TC_IE 0x100 /* Terminal count int enable */ #define R4030_DMA_ENAB_ME_IE 0x200 /* Memory error int enable */ #define R4030_DMA_ENAB_TL_IE 0x400 /* Translation limit int enable */ #define R4030_DMA_COUNT_MASK 0x000fffff /* Byte count mask */ /* * Structure used to control dma. */ #ifndef GXEMUL typedef struct dma_softc { struct device sc_dev; /* use as a device */ struct esp_softc *sc_esp; bus_addr_t dma_va; /* Viritual address for transfer */ int mode; /* Mode register value and direction */ jazz_dma_pte_t *pte_base; /* Pointer to dma tlb array */ int pte_size; /* Size of pte allocated pte array */ pDmaReg dma_reg; /* Pointer to dma registers */ int sc_active; /* Active flag */ void (*reset)(struct dma_softc *); /* Reset routine pointer */ void (*enintr)(struct dma_softc *); /* Int enab routine pointer */ void (*map)(struct dma_softc *, char *, size_t, int); /* Map a dma viritual area */ void (*start)(struct dma_softc *, caddr_t, size_t, int); /* Start routine pointer */ int (*isintr)(struct dma_softc *); /* Int check routine pointer */ int (*intr)(struct dma_softc *); /* Interrupt routine pointer */ void (*end)(struct dma_softc *); /* Interrupt routine pointer */ } dma_softc_t; #endif /* not in gxemul */ #define DMA_TO_DEV 0 #define DMA_FROM_DEV 1 #define DMA_RESET(r) ((r->reset)(r)) #define DMA_START(a, b, c, d) ((a->start)(a, b, c, d)) #define DMA_MAP(a, b, c, d) ((a->map)(a, b, c, d)) #define DMA_INTR(r) ((r->intr)(r)) #define DMA_DRAIN(r) #define DMA_END(r) ((r->end)(r)) #ifndef GXEMUL void picaDmaInit __P((void)); void picaDmaTLBAlloc __P((dma_softc_t *)); void picaDmaTLBFree __P((dma_softc_t *)); void picaDmaMap __P((struct dma_softc *, char *, size_t, int)); void picaDmaStart __P((struct dma_softc *, char *, size_t, int)); void picaDmaFlush __P((struct dma_softc *, char *, size_t, int)); void asc_dma_init __P((struct dma_softc *)); void fdc_dma_init __P((struct dma_softc *)); #endif /* not in gxemul */ #endif /* __JAZZ_R4030_DMA */ gxemul-0.6.1/src/include/thirdparty/sh4_cache.h000644 001750 001750 00000012756 13402411502 021636 0ustar00debugdebug000000 000000 /* $NetBSD: cache_sh4.h,v 1.11 2006/03/04 01:55:03 uwe Exp $ */ #ifndef _SH3_CACHE_SH4_H_ #define _SH3_CACHE_SH4_H_ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by UCHIYAMA Yasushi. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * SH4: SH7750 SH7750S SH7750R SH7751 SH7751R */ /* #include */ /* #ifdef _KERNEL */ #define SH4_ICACHE_SIZE 8192 #define SH4_DCACHE_SIZE 16384 #define SH4_EMODE_ICACHE_SIZE 16384 #define SH4_EMODE_DCACHE_SIZE 32768 #define SH4_CACHE_LINESZ 32 #define SH4_CCR 0xff00001c #define SH4_CCR_EMODE 0x80000000 #define SH4_CCR_IIX 0x00008000 #define SH4_CCR_ICI 0x00000800 #define SH4_CCR_ICE 0x00000100 #define SH4_CCR_OIX 0x00000080 #define SH4_CCR_ORA 0x00000020 #define SH4_CCR_OCI 0x00000008 #define SH4_CCR_CB 0x00000004 #define SH4_CCR_WT 0x00000002 #define SH4_CCR_OCE 0x00000001 #define SH4_QACR0 0xff000038 #define SH4_QACR1 0xff00003c #define SH4_QACR_AREA_SHIFT 2 #define SH4_QACR_AREA_MASK 0x0000001c /* I-cache address/data array */ #define SH4_CCIA 0xf0000000 /* address specification */ #define CCIA_A 0x00000008 /* associate bit */ #define CCIA_ENTRY_SHIFT 5 /* line size 32B */ #define CCIA_ENTRY_MASK 0x00001fe0 /* [12:5] 256-entries */ #define CCIA_EMODE_ENTRY_MASK 0x00003fe0 /* [13:5] 512-entries */ /* data specification */ #define CCIA_V 0x00000001 #define CCIA_TAGADDR_MASK 0xfffffc00 /* [31:10] */ #define SH4_CCID 0xf1000000 /* address specification */ #define CCID_L_SHIFT 2 #define CCID_L_MASK 0x1c /* line-size is 32B */ #define CCID_ENTRY_MASK 0x00001fe0 /* [12:5] 256-entries */ /* D-cache address/data array */ #define SH4_CCDA 0xf4000000 /* address specification */ #define CCDA_A 0x00000008 /* associate bit */ #define CCDA_ENTRY_SHIFT 5 /* line size 32B */ #define CCDA_ENTRY_MASK 0x00003fe0 /* [13:5] 512-entries */ /* data specification */ #define CCDA_V 0x00000001 #define CCDA_U 0x00000002 #define CCDA_TAGADDR_MASK 0xfffffc00 /* [31:10] */ #define SH4_CCDD 0xf5000000 /* Store Queue */ #define SH4_SQ 0xe0000000 /* * cache flush macro for locore level code. */ #define SH4_CACHE_FLUSH() \ do { \ uint32_t __e, __a; \ \ /* D-cache */ \ for (__e = 0; __e < (SH4_DCACHE_SIZE / SH4_CACHE_LINESZ); __e++) {\ __a = SH4_CCDA | (__e << CCDA_ENTRY_SHIFT); \ (*(volatile uint32_t *)__a) &= ~(CCDA_U | CCDA_V); \ } \ /* I-cache */ \ for (__e = 0; __e < (SH4_ICACHE_SIZE / SH4_CACHE_LINESZ); __e++) {\ __a = SH4_CCIA | (__e << CCIA_ENTRY_SHIFT); \ (*(volatile uint32_t *)__a) &= ~(CCIA_V); \ } \ } while(/*CONSTCOND*/0) #define SH4_EMODE_CACHE_FLUSH() \ do { \ uint32_t __e, __a; \ \ /* D-cache */ \ for (__e = 0;__e < (SH4_EMODE_DCACHE_SIZE / SH4_CACHE_LINESZ);__e++) {\ __a = SH4_CCDA | (__e << CCDA_ENTRY_SHIFT); \ (*(volatile uint32_t *)__a) &= ~(CCDA_U | CCDA_V); \ } \ /* I-cache */ \ for (__e = 0;__e < (SH4_EMODE_ICACHE_SIZE / SH4_CACHE_LINESZ);__e++) {\ __a = SH4_CCIA | (__e << CCIA_ENTRY_SHIFT); \ (*(volatile uint32_t *)__a) &= ~(CCIA_V); \ } \ } while(/*CONSTCOND*/0) #define SH7750_CACHE_FLUSH() SH4_CACHE_FLUSH() #define SH7750S_CACHE_FLUSH() SH4_CACHE_FLUSH() #define SH7751_CACHE_FLUSH() SH4_CACHE_FLUSH() #if defined(SH4_CACHE_DISABLE_EMODE) #define SH7750R_CACHE_FLUSH() SH4_CACHE_FLUSH() #define SH7751R_CACHE_FLUSH() SH4_CACHE_FLUSH() #else #define SH7750R_CACHE_FLUSH() SH4_EMODE_CACHE_FLUSH() #define SH7751R_CACHE_FLUSH() SH4_EMODE_CACHE_FLUSH() #endif #if 0 #ifndef _LOCORE extern void sh4_cache_config(void); #endif #endif /* #endif _KERNEL */ #endif /* !_SH3_CACHE_SH4_H_ */ gxemul-0.6.1/src/include/thirdparty/ee_timerreg.h000644 001750 001750 00000012125 13402411502 022272 0ustar00debugdebug000000 000000 /* gxemul: $Id: ee_timerreg.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: timerreg.h,v 1.1 2001/10/16 15:38:40 uch Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by UCHIYAMA Yasushi. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * 16bit timer 0:3 * source: BUSCLK, H-BLNK */ #define EE_TIMER_MIN 0 #define EE_TIMER_MAX 3 #define LEGAL_TIMER(x) \ (((x) >= EE_TIMER_MIN) && ((x) <= EE_TIMER_MAX)) /* Register address. all registers are 32bit wide */ #define TIMER_REGBASE 0x10000000 #define TIMER_REGSIZE 0x2000 #define TIMER_OFS 0x800 #define T_COUNT_REG(x) MIPS_PHYS_TO_KSEG1((TIMER_REGBASE + TIMER_OFS * (x))) #define T_MODE_REG(x) MIPS_PHYS_TO_KSEG1((TIMER_REGBASE + \ TIMER_OFS * (x) + 0x10)) #define T_COMP_REG(x) MIPS_PHYS_TO_KSEG1((TIMER_REGBASE + \ TIMER_OFS * (x) + 0x20)) /* * timer0, timer1 have `hold register'. * (save T_COUNT when SBUS interrupt occured) */ #define T_HOLD_REG(x) (TIMER_REGBASE + TIMER_OFS * (x) + 0x30) #define T0_COUNT_REG MIPS_PHYS_TO_KSEG1(0x10000000) #define T0_MODE_REG MIPS_PHYS_TO_KSEG1(0x10000010) #define T0_COMP_REG MIPS_PHYS_TO_KSEG1(0x10000020) #define T0_HOLD_REG MIPS_PHYS_TO_KSEG1(0x10000030) #define T1_COUNT_REG MIPS_PHYS_TO_KSEG1(0x10000800) #define T1_MODE_REG MIPS_PHYS_TO_KSEG1(0x10000810) #define T1_COMP_REG MIPS_PHYS_TO_KSEG1(0x10000820) #define T1_HOLD_REG MIPS_PHYS_TO_KSEG1(0x10000830) #define T2_COUNT_REG MIPS_PHYS_TO_KSEG1(0x10001000) #define T2_MODE_REG MIPS_PHYS_TO_KSEG1(0x10001010) #define T2_COMP_REG MIPS_PHYS_TO_KSEG1(0x10001020) #define T3_COUNT_REG MIPS_PHYS_TO_KSEG1(0x10001800) #define T3_MODE_REG MIPS_PHYS_TO_KSEG1(0x10001810) #define T3_COMP_REG MIPS_PHYS_TO_KSEG1(0x10001820) /* * Tn_MODE: mode, status register. */ #define T_MODE_CLKS_MASK 0x3 #define T_MODE_CLKS(x) ((x) & T_MODE_CLKS_MASK) #define T_MODE_CLKS_CLR(x) ((x) & ~T_MODE_CLKS_MASK) #define T_MODE_CLKS_BUSCLK1 0 /* 150Mhz */ #define T_MODE_CLKS_BUSCLK16 1 /* 150 / 16 */ #define T_MODE_CLKS_BUSCLK256 2 /* 150 / 256 */ #define T_MODE_CLKS_HBLNK 3 /* H-Blank */ /* Gate Function Enabled */ #define T_MODE_GATE 0x00000004 /* Gate Selection */ #define T_MODE_GATS_VBLNK 0x00000008 /* Gate Mode */ #define T_MODE_GATM_MASK 0x3 #define T_MODE_GATM_SHIFT 4 #define T_MODE_GATM(x) (((x) >> T_MODE_GATM_SHIFT) & T_MODE_GATM_MASK) #define T_MODE_GATM_CLR(x) \ ((x) & ~(T_MODE_GATM_MASK << T_MODE_GATM_SHIFT)) #define T_MODE_GATM_SET(x, val) \ ((x) | (((val) << T_MODE_GATM_SHIFT) & \ (T_MODE_GATM_MASK << T_MODE_GATM_SHIFT))) #define T_MODE_GATM_LOW 0x0 #define T_MODE_GATM_POSEDGE 0x1 #define T_MODE_GATM_NEGEDGE 0x2 #define T_MODE_GATM_EDGE 0x3 /* Zero Return */ #define T_MODE_ZRET 0x00000040 /* Count Up Enable */ #define T_MODE_CUE 0x00000080 /* Compare-Interrupt Enable */ #define T_MODE_CMPE 0x00000100 /* Overflow-Interrupt Enable */ #define T_MODE_OVFE 0x00000200 /* Equal Flag (write clear) */ #define T_MODE_EQUF 0x00000400 /* Overflow Flag (write clear) */ #define T_MODE_OVFF 0x00000800 /* * Tn_COUNT: counter register */ #define T_COUNT_MASK 0x0000ffff #define T_COUNT(x) ((x) & T_COUNT_MASK) /* * Tn_COMP: compare register */ #define T_COMP_MASK 0x0000ffff #define T_COMP(x) ((x) & T_COMP_MASK) /* * Tn_HOLD: hold register */ #define T_HOLD_MASK 0x0000ffff #define T_HOLD(x) ((x) & T_HOLD_MASK) gxemul-0.6.1/src/include/thirdparty/alpha_prom.h000644 001750 001750 00000007303 13402411502 022127 0ustar00debugdebug000000 000000 /* GXemul: $Id: alpha_prom.h,v 1.2 2006-09-01 16:40:57 debug Exp $ */ /* $NetBSD: prom.h,v 1.12 2000/06/08 03:10:06 thorpej Exp $ */ /* * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. * All rights reserved. * * Author: Keith Bostic, Chris G. Demetriou * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ #if 0 #ifndef ASSEMBLER struct prom_vec { u_int64_t routine; void *routine_arg; }; /* The return value from a prom call. */ typedef union { struct { u_int64_t retval : 32, /* return value. */ unit : 8, mbz : 8, error : 13, status : 3; } u; u_int64_t bits; } prom_return_t; #ifdef _STANDALONE int getchar(void); void putchar(int); #endif void prom_halt(int) __attribute__((__noreturn__)); int prom_getenv(int, char *, int); void hwrpb_primary_init(void); void hwrpb_restart_setup(void); #endif #endif /* Prom operation values. */ #define PROM_R_CLOSE 0x11 #define PROM_R_GETC 0x01 #define PROM_R_GETENV 0x22 #define PROM_R_OPEN 0x10 #define PROM_R_PUTS 0x02 #define PROM_R_READ 0x13 #define PROM_R_WRITE 0x14 #define PROM_R_IOCTL 0x12 /* Prom IOCTL operation subcodes */ #define PROM_I_SKIP2IRG 1 #define PROM_I_SKIP2MARK 2 #define PROM_I_REWIND 3 #define PROM_I_WRITEMARK 4 /* Environment variable values. */ #define PROM_E_BOOTED_DEV 0x4 #define PROM_E_BOOTED_FILE 0x6 #define PROM_E_BOOTED_OSFLAGS 0x8 #define PROM_E_TTY_DEV 0xf #define PROM_E_SCSIID 0x42 #define PROM_E_SCSIFAST 0x43 #if defined(_STANDALONE) || defined(ENABLEPROM) /* * These can't be called from the kernel without great care. * * There have to be stub routines to do the copying that ensures that the * PROM doesn't get called with an address larger than 32 bits. Calls that * either don't need to copy anything, or don't need the copy because it's * already being done elsewhere, are defined here. */ #define prom_open(dev, len) \ prom_dispatch(PROM_R_OPEN, (dev), (len), 0, 0) #define prom_close(chan) \ prom_dispatch(PROM_R_CLOSE, chan, 0, 0, 0) #define prom_read(chan, len, buf, blkno) \ prom_dispatch(PROM_R_READ, chan, len, (u_int64_t)buf, blkno) #define prom_write(chan, len, buf, blkno) \ prom_dispatch(PROM_R_WRITE, chan, len, (u_int64_t)buf, blkno) #define prom_ioctl(chan, op, count) \ prom_dispatch(PROM_R_IOCTL, chan, op, (int64_t)count, 0, 0) #define prom_putstr(chan, str, len) \ prom_dispatch(PROM_R_PUTS, chan, (u_int64_t)str, len, 0) #define prom_getc(chan) \ prom_dispatch(PROM_R_GETC, chan, 0, 0, 0) #define prom_getenv_disp(id, buf, len) \ prom_dispatch(PROM_R_GETENV, id, (u_int64_t)buf, len, 0) #endif #ifndef ASSEMBLER #ifdef _KERNEL int prom_enter(void); void prom_leave(int); void promcnputc(dev_t, int); int promcngetc(dev_t); int promcnlookc(dev_t, char *); u_int64_t prom_dispatch(u_int64_t, u_int64_t, u_int64_t, u_int64_t, u_int64_t); #endif /* _KERNEL */ #endif /* ASSEMBLER */ gxemul-0.6.1/src/include/thirdparty/vr_rtcreg.h000644 001750 001750 00000014275 13402411502 022010 0ustar00debugdebug000000 000000 /* $NetBSD: rtcreg.h,v 1.8 2002/02/10 14:36:52 sato Exp $ */ #ifndef VR_RTCREG_H #define VR_RTCREG_H /*- * Copyright (c) 1999 Shin Takemura. All rights reserved. * Copyright (c) 1999-2001 SATO Kazumi. All rights reserved. * Copyright (c) 1999 PocketBSD Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the PocketBSD project * and its contributors. * 4. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #define SECMIN ((unsigned)60) /* seconds per minute */ #define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */ #define SEC2MIN ((unsigned)60/2) /* 2seconds per minute */ #define SEC2HOUR ((unsigned)(60*SECMIN)/2) /* 2seconds per hour */ #define SEC2DAY ((unsigned)(24*SECHOUR)/2) /* 2seconds per day */ #define SEC2YR ((unsigned)(365*SECDAY)/2) /* 2seconds per common year */ #define YRREF 1999 #define MREF 1 #define DREF 1 #ifndef YBASE #define YBASE 1900 #endif #define EPOCHOFF 0 /* epoch offset */ #ifndef EPOCHYEAR #define EPOCHYEAR 1850 /* XXX */ /* WINCE epoch year */ #endif #define EPOCHMONTH 1 /* WINCE epoch month of year */ #define EPOCHDATE 1 /* WINCE epoch date of month */ #define LEAPYEAR4(year) ((((year) % 4) == 0 && ((year) % 100) != 0) || ((year%400)) == 0) #define LEAPYEAR2(year) (((year) % 4) == 0) /* * RTC (Real Time Clock Unit) Registers definitions. * start 0x0B0000C0 (Vr4102-4121) * start 0x0F000100 (Vr4122-4131) * start 0x0B0000C0 (Vr4181) */ #define RTC_NO_REG_W 0xffffffff #define ETIME_L_REG_W 0x000 /* Elapsed Time L */ #define ETIME_M_REG_W 0x002 /* Elapsed Time M */ #define ETIME_H_REG_W 0x004 /* Elapsed Time H */ #define ETIME_L_HZ 0x8000 /* 1 HZ */ #define ECMP_L_REG_W 0x008 /* Elapsed Compare L */ #define ECMP_M_REG_W 0x00a /* Elapsed Compare M */ #define ECMP_H_REG_W 0x00c /* Elapsed Compare H */ #define RTCL1_L_REG_W 0x010 /* RTC Long 1 L */ #define RTCL1_H_REG_W 0x012 /* RTC Long 1 H */ #define RTCL1_L_HZ 0x8000 /* 1 HZ */ #define RTCL1_CNT_L_REG_W 0x014 /* RTC Long 1 Count L */ #define RTCL1_CNT_H_REG_W 0x016 /* RTC Long 1 Count H */ #define RTCL2_L_REG_W 0x018 /* RTC Long 2 L */ #define RTCL2_H_REG_W 0x01a /* RTC Long 2 H */ #define RTCL2_L_HZ 0x8000 /* 1 HZ */ #define RTCL2_CNT_L_REG_W 0x01c /* RTC Long 2 Count L */ #define RTCL2_CNT_H_REG_W 0x01e /* RTC Long 2 Count H */ #define VR4102_TCLK_L_REG_W 0x100 /* TCLK L */ #define VR4102_TCLK_H_REG_W 0x102 /* TCLK H */ #define VR4122_TCLK_L_REG_W 0x020 /* TCLK L */ #define VR4122_TCLK_H_REG_W 0x022 /* TCLK H */ #if defined SINGLE_VRIP_BASE #if defined VRGROUP_4102_4121 #define TCLK_L_REG_W VR4102_TCLK_L_REG_W /* TCLK L */ #define TCLK_H_REG_W VR4102_TCLK_H_REG_W /* TCLK H */ #endif /* VRGROUP_4102_4121 */ #if defined VRGROUP_4122_4131 #define TCLK_L_REG_W VR4122_TCLK_L_REG_W /* TCLK L */ #define TCLK_H_REG_W VR4122_TCLK_H_REG_W /* TCLK H */ #endif /* VRGROUP_4122_4131 */ #if defined VRGROUP_4181 #define TCLK_L_REG_W RTC_NO_REG_W #define TCLK_H_REG_W RTC_NO_REG_W #endif /* VRGROUP_4181 */ #endif /* defined SINGLE_VRIP_BASE */ #define VR4102_TCLK_CNT_L_REG_W 0x104 /* TCLK Count L */ #define VR4102_TCLK_CNT_H_REG_W 0x106 /* TCLK Count H */ #define VR4122_TCLK_CNT_L_REG_W 0x024 /* TCLK Count L */ #define VR4122_TCLK_CNT_H_REG_W 0x026 /* TCLK Count H */ #if defined SINGLE_VRIP_BASE #if defined VRGROUP_4102_4121 #define TCLK_CNT_L_REG_W VR4102_TCLK_CNT_L_REG_W /* TCLK Count L */ #define TCLK_CNT_H_REG_W VR4102_TCLK_CNT_L_REG_W /* TCLK Count H */ #endif /* VRGROUP_4102_4121 */ #if defined VRGROUP_4122_4131 #define TCLK_CNT_L_REG_W VR4122_TCLK_CNT_L_REG_W /* TCLK Count L */ #define TCLK_CNT_H_REG_W VR4122_TCLK_CNT_H_REG_W /* TCLK Count H */ #endif /* VRGROUP_4122_4131 */ #if defined VRGROUP_4181 #define TCLK_CNT_L_REG_W RTC_NO_REG_W #define TCLK_CNT_H_REG_W RTC_NO_REG_W #endif /* VRGROUP_4181 */ #endif /* defined SINGLE_VRIP_BASE */ #define VR4102_RTCINT_REG_W 0x11e /* RTC intr reg. */ #define VR4122_RTCINT_REG_W 0x03e /* RTC intr reg. */ #define VR4181_RTCINT_REG_W 0x11e /* RTC intr reg. */ #if defined SINGLE_VRIP_BASE #if defined VRGROUP_4102_4121 #define RTCINT_REG_W VR4102_RTCINT_REG_W /* RTC intr reg. */ #endif /* VRGROUP_4102_4121 */ #if defined VRGROUP_4122_4131 #define RTCINT_REG_W VR4122_RTCINT_REG_W /* RTC intr reg. */ #endif /* VRGROUP_4122 */ #if defined VRGROUP_4181 #define RTCINT_REG_W VR4181_RTCINT_REG_W /* RTC intr reg. */ #endif /* VRGROUP_4181 */ #endif /* defined SINGLE_VRIP_BASE */ #define RTCINT_TCLOCK (1<<3) /* TClock */ #define RTCINT_RTCLONG2 (1<<2) /* RTC Long 2 */ #define RTCINT_RTCLONG1 (1<<1) /* RTC Long 1 */ #define RTCINT_ELAPSED (1) /* Elapsed time */ #define RTCINT_ALL (RTCINT_TCLOCK|RTCINT_RTCLONG2|RTCINT_RTCLONG1|RTCINT_ELAPSED) #endif /* VR_RTCREG_H */ gxemul-0.6.1/src/include/thirdparty/dec_5100.h000644 001750 001750 00000016722 13402411502 021212 0ustar00debugdebug000000 000000 /* gxemul: $Id: dec_5100.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ #ifndef DEC_5100_H #define DEC_5100_H /* $NetBSD: kn230.h,v 1.2 1999/03/25 01:17:52 simonb Exp $ */ /* * Copyright (c) 1997,1998 Jonathan Stone. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Jonathan Stone for * the NetBSD Project. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Physical addresses of baseboard devices and registers on the * the DECstation 5100 motherboard (also known as the kn230). * * The only options on the kn230 are two slots for daughterboards. * Each slot can contain an extra four-port dc708x DZ11 clone chip. * Most baseborad chips are the same hardware and at the same * address as the DECstation 3100 (kn01), except: * * The kn230 has more devices than the 3100, so instead * of hardwiring each device to a CPU interrupt line, * the kn230 provides an interrupt-request register (ICSR). * Devices are mapped onto CPU interrupt lines as below: * hardint 5: fpu * hardint 4: reset switch * hardint 3: memory error (write to nonexistent memory) * hardint 2: clock * hardint 1: sii, lance * hardint 0: baseboard DZ, I/O option cards * * the ICSR only indicates which devices are requesting interrupts. * there is no interrupt mask register. * * There is no framebuffer, pcc (cursor), colormap or vdac on a 5100. */ #define KN230_SYS_LANCE 0x18000000 /* Lance chip */ #define KN230_SYS_LANCE_B_START 0x19000000 /* 64 Kb Lance Buffer */ #define KN230_SYS_LANCE_B_END 0x19010000 #define KN230_SYS_SII 0x1a000000 /* scsi SII chip */ #define KN230_SYS_SII_B_START 0x1b000000 /* 128 Kb SCSI buffer */ #define KN230_SYS_SII_B_END 0x1b020000 #define KN230_SYS_DZ0 0x1c000000 /* baseboard DZ serial chip */ #define KN230_SYS_CLOCK 0x1d000000 /* mc146818 rtc chip */ #define KN230_SYS_ICSR 0x1e000000 /* System control register */ /* * Interrupt-request bitmasks in the low-order 16 bits of the CSR. * If a bit is set, the corresponding device has an interrupt condition. * There is no equivalent per-device interrupt masking register. * (note: these were LED control bits in the kn01). */ #define KN230_CSR_INTR_RESET 0x00004000 /* reset button */ #define KN230_CSR_INTR_WMERR 0x00002000 /* badaddr() or write error */ #define KN230_CSR_INTR_LANCE 0x00001000 /* lance interrupt */ #define KN230_CSR_INTR_SII 0x00000800 /* scsi interrupt */ #define KN230_CSR_INTR_OPT1 0x00000400 /* second option DZ */ #define KN230_CSR_INTR_OPT0 0x00000200 /* first option DZ */ #define KN230_CSR_INTR_DZ0 0x00000100 /* baseboard DZ */ /* * kn230 LED control register. * Writing a 1 bit to any bit turns off the corresponding LED. * low bits are or'ed to control registers which have side effects. * * This is sort of like the 3100 CSR only at a different address, and * with the same external-logic hack as the 5000/200 to enable 38.4 * baud mode on the baseboard DZ chip. */ #define KN230_SYS_CTL_LED 0x14000000 /* LED register */ #define KN230_LED7 0x00008000 /* no side effect */ #define KN230_LED6 0x00004000 /* no side effect */ #define KN230_LED5 0x00002000 /* no side effect */ #define KN230_LED4 0x00001000 /* no side effect */ #define KN230_LED3 0x00000800 /* Turns off led 3. * Also disables main memory. * enables writes to EEPROM. */ #define KN230_LED2 0x00000400 /* Turns off led 2. * 0: forces DZ to run at * 38.4 when 19.2 is selected * 1: is 19.2 means 19.2. */ #define KN230_LED1 0x00000200 /* read-only * 0: 8M memory in bank 1 * 1: 32M in bank1 */ #define KN230_LED0 0x00000100 /* * Option slot addresses. * dc7084 registers appear here, if present. */ #define KN230_SYS_DZ1 0x15000000 /* DZ1 Control and status */ #define KN230_SYS_DZ2 0x15200000 /* DZ2 Control and status */ /* * Write error address. * Same address as the KN01_SYS_MERR, but with a presence bit for a * PrestoServe option and a secure console-mode the low-order bits. */ #define KN230_SYS_WEAR 0x17000000 /* Write-error address reg */ #define KN230_WEAR_OPTIONMASK 0x00000001 /* 1 if no card present */ #define KN230_WEAR_OPTION_FALSE KN230_WEAR_OPTIONMASK #define KN230_WEAR_OPTION_TRUE 0 #define KN230_WEAR_SECUREMASK 0x00000002 /* "1": system is insecure */ #define KN230_WEAR_INSECURE KN230_WEAR_SECUREMASK #define KN230_WEAR_SECURE 0 /* * various leftover stuff.... */ /* * Option ID register. Indicates whether options are present. */ #define KN230_SYS_OID 0x1f00020c /* option slot ID register */ #define KN230_OID_MASK 0x000000ff /* ID number mask */ #define KN230_ERRCNT_MASK 0x0000ff00 /* hardware failure count */ #define KN230_SYS_PASSWD 0x1f000244 /* password location */ /* * NVRAM state defintions. * Used under Ultrix for PrestoServe. */ #define KN230_SYS_NVRAM_DIAG 0x1f000300 /* NVRAM diagnostic register */ #define KN230_NVRAM_PRESENT 0x00000001 #define KN230_NVRAM_TESTFAIL_RO 0x00000002 #define KN230_NVRAM_TESTFAIL_RW 0x00000004 #define KN230_NVRAM_FAILURE 0x00000008 /* ran out of power anyway? */ #define KN230_NVRAM_SIZEMASK 0x000000f0 #define KN230_SYS_NVRAM_ADDR 0x1f000304 /* holds addr of NVRAM bank */ /* * NVRAM has separete control and status registers for each of * the two motherboard SIMM banks (even and odd), * located at offsets from the value at value at SYS_NVRAM_ADDR. */ # define KN230_SYS_NVRAM_EVENBNK_STATUS_OFFSET (0x200000) # define KN230_SYS_NVRAM_ODDBNK_STATUS_OFFSET (0x200000 +4) # define KN230_SYS_NVRAM_EVENBNK_CONTROL_OFFSET (-0x200000) # define KN230_SYS_NVRAM_ODDNK_STATUS_OFFSET (-0x200000+4) /* flags in nvram per-bank status register */ #define KN230_NVRAM_BATFAIL 0x00000001 /* battery failure */ #define KN230_NVRAM_BATKILL 0x00000002 /* battery kill */ /* * To enable the battery, write 0x00 to each nvram control reg. * To disable the battery, write the sequence * 0x01, 0x01, 0x00, 0x00, 0x01 * to both per-bank control registers (do banks in parallel, not in sequence). */ #endif /* DEC_5100_H */ gxemul-0.6.1/src/include/thirdparty/m8820x.h000644 001750 001750 00000017402 13402411502 020754 0ustar00debugdebug000000 000000 /* $OpenBSD: m8820x.h,v 1.7 2006/05/06 16:59:26 miod Exp $ */ /* * Copyright (c) 2004, Miodrag Vallat. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Mach Operating System * Copyright (c) 1993-1992 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ #ifndef __M88K_M8820X_H__ #define __M88K_M8820X_H__ /* * 8820x CMMU definitions */ /* CMMU registers */ #define CMMU_IDR (0x000 / 4) /* CMMU id register */ #define CMMU_SCR (0x004 / 4) /* system command register */ #define CMMU_SSR (0x008 / 4) /* system status register */ #define CMMU_SAR (0x00c / 4) /* system address register */ #define CMMU_SCTR (0x104 / 4) /* system control register */ #define CMMU_PFSR (0x108 / 4) /* P bus fault status register */ #define CMMU_PFAR (0x10c / 4) /* P bus fault address register */ #define CMMU_SAPR (0x200 / 4) /* supervisor area pointer register */ #define CMMU_UAPR (0x204 / 4) /* user area pointer register */ #define CMMU_BWP0 (0x400 / 4) /* block ATC writer port 0 */ #define CMMU_BWP1 (0x404 / 4) /* block ATC writer port 1 */ #define CMMU_BWP2 (0x408 / 4) /* block ATC writer port 2 */ #define CMMU_BWP3 (0x40c / 4) /* block ATC writer port 3 */ #define CMMU_BWP4 (0x410 / 4) /* block ATC writer port 4 */ #define CMMU_BWP5 (0x414 / 4) /* block ATC writer port 5 */ #define CMMU_BWP6 (0x418 / 4) /* block ATC writer port 6 */ #define CMMU_BWP7 (0x41c / 4) /* block ATC writer port 7 */ #define CMMU_BWP(n) (CMMU_BWP0 + (n)) #define CMMU_CDP0 (0x800 / 4) /* cache data port 0 */ #define CMMU_CDP1 (0x804 / 4) /* cache data port 1 */ #define CMMU_CDP2 (0x808 / 4) /* cache data port 2 */ #define CMMU_CDP3 (0x80c / 4) /* cache data port 3 */ #define CMMU_CTP0 (0x840 / 4) /* cache tag port 0 */ #define CMMU_CTP1 (0x844 / 4) /* cache tag port 1 */ #define CMMU_CTP2 (0x848 / 4) /* cache tag port 2 */ #define CMMU_CTP3 (0x84c / 4) /* cache tag port 3 */ #define CMMU_CSSP0 (0x880 / 4) /* cache set status register */ #define CMMU_CSSP(n) ((0x880 + (n * 0x10)) / 4) /* the following only exist on 88204 */ #define CMMU_CSSP1 (0x890 / 4) /* cache set status register */ #define CMMU_CSSP2 (0x8a0 / 4) /* cache set status register */ #define CMMU_CSSP3 (0x8b0 / 4) /* cache set status register */ /* system commands */ #define CMMU_FLUSH_CACHE_INV_LINE 0x14 /* data cache invalidate */ #define CMMU_FLUSH_CACHE_INV_PAGE 0x15 #define CMMU_FLUSH_CACHE_INV_SEGMENT 0x16 #define CMMU_FLUSH_CACHE_INV_ALL 0x17 #define CMMU_FLUSH_CACHE_CB_LINE 0x18 /* data cache copyback */ #define CMMU_FLUSH_CACHE_CB_PAGE 0x19 #define CMMU_FLUSH_CACHE_CB_SEGMENT 0x1a #define CMMU_FLUSH_CACHE_CB_ALL 0x1b #define CMMU_FLUSH_CACHE_CBI_LINE 0x1c /* copyback and invalidate */ #define CMMU_FLUSH_CACHE_CBI_PAGE 0x1d #define CMMU_FLUSH_CACHE_CBI_SEGMENT 0x1e #define CMMU_FLUSH_CACHE_CBI_ALL 0x1f #define CMMU_PROBE_USER 0x20 /* probe user address */ #define CMMU_PROBE_SUPER 0x24 /* probe supervisor address */ #define CMMU_FLUSH_USER_LINE 0x30 /* flush PATC */ #define CMMU_FLUSH_USER_PAGE 0x31 #define CMMU_FLUSH_USER_SEGMENT 0x32 #define CMMU_FLUSH_USER_ALL 0x33 #define CMMU_FLUSH_SUPER_LINE 0x34 #define CMMU_FLUSH_SUPER_PAGE 0x35 #define CMMU_FLUSH_SUPER_SEGMENT 0x36 #define CMMU_FLUSH_SUPER_ALL 0x37 /* system control values */ #define CMMU_SCTR_PE 0x00008000 /* parity enable */ #define CMMU_SCTR_SE 0x00004000 /* snoop enable */ #define CMMU_SCTR_PR 0x00002000 /* priority arbitration */ /* P bus fault status */ #define CMMU_PFSR_FAULT(pfsr) (((pfsr) >> 16) & 0x07) #define CMMU_PFSR_SUCCESS 0 /* no fault */ #define CMMU_PFSR_BERROR 3 /* bus error */ #define CMMU_PFSR_SFAULT 4 /* segment fault */ #define CMMU_PFSR_PFAULT 5 /* page fault */ #define CMMU_PFSR_SUPER 6 /* supervisor violation */ #define CMMU_PFSR_WRITE 7 /* writer violation */ /* CSSP values */ #define CMMU_CSSP_L5 0x20000000 #define CMMU_CSSP_L4 0x10000000 #define CMMU_CSSP_L3 0x08000000 #define CMMU_CSSP_L2 0x04000000 #define CMMU_CSSP_L1 0x02000000 #define CMMU_CSSP_L0 0x01000000 #define CMMU_CSSP_D3 0x00800000 #define CMMU_CSSP_D2 0x00400000 #define CMMU_CSSP_D1 0x00200000 #define CMMU_CSSP_D0 0x00100000 #define CMMU_CSSP_VV(n,v) (((v) & 0x03) << (12 + 2 * (n))) #define CMMU_VV_EXCLUSIVE 0x00 #define CMMU_VV_MODIFIED 0x01 #define CMMU_VV_SHARED 0x02 #define CMMU_VV_INVALID 0x03 /* IDR values */ #define CMMU_ID(idr) ((idr) >> 24) #define CMMU_TYPE(idr) (((idr) >> 21) & 0x07) #define CMMU_VERSION(idr) (((idr) >> 16) & 0x1f) #define M88200_ID 5 #define M88204_ID 6 /* SSR values */ #define CMMU_SSR_CE 0x00008000 /* copyback error */ #define CMMU_SSR_BE 0x00004000 /* bus error */ #define CMMU_SSR_SO 0x00000100 #define CMMU_SSR_M 0x00000010 #define CMMU_SSR_U 0x00000008 #define CMMU_SSR_PROT 0x00000004 #define CMMU_SSR_BH 0x00000002 /* probe BATC hit */ #define CMMU_SSR_V 0x00000001 /* * Cache line information */ #define MC88200_CACHE_SHIFT 4 #define MC88200_CACHE_LINE (1 << MC88200_CACHE_SHIFT) /* * Hardwired BATC information */ #define BATC8 0xfff7ffb5 #define BATC9 0xfffffff5 #define BATC8_VA 0xfff00000 #define BATC9_VA 0xfff80000 #define NBSG (1 << (PDT_BITS + PG_BITS)) /* segment size */ #define INST_CMMU 0x00 /* even number */ #define DATA_CMMU 0x01 /* odd number */ #define CMMU_MODE(num) ((num) & 1) #define MAX_CMMUS 8 /* maximum cmmus on the board */ #if 0 #ifndef _LOCORE /* * CMMU kernel information */ struct m8820x_cmmu { volatile u_int32_t *cmmu_regs; /* CMMU "base" area */ #ifdef M88200_HAS_SPLIT_ADDRESS vaddr_t cmmu_addr; /* address range */ vaddr_t cmmu_addr_mask; /* address mask */ #endif }; extern struct m8820x_cmmu m8820x_cmmu[MAX_CMMUS]; extern u_int cmmu_shift; extern u_int max_cmmus; void m8820x_setup_board_config(void); cpuid_t m8820x_cpu_number(void); #endif /* _LOCORE */ #endif #endif /* __M88K_M8820X_H__ */ gxemul-0.6.1/src/include/thirdparty/adb_viareg.h000644 001750 001750 00000016670 13402411502 022077 0ustar00debugdebug000000 000000 /* GXemul: $Id: adb_viareg.h,v 1.1 2005-11-29 05:25:29 debug Exp $ */ /* $NetBSD: viareg.h,v 1.4 2001/06/19 12:02:56 simonb Exp $ */ #ifndef ADB_VIAREG_H #define ADB_VIAREG_H /*- * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, * Michael L. Finch, Bradley A. Grantham, and * Lawrence A. Kesteloot * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Alice Group. * 4. The names of the Alice Group or any of its members may not be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* Prototype VIA control definitions 06/04/92,22:33:57 BG Let's see what I can do. */ /* VIA1 data register A */ #define DA1I_vSCCWrReq 0x80 #define DA1O_vPage2 0x40 #define DA1I_CPU_ID1 0x40 #define DA1O_vHeadSel 0x20 #define DA1O_vOverlay 0x10 #define DA1O_vSync 0x08 #define DA1O_RESERVED2 0x04 #define DA1O_RESERVED1 0x02 #define DA1O_RESERVED0 0x01 /* VIA1 data register B */ #define DB1I_Par_Err 0x80 #define DB1O_vSndEnb 0x80 #define DB1O_Par_Enb 0x40 #define DB1O_vFDesk2 0x20 #define DB1O_vFDesk1 0x10 #define DB1I_vFDBInt 0x08 #define DB1O_rTCEnb 0x04 #define DB1O_rTCCLK 0x02 #define DB1O_rTCData 0x01 #define DB1I_rTCData 0x01 /* VIA2 data register A */ #define DA2O_v2Ram1 0x80 #define DA2O_v2Ram0 0x40 #define DA2I_v2IRQ0 0x40 #define DA2I_v2IRQE 0x20 #define DA2I_v2IRQD 0x10 #define DA2I_v2IRQC 0x08 #define DA2I_v2IRQB 0x04 #define DA2I_v2IRQA 0x02 #define DA2I_v2IRQ9 0x01 /* VIA2 data register B */ #define DB2O_v2VBL 0x80 #define DB2O_Par_Test 0x80 #define DB2I_v2SNDEXT 0x40 #define DB2I_v2TM0A 0x20 #define DB2I_v2TM1A 0x10 #define DB2I_vFC3 0x08 #define DB2O_vFC3 0x08 #define DB2O_v2PowerOff 0x04 #define DB2O_v2BusLk 0x02 #define DB2O_vCDis 0x01 #define DB2O_CEnable 0x01 /* * VIA1 interrupts */ #define VIA1_T1 6 #define VIA1_T2 5 #define VIA1_ADBCLK 4 #define VIA1_ADBDATA 3 #define VIA1_ADBRDY 2 #define VIA1_VBLNK 1 #define VIA1_ONESEC 0 /* VIA1 interrupt bits */ #define V1IF_IRQ 0x80 #define V1IF_T1 (1 << VIA1_T1) #define V1IF_T2 (1 << VIA1_T2) #define V1IF_ADBCLK (1 << VIA1_ADBCLK) #define V1IF_ADBDATA (1 << VIA1_ADBDATA) #define V1IF_ADBRDY (1 << VIA1_ADBRDY) #define V1IF_VBLNK (1 << VIA1_VBLNK) #define V1IF_ONESEC (1 << VIA1_ONESEC) /* * VIA2 interrupts */ #define VIA2_T1 6 #define VIA2_T2 5 #define VIA2_ASC 4 #define VIA2_SCSIIRQ 3 #define VIA2_EXPIRQ 2 #define VIA2_SLOTINT 1 #define VIA2_SCSIDRQ 0 /* VIA2 interrupt bits */ #define V2IF_IRQ 0x80 #define V2IF_T1 (1 << VIA2_T1) #define V2IF_T2 (1 << VIA2_T2) #define V2IF_ASC (1 << VIA2_ASC) #define V2IF_SCSIIRQ (1 << VIA2_SCSIIRQ) #define V2IF_EXPIRQ (1 << VIA2_EXPIRQ) #define V2IF_SLOTINT (1 << VIA2_SLOTINT) #define V2IF_SCSIDRQ (1 << VIA2_SCSIDRQ) #define VIA1_INTS (V1IF_T1 | V1IF_ADBRDY) #define VIA2_INTS (V2IF_T1 | V2IF_ASC | V2IF_SCSIIRQ | V2IF_SLOTINT | \ V2IF_SCSIDRQ) #define RBV_INTS (V2IF_T1 | V2IF_ASC | V2IF_SCSIIRQ | V2IF_SLOTINT | \ V2IF_SCSIDRQ | V1IF_ADBRDY) #define ACR_T1LATCH 0x40 #if 0 extern volatile unsigned char *Via1Base; #endif #define VIA1_addr Via1Base /* at PA 0x50f00000 */ #define VIA2OFF 1 /* VIA2 addr = VIA1_addr * 0x2000 */ #define RBVOFF 0x13 /* RBV addr = VIA1_addr * 0x13000 */ #define VIA1 0 #define VIA2 0 /* VIA interface registers */ #define vBufB 0x0000 /* register B */ #define vBufA 0x0200 /* register A */ #define vDirB 0x0400 /* data direction register */ #define vDirA 0x0600 /* data direction register */ #define vT1C 0x0800 #define vT1CH 0x0a00 #define vT1L 0x0c00 #define vT1LH 0x0e00 #define vT2C 0x1000 #define vT2CH 0x1200 #define vSR 0x1400 /* shift register */ #define vACR 0x1600 /* aux control register */ #define vPCR 0x1800 /* peripheral control register */ #define vIFR 0x1a00 /* interrupt flag register */ #define vIER 0x1c00 /* interrupt enable register */ /* RBV interface registers */ #define rBufB 0 /* register B */ #define rBufA 2 /* register A */ #define rIFR 0x3 /* interrupt flag register (writes?) */ #define rIER 0x13 /* interrupt enable register */ #define rMonitor 0x10 /* Monitor type */ #define rSlotInt 0x12 /* Slot interrupt */ /* RBV monitor type flags and masks */ #define RBVDepthMask 0x07 /* depth in bits */ #define RBVMonitorMask 0x38 /* Type numbers */ #define RBVOff 0x40 /* monitor turn off */ #define RBVMonIDNone 0x38 /* What RBV actually has for no video */ #define RBVMonIDOff 0x0 /* What rbv_vidstatus() returns for no video */ #define RBVMonID15BWP 0x08 /* BW portrait */ #define RBVMonIDRGB 0x10 /* color monitor */ #define RBVMonIDRGB15 0x28 /* 15 inch RGB */ #define RBVMonIDBW 0x30 /* No internal video */ #define via_reg(v, r) (*(Via1Base + (r))) #if 0 #include static __inline void via_reg_and(int, int, int); static __inline void via_reg_or(int, int, int); static __inline void via_reg_xor(int, int, int); static __inline void write_via_reg(int, int, int); static __inline int read_via_reg(int, int); static __inline void via_reg_and(ign, reg, val) int ign, reg, val; { volatile unsigned char *addr = Via1Base + reg; out8(addr, in8(addr) & val); } static __inline void via_reg_or(ign, reg, val) int ign, reg, val; { volatile unsigned char *addr = Via1Base + reg; out8(addr, in8(addr) | val); } static __inline void via_reg_xor(ign, reg, val) int ign, reg, val; { volatile unsigned char *addr = Via1Base + reg; out8(addr, in8(addr) ^ val); } static __inline int read_via_reg(ign, reg) int ign, reg; { volatile unsigned char *addr = Via1Base + reg; return in8(addr); } static __inline void write_via_reg(ign, reg, val) int ign, reg, val; { volatile unsigned char *addr = Via1Base + reg; out8(addr, val); } #define vDirA_ADBState 0x30 void via_init __P((void)); int rbv_vidstatus __P((void)); void via_shutdown __P((void)); void via_set_modem __P((int)); int add_nubus_intr __P((int, void (*) __P((void *, int)), void *)); void enable_nubus_intr __P((void)); void via1_register_irq __P((int, void (*)(void *), void *)); void via2_register_irq __P((int, void (*)(void *), void *)); extern void (*via1itab[7]) __P((void *)); extern void (*via2itab[7]) __P((void *)); #endif #endif /* ADB_VIAREG_H */ gxemul-0.6.1/src/include/thirdparty/sh4_rtcreg.h000644 001750 001750 00000007052 13402411502 022052 0ustar00debugdebug000000 000000 /* $NetBSD: rtcreg.h,v 1.9 2006/03/04 01:55:03 uwe Exp $ */ #ifndef SH4_RTCREG_H #define SH4_RTCREG_H /*- * Copyright (C) 1999 SAITOH Masanobu. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* #include */ /* * RTC */ #define SH3_R64CNT 0xfffffec0 #define SH3_RSECCNT 0xfffffec2 #define SH3_RMINCNT 0xfffffec4 #define SH3_RHRCNT 0xfffffec6 #define SH3_RWKCNT 0xfffffec8 #define SH3_RDAYCNT 0xfffffeca #define SH3_RMONCNT 0xfffffecc #define SH3_RYRCNT 0xfffffece #define SH3_RSECAR 0xfffffed0 #define SH3_RMINAR 0xfffffed2 #define SH3_RHRAR 0xfffffed4 #define SH3_RWKAR 0xfffffed6 #define SH3_RDAYAR 0xfffffed8 #define SH3_RMONAR 0xfffffeda #define SH3_RCR1 0xfffffedc #define SH3_RCR2 0xfffffede #define SH4_R64CNT 0xffc80000 #define SH4_RSECCNT 0xffc80004 #define SH4_RMINCNT 0xffc80008 #define SH4_RHRCNT 0xffc8000c #define SH4_RWKCNT 0xffc80010 #define SH4_RDAYCNT 0xffc80014 #define SH4_RMONCNT 0xffc80018 #define SH4_RYRCNT 0xffc8001c /* 16 bit */ #define SH4_RSECAR 0xffc80020 #define SH4_RMINAR 0xffc80024 #define SH4_RHRAR 0xffc80028 #define SH4_RWKAR 0xffc8002c #define SH4_RDAYAR 0xffc80030 #define SH4_RMONAR 0xffc80034 #define SH4_RCR1 0xffc80038 #define SH4_RCR2 0xffc8003c #define SH_RCR1_CF 0x80 #define SH_RCR1_CIE 0x10 #define SH_RCR1_AIE 0x08 #define SH_RCR1_AF 0x01 #define SH_RCR2_PEF 0x80 #define SH_RCR2_PES2 0x40 #define SH_RCR2_PES1 0x20 #define SH_RCR2_PES0 0x10 #define SH_RCR2_ENABLE 0x08 #define SH_RCR2_ADJ 0x04 #define SH_RCR2_RESET 0x02 #define SH_RCR2_START 0x01 #ifndef _LOCORE #if defined(SH3) && defined(SH4) extern uint32_t __sh_R64CNT; extern uint32_t __sh_RSECCNT; extern uint32_t __sh_RMINCNT; extern uint32_t __sh_RHRCNT; extern uint32_t __sh_RWKCNT; extern uint32_t __sh_RDAYCNT; extern uint32_t __sh_RMONCNT; extern uint32_t __sh_RYRCNT; extern uint32_t __sh_RSECAR; extern uint32_t __sh_RMINAR; extern uint32_t __sh_RHRAR; extern uint32_t __sh_RWKAR; extern uint32_t __sh_RDAYAR; extern uint32_t __sh_RMONAR; extern uint32_t __sh_RCR1; extern uint32_t __sh_RCR2; #endif /* SH3 && SH4 */ #endif /* !_LOCORE */ #endif /* SH4_RTCREG_H */ gxemul-0.6.1/src/include/thirdparty/alpha_rpb.h000644 001750 001750 00000045011 13402411502 021733 0ustar00debugdebug000000 000000 /* $NetBSD: rpb.h,v 1.39.18.1 2002/07/29 14:45:46 lukem Exp $ */ #include #include "misc.h" /* * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. * All rights reserved. * * Author: Keith Bostic, Chris G. Demetriou * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * From DEC 3000 300/400/500/600/700/800/900 System Programmer's Manual, * EK-D3SYS-PM.B01. */ /* * HWRPB (Hardware Restart Parameter Block). */ #define HWRPB_ADDR 0x10000000 /* virtual address, at boot */ /* GXemul: */ #define PROM_ENTRY_PADDR 0x10000 #define PROM_ARGSPACE_PADDR 0x12000 #define HWRPB_PADDR 0x14000 #define CTB_ADDR (HWRPB_ADDR + 0x1000) #define CRB_ADDR (HWRPB_ADDR + 0x1400) #define MEMDAT_ADDR (HWRPB_ADDR + 0x1800) #define PCS_ADDR (HWRPB_ADDR + 0x1c00) #ifndef ASSEMBLER struct rpb { u_int64_t rpb_phys; /* 0: HWRPB phys. address. */ char rpb_magic[8]; /* 8: "HWRPB" (in ASCII) */ u_int64_t rpb_version; /* 10 */ u_int64_t rpb_size; /* 18: HWRPB size in bytes */ u_int64_t rpb_primary_cpu_id; /* 20 */ u_int64_t rpb_page_size; /* 28: (8192) */ u_int32_t rpb_phys_addr_size; /* 30: physical address size */ u_int32_t rpb_extended_va_size; /* 34: extended VA size (4L) */ u_int64_t rpb_max_asn; /* 38: (16) */ char rpb_ssn[16]; /* 40: only first 10 valid */ #define ST_ADU 1 /* Alpha Demo. Unit (?) */ #define ST_DEC_4000 2 /* "Cobra" */ #define ST_DEC_7000 3 /* "Ruby" */ #define ST_DEC_3000_500 4 /* "Flamingo" family (TC) */ #define ST_DEC_2000_300 6 /* "Jensen" (EISA/ISA) */ #define ST_DEC_3000_300 7 /* "Pelican" (TC) */ #define ST_AVALON_A12 8 /* XXX Avalon Multicomputer */ #define ST_DEC_2100_A500 9 /* "Sable" */ #define ST_DEC_APXVME_64 10 /* "AXPvme" (VME) */ #define ST_DEC_AXPPCI_33 11 /* "NoName" (PCI/ISA) */ #define ST_DEC_21000 12 /* "TurboLaser" (PCI/EISA) */ #define ST_DEC_2100_A50 13 /* "Avanti" (PCI/ISA) */ #define ST_DEC_MUSTANG 14 /* "Mustang" */ #define ST_DEC_KN20AA 15 /* kn20aa (PCI/EISA) */ #define ST_DEC_1000 17 /* "Mikasa" (PCI/EISA) */ #define ST_EB66 19 /* EB66 (PCI/ISA?) */ #define ST_EB64P 20 /* EB64+ (PCI/ISA?) */ #define ST_ALPHABOOK1 21 /* Alphabook1 */ #define ST_DEC_4100 22 /* "Rawhide" (PCI/EISA) */ #define ST_DEC_EV45_PBP 23 /* "Lego" K2 Passive SBC */ #define ST_DEC_2100A_A500 24 /* "Lynx" */ #define ST_EB164 26 /* EB164 (PCI/ISA) */ #define ST_DEC_1000A 27 /* "Noritake" (PCI/EISA)*/ #define ST_DEC_ALPHAVME_224 28 /* "Cortex" */ #define ST_DEC_550 30 /* "Miata" (PCI/ISA) */ #define ST_DEC_EV56_PBP 32 /* "Takara" */ #define ST_DEC_ALPHAVME_320 33 /* "Yukon" (VME) */ #define ST_DEC_6600 34 /* EV6-Tsunami based systems */ #define ST_DEC_WILDFIRE 35 /* "Wildfire" */ #define ST_DEC_CUSCO 36 /* "CUSCO" */ #define ST_DEC_EIGER 37 /* "Eiger" */ #define ST_DEC_TITAN 38 /* "Titan" */ /* Alpha Processor, Inc. systypes */ #define ST_API_NAUTILUS 201 /* EV6-AMD 751 UP1000 */ u_int64_t rpb_type; /* 50: */ #define SV_MPCAP 0x00000001 /* multiprocessor capable */ #define SV_CONSOLE 0x0000001e /* console hardware mask */ #define SV_CONSOLE_DETACHED 0x00000002 #define SV_CONSOLE_EMBEDDED 0x00000004 #define SV_POWERFAIL 0x000000e0 /* powerfail mask */ #define SV_PF_UNITED 0x00000020 #define SV_PF_SEPARATE 0x00000040 #define SV_PF_BBACKUP 0x00000060 #define SV_PF_ACTION 0x00000100 /* powerfail restart */ #define SV_GRAPHICS 0x00000200 /* graphic engine present */ #define SV_ST_MASK 0x0000fc00 /* system type mask */ #define SV_ST_RESERVED 0x00000000 /* RESERVED */ /* * System types for the DEC 3000/500 (Flamingo) Family */ #define SV_ST_SANDPIPER 0x00000400 /* Sandpiper; 3000/400 */ #define SV_ST_FLAMINGO 0x00000800 /* Flamingo; 3000/500 */ #define SV_ST_HOTPINK 0x00000c00 /* "Hot Pink"; 3000/500X */ #define SV_ST_FLAMINGOPLUS 0x00001000 /* Flamingo+; 3000/800 */ #define SV_ST_ULTRA 0x00001400 /* "Ultra", aka Flamingo+ */ #define SV_ST_SANDPLUS 0x00001800 /* Sandpiper+; 3000/600 */ #define SV_ST_SANDPIPER45 0x00001c00 /* Sandpiper45; 3000/700 */ #define SV_ST_FLAMINGO45 0x00002000 /* Flamingo45; 3000/900 */ /* * System types for ??? */ #define SV_ST_SABLE 0x00000400 /* Sable (???) */ /* * System types for the DEC 3000/300 (Pelican) Family */ #define SV_ST_PELICAN 0x00000000 /* Pelican; 3000/300 */ #define SV_ST_PELICA 0x00000400 /* Pelica; 3000/300L */ #define SV_ST_PELICANPLUS 0x00000800 /* Pelican+; 3000/300X */ #define SV_ST_PELICAPLUS 0x00000c00 /* Pelica+; 3000/300LX */ /* * System types for the AlphaStation Family */ #define SV_ST_AVANTI 0x00000000 /* Avanti; 400 4/233 */ #define SV_ST_MUSTANG2_4_166 0x00000800 /* Mustang II; 200 4/166 */ #define SV_ST_MUSTANG2_4_233 0x00001000 /* Mustang II; 200 4/233 */ #define SV_ST_AVANTI_XXX 0x00001400 /* also Avanti; 400 4/233 */ #define SV_ST_AVANTI_4_266 0x00002000 #define SV_ST_MUSTANG2_4_100 0x00002400 /* Mustang II; 200 4/100 */ #define SV_ST_AVANTI_4_233 0x0000a800 /* AlphaStation 255/233 */ #define SV_ST_KN20AA 0x00000400 /* AlphaStation 500/600 */ /* * System types for the AXPvme Family */ #define SV_ST_AXPVME_64 0x00000000 /* 21068, 64MHz */ #define SV_ST_AXPVME_160 0x00000400 /* 21066, 160MHz */ #define SV_ST_AXPVME_100 0x00000c00 /* 21066A, 99MHz */ #define SV_ST_AXPVME_230 0x00001000 /* 21066A, 231MHz */ #define SV_ST_AXPVME_66 0x00001400 /* 21066A, 66MHz */ #define SV_ST_AXPVME_166 0x00001800 /* 21066A, 165MHz */ #define SV_ST_AXPVME_264 0x00001c00 /* 21066A, 264MHz */ /* * System types for the EB164 Family */ #define SV_ST_EB164_266 0x00000400 /* EB164, 266MHz */ #define SV_ST_EB164_300 0x00000800 /* EB164, 300MHz */ #define SV_ST_ALPHAPC164_366 0x00000c00 /* AlphaPC164, 366MHz */ #define SV_ST_ALPHAPC164_400 0x00001000 /* AlphaPC164, 400MHz */ #define SV_ST_ALPHAPC164_433 0x00001400 /* AlphaPC164, 433MHz */ #define SV_ST_ALPHAPC164_466 0x00001800 /* AlphaPC164, 466MHz */ #define SV_ST_ALPHAPC164_500 0x00001c00 /* AlphaPC164, 500MHz */ #define SV_ST_ALPHAPC164LX_400 0x00002000 /* AlphaPC164LX, 400MHz */ #define SV_ST_ALPHAPC164LX_466 0x00002400 /* AlphaPC164LX, 466MHz */ #define SV_ST_ALPHAPC164LX_533 0x00002800 /* AlphaPC164LX, 533MHz */ #define SV_ST_ALPHAPC164LX_600 0x00002c00 /* AlphaPC164LX, 600MHz */ #define SV_ST_ALPHAPC164SX_400 0x00003000 /* AlphaPC164SX, 400MHz */ #define SV_ST_ALPHAPC164SX_466 0x00003400 /* AlphaPC164SX, 433MHz */ #define SV_ST_ALPHAPC164SX_533 0x00003800 /* AlphaPC164SX, 533MHz */ #define SV_ST_ALPHAPC164SX_600 0x00003c00 /* AlphaPC164SX, 600MHz */ /* * System types for the Digital Personal Workstation (Miata) Family * XXX These are not very complete! */ #define SV_ST_MIATA_1_5 0x00004c00 /* Miata 1.5 */ u_int64_t rpb_variation; /* 58 */ char rpb_revision[8]; /* 60; only first 4 valid */ u_int64_t rpb_intr_freq; /* 68; scaled by 4096 */ u_int64_t rpb_cc_freq; /* 70: cycle cntr frequency */ u_int64_t rpb_vptb; /* 78: */ u_int64_t rpb_reserved_arch; /* 80: */ u_int64_t rpb_tbhint_off; /* 88: */ u_int64_t rpb_pcs_cnt; /* 90: */ u_int64_t rpb_pcs_size; /* 98; pcs size in bytes */ u_int64_t rpb_pcs_off; /* A0: offset to pcs info */ u_int64_t rpb_ctb_cnt; /* A8: console terminal */ u_int64_t rpb_ctb_size; /* B0: ctb size in bytes */ u_int64_t rpb_ctb_off; /* B8: offset to ctb */ u_int64_t rpb_crb_off; /* C0: offset to crb */ u_int64_t rpb_memdat_off; /* C8: memory data offset */ u_int64_t rpb_condat_off; /* D0: config data offset */ u_int64_t rpb_fru_off; /* D8: FRU table offset */ u_int64_t rpb_save_term; /* E0: terminal save */ u_int64_t rpb_save_term_val; /* E8: */ u_int64_t rpb_rest_term; /* F0: terminal restore */ u_int64_t rpb_rest_term_val; /* F8: */ u_int64_t rpb_restart; /* 100: restart */ u_int64_t rpb_restart_val; /* 108: */ u_int64_t rpb_reserve_os; /* 110: */ u_int64_t rpb_reserve_hw; /* 118: */ u_int64_t rpb_checksum; /* 120: HWRPB checksum */ u_int64_t rpb_rxrdy; /* 128: receive ready */ u_int64_t rpb_txrdy; /* 130: transmit ready */ u_int64_t rpb_dsrdb_off; /* 138: HWRPB + DSRDB offset */ u_int64_t rpb_tbhint[8]; /* 140: TB hint block */ }; #define LOCATE_PCS(h,cpunumber) ((struct pcs *) \ ((char *)(h) + (h)->rpb_pcs_off + ((cpunumber) * (h)->rpb_pcs_size))) /* * PCS: Per-CPU information. */ struct pcs { u_int8_t pcs_hwpcb[128]; /* 0: PAL dependent */ #define PCS_BIP 0x000001 /* boot in progress */ #define PCS_RC 0x000002 /* restart possible */ #define PCS_PA 0x000004 /* processor available */ #define PCS_PP 0x000008 /* processor present */ #define PCS_OH 0x000010 /* user halted */ #define PCS_CV 0x000020 /* context valid */ #define PCS_PV 0x000040 /* PALcode valid */ #define PCS_PMV 0x000080 /* PALcode memory valid */ #define PCS_PL 0x000100 /* PALcode loaded */ #define PCS_HALT_REQ 0xff0000 /* halt request mask */ #define PCS_HALT_DEFAULT 0x000000 #define PCS_HALT_SAVE_EXIT 0x010000 #define PCS_HALT_COLD_BOOT 0x020000 #define PCS_HALT_WARM_BOOT 0x030000 #define PCS_HALT_STAY_HALTED 0x040000 #define PCS_mbz 0xffffffffff000000 /* 24:63 -- must be zero */ u_int64_t pcs_flags; /* 80: */ u_int64_t pcs_pal_memsize; /* 88: PAL memory size */ u_int64_t pcs_pal_scrsize; /* 90: PAL scratch size */ u_int64_t pcs_pal_memaddr; /* 98: PAL memory addr */ u_int64_t pcs_pal_scraddr; /* A0: PAL scratch addr */ struct { int /* TODO/NOTE: should be uint64_t */ minorrev : 8, /* alphabetic char 'a' - 'z' */ majorrev : 8, /* alphabetic char 'a' - 'z' */ #define PAL_TYPE_STANDARD 0 #define PAL_TYPE_VMS 1 #define PAL_TYPE_OSF1 2 pal_type : 8, /* PALcode type: * 0 == standard * 1 == OpenVMS * 2 == OSF/1 * 3-127 DIGITAL reserv. * 128-255 non-DIGITAL reserv. */ sbz1 : 8, compatibility : 16, /* Compatibility revision */ proc_cnt : 16; /* Processor count */ } pcs_pal_rev; /* A8: */ #define pcs_minorrev pcs_pal_rev.minorrev #define pcs_majorrev pcs_pal_rev.majorrev #define pcs_pal_type pcs_pal_rev.pal_type #define pcs_compatibility pcs_pal_rev.compatibility #define pcs_proc_cnt pcs_pal_rev.proc_cnt u_int64_t pcs_proc_type; /* B0: processor type */ #define PCS_PROC_EV3 1 /* EV3 */ #define PCS_PROC_EV4 2 /* EV4: 21064 */ #define PCS_PROC_SIMULATION 3 /* Simulation */ #define PCS_PROC_LCA4 4 /* LCA4: 2106[68] */ #define PCS_PROC_EV5 5 /* EV5: 21164 */ #define PCS_PROC_EV45 6 /* EV45: 21064A */ #define PCS_PROC_EV56 7 /* EV56: 21164A */ #define PCS_PROC_EV6 8 /* EV6: 21264 */ #define PCS_PROC_PCA56 9 /* PCA56: 21164PC */ #define PCS_PROC_PCA57 10 /* PCA57: 21164?? */ #define PCS_PROC_EV67 11 /* EV67: 21246A */ #define PCS_PROC_EV68CB 12 /* EV68CB: 21264C */ #define PCS_PROC_EV68AL 13 /* EV68AL: 21264B */ #define PCS_PROC_EV68CX 14 /* EV68CX: 21264D */ #define PCS_CPU_MAJORTYPE(p) ((p)->pcs_proc_type & 0xffffffff) #define PCS_CPU_MINORTYPE(p) ((p)->pcs_proc_type >> 32) /* Minor number interpretation is processor specific. See cpu.c. */ u_int64_t pcs_proc_var; /* B8: processor variation. */ #define PCS_VAR_VAXFP 0x0000000000000001 /* VAX FP support */ #define PCS_VAR_IEEEFP 0x0000000000000002 /* IEEE FP support */ #define PCS_VAR_PE 0x0000000000000004 /* Primary Eligible */ #define PCS_VAR_RESERVED 0xfffffffffffffff8 /* Reserved */ char pcs_proc_revision[8]; /* C0: only first 4 valid */ char pcs_proc_sn[16]; /* C8: only first 10 valid */ u_int64_t pcs_machcheck; /* D8: mach chk phys addr. */ u_int64_t pcs_machcheck_len; /* E0: length in bytes */ u_int64_t pcs_halt_pcbb; /* E8: phys addr of halt PCB */ u_int64_t pcs_halt_pc; /* F0: halt PC */ u_int64_t pcs_halt_ps; /* F8: halt PS */ u_int64_t pcs_halt_r25; /* 100: halt argument list */ u_int64_t pcs_halt_r26; /* 108: halt return addr list */ u_int64_t pcs_halt_r27; /* 110: halt procedure value */ #define PCS_HALT_RESERVED 0 #define PCS_HALT_POWERUP 1 #define PCS_HALT_CONSOLE_HALT 2 #define PCS_HALT_CONSOLE_CRASH 3 #define PCS_HALT_KERNEL_MODE 4 #define PCS_HALT_KERNEL_STACK_INVALID 5 #define PCS_HALT_DOUBLE_ERROR_ABORT 6 #define PCS_HALT_SCBB 7 #define PCS_HALT_PTBR 8 /* 9-FF: reserved */ u_int64_t pcs_halt_reason; /* 118: */ u_int64_t pcs_reserved_soft; /* 120: preserved software */ struct { /* 128: inter-console buffers */ u_int iccb_rxlen; u_int iccb_txlen; char iccb_rxbuf[80]; char iccb_txbuf[80]; } pcs_iccb; #define PALvar_reserved 0 #define PALvar_OpenVMS 1 #define PALvar_OSF1 2 u_int64_t pcs_palrevisions[16]; /* 1D0: PALcode revisions */ u_int64_t pcs_reserved_arch[6]; /* 250: reserved arch */ }; /* * CTB: Console Terminal Block */ struct ctb { u_int64_t ctb_type; /* 0: CTB type */ u_int64_t ctb_unit; /* 8: */ u_int64_t ctb_reserved; /* 16: */ u_int64_t ctb_len; /* 24: bytes of info */ u_int64_t ctb_ipl; /* 32: console ipl level */ u_int64_t ctb_tintr_vec; /* 40: transmit vec (0x800) */ u_int64_t ctb_rintr_vec; /* 48: receive vec (0x800) */ #define CTB_NONE 0x00 /* no console present */ #define CTB_SERVICE 0x01 /* service processor */ #define CTB_PRINTERPORT 0x02 /* printer port on the SCC */ #define CTB_GRAPHICS 0x03 /* graphics device */ #define CTB_TYPE4 0x04 /* type 4 CTB */ #define CTB_NETWORK 0xC0 /* network device */ u_int64_t ctb_term_type; /* 56: terminal type */ u_int64_t ctb_keybd_type; /* 64: keyboard nationality */ u_int64_t ctb_keybd_trans; /* 72: trans. table addr */ u_int64_t ctb_keybd_map; /* 80: map table addr */ u_int64_t ctb_keybd_state; /* 88: keyboard flags */ u_int64_t ctb_keybd_last; /* 96: last key entered */ u_int64_t ctb_font_us; /* 104: US font table addr */ u_int64_t ctb_font_mcs; /* 112: MCS font table addr */ u_int64_t ctb_font_width; /* 120: font width, height */ u_int64_t ctb_font_height; /* 128: in pixels */ u_int64_t ctb_mon_width; /* 136: monitor width, height */ u_int64_t ctb_mon_height; /* 144: in pixels */ u_int64_t ctb_dpi; /* 152: monitor dots per inch */ u_int64_t ctb_planes; /* 160: # of planes */ u_int64_t ctb_cur_width; /* 168: cursor width, height */ u_int64_t ctb_cur_height; /* 176: in pixels */ u_int64_t ctb_head_cnt; /* 184: # of heads */ u_int64_t ctb_opwindow; /* 192: opwindow on screen */ u_int64_t ctb_head_offset; /* 200: offset to head info */ u_int64_t ctb_putchar; /* 208: output char to TURBO */ u_int64_t ctb_io_state; /* 216: I/O flags */ u_int64_t ctb_listen_state; /* 224: listener flags */ u_int64_t ctb_xaddr; /* 232: extended info addr */ u_int64_t ctb_turboslot; /* 248: TURBOchannel slot # */ u_int64_t ctb_server_off; /* 256: offset to server info */ u_int64_t ctb_line_off; /* 264: line parameter offset */ u_int8_t ctb_csd; /* 272: console specific data */ }; struct ctb_tt { u_int64_t ctb_type; /* 0: CTB type */ u_int64_t ctb_unit; /* 8: console unit */ u_int64_t ctb_reserved; /* 16: reserved */ u_int64_t ctb_length; /* 24: length */ u_int64_t ctb_csr; /* 32: address */ u_int64_t ctb_tivec; /* 40: Tx intr vector */ u_int64_t ctb_rivec; /* 48: Rx intr vector */ u_int64_t ctb_baud; /* 56: baud rate */ u_int64_t ctb_put_sts; /* 64: PUTS status */ u_int64_t ctb_get_sts; /* 72: GETS status */ u_int64_t ctb_reserved0; /* 80: reserved */ }; /* * Format of the Console Terminal Block Type 4 `turboslot' field: * * 63 40 39 32 31 24 23 16 15 8 7 0 * | reserved | channel | hose | bus type | bus | slot| */ #define CTB_TURBOSLOT_CHANNEL(x) (((x) >> 32) & 0xff) #define CTB_TURBOSLOT_HOSE(x) (((x) >> 24) & 0xff) #define CTB_TURBOSLOT_TYPE(x) (((x) >> 16) & 0xff) #define CTB_TURBOSLOT_BUS(x) (((x) >> 8) & 0xff) #define CTB_TURBOSLOT_SLOT(x) ((x) & 0xff) #define CTB_TURBOSLOT_TYPE_TC 0 /* TURBOchannel */ #define CTB_TURBOSLOT_TYPE_ISA 1 /* ISA */ #define CTB_TURBOSLOT_TYPE_EISA 2 /* EISA */ #define CTB_TURBOSLOT_TYPE_PCI 3 /* PCI */ /* * CRD: Console Routine Descriptor */ struct crd { int64_t descriptor; u_int64_t entry_va; }; /* * CRB: Console Routine Block */ struct crb { /* struct crd * */ u_int64_t crb_v_dispatch; /* 0: virtual dispatch addr */ u_int64_t crb_p_dispatch; /* 8: phys dispatch addr */ /* struct crd * */ u_int64_t crb_v_fixup; /* 10: virtual fixup addr */ u_int64_t crb_p_fixup; /* 18: phys fixup addr */ u_int64_t crb_map_cnt; /* 20: phys/virt map entries */ u_int64_t crb_page_cnt; /* 28: pages to be mapped */ }; /* * MDDT: Memory Data Descriptor Table */ struct mddt_cluster { u_int64_t mddt_pfn; /* 0: starting PFN */ u_int64_t mddt_pg_cnt; /* 8: 8KB page count */ u_int64_t mddt_pg_test; /* 10: tested page count */ u_int64_t mddt_v_bitaddr; /* 18: bitmap virt addr */ u_int64_t mddt_p_bitaddr; /* 20: bitmap phys addr */ int64_t mddt_bit_cksum; /* 28: bitmap checksum */ #define MDDT_NONVOLATILE 0x10 /* cluster is non-volatile */ #define MDDT_PALCODE 0x01 /* console and PAL only */ #define MDDT_SYSTEM 0x00 /* system software only */ #define MDDT_mbz 0xfffffffffffffffc /* 2:63 -- must be zero */ int64_t mddt_usage; /* 30: bitmap permissions */ }; struct mddt { int64_t mddt_cksum; /* 0: 7-N checksum */ u_int64_t mddt_physaddr; /* 8: bank config addr * IMPLEMENTATION SPECIFIC */ u_int64_t mddt_cluster_cnt; /* 10: memory cluster count */ struct mddt_cluster mddt_clusters[2]; /* variable length array */ }; /* * DSR: Dynamic System Recognition. We're interested in the sysname * offset. The data pointed to by sysname is: * * [8 bytes: length of system name][N bytes: system name string] * * The system name string is NUL-terminated. */ struct dsrdb { int64_t dsr_smm; /* 0: SMM number */ u_int64_t dsr_lurt_off; /* 8: LURT table offset */ u_int64_t dsr_sysname_off; /* 16: offset to sysname */ }; /* * The DSR appeared in version 5 of the HWRPB. */ #define HWRPB_DSRDB_MINVERS 5 #ifdef _KERNEL extern int cputype; extern struct rpb *hwrpb; #endif #endif /* ASSEMBLER */ gxemul-0.6.1/src/include/thirdparty/exec_bout.h000644 001750 001750 00000022463 13402411502 021766 0ustar00debugdebug000000 000000 /* Imported into GXmeul 2018-04-21. Some fields renamed and data types changed. */ #ifndef EXEC_B_OUT_H #define EXEC_B_OUT_H /*(c****************************************************************************** * * Copyright (c) 1990, 1991, 1992, 1993 Intel Corporation * * Intel hereby grants you permission to copy, modify, and distribute this * software and its documentation. Intel grants this permission provided * that the above copyright notice appears in all copies and that both the * copyright notice and this permission notice appear in supporting * documentation. In addition, Intel grants this permission provided that * you prominently mark as "not part of the original" any modifications * made to this software or documentation, and that the name of Intel * Corporation not be used in advertising or publicity pertaining to * distribution of the software or the documentation without specific, * written prior permission. * * Intel Corporation provides this AS IS, WITHOUT ANY WARRANTY, EXPRESS OR * IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE. Intel makes no guarantee or * representations regarding the use of, or the results of the use of, * the software and documentation in terms of correctness, accuracy, * reliability, currentness, or otherwise; and you rely on the software, * documentation and results solely at your own risk. * * IN NO EVENT SHALL INTEL BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS, * LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES * OF ANY KIND. IN NO EVENT SHALL INTEL'S TOTAL LIABILITY EXCEED THE SUM * PAID TO INTEL FOR THE PRODUCT LICENSED HEREUNDER. * *****************************************************************************c)*/ /* * This file, a modified version of 'a.out.h', describes the 'b.out' format * produced by GNU tools modified to support the i960 processor. * * All i960 development is done in a CROSS-DEVELOPMENT environment. I.e., * object code is generated on, and executed under the direction of a symbolic * debugger running on, a host system. We do not want to be subject to the * vagaries of which host it is or whether it supports COFF or a.out format, * or anything else. We DO want to: * * o always generate the same format object files, regardless of host. * * o provide support for additional linker features that the normal * a.out.h header can't accommodate. * * As for byte-ordering, the following rules apply: * * o Text and data contents (which are actually downloaded to the target) * is always in i960 (little-endian) order. * * o Other binary numbers in the file (in the header, symbols, relocation * directives) are either all big-endian or all little-endian. It used * to be dependent on the host on which the file was created, but we * are moving toward a tool set that accepts either order on input and * always generates little-endian output. * * o The downloader (comm960 or gdb960) copies a b.out file to a tmp file * and converts it into a stripped little-endian COFF file before * shipping it off to the NINDY monitor in the target systems. If you * use a different downloader and want to send a b.out file to NINDY, * you should perform the conversion explicitly -- see the objcopy * utility. */ #define BOUT_BMAGIC 0415 /* We don't accept the following (see N_BADMAG macro). * They're just here so GNU code will compile. */ #define BOUT_OMAGIC 0407 /* old impure format */ #define BOUT_NMAGIC 0410 /* read-only text */ #define BOUT_ZMAGIC 0413 /* demand load format */ /* FILE HEADER * All 'lengths' are given as a number of bytes. * All 'alignments' are for relinkable files only; an alignment of * 'n' indicates the corresponding segment must begin at an * address that is a multiple of (2**n). */ struct bout_exec { /* Standard stuff */ uint32_t a_magic; /* Identifies this as a b.out file */ uint32_t a_text; /* Length of text */ uint32_t a_data; /* Length of data */ uint32_t a_bss; /* Length of runtime uninitialized data area */ uint32_t a_syms; /* Length of symbol table */ uint32_t a_entry; /* Runtime start address */ uint32_t a_trsize; /* Length of text relocation info */ uint32_t a_drsize; /* Length of data relocation info */ /* Added for i960 */ uint32_t a_tload; /* Text runtime load address */ uint32_t a_dload; /* Data runtime load address */ uint8_t a_talign; /* Alignment of text segment */ uint8_t a_dalign; /* Alignment of data segment */ uint8_t a_balign; /* Alignment of bss segment */ uint8_t a_ccinfo; /* See below */ }; /* The field a_ccinfo contains the magic value N_CCINFO iff cc_info data * (for 2-pass compiler optimization) is appended to the end of the object file. * * Since cc_info data is removed when a file is stripped, we can assume that * its presence implies the presence of a string table in the file, with the * cc_info block immediately following. * * The format/meaning of the cc_data block are known only to the compiler (and, * to a lesser extent, the linker) except for the first 4 bytes, which contain * the length of the block (including those 4 bytes). This length is stored in * a machine-independent format, and can be retrieved with the CI_U32_FM_BUF * macro in cc_info.h . */ #define N_MAGIC(x) ((x).a_magic) #define N_BADMAG(x) (((x).a_magic)!=BOUT_BMAGIC) #define N_TXTOFF(x) ( sizeof(struct exec) ) #define N_DATOFF(x) ( N_TXTOFF(x) + (x).a_text ) #define N_TROFF(x) ( N_DATOFF(x) + (x).a_data ) #define N_DROFF(x) ( N_TROFF(x) + (x).a_trsize ) #define N_SYMOFF(x) ( N_DROFF(x) + (x).a_drsize ) #define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms ) #define N_CCINFO ( 0x17 ) #define N_HAS_CCINFO(x) (((x).a_ccinfo)==N_CCINFO) /* A single entry in the symbol table */ struct nlist { union { char *n_name; struct nlist *n_next; long n_strx; /* Index into string table */ } n_un; unsigned char n_type; /* See below */ char n_other; /* Used in i960 support -- see below */ short n_desc; unsigned long n_value; }; /* Legal values of n_type */ #define N_UNDF 0 /* Undefined symbol */ #define N_ABS 2 /* Absolute symbol */ #define N_TEXT 4 /* Text symbol */ #define N_DATA 6 /* Data symbol */ #define N_BSS 8 /* BSS symbol */ #define N_FN 31 /* Filename symbol */ #define N_EXT 1 /* External symbol (OR'd in with one of above) */ #define N_TYPE 036 /* Mask for all the type bits */ #define N_STAB 0340 /* Mask for all bits used for SDB entries */ /* MEANING OF 'n_other' * * If n_other is 0, it means the symbol is an ordinary aout symbol. * * If non-zero, the 'n_other' fields indicates either a leaf procedure or * a system procedure, as follows: * * 1 <= n_other < N_BALNAME : * The symbol is the entry point to a system procedure. * 'n_value' is the address of the entry, as for any other * procedure. The system procedure number (which can be used in * a 'calls' instruction) is (n_other-1). These entries come from * '.sysproc' directives. * * n_other == N_CALLNAME * the symbol is the 'call' entry point to a leaf procedure. * The *next* symbol in the symbol table must be the corresponding * 'bal' entry point to the procedure (see following). These * entries come from '.leafproc' directives in which two different * symbols are specified (the first one is represented here). * * * n_other == N_BALNAME * the symbol is the 'bal' entry point to a leaf procedure. * These entries result from '.leafproc' directives in which only * one symbol is specified, or in which the same symbol is * specified twice. * * Note that an N_CALLNAME entry *must* have a corresponding N_BALNAME entry, * but not every N_BALNAME entry must have an N_CALLNAME entry. */ #define N_ORDINARY ((unsigned) 0) #define N_BALNAME ((unsigned) 0xfe) #define N_CALLNAME ((unsigned) 0xff) #define MASK( V ) ((sizeof(V) == 1) ? 0x000000ff :\ ((sizeof(V) == 2) ? 0x0000ffff :\ 0x0000ffff)) /* Get unsigned bits: */ #define GET_UBITS( V ) ((unsigned) (V & MASK( V ))) #define IS_ORDINARY(x) (GET_UBITS(x) == N_ORDINARY) #define IS_CALLNAME(x) (GET_UBITS(x) == N_CALLNAME) #define IS_BALNAME(x) (GET_UBITS(x) == N_BALNAME) #define IS_SYSPROCIDX(x) (GET_UBITS(x) > N_ORDINARY &&\ GET_UBITS(x) < N_BALNAME) /* * Note that the following data structure won't compile using a 16-bit * compiler (MSC7, for example). But is not needed for the target client * (mondb). So just ifdef the structure out of existence... */ #ifndef CC_16BIT struct relocation_info { int r_address; /* File address of item to be relocated */ unsigned r_symbolnum:24,/* Index of symbol on which relocation is based, * if r_extern is set. Otherwise set to * either N_TEXT, N_DATA, or N_BSS to * indicate section on which relocation is * based. */ r_pcrel:1, /* 1 => relocate PC-relative; else absolute * On i960, pc-relative implies 24-bit * address, absolute implies 32-bit. */ r_length:2, /* Number of bytes to relocate: * 0 => 1 byte * 1 => 2 bytes * 2 => 4 bytes -- only value used for i960 */ r_extern:1, r_bsr:1, /* Something for the GNU NS32K assembler */ r_disp:1, /* Something for the GNU NS32K assembler */ r_callj:1, /* 1 if relocation target is an i960 'callj' */ r_calljx:1; /* 1 if relocation target is an i960 'calljx' */ }; #endif #endif // EXEC_B_OUT_H gxemul-0.6.1/src/include/thirdparty/m8820x_pte.h000644 001750 001750 00000013424 13402411502 021624 0ustar00debugdebug000000 000000 /* $OpenBSD: mmu.h,v 1.8 2006/05/21 20:55:43 miod Exp $ */ #ifndef M8820X_PTE_H #define M8820X_PTE_H /* * This file bears almost no resemblance to the original m68k file, * so the following copyright notice is questionable, but we are * nice people. */ /* * Copyright (c) 1988 University of Utah. * Copyright (c) 1982, 1986, 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: Utah $Hdr: pte.h 1.13 92/01/20$ * * @(#)pte.h 8.1 (Berkeley) 6/10/93 */ /* * Parameters which determine the 'geometry' of the m88K page tables in memory. */ #define SDT_BITS 10 /* M88K segment table size bits */ #define PDT_BITS 10 /* M88K page table size bits */ #define PG_BITS PAGE_SHIFT /* M88K hardware page size bits */ /* * Common fields for APR, SDT and PTE */ /* address frame */ #define PG_FRAME 0xfffff000 #define PG_SHIFT PG_BITS #define PG_PFNUM(x) (((x) & PG_FRAME) >> PG_SHIFT) /* cache control bits */ #define CACHE_DFL 0x00000000 #define CACHE_INH 0x00000040 /* cache inhibit */ #define CACHE_GLOBAL 0x00000080 /* global scope */ #define CACHE_WT 0x00000200 /* write through */ #define CACHE_MASK (CACHE_INH | CACHE_GLOBAL | CACHE_WT) /* * Area descriptors */ typedef u_int32_t apr_t; #define APR_V 0x00000001 /* valid bit */ /* * 88200 PATC (TLB) */ #define PATC_ENTRIES 56 /* * BATC entries */ #define BATC_V 0x00000001 #define BATC_PROT 0x00000002 #define BATC_INH 0x00000004 #define BATC_GLOBAL 0x00000008 #define BATC_WT 0x00000010 #define BATC_SO 0x00000020 /* * Segment table entries */ typedef u_int32_t sdt_entry_t; #define SG_V 0x00000001 #define SG_NV 0x00000000 #define SG_PROT 0x00000004 #define SG_RO 0x00000004 #define SG_RW 0x00000000 #define SG_SO 0x00000100 #define SDT_VALID(sdt) (*(sdt) & SG_V) #define SDT_SUP(sdt) (*(sdt) & SG_SO) #define SDT_WP(sdt) (*(sdt) & SG_PROT) /* * Page table entries */ typedef u_int32_t pt_entry_t; #define PG_V 0x00000001 #define PG_NV 0x00000000 #define PG_PROT 0x00000004 #define PG_U 0x00000008 #define PG_M 0x00000010 #define PG_M_U 0x00000018 #define PG_RO 0x00000004 #define PG_RW 0x00000000 #define PG_SO 0x00000100 #define PG_W 0x00000020 /* XXX unused but reserved field */ #define PG_U0 0x00000400 /* U0 bit for M88110 */ #define PG_U1 0x00000800 /* U1 bit for M88110 */ #define PDT_VALID(pte) (*(pte) & PG_V) #define PDT_SUP(pte) (*(pte) & PG_SO) #define PDT_WP(pte) (*(pte) & PG_PROT) /* * Indirect descriptors (mc81110) */ typedef u_int32_t pt_ind_entry_t; /* validity bits */ #define IND_V 0x00000001 #define IND_NV 0x00000000 #define IND_MASKED 0x00000002 #define IND_UNMASKED 0x00000003 #define IND_MASK 0x00000003 #define IND_FRAME 0xfffffffc #define IND_SHIFT 2 #define IND_PDA(x) ((x) & IND_FRAME >> IND_SHIFT) /* * Number of entries in a page table. */ #define SDT_ENTRIES (1<<(SDT_BITS)) #define PDT_ENTRIES (1<<(PDT_BITS)) /* * Size in bytes of a single page table. */ #define SDT_SIZE (sizeof(sdt_entry_t) * SDT_ENTRIES) #define PDT_SIZE (sizeof(pt_entry_t) * PDT_ENTRIES) /* * Shifts and masks */ #define SDT_SHIFT (PDT_BITS + PG_BITS) #define PDT_SHIFT (PG_BITS) #define SDT_MASK (((1 << SDT_BITS) - 1) << SDT_SHIFT) #define PDT_MASK (((1 << PDT_BITS) - 1) << PDT_SHIFT) #define SDTIDX(va) (((va) & SDT_MASK) >> SDT_SHIFT) #define PDTIDX(va) (((va) & PDT_MASK) >> PDT_SHIFT) /* * Parameters and macros for BATC */ /* number of bits to BATC shift (log2(BATC_BLKBYTES)) */ #define BATC_BLKSHIFT 19 /* 'block' size of a BATC entry mapping */ #define BATC_BLKBYTES (1 << BATC_BLKSHIFT) /* BATC block mask */ #define BATC_BLKMASK (BATC_BLKBYTES-1) /* number of BATC entries */ #define BATC_MAX 8 /* physical and logical block address */ #define BATC_PSHIFT 6 #define BATC_VSHIFT (BATC_PSHIFT + (32 - BATC_BLKSHIFT)) #define BATC_BLK_ALIGNED(x) ((x & BATC_BLKMASK) == 0) #define M88K_BTOBLK(x) (x >> BATC_BLKSHIFT) #if 0 static pt_entry_t invalidate_pte(pt_entry_t *); static __inline__ pt_entry_t invalidate_pte(pt_entry_t *pte) { pt_entry_t oldpte; oldpte = PG_NV; __asm__ __volatile__ ("xmem %0, %2, r0" : "=r"(oldpte) : "0"(oldpte), "r"(pte)); __asm__ __volatile__ ("tb1 0, r0, 0"); return oldpte; } #endif #endif /* M8820X_PTE_H */ gxemul-0.6.1/src/include/thirdparty/dreamcast_maple.h000644 001750 001750 00000015046 13402411502 023131 0ustar00debugdebug000000 000000 /* GXemul: $Id: dreamcast_maple.h,v 1.1 2006-10-27 04:22:44 debug Exp $ */ /* $NetBSD: maple.h,v 1.9 2005/12/11 12:17:06 christos Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by ITOH Yasufumi. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2001 Marcus Comstedt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Marcus Comstedt. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _DREAMCAST_DEV_MAPLE_MAPLE_H_ #define _DREAMCAST_DEV_MAPLE_MAPLE_H_ /* signed is more effective than unsigned on SH */ typedef int8_t maple_response_t; /* Maple Bus command and response codes */ #define MAPLE_RESPONSE_LCDERR (-6) #define MAPLE_RESPONSE_FILEERR (-5) #define MAPLE_RESPONSE_AGAIN (-4) /* request should be retransmitted */ #define MAPLE_RESPONSE_BADCMD (-3) #define MAPLE_RESPONSE_BADFUNC (-2) #define MAPLE_RESPONSE_NONE (-1) /* unit didn't respond at all */ #define MAPLE_COMMAND_DEVINFO 1 #define MAPLE_COMMAND_ALLINFO 2 #define MAPLE_COMMAND_RESET 3 #define MAPLE_COMMAND_KILL 4 #define MAPLE_RESPONSE_DEVINFO 5 #define MAPLE_RESPONSE_ALLINFO 6 #define MAPLE_RESPONSE_OK 7 #define MAPLE_RESPONSE_DATATRF 8 #define MAPLE_COMMAND_GETCOND 9 #define MAPLE_COMMAND_GETMINFO 10 #define MAPLE_COMMAND_BREAD 11 #define MAPLE_COMMAND_BWRITE 12 #define MAPLE_COMMAND_GETLASTERR 13 #define MAPLE_COMMAND_SETCOND 14 /* Function codes */ #define MAPLE_FN_CONTROLLER 0 #define MAPLE_FN_MEMCARD 1 #define MAPLE_FN_LCD 2 #define MAPLE_FN_CLOCK 3 #define MAPLE_FN_MICROPHONE 4 #define MAPLE_FN_ARGUN 5 #define MAPLE_FN_KEYBOARD 6 #define MAPLE_FN_LIGHTGUN 7 #define MAPLE_FN_PURUPURU 8 #define MAPLE_FN_MOUSE 9 #define MAPLE_FUNC(fn) (1 << (fn)) struct maple_devinfo { uint32_t di_func; /* function code */ uint32_t di_function_data[3]; /* function data */ uint8_t di_area_code; /* region settings */ uint8_t di_connector_direction; /* direction of expansion connector */ char di_product_name[30]; /* name of the device */ char di_product_license[60]; /* manufacturer info */ uint16_t di_standby_power; /* standby power consumption */ uint16_t di_max_power; /* maximum power consumption */ }; #define MAPLE_CONN_TOP 0 /* connector is to the top */ #define MAPLE_CONN_BOTTOM 1 /* connector is to the bottom */ struct maple_response { uint32_t response_code; uint32_t data[1]; /* variable length */ }; #define MAPLE_FLAG_PERIODIC 1 #define MAPLE_FLAG_CMD_PERIODIC_TIMING 2 #if 0 struct maple_unit; extern void maple_set_callback(struct device *, struct maple_unit *, int, void (*)(void *, struct maple_response *, int, int), void *); extern void maple_enable_unit_ping(struct device *, struct maple_unit *, int /*func*/, int /*enable*/); extern void maple_enable_periodic(struct device *, struct maple_unit *, int /*func*/, int /*on*/); extern void maple_command(struct device *, struct maple_unit *, int /*func*/, int /*command*/, int /*datalen*/, const void *, int /*flags*/); extern uint32_t maple_get_function_data(struct maple_devinfo *, int); extern void maple_run_polling(struct device *); extern int maple_unit_ioctl(struct device *, struct maple_unit *, u_long, caddr_t, int, struct lwp *); #endif #endif /* _DREAMCAST_DEV_MAPLE_MAPLE_H_ */ gxemul-0.6.1/src/include/thirdparty/igsfbreg.h000644 001750 001750 00000030227 13402411502 021576 0ustar00debugdebug000000 000000 /* GXemul: $Id: igsfbreg.h,v 1.2 2006-08-11 17:43:30 debug Exp $ */ /* $NetBSD: igsfbreg.h,v 1.7 2005/12/11 12:21:27 christos Exp $ */ /* * Copyright (c) 2002 Valeriy E. Ushakov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Integraphics Systems IGA 168x and CyberPro series. * Only tested on IGA 1682 in Krups JavaStation-NC. */ #ifndef _DEV_IC_IGSFBREG_H_ #define _DEV_IC_IGSFBREG_H_ /* * Magic address decoding for memory space accesses in CyberPro. */ #define IGS_MEM_MMIO_SELECT 0x00800000 /* memory mapped i/o */ #define IGS_MEM_BE_SELECT 0x00400000 /* endian select */ /* * Cursor sprite data in linear memory at IGS_EXT_SPRITE_DATA_{LO,HI}. * 64x64 pixels, 2bpp = 1Kb */ #define IGS_CURSOR_DATA_SIZE 1024 /* * Starting up the chip. */ /* Video Enable/Setup */ #define IGS_VDO 0x46e8 #define IGS_VDO_ENABLE 0x08 #define IGS_VDO_SETUP 0x10 /* Video Enable */ #define IGS_VSE 0x102 #define IGS_VSE_ENABLE 0x01 /* * We map only 32 bytes of actual IGS registers at 0x3c0..0x3df. * This macro helps to define register names using their "absolute" * locations - it makes matching defines against docs easier. */ #define IGS_REG_BASE 0x3c0 #define IGS_REG_SIZE 0x020 #define IGS_REG_(x) ((x) - IGS_REG_BASE) /* * Attribute controller. Flip-flop reset by IGS_INPUT_STATUS1 at 0x3da. * We don't bother defining actual registers, we only use them once * during video initialization. */ #define IGS_ATTR_IDX IGS_REG_(0x3c0) #define IGS_ATTR_PORT IGS_REG_(0x3c1) /* * Misc output register. We only use the _W register during video * initialization. */ #define IGS_MISC_OUTPUT_W IGS_REG_(0x3c2) #define IGS_MISC_OUTPUT_R IGS_REG_(0x3cc) /* * SEQUENCER. */ #define IGS_SEQ_IDX IGS_REG_(0x3c4) #define IGS_SEQ_PORT IGS_REG_(0x3c5) #define IGS_SEQ_RESET 0x0 #define IGS_SEQ_RESET_ASYNC 0x01 #define IGS_SEQ_RESET_SYNC 0x02 /* IGS_EXT_SPRITE_CTL/IGS_EXT_SPRITE_DAC_PEL (3cf/56[2]) == 0 */ #define IGS_PEL_MASK IGS_REG_(0x3c6) /* IGS_EXT_SPRITE_CTL/IGS_EXT_SPRITE_DAC_PEL 3cf/56[2] == 1 */ #define IGS_DAC_CMD IGS_REG_(0x3c6) /* * Palette Read/Write: write palette index to the index port. * Read/write R/G/B in three consecutive accesses to data port. * After third access to data the index is autoincremented and you can * proceed with reading/writing data port for the next entry. * * When IGS_EXT_SPRITE_DAC_PEL bit in sprite control is set, these * registers are used to access sprite (i.e. cursor) 2-color palette. * (NB: apparently, in this mode index autoincrement doesn't work). */ #define IGS_DAC_PEL_READ_IDX IGS_REG_(0x3c7) #define IGS_DAC_PEL_WRITE_IDX IGS_REG_(0x3c8) #define IGS_DAC_PEL_DATA IGS_REG_(0x3c9) /* * GRAPHICS CONTROLLER registers. */ #define IGS_GRFX_IDX IGS_REG_(0x3ce) #define IGS_GRFX_PORT IGS_REG_(0x3cf) /* * EXTENDED registers. */ #define IGS_EXT_IDX IGS_REG_(0x3ce) #define IGS_EXT_PORT IGS_REG_(0x3cf) /* [3..0] -> [19..16] of start addr if IGS_EXT_START_ADDR_ON is set */ #define IGS_EXT_START_ADDR 0x10 #define IGS_EXT_START_ADDR_ON 0x10 /* overflow 10th bits for severl crtc registers; interlaced mode select */ #define IGS_EXT_VOVFL 0x11 #define IGS_EXT_VOVFL_INTERLACED 0x20 #define IGS_EXT_IRQ_CTL 0x12 #define IGS_EXT_IRQ_ENABLE 0x01 /* * Sync Control. * Two-bit combinations for h/v: * 00 - normal, 01 - force 0, 1x - force 1 */ #define IGS_EXT_SYNC_CTL 0x16 #define IGS_EXT_SYNC_H0 0x01 #define IGS_EXT_SYNC_H1 0x02 #define IGS_EXT_SYNC_V0 0x04 #define IGS_EXT_SYNC_V1 0x08 /* * For PCI just use normal BAR config. */ #define IGS_EXT_BUS_CTL 0x30 #define IGS_EXT_BUS_CTL_LINSIZE_SHIFT 0 #define IGS_EXT_BUS_CTL_LINSIZE_MASK 0x03 #define IGS_EXT_BUS_CTL_LINSIZE(x) \ (((x) >> IGS_EXT_BUS_CTL_LINSIZE_SHIFT) & IGS_EXT_BUS_CTL_LINSIZE_MASK) /* * COPREN - enable direct access to coprocessor registers * COPASELB - select IGS_COP_BASE_B for COP address */ #define IGS_EXT_BIU_MISC_CTL 0x33 #define IGS_EXT_BIU_LINEAREN 0x01 #define IGS_EXT_BIU_LIN2MEM 0x02 #define IGS_EXT_BIU_COPREN 0x04 #define IGS_EXT_BIU_COPASELB 0x08 #define IGS_EXT_BIU_SEGON 0x10 #define IGS_EXT_BIU_SEG2MEM 0x20 /* * Linear Address registers * PCI: don't write directly, just use normal PCI configuration * ISA: only bits [23..20] are programmable, the rest MBZ */ #define IGS_EXT_LINA_LO 0x34 /* [3..0] -> [23..20] */ #define IGS_EXT_LINA_HI 0x35 /* [7..0] -> [31..24] */ /* Hardware cursor on-screen location and hot spot */ #define IGS_EXT_SPRITE_HSTART_LO 0x50 #define IGS_EXT_SPRITE_HSTART_HI 0x51 /* bits [2..0] */ #define IGS_EXT_SPRITE_HPRESET 0x52 /* bits [5..0] */ #define IGS_EXT_SPRITE_VSTART_LO 0x53 #define IGS_EXT_SPRITE_VSTART_HI 0x54 /* bits [2..0] */ #define IGS_EXT_SPRITE_VPRESET 0x55 /* bits [5..0] */ /* Hardware cursor control */ #define IGS_EXT_SPRITE_CTL 0x56 #define IGS_EXT_SPRITE_VISIBLE 0x01 #define IGS_EXT_SPRITE_64x64 0x02 #define IGS_EXT_SPRITE_DAC_PEL 0x04 /* bits unrelated to sprite control */ #define IGS_EXT_COP_RESET 0x08 /* Extended graphics mode */ #define IGS_EXT_GRFX_MODE 0x57 #define IGS_EXT_GRFX_MODE_EXT 0x01 /* Overscan R/G/B registers */ #define IGS_EXT_OVERSCAN_RED 0x58 #define IGS_EXT_OVERSCAN_GREEN 0x59 #define IGS_EXT_OVERSCAN_BLUE 0x5a /* Memory controller */ #define IGS_EXT_MEM_CTL0 0x70 #define IGS_EXT_MEM_CTL1 0x71 #define IGS_EXT_MEM_CTL2 0x72 /* * SEQ miscellaneous: number of SL between CCLK - controls visual depth. * These values are for MODE256 == 1, SRMODE = 1 in GRFX/5 mode register. */ #define IGS_EXT_SEQ_MISC 0x77 #define IGS_EXT_SEQ_IBM_STD 0 #define IGS_EXT_SEQ_8BPP 1 /* 256 indexed */ #define IGS_EXT_SEQ_16BPP 2 /* HiColor 16bpp, 5-6-5 */ #define IGS_EXT_SEQ_32BPP 3 /* TrueColor 32bpp */ #define IGS_EXT_SEQ_24BPP 4 /* TrueColor 24bpp */ #define IGS_EXT_SEQ_15BPP 6 /* HiColor 16bpp, 5-5-5 */ /* Hardware cursor data location in linear memory */ #define IGS_EXT_SPRITE_DATA_LO 0x7e #define IGS_EXT_SPRITE_DATA_HI 0x7f /* bits [3..0] */ #define IGS_EXT_VCLK0 0xb0 /* mult */ #define IGS_EXT_VCLK1 0xb1 /* div */ #define IGS_EXT_MCLK0 0xb2 /* mult */ #define IGS_EXT_MCLK1 0xb3 /* div */ /* ----8<---- end of IGS_EXT registers ----8<---- */ /* * CRTC can be at 0x3b4/0x3b5 (mono) or 0x3d4/0x3d5 (color) * controlled by bit 0 in misc output register (r=0x3cc/w=0x3c2). * We forcibly init it to color. */ #define IGS_CRTC_IDX IGS_REG_(0x3d4) #define IGS_CRTC_PORT IGS_REG_(0x3d5) /* * Reading this register resets flip-flop at 0x3c0 (attribute * controller) to address register. */ #define IGS_INPUT_STATUS1 IGS_REG_(0x3da) /********************************************************************* * IGS Graphic Coprocessor */ /* * Coprocessor registers location in I/O space. * Controlled by COPASELB bit in IGS_EXT_BIU_MISC_CTL. */ #define IGS_COP_BASE_A 0xaf000 /* COPASELB == 0 */ #define IGS_COP_BASE_B 0xbf000 /* COPASELB == 1 */ #define IGS_COP_SIZE 0x00400 /* * NB: Loaded width values should be 1 less than the actual width! */ /* * Coprocessor control. */ #define IGS_COP_CTL_REG 0x011 #define IGS_COP_CTL_HBRDYZ 0x01 #define IGS_COP_CTL_HFEMPTZ 0x02 #define IGS_COP_CTL_CMDFF 0x04 #define IGS_COP_CTL_SOP 0x08 /* rw */ #define IGS_COP_CTL_OPS 0x10 #define IGS_COP_CTL_TER 0x20 /* rw */ #define IGS_COP_CTL_HBACKZ 0x40 #define IGS_COP_CTL_BUSY 0x80 /* * Source(s) and destination widths. * 16 bit registers. Only bits [11..0] are used. */ #define IGS_COP_SRC_MAP_WIDTH_REG 0x018 #define IGS_COP_SRC2_MAP_WIDTH_REG 0x118 #define IGS_COP_DST_MAP_WIDTH_REG 0x218 /* * Bitmap depth. */ #define IGS_COP_MAP_FMT_REG 0x01c #define IGS_COP_MAP_8BPP 0x00 #define IGS_COP_MAP_16BPP 0x01 #define IGS_COP_MAP_24BPP 0x02 #define IGS_COP_MAP_32BPP 0x03 /* * Binary operations are defined below. S - source, D - destination, * N - not; a - and, o - or, x - xor. * * For ternary operations, foreground mix function is one of 256 * ternary raster operations defined by Win32 API; background mix is * ignored. */ #define IGS_COP_FG_MIX_REG 0x048 #define IGS_COP_BG_MIX_REG 0x049 #define IGS_COP_MIX_0 0x0 #define IGS_COP_MIX_SaD 0x1 #define IGS_COP_MIX_SaND 0x2 #define IGS_COP_MIX_S 0x3 #define IGS_COP_MIX_NSaD 0x4 #define IGS_COP_MIX_D 0x5 #define IGS_COP_MIX_SxD 0x6 #define IGS_COP_MIX_SoD 0x7 #define IGS_COP_MIX_NSaND 0x8 #define IGS_COP_MIX_SxND 0x9 #define IGS_COP_MIX_ND 0xa #define IGS_COP_MIX_SoND 0xb #define IGS_COP_MIX_NS 0xc #define IGS_COP_MIX_NSoD 0xd #define IGS_COP_MIX_NSoND 0xe #define IGS_COP_MIX_1 0xf /* * Foreground/background colours (24 bit). * Selected by bits in IGS_COP_PIXEL_OP_3_REG. */ #define IGS_COP_FG_REG 0x058 #define IGS_COP_BG_REG 0x05C /* * Horizontal/vertical dimensions of pixel blit function. * 16 bit registers. Only [11..0] are used. */ #define IGS_COP_WIDTH_REG 0x060 #define IGS_COP_HEIGHT_REG 0x062 /* * Only bits [21..0] are used. */ #define IGS_COP_SRC_BASE_REG 0x070 /* only for 24bpp Src Color Tiling */ #define IGS_COP_SRC_START_REG 0x170 #define IGS_COP_SRC2_START_REG 0x174 #define IGS_COP_DST_START_REG 0x178 /* * Destination phase angle for 24bpp. */ #define IGS_COP_DST_X_PHASE_REG 0x078 #define IGS_COP_DST_X_PHASE_MASK 0x07 /* * Pixel operation: Direction and draw mode. * When an octant bit is set, that axis is traversed backwards. */ #define IGS_COP_PIXEL_OP_0_REG 0x07c #define IGS_COP_OCTANT_Y_NEG 0x02 /* 0: top down, 1: bottom up */ #define IGS_COP_OCTANT_X_NEG 0x04 /* 0: l2r, 1: r2l */ #define IGS_COP_DRAW_ALL 0x00 #define IGS_COP_DRAW_FIRST_NULL 0x10 #define IGS_COP_DRAW_LAST_NULL 0x20 /* * Pixel operation: Pattern operation. */ #define IGS_COP_PIXEL_OP_1_REG 0x07d #define IGS_COP_PPM_TEXT 0x10 #define IGS_COP_PPM_TILE 0x20 #define IGS_COP_PPM_LINE 0x30 #define IGS_COP_PPM_TRANSPARENT 0x40 /* "or" with one of the above */ #define IGS_COP_PPM_FIXED_FG 0x80 #define IGS_COP_PPM_SRC_COLOR_TILE 0x90 /* * Pixel operation: Host CPU access (host blit) to graphics engine. */ #define IGS_COP_PIXEL_OP_2_REG 0x07e #define IGS_COP_HBLTR 0x01 /* enable read from engine */ #define IGS_COP_HBLTW 0x02 /* enable write to engine */ /* * Pixel operation: Operation function of graphic engine. */ #define IGS_COP_PIXEL_OP_3_REG 0x07f #define IGS_COP_OP_STROKE 0x04 /* short stroke */ #define IGS_COP_OP_LINE 0x05 /* bresenham line draw */ #define IGS_COP_OP_PXBLT 0x08 /* pixel blit */ #define IGS_COP_OP_PXBLT_INV 0x09 /* invert pixel blit */ #define IGS_COP_OP_PXBLT_3 0x0a /* ternary pixel blit */ /* select fg/bg source: 0 - fg/bg color reg, 1 - src1 map */ #define IGS_COP_OP_FG_FROM_SRC 0x20 #define IGS_COP_OP_BG_FROM_SRC 0x80 #endif /* _DEV_IC_IGSFBREG_H_ */ gxemul-0.6.1/src/include/thirdparty/netbsd_iyonix_bootconfig.h000644 001750 001750 00000006114 13402411502 025073 0ustar00debugdebug000000 000000 #ifndef NETBSD_IYONIX_BOOTCONFIG_H #define NETBSD_IYONIX_BOOTCONFIG_H /* $NetBSD: bootconfig.h,v 1.4 2006/10/24 20:39:14 bjh21 Exp $ */ /* * Copyright (c) 2002 Reinoud Zandijk. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * boot configuration structures * */ /* #include */ typedef uint32_t Xu_int; /* GXemul */ /* get some spare blocks ;) */ #define DRAM_BLOCKS 32 #define VRAM_BLOCKS 16 #define PHYSMEM_TYPE_GENERIC 0 #define PHYSMEM_TYPE_PROCESSOR_ONLY 1 typedef struct { Xu_int address; Xu_int pages; Xu_int flags; } phys_mem; struct bootconfig { Xu_int magic; Xu_int version; /* version 2+ */ u_char machine_id[4]; /* unique machine Id */ char kernelname[80]; char args[512]; /* 512 bytes is better than 4096 */ Xu_int kernvirtualbase; /* not used now */ Xu_int kernphysicalbase; /* not used now */ Xu_int kernsize; Xu_int scratchvirtualbase; /* not used now */ Xu_int scratchphysicalbase; /* not used now */ Xu_int scratchsize; /* not used now */ Xu_int ksym_start; Xu_int ksym_end; Xu_int MDFvirtualbase; /* not used yet */ Xu_int MDFphysicalbase; /* not used yet */ Xu_int MDFsize; /* not used yet */ Xu_int display_phys; Xu_int display_start; Xu_int display_size; Xu_int width; Xu_int height; Xu_int log2_bpp; Xu_int framerate; char reserved[512]; /* future expansion */ Xu_int pagesize; Xu_int drampages; Xu_int vrampages; Xu_int dramblocks; Xu_int vramblocks; phys_mem dram[DRAM_BLOCKS]; phys_mem vram[VRAM_BLOCKS]; }; #define BOOTCONFIG_MAGIC 0x43112233 #define BOOTCONFIG_VERSION 0x2 extern struct bootconfig bootconfig; /* End of bootconfig.h */ #endif /* NETBSD_IYONIX_BOOTCONFIG_H */ gxemul-0.6.1/src/include/thirdparty/aic7xxx_reg.h000644 001750 001750 00000140312 13402411502 022233 0ustar00debugdebug000000 000000 /* gxemul: $Id: aic7xxx_reg.h,v 1.2 2005-03-30 22:57:34 debug Exp $ */ /* See NetBSD's aic7xxx_reg.h for more info. */ #ifndef AIC7XXX_REG_H #define AIC7XXX_REG_H /* * DO NOT EDIT - This file is automatically generated * from the following source files: * * $NetBSD: aic7xxx_reg.h,v 1.2 2003/04/19 19:27:50 fvdl Exp $ * $NetBSD: aic7xxx_reg.h,v 1.2 2003/04/19 19:27:50 fvdl Exp $ */ #if 0 typedef int (ahc_reg_print_t)(u_int, u_int *, u_int); typedef struct ahc_reg_parse_entry { char *name; uint8_t value; uint8_t mask; } ahc_reg_parse_entry_t; #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scsiseq_print; #else #define ahc_scsiseq_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCSISEQ", 0x00, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sxfrctl0_print; #else #define ahc_sxfrctl0_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SXFRCTL0", 0x01, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sxfrctl1_print; #else #define ahc_sxfrctl1_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SXFRCTL1", 0x02, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scsisigo_print; #else #define ahc_scsisigo_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCSISIGO", 0x03, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scsisigi_print; #else #define ahc_scsisigi_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCSISIGI", 0x03, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scsirate_print; #else #define ahc_scsirate_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCSIRATE", 0x04, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scsiid_print; #else #define ahc_scsiid_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCSIID", 0x05, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scsidatl_print; #else #define ahc_scsidatl_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCSIDATL", 0x06, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scsidath_print; #else #define ahc_scsidath_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCSIDATH", 0x07, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_stcnt_print; #else #define ahc_stcnt_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "STCNT", 0x08, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_optionmode_print; #else #define ahc_optionmode_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "OPTIONMODE", 0x08, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_targcrccnt_print; #else #define ahc_targcrccnt_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "TARGCRCCNT", 0x0a, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_clrsint0_print; #else #define ahc_clrsint0_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CLRSINT0", 0x0b, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sstat0_print; #else #define ahc_sstat0_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SSTAT0", 0x0b, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_clrsint1_print; #else #define ahc_clrsint1_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CLRSINT1", 0x0c, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sstat1_print; #else #define ahc_sstat1_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SSTAT1", 0x0c, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sstat2_print; #else #define ahc_sstat2_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SSTAT2", 0x0d, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sstat3_print; #else #define ahc_sstat3_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SSTAT3", 0x0e, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scsiid_ultra2_print; #else #define ahc_scsiid_ultra2_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCSIID_ULTRA2", 0x0f, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_simode0_print; #else #define ahc_simode0_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SIMODE0", 0x10, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_simode1_print; #else #define ahc_simode1_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SIMODE1", 0x11, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scsibusl_print; #else #define ahc_scsibusl_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCSIBUSL", 0x12, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sxfrctl2_print; #else #define ahc_sxfrctl2_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SXFRCTL2", 0x13, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scsibush_print; #else #define ahc_scsibush_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCSIBUSH", 0x13, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_shaddr_print; #else #define ahc_shaddr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SHADDR", 0x14, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_seltimer_print; #else #define ahc_seltimer_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SELTIMER", 0x18, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_selid_print; #else #define ahc_selid_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SELID", 0x19, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scamctl_print; #else #define ahc_scamctl_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCAMCTL", 0x1a, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_targid_print; #else #define ahc_targid_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "TARGID", 0x1b, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_spiocap_print; #else #define ahc_spiocap_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SPIOCAP", 0x1b, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_brdctl_print; #else #define ahc_brdctl_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "BRDCTL", 0x1d, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_seectl_print; #else #define ahc_seectl_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SEECTL", 0x1e, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sblkctl_print; #else #define ahc_sblkctl_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SBLKCTL", 0x1f, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_busy_targets_print; #else #define ahc_busy_targets_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "BUSY_TARGETS", 0x20, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_ultra_enb_print; #else #define ahc_ultra_enb_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "ULTRA_ENB", 0x30, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_disc_dsb_print; #else #define ahc_disc_dsb_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DISC_DSB", 0x32, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_cmdsize_table_tail_print; #else #define ahc_cmdsize_table_tail_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CMDSIZE_TABLE_TAIL", 0x34, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_mwi_residual_print; #else #define ahc_mwi_residual_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "MWI_RESIDUAL", 0x38, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_next_queued_scb_print; #else #define ahc_next_queued_scb_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "NEXT_QUEUED_SCB", 0x39, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_msg_out_print; #else #define ahc_msg_out_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "MSG_OUT", 0x3a, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_dmaparams_print; #else #define ahc_dmaparams_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DMAPARAMS", 0x3b, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_seq_flags_print; #else #define ahc_seq_flags_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SEQ_FLAGS", 0x3c, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_saved_scsiid_print; #else #define ahc_saved_scsiid_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SAVED_SCSIID", 0x3d, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_saved_lun_print; #else #define ahc_saved_lun_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SAVED_LUN", 0x3e, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_lastphase_print; #else #define ahc_lastphase_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "LASTPHASE", 0x3f, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_waiting_scbh_print; #else #define ahc_waiting_scbh_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "WAITING_SCBH", 0x40, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_disconnected_scbh_print; #else #define ahc_disconnected_scbh_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DISCONNECTED_SCBH", 0x41, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_free_scbh_print; #else #define ahc_free_scbh_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "FREE_SCBH", 0x42, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_complete_scbh_print; #else #define ahc_complete_scbh_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "COMPLETE_SCBH", 0x43, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_hscb_addr_print; #else #define ahc_hscb_addr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "HSCB_ADDR", 0x44, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_shared_data_addr_print; #else #define ahc_shared_data_addr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SHARED_DATA_ADDR", 0x48, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_kernel_qinpos_print; #else #define ahc_kernel_qinpos_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "KERNEL_QINPOS", 0x4c, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_qinpos_print; #else #define ahc_qinpos_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "QINPOS", 0x4d, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_qoutpos_print; #else #define ahc_qoutpos_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "QOUTPOS", 0x4e, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_kernel_tqinpos_print; #else #define ahc_kernel_tqinpos_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "KERNEL_TQINPOS", 0x4f, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_tqinpos_print; #else #define ahc_tqinpos_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "TQINPOS", 0x50, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_arg_1_print; #else #define ahc_arg_1_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "ARG_1", 0x51, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_arg_2_print; #else #define ahc_arg_2_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "ARG_2", 0x52, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_last_msg_print; #else #define ahc_last_msg_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "LAST_MSG", 0x53, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scsiseq_template_print; #else #define ahc_scsiseq_template_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCSISEQ_TEMPLATE", 0x54, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_data_count_odd_print; #else #define ahc_data_count_odd_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DATA_COUNT_ODD", 0x55, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_ha_274_biosglobal_print; #else #define ahc_ha_274_biosglobal_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "HA_274_BIOSGLOBAL", 0x56, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_seq_flags2_print; #else #define ahc_seq_flags2_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SEQ_FLAGS2", 0x57, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scsiconf_print; #else #define ahc_scsiconf_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCSICONF", 0x5a, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_intdef_print; #else #define ahc_intdef_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "INTDEF", 0x5c, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_hostconf_print; #else #define ahc_hostconf_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "HOSTCONF", 0x5d, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_ha_274_biosctrl_print; #else #define ahc_ha_274_biosctrl_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "HA_274_BIOSCTRL", 0x5f, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_seqctl_print; #else #define ahc_seqctl_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SEQCTL", 0x60, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_seqram_print; #else #define ahc_seqram_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SEQRAM", 0x61, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_seqaddr0_print; #else #define ahc_seqaddr0_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SEQADDR0", 0x62, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_seqaddr1_print; #else #define ahc_seqaddr1_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SEQADDR1", 0x63, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_accum_print; #else #define ahc_accum_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "ACCUM", 0x64, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sindex_print; #else #define ahc_sindex_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SINDEX", 0x65, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_dindex_print; #else #define ahc_dindex_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DINDEX", 0x66, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_allones_print; #else #define ahc_allones_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "ALLONES", 0x69, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_none_print; #else #define ahc_none_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "NONE", 0x6a, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_allzeros_print; #else #define ahc_allzeros_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "ALLZEROS", 0x6a, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_flags_print; #else #define ahc_flags_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "FLAGS", 0x6b, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sindir_print; #else #define ahc_sindir_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SINDIR", 0x6c, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_dindir_print; #else #define ahc_dindir_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DINDIR", 0x6d, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_function1_print; #else #define ahc_function1_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "FUNCTION1", 0x6e, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_stack_print; #else #define ahc_stack_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "STACK", 0x6f, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_targ_offset_print; #else #define ahc_targ_offset_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "TARG_OFFSET", 0x70, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sram_base_print; #else #define ahc_sram_base_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SRAM_BASE", 0x70, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_bctl_print; #else #define ahc_bctl_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "BCTL", 0x84, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_dscommand0_print; #else #define ahc_dscommand0_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DSCOMMAND0", 0x84, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_bustime_print; #else #define ahc_bustime_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "BUSTIME", 0x85, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_dscommand1_print; #else #define ahc_dscommand1_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DSCOMMAND1", 0x85, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_busspd_print; #else #define ahc_busspd_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "BUSSPD", 0x86, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_dspcistatus_print; #else #define ahc_dspcistatus_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DSPCISTATUS", 0x86, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_hs_mailbox_print; #else #define ahc_hs_mailbox_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "HS_MAILBOX", 0x86, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_hcntrl_print; #else #define ahc_hcntrl_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "HCNTRL", 0x87, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_haddr_print; #else #define ahc_haddr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "HADDR", 0x88, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_hcnt_print; #else #define ahc_hcnt_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "HCNT", 0x8c, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scbptr_print; #else #define ahc_scbptr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCBPTR", 0x90, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_intstat_print; #else #define ahc_intstat_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "INTSTAT", 0x91, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_error_print; #else #define ahc_error_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "ERROR", 0x92, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_clrint_print; #else #define ahc_clrint_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CLRINT", 0x92, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_dfcntrl_print; #else #define ahc_dfcntrl_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DFCNTRL", 0x93, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_dfstatus_print; #else #define ahc_dfstatus_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DFSTATUS", 0x94, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_dfwaddr_print; #else #define ahc_dfwaddr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DFWADDR", 0x95, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_dfraddr_print; #else #define ahc_dfraddr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DFRADDR", 0x97, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_dfdat_print; #else #define ahc_dfdat_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DFDAT", 0x99, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scbcnt_print; #else #define ahc_scbcnt_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCBCNT", 0x9a, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_qinfifo_print; #else #define ahc_qinfifo_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "QINFIFO", 0x9b, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_qincnt_print; #else #define ahc_qincnt_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "QINCNT", 0x9c, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_crccontrol1_print; #else #define ahc_crccontrol1_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CRCCONTROL1", 0x9d, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_qoutfifo_print; #else #define ahc_qoutfifo_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "QOUTFIFO", 0x9d, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scsiphase_print; #else #define ahc_scsiphase_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCSIPHASE", 0x9e, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_qoutcnt_print; #else #define ahc_qoutcnt_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "QOUTCNT", 0x9e, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sfunct_print; #else #define ahc_sfunct_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SFUNCT", 0x9f, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_base_print; #else #define ahc_scb_base_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_BASE", 0xa0, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_cdb_ptr_print; #else #define ahc_scb_cdb_ptr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_CDB_PTR", 0xa0, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_residual_sgptr_print; #else #define ahc_scb_residual_sgptr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_RESIDUAL_SGPTR", 0xa4, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_scsi_status_print; #else #define ahc_scb_scsi_status_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_SCSI_STATUS", 0xa8, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_target_phases_print; #else #define ahc_scb_target_phases_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_TARGET_PHASES", 0xa9, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_target_data_dir_print; #else #define ahc_scb_target_data_dir_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_TARGET_DATA_DIR", 0xaa, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_target_itag_print; #else #define ahc_scb_target_itag_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_TARGET_ITAG", 0xab, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_dataptr_print; #else #define ahc_scb_dataptr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_DATAPTR", 0xac, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_datacnt_print; #else #define ahc_scb_datacnt_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_DATACNT", 0xb0, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_sgptr_print; #else #define ahc_scb_sgptr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_SGPTR", 0xb4, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_control_print; #else #define ahc_scb_control_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_CONTROL", 0xb8, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_scsiid_print; #else #define ahc_scb_scsiid_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_SCSIID", 0xb9, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_lun_print; #else #define ahc_scb_lun_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_LUN", 0xba, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_tag_print; #else #define ahc_scb_tag_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_TAG", 0xbb, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_cdb_len_print; #else #define ahc_scb_cdb_len_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_CDB_LEN", 0xbc, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_scsirate_print; #else #define ahc_scb_scsirate_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_SCSIRATE", 0xbd, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_scsioffset_print; #else #define ahc_scb_scsioffset_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_SCSIOFFSET", 0xbe, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_next_print; #else #define ahc_scb_next_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_NEXT", 0xbf, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_64_spare_print; #else #define ahc_scb_64_spare_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_64_SPARE", 0xc0, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_seectl_2840_print; #else #define ahc_seectl_2840_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SEECTL_2840", 0xc0, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_status_2840_print; #else #define ahc_status_2840_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "STATUS_2840", 0xc1, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scb_64_btt_print; #else #define ahc_scb_64_btt_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCB_64_BTT", 0xd0, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_cchaddr_print; #else #define ahc_cchaddr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CCHADDR", 0xe0, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_cchcnt_print; #else #define ahc_cchcnt_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CCHCNT", 0xe8, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_ccsgram_print; #else #define ahc_ccsgram_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CCSGRAM", 0xe9, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_ccsgaddr_print; #else #define ahc_ccsgaddr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CCSGADDR", 0xea, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_ccsgctl_print; #else #define ahc_ccsgctl_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CCSGCTL", 0xeb, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_ccscbram_print; #else #define ahc_ccscbram_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CCSCBRAM", 0xec, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_ccscbaddr_print; #else #define ahc_ccscbaddr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CCSCBADDR", 0xed, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_ccscbctl_print; #else #define ahc_ccscbctl_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CCSCBCTL", 0xee, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_ccscbcnt_print; #else #define ahc_ccscbcnt_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CCSCBCNT", 0xef, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_scbbaddr_print; #else #define ahc_scbbaddr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SCBBADDR", 0xf0, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_ccscbptr_print; #else #define ahc_ccscbptr_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "CCSCBPTR", 0xf1, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_hnscb_qoff_print; #else #define ahc_hnscb_qoff_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "HNSCB_QOFF", 0xf4, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_snscb_qoff_print; #else #define ahc_snscb_qoff_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SNSCB_QOFF", 0xf6, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sdscb_qoff_print; #else #define ahc_sdscb_qoff_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SDSCB_QOFF", 0xf8, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_qoff_ctlsta_print; #else #define ahc_qoff_ctlsta_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "QOFF_CTLSTA", 0xfa, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_dff_thrsh_print; #else #define ahc_dff_thrsh_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "DFF_THRSH", 0xfb, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sg_cache_shadow_print; #else #define ahc_sg_cache_shadow_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SG_CACHE_SHADOW", 0xfc, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_sg_cache_pre_print; #else #define ahc_sg_cache_pre_print(regvalue, cur_col, wrap) \ ahc_print_register(NULL, 0, "SG_CACHE_PRE", 0xfc, regvalue, cur_col, wrap) #endif #define SCSISEQ 0x00 #define TEMODE 0x80 #define SCSIRSTO 0x01 #define SXFRCTL0 0x01 #define DFON 0x80 #define DFPEXP 0x40 #define FAST20 0x20 #define CLRSTCNT 0x10 #define SPIOEN 0x08 #define SCAMEN 0x04 #define CLRCHN 0x02 #define SXFRCTL1 0x02 #define STIMESEL 0x18 #define BITBUCKET 0x80 #define SWRAPEN 0x40 #define ENSTIMER 0x04 #define ACTNEGEN 0x02 #define STPWEN 0x01 #define SCSISIGO 0x03 #define CDO 0x80 #define IOO 0x40 #define MSGO 0x20 #define ATNO 0x10 #define SELO 0x08 #define BSYO 0x04 #define REQO 0x02 #define ACKO 0x01 #define SCSISIGI 0x03 #define P_DATAIN_DT 0x60 #define P_DATAOUT_DT 0x20 #define ATNI 0x10 #define SELI 0x08 #define BSYI 0x04 #define REQI 0x02 #define ACKI 0x01 #define SCSIRATE 0x04 #define SXFR 0x70 #define SXFR_ULTRA2 0x0f #define SOFS 0x0f #define WIDEXFER 0x80 #define ENABLE_CRC 0x40 #define SINGLE_EDGE 0x10 #define SCSIID 0x05 #define SCSIOFFSET 0x05 #define SOFS_ULTRA2 0x7f #define SCSIDATL 0x06 #define SCSIDATH 0x07 #define STCNT 0x08 #define OPTIONMODE 0x08 #define OPTIONMODE_DEFAULTS 0x03 #define AUTORATEEN 0x80 #define AUTOACKEN 0x40 #define ATNMGMNTEN 0x20 #define BUSFREEREV 0x10 #define EXPPHASEDIS 0x08 #define SCSIDATL_IMGEN 0x04 #define AUTO_MSGOUT_DE 0x02 #define DIS_MSGIN_DUALEDGE 0x01 #define TARGCRCCNT 0x0a #define CLRSINT0 0x0b #define CLRSELDO 0x40 #define CLRSELDI 0x20 #define CLRSELINGO 0x10 #define CLRSWRAP 0x08 #define CLRIOERR 0x08 #define CLRSPIORDY 0x02 #define SSTAT0 0x0b #define TARGET 0x80 #define SELDO 0x40 #define SELDI 0x20 #define SELINGO 0x10 #define SWRAP 0x08 #define IOERR 0x08 #define SDONE 0x04 #define SPIORDY 0x02 #define DMADONE 0x01 #define CLRSINT1 0x0c #define CLRSELTIMEO 0x80 #define CLRATNO 0x40 #define CLRSCSIRSTI 0x20 #define CLRBUSFREE 0x08 #define CLRSCSIPERR 0x04 #define CLRPHASECHG 0x02 #define CLRREQINIT 0x01 #define SSTAT1 0x0c #define SELTO 0x80 #define ATNTARG 0x40 #define SCSIRSTI 0x20 #define PHASEMIS 0x10 #define BUSFREE 0x08 #define SCSIPERR 0x04 #define PHASECHG 0x02 #define REQINIT 0x01 #define SSTAT2 0x0d #define SFCNT 0x1f #define OVERRUN 0x80 #define SHVALID 0x40 #define EXP_ACTIVE 0x10 #define CRCVALERR 0x08 #define CRCENDERR 0x04 #define CRCREQERR 0x02 #define DUAL_EDGE_ERR 0x01 #define SSTAT3 0x0e #define SCSICNT 0xf0 #define U2OFFCNT 0x7f #define OFFCNT 0x0f #define SCSIID_ULTRA2 0x0f #define SIMODE0 0x10 #define ENSELDO 0x40 #define ENSELDI 0x20 #define ENSELINGO 0x10 #define ENIOERR 0x08 #define ENSWRAP 0x08 #define ENSDONE 0x04 #define ENSPIORDY 0x02 #define ENDMADONE 0x01 #define SIMODE1 0x11 #define ENSELTIMO 0x80 #define ENATNTARG 0x40 #define ENSCSIRST 0x20 #define ENPHASEMIS 0x10 #define ENBUSFREE 0x08 #define ENSCSIPERR 0x04 #define ENPHASECHG 0x02 #define ENREQINIT 0x01 #define SCSIBUSL 0x12 #define SXFRCTL2 0x13 #define ASYNC_SETUP 0x07 #define AUTORSTDIS 0x10 #define CMDDMAEN 0x08 #define SCSIBUSH 0x13 #define SHADDR 0x14 #define SELTIMER 0x18 #define TARGIDIN 0x18 #define STAGE6 0x20 #define STAGE5 0x10 #define STAGE4 0x08 #define STAGE3 0x04 #define STAGE2 0x02 #define STAGE1 0x01 #define SELID 0x19 #define SELID_MASK 0xf0 #define ONEBIT 0x08 #define SCAMCTL 0x1a #define SCAMLVL 0x03 #define ENSCAMSELO 0x80 #define CLRSCAMSELID 0x40 #define ALTSTIM 0x20 #define DFLTTID 0x10 #define TARGID 0x1b #define SPIOCAP 0x1b #define SOFT1 0x80 #define SOFT0 0x40 #define SOFTCMDEN 0x20 #define EXT_BRDCTL 0x10 #define SEEPROM 0x08 #define EEPROM 0x04 #define ROM 0x02 #define SSPIOCPS 0x01 #define BRDCTL 0x1d #define BRDDAT7 0x80 #define BRDDAT6 0x40 #define BRDDAT5 0x20 #define BRDDAT4 0x10 #define BRDSTB 0x10 #define BRDCS 0x08 #define BRDDAT3 0x08 #define BRDDAT2 0x04 #define BRDRW 0x04 #define BRDCTL1 0x02 #define BRDRW_ULTRA2 0x02 #define BRDCTL0 0x01 #define BRDSTB_ULTRA2 0x01 #define SEECTL 0x1e #define EXTARBACK 0x80 #define EXTARBREQ 0x40 #define SEEMS 0x20 #define SEERDY 0x10 #define SEECS 0x08 #define SEECK 0x04 #define SEEDO 0x02 #define SEEDI 0x01 #define SBLKCTL 0x1f #define DIAGLEDEN 0x80 #define DIAGLEDON 0x40 #define AUTOFLUSHDIS 0x20 #define ENAB40 0x08 #define SELBUSB 0x08 #define ENAB20 0x04 #define SELWIDE 0x02 #define XCVR 0x01 #define BUSY_TARGETS 0x20 #define TARG_SCSIRATE 0x20 #define ULTRA_ENB 0x30 #define CMDSIZE_TABLE 0x30 #define DISC_DSB 0x32 #define CMDSIZE_TABLE_TAIL 0x34 #define MWI_RESIDUAL 0x38 #define TARG_IMMEDIATE_SCB 0x38 #define NEXT_QUEUED_SCB 0x39 #define MSG_OUT 0x3a #define DMAPARAMS 0x3b #define PRELOADEN 0x80 #define WIDEODD 0x40 #define SCSIEN 0x20 #define SDMAENACK 0x10 #define SDMAEN 0x10 #define HDMAEN 0x08 #define HDMAENACK 0x08 #define DIRECTION 0x04 #define FIFOFLUSH 0x02 #define FIFORESET 0x01 #define SEQ_FLAGS 0x3c #define NOT_IDENTIFIED 0x80 #define NO_CDB_SENT 0x40 #define TARGET_CMD_IS_TAGGED 0x40 #define DPHASE 0x20 #define TARG_CMD_PENDING 0x10 #define CMDPHASE_PENDING 0x08 #define DPHASE_PENDING 0x04 #define SPHASE_PENDING 0x02 #define NO_DISCONNECT 0x01 #define SAVED_SCSIID 0x3d #define SAVED_LUN 0x3e #define LASTPHASE 0x3f #define PHASE_MASK 0xe0 #define P_MESGIN 0xe0 #define P_STATUS 0xc0 #define P_MESGOUT 0xa0 #define P_COMMAND 0x80 #define P_DATAIN 0x40 #define P_BUSFREE 0x01 #define P_DATAOUT 0x00 #define CDI 0x80 #define IOI 0x40 #define MSGI 0x20 #define WAITING_SCBH 0x40 #define DISCONNECTED_SCBH 0x41 #define FREE_SCBH 0x42 #define COMPLETE_SCBH 0x43 #define HSCB_ADDR 0x44 #define SHARED_DATA_ADDR 0x48 #define KERNEL_QINPOS 0x4c #define QINPOS 0x4d #define QOUTPOS 0x4e #define KERNEL_TQINPOS 0x4f #define TQINPOS 0x50 #define ARG_1 0x51 #define RETURN_1 0x51 #define SEND_MSG 0x80 #define SEND_SENSE 0x40 #define SEND_REJ 0x20 #define MSGOUT_PHASEMIS 0x10 #define EXIT_MSG_LOOP 0x08 #define CONT_MSG_LOOP 0x04 #define CONT_TARG_SESSION 0x02 #define ARG_2 0x52 #define RETURN_2 0x52 #define LAST_MSG 0x53 #define SCSISEQ_TEMPLATE 0x54 #define ENSELO 0x40 #define ENSELI 0x20 #define ENRSELI 0x10 #define ENAUTOATNO 0x08 #define ENAUTOATNI 0x04 #define ENAUTOATNP 0x02 #define DATA_COUNT_ODD 0x55 #define HA_274_BIOSGLOBAL 0x56 #define INITIATOR_TAG 0x56 #define HA_274_EXTENDED_TRANS 0x01 #define SEQ_FLAGS2 0x57 #define TARGET_MSG_PENDING 0x02 #define SCB_DMA 0x01 #define SCSICONF 0x5a #define HWSCSIID 0x0f #define HSCSIID 0x07 #define TERM_ENB 0x80 #define RESET_SCSI 0x40 #define ENSPCHK 0x20 #define INTDEF 0x5c #define VECTOR 0x0f #define EDGE_TRIG 0x80 #define HOSTCONF 0x5d #define HA_274_BIOSCTRL 0x5f #define BIOSDISABLED 0x30 #define BIOSMODE 0x30 #define CHANNEL_B_PRIMARY 0x08 #define SEQCTL 0x60 #define PERRORDIS 0x80 #define PAUSEDIS 0x40 #define FAILDIS 0x20 #define FASTMODE 0x10 #define BRKADRINTEN 0x08 #define STEP 0x04 #define SEQRESET 0x02 #define LOADRAM 0x01 #define SEQRAM 0x61 #define SEQADDR0 0x62 #define SEQADDR1 0x63 #define SEQADDR1_MASK 0x01 #define ACCUM 0x64 #define SINDEX 0x65 #define DINDEX 0x66 #define ALLONES 0x69 #define NONE 0x6a #define ALLZEROS 0x6a #define FLAGS 0x6b #define ZERO 0x02 #define CARRY 0x01 #define SINDIR 0x6c #define DINDIR 0x6d #define FUNCTION1 0x6e #define STACK 0x6f #define TARG_OFFSET 0x70 #define SRAM_BASE 0x70 #define BCTL 0x84 #define ACE 0x08 #define ENABLE 0x01 #define DSCOMMAND0 0x84 #define CACHETHEN 0x80 #define DPARCKEN 0x40 #define MPARCKEN 0x20 #define EXTREQLCK 0x10 #define INTSCBRAMSEL 0x08 #define RAMPS 0x04 #define USCBSIZE32 0x02 #define CIOPARCKEN 0x01 #define BUSTIME 0x85 #define BOFF 0xf0 #define BON 0x0f #define DSCOMMAND1 0x85 #define DSLATT 0xfc #define HADDLDSEL1 0x02 #define HADDLDSEL0 0x01 #define BUSSPD 0x86 #define DFTHRSH 0xc0 #define DFTHRSH_75 0x80 #define STBOFF 0x38 #define STBON 0x07 #define DSPCISTATUS 0x86 #define DFTHRSH_100 0xc0 #define HS_MAILBOX 0x86 #define HOST_MAILBOX 0xf0 #define HOST_TQINPOS 0x80 #define SEQ_MAILBOX 0x0f #define HCNTRL 0x87 #define POWRDN 0x40 #define SWINT 0x10 #define IRQMS 0x08 #define PAUSE 0x04 #define INTEN 0x02 #define CHIPRST 0x01 #define CHIPRSTACK 0x01 #define HADDR 0x88 #define HCNT 0x8c #define SCBPTR 0x90 #define INTSTAT 0x91 #define SEQINT_MASK 0xf1 #define OUT_OF_RANGE 0xe1 #define NO_FREE_SCB 0xd1 #define SCB_MISMATCH 0xc1 #define MISSED_BUSFREE 0xb1 #define MKMSG_FAILED 0xa1 #define DATA_OVERRUN 0x91 #define PERR_DETECTED 0x81 #define BAD_STATUS 0x71 #define HOST_MSG_LOOP 0x61 #define PDATA_REINIT 0x51 #define IGN_WIDE_RES 0x41 #define NO_MATCH 0x31 #define PROTO_VIOLATION 0x21 #define SEND_REJECT 0x11 #define INT_PEND 0x0f #define BAD_PHASE 0x01 #define BRKADRINT 0x08 #define SCSIINT 0x04 #define CMDCMPLT 0x02 #define SEQINT 0x01 #define ERROR 0x92 #define CIOPARERR 0x80 #define PCIERRSTAT 0x40 #define MPARERR 0x20 #define DPARERR 0x10 #define SQPARERR 0x08 #define ILLOPCODE 0x04 #define ILLSADDR 0x02 #define ILLHADDR 0x01 #define CLRINT 0x92 #define CLRPARERR 0x10 #define CLRBRKADRINT 0x08 #define CLRSCSIINT 0x04 #define CLRCMDINT 0x02 #define CLRSEQINT 0x01 #define DFCNTRL 0x93 #define DFSTATUS 0x94 #define PRELOAD_AVAIL 0x80 #define DFCACHETH 0x40 #define FIFOQWDEMP 0x20 #define MREQPEND 0x10 #define HDONE 0x08 #define DFTHRESH 0x04 #define FIFOFULL 0x02 #define FIFOEMP 0x01 #define DFWADDR 0x95 #define DFRADDR 0x97 #define DFDAT 0x99 #define SCBCNT 0x9a #define SCBCNT_MASK 0x1f #define SCBAUTO 0x80 #define QINFIFO 0x9b #define QINCNT 0x9c #define CRCCONTROL1 0x9d #define CRCONSEEN 0x80 #define CRCVALCHKEN 0x40 #define CRCENDCHKEN 0x20 #define CRCREQCHKEN 0x10 #define TARGCRCENDEN 0x08 #define TARGCRCCNTEN 0x04 #define QOUTFIFO 0x9d #define SCSIPHASE 0x9e #define DATA_PHASE_MASK 0x03 #define STATUS_PHASE 0x20 #define COMMAND_PHASE 0x10 #define MSG_IN_PHASE 0x08 #define MSG_OUT_PHASE 0x04 #define DATA_IN_PHASE 0x02 #define DATA_OUT_PHASE 0x01 #define QOUTCNT 0x9e #define SFUNCT 0x9f #define ALT_MODE 0x80 #define SCB_BASE 0xa0 #define SCB_CDB_PTR 0xa0 #define SCB_CDB_STORE 0xa0 #define SCB_RESIDUAL_DATACNT 0xa0 #define SCB_RESIDUAL_SGPTR 0xa4 #define SCB_SCSI_STATUS 0xa8 #define SCB_TARGET_PHASES 0xa9 #define SCB_TARGET_DATA_DIR 0xaa #define SCB_TARGET_ITAG 0xab #define SCB_DATAPTR 0xac #define SCB_DATACNT 0xb0 #define SG_HIGH_ADDR_BITS 0x7f #define SG_LAST_SEG 0x80 #define SCB_SGPTR 0xb4 #define SG_RESID_VALID 0x04 #define SG_FULL_RESID 0x02 #define SG_LIST_NULL 0x01 #define SCB_CONTROL 0xb8 #define SCB_TAG_TYPE 0x03 #define TARGET_SCB 0x80 #define STATUS_RCVD 0x80 #define DISCENB 0x40 #define TAG_ENB 0x20 #define MK_MESSAGE 0x10 #define ULTRAENB 0x08 #define DISCONNECTED 0x04 #define SCB_SCSIID 0xb9 #define TID 0xf0 #define TWIN_TID 0x70 #define OID 0x0f #define TWIN_CHNLB 0x80 #define SCB_LUN 0xba #define LID 0xff #define SCB_TAG 0xbb #define SCB_CDB_LEN 0xbc #define SCB_SCSIRATE 0xbd #define SCB_SCSIOFFSET 0xbe #define SCB_NEXT 0xbf #define SCB_64_SPARE 0xc0 #define SEECTL_2840 0xc0 #define CS_2840 0x04 #define CK_2840 0x02 #define DO_2840 0x01 #define STATUS_2840 0xc1 #define BIOS_SEL 0x60 #define ADSEL 0x1e #define EEPROM_TF 0x80 #define DI_2840 0x01 #define SCB_64_BTT 0xd0 #define CCHADDR 0xe0 #define CCHCNT 0xe8 #define CCSGRAM 0xe9 #define CCSGADDR 0xea #define CCSGCTL 0xeb #define CCSGDONE 0x80 #define CCSGEN 0x08 #define SG_FETCH_NEEDED 0x02 #define CCSGRESET 0x01 #define CCSCBRAM 0xec #define CCSCBADDR 0xed #define CCSCBCTL 0xee #define CCSCBDONE 0x80 #define ARRDONE 0x40 #define CCARREN 0x10 #define CCSCBEN 0x08 #define CCSCBDIR 0x04 #define CCSCBRESET 0x01 #define CCSCBCNT 0xef #define SCBBADDR 0xf0 #define CCSCBPTR 0xf1 #define HNSCB_QOFF 0xf4 #define SNSCB_QOFF 0xf6 #define SDSCB_QOFF 0xf8 #define QOFF_CTLSTA 0xfa #define SCB_QSIZE 0x07 #define SCB_QSIZE_256 0x06 #define SCB_AVAIL 0x40 #define SNSCB_ROLLOVER 0x20 #define SDSCB_ROLLOVER 0x10 #define DFF_THRSH 0xfb #define WR_DFTHRSH 0x70 #define WR_DFTHRSH_MAX 0x70 #define WR_DFTHRSH_90 0x60 #define WR_DFTHRSH_85 0x50 #define WR_DFTHRSH_75 0x40 #define WR_DFTHRSH_63 0x30 #define WR_DFTHRSH_50 0x20 #define WR_DFTHRSH_25 0x10 #define RD_DFTHRSH_MAX 0x07 #define RD_DFTHRSH 0x07 #define RD_DFTHRSH_90 0x06 #define RD_DFTHRSH_85 0x05 #define RD_DFTHRSH_75 0x04 #define RD_DFTHRSH_63 0x03 #define RD_DFTHRSH_50 0x02 #define RD_DFTHRSH_25 0x01 #define WR_DFTHRSH_MIN 0x00 #define RD_DFTHRSH_MIN 0x00 #define SG_CACHE_SHADOW 0xfc #define SG_ADDR_MASK 0xf8 #define ODD_SEG 0x04 #define LAST_SEG 0x02 #define LAST_SEG_DONE 0x01 #define SG_CACHE_PRE 0xfc #define TARGET_DATA_IN 0x01 #define STATUS_BUSY 0x08 #define BUS_16_BIT 0x01 #define TID_SHIFT 0x04 #define SCB_UPLOAD_SIZE 0x20 #define HOST_MAILBOX_SHIFT 0x04 #define MAX_OFFSET_ULTRA2 0x7f #define SCB_LIST_NULL 0xff #define HOST_MSG 0xff #define MAX_OFFSET 0xff #define BUS_32_BIT 0x02 #define CMD_GROUP_CODE_SHIFT 0x05 #define BUS_8_BIT 0x00 #define CCSGRAM_MAXSEGS 0x10 #define STATUS_QUEUE_FULL 0x28 #define MAX_OFFSET_8BIT 0x0f #define SCB_DOWNLOAD_SIZE_64 0x30 #define MAX_OFFSET_16BIT 0x08 #define TARGET_CMD_CMPLT 0xfe #define SG_SIZEOF 0x08 #define SCB_DOWNLOAD_SIZE 0x20 #define SEQ_MAILBOX_SHIFT 0x00 #define CCSGADDR_MAX 0x80 #define STACK_SIZE 0x04 /* Downloaded Constant Definitions */ #define SG_PREFETCH_CNT 0x04 #define SG_PREFETCH_ADDR_MASK 0x06 #define SG_PREFETCH_ALIGN_MASK 0x05 #define QOUTFIFO_OFFSET 0x00 #define INVERTED_CACHESIZE_MASK 0x03 #define CACHESIZE_MASK 0x02 #define QINFIFO_OFFSET 0x01 #define DOWNLOAD_CONST_COUNT 0x07 /* Exported Labels */ #endif /* AIC7XXX_REG_H */ gxemul-0.6.1/src/include/thirdparty/if_lereg.h000644 001750 001750 00000031707 13402411502 021566 0ustar00debugdebug000000 000000 /* gxemul: $Id: if_lereg.h,v 1.4 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: if_lereg.h,v 1.4 1994/10/26 21:09:08 cgd Exp $ */ #ifndef IF_LEREG_H #define IF_LEREG_H /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)if_lereg.h 8.1 (Berkeley) 6/10/93 */ #define LEMTU 1518 #define LEBLEN 1520 /* LEMTU up to a multiple of 16 */ #define LEMINSIZE 60 /* should be 64 if mode DTCR is set */ #define LERBUF 32 #define LERBUFLOG2 5 #define LE_RLEN (LERBUFLOG2 << 13) #define LETBUF 8 #define LETBUFLOG2 3 #define LE_TLEN (LETBUFLOG2 << 13) /* * LANCE registers. */ struct lereg1 { u_short ler1_rdp; /* data port */ short pad0; u_short ler1_rap; /* register select port */ short pad1; }; /* * This structure is overlayed on the network dual-port RAM. * Currently 32 * 1520 receive plus 8 * 1520 transmit buffers plus * buffer descriptor rings. * There are two variants of the structure, one for the Pmax/3min/maxine * with 2 byte pads between entries and one for the 3max and turbochannel * option densely packed. */ struct lermd { /* +0x0020 */ u_short rmd0; u_short rmd1; short rmd2; u_short rmd3; }; struct letmd { /* +0x0058 */ u_short tmd0; u_short tmd1; short tmd2; u_short tmd3; }; struct lermdpad { /* +0x0020 */ u_short rmd0; short pad0; u_short rmd1; short pad1; short rmd2; short pad2; u_short rmd3; short pad3; }; struct letmdpad { /* +0x0058 */ u_short tmd0; short pad0; u_short tmd1; short pad1; short tmd2; short pad2; u_short tmd3; short pad3; }; struct lereg2 { /* init block */ /* CHIP address */ u_short ler2_mode; /* +0x0000 */ u_short ler2_padr0; /* +0x0002 */ u_short ler2_padr1; /* +0x0004 */ u_short ler2_padr2; /* +0x0006 */ u_short ler2_ladrf0; /* +0x0008 */ u_short ler2_ladrf1; /* +0x000A */ u_short ler2_ladrf2; /* +0x000C */ u_short ler2_ladrf3; /* +0x000E */ u_short ler2_rdra; /* +0x0010 */ u_short ler2_rlen; /* +0x0012 */ u_short ler2_tdra; /* +0x0014 */ u_short ler2_tlen; /* +0x0016 */ short pad0[4]; /* Pad to 16 shorts */ /* receive message descriptors */ struct lermd ler2_rmd[LERBUF]; /* transmit message descriptors */ struct letmd ler2_tmd[LETBUF]; char ler2_rbuf[LERBUF][LEBLEN]; /* +0x0060 */ char ler2_tbuf[LETBUF][LEBLEN]; /* +0x2FD0 */ }; struct lereg2pad { /* init block */ /* CHIP address */ u_short ler2_mode; /* +0x0000 */ short pad0; u_short ler2_padr0; /* +0x0002 */ short pad1; u_short ler2_padr1; /* +0x0004 */ short pad2; u_short ler2_padr2; /* +0x0006 */ short pad3; u_short ler2_ladrf0; /* +0x0008 */ short pad4; u_short ler2_ladrf1; /* +0x000A */ short pad5; u_short ler2_ladrf2; /* +0x000C */ short pad6; u_short ler2_ladrf3; /* +0x000E */ short pad7; u_short ler2_rdra; /* +0x0010 */ short pad8; u_short ler2_rlen; /* +0x0012 */ short pad9; u_short ler2_tdra; /* +0x0014 */ short pad10; u_short ler2_tlen; /* +0x0016 */ short pad11[9]; /* Pad to 32 shorts */ /* receive message descriptors */ struct lermdpad ler2_rmd[LERBUF]; /* transmit message descriptors */ struct letmdpad ler2_tmd[LETBUF]; short ler2_rbuf[LERBUF][LEBLEN]; /* +0x0060 */ short ler2_tbuf[LETBUF][LEBLEN]; /* +0x2FD0 */ }; /* * Now for some truly ugly macros to access the structure fields * padded/non-padded at runtime. (For once, a Pascal like record variant * would be nice to have.) */ #define LER2_RMDADDR(p, i) \ (le->sc_ler2pad ? \ (volatile void *)&(((struct lereg2pad *)(p))->ler2_rmd[(i)]) : \ (volatile void *)&(((struct lereg2 *)(p))->ler2_rmd[(i)])) #define LER2_TMDADDR(p, i) \ ((le->sc_ler2pad ? \ (volatile void *)&(((struct lereg2pad *)(p))->ler2_tmd[(i)]) : \ (volatile void *)&(((struct lereg2 *)(p))->ler2_tmd[(i)]))) #define LER2_RBUFADDR(p, i) \ ((le->sc_ler2pad ? \ (volatile void *)(((struct lereg2pad *)(p))->ler2_rbuf[(i)]) : \ (volatile void *)(((struct lereg2 *)(p))->ler2_rbuf[(i)]))) #define LER2_TBUFADDR(p, i) \ ((le->sc_ler2pad ? \ (volatile void *)(((struct lereg2pad *)(p))->ler2_tbuf[(i)]) : \ (volatile void *)(((struct lereg2 *)(p))->ler2_tbuf[(i)]))) #define LER2_mode(p, v) \ (le->sc_ler2pad ? (((volatile struct lereg2pad *)(p))->ler2_mode = (v)) : \ (((volatile struct lereg2 *)(p))->ler2_mode = (v))) #define LER2V_mode(p) \ (le->sc_ler2pad ? ((volatile struct lereg2pad *)(p))->ler2_mode : \ ((volatile struct lereg2 *)(p))->ler2_mode) #define LER2_padr0(p, v) \ (le->sc_ler2pad ? (((volatile struct lereg2pad *)(p))->ler2_padr0 = (v)) : \ (((volatile struct lereg2 *)(p))->ler2_padr0 = (v))) #define LER2V_padr0(p) \ (le->sc_ler2pad ? ((volatile struct lereg2pad *)(p))->ler2_padr0 : \ ((volatile struct lereg2 *)(p))->ler2_padr0) #define LER2_padr1(p, v) \ (le->sc_ler2pad ? (((volatile struct lereg2pad *)(p))->ler2_padr1 = (v)) : \ (((volatile struct lereg2 *)(p))->ler2_padr1 = (v))) #define LER2V_padr1(p) \ (le->sc_ler2pad ? ((volatile struct lereg2pad *)(p))->ler2_padr1 : \ ((volatile struct lereg2 *)(p))->ler2_padr1) #define LER2_padr2(p, v) \ (le->sc_ler2pad ? (((volatile struct lereg2pad *)(p))->ler2_padr2 = (v)) : \ (((volatile struct lereg2 *)(p))->ler2_padr2 = (v))) #define LER2V_padr2(p) \ (le->sc_ler2pad ? ((volatile struct lereg2pad *)(p))->ler2_padr2 : \ ((volatile struct lereg2 *)(p))->ler2_padr2) #define LER2_ladrf0(p, v) \ (le->sc_ler2pad ? (((volatile struct lereg2pad *)(p))->ler2_ladrf0 = (v)) : \ (((volatile struct lereg2 *)(p))->ler2_ladrf0 = (v))) #define LER2V_ladrf0(p) \ (le->sc_ler2pad ? ((volatile struct lereg2pad *)(p))->ler2_ladrf0 : \ ((volatile struct lereg2 *)(p))->ler2_ladrf0) #define LER2_ladrf1(p, v) \ (le->sc_ler2pad ? (((volatile struct lereg2pad *)(p))->ler2_ladrf1 = (v)) : \ (((volatile struct lereg2 *)(p))->ler2_ladrf1 = (v))) #define LER2V_ladrf1(p) \ (le->sc_ler2pad ? ((volatile struct lereg2pad *)(p))->ler2_ladrf1 : \ ((volatile struct lereg2 *)(p))->ler2_ladrf1) #define LER2_ladrf2(p, v) \ (le->sc_ler2pad ? (((volatile struct lereg2pad *)(p))->ler2_ladrf2 = (v)) : \ (((volatile struct lereg2 *)(p))->ler2_ladrf2 = (v))) #define LER2V_ladrf2(p) \ (le->sc_ler2pad ? ((volatile struct lereg2pad *)(p))->ler2_ladrf2 : \ ((volatile struct lereg2 *)(p))->ler2_ladrf2) #define LER2_ladrf3(p, v) \ (le->sc_ler2pad ? (((volatile struct lereg2pad *)(p))->ler2_ladrf3 = (v)) : \ (((volatile struct lereg2 *)(p))->ler2_ladrf3 = (v))) #define LER2V_ladrf3(p) \ (le->sc_ler2pad ? ((volatile struct lereg2pad *)(p))->ler2_ladrf3 : \ ((volatile struct lereg2 *)(p))->ler2_ladrf3) #define LER2_rdra(p, v) \ (le->sc_ler2pad ? (((volatile struct lereg2pad *)(p))->ler2_rdra = (v)) : \ (((volatile struct lereg2 *)(p))->ler2_rdra = (v))) #define LER2V_rdra(p) \ (le->sc_ler2pad ? ((volatile struct lereg2pad *)(p))->ler2_rdra : \ ((volatile struct lereg2 *)(p))->ler2_rdra) #define LER2_rlen(p, v) \ (le->sc_ler2pad ? (((volatile struct lereg2pad *)(p))->ler2_rlen = (v)) : \ (((volatile struct lereg2 *)(p))->ler2_rlen = (v))) #define LER2V_rlen(p) \ (le->sc_ler2pad ? ((volatile struct lereg2pad *)(p))->ler2_rlen : \ ((volatile struct lereg2 *)(p))->ler2_rlen) #define LER2_tdra(p, v) \ (le->sc_ler2pad ? (((volatile struct lereg2pad *)(p))->ler2_tdra = (v)) : \ (((volatile struct lereg2 *)(p))->ler2_tdra = (v))) #define LER2V_tdra(p) \ (le->sc_ler2pad ? ((volatile struct lereg2pad *)(p))->ler2_tdra : \ ((volatile struct lereg2 *)(p))->ler2_tdra) #define LER2_tlen(p, v) \ (le->sc_ler2pad ? (((volatile struct lereg2pad *)(p))->ler2_tlen = (v)) : \ (((volatile struct lereg2 *)(p))->ler2_tlen = (v))) #define LER2V_tlen(p) \ (le->sc_ler2pad ? ((volatile struct lereg2pad *)(p))->ler2_tlen : \ ((volatile struct lereg2 *)(p))->ler2_tlen) #define LER2_rmd0(p, v) \ (le->sc_ler2pad ? (((volatile struct lermdpad *)(p))->rmd0 = (v)) : \ ((((volatile struct lermd *)(p))->rmd0 = (v)))) #define LER2V_rmd0(p) \ (le->sc_ler2pad ? ((volatile struct lermdpad *)(p))->rmd0 : \ ((volatile struct lermd *)(p))->rmd0) #define LER2_rmd1(p, v) \ (le->sc_ler2pad ? (((volatile struct lermdpad *)(p))->rmd1 = (v)) : \ (((volatile struct lermd *)(p))->rmd1 = (v))) #define LER2V_rmd1(p) \ (le->sc_ler2pad ? ((volatile struct lermdpad *)(p))->rmd1 : \ ((volatile struct lermd *)(p))->rmd1) #define LER2_rmd2(p, v) \ (le->sc_ler2pad ? (((volatile struct lermdpad *)(p))->rmd2 = (v)) : \ (((volatile struct lermd *)(p))->rmd2 = (v))) #define LER2V_rmd2(p) \ (le->sc_ler2pad ? ((volatile struct lermdpad *)(p))->rmd2 : \ ((volatile struct lermd *)(p))->rmd2) #define LER2_rmd3(p, v) \ (le->sc_ler2pad ? (((volatile struct lermdpad *)(p))->rmd3 = (v)) : \ (((volatile struct lermd *)(p))->rmd3 = (v))) #define LER2V_rmd3(p) \ (le->sc_ler2pad ? ((volatile struct lermdpad *)(p))->rmd3 : \ ((volatile struct lermd *)(p))->rmd3) #define LER2_tmd0(p, v) \ (le->sc_ler2pad ? (((volatile struct letmdpad *)(p))->tmd0 = (v)) : \ (((volatile struct letmd *)(p))->tmd0 = (v))) #define LER2V_tmd0(p) \ (le->sc_ler2pad ? ((volatile struct letmdpad *)(p))->tmd0 : \ ((volatile struct letmd *)(p))->tmd0) #define LER2_tmd1(p, v) \ (le->sc_ler2pad ? (((volatile struct letmdpad *)(p))->tmd1 = (v)) : \ (((volatile struct letmd *)(p))->tmd1 = (v))) #define LER2V_tmd1(p) \ (le->sc_ler2pad ? ((volatile struct letmdpad *)(p))->tmd1 : \ ((volatile struct letmd *)(p))->tmd1) #define LER2_tmd2(p, v) \ (le->sc_ler2pad ? (((volatile struct letmdpad *)(p))->tmd2 = (v)) : \ (((volatile struct letmd *)(p))->tmd2 = (v))) #define LER2V_tmd2(p) \ (le->sc_ler2pad ? ((volatile struct letmdpad *)(p))->tmd2 : \ ((volatile struct letmd *)(p))->tmd2) #define LER2_tmd3(p, v) \ (le->sc_ler2pad ? (((volatile struct letmdpad *)(p))->tmd3 = (v)) : \ (((volatile struct letmd *)(p))->tmd3 = (v))) #define LER2V_tmd3(p) \ (le->sc_ler2pad ? ((volatile struct letmdpad *)(p))->tmd3 : \ ((volatile struct letmd *)(p))->tmd3) /* * Control and status bits -- lereg0 */ #define LE_IE 0x80 /* interrupt enable */ #define LE_IR 0x40 /* interrupt requested */ #define LE_LOCK 0x08 /* lock status register */ #define LE_ACK 0x04 /* ack of lock */ #define LE_JAB 0x02 /* loss of tx clock (???) */ #define LE_IPL(x) ((((x) >> 4) & 0x3) + 3) /* * Control and status bits -- lereg1 */ #define LE_CSR0 0 #define LE_CSR1 1 #define LE_CSR2 2 #define LE_CSR3 3 /* (gxemul: NOTE: These are lereg0, not lereg1!) */ #define LE_SERR 0x8000 #define LE_BABL 0x4000 #define LE_CERR 0x2000 #define LE_MISS 0x1000 #define LE_MERR 0x0800 #define LE_RINT 0x0400 #define LE_TINT 0x0200 #define LE_IDON 0x0100 #define LE_INTR 0x0080 #define LE_INEA 0x0040 #define LE_RXON 0x0020 #define LE_TXON 0x0010 #define LE_TDMD 0x0008 #define LE_STOP 0x0004 #define LE_STRT 0x0002 #define LE_INIT 0x0001 #define LE_BSWP 0x4 #define LE_MODE 0x0 /* * Control and status bits -- lereg2 */ /* (gxemul: NOTE: These are not lereg, they are tx/rx descriptors) */ #define LE_OWN 0x8000 #define LE_ERR 0x4000 #define LE_STP 0x0200 #define LE_ENP 0x0100 #define LE_FRAM 0x2000 #define LE_OFLO 0x1000 #define LE_CRC 0x0800 #define LE_RBUFF 0x0400 #define LE_MORE 0x1000 #define LE_ONE 0x0800 #define LE_DEF 0x0400 #define LE_TBUFF 0x8000 #define LE_UFLO 0x4000 #define LE_LCOL 0x1000 #define LE_LCAR 0x0800 #define LE_RTRY 0x0400 #endif /* IF_LEREG_H */ gxemul-0.6.1/src/include/thirdparty/dec_prom.h000644 001750 001750 00000033104 13402411502 021573 0ustar00debugdebug000000 000000 /* gxemul: $Id: dec_prom.h,v 1.7 2006-04-22 08:40:45 debug Exp $ */ #ifndef _PMAX_DEC_PROM_H_ #define _PMAX_DEC_PROM_H_ #ifndef __P #define __P(x) x #endif #ifndef _NO_PROM_DEFINES #define _NO_PROM_DEFINES #endif /* $NetBSD: dec_prom.h,v 1.17 2001/08/24 15:33:17 mhitch Exp $ */ /* * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)dec_prom.h 8.1 (Berkeley) 6/10/93 * * machMon.h -- * * Structures, constants and defines for access to the pmax prom. * * Copyright (C) 1989 Digital Equipment Corporation. * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies. * Digital Equipment Corporation makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machMon.h, * v 9.3 90/02/20 14:34:07 shirriff Exp SPRITE (Berkeley) */ /* * This file was created based on information from the document * "TURBOchannel Firmware Specification" (EK-TCAAD-FS-003) * by Digital Equipment Corporation. */ #ifndef _LOCORE #include /* #include */ /* * Programs loaded by the new PROMs pass the following arguments: * a0 argc * a1 argv * a2 DEC_PROM_MAGIC * a3 The callback vector defined below */ #define DEC_PROM_MAGIC 0x30464354 /* typedef */ struct dec_memmap { uint32_t pagesize; /* system page size */ /* was type int in netbsd */ u_char bitmap[15360]; /* bit for each page indicating safe to use */ } /* memmap */; typedef struct { int revision; /* hardware revision level */ int clk_period; /* clock period in nano seconds */ int slot_size; /* slot size in magabytes */ int io_timeout; /* I/O timeout in cycles */ int dma_range; /* DMA address range in megabytes */ int max_dma_burst; /* maximum DMA burst length */ int parity; /* true if system module supports T.C. parity */ int reserved[4]; } tcinfo; #if 0 /* Not in GXemul. */ typedef int jmp_buf[12]; typedef void (*psig_t)(int); struct callback { void *(*_memcpy) __P((void *s1, void *s2, int n)); /* 00 */ void *(*_memset) __P((void *s1, int c, int n)); /* 04 */ char *(*_strcat) __P((char *s1, char *s2)); /* 08 */ int (*_strcmp) __P((char *s1, char *s2)); /* 0c */ char *(*_strcpy) __P((char *s1, char *s2)); /* 10 */ int (*_strlen) __P((char *s1)); /* 14 */ char *(*_strncat) __P((char *s1, char *s2, int n)); /* 18 */ char *(*_strncpy) __P((char *s1, char *s2, int n)); /* 1c */ int (*_strncmp) __P((char *s1, char *s2, int n)); /* 20 */ int (*_getchar) __P((void)); /* 24 */ char *(*_gets) __P((char *s)); /* 28 */ int (*_puts) __P((char *s)); /* 2c */ int (*_printf) __P((char *fmt, ...)); /* 30 */ int (*_sprintf) __P((char *s, char *fmt, ...)); /* 34 */ int (*_io_poll) __P((void)); /* 38 */ long (*_strtol) __P((char *s, char **endptr, int base)); /* 3c */ psig_t (*_signal) __P((int sig, psig_t func)); /* 40 */ int (*_raise) __P((int sig)); /* 44 */ long (*_time) __P((long *tod)); /* 48 */ int (*_setjmp) __P((jmp_buf env)); /* 4c */ void (*_longjmp) __P((jmp_buf env, int value)); /* 50 */ int (*_bootinit) __P((char *fname)); /* 54 */ int (*_bootread) __P((int b, void *buffer, int n)); /* 58 */ int (*_bootwrite) __P((int b, void *buffer, int n)); /* 5c */ int (*_setenv) __P((char *name, char *value)); /* 60 */ char *(*_getenv) __P((char *name)); /* 64 */ int (*_unsetenv) __P((char *name)); /* 68 */ u_long (*_slot_address) __P((int sn)); /* 6c */ void (*_wbflush) __P((void)); /* 70 */ void (*_msdelay) __P((int delay)); /* 74 */ void (*_leds) __P((int value)); /* 78 */ void (*_clear_cache) __P((char *addr, int len)); /* 7c */ int (*_getsysid) __P((void)); /* 80 */ int (*_getbitmap) __P((struct memmap *map)); /* 84 */ /* gxemul: struct memmap */ int (*_disableintr) __P((int sn)); /* 88 */ int (*_enableintr) __P((int sn)); /* 8c */ int (*_testintr) __P((int sn)); /* 90 */ void *_reserved_data; /* 94 */ int (*_console_init) __P((void)); /* 98 */ void (*_halt) __P((int *v, int cnt)); /* 9c */ void (*_showfault) __P((void)); /* a0 */ tcinfo *(*_gettcinfo) __P((void)); /*XXX* bogus proto */ /* a4 */ int (*_execute_cmd) __P((char *cmd)); /* a8 */ void (*_rex) __P((char cmd)); /* ac */ /* b0 to d4 reserved */ }; extern const struct callback *callv; extern const struct callback callvec; #if defined(_STANDALONE) && !defined(_NO_PROM_DEFINES) #define memcpy (*callv -> _memcpy) #define memset (*callv -> _memset) #define strcat (*callv -> _strcat) #define strcmp (*callv -> _strcmp) #define strcpy (*callv -> _strcpy) #define strlen (*callv -> _strlen) #define strncat (*callv -> _strncat) #define strncpy (*callv -> _strncpy) #define strncmp (*callv -> _strncmp) #define getchar (*callv -> _getchar) #define gets (*callv -> _gets) #define puts (*callv -> _puts) #define printf (*callv -> _printf) #define sprintf (*callv -> _sprintf) #define io_poll (*callv -> _io_poll) #define strtol (*callv -> _strtol) #define raise (*callv -> _raise) #define time (*callv -> _time) #define setjmp (*callv -> _setjmp) #define longjmp (*callv -> _longjmp) #define bootinit (*callv -> _bootinit) #define bootread (*callv -> _bootread) #define bootwrite (*callv -> _bootwrite) #define setenv (*callv -> _setenv) #define getenv (*callv -> _getenv) #define unsetenv (*callv -> _unsetenv) #define wbflush (*callv -> _wbflush) #define msdelay (*callv -> _msdelay) #define leds (*callv -> _leds) #define clear_cache (*callv -> _clear_cache) #define getsysid (*callv -> _getsysid) #define getbitmap (*callv -> _getbitmap) #define disableintr (*callv -> _disableintr) #define enableintr (*callv -> _enableintr) #define testintr (*callv -> _testintr) #define console_init (*callv -> _console_init) #define halt (*callv -> _halt) #define showfault (*callv -> _showfault) #define gettcinfo (*callv -> _gettcinfo) #define execute_cmd (*callv -> _execute_cmd) #define rex (*callv -> _rex) #define bzero(dst, len) memset(dst, 0, len) /* XXX make sure that no calls to bcopy overlap! */ #define bcopy(src, dst, len) memcpy(dst, src, len) #endif #endif /* not in gxemul */ /* * The prom routines use the following structure to hold strings. */ typedef struct { char *argPtr[16]; /* Pointers to the strings. */ char strings[256]; /* Buffer for the strings. */ char *end; /* Pointer to end of used buf. */ int num; /* Number of strings used. */ } MachStringTable; #endif /* _LOCORE */ /* * The prom has a jump table at the beginning of it to get to its * functions. */ #define DEC_PROM_JUMP_TABLE_ADDR 0xBFC00000 /* * Each entry in the jump table is 8 bytes - 4 for the jump and 4 for a nop. */ #define DEC_PROM_FUNC_ADDR(funcNum) (DEC_PROM_JUMP_TABLE_ADDR+((funcNum)*8)) /* * The functions: * * DEC_PROM_RESET Run diags, check bootmode, reinit. * DEC_PROM_EXEC Load new program image. * DEC_PROM_RESTART Re-enter monitor command loop. * DEC_PROM_REINIT Re-init monitor, then cmd loop. * DEC_PROM_REBOOT Check bootmode, no config. * DEC_PROM_AUTOBOOT Autoboot the system. * * The following routines access PROM saio routines and may be used by * standalone programs that would like to use PROM I/O: * * DEC_PROM_OPEN Open a file. * DEC_PROM_READ Read from a file. * DEC_PROM_WRITE Write to a file. * DEC_PROM_IOCTL Iocontrol on a file. * DEC_PROM_CLOSE Close a file. * DEC_PROM_LSEEK Seek on a file. * DEC_PROM_GETCHAR Get character from console. * DEC_PROM_PUTCHAR Put character on console. * DEC_PROM_SHOWCHAR Show a char visibly. * DEC_PROM_GETS gets with editing. * DEC_PROM_PUTS Put string to console. * DEC_PROM_PRINTF Kernel style printf to console. * * PROM protocol entry points: * * DEC_PROM_INITPROTO Initialize protocol. * DEC_PROM_PROTOENABLE Enable protocol mode. * DEC_PROM_PROTODISABLE Disable protocol mode. * DEC_PROM_GETPKT Get protocol packet. * DEC_PROM_PUTPKT Put protocol packet. * * The following are other prom routines: * DEC_PROM_FLUSHCACHE Flush entire cache (). * DEC_PROM_CLEARCACHE Clear I & D cache in range (addr, len). * DEC_PROM_SAVEREGS Save registers in a buffer. * DEC_PROM_LOADREGS Get register back from buffer. * DEC_PROM_JUMPS8 Jump to address in s8. * DEC_PROM_GETENV2 Gets a string from system environment. * DEC_PROM_SETENV2 Sets a string in system environment. * DEC_PROM_ATONUM Converts ascii string to number. * DEC_PROM_STRCMP Compares strings (strcmp). * DEC_PROM_STRLEN Length of string (strlen). * DEC_PROM_STRCPY Copies string (strcpy). * DEC_PROM_STRCAT Appends string (strcat). * DEC_PROM_GETCMD Gets a command. * DEC_PROM_GETNUMS Gets numbers. * DEC_PROM_ARGPARSE Parses string to argc,argv. * DEC_PROM_HELP Help on prom commands. * DEC_PROM_DUMP Dumps memory. * DEC_PROM_SETENV Sets a string in system environment. * DEC_PROM_UNSETENV Unsets a string in system environment * DEC_PROM_PRINTENV Prints system environment * DEC_PROM_JUMP2S8 Jumps to s8 * DEC_PROM_ENABLE Performs prom enable command. * DEC_PROM_DISABLE Performs prom disable command. * DEC_PROM_ZEROB Zeros a system buffer. * DEC_PROM_HALT Handler for halt interrupt. * DEC_PROM_STARTCVAX 58xx VAX Diagnostic Supervisor support. */ #define DEC_PROM_RESET DEC_PROM_FUNC_ADDR(0) #define DEC_PROM_EXEC DEC_PROM_FUNC_ADDR(1) #define DEC_PROM_RESTART DEC_PROM_FUNC_ADDR(2) #define DEC_PROM_REINIT DEC_PROM_FUNC_ADDR(3) #define DEC_PROM_REBOOT DEC_PROM_FUNC_ADDR(4) #define DEC_PROM_AUTOBOOT DEC_PROM_FUNC_ADDR(5) #define DEC_PROM_OPEN DEC_PROM_FUNC_ADDR(6) #define DEC_PROM_READ DEC_PROM_FUNC_ADDR(7) #define DEC_PROM_WRITE DEC_PROM_FUNC_ADDR(8) #define DEC_PROM_IOCTL DEC_PROM_FUNC_ADDR(9) #define DEC_PROM_CLOSE DEC_PROM_FUNC_ADDR(10) #define DEC_PROM_LSEEK DEC_PROM_FUNC_ADDR(11) #define DEC_PROM_GETCHAR DEC_PROM_FUNC_ADDR(12) #define DEC_PROM_PUTCHAR DEC_PROM_FUNC_ADDR(13) #define DEC_PROM_SHOWCHAR DEC_PROM_FUNC_ADDR(14) #define DEC_PROM_GETS DEC_PROM_FUNC_ADDR(15) #define DEC_PROM_PUTS DEC_PROM_FUNC_ADDR(16) #define DEC_PROM_PRINTF DEC_PROM_FUNC_ADDR(17) #define DEC_PROM_INITPROTO DEC_PROM_FUNC_ADDR(18) #define DEC_PROM_PROTOENABLE DEC_PROM_FUNC_ADDR(19) #define DEC_PROM_PROTODISABLE DEC_PROM_FUNC_ADDR(20) #define DEC_PROM_GETPKT DEC_PROM_FUNC_ADDR(21) #define DEC_PROM_PUTPKT DEC_PROM_FUNC_ADDR(22) #define DEC_PROM_FLUSHCACHE DEC_PROM_FUNC_ADDR(28) #define DEC_PROM_CLEARCACHE DEC_PROM_FUNC_ADDR(29) #define DEC_PROM_SAVEREGS DEC_PROM_FUNC_ADDR(30) #define DEC_PROM_LOADREGS DEC_PROM_FUNC_ADDR(31) #define DEC_PROM_JUMPS8 DEC_PROM_FUNC_ADDR(32) #define DEC_PROM_GETENV2 DEC_PROM_FUNC_ADDR(33) #define DEC_PROM_SETENV2 DEC_PROM_FUNC_ADDR(34) #define DEC_PROM_ATONUM DEC_PROM_FUNC_ADDR(35) #define DEC_PROM_STRCMP DEC_PROM_FUNC_ADDR(36) #define DEC_PROM_STRLEN DEC_PROM_FUNC_ADDR(37) #define DEC_PROM_STRCPY DEC_PROM_FUNC_ADDR(38) #define DEC_PROM_STRCAT DEC_PROM_FUNC_ADDR(39) #define DEC_PROM_GETCMD DEC_PROM_FUNC_ADDR(40) #define DEC_PROM_GETNUMS DEC_PROM_FUNC_ADDR(41) #define DEC_PROM_ARGPARSE DEC_PROM_FUNC_ADDR(42) #define DEC_PROM_HELP DEC_PROM_FUNC_ADDR(43) #define DEC_PROM_DUMP DEC_PROM_FUNC_ADDR(44) #define DEC_PROM_SETENV DEC_PROM_FUNC_ADDR(45) #define DEC_PROM_UNSETENV DEC_PROM_FUNC_ADDR(46) #define DEC_PROM_PRINTENV DEC_PROM_FUNC_ADDR(47) #define DEC_PROM_JUMP2S8 DEC_PROM_FUNC_ADDR(48) #define DEC_PROM_ENABLE DEC_PROM_FUNC_ADDR(49) #define DEC_PROM_DISABLE DEC_PROM_FUNC_ADDR(50) #define DEC_PROM_ZEROB DEC_PROM_FUNC_ADDR(51) #define DEC_PROM_HALT DEC_PROM_FUNC_ADDR(54) #define DEC_PROM_STARTCVAX DEC_PROM_FUNC_ADDR(97) /* * The nonvolatile ram has a flag to indicate it is usable. */ #define MACH_USE_NON_VOLATILE ((char *)0xbd0000c0) #define MACH_NON_VOLATILE_FLAG 0x02 #define DEC_REX_MAGIC 0x30464354 /* REX Magic number */ #endif /* !_PMAX_DEC_PROM_H_ */ gxemul-0.6.1/src/include/thirdparty/dreamcast_sysasicvar.h000644 001750 001750 00000010541 13402411502 024215 0ustar00debugdebug000000 000000 /* GXemul: $Id: dreamcast_sysasicvar.h,v 1.2 2006-10-28 01:37:54 debug Exp $ */ /* $NetBSD: sysasicvar.h,v 1.5 2005/12/24 23:24:00 perry Exp $ */ /* * Extended with useful macros and also some more event definitions * described in KOS comments by Dan Potter (kos/kernel/arch/dreamcast * /hardware/asic.c). */ #ifndef _DREAMCAST_SYSASICVAR_H_ #define _DREAMCAST_SYSASICVAR_H_ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #define SYSASIC_BASE 0x5f6900 #define SYSASIC_SIZE 0x100 #define SYSASIC_EVENT_RENDERDONE 2 /* Render Completed */ #define SYSASIC_EVENT_PVR_SCANINT1 3 /* Scanline interrupt 1 */ #define SYSASIC_EVENT_PVR_SCANINT2 4 /* Scanline interrupt 2 */ #define SYSASIC_EVENT_VBLINT 5 /* VBlank interrupt */ #define SYSASIC_EVENT_OPAQUEDONE 7 /* Opaque list complete */ #define SYSASIC_EVENT_OPAQUEMODDONE 8 /* Opaque modifiers complete */ #define SYSASIC_EVENT_TRANSDONE 9 /* Transparent list complete */ #define SYSASIC_EVENT_TRANSMODDONE 10 /* Trans. modifiers complete */ #define SYSASIC_EVENT_MAPLE_DMADONE 12 /* Maple DMA complete */ #define SYSASIC_EVENT_MAPLE_ERROR 13 /* Maple error */ #define SYSASIC_EVENT_GDROM_DMA 14 /* GD-ROM DMA Complete */ #define SYSASIC_EVENT_SPU_DMA 15 /* SPU DMA Complete */ #define SYSASIC_EVENT_SPU_IRQ 17 /* SPU Interrupt */ #define SYSASIC_EVENT_PVR_DMA 19 /* PVR DMA Complete */ #define SYSASIC_EVENT_PVR_PTDONE 21 /* Punch-through complete */ #define SYSASIC_EVENT_GDROM 32 /* GD-ROM Command status */ #define SYSASIC_EVENT_AICA 33 /* AICA (?) */ #define SYSASIC_EVENT_8BIT 34 /* Modem/Lan adapter */ #define SYSASIC_EVENT_EXT 35 /* PCI/BBA IRQ */ #define SYSASIC_EVENT_PRIMOUTOFMEM 66 /* Out of primitive mem */ #define SYSASIC_EVENT_MATOUTOFMEM 67 /* Out of matrix mem */ #define SYSASIC_EVENT_TO_ADDR(e) (SYSASIC_BASE + 4*((e)>>5)) #define SYSASIC_EVENT_TO_BITMASK(e) (1 << ((e) & 31)) #define SYSASIC_TRIGGER_EVENT(e) { \ uint8_t buf[8]; \ uint64_t tmp1 = SYSASIC_EVENT_TO_ADDR(e); \ uint64_t tmp2 = SYSASIC_EVENT_TO_BITMASK(e); \ tmp2 |= 0x100000000ULL; /* Internal GXemul hack */ \ memory_writemax64(cpu, buf, 8, tmp2); \ cpu->memory_rw(cpu, cpu->mem, tmp1, buf, 8, \ MEM_WRITE, PHYSICAL); \ } #if 0 const char *__pure sysasic_intr_string(int /*ipl*/) __attribute__((const)); void *sysasic_intr_establish(int /*event*/, int /*ipl*/, int (*ih_fun)(void *), void *); void sysasic_intr_disestablish(void *); void sysasic_intr_enable(void *, int /*on*/); #endif #endif /* !_DREAMCAST_SYSASICVAR_H_ */ gxemul-0.6.1/src/include/thirdparty/bt431reg.h000644 001750 001750 00000004262 13402411502 021341 0ustar00debugdebug000000 000000 /* gxemul: $Id: bt431reg.h,v 1.2 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: bt431reg.h,v 1.1 1998/10/28 04:10:37 nisimura Exp $ */ #ifndef BT431REG_H #define BT431REG_H /* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ /* * Register definitions for the Brooktree Bt431 Monolithic CMOS * 64x64 Pixel Cursor Generator. */ #define BT431_REG_COMMAND 0x000 #define BT431_REG_CURSOR_X_LOW 0x001 #define BT431_REG_CURSOR_X_HIGH 0x002 #define BT431_REG_CURSOR_Y_LOW 0x003 #define BT431_REG_CURSOR_Y_HIGH 0x004 #define BT431_REG_WXLO 0x005 #define BT431_REG_WXHI 0x006 #define BT431_REG_WYLO 0x007 #define BT431_REG_WYHI 0x008 #define BT431_REG_WWLO 0x009 #define BT431_REG_WWHI 0x00a #define BT431_REG_WHLO 0x00b #define BT431_REG_WHHI 0x00c #define BT431_REG_CRAM_BASE 0x000 #define BT431_REG_CRAM_END 0x1ff #define BT431_CMD_CURS_ENABLE 0x40 #define BT431_CMD_XHAIR_ENABLE 0x20 #define BT431_CMD_OR_CURSORS 0x10 #define BT431_CMD_AND_CURSORS 0x00 #define BT431_CMD_1_1_MUX 0x00 #define BT431_CMD_4_1_MUX 0x04 #define BT431_CMD_5_1_MUX 0x08 #define BT431_CMD_xxx_MUX 0x0c #define BT431_CMD_THICK_1 0x00 #define BT431_CMD_THICK_3 0x01 #define BT431_CMD_THICK_5 0x02 #define BT431_CMD_THICK_7 0x03 #endif /* BT431REG_H */ gxemul-0.6.1/src/include/thirdparty/mvme_pcctworeg.h000644 001750 001750 00000006726 13402411502 023036 0ustar00debugdebug000000 000000 /* $OpenBSD: pcctworeg.h,v 1.8 2006/04/27 20:19:28 miod Exp $ */ #ifndef MVME_PCCTWOREG_H #define MVME_PCCTWOREG_H /* * Memory map for PCC2 chip found in MVME1x7 boards. * * PCCchip2 control and status register can be accessed as bytes (8 bits), * two-bytes (16 bits), or four-bytes (32 bits). */ #define PCC2_BASE 0xfff42000 #define PCC2_SIZE 0x0040 #define PCCTWO_CHIPID 0x0000 #define PCCTWO_CHIPREV 0x0001 #define PCCTWO_GENCTL 0x0002 #define PCCTWO_VECBASE 0x0003 #define PCCTWO_T1CMP 0x0004 #define PCCTWO_T1COUNT 0x0008 #define PCCTWO_T2CMP 0x000c #define PCCTWO_T2COUNT 0x0010 #define PCCTWO_PSCALECNT 0x0014 #define PCCTWO_PSCALEADJ 0x0015 #define PCCTWO_T2CTL 0x0016 #define PCCTWO_T1CTL 0x0017 #define PCCTWO_GPIO_ICR 0x0018 #define PCCTWO_GPIO_PCR 0x0019 #define PCCTWO_T2ICR 0x001a #define PCCTWO_T1ICR 0x001b #define PCCTWO_SCCERR 0x001c #define PCCTWO_SCCICR 0x001d #define PCCTWO_SCCTX 0x001e #define PCCTWO_SCCRX 0x001f #define PCCTWO_SCCMOIACK 0x0023 #define PCCTWO_SCCTXIACK 0x0025 #define PCCTWO_SCCRXIACK 0x0027 #define PCCTWO_IEERR 0x0028 #define PCCTWO_IEICR 0x002a #define PCCTWO_IEBERR 0x002b #define PCCTWO_SCSIERR 0x002c #define PCCTWO_SCSIICR 0x002f #define PCCTWO_PRTICR 0x0030 #define PCCTWO_PTRFICR 0x0031 #define PCCTWO_PTRSICR 0x0032 #define PCCTWO_PTRPICR 0x0033 #define PCCTWO_PRTBICR 0x0034 #define PCCTWO_PRTSTATUS 0x0036 #define PCCTWO_PRTCTL 0x0037 #define PCCTWO_SPEED 0x0038 #define PCCTWO_PRTDATA 0x003a /* The following registers are not valid on MVME197 */ #define PCCTWO_IPL 0x003e #define PCCTWO_MASK 0x003f #define PCC2_ID 0x20 /* value at CHIPID */ /* General Control Register */ #define PCC2_DR0 0x80 #define PCC2_C040 0x04 #define PCC2_MIEN 0x02 #define PCC2_FAST 0x01 /* Top 4 bits of the PCC2 VBR. Will be the top 4 bits of the vector */ #define PCC2_VECT 0x50 /* Bottom 4 bits of the vector returned during IACK cycle */ #define PCC2V_PPBUSY 0x00 /* lowest */ #define PCC2V_PPPE 0x01 #define PCC2V_PPSELECT 0x02 #define PCC2V_PPFAULT 0x03 #define PCC2V_PPACK 0x04 #define PCC2V_SCSI 0x05 #define PCC2V_IEFAIL 0x06 #define PCC2V_IE 0x07 #define PCC2V_TIMER2 0x08 #define PCC2V_TIMER1 0x09 #define PCC2V_GPIO 0x0a #define PCC2V_SCC_RXE 0x0c #define PCC2V_SCC_M (PCC2V_SCC_RXE + 1) #define PCC2V_SCC_TX (PCC2V_SCC_M + 1) #define PCC2V_SCC_RX (PCC2V_SCC_TX + 1) #if 0 /* * Vaddrs for interrupt mask and pri registers */ extern u_int8_t *volatile pcc2intr_mask; extern u_int8_t *volatile pcc2intr_ipl; #endif /* * We lock off our interrupt vector at 0x50. */ #define PCC2_VECBASE 0x50 #define PCC2_NVEC 0x10 #define PCC2_TCTL_CEN 0x01 #define PCC2_TCTL_COC 0x02 #define PCC2_TCTL_COVF 0x04 #define PCC2_TCTL_OVF 0xf0 #define PCC2_GPIO_PLTY 0x80 #define PCC2_GPIO_EL 0x40 #define PCC2_GPIOCR_OE 0x2 #define PCC2_GPIOCR_O 0x1 #define PCC2_SCC_AVEC 0x08 #define PCC2_SC_INHIBIT (0 << 6) #define PCC2_SC_SNOOP (1 << 6) #define PCC2_SC_INVAL (2 << 6) #define PCC2_SC_RESV (3 << 6) #define pcc2_timer_us2lim(us) (us) /* timer increments in "us" */ #define PCC2_IRQ_IPL 0x07 #define PCC2_IRQ_ICLR 0x08 #define PCC2_IRQ_IEN 0x10 #define PCC2_IRQ_INT 0x20 /* Tick Timer Interrupt Control Register */ #define PCC2_TTIRQ_INT 0x20 #define PCC2_TTIRQ_IEN 0x10 #define PCC2_TTIRQ_ICLR 0x08 #define PCC2_TTIRQ_IL 0x07 /* mask for IL2-IL0 */ #define PCC2_IEERR_SCLR 0x01 #define PCC2_GENCTL_FAST 0x01 #define PCC2_GENCTL_IEN 0x02 #define PCC2_GENCTL_C040 0x03 #endif /* MVME_PCCTWOREG_H */ gxemul-0.6.1/src/include/thirdparty/m88k_psl.h000644 001750 001750 00000007536 13402411502 021462 0ustar00debugdebug000000 000000 /* $OpenBSD: psl.h,v 1.4 2005/09/25 22:41:12 miod Exp $ */ /* * Copyright (c) 1996 Nivas Madhur * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Nivas Madhur. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* * Mach Operating System * Copyright (c) 1991 Carnegie Mellon University * Copyright (c) 1991 OMRON Corporation * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * */ #ifndef __M88K_PSL_H__ #define __M88K_PSL_H__ /* #ifdef _KERNEL */ /* * 881x0 control registers */ /* * processor identification register (PID) */ #define M88K_PID_ARN 0x0000ff00 /* architectural revision number */ #define M88K_ARN_SHIFT 8 #define M88K_ARN_88100 0x00 #define M88K_ARN_88110 0x01 #define M88K_PID_VN 0x000000fe /* version number */ #define M88K_VN_SHIFT 1 #define M88K_PID_MC 0x00000001 /* 88100 master/checker mode */ /* * processor status register */ #define M88K_PSR_MODE 0x80000000 /* supervisor/user mode */ #define M88K_PSR_BO 0x40000000 /* byte-ordering 0:big 1:little */ #define M88K_PSR_SER 0x20000000 /* 88110 serial mode */ #define M88K_PSR_C 0x10000000 /* carry */ #define M88K_PSR_SGN 0x04000000 /* 88110 Signed Immediate mode */ #define M88K_PSR_SRM 0x02000000 /* 88110 Serialize Memory */ #define M88K_PSR_TRACE 0x00800000 /* 88110 hardware trace */ #define M88K_PSR_SFD 0x000003e0 /* SFU disable */ #define M88K_PSR_SFD2 0x00000010 /* 88110 SFU2 (Graphics) disable */ #define M88K_PSR_SFD1 0x00000008 /* SFU1 (FPU) disable */ #define M88K_PSR_MXM 0x00000004 /* misaligned access enable */ #define M88K_PSR_IND 0x00000002 /* interrupt disable */ #define M88K_PSR_SFRZ 0x00000001 /* shadow freeze */ #define M88K_FIP_V 0x00000002 /* valid */ #define M88K_FIP_E 0x00000001 /* exception */ #define M88K_FIP_ADDR 0xfffffffc /* address mask */ #define M88K_NIP_V 0x00000002 /* valid */ #define M88K_NIP_E 0x00000001 /* exception */ #define M88K_NIP_ADDR 0xfffffffc /* address mask */ #define M88K_XIP_V 0x00000002 /* valid */ #define M88K_XIP_E 0x00000001 /* exception */ #define M88K_XIP_ADDR 0xfffffffc /* address mask */ /* #endif */ #endif /* __M88K_PSL_H__ */ gxemul-0.6.1/src/include/thirdparty/dec_kmin.h000644 001750 001750 00000026133 13402411502 021560 0ustar00debugdebug000000 000000 /* gxemul: $Id: dec_kmin.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ #ifndef MIPS_KMIN_H #define MIPS_KMIN_H 1 #include "tc_ioasicreg.h" /* $NetBSD: kmin.h,v 1.8 2000/02/29 04:41:55 nisimura Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * The Mach Operating System project at Carnegie-Mellon University, * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)kmin.h 8.1 (Berkeley) 6/10/93 */ /* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * HISTORY * Log: kmin.h,v * Revision 2.3 92/03/02 18:33:43 rpd * Split out the ASIC defns into separate file, which is * in common with MAXine. Added some nitwits defines. * [92/03/02 02:28:27 af] * * Revision 2.2 91/08/24 12:21:08 af * Documented new SCSI registers, which were missing in the 3min prototype. * [91/08/22 11:14:57 af] * * Created, from the DEC specs: * "3MIN System Module Functional Specification" Revision 1.7 * Workstation Systems Engineering, Palo Alto, CA. Sept 14, 1990. * "KN02BA Daughter Card Functional Specification" Revision 1.0 * Workstation Systems Engineering, Palo Alto, CA. Aug 14, 1990. * [91/06/21 af] * */ /* * File: kmin.h * Author: Alessandro Forin, Carnegie Mellon University * Date: 6/91 * * Definitions specific to the KN02BA/KN02DA processors and 3MIN * system module (54-20604-01) */ /* * 3MIN's Physical address space */ #define KMIN_PHYS_MIN 0x00000000 /* 512 Meg */ #define KMIN_PHYS_MAX 0x1fffffff /* * Memory map */ #define KMIN_PHYS_MEMORY_START 0x00000000 #define KMIN_PHYS_MEMORY_END 0x07ffffff /* 128 Meg in 8 slots */ /* * I/O map */ #define KMIN_PHYS_RESERVED 0x08000000 /* Reserved */ /* 64 Meg */ #define KMIN_PHYS_MREGS_START 0x0c000000 /* Memory control registers */ #define KMIN_PHYS_MREGS_END 0x0dffffff /* 32 Meg */ #define KMIN_PHYS_CREGS_START 0x0e000000 /* CPU ASIC control regs */ #define KMIN_PHYS_CREGS_END 0x0fffffff /* 32 Meg */ #define KMIN_PHYS_TC_0_START 0x10000000 /* TURBOchannel, slot 0 */ #define KMIN_PHYS_TC_0_END 0x13ffffff /* 64 Meg, option0 */ #define KMIN_PHYS_TC_1_START 0x14000000 /* TURBOchannel, slot 1 */ #define KMIN_PHYS_TC_1_END 0x17ffffff /* 64 Meg, option1 */ #define KMIN_PHYS_TC_2_START 0x18000000 /* TURBOchannel, slot 2 */ #define KMIN_PHYS_TC_2_END 0x1bffffff /* 64 Meg, option2 */ #define KMIN_PHYS_TC_3_START 0x1c000000 /* TURBOchannel, slot 3 */ #define KMIN_PHYS_TC_3_END 0x1fffffff /* 64 Meg, system devices */ #define KMIN_PHYS_TC_START KMIN_PHYS_TC_0_START #define KMIN_PHYS_TC_END KMIN_PHYS_TC_3_END /* 256 Meg */ #define KMIN_TC_NSLOTS 4 #define KMIN_TC_MIN 0 #define KMIN_TC_MAX 2 /* don't look at system slot */ /* * System module space (IOASIC) */ #define KMIN_SYS_ASIC ( KMIN_PHYS_TC_3_START + 0x0000000 ) #define KMIN_SYS_ROM_START ( KMIN_SYS_ASIC + IOASIC_SLOT_0_START ) #define KMIN_SYS_ASIC_REGS ( KMIN_SYS_ASIC + IOASIC_SLOT_1_START ) #define KMIN_SYS_ETHER_ADDRESS ( KMIN_SYS_ASIC + IOASIC_SLOT_2_START ) #define KMIN_SYS_LANCE ( KMIN_SYS_ASIC + IOASIC_SLOT_3_START ) #define KMIN_SYS_SCC_0 ( KMIN_SYS_ASIC + IOASIC_SLOT_4_START ) #define KMIN_SYS_SCC_1 ( KMIN_SYS_ASIC + IOASIC_SLOT_6_START ) #define KMIN_SYS_CLOCK ( KMIN_SYS_ASIC + IOASIC_SLOT_8_START ) #define KMIN_SYS_SCSI ( KMIN_SYS_ASIC + IOASIC_SLOT_12_START ) #define KMIN_SYS_SCSI_DMA ( KMIN_SYS_ASIC + IOASIC_SLOT_14_START ) #define KMIN_SYS_BOOT_ROM_START ( KMIN_PHYS_TC_3_START + 0x3c00000 ) #define KMIN_SYS_BOOT_ROM_END ( KMIN_PHYS_TC_3_START + 0x3c40000 ) /* * Interrupts */ #define KMIN_INT_FPA IP_LEV7 /* Floating Point coproc */ #define KMIN_INT_HALTB IP_LEV6 /* Halt button */ #define KMIN_INT_TC3 IP_LEV5 /* TC slot 3, system */ #define KMIN_INT_TC2 IP_LEV4 /* TC option slot 2 */ #define KMIN_INT_TC1 IP_LEV3 /* TC option slot 1 */ #define KMIN_INT_TC0 IP_LEV2 /* TC option slot 0 */ /* * System registers addresses (MREG and CREG space, and IO Control ASIC) */ #define KMIN_REG_MER 0x0c400000 /* Memory error register */ #define KMIN_REG_MSR 0x0c800000 /* Memory size register */ #define KMIN_REG_CNFG 0x0e000000 /* Config mem timeouts */ #define KMIN_REG_AER 0x0e000004 /* Address error register */ #define KMIN_REG_BOOT 0x0e000008 /* Boot 0 register */ #define KMIN_REG_TIMEOUT 0x0e00000c /* Mem access timeout reg */ #define KMIN_REG_SCSI_DMAPTR ( KMIN_SYS_ASIC + IOASIC_SCSI_DMAPTR ) #define KMIN_REG_SCSI_DMANPTR ( KMIN_SYS_ASIC + IOASIC_SCSI_NEXTPTR ) #define KMIN_REG_LANCE_DMAPTR ( KMIN_SYS_ASIC + IOASIC_LANCE_DMAPTR ) #define KMIN_REG_SCC_T1_DMAPTR ( KMIN_SYS_ASIC + IOASIC_SCC_T1_DMAPTR ) #define KMIN_REG_SCC_R1_DMAPTR ( KMIN_SYS_ASIC + IOASIC_SCC_R1_DMAPTR ) #define KMIN_REG_SCC_T2_DMAPTR ( KMIN_SYS_ASIC + IOASIC_SCC_T2_DMAPTR ) #define KMIN_REG_SCC_R2_DMAPTR ( KMIN_SYS_ASIC + IOASIC_SCC_R2_DMAPTR ) #define KMIN_REG_CSR ( KMIN_SYS_ASIC + IOASIC_CSR ) #define KMIN_REG_INTR ( KMIN_SYS_ASIC + IOASIC_INTR ) #define KMIN_REG_IMSK ( KMIN_SYS_ASIC + IOASIC_IMSK ) #define KMIN_REG_CURADDR ( KMIN_SYS_ASIC + IOASIC_CURADDR ) #define KMIN_REG_LANCE_DECODE ( KMIN_SYS_ASIC + IOASIC_LANCE_DECODE ) #define KMIN_REG_SCSI_DECODE ( KMIN_SYS_ASIC + IOASIC_SCSI_DECODE ) #define KMIN_REG_SCC0_DECODE ( KMIN_SYS_ASIC + IOASIC_SCC0_DECODE ) #define KMIN_REG_SCC1_DECODE ( KMIN_SYS_ASIC + IOASIC_SCC1_DECODE ) # define KMIN_LANCE_CONFIG 3 # define KMIN_SCSI_CONFIG 14 # define KMIN_SCC0_CONFIG (0x10|4) # define KMIN_SCC1_CONFIG (0x10|6) #define KMIN_REG_SCSI_SCR ( KMIN_SYS_ASIC + IOASIC_SCSI_SCR ) #define KMIN_REG_SCSI_SDR0 ( KMIN_SYS_ASIC + IOASIC_SCSI_SDR0 ) #define KMIN_REG_SCSI_SDR1 ( KMIN_SYS_ASIC + IOASIC_SCSI_SDR1 ) /* * System registers defines (MREG and CREG) */ /* Memory error register */ #define KMIN_MER_xxx 0xfffe30ff /* undefined */ #define KMIN_MER_PAGE_BRY 0x00010000 /* rw: Page boundary error */ #define KMIN_MER_TLEN 0x00008000 /* rw: Xfer length error */ #define KMIN_MER_PARDIS 0x00004000 /* rw: Dis parity err intr */ #define KMIN_MER_LASTBYTE 0x00000f00 /* rz: Last byte in error: */ # define KMIN_LASTB31 0x00000800 /* upper byte of word */ # define KMIN_LASTB23 0x00000400 /* .. through .. */ # define KMIN_LASTB15 0x00000200 /* .. the .. */ # define KMIN_LASTB07 0x00000100 /* .. lower byte */ /* Memory size register */ #define KMIN_MSR_SIZE_16Mb 0x00002000 /* rw: using 16Mb mem banks */ #define KMIN_MSR_xxx 0xffffdfff /* undefined */ /* NOTES Memory access priority is, from higher to lower: - DRAM refresh - IO DMA (IO Control ASIC) - Processor - Slot 2 DMA - Slot 1 DMA - Slot 0 DMA Memory performance is (with 80ns mem cycles) - single word read 5 cyc 10.0 Mb/s - word write 3 cyc 16.7 Mb/s - single byte write 3 cyc 4.2 Mb/s - 64w DMA read 68 cyc 47.1 Mb/s - 64w DMA write 66 cyc 48.5 Mb/s - Refresh 5 cyc N/A */ /* Timeout config register */ #define KMIN_CNFG_VALUE_12Mhz 127 #define KMIN_CNFG_VALUE_25Mhz 0 /* Address error register */ #define KMIN_AER_ADDR_MASK 0x1ffffffc /* ro: phys addr in error */ /* Boot 0 register */ #define KMIN_BOOT_FROM_SLOT0 0x00000001 /* rw: diag board boot */ /* Memory access timeout interrupt register */ #define KMIN_TIMEO_INTR 0x00000001 /* rc: intr pending */ /* * More system registers defines (IOASIC) */ /* (re)defines for the system Status and Control register (SSR) */ /* high-order 16 bits 0xFFFF0000 same on all DECstation IOASICs */ #define KMIN_CSR_DIAGDN 0x00008000 /* rw */ #define KMIN_CSR_TXDIS_2 0x00004000 /* rw */ #define KMIN_CSR_TXDIS_1 0x00002000 /* rw */ #define KMIN_CSR_SCC_ENABLE 0x00000800 /* rw */ #define KMIN_CSR_RTC_ENABLE 0x00000400 /* rw */ #define KMIN_CSR_SCSI_ENABLE 0x00000200 /* rw */ #define KMIN_CSR_LANCE_ENABLE 0x00000100 /* rw */ #define KMIN_CSR_LEDS 0x000000ff /* rw */ /* (re)defines for the System Interrupt and Mask Registers */ /* high-order 16 bits 0xFFFF0000 same on all DECstation IOASICs */ #define KMIN_INTR_NVR_JUMPER 0x00004000 /* ro */ #define KMIN_INTR_TIMEOUT 0x00001000 /* ro */ #define KMIN_INTR_NRMOD_JUMPER 0x00000400 /* ro */ #define KMIN_INTR_SCSI 0x00000200 /* ro */ #define KMIN_INTR_LANCE 0x00000100 /* ro */ #define KMIN_INTR_SCC_1 0x00000080 /* ro */ #define KMIN_INTR_SCC_0 0x00000040 /* ro */ #define KMIN_INTR_CLOCK 0x00000020 /* ro */ #define KMIN_INTR_PSWARN 0x00000010 /* ro */ #define KMIN_INTR_SCSI_FIFO 0x00000004 /* ro */ #define KMIN_INTR_PBNC 0x00000002 /* ro */ #define KMIN_INTR_PBNO 0x00000001 /* ro */ #define KMIN_INTR_ASIC 0xff0f0004 #define KMIN_IM0 0xff0f13f0 /* all good ones enabled */ #endif /* MIPS_KMIN_H */ gxemul-0.6.1/src/include/thirdparty/clmpccreg.h000644 001750 001750 00000054165 13402411502 021754 0ustar00debugdebug000000 000000 /* GXemul: $Id: clmpccreg.h,v 1.1 2007-05-15 12:35:14 debug Exp $ */ /* $NetBSD: clmpccreg.h,v 1.3 1999/11/28 12:23:18 scw Exp $ */ #ifndef __clmpccreg_h #define __clmpccreg_h /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Steve C. Woodford. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Register definitions for the Cirrus Logic CD2400/CD2401 * Four Channel Multi-Protocol Communications Controller. * * The values defined here are based on the August 1993 data book. * At the present time, this driver supports non-DMA async. mode only. */ /* * Register offsets depend on the level on the chip's BYTESWAP pin. * When BYTESWAP is low, Motorola byte alignment is in effect. * Otherwise, Intel byte alignment is in effect. * The values given here assume BYTESWAP is low. See 'sc_byteswap' * . */ /* Number of bytes of FIFO (Rx & Tx) */ #define CLMPCC_FIFO_DEPTH 16 /* Global Registers */ #define CLMPCC_REG_GFRCR 0x81 /* Global Firmware Revision Code Register */ #define CLMPCC_REG_CAR 0xee /* Channel Access Register */ /* Option Registers */ #define CLMPCC_REG_CMR 0x1b /* Channel Mode Register */ #define CLMPCC_REG_COR1 0x10 /* Channel Option Register #1 */ #define CLMPCC_REG_COR2 0x17 /* Channel Option Register #2 */ #define CLMPCC_REG_COR3 0x16 /* Channel Option Register #3 */ #define CLMPCC_REG_COR4 0x15 /* Channel Option Register #4 */ #define CLMPCC_REG_COR5 0x14 /* Channel Option Register #5 */ #define CLMPCC_REG_COR6 0x18 /* Channel Option Register #6 */ #define CLMPCC_REG_COR7 0x07 /* Channel Option Register #7 */ #define CLMPCC_REG_SCHR1 0x1f /* Special Character Register #1 */ #define CLMPCC_REG_SCHR2 0x1e /* Special Character Register #2 */ #define CLMPCC_REG_SCHR3 0x1d /* Special Character Register #3 */ #define CLMPCC_REG_SCHR4 0x1c /* Special Character Register #4 */ #define CLMPCC_REG_SCRl 0x23 /* Special Character Range (low) */ #define CLMPCC_REG_SCRh 0x22 /* Special Character Range (high) */ #define CLMPCC_REG_LNXT 0x2e /* LNext Character */ #define CLMPCC_REG_RFAR1 0x1f /* Receive Frame Address Register #1 */ #define CLMPCC_REG_RFAR2 0x1e /* Receive Frame Address Register #2 */ #define CLMPCC_REG_RFAR3 0x1d /* Receive Frame Address Register #3 */ #define CLMPCC_REG_RFAR4 0x1c /* Receive Frame Address Register #4 */ #define CLMPCC_REG_CPSR 0xd6 /* CRC Polynomial Select Register */ /* Bit Rate and Clock Option Registers */ #define CLMPCC_REG_RBPR 0xcb /* Receive Baud Rate Period Register */ #define CLMPCC_REG_RCOR 0xc8 /* Receive Clock Options Register */ #define CLMPCC_REG_TBPR 0xc3 /* Transmit Baud Rate Period Register */ #define CLMPCC_REG_TCOR 0xc0 /* Transmit Clock Options Register */ /* Channel Command and Status Registers */ #define CLMPCC_REG_CCR 0x13 /* Channel Command Register */ #define CLMPCC_REG_STCR 0x12 /* Special Transmit Command Register */ #define CLMPCC_REG_CSR 0x1a /* Channel Status Register */ #define CLMPCC_REG_MSVR 0xde /* Modem Signal Value Register */ #define CLMPCC_REG_MSVR_RTS 0xde /* Modem Signal Value Register (RTS) */ #define CLMPCC_REG_MSVR_DTR 0xdf /* Modem Signal Value Register (DTR) */ /* Interrupt Registers */ #define CLMPCC_REG_LIVR 0x09 /* Local Interrupt Vector Register */ #define CLMPCC_REG_IER 0x11 /* Interrupt Enable Register */ #define CLMPCC_REG_LICR 0x26 /* Local Interrupting Channel Register */ #define CLMPCC_REG_STK 0xe2 /* Stack Register */ /* Receive Interrupt Registers */ #define CLMPCC_REG_RPILR 0xe1 /* Receive Priority Interrupt Level Reg */ #define CLMPCC_REG_RIR 0xed /* Receive Interrupt Register */ #define CLMPCC_REG_RISR 0x88 /* Receive Interrupt Status Reg (16-bits) */ #define CLMPCC_REG_RISRl 0x89 /* Receive Interrupt Status Reg (low) */ #define CLMPCC_REG_RISRh 0x88 /* Receive Interrupt Status Reg (high) */ #define CLMPCC_REG_RFOC 0x30 /* Receive FIFO Output Count */ #define CLMPCC_REG_RDR 0xf8 /* Receive Data Register */ #define CLMPCC_REG_REOIR 0x84 /* Receive End of Interrupt Register */ /* Transmit Interrupt Registers */ #define CLMPCC_REG_TPILR 0xe0 /* Transmit Priority Interrupt Level Reg */ #define CLMPCC_REG_TIR 0xec /* Transmit Interrupt Register */ #define CLMPCC_REG_TISR 0x8a /* Transmit Interrupt Status Register */ #define CLMPCC_REG_TFTC 0x80 /* Transmit FIFO Transfer Count */ #define CLMPCC_REG_TDR 0xf8 /* Transmit Data Register */ #define CLMPCC_REG_TEOIR 0x85 /* Transmit End of Interrupt Register */ /* Modem Interrupt Registers */ #define CLMPCC_REG_MPILR 0xe3 /* Modem Priority Interrupt Level Reg */ #define CLMPCC_REG_MIR 0xef /* Modem Interrupt Register */ #define CLMPCC_REG_MISR 0x8b /* Modem (/Timer) Interrupt Status Reg */ #define CLMPCC_REG_MEOIR 0x86 /* Modem End of Interrupt Register */ /* DMA Registers */ #define CLMPCC_REG_DMR 0xf6 /* DMA Mode Register (write only) */ #define CLMPCC_REG_BERCNT 0x8e /* Bus Error Retry Count */ #define CLMPCC_REG_DMABSTS 0x19 /* DMA Buffer Status */ /* DMA Receive Registers */ #define CLMPCC_REG_ARBADRL 0x42 /* A Receive Buffer Address Lower (word) */ #define CLMPCC_REG_ARBADRU 0x40 /* A Receive Buffer Address Upper (word) */ #define CLMPCC_REG_BRBADRL 0x46 /* B Receive Buffer Address Lower (word) */ #define CLMPCC_REG_BRBADRU 0x44 /* B Receive Buffer Address Upper (16bit) */ #define CLMPCC_REG_ARBCNT 0x4a /* A Receive Buffer Byte Count (word) */ #define CLMPCC_REG_BRBCNT 0x48 /* B Receive Buffer Byte Count (word) */ #define CLMPCC_REG_ARBSTS 0x4f /* A Receive Buffer Status */ #define CLMPCC_REG_BRBSTS 0x4e /* B Receive Buffer Status */ #define CLMPCC_REG_RCBADRL 0x3e /* Receive Current Buff Addr Lower (word) */ #define CLMPCC_REG_RCBADRU 0x3c /* Receive Current Buff Addr Upper (word) */ /* DMA Transmit Registers */ #define CLMPCC_REG_ATBADRL 0x52 /* A Transmit Buffer Address Lower (word) */ #define CLMPCC_REG_ATBADRU 0x50 /* A Transmit Buffer Address Upper (word) */ #define CLMPCC_REG_BTBADRL 0x56 /* B Transmit Buffer Address Lower (word) */ #define CLMPCC_REG_BTBADRU 0x54 /* B Transmit Buffer Address Upper (word) */ #define CLMPCC_REG_ATBCNT 0x5a /* A Transmit Buffer Byte Count (word) */ #define CLMPCC_REG_BTBCNT 0x58 /* B Transmit Buffer Byte Count (word) */ #define CLMPCC_REG_ATBSTS 0x5f /* A Transmit Buffer Status */ #define CLMPCC_REG_BTBSTS 0x5e /* B Transmit Buffer Status */ #define CLMPCC_REG_TCBADRL 0x3a /* Transmit Current Buf Addr Lower (word) */ #define CLMPCC_REG_TCBADRU 0x38 /* Transmit Current Buf Addr Upper (word) */ /* Timer Registers */ #define CLMPCC_REG_TPR 0xda /* Timer Period Register */ #define CLMPCC_REG_RTPR 0x24 /* Receive Timeout Period Register (word) */ #define CLMPCC_REG_RTPRl 0x25 /* Receive Timeout Period Register (low) */ #define CLMPCC_REG_RTPRh 0x24 /* Receive Timeout Period Register (high) */ #define CLMPCC_REG_GT1 0x2a /* General Timer 1 (word) */ #define CLMPCC_REG_GT1l 0x2b /* General Timer 1 (low) */ #define CLMPCC_REG_GT1h 0x2a /* General Timer 1 (high) */ #define CLMPCC_REG_GT2 0x29 /* General Timer 2 */ #define CLMPCC_REG_TTR 0x29 /* Transmit Timer Register */ /* Channel Access Register */ #define CLMPCC_CAR_MASK 0x03 /* Channel bit mask */ /* Channel Mode Register */ #define CLMPCC_CMR_RX_INT (0 << 7) /* Rx using interrupts */ #define CLMPCC_CMR_RX_DMA (1 << 7) /* Rx using DMA */ #define CLMPCC_CMR_TX_INT (0 << 6) /* Tx using interrupts */ #define CLMPCC_CMR_TX_DMA (1 << 6) /* Tx using DMA */ #define CLMPCC_CMR_HDLC 0x00 /* Select HDLC mode */ #define CLMPCC_CMR_BISYNC 0x01 /* Select Bisync mode */ #define CLMPCC_CMR_ASYNC 0x02 /* Select async mode */ #define CLMPCC_CMR_X21 0x03 /* Select X.21 mode */ /* Channel Option Register #1 (Async options) */ #define CLMPCC_COR1_EVEN_PARITY (0 << 7) /* Even parity */ #define CLMPCC_COR1_ODD_PARITY (1 << 7) /* Odd parity */ #define CLMPCC_COR1_NO_PARITY (0 << 5) /* No parity */ #define CLMPCC_COR1_FORCE_PAR (1 << 5) /* Force parity */ #define CLMPCC_COR1_NORM_PARITY (2 << 5) /* Normal parity */ #define CLMPCC_COR1_CHECK_PAR (0 << 4) /* Check parity */ #define CLMPCC_COR1_IGNORE_PAR (1 << 4) /* Ignore parity */ #define CLMPCC_COR1_CHAR_5BITS 0x04 /* 5 bits per character */ #define CLMPCC_COR1_CHAR_6BITS 0x05 /* 6 bits per character */ #define CLMPCC_COR1_CHAR_7BITS 0x06 /* 7 bits per character */ #define CLMPCC_COR1_CHAR_8BITS 0x07 /* 8 bits per character */ /* Channel Option Register #2 (Async options) */ #define CLMPCC_COR2_IXM (1 << 7) /* Implied XON mode */ #define CLMPCC_COR2_TxIBE (1 << 6) /* Transmit In-Band Flow Control */ #define CLMPCC_COR2_ETC (1 << 5) /* Embedded Tx Command Enable */ #define CLMPCC_COR2_RLM (1 << 3) /* Remote Loopback Mode */ #define CLMPCC_COR2_RtsAO (1 << 2) /* RTS Automatic Output Enable */ #define CLMPCC_COR2_CtsAE (1 << 1) /* CTS Automatic Enable */ #define CLMPCC_COR2_DsrAE (1 << 1) /* DSR Automatic Enable */ /* Embedded transmit commands */ #define CLMPCC_ETC_MAGIC 0x00 /* Introduces a command */ #define CLMPCC_ETC_SEND_BREAK 0x81 /* Send a BREAK character */ #define CLMPCC_ETC_DELAY 0x82 /* Insert a delay */ #define CLMPCC_ETC_STOP_BREAK 0x83 /* Stop sending BREAK */ /* Channel Option Register #3 (Async options) */ #define CLMPCC_COR3_ESCDE (1 << 7) /* Ext Special Char Detect Enab */ #define CLMPCC_COR3_RngDE (1 << 6) /* Range Detect Enable */ #define CLMPCC_COR3_FCT (1 << 5) /* Flow Ctrl Transparency Mode */ #define CLMPCC_COR3_SCDE (1 << 4) /* Special Character Detection */ #define CLMPCC_COR3_SpIstp (1 << 3) /* Special Character I Strip */ #define CLMPCC_COR3_STOP_1 0x02 /* 1 Stop Bit */ #define CLMPCC_COR3_STOP_1_5 0x03 /* 1.5 Stop Bits */ #define CLMPCC_COR3_STOP_2 0x04 /* 2 Stop Bits */ /* Channel Option Register #4 */ #define CLMPCC_COR4_DSRzd (1 << 7) /* Detect 1->0 transition on DSR */ #define CLMPCC_COR4_CDzd (1 << 6) /* Detect 1->0 transition on CD */ #define CLMPCC_COR4_CTSzd (1 << 5) /* Detect 1->0 transition on CTS */ #define CLMPCC_COR4_FIFO_MASK 0x0f /* FIFO Threshold bits */ #define CLMPCC_COR4_FIFO_LOW 1 #define CLMPCC_COR4_FIFO_MED 4 #define CLMPCC_COR4_FIFO_HIGH 8 /* Channel Option Register #5 */ #define CLMPCC_COR5_DSRod (1 << 7) /* Detect 0->1 transition on DSR */ #define CLMPCC_COR5_CDod (1 << 6) /* Detect 0->1 transition on CD */ #define CLMPCC_COR5_CTSod (1 << 5) /* Detect 0->1 transition on CTS */ #define CLMPCC_COR5_FLOW_MASK 0x0f /* Rx Flow Control FIFO Threshold */ #define CLMPCC_COR5_FLOW_NORM 8 /* Channel Option Register #6 (Async options) */ #define CLMPCC_COR6_RX_CRNL 0x00 /* No special action on CR or NL */ #define CLMPCC_COR6_BRK_EXCEPT (0 << 3) /* Exception interrupt on BREAK */ #define CLMPCC_COR6_BRK_2_NULL (1 << 3) /* Translate BREAK to NULL char */ #define CLMPCC_COR6_BRK_DISCARD (3 << 3) /* Discard BREAK characters */ #define CLMPCC_COR6_PF_EXCEPT 0x00 /* Exception irq on parity/frame */ #define CLMPCC_COR6_PF_2_NULL 0x01 /* Translate parity/frame to NULL */ #define CLMPCC_COR6_PF_IGNORE 0x02 /* Ignore error */ #define CLMPCC_COR6_PF_DISCARD 0x03 /* Discard character */ #define CLMPCC_COR6_PF_TRANS 0x05 /* Translate to FF NULL + char */ /* Channel Option Register #7 (Async options) */ #define CLMPCC_COR7_ISTRIP (1 << 7) /* Strip MSB */ #define CLMPCC_COR7_LNE (1 << 6) /* Enable LNext Option */ #define CLMPCC_COR7_FCERR (1 << 5) /* Flow Control on Error Char */ #define CLMPCC_COR7_TX_CRNL 0x00 /* No special action on NL or CR */ /* Receive Clock Options Register */ #define CLMPCC_RCOR_CLK(x) (x) #define CLMPCC_RCOR_TLVAL (1 << 7) /* Transmit Line Value */ #define CLMPCC_RCOR_DPLL_ENABLE (1 << 5) /* Phase Locked Loop Enable */ #define CLMPCC_RCOR_DPLL_NRZ (0 << 3) /* PLL runs in NRZ mode */ #define CLMPCC_RCOR_DPLL_NRZI (1 << 3) /* PLL runs in NRZI mode */ #define CLMPCC_RCOR_DPLL_MAN (2 << 3) /* PLL runs in Manchester mode */ #define CLMPCC_RCOR_CLK_0 0x0 /* Rx Clock Source 'Clk0' */ #define CLMPCC_RCOR_CLK_1 0x1 /* Rx Clock Source 'Clk1' */ #define CLMPCC_RCOR_CLK_2 0x2 /* Rx Clock Source 'Clk2' */ #define CLMPCC_RCOR_CLK_3 0x3 /* Rx Clock Source 'Clk3' */ #define CLMPCC_RCOR_CLK_4 0x4 /* Rx Clock Source 'Clk4' */ #define CLMPCC_RCOR_CLK_EXT 0x6 /* Rx Clock Source 'External' */ /* Transmit Clock Options Register */ #define CLMPCC_TCOR_CLK(x) ((x) << 5) #define CLMPCC_TCOR_CLK_0 (0 << 5) /* Tx Clock Source 'Clk0' */ #define CLMPCC_TCOR_CLK_1 (1 << 5) /* Tx Clock Source 'Clk1' */ #define CLMPCC_TCOR_CLK_2 (2 << 5) /* Tx Clock Source 'Clk2' */ #define CLMPCC_TCOR_CLK_3 (3 << 5) /* Tx Clock Source 'Clk3' */ #define CLMPCC_TCOR_CLK_4 (4 << 5) /* Tx Clock Source 'Clk4' */ #define CLMPCC_TCOR_CLK_EXT (6 << 5) /* Tx Clock Source 'External' */ #define CLMPCC_TCOR_CLK_RX (7 << 5) /* Tx Clock Source 'Same as Rx' */ #define CLMPCC_TCOR_EXT_1X (1 << 3) /* Times 1 External Clock */ #define CLMPCC_TCOR_LOCAL_LOOP (1 << 1) /* Enable Local Loopback */ /* Special Transmit Command Register */ #define CLMPCC_STCR_SSPC(n) ((n) & 0x7) /* Send special character 'n' */ #define CLMPCC_STCR_SND_SPC (1 << 3) /* Initiate send special char */ #define CLMPCC_STCR_APPEND_COMP (1 << 5) /* Append complete (Async DMA) */ #define CLMPCC_STCR_ABORT_TX (1 << 6) /* Abort Tx (HDLC Mode only) */ /* Channel Command Register */ #define CLMPCC_CCR_T0_CLEAR 0x40 /* Type 0: Clear Channel */ #define CLMPCC_CCR_T0_INIT 0x20 /* Type 0: Initialise Channel */ #define CLMPCC_CCR_T0_RESET_ALL 0x10 /* Type 0: Reset All */ #define CLMPCC_CCR_T0_TX_EN 0x08 /* Type 0: Transmitter Enable */ #define CLMPCC_CCR_T0_TX_DIS 0x04 /* Type 0: Transmitter Disable */ #define CLMPCC_CCR_T0_RX_EN 0x02 /* Type 0: Receiver Enable */ #define CLMPCC_CCR_T0_RX_DIS 0x01 /* Type 0: Receiver Disable */ #define CLMPCC_CCR_T1_CLR_TMR1 0xc0 /* Type 1: Clear Timer 1 */ #define CLMPCC_CCR_T1_CLR_TMR2 0xa0 /* Type 1: Clear Timer 5 */ #define CLMPCC_CCR_T1_CLR_RECV 0x90 /* Type 1: Clear Receiver */ /* Channel Status Register (Async Mode) */ #define CLMPCC_CSR_RX_ENABLED (1 << 7) /* Receiver Enabled */ #define CLMPCC_CSR_RX_FLOW_OFF (1 << 6) /* Receive Flow Off */ #define CLMPCC_CSR_RX_FLOW_ON (1 << 5) /* Receive Flow On */ #define CLMPCC_CSR_TX_ENABLED (1 << 3) /* Transmitter Enabled */ #define CLMPCC_CSR_TX_FLOW_OFF (1 << 2) /* Transmit Flow Off */ #define CLMPCC_CSR_TX_FLOW_ON (1 << 1) /* Transmit Flow On */ /* Modem Signal Value Register */ #define CLMPCC_MSVR_DSR (1 << 7) /* Current State of DSR Input */ #define CLMPCC_MSVR_CD (1 << 6) /* Current State of CD Input */ #define CLMPCC_MSVR_CTS (1 << 5) /* Current State of CTS Input */ #define CLMPCC_MSVR_DTR_OPT (1 << 4) /* DTR Option Select */ #define CLMPCC_MSVR_PORT_ID (1 << 2) /* Device Type (2400 / 2401) */ #define CLMPCC_MSVR_DTR (1 << 1) /* Current State of DTR Output */ #define CLMPCC_MSVR_RTS (1 << 0) /* Current State of RTS Output */ /* Local Interrupt Vector Register */ #define CLMPCC_LIVR_TYPE_MASK 0x03 /* Type of Interrupt */ #define CLMPCC_LIVR_EXCEPTION 0x0 /* Exception (DMA Completion) */ #define CLMPCC_LIVR_MODEM 0x1 /* Modem Signal Change */ #define CLMPCC_LIVR_TX 0x2 /* Transmit Data Interrupt */ #define CLMPCC_LIVR_RX 0x3 /* Receive Data Interrupt */ /* Interrupt Enable Register */ #define CLMPCC_IER_MODEM (1 << 7) /* Modem Pin Change Detect */ #define CLMPCC_IER_RET (1 << 5) /* Receive Exception Timeout */ #define CLMPCC_IER_RX_FIFO (1 << 3) /* Rx FIFO Threshold Reached */ #define CLMPCC_IER_TIMER (1 << 2) /* General Timer(s) Timeout */ #define CLMPCC_IER_TX_EMPTY (1 << 1) /* Tx Empty */ #define CLMPCC_IER_TX_FIFO (1 << 0) /* Tx FIFO Threshold Reached */ /* Local Interrupting Channel Register */ #define CLMPCC_LICR_MASK 0x0c /* Mask for channel number */ #define CLMPCC_LICR_CHAN(v) (((v) & CLMPCC_LICR_MASK) >> 2) /* Receive Interrupt Register */ #define CLMPCC_RIR_REN (1 << 7) /* Receive Enable */ #define CLMPCC_RIR_RACT (1 << 6) /* Receive Active */ #define CLMPCC_RIR_REOI (1 << 5) /* Receive End of Interrupt */ #define CLMPCC_RIR_RCVT_MASK 0x0c #define CLMPCC_RIR_RCN_MASK 0x03 /* Receive Interrupt Status Register, Low (Async option) */ #define CLMPCC_RISR_TIMEOUT (1 << 7) /* Rx FIFO Empty and Timeout */ #define CLMPCC_RISR_OVERRUN (1 << 3) /* Rx Overrun Error */ #define CLMPCC_RISR_PARITY (1 << 2) /* Rx Parity Error */ #define CLMPCC_RISR_FRAMING (1 << 1) /* Rx Framing Error */ #define CLMPCC_RISR_BREAK (1 << 0) /* BREAK Detected */ /* Receive FIFO Counter Register */ #define CLMPCC_RFOC_MASK 0x1f /* Mask for valid bits */ /* Receive End of Interrupt Register */ #define CLMPCC_REOIR_TERMBUFF (1 << 7) /* Terminate Current DMA Buffer */ #define CLMPCC_REOIR_DIS_EX_CHR (1 << 6) /* Discard Exception Char (DMA) */ #define CLMPCC_REOIR_TMR2_SYNC (1 << 5) /* Set Timer 2 in Sync Mode */ #define CLMPCC_REOIR_TMR1_SYNC (1 << 4) /* Set Timer 1 in Sync Mode */ #define CLMPCC_REOIR_NO_TRANS (1 << 3) /* No Transfer of Data */ /* Transmit Interrupt Register */ #define CLMPCC_TIR_TEN (1 << 7) /* Transmit Enable */ #define CLMPCC_TIR_TACT (1 << 6) /* Transmit Active */ #define CLMPCC_TIR_TEOI (1 << 5) /* Transmit End of Interrupt */ #define CLMPCC_TIR_TCVT_MASK 0x0c #define CLMPCC_TIR_TCN_MASK 0x03 /* Transmit Interrupt Status Register (Async option) */ #define CLMPCC_TISR_BERR (1 << 7) /* Bus Error (DMA) */ #define CLMPCC_TISR_EOF (1 << 6) /* Transmit End of Frame (DMA) */ #define CLMPCC_TISR_EOB (1 << 5) /* Transmit End of Buffer (DMA) */ #define CLMPCC_TISR_UNDERRUN (1 << 4) /* Transmit Underrun (sync only) */ #define CLMPCC_TISR_BUFF_ID (1 << 3) /* Buffer that has exception */ #define CLMPCC_TISR_TX_EMPTY (1 << 1) /* Transmitter Empty */ #define CLMPCC_TISR_TX_FIFO (1 << 0) /* Transmit FIFO Below Threshold */ /* Transmit FIFO Transfer Count Register */ #define CLMPCC_TFTC_MASK 0x1f /* Mask for valid bits */ /* Transmit End of Interrupt Register */ #define CLMPCC_TEOIR_TERMBUFF (1 << 7) /* Terminate Current DMA Buffer */ #define CLMPCC_TEOIR_END_OF_FRM (1 << 6) /* End of Frame (sync mode) */ #define CLMPCC_TEOIR_TMR2_SYNC (1 << 5) /* Set Timer 2 in Sync Mode */ #define CLMPCC_TEOIR_TMR1_SYNC (1 << 4) /* Set Timer 1 in Sync Mode */ #define CLMPCC_TEOIR_NO_TRANS (1 << 3) /* No Transfer of Data */ /* Modem Interrupt Register */ #define CLMPCC_MIR_MEN (1 << 7) /* Modem Enable */ #define CLMPCC_MIR_MACT (1 << 6) /* Modem Active */ #define CLMPCC_MIR_MEOI (1 << 5) /* Modem End of Interrupt */ #define CLMPCC_MIR_MCVT_MASK 0x0c #define CLMPCC_MIR_MCN_MASK 0x03 /* Modem/Timer Interrupt Status Register */ #define CLMPCC_MISR_DSR (1 << 7) /* DSR Changed State */ #define CLMPCC_MISR_CD (1 << 6) /* CD Changed State */ #define CLMPCC_MISR_CTS (1 << 5) /* CTS Changed State */ #define CLMPCC_MISR_TMR2 (1 << 1) /* Timer 2 Timed Out */ #define CLMPCC_MISR_TMR1 (1 << 0) /* Timer 1 Timed Out */ /* Modem End of Interrupt Register */ #define CLMPCC_MEOIR_TMR2_SYNC (1 << 5) /* Set Timer 2 in Sync Mode */ #define CLMPCC_MEOIR_TMR1_SYNC (1 << 4) /* Set Timer 1 in Sync Mode */ /* Default value for CLMPCC_REG_RTPRl */ #define CLMPCC_RTPR_DEFAULT 2 /* 2mS timeout period */ /* * Return a value for the Receive Timer Prescaler register * for a given clock rate and number of milliseconds. * The minimum recommended value for this register is 0x0a. */ #define CLMPCC_MSEC_TO_TPR(c,m) (((((c)/2048)/(1000/(m))) > 0x0a) ? \ (((c)/2048)/(1000/(m))) : 0x0a) #endif /* __clmpccreg_h */ gxemul-0.6.1/src/include/thirdparty/sgi_gl.h000644 001750 001750 00000003032 13402411502 021244 0ustar00debugdebug000000 000000 /* Imported into GXemul from OpenBSD 2018-10-16. */ #ifndef SGI_GL_H #define SGI_GL_H /* $OpenBSD: gl.h,v 1.1 2012/04/16 22:17:13 miod Exp $ */ /* * Copyright (c) 2009, 2010 Joel Sing * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * OpenGL defines */ /* Logic Operations. */ #define OPENGL_LOGIC_OP_CLEAR 0 #define OPENGL_LOGIC_OP_AND 1 #define OPENGL_LOGIC_OP_AND_REVERSE 2 #define OPENGL_LOGIC_OP_COPY 3 #define OPENGL_LOGIC_OP_AND_INVERTED 4 #define OPENGL_LOGIC_OP_NOOP 5 #define OPENGL_LOGIC_OP_XOR 6 #define OPENGL_LOGIC_OP_OR 7 #define OPENGL_LOGIC_OP_NOR 8 #define OPENGL_LOGIC_OP_EQUIV 9 #define OPENGL_LOGIC_OP_INVERT 10 #define OPENGL_LOGIC_OP_OR_REVERSE 11 #define OPENGL_LOGIC_OP_COPY_INVERTED 12 #define OPENGL_LOGIC_OP_OR_INVERTED 13 #define OPENGL_LOGIC_OP_NAND 14 #define OPENGL_LOGIC_OP_SET 15 #endif // SGI_GL_H gxemul-0.6.1/src/include/thirdparty/luna88k_board.h000644 001750 001750 00000017310 13402411502 022445 0ustar00debugdebug000000 000000 /* Imported into GXemul 2018-02-03 from OpenBSD 6.2. */ /* $OpenBSD: board.h,v 1.14 2017/03/20 19:40:47 miod Exp $ */ /* * Mach Operating System * Copyright (c) 1993-1991 Carnegie Mellon University * Copyright (c) 1991 OMRON Corporation * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ #ifndef _MACHINE_BOARD_H_ #define _MACHINE_BOARD_H_ /* * OMRON SX9100DT CPU board constants */ /* * Something to put append a 'U' to a long constant if it's C so that * it'll be unsigned in both ANSI and traditional. */ #if defined(_LOCORE) #define U(num) num #elif defined(__STDC__) #define U(num) num ## U #else #define U(num) num/**/U #endif /* machtype values */ #define LUNA_88K 0x1 #define LUNA_88K2 0x2 #define MAXPHYSMEM U(0x10000000) /* max physical memory */ #define PROM_ADDR U(0x41000000) /* PROM */ #define PROM_SPACE U(0x00040000) #define NVRAM_ADDR U(0x45000000) /* Non Volatile */ #define NVRAM_SPACE U(0x00001FDC) #define FUSE_ROM_ADDR U(0x43000000) /* FUSE_ROM */ #define FUSE_ROM_SPACE 1024 #define OBIO_CAL_CTL U(0x45001FE0) /* calendar control register */ #define OBIO_CAL_SEC U(0x45001FE4) /* seconds */ #define OBIO_CAL_MIN U(0x45001FE8) /* minutes */ #define OBIO_CAL_HOUR U(0x45001FEC) /* hours */ #define OBIO_CAL_DOW U(0x45001FF0) /* Day Of the Week */ #define OBIO_CAL_DAY U(0x45001FF4) /* days */ #define OBIO_CAL_MON U(0x45001FF8) /* months */ #define OBIO_CAL_YEAR U(0x45001FFC) /* years */ #define NVRAM_ADDR_88K2 U(0x47000000) /* Non Volatile RAM area for LUNA-88K2 */ #define OBIO_PIO0_BASE U(0x49000000) /* PIO-0 */ #define OBIO_PIO0_SPACE U(0x0000000C) #define OBIO_PIO0A U(0x49000000) /* PIO-0 port A */ #define OBIO_PIO0B U(0x49000004) /* PIO-0 port B */ #define OBIO_PIO0C U(0x49000008) /* PIO-0 port C*/ #define OBIO_PIO0 U(0x4900000C) /* PIO-0 control */ #define OBIO_PIO1_BASE U(0x4D000000) /* PIO-1 */ #define OBIO_PIO1_SPACE U(0x0000000C) #define OBIO_PIO1A U(0x4D000000) /* PIO-1 port A */ #define OBIO_PIO1B U(0x4D000004) /* PIO-1 port B */ #define OBIO_PIO1C U(0x4D000008) /* PIO-1 port C*/ #define OBIO_PIO1 U(0x4D00000C) /* PIO-1 control */ #define OBIO_SIO U(0x51000000) /* SIO */ #define OBIO_TAS U(0x61000000) /* TAS register */ #define OBIO_CLOCK0 U(0x63000000) /* system clock CPU 0 */ #define OBIO_CLOCK1 U(0x63000004) /* system clock CPU 1 */ #define OBIO_CLOCK2 U(0x63000008) /* system clock CPU 2 */ #define OBIO_CLOCK3 U(0x6300000C) /* system clock CPU 3 */ #define OBIO_CLK_INTR 31 /* system clock interrupt flag */ #define INT_ST_MASK0 U(0x65000000) /* interrupt status register CPU 0 */ #define INT_ST_MASK1 U(0x65000004) /* interrupt status register CPU 1 */ #define INT_ST_MASK2 U(0x65000008) /* interrupt status register CPU 2 */ #define INT_ST_MASK3 U(0x6500000C) /* interrupt status register CPU 3 */ #define INT_LEVEL 8 /* # of interrupt level + 1 */ #define INT_SET_LV7 U(0x00000000) /* disable interrupts */ #define INT_SET_LV6 U(0x00000000) /* enable level 7 */ #define INT_SET_LV5 U(0x84000000) /* enable level 7-6 */ #define INT_SET_LV4 U(0xC4000000) /* enable level 7-5 */ #define INT_SET_LV3 U(0xE4000000) /* enable level 7-4 */ #define INT_SET_LV2 U(0xF4000000) /* enable level 7-3 */ #define INT_SET_LV1 U(0xFC000000) /* enable level 7-2 */ #define INT_SET_LV0 U(0xFC000000) /* enable interrupts */ #define INT_SLAVE_MASK U(0x84000000) /* slave can only enable 6 and 1 */ #define SOFT_INT0 U(0x69000000) /* software interrupt CPU 0 */ #define SOFT_INT1 U(0x69000004) /* software interrupt CPU 1 */ #define SOFT_INT2 U(0x69000008) /* software interrupt CPU 2 */ #define SOFT_INT3 U(0x6900000C) /* software interrupt CPU 3 */ #define SOFT_INT_FLAG0 U(0x6B000000) /* software interrupt flag CPU 0 */ #define SOFT_INT_FLAG1 U(0x6B000000) /* software interrupt flag CPU 1 */ #define SOFT_INT_FLAG2 U(0x6B000000) /* software interrupt flag CPU 2 */ #define SOFT_INT_FLAG3 U(0x6B000000) /* software interrupt flag CPU 3 */ #define RESET_CPU0 U(0x6D000000) /* reset CPU 0 */ #define RESET_CPU1 U(0x6D000004) /* reset CPU 1 */ #define RESET_CPU2 U(0x6D000008) /* reset CPU 2 */ #define RESET_CPU3 U(0x6D00000C) /* reset CPU 3 */ #define RESET_CPU_ALL U(0x6D000010) /* reset ALL CPUs */ #define TRI_PORT_RAM U(0x71000000) /* 3 port RAM */ #define TRI_PORT_RAM_SPACE 0x20000 #define EXT_A_ADDR U(0x81000000) /* extension board A */ #define EXT_A_SPACE U(0x02000000) #define EXT_B_ADDR U(0x83000000) /* extension board B */ #define EXT_B_SPACE U(0x01000000) #define PC_BASE U(0x90000000) /* pc-98 extension board */ #define PC_SPACE U(0x02000000) #define MROM_ADDR U(0xA1000000) /* Mask ROM address */ #define MROM_SPACE 0x400000 #define BMAP_START U(0xB1000000) /* Bitmap start address */ #define BMAP_SPACE (BMAP_END - BMAP_START) #define BMAP_RFCNT U(0xB1000000) /* RFCNT register */ #define BMAP_BMSEL U(0xB1040000) /* BMSEL register */ #define BMAP_BMP U(0xB1080000) /* common bitmap plane */ #define BMAP_BMAP0 U(0xB10C0000) /* bitmap plane 0 */ #define BMAP_BMAP1 U(0xB1100000) /* bitmap plane 1 */ #define BMAP_BMAP2 U(0xB1140000) /* bitmap plane 2 */ #define BMAP_BMAP3 U(0xB1180000) /* bitmap plane 3 */ #define BMAP_BMAP4 U(0xB11C0000) /* bitmap plane 4 */ #define BMAP_BMAP5 U(0xB1200000) /* bitmap plane 5 */ #define BMAP_BMAP6 U(0xB1240000) /* bitmap plane 6 */ #define BMAP_BMAP7 U(0xB1280000) /* bitmap plane 7 */ #define BMAP_FN U(0xB12C0000) /* common bitmap function */ #define BMAP_FN0 U(0xB1300000) /* bitmap function 0 */ #define BMAP_FN1 U(0xB1340000) /* bitmap function 1 */ #define BMAP_FN2 U(0xB1380000) /* bitmap function 2 */ #define BMAP_FN3 U(0xB13C0000) /* bitmap function 3 */ #define BMAP_FN4 U(0xB1400000) /* bitmap function 4 */ #define BMAP_FN5 U(0xB1440000) /* bitmap function 5 */ #define BMAP_FN6 U(0xB1480000) /* bitmap function 6 */ #define BMAP_FN7 U(0xB14C0000) /* bitmap function 7 */ #define BMAP_END U(0xB1500000) #define BMAP_END24P U(0xB1800000) /* end of 24p framemem */ #define BMAP_PALLET0 U(0xC0000000) /* color pallet */ #define BMAP_PALLET1 U(0xC1000000) /* color pallet */ #define BMAP_PALLET2 U(0xC1100000) /* color pallet */ #define BOARD_CHECK_REG U(0xD0000000) /* board check register */ #define BMAP_CRTC U(0xD1000000) /* CRTC-II */ #define BMAP_IDENTROM U(0xD1800000) /* bitmap-board identify ROM */ #define SCSI_ADDR U(0xE1000000) /* SCSI address */ #define LANCE_ADDR U(0xF1000000) /* LANCE */ #define CMMU_I0 U(0xFFF07000) /* CMMU instruction cpu 0 */ #define CMMU_D0 U(0xFFF06000) /* CMMU data cpu 0 */ #define CMMU_I1 U(0xFFF05000) /* CMMU instruction cpu 1 */ #define CMMU_D1 U(0xFFF04000) /* CMMU data cpu 1 */ #define CMMU_I2 U(0xFFF03000) /* CMMU instruction cpu 2 */ #define CMMU_D2 U(0xFFF02000) /* CMMU data cpu 2 */ #define CMMU_I3 U(0xFFF01000) /* CMMU instruction cpu 3 */ #define CMMU_D3 U(0xFFF00000) /* CMMU data cpu 3 */ #endif /* _MACHINE_BOARD_H_ */ gxemul-0.6.1/src/include/thirdparty/comreg.h000644 001750 001750 00000013722 13402411502 021263 0ustar00debugdebug000000 000000 /* gxemul: $Id: comreg.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ #ifndef COMREG_H #define COMREG_H /* $NetBSD: comreg.h,v 1.11 1997/10/19 14:26:21 fvdl Exp $ */ /*- * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)comreg.h 7.2 (Berkeley) 5/9/91 */ #include "ns16550reg.h" #define COM_FREQ 1843200 /* 16-bit baud rate divisor */ #define COM_TOLERANCE 30 /* baud rate tolerance, in 0.1% units */ /* interrupt enable register */ #define IER_ERXRDY 0x1 /* Enable receiver interrupt */ #define IER_ETXRDY 0x2 /* Enable transmitter empty interrupt */ #define IER_ERLS 0x4 /* Enable line status interrupt */ #define IER_EMSC 0x8 /* Enable modem status interrupt */ #define IER_ERTS 0x40 /* Enable RTS interrupt */ #define IER_ECTS 0x80 /* Enable CTS interrupt */ /* interrupt identification register */ #define IIR_IMASK 0xf #define IIR_RXTOUT 0xc #define IIR_RLS 0x6 /* Line status change */ #define IIR_RXRDY 0x4 /* Receiver ready */ #define IIR_TXRDY 0x2 /* Transmitter ready */ #define IIR_MLSC 0x0 /* Modem status */ #define IIR_NOPEND 0x1 /* No pending interrupts */ #define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */ /* fifo control register */ #define FIFO_ENABLE 0x01 /* Turn the FIFO on */ #define FIFO_RCV_RST 0x02 /* Reset RX FIFO */ #define FIFO_XMT_RST 0x04 /* Reset TX FIFO */ #define FIFO_DMA_MODE 0x08 #define FIFO_TRIGGER_1 0x00 /* Trigger RXRDY intr on 1 character */ #define FIFO_TRIGGER_4 0x40 /* ibid 4 */ #define FIFO_TRIGGER_8 0x80 /* ibid 8 */ #define FIFO_TRIGGER_14 0xc0 /* ibid 14 */ /* enhanced feature register */ #define EFR_AUTOCTS 0x80 /* Automatic CTS flow control */ #define EFR_AUTORTS 0x40 /* Automatic RTS flow control */ #define EFR_SPECIAL 0x20 /* Special char detect */ #define EFR_EFCR 0x10 /* Enhanced function control bit */ #define EFR_TXFLOWBOTH 0x0c /* Automatic transmit XON/XOFF 1 and 2 */ #define EFR_TXFLOW1 0x08 /* Automatic transmit XON/XOFF 1 */ #define EFR_TXFLOW2 0x04 /* Automatic transmit XON/XOFF 2 */ #define EFR_TXFLOWNONE 0x00 /* No automatic XON/XOFF transmit */ #define EFR_RXFLOWBOTH 0x03 /* Automatic receive XON/XOFF 1 and 2 */ #define EFR_RXFLOW1 0x02 /* Automatic receive XON/XOFF 1 */ #define EFR_RXFLOW2 0x01 /* Automatic receive XON/XOFF 2 */ #define EFR_RXFLOWNONE 0x00 /* No automatic XON/XOFF receive */ /* line control register */ #define LCR_EERS 0xBF /* Enable access to Enhanced Register Set */ #define LCR_DLAB 0x80 /* Divisor latch access enable */ #define LCR_SBREAK 0x40 /* Break Control */ #define LCR_PZERO 0x38 /* Space parity */ #define LCR_PONE 0x28 /* Mark parity */ #define LCR_PEVEN 0x18 /* Even parity */ #define LCR_PODD 0x08 /* Odd parity */ #define LCR_PNONE 0x00 /* No parity */ #define LCR_PENAB 0x08 /* XXX - low order bit of all parity */ #define LCR_STOPB 0x04 /* 2 stop bits per serial word */ #define LCR_8BITS 0x03 /* 8 bits per serial word */ #define LCR_7BITS 0x02 /* 7 bits */ #define LCR_6BITS 0x01 /* 6 bits */ #define LCR_5BITS 0x00 /* 5 bits */ /* modem control register */ #define MCR_LOOPBACK 0x10 /* Loop test: echos from TX to RX */ #define MCR_IENABLE 0x08 /* Out2: enables UART interrupts */ #define MCR_DRS 0x04 /* Out1: resets some internal modems */ #define MCR_RTS 0x02 /* Request To Send */ #define MCR_DTR 0x01 /* Data Terminal Ready */ /* line status register */ #define LSR_RCV_FIFO 0x80 #define LSR_TSRE 0x40 /* Transmitter empty: byte sent */ #define LSR_TXRDY 0x20 /* Transmitter buffer empty */ #define LSR_BI 0x10 /* Break detected */ #define LSR_FE 0x08 /* Framing error: bad stop bit */ #define LSR_PE 0x04 /* Parity error */ #define LSR_OE 0x02 /* Overrun, lost incoming byte */ #define LSR_RXRDY 0x01 /* Byte ready in Receive Buffer */ #define LSR_RCV_MASK 0x1f /* Mask for incoming data or error */ /* modem status register */ /* All deltas are from the last read of the MSR. */ #define MSR_DCD 0x80 /* Current Data Carrier Detect */ #define MSR_RI 0x40 /* Current Ring Indicator */ #define MSR_DSR 0x20 /* Current Data Set Ready */ #define MSR_CTS 0x10 /* Current Clear to Send */ #define MSR_DDCD 0x08 /* DCD has changed state */ #define MSR_TERI 0x04 /* RI has toggled low to high */ #define MSR_DDSR 0x02 /* DSR has changed state */ #define MSR_DCTS 0x01 /* CTS has changed state */ /* XXX ISA-specific. */ #define COM_NPORTS 8 #endif /* COMREG_H */ gxemul-0.6.1/src/include/thirdparty/m88k_dmt.h000644 001750 001750 00000005043 13402411502 021437 0ustar00debugdebug000000 000000 /* $OpenBSD: m88100.h,v 1.3 2006/11/18 22:58:28 miod Exp $ */ #ifndef M88K_DMT_H #define M88K_DMT_H /* * Mach Operating System * Copyright (c) 1993-1992 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ /* * 88100 RISC definitions */ /* * DMT0, DMT1, DMT2 layout * * The DMT_SKIP bit is never set by the cpu. It is used to mark 'known' * transactions so that they don't get processed a second time by * data_access_emulation(). */ #define DMT_SKIP 0x00010000 /* skip this dmt */ #define DMT_BO 0x00008000 /* Byte-Ordering */ #define DMT_DAS 0x00004000 /* Data Access Space */ #define DMT_DOUB1 0x00002000 /* Double Word */ #define DMT_LOCKBAR 0x00001000 /* Bud Lock */ #define DMT_DREG 0x00000F80 /* Destination Registers 5bits */ #define DMT_SIGNED 0x00000040 /* Sign-Extended Bit */ #define DMT_EN 0x0000003C /* Byte Enable Bit */ #define DMT_WRITE 0x00000002 /* Read/Write Transaction Bit */ #define DMT_VALID 0x00000001 /* Valid Transaction Bit */ #define DMT_DREGSHIFT 7 #define DMT_ENSHIFT 2 #define DMT_DREGBITS(x) (((x) & DMT_DREG) >> DMT_DREGSHIFT) #define DMT_ENBITS(x) (((x) & DMT_EN) >> DMT_ENSHIFT) #if defined(_KERNEL) && !defined(_LOCORE) void dae_print(unsigned *); void data_access_emulation(unsigned *); u_int32_t do_load_word(vaddr_t, int); u_int16_t do_load_half(vaddr_t, int); u_int8_t do_load_byte(vaddr_t, int); void do_store_word(vaddr_t, u_int32_t, int); void do_store_half(vaddr_t, u_int16_t, int); void do_store_byte(vaddr_t, u_int8_t, int); u_int32_t do_xmem_word(vaddr_t, u_int32_t, int); u_int8_t do_xmem_byte(vaddr_t, u_int8_t, int); void m88100_apply_patches(void); #endif #endif /* M88K_DMT_H */ gxemul-0.6.1/src/include/thirdparty/imcreg.h000644 001750 001750 00000015102 13402411502 021247 0ustar00debugdebug000000 000000 /* gxemul: $Id: imcreg.h,v 1.2 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: imcreg.h,v 1.2 2002/03/13 13:12:26 simonb Exp $ */ /* * Copyright (c) 2001 Rafal K. Boni * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _ARCH_SGIMIPS_DEV_IMCREG_H_ #define _ARCH_SGIMIPS_DEV_IMCREG_H_ #define IMC_CPUCTRL0 0x1fa00004 /* CPU control, register 0 */ #define IMC_CPUCTRL0_REFMASK 0x0000000f /* # lines to refresh */ #define IMC_CPUCTRL0_RFE 0x00000010 /* refresh enable */ #define IMC_CPUCTRL0_GPR 0x00000020 /* GIO parity enable */ #define IMC_CPUCTRL0_MPR 0x00000040 /* memory parity enable */ #define IMC_CPUCTRL0_CPR 0x00000080 /* cpu bus parity enable */ #define IMC_CPUCTRL0_WDOG 0x00000100 /* watchdog enable */ #define IMC_CPUCTRL0_SIN 0x00000200 /* reset system */ #define IMC_CPUCTRL0_GRR 0x00000400 /* graphics reset */ #define IMC_CPUCTRL0_ENLOCK 0x00000800 /* enable EISA memory lock */ #define IMC_CPUCTRL0_CMDPAR 0x00001000 /* SysCmd parity enable */ #define IMC_CPUCTRL0_INTENA 0x00002000 /* enable CPU interrupts */ #define IMC_CPUCTRL0_SNOOPENA 0x00004000 /* enable gfx DMA snoop */ #define IMC_CPUCTRL0_PROM_WRENA 0x00008000 /* disable buserr on PROM * writes */ #define IMC_CPUCTRL0_WRST 0x00010000 /* warm restart (reset cpu) */ /* Bit 17 reserved 0x00020000 */ #define IMC_CPUCTRL0_LITTLE 0x00040000 /* MC little-endian toggle */ #define IMC_CPUCTRL0_WRRST 0x00080000 /* cpu warm reset */ #define IMC_CPUCTRL0_MUXHWMSK 0x01f00000 /* MUX fifo high-water mask */ #define IMC_CPUCTRL0_BADPAR 0x02000000 /* generate bad parity on * CPU->memory writes */ #define IMC_CPUCTRL0_NCHKMEMPAR 0x04000000 /* disable CPU parity check * on memory reads. */ #define IMC_CPUCTRL0_BACK2 0x08000000 /* enable back2back GIO wrt */ #define IMC_CPUCTRL0_BUSRTMSK 0xf0000000 /* stall cycle for berr data */ #define IMC_CPUCTRL1 0x1fa0000c /* CPU control, register 1 */ #define IMC_CPUCTRL1_MCHWMSK 0x0000000f /* MC FIFO high water mask */ #define IMC_CPUCTRL1_ABORTEN 0x00000010 /* Enable GIO bus timeouts */ /* Bits 5 - 11 reserved 0x00000fe0 */ #define IMC_CPUCTRL1_HPCFX 0x00001000 /* HPC endian fix */ #define IMC_CPUCTRL1_HPCLITTLE 0x00002000 /* HPC DMA is little-endian */ #define IMC_CPUCTRL1_EXP0FX 0x00004000 /* EXP0 endian fix */ #define IMC_CPUCTRL1_EXP0LITTLE 0x00008000 /* EXP0 DMA is little-endian */ #define IMC_CPUCTRL1_EXP1FX 0x00010000 /* EXP1 endian fix */ #define IMC_CPUCTRL1_EXP1LITTLE 0x00020000 /* EXP1 DMA is little-endian */ #define IMC_WDOG 0x1fa00014 /* Watchdog counter */ #define IMC_WDOG_MASK 0x001fffff /* counter mask */ #define IMC_SYSID 0x1fa0001c /* MC revision register */ #define IMC_SYSID_REVMASK 0x0000000f /* MC revision mask */ #define IMC_SYSID_HAVEISA 0x00000010 /* EISA present */ #define IMC_RPSSDIV 0x1fa0002c /* RPSS divider */ #define IMC_RPSSDIV_DIVMSK 0x000000ff /* RPC divider mask */ #define IMC_RPSSDIV_INCMSK 0x0000ff00 /* RPC increment mask */ #define IMC_EEPROM 0x1fa00034 /* EEPROM serial interface */ /* Bit 1 is reserved 0x00000001 */ #define IMC_EEPROM_CS 0x00000002 /* EEPROM chip select */ #define IMC_EEPROM_SCK 0x00000004 /* EEPROM serial clock */ #define IMC_EEPROM_SO 0x00000008 /* Serial data to EEPROM */ #define IMC_EEPROM_SI 0x00000010 /* Serial data from EEPROM */ #define IMC_CTRLD 0x1fa00044 /* Refresh counter preload */ #define IMC_CTRLD_MSK 0x000000ff /* Counter preload mask */ #define IMC_REFCTR 0x1fa0004c /* Refresh counter */ #define IMC_REFCTR_MSK 0x000000ff /* Refresh counter mask */ #define IMC_GIO64ARB 0x1fa00084 /* GIO64 arbitration params */ #define IMC_GIO64ARB_HPC64 0x00000001 /* HPC addr size (32/64bit) */ #define IMC_GIO64ARB_GRX64 0x00000002 /* Gfx addr size (32/64bit) */ #define IMC_GIO64ARB_EXP064 0x00000004 /* EXP0 addr size (32/64bit) */ #define IMC_GIO64ARB_EXP164 0x00000008 /* EXP0 addr size (32/64bit) */ #define IMC_GIO64ARB_EISA64 0x00000010 /* EISA addr size (32/64bit) */ #define IMC_GIO64ARB_HPCEXP64 0x00000020 /* HPC2 addr size (32/64bit) */ #define IMC_GIO64ARB_GRXRT 0x00000040 /* Gfx is realtime device */ #define IMC_GIO64ARB_EXP0RT 0x00000080 /* EXP0 is realtime device */ #define IMC_GIO64ARB_EXP1RT 0x00000100 /* EXP1 is realtime device */ #define IMC_GIO64ARB_EISAMST 0x00000200 /* EISA can be busmaster */ #define IMC_GIO64ARB_ONEGIO 0x00000400 /* One one GIO64 bus */ #define IMC_GIO64ARB_GRXMST 0x00000800 /* Gfx can be busmaster */ #define IMC_GIO64ARB_EXP0MST 0x00001000 /* EXP0 can be busmaster */ #define IMC_GIO64ARB_EXP1MST 0x00002000 /* EXP1 can be busmaster */ #define IMC_GIO64ARB_EXP0PIPE 0x00004000 /* EXP0 is pipelined */ #define IMC_GIO64ARB_EXP1PIPE 0x00008000 /* EXP1 is pipelined */ #define IMC_CPUTIME 0x1fa0008c /* Arbiter CPU time period */ #define IMC_LBTIME 0x1fa0009c /* Arbiter long-burst time */ #define IMC_MEMCFG0 0x1fa000c4 /* Mem config, regsiter 0 */ #define IMC_MEMCFG1 0x1fa000cc /* Mem config, regsiter 1 */ #define IMC_CPU_MEMACC 0x1fa000d4 /* CPU mem access config */ #define IMC_GIO_MEMACC 0x1fa000dc /* GIO mem access config */ #define IMC_CPU_ERRADDR 0x1fa000e4 /* CPU error address */ #define IMC_CPU_ERRSTAT 0x1fa000ec /* CPU error status */ #define IMC_GIO_ERRADDR 0x1fa000f4 /* GIO error address */ #define IMC_GIO_ERRSTAT 0x1fa000fc /* GIO error status */ #endif /* _ARCH_SGIMIPS_DEV_IMCREG_H_ */ gxemul-0.6.1/src/include/thirdparty/sh4_scifreg.h000644 001750 001750 00000014710 13402411502 022205 0ustar00debugdebug000000 000000 /* $NetBSD: scifreg.h,v 1.10 2006/02/18 00:41:32 uwe Exp $ */ #ifndef _SH3_SCIFREG_H_ #define _SH3_SCIFREG_H_ /*- * Copyright (C) 1999 SAITOH Masanobu. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Serial Communication Interface with FIFO (SCIF) */ #define SH3_SCIF0_BASE 0xa4000150 #define SH3_SCIF1_BASE 0xa4000140 #define SH4_SCIF_BASE 0xffe80000 #ifdef SH3 /* SH3 definitions */ #define SCIF_SMR 0x0 /* serial mode */ #define SCIF_BRR 0x2 /* bit rate */ #define SCIF_SCR 0x4 /* serial control */ #define SCIF_FTDR 0x6 /* transmit fifo data */ #define SCIF_SSR 0x8 /* serial status */ #define SCIF_FRDR 0xa /* receive fifo data */ #define SCIF_FCR 0xc /* fifo control */ #define SCIF_FDR 0xe /* fifo data count set */ #define SHREG_SCSMR2 (*(volatile uint8_t *)(SH3_SCIF0_BASE + SCIF_SMR)) #define SHREG_SCBRR2 (*(volatile uint8_t *)(SH3_SCIF0_BASE + SCIF_BRR)) #define SHREG_SCSCR2 (*(volatile uint8_t *)(SH3_SCIF0_BASE + SCIF_SCR)) #define SHREG_SCFTDR2 (*(volatile uint8_t *)(SH3_SCIF0_BASE + SCIF_FTDR)) #define SHREG_SCSSR2 (*(volatile uint16_t *)(SH3_SCIF0_BASE + SCIF_SSR)) #define SHREG_SCFRDR2 (*(volatile uint8_t *)(SH3_SCIF0_BASE + SCIF_FRDR)) #define SHREG_SCFCR2 (*(volatile uint8_t *)(SH3_SCIF0_BASE + SCIF_FCR)) #define SHREG_SCFDR2 (*(volatile uint16_t *)(SH3_SCIF0_BASE + SCIF_FDR)) #else /* !SH3 */ /* SH4 definitions */ #define SCIF_SMR 0x00 /* serial mode */ #define SCIF_BRR 0x04 /* bit rate */ #define SCIF_SCR 0x08 /* serial control */ #define SCIF_FTDR 0x0c /* transmit fifo data */ #define SCIF_SSR 0x10 /* serial status */ #define SCIF_FRDR 0x14 /* receive fifo data */ #define SCIF_FCR 0x18 /* fifo control */ #define SCIF_FDR 0x1c /* fifo data count set */ #define SCIF_SPTR 0x20 /* serial port */ #define SCIF_LSR 0x24 /* line status */ #define SHREG_SCSMR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_SMR)) #define SHREG_SCBRR2 (*(volatile uint8_t *)(SH4_SCIF_BASE + SCIF_BRR)) #define SHREG_SCSCR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_SCR)) #define SHREG_SCFTDR2 (*(volatile uint8_t *)(SH4_SCIF_BASE + SCIF_FTDR)) #define SHREG_SCSSR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_SSR)) #define SHREG_SCFRDR2 (*(volatile uint8_t *)(SH4_SCIF_BASE + SCIF_FRDR)) #define SHREG_SCFCR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_FCR)) #define SHREG_SCFDR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_FDR)) #define SHREG_SCSPTR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_SPTR)) #define SHREG_SCLSR2 (*(volatile uint16_t *)(SH4_SCIF_BASE + SCIF_LSR)) /* alias */ #define SHREG_SCSFDR2 SHREG_SCFTDR2 #define SHREG_SCFSR2 SHREG_SCSSR2 #define SCSPTR2_RTSIO 0x0080 #define SCSPTR2_RTSDT 0x0040 #define SCSPTR2_CTSIO 0x0020 #define SCSPTR2_CTSDT 0x0010 #define SCSPTR2_SCKIO 0x0008 #define SCSPTR2_SCKDT 0x0004 #define SCSPTR2_SPB2IO 0x0002 #define SCSPTR2_SPB2DT 0x0001 #define SCLSR2_ORER 0x0001 /* overrun error */ #endif /* !SH3 */ /* SMR: serial mode */ #define SCSMR2_CHR 0x40 /* character width (set = 7bit) */ #define SCSMR2_PE 0x20 /* Parity Enable */ #define SCSMR2_O 0x10 /* parity mode Odd */ #define SCSMR2_STOP 0x08 /* STOP bit (set = 2 stop bits) */ #define SCSMR2_CKS1 0x02 /* ClocK Select 1 */ #define SCSMR2_CKS0 0x01 /* ClocK Select 0 */ /* SMR: serial mode (for IrDA) */ #define SCSMR2_IRMOD 0x80 /* IrDA mode */ #define SCSMR2_ICK3 0x40 #define SCSMR2_ICK2 0x20 #define SCSMR2_ICK1 0x10 #define SCSMR2_ICK0 0x08 #define SCSMR2_PSEL 0x04 /* Pulse width SELelect */ /* SCR: serial control */ #define SCSCR2_TIE 0x80 /* Transmit Interrupt Enable */ #define SCSCR2_RIE 0x40 /* Recieve Interrupt Enable */ #define SCSCR2_TE 0x20 /* Transmit Enable */ #define SCSCR2_RE 0x10 /* Receive Enable */ #define SCSCR2_CKE1 0x02 /* ClocK Enable 1 */ #define SCSCR2_CKE0 0x01 /* ClocK Enable 0 (not in sh4) */ /* SSR: serial status */ #define SCSSR2_ER 0x0080 /* ERror */ #define SCSSR2_TEND 0x0040 /* Transmit END */ #define SCSSR2_TDFE 0x0020 /* Transmit Data Fifo Empty */ #define SCSSR2_BRK 0x0010 /* BReaK detection */ #define SCSSR2_FER 0x0008 /* Framing ERror */ #define SCSSR2_PER 0x0004 /* Parity ERror */ #define SCSSR2_RDF 0x0002 /* Recieve fifo Data Full */ #define SCSSR2_DR 0x0001 /* Data Ready */ /* FCR: fifo control */ #define SCFCR2_RTRG1 0x80 /* Receive TRiGger 1 */ #define SCFCR2_RTRG0 0x40 /* Receive TRiGger 0 */ #define SCFCR2_TTRG1 0x20 /* Transmit TRiGger 1 */ #define SCFCR2_TTRG0 0x10 /* Transmit TRiGger 0 */ #define SCFCR2_MCE 0x08 /* Modem Control Enable */ #define SCFCR2_TFRST 0x04 /* Transmit Fifo register ReSeT */ #define SCFCR2_RFRST 0x02 /* Receive Fifo register ReSeT */ #define SCFCR2_LOOP 0x01 /* LOOP back test */ #define FIFO_RCV_TRIGGER_1 0x00 #define FIFO_RCV_TRIGGER_4 0x40 #define FIFO_RCV_TRIGGER_8 0x80 #define FIFO_RCV_TRIGGER_14 0xc0 #define FIFO_XMT_TRIGGER_8 0x00 #define FIFO_XMT_TRIGGER_4 0x10 #define FIFO_XMT_TRIGGER_2 0x20 #define FIFO_XMT_TRIGGER_1 0x30 /* FDR: fifo data count set */ #define SCFDR2_TXCNT 0xff00 /* Tx CouNT */ #define SCFDR2_RECVCNT 0x00ff /* Rx CouNT */ #define SCFDR2_TXF_FULL 0x1000 /* Tx FULL */ #define SCFDR2_RXF_EPTY 0x0000 /* Rx EMPTY */ #endif /* !_SH3_SCIFREG_ */ gxemul-0.6.1/src/include/thirdparty/cyclone_boot.h000644 001750 001750 00000006005 13402411502 022462 0ustar00debugdebug000000 000000 /* GXemul: $Id: cyclone_boot.h,v 1.1 2005-08-20 12:47:06 debug Exp $ */ /* $NetBSD: cyclone_boot.h,v 1.1 2001/06/20 22:14:34 chris Exp $ */ #ifndef CYCLONE_BOOT_H #define CYCLONE_BOOT_H /* * Copyright (c) 1997,1998 Mark Brinicombe. * Copyright (c) 1997,1998 Causality Limited. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Mark Brinicombe. * 4. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Define the boot structure that is passed to the kernel * from the cyclone firmware. * * The bootloader reserves a page for boot argument info. * This page will contain the ebsaboot structure and the * kernel argument string. */ struct ebsaboot { u_int32_t bt_magic; /* boot info magic number */ u_int32_t bt_vargp; /* virtual addr of arg page */ u_int32_t bt_pargp; /* physical addr of arg page */ u_int32_t bt_args; /* kernel args string pointer */ /* was: const char * */ uint32_t bt_l1; /* active L1 page table */ /* was: pd_entry_t * */ u_int32_t bt_memstart; /* start of physical memory */ u_int32_t bt_memend; /* end of physical memory */ u_int32_t bt_memavail; /* start of avail phys memory */ u_int32_t bt_fclk; /* fclk frequency */ u_int32_t bt_pciclk; /* PCI bus frequency */ u_int32_t bt_vers; /* structure version (CATS) */ u_int32_t bt_features; /* feature mask (CATS) */ }; #define BT_MAGIC_NUMBER_EBSA 0x45425341 #define BT_MAGIC_NUMBER_CATS 0x43415453 #define BT_BOOT_VERSION_OLD 0 #define BT_BOOT_VERSION_NEW 1 /* End of cyclone_boot.h */ #endif /* CYCLONE_BOOT_H */ gxemul-0.6.1/src/include/thirdparty/osiopreg.h000644 001750 001750 00000034764 13402411502 021647 0ustar00debugdebug000000 000000 /* $OpenBSD: osiopreg.h,v 1.5 2005/11/21 21:52:47 miod Exp $ */ /* $NetBSD: osiopreg.h,v 1.1 2001/04/30 04:47:51 tsutsui Exp $ */ /* * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Van Jacobson of Lawrence Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)siopreg.h 7.3 (Berkeley) 2/5/91 */ /* * NCR 53C710 SCSI interface hardware description. * * From the Mach scsi driver for the 53C710 and amiga siop driver */ /* GXemul: little-endian is used here, and swapped at runtime instead! */ /* byte lane definitions */ /* #if BYTE_ORDER == LITTLE_ENDIAN */ #define BL0 0 #define BL1 1 #define BL2 2 #define BL3 3 /* #else */ /* #define BL0 3 */ /* #define BL1 2 */ /* #define BL2 1 */ /* #define BL3 0 */ /* #endif */ #define OSIOP_SCNTL0 (0x00+BL0) /* rw: SCSI control reg 0 */ #define OSIOP_SCNTL1 (0x00+BL1) /* rw: SCSI control reg 1 */ #define OSIOP_SDID (0x00+BL2) /* rw: SCSI destination ID */ #define OSIOP_SIEN (0x00+BL3) /* rw: SCSI interrupt enable */ #define OSIOP_SCID (0x04+BL0) /* rw: SCSI Chip ID reg */ #define OSIOP_SXFER (0x04+BL1) /* rw: SCSI Transfer reg */ #define OSIOP_SODL (0x04+BL2) /* rw: SCSI Output Data Latch */ #define OSIOP_SOCL (0x04+BL3) /* rw: SCSI Output Control Latch */ #define OSIOP_SFBR (0x08+BL0) /* ro: SCSI First Byte Received */ #define OSIOP_SIDL (0x08+BL1) /* ro: SCSI Input Data Latch */ #define OSIOP_SBDL (0x08+BL2) /* ro: SCSI Bus Data Lines */ #define OSIOP_SBCL (0x08+BL3) /* rw: SCSI Bus Control Lines */ #define OSIOP_DSTAT (0x0c+BL0) /* ro: DMA status */ #define OSIOP_SSTAT0 (0x0c+BL1) /* ro: SCSI status reg 0 */ #define OSIOP_SSTAT1 (0x0c+BL2) /* ro: SCSI status reg 1 */ #define OSIOP_SSTAT2 (0x0c+BL3) /* ro: SCSI status reg 2 */ #define OSIOP_DSA 0x10 /* rw: Data Structure Address */ #define OSIOP_CTEST0 (0x14+BL0) /* ro: Chip test register 0 */ #define OSIOP_CTEST1 (0x14+BL1) /* ro: Chip test register 1 */ #define OSIOP_CTEST2 (0x14+BL2) /* ro: Chip test register 2 */ #define OSIOP_CTEST3 (0x14+BL3) /* ro: Chip test register 3 */ #define OSIOP_CTEST4 (0x18+BL0) /* rw: Chip test register 4 */ #define OSIOP_CTEST5 (0x18+BL1) /* rw: Chip test register 5 */ #define OSIOP_CTEST6 (0x18+BL2) /* rw: Chip test register 6 */ #define OSIOP_CTEST7 (0x18+BL3) /* rw: Chip test register 7 */ #define OSIOP_TEMP 0x1c /* rw: Temporary Stack reg */ #define OSIOP_DFIFO (0x20+BL0) /* rw: DMA FIFO */ #define OSIOP_ISTAT (0x20+BL1) /* rw: Interrupt Status reg */ #define OSIOP_CTEST8 (0x20+BL2) /* rw: Chip test register 8 */ #define OSIOP_LCRC (0x20+BL3) /* rw: LCRC value */ #define OSIOP_DBC 0x24 /* rw: DMA Counter reg (longword) */ #define OSIOP_DBC0 (0x24+BL0) /* rw: DMA Byte Counter reg 0 */ #define OSIOP_DBC1 (0x24+BL1) /* rw: DMA Byte Counter reg 1 */ #define OSIOP_DBC2 (0x24+BL2) /* rw: DMA Byte Counter reg 2 */ #define OSIOP_DCMD (0x24+BL3) /* rw: DMA Command Register */ #define OSIOP_DNAD 0x28 /* rw: DMA Next Data Address */ #define OSIOP_DSP 0x2c /* rw: DMA SCRIPTS Pointer reg */ #define OSIOP_DSPS 0x30 /* rw: DMA SCRIPTS Pointer Save reg */ #define OSIOP_SCRATCH 0x34 /* rw: Scratch register */ #define OSIOP_DMODE (0x38+BL0) /* rw: DMA Mode reg */ #define OSIOP_DIEN (0x38+BL1) /* rw: DMA Interrupt Enable */ #define OSIOP_DWT (0x38+BL2) /* rw: DMA Watchdog Timer */ #define OSIOP_DCNTL (0x38+BL3) /* rw: DMA Control reg */ #define OSIOP_ADDER 0x3c /* ro: Adder Sum Output */ #define OSIOP_NREGS 0x40 /* * Register defines */ /* Scsi control register 0 (scntl0) */ #define OSIOP_SCNTL0_ARB 0xc0 /* Arbitration mode */ #define OSIOP_ARB_SIMPLE 0x00 #define OSIOP_ARB_FULL 0xc0 #define OSIOP_SCNTL0_START 0x20 /* Start Sequence */ #define OSIOP_SCNTL0_WATN 0x10 /* (Select) With ATN */ #define OSIOP_SCNTL0_EPC 0x08 /* Enable Parity Checking */ #define OSIOP_SCNTL0_EPG 0x04 /* Enable Parity Generation */ #define OSIOP_SCNTL0_AAP 0x02 /* Assert ATN on Parity Error */ #define OSIOP_SCNTL0_TRG 0x01 /* Target Mode */ /* Scsi control register 1 (scntl1) */ #define OSIOP_SCNTL1_EXC 0x80 /* Extra Clock Cycle of data setup */ #define OSIOP_SCNTL1_ADB 0x40 /* Assert Data Bus */ #define OSIOP_SCNTL1_ESR 0x20 /* Enable Selection/Reselection */ #define OSIOP_SCNTL1_CON 0x10 /* Connected */ #define OSIOP_SCNTL1_RST 0x08 /* Assert RST */ #define OSIOP_SCNTL1_AESP 0x04 /* Assert even SCSI parity */ #define OSIOP_SCNTL1_PAR 0x04 /* Force bad Parity */ #define OSIOP_SCNTL1_RES0 0x02 /* Reserved */ #define OSIOP_SCNTL1_RES1 0x01 /* Reserved */ /* Scsi interrupt enable register (sien) */ #define OSIOP_SIEN_M_A 0x80 /* Phase Mismatch or ATN active */ #define OSIOP_SIEN_FCMP 0x40 /* Function Complete */ #define OSIOP_SIEN_STO 0x20 /* (Re)Selection timeout */ #define OSIOP_SIEN_SEL 0x10 /* (Re)Selected */ #define OSIOP_SIEN_SGE 0x08 /* SCSI Gross Error */ #define OSIOP_SIEN_UDC 0x04 /* Unexpected Disconnect */ #define OSIOP_SIEN_RST 0x02 /* RST asserted */ #define OSIOP_SIEN_PAR 0x01 /* Parity Error */ /* Scsi chip ID (scid) */ #define OSIOP_SCID_VALUE(i) (1 << (i)) /* Scsi transfer register (sxfer) */ #define OSIOP_SXFER_DHP 0x80 /* Disable Halt on Parity error/ ATN asserted */ #define OSIOP_SXFER_TP 0x70 /* Synch Transfer Period */ /* see specs for formulas: Period = TCP * (4 + XFERP ) TCP = 1 + CLK + 1..2; */ #define OSIOP_SXFER_MO 0x0f /* Synch Max Offset */ #define OSIOP_MAX_OFFSET 8 /* Scsi output data latch register (sodl) */ /* Scsi output control latch register (socl) */ #define OSIOP_REQ 0x80 /* SCSI signal asserted */ #define OSIOP_ACK 0x40 #define OSIOP_BSY 0x20 #define OSIOP_SEL 0x10 #define OSIOP_ATN 0x08 #define OSIOP_MSG 0x04 #define OSIOP_CD 0x02 #define OSIOP_IO 0x01 #define OSIOP_PHASE(x) ((x) & (OSIOP_MSG|OSIOP_CD|OSIOP_IO)) #define DATA_OUT_PHASE 0x00 #define DATA_IN_PHASE OSIOP_IO #define COMMAND_PHASE OSIOP_CD #define STATUS_PHASE (OSIOP_CD|OSIOP_IO) #define MSG_OUT_PHASE (OSIOP_MSG|OSIOP_CD) #define MSG_IN_PHASE (OSIOP_MSG|OSIOP_CD|OSIOP_IO) /* Scsi first byte received register (sfbr) */ /* Scsi input data latch register (sidl) */ /* Scsi bus data lines register (sbdl) */ /* Scsi bus control lines register (sbcl). Same as socl */ #define OSIOP_SBCL_SSCF1 0x02 /* wo */ #define OSIOP_SBCL_SSCF0 0x01 /* wo */ /* DMA status register (dstat) */ #define OSIOP_DSTAT_DFE 0x80 /* DMA FIFO empty */ #define OSIOP_DSTAT_RES 0x40 #define OSIOP_DSTAT_BF 0x20 /* Bus fault */ #define OSIOP_DSTAT_ABRT 0x10 /* Aborted */ #define OSIOP_DSTAT_SSI 0x08 /* SCRIPT Single Step */ #define OSIOP_DSTAT_SIR 0x04 /* SCRIPT Interrupt Instruction */ #define OSIOP_DSTAT_WTD 0x02 /* Watchdog Timeout Detected */ #define OSIOP_DSTAT_IID 0x01 /* Invalid Instruction Detected */ /* Scsi status register 0 (sstat0) */ #define OSIOP_SSTAT0_M_A 0x80 /* Phase Mismatch or ATN active */ #define OSIOP_SSTAT0_FCMP 0x40 /* Function Complete */ #define OSIOP_SSTAT0_STO 0x20 /* (Re)Selection timeout */ #define OSIOP_SSTAT0_SEL 0x10 /* (Re)Selected */ #define OSIOP_SSTAT0_SGE 0x08 /* SCSI Gross Error */ #define OSIOP_SSTAT0_UDC 0x04 /* Unexpected Disconnect */ #define OSIOP_SSTAT0_RST 0x02 /* RST asserted */ #define OSIOP_SSTAT0_PAR 0x01 /* Parity Error */ /* Scsi status register 1 (sstat1) */ #define OSIOP_SSTAT1_ILF 0x80 /* Input latch (sidl) full */ #define OSIOP_SSTAT1_ORF 0x40 /* output reg (sodr) full */ #define OSIOP_SSTAT1_OLF 0x20 /* output latch (sodl) full */ #define OSIOP_SSTAT1_AIP 0x10 /* Arbitration in progress */ #define OSIOP_SSTAT1_LOA 0x08 /* Lost arbitration */ #define OSIOP_SSTAT1_WOA 0x04 /* Won arbitration */ #define OSIOP_SSTAT1_RST 0x02 /* SCSI RST current value */ #define OSIOP_SSTAT1_SDP 0x01 /* SCSI SDP current value */ /* Scsi status register 2 (sstat2) */ #define OSIOP_SSTAT2_FF 0xf0 /* SCSI FIFO flags (bytecount) */ #define OSIOP_SCSI_FIFO_DEEP 8 #define OSIOP_SSTAT2_SDP 0x08 /* Latched (on REQ) SCSI SDP */ #define OSIOP_SSTAT2_MSG 0x04 /* Latched SCSI phase */ #define OSIOP_SSTAT2_CD 0x02 #define OSIOP_SSTAT2_IO 0x01 /* Chip test register 0 (ctest0) */ #define OSIOP_CTEST0_RES0 0x80 #define OSIOP_CTEST0_BTD 0x40 /* Byte-to-byte Timer Disable */ #define OSIOP_CTEST0_GRP 0x20 /* Generate Receive Parity */ #define OSIOP_CTEST0_EAN 0x10 /* Enable Active Negation */ #define OSIOP_CTEST0_HSC 0x08 /* Halt SCSI clock */ #define OSIOP_CTEST0_ERF 0x04 /* Extend REQ/ACK Filtering */ #define OSIOP_CTEST0_RES1 0x02 #define OSIOP_CTEST0_DDIR 0x01 /* Xfer direction (1-> from SCSI bus) */ /* Chip test register 1 (ctest1) */ #define OSIOP_CTEST1_FMT 0xf0 /* Byte empty in DMA FIFO bottom (high->byte3) */ #define OSIOP_CTEST1_FFL 0x0f /* Byte full in DMA FIFO top, same */ /* Chip test register 2 (ctest2) */ #define OSIOP_CTEST2_RES 0x80 #define OSIOP_CTEST2_SIGP 0x40 /* Signal process */ #define OSIOP_CTEST2_SOFF 0x20 /* Synch Offset compare (1-> zero Init, max Tgt */ #define OSIOP_CTEST2_SFP 0x10 /* SCSI FIFO Parity */ #define OSIOP_CTEST2_DFP 0x08 /* DMA FIFO Parity */ #define OSIOP_CTEST2_TEOP 0x04 /* True EOP (a-la 5380) */ #define OSIOP_CTEST2_DREQ 0x02 /* DREQ status */ #define OSIOP_CTEST2_DACK 0x01 /* DACK status */ /* Chip test register 3 (ctest3) read-only, top of SCSI FIFO */ /* Chip test register 4 (ctest4) */ #define OSIOP_CTEST4_MUX 0x80 /* Host bus multiplex mode */ #define OSIOP_CTEST4_ZMOD 0x40 /* High-impedance outputs */ #define OSIOP_CTEST4_SZM 0x20 /* ditto, SCSI "outputs" */ #define OSIOP_CTEST4_SLBE 0x10 /* SCSI loopback enable */ #define OSIOP_CTEST4_SFWR 0x08 /* SCSI FIFO write enable (from sodl) */ #define OSIOP_CTEST4_FBL 0x07 /* DMA FIFO Byte Lane select (from ctest6) 4->0, .. 7->3 */ /* Chip test register 5 (ctest5) */ #define OSIOP_CTEST5_ADCK 0x80 /* Clock Address Incrementor */ #define OSIOP_CTEST5_BBCK 0x40 /* Clock Byte counter */ #define OSIOP_CTEST5_ROFF 0x20 /* Reset SCSI offset */ #define OSIOP_CTEST5_MASR 0x10 /* Master set/reset pulses (of bits 3-0) */ #define OSIOP_CTEST5_DDIR 0x08 /* (re)set internal DMA direction */ #define OSIOP_CTEST5_EOP 0x04 /* (re)set internal EOP */ #define OSIOP_CTEST5_DREQ 0x02 /* (re)set internal REQ */ #define OSIOP_CTEST5_DACK 0x01 /* (re)set internal ACK */ /* Chip test register 6 (ctest6) DMA FIFO access */ /* Chip test register 7 (ctest7) */ #define OSIOP_CTEST7_CDIS 0x80 /* Cache burst disable */ #define OSIOP_CTEST7_SC1 0x40 /* Snoop control 1 */ #define OSIOP_CTEST7_SC0 0x20 /* Snoop control 0 */ #define OSIOP_CTEST7_STD 0x10 /* Selection timeout disable */ #define OSIOP_CTEST7_DFP 0x08 /* DMA FIFO parity bit */ #define OSIOP_CTEST7_EVP 0x04 /* Even parity (to host bus) */ #define OSIOP_CTEST7_TT1 0x02 /* Transfer type bit */ #define OSIOP_CTEST7_DIFF 0x01 /* Differential mode */ /* DMA FIFO register (dfifo) */ #define OSIOP_DFIFO_FLF 0x80 /* Flush (spill) DMA FIFO */ #define OSIOP_DFIFO_BO 0x7f /* FIFO byte offset counter */ /* Interrupt status register (istat) */ #define OSIOP_ISTAT_ABRT 0x80 /* Abort operation */ #define OSIOP_ISTAT_RST 0x40 /* Software reset */ #define OSIOP_ISTAT_SIGP 0x20 /* Signal process */ #define OSIOP_ISTAT_RES 0x10 #define OSIOP_ISTAT_CON 0x08 /* Connected */ #define OSIOP_ISTAT_RES1 0x04 #define OSIOP_ISTAT_SIP 0x02 /* SCSI Interrupt pending */ #define OSIOP_ISTAT_DIP 0x01 /* DMA Interrupt pending */ /* Chip test register 8 (ctest8) */ #define OSIOP_CTEST8_V 0xf0 /* Chip revision level */ #define OSIOP_CTEST8_FLF 0x08 /* Flush DMA FIFO */ #define OSIOP_CTEST8_CLF 0x04 /* Clear DMA and SCSI FIFOs */ #define OSIOP_CTEST8_FM 0x02 /* Fetch pin mode */ #define OSIOP_CTEST8_SM 0x01 /* Snoop pins mode */ /* DMA Mode register (dmode) */ #define OSIOP_DMODE_BL_MASK 0xc0 /* DMA burst length */ #define OSIOP_DMODE_BL8 0xc0 /* 8 bytes */ #define OSIOP_DMODE_BL4 0x80 /* 4 bytes */ #define OSIOP_DMODE_BL2 0x40 /* 2 bytes */ #define OSIOP_DMODE_BL1 0x00 /* 1 byte */ #define OSIOP_DMODE_FC 0x30 /* Function code */ #define OSIOP_DMODE_PD 0x08 /* Program/data */ #define OSIOP_DMODE_FAM 0x04 /* fixed address mode */ #define OSIOP_DMODE_U0 0x02 /* User programmable transfer type */ #define OSIOP_DMODE_MAN 0x01 /* SCRIPTS in Manual start mode */ /* DMA interrupt enable register (dien) */ #define OSIOP_DIEN_RES 0xc0 #define OSIOP_DIEN_BF 0x20 /* On Bus Fault */ #define OSIOP_DIEN_ABRT 0x10 /* On Abort */ #define OSIOP_DIEN_SSI 0x08 /* On SCRIPTS sstep */ #define OSIOP_DIEN_SIR 0x04 /* On SCRIPTS intr instruction */ #define OSIOP_DIEN_WTD 0x02 /* On watchdog timeout */ #define OSIOP_DIEN_IID 0x01 /* On illegal instruction detected */ /* DMA control register (dcntl) */ #define OSIOP_DCNTL_CF_MASK 0xc0 /* Clock frequency dividers: */ #define OSIOP_DCNTL_CF_2 0x00 /* 0 --> 37.51..50.00 MHz, div=2 */ #define OSIOP_DCNTL_CF_1_5 0x40 /* 1 --> 25.01..37.50 MHz, div=1.5 */ #define OSIOP_DCNTL_CF_1 0x80 /* 2 --> 16.67..25.00 MHz, div=1 */ #define OSIOP_DCNTL_CF_3 0xc0 /* 3 --> 50.01..66.67 MHz, div=3 */ #define OSIOP_DCNTL_EA 0x20 /* Enable ACK */ #define OSIOP_DCNTL_SSM 0x10 /* Single step mode */ #define OSIOP_DCNTL_LLM 0x08 /* Enable SCSI Low-level mode */ #define OSIOP_DCNTL_STD 0x04 /* Start DMA operation */ #define OSIOP_DCNTL_FA 0x02 /* Fast arbitration */ #define OSIOP_DCNTL_COM 0x01 /* 53C700 Compatibility */ gxemul-0.6.1/src/include/thirdparty/impactsr-bsd.h000644 001750 001750 00000016742 13402411502 022404 0ustar00debugdebug000000 000000 #ifndef IMPACTSR_H #define IMPACTSR_H /* * Copyright (C) 2004 by Stanislaw Skowronek. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Convenient access macros */ #define IMPACTSR_REG64(vma,off) (*(volatile unsigned long *)((vma)+(off))) #define IMPACTSR_REG32(vma,off) (*(volatile unsigned int *)((vma)+(off))) #define IMPACTSR_REG16(vma,off) (*(volatile unsigned short *)((vma)+(off))) #define IMPACTSR_REG8(vma,off) (*(volatile unsigned char *)((vma)+(off))) /* ImpactSR (HQ4) register offsets */ #define IMPACTSR_CFIFO(vma) IMPACTSR_REG64(vma,0x20400) #define IMPACTSR_CFIFOW(vma) IMPACTSR_REG32(vma,0x20400) #define IMPACTSR_CFIFOP(vma) IMPACTSR_REG64(vma,0x130400) #define IMPACTSR_CFIFOPW(vma) IMPACTSR_REG32(vma,0x130400) #define IMPACTSR_STATUS(vma) IMPACTSR_REG32(vma,0x20000) #define IMPACTSR_FIFOSTATUS(vma) IMPACTSR_REG32(vma,0x20008) #define IMPACTSR_GIOSTATUS(vma) IMPACTSR_REG32(vma,0x20100) #define IMPACTSR_DMABUSY(vma) IMPACTSR_REG32(vma,0x20200) #define IMPACTSR_RESTATUS(vma) IMPACTSR_REG32(vma,0x2c578) #define IMPACTSR_CFIFO_HW(vma) IMPACTSR_REG32(vma,0x40000) #define IMPACTSR_CFIFO_LW(vma) IMPACTSR_REG32(vma,0x40008) #define IMPACTSR_CFIFO_DELAY(vma) IMPACTSR_REG32(vma,0x40010) #define IMPACTSR_DFIFO_HW(vma) IMPACTSR_REG32(vma,0x40020) #define IMPACTSR_DFIFO_LW(vma) IMPACTSR_REG32(vma,0x40028) #define IMPACTSR_DFIFO_DELAY(vma) IMPACTSR_REG32(vma,0x40030) #define IMPACTSR_XMAP_PP1SELECT(vma) IMPACTSR_REG8(vma,0x71c08) #define IMPACTSR_XMAP_INDEX(vma) IMPACTSR_REG8(vma,0x71c88) #define IMPACTSR_XMAP_CONFIG(vma) IMPACTSR_REG32(vma,0x71d00) #define IMPACTSR_XMAP_CONFIGB(vma) IMPACTSR_REG8(vma,0x71d08) #define IMPACTSR_XMAP_BUF_SELECT(vma) IMPACTSR_REG32(vma,0x71d80) #define IMPACTSR_XMAP_MAIN_MODE(vma) IMPACTSR_REG32(vma,0x71e00) #define IMPACTSR_XMAP_OVERLAY_MODE(vma) IMPACTSR_REG32(vma,0x71e80) #define IMPACTSR_XMAP_DIB(vma) IMPACTSR_REG32(vma,0x71f00) #define IMPACTSR_XMAP_DIB_DW(vma) IMPACTSR_REG32(vma,0x71f40) #define IMPACTSR_XMAP_RE_RAC(vma) IMPACTSR_REG32(vma,0x71f80) #define IMPACTSR_VC3_INDEX(vma) IMPACTSR_REG8(vma,0x72008) #define IMPACTSR_VC3_INDEXDATA(vma) IMPACTSR_REG32(vma,0x72038) #define IMPACTSR_VC3_DATA(vma) IMPACTSR_REG16(vma,0x720b0) #define IMPACTSR_VC3_RAM(vma) IMPACTSR_REG16(vma,0x72190) /* FIFO status */ #define IMPACTSR_CFIFO_MAX 128 #define IMPACTSR_BFIFO_MAX 16 /* Commands for CFIFO */ #define IMPACTSR_CMD_WRITERSS(reg,val) (((0x00180004L|((reg)<<8))<<32)|((unsigned)(val)&0xffffffff)) #define IMPACTSR_CMD_EXECRSS(reg,val) (((0x001c0004L|((reg)<<8))<<32)|((unsigned)(val)&0xffffffff)) #define IMPACTSR_CMD_GLINE_XSTARTF(v) IMPACTSR_CMD_WRITERSS(0x00c,v) #define IMPACTSR_CMD_IR_ALIAS(v) IMPACTSR_CMD_EXECRSS(0x045,v) #define IMPACTSR_CMD_BLOCKXYSTARTI(x,y) IMPACTSR_CMD_WRITERSS(0x046,((x)<<16)|(y)) #define IMPACTSR_CMD_BLOCKXYENDI(x,y) IMPACTSR_CMD_WRITERSS(0x047,((x)<<16)|(y)) #define IMPACTSR_CMD_PACKEDCOLOR(v) IMPACTSR_CMD_WRITERSS(0x05b,v) #define IMPACTSR_CMD_RED(v) IMPACTSR_CMD_WRITERSS(0x05c,v) #define IMPACTSR_CMD_ALPHA(v) IMPACTSR_CMD_WRITERSS(0x05f,v) #define IMPACTSR_CMD_CHAR(v) IMPACTSR_CMD_EXECRSS(0x070,v) #define IMPACTSR_CMD_CHAR_H(v) IMPACTSR_CMD_WRITERSS(0x070,v) #define IMPACTSR_CMD_CHAR_L(v) IMPACTSR_CMD_EXECRSS(0x071,v) #define IMPACTSR_CMD_XFRCONTROL(v) IMPACTSR_CMD_WRITERSS(0x102,v) #define IMPACTSR_CMD_FILLMODE(v) IMPACTSR_CMD_WRITERSS(0x110,v) #define IMPACTSR_CMD_CONFIG(v) IMPACTSR_CMD_WRITERSS(0x112,v) #define IMPACTSR_CMD_XYWIN(x,y) IMPACTSR_CMD_WRITERSS(0x115,((y)<<16)|(x)) #define IMPACTSR_CMD_BKGRD_RG(v) IMPACTSR_CMD_WRITERSS(0x140,((v)<<8)) #define IMPACTSR_CMD_BKGRD_BA(v) IMPACTSR_CMD_WRITERSS(0x141,((v)<<8)) #define IMPACTSR_CMD_WINMODE(v) IMPACTSR_CMD_WRITERSS(0x14f,v) #define IMPACTSR_CMD_XFRSIZE(x,y) IMPACTSR_CMD_WRITERSS(0x153,((y)<<16)|(x)) #define IMPACTSR_CMD_XFRMASKLO(v) IMPACTSR_CMD_WRITERSS(0x156,v) #define IMPACTSR_CMD_XFRMASKHI(v) IMPACTSR_CMD_WRITERSS(0x157,v) #define IMPACTSR_CMD_XFRCOUNTERS(x,y) IMPACTSR_CMD_WRITERSS(0x158,((y)<<16)|(x)) #define IMPACTSR_CMD_XFRMODE(v) IMPACTSR_CMD_WRITERSS(0x159,v) #define IMPACTSR_CMD_RE_TOGGLECNTX(v) IMPACTSR_CMD_WRITERSS(0x15f,v) #define IMPACTSR_CMD_PIXCMD(v) IMPACTSR_CMD_WRITERSS(0x160,v) #define IMPACTSR_CMD_PP1FILLMODE(m,o) IMPACTSR_CMD_WRITERSS(0x161,(m)|(o<<26)) #define IMPACTSR_CMD_COLORMASKMSBS(v) IMPACTSR_CMD_WRITERSS(0x162,v) #define IMPACTSR_CMD_COLORMASKLSBSA(v) IMPACTSR_CMD_WRITERSS(0x163,v) #define IMPACTSR_CMD_COLORMASKLSBSB(v) IMPACTSR_CMD_WRITERSS(0x164,v) #define IMPACTSR_CMD_DRBPOINTERS(v) IMPACTSR_CMD_WRITERSS(0x16d,v) #define IMPACTSR_CMD_HQ_PIXELFORMAT(v) (0x000c000400000000L|((unsigned)(v)&0xffffffff)) #define IMPACTSR_CMD_HQ_SCANWIDTH(v) (0x000a020400000000L|((unsigned)(v)&0xffffffff)) #define IMPACTSR_CMD_HQ_DMATYPE(v) (0x000a060400000000L|((unsigned)(v)&0xffffffff)) #define IMPACTSR_CMD_HQ_PG_LIST_0(v) (0x0008000400000000L|((unsigned)(v)&0xffffffff)) #define IMPACTSR_CMD_HQ_PG_WIDTH(v) (0x0008040400000000L|((unsigned)(v)&0xffffffff)) #define IMPACTSR_CMD_HQ_PG_OFFSET(v) (0x0008050400000000L|((unsigned)(v)&0xffffffff)) #define IMPACTSR_CMD_HQ_PG_STARTADDR(v) (0x0008060400000000L|((unsigned)(v)&0xffffffff)) #define IMPACTSR_CMD_HQ_PG_LINECNT(v) (0x0008070400000000L|((unsigned)(v)&0xffffffff)) #define IMPACTSR_CMD_HQ_PG_WIDTHA(v) (0x0008080400000000L|((unsigned)(v)&0xffffffff)) #define IMPACTSR_CMD_HQ_TXBASE(p) (0x00482008|((p)<<9)) #define IMPACTSR_CMD_HQ_TXMAX(p,v) (0x0048300400000000L|((unsigned)(v)&0xffffffff)|((unsigned long)(p)<<40)) #define IMPACTSR_CMD_HQ_PGBITS(p,v) (0x00482b0400000000L|((unsigned)(v)&0xffffffff)|((unsigned long)(p)<<40)) #define IMPACTSR_CMD_HQ_PGSIZE(v) (0x00482a0400000000L|((unsigned)(v)&0xffffffff)) #define IMPACTSR_CMD_HQ_STACKPTR(v) (0x00483a0400000000L|((unsigned)(v)&0xffffffff)) /* Logic operations for the PP1 (SI=source invert, DI=dest invert, RI=result invert) */ #define IMPACTSR_LO_COPY 0 #define IMPACTSR_LO_DIAND 1 #define IMPACTSR_LO_AND 2 #define IMPACTSR_LO_CLEAR 3 #define IMPACTSR_LO_OR 4 #define IMPACTSR_LO_XOR 5 #define IMPACTSR_LO_NOP 6 #define IMPACTSR_LO_SIAND 7 #define IMPACTSR_LO_DIOR 8 #define IMPACTSR_LO_RINOP 9 #define IMPACTSR_LO_RIXOR 10 #define IMPACTSR_LO_RIOR 11 #define IMPACTSR_LO_SET 12 #define IMPACTSR_LO_RIAND 13 #define IMPACTSR_LO_SIOR 14 #define IMPACTSR_LO_RICOPY 15 #endif /* IMPACTSR_H */ gxemul-0.6.1/src/include/thirdparty/ohcireg.h000644 001750 001750 00000023306 13402411502 021426 0ustar00debugdebug000000 000000 /* $NetBSD: ohcireg.h,v 1.19 2002/07/11 21:14:27 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/ohcireg.h,v 1.8 1999/11/17 22:33:40 n_hibma Exp $ */ #ifndef OHCIREG_H #define OHCIREG_H /* * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Lennart Augustsson (lennart@augustsson.net) at * Carlstedt Research & Technology. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*** PCI config registers ***/ #define PCI_CBMEM 0x10 /* configuration base memory */ #define PCI_INTERFACE_OHCI 0x10 /*** OHCI registers */ #define OHCI_REVISION 0x00 /* OHCI revision # */ #define OHCI_REV_LO(rev) ((rev)&0xf) #define OHCI_REV_HI(rev) (((rev)>>4)&0xf) #define OHCI_REV_LEGACY(rev) ((rev) & 0x100) #define OHCI_CONTROL 0x04 #define OHCI_CBSR_MASK 0x00000003 /* Control/Bulk Service Ratio */ #define OHCI_RATIO_1_1 0x00000000 #define OHCI_RATIO_1_2 0x00000001 #define OHCI_RATIO_1_3 0x00000002 #define OHCI_RATIO_1_4 0x00000003 #define OHCI_PLE 0x00000004 /* Periodic List Enable */ #define OHCI_IE 0x00000008 /* Isochronous Enable */ #define OHCI_CLE 0x00000010 /* Control List Enable */ #define OHCI_BLE 0x00000020 /* Bulk List Enable */ #define OHCI_HCFS_MASK 0x000000c0 /* HostControllerFunctionalState */ #define OHCI_HCFS_RESET 0x00000000 #define OHCI_HCFS_RESUME 0x00000040 #define OHCI_HCFS_OPERATIONAL 0x00000080 #define OHCI_HCFS_SUSPEND 0x000000c0 #define OHCI_IR 0x00000100 /* Interrupt Routing */ #define OHCI_RWC 0x00000200 /* Remote Wakeup Connected */ #define OHCI_RWE 0x00000400 /* Remote Wakeup Enabled */ #define OHCI_COMMAND_STATUS 0x08 #define OHCI_HCR 0x00000001 /* Host Controller Reset */ #define OHCI_CLF 0x00000002 /* Control List Filled */ #define OHCI_BLF 0x00000004 /* Bulk List Filled */ #define OHCI_OCR 0x00000008 /* Ownership Change Request */ #define OHCI_SOC_MASK 0x00030000 /* Scheduling Overrun Count */ #define OHCI_INTERRUPT_STATUS 0x0c #define OHCI_SO 0x00000001 /* Scheduling Overrun */ #define OHCI_WDH 0x00000002 /* Writeback Done Head */ #define OHCI_SF 0x00000004 /* Start of Frame */ #define OHCI_RD 0x00000008 /* Resume Detected */ #define OHCI_UE 0x00000010 /* Unrecoverable Error */ #define OHCI_FNO 0x00000020 /* Frame Number Overflow */ #define OHCI_RHSC 0x00000040 /* Root Hub Status Change */ #define OHCI_OC 0x40000000 /* Ownership Change */ #define OHCI_MIE 0x80000000 /* Master Interrupt Enable */ #define OHCI_INTERRUPT_ENABLE 0x10 #define OHCI_INTERRUPT_DISABLE 0x14 #define OHCI_HCCA 0x18 #define OHCI_PERIOD_CURRENT_ED 0x1c #define OHCI_CONTROL_HEAD_ED 0x20 #define OHCI_CONTROL_CURRENT_ED 0x24 #define OHCI_BULK_HEAD_ED 0x28 #define OHCI_BULK_CURRENT_ED 0x2c #define OHCI_DONE_HEAD 0x30 #define OHCI_FM_INTERVAL 0x34 #define OHCI_GET_IVAL(s) ((s) & 0x3fff) #define OHCI_GET_FSMPS(s) (((s) >> 16) & 0x7fff) #define OHCI_FIT 0x80000000 #define OHCI_FM_REMAINING 0x38 #define OHCI_FM_NUMBER 0x3c #define OHCI_PERIODIC_START 0x40 #define OHCI_LS_THRESHOLD 0x44 #define OHCI_RH_DESCRIPTOR_A 0x48 #define OHCI_GET_NDP(s) ((s) & 0xff) #define OHCI_PSM 0x0100 /* Power Switching Mode */ #define OHCI_NPS 0x0200 /* No Power Switching */ #define OHCI_DT 0x0400 /* Device Type */ #define OHCI_OCPM 0x0800 /* Overcurrent Protection Mode */ #define OHCI_NOCP 0x1000 /* No Overcurrent Protection */ #define OHCI_GET_POTPGT(s) ((s) >> 24) #define OHCI_RH_DESCRIPTOR_B 0x4c #define OHCI_RH_STATUS 0x50 #define OHCI_LPS 0x00000001 /* Local Power Status */ #define OHCI_OCI 0x00000002 /* OverCurrent Indicator */ #define OHCI_DRWE 0x00008000 /* Device Remote Wakeup Enable */ #define OHCI_LPSC 0x00010000 /* Local Power Status Change */ #define OHCI_CCIC 0x00020000 /* OverCurrent Indicator Change */ #define OHCI_CRWE 0x80000000 /* Clear Remote Wakeup Enable */ #define OHCI_RH_PORT_STATUS(n) (0x50 + (n)*4) /* 1 based indexing */ #define OHCI_LES (OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE) #define OHCI_ALL_INTRS (OHCI_SO | OHCI_WDH | OHCI_SF | OHCI_RD | OHCI_UE | \ OHCI_FNO | OHCI_RHSC | OHCI_OC) #define OHCI_NORMAL_INTRS (OHCI_SO | OHCI_WDH | OHCI_RD | OHCI_UE | OHCI_RHSC) #define OHCI_FSMPS(i) (((i-210)*6/7) << 16) #define OHCI_PERIODIC(i) ((i)*9/10) typedef u_int32_t ohci_physaddr_t; #define OHCI_NO_INTRS 32 struct ohci_hcca { ohci_physaddr_t hcca_interrupt_table[OHCI_NO_INTRS]; u_int32_t hcca_frame_number; ohci_physaddr_t hcca_done_head; #define OHCI_DONE_INTRS 1 }; #define OHCI_HCCA_SIZE 256 #define OHCI_HCCA_ALIGN 256 #define OHCI_PAGE_SIZE 0x1000 #define OHCI_PAGE(x) ((x) &~ 0xfff) #define OHCI_PAGE_OFFSET(x) ((x) & 0xfff) typedef struct { u_int32_t ed_flags; #define OHCI_ED_GET_FA(s) ((s) & 0x7f) #define OHCI_ED_ADDRMASK 0x0000007f #define OHCI_ED_SET_FA(s) (s) #define OHCI_ED_GET_EN(s) (((s) >> 7) & 0xf) #define OHCI_ED_SET_EN(s) ((s) << 7) #define OHCI_ED_DIR_MASK 0x00001800 #define OHCI_ED_DIR_TD 0x00000000 #define OHCI_ED_DIR_OUT 0x00000800 #define OHCI_ED_DIR_IN 0x00001000 #define OHCI_ED_SPEED 0x00002000 #define OHCI_ED_SKIP 0x00004000 #define OHCI_ED_FORMAT_GEN 0x00000000 #define OHCI_ED_FORMAT_ISO 0x00008000 #define OHCI_ED_GET_MAXP(s) (((s) >> 16) & 0x07ff) #define OHCI_ED_SET_MAXP(s) ((s) << 16) #define OHCI_ED_MAXPMASK (0x7ff << 16) ohci_physaddr_t ed_tailp; ohci_physaddr_t ed_headp; #define OHCI_HALTED 0x00000001 #define OHCI_TOGGLECARRY 0x00000002 #define OHCI_HEADMASK 0xfffffffc ohci_physaddr_t ed_nexted; } ohci_ed_t; /* #define OHCI_ED_SIZE 16 */ #define OHCI_ED_ALIGN 16 typedef struct { u_int32_t td_flags; #define OHCI_TD_R 0x00040000 /* Buffer Rounding */ #define OHCI_TD_DP_MASK 0x00180000 /* Direction / PID */ #define OHCI_TD_SETUP 0x00000000 #define OHCI_TD_OUT 0x00080000 #define OHCI_TD_IN 0x00100000 #define OHCI_TD_GET_DI(x) (((x) >> 21) & 7) /* Delay Interrupt */ #define OHCI_TD_SET_DI(x) ((x) << 21) #define OHCI_TD_NOINTR 0x00e00000 #define OHCI_TD_INTR_MASK 0x00e00000 #define OHCI_TD_TOGGLE_CARRY 0x00000000 #define OHCI_TD_TOGGLE_0 0x02000000 #define OHCI_TD_TOGGLE_1 0x03000000 #define OHCI_TD_TOGGLE_MASK 0x03000000 #define OHCI_TD_GET_EC(x) (((x) >> 26) & 3) /* Error Count */ #define OHCI_TD_GET_CC(x) ((x) >> 28) /* Condition Code */ #define OHCI_TD_NOCC 0xf0000000 ohci_physaddr_t td_cbp; /* Current Buffer Pointer */ ohci_physaddr_t td_nexttd; /* Next TD */ ohci_physaddr_t td_be; /* Buffer End */ } ohci_td_t; /* #define OHCI_TD_SIZE 16 */ #define OHCI_TD_ALIGN 16 #define OHCI_ITD_NOFFSET 8 typedef struct { u_int32_t itd_flags; #define OHCI_ITD_GET_SF(x) ((x) & 0x0000ffff) #define OHCI_ITD_SET_SF(x) ((x) & 0xffff) #define OHCI_ITD_GET_DI(x) (((x) >> 21) & 7) /* Delay Interrupt */ #define OHCI_ITD_SET_DI(x) ((x) << 21) #define OHCI_ITD_NOINTR 0x00e00000 #define OHCI_ITD_GET_FC(x) ((((x) >> 24) & 7)+1) /* Frame Count */ #define OHCI_ITD_SET_FC(x) (((x)-1) << 24) #define OHCI_ITD_GET_CC(x) ((x) >> 28) /* Condition Code */ #define OHCI_ITD_NOCC 0xf0000000 ohci_physaddr_t itd_bp0; /* Buffer Page 0 */ ohci_physaddr_t itd_nextitd; /* Next ITD */ ohci_physaddr_t itd_be; /* Buffer End */ u_int16_t itd_offset[OHCI_ITD_NOFFSET]; /* Buffer offsets */ #define itd_pswn itd_offset /* Packet Status Word*/ #define OHCI_ITD_PAGE_SELECT 0x00001000 #define OHCI_ITD_MK_OFFS(len) (0xe000 | ((len) & 0x1fff)) #define OHCI_ITD_PSW_LENGTH(x) ((x) & 0xfff) /* Transfer length */ #define OHCI_ITD_PSW_GET_CC(x) ((x) >> 12) /* Condition Code */ } ohci_itd_t; /* #define OHCI_ITD_SIZE 32 */ #define OHCI_ITD_ALIGN 32 #define OHCI_CC_NO_ERROR 0 #define OHCI_CC_CRC 1 #define OHCI_CC_BIT_STUFFING 2 #define OHCI_CC_DATA_TOGGLE_MISMATCH 3 #define OHCI_CC_STALL 4 #define OHCI_CC_DEVICE_NOT_RESPONDING 5 #define OHCI_CC_PID_CHECK_FAILURE 6 #define OHCI_CC_UNEXPECTED_PID 7 #define OHCI_CC_DATA_OVERRUN 8 #define OHCI_CC_DATA_UNDERRUN 9 #define OHCI_CC_BUFFER_OVERRUN 12 #define OHCI_CC_BUFFER_UNDERRUN 13 #define OHCI_CC_NOT_ACCESSED 15 /* Some delay needed when changing certain registers. */ #define OHCI_ENABLE_POWER_DELAY 5 #define OHCI_READ_DESC_DELAY 5 #endif /* OHCIREG_H */ gxemul-0.6.1/src/include/thirdparty/sh4_intcreg.h000644 001750 001750 00000010277 13402411502 022222 0ustar00debugdebug000000 000000 /* $NetBSD: intcreg.h,v 1.10 2005/12/11 12:18:58 christos Exp $ */ #ifndef _SH3_INTCREG_H_ #define _SH3_INTCREG_H_ /*- * Copyright (C) 1999 SAITOH Masanobu. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* #include */ /* * INTC */ /* SH3 SH7708*, SH7709* common */ #define SH3_ICR0 0xfffffee0 /* 16bit */ #define SH3_IPRA 0xfffffee2 /* 16bit */ #define SH3_IPRB 0xfffffee4 /* 16bit */ /* SH7709, SH7709A only */ #define SH7709_ICR1 0xa4000010 /* 16bit */ #define SH7709_ICR2 0xa4000012 /* 16bit */ #define SH7709_PINTER 0xa4000014 /* 16bit */ #define SH7709_IPRC 0xa4000016 /* 16bit */ #define SH7709_IPRD 0xa4000018 /* 16bit */ #define SH7709_IPRE 0xa400001a /* 16bit */ #define SH7709_IRR0 0xa4000004 /* 8bit */ #define SH7709_IRR1 0xa4000006 /* 8bit */ #define SH7709_IRR2 0xa4000008 /* 8bit */ #define IPRC_IRQ3_MASK 0xf000 #define IPRC_IRQ2_MASK 0x0f00 #define IPRC_IRQ1_MASK 0x00f0 #define IPRC_IRQ0_MASK 0x000f #define IPRD_PINT07_MASK 0xf000 #define IPRD_PINT8F_MASK 0x0f00 #define IPRD_IRQ5_MASK 0x00f0 #define IPRD_IRQ4_MASK 0x000f #define IPRE_DMAC_MASK 0xf000 #define IPRE_IRDA_MASK 0x0f00 #define IPRE_SCIF_MASK 0x00f0 #define IPRE_ADC_MASK 0x000f #define IRR0_PINT8F 0x80 #define IRR0_PINT07 0x40 #define IRR0_IRQ5 0x20 #define IRR0_IRQ4 0x10 #define IRR0_IRQ3 0x08 #define IRR0_IRQ2 0x04 #define IRR0_IRQ1 0x02 #define IRR0_IRQ0 0x01 /* SH4 */ #define SH4_ICR 0xffd00000 /* 16bit */ #define SH4_IPRA 0xffd00004 /* 16bit */ #define SH4_IPRB 0xffd00008 /* 16bit */ #define SH4_IPRC 0xffd0000c /* 16bit */ #define SH4_IPRD 0xffd00010 /* 16bit */ #define SH4_INTPRI00 0xfe080000 /* 32bit */ #define SH4_INTREQ00 0xfe080020 /* 32bit */ #define SH4_INTMSK00 0xfe080040 /* 32bit */ #define SH4_INTMSKCLR00 0xfe080060 /* 32bit */ #define IPRC_GPIO_MASK 0xf000 #define IPRC_DMAC_MASK 0x0f00 #define IPRC_SCIF_MASK 0x00f0 #define IPRC_HUDI_MASK 0x000f #define IPRD_IRL0_MASK 0xf000 #define IPRD_IRL1_MASK 0x0f00 #define IPRD_IRL2_MASK 0x00f0 #define IPRD_IRL3_MASK 0x000f #define IPRA_TMU0_MASK 0xf000 #define IPRA_TMU1_MASK 0x0f00 #define IPRA_TMU2_MASK 0x00f0 #define IPRA_RTC_MASK 0x000f #define IPRB_WDT_MASK 0xf000 #define IPRB_REF_MASK 0x0f00 #define IPRB_SCI_MASK 0x00f0 #define INTPRI00_PCI0_MASK 0x0000000f #define INTPRI00_PCI1_MASK 0x000000f0 #define INTPRI00_TMU3_MASK 0x00000f00 #define INTPRI00_TMU4_MASK 0x0000f000 /* INTREQ/INTMSK/INTMSKCLR */ #define INTREQ00_PCISERR 0x00000001 #define INTREQ00_PCIDMA3 0x00000002 #define INTREQ00_PCIDMA2 0x00000004 #define INTREQ00_PCIDMA1 0x00000008 #define INTREQ00_PCIDMA0 0x00000010 #define INTREQ00_PCIPWON 0x00000020 #define INTREQ00_PCIPWDWN 0x00000040 #define INTREQ00_PCIERR 0x00000080 #define INTREQ00_TUNI3 0x00000100 #define INTREQ00_TUNI4 0x00000200 #define INTMSK00_MASK_ALL 0x000003ff #endif /* !_SH3_INTCREG_H_ */ gxemul-0.6.1/src/include/thirdparty/siireg.h000644 001750 001750 00000020636 13402411502 021273 0ustar00debugdebug000000 000000 /* $NetBSD: siireg.h,v 1.4 1994/10/26 21:09:22 cgd Exp $ */ /* * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)siireg.h 8.1 (Berkeley) 6/10/93 * * sii.h -- * * SII registers. * * Copyright (C) 1989 Digital Equipment Corporation. * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies. * Digital Equipment Corporation makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * from: Header: /sprite/src/kernel/dev/ds3100.md/RCS/sii.h, * v 1.2 89/08/15 19:53:04 rab Exp SPRITE (DECWRL) */ #ifndef _SII #define _SII /* * SII hardware registers */ typedef /*volatile*/ struct { u_short sdb; /* SCSI Data Bus and Parity */ u_short pad0; u_short sc1; /* SCSI Control Signals One */ u_short pad1; u_short sc2; /* SCSI Control Signals Two */ u_short pad2; u_short csr; /* Control/Status register */ u_short pad3; u_short id; /* Bus ID register */ u_short pad4; u_short slcsr; /* Select Control and Status Register */ u_short pad5; u_short destat; /* Selection Detector Status Register */ u_short pad6; u_short dstmo; /* DSSI Timeout Register */ u_short pad7; u_short data; /* Data Register */ u_short pad8; u_short dmctrl; /* DMA Control Register */ u_short pad9; u_short dmlotc; /* DMA Length of Transfer Counter */ u_short pad10; u_short dmaddrl; /* DMA Address Register Low */ u_short pad11; u_short dmaddrh; /* DMA Address Register High */ u_short pad12; u_short dmabyte; /* DMA Initial Byte Register */ u_short pad13; u_short stlp; /* DSSI Short Target List Pointer */ u_short pad14; u_short ltlp; /* DSSI Long Target List Pointer */ u_short pad15; u_short ilp; /* DSSI Initiator List Pointer */ u_short pad16; u_short dsctrl; /* DSSI Control Register */ u_short pad17; u_short cstat; /* Connection Status Register */ u_short pad18; u_short dstat; /* Data Transfer Status Register */ u_short pad19; u_short comm; /* Command Register */ u_short pad20; u_short dictrl; /* Diagnostic Control Register */ u_short pad21; u_short clock; /* Diagnostic Clock Register */ u_short pad22; u_short bhdiag; /* Bus Handler Diagnostic Register */ u_short pad23; u_short sidiag; /* SCSI IO Diagnostic Register */ u_short pad24; u_short dmdiag; /* Data Mover Diagnostic Register */ u_short pad25; u_short mcdiag; /* Main Control Diagnostic Register */ u_short pad26; } SIIRegs; /* * SC1 - SCSI Control Signals One */ #define SII_SC1_MSK 0x1ff /* All possible signals on the bus */ #define SII_SC1_SEL 0x80 /* SCSI SEL signal active on bus */ #define SII_SC1_ATN 0x08 /* SCSI ATN signal active on bus */ /* * SC2 - SCSI Control Signals Two */ #define SII_SC2_IGS 0x8 /* SCSI drivers for initiator mode */ /* * CSR - Control/Status Register */ #define SII_HPM 0x10 /* SII in on an arbitrated SCSI bus */ #define SII_RSE 0x08 /* 1 = respond to reselections */ #define SII_SLE 0x04 /* 1 = respond to selections */ #define SII_PCE 0x02 /* 1 = report parity errors */ #define SII_IE 0x01 /* 1 = enable interrupts */ /* * ID - Bus ID Register */ #define SII_ID_IO 0x8000 /* I/O */ /* * DESTAT - Selection Detector Status Register */ #define SII_IDMSK 0x7 /* ID of target reselected the SII */ /* * DMCTRL - DMA Control Register */ #define SII_ASYNC 0x00 /* REQ/ACK Offset for async mode */ #define SII_SYNC 0x03 /* REQ/ACK Offset for sync mode */ /* * DMLOTC - DMA Length Of Transfer Counter */ #define SII_TCMSK 0x1fff /* transfer count mask */ /* * CSTAT - Connection Status Register */ #define SII_CI 0x8000 /* composite interrupt bit for CSTAT */ #define SII_DI 0x4000 /* composite interrupt bit for DSTAT */ #define SII_RST 0x2000 /* 1 if reset is asserted on SCSI bus */ #define SII_BER 0x1000 /* Bus error */ #define SII_OBC 0x0800 /* Out_en Bit Cleared (DSSI mode) */ #define SII_TZ 0x0400 /* Target pointer Zero (STLP or LTLP is zero) */ #define SII_BUF 0x0200 /* Buffer service - outbound pkt to non-DSSI */ #define SII_LDN 0x0100 /* List element Done */ #define SII_SCH 0x0080 /* State Change */ #define SII_CON 0x0040 /* SII is Connected to another device */ #define SII_DST 0x0020 /* SII was Destination of current transfer */ #define SII_TGT 0x0010 /* SII is operating as a Target */ #define SII_STATE_MSK 0x0070 /* State Mask */ #define SII_SWA 0x0008 /* Selected With Attention */ #define SII_SIP 0x0004 /* Selection In Progress */ #define SII_LST 0x0002 /* Lost arbitration */ /* * DSTAT - Data Transfer Status Register */ #define SII_DNE 0x2000 /* DMA transfer Done */ #define SII_TCZ 0x1000 /* Transfer Count register is Zero */ #define SII_TBE 0x0800 /* Transmit Buffer Empty */ #define SII_IBF 0x0400 /* Input Buffer Full */ #define SII_IPE 0x0200 /* Incoming Parity Error */ #define SII_OBB 0x0100 /* Odd Byte Boundry */ #define SII_MIS 0x0010 /* Phase Mismatch */ #define SII_ATN 0x0008 /* ATN set by initiator if in Target mode */ #define SII_MSG 0x0004 /* current bus state of MSG */ #define SII_CD 0x0002 /* current bus state of C/D */ #define SII_IO 0x0001 /* current bus state of I/O */ #define SII_PHASE_MSK 0x0007 /* Phase Mask */ /* * The different phases. */ #define SII_MSG_IN_PHASE 0x7 #define SII_MSG_OUT_PHASE 0x6 #define SII_STATUS_PHASE 0x3 #define SII_CMD_PHASE 0x2 #define SII_DATA_IN_PHASE 0x1 #define SII_DATA_OUT_PHASE 0x0 /* * COMM - Command Register */ #define SII_DMA 0x8000 /* DMA mode */ #define SII_DO_RST 0x4000 /* Assert reset on SCSI bus for 25 usecs */ #define SII_RSL 0x1000 /* 0 = select, 1 = reselect desired device */ /* Commands: I - Initiator, T - Target, D - Disconnected */ #define SII_INXFER 0x0800 /* Information Transfer command (I,T) */ #define SII_SELECT 0x0400 /* Select command (D) */ #define SII_REQDATA 0x0200 /* Request Data command (T) */ #define SII_DISCON 0x0100 /* Disconnect command (I,T,D) */ #define SII_CHRESET 0x0080 /* Chip Reset command (I,T,D) */ /* Command state bits same as connection status register */ /* Command phase bits same as data transfer status register */ /* * DICTRL - Diagnostic Control Register */ #define SII_PRE 0x4 /* Enable the SII to drive the SCSI bus */ #define SII_WAIT_COUNT 10000 /* Delay count used for the SII chip */ /* * Max DMA transfer length for SII * The SII chip only has a 13 bit counter. If 8192 is used as the max count, * you can't tell the difference between a count of zero and 8192. * 8190 is used instead of 8191 so the count is even. */ #define SII_MAX_DMA_XFER_LENGTH 8192 #endif /* _SII */ gxemul-0.6.1/src/include/thirdparty/sh4_exception.h000644 001750 001750 00000013734 13402411502 022566 0ustar00debugdebug000000 000000 /* $NetBSD: exception.h,v 1.8 2006/03/04 01:55:03 uwe Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SH3_EXCEPTION_H_ #define _SH3_EXCEPTION_H_ /* * SH3/SH4 Exception handling. */ /* #include */ /* #ifdef _KERNEL */ #define SH3_TRA 0xffffffd0 /* 32bit */ #define SH3_EXPEVT 0xffffffd4 /* 32bit */ #define SH3_INTEVT 0xffffffd8 /* 32bit */ #define SH7709_INTEVT2 0xa4000000 /* 32bit */ #define SH4_TRA 0xff000020 /* 32bit */ #define SH4_EXPEVT 0xff000024 /* 32bit */ #define SH4_INTEVT 0xff000028 /* 32bit */ /* * EXPEVT */ /* Reset exception */ #define EXPEVT_RESET_POWER 0x000 /* Power-On reset */ #define EXPEVT_RESET_MANUAL 0x020 /* Manual reset */ #define EXPEVT_RESET_TLB_MULTI_HIT 0x140 /* SH4 only */ /* General exception */ #define EXPEVT_TLB_MISS_LD 0x040 /* TLB miss (load) */ #define EXPEVT_TLB_MISS_ST 0x060 /* TLB miss (store) */ #define EXPEVT_TLB_MOD 0x080 /* Initial page write */ #define EXPEVT_TLB_PROT_LD 0x0a0 /* Protection violation (load) */ #define EXPEVT_TLB_PROT_ST 0x0c0 /* Protection violation (store)*/ #define EXPEVT_ADDR_ERR_LD 0x0e0 /* Address error (load) */ #define EXPEVT_ADDR_ERR_ST 0x100 /* Address error (store) */ #define EXPEVT_FPU 0x120 /* FPU exception */ #define EXPEVT_TRAPA 0x160 /* Unconditional trap (TRAPA) */ #define EXPEVT_RES_INST 0x180 /* Illegal instruction */ #define EXPEVT_SLOT_INST 0x1a0 /* Illegal slot instruction */ #define EXPEVT_BREAK 0x1e0 /* User break */ #define EXPEVT_FPU_DISABLE 0x800 /* FPU disabled */ #define EXPEVT_FPU_SLOT_DISABLE 0x820 /* Slot FPU disabled */ /* Software bit */ #define EXP_USER 0x001 /* exception from user-mode */ #define _SH_TRA_BREAK 0xc3 /* magic number for debugger */ /* * INTEVT/INTEVT2 */ /* External interrupt */ #define SH_INTEVT_NMI 0x1c0 #define SH_INTEVT_TMU0_TUNI0 0x400 #define SH_INTEVT_TMU1_TUNI1 0x420 #define SH_INTEVT_TMU2_TUNI2 0x440 #define SH_INTEVT_TMU2_TICPI2 0x460 #define SH_INTEVT_SCI_ERI 0x4e0 #define SH_INTEVT_SCI_RXI 0x500 #define SH_INTEVT_SCI_TXI 0x520 #define SH_INTEVT_SCI_TEI 0x540 #define SH_INTEVT_WDT_ITI 0x560 #define SH_INTEVT_IRL9 0x320 #define SH_INTEVT_IRL11 0x360 #define SH_INTEVT_IRL13 0x3a0 #define SH4_INTEVT_SCIF_ERI 0x700 #define SH4_INTEVT_SCIF_RXI 0x720 #define SH4_INTEVT_SCIF_BRI 0x740 #define SH4_INTEVT_SCIF_TXI 0x760 #define SH7709_INTEVT2_IRQ0 0x600 #define SH7709_INTEVT2_IRQ1 0x620 #define SH7709_INTEVT2_IRQ2 0x640 #define SH7709_INTEVT2_IRQ3 0x660 #define SH7709_INTEVT2_IRQ4 0x680 #define SH7709_INTEVT2_IRQ5 0x6a0 #define SH7709_INTEVT2_PINT07 0x700 #define SH7709_INTEVT2_PINT8F 0x720 #define SH7709_INTEVT2_DEI0 0x800 #define SH7709_INTEVT2_DEI1 0x820 #define SH7709_INTEVT2_DEI2 0x840 #define SH7709_INTEVT2_DEI3 0x860 #define SH7709_INTEVT2_IRDA_ERI 0x880 #define SH7709_INTEVT2_IRDA_RXI 0x8a0 #define SH7709_INTEVT2_IRDA_BRI 0x8c0 #define SH7709_INTEVT2_IRDA_TXI 0x8e0 #define SH7709_INTEVT2_SCIF_ERI 0x900 #define SH7709_INTEVT2_SCIF_RXI 0x920 #define SH7709_INTEVT2_SCIF_BRI 0x940 #define SH7709_INTEVT2_SCIF_TXI 0x960 #define SH7709_INTEVT2_ADC 0x980 /* SH7750R, SH7751, SH7751R */ #define SH4_INTEVT_IRL0 0x240 #define SH4_INTEVT_IRL1 0x2a0 #define SH4_INTEVT_IRL2 0x300 #define SH4_INTEVT_IRL3 0x360 #define SH4_INTEVT_IRQ0 0x200 #define SH4_INTEVT_IRQ1 0x220 #define SH4_INTEVT_IRQ2 0x240 #define SH4_INTEVT_IRQ3 0x260 #define SH4_INTEVT_IRQ4 0x280 #define SH4_INTEVT_IRQ5 0x2a0 #define SH4_INTEVT_IRQ6 0x2c0 #define SH4_INTEVT_IRQ7 0x2e0 #define SH4_INTEVT_IRQ8 0x300 #define SH4_INTEVT_IRQ9 0x320 #define SH4_INTEVT_IRQ10 0x340 #define SH4_INTEVT_IRQ11 0x360 #define SH4_INTEVT_IRQ12 0x380 #define SH4_INTEVT_IRQ13 0x3a0 #define SH4_INTEVT_IRQ14 0x3c0 #define SH4_INTEVT_IRQ15 0x3e0 #define SH4_INTEVT_TMU3 0xb00 #define SH4_INTEVT_TMU4 0xb80 #define SH4_INTEVT_PCISERR 0xa00 #define SH4_INTEVT_PCIERR 0xae0 #define SH4_INTEVT_PCIPWDWN 0xac0 #define SH4_INTEVT_PCIPWON 0xaa0 #define SH4_INTEVT_PCIDMA0 0xa80 #define SH4_INTEVT_PCIDMA1 0xa60 #define SH4_INTEVT_PCIDMA2 0xa40 #define SH4_INTEVT_PCIDMA3 0xa20 #ifndef _LOCORE #if defined(SH3) && defined(SH4) extern uint32_t __sh_TRA; extern uint32_t __sh_EXPEVT; extern uint32_t __sh_INTEVT; #endif /* SH3 && SH4 */ #endif /* !_LOCORE */ /* #endif KERNEL */ #endif /* !_SH3_EXCEPTION_H_ */ gxemul-0.6.1/src/include/thirdparty/sh4_bscreg.h000644 001750 001750 00000006414 13402411502 022032 0ustar00debugdebug000000 000000 /* $NetBSD: bscreg.h,v 1.6 2005/12/11 12:18:58 christos Exp $ */ /* This file has been extended with useful bitfield definitions from the SH7750 manual. */ #ifndef _SH3_BSCREG_H_ #define _SH3_BSCREG_H_ /*- * Copyright (C) 1999 SAITOH Masanobu. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* #include */ /* * Bus State Controller */ #define SH3_BCR1 0xffffff60 /* 16bit */ #define SH3_BCR2 0xffffff62 /* 16bit */ #define SH3_WCR1 0xffffff64 /* 16bit */ #define SH3_WCR2 0xffffff66 /* 16bit */ #define SH3_MCR 0xffffff68 /* 16bit */ #define SH3_DCR 0xffffff6a /* 16bit */ #define SH3_PCR 0xffffff6c /* 16bit */ #define SH3_RTCSR 0xffffff6e /* 16bit */ #define SH3_RTCNT 0xffffff70 /* 16bit */ #define SH3_RTCOR 0xffffff72 /* 16bit */ #define SH3_RFCR 0xffffff74 /* 16bit */ #define SH3_BCR3 0xffffff7e /* 16bit */ #define SH4_BCR1 0xff800000 /* 32bit */ #define SH4_BCR2 0xff800004 /* 16bit */ #define SH4_WCR1 0xff800008 /* 32bit */ #define SH4_WCR2 0xff80000c /* 32bit */ #define SH4_WCR3 0xff800010 /* 32bit */ #define SH4_MCR 0xff800014 /* 32bit */ #define SH4_PCR 0xff800018 /* 16bit */ #define SH4_RTCSR 0xff80001c /* 16bit */ #define SH4_RTCNT 0xff800020 /* 16bit */ #define SH4_RTCOR 0xff800024 /* 16bit */ #define SH4_RFCR 0xff800028 /* 16bit */ #define SH4_PCTRA 0xff80002c /* ??? */ #define SH4_PDTRA 0xff800030 /* ??? */ #define SH4_PCTRB 0xff800040 /* ??? */ #define SH4_PDTRB 0xff800044 /* ??? */ #define SH4_GPIOIC 0xff800048 /* ??? */ #define SH4_BCR3 0xff800050 /* 16bit: SH7751R */ #define SH4_BCR4 0xfe0a00f0 /* 32bit: SH7751R */ #define BCR1_LITTLE_ENDIAN (1 << 31) #define BCR1_MASTER (1 << 30) #define BCR1_BREQEN (1 << 19) #define BCR2_PORTEN (1 << 0) #define RTCSR_CMF (1 << 7) #define RTCSR_CMIE (1 << 6) #define RTCSR_CKS 0x0038 #define RTCSR_OVF (1 << 2) #define RTCSR_OVIE (1 << 1) #define RTCSR_LMTS (1 << 0) #endif /* !_SH3_BSCREG_H_ */ gxemul-0.6.1/src/include/thirdparty/exec_ecoff.h000644 001750 001750 00000011624 13402411502 022074 0ustar00debugdebug000000 000000 /* gxemul: $Id: exec_ecoff.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: exec_ecoff.h,v 1.12 2000/11/21 00:37:56 jdolecek Exp $ */ /* * Copyright (c) 1994 Adam Glass * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Adam Glass. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_EXEC_ECOFF_H_ #define _SYS_EXEC_ECOFF_H_ /* #include */ #include "exec_ecoff_mips.h" struct ecoff_filehdr { uint16_t f_magic; /* magic number */ /* u_short */ uint16_t f_nscns; /* # of sections */ /* u_short */ uint32_t f_timdat; /* time and date stamp */ /* u_int */ uint32_t f_symptr; /* file offset of symbol table */ /* u_long */ uint32_t f_nsyms; /* # of symbol table entries */ /* u_int */ uint16_t f_opthdr; /* sizeof the optional header */ /* u_short */ uint16_t f_flags; /* flags??? */ /* u_short */ }; /* original netbsd types ----^ */ struct ecoff_aouthdr { u_short magic; /* u_short */ u_short vstamp; /* u_short */ ECOFF_PAD uint32_t tsize; /* u_long */ uint32_t dsize; /* u_long */ uint32_t bsize; /* u_long */ uint32_t entry; /* u_long */ uint32_t text_start; /* u_long */ uint32_t data_start; /* u_long */ uint32_t bss_start; /* u_long */ ECOFF_MACHDEP; }; struct ecoff_scnhdr { /* needed for size info */ char s_name[8]; /* name */ uint32_t s_paddr; /* physical addr? for ROMing?*/ /* u_long */ uint32_t s_vaddr; /* virtual addr? */ /* u_long */ uint32_t s_size; /* size */ /* u_long */ uint32_t s_scnptr; /* file offset of raw data */ /* u_long */ uint32_t s_relptr; /* file offset of reloc data */ /* u_long */ uint32_t s_lnnoptr; /* file offset of line data */ /* u_long */ uint16_t s_nreloc; /* # of relocation entries */ /* u_short */ uint16_t s_nlnno; /* # of line entries */ /* u_short */ uint32_t s_flags; /* flags */ /* u_int */ }; struct ecoff_exechdr { struct ecoff_filehdr f; struct ecoff_aouthdr a; }; #define ECOFF_HDR_SIZE (sizeof(struct ecoff_exechdr)) #define ECOFF_OMAGIC 0407 #define ECOFF_NMAGIC 0410 #define ECOFF_ZMAGIC 0413 #define ECOFF_ROUND(value, by) \ (((value) + (by) - 1) & ~((by) - 1)) #define ECOFF_BLOCK_ALIGN(ep, value) \ ((ep)->a.magic == ECOFF_ZMAGIC ? ECOFF_ROUND((value), ECOFF_LDPGSZ) : \ (value)) #define ECOFF_TXTOFF(ep) \ ((ep)->a.magic == ECOFF_ZMAGIC ? 0 : \ ECOFF_ROUND(ECOFF_HDR_SIZE + (ep)->f.f_nscns * \ sizeof(struct ecoff_scnhdr), ECOFF_SEGMENT_ALIGNMENT(ep))) #define ECOFF_DATOFF(ep) \ (ECOFF_BLOCK_ALIGN((ep), ECOFF_TXTOFF(ep) + (ep)->a.tsize)) #define ECOFF_SEGMENT_ALIGN(ep, value) \ (ECOFF_ROUND((value), ((ep)->a.magic == ECOFF_ZMAGIC ? ECOFF_LDPGSZ : \ ECOFF_SEGMENT_ALIGNMENT(ep)))) #ifdef _KERNEL int exec_ecoff_makecmds __P((struct proc *, struct exec_package *)); int exec_ecoff_setup_stack __P((struct proc *, struct exec_package *)); int cpu_exec_ecoff_probe __P((struct proc *, struct exec_package *)); void cpu_exec_ecoff_setregs __P((struct proc *, struct exec_package *, u_long)); int exec_ecoff_prep_omagic __P((struct proc *, struct exec_package *, struct ecoff_exechdr *, struct vnode *)); int exec_ecoff_prep_nmagic __P((struct proc *, struct exec_package *, struct ecoff_exechdr *, struct vnode *)); int exec_ecoff_prep_zmagic __P((struct proc *, struct exec_package *, struct ecoff_exechdr *, struct vnode *)); #endif /* _KERNEL */ #endif /* !_SYS_EXEC_ECOFF_H_ */ gxemul-0.6.1/src/include/thirdparty/rs5c313reg.h000644 001750 001750 00000005124 13402411502 021605 0ustar00debugdebug000000 000000 /* $OpenBSD: rs5c313reg.h,v 1.1 2006/10/06 22:30:26 mickey Exp $ */ /* $NetBSD: rs5c313reg.h,v 1.1 2006/09/07 01:12:00 uwe Exp $ */ #ifndef RS5C313REG_H #define RS5C313REG_H /*- * Copyright (c) 2005 The NetBSD Foundation, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * RICOH RS5C313 Real Time Clock */ #define RS5C313_SEC1 0 #define RS5C313_SEC10 1 #define RS5C313_MIN1 2 #define RS5C313_MIN10 3 #define RS5C313_HOUR1 4 #define RS5C313_HOUR10 5 #define RS5C313_WDAY 6 #define RS5C313_TINT 7 #define RS5C313_DAY1 8 #define RS5C313_DAY10 9 #define RS5C313_MON1 10 #define RS5C313_MON10 11 #define RS5C313_YEAR1 12 #define RS5C313_YEAR10 13 #define RS5C313_CTRL 14 #define RS5C313_TEST 15 /* TINT register */ #define TINT_CT0 0x01 #define TINT_CT1 0x02 #define TINT_CT2 0x04 #define TINT_CT3 0x08 /* CTRL register */ #define CTRL_BSY 0x01 /* read */ #define CTRL_ADJ 0x01 /* write */ #define CTRL_XSTP 0x02 /* read */ #define CTRL_WTEN 0x02 /* write */ #define CTRL_24H 0x04 /* read/write */ #define CTRL_CTFG 0x08 /* read/write */ #define CTRL_BASE CTRL_24H #endif /* RS5C313REG_H */ gxemul-0.6.1/src/include/thirdparty/mips_cpuregs.h000644 001750 001750 00000067676 13402411502 022530 0ustar00debugdebug000000 000000 /* $NetBSD: cpuregs.h,v 1.69 2005/12/20 21:06:43 tron Exp $ */ /* * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)machConst.h 8.1 (Berkeley) 6/10/93 * * machConst.h -- * * Machine dependent constants. * * Copyright (C) 1989 Digital Equipment Corporation. * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies. * Digital Equipment Corporation makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machConst.h, * v 9.2 89/10/21 15:55:22 jhh Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAddrs.h, * v 1.2 89/08/15 18:28:21 rab Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/vm/ds3100.md/RCS/vmPmaxConst.h, * v 9.1 89/09/18 17:33:00 shirriff Exp SPRITE (DECWRL) */ #ifndef _MIPS_CPUREGS_H_ #define _MIPS_CPUREGS_H_ /* #include */ /* For __CONCAT() */ #if defined(_KERNEL_OPT) #include "opt_cputype.h" #endif /* * Address space. * 32-bit mips CPUS partition their 32-bit address space into four segments: * * kuseg 0x00000000 - 0x7fffffff User virtual mem, mapped * kseg0 0x80000000 - 0x9fffffff Physical memory, cached, unmapped * kseg1 0xa0000000 - 0xbfffffff Physical memory, uncached, unmapped * kseg2 0xc0000000 - 0xffffffff kernel-virtual, mapped * * mips1 physical memory is limited to 512Mbytes, which is * doubly mapped in kseg0 (cached) and kseg1 (uncached.) * Caching of mapped addresses is controlled by bits in the TLB entry. */ #define MIPS_KUSEG_START 0x0 #define MIPS_KSEG0_START 0x80000000 #define MIPS_KSEG1_START 0xa0000000 #define MIPS_KSEG2_START 0xc0000000 #define MIPS_MAX_MEM_ADDR 0xbe000000 #define MIPS_RESERVED_ADDR 0xbfc80000 #define MIPS_PHYS_MASK 0x1fffffff #define MIPS_KSEG0_TO_PHYS(x) ((unsigned)(x) & MIPS_PHYS_MASK) #define MIPS_PHYS_TO_KSEG0(x) ((unsigned)(x) | MIPS_KSEG0_START) #define MIPS_KSEG1_TO_PHYS(x) ((unsigned)(x) & MIPS_PHYS_MASK) #define MIPS_PHYS_TO_KSEG1(x) ((unsigned)(x) | MIPS_KSEG1_START) /* Map virtual address to index in mips3 r4k virtually-indexed cache */ #define MIPS3_VA_TO_CINDEX(x) \ ((unsigned)(x) & 0xffffff | MIPS_KSEG0_START) #define MIPS_PHYS_TO_XKPHYS(cca,x) \ ((0x2ULL << 62) | ((unsigned long long)(cca) << 59) | (x)) #define MIPS_XKPHYS_TO_PHYS(x) ((x) & 0x0effffffffffffffULL) /* CPU dependent mtc0 hazard hook */ #define COP0_SYNC /* nothing */ #define COP0_HAZARD_FPUENABLE nop; nop; nop; nop; /* * The bits in the cause register. * * Bits common to r3000 and r4000: * * MIPS_CR_BR_DELAY Exception happened in branch delay slot. * MIPS_CR_COP_ERR Coprocessor error. * MIPS_CR_IP Interrupt pending bits defined below. * (same meaning as in CAUSE register). * MIPS_CR_EXC_CODE The exception type (see exception codes below). * * Differences: * r3k has 4 bits of execption type, r4k has 5 bits. */ #define MIPS_CR_BR_DELAY 0x80000000 #define MIPS_CR_COP_ERR 0x30000000 #define MIPS1_CR_EXC_CODE 0x0000003C /* four bits */ #define MIPS3_CR_EXC_CODE 0x0000007C /* five bits */ #define MIPS_CR_IP 0x0000FF00 #define MIPS_CR_EXC_CODE_SHIFT 2 /* * The bits in the status register. All bits are active when set to 1. * * R3000 status register fields: * MIPS_SR_COP_USABILITY Control the usability of the four coprocessors. * MIPS_SR_TS TLB shutdown. * * MIPS_SR_INT_IE Master (current) interrupt enable bit. * * Differences: * r3k has cache control is via frobbing SR register bits, whereas the * r4k cache control is via explicit instructions. * r3k has a 3-entry stack of kernel/user bits, whereas the * r4k has kernel/supervisor/user. */ #define MIPS_SR_COP_USABILITY 0xf0000000 #define MIPS_SR_COP_0_BIT 0x10000000 #define MIPS_SR_COP_1_BIT 0x20000000 /* r4k and r3k differences, see below */ #define MIPS_SR_MX 0x01000000 /* MIPS64 */ #define MIPS_SR_PX 0x00800000 /* MIPS64 */ #define MIPS_SR_BEV 0x00400000 /* Use boot exception vector */ #define MIPS_SR_TS 0x00200000 /* r4k and r3k differences, see below */ #define MIPS_SR_INT_IE 0x00000001 /*#define MIPS_SR_MBZ 0x0f8000c0*/ /* Never used, true for r3k */ /*#define MIPS_SR_INT_MASK 0x0000ff00*/ /* * The R2000/R3000-specific status register bit definitions. * all bits are active when set to 1. * * MIPS_SR_PARITY_ERR Parity error. * MIPS_SR_CACHE_MISS Most recent D-cache load resulted in a miss. * MIPS_SR_PARITY_ZERO Zero replaces outgoing parity bits. * MIPS_SR_SWAP_CACHES Swap I-cache and D-cache. * MIPS_SR_ISOL_CACHES Isolate D-cache from main memory. * Interrupt enable bits defined below. * MIPS_SR_KU_OLD Old kernel/user mode bit. 1 => user mode. * MIPS_SR_INT_ENA_OLD Old interrupt enable bit. * MIPS_SR_KU_PREV Previous kernel/user mode bit. 1 => user mode. * MIPS_SR_INT_ENA_PREV Previous interrupt enable bit. * MIPS_SR_KU_CUR Current kernel/user mode bit. 1 => user mode. */ #define MIPS1_PARITY_ERR 0x00100000 #define MIPS1_CACHE_MISS 0x00080000 #define MIPS1_PARITY_ZERO 0x00040000 #define MIPS1_SWAP_CACHES 0x00020000 #define MIPS1_ISOL_CACHES 0x00010000 #define MIPS1_SR_KU_OLD 0x00000020 /* 2nd stacked KU/IE*/ #define MIPS1_SR_INT_ENA_OLD 0x00000010 /* 2nd stacked KU/IE*/ #define MIPS1_SR_KU_PREV 0x00000008 /* 1st stacked KU/IE*/ #define MIPS1_SR_INT_ENA_PREV 0x00000004 /* 1st stacked KU/IE*/ #define MIPS1_SR_KU_CUR 0x00000002 /* current KU */ /* backwards compatibility */ #define MIPS_SR_PARITY_ERR MIPS1_PARITY_ERR #define MIPS_SR_CACHE_MISS MIPS1_CACHE_MISS #define MIPS_SR_PARITY_ZERO MIPS1_PARITY_ZERO #define MIPS_SR_SWAP_CACHES MIPS1_SWAP_CACHES #define MIPS_SR_ISOL_CACHES MIPS1_ISOL_CACHES #define MIPS_SR_KU_OLD MIPS1_SR_KU_OLD #define MIPS_SR_INT_ENA_OLD MIPS1_SR_INT_ENA_OLD #define MIPS_SR_KU_PREV MIPS1_SR_KU_PREV #define MIPS_SR_KU_CUR MIPS1_SR_KU_CUR #define MIPS_SR_INT_ENA_PREV MIPS1_SR_INT_ENA_PREV /* * R4000 status register bit definitons, * where different from r2000/r3000. */ #define MIPS3_SR_XX 0x80000000 #define MIPS3_SR_RP 0x08000000 #define MIPS3_SR_FR 0x04000000 #define MIPS3_SR_RE 0x02000000 #define MIPS3_SR_DIAG_DL 0x01000000 /* QED 52xx */ #define MIPS3_SR_DIAG_IL 0x00800000 /* QED 52xx */ #define MIPS3_SR_SR 0x00100000 #define MIPS3_SR_EIE 0x00100000 /* TX79/R5900 */ #define MIPS3_SR_NMI 0x00080000 /* MIPS32/64 */ #define MIPS3_SR_DIAG_CH 0x00040000 #define MIPS3_SR_DIAG_CE 0x00020000 #define MIPS3_SR_DIAG_PE 0x00010000 #define MIPS3_SR_KX 0x00000080 #define MIPS3_SR_SX 0x00000040 #define MIPS3_SR_UX 0x00000020 #define MIPS3_SR_KSU_MASK 0x00000018 #define MIPS3_SR_KSU_USER 0x00000010 #define MIPS3_SR_KSU_SUPER 0x00000008 #define MIPS3_SR_KSU_KERNEL 0x00000000 #define MIPS3_SR_ERL 0x00000004 #define MIPS3_SR_EXL 0x00000002 #ifdef MIPS3_5900 #undef MIPS_SR_INT_IE #define MIPS_SR_INT_IE 0x00010001 /* XXX */ #endif #define MIPS_SR_SOFT_RESET MIPS3_SR_SOFT_RESET #define MIPS_SR_DIAG_CH MIPS3_SR_DIAG_CH #define MIPS_SR_DIAG_CE MIPS3_SR_DIAG_CE #define MIPS_SR_DIAG_PE MIPS3_SR_DIAG_PE #define MIPS_SR_KX MIPS3_SR_KX #define MIPS_SR_SX MIPS3_SR_SX #define MIPS_SR_UX MIPS3_SR_UX #define MIPS_SR_KSU_MASK MIPS3_SR_KSU_MASK #define MIPS_SR_KSU_USER MIPS3_SR_KSU_USER #define MIPS_SR_KSU_SUPER MIPS3_SR_KSU_SUPER #define MIPS_SR_KSU_KERNEL MIPS3_SR_KSU_KERNEL #define MIPS_SR_ERL MIPS3_SR_ERL #define MIPS_SR_EXL MIPS3_SR_EXL /* * The interrupt masks. * If a bit in the mask is 1 then the interrupt is enabled (or pending). */ #define MIPS_INT_MASK 0xff00 #define MIPS_INT_MASK_5 0x8000 #define MIPS_INT_MASK_4 0x4000 #define MIPS_INT_MASK_3 0x2000 #define MIPS_INT_MASK_2 0x1000 #define MIPS_INT_MASK_1 0x0800 #define MIPS_INT_MASK_0 0x0400 #define MIPS_HARD_INT_MASK 0xfc00 #define MIPS_SOFT_INT_MASK_1 0x0200 #define MIPS_SOFT_INT_MASK_0 0x0100 /* * mips3 CPUs have on-chip timer at INT_MASK_5. Each platform can * choose to enable this interrupt. */ #if defined(MIPS3_ENABLE_CLOCK_INTR) #define MIPS3_INT_MASK MIPS_INT_MASK #define MIPS3_HARD_INT_MASK MIPS_HARD_INT_MASK #else #define MIPS3_INT_MASK (MIPS_INT_MASK & ~MIPS_INT_MASK_5) #define MIPS3_HARD_INT_MASK (MIPS_HARD_INT_MASK & ~MIPS_INT_MASK_5) #endif /* * The bits in the context register. */ #define MIPS1_CNTXT_PTE_BASE 0xFFE00000 #define MIPS1_CNTXT_BAD_VPN 0x001FFFFC #define MIPS3_CNTXT_PTE_BASE 0xFF800000 #define MIPS3_CNTXT_BAD_VPN2 0x007FFFF0 /* * The bits in the MIPS3 config register. * * bit 0..5: R/W, Bit 6..31: R/O */ /* kseg0 coherency algorithm - see MIPS3_TLB_ATTR values */ #define MIPS3_CONFIG_K0_MASK 0x00000007 /* * R/W Update on Store Conditional * 0: Store Conditional uses coherency algorithm specified by TLB * 1: Store Conditional uses cacheable coherent update on write */ #define MIPS3_CONFIG_CU 0x00000008 #define MIPS3_CONFIG_DB 0x00000010 /* Primary D-cache line size */ #define MIPS3_CONFIG_IB 0x00000020 /* Primary I-cache line size */ #define MIPS3_CONFIG_CACHE_L1_LSIZE(config, bit) \ (((config) & (bit)) ? 32 : 16) #define MIPS3_CONFIG_DC_MASK 0x000001c0 /* Primary D-cache size */ #define MIPS3_CONFIG_DC_SHIFT 6 #define MIPS3_CONFIG_IC_MASK 0x00000e00 /* Primary I-cache size */ #define MIPS3_CONFIG_IC_SHIFT 9 #define MIPS3_CONFIG_C_DEFBASE 0x1000 /* default base 2^12 */ /* Cache size mode indication: available only on Vr41xx CPUs */ #define MIPS3_CONFIG_CS 0x00001000 #define MIPS3_CONFIG_C_4100BASE 0x0400 /* base is 2^10 if CS=1 */ #define MIPS3_CONFIG_CACHE_SIZE(config, mask, base, shift) \ ((base) << (((config) & (mask)) >> (shift))) /* External cache enable: Controls L2 for R5000/Rm527x and L3 for Rm7000 */ #define MIPS3_CONFIG_SE 0x00001000 /* Block ordering: 0: sequential, 1: sub-block */ #define MIPS3_CONFIG_EB 0x00002000 /* ECC mode - 0: ECC mode, 1: parity mode */ #define MIPS3_CONFIG_EM 0x00004000 /* BigEndianMem - 0: kernel and memory are little endian, 1: big endian */ #define MIPS3_CONFIG_BE 0x00008000 /* Dirty Shared coherency state - 0: enabled, 1: disabled */ #define MIPS3_CONFIG_SM 0x00010000 /* Secondary Cache - 0: present, 1: not present */ #define MIPS3_CONFIG_SC 0x00020000 /* System Port width - 0: 64-bit, 1: 32-bit (QED RM523x), 2,3: reserved */ #define MIPS3_CONFIG_EW_MASK 0x000c0000 #define MIPS3_CONFIG_EW_SHIFT 18 /* Secondary Cache port width - 0: 128-bit data path to S-cache, 1: reserved */ #define MIPS3_CONFIG_SW 0x00100000 /* Split Secondary Cache Mode - 0: I/D mixed, 1: I/D separated by SCAddr(17) */ #define MIPS3_CONFIG_SS 0x00200000 /* Secondary Cache line size */ #define MIPS3_CONFIG_SB_MASK 0x00c00000 #define MIPS3_CONFIG_SB_SHIFT 22 #define MIPS3_CONFIG_CACHE_L2_LSIZE(config) \ (0x10 << (((config) & MIPS3_CONFIG_SB_MASK) >> MIPS3_CONFIG_SB_SHIFT)) /* Write back data rate */ #define MIPS3_CONFIG_EP_MASK 0x0f000000 #define MIPS3_CONFIG_EP_SHIFT 24 /* System clock ratio - this value is CPU dependent */ #define MIPS3_CONFIG_EC_MASK 0x70000000 #define MIPS3_CONFIG_EC_SHIFT 28 /* Master-Checker Mode - 1: enabled */ #define MIPS3_CONFIG_CM 0x80000000 /* * The bits in the MIPS4 config register. */ /* kseg0 coherency algorithm - see MIPS3_TLB_ATTR values */ #define MIPS4_CONFIG_K0_MASK MIPS3_CONFIG_K0_MASK #define MIPS4_CONFIG_DN_MASK 0x00000018 /* Device number */ #define MIPS4_CONFIG_CT 0x00000020 /* CohPrcReqTar */ #define MIPS4_CONFIG_PE 0x00000040 /* PreElmReq */ #define MIPS4_CONFIG_PM_MASK 0x00000180 /* PreReqMax */ #define MIPS4_CONFIG_EC_MASK 0x00001e00 /* SysClkDiv */ #define MIPS4_CONFIG_SB 0x00002000 /* SCBlkSize */ #define MIPS4_CONFIG_SK 0x00004000 /* SCColEn */ #define MIPS4_CONFIG_BE 0x00008000 /* MemEnd */ #define MIPS4_CONFIG_SS_MASK 0x00070000 /* SCSize */ #define MIPS4_CONFIG_SC_MASK 0x00380000 /* SCClkDiv */ #define MIPS4_CONFIG_RESERVED 0x03c00000 /* Reserved wired 0 */ #define MIPS4_CONFIG_DC_MASK 0x1c000000 /* Primary D-Cache size */ #define MIPS4_CONFIG_IC_MASK 0xe0000000 /* Primary I-Cache size */ #define MIPS4_CONFIG_DC_SHIFT 26 #define MIPS4_CONFIG_IC_SHIFT 29 #define MIPS4_CONFIG_CACHE_SIZE(config, mask, base, shift) \ ((base) << (((config) & (mask)) >> (shift))) #define MIPS4_CONFIG_CACHE_L2_LSIZE(config) \ (((config) & MIPS4_CONFIG_SB) ? 128 : 64) /* * Location of exception vectors. * * Common vectors: reset and UTLB miss. */ #define MIPS_RESET_EXC_VEC 0xBFC00000 #define MIPS_UTLB_MISS_EXC_VEC 0x80000000 /* * MIPS-1 general exception vector (everything else) */ #define MIPS1_GEN_EXC_VEC 0x80000080 /* * MIPS-III exception vectors */ #define MIPS3_XTLB_MISS_EXC_VEC 0x80000080 #define MIPS3_CACHE_ERR_EXC_VEC 0x80000100 #define MIPS3_GEN_EXC_VEC 0x80000180 /* * TX79 (R5900) exception vectors */ #define MIPS_R5900_COUNTER_EXC_VEC 0x80000080 #define MIPS_R5900_DEBUG_EXC_VEC 0x80000100 /* * MIPS32/MIPS64 (and some MIPS3) dedicated interrupt vector. */ #define MIPS3_INTR_EXC_VEC 0x80000200 /* * Coprocessor 0 registers: * * v--- width for mips I,III,32,64 * (3=32bit, 6=64bit, i=impl dep) * 0 MIPS_COP_0_TLB_INDEX 3333 TLB Index. * 1 MIPS_COP_0_TLB_RANDOM 3333 TLB Random. * 2 MIPS_COP_0_TLB_LOW 3... r3k TLB entry low. * 2 MIPS_COP_0_TLB_LO0 .636 r4k TLB entry low. * 3 MIPS_COP_0_TLB_LO1 .636 r4k TLB entry low, extended. * 4 MIPS_COP_0_TLB_CONTEXT 3636 TLB Context. * 5 MIPS_COP_0_TLB_PG_MASK .333 TLB Page Mask register. * 6 MIPS_COP_0_TLB_WIRED .333 Wired TLB number. * 8 MIPS_COP_0_BAD_VADDR 3636 Bad virtual address. * 9 MIPS_COP_0_COUNT .333 Count register. * 10 MIPS_COP_0_TLB_HI 3636 TLB entry high. * 11 MIPS_COP_0_COMPARE .333 Compare (against Count). * 12 MIPS_COP_0_STATUS 3333 Status register. * 13 MIPS_COP_0_CAUSE 3333 Exception cause register. * 14 MIPS_COP_0_EXC_PC 3636 Exception PC. * 15 MIPS_COP_0_PRID 3333 Processor revision identifier. * 16 MIPS_COP_0_CONFIG 3333 Configuration register. * 16/1 MIPS_COP_0_CONFIG1 ..33 Configuration register 1. * 16/2 MIPS_COP_0_CONFIG2 ..33 Configuration register 2. * 16/3 MIPS_COP_0_CONFIG3 ..33 Configuration register 3. * 17 MIPS_COP_0_LLADDR .336 Load Linked Address. * 18 MIPS_COP_0_WATCH_LO .336 WatchLo register. * 19 MIPS_COP_0_WATCH_HI .333 WatchHi register. * 20 MIPS_COP_0_TLB_XCONTEXT .6.6 TLB XContext register. * 23 MIPS_COP_0_DEBUG .... Debug JTAG register. * 24 MIPS_COP_0_DEPC .... DEPC JTAG register. * 25 MIPS_COP_0_PERFCNT ..36 Performance Counter register. * 26 MIPS_COP_0_ECC .3ii ECC / Error Control register. * 27 MIPS_COP_0_CACHE_ERR .3ii Cache Error register. * 28/0 MIPS_COP_0_TAG_LO .3ii Cache TagLo register (instr). * 28/1 MIPS_COP_0_DATA_LO ..ii Cache DataLo register (instr). * 28/2 MIPS_COP_0_TAG_LO ..ii Cache TagLo register (data). * 28/3 MIPS_COP_0_DATA_LO ..ii Cache DataLo register (data). * 29/0 MIPS_COP_0_TAG_HI .3ii Cache TagHi register (instr). * 29/1 MIPS_COP_0_DATA_HI ..ii Cache DataHi register (instr). * 29/2 MIPS_COP_0_TAG_HI ..ii Cache TagHi register (data). * 29/3 MIPS_COP_0_DATA_HI ..ii Cache DataHi register (data). * 30 MIPS_COP_0_ERROR_PC .636 Error EPC register. * 31 MIPS_COP_0_DESAVE .... DESAVE JTAG register. */ #ifdef _LOCORE #define MIPS_BIT(n) __CONCAT($,n) #else #define MIPS_BIT(n) n #endif #define MIPS_COP_0_TLB_INDEX MIPS_BIT(0) #define MIPS_COP_0_TLB_RANDOM MIPS_BIT(1) /* Name and meaning of TLB bits for $2 differ on r3k and r4k. */ #define MIPS_COP_0_TLB_CONTEXT MIPS_BIT(4) /* $5 and $6 new with MIPS-III */ #define MIPS_COP_0_BAD_VADDR MIPS_BIT(8) #define MIPS_COP_0_TLB_HI MIPS_BIT(10) #define MIPS_COP_0_STATUS MIPS_BIT(12) #define MIPS_COP_0_CAUSE MIPS_BIT(13) #define MIPS_COP_0_EXC_PC MIPS_BIT(14) #define MIPS_COP_0_PRID MIPS_BIT(15) /* MIPS-I */ #define MIPS_COP_0_TLB_LOW MIPS_BIT(2) /* MIPS-III */ #define MIPS_COP_0_TLB_LO0 MIPS_BIT(2) #define MIPS_COP_0_TLB_LO1 MIPS_BIT(3) #define MIPS_COP_0_TLB_PG_MASK MIPS_BIT(5) #define MIPS_COP_0_TLB_WIRED MIPS_BIT(6) #define MIPS_COP_0_COUNT MIPS_BIT(9) #define MIPS_COP_0_COMPARE MIPS_BIT(11) #define MIPS_COP_0_CONFIG MIPS_BIT(16) #define MIPS_COP_0_LLADDR MIPS_BIT(17) #define MIPS_COP_0_WATCH_LO MIPS_BIT(18) #define MIPS_COP_0_WATCH_HI MIPS_BIT(19) #define MIPS_COP_0_TLB_XCONTEXT MIPS_BIT(20) #define MIPS_COP_0_ECC MIPS_BIT(26) #define MIPS_COP_0_CACHE_ERR MIPS_BIT(27) #define MIPS_COP_0_TAG_LO MIPS_BIT(28) #define MIPS_COP_0_TAG_HI MIPS_BIT(29) #define MIPS_COP_0_ERROR_PC MIPS_BIT(30) /* MIPS32/64 */ #define MIPS_COP_0_DEBUG MIPS_BIT(23) #define MIPS_COP_0_DEPC MIPS_BIT(24) #define MIPS_COP_0_PERFCNT MIPS_BIT(25) #define MIPS_COP_0_DATA_LO MIPS_BIT(28) #define MIPS_COP_0_DATA_HI MIPS_BIT(29) #define MIPS_COP_0_DESAVE MIPS_BIT(31) /* * Values for the code field in a break instruction. */ #define MIPS_BREAK_INSTR 0x0000000d #define MIPS_BREAK_VAL_MASK 0x03ff0000 #define MIPS_BREAK_VAL_SHIFT 16 #define MIPS_BREAK_KDB_VAL 512 #define MIPS_BREAK_SSTEP_VAL 513 #define MIPS_BREAK_BRKPT_VAL 514 #define MIPS_BREAK_SOVER_VAL 515 #define MIPS_BREAK_KDB (MIPS_BREAK_INSTR | \ (MIPS_BREAK_KDB_VAL << MIPS_BREAK_VAL_SHIFT)) #define MIPS_BREAK_SSTEP (MIPS_BREAK_INSTR | \ (MIPS_BREAK_SSTEP_VAL << MIPS_BREAK_VAL_SHIFT)) #define MIPS_BREAK_BRKPT (MIPS_BREAK_INSTR | \ (MIPS_BREAK_BRKPT_VAL << MIPS_BREAK_VAL_SHIFT)) #define MIPS_BREAK_SOVER (MIPS_BREAK_INSTR | \ (MIPS_BREAK_SOVER_VAL << MIPS_BREAK_VAL_SHIFT)) /* * Mininum and maximum cache sizes. */ #define MIPS_MIN_CACHE_SIZE (16 * 1024) #define MIPS_MAX_CACHE_SIZE (256 * 1024) #define MIPS3_MAX_PCACHE_SIZE (32 * 1024) /* max. primary cache size */ /* * The floating point version and status registers. */ #define MIPS_FPU_ID $0 #define MIPS_FPU_CSR $31 /* * The floating point coprocessor status register bits. */ #define MIPS_FPU_ROUNDING_BITS 0x00000003 #define MIPS_FPU_ROUND_RN 0x00000000 #define MIPS_FPU_ROUND_RZ 0x00000001 #define MIPS_FPU_ROUND_RP 0x00000002 #define MIPS_FPU_ROUND_RM 0x00000003 #define MIPS_FPU_STICKY_BITS 0x0000007c #define MIPS_FPU_STICKY_INEXACT 0x00000004 #define MIPS_FPU_STICKY_UNDERFLOW 0x00000008 #define MIPS_FPU_STICKY_OVERFLOW 0x00000010 #define MIPS_FPU_STICKY_DIV0 0x00000020 #define MIPS_FPU_STICKY_INVALID 0x00000040 #define MIPS_FPU_ENABLE_BITS 0x00000f80 #define MIPS_FPU_ENABLE_INEXACT 0x00000080 #define MIPS_FPU_ENABLE_UNDERFLOW 0x00000100 #define MIPS_FPU_ENABLE_OVERFLOW 0x00000200 #define MIPS_FPU_ENABLE_DIV0 0x00000400 #define MIPS_FPU_ENABLE_INVALID 0x00000800 #define MIPS_FPU_EXCEPTION_BITS 0x0003f000 #define MIPS_FPU_EXCEPTION_INEXACT 0x00001000 #define MIPS_FPU_EXCEPTION_UNDERFLOW 0x00002000 #define MIPS_FPU_EXCEPTION_OVERFLOW 0x00004000 #define MIPS_FPU_EXCEPTION_DIV0 0x00008000 #define MIPS_FPU_EXCEPTION_INVALID 0x00010000 #define MIPS_FPU_EXCEPTION_UNIMPL 0x00020000 #define MIPS_FPU_COND_BIT 0x00800000 #define MIPS_FPU_FLUSH_BIT 0x01000000 /* r4k, MBZ on r3k */ #define MIPS1_FPC_MBZ_BITS 0xff7c0000 #define MIPS3_FPC_MBZ_BITS 0xfe7c0000 /* * Constants to determine if have a floating point instruction. */ #define MIPS_OPCODE_SHIFT 26 #define MIPS_OPCODE_C1 0x11 /* * The low part of the TLB entry. */ #define MIPS1_TLB_PFN 0xfffff000 #define MIPS1_TLB_NON_CACHEABLE_BIT 0x00000800 #define MIPS1_TLB_DIRTY_BIT 0x00000400 #define MIPS1_TLB_VALID_BIT 0x00000200 #define MIPS1_TLB_GLOBAL_BIT 0x00000100 #define MIPS3_TLB_PFN 0x3fffffc0 #define MIPS3_TLB_ATTR_MASK 0x00000038 #define MIPS3_TLB_ATTR_SHIFT 3 #define MIPS3_TLB_DIRTY_BIT 0x00000004 #define MIPS3_TLB_VALID_BIT 0x00000002 #define MIPS3_TLB_GLOBAL_BIT 0x00000001 #define MIPS1_TLB_PHYS_PAGE_SHIFT 12 #define MIPS3_TLB_PHYS_PAGE_SHIFT 6 #define MIPS1_TLB_PF_NUM MIPS1_TLB_PFN #define MIPS3_TLB_PF_NUM MIPS3_TLB_PFN #define MIPS1_TLB_MOD_BIT MIPS1_TLB_DIRTY_BIT #define MIPS3_TLB_MOD_BIT MIPS3_TLB_DIRTY_BIT /* * MIPS3_TLB_ATTR values - coherency algorithm: * 0: cacheable, noncoherent, write-through, no write allocate * 1: cacheable, noncoherent, write-through, write allocate * 2: uncached * 3: cacheable, noncoherent, write-back (noncoherent) * 4: cacheable, coherent, write-back, exclusive (exclusive) * 5: cacheable, coherent, write-back, exclusive on write (sharable) * 6: cacheable, coherent, write-back, update on write (update) * 7: uncached, accelerated (gather STORE operations) */ #define MIPS3_TLB_ATTR_WT 0 /* IDT */ #define MIPS3_TLB_ATTR_WT_WRITEALLOCATE 1 /* IDT */ #define MIPS3_TLB_ATTR_UNCACHED 2 /* R4000/R4400, IDT */ #define MIPS3_TLB_ATTR_WB_NONCOHERENT 3 /* R4000/R4400, IDT */ #define MIPS3_TLB_ATTR_WB_EXCLUSIVE 4 /* R4000/R4400 */ #define MIPS3_TLB_ATTR_WB_SHARABLE 5 /* R4000/R4400 */ #define MIPS3_TLB_ATTR_WB_UPDATE 6 /* R4000/R4400 */ #define MIPS4_TLB_ATTR_UNCACHED_ACCELERATED 7 /* R10000 */ /* * The high part of the TLB entry. */ #define MIPS1_TLB_VPN 0xfffff000 #define MIPS1_TLB_PID 0x00000fc0 #define MIPS1_TLB_PID_SHIFT 6 #define MIPS3_TLB_VPN2 0xffffe000 #define MIPS3_TLB_ASID 0x000000ff #define MIPS1_TLB_VIRT_PAGE_NUM MIPS1_TLB_VPN #define MIPS3_TLB_VIRT_PAGE_NUM MIPS3_TLB_VPN2 #define MIPS3_TLB_PID MIPS3_TLB_ASID #define MIPS_TLB_VIRT_PAGE_SHIFT 12 /* * r3000: shift count to put the index in the right spot. */ #define MIPS1_TLB_INDEX_SHIFT 8 /* * The first TLB that write random hits. */ #define MIPS1_TLB_FIRST_RAND_ENTRY 8 #define MIPS3_TLB_WIRED_UPAGES 1 /* * The number of process id entries. */ #define MIPS1_TLB_NUM_PIDS 64 #define MIPS3_TLB_NUM_ASIDS 256 /* * Patch codes to hide CPU design differences between MIPS1 and MIPS3. */ /* XXX simonb: this is before MIPS3_PLUS is defined (and is ugly!) */ #if !(defined(MIPS3) || defined(MIPS4) || defined(MIPS32) || defined(MIPS64)) \ && defined(MIPS1) /* XXX simonb must be neater! */ #define MIPS_TLB_PID_SHIFT MIPS1_TLB_PID_SHIFT #define MIPS_TLB_NUM_PIDS MIPS1_TLB_NUM_PIDS #endif #if (defined(MIPS3) || defined(MIPS4) || defined(MIPS32) || defined(MIPS64)) \ && !defined(MIPS1) /* XXX simonb must be neater! */ #define MIPS_TLB_PID_SHIFT 0 #define MIPS_TLB_NUM_PIDS MIPS3_TLB_NUM_ASIDS #endif #if !defined(MIPS_TLB_PID_SHIFT) #define MIPS_TLB_PID_SHIFT \ ((MIPS_HAS_R4K_MMU) ? 0 : MIPS1_TLB_PID_SHIFT) #define MIPS_TLB_NUM_PIDS \ ((MIPS_HAS_R4K_MMU) ? MIPS3_TLB_NUM_ASIDS : MIPS1_TLB_NUM_PIDS) #endif /* * CPU processor revision IDs for company ID == 0 (non mips32/64 chips) */ #define MIPS_R2000 0x01 /* MIPS R2000 ISA I */ #define MIPS_R3000 0x02 /* MIPS R3000 ISA I */ #define MIPS_R6000 0x03 /* MIPS R6000 ISA II */ #define MIPS_R4000 0x04 /* MIPS R4000/R4400 ISA III */ #define MIPS_R3LSI 0x05 /* LSI Logic R3000 derivative ISA I */ #define MIPS_R6000A 0x06 /* MIPS R6000A ISA II */ #define MIPS_R3IDT 0x07 /* IDT R3041 or RC36100 ISA I */ #define MIPS_R10000 0x09 /* MIPS R10000 ISA IV */ #define MIPS_R4200 0x0a /* NEC VR4200 ISA III */ #define MIPS_R4300 0x0b /* NEC VR4300 ISA III */ #define MIPS_R4100 0x0c /* NEC VR4100 ISA III */ #define MIPS_R12000 0x0e /* MIPS R12000 ISA IV */ #define MIPS_R14000 0x0f /* MIPS R14000 ISA IV */ #define MIPS_R8000 0x10 /* MIPS R8000 Blackbird/TFP ISA IV */ #define MIPS_RC32300 0x18 /* IDT RC32334,332,355 ISA 32 */ #define MIPS_R4600 0x20 /* QED R4600 Orion ISA III */ #define MIPS_R4700 0x21 /* QED R4700 Orion ISA III */ #define MIPS_R3SONY 0x21 /* Sony R3000 based ISA I */ #define MIPS_R4650 0x22 /* QED R4650 ISA III */ #define MIPS_TX3900 0x22 /* Toshiba TX39 family ISA I */ #define MIPS_R5000 0x23 /* MIPS R5000 ISA IV */ #define MIPS_R3NKK 0x23 /* NKK R3000 based ISA I */ #define MIPS_RC32364 0x26 /* IDT RC32364 ISA 32 */ #define MIPS_RM7000 0x27 /* QED RM7000 ISA IV */ #define MIPS_RM5200 0x28 /* QED RM5200s ISA IV */ #define MIPS_TX4900 0x2d /* Toshiba TX49 family ISA III */ #define MIPS_R5900 0x2e /* Toshiba R5900 (EECore) ISA --- */ #define MIPS_RC64470 0x30 /* IDT RC64474/RC64475 ISA III */ #define MIPS_TX7900 0x38 /* Toshiba TX79 ISA III+*/ #define MIPS_R5400 0x54 /* NEC VR5400 ISA IV */ #define MIPS_R5500 0x55 /* NEC VR5500 ISA IV */ /* * CPU revision IDs for some prehistoric processors. */ /* For MIPS_R3000 */ #define MIPS_REV_R3000 0x20 #define MIPS_REV_R3000A 0x30 /* For MIPS_TX3900 */ #define MIPS_REV_TX3912 0x10 #define MIPS_REV_TX3922 0x30 #define MIPS_REV_TX3927 0x40 /* For MIPS_R4000 */ #define MIPS_REV_R4000_A 0x00 #define MIPS_REV_R4000_B 0x22 #define MIPS_REV_R4000_C 0x30 #define MIPS_REV_R4400_A 0x40 #define MIPS_REV_R4400_B 0x50 #define MIPS_REV_R4400_C 0x60 /* For MIPS_TX4900 */ #define MIPS_REV_TX4927 0x22 /* * CPU processor revision IDs for company ID == 1 (MIPS) */ #define MIPS_4Kc 0x80 /* MIPS 4Kc ISA 32 */ #define MIPS_5Kc 0x81 /* MIPS 5Kc ISA 64 */ #define MIPS_20Kc 0x82 /* MIPS 20Kc ISA 64 */ #define MIPS_4Kmp 0x83 /* MIPS 4Km/4Kp ISA 32 */ #define MIPS_4KEc 0x84 /* MIPS 4KEc ISA 32 */ #define MIPS_4KEmp 0x85 /* MIPS 4KEm/4KEp ISA 32 */ #define MIPS_4KSc 0x86 /* MIPS 4KSc ISA 32 */ #define MIPS_M4K 0x87 /* MIPS M4K ISA 32 Rel 2 */ #define MIPS_25Kf 0x88 /* MIPS 25Kf ISA 64 */ #define MIPS_5KE 0x89 /* MIPS 5KE ISA 64 Rel 2 */ #define MIPS_4KEc_R2 0x90 /* MIPS 4KEc_R2 ISA 32 Rel 2 */ #define MIPS_4KEmp_R2 0x91 /* MIPS 4KEm/4KEp_R2 ISA 32 Rel 2 */ #define MIPS_4KSd 0x92 /* MIPS 4KSd ISA 32 Rel 2 */ #define MIPS_24K 0x93 /* MIPS 24K ? */ #define MIPS_34K 0x95 /* MIPS 34K ? */ #define MIPS_24KE 0x96 /* MIPS 24KE ? */ #define MIPS_74K 0x97 /* MIPS 74K ? */ /* * Alchemy (company ID 3) use the processor ID field to donote the CPU core * revision and the company options field do donate the SOC chip type. */ /* CPU processor revision IDs */ #define MIPS_AU_REV1 0x01 /* Alchemy Au1000 (Rev 1) ISA 32 */ #define MIPS_AU_REV2 0x02 /* Alchemy Au1000 (Rev 2) ISA 32 */ /* CPU company options IDs */ #define MIPS_AU1000 0x00 #define MIPS_AU1500 0x01 #define MIPS_AU1100 0x02 #define MIPS_AU1550 0x03 /* * CPU processor revision IDs for company ID == 4 (SiByte) */ #define MIPS_SB1 0x01 /* SiByte SB1 ISA 64 */ /* * CPU processor revision IDs for company ID == 5 (SandCraft) */ #define MIPS_SR7100 0x04 /* SandCraft SR7100 ISA 64 */ /* * FPU processor revision ID */ #define MIPS_SOFT 0x00 /* Software emulation ISA I */ #define MIPS_R2360 0x01 /* MIPS R2360 FPC ISA I */ #define MIPS_R2010 0x02 /* MIPS R2010 FPC ISA I */ #define MIPS_R3010 0x03 /* MIPS R3010 FPC ISA I */ #define MIPS_R6010 0x04 /* MIPS R6010 FPC ISA II */ #define MIPS_R4010 0x05 /* MIPS R4010 FPC ISA II */ #define MIPS_R31LSI 0x06 /* LSI Logic derivate ISA I */ #define MIPS_R3TOSH 0x22 /* Toshiba R3000 based FPU ISA I */ #ifdef ENABLE_MIPS_TX3900 #include #endif #ifdef MIPS3_5900 #include #endif #ifdef MIPS64_SB1 #include #endif #endif /* _MIPS_CPUREGS_H_ */ gxemul-0.6.1/src/include/thirdparty/sh4_scireg.h000644 001750 001750 00000006631 13402411502 022042 0ustar00debugdebug000000 000000 /* $OpenBSD: scireg.h,v 1.1.1.1 2006/10/06 21:02:55 miod Exp $ */ /* $NetBSD: scireg.h,v 1.8 2003/07/01 11:49:37 uwe Exp $ */ #ifndef SH4_SCIREG_H #define SH4_SCIREG_H /* GXemul base address for SCI-connected devices: */ #define SCI_DEVICE_BASE 0x110000000ULL /*- * Copyright (C) 1999 SAITOH Masanobu. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Serial Communication Interface (SCI) */ #if 0 !defined(SH4) /* SH3 definitions */ #define SHREG_SCSMR (*(volatile unsigned char *) 0xFFFFFE80) #define SHREG_SCBRR (*(volatile unsigned char *) 0xFFFFFE82) #define SHREG_SCSCR (*(volatile unsigned char *) 0xFFFFFE84) #define SHREG_SCTDR (*(volatile unsigned char *) 0xFFFFFE86) #define SHREG_SCSSR (*(volatile unsigned char *) 0xFFFFFE88) #define SHREG_SCRDR (*(volatile unsigned char *) 0xFFFFFE8A) #define SHREG_SCSPDR (*(volatile unsigned char *) 0xf4000136) #else /* SH4 definitions */ #define SHREG_SCSMR /* (*(volatile unsigned char *) */ 0xffe00000 #define SHREG_SCBRR /* (*(volatile unsigned char *) */ 0xffe00004 #define SHREG_SCSCR /* (*(volatile unsigned char *) */ 0xffe00008 #define SHREG_SCTDR /* (*(volatile unsigned char *) */ 0xffe0000c #define SHREG_SCSSR /* (*(volatile unsigned char *) */ 0xffe00010 #define SHREG_SCRDR /* (*(volatile unsigned char *) */ 0xffe00014 #define SHREG_SCSPTR /* (*(volatile unsigned char *) */ 0xffe0001c #endif #define SCSCR_TIE 0x80 /* Transmit Interrupt Enable */ #define SCSCR_RIE 0x40 /* Receive Interrupt Enable */ #define SCSCR_TE 0x20 /* Transmit Enable */ #define SCSCR_RE 0x10 /* Receive Enable */ #define SCSCR_MPIE 0x08 /* Multi Processor Interrupt Enable */ #define SCSCR_TEIE 0x04 /* Transmit End Interrupt Enable */ #define SCSCR_CKE1 0x02 /* ClocK Enable 1 */ #define SCSCR_CKE0 0x01 /* ClocK Enable 0 */ #define SCSSR_TDRE 0x80 #define SCSSR_RDRF 0x40 #define SCSSR_ORER 0x20 #define SCSSR_FER 0x10 #define SCSSR_PER 0x08 #define SCSPTR_SPB1IO 0x08 #define SCSPTR_SPB1DT 0x04 #define SCSPTR_SPB0IO 0x02 #define SCSPTR_SPB0DT 0x01 #if defined(SH3) #define SCSPDR_SCP0DT 0x01 #endif #endif /* SH4_SCIREG_H */ gxemul-0.6.1/src/include/thirdparty/bireg.h000644 001750 001750 00000026023 13402411502 021075 0ustar00debugdebug000000 000000 /* gxemul: $Id: bireg.h,v 1.2 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: bireg.h,v 1.7 2000/07/06 17:47:02 ragge Exp $ */ #ifndef BIREG_H #define BIREG_H /* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)bireg.h 7.3 (Berkeley) 6/28/90 */ /* * VAXBI node definitions. */ /* * BI node addresses */ #define BI_NODESIZE 0x2000 /* Size of one BI node */ #define BI_NODE(node) (BI_NODESIZE * (node)) #define BI_BASE(bi,nod) ((0x20000000 + (bi) * 0x2000000) + BI_NODE(nod)) #define MAXNBI 16 /* Spec says there can be 16 anyway */ #define NNODEBI 16 /* 16 nodes per BI */ #define BI_PROBE 0x80000 /* CPU on 8200, NBIA on 8800 */ /* * BI nodes all start with BI interface registers (those on the BIIC chip). * These are followed with interface-specific registers. * * NB: This structure does NOT include the four GPRs (not anymore!) * * 990712: The structs not used anymore due to conversion to bus.h. */ #ifdef notdef struct biiregs { u_short bi_dtype; /* device type */ u_short bi_revs; /* revisions */ u_long bi_csr; /* control and status register */ u_long bi_ber; /* bus error register */ u_long bi_eintrcsr; /* error interrupt control register */ u_long bi_intrdes; /* interrupt destination register */ /* the rest are not required for all nodes */ u_long bi_ipintrmsk; /* IP interrupt mask register */ u_long bi_fipsdes; /* Force-Bit IPINTR/STOP destination reg */ u_long bi_ipintrsrc; /* IPINTR source register */ u_long bi_sadr; /* starting address register */ u_long bi_eadr; /* ending address register */ u_long bi_bcicsr; /* BCI control and status register */ u_long bi_wstat; /* write status register */ u_long bi_fipscmd; /* Force-Bit IPINTR/STOP command reg */ u_long bi_xxx1[3]; /* unused */ u_long bi_uintrcsr; /* user interface interrupt control reg */ u_long bi_xxx2[43]; /* unused */ /* although these are on the BIIC, their interpretation varies */ /* u_long bi_gpr[4]; */ /* general purpose registers */ }; /* * A generic BI node. */ struct bi_node { struct biiregs biic; /* interface */ u_long bi_xxx[1988]; /* pad to 8K */ }; /* * A cpu node. */ struct bi_cpu { struct biiregs biic; /* interface chip */ u_long bi_gpr[4]; /* gprs (unused) */ u_long bi_sosr; /* slave only status register */ u_long bi_xxx[63]; /* pad */ u_long bi_rxcd; /* receive console data register */ }; #endif #define BIREG_DTYPE 0x00 #define BIREG_VAXBICSR 0x04 #define BIREG_BER 0x08 #define BIREG_EINTRCSR 0x0c #define BIREG_INTRDES 0x10 #define BIREG_IPINTRMSK 0x14 #define BIREG_FIPSDES 0x18 #define BIREG_IPINTRSRC 0x1c #define BIREG_SADR 0x20 #define BIREG_EADR 0x24 #define BIREG_BCICSR 0x28 #define BIREG_WSTAT 0x2c #define BIREG_FIPSCMD 0x30 #define BIREG_UINTRCSR 0x40 /* device types */ #define BIDT_MS820 0x0001 /* MS820 memory board */ #define BIDT_DRB32 0x0101 /* DRB32 (MFA) Supercomputer gateway */ #define BIDT_DWBUA 0x0102 /* DWBUA Unibus adapter */ #define BIDT_KLESI 0x0103 /* KLESI-B (DWBLA) adapter */ #define BIDT_HSB70 0x4104 /* HSB70 */ #define BIDT_KA820 0x0105 /* KA820 cpu */ #define BIDT_DB88 0x0106 /* DB88 (NBI) adapter */ #define BIDT_DWMBA 0x2107 /* XMI-BI (XBI) adapter */ #define BIDT_DWMBB 0x0107 /* XMI-BI (XBI) adapter */ #define BIDT_CIBCA 0x0108 /* Computer Interconnect adapter */ #define BIDT_DMB32 0x0109 /* DMB32 (COMB) adapter */ #define BIDT_BAA 0x010a /* BAA */ #define BIDT_CIBCI 0x010b /* Computer Interconnect adapter (old) */ #define BIDT_DEBNT 0x410b /* (AIE_TK70) Ethernet+TK50/TBK70 */ #define BIDT_KA800 0x010c /* KA800 (ACP) slave processor */ #define BIDT_KFBTA 0x410d /* RD/RX disk controller */ #define BIDT_KDB50 0x010e /* KDB50 (BDA) disk controller */ #define BIDT_DEBNK 0x410e /* (AIE_TK) BI Ethernet (Lance) + TK50 */ #define BIDT_DEBNA 0x410f /* (AIE) BI Ethernet (Lance) adapter */ #define BIDT_DEBNI 0x0118 /* (XNA) BI Ethernet adapter */ /* bits in bi_csr */ #define BICSR_IREV(x) ((u_char)((x) >> 24)) /* VAXBI interface rev */ #define BICSR_TYPE(x) ((u_char)((x) >> 16)) /* BIIC type */ #define BICSR_HES 0x8000 /* hard error summary */ #define BICSR_SES 0x4000 /* soft error summary */ #define BICSR_INIT 0x2000 /* initialise node */ #define BICSR_BROKE 0x1000 /* broke */ #define BICSR_STS 0x0800 /* self test status */ #define BICSR_NRST 0x0400 /* node reset */ #define BICSR_UWP 0x0100 /* unlock write pending */ #define BICSR_HEIE 0x0080 /* hard error interrupt enable */ #define BICSR_SEIE 0x0040 /* soft error interrupt enable */ #define BICSR_ARB_MASK 0x0030 /* mask to get arbitration codes */ #define BICSR_ARB_NONE 0x0030 /* no arbitration */ #define BICSR_ARB_LOG 0x0020 /* low priority */ #define BICSR_ARB_HIGH 0x0010 /* high priority */ #define BICSR_ARB_RR 0x0000 /* round robin */ #define BICSR_NODEMASK 0x000f /* node ID */ #define BICSR_BITS \ "\20\20HES\17SES\16INIT\15BROKE\14STS\13NRST\11UWP\10HEIE\7SEIE" /* bits in bi_ber */ #define BIBER_MBZ 0x8000fff0 #define BIBER_NMR 0x40000000 /* no ack to multi-responder command */ #define BIBER_MTCE 0x20000000 /* master transmit check error */ #define BIBER_CTE 0x10000000 /* control transmit error */ #define BIBER_MPE 0x08000000 /* master parity error */ #define BIBER_ISE 0x04000000 /* interlock sequence error */ #define BIBER_TDF 0x02000000 /* transmitter during fault */ #define BIBER_IVE 0x01000000 /* ident vector error */ #define BIBER_CPE 0x00800000 /* command parity error */ #define BIBER_SPE 0x00400000 /* slave parity error */ #define BIBER_RDS 0x00200000 /* read data substitute */ #define BIBER_RTO 0x00100000 /* retry timeout */ #define BIBER_STO 0x00080000 /* stall timeout */ #define BIBER_BTO 0x00040000 /* bus timeout */ #define BIBER_NEX 0x00020000 /* nonexistent address */ #define BIBER_ICE 0x00010000 /* illegal confirmation error */ #define BIBER_UPEN 0x00000008 /* user parity enable */ #define BIBER_IPE 0x00000004 /* ID parity error */ #define BIBER_CRD 0x00000002 /* corrected read data */ #define BIBER_NPE 0x00000001 /* null bus parity error */ #define BIBER_HARD 0x4fff0000 #define BIBER_BITS \ "\20\37NMR\36MTCE\35CTE\34MPE\33ISE\32TDF\31IVE\30CPE\ \27SPE\26RDS\25RTO\24STO\23BTO\22NEX\21ICE\4UPEN\3IPE\2CRD\1NPE" /* bits in bi_eintrcsr */ #define BIEIC_INTRAB 0x01000000 /* interrupt abort */ #define BIEIC_INTRC 0x00800000 /* interrupt complete */ #define BIEIC_INTRSENT 0x00200000 /* interrupt command sent */ #define BIEIC_INTRFORCE 0x00100000 /* interrupt force */ #define BIEIC_LEVELMASK 0x000f0000 /* mask for interrupt levels */ #define BIEIC_IPL17 0x00080000 /* ipl 0x17 */ #define BIEIC_IPL16 0x00040000 /* ipl 0x16 */ #define BIEIC_IPL15 0x00020000 /* ipl 0x15 */ #define BIEIC_IPL14 0x00010000 /* ipl 0x14 */ #define BIEIC_VECMASK 0x00003ffc /* vector mask for error intr */ /* bits in bi_intrdes */ #define BIDEST_MASK 0x0000ffff /* one bit per node to be intr'ed */ /* bits in bi_ipintrmsk */ #define BIIPINTR_MASK 0xffff0000 /* one per node to allow to ipintr */ /* bits in bi_fipsdes */ #define BIFIPSD_MASK 0x0000ffff /* bits in bi_ipintrsrc */ #define BIIPSRC_MASK 0xffff0000 /* sadr and eadr are simple addresses */ /* bits in bi_bcicsr */ #define BCI_BURSTEN 0x00020000 /* burst mode enable */ #define BCI_IPSTOP_FRC 0x00010000 /* ipintr/stop force */ #define BCI_MCASTEN 0x00008000 /* multicast space enable */ #define BCI_BCASTEN 0x00004000 /* broadcast enable */ #define BCI_STOPEN 0x00002000 /* stop enable */ #define BCI_RSRVDEN 0x00001000 /* reserved enable */ #define BCI_IDENTEN 0x00000800 /* ident enable */ #define BCI_INVALEN 0x00000400 /* inval enable */ #define BCI_WINVEN 0x00000200 /* write invalidate enable */ #define BCI_UINTEN 0x00000100 /* user interface csr space enable */ #define BCI_BIICEN 0x00000080 /* BIIC csr space enable */ #define BCI_INTEN 0x00000040 /* interrupt enable */ #define BCI_IPINTEN 0x00000020 /* ipintr enable */ #define BCI_PIPEEN 0x00000010 /* pipeline NXT enable */ #define BCI_RTOEVEN 0x00000008 /* read timeout EV enable */ #define BCI_BITS \ "\20\22BURSTEN\21IPSTOP_FRC\20MCASTEN\ \17BCASTEN\16STOPEN\15RSRVDEN\14IDENTEN\13INVALEN\12WINVEN\11UINTEN\ \10BIICEN\7INTEN\6IPINTEN\5PIPEEN\4RTOEVEN" /* bits in bi_wstat */ #define BIW_GPR3 0x80000000 /* gpr 3 was written */ #define BIW_GPR2 0x40000000 /* gpr 2 was written */ #define BIW_GPR1 0x20000000 /* gpr 1 was written */ #define BIW_GPR0 0x10000000 /* gpr 0 was written */ /* bits in force-bit ipintr/stop command register */ #define BIFIPSC_CMDMASK 0x0000f000 /* command */ #define BIFIPSC_MIDEN 0x00000800 /* master ID enable */ /* bits in bi_uintcsr */ #define BIUI_INTAB 0xf0000000 /* interrupt abort level */ #define BIUI_INTC 0x0f000000 /* interrupt complete bits */ #define BIUI_SENT 0x00f00000 /* interrupt sent bits */ #define BIUI_FORCE 0x000f0000 /* force interrupt level */ #define BIUI_EVECEN 0x00008000 /* external vector enable */ #define BIUI_VEC 0x00003ffc /* interrupt vector */ /* tell if a bi device is a slave (hence has SOSR) */ #define BIDT_ISSLAVE(x) (((x) & 0x7f00) == 0) /* bits in bi_sosr */ #define BISOSR_MEMSIZE 0x1ffc0000 /* memory size */ #define BISOSR_BROKE 0x00001000 /* broke */ /* bits in bi_rxcd */ #define BIRXCD_BUSY2 0x80000000 /* busy 2 */ #define BIRXCD_NODE2 0x0f000000 /* node id 2 */ #define BIRXCD_CHAR2 0x00ff0000 /* character 2 */ #define BIRXCD_BUSY1 0x00008000 /* busy 1 */ #define BIRXCD_NODE1 0x00000f00 /* node id 1 */ #define BIRXCD_CHAR1 0x000000ff /* character 1 */ #endif gxemul-0.6.1/src/include/thirdparty/if_mecreg.h000644 001750 001750 00000014044 13402411502 021725 0ustar00debugdebug000000 000000 /* gxemul: $Id: if_mecreg.h,v 1.2 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: if_mecreg.h,v 1.4 2008/08/07 15:05:02 tsutsui Exp $ */ #ifndef IF_MECREG_H #define IF_MECREG_H /* * Copyright (c) 2001 Christopher Sekiya * Copyright (c) 2000 Soren S. Jorvang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the * NetBSD Project. See http://www.NetBSD.org/ for * information about NetBSD. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * MACE MAC110 ethernet register definitions */ #define MEC_MAC_CONTROL 0x00 #define MEC_MAC_CORE_RESET 0x0000000000000001 /* reset signal */ #define MEC_MAC_FULL_DUPLEX 0x0000000000000002 /* 1 to enable */ #define MEC_MAC_INT_LOOPBACK 0x0000000000000004 /* 0 = normal op */ #define MEC_MAC_SPEED_SELECT 0x0000000000000008 /* 0/1 10/100 */ #define MEC_MAC_MII_SELECT 0x0000000000000010 /* MII/SIA */ #define MEC_MAC_FILTER_MASK 0x0000000000000060 #define MEC_MAC_FILTER_STATION 0x0000000000000000 #define MEC_MAC_FILTER_MATCHMULTI 0x0000000000000020 #define MEC_MAC_FILTER_ALLMULTI 0x0000000000000040 #define MEC_MAC_FILTER_PROMISC 0x0000000000000060 #define MEC_MAC_LINK_FAILURE 0x0000000000000080 #define MEC_MAC_IPGT 0x0000000000007f00 /* interpacket gap */ #define MEC_MAC_IPGT_SHIFT 8 #define MEC_MAC_IPGR1 0x00000000003f8000 #define MEC_MAC_IPGR1_SHIFT 15 #define MEC_MAC_IPGR2 0x000000001fc00000 #define MEC_MAC_IPGR2_SHIFT 22 #define MEC_MAC_REVISION 0x00000000e0000000 #define MEC_MAC_REVISION_SHIFT 29 #define MEC_MAC_IPG_DEFAULT \ (21 << MEC_MAC_IPGT_SHIFT) | \ (17 << MEC_MAC_IPGR1_SHIFT) | \ (11 << MEC_MAC_IPGR2_SHIFT) #define MEC_INT_STATUS 0x08 #define MEC_INT_STATUS_MASK 0x00000000000000ff #define MEC_INT_TX_EMPTY 0x0000000000000001 #define MEC_INT_TX_PACKET_SENT 0x0000000000000002 #define MEC_INT_TX_LINK_FAIL 0x0000000000000004 #define MEC_INT_TX_MEM_ERROR 0x0000000000000008 #define MEC_INT_TX_ABORT 0x0000000000000010 #define MEC_INT_RX_THRESHOLD 0x0000000000000020 #define MEC_INT_RX_FIFO_UNDERFLOW 0x0000000000000040 #define MEC_INT_RX_DMA_UNDERFLOW 0x0000000000000080 #define MEC_INT_RX_MCL_FIFO_ALIAS 0x0000000000001f00 #define MEC_INT_RX_MCL_FIFO_SHIFT 8 #define MEC_INT_TX_RING_BUFFER_ALIAS 0x0000000001ff0000 #define MEC_INT_TX_RING_BUFFER_SHIFT 16 #define MEC_INT_RX_SEQUENCE_NUMBER 0x000000003e000000 #define MEC_INT_MCAST_HASH_OUTPUT 0x0000000040000000 #define MEC_DMA_CONTROL 0x10 #define MEC_DMA_TX_INT_ENABLE 0x0000000000000001 #define MEC_DMA_TX_DMA_ENABLE 0x0000000000000002 #define MEC_DMA_TX_RING_SIZE_MASK 0x000000000000000c #define MEC_DMA_RX_INT_THRESHOLD 0x00000000000001f0 #define MEC_DMA_RX_INT_THRESH_SHIFT 4 #define MEC_DMA_RX_INT_ENABLE 0x0000000000000200 #define MEC_DMA_RX_RUNT 0x0000000000000400 #define MEC_DMA_RX_PACKET_GATHER 0x0000000000000800 #define MEC_DMA_RX_DMA_OFFSET 0x0000000000007000 #define MEC_DMA_RX_DMA_OFFSET_SHIFT 12 #define MEC_DMA_RX_DMA_ENABLE 0x0000000000008000 #define MEC_TIMER 0x18 #define MEC_TX_ALIAS 0x20 #define MEC_TX_ALIAS_INT_ENABLE 0x0000000000000001 #define MEC_RX_ALIAS 0x28 #define MEC_RX_ALIAS_INT_ENABLE 0x0000000000000200 #define MEC_RX_ALIAS_INT_THRESHOLD 0x00000000000001f0 #define MEC_TX_RING_PTR 0x30 #define MEC_TX_RING_WRITE_PTR 0x00000000000001ff #define MEC_TX_RING_READ_PTR 0x0000000001ff0000 #define MEC_TX_RING_PTR_ALIAS 0x38 #define MEC_RX_FIFO 0x40 #define MEC_RX_FIFO_ELEMENT_COUNT 0x000000000000001f #define MEC_RX_FIFO_READ_PTR 0x0000000000000f00 #define MEC_RX_FIFO_GEN_NUMBER 0x0000000000001000 #define MEC_RX_FIFO_WRITE_PTR 0x00000000000f0000 #define MEC_RX_FIFO_GEN_NUMBER_2 0x0000000000100000 #define MEC_RX_FIFO_ALIAS1 0x48 #define MEC_RX_FIFO_ALIAS2 0x50 #define MEC_TX_VECTOR 0x58 #define MEC_IRQ_VECTOR 0x58 #define MEC_PHY_DATA 0x60 #define MEC_PHY_DATA_BUSY 0x00010000 #define MEC_PHY_DATA_VALUE 0x0000ffff #define MEC_PHY_ADDRESS 0x68 #define MEC_PHY_ADDR_REGISTER 0x0000001f #define MEC_PHY_ADDR_DEVICE 0x000003e0 #define MEC_PHY_ADDR_DEVSHIFT 5 #define MEC_PHY_READ_INITIATE 0x70 #define MEC_PHY_BACKOFF 0x78 #define MEC_STATION 0xa0 #define MEC_STATION_ALT 0xa8 #define MEC_STATION_MASK 0x0000ffffffffffffULL #define MEC_MULTICAST 0xb0 #define MEC_TX_RING_BASE 0xb8 #define MEC_TX_PKT1_CMD_1 0xc0 #define MEC_TX_PKT1_BUFFER_1 0xc8 #define MEC_TX_PKT1_BUFFER_2 0xd0 #define MEC_TX_PKT1_BUFFER_3 0xd8 #define MEC_TX_PKT2_CMD_1 0xe0 #define MEC_TX_PKT2_BUFFER_1 0xe8 #define MEC_TX_PKT2_BUFFER_2 0xf0 #define MEC_TX_PKT2_BUFFER_3 0xf8 #define MEC_MCL_RX_FIFO 0x100 #endif /* IF_MECREG_H */ gxemul-0.6.1/src/include/thirdparty/static_assert.h000644 001750 001750 00000003452 13402411502 022656 0ustar00debugdebug000000 000000 /* * Modified for GXemul: * * 1. Better Doxygen comment for struct __nvwa_compile_time_error. */ // -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- // vim:tabstop=4:shiftwidth=4:expandtab: /* * Copyright (C) 2004-2005 Wu Yongwei * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any * damages arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute * it freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must * not claim that you wrote the original software. If you use this * software in a product, an acknowledgment in the product * documentation would be appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must * not be misrepresented as being the original software. * 3. This notice may not be removed or altered from any source * distribution. * * This file is part of Stones of Nvwa: * http://sourceforge.net/projects/nvwa * */ /** * @file static_assert.h * * Template class to check validity duing compile time (adapted from Loki). * * @version 1.2, 2005/11/22 * @author Wu Yongwei * */ #ifndef STATIC_ASSERT template struct __nvwa_compile_time_error; /** * \brief Part of Wu Yongwei's new/delete debug * memory leak detector. */ template <> struct __nvwa_compile_time_error {}; #define STATIC_ASSERT(_Expr, _Msg) \ { \ __nvwa_compile_time_error<((_Expr) != 0)> ERROR_##_Msg; \ (void)ERROR_##_Msg; \ } #endif // STATIC_ASSERT gxemul-0.6.1/src/include/thirdparty/ns16550reg.h000644 001750 001750 00000005121 13402411502 021520 0ustar00debugdebug000000 000000 #ifndef NS16550REG_H #define NS16550REG_H /* $NetBSD: ns16550reg.h,v 1.5 2000/05/16 00:18:44 thorpej Exp $ */ /*- * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ns16550.h 7.1 (Berkeley) 5/9/91 */ /* * NS16550 UART registers */ #define com_data 0 /* data register (R/W) */ #define com_dlbl 0 /* divisor latch low (W) */ #define com_dlbh 1 /* divisor latch high (W) */ #define com_ier 1 /* interrupt enable (W) */ #define com_iir 2 /* interrupt identification (R) */ #define com_fifo 2 /* FIFO control (W) */ #define com_lctl 3 /* line control register (R/W) */ #define com_cfcr 3 /* line control register (R/W) */ #define com_mcr 4 /* modem control register (R/W) */ #define com_lsr 5 /* line status register (R/W) */ #define com_msr 6 /* modem status register (R/W) */ #define com_scratch 7 /* scratch register (R/W) */ #endif /* NS16550REG_H */ gxemul-0.6.1/src/include/thirdparty/pica.h000644 001750 001750 00000013407 13402411502 020723 0ustar00debugdebug000000 000000 /* gxemul: $Id: pica.h,v 1.3 2005-03-05 12:34:03 debug Exp $ */ /* $NetBSD: pica.h,v 1.2 2001/06/13 15:11:38 soda Exp $ */ /* $OpenBSD: pica.h,v 1.4 1996/09/14 15:58:28 pefo Exp $ */ #ifndef _PICA_H_ #define _PICA_H_ 1 #define RELATIVE /* * Copyright (c) 1994, 1995, 1996 Per Fogelstrom * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed under OpenBSD by * Per Fogelstrom. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * PICA's Physical address space */ #define PICA_PHYS_MIN 0x00000000 /* 256 Meg */ #define PICA_PHYS_MAX 0x0fffffff /* * Memory map */ #define PICA_PHYS_MEMORY_START 0x00000000 #define PICA_PHYS_MEMORY_END 0x0fffffff /* 256 Meg in 8 slots */ #define PICA_MEMORY_SIZE_REG 0xe00fffe0 /* Memory size register */ #define PICA_CONFIG_REG 0xe00ffff0 /* Hardware config reg */ /* * I/O map */ #define R4030_P_LOCAL_IO_BASE 0x80000000 /* I/O Base address */ #define R4030_V_LOCAL_IO_BASE 0xe0000000 #define R4030_S_LOCAL_IO_BASE 0x00040000 /* Size */ #ifndef RELATIVE #define R4030 R4030_V_LOCAL_IO_BASE #else #define R4030 0 #endif #define R4030_SYS_CONFIG (R4030+0x0000) /* Global config register */ #define R4030_SYS_TL_BASE (R4030+0x0018) /* DMA transl. table base */ #define R4030_SYS_TL_LIMIT (R4030+0x0020) /* DMA transl. table limit */ #define R4030_SYS_TL_IVALID (R4030+0x0028) /* DMA transl. cache inval */ #define R4030_SYS_DMA0_REGS (R4030+0x0100) /* DMA ch0 base address */ #define R4030_SYS_DMA1_REGS (R4030+0x0120) /* DMA ch0 base address */ #define R4030_SYS_DMA2_REGS (R4030+0x0140) /* DMA ch0 base address */ #define R4030_SYS_DMA3_REGS (R4030+0x0160) /* DMA ch0 base address */ #define R4030_SYS_DMA_INT_SRC (R4030+0x0200) /* DMA int source status reg */ #define R4030_SYS_NVRAM_PROT (R4030+0x0220) /* NV ram protect register */ #define R4030_SYS_IT_VALUE (R4030+0x0228) /* Interval timer reload */ #define R4030_SYS_IT_STAT (R4030+0x0230) /* Interval timer count */ #define R4030_SYS_ISA_VECTOR (R4030+0x0238) /* ISA Interrupt vector */ #define R4030_SYS_EXT_IMASK (R4030+0x00e8) /* External int enable mask */ #ifndef RELATIVE #define PVLB R4030_V_LOCAL_IO_BASE #else #define PVLB 0 #endif #define PICA_SYS_SONIC (PVLB+0x1000) /* SONIC base address */ #define PICA_SYS_SCSI (PVLB+0x2000) /* SCSI base address */ #define PICA_SYS_FLOPPY (PVLB+0x3000) /* Floppy base address */ #define PICA_SYS_CLOCK (PVLB+0x4000) /* Clock base address */ #define PICA_SYS_KBD (PVLB+0x5000) /* Keybrd/mouse base address */ #define PICA_SYS_COM1 (PVLB+0x6000) /* Com port 1 */ #define PICA_SYS_COM2 (PVLB+0x7000) /* Com port 2 */ #define PICA_SYS_PAR1 (PVLB+0x8000) /* Parallel port 1 */ #define PICA_SYS_NVRAM (PVLB+0x9000) /* Unprotected NV-ram */ #define PICA_SYS_PNVRAM (PVLB+0xa000) /* Protected NV-ram */ #define PICA_SYS_NVPROM (PVLB+0xb000) /* Read only NV-ram */ #define PICA_SYS_SOUND (PVLB+0xc000) /* Sound port */ #define PICA_SYS_ISA_AS (PICA_V_ISA_IO+0x70) #define PICA_P_DRAM_CONF 0x800e0000 /* Dram config registers */ #define PICA_V_DRAM_CONF 0xe00e0000 #define PICA_S_DRAM_CONF 0x00020000 #define PICA_P_INT_SOURCE 0xf0000000 /* Interrupt src registers */ #define PICA_V_INT_SOURCE R4030_V_LOCAL_IO_BASE+R4030_S_LOCAL_IO_BASE #define PICA_S_INT_SOURCE 0x00001000 #define PVIS PICA_V_INT_SOURCE #define PICA_SYS_LB_IS (PVIS+0x0000) /* Local bus int source */ #define PICA_SYS_LB_IE (PVIS+0x0002) /* Local bus int enables */ #define PICA_P_LOCAL_VIDEO_CTRL 0x60000000 /* Local video control */ #define PICA_V_LOCAL_VIDEO_CTRL 0xe0200000 #define PICA_S_LOCAL_VIDEO_CTRL 0x00200000 #define PICA_P_EXTND_VIDEO_CTRL 0x60200000 /* Extended video control */ #define PICA_V_EXTND_VIDEO_CTRL 0xe0400000 #define PICA_S_EXTND_VIDEO_CTRL 0x00200000 #define PICA_P_LOCAL_VIDEO 0x40000000 /* Local video memory */ #define PICA_V_LOCAL_VIDEO 0xe0800000 #define PICA_S_LOCAL_VIDEO 0x00800000 #define PICA_P_ISA_IO 0x90000000 /* ISA I/O control */ #define PICA_V_ISA_IO 0xe2000000 #define PICA_S_ISA_IO 0x01000000 #define PICA_P_ISA_MEM 0x91000000 /* ISA Memory control */ #define PICA_V_ISA_MEM 0xe3000000 #define PICA_S_ISA_MEM 0x01000000 /* * Addresses used by various display drivers. */ #define PICA_MONO_BASE (PICA_V_LOCAL_VIDEO_CTRL + 0x3B4) #define PICA_MONO_BUF (PICA_V_LOCAL_VIDEO + 0xB0000) #define PICA_CGA_BASE (PICA_V_LOCAL_VIDEO_CTRL + 0x3D4) #define PICA_CGA_BUF (PICA_V_LOCAL_VIDEO + 0xB8000) #endif /* _PICA_H_ */ gxemul-0.6.1/src/include/thirdparty/tulipreg.h000644 001750 001750 00000164144 13402411502 021647 0ustar00debugdebug000000 000000 /* $NetBSD: tulipreg.h,v 1.31 2005/06/23 23:51:42 rpaulo Exp $ */ #ifndef __volatile #define __volatile #endif /*- * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _DEV_IC_TULIPREG_H_ #define _DEV_IC_TULIPREG_H_ /* * Register description for the Digital Semiconductor ``Tulip'' (21x4x) * Ethernet controller family, and a variety of clone chips, including: * * - Macronix 98713, 98713A, 98715, 98715A, 98725 (PMAC): * * These chips are fairly straight-forward Tulip clones. * The 98713 is a very close 21140A clone. It has GPR * and MII media, and a GPIO facility, and uses the ISV * SROM format (or, at least, should, because of the GPIO * facility). The 98713A has MII, no GPIO facility, and * an internal NWay block. The 98715, 98715A, and 98725 * have only GPR media and the NWay block. The 98715, * 98715A, and 98725 support power management. * * The 98715AEC adds 802.3x flow Frame based Flow Control to the * 98715A. * * - Lite-On 82C115 (PNIC II): * * A clone of the Macronix MX98725, with the following differences: * * - Wake-On-LAN support * - 128-bit multicast hash table rather than the * standard 512-bit hash table * - 802.3x flow control * * - Lite-On 82C168, 82C169 (PNIC): * * Pretty close, with only a few minor differences: * * - EEPROM is accessed completely differently. * - MII is accessed completely differently. * - No SIO facility (due to the above two differences). * - GPIO interface is different than the 21140's. * - Boards that lack PHYs use the internal NWay block * and transceiver. * * - Winbond 89C840F * * Less similar, but still roughly compatible (enough so * that the driver can be adapted, at least): * * - Registers lack the pad word between them. * - Instead of a setup frame, there are two station * address registers and two multicast hash table * registers (64-bit multicast hash table). * - Only supported media interface is MII-over-SIO. * - Different OPMODE register bits for various things * (mostly media related). * * - ADMtek AL981 * * Another pretty-close clone: * * - Wake-On-LAN support * - Instead of a setup frame, there are two station * address registers and two multicast hash table * registers (64-bit multicast hash table). * - 802.3x flow control * - Only supported media interface is built-in PHY * which is accessed through a set of special registers. * - Not all registers have the pad word between them, * but luckily, there are all AL981-specific registers, * so this is easy to deal with. * * - ADMtek AN983 and AN985 * * Similar to the ADMtek AL981, but with a few differences. * * - Xircom X3201-3 * * CardBus 21143 clone, with a few differences: * * - No MicroWire SROM; Ethernet address must come * from CIS. * - Transmit buffers must also be 32-bit aligned. * - The BUSMODE_SWR bit is not self-clearing. * - Must include FS|LS in setup packet descriptor. * - SIA is not 21143-like, and all media attachments * are MII-on-SIO. * * - Davicom DM9102 and DM9102A * * Pretty similar to the 21140A, with a few differences: * * - Wake-On-LAN support * - DM9102 has built-in 10/100 PHY on MII interface. * - DM9102A has built-in 10/100 PHY on MII interface, * as well as a HomePNA 1 PHY on an alternate MII * interface (selected by clearing OPMODE_PS). * - The chip has a bug in the transmit DMA logic, * requiring that the packet be comprised of only * one DMA segment. * - The bus interface is buggy, and the BUSMODE register * must be initialized to 0. * - There seems to be an interrupt logic bug, requiring * that interrupts be disabled on the chip during the * interrupt handler. * * - ASIX AX88140 * * 21433 clone with a few differences: * * - Specific broadcast bit in the OPMODE register. * - Transmit buffer must be 32-bit aligned. * - The BUSMODE_SWR bit is not self-clearing. * - External 10BaseT PHY or 10/100 MII. * * Some of the clone chips have different registers, and some have * different bits in the same registers. These will be denoted by * PMAC, PNICII, PNIC, DM, WINB, ADM and AX in the register/bit names. */ /* * Tulip buffer descriptor. Must be 4-byte aligned. * * Note for receive descriptors, the byte count fields must * be a multiple of 4. */ struct tulip_desc { __volatile u_int32_t td_status; /* Status */ __volatile u_int32_t td_ctl; /* Control and Byte Counts */ __volatile u_int32_t td_bufaddr1; /* Buffer Address 1 */ __volatile u_int32_t td_bufaddr2; /* Buffer Address 2 */ }; /* * Descriptor Status bits common to transmit and receive. */ #define TDSTAT_OWN 0x80000000 /* Tulip owns descriptor */ #define TDSTAT_ES 0x00008000 /* Error Summary */ /* * Descriptor Status bits for Receive Descriptor. */ #define TDSTAT_Rx_FF 0x40000000 /* Filtering Fail */ #define TDSTAT_WINB_Rx_RCMP 0x40000000 /* Receive Complete */ #define TDSTAT_Rx_FL 0x3fff0000 /* Frame Length including CRC */ #define TDSTAT_Rx_DE 0x00004000 /* Descriptor Error */ #define TDSTAT_Rx_DT 0x00003000 /* Data Type */ #define TDSTAT_Rx_RF 0x00000800 /* Runt Frame */ #define TDSTAT_Rx_MF 0x00000400 /* Multicast Frame */ #define TDSTAT_Rx_FS 0x00000200 /* First Descriptor */ #define TDSTAT_Rx_LS 0x00000100 /* Last Descriptor */ #define TDSTAT_Rx_TL 0x00000080 /* Frame Too Long */ #define TDSTAT_Rx_CS 0x00000040 /* Collision Seen */ #define TDSTAT_Rx_RT 0x00000020 /* Frame Type */ #define TDSTAT_Rx_RW 0x00000010 /* Receive Watchdog */ #define TDSTAT_Rx_RE 0x00000008 /* Report on MII Error */ #define TDSTAT_Rx_DB 0x00000004 /* Dribbling Bit */ #define TDSTAT_Rx_CE 0x00000002 /* CRC Error */ #define TDSTAT_Rx_ZER 0x00000001 /* Zero (always 0) */ #define TDSTAT_Rx_LENGTH(x) (((x) & TDSTAT_Rx_FL) >> 16) #define TDSTAT_Rx_DT_SR 0x00000000 /* Serial Received Frame */ #define TDSTAT_Rx_DT_IL 0x00001000 /* Internal Loopback Frame */ #define TDSTAT_Rx_DT_EL 0x00002000 /* External Loopback Frame */ #define TDSTAT_Rx_DT_r 0x00003000 /* Reserved */ /* * Descriptor Status bits for Transmit Descriptor. */ #define TDSTAT_WINB_Tx_TE 0x00008000 /* Transmit Error */ #define TDSTAT_Tx_TO 0x00004000 /* Transmit Jabber Timeout */ #define TDSTAT_Tx_LO 0x00000800 /* Loss of Carrier */ #define TDSTAT_Tx_NC 0x00000400 /* No Carrier */ #define TDSTAT_Tx_LC 0x00000200 /* Late Collision */ #define TDSTAT_Tx_EC 0x00000100 /* Excessive Collisions */ #define TDSTAT_Tx_HF 0x00000080 /* Heartbeat Fail */ #define TDSTAT_Tx_CC 0x00000078 /* Collision Count */ #define TDSTAT_Tx_LF 0x00000004 /* Link Fail */ #define TDSTAT_Tx_UF 0x00000002 /* Underflow Error */ #define TDSTAT_Tx_DE 0x00000001 /* Deferred */ #define TDSTAT_Tx_COLLISIONS(x) (((x) & TDSTAT_Tx_CC) >> 3) /* * Descriptor Control bits common to transmit and receive. */ #define TDCTL_SIZE1 0x000007ff /* Size of buffer 1 */ #define TDCTL_SIZE1_SHIFT 0 #define TDCTL_SIZE2 0x003ff800 /* Size of buffer 2 */ #define TDCTL_SIZE2_SHIFT 11 #define TDCTL_ER 0x02000000 /* End of Ring */ #define TDCTL_CH 0x01000000 /* Second Address Chained */ /* * Descriptor Control bits for Transmit Descriptor. */ #define TDCTL_Tx_IC 0x80000000 /* Interrupt on Completion */ #define TDCTL_Tx_LS 0x40000000 /* Last Segment */ #define TDCTL_Tx_FS 0x20000000 /* First Segment */ #define TDCTL_Tx_FT1 0x10000000 /* Filtering Type 1 */ #define TDCTL_Tx_SET 0x08000000 /* Setup Packet */ #define TDCTL_Tx_AC 0x04000000 /* Add CRC Disable */ #define TDCTL_Tx_DPD 0x00800000 /* Disabled Padding */ #define TDCTL_Tx_FT0 0x00400000 /* Filtering Type 0 */ /* * The Tulip filter is programmed by "transmitting" a Setup Packet * (indicated by TDCTL_Tx_SET). The filtering type is indicated * as follows: * * FT1 FT0 Description * --- --- ----------- * 0 0 Perfect Filtering: The Tulip interprets the * descriptor buffer as a table of 16 MAC addresses * that the Tulip should receive. * * 0 1 Hash Filtering: The Tulip interprets the * descriptor buffer as a 512-bit hash table * plus one perfect address. If the incoming * address is Multicast, the hash table filters * the address, else the address is filtered by * the perfect address. * * 1 0 Inverse Filtering: Like Perfect Filtering, except * the table is addresses that the Tulip does NOT * receive. * * 1 1 Hash-only Filtering: Like Hash Filtering, but * physical addresses are matched by the hash table * as well, and not by matching a single perfect * address. * * A Setup Packet must always be 192 bytes long. The Tulip can store * 16 MAC addresses. If not all 16 are specified in Perfect Filtering * or Inverse Filtering mode, then unused entries should duplicate * one of the valid entries. */ #define TDCTL_Tx_FT_PERFECT 0 #define TDCTL_Tx_FT_HASH TDCTL_Tx_FT0 #define TDCTL_Tx_FT_INVERSE TDCTL_Tx_FT1 #define TDCTL_Tx_FT_HASHONLY (TDCTL_Tx_FT1|TDCTL_Tx_FT0) #define TULIP_SETUP_PACKET_LEN 192 #define TULIP_MAXADDRS 16 #define TULIP_MCHASHSIZE 512 #define TULIP_PNICII_HASHSIZE 128 /* * Maximum size of a Tulip Ethernet Address ROM or SROM. */ #define TULIP_ROM_SIZE(bits) (2 << (bits)) #define TULIP_MAX_ROM_SIZE 512 /* * Format of the standard Tulip SROM information: * * Byte offset Size Usage * 0 18 reserved * 18 1 SROM Format Version * 19 1 Chip Count * 20 6 IEEE Network Address * 26 1 Chip 0 Device Number * 27 2 Chip 0 Info Leaf Offset * 29 1 Chip 1 Device Number * 30 2 Chip 1 Info Leaf Offset * 32 1 Chip 2 Device Number * 33 2 Chip 2 Info Leaf Offset * ... 1 Chip n Device Number * ... 2 Chip n Info Leaf Offset * ... ... ... * Chip Info Leaf Information * ... * ... * ... * 126 2 CRC32 checksum */ #define TULIP_ROM_SROM_FORMAT_VERION 18 /* B */ #define TULIP_ROM_CHIP_COUNT 19 /* B */ #define TULIP_ROM_IEEE_NETWORK_ADDRESS 20 #define TULIP_ROM_CHIPn_DEVICE_NUMBER(n) (26 + ((n) * 3))/* B */ #define TULIP_ROM_CHIPn_INFO_LEAF_OFFSET(n) (27 + ((n) * 3))/* W */ #define TULIP_ROM_CRC32_CHECKSUM 126 /* W */ #define TULIP_ROM_CRC32_CHECKSUM1 94 /* W */ #define TULIP_ROM_IL_SELECT_CONN_TYPE 0 /* W */ #define TULIP_ROM_IL_MEDIA_COUNT 2 /* B */ #define TULIP_ROM_IL_MEDIAn_BLOCK_BASE 3 #define SELECT_CONN_TYPE_TP 0x0000 #define SELECT_CONN_TYPE_BNC 0x0001 #define SELECT_CONN_TYPE_AUI 0x0002 #define SELECT_CONN_TYPE_100TX 0x0003 #define SELECT_CONN_TYPE_100T4 0x0006 #define SELECT_CONN_TYPE_100FX 0x0007 #define SELECT_CONN_TYPE MII_10T 0x0009 #define SELECT_CONN_TYPE_MII_100TX 0x000d #define SELECT_CONN_TYPE_MII_100T4 0x000f #define SELECT_CONN_TYPE_MII_100FX 0x0010 #define SELECT_CONN_TYPE_TP_AUTONEG 0x0100 #define SELECT_CONN_TYPE_TP_FDX 0x0204 #define SELECT_CONN_TYPE_MII_10T_FDX 0x020a #define SELECT_CONN_TYPE_100TX_FDX 0x020e #define SELECT_CONN_TYPE_MII_100TX_FDX 0x0211 #define SELECT_CONN_TYPE_TP_NOLINKPASS 0x0400 #define SELECT_CONN_TYPE_ASENSE 0x0800 #define SELECT_CONN_TYPE_ASENSE_POWERUP 0x8800 #define SELECT_CONN_TYPE_ASENSE_AUTONEG 0x0900 #define TULIP_ROM_MB_MEDIA_CODE 0x3f #define TULIP_ROM_MB_MEDIA_TP 0x00 #define TULIP_ROM_MB_MEDIA_BNC 0x01 #define TULIP_ROM_MB_MEDIA_AUI 0x02 #define TULIP_ROM_MB_MEDIA_100TX 0x03 #define TULIP_ROM_MB_MEDIA_TP_FDX 0x04 #define TULIP_ROM_MB_MEDIA_100TX_FDX 0x05 #define TULIP_ROM_MB_MEDIA_100T4 0x06 #define TULIP_ROM_MB_MEDIA_100FX 0x07 #define TULIP_ROM_MB_MEDIA_100FX_FDX 0x08 #define TULIP_ROM_MB_EXT 0x40 #define TULIP_ROM_MB_CSR13 1 /* W */ #define TULIP_ROM_MB_CSR14 3 /* W */ #define TULIP_ROM_MB_CSR15 5 /* W */ #define TULIP_ROM_MB_SIZE(mc) (((mc) & TULIP_ROM_MB_EXT) ? 7 : 1) #define TULIP_ROM_MB_NOINDICATOR 0x8000 #define TULIP_ROM_MB_DEFAULT 0x4000 #define TULIP_ROM_MB_POLARITY 0x0080 #define TULIP_ROM_MB_OPMODE(x) (((x) & 0x71) << 18) #define TULIP_ROM_MB_BITPOS(x) (1 << (((x) & 0x0e) >> 1)) #define TULIP_ROM_MB_21140_GPR 0 /* 21140[A] GPR block */ #define TULIP_ROM_MB_21140_MII 1 /* 21140[A] MII block */ #define TULIP_ROM_MB_21142_SIA 2 /* 2114[23] SIA block */ #define TULIP_ROM_MB_21142_MII 3 /* 2114[23] MII block */ #define TULIP_ROM_MB_21143_SYM 4 /* 21143 SYM block */ #define TULIP_ROM_MB_21143_RESET 5 /* 21143 reset block */ #define TULIP_ROM_GETW(data, off) ((uint32_t)(data)[(off)] | \ (uint32_t)((data)[(off) + 1]) << 8) /* * Tulip control registers. */ #define TULIP_CSR0 0x00 #define TULIP_CSR1 0x08 #define TULIP_CSR2 0x10 #define TULIP_CSR3 0x18 #define TULIP_CSR4 0x20 #define TULIP_CSR5 0x28 #define TULIP_CSR6 0x30 #define TULIP_CSR7 0x38 #define TULIP_CSR8 0x40 #define TULIP_CSR9 0x48 #define TULIP_CSR10 0x50 #define TULIP_CSR11 0x58 #define TULIP_CSR12 0x60 #define TULIP_CSR13 0x68 #define TULIP_CSR14 0x70 #define TULIP_CSR15 0x78 #define TULIP_CSR16 0x80 #define TULIP_CSR17 0x88 #define TULIP_CSR18 0x90 #define TULIP_CSR19 0x98 #define TULIP_CSR20 0xa0 #define TULIP_CSR21 0xa8 #define TULIP_CSR22 0xb0 #define TULIP_CSR23 0xb8 #define TULIP_CSR24 0xc0 #define TULIP_CSR25 0xc8 #define TULIP_CSR26 0xd0 #define TULIP_CSR27 0xd8 #define TULIP_CSR28 0xe0 #define TULIP_CSR29 0xe8 #define TULIP_CSR30 0xf0 #define TULIP_CSR31 0xf8 #define TULIP_CSR_INDEX(csr) ((csr) >> 3) /* CSR0 - Bus Mode */ #define CSR_BUSMODE TULIP_CSR0 #define BUSMODE_SWR 0x00000001 /* software reset */ #define BUSMODE_BAR 0x00000002 /* bus arbitration */ #define BUSMODE_DSL 0x0000007c /* descriptor skip length */ #define BUSMODE_BLE 0x00000080 /* big endian */ /* programmable burst length */ #define BUSMODE_PBL_DEFAULT 0x00000000 /* default value */ #define BUSMODE_PBL_1LW 0x00000100 /* 1 longword */ #define BUSMODE_PBL_2LW 0x00000200 /* 2 longwords */ #define BUSMODE_PBL_4LW 0x00000400 /* 4 longwords */ #define BUSMODE_PBL_8LW 0x00000800 /* 8 longwords */ #define BUSMODE_PBL_16LW 0x00001000 /* 16 longwords */ #define BUSMODE_PBL_32LW 0x00002000 /* 32 longwords */ /* cache alignment */ #define BUSMODE_CAL_NONE 0x00000000 /* no alignment */ #define BUSMODE_CAL_8LW 0x00004000 /* 8 longwords */ #define BUSMODE_CAL_16LW 0x00008000 /* 16 longwords */ #define BUSMODE_CAL_32LW 0x0000c000 /* 32 longwords */ #define BUSMODE_DAS 0x00010000 /* diagnostic address space */ /* must be zero on most */ /* transmit auto-poll */ /* * Transmit auto-polling not supported on: * Winbond 89C040F * Xircom X3201-3 * Davicom DM9102 (buggy BUSMODE register) * ASIX AX88140 */ #define BUSMODE_TAP_NONE 0x00000000 /* no auto-polling */ #define BUSMODE_TAP_200us 0x00020000 /* 200 uS */ #define BUSMODE_TAP_800us 0x00040000 /* 400 uS */ #define BUSMODE_TAP_1_6ms 0x00060000 /* 1.6 mS */ #define BUSMODE_TAP_12_8us 0x00080000 /* 12.8 uS (21041+) */ #define BUSMODE_TAP_25_6us 0x000a0000 /* 25.6 uS (21041+) */ #define BUSMODE_TAP_51_2us 0x000c0000 /* 51.2 uS (21041+) */ #define BUSMODE_TAP_102_4us 0x000e0000 /* 102.4 uS (21041+) */ #define BUSMODE_DBO 0x00100000 /* desc-only b/e (21041+) */ #define BUSMODE_RME 0x00200000 /* rd/mult enab (21140+) */ #define BUSMODE_WINB_WAIT 0x00200000 /* wait state insertion */ #define BUSMODE_RLE 0x00800000 /* rd/line enab (21140+) */ #define BUSMODE_WLE 0x01000000 /* wt/line enab (21140+) */ #define BUSMODE_PNIC_MBO 0x04000000 /* magic `must be one' bit */ /* on Lite-On PNIC */ /* CSR1 - Transmit Poll Demand */ #define CSR_TXPOLL TULIP_CSR1 #define TXPOLL_TPD 0x00000001 /* transmit poll demand */ /* CSR2 - Receive Poll Demand */ #define CSR_RXPOLL TULIP_CSR2 #define RXPOLL_RPD 0x00000001 /* receive poll demand */ /* CSR3 - Receive List Base Address */ #define CSR_RXLIST TULIP_CSR3 /* CSR4 - Transmit List Base Address */ #define CSR_TXLIST TULIP_CSR4 /* CSR5 - Status */ #define CSR_STATUS TULIP_CSR5 #define STATUS_TI 0x00000001 /* transmit interrupt */ #define STATUS_TPS 0x00000002 /* transmit process stopped */ #define STATUS_TU 0x00000004 /* transmit buffer unavail */ #define STATUS_TJT 0x00000008 /* transmit jabber timeout */ #define STATUS_WINB_REI 0x00000008 /* receive early interrupt */ #define STATUS_LNPANC 0x00000010 /* link pass (21041) */ #define STATUS_WINB_RERR 0x00000010 /* receive error */ #define STATUS_UNF 0x00000020 /* transmit underflow */ #define STATUS_RI 0x00000040 /* receive interrupt */ #define STATUS_RU 0x00000080 /* receive buffer unavail */ #define STATUS_RPS 0x00000100 /* receive process stopped */ #define STATUS_RWT 0x00000200 /* receive watchdog timeout */ #define STATUS_AT 0x00000400 /* SIA AUI/TP pin changed (21040) */ #define STATUS_ETI 0x00000400 /* early transmit interrupt (21142/PMAC/Winbond) */ #define STATUS_FD 0x00000800 /* full duplex short frame received (21040) */ #define STATUS_TM 0x00000800 /* timer expired (21041) */ #define STATUS_LNF 0x00001000 /* link fail (21040) */ #define STATUS_SE 0x00002000 /* system error */ #define STATUS_ER 0x00004000 /* early receive (21041) */ #define STATUS_AIS 0x00008000 /* abnormal interrupt summary */ #define STATUS_NIS 0x00010000 /* normal interrupt summary */ #define STATUS_RS 0x000e0000 /* receive process state */ #define STATUS_RS_STOPPED 0x00000000 /* Stopped */ #define STATUS_RS_FETCH 0x00020000 /* Running - fetch receive descriptor */ #define STATUS_RS_CHECK 0x00040000 /* Running - check for end of receive */ #define STATUS_RS_WAIT 0x00060000 /* Running - wait for packet */ #define STATUS_RS_SUSPENDED 0x00080000 /* Suspended */ #define STATUS_RS_CLOSE 0x000a0000 /* Running - close receive descriptor */ #define STATUS_RS_FLUSH 0x000c0000 /* Running - flush current frame from FIFO */ #define STATUS_RS_QUEUE 0x000e0000 /* Running - queue current frame from FIFO into buffer */ #define STATUS_DM_RS_STOPPED 0x00000000 /* Stopped */ #define STATUS_DM_RS_FETCH 0x00020000 /* Running - fetch receive descriptor */ #define STATUS_DM_RS_WAIT 0x00040000 /* Running - wait for packet */ #define STATUS_DM_RS_QUEUE 0x00060000 /* Running - queue current frame from FIFO into buffer */ #define STATUS_DM_RS_CLOSE_OWN 0x00080000 /* Running - close receive descriptor, clear own */ #define STATUS_DM_RS_CLOSE_ST 0x000a0000 /* Running - close receive descriptor, write status */ #define STATUS_DM_RS_SUSPENDED 0x000c0000 /* Suspended */ #define STATUS_DM_RS_FLUSH 0x000e0000 /* Running - flush current frame from FIFO */ #define STATUS_TS 0x00700000 /* transmit process state */ #define STATUS_TS_STOPPED 0x00000000 /* Stopped */ #define STATUS_TS_FETCH 0x00100000 /* Running - fetch transmit descriptor */ #define STATUS_TS_WAIT 0x00200000 /* Running - wait for end of transmission */ #define STATUS_TS_READING 0x00300000 /* Running - read buffer from memory and queue into FIFO */ #define STATUS_TS_RESERVED 0x00400000 /* RESERVED */ #define STATUS_TS_SETUP 0x00500000 /* Running - Setup packet */ #define STATUS_TS_SUSPENDED 0x00600000 /* Suspended */ #define STATUS_TS_CLOSE 0x00700000 /* Running - close transmit descriptor */ #define STATUS_DM_TS_STOPPED 0x00000000 /* Stopped */ #define STATUS_DM_TS_FETCH 0x00100000 /* Running - fetch transmit descriptor */ #define STATUS_DM_TS_SETUP 0x00200000 /* Running - Setup packet */ #define STATUS_DM_TS_READING 0x00300000 /* Running - read buffer from memory and queue into FIFO */ #define STATUS_DM_TS_CLOSE_OWN 0x00400000 /* Running - close transmit descriptor, clear own */ #define STATUS_DM_TS_WAIT 0x00500000 /* Running - wait for end of transmission */ #define STATUS_DM_TS_CLOSE_ST 0x00600000 /* Running - close transmit descriptor, write status */ #define STATUS_DM_TS_SUSPENDED 0x00700000 /* Suspended */ #define STATUS_EB 0x03800000 /* error bits */ #define STATUS_EB_PARITY 0x00000000 /* parity errror */ #define STATUS_EB_MABT 0x00800000 /* master abort */ #define STATUS_EB_TABT 0x01000000 /* target abort */ #define STATUS_GPPI 0x04000000 /* GPIO interrupt (21142) */ #define STATUS_PNIC_TXABORT 0x04000000 /* transmit aborted */ #define STATUS_LC 0x08000000 /* 100baseTX link change (21142/PMAC) */ #define STATUS_PMAC_WKUPI 0x10000000 /* wake up event */ #define STATUS_X3201_PMEIS 0x10000000 /* power management event interrupt summary */ #define STATUS_X3201_SFIS 0x80000000 /* second function (Modem) interrupt status */ /* CSR6 - Operation Mode */ #define CSR_OPMODE TULIP_CSR6 #define OPMODE_HP 0x00000001 /* hash/perfect mode (ro) */ #define OPMODE_SR 0x00000002 /* start receive */ #define OPMODE_HO 0x00000004 /* hash only mode (ro) */ #define OPMODE_PB 0x00000008 /* pass bad frames */ #define OPMODE_WINB_APP 0x00000008 /* accept all physcal packet */ #define OPMODE_IF 0x00000010 /* inverse filter mode (ro) */ #define OPMODE_WINB_AMP 0x00000010 /* accept multicast packet */ #define OPMODE_SB 0x00000020 /* start backoff counter */ #define OPMODE_WINB_ABP 0x00000020 /* accept broadcast packet */ #define OPMODE_PR 0x00000040 /* promiscuous mode */ #define OPMODE_WINB_ARP 0x00000040 /* accept runt packet */ #define OPMODE_PM 0x00000080 /* pass all multicast */ #define OPMODE_WINB_AEP 0x00000080 /* accept error packet */ #define OPMODE_FKD 0x00000100 /* flaky oscillator disable */ #define OPMODE_AX_RB 0x00000100 /* recieve broadcast packets */ #define OPMODE_FD 0x00000200 /* full-duplex mode */ #define OPMODE_OM 0x00000c00 /* operating mode */ #define OPMODE_OM_NORMAL 0x00000000 /* normal mode */ #define OPMODE_OM_INTLOOP 0x00000400 /* internal loopback */ #define OPMODE_OM_EXTLOOP 0x00000800 /* external loopback */ #define OPMODE_FC 0x00001000 /* force collision */ #define OPMODE_ST 0x00002000 /* start transmitter */ #define OPMODE_TR 0x0000c000 /* threshold control */ #define OPMODE_TR_72 0x00000000 /* 72 bytes */ #define OPMODE_TR_96 0x00004000 /* 96 bytes */ #define OPMODE_TR_128 0x00008000 /* 128 bytes */ #define OPMODE_TR_160 0x0000c000 /* 160 bytes */ #define OPMODE_WINB_TTH 0x001fc000 /* transmit threshold */ #define OPMODE_WINB_TTH_SHIFT 14 #define OPMODE_BP 0x00010000 /* backpressure enable */ #define OPMODE_CA 0x00020000 /* capture effect enable */ #define OPMODE_PNIC_TBEN 0x00020000 /* Tx backoff offset enable */ /* * On Davicom DM9102, OPMODE_PS and OPMODE_HBD must * always be set. */ #define OPMODE_PS 0x00040000 /* port select: 1 = MII/SYM, 0 = SRL (21140) */ #define OPMODE_HBD 0x00080000 /* heartbeat disable: set in MII/SYM 100mbps, set according to PHY in MII 10mbps mode (21140) */ #define OPMODE_PNIC_IT 0x00100000 /* immediate transmit */ #define OPMODE_SF 0x00200000 /* store and forward mode (21140) */ #define OPMODE_WINB_REIT 0x1fe00000 /* receive eartly intr thresh */ #define OPMODE_WINB_REIT_SHIFT 21 #define OPMODE_TTM 0x00400000 /* Transmit Threshold Mode: 1 = 10mbps, 0 = 100mbps (21140) */ #define OPMODE_PCS 0x00800000 /* PCS function (21140) */ #define OPMODE_SCR 0x01000000 /* scrambler mode (21140) */ #define OPMODE_MBO 0x02000000 /* must be one (21140, DM9102) */ #define OPMODE_IDAMSB 0x04000000 /* ignore dest addr MSB (21142) */ #define OPMODE_PNIC_DRC 0x20000000 /* don't include CRC in Rx frames (PNIC) */ #define OPMODE_WINB_FES 0x20000000 /* fast ethernet select */ #define OPMODE_RA 0x40000000 /* receive all (21140) */ #define OPMODE_PNIC_EED 0x40000000 /* 1 == ext, 0 == int ENDEC (PNIC) */ #define OPMODE_WINB_TEIO 0x40000000 /* transmit early intr on */ #define OPMODE_SC 0x80000000 /* special capture effect enable (21041+) */ #define OPMODE_WINB_REIO 0x80000000 /* receive early intr on */ /* Shorthand for media-related OPMODE bits */ #define OPMODE_MEDIA_BITS (OPMODE_FD|OPMODE_PS|OPMODE_TTM|OPMODE_PCS|OPMODE_SCR) /* CSR7 - Interrupt Enable */ #define CSR_INTEN TULIP_CSR7 /* See bits for CSR5 -- Status */ /* CSR8 - Missed Frames */ #define CSR_MISSED TULIP_CSR8 #define MISSED_MFC 0x0000ffff /* missed packet count */ #define MISSED_MFO 0x00010000 /* missed packet count overflowed */ #define MISSED_FOC 0x0ffe0000 /* fifo overflow counter (21140) */ #define MISSED_OCO 0x10000000 /* overflow counter overflowed (21140) */ #define MISSED_GETMFC(x) ((x) & MISSED_MFC) #define MISSED_GETFOC(x) (((x) & MISSED_FOC) >> 17) /* CSR9 - MII, SROM, Boot ROM, Ethernet Address ROM register. */ #define CSR_MIIROM TULIP_CSR9 #define MIIROM_DATA 0x000000ff /* byte of data from Ethernet Address ROM (21040), byte of data to/from Boot ROM (21041+) */ #define MIIROM_SROMCS 0x00000001 /* SROM chip select */ #define MIIROM_SROMSK 0x00000002 /* SROM clock */ #define MIIROM_SROMDI 0x00000004 /* SROM data in (to) */ #define MIIROM_SROMDO 0x00000008 /* SROM data out (from) */ #define MIIROM_REG 0x00000400 /* external register select */ #define MIIROM_SR 0x00000800 /* SROM select */ #define MIIROM_BR 0x00001000 /* boot ROM select */ #define MIIROM_WR 0x00002000 /* write to boot ROM */ #define MIIROM_RD 0x00004000 /* read from boot ROM */ #define MIIROM_MOD 0x00008000 /* mode select (ro) (21041) */ #define MIIROM_MDC 0x00010000 /* MII clock */ #define MIIROM_MDO 0x00020000 /* MII data out */ #define MIIROM_MIIDIR 0x00040000 /* MII direction mode 1 = PHY in read, 0 = PHY in write */ #define MIIROM_MDI 0x00080000 /* MII data in */ #define MIIROM_DN 0x80000000 /* data not valid (21040) */ #define MIIROM_PMAC_LED0SEL 0x10000000 /* 0 == LED0 activity (def) 1 == LED0 speed */ #define MIIROM_PMAC_LED1SEL 0x20000000 /* 0 == LED1 link (def) 1 == LED1 link/act */ #define MIIROM_PMAC_LED2SEL 0x40000000 /* 0 == LED2 speed (def) 1 == LED2 collision */ #define MIIROM_PMAC_LED3SEL 0x80000000 /* 0 == LED3 receive (def) 1 == LED3 full duplex */ /* SROM opcodes */ #define TULIP_SROM_OPC_ERASE 0x04 #define TULIP_SROM_OPC_WRITE 0x05 #define TULIP_SROM_OPC_READ 0x06 /* The Lite-On PNIC does this completely differently */ #define PNIC_MIIROM_DATA 0x0000ffff /* mask of data bits ??? */ #define PNIC_MIIROM_BUSY 0x80000000 /* EEPROM is busy */ /* CSR10 - Boot ROM address register (21041+). */ #define CSR_ROMADDR TULIP_CSR10 #define ROMADDR_MASK 0x000003ff /* boot rom address */ /* CSR11 - General Purpose Timer (21041+). */ #define CSR_GPT TULIP_CSR11 #define GPT_VALUE 0x0000ffff /* timer value */ #define GPT_CON 0x00010000 /* continuous mode */ /* 21143-PD and 21143-TD Interrupt Mitigation bits */ #define GPT_NRX 0x000e0000 /* number of Rx packets */ #define GPT_RXT 0x00f00000 /* Rx timer */ #define GPT_NTX 0x07000000 /* number of Tx packets */ #define GPT_TXT 0x78000000 /* Tx timer */ #define GPT_CYCLE 0x80000000 /* cycle size */ /* CSR12 - SIA Status Register. */ #define CSR_SIASTAT TULIP_CSR12 #define SIASTAT_PAUI 0x00000001 /* pin AUI/TP indication (21040) */ #define SIASTAT_MRA 0x00000001 /* MII receive activity (21142) */ #define SIASTAT_NCR 0x00000002 /* network connection error */ #define SIASTAT_LS100 0x00000002 /* 100baseT link status 0 == pass (21142) */ #define SIASTAT_LKF 0x00000004 /* link fail status */ #define SIASTAT_LS10 0x00000004 /* 10baseT link status 0 == pass (21142) */ #define SIASTAT_APS 0x00000008 /* auto polarity status */ #define SIASTAT_DSD 0x00000010 /* PLL self test done */ #define SIASTAT_DSP 0x00000020 /* PLL self test pass */ #define SIASTAT_DAZ 0x00000040 /* PLL all zero */ #define SIASTAT_DAO 0x00000080 /* PLL all one */ #define SIASTAT_SRA 0x00000100 /* selected port receive activity (21041) */ #define SIASTAT_ARA 0x00000100 /* AUI receive activity (21142) */ #define SIASTAT_NRA 0x00000200 /* non-selected port receive activity (21041) */ #define SIASTAT_TRA 0x00000200 /* 10base-T receive activity (21142) */ #define SIASTAT_NSN 0x00000400 /* non-stable NLPs detected (21041) */ #define SIASTAT_TRF 0x00000800 /* transmit remote fault (21041) */ #define SIASTAT_ANS 0x00007000 /* autonegotiation state (21041) */ #define SIASTAT_ANS_DIS 0x00000000 /* disabled */ #define SIASTAT_ANS_TXDIS 0x00001000 /* transmit disabled */ #define SIASTAT_ANS_START 0x00001000 /* (MX98715AEC) */ #define SIASTAT_ANS_ABD 0x00002000 /* ability detect */ #define SIASTAT_ANS_ACKD 0x00003000 /* acknowledge detect */ #define SIASTAT_ANS_ACKC 0x00004000 /* complete acknowledge */ #define SIASTAT_ANS_FLPGOOD 0x00005000 /* FLP link good */ #define SIASTAT_ANS_LINKCHECK 0x00006000 /* link check */ #define SIASTAT_LPN 0x00008000 /* link partner negotiable (21041) */ #define SIASTAT_LPC 0xffff0000 /* link partner code word */ #define SIASTAT_GETLPC(x) (((x) & SIASTAT_LPC) >> 16) /* CSR13 - SIA Connectivity Register. */ #define CSR_SIACONN TULIP_CSR13 #define SIACONN_SRL 0x00000001 /* SIA reset (0 == reset) */ #define SIACONN_PS 0x00000002 /* pin AUI/TP selection (21040) */ #define SIACONN_CAC 0x00000004 /* CSR autoconfiguration */ #define SIACONN_AUI 0x00000008 /* select AUI (0 = TP) */ #define SIACONN_EDP 0x00000010 /* SIA PLL external input enable (21040) */ #define SIACONN_ENI 0x00000020 /* encoder input multiplexer (21040) */ #define SIACONN_SIM 0x00000040 /* serial interface input multiplexer (21040) */ #define SIACONN_ASE 0x00000080 /* APLL start enable (21040) */ #define SIACONN_SEL 0x00000f00 /* external port output multiplexer select (21040) */ #define SIACONN_IE 0x00001000 /* input enable (21040) */ #define SIACONN_OE1_3 0x00002000 /* output enable 1, 3 (21040) */ #define SIACONN_OE2_4 0x00004000 /* output enable 2, 4 (21040) */ #define SIACONN_OE5_6_7 0x00008000 /* output enable 5, 6, 7 (21040) */ #define SIACONN_SDM 0x0000ef00 /* SIA diagnostic mode; always set to this value for normal operation (21041) */ /* CSR14 - SIA Transmit Receive Register. */ #define CSR_SIATXRX TULIP_CSR14 #define SIATXRX_ECEN 0x00000001 /* encoder enable */ #define SIATXRX_LBK 0x00000002 /* loopback enable */ #define SIATXRX_DREN 0x00000004 /* driver enable */ #define SIATXRX_LSE 0x00000008 /* link pulse send enable */ #define SIATXRX_CPEN 0x00000030 /* compensation enable */ #define SIATXRX_CPEN_DIS0 0x00000000 /* disabled */ #define SIATXRX_CPEN_DIS1 0x00000010 /* disabled */ #define SIATXRX_CPEN_HIGHPWR 0x00000020 /* high power */ #define SIATXRX_CPEN_NORMAL 0x00000030 /* normal */ #define SIATXRX_MBO 0x00000040 /* must be one (21041 pass 2) */ #define SIATXRX_TH 0x00000040 /* 10baseT HDX enable (21142) */ #define SIATXRX_ANE 0x00000080 /* autonegotiation enable (21041/21142) */ #define SIATXRX_RSQ 0x00000100 /* receive squelch enable */ #define SIATXRX_CSQ 0x00000200 /* collision squelch enable */ #define SIATXRX_CLD 0x00000400 /* collision detect enable */ #define SIATXRX_SQE 0x00000800 /* signal quality generation enable */ #define SIATXRX_LTE 0x00001000 /* link test enable */ #define SIATXRX_APE 0x00002000 /* auto-polarity enable */ #define SIATXRX_SPP 0x00004000 /* set polarity plus */ #define SIATXRX_TAS 0x00008000 /* 10base-T/AUI autosensing enable (21041/21142) */ #define SIATXRX_THX 0x00010000 /* 100baseTX-HDX (21142) */ #define SIATXRX_TXF 0x00020000 /* 100baseTX-FDX (21142) */ #define SIATXRX_T4 0x00040000 /* 100baseT4 (21142) */ /* CSR15 - SIA General Register. */ #define CSR_SIAGEN TULIP_CSR15 #define SIAGEN_JBD 0x00000001 /* jabber disable */ #define SIAGEN_HUJ 0x00000002 /* host unjab */ #define SIAGEN_JCK 0x00000004 /* jabber clock */ #define SIAGEN_ABM 0x00000008 /* BNC select (21041) */ #define SIAGEN_RWD 0x00000010 /* receive watchdog disable */ #define SIAGEN_RWR 0x00000020 /* receive watchdog release */ #define SIAGEN_LE1 0x00000040 /* LED 1 enable (21041) */ #define SIAGEN_LV1 0x00000080 /* LED 1 value (21041) */ #define SIAGEN_TSCK 0x00000100 /* test clock */ #define SIAGEN_FUSQ 0x00000200 /* force unsquelch */ #define SIAGEN_FLF 0x00000400 /* force link fail */ #define SIAGEN_LSD 0x00000800 /* LED stretch disable (21041) */ #define SIAGEN_LEE 0x00000800 /* Link extend enable (21142) */ #define SIAGEN_DPST 0x00001000 /* PLL self-test start */ #define SIAGEN_FRL 0x00002000 /* force receiver low */ #define SIAGEN_LE2 0x00004000 /* LED 2 enable (21041) */ #define SIAGEN_RMP 0x00004000 /* received magic packet (21143) */ #define SIAGEN_LV2 0x00008000 /* LED 2 value (21041) */ #define SIAGEN_HCKR 0x00008000 /* hacker (21143) */ #define SIAGEN_MD 0x000f0000 /* general purpose mode/data */ #define SIAGEN_LGS0 0x00100000 /* LED/GEP 0 select */ #define SIAGEN_LGS1 0x00200000 /* LED/GEP 1 select */ #define SIAGEN_LGS2 0x00400000 /* LED/GEP 2 select */ #define SIAGEN_LGS3 0x00800000 /* LED/GEP 3 select */ #define SIAGEN_GEI0 0x01000000 /* GEP pin 0 intr enable */ #define SIAGEN_GEI1 0x02000000 /* GEP pin 1 intr enable */ #define SIAGEN_RME 0x04000000 /* receive match enable */ #define SIAGEN_CWE 0x08000000 /* control write enable */ #define SIAGEN_GI0 0x10000000 /* GEP pin 0 interrupt */ #define SIAGEN_GI1 0x20000000 /* GEP pin 1 interrupt */ #define SIAGEN_RMI 0x40000000 /* receive match interrupt */ /* CSR12 - General Purpose Port (21140+). */ #define CSR_GPP TULIP_CSR12 #define GPP_MD 0x000000ff /* general purpose mode/data */ #define GPP_GPC 0x00000100 /* general purpose control */ #define GPP_PNIC_GPD 0x0000000f /* general purpose data */ #define GPP_PNIC_GPC 0x000000f0 /* general purpose control */ #define GPP_PNIC_IN(x) (1 << (x)) #define GPP_PNIC_OUT(x, on) (((on) << (x)) | (1 << ((x) + 4))) /* * The Lite-On PNIC manual recommends the following for the General Purpose * I/O pins: * * 0 Speed Relay 1 == 100mbps * 1 100mbps loopback 1 == loopback * 2 BNC DC-DC converter 1 == select BNC * 3 Link 100 1 == 100baseTX link status */ #define GPP_PNIC_PIN_SPEED_RLY 0 #define GPP_PNIC_PIN_100M_LPKB 1 #define GPP_PNIC_PIN_BNC_XMER 2 #define GPP_PNIC_PIN_LNK100X 3 /* * Definitions used for the SMC 9332DST (21140) board. */ #define GPP_SMC9332DST_PINS 0x3f /* General Purpose Pin directions */ #define GPP_SMC9332DST_OK10 0x80 /* 10 Mb/sec Signal Detect gep<7> */ #define GPP_SMC9332DST_OK100 0x40 /* 100 Mb/sec Signal Detect gep<6> */ #define GPP_SMC9332DST_INIT 0x09 /* No loopback --- point-to-point */ /* * Definitions used for the Cogent EM1x0 (21140) board. */ #define GPP_COGENT_EM1x0_PINS 0x3f /* General Purpose Pin directions */ #define GPP_COGENT_EM1x0_INIT 0x09 /* No loopback --- point-to-point */ /* * Digital Semiconductor 21040 registers. */ /* CSR11 - Full Duplex Register */ #define CSR_21040_FDX TULIP_CSR11 #define FDX21040_FDXACV 0x0000ffff /* full duplex autoconfiguration value */ /* SIA configuration for 10base-T (from the 21040 manual) */ #define SIACONN_21040_10BASET 0x0000ef01 #define SIATXRX_21040_10BASET 0x0000ffff #define SIAGEN_21040_10BASET 0x00000000 /* SIA configuration for 10base-T full-duplex (from the 21040 manual) */ #define SIACONN_21040_10BASET_FDX 0x0000ef01 #define SIATXRX_21040_10BASET_FDX 0x0000fffd #define SIAGEN_21040_10BASET_FDX 0x00000000 /* SIA configuration for 10base-5 (from the 21040 manual) */ #define SIACONN_21040_AUI 0x0000ef09 #define SIATXRX_21040_AUI 0x00000705 #define SIAGEN_21040_AUI 0x00000006 /* SIA configuration for External SIA (from the 21040 manual) */ #define SIACONN_21040_EXTSIA 0x00003041 #define SIATXRX_21040_EXTSIA 0x00000000 #define SIAGEN_21040_EXTSIA 0x00000006 /* * Digital Semiconductor 21041 registers. */ /* SIA configuration for 10base-T (from the 21041 manual) */ #define SIACONN_21041_10BASET 0x0000ef01 #define SIATXRX_21041_10BASET 0x0000ff3f #define SIAGEN_21041_10BASET 0x00000000 #define SIACONN_21041P2_10BASET SIACONN_21041_10BASET #define SIATXRX_21041P2_10BASET 0x0000ffff #define SIAGEN_21041P2_10BASET SIAGEN_21041_10BASET /* SIA configuration for 10base-T full-duplex (from the 21041 manual) */ #define SIACONN_21041_10BASET_FDX 0x0000ef01 #define SIATXRX_21041_10BASET_FDX 0x0000ff3d #define SIAGEN_21041_10BASET_FDX 0x00000000 #define SIACONN_21041P2_10BASET_FDX SIACONN_21041_10BASET_FDX #define SIATXRX_21041P2_10BASET_FDX 0x0000ffff #define SIAGEN_21041P2_10BASET_FDX SIAGEN_21041_10BASET_FDX /* SIA configuration for 10base-5 (from the 21041 manual) */ #define SIACONN_21041_AUI 0x0000ef09 #define SIATXRX_21041_AUI 0x0000f73d #define SIAGEN_21041_AUI 0x0000000e #define SIACONN_21041P2_AUI SIACONN_21041_AUI #define SIATXRX_21041P2_AUI 0x0000f7fd #define SIAGEN_21041P2_AUI SIAGEN_21041_AUI /* SIA configuration for 10base-2 (from the 21041 manual) */ #define SIACONN_21041_BNC 0x0000ef09 #define SIATXRX_21041_BNC 0x0000f73d #define SIAGEN_21041_BNC 0x00000006 #define SIACONN_21041P2_BNC SIACONN_21041_BNC #define SIATXRX_21041P2_BNC 0x0000f7fd #define SIAGEN_21041P2_BNC SIAGEN_21041_BNC /* * Digital Semiconductor 21142/21143 registers. */ /* SIA configuration for 10baseT (from the 21143 manual) */ #define SIACONN_21142_10BASET 0x00000001 #define SIATXRX_21142_10BASET 0x00007f3f #define SIAGEN_21142_10BASET 0x00000008 /* SIA configuration for 10baseT full-duplex (from the 21143 manual) */ #define SIACONN_21142_10BASET_FDX 0x00000001 #define SIATXRX_21142_10BASET_FDX 0x00007f3d #define SIAGEN_21142_10BASET_FDX 0x00000008 /* SIA configuration for 10base5 (from the 21143 manual) */ #define SIACONN_21142_AUI 0x00000009 #define SIATXRX_21142_AUI 0x00004705 #define SIAGEN_21142_AUI 0x0000000e /* SIA configuration for 10base2 (from the 21143 manual) */ #define SIACONN_21142_BNC 0x00000009 #define SIATXRX_21142_BNC 0x00004705 #define SIAGEN_21142_BNC 0x00000006 /* * Lite-On 82C168/82C169 registers. */ /* ENDEC General Register */ #define CSR_PNIC_ENDEC 0x78 #define PNIC_ENDEC_JDIS 0x00000001 /* jabber disable */ /* SROM Power Register */ #define CSR_PNIC_SROMPWR 0x90 #define PNIC_SROMPWR_MRLE 0x00000001 /* Memory-Read-Line enable */ #define PNIC_SROMPWR_CB 0x00000002 /* cache boundary alignment burst type; 1 == burst to boundary, 0 == single-cycle to boundary */ /* SROM Control Register */ #define CSR_PNIC_SROMCTL 0x98 #define PNIC_SROMCTL_addr 0x0000003f /* mask of address bits */ /* XXX THESE ARE WRONG ACCORDING TO THE MANUAL! */ #define PNIC_SROMCTL_READ 0x00000600 /* read command */ /* MII Access Register */ #define CSR_PNIC_MII 0xa0 #define PNIC_MII_DATA 0x0000ffff /* mask of data bits */ #define PNIC_MII_REG 0x007c0000 /* register mask */ #define PNIC_MII_REGSHIFT 18 #define PNIC_MII_PHY 0x0f800000 /* phy mask */ #define PNIC_MII_PHYSHIFT 23 #define PNIC_MII_OPCODE 0x30000000 /* opcode mask */ #define PNIC_MII_RESERVED 0x00020000 /* must be one/must be zero; 2 bits are described here */ #define PNIC_MII_MBO 0x40000000 /* must be one */ #define PNIC_MII_BUSY 0x80000000 /* MII is busy */ #define PNIC_MII_WRITE 0x10000000 /* write PHY command */ #define PNIC_MII_READ 0x20000000 /* read PHY command */ /* NWAY Register */ #define CSR_PNIC_NWAY 0xb8 #define PNIC_NWAY_RS 0x00000001 /* reset NWay block */ #define PNIC_NWAY_PD 0x00000002 /* power down NWay block */ #define PNIC_NWAY_BX 0x00000004 /* bypass transceiver */ #define PNIC_NWAY_LC 0x00000008 /* AUI low current mode */ #define PNIC_NWAY_UV 0x00000010 /* low squelch voltage */ #define PNIC_NWAY_DX 0x00000020 /* disable TP pol. correction */ #define PNIC_NWAY_TW 0x00000040 /* select TP (0 == AUI) */ #define PNIC_NWAY_AF 0x00000080 /* AUI full/half step input voltage */ #define PNIC_NWAY_FD 0x00000100 /* full duplex mode */ #define PNIC_NWAY_DL 0x00000200 /* disable link integrity test */ #define PNIC_NWAY_DM 0x00000400 /* disable AUI/TP autodetect */ #define PNIC_NWAY_100 0x00000800 /* 1 == 100mbps, 0 == 10mbps */ #define PNIC_NWAY_NW 0x00001000 /* enable NWay block */ #define PNIC_NWAY_CAP10T 0x00002000 /* adv. 10baseT */ #define PNIC_NWAY_CAP10TFDX 0x00004000 /* adv. 10baseT-FDX */ #define PNIC_NWAY_CAP100TXFDX 0x00008000 /* adv. 100baseTX-FDX */ #define PNIC_NWAY_CAP100TX 0x00010000 /* adv. 100baseTX */ #define PNIC_NWAY_CAP100T4 0x00020000 /* adv. 100base-T4 */ #define PNIC_NWAY_RN 0x02000000 /* re-negotiate enable */ #define PNIC_NWAY_RF 0x04000000 /* remote fault detected */ #define PNIC_NWAY_LPAR10T 0x08000000 /* link part. 10baseT */ #define PNIC_NWAY_LPAR10TFDX 0x10000000 /* link part. 10baseT-FDX */ #define PNIC_NWAY_LPAR100TXFDX 0x20000000 /* link part. 100baseTX-FDX */ #define PNIC_NWAY_LPAR100TX 0x40000000 /* link part. 100baseTX */ #define PNIC_NWAY_LPAR100T4 0x80000000 /* link part. 100base-T4 */ #define PNIC_NWAY_LPAR_MASK 0xf8000000 /* * Macronix 98713, 98713A, 98715, 98715A, 98715AEC, 98725, and * Lite-On 82C115 registers. */ /* * Note, the MX98713 is very Tulip-like: * * CSR12 General Purpose Port (like 21140) * CSR13 reserved * CSR14 reserved * CSR15 Watchdog Timer (like 21140) * * The Macronix CSR12, CSR13, CSR14, and CSR15 exist only * on the MX98713A and higher. */ /* CSR12 - 10base-T Status Port (similar to SIASTAT) */ /* See SIASTAT 21142/21143 bits */ #define CSR_PMAC_10TSTAT TULIP_CSR12 #define PMAC_SIASTAT_MASK (SIASTAT_LS100|SIASTAT_LS10| \ SIASTAT_APS|SIASTAT_TRF|SIASTAT_ANS| \ SIASTAT_LPN|SIASTAT_LPC) /* CSR13 - NWAY Reset Register */ #define CSR_PMAC_NWAYRESET TULIP_CSR13 /* See SIACONN 21142/21143 bits */ #define PMAC_SIACONN_MASK (SIACONN_SRL) #define PMAC_NWAYRESET_100TXRESET 0x00000002 /* 100base PMD reset */ /* CSR14 - 10base-T Control Port */ #define CSR_PMAC_10TCTL TULIP_CSR14 /* See SIATXRX 21142/21143 bits */ #define PMAC_SIATXRX_MASK (SIATXRX_LBK|SIATXRX_DREN|SIATXRX_TH| \ SIATXRX_ANE|SIATXRX_RSQ|SIATXRX_LTE| \ SIATXRX_THX|SIATXRX_TXF|SIATXRX_T4) /* CSR15 - Watchdog Timer Register */ /* MX98713: see 21140 CSR15 */ /* others: see SIAGEN 21142/21143 bits */ #define PMAC_SIAGEN_MASK (SIAGEN_JBD|SIAGEN_HUJ|SIAGEN_JCK| \ SIAGEN_RWD|SIAGEN_RWR) /* CSR16 - Test Operation Register (a.k.a. Magic Packet Register) */ #define CSR_PMAC_TOR TULIP_CSR16 #define PMAC_TOR_98713 0x0F370000 #define PMAC_TOR_98715 0x0B3C0000 /* CSR20 - NWAY Status */ #define CSR_PMAC_NWAYSTAT TULIP_CSR20 /* * Note: the MX98715A manual claims that EQTEST and PCITEST * must be set to 1 by software for normal operation, but * this does not appear to be necessary. This is probably * one of the things that frobbing the Test Operation Register * does. * * MX98715AEC uses this register for Auto Compensation. * CSR20<14> and CSR20<9> are called DS130 and DS120 */ #define PMAC_NWAYSTAT_DS120 0x00000200 /* Auto-compensation circ */ #define PMAC_NWAYSTAT_DS130 0x00004000 /* Auto-compensation circ */ #define PMAC_NWAYSTAT_EQTEST 0x00001000 /* EQ test */ #define PMAC_NWAYSTAT_PCITEST 0x00010000 /* PCI test */ #define PMAC_NWAYSTAT_10TXH 0x08000000 /* 10t accepted */ #define PMAC_NWAYSTAT_10TXF 0x10000000 /* 10t-fdx accepted */ #define PMAC_NWAYSTAT_100TXH 0x20000000 /* 100tx accepted */ #define PMAC_NWAYSTAT_100TXF 0x40000000 /* 100tx-fdx accepted */ #define PMAC_NWAYSTAT_T4 0x80000000 /* 100t4 accepted */ /* CSR21 - Flow Control Register */ #define CSR_PNICII_FLOWCTL TULIP_CSR21 #define PNICII_FLOWCTL_WKFCATEN 0x00000010 /* enable wake-up frame catenation feature */ #define PNICII_FLOWCTL_NFCE 0x00000020 /* accept flow control result from NWay */ #define PNICII_FLOWCTL_FCTH0 0x00000040 /* rx flow control thresh 0 */ #define PNICII_FLOWCTL_FCTH1 0x00000080 /* rx flow control thresh 1 */ #define PNICII_FLOWCTL_REJECTFC 0x00000100 /* abort rx flow control */ #define PNICII_FLOWCTL_STOPTX 0x00000200 /* tx flow stopped */ #define PNICII_FLOWCTL_RUFCEN 0x00000400 /* send flow control when RU interrupt occurs */ #define PNICII_FLOWCTL_RXFCEN 0x00000800 /* rx flow control enable */ #define PNICII_FLOWCTL_TXFCEN 0x00001000 /* tx flow control enable */ #define PNICII_FLOWCTL_RESTOP 0x00002000 /* restop mode */ #define PNICII_FLOWCTL_RESTART 0x00004000 /* restart mode */ #define PNICII_FLOWCTL_TEST 0x00008000 /* test flow control timer */ #define PNICII_FLOWCTL_TMVAL 0xffff0000 /* timer value in flow control frame */ #define PNICII_FLOWCTL_TH_512 (PNICII_FLOWCTL_FCTH0|PNICII_FLOWCTL_FCTH1) #define PNICII_FLOWCTL_TH_256 (PNICII_FLOWCTL_FCTH1) #define PNICII_FLOWCTL_TH_128 (PNICII_FLOWCTL_FCTH0) #define PNICII_FLOWCTL_TH_OVFLW (0) /* CSR22 - MAC ID Byte 3-0 Register */ #define CSR_PNICII_MACID0 TULIP_CSR22 #define PNICII_MACID_1 0 /* shift */ #define PNICII_MACID_0 8 /* shift */ #define PNICII_MACID_3 16 /* shift */ #define PNICII_MACID_2 24 /* shift */ /* CSR23 - Magic ID Byte 5,4/MACID Byte 5,4 Register */ #define PNICII_MACID_5 0 /* shift */ #define PNICII_MACID_4 8 /* shift */ #define PNICII_MAGID_5 16 /* shift */ #define PNICII_MAGIC_4 24 /* shift */ /* CSR24 - Magic ID Byte 3-0 Register */ #define PNICII_MAGID_1 0 /* shift */ #define PNICII_MAGID_0 8 /* shift */ #define PNICII_MAGID_3 16 /* shift */ #define PNICII_MAGID_2 24 /* shift */ /* CSR25 - CSR28 - Filter Byte Mask Registers */ #define CSR_PNICII_MASK0 TULIP_CSR25 #define CSR_PNICII_MASK1 TULIP_CSR26 #define CSR_PNICII_MASK2 TULIP_CSR27 #define CSR_PNICII_MASK3 TULIP_CSR28 /* CSR29 - Filter Offset Register */ #define CSR_PNICII_FILOFF TULIP_CSR29 #define PNICII_FILOFF_PAT0 0x0000007f /* pattern 0 offset */ #define PNICII_FILOFF_EN0 0x00000080 /* enable pattern 0 */ #define PNICII_FILOFF_PAT1 0x00007f00 /* pattern 1 offset */ #define PNICII_FILOFF_EN1 0x00008000 /* enable pattern 1 */ #define PNICII_FILOFF_PAT2 0x007f0000 /* pattern 2 offset */ #define PNICII_FILOFF_EN2 0x00800000 /* enable pattern 2 */ #define PNICII_FILOFF_PAT3 0x7f000000 /* pattern 3 offset */ #define PNICII_FILOFF_EN3 0x80000000 /* enable pattern 3 */ /* CSR30 - Filter 1 and 0 CRC-16 Register */ #define CSR_PNICII_FIL01 TULIP_CSR30 #define PNICII_FIL01_CRC0 0x0000ffff /* CRC-16 of pattern 0 */ #define PNICII_FIL01_CRC1 0xffff0000 /* CRC-16 of pattern 1 */ /* CSR31 = Filter 3 and 2 CRC-16 Register */ #define CSR_PNICII_FIL23 TULIP_CSR31 #define PNICII_FIL23_CRC2 0x0000ffff /* CRC-16 of pattern 2 */ #define PNICII_FIL23_CRC3 0xffff0000 /* CRC-16 of pattern 3 */ /* * Winbond 89C840F registers. */ /* CSR12 - Current Receive Descriptor Register */ #define CSR_WINB_CRDAR TULIP_CSR12 /* CSR13 - Current Receive Buffer Register */ #define CSR_WINB_CCRBAR TULIP_CSR13 /* CSR14 - Multicast Address Register 0 */ #define CSR_WINB_CMA0 TULIP_CSR14 /* CSR15 - Multicast Address Register 1 */ #define CSR_WINB_CMA1 TULIP_CSR15 /* CSR16 - Physical Address Register 0 */ #define CSR_WINB_CPA0 TULIP_CSR16 /* CSR17 - Physical Address Register 1 */ #define CSR_WINB_CPA1 TULIP_CSR17 /* CSR18 - Boot ROM Size Register */ #define CSR_WINB_CBRCR TULIP_CSR18 #define WINB_CBRCR_NONE 0x00000000 /* no boot rom */ /* 0x00000001 also no boot rom */ #define WINB_CBRCR_8K 0x00000002 /* 8k */ #define WINB_CBRCR_16K 0x00000003 /* 16k */ #define WINB_CBRCR_32K 0x00000004 /* 32k */ #define WINB_CBRCR_64K 0x00000005 /* 64k */ #define WINB_CBRCR_128K 0x00000006 /* 128k */ #define WINB_CBRCR_256K 0x00000007 /* CSR19 - Current Transmit Descriptor Register */ #define CSR_WINB_CTDAR TULIP_CSR19 /* CSR20 - Current Transmit Buffer Register */ #define CSR_WINB_CTBAR TULIP_CSR20 /* * ADMtek AL981 registers * * We define these as strict byte offsets into PCI space, since * not all of them have consistent access rules. */ /* CSR13 - Wake-up Control/Status Register */ #define CSR_ADM_WCSR 0x68 #define ADM_WCSR_LSC 0x00000001 /* link status changed */ #define ADM_WCSR_MPR 0x00000002 /* magic packet received */ #define ADM_WCSR_WFR 0x00000004 /* wake up frame received */ #define ADM_WCSR_LSCE 0x00000100 /* link status changed en. */ #define ADM_WCSR_MPRE 0x00000200 /* magic packet receive en. */ #define ADM_WCSR_WFRE 0x00000400 /* wake up frame receive en. */ #define ADM_WCSR_LINKON 0x00010000 /* link-on detect en. */ #define ADM_WCSR_LINKOFF 0x00020000 /* link-off detect en. */ #define ADM_WCSR_WP5E 0x02000000 /* wake up pat. 5 en. */ #define ADM_WCSR_WP4E 0x04000000 /* wake up pat. 4 en. */ #define ADM_WCSR_WP3E 0x08000000 /* wake up pat. 3 en. */ #define ADM_WCSR_WP2E 0x10000000 /* wake up pat. 2 en. */ #define ADM_WCSR_WP1E 0x20000000 /* wake up pat. 1 en. */ #define ADM_WCSR_CRCT 0x40000000 /* CRC-16 type: 0 == 0000 initial 1 == ffff initial */ /* CSR14 - Wake-up Pattern Data Register */ #define CSR_ADM_WPDR 0x70 /* * 25 consecutive longword writes are issued to WPDR to * program the wake-up pattern filter. The data written * is as follows: * * XXX */ /* CSR15 - see 21140 CSR15 (Watchdog Timer) */ /* CSR16 - Assistant CSR5 (Status Register 2) */ #define CSR_ADM_ASR 0x80 /* 0 - 14: same as CSR5 */ #define ADM_ASR_AAISS 0x00080000 /* added abnormal int. sum. */ #define ADM_ASR_ANISS 0x00010000 /* added normal int. sum. */ /* XXX Receive state */ /* XXX Transmit state */ #define ADM_ASR_BET 0x03800000 /* bus error type */ #define ADM_ASR_BET_PERR 0x00000000 /* parity error */ #define ADM_ASR_BET_MABT 0x00800000 /* master abort */ #define ADM_ASR_BET_TABT 0x01000000 /* target abort */ #define ADM_ASR_PFR 0x04000000 /* PAUSE frame received */ #define ADM_ASR_TDIS 0x10000000 /* transmit def. int. status */ #define ADM_ASR_XIS 0x20000000 /* xcvr int. status */ #define ADM_ASR_REIS 0x40000000 /* receive early int. status */ #define ADM_ASR_TEIS 0x80000000 /* transmit early int. status */ /* CSR17 - Assistant CSR7 (Interrupt Enable Register 2) */ #define CSR_ADM_AIE 0x84 /* See CSR16 for valid bits */ /* CSR18 - Command Register */ #define CSR_ADM_CR 0x88 #define ADM_CR_ATUR 0x00000001 /* auto. tx underrun recover */ #define ADM_CR_SINT 0x00000002 /* software interrupt */ #define ADM_CR_DRT 0x0000000c /* drain receive threshold */ #define ADM_CR_DRT_8LW 0x00000000 /* 8 longwords */ #define ADM_CR_DRT_16LW 0x00000004 /* 16 longwords */ #define ADM_CR_DRT_SF 0x00000008 /* store-and-forward */ #define ADM_CR_RTE 0x00000010 /* receive threshold enable */ #define ADM_CR_PAUSE 0x00000020 /* enable PAUSE function */ #define ADM_CR_RWP 0x00000040 /* reset wake-up pattern data register pointer */ /* 16 - 31 are automatically recalled from the EEPROM */ #define ADM_CR_WOL 0x00040000 /* wake-on-lan enable */ #define ADM_CR_PM 0x00080000 /* power management enable */ #define ADM_CR_RFS 0x00600000 /* Receive FIFO size */ #define ADM_CR_RFS_1K 0x00600000 /* 1K FIFO */ #define ADM_CR_RFS_2K 0x00400000 /* 2K FIFO */ #define ADM_CR_LEDMODE 0x00800000 /* LED mode */ #define ADM_CR_AUXCL 0x30000000 /* aux current load */ #define ADM_CR_D3CS 0x80000000 /* D3 cold wake up enable */ /* CSR19 - PCI bus performance counter */ #define CSR_ADM_PCIC 0x8c #define ADM_PCIC_DWCNT 0x000000ff /* double-word count of last bus-master transaction */ #define ADM_PCIC_CLKCNT 0xffff0000 /* number of PCI clocks between read request and access completed */ /* CSR20 - Power Management Control/Status Register */ #define CSR_ADM_PMCSR 0x90 /* * This register is also mapped into the PCI configuration * space as the PMCSR. */ /* CSR23 - Transmit Burst Count/Time Out Register */ #define CSR_ADM_TXBR 0x9c #define ADM_TXBR_TTO 0x00000fff /* transmit timeout */ #define ADM_TXBR_TBCNT 0x001f0000 /* transmit burst count */ /* CSR24 - Flash ROM Port Register */ #define CSR_ADM_FROM 0xa0 #define ADM_FROM_DATA 0x000000ff /* data to/from Flash */ #define ADM_FROM_ADDR 0x01ffff00 /* Flash address */ #define ADM_FROM_ADDR_SHIFT 8 #define ADM_FROM_WEN 0x04000000 /* write enable */ #define ADM_FROM_REN 0x08000000 /* read enable */ #define ADM_FROM_bra16on 0x80000000 /* pin 87 is brA16, else pin 87 is fd/col LED pin */ /* CSR25 - Physical Address Register 0 */ #define CSR_ADM_PAR0 0xa4 /* CSR26 - Physical Address Register 1 */ #define CSR_ADM_PAR1 0xa8 /* CSR27 - Multicast Address Register 0 */ #define CSR_ADM_MAR0 0xac /* CSR28 - Multicast Address Register 1 */ #define CSR_ADM_MAR1 0xb0 /* Internal PHY registers are mapped here (lower 16 bits valid) */ #define CSR_ADM_BMCR 0xb4 #define CSR_ADM_BMSR 0xb8 #define CSR_ADM_PHYIDR1 0xbc #define CSR_ADM_PHYIDR2 0xc0 #define CSR_ADM_ANAR 0xc4 #define CSR_ADM_ANLPAR 0xc8 #define CSR_ADM_ANER 0xcc /* XCVR Mode Control Register */ #define CSR_ADM_XMC 0xd0 #define ADM_XMC_LD 0x00000800 /* long distance mode (low squelch enable) */ /* XCVR Configuration Information and Interrupt Status Register */ #define CSR_ADM_XCIIS 0xd4 #define ADM_XCIIS_REF 0x0001 /* 64 error packets received */ #define ADM_XCIIS_ANPR 0x0002 /* autoneg page received */ #define ADM_XCIIS_PDF 0x0004 /* parallel detection fault */ #define ADM_XCIIS_ANAR 0x0008 /* autoneg ACK */ #define ADM_XCIIS_LS 0x0010 /* link status (1 == fail) */ #define ADM_XCIIS_RFD 0x0020 /* remote fault */ #define ADM_XCIIS_ANC 0x0040 /* autoneg completed */ #define ADM_XCIIS_PAUSE 0x0080 /* PAUSE enabled */ #define ADM_XCIIS_DUPLEX 0x0100 /* full duplex */ #define ADM_XCIIS_SPEED 0x0200 /* 100Mb/s */ /* XCVR Interrupt Enable Register */ #define CSR_ADM_XIE 0xd8 /* Bits are as for XCIIS */ /* XCVR 100baseTX PHY Control/Status Register */ #define CSR_ADM_100CTR 0xdc #define ADM_100CTR_DISCRM 0x0001 /* disable scrambler */ #define ADM_100CTR_DISMLT 0x0002 /* disable MLT3 ENDEC */ #define ADM_100CTR_CMODE 0x001c /* current operating mode */ #define ADM_100CTR_CMODE_AUTO 0x0000 /* in autoneg */ #define ADM_100CTR_CMODE_10 0x0004 /* 10baseT */ #define ADM_100CTR_CMODE_100 0x0008 /* 100baseTX */ /* 0x000c reserved */ /* 0x0010 reserved */ #define ADM_100CTR_CMODE_10FD 0x0014 /* 10baseT-FDX */ #define ADM_100CTR_CMODE_100FD 0x0018 /* 100baseTX-FDX */ #define ADM_100CTR_CMODE_ISO 0x001c /* isolated */ #define ADM_100CTR_ISOTX 0x0020 /* transmit isolation */ #define ADM_100CTR_ENRZI 0x0080 /* enable NRZ <> NRZI conv. */ #define ADM_100CTR_ENDCR 0x0100 /* enable DC restoration */ #define ADM_100CTR_ENRLB 0x0200 /* enable remote loopback */ #define ADM_100CTR_RXVPP 0x0800 /* peak Rx voltage: 0 == 1.0 VPP 1 == 1.4 VPP */ #define ADM_100CTR_ANC 0x1000 /* autoneg completed */ #define ADM_100CTR_DISRER 0x2000 /* disable Rx error counter */ /* Operation Mode Register (AN983) */ #define CSR_ADM983_OPMODE 0xfc #define ADM983_OPMODE_SPEED 0x80000000 /* 1 == 100, 0 == 10 */ #define ADM983_OPMODE_FD 0x40000000 /* 1 == fd, 0 == hd */ #define ADM983_OPMODE_LINK 0x20000000 /* 1 == link, 0 == no link */ #define ADM983_OPMODE_EERLOD 0x04000000 /* reload from EEPROM */ #define ADM983_OPMODE_SingleChip 0x00000007 /* single-chip mode */ #define ADM983_OPMODE_MacOnly 0x00000004 /* MAC-only mode */ /* * Xircom X3201-3 registers */ /* Power Management Register */ #define CSR_X3201_PMR TULIP_CSR16 #define X3201_PMR_EDINT 0x0000000f /* energy detect interval */ #define X3201_PMR_EDEN 0x00000100 /* energy detect enable */ #define X3201_PMR_MPEN 0x00000200 /* magic packet enable */ #define X3201_PMR_WOLEN 0x00000400 /* Wake On Lan enable */ #define X3201_PMR_PMGP0EN 0x00001000 /* GP0 change enable */ #define X3201_PMR_PMLCEN 0x00002000 /* link change enable */ #define X3201_PMR_WOLTMEN 0x00008000 /* WOL template mem enable */ #define X3201_PMR_EP 0x00010000 /* energy present */ #define X3201_PMR_LP 0x00200000 /* link present */ #define X3201_PMR_EDES 0x01000000 /* ED event status */ #define X3201_PMR_MPES 0x02000000 /* MP event status */ #define X3201_PMR_WOLES 0x04000000 /* WOL event status */ #define X3201_PMR_WOLPS 0x08000000 /* WOL process status */ #define X3201_PMR_GP0ES 0x10000000 /* GP0 event status */ #define X3201_PMR_LCES 0x20000000 /* LC event status */ /* * Davicom DM9102 registers. */ /* PHY Status Register */ #define CSR_DM_PHYSTAT TULIP_CSR12 #define DM_PHYSTAT_10 0x00000001 /* 10Mb/s */ #define DM_PHYSTAT_100 0x00000002 /* 100Mb/s */ #define DM_PHYSTAT_FDX 0x00000004 /* full-duplex */ #define DM_PHYSTAT_LINK 0x00000008 /* link up */ #define DM_PHYSTAT_RXLOCK 0x00000010 /* RX-lock */ #define DM_PHYSTAT_SIGNAL 0x00000020 /* signal detection */ #define DM_PHYSTAT_UTPSIG 0x00000040 /* UTP SIG */ #define DM_PHYSTAT_GPED 0x00000080 /* general PHY reset control */ #define DM_PHYSTAT_GEPC 0x00000100 /* GPED bits control */ /* Sample Frame Access Register */ #define CSR_DM_SFAR TULIP_CSR13 /* Sample Frame Data Register */ #define CSR_DM_SFDR TULIP_CSR14 /* See 21143 SIAGEN register */ /* * ASIX AX88140A and AX88141 registers. */ /* CSR13 - Filtering Index */ #define CSR_AX_FILTIDX TULIP_CSR13 /* CSR14 - Filtering data */ #define CSR_AX_FILTDATA TULIP_CSR14 /* Filtering Index values */ #define AX_FILTIDX_PAR0 0x00000000 #define AX_FILTIDX_PAR1 0x00000001 #define AX_FILTIDX_MAR0 0x00000002 #define AX_FILTIDX_MAR1 0x00000003 #endif /* _DEV_IC_TULIPREG_H_ */ gxemul-0.6.1/src/include/thirdparty/if_pcnreg.h000644 001750 001750 00000005245 13402411502 021744 0ustar00debugdebug000000 000000 /* GXemul: $Id: if_pcnreg.h,v 1.1 2006-07-26 07:42:03 debug Exp $ */ /* $NetBSD: if_pcnreg.h,v 1.3 2002/09/04 01:36:07 thorpej Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _DEV_PCI_IF_PCNREG_H_ #define _DEV_PCI_IF_PCNREG_H_ /* * Register definitions for the AMD PCnet-PCI series of Ethernet * chips. * * These are only the registers that we access directly from PCI * space. Everything else (accessed via the RAP + RDP/BDP) is * defined in . */ /* * PCI configuration space. */ #define PCN_PCI_CBIO (PCI_MAPREG_START + 0x00) #define PCN_PCI_CBMEM (PCI_MAPREG_START + 0x04) /* * I/O map in Word I/O mode. */ #define PCN16_APROM 0x00 #define PCN16_RDP 0x10 #define PCN16_RAP 0x12 #define PCN16_RESET 0x14 #define PCN16_BDP 0x16 /* * I/O map in DWord I/O mode. */ #define PCN32_APROM 0x00 #define PCN32_RDP 0x10 #define PCN32_RAP 0x14 #define PCN32_RESET 0x18 #define PCN32_BDP 0x1c #endif /* _DEV_PCI_IF_PCNREG_H_ */ gxemul-0.6.1/src/include/thirdparty/sccreg.h000644 001750 001750 00000033330 13402411502 021252 0ustar00debugdebug000000 000000 #ifndef SCCREG_H #define SCCREG_H /* $NetBSD: sccreg.h,v 1.6 1999/04/24 08:01:07 simonb Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)sccreg.h 8.1 (Berkeley) 6/10/93 */ /* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ /* * Definitions for Intel 82530 serial communications chip. * Each chip is a dual uart with the A channels used for the keyboard and * mouse with the B channel(s) for comm ports with modem control. Since * some registers are used for the other channel, the following macros * are used to access the register ports. */ typedef struct scc_regmap { /* Channel B is first, then A */ struct { char scc_pad0; volatile u_char scc_command; /* reg select */ char scc_pad1[3]; volatile u_char scc_data; /* Rx/Tx buffer */ char scc_pad3[2]; } scc_channel[2]; } scc_regmap_t; #define SCC_CHANNEL_A 1 #define SCC_CHANNEL_B 0 #define SCC_INIT_REG(scc,chan) { \ char tmp; \ tmp = (scc)->scc_channel[(chan)].scc_command; \ tmp = (scc)->scc_channel[(chan)].scc_command; \ } #define SCC_READ_REG(scc,chan,reg,val) { \ (scc)->scc_channel[(chan)].scc_command = (reg); \ (val) = (scc)->scc_channel[(chan)].scc_command; \ } #define SCC_READ_REG_ZERO(scc,chan,val) { \ (val) = (scc)->scc_channel[(chan)].scc_command; \ } #define SCC_WRITE_REG(scc,chan,reg,val) { \ (scc)->scc_channel[(chan)].scc_command = (reg); \ (scc)->scc_channel[(chan)].scc_command = (val); \ } #define SCC_WRITE_REG_ZERO(scc,chan,val) { \ (scc)->scc_channel[(chan)].scc_command = (val); \ } #define SCC_READ_DATA(scc,chan,val) { \ (val) = (scc)->scc_channel[(chan)].scc_data; \ } #define SCC_WRITE_DATA(scc,chan,val) { \ (scc)->scc_channel[(chan)].scc_data = (val); \ } #define SCC_RR0 0 /* status register */ #define SCC_RR1 1 /* special receive conditions */ #define SCC_RR2 2 /* (modified) interrupt vector */ #define SCC_RR3 3 /* interrupts pending (cha A only) */ #define SCC_RR8 8 /* recv buffer (alias for data) */ #define SCC_RR10 10 /* sdlc status */ #define SCC_RR12 12 /* BRG constant, low part */ #define SCC_RR13 13 /* BRG constant, high part */ #define SCC_RR15 15 /* interrupts currently enabled */ #define SCC_WR0 0 /* reg select, and commands */ #define SCC_WR1 1 /* interrupt and DMA enables */ #define SCC_WR2 2 /* interrupt vector */ #define SCC_WR3 3 /* receiver params and enables */ #define SCC_WR4 4 /* clock/char/parity params */ #define SCC_WR5 5 /* xmit params and enables */ #define SCC_WR6 6 /* synchr SYNCH/address */ #define SCC_WR7 7 /* synchr SYNCH/flag */ #define SCC_WR8 8 /* xmit buffer (alias for data) */ #define SCC_WR9 9 /* vectoring and resets */ #define SCC_WR10 10 /* synchr params */ #define SCC_WR11 11 /* clocking definitions */ #define SCC_WR12 12 /* BRG constant, low part */ #define SCC_WR13 13 /* BRG constant, high part */ #define SCC_WR14 14 /* BRG enables and commands */ #define SCC_WR15 15 /* interrupt enables */ /* * Read registers defines */ #define SCC_RR0_BREAK 0x80 /* break detected (rings twice), or */ #define SCC_RR0_ABORT 0x80 /* abort (synchr) */ #define SCC_RR0_TX_UNDERRUN 0x40 /* xmit buffer empty/end of message */ #define SCC_RR0_CTS 0x20 /* clear-to-send pin active (sampled only on intr and after RESI cmd */ #define SCC_RR0_SYNCH 0x10 /* SYNCH found/still hunting */ #define SCC_RR0_DCD 0x08 /* carrier-detect (same as CTS) */ #define SCC_RR0_TX_EMPTY 0x04 /* xmit buffer empty */ #define SCC_RR0_ZERO_COUNT 0x02 /* ? */ #define SCC_RR0_RX_AVAIL 0x01 /* recv fifo not empty */ #define SCC_RR1_EOF 0x80 /* end-of-frame, SDLC mode */ #define SCC_RR1_CRC_ERR 0x40 /* incorrect CRC or.. */ #define SCC_RR1_FRAME_ERR 0x40 /* ..bad frame */ #define SCC_RR1_RX_OVERRUN 0x20 /* rcv fifo overflow */ #define SCC_RR1_PARITY_ERR 0x10 /* incorrect parity in data */ #define SCC_RR1_RESIDUE0 0x08 #define SCC_RR1_RESIDUE1 0x04 #define SCC_RR1_RESIDUE2 0x02 #define SCC_RR1_ALL_SENT 0x01 /* RR2 contains the interrupt vector unmodified (channel A) or modified as follows (channel B, if vector-include-status) */ #define SCC_RR2_STATUS(val) ((val)&0xf) #define SCC_RR2_B_XMIT_DONE 0x0 #define SCC_RR2_B_EXT_STATUS 0x2 #define SCC_RR2_B_RECV_DONE 0x4 #define SCC_RR2_B_RECV_SPECIAL 0x6 #define SCC_RR2_A_XMIT_DONE 0x8 #define SCC_RR2_A_EXT_STATUS 0xa #define SCC_RR2_A_RECV_DONE 0xc #define SCC_RR2_A_RECV_SPECIAL 0xe /* Interrupts pending, to be read from channel A only (B raz) */ #define SCC_RR3_zero 0xc0 #define SCC_RR3_RX_IP_A 0x20 #define SCC_RR3_TX_IP_A 0x10 #define SCC_RR3_EXT_IP_A 0x08 #define SCC_RR3_RX_IP_B 0x04 #define SCC_RR3_TX_IP_B 0x02 #define SCC_RR3_EXT_IP_B 0x01 /* RR8 is the receive data buffer, a 3 deep FIFO */ #define SCC_RECV_BUFFER SCC_RR8 #define SCC_RECV_FIFO_DEEP 3 #define SCC_RR10_1CLKS 0x80 #define SCC_RR10_2CLKS 0x40 #define SCC_RR10_zero 0x2d #define SCC_RR10_LOOP_SND 0x10 #define SCC_RR10_ON_LOOP 0x02 /* RR12/RR13 hold the timing base, upper byte in RR13 */ #define SCC_GET_TIMING_BASE(scc,chan,val) { \ char tmp; \ SCC_READ_REG(scc,chan,SCC_RR12,val);\ SCC_READ_REG(scc,chan,SCC_RR13,tmp);\ (val) = ((val)<<8)|(tmp&0xff);\ } #define SCC_RR15_BREAK_IE 0x80 #define SCC_RR15_TX_UNDERRUN_IE 0x40 #define SCC_RR15_CTS_IE 0x20 #define SCC_RR15_SYNCH_IE 0x10 #define SCC_RR15_DCD_IE 0x08 #define SCC_RR15_zero 0x05 #define SCC_RR15_ZERO_COUNT_IE 0x02 /* * Write registers defines */ /* WR0 is used for commands too */ #define SCC_RESET_TXURUN_LATCH 0xc0 #define SCC_RESET_TX_CRC 0x80 #define SCC_RESET_RX_CRC 0x40 #define SCC_RESET_HIGHEST_IUS 0x38 /* channel A only */ #define SCC_RESET_ERROR 0x30 #define SCC_RESET_TX_IP 0x28 #define SCC_IE_NEXT_CHAR 0x20 #define SCC_SEND_SDLC_ABORT 0x18 #define SCC_RESET_EXT_IP 0x10 #define SCC_WR1_DMA_ENABLE 0x80 /* dma control */ #define SCC_WR1_DMA_MODE 0x40 /* drive ~req for DMA controller */ #define SCC_WR1_DMA_RECV_DATA 0x20 /* from wire to host memory */ /* interrupt enable/conditions */ #define SCC_WR1_RXI_SPECIAL_O 0x18 /* on special only */ #define SCC_WR1_RXI_ALL_CHAR 0x10 /* on each char, or special */ #define SCC_WR1_RXI_FIRST_CHAR 0x08 /* on first char, or special */ #define SCC_WR1_RXI_DISABLE 0x00 /* never on recv */ #define SCC_WR1_PARITY_IE 0x04 /* on parity errors */ #define SCC_WR1_TX_IE 0x02 #define SCC_WR1_EXT_IE 0x01 /* WR2 is common and contains the interrupt vector (high nibble) */ #define SCC_WR3_RX_8_BITS 0xc0 #define SCC_WR3_RX_6_BITS 0x80 #define SCC_WR3_RX_7_BITS 0x40 #define SCC_WR3_RX_5_BITS 0x00 #define SCC_WR3_AUTO_ENABLE 0x20 #define SCC_WR3_HUNT_MODE 0x10 #define SCC_WR3_RX_CRC_ENABLE 0x08 #define SCC_WR3_SDLC_SRCH 0x04 #define SCC_WR3_INHIBIT_SYNCH 0x02 #define SCC_WR3_RX_ENABLE 0x01 /* Should be re-written after reset */ #define SCC_WR4_CLK_x64 0xc0 /* clock divide factor */ #define SCC_WR4_CLK_x32 0x80 #define SCC_WR4_CLK_x16 0x40 #define SCC_WR4_CLK_x1 0x00 #define SCC_WR4_EXT_SYNCH_MODE 0x30 /* synch modes */ #define SCC_WR4_SDLC_MODE 0x20 #define SCC_WR4_16BIT_SYNCH 0x10 #define SCC_WR4_8BIT_SYNCH 0x00 #define SCC_WR4_2_STOP 0x0c /* asynch modes */ #define SCC_WR4_1_5_STOP 0x08 #define SCC_WR4_1_STOP 0x04 #define SCC_WR4_SYNCH_MODE 0x00 #define SCC_WR4_EVEN_PARITY 0x02 #define SCC_WR4_PARITY_ENABLE 0x01 #define SCC_WR5_DTR 0x80 /* drive DTR pin */ #define SCC_WR5_TX_8_BITS 0x60 #define SCC_WR5_TX_6_BITS 0x40 #define SCC_WR5_TX_7_BITS 0x20 #define SCC_WR5_TX_5_BITS 0x00 #define SCC_WR5_SEND_BREAK 0x10 #define SCC_WR5_TX_ENABLE 0x08 #define SCC_WR5_CRC_16 0x04 /* CRC if non zero, .. */ #define SCC_WR5_SDLC 0x00 /* ..SDLC otherwise */ #define SCC_WR5_RTS 0x02 /* drive RTS pin */ #define SCC_WR5_TX_CRC_ENABLE 0x01 /* Registers WR6 and WR7 are for synch modes data, with among other things: */ #define SCC_WR6_BISYNCH_12 0x0f #define SCC_WR6_SDLC_RANGE_MASK 0x0f #define SCC_WR7_SDLC_FLAG 0x7e /* WR8 is the transmit data buffer (no FIFO) */ #define SCC_XMT_BUFFER SCC_WR8 #define SCC_WR9_HW_RESET 0xc0 /* force hardware reset */ #define SCC_WR9_RESET_CHA_A 0x80 #define SCC_WR9_RESET_CHA_B 0x40 #define SCC_WR9_NON_VECTORED 0x20 /* mbz for Zilog chip */ #define SCC_WR9_STATUS_HIGH 0x10 #define SCC_WR9_MASTER_IE 0x08 #define SCC_WR9_DLC 0x04 /* disable-lower-chain */ #define SCC_WR9_NV 0x02 /* no vector */ #define SCC_WR9_VIS 0x01 /* vector-includes-status */ #define SCC_WR10_CRC_PRESET 0x80 #define SCC_WR10_FM0 0x60 #define SCC_WR10_FM1 0x40 #define SCC_WR10_NRZI 0x20 #define SCC_WR10_NRZ 0x00 #define SCC_WR10_ACTIVE_ON_POLL 0x10 #define SCC_WR10_MARK_IDLE 0x08 /* flag if zero */ #define SCC_WR10_ABORT_ON_URUN 0x04 /* flag if zero */ #define SCC_WR10_LOOP_MODE 0x02 #define SCC_WR10_6BIT_SYNCH 0x01 #define SCC_WR10_8BIT_SYNCH 0x00 #define SCC_WR11_RTxC_XTAL 0x80 /* RTxC pin is input (ext oscill) */ #define SCC_WR11_RCLK_DPLL 0x60 /* clock received data on dpll */ #define SCC_WR11_RCLK_BAUDR 0x40 /* .. on BRG */ #define SCC_WR11_RCLK_TRc_PIN 0x20 /* .. on TRxC pin */ #define SCC_WR11_RCLK_RTc_PIN 0x00 /* .. on RTxC pin */ #define SCC_WR11_XTLK_DPLL 0x18 #define SCC_WR11_XTLK_BAUDR 0x10 #define SCC_WR11_XTLK_TRc_PIN 0x08 #define SCC_WR11_XTLK_RTc_PIN 0x00 #define SCC_WR11_TRc_OUT 0x04 /* drive TRxC pin as output from..*/ #define SCC_WR11_TRcOUT_DPLL 0x03 /* .. the dpll */ #define SCC_WR11_TRcOUT_BAUDR 0x02 /* .. the BRG */ #define SCC_WR11_TRcOUT_XMTCLK 0x01 /* .. the xmit clock */ #define SCC_WR11_TRcOUT_XTAL 0x00 /* .. the external oscillator */ /* WR12/WR13 are for timing base preset */ #define SCC_SET_TIMING_BASE(scc,chan,val) { \ SCC_WRITE_REG(scc,chan,SCC_RR12,val);\ SCC_WRITE_REG(scc,chan,SCC_RR13,(val)>>8);\ } /* More commands in this register */ #define SCC_WR14_NRZI_MODE 0xe0 /* synch modulations */ #define SCC_WR14_FM_MODE 0xc0 #define SCC_WR14_RTc_SOURCE 0xa0 /* clock is from pin .. */ #define SCC_WR14_BAUDR_SOURCE 0x80 /* .. or internal BRG */ #define SCC_WR14_DISABLE_DPLL 0x60 #define SCC_WR14_RESET_CLKMISS 0x40 #define SCC_WR14_SEARCH_MODE 0x20 /* ..and more bitsy */ #define SCC_WR14_LOCAL_LOOPB 0x10 #define SCC_WR14_AUTO_ECHO 0x08 #define SCC_WR14_DTR_REQUEST 0x04 #define SCC_WR14_BAUDR_SRC 0x02 #define SCC_WR14_BAUDR_ENABLE 0x01 #define SCC_WR15_BREAK_IE 0x80 #define SCC_WR15_TX_UNDERRUN_IE 0x40 #define SCC_WR15_CTS_IE 0x20 #define SCC_WR15_SYNCHUNT_IE 0x10 #define SCC_WR15_DCD_IE 0x08 #define SCC_WR15_zero 0x05 #define SCC_WR15_ZERO_COUNT_IE 0x02 /* bits in dm lsr, copied from dmreg.h */ #define DML_DSR 0000400 /* data set ready, not a real DM bit */ #define DML_RNG 0000200 /* ring */ #define DML_CAR 0000100 /* carrier detect */ #define DML_CTS 0000040 /* clear to send */ #define DML_SR 0000020 /* secondary receive */ #define DML_ST 0000010 /* secondary transmit */ #define DML_RTS 0000004 /* request to send */ #define DML_DTR 0000002 /* data terminal ready */ #define DML_LE 0000001 /* line enable */ /* * Minor device numbers for scc. Weird because B channel comes * first and the A channels are wired for keyboard/mouse and the * B channels for the comm port(s). */ #define SCCCOMM2_PORT 0x0 #define SCCMOUSE_PORT 0x1 #define SCCCOMM3_PORT 0x2 #define SCCKBD_PORT 0x3 #endif /* SCCREG_H */ gxemul-0.6.1/src/include/thirdparty/errno_freebsd.h000644 001750 001750 00000020721 13402411502 022623 0ustar00debugdebug000000 000000 /*- * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)errno.h 8.5 (Berkeley) 1/21/94 * $FreeBSD: src/sys/sys/errno.h,v 1.28 2005/04/02 12:33:28 das Exp $ */ #ifndef _SYS_ERRNO_H_ #define _SYS_ERRNO_H_ #if 0 #ifndef _KERNEL #include __BEGIN_DECLS int * __error(void); __END_DECLS #define errno (* __error()) #endif #endif #define FREEBSD_EPERM 1 /* Operation not permitted */ #define FREEBSD_ENOENT 2 /* No such file or directory */ #define FREEBSD_ESRCH 3 /* No such process */ #define FREEBSD_EINTR 4 /* Interrupted system call */ #define FREEBSD_EIO 5 /* Input/output error */ #define FREEBSD_ENXIO 6 /* Device not configured */ #define FREEBSD_E2BIG 7 /* Argument list too long */ #define FREEBSD_ENOEXEC 8 /* Exec format error */ #define FREEBSD_EBADF 9 /* Bad file descriptor */ #define FREEBSD_ECHILD 10 /* No child processes */ #define FREEBSD_EDEADLK 11 /* Resource deadlock avoided */ /* 11 was EAGAIN */ #define FREEBSD_ENOMEM 12 /* Cannot allocate memory */ #define FREEBSD_EACCES 13 /* Permission denied */ #define FREEBSD_EFAULT 14 /* Bad address */ #ifndef _POSIX_SOURCE #define FREEBSD_ENOTBLK 15 /* Block device required */ #endif #define FREEBSD_EBUSY 16 /* Device busy */ #define FREEBSD_EEXIST 17 /* File exists */ #define FREEBSD_EXDEV 18 /* Cross-device link */ #define FREEBSD_ENODEV 19 /* Operation not supported by device */ #define FREEBSD_ENOTDIR 20 /* Not a directory */ #define FREEBSD_EISDIR 21 /* Is a directory */ #define FREEBSD_EINVAL 22 /* Invalid argument */ #define FREEBSD_ENFILE 23 /* Too many open files in system */ #define FREEBSD_EMFILE 24 /* Too many open files */ #define FREEBSD_ENOTTY 25 /* Inappropriate ioctl for device */ #ifndef _POSIX_SOURCE #define FREEBSD_ETXTBSY 26 /* Text file busy */ #endif #define FREEBSD_EFBIG 27 /* File too large */ #define FREEBSD_ENOSPC 28 /* No space left on device */ #define FREEBSD_ESPIPE 29 /* Illegal seek */ #define FREEBSD_EROFS 30 /* Read-only filesystem */ #define FREEBSD_EMLINK 31 /* Too many links */ #define FREEBSD_EPIPE 32 /* Broken pipe */ /* math software */ #define FREEBSD_EDOM 33 /* Numerical argument out of domain */ #define FREEBSD_ERANGE 34 /* Result too large */ /* non-blocking and interrupt i/o */ #define FREEBSD_EAGAIN 35 /* Resource temporarily unavailable */ #ifndef _POSIX_SOURCE #define FREEBSD_EWOULDBLOCK EAGAIN /* Operation would block */ #define FREEBSD_EINPROGRESS 36 /* Operation now in progress */ #define FREEBSD_EALREADY 37 /* Operation already in progress */ /* ipc/network software -- argument errors */ #define FREEBSD_ENOTSOCK 38 /* Socket operation on non-socket */ #define FREEBSD_EDESTADDRREQ 39 /* Destination address required */ #define FREEBSD_EMSGSIZE 40 /* Message too long */ #define FREEBSD_EPROTOTYPE 41 /* Protocol wrong type for socket */ #define FREEBSD_ENOPROTOOPT 42 /* Protocol not available */ #define FREEBSD_EPROTONOSUPPORT 43 /* Protocol not supported */ #define FREEBSD_ESOCKTNOSUPPORT 44 /* Socket type not supported */ #define FREEBSD_EOPNOTSUPP 45 /* Operation not supported */ #define FREEBSD_ENOTSUP EOPNOTSUPP /* Operation not supported */ #define FREEBSD_EPFNOSUPPORT 46 /* Protocol family not supported */ #define FREEBSD_EAFNOSUPPORT 47 /* Address family not supported by protocol family */ #define FREEBSD_EADDRINUSE 48 /* Address already in use */ #define FREEBSD_EADDRNOTAVAIL 49 /* Can't assign requested address */ /* ipc/network software -- operational errors */ #define FREEBSD_ENETDOWN 50 /* Network is down */ #define FREEBSD_ENETUNREACH 51 /* Network is unreachable */ #define FREEBSD_ENETRESET 52 /* Network dropped connection on reset */ #define FREEBSD_ECONNABORTED 53 /* Software caused connection abort */ #define FREEBSD_ECONNRESET 54 /* Connection reset by peer */ #define FREEBSD_ENOBUFS 55 /* No buffer space available */ #define FREEBSD_EISCONN 56 /* Socket is already connected */ #define FREEBSD_ENOTCONN 57 /* Socket is not connected */ #define FREEBSD_ESHUTDOWN 58 /* Can't send after socket shutdown */ #define FREEBSD_ETOOMANYREFS 59 /* Too many references: can't splice */ #define FREEBSD_ETIMEDOUT 60 /* Operation timed out */ #define FREEBSD_ECONNREFUSED 61 /* Connection refused */ #define FREEBSD_ELOOP 62 /* Too many levels of symbolic links */ #endif /* _POSIX_SOURCE */ #define FREEBSD_ENAMETOOLONG 63 /* File name too long */ /* should be rearranged */ #ifndef _POSIX_SOURCE #define FREEBSD_EHOSTDOWN 64 /* Host is down */ #define FREEBSD_EHOSTUNREACH 65 /* No route to host */ #endif /* _POSIX_SOURCE */ #define FREEBSD_ENOTEMPTY 66 /* Directory not empty */ /* quotas & mush */ #ifndef _POSIX_SOURCE #define FREEBSD_EPROCLIM 67 /* Too many processes */ #define FREEBSD_EUSERS 68 /* Too many users */ #define FREEBSD_EDQUOT 69 /* Disc quota exceeded */ /* Network File System */ #define FREEBSD_ESTALE 70 /* Stale NFS file handle */ #define FREEBSD_EREMOTE 71 /* Too many levels of remote in path */ #define FREEBSD_EBADRPC 72 /* RPC struct is bad */ #define FREEBSD_ERPCMISMATCH 73 /* RPC version wrong */ #define FREEBSD_EPROGUNAVAIL 74 /* RPC prog. not avail */ #define FREEBSD_EPROGMISMATCH 75 /* Program version wrong */ #define FREEBSD_EPROCUNAVAIL 76 /* Bad procedure for program */ #endif /* _POSIX_SOURCE */ #define FREEBSD_ENOLCK 77 /* No locks available */ #define FREEBSD_ENOSYS 78 /* Function not implemented */ #ifndef _POSIX_SOURCE #define FREEBSD_EFTYPE 79 /* Inappropriate file type or format */ #define FREEBSD_EAUTH 80 /* Authentication error */ #define FREEBSD_ENEEDAUTH 81 /* Need authenticator */ #define FREEBSD_EIDRM 82 /* Identifier removed */ #define FREEBSD_ENOMSG 83 /* No message of desired type */ #define FREEBSD_EOVERFLOW 84 /* Value too large to be stored in data type */ #define FREEBSD_ECANCELED 85 /* Operation canceled */ #define FREEBSD_EILSEQ 86 /* Illegal byte sequence */ #define FREEBSD_ENOATTR 87 /* Attribute not found */ #define FREEBSD_EDOOFUS 88 /* Programming error */ #endif /* _POSIX_SOURCE */ #define FREEBSD_EBADMSG 89 /* Bad message */ #define FREEBSD_EMULTIHOP 90 /* Multihop attempted */ #define FREEBSD_ENOLINK 91 /* Link has been severed */ #define FREEBSD_EPROTO 92 /* Protocol error */ #ifndef _POSIX_SOURCE #define FREEBSD_ELAST 92 /* Must be equal largest errno */ #endif /* _POSIX_SOURCE */ #ifdef _KERNEL /* pseudo-errors returned inside kernel to modify return to process */ #define FREEBSD_ERESTART (-1) /* restart syscall */ #define FREEBSD_EJUSTRETURN (-2) /* don't modify regs, just return */ #define FREEBSD_ENOIOCTL (-3) /* ioctl not handled by this layer */ #define FREEBSD_EDIRIOCTL (-4) /* do direct ioctl in GEOM */ #endif #endif gxemul-0.6.1/src/include/thirdparty/mvme_memcreg.h000644 001750 001750 00000006742 13402411502 022456 0ustar00debugdebug000000 000000 /* $OpenBSD: memcreg.h,v 1.3 2003/06/02 07:06:56 deraadt Exp $ */ /* * Copyright (c) 1995 Theo de Raadt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * the MEMC's registers are a subset of the MCECC chip */ struct memcreg { volatile u_char memc_chipid; volatile u_char xx0[3]; volatile u_char memc_chiprev; volatile u_char xx1[3]; volatile u_char memc_memconf; #define MEMC_MEMCONF_MSIZ 0x07 #define MEMC_MEMCONF_RTOB(x) ((4*1024*1024) << ((x) & MEMC_MEMCONF_MSIZ)) volatile u_char xx2[3]; volatile u_char memc_x0; volatile u_char xx3[3]; volatile u_char memc_x1; volatile u_char xx4[3]; volatile u_char memc_baseaddr; volatile u_char xx5[3]; volatile u_char memc_control; volatile u_char xx6[3]; volatile u_char memc_bclk; volatile u_char xx7[3]; /* the following registers only exist on the MCECC */ volatile u_char memc_datactl; volatile u_char xx8[3]; volatile u_char memc_scrubctl; volatile u_char xx9[3]; volatile u_char memc_scrubperh; volatile u_char xx10[3]; volatile u_char memc_scrubperl; volatile u_char xx11[3]; volatile u_char memc_chipprescale; volatile u_char xx12[3]; volatile u_char memc_scrubtime; volatile u_char xx13[3]; volatile u_char memc_scrubprescaleh; volatile u_char xx14[3]; volatile u_char memc_scrubprescalem; volatile u_char xx15[3]; volatile u_char memc_scrubprescalel; volatile u_char xx16[3]; volatile u_char memc_scrubtimeh; volatile u_char xx17[3]; volatile u_char memc_scrubtimel; volatile u_char xx18[3]; volatile u_char memc_scrubaddrhh; volatile u_char xx19[3]; volatile u_char memc_scrubaddrhm; volatile u_char xx20[3]; volatile u_char memc_scrubaddrlm; volatile u_char xx21[3]; volatile u_char memc_scrubaddrll; volatile u_char xx22[3]; volatile u_char memc_errlog; volatile u_char xx23[3]; volatile u_char memc_errloghh; volatile u_char xx24[3]; volatile u_char memc_errloghm; volatile u_char xx25[3]; volatile u_char memc_errloglm; volatile u_char xx26[3]; volatile u_char memc_errlogll; volatile u_char xx27[3]; volatile u_char memc_errsyndrome; volatile u_char xx28[3]; volatile u_char memc_defaults1; volatile u_char xx29[3]; volatile u_char memc_defaults2; volatile u_char xx30[3]; }; #define MEMC_CHIPID 0x80 #define MCECC_CHIPID 0x81 gxemul-0.6.1/src/include/thirdparty/sgi_arcbios.h000644 001750 001750 00000037057 13402411502 022302 0ustar00debugdebug000000 000000 /* This file has been modified from the NetBSD version, the additions are mostly guesses for 64-bit SGI stuff. */ #ifndef SGI_ARCBIOS_H #define SGI_ARCBIOS_H /* It's better to not #define sgimips here, and assume generic ARC instead */ #ifdef __attribute__ #undef __attribute__ #endif #ifdef __noreturn__ #undef __noreturn__ #endif #define __attribute__(x) /* */ #define __noreturn__ /* */ /* $NetBSD: arcbios.h,v 1.3 2001/12/06 14:59:02 rafal Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * The ARC BIOS (which is similar, but not 100% compatible with SGI ARCS) * specification can be found at: * * http://www.microsoft.com/hwdev/download/respec/riscspec.zip */ #define ARCBIOS_STDIN 0 #define ARCBIOS_STDOUT 1 #define ARCBIOS_PAGESIZE 4096 /* ARC BIOS status codes. */ #define ARCBIOS_ESUCCESS 0 /* Success */ #define ARCBIOS_E2BIG 1 /* argument list too long */ #define ARCBIOS_EACCES 2 /* permission denied */ #define ARCBIOS_EAGAIN 3 /* resource temporarily unavailable */ #define ARCBIOS_EBADF 4 /* bad file number */ #define ARCBIOS_EBUSY 5 /* device or resource busy */ #define ARCBIOS_EFAULT 6 /* bad address */ #define ARCBIOS_EINVAL 7 /* invalid argument */ #define ARCBIOS_EIO 8 /* I/O error */ #define ARCBIOS_EISDIR 9 /* is a directory */ #define ARCBIOS_EMFILE 10 /* too many open files */ #define ARCBIOS_EMLINK 11 /* too many links */ #define ARCBIOS_ENAMETOOLONG 12 /* file name too long */ #define ARCBIOS_ENODEV 13 /* no such device */ #define ARCBIOS_ENOENT 14 /* no such file or directory */ #define ARCBIOS_ENOEXEC 15 /* exec format error */ #define ARCBIOS_ENOMEM 16 /* out of memory */ #define ARCBIOS_ENOSPC 17 /* no space left on device */ #define ARCBIOS_ENOTDIR 18 /* not a directory */ #define ARCBIOS_ENOTTY 19 /* not a typewriter */ #define ARCBIOS_ENXIO 20 /* media not loaded */ #define ARCBIOS_EROFS 21 /* read-only file system */ #if defined(sgimips) #define ARCBIOS_EADDRNOTAVAIL 31 /* address not available */ #define ARCBIOS_ETIMEDOUT 32 /* operation timed out */ #define ARCBIOS_ECONNABORTED 33 /* connection aborted */ #define ARCBIOS_ENOCONNECT 34 /* not connected */ #endif /* sgimips */ /* * 4.2.2: System Parameter Block */ struct arcbios_spb { uint32_t SPBSignature; uint32_t SPBLength; uint16_t Version; uint16_t Revision; uint32_t RestartBlock; /* was void * in netbsd */ uint32_t DebugBlock; /* was void * */ uint32_t GEVector; /* was void * */ uint32_t UTLBMissVector; /* was void * */ uint32_t FirmwareVectorLength; uint32_t FirmwareVector; /* was void * */ uint32_t PrivateVectorLength; uint32_t PrivateVector; /* was void * */ uint32_t AdapterCount; uint32_t AdapterType; uint32_t AdapterVectorLength; uint32_t AdapterVector; /* was void * */ }; /* * arcbios_spb_64 is like arcbios_spb, but with 64-bit pointers. * Irix seems to want this. TODO: This is just a guess, based on the * usage of void * in the NetBSD version of arcbios_spb. * * Linux wants a 64-bit SPBSignature? */ struct arcbios_spb_64 { uint64_t SPBSignature; uint64_t SPBLength; uint16_t Version; uint16_t Revision; uint32_t dummy; uint64_t RestartBlock; /* was void * in netbsd */ uint64_t DebugBlock; /* was void * */ uint64_t GEVector; /* was void * */ uint64_t UTLBMissVector; /* was void * */ uint64_t FirmwareVectorLength; uint64_t FirmwareVector; /* was void * */ uint64_t PrivateVectorLength; uint64_t PrivateVector; /* was void * */ uint64_t AdapterCount; uint64_t AdapterType; uint64_t AdapterVectorLength; uint64_t AdapterVector; /* was void * */ }; #define ARCBIOS_SPB_SIGNATURE 0x53435241 /* A R C S */ #define ARCBIOS_SPB_SIGNATURE_1 0x41524353 /* S C R A */ /* * 4.2.5: System Configuration Data */ struct arcbios_component { uint32_t Class; uint32_t Type; uint32_t Flags; uint16_t Version; uint16_t Revision; uint32_t Key; uint32_t AffinityMask; uint32_t ConfigurationDataSize; uint32_t IdentifierLength; uint32_t Identifier; /* was: char * */ }; /* gxemul addition: guess for a 64-bit version of arcbios_component: */ struct arcbios_component64 { uint32_t Class; uint32_t Type; uint32_t Flags; uint16_t Version; uint16_t Revision; uint64_t Key; uint64_t AffinityMask; uint64_t ConfigurationDataSize; uint64_t IdentifierLength; uint64_t Identifier; /* was: char * */ }; /* * SGI ARCS likes to be `special', so it moved some of the class/type * numbers around from the ARC standard definitions. */ #if defined(sgimips) /* Component Class */ #define COMPONENT_CLASS_SystemClass 0 #define COMPONENT_CLASS_ProcessorClass 1 #define COMPONENT_CLASS_CacheClass 2 #define COMPONENT_CLASS_MemoryClass 3 #define COMPONENT_CLASS_AdapterClass 4 #define COMPONENT_CLASS_ControllerClass 5 #define COMPONENT_CLASS_PeripheralClass 6 #else /* Component Class */ #define COMPONENT_CLASS_SystemClass 0 #define COMPONENT_CLASS_ProcessorClass 1 #define COMPONENT_CLASS_CacheClass 2 #define COMPONENT_CLASS_AdapterClass 3 #define COMPONENT_CLASS_ControllerClass 4 #define COMPONENT_CLASS_PeripheralClass 5 #define COMPONENT_CLASS_MemoryClass 6 #endif /* Component Types */ #if defined(sgimips) /* System Class */ #define COMPONENT_TYPE_ARC 0 /* Processor Class */ #define COMPONENT_TYPE_CPU 1 #define COMPONENT_TYPE_FPU 2 /* Cache Class */ #define COMPONENT_TYPE_PrimaryICache 3 #define COMPONENT_TYPE_PrimaryDCache 4 #define COMPONENT_TYPE_SecondaryICache 5 #define COMPONENT_TYPE_SecondaryDCache 6 #define COMPONENT_TYPE_SecondaryCache 7 /* Memory Class */ #define COMPONENT_TYPE_MemoryUnit 8 /* Adapter Class */ #define COMPONENT_TYPE_EISAAdapter 9 #define COMPONENT_TYPE_TCAdapter 10 #define COMPONENT_TYPE_SCSIAdapter 11 #define COMPONENT_TYPE_DTIAdapter 12 #define COMPONENT_TYPE_MultiFunctionAdapter 13 /* Controller Class */ #define COMPONENT_TYPE_DiskController 14 #define COMPONENT_TYPE_TapeController 15 #define COMPONENT_TYPE_CDROMController 16 #define COMPONENT_TYPE_WORMController 17 #define COMPONENT_TYPE_SerialController 18 #define COMPONENT_TYPE_NetworkController 19 #define COMPONENT_TYPE_DisplayController 20 #define COMPONENT_TYPE_ParallelController 21 #define COMPONENT_TYPE_PointerController 22 #define COMPONENT_TYPE_KeyboardController 23 #define COMPONENT_TYPE_AudioController 24 #define COMPONENT_TYPE_OtherController 25 /* Peripheral Class */ #define COMPONENT_TYPE_DiskPeripheral 26 #define COMPONENT_TYPE_FloppyDiskPeripheral 27 #define COMPONENT_TYPE_TapePeripheral 28 #define COMPONENT_TYPE_ModemPeripheral 29 #define COMPONENT_TYPE_MonitorPeripheral 30 #define COMPONENT_TYPE_PrinterPeripheral 31 #define COMPONENT_TYPE_PointerPeripheral 32 #define COMPONENT_TYPE_KeyboardPeripheral 33 #define COMPONENT_TYPE_TerminalPeripheral 34 #define COMPONENT_TYPE_LinePeripheral 35 #define COMPONENT_TYPE_NetworkPeripheral 36 #define COMPONENT_TYPE_OtherPeripheral 37 #else /* not sgimips */ /* System Class */ #define COMPONENT_TYPE_ARC 0 /* Processor Class */ #define COMPONENT_TYPE_CPU 1 #define COMPONENT_TYPE_FPU 2 /* Cache Class */ #define COMPONENT_TYPE_PrimaryICache 3 #define COMPONENT_TYPE_PrimaryDCache 4 #define COMPONENT_TYPE_SecondaryICache 5 #define COMPONENT_TYPE_SecondaryDCache 6 #define COMPONENT_TYPE_SecondaryCache 7 /* Adapter Class */ #define COMPONENT_TYPE_EISAAdapter 8 #define COMPONENT_TYPE_TCAdapter 9 #define COMPONENT_TYPE_SCSIAdapter 10 #define COMPONENT_TYPE_DTIAdapter 11 #define COMPONENT_TYPE_MultiFunctionAdapter 12 /* Controller Class */ #define COMPONENT_TYPE_DiskController 13 #define COMPONENT_TYPE_TapeController 14 #define COMPONENT_TYPE_CDROMController 15 #define COMPONENT_TYPE_WORMController 16 #define COMPONENT_TYPE_SerialController 17 #define COMPONENT_TYPE_NetworkController 18 #define COMPONENT_TYPE_DisplayController 19 #define COMPONENT_TYPE_ParallelController 20 #define COMPONENT_TYPE_PointerController 21 #define COMPONENT_TYPE_KeyboardController 22 #define COMPONENT_TYPE_AudioController 23 #define COMPONENT_TYPE_OtherController 24 /* Peripheral Class */ #define COMPONENT_TYPE_DiskPeripheral 25 #define COMPONENT_TYPE_FloppyDiskPeripheral 26 #define COMPONENT_TYPE_TapePeripheral 27 #define COMPONENT_TYPE_ModemPeripheral 28 #define COMPONENT_TYPE_MonitorPeripheral 29 #define COMPONENT_TYPE_PrinterPeripheral 30 #define COMPONENT_TYPE_PointerPeripheral 31 #define COMPONENT_TYPE_KeyboardPeripheral 32 #define COMPONENT_TYPE_TerminalPeripheral 33 #define COMPONENT_TYPE_OtherPeripheral 34 #define COMPONENT_TYPE_LinePeripheral 35 #define COMPONENT_TYPE_NetworkPeripheral 36 /* Memory Class */ #define COMPONENT_TYPE_MemoryUnit 37 #endif /* Component flags */ #define COMPONENT_FLAG_Failed 1 #define COMPONENT_FLAG_ReadOnly 2 #define COMPONENT_FLAG_Removable 4 #define COMPONENT_FLAG_ConsoleIn 8 #define COMPONENT_FLAG_ConsoleOut 16 #define COMPONENT_FLAG_Input 32 #define COMPONENT_FLAG_Output 64 /* Key for Cache: */ #define COMPONENT_KEY_Cache_CacheSize(x) \ (ARCBIOS_PAGESIZE << ((x) & 0xffff)) #define COMPONENT_KEY_Cache_LineSize(x) \ (1U << (((x) >> 16) & 0xff)) #define COMPONENT_KEY_Cache_RefillSize(x) \ (((x) >> 24) & 0xff) /* * ARC system ID */ #define ARCBIOS_SYSID_FIELDLEN 8 struct arcbios_sysid { char VendorId[ARCBIOS_SYSID_FIELDLEN]; char ProductId[ARCBIOS_SYSID_FIELDLEN]; }; /* * ARC memory descriptor */ struct arcbios_mem { uint32_t Type; uint32_t BasePage; uint32_t PageCount; }; /* gxemul: Linux/Octane reads these as 64-bit values */ struct arcbios_mem64 { uint32_t Type; uint32_t dummy; /* not used by Linux? */ uint64_t BasePage; uint64_t PageCount; }; #if defined(sgimips) #define ARCBIOS_MEM_ExecptionBlock 0 #define ARCBIOS_MEM_SystemParameterBlock 1 #define ARCBIOS_MEM_FreeContiguous 2 #define ARCBIOS_MEM_FreeMemory 3 #define ARCBIOS_MEM_BadMemory 4 #define ARCBIOS_MEM_LoadedProgram 5 #define ARCBIOS_MEM_FirmwareTemporary 6 #define ARCBIOS_MEM_FirmwarePermanent 7 #else /* lif defined(arc) */ #define ARCBIOS_MEM_ExceptionBlock 0 #define ARCBIOS_MEM_SystemParameterBlock 1 #define ARCBIOS_MEM_FreeMemory 2 #define ARCBIOS_MEM_BadMemory 3 #define ARCBIOS_MEM_LoadedProgram 4 #define ARCBIOS_MEM_FirmwareTemporary 5 #define ARCBIOS_MEM_FirmwarePermanent 6 #define ARCBIOS_MEM_FreeContiguous 7 #endif /* * ARC display status */ struct arcbios_dsp_stat { uint16_t CursorXPosition; uint16_t CursorYPosition; uint16_t CursorMaxXPosition; uint16_t CursorMaxYPosition; uint8_t ForegroundColor; uint8_t BackgroundColor; uint8_t HighIntensity; uint8_t Underscored; uint8_t ReverseVideo; }; /* * ARC firmware vector */ struct arcbios_fv { uint32_t (*Load)( char *, /* image to load */ uint32_t, /* top address */ uint32_t, /* entry address */ uint32_t *); /* low address */ uint32_t (*Invoke)( uint32_t, /* entry address */ uint32_t, /* stack address */ uint32_t, /* argc */ char **, /* argv */ char **); /* envp */ uint32_t (*Execute)( char *, /* image path */ uint32_t, /* argc */ char **, /* argv */ char **); /* envp */ void (*Halt)(void) __attribute__((__noreturn__)); void (*PowerDown)(void) __attribute__((__noreturn__)); void (*Restart)(void) __attribute__((__noreturn__)); void (*Reboot)(void) __attribute__((__noreturn__)); void (*EnterInteractiveMode)(void) __attribute__((__noreturn__)); #if defined(sgimips) void *reserved0; #else void (*ReturnFromMain)(void) __attribute__((__noreturn__)); #endif void *(*GetPeer)( void *); /* component */ void *(*GetChild)( void *); /* component */ void *(*GetParent)( void *); /* component */ uint32_t (*GetConfigurationData)( void *, /* configuration data */ void *); /* component */ void *(*AddChild)( void *, /* component */ void *); /* new component */ uint32_t (*DeleteComponent)( void *); /* component */ uint32_t (*GetComponent)( char *); /* path */ uint32_t (*SaveConfiguration)(void); void *(*GetSystemId)(void); void *(*GetMemoryDescriptor)( void *); /* memory descriptor */ #if defined(sgimips) void *reserved1; #else void (*Signal)( uint32_t, /* signal number */ void *); /* handler */ #endif void *(*GetTime)(void); uint32_t (*GetRelativeTime)(void); uint32_t (*GetDirectoryEntry)( uint32_t, /* file ID */ void *, /* directory entry */ uint32_t, /* length */ uint32_t *); /* count */ uint32_t (*Open)( char *, /* path */ uint32_t, /* open mode */ uint32_t *); /* file ID */ uint32_t (*Close)( uint32_t); /* file ID */ uint32_t (*Read)( uint32_t, /* file ID */ void *, /* buffer */ uint32_t, /* length */ uint32_t *); /* count */ uint32_t (*GetReadStatus)( uint32_t); /* file ID */ uint32_t (*Write)( uint32_t, /* file ID */ void *, /* buffer */ uint32_t, /* length */ uint32_t *); /* count */ uint32_t (*Seek)( uint32_t, /* file ID */ int64_t *, /* offset */ uint32_t); /* whence */ uint32_t (*Mount)( char *, /* path */ uint32_t); /* operation */ char *(*GetEnvironmentVariable)( char *); /* variable */ uint32_t (*SetEnvironmentVariable)( char *, /* variable */ char *); /* contents */ uint32_t (*GetFileInformation)( uint32_t, /* file ID */ void *); /* XXX */ uint32_t (*SetFileInformation)( uint32_t, /* file ID */ uint32_t, /* XXX */ uint32_t); /* XXX */ void (*FlushAllCaches)(void); #if !defined(sgimips) uint32_t (*TestUnicode)( uint32_t, /* file ID */ uint16_t); /* unicode character */ void *(*GetDisplayStatus)( uint32_t); /* file ID */ #endif }; #endif /* SGI_ARCBIOS_H */ gxemul-0.6.1/src/include/thirdparty/ppc_pte.h000644 001750 001750 00000012064 13402411502 021437 0ustar00debugdebug000000 000000 /* GXemul: $Id: ppc_pte.h,v 1.1 2005-11-22 16:26:39 debug Exp $ */ /* $NetBSD: pte.h,v 1.5 2003/11/21 22:57:14 matt Exp $ */ #ifndef _POWERPC_OEA_PTE_H_ #define _POWERPC_OEA_PTE_H_ /*- * Copyright (C) 2003 Matt Thomas * Copyright (C) 1995, 1996 Wolfgang Solfrank. * Copyright (C) 1995, 1996 TooLs GmbH. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if 0 #include /* * Page Table Entries */ #ifndef _LOCORE struct pte { register_t pte_hi; register_t pte_lo; }; struct pteg { struct pte pt[8]; }; #endif /* _LOCORE */ #endif /* High word: */ #ifdef PPC_OEA64 #define PTE_VALID 0x00000001 #define PTE_HID 0x00000002 #define PTE_API 0x00000f80 #define PTE_API_SHFT 7 #define PTE_VSID_SHFT 12 #define PTE_VSID (~0xfffL) #else #define PTE_VALID 0x80000000 #define PTE_VSID 0x7fffff80 #define PTE_VSID_SHFT 7 #define PTE_VSID_LEN 24 #define PTE_HID 0x00000040 #define PTE_API 0x0000003f #define PTE_API_SHFT 0 #endif /* PPC_OEA64 */ /* Low word: */ #define PTE_RPGN (~0xfffL) #define PTE_RPGN_SHFT 12 #define PTE_REF 0x00000100 #define PTE_CHG 0x00000080 #define PTE_W 0x00000040 /* 1 = write-through, 0 = write-back */ #define PTE_I 0x00000020 /* cache inhibit */ #define PTE_M 0x00000010 /* memory coherency enable */ #define PTE_G 0x00000008 /* guarded region (not on 601) */ #define PTE_WIMG (PTE_W|PTE_I|PTE_M|PTE_G) #define PTE_IG (PTE_I|PTE_G) #define PTE_PP 0x00000003 #define PTE_SO 0x00000000 /* Super. Only (U: XX, S: RW) */ #define PTE_SW 0x00000001 /* Super. Write-Only (U: RO, S: RW) */ #define PTE_BW 0x00000002 /* Supervisor (U: RW, S: RW) */ #define PTE_BR 0x00000003 /* Both Read Only (U: RO, S: RO) */ #define PTE_RW PTE_BW #define PTE_RO PTE_BR #define PTE_EXEC 0x00000200 /* pseudo bit; page is exec */ /* * Extract bits from address */ #define ADDR_SR (~0x0fffffffL) #define ADDR_SR_SHFT 28 #define ADDR_PIDX 0x0ffff000 #define ADDR_PIDX_SHFT 12 #ifdef PPC_OEA64 #define ADDR_API_SHFT 23 /* API is 5 bits */ #else #define ADDR_API_SHFT 22 /* API is 6 bits */ #endif /* PPC_OEA64 */ #define ADDR_POFF 0x00000fff #ifdef PPC_OEA64 /* * Segment Table Element */ #if 0 #ifndef _LOCORE struct ste { register_t ste_hi; register_t ste_lo; }; struct steg { struct ste st[8]; }; #endif /* _LOCORE */ #endif /* High Word */ #define STE_VALID 0x00000080 #define STE_TYPE 0x00000040 #define STE_SUKEY 0x00000020 /* Super-state protection */ #define STE_PRKEY 0x00000010 /* User-state protection */ #define STE_NOEXEC 0x00000008 /* No-execute protection bit */ #define STE_ESID (~0x0fffffffL) /* Effective Segment ID */ #define STE_ESID_SHFT 28 #define STE_ESID_MASK 0x0000001f /* low 5 bits of the ESID */ /* Low Word */ #define STE_VSID (~0xfffL) /* Virtual Segment ID */ #define STE_VSID_SHFT 12 #defien STE_VSID_WIDTH 52 #define SR_VSID_SHFT STE_VSID_SHFT /* compatibility with PPC_OEA */ #define SR_VSID_WIDTH STE_VSID_WIDTH /* compatibility with PPC_OEA */ #define SR_KEY_LEN 9 /* 64 groups of 8 segment entries */ #else /* !defined(PPC_OEA64) */ /* * Segment registers */ #define SR_KEY_LEN 4 /* 16 segment registers */ #define SR_TYPE 0x80000000 /* T=0 selects memory format */ #define SR_SUKEY 0x40000000 /* Supervisor protection key */ #define SR_PRKEY 0x20000000 /* User protection key */ #define SR_NOEXEC 0x10000000 /* No-execute protection bit */ #define SR_VSID_SHFT 0 /* Starts at LSB */ #define SR_VSID_WIDTH 24 /* Goes for 24 bits */ #endif /* PPC_OEA64 */ /* Virtual segment ID */ #define SR_VSID (((1L << SR_VSID_WIDTH) - 1) << SR_VSID_SHFT) #endif /* _POWERPC_OEA_PTE_H_ */ gxemul-0.6.1/src/include/thirdparty/mvme88k_vme.h000644 001750 001750 00000026463 13402411502 022163 0ustar00debugdebug000000 000000 /* $OpenBSD: vme.h,v 1.17 2005/11/25 22:14:32 miod Exp $ */ /* * Copyright (c) 1995 Theo de Raadt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __MVEME88K_DEV_VME_H__ #define __MVEME88K_DEV_VME_H__ #if 0 struct vmesoftc { struct device sc_dev; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; struct intrhand sc_abih; /* `abort' switch */ }; #endif /* * XXX: this chip has some rather insane access rules! */ #define VME2_BASE 0xfff40000 #define VME2_SADDR1 0x0000 #define VME2_SADDR2 0x0004 #define VME2_SLAVELMOD1 0x0008 #define VME2_SLAVELMOD2 0x000c #define VME2_SLAVECTL 0x0010 #define VME2_MASTER1 0x0014 #define VME2_MASTER2 0x0018 #define VME2_MASTER3 0x001c #define VME2_MASTER4 0x0020 #define VME2_MASTER4MOD 0x0024 #define VME2_MASTERCTL 0x0028 #define VME2_GCSRCTL 0x002c #define VME2_DMACTL 0x0030 #define VME2_DMAMODE 0x0034 #define VME2_DMALADDR 0x0038 #define VME2_DMAVMEADDR 0x003c #define VME2_DMACOUNT 0x0040 #define VME2_DMATABLE 0x0044 #define VME2_DMASTAT 0x0048 #define VME2_TCR 0x004c #define VME2_T1CMP 0x0050 #define VME2_T1COUNT 0x0054 #define VME2_T2CMP 0x0058 #define VME2_T2COUNT 0x005c #define VME2_TCTL 0x0060 #define VME2_PRESCALE 0x0064 #define VME2_IRQSTAT 0x0068 #define VME2_IRQEN 0x006c #define VME2_SETSOFTIRQ 0x0070 #define VME2_IRQCLR 0x0074 #define VME2_IRQL1 0x0078 #define VME2_IRQL2 0x007c #define VME2_IRQL3 0x0080 #define VME2_IRQL4 0x0084 #define VME2_VBR 0x0088 #define VME2_MISC 0x008c #define VME2_SADDR_END 0xffff0000 /* VME address END & START */ #define VME2_SADDR_START 0x0000ffff #define VME2_SADDR_LADDR 0xffff0000 /* local base address */ #define VME2_SADDR_SIZE(mem) (0x1000 - (mem) >> 16) /* encoding of size */ #define VME2_SLAVE_CHOOSE(bits, num) ((bits) << (16*((num)-1))) #define VME2_SLAVECTL_WP 0x00000100 /* write posting */ #define VME2_SLAVECTL_SNP_NO 0x00000000 /* no snooping */ #define VME2_SLAVECTL_SNP_SINK 0x00000200 /* sink data */ #define VME2_SLAVECTL_SNP_INVAL 0x00000400 /* invalidate */ #define VME2_SLAVECTL_ADDER 0x00000800 /* use adder */ #define VME2_SLAVECTL_SUP 0x00000080 /* modifier bit */ #define VME2_SLAVECTL_USR 0x00000040 /* modifier bit */ #define VME2_SLAVECTL_A32 0x00000020 /* modifier bit */ #define VME2_SLAVECTL_A24 0x00000010 /* modifier bit */ #define VME2_SLAVECTL_D64 0x00000008 /* modifier bit */ #define VME2_SLAVECTL_BLK 0x00000004 /* modifier bit */ #define VME2_SLAVECTL_PGM 0x00000002 /* modifier bit */ #define VME2_SLAVECTL_DAT 0x00000001 /* modifier bit */ #define VME2_MASTERCTL_4SHIFT 24 #define VME2_MASTERCTL_3SHIFT 16 #define VME2_MASTERCTL_2SHIFT 8 #define VME2_MASTERCTL_1SHIFT 0 #define VME2_MASTERCTL_D16 0x80 #define VME2_MASTERCTL_WP 0x40 #define VME2_MASTERCTL_AM 0x3f #define VME2_MASTERCTL_AM24SB 0x3f /* A24 Supervisory Block Transfer */ #define VME2_MASTERCTL_AM24SP 0x3e /* A24 Supervisory Program Access */ #define VME2_MASTERCTL_AM24SD 0x3d /* A24 Supervisory Data Access */ #define VME2_MASTERCTL_AM24UB 0x3b /* A24 Non-priv. Block Transfer */ #define VME2_MASTERCTL_AM24UP 0x3a /* A24 Non-priv. Program Access */ #define VME2_MASTERCTL_AM24UD 0x39 /* A24 Non-priv. Data Access */ #define VME2_MASTERCTL_AM16S 0x2d /* A16 Supervisory Access */ #define VME2_MASTERCTL_AM16U 0x29 /* A16 Non-priv. Access */ #define VME2_MASTERCTL_AM32SB 0x0f /* A32 Supervisory Block Transfer */ #define VME2_MASTERCTL_AM32SP 0x0e /* A32 Supervisory Program Access */ #define VME2_MASTERCTL_AM32SD 0x0d /* A32 Supervisory Data Access */ #define VME2_MASTERCTL_AM32UB 0x0b /* A32 Non-priv. Block Transfer */ #define VME2_MASTERCTL_AM32UP 0x0a /* A32 Non-priv. Program Access */ #define VME2_MASTERCTL_AM32UD 0x09 /* A32 Non-priv Data Access */ #define VME2_MASTERCTL_ALL 0xff #define VME2_GCSRCTL_OFF 0xf0000000 #define VME2_GCSRCTL_MDEN4 0x00080000 #define VME2_GCSRCTL_MDEN3 0x00040000 #define VME2_GCSRCTL_MDEN2 0x00020000 #define VME2_GCSRCTL_MDEN1 0x00010000 #define VME2_GCSRCTL_I2EN 0x00008000 /* F decode (A24D16/A32D16) on */ #define VME2_GCSRCTL_I2WP 0x00004000 /* F decode write post */ #define VME2_GCSRCTL_I2SU 0x00002000 /* F decode is supervisor */ #define VME2_GCSRCTL_I2PD 0x00001000 /* F decode is program */ #define VME2_GCSRCTL_I1EN 0x00000800 /* short decode (A16Dx) on */ #define VME2_GCSRCTL_I1D16 0x00000400 /* short decode is D16 */ #define VME2_GCSRCTL_I1WP 0x00000200 /* short decode write post */ #define VME2_GCSRCTL_I1SU 0x00000100 /* short decode is supervisor */ #define VME2_GCSRCTL_ROMSIZE 0x000000c0 /* size of ROM */ #define VME2_GCSRCTL_ROMBSPD 0x00000038 /* speed of ROM */ #define VME2_GCSRCTL_ROMASPD 0x00000007 /* speed of ROM */ #define VME2_TCR_1MS (1 << 8) /* Watchdog 1 ms */ #define VME2_TCR_2MS (2 << 8) /* Watchdog 2 ms */ #define VME2_TCR_4MS (3 << 8) /* Watchdog 4 ms */ #define VME2_TCR_8MS (4 << 8) /* Watchdog 8 ms */ #define VME2_TCR_16MS (5 << 8) /* Watchdog 16 ms */ #define VME2_TCR_32MS (6 << 8) /* Watchdog 32 ms */ #define VME2_TCR_64MS (7 << 8) /* Watchdog 64 ms */ #define VME2_TCR_128MS (8 << 8) /* Watchdog 128 ms */ #define VME2_TCR_256MS (9 << 8) /* Watchdog 256 ms */ #define VME2_TCR_512MS (10 << 8) /* Watchdog 512 ms */ #define VME2_TCR_1S (11 << 8) /* Watchdog 1 s */ #define VME2_TCR_4S (12 << 8) /* Watchdog 4 s */ #define VME2_TCR_16S (13 << 8) /* Watchdog 16 s */ #define VME2_TCR_32S (14 << 8) /* Watchdog 32 s */ #define VME2_TCR_64S (15 << 8) /* Watchdog 64 s */ #define VME2_TCTL1_CEN 0x01 #define VME2_TCTL1_COC 0x02 #define VME2_TCTL1_COVF 0x04 #define VME2_TCTL1_OVF 0xf0 #define VME2_TCTL2_CEN (0x01 << 8) #define VME2_TCTL2_COC (0x02 << 8) #define VME2_TCTL2_COVF (0x04 << 8) #define VME2_TCTL2_OVF (0xf0 << 8) #define VME2_TCTL_WDEN 0x00010000 /* Watchdog Enable */ #define VME2_TCTL_WDRSE 0x00020000 /* Watchdog Reset Enable */ #define VME2_TCTL_WDSL 0x00040000 /* local or system reset */ #define VME2_TCTL_WDBFE 0x00080000 /* Watchdog Board Fail Enable */ #define VME2_TCTL_WDTO 0x00100000 /* Watchdog Timeout Status */ #define VME2_TCTL_WDCC 0x00200000 /* Watchdog Clear Counter */ #define VME2_TCTL_WDCS 0x00400000 /* Watchdog Clear Timeout */ #define VME2_TCTL_SRST 0x00800000 /* system reset */ #define VME2_TCTL_RSWE 0x01000000 /* Reset Switch Enable */ #define VME2_TCTL_BDFLO 0x02000000 /* Assert Board Fail */ #define VME2_TCTL_CPURS 0x04000000 /* Clear Power-up Reset bit */ #define VME2_TCTL_PURS 0x08000000 /* Power-up Reset bit */ #define VME2_TCTL_BDFLI 0x10000000 /* Board Fail Status*/ #define VME2_TCTL_SYSFAIL 0x20000000 /* light SYSFAIL led */ #define VME2_TCTL_SCON 0x40000000 /* we are SCON */ #define VME2_IRQ_ACF 0x80000000 #define VME2_IRQ_AB 0x40000000 #define VME2_IRQ_SYSF 0x20000000 #define VME2_IRQ_MWP 0x10000000 #define VME2_IRQ_PE 0x08000000 #define VME2_IRQ_V1IE 0x04000000 #define VME2_IRQ_TIC2 0x02000000 #define VME2_IRQ_TIC1 0x01000000 #define VME2_IRQ_VIA 0x00800000 #define VME2_IRQ_DMA 0x00400000 #define VME2_IRQ_SIG3 0x00200000 #define VME2_IRQ_SIG2 0x00100000 #define VME2_IRQ_SIG1 0x00080000 #define VME2_IRQ_SIG0 0x00040000 #define VME2_IRQ_LM1 0x00020000 #define VME2_IRQ_LM0 0x00010000 #define VME2_IRQ_SW7 0x00008000 #define VME2_IRQ_SW6 0x00004000 #define VME2_IRQ_SW5 0x00002000 #define VME2_IRQ_SW4 0x00001000 #define VME2_IRQ_SW3 0x00000800 #define VME2_IRQ_SW2 0x00000400 #define VME2_IRQ_SW1 0x00000200 #define VME2_IRQ_SW0 0x00000100 #define VME2_IRQ_SW(x) ((1 << (x))) << 8) #define VME2_IRQ_SPARE 0x00000080 #define VME2_IRQ_VME7 0x00000040 #define VME2_IRQ_VME6 0x00000020 #define VME2_IRQ_VME5 0x00000010 #define VME2_IRQ_VME4 0x00000008 #define VME2_IRQ_VME3 0x00000004 #define VME2_IRQ_VME2 0x00000002 #define VME2_IRQ_VME1 0x00000001 #define VME2_IRQ_VME(x) (1 << ((x) - 1)) #define VME2_IRQL1_ACFSHIFT 28 #define VME2_IRQL1_ABSHIFT 24 #define VME2_IRQL1_SYSFSHIFT 20 #define VME2_IRQL1_WPESHIFT 16 #define VME2_IRQL1_PESHIFT 12 #define VME2_IRQL1_V1IESHIFT 8 #define VME2_IRQL1_TIC2SHIFT 4 #define VME2_IRQL1_TIC1SHIFT 0 #define VME2_IRQL2_VIASHIFT 28 #define VME2_IRQL2_DMASHIFT 24 #define VME2_IRQL2_SIG3SHIFT 20 #define VME2_IRQL2_SIG2SHIFT 16 #define VME2_IRQL2_SIG1SHIFT 12 #define VME2_IRQL2_SIG0SHIFT 8 #define VME2_IRQL2_LM1SHIFT 4 #define VME2_IRQL2_LM0SHIFT 0 #define VME2_IRQL3_SW7SHIFT 28 #define VME2_IRQL3_SW6SHIFT 24 #define VME2_IRQL3_SW5SHIFT 20 #define VME2_IRQL3_SW4SHIFT 16 #define VME2_IRQL3_SW3SHIFT 12 #define VME2_IRQL3_SW2SHIFT 8 #define VME2_IRQL3_SW1SHIFT 4 #define VME2_IRQL3_SW0SHIFT 0 #define VME2_IRQL4_SPARESHIFT 28 #define VME2_IRQL4_VME7SHIFT 24 #define VME2_IRQL4_VME6SHIFT 20 #define VME2_IRQL4_VME5SHIFT 16 #define VME2_IRQL4_VME4SHIFT 12 #define VME2_IRQL4_VME3SHIFT 8 #define VME2_IRQL4_VME2SHIFT 4 #define VME2_IRQL4_VME1SHIFT 0 #define VME2_SYSFAIL (1 << 22) #define VME2_IOCTL1_MIEN (1 << 23) #define VME2_VBR_0SHIFT 28 #define VME2_VBR_1SHIFT 24 #define VME2_SET_VBR0(x) ((x) << VME2_VBR_0SHIFT) #define VME2_SET_VBR1(x) ((x) << VME2_VBR_1SHIFT) #define VME2_GET_VBR0(x) ((((x) >> 28) & 0xf) << 4) #define VME2_GET_VBR1(x) ((((x) >> 24) & 0xf) << 4) #define VME2_VBR_GPOXXXX 0x00ffffff #define VME2_MISC_MPIRQEN 0x00000080 /* do not set */ #define VME2_MISC_REVEROM 0x00000040 /* 167: dis eprom. 166: en flash */ #define VME2_MISC_DISSRAM 0x00000020 /* do not set */ #define VME2_MISC_DISMST 0x00000010 #define VME2_MISC_NOELBBSY 0x00000008 /* do not set */ #define VME2_MISC_DISBSYT 0x00000004 /* do not set */ #define VME2_MISC_ENINT 0x00000002 /* do not set */ #define VME2_MISC_DISBGN 0x00000001 /* do not set */ #define VME2_A16D32BASE 0xffff0000UL #define VME2_A16D32LEN 0x00010000UL #define VME2_A32D16BASE 0xf1000000UL #define VME2_A32D16LEN 0x01000000UL #define VME2_A16D16BASE 0xffff0000UL #define VME2_A16D16LEN 0x00010000UL #define VME2_A24D16BASE 0xf0000000UL #define VME2_A24D16LEN 0x01000000UL #define VME2_A16BASE 0xffff0000UL #define VME2_A24BASE 0xff000000UL #if 0 paddr_t vmepmap(struct device *sc, off_t vmeaddr, int bustype); int vmerw(struct device *sc, struct uio *uio, int flags, int bus); int vmeintr_establish(int, struct intrhand *, const char *); int vme_findvec(int); int vmescan(struct device *, void *, void *, int); #endif #endif /* __MVEME88K_DEV_VME_H__ */ gxemul-0.6.1/src/include/thirdparty/sgi_macereg.h000644 001750 001750 00000015147 13402411502 022257 0ustar00debugdebug000000 000000 /* $NetBSD: macereg.h,v 1.2 2005/12/11 12:18:54 christos Exp $ */ #ifndef SGI_MACEREG_H #define SGI_MACEREG_H /* * Copyright (c) 2000 Soren S. Jorvang * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the * NetBSD Project. See http://www.NetBSD.org/ for * information about NetBSD. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define MACE_BASE 0x1f000000 /* PCI definitions (offset 0x080000) */ #define MACE_PCI_ERROR_ADDR 0x00 #define MACE_PCI_ERROR_FLAGS 0x04 #define MACE_PCI_CONTROL 0x08 #define MACE_PCI_CONTROL_INT_MASK 0x000000ff #define MACE_PCI_CONTROL_SERR_ENA 0x00000100 #define MACE_PCI_CONTROL_ARB_N6 0x00000200 #define MACE_PCI_CONTROL_PARITY_ERR 0x00000400 #define MACE_PCI_CONTROL_MRMRA_ENA 0x00000800 #define MACE_PCI_CONTROL_ARB_N3 0x00001000 #define MACE_PCI_CONTROL_ARB_N4 0x00002000 #define MACE_PCI_CONTROL_ARB_N5 0x00004000 #define MACE_PCI_CONTROL_PARK_LIU 0x00008000 #define MACE_PCI_CONTROL_INV_INT_MASK 0x00ff0000 #define MACE_PCI_CONTROL_OVERRUN_INT 0x01000000 #define MACE_PCI_CONTROL_PARITY_INT 0x02000000 #define MACE_PCI_CONTROL_SERR_INT 0x04000000 #define MACE_PCI_CONTROL_IT_INT 0x08000000 #define MACE_PCI_CONTROL_RE_INT 0x10000000 #define MACE_PCI_CONTROL_DPED_INT 0x20000000 #define MACE_PCI_CONTROL_TAR_INT 0x40000000 #define MACE_PCI_CONTROL_MAR_INT 0x80000000 #define MACE_PCI_REV_INFO_R 0x0c #define MACE_PCI_FLUSH_W 0x0c #define MACE_PCI_CONFIG_ADDR 0xcf8 #define MACE_PCI_CONFIG_DATA 0xcfc #define MACE_PCI_LOW_MEMORY 0x1a000000 #define MACE_PCI_LOW_IO 0x18000000 #define MACE_PCI_NATIVE_VIEW 0x40000000 #define MACE_PCI_IO 0x80000000 #define MACE_PCI_HI_MEMORY 0x280000000 #define MACE_PCI_HI_IO 0x100000000 #define MACE_VIN1 0x100000 #define MACE_VIN2 0x180000 #define MACE_VOUT 0x200000 #define MACE_PERIF 0x300000 #define MACE_ISA_EXT 0x380000 #if 1 /* GXemul, making it easier to use offsets further down: */ #define MACE_AUDIO 0 #define MACE_ISA 0 #define MACE_KBDMS 0 #define MACE_I2C 0 #define MACE_UST_MSC 0 #else #define MACE_AUDIO (MACE_PERIF + 0x00000) #define MACE_ISA (MACE_PERIF + 0x10000) #define MACE_KBDMS (MACE_PERIF + 0x20000) #define MACE_I2C (MACE_PERIF + 0x30000) #define MACE_UST_MSC (MACE_PERIF + 0x40000) #endif /*********************** * PCI_ERROR_FLAGS Bits */ #define MACE_PERR_MASTER_ABORT 0x80000000 #define MACE_PERR_TARGET_ABORT 0x40000000 #define MACE_PERR_DATA_PARITY_ERR 0x20000000 #define MACE_PERR_RETRY_ERR 0x10000000 #define MACE_PERR_ILLEGAL_CMD 0x08000000 #define MACE_PERR_SYSTEM_ERR 0x04000000 #define MACE_PERR_INTERRUPT_TEST 0x02000000 #define MACE_PERR_PARITY_ERR 0x01000000 #define MACE_PERR_OVERRUN 0x00800000 #define MACE_PERR_RSVD 0x00400000 #define MACE_PERR_MEMORY_ADDR 0x00200000 #define MACE_PERR_CONFIG_ADDR 0x00100000 #define MACE_PERR_MASTER_ABORT_ADDR_VALID 0x00080000 #define MACE_PERR_TARGET_ABORT_ADDR_VALID 0x00040000 #define MACE_PERR_DATA_PARITY_ADDR_VALID 0x00020000 #define MACE_PERR_RETRY_ADDR_VALID 0x00010000 /******************************* * MACE ISA External Address Map */ #define MACE_ISA_EPP_BASE (MACE_ISA_EXT + 0x00000) #define MACE_ISA_ECP_BASE (MACE_ISA_EXT + 0x08000) #define MACE_ISA_SER1_BASE (MACE_ISA_EXT + 0x10000) #define MACE_ISA_SER2_BASE (MACE_ISA_EXT + 0x18000) #define MACE_ISA_RTC_BASE (MACE_ISA_EXT + 0x20000) #define MACE_ISA_GAME_BASE (MACE_ISA_EXT + 0x30000) /************************* * ISA Interface Registers */ /* ISA Ringbase Address and Reset Register */ #define MACE_ISA_RINGBASE (MACE_ISA + 0x0000) /* Flash-ROM/LED/DP-RAM/NIC Controller Register */ #define MACE_ISA_FLASH_NIC_REG (MACE_ISA + 0x0008) #define MACE_ISA_FLASH_WE 0x01 /* 1=> Enable FLASH writes */ #define MACE_ISA_PWD_CLEAR 0x02 /* 1=> PWD CLEAR jumper detected */ #define MACE_ISA_NIC_DEASSERT 0x04 #define MACE_ISA_NIC_DATA 0x08 #define MACE_ISA_LED_RED 0x10 /* 1=> Illuminate RED LED */ #define MACE_ISA_LED_GREEN 0x20 /* 1=> Illuminate GREEN LED */ #define MACE_ISA_DP_RAM_ENABLE 0x40 /* Interrupt Status and Mask Registers (32 bits) */ #define MACE_ISA_INT_STATUS (MACE_ISA + 0x0010) #define MACE_ISA_INT_MASK (MACE_ISA + 0x0018) /* bit definitions */ #define MACE_ISA_INT_RTC_IRQ 0x00000100 /******************************** * MACE Timer Interface Registers * * Note: MSC_UST<31:0> is MSC, MSC_UST<63:32> is UST. */ #define MACE_UST (MACE_UST_MSC + 0x00) /* Universial system time */ #define MACE_COMPARE1 (MACE_UST_MSC + 0x08) /* Interrupt compare reg 1 */ #define MACE_COMPARE2 (MACE_UST_MSC + 0x10) /* Interrupt compare reg 2 */ #define MACE_COMPARE3 (MACE_UST_MSC + 0x18) /* Interrupt compare reg 3 */ #define MACE_UST_PERIOD 960 /* UST Period in ns */ #define MACE_AIN_MSC_UST (MACE_UST_MSC + 0x20) /* Audio in MSC/UST pair */ #define MACE_AOUT1_MSC_UST (MACE_UST_MSC + 0x28) /* Audio out 1 MSC/UST pair */ #define MACE_AOUT2_MSC_UST (MACE_UST_MSC + 0x30) /* Audio out 2 MSC/UST pair */ #define MACE_VIN1_MSC_UST (MACE_UST_MSC + 0x38) /* Video In 1 MSC/UST pair */ #define MACE_VIN2_MSC_UST (MACE_UST_MSC + 0x40) /* Video In 2 MSC/UST pair */ #define MACE_VOUT_MSC_UST (MACE_UST_MSC + 0x48) /* Video out MSC/UST pair */ #endif /* SGI_MACEREG_H */ gxemul-0.6.1/src/include/thirdparty/ncr53c9xreg.h000644 001750 001750 00000030612 13402411502 022060 0ustar00debugdebug000000 000000 #ifndef NCR53C9XREG_H #define NCR53C9XREG_H /* $NetBSD: ncr53c9xreg.h,v 1.10 2001/11/21 19:14:29 wiz Exp $ */ /* * Copyright (c) 1994 Peter Galbavy. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Peter Galbavy. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Register addresses, relative to some base address */ #define NCR_TCL 0x00 /* RW - Transfer Count Low */ #define NCR_TCM 0x01 /* RW - Transfer Count Mid */ #define NCR_TCH 0x0e /* RW - Transfer Count High */ /* NOT on 53C90 */ #define NCR_FIFO 0x02 /* RW - FIFO data */ #define NCR_CMD 0x03 /* RW - Command (2 deep) */ #define NCRCMD_DMA 0x80 /* DMA Bit */ #define NCRCMD_NOP 0x00 /* No Operation */ #define NCRCMD_FLUSH 0x01 /* Flush FIFO */ #define NCRCMD_RSTCHIP 0x02 /* Reset Chip */ #define NCRCMD_RSTSCSI 0x03 /* Reset SCSI Bus */ #define NCRCMD_RESEL 0x40 /* Reselect Sequence */ #define NCRCMD_SELNATN 0x41 /* Select without ATN */ #define NCRCMD_SELATN 0x42 /* Select with ATN */ #define NCRCMD_SELATNS 0x43 /* Select with ATN & Stop */ #define NCRCMD_ENSEL 0x44 /* Enable (Re)Selection */ #define NCRCMD_DISSEL 0x45 /* Disable (Re)Selection */ #define NCRCMD_SELATN3 0x46 /* Select with ATN3 */ #define NCRCMD_RESEL3 0x47 /* Reselect3 Sequence */ #define NCRCMD_SNDMSG 0x20 /* Send Message */ #define NCRCMD_SNDSTAT 0x21 /* Send Status */ #define NCRCMD_SNDDATA 0x22 /* Send Data */ #define NCRCMD_DISCSEQ 0x23 /* Disconnect Sequence */ #define NCRCMD_TERMSEQ 0x24 /* Terminate Sequence */ #define NCRCMD_TCCS 0x25 /* Target Command Comp Seq */ #define NCRCMD_DISC 0x27 /* Disconnect */ #define NCRCMD_RECMSG 0x28 /* Receive Message */ #define NCRCMD_RECCMD 0x29 /* Receive Command */ #define NCRCMD_RECDATA 0x2a /* Receive Data */ #define NCRCMD_RECCSEQ 0x2b /* Receive Command Sequence*/ #define NCRCMD_ABORT 0x04 /* Target Abort DMA */ #define NCRCMD_TRANS 0x10 /* Transfer Information */ #define NCRCMD_ICCS 0x11 /* Initiator Cmd Comp Seq */ #define NCRCMD_MSGOK 0x12 /* Message Accepted */ #define NCRCMD_TRPAD 0x18 /* Transfer Pad */ #define NCRCMD_SETATN 0x1a /* Set ATN */ #define NCRCMD_RSTATN 0x1b /* Reset ATN */ #define NCR_STAT 0x04 /* RO - Status */ #define NCRSTAT_INT 0x80 /* Interrupt */ #define NCRSTAT_GE 0x40 /* Gross Error */ #define NCRSTAT_PE 0x20 /* Parity Error */ #define NCRSTAT_TC 0x10 /* Terminal Count */ #define NCRSTAT_VGC 0x08 /* Valid Group Code */ #define NCRSTAT_PHASE 0x07 /* Phase bits */ #define NCR_SELID 0x04 /* WO - Select/Reselect Bus ID */ #define NCR_BUSID_HME 0x10 /* XXX HME reselect ID */ #define NCR_BUSID_HME32 0x40 /* XXX HME to select more than 16 */ #define NCR_INTR 0x05 /* RO - Interrupt */ #define NCRINTR_SBR 0x80 /* SCSI Bus Reset */ #define NCRINTR_ILL 0x40 /* Illegal Command */ #define NCRINTR_DIS 0x20 /* Disconnect */ #define NCRINTR_BS 0x10 /* Bus Service */ #define NCRINTR_FC 0x08 /* Function Complete */ #define NCRINTR_RESEL 0x04 /* Reselected */ #define NCRINTR_SELATN 0x02 /* Select with ATN */ #define NCRINTR_SEL 0x01 /* Selected */ #define NCR_TIMEOUT 0x05 /* WO - Select/Reselect Timeout */ #define NCR_STEP 0x06 /* RO - Sequence Step */ #define NCRSTEP_MASK 0x07 /* the last 3 bits */ #define NCRSTEP_DONE 0x04 /* command went out */ #define NCR_SYNCTP 0x06 /* WO - Synch Transfer Period */ /* Default 5 (53C9X) */ #define NCR_FFLAG 0x07 /* RO - FIFO Flags */ #define NCRFIFO_SS 0xe0 /* Sequence Step (Dup) */ #define NCRFIFO_FF 0x1f /* Bytes in FIFO */ #define NCR_SYNCOFF 0x07 /* WO - Synch Offset */ /* 0 = ASYNC */ /* 1 - 15 = SYNC bytes */ #define NCR_CFG1 0x08 /* RW - Configuration #1 */ #define NCRCFG1_SLOW 0x80 /* Slow Cable Mode */ #define NCRCFG1_SRR 0x40 /* SCSI Reset Rep Int Dis */ #define NCRCFG1_PTEST 0x20 /* Parity Test Mod */ #define NCRCFG1_PARENB 0x10 /* Enable Parity Check */ #define NCRCFG1_CTEST 0x08 /* Enable Chip Test */ #define NCRCFG1_BUSID 0x07 /* Bus ID */ #define NCR_CCF 0x09 /* WO - Clock Conversion Factor */ /* 0 = 35.01 - 40Mhz */ /* NEVER SET TO 1 */ /* 2 = 10Mhz */ /* 3 = 10.01 - 15Mhz */ /* 4 = 15.01 - 20Mhz */ /* 5 = 20.01 - 25Mhz */ /* 6 = 25.01 - 30Mhz */ /* 7 = 30.01 - 35Mhz */ #define NCR_TEST 0x0a /* WO - Test (Chip Test Only) */ #define NCR_CFG2 0x0b /* RW - Configuration #2 */ #define NCRCFG2_RSVD 0xa0 /* reserved */ #define NCRCFG2_FE 0x40 /* Features Enable */ #define NCRCFG2_DREQ 0x10 /* DREQ High Impedance */ #define NCRCFG2_SCSI2 0x08 /* SCSI-2 Enable */ #define NCRCFG2_BPA 0x04 /* Target Bad Parity Abort */ #define NCRCFG2_RPE 0x02 /* Register Parity Error */ #define NCRCFG2_DPE 0x01 /* DMA Parity Error */ #define NCRCFG2_HMEFE 0x10 /* HME feature enable */ #define NCRCFG2_HME32 0x80 /* HME 32 extended */ /* Config #3 only on 53C9X */ #define NCR_CFG3 0x0c /* RW - Configuration #3 */ #define NCRCFG3_RSVD 0xe0 /* reserved */ #define NCRCFG3_IDM 0x10 /* ID Message Res Check */ #define NCRCFG3_QTE 0x08 /* Queue Tag Enable */ #define NCRCFG3_CDB 0x04 /* CDB 10-bytes OK */ #define NCRCFG3_FSCSI 0x02 /* Fast SCSI */ #define NCRCFG3_FCLK 0x01 /* Fast Clock (>25Mhz) */ /* * For some unknown reason, the ESP406/FAS408 looks like every * other ncr53c9x, except for configuration #3 register. At any * rate, if you're dealing with these chips, you need to use these * defines instead. */ /* Config #3 different on ESP406/FAS408 */ #define NCR_ESPCFG3 0x0c /* RW - Configuration #3 */ #define NCRESPCFG3_IDM 0x80 /* ID Message Res Check */ #define NCRESPCFG3_QTE 0x40 /* Queue Tag Enable */ #define NCRESPCFG3_CDB 0x20 /* CDB 10-bytes OK */ #define NCRESPCFG3_FSCSI 0x10 /* Fast SCSI */ #define NCRESPCFG3_SRESB 0x08 /* Save Residual Byte */ #define NCRESPCFG3_FCLK 0x04 /* Fast Clock (>25Mhz) */ #define NCRESPCFG3_ADMA 0x02 /* Alternate DMA Mode */ #define NCRESPCFG3_T8M 0x01 /* Threshold 8 Mode */ /* Config #3 also different on NCR53CF9x/FAS216 */ #define NCR_F9XCFG3 0x0c /* RW - Configuration #3 */ #define NCRF9XCFG3_IDM 0x80 /* ID Message Res Check */ #define NCRF9XCFG3_QTE 0x40 /* Queue Tag Enable */ #define NCRF9XCFG3_CDB 0x20 /* CDB 10-bytes OK */ #define NCRF9XCFG3_FSCSI 0x10 /* Fast SCSI */ #define NCRF9XCFG3_FCLK 0x08 /* Fast Clock (>25Mhz) */ #define NCRF9XCFG3_SRESB 0x04 /* Save Residual Byte */ #define NCRF9XCFG3_ADMA 0x02 /* Alternate DMA Mode */ #define NCRF9XCFG3_T8M 0x01 /* Threshold 8 Mode */ /* Config #3 on FAS366 */ #define NCRFASCFG3_OBAUTO 0x80 /* auto push odd-byte to dma */ #define NCRFASCFG3_EWIDE 0x40 /* Enable Wide-SCSI */ #define NCRFASCFG3_IDBIT3 0x20 /* Bit 3 of HME SCSI-ID */ #define NCRFASCFG3_IDRESCHK 0x10 /* ID message checking */ #define NCRFASCFG3_QUENB 0x08 /* 3-byte msg support */ #define NCRFASCFG3_CDB10 0x04 /* group 2 scsi-2 support */ #define NCRFASCFG3_FASTSCSI 0x02 /* 10 MB/S fast scsi mode */ #define NCRFASCFG3_FASTCLK 0x01 /* fast clock mode */ /* Config #4 only on ESP406/FAS408 */ #define NCR_CFG4 0x0d /* RW - Configuration #4 */ #define NCRCFG4_CRS1 0x80 /* Select register set #1 */ #define NCRCFG4_RSVD 0x7b /* reserved */ #define NCRCFG4_ACTNEG 0x04 /* Active negation */ /* The following registers are only on the ESP406/FAS408. The documentation refers to them as "Control Register Set #1". These are the registers that are visible when bit 7 of register 0x0d is set. This bit is common to both register sets. */ #define NCR_JMP 0x00 /* RO - Jumper Sense Register */ #define NCRJMP_RSVD 0xc0 /* reserved */ #define NCRJMP_ROMSZ 0x20 /* ROM Size 1=16K, 0=32K */ #define NCRJMP_J4 0x10 /* Jumper #4 */ #define NCRJMP_J3 0x08 /* Jumper #3 */ #define NCRJMP_J2 0x04 /* Jumper #2 */ #define NCRJMP_J1 0x02 /* Jumper #1 */ #define NCRJMP_J0 0x01 /* Jumper #0 */ #define NCR_PIOFIFO 0x04 /* WO - PIO FIFO, 4 bytes deep */ #define NCR_PSTAT 0x08 /* RW - PIO Status Register */ #define NCRPSTAT_PERR 0x80 /* PIO Error */ #define NCRPSTAT_SIRQ 0x40 /* Active High of SCSI IRQ */ #define NCRPSTAT_ATAI 0x20 /* ATA IRQ */ #define NCRPSTAT_FEMPT 0x10 /* PIO FIFO Empty */ #define NCRPSTAT_F13 0x08 /* PIO FIFO 1/3 */ #define NCRPSTAT_F23 0x04 /* PIO FIFO 2/3 */ #define NCRPSTAT_FFULL 0x02 /* PIO FIFO Full */ #define NCRPSTAT_PIOM 0x01 /* PIO/DMA Mode */ #define NCR_PIOI 0x0b /* RW - PIO Interrupt Enable */ #define NCRPIOI_RSVD 0xe0 /* reserved */ #define NCRPIOI_EMPTY 0x10 /* IRQ When Empty */ #define NCRPIOI_13 0x08 /* IRQ When 1/3 */ #define NCRPIOI_23 0x04 /* IRQ When 2/3 */ #define NCRPIOI_FULL 0x02 /* IRQ When Full */ #define NCRPIOI_FINV 0x01 /* Flag Invert */ #define NCR_CFG5 0x0d /* RW - Configuration #5 */ #define NCRCFG5_CRS1 0x80 /* Select Register Set #1 */ #define NCRCFG5_SRAM 0x40 /* SRAM Memory Map */ #define NCRCFG5_AADDR 0x20 /* Auto Address */ #define NCRCFG5_PTRINC 0x10 /* Pointer Increment */ #define NCRCFG5_LOWPWR 0x08 /* Low Power Mode */ #define NCRCFG5_SINT 0x04 /* SCSI Interupt Enable */ #define NCRCFG5_INTP 0x02 /* INT Polarity */ #define NCRCFG5_AINT 0x01 /* ATA Interupt Enable */ #define NCR_SIGNTR 0x0e /* RO - Signature */ /* Am53c974 Config #3 */ #define NCR_AMDCFG3 0x0c /* RW - Configuration #3 */ #define NCRAMDCFG3_IDM 0x80 /* ID Message Res Check */ #define NCRAMDCFG3_QTE 0x40 /* Queue Tag Enable */ #define NCRAMDCFG3_CDB 0x20 /* CDB 10-bytes OK */ #define NCRAMDCFG3_FSCSI 0x10 /* Fast SCSI */ #define NCRAMDCFG3_FCLK 0x08 /* Fast Clock (40MHz) */ #define NCRAMDCFG3_RSVD 0x07 /* Reserved */ /* Am53c974 Config #4 */ #define NCR_AMDCFG4 0x0d /* RW - Configuration #4 */ #define NCRAMDCFG4_GE 0xc0 /* Glitch Eater */ #define NCRAMDCFG4_GE12NS 0x00 /* Signal window 12ns */ #define NCRAMDCFG4_GE25NS 0x80 /* Signal window 25ns */ #define NCRAMDCFG4_GE35NS 0x40 /* Signal window 35ns */ #define NCRAMDCFG4_GE0NS 0xc0 /* Signal window 0ns */ #define NCRAMDCFG4_PWD 0x20 /* Reduced power feature */ #define NCRAMDCFG4_RSVD 0x13 /* Reserved */ #define NCRAMDCFG4_RAE 0x08 /* Active neg. REQ/ACK */ #define NCRAMDCFG4_RADE 0x04 /* Active neg. REQ/ACK/DAT */ /* * FAS366 */ #define NCR_RCL NCR_TCH /* Recommand counter low */ #define NCR_RCH 0xf /* Recommand counter high */ #define NCR_UID NCR_RCL /* fas366 part-uniq id */ /* status register #2 definitions (read only) */ #define NCR_STAT2 NCR_CCF #define NCRFAS_STAT2_SEQCNT 0x01 /* Sequence counter bit 7-3 enabled */ #define NCRFAS_STAT2_FLATCHED 0x02 /* FIFO flags register latched */ #define NCRFAS_STAT2_CLATCHED 0x04 /* Xfer cntr & recommand ctr latched */ #define NCRFAS_STAT2_CACTIVE 0x08 /* Command register is active */ #define NCRFAS_STAT2_SCSI16 0x10 /* SCSI interface is wide */ #define NCRFAS_STAT2_ISHUTTLE 0x20 /* FIFO Top register contains 1 byte */ #define NCRFAS_STAT2_OSHUTTLE 0x40 /* next byte from FIFO is MSB */ #define NCRFAS_STAT2_EMPTY 0x80 /* FIFO is empty */ #endif /* NCR53C9XREG_H */ gxemul-0.6.1/src/include/thirdparty/pcireg.h000644 001750 001750 00000047734 13402411502 021272 0ustar00debugdebug000000 000000 /* gxemul: $Id: pcireg.h,v 1.6 2005-11-17 13:53:43 debug Exp $ */ /* $NetBSD: pcireg.h,v 1.37 2002/03/22 20:03:20 drochner Exp $ */ #ifndef _DEV_PCI_PCIREG_H_ #define _DEV_PCI_PCIREG_H_ #ifdef __attribute__ #undef __attribute__ #endif #ifdef __noreturn__ #undef __noreturn__ #endif #define __attribute__(x) /* */ #define __noreturn__ /* */ /* * Copyright (c) 1995, 1996, 1999, 2000 * Christopher G. Demetriou. All rights reserved. * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Charles M. Hannum. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Standardized PCI configuration information * * XXX This is not complete. */ /* * Device identification register; contains a vendor ID and a device ID. */ #define PCI_ID_REG 0x00 typedef u_int16_t pci_vendor_id_t; typedef u_int16_t pci_product_id_t; #define PCI_VENDOR_SHIFT 0 #define PCI_VENDOR_MASK 0xffff #define PCI_VENDOR(id) \ (((id) >> PCI_VENDOR_SHIFT) & PCI_VENDOR_MASK) #define PCI_PRODUCT_SHIFT 16 #define PCI_PRODUCT_MASK 0xffff #define PCI_PRODUCT(id) \ (((id) >> PCI_PRODUCT_SHIFT) & PCI_PRODUCT_MASK) #define PCI_ID_CODE(vid,pid) \ ((((vid) & PCI_VENDOR_MASK) << PCI_VENDOR_SHIFT) | \ (((uint32_t)((pid) & PCI_PRODUCT_MASK)) << PCI_PRODUCT_SHIFT)) /* * Command and status register. */ #define PCI_COMMAND_STATUS_REG 0x04 #define PCI_COMMAND_SHIFT 0 #define PCI_COMMAND_MASK 0xffff #define PCI_STATUS_SHIFT 16 #define PCI_STATUS_MASK 0xffff #define PCI_COMMAND_STATUS_CODE(cmd,stat) \ ((((cmd) & PCI_COMMAND_MASK) >> PCI_COMMAND_SHIFT) | \ (((stat) & PCI_STATUS_MASK) >> PCI_STATUS_SHIFT)) #define PCI_COMMAND_IO_ENABLE 0x00000001 #define PCI_COMMAND_MEM_ENABLE 0x00000002 #define PCI_COMMAND_MASTER_ENABLE 0x00000004 #define PCI_COMMAND_SPECIAL_ENABLE 0x00000008 #define PCI_COMMAND_INVALIDATE_ENABLE 0x00000010 #define PCI_COMMAND_PALETTE_ENABLE 0x00000020 #define PCI_COMMAND_PARITY_ENABLE 0x00000040 #define PCI_COMMAND_STEPPING_ENABLE 0x00000080 #define PCI_COMMAND_SERR_ENABLE 0x00000100 #define PCI_COMMAND_BACKTOBACK_ENABLE 0x00000200 #define PCI_STATUS_CAPLIST_SUPPORT 0x00100000 #define PCI_STATUS_66MHZ_SUPPORT 0x00200000 #define PCI_STATUS_UDF_SUPPORT 0x00400000 #define PCI_STATUS_BACKTOBACK_SUPPORT 0x00800000 #define PCI_STATUS_PARITY_ERROR 0x01000000 #define PCI_STATUS_DEVSEL_FAST 0x00000000 #define PCI_STATUS_DEVSEL_MEDIUM 0x02000000 #define PCI_STATUS_DEVSEL_SLOW 0x04000000 #define PCI_STATUS_DEVSEL_MASK 0x06000000 #define PCI_STATUS_TARGET_TARGET_ABORT 0x08000000 #define PCI_STATUS_MASTER_TARGET_ABORT 0x10000000 #define PCI_STATUS_MASTER_ABORT 0x20000000 #define PCI_STATUS_SPECIAL_ERROR 0x40000000 #define PCI_STATUS_PARITY_DETECT 0x80000000 /* * PCI Class and Revision Register; defines type and revision of device. */ #define PCI_CLASS_REG 0x08 typedef u_int8_t pci_class_t; typedef u_int8_t pci_subclass_t; typedef u_int8_t pci_interface_t; typedef u_int8_t pci_revision_t; #define PCI_CLASS_SHIFT 24 #define PCI_CLASS_MASK 0xff #define PCI_CLASS(cr) \ (((cr) >> PCI_CLASS_SHIFT) & PCI_CLASS_MASK) #define PCI_SUBCLASS_SHIFT 16 #define PCI_SUBCLASS_MASK 0xff #define PCI_SUBCLASS(cr) \ (((cr) >> PCI_SUBCLASS_SHIFT) & PCI_SUBCLASS_MASK) #define PCI_INTERFACE_SHIFT 8 #define PCI_INTERFACE_MASK 0xff #define PCI_INTERFACE(cr) \ (((cr) >> PCI_INTERFACE_SHIFT) & PCI_INTERFACE_MASK) #define PCI_REVISION_SHIFT 0 #define PCI_REVISION_MASK 0xff #define PCI_REVISION(cr) \ (((cr) >> PCI_REVISION_SHIFT) & PCI_REVISION_MASK) #define PCI_CLASS_CODE(mainclass, subclass, interface) \ ((((mainclass) & PCI_CLASS_MASK) << PCI_CLASS_SHIFT) | \ (((subclass) & PCI_SUBCLASS_MASK) << PCI_SUBCLASS_SHIFT) | \ (((interface) & PCI_INTERFACE_MASK) << PCI_INTERFACE_SHIFT)) /* base classes */ #define PCI_CLASS_PREHISTORIC 0x00 #define PCI_CLASS_MASS_STORAGE 0x01 #define PCI_CLASS_NETWORK 0x02 #define PCI_CLASS_DISPLAY 0x03 #define PCI_CLASS_MULTIMEDIA 0x04 #define PCI_CLASS_MEMORY 0x05 #define PCI_CLASS_BRIDGE 0x06 #define PCI_CLASS_COMMUNICATIONS 0x07 #define PCI_CLASS_SYSTEM 0x08 #define PCI_CLASS_INPUT 0x09 #define PCI_CLASS_DOCK 0x0a #define PCI_CLASS_PROCESSOR 0x0b #define PCI_CLASS_SERIALBUS 0x0c #define PCI_CLASS_WIRELESS 0x0d #define PCI_CLASS_I2O 0x0e #define PCI_CLASS_SATCOM 0x0f #define PCI_CLASS_CRYPTO 0x10 #define PCI_CLASS_DASP 0x11 #define PCI_CLASS_UNDEFINED 0xff /* 0x00 prehistoric subclasses */ #define PCI_SUBCLASS_PREHISTORIC_MISC 0x00 #define PCI_SUBCLASS_PREHISTORIC_VGA 0x01 /* 0x01 mass storage subclasses */ #define PCI_SUBCLASS_MASS_STORAGE_SCSI 0x00 #define PCI_SUBCLASS_MASS_STORAGE_IDE 0x01 #define PCI_SUBCLASS_MASS_STORAGE_FLOPPY 0x02 #define PCI_SUBCLASS_MASS_STORAGE_IPI 0x03 #define PCI_SUBCLASS_MASS_STORAGE_RAID 0x04 #define PCI_SUBCLASS_MASS_STORAGE_ATA 0x05 #define PCI_SUBCLASS_MASS_STORAGE_MISC 0x80 /* 0x02 network subclasses */ #define PCI_SUBCLASS_NETWORK_ETHERNET 0x00 #define PCI_SUBCLASS_NETWORK_TOKENRING 0x01 #define PCI_SUBCLASS_NETWORK_FDDI 0x02 #define PCI_SUBCLASS_NETWORK_ATM 0x03 #define PCI_SUBCLASS_NETWORK_ISDN 0x04 #define PCI_SUBCLASS_NETWORK_WORLDFIP 0x05 #define PCI_SUBCLASS_NETWORK_PCIMGMULTICOMP 0x06 #define PCI_SUBCLASS_NETWORK_MISC 0x80 /* 0x03 display subclasses */ #define PCI_SUBCLASS_DISPLAY_VGA 0x00 #define PCI_SUBCLASS_DISPLAY_XGA 0x01 #define PCI_SUBCLASS_DISPLAY_3D 0x02 #define PCI_SUBCLASS_DISPLAY_MISC 0x80 /* 0x04 multimedia subclasses */ #define PCI_SUBCLASS_MULTIMEDIA_VIDEO 0x00 #define PCI_SUBCLASS_MULTIMEDIA_AUDIO 0x01 #define PCI_SUBCLASS_MULTIMEDIA_TELEPHONY 0x02 #define PCI_SUBCLASS_MULTIMEDIA_MISC 0x80 /* 0x05 memory subclasses */ #define PCI_SUBCLASS_MEMORY_RAM 0x00 #define PCI_SUBCLASS_MEMORY_FLASH 0x01 #define PCI_SUBCLASS_MEMORY_MISC 0x80 /* 0x06 bridge subclasses */ #define PCI_SUBCLASS_BRIDGE_HOST 0x00 #define PCI_SUBCLASS_BRIDGE_ISA 0x01 #define PCI_SUBCLASS_BRIDGE_EISA 0x02 #define PCI_SUBCLASS_BRIDGE_MC 0x03 /* XXX _MCA? */ #define PCI_SUBCLASS_BRIDGE_PCI 0x04 #define PCI_SUBCLASS_BRIDGE_PCMCIA 0x05 #define PCI_SUBCLASS_BRIDGE_NUBUS 0x06 #define PCI_SUBCLASS_BRIDGE_CARDBUS 0x07 #define PCI_SUBCLASS_BRIDGE_RACEWAY 0x08 #define PCI_SUBCLASS_BRIDGE_STPCI 0x09 #define PCI_SUBCLASS_BRIDGE_INFINIBAND 0x0a #define PCI_SUBCLASS_BRIDGE_MISC 0x80 /* 0x07 communications subclasses */ #define PCI_SUBCLASS_COMMUNICATIONS_SERIAL 0x00 #define PCI_SUBCLASS_COMMUNICATIONS_PARALLEL 0x01 #define PCI_SUBCLASS_COMMUNICATIONS_MPSERIAL 0x02 #define PCI_SUBCLASS_COMMUNICATIONS_MODEM 0x03 #define PCI_SUBCLASS_COMMUNICATIONS_GPIB 0x04 #define PCI_SUBCLASS_COMMUNICATIONS_SMARTCARD 0x05 #define PCI_SUBCLASS_COMMUNICATIONS_MISC 0x80 /* 0x08 system subclasses */ #define PCI_SUBCLASS_SYSTEM_PIC 0x00 #define PCI_SUBCLASS_SYSTEM_DMA 0x01 #define PCI_SUBCLASS_SYSTEM_TIMER 0x02 #define PCI_SUBCLASS_SYSTEM_RTC 0x03 #define PCI_SUBCLASS_SYSTEM_PCIHOTPLUG 0x04 #define PCI_SUBCLASS_SYSTEM_MISC 0x80 /* 0x09 input subclasses */ #define PCI_SUBCLASS_INPUT_KEYBOARD 0x00 #define PCI_SUBCLASS_INPUT_DIGITIZER 0x01 #define PCI_SUBCLASS_INPUT_MOUSE 0x02 #define PCI_SUBCLASS_INPUT_SCANNER 0x03 #define PCI_SUBCLASS_INPUT_GAMEPORT 0x04 #define PCI_SUBCLASS_INPUT_MISC 0x80 /* 0x0a dock subclasses */ #define PCI_SUBCLASS_DOCK_GENERIC 0x00 #define PCI_SUBCLASS_DOCK_MISC 0x80 /* 0x0b processor subclasses */ #define PCI_SUBCLASS_PROCESSOR_386 0x00 #define PCI_SUBCLASS_PROCESSOR_486 0x01 #define PCI_SUBCLASS_PROCESSOR_PENTIUM 0x02 #define PCI_SUBCLASS_PROCESSOR_ALPHA 0x10 #define PCI_SUBCLASS_PROCESSOR_POWERPC 0x20 #define PCI_SUBCLASS_PROCESSOR_MIPS 0x30 #define PCI_SUBCLASS_PROCESSOR_COPROC 0x40 /* 0x0c serial bus subclasses */ #define PCI_SUBCLASS_SERIALBUS_FIREWIRE 0x00 #define PCI_SUBCLASS_SERIALBUS_ACCESS 0x01 #define PCI_SUBCLASS_SERIALBUS_SSA 0x02 #define PCI_SUBCLASS_SERIALBUS_USB 0x03 #define PCI_SUBCLASS_SERIALBUS_FIBER 0x04 /* XXX _FIBRECHANNEL */ #define PCI_SUBCLASS_SERIALBUS_SMBUS 0x05 #define PCI_SUBCLASS_SERIALBUS_INFINIBAND 0x06 #define PCI_SUBCLASS_SERIALBUS_IPMI 0x07 #define PCI_SUBCLASS_SERIALBUS_SERCOS 0x08 #define PCI_SUBCLASS_SERIALBUS_CANBUS 0x09 /* 0x0d wireless subclasses */ #define PCI_SUBCLASS_WIRELESS_IRDA 0x00 #define PCI_SUBCLASS_WIRELESS_CONSUMERIR 0x01 #define PCI_SUBCLASS_WIRELESS_RF 0x10 #define PCI_SUBCLASS_WIRELESS_BLUETOOTH 0x11 #define PCI_SUBCLASS_WIRELESS_BROADBAND 0x12 #define PCI_SUBCLASS_WIRELESS_MISC 0x80 /* 0x0e I2O (Intelligent I/O) subclasses */ #define PCI_SUBCLASS_I2O_STANDARD 0x00 /* 0x0f satellite communication subclasses */ /* PCI_SUBCLASS_SATCOM_??? 0x00 / * XXX ??? */ #define PCI_SUBCLASS_SATCOM_TV 0x01 #define PCI_SUBCLASS_SATCOM_AUDIO 0x02 #define PCI_SUBCLASS_SATCOM_VOICE 0x03 #define PCI_SUBCLASS_SATCOM_DATA 0x04 /* 0x10 encryption/decryption subclasses */ #define PCI_SUBCLASS_CRYPTO_NETCOMP 0x00 #define PCI_SUBCLASS_CRYPTO_ENTERTAINMENT 0x10 #define PCI_SUBCLASS_CRYPTO_MISC 0x80 /* 0x11 data acquisition and signal processing subclasses */ #define PCI_SUBCLASS_DASP_DPIO 0x00 #define PCI_SUBCLASS_DASP_TIMEFREQ 0x01 #define PCI_SUBCLASS_DASP_SYNC 0x10 #define PCI_SUBCLASS_DASP_MGMT 0x20 #define PCI_SUBCLASS_DASP_MISC 0x80 /* * PCI BIST/Header Type/Latency Timer/Cache Line Size Register. */ #define PCI_BHLC_REG 0x0c #define PCI_BIST_SHIFT 24 #define PCI_BIST_MASK 0xff #define PCI_BIST(bhlcr) \ (((bhlcr) >> PCI_BIST_SHIFT) & PCI_BIST_MASK) #define PCI_HDRTYPE_SHIFT 16 #define PCI_HDRTYPE_MASK 0xff #define PCI_HDRTYPE(bhlcr) \ (((bhlcr) >> PCI_HDRTYPE_SHIFT) & PCI_HDRTYPE_MASK) #define PCI_HDRTYPE_TYPE(bhlcr) \ (PCI_HDRTYPE(bhlcr) & 0x7f) #define PCI_HDRTYPE_MULTIFN(bhlcr) \ ((PCI_HDRTYPE(bhlcr) & 0x80) != 0) #define PCI_LATTIMER_SHIFT 8 #define PCI_LATTIMER_MASK 0xff #define PCI_LATTIMER(bhlcr) \ (((bhlcr) >> PCI_LATTIMER_SHIFT) & PCI_LATTIMER_MASK) #define PCI_CACHELINE_SHIFT 0 #define PCI_CACHELINE_MASK 0xff #define PCI_CACHELINE(bhlcr) \ (((bhlcr) >> PCI_CACHELINE_SHIFT) & PCI_CACHELINE_MASK) #define PCI_BHLC_CODE(bist,type,multi,latency,cacheline) \ ((((bist) & PCI_BIST_MASK) << PCI_BIST_SHIFT) | \ (((type) & PCI_HDRTYPE_MASK) << PCI_HDRTYPE_SHIFT) | \ (((multi)?0x80:0) << PCI_HDRTYPE_SHIFT) | \ (((latency) & PCI_LATTIMER_MASK) << PCI_LATTIMER_SHIFT) | \ (((cacheline) & PCI_CACHELINE_MASK) << PCI_CACHELINE_SHIFT)) /* * Mapping registers */ #define PCI_MAPREG_START 0x10 #define PCI_MAPREG_END 0x28 #define PCI_MAPREG_ROM 0x30 #define PCI_MAPREG_PPB_END 0x18 #define PCI_MAPREG_PCB_END 0x14 #define PCI_MAPREG_TYPE(mr) \ ((mr) & PCI_MAPREG_TYPE_MASK) #define PCI_MAPREG_TYPE_MASK 0x00000001 #define PCI_MAPREG_TYPE_MEM 0x00000000 #define PCI_MAPREG_TYPE_IO 0x00000001 #define PCI_MAPREG_ROM_ENABLE 0x00000001 #define PCI_MAPREG_MEM_TYPE(mr) \ ((mr) & PCI_MAPREG_MEM_TYPE_MASK) #define PCI_MAPREG_MEM_TYPE_MASK 0x00000006 #define PCI_MAPREG_MEM_TYPE_32BIT 0x00000000 #define PCI_MAPREG_MEM_TYPE_32BIT_1M 0x00000002 #define PCI_MAPREG_MEM_TYPE_64BIT 0x00000004 #define PCI_MAPREG_MEM_PREFETCHABLE(mr) \ (((mr) & PCI_MAPREG_MEM_PREFETCHABLE_MASK) != 0) #define PCI_MAPREG_MEM_PREFETCHABLE_MASK 0x00000008 #define PCI_MAPREG_MEM_ADDR(mr) \ ((mr) & PCI_MAPREG_MEM_ADDR_MASK) #define PCI_MAPREG_MEM_SIZE(mr) \ (PCI_MAPREG_MEM_ADDR(mr) & -PCI_MAPREG_MEM_ADDR(mr)) #define PCI_MAPREG_MEM_ADDR_MASK 0xfffffff0 #define PCI_MAPREG_MEM64_ADDR(mr) \ ((mr) & PCI_MAPREG_MEM64_ADDR_MASK) #define PCI_MAPREG_MEM64_SIZE(mr) \ (PCI_MAPREG_MEM64_ADDR(mr) & -PCI_MAPREG_MEM64_ADDR(mr)) #define PCI_MAPREG_MEM64_ADDR_MASK 0xfffffffffffffff0ULL #define PCI_MAPREG_IO_ADDR(mr) \ ((mr) & PCI_MAPREG_IO_ADDR_MASK) #define PCI_MAPREG_IO_SIZE(mr) \ (PCI_MAPREG_IO_ADDR(mr) & -PCI_MAPREG_IO_ADDR(mr)) #define PCI_MAPREG_IO_ADDR_MASK 0xfffffffc #define PCI_MAPREG_SIZE_TO_MASK(size) \ (-(size)) #define PCI_MAPREG_NUM(offset) \ (((unsigned)(offset)-PCI_MAPREG_START)/4) /* * Cardbus CIS pointer (PCI rev. 2.1) */ #define PCI_CARDBUS_CIS_REG 0x28 /* * Subsystem identification register; contains a vendor ID and a device ID. * Types/macros for PCI_ID_REG apply. * (PCI rev. 2.1) */ #define PCI_SUBSYS_ID_REG 0x2c /* * capabilities link list (PCI rev. 2.2) */ #define PCI_CAPLISTPTR_REG 0x34 /* header type 0 */ #define PCI_CARDBUS_CAPLISTPTR_REG 0x14 /* header type 2 */ #define PCI_CAPLIST_PTR(cpr) ((cpr) & 0xff) #define PCI_CAPLIST_NEXT(cr) (((cr) >> 8) & 0xff) #define PCI_CAPLIST_CAP(cr) ((cr) & 0xff) #define PCI_CAP_RESERVED0 0x00 #define PCI_CAP_PWRMGMT 0x01 #define PCI_CAP_AGP 0x02 #define PCI_CAP_VPD 0x03 #define PCI_CAP_SLOTID 0x04 #define PCI_CAP_MBI 0x05 #define PCI_CAP_CPCI_HOTSWAP 0x06 #define PCI_CAP_PCIX 0x07 #define PCI_CAP_LDT 0x08 #define PCI_CAP_VENDSPEC 0x09 #define PCI_CAP_DEBUGPORT 0x0a #define PCI_CAP_CPCI_RSRCCTL 0x0b #define PCI_CAP_HOTPLUG 0x0c /* * Power Management Control Status Register; access via capability pointer. */ #define PCI_PMCSR_STATE_MASK 0x03 #define PCI_PMCSR_STATE_D0 0x00 #define PCI_PMCSR_STATE_D1 0x01 #define PCI_PMCSR_STATE_D2 0x02 #define PCI_PMCSR_STATE_D3 0x03 /* * Interrupt Configuration Register; contains interrupt pin and line. */ #define PCI_INTERRUPT_REG 0x3c typedef u_int8_t pci_intr_latency_t; typedef u_int8_t pci_intr_grant_t; typedef u_int8_t pci_intr_pin_t; typedef u_int8_t pci_intr_line_t; #define PCI_MAX_LAT_SHIFT 24 #define PCI_MAX_LAT_MASK 0xff #define PCI_MAX_LAT(icr) \ (((icr) >> PCI_MAX_LAT_SHIFT) & PCI_MAX_LAT_MASK) #define PCI_MIN_GNT_SHIFT 16 #define PCI_MIN_GNT_MASK 0xff #define PCI_MIN_GNT(icr) \ (((icr) >> PCI_MIN_GNT_SHIFT) & PCI_MIN_GNT_MASK) #define PCI_INTERRUPT_GRANT_SHIFT 24 #define PCI_INTERRUPT_GRANT_MASK 0xff #define PCI_INTERRUPT_GRANT(icr) \ (((icr) >> PCI_INTERRUPT_GRANT_SHIFT) & PCI_INTERRUPT_GRANT_MASK) #define PCI_INTERRUPT_LATENCY_SHIFT 16 #define PCI_INTERRUPT_LATENCY_MASK 0xff #define PCI_INTERRUPT_LATENCY(icr) \ (((icr) >> PCI_INTERRUPT_LATENCY_SHIFT) & PCI_INTERRUPT_LATENCY_MASK) #define PCI_INTERRUPT_PIN_SHIFT 8 #define PCI_INTERRUPT_PIN_MASK 0xff #define PCI_INTERRUPT_PIN(icr) \ (((icr) >> PCI_INTERRUPT_PIN_SHIFT) & PCI_INTERRUPT_PIN_MASK) #define PCI_INTERRUPT_LINE_SHIFT 0 #define PCI_INTERRUPT_LINE_MASK 0xff #define PCI_INTERRUPT_LINE(icr) \ (((icr) >> PCI_INTERRUPT_LINE_SHIFT) & PCI_INTERRUPT_LINE_MASK) #define PCI_INTERRUPT_CODE(lat,gnt,pin,line) \ ((((lat)&PCI_INTERRUPT_LATENCY_MASK)<> 3) & 0xf) #define PCI_VPDRES_LARGE_NAME(x) ((x) & 0x7f) #define PCI_VPDRES_TYPE_COMPATIBLE_DEVICE_ID 0x3 /* small */ #define PCI_VPDRES_TYPE_VENDOR_DEFINED 0xe /* small */ #define PCI_VPDRES_TYPE_END_TAG 0xf /* small */ #define PCI_VPDRES_TYPE_IDENTIFIER_STRING 0x02 /* large */ #define PCI_VPDRES_TYPE_VPD 0x10 /* large */ struct pci_vpd { uint8_t vpd_key0; uint8_t vpd_key1; uint8_t vpd_len; /* length of data only */ /* Actual data. */ } __attribute__((__packed__)); /* * Recommended VPD fields: * * PN Part number of assembly * FN FRU part number * EC EC level of assembly * MN Manufacture ID * SN Serial Number * * Conditionally recommended VPD fields: * * LI Load ID * RL ROM Level * RM Alterable ROM Level * NA Network Address * DD Device Driver Level * DG Diagnostic Level * LL Loadable Microcode Level * VI Vendor ID/Device ID * FU Function Number * SI Subsystem Vendor ID/Subsystem ID * * Additional VPD fields: * * Z0-ZZ User/Product Specific */ #endif /* _DEV_PCI_PCIREG_H_ */ gxemul-0.6.1/src/include/thirdparty/dp83932reg.h000644 001750 001750 00000027316 13402411502 021525 0ustar00debugdebug000000 000000 /* gxemul: $Id: dp83932reg.h,v 1.3 2005-03-05 12:34:02 debug Exp $ */ /* $NetBSD: dp83932reg.h,v 1.2 2002/05/03 00:07:02 thorpej Exp $ */ #ifndef _DEV_IC_DP83932REG_H_ #define _DEV_IC_DP83932REG_H_ #ifdef __attribute__ #undef __attribute__ #endif #ifdef __noreturn__ #undef __noreturn__ #endif #define __attribute__(x) /* */ #define __noreturn__ /* */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Register description for the National Semiconductor DP83932 * Systems-Oriented Network Interface Controller (SONIC). */ /* * SONIC Receive Descriptor Area. */ struct sonic_rda16 { uint16_t rda_status; uint16_t rda_bytecount; uint16_t rda_pkt_ptr0; uint16_t rda_pkt_ptr1; uint16_t rda_seqno; uint16_t rda_link; uint16_t rda_inuse; } __attribute__((__packed__)); struct sonic_rda32 { uint32_t rda_status; uint32_t rda_bytecount; uint32_t rda_pkt_ptr0; uint32_t rda_pkt_ptr1; uint32_t rda_seqno; uint32_t rda_link; uint32_t rda_inuse; } __attribute__((__packed__)); #define RDA_SEQNO_RBA(x) (((x) >> 8) & 0xff) #define RDA_SEQNO_RSN(x) ((x) & 0xff) #define RDA_LINK_EOL 0x01 /* end-of-list */ /* * SONIC Receive Resource Area. * * Note, in 32-bit mode, Rx buffers must be aligned to 32-bit * boundaries, and in 16-bit mode, to 16-bit boundaries. * * Also note the `word count' is always in units of 16-bit words. */ struct sonic_rra16 { uint16_t rra_ptr0; uint16_t rra_ptr1; uint16_t rra_wc0; uint16_t rra_wc1; } __attribute__((__packed__)); struct sonic_rra32 { uint32_t rra_ptr0; uint32_t rra_ptr1; uint32_t rra_wc0; uint32_t rra_wc1; } __attribute__((__packed__)); /* * SONIC Transmit Descriptor Area * * Note the number of fragments defined here is arbitrary. */ #define SONIC_NTXFRAGS 16 struct sonic_frag16 { uint16_t frag_ptr0; uint16_t frag_ptr1; uint16_t frag_size; } __attribute__((__packed__)); struct sonic_frag32 { uint32_t frag_ptr0; uint32_t frag_ptr1; uint32_t frag_size; } __attribute__((__packed__)); /* * Note the frag after the last frag is used to link up to the * next descriptor. */ struct sonic_tda16 { uint16_t tda_status; uint16_t tda_pktconfig; uint16_t tda_pktsize; uint16_t tda_fragcnt; struct sonic_frag16 tda_frags[SONIC_NTXFRAGS + 1]; #if 0 uint16_t tda_link; #endif } __attribute__((__packed__)); struct sonic_tda32 { uint32_t tda_status; uint32_t tda_pktconfig; uint32_t tda_pktsize; uint32_t tda_fragcnt; struct sonic_frag32 tda_frags[SONIC_NTXFRAGS + 1]; #if 0 uint32_t tda_link; #endif } __attribute__((__packed__)); #define TDA_STATUS_NCOL(x) (((x) >> 11) & 0x1f) #define TDA_LINK_EOL 0x01 /* end-of-list */ /* * SONIC CAM Descriptor Area. */ struct sonic_cda16 { uint16_t cda_entry; uint16_t cda_addr0; uint16_t cda_addr1; uint16_t cda_addr2; } __attribute__((__packed__)); struct sonic_cda32 { uint32_t cda_entry; uint32_t cda_addr0; uint32_t cda_addr1; uint32_t cda_addr2; } __attribute__((__packed__)); /* * SONIC register file. * * NOTE: We define these as indices, and use a register map to deal * with different address strides. */ #define SONIC_CR 0x00 /* Command Register */ #define CR_HTX (1U << 0) /* Halt Transmission */ #define CR_TXP (1U << 1) /* Transmit Packets */ #define CR_RXDIS (1U << 2) /* Receiver Disable */ #define CR_RXEN (1U << 3) /* Receiver Enable */ #define CR_STP (1U << 4) /* Stop Timer */ #define CR_ST (1U << 5) /* Start Timer */ #define CR_RST (1U << 7) /* Software Reset */ #define CR_RRRA (1U << 8) /* Read RRA */ #define CR_LCAM (1U << 9) /* Load CAM */ #define SONIC_DCR 0x01 /* Data Configuration Register */ #define DCR_TFT0 (1U << 0) /* Transmit FIFO Threshold (lo) */ #define DCR_TFT1 (1U << 1) /* Transmit FIFO Threshold (hi) */ #define DCR_RFT0 (1U << 2) /* Receive FIFO Threshold (lo) */ #define DCR_RFT1 (1U << 3) /* Receive FIFO Threshold (hi) */ #define DCR_BMS (1U << 4) /* Block Mode Select for DMA */ #define DCR_DW (1U << 5) /* Data Width Select */ #define DCR_WC0 (1U << 6) /* Wait State Control (lo) */ #define DCR_WC1 (1U << 7) /* Wait State Control (hi) */ #define DCR_USR0 (1U << 8) /* User Definable Pin 0 */ #define DCR_USR1 (1U << 9) /* User Definable Pin 1 */ #define DCR_SBUS (1U << 10) /* Synchronous Bus Mode */ #define DCR_PO0 (1U << 11) /* Programmable Output 0 */ #define DCR_PO1 (1U << 12) /* Programmable Output 1 */ #define DCR_LBR (1U << 13) /* Latched Bus Retry */ #define DCR_EXBUS (1U << 15) /* Extended Bus Mode */ #define SONIC_RCR 0x02 /* Receive Control Register */ #define RCR_PRX (1U << 0) /* Packet Received OK */ #define RCR_LBK (1U << 1) /* Loopback Packet Received */ #define RCR_FAER (1U << 2) /* Frame Alignment Error */ #define RCR_CRCR (1U << 3) /* CRC Error */ #define RCR_COL (1U << 4) /* Collision Activity */ #define RCR_CRS (1U << 5) /* Carrier Sense Activity */ #define RCR_LPKT (1U << 6) /* Last Packet in RBA */ #define RCR_BC (1U << 7) /* Broadcast Packet Received */ #define RCR_MC (1U << 8) /* Multicast Packet Received */ #define RCR_LB0 (1U << 9) /* Loopback Control 0 */ #define RCR_LB1 (1U << 10) /* Loopback Control 1 */ #define RCR_AMC (1U << 11) /* Accept All Multicast Packets */ #define RCR_PRO (1U << 12) /* Physical Promiscuous Packets */ #define RCR_BRD (1U << 13) /* Accept Broadcast Packets */ #define RCR_RNT (1U << 14) /* Accept Runt Packets */ #define RCR_ERR (1U << 15) /* Accept Packets with Errors */ #define SONIC_TCR 0x03 /* Transmit Control Register */ #define TCR_PTX (1U << 0) /* Packet Transmitted OK */ #define TCR_BCM (1U << 1) /* Byte Count Mismatch */ #define TCR_FU (1U << 2) /* FIFO Underrun */ #define TCR_PMB (1U << 3) /* Packet Monitored Bad */ #define TCR_OWC (1U << 5) /* Out of Window Collision */ #define TCR_EXC (1U << 6) /* Excessive Collisions */ #define TCR_CRSL (1U << 7) /* Carrier Sense Lost */ #define TCR_NCRS (1U << 8) /* No Carrier Sense */ #define TCR_DEF (1U << 9) /* Deferred Transmission */ #define TCR_EXD (1U << 10) /* Excessive Deferral */ #define TCR_EXDIS (1U << 12) /* Disable Excessive Deferral Timer */ #define TCR_CRCI (1U << 13) /* CRC Inhibit */ #define TCR_POWC (1U << 14) /* Programmed Out of Window Col. Tmr */ #define TCR_PINT (1U << 15) /* Programmable Interrupt */ #define SONIC_IMR 0x04 /* Interrupt Mask Register */ #define IMR_RFO (1U << 0) /* Rx FIFO Overrun */ #define IMR_MP (1U << 1) /* Missed Packet Tally */ #define IMR_FAE (1U << 2) /* Frame Alignment Error Tally */ #define IMR_CRC (1U << 3) /* CRC Tally */ #define IMR_RBA (1U << 4) /* RBA Exceeded */ #define IMR_RBE (1U << 5) /* Rx Buffers Exhausted */ #define IMR_RDE (1U << 6) /* Rx Descriptors Exhausted */ #define IMR_TC (1U << 7) /* Timer Complete */ #define IMR_TXER (1U << 8) /* Transmit Error */ #define IMR_PTX (1U << 9) /* Transmit OK */ #define IMR_PRX (1U << 10) /* Packet Received */ #define IMR_PINT (1U << 11) /* Programmable Interrupt */ #define IMR_LCD (1U << 12) /* Load CAM Done */ #define IMR_HBL (1U << 13) /* Heartbeat Lost */ #define IMR_BR (1U << 14) /* Bus Retry Occurred */ #define SONIC_ISR 0x05 /* Interrupt Status Register */ /* See IMR bits. */ #define SONIC_UTDAR 0x06 /* Upper Tx Descriptor Adress Register */ #define SONIC_CTDAR 0x07 /* Current Tx Descriptor Address Register */ #define SONIC_TPS 0x08 /* Transmit Packet Size */ #define SONIC_TFC 0x09 /* Transmit Fragment Count */ #define SONIC_TSA0 0x0a /* Transmit Start Address (lo) */ #define SONIC_TSA1 0x0b /* Transmit Start Address (hi) */ #define SONIC_TFS 0x0c /* Transmit Fragment Size */ #define SONIC_URDAR 0x0d /* Upper Rx Descriptor Address Register */ #define SONIC_CRDAR 0x0e /* Current Rx Descriptor Address Register */ #define SONIC_CRBA0 0x0f /* Current Receive Buffer Address (lo) */ #define SONIC_CRBA1 0x10 /* Current Receive Buffer Address (hi) */ #define SONIC_RBWC0 0x11 /* Remaining Buffer Word Count 0 */ #define SONIC_RBWC1 0x12 /* Remaining Buffer Word Count 1 */ #define SONIC_EOBC 0x13 /* End Of Buffer Word Count */ #define SONIC_URRAR 0x14 /* Upper Rx Resource Address Register */ #define SONIC_RSAR 0x15 /* Resource Start Address Register */ #define SONIC_REAR 0x16 /* Resource End Address Register */ #define SONIC_RRR 0x17 /* Resource Read Register */ #define SONIC_RWR 0x18 /* Resource Write Register */ #define SONIC_TRBA0 0x19 /* Temporary Receive Buffer Address (lo) */ #define SONIC_TRBA1 0x1a /* Temporary Receive Buffer Address (hi) */ #define SONIC_TBWC0 0x1b /* Temporary Buffer Word Count 0 */ #define SONIC_TBWC1 0x1c /* Temporary Buffer Word Count 1 */ #define SONIC_ADDR0 0x1d /* Address Generator 0 */ #define SONIC_ADDR1 0x1e /* Address Generator 1 */ #define SONIC_LLFA 0x1f /* Last Link Field Address */ #define SONIC_TTDA 0x20 /* Temporary Tx Descriptor Address */ #define SONIC_CEP 0x21 /* CAM Entry Pointer */ #define SONIC_CAP2 0x22 /* CAM Address Port 2 */ #define SONIC_CAP1 0x23 /* CAM Address Port 1 */ #define SONIC_CAP0 0x24 /* CAM Address Port 0 */ #define SONIC_CER 0x25 /* CAM Enable Register */ #define SONIC_CDP 0x26 /* CAM Descriptor Pointer */ #define SONIC_CDC 0x27 /* CAM Descriptor Count */ #define SONIC_SRR 0x28 /* Silicon Revision Register */ #define SONIC_WT0 0x29 /* Watchdog Timer 0 */ #define SONIC_WT1 0x2a /* Watchdog Timer 1 */ #define SONIC_RSC 0x2b /* Receive Sequence Counter */ #define SONIC_CRCETC 0x2c /* CRC Error Tally Count */ #define SONIC_FAET 0x2d /* Frame Alignment Error Tally */ #define SONIC_MPT 0x2e /* Missed Packet Tally */ #define SONIC_DCR2 0x3f /* Data Configuration Register 2 */ #define DCR2_RJCM (1U << 0) /* Reject on CAM Match */ #define DCR2_PCNM (1U << 1) /* Packet Compress When not Matched */ #define DCR2_PCM (1U << 2) /* Packet Compress When Matched */ #define DCR2_PH (1U << 4) /* Program Hold */ #define DCR2_EXPO0 (1U << 12) /* Extended Programmable Output 0 */ #define DCR2_EXPO1 (1U << 13) /* Extended Programmable Output 1 */ #define DCR2_EXPO2 (1U << 14) /* Extended Programmable Output 2 */ #define DCR2_EXPO3 (1U << 15) /* Extended Programmable Output 3 */ #define SONIC_NREGS 0x40 #endif /* _DEV_IC_DP83932REG_H_ */ gxemul-0.6.1/src/include/thirdparty/iopi2creg.h000644 001750 001750 00000007351 13402411502 021673 0ustar00debugdebug000000 000000 /* $NetBSD: iopi2creg.h,v 1.2 2005/12/11 12:16:51 christos Exp $ */ /* * Copyright (c) 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _ARM_XSCALE_IOPIICREG_H_ #define _ARM_XSCALE_IOPIICREG_H_ #define IIC_ICR 0x00 /* i2c control register */ #define IIC_ISR 0x04 /* i2c status register */ #define IIC_ISAR 0x08 /* i2c slave address register */ #define IIC_IDBR 0x0c /* i2c data buffer register */ #define IIC_ICCR 0x10 /* i2c clock control register (i80312 only) */ #define IIC_IBMR 0x14 /* i2c bus monitor register */ #define IIC_ICR_FM (1U << 15) /* fast mode (i80321 only) */ #define IIC_ICR_RESET (1U << 14) /* i2c unit reset */ #define IIC_ICR_SADIE (1U << 13) /* slave addr det int en */ #define IIC_ICR_ALDIE (1U << 12) /* arb loss det int en */ #define IIC_ICR_SSDIE (1U << 11) /* slave stop det in en */ #define IIC_ICR_BEIE (1U << 10) /* bus error int en */ #define IIC_ICR_IRFIE (1U << 9) /* IDBR Rx full int en */ #define IIC_ICR_ITEIE (1U << 8) /* IDBR Tx empty int en */ #define IIC_ICR_GCD (1U << 7) /* general call disable */ #define IIC_ICR_UE (1U << 6) /* i2c unit enable */ #define IIC_ICR_SCLE (1U << 5) /* SCL master enable */ #define IIC_ICR_MA (1U << 4) /* abort as master */ #define IIC_ICR_TB (1U << 3) /* transfer byte */ #define IIC_ICR_NACK (1U << 2) /* 0=ACK, 1=NACK */ #define IIC_ICR_STOP (1U << 1) /* initiate STOP condition */ #define IIC_ICR_START (1U << 0) /* initiate START condition */ #define IIC_ISR_BED (1U << 10) /* bus error detected */ #define IIC_ISR_SAD (1U << 9) /* slave address detected */ #define IIC_ISR_GCAD (1U << 8) /* general call addr detected */ #define IIC_ISR_IRF (1U << 7) /* IDBR Rx full */ #define IIC_ISR_ITE (1U << 6) /* IDBR Tx empty */ #define IIC_ISR_ALD (1U << 5) /* arb loss detected */ #define IIC_ISR_SSD (1U << 4) /* slave STOP detected */ #define IIC_ISR_IBB (1U << 3) /* i2c bus busy */ #define IIC_ISR_UB (1U << 2) /* unit busy */ #define IIC_ISR_NACK (1U << 1) /* NACK received */ #define IIC_ISR_RW (1U << 0) /* 0=mt/sr, 1=mr/st */ #endif /* _ARM_XSCALE_IOPIICREG_H_ */ gxemul-0.6.1/src/include/thirdparty/yamon.h000644 001750 001750 00000007746 13402411502 021143 0ustar00debugdebug000000 000000 /* $NetBSD: yamon.h,v 1.3 2005/06/09 21:43:13 he Exp $ */ #ifndef _MIPS_YAMON_YAMON_H_ #define _MIPS_YAMON_YAMON_H_ /* * Copyright 2002 Wasabi Systems, Inc. * All rights reserved. * * Written by Simon Burge for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* XXX move to arch/mips/yamon/yamon.h or similar? */ #define YAMON_FUNCTION_BASE 0x1fc00500 #define YAMON_PRINT_COUNT_OFS (YAMON_FUNCTION_BASE + 0x04) #define YAMON_EXIT_OFS (YAMON_FUNCTION_BASE + 0x20) #define YAMON_FLUSH_CACHE_OFS (YAMON_FUNCTION_BASE + 0x2c) #define YAMON_PRINT_OFS (YAMON_FUNCTION_BASE + 0x34) #define YAMON_REG_CPU_ISR_OFS (YAMON_FUNCTION_BASE + 0x38) #define YAMON_DEREG_CPU_ISR_OFS (YAMON_FUNCTION_BASE + 0x3c) #define YAMON_REG_IC_ISR_OFS (YAMON_FUNCTION_BASE + 0x40) #define YAMON_DEREG_IC_ISR_OFS (YAMON_FUNCTION_BASE + 0x44) #define YAMON_REG_ESR_OFS (YAMON_FUNCTION_BASE + 0x48) #define YAMON_DEREG_ESR_OFS (YAMON_FUNCTION_BASE + 0x4c) #define YAMON_GETCHAR_OFS (YAMON_FUNCTION_BASE + 0x50) #define YAMON_SYSCON_READ_OFS (YAMON_FUNCTION_BASE + 0x54) #if 0 #define YAMON_FUNC(ofs) (*(uint32_t *)(MIPS_PHYS_TO_KSEG0(ofs))) typedef void (*t_yamon_print_count)(uint32_t port, char *s, uint32_t count); #define YAMON_PRINT_COUNT(s, count) \ ((t_yamon_print_count)(YAMON_FUNC(YAMON_PRINT_COUNT_OFS)))(0, s, count) typedef void (*t_yamon_exit)(uint32_t rc); #define YAMON_EXIT(rc) ((t_yamon_exit)(YAMON_FUNC(YAMON_EXIT_OFS)))(rc) typedef void (*t_yamon_print)(uint32_t port, char *s); #define YAMON_PRINT(s) ((t_yamon_print)(YAMON_FUNC(YAMON_PRINT_OFS)))(0, s) typedef int (*t_yamon_getchar)(uint32_t port, char *ch); #define YAMON_GETCHAR(ch) \ ((t_yamon_getchar)(YAMON_FUNC(YAMON_GETCHAR_OFS)))(0, ch) typedef int t_yamon_syscon_id; typedef int (*t_yamon_syscon_read)(t_yamon_syscon_id id, void *param, uint32_t size); #define YAMON_SYSCON_READ(id, param, size) \ ((t_yamon_syscon_read)(YAMON_FUNC(YAMON_SYSCON_READ_OFS)))\ (id, param, size) typedef struct { char *name; char *val; } yamon_env_var; #endif #define SYSCON_BOARD_CPU_CLOCK_FREQ_ID 34 /* UINT32 */ #define SYSCON_BOARD_BUS_CLOCK_FREQ_ID 35 /* UINT32 */ #define SYSCON_BOARD_PCI_FREQ_KHZ_ID 36 /* UINT32 */ #if 0 const char *yamon_getenv(const char *); void yamon_print(char *); void yamon_exit(uint32_t); int yamon_setcpufreq(int); extern yamon_env_var *yamon_envp; extern struct consdev yamon_promcd; #endif #endif /* _MIPS_YAMON_YAMON_H_ */ gxemul-0.6.1/src/include/thirdparty/lk201.h000644 001750 001750 00000030404 13402411502 020634 0ustar00debugdebug000000 000000 /* * This file contains definitions from two files in NetBSD, lk201.h and lk201.c. * * Technical information can be found here: * * https://www.netbsd.org/docs/Hardware/Machines/DEC/lk201.html * * The header file (lk201.h) in NetBSD did not have a separate copyright * notice on it. Possible sources for lk201.h and lk201.c are the old files * http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/arch/pmax/dev/Attic/fb.c?rev=1.1&content-type=text/x-cvsweb-markup * for the scan codes, and * http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/arch/pmax/dev/Attic/fbreg.h?rev=1.1&content-type=text/x-cvsweb-markup * for other control codes, in which case the copyright is/was: * * * Copyright (c) 1992 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * * @(#)fb.c 7.2 (Berkeley) 12/20/92 * and * @(#)fbreg.h 7.1 (Berkeley) 11/15/92 */ #ifndef LK201_H #define LK201_H /* $NetBSD: lk201.h,v 1.7 1999/03/19 18:34:01 ad Exp $ */ /* * Ascii values of command keys. */ #define KBD_TAB '\t' #define KBD_DEL 127 #define KBD_RET '\r' /* * Define "hardware-independent" codes for the control, shift, meta and * function keys. Codes start after the last 7-bit ASCII code (127) * and are assigned in an arbitrary order. */ #define KBD_NOKEY 128 #define KBD_F1 201 #define KBD_F2 202 #define KBD_F3 203 #define KBD_F4 204 #define KBD_F5 205 #define KBD_F6 206 #define KBD_F7 207 #define KBD_F8 208 #define KBD_F9 209 #define KBD_F10 210 #define KBD_F11 211 #define KBD_F12 212 #define KBD_F13 213 #define KBD_F14 214 #define KBD_HELP 215 #define KBD_DO 216 #define KBD_F17 217 #define KBD_F18 218 #define KBD_F19 219 #define KBD_F20 220 #define KBD_FIND 221 #define KBD_INSERT 222 #define KBD_REMOVE 223 #define KBD_SELECT 224 #define KBD_PREVIOUS 225 #define KBD_NEXT 226 #define KBD_KP_ENTER 227 #define KBD_KP_F1 228 #define KBD_KP_F2 229 #define KBD_KP_F3 230 #define KBD_KP_F4 231 #define KBD_LEFT 232 #define KBD_RIGHT 233 #define KBD_DOWN 234 #define KBD_UP 235 #define KBD_CONTROL 236 #define KBD_SHIFT 237 #define KBD_CAPSLOCK 238 #define KBD_ALTERNATE 239 /* * Definitions for the Keyboard and mouse. */ /* * Special key values. */ #define KEY_R_SHIFT 0xab #define KEY_SHIFT 0xae #define KEY_CONTROL 0xaf #define KEY_CAPSLOCK 0xb0 #define KEY_R_ALT 0xb2 #define KEY_UP 0xb3 #define KEY_REPEAT 0xb4 #define KEY_F1 0x56 #define KEY_COMMAND KEY_F1 /* * Lk201/301 keyboard */ #define LK_UPDOWN 0x86 /* bits for setting lk201 modes */ #define LK_AUTODOWN 0x82 #define LK_DOWN 0x80 #define LK_DEFAULTS 0xd3 /* reset mode settings */ #define LK_AR_ENABLE 0xe3 /* global auto repeat enable */ #define LK_CL_ENABLE 0x1b /* keyclick enable */ #define LK_KBD_ENABLE 0x8b /* keyboard enable */ #define LK_BELL_ENABLE 0x23 /* the bell */ #define LK_LED_ENABLE 0x13 /* light led */ #define LK_LED_DISABLE 0x11 /* turn off led */ #define LK_RING_BELL 0xa7 /* ring keyboard bell */ #define LED_1 0x81 /* led bits */ #define LED_2 0x82 #define LED_3 0x84 #define LED_4 0x88 #define LED_ALL 0x8f #define LK_HELP 0x7c /* help key */ #define LK_DO 0x7d /* do key */ #define LK_KDOWN_ERROR 0x3d /* key down on powerup error */ #define LK_POWER_ERROR 0x3e /* keyboard failure on pwrup tst*/ #define LK_OUTPUT_ERROR 0xb5 /* keystrokes lost during inhbt */ #define LK_INPUT_ERROR 0xb6 /* garbage command to keyboard */ #define LK_LOWEST 0x56 /* lowest significant keycode */ /* max volume is 0, lowest is 0x7 */ #define LK_PARAM_VOLUME(v) (0x80|((v)&0x7)) /* mode command details */ #define LK_CMD_MODE(m,div) ((m)|((div)<<3)) /* * Command characters for the mouse. */ #define MOUSE_SELF_TEST 'T' #define MOUSE_INCREMENTAL 'R' /* * Mouse output bits. * * MOUSE_START_FRAME Start of report frame bit. * MOUSE_X_SIGN Sign bit for X. * MOUSE_Y_SIGN Sign bit for Y. * MOUSE_X_OFFSET X offset to start cursor at. * MOUSE_Y_OFFSET Y offset to start cursor at. */ #define MOUSE_START_FRAME 0x80 #define MOUSE_X_SIGN 0x10 #define MOUSE_Y_SIGN 0x08 /* * Definitions for mouse buttons */ #define EVENT_LEFT_BUTTON 0x01 #define EVENT_MIDDLE_BUTTON 0x02 #define EVENT_RIGHT_BUTTON 0x03 #define RIGHT_BUTTON 0x01 #define MIDDLE_BUTTON 0x02 #define LEFT_BUTTON 0x04 #ifdef _KERNEL extern int LKgetc __P((dev_t dev)); extern void lkdivert __P ((int (*getc_fn)(dev_t dev), dev_t dev)); #endif /* This is also from netbsd, pmax/dev/lk201.c: */ /* * Keyboard to ASCII, unshifted. */ static u_char unshiftedAscii[] = { /* 0 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 4 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 8 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 10 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 14 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 18 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 1c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 20 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 24 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 28 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 2c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 30 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 34 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 38 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 3c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 40 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 44 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 48 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 4c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 50 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 54 */ KBD_NOKEY, KBD_NOKEY, KBD_F1, KBD_F2, /* 58 */ KBD_F3, KBD_F4, KBD_F5, KBD_NOKEY, /* 5c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 60 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 64 */ KBD_F6, KBD_F7, KBD_F8, KBD_F9, /* 68 */ KBD_F10, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 6c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 70 */ KBD_NOKEY, '\033', KBD_F12, KBD_F13, /* 74 */ KBD_F14, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 78 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 7c */ KBD_HELP, KBD_DO, KBD_NOKEY, KBD_NOKEY, /* 80 */ KBD_F17, KBD_F18, KBD_F19, KBD_F20, /* 84 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 88 */ KBD_NOKEY, KBD_NOKEY, KBD_FIND, KBD_INSERT, /* 8c */ KBD_REMOVE, KBD_SELECT, KBD_PREVIOUS, KBD_NEXT, /* 90 */ KBD_NOKEY, KBD_NOKEY, '0', KBD_NOKEY, /* 94 */ '.', KBD_KP_ENTER, '1', '2', /* 98 */ '3', '4', '5', '6', /* 9c */ ',', '7', '8', '9', /* a0 */ '-', KBD_KP_F1, KBD_KP_F2, KBD_KP_F3, /* a4 */ KBD_KP_F4, KBD_NOKEY, KBD_NOKEY, KBD_LEFT, /* a8 */ KBD_RIGHT, KBD_DOWN, KBD_UP, KBD_NOKEY, /* ac */ KBD_NOKEY, KBD_NOKEY, KBD_SHIFT, KBD_CONTROL, /* b0 */ KBD_CAPSLOCK, KBD_ALTERNATE, KBD_NOKEY, KBD_NOKEY, /* b4 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* b8 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* bc */ KBD_DEL, KBD_RET, KBD_TAB, '`', /* c0 */ '1', 'q', 'a', 'z', /* c4 */ KBD_NOKEY, '2', 'w', 's', /* c8 */ 'x', '<', KBD_NOKEY, '3', /* cc */ 'e', 'd', 'c', KBD_NOKEY, /* d0 */ '4', 'r', 'f', 'v', /* d4 */ ' ', KBD_NOKEY, '5', 't', /* d8 */ 'g', 'b', KBD_NOKEY, '6', /* dc */ 'y', 'h', 'n', KBD_NOKEY, /* e0 */ '7', 'u', 'j', 'm', /* e4 */ KBD_NOKEY, '8', 'i', 'k', /* e8 */ ',', KBD_NOKEY, '9', 'o', /* ec */ 'l', '.', KBD_NOKEY, '0', /* f0 */ 'p', KBD_NOKEY, ';', '/', /* f4 */ KBD_NOKEY, '=', ']', '\\', /* f8 */ KBD_NOKEY, '-', '[', '\'', /* fc */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, }; /* * Keyboard to Ascii, shifted. */ static u_char shiftedAscii[] = { /* 0 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 4 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 8 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 10 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 14 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 18 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 1c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 20 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 24 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 28 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 2c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 30 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 34 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 38 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 3c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 40 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 44 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 48 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 4c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 50 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 54 */ KBD_NOKEY, KBD_NOKEY, KBD_F1, KBD_F2, /* 58 */ KBD_F3, KBD_F4, KBD_F5, KBD_NOKEY, /* 5c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 60 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 64 */ KBD_F6, KBD_F7, KBD_F8, KBD_F9, /* 68 */ KBD_F10, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 6c */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 70 */ KBD_NOKEY, KBD_F11, KBD_F12, KBD_F13, /* 74 */ KBD_F14, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 78 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 7c */ KBD_HELP, KBD_DO, KBD_NOKEY, KBD_NOKEY, /* 80 */ KBD_F17, KBD_F18, KBD_F19, KBD_F20, /* 84 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* 88 */ KBD_NOKEY, KBD_NOKEY, KBD_FIND, KBD_INSERT, /* 8c */ KBD_REMOVE, KBD_SELECT, KBD_PREVIOUS, KBD_NEXT, /* 90 */ KBD_NOKEY, KBD_NOKEY, '0', KBD_NOKEY, /* 94 */ '.', KBD_KP_ENTER, '1', '2', /* 98 */ '3', '4', '5', '6', /* 9c */ ',', '7', '8', '9', /* a0 */ '-', KBD_KP_F1, KBD_KP_F2, KBD_KP_F3, /* a4 */ KBD_KP_F4, KBD_NOKEY, KBD_NOKEY, KBD_LEFT, /* a8 */ KBD_RIGHT, KBD_DOWN, KBD_UP, KBD_NOKEY, /* ac */ KBD_NOKEY, KBD_NOKEY, KBD_SHIFT, KBD_CONTROL, /* b0 */ KBD_CAPSLOCK, KBD_ALTERNATE, KBD_NOKEY, KBD_NOKEY, /* b4 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* b8 */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, /* bc */ KBD_DEL, KBD_RET, KBD_TAB, '~', /* c0 */ '!', 'q', 'a', 'z', /* c4 */ KBD_NOKEY, '@', 'w', 's', /* c8 */ 'x', '>', KBD_NOKEY, '#', /* cc */ 'e', 'd', 'c', KBD_NOKEY, /* d0 */ '$', 'r', 'f', 'v', /* d4 */ ' ', KBD_NOKEY, '%', 't', /* d8 */ 'g', 'b', KBD_NOKEY, '^', /* dc */ 'y', 'h', 'n', KBD_NOKEY, /* e0 */ '&', 'u', 'j', 'm', /* e4 */ KBD_NOKEY, '*', 'i', 'k', /* e8 */ '<', KBD_NOKEY, '(', 'o', /* ec */ 'l', '>', KBD_NOKEY, ')', /* f0 */ 'p', KBD_NOKEY, ':', '?', /* f4 */ KBD_NOKEY, '+', '}', '|', /* f8 */ KBD_NOKEY, '_', '{', '"', /* fc */ KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, KBD_NOKEY, }; #endif /* LK201_H */ gxemul-0.6.1/src/include/thirdparty/sh4_mmu.h000644 001750 001750 00000014266 13402411502 021367 0ustar00debugdebug000000 000000 /* $NetBSD: mmu_sh4.h,v 1.6 2006/03/04 01:55:03 uwe Exp $ */ #ifndef _SH3_MMU_SH4_H_ #define _SH3_MMU_SH4_H_ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by UCHIYAMA Yasushi. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* #include */ /* ITLB 4-entry full-associative UTLB 64-entry full-associative */ #define SH4_PTEH 0xff000000 #define SH4_PTEH_VPN_MASK 0xfffffc00 #define SH4_PTEH_ASID_MASK 0x000000ff #define SH4_PTEL 0xff000004 #define SH4_PTEL_WT 0x00000001 #define SH4_PTEL_SH 0x00000002 #define SH4_PTEL_D 0x00000004 #define SH4_PTEL_C 0x00000008 #define SH4_PTEL_PR_SHIFT 5 #define SH4_PTEL_PR_MASK 0x00000060 /* [5:6] */ #define SH4_PTEL_SZ_MASK 0x00000090 /* [4][7] */ #define SH4_PTEL_SZ_1K 0x00000000 #define SH4_PTEL_SZ_4K 0x00000010 #define SH4_PTEL_SZ_64K 0x00000080 #define SH4_PTEL_SZ_1M 0x00000090 #define SH4_PTEL_V 0x00000100 #define SH4_PTEL_HWBITS 0x1ffff1ff /* [28:12]PFN [8:0]attr. */ #define SH4_PTEA 0xff000034 #define SH4_PTEA_SA_MASK 0x00000007 #define SH4_PTEA_SA_TC 0x00000008 #define SH4_TTB 0xff000008 #define SH4_TEA 0xff00000c #define SH4_MMUCR 0xff000010 #define SH4_MMUCR_AT 0x00000001 #define SH4_MMUCR_TI 0x00000004 #define SH4_MMUCR_SV 0x00000100 #define SH4_MMUCR_SQMD 0x00000200 #define SH4_MMUCR_URC_SHIFT 10 #define SH4_MMUCR_URC_MASK 0x0000fc00 /* [10:15] */ #define SH4_MMUCR_URB_SHIFT 18 #define SH4_MMUCR_URB_MASK 0x00fc0000 /* [18:23] */ #define SH4_MMUCR_LRUI_SHIFT 26 #define SH4_MMUCR_LRUT_MASK 0xfc000000 /* [26:31] */ #define SH4_MMUCR_MASK (SH4_MMUCR_LRUT_MASK | SH4_MMUCR_URB_MASK | \ SH4_MMUCR_URC_MASK | SH4_MMUCR_SQMD | SH4_MMUCR_SV | SH4_MMUCR_AT) /* * memory-mapped TLB * must be access from P2-area program. * branch to the other area must be maed at least 8 instruction * after access. */ #define SH4_ITLB_ENTRY 4 #define SH4_UTLB_ENTRY 64 /* ITLB */ #define SH4_ITLB_AA 0xf2000000 /* address specification (common for address and data array(0,1)) */ #define SH4_ITLB_E_SHIFT 8 #define SH4_ITLB_E_MASK 0x00000300 /* [9:8] */ /* data specification */ /* address-array */ #define SH4_ITLB_AA_ASID_MASK 0x000000ff /* [7:0] */ #define SH4_ITLB_AA_V 0x00000100 #define SH4_ITLB_AA_VPN_SHIFT 10 #define SH4_ITLB_AA_VPN_MASK 0xfffffc00 /* [31:10] */ /* data-array 1 */ #define SH4_ITLB_DA1 0xf3000000 #define SH4_ITLB_DA1_SH 0x00000002 #define SH4_ITLB_DA1_C 0x00000008 #define SH4_ITLB_DA1_SZ_MASK 0x00000090 /* [7][4] */ #define SH4_ITLB_DA1_SZ_1K 0x00000000 #define SH4_ITLB_DA1_SZ_4K 0x00000010 #define SH4_ITLB_DA1_SZ_64K 0x00000080 #define SH4_ITLB_DA1_SZ_1M 0x00000090 #define SH4_ITLB_DA1_PR 0x00000040 #define SH4_ITLB_DA1_V 0x00000100 #define SH4_ITLB_DA1_PPN_SHIFT 11 #define SH4_ITLB_DA1_PPN_MASK 0x1ffffc00 /* [28:10] */ /* data-array 2 */ #define SH4_ITLB_DA2 0xf3800000 #define SH4_ITLB_DA2_SA_MASK 0x00000003 #define SH4_ITLB_DA2_TC 0x00000004 /* UTLB */ #define SH4_UTLB_AA 0xf6000000 /* address specification (common for address and data array(0,1)) */ #define SH4_UTLB_E_SHIFT 8 #define SH4_UTLB_E_MASK 0x00003f00 #define SH4_UTLB_A 0x00000080 /* data specification */ /* address-array */ #define SH4_UTLB_AA_VPN_MASK 0xfffffc00 /* [31:10] */ #define SH4_UTLB_AA_D 0x00000200 #define SH4_UTLB_AA_V 0x00000100 #define SH4_UTLB_AA_ASID_MASK 0x000000ff /* [7:0] */ /* data-array 1 */ #define SH4_UTLB_DA1 0xf7000000 #define SH4_UTLB_DA1_WT 0x00000001 #define SH4_UTLB_DA1_SH 0x00000002 #define SH4_UTLB_DA1_D 0x00000004 #define SH4_UTLB_DA1_C 0x00000008 #define SH4_UTLB_DA1_SZ_MASK 0x00000090 /* [7][4] */ #define SH4_UTLB_DA1_SZ_1K 0x00000000 #define SH4_UTLB_DA1_SZ_4K 0x00000010 #define SH4_UTLB_DA1_SZ_64K 0x00000080 #define SH4_UTLB_DA1_SZ_1M 0x00000090 #define SH4_UTLB_DA1_PR_SHIFT 5 #define SH4_UTLB_DA1_PR_MASK 0x00000060 #define SH4_UTLB_DA1_V 0x00000100 #define SH4_UTLB_DA1_PPN_SHIFT 11 #define SH4_UTLB_DA1_PPN_MASK 0x1ffffc00 /* [28:10] */ /* data-array 2 */ #define SH4_UTLB_DA2 0xf7800000 #define SH4_UTLB_DA2_SA_MASK 0x00000003 #define SH4_UTLB_DA2_TC 0x00000004 #define SH4_TLB_DISABLE *(volatile uint32_t *)SH4_MMUCR = SH4_MMUCR_TI #endif /* !_SH3_MMU_SH4_H_ */ gxemul-0.6.1/src/include/commands/BackwardStepCommand.h000644 001750 001750 00000004417 13402411502 023270 0ustar00debugdebug000000 000000 #ifndef BACKWARDSTEPCOMMAND_H #define BACKWARDSTEPCOMMAND_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which sets the RunState to BackwardsSingleStepping. */ class BackwardStepCommand : public Command { public: /** * \brief Constructs a %BackwardStepCommand. */ BackwardStepCommand(); virtual ~BackwardStepCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual bool MayBeReexecutedWithoutArgs() const { return true; } virtual string GetShortDescription() const; virtual string GetLongDescription() const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // BACKWARDSTEPCOMMAND_H gxemul-0.6.1/src/include/commands/QuitCommand.h000644 001750 001750 00000004201 13402411502 021627 0ustar00debugdebug000000 000000 #ifndef QUITCOMMAND_H #define QUITCOMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which quits the %GXemul application. */ class QuitCommand : public Command { public: /** * \brief Constructs a %QuitCommand. */ QuitCommand(); virtual ~QuitCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // QUITCOMMAND_H gxemul-0.6.1/src/include/commands/MoveComponentCommand.h000644 001750 001750 00000004352 13402411502 023505 0ustar00debugdebug000000 000000 #ifndef MOVECOMPONENTCOMMAND_H #define MOVECOMPONENTCOMMAND_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which moves a Component from one location to another in * the component tree. */ class MoveComponentCommand : public Command { public: /** * \brief Constructs a %MoveComponentCommand. */ MoveComponentCommand(); virtual ~MoveComponentCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // MOVECOMPONENTCOMMAND_H gxemul-0.6.1/src/include/commands/ContinueBackwardsCommand.h000644 001750 001750 00000004344 13402411502 024323 0ustar00debugdebug000000 000000 #ifndef CONTINUEBACKWARDSCOMMAND_H #define CONTINUEBACKWARDSCOMMAND_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which sets the RunState to BackwardsRunning. */ class ContinueBackwardsCommand : public Command { public: /** * \brief Constructs a %ContinueBackwardsCommand. */ ContinueBackwardsCommand(); virtual ~ContinueBackwardsCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // CONTINUEBACKWARDSCOMMAND_H gxemul-0.6.1/src/include/commands/StatusCommand.h000644 001750 001750 00000004100 13402411502 022166 0ustar00debugdebug000000 000000 #ifndef STATUSCOMMAND_H #define STATUSCOMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which prints the current status. * * The status includes the RunState (Running or Paused). */ class StatusCommand : public Command { public: /** * \brief Constructs a %StatusCommand. */ StatusCommand(); virtual ~StatusCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; }; #endif // STATUSCOMMAND_H gxemul-0.6.1/src/include/commands/ListComponentsCommand.h000644 001750 001750 00000004101 13402411502 023665 0ustar00debugdebug000000 000000 #ifndef LISTCOMPONENTSCOMMAND_H #define LISTCOMPONENTSCOMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which lists all available components. */ class ListComponentsCommand : public Command { public: /** * \brief Constructs a %ListComponentsCommand. */ ListComponentsCommand(); virtual ~ListComponentsCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; }; #endif // LISTCOMPONENTSCOMMAND_H gxemul-0.6.1/src/include/commands/AddComponentCommand.h000644 001750 001750 00000004134 13402411502 023265 0ustar00debugdebug000000 000000 #ifndef ADDCOMPONENTCOMMAND_H #define ADDCOMPONENTCOMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which adds a Component to some place in a GXemul * instance' component tree. */ class AddComponentCommand : public Command { public: /** * \brief Constructs an %AddComponentCommand. */ AddComponentCommand(); virtual ~AddComponentCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; }; #endif // ADDCOMPONENTCOMMAND_H gxemul-0.6.1/src/include/commands/CopyComponentCommand.h000644 001750 001750 00000004364 13402411502 023514 0ustar00debugdebug000000 000000 #ifndef COPYCOMPONENTCOMMAND_H #define COPYCOMPONENTCOMMAND_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which copies (clones) a Component from one location to another in * the component tree. */ class CopyComponentCommand : public Command { public: /** * \brief Constructs a %CopyComponentCommand. */ CopyComponentCommand(); virtual ~CopyComponentCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // COPYCOMPONENTCOMMAND_H gxemul-0.6.1/src/include/commands/CloseCommand.h000644 001750 001750 00000004014 13402411502 021754 0ustar00debugdebug000000 000000 #ifndef CLOSECOMMAND_H #define CLOSECOMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which closes (discards) the current emulation. */ class CloseCommand : public Command { public: /** * \brief Constructs an %CloseCommand. */ CloseCommand(); virtual ~CloseCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; }; #endif // CLOSECOMMAND_H gxemul-0.6.1/src/include/commands/StepCommand.h000644 001750 001750 00000004316 13402411502 021627 0ustar00debugdebug000000 000000 #ifndef STEPCOMMAND_H #define STEPCOMMAND_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which sets the RunState to SingleStepping. */ class StepCommand : public Command { public: /** * \brief Constructs a %StepCommand. */ StepCommand(); virtual ~StepCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual bool MayBeReexecutedWithoutArgs() const { return true; } virtual string GetShortDescription() const; virtual string GetLongDescription() const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // STEPCOMMAND_H gxemul-0.6.1/src/include/commands/VersionCommand.h000644 001750 001750 00000004236 13402411502 022342 0ustar00debugdebug000000 000000 #ifndef VERSIONCOMMAND_H #define VERSIONCOMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which prints the version of the application. */ class VersionCommand : public Command { public: /** * \brief Constructs a %VersionCommand. */ VersionCommand(); virtual ~VersionCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // VERSIONCOMMAND_H gxemul-0.6.1/src/include/commands/ResetCommand.h000644 001750 001750 00000004434 13402411502 021777 0ustar00debugdebug000000 000000 #ifndef RESETCOMMAND_H #define RESETCOMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which resets the current emulation. * * The emulation is reset by resetting all components' state variables to * their initial state, and by changing the current RunState to Paused. */ class ResetCommand : public Command { public: /** * \brief Constructs a %ResetCommand. */ ResetCommand(); virtual ~ResetCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // RESETCOMMAND_H gxemul-0.6.1/src/include/commands/SaveCommand.h000644 001750 001750 00000004020 13402411502 021602 0ustar00debugdebug000000 000000 #ifndef SAVECOMMAND_H #define SAVECOMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which saves a Component tree to a file in the filesystem. */ class SaveCommand : public Command { public: /** * \brief Constructs an %SaveCommand. */ SaveCommand(); virtual ~SaveCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; }; #endif // SAVECOMMAND_H gxemul-0.6.1/src/include/commands/HelpCommand.h000644 001750 001750 00000003776 13402411502 021615 0ustar00debugdebug000000 000000 #ifndef HELPCOMMAND_H #define HELPCOMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which prints help messages for commands. */ class HelpCommand : public Command { public: /** * \brief Constructs a %HelpCommand. */ HelpCommand(); virtual ~HelpCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; }; #endif // HELPCOMMAND_H gxemul-0.6.1/src/include/commands/PauseCommand.h000644 001750 001750 00000004252 13402411502 021770 0ustar00debugdebug000000 000000 #ifndef PAUSECOMMAND_H #define PAUSECOMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which pauses execution, by changing the * current RunState to Paused. */ class PauseCommand : public Command { public: /** * \brief Constructs a %PauseCommand. */ PauseCommand(); virtual ~PauseCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // PAUSECOMMAND_H gxemul-0.6.1/src/include/commands/LoadCommand.h000644 001750 001750 00000004354 13402411502 021575 0ustar00debugdebug000000 000000 #ifndef LOADCOMMAND_H #define LOADCOMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "Component.h" #include "UnitTest.h" /** * \brief A Command which loads a Component tree from a file in the filesystem. */ class LoadCommand : public Command { public: /** * \brief Constructs an %LoadCommand. */ LoadCommand(); virtual ~LoadCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; private: bool IsComponentTree(GXemul& gxemul, const string& filename) const; bool LoadComponentTree(GXemul& gxemul, const string&filename, refcount_ptr specifiedComponent) const; }; #endif // LOADCOMMAND_H gxemul-0.6.1/src/include/commands/ContinueCommand.h000644 001750 001750 00000004303 13402411502 022474 0ustar00debugdebug000000 000000 #ifndef CONTINUECOMMAND_H #define CONTINUECOMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which continues execution, by changing the * current RunState to Running. */ class ContinueCommand : public Command { public: /** * \brief Constructs a %ContinueCommand. */ ContinueCommand(); virtual ~ContinueCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // CONTINUECOMMAND_H gxemul-0.6.1/src/include/commands/RemoveComponentCommand.h000644 001750 001750 00000004147 13402411502 024036 0ustar00debugdebug000000 000000 #ifndef REMOVECOMPONENTCOMMAND_H #define REMOVECOMPONENTCOMMAND_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "misc.h" #include "Command.h" #include "UnitTest.h" /** * \brief A Command which removes a Component from a GXemul instance' * component tree. */ class RemoveComponentCommand : public Command { public: /** * \brief Constructs a %RemoveComponentCommand. */ RemoveComponentCommand(); virtual ~RemoveComponentCommand(); virtual bool Execute(GXemul& gxemul, const vector& arguments); virtual string GetShortDescription() const; virtual string GetLongDescription() const; }; #endif // REMOVECOMPONENTCOMMAND_H gxemul-0.6.1/src/include/components/MachineComponent.h000644 001750 001750 00000005347 13402411502 023235 0ustar00debugdebug000000 000000 #ifndef MACHINECOMPONENT_H #define MACHINECOMPONENT_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(machine) #include "Component.h" #include "UnitTest.h" /** * \brief A Component representing a machine. * * A machine is, loosely defined, a box containing e.g.: *
    *
  • processor(s) *
  • RAM *
  • ROM *
  • interrupt controller *
  • other busses, such as PCI busses (which in turn have things * like network cards and graphics cards on them) *
  • ... *
*/ class MachineComponent : public Component , public UnitTestable { public: /** * \brief Constructs a MachineComponent. */ MachineComponent(); /** * \brief Creates a MachineComponent. */ static refcount_ptr Create(const ComponentCreateArgs& args); /** * \brief Get attribute information about the MachineComponent class. * * Implementation specifics for the MachineComponent class: * The machine is "stable" and a "machine". * * @param attributeName The attribute name. * @return A string representing the attribute value. */ static string GetAttribute(const string& attributeName); /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // MACHINECOMPONENT_H gxemul-0.6.1/src/include/components/TestM88KMachine.h000644 001750 001750 00000004101 13402411502 022605 0ustar00debugdebug000000 000000 #ifndef TESTM88KMACHINE_H #define TESTM88KMACHINE_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(testm88k) #include "Component.h" /** * \brief A template for creating a "testm88k" Component. * * Note: This class does not inherit from the Component class. */ class TestM88KMachine { public: /** * \brief Creates a "testm88k" Component tree. */ static refcount_ptr Create(const ComponentCreateArgs& args); /** * \brief Gets a Component attribute value. */ static string GetAttribute(const string& attributeName); private: TestM88KMachine(); }; #endif // TESTM88KMACHINE_H gxemul-0.6.1/src/include/components/RAMComponent.h000644 001750 001750 00000021540 13402411502 022301 0ustar00debugdebug000000 000000 #ifndef RAMCOMPONENT_H #define RAMCOMPONENT_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(ram) #include "AddressDataBus.h" #include "MemoryMappedComponent.h" #include "UnitTest.h" #include #include /** * \brief A Random Access Memory Component. * * RAM is emulated by allocating large blocks of host memory (e.g. 4 MB * per block), and simply forwarding all read and write requests to those * memory blocks. * * The host memory blocks are not allocated until they are actually written to. * Reading from uninitialized/unwritten emulated memory returns zeros. This * allows e.g. an emulated machine to have, say, 1 TB RAM, even if the host * only has 1 GB, as long as the emulated guest OS does not touch all of the * emulated memory. * * In addition, host memory blocks are allocated as anonymous zero-filled * memory using mmap(), so the blocks do not necessariliy use up host RAM * unless they are touched. * * Note 1: This class does not handle unaligned access. It is up to the * caller to make sure that e.g. ReadData(uint64_t&, Endianness) is only * called when the selected address is 64-bit aligned. * * (The reason for this is that different emulated components want different * semantics for unaligned access. For example, an x86 processor will * transparently allow unaligned access, most RISC processors will cause * an unaligned address exception, and some old ARM processors may even simply * ignore the lowest bits of the address!) * * Note 2: The RAM component's size and base offset are defined by state * variables in the MemoryMappedComponent base class. */ class RAMComponent : public MemoryMappedComponent , public AddressDataBus , public UnitTestable { public: /** * \brief Constructs a RAMComponent. * * @param visibleClassName The visible class name. Defaults to * "ram". Useful alternatives may be "rom" or * "vram" for video ram. */ RAMComponent(const string& visibleClassName = "ram"); virtual ~RAMComponent(); /** * \brief Creates a RAMComponent. */ static refcount_ptr Create(const ComponentCreateArgs& args); virtual void ResetState(); /** * \brief Get attribute information about the RAMComponent class. * * @param attributeName The attribute name. * @return A string representing the attribute value. */ static string GetAttribute(const string& attributeName); virtual void GetMethodNames(vector& names) const; virtual bool MethodMayBeReexecutedWithoutArgs(const string& methodName) const; virtual void ExecuteMethod(GXemul* gxemul, const string& methodName, const vector& arguments); /** * \brief Returns the component's AddressDataBus interface. * * @return A pointer to an AddressDataBus. */ virtual AddressDataBus* AsAddressDataBus(); /* Implementation of AddressDataBus: */ virtual void AddressSelect(uint64_t address); virtual bool ReadData(uint8_t& data, Endianness endianness); virtual bool ReadData(uint16_t& data, Endianness endianness); virtual bool ReadData(uint32_t& data, Endianness endianness); virtual bool ReadData(uint64_t& data, Endianness endianness); virtual bool WriteData(const uint8_t& data, Endianness endianness); virtual bool WriteData(const uint16_t& data, Endianness endianness); virtual bool WriteData(const uint32_t& data, Endianness endianness); virtual bool WriteData(const uint64_t& data, Endianness endianness); /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); private: void ReleaseAllBlocks(); void* AllocateBlock(); class RAMDataHandler : public CustomStateVariableHandler { public: RAMDataHandler(RAMComponent& ram) : m_ram(ram) { } virtual ~RAMDataHandler() { } virtual void Serialize(ostream& ss) const { for (size_t i=0; i len) { std::cerr << "deserialize ram: internal error\n"; throw std::exception(); } char s1[17]; char s2[9]; memcpy(s1, cstr + p, 16); p += 17; memcpy(s2, cstr + p, 8); p += 9; s1[16] = 0; s2[8] = 0; stringstream ss1; ss1.flags(std::ios::hex); ss1 << s1; uint64_t addr; ss1 >> addr; stringstream ss2; ss2.flags(std::ios::hex); ss2 << s2; uint32_t datalen; ss2 >> datalen; // p points to data. if (p + 2*datalen < len) { for (size_t i=0; i= 'a' && c1 <= 'f') c1 = (c1-'a') + 10; else c1 -= '0'; if (c2 >= 'a' && c2 <= 'f') c2 = (c2-'a') + 10; else c2 -= '0'; uint8_t b = c1*16 + c2; m_ram.AddressSelect(i + addr); m_ram.WriteData(b, BigEndian); } } else { std::cerr << "deserialize ram: internal error\n"; throw std::exception(); } if (cstr[p] != '.') { std::cerr << "deserialize ram: internal error: no dot\n"; throw std::exception(); } } return true; } virtual void CopyValueFrom(CustomStateVariableHandler* other) { // NOTE/TODO: Not space efficient, but works for now. stringstream ss; other->Serialize(ss); Deserialize(ss.str()); } private: void SerializeMemoryBlock(ostream& ss, size_t blockNr, void *block) const { const size_t rowSize = 1024; uint64_t addr = blockNr << m_ram.m_blockSizeShift; uint64_t addrWithinBlock = 0; while (addrWithinBlock < m_ram.m_blockSize) { uint8_t *data = (uint8_t*)block + addrWithinBlock; bool allZeroes = true; for (size_t i=0; i BlockNrToMemoryBlockVector; BlockNrToMemoryBlockVector m_memoryBlocks; bool m_writeProtected; uint64_t m_lastDumpAddr; // Cached/runtime state: uint64_t m_addressSelect; // For AddressDataBus read/write void * m_selectedHostMemoryBlock; size_t m_selectedOffsetWithinBlock; }; #endif // RAMCOMPONENT_H gxemul-0.6.1/src/include/components/CacheComponent.h000644 001750 001750 00000011116 13402411502 022663 0ustar00debugdebug000000 000000 #ifndef CACHECOMPONENT_H #define CACHECOMPONENT_H /* * Copyright (C) 2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(cache) #include "AddressDataBus.h" #include "MemoryMappedComponent.h" #include "UnitTest.h" #include #include /** * \brief A memory Cache Component. * * TODO * * Note: This class does not handle unaligned access. It is up to the * caller to make sure that e.g. ReadData(uint64_t&, Endianness) is only * called when the selected address is 64-bit aligned. * * (The reason for this is that different emulated components want different * semantics for unaligned access. For example, an x86 processor will * transparently allow unaligned access, most RISC processors will cause * an unaligned address exception, and some old ARM processors may even simply * ignore the lowest bits of the address!) */ class CacheComponent : public Component , public AddressDataBus , public UnitTestable { public: /** * \brief Constructs a CacheComponent. * * @param visibleClassName The visible class name. Defaults to * "cache". Useful alternatives may be "l1", "l2", or "l3". */ CacheComponent(const string& visibleClassName = "cache"); virtual ~CacheComponent(); /** * \brief Creates a CacheComponent. */ static refcount_ptr Create(const ComponentCreateArgs& args); virtual void ResetState(); string GenerateDetails() const; /** * \brief Get attribute information about the CacheComponent class. * * @param attributeName The attribute name. * @return A string representing the attribute value. */ static string GetAttribute(const string& attributeName); virtual void GetMethodNames(vector& names) const; virtual bool MethodMayBeReexecutedWithoutArgs(const string& methodName) const; virtual void ExecuteMethod(GXemul* gxemul, const string& methodName, const vector& arguments); /** * \brief Returns the component's AddressDataBus interface. * * @return A pointer to an AddressDataBus. */ virtual AddressDataBus* AsAddressDataBus(); /* Implementation of AddressDataBus: */ virtual void AddressSelect(uint64_t address); virtual bool ReadData(uint8_t& data, Endianness endianness); virtual bool ReadData(uint16_t& data, Endianness endianness); virtual bool ReadData(uint32_t& data, Endianness endianness); virtual bool ReadData(uint64_t& data, Endianness endianness); virtual bool WriteData(const uint8_t& data, Endianness endianness); virtual bool WriteData(const uint16_t& data, Endianness endianness); virtual bool WriteData(const uint32_t& data, Endianness endianness); virtual bool WriteData(const uint64_t& data, Endianness endianness); /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); private: private: // State: uint64_t m_size; // total cache size uint64_t m_lineSize; // line size, in bytes uint64_t m_lastDumpAddr; int m_associativity;// 0 = fully. 1 = direct mapped. n = n-way. // TODO: the actual data (cache lines) // Cached/runtime state: uint64_t m_addressSelect; // For AddressDataBus read/write }; #endif // CACHECOMPONENT_H gxemul-0.6.1/src/include/components/CPUDyntransComponent.h000644 001750 001750 00000046205 13402411502 024041 0ustar00debugdebug000000 000000 #ifndef CPUDYNTRANSCOMPONENT_H #define CPUDYNTRANSCOMPONENT_H /* * Copyright (C) 2008-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // Note: Not included in the component registry. #include "CPUComponent.h" #include "UnitTest.h" #include class CPUDyntransComponent; #define N_DYNTRANS_IC_ARGS 3 /** * \brief A dyntrans instruction call. * * f points to a function to be executed. * arg[] contains arguments, such as pointers to registers, or immediate values. */ struct DyntransIC { void (*f)(CPUDyntransComponent*, DyntransIC*); union { void* p; uint32_t u32; } arg[N_DYNTRANS_IC_ARGS]; }; /* * A dyntrans page contains DyntransIC calls for each instruction slot, followed * by some special entries, which handle execution going over the end of a page * (by changing the PC to the start of the next virtual page). */ #define DYNTRANS_PAGE_NSPECIALENTRIES 2 /* * Some helpers for implementing dyntrans instructions. */ #define DECLARE_DYNTRANS_INSTR(name) static void instr_##name(CPUDyntransComponent* cpubase, DyntransIC* ic); #define DYNTRANS_INSTR(class,name) void class::instr_##name(CPUDyntransComponent* cpubase, DyntransIC* ic) #define DYNTRANS_INSTR_HEAD(class) class* cpu = (class*) cpubase; #define REG32(arg) (*((uint32_t*)((arg).p))) #define REG64(arg) (*((uint64_t*)((arg).p))) #define DYNTRANS_SYNCH_PC cpu->m_nextIC = ic; cpu->DyntransResyncPC() /** * \brief A base-class for processors Component implementations that * use dynamic translation. */ class CPUDyntransComponent : public CPUComponent { public: /** * \brief Constructs a CPUDyntransComponent. * * @param className The class name for the component. * @param cpuKind The CPU kind, e.g. "MIPS R4400" for a * MIPS R4400 processor. */ CPUDyntransComponent(const string& className, const string& cpuKind); virtual int Execute(GXemul* gxemul, int nrOfCycles); /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); protected: // Implemented by specific CPU families: virtual int GetDyntransICshift() const = 0; virtual void (*GetDyntransToBeTranslated())(CPUDyntransComponent* cpu, DyntransIC* ic) = 0; void DyntransToBeTranslatedBegin(struct DyntransIC*); bool DyntransReadInstruction(uint16_t& iword); bool DyntransReadInstruction(uint32_t& iword, int offset = 0); void DyntransToBeTranslatedDone(struct DyntransIC*); /** * \brief Calculate m_pc based on m_nextIC and m_firstIConPage. */ void DyntransResyncPC(); /** * \brief Calculate m_nextIC and m_firstIConPage, based on m_pc. * * This function may return pointers to within an existing translation * page (hopefully the most common case, since it is the fastest), or * it may allocate a new empty page. */ void DyntransPCtoPointers(); private: void DyntransInit(); struct DyntransIC* DyntransGetICPage(uint64_t addr); void DyntransClearICPage(struct DyntransIC* icpage); protected: /* * Generic dyntrans instruction implementations, that may be used by * several different cpu architectures. */ DECLARE_DYNTRANS_INSTR(nop); DECLARE_DYNTRANS_INSTR(abort); DECLARE_DYNTRANS_INSTR(endOfPage); DECLARE_DYNTRANS_INSTR(endOfPage2); // Branches. DECLARE_DYNTRANS_INSTR(branch_samepage); // Data movement. DECLARE_DYNTRANS_INSTR(set_u64_imms32); DECLARE_DYNTRANS_INSTR(mov_u64_u64); // Arithmetic. DECLARE_DYNTRANS_INSTR(add_u32_u32_immu32); DECLARE_DYNTRANS_INSTR(add_u32_u32_u32); DECLARE_DYNTRANS_INSTR(add_u64_u64_imms32_truncS32); DECLARE_DYNTRANS_INSTR(add_u64_u64_u64_truncS32); DECLARE_DYNTRANS_INSTR(add_u64_u64_imms32); DECLARE_DYNTRANS_INSTR(sub_u32_u32_immu32); DECLARE_DYNTRANS_INSTR(sub_u32_u32_u32); DECLARE_DYNTRANS_INSTR(sub_u64_u64_u64_truncS32); // Logic. DECLARE_DYNTRANS_INSTR(and_u32_u32_immu32); DECLARE_DYNTRANS_INSTR(and_u64_u64_immu32); DECLARE_DYNTRANS_INSTR(or_u32_u32_immu32); DECLARE_DYNTRANS_INSTR(or_u32_u32_u32); DECLARE_DYNTRANS_INSTR(or_u64_u64_immu32); DECLARE_DYNTRANS_INSTR(xor_u32_u32_immu32); DECLARE_DYNTRANS_INSTR(xor_u32_u32_u32); DECLARE_DYNTRANS_INSTR(xor_u64_u64_immu32); DECLARE_DYNTRANS_INSTR(xor_u64_u64_u64); // Shifts, rotates. DECLARE_DYNTRANS_INSTR(shift_left_u64_u64_imm5_truncS32); DECLARE_DYNTRANS_INSTR(shift_right_u64_u64asu32_imm5_truncS32); private: class DyntransTranslationPage { public: DyntransTranslationPage(int nICentriesPerpage) : m_prev(-1) , m_next(-1) , m_nextCacheEntryForAddr(-1) , m_addr(0) , m_showFunctionTraceCall(false) { m_ic.resize(nICentriesPerpage); } public: // Linked list: Freelist or MRU list int m_prev; int m_next; // Address match: int m_nextCacheEntryForAddr; uint64_t m_addr; // Flags for this page: // TODO: In the future, this could be stuff like different // instruction encodings (MIPS16/Thumb vs 32-bit encoding), // or other mode switches. bool m_showFunctionTraceCall; // Translated instructions: vector< struct DyntransIC > m_ic; }; class DyntransTranslationCache { public: DyntransTranslationCache() : m_nICentriesPerpage(0) , m_pageShift(0) , m_firstFree(-1) , m_lastFree(-1) , m_firstMRU(-1) , m_lastMRU(-1) { } void Reinit(size_t approximateSize, int nICentriesPerpage, int pageShift) { size_t approximateSizePerPage = sizeof(struct DyntransIC) * nICentriesPerpage + 64; size_t nrOfPages = approximateSize / approximateSizePerPage; if (nrOfPages < 2) { std::cerr << "Too small translation cache!\n"; throw std::exception(); } if (nICentriesPerpage == m_nICentriesPerpage && nrOfPages == m_pageCache.size() && pageShift == m_pageShift) return; m_nICentriesPerpage = nICentriesPerpage; m_pageShift = pageShift; // Generate empty pages: m_pageCache.clear(); m_pageCache.resize(nrOfPages, DyntransTranslationPage(nICentriesPerpage)); // Set up the free-list to connect all pages: m_firstFree = 0; m_lastFree = nrOfPages - 1; for (int i=m_firstFree; i<=m_lastFree; i++) { m_pageCache[i].m_prev = i-1; // note: i=0 (first page) // results in prev = -1. if (i == m_lastFree) m_pageCache[i].m_next = -1; else m_pageCache[i].m_next = i+1; } // No pages in use yet, so nothing on the MRU list: m_firstMRU = m_lastMRU = -1; // Reset the quick lookup table: // (Currently hardcoded to allow the first 1 GB of emulated physical memory // to be looked up with 1 call, if more than 1 GB of RAM is used, the // m_nextCacheEntryForAddr chain must be traversed...) m_addrToFirstPageIndex.resize(1024 * 1048576 >> m_pageShift); for (size_t i=0; i pageIsInMRUList; vector pageIsInFreeList; vector pageIsInMRUListReverse; vector pageIsInFreeListReverse; pageIsInMRUList.resize(m_pageCache.size(), false); pageIsInFreeList.resize(m_pageCache.size(), false); pageIsInMRUListReverse.resize(m_pageCache.size(), false); pageIsInFreeListReverse.resize(m_pageCache.size(), false); // Follow free-list forward: int i = m_firstFree; while (i >= 0) { pageIsInFreeList[i] = true; i = m_pageCache[i].m_next; } // Follow free-list backwards: i = m_lastFree; while (i >= 0) { pageIsInFreeListReverse[i] = true; i = m_pageCache[i].m_prev; } // Follow MRU-list forward: i = m_firstMRU; while (i >= 0) { pageIsInMRUList[i] = true; i = m_pageCache[i].m_next; } // Follow MRU-list backwards: i = m_lastMRU; while (i >= 0) { pageIsInMRUListReverse[i] = true; i = m_pageCache[i].m_prev; } // The forward and reverse sets should match: for (size_t j=0; j pageIsPointedToByQuickLookupTable; vector pageIsPointedToByQLTChain; pageIsPointedToByQuickLookupTable.resize(m_pageCache.size(), false); pageIsPointedToByQLTChain.resize(m_pageCache.size(), false); for (size_t k=0; k= 0) pageIsPointedToByQuickLookupTable[m_addrToFirstPageIndex[k]] = true; for (size_t k=0; k= 0) pageIsPointedToByQLTChain[index] = true; } for (size_t k=0; k= 0) { std::cerr << "Pages on the free-list should not have m_nextCacheEntryForAddr set!\n"; throw std::exception(); } if (pageIsPointedToByQuickLookupTable[k]) { std::cerr << "Pages on the free-list should not be pointed to by the quick lookup table!\n"; throw std::exception(); } if (pageIsPointedToByQLTChain[k]) { std::cerr << "Pages on the free-list should not be in the quick lookup table chain!\n"; throw std::exception(); } } for (size_t k=0; k> m_pageShift; int quickLookupIndex = physPageNumber & (m_addrToFirstPageIndex.size() - 1); int pageIndex = m_addrToFirstPageIndex[quickLookupIndex]; while (pageIndex >= 0) { if (m_pageCache[pageIndex].m_addr == addr) break; pageIndex = m_pageCache[pageIndex].m_nextCacheEntryForAddr; } if (pageIndex < 0) { std::cerr << "Pages in the MRU list must be reachable from the quick lookup table!\n"; throw std::exception(); } } #endif } void FreeLeastRecentlyUsedPage() { // This function should only be called if it is really necessary to // free a page, i.e. if there is no free page at all. assert(m_firstFree < 0); if (m_firstMRU == m_lastMRU) { std::cerr << "Attempt to free a page, but there's only one page in the MRU list. Too small!\n"; throw std::exception(); } // This is the one we will free. int index = m_lastMRU; assert(m_pageCache[index].m_prev >= 0); assert(m_pageCache[index].m_next < 0); // Disconnect it from the MRU list... m_lastMRU = m_pageCache[index].m_prev; m_pageCache[m_lastMRU].m_next = -1; // ... and add it first in the free-list: if (m_firstFree < 0) { // In fact, the free-list was empty. m_firstFree = m_lastFree = index; m_pageCache[index].m_prev = -1; m_pageCache[index].m_next = -1; } else { m_pageCache[index].m_prev = -1; m_pageCache[index].m_next = m_firstFree; m_pageCache[m_firstFree].m_prev = index; m_firstFree = index; } // Remove from the quick lookup chain: uint64_t physPageNumber = m_pageCache[index].m_addr >> m_pageShift; int quickLookupIndex = physPageNumber & (m_addrToFirstPageIndex.size() - 1); int pageIndex = m_addrToFirstPageIndex[quickLookupIndex]; if (pageIndex == index) { // Direct hit? Then remove from the base quick look up table... m_addrToFirstPageIndex[quickLookupIndex] = m_pageCache[index].m_nextCacheEntryForAddr; } else { // ... otherwise traverse the chain until the next entry is the one we are removing. while (true) { if (m_pageCache[pageIndex].m_nextCacheEntryForAddr == index) { m_pageCache[pageIndex].m_nextCacheEntryForAddr = m_pageCache[index].m_nextCacheEntryForAddr; break; } pageIndex = m_pageCache[pageIndex].m_nextCacheEntryForAddr; } } m_pageCache[index].m_nextCacheEntryForAddr = -1; ValidateConsistency(); } struct DyntransIC *AllocateNewPage(uint64_t addr, bool showFunctionTraceCall) { int index = m_firstFree; assert(index >= 0); // Let's grab this index for ourselves... // Was this the only free page? if (index == m_lastFree) { // Then there will be no more free pages. m_firstFree = m_lastFree = -1; } else { // No, just update the chain: m_firstFree = m_pageCache[index].m_next; m_pageCache[m_firstFree].m_prev = -1; } // The page's prev and next fields should be updated to // be part of the MRU list now. // Is there nothing in the MRU list? if (m_firstMRU == -1) { // Then we are the only one. m_firstMRU = m_lastMRU = index; m_pageCache[index].m_next = m_pageCache[index].m_prev = -1; } else { // Then we place ourselves first: m_pageCache[m_firstMRU].m_prev = index; m_pageCache[index].m_next = m_firstMRU; m_firstMRU = index; m_pageCache[index].m_prev = -1; } // Set attributes for the page: address and other flags. m_pageCache[index].m_addr = addr; m_pageCache[index].m_showFunctionTraceCall = showFunctionTraceCall; // Insert into quick lookup table: uint64_t physPageNumber = addr >> m_pageShift; int quickLookupIndex = physPageNumber & (m_addrToFirstPageIndex.size() - 1); // Are we the only one? (I.e. the first page for this quick lookup index.) if (m_addrToFirstPageIndex[quickLookupIndex] < 0) { m_addrToFirstPageIndex[quickLookupIndex] = index; m_pageCache[index].m_nextCacheEntryForAddr = -1; } else { // No. Let's add ourselves first in the chain: m_pageCache[index].m_nextCacheEntryForAddr = m_addrToFirstPageIndex[quickLookupIndex]; m_addrToFirstPageIndex[quickLookupIndex] = index; } ValidateConsistency(); return &(m_pageCache[index].m_ic[0]); } struct DyntransIC *GetICPage(uint64_t addr, bool showFunctionTraceCall, bool& clear) { clear = false; // Strip of the low bits: addr >>= m_pageShift; uint64_t physPageNumber = addr; addr <<= m_pageShift; int quickLookupIndex = physPageNumber & (m_addrToFirstPageIndex.size() - 1); int pageIndex = m_addrToFirstPageIndex[quickLookupIndex]; // std::cerr << "addr " << addr << ", physPageNumber " << physPageNumber << ", quickLookupIndex " << quickLookupIndex << ", pageIndex " << pageIndex << "\n"; // If pageIndex >= 0, then pageIndex points to a page which _may_ be for this addr. while (pageIndex >= 0) { if (m_pageCache[pageIndex].m_addr == addr) break; // If the page for pageIndex was for some other address, then // let's continue searching the chain... pageIndex = m_pageCache[pageIndex].m_nextCacheEntryForAddr; } // If we have a definite page index, then return a pointer that page's ICs: if (pageIndex >= 0) { // Update the MRU list, unless this page was already first, // so that m_firstMRU points to the page. if (m_firstMRU != pageIndex) { // Disconnect from previous place... int prev = m_pageCache[pageIndex].m_prev; int next = m_pageCache[pageIndex].m_next; if (prev >= 0) m_pageCache[prev].m_next = next; if (next >= 0) m_pageCache[next].m_prev = prev; // ... disconnect from "end of list": if (pageIndex == m_lastMRU) m_lastMRU = prev; // ... and insert first in list: m_pageCache[pageIndex].m_prev = -1; m_pageCache[pageIndex].m_next = m_firstMRU; m_pageCache[m_firstMRU].m_prev = pageIndex; m_firstMRU = pageIndex; } // TODO: Hm... also move to front of the Quick Lookup chain? // Only necessary if more memory is used/emulated than the // size of the quick lookup table, e.g. if 2 GB ram are used, // and the size of the lookup table is 1 GB, and pages // at exactly 0 GB and 1 GB are used in this order: // 1 0 1 1 1 1 1 1 1 1 1 1 1 // then 1 would first be placed in the chain, then 0 (which // would insert it first in the chain). But all lookups after // that would have to search the whole chain (0, 1) to find 1. ValidateConsistency(); // If flags are not the same, then let's clear the page: if (m_pageCache[pageIndex].m_showFunctionTraceCall != showFunctionTraceCall) { m_pageCache[pageIndex].m_showFunctionTraceCall = showFunctionTraceCall; clear = true; } return &(m_pageCache[pageIndex].m_ic[0]); } // The address was NOT in the translation cache at all. So we have // to create a new page. // If the free-list is all used up, that means we have to free something // before we can allocate a new page... if (m_firstFree < 0) FreeLeastRecentlyUsedPage(); // ... and then finally allocate a new page: clear = true; return AllocateNewPage(addr, showFunctionTraceCall); } private: // Number of translated instructions per page, and number of bits // to shift to convert address to page number: int m_nICentriesPerpage; int m_pageShift; // Free-list of pages: int m_firstFree; int m_lastFree; // Most-Recently-Used list of pages: int m_firstMRU; int m_lastMRU; // "Usually" quick lookup table, address to page index: vector m_addrToFirstPageIndex; // The actual pages: vector m_pageCache; }; protected: /* * Volatile state: */ struct DyntransIC * m_firstIConPage; struct DyntransIC * m_nextIC; int m_dyntransPageMask; int m_dyntransICentriesPerPage; int m_dyntransICshift; int m_executedCycles; int m_nrOfCyclesToExecute; /* * Translation cache: */ DyntransTranslationCache m_translationCache; /* * Special always present DyntransIC structs, for aborting emulation: */ struct DyntransIC m_abortIC; }; #endif // CPUDYNTRANSCOMPONENT_H gxemul-0.6.1/src/include/components/CycloneVHMachine.h000644 001750 001750 00000004104 13402411502 023113 0ustar00debugdebug000000 000000 #ifndef CYCLONEVHMACHINE_H #define CYCLONEVHMACHINE_H /* * Copyright (C) 2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(cyclonevh) #include "Component.h" /** * \brief A template for creating a "cyclonevh" Component. * * Note: This class does not inherit from the Component class. */ class CycloneVHMachine { public: /** * \brief Creates a "cyclonevh" Component tree. */ static refcount_ptr Create(const ComponentCreateArgs& args); /** * \brief Gets a Component attribute value. */ static string GetAttribute(const string& attributeName); private: CycloneVHMachine(); }; #endif // CYCLONEVHMACHINE_H gxemul-0.6.1/src/include/components/MemoryMappedComponent.h000644 001750 001750 00000005332 13402411502 024262 0ustar00debugdebug000000 000000 #ifndef MEMORYMAPPEDCOMPONENT_H #define MEMORYMAPPEDCOMPONENT_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // Note: not included in the component registry. This is simply a base-class. #include "Component.h" #include "UnitTest.h" /** * \brief A base-class for memory-mapped components. * * A memory-mapped component is a Component which is meant to be mapped * into a bus' address space. It has a base offset and a size, * which the bus sees. The bus then forwards only those read/write requests * to the memory-mapped component that are within that range. * * There is also an address multiplicator, to handle the common * case when a device has, say, N 8-bit registers, but is accessed using * memory-mapped addresses that are seen as N 32-bit registers. In this * example, the address multiplicator would be 4. */ class MemoryMappedComponent : public Component { public: /** * \brief Constructs a MemoryMappedComponent. */ MemoryMappedComponent(const string& className, const string& visibleClassName); string GenerateDetails() const; private: // Variables common to all memory mapped components: uint64_t m_memoryMappedBase; uint64_t m_memoryMappedSize; uint64_t m_memoryMappedAddrMul; }; #endif // MEMORYMAPPEDCOMPONENT_H gxemul-0.6.1/src/include/components/I960_CPUComponent.h000644 001750 001750 00000011112 13402411502 023012 0ustar00debugdebug000000 000000 #ifndef I960_CPUCOMPONENT_H #define I960_CPUCOMPONENT_H /* * Copyright (C) 2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(i960_cpu) #include "CPUDyntransComponent.h" #define N_I960_REGS 32 #define N_I960_SFRS 32 /* Register conventions according to https://people.cs.clemson.edu/~mark/subroutines/i960.html */ static const char* i960_regnames[N_I960_REGS] = { "pfp", // r0 = previous frame pointer "sp", // r1 = stack pointer "rip", // r2 = return instruction pointer "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "g0", "g1", "g2", "g3", // parameters 0-3; return words 0-3 "g4", "g5", "g6", "g7", // parameters 4-7; temporaries "g8", "g9", "g10", "g11", "g12", // preserved accross call "g13", // structure return pointer "g14", // argument block pointer; leaf return address (HW) "fp" // g15 = frame pointer (16-byte aligned HW) }; #define I960_G0 16 // offset to first parameter register /***********************************************************************/ /** * \brief A Component representing an Intel i960 processor. */ class I960_CPUComponent : public CPUDyntransComponent { public: /** * \brief Constructs a I960_CPUComponent. */ I960_CPUComponent(); /** * \brief Creates a I960_CPUComponent. */ static refcount_ptr Create(const ComponentCreateArgs& args); static string GetAttribute(const string& attributeName); virtual void ResetState(); virtual bool PreRunCheckForComponent(GXemul* gxemul); virtual size_t DisassembleInstruction(uint64_t vaddr, size_t maxlen, unsigned char *instruction, vector& result); /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); protected: virtual bool CheckVariableWrite(StateVariable& var, const string& oldValue); virtual bool VirtualToPhysical(uint64_t vaddr, uint64_t& paddr, bool& writable); virtual string VirtualAddressAsString(uint64_t vaddr) { stringstream ss; ss.flags(std::ios::hex | std::ios::showbase | std::ios::right); ss << (uint32_t)vaddr; return ss.str(); } virtual uint64_t PCtoInstructionAddress(uint64_t pc); virtual int FunctionTraceArgumentCount(); virtual int64_t FunctionTraceArgument(int n); virtual bool FunctionTraceReturnImpl(int64_t& retval); virtual int GetDyntransICshift() const; virtual void (*GetDyntransToBeTranslated())(CPUDyntransComponent*, DyntransIC*); virtual void ShowRegisters(GXemul* gxemul, const vector& arguments) const; private: DECLARE_DYNTRANS_INSTR(b); DECLARE_DYNTRANS_INSTR(lda_displacement); DECLARE_DYNTRANS_INSTR(mov_lit_reg); DECLARE_DYNTRANS_INSTR(sysctl); void Translate(uint32_t iword, uint32_t iword2, struct DyntransIC* ic); DECLARE_DYNTRANS_INSTR(ToBeTranslated); private: /* * State: */ string m_model; uint32_t m_r[N_I960_REGS]; // r and g registers // NOTE: The i960 "ip" register is m_pc. uint32_t m_i960_ac; // Arithmetic control uint32_t m_i960_pc; // Process control uint32_t m_i960_tc; // Trace control uint32_t m_nr_of_valid_sfrs; // depends on model uint32_t m_sfr[N_I960_SFRS]; }; #endif // I960_CPUCOMPONENT_H gxemul-0.6.1/src/include/components/MIPS_CPUComponent.h000644 001750 001750 00000016650 13402411502 023147 0ustar00debugdebug000000 000000 #ifndef MIPS_CPUCOMPONENT_H #define MIPS_CPUCOMPONENT_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(mips_cpu) #include "CPUDyntransComponent.h" /***********************************************************************/ #define MIPS_INITIAL_PC ((int32_t) 0xbfc00000) #define MIPS_INITIAL_STACK_POINTER ((int32_t) 0xa0008000 - 256) /* FPU control registers: */ #define N_MIPS_FCRS 32 #define MIPS_FPU_FCIR 0 #define MIPS_FPU_FCCR 25 #define MIPS_FPU_FCSR 31 #define MIPS_FCSR_FCC0_SHIFT 23 #define MIPS_FCSR_FCC1_SHIFT 25 #define N_MIPS_COPROCS 4 #define N_MIPS_GPRS 32 /* General purpose registers */ #define N_MIPS_FPRS 32 /* Floating point registers */ /* * These should all be 2 characters wide: * * NOTE: For the newer ABIs (n32 and 64-bit ABIs), registers 8..11 are used * to pass arguments and are then called "a4".."a7". */ #define MIPS_OLDABI_REGISTER_NAMES { \ "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3", \ "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", \ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \ "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" } #define MIPS_REGISTER_NAMES { \ "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3", \ "a4", "a5", "a6", "a7", "t4", "t5", "t6", "t7", \ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \ "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" } #define MIPS_GPR_ZERO 0 /* zero */ #define MIPS_GPR_AT 1 /* at */ #define MIPS_GPR_V0 2 /* v0 */ #define MIPS_GPR_V1 3 /* v1 */ #define MIPS_GPR_A0 4 /* a0 */ #define MIPS_GPR_A1 5 /* a1 */ #define MIPS_GPR_A2 6 /* a2 */ #define MIPS_GPR_A3 7 /* a3 */ #define MIPS_GPR_T0 8 /* t0 */ #define MIPS_GPR_T1 9 /* t1 */ #define MIPS_GPR_T2 10 /* t2 */ #define MIPS_GPR_T3 11 /* t3 */ #define MIPS_GPR_T4 12 /* t4 */ #define MIPS_GPR_T5 13 /* t5 */ #define MIPS_GPR_T6 14 /* t6 */ #define MIPS_GPR_T7 15 /* t7 */ #define MIPS_GPR_S0 16 /* s0 */ #define MIPS_GPR_S1 17 /* s1 */ #define MIPS_GPR_S2 18 /* s2 */ #define MIPS_GPR_S3 19 /* s3 */ #define MIPS_GPR_S4 20 /* s4 */ #define MIPS_GPR_S5 21 /* s5 */ #define MIPS_GPR_S6 22 /* s6 */ #define MIPS_GPR_S7 23 /* s7 */ #define MIPS_GPR_T8 24 /* t8 */ #define MIPS_GPR_T9 25 /* t9 */ #define MIPS_GPR_K0 26 /* k0 */ #define MIPS_GPR_K1 27 /* k1 */ #define MIPS_GPR_GP 28 /* gp */ #define MIPS_GPR_SP 29 /* sp */ #define MIPS_GPR_FP 30 /* fp */ #define MIPS_GPR_RA 31 /* ra */ #define N_HI6 64 #define N_SPECIAL 64 #define N_REGIMM 32 /***********************************************************************/ /* * CPU type definitions: See mips_cpu_types.h. */ struct mips_cpu_type_def { const char * name; int rev; int sub; int flags; int exc_model; /* EXC3K or EXC4K */ int mmu_model; /* MMU3K or MMU4K */ int isa_level; /* 1, 2, 3, 4, 5, 32, 64 */ int isa_revision; /* 1 or 2 (for MIPS32/64) */ int nr_of_tlb_entries; /* 32, 48, 64, ... */ int instrs_per_cycle; /* simplified, 1, 2, or 4 */ int picache; int pilinesize; int piways; int pdcache; int pdlinesize; int pdways; int scache; int slinesize; int sways; }; /***********************************************************************/ /** * \brief A Component representing a MIPS processor. */ class MIPS_CPUComponent : public CPUDyntransComponent { public: /** * \brief Constructs a MIPS_CPUComponent. */ MIPS_CPUComponent(); /** * \brief Creates a MIPS_CPUComponent. */ static refcount_ptr Create(const ComponentCreateArgs& args); static string GetAttribute(const string& attributeName); virtual void ResetState(); virtual bool PreRunCheckForComponent(GXemul* gxemul); virtual size_t DisassembleInstruction(uint64_t vaddr, size_t maxlen, unsigned char *instruction, vector& result); /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); protected: virtual bool CheckVariableWrite(StateVariable& var, const string& oldValue); virtual bool VirtualToPhysical(uint64_t vaddr, uint64_t& paddr, bool& writable); virtual string VirtualAddressAsString(uint64_t vaddr) { stringstream ss; ss.flags(std::ios::hex | std::ios::showbase | std::ios::right); if (Is32Bit()) ss << (uint32_t)vaddr; else ss << vaddr; return ss.str(); } virtual uint64_t PCtoInstructionAddress(uint64_t pc); virtual int FunctionTraceArgumentCount(); virtual int64_t FunctionTraceArgument(int n); virtual bool FunctionTraceReturnImpl(int64_t& retval); virtual int GetDyntransICshift() const; virtual void (*GetDyntransToBeTranslated())(CPUDyntransComponent*, DyntransIC*); virtual void ShowRegisters(GXemul* gxemul, const vector& arguments) const; private: size_t DisassembleInstructionMIPS16(uint64_t vaddr, unsigned char *instruction, vector& result); bool Is32Bit() const; private: template static void instr_b(CPUDyntransComponent* cpubase, DyntransIC* ic); template static void instr_j(CPUDyntransComponent* cpubase, DyntransIC* ic); template static void instr_jr(CPUDyntransComponent* cpubase, DyntransIC* ic); DECLARE_DYNTRANS_INSTR(multu); DECLARE_DYNTRANS_INSTR(slt); DECLARE_DYNTRANS_INSTR(sltu); template static void instr_loadstore(CPUDyntransComponent* cpubase, DyntransIC* ic); void Translate(uint32_t iword, struct DyntransIC* ic); DECLARE_DYNTRANS_INSTR(ToBeTranslated); DECLARE_DYNTRANS_INSTR(ToBeTranslated_MIPS16); private: /* * State: */ string m_mips_type; // E.g. "R4400" string m_abi; // "o32", "n32", or "n64" uint64_t m_gpr[N_MIPS_GPRS]; uint64_t m_hi; uint64_t m_lo; uint64_t m_scratch; // for loads into the zero register /* * Cached or volatile other state: */ mips_cpu_type_def m_type; // based on m_mips_type }; #endif // MIPS_CPUCOMPONENT_H gxemul-0.6.1/src/include/components/M88K_CPUComponent.h000644 001750 001750 00000043137 13402411502 023066 0ustar00debugdebug000000 000000 #ifndef M88K_CPUCOMPONENT_H #define M88K_CPUCOMPONENT_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(m88k_cpu) #include "CPUDyntransComponent.h" #include "thirdparty/m88k_psl.h" /* M88K CPU types: */ struct m88k_cpu_type_def { const char *name; int type; uint32_t pid; }; #define M88K_PID(arn,vn) ((arn << M88K_ARN_SHIFT) | (vn << M88K_VN_SHIFT)) #define M88K_CPU_TYPE_DEFS { \ { "88100", 88100, M88K_PID(M88K_ARN_88100,3) }, \ { "88110", 88110, M88K_PID(M88K_ARN_88110,0) }, \ { NULL, 0, 0 } \ } /* * Opcode names: */ #define M88K_OPCODE_NAMES { \ "xmem.bu", "xmem", "ld.hu", "ld.bu", \ "ld.d", "ld", "ld.h", "ld.b", \ "st.d", "st", "st.h", "st.b", \ "opcode0c", "opcode0d", "opcode0e", "opcode0f", \ "and", "and.u", "mask", "mask.u", \ "xor", "xor.u", "or", "or.u", \ "addu", "subu", "divu", "mulu", \ "add", "sub", "div", "cmp", \ "c(multi)", "f(multi)", "opcode22", "opcode23", \ "opcode24", "opcode25", "opcode26", "opcode27", \ "opcode28", "opcode29", "opcode2a", "opcode2b", \ "opcode2c", "opcode2d", "opcode2e", "opcode2f", \ "br", "br.n", "bsr", "bsr.n", \ "bb0", "bb0.n", "bb1", "bb1.n", \ "opcode38", "opcode39", "bcnd", "bcnd.n", \ "opcode3c", "3(multi)", "tbnd", "opcode3f" } #define M88K_3C_OPCODE_NAMES { \ "opcode3c_00", "opcode3c_01", "opcode3c_02", "opcode3c_03", \ "opcode3c_04", "opcode3c_05", "opcode3c_06", "opcode3c_07", \ "opcode3c_08", "opcode3c_09", "opcode3c_0a", "opcode3c_0b", \ "opcode3c_0c", "opcode3c_0d", "opcode3c_0e", "opcode3c_0f", \ "opcode3c_10", "opcode3c_11", "opcode3c_12", "opcode3c_13", \ "opcode3c_14", "opcode3c_15", "opcode3c_16", "opcode3c_17", \ "opcode3c_18", "opcode3c_19", "opcode3c_1a", "opcode3c_1b", \ "opcode3c_1c", "opcode3c_1d", "opcode3c_1e", "opcode3c_1f", \ "clr", "opcode3c_21", "set", "opcode3c_23", \ "ext", "opcode3c_25", "extu", "opcode3c_27", \ "mak", "opcode3c_29", "rot", "opcode3c_2b", \ "opcode3c_2c", "opcode3c_2d", "opcode3c_2e", "opcode3c_2f", \ "opcode3c_30", "opcode3c_31", "opcode3c_32", "opcode3c_33", \ "tb0", "opcode3c_35", "tb1", "opcode3c_37", \ "opcode3c_38", "opcode3c_39", "opcode3c_3a", "opcode3c_3b", \ "opcode3c_3c", "opcode3c_3d", "opcode3c_3e", "opcode3c_3f" } #define M88K_3D_OPCODE_NAMES { \ "opcode3d_00", "opcode3d_01", "opcode3d_02", "opcode3d_03", \ "opcode3d_04", "opcode3d_05", "opcode3d_06", "opcode3d_07", \ "opcode3d_08", "opcode3d_09", "opcode3d_0a", "opcode3d_0b", \ "opcode3d_0c", "opcode3d_0d", "opcode3d_0e", "opcode3d_0f", \ "opcode3d_10", "opcode3d_11", "opcode3d_12", "opcode3d_13", \ "opcode3d_14", "opcode3d_15", "opcode3d_16", "opcode3d_17", \ "opcode3d_18", "opcode3d_19", "opcode3d_1a", "opcode3d_1b", \ "opcode3d_1c", "opcode3d_1d", "opcode3d_1e", "opcode3d_1f", \ "opcode3d_20", "opcode3d_21", "opcode3d_22", "opcode3d_23", \ "opcode3d_24", "opcode3d_25", "opcode3d_26", "opcode3d_27", \ "opcode3d_28", "opcode3d_29", "opcode3d_2a", "opcode3d_2b", \ "opcode3d_2c", "opcode3d_2d", "opcode3d_2e", "opcode3d_2f", \ "opcode3d_30", "opcode3d_31", "opcode3d_32", "opcode3d_33", \ "opcode3d_34", "opcode3d_35", "opcode3d_36", "opcode3d_37", \ "opcode3d_38", "opcode3d_39", "opcode3d_3a", "opcode3d_3b", \ "opcode3d_3c", "opcode3d_3d", "opcode3d_3e", "opcode3d_3f", \ \ "and", "opcode3d_41", "opcode3d_42", "opcode3d_43", \ "and.c", "opcode3d_45", "opcode3d_46", "opcode3d_47", \ "opcode3d_48", "opcode3d_49", "opcode3d_4a", "opcode3d_4b", \ "opcode3d_4c", "opcode3d_4d", "opcode3d_4e", "opcode3d_4f", \ "xor", "opcode3d_51", "opcode3d_52", "opcode3d_53", \ "xor.c", "opcode3d_55", "opcode3d_56", "opcode3d_57", \ "or", "opcode3d_59", "opcode3d_5a", "opcode3d_5b", \ "or.c", "opcode3d_5d", "opcode3d_5e", "opcode3d_5f", \ "addu", "addu.co", "addu.ci", "addu.cio", \ "subu", "subu.co", "subu.ci", "subu.cio", \ "divu", "divu.d", "opcode3d_6a", "opcode3d_6b", \ "mul", "mulu.d", "muls", "opcode3d_6f", \ "add", "add.co", "add.ci", "add.cio", \ "sub", "sub.co", "sub.ci", "sub.cio", \ "div", "opcode3d_79", "opcode3d_7a", "opcode3d_7b", \ "cmp", "opcode3d_7d", "opcode3d_7e", "opcode3d_7f", \ \ "clr", "opcode3d_81", "opcode3d_82", "opcode3d_83", \ "opcode3d_84", "opcode3d_85", "opcode3d_86", "opcode3d_87", \ "set", "opcode3d_89", "opcode3d_8a", "opcode3d_8b", \ "opcode3d_8c", "opcode3d_8d", "opcode3d_8e", "opcode3d_8f", \ "ext", "opcode3d_91", "opcode3d_92", "opcode3d_93", \ "opcode3d_94", "opcode3d_95", "opcode3d_96", "opcode3d_97", \ "extu", "opcode3d_99", "opcode3d_9a", "opcode3d_9b", \ "opcode3d_9c", "opcode3d_9d", "opcode3d_9e", "opcode3d_9f", \ "mak", "opcode3d_a1", "opcode3d_a2", "opcode3d_a3", \ "opcode3d_a4", "opcode3d_a5", "opcode3d_a6", "opcode3d_a7", \ "rot", "opcode3d_a9", "opcode3d_aa", "opcode3d_ab", \ "opcode3d_ac", "opcode3d_ad", "opcode3d_ae", "opcode3d_af", \ "opcode3d_b0", "opcode3d_b1", "opcode3d_b2", "opcode3d_b3", \ "opcode3d_b4", "opcode3d_b5", "opcode3d_b6", "opcode3d_b7", \ "opcode3d_b8", "opcode3d_b9", "opcode3d_ba", "opcode3d_bb", \ "opcode3d_bc", "opcode3d_bd", "opcode3d_be", "opcode3d_bf", \ \ "jmp", "opcode3d_c1", "opcode3d_c2", "opcode3d_c3", \ "jmp.n", "opcode3d_c5", "opcode3d_c6", "opcode3d_c7", \ "jsr", "opcode3d_c9", "opcode3d_ca", "opcode3d_cb", \ "jsr.n", "opcode3d_cd", "opcode3d_ce", "opcode3d_cf", \ "opcode3d_d0", "opcode3d_d1", "opcode3d_d2", "opcode3d_d3", \ "opcode3d_d4", "opcode3d_d5", "opcode3d_d6", "opcode3d_d7", \ "opcode3d_d8", "opcode3d_d9", "opcode3d_da", "opcode3d_db", \ "opcode3d_dc", "opcode3d_dd", "opcode3d_de", "opcode3d_df", \ "opcode3d_e0", "opcode3d_e1", "opcode3d_e2", "opcode3d_e3", \ "opcode3d_e4", "opcode3d_e5", "opcode3d_e6", "opcode3d_e7", \ "ff1", "opcode3d_e9", "opcode3d_ea", "opcode3d_eb", \ "ff0", "opcode3d_ed", "opcode3d_ee", "opcode3d_ef", \ "opcode3d_f0", "opcode3d_f1", "opcode3d_f2", "opcode3d_f3", \ "opcode3d_f4", "opcode3d_f5", "opcode3d_f6", "opcode3d_f7", \ "tbnd", "opcode3d_f9", "opcode3d_fa", "opcode3d_fb", \ "opcode3d_fc", "opcode3d_fd", "opcode3d_fe", "opcode3d_ff" } /* Control register names: */ #define N_M88K_CONTROL_REGS 64 #define M88K_CR_NAMES { \ "PID", "PSR", "EPSR", "SSBR", /* 0 .. 3 */ \ "SXIP", "SNIP", "SFIP", "VBR", /* 4 .. 7 */ \ "DMT0", "DMD0", "DMA0", "DMT1", /* 8 .. 11 */ \ "DMD1", "DMA1", "DMT2", "DMD2", /* 12 .. 15 */ \ "DMA2", "SR0", "SR1", "SR2", /* 16 .. 19 */ \ "SR3", "CR21", "CR22", "CR23", /* 20 .. 23 */ \ "CR24", "CR25", "CR26", "CR27", /* 24 .. 27 */ \ "CR28", "CR29", "CR30", "CR31", /* 28 .. 31 */ \ "CR32", "CR33", "CR34", "CR35", /* 32 .. 35 */ \ "CR36", "CR37", "CR38", "CR39", /* 36 .. 39 */ \ "CR40", "CR41", "CR42", "CR43", /* 40 .. 43 */ \ "CR44", "CR45", "CR46", "CR47", /* 44 .. 47 */ \ "CR48", "CR49", "CR50", "CR51", /* 48 .. 51 */ \ "CR52", "CR53", "CR54", "CR55", /* 52 .. 55 */ \ "CR56", "CR57", "CR58", "CR59", /* 56 .. 59 */ \ "CR60", "CR61", "CR62", "CR63" /* 60 .. 63 */ } #define M88K_CR_PID 0 #define M88K_CR_PSR 1 #define M88K_CR_EPSR 2 #define M88K_CR_SSBR 3 #define M88K_CR_SXIP 4 #define M88K_CR_SNIP 5 #define M88K_CR_SFIP 6 #define M88K_CR_VBR 7 #define M88K_CR_DMT0 8 #define M88K_CR_DMD0 9 #define M88K_CR_DMA0 10 #define M88K_CR_DMT1 11 #define M88K_CR_DMD1 12 #define M88K_CR_DMA1 13 #define M88K_CR_DMT2 14 #define M88K_CR_DMD2 15 #define M88K_CR_DMA2 16 #define M88K_CR_SR0 17 #define M88K_CR_SR1 18 #define M88K_CR_SR2 19 #define M88K_CR_SR3 20 /* MVME197 extended control registers: */ #define M88K_CR_NAMES_197 { \ "PID", "PSR", "EPSR", "SSBR", /* 0 .. 3 */ \ "EXIP", "ENIP", "SFIP", "VBR", /* 4 .. 7 */ \ "DMT0", "DMD0", "DMA0", "DMT1", /* 8 .. 11 */ \ "DMD1", "DMA1", "DMT2", "DMD2", /* 12 .. 15 */ \ "SRX", "SR0", "SR1", "SR2", /* 16 .. 19 */ \ "SR3", "CR21", "CR22", "CR23", /* 20 .. 23 */ \ "CR24", "ICMD", "ICTL", "ISAR", /* 24 .. 27 */ \ "ISAP", "IUAP", "IIR", "IBP", /* 28 .. 31 */ \ "IPPU", "IPPL", "ISR", "ILAR", /* 32 .. 35 */ \ "IPAR", "CR37", "CR38", "CR39", /* 36 .. 39 */ \ "DCMD", "DCTL", "DSAR", "DSAP", /* 40 .. 43 */ \ "DUAP", "DIR", "DBP", "DPPU", /* 44 .. 47 */ \ "DPPL", "DSR", "DLAR", "DPAR", /* 48 .. 51 */ \ "CR52", "CR53", "CR54", "CR55", /* 52 .. 55 */ \ "CR56", "CR57", "CR58", "CR59", /* 56 .. 59 */ \ "CR60", "CR61", "CR62", "CR63" /* 60 .. 63 */ } #define M88K_CR_EXIP 4 #define M88K_CR_ENIP 5 #define M88K_CR_SRX 16 #define M88K_CR_ICMD 25 #define M88K_CR_ICTL 26 #define M88K_CR_ISAR 27 #define M88K_CR_ISAP 28 #define M88K_CR_IUAP 29 #define M88K_CR_IIR 30 #define M88K_CR_IBP 31 #define M88K_CR_IPPU 32 #define M88K_CR_IPPL 33 #define M88K_CR_ISR 34 #define M88K_CR_ILAR 35 #define M88K_CR_IPAR 36 #define M88K_CR_DCMD 40 #define M88K_CR_DCTL 41 #define M88K_CR_DSAR 42 #define M88K_CR_DSAP 43 #define M88K_CR_DUAP 44 #define M88K_CR_DIR 45 #define M88K_CR_DBP 46 #define M88K_CR_DPPU 47 #define M88K_CR_DPPL 48 #define M88K_CR_DSR 49 #define M88K_CR_DLAR 50 #define M88K_CR_DPAR 51 #define N_M88K_FPU_CONTROL_REGS 64 #define M88K_FPCR_FPECR 0 #define M88K_FPECR_FDVZ (1 << 3) #define M88K_FPECR_FUNIMP (1 << 6) /* ... TODO: more */ // Dyntrans: #define M88K_INSTR_ALIGNMENT_SHIFT 2 #define M88K_IC_ENTRIES_PER_PAGE 1024 // always 4 KB pages // M88K registers: #define N_M88K_REGS 32 #define M88K_ZERO_REG 0 // r0: always zero #define M88K_RETURN_REG 1 // r1: the return address on function calls #define M88K_RETURN_VALUE_REG 2 // r2: the return value, from function calls #define M88K_FIRST_ARG_REG 2 // r2..r9: eight standard arguments to functions #define M88K_STACKPOINTER_REG 31 // r31: commonly used as stack pointer #define M88K_CMP_HS 0x00000800 #define M88K_CMP_LO 0x00000400 #define M88K_CMP_LS 0x00000200 #define M88K_CMP_HI 0x00000100 #define M88K_CMP_GE 0x00000080 #define M88K_CMP_LT 0x00000040 #define M88K_CMP_LE 0x00000020 #define M88K_CMP_GT 0x00000010 #define M88K_CMP_NE 0x00000008 #define M88K_CMP_EQ 0x00000004 /* Exception numbers: */ #define M88K_EXCEPTION_RESET 0 #define M88K_EXCEPTION_INTERRUPT 1 #define M88K_EXCEPTION_INSTRUCTION_ACCESS 2 #define M88K_EXCEPTION_DATA_ACCESS 3 #define M88K_EXCEPTION_MISALIGNED_ACCESS 4 #define M88K_EXCEPTION_UNIMPLEMENTED_OPCODE 5 #define M88K_EXCEPTION_PRIVILEGE_VIOLATION 6 #define M88K_EXCEPTION_BOUNDS_CHECK_VIOLATION 7 #define M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE 8 #define M88K_EXCEPTION_INTEGER_OVERFLOW 9 #define M88K_EXCEPTION_ERROR 10 #define M88K_EXCEPTION_SFU1_PRECISE 114 #define M88K_EXCEPTION_SFU1_IMPRECISE 115 #define M88K_EXCEPTION_USER_TRAPS_START 128 /* * GXemul-specific instructions: */ /* A reserved/unimplemented instruction, used for PROM calls: */ #define M88K_PROM_INSTR 0xf400fc92 /* An instruction which aborts before doing anything: */ #define M88K_FAIL_EARLY_INSTR 0xf400fc93 /* An instruction which aborts after increasing r1: */ #define M88K_FAIL_LATE_INSTR 0xf400fc94 /* * M88200/88204 CMMU: */ #define MAX_M8820X_CMMUS 8 #define M8820X_LENGTH 0x1000 #define N_M88200_BATC_REGS 10 #define N_M88200_PATC_ENTRIES 56 #define M8820X_PATC_SUPERVISOR_BIT 0x00000001 struct m8820x_cmmu { uint32_t reg[M8820X_LENGTH / sizeof(uint32_t)]; uint32_t batc[N_M88200_BATC_REGS]; uint32_t patc_v_and_control[N_M88200_PATC_ENTRIES]; uint32_t patc_p_and_supervisorbit[N_M88200_PATC_ENTRIES]; int patc_update_index; }; /***********************************************************************/ /** * \brief A Component representing a Motorola 88000 processor. * * The only two implementations there were of the 88K architecture were * 88100 and 88110. GXemul only supports 88100 emulation so far. */ class M88K_CPUComponent : public CPUDyntransComponent { public: /** * \brief Constructs a M88K_CPUComponent. */ M88K_CPUComponent(); /** * \brief Creates a M88K_CPUComponent. */ static refcount_ptr Create(const ComponentCreateArgs& args); static string GetAttribute(const string& attributeName); virtual void ResetState(); virtual bool PreRunCheckForComponent(GXemul* gxemul); virtual size_t DisassembleInstruction(uint64_t vaddr, size_t maxlen, unsigned char *instruction, vector& result); /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); protected: virtual bool CheckVariableWrite(StateVariable& var, const string& oldValue); virtual bool VirtualToPhysical(uint64_t vaddr, uint64_t& paddr, bool& writable); virtual int FunctionTraceArgumentCount() { return 8; } virtual int64_t FunctionTraceArgument(int n) { return m_r[M88K_FIRST_ARG_REG + n]; } virtual bool FunctionTraceReturnImpl(int64_t& retval) { retval = m_r[M88K_RETURN_VALUE_REG]; return true; } virtual int GetDyntransICshift() const; virtual void (*GetDyntransToBeTranslated())(CPUDyntransComponent*, DyntransIC*); virtual void ShowRegisters(GXemul* gxemul, const vector& arguments) const; private: void Exception(int vector, int is_trap); void stcr(int cr, uint32_t value, bool is_rte); void m88k_cmp(struct DyntransIC *ic, uint32_t y); void m88k_extu(struct DyntransIC *ic, int w, int o); void m88k_ext(struct DyntransIC *ic, int w, int o); void m88k_mak(struct DyntransIC *ic, int w, int o); DECLARE_DYNTRANS_INSTR(cmp); DECLARE_DYNTRANS_INSTR(cmp_imm); DECLARE_DYNTRANS_INSTR(extu); DECLARE_DYNTRANS_INSTR(extu_imm); DECLARE_DYNTRANS_INSTR(ext); DECLARE_DYNTRANS_INSTR(ext_imm); DECLARE_DYNTRANS_INSTR(mak); DECLARE_DYNTRANS_INSTR(mak_imm); DECLARE_DYNTRANS_INSTR(divu_imm); DECLARE_DYNTRANS_INSTR(mulu_imm); DECLARE_DYNTRANS_INSTR(bsr); DECLARE_DYNTRANS_INSTR(bsr_samepage); DECLARE_DYNTRANS_INSTR(bsr_functioncalltrace); DECLARE_DYNTRANS_INSTR(bsr_n); DECLARE_DYNTRANS_INSTR(bsr_n_functioncalltrace); DECLARE_DYNTRANS_INSTR(bsr_n_functioncalltrace_singlestep); template static void instr_bcnd(CPUDyntransComponent* cpubase, DyntransIC* ic); template static void instr_bb(CPUDyntransComponent* cpubase, DyntransIC* ic); template static void instr_bb_n(CPUDyntransComponent* cpubase, DyntransIC* ic); template static void instr_bb_n_singlestep(CPUDyntransComponent* cpubase, DyntransIC* ic); DECLARE_DYNTRANS_INSTR(jmp); DECLARE_DYNTRANS_INSTR(jmp_n); DECLARE_DYNTRANS_INSTR(jmp_n_functioncalltrace); DECLARE_DYNTRANS_INSTR(jmp_n_functioncalltrace_singlestep); DECLARE_DYNTRANS_INSTR(ldcr); DECLARE_DYNTRANS_INSTR(stcr); template static void instr_tb(CPUDyntransComponent* cpubase, DyntransIC* ic); template static void instr_loadstore(CPUDyntransComponent* cpubase, DyntransIC* ic); template static void instr_lda(CPUDyntransComponent* cpubase, DyntransIC* ic); void Translate(uint32_t iword, struct DyntransIC* ic); DECLARE_DYNTRANS_INSTR(ToBeTranslated); // For unit tests: DECLARE_DYNTRANS_INSTR(fail_early); DECLARE_DYNTRANS_INSTR(fail_late); private: /* * State: */ string m_m88k_type; // E.g. "88100" uint32_t m_initial_r31; // Initial stack pointer. // General-Purpose Registers: // // 32 (N_M88K_REGS) registers, plus one which is always zero. (This // is to support st.d with d = r31. ld.d with d=r31 is converted to // just ld. uint32_t m_r[N_M88K_REGS+1]; // Destination scratch register for non-nop instructions with d=r0. // (Not serialized.) uint32_t m_zero_scratch; // Control Registers: uint32_t m_cr[N_M88K_CONTROL_REGS]; // Floating Point Control registers: uint32_t m_fcr[N_M88K_FPU_CONTROL_REGS]; /* * Cached other state: */ m88k_cpu_type_def m_type; // based on m_m88k_type }; #endif // M88K_CPUCOMPONENT_H gxemul-0.6.1/src/include/components/RootComponent.h000644 001750 001750 00000005551 13402411502 022611 0ustar00debugdebug000000 000000 #ifndef ROOTCOMPONENT_H #define ROOTCOMPONENT_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Note: This is a special component, which cannot be created interactively * by the user. */ #include "Component.h" #include "UnitTest.h" class GXemul; /** * \brief A Component which is the default root node in the configuration. * * This Component is mostly a dummy component, but it holds the 'step' * count for the entire emulation (inherited from Component), and the following * settings: * *
    *
  • accuracy ("cycle" or "sloppy") *
* * NOTE: A RootComponent is not registered in the component registry, and * can thus not be created interactively by the user at runtime. */ class RootComponent : public Component , public UnitTestable { public: /** * \brief Constructs a RootComponent. */ RootComponent(GXemul* owner = NULL); virtual RootComponent* AsRootComponent() { return this; } virtual bool PreRunCheckForComponent(GXemul* gxemul); GXemul* GetOwner() { return m_gxemul; } void SetOwner(GXemul* owner); /********************************************************************/ public: static void RunUnitTests(int& nSucceeded, int& nFailures); protected: virtual bool CheckVariableWrite(StateVariable& var, const string& oldValue); private: // Pointer to owner (may be NULL): GXemul* m_gxemul; // Model: string m_accuracy; }; #endif // ROOTCOMPONENT_H gxemul-0.6.1/src/include/components/DummyComponent.h000644 001750 001750 00000004576 13402411502 022767 0ustar00debugdebug000000 000000 #ifndef DUMMYCOMPONENT_H #define DUMMYCOMPONENT_H /* * Copyright (C) 2007-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(dummy) #include "Component.h" #include "UnitTest.h" /** * \brief A dummy Component, for unit testing purposes. */ class DummyComponent : public Component , public UnitTestable { public: /** * \brief Constructs a DummyComponent. */ DummyComponent(string className = "dummy"); /** * \brief Creates a DummyComponent. */ static refcount_ptr Create(const ComponentCreateArgs& args); /** * \brief Get attribute information about the DummyComponent class. * * @param attributeName The attribute name. * @return A string representing the attribute value. */ static string GetAttribute(const string& attributeName); /********************************************************************/ public: static void RunUnitTests(int& nSucceeded, int& nFailures); }; #endif // DUMMYCOMPONENT_H gxemul-0.6.1/src/include/components/MVME187Machine.h000644 001750 001750 00000004063 13402411502 022271 0ustar00debugdebug000000 000000 #ifndef MVME187MACHINE_H #define MVME187MACHINE_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(mvme187) #include "Component.h" /** * \brief A template for creating a MVME187 machine. * * Note: This class does not inherit from the Component class. */ class MVME187Machine { public: /** * \brief Creates a MVME187 Component tree. */ static refcount_ptr Create(const ComponentCreateArgs& args); /** * \brief Gets a Component attribute value. */ static string GetAttribute(const string& attributeName); private: MVME187Machine(); }; #endif // MVME187MACHINE_H gxemul-0.6.1/src/include/components/TestMIPSMachine.h000644 001750 001750 00000004101 13402411502 022666 0ustar00debugdebug000000 000000 #ifndef TESTMIPSMACHINE_H #define TESTMIPSMACHINE_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(testmips) #include "Component.h" /** * \brief A template for creating a "testmips" Component. * * Note: This class does not inherit from the Component class. */ class TestMIPSMachine { public: /** * \brief Creates a "testmips" Component tree. */ static refcount_ptr Create(const ComponentCreateArgs& args); /** * \brief Gets a Component attribute value. */ static string GetAttribute(const string& attributeName); private: TestMIPSMachine(); }; #endif // TESTMIPSMACHINE_H gxemul-0.6.1/src/include/components/SGI_IP30_Machine.h000644 001750 001750 00000004106 13402411502 022577 0ustar00debugdebug000000 000000 #ifndef SGI_IP30_MACHINE_H #define SGI_IP30_MACHINE_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(sgi_ip30) #include "Component.h" /** * \brief A template for creating a "sgi_ip30" Component. * * Note: This class does not inherit from the Component class. */ class SGI_IP30_Machine { public: /** * \brief Creates a "sgi_ip30" Component tree. */ static refcount_ptr Create(const ComponentCreateArgs& args); /** * \brief Gets a Component attribute value. */ static string GetAttribute(const string& attributeName); private: SGI_IP30_Machine(); }; #endif // SGI_IP30_MACHINE_H gxemul-0.6.1/src/include/components/CPUComponent.h000644 001750 001750 00000016534 13402411502 022320 0ustar00debugdebug000000 000000 #ifndef CPUCOMPONENT_H #define CPUCOMPONENT_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // Note: Not included in the component registry. #include "AddressDataBus.h" #include "Component.h" #include "SymbolRegistry.h" #include "UnitTest.h" /** * \brief A base-class for processors Component implementations. */ class CPUComponent : public Component , public AddressDataBus , public UnitTestable { public: /** * \brief Constructs a CPUComponent. * * @param className The class name for the component. * @param cpuKind The CPU kind, e.g. "MIPS R4400" for a * MIPS R4400 processor. */ CPUComponent(const string& className, const string& cpuKind); /** * \brief Gets a reference to the CPU's symbol registry. * * @return A reference to the symbol registry. */ SymbolRegistry& GetSymbolRegistry() { return m_symbolRegistry; } const SymbolRegistry& GetSymbolRegistry() const { return m_symbolRegistry; } virtual void ResetState(); virtual double GetCurrentFrequency() const; virtual CPUComponent* AsCPUComponent(); virtual void GetMethodNames(vector& names) const; virtual bool MethodMayBeReexecutedWithoutArgs(const string& methodName) const; virtual void ExecuteMethod(GXemul* gxemul, const string& methodName, const vector& arguments); virtual AddressDataBus* AsAddressDataBus(); /* Implementation of AddressDataBus: */ virtual void AddressSelect(uint64_t address); virtual bool ReadData(uint8_t& data, Endianness endianness); virtual bool ReadData(uint16_t& data, Endianness endianness); virtual bool ReadData(uint32_t& data, Endianness endianness); virtual bool ReadData(uint64_t& data, Endianness endianness); virtual bool WriteData(const uint8_t& data, Endianness endianness); virtual bool WriteData(const uint16_t& data, Endianness endianness); virtual bool WriteData(const uint32_t& data, Endianness endianness); virtual bool WriteData(const uint64_t& data, Endianness endianness); /** * \brief Disassembles an instruction into readable strings. * * @param vaddr The virtual address of the program counter. * @param maxLen The number of bytes in the instruction buffer. * @param instruction A pointer to a buffer containing the instruction. * @param result A vector where the implementation will add: *
    *
  1. machine code bytes in a standard notation *
  2. instruction mnemonic *
  3. instruction arguments *
  4. instruction comments *
* All of the fields above are optional, but they have to be * specified in the same order for a particular CPU implementation, * so that the fields of the vector can be listed in a tabular * format. * @return The number of bytes that the instruction occupied. */ virtual size_t DisassembleInstruction(uint64_t vaddr, size_t maxLen, unsigned char *instruction, vector& result) = 0; /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); protected: virtual void FlushCachedStateForComponent(); virtual bool PreRunCheckForComponent(GXemul* gxemul); virtual void ShowRegisters(GXemul* gxemul, const vector& arguments) const; uint64_t Unassemble(int nRows, bool indicatePC, uint64_t vaddr, ostream& output); /** * \brief Virtual to physical address translation (MMU). * * This function should be overridden in each CPU implementation. * * @param vaddr The virtual address to translate. * @param paddr The return value; physical address. * @param writable This is set to true or false by the function, * depending on if the memory at the virtual address was * writable or not. * @return True if the translation succeeded, false if there was a * translation error. */ virtual bool VirtualToPhysical(uint64_t vaddr, uint64_t& paddr, bool& writable) = 0; /** * \brief Format a virtual address as a displayable string. * * This function may be overridden in each CPU implementation. * The default implementation just uses the stringstream << operator. * * @param vaddr The virtual address to translate. * @return A string rendering of the virtual address, e.g. "0x00100f00" */ virtual string VirtualAddressAsString(uint64_t vaddr) { stringstream ss; ss.flags(std::ios::hex | std::ios::showbase); ss << vaddr; return ss.str(); } /** * \brief Convert PC value to instuction address. * * Usually, this does not need to be overridden. However, some * architectures use e.g. the lowest bit of the PC register to indicate * a different encoding mode (MIPS16), but the instruction is still * aligned as if the lowest bit was 0. */ virtual uint64_t PCtoInstructionAddress(uint64_t pc) { return pc; } // CPUComponent: bool FunctionTraceCall(); bool FunctionTraceReturn(); // Overridden by each CPU architecture: virtual int FunctionTraceArgumentCount() { return 0; } virtual int64_t FunctionTraceArgument(int n) { return 0; } virtual bool FunctionTraceReturnImpl(int64_t& retval) { return false; } private: bool LookupAddressDataBus(GXemul* gxemul = NULL); protected: /* * Variables common to all (or most) kinds of CPUs: */ // Framework frequency/runability: double m_frequency; bool m_paused; // Architecture fundamentals: string m_cpuArchitecture; int m_pageSize; // Program counter: uint64_t m_pc; // Memory dump and disassembly: uint64_t m_lastDumpAddr; uint64_t m_lastUnassembleVaddr; bool m_hasUsedUnassemble; // Endianness: bool m_isBigEndian; // Function call trace: bool m_showFunctionTraceCall; bool m_showFunctionTraceReturn; int32_t m_functionCallTraceDepth; int64_t m_nrOfTracedFunctionCalls; // Delay slot related: bool m_inDelaySlot; uint64_t m_delaySlotTarget; /* * Cached/volatile state: */ AddressDataBus * m_addressDataBus; uint64_t m_addressSelect; bool m_exceptionOrAbortInDelaySlot; private: SymbolRegistry m_symbolRegistry; }; #endif // CPUCOMPONENT_H gxemul-0.6.1/src/include/components/SGI_IP32_Machine.h000644 001750 001750 00000004106 13402411502 022601 0ustar00debugdebug000000 000000 #ifndef SGI_IP32_MACHINE_H #define SGI_IP32_MACHINE_H /* * Copyright (C) 2009-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(sgi_ip32) #include "Component.h" /** * \brief A template for creating a "sgi_ip32" Component. * * Note: This class does not inherit from the Component class. */ class SGI_IP32_Machine { public: /** * \brief Creates a "sgi_ip32" Component tree. */ static refcount_ptr Create(const ComponentCreateArgs& args); /** * \brief Gets a Component attribute value. */ static string GetAttribute(const string& attributeName); private: SGI_IP32_Machine(); }; #endif // SGI_IP32_MACHINE_H gxemul-0.6.1/src/include/components/MainbusComponent.h000644 001750 001750 00000007634 13402411502 023270 0ustar00debugdebug000000 000000 #ifndef MAINBUSCOMPONENT_H #define MAINBUSCOMPONENT_H /* * Copyright (C) 2008-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(mainbus) #include "AddressDataBus.h" #include "Component.h" #include "UnitTest.h" /** * \brief Main bus Component. * * An AddressDataBus Component which forwards reads and writes to * MemoryMappedComponent components (which also must implement the * AddressDataBus interface), e.g. the RAMComponent. */ class MainbusComponent : public Component , public AddressDataBus , public UnitTestable { public: /** * \brief Constructs a MainbusComponent. */ MainbusComponent(); virtual ~MainbusComponent(); /** * \brief Creates a MainbusComponent. */ static refcount_ptr Create(const ComponentCreateArgs& args); /** * \brief Get attribute information about the MainbusComponent class. * * @param attributeName The attribute name. * @return A string representing the attribute value. */ static string GetAttribute(const string& attributeName); /** * \brief Returns the component's AddressDataBus interface. * * @return A pointer to an AddressDataBus. */ virtual AddressDataBus* AsAddressDataBus(); /* Implementation of AddressDataBus: */ virtual void AddressSelect(uint64_t address); virtual bool ReadData(uint8_t& data, Endianness endianness); virtual bool ReadData(uint16_t& data, Endianness endianness); virtual bool ReadData(uint32_t& data, Endianness endianness); virtual bool ReadData(uint64_t& data, Endianness endianness); virtual bool WriteData(const uint8_t& data, Endianness endianness); virtual bool WriteData(const uint16_t& data, Endianness endianness); virtual bool WriteData(const uint32_t& data, Endianness endianness); virtual bool WriteData(const uint64_t& data, Endianness endianness); /********************************************************************/ static void RunUnitTests(int& nSucceeded, int& nFailures); protected: virtual void FlushCachedStateForComponent(); virtual bool PreRunCheckForComponent(GXemul* gxemul); private: bool MakeSureMemoryMapExists(GXemul* gxemul = NULL); private: struct MemoryMapEntry { uint64_t base; uint64_t size; uint64_t addrMul; AddressDataBus * addressDataBus; }; typedef vector MemoryMap; MemoryMap m_memoryMap; bool m_memoryMapFailed; bool m_memoryMapValid; // For the currently selected address: AddressDataBus * m_currentAddressDataBus; // TODO: direct page access... }; #endif // MAINBUSCOMPONENT_H gxemul-0.6.1/src/include/components/HP700RXMachine.h000644 001750 001750 00000004065 13402411502 022277 0ustar00debugdebug000000 000000 #ifndef HP700RXMACHINE_H #define HP700RXMACHINE_H /* * Copyright (C) 2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ // COMPONENT(hp700rx) #include "Component.h" /** * \brief A template for creating a "hp700rx" Component. * * Note: This class does not inherit from the Component class. */ class HP700RXMachine { public: /** * \brief Creates a "hp700rx" Component tree. */ static refcount_ptr Create(const ComponentCreateArgs& args); /** * \brief Gets a Component attribute value. */ static string GetAttribute(const string& attributeName); private: HP700RXMachine(); }; #endif // HP700RXMACHINE_H gxemul-0.6.1/src/old_main/timer.cc000644 001750 001750 00000015265 13402411502 017236 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Timer framework. This is used by emulated clocks. */ #include #include #include #include #include #include #include "misc.h" #include "timer.h" /* #define TEST */ struct timer { struct timer *next; double freq; void (*timer_tick)(struct timer *timer, void *extra); void *extra; double interval; double next_tick_at; }; static struct timer *first_timer = NULL; struct timeval timer_start_tv; static double timer_freq; static int timer_countdown_to_next_gettimeofday; static double timer_current_time; static double timer_current_time_step; static int timer_is_running; #define SECONDS_BETWEEN_GETTIMEOFDAY_SYNCH 1.65 /* * timer_add(): * * Adds a virtual timer to the list of timers. * * Return value is a pointer to a timer struct. */ struct timer *timer_add(double freq, void (*timer_tick)(struct timer *timer, void *extra), void *extra) { struct timer *newtimer; CHECK_ALLOCATION(newtimer = (struct timer *) malloc(sizeof(struct timer))); if (freq <= 0.00000001) freq = 0.00000001; newtimer->freq = freq; newtimer->timer_tick = timer_tick; newtimer->extra = extra; newtimer->interval = 1.0 / freq; newtimer->next_tick_at = timer_current_time + newtimer->interval; newtimer->next = first_timer; first_timer = newtimer; return newtimer; } /* * timer_remove(): * * Removes a virtual timer from the list of timers. */ void timer_remove(struct timer *t) { struct timer *prev = NULL, *cur = first_timer; while (cur != NULL && cur != t) { prev = cur; cur = cur->next; } if (cur == t) { if (prev == NULL) first_timer = cur->next; else prev->next = cur->next; free(cur); } else { fprintf(stderr, "attempt to remove timer %p which " "doesn't exist. aborting\n", t); exit(1); } } /* * timer_update_frequency(): * * Changes the frequency of an existing timer. */ void timer_update_frequency(struct timer *t, double new_freq) { if (t->freq == new_freq) return; t->freq = new_freq; if (new_freq <= 0.00000001) new_freq = 0.00000001; t->interval = 1.0 / new_freq; t->next_tick_at = timer_current_time + t->interval; } /* * timer_tick(): * * Timer tick handler. This is where the interesting stuff happens. */ static void timer_tick(int signal_nr) { struct timer *timer = first_timer; struct timeval tv; timer_current_time += timer_current_time_step; if ((--timer_countdown_to_next_gettimeofday) < 0) { gettimeofday(&tv, NULL); tv.tv_sec -= timer_start_tv.tv_sec; tv.tv_usec -= timer_start_tv.tv_usec; if (tv.tv_usec < 0) { tv.tv_usec += 1000000; tv.tv_sec --; } #ifdef TIMER_DEBUG /* For debugging/testing: */ { double diff = tv.tv_usec * 0.000001 + tv.tv_sec - timer_current_time; printf("timer: lagging behind %f seconds\n", diff); } #endif /* Get exponentially closer to the real time, instead of just changing to it directly: */ timer_current_time = ( (tv.tv_usec * 0.000001 + tv.tv_sec) + timer_current_time ) / 2; timer_countdown_to_next_gettimeofday = (int64_t) (timer_freq * SECONDS_BETWEEN_GETTIMEOFDAY_SYNCH); } while (timer != NULL) { while (timer_current_time >= timer->next_tick_at) { timer->timer_tick(timer, timer->extra); timer->next_tick_at += timer->interval; } timer = timer->next; } #ifdef TEST printf("T"); fflush(stdout); #endif } /* * timer_start(): * * Set the interval timer to timer_freq Hz, and install the signal handler. */ void timer_start(void) { struct timer *timer = first_timer; struct itimerval val; struct sigaction saction; if (timer_is_running) return; timer_is_running = 1; gettimeofday(&timer_start_tv, NULL); timer_current_time = 0.0; /* Reset all timers: */ while (timer != NULL) { timer->next_tick_at = timer->interval; timer = timer->next; } val.it_interval.tv_sec = 0; val.it_interval.tv_usec = (int) (1000000.0 / timer_freq); val.it_value.tv_sec = 0; val.it_value.tv_usec = (int) (1000000.0 / timer_freq); memset(&saction, 0, sizeof(saction)); saction.sa_handler = timer_tick; sigaction(SIGALRM, &saction, NULL); setitimer(ITIMER_REAL, &val, NULL); } /* * timer_stop(): * * Deinstall the signal handler, and disable the interval timer. */ void timer_stop(void) { struct itimerval val; struct sigaction saction; if (!timer_is_running) return; timer_is_running = 0; val.it_interval.tv_sec = 0; val.it_interval.tv_usec = 0; val.it_value.tv_sec = 0; val.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &val, NULL); memset(&saction, 0, sizeof(saction)); saction.sa_handler = NULL; sigaction(SIGALRM, &saction, NULL); } #ifdef TEST static void timer_tick_test(struct timer *t, void *extra) { printf((char *) extra); fflush(stdout); } #endif /* * timer_init(): * * Initialize the timer framework. */ void timer_init(void) { first_timer = NULL; timer_current_time = 0.0; timer_is_running = 0; timer_countdown_to_next_gettimeofday = 0; timer_freq = TIMER_BASE_FREQUENCY; timer_current_time_step = 1.0 / timer_freq; #ifdef TEST timer_add(0.5, timer_tick_test, "X"); timer_add(10.0, timer_tick_test, "."); timer_add(200.0, timer_tick_test, " "); timer_start(); while (1) sleep(999999); #endif } gxemul-0.6.1/src/old_main/misc.cc000644 001750 001750 00000007757 13402411502 017060 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * This file contains things that don't fit anywhere else, and fake/dummy * implementations of libc functions that are missing on some systems. */ #include #include #include #include #include "cpu.h" #include "misc.h" /* * mystrtoull(): * * This function is used on OSes that don't have strtoull() in libc. */ unsigned long long mystrtoull(const char *s, char **endp, int base) { unsigned long long res = 0; int minus_sign = 0; if (s == NULL) return 0; /* TODO: Implement endp? */ if (endp != NULL) { fprintf(stderr, "mystrtoull(): endp isn't implemented\n"); exit(1); } if (s[0] == '-') { minus_sign = 1; s++; } /* Guess base: */ if (base == 0) { if (s[0] == '0') { /* Just "0"? :-) */ if (!s[1]) return 0; if (s[1] == 'x' || s[1] == 'X') { base = 16; s += 2; } else { base = 8; s ++; } } else if (s[0] >= '1' && s[0] <= '9') base = 10; } while (s[0]) { int c = s[0]; if (c >= '0' && c <= '9') c -= '0'; else if (c >= 'a' && c <= 'f') c = c - 'a' + 10; else if (c >= 'A' && c <= 'F') c = c - 'A' + 10; else break; switch (base) { case 8: res = (res << 3) | c; break; case 16:res = (res << 4) | c; break; default:res = (res * base) + c; } s++; } if (minus_sign) res = (uint64_t) -(int64_t)res; return res; } /* * mymkstemp(): * * mkstemp() replacement for systems that lack that function. This is NOT * really safe, but should at least allow the emulator to build and run. */ int mymkstemp(char *templ) { int h = 0; char *p = templ; while (*p) { if (*p == 'X') *p = 48 + random() % 10; p++; } h = open(templ, O_RDWR | O_CREAT | O_EXCL, 0600); return h; } #ifdef USE_STRLCPY_REPLACEMENTS /* * mystrlcpy(): * * Quick hack strlcpy() replacement for systems that lack that function. * NOTE: No length checking is done. */ size_t mystrlcpy(char *dst, const char *src, size_t size) { strcpy(dst, src); return strlen(src); } /* * mystrlcat(): * * Quick hack strlcat() replacement for systems that lack that function. * NOTE: No length checking is done. */ size_t mystrlcat(char *dst, const char *src, size_t size) { size_t orig_dst_len = strlen(dst); strcat(dst, src); return strlen(src) + orig_dst_len; } #endif /* * print_separator_line(): * * Prints a line of "----------". */ void print_separator_line(void) { int i = 79; while (i-- > 0) debug("-"); debug("\n"); } gxemul-0.6.1/src/old_main/float_emul.cc000644 001750 001750 00000020061 13402411502 020233 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Floating point emulation routines. */ #include #include #include #include #include "float_emul.h" #include "misc.h" /* #define IEEE_DEBUG */ /* * ieee_interpret_float_value(): * * Interprets a float value from binary IEEE format into an ieee_float_value * struct. */ void ieee_interpret_float_value(uint64_t x, struct ieee_float_value *fvp, int fmt) { memset(fvp, 0, sizeof(struct ieee_float_value)); #if 0 // HACK: Use the host's float/double representation: switch (fmt) { case IEEE_FMT_S: { uint32_t x2 = x; void* p = (void*) &x2; float *pf = (float*) p; fvp->f = *pf; } break; case IEEE_FMT_D: { void* p = (void*) &x; double *pf = (double*) p; fvp->f = *pf; } break; case IEEE_FMT_W: case IEEE_FMT_L: { fvp->f = x; } break; default:fatal("ieee_interpret_float_value(): " "unimplemented format %i\n", fmt); } fvp->nan = isnan(fvp->f); #else int n_frac = 0, n_exp = 0; int i, nan, sign = 0, exponent; double fraction; /* n_frac and n_exp: */ switch (fmt) { case IEEE_FMT_S: n_frac = 23; n_exp = 8; break; case IEEE_FMT_W: n_frac = 31; n_exp = 0; break; case IEEE_FMT_D: n_frac = 52; n_exp = 11; break; case IEEE_FMT_L: n_frac = 63; n_exp = 0; break; default:fatal("ieee_interpret_float_value(): " "unimplemented format %i\n", fmt); } /* Get the Exponent: */ exponent = 0; switch (fmt) { case IEEE_FMT_W: x &= 0xffffffffULL; case IEEE_FMT_L: break; case IEEE_FMT_S: x &= 0xffffffffULL; case IEEE_FMT_D: exponent = (x >> n_frac) & ((1 << n_exp) - 1); exponent -= (1 << (n_exp-1)) - 1; break; default:fatal("ieee_interpret_float_value(): unimplemented " "format %i\n", fmt); } /* Is this a Not-A-Number? */ nan = 0; switch (fmt) { case IEEE_FMT_S: sign = (x >> 31) & 1; if ((x & ~0x80000000ULL) == 0x7f800000ULL) { fvp->f = 1.0 / 0.0; goto zero_or_no_reasonable_result; } if ((x & 0x7f800000ULL) == 0x7f800000ULL) nan = 1; break; case IEEE_FMT_D: sign = (x >> 63) & 1; if ((x & ~0x8000000000000000ULL) == 0x7ff0000000000000ULL) { fvp->f = 1.0 / 0.0; goto zero_or_no_reasonable_result; } if ((x & 0x7ff0000000000000ULL) == 0x7ff0000000000000ULL) nan = 1; break; } if (nan) { fvp->f = NAN; goto no_reasonable_result; } /* Calculate the fraction: */ fraction = 0.0; switch (fmt) { case IEEE_FMT_W: { int32_t r_int = x; fraction = r_int; } break; case IEEE_FMT_L: { int64_t r_int = x; fraction = r_int; } break; case IEEE_FMT_S: case IEEE_FMT_D: if (x == 0 || (fmt == IEEE_FMT_D && x == 0x8000000000000000ULL) || (fmt == IEEE_FMT_S && x == 0x80000000ULL)) { fvp->f = 0.0; goto zero_or_no_reasonable_result; } fraction = 0.0; for (i=0; i> i) & 1; fraction /= 2.0; if (bit) fraction += 1.0; } /* Add implicit bit 0: */ fraction = (fraction / 2.0) + 1.0; break; default:fatal("ieee_interpret_float_value(): " "unimplemented format %i\n", fmt); } /* form the value: */ fvp->f = fraction; #ifdef IEEE_DEBUG fatal("{ ieee: x=%016"PRIx64" => sign=%i exponent=%i frac=%f ", (uint64_t) x, sign, exponent, fraction); #endif /* TODO: this is awful for exponents of large magnitude. */ if (exponent > 0) { /* * NOTE / TODO: * * This is an ulgy workaround on Alpha, where it seems that * multiplying by 2, 1024 times causes a floating point * exception. (Triggered by running for example NetBSD/pmax * 2.0 emulated on an Alpha host.) */ if (exponent == 1024) exponent = 1023; while (exponent-- > 0) fvp->f *= 2.0; } else if (exponent < 0) { while (exponent++ < 0) fvp->f /= 2.0; } zero_or_no_reasonable_result: if (sign) fvp->f = -fvp->f; no_reasonable_result: fvp->nan = nan; #ifdef IEEE_DEBUG fatal("nan=%i (f=%f) }\n", nan, fvp->f); #endif #endif } /* * ieee_store_float_value(): * * Generates a 64-bit IEEE-formated value in a specific format. */ uint64_t ieee_store_float_value(double nf, int fmt) { int n_frac = 0, n_exp = 0, signofs = 0, i, exponent; uint64_t r = 0, r2; int64_t r3; /* n_frac and n_exp: */ switch (fmt) { case IEEE_FMT_S: n_frac = 23; n_exp = 8; signofs = 31; break; case IEEE_FMT_W: n_frac = 31; n_exp = 0; signofs = 31; break; case IEEE_FMT_D: n_frac = 52; n_exp = 11; signofs = 63; break; case IEEE_FMT_L: n_frac = 63; n_exp = 0; signofs = 63; break; default:fatal("ieee_store_float_value(): unimplemented format" " %i\n", fmt); } switch (fmt) { case IEEE_FMT_W: case IEEE_FMT_L: /* * This causes an implicit conversion of double to integer. * If nf < 0.0, then r2 will begin with a sequence of binary * 1's, which is ok. */ r3 = (int64_t) nf; r2 = r3; r |= r2; break; case IEEE_FMT_S: case IEEE_FMT_D: /* sign bit: */ if (signbit(nf)) { r |= ((uint64_t)1 << signofs); } // printf("fpclassify(nf) = %i\n", fpclassify(nf)); switch (fpclassify(nf)) { case FP_INFINITE: if (fmt == IEEE_FMT_D) r |= 0x7ff0000000000000ULL; else r |= 0x7f800000ULL; break; case FP_NAN: if (fmt == IEEE_FMT_D) r |= 0x7fffffffffffffffULL; else r |= 0x7fffffffULL; break; case FP_NORMAL: if (signbit(nf)) nf = -nf; /* * How to convert back from double to exponent + fraction: * The fraction should be 1.xxx, that is * 1.0 <= fraction < 2.0 * * This method is very slow but should work: * (TODO: Fix the performance problem!) */ exponent = 0; while (nf < 1.0 && exponent > -1023) { nf *= 2.0; exponent --; } while (nf >= 2.0 && exponent < 1023) { nf /= 2.0; exponent ++; } /* Here: 1.0 <= nf < 2.0 */ nf -= 1.0; /* remove implicit first bit */ for (i=n_frac-1; i>=0; i--) { nf *= 2.0; if (nf >= 1.0) { r |= ((uint64_t)1 << i); nf -= 1.0; } } /* Insert the exponent into the resulting word: */ /* (First bias, then make sure it's within range) */ exponent += (((uint64_t)1 << (n_exp-1)) - 1); if (exponent < 0) exponent = 0; if (exponent >= ((int64_t)1 << n_exp)) exponent = ((int64_t)1 << n_exp) - 1; r |= (uint64_t)exponent << n_frac; /* Special case for 0.0: */ if (exponent == 0) r = 0; break; case FP_SUBNORMAL: // TODO break; case FP_ZERO: // r already has zeros in the lowest bits. Done. break; } break; default:/* TODO */ fatal("ieee_store_float_value(): unimplemented format %i\n", fmt); } if (fmt == IEEE_FMT_S || fmt == IEEE_FMT_W) r = (uint32_t) r; return r; } gxemul-0.6.1/src/old_main/interrupt.cc000644 001750 001750 00000017365 13402411502 020155 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * The interrupt subsystem. * * Interrupts have a "path", e.g. "machine[0].cpu.5". A device which * wishes to cause this interrupt needs to connect to it. * * The possible interrupt paths are registered by CPUs, interrupt controllers, * etc., that have a way of receiving interrupt requests. The physical * version of an interrupt path is usually a "pin" on the CPU, or similar. * * Once connected, the interrupt can be asserted or deasserted. * * For examples on how it is used, see the various devices in src/devices/. */ #include #include #include #include "interrupt.h" #include "misc.h" /* #define INTERRUPT_DEBUG */ struct interrupt_handler { struct interrupt templ; int nr_of_exclusive_users; int nr_of_nonexclusive_users; }; static int nr_of_interrupt_handlers = 0; static struct interrupt_handler *interrupt_handlers = NULL; /* * Dummy interrupt assert/deassert for "no interrupt" interrupts: */ static void no_interrupt_assert(struct interrupt *i) { } static void no_interrupt_deassert(struct interrupt *i) { } /* * interrupt_handler_register(): * * Add an interrupt handler to the interrupt subsystem. The template * needs to have all members set. * * Name is of the form "machine[0].cpu[0].irq[3].isa[14]" etc. * * If there already is a handler with this name, the emulator aborts. */ void interrupt_handler_register(struct interrupt *templ) { int i; #ifdef INTERRUPT_DEBUG printf("interrupt_handler_register(\"%s\")\n", templ->name); #endif /* See if the name is already registered: */ for (i=0; iname, interrupt_handlers[i].templ.name) != 0) continue; fatal("\ninterrupt_handler_register(): An interrupt handler" " using the name '%s' is already registered.\n", templ->name); exit(1); } nr_of_interrupt_handlers ++; CHECK_ALLOCATION(interrupt_handlers = (struct interrupt_handler *) realloc(interrupt_handlers, nr_of_interrupt_handlers * sizeof(struct interrupt_handler))); interrupt_handlers[nr_of_interrupt_handlers-1].templ = *templ; CHECK_ALLOCATION(interrupt_handlers[nr_of_interrupt_handlers-1]. templ.name = strdup(templ->name)); } /* * interrupt_handler_remove(): * * Remove an interrupt handler from the interrupt subsystem. If there are * still connected users of this interrupt, then an error message is printed * and the emulator aborts. */ void interrupt_handler_remove(const char *name) { int i; #ifdef INTERRUPT_DEBUG printf("interrupt_handler_remove(\"%s\")\n", name); #endif for (i=0; i 0 || interrupt_handlers[i].nr_of_nonexclusive_users > 0) { fatal("interrupt_handler_remove(): Attempt to " "remove interrupt handler '%s' which has %i " "exclusive and %i non-exclusive users. Aborting.\n", name, interrupt_handlers[i].nr_of_exclusive_users, interrupt_handlers[i].nr_of_nonexclusive_users); exit(1); } if (i != nr_of_interrupt_handlers-1) memcpy(&interrupt_handlers[i], &interrupt_handlers[i + 1], nr_of_interrupt_handlers - i - 1); nr_of_interrupt_handlers --; return; } fatal("interrupt_handler_remove(): '%s' not found? Aborting.\n", name); exit(1); } /* * interrupt_handler_lookup(): * * Scans the list of registered interrupt handlers for a given name. If the * name is found, the template is filled with valid data, and 1 is returned. * If the name is not found, 0 is returned. */ int interrupt_handler_lookup(const char *name, struct interrupt *templ) { int i; #ifdef INTERRUPT_DEBUG printf("interrupt_handler_lookup(\"%s\")\n", name); #endif if (name[0] == '\0') { /* No interrupt: */ memset(templ, 0, sizeof(struct interrupt)); templ->interrupt_assert = no_interrupt_assert; templ->interrupt_deassert = no_interrupt_deassert; } for (i=0; i= nr_of_interrupt_handlers) { printf("interrupt_handler_lookup(\"%s\") failed. " "Aborting.\n", name); abort(); } return 0; } /* * interrupt_connect(): * * Increases the exclusive or nonexclusive nr or users of an interrupt. */ void interrupt_connect(struct interrupt *in, int exclusive) { int i; #ifdef INTERRUPT_DEBUG printf("interrupt_connect(\"%s\")\n", in->name); #endif if (in->name == NULL || in->name[0] == '\0') return; for (i=0; iname, interrupt_handlers[i].templ.name) != 0) continue; if (exclusive) { interrupt_handlers[i].nr_of_exclusive_users ++; if (interrupt_handlers[i].nr_of_exclusive_users > 1) { fatal("Fatal error in interrupt_connect(): " "more than 1 exclusive user. Dumping " "core for backtrace.\n"); abort(); } } else { interrupt_handlers[i].nr_of_nonexclusive_users ++; } return; } fatal("Internal error in interrupt_connect(): name '%s' not " "found? Dumping core for debugging.\n", in->name); abort(); } /* * interrupt_disconnect(): * * Decreases the exclusive or nonexclusive nr or users of an interrupt. */ void interrupt_disconnect(struct interrupt *in, int exclusive) { int i; if (in->name == NULL || in->name[0] == '\0') return; for (i=0; iname, interrupt_handlers[i].templ.name) != 0) continue; if (exclusive) { interrupt_handlers[i].nr_of_exclusive_users --; if (interrupt_handlers[i].nr_of_exclusive_users < 0) { fatal("Fatal error in interrupt_disconnect():" "nr of exclusive users < 0?\n"); exit(1); } } else { interrupt_handlers[i].nr_of_nonexclusive_users --; if (interrupt_handlers[i].nr_of_nonexclusive_users<0) { fatal("Fatal error in interrupt_disconnect():" "nr of non-exclusive users < 0?\n"); exit(1); } } return; } fatal("Internal error in interrupt_disconnect(): name '%s' not " "found?\n", in->name); exit(1); } gxemul-0.6.1/src/old_main/emul.cc000644 001750 001750 00000053336 13402411502 017061 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * LEGACY emulation startup and misc. routines. */ #include #include #include #include #include #include #include #include "arcbios.h" #include "cpu.h" #include "emul.h" #include "console.h" #include "debugger.h" #include "device.h" #include "diskimage.h" #include "machine.h" #include "memory.h" #include "mips_cpu_types.h" #include "misc.h" #include "net.h" #include "settings.h" #include "timer.h" #include "x11.h" #include "thirdparty/exec_elf.h" extern int extra_argc; extern char **extra_argv; extern int verbose; extern int quiet_mode; extern int force_debugger_at_exit; extern int single_step; extern int old_show_trace_tree; extern int old_instruction_trace; extern int old_quiet_mode; extern int quiet_mode; /* * add_breakpoints(): * * Take the strings breakpoint_string[] and convert to addresses * (and store them in breakpoint_addr[]). * * TODO: This function should be moved elsewhere. */ static void add_breakpoints(struct machine *m) { int i; int string_flag; uint64_t dp; for (i=0; ibreakpoints.n; i++) { string_flag = 0; dp = strtoull(m->breakpoints.string[i], NULL, 0); /* * If conversion resulted in 0, then perhaps it is a * symbol: */ if (dp == 0) { uint64_t addr; int res = get_symbol_addr(&m->symbol_context, m->breakpoints.string[i], &addr); if (!res) { fprintf(stderr, "ERROR! Breakpoint '%s' could not be" " parsed\n", m->breakpoints.string[i]); exit(1); } else { dp = addr; string_flag = 1; } } /* * TODO: It would be nice if things like symbolname+0x1234 * were automatically converted into the correct address. */ if (m->arch == ARCH_MIPS) { if ((dp >> 32) == 0 && ((dp >> 31) & 1)) dp |= 0xffffffff00000000ULL; } m->breakpoints.addr[i] = dp; debug("breakpoint %i: 0x%" PRIx64, i, dp); if (string_flag) debug(" (%s)", m->breakpoints.string[i]); debug("\n"); } } /* * fix_console(): */ static void fix_console(void) { console_deinit_main(); } /* * emul_new(): * * Returns a reasonably initialized struct emul. */ struct emul *emul_new(char *name) { struct emul *e; CHECK_ALLOCATION(e = (struct emul *) malloc(sizeof(struct emul))); memset(e, 0, sizeof(struct emul)); e->settings = settings_new(); settings_add(e->settings, "n_machines", 0, SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL, (void *) &e->n_machines); /* TODO: More settings? */ /* Sane default values: */ e->n_machines = 0; e->next_serial_nr = 1; if (name != NULL) { CHECK_ALLOCATION(e->name = strdup(name)); settings_add(e->settings, "name", 0, SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING, (void *) &e->name); } return e; } /* * emul_destroy(): * * Destroys a previously created emul object. */ void emul_destroy(struct emul *emul) { int i; if (emul->name != NULL) { settings_remove(emul->settings, "name"); free(emul->name); } for (i=0; in_machines; i++) machine_destroy(emul->machines[i]); if (emul->machines != NULL) free(emul->machines); /* Remove any remaining level-1 settings: */ settings_remove_all(emul->settings); settings_destroy(emul->settings); free(emul); } /* * emul_add_machine(): * * Calls machine_new(), adds the new machine into the emul struct, and * returns a pointer to the new machine. * * This function should be used instead of manually calling machine_new(). */ struct machine *emul_add_machine(struct emul *e, char *name) { struct machine *m; char tmpstr[20]; int i; m = machine_new(name, e, e->n_machines); m->serial_nr = (e->next_serial_nr ++); i = e->n_machines ++; CHECK_ALLOCATION(e->machines = (struct machine **) realloc(e->machines, sizeof(struct machine *) * e->n_machines)); e->machines[i] = m; snprintf(tmpstr, sizeof(tmpstr), "machine[%i]", i); settings_add(e->settings, tmpstr, 1, SETTINGS_TYPE_SUBSETTINGS, 0, e->machines[i]->settings); return m; } /* * add_arc_components(): * * This function adds ARCBIOS memory descriptors for the loaded program, * and ARCBIOS components for SCSI devices. */ static void add_arc_components(struct machine *m) { struct cpu *cpu = m->cpus[m->bootstrap_cpu]; uint64_t start = cpu->pc & 0x1fffffff; uint64_t len = 0xc00000 - start; struct diskimage *d; uint64_t scsicontroller, scsidevice, scsidisk; if ((cpu->pc >> 60) != 0xf) { start = cpu->pc & 0xffffffffffULL; len = 0xc00000 - start; } len += 1048576 * m->memory_offset_in_mb; /* * NOTE/TODO: magic 12MB end of load program area * * Hm. This breaks the old FreeBSD/MIPS snapshots... */ #if 0 arcbios_add_memory_descriptor(cpu, 0x60000 + m->memory_offset_in_mb * 1048576, start-0x60000 - m->memory_offset_in_mb * 1048576, ARCBIOS_MEM_FreeMemory); #endif arcbios_add_memory_descriptor(cpu, start, len, ARCBIOS_MEM_LoadedProgram); scsicontroller = arcbios_get_scsicontroller(m); if (scsicontroller == 0) return; /* TODO: The device 'name' should defined be somewhere else. */ d = m->first_diskimage; while (d != NULL) { if (d->type == DISKIMAGE_SCSI) { int a, b, flags = COMPONENT_FLAG_Input; char component_string[100]; const char *name = "DEC RZ58 (C) DEC2000"; /* Read-write, or read-only? */ if (d->writable) flags |= COMPONENT_FLAG_Output; else flags |= COMPONENT_FLAG_ReadOnly; a = COMPONENT_TYPE_DiskController; b = COMPONENT_TYPE_DiskPeripheral; if (d->is_a_cdrom) { flags |= COMPONENT_FLAG_Removable; a = COMPONENT_TYPE_CDROMController; b = COMPONENT_TYPE_FloppyDiskPeripheral; name = "NEC CD-ROM CDR-210P 1.0 "; } scsidevice = arcbios_addchild_manual(cpu, COMPONENT_CLASS_ControllerClass, a, flags, 1, 2, d->id, 0xffffffff, name, scsicontroller, NULL, 0); scsidisk = arcbios_addchild_manual(cpu, COMPONENT_CLASS_PeripheralClass, b, flags, 1, 2, 0, 0xffffffff, NULL, scsidevice, NULL, 0); /* * Add device string to component address mappings: * "scsi(0)disk(0)rdisk(0)partition(0)" */ if (d->is_a_cdrom) { snprintf(component_string, sizeof(component_string), "scsi(0)cdrom(%i)", d->id); arcbios_add_string_to_component(m, component_string, scsidevice); snprintf(component_string, sizeof(component_string), "scsi(0)cdrom(%i)fdisk(0)", d->id); arcbios_add_string_to_component(m, component_string, scsidisk); } else { snprintf(component_string, sizeof(component_string), "scsi(0)disk(%i)", d->id); arcbios_add_string_to_component(m, component_string, scsidevice); snprintf(component_string, sizeof(component_string), "scsi(0)disk(%i)rdisk(0)", d->id); arcbios_add_string_to_component(m, component_string, scsidisk); } } d = d->next; } } /* * emul_machine_setup(): * * o) Initialize the hardware (RAM, devices, CPUs, ...) which * will be emulated in this machine. * * o) Load ROM code and/or other programs into emulated memory. * * o) Special hacks needed after programs have been loaded. */ void emul_machine_setup(struct machine *m, int n_load, char **load_names, int n_devices, char **device_names) { struct cpu *cpu; int i, iadd = DEBUG_INDENTATION; uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0; int byte_order; if (m->name != NULL) debug("machine \"%s\":\n", m->name); else debug("machine:\n"); debug_indentation(iadd); if (m->machine_type == MACHINE_NONE) { fatal("No machine type specified?\n"); exit(1); } m->cpu_family = cpu_family_ptr_by_number(m->arch); if (m->arch == ARCH_ALPHA) m->arch_pagesize = 8192; machine_memsize_fix(m); /* * Create the system's memory: */ debug("memory: %i MB", m->physical_ram_in_mb); memory_amount = (uint64_t)m->physical_ram_in_mb * 1048576; if (m->memory_offset_in_mb > 0) { /* * A special hack is used for some SGI models, * where memory is offset by 128MB to leave room for * EISA space and other things. */ debug(" (offset by %iMB)", m->memory_offset_in_mb); memory_amount += 1048576 * m->memory_offset_in_mb; } m->memory = memory_new(memory_amount, m->arch); debug("\n"); /* Create CPUs: */ if (m->cpu_name == NULL) machine_default_cputype(m); if (m->ncpus == 0) m->ncpus = 1; CHECK_ALLOCATION(m->cpus = (struct cpu **) malloc(sizeof(struct cpu *) * m->ncpus)); memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus); debug("cpu0"); if (m->ncpus > 1) debug(" .. cpu%i", m->ncpus - 1); debug(": "); for (i=0; incpus; i++) { m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name); if (m->cpus[i] == NULL) { fprintf(stderr, "Unable to create CPU object. " "Aborting."); exit(1); } } debug("\n"); if (m->use_random_bootstrap_cpu) m->bootstrap_cpu = random() % m->ncpus; else m->bootstrap_cpu = 0; cpu = m->cpus[m->bootstrap_cpu]; if (m->x11_md.in_use) x11_init(m); /* Fill memory with random bytes: */ if (m->random_mem_contents) { for (i=0; iphysical_ram_in_mb * 1048576; i+=256) { unsigned char data[256]; unsigned int j; for (j=0; jmemory_rw(cpu, m->memory, i, data, sizeof(data), MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS | PHYSICAL); } } for (i=0; ifirst_diskimage != NULL) { if (!load_bootblock(m, cpu, &n_load, &load_names)) { fprintf(stderr, "\nNo executable files were" " specified, and booting directly from disk" " failed.\n"); exit(1); } } else { fprintf(stderr, "No executable file(s) loaded, and " "we are not booting directly from a disk image." "\nAborting.\n"); exit(1); } } while (n_load > 0) { FILE *tmp_f; char *name_to_load = *load_names; int remove_after_load = 0; /* Special hack for removing temporary files: */ if (name_to_load[0] == 8) { name_to_load ++; remove_after_load = 1; } /* * gzipped files are automagically gunzipped: * NOTE/TODO: This isn't secure. system() is used. */ tmp_f = fopen(name_to_load, "r"); if (tmp_f != NULL) { unsigned char buf[2]; /* gzip header */ size_t res; memset(buf, 0, sizeof(buf)); res = fread(buf, 1, sizeof(buf), tmp_f); if (res == sizeof(buf) && buf[0] == 0x1f && buf[1] == 0x8b) { size_t zzlen = strlen(name_to_load)*2 + 100; char *zz; CHECK_ALLOCATION(zz = (char*) malloc(zzlen)); debug("gunziping %s\n", name_to_load); /* * gzip header found. If this was a file * extracted from, say, a CDROM image, then it * already has a temporary name. Otherwise we * have to gunzip into a temporary file. */ if (remove_after_load) { snprintf(zz, zzlen, "mv %s %s.gz", name_to_load, name_to_load); if (system(zz) != 0) perror(zz); snprintf(zz, zzlen, "gunzip %s.gz", name_to_load); if (system(zz) != 0) perror(zz); } else { /* gunzip into new temp file: */ int tmpfile_handle; char *new_temp_name; const char *tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) tmpdir = DEFAULT_TMP_DIR; CHECK_ALLOCATION(new_temp_name = (char*) malloc(300)); snprintf(new_temp_name, 300, "%s/gxemul.XXXXXXXXXXXX", tmpdir); tmpfile_handle = mkstemp(new_temp_name); close(tmpfile_handle); snprintf(zz, zzlen, "gunzip -c '%s' > " "%s", name_to_load, new_temp_name); if (system(zz) != 0) perror(zz); name_to_load = new_temp_name; remove_after_load = 1; } free(zz); } fclose(tmp_f); } byte_order = NO_BYTE_ORDER_OVERRIDE; /* * Load the file: :-) */ file_load(m, m->memory, name_to_load, &entrypoint, m->arch, &gp, &byte_order, &toc); if (remove_after_load) { debug("removing %s\n", name_to_load); unlink(name_to_load); } if (byte_order != NO_BYTE_ORDER_OVERRIDE) cpu->byte_order = byte_order; cpu->pc = entrypoint; switch (m->arch) { case ARCH_ALPHA: /* For position-independent code: */ cpu->cd.alpha.r[ALPHA_T12] = cpu->pc; break; case ARCH_ARM: if (cpu->pc & 2) { fatal("ARM: misaligned pc: TODO\n"); exit(1); } cpu->pc = (uint32_t)cpu->pc; // Lowest bit of PC indicates THUMB mode. if (cpu->pc & 1) cpu->cd.arm.cpsr |= ARM_FLAG_T; break; case ARCH_M88K: if (cpu->pc & 3) { fatal("M88K: lowest bits of pc set: TODO\n"); exit(1); } cpu->pc &= 0xfffffffc; break; case ARCH_MIPS: if ((cpu->pc >> 32) == 0 && (cpu->pc & 0x80000000ULL)) cpu->pc |= 0xffffffff00000000ULL; cpu->cd.mips.gpr[MIPS_GPR_GP] = gp; if ((cpu->cd.mips.gpr[MIPS_GPR_GP] >> 32) == 0 && (cpu->cd.mips.gpr[MIPS_GPR_GP] & 0x80000000ULL)) cpu->cd.mips.gpr[MIPS_GPR_GP] |= 0xffffffff00000000ULL; break; case ARCH_PPC: /* See http://www.linuxbase.org/spec/ELF/ppc64/ spec/x458.html for more info. */ cpu->cd.ppc.gpr[2] = toc; /* TODO */ if (cpu->cd.ppc.bits == 32) cpu->pc &= 0xffffffffULL; break; case ARCH_SH: if (cpu->cd.sh.cpu_type.bits == 32) cpu->pc &= 0xffffffffULL; cpu->pc &= ~1; break; default: fatal("emul_machine_setup(): Internal error: " "Unimplemented arch %i\n", m->arch); exit(1); } n_load --; load_names ++; } if (m->byte_order_override != NO_BYTE_ORDER_OVERRIDE) cpu->byte_order = m->byte_order_override; /* Same byte order and entrypoint for all CPUs: */ for (i=0; incpus; i++) if (i != m->bootstrap_cpu) { m->cpus[i]->byte_order = cpu->byte_order; m->cpus[i]->pc = cpu->pc; } /* Startup the bootstrap CPU: */ cpu->running = 1; /* ... or pause all CPUs, if start_paused is set: */ if (m->start_paused) { for (i=0; incpus; i++) m->cpus[i]->running = 0; } /* Parse and add breakpoints: */ add_breakpoints(m); /* TODO: This is MIPS-specific! */ if (m->machine_type == MACHINE_PMAX && cpu->cd.mips.cpu_type.mmu_model == MMU3K) add_symbol_name(&m->symbol_context, 0x9fff0000, 0x10000, "r2k3k_cache", 0, 0); symbol_recalc_sizes(&m->symbol_context); /* Special hack for ARC/SGI emulation: */ if ((m->machine_type == MACHINE_ARC || m->machine_type == MACHINE_SGI) && m->prom_emulation) add_arc_components(m); debug("cpu%i: starting at ", m->bootstrap_cpu); switch (m->arch) { case ARCH_MIPS: if (cpu->is_32bit) { debug("0x%08" PRIx32, (uint32_t) m->cpus[m->bootstrap_cpu]->pc); if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0) debug(" (gp=0x%08" PRIx32")", (uint32_t) m->cpus[m->bootstrap_cpu]->cd.mips.gpr[ MIPS_GPR_GP]); } else { debug("0x%016" PRIx64, (uint64_t) m->cpus[m->bootstrap_cpu]->pc); if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0) debug(" (gp=0x%016" PRIx64")", (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_GP]); } break; default: if (cpu->is_32bit) debug("0x%08" PRIx32, (uint32_t) cpu->pc); else debug("0x%016" PRIx64, (uint64_t) cpu->pc); } debug("\n"); debug_indentation(-iadd); } /* * emul_dumpinfo(): * * Dump info about all machines in an emul. */ void emul_dumpinfo(struct emul *e) { int i; if (e->net != NULL) net_dumpinfo(e->net); for (i = 0; i < e->n_machines; i++) { if (e->n_machines > 1) debug("machine %i: \"%s\"\n", i, e->machines[i]->name); else debug("machine:\n"); debug_indentation(DEBUG_INDENTATION); machine_dumpinfo(e->machines[i]); debug_indentation(-DEBUG_INDENTATION); } } /* * emul_simple_init(): * * For a normal setup: * * o) Initialize a network. * o) Initialize one machine. */ void emul_simple_init(struct emul *emul) { int iadd = DEBUG_INDENTATION; struct machine *m; if (emul->n_machines != 1) { fprintf(stderr, "emul_simple_init(): n_machines != 1\n"); exit(1); } m = emul->machines[0]; debug("Simple setup...\n"); debug_indentation(iadd); /* Create a simple network: */ emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY, NET_DEFAULT_IPV4_MASK, NET_DEFAULT_IPV4_LEN, NULL, 0, 0, NULL); /* Create the machine: */ emul_machine_setup(m, extra_argc, extra_argv, 0, NULL); debug_indentation(-iadd); } /* * emul_create_from_configfile(): * * Create an emul struct by reading settings from a configuration file. */ struct emul *emul_create_from_configfile(char *fname) { int iadd = DEBUG_INDENTATION; struct emul *e = emul_new(fname); debug("Creating emulation from configfile \"%s\":\n", fname); debug_indentation(iadd); emul_parse_config(e, fname); debug_indentation(-iadd); return e; } /* * emul_run(): * * o) Set up things needed before running an emulation. * * o) Run instructions in all machines. * * o) De-initialize things. */ void emul_run(struct emul *emul) { int i = 0, j, go = 1, n, anything; atexit(fix_console); if (emul == NULL) { fatal("No emulation defined. Aborting.\n"); return; } if (emul->n_machines == 0) { fatal("No machine(s) defined. Aborting.\n"); return; } /* Initialize the interactive debugger: */ debugger_init(emul); /* Run any additional debugger commands before starting: */ if (emul->n_debugger_cmds > 0) { if (i == 0) print_separator_line(); for (int k = 0; k < emul->n_debugger_cmds; k ++) { debug("> %s\n", emul->debugger_cmds[k]); debugger_execute_cmd(emul->debugger_cmds[k], strlen(emul->debugger_cmds[k])); } } print_separator_line(); debug("\n"); /* * console_init_main() makes sure that the terminal is in a * reasonable state. * * The SIGINT handler is for CTRL-C (enter the interactive debugger). * * The SIGCONT handler is invoked whenever the user presses CTRL-Z * (or sends SIGSTOP) and then continues. It makes sure that the * terminal is in an expected state. */ console_init_main(emul); signal(SIGINT, debugger_activate); signal(SIGCONT, console_sigcont); /* Not in verbose mode? Then set quiet_mode. */ if (!verbose) quiet_mode = 1; /* Initialize all CPUs in all machines: */ for (j=0; jn_machines; j++) cpu_run_init(emul->machines[j]); /* TODO: Generalize: */ if (emul->machines[0]->show_trace_tree) cpu_functioncall_trace(emul->machines[0]->cpus[0], emul->machines[0]->cpus[0]->pc); /* Start emulated clocks: */ timer_start(); /* * MAIN LOOP: * * Run all emulations in parallel, running instructions from each * cpu in each machine. */ while (go) { struct cpu *bootcpu = emul->machines[0]->cpus[ emul->machines[0]->bootstrap_cpu]; go = 0; /* Flush X11 and serial console output every now and then: */ if (bootcpu->ninstrs > bootcpu->ninstrs_flush + (1<<19)) { x11_check_event(emul); console_flush(); bootcpu->ninstrs_flush = bootcpu->ninstrs; } if (bootcpu->ninstrs > bootcpu->ninstrs_show + (1<<25)) { bootcpu->ninstrs_since_gettimeofday += (bootcpu->ninstrs - bootcpu->ninstrs_show); cpu_show_cycles(emul->machines[0], 0); bootcpu->ninstrs_show = bootcpu->ninstrs; } if (single_step == ENTER_SINGLE_STEPPING) { /* TODO: Cleanup! */ old_instruction_trace = emul->machines[0]->instruction_trace; old_quiet_mode = quiet_mode; old_show_trace_tree = emul->machines[0]->show_trace_tree; emul->machines[0]->instruction_trace = 1; emul->machines[0]->show_trace_tree = 1; quiet_mode = 0; single_step = SINGLE_STEPPING; } if (single_step == SINGLE_STEPPING) debugger(); for (j=0; jn_machines; j++) { anything = machine_run(emul->machines[j]); if (anything) go = 1; } } /* Stop any running timers: */ timer_stop(); /* Deinitialize all CPUs in all machines: */ for (j=0; jn_machines; j++) cpu_run_deinit(emul->machines[j]); /* force_debugger_at_exit flag set? Then enter the debugger: */ if (force_debugger_at_exit) { quiet_mode = 0; debugger_reset(); debugger(); } /* Any machine using X11? Then wait before exiting: */ n = 0; for (j=0; jn_machines; j++) if (emul->machines[j]->x11_md.in_use) n++; if (n > 0) { printf("Press enter to quit.\n"); while (!console_charavail(MAIN_CONSOLE)) { x11_check_event(emul); usleep(10000); } console_readchar(MAIN_CONSOLE); } console_deinit_main(); } gxemul-0.6.1/src/old_main/memory.cc000644 001750 001750 00000063506 13402411502 017427 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Functions for handling the memory of an emulated machine. */ #include #include #include #include #include #include "cpu.h" #include "machine.h" #include "memory.h" #include "misc.h" extern int verbose; extern int quiet_mode; /* * memory_readmax64(): * * Read at most 64 bits of data from a buffer. Length is given by * len, and the byte order by cpu->byte_order. * * This function should not be called with cpu == NULL. */ uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len) { int i, byte_order = cpu->byte_order; uint64_t x = 0; if (len & MEM_PCI_LITTLE_ENDIAN) { len &= ~MEM_PCI_LITTLE_ENDIAN; byte_order = EMUL_LITTLE_ENDIAN; } /* Switch byte order for incoming data, if necessary: */ if (byte_order == EMUL_BIG_ENDIAN) for (i=0; i=0; i--) { x <<= 8; x |= buf[i]; } return x; } /* * memory_writemax64(): * * Write at most 64 bits of data to a buffer. Length is given by * len, and the byte order by cpu->byte_order. * * This function should not be called with cpu == NULL. */ void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, uint64_t data) { int i, byte_order = cpu->byte_order; if (len & MEM_PCI_LITTLE_ENDIAN) { len &= ~MEM_PCI_LITTLE_ENDIAN; byte_order = EMUL_LITTLE_ENDIAN; } if (byte_order == EMUL_LITTLE_ENDIAN) for (i=0; i>= 8; } else for (i=0; i>= 8; } } /* * zeroed_alloc(): * * Allocates a block of memory using mmap(), and if that fails, try * malloc() + memset(). The returned memory block contains only zeroes. */ void *zeroed_alloc(size_t s) { void *p = mmap(NULL, s, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (p == NULL) { #if 1 fprintf(stderr, "zeroed_alloc(): mmap() failed. This should" " not usually happen. If you can reproduce this, then" " please contact me with details about your run-time" " environment.\n"); exit(1); #else CHECK_ALLOCATION(p = malloc(s)); memset(p, 0, s); #endif } return p; } /* * memory_new(): * * This function creates a new memory object. An emulated machine needs one * of these. */ struct memory *memory_new(uint64_t physical_max, int arch) { struct memory *mem; int bits_per_pagetable = BITS_PER_PAGETABLE; int bits_per_memblock = BITS_PER_MEMBLOCK; int entries_per_pagetable = 1 << BITS_PER_PAGETABLE; int max_bits = MAX_BITS; size_t s; CHECK_ALLOCATION(mem = (struct memory *) malloc(sizeof(struct memory))); memset(mem, 0, sizeof(struct memory)); /* Check bits_per_pagetable and bits_per_memblock for sanity: */ if (bits_per_pagetable + bits_per_memblock != max_bits) { fprintf(stderr, "memory_new(): bits_per_pagetable and " "bits_per_memblock mismatch\n"); exit(1); } mem->physical_max = physical_max; mem->dev_dyntrans_alignment = 4095; s = entries_per_pagetable * sizeof(void *); mem->pagetable = (unsigned char *) mmap(NULL, s, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (mem->pagetable == NULL) { CHECK_ALLOCATION(mem->pagetable = malloc(s)); memset(mem->pagetable, 0, s); } mem->mmap_dev_minaddr = 0xffffffffffffffffULL; mem->mmap_dev_maxaddr = 0; return mem; } /* * memory_points_to_string(): * * Returns 1 if there's something string-like in emulated memory at address * addr, otherwise 0. */ int memory_points_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr, int min_string_length) { int cur_length = 0; unsigned char c; for (;;) { c = '\0'; cpu->memory_rw(cpu, mem, addr+cur_length, &c, sizeof(c), MEM_READ, CACHE_NONE | NO_EXCEPTIONS); if (c=='\n' || c=='\t' || c=='\r' || (c>=' ' && c<127)) { cur_length ++; if (cur_length >= min_string_length) return 1; } else { if (cur_length >= min_string_length) return 1; else return 0; } } } /* * memory_conv_to_string(): * * Convert emulated memory contents to a string, placing it in a buffer * provided by the caller. */ char *memory_conv_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr, char *buf, int bufsize) { int len = 0; int output_index = 0; unsigned char c, p='\0'; while (output_index < bufsize-1) { c = '\0'; cpu->memory_rw(cpu, mem, addr+len, &c, sizeof(c), MEM_READ, CACHE_NONE | NO_EXCEPTIONS); buf[output_index] = c; if (c>=' ' && c<127) { len ++; output_index ++; } else if (c=='\n' || c=='\r' || c=='\t') { len ++; buf[output_index] = '\\'; output_index ++; switch (c) { case '\n': p = 'n'; break; case '\r': p = 'r'; break; case '\t': p = 't'; break; } if (output_index < bufsize-1) { buf[output_index] = p; output_index ++; } } else { buf[output_index] = '\0'; return buf; } } buf[bufsize-1] = '\0'; return buf; } /* * memory_device_dyntrans_access(): * * Get the lowest and highest dyntrans access since last time. */ void memory_device_dyntrans_access(struct cpu *cpu, struct memory *mem, void *extra, uint64_t *low, uint64_t *high) { size_t s; int i, need_inval = 0; /* TODO: This is O(n), so it might be good to rewrite it some day. For now, it will be enough, as long as this function is not called too often. */ for (i=0; in_mmapped_devices; i++) { if (mem->devices[i].extra == extra && mem->devices[i].flags & DM_DYNTRANS_WRITE_OK && mem->devices[i].dyntrans_data != NULL) { if (mem->devices[i].dyntrans_write_low != (uint64_t) -1) need_inval = 1; if (low != NULL) *low = mem->devices[i].dyntrans_write_low; mem->devices[i].dyntrans_write_low = (uint64_t) -1; if (high != NULL) *high = mem->devices[i].dyntrans_write_high; mem->devices[i].dyntrans_write_high = 0; if (!need_inval) return; /* Invalidate any pages of this device that might be in the dyntrans load/store cache, by marking the pages read-only. */ if (cpu->invalidate_translation_caches != NULL) { for (s = *low; s <= *high; s += cpu->machine->arch_pagesize) cpu->invalidate_translation_caches (cpu, mem->devices[i].baseaddr + s, JUST_MARK_AS_NON_WRITABLE | INVALIDATE_PADDR); } return; } } } /* * memory_device_update_data(): * * Update a device' dyntrans data pointer. * * SUPER-IMPORTANT NOTE: Anyone who changes a dyntrans data pointer while * things are running also needs to invalidate all CPUs' address translation * caches! Otherwise, these may contain old pointers to the old data. */ void memory_device_update_data(struct memory *mem, void *extra, unsigned char *data) { int i; for (i=0; in_mmapped_devices; i++) { if (mem->devices[i].extra != extra) continue; mem->devices[i].dyntrans_data = data; mem->devices[i].dyntrans_write_low = (uint64_t)-1; mem->devices[i].dyntrans_write_high = 0; } } /* * memory_device_register(): * * Register a memory mapped device. */ void memory_device_register(struct memory *mem, const char *device_name, uint64_t baseaddr, uint64_t len, int (*f)(struct cpu *,struct memory *,uint64_t,unsigned char *, size_t,int,void *), void *extra, int flags, unsigned char *dyntrans_data) { int i, newi = 0; /* * Figure out at which index to insert this device, and simultaneously * check for collisions: */ newi = -1; for (i=0; in_mmapped_devices; i++) { if (i == 0 && baseaddr + len <= mem->devices[i].baseaddr) newi = i; if (i > 0 && baseaddr + len <= mem->devices[i].baseaddr && baseaddr >= mem->devices[i-1].endaddr) newi = i; if (i == mem->n_mmapped_devices - 1 && baseaddr >= mem->devices[i].endaddr) newi = i + 1; /* If this is not colliding with device i, then continue: */ if (baseaddr + len <= mem->devices[i].baseaddr) continue; if (baseaddr >= mem->devices[i].endaddr) continue; fatal("\nERROR! \"%s\" collides with device %i (\"%s\")!\n", device_name, i, mem->devices[i].name); exit(1); } if (mem->n_mmapped_devices == 0) newi = 0; if (newi == -1) { fatal("INTERNAL ERROR\n"); exit(1); } if (verbose >= 2) { /* (40 bits of physical address is displayed) */ debug("device at 0x%010" PRIx64": %s", (uint64_t) baseaddr, device_name); if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK) && (baseaddr & mem->dev_dyntrans_alignment) != 0) { fatal("\nWARNING: Device dyntrans access, but unaligned" " baseaddr 0x%" PRIx64".\n", (uint64_t) baseaddr); } if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) { debug(" (dyntrans %s)", (flags & DM_DYNTRANS_WRITE_OK)? "R/W" : "R"); } debug("\n"); } for (i=0; in_mmapped_devices; i++) { if (dyntrans_data == mem->devices[i].dyntrans_data && mem->devices[i].flags&(DM_DYNTRANS_OK|DM_DYNTRANS_WRITE_OK) && flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) { fatal("ERROR: the data pointer used for dyntrans " "accesses must only be used once!\n"); fatal("(%p cannot be used by '%s'; already in use by '" "%s')\n", dyntrans_data, device_name, mem->devices[i].name); exit(1); } } mem->n_mmapped_devices++; CHECK_ALLOCATION(mem->devices = (struct memory_device *) realloc(mem->devices, sizeof(struct memory_device) * mem->n_mmapped_devices)); /* Make space for the new entry: */ if (newi + 1 != mem->n_mmapped_devices) memmove(&mem->devices[newi+1], &mem->devices[newi], sizeof(struct memory_device) * (mem->n_mmapped_devices - newi - 1)); CHECK_ALLOCATION(mem->devices[newi].name = strdup(device_name)); mem->devices[newi].baseaddr = baseaddr; mem->devices[newi].endaddr = baseaddr + len; mem->devices[newi].length = len; mem->devices[newi].flags = flags; mem->devices[newi].dyntrans_data = dyntrans_data; if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK) && !(flags & DM_EMULATED_RAM) && dyntrans_data == NULL) { fatal("\nERROR: Device dyntrans access, but dyntrans_data" " = NULL!\n"); exit(1); } if ((size_t)dyntrans_data & (sizeof(void *) - 1)) { fprintf(stderr, "memory_device_register():" " dyntrans_data not aligned correctly (%p)\n", dyntrans_data); abort(); } mem->devices[newi].dyntrans_write_low = (uint64_t)-1; mem->devices[newi].dyntrans_write_high = 0; mem->devices[newi].f = f; mem->devices[newi].extra = extra; if (baseaddr < mem->mmap_dev_minaddr) mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment; if (baseaddr + len > mem->mmap_dev_maxaddr) mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) | mem->dev_dyntrans_alignment) + 1; if (newi < mem->last_accessed_device) mem->last_accessed_device ++; } /* * memory_device_remove(): * * Unregister a memory mapped device from a memory object. */ void memory_device_remove(struct memory *mem, int i) { if (i < 0 || i >= mem->n_mmapped_devices) { fatal("memory_device_remove(): invalid device number %i\n", i); exit(1); } mem->n_mmapped_devices --; if (i == mem->n_mmapped_devices) return; memmove(&mem->devices[i], &mem->devices[i+1], sizeof(struct memory_device) * (mem->n_mmapped_devices - i)); if (i <= mem->last_accessed_device) mem->last_accessed_device --; if (mem->last_accessed_device < 0) mem->last_accessed_device = 0; } /* * memory_paddr_to_hostaddr(): * * Translate a physical address into a host address. The usual way to call * this function is to make sure that paddr is page aligned, which will result * in the host _page_ corresponding to that address. * * Return value is a pointer to the address in the host, or NULL on failure. * On reads, a NULL return value should be interpreted as reading all zeroes. */ unsigned char *memory_paddr_to_hostaddr(struct memory *mem, uint64_t paddr, int writeflag) { void **table; int entry; const int mask = (1 << BITS_PER_PAGETABLE) - 1; const int shrcount = MAX_BITS - BITS_PER_PAGETABLE; unsigned char *hostptr; table = (void **) mem->pagetable; entry = (paddr >> shrcount) & mask; /* printf("memory_paddr_to_hostaddr(): p=%16" PRIx64 " w=%i => entry=0x%x\n", (uint64_t) paddr, writeflag, entry); */ if (table[entry] == NULL) { size_t alloclen; /* * Special case: reading from a nonexistant memblock * returns all zeroes, and doesn't allocate anything. * (If any intermediate pagetable is nonexistant, then * the same thing happens): */ if (writeflag == MEM_READ) return NULL; /* Allocate a memblock: */ alloclen = 1 << BITS_PER_MEMBLOCK; /* printf(" allocating for entry %i, len=%i\n", entry, alloclen); */ /* Anonymous mmap() should return zero-filled memory, try malloc + memset if mmap failed. */ table[entry] = (void *) mmap(NULL, alloclen, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (table[entry] == NULL) { CHECK_ALLOCATION(table[entry] = malloc(alloclen)); memset(table[entry], 0, alloclen); } } hostptr = (unsigned char *) table[entry]; if (hostptr != NULL) hostptr += (paddr & ((1 << BITS_PER_MEMBLOCK) - 1)); return hostptr; } #define UPDATE_CHECKSUM(value) { \ internal_state -= 0x118c7771c0c0a77fULL; \ internal_state = ((internal_state + (value)) << 7) ^ \ (checksum >> 11) ^ ((checksum - (value)) << 3) ^ \ (internal_state - checksum) ^ ((value) - internal_state); \ checksum ^= internal_state; \ } /* * memory_checksum(): * * Calculate a 64-bit checksum of everything in a struct memory. This is * useful for tracking down bugs; an old (presumably working) version of * the emulator can be compared to a newer (buggy) version. */ uint64_t memory_checksum(struct memory *mem) { uint64_t internal_state = 0x80624185376feff2ULL; uint64_t checksum = 0xcb9a87d5c010072cULL; const size_t n_entries = (1 << BITS_PER_PAGETABLE) - 1; const size_t len = (1 << BITS_PER_MEMBLOCK) / sizeof(uint64_t); size_t entry, i; for (entry=0; entry<=n_entries; entry++) { uint64_t **table = (uint64_t **) mem->pagetable; uint64_t *memblock = table[entry]; if (memblock == NULL) { UPDATE_CHECKSUM(0x1198ab7c8174a76fULL); continue; } for (i=0; ipc; char *symbol; /* * This allows guest OS kernels to probe memory a few KBs past the * end of memory, without giving too many warnings. */ if (paddr < mem->physical_max + 0x40000) return; if (!cpu->machine->halt_on_nonexistant_memaccess && quiet_mode) return; fatal("[ memory_rw(): %s ", writeflag? "write":"read"); if (writeflag) { unsigned int i; debug("data={", writeflag); if (len > 16) { int start2 = len-16; for (i=0; i<16; i++) debug("%s%02x", i?",":"", data[i]); debug(" .. "); if (start2 < 16) start2 = 16; for (i=start2; i= physical_max; pc=", paddr); if (cpu->is_32bit) fatal("0x%08" PRIx32, (uint32_t) old_pc); else fatal("0x%016" PRIx64, (uint64_t) old_pc); symbol = get_symbol_name(&cpu->machine->symbol_context, old_pc, &offset); fatal(" <%s> ]\n", symbol? symbol : " no symbol "); if (cpu->machine->halt_on_nonexistant_memaccess) { /* TODO: Halt in a nicer way. Not possible with the current dyntrans system... */ exit(1); } } /* * dump_mem_string(): * * Dump the contents of emulated RAM as readable text. Bytes that aren't * readable are dumped in [xx] notation, where xx is in hexadecimal. * Dumping ends after DUMP_MEM_STRING_MAX bytes, or when a terminating * zero byte is found. */ #define DUMP_MEM_STRING_MAX 45 void dump_mem_string(struct cpu *cpu, uint64_t addr) { int i; for (i=0; imemory_rw(cpu, cpu->mem, addr + i, &ch, sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); if (ch == '\0') return; if (ch >= ' ' && ch < 126) debug("%c", ch); else debug("[%02x]", ch); } } /* * store_byte(): * * Stores a byte in emulated ram. (Helper function.) */ void store_byte(struct cpu *cpu, uint64_t addr, uint8_t data) { if ((addr >> 32) == 0) addr = (int64_t)(int32_t)addr; cpu->memory_rw(cpu, cpu->mem, addr, &data, sizeof(data), MEM_WRITE, CACHE_DATA); } /* * store_string(): * * Stores chars into emulated RAM until a zero byte (string terminating * character) is found. The zero byte is also copied. * (strcpy()-like helper function, host-RAM-to-emulated-RAM.) */ void store_string(struct cpu *cpu, uint64_t addr, const char *s) { do { store_byte(cpu, addr++, *s); } while (*s++); } /* * add_environment_string(): * * Like store_string(), but advances the pointer afterwards. The most * obvious use is to place a number of strings (such as environment variable * strings) after one-another in emulated memory. */ void add_environment_string(struct cpu *cpu, const char *s, uint64_t *addr) { store_string(cpu, *addr, s); (*addr) += strlen(s) + 1; } /* * add_environment_string_dual(): * * Add "dual" environment strings, one for the variable name and one for the * value, and update pointers afterwards. */ void add_environment_string_dual(struct cpu *cpu, uint64_t *ptrp, uint64_t *addrp, const char *s1, const char *s2) { uint64_t ptr = *ptrp, addr = *addrp; store_32bit_word(cpu, ptr, addr); ptr += sizeof(uint32_t); if (addr != 0) { store_string(cpu, addr, s1); addr += strlen(s1) + 1; } store_32bit_word(cpu, ptr, addr); ptr += sizeof(uint32_t); if (addr != 0) { store_string(cpu, addr, s2); addr += strlen(s2) + 1; } *ptrp = ptr; *addrp = addr; } /* * store_64bit_word(): * * Stores a 64-bit word in emulated RAM. Byte order is taken into account. * Helper function. */ int store_64bit_word(struct cpu *cpu, uint64_t addr, uint64_t data64) { unsigned char data[8]; if ((addr >> 32) == 0) addr = (int64_t)(int32_t)addr; data[0] = (data64 >> 56) & 255; data[1] = (data64 >> 48) & 255; data[2] = (data64 >> 40) & 255; data[3] = (data64 >> 32) & 255; data[4] = (data64 >> 24) & 255; data[5] = (data64 >> 16) & 255; data[6] = (data64 >> 8) & 255; data[7] = (data64) & 255; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { int tmp = data[0]; data[0] = data[7]; data[7] = tmp; tmp = data[1]; data[1] = data[6]; data[6] = tmp; tmp = data[2]; data[2] = data[5]; data[5] = tmp; tmp = data[3]; data[3] = data[4]; data[4] = tmp; } return cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_WRITE, CACHE_DATA); } /* * store_32bit_word(): * * Stores a 32-bit word in emulated RAM. Byte order is taken into account. * (This function takes a 64-bit word as argument, to suppress some * warnings, but only the lowest 32 bits are used.) */ int store_32bit_word(struct cpu *cpu, uint64_t addr, uint64_t data32) { unsigned char data[4]; data[0] = (data32 >> 24) & 255; data[1] = (data32 >> 16) & 255; data[2] = (data32 >> 8) & 255; data[3] = (data32) & 255; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { int tmp = data[0]; data[0] = data[3]; data[3] = tmp; tmp = data[1]; data[1] = data[2]; data[2] = tmp; } return cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_WRITE, CACHE_DATA); } /* * store_16bit_word(): * * Stores a 16-bit word in emulated RAM. Byte order is taken into account. * (This function takes a 64-bit word as argument, to suppress some * warnings, but only the lowest 16 bits are used.) */ int store_16bit_word(struct cpu *cpu, uint64_t addr, uint64_t data16) { unsigned char data[2]; data[0] = (data16 >> 8) & 255; data[1] = (data16) & 255; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { int tmp = data[0]; data[0] = data[1]; data[1] = tmp; } return cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_WRITE, CACHE_DATA); } /* * store_buf(): * * memcpy()-like helper function, from host RAM to emulated RAM. */ void store_buf(struct cpu *cpu, uint64_t addr, const char *s, size_t len) { size_t psize = 1024; /* 1024 256 64 16 4 1 */ while (len != 0) { if ((addr & (psize-1)) == 0) { while (len >= psize) { cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *)s, psize, MEM_WRITE, CACHE_DATA); addr += psize; s += psize; len -= psize; } } psize >>= 2; } while (len-- != 0) store_byte(cpu, addr++, *s++); } /* * store_pointer_and_advance(): * * Stores a 32-bit or 64-bit pointer in emulated RAM, and advances the * target address. (Useful for e.g. ARCBIOS environment initialization.) */ void store_pointer_and_advance(struct cpu *cpu, uint64_t *addrp, uint64_t data, int flag64) { uint64_t addr = *addrp; if (flag64) { store_64bit_word(cpu, addr, data); addr += 8; } else { store_32bit_word(cpu, addr, data); addr += 4; } *addrp = addr; } /* * load_64bit_word(): * * Helper function. Emulated byte order is taken into account. */ uint64_t load_64bit_word(struct cpu *cpu, uint64_t addr) { unsigned char data[8]; cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_READ, CACHE_DATA); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { int tmp = data[0]; data[0] = data[7]; data[7] = tmp; tmp = data[1]; data[1] = data[6]; data[6] = tmp; tmp = data[2]; data[2] = data[5]; data[5] = tmp; tmp = data[3]; data[3] = data[4]; data[4] = tmp; } return ((uint64_t)data[0] << 56) + ((uint64_t)data[1] << 48) + ((uint64_t)data[2] << 40) + ((uint64_t)data[3] << 32) + ((uint64_t)data[4] << 24) + ((uint64_t)data[5] << 16) + ((uint64_t)data[6] << 8) + (uint64_t)data[7]; } /* * load_32bit_word(): * * Helper function. Emulated byte order is taken into account. */ uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr) { unsigned char data[4]; cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_READ, CACHE_DATA); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { int tmp = data[0]; data[0] = data[3]; data[3] = tmp; tmp = data[1]; data[1] = data[2]; data[2] = tmp; } return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]; } /* * load_16bit_word(): * * Helper function. Emulated byte order is taken into account. */ uint16_t load_16bit_word(struct cpu *cpu, uint64_t addr) { unsigned char data[2]; cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), MEM_READ, CACHE_DATA); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { int tmp = data[0]; data[0] = data[1]; data[1] = tmp; } return (data[0] << 8) + data[1]; } /* * store_64bit_word_in_host(): * * Stores a 64-bit word in the _host's_ RAM. Emulated byte order is taken * into account. This is useful when building structs in the host's RAM * which will later be copied into emulated RAM. */ void store_64bit_word_in_host(struct cpu *cpu, unsigned char *data, uint64_t data64) { data[0] = (data64 >> 56) & 255; data[1] = (data64 >> 48) & 255; data[2] = (data64 >> 40) & 255; data[3] = (data64 >> 32) & 255; data[4] = (data64 >> 24) & 255; data[5] = (data64 >> 16) & 255; data[6] = (data64 >> 8) & 255; data[7] = (data64) & 255; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { int tmp = data[0]; data[0] = data[7]; data[7] = tmp; tmp = data[1]; data[1] = data[6]; data[6] = tmp; tmp = data[2]; data[2] = data[5]; data[5] = tmp; tmp = data[3]; data[3] = data[4]; data[4] = tmp; } } /* * store_32bit_word_in_host(): * * See comment for store_64bit_word_in_host(). * * (Note: The data32 parameter is a uint64_t. This is done to suppress * some warnings.) */ void store_32bit_word_in_host(struct cpu *cpu, unsigned char *data, uint64_t data32) { data[0] = (data32 >> 24) & 255; data[1] = (data32 >> 16) & 255; data[2] = (data32 >> 8) & 255; data[3] = (data32) & 255; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { int tmp = data[0]; data[0] = data[3]; data[3] = tmp; tmp = data[1]; data[1] = data[2]; data[2] = tmp; } } /* * store_16bit_word_in_host(): * * See comment for store_64bit_word_in_host(). */ void store_16bit_word_in_host(struct cpu *cpu, unsigned char *data, uint16_t data16) { data[0] = (data16 >> 8) & 255; data[1] = (data16) & 255; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { int tmp = data[0]; data[0] = data[1]; data[1] = tmp; } } gxemul-0.6.1/src/old_main/settings.cc000644 001750 001750 00000034000 13402411502 017742 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * A generic settings object. (This module should be 100% indepedent of GXemul * and hence easily reusable.) It is basically a tree structure of nodes, * where each node has a name and a few properties. The main property is * a pointer, which can either point to other settings ("sub-settings"), * or to a variable in memory. * * Appart from the pointer, the other properties are a definition of the * type being pointed to (int, int32_t, int64_t, char*, etc), how it should be * presented (e.g. it may be an int value in memory, but it should be * presented as a boolean "true/false" value), and a flag which tells us * whether the setting is directly writable or not. * * If UNSTABLE_DEVEL is defined, then warnings are printed when * settings_destroy() is called if individual settings have not yet been * deleted. (This is to help making sure that code which uses the settings * subsystem correctly un-initializes stuff.) */ #include #include #include /* Including misc.h should ONLY be necessary to work around the fact that many systems don't have PRIx64 etc defined. */ #include "misc.h" #include "settings.h" struct settings { struct settings *parent; char *name_in_parent; int n_settings; /* * Each setting has a name, a writable flag, a storage type, a * presentation format, and a pointer. * * For subsettings, the pointer points to the subsettings object; * for other settings, the pointer points to a variable. * * These pointers point to simple linear arrays, containing n_settings * entries each. */ char **name; int *writable; int *storage_type; int *presentation_format; void **ptr; }; /* * settings_new(): * * Create a new settings object. Return value is a pointer to the newly * created object. The function does not return on failure. */ struct settings *settings_new(void) { struct settings *settings; CHECK_ALLOCATION(settings = (struct settings *) malloc(sizeof(struct settings))); memset(settings, 0, sizeof(struct settings)); return settings; } /* * settings_destroy(): * * Frees all resources occupied by a settings object. Also, if this settings * object has a parent, then remove it from the parent. */ void settings_destroy(struct settings *settings) { int i; if (settings == NULL) { fprintf(stderr, "settings_destroy(): internal error, " "settings = NULL!\n"); exit(1); } #ifdef UNSTABLE_DEVEL if (settings->n_settings > 0) printf("settings_destroy(): there are remaining settings!\n"); #endif if (settings->name != NULL) { for (i=0; in_settings; i++) { if (settings->name[i] != NULL) { #ifdef UNSTABLE_DEVEL printf("settings_destroy(): setting '%s'" " was not properly deleted before " "exiting!\n", settings->name[i]); #endif free(settings->name[i]); } } free(settings->name); } else if (settings->n_settings != 0) { fprintf(stderr, "settings_destroy(): internal error, " "settings->name = NULL, but there were settings?" " (n_settings = %i)\n", settings->n_settings); exit(1); } if (settings->writable != NULL) free(settings->writable); if (settings->storage_type != NULL) free(settings->storage_type); if (settings->presentation_format != NULL) free(settings->presentation_format); if (settings->ptr != NULL) free(settings->ptr); if (settings->parent != NULL) { settings_remove(settings->parent, settings->name_in_parent); free(settings->name_in_parent); } free(settings); } /* * settings_read(): * * Used internally by settings_access() and settings_debugdump(). */ static int settings_read(struct settings *settings, int i, uint64_t *valuep) { *valuep = 0; switch (settings->storage_type[i]) { case SETTINGS_TYPE_INT: *valuep = *((int *) settings->ptr[i]); break; case SETTINGS_TYPE_INT8: *valuep = *((int8_t *) settings->ptr[i]); break; case SETTINGS_TYPE_INT16: *valuep = *((int16_t *) settings->ptr[i]); break; case SETTINGS_TYPE_INT32: *valuep = *((int32_t *) settings->ptr[i]); break; case SETTINGS_TYPE_INT64: *valuep = *((int64_t *) settings->ptr[i]); break; case SETTINGS_TYPE_UINT: *valuep = *((uint *) settings->ptr[i]); break; case SETTINGS_TYPE_UINT8: *valuep = *((uint8_t *) settings->ptr[i]); break; case SETTINGS_TYPE_UINT16: *valuep = *((uint16_t *) settings->ptr[i]); break; case SETTINGS_TYPE_UINT32: *valuep = *((uint32_t *) settings->ptr[i]); break; case SETTINGS_TYPE_UINT64: *valuep = *((uint64_t *) settings->ptr[i]); break; case SETTINGS_TYPE_STRING: /* Note: Strings cannot be read like this. */ break; default:printf("settings_read(): FATAL ERROR! Unknown storage type" ": %i\n", settings->storage_type[i]); exit(1); } return SETTINGS_OK; } /* * settings_write(): * * Used internally by settings_access(). */ static int settings_write(struct settings *settings, int i, uint64_t *valuep) { if (!settings->writable[i]) return SETTINGS_READONLY; switch (settings->storage_type[i]) { case SETTINGS_TYPE_INT: case SETTINGS_TYPE_UINT: *((int *) settings->ptr[i]) = *valuep; break; case SETTINGS_TYPE_INT8: case SETTINGS_TYPE_UINT8: *((int8_t *) settings->ptr[i]) = *valuep; break; case SETTINGS_TYPE_INT16: case SETTINGS_TYPE_UINT16: *((int16_t *) settings->ptr[i]) = *valuep; break; case SETTINGS_TYPE_INT32: case SETTINGS_TYPE_UINT32: *((int32_t *) settings->ptr[i]) = *valuep; break; case SETTINGS_TYPE_INT64: case SETTINGS_TYPE_UINT64: *((int64_t *) settings->ptr[i]) = *valuep; break; case SETTINGS_TYPE_STRING: /* Note: Strings cannot be read like this. */ printf("settings_write(): ERROR! Strings cannot be " "written like this.\n"); break; default:printf("settings_read(): FATAL ERROR! Unknown storage type" ": %i\n", settings->storage_type[i]); exit(1); } return SETTINGS_OK; } /* * settings_debugdump(): * * Dump settings in a settings object to stdout. * If recurse is non-zero, all subsetting objects are also dumped. */ void settings_debugdump(struct settings *settings, const char *prefix, int recurse) { size_t name_buflen = strlen(prefix) + 100; char *name; int i; uint64_t value = 0; CHECK_ALLOCATION(name = (char *) malloc(name_buflen)); for (i=0; in_settings; i++) { snprintf(name, name_buflen, "%s.%s", prefix, settings->name[i]); if (settings->storage_type[i] == SETTINGS_TYPE_SUBSETTINGS) { /* Subsettings: */ if (recurse) settings_debugdump((struct settings *)settings->ptr[i], name, 1); } else { /* Normal value: */ printf("%s = ", name); settings_read(settings, i, &value); switch (settings->presentation_format[i]) { case SETTINGS_FORMAT_DECIMAL: printf("%" PRIi64, value); break; case SETTINGS_FORMAT_HEX8: printf("0x%02" PRIx8, (int8_t) value); break; case SETTINGS_FORMAT_HEX16: printf("0x%04" PRIx16, (int16_t) value); break; case SETTINGS_FORMAT_HEX32: printf("0x%08" PRIx32, (int32_t) value); break; case SETTINGS_FORMAT_HEX64: printf("0x%016" PRIx64, (int64_t) value); break; case SETTINGS_FORMAT_BOOL: printf(value? "true" : "false"); break; case SETTINGS_FORMAT_YESNO: printf(value? "yes" : "no"); break; case SETTINGS_FORMAT_STRING: printf("\"%s\"", *((char **)settings->ptr[i])); break; default:printf("FATAL ERROR! Unknown presentation " "format: %i\n", settings->presentation_format[i]); exit(1); } if (!settings->writable[i]) printf(" (R/O)"); printf("\n"); } } free(name); } /* * settings_add(): * * Add a setting to a settings object. */ void settings_add(struct settings *settings, const char *name, int writable, int type, int format, void *ptr) { int i; for (i=0; in_settings; i++) { if (strcmp(settings->name[i], name) == 0) break; } if (i < settings->n_settings) { fprintf(stderr, "settings_add(): name '%s' is already" " in use\n", name); exit(1); } settings->n_settings ++; CHECK_ALLOCATION(settings->name = (char **) realloc(settings->name, settings->n_settings * sizeof(char *))); CHECK_ALLOCATION(settings->writable = (int *) realloc(settings->writable, settings->n_settings * sizeof(int))); CHECK_ALLOCATION(settings->storage_type = (int *) realloc( settings->storage_type, settings->n_settings * sizeof(int))); CHECK_ALLOCATION(settings->presentation_format = (int *) realloc(settings-> presentation_format, settings->n_settings * sizeof(int))); CHECK_ALLOCATION(settings->ptr = (void **) realloc(settings->ptr, settings->n_settings * sizeof(void *))); CHECK_ALLOCATION(settings->name[settings->n_settings - 1] = strdup(name)); settings->writable[settings->n_settings - 1] = writable; settings->storage_type[settings->n_settings - 1] = type; settings->presentation_format[settings->n_settings - 1] = format; settings->ptr[settings->n_settings - 1] = ptr; if (type == SETTINGS_TYPE_SUBSETTINGS) { ((struct settings *)ptr)->parent = settings; CHECK_ALLOCATION( ((struct settings *)ptr)->name_in_parent = strdup(name) ); } } /* * settings_remove(): * * Remove a setting from a settings object. */ void settings_remove(struct settings *settings, const char *name) { int i, m; for (i=0; in_settings; i++) { if (strcmp(settings->name[i], name) == 0) break; } if (i >= settings->n_settings) { #ifdef UNSTABLE_DEVEL fprintf(stderr, "settings_remove(): attempting to remove" " non-existant setting '%s'\n", name); #endif return; } /* Check subsettings specifically: */ if (settings->storage_type[i] == SETTINGS_TYPE_SUBSETTINGS && settings->ptr[i] != NULL) { struct settings *subsettings = (struct settings *) settings->ptr[i]; if (subsettings->n_settings != 0) { fprintf(stderr, "settings_remove(): attempting to " "remove non-emtpy setting '%s'\n", name); fprintf(stderr, "Remaining settings are:\n"); for (i=0; in_settings; i++) fprintf(stderr, "\t%s\n", subsettings->name[i]); exit(1); } } settings->n_settings --; free(settings->name[i]); m = settings->n_settings - i; if (m == 0) return; memmove(&settings->name[i], &settings->name[i+1], m * sizeof(settings->name[0])); memmove(&settings->writable[i], &settings->writable[i+1], m * sizeof(settings->writable[0])); memmove(&settings->storage_type[i], &settings->storage_type[i+1], m * sizeof(settings->storage_type[0])); memmove(&settings->presentation_format[i], &settings->presentation_format[i+1], m * sizeof(settings->presentation_format[0])); memmove(&settings->ptr[i], &settings->ptr[i+1], m * sizeof(settings->ptr[0])); } /* * settings_remove_all(): * * Remove all (level-1) settings from a settings object. By level-1, I mean * all settings that do not contain subsettings. */ void settings_remove_all(struct settings *settings) { while (settings->n_settings > 0) settings_remove(settings, settings->name[0]); } /* * settings_access(): * * Read or write a setting. fullname may be something like "settings.x.y". * When writing a value, valuebuf should point to a uint64_t containing the * new value (note: always a uint64_t). When reading a value, valuebuf should * point to a uint64_t where the value will be stored. * * The return value is one of the following: * * SETTINGS_OK * The value was read or written. * * SETTINGS_NAME_NOT_FOUND * The name was not found in the settings object. * * SETTINGS_READONLY * The name was found, but it was marked as read-only, and * an attempt was made to write to it. */ int settings_access(struct settings *settings, const char *fullname, int writeflag, uint64_t *valuep) { int i; /* printf("settings_access(fullname='%s')\n", fullname); */ if (strncmp(fullname, GLOBAL_SETTINGS_NAME".", strlen(GLOBAL_SETTINGS_NAME) + 1) == 0) fullname += strlen(GLOBAL_SETTINGS_NAME) + 1; for (i=0; in_settings; i++) { size_t settings_name_len = strlen(settings->name[i]); if (strncmp(fullname, settings->name[i], settings_name_len) != 0) continue; /* Found the correct setting? */ if (fullname[settings_name_len] == '\0') { if (writeflag) return settings_write(settings, i, valuep); else return settings_read(settings, i, valuep); } /* Found a setting which has sub-settings? */ if (fullname[settings_name_len] == '.') { /* Recursive search: */ return settings_access( (struct settings *)settings->ptr[i], fullname + settings_name_len + 1, writeflag, valuep); } } return SETTINGS_NAME_NOT_FOUND; } gxemul-0.6.1/src/old_main/emul_parse.cc000644 001750 001750 00000047271 13402411502 020254 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Set up an emulation by parsing a config file. * * TODO: REWRITE THIS FROM SCRATCH! :-) */ #include #include #include #include "diskimage.h" #include "emul.h" #include "machine.h" #include "misc.h" #include "net.h" #define is_word_char(ch) ( \ (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || \ ch == '_' || ch == '$' || (ch >= '0' && ch <= '9') ) #define MAX_WORD_LEN 200 #define EXPECT_WORD 1 #define EXPECT_LEFT_PARENTHESIS 2 #define EXPECT_RIGHT_PARENTHESIS 4 static int parenthesis_level = 0; /* * read_one_word(): * * Reads the file f until it has read a complete word. Whitespace is ignored, * and also any exclamation mark ('!') and anything following an exclamation * mark on a line. * * Used internally by emul_parse_config(). */ static void read_one_word(FILE *f, char *buf, int buflen, int *line, int expect) { int ch; int done = 0; int curlen = 0; int in_word = 0; while (!done) { if (curlen >= buflen - 1) break; ch = fgetc(f); if (ch == EOF) break; if (in_word) { if (is_word_char(ch)) { buf[curlen++] = ch; if (curlen == buflen - 1) done = 1; continue; } else { if (ungetc(ch, f) == EOF) { fatal("ungetc() failed?\n"); exit(1); } break; } } if (ch == '\n') { (*line) ++; continue; } if (ch == '\r') continue; if (ch == '!') { /* Skip until newline: */ while (ch != '\n' && ch != EOF) ch = fgetc(f); if (ch == '\n') (*line) ++; continue; } if (ch == '{') { int depth = 1; /* Skip until '}': */ while (depth > 0) { ch = fgetc(f); if (ch == '\n') (*line) ++; if (ch == '{') depth ++; if (ch == '}') depth --; if (ch == EOF) { fatal("line %i: unexpected EOF inside" " a nested comment\n", *line); exit(1); } } continue; } /* Whitespace? */ if (ch <= ' ') continue; if (ch == '"' || ch == '\'') { /* This is a quoted word. */ int start_ch = ch; if (expect & EXPECT_LEFT_PARENTHESIS) { fatal("unexpected character '%c', line %i\n", ch, *line); exit(1); } while (curlen < buflen - 1) { ch = fgetc(f); if (ch == '\n') { fatal("line %i: newline inside" " quotes?\n", *line); exit(1); } if (ch == EOF) { fatal("line %i: EOF inside a quoted" " string?\n", *line); exit(1); } if (ch == start_ch) break; buf[curlen++] = ch; } break; } if ((expect & EXPECT_WORD) && is_word_char(ch)) { buf[curlen++] = ch; in_word = 1; if (curlen == buflen - 1) done = 1; } else { if ((expect & EXPECT_LEFT_PARENTHESIS) && ch == '(') { parenthesis_level ++; buf[curlen++] = ch; break; } if ((expect & EXPECT_RIGHT_PARENTHESIS) && ch == ')') { parenthesis_level --; buf[curlen++] = ch; break; } fatal("unexpected character '%c', line %i\n", ch, *line); exit(1); } } buf[curlen] = '\0'; } #define PARSESTATE_NONE 0 #define PARSESTATE_EMUL 1 #define PARSESTATE_NET 2 #define PARSESTATE_MACHINE 3 static char cur_net_ipv4net[50]; static char cur_net_ipv4len[50]; static char cur_net_local_port[10]; #define MAX_N_REMOTE 20 #define MAX_REMOTE_LEN 100 static char *cur_net_remote[MAX_N_REMOTE]; static int cur_net_n_remote; static char cur_machine_name[50]; static char cur_machine_cpu[50]; static char cur_machine_type[50]; static char cur_machine_subtype[50]; static char cur_machine_bootname[150]; static char cur_machine_bootarg[250]; static char cur_machine_slowsi[10]; static char cur_machine_prom_emulation[10]; static char cur_machine_use_x11[10]; static char cur_machine_x11_scaledown[10]; static char cur_machine_byte_order[20]; static char cur_machine_random_mem[10]; static char cur_machine_random_cpu[10]; static char cur_machine_force_netboot[10]; static char cur_machine_start_paused[10]; static char cur_machine_ncpus[10]; static char cur_machine_n_gfx_cards[10]; static char cur_machine_serial_nr[10]; static char cur_machine_emulated_hz[10]; static char cur_machine_memory[10]; #define MAX_N_LOAD 15 #define MAX_LOAD_LEN 2000 static char *cur_machine_load[MAX_N_LOAD]; static int cur_machine_n_load; #define MAX_N_DISK 10 #define MAX_DISK_LEN 2000 static char *cur_machine_disk[MAX_N_DISK]; static int cur_machine_n_disk; #define MAX_N_DEVICE 20 #define MAX_DEVICE_LEN 400 static char *cur_machine_device[MAX_N_DISK]; static int cur_machine_n_device; #define MAX_N_X11_DISP 5 #define MAX_X11_DISP_LEN 1000 static char *cur_machine_x11_disp[MAX_N_X11_DISP]; static int cur_machine_n_x11_disp; #define WORD(w,var) { \ if (strcmp(word, w) == 0) { \ read_one_word(f, word, maxbuflen, \ line, EXPECT_LEFT_PARENTHESIS); \ read_one_word(f, var, sizeof(var), \ line, EXPECT_WORD); \ read_one_word(f, word, maxbuflen, \ line, EXPECT_RIGHT_PARENTHESIS); \ return; \ } \ } static void parse__machine(struct emul *e, FILE *f, int *in_emul, int *line, int *parsestate, char *word, size_t maxbuflen); /* * parse_on_off(): * * Returns 1 for "on", "yes", "enable", or "1". * Returns 0 for "off", "no", "disable", or "0". * Prints a fatal warning and exit()s for other values. */ int parse_on_off(char *s) { if (strcasecmp(s, "on") == 0 || strcasecmp(s, "yes") == 0 || strcasecmp(s, "enable") == 0 || strcasecmp(s, "1") == 0) return 1; if (strcasecmp(s, "off") == 0 || strcasecmp(s, "no") == 0 || strcasecmp(s, "disable") == 0 || strcasecmp(s, "0") == 0) return 0; fprintf(stderr, "parse_on_off(): WARNING: unknown value '%s'\n", s); return 0; } /* * parse__emul(): * * name, net, machine */ static void parse__emul(struct emul *e, FILE *f, int *in_emul, int *line, int *parsestate, char *word, size_t maxbuflen) { if (word[0] == ')') { *parsestate = PARSESTATE_NONE; return; } if (strcmp(word, "name") == 0) { char tmp[200]; read_one_word(f, word, maxbuflen, line, EXPECT_LEFT_PARENTHESIS); read_one_word(f, tmp, sizeof(tmp), line, EXPECT_WORD); read_one_word(f, word, maxbuflen, line, EXPECT_RIGHT_PARENTHESIS); if (e->name != NULL) { free(e->name); e->name = NULL; } CHECK_ALLOCATION(e->name = strdup(tmp)); debug("name: \"%s\"\n", e->name); return; } if (strcmp(word, "net") == 0) { *parsestate = PARSESTATE_NET; read_one_word(f, word, maxbuflen, line, EXPECT_LEFT_PARENTHESIS); /* Default net: */ strlcpy(cur_net_ipv4net, NET_DEFAULT_IPV4_MASK, sizeof(cur_net_ipv4net)); snprintf(cur_net_ipv4len, sizeof(cur_net_ipv4len), "%i", NET_DEFAULT_IPV4_LEN); strlcpy(cur_net_local_port, "", sizeof(cur_net_local_port)); cur_net_n_remote = 0; return; } if (strcmp(word, "machine") == 0) { *parsestate = PARSESTATE_MACHINE; read_one_word(f, word, maxbuflen, line, EXPECT_LEFT_PARENTHESIS); /* A "zero state": */ cur_machine_name[0] = '\0'; cur_machine_cpu[0] = '\0'; cur_machine_type[0] = '\0'; cur_machine_subtype[0] = '\0'; cur_machine_bootname[0] = '\0'; cur_machine_bootarg[0] = '\0'; cur_machine_n_load = 0; cur_machine_n_disk = 0; cur_machine_n_device = 0; cur_machine_n_x11_disp = 0; cur_machine_slowsi[0] = '\0'; cur_machine_prom_emulation[0] = '\0'; cur_machine_use_x11[0] = '\0'; cur_machine_x11_scaledown[0] = '\0'; cur_machine_byte_order[0] = '\0'; cur_machine_random_mem[0] = '\0'; cur_machine_random_cpu[0] = '\0'; cur_machine_force_netboot[0] = '\0'; cur_machine_start_paused[0] = '\0'; cur_machine_ncpus[0] = '\0'; cur_machine_n_gfx_cards[0] = '\0'; cur_machine_serial_nr[0] = '\0'; cur_machine_emulated_hz[0] = '\0'; cur_machine_memory[0] = '\0'; return; } fatal("line %i: not expecting '%s' in an 'emul' section\n", *line, word); exit(1); } /* * parse__net(): * * Simple words: ipv4net, ipv4len, local_port * * Complex: add_remote * * TODO: more words? for example an option to disable the gateway? that would * have to be implemented correctly in src/net.c first. */ static void parse__net(struct emul *e, FILE *f, int *in_emul, int *line, int *parsestate, char *word, size_t maxbuflen) { int i; if (word[0] == ')') { /* Finished with the 'net' section. Let's create the net: */ if (e->net != NULL) { fatal("line %i: more than one net isn't really " "supported yet\n", *line); exit(1); } if (!cur_net_local_port[0]) strlcpy(cur_net_local_port, "0", sizeof(cur_net_local_port)); e->net = net_init(e, NET_INIT_FLAG_GATEWAY, cur_net_ipv4net, atoi(cur_net_ipv4len), cur_net_remote, cur_net_n_remote, atoi(cur_net_local_port), NULL); if (e->net == NULL) { fatal("line %i: fatal error: could not create" " the net (?)\n", *line); exit(1); } for (i=0; i= MAX_N_REMOTE) { fprintf(stderr, "too many remote networks\n"); exit(1); } CHECK_ALLOCATION(cur_net_remote[cur_net_n_remote] = (char *) malloc(MAX_REMOTE_LEN)); read_one_word(f, cur_net_remote[cur_net_n_remote], MAX_REMOTE_LEN, line, EXPECT_WORD); cur_net_n_remote ++; read_one_word(f, word, maxbuflen, line, EXPECT_RIGHT_PARENTHESIS); return; } fatal("line %i: not expecting '%s' in a 'net' section\n", *line, word); exit(1); } /* * parse__machine(): */ static void parse__machine(struct emul *e, FILE *f, int *in_emul, int *line, int *parsestate, char *word, size_t maxbuflen) { int r, i; if (word[0] == ')') { /* Finished with the 'machine' section. */ struct machine *m; if (!cur_machine_name[0]) strlcpy(cur_machine_name, "no_name", sizeof(cur_machine_name)); m = emul_add_machine(e, cur_machine_name); r = machine_name_to_type(cur_machine_type, cur_machine_subtype, &m->machine_type, &m->machine_subtype, &m->arch); if (!r) exit(1); if (cur_machine_cpu[0]) CHECK_ALLOCATION(m->cpu_name = strdup(cur_machine_cpu)); if (!cur_machine_use_x11[0]) strlcpy(cur_machine_use_x11, "no", sizeof(cur_machine_use_x11)); m->x11_md.in_use = parse_on_off(cur_machine_use_x11); if (!cur_machine_slowsi[0]) strlcpy(cur_machine_slowsi, "no", sizeof(cur_machine_slowsi)); m->slow_serial_interrupts_hack_for_linux = parse_on_off(cur_machine_slowsi); if (!cur_machine_prom_emulation[0]) strlcpy(cur_machine_prom_emulation, "yes", sizeof(cur_machine_prom_emulation)); m->prom_emulation = parse_on_off(cur_machine_prom_emulation); if (!cur_machine_random_mem[0]) strlcpy(cur_machine_random_mem, "no", sizeof(cur_machine_random_mem)); m->random_mem_contents = parse_on_off(cur_machine_random_mem); if (!cur_machine_random_cpu[0]) strlcpy(cur_machine_random_cpu, "no", sizeof(cur_machine_random_cpu)); m->use_random_bootstrap_cpu = parse_on_off(cur_machine_random_cpu); m->byte_order_override = NO_BYTE_ORDER_OVERRIDE; if (cur_machine_byte_order[0]) { if (strncasecmp(cur_machine_byte_order, "big", 3) == 0) m->byte_order_override = EMUL_BIG_ENDIAN; else if (strncasecmp(cur_machine_byte_order, "little", 6) == 0) m->byte_order_override = EMUL_LITTLE_ENDIAN; else { fatal("Byte order must be big-endian or" " little-endian\n"); exit(1); } } if (!cur_machine_force_netboot[0]) strlcpy(cur_machine_force_netboot, "no", sizeof(cur_machine_force_netboot)); m->force_netboot = parse_on_off(cur_machine_force_netboot); if (!cur_machine_start_paused[0]) strlcpy(cur_machine_start_paused, "no", sizeof(cur_machine_start_paused)); m->start_paused = parse_on_off(cur_machine_start_paused); /* NOTE: Default nr of CPUs is 0: */ if (!cur_machine_ncpus[0]) strlcpy(cur_machine_ncpus, "0", sizeof(cur_machine_ncpus)); m->ncpus = atoi(cur_machine_ncpus); if (cur_machine_n_gfx_cards[0]) m->n_gfx_cards = atoi(cur_machine_n_gfx_cards); if (cur_machine_serial_nr[0]) { m->serial_nr = atoi(cur_machine_serial_nr); e->next_serial_nr = m->serial_nr+1; } if (cur_machine_emulated_hz[0]) { m->emulated_hz = mystrtoull(cur_machine_emulated_hz, NULL, 0); } /* NOTE: Default nr of CPUs is 0: */ if (!cur_machine_memory[0]) strlcpy(cur_machine_memory, "0", sizeof(cur_machine_memory)); m->physical_ram_in_mb = atoi(cur_machine_memory); if (!cur_machine_x11_scaledown[0]) m->x11_md.scaledown = 1; else { m->x11_md.scaledown = atoi(cur_machine_x11_scaledown); if (m->x11_md.scaledown < 0) { m->x11_md.scaleup = 0 - m->x11_md.scaledown; m->x11_md.scaledown = 1; } if (m->x11_md.scaledown < 1) { fprintf(stderr, "Invalid scaledown value" " (%i)\n", m->x11_md.scaledown); exit(1); } } for (i=0; iboot_kernel_filename = strdup(cur_machine_bootname); if (cur_machine_bootarg[0]) m->boot_string_argument = strdup(cur_machine_bootarg); for (i=0; ix11_md.n_display_names ++; CHECK_ALLOCATION(m->x11_md.display_names = (char **) realloc( m->x11_md.display_names, m->x11_md.n_display_names * sizeof(char *))); CHECK_ALLOCATION(m->x11_md.display_names[ m->x11_md.n_display_names-1] = strdup(cur_machine_x11_disp[i])); free(cur_machine_x11_disp[i]); cur_machine_x11_disp[i] = NULL; } emul_machine_setup(m, cur_machine_n_load, cur_machine_load, cur_machine_n_device, cur_machine_device); for (i=0; i= MAX_N_LOAD) { fprintf(stderr, "too many loads\n"); exit(1); } CHECK_ALLOCATION(cur_machine_load[cur_machine_n_load] = (char*) malloc(MAX_LOAD_LEN)); read_one_word(f, cur_machine_load[cur_machine_n_load], MAX_LOAD_LEN, line, EXPECT_WORD); cur_machine_n_load ++; read_one_word(f, word, maxbuflen, line, EXPECT_RIGHT_PARENTHESIS); return; } if (strcmp(word, "disk") == 0) { read_one_word(f, word, maxbuflen, line, EXPECT_LEFT_PARENTHESIS); if (cur_machine_n_disk >= MAX_N_DISK) { fprintf(stderr, "too many disks\n"); exit(1); } CHECK_ALLOCATION(cur_machine_disk[cur_machine_n_disk] = (char*) malloc(MAX_DISK_LEN)); read_one_word(f, cur_machine_disk[cur_machine_n_disk], MAX_DISK_LEN, line, EXPECT_WORD); cur_machine_n_disk ++; read_one_word(f, word, maxbuflen, line, EXPECT_RIGHT_PARENTHESIS); return; } if (strcmp(word, "device") == 0) { read_one_word(f, word, maxbuflen, line, EXPECT_LEFT_PARENTHESIS); if (cur_machine_n_device >= MAX_N_DEVICE) { fprintf(stderr, "too many devices\n"); exit(1); } CHECK_ALLOCATION(cur_machine_device[cur_machine_n_device] = (char*) malloc(MAX_DEVICE_LEN)); read_one_word(f, cur_machine_device[cur_machine_n_device], MAX_DEVICE_LEN, line, EXPECT_WORD); cur_machine_n_device ++; read_one_word(f, word, maxbuflen, line, EXPECT_RIGHT_PARENTHESIS); return; } if (strcmp(word, "add_x11_display") == 0) { read_one_word(f, word, maxbuflen, line, EXPECT_LEFT_PARENTHESIS); if (cur_machine_n_x11_disp >= MAX_N_X11_DISP) { fprintf(stderr, "too many x11 displays\n"); exit(1); } CHECK_ALLOCATION(cur_machine_x11_disp[cur_machine_n_x11_disp] = (char*) malloc(MAX_X11_DISP_LEN)); read_one_word(f, cur_machine_x11_disp[cur_machine_n_x11_disp], MAX_X11_DISP_LEN, line, EXPECT_WORD); cur_machine_n_x11_disp ++; read_one_word(f, word, maxbuflen, line, EXPECT_RIGHT_PARENTHESIS); return; } fatal("line %i: not expecting '%s' in a 'machine' section\n", *line, word); exit(1); } /* * emul_parse_config(): * * Set up an emulation by parsing a config file. */ void emul_parse_config(struct emul *e, char *fname) { FILE *f = fopen(fname, "r"); char word[MAX_WORD_LEN]; int in_emul = 0; int line = 1; int parsestate = PARSESTATE_EMUL; /* debug("emul_parse_config()\n"); */ if (f == NULL) { perror(fname); exit(1); } while (!feof(f)) { read_one_word(f, word, sizeof(word), &line, EXPECT_WORD | EXPECT_RIGHT_PARENTHESIS); if (!word[0]) break; /* debug("word = '%s'\n", word); */ switch (parsestate) { case PARSESTATE_EMUL: parse__emul(e, f, &in_emul, &line, &parsestate, word, sizeof(word)); break; case PARSESTATE_NET: parse__net(e, f, &in_emul, &line, &parsestate, word, sizeof(word)); break; case PARSESTATE_MACHINE: parse__machine(e, f, &in_emul, &line, &parsestate, word, sizeof(word)); break; case PARSESTATE_NONE: break; default: fatal("INTERNAL ERROR in emul_parse.c (" "parsestate %i is not imlemented yet?)\n", parsestate); exit(1); } } if (parenthesis_level != 0) { fatal("EOF but not enough right parentheses?\n"); exit(1); } fclose(f); } gxemul-0.6.1/src/old_main/Makefile.skel000644 001750 001750 00000000467 13402411502 020202 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/old_main (from GXemul 0.4.x) # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(XINCLUDE) $(DINCLUDE) OBJS=emul.o emul_parse.o float_emul.o interrupt.o main.o memory.o misc.o \ settings.o timer.o all: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) *core clean_all: clean rm -f Makefile gxemul-0.6.1/src/old_main/main.cc000644 001750 001750 00000061465 13402411502 017045 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * GXemul's main entry point. */ #include #include #include #include #include #include #include "ComponentFactory.h" #include "console.h" #include "cpu.h" #include "debugger.h" #include "device.h" #include "diskimage.h" #include "emul.h" #include "GXemul.h" #include "machine.h" #include "misc.h" #include "settings.h" #include "timer.h" #include "UnitTest.h" extern int single_step; extern int force_debugger_at_exit; extern int optind; extern char *optarg; struct settings *global_settings; int extra_argc; char **extra_argv; char *progname; size_t dyntrans_cache_size = DEFAULT_DYNTRANS_CACHE_SIZE; static int skip_srandom_call = 0; /***************************************************************************** * * NOTE: debug(), fatal(), and debug_indentation() are not re-entrant. * The global variable quiet_mode can be used to suppress the output * of debug(), but not the output of fatal(). * *****************************************************************************/ int verbose = 0; int quiet_mode = 0; static int debug_indent = 0; static int debug_currently_at_start_of_line = 1; /* * va_debug(): * * Used internally by debug() and fatal(). */ static void va_debug(va_list argp, const char *fmt) { char buf[DEBUG_BUFSIZE + 1]; char *s; int i; buf[0] = buf[DEBUG_BUFSIZE] = 0; vsnprintf(buf, DEBUG_BUFSIZE, fmt, argp); s = buf; while (*s) { if (debug_currently_at_start_of_line) { for (i=0; i 0) { cerr << "Having memory leaks counts as failure to run the tests!\n"; exit(1); } #endif exit(result); } break; default: fprintf(stderr, "internal_w(): UNIMPLEMENTED arg = '%s'\n", arg); } } /*****************************************************************************/ /* * usage(): * * Prints program usage to stdout. */ static void usage(int longusage) { printf("GXemul " VERSION" " COPYRIGHT_MSG"\n" SECONDARY_MSG); printf("Read the source code and/or documentation for " "other Copyright messages.\n"); printf("\nUsage: %s [options] -e name [additional components and files [...]]\n", progname); printf(" or %s [options] configfile\n", progname); printf(" or %s -H\n", progname); printf(" or %s -V\n", progname); if (longusage) { printf("\nOptions:\n"); printf(" -B Enable snapshotting (reverse stepping support).\n"); printf(" -H Display a list of available machine templates.\n"); printf(" -e name Start with a machine based on template 'name'.\n"); printf(" -q Quiet mode (suppress debug messages).\n"); printf(" -V Start up in interactive debugging mode, paused.\n"); printf("\n"); } if (!longusage) { printf("\nLegacy usage: %s [machine, other, and general options] [file " "[...]]\n", progname); printf(" or %s [general options] @configfile\n", progname); printf("\nRun %s -h for help on command line options.\n", progname); return; } printf("\nThe following are options for the Old framework:\n"); printf("\nLegacy usage: %s [machine, other, and general options] [file " "[...]]\n", progname); printf(" or %s [general options] @configfile\n", progname); printf("\nMachine selection options:\n"); printf(" -E t try to emulate machine type t. (Use -H to get " "a list of types.)\n"); printf(" -e st try to emulate machine subtype st. (Use this " "with -E.)\n"); printf("\nOther options:\n"); printf(" -C x try to emulate a specific CPU. (Use -H to get a " "list of types.)\n"); printf(" -d fname add fname as a disk image. You can add \"xxx:\"" " as a prefix\n"); printf(" where xxx is one or more of the following:\n"); printf(" b specifies that this is the boot" " device\n"); printf(" c CD-ROM\n"); printf(" d DISK\n"); printf(" f FLOPPY\n"); printf(" gH;S; set geometry to H heads and S" " sectors-per-track\n"); printf(" i IDE\n"); printf(" oOFS; set base offset to OFS (for ISO9660" " filesystems)\n"); printf(" r read-only (don't allow changes to the" " file)\n"); printf(" s SCSI\n"); printf(" t tape\n"); printf(" V add an overlay\n"); printf(" 0-7 force a specific ID\n"); printf(" -I hz set the main cpu frequency to hz (not used by " "all combinations\n of machines and guest OSes)\n"); printf(" -i display each instruction as it is executed\n"); printf(" -J disable dyntrans instruction combinations\n"); printf(" -j name set the name of the kernel; for DECstation " "emulation, this passes\n the name to the bootloader," " for example:\n"); printf(" -j netbsd (NetBSD/pmax) " "-j bsd (OpenBSD/pmax)\n"); printf(" -j vmsprite (Sprite/pmax) " "-j vmunix (Ultrix/RISC)\n"); printf(" For other emulation modes, if the boot disk is an" " ISO9660\n filesystem, -j sets the name of the" " kernel to load.\n"); printf(" -M m emulate m MBs of physical RAM\n"); printf(" -N display nr of instructions/second average, at" " regular intervals\n"); printf(" -n nr set nr of CPUs (for SMP experiments)\n"); printf(" -O force netboot (tftp instead of disk), even when" " a disk image is\n" " present (for DECstation, SGI, and ARC emulation)\n"); printf(" -o arg set the boot argument, for DEC, ARC, or SGI" " emulation\n"); printf(" (default arg for DEC is -a, for ARC/SGI -aN)\n"); printf(" -p pc add a breakpoint (remember to use the '0x' " "prefix for hex!)\n"); printf(" -Q no built-in PROM emulation (use this for " "running ROM images)\n"); printf(" -R use random bootstrap cpu, instead of nr 0\n"); printf(" -r register dumps before every instruction\n"); printf(" -S initialize emulated RAM to random bytes, " "instead of zeroes\n"); printf(" -s f:name write statistics to file 'name', " "f is one or more of the following:\n"); printf(" v virtual program counter\n"); printf(" p physical equivalent of program counter\n"); printf(" i internal ic->f representation of " "the program counter\n"); printf(" and optionally:\n"); printf(" d disable statistics gathering at " "startup\n"); printf(" o overwrite instead of append\n"); printf(" -T halt on non-existant memory accesses\n"); printf(" -t show function trace tree\n"); printf(" -U enable slow_serial_interrupts_hack_for_linux\n"); #ifdef WITH_X11 printf(" -X use X11\n"); printf(" -x open up new xterms for emulated serial ports " "(default is on when\n using configuration files or" " when X11 is used, off otherwise)\n"); printf(" -Y n scale down framebuffer windows by n x n times\n"); #endif /* WITH_X11 */ printf(" -Z n set nr of graphics cards, for emulating a " "dual-head or tripple-head\n" " environment (only for DECstation emulation)\n"); printf(" -z disp add disp as an X11 display to use for " "framebuffers\n"); printf("\nGeneral options:\n"); printf(" -c cmd add cmd as a command to run before starting " "the simulation\n"); printf(" -D skip the srandom call at startup\n"); printf(" -H display a list of possible CPU and " "machine types\n"); printf(" -h display this help message\n"); printf(" -k n set dyntrans translation caches to n MB (default" " size is %i MB)\n", DEFAULT_DYNTRANS_CACHE_SIZE / 1048576); printf(" -K force the debugger to be entered at the end " "of a simulation\n"); printf(" -q quiet mode (don't print startup messages)\n"); printf(" -V start up in the single-step debugger, paused\n"); printf(" -v increase debug message verbosity\n"); printf("\n"); printf("If you are selecting a machine type to emulate directly " "on the command line,\nthen you must specify one or more names" " of files that you wish to load into\n" "memory. Supported formats are: ELF a.out ecoff srec syms raw\n" "where syms is the text produced by running 'nm' (or 'nm -S') " "on a binary.\n" "To load a raw binary into memory, add \"address:\" in front " "of the filename,\n" "or \"address:skiplen:\" or \"address:skiplen:initialpc:\".\n" "\nExamples:\n" " 0xbfc00000:rom.bin for a raw ROM image\n" " 0xbfc00000:0x100:rom.bin for an image with " "0x100 bytes header\n" " 0xbfc00000:0x100:0xbfc00884:rom.bin " "start with pc=0xbfc00884\n\n"); } /* * get_cmd_args(): * * Reads command line arguments. */ int get_cmd_args(int argc, char *argv[], struct emul *emul, char ***diskimagesp, int *n_diskimagesp) { int ch, res, using_switch_d = 0, using_switch_Z = 0; int using_switch_e = 0, using_switch_E = 0; bool using_switch_B = false; char *type = NULL, *subtype = NULL; int n_cpus_set = 0; int msopts = 0; /* Machine-specific options used */ struct machine *m = emul_add_machine(emul, NULL); const char *opts = "BC:c:Dd:E:e:HhI:iJj:k:KM:Nn:Oo:p:QqRrSs:TtUVvW:" #ifdef WITH_X11 "XxY:" #endif "Z:z:"; while ((ch = getopt(argc, argv, opts)) != -1) { switch (ch) { case 'B': using_switch_B = true; break; case 'C': CHECK_ALLOCATION(m->cpu_name = strdup(optarg)); msopts = 1; break; case 'c': emul->n_debugger_cmds ++; CHECK_ALLOCATION(emul->debugger_cmds = (char **) realloc(emul->debugger_cmds, emul->n_debugger_cmds * sizeof(char *))); CHECK_ALLOCATION(emul->debugger_cmds[emul-> n_debugger_cmds-1] = strdup(optarg)); break; case 'D': skip_srandom_call = 1; break; case 'd': /* diskimage_add() is called further down */ (*n_diskimagesp) ++; CHECK_ALLOCATION( (*diskimagesp) = (char **) realloc(*diskimagesp, sizeof(char *) * (*n_diskimagesp)) ); CHECK_ALLOCATION( (*diskimagesp)[(*n_diskimagesp) - 1] = strdup(optarg) ); using_switch_d = 1; msopts = 1; break; case 'E': if (using_switch_E ++ > 0) { fprintf(stderr, "-E already used.\n"); exit(1); } type = optarg; msopts = 1; break; case 'e': if (using_switch_e ++ > 0) { fprintf(stderr, "-e already used.\n"); exit(1); } subtype = optarg; msopts = 1; break; case 'H': GXemul::ListTemplates(); printf("--------------------------------------------------------------------------\n\n"); printf("The following applies to the LEGACY modes only:\n\n"); machine_list_available_types_and_cpus(); exit(1); case 'h': usage(1); exit(1); case 'I': m->emulated_hz = atoi(optarg); msopts = 1; break; case 'i': m->instruction_trace = 1; msopts = 1; break; case 'J': m->allow_instruction_combinations = 0; msopts = 1; break; case 'j': CHECK_ALLOCATION(m->boot_kernel_filename = strdup(optarg)); msopts = 1; break; case 'k': dyntrans_cache_size = atoi(optarg) * 1048576; if (dyntrans_cache_size < 1) { fprintf(stderr, "The dyntrans cache size must" " be at least 1 MB.\n"); exit(1); } break; case 'K': force_debugger_at_exit = 1; break; case 'M': m->physical_ram_in_mb = atoi(optarg); msopts = 1; break; case 'N': m->show_nr_of_instructions = 1; msopts = 1; break; case 'n': m->ncpus = atoi(optarg); n_cpus_set = 1; msopts = 1; break; case 'O': m->force_netboot = 1; msopts = 1; break; case 'o': CHECK_ALLOCATION(m->boot_string_argument = strdup(optarg)); msopts = 1; break; case 'p': machine_add_breakpoint_string(m, optarg); msopts = 1; break; case 'Q': m->prom_emulation = 0; msopts = 1; break; case 'q': quiet_mode = 1; break; case 'R': m->use_random_bootstrap_cpu = 1; msopts = 1; break; case 'r': m->register_dump = 1; msopts = 1; break; case 'S': m->random_mem_contents = 1; msopts = 1; break; case 's': machine_statistics_init(m, optarg); msopts = 1; break; case 'T': m->halt_on_nonexistant_memaccess = 1; msopts = 1; break; case 't': m->show_trace_tree = 1; msopts = 1; break; case 'U': m->slow_serial_interrupts_hack_for_linux = 1; msopts = 1; break; case 'V': single_step = ENTER_SINGLE_STEPPING; break; case 'v': verbose ++; break; case 'W': internal_w(optarg); exit(0); case 'X': m->x11_md.in_use = 1; msopts = 1; /* FALL-THROUGH */ case 'x': console_allow_slaves(1); break; case 'Y': m->x11_md.scaledown = atoi(optarg); if (m->x11_md.scaledown < -1) { m->x11_md.scaleup = - m->x11_md.scaledown; m->x11_md.scaledown = 1; } if (m->x11_md.scaledown < 1) { fprintf(stderr, "Invalid scaledown value.\n"); exit(1); } msopts = 1; break; case 'Z': m->n_gfx_cards = atoi(optarg); using_switch_Z = 1; msopts = 1; break; case 'z': m->x11_md.n_display_names ++; CHECK_ALLOCATION(m->x11_md.display_names = (char **) realloc( m->x11_md.display_names, m->x11_md.n_display_names * sizeof(char *))); CHECK_ALLOCATION(m->x11_md.display_names[ m->x11_md.n_display_names-1] = strdup(optarg)); msopts = 1; break; default: fprintf(stderr, "Run %s -h for help on command " "line options.\n", progname); exit(1); } } argc -= optind; argv += optind; extra_argc = argc; extra_argv = argv; // If -V is used, -q is ignored. if (single_step == ENTER_SINGLE_STEPPING) quiet_mode = 0; if (type == NULL && subtype == NULL && (single_step == ENTER_SINGLE_STEPPING || (argc > 0 && argv[0][0] != '@'))) { int res2 = 0; { GXemul gxemul; gxemul.InitUI(); if (single_step == ENTER_SINGLE_STEPPING) gxemul.SetRunState(GXemul::Paused); else gxemul.SetRunState(GXemul::Running); gxemul.SetSnapshottingEnabled(using_switch_B); if (quiet_mode) gxemul.SetQuietMode(true); if (argc > 0 && !gxemul.ParseFilenames("", argc, argv)) res = 1; if (res2 == 0) res2 = gxemul.Run(); } // Note: exit() is outside the GXemul scope, so that GXemul's // destructor runs. exit(res2); } if (type != NULL || subtype != NULL) { if (type == NULL) type = strdup(""); if (subtype == NULL) subtype = strdup(""); /* Is it a new machine mode? */ if (subtype[0] != '\0') { int res2 = 0; bool doExit = false; { GXemul gxemul; gxemul.InitUI(); if (single_step == ENTER_SINGLE_STEPPING) gxemul.SetRunState(GXemul::Paused); else gxemul.SetRunState(GXemul::Running); gxemul.SetSnapshottingEnabled(using_switch_B); if (quiet_mode) gxemul.SetQuietMode(true); if (gxemul.IsTemplateMachine(subtype)) { if (!gxemul.ParseFilenames(subtype, argc, argv)) res2 = 1; if (res2 == 0) res2 = gxemul.Run(); doExit = true; } } if (doExit) exit(res2); } /* Legacy mode? */ res = machine_name_to_type(type, subtype, &m->machine_type, &m->machine_subtype, &m->arch); if (!res) exit(1); } if (m->machine_type == MACHINE_NONE && msopts) { fprintf(stderr, "Machine specific options used directly on " "the command line, but no machine\nemulation specified?\n"); exit(1); } /* -i and -r are pretty verbose: */ if (m->instruction_trace && !verbose) { fprintf(stderr, "Implicitly %sturning on -v, because" " of -i\n", quiet_mode? "turning off -q and " : ""); verbose = 1; quiet_mode = 0; } if (m->register_dump && !verbose) { fprintf(stderr, "Implicitly %sturning on -v, because" " of -r\n", quiet_mode? "turning off -q and " : ""); verbose = 1; quiet_mode = 0; } /* * Usually, an executable filename must be supplied. * * However, it is possible to boot directly from a harddisk image * file. If no kernel is supplied, but a diskimage is being used, * then try to boot from disk. */ if (extra_argc == 0) { if (using_switch_d) { /* Booting directly from a disk image... */ } else { usage(0); fprintf(stderr, "\nNo filename given. Aborting.\n"); exit(1); } } else if (m->boot_kernel_filename[0] == '\0') { /* * Default boot_kernel_filename is "", which can be overriden * by the -j command line option. If it is still "" here, * and we're not booting directly from a disk image, then * try to set it to the last part of the last file name * given on the command line. (Last part = the stuff after * the last slash.) */ char *s = extra_argv[extra_argc - 1]; char *s2; s2 = strrchr(s, '/'); if (s2 == NULL) s2 = s; else s2 ++; CHECK_ALLOCATION(m->boot_kernel_filename = strdup(s2)); } if (m->n_gfx_cards < 0 || m->n_gfx_cards > 3) { fprintf(stderr, "Bad number of gfx cards (-Z).\n"); exit(1); } if (!using_switch_Z && !m->x11_md.in_use) m->n_gfx_cards = 0; return 0; } /* * main(): * * Two kinds of emulations are started from here: * * o) Simple emulations, using command line arguments, compatible with * earlier version of GXemul/mips64emul. * * o) Emulations set up by parsing special config files. (0 or more.) */ int main(int argc, char *argv[]) { /* Setting constants: */ int constant_yes = 1; int constant_true = 1; int constant_no = 0; int constant_false = 0; struct emul *emul; int config_file = 0; char **diskimages = NULL; int n_diskimages = 0; int i; progname = argv[0]; /* * Create the settings object, and add global settings to it: * * Read-only "constants": yes, no, true, false. * Global emulator settings: verbose, single_step, ... */ global_settings = settings_new(); settings_add(global_settings, "yes", 0, SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *)&constant_yes); settings_add(global_settings, "no", 0, SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *)&constant_no); settings_add(global_settings, "true", 0, SETTINGS_TYPE_INT, SETTINGS_FORMAT_BOOL, (void *)&constant_true); settings_add(global_settings, "false", 0, SETTINGS_TYPE_INT, SETTINGS_FORMAT_BOOL, (void *)&constant_false); /* Read-only settings: */ settings_add(global_settings, "single_step", 0, SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *)&single_step); /* Read/write settings: */ settings_add(global_settings, "force_debugger_at_exit", 1, SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *)&force_debugger_at_exit); settings_add(global_settings, "verbose", 1, SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *)&verbose); settings_add(global_settings, "quiet_mode", 1, SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *)&quiet_mode); /* Initialize all emulator subsystems: */ console_init(); cpu_init(); device_init(); machine_init(); timer_init(); /* Create a simple emulation setup: */ emul = emul_new(NULL); settings_add(global_settings, "emul", 1, SETTINGS_TYPE_SUBSETTINGS, 0, emul->settings); get_cmd_args(argc, argv, emul, &diskimages, &n_diskimages); if (!skip_srandom_call) { struct timeval tv; gettimeofday(&tv, NULL); srandom(tv.tv_sec ^ getpid() ^ tv.tv_usec); } /* Print startup message: */ debug("GXemul " VERSION" " COPYRIGHT_MSG"\n" SECONDARY_MSG "Read the source code and/or documentation for other Copyright " "messages.\n\n"); /* Simple initialization, from command line arguments: */ if (emul->machines[0]->machine_type != MACHINE_NONE) { for (i=0; imachines[0], diskimages[i]); /* Make sure that there are no configuration files as well: */ for (i=1; isettings); config_file = 1; } } if (emul->n_machines == 0) { fprintf(stderr, "No emulations defined. Maybe you forgot to " "use -E xx and/or -e yy, to specify\nthe machine type." " For example:\n\n %s -e 3max -d disk.img\n\n" "to boot an emulated DECstation 5000/200 with a disk " "image.\n", progname); exit(1); } if (emul->machines[0]->machine_type == MACHINE_NONE) { printf("No machine type specified? Run gxemul -H for a list\n" "of available machine types. Use the -e or -E option(s)\n" "to specify the machine type.\n"); exit(1); } device_set_exit_on_error(0); console_warn_if_slaves_are_needed(1); /* Run the emulation: */ emul_run(emul); /* * Deinitialize everything: */ console_deinit(); emul_destroy(emul); settings_remove_all(global_settings); settings_destroy(global_settings); return 0; } gxemul-0.6.1/src/devices/dev_sgi_re.cc000644 001750 001750 00000122712 13402411502 020060 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SGI O2 "Rendering Engine" * * Guesswork, based on how Linux, NetBSD, and OpenBSD use the graphics on * the SGI O2. Using NetBSD terminology (from crmfbreg.h): * * dev_sgi_re.cc (THIS FILE): * 0x15001000 rendering engine (TLBs) * 0x15002000 drawing engine * 0x15003000 memory transfer engine * 0x15004000 status registers for drawing engine * * dev_sgi_gbe.cc: * 0x16000000 crm (or GBE) framebuffer control / video output */ #include #include #include #include "console.h" #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/crmfbreg.h" #include "thirdparty/sgi_gl.h" struct sgi_re_data { // Rendering engine registers: uint16_t re_tlb_a[256]; uint16_t re_tlb_b[256]; uint16_t re_tlb_c[256]; uint16_t re_tex[112]; // todo: clip_ids registers. uint32_t re_linear_a[32]; uint32_t re_linear_b[32]; // Drawing engine registers: uint32_t de_reg[DEV_SGI_DE_LENGTH / sizeof(uint32_t)]; // Memory transfer engine registers: uint32_t mte_reg[DEV_SGI_MTE_LENGTH / sizeof(uint32_t)]; }; /* * horrible_getputpixel(): * * This routine gets/puts a pixel in one of the tiles, from the perspective of * the rendering/drawing engine. Given x and y, it figures out which tile * number it is, and then finally does a slow read/write to get/put the pixel * at the correct sub-coordinates within the tile. * * Tiles are always 512 _bytes_ wide, and 128 pixels high. For 32-bit color * modes, for example, that means 128 x 128 pixels. * * For "linear" modes, y is ignored and x is an offset to select which linear * TLB entry to use. */ void horrible_getputpixel(bool put, struct cpu* cpu, struct sgi_re_data* d, int x, int y, uint32_t* color, int mode) { uint32_t color_mode = mode & DE_MODE_TYPE_MASK; int bufdepth = 1 << ((mode >> 8) & 3); // dst_mode (see NetBSD's crmfbreg.h): // #define DE_MODE_TLB_A 0x00000000 // #define DE_MODE_TLB_B 0x00000400 // #define DE_MODE_TLB_C 0x00000800 // #define DE_MODE_LIN_A 0x00001000 // #define DE_MODE_LIN_B 0x00001400 uint32_t tlb_mode = (mode >> 10) & 0x7; bool linear = tlb_mode > 3; if (!linear && (x < 0 || y < 0 || x >= 2048 || y >= 2048)) return; int tilewidth_in_pixels = 512 / bufdepth; int tile_nr_x = x / tilewidth_in_pixels; int tile_nr_y = y >> 7; unsigned int tile_nr = tile_nr_y * 16 + tile_nr_x; y &= 127; int xofs = (x % tilewidth_in_pixels) * bufdepth; int ofs = 512 * y + xofs; uint32_t tileptr = 0; switch (tlb_mode) { case 0: tileptr = d->re_tlb_a[tile_nr] << 16; break; case 1: tileptr = d->re_tlb_b[tile_nr] << 16; break; case 2: tileptr = d->re_tlb_c[tile_nr] << 16; break; case 4: tile_nr = x >> 12; if (tile_nr >= 32) return; tileptr = 0x80000000 | (d->re_linear_a[tile_nr] << 12); ofs = x & 4095; // TODO... probably not correct! // printf("tileptr = %08x x = %i y = %i tile_nr = %i ofs = %i\n", tileptr, x, y, tile_nr, ofs); break; default:fatal("unimplemented dst_mode %i for horrible_getputpixel (%s), x=%i y=%i\n", mode, put ? "put" : "get", x, y); // exit(1); *color = random(); return; } // The highest bit seems to be set for a "valid" tile pointer. if (!(tileptr & 0x80000000)) { //printf("dst_mode %i, tile_nr = %i, tileptr = 0x%llx\n", dst_mode, tile_nr, (long long)tileptr); //fatal("sgi gbe horrible_getputpixel: unexpected non-set high bit of tileptr?\n"); //exit(1); return; } tileptr &= ~0x80000000; uint8_t buf[4]; if (put) { switch (color_mode) { case DE_MODE_TYPE_CI: buf[0] = *color; break; case DE_MODE_TYPE_RGB: buf[0] = *color >> 24; buf[1] = *color >> 16; buf[2] = *color >> 8; buf[3] = 0; break; case DE_MODE_TYPE_RGBA: buf[0] = *color >> 24; buf[1] = *color >> 16; buf[2] = *color >> 8; buf[3] = *color; break; case DE_MODE_TYPE_ABGR: buf[0] = *color; buf[1] = *color >> 8; buf[2] = *color >> 16; buf[3] = *color >> 24; break; default:buf[0] = random(); buf[1] = random(); buf[2] = random(); buf[3] = random(); // TODO. fatal("[ put: color mode = 0x%x ]\n", color_mode); } cpu->memory_rw(cpu, cpu->mem, tileptr + ofs, buf, bufdepth, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); } else { cpu->memory_rw(cpu, cpu->mem, tileptr + ofs, buf, bufdepth, MEM_READ, NO_EXCEPTIONS | PHYSICAL); switch (color_mode) { case DE_MODE_TYPE_CI: *color = buf[0]; break; case DE_MODE_TYPE_RGB: *color = (buf[1] << 24) + (buf[2] << 16) + (buf[3] << 8); break; case DE_MODE_TYPE_RGBA: *color = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; break; case DE_MODE_TYPE_ABGR: *color = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0]; break; default:// Read "raw" 32-bit value: *color = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0]; fatal("[ get: color mode = 0x%x ]\n", color_mode); } } } /* * SGI "re", NetBSD sources describes it as a "rendering engine". */ DEVICE_ACCESS(sgi_re) { struct sgi_re_data *d = (struct sgi_re_data *) extra; uint64_t idata = 0, odata = 0; idata = memory_readmax64(cpu, data, len); relative_addr += 0x1000; if (relative_addr >= CRIME_RE_TLB_A && relative_addr < CRIME_RE_TLB_B) { if (len != 8) { fatal("TODO: unimplemented len=%i for CRIME_RE_TLB_A\n", len); exit(1); } if (writeflag == MEM_WRITE) { int tlbi = ((relative_addr & 0x1ff) >> 1) & 0xff; for (size_t hwi = 0; hwi < len; hwi += sizeof(uint16_t)) { d->re_tlb_a[tlbi] = data[hwi]*256 + data[hwi+1]; debug("d->re_tlb_a[%i] = 0x%04x\n", tlbi, d->re_tlb_a[tlbi]); tlbi++; } } else { fatal("TODO: read from CRIME_RE_TLB_A\n"); exit(1); } } else if (relative_addr >= CRIME_RE_TLB_B && relative_addr < CRIME_RE_TLB_C) { if (len != 8) { fatal("TODO: unimplemented len=%i for CRIME_RE_TLB_B\n", len); exit(1); } if (writeflag == MEM_WRITE) { int tlbi = ((relative_addr & 0x1ff) >> 1) & 0xff; for (size_t hwi = 0; hwi < len; hwi += sizeof(uint16_t)) { d->re_tlb_b[tlbi] = data[hwi]*256 + data[hwi+1]; debug("d->re_tlb_b[%i] = 0x%04x\n", tlbi, d->re_tlb_b[tlbi]); tlbi++; } } else { fatal("TODO: read from CRIME_RE_TLB_B\n"); exit(1); } } else if (relative_addr >= CRIME_RE_TLB_C && relative_addr < CRIME_RE_TLB_C + 0x200) { if (len != 8) { fatal("TODO: unimplemented len=%i for CRIME_RE_TLB_C\n", len); exit(1); } if (writeflag == MEM_WRITE) { int tlbi = ((relative_addr & 0x1ff) >> 1) & 0xff; for (size_t hwi = 0; hwi < len; hwi += sizeof(uint16_t)) { d->re_tlb_c[tlbi] = data[hwi]*256 + data[hwi+1]; debug("d->re_tlb_c[%i] = 0x%04x\n", tlbi, d->re_tlb_c[tlbi]); tlbi++; } } else { fatal("TODO: read from CRIME_RE_TLB_C\n"); exit(1); } } else if (relative_addr >= CRIME_RE_TEX && relative_addr < CRIME_RE_TEX + 0xe0) { if (len != 8) { fatal("TODO: unimplemented len=%i for CRIME_RE_TEX\n", len); exit(1); } if (writeflag == MEM_WRITE) { int tlbi = ((relative_addr & 0xff) >> 3) & 0xff; for (size_t hwi = 0; hwi < len; hwi += sizeof(uint16_t)) { d->re_tex[tlbi] = data[hwi]*256 + data[hwi+1]; debug("d->re_tex[%i] = 0x%04x\n", tlbi, d->re_tex[tlbi]); tlbi++; } } else { fatal("TODO: read from CRIME_RE_TEX\n"); exit(1); } } else if (relative_addr >= CRIME_RE_LINEAR_A && relative_addr < CRIME_RE_LINEAR_A + 0x80) { if (len != 8) { fatal("TODO: unimplemented len=%i for CRIME_RE_LINEAR_A\n", len); exit(1); } if (writeflag == MEM_WRITE) { /* * Very interesting. NetBSD writes stuff such as: * * CRIME_RE_LINEAR_A IDATA = 8000173080001731 * CRIME_RE_LINEAR_A IDATA = 8000173280001733 * CRIME_RE_LINEAR_A IDATA = 8000173480001735 * ... * * but the PROM writes something which looks like wrongly * 32-bit sign-extended words: * * CRIME_RE_LINEAR_A IDATA = ffffffff80040001 * CRIME_RE_LINEAR_A IDATA = ffffffff80040003 * CRIME_RE_LINEAR_A IDATA = ffffffff80040005 * ... * * followed by * [ sgi_mte: STARTING TRANSFER: mode=0x00000011 * dst0=0x0000000040000000, dst1=0x0000000040007fff * (length 0x8000), dst_y_step=0 bg=0x0, bytemask=0xffffffff ] * * indicating that it really meant to put both 0x80040000 * and 0x80040001 into the first LINEAR_A entry. * * The first guess would be a bug in the implementation of * one or more instructions in the emulator while coming up * with those values, but debugging the PROM so far has NOT * revealed any such bug. It may even be that the PROM code * is buggy (?) and never really set the LINEAR entries * correctly. Perhaps the hardware simply ignores the * weird values and does not fill it (using the MTE) * when asked to. */ // printf("CRIME_RE_LINEAR_A IDATA = %016llx\n", (long long)idata); int tlbi = ((relative_addr & 0x7f) >> 2) & 0x1f; d->re_linear_a[tlbi] = idata >> 32ULL; d->re_linear_a[tlbi+1] = idata; debug("[ d->re_linear_a[%i] = 0x%08x, [%i] = 0x%08x ]\n", tlbi, d->re_linear_a[tlbi], tlbi+1, d->re_linear_a[tlbi+1]); } else { fatal("TODO: read from CRIME_RE_LINEAR_A\n"); exit(1); } } else if (relative_addr >= CRIME_RE_LINEAR_B && relative_addr < CRIME_RE_LINEAR_B + 0x80) { if (len != 8) { fatal("TODO: unimplemented len=%i for CRIME_RE_LINEAR_B\n", len); exit(1); } if (writeflag == MEM_WRITE) { int tlbi = ((relative_addr & 0x7f) >> 2) & 0x1f; d->re_linear_b[tlbi] = idata >> 32ULL; d->re_linear_b[tlbi+1] = idata; debug("[ d->re_linear_b[%i] = 0x%08x, [%i] = 0x%08x ]\n", tlbi, d->re_linear_b[tlbi], tlbi+1, d->re_linear_b[tlbi+1]); } else { fatal("TODO: read from CRIME_RE_LINEAR_B\n"); exit(1); } } else { if (writeflag == MEM_WRITE) fatal("[ sgi_re: unimplemented write to " "address 0x%llx, data=0x%016llx ]\n", (long long)relative_addr, (long long)idata); else fatal("[ sgi_re: unimplemented read from address" " 0x%llx ]\n", (long long)relative_addr); exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_sgi_re_init(): */ void dev_sgi_re_init(struct machine *machine, struct memory *mem, uint64_t baseaddr) { struct sgi_re_data *d; CHECK_ALLOCATION(d = (struct sgi_re_data *) malloc(sizeof(struct sgi_re_data))); memset(d, 0, sizeof(struct sgi_re_data)); memory_device_register(mem, "sgi_re", baseaddr + 0x1000, DEV_SGI_RE_LENGTH, dev_sgi_re_access, d, DM_DEFAULT, NULL); dev_sgi_de_init(mem, baseaddr + 0x2000, d); dev_sgi_mte_init(mem, baseaddr + 0x3000, d); dev_sgi_de_status_init(mem, baseaddr + 0x4000, d); } /****************************************************************************/ /* * SGI "de", NetBSD sources describes it as a "drawing engine". */ void draw_primitive(struct cpu* cpu, struct sgi_re_data *d) { uint32_t op = d->de_reg[(CRIME_DE_PRIMITIVE - 0x2000) / sizeof(uint32_t)]; uint32_t drawmode = d->de_reg[(CRIME_DE_DRAWMODE - 0x2000) / sizeof(uint32_t)]; uint32_t dst_mode = d->de_reg[(CRIME_DE_MODE_DST - 0x2000) / sizeof(uint32_t)]; uint32_t src_mode = d->de_reg[(CRIME_DE_MODE_SRC - 0x2000) / sizeof(uint32_t)]; uint32_t fg = d->de_reg[(CRIME_DE_FG - 0x2000) / sizeof(uint32_t)]; uint32_t bg = d->de_reg[(CRIME_DE_BG - 0x2000) / sizeof(uint32_t)]; uint32_t rop = d->de_reg[(CRIME_DE_ROP - 0x2000) / sizeof(uint32_t)]; uint32_t stipple_mode = d->de_reg[(CRIME_DE_STIPPLE_MODE - 0x2000) / sizeof(uint32_t)]; uint32_t pattern = d->de_reg[(CRIME_DE_STIPPLE_PAT - 0x2000) / sizeof(uint32_t)]; int nr_of_bits_to_strip_to_the_left = (stipple_mode >> DE_STIP_STRTIDX_SHIFT) & 31; int nr_of_bits_to_strip_to_the_right = 31 - ((stipple_mode >> DE_STIP_MAXIDX_SHIFT) & 31); pattern >>= nr_of_bits_to_strip_to_the_right; pattern <<= nr_of_bits_to_strip_to_the_right; pattern <<= nr_of_bits_to_strip_to_the_left; int nr_of_bits_in_the_middle = 32 - nr_of_bits_to_strip_to_the_left - nr_of_bits_to_strip_to_the_right; if (stipple_mode & 0xe0e0ffff) fatal("[ sgi_de: UNIMPLEMENTED stipple_mode bits: 0x%08x ]\n", stipple_mode); uint32_t x1 = (d->de_reg[(CRIME_DE_X_VERTEX_0 - 0x2000) / sizeof(uint32_t)] >> 16) & 0x7ff; uint32_t y1 = d->de_reg[(CRIME_DE_X_VERTEX_0 - 0x2000) / sizeof(uint32_t)]& 0x7ff; uint32_t x2 = (d->de_reg[(CRIME_DE_X_VERTEX_1 - 0x2000) / sizeof(uint32_t)] >> 16) & 0x7ff; uint32_t y2 = d->de_reg[(CRIME_DE_X_VERTEX_1 - 0x2000) / sizeof(uint32_t)]& 0x7ff; size_t x, y; debug("[ sgi_de: STARTING DRAWING COMMAND: op = 0x%08x," " drawmode=0x%x src_mode=0x%x dst_mode=0x%x x1=%i y1=%i" " x2=%i y2=%i fg=0x%x bg=0x%x pattern=0x%08x ]\n", op, drawmode, src_mode, dst_mode, x1, y1, x2, y2, fg, bg, pattern); // bufdepth = 1, 2, or 4. // int dst_bufdepth = 1 << ((dst_mode >> 8) & 3); int src_bufdepth = 1 << ((src_mode >> 8) & 3); bool src_is_linear = false; int src_x = -1, src_y = -1; int32_t step_x = 0; if (drawmode & DE_DRAWMODE_XFER_EN) { uint32_t addr_src = d->de_reg[(CRIME_DE_XFER_ADDR_SRC - 0x2000) / sizeof(uint32_t)]; uint32_t strd_src = d->de_reg[(CRIME_DE_XFER_STRD_SRC - 0x2000) / sizeof(uint32_t)]; step_x = d->de_reg[(CRIME_DE_XFER_STEP_X - 0x2000) / sizeof(uint32_t)]; int32_t step_y = d->de_reg[(CRIME_DE_XFER_STEP_Y - 0x2000) / sizeof(uint32_t)]; uint32_t addr_dst = d->de_reg[(CRIME_DE_XFER_ADDR_DST - 0x2000) / sizeof(uint32_t)]; uint32_t strd_dst = d->de_reg[(CRIME_DE_XFER_STRD_DST - 0x2000) / sizeof(uint32_t)]; src_is_linear = ((src_mode & 0x00001c00) >> 10) > 3; if (src_is_linear) { src_x = addr_src; src_y = 0; } else { src_x = (addr_src >> 16) & 0x7ff; src_y = addr_src & 0x7ff; } if (step_x != src_bufdepth || (step_y != 0 && step_y != 1)) { fatal("[ sgi_de: unimplemented XFER addr_src=0x%x src_bufdepth=%i " "strd_src=0x%x step_x=0x%x step_y=0x%x " "addr_dst=0x%x strd_dst=0x%x ]\n", addr_src, src_bufdepth, strd_src, step_x, step_y, addr_dst, strd_dst); // exit(1); } } if (!(drawmode & DE_DRAWMODE_PLANEMASK)) { printf("!DE_DRAWMODE_PLANEMASK: TODO\n"); } if ((drawmode & DE_DRAWMODE_BYTEMASK) != DE_DRAWMODE_BYTEMASK) { printf("not all DE_DRAWMODE_BYTEMASK set: TODO\n"); } // primitive rendering direction (not for Lines? and presumably // not for Points either :-) int dx = op & DE_PRIM_RL ? -1 : 1; int dy = op & DE_PRIM_TB ? 1 : -1; uint16_t saved_src_x = src_x; /* * Drawing is limited to 2048 x 2048 pixel space. * * TODO: MAYBE it is really -2048 to 2027, i.e. 12 bits of * pixel space. Perhaps it is possible to figure out * experimentally some day, e.g. by drawing lines from * -10,10 to 500,20 and see whether the real hardware * interprets -10 as -10 or 0x800 - 10. */ uint16_t endx = (x2 + dx) & 0x7ff; uint16_t endy = (y2 + dy) & 0x7ff; int lx = abs((int)(x2 - x1)), ly = abs((int)(y2 - y1)); int linelen = lx > ly ? lx : ly; switch (op & 0xff000000) { case DE_PRIM_LINE: if (drawmode & DE_DRAWMODE_XFER_EN) fatal("[ sgi_de: XFER_EN for LINE op? ]\n"); // The PROM uses width 32, but NetBSD documents it as "half pixels". // if ((op & DE_PRIM_LINE_WIDTH_MASK) != 2) // fatal("[ sgi_de: LINE_WIDTH_MASK = %i ]\n", op & DE_PRIM_LINE_WIDTH_MASK); if (linelen == 0) linelen ++; for (int i = 0; i < ((op & DE_PRIM_LINE_SKIP_END)? linelen : linelen+1); ++i) { x = (x2 * i + x1 * (linelen-i)) / linelen; y = (y2 * i + y1 * (linelen-i)) / linelen; uint32_t color = fg; uint32_t oldcolor = fg; if (drawmode & DE_DRAWMODE_ROP && rop != OPENGL_LOGIC_OP_COPY) horrible_getputpixel(false, cpu, d, x, y, &oldcolor, dst_mode); bool draw = true; if (drawmode & DE_DRAWMODE_LINE_STIP) { if (drawmode & DE_DRAWMODE_OPAQUE_STIP) color = (pattern & 0x80000000UL) ? fg : bg; else draw = (pattern & 0x80000000UL)? true : false; } // Raster-OP. // TODO: Other ops. // TODO: Should this be before or after other things? if (drawmode & DE_DRAWMODE_ROP) { switch (rop) { case OPENGL_LOGIC_OP_COPY: // color = color; break; case OPENGL_LOGIC_OP_XOR: color = oldcolor ^ color; break; case OPENGL_LOGIC_OP_COPY_INVERTED: color = 0xffffffff - oldcolor; break; default:{ static char rop_used[256]; static bool first = true; if (first) { memset(rop_used, 0, sizeof(rop_used)); first = false; } if (!rop_used[rop & 255]) { rop_used[rop & 255] = 1; fatal("[ sgi_de: LINE: rop[0x%02x] used! ]\n", rop & 255); } if (rop >> 8) { fatal("[ sgi_de: LINE: rop > 255: 0x%08x ]\n", rop); } } } } if (draw) horrible_getputpixel(true, cpu, d, x, y, &color, dst_mode); // Rotate the stipple pattern: pattern = (pattern << 1) | (pattern >> (nr_of_bits_in_the_middle-1)); } break; case DE_PRIM_RECTANGLE: for (y = y1; y != endy; y = (y + dy) & 0x7ff) { src_x = saved_src_x; for (x = x1; x != endx; x = (x + dx) & 0x7ff) { uint32_t color = fg; uint32_t oldcolor = fg; if (drawmode & DE_DRAWMODE_ROP && rop != OPENGL_LOGIC_OP_COPY) horrible_getputpixel(false, cpu, d, x, y, &oldcolor, dst_mode); // Pixel colors copied from another source. // (OpenBSD draws characters using this mechanism.) if (drawmode & DE_DRAWMODE_XFER_EN) horrible_getputpixel(false, cpu, d, src_x, src_y, &color, src_mode); bool draw = true; if (drawmode & DE_DRAWMODE_POLY_STIP) { if (drawmode & DE_DRAWMODE_OPAQUE_STIP) color = (pattern & 0x80000000UL) ? fg : bg; else draw = (pattern & 0x80000000UL)? true : false; } // Raster-OP. // TODO: Other ops. // TODO: Should this be before or after other things? if (drawmode & DE_DRAWMODE_ROP) { switch (rop) { case OPENGL_LOGIC_OP_COPY: // color = color; break; case OPENGL_LOGIC_OP_XOR: color = oldcolor ^ color; break; case OPENGL_LOGIC_OP_COPY_INVERTED: color = 0xffffffff - oldcolor; break; default:{ static char rop_used[256]; static bool first = true; if (first) { memset(rop_used, 0, sizeof(rop_used)); first = false; } if (!rop_used[rop & 255]) { rop_used[rop & 255] = 1; fatal("[ sgi_de: RECT: rop[0x%02x] used! ]\n", rop & 255); } if (rop >> 8) { fatal("[ sgi_de: RECT: rop > 255: 0x%08x ]\n", rop); } } } } if (draw) horrible_getputpixel(true, cpu, d, x, y, &color, dst_mode); // Rotate the stipple pattern: pattern = (pattern << 1) | (pattern >> (nr_of_bits_in_the_middle-1)); if (src_is_linear) src_x += step_x; else src_x = (src_x + dx) & 0x7ff; } src_y = (src_y + dy) & 0x7ff; } break; default:fatal("[ sgi_de: UNIMPLEMENTED drawing op = 0x%08x," " x1=%i y1=%i x2=%i y2=%i fg=0x%x bg=0x%x pattern=0x%08x ]\n", op, x1, y1, x2, y2, fg, bg, pattern); exit(1); } } DEVICE_ACCESS(sgi_de) { struct sgi_re_data *d = (struct sgi_re_data *) extra; uint64_t idata = 0, odata = 0; int regnr; bool startFlag = relative_addr & CRIME_DE_START ? true : false; relative_addr &= ~CRIME_DE_START; idata = memory_readmax64(cpu, data, len); regnr = relative_addr / sizeof(uint32_t); relative_addr += 0x2000; /* * Treat all registers as read/write, by default. Sometimes these * are accessed as 32-bit words, sometimes as 64-bit words to access * two adjacent registers in one operation. */ if (len == 8) { if (writeflag == MEM_WRITE) { d->de_reg[regnr] = idata >> 32ULL; d->de_reg[regnr+1] = idata; } else odata = ((uint64_t)d->de_reg[regnr] << 32ULL) + d->de_reg[regnr+1]; } else if (len == 4) { if (writeflag == MEM_WRITE) d->de_reg[regnr] = idata; else odata = d->de_reg[regnr]; } else { fatal("sgi_de: len = %i not implemented\n", len); exit(1); } switch (relative_addr) { case CRIME_DE_MODE_SRC: debug("[ sgi_de: %s CRIME_DE_MODE_SRC: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_MODE_DST: debug("[ sgi_de: %s CRIME_DE_MODE_DST: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_CLIPMODE: debug("[ sgi_de: %s CRIME_DE_CLIPMODE: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); if (writeflag == MEM_WRITE && idata != 0) fatal("[ sgi_de: TODO: non-zero CRIME_DE_CLIPMODE: 0x%016llx ]\n", idata); break; case CRIME_DE_DRAWMODE: debug("[ sgi_de: %s CRIME_DE_DRAWMODE: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_SCRMASK0: debug("[ sgi_de: %s CRIME_DE_SCRMASK0: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); if (writeflag == MEM_WRITE && idata != 0) fatal("[ sgi_de: TODO: non-zero CRIME_DE_SCRMASK0: 0x%016llx ]\n", idata); break; case CRIME_DE_SCRMASK1: debug("[ sgi_de: %s CRIME_DE_SCRMASK1: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); if (writeflag == MEM_WRITE && idata != 0) fatal("[ sgi_de: TODO: non-zero CRIME_DE_SCRMASK1: 0x%016llx ]\n", idata); break; case CRIME_DE_SCRMASK2: debug("[ sgi_de: %s CRIME_DE_SCRMASK2: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); if (writeflag == MEM_WRITE && idata != 0) fatal("[ sgi_de: TODO: non-zero CRIME_DE_SCRMASK2: 0x%016llx ]\n", idata); break; case CRIME_DE_SCRMASK3: debug("[ sgi_de: %s CRIME_DE_SCRMASK3: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); if (writeflag == MEM_WRITE && idata != 0) fatal("[ sgi_de: TODO: non-zero CRIME_DE_SCRMASK3: 0x%016llx ]\n", idata); break; case CRIME_DE_SCRMASK4: debug("[ sgi_de: %s CRIME_DE_SCRMASK4: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); if (writeflag == MEM_WRITE && idata != 0) fatal("[ sgi_de: TODO: non-zero CRIME_DE_SCRMASK4: 0x%016llx ]\n", idata); break; case CRIME_DE_SCISSOR: debug("[ sgi_de: %s CRIME_DE_SCISSOR: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); if (writeflag == MEM_WRITE && idata != 0) fatal("[ sgi_de: TODO: non-zero CRIME_DE_SCISSOR: 0x%016llx ]\n", idata); break; case CRIME_DE_SCISSOR + 4: // NetBSD writes 0x3fff3fff here. "High" part of SCISSOR register? debug("[ sgi_de: %s CRIME_DE_SCISSOR+4: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); if (writeflag == MEM_WRITE && idata != 0x3fff3fff) fatal("[ sgi_de: TODO: CRIME_DE_SCISSOR+4: 0x%016llx ]\n", idata); break; case CRIME_DE_PRIMITIVE: debug("[ sgi_de: %s CRIME_DE_PRIMITIVE: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_WINOFFSET_SRC: debug("[ sgi_de: %s CRIME_DE_WINOFFSET_SRC: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); if (writeflag == MEM_WRITE && idata != 0) fatal("[ sgi_de: TODO: non-zero CRIME_DE_WINOFFSET_SRC: 0x%016llx ]\n", idata); break; case CRIME_DE_WINOFFSET_DST: debug("[ sgi_de: %s CRIME_DE_WINOFFSET_DST: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); if (writeflag == MEM_WRITE && idata != 0) fatal("[ sgi_de: TODO: non-zero CRIME_DE_WINOFFSET_DST: 0x%016llx ]\n", idata); break; case CRIME_DE_X_VERTEX_0: debug("[ sgi_de: %s CRIME_DE_X_VERTEX_0: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_X_VERTEX_1: debug("[ sgi_de: %s CRIME_DE_X_VERTEX_1: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_XFER_ADDR_SRC: debug("[ sgi_de: %s CRIME_DE_XFER_ADDR_SRC: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_XFER_STRD_SRC: debug("[ sgi_de: %s CRIME_DE_XFER_STRD_SRC: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_XFER_STEP_X: debug("[ sgi_de: %s CRIME_DE_XFER_STEP_X: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_XFER_STEP_Y: debug("[ sgi_de: %s CRIME_DE_XFER_STEP_Y: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_XFER_ADDR_DST: debug("[ sgi_de: %s CRIME_DE_XFER_ADDR_DST: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_XFER_STRD_DST: debug("[ sgi_de: %s CRIME_DE_XFER_STRD_DST: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_STIPPLE_MODE: debug("[ sgi_de: %s CRIME_DE_STIPPLE_MODE: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_STIPPLE_PAT: debug("[ sgi_de: %s CRIME_DE_STIPPLE_PAT: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_FG: debug("[ sgi_de: %s CRIME_DE_FG: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_BG: debug("[ sgi_de: %s CRIME_DE_BG: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_ROP: debug("[ sgi_de: %s CRIME_DE_ROP: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_PLANEMASK: debug("[ sgi_de: %s CRIME_DE_PLANEMASK: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_NULL: debug("[ sgi_de: %s CRIME_DE_NULL: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_DE_FLUSH: debug("[ sgi_de: %s CRIME_DE_FLUSH: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; default: if (writeflag == MEM_WRITE) fatal("[ sgi_de: unimplemented write to " "address 0x%llx, data=0x%016llx ]\n", (long long)relative_addr, (long long)idata); else fatal("[ sgi_de: unimplemented read from address" " 0x%llx ]\n", (long long)relative_addr); } if (startFlag) draw_primitive(cpu, d); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_sgi_de_init(): */ void dev_sgi_de_init(struct memory *mem, uint64_t baseaddr, struct sgi_re_data *d) { memory_device_register(mem, "sgi_de", baseaddr, DEV_SGI_DE_LENGTH, dev_sgi_de_access, (void *)d, DM_DEFAULT, NULL); } /****************************************************************************/ /* * SGI "mte", NetBSD sources describes it as a "memory transfer engine". * * If the relative address has the 0x0800 (CRIME_DE_START) flag set, it means * "go ahead with the transfer". Otherwise, it is just reads and writes of the * registers. */ void do_mte_transfer(struct cpu* cpu, struct sgi_re_data *d) { uint32_t mode = d->mte_reg[(CRIME_MTE_MODE - 0x3000) / sizeof(uint32_t)]; uint32_t src0 = d->mte_reg[(CRIME_MTE_SRC0 - 0x3000) / sizeof(uint32_t)]; uint32_t src1 = d->mte_reg[(CRIME_MTE_SRC1 - 0x3000) / sizeof(uint32_t)]; uint32_t dst0 = d->mte_reg[(CRIME_MTE_DST0 - 0x3000) / sizeof(uint32_t)]; uint32_t dst1 = d->mte_reg[(CRIME_MTE_DST1 - 0x3000) / sizeof(uint32_t)]; int32_t src_y_step = d->mte_reg[(CRIME_MTE_SRC_Y_STEP - 0x3000) / sizeof(uint32_t)]; int32_t dst_y_step = d->mte_reg[(CRIME_MTE_DST_Y_STEP - 0x3000) / sizeof(uint32_t)]; uint32_t dstlen = dst1 - dst0 + 1, fill_addr; unsigned char zerobuf[4096]; int depth = 8 << ((mode & MTE_MODE_DEPTH_MASK) >> MTE_DEPTH_SHIFT); int src = (mode & MTE_MODE_SRC_BUF_MASK) >> MTE_SRC_TLB_SHIFT; uint32_t bytemask = d->mte_reg[(CRIME_MTE_BYTEMASK - 0x3000) / sizeof(uint32_t)]; uint32_t bg = d->mte_reg[(CRIME_MTE_BG - 0x3000) / sizeof(uint32_t)]; debug("[ sgi_mte: STARTING: mode=0x%08x src0=0x%08x src1=0x%08x src_y_step=%i dst0=0x%08x," " dst1=0x%08x dst_y_step=%i bg=0x%x bytemask=0x%x ]\n", mode, src0, src1, src_y_step, dst0, dst1, dst_y_step, bg, bytemask); if (dst_y_step != 0 && dst_y_step != 1 && dst_y_step != -1) { fatal("[ sgi_mte: TODO! unimplemented dst_y_step %i ]", dst_y_step); // exit(1); } if (mode & MTE_MODE_STIPPLE) { fatal("[ sgi_mte: unimplemented MTE_MODE_STIPPLE ]"); exit(1); } int src_tlb = (mode & MTE_MODE_SRC_BUF_MASK) >> MTE_SRC_TLB_SHIFT; int dst_tlb = (mode & MTE_MODE_DST_BUF_MASK) >> MTE_DST_TLB_SHIFT; if (src > MTE_TLB_C) { fatal("[ sgi_mte: unimplemented SRC ]"); exit(1); } switch (dst_tlb) { case MTE_TLB_A: case MTE_TLB_B: case MTE_TLB_C: // Used by NetBSD's crmfb_fill_rect. It puts graphical // coordinates in dst0 and dst1. { int x1 = (dst0 >> 16) & 0xfff; int y1 = dst0 & 0xfff; int x2 = (dst1 >> 16) & 0xfff; int y2 = dst1 & 0xfff; x1 /= (depth / 8); x2 /= (depth / 8); int src_x1 = (src0 >> 16) & 0xfff; int src_y1 = src0 & 0xfff; // int src_x2 = (src1 >> 16) & 0xfff; // int src_y2 = src1 & 0xfff; src_x1 /= (depth / 8); // src_x2 /= (depth / 8); int dx = x1 > x2 ? -1 : 1; int dy = y1 > y2 ? -1 : 1; uint32_t src_mode = (src_tlb << 10) + (((mode & MTE_MODE_DEPTH_MASK) >> MTE_DEPTH_SHIFT) << 8); uint32_t dst_mode = (dst_tlb << 10) + (((mode & MTE_MODE_DEPTH_MASK) >> MTE_DEPTH_SHIFT) << 8); // Hack. The MTE perhaps doesn't deal with colors per se, // but this makes sure that we copy 32 bits when doing 32-bit // transfers. if (depth == 4) { src_mode |= DE_MODE_TYPE_RGBA; dst_mode |= DE_MODE_TYPE_RGBA; } int src_y = src_y1; for (int y = y1; y != y2+dy; y += dy) { int src_x = src_x1; for (int x = x1; x != x2+dx; x += dx) { if (mode & MTE_MODE_COPY) { horrible_getputpixel(false, cpu, d, src_x, src_y, &bg, src_mode); src_x += dx; } horrible_getputpixel(true, cpu, d, x, y, &bg, dst_mode); } src_y += dy; } } break; case MTE_TLB_LIN_A: case MTE_TLB_LIN_B: // Used by the PROM to zero-fill memory (?). if (mode & MTE_MODE_COPY) { fatal("[ sgi_mte: unimplemented MTE_MODE_COPY ]"); exit(1); } if (depth != 8) { fatal("[ sgi_mte: unimplemented MTE_DEPTH_x ]"); exit(1); } debug("[ sgi_mte: LINEAR TRANSFER: mode=0x%08x dst0=0x%016llx," " dst1=0x%016llx (length 0x%llx), dst_y_step=%i bg=0x%x, bytemask=0x%x ]\n", mode, (long long)dst0, (long long)dst1, (long long)dstlen, dst_y_step, (int)bg, (int)bytemask); if (bytemask != 0xffffffff) { fatal("unimplemented MTE bytemask 0x%08x\n", (int)bytemask); exit(1); } /* * Horrible hack: * * During bootup, the PROM fills memory at 0x40000000 and * forward. This corresponds to the lowest possible RAM address. * However, these fills are not going via the CPU's cache, * which contains things such as the return address on the * stack. If we _really_ write this data in the emulator (which * doesn't emulate the cache), it would overwrite the stack. * * So let's not. * * (If some guest OS or firmware variant actually depends on * the ability to write to the start of memory this way, * it would not work in the emulator.) */ // if (dst0 >= 0x40000000 && dst0 < 0x40004000 && dst1 > 0x40004000) { // dst0 += 0x4000; // dstlen -= 0x4000; // } /* * HUH? * * Note that due to a bug (?) in the PROM firmware when it * is setting up the TLB entries, only every _second_ page is * actually put correctly in the TLB. This means that even * though it then tries to fill 0x40000000 .. 0x40007fff with * zeroes, it only fills 0x40001000 .. 0x40001fff, * 0x40003000 .. 0x40003fff and so on! * * So the Horrible hack above is not needed. * * Ironic. */ memset(zerobuf, bg, dstlen < sizeof(zerobuf) ? dstlen : sizeof(zerobuf)); fill_addr = dst0; while (dstlen != 0) { uint64_t fill_len; if (dstlen > sizeof(zerobuf)) fill_len = sizeof(zerobuf); else fill_len = dstlen; uint64_t starting_page = fill_addr & ~0xfff; uint64_t ending_page = (fill_addr + fill_len - 1) & ~0xfff; if (starting_page != ending_page) { fill_len = starting_page + 4096 - fill_addr; } // Find starting_page in the TLB in question. starting_page >>= 12; uint32_t *tlb = dst_tlb == MTE_TLB_LIN_A ? d->re_linear_a : d->re_linear_b; bool match = false; for (int i = 0; i < 32; ++i) { uint32_t entry = tlb[i]; if (entry & 0x80000000) { entry &= ~0x80000000; if (entry == starting_page) { match = true; break; } } } if (match) { cpu->memory_rw(cpu, cpu->mem, fill_addr, zerobuf, fill_len, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); } else { debug("[ sgi_mte: WARNING: address 0x%x not found in TLB? Ignoring fill. ]\n", (long long)fill_addr); } fill_addr += fill_len; dstlen -= sizeof(zerobuf); } break; default: fatal("[ sgi_mte: TODO! unimplemented dst_tlb 0x%x ]", dst_tlb); } } DEVICE_ACCESS(sgi_mte) { struct sgi_re_data *d = (struct sgi_re_data *) extra; uint64_t idata = 0, odata = 0; int regnr; bool startFlag = relative_addr & CRIME_DE_START ? true : false; relative_addr &= ~CRIME_DE_START; idata = memory_readmax64(cpu, data, len); regnr = relative_addr / sizeof(uint32_t); relative_addr += 0x3000; /* * Treat all registers as read/write, by default. Sometimes these * are accessed as 32-bit words, sometimes as 64-bit words. * * NOTE: The lowest bits are internally stored in the "low" (+0) * register, and the higher bits are stored in the "+1" word. */ if (len == 4) { if (writeflag == MEM_WRITE) d->mte_reg[regnr] = idata; else odata = d->mte_reg[regnr]; } else if (len != 4) { if (writeflag == MEM_WRITE) { d->mte_reg[regnr+1] = idata >> 32; d->mte_reg[regnr] = idata; } else { odata = ((uint64_t)d->mte_reg[regnr+1] << 32) + d->mte_reg[regnr]; } } else { fatal("[ sgi_mte: UNIMPLEMENTED read/write len %i ]\n", len); exit(1); } switch (relative_addr) { case CRIME_MTE_MODE: debug("[ sgi_mte: %s CRIME_MTE_MODE: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_MTE_BYTEMASK: debug("[ sgi_mte: %s CRIME_MTE_BYTEMASK: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_MTE_STIPPLEMASK: fatal("[ sgi_mte: %s CRIME_MTE_STIPPLEMASK: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_MTE_BG: debug("[ sgi_mte: %s CRIME_MTE_BG: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_MTE_SRC0: debug("[ sgi_mte: %s CRIME_MTE_SRC0: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_MTE_SRC1: debug("[ sgi_mte: %s CRIME_MTE_SRC1: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_MTE_DST0: debug("[ sgi_mte: %s CRIME_MTE_DST0: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_MTE_DST1: debug("[ sgi_mte: %s CRIME_MTE_DST1: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_MTE_SRC_Y_STEP: debug("[ sgi_mte: %s CRIME_MTE_SRC_Y_STEP: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_MTE_DST_Y_STEP: debug("[ sgi_mte: %s CRIME_MTE_DST_Y_STEP: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_MTE_NULL: fatal("[ sgi_mte: %s CRIME_MTE_NULL: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; case CRIME_MTE_FLUSH: fatal("[ sgi_mte: %s CRIME_MTE_FLUSH: 0x%016llx ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? (long long)idata : (long long)odata); break; default: if (writeflag == MEM_WRITE) fatal("[ sgi_mte: unimplemented write to " "address 0x%llx, data=0x%016llx ]\n", (long long)relative_addr, (long long)idata); else fatal("[ sgi_mte: unimplemented read from address" " 0x%llx ]\n", (long long)relative_addr); } if (startFlag) do_mte_transfer(cpu, d); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_sgi_mte_init(): */ void dev_sgi_mte_init(struct memory *mem, uint64_t baseaddr, struct sgi_re_data *d) { memory_device_register(mem, "sgi_mte", baseaddr, DEV_SGI_MTE_LENGTH, dev_sgi_mte_access, (void *)d, DM_DEFAULT, NULL); } /****************************************************************************/ /* * SGI "de_status". */ DEVICE_ACCESS(sgi_de_status) { // struct sgi_re_data *d = (struct sgi_re_data *) extra; uint64_t idata = 0, odata = 0; idata = memory_readmax64(cpu, data, len); relative_addr += 0x4000; switch (relative_addr) { case CRIME_DE_STATUS: // 0x4000 odata = CRIME_DE_IDLE | CRIME_DE_SETUP_IDLE | CRIME_DE_PIXPIPE_IDLE | CRIME_DE_MTE_IDLE; /* * TODO: Actually simulate pipeline of a number of commands? */ break; case 0x4008: /* Unknown. Ignore for now. */ break; default: if (writeflag == MEM_WRITE) debug("[ sgi_de_status: unimplemented write to " "address 0x%llx, data=0x%016llx ]\n", (long long)relative_addr, (long long)idata); else debug("[ sgi_de_status: unimplemented read from address" " 0x%llx ]\n", (long long)relative_addr); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_sgi_de_status_init(): */ void dev_sgi_de_status_init(struct memory *mem, uint64_t baseaddr, struct sgi_re_data *d) { memory_device_register(mem, "sgi_de_status", baseaddr, DEV_SGI_DE_STATUS_LENGTH, dev_sgi_de_status_access, (void *)d, DM_DEFAULT, NULL); } gxemul-0.6.1/src/devices/makeautodev.sh000755 001750 001750 00000005770 13402411502 020313 0ustar00debugdebug000000 000000 #!/bin/sh ############################################################################### # # Copyright (C) 2005-2018 Anders Gavare. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. printf "Generating autodev.cc... " rm -f autodev.cc printf "/*\n * DO NOT EDIT. AUTOMATICALLY CREATED\n */\n\n" >> autodev.cc cat autodev_head.cc >> autodev.cc printf "5" rm -f .index for a in *.cc; do B=`grep COMMENT $a` if [ z"$B" != z ]; then printf "$a " >> .index echo "$B"|cut -d : -f 2- >> .index fi done printf "4" for a in dev_*.cc; do B=`grep DEVINIT $a` if [ z"$B" != z ]; then C=`grep DEVINIT $a | cut -d \( -f 2|cut -d \) -f 1` for B in $C; do printf "int devinit_$B(struct devinit *);\n" >> autodev.cc done fi done printf "3" for a in bus_pci.cc; do B=`grep PCIINIT $a` if [ z"$B" != z ]; then C=`grep PCIINIT $a | cut -d \( -f 2|cut -d \) -f 1` for B in $C; do printf "void pciinit_$B(struct machine *, " >> autodev.cc printf "struct memory *, struct pci_device *);\n" >> autodev.cc done fi done cat autodev_middle.cc >> autodev.cc printf "2" for a in dev_*.cc; do B=`grep DEVINIT $a` if [ z"$B" != z ]; then C=`grep DEVINIT $a | cut -d \( -f 2|cut -d \) -f 1` for B in $C; do printf "\tdevice_register(\""$B"\"," >> autodev.cc printf " devinit_$B);\n" >> autodev.cc done fi done printf "1" for a in bus_pci.cc; do B=`grep PCIINIT $a` if [ z"$B" != z ]; then C=`grep PCIINIT $a | cut -d \( -f 2|cut -d \) -f 1` for B in $C; do printf "\tpci_register(\""$B"\"," >> autodev.cc printf " pciinit_$B);\n" >> autodev.cc done fi done cat autodev_tail.cc >> autodev.cc printf " done\n" gxemul-0.6.1/src/devices/dev_lca.cc000644 001750 001750 00000023337 13402411502 017352 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: LCA PCI bus, for Alpha machines */ #include #include #include #include "bus_isa.h" #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "emul.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/alpha_lcareg.h" #define LCA_ISA_BASE (LCA_PCI_SIO + 0x10000000) #define LCA_ISA_MEMBASE (LCA_PCI_SIO + 0x18000000) struct lca_data { struct pci_data *pci_data; uint64_t ioc_conf; uint64_t tlb_enable; uint64_t window_base_0; uint64_t window_mask_0; uint64_t window_t_base_0; uint64_t window_base_1; uint64_t window_mask_1; uint64_t window_t_base_1; }; /* * lca_interrupt_assert(): * * Line 0 = ISA interrupt. */ void lca_interrupt_assert(struct interrupt *interrupt) { fatal("lca_interrupt_assert: TODO\n"); exit(1); } /* * lca_interrupt_deassert(): * * Line 0 = ISA interrupt. */ void lca_interrupt_deassert(struct interrupt *interrupt) { fatal("lca_interrupt_deassert: TODO\n"); exit(1); } DEVICE_ACCESS(lca_pci_conf) { uint64_t idata = 0, odata = 0; int tag, bus, dev, func, reg; struct lca_data *d = (struct lca_data *) extra; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* * 1. Decompose the address into a tag. * * According to NetBSD's lca_pci.c, the address is composed like this: * * addr = tag << 5 | (regoffset & ~0x03) << 5 | 0x3 << 3 */ reg = (relative_addr >> 5) & 0xfc; tag = (relative_addr >> 5) & ~0xff; /* * 2. Decompose the tag into bus, dev, and func. * * The tag can be constructed in one of two ways. On the primary * bus (nr 0): * * tag = (1 << (device + 11)) | (function << 8); * * and on other busses, the tag is a normal: * * tag = (bus << 16) | (device << 11) | (function << 8) */ /* printf("tag = 0x%x\n", (int)tag); */ bus = d->ioc_conf & 1; if (bus == 0) { for (dev=0; dev<21; dev++) if (tag & (0x800 << dev)) break; if (dev >= 21) { /* fatal("[ LCA: No bus 0 device? TODO ]\n"); exit(1); */ dev = 0; } } else { fatal("TODO. Non-zero bus.\n"); exit(1); } func = (tag >> 8) & 7; /* printf("bus=%i dev=%i func=%i reg=%i\n", bus,dev,func,reg); */ /* Pass PCI accesses onto bus_pci: */ bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, reg); bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ? &odata : &idata, len, writeflag); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(lca_isa) { unsigned int ofs, i; uint8_t byte; relative_addr >>= 5; ofs = relative_addr & 3; if (ofs > len) { fatal("[ ofs=%i len=%i in lca_isa access function. " "aborting ]\n", ofs, len); exit(1); } if (writeflag == MEM_WRITE) { byte = data[ofs % len]; return cpu->memory_rw(cpu, cpu->mem, LCA_ISA_BASE + relative_addr, &byte, 1, writeflag, CACHE_NONE); } cpu->memory_rw(cpu, cpu->mem, LCA_ISA_BASE + relative_addr, &byte, 1, MEM_READ, CACHE_NONE); for (i=0; iioc_conf; } else { d->ioc_conf = idata; /* Only bit 0 is implemented so far, the PCI bus 0 vs bus non-0 selection bit. */ if (idata & ~1) { fatal("TODO: Write to unimplemented bit of" " IOC_CONF: 0x%x\n", (int)idata); exit(1); } } break; case LCA_IOC_TBIA: /* TLB Invalidate All. */ /* TODO: For now, let's just ignore it. */ break; case LCA_IOC_TB_ENA: if (writeflag == MEM_READ) { odata = d->tlb_enable; } else { d->tlb_enable = idata; /* TODO: Actually implement this. */ if (idata & ~IOC_TB_ENA_TEN) { fatal("TODO: LCA_IOC_TB_ENA value " " (0x%" PRIx64") has unimplemented " "bits.\n", (uint64_t)idata); exit(1); } } break; case LCA_IOC_W_BASE0: if (writeflag == MEM_READ) { odata = d->window_base_0; } else { d->window_base_0 = idata; /* TODO: Actually implement this. */ if (idata != 0ULL && idata != 0x300800000ULL) { fatal("TODO: LCA_IOC_W_BASE0 value differs" " (0x%" PRIx64") from the only implemented" " values\n", (uint64_t)idata); exit(1); } } break; case LCA_IOC_W_MASK0: if (writeflag == MEM_READ) { odata = d->window_mask_0; } else { d->window_mask_0 = idata; /* TODO: Actually implement this. */ if (idata != 0x700000ULL) { fatal("TODO: LCA_IOC_W_MASK0 value differs" " (0x%" PRIx64") from the only implemented" " value\n", (uint64_t)idata); exit(1); } } break; case LCA_IOC_W_T_BASE0: if (writeflag == MEM_READ) { odata = d->window_t_base_0; } else { d->window_t_base_0 = idata; /* TODO: Actually implement this. */ } break; case LCA_IOC_W_BASE1: if (writeflag == MEM_READ) { odata = d->window_base_1; } else { d->window_base_1 = idata; /* TODO: Actually implement this. */ if (idata != 0x240000000ULL) { fatal("TODO: LCA_IOC_W_BASE1 value differs" " (0x%" PRIx64") from the only implemented" " value\n", (uint64_t)idata); exit(1); } } break; case LCA_IOC_W_MASK1: if (writeflag == MEM_READ) { odata = d->window_mask_1; } else { d->window_mask_1 = idata; /* TODO: Actually implement this. */ if (idata != 0x3ff00000ULL) { fatal("TODO: LCA_IOC_W_MASK1 value differs" " (0x%" PRIx64") from the only implemented" " value\n", (uint64_t)idata); exit(1); } } break; case LCA_IOC_W_T_BASE1: if (writeflag == MEM_READ) { odata = d->window_t_base_1; } else { d->window_t_base_1 = idata; /* TODO: Actually implement this. */ } break; default:fatal("[ lca_ioc: unimplemented %s to offset 0x%x", writeflag == MEM_WRITE? "write" : "read", (int) relative_addr); if (writeflag == MEM_WRITE) fatal(": 0x%x", (int)idata); fatal(" ]\n"); exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(lca) { char *interrupt_path; struct interrupt interrupt_template; struct lca_data *d; CHECK_ALLOCATION(d = (struct lca_data *) malloc(sizeof(struct lca_data))); memset(d, 0, sizeof(struct lca_data)); /* Register a PCI bus: */ d->pci_data = bus_pci_init( devinit->machine, "TODO: irq" /* pciirq: TODO */, LCA_PCI_SIO, /* pci device io offset */ 0x00000000, /* pci device mem offset: TODO */ 0x00000000, /* PCI portbase: TODO */ 0x00000000, /* PCI membase: TODO */ "TODO: pci irq base", /* PCI irqbase: TODO */ LCA_ISA_BASE, /* ISA portbase */ LCA_ISA_MEMBASE, /* ISA membase */ "TODO: irqbase isa"); /* ISA irqbase: TODO */ /* Add the "sio0" controller (as seen by NetBSD): */ bus_pci_add(devinit->machine, d->pci_data, devinit->machine->memory, 0, 7, 0, "i82378zb"); memory_device_register(devinit->machine->memory, "lca_pci_conf", LCA_PCI_CONF, 0x20000000, dev_lca_pci_conf_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, "lca_isa", LCA_PCI_SIO, 0x10000 << 5, dev_lca_isa_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, "lca_ioc", LCA_IOC_BASE, 0x20000000, dev_lca_ioc_access, (void *)d, DM_DEFAULT, NULL); CHECK_ALLOCATION(interrupt_path = (char *) malloc(strlen(devinit->machine->path) + 10)); snprintf(interrupt_path, strlen(devinit->machine->path) + 10, "%s.lca", devinit->machine->path); memset(&interrupt_template, 0, sizeof(interrupt_template)); interrupt_template.line = 0; interrupt_template.name = interrupt_path; interrupt_template.extra = d; interrupt_template.interrupt_assert = lca_interrupt_assert; interrupt_template.interrupt_deassert = lca_interrupt_deassert; interrupt_handler_register(&interrupt_template); bus_isa_init(devinit->machine, interrupt_path, BUS_ISA_IDE0 | BUS_ISA_IDE1, LCA_ISA_BASE, LCA_ISA_MEMBASE); return 1; } gxemul-0.6.1/src/devices/dev_bt455.cc000644 001750 001750 00000012414 13402411502 017450 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Brooktree BT455, used by TURBOchannel graphics cards * * TODO: This is hardcoded to only use 16 grayscales, using only the * green component of the palette. Perhaps some other graphics card uses * the BT455 as well; if so then this device must be re-hacked. */ #include #include #include #include "devices.h" #include "memory.h" #include "misc.h" struct bt455_data { unsigned char addr_cmap; unsigned char addr_cmap_data; unsigned char addr_clr; unsigned char addr_ovly; int cur_rgb_offset; struct vfb_data *vfb_data; unsigned char *rgb_palette; /* ptr to 256 * 3 (r,g,b) */ }; DEVICE_ACCESS(bt455) { struct bt455_data *d = (struct bt455_data *) extra; uint64_t idata = 0, odata = 0; int i, modified; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* Read from/write to the bt455: */ switch (relative_addr) { case 0x00: /* addr_cmap */ if (writeflag == MEM_WRITE) { debug("[ bt455: write to addr_cmap, 0x%02x ]\n", idata); d->addr_cmap = idata; d->cur_rgb_offset = (d->addr_cmap & 0xf) * 3; } else { odata = d->addr_cmap; debug("[ bt455: read from addr_cmap: 0x%0x ]\n", odata); } break; case 0x04: /* addr_cmap_data */ if (writeflag == MEM_WRITE) { debug("[ bt455: write to addr_cmap_data, 0x%02x ]\n", (int)idata); d->addr_cmap_data = idata; modified = 0; /* Only write on updates to the Green value: */ if ((d->cur_rgb_offset % 3) == 1) { /* Update 16 copies: */ for (i=0; i<16; i++) { int addr = (d->cur_rgb_offset + 16*i) % 0x300; int newvalue = idata * 0x11; if (d->rgb_palette[(addr / 3) * 3 + 0] != newvalue || d->rgb_palette[(addr / 3) * 3 + 1] != newvalue || d->rgb_palette[(addr / 3) * 3 + 2] != newvalue) modified = 1; d->rgb_palette[(addr / 3) * 3 + 0] = d->rgb_palette[(addr / 3) * 3 + 1] = d->rgb_palette[(addr / 3) * 3 + 2] = newvalue; } } if (modified) { d->vfb_data->update_x1 = 0; d->vfb_data->update_x2 = d->vfb_data->xsize - 1; d->vfb_data->update_y1 = 0; d->vfb_data->update_y2 = d->vfb_data->ysize - 1; } /* Advance to next palette byte: */ d->cur_rgb_offset ++; } else { odata = d->addr_cmap_data; debug("[ bt455: read from addr_cmap_data: 0x%0x ]\n", (int)odata); } break; case 0x08: /* addr_clr */ if (writeflag == MEM_WRITE) { debug("[ bt455: write to addr_clr, value 0x%02x ]\n", (int)idata); d->addr_clr = idata; } else { odata = d->addr_clr; debug("[ bt455: read from addr_clr: value 0x%02x ]\n", (int)odata); } break; case 0x0c: /* addr_ovly */ if (writeflag == MEM_WRITE) { debug("[ bt455: write to addr_ovly, value 0x%02x ]\n", (int)idata); d->addr_ovly = idata; } else { odata = d->addr_ovly; debug("[ bt455: read from addr_ovly: value 0x%02x ]\n", (int)odata); } break; default: if (writeflag == MEM_WRITE) { debug("[ bt455: unimplemented write to address 0x%x," " data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { debug("[ bt455: unimplemented read from address " "0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_bt455_init(): */ void dev_bt455_init(struct memory *mem, uint64_t baseaddr, struct vfb_data *vfb_data) { struct bt455_data *d; CHECK_ALLOCATION(d = (struct bt455_data *) malloc(sizeof(struct bt455_data))); memset(d, 0, sizeof(struct bt455_data)); d->vfb_data = vfb_data; d->rgb_palette = vfb_data->rgb_palette; memory_device_register(mem, "bt455", baseaddr, DEV_BT455_LENGTH, dev_bt455_access, (void *)d, DM_DEFAULT, NULL); } gxemul-0.6.1/src/devices/dev_dc7085.cc000644 001750 001750 00000021077 13402411502 017524 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: DC7085 serial controller, used in some DECstation models */ #include #include #include #include "console.h" #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/dc7085.h" #define DC_TICK_SHIFT 14 #define MAX_QUEUE_LEN 32768 struct dc_data { struct dc7085regs regs; int console_handle; /* For slow_serial_interrupts_hack_for_linux: */ int just_transmitted_something; unsigned char rx_queue_char[MAX_QUEUE_LEN]; char rx_queue_lineno[MAX_QUEUE_LEN]; int cur_rx_queue_pos_write; int cur_rx_queue_pos_read; int tx_scanner; struct interrupt irq; int use_fb; struct lk201_data lk201; }; /* * Add a character to the receive queue. */ void add_to_rx_queue(void *e, int ch, int line_no) { struct dc_data *d = (struct dc_data *) e; int entries_in_use = d->cur_rx_queue_pos_write - d->cur_rx_queue_pos_read; while (entries_in_use < 0) entries_in_use += MAX_QUEUE_LEN; /* Ignore mouse updates, if they come too often: */ if (entries_in_use > MAX_QUEUE_LEN/2 && line_no == DCMOUSE_PORT) return; d->rx_queue_char[d->cur_rx_queue_pos_write] = ch; d->rx_queue_lineno[d->cur_rx_queue_pos_write] = line_no; d->cur_rx_queue_pos_write ++; if (d->cur_rx_queue_pos_write == MAX_QUEUE_LEN) d->cur_rx_queue_pos_write = 0; if (d->cur_rx_queue_pos_write == d->cur_rx_queue_pos_read) fatal("warning: add_to_rx_queue(): rx_queue overrun!\n"); } DEVICE_TICK(dc7085) { /* * If a key is available from the keyboard, add it to the rx queue. * If other bits are set, an interrupt might need to be caused. */ struct dc_data *d = (struct dc_data *) extra; int avail; if (cpu->machine->slow_serial_interrupts_hack_for_linux) { /* * Special hack to prevent Linux from Oopsing. (This makes * interrupts not come as fast as possible.) */ if (d->just_transmitted_something) { d->just_transmitted_something --; return; } } d->regs.dc_csr &= ~CSR_RDONE; if ((d->regs.dc_csr & CSR_MSE) && !(d->regs.dc_csr & CSR_TRDY)) { int scanner_start = d->tx_scanner; /* Loop until we've checked all 4 channels, or some channel was ready to transmit: */ do { d->tx_scanner = (d->tx_scanner + 1) % 4; if (d->regs.dc_tcr & (1 << d->tx_scanner)) { d->regs.dc_csr |= CSR_TRDY; if (d->regs.dc_csr & CSR_TIE) INTERRUPT_ASSERT(d->irq); d->regs.dc_csr &= ~CSR_TX_LINE_NUM; d->regs.dc_csr |= (d->tx_scanner << 8); } } while (!(d->regs.dc_csr & CSR_TRDY) && d->tx_scanner != scanner_start); /* We have to return here. NetBSD can handle both rx and tx interrupts simultaneously, but Ultrix doesn't like that? */ if (d->regs.dc_csr & CSR_TRDY) return; } lk201_tick(cpu->machine, &d->lk201); avail = d->cur_rx_queue_pos_write != d->cur_rx_queue_pos_read; if (avail && (d->regs.dc_csr & CSR_MSE)) d->regs.dc_csr |= CSR_RDONE; if ((d->regs.dc_csr & CSR_RDONE) && (d->regs.dc_csr & CSR_RIE)) INTERRUPT_ASSERT(d->irq); } DEVICE_ACCESS(dc7085) { struct dc_data *d = (struct dc_data *) extra; uint64_t idata = 0, odata = 0; size_t i; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* Always clear: */ d->regs.dc_csr &= ~CSR_CLR; switch (relative_addr) { case 0x00: /* CSR: Control and Status */ if (writeflag == MEM_WRITE) { debug("[ dc7085 write to CSR: 0x%04x ]\n", idata); idata &= (CSR_TIE | CSR_RIE | CSR_MSE | CSR_CLR | CSR_MAINT); d->regs.dc_csr &= ~(CSR_TIE | CSR_RIE | CSR_MSE | CSR_CLR | CSR_MAINT); d->regs.dc_csr |= idata; if (!(d->regs.dc_csr & CSR_MSE)) d->regs.dc_csr &= ~(CSR_TRDY | CSR_RDONE); goto do_return; } else { /* read: */ /* fatal("[ dc7085 read from CSR: (csr = 0x%04x) ]\n", d->regs.dc_csr); */ odata = d->regs.dc_csr; } break; case 0x08: /* LPR: */ if (writeflag == MEM_WRITE) { debug("[ dc7085 write to LPR: 0x%04x ]\n", idata); d->regs.dc_rbuf_lpr = idata; goto do_return; } else { /* read: */ int avail = d->cur_rx_queue_pos_write != d->cur_rx_queue_pos_read; int ch = 0, lineno = 0; /* debug("[ dc7085 read from RBUF: "); */ if (avail) { ch = d->rx_queue_char[d->cur_rx_queue_pos_read]; lineno = d->rx_queue_lineno[ d->cur_rx_queue_pos_read]; d->cur_rx_queue_pos_read++; if (d->cur_rx_queue_pos_read == MAX_QUEUE_LEN) d->cur_rx_queue_pos_read = 0; /* if (ch >= ' ' && ch < 127) debug("'%c'", ch); else debug("0x%x", ch); debug(" for lineno %i ", lineno); */ } /* else debug("empty "); debug("]\n"); */ odata = (avail? RBUF_DVAL:0) | (lineno << RBUF_LINE_NUM_SHIFT) | ch; d->regs.dc_csr &= ~CSR_RDONE; INTERRUPT_DEASSERT(d->irq); d->just_transmitted_something = 4; } break; case 0x10: /* TCR: */ if (writeflag == MEM_WRITE) { /* fatal("[ dc7085 write to TCR: 0x%04x) ]\n", (int)idata); */ d->regs.dc_tcr = idata; d->regs.dc_csr &= ~CSR_TRDY; INTERRUPT_DEASSERT(d->irq); goto do_return; } else { /* read: */ /* debug("[ dc7085 read from TCR: (tcr = 0x%04x) ]\n", d->regs.dc_tcr); */ odata = d->regs.dc_tcr; } break; case 0x18: /* Modem status (R), transmit data (W) */ if (writeflag == MEM_WRITE) { int line_no = (d->regs.dc_csr >> RBUF_LINE_NUM_SHIFT) & 0x3; idata &= 0xff; lk201_tx_data(&d->lk201, line_no, idata); d->regs.dc_csr &= ~CSR_TRDY; INTERRUPT_DEASSERT(d->irq); d->just_transmitted_something = 4; } else { /* read: */ d->regs.dc_msr_tdr |= MSR_DSR2 | MSR_CD2 | MSR_DSR3 | MSR_CD3; debug("[ dc7085 read from MSR: (msr_tdr = 0x%04x) ]\n", d->regs.dc_msr_tdr); odata = d->regs.dc_msr_tdr; } break; default: if (writeflag==MEM_READ) { debug("[ dc7085 read from 0x%08lx ]\n", (long)relative_addr); } else { debug("[ dc7085 write to 0x%08lx:", (long)relative_addr); for (i=0; iirq); d->use_fb = use_fb; d->regs.dc_csr = CSR_TRDY | CSR_MSE; d->regs.dc_tcr = 0x00; d->console_handle = console_start_slave(machine, "DC7085", 1); lk201_init(&d->lk201, use_fb, add_to_rx_queue, d->console_handle, d); memory_device_register(mem, "dc7085", baseaddr, DEV_DC7085_LENGTH, dev_dc7085_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(machine, dev_dc7085_tick, d, DC_TICK_SHIFT); return d->console_handle; } gxemul-0.6.1/src/devices/dev_igsfb.cc000644 001750 001750 00000026052 13402411502 017702 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Integraphics Systems "igsfb" Framebuffer graphics card * * Used in at least the NetWinder. * * TODO: This is hardcoded to 1024x768x8 right now, and only supports the * two acceleration commands used by NetBSD for scrolling the * framebuffer. The cursor is hardcoded to 12x22 pixels, as that is * what NetBSD/netwinder uses. */ #include #include #include #include "console.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "../include/vga.h" #include "thirdparty/igsfbreg.h" struct dev_igsfb_data { int xres; int yres; int bitdepth; struct vfb_data *vfb_data; /* VGA palette stuff: */ int palette_write_index; int palette_write_subindex; /* * Various graphics controller registers. See igsfbreg.h for a * brief explanation of what these do. */ int src_map_width; int src2_map_width; int dst_map_width; int src_start; int src2_start; int dst_start; int map_fmt; int ctl; int fg_mix; int bg_mix; int width; int height; int fg; int bg; int pixel_op_0; int pixel_op_1; int pixel_op_2; int pixel_op_3; uint8_t ext_reg_select; uint8_t ext_reg[256]; }; /* * recalc_sprite_position(): * * TODO: This is hardcoded for NetBSD/netwinder's 12x22 pixel cursor. */ static void recalc_sprite_position(struct dev_igsfb_data *d) { int x = d->ext_reg[IGS_EXT_SPRITE_HSTART_LO] + d->ext_reg[IGS_EXT_SPRITE_HSTART_HI] * 256; int y = d->ext_reg[IGS_EXT_SPRITE_VSTART_LO] + d->ext_reg[IGS_EXT_SPRITE_VSTART_HI] * 256; dev_fb_setcursor(d->vfb_data, x, y, 1, 12, 22); } /* * dev_igsfb_op3_written(): * * This function is called after the pixel_op_3 register has been written to. * I guess this is what triggers accelerated functions to start executing. * * NOTE/TODO: Only those necessary to run NetBSD/netwinder have been * implemented. */ static void dev_igsfb_op3_written(struct dev_igsfb_data *d) { if (d->pixel_op_0 == 0x00 && d->pixel_op_1 == 0x80 && d->pixel_op_2 == 0x00 && d->pixel_op_3 == 0x28 && d->fg_mix == 0x03 && d->ctl == 0x00) { /* NetBSD scroll-up */ framebuffer_blockcopyfill(d->vfb_data, 0, 0,0,0, d->dst_start % d->xres, d->dst_start / d->xres, d->dst_start % d->xres + d->width, d->dst_start / d->xres + d->height, d->src_start % d->xres, d->src_start / d->xres); return; } if (d->pixel_op_0 == 0x00 && d->pixel_op_1 == 0x80 && d->pixel_op_2 == 0x00 && d->pixel_op_3 == 0x08 && d->fg_mix == 0x03 && d->ctl == 0x00) { /* NetBSD fill */ /* TODO: Color! */ framebuffer_blockcopyfill(d->vfb_data, 1, 0,0,0, d->dst_start % d->xres, d->dst_start / d->xres, d->dst_start % d->xres + d->width, d->dst_start / d->xres + d->height, 0, 0); return; } fatal("\nUnimplemented igsfb accelerated framebuffer command:\n"); fatal("pixel_op_0 = 0x%02x\n", d->pixel_op_0); fatal("pixel_op_1 = 0x%02x\n", d->pixel_op_1); fatal("pixel_op_2 = 0x%02x\n", d->pixel_op_2); fatal("pixel_op_3 = 0x%02x\n", d->pixel_op_3); fatal("fg_mix = 0x%02x\n", d->fg_mix); fatal("ctl = 0x%02x\n", d->ctl); fatal("src_start = 0x%x\n", d->src_start); fatal("dst_start = 0x%x\n", d->dst_start); fatal("width = %i\n", d->width); fatal("height = %i\n", d->height); exit(1); } DEVICE_ACCESS(igsfb) { struct dev_igsfb_data *d = (struct dev_igsfb_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (relative_addr >= 0x3c0 && relative_addr <= 0x3df) { switch (relative_addr - 0x3c0) { case VGA_DAC_ADDR_WRITE: /* 0x08 */ if (writeflag == MEM_WRITE) { d->palette_write_index = idata; d->palette_write_subindex = 0; } else { fatal("[ igsdb: WARNING: Read from " "VGA_DAC_ADDR_WRITE? ]\n"); odata = d->palette_write_index; } break; case VGA_DAC_DATA: /* 0x09 */ if (writeflag == MEM_WRITE) { /* Note: 8-bit color, not 6, so it isn't exactly like normal VGA palette: */ int new_ = idata & 0xff; int old = d->vfb_data->rgb_palette[d-> palette_write_index*3+d-> palette_write_subindex]; d->vfb_data->rgb_palette[d->palette_write_index * 3 + d->palette_write_subindex] = new_; /* Redraw whole screen, if the palette changed: */ if (new_ != old) { d->vfb_data->update_x1 = d->vfb_data->update_y1 = 0; d->vfb_data->update_x2 = d->xres - 1; d->vfb_data->update_y2 = d->yres - 1; } d->palette_write_subindex ++; if (d->palette_write_subindex == 3) { d->palette_write_index ++; d->palette_write_subindex = 0; } } /* Note/TODO: Reading from the palette isn't implemented here. */ break; case 0xe: /* IGSFB extended register select */ if (writeflag == MEM_WRITE) d->ext_reg_select = idata; else odata = d->ext_reg_select; break; case 0xf: /* IGSFB extended register data */ if (writeflag == MEM_READ) odata = d->ext_reg[d->ext_reg_select]; else { d->ext_reg[d->ext_reg_select] = idata; switch (d->ext_reg_select) { /* case IGS_EXT_SPRITE_HSTART_LO: case IGS_EXT_SPRITE_HSTART_HI: case IGS_EXT_SPRITE_VSTART_LO: */ case IGS_EXT_SPRITE_VSTART_HI: recalc_sprite_position(d); break; } } break; } return 1; } if (relative_addr >= IGS_COP_BASE_A && relative_addr < IGS_COP_BASE_A + IGS_COP_SIZE) { fatal("[ igsfb: BASE A not implemented yet, only BASE B ]\n"); exit(1); } switch (relative_addr) { case IGS_VDO: if (writeflag == MEM_WRITE) { if (idata & ~(IGS_VDO_ENABLE | IGS_VDO_SETUP)) { fatal("[ igsfb: Unimplemented IGS_VDO flags:" " 0x%08x ]\n", (int)idata); exit(1); } } break; case IGS_VSE: if (writeflag == MEM_WRITE) { if (idata & ~(IGS_VSE_ENABLE)) { fatal("[ igsfb: Unimplemented IGS_VSE flags:" " 0x%08x ]\n", (int)idata); exit(1); } } break; case IGS_COP_BASE_B + IGS_COP_SRC_MAP_WIDTH_REG: if (writeflag == MEM_WRITE) d->src_map_width = idata & 0x3ff; else odata = d->src_map_width; break; case IGS_COP_BASE_B + IGS_COP_SRC2_MAP_WIDTH_REG: if (writeflag == MEM_WRITE) d->src2_map_width = idata & 0x3ff; else odata = d->src2_map_width; break; case IGS_COP_BASE_B + IGS_COP_DST_MAP_WIDTH_REG: if (writeflag == MEM_WRITE) d->dst_map_width = idata & 0x3ff; else odata = d->dst_map_width; break; case IGS_COP_BASE_B + IGS_COP_MAP_FMT_REG: if (writeflag == MEM_WRITE) d->map_fmt = idata; else odata = d->map_fmt; break; case IGS_COP_BASE_B + IGS_COP_CTL_REG: if (writeflag == MEM_WRITE) d->ctl = idata; else odata = d->ctl; break; case IGS_COP_BASE_B + IGS_COP_FG_MIX_REG: if (writeflag == MEM_WRITE) d->fg_mix = idata; else odata = d->fg_mix; break; case IGS_COP_BASE_B + IGS_COP_BG_MIX_REG: if (writeflag == MEM_WRITE) d->bg_mix = idata; else odata = d->bg_mix; break; case IGS_COP_BASE_B + IGS_COP_WIDTH_REG: if (writeflag == MEM_WRITE) d->width = idata & 0x3ff; else odata = d->width; break; case IGS_COP_BASE_B + IGS_COP_HEIGHT_REG: if (writeflag == MEM_WRITE) d->height = idata & 0x3ff; else odata = d->height; break; case IGS_COP_BASE_B + IGS_COP_SRC_START_REG: if (writeflag == MEM_WRITE) d->src_start = idata & 0x3fffff; else odata = d->src_start; break; case IGS_COP_BASE_B + IGS_COP_SRC2_START_REG: if (writeflag == MEM_WRITE) d->src2_start = idata & 0x3fffff; else odata = d->src2_start; break; case IGS_COP_BASE_B + IGS_COP_DST_START_REG: if (writeflag == MEM_WRITE) d->dst_start = idata & 0x3fffff; else odata = d->dst_start; break; case IGS_COP_BASE_B + IGS_COP_FG_REG: if (writeflag == MEM_WRITE) d->fg = idata; else odata = d->fg; break; case IGS_COP_BASE_B + IGS_COP_BG_REG: if (writeflag == MEM_WRITE) d->bg = idata; else odata = d->bg; break; case IGS_COP_BASE_B + IGS_COP_PIXEL_OP_0_REG: if (writeflag == MEM_WRITE) d->pixel_op_0 = idata; else odata = d->pixel_op_0; break; case IGS_COP_BASE_B + IGS_COP_PIXEL_OP_1_REG: if (writeflag == MEM_WRITE) d->pixel_op_1 = idata; else odata = d->pixel_op_1; break; case IGS_COP_BASE_B + IGS_COP_PIXEL_OP_2_REG: if (writeflag == MEM_WRITE) d->pixel_op_2 = idata; else odata = d->pixel_op_2; break; case IGS_COP_BASE_B + IGS_COP_PIXEL_OP_3_REG: if (writeflag == MEM_WRITE) { d->pixel_op_3 = idata; dev_igsfb_op3_written(d); } else { odata = d->pixel_op_3; } break; default:if (writeflag == MEM_WRITE) { fatal("[ igsfb: unimplemented write to address 0x%x" " data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { fatal("[ igsfb: unimplemented read from address 0x%x " "]\n", (int)relative_addr); } exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(igsfb) { struct dev_igsfb_data *d; CHECK_ALLOCATION(d = (struct dev_igsfb_data *) malloc(sizeof(struct dev_igsfb_data))); memset(d, 0, sizeof(struct dev_igsfb_data)); d->xres = 1024; d->yres = 768; d->bitdepth = 8; d->vfb_data = dev_fb_init(devinit->machine, devinit->machine->memory, 0x400000 + devinit->addr, VFB_GENERIC, d->xres, d->yres, d->xres, d->yres, d->bitdepth, "igsfb"); /* TODO: Palette control etc at 0x3c0 + IGS_MEM_MMIO_SELECT */ memory_device_register(devinit->machine->memory, devinit->name, devinit->addr + IGS_MEM_MMIO_SELECT, 0x100000, dev_igsfb_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/README000644 001750 001750 00000001203 13402411502 016312 0ustar00debugdebug000000 000000 $Id: README,v 1.7 2006-02-09 22:40:27 debug Exp $ dev_*: Devices. (Please read 'Emulation of hardware devices' in doc/technical.html for more information about these.) Example: dev_wdc, the IDE/ATA[PI] harddisk controller. bus_isa.c: ISA bus framework. This basically just registers the ISA legacy devices that are common to all machines. bus_pci.c: PCI bus framework, and some glue code for PCI devices. Example of glue code would be PCI-IDE controllers, which are implemented using dev_wdc plus some PCI configuration registers, which identifies the specific controller (fake, but it usually works). other files: Misc. stuff. gxemul-0.6.1/src/devices/dev_mp.cc000644 001750 001750 00000017607 13402411502 017232 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Generic Multi-processor controller for the test machines * * This is a fake multiprocessor (MP) device. It can be useful for * theoretical experiments, but probably bares no resemblance to any * multiprocessor controller used in any real machine. * * NOTE: The devinit irq string should be the part _after_ "cpu[%i].". * For MIPS, it will be MIPS_IPI_INT. */ #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "interrupt.h" #include "memory.h" #include "misc.h" #include "testmachine/dev_mp.h" struct mp_data { struct cpu **cpus; uint64_t startup_addr; uint64_t stack_addr; uint64_t pause_addr; /* Each CPU has an array of pending ipis. */ int *n_pending_ipis; int **ipi; /* Connections to all CPUs' IPI pins: */ struct interrupt *ipi_irq; }; extern int single_step; DEVICE_ACCESS(mp) { struct mp_data *d = (struct mp_data *) extra; int i, which_cpu; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* * NOTE: It is up to the user of this device to read or write * correct addresses. (A write to NCPUS is pretty useless, * for example.) */ switch (relative_addr) { case DEV_MP_WHOAMI: odata = cpu->cpu_id; break; case DEV_MP_NCPUS: odata = cpu->machine->ncpus; break; case DEV_MP_STARTUPCPU: which_cpu = idata; d->cpus[which_cpu]->pc = d->startup_addr; switch (cpu->machine->arch) { case ARCH_MIPS: d->cpus[which_cpu]->cd.mips.gpr[MIPS_GPR_SP] = d->stack_addr; break; case ARCH_PPC: d->cpus[which_cpu]->cd.ppc.gpr[1] = d->stack_addr; break; default: fatal("dev_mp(): DEV_MP_STARTUPCPU: not for this" " arch yet!\n"); exit(1); } d->cpus[which_cpu]->running = 1; /* debug("[ dev_mp: starting up cpu%i at 0x%llx ]\n", which_cpu, (long long)d->startup_addr); */ break; case DEV_MP_STARTUPADDR: if (len==4 && (idata >> 32) == 0 && (idata & 0x80000000ULL)) idata |= 0xffffffff00000000ULL; d->startup_addr = idata; break; case DEV_MP_PAUSE_ADDR: d->pause_addr = idata; break; case DEV_MP_PAUSE_CPU: /* Pause all cpus except a specific CPU: */ which_cpu = idata; for (i=0; imachine->ncpus; i++) if (i != which_cpu) d->cpus[i]->running = 0; break; case DEV_MP_UNPAUSE_CPU: /* Unpause a specific CPU: */ which_cpu = idata; if (which_cpu >= 0 && which_cpu machine->ncpus) d->cpus[which_cpu]->running = 1; break; case DEV_MP_STARTUPSTACK: if (len == 4 && (idata >> 32) == 0 && (idata & 0x80000000ULL)) idata |= 0xffffffff00000000ULL; d->stack_addr = idata; break; case DEV_MP_HARDWARE_RANDOM: /* * Return (up to) 64 bits of "hardware random": * * NOTE: Remember that random() is (usually) 31 bits of * random data, _NOT_ 32, hence this construction. */ odata = random(); odata = (odata << 31) ^ random(); odata = (odata << 31) ^ random(); break; case DEV_MP_MEMORY: /* * Return the number of bytes of memory in the system. * * (It is assumed to be located at physical address 0. * It is actually located at machine->memory_offset_in_mb * but that is only used for SGI emulation so far.) */ odata = cpu->machine->physical_ram_in_mb * 1048576ULL; break; case DEV_MP_IPI_ONE: case DEV_MP_IPI_MANY: /* * idata should be of the form: * * (IPI_nr << 16) | cpu_id * * This will send an Inter-processor interrupt to a specific * CPU. (DEV_MP_IPI_MANY sends to all _except_ the specific * CPU.) * * Sending an IPI means adding the IPI last in the list of * pending IPIs, and asserting the IPI "pin". */ which_cpu = (idata & 0xffff); for (i=0; imachine->ncpus; i++) { int send_it = 0; if (relative_addr == DEV_MP_IPI_ONE && i == which_cpu) send_it = 1; if (relative_addr == DEV_MP_IPI_MANY && i != which_cpu) send_it = 1; if (send_it) { d->n_pending_ipis[i] ++; CHECK_ALLOCATION(d->ipi[i] = (int *) realloc(d->ipi[i], d->n_pending_ipis[i] * sizeof(int))); /* Add the IPI last in the array: */ d->ipi[i][d->n_pending_ipis[i] - 1] = idata >> 16; INTERRUPT_ASSERT(d->ipi_irq[i]); } } break; case DEV_MP_IPI_READ: /* * If the current CPU has any IPIs pending, accessing this * address reads the IPI value. (Writing to this address * discards _all_ pending IPIs.) If there is no pending * IPI, then 0 is returned. Usage of the value 0 for real * IPIs should thus be avoided. */ if (writeflag == MEM_WRITE) { d->n_pending_ipis[cpu->cpu_id] = 0; } odata = 0; if (d->n_pending_ipis[cpu->cpu_id] > 0) { odata = d->ipi[cpu->cpu_id][0]; if (d->n_pending_ipis[cpu->cpu_id]-- > 1) memmove(&d->ipi[cpu->cpu_id][0], &d->ipi[cpu->cpu_id][1], d->n_pending_ipis[cpu->cpu_id]); } /* Deassert the interrupt, if there are no pending IPIs: */ if (d->n_pending_ipis[cpu->cpu_id] == 0) INTERRUPT_DEASSERT(d->ipi_irq[cpu->cpu_id]); break; case DEV_MP_NCYCLES: /* * Return _approximately_ the number of cycles executed * on this CPU. * * (This value is not updated for each instruction.) */ odata = cpu->ninstrs; break; default: fatal("[ dev_mp: unimplemented relative addr 0x%x ]\n", relative_addr); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(mp) { struct mp_data *d; int n, i; CHECK_ALLOCATION(d = (struct mp_data *) malloc(sizeof(struct mp_data))); memset(d, 0, sizeof(struct mp_data)); d->cpus = devinit->machine->cpus; d->startup_addr = INITIAL_PC; d->stack_addr = INITIAL_STACK_POINTER; n = devinit->machine->ncpus; /* Connect to all CPUs' IPI pins: */ CHECK_ALLOCATION(d->ipi_irq = (struct interrupt *) malloc(n * sizeof(struct interrupt))); for (i=0; imachine->path, i, devinit->interrupt_path); INTERRUPT_CONNECT(tmpstr, d->ipi_irq[i]); } CHECK_ALLOCATION(d->n_pending_ipis = (int *) malloc(n * sizeof(int))); memset(d->n_pending_ipis, 0, sizeof(int) * n); CHECK_ALLOCATION(d->ipi = (int **) malloc(n * sizeof(int *))); memset(d->ipi, 0, sizeof(int *) * n); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_MP_LENGTH, dev_mp_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_pvr.cc000644 001750 001750 00000212411 13402411502 017413 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: PowerVR CLX2 (graphics controller used in the Dreamcast) * * Implemented by reading http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt and * http://mc.pp.se/dc/pvr.html, source code of various demos and KallistiOS, * attempting to run the PROM from my own Dreamcast, and doing a lot of * guessing. * * TODO: Almost everything * * x) Change resolution during runtime (PAL/NTSC/???) * * x) Lots of work on the 3D "Tile Accelerator" engine. * Recognize commands and turn into OpenGL or similar * commands on the host? * Wire-frame when running on a host without XGL? * * Multiple lists of various kinds (6?). * Lists growing downwards! * Pixel clip for rendering. * Real Rendering, using OpenGL if possible. * Tile bins... with 6 pointers for each tile (?) * PVR DMA. * Textures. * ... */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "float_emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "timer.h" #include "thirdparty/dreamcast_pvr.h" #include "thirdparty/dreamcast_sysasicvar.h" /* For debugging: */ //#define DEBUG_RENDER_AS_WIRE_FRAME // Renders 3-corner textured polygons as wire-frame //#define TA_DEBUG // Dumps TA commands //#define debug fatal // Dumps debug even without -v. #define INTERNAL_FB_ADDR 0x300000000ULL #define PVR_FB_TICK_SHIFT 18 #define PVR_VBLANK_HZ 60.0 #define PVR_MARGIN 16 #define VRAM_SIZE (8*1048576) /* DMA: */ #define PVR_DMA_MEMLENGTH 0x100 #define N_PVR_DMA_REGS (PVR_DMA_MEMLENGTH / sizeof(uint32_t)) #define PVR_ADDR 0x00 #define PVR_COUNT 0x04 #define PVR_MODE 0x08 #define PVR_LMMODE0 0x84 #define PVR_LMMODE1 0x88 struct pvr_data { struct vfb_data *fb; int fb_update_x1; int fb_update_y1; int fb_update_x2; int fb_update_y2; struct timer *vblank_timer; int vblank_interrupts_pending; /* PVR registers: */ uint32_t reg[PVRREG_REGSIZE / sizeof(uint32_t)]; /* Calculated by pvr_geometry_updated(): */ int xsize, ysize; int bytes_per_pixel; /* Cached values (from registers): */ /* DIWMODE: */ int clock_double; int strip_buffer_enabled; int strip_length; int argb8888_threshold; int extend; int pixelmode; int line_double; int display_enabled; /* BRDCOLR: */ int border_updated; /* SYNCCONF: */ int video_enabled; int broadcast_standard; int interlaced; int h_sync_positive; int v_sync_positive; /* TILEBUF_SIZE: */ int tilebuf_xsize; int tilebuf_ysize; /* Current Tile Accelerator Command (64 bytes): */ uint32_t ta[64 / sizeof(uint32_t)]; /* Stored list of TA commands: */ int current_list_type; uint32_t *ta_commands; size_t allocated_ta_commands; size_t n_ta_commands; /* Video RAM and Z information: */ uint8_t *vram; double *vram_z; /* DMA registers: */ uint32_t dma_reg[N_PVR_DMA_REGS]; uint32_t dma_more_reg[N_PVR_DMA_REGS]; }; struct pvr_data_alt { struct pvr_data *d; }; #define REG(x) (d->reg[(x)/sizeof(uint32_t)]) #define DEFAULT_WRITE REG(relative_addr) = idata; /* Forward declaration. */ DEVICE_ACCESS(pvr_ta); void pvr_dma_transfer(struct cpu *cpu, struct pvr_data *d) { const int channel = 2; uint32_t sar = cpu->cd.sh.dmac_sar[channel] & 0x1fffffff; uint32_t dar = cpu->cd.sh.dmac_dar[channel] & 0x1fffffff; uint32_t count = cpu->cd.sh.dmac_tcr[channel] & 0x1fffffff; uint32_t chcr = cpu->cd.sh.dmac_chcr[channel]; int transmit_size = 1; int src_delta = 0, dst_delta = 0; int cause_interrupt = chcr & CHCR_IE; #if 0 // Dump all SH4 DMA channels, for debugging: for (int dmaChannel = 0; dmaChannel < 4; ++dmaChannel) { fatal("{# dma channel %i: sar=%08x dar=%08x count=%08x chcr=%08x #}\n", dmaChannel, cpu->cd.sh.dmac_sar[dmaChannel], cpu->cd.sh.dmac_dar[dmaChannel], cpu->cd.sh.dmac_tcr[dmaChannel], cpu->cd.sh.dmac_chcr[dmaChannel]); } #endif /* DMAC not enabled? */ if (!(chcr & CHCR_TD)) { fatal("pvr_dma_transfer: SH4 dma not enabled?\n"); exit(1); } /* Transfer End already set? Then don't transfer again. */ if (chcr & CHCR_TE) return; /* Special case: 0 means 16777216: */ if (count == 0) count = 16777216; switch (chcr & CHCR_TS) { case CHCR_TS_8BYTE: transmit_size = 8; break; case CHCR_TS_1BYTE: transmit_size = 1; break; case CHCR_TS_2BYTE: transmit_size = 2; break; case CHCR_TS_4BYTE: transmit_size = 4; break; case CHCR_TS_32BYTE: transmit_size = 32; break; default: fatal("Unimplemented transmit size?! CHCR[%i] = 0x%08x\n", channel, chcr); exit(1); } switch (chcr & CHCR_DM) { case CHCR_DM_FIXED: dst_delta = 0; break; case CHCR_DM_INCREMENTED: dst_delta = 1; break; case CHCR_DM_DECREMENTED: dst_delta = -1; break; default: fatal("Unimplemented destination delta?! CHCR[%i] = 0x%08x\n", channel, chcr); exit(1); } switch (chcr & CHCR_SM) { case CHCR_SM_FIXED: src_delta = 0; break; case CHCR_SM_INCREMENTED: src_delta = 1; break; case CHCR_SM_DECREMENTED: src_delta = -1; break; default: fatal("Unimplemented source delta?! CHCR[%i] = 0x%08x\n", channel, chcr); exit(1); } src_delta *= transmit_size; dst_delta *= transmit_size; switch (chcr & CHCR_RS) { case 0x200: dar = d->dma_reg[PVR_ADDR / sizeof(uint32_t)]; if (dar != 0x10000000) { //fatal("[ NOTE: DMA to non-TA: dar=%08x (delta %i), sar=%08x (delta %i) ]\n", // (int)dar, (int)dst_delta, (int)sar, (int)src_delta); dar = 0x04000000 | (dar & 0x007fffff); if (dst_delta == 0) dst_delta = src_delta; uint8_t *buf = (uint8_t*) malloc(transmit_size); while (count > 0) { // printf("sar = %08x dar = %08x\n", (int)sar, (int)dar); cpu->memory_rw(cpu, cpu->mem, sar, buf, transmit_size, MEM_READ, NO_EXCEPTIONS | PHYSICAL); // for (int i = 0; i < transmit_size; ++i) // printf("%02x ", buf[i]); // printf("\n"); cpu->memory_rw(cpu, cpu->mem, dar, buf, transmit_size, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); count --; sar += src_delta; dar += dst_delta; } free(buf); break; } else { while (count > 0) { unsigned char buf[sizeof(uint32_t)]; int ofs; size_t chunksize = transmit_size; if (chunksize > sizeof(uint32_t)) chunksize = sizeof(uint32_t); for (ofs = 0; ofs < transmit_size; ofs += chunksize) { cpu->memory_rw(cpu, cpu->mem, sar + ofs, buf, chunksize, MEM_READ, NO_EXCEPTIONS | PHYSICAL); dev_pvr_ta_access(cpu, cpu->mem, ofs, buf, chunksize, MEM_WRITE, d); } count --; sar += src_delta; } } // Transfer End. TODO: _EXACTLY_ what happens at the end of // a transfer? cpu->cd.sh.dmac_chcr[channel] |= CHCR_TE; cpu->cd.sh.dmac_chcr[channel] &= ~CHCR_TD; cpu->cd.sh.dmac_sar[channel] = sar; cpu->cd.sh.dmac_tcr[channel] = count; // d->dma_reg[PVR_ADDR / sizeof(uint32_t)] = ???; d->dma_reg[PVR_COUNT / sizeof(uint32_t)] = 0; SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_PVR_DMA); break; default: fatal("Unimplemented SH4 RS DMAC: 0x%08x (PVR)\n", (int) (chcr & CHCR_RS)); exit(1); } if (cause_interrupt) { fatal("TODO: pvr sh4 dmac interrupt!\n"); exit(1); } } DEVICE_ACCESS(pvr_dma) { struct pvr_data *d = (struct pvr_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* Default read: */ if (writeflag == MEM_READ) odata = d->dma_reg[relative_addr / sizeof(uint32_t)]; switch (relative_addr) { case PVR_ADDR: if (writeflag == MEM_WRITE) { debug("[ pvr_dma: ADDR set to 0x%08x ]\n", (int) idata); } break; case PVR_COUNT: if (writeflag == MEM_WRITE) { debug("[ pvr_dma: COUNT set to 0x%08x ]\n", (int) idata); } break; case PVR_MODE: if (writeflag == MEM_WRITE) { debug("[ pvr_dma: MODE set to 0x%08x ]\n", (int) idata); if (idata != 0) { pvr_dma_transfer(cpu, d); idata = 0; } } break; /* These are written to by the Dreamcast ROM, but I have not found them documented anywhere. */ case 0x10: case 0x14: if (writeflag == MEM_WRITE && idata != 0x0cff0000) { fatal("[ pvr_dma: TODO: unknown_0x%02x set to " "0x%08x ]\n", (int) relative_addr, (int) idata); exit(1); } break; case 0x18: case 0x1c: case 0x20: case 0x40: case 0x44: case 0x48: case 0x4c: if (writeflag == MEM_WRITE && idata != 0) { fatal("[ pvr_dma: TODO: unknown_0x%02x set to " "0x%08x ]\n", (int) relative_addr, (int) idata); exit(1); } break; case PVR_LMMODE0: /* 0x84 */ if (writeflag == MEM_WRITE && idata != 0) { fatal("[ pvr_dma: TODO: LMMODE0 set to " "0x%08x ]\n", (int) idata); exit(1); } break; case PVR_LMMODE1: /* 0x88 */ if (writeflag == MEM_WRITE && idata != 0) { fatal("[ pvr_dma: TODO: LMMODE1 set to " "0x%08x ]\n", (int) idata); exit(1); } break; case 0x8c: if (writeflag == MEM_WRITE) { fatal("[ pvr_dma: write to 0x8c: TODO ]\n"); exit(1); } else { /* 0x20 means G2 DMA in progress? */ /* 0x11 = mask which has to do with AICA */ odata = 0x11 * (random() & 1); } break; case 0x9c: if (writeflag == MEM_WRITE && idata != 0) { fatal("[ pvr_dma: TODO: unknown_0x%02x set to " "0x%08x ]\n", (int) relative_addr, (int) idata); exit(1); } break; case 0xa0: if (writeflag == MEM_WRITE && idata != 0x80000000) { fatal("[ pvr_dma: TODO: unknown_0x%02x set to " "0x%08x ]\n", (int) relative_addr, (int) idata); exit(1); } break; case 0xa4: case 0xac: if (writeflag == MEM_WRITE && idata != 0) { fatal("[ pvr_dma: TODO: unknown_0x%02x set to " "0x%08x ]\n", (int) relative_addr, (int) idata); exit(1); } break; default:if (writeflag == MEM_READ) { fatal("[ pvr_dma: read from addr 0x%x ]\n", (int)relative_addr); } else { fatal("[ pvr_dma: write to addr 0x%x: 0x%x ]\n", (int)relative_addr, (int)idata); } exit(1); } /* Default write: */ if (writeflag == MEM_WRITE) d->dma_reg[relative_addr / sizeof(uint32_t)] = idata; if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(pvr_dma_more) { struct pvr_data *d = (struct pvr_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* Default read: */ if (writeflag == MEM_READ) odata = d->dma_more_reg[relative_addr / sizeof(uint32_t)]; switch (relative_addr) { case 0x00: // 0x04ff0000 case 0x04: // 0x0cff0000 case 0x08: // 0x00000020 case 0x0c: // 0x00000000 case 0x10: // 0x00000000 case 0x80: // 0x67027f00 break; case 0x14: case 0x18: if (writeflag == MEM_WRITE && idata != 0) { fatal("PVR other DMA mode (?):\n"); fatal("0x00: %08x\n", d->dma_more_reg[0x00/4]); fatal("0x04: %08x\n", d->dma_more_reg[0x04/4]); fatal("0x08: %08x\n", d->dma_more_reg[0x08/4]); fatal("0x0c: %08x\n", d->dma_more_reg[0x0c/4]); fatal("0x10: %08x\n", d->dma_more_reg[0x10/4]); fatal("0x14: %08x\n", d->dma_more_reg[0x14/4]); exit(1); } break; default:if (writeflag == MEM_READ) { fatal("[ pvr_dma_more: read from addr 0x%x ]\n", (int)relative_addr); } else { fatal("[ pvr_dma_more: write to addr 0x%x: 0x%x ]\n", (int)relative_addr, (int)idata); } exit(1); } /* Default write: */ if (writeflag == MEM_WRITE) d->dma_more_reg[relative_addr / sizeof(uint32_t)] = idata; if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * pvr_fb_invalidate(): */ void pvr_fb_invalidate(struct pvr_data *d, int start, int stop) { d->fb_update_x1 = d->fb_update_y1 = 0; d->fb_update_x2 = d->xsize - 1; d->fb_update_y2 = d->ysize - 1; } /* * pvr_vblank_timer_tick(): * * This function is called PVR_VBLANK_HZ times per real-world second. Its job * is to fake vertical retrace interrupts. */ static void pvr_vblank_timer_tick(struct timer *t, void *extra) { struct pvr_data *d = (struct pvr_data *) extra; d->vblank_interrupts_pending ++; } /* * pvr_geometry_updated(): * * This function should be called every time a register is written to which * affects the framebuffer geometry (size, bit-depth, starting position, etc). */ void pvr_geometry_updated(struct pvr_data *d) { int old_xsize = d->xsize, old_ysize = d->ysize, oldbpp = d->bytes_per_pixel; /* Make sure to redraw border on geometry changes. */ d->border_updated = 1; d->xsize = (REG(PVRREG_DIWSIZE) >> DIWSIZE_DPL_SHIFT) & DIWSIZE_MASK; d->ysize = (REG(PVRREG_DIWSIZE) >> DIWSIZE_LPF_SHIFT) & DIWSIZE_MASK; /* E.g. 319x479 => 320x480 */ d->xsize = (d->xsize + 1) * sizeof(uint32_t); d->ysize ++; switch (d->pixelmode) { case 0: case 1: d->bytes_per_pixel = 2; break; case 2: d->bytes_per_pixel = 3; break; case 3: d->bytes_per_pixel = 4; break; } d->xsize /= d->bytes_per_pixel; if (REG(PVRREG_DIWCONF) & DIWCONF_LR) d->xsize /= 2; if (d->line_double) d->ysize /= 2; bool settingsChanged = d->xsize != old_xsize || d->ysize != old_ysize || d->bytes_per_pixel != oldbpp; if (!settingsChanged) return; /* Scrap Z buffer if we have one. */ if (d->vram_z == NULL) { free(d->vram_z); d->vram_z = NULL; } /* Only show geometry debug message if output is enabled: */ if (!d->video_enabled || !d->display_enabled) return; debug("[ pvr_geometry_updated: %i x %i, ", d->xsize, d->ysize); switch (d->pixelmode) { case 0: debug("RGB0555 (16-bit)"); break; case 1: debug("RGB565 (16-bit)"); break; case 2: debug("RGB888 (24-bit)"); break; case 3: debug("RGB0888 (32-bit)"); break; } debug(" ]\n"); } #ifdef DEBUG_RENDER_AS_WIRE_FRAME /* Ugly quick-hack: */ static void line(struct pvr_data *d, int x1, int y1, int x2, int y2) { int fb_base = REG(PVRREG_FB_RENDER_ADDR1); int i; for (i=0; i<256; i++) { int px = (i * x2 + (256-i) * x1) >> 8; int py = (i * y2 + (256-i) * y1) >> 8; if (px > 0 && py > 0 && px < d->xsize && py < d->ysize) { int ofs = fb_base + (px + py * d->xsize) * d->bytes_per_pixel; d->vram[(ofs+0) % VRAM_SIZE] = 255; d->vram[(ofs+1) % VRAM_SIZE] = 255; } } } #endif // Ugly quick-hack z-buffer line drawer, for triangles. // Assumes 16-bit color. static void simpleline(struct pvr_data *d, int y, double x1, double x2, double z1, double z2, double r1, double r2, double g1, double g2, double b1, double b2) { if (y < 0 || y >= d->ysize || (x1 < 0 && x2 < 0) || (x1 >= d->xsize && x2 >= d->xsize)) return; int fb_base = REG(PVRREG_FB_RENDER_ADDR1); if (x1 > x2) { double tmpf = x1; x1 = x2; x2 = tmpf; tmpf = z1; z1 = z2; z2 = tmpf; tmpf = r1; r1 = r2; r2 = tmpf; tmpf = g1; g1 = g2; g2 = tmpf; tmpf = b1; b1 = b2; b2 = tmpf; } // uint32_t fogDensity = REG(PVRREG_FOG_DENSITY); // double scale_factor = 255.0; // TODO: take fogDensity into account. // uint32_t fogColor = REG(PVRREG_FOG_TABLE_COL); // int fog_r = (fogColor >> 16) & 255; // int fog_g = (fogColor >> 8) & 255; // int fog_b = fogColor & 255; double dz12 = (x2 - x1 != 0) ? ( (double)(z2 - z1) / (double)(x2 - x1) ) : 0; double dr12 = (x2 - x1 != 0) ? ( (double)(r2 - r1) / (double)(x2 - x1) ) : 0; double dg12 = (x2 - x1 != 0) ? ( (double)(g2 - g1) / (double)(x2 - x1) ) : 0; double db12 = (x2 - x1 != 0) ? ( (double)(b2 - b1) / (double)(x2 - x1) ) : 0; double z = z1, r = r1, g = g1, b = b1; for (int x = x1; x <= x2; ++x) { if (x > 0 && x < d->xsize) { int ofs = x + y * d->xsize; if (d->vram_z[ofs] <= z) { d->vram_z[ofs] = z; // z = 1/w // int v = z * scale_factor; // printf("z=%f v=%i\n", z, v); // if (v < 0) v = 0; // if (v > 255) v = 255; // v >>= 1; // int fogvalues = d->reg[PVRREG_FOG_TABLE / sizeof(uint32_t) + v]; // printf("fogv = %04x\n", fogvalues); // NOTE/TODO: Hardcoded for 565 pixelformat. int ri = r, gi = g, bi = b; // int a = (fogvalues >> 8) & 255; // ri = ((fog_r * a) + (ri * (255 - a))) >> 8; // gi = ((fog_g * a) + (gi * (255 - a))) >> 8; // bi = ((fog_b * a) + (bi * (255 - a))) >> 8; if (ri < 0) ri = 0; if (ri > 255) ri = 255; if (gi < 0) gi = 0; if (gi > 255) gi = 255; if (bi < 0) bi = 0; if (bi > 255) bi = 255; int color = ((ri >> 3) << 11) + ((gi >> 2) << 5) + (bi >> 3); int fbofs = fb_base + ofs * d->bytes_per_pixel; d->vram[(fbofs+0) % VRAM_SIZE] = color & 255; d->vram[(fbofs+1) % VRAM_SIZE] = color >> 8; } } z += dz12; r += dr12; g += dg12; b += db12; } } static void texturedline(struct pvr_data *d, int texture_pixelformat, bool twiddled, int stride, int texture, int texture_xsize, int texture_ysize, int y, int x1, int x2, double z1, double z2, double u1, double u2, double v1, double v2) { if (y < 0 || y >= d->ysize || (x1 < 0 && x2 < 0) || (x1 >= d->xsize && x2 >= d->xsize)) return; int fb_base = REG(PVRREG_FB_RENDER_ADDR1); if (x1 > x2) { int tmp = x1; x1 = x2; x2 = tmp; double tmpf = z1; z1 = z2; z2 = tmpf; tmpf = u1; u1 = u2; u2 = tmpf; tmpf = v1; v1 = v2; v2 = tmpf; } int bytesperpixel = 2; switch (texture_pixelformat) { case 0: // ARGB1555 case 1: // RGB565 case 2: // ARGB4444 bytesperpixel = 2; break; case 6: // 8-bit palette bytesperpixel = 1; break; default: // TODO break; } int palette_cfg = d->reg[PVRREG_PALETTE_CFG / sizeof(uint32_t)] & PVR_PALETTE_CFG_MODE_MASK; double dz12 = (x2 - x1 != 0) ? ( (double)(z2 - z1) / (double)(x2 - x1) ) : 0; double du12 = (x2 - x1 != 0) ? ( (double)(u2 - u1) / (double)(x2 - x1) ) : 0; double dv12 = (x2 - x1 != 0) ? ( (double)(v2 - v1) / (double)(x2 - x1) ) : 0; double z = z1, u = u1, v = v1; for (int x = x1; x <= x2; ++x) { if (x > 0 && x < d->xsize) { int ofs = x + y * d->xsize; if (d->vram_z[ofs] <= z) { d->vram_z[ofs] = z; int fbofs = fb_base + ofs * d->bytes_per_pixel; // Get color from texture: int texturex = u * texture_xsize; texturex &= (texture_xsize-1); int texturey = v * texture_ysize; texturey &= (texture_ysize-1); int textureofs; if (twiddled) { texturex = (texturex&1)|((texturex&2)<<1)|((texturex&4)<<2)|((texturex&8)<<3)|((texturex&16)<<4)| ((texturex&32)<<5)|((texturex&64)<<6)|((texturex&128)<<7)|((texturex&256)<<8)|((texturex&512)<<9); texturey = (texturey&1)|((texturey&2)<<1)|((texturey&4)<<2)|((texturey&8)<<3)|((texturey&16)<<4)| ((texturey&32)<<5)|((texturey&64)<<6)|((texturey&128)<<7)|((texturey&256)<<8)|((texturey&512)<<9); textureofs = texturex * 2 + texturey; } else { if (stride > 0) textureofs = texturex + texturey * stride; else textureofs = texturex + texturey * texture_xsize; } textureofs *= bytesperpixel; // 2 bytes per pixel. int addr = texture + textureofs; addr = ((addr & 4) << 20) | (addr & 3) | ((addr & 0x7ffff8) >> 1); int a = 255, r = 64, g = 64, b = 64; switch (texture_pixelformat) { case 0: // ARGB1555: { int color = d->vram[addr] + (d->vram[addr+1] << 8); a = (color >> 15) & 0x1 ? 255 : 0; r = (color >> 10) & 0x1f; g = ((color >> 5) & 0x1f) << 1; b = (color) & 0x1f; } break; case 1: // RGB565: { int color = d->vram[addr] + (d->vram[addr+1] << 8); r = (color >> 11) & 0x1f; g = (color >> 5) & 0x3f; b = (color) & 0x1f; } break; case 2: // ARGB4444: { int color = d->vram[addr] + (d->vram[addr+1] << 8); a = ((color >> 12) & 15) * 0x11; r = ((color >> 8) & 15) << 1; g = ((color >> 4) & 15) << 2; b = ((color) & 15) << 1; } break; case 6: { // TODO: multiple palette banks? Endianness? int index8bpp = d->vram[addr]; char* base = (char*)&d->reg[PVRREG_PALETTE / sizeof(uint32_t)]; uint16_t c16 = *((uint16_t*)(void*)base + index8bpp); uint16_t c32 = *((uint32_t*)(void*)base + index8bpp); switch (palette_cfg) { case PVR_PALETTE_CFG_MODE_ARGB1555: a = (c16 >> 15) & 0x1 ? 255 : 0; r = (c16 >> 10) & 0x1f; g = ((c16 >> 5) & 0x1f) << 1; b = (c16) & 0x1f; break; case PVR_PALETTE_CFG_MODE_RGB565: r = (c16 >> 11) & 0x1f; g = (c16 >> 5) & 0x3f; b = (c16) & 0x1f; break; case PVR_PALETTE_CFG_MODE_ARGB4444: a = ((c16 >> 12) & 15) * 0x11; r = ((c16 >> 8) & 15) << 1; g = ((c16 >> 4) & 15) << 2; b = ((c16) & 15) << 1; break; case PVR_PALETTE_CFG_MODE_ARGB8888: a = (c32 >> 24) & 255; r = ((c32 >> 16) & 255) >> 3; g = ((c32 >> 8) & 255) >> 2; b = ((c32) & 255) >> 3; break; } } break; default: fatal("pvr: unimplemented texture_pixelformat %i\n", texture_pixelformat); exit(1); } if (a == 255) { // Output as RGB565: // TODO: Support other formats. int color = (r << 11) + (g << 5) + (b); d->vram[(fbofs+0) % VRAM_SIZE] = color & 255; d->vram[(fbofs+1) % VRAM_SIZE] = color >> 8; } else if (a > 0) { int oldcolor = d->vram[(fbofs+0) % VRAM_SIZE]; oldcolor += (d->vram[(fbofs+1) % VRAM_SIZE] << 8); int oldr = (oldcolor >> 11) & 0x1f; int oldg = (oldcolor >> 5) & 0x3f; int oldb = (oldcolor) & 0x1f; r = (a * r + oldr * (255 - a)) / 255; g = (a * g + oldg * (255 - a)) / 255; b = (a * b + oldb * (255 - a)) / 255; int color = (r << 11) + (g << 5) + (b); d->vram[(fbofs+0) % VRAM_SIZE] = color & 255; d->vram[(fbofs+1) % VRAM_SIZE] = color >> 8; } } } z += dz12; u += du12; v += dv12; } } // Slow software rendering, for debugging: static void pvr_render_triangle(struct pvr_data *d, int x1, int y1, double z1, int r1, int g1, int b1, int x2, int y2, double z2, int r2, int g2, int b2, int x3, int y3, double z3, int r3, int g3, int b3) { // Easiest if 1, 2, 3 are in order top to bottom. if (y2 < y1) { int tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; tmp = r1; r1 = r2; r2 = tmp; tmp = g1; g1 = g2; g2 = tmp; tmp = b1; b1 = b2; b2 = tmp; double tmpf = z1; z1 = z2; z2 = tmpf; } if (y3 < y1) { int tmp = x1; x1 = x3; x3 = tmp; tmp = y1; y1 = y3; y3 = tmp; tmp = r1; r1 = r3; r3 = tmp; tmp = g1; g1 = g3; g3 = tmp; tmp = b1; b1 = b3; b3 = tmp; double tmpf = z1; z1 = z3; z3 = tmpf; } if (y3 < y2) { int tmp = x2; x2 = x3; x3 = tmp; tmp = y2; y2 = y3; y3 = tmp; tmp = r2; r2 = r3; r3 = tmp; tmp = g2; g2 = g3; g3 = tmp; tmp = b2; b2 = b3; b3 = tmp; double tmpf = z2; z2 = z3; z3 = tmpf; } if (y3 < 0 || y1 >= d->ysize) return; double dx12 = (y2-y1 != 0) ? ( (x2 - x1) / (double)(y2 - y1) ) : 0.0; double dx13 = (y3-y1 != 0) ? ( (x3 - x1) / (double)(y3 - y1) ) : 0.0; double dx23 = (y3-y2 != 0) ? ( (x3 - x2) / (double)(y3 - y2) ) : 0.0; double dz12 = (y2-y1 != 0) ? ( (z2 - z1) / (double)(y2 - y1) ) : 0.0; double dz13 = (y3-y1 != 0) ? ( (z3 - z1) / (double)(y3 - y1) ) : 0.0; double dz23 = (y3-y2 != 0) ? ( (z3 - z2) / (double)(y3 - y2) ) : 0.0; double dr12 = (y2-y1 != 0) ? ( (r2 - r1) / (double)(y2 - y1) ) : 0.0; double dr13 = (y3-y1 != 0) ? ( (r3 - r1) / (double)(y3 - y1) ) : 0.0; double dr23 = (y3-y2 != 0) ? ( (r3 - r2) / (double)(y3 - y2) ) : 0.0; double dg12 = (y2-y1 != 0) ? ( (g2 - g1) / (double)(y2 - y1) ) : 0.0; double dg13 = (y3-y1 != 0) ? ( (g3 - g1) / (double)(y3 - y1) ) : 0.0; double dg23 = (y3-y2 != 0) ? ( (g3 - g2) / (double)(y3 - y2) ) : 0.0; double db12 = (y2-y1 != 0) ? ( (b2 - b1) / (double)(y2 - y1) ) : 0.0; double db13 = (y3-y1 != 0) ? ( (b3 - b1) / (double)(y3 - y1) ) : 0.0; double db23 = (y3-y2 != 0) ? ( (b3 - b2) / (double)(y3 - y2) ) : 0.0; double startx = x1, startz = z1, startr = r1, startg = g1, startb = b1; double stopx = x1, stopz = z1, stopr = r1, stopg = g1, stopb = b1; for (int y = y1; y < y2; ++y) { simpleline(d, y, startx, stopx, startz, stopz, startr, stopr, startg, stopg, startb, stopb); startx += dx13; startz += dz13; startr += dr13; startg += dg13; startb += db13; stopx += dx12; stopz += dz12; stopr += dr12; stopg += dg12; stopb += db12; } stopx = x2; stopz = z2; stopr = r2; stopg = g2; stopb = b2; for (int y = y2; y < y3; ++y) { simpleline(d, y, startx, stopx, startz, stopz, startr, stopr, startg, stopg, startb, stopb); startx += dx13; startz += dz13; startr += dr13; startg += dg13; startb += db13; stopx += dx23; stopz += dz23; stopr += dr23; stopg += dg23; stopb += db23; } #ifdef DEBUG_RENDER_AS_WIRE_FRAME // Wire-frame test: line(d, x1, y1, x2, y2); line(d, x1, y1, x3, y3); line(d, x2, y2, x3, y3); #endif } // Slow software rendering, for debugging: static void pvr_render_triangle_textured(struct pvr_data *d, int texture_pixelformat, bool twiddled, int stride, int texture, int texture_xsize, int texture_ysize, int x1, int y1, double z1, double u1, double v1, int x2, int y2, double z2, double u2, double v2, int x3, int y3, double z3, double u3, double v3) { // Easiest if 1, 2, 3 are in order top to bottom. if (y2 < y1) { int tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; double tmpf = z1; z1 = z2; z2 = tmpf; tmpf = u1; u1 = u2; u2 = tmpf; tmpf = v1; v1 = v2; v2 = tmpf; } if (y3 < y1) { int tmp = x1; x1 = x3; x3 = tmp; tmp = y1; y1 = y3; y3 = tmp; double tmpf = z1; z1 = z3; z3 = tmpf; tmpf = u1; u1 = u3; u3 = tmpf; tmpf = v1; v1 = v3; v3 = tmpf; } if (y3 < y2) { int tmp = x2; x2 = x3; x3 = tmp; tmp = y2; y2 = y3; y3 = tmp; double tmpf = z2; z2 = z3; z3 = tmpf; tmpf = u2; u2 = u3; u3 = tmpf; tmpf = v2; v2 = v3; v3 = tmpf; } if (y3 < 0 || y1 >= d->ysize) return; double dx12 = (y2-y1 != 0) ? ( (x2 - x1) / (double)(y2 - y1) ) : 0.0; double dx13 = (y3-y1 != 0) ? ( (x3 - x1) / (double)(y3 - y1) ) : 0.0; double dx23 = (y3-y2 != 0) ? ( (x3 - x2) / (double)(y3 - y2) ) : 0.0; double dz12 = (y2-y1 != 0) ? ( (z2 - z1) / (double)(y2 - y1) ) : 0.0; double dz13 = (y3-y1 != 0) ? ( (z3 - z1) / (double)(y3 - y1) ) : 0.0; double dz23 = (y3-y2 != 0) ? ( (z3 - z2) / (double)(y3 - y2) ) : 0.0; double du12 = (y2-y1 != 0) ? ( (u2 - u1) / (double)(y2 - y1) ) : 0.0; double du13 = (y3-y1 != 0) ? ( (u3 - u1) / (double)(y3 - y1) ) : 0.0; double du23 = (y3-y2 != 0) ? ( (u3 - u2) / (double)(y3 - y2) ) : 0.0; double dv12 = (y2-y1 != 0) ? ( (v2 - v1) / (double)(y2 - y1) ) : 0.0; double dv13 = (y3-y1 != 0) ? ( (v3 - v1) / (double)(y3 - y1) ) : 0.0; double dv23 = (y3-y2 != 0) ? ( (v3 - v2) / (double)(y3 - y2) ) : 0.0; double startx = x1, startz = z1, startu = u1, startv = v1; double stopx = x1, stopz = z1, stopu = u1, stopv = v1; for (int y = y1; y < y2; ++y) { texturedline(d, texture_pixelformat, twiddled, stride, texture, texture_xsize, texture_ysize, y, startx, stopx, startz, stopz, startu, stopu, startv, stopv); startx += dx13; startz += dz13; startu += du13; startv += dv13; stopx += dx12; stopz += dz12; stopu += du12; stopv += dv12; } stopx = x2; stopz = z2; stopu = u2; stopv = v2; for (int y = y2; y < y3; ++y) { texturedline(d, texture_pixelformat, twiddled, stride, texture, texture_xsize, texture_ysize, y, startx, stopx, startz, stopz, startu, stopu, startv, stopv); startx += dx13; startz += dz13; startu += du13; startv += dv13; stopx += dx23; stopz += dz23; stopu += du23; stopv += dv23; } #ifdef DEBUG_RENDER_AS_WIRE_FRAME // Wire-frame test: line(d, x1, y1, x2, y2); line(d, x1, y1, x3, y3); line(d, x2, y2, x3, y3); #endif } static void pvr_clear_ta_commands(struct pvr_data* d) { d->n_ta_commands = 0; } /* * pvr_render(): * * Render from the Object Buffer to the framebuffer. * * TODO: This function is totally bogus so far, the format of the Object * Buffer is just a quick made-up hack to see if it works at all. */ void pvr_render(struct cpu *cpu, struct pvr_data *d) { int fb_render_cfg = REG(PVRREG_FB_RENDER_CFG); int fb_base = REG(PVRREG_FB_RENDER_ADDR1); if ((fb_render_cfg & FB_RENDER_CFG_RENDER_MODE_MASK) != 0x1) { printf("pvr: only RGB565 rendering has been implemented\n"); exit(1); } // Settings for the current polygon being rendered: // Word 0: int listtype = 0; int striplength = 0; int clipmode; int modifier; int modifier_mode; int color_type = 0; bool texture = false; bool specular; bool shading; bool uv_format; // Word 1: int depthmode; int cullingmode = 0; bool zwrite; bool texture1; bool specular1; bool shading1; bool uv_format1; bool dcalcexact; // Word 2: int fog = 0; int texture_usize = 0, texture_vsize = 0; // Word 3: bool texture_mipmap = false; bool texture_vq_compression = false; int texture_pixelformat = 0; bool texture_twiddled = false; bool texture_stride = false; uint32_t textureAddr = 0; int vertex_index = 0; int wf_x[4], wf_y[4]; double wf_z[4], wf_u[4], wf_v[4]; int wf_r[4], wf_g[4], wf_b[4]; double baseRed = 0.0, baseGreen = 0.0, baseBlue = 0.0; debug("[ pvr_render: rendering to FB offset 0x%x, " "%i Tile Accelerator commands ]\n", fb_base, d->n_ta_commands); /* * Clear all pixels first. * TODO: Maybe only clear the specific tiles that are in use by * the tile accelerator? * TODO: What background color to use? See KOS' pvr_misc.c for * how KOS sets the background. */ memset(d->vram + fb_base, 0x00, d->xsize * d->ysize * d->bytes_per_pixel); /* Clear Z as well: */ if (d->vram_z == NULL) { d->vram_z = (double*) malloc(sizeof(double) * d->xsize * d->ysize); } uint32_t bgplaneZ = REG(PVRREG_BGPLANE_Z); struct ieee_float_value backgroundz; ieee_interpret_float_value(bgplaneZ, &backgroundz, IEEE_FMT_S); for (int q = 0; q < d->xsize * d->ysize; ++q) d->vram_z[q] = backgroundz.f; // Using names from http://www.ludd.luth.se/~jlo/dc/ta-intro.txt. for (size_t index = 0; index < d->n_ta_commands; ++index) { // list points to 8 or 16 words. uint32_t* list = &d->ta_commands[index * 16]; int cmd = (list[0] >> 29) & 7; switch (cmd) { case 0: // END_OF_LIST // Interrupt event already triggered in pvr_ta_command(). #ifdef TA_DEBUG fatal("\nTA end_of_list (list type %i)\n", d->current_list_type); #endif break; case 1: // USER_CLIP // TODO: Ignoring for now. break; case 4: // polygon or modifier volume { vertex_index = 0; // List Word 0: listtype = (list[0] >> 24) & 7; striplength = (list[0] >> 18) & 3; striplength = striplength == 2 ? 4 : ( striplength == 3 ? 6 : (striplength + 1)); clipmode = (list[0] >> 16) & 3; modifier = (list[0] >> 7) & 1; modifier_mode = (list[0] >> 6) & 1; color_type = (list[0] >> 4) & 3; texture = list[0] & 8; specular = list[0] & 4; shading = list[0] & 2; uv_format = list[0] & 1; #ifdef TA_DEBUG fatal("\nTA polygon listtype %i, ", listtype); fatal("striplength %i, ", striplength); fatal("clipmode %i, ", clipmode); fatal("modifier %i, ", modifier); fatal("modifier_mode %i,\n", modifier_mode); fatal(" color_type %i, ", color_type); fatal("texture %s, ", texture ? "TRUE" : "false"); fatal("specular %s, ", specular ? "TRUE" : "false"); fatal("shading %s, ", shading ? "TRUE" : "false"); fatal("uv_format %s\n", uv_format ? "TRUE" : "false"); #endif // List Word 1: depthmode = (list[1] >> 29) & 7; cullingmode = (list[1] >> 27) & 3; zwrite = ! ((list[1] >> 26) & 1); texture1 = (list[1] >> 25) & 1; specular1 = (list[1] >> 24) & 1; shading1 = (list[1] >> 23) & 1; uv_format1 = (list[1] >> 22) & 1; dcalcexact = (list[1] >> 20) & 1; #ifdef TA_DEBUG fatal(" depthmode %i, ", depthmode); fatal("cullingmode %i, ", cullingmode); fatal("zwrite %s, ", zwrite ? "TRUE" : "false"); fatal("texture1 %s\n", texture1 ? "TRUE" : "false"); fatal(" specular1 %s, ", specular1 ? "TRUE" : "false"); fatal("shading1 %s, ", shading1 ? "TRUE" : "false"); fatal("uv_format1 %s, ", uv_format1 ? "TRUE" : "false"); fatal("dcalcexact %s\n", dcalcexact ? "TRUE" : "false"); #endif if (!zwrite) { fatal("pvr: no zwrite? not implemented yet.\n"); exit(1); } // For now, trust texture and ignore texture1. // if (texture != texture1) { // fatal("pvr: texture != texture1. what to do?\n"); // exit(1); // } // List Word 2: // TODO: srcblend (31-29) // TODO: dstblend (28-26) // TODO: srcmode (25) // TODO: dstmode (24) fog = (list[2] >> 22) & 3; // TODO: clamp (21) // TODO: alpha (20) // TODO: texture alpha (19) // TODO: uv flip (18-17) // TODO: uv clamp (16-15) // TODO: filter (14-12) // TODO: mipmap (11-8) // TODO: texture shading (7-6) texture_usize = 8 << ((list[2] >> 3) & 7); texture_vsize = 8 << (list[2] & 7); // List Word 3: texture_mipmap = (list[3] >> 31) & 1; texture_vq_compression = (list[3] >> 30) & 1; texture_pixelformat = (list[3] >> 27) & 7; texture_twiddled = ! ((list[3] >> 26) & 1); texture_stride = (list[3] >> 25) & 1; textureAddr = (list[3] << 3) & 0x7fffff; #ifdef TA_DEBUG fatal(" texture: mipmap %s, ", texture_mipmap ? "TRUE" : "false"); fatal("vq_compression %s, ", texture_vq_compression ? "TRUE" : "false"); fatal("pixelformat %i, ", texture_pixelformat); fatal("twiddled %s\n", texture_twiddled ? "TRUE" : "false"); fatal(" stride %s, ", texture_stride ? "TRUE" : "false"); fatal("textureAddr 0x%08x\n", textureAddr); #endif if (fog != 2) fatal("[ pvr: fog type %i not yet implemented ]\n", fog); if (texture_vq_compression) { fatal("pvr: texture_vq_compression not supported yet\n"); // exit(1); } struct ieee_float_value r, g, b; ieee_interpret_float_value(list[5], &r, IEEE_FMT_S); ieee_interpret_float_value(list[6], &g, IEEE_FMT_S); ieee_interpret_float_value(list[7], &b, IEEE_FMT_S); baseRed = r.f * 255; baseGreen = g.f * 255; baseBlue = b.f * 255; // printf("rgb = %f %f %f\n", r.f, g.f, b.f); break; } case 7: // vertex { // MAJOR TODO: // How to select which one of the 18 (!) types listed // in http://www.ludd.luth.se/~jlo/dc/ta-intro.txt to // use? if (listtype != 0 && listtype != 2 && listtype != 4) break; bool eos = (list[0] >> 28) & 1; struct ieee_float_value fx, fy, fz, u, v, extra1, extra2; ieee_interpret_float_value(list[1], &fx, IEEE_FMT_S); ieee_interpret_float_value(list[2], &fy, IEEE_FMT_S); ieee_interpret_float_value(list[3], &fz, IEEE_FMT_S); wf_x[vertex_index] = fx.f; wf_y[vertex_index] = fy.f; wf_z[vertex_index] = fz.f; #ifdef TA_DEBUG fatal("TA vertex %f %f %f%s\n", fx.f, fy.f, fz.f, eos ? " end_of_strip" : ""); #endif if (texture) { ieee_interpret_float_value(list[4], &u, IEEE_FMT_S); ieee_interpret_float_value(list[5], &v, IEEE_FMT_S); wf_u[vertex_index] = u.f; wf_v[vertex_index] = v.f; } else { if (color_type == 0) { wf_r[vertex_index] = (list[6] >> 16) & 255; wf_g[vertex_index] = (list[6] >> 8) & 255; wf_b[vertex_index] = (list[6]) & 255; } else if (color_type == 1) { ieee_interpret_float_value(list[5], &v, IEEE_FMT_S); ieee_interpret_float_value(list[6], &extra1, IEEE_FMT_S); ieee_interpret_float_value(list[7], &extra2, IEEE_FMT_S); wf_r[vertex_index] = v.f * 255; wf_g[vertex_index] = extra1.f * 255; wf_b[vertex_index] = extra2.f * 255; } else if (color_type == 2) { ieee_interpret_float_value(list[6], &extra1, IEEE_FMT_S); wf_r[vertex_index] = extra1.f * baseRed; wf_g[vertex_index] = extra1.f * baseGreen; wf_b[vertex_index] = extra1.f * baseBlue; } else { // "Intensity from previous face". TODO. Red for now. wf_r[vertex_index] = 255; wf_g[vertex_index] = 0; wf_b[vertex_index] = 0; } } vertex_index ++; if (vertex_index >= 3) { int modulo_mask = REG(PVRREG_TSP_CFG) & TSP_CFG_MODULO_MASK; float crossProduct = ((wf_x[1] - wf_x[0])*(wf_y[2] - wf_y[0])) - ((wf_y[1] - wf_y[0])*(wf_x[2] - wf_x[0])); // Hm. TODO: Instead of flipping back and forth between // clockwise and counter-clockwise culling, perhaps there // is some smarter way of assigning the three points // instead of 012 => 12x...? bool culled = false; if (cullingmode == 2) { if (crossProduct < 0) culled = true; cullingmode = 3; } else if (cullingmode == 3) { if (crossProduct > 0) culled = true; cullingmode = 2; } if (!culled) { if (texture) pvr_render_triangle_textured(d, texture_pixelformat, texture_twiddled, texture_stride ? (32*modulo_mask) : 0, textureAddr, texture_usize, texture_vsize, wf_x[0], wf_y[0], wf_z[0], wf_u[0], wf_v[0], wf_x[1], wf_y[1], wf_z[1], wf_u[1], wf_v[1], wf_x[2], wf_y[2], wf_z[2], wf_u[2], wf_v[2]); else pvr_render_triangle(d, wf_x[0], wf_y[0], wf_z[0], wf_r[0], wf_g[0], wf_b[0], wf_x[1], wf_y[1], wf_z[1], wf_r[1], wf_g[1], wf_b[1], wf_x[2], wf_y[2], wf_z[2], wf_r[2], wf_g[2], wf_b[2]); } if (eos) { // End of strip. vertex_index = 0; } else { // Not a closing vertex, then move points 1 and 2 // into slots 0 and 1, so that the stripe can continue. vertex_index = 2; wf_x[0] = wf_x[1]; wf_y[0] = wf_y[1]; wf_z[0] = wf_z[1]; wf_u[0] = wf_u[1]; wf_v[0] = wf_v[1]; wf_r[0] = wf_r[1]; wf_g[0] = wf_g[1]; wf_b[0] = wf_b[1]; wf_x[1] = wf_x[2]; wf_y[1] = wf_y[2]; wf_z[1] = wf_z[2]; wf_u[1] = wf_u[2]; wf_v[1] = wf_v[2]; wf_r[1] = wf_r[2]; wf_g[1] = wf_g[2]; wf_b[1] = wf_b[2]; } } break; } default: fatal("pvr_render: unimplemented list cmd %i\n", cmd); exit(1); } } pvr_clear_ta_commands(d); // TODO: RENDERDONE is 2. How about other events? SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_RENDERDONE); } /* * pvr_reset_ta(): * * Reset the Tile Accelerator. */ static void pvr_reset_ta(struct pvr_data *d) { REG(PVRREG_DIWCONF) = DIWCONF_MAGIC; pvr_clear_ta_commands(d); } /* * pvr_reset(): * * Reset the PVR. */ static void pvr_reset(struct pvr_data *d) { /* TODO */ } /* * pvr_ta_init(): * * Initialize the Tile Accelerator. This makes the TA ready to receive * commands (via address 0x10000000). */ void pvr_ta_init(struct cpu *cpu, struct pvr_data *d) { REG(PVRREG_TA_OPB_POS) = REG(PVRREG_TA_OPB_START); REG(PVRREG_TA_OB_POS) = REG(PVRREG_TA_OB_START); } static void pvr_tilebuf_debugdump(struct pvr_data *d) { return; // According to Marcus Comstedt's "tatest": // 24 word header (before the TILEBUF_ADDR pointer), followed by // 6 words for each tile. uint32_t tilebuf = REG(PVRREG_TILEBUF_ADDR) & PVR_TILEBUF_ADDR_MASK; // TODO: endianness uint32_t *p = (uint32_t*) (d->vram + tilebuf); fatal("PVR tile buffer debug dump:\n"); p -= 24; for (int i = 0; i < 24; ++i) fatal(" %08x", *p++); fatal("\n%i x %i tiles:\n", d->tilebuf_xsize, d->tilebuf_ysize); for (int x = 0; x < d->tilebuf_xsize; ++x) { for (int y = 0; y < d->tilebuf_ysize; ++y) { fatal(" Tile %i,%i:", x, y); for (int i = 0; i < 6; ++i) fatal(" %08x", *p++); fatal("\n"); } } } /* * pvr_ta_command(): * * Someone has written a [complete] 32-byte or 64-byte command to the Tile * Accelerator memory area. The real hardware probably outputs * "compiled commands" into the Object list and Object Pointer list. * For now, just put all the commands in a plain array, and then later execute * them in pvr_render(). */ static void pvr_ta_command(struct cpu *cpu, struct pvr_data *d, int list_ofs) { uint32_t *ta = &d->ta[list_ofs]; #ifdef TA_DEBUG /* Dump the Tile Accelerator command for debugging: */ { int i; fatal("TA cmd:"); for (i = 0; i < 8; ++i) fatal(" %08x", (int) ta[i]); fatal("\n"); } #endif // ob_ofs = REG(PVRREG_TA_OB_POS); // REG(PVRREG_TA_OB_POS) = ob_ofs + sizeof(uint64_t); if (d->ta_commands == NULL) { d->allocated_ta_commands = 2048; d->ta_commands = (uint32_t *) malloc(64 * d->allocated_ta_commands); d->n_ta_commands = 0; } if (d->n_ta_commands + 1 >= d->allocated_ta_commands) { d->allocated_ta_commands *= 2; d->ta_commands = (uint32_t *) realloc(d->ta_commands, 64 * d->allocated_ta_commands); } // Hack: I don't understand yet what separates a 32-byte transfer // vs two individual 32-byte transfers vs a 64-byte transfer. // TODO: For now, really only support 32-byte transfers... :( memcpy(d->ta_commands + 16 * d->n_ta_commands, ta, 32); memset(d->ta_commands + 16 * d->n_ta_commands + 8, 0, 32); d->n_ta_commands ++; // We need to keep track of the current list type though, and respond // with an event once we reach an end_of_list command. All other // commands are handled in pvr_render() for now. int cmd = (ta[0] >> 29) & 7; if (cmd == 0) { // cmd 0: end of list uint32_t opb_cfg = REG(PVRREG_TA_OPB_CFG); if (d->current_list_type == 0 && opb_cfg & TA_OPB_CFG_OPAQUEPOLY_MASK) SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_OPAQUEDONE); if (d->current_list_type == 1 && opb_cfg & TA_OPB_CFG_OPAQUEMOD_MASK) SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_OPAQUEMODDONE); if (d->current_list_type == 2 && opb_cfg & TA_OPB_CFG_TRANSPOLY_MASK) SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_TRANSDONE); if (d->current_list_type == 3 && opb_cfg & TA_OPB_CFG_TRANSMOD_MASK) SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_TRANSMODDONE); if (d->current_list_type == 4 && opb_cfg & TA_OPB_CFG_PUNCHTHROUGH_MASK) SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_PVR_PTDONE); } else if (cmd == 4) { // cmd 4: polygon or modifier volume d->current_list_type = (ta[0] >> 24) & 7; } } DEVICE_ACCESS(pvr_ta) { struct pvr_data *d = (struct pvr_data *) extra; uint64_t idata = 0, odata = 0; if (len != sizeof(uint32_t)) { fatal("pvr_ta access len = %i: TODO\n", (int) len); exit(1); } // Tile Accelerator commands can be sent to 0x10000000 through // 0x107fffff, it seems, but the SH4 store queues only have 64 bytes. relative_addr &= (sizeof(d->ta) - 1); if (writeflag == MEM_WRITE) { idata = memory_readmax64(cpu, data, len); #if 0 fatal("[ pvr_ta: WRITE addr=%08x value=%08x ]\n", (int)relative_addr, (int)idata); #endif /* Write to the tile accelerator command buffer: */ d->ta[relative_addr / sizeof(uint32_t)] = idata; // Execute the command, after a complete write. // (Note: This assumes that commands are written from low // address to high.) if (relative_addr == 0x1c) pvr_ta_command(cpu, d, 0); if (relative_addr == 0x3c) pvr_ta_command(cpu, d, 8); } else { odata = d->ta[relative_addr / sizeof(uint32_t)]; memory_writemax64(cpu, data, len, odata); #if 1 fatal("[ pvr_ta: READ addr=%08x value=%08x ]\n", (int)relative_addr, (int)odata); #endif } return 1; } DEVICE_ACCESS(pvr) { struct pvr_data *d = (struct pvr_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* Default read action: Read from reg[]: */ if (writeflag == MEM_READ) odata = d->reg[relative_addr / sizeof(uint32_t)]; /* Fog table access: */ if (relative_addr >= PVRREG_FOG_TABLE && relative_addr < PVRREG_FOG_TABLE + PVR_FOG_TABLE_SIZE) { if (writeflag == MEM_WRITE) DEFAULT_WRITE; goto return_ok; } /* Palette access: */ if (relative_addr >= PVRREG_PALETTE && relative_addr < PVRREG_PALETTE + PVR_PALETTE_SIZE) { if (writeflag == MEM_WRITE) DEFAULT_WRITE; goto return_ok; } switch (relative_addr) { case PVRREG_ID: /* ID for Set 5.xx versions of the Dreamcast, according to http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt: */ odata = 0x17fd11db; break; case PVRREG_REVISION: /* Revision 1.1, for Dreamcast Set 5.2x. */ odata = 0x00000011; break; case PVRREG_RESET: if (writeflag == MEM_WRITE) { if (idata != 0) { debug("[ pvr: RESET "); if (idata & PVR_RESET_PVR) pvr_reset(d); if (idata & PVR_RESET_TA) pvr_reset_ta(d); debug("]\n"); } idata = 0; DEFAULT_WRITE; } break; case PVRREG_STARTRENDER: if (writeflag == MEM_WRITE) { debug("[ pvr: STARTRENDER ]\n"); pvr_render(cpu, d); } else { fatal("[ pvr: huh? read from STARTRENDER ]\n"); exit(1); } break; case PVRREG_OB_ADDR: if (writeflag == MEM_WRITE) { debug("[ pvr: OB_ADDR set to 0x%08" PRIx32" ]\n", (uint32_t)(idata & PVR_OB_ADDR_MASK)); if (idata & ~PVR_OB_ADDR_MASK) { fatal("[ pvr: OB_ADDR: Fatal error: Unknown" " bits set: 0x%08" PRIx32" ]\n", (uint32_t)(idata & ~PVR_OB_ADDR_MASK)); exit(1); } idata &= PVR_OB_ADDR_MASK; DEFAULT_WRITE; } break; case PVRREG_TILEBUF_ADDR: if (writeflag == MEM_WRITE) { debug("[ pvr: TILEBUF_ADDR set to 0x%08" PRIx32" ]\n", (uint32_t)(idata & PVR_TILEBUF_ADDR_MASK)); if (idata & ~PVR_TILEBUF_ADDR_MASK) { fatal("[ pvr: TILEBUF_ADDR: Unknown" " bits set: 0x%08" PRIx32" ]\n", (uint32_t)(idata & ~PVR_TILEBUF_ADDR_MASK)); exit(1); } idata &= PVR_TILEBUF_ADDR_MASK; DEFAULT_WRITE; pvr_tilebuf_debugdump(d); } break; case PVRREG_SPANSORT: if (writeflag == MEM_WRITE) { debug("[ pvr: SPANSORT: "); if (idata & PVR_SPANSORT_SPAN0) debug("SPAN0 "); if (idata & PVR_SPANSORT_SPAN1) debug("SPAN1 "); if (idata & PVR_SPANSORT_TSP_CACHE_ENABLE) debug("TSP_CACHE_ENABLE "); debug("]\n"); DEFAULT_WRITE; } break; case PVRREG_BRDCOLR: if (writeflag == MEM_WRITE) { debug("[ pvr: BRDCOLR set to 0x%06" PRIx32" ]\n", (int)idata); DEFAULT_WRITE; d->border_updated = 1; } break; case PVRREG_DIWMODE: if (writeflag == MEM_WRITE) { d->clock_double = idata & DIWMODE_C_MASK? 1:0; d->strip_buffer_enabled = idata & DIWMODE_SE_MASK? 1:0; d->strip_length = (idata & DIWMODE_SL_MASK) >> DIWMODE_SL_SHIFT; d->argb8888_threshold = (idata & DIWMODE_TH_MASK) >> DIWMODE_TH_SHIFT; d->extend = (idata & DIWMODE_EX_MASK) >> DIWMODE_EX_SHIFT; d->pixelmode = (idata & DIWMODE_COL_MASK) >> DIWMODE_COL_SHIFT; d->line_double = idata & DIWMODE_SD_MASK? 1:0; d->display_enabled = idata & DIWMODE_DE_MASK? 1:0; debug("[ pvr: DIWMODE set to: "); debug("clock_double=%i, ", d->clock_double); debug("strip_buffer_enabled=%i, ", d->strip_buffer_enabled); debug("strip_length=%i, ", d->strip_length); debug("argb8888_threshold=%i, ", d->argb8888_threshold); debug("extend=0x%x, ", d->extend); debug("pixelmode="); switch (d->pixelmode) { case 0: debug("RGB0555 (16-bit)"); break; case 1: debug("RGB565 (16-bit)"); break; case 2: debug("RGB888 (24-bit)"); break; case 3: debug("RGB0888 (32-bit)"); break; } debug(", line_double=%i, ", d->line_double); debug("display_enabled=%i", d->display_enabled); debug(" ]\n"); DEFAULT_WRITE; pvr_geometry_updated(d); pvr_fb_invalidate(d, -1, -1); } break; case PVRREG_DIWSIZE: if (writeflag == MEM_WRITE) { debug("[ pvr: DIWSIZE set to modulo=%i, " "width=%i, height=%i ]\n", (int) ((idata >> DIWSIZE_MODULO_SHIFT) & DIWSIZE_MASK), (int)((idata >> DIWSIZE_DPL_SHIFT) & DIWSIZE_MASK), (int)((idata >> DIWSIZE_LPF_SHIFT) & DIWSIZE_MASK)); DEFAULT_WRITE; pvr_geometry_updated(d); pvr_fb_invalidate(d, -1, -1); } break; case PVRREG_FB_RENDER_ADDR1: if (writeflag == MEM_WRITE) { debug("[ pvr: FB_RENDER_ADDR1 set to 0x%08" PRIx32 " ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_FB_RENDER_ADDR2: if (writeflag == MEM_WRITE) { debug("[ pvr: FB_RENDER_ADDR2 set to 0x%08" PRIx32 " ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_FB_CLIP_X: if (writeflag == MEM_WRITE) { debug("[ pvr: FB_CLIP_X set to min=%i, " "max=%i ]\n", (int) (idata & FB_CLIP_XY_MIN_MASK), (int) ((idata & FB_CLIP_XY_MAX_MASK) >> FB_CLIP_XY_MAX_SHIFT)); DEFAULT_WRITE; pvr_geometry_updated(d); pvr_fb_invalidate(d, -1, -1); } break; case PVRREG_FB_CLIP_Y: if (writeflag == MEM_WRITE) { debug("[ pvr: FB_CLIP_Y set to min=%i, " "max=%i ]\n", (int) (idata & FB_CLIP_XY_MIN_MASK), (int) ((idata & FB_CLIP_XY_MAX_MASK) >> FB_CLIP_XY_MAX_SHIFT)); DEFAULT_WRITE; pvr_geometry_updated(d); pvr_fb_invalidate(d, -1, -1); } break; case PVRREG_SHADOW: if (writeflag == MEM_WRITE) { debug("[ pvr: SHADOW set to enable=%i, " "intensity=%i ]\n", (int) (idata & SHADOW_ENABLE? 1 : 0), (int) (idata & SHADOW_INTENSITY_MASK)); DEFAULT_WRITE; pvr_geometry_updated(d); pvr_fb_invalidate(d, -1, -1); } break; case PVRREG_OBJECT_CLIP: if (writeflag == MEM_WRITE) { debug("[ pvr: OBJECT_CLIP 0x%08x ]\n", (int)idata); DEFAULT_WRITE; } break; case PVRREG_OB_CFG: if (writeflag == MEM_WRITE) { debug("[ pvr: OB_CFG 0x%08x ]\n", (int)idata); DEFAULT_WRITE; } break; case PVRREG_UNKNOWN_80: if (writeflag == MEM_WRITE) { debug("[ pvr: UNKNOWN_80 0x%08x ]\n", (int)idata); DEFAULT_WRITE; } break; case PVRREG_UNKNOWN_84: if (writeflag == MEM_WRITE) { debug("[ pvr: UNKNOWN_84 0x%08x ]\n", (int)idata); DEFAULT_WRITE; } break; case PVRREG_BGPLANE_Z: if (writeflag == MEM_WRITE) { debug("[ pvr: BGPLANE_Z 0x%08x ]\n", (int)idata); DEFAULT_WRITE; } break; case PVRREG_BGPLANE_CFG: if (writeflag == MEM_WRITE) { debug("[ pvr: BGPLANE_CFG 0x%08x ]\n", (int)idata); DEFAULT_WRITE; } break; case PVRREG_ISP_CFG: if (writeflag == MEM_WRITE) { debug("[ pvr: ISP_CFG 0x%08x ]\n", (int)idata); DEFAULT_WRITE; } break; case PVRREG_VRAM_CFG1: if (writeflag == MEM_WRITE) { debug("[ pvr: VRAM_CFG1 set to 0x%08" PRIx32, (int) idata); if (idata != VRAM_CFG1_GOOD_REFRESH_VALUE) fatal("{ VRAM_CFG1 = 0x%08" PRIx32" is not " "yet implemented! }", (int) idata); debug(" ]\n"); DEFAULT_WRITE; } break; case PVRREG_VRAM_CFG2: if (writeflag == MEM_WRITE) { debug("[ pvr: VRAM_CFG2 set to 0x%08" PRIx32, (int) idata); if (idata != VRAM_CFG2_UNKNOWN_MAGIC) fatal("{ VRAM_CFG2 = 0x%08" PRIx32" is not " "yet implemented! }", (int) idata); debug(" ]\n"); DEFAULT_WRITE; } break; case PVRREG_VRAM_CFG3: if (writeflag == MEM_WRITE) { debug("[ pvr: VRAM_CFG3 set to 0x%08" PRIx32, (int) idata); if (idata != VRAM_CFG3_UNKNOWN_MAGIC) fatal("{ VRAM_CFG3 = 0x%08" PRIx32" is not " "yet implemented! }", (int) idata); debug(" ]\n"); DEFAULT_WRITE; } break; case PVRREG_FOG_TABLE_COL: // e.g. 0x007f7f7f if (writeflag == MEM_WRITE) { debug("[ pvr: FOG_TABLE_COL set to 0x%06" PRIx32" ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_FOG_VERTEX_COL: // e.g. 0x007f7f7f if (writeflag == MEM_WRITE) { debug("[ pvr: FOG_VERTEX_COL set to 0x%06" PRIx32" ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_FOG_DENSITY: // e.g. 0x0000ff07 if (writeflag == MEM_WRITE) { debug("[ pvr: FOG_DENSITY set to 0x%08" PRIx32" ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_CLAMP_MAX: // e.g. 0xffffffff if (writeflag == MEM_WRITE) { debug("[ pvr: CLAMP_MAX set to 0x%06" PRIx32" ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_CLAMP_MIN: // e.g. 0x00000000 if (writeflag == MEM_WRITE) { debug("[ pvr: CLAMP_MIN set to 0x%06" PRIx32" ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_FB_RENDER_CFG: if (writeflag == MEM_WRITE) { debug("[ pvr: PVRREG_FB_RENDER_CFG set to 0x%08x ]\n", (int) idata); /* TODO */ DEFAULT_WRITE; } break; case PVRREG_FB_RENDER_MODULO: if (writeflag == MEM_WRITE) { debug("[ pvr: PVRREG_FB_RENDER_MODULO set to %i ]\n", (int) idata); /* TODO */ DEFAULT_WRITE; } break; case PVRREG_DIWADDRL: if (writeflag == MEM_WRITE) { debug("[ pvr: DIWADDRL set to 0x%08" PRIx32" ]\n", (int) idata); pvr_fb_invalidate(d, -1, -1); DEFAULT_WRITE; } break; case PVRREG_DIWADDRS: if (writeflag == MEM_WRITE) { debug("[ pvr: DIWADDRS set to 0x%08" PRIx32" ]\n", (int) idata); pvr_fb_invalidate(d, -1, -1); DEFAULT_WRITE; } break; case PVRREG_HPOS_IRQ: DEFAULT_WRITE; break; case PVRREG_RASEVTPOS: if (writeflag == MEM_WRITE) { debug("[ pvr: RASEVTPOS pos1=%i pos2=%i ]\n", (int)((idata & RASEVTPOS_POS1_MASK) >> RASEVTPOS_POS1_SHIFT), (int)(idata & RASEVTPOS_POS2_MASK)); DEFAULT_WRITE; } break; case PVRREG_SYNCCONF: if (writeflag == MEM_WRITE) { d->video_enabled = idata & SYNCCONF_VO_MASK? 1:0; d->broadcast_standard = (idata & SYNCCONF_BC_MASK) >> SYNCCONF_BC_SHIFT; d->interlaced = idata & SYNCCONF_I_MASK? 1:0; d->h_sync_positive = idata & SYNCCONF_HP_MASK? 1:0; d->v_sync_positive = idata & SYNCCONF_VP_MASK? 1:0; debug("[ pvr: SYNCCONF set to: "); debug("video_enabled=%i, ", d->video_enabled); switch (d->broadcast_standard) { case SYNCCONF_BC_VGA: debug("VGA"); break; case SYNCCONF_BC_NTSC: debug("NTSC"); break; case SYNCCONF_BC_PAL: debug("PAL"); break; default: debug("*UNKNOWN*"); break; } debug(", interlaced=%i, ", d->interlaced); debug("hsync=%i, ", d->h_sync_positive); debug("vsync=%i ]\n", d->v_sync_positive); DEFAULT_WRITE; pvr_geometry_updated(d); pvr_fb_invalidate(d, -1, -1); } break; case PVRREG_BRDHORZ: if (writeflag == MEM_WRITE) { debug("[ pvr: BRDHORZ start=%i stop=%i ]\n", (int)((idata & BRDHORZ_START_MASK) >> BRDHORZ_START_SHIFT), (int)(idata & BRDHORZ_STOP_MASK)); DEFAULT_WRITE; } break; case PVRREG_SYNCSIZE: if (writeflag == MEM_WRITE) { debug("[ pvr: SYNCSIZE v=%i h=%i ]\n", (int)((idata & SYNCSIZE_V_MASK) >> SYNCSIZE_V_SHIFT), (int)(idata & SYNCSIZE_H_MASK)); DEFAULT_WRITE; } break; case PVRREG_BRDVERT: if (writeflag == MEM_WRITE) { debug("[ pvr: BRDVERT start=%i stop=%i ]\n", (int)((idata & BRDVERT_START_MASK) >> BRDVERT_START_SHIFT), (int)(idata & BRDVERT_STOP_MASK)); DEFAULT_WRITE; } break; case PVRREG_SYNCH_WIDTH: if (writeflag == MEM_WRITE) { debug("[ pvr: SYNCH_WIDTH 0x%08x ]\n", (int)idata); DEFAULT_WRITE; } break; case PVRREG_TSP_CFG: if (writeflag == MEM_WRITE) { debug("[ pvr: TSP_CFG 0x%08x ]\n", (int)idata); DEFAULT_WRITE; } break; case PVRREG_DIWCONF: if (writeflag == MEM_WRITE) { if ((idata & DIWCONF_MAGIC_MASK) != DIWCONF_MAGIC && (idata & DIWCONF_MAGIC_MASK) != 0) { fatal("PVRREG_DIWCONF magic not set to " "Magic value. 0x%08x\n", (int)idata); exit(1); } if (idata & DIWCONF_BLANK) debug("[ pvr: PVRREG_DIWCONF: BLANK: TODO ]\n"); DEFAULT_WRITE; pvr_geometry_updated(d); } break; case PVRREG_DIWHSTRT: if (writeflag == MEM_WRITE) { int v = idata & DIWVSTRT_HPOS_MASK; debug("[ pvr: DIWHSTRT hpos=%i (%s) ]\n", v, v == 174? "PAL" : (v == 164? "NTSC" : (v == 144? "VGA" : "unknown!"))); DEFAULT_WRITE; } break; case PVRREG_DIWVSTRT: if (writeflag == MEM_WRITE) { debug("[ pvr: DIWVSTRT v2=%i v1=%i ]\n", (int)((idata & DIWVSTRT_V2_MASK) >> DIWVSTRT_V2_SHIFT), (int)(idata & DIWVSTRT_V1_MASK)); DEFAULT_WRITE; } break; case PVRREG_SCALER_CFG: if (writeflag == MEM_WRITE) { debug("[ pvr: SCALER_CFG 0x%08x ]\n", (int)idata); DEFAULT_WRITE; } break; case PVRREG_PALETTE_CFG: if (writeflag == MEM_WRITE) { debug("[ pvr: PALETTE_CFG 0x%08x ]\n", (int)idata); DEFAULT_WRITE; } break; case PVRREG_SYNC_STAT: /* TODO. Ugly hack, but it works: */ odata = random(); break; case PVRREG_MAGIC_110: if (writeflag == MEM_WRITE) { debug("[ pvr: MAGIC_110 set to 0x%08" PRIx32, (int) idata); if (idata != MAGIC_110_VALUE) fatal("{ MAGIC_110 = 0x%08" PRIx32" is not " "yet implemented! }", (int) idata); debug(" ]\n"); DEFAULT_WRITE; } break; case PVRREG_TA_LUMINANCE: if (writeflag == MEM_WRITE) { debug("[ pvr: TA_LUMINANCE set to 0x%08" PRIx32" ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_TA_OPB_START: if (writeflag == MEM_WRITE) { if (idata & ~TA_OPB_START_MASK) { fatal("[ pvr: UNEXPECTED bits in " "TA_OPB_START: 0x%08x ]\n", (int)idata); exit(1); } idata &= TA_OPB_START_MASK; debug("[ pvr: TA_OPB_START set to 0x%x ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_TA_OB_START: if (writeflag == MEM_WRITE) { if (idata & ~TA_OB_START_MASK) { fatal("[ pvr: UNEXPECTED bits in " "TA_OB_START: 0x%08x ]\n", (int)idata); exit(1); } idata &= TA_OB_START_MASK; debug("[ pvr: TA_OB_START set to 0x%x ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_TA_OPB_END: if (writeflag == MEM_WRITE) { idata &= TA_OPB_END_MASK; debug("[ pvr: TA_OPB_END set to 0x%x ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_TA_OB_END: if (writeflag == MEM_WRITE) { idata &= TA_OB_END_MASK; debug("[ pvr: TA_OB_END set to 0x%x ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_TA_OPB_POS: if (writeflag == MEM_WRITE) { idata &= TA_OPB_POS_MASK; debug("[ pvr: TA_OPB_POS set to 0x%x ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_TA_OB_POS: if (writeflag == MEM_WRITE) { idata &= TA_OB_POS_MASK; debug("[ pvr: TA_OB_POS set to 0x%x ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_TA_OPL_INIT: if (writeflag == MEM_WRITE) { idata &= PVR_TA_OPL_INIT_MASK; debug("[ pvr: TA_OPL_INIT set to 0x%x ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_TILEBUF_SIZE: if (writeflag == MEM_WRITE) { d->tilebuf_ysize = (idata & TILEBUF_SIZE_HEIGHT_MASK) >> TILEBUF_SIZE_HEIGHT_SHIFT; d->tilebuf_xsize = idata & TILEBUF_SIZE_WIDTH_MASK; d->tilebuf_xsize ++; d->tilebuf_ysize ++; debug("[ pvr: TILEBUF_SIZE set to %i x %i ]\n", d->tilebuf_xsize, d->tilebuf_ysize); DEFAULT_WRITE; } break; case PVRREG_TA_OPB_CFG: if (writeflag == MEM_WRITE) { debug("[ pvr: TA_OPB_CFG set to 0x%x ]\n", (int) idata); DEFAULT_WRITE; } break; case PVRREG_TA_INIT: if (writeflag == MEM_WRITE) { debug("[ pvr: TA_INIT ]\n"); if (idata & PVR_TA_INIT) pvr_ta_init(cpu, d); if (idata != PVR_TA_INIT && idata != 0) fatal("{ TA_INIT = 0x%08" PRIx32" is not " "yet implemented! }", (int) idata); /* Always reset to 0. */ idata = 0; DEFAULT_WRITE; } break; case PVRREG_YUV_STAT: // TODO. The "luftvarg" demo accesses this register. break; default:if (writeflag == MEM_READ) { fatal("[ pvr: read from UNIMPLEMENTED addr 0x%x ]\n", (int)relative_addr); } else { fatal("[ pvr: write to UNIMPLEMENTED addr 0x%x: 0x%x" " ]\n", (int)relative_addr, (int)idata); DEFAULT_WRITE; } exit(1); } return_ok: if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } void pvr_extend_update_region(struct pvr_data *d, uint64_t low, uint64_t high) { int vram_ofs = REG(PVRREG_DIWADDRL); int bytes_per_line = d->xsize * d->bytes_per_pixel; low -= vram_ofs; high -= vram_ofs; /* Access inside visible part of VRAM? */ if ((int64_t)high >= 0 && (int64_t)low < bytes_per_line * d->ysize) { int new_y1, new_y2; d->fb_update_x1 = 0; d->fb_update_x2 = d->xsize - 1; /* Calculate which line the low and high addresses correspond to: */ new_y1 = low / bytes_per_line; new_y2 = high / bytes_per_line + 1; if (d->fb_update_y1 < 0 || new_y1 < d->fb_update_y1) d->fb_update_y1 = new_y1; if (d->fb_update_y2 < 0 || new_y2 > d->fb_update_y2) d->fb_update_y2 = new_y2; if (d->fb_update_y1 < 0) d->fb_update_y1 = 0; if (d->fb_update_y2 >= d->ysize) d->fb_update_y2 = d->ysize - 1; } } DEVICE_TICK(pvr_fb) { struct pvr_data *d = (struct pvr_data *) extra; uint64_t high, low = (uint64_t)(int64_t) -1; int vram_ofs = REG(PVRREG_DIWADDRL), pixels_to_copy; int bytes_per_line = d->xsize * d->bytes_per_pixel; int fb_ofs, p; uint8_t *fb = (uint8_t *) d->fb->framebuffer; uint8_t *vram = (uint8_t *) d->vram; /* * Vertical retrace interrupts: * * TODO: Maybe it would be even more realistic to have the timer run * at, say, 60*4 = 240 Hz, and have the following events: * * (tick & 3) == 0 SYSASIC_EVENT_VBLINT * (tick & 3) == 1 SYSASIC_EVENT_PVR_SCANINT1 * (tick & 3) == 2 nothing * (tick & 3) == 3 SYSASIC_EVENT_PVR_SCANINT2 */ if (d->vblank_interrupts_pending > 0) { -- d->vblank_interrupts_pending; SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_VBLINT); SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_PVR_SCANINT1); // Is this needed? SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_PVR_SCANINT2); /* TODO: For now, I don't care about missed interrupts: */ d->vblank_interrupts_pending = 0; } /* * Framebuffer update: */ /* Border changed? */ if (d->border_updated) { /* Fill border with border color: */ int rgb = REG(PVRREG_BRDCOLR), addr = 0; int x, y, b = rgb & 0xff, g = (rgb >> 8) & 0xff, r = rgb >> 16; int skiplen = (d->fb->xsize-2*PVR_MARGIN) * d->fb->bit_depth/8; for (y=0; yfb->ysize; y++) { int xskip = y < PVR_MARGIN || y >= d->fb->ysize - PVR_MARGIN? -1 : PVR_MARGIN; for (x=0; xfb->xsize; x++) { if (x == xskip) { x = d->fb->xsize - PVR_MARGIN; addr += skiplen; } fb[addr] = r; fb[addr+1] = g; fb[addr+2] = b; addr += 3; } } /* Full redraw of the framebuffer: */ d->fb->update_x1 = 0; d->fb->update_x2 = d->fb->xsize - 1; d->fb->update_y1 = 0; d->fb->update_y2 = d->fb->ysize - 1; } memory_device_dyntrans_access(cpu, cpu->mem, extra, &low, &high); if ((int64_t)low != -1) pvr_extend_update_region(d, low, high); if (d->fb_update_x1 == -1) return; /* Copy (part of) the VRAM to the framebuffer: */ if (d->fb_update_x2 >= d->xsize) d->fb_update_x2 = d->xsize - 1; if (d->fb_update_y2 >= d->ysize) d->fb_update_y2 = d->ysize - 1; vram_ofs += d->fb_update_y1 * bytes_per_line; vram_ofs += d->fb_update_x1 * d->bytes_per_pixel; pixels_to_copy = (d->fb_update_x2 - d->fb_update_x1 + 1); fb_ofs = (d->fb_update_y1 + PVR_MARGIN) * d->fb->bytes_per_line; fb_ofs += (d->fb_update_x1 + PVR_MARGIN) * d->fb->bit_depth / 8; /* Copy the actual pixels: (Four manually inlined, for speed.) */ switch (d->pixelmode) { case 0: /* RGB0555 (16-bit) */ { int y; for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) { int fo = fb_ofs, vo = vram_ofs; for (p=0; p> 2) & 0x38) + (vram[(vo+1)%VRAM_SIZE] << 6); fb[fo+2] = (vram[vo%VRAM_SIZE] & 0x1f) << 3; fo += 3; vo += 2; } vram_ofs += bytes_per_line; fb_ofs += d->fb->bytes_per_line; } } break; case 1: /* RGB565 (16-bit) */ { int y; for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) { int fo = fb_ofs, vo = vram_ofs; for (p=0; p> 3) & 0x1c) + (vram[(vo+1)%VRAM_SIZE] << 5); fb[fo+2] = (vram[vo%VRAM_SIZE] & 0x1f) << 3; fo += 3; vo += 2; } vram_ofs += bytes_per_line; fb_ofs += d->fb->bytes_per_line; } } break; case 2: /* RGB888 (24-bit) */ { int y; for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) { /* TODO: Reverse colors, like in the 32-bit case? */ memcpy(fb+fb_ofs, vram+(vram_ofs%VRAM_SIZE), 3*pixels_to_copy); vram_ofs += bytes_per_line; fb_ofs += d->fb->bytes_per_line; } } break; case 3: /* RGB0888 (32-bit) */ { int y; for (y=d->fb_update_y1; y<=d->fb_update_y2; y++) { int fo = fb_ofs, vo = vram_ofs; for (p=0; pfb->bytes_per_line; } } break; } /* * Extend the real framebuffer to encompass the area * just written to: */ /* Offset to take the margin into account first... */ d->fb_update_x1 += PVR_MARGIN; d->fb_update_y1 += PVR_MARGIN; d->fb_update_x2 += PVR_MARGIN; d->fb_update_y2 += PVR_MARGIN; if (d->fb_update_x1 < d->fb->update_x1 || d->fb->update_x1 < 0) d->fb->update_x1 = d->fb_update_x1; if (d->fb_update_x2 > d->fb->update_x2 || d->fb->update_x2 < 0) d->fb->update_x2 = d->fb_update_x2; if (d->fb_update_y1 < d->fb->update_y1 || d->fb->update_y1 < 0) d->fb->update_y1 = d->fb_update_y1; if (d->fb_update_y2 > d->fb->update_y2 || d->fb->update_y2 < 0) d->fb->update_y2 = d->fb_update_y2; /* Clear the PVR's update region: */ d->fb_update_x1 = d->fb_update_x2 = d->fb_update_y1 = d->fb_update_y2 = -1; } DEVICE_ACCESS(pvr_vram_alt) { struct pvr_data_alt *d_alt = (struct pvr_data_alt *) extra; struct pvr_data *d = d_alt->d; size_t i; if (writeflag == MEM_READ) { /* Copy from real vram: */ for (i=0; i> 1); data[i] = d->vram[addr % VRAM_SIZE]; } return 1; } // Writes are only allowed as 16-bit access or higher. if (len < sizeof(uint16_t)) fatal("pvr_vram_alt: write of less than 16 bits attempted?\n"); /* * Convert writes to alternative VRAM, into normal writes: */ for (i=0; i> 1); // printf(" %08x => alt addr %08x: %02x\n", (int)(relative_addr + i), (int)addr, data[i]); d->vram[addr % VRAM_SIZE] = data[i]; // TODO: This is probably ultra-slow. (Should not be called // for every _byte_.) pvr_extend_update_region(d, addr, addr); } return 1; } DEVICE_ACCESS(pvr_vram) { struct pvr_data *d = (struct pvr_data *) extra; // According to http://mc.pp.se/dc/pvr.html, reads of any size are // allowed. if (writeflag == MEM_READ) { memcpy(data, d->vram + relative_addr, len); return 1; } // However, writes are only allowed as 16-bit access or higher. if (len < sizeof(uint16_t)) fatal("pvr_vram: write of less than 16 bits attempted?\n"); /* * Write to VRAM: * * Calculate which part of the framebuffer this write corresponds to, * if any, and increase the update region to encompass the written * memory range. */ memcpy(d->vram + relative_addr, data, len); pvr_extend_update_region(d, relative_addr, relative_addr + len - 1); return 1; } DEVINIT(pvr) { struct machine *machine = devinit->machine; struct pvr_data *d; struct pvr_data_alt *d_alt; CHECK_ALLOCATION(d = (struct pvr_data *) malloc(sizeof(struct pvr_data))); memset(d, 0, sizeof(struct pvr_data)); CHECK_ALLOCATION(d_alt = (struct pvr_data_alt *) malloc(sizeof(struct pvr_data_alt))); memset(d_alt, 0, sizeof(struct pvr_data_alt)); d_alt->d = d; memory_device_register(machine->memory, devinit->name, PVRREG_REGSTART, PVRREG_REGSIZE, dev_pvr_access, d, DM_DEFAULT, NULL); /* 8 MB video RAM: */ d->vram = (uint8_t *) zeroed_alloc(VRAM_SIZE); memory_device_register(machine->memory, "pvr_vram", 0x05000000, VRAM_SIZE, dev_pvr_vram_access, (void *)d, DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK | DM_READS_HAVE_NO_SIDE_EFFECTS, d->vram); /* 8 MB video RAM, when accessed at 0xa4000000: */ memory_device_register(machine->memory, "pvr_alt_vram", 0x04000000, VRAM_SIZE, dev_pvr_vram_alt_access, (void *)d_alt, DM_DEFAULT, NULL); /* Tile Accelerator command area at 0x10000000: */ memory_device_register(machine->memory, "pvr_ta", 0x10000000, 0x800000, dev_pvr_ta_access, d, DM_DEFAULT, NULL); /* PVR2 DMA registers at 0x5f6800: */ memory_device_register(machine->memory, "pvr_dma", 0x005f6800, PVR_DMA_MEMLENGTH, dev_pvr_dma_access, d, DM_DEFAULT, NULL); /* More DMA registers at 0x5f7c00: */ memory_device_register(machine->memory, "pvr_dma_more", 0x005f7c00, PVR_DMA_MEMLENGTH, dev_pvr_dma_more_access, d, DM_DEFAULT, NULL); d->xsize = 640; d->ysize = 480; d->pixelmode = 1; /* RGB565 */ d->bytes_per_pixel = 2; d->fb = dev_fb_init(machine, machine->memory, INTERNAL_FB_ADDR, VFB_GENERIC, d->xsize + PVR_MARGIN*2, d->ysize + PVR_MARGIN*2, d->xsize + PVR_MARGIN*2, d->ysize + PVR_MARGIN*2, 24, "Dreamcast PVR"); d->vblank_timer = timer_add(PVR_VBLANK_HZ, pvr_vblank_timer_tick, d); pvr_reset(d); pvr_reset_ta(d); machine_add_tickfunction(machine, dev_pvr_fb_tick, d, PVR_FB_TICK_SHIFT); return 1; } gxemul-0.6.1/src/devices/device.cc000644 001750 001750 00000026431 13402411502 017212 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2013 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Device registry framework */ #include #include #include #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" static struct device_entry *device_entries = NULL; static int device_entries_sorted = 0; static int n_device_entries = 0; static int device_exit_on_error = 1; static struct pci_entry *pci_entries = NULL; static int n_pci_entries = 0; /* * device_entry_compar(): * * Internal function, used by sort_entries(). */ static int device_entry_compar(const void *a, const void *b) { const struct device_entry *pa = (const struct device_entry *) a; const struct device_entry *pb = (const struct device_entry *) b; return strcmp(pa->name, pb->name); } /* * sort_entries(): * * Internal function. Sorts the device_entries array in alphabetic order. */ static void sort_entries(void) { qsort(device_entries, n_device_entries, sizeof(struct device_entry), device_entry_compar); device_entries_sorted = 1; } /* * device_register(): * * Registers a device. The device is added to the end of the device_entries * array, and the sorted flag is set to zero. * * NOTE: It would be a bad thing if two devices had the same name. However, * that isn't checked here, it is up to the caller! * * Return value is 1 if the device was registered, 0 otherwise. */ int device_register(const char *name, int (*initf)(struct devinit *)) { CHECK_ALLOCATION(device_entries = (struct device_entry *) realloc(device_entries, sizeof(struct device_entry) * (n_device_entries + 1))); memset(&device_entries[n_device_entries], 0, sizeof(struct device_entry)); CHECK_ALLOCATION(device_entries[n_device_entries].name = strdup(name)); device_entries[n_device_entries].initf = initf; device_entries_sorted = 0; n_device_entries ++; return 1; } /* * pci_register(): * * Registers a pci device. The pci device is added to the pci_entries array. * * Return value is 1 if the pci device was registered. If it was not * added, this function does not return. */ int pci_register(const char *name, void (*initf)(struct machine *, struct memory *, struct pci_device *)) { CHECK_ALLOCATION(pci_entries = (struct pci_entry *) realloc(pci_entries, sizeof(struct pci_entry) * (n_pci_entries + 1))); memset(&pci_entries[n_pci_entries], 0, sizeof(struct pci_entry)); CHECK_ALLOCATION(pci_entries[n_pci_entries].name = strdup(name)); pci_entries[n_pci_entries].initf = initf; n_pci_entries ++; return 1; } /* * pci_lookup_initf(): * * Find a pci device init function by scanning the pci_entries array. * * Return value is a function pointer, or NULL if the name was not found. */ void (*pci_lookup_initf(const char *name))(struct machine *machine, struct memory *mem, struct pci_device *pd) { int i; if (name == NULL) { fprintf(stderr, "pci_lookup_initf(): name = NULL\n"); exit(1); } for (i=0; i 0) lo = i + 1; } return NULL; } /* * device_unregister(): * * Unregisters a device. * * Return value is 1 if a device was unregistered, 0 otherwise. */ int device_unregister(char *name) { ssize_t i; struct device_entry *p = device_lookup(name); if (p == NULL) { fatal("device_unregister(): no such device (\"%s\")\n", name); return 0; } i = (size_t)p - (size_t)device_entries; i /= sizeof(struct device_entry); free(device_entries[i].name); device_entries[i].name = NULL; if (i == n_device_entries-1) { /* Do nothing if we're removing the last array element. */ } else { /* Remove array element i by copying the last element to i's position: */ device_entries[i] = device_entries[n_device_entries-1]; /* The array is not sorted anymore: */ device_entries_sorted = 0; } n_device_entries --; /* TODO: realloc? */ return 1; } /* * device_add(): * * Add a device to a machine. For example: "kn210 addr=0x12340000" adds a * device called "kn210" at a specific address. * * TODO: This function is quite ugly, and should be cleaned up. */ void *device_add(struct machine *machine, const char *name_and_params) { struct device_entry *p; struct devinit devinit; const char *s2; const char *s3; size_t len, interrupt_path_len = strlen(machine->path) + 100; int quoted; memset(&devinit, 0, sizeof(struct devinit)); devinit.machine = machine; /* Default values: */ devinit.addr_mult = 1; devinit.in_use = 1; /* Get the device name first: */ s2 = name_and_params; while (s2[0] != ',' && s2[0] != ' ' && s2[0] != '\0') s2 ++; len = (size_t)s2 - (size_t)name_and_params; CHECK_ALLOCATION(devinit.name = (char *) malloc(len + 1)); memcpy(devinit.name, name_and_params, len); devinit.name[len] = '\0'; /* Allocate space for the default interrupt name: */ CHECK_ALLOCATION(devinit.interrupt_path = (char *) malloc(interrupt_path_len + 1)); snprintf(devinit.interrupt_path, interrupt_path_len, "%s.cpu[%i]", machine->path, machine->bootstrap_cpu); p = device_lookup(devinit.name); if (p == NULL) { fatal("no such device (\"%s\")\n", devinit.name); if (device_exit_on_error) exit(1); else goto return_fail; } /* Get params from name_and_params: */ while (*s2 != '\0') { /* Skip spaces, commas, and semicolons: */ while (*s2 == ' ' || *s2 == ',' || *s2 == ';') s2 ++; if (*s2 == '\0') break; /* s2 now points to the next param. eg "addr=1234" */ /* Get a word (until there is a '=' sign): */ s3 = s2; while (*s3 != '=' && *s3 != '\0') s3 ++; if (s3 == s2) { fatal("weird param: %s\n", s2); if (device_exit_on_error) exit(1); else goto return_fail; } s3 ++; /* s3 now points to the parameter value ("1234") */ if (strncmp(s2, "addr=", 5) == 0) { devinit.addr = mystrtoull(s3, NULL, 0); } else if (strncmp(s2, "addr2=", 6) == 0) { devinit.addr2 = mystrtoull(s3, NULL, 0); } else if (strncmp(s2, "len=", 4) == 0) { devinit.len = mystrtoull(s3, NULL, 0); } else if (strncmp(s2, "addr_mult=", 10) == 0) { devinit.addr_mult = mystrtoull(s3, NULL, 0); } else if (strncmp(s2, "pci_little_endian=", 18) == 0) { devinit.pci_little_endian = mystrtoull(s3, NULL, 0); switch (devinit.pci_little_endian) { case 0: break; case 1: devinit.pci_little_endian = MEM_PCI_LITTLE_ENDIAN; break; default:fatal("Bad pci_little_endian value.\n"); exit(1); } } else if (strncmp(s2, "irq=", 4) == 0) { snprintf(devinit.interrupt_path, interrupt_path_len, "%s", s3); if (strchr(devinit.interrupt_path, ' ') != NULL) *strchr(devinit.interrupt_path, ' ') = '\0'; } else if (strncmp(s2, "in_use=", 7) == 0) { devinit.in_use = mystrtoull(s3, NULL, 0); } else if (strncmp(s2, "name2=", 6) == 0) { const char *h = s2 + 6; size_t len2 = 0; quoted = 0; while (*h) { if (*h == '\'') quoted = !quoted; h++, len2++; if (!quoted && *h == ' ') break; } CHECK_ALLOCATION(devinit.name2 = (char *) malloc(len2 + 1)); h = s2 + 6; if (*h == '\'') len2 -= 2, h++; snprintf(devinit.name2, len2 + 1, "%s", h); } else { fatal("unknown param: %s\n", s2); if (device_exit_on_error) exit(1); else goto return_fail; } /* skip to the next param: */ s2 = s3; quoted = 0; while (*s2 != '\0' && (*s2 != ' ' || quoted) && *s2 != ',' && *s2 != ';') { if (*s2 == '\'') quoted = !quoted; s2 ++; } } /* * Call the init function for this device: */ devinit.return_ptr = NULL; if (!p->initf(&devinit)) { fatal("error adding device (\"%s\")\n", name_and_params); if (device_exit_on_error) exit(1); else goto return_fail; } free(devinit.interrupt_path); free(devinit.name); return devinit.return_ptr; return_fail: free(devinit.name); return NULL; } /* * device_dumplist(): * * Dump a list of all registered devices. (If the list is not sorted when * this function is called, it is implicitly sorted.) */ void device_dumplist(void) { int i; if (!device_entries_sorted) sort_entries(); for (i=0; i #include #include #include "cpu.h" #include "console.h" #include "device.h" #include "devices.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/sccreg.h" // similar to sio? #include "thirdparty/hitachi_hm53462_rop.h" #include "thirdparty/luna88k_board.h" #include "thirdparty/m8820x.h" #define TICK_STEPS_SHIFT 14 #define LUNA88K_REGISTERS_BASE 0x3ffffff0UL #define LUNA88K_REGISTERS_END 0xff000000UL #define LUNA88K_REGISTERS_LENGTH (LUNA88K_REGISTERS_END - LUNA88K_REGISTERS_BASE) #define MAX_CPUS 4 #define BCD(x) ((((x) / 10) << 4) + ((x) % 10)) struct luna88k_data { struct vfb_data *fb; struct interrupt cpu_irq; bool irqActive; uint32_t interrupt_enable[MAX_CPUS]; uint32_t interrupt_status[MAX_CPUS]; uint32_t software_interrupt_status[MAX_CPUS]; int timer_tick_counter_bogus; struct interrupt timer_irq; int console_handle; int interrupt_delay; struct interrupt irqX; /* Two channels. */ int obio_sio_regno[2]; uint8_t obio_sio_rr[2][8]; uint8_t obio_sio_wr[2][8]; uint32_t fuse_rom[FUSE_ROM_SPACE / sizeof(uint32_t)]; uint8_t nvram[NVRAM_SPACE]; }; static void reassert_interrupts(struct luna88k_data *d) { // printf("status = 0x%08x, enable = 0x%08x\n", // d->interrupt_status[0], d->interrupt_enable[0]); if (d->interrupt_status[0] & d->interrupt_enable[0]) { if (!d->irqActive) INTERRUPT_ASSERT(d->cpu_irq); d->irqActive = true; } else { if (d->irqActive) INTERRUPT_DEASSERT(d->cpu_irq); d->irqActive = false; } } static void luna88k_interrupt_assert(struct interrupt *interrupt) { struct luna88k_data *d = (struct luna88k_data *) interrupt->extra; d->interrupt_status[0] |= (1 << (interrupt->line + 25)); reassert_interrupts(d); } static void luna88k_interrupt_deassert(struct interrupt *interrupt) { struct luna88k_data *d = (struct luna88k_data *) interrupt->extra; d->interrupt_status[0] &= ~(1 << (interrupt->line + 25)); reassert_interrupts(d); } static void reassert_serial_interrupt(struct luna88k_data* d) { bool assertSerial = false; if (d->fb != NULL) { /* Workstation keyboard: */ if ((d->obio_sio_wr[1][SCC_WR1] & SCC_WR1_RXI_ALL_CHAR) || (d->obio_sio_wr[1][SCC_WR1] & SCC_WR1_RXI_FIRST_CHAR)) { if (console_charavail(d->console_handle)) assertSerial = true; } } else { /* Serial: */ if ((d->obio_sio_wr[0][SCC_WR1] & SCC_WR1_RXI_ALL_CHAR) || (d->obio_sio_wr[0][SCC_WR1] & SCC_WR1_RXI_FIRST_CHAR)) { if (console_charavail(d->console_handle)) assertSerial = true; } } if (d->obio_sio_wr[0][SCC_WR1] & SCC_WR1_TX_IE) { assertSerial = true; } if (d->interrupt_delay > 0) { assertSerial = false; d->interrupt_delay --; } if (assertSerial) { INTERRUPT_ASSERT(d->irqX); d->interrupt_delay = 130; } else { INTERRUPT_DEASSERT(d->irqX); } } DEVICE_TICK(luna88k) { struct luna88k_data *d = (struct luna88k_data *) extra; /* TODO: Correct timing. */ if (d->timer_tick_counter_bogus < 3) { if (++d->timer_tick_counter_bogus >= 3) INTERRUPT_ASSERT(d->timer_irq); } /* Serial: */ reassert_serial_interrupt(d); } static void swapBitOrder(uint8_t* data, int len) { for (int bo = 0; bo < len; bo ++) { uint8_t b = (uint8_t)data[bo]; uint8_t c = 0x00; for (int i = 0; i < 8; i++) { if (b & (128 >> i)) c |= (1 << i); } data[bo] = c; } } DEVICE_ACCESS(luna88k) { struct tm *tmp; time_t timet; uint32_t addr = relative_addr + LUNA88K_REGISTERS_BASE; uint64_t idata = 0, odata = 0; struct luna88k_data *d = (struct luna88k_data *) extra; int cpunr; int sio_devnr; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (addr >= FUSE_ROM_ADDR && len == sizeof(uint32_t) && addr < FUSE_ROM_ADDR + FUSE_ROM_SPACE) { if (writeflag == MEM_READ) { odata = d->fuse_rom[(addr - FUSE_ROM_ADDR) / sizeof(uint32_t)]; memory_writemax64(cpu, data, len, odata); } else { d->fuse_rom[(addr - FUSE_ROM_ADDR) / sizeof(uint32_t)] = idata; } return 1; } if (addr >= FUSE_ROM_ADDR && len == sizeof(uint8_t) && addr < FUSE_ROM_ADDR + FUSE_ROM_SPACE) { if (writeflag == MEM_READ) { odata = d->fuse_rom[(addr - FUSE_ROM_ADDR) / sizeof(uint32_t)]; odata >>= ((3 - (addr & 3)) * 8); memory_writemax64(cpu, data, len, odata); } else { fatal("TODO: luna88k byte write to fuse\n"); } return 1; } if (addr >= NVRAM_ADDR && addr + len <= NVRAM_ADDR + NVRAM_SPACE) { size_t offset = addr - NVRAM_ADDR; if (writeflag == MEM_READ) { memmove(data, d->nvram + offset, len); } else { memmove(d->nvram + offset, data, len); } return 1; } if (addr >= NVRAM_ADDR_88K2 && addr < NVRAM_ADDR_88K2 + NVRAM_SPACE && len == sizeof(uint8_t)) { if (writeflag == MEM_READ) { odata = d->nvram[addr - NVRAM_ADDR_88K2]; memory_writemax64(cpu, data, len, odata); } else { d->nvram[addr - NVRAM_ADDR_88K2] = idata; } return 1; } if (addr >= BMAP_BMP && addr < BMAP_BMP + 0x40000) { // X resolution is 1280, but stride is 2048. uint32_t s = 2048 * 1024 / 8; addr -= (uint64_t)(uint32_t)(BMAP_BMP); swapBitOrder(data, len); if (addr + len - 1 < s) { if (addr >= 8) addr -= 8; dev_fb_access(cpu, cpu->mem, addr, data, len, writeflag, d->fb); swapBitOrder(data, len); return 1; } else return 1; } if (addr >= BMAP_BMAP0 && addr < BMAP_BMAP0 + 0x40000) { // X resolution is 1280, but stride is 2048. uint32_t s = 2048 * 1024 / 8; addr -= (uint64_t)(uint32_t)(BMAP_BMAP0); swapBitOrder(data, len); if (addr + len - 1 < s) { if (addr >= 8) addr -= 8; dev_fb_access(cpu, cpu->mem, addr, data, len, writeflag, d->fb); swapBitOrder(data, len); return 1; } else return 1; } if (addr >= BMAP_PALLET2 && addr < BMAP_PALLET2 + 16) { /* Ignore for now. */ return 1; } if (addr >= TRI_PORT_RAM && addr < TRI_PORT_RAM + TRI_PORT_RAM_SPACE) { /* Ignore for now. */ return 1; } switch (addr) { case 0x3ffffff0: /* Accessed by OpenBSD/luna88k to trigger an illegal address */ cpu->cd.m88k.cmmu[1]->reg[CMMU_PFSR] = CMMU_PFSR_BERROR << 16; break; case PROM_ADDR: /* 0x41000000 */ /* OpenBSD/luna88k write here during boot. Ignore for now. (?) */ break; case OBIO_CAL_CTL: /* calendar control register */ break; case OBIO_CAL_SEC: timet = time(NULL); tmp = gmtime(&timet); odata = BCD(tmp->tm_sec) << 24; break; case OBIO_CAL_MIN: timet = time(NULL); tmp = gmtime(&timet); odata = BCD(tmp->tm_min) << 24; break; case OBIO_CAL_HOUR: timet = time(NULL); tmp = gmtime(&timet); odata = BCD(tmp->tm_hour) << 24; break; case OBIO_CAL_DOW: timet = time(NULL); tmp = gmtime(&timet); odata = BCD(tmp->tm_wday + 0) << 24; break; case OBIO_CAL_DAY: timet = time(NULL); tmp = gmtime(&timet); odata = BCD(tmp->tm_mday) << 24; break; case OBIO_CAL_MON: timet = time(NULL); tmp = gmtime(&timet); odata = BCD(tmp->tm_mon + 1) << 24; break; case OBIO_CAL_YEAR: timet = time(NULL); tmp = gmtime(&timet); odata = BCD(tmp->tm_year - 2000) << 24; // ? break; case OBIO_PIO0A: /* 0x49000000: PIO-0 port A */ /* OpenBSD reads dipswitch settings from PIO0A and B. */ odata = 0; // high byte if (cpu->machine->x11_md.in_use) odata |= 0x40; odata |= 0x80; // multi-user mode odata |= 0x20; // don't ask name odata |= 0x10; // don't do manual UKC config break; case OBIO_PIO0B: /* 0x49000004: PIO-0 port B */ /* OpenBSD reads dipswitch settings from PIO0A and B. */ odata = 0x00; // low byte break; case OBIO_PIO0: /* 0x4900000C: PIO-0 control */ /* TODO: Implement for real. */ break; case OBIO_PIO1A: /* 0x4d000000: PIO-0 port A */ case OBIO_PIO1B: /* 0x4d000004: PIO-0 port B */ case OBIO_PIO1: /* 0x4d00000C: PIO-0 control */ /* Ignore for now. (?) */ break; case OBIO_SIO + 0: /* 0x51000000: data channel 0 */ case OBIO_SIO + 4: /* 0x51000004: cmd channel 0 */ case OBIO_SIO + 8: /* 0x51000008: data channel 1 */ case OBIO_SIO + 0xc: /* 0x5100000c: cmd channel 1 */ sio_devnr = ((addr - OBIO_SIO) / 8) & 1; if ((addr - OBIO_SIO) & 4) { /* cmd */ /* Similar to dev_scc.cc ? */ if (writeflag == MEM_WRITE) { if (d->obio_sio_regno[sio_devnr] == 0) { int regnr = idata & 7; d->obio_sio_regno[sio_devnr] = regnr; // printf("[ sio: setting regno for next operation to 0x%02x ]\n", (int)regnr); /* High bits are command. */ } else { int regnr = d->obio_sio_regno[sio_devnr] & 7; d->obio_sio_wr[sio_devnr][regnr] = idata; // printf("[ sio: setting reg 0x%02x = 0x%02x ]\n", d->obio_sio_regno[sio_devnr], (int)idata); d->obio_sio_regno[sio_devnr] = 0; reassert_serial_interrupt(d); } } else { d->obio_sio_rr[sio_devnr][SCC_RR0] = SCC_RR0_TX_EMPTY | SCC_RR0_DCD | SCC_RR0_CTS; if (console_charavail(d->console_handle) && ( (d->fb == NULL && sio_devnr == 0) || (d->fb != NULL && sio_devnr == 1)) ) d->obio_sio_rr[sio_devnr][SCC_RR0] |= SCC_RR0_RX_AVAIL; d->obio_sio_rr[sio_devnr][SCC_RR1] = SCC_RR1_ALL_SENT; int regnr = d->obio_sio_regno[sio_devnr] & 7; odata = d->obio_sio_rr[sio_devnr][regnr]; // printf("[ sio: reading reg 0x%02x: 0x%02x ]\n", regnr, (int)odata); d->obio_sio_regno[sio_devnr] = 0; } } else { /* data */ if (writeflag == MEM_WRITE) { if (sio_devnr == 0) { console_putchar(cpu->machine->main_console_handle, idata); } else fatal("[ luna88k sio dev1 write data: TODO ]\n"); } else { if (sio_devnr == 0) { if (d->fb == NULL && console_charavail(d->console_handle)) { odata = console_readchar(d->console_handle); } } else { fatal("[ luna88k sio dev1 read data: TODO ]\n"); } } INTERRUPT_DEASSERT(d->irqX); } break; case OBIO_CLOCK0: /* 0x63000000: Clock ack? */ d->timer_tick_counter_bogus = 0; INTERRUPT_DEASSERT(d->timer_irq); break; case INT_ST_MASK0: /* 0x65000000: Interrupt status CPU 0. */ case INT_ST_MASK1: /* 0x65000004: Interrupt status CPU 1. */ case INT_ST_MASK2: /* 0x65000008: Interrupt status CPU 2. */ case INT_ST_MASK3: /* 0x6500000c: Interrupt status CPU 3. */ /* * From OpenBSD/luna88k machdep.c source code: * * On write: Bits 31..26 are used to enable/disable levels 6..1. * On read: Bits 31..29 show value 0-7 of current interrupt. * Bits 23..18 show current mask. */ cpunr = (addr - INT_ST_MASK0) / 4; if (writeflag == MEM_WRITE) { if ((idata & 0x03ffffff) != 0x00000000) { fatal("[ TODO: luna88k interrupts, idata = 0x%08x, what to do with low bits? ]\n", (uint32_t)idata); exit(1); } d->interrupt_enable[cpunr] = idata; reassert_interrupts(d); } else { uint32_t currentMask = d->interrupt_enable[cpunr]; int highestCurrentStatus = 0; odata = currentMask >> 8; for (int i = 1; i <= 6; ++i) { int m = 1 << (25 + i); if (d->interrupt_status[cpunr] & m) highestCurrentStatus = i; } odata |= (highestCurrentStatus << 29); // printf("highest = %i 0x%08x\n", highestCurrentStatus, (int)odata); } break; case SOFT_INT0: /* 0x69000000: Software Interrupt status CPU 0. */ case SOFT_INT1: /* 0x69000004: Software Interrupt status CPU 1. */ case SOFT_INT2: /* 0x69000008: Software Interrupt status CPU 2. */ case SOFT_INT3: /* 0x6900000c: Software Interrupt status CPU 3. */ cpunr = (addr - SOFT_INT0) / 4; odata = d->software_interrupt_status[cpunr]; // Reading status clears it. d->software_interrupt_status[cpunr] = 0; if (writeflag == MEM_WRITE) { fatal("TODO: luna88k write to software interrupts\n"); exit(1); } break; case RESET_CPU_ALL: /* 0x6d000010: Reset all CPUs */ cpu->running = 0; break; case BMAP_RFCNT: /* 0xb1000000: RFCNT register */ /* video h-origin/v-origin, according to OpenBSD */ /* Ignore for now. (?) */ break; case BMAP_BMSEL: /* 0xb1000000: BMSEL register */ /* Ignore for now. (?) */ break; case BMAP_BMAP1: /* 0xb1100000: Bitmap plane 1 */ odata = 0xc0dec0de; /* Return dummy value. OpenBSD writes and reads to detect presence of bitplanes. */ break; case BMAP_FN + 4 * ROP_THROUGH: /* 0xb12c0014: "common bitmap function" */ /* Function 5 is "ROP copy", according to OpenBSD sources. */ /* See hitachi_hm53462_rop.h */ if (writeflag == MEM_READ) { fatal("[ TODO: luna88k READ from BMAP_FN ROP register? ]\n"); cpu->running = 0; return 0; } if (idata != 0xffffffff) { fatal("[ TODO: luna88k write which does not set ALL bits? ]\n"); cpu->running = 0; return 0; } break; case SCSI_ADDR + 0x00: /* 0xe1000000: SCSI .. */ case SCSI_ADDR + 0x04: /* 0xe1000004: SCSI .. */ case SCSI_ADDR + 0x08: /* 0xe1000008: SCSI .. */ case SCSI_ADDR + 0x0C: /* 0xe100000C: SCSI .. */ case SCSI_ADDR + 0x20: /* 0xe1000020: SCSI .. */ case SCSI_ADDR + 0x2c: /* 0xe100002c: SCSI .. */ case SCSI_ADDR + 0x30: /* 0xe1000030: SCSI .. */ case SCSI_ADDR + 0x34: /* 0xe1000034: SCSI .. */ case SCSI_ADDR + 0x38: /* 0xe1000038: SCSI .. */ case SCSI_ADDR + 0x40: /* 0xe1000040: SCSI .. */ case SCSI_ADDR + 0x44: /* 0xe1000044: SCSI .. */ case SCSI_ADDR + 0x48: /* 0xe1000048: SCSI .. */ case SCSI_ADDR + 0x4c: /* 0xe100004c: SCSI .. */ case SCSI_ADDR + 0x50: /* 0xe1000050: SCSI .. */ case SCSI_ADDR + 0x60: /* 0xe1000060: SCSI .. */ case SCSI_ADDR + 0x6c: /* 0xe100006c: SCSI .. */ case SCSI_ADDR + 0x70: /* 0xe1000070: SCSI .. */ case SCSI_ADDR + 0x74: /* 0xe1000074: SCSI .. */ case SCSI_ADDR + 0x78: /* 0xe1000078: SCSI .. */ /* MB89352 SCSI Protocol Controller */ /* Ignore for now. (?) */ break; case SCSI_ADDR + 0x10: /* 0xe1000010: SCSI INTS */ odata = 0xffffffff; break; case 0xf1000000: /* Lance Ethernet. TODO. */ case 0xf1000004: case 0xf1000008: break; default:fatal("[ luna88k: unimplemented %s address 0x%x", writeflag == MEM_WRITE? "write to" : "read from", (int) addr); if (writeflag == MEM_WRITE) fatal(": 0x%x", (int)idata); fatal(" (%i bits) ]\n", len * 8); exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } void add_cmmu_for_cpu(struct devinit* devinit, int cpunr, uint32_t iaddr, uint32_t daddr) { char tmpstr[300]; struct m8820x_cmmu *cmmu; /* Instruction CMMU: */ CHECK_ALLOCATION(cmmu = (struct m8820x_cmmu *) malloc(sizeof(struct m8820x_cmmu))); memset(cmmu, 0, sizeof(struct m8820x_cmmu)); if (cpunr < devinit->machine->ncpus) devinit->machine->cpus[cpunr]->cd.m88k.cmmu[0] = cmmu; /* This is a 88200, revision 9: */ cmmu->reg[CMMU_IDR] = (M88200_ID << 21) | (9 << 16); snprintf(tmpstr, sizeof(tmpstr), "m8820x addr=0x%x addr2=0", iaddr); device_add(devinit->machine, tmpstr); /* ... and data CMMU: */ CHECK_ALLOCATION(cmmu = (struct m8820x_cmmu *) malloc(sizeof(struct m8820x_cmmu))); memset(cmmu, 0, sizeof(struct m8820x_cmmu)); if (cpunr < devinit->machine->ncpus) devinit->machine->cpus[cpunr]->cd.m88k.cmmu[1] = cmmu; /* This is also a 88200, revision 9: */ cmmu->reg[CMMU_IDR] = (M88200_ID << 21) | (9 << 16); cmmu->batc[8] = BATC8; cmmu->batc[9] = BATC9; snprintf(tmpstr, sizeof(tmpstr), "m8820x addr=0x%x addr2=1", daddr); device_add(devinit->machine, tmpstr); } DEVINIT(luna88k) { char n[100]; struct luna88k_data *d; CHECK_ALLOCATION(d = (struct luna88k_data *) malloc(sizeof(struct luna88k_data))); memset(d, 0, sizeof(struct luna88k_data)); memory_device_register(devinit->machine->memory, devinit->name, LUNA88K_REGISTERS_BASE, LUNA88K_REGISTERS_LENGTH, dev_luna88k_access, (void *)d, DM_DEFAULT, NULL); /* * Connect to the CPU's interrupt pin, and register * 6 hardware interrupts: */ INTERRUPT_CONNECT(devinit->interrupt_path, d->cpu_irq); for (int i = 1; i <= 6; i++) { struct interrupt templ; snprintf(n, sizeof(n), "%s.luna88k.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = n; templ.extra = d; templ.interrupt_assert = luna88k_interrupt_assert; templ.interrupt_deassert = luna88k_interrupt_deassert; // debug("registering irq: %s\n", n); interrupt_handler_register(&templ); } /* Timer. */ snprintf(n, sizeof(n), "%s.luna88k.6", devinit->interrupt_path); INTERRUPT_CONNECT(n, d->timer_irq); machine_add_tickfunction(devinit->machine, dev_luna88k_tick, d, TICK_STEPS_SHIFT); /* IRQ 5,4,3 (?): "autovec" according to OpenBSD */ snprintf(n, sizeof(n), "%s.luna88k.5", devinit->interrupt_path); INTERRUPT_CONNECT(n, d->irqX); d->console_handle = console_start_slave(devinit->machine, "SIO", 1); if (devinit->machine->x11_md.in_use) { d->fb = dev_fb_init(devinit->machine, devinit->machine->memory, 0x100000000ULL + BMAP_BMAP0, VFB_GENERIC, 1280, 1024, 2048, 1024, 1, "LUNA 88K"); } if (devinit->machine->ncpus > 4) { printf("LUNA 88K can't have more than 4 CPUs.\n"); exit(1); } add_cmmu_for_cpu(devinit, 0, CMMU_I0, CMMU_D0); add_cmmu_for_cpu(devinit, 1, CMMU_I1, CMMU_D1); add_cmmu_for_cpu(devinit, 2, CMMU_I2, CMMU_D2); add_cmmu_for_cpu(devinit, 3, CMMU_I3, CMMU_D3); return 1; } gxemul-0.6.1/src/devices/dev_dreamcast_rtc.cc000644 001750 001750 00000007006 13402411502 021421 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2014 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Dreamcast Real-Time Clock * * Pretty basic; two 32-bit words at physical addresses 0x00710000 and * 0x00710004 hold the high and low 16-bit parts, respectively, of the * system's 32-bit tv_sec value. * * The only difference from the raw Unix concept is that the Dreamcast's * clock is based at 1950 instead of 1970. */ #include #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #define debug fatal struct dreamcast_rtc_data { int dummy; }; DEVICE_ACCESS(dreamcast_rtc) { /* struct dreamcast_rtc_data *d = extra; */ uint64_t idata = 0, odata = 0; struct timeval tv; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0: case 4: /* * While writing to the RTC could set the date/time of the * host, that would probably be very annoying. For now, * simply ignore writes. */ if (writeflag == MEM_WRITE) break; gettimeofday(&tv, NULL); /* Offset by 20 years: */ odata = tv.tv_sec + 631152000; if (relative_addr == 0) odata = (odata >> 16) & 0xffff; else odata &= 0xffff; break; case 8: /* * The Dreamcast PROM writes a 1 here when setting the * date/time. Let's ignore it for now. */ break; default: if (writeflag == MEM_READ) { fatal("[ dreamcast_rtc: read from addr 0x%x ]\n", (int)relative_addr); } else { fatal("[ dreamcast_rtc: write to addr 0x%x: 0x%x ]\n", (int)relative_addr, (int)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(dreamcast_rtc) { struct dreamcast_rtc_data *d; CHECK_ALLOCATION(d = (struct dreamcast_rtc_data *) malloc(sizeof(struct dreamcast_rtc_data))); memset(d, 0, sizeof(struct dreamcast_rtc_data)); memory_device_register(devinit->machine->memory, devinit->name, 0x00710000, 0x100, dev_dreamcast_rtc_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_sgi_mec.cc000644 001750 001750 00000046075 13402411502 020225 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SGI IP32 "mec" ethernet * * Used by the SGI O2 emulation mode. * Based on how NetBSD and OpenBSD use the hardware, just about enough to let * those OSes boot with root-on-nfs. * * http://www.openbsd.org/cgi-bin/cvsweb/src/sys/arch/sgi/dev/if_mec.c * * TODO: * * x) tx and rx interrupts/ring/slot stuff * * A note about word length for reads/writes: * * NetBSD uses (at least) 64-bit reads/writes. * OpenBSD uses both 32-bit and 64-bit reads/writes. * The PROM uses (at least) 32-bit reads/writes and 16-bit reads (from * offsets 0x34 and 0x36)! * * Random googling reveals this NetBSD dmesg about the PHYs: * * https://mail-index.netbsd.org/port-sgimips/2008/01/27/msg000043.html * * mec0 at mace0 offset 0x280000 intr 3 intrmask 0x0: MAC-110 Ethernet, rev 1 * mec0: Ethernet address 08:00:69:0e:85:21 * nsphy0 at mec0 phy 8: DP83840 10/100 media interface, rev. 1 * nsphy0: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto */ #include #include #include #include "bus_pci.h" #include "console.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "net.h" #include "thirdparty/if_mecreg.h" #include "thirdparty/mii.h" // #define debug fatal // #define MEC_DEBUG #define MEC_TICK_SHIFT 14 #define MAX_TX_PACKET_LEN 1700 #define N_RX_ADDRESSES 16 struct sgi_mec_data { uint64_t reg[DEV_SGI_MEC_LENGTH / sizeof(uint64_t)]; struct interrupt irq; int prev_asserted; unsigned char macaddr[6]; unsigned char cur_tx_packet[MAX_TX_PACKET_LEN]; int cur_tx_packet_len; unsigned char *cur_rx_packet; int cur_rx_packet_len; uint64_t rx_addr[N_RX_ADDRESSES]; int cur_rx_addr_index_write; int cur_rx_addr_index; }; /* * mec_reset(): */ static void mec_reset(struct sgi_mec_data *d) { if (d->cur_rx_packet != NULL) free(d->cur_rx_packet); memset(d->reg, 0, sizeof(d->reg)); } /* * mec_control_write(): */ static void mec_control_write(struct cpu *cpu, struct sgi_mec_data *d, uint64_t x) { if (x & MEC_MAC_CORE_RESET) { debug("[ sgi_mec: CORE RESET ]\n"); mec_reset(d); } } /* * mec_try_rx(): */ static int mec_try_rx(struct cpu *cpu, struct sgi_mec_data *d) { uint64_t base; unsigned char data[8]; int i, res, retval = 0; base = d->rx_addr[d->cur_rx_addr_index]; if (base & 0xfff) fatal("[ mec_try_rx(): WARNING! lowest bits of base are " "non-zero (0x%3x). TODO ]\n", (int)(base & 0xfff)); base &= 0xfffff000ULL; if (base == 0) goto skip; /* printf("rx base = 0x%016llx\n", (long long)base); */ /* Read an rx descriptor from memory: */ res = cpu->memory_rw(cpu, cpu->mem, base, &data[0], sizeof(data), MEM_READ, PHYSICAL); if (!res) return 0; /* Is this descriptor already in use? */ if (data[0] & 0x80) { /* printf("INTERRUPT for base = 0x%x\n", (int)base); */ goto skip_and_advance; } if (d->cur_rx_packet == NULL && net_ethernet_rx_avail(cpu->machine->emul->net, d)) net_ethernet_rx(cpu->machine->emul->net, d, &d->cur_rx_packet, &d->cur_rx_packet_len); if (d->cur_rx_packet == NULL) goto skip; #if 0 printf("{ mec: rxdesc %i: ", d->cur_rx_addr_index); for (i=0; icur_rx_packet_len; i++) { res = cpu->memory_rw(cpu, cpu->mem, base + 32 + i + 2, d->cur_rx_packet + i, 1, MEM_WRITE, PHYSICAL); //printf(" %02x", d->cur_rx_packet[i]); } //printf("\n"); #if 0 printf("RX: %i bytes, index %i, base = 0x%x\n", d->cur_rx_packet_len, d->cur_rx_addr_index, (int)base); #endif /* 4 bytes of CRC at the end. Hm. TODO */ d->cur_rx_packet_len += 4; memset(data, 0, sizeof(data)); data[6] = (d->cur_rx_packet_len >> 8) & 255; data[7] = d->cur_rx_packet_len & 255; /* TODO: lots of bits :-) */ data[4] = 0x04; /* match MAC */ data[0] = 0x80; /* 0x80 = received. */ res = cpu->memory_rw(cpu, cpu->mem, base, &data[0], sizeof(data), MEM_WRITE, PHYSICAL); /* Free the packet from memory: */ free(d->cur_rx_packet); d->cur_rx_packet = NULL; d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_RX_THRESHOLD; skip_and_advance: d->cur_rx_addr_index ++; d->cur_rx_addr_index %= N_RX_ADDRESSES; d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &= ~MEC_INT_RX_MCL_FIFO_ALIAS; d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= (d->cur_rx_addr_index & 0x1f) << 8; retval = 1; skip: return retval; } /* * mec_try_tx(): */ static int mec_try_tx(struct cpu *cpu, struct sgi_mec_data *d) { uint64_t base, addr, dma_base; int tx_ring_ptr, ringread, ringwrite, res, i, j; unsigned char data[32]; int len, start_offset, dma_ptr_nr, dma_len; base = d->reg[MEC_TX_RING_BASE / sizeof(uint64_t)]; tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)]; if (base == 0) return 0; /* printf("base = 0x%016llx\n", base); */ ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR; ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR; ringread >>= 16; /* All done? Then abort. */ if (ringread == ringwrite) return 0; tx_ring_ptr &= MEC_TX_RING_READ_PTR; tx_ring_ptr >>= 16; /* Each tx descriptor (+ buffer) is 128 bytes: */ addr = base + tx_ring_ptr*128; res = cpu->memory_rw(cpu, cpu->mem, addr, &data[0], sizeof(data), MEM_READ, PHYSICAL); if (!res) return 0; /* Is this packet transmitted already? */ if (data[0] & 0x80) { fatal("[ mec_try_tx: tx_ring_ptr = %i, already" " transmitted? ]\n", tx_ring_ptr); goto advance_tx; } len = data[6] * 256 + data[7]; start_offset = data[5] & 0x7f; /* Is this packet empty? Then don't transmit. */ if (len == 0) return 0; /* Hm. Is len one too little? TODO */ len ++; #if 0 printf("{ mec: txdesc %i: ", tx_ring_ptr); for (i=0; icur_tx_packet_len = len; //printf("TX: "); for (i=start_offset; imemory_rw(cpu, cpu->mem, addr + i, &ch, sizeof(ch), MEM_READ, PHYSICAL); //printf(" %02x", ch); d->cur_tx_packet[j++] = ch; if (j >= MAX_TX_PACKET_LEN) { fatal("[ mec_try_tx: packet too large? ]\n"); break; } } //printf("\n"); if (j < len) { /* Continue with DMA: */ for (;;) { dma_ptr_nr ++; if (dma_ptr_nr >= 4) break; if (!(data[4] & (0x01 << dma_ptr_nr))) break; dma_base = (data[dma_ptr_nr * 8 + 4] << 24) + (data[dma_ptr_nr * 8 + 5] << 16) + (data[dma_ptr_nr * 8 + 6] << 8) + (data[dma_ptr_nr * 8 + 7]); dma_base &= 0xfffffff8ULL; dma_len = (data[dma_ptr_nr * 8 + 2] << 8) + (data[dma_ptr_nr * 8 + 3]) + 1; /* printf("dma_base = %08x, dma_len = %i\n", (int)dma_base, dma_len); */ while (dma_len > 0) { unsigned char ch; res = cpu->memory_rw(cpu, cpu->mem, dma_base, &ch, sizeof(ch), MEM_READ, PHYSICAL); /* printf(" %02x", ch); */ d->cur_tx_packet[j++] = ch; if (j >= MAX_TX_PACKET_LEN) { fatal("[ mec_try_tx: packet too large?" " ]\n"); break; } dma_base ++; dma_len --; } } } if (j < len) fatal("[ mec_try_tx: not enough data? ]\n"); net_ethernet_tx(cpu->machine->emul->net, d, d->cur_tx_packet, d->cur_tx_packet_len); /* see openbsd's if_mec.c for details */ if (data[4] & 0x01) { d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_PACKET_SENT; } memset(data, 0, 6); /* last 2 bytes are len */ data[0] = 0x80; data[5] = 0x80; res = cpu->memory_rw(cpu, cpu->mem, addr, &data[0], sizeof(data), MEM_WRITE, PHYSICAL); d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_EMPTY; d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= MEC_INT_TX_PACKET_SENT; advance_tx: /* Advance the ring Read ptr. */ tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)]; ringread = tx_ring_ptr & MEC_TX_RING_READ_PTR; ringwrite = tx_ring_ptr & MEC_TX_RING_WRITE_PTR; ringread = (ringread >> 16) + 1; ringread &= 63; ringread <<= 16; d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] = (ringwrite & MEC_TX_RING_WRITE_PTR) | (ringread & MEC_TX_RING_READ_PTR); d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &= ~MEC_INT_TX_RING_BUFFER_ALIAS; d->reg[MEC_INT_STATUS / sizeof(uint64_t)] |= (d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)] & MEC_INT_TX_RING_BUFFER_ALIAS); return 1; } DEVICE_TICK(sgi_mec) { struct sgi_mec_data *d = (struct sgi_mec_data *) extra; int n = 0; while (mec_try_tx(cpu, d)) ; while (mec_try_rx(cpu, d) && n < 16) n++; /* Interrupts: (TODO: only when enabled) */ int asserted = !!(d->reg[MEC_INT_STATUS / sizeof(uint64_t)] & MEC_INT_STATUS_MASK); if (asserted && !d->prev_asserted) INTERRUPT_ASSERT(d->irq); else if (!asserted && d->prev_asserted) INTERRUPT_DEASSERT(d->irq); d->prev_asserted = asserted; } DEVICE_ACCESS(sgi_mec) { struct sgi_mec_data *d = (struct sgi_mec_data *) extra; uint64_t idata = 0, odata = 0; int regnr; uint64_t old_int_status = d->reg[MEC_INT_STATUS / sizeof(uint64_t)]; uint64_t old_tx_ring_ptr = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)]; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); regnr = relative_addr / sizeof(uint64_t); if ((relative_addr & ~7) == MEC_TX_RING_PTR_ALIAS) relative_addr -= 8; // Support both 32-bit and 64-bit big-endian loads and stores... if (len == sizeof(uint64_t)) { if (writeflag == MEM_WRITE) d->reg[regnr] = idata; else odata = d->reg[regnr]; } else if (len == sizeof(uint32_t)) { if (writeflag == MEM_WRITE) { if (relative_addr & 4) d->reg[regnr] = (d->reg[regnr] & ~0xffffffffULL) | (uint32_t)idata; else d->reg[regnr] = (d->reg[regnr] & 0xffffffffULL) | ((uint64_t)idata << 32ULL); } else { odata = d->reg[regnr]; if (relative_addr & 4) odata = (int32_t)odata; else odata = (odata >> 32ULL); } } else if (len == sizeof(uint16_t)) { if (writeflag == MEM_WRITE) { fatal("[ sgi_mec: unimplemented %s len %i (addr 0x%x) ]\n", writeflag ? "write" : "read", len, (long long)relative_addr); } else if ((relative_addr & 7) == 4) { odata = d->reg[regnr]; odata = (uint16_t)(odata >> 16); } else if ((relative_addr & 7) == 6) { odata = d->reg[regnr]; odata = (uint16_t)odata; } else { fatal("[ sgi_mec: unimplemented %s len %i (addr 0x%x) ]\n", writeflag ? "write" : "read", len, (long long)relative_addr); } } else { fatal("[ sgi_mec: unimplemented %s len %i (addr 0x%x) ]\n", writeflag ? "write" : "read", len, (long long)relative_addr); } #ifdef MEC_DEBUG if (writeflag == MEM_WRITE) fatal("[ sgi_mec: write to address" " 0x%llx, len %i, data=0x%016llx ]\n", (long long)relative_addr, len, (long long)idata); #endif // ... and then treat the registers as 64-bit aligned: switch (relative_addr & ~7) { case MEC_MAC_CONTROL: /* 0x00 */ if (writeflag) mec_control_write(cpu, d, idata); else { /* 1 means "Revision 2" in hinv output, as per my O2. (1 + value?) */ odata &= ~MEC_MAC_REVISION; odata |= 1 << MEC_MAC_REVISION_SHIFT; } break; case MEC_INT_STATUS: /* 0x08 */ if (writeflag) { /* Clear bits on write: (This is just a guess) */ uint64_t writtenvalue = d->reg[MEC_INT_STATUS / sizeof(uint64_t)]; d->reg[MEC_INT_STATUS / sizeof(uint64_t)] = old_int_status & ~(writtenvalue & MEC_INT_STATUS_MASK); debug("[ sgi_mec: write to MEC_INT_STATUS: " "0x%016llx ]\n", (long long)idata); } break; case MEC_DMA_CONTROL: /* 0x10 */ if (writeflag) { debug("[ sgi_mec: write to MEC_DMA_CONTROL: " "0x%016llx ]\n", (long long)idata); if (!(idata & MEC_DMA_TX_INT_ENABLE)) { /* This should apparently stop the TX Empty interrupt. */ d->reg[MEC_INT_STATUS / sizeof(uint64_t)] &= ~MEC_INT_TX_EMPTY; } } break; case MEC_TX_ALIAS: /* 0x20 */ if (writeflag) { debug("[ sgi_mec: write to MEC_TX_ALIAS: " "0x%016llx ]\n", (long long)idata); } else { debug("[ sgi_mec: read from MEC_TX_ALIAS: " "0x%016llx ]\n", (long long)idata); odata = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)]; } break; case MEC_RX_ALIAS: /* 0x28 */ if (writeflag) debug("[ sgi_mec: write to MEC_RX_ALIAS: " "0x%016llx ]\n", (long long)idata); break; case MEC_TX_RING_PTR: /* 0x30 */ if (writeflag) { uint64_t writtenvalue = d->reg[MEC_TX_RING_PTR / sizeof(uint64_t)]; writtenvalue &= MEC_TX_RING_WRITE_PTR; d->reg[regnr] = (old_tx_ring_ptr & ~MEC_TX_RING_WRITE_PTR) | writtenvalue; debug("[ sgi_mec: write to MEC_TX_RING_PTR: " "0x%016llx ]\n", (long long)idata); } break; case MEC_PHY_DATA: /* 0x60 */ { int dev = (d->reg[MEC_PHY_ADDRESS / sizeof(uint64_t)] & MEC_PHY_ADDR_DEVICE) >> MEC_PHY_ADDR_DEVSHIFT; int reg = d->reg[MEC_PHY_ADDRESS / sizeof(uint64_t)] & MEC_PHY_ADDR_REGISTER; if (writeflag) { debug("[ sgi_mec: write to MEC_PHY_DATA (dev %i, reg %i): " "0x%016llx ]\n", dev, reg, (long long)idata); } odata = 0; if (dev == 8) { // https://dmesgd.nycbug.org/index.cgi?do=view&id=2828 says: // nsphy0 at mec0 phy 8: DP83840 10/100 media interface, rev. 0 // nsphy0: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto switch (reg) { case MII_BMCR: // 0 odata = BMCR_AUTOEN; break; case MII_BMSR: // 1 odata = BMSR_100TXFDX | BMSR_100TXHDX | BMSR_10TFDX | BMSR_10THDX | BMSR_ANEG | BMSR_LINK; // LINK means cable is connected break; case MII_PHYIDR1: // 2 odata = 0x2000; // To match NetBSD's "xxNATSEMI" value. break; case MII_PHYIDR2: // 3 odata = 0x5c00; // To match NetBSD's "xxNATSEMI" value. break; case 23: // MII_NSPHY_PCR odata = 0x20; // PCR_CIMDIS break; default: fatal("[ sgi_mec: unimplemented %s PHY register %i ]\n", writeflag ? "write to" : "read from", reg); } } if (!writeflag) { debug("[ sgi_mec: read from MEC_PHY_DATA (dev %i, reg %i): " "0x%016llx ]\n", dev, reg, (long long)odata); } } break; case MEC_PHY_ADDRESS: /* 0x68 */ if (writeflag) debug("[ sgi_mec: write to MEC_PHY_ADDRESS: " "0x%016llx ]\n", (long long)idata); break; case MEC_PHY_READ_INITIATE: /* 0x70 */ if (writeflag) debug("[ sgi_mec: write to MEC_PHY_READ_INITIATE: " "0x%016llx ]\n", (long long)idata); break; case MEC_STATION: /* 0xa0 */ if (writeflag) debug("[ sgi_mec: setting the MAC address to " "%02x:%02x:%02x:%02x:%02x:%02x ]\n", (idata >> 40) & 255, (idata >> 32) & 255, (idata >> 24) & 255, (idata >> 16) & 255, (idata >> 8) & 255, (idata >> 0) & 255); else fatal("[ sgi_mec: reading the MAC address as " "%02x:%02x:%02x:%02x:%02x:%02x ]\n", (odata >> 40) & 255, (odata >> 32) & 255, (odata >> 24) & 255, (odata >> 16) & 255, (odata >> 8) & 255, (odata >> 0) & 255); break; case MEC_STATION_ALT: /* 0xa8 */ if (writeflag) debug("[ sgi_mec: setting the ALTERNATIVE MAC address" " to %02x:%02x:%02x:%02x:%02x:%02x ]\n", (idata >> 40) & 255, (idata >> 32) & 255, (idata >> 24) & 255, (idata >> 16) & 255, (idata >> 8) & 255, (idata >> 0) & 255); else debug("[ sgi_mec: reading the ALTERNATIVE MAC address" " as %02x:%02x:%02x:%02x:%02x:%02x ]\n", (odata >> 40) & 255, (odata >> 32) & 255, (odata >> 24) & 255, (odata >> 16) & 255, (odata >> 8) & 255, (odata >> 0) & 255); break; case MEC_MULTICAST: /* 0xb0 */ if (writeflag) debug("[ sgi_mec: write to MEC_MULTICAST: " "0x%016llx ]\n", (long long)idata); break; case MEC_TX_RING_BASE: /* 0xb8 */ if (writeflag) debug("[ sgi_mec: write to MEC_TX_RING_BASE: " "0x%016llx ]\n", (long long)idata); break; case MEC_MCL_RX_FIFO: /* 0x100 */ if (writeflag) { debug("[ sgi_mec: write to MEC_MCL_RX_FIFO: 0x" "%016llx ]\n", (long long)idata); d->rx_addr[d->cur_rx_addr_index_write] = idata; d->cur_rx_addr_index_write ++; d->cur_rx_addr_index_write %= N_RX_ADDRESSES; } break; default: if (writeflag == MEM_WRITE) fatal("[ sgi_mec: unimplemented write to address" " 0x%llx, data=0x%016llx ]\n", (long long)relative_addr, (long long)idata); else fatal("[ sgi_mec: unimplemented read from address" " 0x%llx ]\n", (long long)relative_addr); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); #ifdef MEC_DEBUG if (writeflag == MEM_READ) fatal("[ sgi_mec: read from address" " 0x%llx, len %i, data=0x%llx ]\n", (long long)relative_addr, len, (long long)odata); #endif dev_sgi_mec_tick(cpu, extra); return 1; } /* * dev_sgi_mec_init(): */ void dev_sgi_mec_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, char *irq_path, unsigned char *macaddr) { char *name2; size_t nlen = 55; struct sgi_mec_data *d; CHECK_ALLOCATION(d = (struct sgi_mec_data *) malloc(sizeof(struct sgi_mec_data))); memset(d, 0, sizeof(struct sgi_mec_data)); INTERRUPT_CONNECT(irq_path, d->irq); memcpy(d->macaddr, macaddr, 6); mec_reset(d); CHECK_ALLOCATION(name2 = (char *) malloc(nlen)); snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]", d->macaddr[0], d->macaddr[1], d->macaddr[2], d->macaddr[3], d->macaddr[4], d->macaddr[5]); memory_device_register(mem, name2, baseaddr, DEV_SGI_MEC_LENGTH, dev_sgi_mec_access, (void *)d, DM_DEFAULT, NULL); machine_add_tickfunction(machine, dev_sgi_mec_tick, d, MEC_TICK_SHIFT); net_add_nic(machine->emul->net, d, macaddr); } gxemul-0.6.1/src/devices/dev_cons.cc000644 001750 001750 00000010337 13402411502 017551 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: A simple console device, for the test machines * * This device provides memory mapped I/O for a simple console supporting * putchar (writing to memory) and getchar (reading from memory), and * support for halting the emulator. (This is useful for regression tests, * Hello World-style test programs, and other simple experiments.) */ #include #include #include #include "console.h" #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "testmachine/dev_cons.h" #define CONS_TICK_SHIFT 14 struct cons_data { int console_handle; int in_use; struct interrupt irq; }; DEVICE_TICK(cons) { struct cons_data *d = (struct cons_data *) extra; if (console_charavail(d->console_handle)) INTERRUPT_ASSERT(d->irq); else INTERRUPT_DEASSERT(d->irq); } DEVICE_ACCESS(cons) { struct cons_data *d = (struct cons_data *) extra; unsigned int i; /* Exit the emulator: */ if (relative_addr == DEV_CONS_HALT) { /* cpu->running = 0; cpu->machine->exit_without_entering_debugger = 1; return 1; */ /* TODO: this doesn't work yet. for now, let's simply use exit() */ exit(0); } if (writeflag == MEM_WRITE) { for (i=0; imachine->register_dump || cpu->machine->instruction_trace) debug("putchar '"); console_putchar(d->console_handle, data[i]); if (cpu->machine->register_dump || cpu->machine->instruction_trace) debug("'\n"); fflush(stdout); } } } else { int ch = console_readchar(d->console_handle); if (ch < 0) ch = 0; for (i=0; iname) + 10; if (devinit->name2 != NULL) nlen += strlen(devinit->name2) + 10; CHECK_ALLOCATION(name3 = (char *) malloc(nlen)); if (devinit->name2 != NULL && devinit->name2[0]) snprintf(name3, nlen, "%s [%s]", devinit->name, devinit->name2); else snprintf(name3, nlen, "%s", devinit->name); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); d->in_use = devinit->in_use; d->console_handle = console_start_slave(devinit->machine, name3, d->in_use); memory_device_register(devinit->machine->memory, name3, devinit->addr, DEV_CONS_LENGTH, dev_cons_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_cons_tick, d, CONS_TICK_SHIFT); /* NOTE: Ugly cast into pointer */ devinit->return_ptr = (void *)(size_t)d->console_handle; return 1; } gxemul-0.6.1/src/devices/dev_bt431.cc000644 001750 001750 00000013620 13402411502 017442 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Brooktree BT431, used by TURBOchannel graphics cards * * TODO. */ #include #include #include #include "devices.h" #include "memory.h" #include "misc.h" #include "thirdparty/bt431reg.h" struct bt431_data { uint32_t bt431_reg[DEV_BT431_NREGS]; unsigned char cur_addr_hi; unsigned char cur_addr_lo; int planes; int cursor_on; int cursor_x; int cursor_y; int cursor_xsize; int cursor_ysize; struct vfb_data *vfb_data; }; DEVICE_ACCESS(bt431) { struct bt431_data *d = (struct bt431_data *) extra; uint64_t idata = 0, odata = 0; int btaddr; #if 0 int on, new_cursor_x, new_cursor_y; #endif if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); btaddr = ((d->cur_addr_hi << 8) + d->cur_addr_lo) % DEV_BT431_NREGS; /* TODO */ /* Read from/write to the bt431: */ switch (relative_addr) { case 0x00: /* Low byte of address: */ if (writeflag == MEM_WRITE) { debug("[ bt431: write to Low Address Byte, " "0x%02x ]\n", (int)idata); d->cur_addr_lo = idata; } else { odata = d->cur_addr_lo; debug("[ bt431: read from Low Address Byte: " "0x%0x ]\n", (int)odata); } break; case 0x04: /* High byte of address: */ if (writeflag == MEM_WRITE) { debug("[ bt431: write to High Address Byte, " "0x%02x ]\n", (int)idata); d->cur_addr_hi = idata; } else { odata = d->cur_addr_hi; debug("[ bt431: read from High Address Byte: " "0x%0x ]\n", (int)odata); } break; case 0x08: /* Register access: */ if (writeflag == MEM_WRITE) { debug("[ bt431: write to BT431 register 0x%04x, " "value 0x%02x ]\n", btaddr, (int)idata); d->bt431_reg[btaddr] = idata; #if 0 /* Write to cursor bitmap: */ if (btaddr >= 0x400) bt431_sync_xysize(d); #endif } else { odata = d->bt431_reg[btaddr]; debug("[ bt431: read from BT431 register 0x%04x, " "value 0x%02x ]\n", btaddr, (int)odata); } /* Go to next register: */ d->cur_addr_lo ++; if (d->cur_addr_lo == 0) d->cur_addr_hi ++; break; default: if (writeflag == MEM_WRITE) { debug("[ bt431: unimplemented write to address " "0x%x, data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { debug("[ bt431: unimplemented read from address " "0x%x ]\n", (int)relative_addr); } } #if 0 TODO: This is from bt459! /* NetBSD uses 370,37 as magic values. */ new_cursor_x = (d->bt431_reg[BT431_REG_CXLO] & 255) + ((d->bt431_reg[BT431_REG_CXHI] & 255) << 8) - 370; new_cursor_y = (d->bt431_reg[BT431_REG_CYLO] & 255) + ((d->bt431_reg[BT431_REG_CYHI] & 255) << 8) - 37; /* TODO: what do the bits in the CCR do? */ on = d->bt431_reg[BT431_REG_CCR] ? 1 : 0; on = 1; if (new_cursor_x != d->cursor_x || new_cursor_y != d->cursor_y || on != d->cursor_on) { int ysize_mul = 1; d->cursor_x = new_cursor_x; d->cursor_y = new_cursor_y; d->cursor_on = on; /* * Ugly hack for Ultrix: * * Ultrix and NetBSD assume that the cursor works differently. * Ultrix uses the 370,38 coordinates, but draws the cursor * upwards. NetBSD draws it downwards. Ultrix also makes the * cursor smaller (?). * * TODO: This actually depends on which ultrix kernel you use. * Clearly, the BT459 emulation is not implemented well * enough yet. * * TODO: Find out why? Is it because of special BT459 * commands? * * TODO: Is the above text even valid anymore? :-) */ if (!(d->bt431_reg[BT431_REG_CCR] & 1)) { /* ysize_mul = 4; */ d->cursor_y += 5 - (d->cursor_ysize * ysize_mul); } debug("[ bt431: cursor = %03i,%03i ]\n", d->cursor_x, d->cursor_y); dev_fb_setcursor(d->vfb_data, d->cursor_x, d->cursor_y, on, d->cursor_xsize, d->cursor_ysize * ysize_mul); } #endif if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_bt431_init(): */ void dev_bt431_init(struct memory *mem, uint64_t baseaddr, struct vfb_data *vfb_data, int planes) { struct bt431_data *d; CHECK_ALLOCATION(d = (struct bt431_data *) malloc(sizeof(struct bt431_data))); memset(d, 0, sizeof(struct bt431_data)); d->vfb_data = vfb_data; d->planes = planes; d->cursor_x = -1; d->cursor_y = -1; d->cursor_xsize = d->cursor_ysize = 8; /* anything */ memory_device_register(mem, "bt431", baseaddr, DEV_BT431_LENGTH, dev_bt431_access, (void *)d, DM_DEFAULT, NULL); } gxemul-0.6.1/src/devices/dev_dec_ioasic.cc000644 001750 001750 00000031474 13402411502 020676 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: IOASIC device used in some DECstation machines * * TODO: Lots of stuff, such as DMA and all bits in the control registers. */ #include #include #include #include "cpu.h" #include "devices.h" #include "interrupt.h" #include "memory.h" #include "misc.h" #include "thirdparty/dec_kn03.h" #include "thirdparty/tc_ioasicreg.h" #define IOASIC_DEBUG /* #define debug fatal */ void dec_ioasic_reassert(struct dec_ioasic_data* d) { // printf("[ intr = 0x%08x, imsk = 0x%08x ]\n", d->intr, d->imsk); if (d->intr & d->imsk && !d->int_asserted) { d->int_asserted = 1; d->irq->interrupt_assert(d->irq); } if (!(d->intr & d->imsk) && d->int_asserted) { d->int_asserted = 0; d->irq->interrupt_deassert(d->irq); } } DEVICE_ACCESS(dec_ioasic) { struct dec_ioasic_data *d = (struct dec_ioasic_data *) extra; uint64_t idata = 0, odata = 0; // uint64_t curptr; // uint32_t csr; // int dma_len, dma_res, regnr; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0: /* NetBSD/pmax and OpenBSD/pmax read from this address. */ break; case IOASIC_SCSI_DMAPTR: if (writeflag == MEM_WRITE) d->scsi_dmaptr = idata; else odata = d->scsi_dmaptr; debug("[ dec_ioasic: %s SCSI_DMAPTR, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_SCSI_NEXTPTR: if (writeflag == MEM_WRITE) d->scsi_nextptr = idata; else odata = d->scsi_nextptr; debug("[ dec_ioasic: %s SCSI_NEXTPTR, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_LANCE_DMAPTR: if (writeflag == MEM_WRITE) d->lance_dmaptr = idata; else odata = d->lance_dmaptr; debug("[ dec_ioasic: %s LANCE_DMAPTR, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_FLOPPY_DMAPTR: if (writeflag == MEM_WRITE) d->floppy_dmaptr = idata; else odata = d->floppy_dmaptr; debug("[ dec_ioasic: %s FLOPPY_DMAPTR, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_ISDN_X_DMAPTR: if (writeflag == MEM_WRITE) d->isdn_x_dmaptr = idata; else odata = d->isdn_x_dmaptr; debug("[ dec_ioasic: %s ISDN_X_DMAPTR, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_ISDN_X_NEXTPTR: if (writeflag == MEM_WRITE) d->isdn_x_nextptr = idata; else odata = d->isdn_x_nextptr; debug("[ dec_ioasic: %s ISDN_X_NEXTPTR, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_ISDN_R_DMAPTR: if (writeflag == MEM_WRITE) d->isdn_r_dmaptr = idata; else odata = d->isdn_r_dmaptr; debug("[ dec_ioasic: %s ISDN_R_DMAPTR, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_ISDN_R_NEXTPTR: if (writeflag == MEM_WRITE) d->isdn_r_nextptr = idata; else odata = d->isdn_r_nextptr; debug("[ dec_ioasic: %s ISDN_R_NEXTPTR, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_CSR: if (writeflag == MEM_WRITE) d->csr = idata; else odata = d->csr; debug("[ dec_ioasic: %s CSR, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); #if 0 if (writeflag == MEM_WRITE) { csr = d->reg[(IOASIC_CSR - IOASIC_SLOT_1_START) / 0x10]; d->reg[(IOASIC_INTR - IOASIC_SLOT_1_START) / 0x10] &= ~IOASIC_INTR_T2_PAGE_END; if (csr & IOASIC_CSR_DMAEN_T2) { /* Transmit data: */ curptr = (d->reg[(IOASIC_SCC_T2_DMAPTR - IOASIC_SLOT_1_START) / 0x10] >> 3) | ((d->reg[(IOASIC_SCC_T2_DMAPTR - IOASIC_SLOT_1_START) / 0x10] & 0x1f) << 29); dma_len = 0x1000 - (curptr & 0xffc); if ((curptr & 0xfff) == 0) break; if (d->dma_func[3] != NULL) { d->dma_func[3](cpu, d->dma_func_extra[3], curptr, dma_len, 1); } else fatal("[ dec_ioasic: DMA tx: data @ " "%08x, len %i bytes, but no " "handler? ]\n", (int)curptr, dma_len); /* and signal the end of page: */ d->reg[(IOASIC_INTR - IOASIC_SLOT_1_START) / 0x10] |= IOASIC_INTR_T2_PAGE_END; d->reg[(IOASIC_CSR - IOASIC_SLOT_1_START) / 0x10] &= ~IOASIC_CSR_DMAEN_T2; curptr |= 0xfff; curptr ++; d->reg[(IOASIC_SCC_T2_DMAPTR - IOASIC_SLOT_1_START) / 0x10] = ((curptr << 3) & ~0x1f) | ((curptr >> 29) & 0x1f); } if (csr & IOASIC_CSR_DMAEN_R2) { /* Receive data: */ curptr = (d->reg[(IOASIC_SCC_R2_DMAPTR - IOASIC_SLOT_1_START) / 0x10] >> 3) | ((d->reg[(IOASIC_SCC_R2_DMAPTR - IOASIC_SLOT_1_START) / 0x10] & 0x1f) << 29); dma_len = 0x1000 - (curptr & 0xffc); dma_res = 0; if (d->dma_func[3] != NULL) { dma_res = d->dma_func[3](cpu, d->dma_func_extra[3], curptr, dma_len, 0); } else fatal("[ dec_ioasic: DMA tx: data @ " "%08x, len %i bytes, but no " "handler? ]\n", (int)curptr, dma_len); /* and signal the end of page: */ if (dma_res > 0) { if ((curptr & 0x800) != ((curptr + dma_res) & 0x800)) d->reg[(IOASIC_INTR - IOASIC_SLOT_1_START) / 0x10] |= IOASIC_INTR_R2_HALF_PAGE; curptr += dma_res; /* d->reg[(IOASIC_CSR - IOASIC_SLOT_1_START ) / 0x10] &= ~IOASIC_CSR_DMAEN_R2; */ d->reg[(IOASIC_SCC_R2_DMAPTR - IOASIC_SLOT_1_START) / 0x10] = ((curptr << 3) & ~0x1f) | ((curptr >> 29) & 0x1f); } } } #endif break; case IOASIC_INTR: if (writeflag == MEM_WRITE) { /* Clear bits on write? */ d->intr &= ~idata; dec_ioasic_reassert(d); } else { odata = d->intr; /* Note/TODO: How about other models than KN03? */ //if (!d->rackmount_flag) // odata |= KN03_INTR_PROD_JUMPER; } debug("[ dec_ioasic: %s INTR, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_IMSK: if (writeflag == MEM_WRITE) { d->imsk = idata; dec_ioasic_reassert(d); } else { odata = d->imsk; } debug("[ dec_ioasic: %s IMSK, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_ISDN_X_DATA: if (writeflag == MEM_WRITE) d->isdn_x_data = idata; else odata = d->isdn_x_data; debug("[ dec_ioasic: %s ISDN_X_DATA, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_ISDN_R_DATA: if (writeflag == MEM_WRITE) d->isdn_r_data = idata; else odata = d->isdn_r_data; debug("[ dec_ioasic: %s ISDN_R_DATA, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_LANCE_DECODE: if (writeflag == MEM_WRITE) d->lance_decode = idata; else odata = d->lance_decode; debug("[ dec_ioasic: %s LANCE_DECODE, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_SCSI_DECODE: if (writeflag == MEM_WRITE) d->scsi_decode = idata; else odata = d->scsi_decode; debug("[ dec_ioasic: %s SCSI_DECODE, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_SCC0_DECODE: if (writeflag == MEM_WRITE) d->scc0_decode = idata; else odata = d->scc0_decode; debug("[ dec_ioasic: %s SCC0_DECODE, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_SCC1_DECODE: if (writeflag == MEM_WRITE) d->scc1_decode = idata; else odata = d->scc1_decode; debug("[ dec_ioasic: %s SCC1_DECODE, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_FLOPPY_DECODE: if (writeflag == MEM_WRITE) d->floppy_decode = idata; else odata = d->floppy_decode; debug("[ dec_ioasic: %s FLOPPY_DECODE, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_SCSI_SCR: if (writeflag == MEM_WRITE) d->scsi_scr = idata; else odata = d->scsi_scr; debug("[ dec_ioasic: %s SCSI_SCR, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_SCSI_SDR0: if (writeflag == MEM_WRITE) d->scsi_sdr0 = idata; else odata = d->scsi_sdr0; debug("[ dec_ioasic: %s SCSI_SDR0, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_SCSI_SDR1: if (writeflag == MEM_WRITE) d->scsi_sdr1 = idata; else odata = d->scsi_sdr1; debug("[ dec_ioasic: %s SCSI_SDR1, data=0x%08x ]\n", writeflag == MEM_WRITE ? "write to" : "read from", writeflag == MEM_WRITE ? idata : odata); break; case IOASIC_SYS_ETHER_ADDRESS(0) + 0x00: case IOASIC_SYS_ETHER_ADDRESS(0) + 0x04: case IOASIC_SYS_ETHER_ADDRESS(0) + 0x08: case IOASIC_SYS_ETHER_ADDRESS(0) + 0x0c: case IOASIC_SYS_ETHER_ADDRESS(0) + 0x10: case IOASIC_SYS_ETHER_ADDRESS(0) + 0x14: /* Station's ethernet address: */ if (writeflag == MEM_WRITE) { fatal("[ dec_ioasic: attempt to write to the station's" " ethernet address. ignored for now. ]\n"); } else { odata = ((relative_addr - IOASIC_SYS_ETHER_ADDRESS(0)) / 4 + 1) * 0x10; } break; /* The DECstation 5000/125's PROM uses these for cache testing. TODO. */ case 0x0f004: case 0x1f008: case 0x2f00c: case 0x3f010: case 0x4f014: case 0x5f018: case 0x6f01c: case 0x7f020: case 0x8f024: case 0x9f028: case 0xaf02c: case 0xbf030: break; default: if (writeflag == MEM_WRITE) fatal("[ dec_ioasic: unimplemented write to address " "0x%llx, data=0x%08llx ]\n", (long long)relative_addr, (long long)idata); else fatal("[ dec_ioasic: unimplemented read from address " "0x%llx ]\n", (long long)relative_addr); // exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_dec_ioasic_init(): * * For DECstation "type 4", the rackmount_flag selects which model type * the IOASIC should identify itself as (5000 for zero, 5900 if rackmount_flag * is non-zero). It is probably not meaningful on other machines than * type 4. */ struct dec_ioasic_data *dev_dec_ioasic_init(struct cpu *cpu, struct memory *mem, uint64_t baseaddr, int rackmount_flag, struct interrupt* irqp) { struct dec_ioasic_data *d; CHECK_ALLOCATION(d = (struct dec_ioasic_data *) malloc(sizeof(struct dec_ioasic_data))); memset(d, 0, sizeof(struct dec_ioasic_data)); d->rackmount_flag = rackmount_flag; d->irq = irqp; memory_device_register(mem, "dec_ioasic", baseaddr, DEV_DEC_IOASIC_LENGTH, dev_dec_ioasic_access, (void *)d, DM_DEFAULT, NULL); return d; } gxemul-0.6.1/src/devices/dev_ps2_gif.cc000644 001750 001750 00000031242 13402411502 020136 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: PlayStation 2 "gif" graphics device * * TODO: Convert dev_fb_access() accesses into direct framebuffer reads and * writes, to improve performance. * * TODO 2: The way things are now, rgb bytes are copied from emulated * space to the framebuffer as rgb, but on X Windows servers on * big-endian machines that should be bgr. (?) Hm... */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #define DEV_PS2_GIF_LENGTH 0x10000 #define PS2_FB_ADDR 0x60000000ULL /* hopefully nothing else here */ struct gif_data { struct cpu *cpu; int xsize, ysize; int bytes_per_pixel; int transparent_text; struct vfb_data *vfb_data; }; /* * test_triangle(): * * Draw a triangle: */ void test_triangle(struct gif_data *d, int x1, int y1, int r1, int g1, int b1, int x2, int y2, int r2, int g2, int b2, int x3, int y3, int r3, int g3, int b3) { unsigned char *line; int y, tmp, scale = 32768; int xofs, xlen, savedxlen, xdir, x; int r, g, b; /* scaled */ int xstart, xstop; /* scaled */ int rstart, rstop; /* scaled */ int gstart, gstop; /* scaled */ int bstart, bstop; /* scaled */ int rpx, gpx, bpx; /* scaled */ int xpy12, xpy13, xpy23; int rpy12, rpy13, rpy23; int gpy12, gpy13, gpy23; int bpy12, bpy13, bpy23; CHECK_ALLOCATION(line = (unsigned char *) malloc(d->xsize * d->bytes_per_pixel)); if (y2 > y3) { tmp = x2; x2 = x3; x3 = tmp; tmp = y2; y2 = y3; y3 = tmp; tmp = r2; r2 = r3; r3 = tmp; tmp = g2; g2 = g3; g3 = tmp; tmp = b2; b2 = b3; b3 = tmp; } if (y1 > y2) { tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; tmp = r1; r1 = r2; r2 = tmp; tmp = g1; g1 = g2; g2 = tmp; tmp = b1; b1 = b2; b2 = tmp; } if (y1 > y3) { tmp = x1; x1 = x3; x3 = tmp; tmp = y1; y1 = y3; y3 = tmp; tmp = r1; r1 = r3; r3 = tmp; tmp = g1; g1 = g3; g3 = tmp; tmp = b1; b1 = b3; b3 = tmp; } /* X change per line: */ xpy12 = (y2-y1)? scale*(x2-x1)/(y2-y1) : 0; xpy13 = (y3-y1)? scale*(x3-x1)/(y3-y1) : 0; xpy23 = (y3-y2)? scale*(x3-x2)/(y3-y2) : 0; /* Color change per line: */ rpy12 = (y2-y1)? scale*(r2-r1)/(y2-y1) : 0; rpy13 = (y3-y1)? scale*(r3-r1)/(y3-y1) : 0; rpy23 = (y3-y2)? scale*(r3-r2)/(y3-y2) : 0; gpy12 = (y2-y1)? scale*(g2-g1)/(y2-y1) : 0; gpy13 = (y3-y1)? scale*(g3-g1)/(y3-y1) : 0; gpy23 = (y3-y2)? scale*(g3-g2)/(y3-y2) : 0; bpy12 = (y2-y1)? scale*(b2-b1)/(y2-y1) : 0; bpy13 = (y3-y1)? scale*(b3-b1)/(y3-y1) : 0; bpy23 = (y3-y2)? scale*(b3-b2)/(y3-y2) : 0; xstart = xstop = x1 * scale; rstart = rstop = r1 * scale; gstart = gstop = g1 * scale; bstart = bstop = b1 * scale; for (y=y1; y<=y3; y++) { if (xstart < xstop) xofs = xstart/scale, xlen = (xstop-xstart)/scale + 1; else xofs = xstop/scale, xlen = (xstart-xstop)/scale + 1; savedxlen = xlen; xdir = (xstart < xstop)? 1 : -1; r = rstart; g = gstart; b = bstart; rpx = (xstop-xstart)? (rstop-rstart) / ((xstop-xstart) / scale) : 0; gpx = (xstop-xstart)? (gstop-gstart) / ((xstop-xstart) / scale) : 0; bpx = (xstop-xstart)? (bstop-bstart) / ((xstop-xstart) / scale): 0; x = xstart / scale; while (xlen > 0) { if (x>=0 && xxsize) { int c; c = r/scale; line[x * d->bytes_per_pixel + 0] = c<0? 0 : (c > 255? 255 : c); c = g/scale; line[x * d->bytes_per_pixel + 1] = c<0? 0 : (c > 255? 255 : c); c = b/scale; line[x * d->bytes_per_pixel + 2] = c<0? 0 : (c > 255? 255 : c); } r += rpx; g += gpx; b += bpx; x += xdir; xlen --; } dev_fb_access(d->cpu, d->cpu->mem, (y*d->xsize + xofs) * d->bytes_per_pixel, line + xofs * d->bytes_per_pixel, savedxlen * d->bytes_per_pixel, MEM_WRITE, d->vfb_data); if (y DEV_PS2_GIF_LENGTH) return 0; if (writeflag==MEM_READ) { debug("[ gif read from addr 0x%x, len=%i ]\n", (int)relative_addr, (int)len); } else { if (data[0] == 0x08 && data[1] == 0x80) { /* Possibly "initialize 640x480 mode": */ debug("[ gif: initialize video mode (?) ]\n"); } else if (data[0] == 0x04 && data[1] == 0x00 && len > 300) { /* Possibly "output 8x16 character": */ int xbase, ybase, xsize, ysize, x, y; xbase = data[9*4 + 0] + (data[9*4 + 1] << 8); ybase = data[9*4 + 2] + (data[9*4 + 3] << 8); xsize = data[12*4 + 0] + (data[12*4 + 1] << 8); ysize = data[13*4 + 0] + (data[13*4 + 1] << 8); ysize &= ~0xf; /* multple of 16 */ /* debug("[ gif: putchar at (%i,%i), size (%i,%i) " "]\n", xbase, ybase, xsize, ysize); */ /* * NetBSD and Linux: * * [ gif write to addr 0x0 (len=608): * 04 00 00 00 00 00 00 10, 0e 00 00 00 00 00 00 00, * 00 00 00 00 00 00 0a 00, 50 00 00 00 00 00 00 00, * 00 00 00 00 00 00 00 00, 51 00 00 00 00 00 00 00, * 08 00 00 00 16 00 00 00, 52 00 00 00 00 00 00 00, * 00 00 00 00 00 00 00 00, 53 00 00 00 00 00 00 00, * 20 80 00 00 00 00 00 08, 00 00 00 00 00 00 00 00, * 00 00 aa 80 00 00 aa 80, 00 00 aa 80 00 00 aa 80, * 00 00 aa 80 00 00 aa 80, 00 00 aa 80 00 00 aa 80, * aa aa 00 80 aa aa 00 80, 00 00 aa 80 00 00 aa 80, * 00 00 aa 80 00 00 aa 80, 00 00 aa 80 00 00 aa 80, */ /* fatal("[ gif write to addr 0x%x (len=%i):", (int)relative_addr, (int)len); for (i=0; ixsize) * d->bytes_per_pixel; int addr = (24 + y*xsize) * 4; for (x=0; xcpu, d->cpu->mem, fb_addr, data + addr, 3, MEM_WRITE, d->vfb_data); fb_addr += d->bytes_per_pixel; addr += 4; } } } else if (data[0] == 0x04 && data[1] == 0x80 && len == 0x50) { /* blockcopy */ int y_source, y_dest, x_source, x_dest, x_size, y_size; x_source = data[8*4 + 0] + ((data[8*4 + 1]) << 8); y_source = data[8*4 + 2] + ((data[8*4 + 3]) << 8); x_dest = data[9*4 + 0] + ((data[9*4 + 1]) << 8); y_dest = data[9*4 + 2] + ((data[9*4 + 3]) << 8); x_size = data[12*4 + 0] + ((data[12*4 + 1]) << 8); y_size = data[13*4 + 0] + ((data[13*4 + 1]) << 8); /* debug("[ gif: blockcopy (%i,%i) -> (%i,%i), size=" "(%i,%i) ]\n", x_source,y_source, x_dest,y_dest, x_size,y_size); */ framebuffer_blockcopyfill(d->vfb_data, 0, 0,0,0, x_dest, y_dest, x_dest + x_size - 1, y_dest + y_size - 1, x_source, y_source); } else if (data[8] == 0x10 && data[9] == 0x55 && len == 48) { /* Linux "clear": This is used by linux to clear the lowest 16 pixels of the framebuffer. */ int xbase, ybase, xend, yend; xbase = (data[8*4 + 0] + (data[8*4 + 1] << 8)) / 16; ybase = (data[8*4 + 2] + (data[8*4 + 3] << 8)) / 16; xend = (data[8*5 + 0] + (data[8*5 + 1] << 8)) / 16; yend = (data[8*5 + 2] + (data[8*5 + 3] << 8)) / 16; /* debug("[ gif: linux \"clear\" (%i,%i)-(%i,%i) ]\n", xbase, ybase, xend, yend); */ framebuffer_blockcopyfill(d->vfb_data, 1, 0,0,0, xbase, ybase, xend - 1, yend - 1, 0,0); } else if (data[0] == 0x07 && data[1] == 0x80 && len == 128) { /* NetBSD "output cursor": */ int xbase, ybase, xend, yend, x, y; xbase = (data[20*4 + 0] + (data[20*4 + 1] << 8)) / 16; ybase = (data[20*4 + 2] + (data[20*4 + 3] << 8)) / 16; xend = (data[28*4 + 0] + (data[28*4 + 1] << 8)) / 16; yend = (data[28*4 + 2] + (data[28*4 + 3] << 8)) / 16; /* debug("[ gif: NETBSD cursor at (%i,%i)-(%i,%i) ]\n", xbase, ybase, xend, yend); */ /* Output the cursor to framebuffer memory: */ for (y=ybase; y<=yend; y++) for (x=xbase; x<=xend; x++) { int fb_addr = (x + y * d->xsize) * d->bytes_per_pixel; unsigned char pixels[3]; dev_fb_access(d->cpu, d->cpu->mem, fb_addr, pixels, sizeof(pixels), MEM_READ, d->vfb_data); pixels[0] = 0xff - pixels[0]; pixels[1] = 0xff - pixels[1]; pixels[2] = 0xff - pixels[2]; dev_fb_access(d->cpu, d->cpu->mem, fb_addr, pixels, sizeof(pixels), MEM_WRITE, d->vfb_data); } } else if (data[0] == 0x01 && data[1] == 0x00 && len == 80) { /* Linux "output cursor": */ int xbase, ybase, xend, yend, x, y; xbase = (data[7*8 + 0] + (data[7*8 + 1] << 8)) / 16; ybase = (data[7*8 + 2] + (data[7*8 + 3] << 8)) / 16; xend = (data[8*8 + 0] + (data[8*8 + 1] << 8)) / 16; yend = (data[8*8 + 2] + (data[8*8 + 3] << 8)) / 16; debug("[ gif: LINUX cursor at (%i,%i)-(%i,%i) ]\n", xbase, ybase, xend, yend); /* Output the cursor to framebuffer memory: */ for (y=ybase; y<=yend; y++) for (x=xbase; x<=xend; x++) { int fb_addr = (x + y * d->xsize) * d->bytes_per_pixel; unsigned char pixels[3]; dev_fb_access(d->cpu, d->cpu->mem, fb_addr, pixels, sizeof(pixels), MEM_READ, d->vfb_data); pixels[0] = 0xff - pixels[0]; pixels[1] = 0xff - pixels[1]; pixels[2] = 0xff - pixels[2]; dev_fb_access(d->cpu, d->cpu->mem, fb_addr, pixels, sizeof(pixels), MEM_WRITE, d->vfb_data); } } else { /* Unknown command: */ fatal("[ gif write to addr 0x%x (len=%i):", (int)relative_addr, len); for (i=0; irunning = 0; */ } } return 1; } /* * devinit_ps2_gif(): * * Attached to separate memory by devinit_ps2_gs(). */ DEVINIT(ps2_gif) { struct gif_data *d; CHECK_ALLOCATION(d = (struct gif_data *) malloc(sizeof(struct gif_data))); memset(d, 0, sizeof(struct gif_data)); d->transparent_text = 0; d->cpu = devinit->machine->cpus[0]; /* TODO */ d->xsize = 640; d->ysize = 480; d->bytes_per_pixel = 3; d->vfb_data = dev_fb_init(devinit->machine, devinit->machine->memory, PS2_FB_ADDR, VFB_PLAYSTATION2, d->xsize, d->ysize, d->xsize, d->ysize, 24, "Playstation 2"); if (d->vfb_data == NULL) { fprintf(stderr, "could not initialize fb, out of memory\n"); exit(1); } #if 0 test_triangle(d, 300,50, 255,0,0, 50,150, 0,255,0, 600,400, 0,0,255); test_triangle(d, 310,210, 128,32,0, 175,410, 0,32,0, 500,470, 125,255,125); test_triangle(d, 100,450, 255,255,0, 250,370, 0,255,255, 400,470, 255,0,255); #endif memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_PS2_GIF_LENGTH, dev_ps2_gif_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_malta_lcd.cc000644 001750 001750 00000010030 13402411502 020515 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Malta (evbmips) LCD display * * TODO: Write output to somewhere else, not just as a debug message. */ #include #include #include #include "cpu.h" #include "device.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/maltareg.h" #define DEV_MALTA_LCD_LENGTH 0x80 #define MALTA_LCD_TICK_SHIFT 16 #define LCD_LEN 8 struct malta_lcd_data { uint64_t base_addr; int display_modified; unsigned char display[LCD_LEN]; }; DEVICE_TICK(malta_lcd) { struct malta_lcd_data *d = (struct malta_lcd_data *) extra; int i; if (d->display_modified == 0) return; if (d->display_modified == 1) { d->display_modified = 2; return; } debug("[ malta_lcd: \""); for (i=0; idisplay[i] >= ' ') debug("%c", d->display[i]); else debug("?"); debug("\" ]\n"); d->display_modified = 0; } DEVICE_ACCESS(malta_lcd) { struct malta_lcd_data *d = (struct malta_lcd_data *) extra; uint64_t idata = 0, odata = 0; int pos; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); relative_addr += d->base_addr; switch (relative_addr) { case MALTA_ASCII_BASE + MALTA_ASCIIPOS0: case MALTA_ASCII_BASE + MALTA_ASCIIPOS1: case MALTA_ASCII_BASE + MALTA_ASCIIPOS2: case MALTA_ASCII_BASE + MALTA_ASCIIPOS3: case MALTA_ASCII_BASE + MALTA_ASCIIPOS4: case MALTA_ASCII_BASE + MALTA_ASCIIPOS5: case MALTA_ASCII_BASE + MALTA_ASCIIPOS6: case MALTA_ASCII_BASE + MALTA_ASCIIPOS7: pos = (relative_addr - MALTA_ASCII_BASE) / 8; if (writeflag == MEM_WRITE) { d->display[pos] = idata; d->display_modified = 1; } else { odata = d->display[pos]; } break; default: if (writeflag == MEM_WRITE) { fatal("[ malta_lcd: unimplemented write to " "offset 0x%x: data=0x%02x ]\n", (int) relative_addr, (int)idata); } else { fatal("[ malta_lcd: unimplemented read from " "offset 0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(malta_lcd) { struct malta_lcd_data *d; CHECK_ALLOCATION(d = (struct malta_lcd_data *) malloc(sizeof(struct malta_lcd_data))); memset(d, 0, sizeof(struct malta_lcd_data)); d->base_addr = devinit->addr; memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_MALTA_LCD_LENGTH, dev_malta_lcd_access, (void *)d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_malta_lcd_tick, d, MALTA_LCD_TICK_SHIFT); return 1; } gxemul-0.6.1/src/devices/dev_8259.cc000644 001750 001750 00000017402 13402411502 017216 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Intel 8259 Programmable Interrupt Controller * * See the following URL for more details: * http://www.nondot.org/sabre/os/files/MiscHW/8259pic.txt */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #define DEV_8259_LENGTH 2 /* #define DEV_8259_DEBUG */ DEVICE_ACCESS(8259) { struct pic8259_data *d = (struct pic8259_data *) extra; uint64_t idata = 0, odata = 0; int i; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); #ifdef DEV_8259_DEBUG if (writeflag == MEM_READ) fatal("[ 8259: read from 0x%x ]\n", (int)relative_addr); else fatal("[ 8259: write to 0x%x: 0x%x ]\n", (int)relative_addr, (int)idata); #endif switch (relative_addr) { case 0x00: if (writeflag == MEM_WRITE) { if ((idata & 0x10) == 0x10) { /* Bit 3: 0=edge, 1=level */ if (idata & 0x08) fatal("[ 8259: TODO: Level " "triggered (MCA bus) ]\n"); if (idata & 0x04) fatal("[ 8259: WARNING: Bit 2 set ]\n"); /* Bit 1: 0=cascade, 1=single */ /* Bit 0: 1=4th init byte */ /* This happens on non-x86 systems: if (!(idata & 0x01)) fatal("[ 8259: WARNING: Bit 0 NOT set!" "!! ]\n"); */ d->init_state = 1; break; } /* TODO: Is it ok to abort init state when there is a non-init command? */ if (d->init_state) fatal("[ 8259: WARNING: Was in init-state, but" " it was aborted? ]\n"); d->init_state = 0; if (idata == 0x0a) { d->current_command = 0x0a; } else if (idata == 0x0b) { d->current_command = 0x0b; } else if (idata == 0x0c) { /* Put Master in Buffered Mode */ d->current_command = 0x0c; } else if (idata == 0x20) { int old_irr = d->irr; /* End Of Interrupt */ /* TODO: in buffered mode, is this an EOI 0? */ d->irr &= ~d->isr; d->isr = 0; /* Recalculate interrupt assertions, if necessary: */ if ((old_irr & ~d->ier) != (d->irr & ~d->ier)) { if (d->irr & ~d->ier) INTERRUPT_ASSERT(d->irq); else INTERRUPT_DEASSERT(d->irq); } } else if ((idata >= 0x21 && idata <= 0x27) || (idata >= 0x60 && idata <= 0x67) || (idata >= 0xe0 && idata <= 0xe7)) { /* Specific EOI */ int old_irr = d->irr; d->irr &= ~(1 << (idata & 7)); d->isr &= ~(1 << (idata & 7)); /* Recalc. int assertions, if necessary: */ if ((old_irr & ~d->ier) != (d->irr & ~d->ier)) { if (d->irr & ~d->ier) INTERRUPT_ASSERT(d->irq); else INTERRUPT_DEASSERT(d->irq); } } else if (idata == 0x68) { /* Set Special Mask Mode */ /* TODO */ } else if (idata >= 0xc0 && idata <= 0xc7) { /* Set IRQ Priority Order */ /* TODO */ } else { fatal("[ 8259: unimplemented command 0x%02x" " ]\n", (int)idata); cpu->running = 0; } } else { switch (d->current_command) { case 0x0a: odata = d->irr; break; case 0x0b: odata = d->isr; break; case 0x0c: /* Buffered mode. */ odata = 0x00; for (i=0; i<8; i++) if ((d->irr >> i) & 1) { odata = 0x80 | i; break; } break; default: odata = 0x00; for (i=0; i<8; i++) if ((d->irr >> i) & 1) { odata = 0x80 | i; break; } break; /* * TODO: The "default" label should really do * something like this: * * fatal("[ 8259: unimplemented command 0x%02x" * " while reading ]\n", d->current_command); * cpu->running = 0; * * but Linux seems to read from the secondary PIC * in a manner which works better the way things * are coded right now. */ } } break; case 0x01: if (d->init_state > 0) { if (d->init_state == 1) { d->irq_base = idata & 0xf8; /* This happens on non-x86 machines: if (idata & 7) fatal("[ 8259: WARNING! Lowest" " bits in Init Cmd 1 are" " non-zero! ]\n"); */ d->init_state = 2; } else if (d->init_state == 2) { /* Slave attachment. TODO */ d->init_state = 3; } else if (d->init_state == 3) { if (idata & 0x02) { /* Should not be set in PCs, but on CATS, for example, it is set. */ debug("[ 8259: WARNING! Bit 1 i" "n Init Cmd 4 is set! ]\n"); } if (!(idata & 0x01)) fatal("[ 8259: WARNING! Bit 0 " "in Init Cmd 4 is not" " set! ]\n"); d->init_state = 0; } break; } if (writeflag == MEM_WRITE) { int old_ier = d->ier; d->ier = idata; /* Recalculate interrupt assertions, if necessary: */ if ((d->irr & ~old_ier) != (d->irr & ~d->ier)) { if (d->irr & ~d->ier) INTERRUPT_ASSERT(d->irq); else INTERRUPT_DEASSERT(d->irq); } } else { odata = d->ier; } break; default: if (writeflag == MEM_WRITE) { fatal("[ 8259: unimplemented write to address 0x%x" " data=0x%02x ]\n", (int)relative_addr, (int)idata); cpu->running = 0; } else { fatal("[ 8259: unimplemented read from address 0x%x " "]\n", (int)relative_addr); cpu->running = 0; } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * devinit_8259(): * * Initialize an 8259 PIC. Important notes: * * x) Most systems use _TWO_ 8259 PICs. These should be registered * as separate devices. * * x) The irq number specified is the number used to re-calculate * CPU interrupt assertions. It is _not_ the irq number at * which the PIC is connected. (That is left to machine specific * code in src/machine.c.) */ DEVINIT(8259) { struct pic8259_data *d; char *name2; size_t nlen = strlen(devinit->name) + 20; CHECK_ALLOCATION(d = (struct pic8259_data *) malloc(sizeof(struct pic8259_data))); memset(d, 0, sizeof(struct pic8259_data)); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); CHECK_ALLOCATION(name2 = (char *) malloc(nlen)); snprintf(name2, nlen, "%s", devinit->name); if ((devinit->addr & 0xfff) == 0xa0) { strlcat(name2, " [secondary]", nlen); d->irq_base = 8; } memory_device_register(devinit->machine->memory, name2, devinit->addr, DEV_8259_LENGTH, dev_8259_access, d, DM_DEFAULT, NULL); devinit->return_ptr = d; return 1; } gxemul-0.6.1/src/devices/bus_isa.cc000644 001750 001750 00000024551 13402411502 017401 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Generic ISA bus framework * * This is not a normal device, but it can be used as a quick way of adding * most of the common legacy ISA devices to a machine. */ #include #include #include #define BUS_ISA_C #include "bus_isa.h" #include "device.h" #include "devices.h" #include "diskimage.h" #include "interrupt.h" #include "machine.h" #include "misc.h" /* * isa_interrupt_common(): */ void isa_interrupt_common(struct bus_isa_data *d, int old_isa_assert) { int new_isa_assert, x; /* Any interrupt assertions on PIC2 go to irq 2 on PIC1 */ /* (TODO: don't hardcode this here) */ if (d->pic2->irr & ~d->pic2->ier) d->pic1->irr |= 0x04; else d->pic1->irr &= ~0x04; /* printf("ISA: irr=%02x%02x ier=%02x%02x\n", d->pic2->irr, d->pic1->irr, d->pic2->ier, d->pic1->ier); */ new_isa_assert = d->pic1->irr & ~d->pic1->ier; if (old_isa_assert == new_isa_assert) return; if (!new_isa_assert) { INTERRUPT_DEASSERT(d->irq); return; } for (x=0; x<16; x++) { if (x == 2) continue; if (x < 8 && (d->pic1->irr & ~d->pic1->ier & (1 << x))) break; if (x >= 8 && (d->pic2->irr & ~d->pic2->ier & (1 << (x&7)))) break; } *d->ptr_to_last_int = x; INTERRUPT_ASSERT(d->irq); } /* * isa_interrupt_assert(): * * Called whenever an ISA device asserts an interrupt (0..15). */ void isa_interrupt_assert(struct interrupt *interrupt) { struct bus_isa_data *d = (struct bus_isa_data *) interrupt->extra; int old_isa_assert, line = interrupt->line; int mask = 1 << (line & 7); old_isa_assert = d->pic1->irr & ~d->pic1->ier; if (line < 8) d->pic1->irr |= mask; else if (d->pic2 != NULL) d->pic2->irr |= mask; isa_interrupt_common(d, old_isa_assert); } /* * isa_interrupt_deassert(): * * Called whenever an ISA device deasserts an interrupt (0..15). */ void isa_interrupt_deassert(struct interrupt *interrupt) { struct bus_isa_data *d = (struct bus_isa_data *) interrupt->extra; int line = interrupt->line, mask = 1 << (line & 7); int old_irr1 = d->pic1->irr, old_isa_assert; old_isa_assert = old_irr1 & ~d->pic1->ier; if (line < 8) d->pic1->irr &= ~mask; else if (d->pic2 != NULL) d->pic2->irr &= ~mask; /* If IRQ 0 has been cleared, then this is a timer interrupt. Let's ack it here: */ if (old_irr1 & 1 && !(d->pic1->irr & 1) && d->ptr_to_pending_timer_interrupts != NULL && (*d->ptr_to_pending_timer_interrupts) > 0) (*d->ptr_to_pending_timer_interrupts) --; isa_interrupt_common(d, old_isa_assert); } /* * bus_isa_init(): * * Flags are zero or more of the following, ORed together: * * BUS_ISA_EXTERNAL_PIC Don't register/use isa_interrupt_*(). * BUS_ISA_IDE0 Include wdc0. * BUS_ISA_IDE1 Include wdc1. * BUS_ISA_FDC Include a floppy controller. (Dummy.) * BUS_ISA_VGA Include old-style (non-PCI) VGA. (*1) * BUS_ISA_VGA_FORCE Include VGA even when running without X11. (*2) * BUS_ISA_PCKBC_FORCE_USE Always assume keyboard console, not serial. (*3) * BUS_ISA_PCKBC_NONPCSTYLE Don't set the pc-style flag for the keyboard. * BUS_ISA_NO_SECOND_PIC Only useful for 8086 XT (pre-AT) emulation. :-) * BUS_ISA_LPTBASE_3BC Set lptbase to 0x3bc instead of 0x378. * * (*1) For machines with a PCI bus, this flag should not be used. Instead, a * PCI VGA card should be added to the PCI bus. * * (*2) For machines where it is easy to select VGA vs serial console during * boot, this flag should not be used. Machines that "always" boot up * in VGA console mode should have it set. * * (*3) Similar to *2 above; machines that always boot up with VGA console * should have this flag set, so that the keyboard is always used. * * The interrupt_base_path is the name of the bus, CPU, or controller onto * which this ISA bus will be attached, e.g. "machine[0].lca" or * "machine[0].cpu[0].pic1". */ struct bus_isa_data *bus_isa_init(struct machine *machine, char *interrupt_base_path, uint32_t bus_isa_flags, uint64_t isa_portbase, uint64_t isa_membase) { struct bus_isa_data *d; char tmpstr[300], tmpstr2[300]; int wdc0_irq = 14, wdc1_irq = 15; int i, tmp_handle, kbd_in_use; int lptbase = 0x378; CHECK_ALLOCATION(d = (struct bus_isa_data *) malloc(sizeof(struct bus_isa_data))); memset(d, 0, sizeof(struct bus_isa_data)); d->isa_portbase = isa_portbase; d->isa_membase = isa_membase; if (!(bus_isa_flags & BUS_ISA_EXTERNAL_PIC)) { /* Connect to the interrupt which we're interrupting at (usually a CPU): */ INTERRUPT_CONNECT(interrupt_base_path, d->irq); /* Register the 16 possible ISA interrupts: */ for (i=0; i<16; i++) { struct interrupt templ; char name[300]; snprintf(name, sizeof(name), "%s.isa.%i", interrupt_base_path, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = name; templ.extra = d; templ.interrupt_assert = isa_interrupt_assert; templ.interrupt_deassert = isa_interrupt_deassert; interrupt_handler_register(&templ); } } kbd_in_use = ((bus_isa_flags & BUS_ISA_PCKBC_FORCE_USE) || (machine->x11_md.in_use))? 1 : 0; if (machine->machine_type == MACHINE_PREP) { /* PReP with obio controller has both WDCs on irq 13! */ wdc0_irq = wdc1_irq = 13; } if (!(bus_isa_flags & BUS_ISA_EXTERNAL_PIC)) { snprintf(tmpstr, sizeof(tmpstr), "8259 irq=%s addr=0x%llx", interrupt_base_path, (long long)(isa_portbase + 0x20)); d->pic1 = machine->isa_pic_data.pic1 = (struct pic8259_data *) device_add(machine, tmpstr); d->ptr_to_pending_timer_interrupts = machine->isa_pic_data.pending_timer_interrupts; d->ptr_to_last_int = &machine->isa_pic_data.last_int; if (bus_isa_flags & BUS_ISA_NO_SECOND_PIC) bus_isa_flags &= ~BUS_ISA_NO_SECOND_PIC; else { snprintf(tmpstr, sizeof(tmpstr), "8259 irq=%s.isa.2 addr=0x%llx", interrupt_base_path,(long long)(isa_portbase+0xa0)); d->pic2 = machine->isa_pic_data.pic2 = (struct pic8259_data *) device_add(machine, tmpstr); } } else { bus_isa_flags &= ~BUS_ISA_EXTERNAL_PIC; } snprintf(tmpstr, sizeof(tmpstr), "8253 irq=%s.isa.%i addr=0x%llx " "in_use=0", interrupt_base_path, 0, (long long)(isa_portbase + 0x40)); device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "pccmos irq=%s.isa.%i addr=0x%llx", interrupt_base_path, 8, (long long)(isa_portbase + 0x70)); device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.isa.%i addr=0x%llx " "name2=tty0 in_use=%i", interrupt_base_path, 4, (long long)(isa_portbase + 0x3f8), 1 - kbd_in_use); machine->main_console_handle = (size_t)device_add(machine, tmpstr); snprintf(tmpstr, sizeof(tmpstr), "ns16550 irq=%s.isa.%i addr=0x%llx " "name2=tty1 in_use=0", interrupt_base_path, 3, (long long)(isa_portbase + 0x2f8)); device_add(machine, tmpstr); if (bus_isa_flags & BUS_ISA_LPTBASE_3BC) { bus_isa_flags &= ~BUS_ISA_LPTBASE_3BC; lptbase = 0x3bc; } snprintf(tmpstr, sizeof(tmpstr), "lpt irq=%s.isa.%i addr=0x%llx " "name2=lpt in_use=0", interrupt_base_path, 7, (long long)(isa_portbase + lptbase)); device_add(machine, tmpstr); if (bus_isa_flags & BUS_ISA_IDE0) { bus_isa_flags &= ~BUS_ISA_IDE0; snprintf(tmpstr, sizeof(tmpstr), "wdc irq=%s.isa.%i " "addr=0x%llx", interrupt_base_path, wdc0_irq, (long long)(isa_portbase + 0x1f0)); if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) device_add(machine, tmpstr); } if (bus_isa_flags & BUS_ISA_IDE1) { bus_isa_flags &= ~BUS_ISA_IDE1; snprintf(tmpstr, sizeof(tmpstr), "wdc irq=%s.isa.%i " "addr=0x%llx", interrupt_base_path, wdc1_irq, (long long)(isa_portbase + 0x170)); if (diskimage_exist(machine, 2, DISKIMAGE_IDE) || diskimage_exist(machine, 3, DISKIMAGE_IDE)) device_add(machine, tmpstr); } if (bus_isa_flags & BUS_ISA_FDC) { bus_isa_flags &= ~BUS_ISA_FDC; snprintf(tmpstr, sizeof(tmpstr), "fdc irq=%s.isa.%i " "addr=0x%llx", interrupt_base_path, 6, (long long)(isa_portbase + 0x3f0)); device_add(machine, tmpstr); } if (bus_isa_flags & BUS_ISA_VGA) { if (machine->x11_md.in_use || bus_isa_flags & BUS_ISA_VGA_FORCE) dev_vga_init(machine, machine->memory, isa_membase + 0xa0000, isa_portbase + 0x3c0, machine->machine_name); bus_isa_flags &= ~(BUS_ISA_VGA | BUS_ISA_VGA_FORCE); } snprintf(tmpstr, sizeof(tmpstr), "%s.isa.1", interrupt_base_path); snprintf(tmpstr2, sizeof(tmpstr2), "%s.isa.12", interrupt_base_path); tmp_handle = dev_pckbc_init(machine, machine->memory, isa_portbase + 0x60, PCKBC_8042, tmpstr, tmpstr2, kbd_in_use, bus_isa_flags & BUS_ISA_PCKBC_NONPCSTYLE? 0 : 1); if (kbd_in_use) machine->main_console_handle = tmp_handle; bus_isa_flags &= ~(BUS_ISA_PCKBC_NONPCSTYLE | BUS_ISA_PCKBC_FORCE_USE); if (bus_isa_flags != 0) fatal("WARNING! bus_isa(): unimplemented bus_isa_flags 0x%x\n", bus_isa_flags); return d; } gxemul-0.6.1/src/devices/dev_random.cc000644 001750 001750 00000004041 13402411502 020062 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: A device which returns random data for reads, discards all writes */ #include #include #include #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" DEVICE_ACCESS(random) { if (writeflag == MEM_READ) { size_t i; for (i=0; imachine->memory, devinit->name, devinit->addr, devinit->len, dev_random_access, NULL, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_rtc.cc000644 001750 001750 00000010564 13402411502 017401 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: A generic Real-Time Clock device, for the test machines * * It can be used to retrieve the current system time, and to cause periodic * interrupts. */ #include #include #include #include #include "cpu.h" #include "device.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "timer.h" #include "testmachine/dev_rtc.h" #define DEV_RTC_TICK_SHIFT 14 struct rtc_data { struct interrupt irq; int pending_interrupts; int hz; struct timer *timer; struct timeval cur_time; }; /* * timer_tick(): * * This function is called d->hz times per second. */ static void timer_tick(struct timer *t, void *extra) { struct rtc_data *d = (struct rtc_data *) extra; d->pending_interrupts ++; } DEVICE_TICK(rtc) { struct rtc_data *d = (struct rtc_data *) extra; if (d->pending_interrupts > 0) INTERRUPT_ASSERT(d->irq); else INTERRUPT_DEASSERT(d->irq); } DEVICE_ACCESS(rtc) { struct rtc_data *d = (struct rtc_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case DEV_RTC_TRIGGER_READ: gettimeofday(&d->cur_time, NULL); break; case DEV_RTC_SEC: odata = d->cur_time.tv_sec; break; case DEV_RTC_USEC: odata = d->cur_time.tv_usec; break; case DEV_RTC_HZ: if (writeflag == MEM_READ) { odata = d->hz; } else { d->hz = idata; if (d->hz == 0) { /* Remove the timer, if any: */ if (d->timer != NULL) timer_remove(d->timer); d->timer = NULL; d->pending_interrupts = 0; } else { /* Add a timer, or update the existing one: */ if (d->timer == NULL) d->timer = timer_add(d->hz, timer_tick, d); else timer_update_frequency(d->timer, d->hz); } } break; case DEV_RTC_INTERRUPT_ACK: if (d->pending_interrupts > 0) d->pending_interrupts --; INTERRUPT_DEASSERT(d->irq); /* TODO: Reassert the interrupt here, if d->pending_interrupts is still above zero? */ break; default:if (writeflag == MEM_WRITE) { fatal("[ rtc: unimplemented write to " "offset 0x%x: data=0x%x ]\n", (int) relative_addr, (int)idata); } else { fatal("[ rtc: unimplemented read from " "offset 0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(rtc) { struct rtc_data *d; CHECK_ALLOCATION(d = (struct rtc_data *) malloc(sizeof(struct rtc_data))); memset(d, 0, sizeof(struct rtc_data)); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_RTC_LENGTH, dev_rtc_access, (void *)d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_rtc_tick, d, DEV_RTC_TICK_SHIFT); return 1; } gxemul-0.6.1/src/devices/dev_dreamcast_maple.cc000644 001750 001750 00000045712 13402411502 021735 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2014 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Dreamcast Maple bus controller * * The Maple bus has 4 ports (A-D), and each port has up to 6 possible "units" * (where unit 0 is the main unit). Communication is done using DMA; each * DMA transfer sends one or more requests, and for each of these requests * a response is generated (or a timeout if there was no device at the * specific port). * * See Marcus Comstedt's page (http://mc.pp.se/dc/maplebus.html) for more * details about the DMA request/responses. * * * TODO: * Unit numbers / IDs for real Maple devices. * The Controller (up/down/left/right, buttons, etc). */ #include #include #include #include #include "console.h" #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/dreamcast_maple.h" #include "thirdparty/dreamcast_sysasicvar.h" // #define debug fatal #define N_MAPLE_PORTS 4 #define MAX_CHARS 8192 #define MAX_CONTROLLER_DATA 4096 #define MAPLE_TICK_SHIFT 17 struct maple_device { struct maple_devinfo devinfo; }; struct dreamcast_maple_data { /* Registers: */ uint32_t dmaaddr; int enable; int timeout; /* Attached devices: */ struct maple_device *device[N_MAPLE_PORTS]; /* For keyboard/controller input: */ int console_handle; uint8_t char_queue[MAX_CHARS]; uint16_t controller_queue[MAX_CONTROLLER_DATA]; int char_queue_head, char_queue_tail; int controller_queue_head, controller_queue_tail; }; /* * Maple devices: * * TODO: Figure out strings and numbers of _real_ Maple devices. */ struct maple_device maple_device_controller = { { BE32_TO_HOST(MAPLE_FUNC(MAPLE_FN_CONTROLLER)), /* di_func */ { LE32_TO_HOST(0xfe060f00),0,0 },/* di_function_data[3] */ 0xff, /* di_area_code */ 0, /* di_connector_direction */ "Dreamcast Controller", /* di_product_name */ "di_product_license", /* di_product_license */ LE16_TO_HOST(0x01ae), /* di_standby_power */ LE16_TO_HOST(0x01f4) /* di_max_power */ } }; struct maple_device maple_device_keyboard = { { BE32_TO_HOST(MAPLE_FUNC(MAPLE_FN_KEYBOARD)),/* di_func */ { LE32_TO_HOST(2),0,0 }, /* di_function_data[3] */ 0xff, /* di_area_code */ 0, /* di_connector_direction */ "Keyboard", /* di_product_name */ "di_product_license", /* di_product_license */ LE16_TO_HOST(100), /* di_standby_power */ LE16_TO_HOST(100) /* di_max_power */ } }; struct maple_device maple_device_mouse = { { BE32_TO_HOST(MAPLE_FUNC(MAPLE_FN_MOUSE)),/* di_func */ { LE32_TO_HOST(0xfe060f00),0,0 },/* di_function_data[3] */ 0xff, /* di_area_code */ 0, /* di_connector_direction */ "Dreamcast Mouse", /* di_product_name */ "di_product_license", /* di_product_license */ LE16_TO_HOST(0x0069), /* di_standby_power */ LE16_TO_HOST(0x0120) /* di_max_power */ } }; DEVICE_TICK(maple) { struct dreamcast_maple_data *d = (struct dreamcast_maple_data *) extra; int key; while ((key = console_readchar(d->console_handle)) >= 0) { /* Add to the keyboard queue: */ d->char_queue[d->char_queue_head] = key; d->char_queue_head = (d->char_queue_head + 1) % MAX_CHARS; if (d->char_queue_head == d->char_queue_tail) fatal("[ dreamcast_maple: KEYBOARD QUEUE OVERRUN! ]\n"); /* * NOTE/TODO: * * Implement the controller in a reasonable way! * Theoretically, there are all of these buttons: ABCD XYZ Start * and two digital pads, two analog joysticks, and two * analog fire buttons (left and right). */ int control_bits = 0; switch (key) { case 'a': case 'A': control_bits = 0x0004; break; case 'b': case 'B': control_bits = 0x0002; break; case 'c': case 'C': control_bits = 0x0001; break; case 'd': case 'D': control_bits = 0x0800; break; case 'x': case 'X': control_bits = 0x0400; break; case 'y': case 'Y': control_bits = 0x0200; break; case 'z': case 'Z': control_bits = 0x0100; break; case 's': case 'S': /* Start */ control_bits = 0x0008; break; case '8': /* up */ control_bits = 0x0010; break; case '2': /* down */ case 'k': control_bits = 0x0020; break; case '4': /* left */ case 'u': control_bits = 0x0040; break; case '6': /* right */ case 'o': control_bits = 0x0080; break; } if (control_bits != 0) { /* Add to the controller queue: */ d->controller_queue[d->controller_queue_head] = control_bits; d->controller_queue_head = (d->controller_queue_head + 1) % MAX_CONTROLLER_DATA; if (d->controller_queue_head == d->controller_queue_tail) fatal("[ dreamcast_maple: CONTROLLER QUEUE " "OVERRUN! ]\n"); } } } static int get_key(struct dreamcast_maple_data *d) { int key = d->char_queue[d->char_queue_tail]; if (d->char_queue_head == d->char_queue_tail) return -1; d->char_queue_tail = (d->char_queue_tail + 1) % MAX_CHARS; return key; } static int get_controller(struct dreamcast_maple_data *d) { int c = d->controller_queue[d->controller_queue_tail]; if (d->controller_queue_head == d->controller_queue_tail) return 0; d->controller_queue_tail = (d->controller_queue_tail + 1) % MAX_CONTROLLER_DATA; return c; } /* * maple_getcond_controller_response(): * * Generate a controller response. Based on info from Marcus * Comstedt's page: http://mc.pp.se/dc/controller.html */ static void maple_getcond_controller_response(struct dreamcast_maple_data *d, struct cpu *cpu, int port, uint32_t receive_addr) { uint8_t buf[8]; uint32_t response_code, transfer_code; int c; transfer_code = (MAPLE_RESPONSE_DATATRF << 24) | (((port << 6) | 0x20) << 16) | ((port << 6) << 8) | 3 /* Transfer length in 32-bit words */; transfer_code = BE32_TO_HOST(transfer_code); cpu->memory_rw(cpu, cpu->mem, receive_addr, (unsigned char *) (void *) &transfer_code, 4, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); receive_addr += 4; response_code = BE32_TO_HOST(MAPLE_FUNC(MAPLE_FN_CONTROLLER)); cpu->memory_rw(cpu, cpu->mem, receive_addr, (unsigned char *) (void *) &response_code, 4, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); receive_addr += 4; /* NOTE: Inverse of the buttons pressed! */ c = ~get_controller(d); /* * buf[0..1] = little endian button bitfield * buf[2] = right analogue trigger (0-255) * buf[3] = left analogue trigger (0-255) * buf[4] = analogue joystick X (0-255) * buf[5] = analogue joystick Y (0-255) * buf[6] = second analogue joystick X (0-255) * buf[7] = second analogue joystick Y (0-255) */ memset(buf, 0, 8); buf[0] = c & 0xff; buf[1] = c >> 8; buf[2] = buf[3] = 0; // 0 = not pressed buf[4] = buf[5] = buf[6] = buf[7] = 128; // 128 = centered cpu->memory_rw(cpu, cpu->mem, receive_addr, (unsigned char *) (void *) &buf, 8, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); } /* * maple_getcond_keyboard_response(): * * Generate a keyboard key-press response. Based on info from Marcus * Comstedt's page: http://mc.pp.se/dc/kbd.html */ static void maple_getcond_keyboard_response(struct dreamcast_maple_data *d, struct cpu *cpu, int port, uint32_t receive_addr) { int key; uint8_t buf[8]; uint32_t response_code, transfer_code; transfer_code = (MAPLE_RESPONSE_DATATRF << 24) | (((port << 6) | 0x20) << 16) | ((port << 6) << 8) | 3 /* Transfer length in 32-bit words */; transfer_code = BE32_TO_HOST(transfer_code); cpu->memory_rw(cpu, cpu->mem, receive_addr, (unsigned char *) (void *) &transfer_code, 4, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); receive_addr += 4; response_code = BE32_TO_HOST(MAPLE_FUNC(MAPLE_FN_KEYBOARD)); cpu->memory_rw(cpu, cpu->mem, receive_addr, (unsigned char *) (void *) &response_code, 4, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); receive_addr += 4; key = get_key(d); /* * buf[0] = shift keys (1 = left ctrl, 2 = shift, 0x10 = right ctrl) * buf[1] = led state * buf[2] = key */ memset(buf, 0, 8); if (key >= 'a' && key <= 'z') buf[2] = 4 + key - 'a'; if (key >= 'A' && key <= 'Z') buf[0] = 2, buf[2] = 4 + key - 'A'; if (key >= 1 && key <= 26) buf[0] = 1, buf[2] = 4 + key - 1; if (key >= '1' && key <= '9') buf[2] = 0x1e + key - '1'; if (key == '!') buf[0] = 2, buf[2] = 0x1e; if (key == '"') buf[0] = 2, buf[2] = 0x1f; if (key == '#') buf[0] = 2, buf[2] = 0x20; if (key == '$') buf[0] = 2, buf[2] = 0x21; if (key == '%') buf[0] = 2, buf[2] = 0x22; if (key == '^') buf[0] = 2, buf[2] = 0x23; if (key == '&') buf[0] = 2, buf[2] = 0x24; if (key == '*') buf[0] = 2, buf[2] = 0x25; if (key == '(') buf[0] = 2, buf[2] = 0x26; if (key == '@') buf[0] = 2, buf[2] = 0x1f; if (key == '\n' || key == '\r') buf[0] = 0, buf[2] = 0x28; if (key == ')') buf[0] = 2, buf[2] = 0x27; if (key == '\b') buf[0] = 0, buf[2] = 0x2a; if (key == '\t') buf[0] = 0, buf[2] = 0x2b; if (key == ' ') buf[0] = 0, buf[2] = 0x2c; if (key == '0') buf[2] = 0x27; if (key == 27) buf[2] = 0x29; if (key == '-') buf[2] = 0x2d; if (key == '=') buf[2] = 0x2e; if (key == '[') buf[2] = 0x2f; if (key == '\\') buf[2] = 0x31; if (key == '|') buf[2] = 0x31, buf[0] = 2; if (key == ']') buf[2] = 0x32; if (key == ';') buf[2] = 0x33; if (key == ':') buf[2] = 0x34; if (key == ',') buf[2] = 0x36; if (key == '.') buf[2] = 0x37; if (key == '/') buf[2] = 0x38; if (key == '<') buf[2] = 0x36, buf[0] = 2; if (key == '>') buf[2] = 0x37, buf[0] = 2; if (key == '?') buf[2] = 0x38, buf[0] = 2; if (key == '+') buf[2] = 0x57; cpu->memory_rw(cpu, cpu->mem, receive_addr, (unsigned char *) (void *) &buf, 8, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); } /* * maple_do_dma_xfer(): * * Perform a DMA transfer. enable should be 1, and dmaaddr should point to * the memory to transfer. */ void maple_do_dma_xfer(struct cpu *cpu, struct dreamcast_maple_data *d) { uint32_t addr = d->dmaaddr; if (!d->enable) { debug("[ maple_do_dma_xfer: not enabled? ]\n"); return; } /* debug("[ dreamcast_maple: DMA transfer, dmaaddr = " "0x%08" PRIx32" ]\n", addr); */ /* * DMA transfers must be 32-byte aligned, according to Marcus * Comstedt's Maple demo program. */ if (addr & 0x1f) { fatal("[ dreamcast_maple: dmaaddr 0x%08" PRIx32" is NOT" " 32-byte aligned; aborting ]\n", addr); return; } /* * Handle one or more requests/responses: * * (This is "reverse engineered" from Comstedt's maple demo program; * it might not be good enough to emulate how the Maple is being * used by other programs.) */ for (;;) { uint32_t receive_addr, response_code, cond; int datalen, port, last_message, cmd, to, from, datalen_cmd; int unit; uint8_t buf[8]; /* Read the message' two control words: */ cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *) (void *) &buf, 8, MEM_READ, NO_EXCEPTIONS | PHYSICAL); addr += 8; datalen = buf[0] * sizeof(uint32_t); if (buf[1] & 2) { fatal("[ dreamcast_maple: TODO: GUN bit. ]\n"); /* TODO: Set some bits in A05F80C4 to indicate which raster position a lightgun is pointing at! */ exit(1); } port = buf[2]; last_message = buf[3] & 0x80; receive_addr = buf[4] + (buf[5] << 8) + (buf[6] << 16) + (buf[7] << 24); if (receive_addr & 0xe000001f) fatal("[ dreamcast_maple: WARNING! receive address 0x" "%08" PRIx32" isn't valid! ]\n", receive_addr); /* Read the command word for this message: */ cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *) (void *) &buf, 4, MEM_READ, NO_EXCEPTIONS | PHYSICAL); addr += 4; cmd = buf[0]; to = buf[1]; from = buf[2]; datalen_cmd = buf[3]; /* Decode the unit number: */ unit = 0; switch (to & 0x3f) { case 0x00: case 0x20: unit = 0; break; case 0x01: unit = 1; break; case 0x02: unit = 2; break; case 0x04: unit = 3; break; case 0x08: unit = 4; break; case 0x10: unit = 5; break; default: fatal("[ dreamcast_maple: ERROR! multiple " "units? Not yet implemented. to = 0x%02x ]\n", to); exit(1); } /* fatal("[ dreamcast_maple: cmd=0x%02x, port=%c, unit=%i" ", datalen=%i words. receive_addr=0x%08x ]\n", cmd, port+'A', unit, datalen_cmd, receive_addr); */ /* * Handle the command: */ switch (cmd) { case MAPLE_COMMAND_DEVINFO: if (d->device[port] == NULL || unit != 0) { /* No device present: Timeout. */ /* debug("[ dreamcast_maple: response=" "timeout ]\n"); */ response_code = (uint32_t) -1; response_code = LE32_TO_HOST(response_code); cpu->memory_rw(cpu, cpu->mem, receive_addr, (unsigned char *) (void *) &response_code, 4, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); } else { /* Device present: */ unsigned int i; struct maple_devinfo *di = &d->device[port]->devinfo; /* debug("[ dreamcast_maple: response=" "\"%s\" ]\n", di->di_product_name); */ response_code = MAPLE_RESPONSE_DEVINFO | (((port << 6) | 0x20) << 8) | ((port << 6) << 16) | ((sizeof(struct maple_devinfo) / sizeof(uint32_t)) << 24); response_code = LE32_TO_HOST(response_code); cpu->memory_rw(cpu, cpu->mem, receive_addr, (unsigned char *) (void *) &response_code, 4, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); for (i=0; imemory_rw(cpu, cpu->mem, receive_addr + 4 + i, (unsigned char *) di + i, 1, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); } break; case MAPLE_COMMAND_GETCOND: cpu->memory_rw(cpu, cpu->mem, addr, (unsigned char *) (void *) &buf, 4, MEM_READ, NO_EXCEPTIONS | PHYSICAL); cond = buf[3] + (buf[2] << 8) + (buf[1] << 16) + (buf[0] << 24); if (cond & MAPLE_FUNC(MAPLE_FN_CONTROLLER)) { maple_getcond_controller_response( d, cpu, port, receive_addr); } else if (cond & MAPLE_FUNC(MAPLE_FN_KEYBOARD)) { maple_getcond_keyboard_response( d, cpu, port, receive_addr); } else { fatal("[ dreamcast_maple: WARNING: GETCOND: " "UNIMPLEMENTED 0x%08" PRIx32" ]\n", cond); exit(1); } break; case MAPLE_COMMAND_BWRITE: fatal("[ dreamcast_maple: BWRITE: TODO ]\n"); break; default:fatal("[ dreamcast_maple: command %i: TODO ]\n", cmd); exit(1); } addr += datalen_cmd * 4; /* Last request? Then stop. */ if (last_message) break; } // TODO: Should the DMA address be updated? d->dmaaddr = addr; /* Assert the SYSASIC_EVENT_MAPLE_DMADONE event: */ SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_MAPLE_DMADONE); } DEVICE_ACCESS(dreamcast_maple) { struct dreamcast_maple_data *d = (struct dreamcast_maple_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0x04: /* MAPLE_DMAADDR */ if (writeflag == MEM_WRITE) { d->dmaaddr = idata; /* debug("[ dreamcast_maple: dmaaddr set to 0x%08x" " ]\n", d->dmaaddr); */ } else { fatal("[ dreamcast_maple: TODO: read from dmaaddr ]\n"); odata = d->dmaaddr; exit(1); } break; case 0x10: /* MAPLE_RESET2 */ if (writeflag == MEM_WRITE && idata != 0) fatal("[ dreamcast_maple: UNIMPLEMENTED reset2 value" " 0x%08x ]\n", (int)idata); break; case 0x14: /* MAPLE_ENABLE */ if (writeflag == MEM_WRITE) d->enable = idata; else odata = d->enable; break; case 0x18: /* MAPLE_STATE */ if (writeflag == MEM_WRITE) { switch (idata) { case 0: break; case 1: maple_do_dma_xfer(cpu, d); break; default:fatal("[ dreamcast_maple: UNIMPLEMENTED " "state value %i ]\n", (int)idata); } } else { /* Always return 0 to indicate DMA xfer complete. */ odata = 0; } break; case 0x80: /* MAPLE_SPEED */ if (writeflag == MEM_WRITE) { d->timeout = (idata >> 16) & 0xffff; /* TODO: Bits 8..9 are "speed", but only the value 0 (indicating 2 Mbit/s) should be used. */ debug("[ dreamcast_maple: timeout set to %i ]\n", d->timeout); } else { odata = d->timeout << 16; } break; case 0x8c: /* MAPLE_RESET */ if (writeflag == MEM_WRITE) { if (idata != 0x6155404f && idata != 0x61557f00) fatal("[ dreamcast_maple: UNIMPLEMENTED reset " "value 0x%08x ]\n", (int)idata); d->enable = 0; } break; case 0xe8: /* UNKNOWN_0xe8 */ if (writeflag == MEM_WRITE) { // The Dreamcast PROM writes 1 here. if (idata != 1) { fatal("[ dreamcast_maple: UNIMPLEMENTED 0xe8 " "value 0x%08x ]\n", (int)idata); } } break; default:if (writeflag == MEM_READ) { fatal("[ dreamcast_maple: UNIMPLEMENTED read from " "addr 0x%x ]\n", (int)relative_addr); } else { fatal("[ dreamcast_maple: UNIMPLEMENTED write to addr " "0x%x: 0x%x ]\n", (int)relative_addr, (int)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(dreamcast_maple) { struct dreamcast_maple_data *d; CHECK_ALLOCATION(d = (struct dreamcast_maple_data *) malloc(sizeof(struct dreamcast_maple_data))); memset(d, 0, sizeof(struct dreamcast_maple_data)); memory_device_register(devinit->machine->memory, devinit->name, 0x5f6c00, 0x100, dev_dreamcast_maple_access, d, DM_DEFAULT, NULL); /* Devices connected to port A..D: */ d->device[0] = &maple_device_controller; d->device[1] = NULL; d->device[2] = &maple_device_keyboard; d->device[3] = NULL; /* TODO: &maple_device_mouse; */ d->console_handle = console_start_slave_inputonly( devinit->machine, "maple", 1); devinit->machine->main_console_handle = d->console_handle; machine_add_tickfunction(devinit->machine, dev_maple_tick, d, MAPLE_TICK_SHIFT); return 1; } gxemul-0.6.1/src/devices/dev_zero.cc000644 001750 001750 00000004024 13402411502 017562 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: A simple device which returns zero for reads, discards all writes */ #include #include #include #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" DEVICE_ACCESS(zero) { if (writeflag == MEM_READ) { size_t i; for (i=0; imachine->memory, devinit->name, devinit->addr, devinit->len, dev_zero_access, NULL, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_prep.cc000644 001750 001750 00000005223 13402411502 017553 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: PReP machine mainbus (ISA bus + interrupt controller) */ #include #include #include #include "bus_isa.h" #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" struct prep_data { uint32_t int_status; }; DEVICE_ACCESS(prep) { /* struct prep_data *d = extra; */ uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (writeflag == MEM_READ) { odata = cpu->machine->isa_pic_data.last_int; } else { fatal("[ prep: write to interrupt register? ]\n"); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(prep) { struct prep_data *d; CHECK_ALLOCATION(d = (struct prep_data *) malloc(sizeof(struct prep_data))); memset(d, 0, sizeof(struct prep_data)); memory_device_register(devinit->machine->memory, devinit->name, 0xbffff000, 0x1000, dev_prep_access, d, DM_DEFAULT, NULL); /* This works for at least the IBM 6050: */ bus_isa_init(devinit->machine, devinit->interrupt_path, BUS_ISA_IDE0 | BUS_ISA_IDE1, 0x80000000, 0xc0000000); return 1; } gxemul-0.6.1/src/devices/fb_include.cc000644 001750 001750 00000023034 13402411502 020041 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Included from dev_fb.c. * * FB_SCALEDOWN should be defined if d->vfb_scaledown > 1. * FB_BO for d->fb_window->fb_ximage->byte_order non-zero * FB_24 for 24-bit X11 color. * FB_16 for 16-bit X11 color. * FB_15 for 15-bit X11 color. * (Default is to fallback to grayscale.) */ #ifdef macro_put_pixel1 #undef macro_put_pixel1 #endif /* Combine the color into an X11 long and display it: */ \ /* TODO: construct color in a more portable way: */ \ #ifdef FB_24 #ifdef FB_BO #define macro_put_pixel1 color = (b << 16) + (g << 8) + r #else #define macro_put_pixel1 color = (r << 16) + (g << 8) + b #endif #else /* !24 */ #ifdef FB_16 #ifdef FB_BO #define macro_put_pixel1 color = ((b >> 3) << 11) + ((g >> 2) << 5) + (r >> 3) #else #define macro_put_pixel1 color = ((r >> 3) << 11) + ((g >> 2) << 5) + (b >> 3) #endif #else /* !16 */ #ifdef FB_15 #ifdef FB_BO #define macro_put_pixel1 color = ((b >> 3) << 10) + ((g >> 3) << 5) + (r >> 3) #else #define macro_put_pixel1 color = ((r >> 3) << 10) + ((g >> 3) << 5) + (b >> 3) #endif #else /* !15 */ #define macro_put_pixel1 color = d->fb_window->x11_graycolor[15 * \ (r + g + b) / (255 * 3)].pixel #endif /* !15 */ #endif /* !16 */ #endif /* !24 */ #ifdef macro_put_pixel #undef macro_put_pixel #endif #define macro_put_pixel macro_put_pixel1; \ if (x>=0 && xx11_xsize && y>=0 && yx11_ysize) \ XPutPixel(d->fb_window->fb_ximage, x, y, color); \ void REDRAW(struct vfb_data *d, int addr, int len) { int x, y, pixel, npixels; long color_r, color_g, color_b; long color; #ifndef FB_SCALEDOWN /* Which framebuffer pixel does addr correspond to? */ pixel = addr * 8 / d->bit_depth; y = pixel / d->xsize; x = pixel % d->xsize; /* How many framebuffer pixels? */ npixels = len * 8 / d->bit_depth; if (npixels == 0) npixels = 1; if (d->bit_depth < 8) { for (pixel=0; pixelxsize + x) * d->bit_depth; /* fb_addr is now which _bit_ in the framebuffer */ c = d->framebuffer[fb_addr >> 3]; fb_addr &= 7; /* HPC is reverse: */ if (d->vfb_type == VFB_HPC) fb_addr = 8 - d->bit_depth - fb_addr; c = (c >> fb_addr) & ((1<bit_depth) - 1); /* c <<= (8 - d->bit_depth); */ r = d->rgb_palette[c*3 + 0]; g = d->rgb_palette[c*3 + 1]; b = d->rgb_palette[c*3 + 2]; macro_put_pixel; x++; } } else if (d->bit_depth == 8) { for (pixel=0; pixelxsize + x; /* fb_addr is now which byte in framebuffer */ c = d->framebuffer[fb_addr]; r = d->rgb_palette[c*3 + 0]; g = d->rgb_palette[c*3 + 1]; b = d->rgb_palette[c*3 + 2]; macro_put_pixel; x++; } } else { /* d->bit_depth > 8 */ for (pixel=0; pixelxsize + x) * d->bit_depth; /* fb_addr is now which byte in framebuffer */ /* > 8 bits color. */ fb_addr >>= 3; switch (d->bit_depth) { case 24: case 32: r = d->framebuffer[fb_addr]; g = d->framebuffer[fb_addr + 1]; b = d->framebuffer[fb_addr + 2]; break; case 16: if (d->vfb_type == VFB_HPC) { b = d->framebuffer[fb_addr] + (d->framebuffer[fb_addr+1] << 8); if (d->color32k) { r = b >> 11; g = b >> 5; r = r & 31; g = (g & 31) * 2; b = b & 31; } else if (d->psp_15bit) { int tmp; r = (b >> 10) & 0x1f; g = (b >> 5) & 0x1f; b = b & 0x1f; g <<= 1; tmp = r; r = b; b = tmp; } else { r = (b >> 11) & 0x1f; g = (b >> 5) & 0x3f; b = b & 0x1f; } } else { r = d->framebuffer[fb_addr] >> 3; /* HUH? TODO: */ g = (d->framebuffer[fb_addr] << 5) + (d->framebuffer[fb_addr + 1] >>5); b = d->framebuffer[fb_addr + 1]&31; } r *= 8; g *= 4; b *= 8; break; default: r = g = b = random() & 255; } macro_put_pixel; x++; } } #else /* FB_SCALEDOWN */ /* scaledown > 1: */ int scaledown = d->vfb_scaledown; int scaledownXscaledown = scaledown * scaledown; /* Which framebuffer pixel does addr correspond to? */ pixel = addr * 8 / d->bit_depth; y = pixel / d->xsize; x = pixel % d->xsize; /* How many framebuffer pixels? */ npixels = len * 8 / d->bit_depth; /* Which x11 pixel? */ x /= scaledown; y /= scaledown; /* How many x11 pixels: */ npixels /= scaledown; if (npixels == 0) npixels = 1; if (d->bit_depth < 8) { for (pixel=0; pixelxsize + fb_x; fb_addr = fb_addr * d->bit_depth; /* fb_addr is now which _bit_ in the framebuffer */ c = d->framebuffer[fb_addr >> 3]; fb_addr &= 7; /* HPC is reverse: */ if (d->vfb_type == VFB_HPC) fb_addr = 8 - d->bit_depth - fb_addr; c = (c >> fb_addr) & ((1<bit_depth) - 1); /* c <<= (8 - d->bit_depth); */ r = d->rgb_palette[c*3 + 0]; g = d->rgb_palette[c*3 + 1]; b = d->rgb_palette[c*3 + 2]; color_r += r; color_g += g; color_b += b; } r = color_r / scaledownXscaledown; g = color_g / scaledownXscaledown; b = color_b / scaledownXscaledown; macro_put_pixel; x++; } } else if (d->bit_depth == 8) { for (pixel=0; pixelxsize + fb_x; /* fb_addr is which _byte_ in framebuffer */ c = d->framebuffer[fb_addr] * 3; r = d->rgb_palette[c + 0]; g = d->rgb_palette[c + 1]; b = d->rgb_palette[c + 2]; color_r += r; color_g += g; color_b += b; } r = color_r / scaledownXscaledown; g = color_g / scaledownXscaledown; b = color_b / scaledownXscaledown; macro_put_pixel; x++; } } else { /* Generic > 8 bit bit-depth: */ for (pixel=0; pixelxsize + fb_x; fb_addr = (fb_addr * d->bit_depth) >> 3; /* fb_addr is which _byte_ in framebuffer */ /* > 8 bits color. */ switch (d->bit_depth) { case 24: case 32: r = d->framebuffer[fb_addr]; g = d->framebuffer[fb_addr + 1]; b = d->framebuffer[fb_addr + 2]; break; case 16: if (d->vfb_type == VFB_HPC) { b = d->framebuffer[fb_addr] + (d->framebuffer[fb_addr+1] << 8); if (d->color32k) { r = b >> 11; g = b >> 5; r = r & 31; g = (g & 31) * 2; b = b & 31; } else if (d->psp_15bit) { int tmp; r = (b >> 10) & 0x1f; g = (b >> 5) & 0x1f; b = b & 0x1f; g <<= 1; tmp = r; r = b; b = tmp; } else { r = (b >> 11) & 0x1f; g = (b >> 5) & 0x3f; b = b & 0x1f; } } else { r = d->framebuffer[fb_addr] >> 3; /* HUH? TODO: */ g = (d->framebuffer[fb_addr] << 5) + (d->framebuffer[fb_addr + 1] >>5); b = d->framebuffer[fb_addr + 1]&31; } r *= 8; g *= 4; b *= 8; break; default: r = g = b = random() & 255; } color_r += r; color_g += g; color_b += b; } r = color_r / scaledownXscaledown; g = color_g / scaledownXscaledown; b = color_b / scaledownXscaledown; macro_put_pixel; x++; } } #endif /* FB_SCALEDOWN */ } gxemul-0.6.1/src/devices/dev_uninorth.cc000644 001750 001750 00000010671 13402411502 020456 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Uni-North PCI controller (used by MacPPC machines) */ #include #include #include #include "bus_pci.h" #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" struct uninorth_data { int pciirq; struct pci_data *pci_data; uint64_t cur_addr; }; DEVICE_ACCESS(uninorth_addr) { struct uninorth_data *d = (struct uninorth_data *) extra; if (writeflag == MEM_WRITE) { uint64_t idata = memory_readmax64(cpu, data, len | MEM_PCI_LITTLE_ENDIAN); int bus, dev, func, reg; d->cur_addr = idata; if (idata == 0) return 0; /* Decompose the Uni-North tag: */ if (idata & 1) { idata &= ~1; bus_pci_decompose_1(idata, &bus, &dev, &func, ®); } else { bus = 0; for (dev=11; dev<32; dev++) if (idata & (1 << dev)) break; if (dev == 32) fatal("[ dev_uninorth_addr_access: no dev? " "idata=0x%08x ]\n", (int)idata); func = (idata >> 8) & 7; reg = idata & 0xff; } bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, reg); } else { /* TODO: is returning the current address like this the correct behaviour? */ memory_writemax64(cpu, data, len | MEM_PCI_LITTLE_ENDIAN, d->cur_addr); } return 1; } DEVICE_ACCESS(uninorth_data) { struct uninorth_data *d = (struct uninorth_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN); bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ? &odata : &idata, len, writeflag); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN, odata); return 1; } struct pci_data *dev_uninorth_init(struct machine *machine, struct memory *mem, uint64_t addr, int isa_irqbase, int pciirq) { struct uninorth_data *d; uint64_t pci_io_offset, pci_mem_offset; uint64_t isa_portbase = 0, isa_membase = 0; uint64_t pci_portbase = 0, pci_membase = 0; CHECK_ALLOCATION(d = (struct uninorth_data *) malloc(sizeof(struct uninorth_data))); memset(d, 0, sizeof(struct uninorth_data)); d->pciirq = pciirq; pci_io_offset = 0x00000000ULL; pci_mem_offset = 0x00000000ULL; pci_portbase = 0xd0000000ULL; pci_membase = 0xd1000000ULL; isa_portbase = 0xd2000000ULL; isa_membase = 0xd3000000ULL; /* Create a PCI bus: */ d->pci_data = bus_pci_init(machine, "ZZZ_irq_stuff", pci_io_offset, pci_mem_offset, pci_portbase, pci_membase, "XXX_pci_irqbase", isa_portbase, isa_membase, "YYY_isa_irqbase"); /* Add the PCI glue for the controller itself: */ bus_pci_add(machine, d->pci_data, mem, 0, 11, 0, "uninorth"); /* ADDR and DATA configuration ports: */ memory_device_register(mem, "uninorth_pci_addr", addr + 0x800000, 4, dev_uninorth_addr_access, d, DM_DEFAULT, NULL); memory_device_register(mem, "uninorth_pci_data", addr + 0xc00000, 8, dev_uninorth_data_access, d, DM_DEFAULT, NULL); return d->pci_data; } gxemul-0.6.1/src/devices/dev_colorplanemask.cc000644 001750 001750 00000006050 13402411502 021616 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Color plane mask, used in the DECstation 3100 machine * * Just a one-byte thingy, but the way things work now this has to * be a separate device. :-/ */ #include #include #include #include "devices.h" #include "memory.h" #include "misc.h" struct colorplanemask_data { unsigned char *color_plane_mask; }; DEVICE_ACCESS(colorplanemask) { struct colorplanemask_data *d = (struct colorplanemask_data *) extra; switch (relative_addr) { case 0x00: if (writeflag == MEM_WRITE) { *d->color_plane_mask = data[0]; } else { debug("[ colorplanemask: read isn't actually " "supported ]\n"); data[0] = *d->color_plane_mask; } break; default: if (writeflag == MEM_WRITE) { debug("[ colorplanemask: unimplemented write " "to address 0x%x, data=0x%02x ]\n", (int)relative_addr, data[0]); } else { debug("[ colorplanemask: unimplemented read " "from address 0x%x ]\n", (int)relative_addr); } } /* Pretend it was ok: */ return 1; } /* * dev_colorplanemask_init(): */ void dev_colorplanemask_init(struct memory *mem, uint64_t baseaddr, unsigned char *color_plane_mask) { struct colorplanemask_data *d; CHECK_ALLOCATION(d = (struct colorplanemask_data *) malloc(sizeof(struct colorplanemask_data))); memset(d, 0, sizeof(struct colorplanemask_data)); d->color_plane_mask = color_plane_mask; memory_device_register(mem, "colorplanemask", baseaddr, DEV_COLORPLANEMASK_LENGTH, dev_colorplanemask_access, (void *)d, DM_DEFAULT, NULL); } gxemul-0.6.1/src/devices/dev_pccmos.cc000644 001750 001750 00000010763 13402411502 020076 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: PC CMOS/RTC device (ISA ports 0x70 and 0x71) * * The main point of this device is to be a "PC style wrapper" for accessing * the MC146818 (the RTC). In most other respects, this device is bogus, and * just acts as a 256-byte RAM device. */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #define DEV_PCCMOS_LENGTH 2 #define PCCMOS_MC146818_FAKE_ADDR 0x1d00000000ULL struct pccmos_data { unsigned char select; unsigned char ram[256]; }; DEVICE_ACCESS(pccmos) { struct pccmos_data *d = (struct pccmos_data *) extra; uint64_t idata = 0, odata = 0; unsigned char b = 0; int r = 1; if (writeflag == MEM_WRITE) b = idata = memory_readmax64(cpu, data, len); /* * Accesses to CMOS register 0 .. 0xd are rerouted to the * RTC; all other access are treated as CMOS RAM read/writes. */ if ((relative_addr & 1) == 0) { if (writeflag == MEM_WRITE) { d->select = idata; if (idata <= 0x0d) { r = cpu->memory_rw(cpu, cpu->mem, PCCMOS_MC146818_FAKE_ADDR, &b, 1, MEM_WRITE, PHYSICAL); } } else odata = d->select; } else { if (d->select <= 0x0d) { if (writeflag == MEM_WRITE) { r = cpu->memory_rw(cpu, cpu->mem, PCCMOS_MC146818_FAKE_ADDR + 1, &b, 1, MEM_WRITE, PHYSICAL); } else { r = cpu->memory_rw(cpu, cpu->mem, PCCMOS_MC146818_FAKE_ADDR + 1, &b, 1, MEM_READ, PHYSICAL); odata = b; } } else { if (writeflag == MEM_WRITE) d->ram[d->select] = idata; else odata = d->ram[d->select]; } } if (r == 0) fatal("[ pccmos: memory_rw() error! ]\n"); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(pccmos) { int type = MC146818_PC_CMOS, len = DEV_PCCMOS_LENGTH; struct pccmos_data *d; CHECK_ALLOCATION(d = (struct pccmos_data *) malloc(sizeof(struct pccmos_data))); memset(d, 0, sizeof(struct pccmos_data)); switch (devinit->machine->machine_type) { case MACHINE_CATS: case MACHINE_NETWINDER: type = MC146818_CATS; d->ram[0x48] = 20; /* century */ len = DEV_PCCMOS_LENGTH * 2; break; case MACHINE_ALGOR: type = MC146818_ALGOR; break; case MACHINE_ARC: fatal("\nARC pccmos: TODO\n\n"); type = MC146818_ALGOR; break; case MACHINE_EVBMIPS: /* Malta etc. */ type = MC146818_ALGOR; break; case MACHINE_QEMU_MIPS: case MACHINE_COBALT: case MACHINE_PREP: case MACHINE_MVMEPPC: case MACHINE_ALPHA: case MACHINE_IYONIX: // TODO: not sure about exact type. break; default:fatal("devinit_pccmos(): unimplemented machine type" " %i\n", devinit->machine->machine_type); exit(1); } memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, len, dev_pccmos_access, (void *)d, DM_DEFAULT, NULL); dev_mc146818_init(devinit->machine, devinit->machine->memory, PCCMOS_MC146818_FAKE_ADDR, devinit->interrupt_path, type, 1); return 1; } gxemul-0.6.1/src/devices/dev_ether.cc000644 001750 001750 00000015415 13402411502 017720 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: A simple ethernet controller, for the test machines * * Basic "ethernet" network device. This is a simple test device which can * be used to send and receive packets to/from a simulated ethernet network. */ #include #include #include #include "cpu.h" #include "device.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "net.h" #include "testmachine/dev_ether.h" #define DEV_ETHER_TICK_SHIFT 14 struct ether_data { unsigned char buf[DEV_ETHER_BUFFER_SIZE]; unsigned char mac[6]; int status; int packet_len; struct interrupt irq; }; DEVICE_TICK(ether) { struct ether_data *d = (struct ether_data *) extra; int r = 0; d->status &= ~DEV_ETHER_STATUS_MORE_PACKETS_AVAILABLE; if (cpu->machine->emul->net != NULL) r = net_ethernet_rx_avail(cpu->machine->emul->net, d); if (r) d->status |= DEV_ETHER_STATUS_MORE_PACKETS_AVAILABLE; if (d->status) INTERRUPT_ASSERT(d->irq); else INTERRUPT_DEASSERT(d->irq); } DEVICE_ACCESS(ether_buf) { struct ether_data *d = (struct ether_data *) extra; if (writeflag == MEM_WRITE) memcpy(d->buf + relative_addr, data, len); else memcpy(data, d->buf + relative_addr, len); return 1; } DEVICE_ACCESS(ether) { struct ether_data *d = (struct ether_data *) extra; uint64_t idata = 0, odata = 0; unsigned char *incoming_ptr; int incoming_len; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* Note: relative_addr + DEV_ETHER_BUFFER_SIZE to get the same offsets as in the header file: */ switch (relative_addr + DEV_ETHER_BUFFER_SIZE) { case DEV_ETHER_STATUS: if (writeflag == MEM_READ) { odata = d->status; d->status = 0; INTERRUPT_DEASSERT(d->irq); } else fatal("[ ether: WARNING: write to status ]\n"); break; case DEV_ETHER_PACKETLENGTH: if (writeflag == MEM_READ) odata = d->packet_len; else { if ((int64_t)idata < 0) { fatal("[ ether: ERROR: packet len too" " short (%i bytes) ]\n", (int)idata); idata = (uint64_t) -1; } if (idata > DEV_ETHER_BUFFER_SIZE) { fatal("[ ether: ERROR: packet len too" " large (%i bytes) ]\n", (int)idata); idata = DEV_ETHER_BUFFER_SIZE; } d->packet_len = idata; } break; case DEV_ETHER_COMMAND: if (writeflag == MEM_READ) { fatal("[ ether: WARNING: read from command ]\n"); break; } /* Write: */ switch (idata) { case DEV_ETHER_COMMAND_RX: /* Receive: */ if (cpu->machine->emul->net == NULL) fatal("[ ether: RECEIVE but no net? ]\n"); else { d->status &= ~DEV_ETHER_STATUS_PACKET_RECEIVED; if (net_ethernet_rx(cpu->machine->emul->net, d, &incoming_ptr, &incoming_len)) { d->status |= DEV_ETHER_STATUS_PACKET_RECEIVED; if (incoming_len>DEV_ETHER_BUFFER_SIZE) incoming_len = DEV_ETHER_BUFFER_SIZE; memcpy(d->buf, incoming_ptr, incoming_len); free(incoming_ptr); d->packet_len = incoming_len; } } dev_ether_tick(cpu, d); break; case DEV_ETHER_COMMAND_TX: /* Send */ if (cpu->machine->emul->net == NULL) fatal("[ ether: SEND but no net? ]\n"); else net_ethernet_tx(cpu->machine->emul->net, d, d->buf, d->packet_len); d->status &= ~DEV_ETHER_STATUS_PACKET_RECEIVED; dev_ether_tick(cpu, d); break; default:fatal("[ ether: UNIMPLEMENTED command 0x" "%02x ]\n", idata); cpu->running = 0; } break; case DEV_ETHER_MAC: if (writeflag == MEM_READ) { fatal("[ ether: read of MAC is not allowed! ]\n"); } else { // Write out the MAC address to the address given. cpu->memory_rw(cpu, cpu->mem, idata, d->mac, 6, MEM_WRITE, CACHE_NONE); } break; default:if (writeflag == MEM_WRITE) { fatal("[ ether: unimplemented write to " "offset 0x%x: data=0x%x ]\n", (int) relative_addr, (int)idata); } else { fatal("[ ether: unimplemented read from " "offset 0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(ether) { struct ether_data *d; size_t nlen; char *n1, *n2; char tmp[50]; CHECK_ALLOCATION(d = (struct ether_data *) malloc(sizeof(struct ether_data))); memset(d, 0, sizeof(struct ether_data)); nlen = strlen(devinit->name) + 80; CHECK_ALLOCATION(n1 = (char *) malloc(nlen)); CHECK_ALLOCATION(n2 = (char *) malloc(nlen)); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); net_generate_unique_mac(devinit->machine, d->mac); snprintf(tmp, sizeof(tmp), "%02x:%02x:%02x:%02x:%02x:%02x", d->mac[0], d->mac[1], d->mac[2], d->mac[3], d->mac[4], d->mac[5]); snprintf(n1, nlen, "%s [%s]", devinit->name, tmp); snprintf(n2, nlen, "%s [%s, control]", devinit->name, tmp); memory_device_register(devinit->machine->memory, n1, devinit->addr, DEV_ETHER_BUFFER_SIZE, dev_ether_buf_access, (void *)d, DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK | DM_READS_HAVE_NO_SIDE_EFFECTS, d->buf); memory_device_register(devinit->machine->memory, n2, devinit->addr + DEV_ETHER_BUFFER_SIZE, DEV_ETHER_LENGTH-DEV_ETHER_BUFFER_SIZE, dev_ether_access, (void *)d, DM_DEFAULT, NULL); net_add_nic(devinit->machine->emul->net, d, d->mac); machine_add_tickfunction(devinit->machine, dev_ether_tick, d, DEV_ETHER_TICK_SHIFT); return 1; } gxemul-0.6.1/src/devices/dev_ssc.cc000644 001750 001750 00000014275 13402411502 017404 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: System Support Chip serial controller * * Serial controller on DECsystem 5400 and 5800. * Known as System Support Chip on VAX 3600 (KA650). * * Described around page 80 in the kn210tm1.pdf. */ #include #include #include #include "console.h" #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #define RX_INT_ENABLE 0x40 #define RX_AVAIL 0x80 #define TX_INT_ENABLE 0x40 #define TX_READY 0x80 #define SSC_TICK_SHIFT 14 /* * _TXRX is for debugging putchar/getchar. The other * one is more general. */ /* #define SSC_DEBUG_TXRX */ #define SSC_DEBUG struct ssc_data { int console_handle; int use_fb; int rx_ctl; int tx_ctl; struct interrupt irq; }; DEVICE_TICK(ssc) { struct ssc_data *d = (struct ssc_data *) extra; d->tx_ctl |= TX_READY; /* transmitter always ready */ d->rx_ctl &= ~RX_AVAIL; if (console_charavail(d->console_handle)) d->rx_ctl |= RX_AVAIL; /* rx interrupts enabled, and char avail? */ if (d->rx_ctl & RX_INT_ENABLE && d->rx_ctl & RX_AVAIL) { /* TODO: This is for 5800 only! */ unsigned char txvector = 0xf8; cpu->memory_rw(cpu, cpu->mem, 0x40000050, &txvector, 1, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); INTERRUPT_ASSERT(d->irq); } /* tx interrupts enabled? */ if (d->tx_ctl & TX_INT_ENABLE) { /* TODO: This is for 5800 only! */ unsigned char txvector = 0xfc; cpu->memory_rw(cpu, cpu->mem, 0x40000050, &txvector, 1, MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); INTERRUPT_ASSERT(d->irq); } } DEVICE_ACCESS(ssc) { uint64_t idata = 0, odata = 0; struct ssc_data *d = (struct ssc_data *) extra; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); dev_ssc_tick(cpu, extra); switch (relative_addr) { case 0x0080: /* receive status */ if (writeflag==MEM_READ) { odata = d->rx_ctl; #ifdef SSC_DEBUG_TXRX debug("[ ssc: read from 0x%08lx: 0x%02x ]\n", (long)relative_addr, (int)odata); #endif } else { d->rx_ctl = idata; INTERRUPT_DEASSERT(d->irq); #ifdef SSC_DEBUG_TXRX debug("[ ssc: write to 0x%08lx: 0x%02x ]\n", (long)relative_addr, (int)idata); #endif } break; case 0x0084: /* receive data */ if (writeflag==MEM_READ) { #ifdef SSC_DEBUG_TXRX debug("[ ssc: read from 0x%08lx ]\n", (long)relative_addr); #endif if (console_charavail(d->console_handle)) odata = console_readchar(d->console_handle); } else { #ifdef SSC_DEBUG_TXRX debug("[ ssc: write to 0x%08lx: 0x%02x ]\n", (long)relative_addr, (int)idata); #endif } break; case 0x0088: /* transmit status */ if (writeflag==MEM_READ) { odata = d->tx_ctl; #ifdef SSC_DEBUG_TXRX debug("[ ssc: read from 0x%08lx: 0x%04x ]\n", (long)relative_addr, (int)odata); #endif } else { d->tx_ctl = idata; INTERRUPT_DEASSERT(d->irq); #ifdef SSC_DEBUG_TXRX debug("[ ssc: write to 0x%08lx: 0x%02x ]\n", (long)relative_addr, (int)idata); #endif } break; case 0x008c: /* transmit data */ if (writeflag==MEM_READ) { debug("[ ssc: read from 0x%08lx ]\n", (long)relative_addr); } else { /* debug("[ ssc: write to 0x%08lx: 0x%02x ]\n", (long)relative_addr, (int)idata); */ console_putchar(d->console_handle, idata); } break; case 0x0100: if (writeflag==MEM_READ) { odata = 128; #ifdef SSC_DEBUG_TXRX debug("[ ssc: read from 0x%08lx: 0x%08lx ]\n", (long)relative_addr, (long)odata); #endif } else { #ifdef SSC_DEBUG_TXRX debug("[ ssc: write to 0x%08lx: 0x%08x ]\n", (long)relative_addr, idata); #endif } break; case 0x0108: if (writeflag==MEM_READ) { debug("[ ssc: read from 0x%08lx ]\n", (long)relative_addr); } else { #ifdef SSC_DEBUG debug("[ ssc: write to 0x%08lx: 0x%08x ]\n", (long)relative_addr, (int)idata); #endif } break; default: if (writeflag==MEM_READ) { debug("[ ssc: read from 0x%08lx ]\n", (long)relative_addr); } else { debug("[ ssc: write to 0x%08lx: 0x%08x ]\n", (long)relative_addr, (int)idata); } } dev_ssc_tick(cpu, extra); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } void dev_ssc_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, const char *irq_path, int use_fb) { struct ssc_data *d; CHECK_ALLOCATION(d = (struct ssc_data *) malloc(sizeof(struct ssc_data))); memset(d, 0, sizeof(struct ssc_data)); d->use_fb = use_fb; d->console_handle = console_start_slave(machine, "SSC", 1); INTERRUPT_CONNECT(irq_path, d->irq); memory_device_register(mem, "ssc", baseaddr, DEV_SSC_LENGTH, dev_ssc_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(machine, dev_ssc_tick, d, SSC_TICK_SHIFT); } gxemul-0.6.1/src/devices/dev_vga.cc000644 001750 001750 00000102500 13402411502 017356 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: VGA framebuffer device (charcell and graphics modes) * * It should work with 80x25 and 40x25 text modes, and with a few graphics * modes as long as no fancy VGA features are used. */ #include #include #include #include "console.h" #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "../include/vga.h" /* These are generated from binary font files: */ #include "fonts/font8x8.cc" #include "fonts/font8x10.cc" #include "fonts/font8x16.cc" /* For videomem -> framebuffer updates: */ #define VGA_TICK_SHIFT 18 #define MAX_RETRACE_SCANLINES 420 #define N_IS1_READ_THRESHOLD 50 #define GFX_ADDR_WINDOW 0x18000 #define VGA_FB_ADDR 0x1c00000000ULL #define MODE_CHARCELL 1 #define MODE_GRAPHICS 2 #define GRAPHICS_MODE_8BIT 1 #define GRAPHICS_MODE_4BIT 2 struct vga_data { uint64_t videomem_base; uint64_t control_base; struct vfb_data *fb; uint32_t fb_size; int fb_max_x; /* pixels */ int fb_max_y; /* pixels */ int max_x; /* charcells or pixels */ int max_y; /* charcells or pixels */ /* Selects charcell mode or graphics mode: */ int cur_mode; /* Common for text and graphics modes: */ int pixel_repx, pixel_repy; /* Textmode: */ int font_width; int font_height; unsigned char *font; size_t charcells_size; unsigned char *charcells; /* 2 bytes per char */ unsigned char *charcells_outputed; /* text */ unsigned char *charcells_drawn; /* framebuffer */ /* Graphics: */ int graphics_mode; int bits_per_pixel; unsigned char *gfx_mem; uint32_t gfx_mem_size; /* Registers: */ int attribute_state; /* 0 or 1 */ unsigned char attribute_reg_select; unsigned char attribute_reg[256]; unsigned char misc_output_reg; unsigned char sequencer_reg_select; unsigned char sequencer_reg[256]; unsigned char graphcontr_reg_select; unsigned char graphcontr_reg[256]; unsigned char crtc_reg_select; unsigned char crtc_reg[256]; unsigned char palette_read_index; char palette_read_subindex; unsigned char palette_write_index; char palette_write_subindex; int current_retrace_line; int input_status_1; /* Palette per scanline during retrace: */ unsigned char *retrace_palette; int use_palette_per_line; int64_t n_is1_reads; /* Misc.: */ int console_handle; int cursor_x; int cursor_y; int modified; int palette_modified; int update_x1; int update_y1; int update_x2; int update_y2; }; /* * recalc_cursor_position(): * * Should be called whenever the cursor location _or_ the display * base has been changed. */ static void recalc_cursor_position(struct vga_data *d) { int base = (d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8) + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]; int ofs = d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_HIGH] * 256 + d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_LOW]; ofs -= base; d->cursor_x = ofs % d->max_x; d->cursor_y = ofs / d->max_x; } /* * register_reset(): * * Resets many registers to sane values. */ static void register_reset(struct vga_data *d) { /* Home cursor and start at the top: */ d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_HIGH] = d->crtc_reg[VGA_CRTC_CURSOR_LOCATION_LOW] = 0; d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] = d->crtc_reg[VGA_CRTC_START_ADDR_LOW] = 0; recalc_cursor_position(d); /* Reset cursor scanline stuff: */ d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] = d->font_height - 2; d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END] = d->font_height - 1; d->sequencer_reg[VGA_SEQ_MAP_MASK] = 0x0f; d->graphcontr_reg[VGA_GRAPHCONTR_MASK] = 0xff; d->misc_output_reg = VGA_MISC_OUTPUT_IOAS; d->n_is1_reads = 0; } static void c_putstr(struct vga_data *d, const char *s) { while (*s) console_putchar(d->console_handle, *s++); } /* * reset_palette(): */ static void reset_palette(struct vga_data *d, int grayscale) { int i, r, g, b; /* TODO: default values for entry 16..255? */ for (i=16; i<256; i++) d->fb->rgb_palette[i*3 + 0] = d->fb->rgb_palette[i*3 + 1] = d->fb->rgb_palette[i*3 + 2] = (i & 15) * 4; d->palette_modified = 1; i = 0; if (grayscale) { for (r=0; r<2; r++) for (g=0; g<2; g++) for (b=0; b<2; b++) { d->fb->rgb_palette[i + 0] = d->fb->rgb_palette[i + 1] = d->fb->rgb_palette[i + 2] = (r+g+b) * 0xaa / 3; d->fb->rgb_palette[i + 8*3 + 0] = d->fb->rgb_palette[i + 8*3 + 1] = d->fb->rgb_palette[i + 8*3 + 2] = (r+g+b) * 0xaa / 3 + 0x55; i+=3; } return; } for (r=0; r<2; r++) for (g=0; g<2; g++) for (b=0; b<2; b++) { d->fb->rgb_palette[i + 0] = r * 0xaa; d->fb->rgb_palette[i + 1] = g * 0xaa; d->fb->rgb_palette[i + 2] = b * 0xaa; i+=3; } for (r=0; r<2; r++) for (g=0; g<2; g++) for (b=0; b<2; b++) { d->fb->rgb_palette[i + 0] = r * 0xaa + 0x55; d->fb->rgb_palette[i + 1] = g * 0xaa + 0x55; d->fb->rgb_palette[i + 2] = b * 0xaa + 0x55; i+=3; } } /* * vga_update_textmode(): * * Called from vga_update() when x11 in_use is false. This causes modified * character cells to be "simulated" by outputing ANSI escape sequences * that draw the characters in a terminal window instead. */ static void vga_update_textmode(struct machine *machine, struct vga_data *d, int base, int start, int end) { char s[50]; int i, oldcolor = -1, printed_last = 0; for (i=start; i<=end; i+=2) { unsigned char ch = d->charcells[base+i]; int fg = d->charcells[base+i+1] & 15; int bg = (d->charcells[base+i+1] >> 4) & 15; /* top bit of bg = blink */ int x = (i/2) % d->max_x; int y = (i/2) / d->max_x; if (d->charcells[base+i] == d->charcells_outputed[i] && d->charcells[base+i+1] == d->charcells_outputed[i+1]) { printed_last = 0; continue; } d->charcells_outputed[i] = d->charcells[base+i]; d->charcells_outputed[i+1] = d->charcells[base+i+1]; if (!printed_last || x == 0) { snprintf(s, sizeof(s), "\033[%i;%iH", y + 1, x + 1); c_putstr(d, s); } if (oldcolor < 0 || (bg<<4)+fg != oldcolor || !printed_last) { snprintf(s, sizeof(s), "\033[0;"); c_putstr(d, s); switch (fg & 7) { case 0: c_putstr(d, "30"); break; case 1: c_putstr(d, "34"); break; case 2: c_putstr(d, "32"); break; case 3: c_putstr(d, "36"); break; case 4: c_putstr(d, "31"); break; case 5: c_putstr(d, "35"); break; case 6: c_putstr(d, "33"); break; case 7: c_putstr(d, "37"); break; } if (fg & 8) c_putstr(d, ";1"); c_putstr(d, ";"); switch (bg & 7) { case 0: c_putstr(d, "40"); break; case 1: c_putstr(d, "44"); break; case 2: c_putstr(d, "42"); break; case 3: c_putstr(d, "46"); break; case 4: c_putstr(d, "41"); break; case 5: c_putstr(d, "45"); break; case 6: c_putstr(d, "43"); break; case 7: c_putstr(d, "47"); break; } /* TODO: blink */ c_putstr(d, "m"); } if (ch >= 0x20 && ch != 127) console_putchar(d->console_handle, ch); oldcolor = (bg << 4) + fg; printed_last = 1; } /* Restore the terminal's cursor position: */ snprintf(s, sizeof(s), "\033[%i;%iH", d->cursor_y + 1, d->cursor_x + 1); c_putstr(d, s); } /* * vga_update_graphics(): * * This function should be called whenever any part of d->gfx_mem[] has * been written to. It will redraw all pixels within the range x1,y1 * .. x2,y2 using the right palette. */ static void vga_update_graphics(struct machine *machine, struct vga_data *d, int x1, int y1, int x2, int y2) { int x, y, ix, iy, c, rx = d->pixel_repx, ry = d->pixel_repy; unsigned char pixel[3]; for (y=y1; y<=y2; y++) for (x=x1; x<=x2; x++) { /* addr is where to read from VGA memory, addr2 is where to write on the 24-bit framebuffer device */ int addr = (y * d->max_x + x) * d->bits_per_pixel; switch (d->bits_per_pixel) { case 8: addr >>= 3; c = d->gfx_mem[addr]; pixel[0] = d->fb->rgb_palette[c*3+0]; pixel[1] = d->fb->rgb_palette[c*3+1]; pixel[2] = d->fb->rgb_palette[c*3+2]; break; case 4: addr >>= 2; if (addr & 1) c = d->gfx_mem[addr >> 1] >> 4; else c = d->gfx_mem[addr >> 1] & 0xf; pixel[0] = d->fb->rgb_palette[c*3+0]; pixel[1] = d->fb->rgb_palette[c*3+1]; pixel[2] = d->fb->rgb_palette[c*3+2]; break; } for (iy=y*ry; iy<(y+1)*ry; iy++) for (ix=x*rx; ix<(x+1)*rx; ix++) { uint32_t addr2 = (d->fb_max_x * iy + ix) * 3; if (addr2 < d->fb_size) dev_fb_access(machine->cpus[0], machine->memory, addr2, pixel, sizeof(pixel), MEM_WRITE, d->fb); } } } /* * vga_update_text(): * * This function should be called whenever any part of d->charcells[] has * been written to. It will redraw all characters within the range x1,y1 * .. x2,y2 using the right palette. */ static void vga_update_text(struct machine *machine, struct vga_data *d, int x1, int y1, int x2, int y2) { int fg, bg, x,y, subx, line; size_t i, start, end, base; int font_size = d->font_height; int font_width = d->font_width; unsigned char *pal = d->fb->rgb_palette; if (d->pixel_repx * font_width > 8*8) { fatal("[ too large font ]\n"); return; } /* Hm... I'm still using the old start..end code: */ start = (d->max_x * y1 + x1) * 2; end = (d->max_x * y2 + x2) * 2; start &= ~1; end |= 1; if (end >= d->charcells_size) end = d->charcells_size - 1; base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8) + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2; if (!machine->x11_md.in_use) vga_update_textmode(machine, d, base, start, end); for (i=start; i<=end; i+=2) { unsigned char ch = d->charcells[i + base]; if (!d->palette_modified && d->charcells_drawn[i] == ch && d->charcells_drawn[i+1] == d->charcells[i+base+1]) continue; d->charcells_drawn[i] = ch; d->charcells_drawn[i+1] = d->charcells[i + base + 1]; fg = d->charcells[i+base + 1] & 15; bg = (d->charcells[i+base + 1] >> 4) & 7; /* Blink is hard to do :-), but inversion might be ok too: */ if (d->charcells[i+base + 1] & 128) { int tmp = fg; fg = bg; bg = tmp; } x = (i/2) % d->max_x; x *= font_width; y = (i/2) / d->max_x; y *= font_size; /* Draw the character: */ for (line = 0; line < font_size; line++) { /* hardcoded for max 8 scaleup... :-) */ unsigned char rgb_line[3 * 8 * 8]; int iy; for (subx = 0; subx < font_width; subx++) { int ix, color_index; if (d->use_palette_per_line) { int sline = d->pixel_repy * (line+y); if (sline < MAX_RETRACE_SCANLINES) pal = d->retrace_palette + sline * 256*3; else pal = d->fb->rgb_palette; } if (d->font[ch * font_size + line] & (128 >> subx)) color_index = fg; else color_index = bg; for (ix=0; ixpixel_repx; ix++) memcpy(rgb_line + (subx*d->pixel_repx + ix) * 3, &pal[color_index * 3], 3); } for (iy=0; iypixel_repy; iy++) { uint32_t addr = (d->fb_max_x * (d->pixel_repy * (line+y) + iy) + x * d->pixel_repx) * 3; if (addr >= d->fb_size) continue; dev_fb_access(machine->cpus[0], machine->memory, addr, rgb_line, 3 * machine->x11_md.scaleup * font_width, MEM_WRITE, d->fb); } } } } /* * vga_update_cursor(): */ static void vga_update_cursor(struct machine *machine, struct vga_data *d) { int onoff = 1, height = d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END] - d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] + 1; if (d->cur_mode != MODE_CHARCELL) onoff = 0; if (d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] > d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_END]) { onoff = 0; height = 1; } if (d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START] >= d->font_height) onoff = 0; dev_fb_setcursor(d->fb, d->cursor_x * d->font_width * d->pixel_repx, (d->cursor_y * d->font_height + d->crtc_reg[VGA_CRTC_CURSOR_SCANLINE_START]) * d->pixel_repy, onoff, d->font_width * d->pixel_repx, height * d->pixel_repy); } DEVICE_TICK(vga) { struct vga_data *d = (struct vga_data *) extra; int64_t low = -1, high; vga_update_cursor(cpu->machine, d); /* TODO: text vs graphics tick? */ memory_device_dyntrans_access(cpu, cpu->mem, extra, (uint64_t *) &low, (uint64_t *) &high); if (low != -1) { int base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8) + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2; int new_u_y1, new_u_y2; debug("[ dev_vga_tick: dyntrans access, %" PRIx64" .. %" PRIx64" ]\n", (uint64_t) low, (uint64_t) high); low -= base; high -= base; d->update_x1 = 0; d->update_x2 = d->max_x - 1; new_u_y1 = (low/2) / d->max_x; new_u_y2 = ((high/2) / d->max_x) + 1; if (new_u_y1 < d->update_y1) d->update_y1 = new_u_y1; if (new_u_y2 > d->update_y2) d->update_y2 = new_u_y2; if (d->update_y1 < 0) d->update_y1 = 0; if (d->update_y2 >= d->max_y) d->update_y2 = d->max_y - 1; d->modified = 1; } if (d->n_is1_reads > N_IS1_READ_THRESHOLD && d->retrace_palette != NULL) { d->use_palette_per_line = 1; d->update_x1 = 0; d->update_x2 = d->max_x - 1; d->update_y1 = 0; d->update_y2 = d->max_y - 1; d->modified = 1; } else { if (d->use_palette_per_line) { d->use_palette_per_line = 0; d->update_x1 = 0; d->update_x2 = d->max_x - 1; d->update_y1 = 0; d->update_y2 = d->max_y - 1; d->modified = 1; } } if (!cpu->machine->x11_md.in_use) { /* NOTE: 2 > 0, so this only updates the cursor, no character cells. */ vga_update_textmode(cpu->machine, d, 0, 2, 0); } if (d->modified) { if (d->cur_mode == MODE_CHARCELL) vga_update_text(cpu->machine, d, d->update_x1, d->update_y1, d->update_x2, d->update_y2); else vga_update_graphics(cpu->machine, d, d->update_x1, d->update_y1, d->update_x2, d->update_y2); d->palette_modified = 0; d->modified = 0; d->update_x1 = 999999; d->update_x2 = -1; d->update_y1 = 999999; d->update_y2 = -1; } if (d->n_is1_reads > N_IS1_READ_THRESHOLD) d->n_is1_reads = 0; } /* * Reads and writes to the VGA video memory (pixels). */ DEVICE_ACCESS(vga_graphics) { struct vga_data *d = (struct vga_data *) extra; int j, x=0, y=0, x2=0, y2=0, modified = 0; size_t i; if (relative_addr + len >= GFX_ADDR_WINDOW) return 0; if (d->cur_mode != MODE_GRAPHICS) return 1; switch (d->graphics_mode) { case GRAPHICS_MODE_8BIT: y = relative_addr / d->max_x; x = relative_addr % d->max_x; y2 = (relative_addr+len-1) / d->max_x; x2 = (relative_addr+len-1) % d->max_x; if (writeflag == MEM_WRITE) { memcpy(d->gfx_mem + relative_addr, data, len); modified = 1; } else memcpy(data, d->gfx_mem + relative_addr, len); break; case GRAPHICS_MODE_4BIT: y = relative_addr * 8 / d->max_x; x = relative_addr * 8 % d->max_x; y2 = ((relative_addr+len)*8-1) / d->max_x; x2 = ((relative_addr+len)*8-1) % d->max_x; /* TODO: color stuff */ /* Read/write d->gfx_mem in 4-bit color: */ if (writeflag == MEM_WRITE) { /* i is byte index to write, j is bit index */ for (i=0; isequencer_reg[ VGA_SEQ_MAP_MASK] & 0x0f; uint32_t addr = (y * d->max_x + x + i*8 + j) * d->bits_per_pixel / 8; unsigned char byte; if (!(d->graphcontr_reg[ VGA_GRAPHCONTR_MASK] & pixelmask)) continue; if (addr >= d->gfx_mem_size) continue; byte = d->gfx_mem[addr]; if (b && j&1) byte |= m << 4; if (b && !(j&1)) byte |= m; if (!b && j&1) byte &= ~(m << 4); if (!b && !(j&1)) byte &= ~m; d->gfx_mem[addr] = byte; } modified = 1; } else { fatal("TODO: 4 bit graphics read, mask=0x%02x\n", d->sequencer_reg[VGA_SEQ_MAP_MASK]); for (i=0; igraphics_mode); cpu->running = 0; } if (modified) { d->modified = 1; if (x < d->update_x1) d->update_x1 = x; if (x > d->update_x2) d->update_x2 = x; if (y < d->update_y1) d->update_y1 = y; if (y > d->update_y2) d->update_y2 = y; if (x2 < d->update_x1) d->update_x1 = x2; if (x2 > d->update_x2) d->update_x2 = x2; if (y2 < d->update_y1) d->update_y1 = y2; if (y2 > d->update_y2) d->update_y2 = y2; if (y != y2) { d->update_x1 = 0; d->update_x2 = d->max_x - 1; } } return 1; } /* * Reads and writes the VGA video memory (charcells). */ DEVICE_ACCESS(vga) { struct vga_data *d = (struct vga_data *) extra; uint64_t idata = 0, odata = 0; int x, y, x2, y2, r, base; size_t i; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); base = ((d->crtc_reg[VGA_CRTC_START_ADDR_HIGH] << 8) + d->crtc_reg[VGA_CRTC_START_ADDR_LOW]) * 2; r = relative_addr - base; y = r / (d->max_x * 2); x = (r/2) % d->max_x; y2 = (r+len-1) / (d->max_x * 2); x2 = ((r+len-1)/2) % d->max_x; if (relative_addr + len - 1 < d->charcells_size) { if (writeflag == MEM_WRITE) { for (i=0; icharcells[relative_addr + i]; if (old != data[i]) { d->charcells[relative_addr + i] = data[i]; d->modified = 1; } } if (d->modified) { if (x < d->update_x1) d->update_x1 = x; if (x > d->update_x2) d->update_x2 = x; if (y < d->update_y1) d->update_y1 = y; if (y > d->update_y2) d->update_y2 = y; if (x2 < d->update_x1) d->update_x1 = x2; if (x2 > d->update_x2) d->update_x2 = x2; if (y2 < d->update_y1) d->update_y1 = y2; if (y2 > d->update_y2) d->update_y2 = y2; if (y != y2) { d->update_x1 = 0; d->update_x2 = d->max_x - 1; } } } else memcpy(data, d->charcells + relative_addr, len); return 1; } switch (relative_addr) { default: if (writeflag==MEM_READ) { debug("[ vga: read from 0x%08lx ]\n", (long)relative_addr); } else { debug("[ vga: write to 0x%08lx: 0x%08x ]\n", (long)relative_addr, idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * vga_crtc_reg_write(): * * Writes to VGA CRTC registers. */ static void vga_crtc_reg_write(struct machine *machine, struct vga_data *d, int regnr, int idata) { int i, grayscale; switch (regnr) { case VGA_CRTC_CURSOR_SCANLINE_START: /* 0x0a */ case VGA_CRTC_CURSOR_SCANLINE_END: /* 0x0b */ break; case VGA_CRTC_START_ADDR_HIGH: /* 0x0c */ case VGA_CRTC_START_ADDR_LOW: /* 0x0d */ d->update_x1 = 0; d->update_x2 = d->max_x - 1; d->update_y1 = 0; d->update_y2 = d->max_y - 1; d->modified = 1; recalc_cursor_position(d); break; case VGA_CRTC_CURSOR_LOCATION_HIGH: /* 0x0e */ case VGA_CRTC_CURSOR_LOCATION_LOW: /* 0x0f */ recalc_cursor_position(d); break; case 0xff: grayscale = 0; switch (d->crtc_reg[0xff]) { case 0x00: grayscale = 1; case 0x01: d->cur_mode = MODE_CHARCELL; d->max_x = 40; d->max_y = 25; d->pixel_repx = machine->x11_md.scaleup * 2; d->pixel_repy = machine->x11_md.scaleup; d->font_width = 8; d->font_height = 16; d->font = font8x16; break; case 0x02: grayscale = 1; case 0x03: d->cur_mode = MODE_CHARCELL; d->max_x = 80; d->max_y = 25; d->pixel_repx = d->pixel_repy = machine->x11_md.scaleup; d->font_width = 8; d->font_height = 16; d->font = font8x16; break; case 0x08: d->cur_mode = MODE_GRAPHICS; d->max_x = 160; d->max_y = 200; d->graphics_mode = GRAPHICS_MODE_4BIT; d->bits_per_pixel = 4; d->pixel_repx = 4 * machine->x11_md.scaleup; d->pixel_repy = 2 * machine->x11_md.scaleup; break; case 0x09: case 0x0d: d->cur_mode = MODE_GRAPHICS; d->max_x = 320; d->max_y = 200; d->graphics_mode = GRAPHICS_MODE_4BIT; d->bits_per_pixel = 4; d->pixel_repx = d->pixel_repy = 2 * machine->x11_md.scaleup; break; case 0x0e: d->cur_mode = MODE_GRAPHICS; d->max_x = 640; d->max_y = 200; d->graphics_mode = GRAPHICS_MODE_4BIT; d->bits_per_pixel = 4; d->pixel_repx = machine->x11_md.scaleup; d->pixel_repy = machine->x11_md.scaleup * 2; break; case 0x10: d->cur_mode = MODE_GRAPHICS; d->max_x = 640; d->max_y = 350; d->graphics_mode = GRAPHICS_MODE_4BIT; d->bits_per_pixel = 4; d->pixel_repx = d->pixel_repy = machine->x11_md.scaleup; break; case 0x12: d->cur_mode = MODE_GRAPHICS; d->max_x = 640; d->max_y = 480; d->graphics_mode = GRAPHICS_MODE_4BIT; d->bits_per_pixel = 4; d->pixel_repx = d->pixel_repy = machine->x11_md.scaleup; break; case 0x13: d->cur_mode = MODE_GRAPHICS; d->max_x = 320; d->max_y = 200; d->graphics_mode = GRAPHICS_MODE_8BIT; d->bits_per_pixel = 8; d->pixel_repx = d->pixel_repy = 2 * machine->x11_md.scaleup; break; default: fatal("TODO! video mode change hack (mode 0x%02x)\n", d->crtc_reg[0xff]); exit(1); } if (d->cur_mode == MODE_CHARCELL) { dev_fb_resize(d->fb, d->max_x * d->font_width * d->pixel_repx, d->max_y * d->font_height * d->pixel_repy); d->fb_size = d->max_x * d->pixel_repx * d->font_width * d->max_y * d->pixel_repy * d->font_height * 3; } else { dev_fb_resize(d->fb, d->max_x * d->pixel_repx, d->max_y * d->pixel_repy); d->fb_size = d->max_x * d->pixel_repx * d->max_y * d->pixel_repy * 3; } for (i=0; incpus; i++) machine->cpus[i]->invalidate_translation_caches( machine->cpus[i], 0, INVALIDATE_ALL); if (d->gfx_mem != NULL) free(d->gfx_mem); d->gfx_mem_size = 1; if (d->cur_mode == MODE_GRAPHICS) d->gfx_mem_size = d->max_x * d->max_y / (d->graphics_mode == GRAPHICS_MODE_8BIT? 1 : 2); CHECK_ALLOCATION(d->gfx_mem = (unsigned char *) malloc(d->gfx_mem_size)); /* Clear screen and reset the palette: */ memset(d->charcells_outputed, 0, d->charcells_size); memset(d->charcells_drawn, 0, d->charcells_size); memset(d->gfx_mem, 0, d->gfx_mem_size); d->update_x1 = 0; d->update_x2 = d->max_x - 1; d->update_y1 = 0; d->update_y2 = d->max_y - 1; d->modified = 1; reset_palette(d, grayscale); register_reset(d); break; default:fatal("[ vga_crtc_reg_write: regnr=0x%02x idata=0x%02x ]\n", regnr, idata); } } /* * vga_sequencer_reg_write(): * * Writes to VGA Sequencer registers. */ static void vga_sequencer_reg_write(struct machine *machine, struct vga_data *d, int regnr, int idata) { switch (regnr) { case VGA_SEQ_RESET: case VGA_SEQ_MAP_MASK: case VGA_SEQ_SEQUENCER_MEMORY_MODE: debug("[ vga_sequencer_reg_write: select %i: TODO ]\n", regnr); break; default:fatal("[ vga_sequencer_reg_write: select %i ]\n", regnr); /* cpu->running = 0; */ } } /* * vga_graphcontr_reg_write(): * * Writes to VGA Graphics Controller registers. */ static void vga_graphcontr_reg_write(struct machine *machine, struct vga_data *d, int regnr, int idata) { switch (regnr) { case VGA_GRAPHCONTR_READMAPSELECT: case VGA_GRAPHCONTR_GRAPHICSMODE: case VGA_GRAPHCONTR_MISC: case VGA_GRAPHCONTR_MASK: debug("[ vga_graphcontr_reg_write: select %i: TODO ]\n", regnr); break; default:fatal("[ vga_graphcontr_reg_write: select %i ]\n", regnr); /* cpu->running = 0; */ } } /* * vga_attribute_reg_write(): * * Writes to VGA Attribute registers. */ static void vga_attribute_reg_write(struct machine *machine, struct vga_data *d, int regnr, int idata) { /* 0-15 are palette registers: TODO */ if (regnr >= 0 && regnr <= 0xf) return; switch (regnr) { default:fatal("[ vga_attribute_reg_write: select %i ]\n", regnr); /* cpu->running = 0; */ } } /* * dev_vga_ctrl_access(): * * Reads and writes of the VGA control registers. */ DEVICE_ACCESS(vga_ctrl) { struct vga_data *d = (struct vga_data *) extra; size_t i; uint64_t idata = 0, odata = 0; for (i=0; iattribute_state) { case 0: if (writeflag == MEM_READ) odata = d->attribute_reg_select; else { d->attribute_reg_select = 1; d->attribute_state = 1; } break; case 1: d->attribute_state = 0; d->attribute_reg[d->attribute_reg_select] = idata; vga_attribute_reg_write(cpu->machine, d, d->attribute_reg_select, idata); break; } break; case VGA_ATTRIBUTE_DATA_READ: /* 0x01 */ if (writeflag == MEM_WRITE) fatal("[ dev_vga: WARNING: Write to " "VGA_ATTRIBUTE_DATA_READ? ]\n"); else { if (d->attribute_state == 0) fatal("[ dev_vga: WARNING: Read from " "VGA_ATTRIBUTE_DATA_READ, but no" " register selected? ]\n"); else odata = d->attribute_reg[ d->attribute_reg_select]; } break; case VGA_MISC_OUTPUT_W: /* 0x02 */ if (writeflag == MEM_WRITE) d->misc_output_reg = idata; else { /* Reads: Input Status 0 */ odata = 0x00; } break; case VGA_SEQUENCER_ADDR: /* 0x04 */ if (writeflag == MEM_READ) odata = d->sequencer_reg_select; else d->sequencer_reg_select = idata; break; case VGA_SEQUENCER_DATA: /* 0x05 */ if (writeflag == MEM_READ) odata = d->sequencer_reg[ d->sequencer_reg_select]; else { d->sequencer_reg[d-> sequencer_reg_select] = idata; vga_sequencer_reg_write(cpu->machine, d, d->sequencer_reg_select, idata); } break; case VGA_DAC_ADDR_READ: /* 0x07 */ if (writeflag == MEM_WRITE) { d->palette_read_index = idata; d->palette_read_subindex = 0; } else { debug("[ dev_vga: WARNING: Read from " "VGA_DAC_ADDR_READ? TODO ]\n"); /* TODO */ } break; case VGA_DAC_ADDR_WRITE: /* 0x08 */ if (writeflag == MEM_WRITE) { d->palette_write_index = idata; d->palette_write_subindex = 0; /* TODO: Is this correct? */ d->palette_read_index = idata; d->palette_read_subindex = 0; } else { fatal("[ dev_vga: WARNING: Read from " "VGA_DAC_ADDR_WRITE? ]\n"); odata = d->palette_write_index; } break; case VGA_DAC_DATA: /* 0x09 */ if (writeflag == MEM_WRITE) { int new_ = (idata & 63) << 2; int old = d->fb->rgb_palette[d-> palette_write_index*3+d-> palette_write_subindex]; d->fb->rgb_palette[d->palette_write_index * 3 + d->palette_write_subindex] = new_; /* Redraw whole screen, if the palette changed: */ if (new_ != old) { d->modified = 1; d->palette_modified = 1; d->update_x1 = d->update_y1 = 0; d->update_x2 = d->max_x - 1; d->update_y2 = d->max_y - 1; } d->palette_write_subindex ++; if (d->palette_write_subindex == 3) { d->palette_write_index ++; d->palette_write_subindex = 0; } } else { odata = (d->fb->rgb_palette[d-> palette_read_index * 3 + d->palette_read_subindex] >> 2) & 63; d->palette_read_subindex ++; if (d->palette_read_subindex == 3) { d->palette_read_index ++; d->palette_read_subindex = 0; } } break; case VGA_MISC_OUTPUT_R: odata = d->misc_output_reg; break; case VGA_GRAPHCONTR_ADDR: /* 0x0e */ if (writeflag == MEM_READ) odata = d->graphcontr_reg_select; else d->graphcontr_reg_select = idata; break; case VGA_GRAPHCONTR_DATA: /* 0x0f */ if (writeflag == MEM_READ) odata = d->graphcontr_reg[ d->graphcontr_reg_select]; else { d->graphcontr_reg[d-> graphcontr_reg_select] = idata; vga_graphcontr_reg_write(cpu->machine, d, d->graphcontr_reg_select, idata); } break; case VGA_CRTC_ADDR: /* 0x14 */ if (writeflag == MEM_READ) odata = d->crtc_reg_select; else d->crtc_reg_select = idata; break; case VGA_CRTC_DATA: /* 0x15 */ if (writeflag == MEM_READ) odata = d->crtc_reg[d->crtc_reg_select]; else { d->crtc_reg[d->crtc_reg_select] = idata; vga_crtc_reg_write(cpu->machine, d, d->crtc_reg_select, idata); } break; case VGA_INPUT_STATUS_1: /* 0x1A */ odata = 0; d->n_is1_reads ++; d->current_retrace_line ++; d->current_retrace_line %= (MAX_RETRACE_SCANLINES * 8); /* Whenever we are "inside" a scan line, copy the current palette into retrace_palette[][]: */ if ((d->current_retrace_line & 7) == 7) { if (d->retrace_palette == NULL && d->n_is1_reads > N_IS1_READ_THRESHOLD) { CHECK_ALLOCATION(d->retrace_palette = (unsigned char *) malloc( MAX_RETRACE_SCANLINES * 256*3)); } if (d->retrace_palette != NULL) memcpy(d->retrace_palette + (d-> current_retrace_line >> 3) * 256*3, d->fb->rgb_palette, d->cur_mode == MODE_CHARCELL? (16*3) : (256*3)); } /* These need to go on and off, to fake the real vertical and horizontal retrace info. */ if (d->current_retrace_line < 20*8) odata |= VGA_IS1_DISPLAY_VRETRACE; else { if ((d->current_retrace_line & 7) == 0) odata = VGA_IS1_DISPLAY_DISPLAY_DISABLE; } break; default: if (writeflag==MEM_READ) { debug("[ vga_ctrl: read from 0x%08lx ]\n", (long)relative_addr); } else { debug("[ vga_ctrl: write to 0x%08lx: 0x%08x" " ]\n", (long)relative_addr, (int)idata); } } if (writeflag == MEM_READ) data[i] = odata; /* For multi-byte accesses: */ relative_addr ++; } return 1; } /* * dev_vga_init(): * * Register a VGA text console device. max_x and max_y could be something * like 80 and 25, respectively. */ void dev_vga_init(struct machine *machine, struct memory *mem, uint64_t videomem_base, uint64_t control_base, const char *name) { struct vga_data *d; size_t allocsize, i; CHECK_ALLOCATION(d = (struct vga_data *) malloc(sizeof(struct vga_data))); memset(d, 0, sizeof(struct vga_data)); d->console_handle = console_start_slave(machine, "vga", CONSOLE_OUTPUT_ONLY); d->videomem_base = videomem_base; d->control_base = control_base; d->max_x = 80; d->max_y = 25; d->cur_mode = MODE_CHARCELL; d->crtc_reg[0xff] = 0x03; d->charcells_size = 0x8000; d->gfx_mem_size = 64; /* Nothing, as we start in text mode, but size large enough to make gfx_mem aligned. */ d->pixel_repx = d->pixel_repy = machine->x11_md.scaleup; /* Allocate in full pages, to make it possible to use dyntrans: */ allocsize = ((d->charcells_size-1) | (machine->arch_pagesize-1)) + 1; CHECK_ALLOCATION(d->charcells = (unsigned char *) malloc(d->charcells_size)); CHECK_ALLOCATION(d->charcells_outputed = (unsigned char *) malloc(d->charcells_size)); CHECK_ALLOCATION(d->charcells_drawn = (unsigned char *) malloc(d->charcells_size)); CHECK_ALLOCATION(d->gfx_mem = (unsigned char *) malloc(d->gfx_mem_size)); memset(d->charcells_drawn, 0, d->charcells_size); for (i=0; icharcells_size; i+=2) { d->charcells[i] = ' '; d->charcells[i+1] = 0x07; /* Default color */ d->charcells_drawn[i] = ' '; d->charcells_drawn[i+1] = 0x07; } memset(d->charcells_outputed, 0, d->charcells_size); memset(d->gfx_mem, 0, d->gfx_mem_size); d->font = font8x16; d->font_width = 8; d->font_height = 16; d->fb_max_x = d->pixel_repx * d->max_x; d->fb_max_y = d->pixel_repy * d->max_y; if (d->cur_mode == MODE_CHARCELL) { d->fb_max_x *= d->font_width; d->fb_max_y *= d->font_height; } memory_device_register(mem, "vga_charcells", videomem_base + 0x18000, allocsize, dev_vga_access, d, DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK | DM_READS_HAVE_NO_SIDE_EFFECTS, d->charcells); memory_device_register(mem, "vga_gfx", videomem_base, GFX_ADDR_WINDOW, dev_vga_graphics_access, d, DM_DEFAULT | DM_READS_HAVE_NO_SIDE_EFFECTS, d->gfx_mem); memory_device_register(mem, "vga_ctrl", control_base, 32, dev_vga_ctrl_access, d, DM_DEFAULT, NULL); d->fb = dev_fb_init(machine, mem, VGA_FB_ADDR, VFB_GENERIC, d->fb_max_x, d->fb_max_y, d->fb_max_x, d->fb_max_y, 24, "VGA"); d->fb_size = d->fb_max_x * d->fb_max_y * 3; reset_palette(d, 0); /* This will force an initial redraw/resynch: */ d->update_x1 = 0; d->update_x2 = d->max_x - 1; d->update_y1 = 0; d->update_y2 = d->max_y - 1; d->modified = 1; machine_add_tickfunction(machine, dev_vga_tick, d, VGA_TICK_SHIFT); register_reset(d); vga_update_cursor(machine, d); } gxemul-0.6.1/src/devices/dev_sn.cc000644 001750 001750 00000006677 13402411502 017243 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: National Semiconductor SONIC ("sn") DP83932 ethernet controller * * TODO */ #include #include #include #include "cpu.h" #include "device.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "net.h" #include "thirdparty/dp83932reg.h" #define DEV_SN_LENGTH 0x1000 struct sn_data { struct interrupt irq; unsigned char macaddr[6]; uint32_t reg[SONIC_NREGS]; }; DEVICE_ACCESS(sn) { struct sn_data *d = (struct sn_data *) extra; uint64_t idata = 0, odata = 0; int regnr; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); regnr = relative_addr / sizeof(uint32_t); if (regnr < SONIC_NREGS) { if (writeflag == MEM_WRITE) d->reg[regnr] = idata; else odata = d->reg[regnr]; } switch (regnr) { default: if (writeflag == MEM_WRITE) { fatal("[ sn: unimplemented write to address 0x%x" " (regnr %i), data=0x%02x ]\n", (int)relative_addr, regnr, (int)idata); } else { fatal("[ sn: unimplemented read from address 0x%x " "(regnr %i) ]\n", (int)relative_addr, regnr); } /* exit(1); */ } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(sn) { char *name2; size_t nlen = 55; struct sn_data *d; CHECK_ALLOCATION(d = (struct sn_data *) malloc(sizeof(struct sn_data))); memset(d, 0, sizeof(struct sn_data)); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); net_generate_unique_mac(devinit->machine, d->macaddr); CHECK_ALLOCATION(name2 = (char *) malloc(nlen)); snprintf(name2, nlen, "%s [%02x:%02x:%02x:%02x:%02x:%02x]", devinit->name, d->macaddr[0], d->macaddr[1], d->macaddr[2], d->macaddr[3], d->macaddr[4], d->macaddr[5]); memory_device_register(devinit->machine->memory, name2, devinit->addr, DEV_SN_LENGTH, dev_sn_access, (void *)d, DM_DEFAULT, NULL); net_add_nic(devinit->machine->emul->net, d, d->macaddr); return 1; } gxemul-0.6.1/src/devices/dev_irqc.cc000644 001750 001750 00000012223 13402411502 017541 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Generic IRQ controller for the test machines */ #include #include #include #include "cpu.h" #include "device.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "testmachine/dev_irqc.h" #define N_IRQC_INTERRUPTS 32 struct irqc_data { struct interrupt irq; /* Connected to the CPU */ int asserted; /* Current CPU irq assertion */ uint32_t status; /* Interrupt Status register */ uint32_t enabled; /* Interrupt Enable register */ }; void irqc_interrupt_assert(struct interrupt *interrupt) { struct irqc_data *d = (struct irqc_data *) interrupt->extra; d->status |= interrupt->line; if ((d->status & d->enabled) && !d->asserted) { INTERRUPT_ASSERT(d->irq); d->asserted = 1; } } void irqc_interrupt_deassert(struct interrupt *interrupt) { struct irqc_data *d = (struct irqc_data *) interrupt->extra; d->status &= ~interrupt->line; if (!(d->status & d->enabled) && d->asserted) { INTERRUPT_DEASSERT(d->irq); d->asserted = 0; } } DEVICE_ACCESS(irqc) { struct irqc_data *d = (struct irqc_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case DEV_IRQC_IRQ: /* Status register: */ if (writeflag == MEM_READ) { odata = d->status; } else { fatal("[ irqc: WARNING! write to DEV_IRQC_IRQ ]\n"); } break; case DEV_IRQC_MASK: /* Mask interrupts by clearing Enable bits: */ if (writeflag == MEM_READ) { fatal("[ irqc: WARNING! read from DEV_IRQC_MASK ]\n"); } else { int old_assert = d->status & d->enabled; int new_assert; d->enabled &= ~(1 << idata); new_assert = d->status & d->enabled; if (!old_assert && new_assert) INTERRUPT_ASSERT(d->irq); else if (old_assert && !new_assert) INTERRUPT_DEASSERT(d->irq); } break; case DEV_IRQC_UNMASK: /* Unmask interrupts by setting Enable bits: */ if (writeflag == MEM_READ) { fatal("[ irqc: WARNING! read from DEV_IRQC_UNMASK ]\n"); } else { int old_assert = d->status & d->enabled; int new_assert; d->enabled |= (1 << idata); new_assert = d->status & d->enabled; if (!old_assert && new_assert) INTERRUPT_ASSERT(d->irq); else if (old_assert && !new_assert) INTERRUPT_DEASSERT(d->irq); } break; default:if (writeflag == MEM_WRITE) { fatal("[ irqc: unimplemented write to " "offset 0x%x: data=0x%x ]\n", (int) relative_addr, (int)idata); } else { fatal("[ irqc: unimplemented read from " "offset 0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(irqc) { struct irqc_data *d; char n[300]; int i; CHECK_ALLOCATION(d = (struct irqc_data *) malloc(sizeof(struct irqc_data))); memset(d, 0, sizeof(struct irqc_data)); /* Connect to the CPU's interrupt pin: */ INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); /* Register the interrupts: */ for (i=0; iinterrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = 1 << i; /* Note: line contains the _mask_, not line number. */ templ.name = n; templ.extra = d; templ.interrupt_assert = irqc_interrupt_assert; templ.interrupt_deassert = irqc_interrupt_deassert; interrupt_handler_register(&templ); } /* Default to all interrupts enabled: */ d->enabled = 0xffffffff; memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_IRQC_LENGTH, dev_irqc_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_sfb.cc000644 001750 001750 00000006411 13402411502 017357 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SFB TURBOchannel framebuffer (graphics card) * * See include/sfbreg.h (and NetBSD's arch/pmax/dev/sfb.c) for more info. * * * TODO: This is not really implemented yet. It "happens" to work with * NetBSD and OpenBSD, but not with Ultrix yet. */ #include #include #include #include "devices.h" #include "memory.h" #include "misc.h" #include "thirdparty/sfbreg.h" #define SFB_XSIZE 1280 #define SFB_YSIZE 1024 /* #define debug fatal */ #define SFB_REG_SIZE 0x80 #define N_SFB_REGS (SFB_REG_SIZE / 4) struct sfb_data { struct vfb_data *vfb_data; uint32_t reg[N_SFB_REGS]; }; DEVICE_ACCESS(sfb) { uint64_t idata = 0, odata = 0; struct sfb_data *d = (struct sfb_data *) extra; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (writeflag==MEM_READ) { odata = d->reg[(relative_addr >> 2) & (N_SFB_REGS - 1)]; debug("[ sfb: read from addr 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)odata); } else { d->reg[(relative_addr >> 2) & (N_SFB_REGS - 1)] = idata; debug("[ sfb: write to addr 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)idata); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_sfb_init(): */ void dev_sfb_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, struct vfb_data *fb) { struct sfb_data *d; CHECK_ALLOCATION(d = (struct sfb_data *) malloc(sizeof(struct sfb_data))); memset(d, 0, sizeof(struct sfb_data)); d->vfb_data = fb; d->reg[(SFB_VHORIZONTAL - SFB_ASIC_OFFSET) / 4] = SFB_XSIZE >> 2; d->reg[(SFB_VVERTICAL - SFB_ASIC_OFFSET) / 4] = SFB_YSIZE; memory_device_register(mem, "sfb", baseaddr, SFB_REG_SIZE, dev_sfb_access, d, DM_DEFAULT, NULL); } gxemul-0.6.1/src/devices/dev_kn02ba.cc000644 001750 001750 00000013516 13402411502 017666 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: DEC KN02BA "3min" TurboChannel interrupt controller * * Used in DECstation 5000/1xx "3MIN". See include/dec_kmin.h for more info. */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/dec_kmin.h" struct kn02ba_data { struct dec_ioasic_data *dec_ioasic; uint32_t mer; /* Memory Error Register */ uint32_t msr; /* Memory Size Register */ struct interrupt irq; }; /* * kn02ba_interrupt_assert(), kn02ba_interrupt_deassert(): * * Called whenever a kn02ba interrupt is asserted/deasserted. */ void kn02ba_interrupt_assert(struct interrupt *interrupt) { struct kn02ba_data *d = (struct kn02ba_data *) interrupt->extra; struct dec_ioasic_data *r = (struct dec_ioasic_data *) d->dec_ioasic; r->intr |= interrupt->line; dec_ioasic_reassert(r); } void kn02ba_interrupt_deassert(struct interrupt *interrupt) { struct kn02ba_data *d = (struct kn02ba_data *) interrupt->extra; struct dec_ioasic_data *r = (struct dec_ioasic_data *) d->dec_ioasic; r->intr &= ~interrupt->line; dec_ioasic_reassert(r); } DEVICE_ACCESS(kn02ba_mer) { struct kn02ba_data *d = (struct kn02ba_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0: if (writeflag == MEM_WRITE) d->mer = idata; else odata = d->mer; debug("[ kn02ba_mer: %s MER, data=0x%08x (%s %s %s %s %s %s %s) ]\n", writeflag == MEM_WRITE ? "write to" : "read from", d->mer, d->mer & KMIN_MER_PAGE_BRY ? "PAGE_BRY" : "--", d->mer & KMIN_MER_TLEN ? "TLEN" : "--", d->mer & KMIN_MER_PARDIS ? "PARDIS" : "--", d->mer & KMIN_LASTB31 ? "LASTB31" : "--", d->mer & KMIN_LASTB23 ? "LASTB23" : "--", d->mer & KMIN_LASTB15 ? "LASTB15" : "--", d->mer & KMIN_LASTB07 ? "LASTB07" : "--" ); break; default: if (writeflag == MEM_READ) { fatal("[ kn02ba_mer: read from offset 0x%08lx ]\n", (long)relative_addr); } else { fatal("[ kn02ba_mer: write to offset 0x%08lx: 0x%08x ]\n", (long)relative_addr, (int)idata); } exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(kn02ba_msr) { struct kn02ba_data *d = (struct kn02ba_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0: if (writeflag == MEM_WRITE) d->msr = idata; else odata = d->msr; debug("[ kn02ba_msr: %s MSR, data=0x%08x (%s) ]\n", writeflag == MEM_WRITE ? "write to" : "read from", d->msr, d->msr & KMIN_MSR_SIZE_16Mb ? "16Mb" : "--" ); break; default: if (writeflag == MEM_READ) { fatal("[ kn02ba_msr: read from offset 0x%08lx ]\n", (long)relative_addr); } else { fatal("[ kn02ba_msr: write to offset 0x%08lx: 0x%08x ]\n", (long)relative_addr, (int)idata); } exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(kn02ba) { struct kn02ba_data *d; int i; CHECK_ALLOCATION(d = (struct kn02ba_data *) malloc(sizeof(struct kn02ba_data))); memset(d, 0, sizeof(struct kn02ba_data)); /* Connect the kn02ba to a specific MIPS CPU interrupt line: */ INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); /* Register the interrupts: */ for (i = 0; i < 32; i++) { struct interrupt templ; char tmpstr[300]; snprintf(tmpstr, sizeof(tmpstr), "%s.kn02ba.0x%x", devinit->interrupt_path, 1 << i); // printf("registering '%s'\n", tmpstr); memset(&templ, 0, sizeof(templ)); templ.line = 1 << i; templ.name = tmpstr; templ.extra = d; templ.interrupt_assert = kn02ba_interrupt_assert; templ.interrupt_deassert = kn02ba_interrupt_deassert; interrupt_handler_register(&templ); } memory_device_register(devinit->machine->memory, "kn02ba_mer", KMIN_REG_MER, sizeof(uint32_t), dev_kn02ba_mer_access, d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, "kn02ba_msr", KMIN_REG_MSR, sizeof(uint32_t), dev_kn02ba_msr_access, d, DM_DEFAULT, NULL); d->dec_ioasic = dev_dec_ioasic_init(devinit->machine->cpus[0], devinit->machine->memory, KMIN_SYS_ASIC, 0, &d->irq); d->msr = KMIN_MSR_SIZE_16Mb; return 1; } gxemul-0.6.1/src/devices/dev_clmpcc.cc000644 001750 001750 00000021767 13402411502 020061 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2014 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Cirrus Logic 4-Channel Communications Controller (CD2400/CD2401) * * Used by OpenBSD/mvme88k. * * Works so far: * TX/RX interrupts (happy case). * * TODO: * Multiple channels * DMA? */ #include #include #include #include "console.h" #include "cpu.h" #include "device.h" #include "emul.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/mvme_pcctworeg.h" #include "thirdparty/clmpccreg.h" #define debug fatal #define CLMPCC_LEN 0x200 #define DEV_CLMPCC_TICK_SHIFT 16 struct clmpcc_data { unsigned char reg[CLMPCC_LEN]; int console_handle; /* Interrupt pins on the PCC2 controller: */ struct interrupt irq_scc_rxe; struct interrupt irq_scc_m; struct interrupt irq_scc_tx; struct interrupt irq_scc_rx; }; static void reassert_interrupts(struct clmpcc_data *d) { int rxintr = 0; if (console_charavail(d->console_handle)) rxintr = 1; if (rxintr) INTERRUPT_ASSERT(d->irq_scc_rx); else INTERRUPT_DEASSERT(d->irq_scc_rx); /* TODO: Hack/experiment for now... */ if ((d->reg[CLMPCC_REG_IER] & 3) != 0) INTERRUPT_ASSERT(d->irq_scc_tx); else INTERRUPT_DEASSERT(d->irq_scc_tx); } DEVICE_TICK(clmpcc) { struct clmpcc_data *d = (struct clmpcc_data *) extra; reassert_interrupts(d); } DEVICE_ACCESS(clmpcc) { struct clmpcc_data *d = (struct clmpcc_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) { idata = memory_readmax64(cpu, data, len); d->reg[relative_addr] = idata; } if (writeflag == MEM_READ) odata = d->reg[relative_addr]; switch (relative_addr) { case 0: /* Used by OpenBSD/mvme88k when probing... */ break; case CLMPCC_REG_TPR: /* Timer Period Register */ break; case CLMPCC_REG_CAR: /* Channel Access Register */ /* debug("[ clmpcc: selecting channel %i ]\n", (int) idata); */ break; case CLMPCC_REG_CCR: /* Channel Command Register: */ odata = 0; break; case CLMPCC_REG_CMR: /* Channel Mode Register */ case CLMPCC_REG_COR1: /* Channel Option Register #1 */ case CLMPCC_REG_COR2: /* Channel Option Register #2 */ case CLMPCC_REG_COR3: /* Channel Option Register #3 */ case CLMPCC_REG_COR4: /* Channel Option Register #4 */ case CLMPCC_REG_COR5: /* Channel Option Register #5 */ case CLMPCC_REG_COR6: /* Channel Option Register #6 */ case CLMPCC_REG_COR7: /* Channel Option Register #7 */ case CLMPCC_REG_SCHR1: /* Special Character Register #1 */ case CLMPCC_REG_SCHR2: /* Special Character Register #2 */ case CLMPCC_REG_SCHR3: /* Special Character Register #3 */ case CLMPCC_REG_SCHR4: /* Special Character Register #4 */ case CLMPCC_REG_SCRl: /* Special Character Range (low) */ case CLMPCC_REG_SCRh: /* Special Character Range (high) */ case CLMPCC_REG_LNXT: /* LNext Character */ break; case CLMPCC_REG_STCR: /* Special Transmit Command Register */ if (writeflag == MEM_WRITE) { if (idata == 0x0b) { if (d->reg[CLMPCC_REG_CAR] == 0) console_putchar(d->console_handle, d->reg[CLMPCC_REG_SCHR3]); else fatal("[ clmpcc: TODO: transmit " "to channel, CAR!=0 ]\n"); /* Command done: */ d->reg[CLMPCC_REG_STCR] = 0x00; } else { fatal("clmpcc: unimplemented STCR byte " "0x%02x\n", (int) idata); exit(1); } } break; case CLMPCC_REG_RBPR: /* Receive Baud Rate Period Register */ case CLMPCC_REG_TBPR: /* Transmit Baud Rate Period Register */ case CLMPCC_REG_RCOR: /* Receive Clock Options Register */ case CLMPCC_REG_TCOR: /* Transmit Clock Options Register */ break; case CLMPCC_REG_MSVR_RTS:/* Modem Signal Value Register, RTS */ case CLMPCC_REG_MSVR_DTR:/* Modem Signal Value Register, DTR */ break; case CLMPCC_REG_RTPRl: /* Receive Timeout Period Register (low) */ case CLMPCC_REG_RTPRh: /* Receive Timeout Period Register (high) */ break; case CLMPCC_REG_IER: /* Interrupt Enable Register */ case CLMPCC_REG_LIVR: /* Local Interrupt Vector Register */ case CLMPCC_REG_RPILR: /* Rx Priority Interrupt Level Register */ case CLMPCC_REG_TPILR: /* Tx Priority Interrupt Level Register */ case CLMPCC_REG_MPILR: /* Modem Priority Interrupt Level Register */ reassert_interrupts(d); break; case CLMPCC_REG_RISRl: /* Receive Interrupt Status Reg (low) */ odata = 0x00; break; case CLMPCC_REG_TIR: /* Transmit Interrupt Register */ odata = 0x40; /* see openbsd's cl_txintr */ break; case CLMPCC_REG_RIR: /* Rx Interrupt Register */ odata = 0x00; if (console_charavail(d->console_handle)) odata = 0xc0; break; case CLMPCC_REG_LICR: /* Local Interrupt Status Register */ odata = 0; /* channel nr << 2 */ break; case CLMPCC_REG_RFOC: /* Rx FIFO Output Count */ odata = 0; if (console_charavail(d->console_handle)) odata = 1; break; case CLMPCC_REG_TFTC: /* Tx FIFO Transfer Count */ /* * 0x1f is low enough to allow OpenBSD/mvme88k's ramdisk * kernel to run (bsd.rd), but not the default kernel (bsd). * Lowering it to 0x0f seems to work. */ odata = 0x0f; break; case CLMPCC_REG_TEOIR: /* Tx End of Interrupt Register */ /* TODO: Do something more realistic? */ INTERRUPT_DEASSERT(d->irq_scc_tx); break; case CLMPCC_REG_REOIR: /* Rx End of Interrupt Register */ /* TODO: Do something more realistic? */ INTERRUPT_DEASSERT(d->irq_scc_rx); break; case CLMPCC_REG_TDR: if (writeflag == MEM_WRITE) { if (d->reg[CLMPCC_REG_CAR] == 0) console_putchar(d->console_handle, idata); else fatal("[ clmpcc: TODO: transmit " "to channel, CAR!=0 ]\n"); } else { odata = console_readchar(d->console_handle); } break; default:if (writeflag == MEM_READ) fatal("[ clmpcc: unimplemented READ from offset 0x%x ]" "\n", (int)relative_addr); else fatal("[ clmpcc: unimplemented WRITE to offset 0x%x: " "0x%x ]\n", (int)relative_addr, (int)idata); exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(clmpcc) { struct clmpcc_data *d; char tmpstr[100]; CHECK_ALLOCATION(d = (struct clmpcc_data *) malloc(sizeof(struct clmpcc_data))); memset(d, 0, sizeof(struct clmpcc_data)); d->console_handle = console_start_slave(devinit->machine, devinit->name2 != NULL? devinit->name2 : devinit->name, devinit->in_use); /* * Connect to the PCC2's interrupt pins: * * The supplied interrupt_path is something like * "machine[0].cpu[0].pcc2". * * We want to use "machine[0].cpu[0].pcc2.x", where x is * 0xc, 0xd, 0xe, and 0xf (PCC2V_SCC_xxx). */ snprintf(tmpstr, sizeof(tmpstr), "%s.%i", devinit->interrupt_path, PCC2V_SCC_RXE); INTERRUPT_CONNECT(tmpstr, d->irq_scc_rxe); snprintf(tmpstr, sizeof(tmpstr), "%s.%i", devinit->interrupt_path, PCC2V_SCC_M); INTERRUPT_CONNECT(tmpstr, d->irq_scc_m); snprintf(tmpstr, sizeof(tmpstr), "%s.%i", devinit->interrupt_path, PCC2V_SCC_TX); INTERRUPT_CONNECT(tmpstr, d->irq_scc_tx); snprintf(tmpstr, sizeof(tmpstr), "%s.%i", devinit->interrupt_path, PCC2V_SCC_RX); INTERRUPT_CONNECT(tmpstr, d->irq_scc_rx); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, CLMPCC_LEN, dev_clmpcc_access, (void *)d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_clmpcc_tick, d, DEV_CLMPCC_TICK_SHIFT); /* * NOTE: Ugly cast into a pointer, because this is a convenient way * to return the console handle to code in src/machines/. */ devinit->return_ptr = (void *)(size_t)d->console_handle; return 1; } gxemul-0.6.1/src/devices/Makefile.skel000644 001750 001750 00000004270 13402411502 020036 0ustar00debugdebug000000 000000 # # Makefile for GXemul devices # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(XINCLUDE) $(DINCLUDE) OBJS=device.o bus_isa.o bus_pci.o lk201.o \ dev_8253.o dev_8259.o dev_adb.o dev_ahc.o dev_algor.o dev_asc.o \ dev_bebox.o dev_bt431.o dev_bt455.o dev_bt459.o dev_clmpcc.o \ dev_colorplanemask.o dev_cons.o dev_cpc700.o dev_dc7085.o \ dev_dec21030.o dev_dec21143.o dev_dec5800.o dev_dec_ioasic.o \ dev_disk.o dev_dreamcast_asic.o dev_dreamcast_g2.o \ dev_dreamcast_gdrom.o dev_dreamcast_maple.o dev_dreamcast_rtc.o \ dev_eagle.o dev_ether.o dev_fb.o dev_fbctrl.o dev_fdc.o \ dev_footbridge.o dev_gc.o dev_gt.o dev_hammerhead.o dev_i80321.o \ dev_igsfb.o dev_iq80321_7seg.o dev_irqc.o dev_jazz.o dev_kn01.o \ dev_kn02.o dev_kn02ba.o dev_kn220.o dev_kn230.o dev_lca.o dev_le.o \ dev_lpt.o dev_luna88k.o dev_m8820x.o dev_malta_lcd.o dev_mb8696x.o dev_mc146818.o \ dev_mk48txx.o dev_mp.o dev_mvme187.o dev_ns16550.o dev_ohci.o \ dev_osiop.o dev_palmbus.o dev_pcc2.o dev_pccmos.o dev_pcic.o dev_pckbc.o \ dev_pmagja.o dev_pmppc.o dev_prep.o dev_ps2_ether.o dev_ps2_gif.o \ dev_ps2_gs.o dev_ps2_spd.o dev_ps2_stuff.o dev_pvr.o dev_px.o \ dev_ram.o dev_random.o dev_rs5c313.o dev_rtc.o dev_rtl8139c.o \ dev_scc.o dev_sfb.o dev_sgi_gbe.o dev_sgi_ip19.o dev_sgi_ip20.o \ dev_sgi_ip22.o dev_sgi_ip30.o dev_sgi_ip32.o dev_sgi_mardigras.o \ dev_sgi_mec.o dev_sgi_re.o \ dev_sh4.o dev_sii.o dev_sn.o dev_ssc.o dev_turbochannel.o \ dev_uninorth.o dev_unreadable.o dev_v3.o dev_vga.o dev_vme.o \ dev_vr41xx.o dev_wdc.o dev_z8530.o dev_zero.o all: fonts_done $(MAKE) objs fonts_done: fonts_made $(MAKE) font8x8.cc font8x10.cc font8x16.cc fonts_made: cd fonts; $(MAKE) autodev.cc: autodev_head.cc autodev_middle.cc autodev_tail.cc makeautodev.sh bus_pci.cc $(OBJS) ./makeautodev.sh objs: $(OBJS) $(MAKE) autodev.o $(OBJS): Makefile dev_vga.o: font8x8.cc font8x16.cc font8x10.cc dev_fb.o: fb_include.cc dev_fb.cc font8x8.cc: cp -f fonts/font8x8.cc . font8x10.cc: cp -f fonts/font8x10.cc . font8x16.cc: cp -f fonts/font8x16.cc . clean: rm -f $(OBJS) *core font8x16.cc font8x10.cc font8x8.cc rm -f autodev.[co]* cd fonts; $(MAKE) clean clean_all: clean cd fonts; $(MAKE) clean_all rm -f Makefile fonts/Makefile gxemul-0.6.1/src/devices/dev_lpt.cc000644 001750 001750 00000007600 13402411502 017405 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: LPT (parallel printer) controller */ #include #include #include #include "console.h" #include "cpu.h" #include "device.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/lptreg.h" /* #define debug fatal */ #define TICK_SHIFT 18 #define DEV_LPT_LENGTH 3 struct lpt_data { const char *name; struct interrupt irq; int console_handle; uint8_t data; uint8_t control; }; DEVICE_TICK(lpt) { /* struct lpt_data *d = extra; */ /* TODO */ } DEVICE_ACCESS(lpt) { uint64_t idata = 0, odata=0; struct lpt_data *d = (struct lpt_data *) extra; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case LPT_DATA: if (writeflag == MEM_READ) odata = d->data; else d->data = idata; break; case LPT_STATUS: odata = LPS_NBSY | LPS_NACK | LPS_SELECT | LPS_NERR; break; case LPT_CONTROL: if (writeflag == MEM_WRITE) { if (idata != d->control) { if (idata & LPC_STROBE) { /* data strobe */ console_putchar(d->console_handle, d->data); } } d->control = idata; } break; } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(lpt) { struct lpt_data *d; size_t nlen; char *name; CHECK_ALLOCATION(d = (struct lpt_data *) malloc(sizeof(struct lpt_data))); memset(d, 0, sizeof(struct lpt_data)); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); d->name = devinit->name2 != NULL? devinit->name2 : ""; d->console_handle = console_start_slave(devinit->machine, devinit->name, CONSOLE_OUTPUT_ONLY); nlen = strlen(devinit->name) + 10; if (devinit->name2 != NULL) nlen += strlen(devinit->name2); CHECK_ALLOCATION(name = (char *) malloc(nlen)); if (devinit->name2 != NULL && devinit->name2[0]) snprintf(name, nlen, "%s [%s]", devinit->name, devinit->name2); else snprintf(name, nlen, "%s", devinit->name); memory_device_register(devinit->machine->memory, name, devinit->addr, DEV_LPT_LENGTH, dev_lpt_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_lpt_tick, d, TICK_SHIFT); /* * NOTE: Ugly cast into a pointer, because this is a convenient way * to return the console handle to code in src/machine.c. */ devinit->return_ptr = (void *)(size_t)d->console_handle; return 1; } gxemul-0.6.1/src/devices/bus_pci.cc000644 001750 001750 00000113055 13402411502 017376 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Generic PCI bus framework * * This is not a normal "device", but is used by individual PCI controllers * and devices. * * See NetBSD's pcidevs.h for more PCI vendor and device identifiers. * * TODO: * * x) Allow guest OSes to do runtime address fixups (i.e. actually * move a device from one address to another). * * x) Generalize the PCI and legacy ISA interrupt routing stuff. * * x) Make sure that pci_little_endian is used correctly everywhere. */ #include #include #include #define BUS_PCI_C #include "bus_isa.h" #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "diskimage.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "wdc.h" #include "thirdparty/cpc700reg.h" extern int verbose; // #ifdef UNSTABLE_DEVEL // #define debug fatal // #endif /* * bus_pci_decompose_1(): * * Helper function for decomposing Mechanism 1 tags. */ void bus_pci_decompose_1(uint32_t t, int *bus, int *dev, int *func, int *reg) { *bus = (t >> 16) & 0xff; *dev = (t >> 11) & 0x1f; *func = (t >> 8) & 0x7; *reg = t & 0xff; /* Warn about unaligned register access: */ if (t & 3) fatal("[ bus_pci_decompose_1: WARNING: reg = 0x%02x ]\n", t & 0xff); } /* * bus_pci_data_access(): * * Reads from or writes to the PCI configuration registers of a device. */ void bus_pci_data_access(struct cpu *cpu, struct pci_data *pci_data, uint64_t *data, int len, int writeflag) { struct pci_device *dev; unsigned char *cfg_base; uint64_t x, idata = *data; int i; /* Scan through the list of pci_device entries. */ dev = pci_data->first_device; while (dev != NULL) { if (dev->bus == pci_data->cur_bus && dev->function == pci_data->cur_func && dev->device == pci_data->cur_device) break; dev = dev->next; } /* No device? Then return emptiness. */ if (dev == NULL) { if (writeflag == MEM_READ) { if (pci_data->cur_reg == 0) *data = (uint64_t) -1; else *data = 0; } else { fatal("[ bus_pci_data_access(): write to non-existant" " device, bus %i func %i device %i ]\n", pci_data->cur_bus, pci_data->cur_func, pci_data->cur_device); } return; } /* Return normal config data, or length data? */ if (pci_data->last_was_write_ffffffff && pci_data->cur_reg >= PCI_MAPREG_START && pci_data->cur_reg <= PCI_MAPREG_END - 4) cfg_base = dev->cfg_mem_size; else cfg_base = dev->cfg_mem; /* Read data as little-endian: */ x = 0; for (i=len-1; i>=0; i--) { int ofs = pci_data->cur_reg + i; x <<= 8; x |= cfg_base[ofs & (PCI_CFG_MEM_SIZE - 1)]; } /* Register write: */ if (writeflag == MEM_WRITE) { debug("[ bus_pci: write to PCI DATA: data = 0x%08llx ]\n", (long long)idata); if (idata == 0xffffffffULL && pci_data->cur_reg >= PCI_MAPREG_START && pci_data->cur_reg <= PCI_MAPREG_END - 4) { pci_data->last_was_write_ffffffff = 1; return; } if (dev->cfg_reg_write == NULL || dev->cfg_reg_write(dev, pci_data->cur_reg, *data) == 0) { /* Print a warning for unhandled writes: */ debug("[ bus_pci: write to PCI DATA: data = 0x%08llx" " (current value = 0x%08llx); NOT YET" " SUPPORTED. bus %i, device %i, function %i (%s)" " register 0x%02x ]\n", (long long)idata, (long long)x, pci_data->cur_bus, pci_data->cur_device, pci_data->cur_func, dev->name, pci_data->cur_reg); /* Special warning, to detect if NetBSD's special detection of PCI devices fails: */ if (pci_data->cur_reg == PCI_COMMAND_STATUS_REG && !((*data) & PCI_COMMAND_IO_ENABLE)) { fatal("\n[ NetBSD PCI detection stuff not" " yet implemented for device '%s' ]\n", dev->name); } } return; } /* Register read: */ *data = x; pci_data->last_was_write_ffffffff = 0; debug("[ bus_pci: read from PCI DATA, bus %i, device " "%i, function %i (%s) register 0x%02x: (len=%i) 0x%08lx ]\n", pci_data->cur_bus, pci_data->cur_device, pci_data->cur_func, dev->name, pci_data->cur_reg, len, (long)*data); } /* * bus_pci_setaddr(): * * Sets the address in preparation for a PCI register transfer. */ void bus_pci_setaddr(struct cpu *cpu, struct pci_data *pci_data, int bus, int device, int function, int reg) { if (cpu == NULL || pci_data == NULL) { fatal("bus_pci_setaddr(): NULL ptr\n"); exit(1); } pci_data->cur_bus = bus; pci_data->cur_device = device; pci_data->cur_func = function; pci_data->cur_reg = reg; } /* * bus_pci_add(): * * Add a PCI device to a bus_pci device. */ void bus_pci_add(struct machine *machine, struct pci_data *pci_data, struct memory *mem, int bus, int device, int function, const char *name) { struct pci_device *pd; int ofs; void (*init)(struct machine *, struct memory *, struct pci_device *); if (pci_data == NULL) { fatal("bus_pci_add(): pci_data == NULL!\n"); abort(); } /* Find the PCI device: */ init = pci_lookup_initf(name); /* Make sure this bus/device/function number isn't already in use: */ pd = pci_data->first_device; while (pd != NULL) { if (pd->bus == bus && pd->device == device && pd->function == function) { fatal("bus_pci_add(): (bus %i, device %i, function" " %i) already in use\n", bus, device, function); exit(1); } pd = pd->next; } CHECK_ALLOCATION(pd = (struct pci_device *) malloc(sizeof(struct pci_device))); memset(pd, 0, sizeof(struct pci_device)); /* Add the new device first in the PCI bus' chain: */ pd->next = pci_data->first_device; pci_data->first_device = pd; CHECK_ALLOCATION(pd->name = strdup(name)); pd->pcibus = pci_data; pd->bus = bus; pd->device = device; pd->function = function; /* * Initialize with some default values: * * TODO: The command status register is best to set up per device. * The size registers should also be set up on a per-device basis. */ PCI_SET_DATA(PCI_COMMAND_STATUS_REG, PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE); for (ofs = PCI_MAPREG_START; ofs < PCI_MAPREG_END; ofs += 4) PCI_SET_DATA_SIZE(ofs, 0x00100000 - 1); if (init == NULL) { fatal("No init function for PCI device \"%s\"?\n", name); exit(1); } /* Call the PCI device' init function: */ init(machine, mem, pd); } /* * allocate_device_space(): * * Used by glue code (see below) to allocate space for a PCI device. * * The returned values in portp and memp are the actual (emulated) addresses * that the device should use. (Normally only one of these is actually used.) * * TODO: PCI irqs? */ static void allocate_device_space(struct pci_device *pd, uint64_t portsize, uint64_t memsize, uint64_t *portp, uint64_t *memp) { uint64_t port, mem; /* Calculate an aligned starting port: */ port = pd->pcibus->cur_pci_portbase; if (portsize != 0) { port = ((port - 1) | (portsize - 1)) + 1; pd->pcibus->cur_pci_portbase = port; PCI_SET_DATA(PCI_MAPREG_START + pd->cur_mapreg_offset, port | PCI_MAPREG_TYPE_IO); PCI_SET_DATA_SIZE(PCI_MAPREG_START + pd->cur_mapreg_offset, ((portsize - 1) & ~0xf) | 0xd); pd->cur_mapreg_offset += sizeof(uint32_t); } /* Calculate an aligned starting memory location: */ mem = pd->pcibus->cur_pci_membase; if (memsize != 0) { mem = ((mem - 1) | (memsize - 1)) + 1; pd->pcibus->cur_pci_membase = mem; PCI_SET_DATA(PCI_MAPREG_START + pd->cur_mapreg_offset, mem); PCI_SET_DATA_SIZE(PCI_MAPREG_START + pd->cur_mapreg_offset, ((memsize - 1) & ~0xf) | 0x0); pd->cur_mapreg_offset += sizeof(uint32_t); } *portp = port + pd->pcibus->pci_actual_io_offset; *memp = mem + pd->pcibus->pci_actual_mem_offset; if (verbose >= 2) { debug("pci device '%s' at", pd->name); if (portsize != 0) debug(" port 0x%llx-0x%llx", (long long)pd->pcibus-> cur_pci_portbase, (long long)(pd->pcibus-> cur_pci_portbase + portsize - 1)); if (memsize != 0) debug(" mem 0x%llx-0x%llx", (long long)pd->pcibus-> cur_pci_membase, (long long)(pd->pcibus-> cur_pci_membase + memsize - 1)); debug("\n"); } pd->pcibus->cur_pci_portbase += portsize; pd->pcibus->cur_pci_membase += memsize; } /* * bus_pci_init(): * * This doesn't register a device, but instead returns a pointer to a struct * which should be passed to other bus_pci functions when accessing the bus. * * irq_path is the interrupt path to the PCI controller. * * pci_portbase, pci_membase, and pci_irqbase are the port, memory, and * interrupt bases for PCI devices (as found in the configuration registers). * * pci_actual_io_offset and pci_actual_mem_offset are the offset from * the values in the configuration registers to the actual (emulated) device. * * isa_portbase, isa_membase, and isa_irqbase are the port, memory, and * interrupt bases for legacy ISA devices. */ struct pci_data *bus_pci_init(struct machine *machine, const char *irq_path, uint64_t pci_actual_io_offset, uint64_t pci_actual_mem_offset, uint64_t pci_portbase, uint64_t pci_membase, const char *pci_irqbase, uint64_t isa_portbase, uint64_t isa_membase, const char *isa_irqbase) { struct pci_data *d; CHECK_ALLOCATION(d = (struct pci_data *) malloc(sizeof(struct pci_data))); memset(d, 0, sizeof(struct pci_data)); CHECK_ALLOCATION(d->irq_path = strdup(irq_path)); CHECK_ALLOCATION(d->irq_path_isa = strdup(isa_irqbase)); CHECK_ALLOCATION(d->irq_path_pci = strdup(pci_irqbase)); d->pci_actual_io_offset = pci_actual_io_offset; d->pci_actual_mem_offset = pci_actual_mem_offset; d->pci_portbase = pci_portbase; d->pci_membase = pci_membase; d->isa_portbase = isa_portbase; d->isa_membase = isa_membase; d->cur_pci_portbase = d->pci_portbase; d->cur_pci_membase = d->pci_membase; /* Assume that the first 64KB could be used by legacy ISA devices: */ if (d->isa_portbase != 0 || d->isa_membase != 0) { d->cur_pci_portbase += 0x10000; d->cur_pci_membase += 0x10000; } return d; } /****************************************************************************** * * * The following is glue code for PCI controllers and devices. The glue * * code does the minimal stuff necessary to get an emulated OS to detect * * the device (i.e. set up PCI configuration registers), and then if * * necessary adds a "normal" device. * * * ******************************************************************************/ /* * Integraphics Systems "igsfb" Framebuffer (graphics) card, used in at * least the NetWinder. */ #define PCI_VENDOR_INTEGRAPHICS 0x10ea PCIINIT(igsfb) { char tmpstr[2000]; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEGRAPHICS, 0x2010)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_DISPLAY, PCI_SUBCLASS_DISPLAY_VGA, 0) + 0x01); /* TODO */ PCI_SET_DATA(0x10, 0x08000000); snprintf(tmpstr, sizeof(tmpstr), "igsfb addr=0x%llx", (long long)(pd->pcibus->isa_membase + 0x08000000)); device_add(machine, tmpstr); } /* * S3 ViRGE graphics. * * TODO: Only emulates a standard VGA card, so far. */ #define PCI_VENDOR_S3 0x5333 #define PCI_PRODUCT_S3_VIRGE 0x5631 #define PCI_PRODUCT_S3_VIRGE_DX 0x8a01 PCIINIT(s3_virge) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_S3, PCI_PRODUCT_S3_VIRGE_DX)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_DISPLAY, PCI_SUBCLASS_DISPLAY_VGA, 0) + 0x01); dev_vga_init(machine, mem, pd->pcibus->isa_membase + 0xa0000, pd->pcibus->isa_portbase + 0x3c0, machine->machine_name); } /* * Acer Labs M5229 PCI-IDE (UDMA) controller. * Acer Labs M1543 PCI->ISA bridge. */ #define PCI_VENDOR_ALI 0x10b9 #define PCI_PRODUCT_ALI_M1543 0x1533 /* NOTE: not 1543 */ #define PCI_PRODUCT_ALI_M5229 0x5229 PCIINIT(ali_m1543) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1543)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_ISA, 0) + 0xc3); PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); /* Linux uses these to detect which IRQ the IDE controller uses: */ PCI_SET_DATA(0x44, 0x0000000e); PCI_SET_DATA(0x58, 0x00000003); switch (machine->machine_type) { case MACHINE_CATS: bus_isa_init(machine, pd->pcibus->irq_path_isa, BUS_ISA_PCKBC_FORCE_USE | BUS_ISA_PCKBC_NONPCSTYLE, 0x7c000000, 0x80000000); break; default:fatal("ali_m1543 init: unimplemented machine type\n"); exit(1); } } PCIINIT(ali_m5229) { char tmpstr[2000], irqstr[1000]; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M5229)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE, PCI_SUBCLASS_MASS_STORAGE_IDE, 0x60) + 0xc1); switch (machine->machine_type) { case MACHINE_CATS: /* CATS ISA interrupts are at footbridge irq 10: */ snprintf(irqstr, sizeof(irqstr), "%s.10.isa", pd->pcibus->irq_path); break; default:fatal("ali_m5229 init: unimplemented machine type\n"); exit(1); } if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s.%i", (long long)(pd->pcibus->isa_portbase + 0x1f0), irqstr, 14); device_add(machine, tmpstr); } /* The secondary channel is disabled. TODO: fix this. */ } /* * Adaptec AHC SCSI controller, with values as they are in my SGI O2. */ #define PCI_VENDOR_ADP 0x9004 /* Adaptec */ #define PCI_PRODUCT_ADP_AIC7880 0x8078 /* AIC7880 */ PCIINIT(ahc) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7880)); PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x02800046); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE, PCI_SUBCLASS_MASS_STORAGE_SCSI, 0) + 0x01); PCI_SET_DATA(PCI_BHLC_REG, 0x00001020); PCI_SET_DATA(PCI_MAPREG_START + 0x00, 0xffffff01); PCI_SET_DATA(PCI_MAPREG_START + 0x04, 0x80001000); PCI_SET_DATA(PCI_MAPREG_START + 0x08, 0x00000000); PCI_SET_DATA(PCI_MAPREG_START + 0x0c, 0x00000000); PCI_SET_DATA(PCI_MAPREG_START + 0x10, 0x00000000); PCI_SET_DATA(PCI_MAPREG_START + 0x14, 0x00000000); PCI_SET_DATA(PCI_MAPREG_START + 0x18, 0x00000000); PCI_SET_DATA(PCI_MAPREG_START + 0x1c, 0x00000000); PCI_SET_DATA(0x30, 0x80010000); PCI_SET_DATA(PCI_INTERRUPT_REG, 0x08080100); /* interrupt pin */ PCI_SET_DATA(0x40, 0x00000180); PCI_SET_DATA(0x40, 0x00000180); /* * TODO: this address is based on what NetBSD/sgimips uses * on SGI IP32 (O2). Fix this! Allow devices to move? Or * implement PCI space redirection at least! */ // device_add(machine, "ahc addr=0x1a001000"); device_add(machine, "ahc addr=0x18002000"); } /* * Galileo Technology GT-64xxx PCI controller. * * GT-64011 Used in Cobalt machines. * GT-64120 Used in evbmips machines (Malta). * * NOTE: This works in the opposite way compared to other devices; the PCI * device is added from the normal device instead of the other way around. */ #define PCI_VENDOR_GALILEO 0x11ab /* Galileo Technology */ #define PCI_PRODUCT_GALILEO_GT64011 0x4146 /* GT-64011 System Controller */ #define PCI_PRODUCT_GALILEO_GT64120 0x4620 /* GT-64120 */ #define PCI_PRODUCT_GALILEO_GT64260 0x6430 /* GT-64260 */ PCIINIT(gt64011) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_GALILEO, PCI_PRODUCT_GALILEO_GT64011)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x01); /* Revision 1 */ } PCIINIT(gt64120) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_GALILEO, PCI_PRODUCT_GALILEO_GT64120)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x02); /* Revision 2? */ switch (machine->machine_type) { case MACHINE_EVBMIPS: PCI_SET_DATA(PCI_MAPREG_START + 0x10, 0x1be00000); break; } } PCIINIT(gt64260) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_GALILEO, PCI_PRODUCT_GALILEO_GT64260)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x01); /* Revision 1? */ } /* * AMD PCnet Ethernet card. * * "Am79c970A PCnet-PCI II rev 0" or similar. */ #define PCI_VENDOR_AMD 0x1022 /* Advanced Micro Devices */ #define PCI_PRODUCT_AMD_PCNET_PCI 0x2000 /* PCnet-PCI Ethernet */ PCIINIT(pcn) { int irq; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PCNET_PCI)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_NETWORK, PCI_SUBCLASS_NETWORK_ETHERNET, 0) + 0x00); /* Revision 0 */ switch (machine->machine_type) { case MACHINE_EVBMIPS: irq = (1 << 8) + 10; /* TODO */ break; default:fatal("pcn in non-implemented machine type %i\n", machine->machine_type); exit(1); } PCI_SET_DATA(PCI_INTERRUPT_REG, 0x01100000 | irq); /* * TODO: Add the pcn device here. The pcn device will need to work as * a wrapper for dev_le + all the DMA magic and whatever is required. * It's too much to implement right now. */ } /* * Intel 31244 Serial ATA Controller * Intel 82371SB PIIX3 PCI-ISA bridge * Intel 82371AB PIIX4 PCI-ISA bridge * Intel 82371SB IDE controller * Intel 82371AB IDE controller * Intel 82378ZB System I/O controller. */ #define PCI_VENDOR_INTEL 0x8086 #define PCI_PRODUCT_INTEL_31244 0x3200 #define PCI_PRODUCT_INTEL_82371SB_ISA 0x7000 #define PCI_PRODUCT_INTEL_82371SB_IDE 0x7010 #define PCI_PRODUCT_INTEL_82371AB_ISA 0x7110 #define PCI_PRODUCT_INTEL_82371AB_IDE 0x7111 #define PCI_PRODUCT_INTEL_SIO 0x0484 PCIINIT(i31244) { uint64_t port, memaddr; int irq = 0; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_31244)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE, PCI_SUBCLASS_MASS_STORAGE_IDE, 0x33) + 0x00); switch (machine->machine_type) { case MACHINE_IQ80321: /* S-PCI-X slot uses PCI IRQ A, int 29 */ irq = (1 << 8) + 29; break; default:fatal("i31244 in non-implemented machine type %i\n", machine->machine_type); exit(1); } PCI_SET_DATA(PCI_INTERRUPT_REG, 0x01100000 | irq); allocate_device_space(pd, 0x1000, 0, &port, &memaddr); allocate_device_space(pd, 0x1000, 0, &port, &memaddr); /* PCI IDE using dev_wdc: */ if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { char tmpstr[2000]; snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s.%i", (long long)(pd->pcibus->pci_actual_io_offset + 0), pd->pcibus->irq_path_pci, irq & 255); device_add(machine, tmpstr); } } int piix_isa_cfg_reg_write(struct pci_device *pd, int reg, uint32_t value) { switch (reg) { case PCI_MAPREG_START: case PCI_MAPREG_START + 4: case PCI_MAPREG_START + 8: case PCI_MAPREG_START + 12: case PCI_MAPREG_START + 16: case PCI_MAPREG_START + 20: PCI_SET_DATA(reg, value); return 1; } return 0; } PCIINIT(piix3_isa) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371SB_ISA)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x01); /* Rev 1 */ PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); } PCIINIT(piix4_isa) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_ISA)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x01); /* Rev 1 */ PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); pd->cfg_reg_write = piix_isa_cfg_reg_write; } PCIINIT(i82378zb) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_SIO)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x43); PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); PCI_SET_DATA(0x40, 0x20); /* PIRQ[0]=10 PIRQ[1]=11 PIRQ[2]=14 PIRQ[3]=15 */ PCI_SET_DATA(0x60, 0x0f0e0b0a); } struct piix_ide_extra { void *wdc0; void *wdc1; }; int piix_ide_cfg_reg_write(struct pci_device *pd, int reg, uint32_t value) { void *wdc0 = ((struct piix_ide_extra *)pd->extra)->wdc0; void *wdc1 = ((struct piix_ide_extra *)pd->extra)->wdc1; int enabled = 0; PCI_SET_DATA(reg, value); switch (reg) { case PCI_COMMAND_STATUS_REG: if (value & PCI_COMMAND_IO_ENABLE) enabled = 1; if (wdc0 != NULL) wdc_set_io_enabled((struct wdc_data *) wdc0, enabled); if (wdc1 != NULL) wdc_set_io_enabled((struct wdc_data *) wdc1, enabled); return 1; case PCI_MAPREG_START: case PCI_MAPREG_START + 4: case PCI_MAPREG_START + 8: case PCI_MAPREG_START + 12: case PCI_MAPREG_START + 16: case PCI_MAPREG_START + 20: return 1; } return 0; } PCIINIT(piix3_ide) { char tmpstr[2000]; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371SB_IDE)); /* Possibly not correct: */ PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE, PCI_SUBCLASS_MASS_STORAGE_IDE, 0x00) + 0x00); /* PIIX_IDETIM (see NetBSD's pciide_piix_reg.h) */ /* channel 0 and 1 enabled as IDE */ PCI_SET_DATA(0x40, 0x80008000); CHECK_ALLOCATION(pd->extra = malloc(sizeof(struct piix_ide_extra))); ((struct piix_ide_extra *)pd->extra)->wdc0 = NULL; ((struct piix_ide_extra *)pd->extra)->wdc1 = NULL; if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx " "irq=%s.isa.%i", (long long)(pd->pcibus->isa_portbase + 0x1f0), pd->pcibus->irq_path_isa, 14); ((struct piix_ide_extra *)pd->extra)->wdc0 = device_add(machine, tmpstr); } if (diskimage_exist(machine, 2, DISKIMAGE_IDE) || diskimage_exist(machine, 3, DISKIMAGE_IDE)) { snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx " "irq=%s.isa.%i", (long long)(pd->pcibus->isa_portbase + 0x170), pd->pcibus->irq_path_isa, 15); ((struct piix_ide_extra *)pd->extra)->wdc1 = device_add(machine, tmpstr); } pd->cfg_reg_write = piix_ide_cfg_reg_write; } PCIINIT(piix4_ide) { char tmpstr[2000]; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_IDE)); /* Possibly not correct: */ PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE, PCI_SUBCLASS_MASS_STORAGE_IDE, 0x80) + 0x01); /* PIIX_BMIBA (see NetBSD's pciide_piix_reg.h) */ /* 2009-05-18: Needs to have the lowest bit set, or Linux/Malta crashes. */ PCI_SET_DATA(0x20, 1); /* PIIX_IDETIM (see NetBSD's pciide_piix_reg.h) */ /* channel 0 and 1 enabled as IDE */ PCI_SET_DATA(0x40, 0x80008000); CHECK_ALLOCATION(pd->extra = malloc(sizeof(struct piix_ide_extra))); ((struct piix_ide_extra *)pd->extra)->wdc0 = NULL; ((struct piix_ide_extra *)pd->extra)->wdc1 = NULL; if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s." "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x1f0), pd->pcibus->irq_path_isa, 14); ((struct piix_ide_extra *)pd->extra)->wdc0 = device_add(machine, tmpstr); } if (diskimage_exist(machine, 2, DISKIMAGE_IDE) || diskimage_exist(machine, 3, DISKIMAGE_IDE)) { snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s." "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x170), pd->pcibus->irq_path_isa, 15); ((struct piix_ide_extra *)pd->extra)->wdc1 = device_add(machine, tmpstr); } pd->cfg_reg_write = piix_ide_cfg_reg_write; } /* * IBM ISA bridge (used by at least one PReP machine). */ #define PCI_VENDOR_IBM 0x1014 #define PCI_PRODUCT_IBM_ISABRIDGE 0x000a PCIINIT(ibm_isa) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_IBM, PCI_PRODUCT_IBM_ISABRIDGE)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x02); PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); } /* * Heuricon PCI host bridge for PM/PPC. */ #define PCI_VENDOR_HEURICON 0x1223 #define PCI_PRODUCT_HEURICON_PMPPC 0x000e PCIINIT(heuricon_pmppc) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_HEURICON, PCI_PRODUCT_HEURICON_PMPPC)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x00); /* Revision? */ PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); } /* * VIATECH VT82C586 devices: * * vt82c586_isa PCI->ISA bridge * vt82c586_ide IDE controller * * TODO: This more or less just a dummy device, so far. */ #define PCI_VENDOR_VIATECH 0x1106 /* VIA Technologies */ #define PCI_PRODUCT_VIATECH_VT82C586_IDE 0x1571 /* VT82C586 (Apollo VP) IDE Controller */ #define PCI_PRODUCT_VIATECH_VT82C586_ISA 0x0586 /* VT82C586 (Apollo VP) PCI-ISA Bridge */ PCIINIT(vt82c586_isa) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_ISA)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x39); /* Revision 37 or 39 */ PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); /* * NetBSD/cobalt specific: bits 7..4 are the "model id". See * netbsd/usr/src/sys/arch/cobalt/cobalt/machdep.c read_board_id() * for details. */ if (machine->machine_type == MACHINE_COBALT) { #define COBALT_PCIB_BOARD_ID_REG 0x94 #define COBALT_QUBE2_ID 5 PCI_SET_DATA(COBALT_PCIB_BOARD_ID_REG, COBALT_QUBE2_ID << 4); } } struct vt82c586_ide_extra { void *wdc0; void *wdc1; }; int vt82c586_ide_cfg_reg_write(struct pci_device *pd, int reg, uint32_t value) { void *wdc0 = ((struct vt82c586_ide_extra *)pd->extra)->wdc0; void *wdc1 = ((struct vt82c586_ide_extra *)pd->extra)->wdc1; int enabled = 0; switch (reg) { case PCI_COMMAND_STATUS_REG: if (value & PCI_COMMAND_IO_ENABLE) enabled = 1; if (wdc0 != NULL) wdc_set_io_enabled((struct wdc_data *) wdc0, enabled); if (wdc1 != NULL) wdc_set_io_enabled((struct wdc_data *) wdc1, enabled); return 1; } return 0; } PCIINIT(vt82c586_ide) { char tmpstr[2000]; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_IDE)); /* Possibly not correct: */ PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE, PCI_SUBCLASS_MASS_STORAGE_IDE, 0x00) + 0x01); /* APO_IDECONF */ /* channel 0 and 1 enabled */ PCI_SET_DATA(0x40, 0x00000003); CHECK_ALLOCATION(pd->extra = malloc(sizeof(struct vt82c586_ide_extra))); ((struct vt82c586_ide_extra *)pd->extra)->wdc0 = NULL; ((struct vt82c586_ide_extra *)pd->extra)->wdc1 = NULL; if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s." "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x1f0), pd->pcibus->irq_path_isa, 14); ((struct vt82c586_ide_extra *)pd->extra)->wdc0 = device_add(machine, tmpstr); } if (diskimage_exist(machine, 2, DISKIMAGE_IDE) || diskimage_exist(machine, 3, DISKIMAGE_IDE)) { snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s." "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x170), pd->pcibus->irq_path_isa, 15); ((struct vt82c586_ide_extra *)pd->extra)->wdc1 = device_add(machine, tmpstr); } pd->cfg_reg_write = vt82c586_ide_cfg_reg_write; } /* * Symphony Labs 83C553 PCI->ISA bridge. * Symphony Labs 82C105 PCIIDE controller. */ #define PCI_VENDOR_SYMPHONY 0x10ad #define PCI_PRODUCT_SYMPHONY_83C553 0x0565 #define PCI_PRODUCT_SYMPHONY_82C105 0x0105 PCIINIT(symphony_83c553) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_SYMPHONY, PCI_PRODUCT_SYMPHONY_83C553)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x10); PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); switch (machine->machine_type) { case MACHINE_NETWINDER: bus_isa_init(machine, pd->pcibus->irq_path_isa, 0, 0x7c000000, 0x80000000); break; default:fatal("symphony_83c553 init: unimplemented machine type\n"); exit(1); } } struct symphony_82c105_extra { void *wdc0; void *wdc1; }; int symphony_82c105_cfg_reg_write(struct pci_device *pd, int reg, uint32_t value) { void *wdc0 = ((struct symphony_82c105_extra *)pd->extra)->wdc0; void *wdc1 = ((struct symphony_82c105_extra *)pd->extra)->wdc1; int enabled = 0; printf("reg = 0x%x\n", reg); switch (reg) { case PCI_COMMAND_STATUS_REG: if (value & PCI_COMMAND_IO_ENABLE) enabled = 1; printf(" value = 0x%" PRIx32"\n", value); if (wdc0 != NULL) wdc_set_io_enabled((struct wdc_data *) wdc0, enabled); if (wdc1 != NULL) wdc_set_io_enabled((struct wdc_data *) wdc1, enabled); /* Set all bits: */ PCI_SET_DATA(reg, value); return 1; case PCI_MAPREG_START: case PCI_MAPREG_START + 4: case PCI_MAPREG_START + 8: case PCI_MAPREG_START + 12: case PCI_MAPREG_START + 16: case PCI_MAPREG_START + 20: PCI_SET_DATA(reg, value); return 1; } return 0; } PCIINIT(symphony_82c105) { char tmpstr[2000]; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_SYMPHONY, PCI_PRODUCT_SYMPHONY_82C105)); /* Possibly not correct: */ PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE, PCI_SUBCLASS_MASS_STORAGE_IDE, 0x00) + 0x05); /* TODO: Interrupt line: */ /* PCI_SET_DATA(PCI_INTERRUPT_REG, 0x28140000); */ /* APO_IDECONF */ /* channel 0 and 1 enabled */ PCI_SET_DATA(0x40, 0x00000003); CHECK_ALLOCATION(pd->extra = malloc(sizeof(struct symphony_82c105_extra))); ((struct symphony_82c105_extra *)pd->extra)->wdc0 = NULL; ((struct symphony_82c105_extra *)pd->extra)->wdc1 = NULL; if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s." "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x1f0), pd->pcibus->irq_path_isa, 14); ((struct symphony_82c105_extra *)pd->extra)->wdc0 = device_add(machine, tmpstr); } if (diskimage_exist(machine, 2, DISKIMAGE_IDE) || diskimage_exist(machine, 3, DISKIMAGE_IDE)) { snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s." "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x170), pd->pcibus->irq_path_isa, 15); ((struct symphony_82c105_extra *)pd->extra)->wdc1 = device_add(machine, tmpstr); } pd->cfg_reg_write = symphony_82c105_cfg_reg_write; } /* * Realtek 8139C+ PCI ethernet. */ #define PCI_VENDOR_REALTEK 0x10ec #define PCI_PRODUCT_REALTEK_RT8139 0x8139 PCIINIT(rtl8139c) { uint64_t port, memaddr; int pci_int_line = 0x101, irq = 0; char irqstr[1000]; char tmpstr[2000]; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8139)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_NETWORK, PCI_SUBCLASS_NETWORK_ETHERNET, 0x00) + 0x20); switch (machine->machine_type) { case MACHINE_LANDISK: irq = 5; pci_int_line = 0x105; break; default:fatal("rtl8139c for this machine has not been " "implemented yet\n"); exit(1); } PCI_SET_DATA(PCI_INTERRUPT_REG, 0x28140000 | pci_int_line); allocate_device_space(pd, 0x100, 0, &port, &memaddr); snprintf(irqstr, sizeof(irqstr), "%s.%i", pd->pcibus->irq_path_pci, irq); snprintf(tmpstr, sizeof(tmpstr), "rtl8139c addr=0x%llx " "irq=%s pci_little_endian=1", (long long)port, irqstr); device_add(machine, tmpstr); } /* * DEC 21143 ("Tulip") PCI ethernet. */ #define PCI_VENDOR_DEC 0x1011 /* Digital Equipment */ #define PCI_PRODUCT_DEC_21142 0x0019 /* DECchip 21142/21143 10/100 Ethernet */ PCIINIT(dec21143) { uint64_t port, memaddr; int pci_int_line = 0x101, irq = 0, isa = 0; char irqstr[1000]; char tmpstr[2000]; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21142)); PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x02000017); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_NETWORK, PCI_SUBCLASS_NETWORK_ETHERNET, 0x00) + 0x41); PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0,0, 0x40,0)); switch (machine->machine_type) { case MACHINE_CATS: /* CATS int 18 = PCI. */ irq = 18; pci_int_line = 0x101; break; case MACHINE_COBALT: /* On Cobalt, IRQ 7 = PCI. */ irq = 8 + 7; pci_int_line = 0x407; break; case MACHINE_PREP: irq = 10; isa = 1; pci_int_line = 0x20a; break; case MACHINE_MVMEPPC: /* TODO */ irq = 10; pci_int_line = 0x40a; break; case MACHINE_PMPPC: /* TODO, not working yet */ irq = 31 - CPC_IB_EXT1; pci_int_line = 0x101; break; case MACHINE_MACPPC: /* TODO, not working yet */ irq = 25; pci_int_line = 0x101; break; } PCI_SET_DATA(PCI_INTERRUPT_REG, 0x28140000 | pci_int_line); allocate_device_space(pd, 0x100, 0x100, &port, &memaddr); if (isa) snprintf(irqstr, sizeof(irqstr), "%s.isa.%i", pd->pcibus->irq_path_isa, irq); else snprintf(irqstr, sizeof(irqstr), "%s.%i", pd->pcibus->irq_path_pci, irq); snprintf(tmpstr, sizeof(tmpstr), "dec21143 addr=0x%llx addr2=0x%llx " "irq=%s pci_little_endian=1", (long long)port, (long long)memaddr, irqstr); device_add(machine, tmpstr); } /* * DEC 21030 "tga" graphics. */ #define PCI_PRODUCT_DEC_21030 0x0004 /* DECchip 21030 ("TGA") */ PCIINIT(dec21030) { uint64_t base = 0; char tmpstr[2000]; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21030)); PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x02800087); /* TODO */ PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_DISPLAY, PCI_SUBCLASS_DISPLAY_VGA, 0x00) + 0x03); /* * See http://mail-index.netbsd.org/port-arc/2001/08/13/0000.html * for more info. */ PCI_SET_DATA(PCI_BHLC_REG, 0x0000ff00); /* 8 = prefetchable */ PCI_SET_DATA(0x10, 0x00000008); PCI_SET_DATA(0x30, 0x08000001); PCI_SET_DATA(PCI_INTERRUPT_REG, 0x00000100); /* interrupt pin A? */ /* * Experimental: * * TODO: Base address, pci_little_endian, ... */ switch (machine->machine_type) { case MACHINE_ARC: base = 0x100000000ULL; break; default:fatal("dec21030 in non-implemented machine type %i\n", machine->machine_type); exit(1); } snprintf(tmpstr, sizeof(tmpstr), "dec21030 addr=0x%llx", (long long)(base)); device_add(machine, tmpstr); } /* * Motorola MPC105 "Eagle" Host Bridge * * Used in at least PReP and BeBox. */ #define PCI_VENDOR_MOT 0x1057 #define PCI_PRODUCT_MOT_MPC105 0x0001 PCIINIT(eagle) { PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_MOT, PCI_PRODUCT_MOT_MPC105)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x24); PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); } /* * Apple (MacPPC) stuff: * * Grand Central (I/O controller) * Uni-North (PCI controller) */ #define PCI_VENDOR_APPLE 0x106b #define PCI_PRODUCT_APPLE_GC 0x0002 #define PCI_PRODUCT_APPLE_UNINORTH1 0x001e PCIINIT(gc_obio) { uint64_t port, memaddr; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_GC)); /* TODO: */ PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_SYSTEM, PCI_SUBCLASS_SYSTEM_PIC, 0) + 0x00); PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); /* TODO */ allocate_device_space(pd, 0x10000, 0x10000, &port, &memaddr); } PCIINIT(uninorth) { uint64_t port, memaddr; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_UNINORTH1)); PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_HOST, 0) + 0xff); PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); /* TODO */ allocate_device_space(pd, 0x10000, 0x10000, &port, &memaddr); } /* * ATI graphics cards */ #define PCI_VENDOR_ATI 0x1002 #define PCI_PRODUCT_ATI_RADEON_9200_2 0x5962 PCIINIT(ati_radeon_9200_2) { uint64_t port, memaddr; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ATI, PCI_PRODUCT_ATI_RADEON_9200_2)); /* TODO: other subclass? */ PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_DISPLAY, PCI_SUBCLASS_DISPLAY_VGA, 0) + 0x03); /* TODO */ allocate_device_space(pd, 0x1000, 0x400000, &port, &memaddr); } gxemul-0.6.1/src/devices/dev_pmppc.cc000644 001750 001750 00000010661 13402411502 017726 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Artesyn PM/PPC motherboard registers * * NOTE/TODO: Only enough to boot NetBSD/pmppc has been implemented. */ #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/pmppc.h" struct pmppc_data { uint8_t config0; uint8_t config1; uint8_t reset_reg; }; DEVICE_ACCESS(pmppc_board) { struct pmppc_data *d = (struct pmppc_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); relative_addr += PMPPC_CONFIG0; switch (relative_addr) { case PMPPC_CONFIG0: if (writeflag==MEM_READ) { odata = d->config0; } else { debug("[ pmppc: UNIMPLEMENTED write to PMPPC_CONFIG0:" " 0x%02x ]\n", (int)idata); } break; case PMPPC_CONFIG1: if (writeflag==MEM_READ) { odata = d->config1; } else { debug("[ pmppc: UNIMPLEMENTED write to PMPPC_CONFIG1:" " 0x%02x ]\n", (int)idata); } break; case PMPPC_RESET: if (writeflag==MEM_READ) { odata = d->reset_reg; } else { if (d->reset_reg == PMPPC_RESET_SEQ_STEP1 && idata == PMPPC_RESET_SEQ_STEP2) { cpu->running = 0; cpu->machine-> exit_without_entering_debugger = 1; } d->reset_reg = idata; } break; default: if (writeflag==MEM_READ) { debug("[ pmppc: UNIMPLEMENTED read from 0x%08lx ]\n", (long)relative_addr); } else { debug("[ pmppc: UNIMPLEMENTED write to 0x%08lx:" " 0x%02x ]\n", (long)relative_addr, (int)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(pmppc) { struct pmppc_data *d; struct memory *mem = devinit->machine->memory; CHECK_ALLOCATION(d = (struct pmppc_data *) malloc(sizeof(struct pmppc_data))); memset(d, 0, sizeof(struct pmppc_data)); /* * Based on how NetBSD/pmppc's pmppc_setup() works: * * config0: * bit 7 Is monarch (?). * bit 5 Has ethernet. * bit 4 1 = No RTC. * bits 3..2 Flash size (00 = 256 MB, 01 = 128 MB, * 10 = 64 MB, 11 = 32 MB). * bits 1..0 Flash width (00 = 64, 01 = 32, 10 = 16, 11 = 0). * * config1: * bit 7 Boot device is FLASH (1) or ROM (0). * bit 6 Has ECC. * bits 5..4 Memory size: 00 = 32 MB, 01 = 64 MB, * 10 = 128 MB, 11 = 256 MB. * bits 3..2 L2 cache. * bits 1..0 Bus frequency: 00 = 66.66 MHz, 01 = 83.33 MHz, * 10 = 100.00 MHz, 11 = reserved? */ d->config0 = 0x20; d->config1 = 0; if (mem->physical_max == 32*1048576) { } else if (mem->physical_max == 64*1048576) { d->config1 |= 0x01; } else if (mem->physical_max == 128*1048576) { d->config1 |= 0x10; } else if (mem->physical_max == 256*1048576) { d->config1 |= 0x11; } else { fatal("A PM/PPC can have 32, 64, 128, or 256 MB RAM.\n"); exit(1); } memory_device_register(mem, "pmppc_board", PMPPC_CONFIG0, 0x10, dev_pmppc_board_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_le.cc000644 001750 001750 00000052763 13402411502 017220 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: LANCE ethernet, as used in DECstations * * This is based on "PMAD-AA TURBOchannel Ethernet Module Functional * Specification". I've tried to keep symbol names in this file to what * the specs use. * * This is what the memory layout looks like on a DECstation 5000/200: * * 0x000000 - 0x0fffff Ethernet SRAM buffer (should be 128KB) * 0x100000 - 0x17ffff LANCE registers * 0x1c0000 - 0x1fffff Ethernet Diagnostic ROM and Station * Address ROM * * The length of the device is set to 0x1c0200, however, because Sprite * tries to read TURBOchannel rom data from 0x1c03f0, and that is provided * by the turbochannel device, not this device. * * * TODO: Error conditions (such as when there are not enough receive * buffers) are not emulated yet. * * (Old bug, but probably still valid: "UDP packets that are too * large are not handled well by the Lance device.") */ #include #include #include #include "cpu.h" #include "devices.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "net.h" #include "thirdparty/if_lereg.h" #define LE_TICK_SHIFT 14 /* #define LE_DEBUG */ /* #define debug fatal */ extern int quiet_mode; #define LE_MODE_LOOP 4 #define LE_MODE_DTX 2 #define LE_MODE_DRX 1 #define N_REGISTERS 4 #define SRAM_SIZE (128*1024) #define ROM_SIZE 32 struct le_data { struct interrupt irq; int irq_asserted; uint64_t buf_start; uint64_t buf_end; int len; uint8_t rom[ROM_SIZE]; int reg_select; uint16_t reg[N_REGISTERS]; unsigned char *sram; /* Initialization block: */ uint32_t init_block_addr; uint16_t mode; uint64_t padr; /* MAC address */ uint64_t ladrf; uint32_t rdra; /* receive descriptor ring address */ int rlen; /* nr of rx descriptors */ uint32_t tdra; /* transmit descriptor ring address */ int tlen; /* nr ot tx descriptors */ /* Current rx and tx descriptor indices: */ int rxp; int txp; unsigned char *tx_packet; int tx_packet_len; unsigned char *rx_packet; int rx_packet_len; int rx_packet_offset; int rx_middle_bit; }; /* * le_read_16bit(): * * Read a 16-bit word from the SRAM. */ static uint64_t le_read_16bit(struct le_data *d, int addr) { /* TODO: This is for little endian only */ int x = d->sram[addr & (SRAM_SIZE-1)] + (d->sram[(addr+1) & (SRAM_SIZE-1)] << 8); return x; } /* * le_write_16bit(): * * Write a 16-bit word to the SRAM. */ static void le_write_16bit(struct le_data *d, int addr, uint16_t x) { /* TODO: This is for little endian only */ d->sram[addr & (SRAM_SIZE-1)] = x & 0xff; d->sram[(addr+1) & (SRAM_SIZE-1)] = (x >> 8) & 0xff; } /* * le_chip_init(): * * Initialize data structures by reading an 'initialization block' from the * SRAM. */ static void le_chip_init(struct le_data *d) { d->init_block_addr = (d->reg[1] & 0xffff) + ((d->reg[2] & 0xff) << 16); if (d->init_block_addr & 1) fatal("[ le: WARNING! initialization block address " "not word aligned? ]\n"); debug("[ le: d->init_block_addr = 0x%06x ]\n", d->init_block_addr); d->mode = le_read_16bit(d, d->init_block_addr + 0); d->padr = le_read_16bit(d, d->init_block_addr + 2); d->padr += (le_read_16bit(d, d->init_block_addr + 4) << 16); d->padr += (le_read_16bit(d, d->init_block_addr + 6) << 32); d->ladrf = le_read_16bit(d, d->init_block_addr + 8); d->ladrf += (le_read_16bit(d, d->init_block_addr + 10) << 16); d->ladrf += (le_read_16bit(d, d->init_block_addr + 12) << 32); d->ladrf += (le_read_16bit(d, d->init_block_addr + 14) << 48); d->rdra = le_read_16bit(d, d->init_block_addr + 16); d->rdra += ((le_read_16bit(d, d->init_block_addr + 18) & 0xff) << 16); d->rlen = 1 << ((le_read_16bit(d, d->init_block_addr + 18) >> 13) & 7); d->tdra = le_read_16bit(d, d->init_block_addr + 20); d->tdra += ((le_read_16bit(d, d->init_block_addr + 22) & 0xff) << 16); d->tlen = 1 << ((le_read_16bit(d, d->init_block_addr + 22) >> 13) & 7); debug("[ le: DEBUG: mode %04x ]\n", d->mode); debug("[ le: DEBUG: padr %016llx ]\n", (long long)d->padr); debug("[ le: DEBUG: ladrf %016llx ]\n", (long long)d->ladrf); debug("[ le: DEBUG: rdra %06llx ]\n", d->rdra); debug("[ le: DEBUG: rlen %3i ]\n", d->rlen); debug("[ le: DEBUG: tdra %06llx ]\n", d->tdra); debug("[ le: DEBUG: tlen %3i ]\n", d->tlen); /* Set TXON and RXON, unless they are disabled by 'mode': */ if (d->mode & LE_MODE_DTX) d->reg[0] &= ~LE_TXON; else d->reg[0] |= LE_TXON; if (d->mode & LE_MODE_DRX) d->reg[0] &= ~LE_RXON; else d->reg[0] |= LE_RXON; /* Go to the start of the descriptor rings: */ d->rxp = d->txp = 0; /* Set IDON and reset the INIT bit when we are done. */ d->reg[0] |= LE_IDON; d->reg[0] &= ~LE_INIT; /* Free any old packets: */ if (d->tx_packet != NULL) free(d->tx_packet); d->tx_packet = NULL; d->tx_packet_len = 0; if (d->rx_packet != NULL) free(d->rx_packet); d->rx_packet = NULL; d->rx_packet_len = 0; d->rx_packet_offset = 0; d->rx_middle_bit = 0; } /* * le_tx(): * * Check the transmitter descriptor ring for buffers that are owned by the * Lance chip (that is, buffers that are to be transmitted). * * This routine should only be called if TXON is enabled. */ static void le_tx(struct net *net, struct le_data *d) { int start_txp = d->txp; uint16_t tx_descr[4]; int stp, enp, cur_packet_offset; size_t i; uint32_t bufaddr, buflen; /* TODO: This is just a guess: */ d->reg[0] &= ~LE_TDMD; do { /* Load the 8 descriptor bytes: */ tx_descr[0] = le_read_16bit(d, d->tdra + d->txp*8 + 0); tx_descr[1] = le_read_16bit(d, d->tdra + d->txp*8 + 2); tx_descr[2] = le_read_16bit(d, d->tdra + d->txp*8 + 4); tx_descr[3] = le_read_16bit(d, d->tdra + d->txp*8 + 6); bufaddr = tx_descr[0] + ((tx_descr[1] & 0xff) << 16); stp = tx_descr[1] & LE_STP? 1 : 0; enp = tx_descr[1] & LE_ENP? 1 : 0; buflen = 4096 - (tx_descr[2] & 0xfff); /* * Check the OWN bit. If it is zero, then this buffer is * not ready to be transmitted yet. Also check the '1111' * mark, and make sure that byte-count is reasonable. */ if (!(tx_descr[1] & LE_OWN)) return; if ((tx_descr[2] & 0xf000) != 0xf000) return; if (buflen < 12 || buflen > 1900) { fatal("[ le_tx(): buflen = %i ]\n", buflen); return; } debug("[ le_tx(): descr %3i DUMP: 0x%04x 0x%04x 0x%04x 0x%04x " "=> addr=0x%06x, len=%i bytes, STP=%i ENP=%i ]\n", d->txp, tx_descr[0], tx_descr[1], tx_descr[2], tx_descr[3], bufaddr, buflen, stp, enp); if (d->tx_packet == NULL && !stp) { fatal("[ le_tx(): !stp but tx_packet == NULL ]\n"); return; } if (d->tx_packet != NULL && stp) { fatal("[ le_tx(): stp but tx_packet != NULL ]\n"); free(d->tx_packet); d->tx_packet = NULL; d->tx_packet_len = 0; } /* Where to write to in the tx_packet: */ cur_packet_offset = d->tx_packet_len; /* Start of a new packet: */ if (stp) { d->tx_packet_len = buflen; CHECK_ALLOCATION(d->tx_packet = (unsigned char *) malloc(buflen)); } else { d->tx_packet_len += buflen; CHECK_ALLOCATION(d->tx_packet = (unsigned char *) realloc(d->tx_packet, d->tx_packet_len)); } /* Copy data from SRAM into the tx packet: */ for (i=0; isram[(bufaddr + i) & (SRAM_SIZE-1)]; d->tx_packet[cur_packet_offset + i] = ch; } /* * Is this the last buffer in a packet? Then transmit * it, cause an interrupt, and free the memory used by * the packet. */ if (enp) { net_ethernet_tx(net, d, d->tx_packet, d->tx_packet_len); free(d->tx_packet); d->tx_packet = NULL; d->tx_packet_len = 0; d->reg[0] |= LE_TINT; } /* Clear the OWN bit: */ tx_descr[1] &= ~LE_OWN; /* Write back the descriptor to SRAM: */ le_write_16bit(d, d->tdra + d->txp*8 + 2, tx_descr[1]); le_write_16bit(d, d->tdra + d->txp*8 + 4, tx_descr[2]); le_write_16bit(d, d->tdra + d->txp*8 + 6, tx_descr[3]); /* Go to the next descriptor: */ d->txp ++; if (d->txp >= d->tlen) d->txp = 0; } while (d->txp != start_txp); /* We are here if all descriptors were taken care of. */ fatal("[ le_tx(): all TX descriptors used up? ]\n"); } /* * le_rx(): * * This routine should only be called if RXON is enabled. */ static void le_rx(struct net *net, struct le_data *d) { int start_rxp = d->rxp; size_t i; uint16_t rx_descr[4]; uint32_t bufaddr, buflen; do { if (d->rx_packet == NULL) return; /* Load the 8 descriptor bytes: */ rx_descr[0] = le_read_16bit(d, d->rdra + d->rxp*8 + 0); rx_descr[1] = le_read_16bit(d, d->rdra + d->rxp*8 + 2); rx_descr[2] = le_read_16bit(d, d->rdra + d->rxp*8 + 4); rx_descr[3] = le_read_16bit(d, d->rdra + d->rxp*8 + 6); bufaddr = rx_descr[0] + ((rx_descr[1] & 0xff) << 16); buflen = 4096 - (rx_descr[2] & 0xfff); /* * Check the OWN bit. If it is zero, then this buffer is * not ready to receive data yet. Also check the '1111' * mark, and make sure that byte-count is reasonable. */ if (!(rx_descr[1] & LE_OWN)) return; if ((rx_descr[2] & 0xf000) != 0xf000) return; if (buflen < 12 || buflen > 1900) { fatal("[ le_rx(): buflen = %i ]\n", buflen); return; } debug("[ le_rx(): descr %3i DUMP: 0x%04x 0x%04x 0x%04x 0x%04x " "=> addr=0x%06x, len=%i bytes ]\n", d->rxp, rx_descr[0], rx_descr[1], rx_descr[2], rx_descr[3], bufaddr, buflen); /* Copy data from the packet into SRAM: */ for (i=0; irx_packet_offset+(ssize_t)i >= d->rx_packet_len) break; d->sram[(bufaddr + i) & (SRAM_SIZE-1)] = d->rx_packet[d->rx_packet_offset + i]; } /* Here, i is the number of bytes copied. */ d->rx_packet_offset += i; /* Set the ENP bit if this was the end of a packet: */ if (d->rx_packet_offset >= d->rx_packet_len) { rx_descr[1] |= LE_ENP; /* * NOTE: The Lance documentation that I have read * says _NOTHING_ about the length being 4 more than * the length of the data. You can guess how * surprised I was when I saw the following in * NetBSD (dev/ic/am7990.c): * * lance_read(sc, LE_RBUFADDR(sc, bix), * (int)rmd.rmd3 - 4); */ rx_descr[3] &= ~0xfff; rx_descr[3] |= d->rx_packet_len + 4; free(d->rx_packet); d->rx_packet = NULL; d->rx_packet_len = 0; d->rx_packet_offset = 0; d->rx_middle_bit = 0; d->reg[0] |= LE_RINT; } /* Set the STP bit if this was the start of a packet: */ if (!d->rx_middle_bit) { rx_descr[1] |= LE_STP; /* Are we continuing on this packet? */ if (d->rx_packet != NULL) d->rx_middle_bit = 1; } /* Clear the OWN bit: */ rx_descr[1] &= ~LE_OWN; /* Write back the descriptor to SRAM: */ le_write_16bit(d, d->rdra + d->rxp*8 + 2, rx_descr[1]); le_write_16bit(d, d->rdra + d->rxp*8 + 4, rx_descr[2]); le_write_16bit(d, d->rdra + d->rxp*8 + 6, rx_descr[3]); /* Go to the next descriptor: */ d->rxp ++; if (d->rxp >= d->rlen) d->rxp = 0; } while (d->rxp != start_rxp); /* We are here if all descriptors were taken care of. */ fatal("[ le_rx(): all RX descriptors used up? ]\n"); } /* * le_register_fix(): */ static void le_register_fix(struct net *net, struct le_data *d) { /* Init with new Initialization block, if needed. */ if (d->reg[0] & LE_INIT) le_chip_init(d); #ifdef LE_DEBUG { static int x = 1234; if (x != d->reg[0]) { debug("[ le reg[0] = 0x%04x ]\n", d->reg[0]); x = d->reg[0]; } } #endif /* * If the receiver is on: * If there is a current rx_packet, try to receive it into the * Lance buffers. Then try to receive any additional packets. */ if (d->reg[0] & LE_RXON) { do { if (d->rx_packet != NULL) /* Try to receive the packet: */ le_rx(net, d); if (d->rx_packet != NULL) /* If the packet wasn't fully received, then abort for now. */ break; if (d->rx_packet == NULL && net_ethernet_rx_avail(net, d)) net_ethernet_rx(net, d, &d->rx_packet, &d->rx_packet_len); } while (d->rx_packet != NULL); } /* If the transmitter is on, check for outgoing buffers: */ if (d->reg[0] & LE_TXON) le_tx(net, d); /* SERR should be the OR of BABL, CERR, MISS, and MERR: */ d->reg[0] &= ~LE_SERR; if (d->reg[0] & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) d->reg[0] |= LE_SERR; /* INTR should be the OR of BABL, MISS, MERR, RINT, TINT, IDON: */ d->reg[0] &= ~LE_INTR; if (d->reg[0] & (LE_BABL | LE_MISS | LE_MERR | LE_RINT | LE_TINT | LE_IDON)) d->reg[0] |= LE_INTR; /* The MERR bit clears some bits: */ if (d->reg[0] & LE_MERR) d->reg[0] &= ~(LE_RXON | LE_TXON); /* The STOP bit clears a lot of stuff: */ #if 0 /* According to the LANCE manual: (doesn't work with Ultrix) */ if (d->reg[0] & LE_STOP) d->reg[0] &= ~(LE_SERR | LE_BABL | LE_CERR | LE_MISS | LE_MERR | LE_RINT | LE_TINT | LE_IDON | LE_INTR | LE_INEA | LE_RXON | LE_TXON | LE_TDMD); #else /* Works with Ultrix: */ if (d->reg[0] & LE_STOP) d->reg[0] &= ~(LE_IDON); #endif } DEVICE_TICK(le) { struct le_data *d = (struct le_data *) extra; int new_assert; le_register_fix(cpu->machine->emul->net, d); new_assert = (d->reg[0] & LE_INTR) && (d->reg[0] & LE_INEA); if (new_assert && !d->irq_asserted) INTERRUPT_ASSERT(d->irq); if (d->irq_asserted && !new_assert) INTERRUPT_DEASSERT(d->irq); d->irq_asserted = new_assert; } /* * le_register_write(): * * This function is called when the value 'x' is written to register 'r'. */ void le_register_write(struct le_data *d, int r, uint32_t x) { switch (r) { case 0: /* CSR0: */ /* Some bits are write-one-to-clear: */ if (x & LE_BABL) d->reg[r] &= ~LE_BABL; if (x & LE_CERR) d->reg[r] &= ~LE_CERR; if (x & LE_MISS) d->reg[r] &= ~LE_MISS; if (x & LE_MERR) d->reg[r] &= ~LE_MERR; if (x & LE_RINT) d->reg[r] &= ~LE_RINT; if (x & LE_TINT) d->reg[r] &= ~LE_TINT; if (x & LE_IDON) d->reg[r] &= ~LE_IDON; /* Some bits are write-only settable, not clearable: */ if (x & LE_TDMD) d->reg[r] |= LE_TDMD; if (x & LE_STRT) { d->reg[r] |= LE_STRT; d->reg[r] &= ~LE_STOP; } if (x & LE_INIT) { if (!(d->reg[r] & LE_STOP)) fatal("[ le: attempt to INIT before" " STOPped! ]\n"); d->reg[r] |= LE_INIT; d->reg[r] &= ~LE_STOP; } if (x & LE_STOP) { d->reg[r] |= LE_STOP; /* STOP takes precedence over STRT and INIT: */ d->reg[r] &= ~(LE_STRT | LE_INIT); } /* Some bits get through, both settable and clearable: */ d->reg[r] &= ~LE_INEA; d->reg[r] |= (x & LE_INEA); break; default: /* CSR1, CSR2, and CSR3: */ d->reg[r] = x; } } DEVICE_ACCESS(le_sram) { struct le_data *d = (struct le_data *) extra; size_t i; int retval; #ifdef LE_DEBUG if (writeflag == MEM_WRITE) { fatal("[ le_sram: write to addr 0x%06x: ", (int)relative_addr); for (i=0; isram + relative_addr, len); if (!quiet_mode) { debug("[ le: read from SRAM offset 0x%05x:", relative_addr); for (i=0; isram + relative_addr, data, len); if (!quiet_mode) { debug("[ le: write to SRAM offset 0x%05x:", relative_addr); for (i=0; i= 0xc0000 && relative_addr <= 0xfffff) { uint32_t a; int j = (relative_addr & 0xff) / 4; a = d->rom[j & (ROM_SIZE-1)]; if (writeflag == MEM_READ) { odata = (a << 24) + (a << 16) + (a << 8) + a; } else { fatal("[ le: WRITE to ethernet addr (%08lx):", (long)relative_addr); for (i=0; ireg[d->reg_select]; if (!quiet_mode) debug("[ le: read from register 0x%02x: 0x" "%02x ]\n", d->reg_select, (int)odata); /* * A read from csr1..3 should return "undefined" * result if the stop bit is set. However, Ultrix * seems to do just that, so let's _not_ print * a warning here. */ } else { if (!quiet_mode) debug("[ le: write to register 0x%02x: 0x" "%02x ]\n", d->reg_select, (int)idata); /* * A write to from csr1..3 when the stop bit is * set should be ignored. However, Ultrix writes * even if the stop bit is set, so let's _not_ * print a warning about it. */ le_register_write(d, d->reg_select, idata); } break; /* Register select: */ case 4: if (writeflag==MEM_READ) { odata = d->reg_select; if (!quiet_mode) debug("[ le: read from register select: " "0x%02x ]\n", (int)odata); } else { if (!quiet_mode) debug("[ le: write to register select: " "0x%02x ]\n", (int)idata); d->reg_select = idata & (N_REGISTERS - 1); if (idata >= N_REGISTERS) fatal("[ le: WARNING! register select %i " "(max is %i) ]\n", idata, N_REGISTERS - 1); } break; default: if (writeflag==MEM_READ) { fatal("[ le: read from UNIMPLEMENTED addr 0x%06x ]\n", (int)relative_addr); } else { fatal("[ le: write to UNIMPLEMENTED addr 0x%06x: " "0x%08x ]\n", (int)relative_addr, (int)idata); } } do_return: if (writeflag == MEM_READ) { memory_writemax64(cpu, data, len, odata); #ifdef LE_DEBUG fatal("[ le: read from addr 0x%06x: 0x%08x ]\n", relative_addr, odata); #endif } dev_le_tick(cpu, extra); return retval; } /* * dev_le_init(): */ void dev_le_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, uint64_t buf_start, uint64_t buf_end, const char *irq_path, int len) { char *name2; size_t nlen = 55; struct le_data *d; CHECK_ALLOCATION(d = (struct le_data *) malloc(sizeof(struct le_data))); memset(d, 0, sizeof(struct le_data)); INTERRUPT_CONNECT(irq_path, d->irq); CHECK_ALLOCATION(d->sram = (unsigned char *) malloc(SRAM_SIZE)); memset(d->sram, 0, SRAM_SIZE); /* TODO: Are these actually used yet? */ d->len = len; d->buf_start = buf_start; d->buf_end = buf_end; /* Initial register contents: */ d->reg[0] = LE_STOP; d->tx_packet = NULL; d->rx_packet = NULL; /* ROM (including the MAC address): */ net_generate_unique_mac(machine, &d->rom[0]); /* Copies of the MAC address and a test pattern: */ d->rom[10] = d->rom[21] = d->rom[5]; d->rom[11] = d->rom[20] = d->rom[4]; d->rom[12] = d->rom[19] = d->rom[3]; d->rom[7] = d->rom[8] = d->rom[23] = d->rom[13] = d->rom[18] = d->rom[2]; d->rom[6] = d->rom[9] = d->rom[22] = d->rom[14] = d->rom[17] = d->rom[1]; d->rom[15] = d->rom[16] = d->rom[0]; d->rom[24] = d->rom[28] = 0xff; d->rom[25] = d->rom[29] = 0x00; d->rom[26] = d->rom[30] = 0x55; d->rom[27] = d->rom[31] = 0xaa; memory_device_register(mem, "le_sram", baseaddr, SRAM_SIZE, dev_le_sram_access, (void *)d, DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK | DM_READS_HAVE_NO_SIDE_EFFECTS, d->sram); CHECK_ALLOCATION(name2 = (char *) malloc(nlen)); snprintf(name2, nlen, "le [%02x:%02x:%02x:%02x:%02x:%02x]", d->rom[0], d->rom[1], d->rom[2], d->rom[3], d->rom[4], d->rom[5]); memory_device_register(mem, name2, baseaddr + 0x100000, len - 0x100000, dev_le_access, (void *)d, DM_DEFAULT, NULL); machine_add_tickfunction(machine, dev_le_tick, d, LE_TICK_SHIFT); net_add_nic(machine->emul->net, d, &d->rom[0]); } gxemul-0.6.1/src/devices/dev_unreadable.cc000644 001750 001750 00000003712 13402411502 020710 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: A simple device which returns an error for all reads/writes */ #include #include #include #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" DEVICE_ACCESS(unreadable) { return 0; } DEVINIT(unreadable) { memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, devinit->len, dev_unreadable_access, NULL, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_m8820x.cc000644 001750 001750 00000014425 13402411502 017557 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: M88200/M88204 CMMU (Cache/Memory Management Unit) */ #include #include #include #include "cpu.h" #include "device.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/m8820x.h" #include "thirdparty/m8820x_pte.h" struct m8820x_data { int cmmu_nr; }; /* * m8820x_command(): * * Handle M8820x commands written to the System Command Register. */ static void m8820x_command(struct cpu *cpu, struct m8820x_data *d) { uint32_t *regs = cpu->cd.m88k.cmmu[d->cmmu_nr]->reg; int cmd = regs[CMMU_SCR]; uint32_t sar = regs[CMMU_SAR]; size_t i; uint32_t super, all; switch (cmd) { case CMMU_FLUSH_CACHE_CB_LINE: case CMMU_FLUSH_CACHE_CB_PAGE: case CMMU_FLUSH_CACHE_INV_LINE: case CMMU_FLUSH_CACHE_INV_PAGE: case CMMU_FLUSH_CACHE_INV_ALL: case CMMU_FLUSH_CACHE_CBI_LINE: case CMMU_FLUSH_CACHE_CBI_PAGE: case CMMU_FLUSH_CACHE_CBI_SEGMENT: case CMMU_FLUSH_CACHE_CBI_ALL: /* TODO */ break; case CMMU_FLUSH_USER_ALL: case CMMU_FLUSH_USER_PAGE: case CMMU_FLUSH_SUPER_ALL: case CMMU_FLUSH_SUPER_PAGE: /* TODO: Segment invalidation. */ all = super = 0; if (cmd == CMMU_FLUSH_USER_ALL || cmd == CMMU_FLUSH_SUPER_ALL) all = 1; if (cmd == CMMU_FLUSH_SUPER_ALL || cmd == CMMU_FLUSH_SUPER_PAGE) super = M8820X_PATC_SUPERVISOR_BIT; /* TODO: Don't invalidate EVERYTHING like this! */ cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); for (i=0; icd.m88k.cmmu[d->cmmu_nr] ->patc_v_and_control[i]; uint32_t p = cpu->cd.m88k.cmmu[d->cmmu_nr] ->patc_p_and_supervisorbit[i]; /* Already invalid? Then skip this entry. */ if (!(v & PG_V)) continue; /* Super/user mismatch? Then skip the entry. */ if ((p & M8820X_PATC_SUPERVISOR_BIT) != super) continue; /* If not all pages are to be invalidated, there must be a virtual address match: */ if (!all && (sar & 0xfffff000) != (v & 0xfffff000)) continue; /* Finally, invalidate the entry: */ cpu->cd.m88k.cmmu[d->cmmu_nr]->patc_v_and_control[i] = v & ~PG_V; } break; default: fatal("[ m8820x_command: FATAL ERROR! unimplemented " "command 0x%02x ]\n", cmd); exit(1); } } DEVICE_ACCESS(m8820x) { uint64_t idata = 0, odata = 0; struct m8820x_data *d = (struct m8820x_data *) extra; uint32_t *regs = cpu->cd.m88k.cmmu[d->cmmu_nr]->reg; uint32_t *batc = cpu->cd.m88k.cmmu[d->cmmu_nr]->batc; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (writeflag == MEM_READ) odata = regs[relative_addr / sizeof(uint32_t)]; switch (relative_addr / sizeof(uint32_t)) { case CMMU_IDR: if (writeflag == MEM_WRITE) { fatal("m8820x: write to CMMU_IDR: TODO\n"); exit(1); } break; case CMMU_SCR: if (writeflag == MEM_READ) { fatal("m8820x: read from CMMU_SCR: TODO\n"); exit(1); } else { regs[relative_addr / sizeof(uint32_t)] = idata; m8820x_command(cpu, d); } break; case CMMU_SSR: if (writeflag == MEM_WRITE) { fatal("m8820x: write to CMMU_SSR: TODO\n"); exit(1); } break; case CMMU_PFSR: case CMMU_PFAR: case CMMU_SAR: case CMMU_SCTR: case CMMU_SAPR: /* TODO: Invalidate something for */ case CMMU_UAPR: /* SAPR and UAPR writes? */ /* TODO: Don't invalidate everything. */ cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); if (writeflag == MEM_WRITE) regs[relative_addr / sizeof(uint32_t)] = idata; break; case CMMU_BWP0: case CMMU_BWP1: case CMMU_BWP2: case CMMU_BWP3: case CMMU_BWP4: case CMMU_BWP5: case CMMU_BWP6: case CMMU_BWP7: if (writeflag == MEM_WRITE) { uint32_t old; int i = (relative_addr / sizeof(uint32_t)) - CMMU_BWP0; regs[relative_addr / sizeof(uint32_t)] = idata; /* Also write to the specific batc registers: */ old = batc[i]; batc[i] = idata; if (old != idata) { /* TODO: Don't invalidate everything? */ cpu->invalidate_translation_caches( cpu, 0, INVALIDATE_ALL); } } break; case CMMU_CSSP0: /* TODO: Actually care about cache details. */ break; default:fatal("[ m8820x: unimplemented %s offset 0x%x", writeflag == MEM_WRITE? "write to" : "read from", (int) relative_addr); if (writeflag == MEM_WRITE) fatal(": 0x%x", (int)idata); fatal(" ]\n"); exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(m8820x) { struct m8820x_data *d; CHECK_ALLOCATION(d = (struct m8820x_data *) malloc(sizeof(struct m8820x_data))); memset(d, 0, sizeof(struct m8820x_data)); d->cmmu_nr = devinit->addr2; memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, M8820X_LENGTH, dev_m8820x_access, (void *)d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_algor.cc000644 001750 001750 00000014153 13402411502 017713 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Algor P5064 misc. stuff * * TODO: This is hardcoded for P5064 right now. Generalize it to P40xx etc. * * CPU irq 2 = ISA, 3 = PCI, 4 = Local. */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/algor_p5064reg.h" struct algor_data { uint64_t base_addr; struct interrupt mips_irq_2; struct interrupt mips_irq_3; struct interrupt mips_irq_4; }; DEVICE_ACCESS(algor) { struct algor_data *d = (struct algor_data *) extra; uint64_t idata = 0, odata = 0; const char *n = NULL; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); relative_addr += d->base_addr; switch (relative_addr) { case P5064_LED1 + 0x0: case P5064_LED1 + 0x4: case P5064_LED1 + 0x8: case P5064_LED1 + 0xc: break; case P5064_LOCINT: /* * TODO: See how ISAINT is implemented. * * Implemented so far: COM1 only. */ n = "P5064_LOCINT"; if (writeflag == MEM_READ) { /* Ugly hack for NetBSD startup. TODO: fix */ static int x = 0; if (((++ x) & 0xffff) == 0) odata |= LOCINT_RTC; if (cpu->machine->isa_pic_data.pic1->irr & ~cpu->machine->isa_pic_data.pic1->ier & 0x10) odata |= LOCINT_COM1; if (cpu->machine->isa_pic_data.pic1->irr & ~cpu->machine->isa_pic_data.pic1->ier & 0x08) odata |= LOCINT_COM2; /* Read => ack: */ cpu->machine->isa_pic_data.pic1->irr &= ~0x18; INTERRUPT_DEASSERT(d->mips_irq_4); } else { if (idata & LOCINT_COM1) cpu->machine->isa_pic_data.pic1->ier &= ~0x10; else cpu->machine->isa_pic_data.pic1->ier |= 0x10; if (idata & LOCINT_COM2) cpu->machine->isa_pic_data.pic1->ier &= ~0x08; else cpu->machine->isa_pic_data.pic1->ier |= 0x08; } break; case P5064_PANIC: n = "P5064_PANIC"; if (writeflag == MEM_READ) odata = 0; break; case P5064_PCIINT: /* * TODO: See how ISAINT is implemented. */ n = "P5064_PCIINT"; if (writeflag == MEM_READ) { odata = 0; INTERRUPT_DEASSERT(d->mips_irq_3); } break; case P5064_ISAINT: /* * ISA interrupts: * * Bit: IRQ Source: * 0 ISAINT_ISABR * 1 ISAINT_IDE0 * 2 ISAINT_IDE1 * * NOTE/TODO: Ugly redirection to the ISA controller. */ n = "P5064_ISAINT"; if (writeflag == MEM_WRITE) { if (idata & ISAINT_IDE0) cpu->machine->isa_pic_data.pic2->ier &= ~0x40; else cpu->machine->isa_pic_data.pic2->ier |= 0x40; if (idata & ISAINT_IDE1) cpu->machine->isa_pic_data.pic2->ier &= ~0x80; else cpu->machine->isa_pic_data.pic2->ier |= 0x80; cpu->machine->isa_pic_data.pic1->ier &= ~0x04; } else { if (cpu->machine->isa_pic_data.pic2->irr & ~cpu->machine->isa_pic_data.pic2->ier & 0x40) odata |= ISAINT_IDE0; if (cpu->machine->isa_pic_data.pic2->irr & ~cpu->machine->isa_pic_data.pic2->ier & 0x80) odata |= ISAINT_IDE1; /* Read => ack: */ cpu->machine->isa_pic_data.pic2->irr &= ~0xc0; INTERRUPT_DEASSERT(d->mips_irq_2); } break; case P5064_KBDINT: /* * TODO: See how ISAINT is implemented. */ n = "P5064_KBDINT"; if (writeflag == MEM_READ) odata = 0; break; default:if (writeflag == MEM_READ) { fatal("[ algor: read from 0x%x ]\n", (int)relative_addr); } else { fatal("[ algor: write to 0x%x: 0x%" PRIx64" ]\n", (int) relative_addr, (uint64_t) idata); } } if (n != NULL) { if (writeflag == MEM_READ) { debug("[ algor: read from %s: 0x%" PRIx64" ]\n", n, (uint64_t) odata); } else { debug("[ algor: write to %s: 0x%" PRIx64" ]\n", n, (uint64_t) idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(algor) { char tmpstr[200]; struct algor_data *d; CHECK_ALLOCATION(d = (struct algor_data *) malloc(sizeof(struct algor_data))); memset(d, 0, sizeof(struct algor_data)); d->base_addr = devinit->addr; if (devinit->addr != 0x1ff00000) { fatal("The Algor base address should be 0x1ff00000.\n"); exit(1); } /* Connect to MIPS irq 2, 3, and 4: */ snprintf(tmpstr, sizeof(tmpstr), "%s.2", devinit->interrupt_path); INTERRUPT_CONNECT(tmpstr, d->mips_irq_2); snprintf(tmpstr, sizeof(tmpstr), "%s.3", devinit->interrupt_path); INTERRUPT_CONNECT(tmpstr, d->mips_irq_3); snprintf(tmpstr, sizeof(tmpstr), "%s.4", devinit->interrupt_path); INTERRUPT_CONNECT(tmpstr, d->mips_irq_4); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, 0x100000, dev_algor_access, d, DM_DEFAULT, NULL); devinit->return_ptr = d; return 1; } gxemul-0.6.1/src/devices/dev_dreamcast_g2.cc000644 001750 001750 00000020021 13402411502 021131 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Dreamcast G2 bus * * Register offsets are from KOS, NetBSD sources, etc. * * TODO: * Figure out what all these registers do! */ #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #ifdef UNSTABLE_DEVEL // #define debug fatal #endif #define NREGS_EXT_DMA (0x80/sizeof(uint32_t)) #define NREGS_MISC (0x80/sizeof(uint32_t)) struct dreamcast_g2_data { uint32_t extdma_reg[NREGS_EXT_DMA]; uint32_t misc_reg[NREGS_MISC]; }; /* * External DMA: 4 channels * * Note: Addresses and sizes must be 32-byte aligned. * DIR is 0 for CPU to External device, 1 for External to CPU. * MODE should be 5 for transfers to/from the SPU. */ #define EXTDMA_CTRL_EXT_ADDR 0x00 /* EXTDMA_CTRL_* are repeated */ #define EXTDMA_CTRL_SH4_ADDR 0x04 /* 4 times (once for each channel) */ #define EXTDMA_CTRL_SIZE 0x08 #define EXTDMA_CTRL_DIR 0x0c #define EXTDMA_CTRL_MODE 0x10 #define EXTDMA_CTRL_CHAN_ENABLE 0x14 /* Channel enable */ #define EXTDMA_CTRL_XFER_ENABLE 0x18 /* Transfer enable */ #define EXTDMA_CTRL_STATUS 0x1c /* Transfer status */ #define EXTDMA_WAITSTATE 0x90 #define EXTDMA_MAGIC 0xbc #define EXTDMA_MAGIC_VALUE 0x4659404f #define EXTDMA_MAGIC_VALUE_ROM 0x46597f00 #define EXTDMA_STAT_EXT_ADDR 0xc0 /* EXTDMA_STAT_* are repeated 4 */ #define EXTDMA_STAT_SH4_ADDR 0xc4 /* times too */ #define EXTDMA_STAT_SIZE 0xc8 #define EXTDMA_STAT_STATUS 0xcc DEVICE_ACCESS(dreamcast_g2_extdma) { struct dreamcast_g2_data *d = (struct dreamcast_g2_data *) extra; uint64_t idata = 0, odata = 0; int reg = relative_addr, channel = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* Default read: */ if (writeflag == MEM_READ) odata = d->extdma_reg[relative_addr / sizeof(uint32_t)]; /* * 0x5f7800 .. 1f = DMA channel 0 * 20 .. 3f = DMA channel 1 * 40 .. 5f = DMA channel 2 * 60 .. 7f = DMA channel 3 * 80 .. bf = misc magic stuff * c0 .. cf = DMA channel 0 status * d0 .. df = DMA channel 1 status * e0 .. ef = DMA channel 2 status * f0 .. ff = DMA channel 3 status */ if (reg < 0x7f) { channel = (reg >> 5) & 3; reg &= 0x1f; } if (reg >= 0xc0 && reg < 0xff) { channel = (reg >> 4) & 3; reg = 0xc0 + (reg & 0xf); } switch (reg) { case EXTDMA_CTRL_EXT_ADDR: if (writeflag == MEM_WRITE) { debug("[ dreamcast_g2_extdma: write to channel %i:" " EXT_ADDR = 0x%08x ]\n", channel, (int) idata); } break; case EXTDMA_CTRL_SH4_ADDR: if (writeflag == MEM_WRITE) { debug("[ dreamcast_g2_extdma: write to channel %i:" " SH4_ADDR = 0x%08x ]\n", channel, (int) idata); } break; case EXTDMA_CTRL_SIZE: if (writeflag == MEM_WRITE) { debug("[ dreamcast_g2_extdma: write to channel %i:" " SIZE = 0x%08x ]\n", channel, (int) idata); } break; case EXTDMA_CTRL_DIR: if (writeflag == MEM_WRITE) { debug("[ dreamcast_g2_extdma: write to channel %i:" " DIR = 0x%08x ]\n", channel, (int) idata); } break; case EXTDMA_CTRL_MODE: if (writeflag == MEM_WRITE) { debug("[ dreamcast_g2_extdma: write to channel %i:" " MODE = 0x%08x ]\n", channel, (int) idata); } break; case EXTDMA_CTRL_CHAN_ENABLE: if (writeflag == MEM_WRITE) { debug("[ dreamcast_g2_extdma: write to channel %i:" " CHAN_ENABLE = 0x%08x ]\n", channel, (int) idata); if (idata != 0) { fatal("EXTDMA_CTRL_CHAN_ENABLE: todo\n"); exit(1); } } break; case EXTDMA_CTRL_XFER_ENABLE: if (writeflag == MEM_WRITE) { debug("[ dreamcast_g2_extdma: write to channel %i:" " XFER_ENABLE = 0x%08x ]\n", channel, (int) idata); if (idata != 0) { fatal("EXTDMA_CTRL_XFER_ENABLE: todo\n"); exit(1); } } break; case EXTDMA_CTRL_STATUS: if (writeflag == MEM_WRITE) { debug("[ dreamcast_g2_extdma: write to channel %i:" " STATUS = 0x%08x ]\n", channel, (int) idata); if (idata != 0) { fatal("[ dreamcast_g2_extdma: write to channel %i:" " STATUS = 0x%08x: TODO (start transfer?) ]\n", channel, (int) idata); exit(1); } } break; case EXTDMA_WAITSTATE: break; case 0x94: case 0x98: case 0x9c: case 0xa0: case 0xa4: case 0xa8: case 0xac: case 0xb0: case 0xb4: case 0xb8: /* TODO */ break; case EXTDMA_MAGIC: if (writeflag == MEM_WRITE) { if (idata != EXTDMA_MAGIC_VALUE && idata != EXTDMA_MAGIC_VALUE_ROM) { fatal("Unimplemented g2 extdma magic " "vaule 0x%x\n", (int) idata); exit(1); } } break; default:if (writeflag == MEM_READ) { fatal("[ dreamcast_g2_extdma: read from addr 0x%x ]\n", (int)relative_addr); } else { fatal("[ dreamcast_g2_extdma: write to addr 0x%x: " "0x%x ]\n", (int)relative_addr, (int)idata); } exit(1); } /* Default write: */ if (writeflag == MEM_WRITE) d->extdma_reg[relative_addr / sizeof(uint32_t)] = idata; if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(dreamcast_g2_misc) { struct dreamcast_g2_data *d = (struct dreamcast_g2_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* Default read: */ if (writeflag == MEM_READ) odata = d->misc_reg[relative_addr / sizeof(uint32_t)]; switch (relative_addr) { case 0x64: /* Writing 0x1fffff to 0x5f74e4 resets a disabled GD-ROM drive? */ if (writeflag != MEM_WRITE || idata != 0x1fffff) { fatal("[ dreamcast_g2_misc: unimplemented 0xe4 ]\n"); exit(1); } break; default:if (writeflag == MEM_READ) { debug("[ dreamcast_g2_misc: read from addr 0x%x ]\n", (int)relative_addr); } else { debug("[ dreamcast_g2_misc: write to addr 0x%x: " "0x%x ]\n", (int)relative_addr, (int)idata); } /* exit(1); */ } /* Default write: */ if (writeflag == MEM_WRITE) d->misc_reg[relative_addr / sizeof(uint32_t)] = idata; if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(dreamcast_g2) { struct machine *machine = devinit->machine; struct dreamcast_g2_data *d; CHECK_ALLOCATION(d = (struct dreamcast_g2_data *) malloc(sizeof(struct dreamcast_g2_data))); memset(d, 0, sizeof(struct dreamcast_g2_data)); memory_device_register(machine->memory, "g2_misc", 0x005f7480, 0x80, dev_dreamcast_g2_misc_access, d, DM_DEFAULT, NULL); memory_device_register(machine->memory, "g2_extdma", 0x005f7800, 0x100, dev_dreamcast_g2_extdma_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_adb.cc000644 001750 001750 00000026325 13402411502 017341 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Apple Desktop Bus (ADB) controller * * Based on intuition from reverse-engineering NetBSD/macppc source code, * so it probably only works with that OS. * * The comment "OK" means that 100% of the functionality used by NetBSD/macppc * is covered. * * TODO: * o) Clean up, don't hardcode values. * o) Convert into a separate controller, bus, device architecture. */ #include #include #include #include #include "console.h" #include "cpu.h" #include "device.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/adb_viareg.h" #define debug fatal /* #define ADB_DEBUG */ #define TICK_SHIFT 17 #define DEV_ADB_LENGTH 0x2000 #define N_VIA_REGS 0x10 #define VIA_REG_SHIFT 9 #define MAX_BUF 100 static const char *via_regname[N_VIA_REGS] = { "vBufB", "vBufA", "vDirB", "vDirA", "vT1C", "vT1CH", "vT1L", "vT1LH", "vT2C", "vT2CH", "vSR", "vACR", "vPCR", "vIFR", "vIER", "(unknown)" }; struct adb_data { struct interrupt irq; int int_asserted; int kbd_dev; long long transfer_nr; uint8_t reg[N_VIA_REGS]; int cur_output_offset; uint8_t output_buf[MAX_BUF]; int cur_input_offset; int cur_input_length; uint8_t input_buf[MAX_BUF]; int dir; int int_enable; int ack; /* last ack state */ int tip; /* transfer in progress */ }; #define DIR_INPUT 0 #define DIR_OUTPUT 1 #define BUFB_nINTR 0x08 #define BUFB_ACK 0x10 #define BUFB_nTIP 0x20 #define IFR_SR 0x04 #define IFR_ANY 0x80 #define ACR_SR_OUT 0x10 DEVICE_TICK(adb) { struct adb_data *d = (struct adb_data *) extra; int assert; assert = d->reg[vIFR >> VIA_REG_SHIFT] & IFR_ANY; if (assert == IFR_ANY && d->int_enable) assert = 1; if (assert) INTERRUPT_ASSERT(d->irq); else if (d->int_asserted) INTERRUPT_DEASSERT(d->irq); d->int_asserted = assert; } /* * adb_reset(): * * Reset registers to default values. */ static void adb_reset(struct adb_data *d) { d->kbd_dev = 2; memset(d->reg, 0, sizeof(d->reg)); d->reg[vBufB >> VIA_REG_SHIFT] = BUFB_nINTR | BUFB_nTIP; d->cur_output_offset = 0; memset(d->output_buf, 0, sizeof(d->output_buf)); d->dir = 0; d->int_enable = 0; d->ack = 0; d->tip = 0; } /* * adb_process_cmd(): * * This function should be called whenever a complete ADB command has been * received. */ static void adb_process_cmd(struct cpu *cpu, struct adb_data *d) { int i, reg, dev; debug("[ adb: COMMAND:"); for (i=0; icur_output_offset; i++) debug(" %02x", d->output_buf[i]); debug(" ]\n"); if (d->cur_output_offset < 2) { fatal("[ adb: WEIRD output length: %i ]\n", d->cur_output_offset); exit(1); } switch (d->output_buf[0]) { case 0: /* ADB commands: */ if (d->output_buf[1] == 0x00) { /* Reset. */ return; } if ((d->output_buf[1] & 0x0c) == 0x0c) { /* ADBTALK: */ reg = d->output_buf[1] & 3; dev = d->output_buf[1] >> 4; fatal("dev=%i reg=%i\n", dev, reg); /* Default values: nothing here */ d->input_buf[0] = 0x00; d->input_buf[1] = 0x00; d->input_buf[2] = d->output_buf[1]; d->cur_input_length = 3; if (dev == d->kbd_dev) { /* Keyboard. */ d->input_buf[0] = 0x01; d->input_buf[1] = 0x01; d->input_buf[2] = d->output_buf[1]; d->input_buf[3] = 0x01; d->input_buf[4] = 0x01; d->cur_input_length = 5; } } else if ((d->output_buf[1] & 0x0c) == 0x08) { int new_dev_pos = d->output_buf[2] & 15; /* ADBLISTEN: */ if ((d->output_buf[1] >> 4) != d->kbd_dev) { fatal("[ adb: ADBLISTEN not to kbd ]\n"); exit(1); } if (d->output_buf[3] != 0xfe || (d->output_buf[2] & 0xf0) != 0x60) { fatal("[ adb: unknown ADBLISTEN ]\n"); exit(1); } /* Move device. */ d->kbd_dev = new_dev_pos; } else { fatal("[ adb: unknown ADB command? ]\n"); exit(1); } break; case 1: /* PRAM/RTC: */ if (d->cur_output_offset == 3 && d->output_buf[1] == 0x01 && d->output_buf[2] == 0x01) { /* Autopoll: */ d->input_buf[0] = 0x00; d->input_buf[1] = 0x00; d->input_buf[2] = d->output_buf[1]; d->cur_input_length = 3; } else if (d->cur_output_offset == 2 && d->output_buf[1] == 0x03) { /* Read RTC date/time: */ struct timeval tv; gettimeofday(&tv, NULL); d->input_buf[0] = tv.tv_sec >> 24; d->input_buf[1] = tv.tv_sec >> 16; d->input_buf[2] = tv.tv_sec >> 8; d->input_buf[3] = tv.tv_sec; d->cur_input_length = 4; } else if (d->cur_output_offset == 2 && d->output_buf[1] == 0x11) { /* Reboot. */ fatal("[ adb: reboot. TODO: make this nicer ]\n"); exit(1); } else { fatal("[ adb: UNIMPLEMENTED PRAM/RTC command ]\n"); exit(1); } break; default:fatal("[ adb: UNKNOWN command type 0x%02x ]\n", d->output_buf[0]); exit(1); } d->reg[vBufB >> VIA_REG_SHIFT] &= ~BUFB_nINTR; d->reg[vIFR >> VIA_REG_SHIFT] |= IFR_ANY | IFR_SR; d->reg[vSR >> VIA_REG_SHIFT] = 0x00; /* Dummy. */ } /* * adb_transfer(): * * This function should be called whenever a new transfer is started, a * transfer is finished, or when the next byte in a transfer should be * sent/received. */ static void adb_transfer(struct cpu *cpu, struct adb_data *d, int state_change) { unsigned char c = 0x00; if (state_change) { if (d->tip == 0) { debug("[ adb: transfer #%lli done ]\n", (long long)d->transfer_nr); if (d->cur_output_offset > 0) adb_process_cmd(cpu, d); d->transfer_nr ++; return; } debug("[ adb: starting transfer #%lli: %s ]\n", (long long) d->transfer_nr, d->dir == DIR_INPUT? "INPUT" : "OUTPUT"); d->cur_input_offset = d->cur_output_offset = 0; } debug("[ adb: transfer #%lli: ", (long long)d->transfer_nr); switch (d->dir) { case DIR_INPUT: if (d->cur_input_offset >= d->cur_input_length) fatal("[ adb: INPUT beyond end of data? ]\n"); else c = d->input_buf[d->cur_input_offset ++]; debug("input 0x%02x", c); d->reg[vSR >> VIA_REG_SHIFT] = c; d->reg[vIFR >> VIA_REG_SHIFT] |= IFR_ANY | IFR_SR; if (d->cur_input_offset >= d->cur_input_length) d->reg[vBufB >> VIA_REG_SHIFT] |= BUFB_nINTR; break; case DIR_OUTPUT: c = d->reg[vSR >> VIA_REG_SHIFT]; debug("output 0x%02x", c); d->reg[vIFR >> VIA_REG_SHIFT] |= IFR_ANY | IFR_SR; d->reg[vBufB >> VIA_REG_SHIFT] |= BUFB_nINTR; d->output_buf[d->cur_output_offset ++] = c; break; } debug(" ]\n"); } DEVICE_ACCESS(adb) { uint64_t idata = 0, odata = 0; struct adb_data *d = (struct adb_data *) extra; // uint8_t old = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); #ifdef ADB_DEBUG if ((relative_addr & ((1 << VIA_REG_SHIFT) - 1)) != 0) fatal("[ adb: %s non-via register? offset 0x%x ]\n", writeflag == MEM_READ? "read from" : "write to", (int)relative_addr); else if (writeflag == MEM_READ) fatal("[ adb: read from %s: 0x%02x ]\n", via_regname[relative_addr >> VIA_REG_SHIFT], (int)d->reg[relative_addr >> VIA_REG_SHIFT]); else fatal("[ adb: write to %s: 0x%02x ]\n", via_regname[ relative_addr >> VIA_REG_SHIFT], (int)idata); #endif if (writeflag == MEM_READ) odata = d->reg[relative_addr >> VIA_REG_SHIFT]; else { // old = d->reg[relative_addr >> VIA_REG_SHIFT]; switch (relative_addr) { case vIFR: /* * vIFR is write-ones-to-clear, and the highest bit * (IFR_ANY) is set if any of the lower bits are set. */ d->reg[relative_addr >> VIA_REG_SHIFT] &= ~(idata|0x80); if (d->reg[relative_addr >> VIA_REG_SHIFT] & 0x7f) d->reg[relative_addr >> VIA_REG_SHIFT] |= 0x80; break; default: d->reg[relative_addr >> VIA_REG_SHIFT] = idata; } } switch (relative_addr) { case vBufB: /* OK */ if (writeflag == MEM_WRITE) { int old_tip = d->tip; int old_ack = d->ack; if (idata & BUFB_nINTR) idata &= ~BUFB_nINTR; d->ack = 0; if (idata & BUFB_ACK) { idata &= ~BUFB_ACK; d->ack = 1; } d->tip = 1; if (idata & BUFB_nTIP) { idata &= ~BUFB_nTIP; d->tip = 0; } if (idata != 0) fatal("[ adb: WARNING! UNIMPLEMENTED bits in" " vBufB: 0x%02x ]\n", (int)idata); if (old_tip != d->tip) adb_transfer(cpu, d, 1); else if (old_ack != d->ack) adb_transfer(cpu, d, 0); } break; case vDirB: break; case vSR: /* Clear the SR interrupt flag, if set: */ d->reg[vIFR >> VIA_REG_SHIFT] &= ~IFR_SR; break; case vACR: /* OK */ if (writeflag == MEM_WRITE) { if (idata & ACR_SR_OUT) d->dir = DIR_OUTPUT; else d->dir = DIR_INPUT; } break; case vIFR: /* OK */ break; case vIER: /* OK */ if (writeflag == MEM_WRITE) { d->int_enable = idata & 0x80? 1 : 0; if (idata != 0x04 && idata != 0x84) fatal("[ adb: WARNING! vIER value 0x%x is" " UNKNOWN ]\n", (int)idata); } break; default:if ((relative_addr & ((1 << VIA_REG_SHIFT) - 1)) != 0) fatal("[ adb: %s non-via register? offset 0x%x ]\n", writeflag == MEM_READ? "read from" : "write to", (int)relative_addr); else if (writeflag == MEM_READ) fatal("[ adb: READ from UNIMPLEMENTED %s ]\n", via_regname[relative_addr >> VIA_REG_SHIFT]); else fatal("[ adb: WRITE to UNIMPLEMENTED %s: 0x%x ]\n", via_regname[relative_addr >> VIA_REG_SHIFT], (int)idata); exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(adb) { struct adb_data *d; CHECK_ALLOCATION(d = (struct adb_data *) malloc(sizeof(struct adb_data))); memset(d, 0, sizeof(struct adb_data)); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); adb_reset(d); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_ADB_LENGTH, dev_adb_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_adb_tick, d, TICK_SHIFT); return 1; } gxemul-0.6.1/src/devices/dev_i80321.cc000644 001750 001750 00000032717 13402411502 017443 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Intel i80321 (ARM) core functionality * * o) Interrupt controller * o) Timer * o) PCI controller * o) Memory controller * o) I2C * * TODO: * o) More or less everything. * o) This is hardcoded for little endian emulation. */ #include #include #include #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "timer.h" #include "thirdparty/i80321reg.h" #include "thirdparty/iopi2creg.h" #define TICK_SHIFT 15 #define DEV_I80321_LENGTH VERDE_PMMR_SIZE struct i80321_data { /* Interrupt Controller */ struct interrupt irq; uint32_t *status; /* Note: these point to i80321_isrc */ uint32_t *enable; /* and i80321_inten in the CPU! */ /* Timer: */ struct timer *timer; double hz; int pending_tmr0_interrupts; /* PCI Controller: */ uint32_t pci_addr; struct pci_data *pci_bus; /* Memory Controller: */ uint32_t mcu_reg[0x100 / sizeof(uint32_t)]; /* I2C Controller: */ uint32_t i2c_reg[VERDE_I2C_SIZE / sizeof(uint32_t)]; }; static void i80321_assert(struct i80321_data *d, uint32_t linemask) { *d->status |= linemask; if (*d->status & *d->enable) INTERRUPT_ASSERT(d->irq); } static void i80321_deassert(struct i80321_data *d, uint32_t linemask) { *d->status &= ~linemask; if (!(*d->status & *d->enable)) INTERRUPT_DEASSERT(d->irq); } /* * i80321_interrupt_assert(): * i80321_interrupt_deassert(): * * Called whenever an i80321 interrupt is asserted/deasserted. */ void i80321_interrupt_assert(struct interrupt *interrupt) { i80321_assert((struct i80321_data *)interrupt->extra, interrupt->line); } void i80321_interrupt_deassert(struct interrupt *interrupt) { struct i80321_data *d = (struct i80321_data *) interrupt->extra; /* Ack. timer interrupts: */ if (interrupt->line == 1 << 9 && d->pending_tmr0_interrupts > 0) d->pending_tmr0_interrupts --; i80321_deassert(d, interrupt->line); } /* TMR0 ticks, called d->hz times per second. */ static void tmr0_tick(struct timer *t, void *extra) { struct i80321_data *d = (struct i80321_data *) extra; d->pending_tmr0_interrupts ++; } DEVICE_TICK(i80321) { struct i80321_data *d = (struct i80321_data *) extra; if (cpu->cd.arm.tmr0 & TMRx_ENABLE && d->pending_tmr0_interrupts > 0) { i80321_assert(d, 1 << 9); cpu->cd.arm.tisr |= TISR_TMR0; } else { i80321_deassert(d, 1 << 9); cpu->cd.arm.tisr &= ~TISR_TMR0; } } DEVICE_ACCESS(i80321) { struct i80321_data *d = (struct i80321_data *) extra; uint64_t idata = 0, odata = 0; const char *n = NULL; int bus, dev, func, reg; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* PCI configuration space: */ if (relative_addr >= 0x100 && relative_addr < 0x140) { /* TODO */ goto ret; } /* MCU registers: */ if (relative_addr >= VERDE_MCU_BASE && relative_addr < VERDE_MCU_BASE + VERDE_MCU_SIZE) { int regnr = (relative_addr - VERDE_MCU_BASE) / sizeof(uint32_t); if (writeflag == MEM_WRITE) d->mcu_reg[regnr] = idata; else odata = d->mcu_reg[regnr]; } /* I2C registers: */ if (relative_addr >= VERDE_I2C_BASE && relative_addr < VERDE_I2C_BASE + VERDE_I2C_SIZE) { int regnr = (relative_addr - VERDE_I2C_BASE) / sizeof(uint32_t); if (writeflag == MEM_WRITE) d->i2c_reg[regnr] = idata; else odata = d->i2c_reg[regnr]; } switch (relative_addr) { /* Address Translation Unit: */ case VERDE_ATU_BASE + ATU_IALR0: case VERDE_ATU_BASE + ATU_IATVR0: case VERDE_ATU_BASE + ATU_IALR1: case VERDE_ATU_BASE + ATU_IALR2: case VERDE_ATU_BASE + ATU_IATVR2: case VERDE_ATU_BASE + ATU_OIOWTVR: case VERDE_ATU_BASE + ATU_OMWTVR0: case VERDE_ATU_BASE + ATU_OUMWTVR0: case VERDE_ATU_BASE + ATU_OMWTVR1: case VERDE_ATU_BASE + ATU_OUMWTVR1: /* Ignoring these for now. TODO */ break; case VERDE_ATU_BASE + ATU_ATUCR: /* ATU configuration register; ignored for now. TODO */ break; case VERDE_ATU_BASE + ATU_PCSR: /* TODO: Temporary hack to allow NetBSD/evbarm to reboot itself. Should be rewritten as soon as possible! */ if (writeflag == MEM_WRITE && idata == 0x30) { int j; for (j=0; jmachine->ncpus; j++) cpu->machine->cpus[j]->running = 0; cpu->machine->exit_without_entering_debugger = 1; } break; case VERDE_ATU_BASE + ATU_ATUIMR: case VERDE_ATU_BASE + ATU_IABAR3: case VERDE_ATU_BASE + ATU_IAUBAR3: case VERDE_ATU_BASE + ATU_IALR3: case VERDE_ATU_BASE + ATU_IATVR3: /* Ignoring these for now. TODO */ break; case VERDE_ATU_BASE + ATU_OCCAR: /* PCI address */ if (writeflag == MEM_WRITE) { d->pci_addr = idata; bus_pci_decompose_1(idata, &bus, &dev, &func, ®); bus = 0; /* NOTE */ bus_pci_setaddr(cpu, d->pci_bus, bus, dev, func, reg); } else { odata = d->pci_addr; } break; case VERDE_ATU_BASE + ATU_OCCDR: case VERDE_ATU_BASE + ATU_OCCDR + 1: case VERDE_ATU_BASE + ATU_OCCDR + 2: case VERDE_ATU_BASE + ATU_OCCDR + 3: /* PCI data */ if (writeflag == MEM_READ) { uint64_t tmp; bus_pci_data_access(cpu, d->pci_bus, &tmp, sizeof(uint32_t), MEM_READ); switch (relative_addr) { case VERDE_ATU_BASE + ATU_OCCDR + 1: odata = tmp >> 8; break; case VERDE_ATU_BASE + ATU_OCCDR + 2: odata = tmp >> 16; break; case VERDE_ATU_BASE + ATU_OCCDR + 3: odata = tmp >> 24; break; default:odata = tmp; } } else { uint64_t tmp; unsigned int i; int r = relative_addr - (VERDE_ATU_BASE + ATU_OCCDR); bus_pci_data_access(cpu, d->pci_bus, &tmp, sizeof(uint32_t), MEM_READ); for (i=0; i> (i*8); tmp &= ~(0xff << ((r+i)*8)); tmp |= b << ((r+i)*8); } tmp &= 0xffffffff; /* needed because << is 32-bit */ bus_pci_data_access(cpu, d->pci_bus, &tmp, sizeof(uint32_t), MEM_WRITE); } break; case VERDE_ATU_BASE + ATU_PCIXSR: odata = 0; /* TODO */ break; /* Memory Controller Unit: */ case VERDE_MCU_BASE + MCU_SDIR: n = "MCU_SDIR (DDR SDRAM Init Register)"; break; case VERDE_MCU_BASE + MCU_SDCR: n = "MCU_SDCR (DDR SDRAM Control Register)"; break; case VERDE_MCU_BASE + MCU_SDBR: n = "MCU_SDBR (SDRAM Base Register)"; break; case VERDE_MCU_BASE + MCU_SBR0: n = "MCU_SBR0 (SDRAM Boundary 0)"; break; case VERDE_MCU_BASE + MCU_SBR1: n = "MCU_SBR1 (SDRAM Boundary 1)"; break; case VERDE_MCU_BASE + MCU_ECCR: n = "MCU_ECCR (ECC Control Register)"; break; case VERDE_MCU_BASE + MCU_RFR: n = "MCU_RFR (Refresh Frequency Register)"; break; case VERDE_MCU_BASE + MCU_DBUDSR: n = "MCU_DBUDSR (Data Bus Pull-up Drive Strength)"; break; case VERDE_MCU_BASE + MCU_DBDDSR: n = "MCU_DBDDSR (Data Bus Pull-down Drive Strength)"; break; case VERDE_MCU_BASE + MCU_CUDSR: n = "MCU_CUDSR (Clock Pull-up Drive Strength)"; break; case VERDE_MCU_BASE + MCU_CDDSR: n = "MCU_CDDSR (Clock Pull-down Drive Strength)"; break; case VERDE_MCU_BASE + MCU_CEUDSR: n = "MCU_CEUDSR (Clock En Pull-up Drive Strength)"; break; case VERDE_MCU_BASE + MCU_CEDDSR: n = "MCU_CEDDSR (Clock En Pull-down Drive Strength)"; break; case VERDE_MCU_BASE + MCU_CSUDSR: n = "MCU_CSUDSR (Chip Sel Pull-up Drive Strength)"; break; case VERDE_MCU_BASE + MCU_CSDDSR: n = "MCU_CSDDSR (Chip Sel Pull-down Drive Strength)"; break; case VERDE_MCU_BASE + MCU_REUDSR: n = "MCU_REUDSR (Rx En Pull-up Drive Strength)"; break; case VERDE_MCU_BASE + MCU_REDDSR: n = "MCU_REDDSR (Rx En Pull-down Drive Strength)"; break; case VERDE_MCU_BASE + MCU_ABUDSR: n = "MCU_ABUDSR (Addr Bus Pull-up Drive Strength)"; break; case VERDE_MCU_BASE + MCU_ABDDSR: n = "MCU_ABDDSR (Addr Bus Pull-down Drive Strength)"; break; /* Peripheral Bus Interface Unit */ case VERDE_PBIU_BASE + PBIU_PBCR: n = "PBIU_PBCR (PBIU Control Register)"; break; case VERDE_PBIU_BASE + PBIU_PBBAR0: n = "PBIU_PBBAR0 (PBIU Base Address Register 0)"; break; case VERDE_PBIU_BASE + PBIU_PBLR0: n = "PBIU_PBLR0 (PBIU Limit Register 0)"; break; case VERDE_PBIU_BASE + PBIU_PBBAR1: n = "PBIU_PBBAR1 (PBIU Base Address Register 1)"; break; case VERDE_PBIU_BASE + PBIU_PBLR1: n = "PBIU_PBLR1 (PBIU Limit Register 1)"; break; case VERDE_PBIU_BASE + PBIU_PBBAR2: n = "PBIU_PBBAR2 (PBIU Base Address Register 2)"; break; case VERDE_PBIU_BASE + PBIU_PBLR2: n = "PBIU_PBLR2 (PBIU Limit Register 2)"; break; /* TODO: */ case 0x7cc: n = "0x7cc_TODO"; break; case VERDE_I2C_BASE0 + IIC_ICR: n = "I2C 0, IIC_ICR (control register)"; break; case VERDE_I2C_BASE0 + IIC_ISR: n = "I2C 0, IIC_ISR (status register)"; break; case VERDE_I2C_BASE0 + IIC_ISAR: n = "I2C 0, IIC_ISAR (slave address register)"; break; case VERDE_I2C_BASE0 + IIC_IDBR: n = "I2C 0, IIC_IDBR (data buffer register)"; break; case VERDE_I2C_BASE1 + IIC_ICR: n = "I2C 1, IIC_ICR (control register)"; break; case VERDE_I2C_BASE1 + IIC_ISR: n = "I2C 1, IIC_ISR (status register)"; odata = IIC_ISR_ITE; /* IDBR Tx empty */ odata |= IIC_ISR_IRF; /* IDBR Rx full */ break; case VERDE_I2C_BASE1 + IIC_ISAR: n = "I2C 1, IIC_ISAR (slave address register)"; break; case VERDE_I2C_BASE1 + IIC_IDBR: n = "I2C 1, IIC_IDBR (data buffer register)"; odata = 7; /* TODO */ break; default:if (writeflag == MEM_READ) { fatal("[ i80321: read from 0x%x ]\n", (int)relative_addr); } else { fatal("[ i80321: write to 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)idata); } exit(1); } if (n != NULL) { if (writeflag == MEM_READ) { debug("[ i80321: read from %s: 0x%llx ]\n", n, (long long)idata); } else { debug("[ i80321: write to %s: 0x%llx ]\n", n, (long long)idata); } } ret: if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(i80321) { struct i80321_data *d; uint32_t memsize = devinit->machine->physical_ram_in_mb * 1048576; uint32_t base; char tmpstr[300]; struct cpu *cpu = devinit->machine->cpus[devinit-> machine->bootstrap_cpu]; int i; CHECK_ALLOCATION(d = (struct i80321_data *) malloc(sizeof(struct i80321_data))); memset(d, 0, sizeof(struct i80321_data)); /* Connect to the CPU interrupt pin: */ INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); /* Register 32 i80321 interrupts: */ for (i=0; i<32; i++) { struct interrupt templ; char tmpstr2[300]; snprintf(tmpstr2, sizeof(tmpstr2), "%s.i80321.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = 1 << i; templ.name = tmpstr2; templ.extra = d; templ.interrupt_assert = i80321_interrupt_assert; templ.interrupt_deassert = i80321_interrupt_deassert; interrupt_handler_register(&templ); /* * Connect the CPU's TMR0 and TMR1 interrupts to these * i80321 timer interrupts (nr 9 and 10): */ if (i == 9) INTERRUPT_CONNECT(tmpstr2, cpu->cd.arm.tmr0_irq); if (i == 10) INTERRUPT_CONNECT(tmpstr2, cpu->cd.arm.tmr1_irq); } d->status = &cpu->cd.arm.i80321_isrc; d->enable = &cpu->cd.arm.i80321_inten; /* TODO: base = 0 on Iyonix? */ d->mcu_reg[MCU_SDBR / sizeof(uint32_t)] = base = 0xa0000000; d->mcu_reg[MCU_SBR0 / sizeof(uint32_t)] = (base + memsize) >> 25; d->mcu_reg[MCU_SBR1 / sizeof(uint32_t)] = (base + memsize) >> 25; snprintf(tmpstr, sizeof(tmpstr), "%s.i80321", devinit->interrupt_path); d->pci_bus = bus_pci_init(devinit->machine, tmpstr /* pciirq */, 0x90000000 /* TODO: pci_io_offset */, 0x90010000 /* TODO: pci_mem_offset */, 0xffff0000 /* TODO: pci_portbase */, 0x00000000 /* TODO: pci_membase */, tmpstr /* pci_irqbase */, 0x90000000 /* TODO: isa_portbase */, 0x90010000 /* TODO: isa_membase */, "TODO: isa_irqbase" /* TODO: isa_irqbase */); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_I80321_LENGTH, dev_i80321_access, d, DM_DEFAULT, NULL); /* TODO: Don't hardcode to 100 Hz! */ d->hz = 100; d->timer = timer_add(d->hz, tmr0_tick, d); machine_add_tickfunction(devinit->machine, dev_i80321_tick, d, TICK_SHIFT); devinit->return_ptr = d->pci_bus; return 1; } gxemul-0.6.1/src/devices/autodev_middle.cc000644 001750 001750 00000000202 13402411502 020724 0ustar00debugdebug000000 000000 /* * autodev_init(): */ void autodev_init(void) { /* printf("autodev_init()\n"); */ /* autodev_middle.c ends here. */ gxemul-0.6.1/src/devices/lk201.cc000644 001750 001750 00000025437 13402411502 016611 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: LK201 keyboard and mouse, used by the dc7085 and scc controllers */ #include #include #include #include "console.h" #include "devices.h" #include "machine.h" #include "misc.h" #include "thirdparty/dc7085.h" /* for port names */ #include "thirdparty/lk201.h" // #define debug fatal /* * lk201_convert_ascii_to_keybcode(): * * Converts ascii console input to LK201 keyboard scan codes, and adds * those scancodes using the add_to_rx_queue() function. */ void lk201_convert_ascii_to_keybcode(struct lk201_data *d, unsigned char ch) { int i, found=-1, shifted = 0, controlled = 0; if (d->keyb_buf_pos > 0 && d->keyb_buf_pos < (int)sizeof(d->keyb_buf)) { /* Escape sequence: */ d->keyb_buf[d->keyb_buf_pos] = ch; d->keyb_buf_pos ++; if (d->keyb_buf_pos == 2) { if (ch == '[') return; d->keyb_buf_pos = 0; /* not esc+[, output as normal key */ } else { /* Inside an esc+[ sequence */ switch (ch) { case 'A': found = 0xaa; /* Up */ break; case 'B': found = 0xa9; /* Down */ break; case 'C': found = 0xa8; /* Right */ break; case 'D': found = 0xa7; /* Left */ break; /* TODO: pageup, pagedown, ... */ default: ; } d->keyb_buf_pos = 0; } } else d->keyb_buf_pos = 0; if (found == -1) { switch (ch) { case '\b': found = 0xbc; break; case '\n': case '\r': found = 0xbd; break; case '\t': found = 0xbe; break; case 27: /* esc */ d->keyb_buf[0] = 27; d->keyb_buf_pos = 1; return; default: if (ch >= 1 && ch <= 26) { ch = 'a' + ch - 1; controlled = 1; } shifted = 0; for (i=0; i<256; i++) { /* Skip numeric digits, so that the normal digits are used instead. */ if (i >= 0x92 && i<=0xa0) continue; if (unshiftedAscii[i] == ch) { found = i; break; } } if (found == -1) { /* unshift ch: */ if (ch >= 'A' && ch <= 'Z') ch = ch + ('a' - 'A'); for (i=0; i<256; i++) if (shiftedAscii[i] == ch) { found = i; shifted = 1; break; } } } } if (!shifted) d->add_to_rx_queue(d->add_data, KEY_UP, DCKBD_PORT); else { d->add_to_rx_queue(d->add_data, KEY_UP, DCKBD_PORT); d->add_to_rx_queue(d->add_data, KEY_SHIFT, DCKBD_PORT); } if (controlled) d->add_to_rx_queue(d->add_data, KEY_CONTROL, DCKBD_PORT); /* Send the actual scan code: */ d->add_to_rx_queue(d->add_data, found, DCKBD_PORT); /* Release the key: */ d->add_to_rx_queue(d->add_data, KEY_UP, DCKBD_PORT); } /* * lk201_send_mouse_update_sequence(): * * mouse_x, _y, _buttons contains the coordinates on the host's display, the * "goal" of where we want to move. * * d->mouse_x, _y, _buttons contain the last values transmitted to the * emulated machine. */ static int lk201_send_mouse_update_sequence(struct lk201_data *d, int mouse_x, int mouse_y, int mouse_buttons, int mouse_fb_nr) { int xsign, xdelta, ysign, ydelta, m; xdelta = mouse_x - d->mouse_x; ydelta = mouse_y - d->mouse_y; /* If no change, then don't send any update! */ if (xdelta == 0 && ydelta == 0 && d->mouse_buttons == mouse_buttons) return 0; m = 20; if (xdelta > m) xdelta = m; if (xdelta < -m) xdelta = -m; if (ydelta > m) ydelta = m; if (ydelta < -m) ydelta = -m; d->mouse_x += xdelta; d->mouse_y += ydelta; d->mouse_buttons = mouse_buttons; /* * TODO: Update d->mouse_framebuffer_nr some way! */ xsign = xdelta < 0? 1 : 0; ysign = ydelta < 0? 1 : 0; switch (d->mouse_mode) { case 0: /* Do nothing (before the mouse is initialized) */ return 0; case MOUSE_INCREMENTAL: if (xdelta < 0) xdelta = -xdelta; if (ydelta < 0) ydelta = -ydelta; /* Reverse sign of x: (this is needed for some reason) */ xsign ^= 1; d->add_to_rx_queue(d->add_data, MOUSE_START_FRAME + MOUSE_X_SIGN*xsign + MOUSE_Y_SIGN*ysign + (mouse_buttons & 7), DCMOUSE_PORT); d->add_to_rx_queue(d->add_data, xdelta, DCMOUSE_PORT); d->add_to_rx_queue(d->add_data, ydelta, DCMOUSE_PORT); break; default: /* TODO: prompt mode and perhaps more stuff */ fatal("[ lk201: mouse mode 0x%02x unknown: TODO ]\n", d->mouse_mode); exit(1); } return 1; } /* * lk201_tick(): * * This function should be called "every now and then". * If a key is available from the keyboard, add it to the rx queue. * If other bits are set, an interrupt might need to be caused. */ void lk201_tick(struct machine *machine, struct lk201_data *d) { int mouse_x, mouse_y, mouse_buttons, mouse_fb_nr; if (console_charavail(d->console_handle)) { unsigned char ch = console_readchar(d->console_handle); if (d->use_fb) lk201_convert_ascii_to_keybcode(d, ch); else { /* * This is ugly, but necessary because different * machines seem to use different ports for their * serial console: * * DEC MIPSMATE 5100 uses the keyboard port. * DECstation 3100 (PMAX) and 5000/2000 (3MAX) use * the printer port. * Others seem to use the comm port. */ if (machine->machine_type == MACHINE_PMAX) { switch (machine->machine_subtype) { case MACHINE_DEC_MIPSMATE_5100: d->add_to_rx_queue(d->add_data, ch, DCKBD_PORT); break; case MACHINE_DEC_PMAX_3100: case MACHINE_DEC_3MAX_5000: d->add_to_rx_queue(d->add_data, ch, DCPRINTER_PORT); break; default: d->add_to_rx_queue(d->add_data, ch, DCCOMM_PORT); } } else { d->add_to_rx_queue(d->add_data, ch, DCCOMM_PORT); } } } /* Don't do mouse updates if we're running in serial console mode: */ if (!d->use_fb) return; console_getmouse(&mouse_x, &mouse_y, &mouse_buttons, &mouse_fb_nr); lk201_send_mouse_update_sequence(d, mouse_x, mouse_y, mouse_buttons, mouse_fb_nr); } void lk201_tx_data(struct lk201_data *d, int port, int idata) { switch (port) { case DCKBD_PORT: /* port 0 */ if (!d->use_fb) { /* Simply print the character to stdout: */ console_putchar(d->console_handle, idata); } else { debug("[ lk201: writing data to KBD: 0x%02x ]\n", idata); switch (idata) { case LK_LED_DISABLE: /* 0x11 */ break; case LK_LED_ENABLE: /* 0x13 */ break; case LK_BELL_ENABLE: /* 0x23 */ break; case 0x41: d->add_to_rx_queue(d->add_data, 0xa, DCKBD_PORT); d->add_to_rx_queue(d->add_data, 0xb, DCKBD_PORT); d->add_to_rx_queue(d->add_data, 0xc, DCKBD_PORT); d->add_to_rx_queue(d->add_data, 0xd, DCKBD_PORT); break; case LED_1: case LED_2: break; case LED_3: break; case LED_4: break; case LK_KBD_ENABLE: /* 0x8b */ break; case LED_ALL: /* 0x8f */ break; case LK_RING_BELL: /* 0xa7 */ break; case 0xab: /* Get Keyboard ID: */ /* * First byte: * 1 = LK201 * 2 = LK401 * 3 = LK443 * 4 = LK421 * * TODO: What about the second byte? 0x22 or * 0x00? */ d->add_to_rx_queue(d->add_data, 0x01, DCKBD_PORT); d->add_to_rx_queue(d->add_data, 0x00, DCKBD_PORT); break; case LK_DEFAULTS: /* 0xd3 */ /* TODO? */ break; case 0xfd: /* Keyboard self-test: */ /* Suitable return values according to Mach/PMAX source code: */ d->add_to_rx_queue(d->add_data, 0x01, DCKBD_PORT); d->add_to_rx_queue(d->add_data, 0x00, DCKBD_PORT); d->add_to_rx_queue(d->add_data, 0x00, DCKBD_PORT); d->add_to_rx_queue(d->add_data, 0x00, DCKBD_PORT); break; default: debug("[ lk201: unimplemented keyboard control: 0x%x ]\n", idata); } } break; case DCMOUSE_PORT: /* port 1 */ debug("[ lk201: writing data to MOUSE: 0x%x ", idata); switch (idata) { case MOUSE_INCREMENTAL: d->mouse_mode = MOUSE_INCREMENTAL; break; case MOUSE_SELF_TEST: /* * Mouse self-test: * * TODO: Find out if this is correct. The lowest * four bits of the second byte should be * 0x2, according to NetBSD/pmax. But the * other bits and bytes? */ debug("(mouse self-test request)"); d->add_to_rx_queue(d->add_data, 0xa0 | d->mouse_revision, DCMOUSE_PORT); d->add_to_rx_queue(d->add_data, 0x02, DCMOUSE_PORT); d->add_to_rx_queue(d->add_data, 0x00, DCMOUSE_PORT); d->add_to_rx_queue(d->add_data, 0x00, DCMOUSE_PORT); break; default: debug("UNKNOWN byte; TODO"); } debug(" ]\n"); break; case DCCOMM_PORT: /* port 2 */ case DCPRINTER_PORT: /* port 3 */ /* Simply print the character to stdout: */ console_putchar(d->console_handle, idata); } } /* * lk201_init(): * * Initialize lk201 keyboard/mouse settings. */ void lk201_init(struct lk201_data *d, int use_fb, void (*add_to_rx_queue)(void *,int,int), int console_handle, void *add_data) { memset(d, 0, sizeof(struct lk201_data)); d->add_to_rx_queue = add_to_rx_queue; d->add_data = add_data; d->use_fb = use_fb; d->mouse_mode = 0; d->mouse_revision = 0; /* 0..15 */ d->console_handle = console_handle; /* * Power up self-test result, as per * https://www.netbsd.org/docs/Hardware/Machines/DEC/lk201.html#power_up */ if (d->use_fb) { d->add_to_rx_queue(d->add_data, 0x01, DCKBD_PORT); d->add_to_rx_queue(d->add_data, 0x00, DCKBD_PORT); d->add_to_rx_queue(d->add_data, 0x00, DCKBD_PORT); d->add_to_rx_queue(d->add_data, 0x00, DCKBD_PORT); } } gxemul-0.6.1/src/devices/dev_ram.cc000644 001750 001750 00000014325 13402411502 017367 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: A generic RAM (memory) device * * Note: This device can also be used to mirror/alias another part of RAM. */ #include #include #include #include #include #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" struct ram_data { uint64_t baseaddress; const char* name; bool trace; int mode; uint64_t otheraddress; /* If mode = DEV_RAM_MIRROR: */ uint64_t offset; /* If mode = DEV_RAM_RAM: */ unsigned char *data; uint64_t length; }; DEVICE_ACCESS(ram) { struct ram_data *d = (struct ram_data *) extra; if (cpu->running && d->trace && writeflag == MEM_WRITE) { fatal("[ %s: write %i byte%s from 0x%x:", d->name, (int)len, len==1? "":"s", (int)relative_addr); for (size_t i=0; imode) { case DEV_RAM_MIRROR: /* TODO: how about caches? */ { int result = cpu->memory_rw(cpu, mem, d->otheraddress + relative_addr, data, len, writeflag, PHYSICAL); if (cpu->running && d->trace) { fatal("[ %s: read %i byte%s from 0x%x:", d->name, (int)len, len==1? "":"s", (int)relative_addr); for (size_t i=0; idata[relative_addr], data, len); /* Invalidate any code translations on a write: */ if (cpu->invalidate_code_translation != NULL) { cpu->invalidate_code_translation( cpu, d->baseaddress + relative_addr, INVALIDATE_PADDR); } } else { memcpy(data, &d->data[relative_addr], len); if (cpu->running && d->trace) { fatal("[ %s: read %i byte%s from 0x%x:", d->name, (int)len, len==1? "":"s", (int)relative_addr); for (size_t i=0; imode); exit(1); } return 1; } /* * dev_ram_init(): * * Initializes a RAM or mirror device. Things get a bit complicated because * of dyntrans (i.e. mirrored memory ranges should be entered into the * translation arrays just as normal memory and other devices are). */ void dev_ram_init(struct machine *machine, uint64_t baseaddr, uint64_t length, int mode, uint64_t otheraddress, const char* name) { struct ram_data *d; int flags = DM_DEFAULT, points_to_ram = 1; CHECK_ALLOCATION(d = (struct ram_data *) malloc(sizeof(struct ram_data))); memset(d, 0, sizeof(struct ram_data)); d->name = strdup((name == NULL) ? "ram" : name); if (mode & DEV_RAM_MIGHT_POINT_TO_DEVICES) { mode &= ~DEV_RAM_MIGHT_POINT_TO_DEVICES; points_to_ram = 0; } if (mode & DEV_RAM_TRACE_ALL_ACCESSES) { mode &= ~DEV_RAM_TRACE_ALL_ACCESSES; d->trace = true; } d->mode = mode; d->baseaddress = baseaddr; d->otheraddress = otheraddress; switch (d->mode) { case DEV_RAM_MIRROR: /* * Calculate the amount that the mirror memory is offset from * the real (physical) memory. This is used in src/memory_rw.c * with dyntrans accesses if DM_EMULATED_RAM is set. */ d->offset = baseaddr - otheraddress; d->name = (string(d->name) + " [mirror]").c_str(); /* Aligned RAM? Then it works with dyntrans. */ if (points_to_ram && (baseaddr & (machine->arch_pagesize-1)) == 0 && (otheraddress & (machine->arch_pagesize - 1)) == 0 && (length & (machine->arch_pagesize - 1)) == 0 && !d->trace) flags |= DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK | DM_EMULATED_RAM; memory_device_register(machine->memory, d->name, baseaddr, length, dev_ram_access, d, flags | DM_READS_HAVE_NO_SIDE_EFFECTS, (unsigned char*) (void *) &d->offset); break; case DEV_RAM_RAM: /* * Allocate zero-filled RAM using mmap(). If mmap() failed, * try malloc(), but then memset() must also be called, which * can be slow for large chunks of memory. */ d->length = length; d->data = (unsigned char *) mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (d->data == NULL) { CHECK_ALLOCATION(d->data = (unsigned char *) malloc(length)); memset(d->data, 0, length); } /* Aligned memory? Then it works with dyntrans. */ if ((baseaddr & (machine->arch_pagesize - 1)) == 0 && (length & (machine->arch_pagesize - 1)) == 0 && !d->trace) flags |= DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK; memory_device_register(machine->memory, d->name, baseaddr, d->length, dev_ram_access, d, flags | DM_READS_HAVE_NO_SIDE_EFFECTS, d->data); break; default: fatal("dev_ram_access(): %s: unknown mode %i\n", d->name, d->mode); exit(1); } } gxemul-0.6.1/src/devices/dev_sgi_gbe.cc000644 001750 001750 00000052565 13402411502 020217 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SGI "Graphics Back End", graphics controller + framebuffer * * Guesswork, based on how Linux, NetBSD, and OpenBSD use the graphics on * the SGI O2. Using NetBSD terminology (from crmfbreg.h): * * dev_sgi_re.cc: * 0x15001000 rendering engine (TLBs) * 0x15002000 drawing engine * 0x15003000 memory transfer engine * 0x15004000 status registers for drawing engine * * dev_sgi_gbe.cc: * 0x16000000 crm (or GBE) framebuffer control / video output * * According to https://www.linux-mips.org/wiki/GBE, the GBE is also used in * the SGI Visual Workstation. */ #include #include #include #include "console.h" #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/crmfbreg.h" /* Let's hope nothing is there already... */ #define FAKE_GBE_FB_ADDRESS 0x380000000 // #define GBE_DEBUG // #define debug fatal #define GBE_DEFAULT_XRES 1280 #define GBE_DEFAULT_YRES 1024 #define GBE_DEFAULT_BITDEPTH 8 struct sgi_gbe_data { // CRM / GBE registers: uint32_t ctrlstat; /* 0x00000 */ uint32_t dotclock; /* 0x00004 */ uint32_t i2c; /* 0x00008 */ uint32_t i2cfp; /* 0x00010 */ uint32_t freeze; /* and xy */ /* 0x10000 */ uint32_t y_intr01; /* 0x10020 */ uint32_t y_intr23; /* 0x10024 */ uint32_t ovr_tilesize; /* 0x20000 */ uint32_t ovr_control; /* 0x2000c */ uint32_t tilesize; /* 0x30000 */ uint32_t frm_control; /* 0x3000c */ uint32_t palette[32 * 256]; /* 0x50000 */ uint32_t cursor_pos; /* 0x70000 */ uint32_t cursor_control; /* 0x70004 */ uint32_t cursor_cmap0; /* 0x70008 */ uint32_t cursor_cmap1; /* 0x7000c */ uint32_t cursor_cmap2; /* 0x70010 */ uint32_t cursor_bitmap[64]; /* 0x78000 */ // Emulator's representation: int xres, yres; int width_in_tiles; int partial_pixels; int ovr_width_in_tiles; int ovr_partial_pixels; int bitdepth; int color_mode; int cmap_select; uint32_t selected_palette[256]; struct vfb_data *fb_data; }; void get_rgb(struct sgi_gbe_data *d, uint32_t color, uint8_t* r, uint8_t* g, uint8_t* b) { // TODO: Don't switch on color_mode. For overlays, this is always // 8-bit index mode! switch (d->color_mode) { case CRMFB_MODE_TYP_I8: color &= 0xff; *r = d->selected_palette[color] >> 24; *g = d->selected_palette[color] >> 16; *b = d->selected_palette[color] >> 8; break; case CRMFB_MODE_TYP_RG3B2: // Used by NetBSD console mode *r = 255 * ((color >> 5) & 7) / 7; *g = 255 * ((color >> 2) & 7) / 7; *b = (color & 3) * 85; break; case CRMFB_MODE_TYP_RGB8: // Used by NetBSD's X11 server *r = color >> 24; *g = color >> 16; *b = color >> 8; break; default:fatal("sgi gbe get_rgb(): unimplemented mode %i\n", d->color_mode); exit(1); } } void select_palette(struct sgi_gbe_data *d, int palette_nr) { memmove(&d->selected_palette[0], &d->palette[256 * palette_nr], 256 * sizeof(uint32_t)); } /* * dev_sgi_gbe_tick(): * * Every now and then, copy data from the framebuffer in normal ram * to the actual framebuffer (which will then redraw the window). * * NOTE: This is very slow, even slower than the normal emulated framebuffer, * which is already slow as it is. * * frm_control contains a pointer to an array of uint16_t. These numbers * (when shifted 16 bits to the left) are pointers to the tiles. Tiles are * 512x128 in 8-bit mode, 256x128 in 16-bit mode, and 128x128 in 32-bit mode. * * An exception is how Linux/O2 uses the framebuffer, in a "tweaked" mode * which resembles linear mode. This code attempts to support both. */ DEVICE_TICK(sgi_gbe) { struct sgi_gbe_data *d = (struct sgi_gbe_data *) extra; uint64_t tiletable; unsigned char buf[16384]; /* must be power of 2, at most 65536 */ int bytes_per_pixel = d->bitdepth / 8; int partial_pixels, width_in_tiles; if (!cpu->machine->x11_md.in_use) return; // If not frozen... if (!(d->freeze & 0x80000000)) { // ... check if the guest OS wants interrupts based on Y: if ((d->y_intr01 & CRMFB_INTR_0_MASK) != 0xfff000 || (d->y_intr01 & CRMFB_INTR_1_MASK) != 0xfff || (d->y_intr23 & CRMFB_INTR_2_MASK) != 0xfff000 || (d->y_intr23 & CRMFB_INTR_3_MASK) != 0xfff) { fatal("[ sgi_gbe: WARNING: Y interrupts not yet implemented. ]\n"); } } // printf("d->frm_control = %08x d->ovr_control = %08x\n", d->frm_control,d->ovr_control); // NetBSD's crmfbreg.h documents the tileptr as having a "9 bit shift", // but IRIX seems to put a value ending in 0x......80 there, and the // last part of that address seems to matter. // TODO: Double-check this with the real hardware. if (d->ovr_control & CRMFB_DMA_ENABLE) { tiletable = (d->ovr_control & 0xffffff80); bytes_per_pixel = 1; partial_pixels = d->ovr_partial_pixels; width_in_tiles = d->ovr_width_in_tiles; select_palette(d, 17); // TODO: is it always palette nr 17 for overlays? } else if (d->frm_control & CRMFB_DMA_ENABLE) { tiletable = (d->frm_control & 0xffffff80); partial_pixels = d->partial_pixels; width_in_tiles = d->width_in_tiles; select_palette(d, d->cmap_select); } else { return; } #ifdef GBE_DEBUG fatal("[ sgi_gbe: dev_sgi_gbe_tick(): tiletable = 0x%llx, bytes_per_pixel = %i ]\n", (long long)tiletable, bytes_per_pixel); #endif if (tiletable == 0) return; // Nr of tiles horizontally: int w = width_in_tiles + (partial_pixels > 0 ? 1 : 0); // Actually, the number of tiles vertically is usually very few, // but this algorithm will render "up to" 256 and abort as soon // as the screen is filled instead. This makes it work for both // Linux' "tweaked linear" mode and all the other guest OSes. const int max_nr_of_tiles = 256; uint32_t tile[max_nr_of_tiles]; uint8_t alltileptrs[max_nr_of_tiles * sizeof(uint16_t)]; cpu->memory_rw(cpu, cpu->mem, tiletable, alltileptrs, sizeof(alltileptrs), MEM_READ, NO_EXCEPTIONS | PHYSICAL); for (int i = 0; i < 256; ++i) { tile[i] = (256 * alltileptrs[i*2] + alltileptrs[i*2+1]) << 16; #ifdef GBE_DEBUG if (tile[i] != 0) printf("tile[%i] = 0x%08x\n", i, tile[i]); #endif } int screensize = d->xres * d->yres * 3; int x = 0, y = 0; for (int tiley = 0; tiley < max_nr_of_tiles; ++tiley) { for (int line = 0; line < 128; ++line) { for (int tilex = 0; tilex < w; ++tilex) { int tilenr = tilex + tiley * w; if (tilenr >= max_nr_of_tiles) continue; uint32_t base = tile[tilenr]; if (base == 0) continue; // Read one line of up to 512 bytes from the tile. int len = tilex < width_in_tiles ? 512 : (partial_pixels * bytes_per_pixel); cpu->memory_rw(cpu, cpu->mem, base + 512 * line, buf, len, MEM_READ, NO_EXCEPTIONS | PHYSICAL); int fb_offset = (x + y * d->xres) * 3; int fb_len = (len / bytes_per_pixel) * 3; if (fb_offset + fb_len > screensize) { fb_len = screensize - fb_offset; } if (fb_len <= 0) { tiley = max_nr_of_tiles; // to break tilex = w; line = 128; } uint8_t fb_buf[512 * 3]; int fb_i = 0; for (int i = 0; i < 512; i+=bytes_per_pixel) { uint32_t color; if (bytes_per_pixel == 1) color = buf[i]; else if (bytes_per_pixel == 2) color = (buf[i]<<8) + buf[i+1]; else // if (bytes_per_pixel == 4) color = (buf[i]<<24) + (buf[i+1]<<16) + (buf[i+2]<<8)+buf[i+3]; get_rgb(d, color, &fb_buf[fb_i], &fb_buf[fb_i+1], &fb_buf[fb_i+2]); fb_i += 3; } dev_fb_access(cpu, cpu->mem, fb_offset, fb_buf, fb_len, MEM_WRITE, d->fb_data); x += len / bytes_per_pixel; if (x >= d->xres) { x -= d->xres; ++y; if (y >= d->yres) { tiley = max_nr_of_tiles; // to break tilex = w; line = 128; } } } } } if (d->cursor_control & CRMFB_CURSOR_ON) { int16_t cx = d->cursor_pos & 0xffff; int16_t cy = d->cursor_pos >> 16; if (d->cursor_control & CRMFB_CURSOR_CROSSHAIR) { uint8_t pixel[3]; pixel[0] = d->cursor_cmap0 >> 24; pixel[1] = d->cursor_cmap0 >> 16; pixel[2] = d->cursor_cmap0 >> 8; if (cx >= 0 && cx < d->xres) { for (y = 0; y < d->yres; ++y) dev_fb_access(cpu, cpu->mem, (cx + y * d->xres) * 3, pixel, 3, MEM_WRITE, d->fb_data); } // TODO: Rewrite as a single framebuffer block write? if (cy >= 0 && cy < d->yres) { for (x = 0; x < d->xres; ++x) dev_fb_access(cpu, cpu->mem, (x + cy * d->xres) * 3, pixel, 3, MEM_WRITE, d->fb_data); } } else { uint8_t pixel[3]; int sx, sy; for (int dy = 0; dy < 32; ++dy) { for (int dx = 0; dx < 32; ++dx) { sx = cx + dx; sy = cy + dy; if (sx < 0 || sx >= d->xres || sy < 0 || sy >= d->yres) continue; int wordindex = dy*2 + (dx>>4); uint32_t word = d->cursor_bitmap[wordindex]; int color = (word >> ((15 - (dx&15))*2)) & 3; if (!color) continue; if (color == 1) { pixel[0] = d->cursor_cmap0 >> 24; pixel[1] = d->cursor_cmap0 >> 16; pixel[2] = d->cursor_cmap0 >> 8; } else if (color == 2) { pixel[0] = d->cursor_cmap1 >> 24; pixel[1] = d->cursor_cmap1 >> 16; pixel[2] = d->cursor_cmap1 >> 8; } else { pixel[0] = d->cursor_cmap2 >> 24; pixel[1] = d->cursor_cmap2 >> 16; pixel[2] = d->cursor_cmap2 >> 8; } dev_fb_access(cpu, cpu->mem, (sx + sy * d->xres) * 3, pixel, 3, MEM_WRITE, d->fb_data); } } } } } DEVICE_ACCESS(sgi_gbe) { struct sgi_gbe_data *d = (struct sgi_gbe_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) { idata = memory_readmax64(cpu, data, len); #ifdef GBE_DEBUG fatal("[ sgi_gbe: DEBUG: write to address 0x%llx, data" "=0x%llx ]\n", (long long)relative_addr, (long long)idata); #endif } switch (relative_addr) { case CRMFB_CTRLSTAT: // 0x0 if (writeflag == MEM_WRITE) { debug("[ sgi_gbe: write to ctrlstat: 0x%08x ]\n", (int)idata); d->ctrlstat = (idata & ~CRMFB_CTRLSTAT_CHIPID_MASK) | (d->ctrlstat & CRMFB_CTRLSTAT_CHIPID_MASK); } else odata = d->ctrlstat; break; case CRMFB_DOTCLOCK: // 0x4 if (writeflag == MEM_WRITE) d->dotclock = idata; else odata = d->dotclock; break; case CRMFB_I2C_VGA: // 0x8 /* * "CRT I2C control". * * I'm not sure what this does. It isn't really commented * in the Linux sources. The IP32 PROM writes the values * 0x03, 0x01, and then 0x00 to this address, and then * reads back a value. */ if (writeflag == MEM_WRITE) { //if (!(d->i2c & CRMFB_I2C_SCL) && // (idata & CRMFB_I2C_SCL)) { // fatal("vga i2c data: %i\n", idata & CRMFB_I2C_SDA); //} d->i2c = idata; } else { odata = d->i2c; odata |= 1; /* ? The IP32 prom wants this? */ } break; case CRMFB_I2C_FP: // 0x10, i2cfp, flat panel control if (writeflag == MEM_WRITE) { //if (d->i2c & CRMFB_I2C_SCL && // !(idata & CRMFB_I2C_SCL)) { // fatal("fp i2c data: %i\n", idata & CRMFB_I2C_SDA); //} d->i2cfp = idata; } else { odata = d->i2cfp; odata |= 1; /* ? The IP32 prom wants this? */ } break; case CRMFB_DEVICE_ID: // 0x14 odata = CRMFB_DEVICE_ID_DEF; break; case CRMFB_VT_XY: // 0x10000 if (writeflag == MEM_WRITE) d->freeze = idata & 0x80000000; else { /* * vt_xy, according to Linux: * * bit 31 = freeze, 23..12 = cury, 11.0 = curx */ /* odata = ((random() % (d->yres + 10)) << 12) + (random() % (d->xres + 10)) + d->freeze; */ /* * Hack for IRIX/IP32. During startup, it waits for * the value to be over 0x400 (in "gbeRun"). * * Hack for the IP32 PROM: During startup, it waits * for the value to be above 0x500 (I think). */ odata = d->freeze | (random() & 1 ? 0x3ff : 0x501); } break; case CRMFB_VT_XYMAX: // 0x10004, vt_xymax, according to Linux & NetBSD odata = ((d->yres-1) << 12) + d->xres-1; /* ... 12 bits maxy, 12 bits maxx. */ break; case CRMFB_VT_VSYNC: // 0x10008 case CRMFB_VT_HSYNC: // 0x1000c case CRMFB_VT_VBLANK: // 0x10010 case CRMFB_VT_HBLANK: // 0x10014 // TODO break; case CRMFB_VT_FLAGS: // 0x10018 // OpenBSD/sgi writes to this register. break; case CRMFB_VT_FRAMELOCK: // 0x1001c // TODO. break; case CRMFB_VT_INTR01: // 0x10020 if (writeflag == MEM_WRITE) d->y_intr01 = idata; break; case CRMFB_VT_INTR23: // 0x10024 if (writeflag == MEM_WRITE) d->y_intr23 = idata; break; case 0x10028: // 0x10028 case 0x1002c: // 0x1002c case 0x10030: // 0x10030 // TODO: Unknown, written to by the PROM? break; case CRMFB_VT_HPIX_EN: // 0x10034, vt_hpixen, according to Linux odata = (0 << 12) + d->xres-1; /* ... 12 bits on, 12 bits off. */ break; case CRMFB_VT_VPIX_EN: // 0x10038, vt_vpixen, according to Linux odata = (0 << 12) + d->yres-1; /* ... 12 bits on, 12 bits off. */ break; case CRMFB_VT_HCMAP: // 0x1003c if (writeflag == MEM_WRITE) { d->xres = (idata & CRMFB_HCMAP_ON_MASK) >> CRMFB_VT_HCMAP_ON_SHIFT; dev_fb_resize(d->fb_data, d->xres, d->yres); } odata = (d->xres << CRMFB_VT_HCMAP_ON_SHIFT) + d->xres + 100; break; case CRMFB_VT_VCMAP: // 0x10040 if (writeflag == MEM_WRITE) { d->yres = (idata & CRMFB_VCMAP_ON_MASK) >> CRMFB_VT_VCMAP_ON_SHIFT; dev_fb_resize(d->fb_data, d->xres, d->yres); } odata = (d->yres << CRMFB_VT_VCMAP_ON_SHIFT) + d->yres + 100; break; case CRMFB_VT_DID_STARTXY: // 0x10044 case CRMFB_VT_CRS_STARTXY: // 0x10048 case CRMFB_VT_VC_STARTXY: // 0x1004c // TODO break; case CRMFB_OVR_WIDTH_TILE: // 0x20000 if (writeflag == MEM_WRITE) { d->ovr_tilesize = idata; d->ovr_width_in_tiles = (idata >> CRMFB_FRM_TILESIZE_WIDTH_SHIFT) & 0xff; d->ovr_partial_pixels = ((idata >> CRMFB_FRM_TILESIZE_RHS_SHIFT) & 0x1f) * 32; debug("[ sgi_gbe: OVR setting width in tiles = %i, partial pixels = %i ]\n", d->ovr_width_in_tiles, d->ovr_partial_pixels); } else odata = d->ovr_tilesize; break; case CRMFB_OVR_TILE_PTR: // 0x20004 odata = d->ovr_control ^ (random() & 1); break; case CRMFB_OVR_CONTROL: // 0x20008 if (writeflag == MEM_WRITE) d->ovr_control = idata; else odata = d->ovr_control; break; case CRMFB_FRM_TILESIZE: // 0x30000: if (writeflag == MEM_WRITE) { d->tilesize = idata; d->bitdepth = 8 << ((d->tilesize >> CRMFB_FRM_TILESIZE_DEPTH_SHIFT) & 3); d->width_in_tiles = (idata >> CRMFB_FRM_TILESIZE_WIDTH_SHIFT) & 0xff; d->partial_pixels = ((idata >> CRMFB_FRM_TILESIZE_RHS_SHIFT) & 0x1f) * 32 * 8 / d->bitdepth; debug("[ sgi_gbe: setting color depth to %i bits, width in tiles = %i, partial pixels = %i ]\n", d->bitdepth, d->width_in_tiles, d->partial_pixels); } else odata = d->tilesize; break; case CRMFB_FRM_PIXSIZE: // 0x30004 if (writeflag == MEM_WRITE) { debug("[ sgi_gbe: setting PIXSIZE to 0x%08x ]\n", (int)idata); } break; case 0x30008: // TODO: Figure out exactly what the low bits do. // Irix seems to want 0x20 to "sometimes" be on or off here. odata = d->frm_control ^ (random() & 0x20); break; case CRMFB_FRM_CONTROL: // 0x3000c /* * Writes to 3000c should be readable back at 30008? * At least bit 0 (dma) ctrl 3. */ if (writeflag == MEM_WRITE) { d->frm_control = idata; debug("[ sgi_gbe: frm_control = 0x%08x ]\n", d->frm_control); } else odata = d->frm_control; break; case CRMFB_DID_PTR: // 0x40000 odata = random(); /* IP32 prom test hack. TODO */ /* IRIX wants 0x20, it seems. */ if (random() & 1) odata = 0x20; break; case CRMFB_DID_CONTROL: // 0x40004 // TODO break; case CRMFB_CMAP_FIFO: // 0x58000 break; case CRMFB_CURSOR_POS: // 0x70000 if (writeflag == MEM_WRITE) d->cursor_pos = idata; else odata = d->cursor_pos; break; case CRMFB_CURSOR_CONTROL: // 0x70004 if (writeflag == MEM_WRITE) d->cursor_control = idata; else odata = d->cursor_control; break; case CRMFB_CURSOR_CMAP0: // 0x70008 if (writeflag == MEM_WRITE) d->cursor_cmap0 = idata; else odata = d->cursor_cmap0; break; case CRMFB_CURSOR_CMAP1: // 0x7000c if (writeflag == MEM_WRITE) d->cursor_cmap1 = idata; else odata = d->cursor_cmap1; break; case CRMFB_CURSOR_CMAP2: // 0x70010 if (writeflag == MEM_WRITE) d->cursor_cmap2 = idata; else odata = d->cursor_cmap2; break; /* * Linux/sgimips seems to write color palette data to offset 0x50000 * to 0x503xx, and gamma correction data to 0x60000 - 0x603ff, as * 32-bit values at addresses divisible by 4 (formated as 0xrrggbb00). * * "sgio2fb: initializing * sgio2fb: I/O at 0xffffffffb6000000 * sgio2fb: tiles at ffffffffa2ef5000 * sgio2fb: framebuffer at ffffffffa1000000 * sgio2fb: 8192kB memory * Console: switching to colour frame buffer device 80x30" * * NetBSD's crmfb_set_palette, however, uses values in reverse, like this: * val = (r << 8) | (g << 16) | (b << 24); */ default: /* WID at 0x48000 .. 0x48000 + 4*31: */ if (relative_addr >= CRMFB_WID && relative_addr <= CRMFB_WID + 4 * 31) { // TODO: Figure out how this really works. Why are // there 32 such registers? if (writeflag == MEM_WRITE) { d->color_mode = (idata >> CRMFB_MODE_TYP_SHIFT) & 7; d->cmap_select = (idata >> CRMFB_MODE_CMAP_SELECT_SHIFT) & 0x1f; } break; } /* RGB Palette at 0x50000 .. 0x57fff: */ if (relative_addr >= CRMFB_CMAP && relative_addr < CRMFB_CMAP + 256 * 32 * sizeof(uint32_t)) { int color_index = (relative_addr - CRMFB_CMAP) >> 2; if (writeflag == MEM_WRITE) { int cmap = color_index >> 8; d->palette[color_index] = idata; if (cmap == d->cmap_select) d->selected_palette[color_index] = idata; } else { odata = d->palette[color_index]; } break; } /* Gamma correction at 0x60000 .. 0x603ff: */ if (relative_addr >= CRMFB_GMAP && relative_addr <= CRMFB_GMAP + 0x3ff) { /* ignore gamma correction for now */ break; } /* Cursor bitmap at 0x78000 ..: */ if (relative_addr >= CRMFB_CURSOR_BITMAP && relative_addr <= CRMFB_CURSOR_BITMAP + 0xff) { if (len != 4) { printf("unimplemented CRMFB_CURSOR_BITMAP len %i\n", (int)len); } int index = (relative_addr & 0xff) / 4; if (writeflag == MEM_WRITE) d->cursor_bitmap[index] = idata; else odata = d->cursor_bitmap[index]; break; } if (writeflag == MEM_WRITE) fatal("[ sgi_gbe: unimplemented write to address " "0x%llx, data=0x%llx ]\n", (long long)relative_addr, (long long)idata); else fatal("[ sgi_gbe: unimplemented read from address " "0x%llx ]\n", (long long)relative_addr); } if (writeflag == MEM_READ) { #ifdef GBE_DEBUG debug("[ sgi_gbe: DEBUG: read from address 0x%llx: 0x%llx ]\n", (long long)relative_addr, (long long)odata); #endif memory_writemax64(cpu, data, len, odata); } return 1; } void dev_sgi_gbe_init(struct machine *machine, struct memory *mem, uint64_t baseaddr) { struct sgi_gbe_data *d; CHECK_ALLOCATION(d = (struct sgi_gbe_data *) malloc(sizeof(struct sgi_gbe_data))); memset(d, 0, sizeof(struct sgi_gbe_data)); d->xres = GBE_DEFAULT_XRES; d->yres = GBE_DEFAULT_YRES; d->bitdepth = GBE_DEFAULT_BITDEPTH; // My O2 says 0x300ae001 here (while running). d->ctrlstat = CRMFB_CTRLSTAT_INTERNAL_PCLK | CRMFB_CTRLSTAT_GPIO6_INPUT | CRMFB_CTRLSTAT_GPIO5_INPUT | CRMFB_CTRLSTAT_GPIO4_INPUT | CRMFB_CTRLSTAT_GPIO4_SENSE | CRMFB_CTRLSTAT_GPIO3_INPUT | (CRMFB_CTRLSTAT_CHIPID_MASK & 1); // Set a value in the interrupt register that will "never happen" by default. d->y_intr01 = (0xfff << 12) | 0xfff; d->y_intr23 = (0xfff << 12) | 0xfff; // Grayscale palette, most likely overwritten immediately by the // guest operating system. for (int i = 0; i < 256; ++i) d->palette[i] = i * 0x01010100; d->fb_data = dev_fb_init(machine, mem, FAKE_GBE_FB_ADDRESS, VFB_GENERIC, d->xres, d->yres, d->xres, d->yres, 24, "SGI GBE"); memory_device_register(mem, "sgi_gbe", baseaddr, DEV_SGI_GBE_LENGTH, dev_sgi_gbe_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(machine, dev_sgi_gbe_tick, d, 19); } gxemul-0.6.1/src/devices/dev_bebox.cc000644 001750 001750 00000014734 13402411502 017713 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: BeBox motherboard registers and interrupt controller * * See the following URL for more information: * * http://www.bebox.nu/history.php?s=history/benews/benews27 * * These interrupt numbers are from NetBSD's bebox/extint.c: * * serial3 6 * serial4 7 * midi1 8 * midi2 9 * scsi 10 * pci1 11 * pci2 12 * pci3 13 * sound 14 * 8259 26 * irda 27 * a2d 28 * geekport 29 * * Note that these are in IBM order, i.e. reversed. So 8259 interrupts * go to interrupt 31 - 26 = 5, when using normal numbers. * * Interrupt routing should work to both CPUs, but I've only ever seen the * first CPU being used by NetBSD/bebox, so the second CPU is untested :-) */ #include #include #include #include "cpu.h" #include "device.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" struct bebox_data { struct interrupt cpu_irq[2]; /* The 5 motherboard registers: */ uint32_t cpu0_int_mask; uint32_t cpu1_int_mask; uint32_t int_status; uint32_t xpi; uint32_t resets; }; static void bebox_interrupt_assert(struct interrupt *interrupt) { struct bebox_data *d = (struct bebox_data *) interrupt->extra; d->int_status |= interrupt->line; /* printf("STATUS %08x CPU0 %08x CPU1 %08x\n", d->int_status, d->cpu0_int_mask, d->cpu1_int_mask); */ if (d->int_status & d->cpu0_int_mask) INTERRUPT_ASSERT(d->cpu_irq[0]); if (d->int_status & d->cpu1_int_mask) INTERRUPT_ASSERT(d->cpu_irq[1]); } static void bebox_interrupt_deassert(struct interrupt *interrupt) { struct bebox_data *d = (struct bebox_data *) interrupt->extra; d->int_status &= ~interrupt->line; if (!(d->int_status & d->cpu0_int_mask)) INTERRUPT_DEASSERT(d->cpu_irq[0]); if (!(d->int_status & d->cpu1_int_mask)) INTERRUPT_DEASSERT(d->cpu_irq[1]); } /* * check_cpu_masks(): * * BeBox interrupt enable bits are not allowed to be present in * both CPUs at the same time. */ static void check_cpu_masks(struct cpu *cpu, struct bebox_data *d) { d->cpu0_int_mask &= 0x7fffffff; d->cpu1_int_mask &= 0x7fffffff; if ((d->cpu0_int_mask | d->cpu1_int_mask) != (d->cpu0_int_mask ^ d->cpu1_int_mask)) fatal("check_cpu_masks(): BeBox cpu int masks collide!\n"); } DEVICE_ACCESS(bebox) { struct bebox_data *d = (struct bebox_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0x0f0: if (writeflag == MEM_READ) odata = d->cpu0_int_mask; else { if (idata & 0x80000000) d->cpu0_int_mask |= idata; else d->cpu0_int_mask &= ~idata; check_cpu_masks(cpu, d); } break; case 0x1f0: if (writeflag == MEM_READ) odata = d->cpu1_int_mask; else { if (idata & 0x80000000) d->cpu1_int_mask |= idata; else d->cpu1_int_mask &= ~idata; check_cpu_masks(cpu, d); } break; case 0x2f0: if (writeflag == MEM_READ) odata = d->int_status; else { if (idata & 0x80000000) d->int_status |= idata; else d->int_status &= ~idata; d->int_status &= 0x7fffffff; } break; case 0x3f0: if (writeflag == MEM_READ) { odata = d->xpi; /* Bit 6 (counted from the left) is cpuid: */ odata &= ~0x02000000; if (cpu->cpu_id == 1) odata |= 0x02000000; } else { fatal("[ bebox: unimplemented write to 0x3f0:" " 0x%08x ]\n", (int)idata); } break; default: if (writeflag==MEM_READ) { fatal("[ bebox: unimplemented read from 0x%08lx ]\n", (long)relative_addr); } else { fatal("[ bebox: unimplemented write to 0x%08lx: 0x" "%08x ]\n", (long)relative_addr, (int)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(bebox) { struct bebox_data *d; int i; char n[300]; struct machine *machine = devinit->machine; CHECK_ALLOCATION(d = (struct bebox_data *) malloc(sizeof(struct bebox_data))); memset(d, 0, sizeof(struct bebox_data)); /* Connect to the two BeBox CPUs: */ for (i=0; i<2; i++) { if (i >= machine->ncpus) { fatal("FATAL ERROR: The machine seem to be " "lacking cpu nr %i (0-based)\n", i); exit(1); } snprintf(n, sizeof(n), "%s.cpu[%i]", machine->path, i); INTERRUPT_CONNECT(n, d->cpu_irq[i]); } /* * Register the 32 BeBox interrupts: * * NOTE: They are registered on cpu[0], but the interrupt assert/ * deassert routines in this file make sure that the interrupts * are routed to the correct cpu! */ for (i=0; i<32; i++) { struct interrupt templ; snprintf(n, sizeof(n), "%s.bebox.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = 1 << i; templ.name = n; templ.extra = d; templ.interrupt_assert = bebox_interrupt_assert; templ.interrupt_deassert = bebox_interrupt_deassert; interrupt_handler_register(&templ); } memory_device_register(machine->memory, devinit->name, 0x7ffff000, 0x500, dev_bebox_access, d, DM_DEFAULT, NULL); devinit->return_ptr = d; return 1; } gxemul-0.6.1/src/devices/dev_sgi_ip32.cc000644 001750 001750 00000057021 13402411502 020227 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SGI IP32 stuff (CRIME, MACE, MACEPCI, ust) * * o) CRIME (interrupt controller) * o) MACE (Multimedia, Audio and Communications Engine) * o) MACE PCI bus * o) ust (unknown device) * * TODO: * o) VICE (Video and Image Compression Engine) * (perhaps best to place in the Graphics Back End?) * * The GBE graphics (Graphics Back End) is in dev_sgi_gbe.cc. * * Some info here: http://bukosek.si/hardware/collection/sgi-o2.html * but mostly based on how NetBSD, OpenBSD, and Linux use the hardware. */ #include #include #include #include #include "bus_pci.h" #include "console.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "net.h" #include "thirdparty/crimereg.h" #include "thirdparty/sgi_macereg.h" // #define debug fatal // #define MACEPCI_DEBUG #define CRIME_TICKSHIFT 14 struct macepci_data { struct pci_data *pci_data; }; #define DEV_CRIME_LENGTH 0x280 struct crime_data { uint64_t reg[DEV_CRIME_LENGTH / sizeof(uint64_t)]; uint64_t last_microseconds; struct interrupt irq; int prev_asserted; int use_fb; }; void mips_pc_to_pointers(struct cpu *); void mips32_pc_to_pointers(struct cpu *); void crime_interrupt_reassert(struct crime_data *d) { uint64_t status = d->reg[CRIME_SOFTINT / sizeof(uint64_t)] | d->reg[CRIME_HARDINT / sizeof(uint64_t)]; d->reg[CRIME_INTSTAT / sizeof(uint64_t)] = status; status &= d->reg[CRIME_INTMASK / sizeof(uint64_t)]; #if 0 printf("CRIME SOFTINT=0x%08x HARDINT=0x%08x => 0x%08x, INTMASK=0x%08x\n", (uint32_t)d->reg[CRIME_SOFTINT / sizeof(uint64_t)], (uint32_t)d->reg[CRIME_HARDINT / sizeof(uint64_t)], (uint32_t)status, (uint32_t)d->reg[CRIME_INTMASK / sizeof(uint64_t)]); #endif int asserted = !!status; if (asserted && !d->prev_asserted) INTERRUPT_ASSERT(d->irq); else if (!asserted && d->prev_asserted) INTERRUPT_DEASSERT(d->irq); d->prev_asserted = asserted; } /* * crime_interrupt_assert(): * crime_interrupt_deassert(): */ void crime_interrupt_assert(struct interrupt *interrupt) { struct crime_data *d = (struct crime_data *) interrupt->extra; d->reg[CRIME_HARDINT / sizeof(uint64_t)] |= interrupt->line; //printf("CRIME asserting 0x%08x\n", interrupt->line); crime_interrupt_reassert(d); } void crime_interrupt_deassert(struct interrupt *interrupt) { struct crime_data *d = (struct crime_data *) interrupt->extra; d->reg[CRIME_HARDINT / sizeof(uint64_t)] &= ~interrupt->line; //printf("CRIME deasserting 0x%08x\n", interrupt->line); crime_interrupt_reassert(d); } void crime_update_crime_time(struct crime_data* d) { struct timeval tv; gettimeofday(&tv, NULL); uint64_t microseconds = tv.tv_sec * 1000000 + tv.tv_usec; if (d->last_microseconds == 0) d->last_microseconds = microseconds; int64_t delta = microseconds - d->last_microseconds; if (delta < 0) { fatal("[ crime_update_crime_time: host system time went backwards? ]\n"); d->last_microseconds = microseconds; delta = 0; } // The delta to add is 66 per microsecond. int64_t to_add = delta * 66; if (to_add >= 1) { // NetBSD says CRIME_TIME_MASK = 0x0000ffffffffffffULL // but my O2 seems to use only the lower 32 bits as an // _unsigned_ value. (TODO: Double-check this again.) d->reg[CRIME_TIME / sizeof(uint64_t)] = (uint32_t)(d->reg[CRIME_TIME / sizeof(uint64_t)] + to_add); d->last_microseconds = microseconds; } } /* * dev_crime_tick(): * * Updates CRIME_TIME (at 66 MHz) and reassert CRIME interrupts. */ DEVICE_TICK(crime) { struct crime_data *d = (struct crime_data *) extra; crime_update_crime_time(d); crime_interrupt_reassert(d); } DEVICE_ACCESS(crime) { /* * The CRIME is memory mapped as 0x80 bytes, starting at * physical 0x14000000. * * On my real O2: * * 0x14000080..0x140000ff is the same as 0x14000000..0x1400007f. * 0x14000100..0x1400017f is the same as 0x14000000..0x1400007f. * 0x14000180..0x140001ff is the same as 0x14000000..0x1400007f. * * (I assume that real code will never access the above "mirrors", * but it would be trivial to add redirection so that such code * would work too.) * * Memory control then starts at 0x14000200. */ struct crime_data *d = (struct crime_data *) extra; uint64_t idata = 0, odata = 0; uint64_t preserved_CRIME_HARDINT = d->reg[CRIME_HARDINT / sizeof(uint64_t)]; size_t i; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* * Set crime version/revision: * * This might not be the most elegant or correct solution, but it * seems that the IP32 PROM likes 0x11 for machines without graphics, * and 0xa1 for machines with graphics. * * NetBSD 2.0 complains about "unknown" crime for 0x11, but I guess * that's something one has to live with. (TODO?) */ d->reg[CRIME_REV / sizeof(uint64_t)] = d->use_fb? 0xa1 : 0x11; d->reg[CRIME_CONTROL / sizeof(uint64_t)] = CRIME_CONTROL_ENDIANESS; d->reg[CRIME_INTSTAT / sizeof(uint64_t)] = (d->reg[CRIME_SOFTINT / sizeof(uint64_t)] | d->reg[CRIME_HARDINT / sizeof(uint64_t)]); /* * Amount of memory. Bit 8 of bank control set ==> 128MB instead * of 32MB per bank (?) * * When the bank control registers contain the same value as the * previous one, that bank is not valid. (?) * * TODO: Make this work reliably with other sizes than 128 or 256 MB. * 128 MB is what I have in my machine. Theoretically, up to 1 GB * could be supported in the O2, of which the first 256 MB is * accessible at low physical addresses (below 0x10000000). */ if (cpu->machine->physical_ram_in_mb >= 1024) { fatal("[ sgi_crime: SGI O2 can not have more than 1024 MB RAM ]\n"); exit(1); } int mb_per_bank; if (cpu->machine->physical_ram_in_mb <= 256) mb_per_bank = 32; else mb_per_bank = 128; if (cpu->machine->physical_ram_in_mb % mb_per_bank) { fatal("[ sgi_crime: for up to 256 MB RAM, RAM size needs to be divisible " "by 32 MB. for larger RAM sizes (up to 1024 MB), it needs to be " "divisible by 128 MB. ]\n"); exit(1); } int flag_for_128MB = mb_per_bank == 128 ? 0x100 : 0x000; int total_mb = 0; for (int bank = 0; bank < 8; ++bank) { int b = mb_per_bank == 128 ? (bank << 2) : bank; if (total_mb >= cpu->machine->physical_ram_in_mb) d->reg[CRIME_MEM_BANK_CTRL0 / sizeof(uint64_t) + bank] = d->reg[CRIME_MEM_BANK_CTRL0 / sizeof(uint64_t) + 0]; else d->reg[CRIME_MEM_BANK_CTRL0 / sizeof(uint64_t) + bank] = flag_for_128MB | b; total_mb += mb_per_bank; } if (len == 8) { if (writeflag == MEM_WRITE) d->reg[relative_addr / 8] = idata; else odata = d->reg[relative_addr / 8]; } else if (len == 4) { if (writeflag == MEM_WRITE) { if (relative_addr & 4) { d->reg[relative_addr / 8] &= ~0xffffffffULL; d->reg[relative_addr / 8] |= (uint32_t)idata; } else { d->reg[relative_addr / 8] &= 0xffffffffULL; d->reg[relative_addr / 8] |= (uint64_t)(idata << 32ULL); } } else { odata = d->reg[relative_addr / 8]; if (relative_addr & 4) odata = (int32_t)odata; else odata = (int32_t)(odata >> 32); } } else { fatal("crime access len = %i!\n", len); exit(1); } switch (relative_addr) { case CRIME_REV: /* 0x000 */ /* * A contender for winning a prize for the worst hack * in history: the IP32 PROM probes the CPU caches during * bootup, but they are not really emulated, so it fails. * During the probe, the CRIME_REV is read a lot. By * "returning" from the probe function, i.e. jumping to ra, * when this register is read the second time, the probe * can be skipped, and the PROM thus runs further. * * The address where this happens is: * 0xbfc0517c PROM v2.3 * 0xbfc051ac PROM v4.13 * * 4.18 works too. * * By extrapolating a bit (allowing for variations for other * versions of the PROM), let's return if the read of the * CRIME_REV register occurs anywhere near 0xbfc051XX. */ if (((uint32_t)cpu->pc & 0xffffff00) == (uint32_t)0xbfc05100) { cpu->pc = cpu->cd.mips.gpr[MIPS_GPR_RA]; if (cpu->is_32bit) mips32_pc_to_pointers(cpu); else mips_pc_to_pointers(cpu); } break; case CRIME_CONTROL: /* 0x008 */ /* TODO: 64-bit write to CRIME_CONTROL, but some things (such as NetBSD 1.6.2) write to 0x00c! */ if (writeflag == MEM_WRITE) { /* * 0x200 = watchdog timer (according to NetBSD) * 0x800 = "reboot" used by the IP32 PROM */ if (idata & CRIME_CONTROL_DOG_ENABLE) { idata &= ~CRIME_CONTROL_DOG_ENABLE; } if (idata & CRIME_CONTROL_HARD_RESET) { int j; /* This is used by the IP32 PROM's "reboot" command: */ for (j=0; jmachine->ncpus; j++) cpu->machine->cpus[j]->running = 0; cpu->machine-> exit_without_entering_debugger = 1; idata &= ~CRIME_CONTROL_HARD_RESET; } idata &= ~CRIME_CONTROL_ENDIANESS; if (idata != 0) fatal("[ CRIME_CONTROL: unimplemented " "control 0x%016llx ]\n", (long long)idata); } break; case CRIME_INTSTAT: /* 0x010, Current interrupt status */ case CRIME_INTMASK: /* 0x018, Current interrupt mask */ crime_interrupt_reassert(d); break; case CRIME_DOG: /* 0x030 */ // No warning. break; case CRIME_TIME: /* 0x038 */ crime_update_crime_time(d); break; default: if (writeflag==MEM_READ) { debug("[ crime: read from 0x%x, len=%i:", (int)relative_addr, len); for (i=0; ireg[CRIME_HARDINT / sizeof(uint64_t)] = preserved_CRIME_HARDINT; d->reg[CRIME_INTSTAT / sizeof(uint64_t)] = (d->reg[CRIME_SOFTINT / sizeof(uint64_t)] | d->reg[CRIME_HARDINT / sizeof(uint64_t)]); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_crime_init(): */ void dev_crime_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, char *irq_path, int use_fb) { struct crime_data *d; char tmpstr[200]; int i; CHECK_ALLOCATION(d = (struct crime_data *) malloc(sizeof(struct crime_data))); memset(d, 0, sizeof(struct crime_data)); d->use_fb = use_fb; INTERRUPT_CONNECT(irq_path, d->irq); /* Register 32 crime interrupts (hexadecimal names): */ for (i=0; i<32; i++) { struct interrupt templ; char name[400]; snprintf(name, sizeof(name), "%s.crime.0x%x", irq_path, 1 << i); memset(&templ, 0, sizeof(templ)); templ.line = 1 << i; templ.name = name; templ.extra = d; templ.interrupt_assert = crime_interrupt_assert; templ.interrupt_deassert = crime_interrupt_deassert; interrupt_handler_register(&templ); } memory_device_register(mem, "crime", baseaddr, DEV_CRIME_LENGTH, dev_crime_access, d, DM_DEFAULT, NULL); snprintf(tmpstr, sizeof(tmpstr), "mace addr=0x1f310000 irq=%s.crime", irq_path); device_add(machine, tmpstr); machine_add_tickfunction(machine, dev_crime_tick, d, CRIME_TICKSHIFT); } /****************************************************************************/ #define DEV_MACE_LENGTH 0x100 struct mace_data { unsigned char reg[DEV_MACE_LENGTH]; struct interrupt irq_periph; struct interrupt irq_misc; int prev_assert_periph; int prev_assert_misc; }; void mace_interrupt_reassert(struct mace_data *d) { uint8_t s4 = d->reg[MACE_ISA_INT_STATUS+4] & d->reg[MACE_ISA_INT_MASK+4]; uint8_t s5 = d->reg[MACE_ISA_INT_STATUS+5] & d->reg[MACE_ISA_INT_MASK+5]; uint8_t s6 = d->reg[MACE_ISA_INT_STATUS+6] & d->reg[MACE_ISA_INT_MASK+6]; uint8_t s7 = d->reg[MACE_ISA_INT_STATUS+7] & d->reg[MACE_ISA_INT_MASK+7]; int assert_periph = s4 | s5 ? 1 : 0; int assert_misc = s6 | s7 ? 1 : 0; /* printf("status=%02x%02x%02x%02x mask=%02x%02x%02x%02x => periph = %i misc = %i\n", d->reg[MACE_ISA_INT_STATUS+4], d->reg[MACE_ISA_INT_STATUS+5], d->reg[MACE_ISA_INT_STATUS+6], d->reg[MACE_ISA_INT_STATUS+7], d->reg[MACE_ISA_INT_MASK+4], d->reg[MACE_ISA_INT_MASK+5], d->reg[MACE_ISA_INT_MASK+6], d->reg[MACE_ISA_INT_MASK+7], assert_periph, assert_misc); */ if (assert_periph != d->prev_assert_periph) { d->prev_assert_periph = assert_periph; if (assert_periph) INTERRUPT_ASSERT(d->irq_periph); else INTERRUPT_DEASSERT(d->irq_periph); } if (assert_misc != d->prev_assert_misc) { d->prev_assert_misc = assert_misc; if (assert_misc) INTERRUPT_ASSERT(d->irq_misc); else INTERRUPT_DEASSERT(d->irq_misc); } } /* * mace_interrupt_assert(): * mace_interrupt_deassert(): */ void mace_interrupt_assert(struct interrupt *interrupt) { struct mace_data *d = (struct mace_data *) interrupt->extra; uint32_t line = 1 << interrupt->line; d->reg[MACE_ISA_INT_STATUS + 4] |= ((line >> 24) & 255); d->reg[MACE_ISA_INT_STATUS + 5] |= ((line >> 16) & 255); d->reg[MACE_ISA_INT_STATUS + 6] |= ((line >> 8) & 255); d->reg[MACE_ISA_INT_STATUS + 7] |= (line & 255); mace_interrupt_reassert(d); } void mace_interrupt_deassert(struct interrupt *interrupt) { struct mace_data *d = (struct mace_data *) interrupt->extra; uint32_t line = 1 << interrupt->line; d->reg[MACE_ISA_INT_STATUS + 4] &= ~((line >> 24) & 255); d->reg[MACE_ISA_INT_STATUS + 5] &= ~((line >> 16) & 255); d->reg[MACE_ISA_INT_STATUS + 6] &= ~((line >> 8) & 255); d->reg[MACE_ISA_INT_STATUS + 7] &= ~(line & 255); mace_interrupt_reassert(d); } DEVICE_ACCESS(mace) { size_t i; struct mace_data *d = (struct mace_data *) extra; /* * My O2 returns the following when dumping 0xbf310000 and forward: * * +0x00: 0x0000000000000010 0x000000000000001e * +0x10: 0x0000000000000000 0x0000000000000000 * * and then the following addresses result in the same data as * 0xbf310000. */ d->reg[MACE_ISA_RINGBASE + 7] = 0x10; d->reg[MACE_ISA_FLASH_NIC_REG + 7] |= MACE_ISA_PWD_CLEAR; uint8_t old_mace_isa_flash_nic_reg = d->reg[MACE_ISA_FLASH_NIC_REG + 7]; if (writeflag == MEM_WRITE) memcpy(&d->reg[relative_addr], data, len); else memcpy(data, &d->reg[relative_addr], len); switch (relative_addr & ~7) { case MACE_ISA_RINGBASE: break; case MACE_ISA_FLASH_NIC_REG: // I think the PROM attempts to read the machine's ethernet // address from a DS2502 EPROM, by writing MACE_ISA_NIC_DEASSERT // to this register in various patterns, and looking at the // resulting MACE_ISA_NIC_DATA (or does it write data as well?) // In any case, onewire is too complicated to implement right // now. TODO. if (writeflag) { /* * The NetBSD defines are called "RED" and "GREEN", * and are documented like this: * * 1=> Illuminate RED LED * * (and similarly for GREEN). But on my O2, it feels * like the other way around (i.e. 1 = do NOT illuminate * that LED color). Also, having it this way is more * compatible with how NetBSD, OpenBSD, and the PROM * actually use the LED. */ uint8_t change = (d->reg[MACE_ISA_FLASH_NIC_REG + 7] ^ old_mace_isa_flash_nic_reg) & (MACE_ISA_LED_RED | MACE_ISA_LED_GREEN); if (change) { switch (d->reg[MACE_ISA_FLASH_NIC_REG + 7] & (MACE_ISA_LED_RED | MACE_ISA_LED_GREEN)) { case 0: debug("[ mace: turning LED WHITE/ORANGE ]\n"); break; case MACE_ISA_LED_RED: debug("[ mace: turning LED GREEN ]\n"); break; case MACE_ISA_LED_GREEN: debug("[ mace: turning LED RED ]\n"); break; default:fatal("[ mace: turning LED OFF ]\n"); break; } } //printf("%02x: MACE_ISA_NIC_DEASSERT = %i, DATA = %i\n", //d->reg[MACE_ISA_FLASH_NIC_REG + 7], //d->reg[MACE_ISA_FLASH_NIC_REG + 7] & MACE_ISA_NIC_DEASSERT, //d->reg[MACE_ISA_FLASH_NIC_REG + 7] & MACE_ISA_NIC_DATA); } else { // data[len-1] ^= (random() & MACE_ISA_NIC_DATA); // data[len-1] |= MACE_ISA_NIC_DEASSERT; } break; case MACE_ISA_INT_STATUS: /* Current interrupt assertions */ /* don't dump debug info for these */ if (writeflag == MEM_WRITE) { fatal("[ NOTE/TODO: WRITE to mace intr: " "reladdr=0x%x data=", (int)relative_addr); for (i=0; iinterrupt_path, CRIME_INT_PERIPH_SERIAL); INTERRUPT_CONNECT(tmpstr, d->irq_periph); snprintf(tmpstr, sizeof(tmpstr), "%s.0x%x", devinit->interrupt_path, CRIME_INT_PERIPH_MISC); INTERRUPT_CONNECT(tmpstr, d->irq_misc); /* * For CRIME interrupts PERIPH_SERIAL and PERIPH_MISC, * register 32 mace interrupts each. */ for (i=0; i<32; i++) { struct interrupt templ; char name[400]; snprintf(name, sizeof(name), "%s.0x%x.mace.%i", devinit->interrupt_path, CRIME_INT_PERIPH_SERIAL, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = name; templ.extra = d; templ.interrupt_assert = mace_interrupt_assert; templ.interrupt_deassert = mace_interrupt_deassert; interrupt_handler_register(&templ); snprintf(name, sizeof(name), "%s.0x%x.mace.%i", devinit->interrupt_path, CRIME_INT_PERIPH_MISC, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = name; templ.extra = d; templ.interrupt_assert = mace_interrupt_assert; templ.interrupt_deassert = mace_interrupt_deassert; interrupt_handler_register(&templ); } memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_MACE_LENGTH, dev_mace_access, d, DM_DEFAULT, NULL); devinit->return_ptr = d; return 1; } /****************************************************************************/ DEVICE_ACCESS(macepci) { struct macepci_data *d = (struct macepci_data *) extra; uint64_t idata = 0, odata=0; int res = 1, bus, dev, func, pcireg; if (len != 4) fatal("[ macepci: unimplemented len %i ]\n", len); if (writeflag == MEM_WRITE) { idata = memory_readmax64(cpu, data, len); #ifdef MACEPCI_DEBUG fatal("[ macepci: write to address 0x%x, data=0x%02x (len %i) ]\n", (int)relative_addr, (int)idata, len); #endif } /* Read from/write to the macepci: */ switch (relative_addr) { case 0x00: /* Error address */ if (writeflag == MEM_WRITE) { } else { /* My real O2 returns 0x4000. */ odata = 0x4000; } break; case 0x04: /* Error flags */ if (writeflag == MEM_WRITE) { } else { /* My real O2 returns 0x00100006. */ odata = 0x00100006; } break; case 0x08: /* TODO: Unknown? */ if (writeflag == MEM_WRITE) { } else { /* My real O2 returns 0xff000500. */ odata = 0xff000500; } break; case 0x0c: /* Revision number */ if (writeflag == MEM_WRITE) { } else { /* My real O2 returns 0x00000001. */ odata = 0x00000001; } break; case 0xcf8: /* PCI ADDR */ bus_pci_decompose_1(idata, &bus, &dev, &func, &pcireg); bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, pcireg); break; case 0xcfc: /* PCI DATA */ bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ? &odata : &idata, len, writeflag); break; default: if (writeflag == MEM_WRITE) { fatal("[ macepci: unimplemented write to address " "0x%x, data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { fatal("[ macepci: unimplemented read from address " "0x%x ]\n", (int)relative_addr); /* My real O2 returns 0xffffffff for all unimplemented registers. */ odata = 0xffffffff; } } if (writeflag == MEM_READ) { memory_writemax64(cpu, data, len, odata); #ifdef MACEPCI_DEBUG fatal("[ macepci: read from address 0x%x, data=0x%02x (len %i) ]\n", (int)relative_addr, (int)odata, len); #endif } return res; } /* * dev_macepci_init(): */ struct pci_data *dev_macepci_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, char *irq_path) { struct macepci_data *d; CHECK_ALLOCATION(d = (struct macepci_data *) malloc(sizeof(struct macepci_data))); memset(d, 0, sizeof(struct macepci_data)); /* TODO: PCI vs ISA interrupt? */ d->pci_data = bus_pci_init(machine, irq_path, 0, 0, 0, 0, "TODO: pci irq path", 0x18000003, /* ISA portbase */ 0, irq_path); memory_device_register(mem, "macepci", baseaddr, DEV_MACEPCI_LENGTH, dev_macepci_access, (void *)d, DM_DEFAULT, NULL); return d->pci_data; } /****************************************************************************/ struct sgi_ust_data { uint64_t reg[DEV_SGI_UST_LENGTH / sizeof(uint64_t)]; }; DEVICE_ACCESS(sgi_ust) { struct sgi_ust_data *d = (struct sgi_ust_data *) extra; uint64_t idata = 0, odata = 0; int regnr; idata = memory_readmax64(cpu, data, len); regnr = relative_addr / sizeof(uint64_t); /* Treat all registers as read/write, by default. */ if (writeflag == MEM_WRITE) d->reg[regnr] = idata; else odata = d->reg[regnr]; switch (relative_addr) { case 0: d->reg[regnr] += 0x2710; // HUH? break; default: if (writeflag == MEM_WRITE) debug("[ sgi_ust: unimplemented write to " "address 0x%llx, data=0x%016llx ]\n", (long long)relative_addr, (long long)idata); else debug("[ sgi_ust: unimplemented read from address" " 0x%llx ]\n", (long long)relative_addr); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_sgi_ust_init(): */ void dev_sgi_ust_init(struct memory *mem, uint64_t baseaddr) { struct sgi_ust_data *d; CHECK_ALLOCATION(d = (struct sgi_ust_data *) malloc(sizeof(struct sgi_ust_data))); memset(d, 0, sizeof(struct sgi_ust_data)); memory_device_register(mem, "sgi_ust", baseaddr, DEV_SGI_UST_LENGTH, dev_sgi_ust_access, (void *)d, DM_DEFAULT, NULL); } gxemul-0.6.1/src/devices/dev_palmbus.cc000644 001750 001750 00000006372 13402411502 020256 0ustar00debugdebug000000 000000 /* * Copyright (C) 2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: VoCore Palmbus * * TODO */ #include #include #include #include "cpu.h" #include "console.h" #include "device.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #define DEV_PALMBUS_LENGTH 0x1000 struct palmbus_data { // struct interrupt irq; int console_handle; }; DEVICE_ACCESS(palmbus) { struct palmbus_data *d = (struct palmbus_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0x0000: odata = 0x30335452; break; case 0x0004: odata = 0x20203235; break; case 0x000c: /* Linux boot message says "SoC Type: Ralink RT5350 id:1 rev:3" */ odata = 0x00000103; break; case 0x0c04: console_putchar(d->console_handle, idata); break; case 0x0c1c: odata = 0x20; // Serial ready (?) break; default: if (writeflag == MEM_WRITE) { fatal("[ palmbus: unimplemented write to address 0x%x" ", data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { fatal("[ palmbus: unimplemented read from address 0x%x " "]\n", (int)relative_addr); } /* exit(1); */ } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(palmbus) { char *name2; struct palmbus_data *d; CHECK_ALLOCATION(d = (struct palmbus_data *) malloc(sizeof(struct palmbus_data))); memset(d, 0, sizeof(struct palmbus_data)); // INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); d->console_handle = console_start_slave(devinit->machine, "uartlite", 1); memory_device_register(devinit->machine->memory, name2, devinit->addr, DEV_PALMBUS_LENGTH, dev_palmbus_access, (void *)d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_v3.cc000644 001750 001750 00000022575 13402411502 017146 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: V3 Semiconductor PCI controller * * The ISA interrupt controller part forwards ISA interrupts as follows * (on Algor P5064): * * ISA interrupt 3 and 4 -> MIPS interrupt 4 ("Local") * All other ISA interrupts -> MIPS interrupt 2 ("ISA") * * See NetBSD's src/sys/arch/algor/pci/ for details. */ #include #include #include #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" struct v3_data { struct interrupt irq_isa; struct interrupt irq_local; uint8_t secondary_mask1; struct pic8259_data* pic1; struct pic8259_data* pic2; int *ptr_to_pending_timer_interrupts; struct pci_data *pci_data; uint16_t lb_map0; }; /* * v3_isa_interrupt_common(): */ void v3_isa_interrupt_common(struct v3_data *d, int old_isa_assert) { int new_isa_assert; /* Any interrupt assertions on PIC2 go to irq 2 on PIC1 */ /* (TODO: don't hardcode this here) */ if (d->pic2->irr & ~d->pic2->ier) d->pic1->irr |= 0x04; else d->pic1->irr &= ~0x04; new_isa_assert = d->pic1->irr & ~d->pic1->ier; if (old_isa_assert == new_isa_assert) return; if (new_isa_assert & d->secondary_mask1) INTERRUPT_ASSERT(d->irq_local); else INTERRUPT_DEASSERT(d->irq_local); if (new_isa_assert & ~d->secondary_mask1) INTERRUPT_ASSERT(d->irq_isa); else INTERRUPT_DEASSERT(d->irq_isa); } /* * v3_isa_interrupt_assert(): * * Called whenever an ISA device asserts an interrupt (0..15). * If the interrupt number is 16, then it is a re-assert. */ void v3_isa_interrupt_assert(struct interrupt *interrupt) { struct v3_data *d = (struct v3_data *) interrupt->extra; int old_isa_assert, line = interrupt->line; int mask = 1 << (line & 7); old_isa_assert = d->pic1->irr & ~d->pic1->ier; if (line < 8) d->pic1->irr |= mask; else if (line < 16) d->pic2->irr |= mask; v3_isa_interrupt_common(d, old_isa_assert); } /* * v3_isa_interrupt_deassert(): * * Called whenever an ISA device deasserts an interrupt (0..15). * If the interrupt number is 16, then it is a re-assert. */ void v3_isa_interrupt_deassert(struct interrupt *interrupt) { struct v3_data *d = (struct v3_data *) interrupt->extra; int line = interrupt->line, mask = 1 << (line & 7); int old_irr1 = d->pic1->irr, old_isa_assert; old_isa_assert = old_irr1 & ~d->pic1->ier; if (line < 8) d->pic1->irr &= ~mask; else if (line < 16) d->pic2->irr &= ~mask; /* If IRQ 0 has been cleared, then this is a timer interrupt. Let's ack it here: */ if (old_irr1 & 1 && !(d->pic1->irr & 1) && d->ptr_to_pending_timer_interrupts != NULL && (*d->ptr_to_pending_timer_interrupts) > 0) (*d->ptr_to_pending_timer_interrupts) --; v3_isa_interrupt_common(d, old_isa_assert); } DEVICE_ACCESS(v3_pci) { uint64_t idata = 0, odata = 0; int bus, dev, func, reg; struct v3_data *d = (struct v3_data *) extra; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN); /* Decompose the tag: */ relative_addr &= 0xfffff; relative_addr |= ((d->lb_map0 & 0xfff0) << 16); bus = 0; for (dev=24; dev<32; dev++) if (relative_addr & (1 << dev)) break; dev -= 24; if (dev == 8) { fatal("[ v3_pci: NO DEVICE? ]\n"); dev = 0; } func = (relative_addr >> 8) & 7; reg = relative_addr & 0xfc; bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, reg); /* Pass semi-direct PCI accesses onto bus_pci: */ bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ? &odata : &idata, len, writeflag); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN, odata); return 1; } DEVICE_ACCESS(v3) { struct v3_data *d = (struct v3_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0x06: /* PCI stat */ break; case 0x08: /* Revision */ odata = 4; break; case 0x18: /* PCI DMA base 1 */ odata = 0x11000000; break; case 0x5e: /* LB MAP0 */ if (writeflag == MEM_READ) odata = d->lb_map0; else d->lb_map0 = idata; break; case 0x62: /* PCI mem base 1 */ odata = 0x1100; break; case 0x64: /* L2 BASE */ odata = 1; /* pci i/o enable */ break; case 0x66: /* Map 2 */ odata = 0x1d00; break; default:if (writeflag == MEM_WRITE) { fatal("[ v3: unimplemented write to " "offset 0x%x: data=0x%x ]\n", (int) relative_addr, (int)idata); } else { fatal("[ v3: unimplemented read from " "offset 0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(v3) { struct v3_data *d; uint32_t isa_port_base = 0x1d000000; char tmpstr[200]; char isa_irq_base[200]; char pci_irq_base[200]; int i; CHECK_ALLOCATION(d = (struct v3_data *) malloc(sizeof(struct v3_data))); memset(d, 0, sizeof(struct v3_data)); switch (devinit->machine->machine_type) { case MACHINE_ALGOR: snprintf(tmpstr, sizeof(tmpstr), "%s.4", devinit->interrupt_path); INTERRUPT_CONNECT(tmpstr, d->irq_local); snprintf(tmpstr, sizeof(tmpstr), "%s.2", devinit->interrupt_path); INTERRUPT_CONNECT(tmpstr, d->irq_isa); d->secondary_mask1 = 0x18; break; default:fatal("!\n! WARNING: v3 for non-implemented machine" " type %i\n!\n", devinit->machine->machine_type); exit(1); } /* * Register the 16 possible ISA interrupts, plus a dummy. The * dummy is used by re-asserts. */ for (i=0; i<17; i++) { struct interrupt templ; char n[300]; snprintf(n, sizeof(n), "%s.v3.isa.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = n; templ.extra = d; templ.interrupt_assert = v3_isa_interrupt_assert; templ.interrupt_deassert = v3_isa_interrupt_deassert; interrupt_handler_register(&templ); } /* Register two 8259 PICs: */ snprintf(tmpstr, sizeof(tmpstr), "8259 irq=%s.v3.isa.16 addr=0x%llx", devinit->interrupt_path, (long long)(isa_port_base + 0x20)); d->pic1 = devinit->machine->isa_pic_data.pic1 = (struct pic8259_data *) device_add(devinit->machine, tmpstr); d->ptr_to_pending_timer_interrupts = devinit->machine->isa_pic_data.pending_timer_interrupts; snprintf(tmpstr, sizeof(tmpstr), "8259 irq=%s.v3.isa.2 addr=0x%llx", devinit->interrupt_path, (long long)(isa_port_base + 0xa0)); d->pic2 = devinit->machine->isa_pic_data.pic2 = (struct pic8259_data *) device_add(devinit->machine, tmpstr); snprintf(isa_irq_base, sizeof(isa_irq_base), "%s.v3", devinit->interrupt_path); snprintf(pci_irq_base, sizeof(pci_irq_base), "%s.v3", devinit->interrupt_path); /* Register a PCI bus: */ d->pci_data = bus_pci_init( devinit->machine, pci_irq_base /* pciirq: TODO */, 0x1d000000, /* pci device io offset */ 0x11000000, /* pci device mem offset: TODO */ 0x00000000, /* PCI portbase: TODO */ 0x00000000, /* PCI membase: TODO */ pci_irq_base, /* PCI irqbase */ isa_port_base, /* ISA portbase */ 0x10000000, /* ISA membase */ isa_irq_base); /* ISA irqbase */ switch (devinit->machine->machine_type) { case MACHINE_ALGOR: bus_pci_add(devinit->machine, d->pci_data, devinit->machine->memory, 0, 2, 0, "piix3_isa"); bus_pci_add(devinit->machine, d->pci_data, devinit->machine->memory, 0, 2, 1, "piix3_ide"); break; default:fatal("!\n! WARNING: v3 for non-implemented machine" " type %i\n!\n", devinit->machine->machine_type); exit(1); } /* PCI configuration space: */ memory_device_register(devinit->machine->memory, "v3_pci", 0x1ee00000, 0x100000, dev_v3_pci_access, d, DM_DEFAULT, NULL); /* PCI controller: */ memory_device_register(devinit->machine->memory, "v3", 0x1ef00000, 0x1000, dev_v3_access, d, DM_DEFAULT, NULL); devinit->return_ptr = d->pci_data; return 1; } gxemul-0.6.1/src/devices/.index000644 001750 001750 00000013655 13402411502 016560 0ustar00debugdebug000000 000000 bus_isa.cc Generic ISA bus framework bus_pci.cc Generic PCI bus framework dev_8253.cc Intel 8253/8254 Programmable Interval Timer dev_8259.cc Intel 8259 Programmable Interrupt Controller dev_adb.cc Apple Desktop Bus (ADB) controller dev_ahc.cc Adaptec AHC SCSI controller dev_algor.cc Algor P5064 misc. stuff dev_asc.cc NCR53C9X "ASC" SCSI controller dev_bebox.cc BeBox motherboard registers and interrupt controller dev_bt431.cc Brooktree BT431, used by TURBOchannel graphics cards dev_bt455.cc Brooktree BT455, used by TURBOchannel graphics cards dev_bt459.cc Brooktree BT459, used by TURBOchannel graphics cards dev_clmpcc.cc Cirrus Logic 4-Channel Communications Controller (CD2400/CD2401) dev_colorplanemask.cc Color plane mask, used in the DECstation 3100 machine dev_cons.cc A simple console device, for the test machines dev_cpc700.cc IBM CPC700 bridge (PCI and interrupt controller) dev_dc7085.cc DC7085 serial controller, used in some DECstation models dev_dec21030.cc DEC 21030 "TGA" graphics card dev_dec21143.cc DEC 21143 "Tulip" ethernet controller dev_dec5800.cc DECsystem 58x0 devices dev_dec_ioasic.cc IOASIC device used in some DECstation machines dev_disk.cc A simple disk controller device, for the test machines dev_dreamcast_asic.cc Dreamcast-specific ASIC dev_dreamcast_g2.cc Dreamcast G2 bus dev_dreamcast_gdrom.cc Dreamcast GD-ROM dev_dreamcast_maple.cc Dreamcast Maple bus controller dev_dreamcast_rtc.cc Dreamcast Real-Time Clock dev_eagle.cc Motorola MPC105 "Eagle" host bridge dev_ether.cc A simple ethernet controller, for the test machines dev_fb.cc Generic framebuffer device dev_fbctrl.cc Framebuffer controller device (control's dev_fb in test machines) dev_fdc.cc PC-style floppy controller dev_footbridge.cc DC21285 "Footbridge" controller; used in Netwinder and Cats dev_gc.cc Grand Central Interrupt controller (used by MacPPC) dev_gt.cc Galileo Technology GT-64xxx PCI controller dev_hammerhead.cc Hammerhead controller, for the secondary CPU on MacPPC machines dev_i80321.cc Intel i80321 (ARM) core functionality dev_igsfb.cc Integraphics Systems "igsfb" Framebuffer graphics card dev_iq80321_7seg.cc IQ80321 LED device dev_irqc.cc Generic IRQ controller for the test machines dev_jazz.cc Microsoft Jazz-related stuff (Acer PICA-61, etc) dev_kn01.cc DEC KN01 ("PMAX", DECstation type 1) control register and VDAC dev_kn02.cc DEC KN02 mainbus (TurboChannel interrupt controller) dev_kn02ba.cc DEC KN02BA "3min" TurboChannel interrupt controller dev_kn220.cc DEC KN220 (DECsystem 5500) devices dev_kn230.cc DEC KN230 (MIPSMATE 5100) stuff dev_lca.cc LCA PCI bus, for Alpha machines dev_le.cc LANCE ethernet, as used in DECstations dev_lpt.cc LPT (parallel printer) controller dev_luna88k.cc OMRON Luna 88K-specific devices and control registers dev_m8820x.cc M88200/M88204 CMMU (Cache/Memory Management Unit) dev_malta_lcd.cc Malta (evbmips) LCD display dev_mb8696x.cc Fujitsu MB8696x Ethernet interface (used in the Dreamcast) dev_mc146818.cc MC146818 real-time clock dev_mk48txx.cc Mostek MK48Txx Real Time Clock dev_mp.cc Generic Multi-processor controller for the test machines dev_mvme187.cc MVME187-specific devices and control registers dev_ns16550.cc NS16550 serial controller dev_ohci.cc USB Open Host Controller Interface dev_osiop.cc NCR 53C710 SCSI I/O Processor (SIOP) dev_palmbus.cc VoCore Palmbus dev_pcc2.cc Peripheral Channel Controller (PCC2) bus (used in MVME machines) dev_pccmos.cc PC CMOS/RTC device (ISA ports 0x70 and 0x71) dev_pcic.cc Intel 82365SL PC Card Interface Controller dev_pckbc.cc 8042 PC keyboard controller (+ 8242WB Keyboard/Mouse controller) dev_pmagja.cc TURBOchannel PMAG-JA graphics card dev_pmppc.cc Artesyn PM/PPC motherboard registers dev_prep.cc PReP machine mainbus (ISA bus + interrupt controller) dev_ps2_ether.cc PlayStation 2 ethernet (smap and emac3) dev_ps2_gif.cc PlayStation 2 "gif" graphics device dev_ps2_gs.cc PlayStation 2 graphics system dev_ps2_spd.cc PlayStation 2 SPD harddisk controller dev_ps2_stuff.cc PlayStation 2 misc stuff (timer, DMA, interrupts, ...) dev_pvr.cc PowerVR CLX2 (graphics controller used in the Dreamcast) dev_px.cc TURBOchannel Pixelstamp graphics card dev_ram.cc A generic RAM (memory) device dev_random.cc A device which returns random data for reads, discards all writes dev_rs5c313.cc RICOH RS5C313 Real Time Clock dev_rtc.cc A generic Real-Time Clock device, for the test machines dev_rtl8139c.cc Realtek 8139 ethernet controller dev_scc.cc Serial controller used in some DECsystem and SGI machines dev_sfb.cc SFB TURBOchannel framebuffer (graphics card) dev_sgi_gbe.cc SGI "Graphics Back End", graphics controller + framebuffer dev_sgi_ip19.cc SGI IP19 (and IP25) stuff dev_sgi_ip20.cc SGI IP20 stuff dev_sgi_ip22.cc SGI IP22 stuff dev_sgi_ip30.cc SGI IP30 ("Octane") stuff dev_sgi_ip32.cc SGI IP32 stuff (CRIME, MACE, MACEPCI, ust) dev_sgi_mardigras.cc MardiGras graphics controller on SGI IP30 (Octane) dev_sgi_mec.cc SGI IP32 "mec" ethernet dev_sgi_re.cc SGI O2 "Rendering Engine" dev_sh4.cc SH4-specific memory mapped registers (0xf0000000 - 0xffffffff) dev_sii.cc SII SCSI controller, used in some DECstation systems dev_sn.cc National Semiconductor SONIC ("sn") DP83932 ethernet controller dev_ssc.cc System Support Chip serial controller dev_turbochannel.cc TURBOchannel bus framework, used in DECstation machines dev_uninorth.cc Uni-North PCI controller (used by MacPPC machines) dev_unreadable.cc A simple device which returns an error for all reads/writes dev_v3.cc V3 Semiconductor PCI controller dev_vga.cc VGA framebuffer device (charcell and graphics modes) dev_vme.cc VME bus dev_vr41xx.cc VR41xx (VR4122 and VR4131) misc functions dev_wdc.cc Standard "wdc" IDE controller dev_z8530.cc Zilog Z8530 "zs" serial controller dev_zero.cc A simple device which returns zero for reads, discards all writes device.cc Device registry framework lk201.cc LK201 keyboard and mouse, used by the dc7085 and scc controllers gxemul-0.6.1/src/devices/dev_gt.cc000644 001750 001750 00000020317 13402411502 017220 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Galileo Technology GT-64xxx PCI controller * * GT-64011 Used in Cobalt machines. * GT-64120 Used in evbmips machines (Malta). * GT-64260 Used in mvmeppc machines. */ #include #include #include #include "bus_pci.h" #include "cpu.h" #include "devices.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "timer.h" #include "thirdparty/gtreg.h" #define TICK_SHIFT 14 /* #define debug fatal */ #define PCI_PRODUCT_GALILEO_GT64011 0x4146 /* GT-64011 */ #define PCI_PRODUCT_GALILEO_GT64120 0x4620 /* GT-64120 */ #define PCI_PRODUCT_GALILEO_GT64260 0x6430 /* GT-64260 */ struct gt_data { int type; struct timer *timer; struct interrupt timer0_irq; int interrupt_hz; int pending_timer0_interrupts; /* Address decode registers: */ uint32_t decode[GT_N_DECODE_REGS]; struct pci_data *pci_data; }; /* * timer_tick(): * * Called d->interrupt_hz times per (real-world) second. */ static void timer_tick(struct timer *timer, void *extra) { struct gt_data *d = (struct gt_data *) extra; d->pending_timer0_interrupts ++; } DEVICE_TICK(gt) { struct gt_data *d = (struct gt_data *) extra; if (d->pending_timer0_interrupts > 0) INTERRUPT_ASSERT(d->timer0_irq); } DEVICE_ACCESS(gt) { struct gt_data *d = (struct gt_data *) extra; uint64_t idata = 0, odata = 0; int bus, dev, func, reg; size_t i; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case GT_PCI0IOLD_OFS: case GT_PCI0IOHD_OFS: case GT_PCI0M0LD_OFS: case GT_PCI0M0HD_OFS: case GT_PCI0M1LD_OFS: case GT_PCI0M1HD_OFS: case GT_PCI0IOREMAP_OFS: case GT_PCI0M0REMAP_OFS: case GT_PCI0M1REMAP_OFS: if (writeflag == MEM_READ) { odata = d->decode[relative_addr / 8]; debug("[ gt: read from offset 0x%x: 0x%x ]\n", (int)relative_addr, (int)odata); } else { d->decode[relative_addr / 8] = idata; fatal("[ gt: write to offset 0x%x: 0x%x (TODO) ]\n", (int)relative_addr, (int)idata); } break; case GT_PCI0_CMD_OFS: if (writeflag == MEM_WRITE) { debug("[ gt: write to GT_PCI0_CMD: 0x%08x (TODO) ]\n", (int)idata); } else { debug("[ gt: read from GT_PCI0_CMD (0x%08x) (TODO) ]\n", (int)odata); } break; case GT_INTR_CAUSE: if (writeflag == MEM_WRITE) { debug("[ gt: write to GT_INTR_CAUSE: 0x%08x ]\n", (int)idata); return 1; } else { odata = GTIC_T0EXP; INTERRUPT_DEASSERT(d->timer0_irq); if (d->pending_timer0_interrupts > 0) d->pending_timer0_interrupts --; debug("[ gt: read from GT_INTR_CAUSE (0x%08x) ]\n", (int)odata); } break; case GT_PCI0_INTR_ACK: odata = cpu->machine->isa_pic_data.last_int; /* TODO: Actually ack the interrupt? */ break; case GT_TIMER_CTRL: if (writeflag == MEM_WRITE) { if (idata & ENTC0) { /* TODO: Don't hardcode this. */ d->interrupt_hz = 100; if (d->timer == NULL) d->timer = timer_add(d->interrupt_hz, timer_tick, d); else timer_update_frequency(d->timer, d->interrupt_hz); } } break; case GT_PCI0_CFG_ADDR: if (cpu->byte_order != EMUL_LITTLE_ENDIAN) { // Hack: if (len == sizeof(uint32_t)) { idata = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24); } } bus_pci_decompose_1(idata, &bus, &dev, &func, ®); bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, reg); break; case GT_PCI0_CFG_DATA: if (cpu->byte_order != EMUL_LITTLE_ENDIAN) { // Hack: if (len == sizeof(uint32_t)) { idata = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24); } } bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ? &odata : &idata, len, writeflag); break; default: if (writeflag == MEM_READ) { debug("[ gt: read from addr 0x%x ]\n", (int)relative_addr); } else { debug("[ gt: write to addr 0x%x:", (int)relative_addr); for (i=0; itimer0_irq); switch (type) { case 11: /* Cobalt: */ d->type = PCI_PRODUCT_GALILEO_GT64011; gt_name = "gt64011"; pci_io_offset = 0; pci_mem_offset = 0; pci_portbase = 0x10000000ULL; pci_membase = 0x10100000ULL; isa_portbase = 0x10000000ULL; isa_membase = 0x10100000ULL; break; case 120: /* EVBMIPS (Malta): */ d->type = PCI_PRODUCT_GALILEO_GT64120; gt_name = "gt64120"; pci_io_offset = 0; pci_mem_offset = 0; pci_portbase = 0x18000000ULL; pci_membase = 0x10000000ULL; isa_portbase = 0x18000000ULL; isa_membase = 0x10000000ULL; break; case 260: /* MVMEPPC (mvme5500): */ d->type = PCI_PRODUCT_GALILEO_GT64260; gt_name = "gt64260"; pci_io_offset = 0; pci_mem_offset = 0; pci_portbase = 0x18000000ULL; pci_membase = 0x10000000ULL; isa_portbase = 0x18000000ULL; isa_membase = 0x10000000ULL; break; default:fatal("dev_gt_init(): unimplemented GT type (%i).\n", type); exit(1); } /* * TODO: FIX THESE! Hardcoded numbers = bad. */ d->decode[GT_PCI0IOLD_OFS / 8] = pci_portbase >> 21; d->decode[GT_PCI0IOHD_OFS / 8] = 0x40; d->decode[GT_PCI0M0LD_OFS / 8] = 0x80; d->decode[GT_PCI0M0HD_OFS / 8] = 0x3f; d->decode[GT_PCI0M1LD_OFS / 8] = 0xc1; d->decode[GT_PCI0M1HD_OFS / 8] = 0x5e; d->decode[GT_PCI0IOREMAP_OFS / 8] = d->decode[GT_PCI0IOLD_OFS / 8]; d->decode[GT_PCI0M0REMAP_OFS / 8] = d->decode[GT_PCI0M0LD_OFS / 8]; d->decode[GT_PCI0M1REMAP_OFS / 8] = d->decode[GT_PCI0M1LD_OFS / 8]; d->pci_data = bus_pci_init(machine, "TODO_gt_irq", pci_io_offset, pci_mem_offset, pci_portbase, pci_membase, "TODO_pci_irqbase", isa_portbase, isa_membase, isa_irq_path); /* * According to NetBSD/cobalt: * pchb0 at pci0 dev 0 function 0: Galileo GT-64011 * System Controller, rev 1 */ bus_pci_add(machine, d->pci_data, mem, 0, 0, 0, gt_name); memory_device_register(mem, "gt", baseaddr, DEV_GT_LENGTH, dev_gt_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(machine, dev_gt_tick, d, TICK_SHIFT); return d->pci_data; } gxemul-0.6.1/src/devices/dev_sgi_mardigras.cc000644 001750 001750 00000020330 13402411502 021414 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: MardiGras graphics controller on SGI IP30 (Octane) * * Most of this is just guesses based on the behaviour of Linux/Octane. * * TODO */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "memory.h" #include "machine.h" #include "misc.h" #define debug fatal #define DEV_SGI_MARDIGRAS_LENGTH 0x800000 #define MARDIGRAS_FAKE_OFFSET 0x500000000ULL /* hopefully available */ #define MARDIGRAS_DEFAULT_XSIZE 1280 #define MARDIGRAS_DEFAULT_YSIZE 1024 #define MICROCODE_START 0x50000 #define MICROCODE_END 0x55000 static int mardigras_xsize = MARDIGRAS_DEFAULT_XSIZE; static int mardigras_ysize = MARDIGRAS_DEFAULT_YSIZE; struct sgi_mardigras_data { struct vfb_data *fb; unsigned char microcode_ram[MICROCODE_END - MICROCODE_START]; uint64_t palette_reg_select; int currentx; int currenty; int color; int startx; int starty; int stopx; int stopy; uint64_t draw_mode; }; /* * mardigras_20400(): */ void mardigras_20400(struct cpu *cpu, struct sgi_mardigras_data *d, uint64_t idata) { int i, x, y, r,g,b, len, addr; unsigned char pixels[3 * 8000]; /* Get rgb from palette: */ r = d->fb->rgb_palette[d->color * 3 + 0]; g = d->fb->rgb_palette[d->color * 3 + 1]; b = d->fb->rgb_palette[d->color * 3 + 2]; /* Set color: */ if ((idata & 0x00ffffff00000000ULL) == 0x00185C0400000000ULL) { int color = (idata >> 12) & 0xff; d->color = color; return; } /* Set start XY: */ if ((idata & 0x00ffffff00000000ULL) == 0x0018460400000000ULL) { d->startx = (idata >> 16) & 0xffff; d->starty = idata & 0xffff; if (d->startx >= mardigras_xsize) d->startx = 0; if (d->starty >= mardigras_ysize) d->starty = 0; d->currentx = d->startx; d->currenty = d->starty; return; } /* Set stop XY: */ if ((idata & 0x00ffffff00000000ULL) == 0x0018470400000000ULL) { d->stopx = (idata >> 16) & 0xffff; d->stopy = idata & 0xffff; if (d->stopx >= mardigras_xsize) d->stopx = 0; if (d->stopy >= mardigras_ysize) d->stopy = 0; return; } /* Draw modes: (Rectangle or Bitmap, respectively) */ if (idata == 0x0019100400018000ULL || idata == 0x0019100400418008ULL) { d->draw_mode = idata; return; } /* Send command: */ if (idata == 0x001C130400000018ULL) { switch (d->draw_mode) { /* Rectangle: */ case 0x0019100400018000ULL: /* Fill pixels[] with pixels: */ len = 0; for (x=d->startx; x<=d->stopx; x++) { pixels[len + 0] = r; pixels[len + 1] = g; pixels[len + 2] = b; len += 3; } if (len == 0) break; for (y=d->starty; y<=d->stopy; y++) { addr = (mardigras_xsize * (mardigras_ysize - 1 - y) + d->startx) * 3; /* printf("addr = %i\n", addr); */ /* Write a line: */ dev_fb_access(cpu, cpu->mem, addr, pixels, len, MEM_WRITE, d->fb); } break; /* Bitmap: */ case 0x0019100400418008ULL: break; default: fatal("[ sgi_mardigras: unknown draw mode ]\n"); } return; } /* Send a line of bitmap data: */ if ((idata & 0x00ffffff00000000ULL) == 0x001C700400000000ULL) { addr = (mardigras_xsize * (mardigras_ysize - 1 - d->currenty) + d->currentx) * 3; /* printf("addr=%08x curx,y=%4i,%4i startx,y=%4i,%4i " "stopx,y=%4i,%4i\n", addr, d->currentx, d->currenty, d->startx, d->starty, d->stopx, d->stopy); */ len = 8*3; if (addr > mardigras_xsize * mardigras_ysize * 3 || addr < 0) return; /* Read a line: */ dev_fb_access(cpu, cpu->mem, addr, pixels, len, MEM_READ, d->fb); i = 0; while (i < 8) { if ((idata >> (24 + (7-i))) & 1) { pixels[i*3 + 0] = r; pixels[i*3 + 1] = g; pixels[i*3 + 2] = b; } i ++; d->currentx ++; if (d->currentx > d->stopx) { d->currentx = d->startx; d->currenty ++; if (d->currenty > d->stopy) d->currenty = d->starty; } } /* Write a line: */ dev_fb_access(cpu, cpu->mem, addr, pixels, len, MEM_WRITE, d->fb); return; } debug("mardigras_20400(): 0x%016" PRIx64"\n", (uint64_t) idata); } DEVICE_ACCESS(sgi_mardigras) { uint64_t idata = 0, odata = 0; struct sgi_mardigras_data *d = (struct sgi_mardigras_data *) extra; int i; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* Accessing the microcode_ram works like ordinary ram: */ if (relative_addr >= MICROCODE_START && relative_addr < MICROCODE_END) { relative_addr -= MICROCODE_START; if (writeflag == MEM_WRITE) memcpy(d->microcode_ram + relative_addr, data, len); else memcpy(data, d->microcode_ram + relative_addr, len); return 1; } switch (relative_addr) { case 0x00004: /* xtalk data: (according to Linux/IP30) */ /* (mfgr & 0x7ff) << 1 */ /* (part & 0xffff) << 12 */ /* (rev & 0xf) << 28 */ odata = (2 << 28) | (0xc003 << 12) | (0x2aa << 1); break; case 0x20008: /* Fifo status */ break; case 0x20200: break; case 0x20400: if (writeflag == MEM_WRITE) mardigras_20400(cpu, d, idata); else debug("[ sgi_mardigras: read from 0x20400? ]\n"); break; case 0x58040: /* HQ4 microcode stuff */ break; case 0x70c30: /* Palette register select? */ if (writeflag == MEM_WRITE) d->palette_reg_select = idata; else odata = d->palette_reg_select; break; case 0x70d18: /* Palette register read/write? */ i = 3 * ((d->palette_reg_select >> 8) & 0xff); if (writeflag == MEM_WRITE) { d->fb->rgb_palette[i + 0] = (idata >> 24) & 0xff; d->fb->rgb_palette[i + 1] = (idata >> 16) & 0xff; d->fb->rgb_palette[i + 2] = (idata >> 8) & 0xff; } else { odata = (d->fb->rgb_palette[i+0] << 24) + (d->fb->rgb_palette[i+1] << 16) + (d->fb->rgb_palette[i+2] << 8); } break; case 0x71208: odata = 8; break; default: if (writeflag==MEM_READ) { debug("[ sgi_mardigras: read from 0x%08lx ]\n", (long)relative_addr); } else { debug("[ sgi_mardigras: write to 0x%08lx: 0x%016" PRIx64 " ]\n", (long) relative_addr, (uint64_t) idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(sgi_mardigras) { struct sgi_mardigras_data *d; CHECK_ALLOCATION(d = (struct sgi_mardigras_data *) malloc(sizeof(struct sgi_mardigras_data))); memset(d, 0, sizeof(struct sgi_mardigras_data)); d->fb = dev_fb_init(devinit->machine, devinit->machine->memory, MARDIGRAS_FAKE_OFFSET, VFB_GENERIC, mardigras_xsize, mardigras_ysize, mardigras_xsize, mardigras_ysize, 24, "SGI MardiGras"); if (d->fb == NULL) { fprintf(stderr, "dev_sgi_mardigras_init(): out of memory\n"); exit(1); } memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_SGI_MARDIGRAS_LENGTH, dev_sgi_mardigras_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_bt459.cc000644 001750 001750 00000035624 13402411502 017464 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Brooktree BT459, used by TURBOchannel graphics cards */ #include #include #include #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "x11.h" #include "thirdparty/bt459.h" #ifdef WITH_X11 #include #include #endif extern int quiet_mode; /* #define BT459_DEBUG */ /* #define WITH_CURSOR_DEBUG */ #define BT459_TICK_SHIFT 14 struct bt459_data { uint32_t bt459_reg[DEV_BT459_NREGS]; unsigned char cur_addr_hi; unsigned char cur_addr_lo; int planes; int type; struct interrupt irq; int interrupts_enable; int interrupt_time; int interrupt_time_reset_value; int cursor_x_add; int cursor_y_add; int need_to_redraw_whole_screen; int need_to_update_cursor_shape; int cursor_on; int cursor_x; int cursor_y; int cursor_xsize; int cursor_ysize; int palette_sub_offset; /* 0, 1, or 2 */ struct vfb_data *vfb_data; /* * There is one pointer to the framebuffer's RGB palette, * and then a local copy of the palette. 256 * 3 bytes (r,g,b). * The reason for this is that when we need to blank the screen * (ie video_on = 0), we can set the framebuffer's palette to all * zeroes, but keep our own copy intact, to be reused later again * when the screen is unblanked. */ int video_on; unsigned char *rgb_palette; /* 256 * 3 (r,g,b) */ unsigned char local_rgb_palette[256 * 3]; }; /* * bt459_update_X_cursor(): * * This routine takes the color values in the cursor RAM area, and put them * in the framebuffer window's cursor_pixels. * * d->cursor_xsize and ysize are also updated. */ static void bt459_update_X_cursor(struct cpu *cpu, struct bt459_data *d) { int i, x,y, xmax=0, ymax=0; int bw_only = 1; /* First, let's calculate the size of the cursor: */ for (y=0; y<64; y++) for (x=0; x<64; x+=4) { int reg = BT459_REG_CRAM_BASE + y*16 + x/4; unsigned char data = d->bt459_reg[reg]; if (data) ymax = y; for (i=0; i<4; i++) { int color = (data >> (6-2*i)) & 3; if (color != 0) xmax = x + i; if (color != 0 && color != 3) bw_only = 0; } } d->cursor_xsize = xmax + 1; d->cursor_ysize = ymax + 1; /* * The 'bw_only' hack is because it is nicer to have the b/w * text cursor invert whatever it is standing on, not just overwrite * it with a big white box. * * The following seems to work with NetBSD/OpenBSD/Ultrix/Sprite: * 0 = transparent, 1 and 2 = use the color specified by * BT459_REG_CCOLOR_2, 3 = reverse of color 1/2. */ #ifdef WITH_X11 if (cpu->machine->x11_md.in_use && d->vfb_data->fb_window != NULL) { for (y=0; y<=ymax; y++) { for (x=0; x<=xmax; x+=4) { struct fb_window *win = d->vfb_data->fb_window; int reg = BT459_REG_CRAM_BASE + y*16 + x/4; unsigned char data = d->bt459_reg[reg]; for (i=0; i<4; i++) { int color = (data >> (6-2*i)) & 3; int pixelvalue; if (bw_only) { if (color) pixelvalue = CURSOR_COLOR_INVERT; else pixelvalue = 0; } else { pixelvalue = CURSOR_COLOR_TRANSPARENT; switch (color) { case 1: case 2: pixelvalue = (d-> bt459_reg[ BT459_REG_CCOLOR_2] >> 4) & 0xf; break; case 3: pixelvalue = 15 - ((d->bt459_reg[ BT459_REG_CCOLOR_2] >> 4) & 0xf); break; } } win->cursor_pixels[y][x+i] = pixelvalue; #ifdef WITH_CURSOR_DEBUG printf("%i", color); #endif } } #ifdef WITH_CURSOR_DEBUG printf("\n"); #endif } #ifdef WITH_CURSOR_DEBUG printf("color 1,2,3 = 0x%02x, 0x%02x, 0x%02x\n", d->bt459_reg[BT459_REG_CCOLOR_1], d->bt459_reg[BT459_REG_CCOLOR_2], d->bt459_reg[BT459_REG_CCOLOR_3]); printf("\n"); #endif /* * Make sure the cursor is redrawn, if it is on: * * How does this work? Well, 0 is off, and non-zero is on, * but if the old and new differ, the cursor is redrawn. * (Hopefully this will "never" overflow.) */ if (d->cursor_on) d->cursor_on ++; } #endif } /* * bt459_update_cursor_position(): */ static void bt459_update_cursor_position(struct bt459_data *d, int old_cursor_on) { int new_cursor_x = (d->bt459_reg[BT459_REG_CXLO] & 255) + ((d->bt459_reg[BT459_REG_CXHI] & 255) << 8) - d->cursor_x_add; int new_cursor_y = (d->bt459_reg[BT459_REG_CYLO] & 255) + ((d->bt459_reg[BT459_REG_CYHI] & 255) << 8) - d->cursor_y_add; if (new_cursor_x != d->cursor_x || new_cursor_y != d->cursor_y || d->cursor_on != old_cursor_on) { int on; d->cursor_x = new_cursor_x; d->cursor_y = new_cursor_y; if (!quiet_mode) debug("[ bt459: cursor = %03i,%03i ]\n", d->cursor_x, d->cursor_y); on = d->cursor_on; if (d->cursor_xsize == 0 || d->cursor_ysize == 0) on = 0; dev_fb_setcursor(d->vfb_data, d->cursor_x, d->cursor_y, on, d->cursor_xsize, d->cursor_ysize); } } DEVICE_TICK(bt459) { struct bt459_data *d = (struct bt459_data *) extra; int old_cursor_on = d->cursor_on; if (d->need_to_update_cursor_shape) { d->need_to_update_cursor_shape = 0; bt459_update_X_cursor(cpu, d); bt459_update_cursor_position(d, old_cursor_on); } if (d->need_to_redraw_whole_screen) { d->vfb_data->update_x1 = 0; d->vfb_data->update_x2 = d->vfb_data->xsize - 1; d->vfb_data->update_y1 = 0; d->vfb_data->update_y2 = d->vfb_data->ysize - 1; d->need_to_redraw_whole_screen = 0; } /* * Vertical retrace interrupts. (This hack is kind of ugly.) * Once every 'interrupt_time_reset_value', the interrupt is * asserted. It is acked either manually (by someone reading * a normal BT459 register or the Interrupt ack register), * or after another tick has passed. (This is to prevent * lockups from unhandled interrupts.) */ if (d->type != BT459_PX && d->interrupts_enable) { d->interrupt_time --; if (d->interrupt_time < 0) { d->interrupt_time = d->interrupt_time_reset_value; INTERRUPT_ASSERT(d->irq); } else INTERRUPT_DEASSERT(d->irq); } } DEVICE_ACCESS(bt459_irq) { struct bt459_data *d = (struct bt459_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); #ifdef BT459_DEBUG fatal("[ bt459: IRQ ack ]\n"); #endif d->interrupts_enable = 1; INTERRUPT_DEASSERT(d->irq); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(bt459) { struct bt459_data *d = (struct bt459_data *) extra; uint64_t idata = 0, odata = 0; int btaddr, old_cursor_on = d->cursor_on, modified; idata = memory_readmax64(cpu, data, len); #ifdef BT459_DEBUG if (writeflag == MEM_WRITE) fatal("[ bt459: write to addr 0x%02x: %08x ]\n", (int)relative_addr, (int)idata); #endif /* * Vertical retrace interrupts are acked either by * accessing a normal BT459 register, or the irq register, * or by simply "missing" it. */ INTERRUPT_DEASSERT(d->irq); /* ID register is read-only, should always be 0x4a or 0x4a4a4a: */ if (d->planes == 24) d->bt459_reg[BT459_REG_ID] = 0x4a4a4a; else { /* * TODO: Is it really 0x4a, or 0x4a0000? * Ultrix panics with a "bad VDAC ID" message if 0x4a * is returned. */ d->bt459_reg[BT459_REG_ID] = 0x4a0000; } btaddr = ((d->cur_addr_hi << 8) + d->cur_addr_lo) % DEV_BT459_NREGS; /* Read from/write to the bt459: */ switch (relative_addr) { case 0x00: /* Low byte of address: */ if (writeflag == MEM_WRITE) { if (!quiet_mode) debug("[ bt459: write to Low Address Byte, " "0x%02x ]\n", (int)idata); d->cur_addr_lo = idata; d->palette_sub_offset = 0; } else { odata = d->cur_addr_lo; if (!quiet_mode) debug("[ bt459: read from Low Address Byte: " "0x%0x ]\n", (int)odata); } break; case 0x04: /* High byte of address: */ if (writeflag == MEM_WRITE) { if (!quiet_mode) debug("[ bt459: write to High Address Byte, " "0x%02x ]\n", (int)idata); d->cur_addr_hi = idata; d->palette_sub_offset = 0; } else { odata = d->cur_addr_hi; if (!quiet_mode) debug("[ bt459: read from High Address Byte: " "0x%0x ]\n", (int)odata); } break; case 0x08: /* Register access: */ if (writeflag == MEM_WRITE) { if (!quiet_mode) debug("[ bt459: write to BT459 register " "0x%04x, value 0x%02x ]\n", btaddr, (int)idata); modified = (d->bt459_reg[btaddr] != idata); d->bt459_reg[btaddr] = idata; switch (btaddr) { case BT459_REG_CCOLOR_1: case BT459_REG_CCOLOR_2: case BT459_REG_CCOLOR_3: if (modified) d->need_to_update_cursor_shape = 1; break; case BT459_REG_PRM: /* * NetBSD writes 0x00 to this register to * blank the screen (video off), and 0xff * to turn the screen on. */ switch (idata & 0xff) { case 0: d->video_on = 0; memset(d->rgb_palette, 0, 256*3); d->need_to_redraw_whole_screen = 1; debug("[ bt459: video OFF ]\n"); break; default:d->video_on = 1; memcpy(d->rgb_palette, d->local_rgb_palette, 256*3); d->need_to_redraw_whole_screen = 1; debug("[ bt459: video ON ]\n"); } break; case BT459_REG_CCR: /* Cursor control register: */ switch (idata & 0xff) { case 0x00: d->cursor_on = 0; break; case 0xc0: case 0xc1: d->cursor_on = 1; break; default: fatal("[ bt459: unimplemented CCR " "value 0x%08x ]\n", (int)idata); } if (modified) d->need_to_update_cursor_shape = 1; break; default: if (btaddr < 0x100) fatal("[ bt459: write to BT459 " "register 0x%04x, value 0x%02x ]\n", btaddr, (int)idata); } /* Write to cursor bitmap: */ if (btaddr >= BT459_REG_CRAM_BASE && modified) d->need_to_update_cursor_shape = 1; } else { odata = d->bt459_reg[btaddr]; /* Perhaps this hack is not necessary: */ if (btaddr == BT459_REG_ID && len==1) odata = (odata >> 16) & 255; if (!quiet_mode) debug("[ bt459: read from BT459 register " "0x%04x, value 0x%02x ]\n", btaddr, (int)odata); } /* Go to next register: */ d->cur_addr_lo ++; if (d->cur_addr_lo == 0) d->cur_addr_hi ++; break; case 0xc: /* Color map: */ if (writeflag == MEM_WRITE) { idata &= 255; if (!quiet_mode) debug("[ bt459: write to BT459 colormap " "0x%04x subaddr %i, value 0x%02x ]\n", btaddr, d->palette_sub_offset, (int)idata); if (btaddr < 0x100) { if (d->video_on && d->local_rgb_palette[(btaddr & 0xff) * 3 + d->palette_sub_offset] != idata) d->need_to_redraw_whole_screen = 1; /* * Actually, the palette should only be * updated after the third write, * but this should probably work fine too: */ d->local_rgb_palette[(btaddr & 0xff) * 3 + d->palette_sub_offset] = idata; if (d->video_on) d->rgb_palette[(btaddr & 0xff) * 3 + d->palette_sub_offset] = idata; } } else { if (btaddr < 0x100) odata = d->local_rgb_palette[(btaddr & 0xff) * 3 + d->palette_sub_offset]; if (!quiet_mode) debug("[ bt459: read from BT459 colormap " "0x%04x subaddr %i, value 0x%02x ]\n", btaddr, d->palette_sub_offset, (int)odata); } d->palette_sub_offset ++; if (d->palette_sub_offset >= 3) { d->palette_sub_offset = 0; d->cur_addr_lo ++; if (d->cur_addr_lo == 0) d->cur_addr_hi ++; } break; default: if (writeflag == MEM_WRITE) { debug("[ bt459: unimplemented write to address 0x%x, " "data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { debug("[ bt459: unimplemented read from address " "0x%x ]\n", (int)relative_addr); } } bt459_update_cursor_position(d, old_cursor_on); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); #ifdef BT459_DEBUG if (writeflag == MEM_READ) fatal("[ bt459: read from addr 0x%02x: %08x ]\n", (int)relative_addr, (int)idata); #endif return 1; } /* * dev_bt459_init(): */ void dev_bt459_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, uint64_t baseaddr_irq, struct vfb_data *vfb_data, int planes, const char *irq_path, int type) { struct bt459_data *d; CHECK_ALLOCATION(d = (struct bt459_data *) malloc(sizeof(struct bt459_data))); memset(d, 0, sizeof(struct bt459_data)); INTERRUPT_CONNECT(irq_path, d->irq); d->vfb_data = vfb_data; d->rgb_palette = vfb_data->rgb_palette; d->planes = planes; d->type = type; d->cursor_x = -1; d->cursor_y = -1; d->cursor_xsize = d->cursor_ysize = 0; /* anything */ d->video_on = 1; /* * These offsets are based on those mentioned in NetBSD, * and then adjusted to look good with both NetBSD and * Ultrix: */ switch (d->type) { case BT459_PX: d->cursor_x_add = 370; d->cursor_y_add = 37; break; case BT459_BA: d->cursor_x_add = 220; d->cursor_y_add = 35; break; case BT459_BBA: if (vfb_data->xsize == 1280) { /* 1280x1024: */ d->cursor_x_add = 368; d->cursor_y_add = 38; } else { /* 1024x864: */ d->cursor_x_add = 220; d->cursor_y_add = 35; } break; } d->interrupt_time_reset_value = 500; memory_device_register(mem, "bt459", baseaddr, DEV_BT459_LENGTH, dev_bt459_access, (void *)d, DM_DEFAULT, NULL); if (baseaddr_irq != 0) memory_device_register(mem, "bt459_irq", baseaddr_irq, 0x10000, dev_bt459_irq_access, (void *)d, DM_DEFAULT, NULL); machine_add_tickfunction(machine, dev_bt459_tick, d, BT459_TICK_SHIFT); } gxemul-0.6.1/src/devices/dev_mvme187.cc000644 001750 001750 00000010760 13402411502 020013 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: MVME187-specific devices and control registers */ #include #include #include #include "cpu.h" #include "device.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/mvme187.h" #include "thirdparty/mvme_memcreg.h" #include "thirdparty/m8820x.h" struct mvme187_data { struct memcreg memcreg; }; DEVICE_ACCESS(mvme187_memc) { uint64_t idata = 0, odata = 0; struct mvme187_data *d = (struct mvme187_data *) extra; int controller = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (relative_addr & 0x100) { controller = 1; relative_addr &= ~0x100; } odata = ((uint8_t*)&d->memcreg)[relative_addr]; switch (relative_addr) { case 0x00: /* chipid */ case 0x04: /* chiprev */ break; case 0x08: /* memconf */ if (writeflag == MEM_WRITE) { fatal("mvme187_memc: Write to relative_addr %i not yet" " implemented!\n"); exit(1); } break; default:fatal("[ mvme187_memc: unimplemented %s offset 0x%x", writeflag == MEM_WRITE? "write to" : "read from", (int) relative_addr); if (writeflag == MEM_WRITE) fatal(": 0x%x", (int)idata); fatal(" ]\n"); exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(mvme187) { struct mvme187_data *d; char tmpstr[300]; struct m8820x_cmmu *cmmu; int size_per_memc, r; CHECK_ALLOCATION(d = (struct mvme187_data *) malloc(sizeof(struct mvme187_data))); memset(d, 0, sizeof(struct mvme187_data)); /* * Two memory controllers per MVME187 machine: */ size_per_memc = devinit->machine->physical_ram_in_mb / 2 * 1048576; for (r=0; ; r++) { if (MEMC_MEMCONF_RTOB(r) > size_per_memc) { r--; break; } } d->memcreg.memc_chipid = MEMC_CHIPID; d->memcreg.memc_chiprev = 1; d->memcreg.memc_memconf = r; memory_device_register(devinit->machine->memory, devinit->name, MVME187_MEM_CTLR, 0x200, dev_mvme187_memc_access, (void *)d, DM_DEFAULT, NULL); /* Instruction CMMU: */ CHECK_ALLOCATION(cmmu = (struct m8820x_cmmu *) malloc(sizeof(struct m8820x_cmmu))); memset(cmmu, 0, sizeof(struct m8820x_cmmu)); devinit->machine->cpus[devinit->machine->bootstrap_cpu]-> cd.m88k.cmmu[0] = cmmu; /* This is a 88200, revision 9: */ cmmu->reg[CMMU_IDR] = (M88200_ID << 21) | (9 << 16); snprintf(tmpstr, sizeof(tmpstr), "m8820x addr=0x%x addr2=0", MVME187_SBC_CMMU_I); device_add(devinit->machine, tmpstr); /* ... and data CMMU: */ CHECK_ALLOCATION(cmmu = (struct m8820x_cmmu *) malloc(sizeof(struct m8820x_cmmu))); memset(cmmu, 0, sizeof(struct m8820x_cmmu)); devinit->machine->cpus[devinit->machine->bootstrap_cpu]-> cd.m88k.cmmu[1] = cmmu; /* This is also a 88200, revision 9: */ cmmu->reg[CMMU_IDR] = (M88200_ID << 21) | (9 << 16); cmmu->batc[8] = BATC8; cmmu->batc[9] = BATC9; snprintf(tmpstr, sizeof(tmpstr), "m8820x addr=0x%x addr2=1", MVME187_SBC_CMMU_D); device_add(devinit->machine, tmpstr); return 1; } gxemul-0.6.1/src/devices/dev_gc.cc000644 001750 001750 00000015647 13402411502 017211 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Grand Central Interrupt controller (used by MacPPC) */ #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #define DEV_GC_LENGTH 0x100 struct gc_data { struct interrupt cpu_irq; uint32_t status_hi; uint32_t status_lo; uint32_t enable_hi; uint32_t enable_lo; }; void gc_hi_interrupt_assert(struct interrupt *interrupt) { struct gc_data *d = (struct gc_data *) interrupt->extra; d->status_hi |= interrupt->line; if (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi) INTERRUPT_ASSERT(d->cpu_irq); } void gc_hi_interrupt_deassert(struct interrupt *interrupt) { struct gc_data *d = (struct gc_data *) interrupt->extra; d->status_hi &= ~interrupt->line; if (!(d->status_lo & d->enable_lo || d->status_hi & d->enable_hi)) INTERRUPT_DEASSERT(d->cpu_irq); } void gc_lo_interrupt_assert(struct interrupt *interrupt) { struct gc_data *d = (struct gc_data *) interrupt->extra; d->status_lo |= interrupt->line; if (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi) INTERRUPT_ASSERT(d->cpu_irq); } void gc_lo_interrupt_deassert(struct interrupt *interrupt) { struct gc_data *d = (struct gc_data *) interrupt->extra; d->status_lo &= ~interrupt->line; if (!(d->status_lo & d->enable_lo || d->status_hi & d->enable_hi)) INTERRUPT_DEASSERT(d->cpu_irq); } DEVICE_ACCESS(gc) { struct gc_data *d = (struct gc_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { #if 0 #define INT_STATE_REG_H (interrupt_reg + 0x00) #define INT_ENABLE_REG_H (interrupt_reg + 0x04) #define INT_CLEAR_REG_H (interrupt_reg + 0x08) #define INT_LEVEL_REG_H (interrupt_reg + 0x0c) #define INT_STATE_REG_L (interrupt_reg + 0x10) #define INT_ENABLE_REG_L (interrupt_reg + 0x14) #define INT_CLEAR_REG_L (interrupt_reg + 0x18) #define INT_LEVEL_REG_L (interrupt_reg + 0x1c) #endif case 0x10: if (writeflag == MEM_READ) odata = d->status_hi & d->enable_hi; break; case 0x14: if (writeflag == MEM_READ) odata = d->enable_hi; else { int old_assert = (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi); int new_assert; d->enable_hi = idata; new_assert = (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi); if (old_assert && !new_assert) INTERRUPT_DEASSERT(d->cpu_irq); else if (!old_assert && new_assert) INTERRUPT_ASSERT(d->cpu_irq); } break; case 0x18: if (writeflag == MEM_WRITE) { int old_assert = (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi); int new_assert; d->status_hi &= ~idata; new_assert = (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi); if (old_assert && !new_assert) INTERRUPT_DEASSERT(d->cpu_irq); else if (!old_assert && new_assert) INTERRUPT_ASSERT(d->cpu_irq); } break; case 0x20: if (writeflag == MEM_READ) odata = d->status_lo & d->enable_lo; break; case 0x24: if (writeflag == MEM_READ) odata = d->enable_lo; else { int old_assert = (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi); int new_assert; d->enable_lo = idata; new_assert = (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi); if (old_assert && !new_assert) INTERRUPT_DEASSERT(d->cpu_irq); else if (!old_assert && new_assert) INTERRUPT_ASSERT(d->cpu_irq); } break; case 0x28: if (writeflag == MEM_WRITE) { int old_assert = (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi); int new_assert; d->status_lo &= ~idata; new_assert = (d->status_lo & d->enable_lo || d->status_hi & d->enable_hi); if (old_assert && !new_assert) INTERRUPT_DEASSERT(d->cpu_irq); else if (!old_assert && new_assert) INTERRUPT_ASSERT(d->cpu_irq); } break; case 0x1c: case 0x2c: /* Avoid a debug message. */ break; default:if (writeflag == MEM_WRITE) { fatal("[ gc: unimplemented write to " "offset 0x%x: data=0x%x ]\n", (int) relative_addr, (int)idata); } else { fatal("[ gc: unimplemented read from " "offset 0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(gc) { struct gc_data *d; int i; CHECK_ALLOCATION(d = (struct gc_data *) malloc(sizeof(struct gc_data))); memset(d, 0, sizeof(struct gc_data)); /* Connect to the CPU interrupt pin: */ INTERRUPT_CONNECT(devinit->interrupt_path, d->cpu_irq); /* * Register the 64 Grand Central interrupts (32 lo, 32 hi): */ for (i=0; i<32; i++) { struct interrupt templ; char n[300]; snprintf(n, sizeof(n), "%s.gc.lo.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = 1 << i; templ.name = n; templ.extra = d; templ.interrupt_assert = gc_lo_interrupt_assert; templ.interrupt_deassert = gc_lo_interrupt_deassert; interrupt_handler_register(&templ); snprintf(n, sizeof(n), "%s.gc.hi.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = 1 << i; templ.name = n; templ.extra = d; templ.interrupt_assert = gc_hi_interrupt_assert; templ.interrupt_deassert = gc_hi_interrupt_deassert; interrupt_handler_register(&templ); } memory_device_register(devinit->machine->memory, "gc", devinit->addr, DEV_GC_LENGTH, dev_gc_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_mc146818.cc000644 001750 001750 00000044214 13402411502 017703 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: MC146818 real-time clock * * (DS1687 as used in some other machines is also similar to the MC146818.) * * This device contains Date/time, the machine's ethernet address (on * DECstation 3100), and can cause periodic (hardware) interrupts. * * NOTE: Many register offsets are multiplied by 4 in this code; this is * because I originally wrote it for DECstation 3100 emulation, where the * registered are spaced that way. */ #include #include #include #include #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "timer.h" #include "thirdparty/mc146818reg.h" #define to_bcd(x) ( ((x)/10) * 16 + ((x)%10) ) #define from_bcd(x) ( ((x)>>4) * 10 + ((x)&15) ) /* #define MC146818_DEBUG */ #define MC146818_TICK_SHIFT 14 /* 256 on DECstation, SGI uses reg at 72*4 as the Century */ #define N_REGISTERS 1024 struct mc_data { int access_style; int last_addr; int register_choice; int reg[N_REGISTERS]; int addrdiv; int use_bcd; int timebase_hz; int interrupt_hz; int old_interrupt_hz; struct interrupt irq; struct timer *timer; volatile int pending_timer_interrupts; int previous_second; int n_seconds_elapsed; int uip_threshold; int ugly_netbsd_prep_hack_done; int ugly_netbsd_prep_hack_sec; }; /* * Ugly hack to fool NetBSD/prep to accept the clock. (See mcclock_isa_match * in NetBSD's arch/prep/isa/mcclock_isa.c for details.) */ #define NETBSD_HACK_INIT 0 #define NETBSD_HACK_FIRST_1 1 #define NETBSD_HACK_FIRST_2 2 #define NETBSD_HACK_SECOND_1 3 #define NETBSD_HACK_SECOND_2 4 #define NETBSD_HACK_DONE 5 /* * timer_tick(): * * Called d->interrupt_hz times per (real-world) second. */ static void timer_tick(struct timer *timer, void *extra) { struct mc_data *d = (struct mc_data *) extra; d->pending_timer_interrupts ++; } DEVICE_TICK(mc146818) { struct mc_data *d = (struct mc_data *) extra; int pti = d->pending_timer_interrupts; if ((d->reg[MC_REGB * 4] & MC_REGB_PIE) && pti > 0) { #if 0 /* For debugging, to see how much the interrupts are lagging behind the real clock: */ { static int x = 0; if (++x == 1) { x = 0; printf("%i ", pti); fflush(stdout); } } #endif INTERRUPT_ASSERT(d->irq); d->reg[MC_REGC * 4] |= MC_REGC_PF; } if (d->reg[MC_REGC * 4] & MC_REGC_UF || d->reg[MC_REGC * 4] & MC_REGC_AF || d->reg[MC_REGC * 4] & MC_REGC_PF) d->reg[MC_REGC * 4] |= MC_REGC_IRQF; } /* * dev_mc146818_jazz_access(): * * It seems like JAZZ machines accesses the mc146818 by writing one byte to * 0x90000070 and then reading or writing another byte at 0x......0004000. */ DEVICE_ACCESS(mc146818_jazz) { struct mc_data *d = (struct mc_data *) extra; #ifdef MC146818_DEBUG if (writeflag == MEM_WRITE) { int i; fatal("[ mc146818_jazz: write to addr=0x%04x: ", (int)relative_addr); for (i=0; ilast_addr = data[0]; return 1; } else { data[0] = d->last_addr; return 1; } } /* * mc146818_update_time(): * * This function updates the MC146818 registers by reading * the host's clock. */ static void mc146818_update_time(struct mc_data *d) { struct tm *tmp; time_t timet; timet = time(NULL); tmp = gmtime(&timet); d->reg[4 * MC_SEC] = tmp->tm_sec; d->reg[4 * MC_MIN] = tmp->tm_min; d->reg[4 * MC_HOUR] = tmp->tm_hour; d->reg[4 * MC_DOW] = tmp->tm_wday + 1; d->reg[4 * MC_DOM] = tmp->tm_mday; d->reg[4 * MC_MONTH] = tmp->tm_mon + 1; d->reg[4 * MC_YEAR] = tmp->tm_year; /* * Special hacks for emulating the behaviour of various machines: */ switch (d->access_style) { case MC146818_ALGOR: /* * NetBSD/evbmips sources indicate that the Algor year base * is 1920. This makes the time work with NetBSD in Malta * emulation. However, for Linux, commenting out this line * works better. (TODO: Find a way to make both work?) */ d->reg[4 * MC_YEAR] += 80; break; case MC146818_ARC_NEC: d->reg[4 * MC_YEAR] += (0x18 - 104); break; case MC146818_CATS: d->reg[4 * MC_YEAR] %= 100; break; case MC146818_SGI: /* * NetBSD/sgimips assumes data in BCD format. * Also, IRIX stores the year value in a weird * format, according to ../arch/sgimips/sgimips/clockvar.h * in NetBSD: * * "If year < 1985, store (year - 1970), else * (year - 1940). This matches IRIX semantics." * * Another rule: It seems that a real SGI IP32 box * uses the value 5 for the year 2005. */ d->reg[4 * MC_YEAR] = d->reg[4 * MC_YEAR] >= 100 ? (d->reg[4 * MC_YEAR] - 100) : ( d->reg[4 * MC_YEAR] < 85 ? (d->reg[4 * MC_YEAR] - 30 + 40) : (d->reg[4 * MC_YEAR] - 40) ); /* Century: */ d->reg[72 * 4] = 19 + (tmp->tm_year / 100); break; case MC146818_DEC: /* * DECstations must have 72 or 73 in the * Year field, or Ultrix screems. (Weird.) */ d->reg[4 * MC_YEAR] = 72; /* * Linux on DECstation stores the year in register 63, * but no other DECstation OS does? (Hm.) */ d->reg[4 * 63] = tmp->tm_year - 100; break; } if (d->use_bcd) { d->reg[4 * MC_SEC] = to_bcd(d->reg[4 * MC_SEC]); d->reg[4 * MC_MIN] = to_bcd(d->reg[4 * MC_MIN]); d->reg[4 * MC_HOUR] = to_bcd(d->reg[4 * MC_HOUR]); d->reg[4 * MC_DOW] = to_bcd(d->reg[4 * MC_DOW]); d->reg[4 * MC_DOM] = to_bcd(d->reg[4 * MC_DOM]); d->reg[4 * MC_MONTH] = to_bcd(d->reg[4 * MC_MONTH]); d->reg[4 * MC_YEAR] = to_bcd(d->reg[4 * MC_YEAR]); /* Used by Linux on DECstation: (Hm) */ d->reg[4 * 63] = to_bcd(d->reg[4 * 63]); /* Used on SGI: */ d->reg[4 * 72] = to_bcd(d->reg[4 * 72]); } } DEVICE_ACCESS(mc146818) { struct mc_data *d = (struct mc_data *) extra; struct tm *tmp; time_t timet; size_t i; /* NOTE/TODO: This access function only handles 8-bit accesses! */ relative_addr /= d->addrdiv; /* Different ways of accessing the registers: */ switch (d->access_style) { case MC146818_ALGOR: case MC146818_CATS: case MC146818_PC_CMOS: if ((relative_addr & 1) == 0x00) { if (writeflag == MEM_WRITE) { d->last_addr = data[0]; return 1; } else { data[0] = d->last_addr; return 1; } } else relative_addr = d->last_addr * 4; break; case MC146818_ARC_NEC: if (relative_addr == 0x01) { if (writeflag == MEM_WRITE) { d->last_addr = data[0]; return 1; } else { data[0] = d->last_addr; return 1; } } else if (relative_addr == 0x00) relative_addr = d->last_addr * 4; else { fatal("[ mc146818: not accessed as an " "MC146818_ARC_NEC device! ]\n"); } break; case MC146818_ARC_JAZZ: /* See comment for dev_mc146818_jazz_access(). */ relative_addr = d->last_addr * 4; break; case MC146818_DEC: case MC146818_SGI: /* * This device was originally written for DECstation * emulation, so no changes are necessary for that access * style. * * SGI access bytes 0x0..0xd at offsets 0x0yz..0xdyz, where yz * should be ignored. It works _almost_ as DEC, if offsets are * divided by 0x40. */ break; case MC146818_PMPPC: relative_addr *= 4; break; default: ; } #ifdef MC146818_DEBUG if (writeflag == MEM_WRITE) { fatal("[ mc146818: write to addr=0x%04x (len %i): ", (int)relative_addr, (int)len); for (i=0; ireg[MC_REGC * 4] &= ~MC_REGC_UF; if (tmp->tm_sec != d->previous_second) { d->n_seconds_elapsed ++; d->previous_second = tmp->tm_sec; } if (d->n_seconds_elapsed > d->uip_threshold) { d->n_seconds_elapsed = 0; d->reg[MC_REGA * 4] |= MC_REGA_UIP; d->reg[MC_REGC * 4] |= MC_REGC_UF; d->reg[MC_REGC * 4] |= MC_REGC_IRQF; /* For some reason, some Linux/DECstation KN04 kernels want the PF (periodic flag) bit set, even though interrupts are not enabled? */ d->reg[MC_REGC * 4] |= MC_REGC_PF; } else d->reg[MC_REGA * 4] &= ~MC_REGA_UIP; } /* RTC data is in either BCD format or binary: */ if (d->use_bcd) d->reg[MC_REGB * 4] &= ~(1 << 2); else d->reg[MC_REGB * 4] |= (1 << 2); /* RTC date/time is always Valid: */ d->reg[MC_REGD * 4] |= MC_REGD_VRT; if (writeflag == MEM_WRITE) { /* WRITE: */ switch (relative_addr) { case MC_REGA*4: if ((data[0] & MC_REGA_DVMASK) == MC_BASE_32_KHz) d->timebase_hz = 32000; if ((data[0] & MC_REGA_DVMASK) == MC_BASE_1_MHz) d->timebase_hz = 1000000; if ((data[0] & MC_REGA_DVMASK) == MC_BASE_4_MHz) d->timebase_hz = 4000000; switch (data[0] & MC_REGA_RSMASK) { case MC_RATE_NONE: d->interrupt_hz = 0; break; case MC_RATE_1: if (d->timebase_hz == 32000) d->interrupt_hz = 256; else d->interrupt_hz = 32768; break; case MC_RATE_2: if (d->timebase_hz == 32000) d->interrupt_hz = 128; else d->interrupt_hz = 16384; break; case MC_RATE_8192_Hz: d->interrupt_hz = 8192; break; case MC_RATE_4096_Hz: d->interrupt_hz = 4096; break; case MC_RATE_2048_Hz: d->interrupt_hz = 2048; break; case MC_RATE_1024_Hz: d->interrupt_hz = 1024; break; case MC_RATE_512_Hz: d->interrupt_hz = 512; break; case MC_RATE_256_Hz: d->interrupt_hz = 256; break; case MC_RATE_128_Hz: d->interrupt_hz = 128; break; case MC_RATE_64_Hz: d->interrupt_hz = 64; break; case MC_RATE_32_Hz: d->interrupt_hz = 32; break; case MC_RATE_16_Hz: d->interrupt_hz = 16; break; case MC_RATE_8_Hz: d->interrupt_hz = 8; break; case MC_RATE_4_Hz: d->interrupt_hz = 4; break; case MC_RATE_2_Hz: d->interrupt_hz = 2; break; default:/* debug("[ mc146818: unimplemented " "MC_REGA RS: %i ]\n", data[0] & MC_REGA_RSMASK); */ ; } if (d->interrupt_hz != d->old_interrupt_hz) { debug("[ rtc changed to interrupt at %i Hz ]\n", d->interrupt_hz); d->old_interrupt_hz = d->interrupt_hz; if (d->timer == NULL) d->timer = timer_add(d->interrupt_hz, timer_tick, d); else timer_update_frequency(d->timer, d->interrupt_hz); } d->reg[MC_REGA * 4] = data[0] & (MC_REGA_RSMASK | MC_REGA_DVMASK); break; case MC_REGB*4: d->reg[MC_REGB*4] = data[0]; if (!(data[0] & MC_REGB_PIE)) { INTERRUPT_DEASSERT(d->irq); } /* debug("[ mc146818: write to MC_REGB, data[0] " "= 0x%02x ]\n", data[0]); */ break; case MC_REGC*4: d->reg[MC_REGC * 4] = data[0]; debug("[ mc146818: write to MC_REGC, data[0] = " "0x%02x ]\n", data[0]); break; case 0x128: d->reg[relative_addr] = data[0]; if (data[0] & 8) { int j; /* Used on SGI to power off the machine. */ fatal("[ md146818: power off ]\n"); for (j=0; jmachine->ncpus; j++) cpu->machine->cpus[j]->running = 0; cpu->machine-> exit_without_entering_debugger = 1; } break; default: d->reg[relative_addr] = data[0]; debug("[ mc146818: unimplemented write to " "relative_addr = %08lx: ", (long)relative_addr); for (i=0; iugly_netbsd_prep_hack_done < NETBSD_HACK_DONE) { d->ugly_netbsd_prep_hack_done ++; switch (d->ugly_netbsd_prep_hack_done) { case NETBSD_HACK_FIRST_1: d->ugly_netbsd_prep_hack_sec = from_bcd(d->reg[relative_addr]); break; case NETBSD_HACK_FIRST_2: d->reg[relative_addr] = to_bcd( d->ugly_netbsd_prep_hack_sec); break; case NETBSD_HACK_SECOND_1: case NETBSD_HACK_SECOND_2: d->reg[relative_addr] = to_bcd((1 + d->ugly_netbsd_prep_hack_sec) % 60); break; } } case 4 * MC_MIN: case 4 * MC_HOUR: case 4 * MC_DOW: case 4 * MC_DOM: case 4 * MC_MONTH: case 4 * MC_YEAR: case 4 * 63: /* 63 is used by Linux on DECstation */ case 4 * 72: /* 72 is Century, on SGI (DS1687) */ /* * If the SET bit is set, then we don't automatically * update the values. Otherwise, we update them by * reading from the host's clock: */ if (d->reg[MC_REGB * 4] & MC_REGB_SET) break; if (d->ugly_netbsd_prep_hack_done >= NETBSD_HACK_DONE) mc146818_update_time(d); break; case 4 * MC_REGA: break; case 4 * MC_REGC: /* Interrupt ack. */ /* NOTE: Acking is done below, _after_ the register has been read. */ break; default:debug("[ mc146818: read from relative_addr = " "%04x ]\n", (int)relative_addr); } data[0] = d->reg[relative_addr]; if (relative_addr == MC_REGC*4) { INTERRUPT_DEASSERT(d->irq); /* * Acknowledging an interrupt decreases the * number of pending "real world" timer ticks. */ if (d->reg[MC_REGC * 4] & MC_REGC_PF && d->pending_timer_interrupts > 0) d->pending_timer_interrupts --; d->reg[MC_REGC * 4] = 0x00; } } #ifdef MC146818_DEBUG if (writeflag == MEM_READ) { fatal("[ mc146818: read from addr=0x%04x (len %i): ", (int)relative_addr, (int)len); for (i=0; iaccess_style = access_style; d->addrdiv = addrdiv; INTERRUPT_CONNECT(irq_path, d->irq); d->use_bcd = 0; switch (access_style) { case MC146818_SGI: case MC146818_PC_CMOS: case MC146818_PMPPC: d->use_bcd = 1; } if (machine->machine_type != MACHINE_PREP) { /* NetBSD/prep has a really ugly clock detection code; no other machines/OSes don't need this. */ d->ugly_netbsd_prep_hack_done = NETBSD_HACK_DONE; } if (access_style == MC146818_DEC) { /* Station Ethernet Address, on DECstation 3100: */ for (i=0; i<6; i++) ether_address[i] = 0x10 * (i+1); d->reg[0x01] = ether_address[0]; d->reg[0x05] = ether_address[1]; d->reg[0x09] = ether_address[2]; d->reg[0x0d] = ether_address[3]; d->reg[0x11] = ether_address[4]; d->reg[0x15] = ether_address[5]; /* TODO: 19, 1d, 21, 25 = checksum bytes 1,2,2,1 resp. */ d->reg[0x29] = ether_address[5]; d->reg[0x2d] = ether_address[4]; d->reg[0x31] = ether_address[3]; d->reg[0x35] = ether_address[2]; d->reg[0x39] = ether_address[1]; d->reg[0x3d] = ether_address[1]; d->reg[0x41] = ether_address[0]; d->reg[0x45] = ether_address[1]; d->reg[0x49] = ether_address[2]; d->reg[0x4d] = ether_address[3]; d->reg[0x51] = ether_address[4]; d->reg[0x55] = ether_address[5]; /* TODO: 59, 5d = checksum bytes 1,2 resp. */ d->reg[0x61] = 0xff; d->reg[0x65] = 0x00; d->reg[0x69] = 0x55; d->reg[0x6d] = 0xaa; d->reg[0x71] = 0xff; d->reg[0x75] = 0x00; d->reg[0x79] = 0x55; d->reg[0x7d] = 0xaa; /* Battery valid, for DECstations */ d->reg[0xf8] = 1; } /* * uip_threshold should ideally be 1, but when Linux polls the UIP bit * it looses speed. This hack gives Linux the impression that the cpu * is uip_threshold times faster than the slow clock it would * otherwise detect. * * TODO: Find out if this messes up Sprite emulation; if so, then * this hack has to be removed. */ d->uip_threshold = 8; if (access_style == MC146818_ARC_JAZZ) memory_device_register(mem, "mc146818_jazz", 0x90000070ULL, 1, dev_mc146818_jazz_access, d, DM_DEFAULT, NULL); dev_len = DEV_MC146818_LENGTH; switch (access_style) { case MC146818_CATS: case MC146818_PC_CMOS: dev_len = 2; break; case MC146818_SGI: dev_len = 0x400; } memory_device_register(mem, "mc146818", baseaddr, dev_len * addrdiv, dev_mc146818_access, d, DM_DEFAULT, NULL); mc146818_update_time(d); machine_add_tickfunction(machine, dev_mc146818_tick, d, MC146818_TICK_SHIFT); } gxemul-0.6.1/src/devices/dev_vr41xx.cc000644 001750 001750 00000053414 13402411502 017766 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: VR41xx (VR4122 and VR4131) misc functions * * This is just a big hack. * * TODO: Implement more functionality some day. */ #include #include #include #include "console.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "timer.h" #include "thirdparty/bcureg.h" #include "thirdparty/vripreg.h" #include "thirdparty/vrkiureg.h" #include "thirdparty/vr_rtcreg.h" /* #define debug fatal */ #define DEV_VR41XX_TICKSHIFT 14 #define DEV_VR41XX_LENGTH 0x800 /* TODO? */ struct vr41xx_data { struct interrupt cpu_irq; /* Connected to MIPS irq 2 */ int cpumodel; /* Model nr, e.g. 4121 */ /* KIU: */ int kiu_console_handle; uint32_t kiu_offset; struct interrupt kiu_irq; int kiu_int_assert; int old_kiu_int_assert; int d0, d1, d2, d3, d4, d5; int dont_clear_next; int escape_state; /* Timer: */ int pending_timer_interrupts; struct interrupt timer_irq; struct timer *timer; /* See icureg.h in NetBSD for more info. */ uint16_t sysint1; uint16_t msysint1; uint16_t giuint; uint16_t giumask; uint16_t sysint2; uint16_t msysint2; struct interrupt giu_irq; }; /* * vr41xx_vrip_interrupt_assert(): * vr41xx_vrip_interrupt_deassert(): */ void vr41xx_vrip_interrupt_assert(struct interrupt *interrupt) { struct vr41xx_data *d = (struct vr41xx_data *) interrupt->extra; int line = interrupt->line; if (line < 16) d->sysint1 |= (1 << line); else d->sysint2 |= (1 << (line-16)); if ((d->sysint1 & d->msysint1) | (d->sysint2 & d->msysint2)) INTERRUPT_ASSERT(d->cpu_irq); } void vr41xx_vrip_interrupt_deassert(struct interrupt *interrupt) { struct vr41xx_data *d = (struct vr41xx_data *) interrupt->extra; int line = interrupt->line; if (line < 16) d->sysint1 &= ~(1 << line); else d->sysint2 &= ~(1 << (line-16)); if (!(d->sysint1 & d->msysint1) && !(d->sysint2 & d->msysint2)) INTERRUPT_DEASSERT(d->cpu_irq); } /* * vr41xx_giu_interrupt_assert(): * vr41xx_giu_interrupt_deassert(): */ void vr41xx_giu_interrupt_assert(struct interrupt *interrupt) { struct vr41xx_data *d = (struct vr41xx_data *) interrupt->extra; int line = interrupt->line; d->giuint |= (1 << line); if (d->giuint & d->giumask) INTERRUPT_ASSERT(d->giu_irq); } void vr41xx_giu_interrupt_deassert(struct interrupt *interrupt) { struct vr41xx_data *d = (struct vr41xx_data *) interrupt->extra; int line = interrupt->line; d->giuint &= ~(1 << line); if (!(d->giuint & d->giumask)) INTERRUPT_DEASSERT(d->giu_irq); } static void recalc_kiu_int_assert(struct cpu *cpu, struct vr41xx_data *d) { if (d->kiu_int_assert != d->old_kiu_int_assert) { d->old_kiu_int_assert = d->kiu_int_assert; if (d->kiu_int_assert != 0) INTERRUPT_ASSERT(d->kiu_irq); else INTERRUPT_DEASSERT(d->kiu_irq); } } /* * vr41xx_keytick(): */ static void vr41xx_keytick(struct cpu *cpu, struct vr41xx_data *d) { int keychange = 0; /* * Keyboard input: * * Hardcoded for MobilePro. (See NetBSD's hpckbdkeymap.h for * info on other keyboard layouts. mobilepro780_keytrans is the * one used here.) * * TODO: Make this work with "any" keyboard layout. * * ofs 0: * 8000='o' 4000='.' 2000=DOWN 1000=UP * 800=';' 400=''' 200='[' 100=? * 80='l' 40=CR 20=RIGHT 10=LEFT * 8='/' 4='\' 2=']' 1=SPACE * ofs 2: * 8000='a' 4000='s' 2000='d' 1000='f' * 800='`' 400='-' 200='=' 100=? * 80='z' 40='x' 20='c' 10='v' * 8=? 4=? 2=? * ofs 4: * 8000='9' 4000='0' 2000=? 1000=? * 800='b' 400='n' 200='m' 100=',' * 80='q' 40='w' 20='e' 10='r' * 8='5' 4='6' 2='7' 1='8' * ofs 6: * 8000=ESC 4000=DEL 2000=CAPS 1000=? * 800='t' 400='y' 200='u' 100='i' * 80='1' 40='2' 20='3' 10='4' * 8='g' 4='h' 2='j' 1='k' * ofs 8: * 200=ALT_L * 80= 40=TAB 20='p' 10=BS * 8= 4= 2= 1=ALT_R * ofs a: * 800=SHIFT 4=CTRL * * * The following are for the IBM WorkPad Z50: * (Not yet implemented, TODO) * * 00 f1 f3 f5 f7 f9 - - f11 * 08 f2 f4 f6 f8 f10 - - f12 * 10 ' [ - 0 p ; up / * 18 - - - 9 o l . - * 20 left ] = 8 i k , - * 28 h y 6 7 u j m n * 30 - bs num del - \ ent sp * 38 g t 5 4 r f v b * 40 - - - 3 e d c right * 48 - - - 2 w s x down * 50 esc tab ~ 1 q a z - * 58 menu Ls Lc Rc La Ra Rs - */ if (d->d0 != 0 || d->d1 != 0 || d->d2 != 0 || d->d3 != 0 || d->d4 != 0 || d->d5 != 0) keychange = 1; /* Release all keys: */ if (!d->dont_clear_next) { d->d0 = d->d1 = d->d2 = d->d3 = d->d4 = d->d5 = 0; } else d->dont_clear_next = 0; if (console_charavail(d->kiu_console_handle)) { char ch = console_readchar(d->kiu_console_handle); if (d->escape_state > 0) { switch (d->escape_state) { case 1: /* expecting a [ */ d->escape_state = 0; if (ch == '[') d->escape_state = 2; break; case 2: /* cursor keys etc: */ /* Ugly hack for Mobilepro770: */ if (cpu->machine->machine_subtype == MACHINE_HPCMIPS_NEC_MOBILEPRO_770) { switch (ch) { case 'A': d->d0 = 0x2000; break; case 'B': d->d0 = 0x20; break; case 'C': d->d0 = 0x1000; break; case 'D': d->d0 = 0x10; break; default: fatal("[ vr41xx kiu: unimpl" "emented escape 0x%02 ]\n", ch); } } else { switch (ch) { case 'A': d->d0 = 0x1000; break; case 'B': d->d0 = 0x2000; break; case 'C': d->d0 = 0x20; break; case 'D': d->d0 = 0x10; break; default: fatal("[ vr41xx kiu: unimpl" "emented escape 0x%02 ]\n", ch); } } d->escape_state = 0; } } else switch (ch) { case '+': console_makeavail(d->kiu_console_handle, '='); d->d5 = 0x800; break; case '_': console_makeavail(d->kiu_console_handle, '-'); d->d5 = 0x800; break; case '<': console_makeavail(d->kiu_console_handle, ','); d->d5 = 0x800; break; case '>': console_makeavail(d->kiu_console_handle, '.'); d->d5 = 0x800; break; case '{': console_makeavail(d->kiu_console_handle, '['); d->d5 = 0x800; break; case '}': console_makeavail(d->kiu_console_handle, ']'); d->d5 = 0x800; break; case ':': console_makeavail(d->kiu_console_handle, ';'); d->d5 = 0x800; break; case '"': console_makeavail(d->kiu_console_handle, '\''); d->d5 = 0x800; break; case '|': console_makeavail(d->kiu_console_handle, '\\'); d->d5 = 0x800; break; case '?': console_makeavail(d->kiu_console_handle, '/'); d->d5 = 0x800; break; case '!': console_makeavail(d->kiu_console_handle, '1'); d->d5 = 0x800; break; case '@': console_makeavail(d->kiu_console_handle, '2'); d->d5 = 0x800; break; case '#': console_makeavail(d->kiu_console_handle, '3'); d->d5 = 0x800; break; case '$': console_makeavail(d->kiu_console_handle, '4'); d->d5 = 0x800; break; case '%': console_makeavail(d->kiu_console_handle, '5'); d->d5 = 0x800; break; case '^': console_makeavail(d->kiu_console_handle, '6'); d->d5 = 0x800; break; case '&': console_makeavail(d->kiu_console_handle, '7'); d->d5 = 0x800; break; case '*': console_makeavail(d->kiu_console_handle, '8'); d->d5 = 0x800; break; case '(': console_makeavail(d->kiu_console_handle, '9'); d->d5 = 0x800; break; case ')': console_makeavail(d->kiu_console_handle, '0'); d->d5 = 0x800; break; case '1': d->d3 = 0x80; break; case '2': d->d3 = 0x40; break; case '3': d->d3 = 0x20; break; case '4': d->d3 = 0x10; break; case '5': d->d2 = 0x08; break; case '6': d->d2 = 0x04; break; case '7': d->d2 = 0x02; break; case '8': d->d2 = 0x01; break; case '9': d->d2 = 0x8000; break; case '0': d->d2 = 0x4000; break; case ';': d->d0 = 0x800; break; case '\'': d->d0 = 0x400; break; case '[': d->d0 = 0x200; break; case '/': d->d0 = 0x8; break; case '\\': d->d0 = 0x4; break; case ']': d->d0 = 0x2; break; case 'a': d->d1 = 0x8000; break; case 'b': d->d2 = 0x800; break; case 'c': d->d1 = 0x20; break; case 'd': d->d1 = 0x2000; break; case 'e': d->d2 = 0x20; break; case 'f': d->d1 = 0x1000; break; case 'g': d->d3 = 0x8; break; case 'h': d->d3 = 0x4; break; case 'i': d->d3 = 0x100; break; case 'j': d->d3 = 0x2; break; case 'k': d->d3 = 0x1; break; case 'l': d->d0 = 0x80; break; case 'm': d->d2 = 0x200; break; case 'n': d->d2 = 0x400; break; case 'o': d->d0 = 0x8000; break; case 'p': d->d4 = 0x20; break; case 'q': d->d2 = 0x80; break; case 'r': d->d2 = 0x10; break; case 's': d->d1 = 0x4000; break; case 't': d->d3 = 0x800; break; case 'u': d->d3 = 0x200; break; case 'v': d->d1 = 0x10; break; case 'w': d->d2 = 0x40; break; case 'x': d->d1 = 0x40; break; case 'y': d->d3 = 0x400; break; case 'z': d->d1 = 0x80; break; case ',': d->d2 = 0x100; break; case '.': d->d0 = 0x4000; break; case '-': d->d1 = 0x400; break; case '=': d->d1 = 0x200; break; case '\r': case '\n': d->d0 = 0x40; break; case ' ': d->d0 = 0x01; break; case '\b': d->d4 = 0x10; break; case 27: d->escape_state = 1; break; default: /* Shifted: */ if (ch >= 'A' && ch <= 'Z') { console_makeavail(d->kiu_console_handle, ch + 32); d->d5 = 0x800; d->dont_clear_next = 1; break; } /* CTRLed: */ if (ch >= 1 && ch <= 26) { console_makeavail(d->kiu_console_handle, ch + 96); d->d5 = 0x4; d->dont_clear_next = 1; break; } } if (d->escape_state == 0) keychange = 1; } if (keychange) { /* 4=lost data, 2=data complete, 1=key input detected */ d->kiu_int_assert |= 3; recalc_kiu_int_assert(cpu, d); } } /* * timer_tick(): */ static void timer_tick(struct timer *timer, void *extra) { struct vr41xx_data *d = (struct vr41xx_data *) extra; d->pending_timer_interrupts ++; } DEVICE_TICK(vr41xx) { struct vr41xx_data *d = (struct vr41xx_data *) extra; if (d->pending_timer_interrupts > 0) INTERRUPT_ASSERT(d->timer_irq); if (cpu->machine->x11_md.in_use) vr41xx_keytick(cpu, d); } /* * vr41xx_kiu(): * * Keyboard Interface Unit. Return value is "odata". * (See NetBSD's vrkiu.c for more info.) */ static uint64_t vr41xx_kiu(struct cpu *cpu, int ofs, uint64_t idata, int writeflag, struct vr41xx_data *d) { uint64_t odata = 0; switch (ofs) { case KIUDAT0: odata = d->d0; break; case KIUDAT1: odata = d->d1; break; case KIUDAT2: odata = d->d2; break; case KIUDAT3: odata = d->d3; break; case KIUDAT4: odata = d->d4; break; case KIUDAT5: odata = d->d5; break; case KIUSCANREP: if (writeflag == MEM_WRITE) { debug("[ vr41xx KIU: setting KIUSCANREP to 0x%04x ]\n", (int)idata); /* TODO */ } else fatal("[ vr41xx KIU: unimplemented read from " "KIUSCANREP ]\n"); break; case KIUSCANS: if (writeflag == MEM_WRITE) { debug("[ vr41xx KIU: write to KIUSCANS: 0x%04x: TODO" " ]\n", (int)idata); /* TODO */ } else debug("[ vr41xx KIU: unimplemented read from " "KIUSCANS ]\n"); break; case KIUINT: /* Interrupt. A wild guess: zero-on-write */ if (writeflag == MEM_WRITE) { d->kiu_int_assert &= ~idata; } else { odata = d->kiu_int_assert; } recalc_kiu_int_assert(cpu, d); break; case KIURST: /* Reset. */ break; default: if (writeflag == MEM_WRITE) debug("[ vr41xx KIU: unimplemented write to offset " "0x%x, data=0x%016" PRIx64" ]\n", ofs, (uint64_t) idata); else debug("[ vr41xx KIU: unimplemented read from offset " "0x%x ]\n", ofs); } return odata; } DEVICE_ACCESS(vr41xx) { struct vr41xx_data *d = (struct vr41xx_data *) extra; uint64_t idata = 0, odata = 0; int regnr; int revision = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); regnr = relative_addr / sizeof(uint64_t); /* KIU ("Keyboard Interface Unit") is handled separately. */ if (relative_addr >= d->kiu_offset && relative_addr < d->kiu_offset + 0x20) { odata = vr41xx_kiu(cpu, relative_addr - d->kiu_offset, idata, writeflag, d); goto ret; } /* TODO: Maybe these should be handled separately as well? */ switch (relative_addr) { /* BCU: 0x00 .. 0x1c */ case BCUREVID_REG_W: /* 0x010 */ case BCU81REVID_REG_W: /* 0x014 */ /* * TODO? Linux seems to read 0x14. The lowest bits are * a divisor for PClock, bits 8 and up seem to be a * divisor for VTClock (relative to PClock?)... */ switch (d->cpumodel) { case 4131: revision = BCUREVID_RID_4131; break; case 4122: revision = BCUREVID_RID_4122; break; case 4121: revision = BCUREVID_RID_4121; break; case 4111: revision = BCUREVID_RID_4111; break; case 4102: revision = BCUREVID_RID_4102; break; case 4101: revision = BCUREVID_RID_4101; break; case 4181: revision = BCUREVID_RID_4181; break; } odata = (revision << BCUREVID_RIDSHFT) | 0x020c; break; case BCU81CLKSPEED_REG_W: /* 0x018 */ /* * TODO: Implement this for ALL cpu types: */ odata = BCUCLKSPEED_DIVT4 << BCUCLKSPEED_DIVTSHFT; break; /* DMAAU: 0x20 .. 0x3c */ /* DCU: 0x40 .. 0x5c */ /* CMU: 0x60 .. 0x7c */ /* ICU: 0x80 .. 0xbc */ case 0x80: /* Level 1 system interrupt reg 1... */ if (writeflag == MEM_READ) odata = d->sysint1; else { /* TODO: clear-on-write-one? */ d->sysint1 &= ~idata; d->sysint1 &= 0xffff; } break; case 0x88: if (writeflag == MEM_READ) odata = d->giuint; else d->giuint &= ~idata; break; case 0x8c: if (writeflag == MEM_READ) odata = d->msysint1; else d->msysint1 = idata; break; case 0x94: if (writeflag == MEM_READ) odata = d->giumask; else d->giumask = idata; break; case 0xa0: /* Level 1 system interrupt reg 2... */ if (writeflag == MEM_READ) odata = d->sysint2; else { /* TODO: clear-on-write-one? */ d->sysint2 &= ~idata; d->sysint2 &= 0xffff; } break; case 0xa6: if (writeflag == MEM_READ) odata = d->msysint2; else d->msysint2 = idata; break; /* RTC: */ case 0xc0: case 0xc2: case 0xc4: { struct timeval tv; gettimeofday(&tv, NULL); /* Adjust time by 120 years and 29 days. */ tv.tv_sec += (int64_t) (120*365 + 29) * 24*60*60; switch (relative_addr) { case 0xc0: odata = (tv.tv_sec & 1) << 15; odata += (uint64_t)tv.tv_usec * 32768 / 1000000; break; case 0xc2: odata = (tv.tv_sec >> 1) & 0xffff; break; case 0xc4: odata = (tv.tv_sec >> 17) & 0xffff; break; } } break; case 0xd0: /* RTCL1_L_REG_W */ if (writeflag == MEM_WRITE && idata != 0) { int hz = RTCL1_L_HZ / idata; debug("[ vr41xx: rtc interrupts at %i Hz ]\n", hz); if (d->timer == NULL) d->timer = timer_add(hz, timer_tick, d); else timer_update_frequency(d->timer, hz); } break; case 0xd2: /* RTCL1_H_REG_W */ break; case 0x108: if (writeflag == MEM_READ) odata = d->giuint; else d->giuint &= ~idata; break; /* case 0x10a: "High" part of GIU? break; */ case 0x13e: /* on 4181? */ case 0x1de: /* on 4121? */ /* RTC interrupt register... */ /* Ack. timer interrupts? */ INTERRUPT_DEASSERT(d->timer_irq); if (d->pending_timer_interrupts > 0) d->pending_timer_interrupts --; break; default: if (writeflag == MEM_WRITE) debug("[ vr41xx: unimplemented write to address " "0x%" PRIx64", data=0x%016" PRIx64" ]\n", (uint64_t) relative_addr, (uint64_t) idata); else debug("[ vr41xx: unimplemented read from address " "0x%" PRIx64" ]\n", (uint64_t) relative_addr); } ret: /* * Recalculate interrupt assertions: */ if (d->giuint & d->giumask) INTERRUPT_ASSERT(d->giu_irq); else INTERRUPT_DEASSERT(d->giu_irq); if ((d->sysint1 & d->msysint1) | (d->sysint2 & d->msysint2)) INTERRUPT_ASSERT(d->cpu_irq); else INTERRUPT_DEASSERT(d->cpu_irq); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_vr41xx_init(): * * machine->path is something like "machine[0]". */ struct vr41xx_data *dev_vr41xx_init(struct machine *machine, struct memory *mem, int cpumodel) { struct vr41xx_data *d; uint64_t baseaddr = 0; char tmps[300]; int i; CHECK_ALLOCATION(d = (struct vr41xx_data *) malloc(sizeof(struct vr41xx_data))); memset(d, 0, sizeof(struct vr41xx_data)); /* Connect to MIPS irq 2: */ snprintf(tmps, sizeof(tmps), "%s.cpu[%i].2", machine->path, machine->bootstrap_cpu); INTERRUPT_CONNECT(tmps, d->cpu_irq); /* * Register VRIP interrupt lines 0..25: */ for (i=0; i<=25; i++) { struct interrupt templ; snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i", machine->path, machine->bootstrap_cpu, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = tmps; templ.extra = d; templ.interrupt_assert = vr41xx_vrip_interrupt_assert; templ.interrupt_deassert = vr41xx_vrip_interrupt_deassert; interrupt_handler_register(&templ); } /* * Register GIU interrupt lines 0..31: */ for (i=0; i<32; i++) { struct interrupt templ; snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i.giu.%i", machine->path, machine->bootstrap_cpu, VRIP_INTR_GIU, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = tmps; templ.extra = d; templ.interrupt_assert = vr41xx_giu_interrupt_assert; templ.interrupt_deassert = vr41xx_giu_interrupt_deassert; interrupt_handler_register(&templ); } d->cpumodel = cpumodel; /* TODO: VRC4173 has the KIU at offset 0x100? */ d->kiu_offset = 0x180; d->kiu_console_handle = -1; if (machine->x11_md.in_use) d->kiu_console_handle = console_start_slave_inputonly( machine, "kiu", 1); /* Connect to the KIU and GIU interrupts: */ snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i", machine->path, machine->bootstrap_cpu, VRIP_INTR_GIU); INTERRUPT_CONNECT(tmps, d->giu_irq); snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i", machine->path, machine->bootstrap_cpu, VRIP_INTR_KIU); INTERRUPT_CONNECT(tmps, d->kiu_irq); if (machine->x11_md.in_use) machine->main_console_handle = d->kiu_console_handle; switch (cpumodel) { case 4101: case 4102: case 4111: case 4121: baseaddr = 0xb000000; break; case 4181: baseaddr = 0xa000000; dev_ram_init(machine, 0xb000000, 0x1000000, DEV_RAM_MIRROR, 0xa000000); break; case 4122: case 4131: baseaddr = 0xf000000; break; default: printf("Unimplemented VR cpu model\n"); exit(1); } if (d->cpumodel == 4121 || d->cpumodel == 4181) snprintf(tmps, sizeof(tmps), "%s.cpu[%i].3", machine->path, machine->bootstrap_cpu); else snprintf(tmps, sizeof(tmps), "%s.cpu[%i].vrip.%i", machine->path, machine->bootstrap_cpu, VRIP_INTR_ETIMER); INTERRUPT_CONNECT(tmps, d->timer_irq); memory_device_register(mem, "vr41xx", baseaddr, DEV_VR41XX_LENGTH, dev_vr41xx_access, (void *)d, DM_DEFAULT, NULL); /* * TODO: Find out which controllers are at which addresses on * which chips. */ if (cpumodel == 4131) { snprintf(tmps, sizeof(tmps), "ns16550 irq=%s.cpu[%i].vrip.%i " "addr=0x%" PRIx64" name2=siu", machine->path, machine->bootstrap_cpu, VRIP_INTR_SIU, (uint64_t) (baseaddr+0x800)); device_add(machine, tmps); } else { /* This is used by Linux and NetBSD: */ snprintf(tmps, sizeof(tmps), "ns16550 irq=%s.cpu[%i]." "vrip.%i addr=0x%x name2=serial", machine->path, machine->bootstrap_cpu, VRIP_INTR_SIU, 0xc000000); device_add(machine, tmps); } /* Hm... maybe this should not be here. TODO */ snprintf(tmps, sizeof(tmps), "pcic irq=%s.cpu[%i].vrip.%i addr=" "0x140003e0", machine->path, machine->bootstrap_cpu, VRIP_INTR_GIU); device_add(machine, tmps); machine_add_tickfunction(machine, dev_vr41xx_tick, d, DEV_VR41XX_TICKSHIFT); /* Some machines (?) use ISA space at 0x15000000 instead of 0x14000000, eg IBM WorkPad Z50. */ dev_ram_init(machine, 0x15000000, 0x1000000, DEV_RAM_MIRROR, 0x14000000); return d; } gxemul-0.6.1/src/devices/dev_rtl8139c.cc000644 001750 001750 00000014126 13402411502 020100 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Realtek 8139 ethernet controller * * TODO: Pretty much everything. */ #include #include #include #include "cpu.h" #include "device.h" #include "emul.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "net.h" #include "thirdparty/rtl81x9reg.h" #define DEV_RTL8139C_LENGTH 0x100 #define EEPROM_SIZE 0x100 struct rtl8139c_data { struct interrupt irq; unsigned char macaddr[6]; /* Registers: */ uint8_t rl_command; uint8_t rl_eecmd; /* EEPROM: */ int eeprom_address_width; int eeprom_selected; int8_t eeprom_cur_cmd_bit; uint16_t eeprom_cur_cmd; uint16_t eeprom_cur_data; uint16_t eeprom_reg[EEPROM_SIZE]; }; /* * eeprom_clk(): * * Called whenever the eeprom CLK bit is toggled from 0 to 1. */ static void eeprom_clk(struct rtl8139c_data *d) { int data_in = d->rl_eecmd & RL_EE_DATAIN? 1 : 0; if (d->eeprom_cur_cmd_bit < d->eeprom_address_width + 4) { d->eeprom_cur_cmd <<= 1; d->eeprom_cur_cmd |= data_in; } if (d->eeprom_cur_cmd_bit == d->eeprom_address_width + 3) { int cmd = d->eeprom_cur_cmd >> d->eeprom_address_width; int addr = d->eeprom_cur_cmd & ((1<eeprom_address_width)-1); debug("[ rtl8139c eeprom cmd=0x%x addr=0x%02x ]\n", cmd, addr); switch (cmd) { case RL_9346_READ: d->eeprom_cur_data = d->eeprom_reg[addr % EEPROM_SIZE]; break; default:fatal("[ rtl8139c eeprom: only the read command has" " been implemented. sorry. ]\n"); exit(1); } } /* Data output: (Note: Only the READ command has been implemented.) */ if (d->eeprom_cur_cmd_bit >= d->eeprom_address_width + 4) { int cur_out_bit = d->eeprom_cur_cmd_bit - (d->eeprom_address_width + 4); int bit = d->eeprom_cur_data & (1 << (15-cur_out_bit)); if (bit) d->rl_eecmd |= RL_EE_DATAOUT; else d->rl_eecmd &= ~RL_EE_DATAOUT; } d->eeprom_cur_cmd_bit ++; if (d->eeprom_cur_cmd_bit >= d->eeprom_address_width + 4 + 16) { d->eeprom_cur_cmd = 0; d->eeprom_cur_cmd_bit = 0; } } DEVICE_ACCESS(rtl8139c) { struct rtl8139c_data *d = (struct rtl8139c_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case RL_COMMAND: if (writeflag == MEM_WRITE) { if (idata & RL_CMD_RESET) { /* Reset. TODO */ /* ... and then clear the reset bit: */ idata &= ~RL_CMD_RESET; } d->rl_command = idata; } else { odata = d->rl_command; } break; case RL_EECMD: if (writeflag == MEM_WRITE) { uint8_t old = d->rl_eecmd; d->rl_eecmd = idata; if (!d->eeprom_selected && d->rl_eecmd & RL_EE_SEL) { /* Reset eeprom cmd bit state: */ d->eeprom_cur_cmd = 0; d->eeprom_cur_cmd_bit = 0; } d->eeprom_selected = d->rl_eecmd & RL_EE_SEL; if (idata & RL_EE_CLK && !(old & RL_EE_CLK)) eeprom_clk(d); } else { odata = d->rl_eecmd; } break; case 0x82: /* Unknown address, but OpenBSD's re driver writes a 0x01 to this address, in re_reset(). */ if (writeflag == MEM_WRITE) { if (idata != 0x01) { fatal("rtl8139c: unimplemented write to" " register 0x82.\n"); exit(1); } } break; default:if (writeflag == MEM_WRITE) { fatal("[ rtl8139c: unimplemented write to " "offset 0x%x: data=0x%x ]\n", (int) relative_addr, (int)idata); } else { fatal("[ rtl8139c: unimplemented read from " "offset 0x%x ]\n", (int)relative_addr); } exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(rtl8139c) { char *name2; size_t nlen = 100; struct rtl8139c_data *d; CHECK_ALLOCATION(d = (struct rtl8139c_data *) malloc(sizeof(struct rtl8139c_data))); memset(d, 0, sizeof(struct rtl8139c_data)); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); net_generate_unique_mac(devinit->machine, d->macaddr); /* TODO: eeprom address width = 6 on 8129? */ d->eeprom_address_width = 8; d->eeprom_reg[0] = 0x8139; d->eeprom_reg[7] = d->macaddr[0] + (d->macaddr[1] << 8); d->eeprom_reg[8] = d->macaddr[2] + (d->macaddr[3] << 8); d->eeprom_reg[9] = d->macaddr[4] + (d->macaddr[5] << 8); CHECK_ALLOCATION(name2 = (char *) malloc(nlen)); snprintf(name2, nlen, "%s [%02x:%02x:%02x:%02x:%02x:%02x]", devinit->name, d->macaddr[0], d->macaddr[1], d->macaddr[2], d->macaddr[3], d->macaddr[4], d->macaddr[5]); memory_device_register(devinit->machine->memory, name2, devinit->addr, DEV_RTL8139C_LENGTH, dev_rtl8139c_access, (void *)d, DM_DEFAULT, NULL); net_add_nic(devinit->machine->emul->net, d, d->macaddr); return 1; } gxemul-0.6.1/src/devices/dev_dec21030.cc000644 001750 001750 00000016440 13402411502 017731 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: DEC 21030 "TGA" graphics card * * Resolutions that seem to be possible: 640x480, 1024x768, 1280x1024. * 8 bits, perhaps others? (24 bit?) * * NetBSD should say something like this: * * tga0 at pci0 dev 12 function 0: TGA2 pass 2, board type T8-02 * tga0: 1280 x 1024, 8bpp, Bt485 RAMDAC * * See netbsd/src/sys/dev/pci/tga.c for more info. * tga_rop_vtov() for video-to-video copy (scrolling and fast * erasing) * * TODO: This device is far from complete. * The RAMDAC is non-existant. * * TODO: all fb device writes with direct writes to the framebuffer * memory, and update the x1,y1,x2,y2 coordinates instead. * That will give better performance. */ #include #include #include #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/tgareg.h" #define MAX_XSIZE 2048 #if 1 int dec21030_default_xsize = 640; int dec21030_default_ysize = 480; #else int dec21030_default_xsize = 1024; int dec21030_default_ysize = 768; #endif /* TODO: Ugly hack: this causes the framebuffer to be in memory */ #define FRAMEBUFFER_PADDR 0x4000000000ULL #define FRAMEBUFFER_BASE 0x201000 struct dec21030_data { int graphics_mode; uint32_t pixel_mask; uint32_t copy_source; uint32_t color; struct vfb_data *vfb_data; }; DEVICE_ACCESS(dec21030) { struct dec21030_data *d = (struct dec21030_data *) extra; uint64_t idata, odata = 0; int reg, r, white = 255, black = 0; size_t i, newlen; unsigned char buf2[MAX_XSIZE]; /* Read/write to the framebuffer: */ if (relative_addr >= FRAMEBUFFER_BASE) { /* TODO: Perhaps this isn't graphics mode (GMOR), but GOPR (operation) specific: */ switch (d->graphics_mode) { case 1: /* Bitmap write: */ /* Copy from data into buf2: */ for (i=0; ipixel_mask & (1 << i)) newlen ++; if (newlen > len * 8) newlen = len * 8; r = dev_fb_access(cpu, mem, relative_addr - FRAMEBUFFER_BASE, buf2, newlen, writeflag, d->vfb_data); break; case 0x2d: /* Block fill: */ /* data is nr of pixels to fill minus one */ newlen = memory_readmax64(cpu, data, len) + 1; /* debug("YO addr=0x%08x, newlen=%i\n", relative_addr, newlen); */ if (newlen > MAX_XSIZE) newlen = MAX_XSIZE; memset(buf2, d->color, newlen); r = dev_fb_access(cpu, mem, relative_addr - FRAMEBUFFER_BASE, buf2, newlen, MEM_WRITE, d->vfb_data); break; default: r = dev_fb_access(cpu, mem, relative_addr - FRAMEBUFFER_BASE, data, len, writeflag, d->vfb_data); } return r; } idata = memory_readmax64(cpu, data, len); /* Read from/write to the dec21030's registers: */ reg = ((relative_addr - TGA_MEM_CREGS) & (TGA_CREGS_ALIAS - 1)) / sizeof(uint32_t); switch (reg) { /* Color? (there are 8 of these, 2 used in 8-bit mode, 8 in 24-bit mode) */ case TGA_REG_GBCR0: if (writeflag == MEM_WRITE) d->color = idata; else odata = d->color; break; /* Board revision */ /* case TGA_MEM_CREGS + sizeof(uint32_t) * TGA_REG_GREV: */ case TGA_REG_GREV: /* 01,02,03,04 (rev0) and 20,21,22 (rev1) are allowed */ odata = 0x04; break; /* Graphics Mode: */ case TGA_REG_GMOR: if (writeflag == MEM_WRITE) d->graphics_mode = idata; else odata = d->graphics_mode; break; /* Pixel mask: */ case TGA_REG_GPXR_S: /* "one-shot" */ case TGA_REG_GPXR_P: /* persistant */ if (writeflag == MEM_WRITE) d->pixel_mask = idata; else odata = d->pixel_mask; break; /* Horizonsal size: */ case TGA_REG_VHCR: odata = dec21030_default_xsize / 4; /* lowest 9 bits */ break; /* Vertical size: */ case TGA_REG_VVCR: odata = dec21030_default_ysize; /* lowest 11 bits */ break; /* Block copy source: */ case TGA_REG_GCSR: d->copy_source = idata; debug("[ dec21030: block copy source = 0x%08x ]\n", idata); break; /* Block copy destination: */ case TGA_REG_GCDR: debug("[ dec21030: block copy destination = 0x%08x ]\n", idata); newlen = 64; /* Both source and destination are raw framebuffer addresses, offset by 0x1000. */ dev_fb_access(cpu, mem, d->copy_source - 0x1000, buf2, newlen, MEM_READ, d->vfb_data); dev_fb_access(cpu, mem, idata - 0x1000, buf2, newlen, MEM_WRITE, d->vfb_data); break; default: if (writeflag == MEM_WRITE) debug("[ dec21030: unimplemented write to address" " 0x%x (=reg 0x%x), data=0x%02x ]\n", (int)relative_addr, reg, (int)idata); else debug("[ dec21030: unimplemented read from address" " 0x%x (=reg 0x%x) ]\n", (int)relative_addr, reg); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(dec21030) { struct dec21030_data *d; CHECK_ALLOCATION(d = (struct dec21030_data *) malloc(sizeof(struct dec21030_data))); memset(d, 0, sizeof(struct dec21030_data)); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, 128*1048576, dev_dec21030_access, d, DM_DEFAULT, NULL); /* * TODO: I have no idea about how/where this framebuffer should * be in relation to the pci device */ d->vfb_data = dev_fb_init(devinit->machine, devinit->machine->memory, FRAMEBUFFER_PADDR, VFB_GENERIC, dec21030_default_xsize, dec21030_default_ysize, dec21030_default_xsize, dec21030_default_ysize, 8, "TGA"); return 1; } gxemul-0.6.1/src/devices/dev_pcic.cc000644 001750 001750 00000016003 13402411502 017521 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Intel 82365SL PC Card Interface Controller * * (Called "pcic" by NetBSD.) * * TODO: Lots of stuff. This is just a quick hack. Don't rely on it. */ #include #include #include #include "cpu.h" #include "device.h" #include "emul.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/i82365reg.h" #include "thirdparty/pcmciareg.h" /* #define debug fatal */ #define DEV_PCIC_LENGTH 2 struct pcic_data { struct interrupt irq; int regnr; }; DEVICE_ACCESS(pcic_cis) { /* struct pcic_data *d = (struct pcic_data *) extra; */ uint64_t idata = 0, odata = 0; idata = memory_readmax64(cpu, data, len); { #if 0 /* SMC, PCM Ethernet Adapter, CIS V1.05 (manufacturer 0x108, product 0x105) */ unsigned char x[] = { PCMCIA_CISTPL_DEVICE, 3, PCMCIA_DTYPE_FUNCSPEC, 0xff,0xff, PCMCIA_CISTPL_FUNCID, 2, 0x06, 0x00, PCMCIA_CISTPL_MANFID, 4, 0x08, 0x01, 0x05, 0x01, PCMCIA_CISTPL_VERS_1, 0x26, 0x04, 0x01, 0x53, 0x4d, 0x43, 0x00, 0x50, 0x43, 0x4d, 0x20, 0x45, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x41, 0x64, 0x61, 0x70, 0x74, 0x65, 0x72, 0x00, 0x43, 0x49, 0x53, 0x20, 0x56, 0x31, 0x2e, 0x30, 0x35, 0x00, 0xff, PCMCIA_CISTPL_CONFIG, 0x0a, 0x02, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0xff, PCMCIA_CISTPL_CFTABLE_ENTRY, 0x0b, 0xc1, 0x01, 0x70, 0x50, 0xbc, 0x8e, 0x48, 0x40, 0x00,0x02,0xff, /* unhandled CISTPL 22 */ 0x22, 0x02, 0x01, 0x02, /* unhandled CISTPL 22 */ 0x22, 0x05, 0x02, 0x80, 0x96, 0x98, 0x00, /* unhandled CISTPL 22 */ 0x22, 0x02, 0x03, 0x01, /* unhandled CISTPL 22 */ 0x22, 0x08, 0x04, 0x06, 0x00, 0x00, 0xc0, 0x2f, 0x48, 0xd2, /* unhandled CISTPL 22 */ 0x22, 0x02, 0x05, 0x01, PCMCIA_CISTPL_END, 0 }; #endif /* From http://www.mail-archive.com/freebsd-current@freebsd. org/msg32550.html */ unsigned char x[] = { PCMCIA_CISTPL_DEVICE, 3, 0xdc, 0x00, 0xff, PCMCIA_CISTPL_VERS_1, 0x1a, 0x04,0x01,0x20,0x00,0x4e,0x69,0x6e,0x6a,0x61,0x41,0x54,0x41, 0x2d,0x00,0x56,0x31,0x2e,0x30,0x00,0x41,0x50,0x30,0x30,0x20, 0x00,0xff, PCMCIA_CISTPL_CONFIG, 5, 0x01,0x23,0x00,0x02,0x03, PCMCIA_CISTPL_CFTABLE_ENTRY, 0x15, 0xe1,0x01,0x3d,0x11,0x55,0x1e,0xfc,0x23,0xf0,0x61,0x80,0x01, 0x07,0x86,0x03,0x01,0x30,0x68,0xd0,0x10,0x00, #if 0 PCMCIA_CISTPL_CFTABLE_ENTRY, 0xf, 0x22,0x38,0xf0,0x61,0x90,0x01,0x07,0x96,0x03,0x01,0x30,0x68, 0xd0,0x10,0x00, PCMCIA_CISTPL_CFTABLE_ENTRY, 0xf, 0x23,0x38,0xf0,0x61,0xa0,0x01,0x07,0xa6,0x03,0x01,0x30,0x68, 0xd0,0x10,0x00, #endif PCMCIA_CISTPL_NO_LINK, 0, PCMCIA_CISTPL_END, 0 }; relative_addr /= 2; if (relative_addr < sizeof(x)) odata = x[relative_addr]; debug("[ dev_pcic_cis_access: blah blah: addr=0x%x ]\n", (int)relative_addr); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(pcic) { struct pcic_data *d = (struct pcic_data *) extra; uint64_t idata = 0, odata = 0; int controller_nr, socket_nr; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); controller_nr = d->regnr & 0x80? 1 : 0; socket_nr = d->regnr & 0x40? 1 : 0; switch (relative_addr) { case 0: /* Register select: */ if (writeflag == MEM_WRITE) d->regnr = idata; else odata = d->regnr; break; case 1: /* Register access: */ switch (d->regnr & 0x3f) { case PCIC_IDENT: /* This causes sockets A and B to be present on controller 0, and only socket A on controller 1. */ if (controller_nr == 1 && socket_nr == 1) odata = 0; else odata = PCIC_IDENT_IFTYPE_MEM_AND_IO | PCIC_IDENT_REV_I82365SLR1; break; #if 1 case PCIC_INTR: odata = PCIC_INTR_IRQ3; break; #endif case PCIC_CSC: odata = PCIC_CSC_GPI; break; case PCIC_IF_STATUS: odata = PCIC_IF_STATUS_READY | PCIC_IF_STATUS_POWERACTIVE; if (controller_nr == 0 && socket_nr == 0) odata |= PCIC_IF_STATUS_CARDDETECT_PRESENT; break; default: if (writeflag == MEM_WRITE) { debug("[ pcic: unimplemented write to " "controller %i socket %c, regnr %i: " "data=0x%02x ]\n", controller_nr, socket_nr? 'B' : 'A', d->regnr & 0x3f, (int)idata); } else { debug("[ pcic: unimplemented read from " "controller %i socket %c, regnr %i ]\n", controller_nr, socket_nr? 'B' : 'A', d->regnr & 0x3f); } } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(pcic) { char tmpstr[200]; struct pcic_data *d; CHECK_ALLOCATION(d = (struct pcic_data *) malloc(sizeof(struct pcic_data))); memset(d, 0, sizeof(struct pcic_data)); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_PCIC_LENGTH, dev_pcic_access, (void *)d, DM_DEFAULT, NULL); /* TODO: this shouldn't be hardcoded for hpcmips here! */ memory_device_register(devinit->machine->memory, "pcic_cis", 0x10070000, 0x1000, dev_pcic_cis_access, (void *)d, DM_DEFAULT, NULL); /* TODO: find out a good way to specify the address, and the IRQ! */ snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x14000180 irq=%s.giu.9", devinit->interrupt_path); device_add(devinit->machine, tmpstr); /* TODO: Linux/MobilePro looks at 0x14000170 and 0x1f0... */ /* Yuck. Now there are two. How should this be solved nicely? */ snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x140001f0 irq=%s.giu.9", devinit->interrupt_path); device_add(devinit->machine, tmpstr); return 1; } gxemul-0.6.1/src/devices/dev_kn220.cc000644 001750 001750 00000011433 13402411502 017441 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: DEC KN220 (DECsystem 5500) devices * * o) I/O board * o) SGEC (ethernet) (Called "ne" in Ultrix.) * * TODO: Study docs. */ #include #include #include #include "devices.h" #include "memory.h" #include "misc.h" #define IOBOARD_DEBUG struct dec5500_ioboard_data { int dummy; }; #define SGEC_DEBUG struct sgec_data { int irq_nr; }; /* * dev_dec5500_ioboard_access(): */ DEVICE_ACCESS(dec5500_ioboard) { /* struct dec5500_ioboard_data *d = (struct dec5500_ioboard_data *) extra; */ uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); #ifdef IOBOARD_DEBUG if (writeflag == MEM_WRITE) debug("[ dec5500_ioboard: write to address 0x%llx, " "data=0x%016llx ]\n", (long long)relative_addr, (long long)idata); else debug("[ dec5500_ioboard: read from address 0x%llx ]\n", (long long)relative_addr); #endif switch (relative_addr) { case 0: if (writeflag == MEM_READ) /* * TODO: One of these bits indicate I/O board * present. */ odata = 0xffffffffULL; break; default: if (writeflag == MEM_WRITE) debug("[ dec5500_ioboard: unimplemented write to " "address 0x%llx, data=0x%016llx ]\n", (long long)relative_addr, (long long)idata); else debug("[ dec5500_ioboard: unimplemented read from" " address 0x%llx ]\n", (long long)relative_addr); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_sgec_access(): */ DEVICE_ACCESS(sgec) { /* struct sgec_data *d = (struct sgec_data *) extra; */ uint64_t idata = 0, odata = 0; idata = memory_readmax64(cpu, data, len); #ifdef SGEC_DEBUG if (writeflag == MEM_WRITE) debug("[ sgec: write to address 0x%llx, data=0x%016llx ]\n", (long long)relative_addr, (long long)idata); else debug("[ sgec: read from address 0x%llx ]\n", (long long)relative_addr); #endif switch (relative_addr) { case 0x14: if (writeflag == MEM_READ) odata = 0x80000000; break; default: if (writeflag == MEM_WRITE) debug("[ sgec: unimplemented write to address 0x%llx," " data=0x%016llx ]\n", (long long)relative_addr, (long long)idata); else debug("[ sgec: unimplemented read from address " "0x%llx ]\n", (long long)relative_addr); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_sgec_init(): */ void dev_sgec_init(struct memory *mem, uint64_t baseaddr, int irq_nr) { struct sgec_data *d; CHECK_ALLOCATION(d = (struct sgec_data *) malloc(sizeof(struct sgec_data))); memset(d, 0, sizeof(struct sgec_data)); d->irq_nr = irq_nr; memory_device_register(mem, "sgec", baseaddr, DEV_SGEC_LENGTH, dev_sgec_access, (void *)d, DM_DEFAULT, NULL); } /* * dev_dec5500_ioboard_init(): */ struct dec5500_ioboard_data *dev_dec5500_ioboard_init(struct cpu *cpu, struct memory *mem, uint64_t baseaddr) { struct dec5500_ioboard_data *d; CHECK_ALLOCATION(d = (struct dec5500_ioboard_data *) malloc(sizeof(struct dec5500_ioboard_data))); memset(d, 0, sizeof(struct dec5500_ioboard_data)); memory_device_register(mem, "dec5500_ioboard", baseaddr, DEV_DEC5500_IOBOARD_LENGTH, dev_dec5500_ioboard_access, (void *)d, DM_DEFAULT, NULL); return d; } gxemul-0.6.1/src/devices/dev_ps2_stuff.cc000644 001750 001750 00000033404 13402411502 020522 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: PlayStation 2 misc stuff (timer, DMA, interrupts, ...) * * offset 0x0000 timer control * offset 0x8000 DMA controller * offset 0xf000 Interrupt register * * The 16 normal PS2 interrupts interrupt at MIPS interrupt 2. * The 16 DMA interrupts are connected to MIPS interrupt 3. * * SBUS interrupts go via PS2 interrupt 1. */ #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/ee_timerreg.h" #include "thirdparty/ps2_dmacreg.h" #define TICK_STEPS_SHIFT 14 /* NOTE/TODO: This should be the same as in ps2_gs: */ #define DEV_PS2_GIF_FAKE_BASE 0x50000000 #define N_PS2_DMA_CHANNELS 10 #define N_PS2_TIMERS 4 struct ps2_data { uint32_t timer_count[N_PS2_TIMERS]; uint32_t timer_comp[N_PS2_TIMERS]; uint32_t timer_mode[N_PS2_TIMERS]; uint32_t timer_hold[N_PS2_TIMERS]; /* NOTE: only 0 and 1 are valid */ struct interrupt timer_irq[N_PS2_TIMERS]; uint64_t dmac_reg[DMAC_REGSIZE / 0x10]; struct interrupt dmac_irq; /* MIPS irq 3 */ struct interrupt dma_channel2_irq; /* irq path of channel 2 */ uint64_t other_memory_base[N_PS2_DMA_CHANNELS]; uint32_t intr; uint32_t imask; uint32_t sbus_smflg; struct interrupt intr_irq; /* MIPS irq 2 */ struct interrupt sbus_irq; /* PS2 irq 1 */ }; #define DEV_PS2_LENGTH 0x10000 void ps2_intr_interrupt_assert(struct interrupt *interrupt) { struct ps2_data *d = (struct ps2_data *) interrupt->extra; d->intr |= (1 << interrupt->line); if (d->intr & d->imask) INTERRUPT_ASSERT(d->intr_irq); } void ps2_intr_interrupt_deassert(struct interrupt *interrupt) { struct ps2_data *d = (struct ps2_data *) interrupt->extra; d->intr &= ~(1 << interrupt->line); if (!(d->intr & d->imask)) INTERRUPT_DEASSERT(d->intr_irq); } void ps2_dmac_interrupt_assert(struct interrupt *interrupt) { struct ps2_data *d = (struct ps2_data *) interrupt->extra; d->dmac_reg[0x601] |= (1 << interrupt->line); /* TODO: DMA interrupt mask? */ if (d->dmac_reg[0x601] & 0xffff) INTERRUPT_ASSERT(d->dmac_irq); } void ps2_dmac_interrupt_deassert(struct interrupt *interrupt) { struct ps2_data *d = (struct ps2_data *) interrupt->extra; d->dmac_reg[0x601] &= ~(1 << interrupt->line); /* TODO: DMA interrupt mask? */ if (!(d->dmac_reg[0x601] & 0xffff)) INTERRUPT_DEASSERT(d->dmac_irq); } void ps2_sbus_interrupt_assert(struct interrupt *interrupt) { /* Note: sbus irq 0 = mask 0x100, sbus irq 1 = mask 0x400 */ struct ps2_data *d = (struct ps2_data *) interrupt->extra; d->sbus_smflg |= (1 << (8 + interrupt->line * 2)); /* TODO: SBUS interrupt mask? */ if (d->sbus_smflg != 0) INTERRUPT_ASSERT(d->sbus_irq); } void ps2_sbus_interrupt_deassert(struct interrupt *interrupt) { /* Note: sbus irq 0 = mask 0x100, sbus irq 1 = mask 0x400 */ struct ps2_data *d = (struct ps2_data *) interrupt->extra; d->sbus_smflg &= ~(1 << (8 + interrupt->line * 2)); /* TODO: SBUS interrupt mask? */ if (d->sbus_smflg == 0) INTERRUPT_DEASSERT(d->sbus_irq); } DEVICE_TICK(ps2) { struct ps2_data *d = (struct ps2_data *) extra; int i; /* * Right now this interrupts every now and then. * The main interrupt in NetBSD should be 100 Hz. TODO. */ for (i=0; itimer_mode[i] & T_MODE_CUE) d->timer_count[i] ++; if (d->timer_mode[i] & (T_MODE_CMPE | T_MODE_OVFE)) { /* Zero return: */ if (d->timer_mode[i] & T_MODE_ZRET) d->timer_count[i] = 0; INTERRUPT_ASSERT(d->timer_irq[i]); /* timer 1..3 are "single-shot"? TODO */ if (i > 0) { d->timer_mode[i] &= ~(T_MODE_CMPE | T_MODE_OVFF); } } } } DEVICE_ACCESS(ps2) { uint64_t idata = 0, odata = 0; int regnr = 0; struct ps2_data *d = (struct ps2_data *) extra; int timer_nr = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (relative_addr >= 0x8000 && relative_addr < 0x8000 + DMAC_REGSIZE) { regnr = (relative_addr - 0x8000) / 16; if (writeflag == MEM_READ) odata = d->dmac_reg[regnr]; else d->dmac_reg[regnr] = idata; } /* * Timer control: * The four timers are at offsets 0, 0x800, 0x1000, and 0x1800. */ if (relative_addr < TIMER_REGSIZE) { /* 0, 1, 2, or 3 */ timer_nr = (relative_addr & 0x1800) >> 11; relative_addr &= (TIMER_OFS-1); } switch (relative_addr) { case 0x0000: /* timer count */ if (writeflag == MEM_READ) { odata = d->timer_count[timer_nr]; if (timer_nr == 0) { /* :-) TODO: remove this? */ d->timer_count[timer_nr] ++; } debug("[ ps2: read timer %i count: 0x%llx ]\n", timer_nr, (long long)odata); } else { d->timer_count[timer_nr] = idata; debug("[ ps2: write timer %i count: 0x%llx ]\n", timer_nr, (long long)idata); } break; case 0x0010: /* timer mode */ if (writeflag == MEM_READ) { odata = d->timer_mode[timer_nr]; debug("[ ps2: read timer %i mode: 0x%llx ]\n", timer_nr, (long long)odata); } else { d->timer_mode[timer_nr] = idata; debug("[ ps2: write timer %i mode: 0x%llx ]\n", timer_nr, (long long)idata); } break; case 0x0020: /* timer comp */ if (writeflag == MEM_READ) { odata = d->timer_comp[timer_nr]; debug("[ ps2: read timer %i comp: 0x%llx ]\n", timer_nr, (long long)odata); } else { d->timer_comp[timer_nr] = idata; debug("[ ps2: write timer %i comp: 0x%llx ]\n", timer_nr, (long long)idata); } break; case 0x0030: /* timer hold */ if (writeflag == MEM_READ) { odata = d->timer_hold[timer_nr]; debug("[ ps2: read timer %i hold: 0x%llx ]\n", timer_nr, (long long)odata); if (timer_nr >= 2) fatal("[ WARNING: ps2: read from non-" "existant timer %i hold register ]\n"); } else { d->timer_hold[timer_nr] = idata; debug("[ ps2: write timer %i hold: 0x%llx ]\n", timer_nr, (long long)idata); if (timer_nr >= 2) fatal("[ WARNING: ps2: write to " "non-existant timer %i hold register ]\n", timer_nr); } break; case 0x8000 + D2_CHCR_REG: if (writeflag==MEM_READ) { odata = d->dmac_reg[regnr]; /* debug("[ ps2: dmac read from D2_CHCR " "(0x%llx) ]\n", (long long)d->dmac_reg[regnr]); */ } else { /* debug("[ ps2: dmac write to D2_CHCR, " "data 0x%016llx ]\n", (long long) idata); */ if (idata & D_CHCR_STR) { int length = d->dmac_reg[D2_QWC_REG/0x10] * 16; uint64_t from_addr = d->dmac_reg[ D2_MADR_REG/0x10]; uint64_t to_addr = d->dmac_reg[ D2_TADR_REG/0x10]; unsigned char *copy_buf; debug("[ ps2: dmac [ch2] transfer addr=" "0x%016llx len=0x%lx ]\n", (long long) d->dmac_reg[D2_MADR_REG/0x10], (long)length); CHECK_ALLOCATION(copy_buf = (unsigned char *) malloc(length)); cpu->memory_rw(cpu, cpu->mem, from_addr, copy_buf, length, MEM_READ, CACHE_NONE | PHYSICAL); cpu->memory_rw(cpu, cpu->mem, d->other_memory_base[DMA_CH_GIF] + to_addr, copy_buf, length, MEM_WRITE, CACHE_NONE | PHYSICAL); free(copy_buf); /* Done with the transfer: */ d->dmac_reg[D2_QWC_REG/0x10] = 0; idata &= ~D_CHCR_STR; /* interrupt DMA channel 2 */ INTERRUPT_ASSERT(d->dma_channel2_irq); } else debug("[ ps2: dmac [ch2] stopping " "transfer ]\n"); d->dmac_reg[regnr] = idata; return 1; } break; case 0x8000 + D2_QWC_REG: case 0x8000 + D2_MADR_REG: case 0x8000 + D2_TADR_REG: /* no debug output */ break; case 0xe010: /* dmac interrupt status (and mask, */ /* the upper 16 bits) */ if (writeflag == MEM_WRITE) { uint32_t oldmask = d->dmac_reg[regnr] & 0xffff0000; /* Clear out those bits that are set in idata: */ d->dmac_reg[regnr] &= ~idata; d->dmac_reg[regnr] &= 0xffff; d->dmac_reg[regnr] |= oldmask; if (((d->dmac_reg[regnr] & 0xffff) & ((d->dmac_reg[regnr]>>16) & 0xffff)) == 0) { INTERRUPT_DEASSERT(d->dmac_irq); } } else { /* Hm... make it seem like the mask bits are (at least as much as) the interrupt assertions: */ odata = d->dmac_reg[regnr]; odata |= (odata << 16); } break; case 0xf000: /* interrupt register */ if (writeflag == MEM_READ) { odata = d->intr; debug("[ ps2: read from Interrupt Register:" " 0x%llx ]\n", (long long)odata); /* TODO: This is _NOT_ correct behavior: */ // d->intr = 0; // INTERRUPT_DEASSERT(d->intr_irq); } else { debug("[ ps2: write to Interrupt Register: " "0x%llx ]\n", (long long)idata); /* Clear out bits that are set in idata: */ d->intr &= ~idata; if ((d->intr & d->imask) == 0) INTERRUPT_DEASSERT(d->intr_irq); } break; case 0xf010: /* interrupt mask */ if (writeflag == MEM_READ) { odata = d->imask; /* debug("[ ps2: read from Interrupt Mask " "Register: 0x%llx ]\n", (long long)odata); */ } else { /* debug("[ ps2: write to Interrupt Mask " "Register: 0x%llx ]\n", (long long)idata); */ /* Note: written value indicates which bits to _toggle_, not which bits to set! */ d->imask ^= idata; } break; case 0xf230: /* sbus interrupt register? */ if (writeflag == MEM_READ) { odata = d->sbus_smflg; debug("[ ps2: read from SBUS SMFLG:" " 0x%llx ]\n", (long long)odata); } else { /* Clear bits on write: */ debug("[ ps2: write to SBUS SMFLG:" " 0x%llx ]\n", (long long)idata); d->sbus_smflg &= ~idata; /* irq 1 is SBUS */ if (d->sbus_smflg == 0) INTERRUPT_DEASSERT(d->sbus_irq); } break; default: if (writeflag==MEM_READ) { debug("[ ps2: read from addr 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)odata); } else { debug("[ ps2: write to addr 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(ps2) { struct ps2_data *d; int i; struct interrupt templ; char n[300]; CHECK_ALLOCATION(d = (struct ps2_data *) malloc(sizeof(struct ps2_data))); memset(d, 0, sizeof(struct ps2_data)); d->other_memory_base[DMA_CH_GIF] = DEV_PS2_GIF_FAKE_BASE; /* Connect to MIPS irq 2 (interrupt controller) and 3 (dmac): */ snprintf(n, sizeof(n), "%s.2", devinit->interrupt_path); INTERRUPT_CONNECT(n, d->intr_irq); snprintf(n, sizeof(n), "%s.3", devinit->interrupt_path); INTERRUPT_CONNECT(n, d->dmac_irq); /* * Register interrupts: * * 16 normal IRQs (machine[x].cpu[x].ps2_intr.%i) * 16 DMA IRQs (machine[x].cpu[x].ps2_dmac.%i) * 2 sbus IRQs (machine[x].cpu[x].ps2_sbus.%i) */ for (i=0; i<16; i++) { snprintf(n, sizeof(n), "%s.ps2_intr.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = n; templ.extra = d; templ.interrupt_assert = ps2_intr_interrupt_assert; templ.interrupt_deassert = ps2_intr_interrupt_deassert; interrupt_handler_register(&templ); } for (i=0; i<16; i++) { snprintf(n, sizeof(n), "%s.ps2_dmac.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = n; templ.extra = d; templ.interrupt_assert = ps2_dmac_interrupt_assert; templ.interrupt_deassert = ps2_dmac_interrupt_deassert; interrupt_handler_register(&templ); } for (i=0; i<2; i++) { snprintf(n, sizeof(n), "%s.ps2_sbus.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = n; templ.extra = d; templ.interrupt_assert = ps2_sbus_interrupt_assert; templ.interrupt_deassert = ps2_sbus_interrupt_deassert; interrupt_handler_register(&templ); } /* Connect to DMA channel 2 irq: */ snprintf(n, sizeof(n), "%s.ps2_dmac.2", devinit->interrupt_path); INTERRUPT_CONNECT(n, d->dma_channel2_irq); /* Connect to SBUS interrupt, at ps2 interrupt 1: */ snprintf(n, sizeof(n), "%s.ps2_intr.1", devinit->interrupt_path); INTERRUPT_CONNECT(n, d->sbus_irq); /* Connect to the timers' interrupts: */ for (i=0; iinterrupt_path, 9 + i); INTERRUPT_CONNECT(n, d->timer_irq[i]); } memory_device_register(devinit->machine->memory, "ps2", devinit->addr, DEV_PS2_LENGTH, dev_ps2_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_ps2_tick, d, TICK_STEPS_SHIFT); return 1; } gxemul-0.6.1/src/devices/fonts/000755 001750 001750 00000000000 13402411502 016567 5ustar00debugdebug000000 000000 gxemul-0.6.1/src/devices/dev_osiop.cc000644 001750 001750 00000061403 13402411502 017740 0ustar00debugdebug000000 000000 /* * Copyright (C) 2008-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: NCR 53C710 SCSI I/O Processor (SIOP) * * Based on reverse-engineering OpenBSD's osiop.c, and a PDF manual: * "Symbios SYM53C710 SCSI I/O Processor Technical Manual, version 3.1". * * See e.g. openbsd/sys/dev/microcode/siop/osiop.ss for an example of what * the SCRIPTS assembly language looks like (or osiop.out for the raw result). * * * TODOs: * * o) Target mode. Right now, only Initiator mode is implemented. * o) Errors. Right now, the emulator aborts if there is a SCSI error. * o) Allow all phases to do partial transfers. Right now, only data in * and data out support this (hackish). */ #include #include #include #include "console.h" #include "cpu.h" #include "device.h" #include "diskimage.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/osiopreg.h" /* #define debug fatal */ const int osiop_debug = 0; static const char *phases[8] = { "DATA_OUT", "DATA_IN", "COMMAND", "STATUS", "RESERVED_OUT", "RESERVED_IN", "MSG_OUT", "MSG_IN" }; #define DEV_OSIOP_LENGTH OSIOP_NREGS #define OSIOP_CHIP_REVISION 2 #define MAX_SCRIPTS_PER_CHUNK 256 /* 256 may be a reasonable value? */ #define OSIOP_TICK_SHIFT 17 struct osiop_data { struct interrupt irq; int asserted; int scripts_running; /* Current transfer: */ int selected_id; struct scsi_transfer *xferp; size_t data_offset; /* Cached emulated physical RAM page lookup: */ uint32_t last_phys_page; uint8_t *last_host_page; /* ALU: */ int carry; /* * Most of these are byte-addressed, but some are not. (Note: For * convenience, 32-bit words are stored in host byte order!) */ uint8_t reg[OSIOP_NREGS]; }; static void osiop_free_xfer(struct osiop_data *d) { if (d->xferp != NULL) scsi_transfer_free(d->xferp); d->xferp = NULL; } /* Allocate memory for a new transfer. */ static void osiop_new_xfer(struct osiop_data *d, int target_scsi_id) { if (d->xferp != NULL) { fatal("WARNING! osiop_new_xfer(): freeing previous" " transfer\n"); osiop_free_xfer(d); } d->selected_id = target_scsi_id; d->xferp = scsi_transfer_alloc(); } static int osiop_get_scsi_phase(struct osiop_data *d) { return OSIOP_PHASE(d->reg[OSIOP_SOCL]); } static void osiop_set_scsi_phase(struct osiop_data *d, int phase) { int mask = OSIOP_MSG | OSIOP_CD | OSIOP_IO; d->reg[OSIOP_SOCL] &= ~mask; d->reg[OSIOP_SOCL] |= (phase & mask); } /* * osiop_update_sip_and_dip(): * * The SIP bit in ISTAT is basically a "summary" of whether there is * a non-masked SCSI interrupt. Similarly for DIP, for DMA. * * However, the SIP and DIP bits are set even if interrupts are * masked away using DIEN and SIEN. (At least that is how I understood * things from reading OpenBSD's osiop.c osiop_poll().) */ static int osiop_update_sip_and_dip(struct osiop_data *d) { int assert = 0; /* First, let's assume no interrupt assertions. */ d->reg[OSIOP_ISTAT] &= ~(OSIOP_ISTAT_SIP | OSIOP_ISTAT_DIP); /* Any enabled SCSI interrupts? */ if (d->reg[OSIOP_SSTAT0]) d->reg[OSIOP_ISTAT] |= OSIOP_ISTAT_SIP; if (d->reg[OSIOP_SSTAT0] & d->reg[OSIOP_SIEN]) assert = 1; /* Or enabled DMA interrupts? */ if (d->reg[OSIOP_DSTAT] & ~OSIOP_DIEN_RES) d->reg[OSIOP_ISTAT] |= OSIOP_ISTAT_DIP; if (d->reg[OSIOP_DSTAT] & d->reg[OSIOP_DIEN] & ~OSIOP_DIEN_RES) assert = 1; return assert; } /* * osiop_reassert_interrupts(): * * Recalculate interrupt assertions; if either of the SIP or DIP bits * in the ISTAT register is set, then we should cause an interrupt. * * (The d->asserted stuff is to make sure we don't call INTERRUPT_DEASSERT * etc. too often when not necessary. Just an optimization.) */ static void osiop_reassert_interrupts(struct osiop_data *d) { int assert = 0; if (osiop_update_sip_and_dip(d)) assert = 1; if (assert && !d->asserted) INTERRUPT_ASSERT(d->irq); if (!assert && d->asserted) INTERRUPT_DEASSERT(d->irq); d->asserted = assert; } /* Helper: returns a word in host order, from emulated physical RAM. */ static uint32_t read_word(struct osiop_data *d, struct cpu *cpu, uint32_t addr) { uint32_t word; if (d->last_host_page == NULL || d->last_phys_page != (addr & 0xfffff000)) { d->last_phys_page = addr & 0xfffff000; d->last_host_page = memory_paddr_to_hostaddr(cpu->mem, d->last_phys_page, 0); } word = *((uint32_t *) (d->last_host_page + (addr & 0xffc))); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) word = LE32_TO_HOST(word); else word = BE32_TO_HOST(word); return word; } /* Helper: reads/writes single bytes from emulated physical RAM. */ static uint8_t read_byte(struct osiop_data *d, struct cpu *cpu, uint32_t addr) { if (d->last_host_page == NULL || d->last_phys_page != (addr & 0xfffff000)) { d->last_phys_page = addr & 0xfffff000; d->last_host_page = memory_paddr_to_hostaddr(cpu->mem, d->last_phys_page, 0); } return d->last_host_page[addr & 0xfff]; } static void write_byte(struct osiop_data *d, struct cpu *cpu, uint32_t addr, uint8_t byte) { if (d->last_host_page == NULL || d->last_phys_page != (addr & 0xfffff000)) { d->last_phys_page = addr & 0xfffff000; d->last_host_page = memory_paddr_to_hostaddr(cpu->mem, d->last_phys_page, 1); } d->last_host_page[addr & 0xfff] = byte; } /* * osiop_get_next_scripts_word(): * * Reads a 32-bit word at physical memory location DSP, and returns it * in host order. DSP is then advanced to point to the next instruction word. * * (NOTE/TODO: This could be optimized to read from a host page directly, * but then care must be taken when the instruction pointer (DSP) goes * over a page boundary to the next page. At least the page lookup * could be "cached"...) */ uint32_t osiop_get_next_scripts_word(struct cpu *cpu, struct osiop_data *d) { uint32_t *dspp = (uint32_t*) &d->reg[OSIOP_DSP]; uint32_t dsp = *dspp; uint32_t instr; if (dsp & 3) { fatal("osiop_get_next_scripts_word: unaligned DSP 0x%08x\n", dsp); exit(1); } instr = read_word(d, cpu, dsp); dsp += sizeof(instr); *dspp = dsp; return instr; } /* * osiop_execute_scripts_instr(): * * Interprets a single SCRIPTS machine code instruction. Returns 1 if * execution should continue, or 0 if there was an interrupt. * * See "Symbios SYM53C710 SCSI I/O Processor Technical Manual, version 3.1" * chapter 5 for details about the instruction set. */ int osiop_execute_scripts_instr(struct cpu *cpu, struct osiop_data *d) { uint32_t *dsap = (uint32_t*) &d->reg[OSIOP_DSA]; uint32_t *dnadp = (uint32_t*) &d->reg[OSIOP_DNAD]; uint32_t *dbcp = (uint32_t*) &d->reg[OSIOP_DBC]; uint32_t *dspsp = (uint32_t*) &d->reg[OSIOP_DSPS]; uint32_t *dspp = (uint32_t*) &d->reg[OSIOP_DSP]; uint32_t *tempp = (uint32_t*) &d->reg[OSIOP_TEMP]; uint32_t dspOrig = *dspp; uint32_t instr1 = osiop_get_next_scripts_word(cpu, d); uint32_t instr2 = osiop_get_next_scripts_word(cpu, d); uint32_t dbc, target_addr = 0; uint8_t dcmd; int32_t reladdr; int opcode, phase, relative_addressing, table_indirect_addressing; int select_with_atn, scsi_ids_to_select = -1, scsi_id_to_select; int test_carry, compare_data, compare_phase; int jump_if_true, wait_for_valid_phase; int comparison = 0, interrupt_instead_of_branch = 0; /* * According to the 53C710 manual, chapter 5 (introduction): the first * 32-bit word is always loaded into DCMD and DBC, the second into * DSPS, the third (only used by memory move instructions) is loaded * into the TEMP register. */ dcmd = d->reg[OSIOP_DCMD] = instr1 >> 24; dbc = *dbcp = instr1 & 0x00ffffff; *dspsp = instr2; reladdr = (instr2 << 8); reladdr >>= 8; opcode = (dcmd >> 3) & 7; phase = dcmd & 7; if (osiop_debug) debug("{ SCRIPTS @ 0x%08x: 0x%08x 0x%08x", (int) dspOrig, (int) instr1, (int) instr2); switch (dcmd & 0xc0) { case 0x00: { int ofs1 = instr1 & 0x00ffffff; int ofs2 = instr2 & 0x00ffffff; int indirect_addressing = dcmd & 0x20; uint32_t dsa = *dsap; uint32_t addr, xfer_byte_count, xfer_addr; int32_t tmp = ofs2 << 8; int res; size_t i; tmp >>= 8; table_indirect_addressing = dcmd & 0x10; opcode = (dcmd >> 3) & 1; switch (opcode) { case 0: if (osiop_debug) debug(": CHMOV"); break; case 1: if (osiop_debug) debug(": MOVE"); break; } if (indirect_addressing) { fatal("osiop: TODO: indirect_addressing move\n"); exit(1); } if (!table_indirect_addressing) { fatal("osiop: TODO: !table_indirect_addressing move\n"); exit(1); } if (osiop_debug) debug(" FROM %i", tmp); if (ofs1 != ofs2) { fatal("osiop: TODO: move ofs1!=ofs2\n"); exit(1); } if (phase != osiop_get_scsi_phase(d)) { fatal("osiop: TODO: move: wait for phase. " "phase = %i, osiop_get_scsi_phase = %i\n", phase, osiop_get_scsi_phase(d)); exit(1); } if (osiop_debug) debug(" WHEN %s", phases[phase]); addr = dsa + tmp; xfer_byte_count = read_word(d, cpu, addr) & 0x00ffffff; xfer_addr = read_word(d, cpu, addr+4); switch (phase) { case MSG_OUT_PHASE: scsi_transfer_allocbuf(&d->xferp->msg_out_len, &d->xferp->msg_out, xfer_byte_count, 0); i = 0; while (xfer_byte_count > 0) { uint8_t byte = read_byte(d, cpu, xfer_addr); /* debug(" reading msg_out byte @ 0x%08x = 0x%02x\n", xfer_addr, byte); */ d->xferp->msg_out[i++] = byte; xfer_addr ++; xfer_byte_count --; } osiop_set_scsi_phase(d, COMMAND_PHASE); break; case COMMAND_PHASE: scsi_transfer_allocbuf(&d->xferp->cmd_len, &d->xferp->cmd, xfer_byte_count, 0); i = 0; while (xfer_byte_count > 0) { uint8_t byte = read_byte(d, cpu, xfer_addr); /* debug(" reading cmd byte @ 0x%08x = 0x%02x\n", xfer_addr, byte); */ d->xferp->cmd[i++] = byte; xfer_addr ++; xfer_byte_count --; } res = diskimage_scsicommand(cpu, d->selected_id, DISKIMAGE_SCSI, d->xferp); if (res == 0) { fatal("osiop TODO: error\n"); exit(1); } d->data_offset = 0; if (res == 2) osiop_set_scsi_phase(d, DATA_OUT_PHASE); else if (d->xferp->data_in_len > 0) osiop_set_scsi_phase(d, DATA_IN_PHASE); else osiop_set_scsi_phase(d, STATUS_PHASE); break; case DATA_OUT_PHASE: if (d->xferp->data_out == NULL) scsi_transfer_allocbuf(&d->xferp->data_out_len, &d->xferp->data_out, d->xferp->data_out_len, 0); while (xfer_byte_count > 0) { uint8_t byte = read_byte(d, cpu, xfer_addr); /* debug(" reading data_out byte @ 0x%08x = 0x%02x\n", xfer_addr, byte); */ d->xferp->data_out[d->xferp->data_out_offset++] = byte; xfer_addr ++; xfer_byte_count --; } /* Rerun the command to actually write out the data: */ res = diskimage_scsicommand(cpu, d->selected_id, DISKIMAGE_SCSI, d->xferp); if (res == 0) { fatal("osiop TODO: error on rerun\n"); exit(1); } else if (res == 2) { /* Stay at data out phase. */ } else { osiop_set_scsi_phase(d, STATUS_PHASE); } break; case DATA_IN_PHASE: i = 0; while (xfer_byte_count > 0 && i + d->data_offset < d->xferp->data_in_len) { uint8_t byte = d->xferp->data_in[i + d->data_offset]; i ++; /* debug(" writing data_in byte @ 0x%08x = 0x%02x\n", xfer_addr, byte); */ write_byte(d, cpu, xfer_addr, byte); xfer_addr ++; xfer_byte_count --; } d->data_offset += i; if (d->data_offset >= d->xferp->data_in_len) osiop_set_scsi_phase(d, STATUS_PHASE); break; case STATUS_PHASE: i = 0; while (xfer_byte_count > 0 && i < d->xferp->status_len) { uint8_t byte = d->xferp->status[i++]; /* debug(" writing status byte @ 0x%08x = 0x%02x\n", xfer_addr, byte); */ write_byte(d, cpu, xfer_addr, byte); xfer_addr ++; xfer_byte_count --; } osiop_set_scsi_phase(d, MSG_IN_PHASE); break; case MSG_IN_PHASE: i = 0; while (xfer_byte_count > 0 && i < d->xferp->msg_in_len) { uint8_t byte = d->xferp->msg_in[i++]; /* debug(" writing msg_in byte @ 0x%08x = 0x%02x\n", xfer_addr, byte); */ write_byte(d, cpu, xfer_addr, byte); xfer_addr ++; xfer_byte_count --; } /* Done. */ osiop_free_xfer(d); break; default:fatal("osiop: TODO: unimplemented move, " "phase=%i\n", phase); exit(1); } /* Transfer complete. */ *dnadp = xfer_addr; *dbcp = xfer_byte_count; d->reg[OSIOP_DFIFO] = 0; /* TODO */ } break; case 0x40: /* I/O or Read/Write */ relative_addressing = dcmd & 4; table_indirect_addressing = dcmd & 2; select_with_atn = dcmd & 1; scsi_ids_to_select = (dbc >> 16) & 0xff; switch (opcode) { case 0: if (osiop_debug) debug(": SELECT"); if (select_with_atn) { if (osiop_debug) debug(" ATN"); d->reg[OSIOP_SOCL] |= OSIOP_ATN; } if (table_indirect_addressing) { uint32_t dsa = *dsap; uint32_t addr, word; int32_t tmp = dbc << 8; tmp >>= 8; addr = dsa + tmp; if (osiop_debug) debug(" FROM %i", dbc); word = read_word(d, cpu, addr); scsi_ids_to_select = (word >> 16) & 0xff; } if (scsi_ids_to_select == 0) { fatal("osiop: TODO: scsi_ids_to_select = 0!\n"); exit(1); } scsi_id_to_select = 0; while (!(scsi_ids_to_select & 1)) { scsi_ids_to_select >>= 1; scsi_id_to_select ++; } scsi_ids_to_select &= ~1; if (scsi_ids_to_select != 0) { fatal("osiop: TODO: multiselect?\n"); exit(1); } if (osiop_debug) debug(" [SCSI ID %i]", scsi_id_to_select); if (relative_addressing) { /* Note: Relative to _current_ DSP value, not what the DSP was when the current instruction was read! */ target_addr = reladdr + *dspp; if (osiop_debug) debug(" REL(%i)", reladdr); } else { target_addr = instr2; if (osiop_debug) debug(" 0x%08x", instr2); } if (diskimage_exist(cpu->machine, scsi_id_to_select, DISKIMAGE_SCSI)) { osiop_new_xfer(d, scsi_id_to_select); /* TODO: Just a guess, so far: */ osiop_set_scsi_phase(d, MSG_OUT_PHASE); } else { d->selected_id = -1; #if 1 /* TODO: The scsi ID does not exist. Should we simply timeout: */ d->scripts_running = 0; #else /* or branch to the reselect address? */ *(uint32_t*) &d->reg[OSIOP_DSP] = target_addr; #endif } break; case 1: if (osiop_debug) debug(": WAIT DISCONNECT"); /* TODO */ break; case 2: if (osiop_debug) debug(": WAIT RESELECT"); fatal("osiop: TODO: wait reselect\n"); exit(1); break; case 3: if (osiop_debug) debug(": SET"); break; case 4: if (osiop_debug) debug(": CLEAR"); break; default:fatal(": UNIMPLEMENTED dcmd=0x%02x opcode=%i\n", dcmd, opcode); exit(1); } /* SET or CLEAR: */ if (opcode == 3 || opcode == 4) { int bit_atn = (dbc >> 3) & 1; int bit_ack = (dbc >> 6) & 1; int bit_target = (dbc >> 9) & 1; int bit_carry = (dbc >> 10) & 1; if (osiop_debug) { if (bit_atn) debug(" ATN"); if (bit_ack) debug(" ACK"); if (bit_target) debug(" TARGET"); if (bit_carry) debug(" CARRY"); } if (opcode == 3) { d->reg[OSIOP_SOCL] |= (bit_ack * OSIOP_ACK); d->reg[OSIOP_SOCL] |= (bit_atn * OSIOP_ATN); if (bit_carry) d->carry = 1; d->reg[OSIOP_SCNTL0] |= (bit_target * OSIOP_SCNTL0_TRG); } else { d->reg[OSIOP_SOCL] &= ~(bit_ack * OSIOP_ACK); d->reg[OSIOP_SOCL] &= ~(bit_atn * OSIOP_ATN); if (bit_carry) d->carry = 0; d->reg[OSIOP_SCNTL0] &= ~(bit_target * OSIOP_SCNTL0_TRG); } } break; case 0x80: /* Transfer Control */ relative_addressing = (dbc >> 23) & 1; test_carry = (dbc >> 21) & 1; jump_if_true = (dbc >> 19) & 1; compare_data = (dbc >> 18) & 1; compare_phase = (dbc >> 17) & 1; wait_for_valid_phase = (dbc >> 16) & 1; switch (opcode) { case 0: if (osiop_debug) debug(": JUMP"); break; case 1: if (osiop_debug) debug(": CALL"); break; case 2: if (osiop_debug) debug(": RETURN"); break; case 3: if (osiop_debug) debug(": INTERRUPT"); break; default:fatal(": UNIMPLEMENTED dcmd=0x%02x opcode=%i\n", dcmd, opcode); exit(1); } if (opcode == 0 || opcode == 1) { if (relative_addressing) { /* Note: Relative to _current_ DSP value, not what it was when the current instruction was read! */ target_addr = reladdr + *dspp; if (osiop_debug) debug(" REL(%i)", reladdr); } else { target_addr = instr2; if (osiop_debug) debug(" 0x%08x", instr2); } } else { if (opcode == 2) { /* Return: */ target_addr = *tempp; } else { /* Interrupt: */ interrupt_instead_of_branch = 1; } } if (test_carry) { if (compare_data || compare_phase) { fatal("osiop: TODO: test_carry cannot be" " combined with other tests!\n"); exit(1); } fatal("osiop: TODO: test_carry\n"); exit(1); } if (compare_data) { fatal("osiop: TODO: compare_data\n"); exit(1); } if (compare_phase) { int cur_phase; if (osiop_debug) debug(" %s %s%s", wait_for_valid_phase ? "WHEN" : "IF", jump_if_true? "" : "NOT ", phases[phase]); /* TODO: wait for valid phase! */ cur_phase = osiop_get_scsi_phase(d); comparison = (phase == cur_phase); } if (!test_carry && !compare_data && !compare_phase) jump_if_true = comparison = 1; if ((jump_if_true && comparison) || (!jump_if_true && !comparison)) { /* Perform the branch or interrupt. */ if (interrupt_instead_of_branch) { d->scripts_running = 0; d->reg[OSIOP_DSTAT] |= OSIOP_DSTAT_SIR; } else { *dspp = target_addr; } } break; case 0xc0: if (osiop_debug) debug(": MEMORY MOVE"); /* TODO: third instruction word! */ fatal(": TODO\n"); exit(1); break; default:fatal(": UNIMPLEMENTED dcmd 0x%02x\n", dcmd); exit(1); } if (osiop_debug) debug(" }\n"); return 1; } /* * osiop_execute_scripts(): * * Interprets SCRIPTS machine code by reading one instruction word at a time, * and executing it. */ void osiop_execute_scripts(struct cpu *cpu, struct osiop_data *d) { int n = 0; if (osiop_debug) debug("{ SCRIPTS start }\n"); while (d->scripts_running && n < MAX_SCRIPTS_PER_CHUNK && osiop_execute_scripts_instr(cpu, d)) n++; if (osiop_debug) debug("{ SCRIPTS end }\n"); } DEVICE_TICK(osiop) { struct osiop_data *d = (struct osiop_data *) extra; if (d->scripts_running) osiop_execute_scripts(cpu, d); osiop_reassert_interrupts(d); } DEVICE_ACCESS(osiop) { uint64_t idata = 0, odata = 0; uint8_t oldreg = 0; struct osiop_data *d = (struct osiop_data *) extra; int origofs = relative_addr; int non1lenOk = 0; idata = memory_readmax64(cpu, data, len); /* Make relative_addr suit addresses in osiopreg.h: */ if (cpu->byte_order == EMUL_BIG_ENDIAN) { relative_addr = (relative_addr & ~3) | (3 - (relative_addr & 3)); } if (len == sizeof(uint32_t)) { /* * NOTE: These are stored in HOST byte order! */ switch (origofs) { case OSIOP_DSA: case OSIOP_TEMP: case OSIOP_DBC: case OSIOP_DNAD: case OSIOP_DSP: case OSIOP_DSPS: case OSIOP_SCRATCH: case OSIOP_ADDER: relative_addr = origofs; non1lenOk = 1; uint32_t *p = (uint32_t*) &d->reg[origofs]; if (writeflag == MEM_WRITE) *p = idata; else odata = *p; break; } } else { /* Byte access: */ oldreg = d->reg[relative_addr]; if (writeflag == MEM_WRITE) d->reg[relative_addr] = idata; else odata = oldreg; } switch (relative_addr) { case OSIOP_SCNTL0: case OSIOP_SCNTL1: break; case OSIOP_SIEN: /* Used by OpenBSD/mvme88k during probing: */ if (len == 4) non1lenOk = 1; if (writeflag == MEM_WRITE) osiop_reassert_interrupts(d); break; case OSIOP_SCID: if (idata != oldreg) { fatal("osiop TODO: attempt to change SCID?\n"); exit(1); } break; case OSIOP_SBDL: if (writeflag == MEM_WRITE) fatal("[ osiop: SBDL set to 0x%x, but should be " "read-only! ]\n", (int) idata); break; case OSIOP_SBCL: if (writeflag == MEM_WRITE) { if (osiop_debug) debug("[ osiop: SBCL set to 0x%x ]\n", (int) idata); } break; case OSIOP_DSTAT: /* Cleared when read. Most likely not writable. */ odata = d->reg[OSIOP_DSTAT]; d->reg[OSIOP_DSTAT] = OSIOP_DSTAT_DFE; osiop_reassert_interrupts(d); break; case OSIOP_SSTAT0: /* Cleared when read. Most likely not writable. */ odata = d->reg[OSIOP_SSTAT0]; d->reg[OSIOP_SSTAT0] = 0; osiop_reassert_interrupts(d); break; case OSIOP_SSTAT1: case OSIOP_SSTAT2: break; case OSIOP_DSA: if (writeflag == MEM_WRITE) { if (osiop_debug) debug("[ osiop: DSA set to 0x%x ]\n", (int) idata); } break; case OSIOP_CTEST0: case OSIOP_CTEST1: case OSIOP_CTEST2: case OSIOP_CTEST3: case OSIOP_CTEST4: case OSIOP_CTEST5: case OSIOP_CTEST6: case OSIOP_CTEST7: break; case OSIOP_TEMP: if (writeflag == MEM_WRITE) { if (osiop_debug) debug("[ osiop: TEMP set to 0x%x ]\n", (int) idata); } break; case OSIOP_DFIFO: break; case OSIOP_ISTAT: if (writeflag == MEM_WRITE) { if ((idata & 0x3f) != 0x00) { fatal("osiop TODO: istat 0x%x\n", (int) idata); exit(1); } d->reg[relative_addr] = idata & ~(OSIOP_ISTAT_ABRT | OSIOP_ISTAT_RST); osiop_reassert_interrupts(d); } break; case OSIOP_CTEST8: odata = (odata & 0xf) | (OSIOP_CHIP_REVISION << 4); break; case OSIOP_DBC: break; case OSIOP_DSP: if (writeflag == MEM_WRITE) { if (osiop_debug) debug("[ osiop: DSP set to 0x%x ]\n", (int) idata); d->scripts_running = 1; osiop_execute_scripts(cpu, d); osiop_reassert_interrupts(d); } break; case OSIOP_DSPS: case OSIOP_SCRATCH: break; case OSIOP_DMODE: break; case OSIOP_DIEN: if (writeflag == MEM_WRITE) osiop_reassert_interrupts(d); break; case OSIOP_DWT: break; case OSIOP_DCNTL: if (writeflag == MEM_WRITE) { if (idata & OSIOP_DCNTL_SSM) { fatal("osiop TODO: SSM\n"); exit(1); } if (idata & OSIOP_DCNTL_LLM) { fatal("osiop TODO: LLM\n"); exit(1); } if (idata & OSIOP_DCNTL_STD) { fatal("osiop TODO: STD\n"); exit(1); } } break; default: if (writeflag == MEM_READ) { fatal("[ osiop: read from 0x%02lx ]\n", (long)relative_addr); } else { fatal("[ osiop: write to 0x%02lx: 0x%02x ]\n", (long)relative_addr, (int)idata); } exit(1); } if (len != 1 && !non1lenOk) { fatal("[ osiop: TODO: len != 1, addr 0x%0x ]\n", (int)relative_addr); exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(osiop) { struct osiop_data *d; CHECK_ALLOCATION(d = (struct osiop_data *) malloc(sizeof(struct osiop_data))); memset(d, 0, sizeof(struct osiop_data)); /* Set up initial device register values: */ d->reg[OSIOP_SCID] = OSIOP_SCID_VALUE(7); /* OpenBSD's osiop_checkintr needs this: */ d->reg[OSIOP_CTEST1] = OSIOP_CTEST1_FMT; INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); memory_device_register(devinit->machine->memory, "osiop", devinit->addr, DEV_OSIOP_LENGTH, dev_osiop_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_osiop_tick, d, OSIOP_TICK_SHIFT); return 1; } gxemul-0.6.1/src/devices/dev_sgi_ip30.cc000644 001750 001750 00000023546 13402411502 020232 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SGI IP30 ("Octane") stuff * * NOTE/TODO: This is just comprised of hardcoded guesses so far. (Ugly.) */ #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #define DEV_SGI_IP30_LENGTH 0x80000 struct sgi_ip30_data { /* ip30: */ uint64_t imask0; /* 0x10000 */ uint64_t reg_0x10018; uint64_t isr; /* 0x10030 */ uint64_t reg_0x20000; uint64_t reg_0x30000; /* ip30_2: */ uint64_t reg_0x0029c; /* ip30_3: */ uint64_t reg_0x00284; /* ip30_4: */ uint64_t reg_0x000b0; /* ip30_5: */ uint64_t reg_0x00000; }; DEVICE_TICK(sgi_ip30) { struct sgi_ip30_data *d = (struct sgi_ip30_data *) extra; d->reg_0x20000 += 1000; if (d->imask0 & ((int64_t)1<<50)) { /* TODO: Only interrupt if reg 0x20000 (the counter) has passed the compare (0x30000). */ fatal("IP30 legacy interrupt rewrite: TODO\n"); abort(); // cpu_interrupt(cpu, 8+1 + 50); } } DEVICE_ACCESS(sgi_ip30) { struct sgi_ip30_data *d = (struct sgi_ip30_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0x20: /* Memory bank configuration: */ odata = 0x80010000ULL; break; case 0x10000: /* Interrupt mask register 0: */ if (writeflag == MEM_WRITE) { d->imask0 = idata; } else { odata = d->imask0; } break; case 0x10018: /* * If this is not implemented, the IP30 PROM complains during * bootup: * * *FAILED* * Address: 0xffffffffaff10018, Expected: * 0x0000000000000001, Received: 0x0000000000000000 */ if (writeflag == MEM_WRITE) { d->reg_0x10018 = idata; } else { odata = d->reg_0x10018; } break; case 0x10020: /* Set ISR, according to Linux/IP30 */ d->isr = idata; /* Recalculate CPU interrupt assertions: */ fatal("IP30 legacy interrupt rewrite: TODO\n"); abort(); // cpu_interrupt(cpu, 8); break; case 0x10028: /* Clear ISR, according to Linux/IP30 */ d->isr &= ~idata; /* Recalculate CPU interrupt assertions: */ fatal("IP30 legacy interrupt rewrite: TODO\n"); abort(); // cpu_interrupt(cpu, 8); break; case 0x10030: /* Interrupt Status Register */ if (writeflag == MEM_WRITE) { /* Clear-on-write (TODO: is this correct?) */ d->isr &= ~idata; /* Recalculate CPU interrupt assertions: */ fatal("IP30 legacy interrupt rewrite: TODO\n"); abort(); // cpu_interrupt(cpu, 8); } else { odata = d->isr; } break; case 0x20000: /* A counter */ if (writeflag == MEM_WRITE) { d->reg_0x20000 = idata; } else { odata = d->reg_0x20000; } break; case 0x30000: if (writeflag == MEM_WRITE) { d->reg_0x30000 = idata; } else { odata = d->reg_0x30000; } break; default: if (writeflag == MEM_WRITE) { debug("[ sgi_ip30: unimplemented write to address " "0x%x, data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { debug("[ sgi_ip30: unimplemented read from address" " 0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(sgi_ip30_2) { struct sgi_ip30_data *d = (struct sgi_ip30_data *) extra; uint64_t idata = 0, odata = 0; idata = memory_readmax64(cpu, data, len); switch (relative_addr) { /* 0x114 + 0x40 * (wid - 8): 0x80000000 for "alive", according to Linux/IP30 */ case 0x114 + 0x40 * (12 - 8): fatal("[ IP30: asdvasdvnb ]\n"); odata = 0x80000000; break; case 0x0029c: /* * If this is not implemented, the IP30 PROM complains during * bootup: * * *FAILED* * Address: 0xffffffffb000029c, Expected: * 0x0000000000000001, Received: 0x0000000000000000 */ if (writeflag == MEM_WRITE) { d->reg_0x0029c = idata; } else { odata = d->reg_0x0029c; } break; default: if (writeflag == MEM_WRITE) { debug("[ sgi_ip30_2: unimplemented write to " "address 0x%x, data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { debug("[ sgi_ip30_2: unimplemented read from address " "0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(sgi_ip30_3) { struct sgi_ip30_data *d = (struct sgi_ip30_data *) extra; uint64_t idata = 0, odata = 0; idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0xb4: if (writeflag == MEM_WRITE) { debug("[ sgi_ip30_3: unimplemented write to " "address 0x%x, data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { odata = 2; /* should be 2, or Irix loops */ } break; case 0x00104: if (writeflag == MEM_WRITE) { debug("[ sgi_ip30_3: unimplemented write to address " "0x%x, data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { odata = 64; /* should be 64, or the PROM complains */ } break; case 0x00284: /* * If this is not implemented, the IP30 PROM complains during * bootup: * * *FAILED* * Address: 0xffffffffbf000284, Expected: * 0x0000000000000001, Received: 0x0000000000000000 */ if (writeflag == MEM_WRITE) { d->reg_0x00284 = idata; } else { odata = d->reg_0x00284; } break; default: if (writeflag == MEM_WRITE) { debug("[ sgi_ip30_3: unimplemented write to address " "0x%x, data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { debug("[ sgi_ip30_3: unimplemented read from " "address 0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(sgi_ip30_4) { struct sgi_ip30_data *d = (struct sgi_ip30_data *) extra; uint64_t idata = 0, odata = 0; idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0x000b0: /* * If this is not implemented, the IP30 PROM complains during * bootup: * * *FAILED* * Address: 0xffffffffbf6000b0, Expected: * 0x0000000000000001, Received: 0x0000000000000000 */ if (writeflag == MEM_WRITE) { d->reg_0x000b0 = idata; } else { odata = d->reg_0x000b0; } break; default: if (writeflag == MEM_WRITE) { debug("[ sgi_ip30_4: unimplemented write to address" " 0x%x, data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { debug("[ sgi_ip30_4: unimplemented read from address" " 0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(sgi_ip30_5) { struct sgi_ip30_data *d = (struct sgi_ip30_data *) extra; uint64_t idata = 0, odata = 0; idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0x00000: if (writeflag == MEM_WRITE) { d->reg_0x00000 = idata; } else { odata = d->reg_0x00000; } break; default: if (writeflag == MEM_WRITE) { debug("[ sgi_ip30_5: unimplemented write to address " "0x%x, data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { debug("[ sgi_ip30_5: unimplemented read from address " "0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(sgi_ip30) { struct sgi_ip30_data *d; CHECK_ALLOCATION(d = (struct sgi_ip30_data *) malloc(sizeof(struct sgi_ip30_data))); memset(d, 0, sizeof(struct sgi_ip30_data)); memory_device_register(devinit->machine->memory, "sgi_ip30_1", devinit->addr, DEV_SGI_IP30_LENGTH, dev_sgi_ip30_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, "sgi_ip30_2", 0x10000000, 0x10000, dev_sgi_ip30_2_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, "sgi_ip30_3", 0x1f000000, 0x10000, dev_sgi_ip30_3_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, "sgi_ip30_4", 0x1f600000, 0x10000, dev_sgi_ip30_4_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, "sgi_ip30_5", 0x1f6c0000, 0x10000, dev_sgi_ip30_5_access, (void *)d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_sgi_ip30_tick, d, 16); return 1; } gxemul-0.6.1/src/devices/dev_pcc2.cc000644 001750 001750 00000041204 13402411502 017433 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2014 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Peripheral Channel Controller (PCC2) bus (used in MVME machines) * * See "Single Board Computers Programmer's Reference Guide (Part 2 of 2)", * "VMESBCA2/PG1" (vmesbcp2.pdf) for more details. * * Note: This is somewhat MVME187-specific, at the moment. * * Implemented so far: * Timers 1 and 2. * The interrupt controller mechanism (partially!) * * TODO: * All devices appart from the timers. */ #include #include #include #include "cpu.h" #include "device.h" #include "emul.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/mvme187.h" #include "thirdparty/mvme_pcctworeg.h" #define INTERRUPT_LEVEL_MASK 0x07 #define PCC_TIMER_TICK_HZ 100.0 #define DEV_PCC2_TICK_SHIFT 14 // #define debug fatal struct pcc2_data { struct interrupt cpu_irq; uint8_t pcctwo_reg[PCC2_SIZE]; uint8_t cur_int_vec[8]; /* Timers: */ struct timer *timer; int pending_timer1_interrupts; int pending_timer2_interrupts; }; static uint32_t read32(unsigned char *p) { uint32_t x = 0; size_t i; for (i=0; i>= 8; } } static void pcc_timer_tick(struct timer *t, void *extra) { struct pcc2_data *d = (struct pcc2_data *) extra; /* The PCC2 timers run at 1 MHz. */ int steps = (int) (1000000.0 / PCC_TIMER_TICK_HZ); uint32_t count1, count2, compare1, compare2; int interrupt1 = 0, interrupt2 = 0; /* Read values: */ count1 = read32(&d->pcctwo_reg[PCCTWO_T1COUNT]); count2 = read32(&d->pcctwo_reg[PCCTWO_T2COUNT]); compare1 = read32(&d->pcctwo_reg[PCCTWO_T1CMP]); compare2 = read32(&d->pcctwo_reg[PCCTWO_T2CMP]); /* Timer enabled? Then count... */ if (d->pcctwo_reg[PCCTWO_T1CTL] & PCC2_TCTL_CEN) { uint32_t old_count1 = count1; count1 += steps; /* Did we pass the compare value? */ if ((old_count1 < compare1 && count1 >= compare1) || (old_count1 < compare1 && count1 < old_count1)) { interrupt1 = 1; if (d->pcctwo_reg[PCCTWO_T1CTL] & PCC2_TCTL_COC) { while (count1 >= compare1) { count1 -= compare1; interrupt1 ++; } interrupt1 --; } } /* Overflow? */ if ((int32_t) old_count1 >= 0 && (int32_t) count1 < 0) { int oc = 1 + (d->pcctwo_reg[PCCTWO_T1CTL] >> 4); d->pcctwo_reg[PCCTWO_T1CTL] &= ~PCC2_TCTL_OVF; d->pcctwo_reg[PCCTWO_T1CTL] |= (oc << 4); } } /* ... and the same for timer 2: */ if (d->pcctwo_reg[PCCTWO_T2CTL] & PCC2_TCTL_CEN) { uint32_t old_count2 = count2; count2 += steps; if ((old_count2 < compare2 && count2 >= compare2) || (old_count2 < compare2 && count2 < old_count2)) { interrupt2 = 1; if (d->pcctwo_reg[PCCTWO_T2CTL] & PCC2_TCTL_COC) { while (count2 >= compare2) { count2 -= compare2; interrupt2 ++; } interrupt2 --; } } if ((int32_t) old_count2 >= 0 && (int32_t) count2 < 0) { int oc = 1 + (d->pcctwo_reg[PCCTWO_T2CTL] >> 4); d->pcctwo_reg[PCCTWO_T2CTL] &= ~PCC2_TCTL_OVF; d->pcctwo_reg[PCCTWO_T2CTL] |= (oc << 4); } } /* Should we cause interrupts? */ if (interrupt1 && d->pcctwo_reg[PCCTWO_T1ICR] & PCC2_TTIRQ_IEN) d->pending_timer1_interrupts += interrupt1; if (interrupt2 && d->pcctwo_reg[PCCTWO_T2ICR] & PCC2_TTIRQ_IEN) d->pending_timer2_interrupts += interrupt2; /* Write back values: */ write32(&d->pcctwo_reg[PCCTWO_T1COUNT], count1); write32(&d->pcctwo_reg[PCCTWO_T2COUNT], count2); } static void reassert_interrupts(struct pcc2_data *d) { int assert = 0; if (d->pcctwo_reg[PCCTWO_GENCTL] & PCC2_C040) { /* The M68000 interrupt mechanism involves outputting interrupt level on pins EIPL<2..0>. Not implemented yet. */ fatal("pcc2: C040 interrupt assertions... TODO\n"); exit(1); } /* * Recalculate current interrupt level: */ d->pcctwo_reg[PCCTWO_IPL] = 0; /* Timer interrupts? */ if (d->pending_timer1_interrupts > 0 && d->pcctwo_reg[PCCTWO_T1ICR] & PCC2_TTIRQ_IEN) d->pcctwo_reg[PCCTWO_T1ICR] |= PCC2_TTIRQ_INT; if (d->pending_timer2_interrupts > 0 && d->pcctwo_reg[PCCTWO_T2ICR] & PCC2_TTIRQ_IEN) d->pcctwo_reg[PCCTWO_T2ICR] |= PCC2_TTIRQ_INT; if (d->pcctwo_reg[PCCTWO_T1ICR] & PCC2_TTIRQ_INT) { int intlevel = d->pcctwo_reg[PCCTWO_T1ICR] & PCC2_TTIRQ_IL; d->cur_int_vec[intlevel] = PCC2V_TIMER1; if (d->pcctwo_reg[PCCTWO_IPL] < intlevel) d->pcctwo_reg[PCCTWO_IPL] = intlevel; } if (d->pcctwo_reg[PCCTWO_T2ICR] & PCC2_TTIRQ_INT) { int intlevel = d->pcctwo_reg[PCCTWO_T2ICR] & PCC2_TTIRQ_IL; d->cur_int_vec[intlevel] = PCC2V_TIMER2; if (d->pcctwo_reg[PCCTWO_IPL] < intlevel) d->pcctwo_reg[PCCTWO_IPL] = intlevel; } if (d->pcctwo_reg[PCCTWO_SCCTX] & PCC2_IRQ_IEN && d->pcctwo_reg[PCCTWO_SCCTX] & PCC2_IRQ_INT) { int intlevel = d->pcctwo_reg[PCCTWO_SCCTX] & PCC2_IRQ_IPL; d->cur_int_vec[intlevel] = PCC2V_SCC_TX; if (d->pcctwo_reg[PCCTWO_IPL] < intlevel) d->pcctwo_reg[PCCTWO_IPL] = intlevel; } if (d->pcctwo_reg[PCCTWO_SCCRX] & PCC2_IRQ_IEN && d->pcctwo_reg[PCCTWO_SCCRX] & PCC2_IRQ_INT) { int intlevel = d->pcctwo_reg[PCCTWO_SCCRX] & PCC2_IRQ_IPL; d->cur_int_vec[intlevel] = PCC2V_SCC_RX; if (d->pcctwo_reg[PCCTWO_IPL] < intlevel) d->pcctwo_reg[PCCTWO_IPL] = intlevel; } if (d->pcctwo_reg[PCCTWO_SCSIICR] & PCC2_IRQ_IEN && d->pcctwo_reg[PCCTWO_SCSIICR] & PCC2_IRQ_INT) { int intlevel = d->pcctwo_reg[PCCTWO_SCSIICR] & PCC2_IRQ_IPL; d->cur_int_vec[intlevel] = PCC2V_SCSI; if (d->pcctwo_reg[PCCTWO_IPL] < intlevel) d->pcctwo_reg[PCCTWO_IPL] = intlevel; } /* TODO: Other interrupt sources. */ /* Assert interrupt on the CPU if the IPL is higher than the mask: */ if ((d->pcctwo_reg[PCCTWO_IPL] & INTERRUPT_LEVEL_MASK) > (d->pcctwo_reg[PCCTWO_MASK] & INTERRUPT_LEVEL_MASK)) assert = 1; debug("[ pcc2: IPL = %i, MASK = %i => %s ]\n", d->pcctwo_reg[PCCTWO_IPL]& INTERRUPT_LEVEL_MASK, d->pcctwo_reg[PCCTWO_MASK] & INTERRUPT_LEVEL_MASK, assert ? "ASSERT" : "no assert"); /* ... but only allow interrupts if Master Interrupt Enable is on: */ if (!(d->pcctwo_reg[PCCTWO_GENCTL] & PCC2_MIEN)) assert = 0; if (assert) INTERRUPT_ASSERT(d->cpu_irq); else INTERRUPT_DEASSERT(d->cpu_irq); } void pcctwo_interrupt_common(struct interrupt *interrupt, int assert) { struct pcc2_data *d = (struct pcc2_data *) interrupt->extra; switch (interrupt->line) { case PCC2V_SCSI: if (assert) d->pcctwo_reg[PCCTWO_SCSIICR] |= PCC2_IRQ_INT; else d->pcctwo_reg[PCCTWO_SCSIICR] &= ~PCC2_IRQ_INT; break; case PCC2V_SCC_TX: if (assert) d->pcctwo_reg[PCCTWO_SCCTX] |= PCC2_IRQ_INT; else d->pcctwo_reg[PCCTWO_SCCTX] &= ~PCC2_IRQ_INT; break; case PCC2V_SCC_RX: if (assert) d->pcctwo_reg[PCCTWO_SCCRX] |= PCC2_IRQ_INT; else d->pcctwo_reg[PCCTWO_SCCRX] &= ~PCC2_IRQ_INT; break; default:fatal("[ pcctwo_interrupt_common: TODO: line = %i ]\n", interrupt->line); exit(1); } reassert_interrupts(d); } static void pcctwo_interrupt_assert(struct interrupt *interrupt) { pcctwo_interrupt_common(interrupt, 1); } static void pcctwo_interrupt_deassert(struct interrupt *interrupt) { pcctwo_interrupt_common(interrupt, 0); } DEVICE_TICK(pcc2) { struct pcc2_data *d = (struct pcc2_data *) extra; reassert_interrupts(d); } DEVICE_ACCESS(pcc2) { uint64_t idata = 0; struct pcc2_data *d = (struct pcc2_data *) extra; /* 0xfff42000..0xfff42fff, but only 0x40 unique registers: */ relative_addr %= PCC2_SIZE; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (writeflag == MEM_READ) memcpy(data, d->pcctwo_reg + relative_addr, len); switch (relative_addr) { case PCCTWO_CHIPID: case PCCTWO_CHIPREV: if (writeflag == MEM_WRITE) { fatal("[ IGNORING write to read-only PCCTWO_CHIPID/" "CHIPREV register ]\n"); } break; case PCCTWO_GENCTL: if (len != 1) { fatal("TODO: pcc2: non-byte reads and writes of " "PCCTWO_GENCTL\n"); exit(1); } if (writeflag == MEM_WRITE) { d->pcctwo_reg[relative_addr] = idata; reassert_interrupts(d); } break; case PCCTWO_VECBASE: if (len != 1) { fatal("TODO: pcc2: non-byte reads and writes of " "PCCTWO_VECBASE\n"); exit(1); } if (writeflag == MEM_WRITE) { d->pcctwo_reg[relative_addr] = idata & 0xf0; if (idata & ~0xf0) fatal("[ pcc2: HUH? write to PCCTWO_VECBASE" " with value 0x%02x. ]\n", (int) idata); } break; case PCCTWO_T1CMP: case PCCTWO_T2CMP: case PCCTWO_T1COUNT: case PCCTWO_T2COUNT: if (writeflag == MEM_WRITE) memcpy(d->pcctwo_reg + relative_addr, data, len); break; case PCCTWO_PSCALEADJ: if (len != 1) { fatal("TODO: pcc2: non-byte reads and writes of " "PCCTWO_PSCALEADJ\n"); exit(1); } if (writeflag == MEM_WRITE) { fatal("[ pcc2: write to PSCALEADJ ignored (value " "0x%02x) ]\n", (int)idata); } break; case PCCTWO_T2CTL: case PCCTWO_T1CTL: if (len != 1) { fatal("TODO: pcc2: non-byte reads and writes of " "PCCTWO_TxCTL\n"); exit(1); } if (writeflag == MEM_WRITE) { /* PCC2_TCTL_CEN and PCC2_TCTL_COC: */ d->pcctwo_reg[relative_addr] &= 0xfc; d->pcctwo_reg[relative_addr] |= (idata & 3); if (idata & PCC2_TCTL_COVF) d->pcctwo_reg[relative_addr] &= ~(PCC2_TCTL_OVF | PCC2_TCTL_COVF); if (idata & ~7) fatal("[ pcc2: HUH? write to PCCTWO_TxCTL" " with value 0x%02x. ]\n", (int) idata); } break; case PCCTWO_T2ICR: case PCCTWO_T1ICR: if (len != 1) { fatal("TODO: pcc2: non-byte reads and writes of " "PCCTWO_TxICR\n"); exit(1); } if (writeflag == MEM_WRITE) { d->pcctwo_reg[relative_addr] &= ~0x17; d->pcctwo_reg[relative_addr] |= (idata & 0x17); if (relative_addr == PCCTWO_T1ICR && !(idata & PCC2_TTIRQ_IEN)) d->pending_timer1_interrupts = 0; if (relative_addr == PCCTWO_T2ICR && !(idata & PCC2_TTIRQ_IEN)) d->pending_timer2_interrupts = 0; if (relative_addr == PCCTWO_T1ICR && (idata & PCC2_TTIRQ_ICLR) && d->pcctwo_reg[relative_addr] & PCC2_TTIRQ_INT && d->pending_timer1_interrupts > 0) d->pending_timer1_interrupts --; if (relative_addr == PCCTWO_T2ICR && (idata & PCC2_TTIRQ_ICLR) && d->pcctwo_reg[relative_addr] & PCC2_TTIRQ_INT && d->pending_timer2_interrupts > 0) d->pending_timer2_interrupts --; if (idata & PCC2_TTIRQ_ICLR) d->pcctwo_reg[relative_addr] &= ~PCC2_TTIRQ_INT; if (idata & 0xe0) fatal("[ pcc2: HUH? write to PCCTWO_TxICR" " with value 0x%02x. ]\n", (int) idata); reassert_interrupts(d); } break; case PCCTWO_SCCERR: if (len != 1) { fatal("TODO: pcc2: non-byte reads and writes of " "PCCTWO_SCCERR\n"); exit(1); } if (writeflag == MEM_WRITE) d->pcctwo_reg[relative_addr] = 0; /* clear */ break; case PCCTWO_SCCICR: if (len != 1) { fatal("TODO: pcc2: non-byte reads and writes of " "PCCTWO_SCCICR\n"); exit(1); } if (writeflag == MEM_WRITE) { d->pcctwo_reg[relative_addr] = idata & 0x1f; if (idata & ~0x1f) fatal("[ pcc2: HUH? write to PCCTWO_SCCICR" " with value 0x%02x. ]\n", (int) idata); reassert_interrupts(d); } break; case PCCTWO_SCCTX: if (len != 1) { fatal("TODO: pcc2: non-byte reads and writes of " "PCCTWO_SCCTX\n"); exit(1); } if (writeflag == MEM_WRITE) { d->pcctwo_reg[relative_addr] = idata & 0x1f; if (idata & ~0x1f) fatal("[ pcc2: HUH? write to PCCTWO_SCCTX" " with value 0x%02x. ]\n", (int) idata); reassert_interrupts(d); } break; case PCCTWO_SCCRX: if (len != 1) { fatal("TODO: pcc2: non-byte reads and writes of " "PCCTWO_SCCRX\n"); exit(1); } if (writeflag == MEM_WRITE) { d->pcctwo_reg[relative_addr] = idata & 0xdf; if (idata & ~0xdf) fatal("[ pcc2: HUH? write to PCCTWO_SCCRX" " with value 0x%02x. ]\n", (int) idata); reassert_interrupts(d); } break; case PCCTWO_SCCRXIACK: /* TODO. Hm. Is this enough? */ d->pcctwo_reg[PCCTWO_SCCRX] &= ~PCC2_IRQ_INT; reassert_interrupts(d); break; case PCCTWO_SCSIICR: if (len != 1) { fatal("TODO: pcc2: non-byte reads and writes of " "PCCTWO_SCSIICR\n"); exit(1); } if (writeflag == MEM_WRITE) { d->pcctwo_reg[relative_addr] = idata & 0xdf; if (idata & ~0xdf) fatal("[ pcc2: HUH? write to PCCTWO_SCSIICR" " with value 0x%02x. ]\n", (int) idata); reassert_interrupts(d); } break; case PCCTWO_IPL: if (len != 1) { fatal("TODO: pcc2: non-byte reads and writes of " "PCCTWO_IPL\n"); exit(1); } if (writeflag == MEM_WRITE) { fatal("[ pcc2: HUH? Write attempt to PCCTWO_IPL. ]\n"); exit(1); } else { if (d->pcctwo_reg[PCCTWO_IPL] == 0) { fatal("pcc2: IPL == 0 on read!\n"); exit(1); } } break; case PCCTWO_MASK: if (len != 1) { fatal("TODO: pcc2: non-byte reads and writes of " "PCCTWO_MASK\n"); exit(1); } if (writeflag == MEM_WRITE) { d->pcctwo_reg[relative_addr] = idata; reassert_interrupts(d); } break; default: debug("[ pcc2: unimplemented %s offset 0x%x", writeflag == MEM_WRITE? "write to" : "read from", (int) relative_addr); if (writeflag == MEM_WRITE) debug(": 0x%x", (int)idata); debug(" ]\n"); exit(1); } return 1; } DEVICE_ACCESS(mvme187_iack) { uint64_t odata = 0; struct pcc2_data *d = (struct pcc2_data *) extra; if (writeflag == MEM_WRITE) { fatal("[ pcc2: write to mvme187_iack? ]\n"); } else { odata = d->pcctwo_reg[PCCTWO_VECBASE] + d->cur_int_vec[ (relative_addr >> 2) & INTERRUPT_LEVEL_MASK]; debug("[ pcc2: mvme187_iack level %i => vector 0x%02x ]\n", (int)(relative_addr >> 2), (int)odata); memory_writemax64(cpu, data, len, odata); } return 1; } DEVINIT(pcc2) { struct pcc2_data *d; int i; CHECK_ALLOCATION(d = (struct pcc2_data *) malloc(sizeof(struct pcc2_data))); memset(d, 0, sizeof(struct pcc2_data)); /* * Initial values, according to the manual: * * VECBASE is 0x0f after a reset, although the lowest four bits * cannot be manually written to after startup. */ d->pcctwo_reg[PCCTWO_CHIPID] = PCC2_ID; d->pcctwo_reg[PCCTWO_CHIPREV] = 0x00; d->pcctwo_reg[PCCTWO_GENCTL] = 0x00; d->pcctwo_reg[PCCTWO_VECBASE] = 0x0f; d->pcctwo_reg[PCCTWO_PSCALEADJ] = 256 - 33; // 256 - MHz (fake) /* Connect to the CPU's interrupt pin: */ INTERRUPT_CONNECT(devinit->interrupt_path, d->cpu_irq); /* * Register the 16 PCC2 interrupt vectors: */ for (i=0; i<16; i++) { struct interrupt templ; char n[300]; snprintf(n, sizeof(n), "%s.pcc2.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = n; templ.extra = d; templ.interrupt_assert = pcctwo_interrupt_assert; templ.interrupt_deassert = pcctwo_interrupt_deassert; interrupt_handler_register(&templ); } memory_device_register(devinit->machine->memory, "pcc2", devinit->addr, 4096, dev_pcc2_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, "mvme187_iack", M187_IACK, 32, dev_mvme187_iack_access, (void *)d, DM_DEFAULT, NULL); d->timer = timer_add(PCC_TIMER_TICK_HZ, pcc_timer_tick, d); machine_add_tickfunction(devinit->machine, dev_pcc2_tick, d, DEV_PCC2_TICK_SHIFT); return 1; } gxemul-0.6.1/src/devices/dev_z8530.cc000644 001750 001750 00000015054 13402411502 017401 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Zilog Z8530 "zs" serial controller * * Features: * o) Two channels, 0 = "channel B", 1 = "channel A". * Normally, only channel B is in use. * * This is a work in progress... TODOs include: * o) Implement more of the register set. * o) Verify that it works with other guest OSes than NetBSD and OpenBSD. * o) Implement DMA! */ #include #include #include #include "console.h" #include "cpu.h" #include "device.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/z8530reg.h" /* #define debug fatal */ #define ZS_TICK_SHIFT 14 #define ZS_N_REGS 16 #define ZS_N_CHANNELS 2 #define DEV_Z8530_LENGTH 4 struct z8530_data { struct interrupt irq; int irq_asserted; int addr_mult; int console_handle[ZS_N_CHANNELS]; int reg_select[ZS_N_CHANNELS]; uint8_t rr[ZS_N_CHANNELS][ZS_N_REGS]; uint8_t wr[ZS_N_CHANNELS][ZS_N_REGS]; }; /* * check_incoming(): * * Sets the RX interrupt flag for ports B and A, if something there is input * available on port 0 or 1, respectively. */ static void check_incoming(struct cpu *cpu, struct z8530_data *d) { if (console_charavail(d->console_handle[0])) { d->rr[1][3] |= ZSRR3_IP_B_RX; d->rr[0][0] |= ZSRR0_RX_READY; } if (console_charavail(d->console_handle[1])) { d->rr[1][3] |= ZSRR3_IP_A_RX; d->rr[1][0] |= ZSRR0_RX_READY; } } DEVICE_TICK(z8530) { /* Generate transmit and receive interrupts at regular intervals. */ struct z8530_data *d = (struct z8530_data *) extra; int asserted = 0; if (d->rr[1][3] & ZSRR3_IP_B_TX && d->wr[0][1] & ZSWR1_TIE) asserted = 1; if (d->rr[1][3] & ZSRR3_IP_A_TX && d->wr[1][1] & ZSWR1_TIE) asserted = 1; d->rr[1][3] &= ~(ZSRR3_IP_B_RX | ZSRR3_IP_A_RX); if (!asserted) check_incoming(cpu, d); if (d->rr[1][3] & ZSRR3_IP_B_RX && (d->wr[0][1]&0x18) != ZSWR1_RIE_NONE) asserted = 1; if (d->rr[1][3] & ZSRR3_IP_A_RX && (d->wr[1][1]&0x18) != ZSWR1_RIE_NONE) asserted = 1; if (!(d->wr[1][9] & ZSWR9_MASTER_IE)) asserted = 0; if (asserted) INTERRUPT_ASSERT(d->irq); if (d->irq_asserted && !asserted) INTERRUPT_DEASSERT(d->irq); d->irq_asserted = asserted; } DEVICE_ACCESS(z8530) { struct z8530_data *d = (struct z8530_data *) extra; uint64_t idata = 0, odata = 0; int port_nr; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* Both ports are always ready to transmit: */ d->rr[0][0] |= ZSRR0_TX_READY | ZSRR0_DCD | ZSRR0_CTS; d->rr[1][0] |= ZSRR0_TX_READY | ZSRR0_DCD | ZSRR0_CTS; relative_addr /= d->addr_mult; port_nr = (relative_addr / 2) % ZS_N_CHANNELS; relative_addr &= 1; if (relative_addr == 0) { /* Register access: */ if (writeflag == MEM_READ) { odata = d->rr[port_nr][d->reg_select[port_nr]]; debug("[ z8530: read from port %i reg %2i: " "0x%02x ]\n", port_nr, d->reg_select[ port_nr], (int)odata); d->reg_select[port_nr] = 0; } else { if (d->reg_select[port_nr] == 0) { if (idata < 16) d->reg_select[port_nr] = idata & 15; else d->reg_select[port_nr] = idata & 7; switch (idata & 0xf8) { case ZSWR0_CLR_INTR: /* Interrupt ack: */ d->rr[1][3] = 0; break; } } else { d->wr[port_nr][d->reg_select[port_nr]] = idata; switch (d->reg_select[port_nr]) { default:debug("[ z8530: write to port %i reg " "%2i: 0x%02x ]\n", port_nr, d-> reg_select[port_nr], (int)idata); } d->reg_select[port_nr] = 0; } } } else { /* Data access: */ if (writeflag == MEM_READ) { int x = console_readchar(d->console_handle[port_nr]); d->rr[port_nr][0] &= ~ZSRR0_RX_READY; odata = x < 0? 0 : x; } else { idata &= 255; if (idata != 0) console_putchar(d->console_handle[port_nr], idata); if (1 /* d->wr[port_nr][1] & ZSWR1_TIE */) { if (port_nr == 0) d->rr[1][3] |= ZSRR3_IP_B_TX; else d->rr[1][3] |= ZSRR3_IP_A_TX; } } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); dev_z8530_tick(cpu, extra); return 1; } DEVINIT(z8530) { struct z8530_data *d; char tmp[100]; CHECK_ALLOCATION(d = (struct z8530_data *) malloc(sizeof(struct z8530_data))); memset(d, 0, sizeof(struct z8530_data)); d->addr_mult = devinit->addr_mult; INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); snprintf(tmp, sizeof(tmp), "%s [ch-b]", devinit->name); d->console_handle[0] = console_start_slave(devinit->machine, tmp, devinit->in_use); snprintf(tmp, sizeof(tmp), "%s [ch-a]", devinit->name); d->console_handle[1] = console_start_slave(devinit->machine, tmp, 0); if (devinit->name2 != NULL && devinit->name2[0]) snprintf(tmp, sizeof(tmp), "%s [%s]", devinit->name, devinit->name2); else snprintf(tmp, sizeof(tmp), "%s", devinit->name); memory_device_register(devinit->machine->memory, tmp, devinit->addr, DEV_Z8530_LENGTH * d->addr_mult, dev_z8530_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_z8530_tick, d, ZS_TICK_SHIFT); devinit->return_ptr = (void *)(size_t) d->console_handle[0]; return 1; } gxemul-0.6.1/src/devices/dev_dec5800.cc000644 001750 001750 00000031406 13402411502 017657 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: DECsystem 58x0 devices * * Emulation of devices found in a DECsystem 58x0, where x is the number * of CPUs in the system. (The CPU board is called KN5800 by Ultrix.) * * o) timers and misc stuff * o) BI (Backplane Interconnect) * o) CCA (Console Communication Area) * o) XMI (Extended Memory Interconnect) * * TODO: This hardware is not very easy to find docs about. * Perhaps VAX 6000/300 docs? */ #include #include #include #include "console.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #define DEV_DEC5800_LENGTH 0x1000 /* TODO */ struct dec5800_data { uint32_t csr; struct interrupt cpu_irq; uint32_t vector_0x50; struct interrupt timer_irq; }; void dec5800_interrupt_assert(struct interrupt *interrupt) { struct dec5800_data *d = (struct dec5800_data *) interrupt->extra; d->csr |= (1 << interrupt->line); if (d->csr & 0x10000000) INTERRUPT_ASSERT(d->cpu_irq); } void dec5800_interrupt_deassert(struct interrupt *interrupt) { struct dec5800_data *d = (struct dec5800_data *) interrupt->extra; d->csr &= ~(1 << interrupt->line); if (!(d->csr & 0x10000000)) INTERRUPT_DEASSERT(d->cpu_irq); } DEVICE_TICK(dec5800) { struct dec5800_data *d = (struct dec5800_data *) extra; /* Timer interrupts? */ if (d->csr & 0x8000) { debug("[ dec5800: timer interrupt! ]\n"); /* Set timer interrupt pending bit: */ d->csr |= 0x20000000; INTERRUPT_ASSERT(d->timer_irq); } } DEVICE_ACCESS(dec5800_vectors) { uint64_t idata = 0, odata = 0; struct dec5800_data *d = (struct dec5800_data *) extra; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (writeflag == MEM_READ) { /* TODO */ /* 0xfc = transmit interrupt, 0xf8 = receive interrupt, 0x80 = IPI */ odata = d->vector_0x50; /* odata = 0xfc; */ debug("[ dec5800_vectors: read from 0x%02x: 0x%02x ]\n", (int)relative_addr, (int)odata); } else { d->vector_0x50 = idata; debug("[ dec5800_vectors: write to 0x%02x: 0x%02x ]\n", (int)relative_addr, (int)idata); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(dec5800) { uint64_t idata = 0, odata = 0; struct dec5800_data *d = (struct dec5800_data *) extra; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* Lowest 4 bits of csr contain cpu id: */ d->csr = (d->csr & ~0xf) | (cpu->cpu_id & 0xf); switch (relative_addr) { case 0x0000: /* csr */ if (writeflag == MEM_READ) { odata = d->csr; odata ^= random() & 0x10000; debug("[ dec5800: read from csr: 0x%08x ]\n", (int)odata); } else { d->csr = idata; /* Ack. timer interrupts: */ d->csr &= ~0x20000000; INTERRUPT_DEASSERT(d->timer_irq); debug("[ dec5800: write to csr: 0x%08x ]\n", (int)idata); } break; default: if (writeflag==MEM_READ) { debug("[ dec5800: read from 0x%08lx ]\n", (long)relative_addr); } else { debug("[ dec5800: write to 0x%08lx: 0x%08x ]\n", (long)relative_addr, (int)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(dec5800) { struct dec5800_data *d; char tmpstr[200]; int i; CHECK_ALLOCATION(d = (struct dec5800_data *) malloc(sizeof(struct dec5800_data))); memset(d, 0, sizeof(struct dec5800_data)); snprintf(tmpstr, sizeof(tmpstr), "%s.2", devinit->interrupt_path); INTERRUPT_CONNECT(tmpstr, d->cpu_irq); snprintf(tmpstr, sizeof(tmpstr), "%s.3", devinit->interrupt_path); INTERRUPT_CONNECT(tmpstr, d->timer_irq); /* Register 32 CSR interrupts, corresponding to bits in the CSR: */ for (i=0; i<32; i++) { char n[200]; struct interrupt templ; snprintf(n, sizeof(n), "%s.dec5800.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = n; templ.extra = d; templ.interrupt_assert = dec5800_interrupt_assert; templ.interrupt_deassert = dec5800_interrupt_deassert; interrupt_handler_register(&templ); } memory_device_register(devinit->machine->memory, "dec5800", devinit->addr, DEV_DEC5800_LENGTH, dev_dec5800_access, d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, "dec5800_vectors", devinit->addr + 0x30000000, 0x100, dev_dec5800_vectors_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_dec5800_tick, d, 14); return 1; } /*****************************************************************************/ #include "thirdparty/bireg.h" /* 16 slots, 0x2000 bytes each */ #define DEV_DECBI_LENGTH 0x20000 struct decbi_data { int csr[NNODEBI]; }; DEVICE_ACCESS(decbi) { uint64_t idata = 0, odata = 0; int node_nr; struct decbi_data *d = (struct decbi_data *) extra; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); relative_addr += BI_NODESIZE; /* HACK */ node_nr = relative_addr / BI_NODESIZE; relative_addr &= (BI_NODESIZE - 1); /* TODO: This "1" here is the max node number in actual use. */ if (node_nr > 1 || node_nr >= NNODEBI) return 0; switch (relative_addr) { case BIREG_DTYPE: if (writeflag==MEM_READ) { /* * This is a list of the devices in our BI slots: */ switch (node_nr) { case 1: odata = BIDT_KDB50; break; /* Disk */ /* case 2: odata = BIDT_DEBNA; break; */ /* BIDT_DEBNA = Ethernet */ /* case 3: odata = BIDT_MS820; break; */ /* BIDT_MS820 = Memory */ default: /* No device. */ odata = 0; } debug("[ decbi: (node %i) read from BIREG_DTYPE:" " 0x%x ]\n", node_nr, (int)odata); } else { debug("[ decbi: (node %i) attempt to write to " "BIREG_DTYPE: 0x%08x ]\n", node_nr, (int)idata); } break; case BIREG_VAXBICSR: if (writeflag==MEM_READ) { odata = (d->csr[node_nr] & ~BICSR_NODEMASK) | node_nr; debug("[ decbi: (node %i) read from BIREG_" "VAXBICSR: 0x%x ]\n", node_nr, (int)odata); } else { d->csr[node_nr] = idata; debug("[ decbi: (node %i) attempt to write to " "BIREG_VAXBICSR: 0x%08x ]\n", node_nr, (int)idata); } break; case 0xf4: if (writeflag==MEM_READ) { odata = 0xffff; /* ? */ debug("[ decbi: (node %i) read from 0xf4: " "0x%x ]\n", node_nr, (int)odata); } else { debug("[ decbi: (node %i) attempt to write " "to 0xf4: 0x%08x ]\n", node_nr, (int)idata); } break; default: if (writeflag==MEM_READ) { debug("[ decbi: (node %i) read from unimplemented " "0x%08lx ]\n", node_nr, (long)relative_addr, (int)odata); } else { debug("[ decbi: (node %i) write to unimplemented " "0x%08lx: 0x%08x ]\n", node_nr, (long)relative_addr, (int)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(decbi) { struct decbi_data *d; CHECK_ALLOCATION(d = (struct decbi_data *) malloc(sizeof(struct decbi_data))); memset(d, 0, sizeof(struct decbi_data)); memory_device_register(devinit->machine->memory, "decbi", devinit->addr + 0x2000, DEV_DECBI_LENGTH - 0x2000, dev_decbi_access, d, DM_DEFAULT, NULL); return 1; } /*****************************************************************************/ /* * CCA, "Console Communication Area" for a DEC 5800 SMP system. */ struct deccca_data { int dummy; }; DEVICE_ACCESS(deccca) { uint64_t idata = 0, odata = 0; /* struct deccca_data *d = extra; */ if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 6: case 7: /* CCA "ID" bytes? These must be here, or Ultrix complains. */ if (writeflag == MEM_READ) odata = 67; break; case 8: if (writeflag == MEM_READ) odata = cpu->machine->ncpus; break; case 20: if (writeflag == MEM_READ) odata = (1 << cpu->machine->ncpus) - 1; /* one bit for each cpu */ break; case 28: if (writeflag == MEM_READ) odata = (1 << cpu->machine->ncpus) - 1; /* one bit for each enabled(?) cpu */ break; default: if (writeflag==MEM_READ) { debug("[ deccca: read from 0x%08lx ]\n", (long)relative_addr); } else { debug("[ deccca: write to 0x%08lx: 0x%08x ]\n", (long)relative_addr, (int)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_deccca_init(): */ void dev_deccca_init(struct memory *mem, uint64_t baseaddr) { struct deccca_data *d; CHECK_ALLOCATION(d = (struct deccca_data *) malloc(sizeof(struct deccca_data))); memset(d, 0, sizeof(struct deccca_data)); memory_device_register(mem, "deccca", baseaddr, DEV_DECCCA_LENGTH, dev_deccca_access, d, DM_DEFAULT, NULL); } /*****************************************************************************/ /* * DEC 5800 XMI (this has to do with SMP...) */ #include "thirdparty/xmireg.h" struct decxmi_data { uint32_t reg_0xc[NNODEXMI]; }; /* * dev_decxmi_access(): */ DEVICE_ACCESS(decxmi) { uint64_t idata = 0, odata = 0; int node_nr; struct decxmi_data *d = (struct decxmi_data *) extra; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); node_nr = relative_addr / XMI_NODESIZE; relative_addr &= (XMI_NODESIZE - 1); if (node_nr >= cpu->machine->ncpus + 1 || node_nr >= NNODEXMI) return 0; switch (relative_addr) { case XMI_TYPE: if (writeflag == MEM_READ) { /* * The first node is an XMI->BI adapter node, and then * there are n CPU nodes. */ odata = XMIDT_ISIS; if (node_nr == 0) odata = XMIDT_DWMBA; debug("[ decxmi: (node %i) read from XMI_TYPE: " "0x%08x ]\n", node_nr, (int)odata); } else debug("[ decxmi: (node %i) write to XMI_TYPE: " "0x%08x ]\n", node_nr, (int)idata); break; case XMI_BUSERR: if (writeflag == MEM_READ) { odata = 0; debug("[ decxmi: (node %i) read from XMI_BUSERR: " "0x%08x ]\n", node_nr, (int)odata); } else debug("[ decxmi: (node %i) write to XMI_BUSERR: " "0x%08x ]\n", node_nr, (int)idata); break; case XMI_FAIL: if (writeflag == MEM_READ) { odata = 0; debug("[ decxmi: (node %i) read from XMI_FAIL: " "0x%08x ]\n", node_nr, (int)odata); } else debug("[ decxmi: (node %i) write to XMI_FAIL: " "0x%08x ]\n", node_nr, (int)idata); break; case 0xc: if (writeflag == MEM_READ) { odata = d->reg_0xc[node_nr]; debug("[ decxmi: (node %i) read from REG 0xC: " "0x%08x ]\n", node_nr, (int)odata); } else { d->reg_0xc[node_nr] = idata; debug("[ decxmi: (node %i) write to REG 0xC: " "0x%08x ]\n", node_nr, (int)idata); } break; default: if (writeflag==MEM_READ) { debug("[ decxmi: (node %i) read from unimplemented " "0x%08lx ]\n", node_nr, (long)relative_addr, (int)odata); } else { debug("[ decxmi: (node %i) write to unimplemented " "0x%08lx: 0x%08x ]\n", node_nr, (long)relative_addr, (int)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_decxmi_init(): */ void dev_decxmi_init(struct memory *mem, uint64_t baseaddr) { struct decxmi_data *d; CHECK_ALLOCATION(d = (struct decxmi_data *) malloc(sizeof(struct decxmi_data))); memset(d, 0, sizeof(struct decxmi_data)); memory_device_register(mem, "decxmi", baseaddr, DEV_DECXMI_LENGTH, dev_decxmi_access, d, DM_DEFAULT, NULL); } gxemul-0.6.1/src/devices/dev_mb8696x.cc000644 001750 001750 00000017512 13402411502 017734 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Fujitsu MB8696x Ethernet interface (used in the Dreamcast) * * Used as the LAN adapter (MB86967) in the Dreamcast machine mode. * * * Note: This is just a bogus module so far. * * (TODO: "Reverse engineer" more of NetBSD's mb86960.c to implement this.) */ #include #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "net.h" #include "thirdparty/mb86960reg.h" #ifdef UNSTABLE_DEVEL #define MB8696X_DEBUG #endif #ifdef MB8696X_DEBUG #define debug fatal #endif struct mb8696x_data { int addr_mult; /* * Registers: * * reg contains 32 registers. However, registers 8..15 are bank- * switched, based on a setting in FE_DLCR7. mar_8_15 are "multicast * address registers", and bmpr_8_15 are "buffer memory port * registers". */ uint8_t reg[MB8696X_NREGS]; uint8_t mar_8_15[8]; uint8_t bmpr_8_15[8]; /* EEPROM contents and internal state during a read operation: */ uint8_t eeprom[FE_EEPROM_SIZE]; int eeprom_state; uint8_t eeprom_bit_count; uint8_t eeprom_command; uint16_t eeprom_data; }; #define EEPROM_STATE_NOTHING 0 #define EEPROM_STATE_READY 1 /* Waiting for start bit */ #define EEPROM_STATE_COMMAND 2 /* Waiting for 8 command bits */ #define EEPROM_STATE_READ 3 DEVICE_ACCESS(mb8696x) { struct mb8696x_data *d = (struct mb8696x_data *) extra; uint64_t idata = 0, odata = 0; uint8_t *reg_ptr; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); relative_addr /= d->addr_mult; /* * Default result on reads: (Note special treatment of banked regs.) */ reg_ptr = &d->reg[relative_addr]; if (relative_addr >= 8 && relative_addr <= 15 && (d->reg[FE_DLCR7] & FE_D7_RBS) == FE_D7_RBS_MAR) reg_ptr = &d->mar_8_15[relative_addr - 8]; if (relative_addr >= 8 && relative_addr <= 15 && (d->reg[FE_DLCR7] & FE_D7_RBS) == FE_D7_RBS_BMPR) reg_ptr = &d->bmpr_8_15[relative_addr - 8]; odata = *reg_ptr; switch (relative_addr) { case FE_DLCR0: /* TX interrupt status */ case FE_DLCR1: /* RX interrupt status */ /* Write-1-to-clear: */ if (writeflag == MEM_WRITE) (*reg_ptr) &= ~idata; /* TODO: reassert interrupts */ break; case FE_DLCR2: /* TX interrupt control */ case FE_DLCR3: /* RX interrupt control */ if (writeflag == MEM_WRITE) (*reg_ptr) = idata; /* TODO: reassert interrupts */ break; case FE_DLCR6: case FE_DLCR8: /* Ethernet addr byte 0 */ case FE_DLCR9: /* Ethernet addr byte 1 */ case FE_DLCR10: /* Ethernet addr byte 2 */ case FE_DLCR11: /* Ethernet addr byte 3 */ case FE_DLCR12: /* Ethernet addr byte 4 */ case FE_DLCR13: /* Ethernet addr byte 5 */ if (writeflag == MEM_WRITE) (*reg_ptr) = idata; break; case FE_DLCR7: if (writeflag == MEM_WRITE) { /* Identification cannot be overwritten: */ (*reg_ptr) &= FE_D7_IDENT; (*reg_ptr) |= (idata & ~FE_D7_IDENT); } break; case FE_BMPR16: /* EEPROM control */ if (writeflag == MEM_WRITE) { if (idata & ~(FE_B16_DOUT | FE_B16_DIN | FE_B16_SELECT | FE_B16_CLOCK)) { fatal("mb8696x: UNIMPLEMENTED bits when " "writing to FE_BMPR16: 0x%02x\n", (int)idata); exit(1); } /* Dropped out of select state? */ if (!(idata & FE_B16_SELECT)) d->eeprom_state = EEPROM_STATE_NOTHING; /* Switching to select state? */ if (!((*reg_ptr) & FE_B16_SELECT) && idata & FE_B16_SELECT) d->eeprom_state = EEPROM_STATE_READY; /* Bit clock? */ if (!((*reg_ptr) & FE_B16_CLOCK) && idata & FE_B16_CLOCK) { int bit = d->reg[FE_BMPR17] & FE_B17_DATA? 1:0; switch (d->eeprom_state) { case EEPROM_STATE_READY: d->eeprom_state = EEPROM_STATE_COMMAND; d->eeprom_bit_count = 0; break; case EEPROM_STATE_COMMAND: d->eeprom_bit_count ++; d->eeprom_command <<= 1; d->eeprom_command |= bit; if (d->eeprom_bit_count == 8) { int addr = (d->eeprom_command & 0x7f) << 1; /* printf("COMMAND=%08x\n", d->eeprom_command); */ if (!(d->eeprom_command&0x80)) { fatal("WRITES to the " "EEPROM are not yet" " implemented.\n"); exit(1); } /* This is a read command. */ d->eeprom_bit_count = 0; d->eeprom_state = EEPROM_STATE_READ; d->eeprom_data = d->eeprom[addr] * 256 + d->eeprom[addr+1]; } break; case EEPROM_STATE_READ: d->reg[FE_BMPR17] = 0; if (d->eeprom_data & 0x8000) d->reg[FE_BMPR17] = FE_B17_DATA; d->eeprom_data <<= 1; d->eeprom_bit_count ++; if (d->eeprom_bit_count > 16) fatal("[ WARNING: more than 16" " bits of EEPROM data " "read? ]\n"); break; } } (*reg_ptr) = idata; } break; case FE_BMPR17: /* EEPROM data */ if (writeflag == MEM_WRITE) { if (idata & ~FE_B17_DATA) { fatal("mb8696x: UNIMPLEMENTED bits when " "writing to FE_BMPR17: 0x%02x\n", (int)idata); exit(1); } (*reg_ptr) = idata; } break; default: { const char *bank = ""; if ((d->reg[FE_DLCR7] & FE_D7_RBS) == FE_D7_RBS_MAR) bank = " (bank MAR)"; if ((d->reg[FE_DLCR7] & FE_D7_RBS) == FE_D7_RBS_BMPR) bank = " (bank BMPR)"; if (writeflag == MEM_READ) { fatal("[ mb8696x: read from UNIMPLEMENTED reg " "%i%s ]\n", (int)relative_addr, bank); } else { fatal("[ mb8696x: write to UNIMPLEMENTED reg " "%i%s: 0x%02x ]\n", (int)relative_addr, bank, (int)idata); } #ifdef MB8696X_DEBUG exit(1); #endif } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(mb8696x) { struct mb8696x_data *d; CHECK_ALLOCATION(d = (struct mb8696x_data *) malloc(sizeof(struct mb8696x_data))); memset(d, 0, sizeof(struct mb8696x_data)); d->addr_mult = devinit->addr_mult; memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, MB8696X_NREGS * d->addr_mult, dev_mb8696x_access, d, DM_DEFAULT, NULL); /* NetBSD/dreamcast expects ident = 86967. */ d->reg[FE_DLCR7] = FE_D7_IDENT_86967; /* * Generate the MAC address, both in the first 6 bytes of the * EEPROM, and in DLCR8..13: */ net_generate_unique_mac(devinit->machine, &d->eeprom[0]); memcpy(&d->reg[FE_DLCR8], &d->eeprom[0], 6); return 1; } gxemul-0.6.1/src/devices/dev_cpc700.cc000644 001750 001750 00000016062 13402411502 017604 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: IBM CPC700 bridge (PCI and interrupt controller) */ #include #include #include #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/cpc700reg.h" struct cpc700_data { struct interrupt ppc_irq; /* Connected to the CPU */ uint32_t sr; /* Interrupt Status register */ uint32_t er; /* Interrupt Enable register */ struct pci_data *pci_data; /* PCI bus */ }; void cpc700_interrupt_assert(struct interrupt *interrupt) { struct cpc700_data *d = (struct cpc700_data *) interrupt->extra; d->sr |= interrupt->line; if (d->sr & d->er) INTERRUPT_ASSERT(d->ppc_irq); } void cpc700_interrupt_deassert(struct interrupt *interrupt) { struct cpc700_data *d = (struct cpc700_data *) interrupt->extra; d->sr &= ~interrupt->line; if (!(d->sr & d->er)) INTERRUPT_DEASSERT(d->ppc_irq); } /* * dev_cpc700_pci_access(): * * Passes PCI indirect addr and data accesses onto bus_pci. */ DEVICE_ACCESS(cpc700_pci) { uint64_t idata = 0, odata = 0; int bus, dev, func, reg; struct cpc700_data *d = (struct cpc700_data *) extra; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN); switch (relative_addr) { case 0: /* Address: */ bus_pci_decompose_1(idata, &bus, &dev, &func, ®); bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, reg); break; case 4: /* Data: */ bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ? &odata : &idata, len, writeflag); break; } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN, odata); return 1; } /* * dev_cpc700_int_access(): * * The interrupt controller. */ DEVICE_ACCESS(cpc700_int) { struct cpc700_data *d = (struct cpc700_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case CPC_UIC_SR: /* Status register (cleared by writing ones): */ if (writeflag == MEM_READ) { odata = d->sr; } else { d->sr &= ~idata; if (!(d->sr & d->er)) INTERRUPT_DEASSERT(d->ppc_irq); } break; case CPC_UIC_SRS: /* Status register set: */ if (writeflag == MEM_READ) { fatal("[ cpc700_int: read from CPC_UIC_SRS? ]\n"); odata = d->sr; } else { d->sr = idata; if (d->sr & d->er) INTERRUPT_ASSERT(d->ppc_irq); else INTERRUPT_DEASSERT(d->ppc_irq); } break; case CPC_UIC_ER: /* Enable register: */ if (writeflag == MEM_READ) { odata = d->er; } else { d->er = idata; if (d->sr & d->er) INTERRUPT_ASSERT(d->ppc_irq); else INTERRUPT_DEASSERT(d->ppc_irq); } break; case CPC_UIC_MSR: /* Masked status: */ if (writeflag == MEM_READ) { odata = d->sr & d->er; } else { fatal("[ cpc700_int: write to CPC_UIC_MSR? ]\n"); } break; default:if (writeflag == MEM_WRITE) { fatal("[ cpc700_int: unimplemented write to " "offset 0x%x: data=0x%x ]\n", (int) relative_addr, (int)idata); } else { fatal("[ cpc700_int: unimplemented read from " "offset 0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(cpc700) { struct cpc700_data *d; char tmp[300]; int i; CHECK_ALLOCATION(d = (struct cpc700_data *) malloc(sizeof(struct cpc700_data))); memset(d, 0, sizeof(struct cpc700_data)); /* Connect to the CPU's interrupt pin: */ INTERRUPT_CONNECT(devinit->interrupt_path, d->ppc_irq); /* Register 32 CPC700 interrupts: */ for (i=0; i<32; i++) { struct interrupt templ; char n[300]; snprintf(n, sizeof(n), "%s.cpc700.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = 1 << i; templ.name = n; templ.extra = d; templ.interrupt_assert = cpc700_interrupt_assert; templ.interrupt_deassert = cpc700_interrupt_deassert; interrupt_handler_register(&templ); } /* Register a PCI bus: */ snprintf(tmp, sizeof(tmp), "%s.cpc700", devinit->interrupt_path); d->pci_data = bus_pci_init( devinit->machine, tmp, /* pciirq path */ 0, /* pci device io offset */ 0, /* pci device mem offset */ CPC_PCI_IO_BASE, /* PCI portbase */ CPC_PCI_MEM_BASE, /* PCI membase: TODO */ tmp, /* PCI irqbase */ 0, /* ISA portbase: TODO */ 0, /* ISA membase: TODO */ tmp); /* ISA irqbase */ switch (devinit->machine->machine_type) { case MACHINE_PMPPC: bus_pci_add(devinit->machine, d->pci_data, devinit->machine->memory, 0, 0, 0, "heuricon_pmppc"); break; default:fatal("!\n! WARNING: cpc700 for non-implemented machine" " type\n!\n"); exit(1); } /* PCI configuration registers: */ memory_device_register(devinit->machine->memory, "cpc700_pci", CPC_PCICFGADR, 8, dev_cpc700_pci_access, d, DM_DEFAULT, NULL); /* Interrupt controller: */ memory_device_register(devinit->machine->memory, "cpc700_int", CPC_UIC_BASE, CPC_UIC_SIZE, dev_cpc700_int_access, d, DM_DEFAULT, NULL); /* Two serial ports: */ snprintf(tmp, sizeof(tmp), "ns16550 irq=%s.cpc700.%i addr=0x%llx " "name2=tty0", devinit->interrupt_path, 31 - CPC_IB_UART_0, (long long)CPC_COM0); devinit->machine->main_console_handle = (size_t) device_add(devinit->machine, tmp); snprintf(tmp, sizeof(tmp), "ns16550 irq=%s.cpc700.%i addr=0x%llx " "name2=tty1", devinit->interrupt_path, 31 - CPC_IB_UART_1, (long long)CPC_COM1); device_add(devinit->machine, tmp); devinit->return_ptr = d->pci_data; return 1; } gxemul-0.6.1/src/devices/dev_ps2_ether.cc000644 001750 001750 00000005457 13402411502 020511 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: PlayStation 2 ethernet (smap and emac3) * * TODO */ #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #define debug fatal struct ps2_ether_data { int dummy; }; DEVICE_ACCESS(ps2_ether) { /* struct ps2_ether_data *d = extra; */ uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0x105c: /* TODO: make these register accesses nicer */ break; case 0x105e: odata = 0x8000; /* STACR_OC */ break; default: if (writeflag==MEM_READ) { debug("[ ps2_ether: read from addr 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)odata); } else { debug("[ ps2_ether: write to addr 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(ps2_ether) { struct ps2_ether_data *d; CHECK_ALLOCATION(d = (struct ps2_ether_data *) malloc(sizeof(struct ps2_ether_data))); memset(d, 0, sizeof(struct ps2_ether_data)); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, 0x4000, dev_ps2_ether_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_px.cc000644 001750 001750 00000054301 13402411502 017235 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: TURBOchannel Pixelstamp graphics card * * PMAG-CA = PX * PMAG-DA = PXG * PMAG-EA = PXG+ * PMAG-FA = PXG+ TURBO * * See include/pxreg.h (and NetBSD's arch/pmax/dev/px.c) for more information. * * The emulation of this device is far from complete. Different pixelstamp * boards are recognizes under different names depending on operating system: * * NetBSD/pmax: (works fine both with and without console on framebuffer) * PMAG-CA: px0 at tc0 slot 0 offset 0x0: 2D, 4x1 stamp, * 8 plane * PMAG-DA: px0 at tc0 slot 0 offset 0x0: 3D, 4x1 stamp, * 8 plane, 128KB SRAM * PMAG-EA: (not supported) * PMAG-FA: px0 at tc0 slot 0 offset 0x0: 3D, 5x2 stamp, * 24 plane, 128KB SRAM * * Ultrix 4.2A rev 47: (usually crashes if the device is installed, but * serial console is used) * PMAG-CA: px0 at ibus0, pa0 (5x1 8+8+0+0) * PMAG-DA: px0 at ibus0, pq0 (5x1 16+16+16+0 128KB) * or (5x1 0+0+16+0 128KB) * PMAG-EA: (not supported) * PMAG-FA: px0 at ibus0, pq0 (5x2 24+24+16+16 128KB) * * Ultrix 4.2 rev 85: (usually crashes if the device is installed, * but serial console is used) * PMAG-CA: ga0 at ibus0, ga0 ( 8 planes 4x1 stamp ) * PMAG-DA: gq0 at ibus0, gq0 ( 8+8+16Z+0X plane 4x1 stamp ) * PMAG-EA: (not supported) * PMAG-FA: gq0 at ibus0, gq0 ( 24+24+24Z+24X plane * 5x2 stamp ) (crashes in serial console mode) * * TODO: A lot of stuff: * * Read http://www.mit.edu/afs/athena/system/pmax_ul3/srvd.73/sys/ * io/tc/gq.h * and try to figure out the interrupt and memory management stuff. * * Color support: foreground, background, 8-bit palette? * 2D and 3D stuff: polygons? shading? * Don't use so many hardcoded values. * Actually interpret the values in each command, don't just * assume NetBSD/Ultrix usage. * Factor out the DMA read (main memory vs sram). * Interrupts? * Make sure that everything works with both NetBSD and Ultrix. */ #include #include #include #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/pxreg.h" #define PX_XSIZE 1280 #define PX_YSIZE 1024 /* #define PX_DEBUG */ DEVICE_TICK(px) { #if 0 struct px_data *d = extra; if (d->intr & STIC_INT_P_EN) /* or _WE ? */ INTERRUPT_ASSERT(d->irq); #endif } /* * px_readword(): * * Helper function to read 32-bit words from DMA memory, * to allow both little and big endian accesses. * (DECstations probably only use little endian access, * but endianness-independance is probably nice to have anyway.) */ uint32_t px_readword(struct cpu *cpu, unsigned char *dma_buf, int ofs) { if (cpu->byte_order == EMUL_LITTLE_ENDIAN) return dma_buf[ofs+0] + (dma_buf[ofs+1] << 8) + (dma_buf[ofs+2] << 16) + (dma_buf[ofs+3] << 24); else return dma_buf[ofs+3] + (dma_buf[ofs+2] << 8) + (dma_buf[ofs+1] << 16) + (dma_buf[ofs+0] << 24); } /* * dev_px_dma(): * * This routine performs a (fake) DMA transfer of STAMP commands * and executes them. * * For the "PX" board, read from main memory (cpu->mem). For all other * boards, read from the i860 SRAM portion of the device (d->sram). */ void dev_px_dma(struct cpu *cpu, uint32_t sys_addr, struct px_data *d) { unsigned char dma_buf[32768]; size_t dma_len = sizeof(dma_buf); int bytesperpixel; uint32_t cmdword; bytesperpixel = d->bitdepth >> 3; dma_len = 56 * 4; /* TODO: this is just enough for NetBSD's putchar */ if (d->type == DEV_PX_TYPE_PX) { cpu->memory_rw(cpu, cpu->mem, sys_addr, dma_buf, dma_len, MEM_READ, NO_EXCEPTIONS | PHYSICAL); } else { /* TODO: past end of sram? */ memmove(dma_buf, &d->sram[sys_addr & 0x1ffff], dma_len); } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) cmdword = dma_buf[0] + (dma_buf[1] << 8) + (dma_buf[2] << 16) + (dma_buf[3] << 24); else cmdword = dma_buf[3] + (dma_buf[2] << 8) + (dma_buf[1] << 16) + (dma_buf[0] << 24); #ifdef PX_DEBUG debug("[ px: dma from 0x%08x: ", (int)sys_addr); debug("cmd="); switch (cmdword & 0xf) { case STAMP_CMD_POINTS: debug("points"); break; case STAMP_CMD_LINES: debug("lines"); break; case STAMP_CMD_TRIANGLES: debug("triangles"); break; case STAMP_CMD_COPYSPANS: debug("copyspans"); break; case STAMP_CMD_READSPANS: debug("readspans"); break; case STAMP_CMD_WRITESPANS: debug("writespans"); break; case STAMP_CMD_VIDEO: debug("video"); break; default: debug("0x%x (?)", cmdword & 0xf); } debug(",rgb="); switch (cmdword & 0x30) { case STAMP_RGB_NONE: debug("none"); break; case STAMP_RGB_CONST: debug("const"); break; case STAMP_RGB_FLAT: debug("flat"); break; case STAMP_RGB_SMOOTH: debug("smooth"); break; default: debug("0x%x (?)", cmdword & 0x30); } debug(",z="); switch (cmdword & 0xc0) { case STAMP_Z_NONE: debug("none"); break; case STAMP_Z_CONST: debug("const"); break; case STAMP_Z_FLAT: debug("flat"); break; case STAMP_Z_SMOOTH: debug("smooth"); break; default: debug("0x%x (?)", cmdword & 0xc0); } debug(",xy="); switch (cmdword & 0x300) { case STAMP_XY_NONE: debug("none"); break; case STAMP_XY_PERPACKET: debug("perpacket"); break; case STAMP_XY_PERPRIMATIVE: debug("perprimative"); break; default: debug("0x%x (?)", cmdword & 0x300); } debug(",lw="); switch (cmdword & 0xc00) { case STAMP_LW_NONE: debug("none"); break; case STAMP_LW_PERPACKET: debug("perpacket"); break; case STAMP_LW_PERPRIMATIVE: debug("perprimative"); break; default: debug("0x%x (?)", cmdword & 0xc00); } if (cmdword & STAMP_CLIPRECT) debug(",CLIPRECT"); if (cmdword & STAMP_MESH) debug(",MESH"); if (cmdword & STAMP_AALINE) debug(",AALINE"); if (cmdword & STAMP_HS_EQUALS) debug(",HS_EQUALS"); { size_t i; for (i=0; ibyte_order == EMUL_LITTLE_ENDIAN) nspans = dma_buf[4] + (dma_buf[5] << 8) + (dma_buf[6] << 16) + (dma_buf[7] << 24); else nspans = dma_buf[7] + (dma_buf[6] << 8) + (dma_buf[5] << 16) + (dma_buf[4] << 24); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) lw = dma_buf[16] + (dma_buf[17] << 8) + (dma_buf[18] << 16) + (dma_buf[19] << 24); else lw = dma_buf[19] + (dma_buf[18] << 8) + (dma_buf[17] << 16) + (dma_buf[16] << 24); nspans >>= 24; /* Why not this? lw = (lw + 1) >> 2; */ #ifdef PX_DEBUG debug("[ px: copyspans: nspans = %i, lw = %i ]\n", nspans, lw); #endif /* Reread copyspans command if it wasn't completely read: */ if (dma_len < 4*(5 + nspans*3)) { dma_len = 4 * (5+nspans*3); if (d->type == DEV_PX_TYPE_PX) cpu->memory_rw(cpu, cpu->mem, sys_addr, dma_buf, dma_len, MEM_READ, NO_EXCEPTIONS | PHYSICAL); else memmove(dma_buf, &d->sram[sys_addr & 0x1ffff], dma_len); /* TODO: past end of sram? */ } ofs = 4*5; for (spannr=0; spannrbyte_order == EMUL_LITTLE_ENDIAN) span_len = dma_buf[ofs+0] + (dma_buf[ofs+1] << 8) + (dma_buf[ofs+2] << 16) + (dma_buf[ofs+3] << 24); else span_len = dma_buf[ofs+3] + (dma_buf[ofs+2] << 8) + (dma_buf[ofs+1] << 16) + (dma_buf[ofs+0] << 24); ofs += 4; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) span_src = dma_buf[ofs+0] + (dma_buf[ofs+1] << 8) + (dma_buf[ofs+2] << 16) + (dma_buf[ofs+3] << 24); else span_src = dma_buf[ofs+3] + (dma_buf[ofs+2] << 8) + (dma_buf[ofs+1] << 16) + (dma_buf[ofs+0] << 24); ofs += 4; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) span_dst = dma_buf[ofs+0] + (dma_buf[ofs+1] << 8) + (dma_buf[ofs+2] << 16) + (dma_buf[ofs+3] << 24); else span_dst = dma_buf[ofs+3] + (dma_buf[ofs+2] << 8) + (dma_buf[ofs+1] << 16) + (dma_buf[ofs+0] << 24); ofs += 4; span_len >>= 3; span_dst >>= 3; span_src >>= 3; if (span_len > PX_XSIZE) span_len = PX_XSIZE; /* debug(" span %i: len=%i src=%i dst=%i\n", spannr, span_len, span_src, span_dst); */ memmove(d->vfb_data->framebuffer + span_dst * PX_XSIZE * bytesperpixel, d->vfb_data->framebuffer + span_src * PX_XSIZE * bytesperpixel, span_len * bytesperpixel); d->vfb_data->update_x1 = 0; d->vfb_data->update_x2 = PX_XSIZE-1; if ((int32_t)span_dst < d->vfb_data->update_y1) d->vfb_data->update_y1 = span_dst; if ((int32_t)span_dst > d->vfb_data->update_y2) d->vfb_data->update_y2 = span_dst; if ((int32_t)span_src < d->vfb_data->update_y1) d->vfb_data->update_y1 = span_src; if ((int32_t)span_src > d->vfb_data->update_y2) d->vfb_data->update_y2 = span_src; } } /* NetBSD and Ultrix erasecols/eraserows */ if (cmdword == 0x411) { uint32_t v1, v2, attr; int32_t lw; int x,y,x2,y2; int fb_y; int bg_r, bg_g, bg_b; unsigned char pixels[PX_XSIZE * 3]; lw = px_readword(cpu, dma_buf, 16); attr = px_readword(cpu, dma_buf, 20); v1 = px_readword(cpu, dma_buf, 24); v2 = px_readword(cpu, dma_buf, 28); #if 0 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) lw = dma_buf[16] + (dma_buf[17] << 8) + (dma_buf[18] << 16) + (dma_buf[19] << 24); else lw = dma_buf[19] + (dma_buf[18] << 8) + (dma_buf[17] << 16) + (dma_buf[16] << 24); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) v1 = dma_buf[24] + (dma_buf[25] << 8) + (dma_buf[26] << 16) + (dma_buf[27] << 24); else v1 = dma_buf[27] + (dma_buf[26] << 8) + (dma_buf[25] << 16) + (dma_buf[24] << 24); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) v2 = dma_buf[28] + (dma_buf[29] << 8) + (dma_buf[30] << 16) + (dma_buf[31] << 24); else v2 = dma_buf[31] + (dma_buf[30] << 8) + (dma_buf[29] << 16) + (dma_buf[28] << 24); #endif bg_r = (attr >> 16) & 255; bg_g = (attr >> 8) & 255; bg_b = attr & 255; if (bg_r == 0) bg_r = bg_g = bg_b = 0; else if (bg_r == 7) bg_r = bg_g = bg_b = 192; else bg_r = bg_g = bg_b = 255; v1 -= lw; v2 -= lw; x = (v1 >> 19) & 2047; y = (v1 >> 3) & 1023; x2 = (v2 >> 19) & 2047; y2 = (v2 >> 3) & 1023; lw = (lw + 1) >> 2; if (x2 - x > PX_XSIZE) x2 = PX_XSIZE; #ifdef PX_DEBUG debug("[ px: clear/fill: v1 = 0x%08x v2 = 0x%08x " "lw=%i x=%i y=%i x2=%i y2=%i ]\n", (int)v1, (int)v2, lw, x,y, x2,y2); #endif if (bytesperpixel == 3) { int xi; for (xi=0; xivfb_data->update_x1) d->vfb_data->update_x1 = x; if (x2 > d->vfb_data->update_x2) d->vfb_data->update_x2 = x2; for (fb_y=y; fb_y < y2 + lw; fb_y ++) { memcpy(d->vfb_data->framebuffer + (fb_y * PX_XSIZE + x) * bytesperpixel, pixels, (x2-x)*bytesperpixel); if (fb_y < d->vfb_data->update_y1) d->vfb_data->update_y1 = fb_y; if (fb_y > d->vfb_data->update_y2) d->vfb_data->update_y2 = fb_y; } } /* NetBSD and Ultrix putchar */ if (cmdword == 0xa21) { /* Ugly test code: */ unsigned char pixels[16 * 3]; int pixels_len = 16; uint32_t v1, v2, fgcolor, bgcolor; int x, y, x2,y2, i, maxi; int xbit; int suby; int fg_r, fg_g, fg_b; int bg_r, bg_g, bg_b; v1 = px_readword(cpu, dma_buf, 52); v2 = px_readword(cpu, dma_buf, 56); fgcolor = px_readword(cpu, dma_buf, 16 * 4); bgcolor = px_readword(cpu, dma_buf, 29 * 4); /* * TODO: Which one is r, which one is g, and which one is b? * TODO 2: Use the BT459 palette, these values are hardcoded * for NetBSD and Ultrix grayscale only. */ fg_r = (fgcolor >> 16) & 255; fg_g = (fgcolor >> 8) & 255; fg_b = fgcolor & 255; if (fg_r == 0) fg_r = fg_g = fg_b = 0; else if (fg_r == 7) fg_r = fg_g = fg_b = 192; else fg_r = fg_g = fg_b = 255; bg_r = (bgcolor >> 16) & 255; bg_g = (bgcolor >> 8) & 255; bg_b = bgcolor & 255; if (bg_r == 0) bg_r = bg_g = bg_b = 0; else if (bg_r == 7) bg_r = bg_g = bg_b = 192; else bg_r = bg_g = bg_b = 255; x = (v1 >> 19) & 2047; y = ((v1 - 63) >> 3) & 1023; x2 = (v2 >> 19) & 2047; y2 = ((v2 - 63) >> 3) & 1023; #ifdef PX_DEBUG debug("[ px putchar: v1 = 0x%08x v2 = 0x%08x x=%i y=%i ]\n", (int)v1, (int)v2, x,y, x2,y2); #endif x %= PX_XSIZE; y %= PX_YSIZE; x2 %= PX_XSIZE; y2 %= PX_YSIZE; pixels_len = x2 - x; suby = 0; maxi = 12; maxi = 33; for (i=4; ivfb_data->framebuffer + ((y+suby) * PX_XSIZE + x) * bytesperpixel, pixels, pixels_len * bytesperpixel); if (y+suby < d->vfb_data->update_y1) d->vfb_data->update_y1 = y+suby; if (y+suby > d->vfb_data->update_y2) d->vfb_data->update_y2 = y+suby; suby ++; } if (x < d->vfb_data->update_x1) d->vfb_data->update_x1 = x; if (x2 > d->vfb_data->update_x2) d->vfb_data->update_x2 = x2; } } } DEVICE_ACCESS(px) { uint64_t idata = 0, odata = 0; struct px_data *d = (struct px_data *) extra; size_t i; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (relative_addr < 0x0c0000) { /* * DMA poll: a read from this address should start a DMA * transfer, and return 1 in odata while the DMA is in * progress (STAMP_BUSY), and then 0 (STAMP_OK) once we're * done. * * According to NetBSD's pxreg.h, the following formula gets * us from system address to DMA address: (v is the system * address) * * dma_addr = ( ( ((v & ~0x7fff) << 3) | * (v & 0x7fff) ) & 0x1ffff800) >> 9; * * Hopefully, this is a good enough reversal of that formula: * * sys_addr = ((dma_addr << 9) & 0x7800) + * ((dma_addr << 6) & 0xffff8000); * * If the board type is "PX" then the system address is an * address in host memory. Otherwise, it is relative to * 0x200000 (the i860's memory space on the board). */ uint32_t sys_addr; /* system address for DMA transfers */ sys_addr = ((relative_addr << 9) & 0x7800) + ((relative_addr << 6) & 0xffff8000); /* * If the system address is sane enough, then start a DMA * transfer: (for the "PX" board type, don't allow obviously * too-low physical addresses) */ if (sys_addr >= 0x4000 || d->type != DEV_PX_TYPE_PX) dev_px_dma(cpu, sys_addr, d); /* Pretend that it was always OK: */ odata = STAMP_OK; } /* N10 sram: */ if (relative_addr >= 0x200000 && relative_addr < 0x280000) { if (d->type == DEV_PX_TYPE_PX) fatal("WARNING: the vdac should be at this " "address. overlap problems?\n"); if (writeflag == MEM_WRITE) { for (i=0; isram[relative_addr - 0x200000 + i] = data[i]; /* NOTE: this return here supresses debug output (which would be printed if we continue) */ return 1; } else { /* * Huh? Why have I commented out this? TODO */ /* for (i=0; isram[relative_addr - 0x200000 + i]; */ odata = 1; } } /* TODO: Most of these aren't implemented yet. */ switch (relative_addr) { case 0x180008: /* hsync */ if (writeflag==MEM_READ) { debug("[ px: read from hsync: 0x%08llx ]\n", (long long)odata); } else { debug("[ px: write to hsync: 0x%08llx ]\n", (long long)idata); } break; case 0x18000c: /* hsync2 */ if (writeflag==MEM_READ) { debug("[ px: read from hsync2: 0x%08llx ]\n", (long long)odata); } else { debug("[ px: write to hsync2: 0x%08llx ]\n", (long long)idata); } break; case 0x180010: /* hblank */ if (writeflag==MEM_READ) { debug("[ px: read from hblank: 0x%08llx ]\n", (long long)odata); } else { debug("[ px: write to hblank: 0x%08llx ]\n", (long long)idata); } break; case 0x180014: /* vsync */ if (writeflag==MEM_READ) { debug("[ px: read from vsync: 0x%08llx ]\n", (long long)odata); } else { debug("[ px: write to vsync: 0x%08llx ]\n", (long long)idata); } break; case 0x180018: /* vblank */ if (writeflag==MEM_READ) { debug("[ px: read from vblank: 0x%08llx ]\n", (long long)odata); } else { debug("[ px: write to vblank: 0x%08llx ]\n", (long long)idata); } break; case 0x180020: /* ipdvint */ if (writeflag==MEM_READ) { odata = d->intr; /* TODO: how do interrupts work on the pixelstamp boards? */ odata = random(); debug("[ px: read from ipdvint: 0x%08llx ]\n", (long long)odata); } else { d->intr = idata; if (idata & STIC_INT_E_WE) d->intr &= ~STIC_INT_E; if (idata & STIC_INT_V_WE) d->intr &= ~STIC_INT_V; if (idata & STIC_INT_P_WE) d->intr &= ~STIC_INT_P; debug("[ px: write to ipdvint: 0x%08llx ]\n", (long long)idata); } break; case 0x180028: /* sticsr */ if (writeflag==MEM_READ) { debug("[ px: read from sticsr: 0x%08llx ]\n", (long long)odata); } else { debug("[ px: write to sticsr: 0x%08llx ]\n", (long long)idata); } break; case 0x180038: /* buscsr */ if (writeflag==MEM_READ) { debug("[ px: read from buscsr: 0x%08llx ]\n", (long long)odata); } else { debug("[ px: write to buscsr: 0x%08llx ]\n", (long long)idata); } break; case 0x18003c: /* modcl */ if (writeflag==MEM_READ) { odata = (d->type << 12) + (d->xconfig << 11) + (d->yconfig << 9); debug("[ px: read from modcl: 0x%llx ]\n", (long long)odata); } else { debug("[ px: write to modcl: 0x%llx ]\n", (long long)idata); } break; default: if (writeflag==MEM_READ) { debug("[ px: read from addr 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)odata); } else { debug("[ px: write to addr 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } void dev_px_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, int px_type, const char *irq_path) { struct px_data *d; CHECK_ALLOCATION(d = (struct px_data *) malloc(sizeof(struct px_data))); memset(d, 0, sizeof(struct px_data)); d->type = px_type; INTERRUPT_CONNECT(irq_path, d->irq); d->xconfig = d->yconfig = 0; /* 4x1 */ d->bitdepth = 24; d->px_name = "(invalid)"; switch (d->type) { case DEV_PX_TYPE_PX: d->bitdepth = 8; d->px_name = "PX"; break; case DEV_PX_TYPE_PXG: d->bitdepth = 8; d->px_name = "PXG"; break; case DEV_PX_TYPE_PXGPLUS: d->px_name = "PXG+"; break; case DEV_PX_TYPE_PXGPLUSTURBO: d->px_name = "PXG+ TURBO"; d->xconfig = d->yconfig = 1; /* 5x2 */ break; default: fatal("dev_px_init(): unimplemented px_type\n"); } d->fb_mem = memory_new(PX_XSIZE * PX_YSIZE * d->bitdepth / 8, machine->arch); if (d->fb_mem == NULL) { fprintf(stderr, "dev_px_init(): out of memory (1)\n"); exit(1); } d->vfb_data = dev_fb_init(machine, d->fb_mem, 0, VFB_GENERIC, PX_XSIZE, PX_YSIZE, PX_XSIZE, PX_YSIZE, d->bitdepth, d->px_name); if (d->vfb_data == NULL) { fprintf(stderr, "dev_px_init(): out of memory (2)\n"); exit(2); } switch (d->type) { case DEV_PX_TYPE_PX: dev_bt459_init(machine, mem, baseaddr + 0x200000, 0, d->vfb_data, 8, irq_path, BT459_PX); break; case DEV_PX_TYPE_PXG: case DEV_PX_TYPE_PXGPLUS: case DEV_PX_TYPE_PXGPLUSTURBO: dev_bt459_init(machine, mem, baseaddr + 0x300000, 0, d->vfb_data, d->bitdepth, irq_path, BT459_PX); break; default: fatal("dev_px_init(): unimplemented px_type\n"); } memory_device_register(mem, "px", baseaddr, DEV_PX_LENGTH, dev_px_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(machine, dev_px_tick, d, 14); } gxemul-0.6.1/src/devices/dev_jazz.cc000644 001750 001750 00000043623 13402411502 017571 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Microsoft Jazz-related stuff (Acer PICA-61, etc) * * TODO/NOTE: This is mostly a quick hack, it doesn't really implement * much of the Jazz architecture. Also, the a0/20 isa-like stuff is * not supposed to be here. * * TODO: Figure out how the int enable mask works; it seems to be shifted * 10 bits (?) according to NetBSD/arc sources. * * TODO: Don't hardcode the timer to 100 Hz. * * JAZZ interrupts 0..14 are connected to MIPS irq 3, * JAZZ interrupt 15 (the timer) is connected to MIPS irq 6, * and ISA interrupts 0..15 are connected to MIPS irq 4. */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "timer.h" #include "thirdparty/jazz_r4030_dma.h" #include "thirdparty/pica.h" #define DEV_JAZZ_LENGTH 0x280 #define DEV_JAZZ_TICKSHIFT 14 #define PICA_TIMER_IRQ 15 struct jazz_data { struct interrupt mips_irq_3; struct interrupt mips_irq_4; struct interrupt mips_irq_6; struct cpu *cpu; /* Jazz stuff: */ uint32_t int_enable_mask; /* TODO! */ uint32_t int_asserted; /* ISA stuff: */ uint32_t isa_int_enable_mask; uint32_t isa_int_asserted; int interval; int interval_start; struct timer *timer; int pending_timer_interrupts; int jazz_timer_value; int jazz_timer_current; struct interrupt jazz_timer_irq; uint64_t dma_translation_table_base; uint64_t dma_translation_table_limit; uint32_t dma0_mode; uint32_t dma0_enable; uint32_t dma0_count; uint32_t dma0_addr; uint32_t dma1_mode; /* same for dma1,2,3 actually (TODO) */ int led; }; void reassert_isa_interrupts(struct jazz_data *d) { if (d->isa_int_asserted & d->isa_int_enable_mask) INTERRUPT_ASSERT(d->mips_irq_4); else INTERRUPT_DEASSERT(d->mips_irq_4); } void jazz_interrupt_assert(struct interrupt *interrupt) { struct jazz_data *d = (struct jazz_data *) interrupt->extra; d->int_asserted |= (1 << interrupt->line); if (d->int_asserted & 0x7fff) INTERRUPT_ASSERT(d->mips_irq_3); if (d->int_asserted & 0x8000) INTERRUPT_ASSERT(d->mips_irq_6); } void jazz_interrupt_deassert(struct interrupt *interrupt) { struct jazz_data *d = (struct jazz_data *) interrupt->extra; d->int_asserted &= ~(1 << interrupt->line); if (!(d->int_asserted & 0x7fff)) INTERRUPT_DEASSERT(d->mips_irq_3); if (!(d->int_asserted & 0x8000)) INTERRUPT_DEASSERT(d->mips_irq_6); } void jazz_isa_interrupt_assert(struct interrupt *interrupt) { struct jazz_data *d = (struct jazz_data *) interrupt->extra; d->isa_int_asserted |= (1 << interrupt->line); reassert_isa_interrupts(d); } void jazz_isa_interrupt_deassert(struct interrupt *interrupt) { struct jazz_data *d = (struct jazz_data *) interrupt->extra; d->isa_int_asserted &= ~(1 << interrupt->line); reassert_isa_interrupts(d); } /* * dev_jazz_dma_controller(): */ size_t dev_jazz_dma_controller(void *dma_controller_data, unsigned char *data, size_t len, int writeflag) { struct jazz_data *d = (struct jazz_data *) dma_controller_data; struct cpu *cpu = d->cpu; int i, enab_writeflag; int res, ncpy; uint32_t dma_addr; unsigned char tr[sizeof(uint32_t)]; uint32_t phys_addr; #if 0 fatal("[ dev_jazz_dma_controller(): writeflag=%i, len=%i, data =", writeflag, (int)len); for (i=0; idma0_mode, d->dma0_enable, d->dma0_count, d->dma0_addr); fatal(" table=%08x", d->dma_translation_table_base); fatal(" ]\n"); #endif if (!(d->dma0_enable & R4030_DMA_ENAB_RUN)) { fatal("[ dev_jazz_dma_controller(): dma not enabled? ]\n"); /* return 0; */ } /* R4030 "write" means write to the device, writeflag as the argument to this function means write to memory. */ enab_writeflag = (d->dma0_enable & R4030_DMA_ENAB_WRITE)? 0 : 1; if (enab_writeflag != writeflag) { fatal("[ dev_jazz_dma_controller(): wrong direction? ]\n"); return 0; } dma_addr = d->dma0_addr; i = 0; while (dma_addr < d->dma0_addr + d->dma0_count && i < (int32_t)len) { res = cpu->memory_rw(cpu, cpu->mem, d->dma_translation_table_base + (dma_addr >> 12) * 8, tr, sizeof(tr), 0, PHYSICAL | NO_EXCEPTIONS); if (cpu->byte_order==EMUL_BIG_ENDIAN) phys_addr = (tr[0] << 24) + (tr[1] << 16) + (tr[2] << 8) + tr[3]; else phys_addr = (tr[3] << 24) + (tr[2] << 16) + (tr[1] << 8) + tr[0]; phys_addr &= ~0xfff; /* just in case */ phys_addr += (dma_addr & 0xfff); /* fatal(" !!! dma_addr = %08x, phys_addr = %08x\n", (int)dma_addr, (int)phys_addr); */ /* Speed up the copying by copying 16 or 256 bytes: */ ncpy = 1; if ((phys_addr & 15) == 0 && i + 15 <= (int32_t)len) ncpy = 15; if ((phys_addr & 255) == 0 && i + 255 <= (int32_t)len) ncpy = 255; res = cpu->memory_rw(cpu, cpu->mem, phys_addr, &data[i], ncpy, writeflag, PHYSICAL | NO_EXCEPTIONS); dma_addr += ncpy; i += ncpy; } /* TODO: Is this correct? */ d->dma0_count = 0; return len; } static void timer_tick(struct timer *t, void *extra) { struct jazz_data *d = (struct jazz_data *) extra; d->pending_timer_interrupts ++; } DEVICE_TICK(jazz) { struct jazz_data *d = (struct jazz_data *) extra; /* Used by NetBSD/arc and OpenBSD/arc: */ if (d->interval_start > 0 && d->interval > 0 && (d->int_enable_mask & 2) /* Hm? */ ) { d->interval -= 2; if (d->interval <= 0) { /* debug("[ jazz: interval timer interrupt ]\n"); INTERRUPT_ASSERT(d->jazz_timer_irq); */ } /* New timer system: */ if (d->pending_timer_interrupts > 0) INTERRUPT_ASSERT(d->jazz_timer_irq); } /* Linux? */ if (d->jazz_timer_value != 0) { d->jazz_timer_current -= 5; if (d->jazz_timer_current < 1) { d->jazz_timer_current = d->jazz_timer_value; /* INTERRUPT_ASSERT(d->mips_irq_6); */ } /* New timer system: */ if (d->pending_timer_interrupts > 0) INTERRUPT_ASSERT(d->mips_irq_6); } } DEVICE_ACCESS(jazz) { struct jazz_data *d = (struct jazz_data *) extra; uint64_t idata = 0, odata = 0; int regnr; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); regnr = relative_addr / sizeof(uint32_t); switch (relative_addr) { case R4030_SYS_CONFIG: if (writeflag == MEM_WRITE) { fatal("[ jazz: unimplemented write to R4030_SYS_CONFIG" ", data=0x%08x ]\n", (int)idata); } else { /* Reading the config register should give 0x0104 or 0x0410. Why? TODO */ odata = 0x104; } break; case R4030_SYS_TL_BASE: if (writeflag == MEM_WRITE) { d->dma_translation_table_base = idata; } else { odata = d->dma_translation_table_base; } break; case R4030_SYS_TL_LIMIT: if (writeflag == MEM_WRITE) { d->dma_translation_table_limit = idata; } else { odata = d->dma_translation_table_limit; } break; case R4030_SYS_TL_IVALID: /* TODO: Does invalidation actually need to be implemented? */ break; case R4030_SYS_DMA0_REGS: if (writeflag == MEM_WRITE) { d->dma0_mode = idata; } else { odata = d->dma0_mode; } break; case R4030_SYS_DMA0_REGS + 0x8: if (writeflag == MEM_WRITE) { d->dma0_enable = idata; } else { odata = d->dma0_enable; } break; case R4030_SYS_DMA0_REGS + 0x10: if (writeflag == MEM_WRITE) { d->dma0_count = idata; } else { odata = d->dma0_count; } break; case R4030_SYS_DMA0_REGS + 0x18: if (writeflag == MEM_WRITE) { d->dma0_addr = idata; } else { odata = d->dma0_addr; } break; case R4030_SYS_DMA1_REGS: if (writeflag == MEM_WRITE) { d->dma1_mode = idata; } else { odata = d->dma1_mode; } break; case R4030_SYS_ISA_VECTOR: /* ? */ printf("R4030_SYS_ISA_VECTOR: w=%i\n", writeflag); { uint32_t x = d->isa_int_asserted & d->isa_int_enable_mask; odata = 0; while (odata < 16) { if (x & (1 << odata)) break; odata ++; } if (odata >= 16) odata = 0; } break; case R4030_SYS_IT_VALUE: /* Interval timer reload value */ if (writeflag == MEM_WRITE) { d->interval_start = idata; d->interval = d->interval_start; } else odata = d->interval_start; break; case R4030_SYS_IT_STAT: /* Accessing this word seems to acknowledge interrupts? */ INTERRUPT_DEASSERT(d->jazz_timer_irq); if (d->pending_timer_interrupts > 0) d->pending_timer_interrupts --; if (writeflag == MEM_WRITE) d->interval = idata; else odata = d->interval; d->interval = d->interval_start; break; case R4030_SYS_EXT_IMASK: if (writeflag == MEM_WRITE) { int old_assert_3 = (0x7fff & d->int_asserted & d->int_enable_mask); int old_assert_6 = (0x8000 & d->int_asserted & d->int_enable_mask); int new_assert_3, new_assert_6; d->int_enable_mask = idata; new_assert_3 = d->int_asserted & d->int_enable_mask & 0x7fff; new_assert_6 = d->int_asserted & d->int_enable_mask & 0x8000; if (old_assert_3 && !new_assert_3) INTERRUPT_DEASSERT(d->mips_irq_3); else if (!old_assert_3 && new_assert_3) INTERRUPT_ASSERT(d->mips_irq_3); if (old_assert_6 && !new_assert_6) INTERRUPT_DEASSERT(d->mips_irq_6); else if (!old_assert_6 && new_assert_6) INTERRUPT_ASSERT(d->mips_irq_6); } else odata = d->int_enable_mask; break; default: if (writeflag == MEM_WRITE) { fatal("[ jazz: unimplemented write to address 0x%x" ", data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { fatal("[ jazz: unimplemented read from address 0x%x" " ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(jazz_led) { struct jazz_data *d = (struct jazz_data *) extra; uint64_t idata = 0, odata = 0; int regnr; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); regnr = relative_addr / sizeof(uint32_t); switch (relative_addr) { case 0: if (writeflag == MEM_WRITE) { d->led = idata; debug("[ jazz_led: write to LED: 0x%02x ]\n", (int)idata); } else { odata = d->led; } break; default: if (writeflag == MEM_WRITE) { fatal("[ jazz_led: unimplemented write to address 0x%x" ", data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { fatal("[ jazz_led: unimplemented read from address 0x%x" " ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_jazz_a0_access(): * * ISA interrupt stuff, high 8 interrupts. * * TODO: use isa8 stuff instead! */ DEVICE_ACCESS(jazz_a0) { struct jazz_data *d = (struct jazz_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0: if (writeflag == MEM_WRITE) { /* TODO: only if idata == 0x20? */ d->isa_int_asserted &= 0xff; reassert_isa_interrupts(d); } break; case 1: if (writeflag == MEM_WRITE) { idata = ((idata ^ 0xff) & 0xff) << 8; d->isa_int_enable_mask = (d->isa_int_enable_mask & 0xff) | idata; debug("[ jazz_isa_a0: setting isa_int_enable_mask " "to 0x%04x ]\n", (int)d->isa_int_enable_mask); reassert_isa_interrupts(d); } else odata = d->isa_int_enable_mask; break; default: if (writeflag == MEM_WRITE) { fatal("[ jazz_isa_a0: unimplemented write to " "address 0x%x, data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { fatal("[ jazz_isa_a0: unimplemented read from " "address 0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_jazz_20_access(): * * ISA interrupt stuff, low 8 interrupts. */ DEVICE_ACCESS(jazz_20) { struct jazz_data *d = (struct jazz_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0: if (writeflag == MEM_WRITE) { /* TODO: only if idata == 0x20? */ d->isa_int_asserted &= 0xff00; reassert_isa_interrupts(d); } break; case 1: if (writeflag == MEM_WRITE) { idata = (idata ^ 0xff) & 0xff; d->isa_int_enable_mask = (d->isa_int_enable_mask & 0xff00) | idata; debug("[ jazz_isa_20: setting isa_int_enable_mask " "to 0x%04x ]\n", (int)d->isa_int_enable_mask); reassert_isa_interrupts(d); } else odata = d->isa_int_enable_mask; break; default: if (writeflag == MEM_WRITE) { fatal("[ jazz_isa_20: unimplemented write to " "address 0x%x, data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { fatal("[ jazz_isa_20: unimplemented read from " "address 0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_jazz_jazzio_access(): * * See jazzio_intr() in NetBSD's * /usr/src/sys/arch/arc/jazz/jazzio.c for more info. */ DEVICE_ACCESS(jazz_jazzio) { struct jazz_data *d = (struct jazz_data *) extra; uint64_t idata = 0, odata = 0; int i, v; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0: v = 0; for (i=0; i<15; i++) { if (d->int_asserted & (1<jazz_timer_value = idata; else odata = d->jazz_timer_value; break; default: if (writeflag == MEM_WRITE) { fatal("[ jazzio: unimplemented write to address 0x%x" ", data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { fatal("[ jazzio: unimplemented read from address 0x%x" " ]\n", (int)relative_addr); } } /* This is needed by Windows NT during startup: */ INTERRUPT_DEASSERT(d->mips_irq_3); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(jazz) { struct jazz_data *d; char tmpstr[300]; int i; CHECK_ALLOCATION(d = (struct jazz_data *) malloc(sizeof(struct jazz_data))); memset(d, 0, sizeof(struct jazz_data)); d->cpu = devinit->machine->cpus[0]; /* TODO */ d->isa_int_enable_mask = 0xffff; /* * Register 16 native JAZZ irqs, and 16 ISA irqs: * * machine[y].cpu[z].jazz.%i (native) * machine[y].cpu[z].jazz.isa.%i (ISA) */ for (i=0; i<16; i++) { struct interrupt templ; char n[300]; snprintf(n, sizeof(n), "%s.jazz.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = n; templ.extra = d; templ.interrupt_assert = jazz_interrupt_assert; templ.interrupt_deassert = jazz_interrupt_deassert; interrupt_handler_register(&templ); } for (i=0; i<16; i++) { struct interrupt templ; char n[300]; snprintf(n, sizeof(n), "%s.jazz.isa.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = n; templ.extra = d; templ.interrupt_assert = jazz_isa_interrupt_assert; templ.interrupt_deassert = jazz_isa_interrupt_deassert; interrupt_handler_register(&templ); } /* Connect to MIPS CPU interrupt lines: */ snprintf(tmpstr, sizeof(tmpstr), "%s.3", devinit->interrupt_path); INTERRUPT_CONNECT(tmpstr, d->mips_irq_3); snprintf(tmpstr, sizeof(tmpstr), "%s.4", devinit->interrupt_path); INTERRUPT_CONNECT(tmpstr, d->mips_irq_4); snprintf(tmpstr, sizeof(tmpstr), "%s.6", devinit->interrupt_path); INTERRUPT_CONNECT(tmpstr, d->mips_irq_6); /* Connect to JAZZ timer interrupt: */ snprintf(tmpstr, sizeof(tmpstr), "%s.jazz.%i", devinit->interrupt_path, PICA_TIMER_IRQ); INTERRUPT_CONNECT(tmpstr, d->jazz_timer_irq); memory_device_register(devinit->machine->memory, "jazz", devinit->addr, DEV_JAZZ_LENGTH, dev_jazz_access, (void *)d, DM_DEFAULT, NULL); /* At least for Magnum and Pica-61: */ memory_device_register(devinit->machine->memory, "jazz_led", 0x08000f000ULL, 4, dev_jazz_led_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, "jazz_isa_20", 0x90000020ULL, 2, dev_jazz_20_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, "jazz_isa_a0", 0x900000a0ULL, 2, dev_jazz_a0_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, "pica_jazzio", 0xf0000000ULL, 4, dev_jazz_jazzio_access, (void *)d, DM_DEFAULT, NULL); /* Add a timer, hardcoded to 100 Hz. TODO: Don't hardcode! */ d->timer = timer_add(100.0, timer_tick, d); machine_add_tickfunction(devinit->machine, dev_jazz_tick, d, DEV_JAZZ_TICKSHIFT); devinit->return_ptr = d; return 1; } gxemul-0.6.1/src/devices/dev_pmagja.cc000644 001750 001750 00000013710 13402411502 020044 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: TURBOchannel PMAG-JA graphics card * * TODO */ #include #include #include #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #define XSIZE 1280 #define YSIZE 1024 #define PMAGJA_FIRSTOFFSET 0x40030 /* #define JA_DEBUG */ struct pmagja_data { struct interrupt irq; struct memory *fb_mem; struct vfb_data *vfb_data; unsigned char pixeldata[XSIZE * YSIZE]; int current_r; int current_g; int current_b; int pip_offset; }; DEVICE_ACCESS(pmagja) { struct pmagja_data *d = (struct pmagja_data *) extra; uint64_t idata = 0, odata = 0; size_t i, res = 1; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); relative_addr += PMAGJA_FIRSTOFFSET; #ifdef JA_DEBUG { size_t i; for (i=0; ipip_offset; debug("[ pmagja: read from pip offset: 0x%08llx ]\n", (long long)odata); } else { d->pip_offset = idata; debug("[ px: write to pip offset: 0x%08llx ]\n", (long long)idata); } break; default: if (relative_addr >= 0x200000) { /* 8-bit access: */ for (i=0; ipixeldata[x + y*XSIZE] = data[i]; newdata[0] = d->vfb_data->rgb_palette[ data[i] * 3 + 0]; newdata[1] = d->vfb_data->rgb_palette[ data[i] * 3 + 1]; newdata[2] = d->vfb_data->rgb_palette[ data[i] * 3 + 2]; dev_fb_access(cpu, d->fb_mem, (x + y * XSIZE) * 3, newdata, 3, writeflag, d->vfb_data); } else { data[i] = d->pixeldata[x + y*XSIZE]; } } /* Return success. */ return 1; } else if (relative_addr >= 0x100000 && relative_addr < 0x200000) { /* 24-bit access: */ #if 0 { if (writeflag) if (idata != 0) fatal("[ pmagja: write to addr 0x%08llx: 0x%08llx ]\n", (long long)relative_addr, (long long)idata); } #endif int x, y, ofs; ofs = (relative_addr - 0x100000) * 2; y = ofs / XSIZE; x = ofs - y * XSIZE; #if 0 if (writeflag == MEM_WRITE) { int ix; for (ix=0; ix> (ix*4)) & 0xf; if (ctype == 0) data[0] = 255; if (ctype == 3) data[1] = 255; if (ctype == 0xf) data[2] = 255; res = dev_fb_access(cpu, d->fb_mem, ofs * 3, data, 3, MEM_WRITE, d->vfb_data); ofs ++; } } #endif return 1; } else { /* Unknown: */ if (writeflag==MEM_READ) { fatal("[ pmagja: read from addr 0x%x: " "0x%llx ]\n", (int)relative_addr, (long long)odata); } else { fatal("[ pmagja: write to addr 0x%x: " "0x%llx ]\n", (int)relative_addr, (long long)idata); } } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); #ifdef JA_DEBUG /* if (!writeflag) fatal("[ pmagja: read from addr 0x%08llx: 0x%08llx ]\n", (long long)relative_addr, (long long)odata); */ #endif return res; } void dev_pmagja_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, const char *irq_path) { struct pmagja_data *d; CHECK_ALLOCATION(d = (struct pmagja_data *) malloc(sizeof(struct pmagja_data))); memset(d, 0, sizeof(struct pmagja_data)); INTERRUPT_CONNECT(irq_path, d->irq); d->fb_mem = memory_new(XSIZE * YSIZE * 3, machine->arch); if (d->fb_mem == NULL) { fprintf(stderr, "dev_pmagja_init(): out of memory (1)\n"); exit(1); } d->vfb_data = dev_fb_init(machine, d->fb_mem, 0, VFB_GENERIC, XSIZE, YSIZE, XSIZE, YSIZE, 24, "PMAG-JA"); if (d->vfb_data == NULL) { fprintf(stderr, "dev_pmagja_init(): out of memory (2)\n"); exit(2); } /* TODO: not bt459, but a bt463: */ dev_bt459_init(machine, mem, baseaddr + 0x40000, 0, d->vfb_data, 8, irq_path, 0); /* palette (TODO: type) */ dev_bt431_init(mem, baseaddr + 0x40010, d->vfb_data, 8); /* cursor */ memory_device_register(mem, "pmagja", baseaddr + PMAGJA_FIRSTOFFSET, DEV_PMAGJA_LENGTH - PMAGJA_FIRSTOFFSET, dev_pmagja_access, d, DM_DEFAULT, NULL); } gxemul-0.6.1/src/devices/dev_asc.cc000644 001750 001750 00000075376 13402411502 017373 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: NCR53C9X "ASC" SCSI controller * * This is the SCSI controller used in some DECstation/DECsystem models and * the PICA-61 machine. * * Supposed to support SCSI-1 and SCSI-2. I've not yet found any docs * on NCR53C9X, so I'll try to implement this device from LSI53CF92A docs * instead. * * * Memory layout on DECstation: * * NCR53C94 registers at base + 0 * DMA address register at base + 0x40000 * 128K SRAM buffer at base + 0x80000 * ROM at base + 0xc0000 * * Memory layout on PICA-61: * * I haven't had time to look this up yet, but length = 0x1000. * * * TODO: This module needs a clean-up, and some testing to see that * it works will all OSes that might use it (NetBSD, OpenBSD, * Ultrix, Linux, Mach, OSF/1, Sprite, ...) * * Running Linux/DECstation 2.4.26 with no scsi disks attached causes * a warning message to be printed by Linux. (Whether this is a bug, * is is the way it works on real hardware, I don't know.) */ #include #include #include #include "cpu.h" #include "devices.h" #include "diskimage.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/ncr53c9xreg.h" /* #define ASC_DEBUG */ /* #define debug fatal */ /* #define ASC_FULL_REGISTER_ACCESS_DEBUG */ /* static int quiet_mode = 0; */ #define ASC_TICK_SHIFT 15 extern int quiet_mode; #define ASC_FIFO_LEN 16 #define STATE_DISCONNECTED 0 #define STATE_INITIATOR 1 #define STATE_TARGET 2 #define PHASE_DATA_OUT 0 #define PHASE_DATA_IN 1 #define PHASE_COMMAND 2 #define PHASE_STATUS 3 #define PHASE_MSG_OUT 6 #define PHASE_MSG_IN 7 /* The controller's SCSI id: */ #define ASC_SCSI_ID 7 #define ASC_DMA_SIZE (128*1024) struct asc_data { int mode; void *turbochannel; struct interrupt irq; int irq_asserted; /* Current state and transfer: */ int cur_state; int cur_phase; struct scsi_transfer *xferp; /* FIFO: */ unsigned char fifo[ASC_FIFO_LEN]; int fifo_in; int fifo_out; int n_bytes_in_fifo; /* cached */ /* ATN signal: */ int atn; /* Incoming dma data: */ unsigned char *incoming_data; int incoming_len; int incoming_data_addr; /* Built-in DMA memory (for DECstation 5000/200): */ uint32_t dma_address_reg; unsigned char *dma_address_reg_memory; unsigned char *dma; void *dma_controller_data; size_t (*dma_controller)(void *dma_controller_data, unsigned char *data, size_t len, int writeflag); /* Read registers and write registers: */ uint32_t reg_ro[0x10]; uint32_t reg_wo[0x10]; }; /* (READ/WRITE name, if split) */ const char *asc_reg_names[0x10] = { "NCR_TCL", "NCR_TCM", "NCR_FIFO", "NCR_CMD", "NCR_STAT/NCR_SELID", "NCR_INTR/NCR_TIMEOUT", "NCR_STEP/NCR_SYNCTP", "NCR_FFLAG/NCR_SYNCOFF", "NCR_CFG1", "NCR_CCF", "NCR_TEST", "NCR_CFG2", "NCR_CFG3", "reg_0xd", "NCR_TCH", "reg_0xf" }; /* This is referenced below. */ static int dev_asc_select(struct cpu *cpu, struct asc_data *d, int from_id, int to_id, int dmaflag, int n_messagebytes); DEVICE_TICK(asc) { struct asc_data *d = (struct asc_data *) extra; int new_assert = d->reg_ro[NCR_STAT] & NCRSTAT_INT; if (new_assert && !d->irq_asserted) INTERRUPT_ASSERT(d->irq); d->irq_asserted = new_assert; } /* * dev_asc_fifo_flush(): * * Flush the fifo. */ static void dev_asc_fifo_flush(struct asc_data *d) { d->fifo[0] = 0x00; d->fifo_in = 0; d->fifo_out = 0; d->n_bytes_in_fifo = 0; } /* * dev_asc_reset(): * * Reset the state of the asc. */ static void dev_asc_reset(struct asc_data *d) { d->cur_state = STATE_DISCONNECTED; d->atn = 0; if (d->xferp != NULL) scsi_transfer_free(d->xferp); d->xferp = NULL; dev_asc_fifo_flush(d); /* According to table 4.1 in the LSI53CF92A manual: */ memset(d->reg_wo, 0, sizeof(d->reg_wo)); d->reg_wo[NCR_TCH] = 0x94; d->reg_wo[NCR_CCF] = 2; memcpy(d->reg_ro, d->reg_wo, sizeof(d->reg_ro)); d->reg_wo[NCR_SYNCTP] = 5; } /* * dev_asc_fifo_read(): * * Read a byte from the asc FIFO. */ static int dev_asc_fifo_read(struct asc_data *d) { int res = d->fifo[d->fifo_out]; if (d->fifo_in == d->fifo_out) fatal("dev_asc: WARNING! FIFO overrun!\n"); d->fifo_out = (d->fifo_out + 1) % ASC_FIFO_LEN; d->n_bytes_in_fifo --; return res; } /* * dev_asc_fifo_write(): * * Write a byte to the asc FIFO. */ static void dev_asc_fifo_write(struct asc_data *d, unsigned char data) { d->fifo[d->fifo_in] = data; d->fifo_in = (d->fifo_in + 1) % ASC_FIFO_LEN; d->n_bytes_in_fifo ++; if (d->fifo_in == d->fifo_out) fatal("dev_asc: WARNING! FIFO overrun on write!\n"); } /* * dev_asc_newxfer(): * * Allocate memory for a new transfer. */ static void dev_asc_newxfer(struct asc_data *d) { if (d->xferp != NULL) { printf("WARNING! dev_asc_newxfer(): freeing previous" " transfer\n"); scsi_transfer_free(d->xferp); d->xferp = NULL; } d->xferp = scsi_transfer_alloc(); #if 0 d->xferp->get_data_out = dev_asc_get_data_out; d->xferp->gdo_extra = (void *) d; #endif } /* * dev_asc_transfer(): * * Transfer data from a SCSI device to the controller (or vice versa), * depending on the current phase. * * Returns 1 if ok, 0 on error. */ static int dev_asc_transfer(struct cpu *cpu, struct asc_data *d, int dmaflag) { int res = 1, all_done = 1; int len, i, ch; if (!quiet_mode) debug(" { TRANSFER to/from id %i: ", d->reg_wo[NCR_SELID] & 7); if (d->cur_phase == PHASE_DATA_IN) { /* Data coming into the controller from external device: */ if (!dmaflag) { if (d->xferp->data_in == NULL) { fatal("no incoming data?\n"); res = 0; } else { /* TODO */ fatal("TODO..............\n"); len = d->reg_wo[NCR_TCL] + d->reg_wo[NCR_TCM] * 256; len--; ch = d->incoming_data[d->incoming_data_addr]; debug(" %02x", ch); d->incoming_data_addr ++; dev_asc_fifo_write(d, ch); if (len == 0) { free(d->incoming_data); d->incoming_data = NULL; } d->reg_ro[NCR_TCL] = len & 255; d->reg_ro[NCR_TCM] = (len >> 8) & 255; } } else { /* Copy from the incoming data into dma memory: */ if (d->xferp->data_in == NULL) { fatal("no incoming DMA data?\n"); res = 0; } else { size_t lenIn = d->xferp->data_in_len; size_t lenIn2 = d->reg_wo[NCR_TCL] + d->reg_wo[NCR_TCM] * 256; if (lenIn2 == 0) lenIn2 = 65536; if (lenIn < lenIn2) { fatal("{ asc: data in, lenIn=%i lenIn2=%i " "}\n", lenIn, lenIn2); } /* TODO: check lenIn2 in a similar way? */ if (lenIn + (d->dma_address_reg & (ASC_DMA_SIZE-1)) > ASC_DMA_SIZE) lenIn = ASC_DMA_SIZE - (d->dma_address_reg & (ASC_DMA_SIZE-1)); if (lenIn2 > lenIn) { memset(d->dma + (d->dma_address_reg & (ASC_DMA_SIZE-1)), 0, lenIn2); lenIn2 = lenIn; } #ifdef ASC_DEBUG if (!quiet_mode) { int i; for (i=0; ixferp-> data_in[i]); } #endif /* * Are we using an external DMA controller? * Then use it. Otherwise place the data in * the DECstation 5000/200 built-in DMA * region. */ if (d->dma_controller != NULL) d->dma_controller( d->dma_controller_data, d->xferp->data_in, lenIn2, 1); else memcpy(d->dma + (d->dma_address_reg & (ASC_DMA_SIZE-1)), d->xferp->data_in, lenIn2); if (d->xferp->data_in_len > lenIn2) { unsigned char *n; if (d->dma_controller != NULL) printf("WARNING!!!!!!!!! BUG!!!! Unexpected stuff..." "lenIn2=%i d->xferp->data_in_len=%i\n", (int)lenIn2, (int)d->xferp->data_in_len); all_done = 0; /* fatal("{ asc: multi-transfer" " data_in, lenIn=%i lenIn2=%i }\n", (int)lenIn, (int)lenIn2); */ d->xferp->data_in_len -= lenIn2; CHECK_ALLOCATION(n = (unsigned char *) malloc(d->xferp->data_in_len)); memcpy(n, d->xferp->data_in + lenIn2, d->xferp->data_in_len); free(d->xferp->data_in); d->xferp->data_in = n; lenIn = lenIn2; } lenIn = 0; d->reg_ro[NCR_TCL] = lenIn & 255; d->reg_ro[NCR_TCM] = (lenIn >> 8) & 255; /* Successful DMA transfer: */ d->reg_ro[NCR_STAT] |= NCRSTAT_TC; } } } else if (d->cur_phase == PHASE_DATA_OUT) { /* Data going from the controller to an external device: */ if (!dmaflag) { fatal("TODO.......asdgasin\n"); } else { /* Copy data from DMA to data_out: */ int len2 = d->reg_wo[NCR_TCL] + d->reg_wo[NCR_TCM] * 256; len = d->xferp->data_out_len; if (len2 == 0) len2 = 65536; if (len == 0) { fprintf(stderr, "d->xferp->data_out_len == " "0 ?\n"); exit(1); } /* TODO: Make sure that len2 doesn't go outside of the dma memory? */ /* fatal(" data out offset=%5i len=%5i\n", d->xferp->data_out_offset, len2); */ if (d->xferp->data_out_offset + len2 > d->xferp->data_out_len) { len2 = d->xferp->data_out_len - d->xferp->data_out_offset; } /* * Are we using an external DMA controller? Then use * it. Otherwise place the data in the DECstation * 5000/200 built-in DMA region. */ if (d->xferp->data_out == NULL) { scsi_transfer_allocbuf(&d->xferp->data_out_len, &d->xferp->data_out, len, 0); if (d->dma_controller != NULL) d->dma_controller( d->dma_controller_data, d->xferp->data_out, len2, 0); else memcpy(d->xferp->data_out, d->dma + (d->dma_address_reg & (ASC_DMA_SIZE-1)), len2); d->xferp->data_out_offset = len2; } else { /* Continuing a multi-transfer: */ if (d->dma_controller != NULL) d->dma_controller( d->dma_controller_data, d->xferp->data_out + d->xferp->data_out_offset, len2, 0); else memcpy(d->xferp->data_out + d->xferp->data_out_offset, d->dma + (d->dma_address_reg & (ASC_DMA_SIZE-1)), len2); d->xferp->data_out_offset += len2; } /* If the disk wants more than we're DMAing, then this is a multitransfer: */ if (d->xferp->data_out_offset != d->xferp->data_out_len) { if (!quiet_mode) debug("[ asc: data_out, multitransfer " "len = %i, len2 = %i ]\n", (int)len, (int)len2); if (d->xferp->data_out_offset > d->xferp->data_out_len) fatal("[ asc data_out dma: too much?" " ]\n"); else all_done = 0; } #ifdef ASC_DEBUG if (!quiet_mode) { int i; for (i=0; ixferp->data_out[i]); } #endif len = 0; d->reg_ro[NCR_TCL] = len & 255; d->reg_ro[NCR_TCM] = (len >> 8) & 255; /* Successful DMA transfer: */ d->reg_ro[NCR_STAT] |= NCRSTAT_TC; } } else if (d->cur_phase == PHASE_MSG_OUT) { if (!quiet_mode) debug("MSG OUT: "); /* Data going from the controller to an external device: */ if (!dmaflag) { /* There should already be one byte in msg_out, so we just extend the message: */ int oldlen = d->xferp->msg_out_len; int newlen; if (oldlen != 1) { fatal(" (PHASE OUT MSG len == %i, " "should be 1)\n", oldlen); } newlen = oldlen + d->n_bytes_in_fifo; CHECK_ALLOCATION(d->xferp->msg_out = (unsigned char *) realloc(d->xferp->msg_out, newlen)); d->xferp->msg_out_len = newlen; i = oldlen; while (d->fifo_in != d->fifo_out) { ch = dev_asc_fifo_read(d); d->xferp->msg_out[i++] = ch; #ifdef ASC_DEBUG debug("0x%02x ", ch); #endif } #ifdef MACH /* Super-ugly hack for Mach/PMAX: TODO: make nicer */ if (d->xferp->msg_out_len == 6 && (d->xferp->msg_out[0] == 0x80 || d->xferp->msg_out[0] == 0xc0) && d->xferp->msg_out[1] == 0x01 && d->xferp->msg_out[2] == 0x03 && d->xferp->msg_out[3] == 0x01 && d->xferp->msg_out[4] == 0x32 && d->xferp->msg_out[5] == 0x0f) { fatal(" !! Mach/PMAX hack !! "); all_done = 0; d->cur_phase = PHASE_MSG_IN; } #endif } else { /* Copy data from DMA to msg_out: */ fatal("[ DMA MSG OUT: xxx TODO! ]"); /* TODO */ res = 0; } } else if (d->cur_phase == PHASE_MSG_IN) { if (!quiet_mode) debug(" MSG IN"); fatal("[ MACH HACK! ]"); /* Super-ugly hack for Mach/PMAX: TODO: make nicer */ dev_asc_fifo_write(d, 0x07); d->cur_phase = PHASE_COMMAND; all_done = 0; } else if (d->cur_phase == PHASE_COMMAND) { if (!quiet_mode) debug(" COMMAND ==> select "); res = dev_asc_select(cpu, d, d->reg_ro[NCR_CFG1] & 7, d->reg_wo[NCR_SELID] & 7, dmaflag, 0); return res; } else { fatal("!!! TODO: unknown/unimplemented phase " "in transfer: %i\n", d->cur_phase); } /* Redo the command if data was just sent using DATA_OUT: */ if (d->cur_phase == PHASE_DATA_OUT) { res = diskimage_scsicommand(cpu, d->reg_wo[NCR_SELID] & 7, DISKIMAGE_SCSI, d->xferp); } if (all_done) { if (d->cur_phase == PHASE_MSG_OUT) d->cur_phase = PHASE_COMMAND; else d->cur_phase = PHASE_STATUS; } /* * Cause an interrupt after the transfer: * * NOTE: Earlier I had this in here as well: * d->reg_ro[NCR_INTR] |= NCRINTR_FC; * but Linux/DECstation and OpenBSD/pmax seems to choke on that. */ d->reg_ro[NCR_STAT] |= NCRSTAT_INT; d->reg_ro[NCR_INTR] |= NCRINTR_BS; d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase; d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4; /* 4? */ if (!quiet_mode) debug("}"); return res; } /* * dev_asc_select(): * * Select a SCSI device, send msg bytes (if any), and send command bytes. * (Call diskimage_scsicommand() to handle the command.) * * Return value: 1 if ok, 0 on error. */ static int dev_asc_select(struct cpu *cpu, struct asc_data *d, int from_id, int to_id, int dmaflag, int n_messagebytes) { int ok, len, i, ch; if (!quiet_mode) debug(" { SELECT id %i: ", to_id); /* * Message bytes, if any: */ if (!quiet_mode) debug("msg:"); if (n_messagebytes > 0) { scsi_transfer_allocbuf(&d->xferp->msg_out_len, &d->xferp->msg_out, n_messagebytes, 0); i = 0; while (n_messagebytes-- > 0) { int ch2 = dev_asc_fifo_read(d); if (!quiet_mode) debug(" %02x", ch2); d->xferp->msg_out[i++] = ch2; } if ((d->xferp->msg_out[0] & 0x7) != 0x00) { debug(" (LUNs not implemented yet: 0x%02x) }", d->xferp->msg_out[0]); return 0; } if (((d->xferp->msg_out[0] & ~0x7) != 0xc0) && ((d->xferp->msg_out[0] & ~0x7) != 0x80)) { fatal(" (Unimplemented msg out: 0x%02x) }", d->xferp->msg_out[0]); return 0; } if (d->xferp->msg_out_len > 1) { fatal(" (Long msg out, not implemented yet;" " len=%i) }", d->xferp->msg_out_len); return 0; } } else { if (!quiet_mode) debug(" none"); } /* Special case: SELATNS (with STOP sequence): */ if (d->cur_phase == PHASE_MSG_OUT) { if (!quiet_mode) debug(" MSG OUT DEBUG"); if (d->xferp->msg_out_len != 1) { fatal(" (SELATNS: msg out len == %i, should be 1)", d->xferp->msg_out_len); return 0; } /* d->cur_phase = PHASE_COMMAND; */ /* According to the LSI manual: */ d->reg_ro[NCR_STAT] |= NCRSTAT_INT; d->reg_ro[NCR_INTR] |= NCRINTR_FC; d->reg_ro[NCR_INTR] |= NCRINTR_BS; d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase; d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 1; if (!quiet_mode) debug("}"); return 1; } /* * Command bytes: */ if (!quiet_mode) debug(", cmd: "); if (!dmaflag) { if (!quiet_mode) debug("[non-DMA] "); scsi_transfer_allocbuf(&d->xferp->cmd_len, &d->xferp->cmd, d->n_bytes_in_fifo, 0); i = 0; while (d->fifo_in != d->fifo_out) { ch = dev_asc_fifo_read(d); d->xferp->cmd[i++] = ch; if (!quiet_mode) debug("%02x ", ch); } } else { if (!quiet_mode) debug("[DMA] "); len = d->reg_wo[NCR_TCL] + d->reg_wo[NCR_TCM] * 256; if (len == 0) len = 65536; scsi_transfer_allocbuf(&d->xferp->cmd_len, &d->xferp->cmd, len, 0); for (i=0; idma_address_reg + i; ch = d->dma[ofs & (ASC_DMA_SIZE-1)]; d->xferp->cmd[i] = ch; if (!quiet_mode) debug("%02x ", ch); } d->reg_ro[NCR_TCL] = len & 255; d->reg_ro[NCR_TCM] = (len >> 8) & 255; d->reg_ro[NCR_STAT] |= NCRSTAT_TC; } /* * Call the SCSI device to perform the command: */ ok = diskimage_scsicommand(cpu, to_id, DISKIMAGE_SCSI, d->xferp); /* Cause an interrupt: */ d->reg_ro[NCR_STAT] |= NCRSTAT_INT; d->reg_ro[NCR_INTR] |= NCRINTR_FC; d->reg_ro[NCR_INTR] |= NCRINTR_BS; if (ok == 2) d->cur_phase = PHASE_DATA_OUT; else if (d->xferp->data_in != NULL) d->cur_phase = PHASE_DATA_IN; else d->cur_phase = PHASE_STATUS; d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase; d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4; /* DONE (?) */ if (!quiet_mode) debug("}"); return ok; } DEVICE_ACCESS(asc_address_reg) { struct asc_data *d = (struct asc_data *) extra; if (relative_addr + len > 4) return 0; if (writeflag==MEM_READ) { memcpy(data, d->dma_address_reg_memory + relative_addr, len); } else { memcpy(d->dma_address_reg_memory + relative_addr, data, len); } return 1; } DEVICE_ACCESS(asc_dma) { struct asc_data *d = (struct asc_data *) extra; if (writeflag==MEM_READ) { memcpy(data, d->dma + relative_addr, len); #ifdef ASC_DEBUG { int i; debug("[ asc: read from DMA addr 0x%05x:", (int) relative_addr); for (i=0; idma + relative_addr, data, len); #ifdef ASC_DEBUG { int i; debug("[ asc: write to DMA addr 0x%05x:", (int) relative_addr); for (i=0; imode) { case DEV_ASC_DEC: regnr = relative_addr / 4; break; case DEV_ASC_PICA: default: regnr = relative_addr; } /* Controller's ID is fixed: */ d->reg_ro[NCR_CFG1] = (d->reg_ro[NCR_CFG1] & ~7) | ASC_SCSI_ID; d->reg_ro[NCR_FFLAG] = ((d->reg_ro[NCR_STEP] & 0x7) << 5) + d->n_bytes_in_fifo; d->dma_address_reg = d->dma_address_reg_memory[0] + (d->dma_address_reg_memory[1] << 8) + (d->dma_address_reg_memory[2] << 16) + (d->dma_address_reg_memory[3] << 24); if (regnr < 0x10) { if (regnr == NCR_FIFO) { if (writeflag == MEM_WRITE) dev_asc_fifo_write(d, idata); else odata = dev_asc_fifo_read(d); } else { if (writeflag==MEM_WRITE) d->reg_wo[regnr] = idata; else odata = d->reg_ro[regnr]; } #ifdef ASC_FULL_REGISTER_ACCESS_DEBUG if (!quiet_mode) { if (writeflag==MEM_READ) { debug("[ asc: read from %s: 0x%02x", asc_reg_names[regnr], (int)odata); } else { debug("[ asc: write to %s: 0x%02x", asc_reg_names[regnr], (int)idata); } } #endif } else if (relative_addr >= 0x300 && relative_addr < 0x600 && d->turbochannel != NULL) { debug("[ asc: offset 0x%x, redirecting to turbochannel" " access ]\n", relative_addr); return dev_turbochannel_access(cpu, mem, relative_addr, data, len, writeflag, d->turbochannel); } else { if (writeflag==MEM_READ) { fatal("[ asc: read from 0x%04x: 0x%02x ]\n", relative_addr, (int)odata); } else { fatal("[ asc: write to 0x%04x: 0x%02x ]\n", relative_addr, (int)idata); } } /* * Some registers are read/write. Copy contents of * reg_wo to reg_ro: */ #if 0 d->reg_ro[ 0] = d->reg_wo[0]; /* Transfer count lo and */ d->reg_ro[ 1] = d->reg_wo[1]; /* middle */ #endif d->reg_ro[ 2] = d->reg_wo[2]; d->reg_ro[ 3] = d->reg_wo[3]; d->reg_ro[ 8] = d->reg_wo[8]; d->reg_ro[ 9] = d->reg_wo[9]; d->reg_ro[10] = d->reg_wo[10]; d->reg_ro[11] = d->reg_wo[11]; d->reg_ro[12] = d->reg_wo[12]; if (regnr == NCR_CMD && writeflag == MEM_WRITE) { if (!quiet_mode) debug(" "); /* TODO: Perhaps turn off others here too? */ d->reg_ro[NCR_INTR] &= ~NCRINTR_SBR; if (idata & NCRCMD_DMA) { if (!quiet_mode) debug("[DMA] "); /* * DMA commands load the transfer count from the * write-only registers to the read-only ones, and * the Terminal Count bit is cleared. */ d->reg_ro[NCR_TCL] = d->reg_wo[NCR_TCL]; d->reg_ro[NCR_TCM] = d->reg_wo[NCR_TCM]; d->reg_ro[NCR_TCH] = d->reg_wo[NCR_TCH]; d->reg_ro[NCR_STAT] &= ~NCRSTAT_TC; } switch (idata & ~NCRCMD_DMA) { case NCRCMD_NOP: if (!quiet_mode) debug("NOP"); break; case NCRCMD_FLUSH: if (!quiet_mode) debug("FLUSH"); /* Flush the FIFO: */ dev_asc_fifo_flush(d); break; case NCRCMD_RSTCHIP: if (!quiet_mode) debug("RSTCHIP"); /* Hardware reset. */ dev_asc_reset(d); break; case NCRCMD_RSTSCSI: if (!quiet_mode) debug("RSTSCSI"); /* No interrupt if interrupts are disabled. */ if (!(d->reg_wo[NCR_CFG1] & NCRCFG1_SRR)) d->reg_ro[NCR_STAT] |= NCRSTAT_INT; d->reg_ro[NCR_INTR] |= NCRINTR_SBR; d->reg_ro[NCR_INTR] |= NCRINTR_FC; d->cur_state = STATE_DISCONNECTED; break; case NCRCMD_ENSEL: if (!quiet_mode) debug("ENSEL"); /* TODO */ break; case NCRCMD_ICCS: if (!quiet_mode) debug("ICCS"); /* Reveice a status byte + a message byte. */ /* TODO: how about other status and message bytes? */ if (d->xferp != NULL && d->xferp->status != NULL) dev_asc_fifo_write(d, d->xferp->status[0]); else dev_asc_fifo_write(d, 0x00); if (d->xferp != NULL && d->xferp->msg_in != NULL) dev_asc_fifo_write(d, d->xferp->msg_in[0]); else dev_asc_fifo_write(d, 0x00); d->reg_ro[NCR_STAT] |= NCRSTAT_INT; d->reg_ro[NCR_INTR] |= NCRINTR_FC; /* d->reg_ro[NCR_INTR] |= NCRINTR_BS; */ d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | 7; /* ? probably 7 */ d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4; /* ? */ break; case NCRCMD_MSGOK: /* Message is being Rejected if ATN is set, otherwise Accepted. */ if (!quiet_mode) { debug("MSGOK"); if (d->atn) debug("; Rejecting message"); else debug("; Accepting message"); } d->reg_ro[NCR_STAT] |= NCRSTAT_INT; d->reg_ro[NCR_INTR] |= NCRINTR_DIS; d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase; /* 6? */ d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4; /* ? */ d->cur_state = STATE_DISCONNECTED; if (d->xferp != NULL) scsi_transfer_free(d->xferp); d->xferp = NULL; break; case NCRCMD_SETATN: if (!quiet_mode) debug("SETATN"); d->atn = 1; break; case NCRCMD_RSTATN: if (!quiet_mode) debug("RSTATN"); d->atn = 0; break; case NCRCMD_SELNATN: case NCRCMD_SELATN: case NCRCMD_SELATNS: case NCRCMD_SELATN3: d->cur_phase = PHASE_COMMAND; switch (idata & ~NCRCMD_DMA) { case NCRCMD_SELATN: case NCRCMD_SELATNS: if ((idata & ~NCRCMD_DMA) == NCRCMD_SELATNS) { if (!quiet_mode) debug("SELATNS: select with " "atn and stop, id %i", d->reg_wo[NCR_SELID] & 7); d->cur_phase = PHASE_MSG_OUT; } else { if (!quiet_mode) debug("SELATN: select with atn" ", id %i", d->reg_wo[NCR_SELID] & 7); } n_messagebytes = 1; break; case NCRCMD_SELATN3: if (!quiet_mode) debug("SELNATN: select with atn3, " "id %i", d->reg_wo[NCR_SELID] & 7); n_messagebytes = 3; break; case NCRCMD_SELNATN: if (!quiet_mode) debug("SELNATN: select without atn, " "id %i", d->reg_wo[NCR_SELID] & 7); n_messagebytes = 0; } /* TODO: not just disk, but some generic SCSI device */ target_exists = diskimage_exist(cpu->machine, d->reg_wo[NCR_SELID] & 7, DISKIMAGE_SCSI); if (target_exists) { /* * Select a SCSI device, send message bytes * (if any) and command bytes to the target. */ int ok; dev_asc_newxfer(d); ok = dev_asc_select(cpu, d, d->reg_ro[NCR_CFG1] & 7, d->reg_wo[NCR_SELID] & 7, idata & NCRCMD_DMA? 1 : 0, n_messagebytes); if (ok) d->cur_state = STATE_INITIATOR; else { d->cur_state = STATE_DISCONNECTED; d->reg_ro[NCR_INTR] |= NCRINTR_DIS; d->reg_ro[NCR_STAT] |= NCRSTAT_INT; d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 0; if (d->xferp != NULL) scsi_transfer_free(d->xferp); d->xferp = NULL; } } else { /* * Selection failed, non-existant scsi ID: * * This is good enough to fool Ultrix, NetBSD, * OpenBSD and Linux to continue detection of * other IDs, without giving any warnings. */ d->reg_ro[NCR_STAT] |= NCRSTAT_INT; d->reg_ro[NCR_INTR] |= NCRINTR_DIS; d->reg_ro[NCR_STEP] &= ~7; d->reg_ro[NCR_STEP] |= 0; dev_asc_fifo_flush(d); d->cur_state = STATE_DISCONNECTED; } break; case NCRCMD_TRPAD: if (!quiet_mode) debug("TRPAD"); dev_asc_newxfer(d); { int ok; ok = dev_asc_transfer(cpu, d, idata & NCRCMD_DMA? 1 : 0); if (!ok) { d->cur_state = STATE_DISCONNECTED; d->reg_ro[NCR_INTR] |= NCRINTR_DIS; d->reg_ro[NCR_STAT] |= NCRSTAT_INT; d->reg_ro[NCR_STEP] = (d->reg_ro[ NCR_STEP] & ~7) | 0; if (d->xferp != NULL) scsi_transfer_free(d->xferp); d->xferp = NULL; } } break; /* Old code which didn't work with Mach: */ #if 0 d->reg_ro[NCR_STAT] |= NCRSTAT_INT; d->reg_ro[NCR_INTR] |= NCRINTR_BS; d->reg_ro[NCR_INTR] |= NCRINTR_FC; d->reg_ro[NCR_STAT] |= NCRSTAT_TC; d->reg_ro[NCR_TCL] = 0; d->reg_ro[NCR_TCM] = 0; d->reg_ro[NCR_STEP] &= ~7; #if 0 d->reg_ro[NCR_STEP] |= 0; dev_asc_fifo_flush(d); #else d->reg_ro[NCR_STEP] |= 4; #endif break; #endif case NCRCMD_TRANS: if (!quiet_mode) debug("TRANS"); { int ok; ok = dev_asc_transfer(cpu, d, idata & NCRCMD_DMA? 1 : 0); if (!ok) { d->cur_state = STATE_DISCONNECTED; d->reg_ro[NCR_INTR] |= NCRINTR_DIS; d->reg_ro[NCR_STAT] |= NCRSTAT_INT; d->reg_ro[NCR_STEP] = (d->reg_ro[ NCR_STEP] & ~7) | 0; if (d->xferp != NULL) scsi_transfer_free(d->xferp); d->xferp = NULL; } } break; default: fatal("(unimplemented asc cmd 0x%02x)", (int)idata); d->reg_ro[NCR_STAT] |= NCRSTAT_INT; d->reg_ro[NCR_INTR] |= NCRINTR_ILL; /* * TODO: exit or continue with Illegal command * interrupt? */ exit(1); } } if (regnr == NCR_INTR && writeflag == MEM_READ) { /* * Reading the interrupt register de-asserts the * interrupt pin. Also, INTR, STEP, and STAT are all * cleared, according to page 64 of the LSI53CF92A manual, * if "interrupt output is true". */ if (d->reg_ro[NCR_STAT] & NCRSTAT_INT) { d->reg_ro[NCR_INTR] = 0; d->reg_ro[NCR_STEP] = 0; d->reg_ro[NCR_STAT] = 0; /* For Mach/PMAX? TODO */ d->reg_ro[NCR_STAT] = PHASE_COMMAND; } INTERRUPT_DEASSERT(d->irq); d->irq_asserted = 0; } if (regnr == NCR_CFG1) { /* TODO: other bits */ if (!quiet_mode) { debug(" parity %s,", d->reg_ro[regnr] & NCRCFG1_PARENB? "enabled" : "disabled"); debug(" scsi_id %i", d->reg_ro[regnr] & 0x7); } } #ifdef ASC_FULL_REGISTER_ACCESS_DEBUG debug(" ]\n"); #endif dev_asc_tick(cpu, extra); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_asc_init(): * * Register an 'asc' device. */ void dev_asc_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, const char *irq_path, void *turbochannel, int mode, size_t (*dma_controller)(void *dma_controller_data, unsigned char *data, size_t len, int writeflag), void *dma_controller_data) { struct asc_data *d; CHECK_ALLOCATION(d = (struct asc_data *) malloc(sizeof(struct asc_data))); memset(d, 0, sizeof(struct asc_data)); INTERRUPT_CONNECT(irq_path, d->irq); d->turbochannel = turbochannel; d->mode = mode; d->reg_ro[NCR_CFG3] = NCRF9XCFG3_CDB; CHECK_ALLOCATION(d->dma_address_reg_memory = (unsigned char *) malloc(machine->arch_pagesize)); memset(d->dma_address_reg_memory, 0, machine->arch_pagesize); CHECK_ALLOCATION(d->dma = (unsigned char *) malloc(ASC_DMA_SIZE)); memset(d->dma, 0, ASC_DMA_SIZE); d->dma_controller = dma_controller; d->dma_controller_data = dma_controller_data; memory_device_register(mem, "asc", baseaddr, mode == DEV_ASC_PICA? DEV_ASC_PICA_LENGTH : DEV_ASC_DEC_LENGTH, dev_asc_access, d, DM_DEFAULT, NULL); if (mode == DEV_ASC_DEC) { memory_device_register(mem, "asc_dma_address_reg", baseaddr + 0x40000, 4096, dev_asc_address_reg_access, d, DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK, (unsigned char *)&d->dma_address_reg_memory[0]); memory_device_register(mem, "asc_dma", baseaddr + 0x80000, ASC_DMA_SIZE, dev_asc_dma_access, d, DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK, d->dma); } machine_add_tickfunction(machine, dev_asc_tick, d, ASC_TICK_SHIFT); } gxemul-0.6.1/src/devices/dev_sii.cc000644 001750 001750 00000031057 13402411502 017375 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SII SCSI controller, used in some DECstation systems * * TODO: This is huge and ugly. Fix this. */ #include #include #include #include "cpu.h" #include "devices.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/siireg.h" #define SII_TICK_SHIFT 14 struct sii_data { struct interrupt irq; uint64_t buf_start; uint64_t buf_end; int connected; int connected_to_id; int register_choice; SIIRegs siiregs; uint16_t *regs; }; /* * combine_sii_bits(): * * Combines some bits of CSTAT and DSTAT that are connected. */ void combine_sii_bits(struct sii_data *d) { int ci, di; di = ((d->siiregs.dstat & SII_MIS) | (d->siiregs.dstat & SII_IBF) | (d->siiregs.dstat & SII_TBE) | (d->siiregs.dstat & SII_DNE))==0? 0 : SII_DI; ci = ((d->siiregs.cstat & SII_RST) | (d->siiregs.cstat & SII_BER) | (d->siiregs.cstat & SII_OBC) | (d->siiregs.cstat & SII_BUF) | (d->siiregs.cstat & SII_LDN) | (d->siiregs.cstat & SII_SCH))==0? 0 : SII_CI; d->siiregs.cstat &= ~(SII_CI | SII_DI); d->siiregs.dstat &= ~(SII_CI | SII_DI); d->siiregs.cstat |= (ci | di); d->siiregs.dstat |= (ci | di); } DEVICE_TICK(sii) { struct sii_data *d = (struct sii_data *) extra; /* ? */ d->siiregs.dstat = (d->siiregs.dstat & ~0x7) | ((d->siiregs.dstat + 1) & 0x7); /* SCSI Commands: */ if (d->siiregs.comm & SII_CHRESET) { /* (I,T,D) */ /* debug("[ sii: command TODO: CHRESET ]\n"); */ } if (d->siiregs.comm & SII_DISCON) { /* (I,T,D) */ /* debug("[ sii: command TODO: DISCON ]\n"); */ d->siiregs.cstat &= ~SII_CON; /* Connected */ if (d->connected) { d->siiregs.cstat |= SII_SCH; /* State change */ d->connected = 0; } d->siiregs.cstat &= ~SII_SIP; /* Selection in progress */ d->siiregs.comm &= ~SII_DISCON; } if (d->siiregs.comm & SII_REQDATA) { /* (T) */ /* debug("[ sii: command TODO: REQDATA ]\n"); */ } if (d->siiregs.comm & SII_SELECT) { /* (D) */ /* debug("[ sii: command SELECT ]\n"); */ d->siiregs.comm &= ~SII_SELECT; /* slcsr contains the other target's id */ d->siiregs.cstat |= SII_SIP; /* Selection in progress */ d->connected = 0; d->connected_to_id = 0; /* Is the target available for selection? TODO: make this nicer */ #if 0 if ((d->siiregs.slcsr & 7) == 0) { d->siiregs.cstat |= SII_CON; /* Connected */ d->siiregs.cstat |= SII_SCH; /* State change */ d->siiregs.cstat &= ~SII_SIP; /* Sel. in progress */ d->connected = 1; d->connected_to_id = 0; } #endif } if (d->siiregs.comm & SII_INXFER && (d->siiregs.comm & 0x70) == (d->siiregs.cstat & 0x70) && (d->siiregs.comm & 0x03) == (d->siiregs.dstat & 0x03) && !(d->siiregs.cstat & SII_SIP)) { /* (I,T) */ debug("[ sii: command INXFER to scsiid=%i ]\n", d->siiregs.slcsr); if (d->siiregs.comm & SII_DMA) debug("[ sii DMA: TODO ]\n"); else { debug("[ sii: transmitting byte 0x%02x using " "PIO mode ]\n", d->siiregs.data); d->siiregs.comm &= ~SII_INXFER; /* d->siiregs.dstat |= SII_DNE; */ /* Done, only for DMA? */ d->siiregs.dstat |= SII_TBE; /* Buffer empty? */ } } combine_sii_bits(d); if (d->siiregs.csr & SII_IE && d->siiregs.cstat & (SII_CI | SII_DI)) INTERRUPT_ASSERT(d->irq); else INTERRUPT_DEASSERT(d->irq); } DEVICE_ACCESS(sii) { uint64_t idata = 0, odata = 0; int regnr; struct sii_data *d = (struct sii_data *) extra; if (relative_addr & 3) { debug("[ sii relative_addr = 0x%x !!! ]\n", (int) relative_addr); return 0; } dev_sii_tick(cpu, extra); if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); regnr = relative_addr / 2; odata = d->regs[regnr]; switch (relative_addr) { case 0x00: /* SII_SDB: Diagnostic */ if (writeflag == MEM_READ) { debug("[ sii: read from SDB (data=0x%04x) ]\n", d->regs[regnr]); } else { debug("[ sii: write to SDB (data=0x%04x) ]\n", (int)idata); d->regs[regnr] = idata; return 1; } break; case 0x0c: /* SII_CSR: Control/status */ if (writeflag == MEM_READ) { debug("[ sii: read from CSR (data=0x%04x) ]\n", d->regs[regnr]); } else { debug("[ sii: write to CSR (data=0x%04x: %s %s " "%s %s %s) ]\n", (int)idata, idata & SII_HPM? "HPM" : "!hpm", idata & SII_RSE? "RSE" : "!rse", idata & SII_SLE? "SLE" : "!sle", idata & SII_PCE? "PCE" : "!pce", idata & SII_IE? "IE" : "!ie"); d->regs[regnr] = idata; return 1; } break; case 0x10: /* SII_ID: SCSI ID */ if (writeflag == MEM_READ) { debug("[ sii: read from ID (data=0x%04x) ]\n", d->regs[regnr]); } else { debug("[ sii: write to ID (data=0x%04x: scsi id %i)" " ]\n", (int)idata, (int)(idata & 7)); if (!(idata & SII_ID_IO)) debug("WARNING: sii ID bit SII_ID_IO not " "set on write!\n"); idata &= ~SII_ID_IO; if ((idata & ~0x7) != 0) debug("WARNING: sii ID bits that should " "be zero are not zero!\n"); idata &= 0x7; d->regs[regnr] = idata & 0x7; return 1; } break; case 0x14: /* SII_SLCSR: Selector control */ if (writeflag == MEM_READ) { debug("[ sii: read from SLCSR (data=0x%04x: " "scsi_id=%i) ]\n", d->regs[regnr], d->regs[regnr] & 7); } else { debug("[ sii: write to SLCSR (data=0x%04x: " "scsi_id=%i) ]\n", (int)idata, (int)(idata & 7)); if ((idata & ~0x7) != 0) debug("WARNING: sii SLCSR bits that should " "be zero are not zero!\n"); idata &= 0x7; d->regs[regnr] = idata & 0x7; return 1; } break; case 0x18: /* SII_DESTAT: Selection detector status */ if (writeflag == MEM_READ) { /* TODO: set DESTAT from somewhere else? */ debug("[ sii: read from DESTAT (data=0x%04x: " "scsi_id=%i) ]\n", d->regs[regnr], d->regs[regnr] & 7); } else { debug("[ sii: write to DESTAT (data=0x%04x: " "scsi_id=%i) ]\n", (int)idata, (int)(idata & 7)); debug("WARNING: sii DESTAT is read-only!\n"); return 1; } break; case 0x20: /* SII_DATA: Data register */ if (writeflag == MEM_READ) { /* TODO */ debug("[ sii: read from DATA (data=0x%04x) ]\n", d->regs[regnr]); } else { /* TODO */ debug("[ sii: write to DATA (data=0x%04x) ]\n", (int)idata); idata &= 0xff; d->regs[regnr] = idata; return 1; } break; case 0x24: /* SII_DMCTRL: DMA control */ if (writeflag == MEM_READ) { debug("[ sii: read from DMCTRL (data=0x%04x) ]\n", d->regs[regnr]); } else { debug("[ sii: write to DMCTRL (data=0x%04x: %s) ]\n", (int)idata, (idata & 3)==0? "async" : "sync"); if ((idata & ~0x3) != 0) debug("WARNING: sii DMCTRL bits that " "should be zero are not zero!\n"); idata &= 0x3; d->regs[regnr] = idata; return 1; } break; case 0x48: /* SII_CSTAT: Connection status */ if (writeflag == MEM_READ) { debug("[ sii: read from CSTAT (data=0x%04x) ]\n", d->regs[regnr]); } else { debug("[ sii: write to CSTAT (data=0x%04x) ]\n", (int)idata); /* readonly / writeoncetoclear bits according to page 21 in the DS3100 manual: */ if (idata & (1<<13)) { idata &= ~(1<<13); d->regs[regnr] &= ~(1<<13); } if (idata & (1<<12)) { idata &= ~(1<<12); d->regs[regnr] &= ~(1<<12); } if (idata & (1<<11)) { /* is this actually write-1-to-clear? */ idata &= ~(1<<11); d->regs[regnr] &= ~(1<<11); } if (idata & (1<<9)) { /* ? */ idata &= ~(1<<9); d->regs[regnr] &= ~(1<<9); } if (idata & (1<<8)) { /* ? */ idata &= ~(1<<8); d->regs[regnr] &= ~(1<<8); } if (idata & (1<<7)) { idata &= ~(1<<7); d->regs[regnr] &= ~(1<<7); } if (idata & (1<<3)) { idata &= ~(1<<3); d->regs[regnr] &= ~(1<<3); } /* Read-only bits are taken from the old register: */ idata &= ~0x3bf7; idata |= d->regs[regnr] & 0x3bf7; d->regs[regnr] = idata; return 1; } break; case 0x4c: /* SII_DSTAT: Data transfer status */ if (writeflag == MEM_READ) { debug("[ sii: read from DSTAT (data=0x%04x) ]\n", d->regs[regnr]); } else { debug("[ sii: write to DSTAT (data=0x%04x) ]\n", (int)idata); /* readonly / writeoncetoclear bits according to page 22 in the DS3100 manual: */ if (idata & (1<<13)) { idata &= ~(1<<13); d->regs[regnr] &= ~(1<<13); } if (idata & (1<<11)) { /* is this write-1-to-clear? */ idata &= ~(1<<11); d->regs[regnr] &= ~(1<<11); } if (idata & (1<<10)) { /* is this write-1-to-clear? */ idata &= ~(1<<10); d->regs[regnr] &= ~(1<<10); } if (idata & (1<<4)) { /* is this write-1-to-clear? */ idata &= ~(1<<4); d->regs[regnr] &= ~(1<<4); } if (idata & (1<<3)) { idata &= ~(1<<3); d->regs[regnr] &= ~(1<<3); } /* Read-only bits are taken from the old register: */ idata &= ~0x0c17; idata |= d->regs[regnr] & 0x0c17; d->regs[regnr] = idata; return 1; } break; case 0x50: /* SII_COMM: Command */ if (writeflag == MEM_READ) { debug("[ sii: read from COMM (data=0x%04x) ]\n", d->regs[regnr]); } else { debug("[ sii: write to COMM (data=0x%04x: %s %s " "%s command=0x%02x rest=0x%02x) ]\n", (int)idata, idata & SII_DMA? "DMA" : "!dma", idata & SII_DO_RST? "RST" : "!rst", idata & SII_RSL? "RSL" : "!rsl", /* command, 5 bits: */ (int)((idata >> 7) & 0x1f), /* rest, 7 bits: */ (int)(idata & 0x3f)); if (idata & SII_DO_RST) { /* Reset: TODO */ } idata &= ~SII_DO_RST; d->regs[regnr] = idata; dev_sii_tick(cpu, extra); return 1; } break; case 0x54: /* SII_DICTRL: Diagnostics control */ if (writeflag == MEM_READ) { debug("[ sii: read from DICTRL (data=0x%04x) ]\n", d->regs[regnr]); } else { debug("[ sii: write to DICTRL (data=0x%04x: " "port=%s) ]\n", (int)idata, idata & SII_PRE? "enabled" : "disabled"); if ((idata & ~0xf) != 0) debug("WARNING: sii DICTRL bits that " "should be zero are not zero!\n"); d->regs[regnr] = idata; return 1; } break; default: if (writeflag==MEM_READ) { debug("[ sii: read from %08lx (data=0x%04x) ]\n", (long)relative_addr, d->regs[regnr]); } else { debug("[ sii: write to %08lx (data=0x%04x) ]\n", (long)relative_addr, (int)idata); d->regs[regnr] = idata; } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } void dev_sii_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, uint64_t buf_start, uint64_t buf_end, char *irq_path) { struct sii_data *d; CHECK_ALLOCATION(d = (struct sii_data *) malloc(sizeof(struct sii_data))); memset(d, 0, sizeof(struct sii_data)); INTERRUPT_CONNECT(irq_path, d->irq); d->buf_start = buf_start; d->buf_end = buf_end; d->regs = (uint16_t *) &d->siiregs; memory_device_register(mem, "sii", baseaddr, DEV_SII_LENGTH, dev_sii_access, (void *)d, DM_DEFAULT, NULL); machine_add_tickfunction(machine, dev_sii_tick, d, SII_TICK_SHIFT); } gxemul-0.6.1/src/devices/dev_footbridge.cc000644 001750 001750 00000037013 13402411502 020733 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: DC21285 "Footbridge" controller; used in Netwinder and Cats * * TODO: * o) Add actual support for the fcom serial port. * o) FIQs. * o) Pretty much everything else as well :) (This entire thing * is a quick hack to work primarily with NetBSD and OpenBSD * as guest OSes.) */ #include #include #include #include "bus_pci.h" #include "console.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "timer.h" #include "thirdparty/dc21285reg.h" #define DEV_FOOTBRIDGE_TICK_SHIFT 14 #define DEV_FOOTBRIDGE_LENGTH 0x400 #define N_FOOTBRIDGE_TIMERS 4 struct footbridge_data { struct interrupt irq; struct pci_data *pcibus; int console_handle; uint32_t timer_load[N_FOOTBRIDGE_TIMERS]; uint32_t timer_value[N_FOOTBRIDGE_TIMERS]; uint32_t timer_control[N_FOOTBRIDGE_TIMERS]; struct interrupt timer_irq[N_FOOTBRIDGE_TIMERS]; struct timer *timer[N_FOOTBRIDGE_TIMERS]; int pending_timer_interrupts[N_FOOTBRIDGE_TIMERS]; int irq_asserted; uint32_t irq_status; uint32_t irq_enable; uint32_t fiq_status; uint32_t fiq_enable; }; static void timer_tick0(struct timer *t, void *extra) { ((struct footbridge_data *)extra)->pending_timer_interrupts[0] ++; } static void timer_tick1(struct timer *t, void *extra) { ((struct footbridge_data *)extra)->pending_timer_interrupts[1] ++; } static void timer_tick2(struct timer *t, void *extra) { ((struct footbridge_data *)extra)->pending_timer_interrupts[2] ++; } static void timer_tick3(struct timer *t, void *extra) { ((struct footbridge_data *)extra)->pending_timer_interrupts[3] ++; } static void reload_timer_value(struct cpu *cpu, struct footbridge_data *d, int timer_nr) { double freq = (double)cpu->machine->emulated_hz; int cycles = d->timer_load[timer_nr]; if (d->timer_control[timer_nr] & TIMER_FCLK_16) cycles <<= 4; else if (d->timer_control[timer_nr] & TIMER_FCLK_256) cycles <<= 8; freq /= (double)cycles; d->timer_value[timer_nr] = d->timer_load[timer_nr]; /* printf("%i: %i -> %f Hz\n", timer_nr, d->timer_load[timer_nr], freq); */ if (d->timer[timer_nr] == NULL) { switch (timer_nr) { case 0: d->timer[0] = timer_add(freq, timer_tick0, d); break; case 1: d->timer[1] = timer_add(freq, timer_tick1, d); break; case 2: d->timer[2] = timer_add(freq, timer_tick2, d); break; case 3: d->timer[3] = timer_add(freq, timer_tick3, d); break; } } else { timer_update_frequency(d->timer[timer_nr], freq); } } /* * The 4 footbridge timers should decrease and cause interrupts. Periodic * interrupts restart as soon as they are acknowledged, non-periodic * interrupts need to be "reloaded" to restart. * * TODO: Hm. I thought I had solved this, but it didn't quite work. * This needs to be re-checked against documentation, sometime. */ DEVICE_TICK(footbridge) { struct footbridge_data *d = (struct footbridge_data *) extra; int i; for (i=0; itimer_control[i] & TIMER_ENABLE) { if (d->pending_timer_interrupts[i] > 0) { d->timer_value[i] = random() % d->timer_load[i]; INTERRUPT_ASSERT(d->timer_irq[i]); } } } } /* * footbridge_interrupt_assert(): */ void footbridge_interrupt_assert(struct interrupt *interrupt) { struct footbridge_data *d = (struct footbridge_data *) interrupt->extra; d->irq_status |= interrupt->line; if ((d->irq_status & d->irq_enable) && !d->irq_asserted) { d->irq_asserted = 1; INTERRUPT_ASSERT(d->irq); } } /* * footbridge_interrupt_deassert(): */ void footbridge_interrupt_deassert(struct interrupt *interrupt) { struct footbridge_data *d = (struct footbridge_data *) interrupt->extra; d->irq_status &= ~interrupt->line; if (!(d->irq_status & d->irq_enable) && d->irq_asserted) { d->irq_asserted = 0; INTERRUPT_DEASSERT(d->irq); } } /* * Reading the byte at 0x79000000 is a quicker way to figure out which ISA * interrupt has occurred (and acknowledging it at the same time), than * dealing with the legacy 0x20/0xa0 ISA ports. */ DEVICE_ACCESS(footbridge_isa) { /* struct footbridge_data *d = extra; */ uint64_t idata = 0, odata = 0; int x; if (writeflag == MEM_WRITE) { idata = memory_readmax64(cpu, data, len); fatal("[ footbridge_isa: WARNING/TODO: write! ]\n"); } x = cpu->machine->isa_pic_data.last_int; if (x < 8) odata = cpu->machine->isa_pic_data.pic1->irq_base + x; else odata = cpu->machine->isa_pic_data.pic2->irq_base + x - 8; if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * Reset pin at ISA port 0x338, at least in the NetWinder: * * TODO: NOT WORKING YET! */ DEVICE_ACCESS(footbridge_reset) { uint64_t idata = 0; if (writeflag == MEM_WRITE) { idata = memory_readmax64(cpu, data, len); if (idata & 0x40) { debug("[ footbridge_reset: GP16: Halting. ]\n"); cpu->running = 0; exit(1); } } return 1; } /* * The Footbridge PCI configuration space is implemented as a direct memory * space (i.e. not one port for addr and one port for data). This function * translates that into bus_pci calls. */ DEVICE_ACCESS(footbridge_pci) { struct footbridge_data *d = (struct footbridge_data *) extra; uint64_t idata = 0, odata = 0; int bus, dev, func, reg; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN); /* Decompose the (direct) address into its components: */ bus_pci_decompose_1(relative_addr, &bus, &dev, &func, ®); bus_pci_setaddr(cpu, d->pcibus, bus, dev, func, reg); if (bus == 255) { fatal("[ footbridge DEBUG ERROR: bus 255 unlikely," " pc (might not be updated) = 0x%08x ]\n", (int)cpu->pc); exit(1); } debug("[ footbridge pci: %s bus %i, device %i, function %i, register " "%i ]\n", writeflag == MEM_READ? "read from" : "write to", bus, dev, func, reg); bus_pci_data_access(cpu, d->pcibus, writeflag == MEM_READ? &odata : &idata, len, writeflag); if (writeflag == MEM_READ) memory_writemax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN, odata); return 1; } DEVICE_ACCESS(footbridge) { struct footbridge_data *d = (struct footbridge_data *) extra; uint64_t idata = 0, odata = 0; int timer_nr = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (relative_addr >= TIMER_1_LOAD && relative_addr <= TIMER_4_CLEAR) { timer_nr = (relative_addr >> 5) & (N_FOOTBRIDGE_TIMERS - 1); relative_addr &= ~0x060; } switch (relative_addr) { case VENDOR_ID: odata = 0x1011; /* DC21285_VENDOR_ID */ break; case DEVICE_ID: odata = 0x1065; /* DC21285_DEVICE_ID */ break; case 0x04: case 0x0c: case 0x10: case 0x14: case 0x18: /* TODO. Written to by Linux. */ break; case REVISION: odata = 3; /* footbridge revision number */ break; case PCI_ADDRESS_EXTENSION: /* TODO: Written to by Linux. */ if (writeflag == MEM_WRITE && idata != 0) fatal("[ footbridge: TODO: write to PCI_ADDRESS_" "EXTENSION: 0x%llx ]\n", (long long)idata); break; case SA_CONTROL: /* Read by Linux: */ odata = PCI_CENTRAL_FUNCTION; break; case UART_DATA: if (writeflag == MEM_WRITE) console_putchar(d->console_handle, idata); break; case UART_RX_STAT: /* TODO */ odata = 0; break; case UART_FLAGS: odata = UART_TX_EMPTY; break; case IRQ_STATUS: if (writeflag == MEM_READ) odata = d->irq_status & d->irq_enable; else { fatal("[ WARNING: footbridge write to irq status? ]\n"); exit(1); } break; case IRQ_RAW_STATUS: if (writeflag == MEM_READ) odata = d->irq_status; else { fatal("[ footbridge write to irq_raw_status ]\n"); exit(1); } break; case IRQ_ENABLE_SET: if (writeflag == MEM_WRITE) { d->irq_enable |= idata; if (d->irq_status & d->irq_enable) INTERRUPT_ASSERT(d->irq); else INTERRUPT_DEASSERT(d->irq); } else { odata = d->irq_enable; fatal("[ WARNING: footbridge read from " "ENABLE SET? ]\n"); exit(1); } break; case IRQ_ENABLE_CLEAR: if (writeflag == MEM_WRITE) { d->irq_enable &= ~idata; if (d->irq_status & d->irq_enable) INTERRUPT_ASSERT(d->irq); else INTERRUPT_DEASSERT(d->irq); } else { odata = d->irq_enable; fatal("[ WARNING: footbridge read from " "ENABLE CLEAR? ]\n"); exit(1); } break; case FIQ_STATUS: if (writeflag == MEM_READ) odata = d->fiq_status & d->fiq_enable; else { fatal("[ WARNING: footbridge write to fiq status? ]\n"); exit(1); } break; case FIQ_RAW_STATUS: if (writeflag == MEM_READ) odata = d->fiq_status; else { fatal("[ footbridge write to fiq_raw_status ]\n"); exit(1); } break; case FIQ_ENABLE_SET: if (writeflag == MEM_WRITE) d->fiq_enable |= idata; break; case FIQ_ENABLE_CLEAR: if (writeflag == MEM_WRITE) d->fiq_enable &= ~idata; break; case TIMER_1_LOAD: if (writeflag == MEM_READ) odata = d->timer_load[timer_nr]; else { d->timer_load[timer_nr] = idata & TIMER_MAX_VAL; reload_timer_value(cpu, d, timer_nr); /* debug("[ footbridge: timer %i (1-based), " "value %i ]\n", timer_nr + 1, (int)d->timer_value[timer_nr]); */ INTERRUPT_DEASSERT(d->timer_irq[timer_nr]); } break; case TIMER_1_VALUE: if (writeflag == MEM_READ) odata = d->timer_value[timer_nr]; else d->timer_value[timer_nr] = idata & TIMER_MAX_VAL; break; case TIMER_1_CONTROL: if (writeflag == MEM_READ) odata = d->timer_control[timer_nr]; else { d->timer_control[timer_nr] = idata; if (idata & TIMER_FCLK_16 && idata & TIMER_FCLK_256) { fatal("TODO: footbridge timer: " "both 16 and 256?\n"); exit(1); } if (idata & TIMER_ENABLE) { reload_timer_value(cpu, d, timer_nr); } else { d->pending_timer_interrupts[timer_nr] = 0; } INTERRUPT_DEASSERT(d->timer_irq[timer_nr]); } break; case TIMER_1_CLEAR: if (d->timer_control[timer_nr] & TIMER_MODE_PERIODIC) { reload_timer_value(cpu, d, timer_nr); } if (d->pending_timer_interrupts[timer_nr] > 0) { d->pending_timer_interrupts[timer_nr] --; } INTERRUPT_DEASSERT(d->timer_irq[timer_nr]); break; default:if (writeflag == MEM_READ) { fatal("[ footbridge: read from 0x%x ]\n", (int)relative_addr); } else { fatal("[ footbridge: write to 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(footbridge) { struct footbridge_data *d; char irq_path[300], irq_path_isa[400]; uint64_t pci_addr = 0x7b000000; int i; CHECK_ALLOCATION(d = (struct footbridge_data *) malloc(sizeof(struct footbridge_data))); memset(d, 0, sizeof(struct footbridge_data)); /* Connect to the CPU which this footbridge will interrupt: */ INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); /* DC21285 register access: */ memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_FOOTBRIDGE_LENGTH, dev_footbridge_access, d, DM_DEFAULT, NULL); /* ISA interrupt status/acknowledgement: */ memory_device_register(devinit->machine->memory, "footbridge_isa", 0x79000000, 8, dev_footbridge_isa_access, d, DM_DEFAULT, NULL); /* The "fcom" console: */ d->console_handle = console_start_slave(devinit->machine, "fcom", 0); /* Register 32 footbridge interrupts: */ snprintf(irq_path, sizeof(irq_path), "%s.footbridge", devinit->interrupt_path); for (i=0; i<32; i++) { struct interrupt interrupt_template; char tmpstr[600]; memset(&interrupt_template, 0, sizeof(interrupt_template)); interrupt_template.line = 1 << i; snprintf(tmpstr, sizeof(tmpstr), "%s.%i", irq_path, i); interrupt_template.name = tmpstr; interrupt_template.extra = d; interrupt_template.interrupt_assert = footbridge_interrupt_assert; interrupt_template.interrupt_deassert = footbridge_interrupt_deassert; interrupt_handler_register(&interrupt_template); /* Connect locally to some interrupts: */ if (i>=IRQ_TIMER_1 && i<=IRQ_TIMER_4) INTERRUPT_CONNECT(tmpstr, d->timer_irq[i-IRQ_TIMER_1]); } switch (devinit->machine->machine_type) { case MACHINE_CATS: snprintf(irq_path_isa, sizeof(irq_path_isa), "%s.10", irq_path); break; case MACHINE_NETWINDER: snprintf(irq_path_isa, sizeof(irq_path_isa), "%s.11", irq_path); break; default:fatal("footbridge unimpl machine type\n"); exit(1); } /* A PCI bus: */ d->pcibus = bus_pci_init( devinit->machine, irq_path, 0x7c000000, /* PCI device io offset */ 0x80000000, /* PCI device mem offset */ 0x00000000, /* PCI port base */ 0x00000000, /* PCI mem base */ irq_path, /* PCI irq base */ 0x7c000000, /* ISA port base */ 0x80000000, /* ISA mem base */ irq_path_isa); /* ISA port base */ /* ... with some default devices for known machine types: */ switch (devinit->machine->machine_type) { case MACHINE_CATS: bus_pci_add(devinit->machine, d->pcibus, devinit->machine->memory, 0xc0, 7, 0, "ali_m1543"); bus_pci_add(devinit->machine, d->pcibus, devinit->machine->memory, 0xc0, 10, 0, "dec21143"); bus_pci_add(devinit->machine, d->pcibus, devinit->machine->memory, 0xc0, 16, 0, "ali_m5229"); break; case MACHINE_NETWINDER: bus_pci_add(devinit->machine, d->pcibus, devinit->machine->memory, 0xc0, 11, 0, "symphony_83c553"); bus_pci_add(devinit->machine, d->pcibus, devinit->machine->memory, 0xc0, 11, 1, "symphony_82c105"); memory_device_register(devinit->machine->memory, "footbridge_reset", 0x7c000338, 1, dev_footbridge_reset_access, d, DM_DEFAULT, NULL); break; default:fatal("footbridge: unimplemented machine type.\n"); exit(1); } /* PCI configuration space: */ memory_device_register(devinit->machine->memory, "footbridge_pci", pci_addr, 0x1000000, dev_footbridge_pci_access, d, DM_DEFAULT, NULL); /* Timer ticks: */ for (i=0; itimer_control[i] = TIMER_MODE_PERIODIC; d->timer_load[i] = TIMER_MAX_VAL; } machine_add_tickfunction(devinit->machine, dev_footbridge_tick, d, DEV_FOOTBRIDGE_TICK_SHIFT); devinit->return_ptr = d->pcibus; return 1; } gxemul-0.6.1/src/devices/dev_mk48txx.cc000644 001750 001750 00000010271 13402411502 020133 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Mostek MK48Txx Real Time Clock * * TODO: * Only the MK48T08 is implemented so far. */ #include #include #include #include #include "cpu.h" #include "device.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/mk48txxreg.h" #define MK48TXX_LEN MK48T08_CLKSZ #define BCD(x) ((((x) / 10) << 4) + ((x) % 10)) struct mk48txx_data { uint8_t reg[MK48TXX_LEN]; }; void mk48txx_update_regs(struct mk48txx_data *d) { struct tm *tmp; time_t timet; timet = time(NULL); tmp = gmtime(&timet); d->reg[MK48T08_CLKOFF + MK48TXX_ISEC] = BCD(tmp->tm_sec); d->reg[MK48T08_CLKOFF + MK48TXX_IMIN] = BCD(tmp->tm_min); d->reg[MK48T08_CLKOFF + MK48TXX_IHOUR] = BCD(tmp->tm_hour); d->reg[MK48T08_CLKOFF + MK48TXX_IWDAY] = tmp->tm_wday + 1; d->reg[MK48T08_CLKOFF + MK48TXX_IDAY] = BCD(tmp->tm_mday); d->reg[MK48T08_CLKOFF + MK48TXX_IMON] = BCD(tmp->tm_mon + 1); d->reg[MK48T08_CLKOFF + MK48TXX_IYEAR] = BCD(tmp->tm_year % 100); } DEVICE_ACCESS(mk48txx) { struct mk48txx_data *d = (struct mk48txx_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (writeflag == MEM_READ) odata = d->reg[relative_addr]; if (relative_addr < MK48T08_CLKOFF || relative_addr >= MK48T08_CLKOFF + MK48TXX_ISEC) { /* Reads and writes to the RAM part of the mk48txx, or the clock registers, are OK: */ if (writeflag == MEM_WRITE) d->reg[relative_addr] = idata; goto ret; } switch (relative_addr) { case MK48T08_CLKOFF + MK48TXX_ICSR: if (writeflag == MEM_WRITE) { if ((idata & MK48TXX_CSR_READ) && !(d->reg[relative_addr] & MK48TXX_CSR_READ)) { /* Switching the read bit from 0 to 1 causes registers to be "froozen". In the emulator, simply updating them with data from the host should be good enough. */ mk48txx_update_regs(d); } d->reg[relative_addr] = idata; } break; default:if (writeflag == MEM_READ) fatal("[ mk48txx: unimplemented READ from offset 0x%x ]" "\n", (int)relative_addr); else fatal("[ mk48txx: unimplemented WRITE to offset 0x%x: " "0x%x ]\n", (int)relative_addr, (int)idata); exit(1); } ret: if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(mk48txx) { struct mk48txx_data *d; CHECK_ALLOCATION(d = (struct mk48txx_data *) malloc(sizeof(struct mk48txx_data))); memset(d, 0, sizeof(struct mk48txx_data)); mk48txx_update_regs(d); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, MK48TXX_LEN, dev_mk48txx_access, (void *)d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_vme.cc000644 001750 001750 00000010761 13402411502 017377 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: VME bus * * TODO: Probably almost everything. */ #include #include #include #include "cpu.h" #include "device.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/mvme88k_vme.h" /* #define debug fatal */ #define VME_LEN 0x1000 struct vme_data { uint32_t reg[VME_LEN / sizeof(uint32_t)]; }; DEVICE_ACCESS(vme) { struct vme_data *d = (struct vme_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (writeflag == MEM_READ) odata = d->reg[relative_addr / sizeof(uint32_t)]; switch (relative_addr) { case 0: /* Used by OpenBSD/mvme88k when probing... */ break; case VME2_GCSRCTL: debug("[ vme: unimplemented GCSRCTL ]\n"); break; case VME2_TCR: if (writeflag == MEM_READ) debug("[ vme: unimplemented READ from TCR ]\n"); else debug("[ vme: unimplemented WRITE to TCR: " "0x%x ]\n", (int)idata); break; case VME2_T1CMP: if (writeflag == MEM_WRITE) d->reg[relative_addr / sizeof(uint32_t)] = idata; break; case VME2_T1COUNT: if (writeflag == MEM_WRITE) d->reg[relative_addr / sizeof(uint32_t)] = idata; else { /* NOTE! This is a quick hack. TODO: Fix! */ d->reg[relative_addr / sizeof(uint32_t)] += 100; } break; case VME2_TCTL: if (writeflag == MEM_WRITE) d->reg[relative_addr / sizeof(uint32_t)] = idata; /* TODO */ /* debug("[ vme: unimplemented TCTL ]\n"); */ break; case VME2_IRQEN: if (writeflag == MEM_READ) debug("[ vme: unimplemented READ from IRQEN ]\n"); else debug("[ vme: unimplemented WRITE to IRQEN: " "0x%x ]\n", (int)idata); break; case VME2_IRQL3: if (writeflag == MEM_READ) debug("[ vme: unimplemented READ from IRQL3 ]\n"); else debug("[ vme: unimplemented WRITE to IRQL3: " "0x%x ]\n", (int)idata); break; case VME2_IRQL4: if (writeflag == MEM_READ) debug("[ vme: unimplemented READ from IRQL4 ]\n"); else debug("[ vme: unimplemented WRITE to IRQL4: " "0x%x ]\n", (int)idata); break; case VME2_VBR: /* Vector Base Register. */ if (writeflag == MEM_WRITE) d->reg[relative_addr / sizeof(uint32_t)] = idata; break; default:if (writeflag == MEM_READ) debug("[ vme: unimplemented READ from offset 0x%x ]" "\n", (int)relative_addr); else debug("[ vme: unimplemented WRITE to offset 0x%x: " "0x%x ]\n", (int)relative_addr, (int)idata); exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(vme) { struct vme_data *d; CHECK_ALLOCATION(d = (struct vme_data *) malloc(sizeof(struct vme_data))); memset(d, 0, sizeof(struct vme_data)); /* According to OpenBSD/mvme88k: */ d->reg[VME2_VBR / sizeof(uint32_t)] = VME2_SET_VBR0(6) + VME2_SET_VBR1(7); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, VME_LEN, dev_vme_access, (void *)d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/autodev_head.cc000644 001750 001750 00000003542 13402411502 020401 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Automatically register all devices from the devices/ subdir. * * NOTE: autodev_head.c, plus a line for each device, plus autodev_middle.c, * plus another line (again) for each device, plus autodev_tail.c should be * combined into one. See makeautodev.sh for more info. */ #include #include "bus_pci.h" #include "device.h" gxemul-0.6.1/src/devices/dev_fb.cc000644 001750 001750 00000062757 13402411502 017213 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Generic framebuffer device * * DECstation VFB01 monochrome framebuffer, 1024x864 * DECstation VFB02 8-bit color framebuffer, 1024x864 * DECstation Maxine, 1024x768 8-bit color * Playstation 2 (24-bit color) * Generic (any resolution, several bit depths possible, useful for * testmachines) * * * TODO: This should actually be independent of X11, but that * might be too hard to do right now. * * TODO: playstation 2 pixels are stored in another format, actually */ #include #include #include #include "console.h" #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "x11.h" #ifdef WITH_X11 #include #include #include #endif #define FB_TICK_SHIFT 19 /* #define FB_DEBUG */ /* * set_grayscale_palette(): * * Fill d->rgb_palette with grayscale values. ncolors should * be something like 2, 4, 16, or 256. */ void set_grayscale_palette(struct vfb_data *d, int ncolors) { int i, gray; for (i=0; i<256; i++) { gray = 255*i/(ncolors-1); d->rgb_palette[i*3 + 0] = gray; d->rgb_palette[i*3 + 1] = gray; d->rgb_palette[i*3 + 2] = gray; } } /* * set_blackwhite_palette(): * * Set color 0 = black, all others to white. */ void set_blackwhite_palette(struct vfb_data *d, int ncolors) { int i, gray; for (i=0; i<256; i++) { gray = i==0? 0 : 255; d->rgb_palette[i*3 + 0] = gray; d->rgb_palette[i*3 + 1] = gray; d->rgb_palette[i*3 + 2] = gray; } } static void set_title(struct vfb_data *d) { snprintf(d->title, sizeof(d->title),"GXemul: %ix%ix%i %s framebuffer", d->visible_xsize, d->visible_ysize, d->bit_depth, d->name); d->title[sizeof(d->title)-1] = '\0'; } /* * dev_fb_resize(): * * Resize a framebuffer window. (This functionality is probably a bit buggy, * because I didn't think of including it from the start.) * * SUPER-IMPORTANT: Anyone who resizes a framebuffer by calling this function * must also clear all dyntrans address translations manually, in all cpus * which might have access to the framebuffer! */ void dev_fb_resize(struct vfb_data *d, int new_xsize, int new_ysize) { unsigned char *new_framebuffer; int y, new_bytes_per_line; size_t size; if (d == NULL) { fatal("dev_fb_resize(): d == NULL\n"); return; } if (new_xsize < 10 || new_ysize < 10) { fatal("dev_fb_resize(): size too small.\n"); exit(1); } new_bytes_per_line = new_xsize * d->bit_depth / 8; size = new_ysize * new_bytes_per_line; CHECK_ALLOCATION(new_framebuffer = (unsigned char *) malloc(size)); /* Copy the old framebuffer to the new: */ if (d->framebuffer != NULL) { for (y=0; ybytes_per_line * y; size_t toofs = new_bytes_per_line * y; size_t len_to_copy = d->bytes_per_line < new_bytes_per_line? d->bytes_per_line : new_bytes_per_line; memset(new_framebuffer + toofs, 0, new_bytes_per_line); if (y < d->x11_ysize) memmove(new_framebuffer + toofs, d->framebuffer + fromofs, len_to_copy); } free(d->framebuffer); } d->framebuffer = new_framebuffer; d->framebuffer_size = size; if (new_xsize > d->xsize || new_ysize > d->ysize) { d->update_x1 = d->update_y1 = 0; d->update_x2 = new_xsize - 1; d->update_y2 = new_ysize - 1; } d->bytes_per_line = new_bytes_per_line; d->xsize = d->visible_xsize = new_xsize; d->ysize = d->visible_ysize = new_ysize; d->x11_xsize = d->xsize / d->vfb_scaledown; d->x11_ysize = d->ysize / d->vfb_scaledown; memory_device_update_data(d->memory, d, d->framebuffer); set_title(d); #ifdef WITH_X11 if (d->fb_window != NULL) { x11_fb_resize(d->fb_window, d->x11_xsize, d->x11_ysize); x11_set_standard_properties(d->fb_window, d->title); } #endif } /* * dev_fb_setcursor(): */ void dev_fb_setcursor(struct vfb_data *d, int cursor_x, int cursor_y, int on, int cursor_xsize, int cursor_ysize) { if (cursor_x < 0) cursor_x = 0; if (cursor_y < 0) cursor_y = 0; if (cursor_x + cursor_xsize >= d->xsize) cursor_x = d->xsize - cursor_xsize; if (cursor_y + cursor_ysize >= d->ysize) cursor_y = d->ysize - cursor_ysize; #ifdef WITH_X11 if (d->fb_window != NULL) { d->fb_window->cursor_x = cursor_x; d->fb_window->cursor_y = cursor_y; d->fb_window->cursor_on = on; d->fb_window->cursor_xsize = cursor_xsize; d->fb_window->cursor_ysize = cursor_ysize; } #endif /* debug("dev_fb_setcursor(%i,%i, size %i,%i, on=%i)\n", cursor_x, cursor_y, cursor_xsize, cursor_ysize, on); */ } /* * framebuffer_blockcopyfill(): * * This function should be used by devices that are capable of doing * block copy/fill. * * If fillflag is non-zero, then fill_[rgb] should contain the color * with which to fill. (In 8-bit mode, only fill_r is used.) * * If fillflag is zero, copy mode is used, and from_[xy] should contain * the offset on the framebuffer where we should copy from. * * NOTE: Overlapping copies are undefined! */ void framebuffer_blockcopyfill(struct vfb_data *d, int fillflag, int fill_r, int fill_g, int fill_b, int x1, int y1, int x2, int y2, int from_x, int from_y) { int x, y; size_t from_ofs, dest_ofs, linelen; if (fillflag) debug("framebuffer_blockcopyfill(FILL, %i,%i, %i,%i, " "color %i,%i,%i)\n", x1,y1, x2,y2, fill_r, fill_g, fill_b); else debug("framebuffer_blockcopyfill(COPY, %i,%i, %i,%i, from " "%i,%i)\n", x1,y1, x2,y2, from_x,from_y); /* Clip x: */ if (x1 < 0) x1 = 0; if (x1 >= d->xsize) x1 = d->xsize-1; if (x2 < 0) x2 = 0; if (x2 >= d->xsize) x2 = d->xsize-1; dest_ofs = d->bytes_per_line * y1 + (d->bit_depth/8) * x1; linelen = (x2-x1 + 1) * (d->bit_depth/8); /* NOTE: linelen is nr of bytes, not pixels */ if (fillflag) { for (y=y1; y<=y2; y++) { if (y>=0 && yysize) { unsigned char *buf = d->framebuffer + dest_ofs; if (d->bit_depth == 24) { for (x=0; x<(ssize_t)linelen && x < (int) sizeof(buf); x += 3) { buf[x] = fill_r; buf[x+1] = fill_g; buf[x+2] = fill_b; } } else if (d->bit_depth == 8) { memset(buf, fill_r, linelen); } else { fatal("Unimplemented bit-depth (%i)" " for fb fill\n", d->bit_depth); exit(1); } } dest_ofs += d->bytes_per_line; } } else { from_ofs = d->bytes_per_line * from_y + (d->bit_depth/8) * from_x; for (y=y1; y<=y2; y++) { if (y >= 0 && y < d->ysize) { if (from_y >= 0 && from_y < d->ysize) memmove(d->framebuffer + dest_ofs, d->framebuffer + from_ofs, linelen); else memset(d->framebuffer + dest_ofs, 0, linelen); } from_y ++; from_ofs += d->bytes_per_line; dest_ofs += d->bytes_per_line; } } if (x1 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x1; if (x1 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x1; if (x2 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x2; if (x2 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x2; if (y1 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y1; if (y1 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y1; if (y2 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y2; if (y2 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y2; } #ifdef WITH_X11 #define REDRAW redraw_fallback #include "fb_include.cc" #undef REDRAW #define FB_24 #define REDRAW redraw_24 #include "fb_include.cc" #undef REDRAW #undef FB_24 #define FB_16 #define REDRAW redraw_16 #include "fb_include.cc" #undef FB_16 #undef REDRAW #define FB_15 #define REDRAW redraw_15 #include "fb_include.cc" #undef REDRAW #undef FB_15 #define FB_BO #define FB_24 #define REDRAW redraw_24_bo #include "fb_include.cc" #undef REDRAW #undef FB_24 #define FB_16 #define REDRAW redraw_16_bo #include "fb_include.cc" #undef FB_16 #undef REDRAW #define FB_15 #define REDRAW redraw_15_bo #include "fb_include.cc" #undef REDRAW #undef FB_15 #undef FB_BO #define FB_SCALEDOWN #define REDRAW redraw_fallback_sd #include "fb_include.cc" #undef REDRAW #define FB_24 #define REDRAW redraw_24_sd #include "fb_include.cc" #undef REDRAW #undef FB_24 #define FB_16 #define REDRAW redraw_16_sd #include "fb_include.cc" #undef FB_16 #undef REDRAW #define FB_15 #define REDRAW redraw_15_sd #include "fb_include.cc" #undef REDRAW #undef FB_15 #define FB_BO #define FB_24 #define REDRAW redraw_24_bo_sd #include "fb_include.cc" #undef REDRAW #undef FB_24 #define FB_16 #define REDRAW redraw_16_bo_sd #include "fb_include.cc" #undef FB_16 #undef REDRAW #define FB_15 #define REDRAW redraw_15_bo_sd #include "fb_include.cc" #undef REDRAW #undef FB_15 #undef FB_BO void (*redraw[2 * 4 * 2])(struct vfb_data *, int, int) = { redraw_fallback, redraw_fallback, redraw_15, redraw_15_bo, redraw_16, redraw_16_bo, redraw_24, redraw_24_bo, redraw_fallback_sd, redraw_fallback_sd, redraw_15_sd, redraw_15_bo_sd, redraw_16_sd, redraw_16_bo_sd, redraw_24_sd, redraw_24_bo_sd }; #endif /* WITH_X11 */ DEVICE_TICK(fb) { struct vfb_data *d = (struct vfb_data *) extra; #ifdef WITH_X11 int need_to_flush_x11 = 0; int need_to_redraw_cursor = 0; #endif if (!cpu->machine->x11_md.in_use) return; do { uint64_t high, low = (uint64_t)(int64_t) -1; int x, y; memory_device_dyntrans_access(cpu, cpu->mem, extra, &low, &high); if ((int64_t)low == -1) break; /* printf("low=%016llx high=%016llx\n", (long long)low, (long long)high); */ x = (low % d->bytes_per_line) * 8 / d->bit_depth; y = low / d->bytes_per_line; if (x < d->update_x1 || d->update_x1 == -1) d->update_x1 = x; if (x > d->update_x2 || d->update_x2 == -1) d->update_x2 = x; if (y < d->update_y1 || d->update_y1 == -1) d->update_y1 = y; if (y > d->update_y2 || d->update_y2 == -1) d->update_y2 = y; x = ((low+7) % d->bytes_per_line) * 8 / d->bit_depth; y = (low+7) / d->bytes_per_line; if (x < d->update_x1 || d->update_x1 == -1) d->update_x1 = x; if (x > d->update_x2 || d->update_x2 == -1) d->update_x2 = x; if (y < d->update_y1 || d->update_y1 == -1) d->update_y1 = y; if (y > d->update_y2 || d->update_y2 == -1) d->update_y2 = y; x = (high % d->bytes_per_line) * 8 / d->bit_depth; y = high / d->bytes_per_line; if (x < d->update_x1 || d->update_x1 == -1) d->update_x1 = x; if (x > d->update_x2 || d->update_x2 == -1) d->update_x2 = x; if (y < d->update_y1 || d->update_y1 == -1) d->update_y1 = y; if (y > d->update_y2 || d->update_y2 == -1) d->update_y2 = y; x = ((high+7) % d->bytes_per_line) * 8 / d->bit_depth; y = (high+7) / d->bytes_per_line; if (x < d->update_x1 || d->update_x1 == -1) d->update_x1 = x; if (x > d->update_x2 || d->update_x2 == -1) d->update_x2 = x; if (y < d->update_y1 || d->update_y1 == -1) d->update_y1 = y; if (y > d->update_y2 || d->update_y2 == -1) d->update_y2 = y; /* * An update covering more than one line will automatically * force an update of all the affected lines: */ if (d->update_y1 != d->update_y2) { d->update_x1 = 0; d->update_x2 = d->xsize-1; } } while (0); #ifdef WITH_X11 /* Do we need to redraw the cursor? */ if (d->fb_window->cursor_on != d->fb_window->OLD_cursor_on || d->fb_window->cursor_x != d->fb_window->OLD_cursor_x || d->fb_window->cursor_y != d->fb_window->OLD_cursor_y || d->fb_window->cursor_xsize != d->fb_window->OLD_cursor_xsize || d->fb_window->cursor_ysize != d->fb_window->OLD_cursor_ysize) need_to_redraw_cursor = 1; if (d->update_x2 != -1) { if (((d->update_x1 >= d->fb_window->OLD_cursor_x && d->update_x1 < (d->fb_window->OLD_cursor_x + d->fb_window->OLD_cursor_xsize)) || (d->update_x2 >= d->fb_window->OLD_cursor_x && d->update_x2 < (d->fb_window->OLD_cursor_x + d->fb_window->OLD_cursor_xsize)) || (d->update_x1 < d->fb_window->OLD_cursor_x && d->update_x2 >= (d->fb_window->OLD_cursor_x + d->fb_window->OLD_cursor_xsize)) ) && ( (d->update_y1 >= d->fb_window->OLD_cursor_y && d->update_y1 < (d->fb_window->OLD_cursor_y + d->fb_window->OLD_cursor_ysize)) || (d->update_y2 >= d->fb_window->OLD_cursor_y && d->update_y2 < (d->fb_window->OLD_cursor_y + d->fb_window->OLD_cursor_ysize)) || (d->update_y1 < d->fb_window->OLD_cursor_y && d->update_y2 >= (d->fb_window->OLD_cursor_y + d->fb_window->OLD_cursor_ysize)) ) ) need_to_redraw_cursor = 1; } if (need_to_redraw_cursor) { /* Remove old cursor, if any: */ if (d->fb_window->OLD_cursor_on) { XPutImage(d->fb_window->x11_display, d->fb_window->x11_fb_window, d->fb_window->x11_fb_gc, d->fb_window->fb_ximage, d->fb_window->OLD_cursor_x/d->vfb_scaledown, d->fb_window->OLD_cursor_y/d->vfb_scaledown, d->fb_window->OLD_cursor_x/d->vfb_scaledown, d->fb_window->OLD_cursor_y/d->vfb_scaledown, d->fb_window->OLD_cursor_xsize/d->vfb_scaledown + 1, d->fb_window->OLD_cursor_ysize/d->vfb_scaledown +1); } } #endif if (d->update_x2 != -1) { #ifdef WITH_X11 int y; #endif int addr, addr2, q = d->vfb_scaledown; if (d->update_x1 >= d->visible_xsize) d->update_x1 = d->visible_xsize - 1; if (d->update_x2 >= d->visible_xsize) d->update_x2 = d->visible_xsize - 1; if (d->update_y1 >= d->visible_ysize) d->update_y1 = d->visible_ysize - 1; if (d->update_y2 >= d->visible_ysize) d->update_y2 = d->visible_ysize - 1; /* Without these, we might miss the rightmost/bottom pixel: */ d->update_x2 += (q - 1); d->update_y2 += (q - 1); d->update_x1 = d->update_x1 / q * q; d->update_x2 = d->update_x2 / q * q; d->update_y1 = d->update_y1 / q * q; d->update_y2 = d->update_y2 / q * q; addr = d->update_y1 * d->bytes_per_line + d->update_x1 * d->bit_depth / 8; addr2 = d->update_y1 * d->bytes_per_line + d->update_x2 * d->bit_depth / 8; #ifdef WITH_X11 for (y=d->update_y1; y<=d->update_y2; y+=q) { d->redraw_func(d, addr, addr2 - addr); addr += d->bytes_per_line * q; addr2 += d->bytes_per_line * q; } XPutImage(d->fb_window->x11_display, d->fb_window-> x11_fb_window, d->fb_window->x11_fb_gc, d->fb_window-> fb_ximage, d->update_x1/d->vfb_scaledown, d->update_y1/ d->vfb_scaledown, d->update_x1/d->vfb_scaledown, d->update_y1/d->vfb_scaledown, (d->update_x2 - d->update_x1)/d->vfb_scaledown + 1, (d->update_y2 - d->update_y1)/d->vfb_scaledown + 1); need_to_flush_x11 = 1; #endif d->update_x1 = d->update_y1 = 99999; d->update_x2 = d->update_y2 = -1; } #ifdef WITH_X11 if (need_to_redraw_cursor) { /* Paint new cursor: */ if (d->fb_window->cursor_on) { x11_redraw_cursor(cpu->machine, d->fb_window->fb_number); d->fb_window->OLD_cursor_on = d->fb_window->cursor_on; d->fb_window->OLD_cursor_x = d->fb_window->cursor_x; d->fb_window->OLD_cursor_y = d->fb_window->cursor_y; d->fb_window->OLD_cursor_xsize = d->fb_window-> cursor_xsize; d->fb_window->OLD_cursor_ysize = d->fb_window-> cursor_ysize; need_to_flush_x11 = 1; } } #endif #ifdef WITH_X11 if (need_to_flush_x11) XFlush(d->fb_window->x11_display); #endif #if 0 This is a hack used to produce raw ppm image dumps, which can then be used to make movies, e.g. http://www.youtube.com/watch?v=Afh1ECLWac8 { static struct timeval tv_last; static bool first = true; struct timeval tv; gettimeofday(&tv, NULL); if (first) { tv_last = tv; first = false; } else { double diff = (tv.tv_sec - tv_last.tv_sec) + (tv.tv_usec - tv_last.tv_usec) / 1000000.0; if (diff > 0.2) { static int outputNr = 0; outputNr ++; tv_last = tv; char name[50]; snprintf(name, sizeof(name), "gxemul-%06i.ppm", outputNr); FILE *f = fopen(name, "w"); if (f == NULL) { perror(name); } else { const int xsize = 640; const int ysize = 480; fprintf(f, "P6\n%i %i\n255\n", xsize, ysize); unsigned char buf[xsize*ysize*3]; memset(buf, 0, xsize*ysize*3); // Calculate scaledown: int scaledown = 1; while (d->visible_xsize / scaledown > xsize || d->visible_ysize / scaledown > ysize) { scaledown ++; } // printf("scaledown = %i\n", scaledown); int xofs = (xsize - d->visible_xsize / scaledown) / 2; int yofs = (ysize - d->visible_ysize / scaledown) / 2; for (int y = 0; y < d->visible_ysize / scaledown; ++y) for (int x = 0; x < d->visible_xsize / scaledown; ++x) { int r = 0, g = 0, b = 0, n = 0; for (int suby = 0; suby < scaledown; ++suby) for (int subx = 0; subx < scaledown; ++subx) { ++n; int rx = x * scaledown + subx; int ry = y * scaledown + suby; int i = (d->xsize * ry + rx) * d->bit_depth / 8; #if 0 r += d->framebuffer[i+0]; g += d->framebuffer[i+1]; b += d->framebuffer[i+2]; #else int col = d->framebuffer[i]; r += d->rgb_palette[col*3 + 0]; g += d->rgb_palette[col*3 + 1]; b += d->rgb_palette[col*3 + 2]; #endif } r /= n; g /= n; b /= n; int j = (y + yofs) * xsize + x + xofs; buf[j*3+0] = r; buf[j*3+1] = g; buf[j*3+2] = b; } fwrite(buf, 1, xsize*ysize*3, f); fclose(f); } } } } #endif } DEVICE_ACCESS(fb) { struct vfb_data *d = (struct vfb_data *) extra; size_t i; #ifdef FB_DEBUG if (writeflag == MEM_WRITE) { if (data[0]) { fatal("[ dev_fb: write to addr=%08lx, data = ", (long)relative_addr); for (i=0; iframebuffer[relative_addr + i]); fatal("]\n"); } #endif if (relative_addr >= d->framebuffer_size) return 0; /* See if a write actually modifies the framebuffer contents: */ if (writeflag == MEM_WRITE) { for (i=0; iframebuffer[relative_addr + i]) break; /* If all bytes are equal to what is already stored in the framebuffer, then simply return: */ if (i == len-1) return 1; } } /* * If the framebuffer is modified, then we should keep a track * of which area(s) we modify, so that the display isn't updated * unnecessarily. */ if (writeflag == MEM_WRITE && cpu->machine->x11_md.in_use) { int x, y, x2,y2; x = (relative_addr % d->bytes_per_line) * 8 / d->bit_depth; y = relative_addr / d->bytes_per_line; x2 = ((relative_addr + len) % d->bytes_per_line) * 8 / d->bit_depth; y2 = (relative_addr + len) / d->bytes_per_line; if (x < d->update_x1 || d->update_x1 == -1) d->update_x1 = x; if (x > d->update_x2 || d->update_x2 == -1) d->update_x2 = x; if (y < d->update_y1 || d->update_y1 == -1) d->update_y1 = y; if (y > d->update_y2 || d->update_y2 == -1) d->update_y2 = y; if (x2 < d->update_x1 || d->update_x1 == -1) d->update_x1 = x2; if (x2 > d->update_x2 || d->update_x2 == -1) d->update_x2 = x2; if (y2 < d->update_y1 || d->update_y1 == -1) d->update_y1 = y2; if (y2 > d->update_y2 || d->update_y2 == -1) d->update_y2 = y2; /* * An update covering more than one line will automatically * force an update of all the affected lines: */ if (y != y2) { d->update_x1 = 0; d->update_x2 = d->xsize-1; } } /* * Read from/write to the framebuffer: * (TODO: take the color_plane_mask into account) * * Calling memcpy() is probably overkill, as it usually is just one * or a few bytes that are read/written at a time. */ if (writeflag == MEM_WRITE) { if (len > 8) memcpy(d->framebuffer + relative_addr, data, len); else { for (i=0; iframebuffer[relative_addr + i] = data[i]; } } else { if (len > 8) memcpy(data, d->framebuffer + relative_addr, len); else { for (i=0; iframebuffer[relative_addr + i]; } } return 1; } /* * dev_fb_init(): * * This function is big and ugly, but the point is to initialize a framebuffer * device. :-) * * visible_xsize and visible_ysize are the sizes of the visible display area. * xsize and ysize tell how much memory is actually allocated (for example * visible_xsize could be 640, but xsize could be 1024, for better alignment). * * vfb_type is useful for selecting special features. * * type = VFB_GENERIC is the most useful type, especially when bit_depth = 24. * * VFB_DEC_VFB01, _VFB02, and VFB_DEC_MAXINE are DECstation specific. * * VFB_HPC is like generic, but the color encoding is done as on HPCmips * and Dreamcast. * * If bit_depth = -15 (note the minus sign), then a special hack is used for * the Playstation Portable's 5-bit R, 5-bit G, 5-bit B. */ struct vfb_data *dev_fb_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, int vfb_type, int visible_xsize, int visible_ysize, int xsize, int ysize, int bit_depth, const char *name) { struct vfb_data *d; size_t size, nlen; int flags; int reverse_start = 0; char *name2; CHECK_ALLOCATION(d = (struct vfb_data *) malloc(sizeof(struct vfb_data))); memset(d, 0, sizeof(struct vfb_data)); if (vfb_type & VFB_REVERSE_START) { vfb_type &= ~VFB_REVERSE_START; reverse_start = 1; } d->memory = mem; d->vfb_type = vfb_type; /* Defaults: */ d->xsize = xsize; d->visible_xsize = visible_xsize; d->ysize = ysize; d->visible_ysize = visible_ysize; d->bit_depth = bit_depth; if (bit_depth == 15) { d->color32k = 1; bit_depth = d->bit_depth = 16; } else if (bit_depth == -15) { d->psp_15bit = 1; bit_depth = d->bit_depth = 16; } /* Specific types: */ switch (vfb_type) { case VFB_DEC_VFB01: /* DECstation VFB01 (monochrome) */ d->xsize = 2048; d->visible_xsize = 1024; d->ysize = 1024; d->visible_ysize = 864; d->bit_depth = 1; break; case VFB_DEC_VFB02: /* DECstation VFB02 (color) */ d->xsize = 1024; d->visible_xsize = 1024; d->ysize = 1024; d->visible_ysize = 864; d->bit_depth = 8; break; case VFB_DEC_MAXINE: /* DECstation Maxine (1024x768x8) */ d->xsize = 1024; d->visible_xsize = d->xsize; d->ysize = 768; d->visible_ysize = d->ysize; d->bit_depth = 8; break; case VFB_PLAYSTATION2: /* Playstation 2 */ d->xsize = xsize; d->visible_xsize = d->xsize; d->ysize = ysize; d->visible_ysize = d->ysize; d->bit_depth = 24; break; } if (d->bit_depth == 2 || d->bit_depth == 4) set_grayscale_palette(d, 1 << d->bit_depth); else if (d->bit_depth == 8 || d->bit_depth == 1) set_blackwhite_palette(d, 1 << d->bit_depth); d->vfb_scaledown = machine->x11_md.scaledown; d->bytes_per_line = d->xsize * d->bit_depth / 8; size = d->ysize * d->bytes_per_line; CHECK_ALLOCATION(d->framebuffer = (unsigned char *) malloc(size)); /* Clear the framebuffer (all black pixels): */ d->framebuffer_size = size; memset(d->framebuffer, reverse_start? 255 : 0, size); d->x11_xsize = d->visible_xsize / d->vfb_scaledown; d->x11_ysize = d->visible_ysize / d->vfb_scaledown; /* Only "update" from the start if we need to fill with white. */ /* (The Ximage will be black from the start anyway.) */ if (reverse_start) { d->update_x1 = d->update_y1 = 0; d->update_x2 = d->xsize - 1; d->update_y2 = d->ysize - 1; } else { d->update_x1 = d->update_y1 = 99999; d->update_x2 = d->update_y2 = -1; } CHECK_ALLOCATION(d->name = strdup(name)); set_title(d); #ifdef WITH_X11 if (machine->x11_md.in_use) { int i = 0; d->fb_window = x11_fb_init(d->x11_xsize, d->x11_ysize, d->title, machine->x11_md.scaledown, machine); switch (d->fb_window->x11_screen_depth) { case 15: i = 2; break; case 16: i = 4; break; case 24: i = 6; break; } if (d->fb_window->fb_ximage->byte_order) i ++; if (d->vfb_scaledown > 1) i += 8; d->redraw_func = redraw[i]; } else #endif d->fb_window = NULL; nlen = strlen(name) + 10; CHECK_ALLOCATION(name2 = (char *) malloc(nlen)); snprintf(name2, nlen, "fb [%s]", name); flags = DM_DEFAULT; if ((baseaddr & 0xfff) == 0) flags = DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK; flags |= DM_READS_HAVE_NO_SIDE_EFFECTS; memory_device_register(mem, name2, baseaddr, size, dev_fb_access, d, flags, d->framebuffer); machine_add_tickfunction(machine, dev_fb_tick, d, FB_TICK_SHIFT); return d; } gxemul-0.6.1/src/devices/dev_sgi_ip22.cc000644 001750 001750 00000030267 13402411502 020231 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SGI IP22 stuff */ #include #include #include #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/imcreg.h" #define SGI_IP22_TICK_SHIFT 14 DEVICE_TICK(sgi_ip22) { struct sgi_ip22_data *d = (struct sgi_ip22_data *) extra; // TODO: Document this! if (d->reg[0x38 / 4] != 0) d->reg[0x38 / 4] --; } /* * dev_sgi_ip22_imc_access(): * * The memory controller (?). */ DEVICE_ACCESS(sgi_ip22_imc) { struct sgi_ip22_data *d = (struct sgi_ip22_data *) extra; uint64_t idata = 0, odata = 0; int regnr; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); regnr = relative_addr / sizeof(uint32_t); if (writeflag == MEM_WRITE) d->imc_reg[regnr] = idata; else odata = d->imc_reg[regnr]; switch (relative_addr) { case (IMC_CPUCTRL0 - IP22_IMC_BASE): if (writeflag == MEM_WRITE) { /* debug("[ sgi_ip22_imc: write to " "IMC_CPUCTRL0, data=0x%08x ]\n", (int)idata); */ } else { /* debug("[ sgi_ip22_imc: read from IMC_CPUCTRL0, " "data=0x%08x ]\n", (int)odata); */ } break; case (IMC_SYSID - IP22_IMC_BASE): if (writeflag == MEM_WRITE) { debug("[ sgi_ip22_imc: unimplemented write " "IMC_SYSID, data=0x%08x ]\n", (int)idata); } else { /* Lowest 4 bits are the revision bits. */ odata = 3; /* + IMC_SYSID_HAVEISA; */ /* debug("[ sgi_ip22_imc: read from IMC_SYSID, " "data=0x%08x ]\n", (int)odata); */ } break; case (IMC_WDOG - IP22_IMC_BASE): if (writeflag == MEM_WRITE) { /* debug("[ sgi_ip22_imc: write to IMC_WDOG, " "data=0x%08x ]\n", (int)idata); */ } else { /* debug("[ sgi_ip22_imc: read from IMC_WDOG, " "data=0x%08x ]\n", (int)odata); */ } break; case (IMC_MEMCFG0 - IP22_IMC_BASE): if (writeflag == MEM_WRITE) { debug("[ sgi_ip22_imc: unimplemented write " "IMC_MEMCFG0, data=0x%08x ]\n", (int)idata); } else { odata = 0x3100 + (0x8000000 >> 22); /* ? TODO */ /* debug("[ sgi_ip22_imc: read from IMC_MEMCFG0," " data=0x%08x ]\n", (int)odata); */ } break; case (IMC_MEMCFG1 - IP22_IMC_BASE): if (writeflag == MEM_WRITE) { debug("[ sgi_ip22_imc: unimplemented write " "IMC_MEMCFG1, data=0x%08x ]\n", (int)idata); } else { odata = 0; /* debug("[ sgi_ip22_imc: read from IMC_MEMCFG1, " "data=0x%08x ]\n", (int)odata); */ } break; case (IMC_EEPROM - IP22_IMC_BASE): /* * The IP22 prom tries to access this during bootup, * but I have no idea how it works. */ if (writeflag == MEM_WRITE) { debug("[ sgi_ip22_imc: write to IMC_EEPROM, data=" "0x%08x ]\n", (int)idata); } else { odata = random() & 0x1e; debug("[ sgi_ip22_imc: read from IMC_WDOG, " "data=0x%08x ]\n", (int)odata); } break; default: if (writeflag == MEM_WRITE) { debug("[ sgi_ip22_imc: unimplemented write to " "address 0x%x, data=0x%08x ]\n", (int)relative_addr, (int)idata); } else { debug("[ sgi_ip22_imc: unimplemented read from " "address 0x%x, data=0x%08x ]\n", (int)relative_addr, (int)odata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_sgi_ip22_unknown_access(): * * A so far unknown device, used by the IP22 prom during startup. */ DEVICE_ACCESS(sgi_ip22_unknown) { struct sgi_ip22_data *d = (struct sgi_ip22_data *) extra; uint64_t idata = 0, odata = 0; idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0x04: if (writeflag == MEM_WRITE) { debug("[ sgi_ip22_unknown: write to address 0x%x," " data=0x%08x ]\n", (int)relative_addr, (int)idata); } else { odata = d->unknown_timer; d->unknown_timer += 100; debug("[ sgi_ip22_unknown: read from address 0x%x, " "data=0x%08x ]\n", (int)relative_addr, (int)odata); } break; default: if (writeflag == MEM_WRITE) { debug("[ sgi_ip22_unknown: unimplemented write to " "address 0x%x, data=0x%08x ]\n", (int)relative_addr, (int)idata); } else { debug("[ sgi_ip22_unknown: unimplemented read from " "address 0x%x, data=0x%08x ]\n", (int)relative_addr, (int)odata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_sgi_ip22_unknown2_access(): * * A so far unknown device, used by the IP22 prom during startup. */ DEVICE_ACCESS(sgi_ip22_unknown2) { struct sgi_ip22_data *d = (struct sgi_ip22_data *) extra; uint64_t idata = 0, odata = 0; int regnr; idata = memory_readmax64(cpu, data, len); regnr = relative_addr / sizeof(uint32_t); if (writeflag == MEM_WRITE) d->unknown2_reg[regnr] = idata; else odata = d->unknown2_reg[regnr]; switch (relative_addr) { default: if (writeflag == MEM_WRITE) { debug("[ sgi_ip22_unknown2: unimplemented write " "to address 0x%x, data=0x%08x ]\n", (int)relative_addr, (int)idata); } else { debug("[ sgi_ip22_unknown2: unimplemented read from " "address 0x%x, data=0x%08x ]\n", (int)relative_addr, (int)odata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(sgi_ip22_sysid) { struct sgi_ip22_data *d = (struct sgi_ip22_data *) extra; uint64_t idata = 0, odata = 0; idata = memory_readmax64(cpu, data, len); if (writeflag == MEM_WRITE) { debug("[ sgi_ip22_sysid: write to address 0x%x, " "data=0x%08x ]\n", (int)relative_addr, (int)idata); } else { /* * According to NetBSD's sgimips/ip22.c: * * printf("IOC rev %d, machine %s, board rev %d\n", * (sysid >> 5) & 0x07, * (sysid & 1) ? "Indigo2 (Fullhouse)" : "Indy (Guiness)", * (sysid >> 1) & 0x0f); */ /* IOC rev 1, Guiness, board rev 3: */ odata = (1 << 5) + (3 << 1) + (d->guiness_flag? 0 : 1); debug("[ sgi_ip22_sysid: read from address 0x%x, data=" "0x%08x ]\n", (int)relative_addr, (int)odata); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(sgi_ip22) { struct sgi_ip22_data *d = (struct sgi_ip22_data *) extra; uint64_t idata = 0, odata = 0; int regnr; idata = memory_readmax64(cpu, data, len); regnr = relative_addr / sizeof(uint32_t); if (writeflag == MEM_WRITE) d->reg[regnr] = idata; else odata = d->reg[regnr]; /* Read from/write to the sgi_ip22: */ switch (relative_addr) { case 0x00: /* local0 irq stat */ if (writeflag == MEM_WRITE) { debug("[ sgi_ip22: write to local0 IRQ STAT, " "data=0x%llx ]\n", (long long)idata); } else { debug("[ sgi_ip22: read from local0 IRQ STAT, " "data=0x%llx ]\n", (long long)odata); } break; case 0x04: /* local0 irq mask */ if (writeflag == MEM_WRITE) { /* * Ugly hack: if an interrupt is asserted, and someone * writes to this mask register, the interrupt should * be masked. That is, sgi_ip22_interrupt() in * src/machine.c has to be called to deal with this. * The ugly solution I choose here is to deassert * some interrupt which should never be used anyway. * (TODO: Fix this.) */ fatal("TODO: ip22 legacy interrupt rewrite!\n"); abort(); // cpu_interrupt_ack(cpu, 8 + 63); // debug("[ sgi_ip22: write to local0 IRQ MASK, " // "data=0x%llx ]\n", (long long)idata); } else { debug("[ sgi_ip22: read from local0 IRQ MASK, " "data=0x%llx ]\n", (long long)odata); } break; case 0x08: /* local1 irq stat */ if (writeflag == MEM_WRITE) { debug("[ sgi_ip22: write to local1 IRQ STAT, " "data=0x%llx ]\n", (long long)idata); } else { debug("[ sgi_ip22: read from local1 IRQ STAT, " "data=0x%llx ]\n", (long long)odata); } break; case 0x0c: /* local1 irq mask */ if (writeflag == MEM_WRITE) { /* See commen above, about local0 irq mask. */ fatal("TODO: ip22 legacy interrupt rewrite!\n"); abort(); // cpu_interrupt_ack(cpu, 8 + 63); // debug("[ sgi_ip22: write to local1 IRQ MASK, " // "data=0x%llx ]\n", (long long)idata); } else { debug("[ sgi_ip22: read from local1 IRQ MASK, " "data=0x%llx ]\n", (long long)odata); } break; case 0x10: if (writeflag == MEM_WRITE) { debug("[ sgi_ip22: write to mappable IRQ STAT, " "data=0x%llx ]\n", (long long)idata); } else { debug("[ sgi_ip22: read from mappable IRQ STAT, " "data=0x%llx ]\n", (long long)odata); } break; case 0x14: if (writeflag == MEM_WRITE) { debug("[ sgi_ip22: write to mappable local0 IRQ " "MASK, data=0x%llx ]\n", (long long)idata); } else { debug("[ sgi_ip22: read from mappable local0 IRQ " "MASK, data=0x%llx ]\n", (long long)odata); } break; case 0x18: if (writeflag == MEM_WRITE) { debug("[ sgi_ip22: write to mappable local1 IRQ " "MASK, data=0x%llx ]\n", (long long)idata); } else { debug("[ sgi_ip22: read from mappable local1 IRQ " "MASK, data=0x%llx ]\n", (long long)odata); } break; case 0x38: /* timer count */ if (writeflag == MEM_WRITE) { /* Two byte values are written to this address, sequentially... TODO */ } else { /* The timer is decreased by the tick function. */ } break; case 0x3b: /* ? */ odata = random(); break; case 0x3c: /* timer control */ break; case 0x3f: /* ? */ odata = random(); break; default: if (writeflag == MEM_WRITE) { debug("[ sgi_ip22: unimplemented write to address " "0x%x, data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { debug("[ sgi_ip22: unimplemented read from address " "0x%llx ]\n", (long long)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } struct sgi_ip22_data *dev_sgi_ip22_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, int guiness_flag) { struct sgi_ip22_data *d; CHECK_ALLOCATION(d = (struct sgi_ip22_data *) malloc(sizeof(struct sgi_ip22_data))); memset(d, 0, sizeof(struct sgi_ip22_data)); d->guiness_flag = guiness_flag; memory_device_register(mem, "sgi_ip22", baseaddr, DEV_SGI_IP22_LENGTH, dev_sgi_ip22_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(mem, "sgi_ip22_sysid", 0x1fbd9858, 0x8, dev_sgi_ip22_sysid_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(mem, "sgi_ip22_imc", IP22_IMC_BASE, DEV_SGI_IP22_IMC_LENGTH, dev_sgi_ip22_imc_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(mem, "sgi_ip22_unknown", 0x1fa01000, 0x10, dev_sgi_ip22_unknown_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(mem, "sgi_ip22_unknown2", IP22_UNKNOWN2_BASE, DEV_SGI_IP22_UNKNOWN2_LENGTH, dev_sgi_ip22_unknown2_access, (void *)d, DM_DEFAULT, NULL); machine_add_tickfunction(machine, dev_sgi_ip22_tick, d, SGI_IP22_TICK_SHIFT); return d; } gxemul-0.6.1/src/devices/dev_kn02.cc000644 001750 001750 00000012603 13402411502 017357 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: DEC KN02 mainbus (TurboChannel interrupt controller) * * Used in DECstation type 2 ("3MAX"). See include/dec_kn02.h for more info. */ #include #include #include #include "cpu.h" #include "device.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/dec_kn02.h" #define DEV_KN02_LENGTH 0x1000 struct kn02_data { uint8_t csr[sizeof(uint32_t)]; /* Dummy fill bytes, so dyntrans can be used: */ uint8_t filler[DEV_KN02_LENGTH - sizeof(uint32_t)]; struct interrupt irq; int int_asserted; }; /* * kn02_interrupt_assert(), kn02_interrupt_deassert(): * * Called whenever a KN02 (TurboChannel) interrupt is asserted/deasserted. */ void kn02_interrupt_assert(struct interrupt *interrupt) { struct kn02_data *d = (struct kn02_data *) interrupt->extra; d->csr[0] |= interrupt->line; if (d->csr[0] & d->csr[2] && !d->int_asserted) { d->int_asserted = 1; INTERRUPT_ASSERT(d->irq); } } void kn02_interrupt_deassert(struct interrupt *interrupt) { struct kn02_data *d = (struct kn02_data *) interrupt->extra; d->csr[0] &= ~interrupt->line; if (!(d->csr[0] & d->csr[2]) && d->int_asserted) { d->int_asserted = 0; INTERRUPT_DEASSERT(d->irq); } } DEVICE_ACCESS(kn02) { struct kn02_data *d = (struct kn02_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0: if (writeflag==MEM_READ) { odata = d->csr[0] + (d->csr[1] << 8) + (d->csr[2] << 16) + (d->csr[3] << 24); /* debug("[ kn02: read from CSR: 0x%08x ]\n", odata); */ } else { /* * Only bits 23..8 are considered writable. The * lowest 8 bits are actually writable, but don't * affect the interrupt I/O bits; the low 8 bits * on write turn on and off LEDs. (There are no * LEDs in the emulator, so those bits are just * ignored.) */ int old_assert = (d->csr[0] & d->csr[2])? 1 : 0; int new_assert; /* fatal("[ kn02: write to CSR: 0x%08x ]\n", idata); */ d->csr[1] = (idata >> 8) & 255; d->csr[2] = (idata >> 16) & 255; /* Recalculate interrupt assertions: */ new_assert = (d->csr[0] & d->csr[2])? 1 : 0; if (new_assert != old_assert) { if (new_assert) { INTERRUPT_ASSERT(d->irq); d->int_asserted = 1; } else { INTERRUPT_DEASSERT(d->irq); d->int_asserted = 0; } } } break; default: if (writeflag==MEM_READ) { debug("[ kn02: read from 0x%08lx ]\n", (long)relative_addr); } else { debug("[ kn02: write to 0x%08lx: 0x%08x ]\n", (long)relative_addr, (int)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(kn02) { struct kn02_data *d; uint32_t csr; int i; CHECK_ALLOCATION(d = (struct kn02_data *) malloc(sizeof(struct kn02_data))); memset(d, 0, sizeof(struct kn02_data)); /* Connect the KN02 to a specific MIPS CPU interrupt line: */ INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); /* Register the 8 possible TurboChannel interrupts: */ for (i=0; i<8; i++) { struct interrupt templ; char tmpstr[300]; snprintf(tmpstr, sizeof(tmpstr), "%s.kn02.%i", devinit->interrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = 1 << i; templ.name = tmpstr; templ.extra = d; templ.interrupt_assert = kn02_interrupt_assert; templ.interrupt_deassert = kn02_interrupt_deassert; interrupt_handler_register(&templ); } /* * Set initial value of the CSR. Note: If the KN02_CSR_NRMMOD bit * is not set, the 5000/200 PROM image loops forever. */ csr = KN02_CSR_NRMMOD; d->csr[0] = csr; d->csr[1] = csr >> 8; d->csr[2] = csr >> 16; d->csr[3] = csr >> 24; memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_KN02_LENGTH, dev_kn02_access, d, DM_DYNTRANS_OK, &d->csr[0]); return 1; } gxemul-0.6.1/src/devices/dev_ahc.cc000644 001750 001750 00000012302 13402411502 017334 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Adaptec AHC SCSI controller * * NetBSD should say something like this, on SGI-IP32: * * ahc0 at pci0 dev 1 function 0: Adaptec aic7880 Ultra SCSI adapter * ahc0: interrupting at crime interrupt 8 * ahc0: Using left over BIOS settings * ahc0: Host Adapter has no SEEPROM. Using default SCSI target parameters * ahc0: aic7880: Ultra Wide Channel A, SCSI Id=0, 16/253 SCBs * scsibus0 at ahc0: 16 targets, 8 luns per target * * TODO: This is just a dummy device, so far. */ #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/aic7xxx_reg.h" #define AHC_DEBUG #define debug fatal #define DEV_AHC_LENGTH 0x100 struct ahc_data { unsigned char reg[DEV_AHC_LENGTH]; }; DEVICE_ACCESS(ahc) { struct ahc_data *d = (struct ahc_data *) extra; uint64_t idata, odata = 0; int ok = 0; const char *name = NULL; idata = memory_readmax64(cpu, data, len); /* SGI uses weird reversed order addresses: */ if (cpu->byte_order == EMUL_BIG_ENDIAN) relative_addr ^= 3; if (len != 1) fatal("[ ahc: ERROR! Unimplemented len %i ]\n", len); if (writeflag == MEM_READ) odata = d->reg[relative_addr]; switch (relative_addr) { case SCSIID: if (writeflag == MEM_READ) { ok = 1; name = "SCSIID"; odata = 0; } else { fatal("[ ahc: write to SCSIOFFSET, data = 0x" "%02x: TODO ]\n", (int)idata); } break; case KERNEL_QINPOS: if (writeflag == MEM_WRITE) { /* TODO */ d->reg[INTSTAT] |= SEQINT; } break; case SEECTL: ok = 1; name = "SEECTL"; if (writeflag == MEM_WRITE) d->reg[relative_addr] = idata; odata |= SEERDY; break; case SCSICONF: ok = 1; name = "SCSICONF"; if (writeflag == MEM_READ) { odata = 0; } else { fatal("[ ahc: write to SCSICONF, data = 0x%02x:" " TODO ]\n", (int)idata); } break; case SEQRAM: case SEQADDR0: case SEQADDR1: /* TODO: This is just a dummy. */ break; case HCNTRL: ok = 1; name = "HCNTRL"; if (writeflag == MEM_WRITE) d->reg[relative_addr] = idata; break; case INTSTAT: ok = 1; name = "INTSTAT"; if (writeflag == MEM_WRITE) fatal("[ ahc: write to INTSTAT? data = 0x%02x ]\n", (int)idata); break; case CLRINT: if (writeflag == MEM_READ) { ok = 1; name = "ERROR"; /* TODO */ } else { ok = 1; name = "CLRINT"; if (idata & ~0xf) fatal("[ ahc: write to CLRINT: 0x%02x " "(TODO) ]\n", (int)idata); /* Clear the lowest 4 bits of intstat: */ d->reg[INTSTAT] &= ~(idata & 0xf); } break; default: if (writeflag == MEM_WRITE) fatal("[ ahc: UNIMPLEMENTED write to address 0x%x, " "data=0x%02x ]\n", (int)relative_addr, (int)idata); else fatal("[ ahc: UNIMPLEMENTED read from address 0x%x ]\n", (int)relative_addr); } #ifdef AHC_DEBUG if (ok) { if (name == NULL) { if (writeflag == MEM_WRITE) debug("[ ahc: write to address 0x%x: 0x" "%02x ]\n", (int)relative_addr, (int)idata); else debug("[ ahc: read from address 0x%x: 0x" "%02x ]\n", (int)relative_addr, (int)odata); } else { if (writeflag == MEM_WRITE) debug("[ ahc: write to %s: 0x%02x ]\n", name, (int)idata); else debug("[ ahc: read from %s: 0x%02x ]\n", name, (int)odata); } } #endif if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(ahc) { struct ahc_data *d; CHECK_ALLOCATION(d = (struct ahc_data *) malloc(sizeof(struct ahc_data))); memset(d, 0, sizeof(struct ahc_data)); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_AHC_LENGTH, dev_ahc_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_fdc.cc000644 001750 001750 00000006062 13402411502 017343 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: PC-style floppy controller * * TODO! (This is just a dummy skeleton right now.) * * TODO 2: Make it work nicely with both ARC and PC emulation. * * See http://members.tripod.com/~oldboard/assembly/765.html for a * quick overview. */ #include #include #include #include "device.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #define DEV_FDC_LENGTH 6 /* TODO 8, but collision with wdc */ struct fdc_data { uint8_t reg[DEV_FDC_LENGTH]; struct interrupt irq; }; DEVICE_ACCESS(fdc) { struct fdc_data *d = (struct fdc_data *) extra; uint64_t idata = 0, odata = 0; size_t i; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0x04: break; default:if (writeflag==MEM_READ) { fatal("[ fdc: read from reg %i ]\n", (int)relative_addr); odata = d->reg[relative_addr]; } else { fatal("[ fdc: write to reg %i:", (int)relative_addr); for (i=0; ireg[relative_addr] = idata; } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(fdc) { struct fdc_data *d; CHECK_ALLOCATION(d = (struct fdc_data *) malloc(sizeof(struct fdc_data))); memset(d, 0, sizeof(struct fdc_data)); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_FDC_LENGTH, dev_fdc_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_fbctrl.cc000644 001750 001750 00000011406 13402411502 020061 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Framebuffer controller device (control's dev_fb in test machines) * * A "framebuffer control" device. It can be used to manipulate the * framebuffer device in testmachines. */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "testmachine/dev_fb.h" struct fbctrl_data { struct vfb_data *vfb_data; int current_port; int port[DEV_FBCTRL_NPORTS]; }; /* * fbctrl_command(): * * Execute a framebuffer control command. */ static void fbctrl_command(struct cpu *cpu, struct fbctrl_data *d) { int cmd = d->port[DEV_FBCTRL_PORT_COMMAND]; int x1, y1, i; switch (cmd) { case DEV_FBCTRL_COMMAND_NOP: break; case DEV_FBCTRL_COMMAND_SET_RESOLUTION: /* * Change the framebuffer resolution to X1 x Y1 pixels. */ x1 = d->port[DEV_FBCTRL_PORT_X1]; y1 = d->port[DEV_FBCTRL_PORT_Y1]; debug("[ dev_fbctrl: changing resolution to %i,%i ]\n", x1, y1); dev_fb_resize(d->vfb_data, x1, y1); /* Remember to invalidate all translations for anyone who might have used the old framebuffer: */ for (i = 0; i < cpu->machine->ncpus; i++) cpu->machine->cpus[i]->invalidate_translation_caches( cpu->machine->cpus[i], 0, INVALIDATE_ALL); break; case DEV_FBCTRL_COMMAND_GET_RESOLUTION: if (cpu->machine->x11_md.in_use) { d->port[DEV_FBCTRL_PORT_X1] = d->vfb_data->xsize; d->port[DEV_FBCTRL_PORT_Y1] = d->vfb_data->ysize; } else { // When not using X11 output, return 0x0 size. d->port[DEV_FBCTRL_PORT_X1] = 0; d->port[DEV_FBCTRL_PORT_Y1] = 0; } break; /* TODO: Block copy and fill. */ default:fatal("fbctrl_command: Unimplemented command %i.\n", cmd); exit(1); } } DEVICE_ACCESS(fbctrl) { struct fbctrl_data *d = (struct fbctrl_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case DEV_FBCTRL_PORT: if (writeflag == MEM_READ) odata = d->current_port; else { d->current_port = idata; if (idata >= DEV_FBCTRL_NPORTS) fatal("[ WARNING: fbctrl port number is out" " of range! ]\n"); } break; case DEV_FBCTRL_DATA: if (d->current_port < 0 || d->current_port >= DEV_FBCTRL_NPORTS) { fatal("[ fbctrl port number is out of range! ]\n"); exit(1); } if (writeflag == MEM_READ) odata = d->port[d->current_port]; else { d->port[d->current_port] = idata; if (d->current_port == DEV_FBCTRL_PORT_COMMAND) fbctrl_command(cpu, d); } break; default: fatal("[ dev_fbctrl: unimplemented relative addr 0x%x ]\n", (int)relative_addr); exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(fbctrl) { struct fbctrl_data *d; CHECK_ALLOCATION(d = (struct fbctrl_data *) malloc(sizeof(struct fbctrl_data))); memset(d, 0, sizeof(struct fbctrl_data)); d->vfb_data = dev_fb_init(devinit->machine, devinit->machine->memory, DEV_FB_ADDRESS, VFB_GENERIC, 640, 480, 640, DEV_FBCTRL_MAXY(640), 24, "generic"); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_FBCTRL_LENGTH, dev_fbctrl_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_dreamcast_gdrom.cc000644 001750 001750 00000033711 13402411502 021743 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2014 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Dreamcast GD-ROM * * TODO: This is mostly just a dummy so far. It is enough for NetBSD/dreamcast * to read the GD-ROM (or actually, just a particular Live CD). It shouldn't * be assumed to work for anything else. */ #include #include #include #include "cpu.h" #include "device.h" #include "diskimage.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/dreamcast_sysasicvar.h" // #define debug fatal #define NREGS_GDROM_DMA (0x100/sizeof(uint32_t)) struct dreamcast_gdrom_data { // 0x005f7000: GDROM control registers uint8_t busy; /* Busy status */ uint8_t stat; /* Status */ int cnt; /* Data length in bytes */ uint8_t cond; int cmd_count; uint8_t cmd[12]; uint8_t *data; int data_len; int cur_data_offset; int cur_cnt; // 0x005f7400: GDROM DMA uint32_t dma_reg[NREGS_GDROM_DMA]; }; /* Register offsets, from NetBSD: */ #define GDROM_BUSY 0x18 #define GDROM_DATA 0x80 #define GDROM_REGX 0x84 #define GDROM_UNKNOWN_0x88 0x88 #define GDROM_STAT 0x8c #define GDROM_CNTLO 0x90 #define GDROM_CNTHI 0x94 #define GDROM_COND 0x9c // See the interrupt routine (gdrom_intr()) in NetBSD's dreamcast/dev/gdrom.c: #define COND_DATA_AVAIL 0x08 static void alloc_data(struct dreamcast_gdrom_data *d) { d->data_len = d->cnt; CHECK_ALLOCATION(d->data = (uint8_t *) malloc(d->data_len)); memset(d->data, 0, d->data_len); } static void handle_command(struct cpu *cpu, struct dreamcast_gdrom_data *d) { int64_t sector_nr, sector_count; int i, res; debug("[ GDROM cmd: "); for (i=0; i<12; i++) debug("%02x ", d->cmd[i]); debug("(cnt=%i) ]\n", d->cnt); if (d->data != NULL) free(d->data); d->data = NULL; d->cur_data_offset = 0; d->cur_cnt = 0; switch (d->cmd[0]) { case 0x14: /* * Read Table-Of-Contents: * * See NetBSD's sys/arch/dreamcast/dev/gdrom.c: gdrom_read_toc(). */ if (d->cnt != 408) { fatal("GDROM Read TOC not 408 bytes?\n"); exit(1); } alloc_data(d); /* * From David Brownlee: * "TOC from test booted real CD image on NetBSD/dreamcast * 01000096,41002e4c,ffffffff * 97,01010000,41020000,6100e641," * * TODO: Perhaps generalize this in the future, to support * disk images with multiple TOCs and/or tracks. */ memset(d->data, 0xff, d->cnt); /* Default data to 0xff */ d->data[0*4] = 0x10; /* Track 1 */ d->data[0*4+1] = 0; d->data[0*4+2] = 0; d->data[0*4+3] = 0x96; d->data[1*4] = 0x41; /* Track 2 */ d->data[1*4+1] = 0; d->data[1*4+2] = 0x2e; d->data[1*4+3] = 0x4c; d->data[99*4] = 0x01; /* First track */ d->data[99*4+1] = 0x01; d->data[99*4+2] = 0; d->data[99*4+3] = 0; d->data[100*4] = 0x41; /* Last track */ d->data[100*4+1] = 0x02; d->data[100*4+2] = 0; d->data[100*4+3] = 0; d->data[101*4] = 0x61; /* Leadout */ d->data[101*4+1] = 0; d->data[101*4+2] = 0xe6; d->data[101*4+3] = 0x41; break; case 0x30: /* * Read sectors: * * See NetBSD's sys/arch/dreamcast/dev/gdrom.c: gdrom_read_sectors(). */ if (d->cmd[1] == 0x24) { fatal("GDROM unimplemented data format 0x%02x. Continuing anway.\n", d->cmd[1]); } else if (d->cmd[1] != 0x20) { fatal("GDROM unimplemented data format 0x%02x\n", d->cmd[1]); exit(1); } sector_nr = d->cmd[2] * 65536 + d->cmd[3] * 256 + d->cmd[4]; sector_count = d->cmd[8] * 65536 + d->cmd[9] * 256 + d->cmd[10]; // NetBSD/dreamcast uses correct length, but the Dreamcast PROM // uses len = 0 (!), but sector count = 7, // which means len = 0x3800. It also sets up DMA to // transfer 0x3800 bytes, so I'm assuming that the // sector count is to be trusted more than the length. if (d->cnt == 0) d->cnt = 2048 * sector_count; if (sector_count * 2048 != d->cnt) { fatal("Huh? GDROM data_len=0x%x, but sector_count" "=0x%x\n", (int)d->cnt, (int)sector_count); exit(1); } alloc_data(d); // Hm. This is an ugly hack to make a NetBSD/dreamcast // live-cd work. It should be fixed (i.e. removed). // When running with -Q (i.e. no PROM software emulation), // experiments with the Dreamcast PROM can be made instead. if (cpu->machine->prom_emulation) { // printf("sector nr step 1 = %i\n", (int)sector_nr); // Hack to get NetBSD/dreamcast to work: // See the variable "openpart_start" in NetBSD's // sys/arch/dreamcast/dev/gdrom.c: sector_nr -= 150; // printf("sector nr step 2 = %i\n", (int)sector_nr); } else { // printf("sector nr step 1 = %i\n", (int)sector_nr); sector_nr -= 45150; // printf("sector nr step 2 = %i\n", (int)sector_nr); sector_nr += (diskimage_get_baseoffset(cpu->machine, 0, DISKIMAGE_IDE) / 2048); // printf("sector nr step 3 = %i\n", (int)sector_nr); } res = diskimage_access(cpu->machine, 0, DISKIMAGE_IDE, 0, sector_nr * 2048, d->data, d->data_len); if (!res) { fatal("GDROM: diskimage_access failed? TODO\n"); free(d->data); d->data = NULL; } /* { printf("(Dump of GDROM sector %i: \"", (int)sector_nr); for (int k = 0; k < 256; ++k) printf("%c", d->data[k] >= 32 ? d->data[k] : '.'); printf("\")\n"); } */ break; case 0x70: /* * Mount: * * See NetBSD's sys/arch/dreamcast/dev/gdrom.c: gdrom_mount_disk(). */ // Note/TODO: This is ignored for now. break; default:fatal("GDROM handle_command: unimplemented command 0x%02x" "\n", d->cmd[0]); exit(1); } // Any resulting data? Then set COND_DATA_AVAIL. Otherwise, clear // that bit, and set count to zero. if (d->data != NULL) { d->cond |= COND_DATA_AVAIL; } else { d->cnt = 0; d->cond &= ~COND_DATA_AVAIL; } // NetBSD seems to sometimes request 32 sectors (2048 bytes each), i.e. // 65536 bytes. That is represented as count = 0x0000 (when NetBSD reads // from the CNTHI and CNTLO registers). That does not work very well. // This is a hack/workaround for that. if (d->cnt == 65536) d->cnt = 32768; SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_GDROM); } void dreamcast_gdrom_update_stat(struct cpu *cpu, struct dreamcast_gdrom_data *d) { // See NetBSD's gdrom.c. d->stat = 6; if (diskimage_exist(cpu->machine, 0, DISKIMAGE_IDE)) { d->stat = 0; } } DEVICE_ACCESS(dreamcast_gdrom) { struct dreamcast_gdrom_data *d = (struct dreamcast_gdrom_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case GDROM_BUSY: if (writeflag == MEM_READ) { odata = d->busy; } else { // fatal("[ Write to GDROM_BUSY: 0x%08x ]\n", (int)idata); // I'm assuming that writing bits to BUSY clears them. d->busy &= ~idata; } break; case GDROM_DATA: if (len != sizeof(uint16_t)) { fatal("Non-16bit GDROM data access? TODO\n"); exit(1); } if (writeflag == MEM_READ) { if (!(d->cond & COND_DATA_AVAIL)) { fatal("Read from GDROM_DATA when no data" " is available? TODO\n"); exit(1); } if (d->cur_data_offset < d->data_len) { odata = d->data[d->cur_data_offset ++]; odata |= (d->data[d->cur_data_offset ++] << 8); d->cur_cnt += sizeof(uint16_t); if (d->cur_cnt >= d->cnt) { if (d->cur_data_offset >= d->data_len) { d->cond &= ~COND_DATA_AVAIL; } else { d->cnt = d->data_len - d->cur_data_offset; d->cur_cnt = 0; } SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_GDROM); } } else { fatal("Read too much from GDROM_DATA\n"); exit(1); } } else { if (d->busy & 0x08) { if (d->cmd_count >= 12) { fatal("Too much GDROM_DATA?\n"); exit(1); } /* Add data to cmd: */ d->cmd[d->cmd_count++] = idata; d->cmd[d->cmd_count++] = idata >> 8; if (d->cmd_count == 12) { d->busy &= ~0x08; handle_command(cpu, d); } } else { fatal("Write to GDROM_DATA, but not waiting" " for data?\n"); exit(1); } } break; case GDROM_REGX: if (writeflag == MEM_READ) { debug("[ Read to GDROM_REGX? ]\n"); } else { /* NetBSD/dreamcast writes 0 here. */ if (idata != 0) debug("[ Write 0x%x to GDROM_REGX? ]\n", (int)idata); } break; case GDROM_UNKNOWN_0x88: if (writeflag == MEM_READ) { fatal("Read from GDROM_UNKNOWN_0x88?\n"); // exit(1); } else { if (idata != 0xb) { fatal("[ Write to GDROM_UNKNOWN_0x88: TODO ]\n"); exit(1); } } break; case GDROM_STAT: if (writeflag == MEM_READ) { dreamcast_gdrom_update_stat(cpu, d); odata = d->stat; } else { fatal("[ Write to GDROM_STAT? ]\n"); /* exit(1); */ } break; case GDROM_CNTLO: if (writeflag == MEM_READ) { odata = d->cnt & 0xff; } else { d->cnt = (d->cnt & 0xff00) | (idata & 0xff); } break; case GDROM_CNTHI: if (writeflag == MEM_READ) { odata = (d->cnt >> 8) & 0xff; } else { d->cnt = (d->cnt & 0x00ff) | ((idata & 0xff) << 8); } break; case GDROM_COND: if (writeflag == MEM_READ) { odata = d->cond; } else { d->cond = idata; /* * NetBSD/dreamcast writes 0xa0 to GDROM_COND to * start a command. See gdrom_do_command() in NetBSD's * sys/arch/dreamcast/dev/gdrom.c. * * Before sending anything, NetBSD expects: * o) the lowest 4 bits of STAT to not be 6. * * After writing 0xa0 to GDROM_COND, NetBSD expects: * o) (BUSY & 0x88) to be 0x08. * * NetBSD then sends 6 16-bit data words to GDROM_DATA. */ if (idata == 0xa0) { d->stat = 0; /* TODO */ d->busy |= 0x08; d->cmd_count = 0; } else if (idata == 0xef) { debug("dreamcast_gdrom: ROM: TODO\n"); SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_GDROM); } else { fatal("dreamcast_gdrom: unimplemented " "GDROM_COND = 0x%02x\n", (int)idata); exit(1); } } break; default:if (writeflag == MEM_READ) { fatal("[ dreamcast_gdrom: read from addr 0x%x ]\n", (int)relative_addr); } else { fatal("[ dreamcast_gdrom: write to addr 0x%x: 0x%x ]\n", (int)relative_addr, (int)idata); } exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(dreamcast_gdrom_dma) { struct dreamcast_gdrom_data *d = (struct dreamcast_gdrom_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* Default read: */ if (writeflag == MEM_READ) odata = d->dma_reg[relative_addr / sizeof(uint32_t)]; switch (relative_addr) { case 0x04: // destination address? e.g. 0x8c008000 case 0x08: // DMA length in bytes? e.g. 0x3800 case 0x0c: // count? e.g. 1 case 0x14: // "enable"? break; case 0x18: // GDROM DMA start? if (idata != 0) { if (d->dma_reg[0x0c / sizeof(uint32_t)] == 1 && d->dma_reg[0x14 / sizeof(uint32_t)] == 1) { // GDROM DMA transfer. uint32_t dst = d->dma_reg[0x04 / sizeof(uint32_t)]; int length = d->dma_reg[0x08 / sizeof(uint32_t)]; fatal("[ dreamcast_gdrom_dma: Transfering %i bytes to 0x%08" PRIx32" ]\n", length, dst); if (d->data == NULL) { fatal("dreamcast_gdrom_dma: DMA transfer but d->data is NULL. TODO\n"); exit(1); } dst &= 0x0fffffff; // 0x8c008000 => 0x0c008000 cpu->memory_rw(cpu, cpu->mem, dst, d->data, d->data_len, MEM_WRITE, PHYSICAL); SYSASIC_TRIGGER_EVENT(SYSASIC_EVENT_GDROM_DMA); idata = 0; } else { fatal("Unimplemented GDROM DMA start? TODO\n"); fatal(" %08x\n", (int) d->dma_reg[4 / sizeof(uint32_t)]); fatal(" %08x\n", (int) d->dma_reg[8 / sizeof(uint32_t)]); fatal(" %08x\n", (int) d->dma_reg[0xc / sizeof(uint32_t)]); fatal(" %08x\n", (int) d->dma_reg[0x14 / sizeof(uint32_t)]); exit(1); } } break; default:if (writeflag == MEM_READ) { fatal("[ dreamcast_gdrom_dma: read from addr 0x%x ]\n", (int)relative_addr); } else { fatal("[ dreamcast_gdrom_dma: write to addr 0x%x: " "0x%x ]\n", (int)relative_addr, (int)idata); } exit(1); } /* Default write: */ if (writeflag == MEM_WRITE) d->dma_reg[relative_addr / sizeof(uint32_t)] = idata; if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(dreamcast_gdrom) { struct dreamcast_gdrom_data *d; CHECK_ALLOCATION(d = (struct dreamcast_gdrom_data *) malloc(sizeof(struct dreamcast_gdrom_data))); memset(d, 0, sizeof(struct dreamcast_gdrom_data)); memory_device_register(devinit->machine->memory, devinit->name, 0x005f7000, 0x100, dev_dreamcast_gdrom_access, d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, "gdrom_dma", 0x005f7400, 0x80, dev_dreamcast_gdrom_dma_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_dec21143.cc000644 001750 001750 00000067040 13402411502 017740 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: DEC 21143 "Tulip" ethernet controller * * Implemented from Intel document 278074-001 ("21143 PC/CardBus 10/100Mb/s * Ethernet LAN Controller") and by reverse-engineering OpenBSD and NetBSD * sources. * * This device emulates several sub-components: * * 21143: This is the actual ethernet controller. * * MII: The "physical" network interface. * * SROM: A ROM area containing setting such as which MAC address to * use, and info about the MII. * * * TODO: * o) Handle _writes_ to MII registers. * o) Make it work with modern Linux kernels (as a guest OS). * o) Endianness for descriptors? If necessary. * o) Actually handle the "Setup" packet. * o) MAC filtering on incoming packets. * o) Don't hardcode as many values. */ #include #include #include #include "cpu.h" #include "device.h" #include "devices.h" #include "emul.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "net.h" #include "thirdparty/mii.h" #include "thirdparty/tulipreg.h" /* #define debug fatal */ #define DEC21143_TICK_SHIFT 16 #define N_REGS 32 #define ROM_WIDTH 6 struct dec21143_data { struct interrupt irq; int irq_was_asserted; /* PCI: */ int pci_little_endian; /* Ethernet address, and a network which we are connected to: */ uint8_t mac[6]; struct net *net; /* SROM emulation: */ uint8_t srom[1 << (ROM_WIDTH + 1)]; int srom_curbit; int srom_opcode; int srom_opcode_has_started; int srom_addr; /* MII PHY emulation: */ uint16_t mii_phy_reg[MII_NPHY * 32]; int mii_state; int mii_bit; int mii_opcode; int mii_phyaddr; int mii_regaddr; /* 21143 registers: */ uint32_t reg[N_REGS]; /* Internal TX state: */ uint64_t cur_tx_addr; unsigned char *cur_tx_buf; int cur_tx_buf_len; int tx_idling; int tx_idling_threshold; /* Internal RX state: */ uint64_t cur_rx_addr; unsigned char *cur_rx_buf; int cur_rx_buf_len; int cur_rx_offset; }; /* Internal states during MII data stream decode: */ #define MII_STATE_RESET 0 #define MII_STATE_START_WAIT 1 #define MII_STATE_READ_OP 2 #define MII_STATE_READ_PHYADDR_REGADDR 3 #define MII_STATE_A 4 #define MII_STATE_D 5 #define MII_STATE_IDLE 6 /* * dec21143_rx(): * * Receive a packet. (If there is no current packet, then check for newly * arrived ones. If the current packet couldn't be fully transfered the * last time, then continue on that packet.) */ int dec21143_rx(struct cpu *cpu, struct dec21143_data *d) { uint64_t addr = d->cur_rx_addr, bufaddr; unsigned char descr[16]; uint32_t rdes0, rdes1, rdes2, rdes3; int bufsize, buf1_size, buf2_size, i, writeback_len = 4, to_xfer; /* No current packet? Then check for new ones. */ if (d->cur_rx_buf == NULL) { /* Nothing available? Then abort. */ if (!net_ethernet_rx_avail(d->net, d)) return 0; /* Get the next packet into our buffer: */ net_ethernet_rx(d->net, d, &d->cur_rx_buf, &d->cur_rx_buf_len); /* Append a 4 byte CRC: */ d->cur_rx_buf_len += 4; CHECK_ALLOCATION(d->cur_rx_buf = (unsigned char *) realloc(d->cur_rx_buf, d->cur_rx_buf_len)); /* Well... the CRC is just zeros, for now. */ memset(d->cur_rx_buf + d->cur_rx_buf_len - 4, 0, 4); d->cur_rx_offset = 0; } /* fatal("{ dec21143_rx: base = 0x%08x }\n", (int)addr); */ addr &= 0x7fffffff; if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t), MEM_READ, PHYSICAL | NO_EXCEPTIONS)) { fatal("[ dec21143_rx: memory_rw failed! ]\n"); return 0; } rdes0 = descr[0] + (descr[1]<<8) + (descr[2]<<16) + (descr[3]<<24); /* Only use descriptors owned by the 21143: */ if (!(rdes0 & TDSTAT_OWN)) { d->reg[CSR_STATUS/8] |= STATUS_RU; return 0; } if (!cpu->memory_rw(cpu, cpu->mem, addr + sizeof(uint32_t), descr + sizeof(uint32_t), sizeof(uint32_t) * 3, MEM_READ, PHYSICAL | NO_EXCEPTIONS)) { fatal("[ dec21143_rx: memory_rw failed! ]\n"); return 0; } rdes1 = descr[4] + (descr[5]<<8) + (descr[6]<<16) + (descr[7]<<24); rdes2 = descr[8] + (descr[9]<<8) + (descr[10]<<16) + (descr[11]<<24); rdes3 = descr[12] + (descr[13]<<8) + (descr[14]<<16) + (descr[15]<<24); buf1_size = rdes1 & TDCTL_SIZE1; buf2_size = (rdes1 & TDCTL_SIZE2) >> TDCTL_SIZE2_SHIFT; bufaddr = buf1_size? rdes2 : rdes3; bufsize = buf1_size? buf1_size : buf2_size; d->reg[CSR_STATUS/8] &= ~STATUS_RS; if (rdes1 & TDCTL_ER) d->cur_rx_addr = d->reg[CSR_RXLIST / 8]; else { if (rdes1 & TDCTL_CH) d->cur_rx_addr = rdes3; else d->cur_rx_addr += 4 * sizeof(uint32_t); } debug("{ RX (%llx): 0x%08x 0x%08x 0x%x 0x%x: buf %i bytes at 0x%x }\n", (long long)addr, rdes0, rdes1, rdes2, rdes3, bufsize, (int)bufaddr); bufaddr &= 0x7fffffff; /* Turn off all status bits, and give up ownership: */ rdes0 = 0x00000000; to_xfer = d->cur_rx_buf_len - d->cur_rx_offset; if (to_xfer > bufsize) to_xfer = bufsize; /* DMA bytes from the packet into emulated physical memory: */ for (i=0; imemory_rw(cpu, cpu->mem, bufaddr + i, d->cur_rx_buf + d->cur_rx_offset + i, 1, MEM_WRITE, PHYSICAL | NO_EXCEPTIONS); /* fatal(" %02x", d->cur_rx_buf[d->cur_rx_offset + i]); */ } /* Was this the first buffer in a frame? Then mark it as such. */ if (d->cur_rx_offset == 0) rdes0 |= TDSTAT_Rx_FS; d->cur_rx_offset += to_xfer; /* Frame completed? */ if (d->cur_rx_offset >= d->cur_rx_buf_len) { rdes0 |= TDSTAT_Rx_LS; /* Set the frame length: */ rdes0 |= (d->cur_rx_buf_len << 16) & TDSTAT_Rx_FL; /* Frame too long? (1518 is max ethernet frame length) */ if (d->cur_rx_buf_len > 1518) rdes0 |= TDSTAT_Rx_TL; /* Cause a receiver interrupt: */ d->reg[CSR_STATUS/8] |= STATUS_RI; free(d->cur_rx_buf); d->cur_rx_buf = NULL; d->cur_rx_buf_len = 0; } /* Descriptor writeback: */ descr[ 0] = rdes0; descr[ 1] = rdes0 >> 8; descr[ 2] = rdes0 >> 16; descr[ 3] = rdes0 >> 24; if (writeback_len > 1) { descr[ 4] = rdes1; descr[ 5] = rdes1 >> 8; descr[ 6] = rdes1 >> 16; descr[ 7] = rdes1 >> 24; descr[ 8] = rdes2; descr[ 9] = rdes2 >> 8; descr[10] = rdes2 >> 16; descr[11] = rdes2 >> 24; descr[12] = rdes3; descr[13] = rdes3 >> 8; descr[14] = rdes3 >> 16; descr[15] = rdes3 >> 24; } if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t) * writeback_len, MEM_WRITE, PHYSICAL | NO_EXCEPTIONS)) { fatal("[ dec21143_rx: memory_rw failed! ]\n"); return 0; } return 1; } /* * dec21143_tx(): * * Transmit a packet, if the guest OS has marked a descriptor as containing * data to transmit. */ int dec21143_tx(struct cpu *cpu, struct dec21143_data *d) { uint64_t addr = d->cur_tx_addr, bufaddr; unsigned char descr[16]; uint32_t tdes0, tdes1, tdes2, tdes3; int bufsize, buf1_size, buf2_size, i; addr &= 0x7fffffff; if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t), MEM_READ, PHYSICAL | NO_EXCEPTIONS)) { fatal("[ dec21143_tx: memory_rw failed! ]\n"); return 0; } tdes0 = descr[0] + (descr[1]<<8) + (descr[2]<<16) + (descr[3]<<24); /* fatal("{ dec21143_tx: base=0x%08x, tdes0=0x%08x }\n", (int)addr, (int)tdes0); */ /* Only process packets owned by the 21143: */ if (!(tdes0 & TDSTAT_OWN)) { if (d->tx_idling > d->tx_idling_threshold) { d->reg[CSR_STATUS/8] |= STATUS_TU; d->tx_idling = 0; } else d->tx_idling ++; return 0; } if (!cpu->memory_rw(cpu, cpu->mem, addr + sizeof(uint32_t), descr + sizeof(uint32_t), sizeof(uint32_t) * 3, MEM_READ, PHYSICAL | NO_EXCEPTIONS)) { fatal("[ dec21143_tx: memory_rw failed! ]\n"); return 0; } tdes1 = descr[4] + (descr[5]<<8) + (descr[6]<<16) + (descr[7]<<24); tdes2 = descr[8] + (descr[9]<<8) + (descr[10]<<16) + (descr[11]<<24); tdes3 = descr[12] + (descr[13]<<8) + (descr[14]<<16) + (descr[15]<<24); buf1_size = tdes1 & TDCTL_SIZE1; buf2_size = (tdes1 & TDCTL_SIZE2) >> TDCTL_SIZE2_SHIFT; bufaddr = buf1_size? tdes2 : tdes3; bufsize = buf1_size? buf1_size : buf2_size; d->reg[CSR_STATUS/8] &= ~STATUS_TS; if (tdes1 & TDCTL_ER) d->cur_tx_addr = d->reg[CSR_TXLIST / 8]; else { if (tdes1 & TDCTL_CH) d->cur_tx_addr = tdes3; else d->cur_tx_addr += 4 * sizeof(uint32_t); } /* fatal("{ TX (%llx): 0x%08x 0x%08x 0x%x 0x%x: buf %i bytes at 0x%x }\n", (long long)addr, tdes0, tdes1, tdes2, tdes3, bufsize, (int)bufaddr); */ bufaddr &= 0x7fffffff; /* Assume no error: */ tdes0 &= ~ (TDSTAT_Tx_UF | TDSTAT_Tx_EC | TDSTAT_Tx_LC | TDSTAT_Tx_NC | TDSTAT_Tx_LO | TDSTAT_Tx_TO | TDSTAT_ES); if (tdes1 & TDCTL_Tx_SET) { /* * Setup Packet. * * TODO. For now, just ignore it, and pretend it worked. */ /* fatal("{ TX: setup packet }\n"); */ if (bufsize != 192) fatal("[ dec21143: setup packet len = %i, should be" " 192! ]\n", (int)bufsize); if (tdes1 & TDCTL_Tx_IC) d->reg[CSR_STATUS/8] |= STATUS_TI; /* New descriptor values, according to the docs: */ tdes0 = 0x7fffffff; tdes1 = 0xffffffff; tdes2 = 0xffffffff; tdes3 = 0xffffffff; } else { /* * Data Packet. */ /* fatal("{ TX: data packet: "); */ if (tdes1 & TDCTL_Tx_FS) { /* First segment. Let's allocate a new buffer: */ /* fatal("new frame }\n"); */ CHECK_ALLOCATION(d->cur_tx_buf = (unsigned char *) malloc(bufsize)); d->cur_tx_buf_len = 0; } else { /* Not first segment. Increase the length of the current buffer: */ /* fatal("continuing last frame }\n"); */ if (d->cur_tx_buf == NULL) fatal("[ dec21143: WARNING! tx: middle " "segment, but no first segment?! ]\n"); CHECK_ALLOCATION(d->cur_tx_buf = (unsigned char *) realloc(d->cur_tx_buf, d->cur_tx_buf_len + bufsize)); } /* "DMA" data from emulated physical memory into the buf: */ for (i=0; imemory_rw(cpu, cpu->mem, bufaddr + i, d->cur_tx_buf + d->cur_tx_buf_len + i, 1, MEM_READ, PHYSICAL | NO_EXCEPTIONS); /* fatal(" %02x", d->cur_tx_buf[ d->cur_tx_buf_len + i]); */ } d->cur_tx_buf_len += bufsize; /* Last segment? Then actually transmit it: */ if (tdes1 & TDCTL_Tx_LS) { /* fatal("{ TX: data frame complete. }\n"); */ if (d->net != NULL) { net_ethernet_tx(d->net, d, d->cur_tx_buf, d->cur_tx_buf_len); } else { static int warn = 0; if (!warn) fatal("[ dec21143: WARNING! Not " "connected to a network! ]\n"); warn = 1; } free(d->cur_tx_buf); d->cur_tx_buf = NULL; d->cur_tx_buf_len = 0; /* Interrupt, if Tx_IC is set: */ if (tdes1 & TDCTL_Tx_IC) d->reg[CSR_STATUS/8] |= STATUS_TI; } /* We are done with this segment. */ tdes0 &= ~TDSTAT_OWN; } /* Error summary: */ if (tdes0 & (TDSTAT_Tx_UF | TDSTAT_Tx_EC | TDSTAT_Tx_LC | TDSTAT_Tx_NC | TDSTAT_Tx_LO | TDSTAT_Tx_TO)) tdes0 |= TDSTAT_ES; /* Descriptor writeback: */ descr[ 0] = tdes0; descr[ 1] = tdes0 >> 8; descr[ 2] = tdes0 >> 16; descr[ 3] = tdes0 >> 24; descr[ 4] = tdes1; descr[ 5] = tdes1 >> 8; descr[ 6] = tdes1 >> 16; descr[ 7] = tdes1 >> 24; descr[ 8] = tdes2; descr[ 9] = tdes2 >> 8; descr[10] = tdes2 >> 16; descr[11] = tdes2 >> 24; descr[12] = tdes3; descr[13] = tdes3 >> 8; descr[14] = tdes3 >> 16; descr[15] = tdes3 >> 24; if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t) * 4, MEM_WRITE, PHYSICAL | NO_EXCEPTIONS)) { fatal("[ dec21143_tx: memory_rw failed! ]\n"); return 0; } return 1; } DEVICE_TICK(dec21143) { struct dec21143_data *d = (struct dec21143_data *) extra; int asserted; if (d->reg[CSR_OPMODE / 8] & OPMODE_ST) while (dec21143_tx(cpu, d)) ; if (d->reg[CSR_OPMODE / 8] & OPMODE_SR) while (dec21143_rx(cpu, d)) ; /* Normal and Abnormal interrupt summary: */ d->reg[CSR_STATUS / 8] &= ~(STATUS_NIS | STATUS_AIS); if (d->reg[CSR_STATUS / 8] & 0x00004845) d->reg[CSR_STATUS / 8] |= STATUS_NIS; if (d->reg[CSR_STATUS / 8] & 0x0c0037ba) d->reg[CSR_STATUS / 8] |= STATUS_AIS; asserted = d->reg[CSR_STATUS / 8] & d->reg[CSR_INTEN / 8] & 0x0c01ffff; if (asserted) INTERRUPT_ASSERT(d->irq); if (!asserted && d->irq_was_asserted) INTERRUPT_DEASSERT(d->irq); /* Remember assertion flag: */ d->irq_was_asserted = asserted; } /* * mii_access(): * * This function handles accesses to the MII. Data streams seem to be of the * following format: * * vv---- starting delimiter * ... 01 xx yyyyy zzzzz a[a] dddddddddddddddd * ^---- I am starting with mii_bit = 0 here * * where x = opcode (10 = read, 01 = write) * y = PHY address * z = register address * a = on Reads: ACK bit (returned, should be 0) * on Writes: _TWO_ dummy bits (10) * d = 16 bits of data (MSB first) */ static void mii_access(struct cpu *cpu, struct dec21143_data *d, uint32_t oldreg, uint32_t idata) { int obit, ibit = 0; uint16_t tmp; /* Only care about data during clock cycles: */ if (!(idata & MIIROM_MDC)) return; if (idata & MIIROM_MDC && oldreg & MIIROM_MDC) return; /* fatal("[ mii_access(): 0x%08x ]\n", (int)idata); */ if (idata & MIIROM_BR) { fatal("[ mii_access(): MIIROM_BR: TODO ]\n"); return; } obit = idata & MIIROM_MDO? 1 : 0; if (d->mii_state >= MII_STATE_START_WAIT && d->mii_state <= MII_STATE_READ_PHYADDR_REGADDR && idata & MIIROM_MIIDIR) fatal("[ mii_access(): bad dir? ]\n"); switch (d->mii_state) { case MII_STATE_RESET: /* Wait for a starting delimiter (0 followed by 1). */ if (obit) return; if (idata & MIIROM_MIIDIR) return; /* fatal("[ mii_access(): got a 0 delimiter ]\n"); */ d->mii_state = MII_STATE_START_WAIT; d->mii_opcode = 0; d->mii_phyaddr = 0; d->mii_regaddr = 0; break; case MII_STATE_START_WAIT: /* Wait for a starting delimiter (0 followed by 1). */ if (!obit) return; if (idata & MIIROM_MIIDIR) { d->mii_state = MII_STATE_RESET; return; } /* fatal("[ mii_access(): got a 1 delimiter ]\n"); */ d->mii_state = MII_STATE_READ_OP; d->mii_bit = 0; break; case MII_STATE_READ_OP: if (d->mii_bit == 0) { d->mii_opcode = obit << 1; /* fatal("[ mii_access(): got first opcode bit " "(%i) ]\n", obit); */ } else { d->mii_opcode |= obit; /* fatal("[ mii_access(): got opcode = %i ]\n", d->mii_opcode); */ d->mii_state = MII_STATE_READ_PHYADDR_REGADDR; } d->mii_bit ++; break; case MII_STATE_READ_PHYADDR_REGADDR: /* fatal("[ mii_access(): got phy/reg addr bit nr %i (%i)" " ]\n", d->mii_bit - 2, obit); */ if (d->mii_bit <= 6) d->mii_phyaddr |= obit << (6-d->mii_bit); else d->mii_regaddr |= obit << (11-d->mii_bit); d->mii_bit ++; if (d->mii_bit >= 12) { /* fatal("[ mii_access(): phyaddr=0x%x regaddr=0x" "%x ]\n", d->mii_phyaddr, d->mii_regaddr); */ d->mii_state = MII_STATE_A; } break; case MII_STATE_A: switch (d->mii_opcode) { case MII_COMMAND_WRITE: if (d->mii_bit >= 13) d->mii_state = MII_STATE_D; break; case MII_COMMAND_READ: ibit = 0; d->mii_state = MII_STATE_D; break; default:debug("[ mii_access(): UNIMPLEMENTED MII opcode " "%i (probably just a bug in GXemul's " "MII data stream handling) ]\n", d->mii_opcode); d->mii_state = MII_STATE_RESET; } d->mii_bit ++; break; case MII_STATE_D: switch (d->mii_opcode) { case MII_COMMAND_WRITE: if (idata & MIIROM_MIIDIR) fatal("[ mii_access(): write: bad dir? ]\n"); obit = obit? (0x8000 >> (d->mii_bit - 14)) : 0; tmp = d->mii_phy_reg[(d->mii_phyaddr << 5) + d->mii_regaddr] | obit; if (d->mii_bit >= 29) { d->mii_state = MII_STATE_IDLE; debug("[ mii_access(): WRITE to phyaddr=0x%x " "regaddr=0x%x: 0x%04x ]\n", d->mii_phyaddr, d->mii_regaddr, tmp); } break; case MII_COMMAND_READ: if (!(idata & MIIROM_MIIDIR)) break; tmp = d->mii_phy_reg[(d->mii_phyaddr << 5) + d->mii_regaddr]; if (d->mii_bit == 13) debug("[ mii_access(): READ phyaddr=0x%x " "regaddr=0x%x: 0x%04x ]\n", d->mii_phyaddr, d->mii_regaddr, tmp); ibit = tmp & (0x8000 >> (d->mii_bit - 13)); if (d->mii_bit >= 28) d->mii_state = MII_STATE_IDLE; break; } d->mii_bit ++; break; case MII_STATE_IDLE: d->mii_bit ++; if (d->mii_bit >= 31) d->mii_state = MII_STATE_RESET; break; } d->reg[CSR_MIIROM / 8] &= ~MIIROM_MDI; if (ibit) d->reg[CSR_MIIROM / 8] |= MIIROM_MDI; } /* * srom_access(): * * This function handles reads from the Ethernet Address ROM. This is not a * 100% correct implementation, as it was reverse-engineered from OpenBSD * sources; it seems to work with OpenBSD, NetBSD, and Linux, though. * * Each transfer (if I understood this correctly) is of the following format: * * 1xx yyyyyy zzzzzzzzzzzzzzzz * * where 1xx = operation (6 means a Read), * yyyyyy = ROM address * zz...z = data * * y and z are _both_ read and written to at the same time; this enables the * operating system to sense the number of bits in y (when reading, all y bits * are 1 except the last one). */ static void srom_access(struct cpu *cpu, struct dec21143_data *d, uint32_t oldreg, uint32_t idata) { int obit, ibit; /* debug("CSR9 WRITE! 0x%08x\n", (int)idata); */ /* New selection? Then reset internal state. */ if (idata & MIIROM_SR && !(oldreg & MIIROM_SR)) { d->srom_curbit = 0; d->srom_opcode = 0; d->srom_opcode_has_started = 0; d->srom_addr = 0; } /* Only care about data during clock cycles: */ if (!(idata & MIIROM_SROMSK)) return; obit = 0; ibit = idata & MIIROM_SROMDI? 1 : 0; /* debug("CLOCK CYCLE! (bit %i): ", d->srom_curbit); */ /* * Linux sends more zeroes before starting the actual opcode, than * OpenBSD and NetBSD. Hopefully this is correct. (I'm just guessing * that all opcodes should start with a 1, perhaps that's not really * the case.) */ if (!ibit && !d->srom_opcode_has_started) return; if (d->srom_curbit < 3) { d->srom_opcode_has_started = 1; d->srom_opcode <<= 1; d->srom_opcode |= ibit; /* debug("opcode input '%i'\n", ibit); */ } else { switch (d->srom_opcode) { case TULIP_SROM_OPC_READ: if (d->srom_curbit < ROM_WIDTH + 3) { obit = d->srom_curbit < ROM_WIDTH + 2; d->srom_addr <<= 1; d->srom_addr |= ibit; } else { uint16_t romword = d->srom[d->srom_addr*2] + (d->srom[d->srom_addr*2+1] << 8); if (d->srom_curbit == ROM_WIDTH + 3) debug("[ dec21143: ROM read from offset" " 0x%03x: 0x%04x ]\n", d->srom_addr, romword); obit = romword & (0x8000 >> (d->srom_curbit - ROM_WIDTH - 3))? 1 : 0; } break; default:fatal("[ dec21243: unimplemented SROM/EEPROM " "opcode %i ]\n", d->srom_opcode); } d->reg[CSR_MIIROM / 8] &= ~MIIROM_SROMDO; if (obit) d->reg[CSR_MIIROM / 8] |= MIIROM_SROMDO; /* debug("input '%i', output '%i'\n", ibit, obit); */ } d->srom_curbit ++; /* * Done opcode + addr + data? Then restart. (At least NetBSD does * sequential reads without turning selection off and then on.) */ if (d->srom_curbit >= 3 + ROM_WIDTH + 16) { d->srom_curbit = 0; d->srom_opcode = 0; d->srom_opcode_has_started = 0; d->srom_addr = 0; } } /* * dec21143_reset(): * * Set the 21143 registers, SROM, and MII data to reasonable values. */ static void dec21143_reset(struct cpu *cpu, struct dec21143_data *d) { int leaf; if (d->cur_rx_buf != NULL) free(d->cur_rx_buf); if (d->cur_tx_buf != NULL) free(d->cur_tx_buf); d->cur_rx_buf = d->cur_tx_buf = NULL; memset(d->reg, 0, sizeof(uint32_t) * N_REGS); memset(d->srom, 0, sizeof(d->srom)); memset(d->mii_phy_reg, 0, sizeof(d->mii_phy_reg)); /* Register values at reset, according to the manual: */ d->reg[CSR_BUSMODE / 8] = 0xfe000000; /* csr0 */ d->reg[CSR_MIIROM / 8] = 0xfff483ff; /* csr9 */ d->reg[CSR_SIACONN / 8] = 0xffff0000; /* csr13 */ d->reg[CSR_SIATXRX / 8] = 0xffffffff; /* csr14 */ d->reg[CSR_SIAGEN / 8] = 0x8ff00000; /* csr15 */ d->tx_idling_threshold = 10; d->cur_rx_addr = d->cur_tx_addr = 0; /* Version (= 1) and Chip count (= 1): */ d->srom[TULIP_ROM_SROM_FORMAT_VERION] = 1; d->srom[TULIP_ROM_CHIP_COUNT] = 1; /* Set the MAC address: */ memcpy(d->srom + TULIP_ROM_IEEE_NETWORK_ADDRESS, d->mac, 6); leaf = 30; d->srom[TULIP_ROM_CHIPn_DEVICE_NUMBER(0)] = 0; d->srom[TULIP_ROM_CHIPn_INFO_LEAF_OFFSET(0)] = leaf & 255; d->srom[TULIP_ROM_CHIPn_INFO_LEAF_OFFSET(0)+1] = leaf >> 8; d->srom[leaf+TULIP_ROM_IL_SELECT_CONN_TYPE] = 0; /* Not used? */ d->srom[leaf+TULIP_ROM_IL_MEDIA_COUNT] = 2; leaf += TULIP_ROM_IL_MEDIAn_BLOCK_BASE; d->srom[leaf] = 7; /* descriptor length */ d->srom[leaf+1] = TULIP_ROM_MB_21142_SIA; d->srom[leaf+2] = TULIP_ROM_MB_MEDIA_100TX; /* here comes 4 bytes of GPIO control/data settings */ leaf += d->srom[leaf]; d->srom[leaf] = 15; /* descriptor length */ d->srom[leaf+1] = TULIP_ROM_MB_21142_MII; d->srom[leaf+2] = 0; /* PHY nr */ d->srom[leaf+3] = 0; /* len of select sequence */ d->srom[leaf+4] = 0; /* len of reset sequence */ /* 5,6, 7,8, 9,10, 11,12, 13,14 = unused by GXemul */ leaf += d->srom[leaf]; /* MII PHY initial state: */ d->mii_state = MII_STATE_RESET; /* PHY #0: */ d->mii_phy_reg[MII_BMSR] = BMSR_100TXFDX | BMSR_10TFDX | BMSR_ACOMP | BMSR_ANEG | BMSR_LINK; } DEVICE_ACCESS(dec21143) { struct dec21143_data *d = (struct dec21143_data *) extra; uint64_t idata = 0, odata = 0; uint32_t oldreg = 0; int regnr = relative_addr >> 3; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len | d->pci_little_endian); if ((relative_addr & 7) == 0 && regnr < N_REGS) { if (writeflag == MEM_READ) { odata = d->reg[regnr]; } else { oldreg = d->reg[regnr]; switch (regnr) { case CSR_STATUS / 8: /* Zero-on-write */ d->reg[regnr] &= ~(idata & 0x0c01ffff); break; case CSR_MISSED / 8: /* Read only */ break; default:d->reg[regnr] = idata; } } } else fatal("[ dec21143: WARNING! unaligned access (0x%x) ]\n", (int)relative_addr); switch (relative_addr) { case CSR_BUSMODE: /* csr0 */ if (writeflag == MEM_WRITE) { /* Software reset takes effect immediately. */ if (idata & BUSMODE_SWR) { dec21143_reset(cpu, d); idata &= ~BUSMODE_SWR; } } break; case CSR_TXPOLL: /* csr1 */ if (writeflag == MEM_READ) fatal("[ dec21143: UNIMPLEMENTED READ from " "txpoll ]\n"); d->tx_idling = d->tx_idling_threshold; dev_dec21143_tick(cpu, extra); break; case CSR_RXPOLL: /* csr2 */ if (writeflag == MEM_READ) fatal("[ dec21143: UNIMPLEMENTED READ from " "rxpoll ]\n"); dev_dec21143_tick(cpu, extra); break; case CSR_RXLIST: /* csr3 */ if (writeflag == MEM_WRITE) { debug("[ dec21143: setting RXLIST to 0x%x ]\n", (int)idata); if (idata & 0x3) fatal("[ dec21143: WARNING! RXLIST not aligned" "? (0x%llx) ]\n", (long long)idata); idata &= ~0x3; d->cur_rx_addr = idata; } break; case CSR_TXLIST: /* csr4 */ if (writeflag == MEM_WRITE) { debug("[ dec21143: setting TXLIST to 0x%x ]\n", (int)idata); if (idata & 0x3) fatal("[ dec21143: WARNING! TXLIST not aligned" "? (0x%llx) ]\n", (long long)idata); idata &= ~0x3; d->cur_tx_addr = idata; } break; case CSR_STATUS: /* csr5 */ case CSR_INTEN: /* csr7 */ if (writeflag == MEM_WRITE) { /* Recalculate interrupt assertion. */ dev_dec21143_tick(cpu, extra); } break; case CSR_OPMODE: /* csr6: */ if (writeflag == MEM_WRITE) { if (idata & 0x02000000) { /* A must-be-one bit. */ idata &= ~0x02000000; } if (idata & OPMODE_ST) { idata &= ~OPMODE_ST; } else { /* Turned off TX? Then idle: */ d->reg[CSR_STATUS/8] |= STATUS_TPS; } if (idata & OPMODE_SR) { idata &= ~OPMODE_SR; } else { /* Turned off RX? Then go to stopped state: */ d->reg[CSR_STATUS/8] &= ~STATUS_RS; } idata &= ~(OPMODE_HBD | OPMODE_SCR | OPMODE_PCS | OPMODE_PS | OPMODE_SF | OPMODE_TTM | OPMODE_FD); if (idata & OPMODE_PNIC_IT) { idata &= ~OPMODE_PNIC_IT; d->tx_idling = d->tx_idling_threshold; } if (idata != 0) { fatal("[ dec21143: UNIMPLEMENTED OPMODE bits" ": 0x%08x ]\n", (int)idata); } dev_dec21143_tick(cpu, extra); } break; case CSR_MISSED: /* csr8 */ break; case CSR_MIIROM: /* csr9 */ if (writeflag == MEM_WRITE) { if (idata & MIIROM_MDC) mii_access(cpu, d, oldreg, idata); else srom_access(cpu, d, oldreg, idata); } break; case CSR_SIASTAT: /* csr12 */ /* Auto-negotiation status = Good. */ odata = SIASTAT_ANS_FLPGOOD; break; case CSR_SIATXRX: /* csr14 */ /* Auto-negotiation Enabled */ odata = SIATXRX_ANE; break; case CSR_SIACONN: /* csr13 */ case CSR_SIAGEN: /* csr15 */ /* Don't print warnings for these, for now. */ break; default:if (writeflag == MEM_READ) fatal("[ dec21143: read from unimplemented 0x%02x ]\n", (int)relative_addr); else fatal("[ dec21143: write to unimplemented 0x%02x: " "0x%02x ]\n", (int)relative_addr, (int)idata); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len | d->pci_little_endian, odata); return 1; } DEVINIT(dec21143) { struct dec21143_data *d; char name2[100]; CHECK_ALLOCATION(d = (struct dec21143_data *) malloc(sizeof(struct dec21143_data))); memset(d, 0, sizeof(struct dec21143_data)); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); d->pci_little_endian = devinit->pci_little_endian; net_generate_unique_mac(devinit->machine, d->mac); net_add_nic(devinit->machine->emul->net, d, d->mac); d->net = devinit->machine->emul->net; dec21143_reset(devinit->machine->cpus[0], d); snprintf(name2, sizeof(name2), "%s [%02x:%02x:%02x:%02x:%02x:%02x]", devinit->name, d->mac[0], d->mac[1], d->mac[2], d->mac[3], d->mac[4], d->mac[5]); memory_device_register(devinit->machine->memory, name2, devinit->addr, 0x100, dev_dec21143_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_dec21143_tick, d, DEC21143_TICK_SHIFT); /* * NetBSD/cats uses memory accesses, OpenBSD/cats uses I/O registers. * Let's make a mirror from the memory range to the I/O range: */ dev_ram_init(devinit->machine, devinit->addr2, 0x100, DEV_RAM_MIRROR | DEV_RAM_MIGHT_POINT_TO_DEVICES, devinit->addr); return 1; } gxemul-0.6.1/src/devices/dev_8253.cc000644 001750 001750 00000015362 13402411502 017213 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Intel 8253/8254 Programmable Interval Timer * * TODO/NOTE: * The timers don't really count down. Timer 0 causes clock interrupts * at a specific frequency, but reading the counter register would not * result in anything meaningful. * * (Split counter[] into reset value and current value.) */ #include #include #include #include "cpu.h" #include "device.h" #include "emul.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "timer.h" #include "thirdparty/i8253reg.h" /* #define debug fatal */ #define DEV_8253_LENGTH 4 #define TICK_SHIFT 14 struct pit8253_data { int in_use; int counter_select; uint8_t mode_byte; int mode[3]; int counter[3]; int hz[3]; struct timer *timer0; struct interrupt irq; int pending_interrupts_timer0; }; static void timer0_tick(struct timer *t, void *extra) { struct pit8253_data *d = (struct pit8253_data *) extra; d->pending_interrupts_timer0 ++; /* printf("%i ", d->pending_interrupts_timer0); fflush(stdout); */ } DEVICE_TICK(8253) { struct pit8253_data *d = (struct pit8253_data *) extra; if (!d->in_use) return; // Generate interrupts regardless of (d->mode[0] & 0x0e)? // (It seems like Linux/MALTA kernels like this.) if (d->pending_interrupts_timer0 > 0) INTERRUPT_ASSERT(d->irq); } DEVICE_ACCESS(8253) { struct pit8253_data *d = (struct pit8253_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); d->in_use = 1; switch (relative_addr) { case I8253_TIMER_CNTR0: case I8253_TIMER_CNTR1: case I8253_TIMER_CNTR2: if (writeflag == MEM_WRITE) { switch (d->mode_byte & 0x30) { case I8253_TIMER_LSB: case I8253_TIMER_16BIT: d->counter[relative_addr] &= 0xff00; d->counter[relative_addr] |= (idata & 0xff); break; case I8253_TIMER_MSB: d->counter[relative_addr] &= 0x00ff; d->counter[relative_addr] |= ((idata&0xff)<<8); if (d->counter[relative_addr] != 0) d->hz[relative_addr] = (int) ( I8253_TIMER_FREQ / (float) d->counter[relative_addr] + 0.5); else d->hz[relative_addr] = 0; debug("[ 8253: counter %i set to %i (%i Hz) " "]\n", relative_addr, d->counter[ relative_addr], d->hz[relative_addr]); switch (relative_addr) { case 0: if (d->timer0 == NULL) d->timer0 = timer_add( d->hz[0], timer0_tick, d); else timer_update_frequency( d->timer0, d->hz[0]); break; case 1: fatal("TODO: DMA refresh?\n"); exit(1); case 2: fatal("TODO: 8253 tone generation?\n"); break; } break; default:fatal("[ 8253: huh? writing to counter" " %i but neither from msb nor lsb? ]\n", relative_addr); exit(1); } } else { switch (d->mode_byte & 0x30) { case I8253_TIMER_LSB: case I8253_TIMER_16BIT: odata = d->counter[relative_addr] & 0xff; break; case I8253_TIMER_MSB: odata = (d->counter[relative_addr] >> 8) & 0xff; break; default:fatal("[ 8253: huh? reading from counter" " %i but neither from msb nor lsb? ]\n", relative_addr); exit(1); } } /* Switch from LSB to MSB, if accessing as 16-bit word: */ if ((d->mode_byte & 0x30) == I8253_TIMER_16BIT) d->mode_byte &= ~I8253_TIMER_LSB; break; case I8253_TIMER_MODE: if (writeflag == MEM_WRITE) { d->mode_byte = idata; d->counter_select = idata >> 6; if (d->counter_select > 2) { debug("[ 8253: attempt to select counter 3," " which doesn't exist. ]\n"); d->counter_select = 0; } d->mode[d->counter_select] = idata & 0x0e; debug("[ 8253: select=%i mode=0x%x ", d->counter_select, d->mode[d->counter_select]); if (idata & 0x30) { switch (idata & 0x30) { case I8253_TIMER_LSB: debug("LSB "); break; case I8253_TIMER_16BIT: debug("LSB+"); case I8253_TIMER_MSB: debug("MSB "); } } debug("]\n"); if (idata & I8253_TIMER_BCD) { fatal("[ 8253: BCD not yet implemented ]\n"); exit(1); } } else { debug("[ 8253: read; can this actually happen? ]\n"); odata = d->mode_byte; } break; default:if (writeflag == MEM_WRITE) { fatal("[ 8253: unimplemented write to address 0x%x" " data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { fatal("[ 8253: unimplemented read from address 0x%x " "]\n", (int)relative_addr); } exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(8253) { struct pit8253_data *d; CHECK_ALLOCATION(d = (struct pit8253_data *) malloc(sizeof(struct pit8253_data))); memset(d, 0, sizeof(struct pit8253_data)); d->in_use = devinit->in_use; INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); /* Don't cause interrupt, by default. */ d->mode[0] = I8253_TIMER_RATEGEN; d->mode[1] = I8253_TIMER_RATEGEN; d->mode[2] = I8253_TIMER_RATEGEN; devinit->machine->isa_pic_data.pending_timer_interrupts = &d->pending_interrupts_timer0; memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_8253_LENGTH, dev_8253_access, (void *)d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_8253_tick, d, TICK_SHIFT); return 1; } gxemul-0.6.1/src/devices/dev_eagle.cc000644 001750 001750 00000013560 13402411502 017665 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Motorola MPC105 "Eagle" host bridge */ #include #include #include #include "bus_isa.h" #include "bus_pci.h" #include "cpu.h" #include "device.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" struct eagle_data { struct interrupt irq; struct pci_data *pci_data; }; DEVICE_ACCESS(eagle) { struct eagle_data *d = (struct eagle_data *) extra; uint64_t idata = 0, odata = 0; int bus, dev, func, reg; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN); /* * Pass accesses to ISA ports 0xcf8 and 0xcfc onto bus_pci_*: */ switch (relative_addr) { case 0: /* Address: */ bus_pci_decompose_1(idata, &bus, &dev, &func, ®); bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, reg); break; case 4: /* Data: */ bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ? &odata : &idata, len, writeflag); break; } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len|MEM_PCI_LITTLE_ENDIAN, odata); return 1; } DEVINIT(eagle) { struct eagle_data *d; uint64_t pci_io_offset, pci_mem_offset; uint64_t isa_portbase = 0, isa_membase = 0; uint64_t pci_portbase = 0, pci_membase = 0; char pci_irq_base[300]; char isa_irq_base[300]; CHECK_ALLOCATION(d = (struct eagle_data *) malloc(sizeof(struct eagle_data))); memset(d, 0, sizeof(struct eagle_data)); /* The interrupt path to the CPU at which we are connected: */ INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); /* * According to http://www.beatjapan.org/mirror/www.be.com/ * aboutbe/benewsletter/Issue27.html#Cookbook : * * "HARDWARE MEMORY MAP * The MPC105 defines the physical memory map of the system as * follows: * * Start Size Description * * 0x00000000 0x40000000 Physical RAM * 0x40000000 0x40000000 Other system memory * (motherboard glue regs) * 0x80000000 0x00800000 ISA I/O * 0x81000000 0x3E800000 PCI I/O * 0xBFFFFFF0 0x00000010 PCI/ISA interrupt acknowledge * 0xC0000000 0x3F000000 PCI memory * 0xFF000000 0x01000000 ROM/flash */ /* TODO: Make these work like the BE web page stated... */ pci_io_offset = 0x80000000ULL; pci_mem_offset = 0xc0000000ULL; pci_portbase = 0x00000000ULL; pci_membase = 0x00000000ULL; isa_portbase = 0x80000000ULL; isa_membase = 0xc0000000ULL; switch (devinit->machine->machine_type) { /* case MACHINE_BEBOX: snprintf(pci_irq_base, sizeof(pci_irq_base), "%s.bebox", devinit->interrupt_path); snprintf(isa_irq_base, sizeof(isa_irq_base), "%s.bebox.5", devinit->interrupt_path); break; */ default: snprintf(pci_irq_base, sizeof(pci_irq_base), "%s", devinit->interrupt_path); snprintf(isa_irq_base, sizeof(isa_irq_base), "%s", devinit->interrupt_path); } /* Create a PCI bus: */ d->pci_data = bus_pci_init(devinit->machine, devinit->interrupt_path, pci_io_offset, pci_mem_offset, pci_portbase, pci_membase, pci_irq_base, isa_portbase, isa_membase, isa_irq_base); /* Add the PCI glue for the controller itself: */ bus_pci_add(devinit->machine, d->pci_data, devinit->machine->memory, 0, 0, 0, "eagle"); /* ADDR and DATA configuration ports in ISA space: */ memory_device_register(devinit->machine->memory, "eagle", isa_portbase + BUS_PCI_ADDR, 8, dev_eagle_access, d, DM_DEFAULT, NULL); switch (devinit->machine->machine_type) { /* case MACHINE_BEBOX: bus_isa_init(devinit->machine, isa_irq_base, BUS_ISA_IDE0 | BUS_ISA_VGA, isa_portbase, isa_membase); bus_pci_add(devinit->machine, d->pci_data, devinit->machine->memory, 0, 11, 0, "i82378zb"); break; */ case MACHINE_PREP: bus_pci_add(devinit->machine, d->pci_data, devinit->machine->memory, 0, 11, 0, "ibm_isa"); break; case MACHINE_MVMEPPC: bus_isa_init(devinit->machine, isa_irq_base, BUS_ISA_LPTBASE_3BC, isa_portbase, isa_membase); switch (devinit->machine->machine_subtype) { case MACHINE_MVMEPPC_1600: bus_pci_add(devinit->machine, d->pci_data, devinit->machine->memory, 0, 11, 0, "i82378zb"); break; default:fatal("unimplemented machine subtype for " "eagle/mvmeppc\n"); exit(1); } break; default:fatal("unimplemented machine type for eagle\n"); exit(1); } devinit->return_ptr = d->pci_data; return 1; } gxemul-0.6.1/src/devices/dev_pckbc.cc000644 001750 001750 00000101645 13402411502 017674 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: 8042 PC keyboard controller (+ 8242WB Keyboard/Mouse controller) * * This module includes emulation of the 8048 keyboard chip too. * * Quick source of good info: http://my.execpc.com/~geezer/osd/kbd/kbd.txt * * Some scancode listings for various types: * http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html * http://www.computer-engineering.org/ps2keyboard/scancodes3.html * https://www.win.tue.nl/~aeb/linux/kbd/scancodes-10.html#scancodesets * http://nixdoc.net/man-pages/irix/man7/pckeyboard.7.html */ #include #include #include #include "console.h" #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/kbdreg.h" // #define PCKBC_DEBUG // #define debug fatal // Should be 256 to emulate a real 8042? Having a larger value allows // pasting of larger text chunks which is useful in the emulator. // #define MAX_8042_QUEUELEN 256 #define MAX_8042_QUEUELEN 32768 #define PC_DATA 0 #define PC_CMD 0 #define PC_STATUS 1 #define PS2_TXBUF 0 #define PS2_RXBUF 1 #define PS2_CONTROL 2 #define PS2_CONTROL_TXINTEN (1 << 2) #define PS2_CONTROL_RXINTEN (1 << 3) #define PS2_STATUS 3 #define PS2_STATUS_TXEMPTY (1 << 3) #define PS2_STATUS_RXFULL (1 << 4) #define PS2 100 // internal offset #define PCKBC_TICKSHIFT 15 struct pckbc_data { int console_handle; int in_use; int reg[DEV_PCKBC_LENGTH]; struct interrupt irq_keyboard; struct interrupt irq_mouse; int currently_asserted[2]; int type; int pc_style_flag; /* TODO: one of these for each port? */ int clocksignal; int rx_int_enable[2]; int tx_int_enable[2]; int scanning_enabled[2]; int translation_table; int state[2]; int cmdbyte; int output_byte; int last_scancode; unsigned key_queue[2][MAX_8042_QUEUELEN]; int head[2], tail[2]; int mouse_x; int mouse_y; int mouse_buttons; }; #define STATE_NORMAL 0 #define STATE_LDCMDBYTE 1 #define STATE_RDCMDBYTE 2 #define STATE_WAITING_FOR_TRANSLTABLE 3 #define STATE_WAITING_FOR_RATE 4 #define STATE_WAITING_FOR_ONEKEY_MB 5 #define STATE_WAITING_FOR_AUX 6 #define STATE_WAITING_FOR_AUX_OUT 7 #define STATE_LDOUTPUT 8 #define STATE_RDOUTPUT 9 /* * pckbc_add_code(): * * Adds a byte to the data queue. */ void pckbc_add_code(struct pckbc_data *d, int code, int port) { /* Add at the head, read at the tail: */ d->head[port] = (d->head[port]+1) % MAX_8042_QUEUELEN; if (d->head[port] == d->tail[port]) fatal("[ pckbc: queue overrun, port %i! ]\n", port); d->key_queue[port][d->head[port]] = code; } /* * pckbc_get_code(): * * Reads a byte from a data queue. */ int pckbc_get_code(struct pckbc_data *d, int port) { if (d->head[port] == d->tail[port]) fatal("[ pckbc: queue empty, port %i! ]\n", port); else d->tail[port] = (d->tail[port]+1) % MAX_8042_QUEUELEN; return d->key_queue[port][d->tail[port]]; } /* * ascii_to_scancodes_type1(): * * Conversion from ASCII codes to default (US) keyboard scancodes. */ static void ascii_to_pc_scancodes_type1(int a, struct pckbc_data *d) { int old_head; int p = 0; /* port */ int shift = 0, ctrl = 0; if (a >= 'A' && a <= 'Z') { a += 32; shift = 1; } if ((a >= 1 && a <= 26) && (a!='\n' && a!='\t' && a!='\b' && a!='\r')) { a += 96; ctrl = 1; } if (a=='!') { a = '1'; shift = 1; } if (a=='@') { a = '2'; shift = 1; } if (a=='#') { a = '3'; shift = 1; } if (a=='$') { a = '4'; shift = 1; } if (a=='%') { a = '5'; shift = 1; } if (a=='^') { a = '6'; shift = 1; } if (a=='&') { a = '7'; shift = 1; } if (a=='*') { a = '8'; shift = 1; } if (a=='(') { a = '9'; shift = 1; } if (a==')') { a = '0'; shift = 1; } if (a=='_') { a = '-'; shift = 1; } if (a=='+') { a = '='; shift = 1; } if (a=='{') { a = '['; shift = 1; } if (a=='}') { a = ']'; shift = 1; } if (a==':') { a = ';'; shift = 1; } if (a=='"') { a = '\''; shift = 1; } if (a=='|') { a = '\\'; shift = 1; } if (a=='<') { a = ','; shift = 1; } if (a=='>') { a = '.'; shift = 1; } if (a=='?') { a = '/'; shift = 1; } if (a=='~') { a = '`'; shift = 1; } if (shift) pckbc_add_code(d, 0x2a, p); else pckbc_add_code(d, 0x2a + 0x80, p); if (ctrl) pckbc_add_code(d, 0x1d, p); /* * Note: The ugly hack used to add release codes for all of these * keys is as follows: we remember how much of the kbd buf that * is in use here, before we add any scancode. After we've added * one or more scancodes (ie an optional shift + another key) * then we duplicate the last scancode | 0x80 _if_ the kbd buf * was altered. */ old_head = d->head[p]; if (a==27) pckbc_add_code(d, 0x01, p); if (a=='1') pckbc_add_code(d, 0x02, p); if (a=='2') pckbc_add_code(d, 0x03, p); if (a=='3') pckbc_add_code(d, 0x04, p); if (a=='4') pckbc_add_code(d, 0x05, p); if (a=='5') pckbc_add_code(d, 0x06, p); if (a=='6') pckbc_add_code(d, 0x07, p); if (a=='7') pckbc_add_code(d, 0x08, p); if (a=='8') pckbc_add_code(d, 0x09, p); if (a=='9') pckbc_add_code(d, 0x0a, p); if (a=='0') pckbc_add_code(d, 0x0b, p); if (a=='-') pckbc_add_code(d, 0x0c, p); if (a=='=') pckbc_add_code(d, 0x0d, p); if (a=='!') { pckbc_add_code(d, 0x2a, p); pckbc_add_code(d, 0x02, p); } if (a=='@') { pckbc_add_code(d, 0x2a, p); pckbc_add_code(d, 0x03, p); } if (a=='#') { pckbc_add_code(d, 0x2a, p); pckbc_add_code(d, 0x04, p); } if (a=='$') { pckbc_add_code(d, 0x2a, p); pckbc_add_code(d, 0x05, p); } if (a=='%') { pckbc_add_code(d, 0x2a, p); pckbc_add_code(d, 0x06, p); } if (a=='^') { pckbc_add_code(d, 0x2a, p); pckbc_add_code(d, 0x07, p); } if (a=='&') { pckbc_add_code(d, 0x2a, p); pckbc_add_code(d, 0x08, p); } if (a=='*') { pckbc_add_code(d, 0x2a, p); pckbc_add_code(d, 0x09, p); } if (a=='(') { pckbc_add_code(d, 0x2a, p); pckbc_add_code(d, 0x0a, p); } if (a=='\b') pckbc_add_code(d, 0x0e, p); if (a=='\t') pckbc_add_code(d, 0x0f, p); if (a=='q') pckbc_add_code(d, 0x10, p); if (a=='w') pckbc_add_code(d, 0x11, p); if (a=='e') pckbc_add_code(d, 0x12, p); if (a=='r') pckbc_add_code(d, 0x13, p); if (a=='t') pckbc_add_code(d, 0x14, p); if (a=='y') pckbc_add_code(d, 0x15, p); if (a=='u') pckbc_add_code(d, 0x16, p); if (a=='i') pckbc_add_code(d, 0x17, p); if (a=='o') pckbc_add_code(d, 0x18, p); if (a=='p') pckbc_add_code(d, 0x19, p); if (a=='[') pckbc_add_code(d, 0x1a, p); if (a==']') pckbc_add_code(d, 0x1b, p); if (a=='\n' || a=='\r') pckbc_add_code(d, 0x1c, p); if (a=='a') pckbc_add_code(d, 0x1e, p); if (a=='s') pckbc_add_code(d, 0x1f, p); if (a=='d') pckbc_add_code(d, 0x20, p); if (a=='f') pckbc_add_code(d, 0x21, p); if (a=='g') pckbc_add_code(d, 0x22, p); if (a=='h') pckbc_add_code(d, 0x23, p); if (a=='j') pckbc_add_code(d, 0x24, p); if (a=='k') pckbc_add_code(d, 0x25, p); if (a=='l') pckbc_add_code(d, 0x26, p); if (a==';') pckbc_add_code(d, 0x27, p); if (a=='\'') pckbc_add_code(d, 0x28, p); if (a=='`') pckbc_add_code(d, 0x29, p); if (a=='\\') pckbc_add_code(d, 0x2b, p); if (a=='z') pckbc_add_code(d, 0x2c, p); if (a=='x') pckbc_add_code(d, 0x2d, p); if (a=='c') pckbc_add_code(d, 0x2e, p); if (a=='v') pckbc_add_code(d, 0x2f, p); if (a=='b') pckbc_add_code(d, 0x30, p); if (a=='n') pckbc_add_code(d, 0x31, p); if (a=='m') pckbc_add_code(d, 0x32, p); if (a==',') pckbc_add_code(d, 0x33, p); if (a=='.') pckbc_add_code(d, 0x34, p); if (a=='/') pckbc_add_code(d, 0x35, p); if (a==' ') pckbc_add_code(d, 0x39, p); /* Add release code, if a key was pressed: */ if (d->head[p] != old_head) { int code = d->key_queue[p][d->head[p]] | 0x80; pckbc_add_code(d, code, p); } /* Release ctrl: */ if (ctrl) pckbc_add_code(d, 0x1d + 0x80, p); } /* * ascii_to_scancodes_type2(): * * Conversion from ASCII codes to default (US) keyboard scancodes. */ static void ascii_to_pc_scancodes_type2(int a, struct pckbc_data *d) { int old_head; int p = 0; /* port */ int shift = 0, ctrl = 0; if (a >= 'A' && a <= 'Z') { a += 32; shift = 1; } if ((a >= 1 && a <= 26) && (a!='\n' && a!='\t' && a!='\b' && a!='\r')) { a += 96; ctrl = 1; } if (a=='!') { a = '1'; shift = 1; } if (a=='@') { a = '2'; shift = 1; } if (a=='#') { a = '3'; shift = 1; } if (a=='$') { a = '4'; shift = 1; } if (a=='%') { a = '5'; shift = 1; } if (a=='^') { a = '6'; shift = 1; } if (a=='&') { a = '7'; shift = 1; } if (a=='*') { a = '8'; shift = 1; } if (a=='(') { a = '9'; shift = 1; } if (a==')') { a = '0'; shift = 1; } if (a=='_') { a = '-'; shift = 1; } if (a=='+') { a = '='; shift = 1; } if (a=='{') { a = '['; shift = 1; } if (a=='}') { a = ']'; shift = 1; } if (a==':') { a = ';'; shift = 1; } if (a=='"') { a = '\''; shift = 1; } if (a=='|') { a = '\\'; shift = 1; } if (a=='<') { a = ','; shift = 1; } if (a=='>') { a = '.'; shift = 1; } if (a=='?') { a = '/'; shift = 1; } if (a=='~') { a = '`'; shift = 1; } if (shift) pckbc_add_code(d, 0x12, p); if (ctrl) pckbc_add_code(d, 0x14, p); /* * Note: The ugly hack used to add release codes for all of these * keys is as follows: we remember how much of the kbd buf that * is in use here, before we add any scancode. After we've added * one or more scancodes (ie an optional shift + another key) * then we add 0xf0 + the last scancode _if_ the kbd buf was altered. */ old_head = d->head[p]; if (a==27) pckbc_add_code(d, 0x76, p); if (a=='1') pckbc_add_code(d, 0x16, p); if (a=='2') pckbc_add_code(d, 0x1e, p); if (a=='3') pckbc_add_code(d, 0x26, p); if (a=='4') pckbc_add_code(d, 0x25, p); if (a=='5') pckbc_add_code(d, 0x2e, p); if (a=='6') pckbc_add_code(d, 0x36, p); if (a=='7') pckbc_add_code(d, 0x3d, p); if (a=='8') pckbc_add_code(d, 0x3e, p); if (a=='9') pckbc_add_code(d, 0x46, p); if (a=='0') pckbc_add_code(d, 0x45, p); if (a=='-') pckbc_add_code(d, 0x4e, p); if (a=='=') pckbc_add_code(d, 0x55, p); if (a=='\b') pckbc_add_code(d, 0x66, p); if (a=='\t') pckbc_add_code(d, 0x0d, p); if (a=='q') pckbc_add_code(d, 0x15, p); if (a=='w') pckbc_add_code(d, 0x1d, p); if (a=='e') pckbc_add_code(d, 0x24, p); if (a=='r') pckbc_add_code(d, 0x2d, p); if (a=='t') pckbc_add_code(d, 0x2c, p); if (a=='y') pckbc_add_code(d, 0x35, p); if (a=='u') pckbc_add_code(d, 0x3c, p); if (a=='i') pckbc_add_code(d, 0x43, p); if (a=='o') pckbc_add_code(d, 0x44, p); if (a=='p') pckbc_add_code(d, 0x4d, p); if (a=='[') pckbc_add_code(d, 0x54, p); if (a==']') pckbc_add_code(d, 0x5b, p); if (a=='\n' || a=='\r') pckbc_add_code(d, 0x5a, p); if (a=='a') pckbc_add_code(d, 0x1c, p); if (a=='s') pckbc_add_code(d, 0x1b, p); if (a=='d') pckbc_add_code(d, 0x23, p); if (a=='f') pckbc_add_code(d, 0x2b, p); if (a=='g') pckbc_add_code(d, 0x34, p); if (a=='h') pckbc_add_code(d, 0x33, p); if (a=='j') pckbc_add_code(d, 0x3b, p); if (a=='k') pckbc_add_code(d, 0x42, p); if (a=='l') pckbc_add_code(d, 0x4b, p); if (a==';') pckbc_add_code(d, 0x4c, p); if (a=='\'') pckbc_add_code(d, 0x52, p); if (a=='`') pckbc_add_code(d, 0x0e, p); // ? if (a=='\\') pckbc_add_code(d, 0x5d, p); // 0x5c? if (a=='z') pckbc_add_code(d, 0x1a, p); if (a=='x') pckbc_add_code(d, 0x22, p); if (a=='c') pckbc_add_code(d, 0x21, p); if (a=='v') pckbc_add_code(d, 0x2a, p); if (a=='b') pckbc_add_code(d, 0x32, p); if (a=='n') pckbc_add_code(d, 0x31, p); if (a=='m') pckbc_add_code(d, 0x3a, p); if (a==',') pckbc_add_code(d, 0x41, p); if (a=='.') pckbc_add_code(d, 0x49, p); if (a=='/') pckbc_add_code(d, 0x4a, p); if (a==' ') pckbc_add_code(d, 0x29, p); /* Add release code, if a key was pressed: */ if (d->head[p] != old_head) { int code = d->key_queue[p][d->head[p]]; pckbc_add_code(d, 0xf0, p); pckbc_add_code(d, code, p); } /* Release shift and ctrl: */ if (shift) { pckbc_add_code(d, 0xf0, p); pckbc_add_code(d, 0x12, p); } if (ctrl) { pckbc_add_code(d, 0xf0, p); pckbc_add_code(d, 0x14, p); } } /* * ascii_to_scancodes_type3(): * * Conversion from ASCII codes to default (US) keyboard scancodes. */ static void ascii_to_pc_scancodes_type3(int a, struct pckbc_data *d) { int old_head; int p = 0; /* port */ int shift = 0, ctrl = 0; if (a >= 'A' && a <= 'Z') { a += 32; shift = 1; } if ((a >= 1 && a <= 26) && (a!='\n' && a!='\t' && a!='\b' && a!='\r')) { a += 96; ctrl = 1; } if (a=='!') { a = '1'; shift = 1; } if (a=='@') { a = '2'; shift = 1; } if (a=='#') { a = '3'; shift = 1; } if (a=='$') { a = '4'; shift = 1; } if (a=='%') { a = '5'; shift = 1; } if (a=='^') { a = '6'; shift = 1; } if (a=='&') { a = '7'; shift = 1; } if (a=='*') { a = '8'; shift = 1; } if (a=='(') { a = '9'; shift = 1; } if (a==')') { a = '0'; shift = 1; } if (a=='_') { a = '-'; shift = 1; } if (a=='+') { a = '='; shift = 1; } if (a=='{') { a = '['; shift = 1; } if (a=='}') { a = ']'; shift = 1; } if (a==':') { a = ';'; shift = 1; } if (a=='"') { a = '\''; shift = 1; } if (a=='|') { a = '\\'; shift = 1; } if (a=='<') { a = ','; shift = 1; } if (a=='>') { a = '.'; shift = 1; } if (a=='?') { a = '/'; shift = 1; } if (a=='~') { a = '`'; shift = 1; } if (shift) pckbc_add_code(d, 0x12, p); if (ctrl) pckbc_add_code(d, 0x11, p); /* * Note: The ugly hack used to add release codes for all of these * keys is as follows: we remember how much of the kbd buf that * is in use here, before we add any scancode. After we've added * one or more scancodes (ie an optional shift + another key) * then we add 0xf0 + the last scancode _if_ the kbd buf was altered. */ old_head = d->head[p]; if (a==27) pckbc_add_code(d, 0x08, p); if (a=='1') pckbc_add_code(d, 0x16, p); if (a=='2') pckbc_add_code(d, 0x1e, p); if (a=='3') pckbc_add_code(d, 0x26, p); if (a=='4') pckbc_add_code(d, 0x25, p); if (a=='5') pckbc_add_code(d, 0x2e, p); if (a=='6') pckbc_add_code(d, 0x36, p); if (a=='7') pckbc_add_code(d, 0x3d, p); if (a=='8') pckbc_add_code(d, 0x3e, p); if (a=='9') pckbc_add_code(d, 0x46, p); if (a=='0') pckbc_add_code(d, 0x45, p); if (a=='-') pckbc_add_code(d, 0x4e, p); if (a=='=') pckbc_add_code(d, 0x55, p); if (a=='\b') pckbc_add_code(d, 0x66, p); if (a=='\t') pckbc_add_code(d, 0x0d, p); if (a=='q') pckbc_add_code(d, 0x15, p); if (a=='w') pckbc_add_code(d, 0x1d, p); if (a=='e') pckbc_add_code(d, 0x24, p); if (a=='r') pckbc_add_code(d, 0x2d, p); if (a=='t') pckbc_add_code(d, 0x2c, p); if (a=='y') pckbc_add_code(d, 0x35, p); if (a=='u') pckbc_add_code(d, 0x3c, p); if (a=='i') pckbc_add_code(d, 0x43, p); if (a=='o') pckbc_add_code(d, 0x44, p); if (a=='p') pckbc_add_code(d, 0x4d, p); if (a=='[') pckbc_add_code(d, 0x54, p); if (a==']') pckbc_add_code(d, 0x5b, p); if (a=='\n' || a=='\r') pckbc_add_code(d, 0x5a, p); if (a=='a') pckbc_add_code(d, 0x1c, p); if (a=='s') pckbc_add_code(d, 0x1b, p); if (a=='d') pckbc_add_code(d, 0x23, p); if (a=='f') pckbc_add_code(d, 0x2b, p); if (a=='g') pckbc_add_code(d, 0x34, p); if (a=='h') pckbc_add_code(d, 0x33, p); if (a=='j') pckbc_add_code(d, 0x3b, p); if (a=='k') pckbc_add_code(d, 0x42, p); if (a=='l') pckbc_add_code(d, 0x4b, p); if (a==';') pckbc_add_code(d, 0x4c, p); if (a=='\'') pckbc_add_code(d, 0x52, p); if (a=='`') pckbc_add_code(d, 0x0e, p); // ? if (a=='\\') pckbc_add_code(d, 0x5d, p); // 0x5c? if (a=='z') pckbc_add_code(d, 0x1a, p); if (a=='x') pckbc_add_code(d, 0x22, p); if (a=='c') pckbc_add_code(d, 0x21, p); if (a=='v') pckbc_add_code(d, 0x2a, p); if (a=='b') pckbc_add_code(d, 0x32, p); if (a=='n') pckbc_add_code(d, 0x31, p); if (a=='m') pckbc_add_code(d, 0x3a, p); if (a==',') pckbc_add_code(d, 0x41, p); if (a=='.') pckbc_add_code(d, 0x49, p); if (a=='/') pckbc_add_code(d, 0x4a, p); if (a==' ') pckbc_add_code(d, 0x29, p); /* Add release code, if a key was pressed: */ if (d->head[p] != old_head) { int code = d->key_queue[p][d->head[p]]; pckbc_add_code(d, 0xf0, p); pckbc_add_code(d, code, p); } /* Release shift and ctrl: */ if (shift) { pckbc_add_code(d, 0xf0, p); pckbc_add_code(d, 0x12, p); } if (ctrl) { pckbc_add_code(d, 0xf0, p); pckbc_add_code(d, 0x11, p); } } void pckbc_reassert_interrupts(struct pckbc_data *d) { bool ints_enabled = true; // if (d->cmdbyte & KC8_KDISABLE) // ints_enabled = false; for (int port_nr = 0; port_nr < 2; port_nr++) { /* * Cause receive interrupt, if there's something in the * receive buffer: (Otherwise deassert the interrupt.) */ if (d->head[port_nr] != d->tail[port_nr] && ints_enabled && d->rx_int_enable[port_nr]) { if (!d->currently_asserted[port_nr]) { // fatal("[ pckbc: interrupt port %i ]\n", port_nr); if (port_nr == 0) INTERRUPT_ASSERT(d->irq_keyboard); else INTERRUPT_ASSERT(d->irq_mouse); } d->currently_asserted[port_nr] = 1; } else { if (d->currently_asserted[port_nr]) { // fatal("[ pckbc: DEASSERT interrupt port %i ]\n", port_nr); if (port_nr == 0) INTERRUPT_DEASSERT(d->irq_keyboard); else INTERRUPT_DEASSERT(d->irq_mouse); } d->currently_asserted[port_nr] = 0; } } } DEVICE_TICK(pckbc) { struct pckbc_data *d = (struct pckbc_data *) extra; int ch; // Keyboard input: if (d->in_use) { while (console_charavail(d->console_handle)) { ch = console_readchar(d->console_handle); if (ch >= 0) { switch (d->translation_table) { case 1: ascii_to_pc_scancodes_type1(ch, d); break; case 2: ascii_to_pc_scancodes_type2(ch, d); break; case 3: ascii_to_pc_scancodes_type3(ch, d); break; default:fatal("[ pckbc: unimplemented translation table type %i ]\n", d->translation_table); } } } } // Mouse input: /* Don't do mouse updates if we're running in serial console mode: */ if (cpu->machine->x11_md.in_use && d->state[1] == STATE_NORMAL && d->scanning_enabled[1]) { int mouse_x, mouse_y, mouse_buttons, mouse_fb_nr; console_getmouse(&mouse_x, &mouse_y, &mouse_buttons, &mouse_fb_nr); int xdelta = mouse_x - d->mouse_x; int ydelta = d->mouse_y - mouse_y; // note: inverted const int m = 100; if (xdelta > m) xdelta = m; if (xdelta < -m) xdelta = -m; if (ydelta > m) ydelta = m; if (ydelta < -m) ydelta = -m; /* Only send update if there is an actual diff. */ if (xdelta != 0 || ydelta != 0 || d->mouse_buttons != mouse_buttons) { d->mouse_x = mouse_x; d->mouse_y = mouse_y; d->mouse_buttons = mouse_buttons; // See "The default protocol" at // https://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html uint8_t b1 = 0x08; uint8_t b2 = xdelta; uint8_t b3 = ydelta; b1 |= (mouse_buttons & 4) >> 2; // Left b1 |= (mouse_buttons & 2) << 1; // Middle b1 |= (mouse_buttons & 1) << 1; // Right b1 |= ((xdelta >> 8) & 1) << 4; b1 |= ((ydelta >> 8) & 1) << 5; // printf("x=%i y=%i b1=%02x %02x %02x\n", xdelta, ydelta, b1,b2,b3); pckbc_add_code(d, b1, 1); pckbc_add_code(d, b2, 1); pckbc_add_code(d, b3, 1); } } pckbc_reassert_interrupts(d); } /* * dev_pckbc_command(): * * Handle commands to the 8048 in the emulated keyboard. */ static void dev_pckbc_command(struct pckbc_data *d, int port_nr) { int cmd = d->type == PCKBC_8242 ? d->reg[PS2_TXBUF] : d->reg[PC_CMD]; #if 0 // Mouse port debugging: if (port_nr == 1) fatal("[ pckbc: (port %i) command 0x%02x ]\n", port_nr, cmd); #endif if (d->state[port_nr] == STATE_WAITING_FOR_TRANSLTABLE) { debug("[ pckbc: (port %i) switching to translation table " "0x%02x ]\n", port_nr, cmd); switch (cmd) { case 0: // TODO. "Writing 0xf0 followed by 0 queries the mode, // resulting in a scancode byte 43, 41 or 3f from the // keyboard." according to // https://www.win.tue.nl/~aeb/linux/kbd/scancodes-10.html#scancodesets fatal("[ pckbc: TODO: return current translation table ]\n"); break; case 1: // Fall-through. case 2: // Fall-through. case 3: d->translation_table = cmd; break; default:fatal("[ pckbc: (port %i) translation table " "0x%02x is NOT YET IMPLEMENTED ]\n", port_nr, cmd); } // Hack for OpenBSD/cats and NetBSD/cats: if (d->type != PCKBC_8242) { fatal("[ pckbc: TODO: hack for non-8242. figure out how to deal with this ]\n"); d->translation_table = 1; } pckbc_add_code(d, KBR_ACK, port_nr); d->state[port_nr] = STATE_NORMAL; return; } if (d->state[port_nr] == STATE_WAITING_FOR_RATE) { debug("[ pckbc: (port %i) received Typematic/Sample Rate data: " "0x%02x ]\n", port_nr, cmd); pckbc_add_code(d, KBR_ACK, port_nr); d->state[port_nr] = STATE_NORMAL; return; } if (d->state[port_nr] == STATE_WAITING_FOR_ONEKEY_MB) { debug("[ pckbc: (port %i) received One-key make/break data: " "0x%02x ]\n", port_nr, cmd); pckbc_add_code(d, KBR_ACK, port_nr); d->state[port_nr] = STATE_NORMAL; return; } if (d->state[port_nr] == STATE_WAITING_FOR_AUX) { debug("[ pckbc: (port %i) received aux data: " "0x%02x ]\n", port_nr, cmd); /* Echo back. */ pckbc_add_code(d, cmd, port_nr); d->state[port_nr] = STATE_NORMAL; return; } if (d->state[port_nr] == STATE_WAITING_FOR_AUX_OUT) { debug("[ pckbc: (port %i) received aux out data: " "0x%02x ]\n", port_nr, cmd); /* Echo back. */ pckbc_add_code(d, cmd, port_nr); d->state[port_nr] = STATE_NORMAL; return; } switch (cmd) { case 0x00: /* * TODO: What does this do? This is possibly due to an * error in the handling of some other command code. */ pckbc_add_code(d, KBR_ACK, port_nr); break; case KBC_MODEIND: /* Set LEDs */ /* Just ACK, no LEDs are actually set. */ pckbc_add_code(d, KBR_ACK, port_nr); break; case KBC_ECHO: pckbc_add_code(d, KBR_ECHO, port_nr); break; case KBC_SETTABLE: pckbc_add_code(d, KBR_ACK, port_nr); d->state[port_nr] = STATE_WAITING_FOR_TRANSLTABLE; break; case KBC_ENABLE: d->scanning_enabled[port_nr] = 1; pckbc_add_code(d, KBR_ACK, port_nr); break; case KBC_DISABLE: d->scanning_enabled[port_nr] = 0; pckbc_add_code(d, KBR_ACK, port_nr); break; case KBC_SETDEFAULT: pckbc_add_code(d, KBR_ACK, port_nr); break; case KBC_GETID: /* Get keyboard/mouse ID. NOTE/TODO: Ugly hardcoded answer. */ pckbc_add_code(d, KBR_ACK, port_nr); if (port_nr == 0) { // Keyboard: pckbc_add_code(d, 0xab, port_nr); pckbc_add_code(d, 0x41, port_nr); } else { // Mouse: pckbc_add_code(d, 0x00, port_nr); pckbc_add_code(d, 0x00, port_nr); } break; case KBC_TYPEMATIC: /* * Keyboard: Set typematic (auto-repeat) delay/speed. * PS/2 mouse: Set sample ratre. */ pckbc_add_code(d, KBR_ACK, port_nr); d->state[port_nr] = STATE_WAITING_FOR_RATE; break; case KBC_ALLKEYS_TMB: /* "Make all keys typematic/make/break" */ pckbc_add_code(d, KBR_ACK, port_nr); break; case KBC_ONEKEY_MB: /* "Make one key typematic/make/break" */ pckbc_add_code(d, KBR_ACK, port_nr); d->state[port_nr] = STATE_WAITING_FOR_ONEKEY_MB; break; case KBC_RESET: pckbc_add_code(d, KBR_ACK, port_nr); pckbc_add_code(d, KBR_RSTDONE, port_nr); if (port_nr == 1) { // Mouse (based on NetBSD's pckbport/pms.c) sends // mouse ID after RSTDONE: pckbc_add_code(d, 0x00, port_nr); } /* * Disable interrupts during reset, or Linux 2.6 * prints warnings about spurious interrupts. */ // d->rx_int_enable = 0; d->scanning_enabled[port_nr] = 0; break; default: pckbc_add_code(d, KBR_RESEND, port_nr); // Error fatal("[ pckbc: UNIMPLEMENTED command" " 0x%02x (port %i) ]\n", cmd, port_nr); } } DEVICE_ACCESS(pckbc) { struct pckbc_data *d = (struct pckbc_data *) extra; uint64_t idata = 0, odata = 0; int port_nr = 0; size_t i; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); #ifdef PCKBC_DEBUG if (writeflag == MEM_WRITE) fatal("[ pckbc: write to addr 0x%x: 0x%x ]\n", (int)relative_addr, (int)idata); else fatal("[ pckbc: read from addr 0x%x ]\n", (int)relative_addr); #endif /* For JAZZ-based machines: */ if (relative_addr >= 0x60) { relative_addr -= 0x60; if (relative_addr != 0) relative_addr = 1; } else if (d->type == PCKBC_8242) { /* 8242 PS2-style: */ /* when using 8-byte alignment... */ relative_addr /= sizeof(uint64_t); /* port_nr = 0 for keyboard, 1 for mouse */ port_nr = (relative_addr >> 2); relative_addr &= 3; relative_addr += PS2; } else if (d->pc_style_flag) { /* PC-style: */ if (relative_addr != 0 && relative_addr != 4) { /* TODO (port 0x61) */ odata = 0x21; { static int x = 0; x++; if (x&1) odata ^= 0x10; } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } if (relative_addr != 0) relative_addr = 1; } else { /* Others... Non-Jazz ARC-based machines etc. */ if (relative_addr != 0) relative_addr = 1; } switch (relative_addr) { /* * 8042 (PC): */ case 0: /* data */ if (writeflag==MEM_READ) { switch (d->state[port_nr]) { case STATE_RDCMDBYTE: odata = d->cmdbyte; d->state[port_nr] = STATE_NORMAL; break; case STATE_RDOUTPUT: odata = d->output_byte; d->state[port_nr] = STATE_NORMAL; break; default:if (d->head[0] != d->tail[0]) { odata = pckbc_get_code(d, 0); d->last_scancode = odata; } else { odata = d->last_scancode; d->last_scancode |= 0x80; } } /* debug("[ pckbc: read from DATA: 0x%02x ]\n", (int)odata); */ } else { if (port_nr == 1) { fatal("[ pckbc: write to DATA:"); for (i=0; istate[port_nr]) { case STATE_LDCMDBYTE: d->cmdbyte = idata; d->rx_int_enable[port_nr] = d->cmdbyte & (KC8_KENABLE | KC8_MENABLE) ? 1 : 0; d->state[port_nr] = STATE_NORMAL; break; case STATE_LDOUTPUT: d->output_byte = idata; d->state[port_nr] = STATE_NORMAL; break; default:d->reg[relative_addr] = idata; dev_pckbc_command(d, port_nr); } } break; case 1: /* control */ if (writeflag==MEM_READ) { odata = 0; /* "Data in buffer" bit */ if (d->head[0] != d->tail[0] || d->state[port_nr] == STATE_RDCMDBYTE || d->state[port_nr] == STATE_RDOUTPUT) odata |= KBS_DIB; if (d->state[port_nr] == STATE_RDCMDBYTE) odata |= KBS_OCMD; odata |= KBS_NOSEC; /* debug("[ pckbc: read from CTL status port: " "0x%02x ]\n", (int)odata); */ } else { debug("[ pckbc: write to CTL:"); for (i=0; ireg[relative_addr] = idata; switch (idata) { case 0x10: case 0x11: /* TODO: For now, don't print warnings about these. NetBSD sends these. */ break; case K_RDCMDBYTE: d->state[port_nr] = STATE_RDCMDBYTE; break; case K_LDCMDBYTE: d->state[port_nr] = STATE_LDCMDBYTE; break; case 0xa7: d->cmdbyte |= KC8_MDISABLE; break; case 0xa8: d->cmdbyte &= ~KC8_MDISABLE; break; case 0xa9: /* test auxiliary port */ debug("[ pckbc: CONTROL 0xa9, TODO ]\n"); break; case 0xaa: /* keyboard self-test */ pckbc_add_code(d, 0x55, port_nr); break; case 0xab: /* keyboard interface self-test */ pckbc_add_code(d, 0x00, port_nr); break; case 0xad: d->cmdbyte |= KC8_KDISABLE; break; case 0xae: d->cmdbyte &= ~KC8_KDISABLE; break; case 0xd0: d->state[port_nr] = STATE_RDOUTPUT; break; case 0xd1: d->state[port_nr] = STATE_LDOUTPUT; break; case 0xd3: /* write to auxiliary device output buffer */ debug("[ pckbc: CONTROL 0xd3, TODO ]\n"); d->state[port_nr] = STATE_WAITING_FOR_AUX_OUT; break; case 0xd4: /* write to auxiliary port */ debug("[ pckbc: CONTROL 0xd4, TODO ]\n"); d->state[port_nr] = STATE_WAITING_FOR_AUX; break; default: fatal("[ pckbc: unknown CONTROL 0x%x ]\n", (int)idata); d->state[port_nr] = STATE_NORMAL; } } break; /* * 8242 (PS2): */ case PS2 + PS2_TXBUF: if (writeflag==MEM_READ) { odata = random() & 0xff; debug("[ pckbc: read from port %i, PS2_TXBUF: " "0x%x ]\n", port_nr, (int)odata); } else { debug("[ pckbc: write to port %i, PS2_TXBUF: " "0x%llx ]\n", port_nr, (long long)idata); /* Handle keyboard commands: */ d->reg[PS2_TXBUF] = idata; dev_pckbc_command(d, port_nr); } break; case PS2 + PS2_RXBUF: if (writeflag==MEM_READ) { /* TODO: What should be returned if no data is available? */ odata = 0; if (d->head[port_nr] != d->tail[port_nr]) odata = pckbc_get_code(d, port_nr); debug("[ pckbc: read from port %i, PS2_RXBUF: " "0x%02x ]\n", port_nr, (int)odata); } else { debug("[ pckbc: write to port %i, PS2_RXBUF: " "0x%llx ]\n", port_nr, (long long)idata); } break; case PS2 + PS2_CONTROL: if (writeflag==MEM_READ) { debug("[ pckbc: read from port %i, PS2_CONTROL" " ]\n", port_nr); } else { debug("[ pckbc: write to port %i, PS2_CONTROL:" " 0x%llx ]\n", port_nr, (long long)idata); d->clocksignal = (idata & 0x10) ? 1 : 0; d->rx_int_enable[port_nr] = (idata & PS2_CONTROL_RXINTEN) ? 1 : 0; d->tx_int_enable[port_nr] = (idata & PS2_CONTROL_TXINTEN) ? 1 : 0; // HACK/TODO: NetBSD/sgimips' X11 seems to work when // interrupts are enabled, but it seems to not turn // them on. Having this here makes it work, but it not // the correct solution. if (port_nr == 1) { d->rx_int_enable[port_nr] = 1; } } break; case PS2 + PS2_STATUS: if (writeflag==MEM_READ) { odata = d->clocksignal + PS2_STATUS_TXEMPTY; if (d->head[port_nr] != d->tail[port_nr]) { /* receiced data available */ odata |= PS2_STATUS_RXFULL; } //debug("[ pckbc: read from port %i, PS2_STATUS: " // "0x%llx ]\n", port_nr, (long long)odata); } else { debug("[ pckbc: write to port %i, PS2_STATUS: " "0x%llx ]\n", port_nr, (long long)idata); } break; default: if (writeflag==MEM_READ) { debug("[ pckbc: read from unimplemented reg %i ]\n", (int)relative_addr); odata = d->reg[relative_addr % DEV_PCKBC_LENGTH]; } else { debug("[ pckbc: write to unimplemented reg %i:", (int)relative_addr); for (i=0; ireg[relative_addr % DEV_PCKBC_LENGTH] = idata; } } /* SGI? TODO: fix */ #if 0 if (len == 8) odata |= (odata << 8) | (odata << 16) | (odata << 24) | (odata << 32) | (odata << 40) | (odata << 48) | (odata << 56); #endif if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); pckbc_reassert_interrupts(d); return 1; } /* * dev_pckbc_init(): * * Type should be PCKBC_8042 or PCKBC_8242. */ int dev_pckbc_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, int type, char *keyboard_irqpath, char *mouse_irqpath, int in_use, int pc_style_flag) { struct pckbc_data *d; int len = DEV_PCKBC_LENGTH; CHECK_ALLOCATION(d = (struct pckbc_data *) malloc(sizeof(struct pckbc_data))); memset(d, 0, sizeof(struct pckbc_data)); d->translation_table = 2; if (type == PCKBC_8242) { len = 0x40; d->translation_table = 3; } if (type == PCKBC_JAZZ) { type = PCKBC_8042; len = DEV_PCKBC_LENGTH + 0x60; } INTERRUPT_CONNECT(keyboard_irqpath, d->irq_keyboard); INTERRUPT_CONNECT(mouse_irqpath, d->irq_mouse); d->type = type; d->in_use = in_use; d->pc_style_flag = pc_style_flag; d->rx_int_enable[0] = 1; d->rx_int_enable[1] = 0; d->output_byte = 0x02; /* A20 enable on PCs */ // Default is ENABLE keyboard but DISABLE mouse port: d->scanning_enabled[0] = 1; d->scanning_enabled[1] = 0; d->console_handle = console_start_slave_inputonly( machine, "pckbc", d->in_use); memory_device_register(mem, "pckbc", baseaddr, len, dev_pckbc_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(machine, dev_pckbc_tick, d, PCKBC_TICKSHIFT); return d->console_handle; } gxemul-0.6.1/src/devices/dev_wdc.cc000644 001750 001750 00000061276 13402411502 017374 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Standard "wdc" IDE controller */ #include #include #include #include "cpu.h" #include "device.h" #include "diskimage.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/wdcreg.h" #define DEV_WDC_LENGTH 8 #define WDC_TICK_SHIFT 14 #define WDC_MAX_SECTORS 512 #define WDC_INBUF_SIZE (512*(WDC_MAX_SECTORS+1)) extern int quiet_mode; /* #define debug fatal */ struct wdc_data { struct interrupt irq; int addr_mult; int base_drive; int data_debug; int io_enabled; /* Cached values: */ int cyls[2]; int heads[2]; int sectors_per_track[2]; unsigned char *inbuf; int inbuf_head; int inbuf_tail; int int_assert; int write_in_progress; int write_count; int64_t write_offset; int error; int precomp; int seccnt; int sector; int cyl_lo; int cyl_hi; int sectorsize; int lba; int drive; int head; int cur_command; int atapi_cmd_in_progress; int atapi_phase; struct scsi_transfer *atapi_st; int atapi_len; size_t atapi_received; unsigned char identify_struct[512]; }; #define COMMAND_RESET 0x100 DEVICE_TICK(wdc) { struct wdc_data *d = (struct wdc_data *) extra; if (d->int_assert) INTERRUPT_ASSERT(d->irq); } /* * wdc_set_io_enabled(): * * Set io_enabled to zero to disable the I/O registers temporarily (e.g. * used by PCI code in NetBSD to detect whether multiple controllers collide * in I/O space). * * Return value is old contents of the io_enabled variable. */ int wdc_set_io_enabled(struct wdc_data *d, int io_enabled) { int old = d->io_enabled; d->io_enabled = io_enabled; return old; } /* * wdc_addtoinbuf(): * * Write to the inbuf at its head, read at its tail. */ static void wdc_addtoinbuf(struct wdc_data *d, int c) { d->inbuf[d->inbuf_head] = c; d->inbuf_head = (d->inbuf_head + 1) % WDC_INBUF_SIZE; if (d->inbuf_head == d->inbuf_tail) fatal("[ wdc_addtoinbuf(): WARNING! wdc inbuf overrun!" " Increase WDC_MAX_SECTORS. ]\n"); } /* * wdc_get_inbuf(): * * Read from the tail of inbuf. */ static uint64_t wdc_get_inbuf(struct wdc_data *d) { int c = d->inbuf[d->inbuf_tail]; if (d->inbuf_head == d->inbuf_tail) { fatal("[ wdc: WARNING! someone is reading too much from the " "wdc inbuf! ]\n"); return (uint64_t) -1; } d->inbuf_tail = (d->inbuf_tail + 1) % WDC_INBUF_SIZE; return c; } /* * wdc_initialize_identify_struct(): */ static void wdc_initialize_identify_struct(struct cpu *cpu, struct wdc_data *d) { uint64_t total_size; int flags, cdrom = 0; char namebuf[40]; total_size = diskimage_getsize(cpu->machine, d->drive + d->base_drive, DISKIMAGE_IDE); if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive, DISKIMAGE_IDE)) cdrom = 1; memset(d->identify_struct, 0, sizeof(d->identify_struct)); /* Offsets are in 16-bit WORDS! High byte, then low. */ /* 0: general flags */ flags = 1 << 6; /* Fixed */ if (cdrom) flags = 0x8580; /* ATAPI, CDROM, removable */ d->identify_struct[2 * 0 + 0] = flags >> 8; d->identify_struct[2 * 0 + 1] = flags; /* 1: nr of cylinders */ d->identify_struct[2 * 1 + 0] = d->cyls[d->drive] >> 8; d->identify_struct[2 * 1 + 1] = d->cyls[d->drive]; /* 3: nr of heads */ d->identify_struct[2 * 3 + 0] = d->heads[d->drive] >> 8; d->identify_struct[2 * 3 + 1] = d->heads[d->drive]; /* 6: sectors per track */ d->identify_struct[2 * 6 + 0] = d->sectors_per_track[d->drive] >> 8; d->identify_struct[2 * 6 + 1] = d->sectors_per_track[d->drive]; /* 10-19: Serial number */ memcpy(&d->identify_struct[2 * 10], "#0 ", 20); /* 23-26: Firmware version */ memcpy(&d->identify_struct[2 * 23], "1.0 ", 8); /* 27-46: Model number */ if (diskimage_getname(cpu->machine, d->drive + d->base_drive, DISKIMAGE_IDE, namebuf, sizeof(namebuf))) { size_t i; for (i=0; iidentify_struct[2 * 27], namebuf, 40); } else memcpy(&d->identify_struct[2 * 27], "Fake GXemul IDE disk ", 40); /* 47: max sectors per multitransfer */ d->identify_struct[2 * 47 + 0] = 0x80; d->identify_struct[2 * 47 + 1] = 128; /* 49: capabilities: */ /* (0x200 = LBA, 0x100 = DMA support.) */ d->identify_struct[2 * 49 + 0] = 0; d->identify_struct[2 * 49 + 1] = 0; /* 51: PIO timing mode. */ d->identify_struct[2 * 51 + 0] = 0x00; /* ? */ d->identify_struct[2 * 51 + 1] = 0x00; /* 53: 0x02 = fields 64-70 valid, 0x01 = fields 54-58 valid */ d->identify_struct[2 * 53 + 0] = 0x00; d->identify_struct[2 * 53 + 1] = 0x02; /* 57-58: current capacity in sectors */ d->identify_struct[2 * 58 + 0] = ((total_size / 512) >> 24) % 255; d->identify_struct[2 * 58 + 1] = ((total_size / 512) >> 16) % 255; d->identify_struct[2 * 57 + 0] = ((total_size / 512) >> 8) % 255; d->identify_struct[2 * 57 + 1] = (total_size / 512) & 255; /* 60-61: total nr of addressable sectors */ d->identify_struct[2 * 61 + 0] = ((total_size / 512) >> 24) % 255; d->identify_struct[2 * 61 + 1] = ((total_size / 512) >> 16) % 255; d->identify_struct[2 * 60 + 0] = ((total_size / 512) >> 8) % 255; d->identify_struct[2 * 60 + 1] = (total_size / 512) & 255; /* 64: Advanced PIO mode support. 0x02 = mode4, 0x01 = mode3 */ d->identify_struct[2 * 64 + 0] = 0x00; d->identify_struct[2 * 64 + 1] = 0x03; /* 67, 68: PIO timing */ d->identify_struct[2 * 67 + 0] = 0; d->identify_struct[2 * 67 + 1] = 120; d->identify_struct[2 * 68 + 0] = 0; d->identify_struct[2 * 68 + 1] = 120; } /* * wdc__read(): */ void wdc__read(struct cpu *cpu, struct wdc_data *d) { #define MAX_SECTORS_PER_CHUNK 64 const int max_sectors_per_chunk = MAX_SECTORS_PER_CHUNK; unsigned char buf[512 * MAX_SECTORS_PER_CHUNK]; int i, cyl = d->cyl_hi * 256+ d->cyl_lo; int count = d->seccnt? d->seccnt : 256; uint64_t offset = 512 * (d->sector - 1 + (int64_t)d->head * d->sectors_per_track[d->drive] + (int64_t)d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl); #if 0 /* LBA: */ if (d->lba) offset = 512 * (((d->head & 0xf) << 24) + (cyl << 8) + d->sector); printf("WDC read from offset %lli\n", (long long)offset); #endif while (count > 0) { int to_read = count > max_sectors_per_chunk? max_sectors_per_chunk : count; /* TODO: result code from the read? */ if (d->inbuf_head + 512 * to_read <= WDC_INBUF_SIZE) { diskimage_access(cpu->machine, d->drive + d->base_drive, DISKIMAGE_IDE, 0, offset, d->inbuf + d->inbuf_head, 512 * to_read); d->inbuf_head += 512 * to_read; if (d->inbuf_head == WDC_INBUF_SIZE) d->inbuf_head = 0; } else { diskimage_access(cpu->machine, d->drive + d->base_drive, DISKIMAGE_IDE, 0, offset, buf, 512 * to_read); for (i=0; i<512 * to_read; i++) wdc_addtoinbuf(d, buf[i]); } offset += 512 * to_read; count -= to_read; } d->int_assert = 1; } /* * wdc__write(): */ void wdc__write(struct cpu *cpu, struct wdc_data *d) { int cyl = d->cyl_hi * 256+ d->cyl_lo; int count = d->seccnt? d->seccnt : 256; uint64_t offset = 512 * (d->sector - 1 + (int64_t)d->head * d->sectors_per_track[d->drive] + (int64_t)d->heads[d->drive] * d->sectors_per_track[d->drive] * cyl); #if 0 /* LBA: */ if (d->lba) offset = 512 * (((d->head & 0xf) << 24) + (cyl << 8) + d->sector); printf("WDC write to offset %lli\n", (long long)offset); #endif d->write_in_progress = d->cur_command; d->write_count = count; d->write_offset = offset; /* TODO: result code? */ } /* * status_byte(): * * Return a reasonable status byte corresponding to the controller's current * state. */ static int status_byte(struct wdc_data *d, struct cpu *cpu) { int odata = 0; if (diskimage_exist(cpu->machine, d->drive + d->base_drive, DISKIMAGE_IDE)) odata |= WDCS_DRDY | WDCS_DSC; if (d->inbuf_head != d->inbuf_tail) odata |= WDCS_DRQ; if (d->write_in_progress) odata |= WDCS_DRQ; if (d->error) odata |= WDCS_ERR; if (d->atapi_cmd_in_progress && (d->atapi_phase & WDCS_DRQ)) { odata |= WDCS_DRQ; } return odata; } DEVICE_ACCESS(wdc_altstatus) { struct wdc_data *d = (struct wdc_data *) extra; uint64_t idata = 0, odata = 0; idata = data[0]; /* Same as the normal status byte: */ odata = status_byte(d, cpu); if (writeflag==MEM_READ) debug("[ wdc: read from ALTSTATUS: 0x%02x ]\n", (int)odata); else { debug("[ wdc: write to ALT. CTRL: 0x%02x ]\n", (int)idata); if (idata & WDCTL_4BIT) d->cur_command = COMMAND_RESET; } if (writeflag == MEM_READ) data[0] = odata; return 1; } /* * wdc_command(): */ void wdc_command(struct cpu *cpu, struct wdc_data *d, int idata) { size_t i; d->cur_command = idata; d->atapi_cmd_in_progress = 0; d->error = 0; /* * Disk images that do not exist return an ABORT error. This also * happens with CDROM images with the WDCC_IDENTIFY command; CDROM * images must be detected with ATAPI_IDENTIFY_DEVICE instead. * * TODO: Is this correct/good behaviour? */ if (!diskimage_exist(cpu->machine, d->drive + d->base_drive, DISKIMAGE_IDE)) { debug("[ wdc: command 0x%02x drive %i, but no disk image ]\n", d->cur_command, d->drive + d->base_drive); d->error |= WDCE_ABRT; d->int_assert = 1; return; } if (diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive, DISKIMAGE_IDE) && d->cur_command == WDCC_IDENTIFY) { debug("[ wdc: IDENTIFY drive %i, but it is an ATAPI " "drive ]\n", d->drive + d->base_drive); d->error |= WDCE_ABRT; d->int_assert = 1; return; } /* Handle the command: */ switch (d->cur_command) { case WDCC_READ: case WDCC_READMULTI: if (!quiet_mode) debug("[ wdc: READ from drive %i, head %i, cyl %i, " "sector %i, nsecs %i ]\n", d->drive, d->head, d->cyl_hi*256+d->cyl_lo, d->sector, d->seccnt); wdc__read(cpu, d); break; case WDCC_WRITE: case WDCC_WRITEMULTI: if (!quiet_mode) debug("[ wdc: WRITE to drive %i, head %i, cyl %i, " "sector %i, nsecs %i ]\n", d->drive, d->head, d->cyl_hi*256+d->cyl_lo, d->sector, d->seccnt); wdc__write(cpu, d); break; case WDCC_IDP: /* Initialize drive parameters */ debug("[ wdc: IDP drive %i (TODO) ]\n", d->drive); /* TODO */ d->int_assert = 1; break; case SET_FEATURES: debug("[ wdc: SET_FEATURES drive %i (TODO), feature 0x%02x ]\n", d->drive, d->precomp); /* TODO */ switch (d->precomp) { case WDSF_SET_MODE: debug("[ wdc: WDSF_SET_MODE drive %i, pio/dma flags " "0x%02x ]\n", d->drive, d->seccnt); break; default:d->error |= WDCE_ABRT; } /* TODO: always interrupt? */ d->int_assert = 1; break; case WDCC_RECAL: debug("[ wdc: RECAL drive %i ]\n", d->drive); d->int_assert = 1; break; case WDCC_IDENTIFY: case ATAPI_IDENTIFY_DEVICE: debug("[ wdc: %sIDENTIFY drive %i ]\n", d->cur_command == ATAPI_IDENTIFY_DEVICE? "ATAPI " : "", d->drive); wdc_initialize_identify_struct(cpu, d); /* The IDENTIFY data is sent out in low/high byte order: */ for (i=0; iidentify_struct); i+=2) { wdc_addtoinbuf(d, d->identify_struct[i+1]); wdc_addtoinbuf(d, d->identify_struct[i+0]); } d->int_assert = 1; break; case WDCC_IDLE_IMMED: debug("[ wdc: IDLE_IMMED drive %i ]\n", d->drive); /* TODO: interrupt here? */ d->int_assert = 1; break; case WDCC_SETMULTI: debug("[ wdc: SETMULTI drive %i ]\n", d->drive); /* TODO: interrupt here? */ d->int_assert = 1; break; case ATAPI_SOFT_RESET: debug("[ wdc: ATAPI_SOFT_RESET drive %i ]\n", d->drive); /* TODO: interrupt here? */ d->int_assert = 1; break; case ATAPI_PKT_CMD: debug("[ wdc: ATAPI_PKT_CMD drive %i ]\n", d->drive); /* TODO: interrupt here? */ /* d->int_assert = 1; */ d->atapi_cmd_in_progress = 1; d->atapi_phase = PHASE_CMDOUT; break; case WDCC_DIAGNOSE: debug("[ wdc: WDCC_DIAGNOSE drive %i: TODO ]\n", d->drive); /* TODO: interrupt here? */ d->int_assert = 1; d->error = 1; /* No error? */ break; /* Unsupported commands, without warning: */ case WDCC_SEC_SET_PASSWORD: case WDCC_SEC_UNLOCK: case WDCC_SEC_ERASE_PREPARE: case WDCC_SEC_ERASE_UNIT: case WDCC_SEC_FREEZE_LOCK: case WDCC_SEC_DISABLE_PASSWORD: d->error |= WDCE_ABRT; break; default:/* TODO */ d->error |= WDCE_ABRT; fatal("[ wdc: WARNING! Unimplemented command 0x%02x (drive %i," " head %i, cyl %i, sector %i, nsecs %i) ]\n", d->cur_command, d->drive, d->head, d->cyl_hi*256+d->cyl_lo, d->sector, d->seccnt); } } DEVICE_ACCESS(wdc) { struct wdc_data *d = (struct wdc_data *) extra; uint64_t idata = 0, odata = 0; int i; relative_addr /= d->addr_mult; if (!d->io_enabled) goto ret; if (writeflag == MEM_WRITE) { if (relative_addr == wd_data) idata = memory_readmax64(cpu, data, len); else { if (len != 1) fatal("[ wdc: WARNING! non-8-bit access on WRITE! ]\n"); idata = data[0]; } } switch (relative_addr) { case wd_data: /* 0: data */ if (writeflag == MEM_READ) { odata = wdc_get_inbuf(d); if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { if (len >= 2) odata += (wdc_get_inbuf(d) << 8); if (len == 4) { odata += (wdc_get_inbuf(d) << 16); odata += (wdc_get_inbuf(d) << 24); } } else { if (len >= 2) odata = (odata << 8) + wdc_get_inbuf(d); if (len == 4) { odata = (odata << 8) + wdc_get_inbuf(d); odata = (odata << 8) + wdc_get_inbuf(d); } } if (d->data_debug) { const char *s = "0x%04" PRIx64" ]\n"; if (len == 1) s = "0x%02" PRIx64" ]\n"; if (len == 4) s = "0x%08" PRIx64" ]\n"; if (len == 8) s = "0x%016" PRIx64" ]\n"; debug("[ wdc: read from DATA: "); debug(s, (uint64_t) odata); } if (d->atapi_cmd_in_progress) { d->atapi_len -= len; d->atapi_received += len; if (d->atapi_len == 0) { if (d->atapi_received < d->atapi_st-> data_in_len) { d->atapi_phase = PHASE_DATAIN; d->atapi_len = d->atapi_st-> data_in_len - d->atapi_received; if (d->atapi_len > 32768) d->atapi_len = 0; } else d->atapi_phase = PHASE_COMPLETED; d->int_assert = 1; } } else { #if 0 if (d->inbuf_tail != d->inbuf_head) #else if (d->inbuf_tail != d->inbuf_head && ((d->inbuf_tail - d->inbuf_head) % 512) == 0) #endif d->int_assert = 1; } } else { int inbuf_len; if (d->data_debug) { const char *s = "0x%04" PRIx64" ]\n"; if (len == 1) s = "0x%02" PRIx64" ]\n"; if (len == 4) s = "0x%08" PRIx64" ]\n"; if (len == 8) s = "0x%016" PRIx64" ]\n"; debug("[ wdc: write to DATA: "); debug(s, (uint64_t) idata); } if (!d->write_in_progress && !d->atapi_cmd_in_progress) { fatal("[ wdc: write to DATA, but not " "expecting any? (len=%i): 0x%08lx ]\n", (int)len, (long)idata); } if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { switch (len) { case 4: wdc_addtoinbuf(d, idata & 0xff); wdc_addtoinbuf(d, (idata >> 8) & 0xff); wdc_addtoinbuf(d, (idata >> 16) & 0xff); wdc_addtoinbuf(d, (idata >> 24) & 0xff); break; case 2: wdc_addtoinbuf(d, idata & 0xff); wdc_addtoinbuf(d, (idata >> 8) & 0xff); break; case 1: wdc_addtoinbuf(d, idata); break; default:fatal("wdc: unimplemented write " "len %i\n", len); exit(1); } } else { switch (len) { case 4: wdc_addtoinbuf(d, (idata >> 24) & 0xff); wdc_addtoinbuf(d, (idata >> 16) & 0xff); wdc_addtoinbuf(d, (idata >> 8) & 0xff); wdc_addtoinbuf(d, idata & 0xff); break; case 2: wdc_addtoinbuf(d, (idata >> 8) & 0xff); wdc_addtoinbuf(d, idata & 0xff); break; case 1: wdc_addtoinbuf(d, idata); break; default:fatal("wdc: unimplemented write " "len %i\n", len); exit(1); } } inbuf_len = d->inbuf_head - d->inbuf_tail; while (inbuf_len < 0) inbuf_len += WDC_INBUF_SIZE; if (d->atapi_cmd_in_progress && inbuf_len == 12) { unsigned char *scsi_cmd; int x = 0, res; CHECK_ALLOCATION(scsi_cmd = (unsigned char *) malloc(12)); if (d->atapi_st != NULL) scsi_transfer_free(d->atapi_st); d->atapi_st = scsi_transfer_alloc(); debug("[ wdc: ATAPI command ]\n"); while (inbuf_len > 0) { scsi_cmd[x++] = wdc_get_inbuf(d); inbuf_len --; } d->atapi_st->cmd = scsi_cmd; d->atapi_st->cmd_len = 12; if (scsi_cmd[0] == SCSIBLOCKCMD_READ_CAPACITY || scsi_cmd[0] == SCSICMD_READ_10 || scsi_cmd[0] == SCSICMD_MODE_SENSE10) d->atapi_st->cmd_len = 10; res = diskimage_scsicommand(cpu, d->drive + d->base_drive, DISKIMAGE_IDE, d->atapi_st); if (res == 0) { fatal("WDC: ATAPI scsi error?\n"); exit(1); } d->atapi_len = 0; d->atapi_received = 0; if (res == 1) { if (d->atapi_st->data_in != NULL) { d->atapi_phase = PHASE_DATAIN; d->atapi_len = d->atapi_st->data_in_len; for (int j=0; jatapi_len; j++) wdc_addtoinbuf(d, d->atapi_st->data_in[j]); if (d->atapi_len > 32768) d->atapi_len = 32768; } else { d->atapi_phase = PHASE_COMPLETED; } } else { fatal("wdc atapi Dataout? TODO\n"); d->atapi_phase = PHASE_DATAOUT; exit(1); } d->int_assert = 1; } if (( d->write_in_progress == WDCC_WRITEMULTI && inbuf_len % (512 * d->write_count) == 0) || ( d->write_in_progress == WDCC_WRITE && inbuf_len % 512 == 0) ) { int count = (d->write_in_progress == WDCC_WRITEMULTI)? d->write_count : 1; unsigned char *buf, *b; CHECK_ALLOCATION(buf = (unsigned char *) malloc(512 * count)); b = buf; if (d->inbuf_tail+512*count <= WDC_INBUF_SIZE) { b = d->inbuf + d->inbuf_tail; d->inbuf_tail = (d->inbuf_tail + 512 * count) % WDC_INBUF_SIZE; } else { for (i=0; i<512 * count; i++) buf[i] = wdc_get_inbuf(d); } diskimage_access(cpu->machine, d->drive + d->base_drive, DISKIMAGE_IDE, 1, d->write_offset, b, 512 * count); d->write_count -= count; d->write_offset += 512 * count; d->int_assert = 1; if (d->write_count == 0) d->write_in_progress = 0; free(buf); } } break; case wd_error: /* 1: error (r), precomp (w) */ if (writeflag == MEM_READ) { odata = d->error; debug("[ wdc: read from ERROR: 0x%02x ]\n", (int)odata); } else { d->precomp = idata; debug("[ wdc: write to PRECOMP: 0x%02x ]\n",(int)idata); } break; case wd_seccnt: /* 2: sector count (or "ireason" for ATAPI) */ if (writeflag == MEM_READ) { odata = d->seccnt; if (d->atapi_cmd_in_progress) { odata = d->atapi_phase & (WDCI_CMD | WDCI_IN); } debug("[ wdc: read from SECCNT: 0x%02x ]\n",(int)odata); } else { d->seccnt = idata; debug("[ wdc: write to SECCNT: 0x%02x ]\n", (int)idata); } break; case wd_sector: /* 3: first sector */ if (writeflag == MEM_READ) { odata = d->sector; debug("[ wdc: read from SECTOR: 0x%02x ]\n",(int)odata); } else { d->sector = idata; debug("[ wdc: write to SECTOR: 0x%02x ]\n", (int)idata); } break; case wd_cyl_lo: /* 4: cylinder low */ if (writeflag == MEM_READ) { odata = d->cyl_lo; if (d->cur_command == COMMAND_RESET && diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive, DISKIMAGE_IDE)) odata = 0x14; if (d->atapi_cmd_in_progress) { int x = d->atapi_len; if (x > 32768) x = 32768; odata = x & 255; } debug("[ wdc: read from CYL_LO: 0x%02x ]\n",(int)odata); } else { d->cyl_lo = idata; debug("[ wdc: write to CYL_LO: 0x%02x ]\n", (int)idata); } break; case wd_cyl_hi: /* 5: cylinder high */ if (writeflag == MEM_READ) { odata = d->cyl_hi; if (d->cur_command == COMMAND_RESET && diskimage_is_a_cdrom(cpu->machine, d->drive + d->base_drive, DISKIMAGE_IDE)) odata = 0xeb; if (d->atapi_cmd_in_progress) { int x = d->atapi_len; if (x > 32768) x = 32768; odata = (x >> 8) & 255; } debug("[ wdc: read from CYL_HI: 0x%02x ]\n",(int)odata); } else { d->cyl_hi = idata; debug("[ wdc: write to CYL_HI: 0x%02x ]\n", (int)idata); } break; case wd_sdh: /* 6: sectorsize/drive/head */ if (writeflag==MEM_READ) { odata = (d->sectorsize << 6) + (d->lba << 5) + (d->drive << 4) + (d->head); debug("[ wdc: read from SDH: 0x%02x (sectorsize %i," " lba=%i, drive %i, head %i) ]\n", (int)odata, d->sectorsize, d->lba, d->drive, d->head); } else { d->sectorsize = (idata >> 6) & 3; d->lba = (idata >> 5) & 1; d->drive = (idata >> 4) & 1; d->head = idata & 0xf; debug("[ wdc: write to SDH: 0x%02x (sectorsize %i," " lba=%i, drive %i, head %i) ]\n", (int)idata, d->sectorsize, d->lba, d->drive, d->head); } break; case wd_command: /* 7: command or status */ if (writeflag==MEM_READ) { odata = status_byte(d, cpu); if (!quiet_mode) debug("[ wdc: read from STATUS: 0x%02x ]\n", (int)odata); INTERRUPT_DEASSERT(d->irq); d->int_assert = 0; } else { debug("[ wdc: write to COMMAND: 0x%02x ]\n",(int)idata); wdc_command(cpu, d, idata); } break; default: if (writeflag==MEM_READ) debug("[ wdc: read from 0x%02x ]\n", (int)relative_addr); else debug("[ wdc: write to 0x%02x: 0x%02x ]\n", (int)relative_addr, (int)idata); } /* Assert interrupt, if necessary: */ dev_wdc_tick(cpu, extra); ret: if (writeflag == MEM_READ) { if (relative_addr == wd_data) memory_writemax64(cpu, data, len, odata); else { if (len != 1) fatal("[ wdc: WARNING! non-8-bit access on READ! ]\n"); data[0] = odata; } } return 1; } DEVINIT(wdc) { struct wdc_data *d; uint64_t alt_status_addr; int i, tick_shift = WDC_TICK_SHIFT; CHECK_ALLOCATION(d = (struct wdc_data *) malloc(sizeof(struct wdc_data))); memset(d, 0, sizeof(struct wdc_data)); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); d->addr_mult = devinit->addr_mult; d->data_debug = 1; d->io_enabled = 1; d->error = 1; d->inbuf = (unsigned char *) zeroed_alloc(WDC_INBUF_SIZE); /* base_drive = 0 for the primary controller, 2 for the secondary. */ d->base_drive = 0; if ((devinit->addr & 0xfff) == 0x170) d->base_drive = 2; alt_status_addr = devinit->addr + 0x206; /* Special hacks for individual machines: */ switch (devinit->machine->machine_type) { case MACHINE_MACPPC: alt_status_addr = devinit->addr + 0x160; break; case MACHINE_HPCMIPS: /* TODO: Fix */ if (devinit->addr == 0x14000180) alt_status_addr = 0x14000386; break; case MACHINE_IQ80321: alt_status_addr = devinit->addr + 0x402; break; } /* Get disk geometries: */ for (i=0; i<2; i++) if (diskimage_exist(devinit->machine, d->base_drive +i, DISKIMAGE_IDE)) diskimage_getchs(devinit->machine, d->base_drive + i, DISKIMAGE_IDE, &d->cyls[i], &d->heads[i], &d->sectors_per_track[i]); memory_device_register(devinit->machine->memory, "wdc_altstatus", alt_status_addr, 2, dev_wdc_altstatus_access, d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_WDC_LENGTH * devinit->addr_mult, dev_wdc_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_wdc_tick, d, tick_shift); devinit->return_ptr = d; return 1; } gxemul-0.6.1/src/devices/dev_rs5c313.cc000644 001750 001750 00000007516 13402411502 017717 0ustar00debugdebug000000 000000 /* * Copyright (C) 2007-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: RICOH RS5C313 Real Time Clock * * The RS5C313 has 16 registers, see rs5c313reg.h for details. These registers * are addressed at byte offsets. * * Note: The only use for this device so far is in the Landisk, connected to * the SH4 SCI pins. In the Landisk machine, the RS5C313 is placed at * a fake (high) address in memory. */ #include #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/rs5c313reg.h" #define DEV_RS5C313_LENGTH 16 struct rs5c313_data { uint8_t reg[DEV_RS5C313_LENGTH]; }; /* * rs5c313_update_time(): * * Set the RS5C313 registers to correspond to the host's clock. */ static void rs5c313_update_time(struct rs5c313_data *d) { struct tm *tmp; time_t timet; timet = time(NULL); tmp = gmtime(&timet); d->reg[RS5C313_SEC1] = tmp->tm_sec % 10; d->reg[RS5C313_SEC10] = tmp->tm_sec / 10; d->reg[RS5C313_MIN1] = tmp->tm_min % 10; d->reg[RS5C313_MIN10] = tmp->tm_min / 10; d->reg[RS5C313_HOUR1] = tmp->tm_hour % 10; d->reg[RS5C313_HOUR10] = tmp->tm_hour / 10; /* WDAY. Zero-based. TODO: Is this correct? */ d->reg[RS5C313_WDAY] = tmp->tm_wday; d->reg[RS5C313_DAY1] = tmp->tm_mday % 10; d->reg[RS5C313_DAY10] = tmp->tm_mday / 10; d->reg[RS5C313_MON1] = (tmp->tm_mon + 1) % 10; d->reg[RS5C313_MON10] = (tmp->tm_mon + 1) / 10; d->reg[RS5C313_YEAR1] = tmp->tm_year % 10; d->reg[RS5C313_YEAR10] = (tmp->tm_year / 10) % 10; } DEVICE_ACCESS(rs5c313) { struct rs5c313_data *d = (struct rs5c313_data *) extra; uint64_t idata = 0, odata = 0; rs5c313_update_time(d); /* Generic register read/write: */ if (writeflag == MEM_WRITE) { idata = memory_readmax64(cpu, data, len); d->reg[relative_addr] = idata & 0x0f; } else { odata = d->reg[relative_addr] & 0x0f; memory_writemax64(cpu, data, len, odata); } return 1; } DEVINIT(rs5c313) { struct rs5c313_data *d; CHECK_ALLOCATION(d = (struct rs5c313_data *) malloc(sizeof(struct rs5c313_data))); memset(d, 0, sizeof(struct rs5c313_data)); /* Default values: */ d->reg[RS5C313_CTRL] = CTRL_24H; memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_RS5C313_LENGTH, dev_rs5c313_access, (void *)d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_hammerhead.cc000644 001750 001750 00000005761 13402411502 020707 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Hammerhead controller, for the secondary CPU on MacPPC machines */ #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" /* #define debug fatal */ void ppc_pc_to_pointers(struct cpu *); void ppc32_pc_to_pointers(struct cpu *); #define DEV_HAMMERHEAD_LENGTH 4 struct hammerhead_data { int dummy; }; DEVICE_ACCESS(hammerhead) { /* struct hammerhead_data *d = extra; */ uint64_t idata = 0, odata=0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); if (writeflag == MEM_WRITE) { int my_id = cpu->cpu_id; struct cpu *other_cpu = cpu->machine->cpus[!my_id]; debug("[ HAMMERHEAD: from cpu%i to cpu%i: new pc = 0x%llx ]\n", my_id, !my_id, (long long)idata); if (idata <= 0x100) return 1; other_cpu->running = 1; other_cpu->pc = idata; if (other_cpu->is_32bit) ppc32_pc_to_pointers(other_cpu); else ppc_pc_to_pointers(other_cpu); } else { fatal("[ HAMMERHEAD read: TODO ]\n"); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(hammerhead) { struct hammerhead_data *d; CHECK_ALLOCATION(d = (struct hammerhead_data *) malloc(sizeof(struct hammerhead_data))); memset(d, 0, sizeof(struct hammerhead_data)); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_HAMMERHEAD_LENGTH, dev_hammerhead_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_sgi_ip20.cc000644 001750 001750 00000006550 13402411502 020225 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SGI IP20 stuff * * TODO. */ #include #include #include #include "devices.h" #include "memory.h" #include "misc.h" extern int quiet_mode; DEVICE_ACCESS(sgi_ip20) { /* struct sgi_ip20_data *d = extra; */ uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0x38: if (writeflag == MEM_WRITE) { debug("[ sgi_ip20: write to address 0x%x, " "data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { /* * TODO: * * I haven't had time to figure out what values should * be returned by this device. Simple bit patterns * don't seem to be enough, but using random() is * obviously pretty bad. This must be fixed some day. */ /* instruction_trace = 1; quiet_mode = 0; */ odata = random() & 0xff; debug("[ sgi_ip20: read from address 0x%x: 0x%x ]\n", (int)relative_addr, (int)odata); } break; default: if (writeflag == MEM_WRITE) { debug("[ sgi_ip20: unimplemented write to address " "0x%x, data=0x%02x ]\n", (int)relative_addr, (int)idata); } else { debug("[ sgi_ip20: unimplemented read from address " "0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } struct sgi_ip20_data *dev_sgi_ip20_init(struct cpu *cpu, struct memory *mem, uint64_t baseaddr) { struct sgi_ip20_data *d; CHECK_ALLOCATION(d = (struct sgi_ip20_data *) malloc(sizeof(struct sgi_ip20_data))); memset(d, 0, sizeof(struct sgi_ip20_data)); /* * This device is detected as int0 by NetBSD 2.0_BETA, so I call it * "sgi_ip20_int". */ memory_device_register(mem, "sgi_ip20_int", baseaddr, DEV_SGI_IP20_LENGTH, dev_sgi_ip20_access, (void *)d, DM_DEFAULT, NULL); return d; } gxemul-0.6.1/src/devices/dev_ohci.cc000644 001750 001750 00000010405 13402411502 017525 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: USB Open Host Controller Interface * * TODO */ #include #include #include #include "cpu.h" #include "device.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/ohcireg.h" /* Length is 0x1000 at least on Playstation 2 */ #define DEV_OHCI_LENGTH 0x1000 #define debug fatal struct ohci_data { struct interrupt irq; int port1reset; }; DEVICE_ACCESS(ohci) { struct ohci_data *d = (struct ohci_data *) extra; uint64_t idata = 0, odata = 0; const char *name = NULL; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case OHCI_REVISION: name = "REVISION"; if (writeflag == MEM_READ) { odata = 0x10; /* Version 1.0. */ } break; case OHCI_COMMAND_STATUS: name = "COMMAND_STATUS"; if (idata == 0x2) { fatal("Hm... OHCI COMMAND STATUS\n"); INTERRUPT_ASSERT(d->irq); } break; case OHCI_INTERRUPT_STATUS: name = "INTERRUPT_STATUS"; odata = OHCI_WDH; break; /* * TODO: It now sleeps at tsleep(xfer, PRIBIO, "usbsyn", 0); * in netbsd/src/sys/dev/usb/usbdi.c */ case OHCI_RH_DESCRIPTOR_A: name = "RH_DESCRIPTOR_A"; odata = 2; /* Nr of ports */ break; case OHCI_RH_STATUS: name = "RH_STATUS"; /* TODO */ break; case OHCI_RH_PORT_STATUS(1): /* First port */ name = "RH_PORT_STATUS(1)"; if (writeflag == MEM_READ) { /* Status = low 16, Change = top 16 */ odata = 0x10101; /* 0x0001 = connected 0x0100 = power */ if (d->port1reset) odata |= (0x10 << 16) | 0x10; } else { /* 0x10 = UPS_C_PORT_RESET */ if (idata & 0x10) d->port1reset = 1; if (idata & 0x100000) d->port1reset = 0; } break; case OHCI_RH_PORT_STATUS(2): /* Second port */ name = "RH_PORT_STATUS(2)"; /* TODO */ odata = 0; break; default: if (writeflag == MEM_READ) { debug("[ ohci: read from addr 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)odata); } else { debug("[ ohci: write to addr 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)idata); } } if (name != NULL) { if (writeflag == MEM_READ) debug("[ ohci: read from %s: 0x%llx ]\n", name, (long long)odata); else debug("[ ohci: write to %s: 0x%llx ]\n", name, (long long)idata); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(ohci) { struct ohci_data *d; CHECK_ALLOCATION(d = (struct ohci_data *) malloc(sizeof(struct ohci_data))); memset(d, 0, sizeof(struct ohci_data)); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_OHCI_LENGTH, dev_ohci_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_kn230.cc000644 001750 001750 00000011721 13402411502 017442 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: DEC KN230 (MIPSMATE 5100) stuff */ #include #include #include #include "device.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/dec_5100.h" #define DEV_KN230_LENGTH 0x1c00000 struct kn230_data { struct interrupt mips_irq_2; struct interrupt mips_irq_3; uint32_t csr; }; /* * kn230_interrupt_assert(): * kn230_interrupt_deassert(): * * Called whenever a KN230 interrupt is asserted/deasserted. */ void kn230_interrupt_assert(struct interrupt *interrupt) { struct kn230_data *d = (struct kn230_data *) interrupt->extra; int assert2 = 0, assert3 = 0; d->csr |= interrupt->line; if (d->csr & (KN230_CSR_INTR_SII | KN230_CSR_INTR_LANCE)) assert3 = 1; if (d->csr & (KN230_CSR_INTR_DZ0 | KN230_CSR_INTR_OPT0 | KN230_CSR_INTR_OPT1)) assert2 = 1; if (assert2) INTERRUPT_ASSERT(d->mips_irq_2); if (assert3) INTERRUPT_ASSERT(d->mips_irq_2); } void kn230_interrupt_deassert(struct interrupt *interrupt) { struct kn230_data *d = (struct kn230_data *) interrupt->extra; int assert2 = 0, assert3 = 0; d->csr &= ~interrupt->line; if (d->csr & (KN230_CSR_INTR_SII | KN230_CSR_INTR_LANCE)) assert3 = 1; if (d->csr & (KN230_CSR_INTR_DZ0 | KN230_CSR_INTR_OPT0 | KN230_CSR_INTR_OPT1)) assert2 = 1; if (!assert2) INTERRUPT_DEASSERT(d->mips_irq_2); if (!assert3) INTERRUPT_DEASSERT(d->mips_irq_2); } DEVICE_ACCESS(kn230) { struct kn230_data *d = (struct kn230_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0: if (writeflag==MEM_READ) { odata = d->csr; /* debug("[ kn230: read from CSR: 0x%08x ]\n", (int)odata); */ } else { /* debug("[ kn230: write to CSR: 0x%08x ]\n", (int)idata); */ } break; default: if (writeflag==MEM_READ) { debug("[ kn230: read from 0x%08lx ]\n", (long)relative_addr); } else { debug("[ kn230: write to 0x%08lx: 0x%08x ]\n", (long)relative_addr, (int)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(kn230) { struct kn230_data *d; char tmpstr[300]; int i; CHECK_ALLOCATION(d = (struct kn230_data *) malloc(sizeof(struct kn230_data))); memset(d, 0, sizeof(struct kn230_data)); /* * devinit->interrupt_path points to the MIPS cpu itself. * The KN230 interrupt controller interrupts at MIPS interrupts * 2 and 3, depending on which KN230 is asserted. */ snprintf(tmpstr, sizeof(tmpstr), "%s.2", devinit->interrupt_path); INTERRUPT_CONNECT(tmpstr, d->mips_irq_2); snprintf(tmpstr, sizeof(tmpstr), "%s.3", devinit->interrupt_path); INTERRUPT_CONNECT(tmpstr, d->mips_irq_3); /* Register KN230 interrupts 8..15: */ for (i=8; i<=15; i++) { struct interrupt templ; char tmpstr2[300]; snprintf(tmpstr2, sizeof(tmpstr2), "%s.kn230.0x%x", devinit->interrupt_path, 1 << i); memset(&templ, 0, sizeof(templ)); templ.line = 1 << i; templ.name = tmpstr2; templ.extra = d; templ.interrupt_assert = kn230_interrupt_assert; templ.interrupt_deassert = kn230_interrupt_deassert; interrupt_handler_register(&templ); } memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_KN230_LENGTH, dev_kn230_access, d, DM_DEFAULT, NULL); devinit->return_ptr = d; return 1; } gxemul-0.6.1/src/devices/dev_sh4.cc000644 001750 001750 00000141106 13402411502 017304 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SH4-specific memory mapped registers (0xf0000000 - 0xffffffff) * * TODO: Among other things: * * x) Interrupt masks (msk register stuff). Are these really correct? * x) BSC (Bus state controller). * x) DMA: Right now there's a hack for Dreamcast emulation * x) UBC (User Break Controller) * x) ... */ #include #include #include #include "bus_pci.h" #include "console.h" #include "cpu.h" #include "device.h" #include "devices.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "sh4_dmacreg.h" #include "timer.h" #include "thirdparty/sh4_bscreg.h" #include "thirdparty/sh4_cache.h" #include "thirdparty/sh4_exception.h" #include "thirdparty/sh4_intcreg.h" #include "thirdparty/sh4_mmu.h" #include "thirdparty/sh4_pcicreg.h" #include "thirdparty/sh4_rtcreg.h" #include "thirdparty/sh4_scifreg.h" #include "thirdparty/sh4_scireg.h" #include "thirdparty/sh4_tmureg.h" #define SH4_REG_BASE 0xff000000 #define SH4_TICK_SHIFT 14 #define N_SH4_TIMERS 3 /* PCI stuff: */ #define N_PCIC_REGS (0x224 / sizeof(uint32_t)) #define N_PCIC_IRQS 16 #define PCIC_REG(addr) ((addr - SH4_PCIC) / sizeof(uint32_t)) #define PCI_VENDOR_HITACHI 0x1054 #define PCI_PRODUCT_HITACHI_SH7751 0x3505 #define PCI_PRODUCT_HITACHI_SH7751R 0x350e #define SCIF_TX_FIFO_SIZE 16 #define SCIF_DELAYED_TX_VALUE 2 /* 2 to be safe, 1 = fast but buggy */ #ifdef UNSTABLE_DEVEL // #define SH4_DEBUG /* #define debug fatal */ #endif // Clock/occilation related #define SH4_CPG_FRQCR 0xffc00000 /* 16-bit */ #define SH4_CPG_STBCR 0xffc00004 /* 8-bit */ #define SH4_CPG_WTCNT 0xffc00008 /* 8/16-bit */ #define SH4_CPG_WTCSR 0xffc0000c /* 8/16-bit */ #define SH4_CPG_STBCR2 0xffc00010 /* 8-bit */ struct sh4_data { /* Store Queues: */ uint8_t sq[32 * 2]; /* SCIF (Serial controller): */ uint16_t scif_smr; uint8_t scif_brr; uint16_t scif_scr; uint16_t scif_ssr; uint16_t scif_fcr; uint16_t scif_lsr; int scif_delayed_tx; int scif_console_handle; uint8_t scif_tx_fifo[SCIF_TX_FIFO_SIZE + 1]; size_t scif_tx_fifo_cursize; struct interrupt scif_tx_irq; struct interrupt scif_rx_irq; int scif_tx_irq_asserted; int scif_rx_irq_asserted; /* Bus State Controller: */ uint32_t bsc_bcr1; uint16_t bsc_bcr2; uint16_t bsc_bcr3; /* SH7751R */ uint32_t bsc_wcr1; uint32_t bsc_wcr2; uint32_t bsc_wcr3; uint32_t bsc_mcr; uint16_t bsc_pcr; uint16_t bsc_rtcsr; uint16_t bsc_rtcor; uint16_t bsc_rfcr; /* CPG: */ uint16_t cpg_frqcr; uint8_t cpg_stbcr; uint16_t cpg_wtcnt; uint16_t cpg_wtcsr; uint8_t cpg_stbcr2; /* GPIO: */ uint32_t pctra; /* Port Control Register A */ uint32_t pdtra; /* Port Data Register A */ uint32_t pctrb; /* Port Control Register B */ uint32_t pdtrb; /* Port Data Register B */ uint16_t bsc_gpioic; /* PCIC (PCI controller): */ struct pci_data *pci_data; struct interrupt cpu_pcic_interrupt[N_PCIC_IRQS]; uint32_t pcic_reg[N_PCIC_REGS]; /* SCI (serial interface): */ int sci_bits_outputed; int sci_bits_read; uint8_t sci_scsptr; uint8_t sci_curbyte; uint8_t sci_cur_addr; /* SD-RAM: */ uint16_t sdmr2; uint16_t sdmr3; /* Timer Management Unit: */ struct timer *sh4_timer; struct interrupt timer_irq[4]; uint32_t tocr; uint32_t tstr; uint32_t tcnt[N_SH4_TIMERS]; uint32_t tcor[N_SH4_TIMERS]; uint32_t tcr[N_SH4_TIMERS]; int timer_interrupts_pending[N_SH4_TIMERS]; double timer_hz[N_SH4_TIMERS]; /* RTC: */ uint32_t rtc_reg[14]; /* Excluding rcr1 and rcr2 */ uint8_t rtc_rcr1; uint8_t rtc_rcr2; }; #define SH4_PSEUDO_TIMER_HZ 110.0 /* * sh4_timer_tick(): * * This function is called SH4_PSEUDO_TIMER_HZ times per real-world second. * Its job is to update the SH4 timer counters, and if necessary, increase * the number of pending interrupts. * * Also, RAM Refresh is also faked here. */ static void sh4_timer_tick(struct timer *t, void *extra) { struct sh4_data *d = (struct sh4_data *) extra; int i; /* Fake RAM refresh: */ d->bsc_rfcr ++; if (d->bsc_rtcsr & (RTCSR_CMIE | RTCSR_OVIE)) { fatal("sh4: RTCSR_CMIE | RTCSR_OVIE: TODO\n"); /* TODO: Implement refresh interrupts etc. */ exit(1); } /* Timer interrupts: */ for (i=0; itcnt[i]; /* printf("tcnt[%i] = %08x tcor[%i] = %08x\n", i, d->tcnt[i], i, d->tcor[i]); */ /* Only update timers that are currently started: */ if (!(d->tstr & (TSTR_STR0 << i))) continue; /* Update the current count: */ d->tcnt[i] -= (uint32_t) (d->timer_hz[i] / SH4_PSEUDO_TIMER_HZ); /* Has the timer underflowed? */ if ((int32_t)d->tcnt[i] < 0 && old >= 0) { d->tcr[i] |= TCR_UNF; if (d->tcr[i] & TCR_UNIE) d->timer_interrupts_pending[i] ++; /* * Set tcnt[i] to tcor[i]. Note: Since this function * is only called now and then, adding tcor[i] to * tcnt[i] produces more correct values for long * running timers. */ d->tcnt[i] += d->tcor[i]; /* At least make sure that tcnt is non-negative... */ if ((int32_t)d->tcnt[i] < 0) d->tcnt[i] = 0; } } } static void sh4_pcic_interrupt_assert(struct interrupt *interrupt) { struct sh4_data *d = (struct sh4_data *) interrupt->extra; INTERRUPT_ASSERT(d->cpu_pcic_interrupt[interrupt->line]); } static void sh4_pcic_interrupt_deassert(struct interrupt *interrupt) { struct sh4_data *d = (struct sh4_data *) interrupt->extra; INTERRUPT_DEASSERT(d->cpu_pcic_interrupt[interrupt->line]); } static void scif_reassert_interrupts(struct sh4_data *d) { int old_tx_asserted = d->scif_tx_irq_asserted; int old_rx_asserted = d->scif_rx_irq_asserted; d->scif_rx_irq_asserted = d->scif_scr & SCSCR2_RIE && d->scif_ssr & SCSSR2_DR; if (d->scif_rx_irq_asserted && !old_rx_asserted) INTERRUPT_ASSERT(d->scif_rx_irq); else if (!d->scif_rx_irq_asserted && old_rx_asserted) INTERRUPT_DEASSERT(d->scif_rx_irq); d->scif_tx_irq_asserted = d->scif_scr & SCSCR2_TIE && d->scif_ssr & (SCSSR2_TDFE | SCSSR2_TEND); if (d->scif_tx_irq_asserted && !old_tx_asserted) INTERRUPT_ASSERT(d->scif_tx_irq); else if (!d->scif_tx_irq_asserted && old_tx_asserted) INTERRUPT_DEASSERT(d->scif_tx_irq); } DEVICE_TICK(sh4) { struct sh4_data *d = (struct sh4_data *) extra; unsigned int i; /* * Serial controller interrupts: * * RX: Cause interrupt if any char is available. * TX: Send entire TX FIFO contents, and interrupt. */ if (console_charavail(d->scif_console_handle)) d->scif_ssr |= SCSSR2_DR; else d->scif_ssr &= ~SCSSR2_DR; if (d->scif_delayed_tx) { if (--d->scif_delayed_tx == 0) { /* Send TX FIFO contents: */ for (i=0; iscif_tx_fifo_cursize; i++) console_putchar(d->scif_console_handle, d->scif_tx_fifo[i]); /* Clear FIFO: */ d->scif_tx_fifo_cursize = 0; /* Done sending; cause a transmit end interrupt: */ d->scif_ssr |= SCSSR2_TDFE | SCSSR2_TEND; } } scif_reassert_interrupts(d); /* Timer interrupts: */ for (i=0; itimer_interrupts_pending[i] > 0) { INTERRUPT_ASSERT(d->timer_irq[i]); d->tcr[i] |= TCR_UNF; } } /* * sh4_dmac_transfer(): * * Called whenever a DMA transfer is to be executed. * Clears the lowest bit of the corresponding channel's CHCR when done. */ void sh4_dmac_transfer(struct cpu *cpu, struct sh4_data *d, int channel) { /* According to the SH7760 manual, bits 31..29 are ignored in */ /* both the SAR and DAR. */ uint32_t sar = cpu->cd.sh.dmac_sar[channel] & 0x1fffffff; uint32_t dar = cpu->cd.sh.dmac_dar[channel] & 0x1fffffff; uint32_t count = cpu->cd.sh.dmac_tcr[channel] & 0x1fffffff; uint32_t chcr = cpu->cd.sh.dmac_chcr[channel]; int transmit_size = 1; int src_delta = 0, dst_delta = 0; int cause_interrupt = chcr & CHCR_IE; /* DMAC not enabled? Then just return. */ if (!(chcr & CHCR_TD)) return; /* Transfer End already set? Then don't transfer again. */ if (chcr & CHCR_TE) return; /* Special case: 0 means 16777216: */ if (count == 0) count = 16777216; switch (chcr & CHCR_TS) { case CHCR_TS_8BYTE: transmit_size = 8; break; case CHCR_TS_1BYTE: transmit_size = 1; break; case CHCR_TS_2BYTE: transmit_size = 2; break; case CHCR_TS_4BYTE: transmit_size = 4; break; case CHCR_TS_32BYTE: transmit_size = 32; break; default: fatal("Unimplemented transmit size?! CHCR[%i] = 0x%08x\n", channel, chcr); exit(1); } switch (chcr & CHCR_DM) { case CHCR_DM_FIXED: dst_delta = 0; break; case CHCR_DM_INCREMENTED: dst_delta = 1; break; case CHCR_DM_DECREMENTED: dst_delta = -1; break; default: fatal("Unimplemented destination delta?! CHCR[%i] = 0x%08x\n", channel, chcr); exit(1); } switch (chcr & CHCR_SM) { case CHCR_SM_FIXED: src_delta = 0; break; case CHCR_SM_INCREMENTED: src_delta = 1; break; case CHCR_SM_DECREMENTED: src_delta = -1; break; default: fatal("Unimplemented source delta?! CHCR[%i] = 0x%08x\n", channel, chcr); exit(1); } src_delta *= transmit_size; dst_delta *= transmit_size; #ifdef SH4_DEBUG fatal("|SH4 DMA transfer, channel %i\n", channel); fatal("|Source addr: 0x%08x (delta %i)\n", (int) sar, src_delta); fatal("|Destination addr: 0x%08x (delta %i)\n", (int) dar, dst_delta); fatal("|Count: 0x%08x\n", (int) count); fatal("|Transmit size: 0x%08x\n", (int) transmit_size); fatal("|Interrupt: %s\n", cause_interrupt? "yes" : "no"); #endif switch (chcr & CHCR_RS) { case 0x200: /* * Single Address Mode * External Address Space => external device */ // Avoid compiler warnings about unused sar and dar. (void)sar; (void)dar; /* Note: No transfer is done here! It is up to the external device to do the transfer itself! */ break; default:fatal("Unimplemented SH4 RS DMAC: 0x%08x\n", (int) (chcr & CHCR_RS)); exit(1); } if (cause_interrupt) { fatal("TODO: sh4 dmac interrupt!\n"); exit(1); } } /* * sh4_sci_cmd(): * * Handle a SCI command byte. * * Bit: Meaning: * 7 Ignored (usually 1?) * 6 0=Write, 1=Read * 5 AD: Address transfer * 4 DT: Data transfer * 3..0 Data or address bits */ static void sh4_sci_cmd(struct sh4_data *d, struct cpu *cpu) { uint8_t cmd = d->sci_curbyte; int writeflag = cmd & 0x40? 0 : 1; int address_transfer; /* fatal("[ CMD BYTE %02x ]\n", cmd); */ if (!(cmd & 0x80)) { fatal("SCI cmd bit 7 not set? TODO\n"); exit(1); } if ((cmd & 0x30) == 0x20) address_transfer = 1; else if ((cmd & 0x30) == 0x10) address_transfer = 0; else { fatal("SCI: Neither data nor address transfer? TODO\n"); exit(1); } if (address_transfer) d->sci_cur_addr = cmd & 0x0f; if (!writeflag) { /* Read data from the current address: */ uint8_t data_byte; cpu->memory_rw(cpu, cpu->mem, SCI_DEVICE_BASE + d->sci_cur_addr, &data_byte, 1, MEM_READ, PHYSICAL); debug("[ SCI: read addr=%x data=%x ]\n", d->sci_cur_addr, data_byte); d->sci_curbyte = data_byte; /* Set bit 7 right away: */ d->sci_scsptr &= ~SCSPTR_SPB1DT; if (data_byte & 0x80) d->sci_scsptr |= SCSPTR_SPB1DT; } if (writeflag && !address_transfer) { /* Write the 4 data bits to the current address: */ uint8_t data_byte = cmd & 0x0f; debug("[ SCI: write addr=%x data=%x ]\n", d->sci_cur_addr, data_byte); cpu->memory_rw(cpu, cpu->mem, SCI_DEVICE_BASE + d->sci_cur_addr, &data_byte, 1, MEM_WRITE, PHYSICAL); } } /* * sh4_sci_access(): * * Reads or writes a bit via the SH4's serial interface. If writeflag is * non-zero, input is used. If writeflag is zero, a bit is outputed as * the return value from this function. */ static uint8_t sh4_sci_access(struct sh4_data *d, struct cpu *cpu, int writeflag, uint8_t input) { if (writeflag) { /* WRITE: */ int clockpulse; uint8_t old = d->sci_scsptr; d->sci_scsptr = input; /* * Clock pulse (SCSPTR_SPB0DT going from 0 to 1, * when SCSPTR_SPB0IO was already set): */ clockpulse = old & SCSPTR_SPB0IO && d->sci_scsptr & SCSPTR_SPB0DT && !(old & SCSPTR_SPB0DT); if (!clockpulse) return 0; /* Are we in output or input mode? */ if (d->sci_scsptr & SCSPTR_SPB1IO) { /* Output: */ int bit = d->sci_scsptr & SCSPTR_SPB1DT? 1 : 0; d->sci_curbyte <<= 1; d->sci_curbyte |= bit; d->sci_bits_outputed ++; if (d->sci_bits_outputed == 8) { /* 4 control bits and 4 address/data bits have been written. */ sh4_sci_cmd(d, cpu); d->sci_bits_outputed = 0; } } else { /* Input: */ int bit; d->sci_bits_read ++; d->sci_bits_read &= 7; bit = d->sci_curbyte & (0x80 >> d->sci_bits_read); d->sci_scsptr &= ~SCSPTR_SPB1DT; if (bit) d->sci_scsptr |= SCSPTR_SPB1DT; } /* Return (value doesn't matter). */ return 0; } else { /* READ: */ return d->sci_scsptr; } } DEVICE_ACCESS(sh4_itlb_aa) { uint64_t idata = 0, odata = 0; int e = (relative_addr & SH4_ITLB_E_MASK) >> SH4_ITLB_E_SHIFT; if (writeflag == MEM_WRITE) { int safe_to_invalidate = 0; uint32_t old_hi = cpu->cd.sh.itlb_hi[e]; if ((cpu->cd.sh.itlb_lo[e] & SH4_PTEL_SZ_MASK)==SH4_PTEL_SZ_4K) safe_to_invalidate = 1; idata = memory_readmax64(cpu, data, len); cpu->cd.sh.itlb_hi[e] &= ~(SH4_PTEH_VPN_MASK | SH4_PTEH_ASID_MASK); cpu->cd.sh.itlb_hi[e] |= (idata & (SH4_ITLB_AA_VPN_MASK | SH4_ITLB_AA_ASID_MASK)); cpu->cd.sh.itlb_lo[e] &= ~SH4_PTEL_V; if (idata & SH4_ITLB_AA_V) cpu->cd.sh.itlb_lo[e] |= SH4_PTEL_V; /* Invalidate if this ITLB entry previously belonged to the currently running process, or if it was shared: */ if (cpu->cd.sh.ptel & SH4_PTEL_SH || (old_hi & SH4_ITLB_AA_ASID_MASK) == (cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK)) { if (safe_to_invalidate) cpu->invalidate_translation_caches(cpu, old_hi & ~0xfff, INVALIDATE_VADDR); else cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); } } else { odata = cpu->cd.sh.itlb_hi[e] & (SH4_ITLB_AA_VPN_MASK | SH4_ITLB_AA_ASID_MASK); if (cpu->cd.sh.itlb_lo[e] & SH4_PTEL_V) odata |= SH4_ITLB_AA_V; memory_writemax64(cpu, data, len, odata); } return 1; } DEVICE_ACCESS(sh4_itlb_da1) { uint32_t mask = SH4_PTEL_SH | SH4_PTEL_C | SH4_PTEL_SZ_MASK | SH4_PTEL_PR_MASK | SH4_PTEL_V | 0x1ffffc00; uint64_t idata = 0, odata = 0; int e = (relative_addr & SH4_ITLB_E_MASK) >> SH4_ITLB_E_SHIFT; if (relative_addr & 0x800000) { fatal("sh4_itlb_da1: TODO: da2 area\n"); exit(1); } if (writeflag == MEM_WRITE) { uint32_t old_lo = cpu->cd.sh.itlb_lo[e]; int safe_to_invalidate = 0; if ((cpu->cd.sh.itlb_lo[e] & SH4_PTEL_SZ_MASK)==SH4_PTEL_SZ_4K) safe_to_invalidate = 1; idata = memory_readmax64(cpu, data, len); cpu->cd.sh.itlb_lo[e] &= ~mask; cpu->cd.sh.itlb_lo[e] |= (idata & mask); /* Invalidate if this ITLB entry belongs to the currently running process, or if it was shared: */ if (old_lo & SH4_PTEL_SH || (cpu->cd.sh.itlb_hi[e] & SH4_ITLB_AA_ASID_MASK) == (cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK)) { if (safe_to_invalidate) cpu->invalidate_translation_caches(cpu, cpu->cd.sh.itlb_hi[e] & ~0xfff, INVALIDATE_VADDR); else cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); } } else { odata = cpu->cd.sh.itlb_lo[e] & mask; memory_writemax64(cpu, data, len, odata); } return 1; } DEVICE_ACCESS(sh4_utlb_aa) { uint64_t idata = 0, odata = 0; int i, e = (relative_addr & SH4_UTLB_E_MASK) >> SH4_UTLB_E_SHIFT; int a = relative_addr & SH4_UTLB_A; if (writeflag == MEM_WRITE) { int n_hits = 0; int safe_to_invalidate = 0; uint32_t vaddr_to_invalidate = 0; idata = memory_readmax64(cpu, data, len); if (a) { for (i=-SH_N_ITLB_ENTRIES; icd.sh.itlb_lo[ i + SH_N_ITLB_ENTRIES]; hi = cpu->cd.sh.itlb_hi[ i + SH_N_ITLB_ENTRIES]; } else { lo = cpu->cd.sh.utlb_lo[i]; hi = cpu->cd.sh.utlb_hi[i]; } sh = lo & SH4_PTEL_SH; if (!(lo & SH4_PTEL_V)) continue; switch (lo & SH4_PTEL_SZ_MASK) { case SH4_PTEL_SZ_1K: mask = 0xfffffc00; break; case SH4_PTEL_SZ_64K: mask = 0xffff0000; break; case SH4_PTEL_SZ_1M: mask = 0xfff00000; break; } if ((hi & mask) != (idata & mask)) continue; if ((lo & SH4_PTEL_SZ_MASK) == SH4_PTEL_SZ_4K) { safe_to_invalidate = 1; vaddr_to_invalidate = hi & mask; } if (!sh && (hi & SH4_PTEH_ASID_MASK) != (cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK)) continue; if (i < 0) { cpu->cd.sh.itlb_lo[i + SH_N_ITLB_ENTRIES] &= ~SH4_PTEL_V; if (idata & SH4_UTLB_AA_V) cpu->cd.sh.itlb_lo[ i+SH_N_ITLB_ENTRIES] |= SH4_PTEL_V; } else { cpu->cd.sh.utlb_lo[i] &= ~(SH4_PTEL_D | SH4_PTEL_V); if (idata & SH4_UTLB_AA_D) cpu->cd.sh.utlb_lo[i] |= SH4_PTEL_D; if (idata & SH4_UTLB_AA_V) cpu->cd.sh.utlb_lo[i] |= SH4_PTEL_V; } if (i >= 0) n_hits ++; } if (n_hits > 1) sh_exception(cpu, EXPEVT_RESET_TLB_MULTI_HIT, 0, 0); } else { if ((cpu->cd.sh.utlb_lo[e] & SH4_PTEL_SZ_MASK) == SH4_PTEL_SZ_4K) { safe_to_invalidate = 1; vaddr_to_invalidate = cpu->cd.sh.utlb_hi[e] & ~0xfff; } cpu->cd.sh.utlb_hi[e] &= ~(SH4_PTEH_VPN_MASK | SH4_PTEH_ASID_MASK); cpu->cd.sh.utlb_hi[e] |= (idata & (SH4_UTLB_AA_VPN_MASK | SH4_UTLB_AA_ASID_MASK)); cpu->cd.sh.utlb_lo[e] &= ~(SH4_PTEL_D | SH4_PTEL_V); if (idata & SH4_UTLB_AA_D) cpu->cd.sh.utlb_lo[e] |= SH4_PTEL_D; if (idata & SH4_UTLB_AA_V) cpu->cd.sh.utlb_lo[e] |= SH4_PTEL_V; } if (safe_to_invalidate) cpu->invalidate_translation_caches(cpu, vaddr_to_invalidate, INVALIDATE_VADDR); else cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); } else { odata = cpu->cd.sh.utlb_hi[e] & (SH4_UTLB_AA_VPN_MASK | SH4_UTLB_AA_ASID_MASK); if (cpu->cd.sh.utlb_lo[e] & SH4_PTEL_D) odata |= SH4_UTLB_AA_D; if (cpu->cd.sh.utlb_lo[e] & SH4_PTEL_V) odata |= SH4_UTLB_AA_V; memory_writemax64(cpu, data, len, odata); } return 1; } DEVICE_ACCESS(sh4_utlb_da1) { uint32_t mask = SH4_PTEL_WT | SH4_PTEL_SH | SH4_PTEL_D | SH4_PTEL_C | SH4_PTEL_SZ_MASK | SH4_PTEL_PR_MASK | SH4_PTEL_V | 0x1ffffc00; uint64_t idata = 0, odata = 0; int e = (relative_addr & SH4_UTLB_E_MASK) >> SH4_UTLB_E_SHIFT; if (relative_addr & 0x800000) { fatal("sh4_utlb_da1: TODO: da2 area\n"); exit(1); } if (writeflag == MEM_WRITE) { uint32_t old_lo = cpu->cd.sh.utlb_lo[e]; int safe_to_invalidate = 0; if ((cpu->cd.sh.utlb_lo[e] & SH4_PTEL_SZ_MASK)==SH4_PTEL_SZ_4K) safe_to_invalidate = 1; idata = memory_readmax64(cpu, data, len); cpu->cd.sh.utlb_lo[e] &= ~mask; cpu->cd.sh.utlb_lo[e] |= (idata & mask); /* Invalidate if this UTLB entry belongs to the currently running process, or if it was shared: */ if (old_lo & SH4_PTEL_SH || (cpu->cd.sh.utlb_hi[e] & SH4_ITLB_AA_ASID_MASK) == (cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK)) { if (safe_to_invalidate) cpu->invalidate_translation_caches(cpu, cpu->cd.sh.utlb_hi[e] & ~0xfff, INVALIDATE_VADDR); else cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); } } else { odata = cpu->cd.sh.utlb_lo[e] & mask; memory_writemax64(cpu, data, len, odata); } return 1; } DEVICE_ACCESS(sh4_pcic) { struct sh4_data *d = (struct sh4_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); relative_addr += SH4_PCIC; /* Register read/write: */ if (writeflag == MEM_WRITE) d->pcic_reg[PCIC_REG(relative_addr)] = idata; else odata = d->pcic_reg[PCIC_REG(relative_addr)]; /* Special cases: */ switch (relative_addr) { case SH4_PCICONF0: if (writeflag == MEM_WRITE) { fatal("[ sh4_pcic: TODO: Write to SH4_PCICONF0? ]\n"); exit(1); } else { if (strcmp(cpu->cd.sh.cpu_type.name, "SH7751") == 0) { odata = PCI_ID_CODE(PCI_VENDOR_HITACHI, PCI_PRODUCT_HITACHI_SH7751); } else if (strcmp(cpu->cd.sh.cpu_type.name, "SH7751R") == 0) { odata = PCI_ID_CODE(PCI_VENDOR_HITACHI, PCI_PRODUCT_HITACHI_SH7751R); } else { fatal("sh4_pcic: TODO: PCICONF0 read for" " unimplemented CPU type?\n"); exit(1); } } break; case SH4_PCICONF1: case SH4_PCICONF2: case SH4_PCICR: case SH4_PCIBCR1: case SH4_PCIBCR2: case SH4_PCIBCR3: case SH4_PCIWCR1: case SH4_PCIWCR2: case SH4_PCIWCR3: case SH4_PCIMCR: break; case SH4_PCICONF5: /* Hardcoded to what OpenBSD/landisk uses: */ if (writeflag == MEM_WRITE && idata != 0xac000000) { fatal("sh4_pcic: SH4_PCICONF5 unknown value" " 0x%" PRIx32"\n", (uint32_t) idata); exit(1); } break; case SH4_PCICONF6: /* Hardcoded to what OpenBSD/landisk uses: */ if (writeflag == MEM_WRITE && idata != 0x8c000000) { fatal("sh4_pcic: SH4_PCICONF6 unknown value" " 0x%" PRIx32"\n", (uint32_t) idata); exit(1); } break; case SH4_PCILSR0: /* Hardcoded to what OpenBSD/landisk uses: */ if (writeflag == MEM_WRITE && idata != ((64 - 1) << 20)) { fatal("sh4_pcic: SH4_PCILSR0 unknown value" " 0x%" PRIx32"\n", (uint32_t) idata); exit(1); } break; case SH4_PCILAR0: /* Hardcoded to what OpenBSD/landisk uses: */ if (writeflag == MEM_WRITE && idata != 0xac000000) { fatal("sh4_pcic: SH4_PCILAR0 unknown value" " 0x%" PRIx32"\n", (uint32_t) idata); exit(1); } break; case SH4_PCILSR1: /* Hardcoded to what OpenBSD/landisk uses: */ if (writeflag == MEM_WRITE && idata != ((64 - 1) << 20)) { fatal("sh4_pcic: SH4_PCILSR1 unknown value" " 0x%" PRIx32"\n", (uint32_t) idata); exit(1); } break; case SH4_PCILAR1: /* Hardcoded to what OpenBSD/landisk uses: */ if (writeflag == MEM_WRITE && idata != 0xac000000) { fatal("sh4_pcic: SH4_PCILAR1 unknown value" " 0x%" PRIx32"\n", (uint32_t) idata); exit(1); } break; case SH4_PCIMBR: if (writeflag == MEM_WRITE && idata != SH4_PCIC_MEM) { fatal("sh4_pcic: PCIMBR set to 0x%" PRIx32", not" " 0x%" PRIx32"? TODO\n", (uint32_t) idata, (uint32_t) SH4_PCIC_MEM); exit(1); } break; case SH4_PCIIOBR: if (writeflag == MEM_WRITE && idata != SH4_PCIC_IO) { fatal("sh4_pcic: PCIIOBR set to 0x%" PRIx32", not" " 0x%" PRIx32"? TODO\n", (uint32_t) idata, (uint32_t) SH4_PCIC_IO); exit(1); } break; case SH4_PCIPAR: /* PCI bus access Address Register: */ { int bus = (idata >> 16) & 0xff; int dev = (idata >> 11) & 0x1f; int func = (idata >> 8) & 7; int reg = idata & 0xff; bus_pci_setaddr(cpu, d->pci_data, bus, dev, func, reg); } break; case SH4_PCIPDR: /* PCI bus access Data Register: */ bus_pci_data_access(cpu, d->pci_data, writeflag == MEM_READ? &odata : &idata, len, writeflag); break; default:if (writeflag == MEM_READ) { fatal("[ sh4_pcic: read from addr 0x%x: TODO ]\n", (int)relative_addr); } else { fatal("[ sh4_pcic: write to addr 0x%x: 0x%x: TODO ]\n", (int)relative_addr, (int)idata); } exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVICE_ACCESS(sh4_sq) { struct sh4_data *d = (struct sh4_data *) extra; size_t i; if (writeflag == MEM_WRITE) { for (i=0; isq[(relative_addr + i) % sizeof(d->sq)] = data[i]; } else { for (i=0; isq[(relative_addr + i) % sizeof(d->sq)]; } return 1; } DEVICE_ACCESS(sh4) { struct sh4_data *d = (struct sh4_data *) extra; uint64_t idata = 0, odata = 0; int timer_nr = 0, dma_channel = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); relative_addr += SH4_REG_BASE; /* SD-RAM access uses address only: */ if (relative_addr >= 0xff900000 && relative_addr <= 0xff97ffff) { /* Possibly not 100% correct... TODO */ int v = (relative_addr >> 2) & 0xffff; if (relative_addr & 0x00040000) d->sdmr3 = v; else d->sdmr2 = v; debug("[ sh4: sdmr%i set to 0x%04" PRIx16" ]\n", relative_addr & 0x00040000? 3 : 2, v); return 1; } switch (relative_addr) { /*************************************************/ case SH4_PVR_ADDR: odata = cpu->cd.sh.cpu_type.pvr; break; case SH4_PRR_ADDR: odata = cpu->cd.sh.cpu_type.prr; break; case SH4_PTEH: if (writeflag == MEM_READ) odata = cpu->cd.sh.pteh; else { unsigned int old_asid = cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK; cpu->cd.sh.pteh = idata; if ((idata & SH4_PTEH_ASID_MASK) != old_asid) { /* * TODO: Don't invalidate everything, * only those pages that belonged to the * old asid. */ cpu->invalidate_translation_caches( cpu, 0, INVALIDATE_ALL); } } break; case SH4_PTEL: if (writeflag == MEM_READ) odata = cpu->cd.sh.ptel; else cpu->cd.sh.ptel = idata; break; case SH4_TTB: if (writeflag == MEM_READ) odata = cpu->cd.sh.ttb; else cpu->cd.sh.ttb = idata; break; case SH4_TEA: if (writeflag == MEM_READ) odata = cpu->cd.sh.tea; else cpu->cd.sh.tea = idata; break; case SH4_PTEA: if (writeflag == MEM_READ) odata = cpu->cd.sh.ptea; else cpu->cd.sh.ptea = idata; break; case SH4_MMUCR: if (writeflag == MEM_READ) { odata = cpu->cd.sh.mmucr; } else { if (idata & SH4_MMUCR_TI) { /* TLB invalidate. */ int i; for (i = 0; i < SH_N_ITLB_ENTRIES; i++) cpu->cd.sh.itlb_lo[i] &= ~SH4_PTEL_V; for (i = 0; i < SH_N_UTLB_ENTRIES; i++) cpu->cd.sh.utlb_lo[i] &= ~SH4_PTEL_V; cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); /* The TI bit should always read as 0. */ idata &= ~SH4_MMUCR_TI; } cpu->cd.sh.mmucr = idata; } break; case SH4_CCR: if (writeflag == MEM_READ) { odata = cpu->cd.sh.ccr; } else { cpu->cd.sh.ccr = idata; } break; case SH4_QACR0: if (writeflag == MEM_READ) { odata = cpu->cd.sh.qacr0; } else { cpu->cd.sh.qacr0 = idata; } break; case SH4_QACR1: if (writeflag == MEM_READ) { odata = cpu->cd.sh.qacr1; } else { cpu->cd.sh.qacr1 = idata; } break; case SH4_TRA: if (writeflag == MEM_READ) odata = cpu->cd.sh.tra; else cpu->cd.sh.tra = idata; break; case SH4_EXPEVT: if (writeflag == MEM_READ) odata = cpu->cd.sh.expevt; else cpu->cd.sh.expevt = idata; break; case SH4_INTEVT: if (writeflag == MEM_READ) odata = cpu->cd.sh.intevt; else cpu->cd.sh.intevt = idata; break; /********************************/ /* UBC: User Break Controller */ case 0xff000014: /* SH4_UBC_BASRA */ case 0xff000018: /* SH4_UBC_BASRB */ case 0xff200000: /* SH4_UBC_BARA */ case 0xff200004: /* SH4_UBC_BAMRA */ case 0xff200008: /* SH4_UBC_BBRA */ case 0xff20000c: /* SH4_UBC_BARB */ case 0xff200010: /* SH4_UBC_BAMRB */ case 0xff200014: /* SH4_UBC_BBRB */ case 0xff200018: /* SH4_UBC_BDRB */ case 0xff20001c: /* SH4_UBC_BDMRB */ case 0xff200020: /* SH4_UBC_BRCR */ /* TODO */ break; /********************************/ /* TMU: Timer Management Unit */ case SH4_TOCR: /* Timer Output Control Register */ if (writeflag == MEM_WRITE) { d->tocr = idata; if (idata & TOCR_TCOE) fatal("[ sh4 timer: TCOE not yet " "implemented ]\n"); } else { odata = d->tocr; } break; case SH4_TSTR: /* Timer Start Register */ if (writeflag == MEM_READ) { odata = d->tstr; } else { if (idata & 1 && !(d->tstr & 1)) debug("[ sh4 timer: starting timer 0 ]\n"); if (idata & 2 && !(d->tstr & 2)) debug("[ sh4 timer: starting timer 1 ]\n"); if (idata & 4 && !(d->tstr & 4)) debug("[ sh4 timer: starting timer 2 ]\n"); if (!(idata & 1) && d->tstr & 1) debug("[ sh4 timer: stopping timer 0 ]\n"); if (!(idata & 2) && d->tstr & 2) debug("[ sh4 timer: stopping timer 1 ]\n"); if (!(idata & 4) && d->tstr & 4) debug("[ sh4 timer: stopping timer 2 ]\n"); d->tstr = idata; } break; case SH4_TCOR2: timer_nr ++; case SH4_TCOR1: timer_nr ++; case SH4_TCOR0: /* Timer Constant Register */ if (writeflag == MEM_READ) odata = d->tcor[timer_nr]; else d->tcor[timer_nr] = idata; break; case SH4_TCNT2: timer_nr ++; case SH4_TCNT1: timer_nr ++; case SH4_TCNT0: /* Timer Counter Register */ if (writeflag == MEM_READ) odata = d->tcnt[timer_nr]; else d->tcnt[timer_nr] = idata; break; case SH4_TCR2: timer_nr ++; case SH4_TCR1: timer_nr ++; case SH4_TCR0: /* Timer Control Register */ if (writeflag == MEM_READ) { odata = d->tcr[timer_nr]; } else { if (cpu->cd.sh.pclock == 0) { fatal("INTERNAL ERROR: pclock must be set" " for this machine. Aborting.\n"); exit(1); } switch (idata & 3) { case TCR_TPSC_P4: d->timer_hz[timer_nr] = cpu->cd.sh.pclock/4.0; break; case TCR_TPSC_P16: d->timer_hz[timer_nr] = cpu->cd.sh.pclock/16.0; break; case TCR_TPSC_P64: d->timer_hz[timer_nr] = cpu->cd.sh.pclock/64.0; break; case TCR_TPSC_P256: d->timer_hz[timer_nr] = cpu->cd.sh.pclock/256.0; break; } debug("[ sh4 timer %i clock set to %f Hz ]\n", timer_nr, d->timer_hz[timer_nr]); if (idata & (TCR_ICPF | TCR_ICPE1 | TCR_ICPE0 | TCR_CKEG1 | TCR_CKEG0 | TCR_TPSC2)) { fatal("Unimplemented SH4 timer control" " bits: 0x%08" PRIx32". Aborting.\n", (int) idata); exit(1); } INTERRUPT_DEASSERT(d->timer_irq[timer_nr]); if (d->tcr[timer_nr] & TCR_UNF && !(idata & TCR_UNF)) { if (d->timer_interrupts_pending[timer_nr] > 0) d->timer_interrupts_pending[timer_nr]--; } d->tcr[timer_nr] = idata; } break; /*************************************************/ /* DMAC: DMA Controller */ /* 4 channels on SH7750 */ /* 8 channels on SH7760 */ case SH4_SAR7: dma_channel ++; case SH4_SAR6: dma_channel ++; case SH4_SAR5: dma_channel ++; case SH4_SAR4: dma_channel ++; case SH4_SAR3: dma_channel ++; case SH4_SAR2: dma_channel ++; case SH4_SAR1: dma_channel ++; case SH4_SAR0: if (writeflag == MEM_READ) odata = cpu->cd.sh.dmac_sar[dma_channel]; else cpu->cd.sh.dmac_sar[dma_channel] = idata; break; case SH4_DAR7: dma_channel ++; case SH4_DAR6: dma_channel ++; case SH4_DAR5: dma_channel ++; case SH4_DAR4: dma_channel ++; case SH4_DAR3: dma_channel ++; case SH4_DAR2: dma_channel ++; case SH4_DAR1: dma_channel ++; case SH4_DAR0: if (writeflag == MEM_READ) odata = cpu->cd.sh.dmac_dar[dma_channel]; else cpu->cd.sh.dmac_dar[dma_channel] = idata; break; case SH4_DMATCR7: dma_channel ++; case SH4_DMATCR6: dma_channel ++; case SH4_DMATCR5: dma_channel ++; case SH4_DMATCR4: dma_channel ++; case SH4_DMATCR3: dma_channel ++; case SH4_DMATCR2: dma_channel ++; case SH4_DMATCR1: dma_channel ++; case SH4_DMATCR0: if (writeflag == MEM_READ) odata = cpu->cd.sh.dmac_tcr[dma_channel] & 0x00ffffff; else { if (idata & ~0x00ffffff) { fatal("[ SH4 DMA: Attempt to set top 8 " "bits of the count register? 0x%08" PRIx32" ]\n", (uint32_t) idata); exit(1); } cpu->cd.sh.dmac_tcr[dma_channel] = idata; } break; case SH4_CHCR7: dma_channel ++; case SH4_CHCR6: dma_channel ++; case SH4_CHCR5: dma_channel ++; case SH4_CHCR4: dma_channel ++; case SH4_CHCR3: dma_channel ++; case SH4_CHCR2: dma_channel ++; case SH4_CHCR1: dma_channel ++; case SH4_CHCR0: if (writeflag == MEM_READ) { odata = cpu->cd.sh.dmac_chcr[dma_channel]; } else { /* CHCR_CHSET always reads back as 0: */ idata &= ~CHCR_CHSET; cpu->cd.sh.dmac_chcr[dma_channel] = idata; /* Perform a transfer? */ if (idata & CHCR_TD) sh4_dmac_transfer(cpu, d, dma_channel); } break; case SH4_DMAOR: if (writeflag == MEM_READ) { odata = cpu->cd.sh.dmaor; } else { // Only some bits are writable: idata &= (DMAOR_DDT | DMAOR_PR1 | DMAOR_PR0 | DMAOR_DME); cpu->cd.sh.dmaor = idata; } break; /*************************************************/ /* BSC: Bus State Controller */ case SH4_BCR1: if (writeflag == MEM_WRITE) d->bsc_bcr1 = idata & 0x033efffd; else { odata = d->bsc_bcr1; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) odata |= BCR1_LITTLE_ENDIAN; } break; case SH4_BCR2: if (len != sizeof(uint16_t)) { fatal("Non-16-bit SH4_BCR2 access?\n"); exit(1); } if (writeflag == MEM_WRITE) d->bsc_bcr2 = idata & 0x3ffd; else odata = d->bsc_bcr2; break; case SH4_BCR3: if (len != sizeof(uint16_t)) { fatal("Non-16-bit SH4_BCR3 access?\n"); exit(1); } if (writeflag == MEM_WRITE) d->bsc_bcr3 = idata; else odata = d->bsc_bcr3; break; case SH4_WCR1: if (writeflag == MEM_WRITE) d->bsc_wcr1 = idata & 0x77777777; else odata = d->bsc_wcr1; break; case SH4_WCR2: if (writeflag == MEM_WRITE) d->bsc_wcr2 = idata & 0xfffeefff; else odata = d->bsc_wcr2; break; case SH4_WCR3: if (writeflag == MEM_WRITE) d->bsc_wcr3 = idata & 0x77777777; else odata = d->bsc_wcr3; break; case SH4_MCR: if (writeflag == MEM_WRITE) d->bsc_mcr = idata & 0xf8bbffff; else odata = d->bsc_mcr; break; case SH4_PCR: if (writeflag == MEM_WRITE) d->bsc_pcr = idata; else odata = d->bsc_pcr; break; case SH4_RTCSR: /* * Refresh Time Control/Status Register. Called RTCSR in * NetBSD, but RTSCR in the SH7750 manual? */ if (writeflag == MEM_WRITE) { idata &= 0x00ff; if (idata & RTCSR_CMF) { idata = (idata & ~RTCSR_CMF) | (d->bsc_rtcsr & RTCSR_CMF); } d->bsc_rtcsr = idata & 0x00ff; } else odata = d->bsc_rtcsr; break; case SH4_RTCOR: /* Refresh Time Constant Register (8 bits): */ if (writeflag == MEM_WRITE) d->bsc_rtcor = idata & 0x00ff; else odata = d->bsc_rtcor & 0x00ff; break; case SH4_RFCR: /* Refresh Count Register (10 bits): */ if (writeflag == MEM_WRITE) d->bsc_rfcr = idata & 0x03ff; else odata = d->bsc_rfcr & 0x03ff; break; /*******************************************/ /* GPIO: General-purpose I/O controller */ case SH4_PCTRA: if (writeflag == MEM_WRITE) { d->pctra = idata; // Hack: Makes the Dreamcast BIOS pass "cable select" // detection, it seems, without hanging in an endless // loop. d->pdtra |= 0x03; } else { odata = d->pctra; } break; case SH4_PDTRA: if (writeflag == MEM_WRITE) { // debug("[ sh4: pdtra: write 0x%08x (while pctra = 0x%08x) ]\n", (int)idata, (int)d->pctra); d->pdtra = idata; // Hack: Makes the Dreamcast BIOS pass "cable select" // detection, it seems, without hanging in an endless // loop. if ((idata & 1) == 0 || (idata & 2) == 0) d->pdtra &= ~3; } else { // debug("[ sh4: pdtra: read ]\n"); odata = d->pdtra; // bits 8..9 on Dreamcast mean: // 00 = VGA, 10 = RGB, 11 = composite. odata |= (0 << 8); } break; case SH4_PCTRB: if (writeflag == MEM_WRITE) d->pctrb = idata; else odata = d->pctrb; break; case SH4_PDTRB: if (writeflag == MEM_WRITE) { debug("[ sh4: pdtrb: write: TODO ]\n"); d->pdtrb = idata; } else { debug("[ sh4: pdtrb: read: TODO ]\n"); odata = d->pdtrb; } break; case SH4_GPIOIC: if (writeflag == MEM_WRITE) d->bsc_gpioic = idata; else odata = d->bsc_gpioic; break; /****************************/ /* SCI: Serial Interface */ case SHREG_SCSPTR: odata = sh4_sci_access(d, cpu, writeflag == MEM_WRITE? 1 : 0, idata); /* * TODO * * Find out the REAL way to make OpenBSD/landisk 4.1 run * in a stable manner! This is a SUPER-UGLY HACK which * just side-steps the real bug. * * NOTE: Snapshots of OpenBSD/landisk _after_ 4.1 seem * to work WITHOUT this hack, but NOT with it! */ cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); break; /*********************************/ /* INTC: Interrupt Controller */ case SH4_ICR: if (writeflag == MEM_WRITE) { if (idata & 0x80) { fatal("SH4 INTC: IRLM not yet " "supported. TODO\n"); exit(1); } } break; case SH4_IPRA: if (writeflag == MEM_READ) odata = cpu->cd.sh.intc_ipra; else { cpu->cd.sh.intc_ipra = idata; sh_update_interrupt_priorities(cpu); } break; case SH4_IPRB: if (writeflag == MEM_READ) odata = cpu->cd.sh.intc_iprb; else { cpu->cd.sh.intc_iprb = idata; sh_update_interrupt_priorities(cpu); } break; case SH4_IPRC: if (writeflag == MEM_READ) odata = cpu->cd.sh.intc_iprc; else { cpu->cd.sh.intc_iprc = idata; sh_update_interrupt_priorities(cpu); } break; case SH4_IPRD: if (writeflag == MEM_READ) odata = cpu->cd.sh.intc_iprd; else { cpu->cd.sh.intc_iprd = idata; sh_update_interrupt_priorities(cpu); } break; case SH4_INTPRI00: if (writeflag == MEM_READ) odata = cpu->cd.sh.intc_intpri00; else { cpu->cd.sh.intc_intpri00 = idata; sh_update_interrupt_priorities(cpu); } break; case SH4_INTPRI00 + 4: if (writeflag == MEM_READ) odata = cpu->cd.sh.intc_intpri04; else { cpu->cd.sh.intc_intpri04 = idata; sh_update_interrupt_priorities(cpu); } break; case SH4_INTPRI00 + 8: if (writeflag == MEM_READ) odata = cpu->cd.sh.intc_intpri08; else { cpu->cd.sh.intc_intpri08 = idata; sh_update_interrupt_priorities(cpu); } break; case SH4_INTPRI00 + 0xc: if (writeflag == MEM_READ) odata = cpu->cd.sh.intc_intpri0c; else { cpu->cd.sh.intc_intpri0c = idata; sh_update_interrupt_priorities(cpu); } break; case SH4_INTMSK00: /* Note: Writes can only set bits, not clear them. */ if (writeflag == MEM_READ) odata = cpu->cd.sh.intc_intmsk00; else cpu->cd.sh.intc_intmsk00 |= idata; break; case SH4_INTMSK00 + 4: /* Note: Writes can only set bits, not clear them. */ if (writeflag == MEM_READ) odata = cpu->cd.sh.intc_intmsk04; else cpu->cd.sh.intc_intmsk04 |= idata; break; case SH4_INTMSKCLR00: /* Note: Writes can only clear bits, not set them. */ if (writeflag == MEM_WRITE) cpu->cd.sh.intc_intmsk00 &= ~idata; break; case SH4_INTMSKCLR00 + 4: /* Note: Writes can only clear bits, not set them. */ if (writeflag == MEM_WRITE) cpu->cd.sh.intc_intmsk04 &= ~idata; break; /*************************************************/ /* SCIF: Serial Controller Interface with FIFO */ case SH4_SCIF_BASE + SCIF_SMR: if (writeflag == MEM_WRITE) { d->scif_smr = idata; } else { odata = d->scif_smr; } break; case SH4_SCIF_BASE + SCIF_BRR: if (writeflag == MEM_WRITE) { d->scif_brr = idata; } else { odata = d->scif_brr; } break; case SH4_SCIF_BASE + SCIF_SCR: if (writeflag == MEM_WRITE) { d->scif_scr = idata; scif_reassert_interrupts(d); } else { odata = d->scif_scr; } break; case SH4_SCIF_BASE + SCIF_FTDR: if (writeflag == MEM_WRITE) { /* Add to TX fifo: */ if (d->scif_tx_fifo_cursize >= sizeof(d->scif_tx_fifo)) { fatal("[ SCIF TX fifo overrun! ]\n"); d->scif_tx_fifo_cursize = 0; } d->scif_tx_fifo[d->scif_tx_fifo_cursize++] = idata; d->scif_delayed_tx = SCIF_DELAYED_TX_VALUE; } break; case SH4_SCIF_BASE + SCIF_SSR: if (writeflag == MEM_READ) { odata = d->scif_ssr; } else { d->scif_ssr = idata; scif_reassert_interrupts(d); } break; case SH4_SCIF_BASE + SCIF_FRDR: { int x = console_readchar(d->scif_console_handle); if (x == 13) x = 10; odata = x < 0? 0 : x; if (console_charavail(d->scif_console_handle)) d->scif_ssr |= SCSSR2_DR; else d->scif_ssr &= ~SCSSR2_DR; scif_reassert_interrupts(d); } break; case SH4_SCIF_BASE + SCIF_FCR: if (writeflag == MEM_WRITE) { d->scif_fcr = idata; } else { odata = d->scif_fcr; } break; case SH4_SCIF_BASE + SCIF_FDR: /* Nr of bytes in the TX and RX fifos, respectively: */ odata = (console_charavail(d->scif_console_handle)? 1 : 0) + (d->scif_tx_fifo_cursize << 8); break; case SH4_SCIF_BASE + SCIF_SPTR: /* TODO: Implement all bits. */ odata = 0; break; case SH4_SCIF_BASE + SCIF_LSR: /* TODO: Implement all bits. */ odata = 0; break; /*************************************************/ case SH4_CPG_FRQCR: // 0xffc00000 16-bit if (writeflag == MEM_WRITE) d->cpg_frqcr = idata; else odata = d->cpg_frqcr; break; case SH4_CPG_STBCR: // 0xffc00004 8-bit if (writeflag == MEM_WRITE) d->cpg_stbcr = idata; else odata = d->cpg_stbcr; break; case SH4_CPG_WTCNT: // 0xffc00008 8/16-bit if (writeflag == MEM_WRITE) d->cpg_wtcnt = idata; else odata = d->cpg_wtcnt; break; case SH4_CPG_WTCSR: // 0xffc0000c 8/16-bit if (writeflag == MEM_WRITE) d->cpg_wtcsr = idata; else odata = d->cpg_wtcsr; break; case SH4_CPG_STBCR2: // 0xffc00010 8-bit if (writeflag == MEM_WRITE) d->cpg_stbcr2 = idata; else odata = d->cpg_stbcr2; break; /*************************************************/ case SH4_RSECCNT: case SH4_RMINCNT: case SH4_RHRCNT: case SH4_RWKCNT: case SH4_RDAYCNT: case SH4_RMONCNT: case SH4_RYRCNT: case SH4_RSECAR: case SH4_RMINAR: case SH4_RHRAR: case SH4_RWKAR: case SH4_RDAYAR: case SH4_RMONAR: if (writeflag == MEM_WRITE) { d->rtc_reg[(relative_addr - 0xffc80000) / 4] = idata; } else { /* TODO: Update rtc_reg based on host's date/time. */ odata = d->rtc_reg[(relative_addr - 0xffc80000) / 4]; } break; case SH4_RCR1: if (writeflag == MEM_READ) odata = d->rtc_rcr1; else { d->rtc_rcr1 = idata; if (idata & 0x18) { fatal("SH4: TODO: RTC interrupt enable\n"); exit(1); } } break; case SH4_RCR2: if (writeflag == MEM_READ) odata = d->rtc_rcr2; else { d->rtc_rcr2 = idata; // bit 1 (i.e. idata == 0x02) means reset. if (idata != 0x02) { debug("[ SH4: TODO: RTC RCR2 value 0x%02x ignored. ]\n", (int)idata); } } break; /*************************************************/ default:if (writeflag == MEM_READ) { fatal("[ sh4: read from addr 0x%x ]\n", (int)relative_addr); } else { fatal("[ sh4: write to addr 0x%x: 0x%x ]\n", (int)relative_addr, (int)idata); } #ifdef SH4_DEBUG exit(1); #endif } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(sh4) { char tmp[200], n[200]; int i; struct machine *machine = devinit->machine; struct sh4_data *d; CHECK_ALLOCATION(d = (struct sh4_data *) malloc(sizeof(struct sh4_data))); memset(d, 0, sizeof(struct sh4_data)); /* * Main SH4 device, and misc memory stuff: */ memory_device_register(machine->memory, devinit->name, SH4_REG_BASE, 0x01000000, dev_sh4_access, d, DM_DEFAULT, NULL); /* On-chip RAM/cache: */ dev_ram_init(machine, 0x1e000000, 0x8000, DEV_RAM_RAM, 0x0); /* 0xe0000000: Store queues: */ memory_device_register(machine->memory, "sh4_sq", 0xe0000000, 0x04000000, dev_sh4_sq_access, d, DM_DEFAULT, NULL); /* * SCIF (Serial console): */ d->scif_console_handle = console_start_slave(devinit->machine, "SH4 SCIF", 1); snprintf(tmp, sizeof(tmp), "%s.irq[0x%x]", devinit->interrupt_path, SH4_INTEVT_SCIF_RXI); INTERRUPT_CONNECT(tmp, d->scif_rx_irq); snprintf(tmp, sizeof(tmp), "%s.irq[0x%x]", devinit->interrupt_path, SH4_INTEVT_SCIF_TXI); INTERRUPT_CONNECT(tmp, d->scif_tx_irq); /* * Caches (fake): * * 0xf0000000 SH4_CCIA I-Cache address array * 0xf1000000 SH4_CCID I-Cache data array * 0xf4000000 SH4_CCDA D-Cache address array * 0xf5000000 SH4_CCDD D-Cache data array * * TODO: Implement more correct cache behavior? */ dev_ram_init(machine, SH4_CCIA, SH4_ICACHE_SIZE * 2, DEV_RAM_RAM, 0x0); dev_ram_init(machine, SH4_CCID, SH4_ICACHE_SIZE, DEV_RAM_RAM, 0x0); dev_ram_init(machine, SH4_CCDA, SH4_DCACHE_SIZE * 2, DEV_RAM_RAM, 0x0); dev_ram_init(machine, SH4_CCDD, SH4_DCACHE_SIZE, DEV_RAM_RAM, 0x0); /* 0xf2000000 SH4_ITLB_AA */ memory_device_register(machine->memory, "sh4_itlb_aa", SH4_ITLB_AA, 0x01000000, dev_sh4_itlb_aa_access, d, DM_DEFAULT, NULL); /* 0xf3000000 SH4_ITLB_DA1 */ memory_device_register(machine->memory, "sh4_itlb_da1", SH4_ITLB_DA1, 0x01000000, dev_sh4_itlb_da1_access, d, DM_DEFAULT, NULL); /* 0xf6000000 SH4_UTLB_AA */ memory_device_register(machine->memory, "sh4_utlb_aa", SH4_UTLB_AA, 0x01000000, dev_sh4_utlb_aa_access, d, DM_DEFAULT, NULL); /* 0xf7000000 SH4_UTLB_DA1 */ memory_device_register(machine->memory, "sh4_utlb_da1", SH4_UTLB_DA1, 0x01000000, dev_sh4_utlb_da1_access, d, DM_DEFAULT, NULL); /* * PCIC (PCI controller) at 0xfe200000: */ memory_device_register(machine->memory, "sh4_pcic", SH4_PCIC, N_PCIC_REGS * sizeof(uint32_t), dev_sh4_pcic_access, d, DM_DEFAULT, NULL); /* Initial PCI control register contents: */ d->bsc_bcr2 = BCR2_PORTEN; d->pcic_reg[PCIC_REG(SH4_PCICONF2)] = PCI_CLASS_CODE(PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_HOST, 0); /* Register 16 PCIC interrupts: */ for (i=0; iinterrupt_path, i); memset(&templ, 0, sizeof(templ)); templ.line = i; templ.name = n; templ.extra = d; templ.interrupt_assert = sh4_pcic_interrupt_assert; templ.interrupt_deassert = sh4_pcic_interrupt_deassert; interrupt_handler_register(&templ); snprintf(tmp, sizeof(tmp), "%s.irq[0x%x]", devinit->interrupt_path, SH4_INTEVT_IRQ0 + 0x20 * i); INTERRUPT_CONNECT(tmp, d->cpu_pcic_interrupt[i]); } /* Register the PCI bus: */ snprintf(tmp, sizeof(tmp), "%s.pcic", devinit->interrupt_path); d->pci_data = bus_pci_init( devinit->machine, tmp, /* pciirq */ 0, /* pci device io offset */ 0, /* pci device mem offset */ SH4_PCIC_IO, /* PCI portbase */ SH4_PCIC_MEM, /* PCI membase */ tmp, /* PCI irqbase */ 0x00000000, /* ISA portbase */ 0x00000000, /* ISA membase */ "TODOisaIrqBase"); /* ISA irqbase */ /* Return PCI bus pointer, to allow per-machine devices to be added later: */ devinit->return_ptr = d->pci_data; /* * Timer: */ d->sh4_timer = timer_add(SH4_PSEUDO_TIMER_HZ, sh4_timer_tick, d); machine_add_tickfunction(devinit->machine, dev_sh4_tick, d, SH4_TICK_SHIFT); /* Initial Timer values, according to the SH7750 manual: */ d->tcor[0] = 0xffffffff; d->tcnt[0] = 0xffffffff; d->tcor[1] = 0xffffffff; d->tcnt[1] = 0xffffffff; d->tcor[2] = 0xffffffff; d->tcnt[2] = 0xffffffff; snprintf(tmp, sizeof(tmp), "machine[0].cpu[0].irq[0x%x]", SH_INTEVT_TMU0_TUNI0); if (!interrupt_handler_lookup(tmp, &d->timer_irq[0])) { fatal("Could not find interrupt '%s'.\n", tmp); exit(1); } snprintf(tmp, sizeof(tmp), "machine[0].cpu[0].irq[0x%x]", SH_INTEVT_TMU1_TUNI1); if (!interrupt_handler_lookup(tmp, &d->timer_irq[1])) { fatal("Could not find interrupt '%s'.\n", tmp); exit(1); } snprintf(tmp, sizeof(tmp), "machine[0].cpu[0].irq[0x%x]", SH_INTEVT_TMU2_TUNI2); if (!interrupt_handler_lookup(tmp, &d->timer_irq[2])) { fatal("Could not find interrupt '%s'.\n", tmp); exit(1); } // The RTC RCR2 register is "basically" initialized to 0x09, with // some bit undefined. :-) According to the manual. d->rtc_rcr2 = 0x09; /* * Bus State Controller initial values, according to the * SH7760 manual: */ d->bsc_bcr2 = 0x3ffc; d->bsc_wcr1 = 0x77777777; d->bsc_wcr2 = 0xfffeefff; d->bsc_wcr3 = 0x77777777; return 1; } gxemul-0.6.1/src/devices/dev_ns16550.cc000644 001750 001750 00000024251 13402411502 017630 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: NS16550 serial controller * * TODO: Implement the FIFO. */ #include #include #include #include "console.h" #include "cpu.h" #include "device.h" #include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/comreg.h" /* #define debug fatal */ #define TICK_SHIFT 14 #define DEV_NS16550_LENGTH 8 struct ns_data { int addrmult; int in_use; const char *name; int console_handle; int enable_fifo; struct interrupt irq; unsigned char reg[DEV_NS16550_LENGTH]; unsigned char fcr; /* FIFO control register */ int int_asserted; int dlab; /* Divisor Latch Access bit */ int divisor; int databits; char parity; const char *stopbits; }; DEVICE_TICK(ns16550) { /* * This function is called at regular intervals. An interrupt is * asserted if there is a character available for reading, or if the * transmitter slot is empty (i.e. the ns16550 is ready to transmit). */ struct ns_data *d = (struct ns_data *) extra; d->reg[com_iir] &= ~IIR_RXRDY; if (console_charavail(d->console_handle)) d->reg[com_iir] |= IIR_RXRDY; /* * If interrupts are enabled, and interrupts are pending, then * cause a CPU interrupt. */ if (((d->reg[com_ier] & IER_ETXRDY) && (d->reg[com_iir] & IIR_TXRDY)) || ((d->reg[com_ier] & IER_ERXRDY) && (d->reg[com_iir] & IIR_RXRDY))) { d->reg[com_iir] &= ~IIR_NOPEND; if (d->reg[com_mcr] & MCR_IENABLE) { INTERRUPT_ASSERT(d->irq); d->int_asserted = 1; } } else { d->reg[com_iir] |= IIR_NOPEND; if (d->int_asserted) INTERRUPT_DEASSERT(d->irq); d->int_asserted = 0; } } DEVICE_ACCESS(ns16550) { uint64_t idata = 0, odata=0; size_t i; struct ns_data *d = (struct ns_data *) extra; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); #if 0 /* The NS16550 should be accessed using byte read/writes: */ if (len != 1) fatal("[ ns16550 (%s): len=%i, idata=0x%16llx! ]\n", d->name, len, (long long)idata); #endif /* * Always ready to transmit: */ d->reg[com_lsr] |= LSR_TXRDY | LSR_TSRE; d->reg[com_msr] |= MSR_DCD | MSR_DSR | MSR_CTS; d->reg[com_iir] &= ~0xf0; if (d->enable_fifo) d->reg[com_iir] |= ((d->fcr << 5) & 0xc0); d->reg[com_lsr] &= ~LSR_RXRDY; if (console_charavail(d->console_handle)) d->reg[com_lsr] |= LSR_RXRDY; relative_addr /= d->addrmult; if (relative_addr >= DEV_NS16550_LENGTH) { fatal("[ ns16550 (%s): outside register space? relative_addr=" "0x%llx. bad addrmult? bad device length? ]\n", d->name, (long long)relative_addr); return 0; } switch (relative_addr) { case com_data: /* data AND low byte of the divisor */ /* Read/write of the Divisor value: */ if (d->dlab) { /* Write or read the low byte of the divisor: */ if (writeflag == MEM_WRITE) d->divisor = (d->divisor & 0xff00) | idata; else odata = d->divisor & 0xff; break; } /* Read/write of data: */ if (writeflag == MEM_WRITE) { if (d->reg[com_mcr] & MCR_LOOPBACK) console_makeavail(d->console_handle, idata); else console_putchar(d->console_handle, idata); d->reg[com_iir] |= IIR_TXRDY; } else { int x = console_readchar(d->console_handle); odata = x < 0? 0 : x; } dev_ns16550_tick(cpu, d); break; case com_ier: /* interrupt enable AND high byte of the divisor */ /* Read/write of the Divisor value: */ if (d->dlab) { if (writeflag == MEM_WRITE) { /* Set the high byte of the divisor: */ d->divisor = (d->divisor & 0xff) | (idata << 8); debug("[ ns16550 (%s): speed set to %i bps ]\n", d->name, (int)(115200 / d->divisor)); } else odata = d->divisor >> 8; break; } /* IER: */ if (writeflag == MEM_WRITE) { /* This is to supress Linux' behaviour */ if (idata != 0) debug("[ ns16550 (%s): write to ier: 0x%02x ]" "\n", d->name, (int)idata); /* Needed for NetBSD 2.0.x, but not 1.6.2? */ if (!(d->reg[com_ier] & IER_ETXRDY) && (idata & IER_ETXRDY)) d->reg[com_iir] |= IIR_TXRDY; d->reg[com_ier] = idata; dev_ns16550_tick(cpu, d); } else odata = d->reg[com_ier]; break; case com_iir: /* interrupt identification (r), fifo control (w) */ if (writeflag == MEM_WRITE) { debug("[ ns16550 (%s): write to fifo control: 0x%02x ]" "\n", d->name, (int)idata); d->fcr = idata; } else { odata = d->reg[com_iir]; if (d->reg[com_iir] & IIR_TXRDY) d->reg[com_iir] &= ~IIR_TXRDY; debug("[ ns16550 (%s): read from iir: 0x%02x ]\n", d->name, (int)odata); dev_ns16550_tick(cpu, d); } break; case com_lsr: if (writeflag == MEM_WRITE) { debug("[ ns16550 (%s): write to lsr: 0x%02x ]\n", d->name, (int)idata); d->reg[com_lsr] = idata; } else { odata = d->reg[com_lsr]; /* debug("[ ns16550 (%s): read from lsr: 0x%02x ]\n", d->name, (int)odata); */ } break; case com_msr: if (writeflag == MEM_WRITE) { debug("[ ns16550 (%s): write to msr: 0x%02x ]\n", d->name, (int)idata); d->reg[com_msr] = idata; } else { odata = d->reg[com_msr]; debug("[ ns16550 (%s): read from msr: 0x%02x ]\n", d->name, (int)odata); } break; case com_lctl: if (writeflag == MEM_WRITE) { d->reg[com_lctl] = idata; switch (idata & 0x7) { case 0: d->databits = 5; d->stopbits = "1"; break; case 1: d->databits = 6; d->stopbits = "1"; break; case 2: d->databits = 7; d->stopbits = "1"; break; case 3: d->databits = 8; d->stopbits = "1"; break; case 4: d->databits = 5; d->stopbits = "1.5"; break; case 5: d->databits = 6; d->stopbits = "2"; break; case 6: d->databits = 7; d->stopbits = "2"; break; case 7: d->databits = 8; d->stopbits = "2"; break; } switch ((idata & 0x38) / 0x8) { case 0: d->parity = 'N'; break; /* none */ case 1: d->parity = 'O'; break; /* odd */ case 2: d->parity = '?'; break; case 3: d->parity = 'E'; break; /* even */ case 4: d->parity = '?'; break; case 5: d->parity = 'Z'; break; /* zero */ case 6: d->parity = '?'; break; case 7: d->parity = 'o'; break; /* one */ } d->dlab = idata & 0x80? 1 : 0; debug("[ ns16550 (%s): write to lctl: 0x%02x (%s%s" "setting mode %i%c%s) ]\n", d->name, (int)idata, d->dlab? "Divisor Latch access, " : "", idata&0x40? "sending BREAK, " : "", d->databits, d->parity, d->stopbits); } else { odata = d->reg[com_lctl]; debug("[ ns16550 (%s): read from lctl: 0x%02x ]\n", d->name, (int)odata); } break; case com_mcr: if (writeflag == MEM_WRITE) { d->reg[com_mcr] = idata; debug("[ ns16550 (%s): write to mcr: 0x%02x ]\n", d->name, (int)idata); if (!(d->reg[com_iir] & IIR_TXRDY) && (idata & MCR_IENABLE)) d->reg[com_iir] |= IIR_TXRDY; dev_ns16550_tick(cpu, d); } else { odata = d->reg[com_mcr]; debug("[ ns16550 (%s): read from mcr: 0x%02x ]\n", d->name, (int)odata); } break; default: if (writeflag==MEM_READ) { debug("[ ns16550 (%s): read from reg %i ]\n", d->name, (int)relative_addr); odata = d->reg[relative_addr]; } else { debug("[ ns16550 (%s): write to reg %i:", d->name, (int)relative_addr); for (i=0; ireg[relative_addr] = idata; } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(ns16550) { struct ns_data *d; size_t nlen; char *name; CHECK_ALLOCATION(d = (struct ns_data *) malloc(sizeof(struct ns_data))); memset(d, 0, sizeof(struct ns_data)); d->addrmult = devinit->addr_mult; d->in_use = devinit->in_use; d->enable_fifo = 1; d->dlab = 0; d->divisor = 115200 / 9600; d->databits = 8; d->parity = 'N'; d->stopbits = "1"; d->name = devinit->name2 != NULL? devinit->name2 : ""; d->console_handle = console_start_slave(devinit->machine, devinit->name2 != NULL? devinit->name2 : devinit->name, d->in_use); INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); nlen = strlen(devinit->name) + 10; if (devinit->name2 != NULL) nlen += strlen(devinit->name2); CHECK_ALLOCATION(name = (char *) malloc(nlen)); if (devinit->name2 != NULL && devinit->name2[0]) snprintf(name, nlen, "%s [%s]", devinit->name, devinit->name2); else snprintf(name, nlen, "%s", devinit->name); memory_device_register(devinit->machine->memory, name, devinit->addr, DEV_NS16550_LENGTH * d->addrmult, dev_ns16550_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_ns16550_tick, d, TICK_SHIFT); /* * NOTE: Ugly cast into a pointer, because this is a convenient way * to return the console handle to code in src/machines/. */ devinit->return_ptr = (void *)(size_t)d->console_handle; return 1; } gxemul-0.6.1/src/devices/dev_ps2_gs.cc000644 001750 001750 00000010771 13402411502 020006 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: PlayStation 2 graphics system */ #include #include #include #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #define DEV_PS2_GS_LENGTH 0x2000 /* NOTE/TODO: This should be the same as in ps2_stuff: */ #define DEV_PS2_GIF_FAKE_BASE 0x50000000 #define N_GS_REGS 0x108 struct gs_data { uint64_t reg[N_GS_REGS]; /* GS registers */ }; #define GS_S_PMODE_REG 0x00 #define GS_S_SMODE1_REG 0x01 #define GS_S_SMODE2_REG 0x02 #define GS_S_SRFSH_REG 0x03 #define GS_S_SYNCH1_REG 0x04 #define GS_S_SYNCH2_REG 0x05 #define GS_S_SYNCV_REG 0x06 #define GS_S_DISPFB1_REG 0x07 #define GS_S_DISPLAY1_REG 0x08 #define GS_S_DISPFB2_REG 0x09 #define GS_S_DISPLAY2_REG 0x0a #define GS_S_EXTBUF_REG0 0x0b #define GS_S_EXTDATA_REG 0x0c #define GS_S_EXTWRITE_REG 0x0d #define GS_S_BGCOLOR_REG 0x0e //static const char *gs_reg_names[15] = { // "PMODE", "SMODE1", "SMODE2", "SRFSH", // "SYNCH1", "SYNCH2", "SYNCV", "DISPFB1", // "DISPLAY1", "DISPFB2", "DISPLAY2", "EXTBUF", // "EXTDATA", "EXTWRITE", "BGCOLOR" }; #define GS_S_CSR_REG 0x100 #define GS_S_IMR_REG 0x101 #define GS_S_BUSDIR_REG 0x104 #define GS_S_SIGLBLID_REG 0x108 //static const char *gs_reg_high_names[4] = { // "CSR", "IMR", "BUSDIR", "SIGLBLID" // }; DEVICE_ACCESS(ps2_gs) { struct gs_data *d = (struct gs_data *) extra; uint64_t idata = 0, odata = 0; size_t i; int regnr; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); regnr = relative_addr / 16; if (relative_addr & 0xf) { debug("[ gs unaligned access, addr 0x%x ]\n", (int)relative_addr); return 0; } /* Empty the GS FIFO: */ d->reg[GS_S_CSR_REG] &= ~(3 << 14); d->reg[GS_S_CSR_REG] |= (1 << 14); switch (relative_addr) { default: if (writeflag==MEM_READ) { debug("[ gs read from addr 0x%x ]\n", (int)relative_addr); odata = d->reg[regnr]; } else { debug("[ gs write to addr 0x%x:", (int)relative_addr); for (i=0; ireg[regnr] = idata; return 1; } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * devinit_ps2_gs(): * * Initialize the Playstation 2 graphics system. This is a bit tricky. * 'gs' is the memory mapped device, as seen by the main processor. * 'gif' is another thing which has its own memory. DMA is used to * transfer stuff to the gif from the main memory. * There is also a framebuffer, which is separated from the main * memory. * * TODO: Make this clearer. */ DEVINIT(ps2_gs) { struct gs_data *d; char str[100]; CHECK_ALLOCATION(d = (struct gs_data *) malloc(sizeof(struct gs_data))); memset(d, 0, sizeof(struct gs_data)); snprintf(str, sizeof(str) - 1, "ps2_gif addr=0x%llx", (long long)DEV_PS2_GIF_FAKE_BASE); device_add(devinit->machine, str); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_PS2_GS_LENGTH, dev_ps2_gs_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/autodev_tail.cc000644 001750 001750 00000000034 13402411502 020422 0ustar00debugdebug000000 000000 /* autodev_tail.c */ } gxemul-0.6.1/src/devices/dev_ps2_spd.cc000644 001750 001750 00000006654 13402411502 020170 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: PlayStation 2 SPD harddisk controller * * TODO */ #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #define DEV_PS2_SPD_LENGTH 0x800 struct ps2_spd_data { uint64_t wdcaddr; }; DEVICE_ACCESS(ps2_spd) { struct ps2_spd_data *d = (struct ps2_spd_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0x40: case 0x42: case 0x44: case 0x46: case 0x48: case 0x4a: case 0x4c: case 0x4e: debug("[ ps2_spd: wdc access ]\n"); cpu->memory_rw(cpu, mem, (relative_addr - 0x40) / 2 + d->wdcaddr, data, len, writeflag, PHYSICAL); return 1; case 0x5c: /* aux control */ debug("[ ps2_spd: wdc access (2) ]\n"); cpu->memory_rw(cpu, mem, d->wdcaddr + 0x206, data, len, writeflag, PHYSICAL); return 1; default: if (writeflag==MEM_READ) { debug("[ ps2_spd: read from addr 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)odata); } else { debug("[ ps2_spd: write to addr 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(ps2_spd) { struct ps2_spd_data *d; char tmpstr[200]; CHECK_ALLOCATION(d = (struct ps2_spd_data *) malloc(sizeof(struct ps2_spd_data))); memset(d, 0, sizeof(struct ps2_spd_data)); d->wdcaddr = devinit->addr + DEV_PS2_SPD_LENGTH; memory_device_register(devinit->machine->memory, "ps2_spd", devinit->addr, DEV_PS2_SPD_LENGTH, dev_ps2_spd_access, d, DM_DEFAULT, NULL); /* Register a generic wdc device at a bogus address: */ /* IRQ = PS2 SBUS irq 0 */ snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s.ps2_sbus.0", (long long)d->wdcaddr, devinit->interrupt_path); device_add(devinit->machine, tmpstr); return 1; } gxemul-0.6.1/src/devices/dev_disk.cc000644 001750 001750 00000012164 13402411502 017541 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: A simple disk controller device, for the test machines * * Basic "disk" device. This is a simple test device which can be used to * read and write data from disk devices. */ #include #include #include #include "cpu.h" #include "device.h" #include "diskimage.h" #include "emul.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "testmachine/dev_disk.h" extern int verbose; #define SECTOR_SIZE 512 struct disk_data { uint64_t offset; int disk_id; int command; int status; unsigned char *buf; }; DEVICE_ACCESS(disk_buf) { struct disk_data *d = (struct disk_data *) extra; if (writeflag == MEM_WRITE) memcpy(d->buf + relative_addr, data, len); else memcpy(data, d->buf + relative_addr, len); return 1; } DEVICE_ACCESS(disk) { struct disk_data *d = (struct disk_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case DEV_DISK_OFFSET: if (writeflag == MEM_READ) { odata = d->offset; } else { d->offset = idata; } if (d->offset & (SECTOR_SIZE-1)) fatal("[ disk: WARNING! offset (%lli) must be %i-byte aligned ]\n", (long long)d->offset, SECTOR_SIZE); break; case DEV_DISK_OFFSET_HIGH32: if (writeflag == MEM_READ) { odata = d->offset >> 32; } else { d->offset = (uint32_t)d->offset | (idata << 32); } break; case DEV_DISK_ID: if (writeflag == MEM_READ) { odata = d->disk_id; } else { d->disk_id = idata; } break; case DEV_DISK_START_OPERATION: if (writeflag == MEM_READ) { odata = d->command; } else { d->command = idata; switch (d->command) { case 0: d->status = diskimage_access(cpu->machine, d->disk_id, DISKIMAGE_IDE, 0, d->offset, d->buf, SECTOR_SIZE); break; case 1: d->status = diskimage_access(cpu->machine, d->disk_id, DISKIMAGE_IDE, 1, d->offset, d->buf, SECTOR_SIZE); break; } if (verbose >= 2) { debug("[ disk: %s disk %i offset %lli ]\n", d->command ? "WRITE" : "READ", d->disk_id, (long long)d->offset); } d->offset += SECTOR_SIZE; } break; case DEV_DISK_STATUS: if (writeflag == MEM_READ) { odata = d->status; } else { d->status = idata; } break; default:if (writeflag == MEM_WRITE) { fatal("[ disk: unimplemented write to " "offset 0x%x: data=0x%x ]\n", (int) relative_addr, (int)idata); } else { fatal("[ disk: unimplemented read from " "offset 0x%x ]\n", (int)relative_addr); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(disk) { struct disk_data *d; size_t nlen; char *n1, *n2; CHECK_ALLOCATION(d = (struct disk_data *) malloc(sizeof(struct disk_data))); memset(d, 0, sizeof(struct disk_data)); nlen = strlen(devinit->name) + 30; CHECK_ALLOCATION(n1 = (char *) malloc(nlen)); CHECK_ALLOCATION(n2 = (char *) malloc(nlen)); CHECK_ALLOCATION(d->buf = (unsigned char *) malloc(devinit->machine->arch_pagesize)); memset(d->buf, 0, devinit->machine->arch_pagesize); snprintf(n1, nlen, "%s [control]", devinit->name); snprintf(n2, nlen, "%s [data buffer]", devinit->name); memory_device_register(devinit->machine->memory, n1, devinit->addr, DEV_DISK_BUFFER, dev_disk_access, (void *)d, DM_DEFAULT, NULL); memory_device_register(devinit->machine->memory, n2, devinit->addr + DEV_DISK_BUFFER, devinit->machine->arch_pagesize, dev_disk_buf_access, (void *)d, DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK | DM_READS_HAVE_NO_SIDE_EFFECTS, d->buf); return 1; } gxemul-0.6.1/src/devices/dev_sgi_ip19.cc000644 001750 001750 00000007332 13402411502 020234 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SGI IP19 (and IP25) stuff * * NOTE/TODO: The stuff in here is mostly guesswork. */ #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #define DEV_SGI_IP19_LENGTH 0x100000 struct sgi_ip19_data { uint64_t cycle_counter; }; DEVICE_ACCESS(sgi_ip19) { struct sgi_ip19_data *d = (struct sgi_ip19_data *) extra; uint64_t idata = 0, odata = 0; int regnr; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); regnr = relative_addr / sizeof(uint32_t); switch (relative_addr) { case 0x08: /* cpu id */ if (writeflag == MEM_WRITE) { debug("[ sgi_ip19: unimplemented write to address " "0x%x (cpu id), data=0x%08x ]\n", (int) relative_addr, (int)idata); } else { odata = cpu->cpu_id; /* ? TODO */ } break; case 0x200: /* cpu available mask? */ if (writeflag == MEM_WRITE) { debug("[ sgi_ip19: unimplemented write to address " "0x%x (cpu available mask), data=0x%08x ]\n", (int)relative_addr, (int)idata); } else { /* Max 16 cpus? */ odata = ((1 << cpu->machine->ncpus) - 1) << 16; } break; case 0x20000: /* cycle counter or clock */ if (writeflag == MEM_WRITE) { debug("[ sgi_ip19: unimplemented write to address " "0x%x (cycle counter), data=0x%08x ]\n", (int)relative_addr, (int)idata); } else { d->cycle_counter += 100; odata = d->cycle_counter; } break; default: if (writeflag == MEM_WRITE) { debug("[ sgi_ip19: unimplemented write to address " "0x%x, data=0x%08x ]\n", (int)relative_addr, (int)idata); } else { debug("[ sgi_ip19: unimplemented read from address " "0x%x: 0x%08x ]\n", (int)relative_addr, (int)odata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(sgi_ip19) { struct sgi_ip19_data *d; CHECK_ALLOCATION(d = (struct sgi_ip19_data *) malloc(sizeof(struct sgi_ip19_data))); memset(d, 0, sizeof(struct sgi_ip19_data)); memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, DEV_SGI_IP19_LENGTH, dev_sgi_ip19_access, (void *)d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/dev_dreamcast_asic.cc000644 001750 001750 00000013264 13402411502 021553 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2011 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Dreamcast-specific ASIC * * A simple device which forwards various Dreamcast device events as * interrupts 13, 11, or 9, to the CPU. */ #include #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/dreamcast_sysasicvar.h" #include "thirdparty/sh4_exception.h" // #define debug fatal #define DREAMCAST_ASIC_TICK_SHIFT 15 struct dreamcast_asic_data { uint32_t pending_irq[3]; uint32_t mask_13[3]; uint32_t mask_11[3]; uint32_t mask_9[3]; int asserted_13; int asserted_11; int asserted_9; struct interrupt irq_13; struct interrupt irq_11; struct interrupt irq_9; }; DEVICE_TICK(dreamcast_asic) { struct dreamcast_asic_data *d = (struct dreamcast_asic_data *) extra; int i, old_asserted_13 = d->asserted_13, old_asserted_11 = d->asserted_11, old_asserted_9 = d->asserted_9; d->asserted_13 = d->asserted_11 = d->asserted_9 = 0; for (i=0; i<3; i++) { if (d->pending_irq[i] & d->mask_13[i]) d->asserted_13 = 1; if (d->pending_irq[i] & d->mask_11[i]) d->asserted_11 = 1; if (d->pending_irq[i] & d->mask_9[i]) d->asserted_9 = 1; } if (d->asserted_13 != old_asserted_13) { if (d->asserted_13) INTERRUPT_ASSERT(d->irq_13); else INTERRUPT_DEASSERT(d->irq_13); } if (d->asserted_11 != old_asserted_11) { if (d->asserted_11) INTERRUPT_ASSERT(d->irq_11); else INTERRUPT_DEASSERT(d->irq_11); } if (d->asserted_9 != old_asserted_9) { if (d->asserted_9) INTERRUPT_ASSERT(d->irq_9); else INTERRUPT_DEASSERT(d->irq_9); } } DEVICE_ACCESS(dreamcast_asic) { struct dreamcast_asic_data *d = (struct dreamcast_asic_data *) extra; uint64_t idata = 0, odata = 0; int r; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); r = (relative_addr / 4) & 3; if (r == 3) { fatal("[ dreamcast_asic: Bad address ]\n"); r = 0; exit(1); // TODO? } switch (relative_addr) { case 0: case 4: case 8: if (writeflag == MEM_READ) { odata = d->pending_irq[r]; } else { /* Should only be used interally by GXemul: */ if (idata & 0x100000000ULL) { /* Set specific bits: */ d->pending_irq[r] |= idata; } else { /* Clear interrupt assertions: */ d->pending_irq[r] &= ~idata; } dev_dreamcast_asic_tick(cpu, d); } break; case 0x10: case 0x14: case 0x18: if (writeflag == MEM_WRITE) { d->mask_13[r] = idata; dev_dreamcast_asic_tick(cpu, d); } else { odata = d->mask_13[r]; } break; case 0x20: case 0x24: case 0x28: if (writeflag == MEM_WRITE) { d->mask_11[r] = idata; dev_dreamcast_asic_tick(cpu, d); } else { odata = d->mask_11[r]; } break; case 0x30: case 0x34: case 0x38: if (writeflag == MEM_WRITE) { d->mask_9[r] = idata; dev_dreamcast_asic_tick(cpu, d); } else { odata = d->mask_9[r]; } break; default:if (writeflag == MEM_READ) { debug("[ dreamcast_asic: read from addr 0x%x ]\n", (int)relative_addr); } else { debug("[ dreamcast_asic: write to addr 0x%x: 0x%x ]\n", (int)relative_addr, (int)idata); } } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(dreamcast_asic) { char tmpstr[300]; struct machine *machine = devinit->machine; struct dreamcast_asic_data *d; CHECK_ALLOCATION(d = (struct dreamcast_asic_data *) malloc(sizeof(struct dreamcast_asic_data))); memset(d, 0, sizeof(struct dreamcast_asic_data)); /* Connect to SH4 interrupt levels 13, 11, and 9: */ snprintf(tmpstr, sizeof(tmpstr), "%s.irq[0x%x]", devinit->interrupt_path, SH_INTEVT_IRL13); INTERRUPT_CONNECT(tmpstr, d->irq_13); snprintf(tmpstr, sizeof(tmpstr), "%s.irq[0x%x]", devinit->interrupt_path, SH_INTEVT_IRL11); INTERRUPT_CONNECT(tmpstr, d->irq_11); snprintf(tmpstr, sizeof(tmpstr), "%s.irq[0x%x]", devinit->interrupt_path, SH_INTEVT_IRL9); INTERRUPT_CONNECT(tmpstr, d->irq_9); memory_device_register(machine->memory, devinit->name, SYSASIC_BASE, SYSASIC_SIZE, dev_dreamcast_asic_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(devinit->machine, dev_dreamcast_asic_tick, d, DREAMCAST_ASIC_TICK_SHIFT); return 1; } gxemul-0.6.1/src/devices/dev_scc.cc000644 001750 001750 00000031761 13402411502 017363 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Serial controller used in some DECsystem and SGI machines * * Hm... Same as Z8530? Most of the code in here is written for DECsystem * emulation, though. * * NOTE: * Each scc device is responsible for two lines; the first scc device * controls mouse (0) and keyboard (1), and the second device controls * serial ports (2 and 3). * * TODO: * Mouse support!!! (scc0 and scc1 need to cooperate, in order to * emulate the same lk201 behaviour as when using the dc device) * DMA * More correct interrupt support. * ****************************************************************************** * _____ ___ ____ ___ _ * |_ _/ _ \| _ \ / _ \| | * | || | | | | | | | | | | * | || |_| | |_| | |_| |_| * |_| \___/|____/ \___/(_) * * Since this is actually a Z8530, it should be merged with dev_z8530.c! */ #include #include #include #include "console.h" #include "cpu.h" #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/sccreg.h" #define SCC_TICK_SHIFT 14 #define N_SCC_PORTS 2 #define N_SCC_REGS 16 #define MAX_QUEUE_LEN 1024 /* #define SCC_DEBUG */ struct scc_data { struct interrupt irq; int use_fb; int console_handle; int scc_nr; int addrmul; int register_select_in_progress[N_SCC_PORTS]; int register_selected[N_SCC_PORTS]; unsigned char scc_register_r[N_SCC_PORTS * N_SCC_REGS]; unsigned char scc_register_w[N_SCC_PORTS * N_SCC_REGS]; unsigned char rx_queue_char[N_SCC_PORTS * MAX_QUEUE_LEN]; int cur_rx_queue_pos_write[N_SCC_PORTS]; int cur_rx_queue_pos_read[N_SCC_PORTS]; struct lk201_data lk201; }; /* * dev_scc_add_to_rx_queue(): * * Add a character to the receive queue. */ void dev_scc_add_to_rx_queue(void *e, int ch, int portnr) { struct scc_data *d = (struct scc_data *) e; int scc_nr; /* DC's keyboard port ==> SCC keyboard port */ if (portnr == 0) portnr = 3; scc_nr = portnr / N_SCC_PORTS; if (scc_nr != d->scc_nr) return; portnr &= (N_SCC_PORTS - 1); d->rx_queue_char[portnr * MAX_QUEUE_LEN + d->cur_rx_queue_pos_write[portnr]] = ch; d->cur_rx_queue_pos_write[portnr] ++; if (d->cur_rx_queue_pos_write[portnr] == MAX_QUEUE_LEN) d->cur_rx_queue_pos_write[portnr] = 0; if (d->cur_rx_queue_pos_write[portnr] == d->cur_rx_queue_pos_read[portnr]) fatal("warning: add_to_rx_queue(): rx_queue overrun!\n"); } static int rx_avail(struct scc_data *d, int portnr) { return d->cur_rx_queue_pos_write[portnr] != d->cur_rx_queue_pos_read[portnr]; } static unsigned char rx_nextchar(struct scc_data *d, int portnr) { unsigned char ch; ch = d->rx_queue_char[portnr * MAX_QUEUE_LEN + d->cur_rx_queue_pos_read[portnr]]; d->cur_rx_queue_pos_read[portnr]++; if (d->cur_rx_queue_pos_read[portnr] == MAX_QUEUE_LEN) d->cur_rx_queue_pos_read[portnr] = 0; return ch; } DEVICE_TICK(scc) { struct scc_data *d = (struct scc_data *) extra; int i; /* Add keystrokes to the rx queue: */ if (d->scc_nr == 1) { if (d->use_fb == 0) { if (console_charavail(d->console_handle)) dev_scc_add_to_rx_queue(extra, console_readchar( d->console_handle), 2); } else if (d->use_fb == 1) lk201_tick(cpu->machine, &d->lk201); } for (i=0; iscc_register_r[i * N_SCC_REGS + SCC_RR0] |= SCC_RR0_TX_EMPTY; d->scc_register_r[i * N_SCC_REGS + SCC_RR1] = 0; /* No receive errors */ d->scc_register_r[i * N_SCC_REGS + SCC_RR0] &= ~SCC_RR0_RX_AVAIL; if (rx_avail(d, i)) d->scc_register_r[i * N_SCC_REGS + SCC_RR0] |= SCC_RR0_RX_AVAIL; /* * Interrupts: * (NOTE: Interrupt enables are always at channel A) */ if (d->scc_register_w[N_SCC_REGS + SCC_WR9] & SCC_WR9_MASTER_IE) { /* TX interrupts? */ if (d->scc_register_w[i * N_SCC_REGS + SCC_WR1] & SCC_WR1_TX_IE) { if (d->scc_register_r[i * N_SCC_REGS + SCC_RR3] & SCC_RR3_TX_IP_A || d->scc_register_r[i * N_SCC_REGS + SCC_RR3] & SCC_RR3_TX_IP_B) { INTERRUPT_ASSERT(d->irq); } } /* RX interrupts? */ if (d->scc_register_w[N_SCC_REGS + SCC_WR1] & (SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_RXI_ALL_CHAR)) { if (d->scc_register_r[i * N_SCC_REGS + SCC_RR0] & SCC_RR0_RX_AVAIL) { if (i == SCC_CHANNEL_A) d->scc_register_r[N_SCC_REGS + SCC_RR3] |= SCC_RR3_RX_IP_A; else d->scc_register_r[N_SCC_REGS + SCC_RR3] |= SCC_RR3_RX_IP_B; } if (d->scc_register_r[i * N_SCC_REGS + SCC_RR3] & SCC_RR3_RX_IP_A || d->scc_register_r[i * N_SCC_REGS + SCC_RR3] & SCC_RR3_RX_IP_B) { INTERRUPT_ASSERT(d->irq); } } if (d->scc_register_w[N_SCC_REGS + SCC_WR1] & SCC_WR1_DMA_MODE) { if (d->scc_register_r[i * N_SCC_REGS + SCC_RR0] & SCC_RR0_RX_AVAIL) { if (i == SCC_CHANNEL_A) d->scc_register_r[N_SCC_REGS + SCC_RR3] |= SCC_RR3_EXT_IP_A; else d->scc_register_r[N_SCC_REGS + SCC_RR3] |= SCC_RR3_EXT_IP_B; } if (d->scc_register_r[i * N_SCC_REGS + SCC_RR3] & SCC_RR3_EXT_IP_A || d->scc_register_r[i * N_SCC_REGS + SCC_RR3] & SCC_RR3_EXT_IP_B) { INTERRUPT_ASSERT(d->irq); } } } } } /* * dev_scc_dma_func(): */ int dev_scc_dma_func(struct cpu *cpu, void *extra, uint64_t addr, size_t dma_len, int tx) { /* printf("dev_scc_dma_func(): addr = %08x, len = %i\n", (int)addr, (int)dma_len); */ unsigned char word[4]; struct scc_data *d = (struct scc_data *) extra; int n; int port = SCC_CHANNEL_A; /* TODO */ if (tx) { do { cpu->memory_rw(cpu, cpu->mem, addr, &word[0], sizeof(word), MEM_READ, NO_EXCEPTIONS | PHYSICAL); lk201_tx_data(&d->lk201, d->scc_nr * 2 + port, word[1]); /* Loopback: */ if (d->scc_register_w[port * N_SCC_REGS + SCC_WR14] & SCC_WR14_LOCAL_LOOPB) dev_scc_add_to_rx_queue(d, word[1], d->scc_nr * 2 + port); addr += sizeof(word); } while ((addr & 0xffc) != 0); dev_scc_tick(cpu, extra); return 1; } else { printf("dev_scc_dma_func(): addr = %08x, len = %i\n", (int)addr, (int)dma_len); /* TODO: all this is just nonsense */ n = 0; while (rx_avail(d, port)) { word[0] = word[1] = word[2] = word[3] = 0; word[0] = word[1] = word[2] = word[3] = rx_nextchar(d, port); n++; cpu->memory_rw(cpu, cpu->mem, addr, &word[0], sizeof(word), MEM_WRITE, NO_EXCEPTIONS | PHYSICAL); addr += sizeof(word); /* Half-page? */ if ((addr & 0x7fc) == 0) break; } dev_scc_tick(cpu, extra); return n*4; } } DEVICE_ACCESS(scc) { struct scc_data *d = (struct scc_data *) extra; uint64_t idata = 0, odata = 0; int port; int ultrix_mode = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); /* relative_addr /= d->addrmul; */ /* See SGI comment below instead. */ /* * SGI writes command to 0x0f, and data to 0x1f. * (TODO: This works for port nr 0, how about port nr 1?) */ if ((relative_addr & 0x0f) == 0xf) { if (relative_addr == 0x0f) relative_addr = 1; else relative_addr = 5; } port = relative_addr / 8; relative_addr &= 7; dev_scc_tick(cpu, extra); /* * Ultrix writes words such as 0x1200 to relative address 0, * instead of writing the byte 0x12 directly to address 1. */ if ((relative_addr == 0 || relative_addr == 4) && (idata & 0xff) == 0) { ultrix_mode = 1; relative_addr ++; idata >>= 8; } switch (relative_addr) { case 1: /* command */ if (writeflag==MEM_READ) { odata = d->scc_register_r[port * N_SCC_REGS + d->register_selected[port]]; if (d->register_selected[port] == SCC_RR3) { if (port == SCC_CHANNEL_B) fatal("WARNING! scc channel B has " "no RR3\n"); d->scc_register_r[port * N_SCC_REGS + SCC_RR3] = 0; INTERRUPT_DEASSERT(d->irq); } #ifdef SCC_DEBUG fatal("[ scc: port %i, register %i, read value " "0x%02x ]\n", port, d->register_selected[port], (int)odata); #endif d->register_select_in_progress[port] = 0; d->register_selected[port] = 0; /* debug("[ scc: (port %i) read from 0x%08lx ]\n", port, (long)relative_addr); */ } else { /* If no register is selected, then select one. Otherwise, write to the selected register. */ if (d->register_select_in_progress[port] == 0) { d->register_select_in_progress[port] = 1; d->register_selected[port] = idata; d->register_selected[port] &= (N_SCC_REGS-1); } else { d->scc_register_w[port * N_SCC_REGS + d->register_selected[port]] = idata; #ifdef SCC_DEBUG fatal("[ scc: port %i, register %i, write " "value 0x%02x ]\n", port, d->register_selected[port], idata); #endif d->scc_register_r[port * N_SCC_REGS + SCC_RR12] = d->scc_register_w[port * N_SCC_REGS + SCC_WR12]; d->scc_register_r[port * N_SCC_REGS + SCC_RR13] = d->scc_register_w[port * N_SCC_REGS + SCC_WR13]; d->register_select_in_progress[port] = 0; d->register_selected[port] = 0; } } break; case 5: /* data */ if (writeflag==MEM_READ) { if (rx_avail(d, port)) odata = rx_nextchar(d, port); /* TODO: perhaps only clear the RX part of RR3? */ d->scc_register_r[N_SCC_REGS + SCC_RR3] = 0; INTERRUPT_DEASSERT(d->irq); // debug("[ scc: (port %i) read from 0x%08lx: 0x%02x ]\n", // port, (long)relative_addr, (int)odata); } else { /* debug("[ scc: (port %i) write to 0x%08lx: " "0x%08x ]\n", port, (long)relative_addr, (int)idata); */ /* Send the character: */ lk201_tx_data(&d->lk201, d->scc_nr * 2 + port, idata); /* Loopback: */ if (d->scc_register_w[port * N_SCC_REGS + SCC_WR14] & SCC_WR14_LOCAL_LOOPB) dev_scc_add_to_rx_queue(d, idata, d->scc_nr * 2 + port); /* TX interrupt: */ if (d->scc_register_w[port * N_SCC_REGS + SCC_WR9] & SCC_WR9_MASTER_IE && d->scc_register_w[port * N_SCC_REGS + SCC_WR1] & SCC_WR1_TX_IE) { if (port == SCC_CHANNEL_A) d->scc_register_r[N_SCC_REGS + SCC_RR3] |= SCC_RR3_TX_IP_A; else d->scc_register_r[N_SCC_REGS + SCC_RR3] |= SCC_RR3_TX_IP_B; } dev_scc_tick(cpu, extra); } break; default: if (writeflag==MEM_READ) { debug("[ scc: (port %i) read from 0x%08lx ]\n", port, (long)relative_addr); } else { debug("[ scc: (port %i) write to 0x%08lx: 0x%08x ]\n", port, (long)relative_addr, (int)idata); } } if (ultrix_mode && writeflag == MEM_READ) { odata <<= 8; } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_scc_init(): * * use_fb = non-zero when using graphical console + keyboard * scc_nr = 0 or 1 * addmul = 1 in most cases, 8 on SGI? */ void *dev_scc_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, char* irq_path, int use_fb, int scc_nr, int addrmul) { struct scc_data *d; CHECK_ALLOCATION(d = (struct scc_data *) malloc(sizeof(struct scc_data))); memset(d, 0, sizeof(struct scc_data)); INTERRUPT_CONNECT(irq_path, d->irq); d->scc_nr = scc_nr; d->use_fb = use_fb; d->addrmul = addrmul; d->console_handle = console_start_slave(machine, "SCC", 1); d->scc_register_r[SCC_RR0] |= SCC_RR0_TX_UNDERRUN; lk201_init(&d->lk201, use_fb, dev_scc_add_to_rx_queue, d->console_handle, d); memory_device_register(mem, "scc", baseaddr, DEV_SCC_LENGTH, dev_scc_access, d, DM_DEFAULT, NULL); machine_add_tickfunction(machine, dev_scc_tick, d, SCC_TICK_SHIFT); return (void *) d; } gxemul-0.6.1/src/devices/dev_turbochannel.cc000644 001750 001750 00000025553 13402411502 021301 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: TURBOchannel bus framework, used in DECstation machines */ #include #include #include #include "devices.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "thirdparty/sfbreg.h" #define DEVICE_MAX_NAMELEN 9 #define CARD_NAME_BUFLEN 9 #define CARD_FIRMWARE_BUFLEN 5 struct turbochannel_data { int slot_nr; uint64_t baseaddr; uint64_t endaddr; int rom_skip; char device_name[DEVICE_MAX_NAMELEN]; /* NUL-terminated */ /* These should be terminated with spaces */ char card_firmware_version[CARD_NAME_BUFLEN]; char card_vendor_name[CARD_NAME_BUFLEN]; char card_module_name[CARD_NAME_BUFLEN]; char card_firmware_type[CARD_FIRMWARE_BUFLEN]; }; DEVICE_ACCESS(turbochannel) { struct turbochannel_data *d = (struct turbochannel_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); relative_addr += d->rom_skip; if (writeflag == MEM_READ) { debug("[ turbochannel: read from slot %i addr 0x%08lx (", d->slot_nr, (long)relative_addr); relative_addr &= 0x7fff; switch (relative_addr) { case 0x3e0: odata = 0x00000001; debug("ROM width"); break; case 0x3e4: odata = 0x00000004; debug("ROM stride"); break; case 0x3e8: /* 8KB * romsize */ odata = 0x00000001; debug("ROM size"); break; case 0x3ec: /* 4MB * slotsize */ odata = 0x00000001; debug("slot size"); break; case 0x3f0: odata = 0x55555555; debug("ROM signature byte 0"); break; case 0x3f4: odata = 0x00000000; debug("ROM signature byte 1"); break; case 0x3f8: odata = 0xaaaaaaaa; debug("ROM signature byte 2"); break; case 0x3fc: odata = 0xffffffff; debug("ROM signature byte 3"); break; case 0x470: /* 0=nothing, 1=parity */ odata = 0x00000000; debug("flags"); break; default: if (relative_addr >= 0x400 && relative_addr < 0x420) odata = d->card_firmware_version[ (relative_addr-0x400)/4]; else if (relative_addr >= 0x420 && relative_addr < 0x440) odata = d->card_vendor_name[ (relative_addr-0x420)/4]; else if (relative_addr >= 0x440 && relative_addr < 0x460) odata = d->card_module_name[ (relative_addr-0x440)/4]; else if (relative_addr >= 0x460 && relative_addr < 0x470) odata = d->card_firmware_type[ (relative_addr-0x460)/4]; else { debug("?"); } } /* * If this slot is empty, return an error so that a DBE * exception is caused. (This is the way DECstation operating * systems have to detect the absence of cards in a * TURBOchannel slot.) * * NOTE: The Sprite kernel reads from offsets 0x3e0..0x400 * without handling the DBE exception, and both Ultrix and * NetBSD seem to detect the DBE exception using addresses * around offset 0x0 or 0x3c0000. This code seems to work * with all of the those OS kernels: */ if (d->card_module_name[0] == ' ') { /* Return no data for empty slot: */ odata = 0; /* Return DBE exception in some cases: */ if (relative_addr < 0x3e0 || relative_addr >= 0x500) return 0; } debug(") ]\n"); } else { /* debug("[ turbochannel: write to 0x%08lx: 0x%08x ]\n", (long)relative_addr, (int)idata); */ } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } /* * dev_turbochannel_init(): * * This is a generic turbochannel card device. device_name should point * to a string such as "PMAG-BA". * * TODO: When running for example dual-head, maybe the name of each * framebuffer should include the card slot number? */ void dev_turbochannel_init(struct machine *machine, struct memory *mem, int slot_nr, uint64_t baseaddr, uint64_t endaddr, const char *device_name, const char *irq_path) { struct vfb_data *fb; struct turbochannel_data *d; int rom_offset=0x3c0000, rom_length=DEV_TURBOCHANNEL_LEN, rom_skip=0; char *name2; size_t nlen; if (device_name == NULL) return; if (strlen(device_name) > 8) { fprintf(stderr, "dev_turbochannel_init(): bad device_name\n"); exit(1); } CHECK_ALLOCATION(d = (struct turbochannel_data *) malloc(sizeof(struct turbochannel_data))); memset(d, 0, sizeof(struct turbochannel_data)); d->slot_nr = slot_nr; d->baseaddr = baseaddr; d->endaddr = endaddr; strlcpy(d->device_name, device_name, DEVICE_MAX_NAMELEN); strncpy(d->card_firmware_version, "V5.3a ", CARD_NAME_BUFLEN); strncpy(d->card_vendor_name, "DEC ", CARD_NAME_BUFLEN); strncpy(d->card_firmware_type, "TCF0", CARD_FIRMWARE_BUFLEN); memset(d->card_module_name, ' ', 8); memcpy(d->card_module_name, device_name, strlen(device_name)); /* * According to NetBSD/pmax: * * PMAD-AA: le1 at tc0 slot 2 offset 0x0: address 00:00:00:00:00:00 * PMAG-AA: mfb0 at tc0 slot 2 offset 0x0: 1280x1024x8 * PMAG-BA: cfb0 at tc0 slot 2 offset 0x0cfb0: 1024x864x8 * PMAG-CA: px0 at tc0 slot 2 offset 0x0: 2D, 4x1 stamp, 8 plane * (PMAG-DA,EA,FA,FB are also pixelstamps) * PMAG-DV: xcfb0 at tc0 slot 2 offset 0x0: 1024x768x8 * PMAG-JA: "truecolor" in Ultrix * PMAGB-BA: sfb0 at tc0 slot 0 offset 0x0: 0x0x8 * PMAGB-VA: sfb0 at tc0 slot 2 offset 0x0: 0x0x8 * PMAZ-AA: asc0 at tc0 slot 2 offset 0x0: NCR53C94, 25MHz, SCSI ID 7 * * PMAF-FA: fta0 at tc0 slot 0 (fddi network, "DEC", "V1.0b") */ if (strcmp(device_name, "PMAD-AA")==0) { /* le in NetBSD, Lance ethernet */ dev_le_init(machine, mem, baseaddr, 0, 0, irq_path, DEV_LE_LENGTH); /* One ROM at 0x1c03e0, and one at 0x3c0000. */ rom_skip = 0x300; rom_offset = 0x1c0000; rom_length = 0x201000; } else if (strcmp(device_name, "PMAZ-AA")==0) { /* asc in NetBSD, SCSI */ dev_asc_init(machine, mem, baseaddr, irq_path, d, DEV_ASC_DEC, NULL, NULL); rom_offset = 0xc0000; /* There is a copy at 0x0, at least that's where Linux looks for the rom signature */ } else if (strcmp(device_name, "PMAG-AA")==0) { /* mfb in NetBSD */ fb = dev_fb_init(machine, mem, baseaddr + VFB_MFB_VRAM, VFB_GENERIC, 1280, 1024, 2048, 1024, 8, device_name); /* bt455 = palette, bt431 = cursor */ dev_bt455_init(mem, baseaddr + VFB_MFB_BT455, fb); dev_bt431_init(mem, baseaddr + VFB_MFB_BT431, fb, 8); rom_offset = 0; } else if (strcmp(device_name, "PMAG-BA")==0) { /* cfb in NetBSD */ fb = dev_fb_init(machine, mem, baseaddr, VFB_GENERIC, 1024,864, 1024,1024,8, device_name); dev_bt459_init(machine, mem, baseaddr + VFB_CFB_BT459, baseaddr + 0x300000, fb, 8, irq_path, BT459_BA); /* ROM at both 0x380000 and 0x3c0000? */ rom_offset = 0x380000; rom_length = 0x080000; } else if (strcmp(device_name, "PMAGB-BA")==0) { /* sfb in NetBSD */ /* TODO: This is not working with Ultrix yet. */ fb = dev_fb_init(machine, mem, baseaddr + SFB_OFFSET_VRAM, VFB_GENERIC, 1280,1024, 1280,1024,8, device_name); dev_sfb_init(machine, mem, baseaddr + SFB_ASIC_OFFSET, fb); /* TODO: the CLEAR doesn't get through, as the address range is already in use by the asic */ dev_bt459_init(machine, mem, baseaddr + SFB_OFFSET_BT459, baseaddr + SFB_CLEAR, fb, 8, irq_path, BT459_BBA); rom_offset = 0x0; /* ? TODO */ } else if (strcmp(device_name, "PMAG-CA")==0) { /* px in NetBSD */ dev_px_init(machine, mem, baseaddr, DEV_PX_TYPE_PX, irq_path); rom_offset = 0x3c0000; } else if (strcmp(device_name, "PMAG-DA")==0) { /* pxg in NetBSD */ dev_px_init(machine, mem, baseaddr, DEV_PX_TYPE_PXG, irq_path); rom_offset = 0x3c0000; } else if (strcmp(device_name, "PMAG-EA")==0) { /* pxg+ in NetBSD: TODO (not supported by the kernel I've tried) */ fatal("TODO (see dev_turbochannel.c)\n"); rom_offset = 0x3c0000; } else if (strcmp(device_name, "PMAG-FA")==0) { /* "pxg+ Turbo" in NetBSD */ dev_px_init(machine, mem, baseaddr, DEV_PX_TYPE_PXGPLUSTURBO, irq_path); rom_offset = 0x3c0000; } else if (strcmp(device_name, "PMAG-DV")==0) { /* xcfb in NetBSD: TODO */ fb = dev_fb_init(machine, mem, baseaddr + 0x2000000, VFB_DEC_MAXINE, 0, 0, 0, 0, 0, "PMAG-DV"); /* TODO: not yet usable, needs a IMS332 vdac */ rom_offset = 0x3c0000; } else if (strcmp(device_name, "PMAG-JA")==0) { /* "Truecolor", mixed 8- and 24-bit */ dev_pmagja_init(machine, mem, baseaddr, irq_path); rom_offset = 0; /* NOTE: 0, not 0x3c0000 */ } else if (strcmp(device_name, "PMAG-RO")==0) { /* This works at least B/W in Ultrix, so far. */ fb = dev_fb_init(machine, mem, baseaddr + 0x200000, VFB_GENERIC, 1280,1024, 1280,1024, 8, "PMAG-RO"); /* TODO: bt463 at offset 0x040000, not bt459 */ dev_bt459_init(machine, mem, baseaddr + 0x40000, 0, fb, 8, irq_path, 0); /* TODO: type */ dev_bt431_init(mem, baseaddr + 0x40010, fb, 8); /* cursor */ rom_offset = 0x3c0000; } else if (device_name[0] == '\0') { /* If this slot is empty, then occupy the entire 4MB slot address range: */ rom_offset = 0; rom_length = 4*1048576; } else { fatal("warning: unknown TURBOchannel device name \"%s\"\n", device_name); } d->rom_skip = rom_skip; nlen = strlen(device_name) + 30; CHECK_ALLOCATION(name2 = (char *) malloc(nlen)); if (*device_name) snprintf(name2, nlen, "turbochannel [%s]", device_name); else snprintf(name2, nlen, "turbochannel"); memory_device_register(mem, name2, baseaddr + rom_offset + rom_skip, rom_length-rom_skip, dev_turbochannel_access, d, DM_DEFAULT, NULL); } gxemul-0.6.1/src/devices/dev_kn01.cc000644 001750 001750 00000015465 13402411502 017367 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: DEC KN01 ("PMAX", DECstation type 1) control register and VDAC * * TODO: The CSR isn't really complete. * * One of the few usable bits in the csr would be KN01_CSR_MONO. * If that bit is set, the framebuffer is treated as a monochrome * one. */ #include #include #include #include "cpu.h" #include "devices.h" #include "memory.h" #include "misc.h" #include "thirdparty/dec_kn01.h" struct kn01_data { int color_fb; uint32_t csr; }; struct vdac_data { unsigned char vdac_reg[DEV_VDAC_LENGTH]; int color_fb_flag; unsigned char cur_read_addr; unsigned char cur_write_addr; int sub_color; /* subcolor. 0, 1, or 2 */ unsigned char cur_rgb[3]; unsigned char *rgb_palette; /* ptr to 256 * 3 (r,g,b) */ unsigned char cur_read_addr_overlay; unsigned char cur_write_addr_overlay; int sub_color_overlay; /* subcolor: 0, 1, or 2 */ unsigned char cur_rgb_overlay[3]; unsigned char rgb_palette_overlay[16 * 3]; /* 16 * 3 (r,g,b) */ }; DEVICE_ACCESS(kn01) { struct kn01_data *d = (struct kn01_data *) extra; int csr; if (writeflag == MEM_WRITE) { /* TODO */ return 1; } /* Read: */ if (len != 2 || relative_addr != 0) { fatal("[ kn01: trying to read something which is not " "the first half-word of the csr ]"); } csr = d->csr; if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { data[0] = csr & 0xff; data[1] = (csr >> 8) & 0xff; } else { data[1] = csr & 0xff; data[0] = (csr >> 8) & 0xff; } return 1; } /* * dev_vdac_access(): */ DEVICE_ACCESS(vdac) { struct vdac_data *d = (struct vdac_data *) extra; /* Read from/write to the vdac: */ switch (relative_addr) { case DEV_VDAC_MAPWA: if (writeflag == MEM_WRITE) { d->cur_write_addr = data[0]; d->sub_color = 0; } else { debug("[ vdac: read from MAPWA ]\n"); data[0] = d->vdac_reg[relative_addr]; } break; case DEV_VDAC_MAP: if (writeflag == MEM_WRITE) { d->cur_rgb[d->sub_color] = data[0]; d->sub_color++; if (d->sub_color > 2) { /* (Only update for color, not mono mode) */ if (d->color_fb_flag) memcpy(d->rgb_palette + 3*d->cur_write_addr, d->cur_rgb, 3); d->sub_color = 0; d->cur_write_addr ++; } } else { if (d->sub_color == 0) { memcpy(d->cur_rgb, d->rgb_palette + 3 * d->cur_read_addr, 3); } data[0] = d->cur_rgb[d->sub_color]; d->sub_color++; if (d->sub_color > 2) { d->sub_color = 0; d->cur_read_addr ++; } } break; case DEV_VDAC_MAPRA: if (writeflag == MEM_WRITE) { d->cur_read_addr = data[0]; d->sub_color = 0; } else { debug("[ vdac: read from MAPRA ]\n"); data[0] = d->vdac_reg[relative_addr]; } break; case DEV_VDAC_OVERWA: if (writeflag == MEM_WRITE) { d->cur_write_addr_overlay = data[0]; d->sub_color_overlay = 0; } else { debug("[ vdac: read from OVERWA ]\n"); data[0] = d->vdac_reg[relative_addr]; } break; case DEV_VDAC_OVER: if (writeflag == MEM_WRITE) { d->cur_rgb_overlay[d->sub_color_overlay] = data[0]; d->sub_color_overlay++; if (d->sub_color_overlay > 2) { /* (Only update for color, not mono mode) */ if (d->color_fb_flag) memcpy(d->rgb_palette_overlay + 3 * d->cur_write_addr_overlay, d->cur_rgb_overlay, 3); d->sub_color_overlay = 0; d->cur_write_addr_overlay ++; if (d->cur_write_addr_overlay > 15) d->cur_write_addr_overlay = 0; } } else { if (d->sub_color_overlay == 0) { memcpy(d->cur_rgb_overlay, d->rgb_palette_overlay + 3 * d->cur_read_addr_overlay, 3); } data[0] = d->cur_rgb_overlay[d->sub_color_overlay]; d->sub_color_overlay++; if (d->sub_color_overlay > 2) { d->sub_color_overlay = 0; d->cur_read_addr_overlay ++; if (d->cur_read_addr_overlay > 15) d->cur_read_addr_overlay = 0; } } break; case DEV_VDAC_OVERRA: if (writeflag == MEM_WRITE) { d->cur_read_addr_overlay = data[0]; d->sub_color_overlay = 0; } else { debug("[ vdac: read from OVERRA ]\n"); data[0] = d->vdac_reg[relative_addr]; } break; default: if (writeflag == MEM_WRITE) { debug("[ vdac: unimplemented write to address 0x%x," " data=0x%02x ]\n", (int)relative_addr, data[0]); d->vdac_reg[relative_addr] = data[0]; } else { debug("[ vdac: unimplemented read from address 0x%x" " ]\n", (int)relative_addr); data[0] = d->vdac_reg[relative_addr]; } } /* Pretend it was ok: */ return 1; } /* * dev_vdac_init(): */ void dev_vdac_init(struct memory *mem, uint64_t baseaddr, unsigned char *rgb_palette, int color_fb_flag) { struct vdac_data *d; CHECK_ALLOCATION(d = (struct vdac_data *) malloc(sizeof(struct vdac_data))); memset(d, 0, sizeof(struct vdac_data)); d->rgb_palette = rgb_palette; d->color_fb_flag = color_fb_flag; memory_device_register(mem, "vdac", baseaddr, DEV_VDAC_LENGTH, dev_vdac_access, (void *)d, DM_DEFAULT, NULL); } /* * dev_kn01_init(): */ void dev_kn01_init(struct memory *mem, uint64_t baseaddr, int color_fb) { struct kn01_data *d; CHECK_ALLOCATION(d = (struct kn01_data *) malloc(sizeof(struct kn01_data))); memset(d, 0, sizeof(struct kn01_data)); d->color_fb = color_fb; d->csr = 0; d->csr |= (color_fb? 0 : KN01_CSR_MONO); memory_device_register(mem, "kn01", baseaddr, DEV_KN01_LENGTH, dev_kn01_access, d, DM_DEFAULT, NULL); } gxemul-0.6.1/src/devices/dev_iq80321_7seg.cc000644 001750 001750 00000006164 13402411502 020546 0ustar00debugdebug000000 000000 /* * Copyright (C) 2006-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: IQ80321 LED device * * Should work with NetBSD's iq80321_7seg.c. * * TODO: Graphical output of LED lines? */ #include #include #include #include "cpu.h" #include "device.h" #include "machine.h" #include "memory.h" #include "misc.h" struct iq80321_7seg_data { uint8_t msb, lsb; }; DEVICE_ACCESS(iq80321_7seg) { struct iq80321_7seg_data *d = (struct iq80321_7seg_data *) extra; uint64_t idata = 0, odata = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); switch (relative_addr) { case 0: if (writeflag == MEM_READ) odata = d->msb; else { d->msb = idata; debug("[ iq80321_7seg: setting MSB to 0x%02x ]\n", (int)idata); } break; case 0x10000: if (writeflag == MEM_READ) odata = d->lsb; else { d->lsb = idata; debug("[ iq80321_7seg: setting LSB to 0x%02x ]\n", (int)idata); } break; default:if (writeflag == MEM_READ) { fatal("[ iq80321_7seg: read from 0x%x ]\n", (int)relative_addr); } else { fatal("[ iq80321_7seg: write to 0x%x: 0x%llx ]\n", (int)relative_addr, (long long)idata); } exit(1); } if (writeflag == MEM_READ) memory_writemax64(cpu, data, len, odata); return 1; } DEVINIT(iq80321_7seg) { struct iq80321_7seg_data *d; CHECK_ALLOCATION(d = (struct iq80321_7seg_data *) malloc(sizeof(struct iq80321_7seg_data))); memset(d, 0, sizeof(struct iq80321_7seg_data)); /* 0xfe840000 and 0xfe850000 */ memory_device_register(devinit->machine->memory, devinit->name, devinit->addr, 0x10004, dev_iq80321_7seg_access, d, DM_DEFAULT, NULL); return 1; } gxemul-0.6.1/src/devices/fonts/vt220l.816000644 001750 001750 00000010000 13402411502 020047 0ustar00debugdebug000000 000000 ~~~~l|88||8<<<<~~<<<><~~<fffffffff{|`8ll8 |<~~<~<~~< 0``0(ll(88||||88<<<fff$lllllll||| 0`Ɔ8ll8vv000` 000000 0 0f<l8l||||`0||0xv`0v~ x|||~8ll8|0000`|0`܆ >0fΞ><<<6ll6l6lDDDDDDDDUUUUUUUUwwwwwwww66666666666666666666666666666666666666666666666666666666666666666666666666666667666666666666670??07666666666666666666666666667076666666666666666666666666666666666666666666??66666666666666666666666vvxlllllll`00`~pfffff|``v~ffff<~~~~`0``~```0|~0  0~ 0`0 ~p~vv8ll8 ll<lllllp0`|||||||gxemul-0.6.1/src/devices/fonts/vt220l.808000644 001750 001750 00000004000 13402411502 020053 0ustar00debugdebug000000 000000 ~~~~l|88||88|888||8<<><~~<ffffff{~ff?~~~~<~~<<~~< 0``0```~$ff$8||8<<llllllll0||00f8l8v{``0```00 0l88l000000` 0`||0p000x 8`x 8 xx00000x xlxpxl```bf8ll8ff|``xxff|lfxx x0000xxx0l88lx00x̘0dx`````x`0 xx8l00x |v``|ffxx |~xx8l```v| `lvff0p000x  x`flxlp00000xxxff|`v| v``||0|006v|8ll8l| 0d00000000v8llxx x~xx~<>f?x |~x |~00x |~xx 8~lxxxxxxxx~~| ~8ll8|00`x 3f7o3ff3f3f""""UUUUww66666666666666666666666666666666666676666670??0766666666667076666666666666666666??6666666666vvxlllll`0`~pffff|`v0xx08ll88lll0|x~~ ~~`<``<x0000`00`0`0p0000vv8ll8 l<xllllp0`x<<<<gxemul-0.6.1/src/devices/fonts/COPYRIGHT000644 001750 001750 00000004223 13402411502 020063 0ustar00debugdebug000000 000000 $Id: COPYRIGHT,v 1.4 2005-03-05 12:40:16 debug Exp $ The vt220l.816, vt220l.810, and vt220l.808 fonts were imported into GXemul from FreeBSD. Here's the COPYRIGHT message as found in FreeBSD (/usr/src/usr.sbin/pcvt/fonts/COPYRIGHT): ------------------------------------------------------------------------------- The font files: vt100pc.814.uu, vt100sg.814.uu, vt220h.808.uu, vt220h.810.uu, vt220h.814.uu, vt220h.816.uu, vt220l.808.uu, vt220l.810.uu, vt220l.814.uu and vt220l.816.uu in this directory are Copyright (c) 1992, 1993, 1994 Hellmuth Michaelis and Joerg Wunsch All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by Hellmuth Michaelis and Joerg Wunsch 4. The name authors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. gxemul-0.6.1/src/devices/fonts/Xconv_raw_to_c.c000644 001750 001750 00000004710 13402411502 021707 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Convert a raw binary file into an unsigned char array, usable from C. * Example: * * ./Xconv_raw_to_c somefile.raw hello * * gives the following output: * * unsigned char hello[] = { * 35,10,35,32,32,77,97,107,101,102, * 105,108,101,32,105,115,32,103,101,110, * 101,114,97,116,101,100,32,102,114,111, * 109,32,77,97,107,101,102,105,108,101, * 46,115,107,101,108,46,32,68,111,110, * ... * } * * This is useful to include things such as trampoline code, which needs * to be copied to some specific address at runtime, into a kernel image. */ #include #include int main(int argc, char *argv[]) { FILE *f; unsigned char buf[50000]; int len, i; if (argc < 3) { fprintf(stderr, "syntax: %s input_binary symbol_name\n", argv[0]); fprintf(stderr, "Output is written to stdout.\n"); exit(1); } f = fopen(argv[1], "r"); printf("unsigned char %s[] = {", argv[2]); len = fread(&buf, 1, sizeof(buf), f); for (i=0; i font8x8.cc font8x10.cc: Xconv_raw_to_c ./Xconv_raw_to_c vt220l.810 font8x10 > font8x10.cc font8x16.cc: Xconv_raw_to_c ./Xconv_raw_to_c vt220l.816 font8x16 > font8x16.cc clean: rm -f Xconv_raw_to_c font8x16.cc font8x8.cc font8x10.cc clean_all: clean rm -f Makefile gxemul-0.6.1/src/devices/fonts/vt220l.810000644 001750 001750 00000005000 13402411502 020045 0ustar00debugdebug000000 000000 ~~~~l||888||88||8||8|88||8|<<><~~<ffffffff{ff?x |vpx |v00x |v~~<l8l||||p||xvpv~8ll8|~~8ld```x0000<px |v8p0000x||vp~8lll8|000`|>{ 3g<<<3ff3f3f"""""UUUUUwww666666666666666666666666666666666666666666666667666666670??07666666666666667076666666666666666666666666??6666666666666vv|fd`````lllllll`00`xfffvl`v<~~<8ll88llll20|xvn|>`0`|`0|0000`0 0` 0`0 p0000vv8lll8 ll4<xlllllpp<<<<gxemul-0.6.1/src/file/file.cc000644 001750 001750 00000025765 13402411502 016200 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * This module contains functions which load executable images into (emulated) * memory. File formats recognized so far are: * * a.out traditional old-style Unix binary format * Mach-O MacOS X format, etc. * ecoff old format used by Ultrix, Windows NT, etc * srec Motorola SREC format * raw raw binaries, "address:[skiplen:[entrypoint:]]filename" * ELF 32-bit and 64-bit ELFs * * If a file is not of one of the above mentioned formats, it is assumed * to be symbol data generated by 'nm' or 'nm -S'. */ #include #include #include #include #include "cpu.h" #include "machine.h" #include "memory.h" #include "misc.h" #include "symbol.h" extern int quiet_mode; extern int verbose; /* * This should be increased by every routine here that actually loads an * executable file into memory. (For example, loading a symbol file should * NOT increase this.) */ static int n_executables_loaded = 0; #include "thirdparty/exec_elf.h" /* Ugly; needed for ELFDATA2LSB etc. */ #define unencode(var,dataptr,typ) { \ int Wi; unsigned char Wb; \ unsigned char *Wp = (unsigned char *) dataptr; \ int Wlen = sizeof(typ); \ var = 0; \ for (Wi=0; Wi= 2? ":" : ""); debug_indentation(iadd); old_quiet_mode = quiet_mode; if (verbose < 2) quiet_mode = 1; f = fopen(filename, "r"); if (f == NULL) { file_load_raw(machine, mem, filename, entrypointp); goto ret; } fseek(f, 0, SEEK_END); size = ftello(f); fseek(f, 0, SEEK_SET); memset(buf, 0, sizeof(buf)); len = fread(buf, 1, sizeof(buf), f); fseek(f, 510, SEEK_SET); len2 = fread(buf2, 1, sizeof(buf2), f); fclose(f); if (len < (signed int)sizeof(buf)) { fprintf(stderr, "\nThis file is too small to contain " "anything useful\n"); exit(1); } /* Is it an ELF? */ if (buf[0] == 0x7f && buf[1]=='E' && buf[2]=='L' && buf[3]=='F') { file_load_elf(machine, mem, filename, entrypointp, arch, gpp, byte_orderp, tocp); goto ret; } /* Is it an a.out? */ if (buf[0]==0x00 && buf[1]==0x8b && buf[2]==0x01 && buf[3]==0x07) { /* MIPS a.out */ file_load_aout(machine, mem, filename, 0, entrypointp, arch, byte_orderp); goto ret; } if (buf[0]==0x00 && buf[1]==0x87 && buf[2]==0x01 && buf[3]==0x08) { /* M68K a.out */ file_load_aout(machine, mem, filename, AOUT_FLAG_VADDR_ZERO_HACK /* for OpenBSD/mac68k */, entrypointp, arch, byte_orderp); goto ret; } if (buf[0]==0x00 && buf[1]==0x99 && buf[2]==0x01 && buf[3]==0x0b) { /* OpenBSD/M88K a.out */ file_load_aout(machine, mem, filename, AOUT_FLAG_FROM_BEGINNING, entrypointp, arch, byte_orderp); goto ret; } if (buf[0]==0x00 && buf[1]==0x8f && buf[2]==0x01 && buf[3]==0x0b) { /* ARM a.out */ file_load_aout(machine, mem, filename, AOUT_FLAG_FROM_BEGINNING, entrypointp, arch, byte_orderp); goto ret; } if (buf[0]==0x00 && buf[1]==0x86 && buf[2]==0x01 && buf[3]==0x0b) { /* i386 a.out (old OpenBSD and NetBSD etc) */ file_load_aout(machine, mem, filename, AOUT_FLAG_FROM_BEGINNING, entrypointp, arch, byte_orderp); goto ret; } if (buf[0]==0x01 && buf[1]==0x03 && buf[2]==0x01 && buf[3]==0x07) { /* SPARC a.out (old 32-bit NetBSD etc) */ file_load_aout(machine, mem, filename, AOUT_FLAG_NO_SIZES, entrypointp, arch, byte_orderp); goto ret; } if (buf[0]==0x00 && buf[2]==0x00 && buf[8]==0x7a && buf[9]==0x75) { /* DEC OSF1 on MIPS: */ file_load_aout(machine, mem, filename, AOUT_FLAG_DECOSF1, entrypointp, arch, byte_orderp); goto ret; } /* * Is it a Mach-O file? */ if (buf[0] == 0xfe && buf[1] == 0xed && buf[2] == 0xfa && (buf[3] == 0xce || buf[3] == 0xcf)) { file_load_macho(machine, mem, filename, entrypointp, arch, byte_orderp, buf[3] == 0xcf, 0); goto ret; } if ((buf[0] == 0xce || buf[0] == 0xcf) && buf[1] == 0xfa && buf[2] == 0xed && buf[3] == 0xfe) { file_load_macho(machine, mem, filename, entrypointp, arch, byte_orderp, buf[0] == 0xcf, 1); goto ret; } /* * Is it an ecoff? * * TODO: What's the deal with the magic value's byte order? Sometimes * it seems to be reversed for BE when compared to LE, but not always? */ if (buf[0]+256*buf[1] == ECOFF_MAGIC_MIPSEB || buf[0]+256*buf[1] == ECOFF_MAGIC_MIPSEL || buf[0]+256*buf[1] == ECOFF_MAGIC_MIPSEB2 || buf[0]+256*buf[1] == ECOFF_MAGIC_MIPSEL2 || buf[0]+256*buf[1] == ECOFF_MAGIC_MIPSEB3 || buf[0]+256*buf[1] == ECOFF_MAGIC_MIPSEL3 || buf[1]+256*buf[0] == ECOFF_MAGIC_MIPSEB || buf[1]+256*buf[0] == ECOFF_MAGIC_MIPSEL || buf[1]+256*buf[0] == ECOFF_MAGIC_MIPSEB2 || buf[1]+256*buf[0] == ECOFF_MAGIC_MIPSEL2 || buf[1]+256*buf[0] == ECOFF_MAGIC_MIPSEB3 || buf[1]+256*buf[0] == ECOFF_MAGIC_MIPSEL3) { file_load_ecoff(machine, mem, filename, entrypointp, arch, gpp, byte_orderp); goto ret; } /* Is it a Motorola SREC file? */ if ((buf[0]=='S' && buf[1]>='0' && buf[1]<='9')) { file_load_srec(machine, mem, filename, entrypointp); goto ret; } /* gzipped files are not supported: */ if (buf[0]==0x1f && buf[1]==0x8b) { fprintf(stderr, "\nYou need to gunzip the file before you" " try to use it.\n"); exit(1); } if (size > 24000000) { fprintf(stderr, "\nThis file is very large (%lli bytes)\n", (long long)size); fprintf(stderr, "Are you sure it is a kernel and not a disk " "image? (Use the -d option.)\n"); exit(1); } if (size == 1474560) fprintf(stderr, "Hm... this file is the size of a 1.44 MB " "floppy image. Maybe you forgot the\n-d switch?\n"); /* * Ugly hack for Dreamcast: When booting from a Dreamcast CDROM * image, a temporary file is extracted into /tmp/gxemul.*, but this * is a "scrambled" raw binary. This code unscrambles it, and loads * it as a raw binary. */ snprintf(tmpname, sizeof(tmpname), "%s/gxemul.", tmpdir); if (machine->machine_type == MACHINE_DREAMCAST && strncmp(filename, tmpname, strlen(tmpname)) == 0) { char *tmp_filename = (char *) malloc(strlen(filename) + 100); snprintf(tmp_filename, strlen(filename) + 100, "%s.descrambled", filename); debug("descrambling into %s\n", tmp_filename); dreamcast_descramble(filename, tmp_filename); snprintf(tmp_filename, strlen(filename) + 100, "0x8c010000:%s.descrambled", filename); debug("loading descrambled Dreamcast binary\n"); file_load_raw(machine, mem, tmp_filename, entrypointp); snprintf(tmp_filename, strlen(filename) + 100, "%s.descrambled", filename); remove(tmp_filename); free(tmp_filename); /* Hack: Start a "boot from CDROM" sequence: */ *entrypointp = 0x8c000140; goto ret; } /* * Last resort: symbol definitions from nm (or nm -S): * * If the buf contains typical 'binary' characters, then print * an error message and quit instead of assuming that it is a * symbol file. */ for (i=0; i<(signed)sizeof(buf); i++) if (buf[i] < 32 && buf[i] != '\t' && buf[i] != '\n' && buf[i] != '\r' && buf[i] != '\f') { fprintf(stderr, "\nThe file format of '%s' is " "unknown.\n\n ", filename); for (i=0; i<(signed)sizeof(buf); i++) fprintf(stderr, " %02x", buf[i]); if (len2 == 2 && buf2[0] == 0x55 && buf2[1] == 0xaa) fprintf(stderr, "\n\nIt has a PC-style " "bootsector marker."); fprintf(stderr, "\n\nPossible explanations:\n\n" " o) If this is a disk image, you forgot '-d' " "on the command line.\n" " o) You are attempting to load a raw binary " "into emulated memory,\n" " but forgot to add the address prefix.\n" " o) This is an unsupported binary format.\n\n"); exit(1); } symbol_readfile(&machine->symbol_context, filename); ret: debug_indentation(-iadd); quiet_mode = old_quiet_mode; } gxemul-0.6.1/src/file/file_elf.cc000644 001750 001750 00000051524 13402411502 017016 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2014 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: ELF file support */ /* Note: Included from file.c. */ #include "thirdparty/exec_elf.h" /* ELF machine types as strings: (same as exec_elf.h) */ #define N_ELF_MACHINE_TYPES 89 static const char *elf_machine_type[N_ELF_MACHINE_TYPES] = { "NONE", "M32", "SPARC", "386", /* 0..3 */ "68K", "88K", "486", "860", /* 4..7 */ "MIPS", "S370", "MIPS_RS3_LE", "RS6000", /* 8..11 */ "unknown12", "unknown13", "unknown14", "PARISC", /* 12..15 */ "NCUBE", "VPP500", "SPARC32PLUS", "960", /* 16..19 */ "PPC", "PPC64", "unknown22", "unknown23", /* 20..23 */ "unknown24", "unknown25", "unknown26", "unknown27", /* 24..27 */ "unknown28", "unknown29", "unknown30", "unknown31", /* 28..31 */ "unknown32", "unknown33", "unknown34", "unknown35", /* 32..35 */ "V800", "FR20", "RH32", "RCE", /* 36..39 */ "ARM", "ALPHA", "SH", "SPARCV9", /* 40..43 */ "TRICORE", "ARC", "H8_300", "H8_300H", /* 44..47 */ "H8S", "H8_500", "IA_64", "MIPS_X", /* 48..51 */ "COLDFIRE", "68HC12", "unknown54", "unknown55", /* 52..55 */ "unknown56", "unknown57", "unknown58", "unknown59", /* 56..59 */ "unknown60", "unknown61", "AMD64", "unknown63", /* 60..63 */ "unknown64", "unknown65", "unknown66", "unknown67", /* 64..67 */ "unknown68", "unknown69", "unknown70", "unknown71", /* 68..71 */ "unknown72", "unknown73", "unknown74", "unknown75", /* 72..75 */ "unknown76", "unknown77", "unknown78", "unknown79", /* 76..79 */ "unknown80", "unknown81", "unknown82", "AVR", /* 80..83 */ "unknown84", "unknown85", "unknown86", "unknown87", /* 84..87 */ "M32R" /* 88 */ }; /* * file_load_elf(): * * Loads an ELF image into the emulated memory. The entry point (read from * the ELF header) and the initial value of the gp register (read from the * ELF symbol table) are stored in the specified CPU's registers. * * This is pretty heavy stuff, but is needed because of the heaviness of * ELF files. :-/ Hopefully it will be able to recognize most valid ELFs. */ static void file_load_elf(struct machine *m, struct memory *mem, char *filename, uint64_t *entrypointp, int arch, uint64_t *gpp, int *byte_order, uint64_t *tocp) { Elf32_Ehdr hdr32; Elf64_Ehdr hdr64; FILE *f; uint64_t eentry; int len, i, ok; int elf64, encoding, eflags; int etype, emachine; int ephnum, ephentsize, eshnum, eshentsize; off_t ephoff, eshoff; Elf32_Phdr phdr32; Elf64_Phdr phdr64; Elf32_Shdr shdr32; Elf64_Shdr shdr64; Elf32_Sym sym32; Elf64_Sym sym64; int ofs; int chunk_len = 1024, align_len; char *symbol_strings = NULL; size_t symbol_length = 0; const char *s; int n_symbols = 0; Elf32_Sym *symbols_sym32 = NULL; Elf64_Sym *symbols_sym64 = NULL; f = fopen(filename, "r"); if (f == NULL) { perror(filename); exit(1); } len = fread(&hdr32, 1, sizeof(Elf32_Ehdr), f); if (len < (signed int)sizeof(Elf32_Ehdr)) { fprintf(stderr, "%s: not an ELF file image\n", filename); exit(1); } if (memcmp(&hdr32.e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0) { fprintf(stderr, "%s: not an ELF file image\n", filename); exit(1); } switch (hdr32.e_ident[EI_CLASS]) { case ELFCLASS32: elf64 = 0; break; case ELFCLASS64: elf64 = 1; fseek(f, 0, SEEK_SET); len = fread(&hdr64, 1, sizeof(Elf64_Ehdr), f); if (len < (signed int)sizeof(Elf64_Ehdr)) { fprintf(stderr, "%s: not an ELF64 file image\n", filename); exit(1); } break; default: fprintf(stderr, "%s: unknown ELF class '%i'\n", filename, hdr32.e_ident[EI_CLASS]); exit(1); } encoding = hdr32.e_ident[EI_DATA]; if (encoding != ELFDATA2LSB && encoding != ELFDATA2MSB) { fprintf(stderr, "%s: unknown data encoding '%i'\n", filename, hdr32.e_ident[EI_DATA]); exit(1); } if (elf64) { unencode(etype, &hdr64.e_type, Elf64_Quarter); unencode(eflags, &hdr64.e_flags, Elf64_Half); unencode(emachine, &hdr64.e_machine, Elf64_Quarter); unencode(eentry, &hdr64.e_entry, Elf64_Addr); unencode(ephnum, &hdr64.e_phnum, Elf64_Quarter); unencode(ephentsize, &hdr64.e_phentsize, Elf64_Quarter); unencode(ephoff, &hdr64.e_phoff, Elf64_Off); unencode(eshnum, &hdr64.e_shnum, Elf64_Quarter); unencode(eshentsize, &hdr64.e_shentsize, Elf64_Quarter); unencode(eshoff, &hdr64.e_shoff, Elf64_Off); if (ephentsize != sizeof(Elf64_Phdr)) { fprintf(stderr, "%s: incorrect phentsize? %i, should " "be %i\nPerhaps this is a dynamically linked " "binary (which isn't supported yet).\n", filename, (int)ephentsize, (int)sizeof(Elf64_Phdr)); exit(1); } if (eshentsize != sizeof(Elf64_Shdr)) { fprintf(stderr, "%s: incorrect shentsize? %i, should " "be %i\nPerhaps this is a dynamically linked " "binary (which isn't supported yet).\n", filename, (int)eshentsize, (int)sizeof(Elf64_Shdr)); exit(1); } } else { unencode(etype, &hdr32.e_type, Elf32_Half); unencode(eflags, &hdr32.e_flags, Elf32_Word); unencode(emachine, &hdr32.e_machine, Elf32_Half); unencode(eentry, &hdr32.e_entry, Elf32_Addr); unencode(ephnum, &hdr32.e_phnum, Elf32_Half); unencode(ephentsize, &hdr32.e_phentsize, Elf32_Half); unencode(ephoff, &hdr32.e_phoff, Elf32_Off); unencode(eshnum, &hdr32.e_shnum, Elf32_Half); unencode(eshentsize, &hdr32.e_shentsize, Elf32_Half); unencode(eshoff, &hdr32.e_shoff, Elf32_Off); if (ephentsize != sizeof(Elf32_Phdr)) { fprintf(stderr, "%s: incorrect phentsize? %i, should " "be %i\nPerhaps this is a dynamically linked " "binary (which isn't supported yet).\n", filename, (int)ephentsize, (int)sizeof(Elf32_Phdr)); exit(1); } if (eshentsize != sizeof(Elf32_Shdr)) { fprintf(stderr, "%s: incorrect shentsize? %i, should " "be %i\nPerhaps this is a dynamically linked " "binary (which isn't supported yet).\n", filename, (int)eshentsize, (int)sizeof(Elf32_Shdr)); exit(1); } } if ( etype != ET_EXEC ) { fprintf(stderr, "%s is not an ELF Executable file, type = %i\n", filename, etype); exit(1); } ok = 0; switch (arch) { case ARCH_M88K: switch (emachine) { case EM_88K: ok = 1; } break; case ARCH_ALPHA: switch (emachine) { case EM_ALPHA: case -28634: ok = 1; } break; case ARCH_ARM: switch (emachine) { case EM_ARM: ok = 1; } break; /* case ARCH_AVR: switch (emachine) { case EM_AVR: ok = 1; } break; case ARCH_AVR32: switch (emachine) { case 6317: ok = 1; } break; case ARCH_HPPA: switch (emachine) { case EM_PARISC: ok = 1; } break; case ARCH_I960: switch (emachine) { case EM_960: ok = 1; } break; case ARCH_IA64: switch (emachine) { case EM_IA_64: ok = 1; } break; case ARCH_M68K: switch (emachine) { case EM_68K: ok = 1; } break; case ARCH_M32R: switch (emachine) { case EM_M32R: ok = 1; } break;*/ case ARCH_MIPS: switch (emachine) { case EM_MIPS: case EM_MIPS_RS3_LE: ok = 1; } break; case ARCH_PPC: switch (emachine) { case EM_PPC: case EM_PPC64: ok = 1; } break; case ARCH_SH: switch (emachine) { case EM_SH: ok = 1; } break; /*case ARCH_SPARC: switch (emachine) { case EM_SPARC: case EM_SPARCV9: ok = 1; } break; case ARCH_X86: switch (emachine) { case EM_386: case EM_486: *tocp = 1; ok = 1; break; case EM_AMD64: *tocp = 2; ok = 1; break; } break; */ default: fatal("file.c: INTERNAL ERROR: Unimplemented arch!\n"); } if (!ok) { fprintf(stderr, "%s: this is a ", filename); if (emachine >= 0 && emachine < N_ELF_MACHINE_TYPES) fprintf(stderr, "%s", elf_machine_type[emachine]); else fprintf(stderr, "machine type '%i'", emachine); fprintf(stderr, " ELF binary!\n"); exit(1); } s = "entry point"; if (elf64 && arch == ARCH_PPC) s = "function descriptor at"; debug("ELF%i %s, %s 0x", elf64? 64 : 32, encoding == ELFDATA2LSB? "LSB (LE)" : "MSB (BE)", s); if (elf64) debug("%016" PRIx64"\n", (uint64_t) eentry); else debug("%08" PRIx32"\n", (uint32_t) eentry); /* * SH64: 32-bit instruction encoding? */ if (arch == ARCH_SH && (eentry & 1)) { fatal("SH64: 32-bit instruction encoding: TODO\n"); /* m->cpus[0]->cd.sh.compact = 0; */ m->cpus[0]->cd.sh.cpu_type.bits = 64; exit(1); } /* Read the program headers: */ for (i=0; i> 60) != 0) || (!elf64 && (p_vaddr >> 28) != 0) ) m->cpus[m->bootstrap_cpu]-> cd.ppc.msr |= PPC_MSR_IR | PPC_MSR_DR; } if (p_memsz != 0 && (p_type == PT_LOAD || (p_type & PF_MASKPROC) == PT_MIPS_REGINFO)) { debug("chunk %i (", i); if (p_type == PT_LOAD) debug("load"); else debug("0x%08" PRIx32, (uint32_t) p_type); debug(") @ 0x%" PRIx64", vaddr 0x", (uint64_t) p_offset); if (elf64) debug("%016" PRIx64, (uint64_t) p_vaddr); else debug("%08" PRIx32, (uint32_t) p_vaddr); debug(" len=0x%" PRIx64"\n", (uint64_t) p_memsz); if (p_vaddr != p_paddr) { if (elf64) debug("NOTE: vaddr (0x%" PRIx64") and " "paddr (0x%" PRIx64") differ; using " "vaddr\n", (uint64_t) p_vaddr, (uint64_t) p_paddr); else debug("NOTE: vaddr (0x%08" PRIx32") and " "paddr (0x%08" PRIx32") differ; usin" "g vaddr\n", (uint32_t) p_vaddr, (uint32_t)p_paddr); } if (p_memsz < p_filesz) { fprintf(stderr, "%s: memsz < filesz. TODO: how" " to handle this? memsz=%016" PRIx64 " filesz=%016" PRIx64"\n", filename, (uint64_t) p_memsz, (uint64_t) p_filesz); exit(1); } fseek(f, p_offset, SEEK_SET); align_len = 1; if ((p_vaddr & 0xf)==0) align_len = 0x10; if ((p_vaddr & 0x3f)==0) align_len = 0x40; if ((p_vaddr & 0xff)==0) align_len = 0x100; if ((p_vaddr & 0xfff)==0) align_len = 0x1000; if ((p_vaddr & 0x3fff)==0) align_len = 0x4000; if ((p_vaddr & 0xffff)==0) align_len = 0x10000; ofs = 0; len = chunk_len = align_len; while (ofs < (int64_t)p_filesz && len==chunk_len) { unsigned char *ch; CHECK_ALLOCATION(ch = (unsigned char *) malloc(chunk_len)); /* Switch to larger size, if possible: */ if (align_len < 0x10000 && ((p_vaddr + ofs) & 0xffff)==0) { align_len = 0x10000; len = chunk_len = align_len; free(ch); CHECK_ALLOCATION(ch=(unsigned char *)malloc(chunk_len)); } else if (align_len < 0x1000 && ((p_vaddr + ofs) & 0xfff)==0) { align_len = 0x1000; len = chunk_len = align_len; free(ch); CHECK_ALLOCATION(ch=(unsigned char *)malloc(chunk_len)); } len = fread(&ch[0], 1, chunk_len, f); if (ofs + len > (int64_t)p_filesz) len = p_filesz - ofs; int j = 0; while (j < len) { size_t len_to_copy; len_to_copy = (j + align_len) <= len? align_len : len - j; m->cpus[0]->memory_rw(m->cpus[0], mem, p_vaddr + ofs, &ch[j], len_to_copy, MEM_WRITE, NO_EXCEPTIONS); ofs += align_len; j += align_len; } free(ch); } } } /* * Read the section headers to find the address of the _gp * symbol (for MIPS): */ for (i=0; i symbol_length) { if (symbol_strings != NULL) free(symbol_strings); CHECK_ALLOCATION(symbol_strings = (char *) malloc(sh_size + 1)); fseek(f, sh_offset, SEEK_SET); size_t len2 = fread(symbol_strings, 1, sh_size, f); if (len2 != sh_size) { fprintf(stderr, "could not read symbols from " "%s\n", filename); exit(1); } debug("%i bytes of symbol strings at 0x%" PRIx64"\n", (int) sh_size, (uint64_t) sh_offset); symbol_strings[sh_size] = '\0'; symbol_length = sh_size; } } fclose(f); /* Decode symbols: */ if (symbol_strings != NULL) { for (i=0; i> 4) & 0xf) >= STB_GLOBAL) */ { /* debug("symbol info=0x%02x addr=0x%016" PRIx64 " '%s'\n", st_info, (uint64_t) addr, symbol_strings + st_name); */ add_symbol_name(&m->symbol_context, addr, size, symbol_strings + st_name, 0, -1); } if (strcmp(symbol_strings + st_name, "_gp") == 0) { debug("found _gp address: 0x"); if (elf64) debug("%016" PRIx64"\n", (uint64_t)addr); else debug("%08" PRIx32"\n", (uint32_t)addr); *gpp = addr; } } } *entrypointp = eentry; if (encoding == ELFDATA2LSB) *byte_order = EMUL_LITTLE_ENDIAN; else *byte_order = EMUL_BIG_ENDIAN; if (elf64 && arch == ARCH_PPC) { /* * Special case for 64-bit PPC ELFs: * * The ELF starting symbol points to a ".opd" section * which contains a function descriptor: * * uint64_t start; * uint64_t toc_base; * uint64_t something_else; (?) */ int res; unsigned char b[sizeof(uint64_t)]; uint64_t toc_base; debug("PPC64: "); res = m->cpus[0]->memory_rw(m->cpus[0], mem, eentry, b, sizeof(b), MEM_READ, NO_EXCEPTIONS); if (!res) debug(" [WARNING: could not read memory?] "); /* PPC are always big-endian: */ *entrypointp = ((uint64_t)b[0] << 56) + ((uint64_t)b[1] << 48) + ((uint64_t)b[2] << 40) + ((uint64_t)b[3] << 32) + ((uint64_t)b[4] << 24) + ((uint64_t)b[5] << 16) + ((uint64_t)b[6] << 8) + (uint64_t)b[7]; res = m->cpus[0]->memory_rw(m->cpus[0], mem, eentry + 8, b, sizeof(b), MEM_READ, NO_EXCEPTIONS); if (!res) fatal(" [WARNING: could not read memory?] "); toc_base = ((uint64_t)b[0] << 56) + ((uint64_t)b[1] << 48) + ((uint64_t)b[2] << 40) + ((uint64_t)b[3] << 32) + ((uint64_t)b[4] << 24) + ((uint64_t)b[5] << 16) + ((uint64_t)b[6] << 8) + (uint64_t)b[7]; debug("entrypoint 0x%016" PRIx64", toc_base 0x%016" PRIx64"\n", (uint64_t) *entrypointp, (uint64_t) toc_base); if (tocp != NULL) *tocp = toc_base; } n_executables_loaded ++; } gxemul-0.6.1/src/file/file_ecoff.cc000644 001750 001750 00000033025 13402411502 017326 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: ECOFF file support */ /* Note: Included from file.c. */ #include "thirdparty/exec_ecoff.h" /* Special symbol format used by Microsoft-ish COFF files: */ struct ms_sym { unsigned char name[8]; unsigned char value[4]; unsigned char section[2]; unsigned char type[2]; unsigned char storage_class; unsigned char n_aux_syms; }; /* * file_load_ecoff(): * * Loads an ecoff binary image into the emulated memory. The entry point * (read from the ecoff header) is stored in the specified CPU's registers. */ static void file_load_ecoff(struct machine *m, struct memory *mem, char *filename, uint64_t *entrypointp, int arch, uint64_t *gpp, int *byte_orderp) { struct ecoff_exechdr exechdr; int f_magic, f_nscns, f_nsyms; int a_magic; off_t f_symptr, a_tsize, a_dsize, a_bsize; uint64_t a_entry, a_tstart, a_dstart, a_bstart, a_gp, end_addr=0; const char *format_name; struct ecoff_scnhdr scnhdr; FILE *f; int len, secn, total_len, chunk_size; int encoding = ELFDATA2LSB; /* Assume little-endian. See below */ int program_byte_order = -1; unsigned char buf[8192]; f = fopen(filename, "r"); if (f == NULL) { perror(filename); exit(1); } len = fread(&exechdr, 1, sizeof(exechdr), f); if (len != sizeof(exechdr)) { fprintf(stderr, " not a complete ecoff image\n"); exit(1); } /* * The following code looks a bit ugly, but it should work. The ECOFF * 16-bit magic value seems to be stored in MSB byte order for * big-endian binaries, and LSB byte order for little-endian binaries. * * The unencode() assumes little-endianness by default. */ unencode(f_magic, &exechdr.f.f_magic, uint16_t); switch (f_magic) { case ((ECOFF_MAGIC_MIPSEB & 0xff) << 8) + ((ECOFF_MAGIC_MIPSEB >> 8) & 0xff): format_name = "MIPS1 BE"; encoding = ELFDATA2MSB; break; case ECOFF_MAGIC_MIPSEB: /* NOTE: Big-endian header, little-endian code! */ format_name = "MIPS1 BE-LE"; encoding = ELFDATA2MSB; program_byte_order = ELFDATA2LSB; break; case ECOFF_MAGIC_MIPSEL: format_name = "MIPS1 LE"; encoding = ELFDATA2LSB; break; case ((ECOFF_MAGIC_MIPSEB2 & 0xff) << 8) + ((ECOFF_MAGIC_MIPSEB2 >> 8) & 0xff): format_name = "MIPS2 BE"; encoding = ELFDATA2MSB; break; case ECOFF_MAGIC_MIPSEL2: format_name = "MIPS2 LE"; encoding = ELFDATA2LSB; break; case ((ECOFF_MAGIC_MIPSEB3 & 0xff) << 8) + ((ECOFF_MAGIC_MIPSEB3 >> 8) & 0xff): format_name = "MIPS3 BE"; encoding = ELFDATA2MSB; break; case ECOFF_MAGIC_MIPSEL3: format_name = "MIPS3 LE"; encoding = ELFDATA2LSB; break; default: fprintf(stderr, "%s: unimplemented ECOFF format, magic = " "0x%04x\n", filename, (int)f_magic); exit(1); } /* Read various header information: */ unencode(f_nscns, &exechdr.f.f_nscns, uint16_t); unencode(f_symptr, &exechdr.f.f_symptr, uint32_t); unencode(f_nsyms, &exechdr.f.f_nsyms, uint32_t); debug("ECOFF, %s, %i sections, %i symbols @ 0x%lx\n", format_name, f_nscns, f_nsyms, (long)f_symptr); unencode(a_magic, &exechdr.a.magic, uint16_t); unencode(a_tsize, &exechdr.a.tsize, uint32_t); unencode(a_dsize, &exechdr.a.dsize, uint32_t); unencode(a_bsize, &exechdr.a.bsize, uint32_t); debug("magic 0x%04x, tsize 0x%x, dsize 0x%x, bsize 0x%x\n", a_magic, (int)a_tsize, (int)a_dsize, (int)a_bsize); unencode(a_tstart, &exechdr.a.text_start, uint32_t); unencode(a_dstart, &exechdr.a.data_start, uint32_t); unencode(a_bstart, &exechdr.a.bss_start, uint32_t); debug("text @ 0x%08x, data @ 0x%08x, bss @ 0x%08x\n", (int)a_tstart, (int)a_dstart, (int)a_bstart); unencode(a_entry, &exechdr.a.entry, uint32_t); unencode(a_gp, &exechdr.a.gp_value, uint32_t); debug("entrypoint 0x%08x, gp = 0x%08x\n", (int)a_entry, (int)a_gp); /* * Special hack for a MACH/pmax kernel, I don't know how applicable * this is for other files: * there are no sections (!), and a_magic = 0x0108 instead of * 0x0107 as it is on most other (E)COFF files I've seen. * * Then load everything after the header to the text start address. */ if (f_nscns == 0 && a_magic == 0x108) { uint64_t where = a_tstart; total_len = 0; fseek(f, 0x50, SEEK_SET); while (!feof(f)) { chunk_size = 256; len = fread(buf, 1, chunk_size, f); if (len > 0) m->cpus[0]->memory_rw(m->cpus[0], mem, where, &buf[0], len, MEM_WRITE, NO_EXCEPTIONS); where += len; total_len += len; } debug("MACH/pmax hack (!), read 0x%x bytes\n", total_len); } /* Go through all the section headers: */ for (secn=0; secn= 32 && scnhdr.s_name[i] < 127) debug("%c", scnhdr.s_name[i]); else break; debug(" ("); unencode(s_paddr, &scnhdr.s_paddr, uint32_t); unencode(s_vaddr, &scnhdr.s_vaddr, uint32_t); unencode(s_size, &scnhdr.s_size, uint32_t); unencode(s_scnptr, &scnhdr.s_scnptr, uint32_t); unencode(s_relptr, &scnhdr.s_relptr, uint32_t); unencode(s_lnnoptr, &scnhdr.s_lnnoptr, uint32_t); unencode(s_nreloc, &scnhdr.s_nreloc, uint16_t); unencode(s_nlnno, &scnhdr.s_nlnno, uint16_t); unencode(s_flags, &scnhdr.s_flags, uint32_t); debug("0x%x @ 0x%08x, offset 0x%lx, flags 0x%x)\n", (int)s_size, (int)s_vaddr, (long)s_scnptr, (int)s_flags); end_addr = s_vaddr + s_size; if (s_relptr != 0) { /* * TODO: Read this url, or similar: * http://www.iecc.com/linker/linker07.html */ fprintf(stderr, "%s: relocatable code/data in " "section nr %i: not yet implemented\n", filename, secn); exit(1); } /* Loadable? Then load the section: */ if (s_scnptr != 0 && s_size != 0 && s_vaddr != 0 && !(s_flags & 0x02)) { /* Remember the current file offset: */ oldpos = ftello(f); /* Load the section into emulated memory: */ fseek(f, s_scnptr, SEEK_SET); total_len = 0; chunk_size = 1; if ((s_vaddr & 0xf) == 0) chunk_size = 0x10; if ((s_vaddr & 0xff) == 0) chunk_size = 0x100; if ((s_vaddr & 0xfff) == 0) chunk_size = 0x1000; while (total_len < s_size) { len = chunk_size; if (total_len + len > s_size) len = s_size - total_len; len = fread(buf, 1, chunk_size, f); if (len == 0) { debug("!!! total_len = %i, " "chunk_size = %i, len = %i\n", total_len, chunk_size, len); break; } m->cpus[0]->memory_rw(m->cpus[0], mem, s_vaddr, &buf[0], len, MEM_WRITE, NO_EXCEPTIONS); s_vaddr += len; total_len += len; } /* Return to position inside the section headers: */ fseek(f, oldpos, SEEK_SET); } } if (f_symptr != 0 && f_nsyms != 0) { struct ecoff_symhdr symhdr; int sym_magic, iextMax, issExtMax, issMax, crfd; off_t cbRfdOffset, cbExtOffset, cbSsExtOffset, cbSsOffset; char *symbol_data; struct ecoff_extsym *extsyms; int nsymbols, sym_nr; fseek(f, f_symptr, SEEK_SET); len = fread(&symhdr, 1, sizeof(symhdr), f); if (len != sizeof(symhdr)) { fprintf(stderr, "%s: not a complete " "ecoff image: symhdr broken\n", filename); exit(1); } unencode(sym_magic, &symhdr.magic, uint16_t); unencode(crfd, &symhdr.crfd, uint32_t); unencode(cbRfdOffset, &symhdr.cbRfdOffset, uint32_t); unencode(issMax, &symhdr.issMax, uint32_t); unencode(cbSsOffset, &symhdr.cbSsOffset, uint32_t); unencode(issExtMax, &symhdr.issExtMax, uint32_t); unencode(cbSsExtOffset, &symhdr.cbSsExtOffset, uint32_t); unencode(iextMax, &symhdr.iextMax, uint32_t); unencode(cbExtOffset, &symhdr.cbExtOffset, uint32_t); if (sym_magic != MIPS_MAGIC_SYM) { unsigned char *ms_sym_buf; struct ms_sym *sym; int n_real_symbols = 0; debug("bad symbol magic, assuming Microsoft format: "); /* * See http://www.lisoleg.net/lisoleg/elfandlib/ * Microsoft%20Portable%20Executable%20COFF%20For * mat%20Specification.txt * for more details. */ CHECK_ALLOCATION(ms_sym_buf = (unsigned char *) malloc(sizeof(struct ms_sym) * f_nsyms)); fseek(f, f_symptr, SEEK_SET); len = fread(ms_sym_buf, 1, sizeof(struct ms_sym) * f_nsyms, f); sym = (struct ms_sym *) ms_sym_buf; for (sym_nr=0; sym_nrname[i]; i++) debug("%c", sym->name[i]); */ v = sym->value[0] + (sym->value[1] << 8) + (sym->value[2] << 16) + ((uint64_t)sym->value[3] << 24); altname = sym->name[4] + (sym->name[5] << 8) + (sym->name[6] << 16) + ((uint64_t)sym->name[3] << 24); t = (sym->type[1] << 8) + sym->type[0]; /* TODO: big endian COFF? */ /* debug("' value=0x%x type=0x%04x", v, t); */ if (t == 0x20 && sym->name[0]) { memcpy(name, sym->name, 8); name[8] = '\0'; add_symbol_name(&m->symbol_context, v, 0, name, 0, -1); n_real_symbols ++; } else if (t == 0x20 && !sym->name[0]) { off_t ofs; ofs = f_symptr + altname + sizeof(struct ms_sym) * f_nsyms; fseek(f, ofs, SEEK_SET); if (fread(name, 1, sizeof(name), f) != sizeof(name)) { fprintf(stderr, "error reading symbol from %s\n", filename); exit(1); } name[sizeof(name)-1] = '\0'; /* debug(" [altname=0x%x '%s']", altname, name); */ add_symbol_name(&m->symbol_context, v, 0, name, 0, -1); n_real_symbols ++; } if (sym->n_aux_syms) { int n = sym->n_aux_syms; /* debug(" aux='"); */ while (n-- > 0) { sym ++; sym_nr ++; /* for (i=0; i<8 && sym->name[i]; i++) debug("%c", sym->name[i]); */ } /* debug("'"); */ } /* debug("\n"); */ sym ++; } debug("%i symbols\n", n_real_symbols); free(ms_sym_buf); goto skip_normal_coff_symbols; } debug("symbol header: magic = 0x%x\n", sym_magic); debug("%i symbols @ 0x%08x (strings @ 0x%08x)\n", iextMax, cbExtOffset, cbSsExtOffset); CHECK_ALLOCATION(symbol_data = (char *) malloc(issExtMax + 2)); memset(symbol_data, 0, issExtMax + 2); fseek(f, cbSsExtOffset, SEEK_SET); if (fread(symbol_data, 1, issExtMax + 1, f) != (size_t) issExtMax+1) { fprintf(stderr, "error reading symbol data from %s\n", filename); exit(1); } nsymbols = iextMax; CHECK_ALLOCATION(extsyms = (struct ecoff_extsym *) malloc(iextMax * sizeof(struct ecoff_extsym))); memset(extsyms, 0, iextMax * sizeof(struct ecoff_extsym)); fseek(f, cbExtOffset, SEEK_SET); if (fread(extsyms, 1, iextMax * sizeof(struct ecoff_extsym), f) != iextMax * sizeof(struct ecoff_extsym)) { fprintf(stderr, "error reading extsyms from %s\n", filename); exit(1); } /* Unencode the strindex and value first: */ for (sym_nr=0; sym_nrsymbol_context, extsyms[sym_nr].es_value, 0, symbol_data + extsyms[sym_nr].es_strindex, 0, -1); } free(extsyms); free(symbol_data); skip_normal_coff_symbols: ; } fclose(f); *entrypointp = a_entry; *gpp = a_gp; m->file_loaded_end_addr = end_addr; if (program_byte_order != -1) encoding = program_byte_order; if (encoding == ELFDATA2LSB) *byte_orderp = EMUL_LITTLE_ENDIAN; else *byte_orderp = EMUL_BIG_ENDIAN; n_executables_loaded ++; } gxemul-0.6.1/src/file/file_raw.cc000644 001750 001750 00000007172 13402411502 017041 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Raw file support * * (Simply loads raw data into emulated memory space). */ /* Note: Included from file.c. */ /* * file_load_raw(): * * Loads a raw binary into emulated memory. The filename should be * of the following form: loadaddress:filename * or loadaddress:skiplen:filename * or loadaddress:skiplen:pc:filename */ static void file_load_raw(struct machine *m, struct memory *mem, char *filename, uint64_t *entrypointp) { FILE *f; int len, sign3264; unsigned char buf[16384]; uint64_t entry, loadaddr, vaddr, skip = 0; char *p, *p2; /* Special case for 32-bit MIPS: */ sign3264 = 0; if (m->arch == ARCH_MIPS && m->cpus[0]->is_32bit) sign3264 = 1; p = strchr(filename, ':'); if (p == NULL) { fprintf(stderr, "\n"); perror(filename); exit(1); } loadaddr = vaddr = entry = strtoull(filename, NULL, 0); p2 = p+1; /* A second value? That's the optional skip value */ p = strchr(p2, ':'); if (p != NULL) { skip = strtoull(p2, NULL, 0); p = p+1; /* A third value? That's the initial pc: */ if (strchr(p, ':') != NULL) { entry = strtoull(p, NULL, 0); p = strchr(p, ':') + 1; } } else p = p2; if (sign3264) { loadaddr = (int64_t)(int32_t)loadaddr; entry = (int64_t)(int32_t)entry; vaddr = (int64_t)(int32_t)vaddr; skip = (int64_t)(int32_t)skip; } f = fopen(strrchr(filename, ':')+1, "r"); if (f == NULL) { perror(p); exit(1); } fseek(f, skip, SEEK_SET); /* Load file contents: */ while (!feof(f)) { size_t to_read = sizeof(buf); /* If vaddr isn't buf-size aligned, then start with a smaller buffer: */ if (vaddr & (sizeof(buf) - 1)) to_read = sizeof(buf) - (vaddr & (sizeof(buf)-1)); len = fread(buf, 1, to_read, f); if (len > 0) m->cpus[0]->memory_rw(m->cpus[0], mem, vaddr, &buf[0], len, MEM_WRITE, NO_EXCEPTIONS); vaddr += len; } debug("RAW: 0x%" PRIx64" bytes @ 0x%08" PRIx64, (uint64_t) (ftello(f) - skip), (uint64_t) loadaddr); if (skip != 0) debug(" (0x%" PRIx64" bytes of header skipped)", (uint64_t) skip); debug("\n"); fclose(f); *entrypointp = entry; n_executables_loaded ++; } gxemul-0.6.1/src/file/file_macho.cc000644 001750 001750 00000021051 13402411502 017327 0ustar00debugdebug000000 000000 /* * Copyright (C) 2005-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: Mach-O file support */ /* Note: Included from file.c. */ /* * file_load_macho(): * * Loads a Mach-O binary image into the emulated memory. The entry point * is stored in the specified CPU's registers. * * TODO: * * o) Almost everything. * * o) I haven't had time to look into whether Apple's open source * license is BSD-compatible or not. Perhaps it would be possible * to use a header file containing symbolic names, and not use * hardcoded values. */ static void file_load_macho(struct machine *m, struct memory *mem, char *filename, uint64_t *entrypointp, int arch, int *byte_orderp, int is_64bit, int is_reversed) { FILE *f; uint64_t entry = 0; int entry_set = 0; int encoding = ELFDATA2MSB; unsigned char buf[65536]; char *symbols, *strings; uint32_t cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags; uint64_t vmaddr, vmsize, fileoff, filesize; int cmd_type, cmd_len, i, flavor; int32_t symoff, nsyms, stroff, strsize; size_t len, pos; if (m->cpus[0]->byte_order == EMUL_BIG_ENDIAN) encoding = ELFDATA2MSB; f = fopen(filename, "r"); if (f == NULL) { perror(filename); exit(1); } if (is_64bit) { fatal("TODO: 64-bit Mach-O. Not supported yet.\n"); exit(1); } if (is_reversed) { fatal("TODO: Reversed-endianness. Not supported yet.\n"); exit(1); } len = fread(buf, 1, sizeof(buf), f); if (len < 100) { fatal("Bad Mach-O file?\n"); exit(1); } unencode(cputype, &buf[4], uint32_t); unencode(cpusubtype, &buf[8], uint32_t); unencode(filetype, &buf[12], uint32_t); unencode(ncmds, &buf[16], uint32_t); unencode(sizeofcmds, &buf[20], uint32_t); unencode(flags, &buf[24], uint32_t); /* debug("cputype=0x%x cpusubtype=0x%x filetype=0x%x\n", cputype, cpusubtype, filetype); debug("ncmds=%i sizeofcmds=0x%08x flags=0x%08x\n", ncmds, sizeofcmds, flags); */ /* * Compare to "normal" values. * NOTE/TODO: These were for a Darwin (Macintosh PPC) kernel. */ if (cputype != 0x12) { fatal("Error: Unimplemented cputype 0x%x\n", cputype); exit(1); } if (cpusubtype != 0) { fatal("Error: Unimplemented cpusubtype 0x%x\n", cpusubtype); exit(1); } /* Filetype 2 means an executable image. */ if (filetype != 2) { fatal("Error: Unimplemented filetype 0x%x\n", filetype); exit(1); } if (!(flags & 1)) { fatal("Error: File has 'undefined references'. Cannot" " be executed.\n", flags); exit(1); } /* I've only encountered flags == 1 so far. */ if (flags != 1) { fatal("Error: Unimplemented flags 0x%x\n", flags); exit(1); } /* * Read all load commands: */ pos = is_64bit? 32 : 28; cmd_type = 0; do { /* Read command type and length: */ unencode(cmd_type, &buf[pos], uint32_t); unencode(cmd_len, &buf[pos+4], uint32_t); #if 0 debug("cmd %i, len=%i\n", cmd_type, cmd_len); for (i=8; i= ' ' && ch < 127) debug("%c", ch); else debug("."); } #endif switch (cmd_type) { case 1: /* LC_SEGMENT */ debug("seg "); for (i=0; i<16; i++) { if (buf[pos + 8 + i] == 0) break; debug("%c", buf[pos + 8 + i]); } unencode(vmaddr, &buf[pos+8+16+0], uint32_t); unencode(vmsize, &buf[pos+8+16+4], uint32_t); unencode(fileoff, &buf[pos+8+16+8], uint32_t); unencode(filesize, &buf[pos+8+16+12], uint32_t); debug(": vmaddr=0x%x size=0x%x fileoff=0x%x", (int)vmaddr, (int)vmsize, (int)fileoff); if (filesize == 0) { debug("\n"); break; } fseek(f, fileoff, SEEK_SET); /* Load data from the file: */ while (filesize != 0) { unsigned char buf2[32768]; ssize_t lenRead = filesize > sizeof(buf2) ? sizeof(buf2) : filesize; lenRead = fread(buf2, 1, lenRead, f); /* printf("fread len=%i vmaddr=%x buf[0..]=" "%02x %02x %02x\n", (int)len, (int)vmaddr, buf2[0], buf2[1], buf2[2]); */ if (lenRead > 0) { int len2 = 0; uint64_t vaddr1 = vmaddr & ((1 << BITS_PER_MEMBLOCK) - 1); uint64_t vaddr2 = (vmaddr + lenRead) & ((1 << BITS_PER_MEMBLOCK)-1); if (vaddr2 < vaddr1) { len2 = lenRead - vaddr2; m->cpus[0]->memory_rw(m->cpus[ 0], mem, vmaddr, &buf2[0], len2, MEM_WRITE, NO_EXCEPTIONS); } m->cpus[0]->memory_rw(m->cpus[0], mem, vmaddr + len2, &buf2[len2], lenRead-len2, MEM_WRITE, NO_EXCEPTIONS); } else { fprintf(stderr, "error reading\n"); exit(1); } vmaddr += lenRead; filesize -= lenRead; } debug("\n"); break; case 2: /* LC_SYMTAB */ unencode(symoff, &buf[pos+8], uint32_t); unencode(nsyms, &buf[pos+12], uint32_t); unencode(stroff, &buf[pos+16], uint32_t); unencode(strsize, &buf[pos+20], uint32_t); debug("symtable: %i symbols @ 0x%x (strings at " "0x%x)\n", nsyms, symoff, stroff); CHECK_ALLOCATION(symbols = (char *) malloc(12 * nsyms)); fseek(f, symoff, SEEK_SET); if (fread(symbols, 1, 12 * nsyms, f) != (size_t) 12*nsyms) { fprintf(stderr, "could not read symbols from %s\n", filename); exit(1); } CHECK_ALLOCATION(strings = (char *) malloc(strsize)); fseek(f, stroff, SEEK_SET); if (fread(strings, 1, strsize, f) != (size_t) strsize) { fprintf(stderr, "could not read symbol strings from %s\n", filename); exit(1); } for (i=0; isymbol_context, n_value, 0, strings + n_strx, 0, -1); } free(symbols); free(strings); break; case 5: debug("unix thread context: "); /* See http://cvs.sf.net/viewcvs.py/hte/ HT%20Editor/machostruc.h or similar for details on the thread struct. */ unencode(flavor, &buf[pos+8], uint32_t); if (flavor != 1) { fatal("unimplemented flavor %i\n", flavor); exit(1); } if (arch != ARCH_PPC) { fatal("non-PPC arch? TODO\n"); exit(1); } unencode(entry, &buf[pos+16], uint32_t); entry_set = 1; debug("pc=0x%x\n", (int)entry); for (i=1; i<40; i++) { uint32_t x; unencode(x, &buf[pos+16+i*4], uint32_t); if (x != 0) { fatal("Entry nr %i in the Mach-O" " thread struct is non-zero" " (0x%x). This is not supported" " yet. TODO\n", i, x); exit(1); } } break; default:fatal("WARNING! Unimplemented load command %i!\n", cmd_type); } pos += cmd_len; } while (pos < sizeofcmds && cmd_type != 0); fclose(f); if (!entry_set) { fatal("No entry point? Aborting.\n"); exit(1); } *entrypointp = entry; if (encoding == ELFDATA2LSB) *byte_orderp = EMUL_LITTLE_ENDIAN; else *byte_orderp = EMUL_BIG_ENDIAN; n_executables_loaded ++; } gxemul-0.6.1/src/file/file_aout.cc000644 001750 001750 00000015163 13402411502 017217 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: a.out executable file support */ /* Note: Included from file.c. */ #include "thirdparty/exec_aout.h" #define AOUT_FLAG_DECOSF1 1 #define AOUT_FLAG_FROM_BEGINNING 2 #define AOUT_FLAG_VADDR_ZERO_HACK 4 #define AOUT_FLAG_NO_SIZES 8 struct aout_symbol { uint32_t strindex; uint32_t type; uint32_t addr; }; /* * file_load_aout(): * * Loads an a.out binary image into the emulated memory. The entry point * (read from the a.out header) is stored in the specified CPU's registers. * * TODO: This has to be rewritten / corrected to support multiple a.out * formats, where text/data are aligned differently. */ static void file_load_aout(struct machine *m, struct memory *mem, char *filename, int flags, uint64_t *entrypointp, int arch, int *byte_orderp) { struct exec aout_header; FILE *f; int len; int encoding = ELFDATA2LSB; uint32_t entry, datasize, textsize; int32_t symbsize = 0; uint32_t vaddr, total_len; unsigned char buf[65536]; unsigned char *syms; if (m->cpus[0]->byte_order == EMUL_BIG_ENDIAN) encoding = ELFDATA2MSB; f = fopen(filename, "r"); if (f == NULL) { perror(filename); exit(1); } if (flags & AOUT_FLAG_DECOSF1) { if (fread(&buf, 1, 32, f) != 32) { perror(filename); exit(1); } vaddr = buf[16] + (buf[17] << 8) + (buf[18] << 16) + ((uint64_t)buf[19] << 24); entry = buf[20] + (buf[21] << 8) + (buf[22] << 16) + ((uint64_t)buf[23] << 24); debug("OSF1 a.out, load address 0x%08lx, " "entry point 0x%08x\n", (long)vaddr, (long)entry); symbsize = 0; fseek(f, 0, SEEK_END); /* This is of course wrong, but should work anyway: */ textsize = ftello(f) - 512; datasize = 0; fseek(f, 512, SEEK_SET); } else if (flags & AOUT_FLAG_NO_SIZES) { fseek(f, 0, SEEK_END); textsize = ftello(f) - 32; datasize = 0; vaddr = entry = 0; fseek(f, 32, SEEK_SET); } else { len = fread(&aout_header, 1, sizeof(aout_header), f); if (len != sizeof(aout_header)) { fprintf(stderr, "%s: not a complete a.out image\n", filename); exit(1); } unencode(entry, &aout_header.a_entry, uint32_t); debug("a.out, entry point 0x%08lx\n", (long)entry); vaddr = entry; if (flags & AOUT_FLAG_VADDR_ZERO_HACK) vaddr = 0; unencode(textsize, &aout_header.a_text, uint32_t); unencode(datasize, &aout_header.a_data, uint32_t); debug("text + data = %i + %i bytes\n", textsize, datasize); unencode(symbsize, &aout_header.a_syms, uint32_t); } if (flags & AOUT_FLAG_FROM_BEGINNING) { fseek(f, 0, SEEK_SET); vaddr &= ~0xfff; } /* Load text and data: */ total_len = textsize + datasize; while (total_len != 0) { len = total_len > sizeof(buf) ? sizeof(buf) : total_len; len = fread(buf, 1, len, f); /* printf("fread len=%i vaddr=%x buf[0..]=%02x %02x %02x\n", (int)len, (int)vaddr, buf[0], buf[1], buf[2]); */ if (len > 0) { int len2 = 0; uint64_t vaddr1 = vaddr & ((1 << BITS_PER_MEMBLOCK) - 1); uint64_t vaddr2 = (vaddr + len) & ((1 << BITS_PER_MEMBLOCK) - 1); if (vaddr2 < vaddr1) { len2 = len - vaddr2; m->cpus[0]->memory_rw(m->cpus[0], mem, vaddr, &buf[0], len2, MEM_WRITE, NO_EXCEPTIONS); } m->cpus[0]->memory_rw(m->cpus[0], mem, vaddr + len2, &buf[len2], len-len2, MEM_WRITE, NO_EXCEPTIONS); } else { if (flags & AOUT_FLAG_DECOSF1) break; else { fprintf(stderr, "could not read from %s," " wanted to read %i bytes\n", filename, (int) total_len); exit(1); } } vaddr += len; total_len -= len; } if (symbsize != 0) { struct aout_symbol *aout_symbol_ptr; int i, n_symbols; uint32_t type, addr, str_index; uint32_t strings_len; char *string_symbols; off_t oldpos; debug("symbols: %i bytes @ 0x%x\n", symbsize, (int)ftello(f)); CHECK_ALLOCATION(syms = (unsigned char *) malloc(symbsize)); len = fread(syms, 1, symbsize, f); if (len != symbsize) { fprintf(stderr, "error reading symbols from %s\n", filename); exit(1); } oldpos = ftello(f); fseek(f, 0, SEEK_END); strings_len = ftello(f) - oldpos; fseek(f, oldpos, SEEK_SET); debug("strings: %i bytes @ 0x%x\n", strings_len,(int)ftello(f)); CHECK_ALLOCATION(string_symbols = (char *) malloc(strings_len)); if (fread(string_symbols, 1, strings_len, f) != strings_len) { fprintf(stderr, "Could not read symbols from %s?\n", filename); perror("fread"); exit(1); } aout_symbol_ptr = (struct aout_symbol *) (void*) syms; n_symbols = symbsize / sizeof(struct aout_symbol); i = 0; while (i < n_symbols) { unencode(str_index, &aout_symbol_ptr[i].strindex, uint32_t); unencode(type, &aout_symbol_ptr[i].type, uint32_t); unencode(addr, &aout_symbol_ptr[i].addr, uint32_t); /* debug("symbol type 0x%04x @ 0x%08x: %s\n", type, addr, string_symbols + str_index); */ if (type != 0 && addr != 0) add_symbol_name(&m->symbol_context, addr, 0, string_symbols + str_index, 0, -1); i++; } free(string_symbols); free(syms); } fclose(f); *entrypointp = (int32_t)entry; if (encoding == ELFDATA2LSB) *byte_orderp = EMUL_LITTLE_ENDIAN; else *byte_orderp = EMUL_BIG_ENDIAN; n_executables_loaded ++; } gxemul-0.6.1/src/file/.index000644 001750 001750 00000000315 13402411502 016042 0ustar00debugdebug000000 000000 file_aout.cc a.out executable file support file_ecoff.cc ECOFF file support file_elf.cc ELF file support file_macho.cc Mach-O file support file_raw.cc Raw file support file_srec.cc SREC file support gxemul-0.6.1/src/file/Makefile.skel000644 001750 001750 00000000503 13402411502 017326 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/file # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(DINCLUDE) OBJS=file.o all: $(OBJS) ../../experiments/make_index.sh $(OBJS): Makefile file.o: file.cc file_aout.cc file_ecoff.cc file_elf.cc file_macho.cc \ file_raw.cc file_srec.cc clean: rm -f $(OBJS) *core clean_all: clean rm -f Makefile gxemul-0.6.1/src/file/file_srec.cc000644 001750 001750 00000011643 13402411502 017202 0ustar00debugdebug000000 000000 /* * Copyright (C) 2003-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * COMMENT: SREC file support */ /* Note: Included from file.c. */ /* * file_load_srec(): * * Loads a Motorola SREC file into emulated memory. Description of the SREC * file format can be found at here: * * http://www.ndsu.nodak.edu/instruct/tareski/373f98/notes/srecord.htm * or http://www.amelek.gda.pl/avr/uisp/srecord.htm */ static void file_load_srec(struct machine *m, struct memory *mem, char *filename, uint64_t *entrypointp) { FILE *f; unsigned char buf[516]; unsigned char bytes[270]; uint64_t entry = 0, vaddr = 0; int i, j, count; char ch; int buf_len, data_start = 0; int entry_set = 0; int warning = 0; int warning_len = 0; int total_bytes_loaded = 0; f = fopen(filename, "r"); if (f == NULL) { perror(filename); exit(1); } /* Load file contents: */ while (!feof(f)) { memset(buf, 0, sizeof(buf)); if (fgets((char *)buf, sizeof(buf)-1, f) == NULL || buf[0] == 0 || buf[0]=='\r' || buf[0]=='\n') continue; if (buf[0] != 'S') { if (!warning) debug("WARNING! non-S-record found\n"); warning = 1; continue; } buf_len = strlen((char *)buf); if (buf_len < 10) { if (!warning_len) debug("WARNING! invalid S-record found\n"); warning_len = 1; continue; } /* * Stype count address data checksum * 01 23 4.. .. (last 2 bytes) * * TODO: actually check the checksum */ j = 0; for (i=1; i='a' && buf[i]<='f') buf[i] += 10 - 'a'; else if (buf[i] >= 'A' && buf[i] <= 'F') buf[i] += 10 - 'A'; else if (buf[i] >= '0' && buf[i] <= '9') buf[i] -= '0'; else if (buf[i] == '\r' || buf[i] == '\n') { } else fatal("invalid characters '%c' in S-record\n", buf[i]); if (i >= 4) { if (i & 1) bytes[j++] += buf[i]; else bytes[j] = buf[i] * 16; } } count = buf[2] * 16 + buf[3]; /* debug("count=%i j=%i\n", count, j); */ /* count is j - 1. */ switch (buf[1]) { case 0: debug("SREC \""); for (i=2; i= ' ' && ch < 127) debug("%c", ch); else debug("?"); } debug("\"\n"); break; case 1: case 2: case 3: /* switch again, to get the load address: */ switch (buf[1]) { case 1: data_start = 2; vaddr = (bytes[0] << 8) + bytes[1]; break; case 2: data_start = 3; vaddr = (bytes[0] << 16) + (bytes[1] << 8) + bytes[2]; break; case 3: data_start = 4; vaddr = ((uint64_t)bytes[0] << 24) + (bytes[1] << 16) + (bytes[2]<<8) + bytes[3]; } m->cpus[0]->memory_rw(m->cpus[0], mem, vaddr, &bytes[data_start], count - 1 - data_start, MEM_WRITE, NO_EXCEPTIONS); total_bytes_loaded += count - 1 - data_start; break; case 7: case 8: case 9: /* switch again, to get the entry point: */ switch (buf[1]) { case 7: entry = ((uint64_t)bytes[0] << 24) + (bytes[1] << 16) + (bytes[2]<<8) + bytes[3]; break; case 8: entry = (bytes[0] << 16) + (bytes[1] << 8) + bytes[2]; break; case 9: entry = (bytes[0] << 8) + bytes[1]; break; } entry_set = 1; debug("entry point 0x%08x\n", (unsigned int)entry); break; default: debug("unimplemented S-record type %i\n", buf[1]); } } debug("0x%x bytes loaded\n", total_bytes_loaded); fclose(f); if (!entry_set) debug("WARNING! no entrypoint found!\n"); else *entrypointp = entry; n_executables_loaded ++; } gxemul-0.6.1/src/net/net.cc000644 001750 001750 00000052571 13402411502 015711 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2009 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Emulated network. * * (Read the README file in this directory for more details.) * * * NOTE: The 'extra' argument used in many functions in this file is a pointer * to something unique for each NIC (i.e. the NIC itself :-), so that if * multiple NICs are emulated concurrently, they will not get packets that * are meant for some other controller. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "machine.h" #include "misc.h" #include "net.h" /* #define debug fatal */ /* * net_allocate_ethernet_packet_link(): * * This routine allocates an ethernet_packet_link struct, and adds it at * the end of the packet chain. A data buffer is allocated, and the data, * extra, and len fields of the link are set. * * Note: The data buffer is not zeroed. * * Return value is a pointer to the link on success. It doesn't return on * failure. */ struct ethernet_packet_link *net_allocate_ethernet_packet_link( struct net *net, void *extra, size_t len) { struct ethernet_packet_link *lp; CHECK_ALLOCATION(lp = (struct ethernet_packet_link *) malloc(sizeof(struct ethernet_packet_link))); lp->len = len; lp->extra = extra; CHECK_ALLOCATION(lp->data = (unsigned char *) malloc(len)); lp->next = NULL; /* Add last in the link chain: */ lp->prev = net->last_ethernet_packet; if (lp->prev != NULL) lp->prev->next = lp; else net->first_ethernet_packet = lp; net->last_ethernet_packet = lp; return lp; } /* * net_arp(): * * Handle an ARP (or RARP) packet, coming from the emulated NIC. * * An ARP packet might look like this: * * ARP header: * ARP hardware addr family: 0001 * ARP protocol addr family: 0800 * ARP addr lengths: 06 04 * ARP request: 0001 * ARP from: 112233445566 01020304 * ARP to: 000000000000 01020301 * * An ARP request with a 'to' IP value of the gateway should cause an * ARP response packet to be created. * * An ARP request with the same from and to IP addresses should be ignored. * (This would be a host testing to see if there is an IP collision.) */ static void net_arp(struct net *net, void *extra, unsigned char *packet, int len, int reverse) { int q; int i; /* TODO: This debug dump assumes ethernet->IPv4 translation: */ if (reverse) debug("[ net: RARP: "); else debug("[ net: ARP: "); for (i=0; i<2; i++) debug("%02x", packet[i]); debug(" "); for (i=2; i<4; i++) debug("%02x", packet[i]); debug(" "); debug("%02x", packet[4]); debug(" "); debug("%02x", packet[5]); debug(" req="); debug("%02x", packet[6]); /* Request type */ debug("%02x", packet[7]); debug(" from="); for (i=8; i<18; i++) debug("%02x", packet[i]); debug(" to="); for (i=18; i<28; i++) debug("%02x", packet[i]); debug(" ]\n"); if (packet[0] == 0x00 && packet[1] == 0x01 && packet[2] == 0x08 && packet[3] == 0x00 && packet[4] == 0x06 && packet[5] == 0x04) { int r = (packet[6] << 8) + packet[7]; struct ethernet_packet_link *lp; switch (r) { case 1: /* Request */ /* Only create a reply if this was meant for the gateway: */ if (memcmp(packet+24, net->gateway_ipv4_addr, 4) != 0) break; lp = net_allocate_ethernet_packet_link( net, extra, 60 + 14); /* Copy the old packet first: */ memset(lp->data, 0, 60 + 14); memcpy(lp->data + 14, packet, len); /* Add ethernet ARP header: */ memcpy(lp->data + 0, lp->data + 8 + 14, 6); memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); lp->data[12] = 0x08; lp->data[13] = 0x06; /* Address of the emulated machine: */ memcpy(lp->data + 18 + 14, lp->data + 8 + 14, 10); /* Address of the gateway: */ memcpy(lp->data + 8 + 14, net->gateway_ethernet_addr, 6); memcpy(lp->data + 14 + 14, net->gateway_ipv4_addr, 4); /* This is a Reply: */ lp->data[6 + 14] = 0x00; lp->data[7 + 14] = 0x02; break; case 3: /* Reverse Request */ lp = net_allocate_ethernet_packet_link( net, extra, 60 + 14); /* Copy the old packet first: */ memset(lp->data, 0, 60 + 14); memcpy(lp->data + 14, packet, len); /* Add ethernet RARP header: */ memcpy(lp->data + 0, packet + 8, 6); memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); lp->data[12] = 0x80; lp->data[13] = 0x35; /* This is a RARP reply: */ lp->data[6 + 14] = 0x00; lp->data[7 + 14] = 0x04; /* Address of the gateway: */ memcpy(lp->data + 8 + 14, net->gateway_ethernet_addr, 6); memcpy(lp->data + 14 + 14, net->gateway_ipv4_addr, 4); /* MAC address of emulated machine: */ memcpy(lp->data + 18 + 14, packet + 8, 6); /* * IP address of the emulated machine: Automagically * generated from the MAC address. :-) * * packet+8 points to the client's mac address, * for example 10:20:30:00:00:z0, where z is 0..15. * 10:20:30:00:00:10 results in 10.0.0.1. */ /* q = (packet[8 + 3]) >> 4; */ /* q = q*15 + ((packet[8 + 4]) >> 4); */ q = (packet[8 + 5]) >> 4; lp->data[24 + 14] = 10; lp->data[25 + 14] = 0; lp->data[26 + 14] = 0; lp->data[27 + 14] = q; break; case 2: /* Reply */ case 4: /* Reverse Reply */ default: fatal("[ net: ARP: UNIMPLEMENTED request type " "0x%04x ]\n", r); } } else { fatal("[ net: ARP: UNIMPLEMENTED arp packet type: "); for (i=0; ilocal_port != 0) { struct sockaddr_in si; socklen_t si_len = sizeof(si); int res, i, nreceived = 0; unsigned char buf[60000]; do { res = recvfrom(net->local_port_socket, buf, sizeof(buf), 0, (struct sockaddr *)&si, &si_len); if (res != -1) { nreceived ++; /* fatal("[ incoming DISTRIBUTED packet, %i " "bytes from %s:%d\n", res, inet_ntoa(si.sin_addr), ntohs(si.sin_port)); */ /* Add the packet to all "our" NICs on this network: */ for (i=0; in_nics; i++) { struct ethernet_packet_link *lp; lp = net_allocate_ethernet_packet_link( net, net->nic_extra[i], res); memcpy(lp->data, buf, res); } } } while (res != -1 && nreceived < 100); } /* IP protocol specific: */ net_udp_rx_avail(net, extra); net_tcp_rx_avail(net, extra); return net_ethernet_rx(net, extra, NULL, NULL); } /* * net_ethernet_rx(): * * Receive an ethernet packet. (This means handing over an already prepared * packet from this module to a specific ethernet controller device.) * * Return value is 1 if there was a packet available. *packetp and *lenp * will be set to the packet's data pointer and length, respectively, and * the packet will be removed from the linked list). If there was no packet * available, 0 is returned. * * If packetp is NULL, then the search is aborted as soon as a packet with * the correct 'extra' field is found, and a 1 is returned, but as packetp * is NULL we can't return the actual packet. (This is the internal form * if net_ethernet_rx_avail().) */ int net_ethernet_rx(struct net *net, void *extra, unsigned char **packetp, int *lenp) { struct ethernet_packet_link *lp, *prev; if (net == NULL) return 0; /* Find the first packet which has the right 'extra' field. */ lp = net->first_ethernet_packet; prev = NULL; while (lp != NULL) { if (lp->extra == extra) { /* We found a packet for this controller! */ if (packetp == NULL || lenp == NULL) return 1; /* Let's return it: */ (*packetp) = lp->data; (*lenp) = lp->len; /* Remove this link from the linked list: */ if (prev == NULL) net->first_ethernet_packet = lp->next; else prev->next = lp->next; if (lp->next == NULL) net->last_ethernet_packet = prev; else lp->next->prev = prev; free(lp); /* ... and return successfully: */ return 1; } prev = lp; lp = lp->next; } /* No packet found. :-( */ return 0; } /* * net_ethernet_tx(): * * Transmit an ethernet packet, as seen from the emulated ethernet controller. * If the packet can be handled here, it will not necessarily be transmitted * to the outside world. */ void net_ethernet_tx(struct net *net, void *extra, unsigned char *packet, int len) { int i, eth_type, for_the_gateway; if (net == NULL) return; for_the_gateway = !memcmp(packet, net->gateway_ethernet_addr, 6); /* Drop too small packets: */ if (len < 20) { fatal("[ net_ethernet_tx: Warning: dropping tiny packet " "(%i bytes) ]\n", len); return; } /* * Copy this packet to all other NICs on this network (except if * it is aimed specifically at the gateway's ethernet address): */ if (!for_the_gateway && extra != NULL && net->n_nics > 0) { for (i=0; in_nics; i++) if (extra != net->nic_extra[i]) { struct ethernet_packet_link *lp; lp = net_allocate_ethernet_packet_link(net, net->nic_extra[i], len); /* Copy the entire packet: */ memcpy(lp->data, packet, len); } } /* * If this network is distributed across multiple emulator processes, * then transmit the packet to those other processes. */ if (!for_the_gateway && net->remote_nets != NULL) { struct remote_net *rnp = net->remote_nets; while (rnp != NULL) { send_udp(&rnp->ipv4_addr, rnp->portnr, packet, len); rnp = rnp->next; } } /* * The code below simulates the behaviour of a "NAT"-style gateway. * * Packets that are not destined for the gateway are dropped first: * (DHCP packets are let through, though.) */ if (!for_the_gateway && packet[0] != 0xff && packet[0] != 0x00) return; #if 0 fatal("[ net: ethernet: "); for (i=0; i<6; i++) fatal("%02x", packet[i]); fatal(" "); for (i=6; i<12; i++) fatal("%02x", packet[i]); fatal(" "); for (i=12; i<14; i++) fatal("%02x", packet[i]); fatal(" "); for (i=14; in_nics < 2) { fatal("[ net_ethernet_tx: IP packet not for gateway, " "and not broadcast: "); for (i=0; i<14; i++) fatal("%02x", packet[i]); fatal(" ]\n"); } return; } /* ARP: */ if (eth_type == ETHERTYPE_ARP) { if (len != 42 && len != 60) fatal("[ net_ethernet_tx: WARNING! unusual " "ARP len (%i) ]\n", len); net_arp(net, extra, packet + 14, len - 14, 0); return; } /* RARP: */ if (eth_type == ETHERTYPE_REVARP) { net_arp(net, extra, packet + 14, len - 14, 1); return; } /* Sprite: */ if (eth_type == ETHERTYPE_SPRITE) { /* TODO. */ fatal("[ net: TX: UNIMPLEMENTED Sprite packet ]\n"); return; } /* IPv6: */ if (eth_type == ETHERTYPE_IPV6) { /* TODO. */ fatal("[ net_ethernet_tx: IPv6 is not implemented yet! ]\n"); return; } fatal("[ net_ethernet_tx: ethernet packet type 0x%04x not yet " "implemented ]\n", eth_type); } /* * parse_resolvconf(): * * This function parses "/etc/resolv.conf" to figure out the nameserver * and domain used by the host. */ static void parse_resolvconf(struct net *net) { FILE *f; char buf[8000]; size_t len; int res; unsigned int i, start; /* * This is a very ugly hack, which tries to figure out which * nameserver the host uses by looking for the string 'nameserver' * in /etc/resolv.conf. * * This can later on be used for DHCP autoconfiguration. (TODO) * * TODO: This is hardcoded to use /etc/resolv.conf. Not all * operating systems use that filename. * * TODO: This is hardcoded for AF_INET (that is, IPv4). * * TODO: This assumes that the first nameserver listed is the * one to use. */ f = fopen("/etc/resolv.conf", "r"); if (f == NULL) return; /* TODO: get rid of the hardcoded values */ memset(buf, 0, sizeof(buf)); len = fread(buf, 1, sizeof(buf) - 100, f); fclose(f); buf[sizeof(buf) - 1] = '\0'; for (i=0; i= len) break; start = i; p = buf+start; while ((*p >= '0' && *p <= '9') || *p == '.') p++; *p = '\0'; #ifdef HAVE_INET_PTON res = inet_pton(AF_INET, buf + start, &net->nameserver_ipv4); #else res = inet_aton(buf + start, &net->nameserver_ipv4); #endif if (res < 1) break; net->nameserver_known = 1; break; } for (i=0; i= len) break; start = i; while (idomain_name = strdup(buf+start)); break; } } /* * net_add_nic(): * * Add a NIC to a network. (All NICs on a network will see each other's * packets.) */ void net_add_nic(struct net *net, void *extra, unsigned char *macaddr) { if (net == NULL) return; if (extra == NULL) { fprintf(stderr, "net_add_nic(): extra = NULL\n"); exit(1); } net->n_nics ++; CHECK_ALLOCATION(net->nic_extra = (void **) realloc(net->nic_extra, sizeof(void *) * net->n_nics)); net->nic_extra[net->n_nics - 1] = extra; } /* * net_gateway_init(): * * This function creates a "gateway" machine (for example at IPv4 address * 10.0.0.254, if the net is 10.0.0.0/8), which acts as a gateway/router/ * nameserver etc. */ static void net_gateway_init(struct net *net) { unsigned char *p = (unsigned char *) &net->netmask_ipv4; uint32_t x; int xl; x = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; xl = 32 - net->netmask_ipv4_len; if (xl > 8) xl = 8; x |= ((1 << xl) - 1) & ~1; net->gateway_ipv4_addr[0] = x >> 24; net->gateway_ipv4_addr[1] = x >> 16; net->gateway_ipv4_addr[2] = x >> 8; net->gateway_ipv4_addr[3] = x; net->gateway_ethernet_addr[0] = 0x60; net->gateway_ethernet_addr[1] = 0x50; net->gateway_ethernet_addr[2] = 0x40; net->gateway_ethernet_addr[3] = 0x30; net->gateway_ethernet_addr[4] = 0x20; net->gateway_ethernet_addr[5] = 0x10; } /* * net_dumpinfo(): * * Called from the debugger's "machine" command, to print some info about * a network. */ void net_dumpinfo(struct net *net) { int iadd = DEBUG_INDENTATION; struct remote_net *rnp; debug("net:\n"); debug_indentation(iadd); debug("simulated network: "); net_debugaddr(&net->netmask_ipv4, NET_ADDR_IPV4); debug("/%i", net->netmask_ipv4_len); debug(" (max outgoing: TCP=%i, UDP=%i)\n", MAX_TCP_CONNECTIONS, MAX_UDP_CONNECTIONS); debug("simulated gateway+nameserver: "); net_debugaddr(&net->gateway_ipv4_addr, NET_ADDR_IPV4); debug(" ("); net_debugaddr(&net->gateway_ethernet_addr, NET_ADDR_ETHERNET); debug(")\n"); if (!net->nameserver_known) { debug("(could not determine nameserver)\n"); } else { debug("simulated nameserver uses real nameserver "); net_debugaddr(&net->nameserver_ipv4, NET_ADDR_IPV4); debug("\n"); } if (net->domain_name != NULL && net->domain_name[0]) debug("domain: %s\n", net->domain_name); rnp = net->remote_nets; if (net->local_port != 0) debug("distributed network: local port = %i\n", net->local_port); debug_indentation(iadd); while (rnp != NULL) { debug("remote \"%s\": ", rnp->name); net_debugaddr(&rnp->ipv4_addr, NET_ADDR_IPV4); debug(" port %i\n", rnp->portnr); rnp = rnp->next; } debug_indentation(-iadd); debug_indentation(-iadd); } /* * net_init(): * * This function creates a network, and returns a pointer to it. * * ipv4addr should be something like "10.0.0.0", netipv4len = 8. * * If n_remote is more than zero, remote should be a pointer to an array * of strings of the following format: "host:portnr". * * Network settings are registered if settings_prefix is non-NULL. * (The one calling net_init() is also responsible for calling net_deinit().) * * On failure, exit() is called. */ struct net *net_init(struct emul *emul, int init_flags, const char *ipv4addr, int netipv4len, char **remote, int n_remote, int local_port, const char *settings_prefix) { struct net *net; int res; CHECK_ALLOCATION(net = (struct net *) malloc(sizeof(struct net))); memset(net, 0, sizeof(struct net)); /* Set the back pointer: */ net->emul = emul; /* Sane defaults: */ net->timestamp = 0; net->first_ethernet_packet = net->last_ethernet_packet = NULL; #ifdef HAVE_INET_PTON res = inet_pton(AF_INET, ipv4addr, &net->netmask_ipv4); #else res = inet_aton(ipv4addr, &net->netmask_ipv4); #endif if (res < 1) { fprintf(stderr, "net_init(): could not parse IPv4 address" " '%s'\n", ipv4addr); exit(1); } if (netipv4len < 1 || netipv4len > 30) { fprintf(stderr, "net_init(): extremely weird ipv4 " "network length (%i)\n", netipv4len); exit(1); } net->netmask_ipv4_len = netipv4len; net->nameserver_known = 0; net->domain_name = strdup(""); parse_resolvconf(net); /* Distributed network? Then add remote hosts: */ if (local_port != 0) { struct sockaddr_in si_self; net->local_port = local_port; net->local_port_socket = socket(AF_INET, SOCK_DGRAM, 0); if (net->local_port_socket < 0) { perror("socket"); exit(1); } memset((char *)&si_self, 0, sizeof(si_self)); si_self.sin_family = AF_INET; si_self.sin_port = htons(local_port); si_self.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(net->local_port_socket, (struct sockaddr *)&si_self, sizeof(si_self)) < 0) { perror("bind"); exit(1); } /* Set the socket to non-blocking: */ res = fcntl(net->local_port_socket, F_GETFL); fcntl(net->local_port_socket, F_SETFL, res | O_NONBLOCK); } if (n_remote != 0) { struct remote_net *rnp; while ((n_remote--) != 0) { struct hostent *hp; /* debug("adding '%s'\n", remote[n_remote]); */ CHECK_ALLOCATION(rnp = (struct remote_net *) malloc(sizeof(struct remote_net))); memset(rnp, 0, sizeof(struct remote_net)); rnp->next = net->remote_nets; net->remote_nets = rnp; CHECK_ALLOCATION(rnp->name = strdup(remote[n_remote])); if (strchr(rnp->name, ':') != NULL) strchr(rnp->name, ':')[0] = '\0'; hp = gethostbyname(rnp->name); if (hp == NULL) { fprintf(stderr, "could not resolve '%s'\n", rnp->name); exit(1); } memcpy(&rnp->ipv4_addr, hp->h_addr, hp->h_length); free(rnp->name); /* And again: */ CHECK_ALLOCATION(rnp->name = strdup(remote[n_remote])); if (strchr(rnp->name, ':') == NULL) { fprintf(stderr, "Remote network '%s' is not " "'host:portnr'?\n", rnp->name); exit(1); } rnp->portnr = atoi(strchr(rnp->name, ':') + 1); } } if (init_flags & NET_INIT_FLAG_GATEWAY) net_gateway_init(net); net_dumpinfo(net); /* This is necessary when using the real network: */ signal(SIGPIPE, SIG_IGN); return net; } gxemul-0.6.1/src/net/Makefile.skel000644 001750 001750 00000000336 13402411502 017201 0ustar00debugdebug000000 000000 # # Makefile for GXemul src/net # CXXFLAGS=$(CWARNINGS) $(COPTIM) $(XINCLUDE) $(DINCLUDE) OBJS=net.o net_ip.o net_misc.o all: $(OBJS) $(OBJS): Makefile clean: rm -f $(OBJS) *core clean_all: clean rm -f Makefile gxemul-0.6.1/src/net/net_misc.cc000644 001750 001750 00000007727 13402411502 016727 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2018 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Misc. helper functions. */ #include #include #include #include #include #include #include #include #include "machine.h" #include "misc.h" #include "net.h" /* * net_debugaddr(): * * Print an address using debug(). */ void net_debugaddr(void *addr, int type) { int i; unsigned char *p = (unsigned char *) addr; switch (type) { case NET_ADDR_IPV4: for (i=0; i<4; i++) debug("%s%i", i? "." : "", p[i]); break; case NET_ADDR_IPV6: for (i=0; i<16; i+=2) debug("%s%4x", i? ":" : "", p[i] * 256 + p[i+1]); break; case NET_ADDR_ETHERNET: for (i=0; i<6; i++) debug("%s%02x", i? ":" : "", p[i]); break; default: fatal("net_debugaddr(): UNIMPLEMTED type %i\n", type); exit(1); } } /* * net_generate_unique_mac(): * * Generate a "unique" serial number for a machine. The machine's serial * number is combined with the machine's current number of NICs to form a * more-or-less valid MAC address. * * The return value (6 bytes) are written to macbuf. */ void net_generate_unique_mac(struct machine *machine, unsigned char *macbuf) { int x, y; if (macbuf == NULL || machine == NULL) { fatal("**\n** net_generate_unique_mac(): NULL ptr\n**\n"); return; } x = machine->serial_nr; y = machine->nr_of_nics; // Special case: SGI machines have 0x08 as their first byte? macbuf[0] = machine->machine_type == MACHINE_SGI ? 0x08 : 0x10; macbuf[1] = 0x20; macbuf[2] = 0x30; macbuf[3] = 0; macbuf[4] = 0; /* NOTE/TODO: This only allows 8 nics per machine! */ macbuf[5] = (machine->serial_nr << 4) + (machine->nr_of_nics << 1); if (macbuf[0] & 1 || macbuf[5] & 1) { fatal("Internal error in net_generate_unique_mac().\n"); exit(1); } /* TODO: Remember the mac addresses somewhere? */ machine->nr_of_nics ++; } /* * send_udp(): * * Send a simple UDP packet to a real (physical) host. Used for distributed * network simulations. */ void send_udp(struct in_addr *addrp, int portnr, unsigned char *packet, size_t len) { int s; struct sockaddr_in si; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("send_udp(): socket"); return; } /* fatal("send_udp(): sending to port %i\n", portnr); */ si.sin_family = AF_INET; si.sin_addr = *addrp; si.sin_port = htons(portnr); if (sendto(s, packet, len, 0, (struct sockaddr *)&si, sizeof(si)) != (ssize_t)len) { perror("send_udp(): sendto"); } close(s); } gxemul-0.6.1/src/net/README000644 001750 001750 00000003157 13402411502 015470 0ustar00debugdebug000000 000000 Emulated (ethernet / internet) network support. NOTE: This is just an ugly hack, and just barely enough to get some Internet networking up and running for the guest OS. TODO: o) TCP: fin/ack stuff, and connection time-outs and connection refused (reset on connect?), resend data to the guest OS if no ack has arrived for some time (? buffers?) http://www.tcpipguide.com/free/t_TCPConnectionTermination-2.htm o) remove the netbsd-specific options in the tcp header (?) o) Outgoing UDP packet fragment support. o) IPv6 (outgoing, incoming, and the nameserver/gateway) o) Incoming connections (TODO 2: The following comments are old! Fix this.) The emulated NIC has a MAC address of (for example) 10:20:30:00:00:10. From the emulated environment, the only other machine existing on the network is a "gateway" or "firewall", which has an address of 60:50:40:30:20:10. This module (net.c) contains the emulation of that gateway. It works like a NAT firewall, but emulated in userland software. The gateway uses IPv4 address 10.0.0.254, the guest OS (inside the emulator) could use any 10.x.x.x address, except 10.0.0.254. A suitable choice is, for example 10.0.0.1. |------------------ a network --------------------------------| ^ ^ ^ | | | a NIC connected another NIC the gateway to the network | v outside world The gateway isn't connected as a NIC, but is an "implicit" machine on the network. (See http://www.sinclair.org.au/keith/networking/vendor.html for a list of ethernet MAC assignments.) gxemul-0.6.1/src/net/net_ip.cc000644 001750 001750 00000130377 13402411502 016402 0ustar00debugdebug000000 000000 /* * Copyright (C) 2004-2010 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * Internet Protocol related networking stuff. */ #include #include #include #include #include #include #include #include #include #include "misc.h" #include "net.h" /* #define debug fatal */ /* * net_ip_checksum(): * * Fill in an IP header checksum. (This works for ICMP too.) * chksumoffset should be 10 for IP headers, and len = 20. * For ICMP packets, chksumoffset = 2 and len = length of the ICMP packet. */ void net_ip_checksum(unsigned char *ip_header, int chksumoffset, int len) { int i; uint32_t sum = 0; for (i=0; i 65535) { int to_add = sum >> 16; sum = (sum & 0xffff) + to_add; } } sum ^= 0xffff; ip_header[chksumoffset + 0] = sum >> 8; ip_header[chksumoffset + 1] = sum & 0xff; } /* * net_ip_tcp_checksum(): * * Fill in a TCP header checksum. This differs slightly from the IP * checksum. The checksum is calculated on a pseudo header, the actual * TCP header, and the data. This is what the pseudo header looks like: * * uint32_t srcaddr; * uint32_t dstaddr; * uint16_t protocol; (= 6 for tcp) * uint16_t tcp_len; * * tcp_len is length of header PLUS data. The psedo header is created * internally here, and does not need to be supplied by the caller. */ void net_ip_tcp_checksum(unsigned char *tcp_header, int chksumoffset, int tcp_len, unsigned char *srcaddr, unsigned char *dstaddr, int udpflag) { int i, pad = 0; unsigned char pseudoh[12]; uint32_t sum = 0; memcpy(pseudoh + 0, srcaddr, 4); memcpy(pseudoh + 4, dstaddr, 4); pseudoh[8] = 0x00; pseudoh[9] = udpflag? 17 : 6; pseudoh[10] = tcp_len >> 8; pseudoh[11] = tcp_len & 255; for (i=0; i<12; i+=2) { uint16_t w = (pseudoh[i] << 8) + pseudoh[i+1]; sum += w; while (sum > 65535) { int to_add = sum >> 16; sum = (sum & 0xffff) + to_add; } } if (tcp_len & 1) { tcp_len ++; pad = 1; } for (i=0; i 65535) { int to_add = sum >> 16; sum = (sum & 0xffff) + to_add; } } sum ^= 0xffff; tcp_header[chksumoffset + 0] = sum >> 8; tcp_header[chksumoffset + 1] = sum & 0xff; } /* * net_ip_icmp(): * * Handle an ICMP packet. * * The IP header (at offset 14) could look something like * * ver=45 tos=00 len=0054 id=001a ofs=0000 ttl=ff p=01 sum=a87e * src=0a000005 dst=03050607 * * and the ICMP specific data (beginning at offset 34): * * type=08 code=00 chksum=b8bf * 000c0008d5cee94089190c0008090a0b * 0c0d0e0f101112131415161718191a1b * 1c1d1e1f202122232425262728292a2b * 2c2d2e2f3031323334353637 */ static void net_ip_icmp(struct net *net, void *extra, unsigned char *packet, int len) { int type; struct ethernet_packet_link *lp; type = packet[34]; switch (type) { case 8: /* ECHO request */ debug("[ ICMP echo ]\n"); lp = net_allocate_ethernet_packet_link(net, extra, len); /* Copy the old packet first: */ memcpy(lp->data + 12, packet + 12, len - 12); /* Switch to and from ethernet addresses: */ memcpy(lp->data + 0, packet + 6, 6); memcpy(lp->data + 6, packet + 0, 6); /* Switch to and from IP addresses: */ memcpy(lp->data + 26, packet + 30, 4); memcpy(lp->data + 30, packet + 26, 4); /* Change from echo REQUEST to echo REPLY: */ lp->data[34] = 0x00; /* Decrease the TTL to a low value: */ lp->data[22] = 2; /* Recalculate ICMP checksum: */ net_ip_checksum(lp->data + 34, 2, len - 34); /* Recalculate IP header checksum: */ net_ip_checksum(lp->data + 14, 10, 20); break; default: fatal("[ net: ICMP type %i not yet implemented ]\n", type); } } /* * tcp_closeconnection(): * * Helper function which closes down a TCP connection completely. */ static void tcp_closeconnection(struct net *net, int con_id) { close(net->tcp_connections[con_id].socket); net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED; net->tcp_connections[con_id].in_use = 0; net->tcp_connections[con_id].incoming_buf_len = 0; } /* * net_ip_tcp_connectionreply(): * * When changing from state _TRYINGTOCONNECT to _CONNECTED, then this * function should be called with connecting set to 1. * * To send a generic ack reply, set connecting to 0. * * To send data (PSH), set data to non-NULL and datalen to the length. * * This creates an ethernet packet for the guest OS with an ACK to the * initial SYN packet. */ void net_ip_tcp_connectionreply(struct net *net, void *extra, int con_id, int connecting, unsigned char *data, int datalen, int rst) { struct ethernet_packet_link *lp; int tcp_length, ip_len, option_len = 20; if (connecting) net->tcp_connections[con_id].outside_acknr = net->tcp_connections[con_id].inside_seqnr + 1; net->tcp_connections[con_id].tcp_id ++; tcp_length = 20 + option_len + datalen; ip_len = 20 + tcp_length; lp = net_allocate_ethernet_packet_link(net, extra, 14 + ip_len); /* Ethernet header: */ memcpy(lp->data + 0, net->tcp_connections[con_id].ethernet_address, 6); memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); lp->data[12] = 0x08; /* IP = 0x0800 */ lp->data[13] = 0x00; /* IP header: */ lp->data[14] = 0x45; /* ver */ lp->data[15] = 0x10; /* tos */ lp->data[16] = ip_len >> 8; lp->data[17] = ip_len & 0xff; lp->data[18] = net->tcp_connections[con_id].tcp_id >> 8; lp->data[19] = net->tcp_connections[con_id].tcp_id & 0xff; lp->data[20] = 0x40; /* don't fragment */ lp->data[21] = 0x00; lp->data[22] = 0x40; /* ttl */ lp->data[23] = 6; /* p = TCP */ memcpy(lp->data + 26, net->tcp_connections[con_id]. outside_ip_address, 4); memcpy(lp->data + 30, net->tcp_connections[con_id]. inside_ip_address, 4); net_ip_checksum(lp->data + 14, 10, 20); /* TCP header and options at offset 34: */ lp->data[34] = net->tcp_connections[con_id].outside_tcp_port >> 8; lp->data[35] = net->tcp_connections[con_id].outside_tcp_port & 0xff; lp->data[36] = net->tcp_connections[con_id].inside_tcp_port >> 8; lp->data[37] = net->tcp_connections[con_id].inside_tcp_port & 0xff; lp->data[38] = (net->tcp_connections[con_id]. outside_seqnr >> 24) & 0xff; lp->data[39] = (net->tcp_connections[con_id]. outside_seqnr >> 16) & 0xff; lp->data[40] = (net->tcp_connections[con_id]. outside_seqnr >> 8) & 0xff; lp->data[41] = net->tcp_connections[con_id]. outside_seqnr & 0xff; lp->data[42] = (net->tcp_connections[con_id]. outside_acknr >> 24) & 0xff; lp->data[43] = (net->tcp_connections[con_id]. outside_acknr >> 16) & 0xff; lp->data[44] = (net->tcp_connections[con_id]. outside_acknr >> 8) & 0xff; lp->data[45] = net->tcp_connections[con_id].outside_acknr & 0xff; /* Control */ lp->data[46] = (option_len + 20) / 4 * 0x10; lp->data[47] = 0x10; /* ACK */ if (connecting) lp->data[47] |= 0x02; /* SYN */ if (net->tcp_connections[con_id].state == TCP_OUTSIDE_CONNECTED) lp->data[47] |= 0x08; /* PSH */ if (rst) lp->data[47] |= 0x04; /* RST */ if (net->tcp_connections[con_id].state >= TCP_OUTSIDE_DISCONNECTED) lp->data[47] |= 0x01; /* FIN */ /* Window */ lp->data[48] = 0x10; lp->data[49] = 0x00; /* no urgent ptr */ /* options */ /* TODO: HAHA, this is ugly */ lp->data[54] = 0x02; lp->data[55] = 0x04; lp->data[56] = 0x05; lp->data[57] = 0xb4; lp->data[58] = 0x01; lp->data[59] = 0x03; lp->data[60] = 0x03; lp->data[61] = 0x00; lp->data[62] = 0x01; lp->data[63] = 0x01; lp->data[64] = 0x08; lp->data[65] = 0x0a; lp->data[66] = (net->timestamp >> 24) & 0xff; lp->data[67] = (net->timestamp >> 16) & 0xff; lp->data[68] = (net->timestamp >> 8) & 0xff; lp->data[69] = net->timestamp & 0xff; lp->data[70] = (net->tcp_connections[con_id]. inside_timestamp >> 24) & 0xff; lp->data[71] = (net->tcp_connections[con_id]. inside_timestamp >> 16) & 0xff; lp->data[72] = (net->tcp_connections[con_id]. inside_timestamp >> 8) & 0xff; lp->data[73] = net->tcp_connections[con_id]. inside_timestamp & 0xff; /* data: */ if (data != NULL) { memcpy(lp->data + 74, data, datalen); net->tcp_connections[con_id].outside_seqnr += datalen; } /* Checksum: */ net_ip_tcp_checksum(lp->data + 34, 16, tcp_length, lp->data + 26, lp->data + 30, 0); #if 0 { int i; fatal("[ net_ip_tcp_connectionreply(%i): ", connecting); for (i=0; idata[i]); fatal(" ]\n"); } #endif if (connecting) net->tcp_connections[con_id].outside_seqnr ++; } /* * net_ip_tcp(): * * Handle a TCP packet comming from the emulated OS. * * The IP header (at offset 14) could look something like * * ver=45 tos=00 len=003c id=0006 ofs=0000 ttl=40 p=11 sum=b798 * src=0a000001 dst=c1abcdef * * TCP header, at offset 34: * * srcport=fffe dstport=0015 seqnr=af419a1d acknr=00000000 * control=a002 window=4000 checksum=fe58 urgent=0000 * and then "options and padding" and then data. * (020405b4010303000101080a0000000000000000) * * See the following URLs for good descriptions of TCP: * * http://www.networksorcery.com/enp/protocol/tcp.htm * http://www.tcpipguide.com/free/t_TCPIPTransmissionControlProtocolTCP.htm */ static void net_ip_tcp(struct net *net, void *extra, unsigned char *packet, int len) { int con_id, free_con_id, i, res; int srcport, dstport, data_offset, window, checksum, urgptr; int syn, ack, psh, rst, urg, fin; uint32_t seqnr, acknr; struct sockaddr_in remote_ip; fd_set rfds; struct timeval tv; int send_ofs; #if 0 fatal("[ net: TCP: "); for (i=0; i<26; i++) fatal("%02x", packet[i]); fatal(" "); #endif srcport = (packet[34] << 8) + packet[35]; dstport = (packet[36] << 8) + packet[37]; seqnr = (packet[38] << 24) + (packet[39] << 16) + (packet[40] << 8) + packet[41]; acknr = (packet[42] << 24) + (packet[43] << 16) + (packet[44] << 8) + packet[45]; #if 0 fatal("%i.%i.%i.%i:%i -> %i.%i.%i.%i:%i, seqnr=%lli acknr=%lli ", packet[26], packet[27], packet[28], packet[29], srcport, packet[30], packet[31], packet[32], packet[33], dstport, (long long)seqnr, (long long)acknr); #endif data_offset = (packet[46] >> 4) * 4 + 34; /* data_offset is now data offset within packet :-) */ urg = packet[47] & 32; ack = packet[47] & 16; psh = packet[47] & 8; rst = packet[47] & 4; syn = packet[47] & 2; fin = packet[47] & 1; window = (packet[48] << 8) + packet[49]; checksum = (packet[50] << 8) + packet[51]; urgptr = (packet[52] << 8) + packet[53]; #if 0 fatal(urg? "URG " : ""); fatal(ack? "ACK " : ""); fatal(psh? "PSH " : ""); fatal(rst? "RST " : ""); fatal(syn? "SYN " : ""); fatal(fin? "FIN " : ""); fatal("window=0x%04x checksum=0x%04x urgptr=0x%04x ", window, checksum, urgptr); fatal("options="); for (i=34+20; itcp_connections[i].in_use) free_con_id = i; if (net->tcp_connections[i].in_use && net->tcp_connections[i].inside_tcp_port == srcport && net->tcp_connections[i].outside_tcp_port == dstport && memcmp(net->tcp_connections[i].inside_ip_address, packet + 26, 4) == 0 && memcmp(net->tcp_connections[i].outside_ip_address, packet + 30, 4) == 0) { con_id = i; break; } } /* * Unknown connection, and not SYN? Then drop the packet. * TODO: Send back RST? */ if (con_id < 0 && !syn) { debug("[ net: TCP: dropping packet from unknown connection," " %i.%i.%i.%i:%i -> %i.%i.%i.%i:%i %s%s%s%s%s]\n", packet[26], packet[27], packet[28], packet[29], srcport, packet[30], packet[31], packet[32], packet[33], dstport, fin? "FIN ": "", syn? "SYN ": "", ack? "ACK ": "", psh? "PSH ": "", rst? "RST ": ""); return; } /* Known connection, and SYN? Then ignore the packet. */ if (con_id >= 0 && syn) { debug("[ net: TCP: ignoring redundant SYN packet from known" " connection, %i.%i.%i.%i:%i -> %i.%i.%i.%i:%i ]\n", packet[26], packet[27], packet[28], packet[29], srcport, packet[30], packet[31], packet[32], packet[33], dstport); return; } /* * A new outgoing connection? */ if (con_id < 0 && syn) { debug("[ net: TCP: new outgoing connection, %i.%i.%i.%i:%i" " -> %i.%i.%i.%i:%i ]\n", packet[26], packet[27], packet[28], packet[29], srcport, packet[30], packet[31], packet[32], packet[33], dstport); /* Find a free connection id to use: */ if (free_con_id < 0) { #if 1 /* * TODO: Reuse the oldest one currently in use, or * just drop the new connection attempt? Drop for now. */ fatal("[ TOO MANY TCP CONNECTIONS IN USE! " "Increase MAX_TCP_CONNECTIONS! ]\n"); return; #else int i; int64_t oldest = net-> tcp_connections[0].last_used_timestamp; free_con_id = 0; fatal("[ NO FREE TCP SLOTS, REUSING OLDEST ONE ]\n"); for (i=0; itcp_connections[i]. last_used_timestamp < oldest) { oldest = net->tcp_connections[i]. last_used_timestamp; free_con_id = i; } tcp_closeconnection(net, free_con_id); #endif } con_id = free_con_id; memset(&net->tcp_connections[con_id], 0, sizeof(struct tcp_connection)); memcpy(net->tcp_connections[con_id].ethernet_address, packet + 6, 6); memcpy(net->tcp_connections[con_id].inside_ip_address, packet + 26, 4); net->tcp_connections[con_id].inside_tcp_port = srcport; memcpy(net->tcp_connections[con_id].outside_ip_address, packet + 30, 4); net->tcp_connections[con_id].outside_tcp_port = dstport; net->tcp_connections[con_id].socket = socket(AF_INET, SOCK_STREAM, 0); if (net->tcp_connections[con_id].socket < 0) { fatal("[ net: TCP: socket() returned %i ]\n", net->tcp_connections[con_id].socket); return; } debug("[ new tcp outgoing socket=%i ]\n", net->tcp_connections[con_id].socket); net->tcp_connections[con_id].in_use = 1; /* Set the socket to non-blocking: */ res = fcntl(net->tcp_connections[con_id].socket, F_GETFL); fcntl(net->tcp_connections[con_id].socket, F_SETFL, res | O_NONBLOCK); remote_ip.sin_family = AF_INET; memcpy((unsigned char *)&remote_ip.sin_addr, net->tcp_connections[con_id].outside_ip_address, 4); remote_ip.sin_port = htons( net->tcp_connections[con_id].outside_tcp_port); res = connect(net->tcp_connections[con_id].socket, (struct sockaddr *)&remote_ip, sizeof(remote_ip)); /* connect can return -1, and errno = EINPROGRESS as we might not have connected right away. */ net->tcp_connections[con_id].state = TCP_OUTSIDE_TRYINGTOCONNECT; net->tcp_connections[con_id].outside_acknr = 0; net->tcp_connections[con_id].outside_seqnr = ((random() & 0xffff) << 16) + (random() & 0xffff); } if (rst) { debug("[ 'rst': disconnecting TCP connection %i ]\n", con_id); net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 1); tcp_closeconnection(net, con_id); return; } if (ack && net->tcp_connections[con_id].state == TCP_OUTSIDE_DISCONNECTED2) { debug("[ 'ack': guestOS's final termination of TCP " "connection %i ]\n", con_id); /* Send an RST? (TODO, this is wrong...) */ net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 1); /* ... and forget about this connection: */ tcp_closeconnection(net, con_id); return; } if (fin && net->tcp_connections[con_id].state == TCP_OUTSIDE_DISCONNECTED) { debug("[ 'fin': response to outside's disconnection of " "TCP connection %i ]\n", con_id); /* Send an ACK: */ net->tcp_connections[con_id].state = TCP_OUTSIDE_CONNECTED; net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0); net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED2; return; } if (fin) { debug("[ 'fin': guestOS disconnecting TCP connection %i ]\n", con_id); /* Send ACK: */ net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0); net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED2; /* Return and send FIN: */ goto ret; } if (ack) { debug("ACK %i bytes, inside_acknr=%u outside_seqnr=%u\n", net->tcp_connections[con_id].incoming_buf_len, net->tcp_connections[con_id].inside_acknr, net->tcp_connections[con_id].outside_seqnr); net->tcp_connections[con_id].inside_acknr = acknr; if (net->tcp_connections[con_id].inside_acknr == net->tcp_connections[con_id].outside_seqnr && net->tcp_connections[con_id].incoming_buf_len != 0) { debug(" all acked\n"); net->tcp_connections[con_id].incoming_buf_len = 0; } } net->tcp_connections[con_id].inside_seqnr = seqnr; /* TODO: This is hardcoded for a specific NetBSD packet: */ if (packet[34 + 30] == 0x08 && packet[34 + 31] == 0x0a) net->tcp_connections[con_id].inside_timestamp = (packet[34 + 32 + 0] << 24) + (packet[34 + 32 + 1] << 16) + (packet[34 + 32 + 2] << 8) + (packet[34 + 32 + 3] << 0); net->timestamp ++; net->tcp_connections[con_id].last_used_timestamp = net->timestamp; if (net->tcp_connections[con_id].state != TCP_OUTSIDE_CONNECTED) { debug("[ not connected to outside ]\n"); return; } if (data_offset >= len) return; /* * We are here if this is a known connection, and data is to be * transmitted to the outside world. */ send_ofs = data_offset; send_ofs += ((int32_t)net->tcp_connections[con_id].outside_acknr - (int32_t)seqnr); #if 1 debug("[ %i bytes of tcp data to be sent, beginning at seqnr %u, ", len - data_offset, seqnr); debug("outside is at acknr %u ==> %i actual bytes to be sent ]\n", net->tcp_connections[con_id].outside_acknr, len - send_ofs); #endif /* Drop outgoing packet if the guest OS' seqnr is not the same as we have acked. (We have missed something, perhaps.) */ if (seqnr != net->tcp_connections[con_id].outside_acknr) { debug("!! outgoing TCP packet dropped (seqnr = %u, " "outside_acknr = %u)\n", seqnr, net->tcp_connections[con_id].outside_acknr); goto ret; } if (len - send_ofs > 0) { /* Is the socket available for output? */ FD_ZERO(&rfds); /* write */ FD_SET(net->tcp_connections[con_id].socket, &rfds); tv.tv_sec = tv.tv_usec = 0; errno = 0; res = select(net->tcp_connections[con_id].socket+1, NULL, &rfds, NULL, &tv); if (res < 1) { net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED; debug("[ TCP: disconnect on select for writing ]\n"); goto ret; } res = write(net->tcp_connections[con_id].socket, packet + send_ofs, len - send_ofs); if (res > 0) { net->tcp_connections[con_id].outside_acknr += res; } else if (errno == EAGAIN) { /* Just ignore this attempt. */ return; } else { debug("[ error writing %i bytes to TCP connection %i:" " errno = %i ]\n", len - send_ofs, con_id, errno); net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED; debug("[ TCP: disconnect on write() ]\n"); goto ret; } } ret: /* Send an ACK (or FIN) to the guest OS: */ net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0); } /* * net_ip_udp(): * * Handle a UDP packet. * * (See http://www.networksorcery.com/enp/protocol/udp.htm.) * * The IP header (at offset 14) could look something like * * ver=45 tos=00 len=003c id=0006 ofs=0000 ttl=40 p=11 sum=b798 * src=0a000001 dst=c1abcdef * * and the UDP data (beginning at offset 34): * * srcport=fffc dstport=0035 length=0028 chksum=76b6 * 43e20100000100000000000003667470066e6574627364036f726700001c0001 */ static void net_ip_udp(struct net *net, void *extra, unsigned char *packet, int len) { int con_id, free_con_id, i, srcport, dstport, udp_len; ssize_t res; struct sockaddr_in remote_ip; if ((packet[20] & 0x3f) != 0) { fatal("[ net_ip_udp(): WARNING! fragmented UDP " "packet, TODO ]\n"); return; } srcport = (packet[34] << 8) + packet[35]; dstport = (packet[36] << 8) + packet[37]; udp_len = (packet[38] << 8) + packet[39]; /* chksum at offset 40 and 41 */ debug("[ net: UDP: "); debug("srcport=%i dstport=%i len=%i ", srcport, dstport, udp_len); for (i=42; i= ' ' && packet[i] < 127) debug("%c", packet[i]); else debug("[%02x]", packet[i]); } debug(" ]\n"); /* Is this "connection" new, or a currently ongoing one? */ con_id = free_con_id = -1; for (i=0; iudp_connections[i].in_use) free_con_id = i; if (net->udp_connections[i].in_use && net->udp_connections[i].inside_udp_port == srcport && net->udp_connections[i].outside_udp_port == dstport && memcmp(net->udp_connections[i].inside_ip_address, packet + 26, 4) == 0 && memcmp(net->udp_connections[i].outside_ip_address, packet + 30, 4) == 0) { con_id = i; break; } } debug("&& UDP connection is "); if (con_id >= 0) debug("ONGOING"); else { debug("NEW"); if (free_con_id < 0) { int64_t oldest = net-> udp_connections[0].last_used_timestamp; free_con_id = 0; debug(", NO FREE SLOTS, REUSING OLDEST ONE"); for (int j=0; judp_connections[j].last_used_timestamp < oldest) { oldest = net->udp_connections[j].last_used_timestamp; free_con_id = j; } close(net->udp_connections[free_con_id].socket); } con_id = free_con_id; memset(&net->udp_connections[con_id], 0, sizeof(struct udp_connection)); memcpy(net->udp_connections[con_id].ethernet_address, packet + 6, 6); memcpy(net->udp_connections[con_id].inside_ip_address, packet + 26, 4); net->udp_connections[con_id].inside_udp_port = srcport; memcpy(net->udp_connections[con_id].outside_ip_address, packet + 30, 4); net->udp_connections[con_id].outside_udp_port = dstport; net->udp_connections[con_id].socket = socket(AF_INET, SOCK_DGRAM, 0); if (net->udp_connections[con_id].socket < 0) { fatal("[ net: UDP: socket() returned %i ]\n", net->udp_connections[con_id].socket); return; } debug(" {socket=%i}", net->udp_connections[con_id].socket); net->udp_connections[con_id].in_use = 1; /* Set the socket to non-blocking: */ res = fcntl(net->udp_connections[con_id].socket, F_GETFL); fcntl(net->udp_connections[con_id].socket, F_SETFL, res | O_NONBLOCK); } debug(", connection id %i\n", con_id); net->timestamp ++; net->udp_connections[con_id].last_used_timestamp = net->timestamp; remote_ip.sin_family = AF_INET; memcpy((unsigned char *)&remote_ip.sin_addr, net->udp_connections[con_id].outside_ip_address, 4); /* * Special case for the nameserver: If a UDP packet is sent to * the gateway, it will be forwarded to the nameserver, if it is * known. */ if (net->nameserver_known && memcmp(net->udp_connections[con_id].outside_ip_address, &net->gateway_ipv4_addr[0], 4) == 0) { memcpy((unsigned char *)&remote_ip.sin_addr, &net->nameserver_ipv4, 4); net->udp_connections[con_id].fake_ns = 1; } remote_ip.sin_port = htons( net->udp_connections[con_id].outside_udp_port); res = sendto(net->udp_connections[con_id].socket, packet + 42, len - 42, 0, (const struct sockaddr *)&remote_ip, sizeof(remote_ip)); if (res != len-42) debug("[ net: UDP: unable to send %i bytes ]\n", len-42); else debug("[ net: UDP: OK!!! ]\n"); } /* * net_ip(): * * Handle an IP packet, coming from the emulated NIC. */ void net_ip(struct net *net, void *extra, unsigned char *packet, int len) { #if 1 int i; debug("[ net: IP: "); debug("ver=%02x ", packet[14]); debug("tos=%02x ", packet[15]); debug("len=%02x%02x ", packet[16], packet[17]); debug("id=%02x%02x ", packet[18], packet[19]); debug("ofs=%02x%02x ", packet[20], packet[21]); debug("ttl=%02x ", packet[22]); debug("p=%02x ", packet[23]); debug("sum=%02x%02x ", packet[24], packet[25]); debug("src=%02x%02x%02x%02x ", packet[26], packet[27], packet[28], packet[29]); debug("dst=%02x%02x%02x%02x ", packet[30], packet[31], packet[32], packet[33]); for (i=34; i 14 + packet[16]*256 + packet[17]) len = 14 + packet[16]*256 + packet[17]; if (packet[14] == 0x45) { /* IPv4: */ switch (packet[23]) { case 1: /* ICMP */ net_ip_icmp(net, extra, packet, len); break; case 6: /* TCP */ net_ip_tcp(net, extra, packet, len); break; case 17:/* UDP */ net_ip_udp(net, extra, packet, len); break; default: fatal("[ net: IP: UNIMPLEMENTED protocol %i ]\n", packet[23]); } } else fatal("[ net: IP: UNIMPLEMENTED ip, first byte = 0x%02x ]\n", packet[14]); } /* * net_ip_broadcast_dhcp(): * * Handle an IPv4 DHCP broadcast packet, coming from the emulated NIC. * * Read http://tools.ietf.org/html/rfc2131 for details on DHCP. * (And http://users.telenet.be/mydotcom/library/network/dhcp.htm.) */ static void net_ip_broadcast_dhcp(struct net *net, void *extra, unsigned char *packet, int len) { /* * TODO */ #if 1 struct ethernet_packet_link *lp; int i, reply_len; fatal("[ net: IPv4 DHCP: "); #if 1 fatal("ver=%02x ", packet[14]); fatal("tos=%02x ", packet[15]); fatal("len=%02x%02x ", packet[16], packet[17]); fatal("id=%02x%02x ", packet[18], packet[19]); fatal("ofs=%02x%02x ", packet[20], packet[21]); fatal("ttl=%02x ", packet[22]); fatal("p=%02x ", packet[23]); fatal("sum=%02x%02x ", packet[24], packet[25]); #endif fatal("src=%02x%02x%02x%02x ", packet[26], packet[27], packet[28], packet[29]); fatal("dst=%02x%02x%02x%02x ", packet[30], packet[31], packet[32], packet[33]); #if 0 for (i=34; idata, packet, 278); /* We are sending to the client, from the gateway: */ memcpy(lp->data + 0, packet + 6, 6); memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); /* Set IP length: */ lp->data[16] = (reply_len - 14) >> 8; lp->data[17] = (reply_len - 14) & 0xff; /* Set IP addresses: */ memcpy(lp->data + 26, &net->gateway_ipv4_addr[0], 4); lp->data[30] = 0xff; lp->data[31] = 0xff; lp->data[32] = 0xff; lp->data[33] = 0xff; /* Switch src and dst ports: */ memcpy(lp->data + 34, packet + 36, 2); memcpy(lp->data + 36, packet + 34, 2); /* Set UDP length: */ lp->data[38] = (reply_len - 34) >> 8; lp->data[39] = (reply_len - 34) & 0xff; /* Client's (yiaddr) IPv4 address: */ lp->data[58] = 10; lp->data[59] = 0; lp->data[60] = 0; lp->data[61] = 1; /* Server's IPv4 address: (giaddr) */ memcpy(lp->data + 66, &net->gateway_ipv4_addr[0], 4); /* This is a Reply: */ lp->data[42] = 0x02; snprintf((char *)lp->data + 70+16+64, 8, "gxemul"); /* Options field at offset 278: */ lp->data[278] = 99; lp->data[279] = 130; lp->data[280] = 83; lp->data[281] = 99; /* DHCP options, http://tools.ietf.org/html/rfc1533 */ lp->data[282] = 1; /* subnet mask */ lp->data[283] = 4; lp->data[284] = 255; lp->data[285] = 0; lp->data[286] = 0; lp->data[287] = 0; lp->data[288] = 3; /* router */ lp->data[289] = 4; memcpy(lp->data + 290, &net->gateway_ipv4_addr[0], 4); lp->data[294] = 6; /* domain name server */ lp->data[295] = 4; memcpy(lp->data + 296, &net->gateway_ipv4_addr[0], 4); lp->data[300] = 54; /* server identifier */ lp->data[301] = 4; memcpy(lp->data + 302, &net->gateway_ipv4_addr[0], 4); lp->data[306] = 255; /* end */ /* Recalculate IP header checksum: */ net_ip_checksum(lp->data + 14, 10, 20); /* ... and the UDP checksum: */ net_ip_tcp_checksum(lp->data + 34, 6, reply_len - 34, lp->data + 26, lp->data + 30, 1); /* Debug dump: */ packet = lp->data; fatal("[ net: IPv4 DHCP REPLY: "); for (i=0; i<14; i++) fatal("%02x", packet[i]); fatal("ver=%02x ", packet[14]); fatal("tos=%02x ", packet[15]); fatal("len=%02x%02x ", packet[16], packet[17]); fatal("id=%02x%02x ", packet[18], packet[19]); fatal("ofs=%02x%02x ", packet[20], packet[21]); fatal("ttl=%02x ", packet[22]); fatal("p=%02x ", packet[23]); fatal("sum=%02x%02x ", packet[24], packet[25]); fatal("src=%02x%02x%02x%02x ", packet[26], packet[27], packet[28], packet[29]); fatal("dst=%02x%02x%02x%02x ", packet[30], packet[31], packet[32], packet[33]); fatal("op=%02x ", packet[42]); fatal("htype=%02x ", packet[43]); fatal("hlen=%02x ", packet[44]); fatal("hops=%02x ", packet[45]); fatal("xid=%02x%02x%02x%02x ", packet[46], packet[47], packet[48], packet[49]); fatal("secs=%02x%02x ", packet[50], packet[51]); fatal("flags=%02x%02x ", packet[52], packet[53]); fatal("ciaddr=%02x%02x%02x%02x ", packet[54], packet[55], packet[56], packet[57]); fatal("yiaddr=%02x%02x%02x%02x ", packet[58], packet[59], packet[60], packet[61]); fatal("siaddr=%02x%02x%02x%02x ", packet[62], packet[63], packet[64], packet[65]); fatal("giaddr=%02x%02x%02x%02x ", packet[66], packet[67], packet[68], packet[69]); fatal("chaddr="); for (i=70; i<70+16; i++) fatal("%02x", packet[i]); fatal(" ]\n"); #endif } /* * net_ip_broadcast(): * * Handle an IP broadcast packet, coming from the emulated NIC. * (This is usually a DHCP request, or similar.) */ void net_ip_broadcast(struct net *net, void *extra, unsigned char *packet, int len) { unsigned char *p = (unsigned char *) &net->netmask_ipv4; uint32_t x, y; int i, xl, warning = 0, match = 0; #if 0 fatal("[ net: IP BROADCAST: "); fatal("ver=%02x ", packet[14]); fatal("tos=%02x ", packet[15]); fatal("len=%02x%02x ", packet[16], packet[17]); fatal("id=%02x%02x ", packet[18], packet[19]); fatal("ofs=%02x%02x ", packet[20], packet[21]); fatal("ttl=%02x ", packet[22]); fatal("p=%02x ", packet[23]); fatal("sum=%02x%02x ", packet[24], packet[25]); fatal("src=%02x%02x%02x%02x ", packet[26], packet[27], packet[28], packet[29]); fatal("dst=%02x%02x%02x%02x ", packet[30], packet[31], packet[32], packet[33]); for (i=34; inetmask_ipv4_len; x |= (1 << xl) - 1; /* x = 10.255.255.255 */ if (x == y) match = 1; if (y == 0xffffffff) match = 1; if (warning) fatal("[ net_ip_broadcast(): warning: broadcast to " "0x%08x, expecting broadcast to 0x%08x or " "0xffffffff ]\n", y, x); /* Cut off overflowing tail data: */ if (len > 14 + packet[16]*256 + packet[17]) len = 14 + packet[16]*256 + packet[17]; /* Check for known packets: */ if (packet[14] == 0x45 && /* IPv4 */ packet[23] == 0x11 && /* UDP */ packet[34] == 0 && packet[35] == 68 && /* DHCP client */ packet[36] == 0 && packet[37] == 67) { /* DHCP server */ net_ip_broadcast_dhcp(net, extra, packet, len); return; } /* Unknown packet: */ fatal("[ net: UNIMPLEMENTED IP BROADCAST: "); fatal("ver=%02x ", packet[14]); fatal("tos=%02x ", packet[15]); fatal("len=%02x%02x ", packet[16], packet[17]); fatal("id=%02x%02x ", packet[18], packet[19]); fatal("ofs=%02x%02x ", packet[20], packet[21]); fatal("ttl=%02x ", packet[22]); fatal("p=%02x ", packet[23]); fatal("sum=%02x%02x ", packet[24], packet[25]); fatal("src=%02x%02x%02x%02x ", packet[26], packet[27], packet[28], packet[29]); fatal("dst=%02x%02x%02x%02x ", packet[30], packet[31], packet[32], packet[33]); for (i=34; i max_packets_this_tick) break; if (!net->udp_connections[con_id].in_use) continue; if (net->udp_connections[con_id].socket < 0) { fatal("INTERNAL ERROR in net.c, udp socket < 0 " "but in use?\n"); continue; } res = recvfrom(net->udp_connections[con_id].socket, buf, sizeof(buf), 0, (struct sockaddr *)&from, &from_len); /* No more incoming UDP on this connection? */ if (res < 0) continue; net->timestamp ++; net->udp_connections[con_id].last_used_timestamp = net->timestamp; net->udp_connections[con_id].udp_id ++; /* * Special case for the nameserver: If a UDP packet is * received from the nameserver (if the nameserver's IP is * known), fake it so that it comes from the gateway instead. */ if (net->udp_connections[con_id].fake_ns) memcpy(((unsigned char *)(&from))+4, &net->gateway_ipv4_addr[0], 4); /* * We now have a UDP packet of size 'res' which we need * turn into one or more ethernet packets for the emulated * operating system. Ethernet packets are at most 1518 * bytes long. With some margin, that means we can have * about 1500 bytes per packet. * * Ethernet = 14 bytes * IP = 20 bytes * (UDP = 8 bytes + data) * * So data can be at most max_per_packet - 34. For UDP * fragments, each multiple should (?) be a multiple of * 8 bytes, except the last which doesn't have any such * restriction. */ max_per_packet = 1500; /* UDP: */ udp_len = res + 8; /* from[2..3] = outside_udp_port */ udp_data[0] = ((unsigned char *)&from)[2]; udp_data[1] = ((unsigned char *)&from)[3]; udp_data[2] = (net->udp_connections[con_id]. inside_udp_port >> 8) & 0xff; udp_data[3] = net->udp_connections[con_id]. inside_udp_port & 0xff; udp_data[4] = udp_len >> 8; udp_data[5] = udp_len & 0xff; udp_data[6] = 0; udp_data[7] = 0; memcpy(udp_data + 8, buf, res); /* * TODO: UDP checksum, if necessary. At least NetBSD * and OpenBSD accept UDP packets with 0x0000 in the * checksum field anyway. */ while (bytes_converted < udp_len) { this_packets_data_length = udp_len - bytes_converted; /* Do we need to fragment? */ if (this_packets_data_length > max_per_packet-34) { this_packets_data_length = max_per_packet - 34; while (this_packets_data_length & 7) this_packets_data_length --; } ip_len = 20 + this_packets_data_length; lp = net_allocate_ethernet_packet_link(net, extra, 14 + 20 + this_packets_data_length); /* Ethernet header: */ memcpy(lp->data + 0, net->udp_connections[con_id]. ethernet_address, 6); memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); lp->data[12] = 0x08; /* IP = 0x0800 */ lp->data[13] = 0x00; /* IP header: */ lp->data[14] = 0x45; /* ver */ lp->data[15] = 0x00; /* tos */ lp->data[16] = ip_len >> 8; lp->data[17] = ip_len & 0xff; lp->data[18] = net->udp_connections[con_id].udp_id >> 8; lp->data[19] = net->udp_connections[con_id].udp_id & 0xff; lp->data[20] = (fragment_ofs >> 8); if (bytes_converted + this_packets_data_length < udp_len) lp->data[20] |= 0x20; /* More fragments */ lp->data[21] = fragment_ofs & 0xff; lp->data[22] = 0x40; /* ttl */ lp->data[23] = 17; /* p = UDP */ lp->data[26] = ((unsigned char *)&from)[4]; lp->data[27] = ((unsigned char *)&from)[5]; lp->data[28] = ((unsigned char *)&from)[6]; lp->data[29] = ((unsigned char *)&from)[7]; memcpy(lp->data + 30, net->udp_connections[con_id]. inside_ip_address, 4); net_ip_checksum(lp->data + 14, 10, 20); memcpy(lp->data+34, udp_data + bytes_converted, this_packets_data_length); bytes_converted += this_packets_data_length; fragment_ofs = bytes_converted / 8; received_packets_this_tick ++; } /* This makes sure we check this connection AGAIN for more incoming UDP packets, before moving to the next connection: */ con_id --; } } /* * net_tcp_rx_avail(): * * Receive any available TCP packets (from the outside world). */ void net_tcp_rx_avail(struct net *net, void *extra) { int received_packets_this_tick = 0; int max_packets_this_tick = 200; int con_id; for (con_id=0; con_id max_packets_this_tick) break; if (!net->tcp_connections[con_id].in_use) continue; if (net->tcp_connections[con_id].socket < 0) { fatal("INTERNAL ERROR in net.c, tcp socket < 0" " but in use?\n"); continue; } if (net->tcp_connections[con_id].incoming_buf == NULL) CHECK_ALLOCATION(net->tcp_connections[con_id]. incoming_buf = (unsigned char *) malloc(TCP_INCOMING_BUF_LEN)); if (net->tcp_connections[con_id].state >= TCP_OUTSIDE_DISCONNECTED) continue; /* Is the socket available for output? */ FD_ZERO(&rfds); /* write */ FD_SET(net->tcp_connections[con_id].socket, &rfds); tv.tv_sec = tv.tv_usec = 0; errno = 0; res = select(net->tcp_connections[con_id].socket+1, NULL, &rfds, NULL, &tv); if (errno == ECONNREFUSED) { fatal("[ ECONNREFUSED: TODO ]\n"); net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED; fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED " "(refused connection)\n"); continue; } if (errno == ETIMEDOUT) { fatal("[ ETIMEDOUT: TODO ]\n"); /* TODO */ net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED; fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED " "(timeout)\n"); continue; } if (net->tcp_connections[con_id].state == TCP_OUTSIDE_TRYINGTOCONNECT && res > 0) { net->tcp_connections[con_id].state = TCP_OUTSIDE_CONNECTED; debug("CHANGING TO TCP_OUTSIDE_CONNECTED\n"); net_ip_tcp_connectionreply(net, extra, con_id, 1, NULL, 0, 0); } if (net->tcp_connections[con_id].state == TCP_OUTSIDE_CONNECTED && res < 1) { continue; } /* * Does this connection have unacknowledged data? Then, if * enough number of rounds have passed, try to resend it using * the old value of seqnr. */ if (net->tcp_connections[con_id].incoming_buf_len != 0) { net->tcp_connections[con_id].incoming_buf_rounds ++; if (net->tcp_connections[con_id].incoming_buf_rounds > 10000) { debug(" at seqnr %u but backing back to %u," " resending %i bytes\n", net->tcp_connections[con_id].outside_seqnr, net->tcp_connections[con_id]. incoming_buf_seqnr, net->tcp_connections[con_id]. incoming_buf_len); net->tcp_connections[con_id]. incoming_buf_rounds = 0; net->tcp_connections[con_id].outside_seqnr = net->tcp_connections[con_id]. incoming_buf_seqnr; net_ip_tcp_connectionreply(net, extra, con_id, 0, net->tcp_connections[con_id]. incoming_buf, net->tcp_connections[con_id]. incoming_buf_len, 0); } continue; } /* Don't receive unless the guest OS is ready! */ if (((int32_t)net->tcp_connections[con_id].outside_seqnr - (int32_t)net->tcp_connections[con_id].inside_acknr) > 0) { /* fatal("YOYO 1! outside_seqnr - inside_acknr = %i\n", net->tcp_connections[con_id].outside_seqnr - net->tcp_connections[con_id].inside_acknr); */ continue; } /* Is there incoming data available on the socket? */ FD_ZERO(&rfds); /* read */ FD_SET(net->tcp_connections[con_id].socket, &rfds); tv.tv_sec = tv.tv_usec = 0; res2 = select(net->tcp_connections[con_id].socket+1, &rfds, NULL, NULL, &tv); /* No more incoming TCP data on this connection? */ if (res2 < 1) continue; res = read(net->tcp_connections[con_id].socket, buf, 1400); if (res > 0) { /* debug("\n -{- %lli -}-\n", (long long)res); */ net->tcp_connections[con_id].incoming_buf_len = res; net->tcp_connections[con_id].incoming_buf_rounds = 0; net->tcp_connections[con_id].incoming_buf_seqnr = net->tcp_connections[con_id].outside_seqnr; debug(" putting %i bytes (seqnr %u) in the incoming " "buf\n", res, net->tcp_connections[con_id]. incoming_buf_seqnr); memcpy(net->tcp_connections[con_id].incoming_buf, buf, res); net_ip_tcp_connectionreply(net, extra, con_id, 0, buf, res, 0); } else if (res == 0) { net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED; debug("CHANGING TO TCP_OUTSIDE_DISCONNECTED, read" " res=0\n"); net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0); } else { net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED; fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED, " "read res<=0, errno = %i\n", errno); net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0); } net->timestamp ++; net->tcp_connections[con_id].last_used_timestamp = net->timestamp; } } gxemul-0.6.1/test/test_openbsd_mvme88k_install.expect000755 001750 001750 00000002360 13402411502 023220 0ustar00debugdebug000000 000000 #!/usr/local/bin/expect set timeout 4000 spawn ./gxemul -e mvme187old -q -d obsd_mvme88k.img -d b:../../emul/m88k/openbsd_mvme88k_4.5.iso -j 4.5/mvme88k/bsd.rd set send_slow {1 .5} expect "(I)nstall" send -s "i\r" expect "Terminal type" send -s "xterm\r" expect "Proceed with install" send -s "yes\r" expect "Which one is the root disk" send -s "sd0\r" expect "Initial label editor" send -s "d a\ra a\r63\r3500000\r4.2BSD\r/\rd b\ra b\r\r\rswap\rw\rq\r" expect "Are you really sure that" send -s "yes\r" expect "System hostname" send -s "autotest\r" expect "Configure the network" send -s "no\r" expect "Password for root account" send -s "123456\r" expect "again" send -s "123456\r" expect "Location of sets" send -s "disk\r" expect "Is the disk partition already mounted" send -s "!mount -t cd9660 /dev/cd0c /mnt2\r" expect "Is the disk partition already mounted" send -s "yes\r" expect "Pathname to the sets" send -s "/mnt2/4.5/mvme88k\r" expect "Set name" send -s "done\r" expect "Ready to install sets" send -s "\r" expect "Location of sets" send -s "done\r" expect "sshd" send -s "\r" expect "ntpd" send -s "\r" expect "timezone" send -s "Europe/Stockholm\r" expect "reset the machine and boot from the disk" send -s "umount /mnt\r" expect "# " close gxemul-0.6.1/test/test_openbsd_landisk_install.expect000755 001750 001750 00000002412 13402411502 023344 0ustar00debugdebug000000 000000 #!/usr/local/bin/expect set timeout 4000 spawn ./gxemul -E landisk -q -d obsd_landisk.img -d bd:../../emul/sh/openbsd_landisk_4.5.iso -j 4.5/landisk/bsd.rd set send_slow {1 .5} expect "(I)nstall" send -s "i\r" expect "vt220" send -s "xterm\r" expect "Proceed with install" send -s "yes\r" expect "Which one is the root disk" send -s "wd0\r" expect "of wd0 for OpenBSD" send -s "yes\r" expect "Initial label editor" send -s "d a\ra a\r63\r3500000\r4.2BSD\r/\ra b\r\r\rswap\rw\rq\r" expect "Available disks are: wd1" send -s "done\r" expect "Are you really sure that" send -s "yes\r" expect "System hostname" send -s "autotest\r" expect "Configure the network" send -s "no\r" expect "Password for root account" send -s "123456\r" expect "again" send -s "123456\r" expect "Location of sets" send -s "disk\r" expect "Is the disk partition already mounted" send -s "no\r" expect "Which one contains the install media" send -s "wd1\r" expect "Pathname to the sets" send -s "\r" expect "Set name" send -s "done\r" expect "Ready to install sets" send -s "yes\r" expect "Location of sets" send -s "done\r" expect "sshd" send -s "\r" expect "ntpd" send -s "\r" expect "timezone" send -s "Europe/Stockholm\r" expect "reset the machine and boot from the disk" send -s "sync\r" expect "# " close gxemul-0.6.1/test/test_openbsd_landisk_install.sh000755 001750 001750 00000000533 13402411502 022470 0ustar00debugdebug000000 000000 #!/bin/sh # # Regression test -- automated install of OpenBSD/landisk # Start with: # # test/test_openbsd_landisk_install.sh # rm -f obsd_landisk.img dd if=/dev/zero of=obsd_landisk.img bs=1024 count=1 seek=1900000 sync sleep 2 time test/test_openbsd_landisk_install.expect 2> /tmp/gxemul_result echo echo echo echo cat /tmp/gxemul_result gxemul-0.6.1/test/FileLoader_NonsenseFile000644 001750 001750 00000000031 13402411502 020577 0ustar00debugdebug000000 000000 This is a nonsense file. gxemul-0.6.1/test/FileLoader_ELF_MIPS000755 001750 001750 00000013644 13402411502 017466 0ustar00debugdebug000000 000000 ELF44 ( ĀĀ @kp! Kh!y`! P&K #AH8!0!(#'* $!8`!#eP#X@d@! 9H@"0!(!$<! !&1&(!@@0! @q * !$ '('<<($, 4v4U @! +x!!H+#Qx&qPH!h!#Qh& m`!8#`& l@! 0#@&(!#p&)#!@#QT! P#:g0#@#r8*BH! q0#h B@(!!#if8#`@(#!@@1P!&X!%Q< ! !&R&(!  0! @r*`@N @!<$ !`$!$`$$oL(0.symtab.strtab.shstrtab.text.reginfo.data.sdata.sbss.bss.pdr.mdebug.abi32!p@*07=BGddU  LX@    !L+-13:FMRx1.ca.0b.1x2.crandom_fdatarectanglef_gpg_ftext__bss_start_edata_end_fbssgxemul-0.6.1/test/test_netbsd_arc_install.expect000755 001750 001750 00000002154 13402411502 022314 0ustar00debugdebug000000 000000 #!/usr/local/bin/expect set timeout 4000 spawn ./gxemul -e pica -q -d nbsd_arc.img -d bc:../../emul/mips/arccd-5.0.iso ../../emul/mips/netbsd-arc-5.0-RAMDISK.gz expect "Terminal type" send "vt100\r" expect "(I)nstall" send "i\r" expect "a: Install NetBSD to" send "\r" expect "b: Yes" send "b\r" expect "Hit enter to continue" send "\r" expect "a: Full installation" send "\r" expect "sectors" send "\r" expect "heads" send "\r" expect "b: Use the entire disk" send "b\r" expect "a: Set sizes of NetBSD partitions" send "\r" expect "Accept partition sizes" send " \r" expect "x: Partition sizes ok" send "\r" expect "Please enter a name for" send "\r" expect "b: Yes" send "b\r" expect "a: Progress bar" send "\r" expect "a: CD-ROM" send "\r" expect "x: Continue" send "x\r" expect "Hit enter to continue" send "\r" expect "Hit enter to continue" send "\r" expect "Press 'x' followed by RETURN to quit" send "x\r" expect "a: DES" send "\r" expect "b: No" send "b\r" expect "a: /bin/sh" send "\r" expect "Hit enter to continue" send "\r" expect "Hit enter to continue" send "\r" expect "d: Reboot the computer" send "d\r" close gxemul-0.6.1/test/test_openbsd_mvme88k_install.sh000755 001750 001750 00000000625 13402411502 022344 0ustar00debugdebug000000 000000 #!/bin/sh # # A small test to measure how long time it takes (real time) to install # OpenBSD/mvme88k 4.5, without interaction. # # Start with: # # test/test_openbsd_mvme88k_install.sh # rm -f obsd_mvme88k.img dd if=/dev/zero of=obsd_mvme88k.img bs=1024 count=1 seek=1900000 sync sleep 2 time test/test_openbsd_mvme88k_install.expect 2> /tmp/gxemul_result echo echo echo echo cat /tmp/gxemul_result gxemul-0.6.1/test/check_delete_calls.sh000755 001750 001750 00000000717 13402411502 020325 0ustar00debugdebug000000 000000 #!/bin/sh rm -f tmp_delete.out LC_ALL=C grep -R "delete " src|grep -v \\.svn|cut -d \: -f 1|sort|uniq |grep -v "inary file" > tmp_delete.out 2> /dev/null ANYERRORS=0 for a in `cat tmp_delete.out`; do # Is $a a known exception? if grep -q $a test/check_delete_calls.exceptions; then : else printf "\nError: $a is not in check_delete_calls.exceptions!" ANYERRORS=1 fi done rm -f tmp_delete.out if [ z$ANYERRORS = z1 ]; then printf "\n\n" false fi gxemul-0.6.1/test/FileLoader_ELF_SH5000755 001750 001750 00000005427 13402411502 017315 0ustar00debugdebug000000 000000 ELF*@ @8@ Lp```L`p`0  kJ0( ~ p `DDuDeDU  Ь 9YA ad700 p0 0zpJpZ`kfP80p H(  80(8 o 000@g0`DQ Ԡ0 (d*p !kPk`kFpkJ DooDuDeDUnpkfPkf`31" 35"$$  ЬoDQ (DQ (DQ (DQ (DQ pp08p8`30$P2$@spc`r b 0Pp@`xph`$P0$@00ZPJ @pp``(`0 @PDa Dq >OkJ )`pg 30pp (`0``dD!o$ޭޭGCC: (GNU) 4.0.1GCC: (GNU) 4.0.1.symtab.strtab.shstrtab.text.data.ctors.dtors.sbss.bss.comment.stack@ !'.5;@$IP      @`)`1:FS\(_fkrx1.c_b.1154_a.1153x2.c_g_rectangle_random___dtors__bss_start___ctors_end___ctors_f_edata_end_stack___dtors_endgxemul-0.6.1/test/floatingpoint/000755 001750 001750 00000000000 13402411502 017061 5ustar00debugdebug000000 000000 gxemul-0.6.1/test/test_netbsd_pmax_install.expect000755 001750 001750 00000001675 13402411502 022523 0ustar00debugdebug000000 000000 #!/usr/local/bin/expect set timeout 4000 spawn ./gxemul -e3max -q -d nbsd_pmax.img -d bc:../../emul/mips/pmaxcd-5.1.1.iso expect "Terminal type" send "vt100\r" expect " in English" send "\r" expect "a: Install NetBSD to" send "\r" expect "b: Yes" send "b\r" expect "Hit enter to continue" send "\r" expect "a: Full installation" send "\r" expect "a: Set sizes of NetBSD partitions" send "\r" expect "Accept partition sizes" send " \r" expect "x: Partition sizes ok" send "\r" expect "Please enter a name for" send "\r" expect "b: Yes" send "b\r" expect "a: Progress bar" send "\r" expect "a: CD-ROM" send "\r" expect "x: Continue" send "x\r" expect "Hit enter to continue" send "\r" expect "Hit enter to continue" send "\r" expect "Press 'x' followed by RETURN to quit" send "x\r" expect "a: DES" send "\r" expect "b: No" send "b\r" expect "a: /bin/sh" send "\r" expect "Hit enter to continue" send "\r" expect "d: Reboot the computer" send "d\r" close gxemul-0.6.1/test/FileLoader_B.OUT_i960000755 001750 001750 00000000633 13402411502 017620 0ustar00debugdebug000000 000000 @@0 \\\00  0'068D8S@Z@`@e@s @~ @} _testfunc.texttestfunc.lf_etext___CTOR_LIST_____CTOR_END_____DTOR_LIST___edata.data.bss___DTOR_END___bss_start_endx.cgxemul-0.6.1/test/test_netbsd_arc_install.sh000755 001750 001750 00000000454 13402411502 021437 0ustar00debugdebug000000 000000 #!/bin/sh # # Regression test: Automated install of NetBSD/arc 5.0. Start using: # # test/test_netbsd_arc_install.sh # rm -f nbsd_arc.img dd if=/dev/zero of=nbsd_arc.img bs=1024 count=1 seek=1000000 time test/test_netbsd_arc_install.expect 2> /tmp/gxemul_result echo echo cat /tmp/gxemul_result gxemul-0.6.1/test/FileLoader_A.OUT_M88K000644 001750 001750 00000024432 13402411502 017617 0ustar00debugdebug000000 000000  g$c Xd$?`,`B X)dc?cg0' c #X"X& X|ԭ$?$dao8 `: ]9` :9` @X`XXc|ܭc9 `g ?$  c0g$c] $? \G m(3cmBP ")`)d%' ?cg$c] $?c@$ ?cg$c] Y)$?c@$ ?cg 'c'? X$?X@@Xg?? c g 'c'? X$?X@@Xg?? c g 'c'? X$?X@@Xg?? c g 'c'? $? X@XX@g?? c g 'cX@ X`X$?# Xi m d XiXmXd Xi m {d XiXmXv9d X@X`XXXId!p$oh "P50ETcnPp     d  E^|׀4FYqՀD ,D!<$ @@@D)xD&D)D+D,D)D0&$h9@?@E@K@Q@V@[H\] b D7 D9$D8(D7,D80D9@D:Ph$u& z& @0D?\$P@DE$@DJDKDL$@DQDRDS$@DX@DYDDZP$0@D_D`DaDb$p@ @DiDmDlL($._f_draw_rectangle_my_memset_fbctrl_write_port_fbctrl_command_fbctrl_set_x1_fbctrl_set_y1_my_random_fbctrl_write_data_etext_change_resolution_edata_endrectangles_m88k_O2.ogcc2_compiled.___gnu_compiled_crectangles.cint:t1=r1;-2147483648;2147483647;char:t2=r2;0;127;long int:t3=r3;-2147483648;2147483647;unsigned int:t4=r4;0;-1;long unsigned int:t5=r5;0;-1;long long int:t6=r6;0;-1;long long unsigned int:t7=r7;0;-1;short int:t8=r8;-32768;32767;short unsigned int:t9=r9;0;65535;signed char:t10=r10;-128;127;unsigned char:t11=r11;0;255;float:t12=r1;4;0;double:t13=r1;8;0;long double:t14=r1;8;0;complex int:t15=s8real:1,0,32;imag:1,32,32;;complex float:t16=r16;4;0;complex double:t17=r17;8;0;complex long double:t18=r18;8;0;void:t19=19my_memset:F19a:P20=*11x:P1len:P1draw_rectangle:F19x1:P1y1:P1x2:P1y2:P1c:P1y:r1_a.9_b.10my_random:F4a:V1b:V1c:r1fbctrl_write_port:F19p:P1fbctrl_write_data:F19d:P1fbctrl_set_x1:F19v:P1fbctrl_set_y1:F19v:P1fbctrl_command:F19c:P1change_resolution:F19xres:P1yres:P1f:F19gxemul-0.6.1/test/test_netbsd_pmax_install.r4400.expect000755 001750 001750 00000001706 13402411502 023266 0ustar00debugdebug000000 000000 #!/usr/local/bin/expect set timeout 4000 spawn ./gxemul -e3max -C R4400 -q -d nbsd_pmax.img -d bc:../../emul/mips/pmaxcd-5.1.1.iso expect "Terminal type" send "vt100\r" expect " in English" send "\r" expect "a: Install NetBSD to" send "\r" expect "b: Yes" send "b\r" expect "Hit enter to continue" send "\r" expect "a: Full installation" send "\r" expect "a: Set sizes of NetBSD partitions" send "\r" expect "Accept partition sizes" send " \r" expect "x: Partition sizes ok" send "\r" expect "Please enter a name for" send "\r" expect "b: Yes" send "b\r" expect "a: Progress bar" send "\r" expect "a: CD-ROM" send "\r" expect "x: Continue" send "x\r" expect "Hit enter to continue" send "\r" expect "Hit enter to continue" send "\r" expect "Press 'x' followed by RETURN to quit" send "x\r" expect "a: DES" send "\r" expect "b: No" send "b\r" expect "a: /bin/sh" send "\r" expect "Hit enter to continue" send "\r" expect "d: Reboot the computer" send "d\r" close gxemul-0.6.1/test/FileLoader_ELF_MIPS16000755 001750 001750 00000027373 13402411502 017641 0ustar00debugdebug000000 000000 ELF4#P$ 4 (pppppVakjJ`La ec! ga J3D]32i3Hi3DM WygXe gH*lgf,JÀKaMaN`! cgpn3PMp e=Finʲڀ eڀ ek`ڀ ek`ڀ ek`ڀ eojۀ@j۠@ eMNm jܠ@j@@J@j@۠g\PFGejGe GeJ @c!eeegg3gHMgLYgg*724Q2_2pighiN3ggJNgLY024 Q2C2pighiN20)meka 2 Hgm| 32i3HiKleS 2 Hgm| h2t3|i3HiKQ2e*32i3HgiI3DMgigiSgxeg, ng,LgijMaOaJainN=FQ$`GCC: (GNU) 4.3.2p my_memset7draw_rectanglemy_randomfbctrl_write_portfbctrl_write_data fbctrl_set_x1Wfbctrl_set_y1fbctrl_commandchange_resolutionf<pQaQx^len^Wintm>}p=^DdC^)JvI^s MQvP^s XcW^ s [_| 7^^ ^^OGs g_s  ss  4 c7^ p & x1%^y1%^x2%^y2%^c%^ y'^ len'^ E<3%m73T<UEVt =[yU%S],/(!S|u8meHmsT}Xm ThmWTeKA}LɀxmTeɀR}πSmTeY}Zm!T,U`L}L:e0KPaepRp}  SbeY} ZfgpSi+`!eK}L+5ace+/RM}/5S5Sbe59Y}9SZ|_em_e|eomeo3|mF|(m,Ha|mSzhmtkbYPW%9E,/(!% .? : ; ' : ; I I$ > $ >  1  : ; I .? : ; I  4: ; I 4 .1@@ 1 .1@@141 411X Y 411X Y 1UX Y 1UX Y .? : ; ' @@  U# rectangles.c-/Il1+JM$v-/I .݃-/KKylRrlJklJd4z.lz.Pz.4.\4z.4zJ4z.PzfP"P6JJ6JJ6XJ<qf.q..hv-KI .+ |  [BF u#      #SxDrectangles.cunsigned intfbctrl_commandfbctrl_set_x1xres/tmp/u/apa3-0.42fbctrl_set_y1change_resolutionfbctrl_write_portmy_memsetunsigned charmy_randomdraw_rectangleyresfbctrl_write_dataGNU C 4.3.2 -gmtOT]tT_UgtUEVgtV'W'k`ktWS$S]a]t$RUmUp_VR5VEpVoS_UR 7UEpUS_uU/pUu       ')!#!)+#'susuuwuw/p/p.symtab.strtab.shstrtab.text.reginfo.sdata.comment.debug_aranges.debug_pubnames.debug_info.debug_abbrev.debug_line.debug_frame.debug_str.debug_loc.mdebug.abiO64.gcc_compiled_long32.pdr.debug_rangesp!p@t*pp1:p IpYp~ep-MspzpHp0p@p "t&pP ,{@p     R!\(t.p5;AHNU\cjpw~  ƀ΀րހ***.. 444%4-858=RERMRU^]^edmdud}dnn8Dŀp̀T΀$`\  +2t>t$HWt^tc utrectangles.c$LFB2$LFB3$LBB68$LBE68$LFB4a.1282$LFB5$LFB6$LBB70$LFB7$LBB72$LBE70$LBE72$LBB74$LFB8$LBB76$LBE74$LBE76$LBB78$LFB9$LBB80$LBE78$LBE80$LFB10$LBB102$LBE102$LBB113$LBE113$LBB120$LBB118$LFB11$LBB136$LBB134$LBE120$LBB138$LBE136$LBB142$LBB140$LBE134$LBE138$LBB144$LBE142$LBE118$LBE140$LBE144$LBB147$LBB146$LBB149$LBB148$LBE146$LBE147$LBE148$LBE149$LBB159$LBB158$LBE158$LBE159$LBB164$LBE164_fdatafchange_resolution_gpfbctrl_set_x1draw_rectanglemy_memsetfbctrl_write_datafbctrl_set_y1_ftext__bss_startmy_randomfbctrl_command_edata_endfbctrl_write_port_fbssgxemul-0.6.1/test/test_netbsd_pmax_install.r4400.sh000755 001750 001750 00000000535 13402411502 022407 0ustar00debugdebug000000 000000 #!/bin/sh # # Regression test: Automated install of NetBSD/pmax using R4400 cpu. # Start using: # # test/test_netbsd_pmax_install.r4400.sh # rm -f nbsd_pmax.img dd if=/dev/zero of=nbsd_pmax.img bs=1024 count=1 seek=1900000 sync sleep 2 time test/test_netbsd_pmax_install.r4400.expect 2> /tmp/gxemul_result echo echo echo cat /tmp/gxemul_result gxemul-0.6.1/test/check_delete_calls.exceptions000644 001750 001750 00000000415 13402411502 022064 0ustar00debugdebug000000 000000 ./HISTORY ./src/debugger/debugger.cc ./src/debugger/debugger_cmds.cc ./src/include/refcount_ptr.h ./src/include/thirdparty/debug_new.h ./src/include/thirdparty/fast_mutex.h ./src/include/thirdparty/static_assert.h ./src/main/debug_new.cc ./src/main/ComponentFactory.cc gxemul-0.6.1/test/test_netbsd_pmax_install.sh000755 001750 001750 00000000762 13402411502 021641 0ustar00debugdebug000000 000000 #!/bin/sh # # Regression test: Automated install of NetBSD/pmax using R3000 CPU. # # 1. Place the iso here: # # ../../emul/mips/pmaxcd-5.1.1.iso # # (update test_netbsd_pmax_install.*expect when changing version) # # 2. Start the regression test with: # # test/test_netbsd_pmax_install.sh # rm -f nbsd_pmax.img dd if=/dev/zero of=nbsd_pmax.img bs=1024 count=1 seek=1900000 sync sleep 2 time test/test_netbsd_pmax_install.expect 2> /tmp/gxemul_result echo echo echo cat /tmp/gxemul_result gxemul-0.6.1/test/floatingpoint/fptest.c000644 001750 001750 00000023430 13402411502 020534 0ustar00debugdebug000000 000000 /* * GXemul floating point tests. * * This file is in the Public Domain. */ #ifdef HOSTNATIVE #include #include #else #include "dev_cons.h" #endif #ifdef MIPS /* Note: The ugly cast to a signed int (32-bit) causes the address to be sign-extended correctly on MIPS when compiled in 64-bit mode */ #define PHYSADDR_OFFSET ((signed int)0xa0000000) #else #define PHYSADDR_OFFSET 0 #endif #define PUTCHAR_ADDRESS (PHYSADDR_OFFSET + \ DEV_CONS_ADDRESS + DEV_CONS_PUTGETCHAR) #define HALT_ADDRESS (PHYSADDR_OFFSET + \ DEV_CONS_ADDRESS + DEV_CONS_HALT) #include "fpconst.h" void printchar(char ch) { #ifdef HOSTNATIVE printf("%c", ch); #else *((volatile unsigned char *) PUTCHAR_ADDRESS) = ch; #endif } void halt(void) { #ifdef HOSTNATIVE exit(0); #else *((volatile unsigned char *) HALT_ADDRESS) = 0; #endif } void str(char *s) { while (*s) printchar(*s++); } void print_hex(unsigned long long value, int bits) { unsigned long long head = value >> 4; unsigned long long tail = value & 15; char hexchar[16] = "0123456789abcdef"; if (bits > 4) print_hex(head, bits - 4); printchar(hexchar[tail]); } void print_float(void* value) { unsigned int v = *(unsigned int *) value; print_hex(v, 32); } void print_double(void* value) { unsigned long long v = *(unsigned long long *) value; print_hex(v, 64); } #ifdef HOSTNATIVE int main(int argc, char* argv[]) #else int f(void) #endif { str("GXemul floating point tests\n\n"); str("constant 0.0:\t"); { float f; f = f_0_0(); print_float(&f); str("\t"); } { double d; d = d_0_0(); print_double(&d); str("\n"); } str("constant -0.0:\t"); { float f; f = f_m0_0(); print_float(&f); str("\t"); } { double d; d = d_m0_0(); print_double(&d); str("\n"); } str("constant 0.17:\t"); { float f; f = f_0_17(); print_float(&f); str("\t"); } { double d; d = d_0_17(); print_double(&d); str("\n"); } str("constant -0.17:\t"); { float f; f = f_m0_17(); print_float(&f); str("\t"); } { double d; d = d_m0_17(); print_double(&d); str("\n"); } str("constant 1.0:\t"); { float f; f = f_1_0(); print_float(&f); str("\t"); } { double d; d = d_1_0(); print_double(&d); str("\n"); } str("constant -1.0:\t"); { float f; f = f_m1_0(); print_float(&f); str("\t"); } { double d; d = d_m1_0(); print_double(&d); str("\n"); } str("constant 1.7:\t"); { float f; f = f_1_7(); print_float(&f); str("\t"); } { double d; d = d_1_7(); print_double(&d); str("\n"); } str("constant -1.7:\t"); { float f; f = f_m1_7(); print_float(&f); str("\t"); } { double d; d = d_m1_7(); print_double(&d); str("\n"); } str("constant 42:\t"); { float f; f = f_42(); print_float(&f); str("\t"); } { double d; d = d_42(); print_double(&d); str("\n"); } str("constant -42:\t"); { float f; f = f_m42(); print_float(&f); str("\t"); } { double d; d = d_m42(); print_double(&d); str("\n"); } str("constant inf:\t"); { float f; f = f_inf(); print_float(&f); str("\t"); } { double d; d = d_inf(); print_double(&d); str("\n"); } str("constant -inf:\t"); { float f; f = f_m_inf(); print_float(&f); str("\t"); } { double d; d = d_m_inf(); print_double(&d); str("\n"); } str("constant nan:\t"); { float f; f = f_nan(); print_float(&f); str("\t"); } { double d; d = d_nan(); print_double(&d); str("\n"); } str("constant nan_x:\t"); { float f; f = f_nan_x(); print_float(&f); str("\t"); } { double d; d = d_nan_x(); print_double(&d); str("\n"); } // TODO: Denormalized subnormal values // TODO: Min/max values? str("\n"); str("0.0 + 0.0:\t"); { float x1, x2, x; x1 = f_0_0(); x2 = f_0_0(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_0_0(); x2 = d_0_0(); x = x1 + x2; print_double(&x); str("\n"); } str("0.0 + -0.0:\t"); { float x1, x2, x; x1 = f_0_0(); x2 = f_m0_0(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_0_0(); x2 = d_m0_0(); x = x1 + x2; print_double(&x); str("\n"); } str("-0.0 + 0.0:\t"); { float x1, x2, x; x1 = f_m0_0(); x2 = f_0_0(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_m0_0(); x2 = d_0_0(); x = x1 + x2; print_double(&x); str("\n"); } str("0.0 + 1.0:\t"); { float x1, x2, x; x1 = f_0_0(); x2 = f_1_0(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_0_0(); x2 = d_1_0(); x = x1 + x2; print_double(&x); str("\n"); } str("0.0 + -1.0:\t"); { float x1, x2, x; x1 = f_0_0(); x2 = f_m1_0(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_0_0(); x2 = d_m1_0(); x = x1 + x2; print_double(&x); str("\n"); } str("1.0 + 0.0:\t"); { float x1, x2, x; x1 = f_1_0(); x2 = f_0_0(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_1_0(); x2 = d_0_0(); x = x1 + x2; print_double(&x); str("\n"); } str("1.0 + 1.0:\t"); { float x1, x2, x; x1 = f_1_0(); x2 = f_1_0(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_1_0(); x2 = d_1_0(); x = x1 + x2; print_double(&x); str("\n"); } str("1.0 + -1.0:\t"); { float x1, x2, x; x1 = f_1_0(); x2 = f_m1_0(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_1_0(); x2 = d_m1_0(); x = x1 + x2; print_double(&x); str("\n"); } str("0.0 + 1.7:\t"); { float x1, x2, x; x1 = f_0_0(); x2 = f_1_7(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_0_0(); x2 = d_1_7(); x = x1 + x2; print_double(&x); str("\n"); } str("1.7 + 0.0:\t"); { float x1, x2, x; x1 = f_1_7(); x2 = f_0_0(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_1_7(); x2 = d_0_0(); x = x1 + x2; print_double(&x); str("\n"); } str("42 + 0.0:\t"); { float x1, x2, x; x1 = f_42(); x2 = f_0_0(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_42(); x2 = d_0_0(); x = x1 + x2; print_double(&x); str("\n"); } str("42 + 42:\t"); { float x1, x2, x; x1 = f_42(); x2 = f_42(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_42(); x2 = d_42(); x = x1 + x2; print_double(&x); str("\n"); } str("-42 + 42:\t"); { float x1, x2, x; x1 = f_m42(); x2 = f_42(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_m42(); x2 = d_42(); x = x1 + x2; print_double(&x); str("\n"); } str("0.0 + inf:\t"); { float x1, x2, x; x1 = f_0_0(); x2 = f_inf(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_0_0(); x2 = d_inf(); x = x1 + x2; print_double(&x); str("\n"); } str("0.0 + -inf:\t"); { float x1, x2, x; x1 = f_0_0(); x2 = f_m_inf(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_0_0(); x2 = d_m_inf(); x = x1 + x2; print_double(&x); str("\n"); } str("inf + inf:\t"); { float x1, x2, x; x1 = f_inf(); x2 = f_inf(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_inf(); x2 = d_inf(); x = x1 + x2; print_double(&x); str("\n"); } str("inf + -inf:\t"); { float x1, x2, x; x1 = f_inf(); x2 = f_m_inf(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_inf(); x2 = d_m_inf(); x = x1 + x2; print_double(&x); str("\n"); } str("-inf + -inf:\t"); { float x1, x2, x; x1 = f_m_inf(); x2 = f_m_inf(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_m_inf(); x2 = d_m_inf(); x = x1 + x2; print_double(&x); str("\n"); } str("inf + 1.7:\t"); { float x1, x2, x; x1 = f_inf(); x2 = f_1_7(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_inf(); x2 = d_1_7(); x = x1 + x2; print_double(&x); str("\n"); } str("inf + nan:\t"); { float x1, x2, x; x1 = f_inf(); x2 = f_nan(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_inf(); x2 = d_nan(); x = x1 + x2; print_double(&x); str("\n"); } str("nan + 0.0:\t"); { float x1, x2, x; x1 = f_nan(); x2 = f_0_0(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_nan(); x2 = d_0_0(); x = x1 + x2; print_double(&x); str("\n"); } str("nan_x + 0.0:\t"); { float x1, x2, x; x1 = f_nan_x(); x2 = f_0_0(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_nan_x(); x2 = d_0_0(); x = x1 + x2; print_double(&x); str("\n"); } str("nan + 1.7:\t"); { float x1, x2, x; x1 = f_nan(); x2 = f_1_7(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_nan(); x2 = d_1_7(); x = x1 + x2; print_double(&x); str("\n"); } str("nan_x + 1.7:\t"); { float x1, x2, x; x1 = f_nan_x(); x2 = f_1_7(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_nan_x(); x2 = d_1_7(); x = x1 + x2; print_double(&x); str("\n"); } str("nan + nan_x:\t"); { float x1, x2, x; x1 = f_nan(); x2 = f_nan_x(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_nan(); x2 = d_nan_x(); x = x1 + x2; print_double(&x); str("\n"); } str("nan_x + nan:\t"); { float x1, x2, x; x1 = f_nan_x(); x2 = f_nan(); x = x1 + x2; print_float(&x); str("\t"); } { double x1, x2, x; x1 = d_nan_x(); x2 = d_nan(); x = x1 + x2; print_double(&x); str("\n"); } // TODO: - * / // TODO: == < > <= >= // TODO: sqrt sin cos etc... str("\n"); halt(); return 0; } gxemul-0.6.1/test/floatingpoint/fpconst.c000644 001750 001750 00000003572 13402411502 020710 0ustar00debugdebug000000 000000 /* * GXemul floating point tests. * * This file is in the Public Domain. */ // Regenerate fpconst.h like this: // grep void\) fpconst.c | while read a; do echo $a";"; done > fpconst.h #include "fpconst.h" float f_0_0(void) { return 0.0; } double d_0_0(void) { return 0.0; } float f_m0_0(void) { return -0.0; } double d_m0_0(void) { return -0.0; } float f_0_17(void) { return 0.17; } double d_0_17(void) { return 0.17; } float f_m0_17(void) { return -0.17; } double d_m0_17(void) { return -0.17; } float f_1_0(void) { return 1.0; } double d_1_0(void) { return 1.0; } float f_m1_0(void) { return -1.0; } double d_m1_0(void) { return -1.0; } float f_1_7(void) { return 1.7; } double d_1_7(void) { return 1.7; } float f_m1_7(void) { return -1.7; } double d_m1_7(void) { return -1.7; } float f_42(void) { return 42; } double d_42(void) { return 42; } float f_m42(void) { return -42; } double d_m42(void) { return -42; } float f_nan(void) { unsigned int v = 0x7fffffff; void *p = &v; float *pf = (float*) p; return *pf; } double d_nan(void) { unsigned long long v = 0x7fffffffffffffffULL; void *p = &v; double *pd = (double*) p; return *pd; } float f_nan_x(void) { unsigned int v = 0x7fc01234; void *p = &v; float *pf = (float*) p; return *pf; } double d_nan_x(void) { unsigned long long v = 0x7ff8000000001234ULL; void *p = &v; double *pd = (double*) p; return *pd; } float f_inf(void) { unsigned int v = 0x7f800000; void *p = &v; float *pf = (float*) p; return *pf; } double d_inf(void) { unsigned long long v = 0x7ff0000000000000ULL; void *p = &v; double *pd = (double*) p; return *pd; } float f_m_inf(void) { unsigned int v = 0xff800000; void *p = &v; float *pf = (float*) p; return *pf; } double d_m_inf(void) { unsigned long long v = 0xfff0000000000000ULL; void *p = &v; double *pd = (double*) p; return *pd; } gxemul-0.6.1/test/floatingpoint/Makefile000644 001750 001750 00000000627 13402411502 020526 0ustar00debugdebug000000 000000 CFLAGS=-DHOSTNATIVE -I../../src/include/testmachine all: @echo Read the README file for instructions on how to build @echo the floatingpoint test program for various targets. @echo To build for the host, type \"make native\" native: fptest.o fpconst.o $(CC) fptest.o fpconst.o -o fptest ./fptest > fptest_hostnative.output cat fptest_hostnative.output clean: rm -f *.o fptest fptest.output *core gxemul-0.6.1/test/floatingpoint/README000644 001750 001750 00000003034 13402411502 017741 0ustar00debugdebug000000 000000 ARM --- arm-unknown-elf-gcc -I../../src/include/testmachine -g fptest.c -O2 -c -mhard-float arm-unknown-elf-gcc -I../../src/include/testmachine -g fpconst.c -O2 -c -mhard-float arm-unknown-elf-ld -e f fptest.o fpconst.o -o fptest file fptest ../../gxemul -E testarm fptest > fptest.output diff fptest_hostnative.output fptest.output MIPS (64-bit) ------------- mips64-unknown-elf-gcc -DMIPS -I../../src/include/testmachine -g fptest.c -O0 -mips4 -mabi=64 -c -G 0 mips64-unknown-elf-gcc -DMIPS -I../../src/include/testmachine -g fpconst.c -O0 -mips4 -mabi=64 -c -G 0 mips64-unknown-elf-ld -Ttext 0xa800000000030000 -e f fptest.o fpconst.o -o fptest --oformat=elf64-bigmips file fptest ../../gxemul -qE oldtestmips fptest > fptest.output diff fptest_hostnative.output fptest.output MIPS (32-bit) ------------- mips64-unknown-elf-gcc -DMIPS -I../../src/include/testmachine -g fptest.c -O0 -mips1 -mabi=32 -c -G 0 mips64-unknown-elf-gcc -DMIPS -I../../src/include/testmachine -g fpconst.c -O0 -mips1 -mabi=32 -c -G 0 mips64-unknown-elf-ld -Ttext 0x80030000 -e f fptest.o fpconst.o -o fptest file fptest ../../gxemul -C 4Kc -qE oldtestmips fptest > fptest.output diff fptest_hostnative.output fptest.output SH -- sh4-unknown-elf-gcc -I../../src/include/testmachine -O2 -g fptest.c -c sh4-unknown-elf-gcc -I../../src/include/testmachine -O2 -g fpconst.c -c sh4-unknown-elf-ld -e _f fptest.o fpconst.o -o fptest file fptest ../../gxemul -E testsh fptest > fptest.output diff fptest_hostnative.output fptest.output // TODO: undefined reference to `__fpscr_values' gxemul-0.6.1/test/floatingpoint/fpconst.h000644 001750 001750 00000001064 13402411502 020707 0ustar00debugdebug000000 000000 float f_0_0(void); double d_0_0(void); float f_m0_0(void); double d_m0_0(void); float f_0_17(void); double d_0_17(void); float f_m0_17(void); double d_m0_17(void); float f_1_0(void); double d_1_0(void); float f_m1_0(void); double d_m1_0(void); float f_1_7(void); double d_1_7(void); float f_m1_7(void); double d_m1_7(void); float f_42(void); double d_42(void); float f_m42(void); double d_m42(void); float f_nan(void); double d_nan(void); float f_nan_x(void); double d_nan_x(void); float f_inf(void); double d_inf(void); float f_m_inf(void); double d_m_inf(void); gxemul-0.6.1/test/floatingpoint/fptest_hostnative.output000644 001750 001750 00000003045 13402411502 024116 0ustar00debugdebug000000 000000 GXemul floating point tests constant 0.0: 00000000 0000000000000000 constant -0.0: 80000000 8000000000000000 constant 0.17: 3e2e147b 3fc5c28f5c28f5c3 constant -0.17: be2e147b bfc5c28f5c28f5c3 constant 1.0: 3f800000 3ff0000000000000 constant -1.0: bf800000 bff0000000000000 constant 1.7: 3fd9999a 3ffb333333333333 constant -1.7: bfd9999a bffb333333333333 constant 42: 42280000 4045000000000000 constant -42: c2280000 c045000000000000 constant inf: 7f800000 7ff0000000000000 constant -inf: ff800000 fff0000000000000 constant nan: 7fffffff 7fffffffffffffff constant nan_x: 7fc01234 7ff8000000001234 0.0 + 0.0: 00000000 0000000000000000 0.0 + -0.0: 00000000 0000000000000000 -0.0 + 0.0: 00000000 0000000000000000 0.0 + 1.0: 3f800000 3ff0000000000000 0.0 + -1.0: bf800000 bff0000000000000 1.0 + 0.0: 3f800000 3ff0000000000000 1.0 + 1.0: 40000000 4000000000000000 1.0 + -1.0: 00000000 0000000000000000 0.0 + 1.7: 3fd9999a 3ffb333333333333 1.7 + 0.0: 3fd9999a 3ffb333333333333 42 + 0.0: 42280000 4045000000000000 42 + 42: 42a80000 4055000000000000 -42 + 42: 00000000 0000000000000000 0.0 + inf: 7f800000 7ff0000000000000 0.0 + -inf: ff800000 fff0000000000000 inf + inf: 7f800000 7ff0000000000000 inf + -inf: ffc00000 fff8000000000000 -inf + -inf: ff800000 fff0000000000000 inf + 1.7: 7f800000 7ff0000000000000 inf + nan: 7fffffff 7fffffffffffffff nan + 0.0: 7fffffff 7fffffffffffffff nan_x + 0.0: 7fc01234 7ff8000000001234 nan + 1.7: 7fffffff 7fffffffffffffff nan_x + 1.7: 7fc01234 7ff8000000001234 nan + nan_x: 7fffffff 7fffffffffffffff nan_x + nan: 7fc01234 7ff8000000001234 gxemul-0.6.1/man/gxemul.1000644 001750 001750 00000050202 13402411502 015362 0ustar00debugdebug000000 000000 .\" .\" Copyright (C) 2004-2018 Anders Gavare. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions are met: .\" .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" .\" This is the man page for GXemul. Process this file with .\" .\" groff -man -Tascii gxemul.1 or nroff -man gxemul.1 .\" .Dd NOVEMBER 2018 .Dt GXEMUL 1 .Os .Sh NAME .Nm gxemul .Nd an experimental framework for full-system machine emulation .Sh SYNOPSIS .Nm .Op options .Fl e .Ar name .Op additional components and files Ar ... .Nm .Op options .Ar configfile .Nm .Fl V .Nm .Fl H .Sh SYNOPSIS (OLD FRAMEWORK) .Nm .Op machine, other, and general options .Op file Ar ... .Nm .Op general options .Ar @configfile .Sh DESCRIPTION .Nm is a framework for full-system computer architecture emulation. Several processor architectures and machine types have been implemented. It is working well enough to allow unmodified "guest" operating systems (e.g. NetBSD) to run inside the emulator, as if they were running on real hardware. .Pp The emulator emulates (networks of) real machines. The machines may consist of ARM, MIPS, Motorola 88K, PowerPC, and SuperH processors, and various surrounding hardware components such as framebuffers, busses, interrupt controllers, ethernet controllers, disk controllers, and serial port controllers. .Pp Note: Only very few emulated machine modes have been rewritten to use the new emulation framework introduced in version 0.6.x, so there are two different ways to use the emulator. (Most emulation modes and machines are only valid in the old framework.) .Pp The options available for the new framework are: .Pp .Bl -tag -width Ds .It Fl B Enables snapshotting (required for reverse execution/stepping). .It Fl e Ar name Start with a machine based on template 'name'. The name may be followed by optional arguments in parentheses, e.g. .Pp .Dl "gxemul -V -e 'testmips(cpu=R4400)'" .Pp Remember to use quotes if your shell gives special meaning to parentheses. .It Fl H Display a list of available machine templates. .It Fl q Start up in Quiet mode (i.e. suppress debug messages). If an error occurs during emulation which stops execution and drops the user into the debugger, quiet mode is turned off. .It Fl V Start up in interactive mode, paused. If this option is used, .Fl q is ignored. .El .Pp When using the .Fl e option, the remainder of the command line consists of zero or more additional files to load, or components to add to the emulation setup. Including these on the command line is equivalent to using the 'add' command (although with a different syntax) in the interactive debugger. A simple example is a file name to load into the emulated machine, but they can be more complex as well. See the Adding Additional Components on the Command Line section below for more details. .Pp When not using the .Fl e option, the config file should be one that was previously saved from within the emulator using the 'save' command. .Pp Starting the emulator with the .Fl V switch will bring you to the interactive debugger environment, without starting the emulation. .Sh ADDING ADDITIONAL COMPONENTS ON THE COMMAND LINE The general syntax is: .Pp .Dl "existing_component_path:component(args)" .Pp If existing_component_path part is omitted, it is assumed to be cpu0. The component(args) part may be written as just args, in which case the name of the component is autodetected, and the args is given as an argument called "name" to that component. .Pp .Nm For example, if the additional component/filename is just .Pp .Dl "netbsd-GENERIC" .Pp this will be equivalent to .Pp .Dl "cpu0:file(name=netbsd-GENERIC)" .Pp An attempt will be made to load the file netbsd-GENERIC into cpu0, which is the default component if none is specified. This will most likely be expanded into root.machine0.mainbus0.cpu0. If cpu0 is ambiguous, then this will not work; the specific cpu0 name must be supplied instead, like this: .Pp .Dl "machine3.mainbus0.cpu0:netbsd-GENERIC" .Pp Another example, using an SDL display component to show the contents of an emulated video framebuffer: .Pp .Dl "fb_videoram0:sdl()" .Pp Here, the existing component name (the framebuffer) and the component to add (the SDL display component) are included, but no arguments. .Sh RUNNING GUEST OPERATING SYSTEMS Please read the HTML documentation for more details on how to run complete guest operating systems in the emulator. .Sh DESCRIPTION (OLD FRAMEWORK) The emulator can be invoked in the following ways: .Pp 1. When emulating a complete machine, configuration options can be supplied directly on the command line. .Pp 2. Options can be read from a configuration file. .Pp The easiest way to use the emulator is to supply settings directly on the command line. .Pp The most important thing you need to supply is the file argument. This is the name of a binary file (an ELF, a.out, COFF/ECOFF, SREC, or a raw binary image) which you wish to run in the emulator. This file might be an operating system kernel, or perhaps a ROM image file. If more than one filename is supplied, all files are loaded into memory, and the entry point (if available) is taken from the last file. .Pp Apart from the name of a binary file, you must also use the .Fl E and/or .Fl e options to select which emulation mode to use. This is necessary because the emulator cannot in general deduce this from the file being executed. For example, a MIPS-based machine from DEC (a DECstation) is very different from a MIPS-based machine from SGI. Use .Nm .Fl H to get a list of available emulation modes. .Pp There are three exceptions to the normal invocation usage mentioned above. .Pp 1. For DECstation emulation, if you have a bootable DECstation harddisk or CDROM image, then just supplying the diskimage via the .Fl d option is sufficient. The filename of the kernel can then be skipped, as the emulator runs the bootblocks from the diskimage directly and doesn't need the kernel as a separate file. .Pp 2. If you supply an ISO9660 CDROM disk image, then using the .Fl j option to indicate a file on the CDROM filesystem to load is sufficient; no additional kernel filename needs to be supplied on the command line. .Pp 3. For Dreamcast emulation, when booting e.g. a NetBSD/dreamcast CDROM image, it is enough to supply the disk image (with the correct ISO partition start offset). Bootblocks will be read directly from the CDROM image, and there is no need to supply the name of an external kernel on the command line. .Pp Gzipped kernels are automatically unzipped, by calling the external gunzip program, both when specifying a gzipped file directly on the command line and when loading such a file using the .Fl j option. .Pp Machine selection options: .Bl -tag -width Ds .It Fl E Ar t Try to emulate machine type .Ar "t". This option is not always needed, if the .Fl e option uniquely selects a machine. (Use .Fl H to get a list of types.) .It Fl e Ar st Try to emulate machine subtype .Ar "st". Use this together with .Fl E . (This option is not always needed, if a machine type has no subtypes.) .El .Pp Other options: .Bl -tag -width Ds .It Fl C Ar x Try to emulate a specific CPU type, .Ar "x". This overrides the default CPU type for the machine being emulated. (Use .Fl H to get a list of available CPU types.) .It Fl d Ar [modifiers:]filename Add .Ar filename as a disk image. By adding one or more modifier characters and then a colon (":") as a prefix to .Ar filename, you can modify the way the disk image is treated. Available modifiers are: .Bl -tag -width Ds .It b Specifies that this is a boot device. .It c CD-ROM. .It d DISK (this is the default). .It f FLOPPY. .It gH;S; Override the default geometry; use H heads and S sectors-per-track. (The number of cylinders is calculated automatically.) .It i IDE. (This is the default for most machine types.) .It oOFS; Set the base offset for an ISO9660 filesystem on a disk image. The default is 0. A suitable offset when booting from Dreamcast ISO9660 filesystem images, which are offset by 11702 sectors, is 23965696. .It r Read-only (don't allow changes to be written to the file). .It s SCSI. .It t Tape. .It V Add an overlay filename to an already defined disk image. (A ID number must also be specified when this flag is used. See the documentation for an example of how to use overlays.) .It 0-7 Force a specific ID number. .El .Pp For SCSI devices, the ID number is the SCSI ID. For IDE harddisks, the ID number has the following meaning: .Bl -tag -width Ds .It 0 Primary master. .It 1 Primary slave. .It 2 Secondary master. .It 3 Secondary slave. .El .Pp Unless otherwise specified, filenames ending with ".iso" or ".cdr" are assumed to be CDROM images. Most others are assumed to be disks. Depending on which machine is being emulated, the default for disks can be either SCSI or IDE. Some disk images that are very small are assumed to be floppy disks. (If you are not happy with the way a disk image is detected, then you need to use explicit prefixes to force a specific type.) .Pp For floppies, the gH;S; prefix is ignored. Instead, the number of heads and cylinders are assumed to be 2 and 80, respectively, and the number of sectors per track is calculated automatically. (This works for 720KB, 1.2MB, 1.44MB, and 2.88MB floppies.) .It Fl I Ar hz Set the main CPU's frequency to .Ar hz Hz. This option does not work for all emulated machine modes. It affects the way count/compare interrupts are faked to simulate emulated time = real world time. If the guest operating system relies on RTC interrupts instead of count/compare interrupts, then this option has no effect. .Pp Setting the frequency to zero disables automatic synchronization of emulated time vs real world time, and the count/compare system runs at a fixed rate. .It Fl i Enable instruction trace, i.e. display disassembly of each instruction as it is being executed. .It Fl J Disable instruction combinations in the dynamic translator. .It Fl j Ar n Set the name of the kernel to .Ar "n". When booting from an ISO9660 filesystem, the emulator will try to boot using this file. (In some emulation modes, eg. DECstation, this name is passed along to the boot program. Useful names are "bsd" for OpenBSD/pmax, "vmunix" for Ultrix, or "vmsprite" for Sprite.) .It Fl M Ar m Emulate .Ar m MBs of physical RAM. This overrides the default amount of RAM for the selected machine type. .It Fl N Display the number of executed instructions per second on average, at regular intervals. .It Fl n Ar nr Set the number of processors in the machine, for SMP experiments. .Pp Note 1: The emulator allocates quite a lot of virtual memory for per-CPU translation tables. On 64-bit hosts, this is normally not a problem. On 32-bit hosts, this can use up all available virtual userspace memory. The solution is to either run the emulator on a 64-bit host, or limit the number of emulated CPUs to a reasonably low number. .Pp Note 2: SMP simulation is not working very well yet; multiple processors are simulated, but synchronization between the processors does not map very well to how real-world SMP systems work. .It Fl O Force a "netboot" (tftp instead of disk), even when a disk image is present (for DECstation, SGI, and ARC emulation). .It Fl o Ar arg Set the boot argument (mostly useful for DEC, ARC, or SGI emulation). Default .Ar arg for DEC is "\-a", for ARC/SGI it is "\-aN", and for CATS it is "\-A". .It Fl p Ar pc Add a breakpoint. .Ar pc can be a symbol, or a numeric value. (Remember to use the "0x" prefix for hexadecimal values.) .It Fl Q Disable the built-in (software-only) PROM emulation. This option is useful for experimenting with running raw ROM images from real machines. The default behaviour of the emulator is to "fake" certain PROM calls used by guest operating systems (e.g. NetBSD), so that no real PROM image is needed. .It Fl R Use a random bootstrap cpu, instead of CPU nr 0. (This option is only meaningful together with the .Fl n option.) .It Fl r Dump register contents for every executed instruction. .It Fl S Initialize emulated RAM to random data, instead of zeroes. This option is useful when trying to trigger bugs in a program that occur because the program assumed that uninitialized memory contains zeros. (Use with care.) .It Fl s Ar flags:filename Gather statistics based on the current emulated program counter value, while the program executes. The statistics is actually just a raw dump of all program counter values in sequence, suitable for post-analysis with separate tools. Output is appended to .Ar filename. .Pp The .Ar flags should include one or more of the following type specifiers: .Bl -tag -width Ds .It v Virtual. This means that the program counter value is used. .It p Physical. This means that the physical address of where the program is actually running is used. .It i Instruction call. This type of statistics gathering is practically only useful during development of the emulator itself. The output is a list of addresses of instruction call functions (ic->f), which after some post-processing can be used as a basis for deciding when to implement instruction combinations. .El .Pp The .Ar flags may also include the following optional modifiers: .Bl -tag -width Ds .It d Disabled at startup. .It o Overwrite the file, instead of appending to it. .El .Pp Statistics gathering can be enabled/disabled at runtime by using the "statistics_enabled = yes" and "statistics_enabled = no" debugger commands. .Pp When gathering instruction statistics using the .Fl s option, instruction combinations are always disabled (i.e. an implicit .Fl J flag is added to the command line). .It Fl T Halt if the emulated program attempts to access non-existing memory. .It Fl t Show a trace tree of all function calls being made. .It Fl U Enable slow_serial_interrupts_hack_for_linux. .It Fl X Use X11. This option enables graphical framebuffers. .It Fl x Open up new xterms for emulated serial ports. The default behaviour is to open up xterms when using configuration files, or if X11 is enabled. When starting up a simple emulation session with settings directly on the command line, and neither .Fl X nor .Fl x is used, then all output is confined to the terminal that .Nm started in. .It Fl Y Ar n Scale down framebuffer windows by .Ar n x .Ar n times. This option is useful when emulating a very large framebuffer, and the actual display is of lower resolution. If .Ar n is negative, then there will be no scaledown, but emulation of certain graphic controllers will be scaled up by .Ar -n times instead. E.g. Using .Ar -2 with VGA text mode emulation will result in 80x25 character cells rendered in a 1280x800 window, instead of the normal resolution of 640x400. .It Fl Z Ar n Set the number of graphics cards, for emulating a dual-head or tripple-head environment. (Only for DECstation emulation so far.) .It Fl z Ar disp Add .Ar disp as an X11 display to use for framebuffers. .El .Pp General options: .Bl -tag -width Ds .It Fl c Ar cmd Add .Ar cmd as a command to run before starting the simulation. A similar effect can be achieved by using the .Fl V option, and entering the commands manually. .It Fl D Causes the emulator to skip a call to srandom(). This leads to somewhat more deterministic behaviour than running without this option. However, if the emulated machine has clocks or timer interrupt sources, or if user interaction is taking place (e.g. keyboard input at irregular intervals), then this option is meaningless. .It Fl H Display a list of available CPU types and machine types. (Most of these don't work. Please read the HTML documentation included in the .Nm distribution for details on which modes that actually work.) .It Fl h Display a list of all available command line options. .It Fl k Ar n Set the size of the dyntrans cache (per emulated CPU) to .Ar n MB. The default size is 48 MB. .It Fl K Force the single-step debugger to be entered at the end of a simulation. .It Fl q Quiet mode; this suppresses startup messages. .It Fl V Start up in the single-step debugger, paused. If this option is used, .Fl q is ignored. .It Fl v Increase verbosity (show more debug messages). This option can be used multiple times. .El .Pp Configuration file startup: .Bl -tag -width Ds .It @ Ar configfile Start an emulation based on the contents of .Ar "configfile". .El .Pp For more information, please read the HTML documentation in the doc/ subdirectory of the .Nm distribution. .Sh OLD FRAMEWORK EXAMPLES The following command will start NetBSD/pmax on an emulated DECstation 5000/200 (3MAX): .Pp .Dl "gxemul -e 3max -d nbsd_pmax.img" .Pp nbsd_pmax.img should be a raw disk image containing a bootable NetBSD/pmax filesystem. .Pp The following command will start an emulation session based on settings in the configuration file "mysession". The \-v option tells gxemul to be verbose. .Pp .Dl "gxemul -v @mysession" .Pp If you have compiled the small Hello World program mentioned in the .Nm documentation, the following command will start up an emulated test machine in "paused" mode: .Pp .Dl "gxemul -E oldtestmips -V hello_mips" .Pp Paused mode means that you enter the interactive single-step debugger directly at startup, instead of launching the Hello World program. .Pp The paused mode is also what should be used when running "unknown" files for the first time in the emulator. E.g. if you have a binary which you think is some kind of MIPS ROM image, then you can try the following: .Pp .Dl "gxemul -vv -E baremips -V 0xbfc00000:image.raw" .Pp You can then use the single-stepping functionality of the built-in debugger to run the code in the ROM image, to see how it behaves. Based on that, you can deduce what machine type it was actually from (the baremips machine is not a real machine), and perhaps try again with another emulation mode. .Pp In general, however, real ROM images require much more emulation detail than GXemul provides, so they can usually not run. .Pp Please read the HTML documentation for more details. .Sh BUGS There are many bugs. Some of the known bugs are mentioned in the TODO file in the .Nm source distribution, some are marked as TODO in the source code itself. .Pp Most emulation modes are legacy (Old framework) modes, which have not yet been rewritten to use the new framework. The documentation is most likely buggy, in the sense that it describes things from the old framework when the new one applies, and/or vice versa. .Pp .Nm is in general not cycle-accurate; it does not simulate individual pipe-line stages or penalties caused by branch-prediction misses or cache misses, so it cannot be used for accurate simulation of any actual real-world processor. .Pp .Nm is in general not timing-accurate. Many emulation modes try to make the guest operating system's clock run at the same speed as the host clock. However, the number of instructions executed per clock tick can obviously vary, depending on the current CPU load on the host. .Sh AUTHOR GXemul is Copyright (C) 2003-2018 Anders Gavare .Pp See http://gxemul.sourceforge.net/ for more information. For other Copyright messages, see the corresponding parts of the source code and/or documentation. gxemul-0.6.1/man/.index000644 001750 001750 00000000034 13402411502 015105 0ustar00debugdebug000000 000000 gxemul.1 gxemul(1) man page gxemul-0.6.1/doc/Doxyfile000644 001750 001750 00000147004 13402411501 015505 0ustar00debugdebug000000 000000 # Doxyfile 1.5.2 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file that # follow. The default is UTF-8 which is also the encoding used for all text before # the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into # libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of # possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = GXemul # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doc/doxygen # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), Korean, # Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. #FULL_PATH_NAMES = YES FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. #DETAILS_AT_TOP = NO # Hm :( Apparently this has become obsolete #DETAILS_AT_TOP = YES # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. #BUILTIN_STL_SUPPORT = NO BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES #EXTRACT_ALL = NO EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. #MAX_INITIALIZER_LINES = 30 MAX_INITIALIZER_LINES = 300 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. #SHOW_DIRECTORIES = NO SHOW_DIRECTORIES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. #QUIET = NO QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. #INPUT = INPUT = src # This tag can be used to specify the character encoding of the source files that # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default # input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. # See http://www.gnu.org/software/libiconv for the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. #RECURSIVE = NO RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = .svn # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the output. # The symbol name can be a fully qualified name, a word, or if the wildcard * is used, # a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. #SOURCE_BROWSER = NO SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. #STRIP_CODE_COMMENTS = YES STRIP_CODE_COMMENTS = NO # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. #HTML_HEADER = HTML_HEADER = doc/doxygen_headerFile.html # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. #HTML_FOOTER = HTML_FOOTER = doc/doxygen_footerFile.html # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! #HTML_STYLESHEET = HTML_STYLESHEET = doc/doxygen.css # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO #GENERATE_TREEVIEW = YES # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. #GENERATE_LATEX = YES GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. #INCLUDE_PATH = INCLUDE_PATH = /usr/local/include/gtkmm-2.4 /usr/local/include/glibmm-2.4 # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to # produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to # specify the directory where the mscgen tool resides. If left empty the tool is assumed to # be found in the default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. #CALL_GRAPH = NO CALL_GRAPH = YES # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. #CALLER_GRAPH = NO CALLER_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen will always # show the root nodes and its direct children regardless of this setting. DOT_GRAPH_MAX_NODES = 50 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO gxemul-0.6.1/doc/20070128-netbsd-dreamcast-livecd-2_small.png000644 001750 001750 00000006013 13402411501 023413 0ustar00debugdebug000000 000000 PNG  IHDRt\aNgAMA anPLTE  %&%&'&*+*,-,./.0103435657779:9:;:<<<=>=@@@@A@EFEFFFFGFJLJLLLLNLPQPRRRSTSTVTUWUWWWY[YZ\Z]]]]^]`b`cccegefhfhhhiiijljlolooopppprpsusuuuuwuwwwy|yz}z{{{|~|~~~$yMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDAThZ6 K\Y;H;qa:ą),-etAx 0חA34wslH~69v-s_|'o{ɝoG}デw~o8~N>a{?yF~mڵkv/ݿs߸/ݿvƭ^|_v/\{̇?Ͽ1y߽vptt^{Gw޿{xt×Wg?M|~;dedTAIՒ$$BIcVl]F"='o"d8ku/_VF3BJ8F.(uC,HK j=$V 3U(eDcQDBzMZJUeQ*3fTNcA0ȹ:BkqSѓIO">o}jdߋ5JGqF3ƴ"QC9c6lBèXgJ82ĸi½zaeLʍi$tAjo⺌RNc'j ̰|MFYcyFvatٟHFk1i%r҆hSTn1].lk|IxI|,y7 |ZBؔĉԜ"r"ւI)x7=GZނaT1'xlkBtp\ 2# ` lS~D**n?.B:IIu^rVݷMcHg4i<2_kgQ "e3DYg2ϪV^=3I[lM$ٚo_YQ:fMY? T)jbC k7*1!ڝTJ2.Ü`dF+A0&R]@l>0i<[.o%v $\l'rL'Cg^{??je >r"Bwhft lȷِvc<^_{xcFM05!3 lh׋P&RFKŬՌj^JB.UѤMRkR8U.˲^9^Ә%-xt~p)8 C7ct+!g{7k)RiR{z0+Tfw!.j,E<zDl߭z,vy[",M7{}XYa{i? "$sZD/3k#v#K| Ҟ&$B+rWxI|xA [ JmSAǓ]~!$Щ}, `q<ڶM.c#ncBkMPLh.$aA- erW3ۇ*F_ 1})tabi5E6*,&B>uߵ5UygiB1^עȼ[<5=Iܲd(E`TE IN -Pi1Ǥ7Î0S"L$l!9)eE`qnuPHUSG(8s\ R-+m*|Q\ mu)rȵ$ ) gff saZb gg.gָ;bCi Y(KxOݤJ>d,/IRmɉiy)8 9Χ6ƽEGDC"/bSʸ!%WӽDQ\UsRCPz=u$2K )|K x!XA-:0)q3/6ߵZ׏,fbjŘCYF3pU z tDe#62\EF TǰoB+\=r|( e^{{:1# m[.N39'8BN1!x5tgP(JOkq{%4ȇo:6: \ ?[kCC48T],.ʡ;9iN@:k>W((-=er6(|Td&Gu5*N tRVPO [C)' KUUEQN'EQd:TBk*WN W|'+^!+ڈmL| F>y⽿|˛`kvYCStIME =HRIENDB`gxemul-0.6.1/doc/generate_machine_doc.sh000755 001750 001750 00000001435 13402411501 020436 0ustar00debugdebug000000 000000 #!/bin/sh # # A simple script which puts a component tree dump into the HTML # documentation for each machine. # if [ ! -x gxemul ]; then echo "GXemul hasn't been built yet?" echo "Remember to launch this script from the main gxemul" echo "directory, not from the doc directory." exit fi for a in doc/machines/*.SKEL; do MACHINE=`echo $a|cut -d _ -f 2- | cut -d . -f 1` echo Generating final HTML documentation for machine $MACHINE... sed s/XMACHINEX/$MACHINE/g < doc/machine_template.html > doc/machines/machine_$MACHINE.html echo "" >> doc/machines/machine_$MACHINE.html ./gxemul -WW@D$MACHINE >> doc/machines/machine_$MACHINE.html cat doc/machines/machine_$MACHINE.html.SKEL >> doc/machines/machine_$MACHINE.html done gxemul-0.6.1/doc/doxygen_footerFile.html000644 001750 001750 00000000413 13402411501 020510 0ustar00debugdebug000000 000000
Generated on $datetime for $projectname by doxygen $doxygenversion
gxemul-0.6.1/doc/20041213-debian_3_small.gif000644 001750 001750 00000005256 13402411501 020216 0ustar00debugdebug000000 000000 GIF87aP@  !!!###$$$&&&''')))***,,,---///000222333555666777999:::<<<===???@@@BBBCCCDDDFFFGGGIIIJJJKKKMMMNNNPPPQQQRRRTTTVVVXXXYYY\\\]]]bbbeeefffhhhlllmmmnnnoooqqqrrrtttvvvwwwxxxyyy{{{|||}}}~~~eee~~~;;;333111 111VVV555###""" YYYnnnZZZSSS ppprrr555'''|||444bbb(((QQQvvvnnn ggg,P@L"*\Ȱ8k⸙Hŋ߼f#:s@ڹ3GN9rHˉlּrK18s3goI 7tθicF 7rիcȄ#KٳhӪ]6mW`hKݻeѣ޿wPO+^ە˗<`XL!bP(0@tABR0 ` (8@`nԁ9`! ZE !V]R B'A7 Ze /n#YB/JSL`¾P1 V ;\Y&g̱%Q9Z LXH2#r r@'ݨd/{%lK"nA$#p3Hɘd aI`c;ޔ1Z/iyq !uD^{+<*D˚0jҔ;cY%'P3BC'#+4m{]i$M 4U *Yg E~,䍕j!C"L\ lL> l"62Ӆv4R,b%p}s z'^~|Xh$,֑;kuڍ.+%z: AԛT)$9\Q@{u$Ra d!7q5R[!1-(Hʳ$zNUN4>YQǨX|sd3b@& Wezxi)$1J@vKR9)cCZI2T6Ҙ"y"S^ ,/8iMP:tIJ&;"h\Q'?EC@uģaO gM8r %醔<q%\HAboU'{8!)=dG39r$ˡ\U +:c(K*w KŤMNJWpn%WW`P^yOb-wΛl8H'ol(Ӳ@M ]z/ m[J^mwv'j}hRf1l2Y7ER"+Y4~e['龳d%YEs[<ٚz" YURu4///Of)1ƙS3dlZ'aQ;Sif#s)x'gd3xRh6g0Q쏯9 lBgc$3jgrC#]9A Ct7n؁AfjK6]JK'9g gbR&W_k6i@7gAMA aKPLTEw&&333333?{?LLsLLfffffffrrnpUMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDATx w8.7(n/$|=W{hBߜS,JFSޯ/۷a 9cȘ–[V[:Arvu zlզMKZLi+պv]hk=q.$sӰ]KSZqNidf<m r]l7Q݉*ubAR`~]Q7> ›43 9ӥ`Œ(=XƘ(568F΍1"kL?j ls[W}Ci~<\og--tful*D6o&'Q҉gmn2a^ds!l^ q {[m+5慝˙ɧ=S&z*)+p|}a8/,7Z(۰WMb]>&ʶc#:ǭmuL jlZ!i\/\Hj:3o ! ~@nMLtard^hl 6` 6` 6` 6` 6` 6ضv\llllllll-v^u 6` 6` 6` 6` 6`-CU^vy-/maK͇p|4 Qfɱ28--6 QI< lUAG'{ULaKMFP-4Ma ;oY{ᚦZkl[3l?%IV=@w ߶&}'lv\u8(h[JGƦ%FmJ"lդ29ֳ%Haˌ-&7l0-lǬO.et|lVUCYpzH멡GgaZ` 6` 6` 6` 6` 6` 6` 6` 6` 6`m{lK7ޖ}}O"˛ llllllllll[^l-z5/?lllW+m6c>?6w/F%.[km%ֶisC6F?j,%u6ޗmF6ipZƐhbl,6& T`J_ӧU,Ls,lYCl=Մ#a#ocl㑭}Ϸ,LS-dF/]U3_)T4M&J+5m%6 QCz)I)&LmH$C0 l[:& l[rl8[flfQmm-C$CyB$lk`[o+`rnF?%oc]`[Mrb67VbK'OX0UJ4lY.mw{2`%K rdpː ϳ8A $h٨e8o[b RPPЗϔ~g~s"-V' uo3:ƭ;mw&(m)'wPi%x tO%c/ ѯx"qۃު=@,DjYi3a_@qۃVIR!-m|8[N>h'uI3=JNjyoY)S}~׷5i܎~>3="[bfy$zn-ɵ&=EqItVvYzh>$ΟshrKrg? Bx.M]!sm푞UR$LY| O9:s?M]/gz<ɸs#5Yx)u-wߨ-v!fW9$ 7Wٳ>=pe|[Q [ZiWi v+L~cg3O_n+A֟-_U>i9v7vi؞g$zGk5sgt72^c O#gѳfԇU>lJ|g0 F6+Kr9x 3ϛTg4$u3鶿72Vں<|fkcD$.╭-(i Ȋ~=A6=!^g yT->R;FJӟK( w1?=Q[,Ƥ$uԎ@j^ 16`/-W)@ym`VϺoQ˿t rrzU(\?ӟh"eq?AHJa?M?"qF3~5=(qAJ?S cD&㶿a| #W 7{t m:8+~_ܵ?m>=UR:(/` T@7M~ǔRBĔ*8>i@/]cһ<]0۪݁~x~k!`(g7㵟K Suu#@$A_ֿe5 tZZ i]gj4L&MSWklfBJ3ze&:5BJXaΠob:e) 4e|+R$HȎyz3 ͹<~coĒUCiX9t BH$u&©(0Ҏ>+Y l&n |@m@4l;-ւY-rcP_ 05m0}~>l?ia -t&K0,jq=RGO'; tucAqGhTN N-6"GT[=&sT0dsg_ _}{$zzА 0qvZb^R@fͷJ_] _2&:lWs%$ uGlؼ4\+(wj,dHjXOŸ ,l&nߨ֤a- jPG'ұ|t U3=+_swL:G-Nj^X,W an׃O@cѲ^a=&P'dAAb].}g9׃񇝤0 cs|YcRZ`ʂ3#b4tQGLpZ-8kT}ퟹCuG0W1- [0!u݃m8m;.`J#\jc(#-(hpp"N?mlݳͰ$D ggSle|wp> :ppe<1`ݖ|=#fR?~ʲ 2k)Ђ2sP>{ml1AIgSledAAf8([l7k@t *Ck\7paKS=I! &!/0,!6ڴC+}[tgnҫ8U|ˣ^8\GhJy kHqWХzCAMX5χ!)hDtEzX s(rD>\ Lcya˚WZت{+[/oV'LyykcN# j$S (IS}%bN@,' qi]CoVqkQZ8Ɇ(ڂ5LkN@&7r-9J-r>0 ISv~t_%c=p< r5KA6::RQK908l\M fƍj_+'79ej"aX+z2`?a( ?"^,a@XKk8a3]$icNE]h| ӂI8îY0"@ =UO8װK'o,h3PmTj?즃 <@3qCD4]@36F2ZLe.Wkv!]VG)P\@S0f $%.Tװv{C7{gyc>=c_2'0'`Jᕂo+" J&)cBh6=q 06^wیGcUNwlI/ C?xټ9_ΜAAdAoeZAAbڴ6~5aKld``٧ C0ATCG8ذ][- :r*p"4 4h2ڎO--OGwֺ_N HYJv40[a'GQ2 ek]9E-`'(w~Ez)+w?&s̃0p{>/;=w&hnDc"> Pt;X`m61'ܮeS2̃>y{s5 M@@^{%e.R] XJ > d.NaX":~!JN > z8O1 I&yNq[{*g޲|s,L(PGx T ߹I J5Ė[=,d'm-v'FIKY. x|xVuɭ ZTSi2|7b׻#@dz8i|<2"t/ "0wQ:v}o52}?IFTu|֒+Q.PT)lOcgL3ҿd҅'>(4F32'4f. PI- ~meӫ]'<ε]C{F/1LMV?1 yIw~u?0[z[e:ݢf/r)?֯,}gBf{`1L%aE tv ՐH+G5<gDX5o`<èJlVpN0LW2_h>O^2!X"X6uzφ'DU - qBK7n٘rn3dv!76yOb+w弰Rx.%uV^O.m  qw_w7J7ed'Ohky'ҍ臜8mz`-G ;KtPv%$XFGQSOԳ#PX}w,0cWޑ!qFrEh7MဆB%ɻKIPH :-XtD?Թ\9'5!{U-GJx.)=Rz6>L7OeJ>`a{pSC=>%XQ=SWdj!KF| Rz6ʳH)fSY,~=21_ϊoht@CP+t厮.tDGOϭHR`zR"iF&p(oh,Ts*s'+BF8#=,W@XKA9U#*͌4遗oD\}֯lͼ"sd0r\x,fG /*{@G^)=_IX:;*>x>D *W}rт>2pϡq8vCJwY]y}>LfLGz>E։]xT>׾3bVe-pOVuJ/粴r0P';lSy̯k{vV6˙cdusTx䑧}e#B29x_ `x9:4)%fm{imãQ|n8@V#w /: tgj[iD9}w<<ݪ=<sUG6F89o"9B+.WzcAN |oc;XNG1?R5PJ?urg?&Ã/dYcx6G$^}&Gs9İ+M#, >B=:?4%$ vaJ\L E& NpSwy=d#;v9vКaƖBɹ/Q9Jϯ>{vJ4i= "H@ W-ܾ 7jn#wOWT [bI71H 0J) .9q*UZJ){ 6NkN'YF l͈G#"&,{tWGjXJ&҃Ix`o>/n37wUZC-0]VY+`}WfE;h+8}Q)^䠠W$1t]'(1kh%:67mH*o@xͻplY/W#_Mt)C :;]Mǜb\) wz7y_0lp.k⦊=!"5NqQm,@_=҃  J 1ƖS(ͣ 'ox$z&2RxA&ճw|-oF+_:Z:aKj H:6Mz(6i9}-֌&"="Or=bJ 7>`0T;Z2֎TYyDH)13Gdn5UݍBV@"xӛ$b@<Pu]Q ( H%g61i:*X¸x*_ohh˥dC  x7Y(W gv#2췬IPAxZ | 3V Eб;{ϡӵq89[/Ad_qrhn,G=7ӧ=aܙN2w'7hs*uJ!_TڙTxWJC5$f}:Z bpr %P\k$>&}S~;atR+a1 /Za{{ 奝[9ܿfGu6c!HpMOXO3xg!H?ߢ,k_Z^z/9jj5~aX_4^7/'[DXBup"Dif|EmPDZkq#QGc}q|p_A<'Amzudw(AD;Z}cxE~-~S~ѵZGYiE:'-id,89i yӤ=`G%xA_ .S YCqPt$H^L+pЧI++PeҸ^(#XkU/xIOĬǩu*ҐfZ= 4e[пaV^H\Q d}a?;zvqSFB,19?  tDwKK {M 3?2.}~;q[/|&=PE}K;SLVVdDkЧҟ_p;^ "$Ks~v,NCL"k''pl n7݄oN$ƴ!`ڶ(} .d0oYP>+SL`+ $2*!!4.XqF)n*/ek>G5]UN^k2Vpb,G8.TJs~@Qs@w4-L{HA8(M= cՓǀ(#%? ʤdK GQL@΍Bo;W`+ <}732șؽLh,o@;^07p2}  k 1c5sAJ㦼>, Я^-%5\ʮsP'=Z:?<2)?vC3E`w[bPKhɶ vр[+1zz;7mjV GmHQC[bI]U|؀@y`y8[xTmRw]Q95rW/ [;>Nӓc]~wV ГV=Շ}p&1n`:STpHv2{zL )KxXf IDAT73Bi$, O42z`+nXX).F7"bBLWsHw4|*ݵyq^,Qw[ht@-q!"qkW[su'gs߰_bR[tjztс]'QO㴐ĞŻ$$6(i rpl\`P,y6 {Nڱ,#X=} &FmiE`OgCmQg25gS;2DDnu`JL40Cv-sh`bh.SO%`e*@s M S!o)TNr66??tZ.J, AH"BWBy#A X6MT|9 $!Ip#X_ᤡBK @$g*b>y2qإQ{`4*#^*z~z[5K0e}paoZXԝauC0q{3&bYY՞8"={;90jq wh0G/#7Umxv SIL〫iEKg{zp;m)`(F^jCp\:0uM0=ȴGZis3mFWbMb AAalCĂȿ-@!Lf :BkkahJ*؎}m,=z;U8"0 ,8eHr9ɬgνz_caP2tgAW<Vj<ETӠ5N (OL/bM7Zsto]3@ 138`e>BtY kI`icpF lCzR<8伣@aNCv\HƋ[jV:=h9%ɟ "3@WNCq$?˭_/l?YY@AeC_/pv!"y gBgs},i>l, !f0_:`33Jܭ߉δ`"N{z>TBS<0PY}f׏2&XMY[C#r](u9@#/$AS!HyZpnҝ<*Iy%&JVVNΒ,:Y?ܭ@eY zOahD=e f65dNT0Pm7e%'E[Z{ۜ@h$ghAoH SisXwHu-tU{<#`}'`;26DBqByN̤$ax)E\{ "Rsٟ LrG`*Vo;鱡< ڤ<2P–'z6PN%{yzw<,+ؘ/N>73[i:0%=$l[.y{z pZ{WWG0gxQ.lN `LϖTN@.> qiHV4 q@%Aʡp퟿S8o R9@i"7Ȓ:ٷsJ)|9~n lՂygб~wZβHe`5 c&t=}kZ{6;|`>xyv("iIa$XB_7/wc,{@U;Z${cp^`9Dmc ;#2-3"dw1c?b@0P x"NEf$A8Qhu^9ަC`H% =r 2(O+d$Ie1hOO+wZ-87UYg[e޸_<m@D8lYGk>NkBrrէPe:0[oX0 It)%$hPؐDI9IqHqRÛ60am_g P|*Ш O$u H _^Ѻ>#.pN5\9.B :]o8 D/4}{ZymBhUX tjHS1A^]O.+Ȝ!xSdppM٘? ?,'QG@q.8Hnl vmJ.d/& ]`ClݦC̏-ːrT،ALX+%4̰țV\k{w E}A#LI" qiƴsp>)dgP592[Ij,cI"Ь֘TЅ& s ULB;dwq8%9ܲ~ xO.ЖV[{P 6d6ginݯ0%le"c46ꂾ/ϦAxOZhMoܙ̚G}WIffN``@>/X`MpZQ+`D95.=Z(̀yv]`c:.+@iޏA%a76vy(Ag#i<ʉB(/FyK ͠%}'!F+ pA|\Rĭ#w7UG[:ŠKA!% %9n1[+q/ӀUc <1 @madTMF z]> 9" 1725݄wpbE~PH_@jW @7KEomb_͗4Y1ǼY W8q`EеbQ@a(״d-IаknM}͎WcehRq&A;*m =XS]fTO ¶tY(,DZ*׵1 53 q^-&=ȏX;%9BQ$/cKɴ99"v(O @ Cf8Y Gv^1QkL4*X !K5:U.%)uv=[ nX Fi@CpY#rZmQ@hHd~r Ad|3X R76hRAxkpZ0b;pۄ1Q@Cb^*?08o૟n uR%TRrW=\GYiVDž݁5\D197F 傸KS^wi`w(S#VUw2(R6Ӯ%u&x5t;]oR08限8OEkRz!5&E3WkwN~1 + I:LP5$tOW4 Goa @\ i¯=o > !l qb z/YVb^"[@!8 Cn  6kA5/B4&HI<_?0U\tXN'=L :6a``0og 8\V^kmə=[c_ӔB`7Cxw,,$M/`L'@bъ0j$r:1L/eE'/*z p%|V̲z)p]Y|ч @zʹZr S4>K^\-?P;^09=ih,@>\3 H˯ e[mtMpZ P xitF"JQ8-iOG]T<7-GdxW x;3Z~ы *Aҭ#G);ܛǑz`}CPY˯]'D!catPlo%/VpKH9@P$#ɍWʩ?P\W+vɕv":5c4]f0?wPcklgtVu۱^v,h]Y멚 {FP|qTQ}y6AںɌЎi(!myAE9A`0#иs H< tNKMM1~מqt< ,/GBNC袏xX"V!@PhA:Q܇t|e& ViCLZH\3L$_w} c+'s]A .wȱnN$_ui>H,FXw Oƶp;Q2 q  aV b2}]PFtxOҊi!'m8wq2j0`FMLIFʯ/(9wmh1W|^k  4X,'ə 1كFTonDUv;eϻ=)10`-]kjmA@Rb"%,6YE 'li@Fk=qAFh >~z:{'IW1 !m_*@J)߇qfx;^OC{ЋCA y19Ϟ;8Ւ'QƊ3BuA7iً  : 4Ģ_.znD'wz.,a0ʷyb@#&=I#yQ C9n-u[nv;߁4 D|&d@ҷI[`f(\XReiAJY$6꧄Z8 -AAX8Tj)"7*AYr 3 z %hT~L<{y;<0sEF]u, %9=7!8bСJuiAt`6qby鰋ah.]*}|C  ؚ_ʵr020?צNcCc7K$+ÂzoYr衜w[{ g ٜ&+Yڜ(*HC|RQ nŞ[(B&\n|!>*m†8 =Ӭ)ҷbvb%ҿ-5탋(W[`oA~ٲ/8vcI#eE:;Ov7 $wUbVHlc:Y/$/ii s~` ZSI0vv9Zw=8[ϒH# Q̮mտu_$R)zUTmXmS9?TS6yņgZVM|Rc訬W3^cPhaܯnXtGlk|mY6 prLsȸፖ'0"h~*޼|`Qb“ip/}[[yyQc P}cqHs3%e#Mnq6k1Ld;[ㅘ!% f@XZD X 䈎yZ sjk"0O&(.  $%3 :F!Wm{$4廬=̜:` xE|.,*31e}@mA9H gC˔nLkjjh5BVKKyQ63Z`Dv;Ѳ2$8 i!_g\i^#[ -xo00ޙV74aG^p Oi2)7RAw uqF?'Qf" AgHԏ/twH %TwX\N@{?< 8HO3ڀ !A}m%H?]9Dm嘫=̀`eR` jlݽAEx?A_m+Tu&+$O @*6rDzق:yOK ewM={1a۟cOG [ @$bɈRb,?༞`ϿYIk]V6IdX8pYC;ʙ~Q%KWꑧRoiF1(wH|Cٯ=ՁC##bR]@]@Z86'@j98_FcQ@AD\3Fb|k,@YP^bh J+8$ސ -DN.hkfu)Z@v {6gpmF@%ꮉ!@|@ ''z'C M֍D.H<$b}}6^ 蕬 7"^NHR LT"UV)zhcB2AN֗5p.bmu_$Ncq`[ؕTȤ 6F-l8G+a:q F?W Wt=#yA.u=}6v;'& FM]Wh{>bwi[[*M:Ѝ:󻓛ڲp_Z2fIJ#aX^EV@Pp`BQh{R IDATm H4 R)-`ADÔM#hU $",VceE"{3w =Siͧ8K3#4{MT ҿ:B֎ZC?[@!;[sh!'M#Q ;NEoSǻڒy7״_7ސ}m|>i817#-IsMB.((VX?೑wн7{A rXa)2+B0؈jSLU։I6 gأ59a{yB0P@CÊ`0^GA%Nף(S uXW+ 3jaޘ,du7z7=IsB<Knif &OMgcIMJ{ߎ082zxˍU]@kd+` 5? VAd4IPƗ6L+^ƞL:*c]Pd`X]Hx&vO!e\ŀR9<`  z2jm1Uu b@W}x΃ }ae*HfG̹̈́.eau\d Xهy~/FPԯ2U*I Tgx ZH3D=,y`b` ۚG4?\ v7J`j%Ƌ _5]`wхe^LrOǂXX `PsL~1ˌFj ^0<0Nج dFDDWgD\>wB# P_MC^= ``314@pN.M|bm2zPP0ck0Ub [-#W# ,?tkiv mM0"q[L4jsNX [ިo6?_az<qSg #8nڇ 4hl-g|F;t$4FT71f0(; 69^:q޶Ǵzyqۃ1To[~rDi33j|`fI#\CTJC5<3ys<^`EB|܏4矃˼ᔷѣF %@ F0Ihy9 onw@>tѝ/[~ ]*@_y՗.  CзK 8o o`;vp'9Tĝ:-q?0kAkM 8o$oX;eL'!hq~B"zN5)B8eEPId hيx@w^(A9],C9U'! eT"Gu HXǷY&2(sFX"9%s14|:'-xb.ĭ˪/ ;!'D_W!ylc?\ GJ) ij@hȻBplt΀{,Pb^DN׊n0JYT@7P_&NxfI30)-lؠIDA{q,ꋙ(vs#:n=d\ !r*>ݙc008w"܈@kmpÇ hru%(c%އnx:k Lvt!M'W^ .dB=^&T),rDhNV23':wCIfи6ֈ;c:'N\{kI"1ה{o?}LNJW^ϓ2 THIaD1t^H$1  k#@c@sxAEiA[:"LJRdI wnh /_@ # 'Œ]߀#).# E^RfjWD Q3[eoy:o 2&٨m1,^(r.ٝh(5+R8ޘ= ẒM FuxP1Ꮈ|*\$*kOj%ɰ̳v@Cv7Tf0 =x9Us?@8, y;B*_,C/l&` h] *Ĉ70čU2vg(0,BV#>iZz=( 26NB#vAp\>u4܊٦)Ȁ& U !% , qѡ5|Xf{i{}i@ e=Hb/.kQ*$yIn+"@&1F&ٟRlVb %47c<"|k^z)M6$LWؚkPGDkH?e],K0v~O]}sm#ck|!L&;BF"s8%שׂ n7np;n320N/'v Tq;ҁ-C{Lf MGshj=8@oT1O(/hl!dIF@96ʀ!dG \!\jQ@j&Ejph$"u;oykRQG7",O/0 &jw(bעH*)joy21}Oq sw$_aˀ7s`}3! x:YEg{`Pg};#_f@T#J#,Uc`kA@7l*L-dP)5Գفm\: iI*^?1c)Hu`/?^bL=EkP;ď\H 7Ph$jKE*Sג܆؈"%u YNS׺~SI56230}Ͽj3_stx=@71x;`͗5]Qȃz50 4 `MS>̷am˶Kκ[(.uW8+#\kUVUOL%x<#]Zܡ漣iS n@"% 1{$h#6u̺?'V)ȼ 9;E[upJ xٸ[o`@8HCx8m?CɡI6xH5\yP} Gv$g`qrZTiH@|#(% W"ԋSL{p6Xj q]_hyfl S`0) p AQлm^@[pP&B$ݒ믁Q1;~0f |F'уaz1nB̀I!b<!q0 _epY::PPLS1x!W͞kT P haO@ݚ@Ưz9T+1WnJVN=MƬBzN`ݲfț]ض $34D;I)29ԣ.I86ED^` ,33`ț Wbx'`6J53V/" Jމf[D2 `66\'N,tFZOd bjE x  e;( 5ɝkn hpw+&O oLtk5 <'D?+)l4$\ !Q+Ү0ݎn%@GoUJE0 i6ﱠg | kK(9]LN.SQsIl0#8 $ HI{Z1D ۗ7sg3B ,`! M@Z=(O?R,ETXȹ\(Oh!})Yys~(b`Rfߥ0N+ Rw}/"[>`Zܐ4UؾjsdFX| !Qa< xmm~DTu~8giArˆh/n֔;J|- IDATK4NYekQDc^Ƣ%Y")%ZgM⌖,/>SӐ%:.j͙&s mdNVna$6ykO[?j%p|7sP5&dMc 3IqV_$q74nL9=$P8mqFؾ >G@}a{ kA-u Yv] dxfimRСa.u56dzzN;9%•*CƜ1ƛs`$L zF?f {(3$ Ё)dԤW JZ(rmp' "~bF(ٞ6h6Ae4CH$ FZ-bv"hɁ7 С1 pW+үF<Q"seUy!g%9D/fH%j5\qu!KsN$ z m[jN_bT%! \0subܐ^ )=|ȃvU &<^ CɷX/pVs&Źn6nḁ 8hX+ʐ4gu@иL5u000|+G]ml:^UoGDv AG+^ѷqs?!0Rn$C^+zdNTC`=(Gp `J+rb?F1zj0AdM++(sZiO|{ϱO9x㪃<,Od-;cؘf&' -yݟ .fCs]}ױk=띕E9+[^ԎYdB)P.>'6/2S}@WgX*I 72ݿ' 9He ˱ C398252y6éW!k mjPϡmoA.P /=YZN.'Pg i_BHimo- pCq| b'vPyvZk 'ț2J+Le R1RpeԛБ+t~cya]~#ЏkM=.7aDJCEI/ڠGnauf8j/hE!Ș.Uz4\ຳ>!ߙld g D]AC`M I^pA/W2~w"vAA=@ .pKKW\VԄAA0lF U|@džt ^f, P[ԩ M͠{0Em+ O^u/ُq"Lt/SpH\dZe #w~ƝP0FQ@AAeAɷz )'(h~p I:FEm$NiN/=n, zi#4֨lDc=`xCbϺt~4*J;r B_@M#E`@E h 9J_JI]! W ` Wuحy/0TcӢw{@ U!(h @P̛oU @p5_C1|tIo>%0@F%+Ըv}AJ 1,o>t5qwKleS<Δ`Nʴ`NJL6nqA\vRa$뭒(1׽HUomlZwr)6 2ߑ6rJH.PwI}C~B IuH4>QGlQ(\oDF>v̯a*NGs\`e_{^dI3Cz^;jVk,*f1!֦: "[KTƚZ kXWa[D<:opS,xl$zIHXZ\)0ڒʠȍvQ2, >*a1(d{Ne z Z0*Q!zWtO1}3||#= ͮ?Qw m#lDθvG;cHv6jj9!4MCP;ھY#!i@\y,ȿ@^v䪙$)T] #r0 E޽3~X@{F2b |pFXB\D`i OTlT ѬdK9nvz;;E p"p{L S[piJ;%o=蜃ogt[x64[XZ$ >RH#M I|oe:C[;dGsP\׎md2P\ *m7tR1E@&P[)7_R*E! ݟ/2|6 8̬*N<, ^/OV2eY.c [m]Bxt%@n)rz2}/-6{]6AJUz8c0&xGO@iVGPY'_+8߫i:Mn/85 HtI"T} oS.Ch֪ mG+KVw/b'QҼ/8b(Sql9Eݟ/TTEHSCcZ(sGshAH;MCAer 5-^z#Zr#v0YaC@?Hn$HW>e }h!H`mp{Eߠ ' Y$6,zzZvə~3|/(Lߞb 1te%9=!4YWD-(Wa- @{);ëM'+'3ײy uOm4+(`ꀃibb) t AU;<3vof@sP#K@ Q0]Kyi7A+uf,VG3LEJrkތoij4o.2ܿ0xi\`\8` ^u!i6Jz+y 1&&Q;"[˾@˓= R2>p0P @;)3>&3Jϝ]BZ>%1`2`-}a h B8@┧I$ 4@3I*@@"̀tR[2& h d=u_% wg/0x8ގ(P/ZE@9mm̀5X}"2 ;j< 1hH28E?zA![ẁZ6;`䛖ATO#xE71Bueu00T8H0rv?1._g>kiR3&f9Z:HT 7'`q# G!z.VǛ'(9}Ώhgg'^x%z]מQ(6a?`;W"0.2K%B<]t(Rvp34cyXmQjH:1Ư%,H BZC :)=U R89N"/!?3J:XZ> r۹W 5,i7M#!H7UOhN!z ֕;! پX6B `lEo{ͩg-G >*]yIN@}+Q`]@Ӝf 0xB7U^3m~ax?TAjZH+pF`WG7ُVLlD#21fJE;u,B~}uc{1m(r8%ab/}(`[)i,+@yr d@d 㪤[,Ys6Ueb-`I=X+.+ ̍{TNd''(T`ht-hX^f h> '?Xv3'`}z+ Erİm'tR9K4;~+{BN@/$֝ kpLݱ&P #}pAySI ZYe#?>nZEHxv%1R1ݕtvǕ#^}JCt^A9M3,͠ 6y$HFU-%5DHARt~F9:lv,73~\c"*? ޅ?8?c#D^wErVO}A\d@@![PXꂂe@DM e L9->'7ŭگ0d*݅QM]ך2/(g!^ǐp nvjO.Z.?`6jC4|boVWUAՃ>H]iWqO<ݎ|~ 5#]48^vh$gM40t[P8}&Ƕ/>.cax^` *=x0Ƞs3v( ^.fmf&M(u?1ttJ6o`>:p 駏)+DŽ_!7GOmMS&D61fсo! |Hq*Ĵ% 헖,( y8t4:&d|{W_[x!#6ZçuFBZ%) `K&@vŘnnсAÒ8K.ʕM-8RF oUa9wYjUbVdHm_@!uÍ YVFLnZ\%hah - k42GYK& j@ECjDąz71TpvdU &с/ԄVbBK_XXڷn!}%8_| Jd1dlJ.];38ygjCcX1HWuħxӚ(} 7p砍? n1A~/1)ۜ_4T _ -ΟUCs`F@4d+XL^wl g-Z"TpH.i(;h64t  )O@g#@|gpN+4`rъ;Yw^2$GBFnAe#YB!Z=ud]!Ԃ)<*@<lעk\O:Ջt]WV>r%1^4-q#YғjU4mVdaZf?#.&|[0o+_׍Rf/@%G@DFr-NWÓNE2 ~˶ȊίiCs⿿ 0zk55M!~zBڎ0s @wk^?/43 eaq pTE u_]&L^,o894y2dP`;m6s,Yr)@_W'1&f/A@l䏳めOU’ĂZ֯49|,`=6M ﰈb @ cbRH-A'546 d61A!`#]'Ak8#(H30\XI_+ p &,&+iTf3`'aQ+rD..eɁu@g9.YX$([e7U%K$% ݿz\.:d0iQvh̒j8 CL&fv {=w % 6u`rB%4q`qqO -v6aO]wIYb?8g" C_=9 Ϗ| `x|qE&Nkq\@P*w6tiċcu`*ēI{Ip \5/Cs5}L_'CV Sjj #6O,D ,tYzm&SR?kg>E| Ȉ q[ϗJOԕ6>?B=ͦbudM 㘴D U.LwC#4ryݹv*|EZcNe1@MASϴ=z#k.Ep\%ëa>7Z&\7Iأ\lsqGGd`m8F9rL\4(}p.MRW 4Նl͑8pJWJ?UEKםPsUeˊHgbl:NTT`MFx:#KvpY5@/jbr.w4/"d~xGBOoIo;H_YЕwȊQlao匄 IZ&Ѝ\_ }O1GgrwH-#+Uwף)>{ \[@7`yɆ*qiMd.JE4l1V)>ĩ_*P5A\-%ﻛ%ڃ9Ňx@Y@"W|M}ZHj__K )I V=^*C(a6 _-),ο1EAS6F*<]>'iFS Qb v:}-(ܖZlk@щc6<) }()+Qf_ң(.J]r*Cov Pyb˕"1A۩ l:{`k\{n =ƂH/ō#}/]w\T?[ā~u 쵅e Օѿ|n=67df: 4^~cP=q7ה ) v)V̪VL^)\&:j#7,Z{*nc]9 `D 1iVa^]\SgJk%QP&-xF_|Ԝ0gV;ɷ\&B3_=8įjv 7 -,Fp Zzs}u?S\O_(V+pW'M@x/"5>w^\do8z¦iuRJwA6ST]>tE8R\` IQN@]J-cu_4JL_uWUTUٚuch+&G>7 3dcqd}\Nתژ }9qK)(AԖ3KQyQY`ݻFܣ4D bSԧOGׂLҶ2ΧI*H5aP/E;R^i1-J >p_-u?F@`sWq-!D\Æzc_vZ~~5zn#v$q,`hϫ;lt# {P n>IJzGMAMt%D0e7T[P;;{&vTxj RdDzw꿚 \X?b"ʑjWT"DDY L=wi[**VfJ^+O"Q 89i衪bSgVjPxHKspuҊ֜nS΄j9!Ux&:T\82%}v"RAW]bfG8^u{q">7S3K\ QX\S*jo[|T2FZisFs 7^ĄRUP#Ai^ Mq8"hA/ɷx&>/gĨ&E5wRoF8mLb2S_='TpϟHy#U/J/=BO=w9Z Aza$9sz/1uF2<dVZy^B/3Jwzy%V0S@<=ahMfӨ.~ahkוeLLV V9Q/sXxިcUE5V|db0^4 㗬--#| "$oNծUH1e&/#B\[x r3WrUPfIĂ1en89qe:͘c.,qDL(aKf&S4e6ΏJtN W:NE@(`Y%Lѓ]Kĵwxb$l|>ORo@x !b̳{S ^Q X͞6y('ogqboA] # &jo+A0S%>]I`/Zb_s #fjR i/G@P?5`G|>?Xnz#|S|*Tnצ@}# , -(_77/>Gt#үyv9J+^dC>oNk|4ϱp'8'wrbF  ;A?o ^ ̧ aı{`'5x%0A w ^-3'A;X";tIME*y֤VIENDB`gxemul-0.6.1/doc/tail.html000644 001750 001750 00000000036 13402411501 015607 0ustar00debugdebug000000 000000



gxemul-0.6.1/doc/20041024-openbsd-arc-installed_small.gif000644 001750 001750 00000005441 13402411501 022720 0ustar00debugdebug000000 000000 GIF87aP@ !!!###%%%)))+++---...000222444666888<<<>>>???CCCEEEGGGIIIJJJLLLNNNPPPRRRSSSUUUWWWYYYZZZ\\\```aaaccceeefffhhhjjjkkkmmmppptttuuuwwwzzzOOO,,,333FFF nnn~~~;;;333 111 :::VVV555###,,, {{{XXX)))!!!||| '''YYYEEE ===777nnnZZZSSS ,P@sH*\p +V@Hŋ3jHQ DRrXɓ(SDE ,]d% 0Y . pࣽD 3+4 &ĐH`(0 7C[^/\_yh܂@*)aA _5 @L gZr| ,po &@ T#<`p !prP3 (@T@@0-GK VP 8  |؎$^[ai@ ր0@~ث5`@( l/*@@/ QE UkD 1x I6 dPA H p8 0 ``|%< @ # L ٳ lr[D cT( h 4Y7V~+S"% q)|IK0SLs jid`DH9@A` 0ŭl(Ccd h0t-+wp J$yh(Yi 7?EkTРxj,yt,e'tg"X&Ȥ #@&̖:%8( Xy?/jȌ{xpir-#$dg7'SKc \6&6KP3VplpZ󤧼gw|UG]e}D4Ƀm@LuDTh=@ WB H 4VjD a*(rn- e@>>>>???@@@AAABBBCCCCCDDDEEEFFFGGGGGIIIKKKLLMMMNNOOOQQQSSSSSUUUUUVVVVVXXXXXYYYZZZZZ[[\\\^^^^^```bbbccffhhhhhqqqqqև^kMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0hIDATx{6Dž9$ M:Q U͙S͸8IGK/K<'Kl/;Yu:0W:<ؾs?lo?{ygÇ?:M _ǎ5~uW_ګ͗_k~c> ~̗Ϭn| g)0z<1n7ivΖ".i."A;, DgHHY#   ^C ( HQxf B($$,.L2q:ǕIAg;v2,IW?<; :_ւy0 kP1%%P HHlt\YirP ]&$י(|g1ZӔy4srSj.*7j6v76FdnsȋOP9@ ,tDp"Nd %EPD0A0S (J®#' n׳n+oհu-O%8G@BV7l*7A -04B~o|T{*D_*Sa[:v6+:gM )QVJ뒩Xh(4ή-5wOJfD"! 1,$8I"!q(  7$/FV*}fJ+$+c}"AD DJv/6俻RXy#H 8s&Gjcyx)\q,"AthGm5LmڠTS`")Y@&(ܔg߃Sg[[44,Xf&\0DRj$| 3?qx7=Jjߕ;[./Be"   -iM,1h{JnM&J6*릋JovY_0I7]a:P#RPBP921I#.`*QNx-NH&'!ÍTq>byQt)@HTgL5v Ek'hB r#3mcLZ漟gTjslITA,eXNєu $DXӑڬpI cYH&)}&Ou{JAXz/bsZhJF%cC('- u:j9Ś7:n/;ʡ |,JH SIy*X}T:YT:.TZD'㊦EWV2Snh< Oƅⴧ{* =ORŰH򴦍ZYip@.)Rå<%XH94X vvl1]BP}ACUqx#B|,j#hZv="d&` }B9"eA u?6~Qݏ2%ZIJ~SgAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDATxڥXm<K\[Z+C*x㫃Ml$EJTbJDvvvvW \y;sxjct/͟X q;8k+BsWs:?ݿ1W7gWguw gdO$#ֶ+m.RbﲡL$;H^d>;d/ە[y] ڮi&<- E @Cv|3So_@)1".12 =%6͒;`oeN6+Y\R0 D2tGz>i#pǹ".`$ ;[)gv;8F#F#s+VZ3|vEތOFk*fj>ؽ PؒE˅ A)B. >Hoӽu6J8P%)Q!mi?y߄|X5K%Uή@ؓD:d{T,W_r900:#ڬ@霡ݲ1;" w?F `t#FPNmLeZulmL+|6ZǼJTrGڰŽ:RCbv@[lɔ`U:ɀ@ nV6ZgjٽڤJ @%X&b3 O:_vզQJ4@N?QP8)2)* SXao4QX؄~Z | L1-O4#z6Z&t߽d|>Sv{&. 62>2AWIRY'ntmP tܲAZC̖UwW$Wת4%{TT6 >٤7g)'ەmyڤY9'jY}x ` /Tb5A}&϶Uoοۦd `ˑuvv?ƔentIME"̇IENDB`gxemul-0.6.1/doc/20060724-netbsd-netwinder-1.png000644 001750 001750 00000031635 13402411501 021023 0ustar00debugdebug000000 000000 PNG  IHDR_.gAMA a PLTE&MtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATx]Ɏ<Xj'}_Ey =}ZS^Eyw!F;&`'6+ĚI6B4Nh'wO|V7 Rn˺Vڙ !]XQ۹7kPN`l5ܗ5Bhn5x#ou'Z`oWuanDC!>ԚR:7*f Uhkٴ7W\oC]-֪l%F*jFS#[P%|%Tm7R]P5L!{0dvoҴ޳Z7PkPj*49J1#>Q6q-0zM} Jӡ&b 7\~AP%CUI!غTUcrr-:˧g չ 4+T8y1MD\s~"`U1lB0'Aɥ|=T[j/4_HdʀڅPk@FP;j5Vj*&*Z/ xPQ}P5!clsg Er-a_2i>Q]~;t[(8d ,crCW.e3,+3A'WpM< O) #1'0- #1Z5PU uC̕Fi RLPmAmA=/՚. Jڃ- 3wLp9-F 5N*R33Į4Sq$ $Sz HrwLqrK8 4<""ժ$ŖbvP#N"uZxؒժ!fXf}{ԘR؀چPIr`3 jWX Uw`CC1!fu RO`.AW؆l;#Sb)YM[ߪ=ʍvПk 失ku\L@"úeC= AU_ uNcgCUEC:ʋ0OF2m | 'b!͟rH59>^M2aH60Oۙ<;oO`[yΊi IWmZ-x=rAm:$V!UINZKίcI IW3C6vKv 5q-ZUtP{wMSi8_1tݒZ|zc`BXH:!thCPeTٹ:ZCV?tu*o7گ*eC<5`]ևj7 5b!\vP?1:%CE;4trPMݾh!u\SE u\Զ0+$jf"cQ*O> Jjˀ:A`k"E;4l(Lk1(i%@%h6aА(tǙOnJJȩaa ICC,\:np*+V;PvtA}mbSP{2 ?*b~K5g_R{5VaА(D5";QW7Ẉ$j9?$p""[AHlLTOK ('ٰjP2wbMk?( 31P4+G)Byj&DrP;aPUAPkzO#Ũ N^ fpCP VuH(s8@*,QB:I@Gܨ\jV !UrӉpP[Ϩ5;QK}PkէgmP%tP"`SFCe ,*k l0fA}"$!巪C|`Q^!c:l Ti)'`f@&(§`R+o]Eؓp7}vqE@Hc?}(V2'}T$xK.)2! D oE>8;y7`pϻWϿx i oIU<.+@5y\eI@%I7)y\eIm̋hΝTf{O6 kRpr\^-yٙ<!T>9_}O6[т<*´E٫;E ԙ9Pá2 L[^zEb[:=PDgƲ/7_vGEPVAB>c0}G>oxуˋ; 4o/;ucCU0 0zzj)BRL5+rw@}K#5feXH݈5X25ma:[)̔"\ЁJw=HjRӋԙPkCm3zE<6J0an҈N1z3PF'E:ied< "t(E l)u@Sv1d: 3zEZev[̗jX,;U 1z"FܩE% 'N1 0O [(0zu^"F)⩫i%g.ԣa _!~?ơ,"~n**+PY|گ# xb𻉹z uJi ] 7cV%*yK% UaM8g~ΑkxR3(gۉDj CquEلaPՏ:=jlSP-C}R辐nQtA§`$MR4OݏB2HKHf6*{R9b1}q/zC nfCi,cϩřbbPtPqgN?^FV*Vgj0ȜjBUM Uv RyBUMP_׀kaָ)0gz3P#.`:0%Ě5>T : l]6oM63pܪOll3ضaahV"*wB 马OLh2e=FOp0qsg{kPW[<_S,^#BiCM_$k*sb(jgju"YFv!Ƶ*2* #UCONAͦB$Cރ ъG!yC:p'O[#Nrdt\h 1 2GI!(X =C$^93iusfeǯ|ɏq2\G&`Y"\NɼSFg6ơ!i|e!>/B%ŷs1l6zbal"&~_YB$Fl@~˴ )l,,TRPZH\ =J!gyPkv1n砊g@ BCUj~c(D0 `@u*Wl%pʎ r3T* ^"ͬQdЃ<eOYP =bc,*;u"7W 9y)ikV}:},%h*/ AŲ;\({ҹ8eMkz/cPOܩ(/!1#Np'mZH'{|-Wڈ 1 w!܌ J=5MPCRyTU=p>{zi*,TfTjR~y.8{EXZC%}? 1,qug꯯+ɨ OO,TZDGab3O|t3pZ"юuN1dGf-1 }ʐUl6PRȔϪws}hCpּ`$ʒ=EK;~1dcNP"1O: ԽQ'hPC팅.^wl_ܚ14CC ѝ|14e d>eE2Ҫ]0bM6ItP[A$WlI!dɪ:Ac&I8v{ȉ3پ7vL*A6 ClnlwSqHy^b=.xSB rDEPY:ˏSPYPQPTPagPw-,c-' 6l = h#F{a)EP[X{{ؘn^4&Ro6 #:>4 !KG tzقxC j k=uo'fR(%x8amdVdhM7Ç-cp "x[4 FxINi{t4 t_5+!FIb[b!qO-/o$c>PyZC}drQ_)ܭ$>1Dx)!Nlڍzթ$h XgU`.ԺC}Z0Ի&# 257RT;"/g=6cr|VMJ.ҎEڥW)2dKiFPWy8u k9koAXFjC K!25w_7fa@?_ z6nPsP^cGMATcPyQ@6Qȷ`Kg7Ϧ2mL K)''8۹m?B_Zam Joi2;D!SS:i{L7yLfwaJk8/ڀx꘬LSƌaukP{%lSxkoكfz/OE,D/#̪]z=m7EHx0rDĉt5d~,Ԧ5 MW=y$yiZ;X6.  6 izB8OÈ4Y٪a+\p-GWƷ 5 eXJL8RD'S=(fLVs>iu{ZL Or:u{ٿB<~l?&<^wg[Ӛ>1xc ݲxMr<0CFժs S{&|DLq?Qdc|n@ONlXRFC&뉺1vʂ<ZaaP}=Y]5` %p<8)3Z1c( ;咡v#HRP['.j {h5M&Ž]&(bòa,@ᡱSЊ h [2;=:/~vB-Xٽ5*yAg*9etl.Z}UotjPeG>WJ!d)1CVɞ18%OB}Ugt 0KvYB}Ugʡf)OP?dJ ~*9]X?]VɞqU#Vɞ1\<9G=cQT/Z%F~/Tf,+jk״>Ҽ6l4ugӝ㴉ý Ύ~KQ!1[szjA!1wՄX^d*:$#@㘛IyS1 sGM5aȫ`ԡc =dž!U1&DA A:Br S Pˠ-c(@ Nnv:TwfGZP+۠U E>iWJqO <*Xu"t+&[ A'{7G4QvυU E>Q+#~ZU,B >'u~S<5t3ի~xӔX`ҌYL'['sz>1 yAnlP$V`>k )\S^?aɲ;R |3m_T c8)u&jIF-r18g1PMPљsacd9`ʖR5>8 .M)c a$gSg7UJ[#( FXYƐXE}T3WJP;Dۉ$cCew"✐7 #CM1=U nOvHv[:MH; UUjưoSPE=0~mTCm(2:2BiG=SPNz?ӌ!{4_HNRuH8H1B_ |b?-ۏzg)@}ȩE~ 3\)㶼8;1gs3T]E1gjd%CUdCRP7Y%w@͐})b)OUolKG9AK-VIDATfuY%S͐})"Yr6idifȁ)!P!`OAm;WpMY&"e>96oV<14cQ9C 2#*3G`k+wy}P

0mnN=_c@Sgk/?6,*P^T}B8.?7\i AAx痮@6OEg3P74z?`)l=<Y:^-O],?lπـv#loQ8ဣ.b`+f_UO # :#Xm*$D787Xk@<eXKGu7s{ѥtp <( sl)M>8GOB ^߇z]%px5e_~;yW:KF٩ 2Ko6C!z4'*JZ%(9UPߑDB0d ؀i<ުAoGuD%bpc-J6q,{ U"f nrx{{LZ*0L E\:W1@"ګƄUd܀9VsPJZ0>TK81_P4Tl;UK8f<ߐ5j* 4T觎[d ԋz C ST H^2h1$:"Q96h/0ztSzZJx\Hx|rI֫=P< od~q#o#h˨Ca8^~<|Z%iVw>̓P7q^jjuO,db& VB~@? Vk3w_D^.T.ٮ(1q_uh7Nra%%ԡ;zC#vƋYG$Q~Xcu NAs%BZS_6 gcn="}6;``- %M-gr*Pm;Am"1M/* Vю&U_Ou4u[WVsLՔV/!?P~ ķ K--!3WV7ϙZpA^ӳ=ƗoƏxeP6?Dٵ: N1,C HJCS ̤ äCHR!P6g3~ y")_M0b[C*6)C HRY;~ @-V^chw dL;?dۢ?l; 4BN_Jv+TzoⷤUKxi}8ݟ'K7x:]Px-1z*a@ jk%tnCQaBqxy{)j5 PzsPGKт(P?o74z@ZU7CtS a*{$< chn/AuPz f9Z񱆅w\/ml\]K@-JoXh ἿAf3 6``O$u!T͇]ENP R`P qd/M ~. %UPs $|"| T)9; ZbP6GZ]/7hVXe-6x(<:%ݍF_ Tl=bhǟ Qpt<"@9"6WvMH DZGB:CeTjpj`zfׄH8߿ݤZ kִ5iMkG!M#< B0d‹?z4"Y5 UFS@;l!8d .3ϪxÀ,_!-'T3@^P\Tt/ P 0dgJV_p,?h 1O)*0&zb``\kZӚִ5-M Z^+b~,1O=e>KP6ænL̓)C]zSU!PY v'Eɘ"&8Sz6/Gj : S}dCb2j(z6FTxwjtIME %wZIENDB`gxemul-0.6.1/doc/20070128-netbsd-dreamcast-livecd-1_small.png000644 001750 001750 00000006444 13402411501 023422 0ustar00debugdebug000000 000000 PNG  IHDRt\aNgAMA aPLTE  %&%&'&)*)*+*,-,./.0103435657777879:9:;:<<<=>=@@@@A@EFEFFFFGFJLJLLLLNLPQPRRRRTRSTSTVTUWUWWWY[YZ\Z\^\]]]`b`ccccecegefhfhhhiiijljkmklolooopppprpsusuuuuwuwwwy|yz}z{{{~~~FMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDAThZ {#"dQkWXѩ;fLvJJK!4K -Rzv!0[̍t=G| v~|<>~v}ܫs[NxWO^u_~rW޹}ۯx­7z֭h_'QG/{iGKp:LAV,G[/fӢd1rLuPm(47aصKc]mb ).c2jha/*ێ{ Bv{!~O^49U^u=ZSeqh"c&@c /Ue;X4VQXB0FQn D 4հZ)#mo aoZc;q:`[dh6 :K'}/((R)a ǹ}}]6Z~کxϤ[Lj8M!H/:8#<#x>y΅a4O)]Iw"' &tza嬕DfM-,p1#u96D$)N*2y ļ4b& g:eo}hGM:HmLÞeTJiIjj3qZv%R;EG]XzvhqZBĺR|0/^8dF9Q0qA9MHn)Q($Bt6| iQkv|"`?F{/Ԕq6AI2[責Av&m\Pի9gЌJK8=g+NẪbuvzݜhDzsKØS:t-.ĵhcJ:uK+YN' R9˳Ťz`ҔqUcP5j\S)$B.hrj#Yh9Lmsl%/h"ʄMܐm1 &$4E#\ )Ą#SLPaIƒVZ.k`:A! 2r켒~)> H]$,v*ԚJKK`brQ8I)Hd#*_-|BJ^ݢ 5 W3OgddLjrd*m^a׮PF adt l/:TS'k}\џv;K!sh[piw}%֛YC,%- @|yKQ]ˉ$B1i.&XE#,_n֭S %Uϛ޲5h/7"gqѓ{²k}//6hV%D#rUmXRDOp0m/9_/mFlbkUG|DWSSɞXiCz:- ȸrJ9J4VȧԞn2:v% bd} j*+TAV{¢#HGŸ.* E𢔲GEPԓrEUlhNq;\K$Y >-1]Acj)wϲ Ie}0dؚ:Iӗi[R-V; e$-t"F䀞Uy$]bi@n# bsMjuI&pO/'BѐV~'0 R6abCbN]" u)+KpiS O8 9rH~:#8R.Wr&97eq[A o 62[Y@1S3A&N~vIxMZM-g]K-ÒHw6$ي&d>.vۜ6Ҩ`V^rW0Aj6%33:jV-lw[kvd/*JuwhT^E^I8@=^α*'MMњq{6o]aSMq &0rp>)Ru|RUY|ڤ̃gggLS~{2R\D"'S1П h_eM)kas܋4CN) 21ZI+Io,YE!+L-TeK6VHd$>b\ E^@j0$EmN4AнLpج>9tdḮŵ]} ^"^|ЬdpZrx&cleٰQfV6`FRfIN 4Ou Ut3HGN 6OuS_i%Gr fjdCR|hҔ%IЦj*?.s,&˲&J K?is~c7{Ї?OFKtOHptIMEIENDB`gxemul-0.6.1/doc/simplified_dyntrans.png000644 001750 001750 00000010423 13402411501 020546 0ustar00debugdebug000000 000000 PNG  IHDRyʸngAMA a=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)|nIDATx]=:9z}B^`@( lhu88 l` HJJUgדHJO(DNard򆼉!oțm{TG5uN:k/fRYĈ&xQcԈR|nͷ{U5"j|Ϊ1 HF:2Shr p뙺Қ Zeڸ#w.󞟰'GHT+@$_[Υ5wޭ1nAc@Q!x jkՈࡩO{sg|CBnW8PH"H)Xksj-wJ?;>49?=pp;DIcfț #!"C~!~tެ!oț򆼉!oț򆼉!oț򆼉!oC>ȋ!<y!ob&!oț򆼉!oțU]?os^y3xvpU"fF#G عHq\}]ss\|8p9sܟR[!197%K2Ҫ_Ə̓Ls! 2!^QWEA2Ϊ54f%+Jzryz!e,GVbj. Tm(N& L &ZDJgvM>!8|p Ժks=GҴP$iO\(f76!}PF "AoiN$IQN|@I(cx>w 7u lp_iPYu7vbES_v:O˳k|tzwrYWyim61';~ڐƷ EKJ@uVաxڳS5~:LU^RF\P&+$Xj1Α6_HLsr/h|PFx^4J bfRCPe`H5Ըrksz& 8Xe߄DvAC`T6kmEnJi}OPUr%h%1JDL^iV| ICc$v4$XhڀCgnr+m c?|)Ց+AJF@HG 2@ЗA9"wUl_߮˚絯rT-/4άs НòLDI_ؑF7L]B]˼m0N4ymAg ٛD?hl]u:,$XqGs#rW(2ד`y!X"h5cco!ֹ(XcAh.Vff ZLqh1@m^ME@\P3r,$(h&<||{\*$7:wL'4"3YڄRVx"shέe#t+* m(r\:z_ώ=1ƹxCI.vsV ]knVpbcLeXi{/qBh %"q6c"A~W !J Pi-S"24+iB}ɋ'@_I0;42 03 6TODĐA5Lo\ϟmvab!coLآޟwm VcI<zݎ lOYn " 矆φ}ِL "׌YO&;LI΃xn)Fx,~SH>?My?F~1^?t~]#p'o/|+__,//B|{+DPnc髼A˗o/_sxy_`9SQLom7: C7(kx'M_M+yA_zlMWccj_w^ }Pr#>gPK,w^1`ky//C^˳! [xYQK&s9T:ےQ-,NYM +Z[ ІB)%BBsS")7;\2g ~&uC9WiЈ0^sS\Rm0n -'hBѰS?~OP2%(S~jTl>>tG,ɨp14ċcVOt ,?j|x(ME6z'D|h Wt檌|HkR̘]xXøYٴ:|Cc6gl!ᬔ<ă̳`NuYR1=b6Sg#Ҡ7@Gq9*'zMdt*{9Sc*ϤPpU#.sTfMB}U5NX|52f L45GG/0;8ɼL+6C{? XrĕDeYTeÜڐ[?+<lӻ+3C1fYny|z;jY16&!ob&!obɚʚyCyCĐ7M yCސ71 yCސ71 yCސ71 yCސ71 yCĐ7M yCĐ7M yCĐ7MRG.e_;C@+6!obGOttµm"?S #Je]A+X`)8]uì̈́2R-A(m[GKݖ N\?Ogw/2UưaJuՍAw#3MAGm0h:hЩ1MڌJezxO!/- pǹ\r Ƹm.uRh\u(yvUY\ƥnE ޴#؃ccNb`y{,צOƘ-SŦB0kcț!,g1M yCĐ7M,;:ztIME( IENDB`gxemul-0.6.1/doc/debian-13.png000644 001750 001750 00000040715 13402411501 016151 0ustar00debugdebug000000 000000 PNG  IHDR WgAMA aPLTE^ffUnz8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IDATx[z8ϭy ~_={"ʎEXAIdk%RI ?]w |_?E'O AOЮc1]pp!)4ppa?H_ŀ]˘=c|쯌} ߼o >>>>klW!osZ=+11|n>߿>KTN>.O>-~-U.o>Yv~~m w6o!KaPц0AZ_T-axk8`_z' n]S n?>ayx4(v6:Xxn8`A Nc ډ*el[?~57`2 cAx g*+Eka{R,s=w'ˋC1{i";˃(݅1ȭx֗~G= b%}qy5:IFXS n&1x 1 ! ʻyGopb n?oRj^tdjy/\i=8!k"ʣbp ʸ.rwЈzFL0 :pDT'pbdQ8Q( 1[fxs_e@Jk09xO9ln`|ylbF{֠`0v/80([~t?< .bv~a0$ld4 > ՞ PKrH0X/$ZY~9oAWsl/1ڵ0x@u5m ]dv0C·AvN<NAHYf1L5(-J̓uuNC¶iM@ty̿@݃ScЭC`yP K\@݃bNJFxkց P105 {=x TyiHH݃3O-}TGkut4l@݃bpde" < ̦hx)Ј| /P_#m̩1yaOkƀs`e:`38%k4n@gtĈjBY0|lSи-0_枚 gp`= 1ja8y) 8y С'00ЗbPcV0``0ϧqX-B8 ,B}3G4n@c &/Es*8 m0b@ `/1LՔe&;Rv+j4/#tLde ϧbBً vAM%1 k&2`۳w4ou7*X cԽc[ 8](¨\A'VhTRàeQ0D8NDpL,6bsRV&5| k<A">v1 P5ePZr4 Lq[ n b[en,1؋v[ 1(`ymZ  Yi B-Åu_A҄{=B0AX<~L08DX l 2`# z7XwI3nBpZ jo?[44~Е'e:0|}׌]`mЈ1(|ݚ^~ f6.xV1= 5e2~A9ioR0_@]=] )I\8g\+Sq`kp iI F1xk |!:oЈFb@ a}08dmcplX/ycܫo/ܫoC כ|~q 1r 7أgI+c!r|gkp\`Hg)ӾxYؾGʈկs˹k^O;?=d$Y qaapL`E2oho0K _{ t{U$ el }-MV a `Mgf^bz)Јk.dO~CNӘD9ᓎj&JQ*<1xE x2Lb~ ΋XAiѥ)p/!R(Ey2/MnU:2d·V΋k[,.@zk4ԓ˕Ϣq 'Ǡkk m &zկK*xO;K</@ NEݰo0htJuXQ)rxo(-~l,c ,`L (G OKF hĀܫo FWEfjMa|렃0S@tPA8]/^}(MӲ3 %}{ dlWWa Αu"0C7I[zZo dk:ŭq}ET2c}zc zUQb`G~v"[z2٤oh 8}^ O`7U3Ā}H@1 ʹˉ|w lh=bp;J<|p_aT޲@`.b07 ډ_ 4b@#Ǡ_P]?cA_GݮaRfwDOan!2Ġ3(\o NZA{Lj-hF$<r޽Z ^5a8Wa LS; `BQ<]~Y}0hf"NK>8i5[Eͮ^KU(ޒ" \rn.`Q}[[~Q+fj8j'5/%1c-N` ̷b0z)Šu]b< ?(` XccѾC~1 AsFx{>m8 02M~.Naُ80Ckc~nP0kdh g}1"3L4b@#Ġu 2oڲ2q0 #[Z֠ͣyGܩgy?IS YF `tb|ʷ^ bWo6 0Ġ@,,>}ϩ۲Bumc]@B}> e0bus bkzEocp2[)>6R>(nUH834URs07 o)m1(TV@Z>pxX}\!]s\ [?GkS8`}-<~֠qIkY]bk0M|S1h[ t0Xi A7z-#xL1@@ =®2tDcް7xi|@Uߠ ?eE݅SQXpѫh|藿p2,q:n"_ ܁_ 3[x_wqЈЮA԰|ݻ,9+綻~!NAZ$[=Qy's[ Sq8aK|JqvM>Lϱ%1} NTr<) yj T_HN iHA@D[Z\K[$5l/~݋SXj|@W+G VƜR ְnsH40P_@]4à؅Roxcbzk|DɄ`^~Ej@ 4]DI~A@C$b 4eaW`/N jnؕ?=f M\B.xo`Ǵ.7R~:iFwu,1Q ^~. @ATua*ns.7}Mk R~>RF?]MgE'N&ӈЮRo^P4M7LF:e:?Z ,]d.Rg<r*7iGe~>2&|7AQgY40 cAlnhA&k1m`0(aP}0oV`9'o4e/I͛ ÷+}˱ɜ${%(~)&-@A$ hN A9у},]@)C=Qx* Z 2o0[~..*n,<Ϥ 1䷤L2 u`!G0p>{0@'18 }\ALL1ۏS N mz箜k|mH3_Nkt]kj>A׬癖)y]%'euߕu .Z1Xы.SpЈ8fP ~nuR_nOB|AZb0!pλIηz =˴* r1-8Wrq2QZÁrW|6I[0AANV5 BsqXףlIZ i^HfVW |I |\ 6KM+I@S(!_<(ZXgxcV\K$F.mbU Xqјq5֎{j M.U^ AٿAЧ6x QP^bqWƍq#I]*` (|+c3# (m`v`0q,ߍfq6;@1hbva0[DTia0.Pg]K$kz7#iykA9Zh98]zwgbs`poF hĀr47H.}u cb1øHL~mϷ >Fy. sL ε{^:# 0U,>TtΎ>{~V.eT\8s#8f]_ ^ 6Qs軟̥ʉ1T[;y1̈́kGKǨ.ht8sݽDŽ44 T| [cH~HM蘁Ru~ v'1@\a"10%N`f!psN蘡.BSE "jj8f"/=q2)b@ ]1%ꗜtKNz΅qs[u?뷌` a]ixO?} 2y, ۲U4 ϲ=ϰvt_1ow0hBAuXwwa/7UB5Q ~U!jX6@\A[&.aɉ:l^ ;@@RmR˥P1&oŽ ڪɊAlVW&n]6fAaɃ+u1P'3WXr#BW%`&]ծL"ITs%Xrl`Gߪi<@ka 1(Z'HrIrm|oi6VaML?NOAҥ1((#rŠqRDC~t˯n_˹5N8­A͒ALM0LQ>jh Zj >?<ɏ61::R5(Hj1]Hb0+R1:Gh)MԅG [`orLl~Xc<~@&ri~ }zlap$pJmOݬ_w U Jub ֤ވ)v]Nqcb;丆lZ  6[Usiq*71yA^$n:»}cQ7׮t|Lv[_d褿kN-Yeۛx=sK_Ƕh|խ,w:%'GbPē+* q{xǷZڔU B94HЬcw0 op$cazS x V)c0Ą'aX6͏ 1TYwo&H=6'xx-7IhKebGj@[;,(M'C!N#19t,ߐf=4b@#M b}>Ez=Wmbd^1mX[.ˬ~oSi6(+MQ@g1Pbī+/!6_g C K?`'HyQamCg wp9#.9as,WŽ ߱e-5m`&\ΈbP\G=N[4-*"Way3YRl[&$*NJ~.g1cJŢ6[ d^@ҏMҒz J<1bb%xN r@7H? bsxھ&}ӴĠ,S+n-8YL@ P7 պk=n{YlGz ]Qd;k9?1 +mNosĀF hĀF 4čp^հ//,N9u |=mY/j<=qH Ʒ0yhG9^{DŽ6_n;Ou0a\?+&WW+``,ĪyRwwJԉ>ȇej`m(sm@V4VBKA:E,0eg `2b09am >) nօI fZӎc 6f{0 мٚ]=b ul%p>q< `l{1ps&7`_l.S5Buw/j}SkP@ny Bc`rr¾`k 5mU!W1x= @pƀ} _ %pp} Ci$bMо&zW~* БFB;zwbpde}wڏ` +ȝ;rQl=e^ 4b@#4tϪ\nߌM8@{8Oa!ueiefWmQV= eYĴY޲w/=F:]ڄumM|ĻiUK@]M@x=u kuT yMutLpZ^r,o_VgAsqglA`[Yg謹,tiU !ye 6>yEpSl; @ F5B,ۖV1꣐cbFl{ b` n`{`~JvKq|餎)cYd_Š 8=0vsV`R*càfY!$}81NaOs f@&`"9# @G `{ U*Mu`^/k k1 `vvоFCx7I :D1u18| m|FlBu>_M#F1ֿ^_|x 7+lP8-۸$nݜp] K5jWqNmfK>fȵ1! ͢^~s7múe6 `PYoh|͉PUNL1hcc &97:Z¥_  |+[ T"#u=)SbM,jgr~ Koӥ1( aeZ7=1P]I2~]N]``J.N&xf+ÀK/%a 0}h'}M)@ 60U 07 =k99x:e70>jvxˍ0ٻz]1p!ATxԸ;Rx`Cъ@183\7/R1"O8LLIb9em04wX!18m<[-@Pq)+" ?i0h^@}^ 蟨e1N$΃̴̷?u=o VFӵ<"PI_lN1xQ a݃_ 0}̖:-AL4ko>z-2bHA>3?u!ĀpzI<4b@#4bGv+}Ƚwi0s B2i0A`zZ0~bHkw`wV꒔aAKUPO1eSrPa,s`api1RU8ejjUt: ^ ]r^̤[MS i Ն0+*-ušKjc$LQA]-%1\?\7͘e9 r4k\B!+A\)Sm 0h`оbz<0]4RI:bHޱZB]6h pU b`CWɽ@ o1 Gۡ֩ڋf2.[G `mXࣟ91xI< j? 槧cPb _ Yha` +N ;1 숁bʴX{Ѡu`},$aG 9.ǎLU=R :}ڜ叩M _ M&S" r]7} hĀF h F{f($B'yF'2àj&q< V~{bS1a[!|\V0E.Pu,ng -gu GCy BVvy )d]mhF XD | "C:mè9`P[DZM>@-H{1(d,% uŠ=G`,+T '0@71Hm ~Pt0Jo1{0Z|? i2D xމA]aα =G RAcF `@F']mo0ĠT*78X&ȨCuޮjhqtVbx5,oa>/#{`kC_ k'CXo1,X;H y_}D z\fS(1S1vbb5-`fmb]uu؃k'-0fZh$tc a'XvbP71o۵z}m so0+cPo)ҼSrX)&v`߬-pawմ#ѵ_5?n'e?^gH;bo:GK}}x/?:Avd2ЈXjݗu?B2݄pɻc~w΀A MbpxUN>TʭsA)[jς^_~%.̇_W= 6׼=%+`..c>|ȮhJ=ŠZ?dS֗o۝gaGqPsj-%`/_ihwՇrpQ18Ok<1M}A|01?>P7A ݴQ~%jRⱿ1Q>CGi~,e`́HAcϛc/ Z<뗺CDqp09f賺O9nW_QRN-hNcKwF ;eytA8r%HYh~Ykˡ\}C듚r'Xgsm;XY*^ `EoS,YN0ADHۈC Tf[)y\}{ *=+Z|+0P'qS@wqW4T<:gToK# s1ݏ*I<Aݶ`P3 060f܁[7p)>Q71oC7y@apyc/22Ƚ.m 5Y_q _[yʔN;A:b7Xwd/_ևS{7Wv@&<<-y+ F%|񼿱<[\ãϛa@#4b@8λW|2 /A_" b)#`XOYT)>^Ω_<(pd9u0'u:ص@6ZsSG1 %wA<4KP@`0>Z `qySg ){ "y]$Ҫօp @X\.^Ii $x- $%ڜs8p" ~񻠼.LF.B?оm \;> +b0q0coP>C:M>I ߆AKO@! P8REX7媎qllkb@>11e1hu Y+X(f4oF wa^:ht ou,.2=X7pCs ƍ 8^ ~B {r=WBm0ay7/߈ 7{:w`60X0p_a^A 4@&<_-ۗxz rh}L*qqG1 : 2q]g-/ )u&R_ BR7b0pŕ: _/0I_V&rCPmJoRr؃+hyT063!{})2LX0ER7b+,W%Gޤ fm4޹%?elo0< wK^0^./} {^bARUXZ @8bx֠8r`PW maA@mqh!mU^zz,'"6“ SR{N4Mb i0GdGw!/0ᣑA ZM=ec๷1nm>m7@"~6zM~ JLhG cj́jD']4'^KuTJΝ/@dVzJ$b@Wq8}wfh)-J{?a Jrm qGb4} ziĀF hp x6c ;"q],I,zNTx>c _DV\&Q0  x0 ώ-`&E{e8^oPJA  bjeR77_ϗ]:PW+N ?xfb X7.P:q:Jz؁G0h ZnZl vktbDYbJո~2Jj |}C b Bh1]^_ZzJrwźm7ό-E.7BCq:؊(pj:r￝p: DP. f'|T hĀF hWmM|}N/]#`cPg7nk O4\r g7X{ &14=EAQPo 'Z^fxokoP} EVq#N@_(` 64# -uH[b V[F` 7@5HۚJ{1p}s]$p\(`cxx|/V`&^)`u7X%@=}&A(*N&lyGK {} -x?of3iЈ.3`l4ޠ9-zA3}^s7h}D~d x`pxqA$ \fD>KW:2׎5h0x>K|#Z%c &@;OoAW(>wA \  gbIܳ8WAx} +yW%!AY5% \pn}קX hж)$]< Q Bug71({3NL5`ڱIoP@J3̓wjb.8}Y 7k!w=9A ΀2 ~<`]u^$ޠ1@ Dzw]Wȧ1 5оg4fwdi&q JKJP ^}P1p>~~k%S?^Xtc$@pHg-t73/A^k W,ݍs=] z ]B aPv0ׯ.>OR0h5!QR|~-Ae)r^N=8}&C ?TWbc2~~ж1`[M hĀF hĀF hĀF hĀ7b@ hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF x#1 ĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀ7b@ hĀF hĀF hĀF hĀF hĀF hĀF hĀFIDATF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF hĀF h1D1y#.'l ."8R1111111ڝЮmShooگ \4T*<1 7 žK2|E OtIME &L躂IENDB`gxemul-0.6.1/doc/20060218-netbsd-evbarm_small.png000644 001750 001750 00000007504 13402411501 021326 0ustar00debugdebug000000 000000 PNG  IHDRt]QRgAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDATxYovgHrHJVI1VbN4hЋ) kO/(>S6m6E\IIZDQJK.r>nҸyhB`83Ϝ'Qq?1hn$hg,NNkX|3KhΩ643@әvDSm0ᤥRa۝|> ϤL ג#B5KI5uZٸuSEܙ"~/m.;@=d?,\/ TZK,߀ gFM;߶/LB]Fp$‹BzQƠT.G A)T׵?hDIOȞc'0|e@sCw}S ea:Ip <g ڙm+ǹTCʍԨx'2pez{n5aiZ' RM}U6GA5i3iH#}+@FAGV|x{!.Y ^i Kҧ h&`ORj_V<3:LaXPMNe~c[FJ'6:e\Mxd[I<rxxyNy0S U|;)p>^vZTr΀)k24$}N1CG(i@.Z:n !jK uSo.rQH~{1Lxra'"@P#Bj[<=~36n&Rtfn[lULp 7+A7LjB{)i)Uz {ʪh!nN0h},wn9b=7OTn"?ww0pSQf}e!TQD{:T3&0 nE&' r6짇) ! }>ۏ@JugLL_ٜ)} pX4 ܻ?P!@OZ5U'8.Cj\8[֢I5<3kKǡI!5AWoUWق|gC(x]Sb+ڀg 13u䈈4Nc__S0Fg/ݸ|p *EߡWs5 O_:gިլ![skJ\m|O#'2+Ē~iӓ9jiB10ԡ!+c Ủ)ke}{Cx3!xF_!Wb;gSƍw[8M15{qg))#Bl2@4ޭ.d%TȚU! B&/fHr)$G 9"W,8럐,E>1TWhxbRǥpD'ƒ@=E `( ׹tHf/dsACzCC&E6D[|RvJ,@ui^f@g`c돪bk>U3*{0k ahXFYb ȣG/+&|߽ !'EjbUp8~MN<>J}ٛ~@+TIܻq֬\D'~⅗geq,{dv*&QB{!D O1lcg ?ŤGx{az>)8WESl}?I!#* 8f-f飼[ETo 10^ArZY*6|p$;39˽ȥ;/9Aq㎹3a,@Dߞc]uEy R1G4*p'a@xӝQ SMC*g6?Ok!keEGQMM I@VI?)uhT@mJD>%C(9̯u0mҐ[ipS0˙_ NQ(*~5%} g{so[шt(1F#!' qR@ƙ''W"+JwNq#vJ7ڧQ(f~z:K*KrPv6;w^+8^.t'\p|c-Z643WcmƢ@?$(M\ v;1)зP~uA(%/HBKdsK4TZ/[>'隣؄go7ߨf͚ ty$1Ai<3+'yRǑW Sk^ɕha+|6Һo{.G1UK=^]g^r>x&)EOo"Q>WYޔگ^uR2MT A~xqJ7FBE`zƸ/fKeJƱ1Nl/J"=[0pF26Zp-(I-{쾿pl(k}zJpuFH|sZ{q2#oE}$cH]5V_'܃K(JVQkT&E2JS19X]R>YD rx)YSVfy񼲒ׂΘK)yii>Kt\"LS<~s*VlBnW9}R?roIHڎzlKg{ GM=zm(v ӯӂĹO5BN'k ۢ!\%E[akv3R~(qMo綯NSJ-@r=[Bb̖c @.O?=u}l~嚡a"1NӗSa.a*/g$H-EIU >IS\C0J`]vM)[ZNy7Y$=h[tvH}*hǒru jaJ3C aǥF<4|/CKg/|1N %(675 \ՉcQR>psp(뿗zQI7ublm-11D ; SU|||eKۘÚS>vgmUzD)6;rOݿ<(vg;7Ǩ;Nz7]p8o=~z ^y``fͥgo?r`AjDu{? sCJ3gCo 1>>">Q`_-|7e;QVسLXuZu6s9su:>j?Bzq)h? 1{~A`" ~={=,g`>=ˬi_JKcb8J]ڔa΁ɱLu+lм 6Vt[pE+p;uŒy7yz~vN^ʥq #}c zρ9s@yNepb=hǩ ZG)ᾳT4vٶe6~yYέbG4LsBVZJៀYĨkXa,v{'|M_HٔzVjٚM S6+`T3ԗ2nd*(O8mQr7S9exqz?IqsPH\Jp(0<yqp[1jx1ʭ=E~hyDy:b^wO+9sL 4Yrgj=F}QE=QqoA\u~Qr8&@lh=LUAN0OL9p@&#( 4zGeY3o=&ۛ9Ҝ 6rE89=@~‡ `fa%,00~q۔/1 ^ 도m ~kT*T0R`n ғ|YlՕHw(l̨r܋  Z -7~hTU998ANN_D@;Fn..nzt5}V܈9&muk6?` 5D~`VA4O\Ǩf*f)p_l7jԆrq 3=$b<5 }w)՟^?HMOH]#ң -9Sצkhӂsݮ-v_ÉhD~dn48)aW:KLGNz;|p [|e' !Kkq󉃑(<s6$@n48)Ugݭh#Cp3ȉTogxqn/Uo3s>qT+JfۜZJšTOOs*7Pܚt=d3|x"#Is'rs=9-n':{'6S='SR^u|;/@oa80$=s'JAM3|NOgkN{0s1si ~?jzF=|5~cjh>q-O}>q%Dg|"'0x[WIϢhK$SI3O]xB78g\.fv|n%|6w;Z' [P@lrRz |RǽRy3+w; 2[OFp>1e[l`t9'FPH&`hֶe Y|q i 8zJ134q|rdC`L|  Lb2se6 mB,8Qmlg)_nCHYye7!=oo'I=oQ|H5k7s_\W=4B~@zȯ(>פsC~@F!? =oTȯHUk7C~M~p]|!&_CFFzHUCFzHŇ_Q!&#=WH5uC!C~MzH!? =WA!== VTCzϯپQCC_7/̧磔<zK=~ hӈŽ{>]ӧ_~\Çu/ }`mNVO;e?r%(V7LZMp,l^-kT'uNſ>dA]:nݧYwNHwa93݇h(Oa*Wԍ1,zu4O_e08H^~\a` 1wyO &?ɠ?8u*m*=,'K1 n0<^wqim ϼTeJyPVWY՘A<}k ^->z*JAq( %5Q9V<ՅCH,C}9TH5( ;u A=  "槑ug/:/ߏʳW<ӯޚ㿎/{k|+O3fw sa4Co^;a-~?|{ze$^/yux[N7w୞. QO.n=1§cP*yu01x0x : ' s t0>Ӫ_XNq5mt=M26 1HztOoa 0@a 0@`` 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0`a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a `@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a`0@a 0@a 0@a 0@a 0@a 0@~쾫bw5}c ?]e؞xs~|7u><=ow\%4Of߸_b| vmx?\o"NݜLӬBޮ8m\Nr?\u;ϻf ׻t]^do-/Wa&al70X,w~e ifk뼂-|[ 7+Xu׻(\5|o[)bpK;z,@A%`@a 0@a nA?Y:}JGgMhe^"\2=gi6S!`p] 2OWnMPg]<ͮW&!O7ٕeo ζD,L^q.G-r'Im23׹4xeBI.Cte֗jݥ A]7ć» vr~gy͹uV- AH{q3= k*bR+:]zFhtYH`p#_&e^  0!|~a´F 0 0 0 0a 0@a t[ 6'gꙟ)<9v=~ot1;MǶ{zpMsma82HÙgqb삣Y.Q_apnO0.0l<c| N=s >r;w({# *Sci4y7.T#_{=iZrX !r[aS! \!b;<a|appm;3F) c_n7^gQ}z]~4͊n1C1~9}iF{ narxtw p>>2+0||aPa<G ڟ P q f`2^B;OnCE=?Q8' il&c2&ݰ*/ZG !>M}} 1( ތ;;웸k:;C`[9_ NjPPCx܃r[c)ӎ5ܵLǃ0㺗Su9y|rV]5<+uv<]/5cLG()!O4;U1#};ͧ  Fp ie$ڝק CY c!#` ʸ sa3{7n>tx8͠9b4{7>øcybn0C`~x;^7h&8fP> &$ 2{PZ7&ȕ}}47Af0.@R:6t 1 NpzKax ЎcǐW$MC^% &cnK"N.kGkgp;?=7K? 03| 8+Fa 0@a 0@a<2nC3u~nc<,nIw<*n'ݑ8 .z8!A\G0`KAPn`K!zq7H_F |[D 0 0c'@a 0@a 0@a t? `oa 0@ʠW8@a 0@a nn: 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@aa 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0 0@a 0@a 0@a 0@a 0@a 0@a 0@a tS ^1xtGg/^_v , UD l)a 0@a 0@d.1Z{F>BBCCGGHHKKLLNNPPQQQQQSSSSSUUUUUVVXXXXZZZZZ[[[[^^^^^^^```aabbbccfffffgghhhhhjjkkkmmmnnnoooqqqqq{qqsssttuuuvvvwwwwwxxxyyyzzz{{{}}},,00>>AACCOOZZ\\``ddhhkkmmqqssuuvvwwyy{{>MtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDATxyS@hUi=EZkcm!Fihi5MUPn׬4{ԠtYƾ~*0ɣʎ>{<09o9\FJ ( ( ( (DWUuoO B[tIME4K_jIENDB`gxemul-0.6.1/doc/20041024-netbsd-arc-installed.gif000644 001750 001750 00000042317 13402411501 021360 0ustar00debugdebug000000 000000 GIF87aHHH,0I8ͻ`(dihlp,x|pH,Ȥrl:ШtJޔdzxL.p\|No~wnWv. oȜH*\ȰÇ$0ŋ3jǏ Y  ɓ(S\ 9,c6q67gyO@U3PmG$ siЧj,S-^ŚoFDr;Zتh1PjJ5\u-m$ٸYnԩ6ӦmZV̦cG|S2Ң!7Vj9ngΘ1xəOW䭪5e٠Q)Z`3FfKe[xN~3בq9`~>gYi8a $`{":'١j)dfjI( c#B&NbvjթBzީ'U6Y_hjjȲ꟣),f{'2Ysv洂eZ'Jǒ -J\]&* V;"6UN9mjjxv`d+d6 ZV L*޶ qz,q.͑4Хϐhm.R+pt@nҡ-LuPBp@shǬkNG^{]=}ro'ǫ0jǢua lnLq$x'INE^Cy複x騧~z.?$U|I_W)f>:ŁNyuzG 1`0R-|A?{1(]ojն%ъc GHB pU1nl!E2~ DR Csu@ GNg+U˜&Bpz =LXbGG%*oTD*NQagE uQpcBXFue x7Fxagc)9#efɉ!?p{#I="tȼyLD;ev9/ϘTxKb COYRmO:}tR{ɏe XM(=3ԅAˬ;F.G4bl־6N$_u)MGV,ZlJY؅,j$۵V@ ΓhY†WC++Za'MKkgK[Qj=!lY7=r2]_THϝjz)yXR #wʒs/"KՀWEC܋ėNKEӲS!i5h\u%s`Vؖmrr*opϷS-2%jF%hdJ V1r,X%4V aK{C ԨWbB@HV v|DZ_zPF6o'}N> ->~V@2]+y\(),XBYe7`-9sK!8&qFty"HZu:Uw,ؖǣ\>pc4}c+.>YO6%>gM3ʎSptE)15TuYׅ3hoH9/FUmxȞ6\_zpɦkosq.2]ݺ#Ndϸ7rY[-ܸȳ Xuor6|'Gd|ۜ'u{\'%%'A/&nb 'CG@tgb`/؋a7Qu+4C|ܢS77.,Oր̘頉v{ׅu֘lLHܘCȁjj2-Wd^%oye1IQXh4{a  {Y ّ#p0Hb}D|u,]X۳A})),G*'OrrDIBv_~&f'o8:ÑaCG.`86ƀ?1rA0#h8ʑ刅<8aotK#6J :M#Ʀnwf[r4dQltHT}gywGngCJoVKY[ x_a[zh+\wڥ1")sk+㚙ǩ-9szP{ˆu>ݕf3NG~Xjו78նFkyI4er+_jeV.('u6(F8v%Uce +% [*101n&X\ۭ%m4A*1BZ<ڻ8eͣ7;مyY6ȫTʽ$K򫢢Zxө_˿)TK\gRhbx"nF=$C9vR[ϵALIςy\u=} ͵k9vF|?+MkIIZY$ެXF~<8HZʝn)5oWyMhL'A2$T6+͕ S[z:0.! BEmmƉ6xE '`ms̘ T>&؋M6 L +ƥ GSGcЫ||v99D۷L:.]zn܇Ƚd騡 qh(A w|zFC}2ݬ{Qf+]Mʔe%e6+@W PBPCק}N{nF[W]';߉7 ^[ʍx6'&ZL+e'^mBLX~K{^Baym?ғ$ʖhbϋhiw؝D>g҄xΒr:+ ;NHxC4-U֣W].>eA5Ǎ ʢ̞~9PNy7fN9~}s^Z .N@zQ\N۳r\ɾ]M` ! MՐ~_}-]F*6[&q}#._Y2@j+ Wɜ) IW&RD\k>F>Y]wkr[َ<\ O?Kk|ڌ3 ڄ}:{ R[aTS? ٷNzsMzTeAOmj-߾s,e/ y}u-Jq'wL o:^>@2Zvڕadihlp,tmxR0 A` PC)t't9mU5:~H ,pfK|N<GMMmKLmbna)lW iUkzv|FVRu ~ˁi3͹~Ԩ0{Ezs7\ȰÇw*5h3jQD]`رɓ(}ҢODLj"`Q=e\ʟ@ }Nnq4m 6gd:JիR4KK3SERhb]˶mGgE31aI$Zۿ^/n¤/"#KLX-5,^hLy,Rs( UΫ+Fͻoձe/6a$&\BAn`8aO6%( +\f5u`NV^1>exc@g=Fbm6E zU/iCb'I%%WOF4u Rb]Wdw}6IcT6T*.甀o8g+lEK(x̝CP{^V院y[S/.% [~ϽۧŒ!=pre@j(!kn֧"v `v,DzhlW9.?L϶}'yЈ#XmN۬t_z4IgZ$5;:T{⋵a|uNNn c~)NOSuZ]|/_T`y3ikfL*9x ͰQܶfN>I nIu$=s;rINr .OBgx()tk؆DtmrvP>rH`|Z IU}zRp/x,2%G,Gq6P~\{tl9Dw^҅cgCwĈ)gA2~Tfd4ݔvfsaTd4qb`af6q9w[#et9:G5a'aND<Égu4ywEhF{e97dSp؍8#qƊԨuR # (<ՕzLhRӸ)tNh{k(C|nWD)@IT8.Y{074yx6ys:iv<ٓb@uB9'FELK0RqTYwX9oZ^)]6NFɒ[`s8pv1w6lyv5؊uPLJW{,UQQ~Axy }wUp8?(7HtJn @Ik`ez-IDh'b 'ոPrDiqn7eM6"ћ5Jp|hOPtHlju{[Iry^jI]4Mq@A\ŘC+I 'N{%}B^6Xpi gdpJhG名`XW:iH*Wwq9`jUXD f) b 7:=<>;BDZAyHJJGN|5$6Tj{Mz=gZ*|Pڥyǥ`Y:YYfʕh_lvbrj] XF;Zk&ħ~:Zkb!t.)>8Rxc(z<ڠ(Diii=Ea𵜟Arȩ™r ne;\҂v0TH1i%ylbWU'LXjXskחШ.*cx'b=Tڊtު hHoi)B^~G Ϸ)X f9閖X f˳iY[ʉv+{Gyj|빊n8et(\iExt1ʚ&7wPԊ-tJۻB B;Up˹i۷o;ZJ.{$Y?`D6&{>P˸\Kzn;^*̧-sJ~C@Fәʼɾ9w\Λ`;UjL::ó*?ۑS̫,g|~|k+\\[   m;!}vx ݎbhgLqU-^ڿ% G9lX \I%\sY%\|@;AH=^Σ5&F 6Z,ȡ}(n2,lOlͪa|Wm_<̋K|UJyRkl!P?Xq׉h@귣*>(M ~G kr{Je{emV{ö ~ٗRl0T$]̟~̝y^㽈zmj Mߨ|ܛ{+\^ڳōW鬲k w ϩKgπx܍+h|Ӈ .]H)>=FNк)v&EU~&ݢ$"9]~Ŕ]. %#N7%֗vطj ʭ 禷fg<ב ?TWӰ am$L<{,=\|ߊ4:JB]֛ZBh@dr',vC, ڤ>4 ۧ}/Qxmڴg.W7^-]>7NR댧dH~;HL ڋf, 6\jMݧnb-c Z0E3]/UuȜxύ x1? N!횞1xw)o :"`( 3ʅnɯSy]Ä^Ŀ͸uC`|HϽ/"_/왱*4<΀Nj(UΆoo%ȪMpT[ vê@y ɾ ĊH*6do OCK |ewW3lˏKzO 5iמ`.;, ?o.?:Jjo @-.dhpeMN؅"Vi0t-8?5~Pn "O5ԁNԜvzxL F}?^2ӕ՘]ӜT߉ʻqoRO%6Nˊ69} 56V(*gFax$JD謰fɓR + ygܺ -S'͜@(U#sSkH沪իrXҳզy`46QP̲GoTt1hUÈj՚Q|EfD(dM?f:)'wʈvE9Qnm/ۨ۸oxpM}LμqxNzqu-ν9}O^{yϫ_>p˟O}W[z(`IM[;DIC &QA$EYH5Eaa`Ț ^l!"נ5zuF=`YY=c_߅A(൓ɐ lL3W7]Xri$PmbeZGef@gij首 šT%q_&d}ʼn0b'"gfwjJ)~)cz©'|"h~u±C3J&R$aT oJql3lH'Ȃ:alb1 mzk{n`y9[O*1bꇨƹ"; jog zz60@K0Y疗(xR6Hoy*lWq \xr͟^IˏLuG檏9jKLc. s63qPOulУpL*[TDzsޒl}]݆]ȅG5i\4%jn (/@Z;٘c!hR:j$~HhX>!">HGO2ItՊ9n] QS^!71.߇_5חtH Ϊ_Xo? LH@9#;G|E5An zBPӅ1y7"^{jmpl8 c5wU+J-1Y8i$5))'1()A1fJv kakJb-""]ItNE ,Ų@x*PvlN4_L3X6ĩyҚI1fA\R$nkH'zY)MjVd2g(I;Yj 3%8=b1㓁TY4([Xr(: Ya@Kutw $0Bz'*2΀dNsfǡ27kN^I,MDu2)QR&EAD=Ri* `W0nxC Z'I"QˊH峵 ,&x#Ԕ9B4E,HNALi1wIM4-Yipy鼮mpt+y8-Y V`3:C5U2kWK:Ldg"}1R*J8mNRmǶhFԖBZ+L_^9[Mi^ux]1͜.`oI FV\&~L,%uHN=T3yϸIp|T,rִV56G0^6l;@+ U,/(O=<)Uz&znYO @wQ=WK"B!r"ϵ%4䔩\{~[yqx+;8ƭfWgmno6Y2`IO~Y ֹ>q$oi oy\Vz43saPq.˔ gEc_@]PFBx~1X]Cd2SkGnv Z.ħw0Й1wԾR=1(Џ~/[Կ{_w_??c_C@}wyxC'z>" X8}Yxhu.hyO Bv6dBaCUwxF|x3muXwZK)G/EW(cfw^G8lDy|4p:D=ro҄ArUsejX( ؊H6x(X x؋(H#XȈ^ǘ(c*\4XA֘ވ<(U8xYB'v#x==L$vhՏu'IL`eR!dVG1dWdX_9buVv%'6Hבt6;6%t)dI*, #ׅ3v\Crsa"ke'KQMYd\J bL)$O*=qYFij7&ySQRTgYya[YxBX=w~ 8e%6 UROkIH- tɋyC|^lv|8 $̇?jEX _z5[DW6!bat Ě! cCg^&@y U;0HHuCe")XwɜbљyysS59Yx9JyGwy[HAs)nHb9LP4$dNRhv"!.vcKIJ쉁m iōpds4̣kygUP(g8>s='rGtqguAOE8-Ţƈyxkuqc7\0ER+A&AroITcduFu3Zx}fxt\jwWnj,Zz8Sّ|MiDjfpAjI4:JأZkfTٔ?y.GNeIuyzF0ASYOXZ"-.nf>ꦂjF.%(qu%)ct 37qL†+)rFNWB:yF6Vs LoUE֮Zn^dj:@X} th{ Kc} Kcu~[ٱ dI(+jl.}q!/[&AWZ'tB1+XF;S1KDN8UۊWRC7<}յX_xT1f#r;t[xxzkav{`R*1NfTz9E(ػqƧsѫтr+JCNGr ^17 6#׫r+#̛ JgShbQ"GDswN2"u{hUcT׊VZ6Y{E+SAwnGnv73%HɅ`&Jդqiyh]#yogiKu8WW %Q pJ[˛=}iqGF4ya<ڲd\+%EWpL +j{*kD+fbc\Ŏ,tjhji(ņ sD\Cp&-u? pu\V@<<\̬e;54N|$hGwi Ƀ̆qE6 0㸅зBD]Ĩ<g/[=dk@t٣ ?S+}zՂG>E瀭qLdBY>8S5\u?|պ? cԔ,Sz,OlLi̪lRƱǬ؆]wDݾ{ݒU0={@2نNwU'-s[AF= e &Yn݁B c&$Oլ]/VόfGLZ3ʵg-lΨ}j{,% q%c"e, qʏXn21+U2 |؉%wS5nbr-CݹK}(Ufyj/t״y&E ML_0Mʝ~1ۘG=>!duԇH EM-:y~ "mYs躮խfwV͛f*Ff'J]ڦ]ة-1od_;z,i]^p7 fۺ>>>>???@@@@@AAABBBCCCCCDDDEEEFFFGGGGGIIIKKKLLMMMNNOOOQQQRRRSSSSSUUUUUVVVVVXXXXXZZZZZ[[\\\^^^^^bbbccfffffhhqq-MtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxX6Zs]$@-⋂r^"zkB rsL3wn 9r=z0ߢIa-?\4H+3k=:>݀^5w\wwޝw߉q;/<փ|o>|}\G'/Koԥ7.]7^ҥK2~/OW*y= IÇ \|5# H- ']a|:]O%DL ċb@M%E%+4*EPcil|[6<1xB`J.4c\jKSEu\`hmGʰr^"[iKWmq׏e%Q$8Y$Z|aq̚PNwj|aBo{05ƪD^&/! #lSS})E9E!=QA_0](0ldU1·WJE5Sz(Ph=E1³",'(L%6O,$e"QHe05&1/&㺉 4Mjz6FEFVMbB]t2T d)dS[)S^*l8J]Q,܀q{ a"ȁu9=kN煱{2&!L m4`ʗ Xju+udqO56q~2+gDk;ˤjerl:KPٗNARiX  / 9'6VW,m_)f]@]9uaX?5]f74eEgR+ö:盛 L&VS1ƱP1x`/EOkwi Ls: b[] 4ݩ47i9ڞxb?/6)( TSN-PQ(K1I4N<T\u]иU{D+^95mN*3h@6iW IXklYi-/l*/kK&{M:D@ 9kk7i@^<]ep`i@;$,UeB1Ʃ$$Z0$0d+HNjq ]@۶[C~0Wn[;>tk,}fןݞv:acD2l*I5Ss(9QIJm{ٷm`eU}})a9W (˅T4z~FJ6} 4{аq#!@\HMJa2SCwyx^8 ٶimpƔT-:WeMVv5;d{Ѥ㚶69IoZՌj>JYUXnފ.ؙ2haQ@!g@.!IFR1J1ѱxń OgUmG'fʛ05=n=4ut7{-s0G(2N nDω FJA 4PS*eiN#sV<~qiO/ԌOa+wg5HjWT?R (y fT%Brc7[4(a.˘ā *x{ܳwo:^ n]]z7ꕛʾlo[x;˳> a uQ,8,TcRyb:ќ.? 3e8G #B=UBJ A!5ŢT ZyHNrm莏60 tLJցIptuS>4hCc'|p}4/@ S Lˌs>R)F4G4BEGSUĮK˳H+ 8%ا ?L]/rG[UUq8-j0 pEۣrX >b'QGOE ef HFF( TlL;5PG]}#U߄&0Ec RKٶ6 NE2@4Xnjy9J7|Q,$ M&5XSCer@-K-V\uN+x +W@_} g@?7AW&WtIME;0~aaIENDB`gxemul-0.6.1/doc/20070616-netbsd-pmppc-diskless_small.png000644 001750 001750 00000013562 13402411501 023014 0ustar00debugdebug000000 000000 PNG  IHDR{bUugAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDAThz]XCP<(X*JRٲ.ն]t&ݘ^l$Y  Ar*@` @&xwjʶlT.J$J"C̅=;n t9}=/)|xuhU᜸-re >,ɞY}VOv \~I*CXKҘѨ*SJ[})4GnQ‡L $<@R$'yGK;{*KJ.Mr!G*HQgp QL~&Z RaJ56H/O51\q)]O!S" FG ˆws'3geG^lMzӃ1 D GA{"41 S޲:{s[S[smu?2qfmK/@9d_8#)uŨn ;(W_aܝt4wG7.;`Z O/͊7Ķ>H:g[jvq7*w~e‡kY=*'$HhvF4}bifJ>e'/tkj(DfZ V0 ԕbq#NeeC'W2ǮGAcz{~ìZ wLjenDVߙ_>;?:~ ,N/3yݔ?S;#f+B |i6H&t 2Av?s&HpsqL=<;=x\9bUT3S3frQ1˲PFZ^z!v'e}.nǍɦ_@^yO$Rid̹"-@$ą!ZQ*C8ê%tr$:'`k-n-q*4֫jS2QT%d,sǸbBݭO|"=ouF 1U;` PJO"V}<5$.m&mI~E[f-b3o7n}pȴG.R8ό?z`HQCЕVTUIDc*)=s,vP>9b|+<1?oãq[wAÛ{8j37O<OFIJdb&=Cx&E H eW-^`mYak3'3`kj ,!XJꀆ>Q{O ۛp?21ky[`跑c^ml%iRC}ryf fZ7 9ӢM'o IfDkJF-߈VTIl%S^n|nC%orz&@| 7qQqer <9͔'SqVO3rثwY</̸k,E;e7A"D$Zz>g#+.;`?L%0Ga*pkSW/*2 RӼISAI%snEFFS#ic%'2]m'j)Nkifx~sH܂v挈E}4CT8'Ii66uо nUEgPʍlMzM(E|j P2[i>whl!_Z{g̏g3꜒)3q&2g?'#{ok4f0`EphngoY𞐢5c0}:U5ͨpǘ?>Q{pO{DTꁜMaVFr̋pk}qpYةzp2lD:@5)F3S?LKp[y|@yG#0b]5DLq!KG!Wb~vGKI|{mu+'ZoM/4ítOw\Y1s}K:_L\k.ֻ/ֵ1e NqV9ż|`کV_uZxu&9&hPh&c9[ՑJe2>p+k O٘' jJT8b~E^Ǫ&r ~5)󵍥ۥּ`Qs^)9֬+N ~xc_hn40Js ajZ+)kDe_e-%YN$|$U9sf婡 l)q ޯўcQrd 7jh NZ$m瘃q3NbnjZ'V; Vg_}sS8 ߁7tW_dES-O_>w "gVr5qj yT&[1]J؞̨s~զZ;S1F UXLZH*UfiQ63 Gfy^[&y(ۅHLتf9j(RMUG=gby[Q=]3M4!0 rт槓fTTk1nk'ΌjctrR\j0Q2TēbDͧ6m +FnWՑ< Nzz.|q\4ӺG۝R7. >os[S6%~gnBI⢌W;pB~4ŖpV f/^_ԥ8 ^95DaRPP՛zvOŨtlIW%+0!^7/4rc6LJ Q2l?ťA*/(yB2$1;g/ā1luH?ɱ~34LUnƥ. <9u^f/jn .Kk {㘖9oZڣzP[krH[p E͕t!/:\NHfӸ8eR8 rHT D@<h]4-sb:u&&ϛN6-W1&_ׯ?6;|lkez16e.e9$;(|xD׽S+{Ip{DfUPF}ao;ji5=ŠՃSy$jwꉭ/j}R15HQw'i+'GݍHK뚭_?kٚX7it?a7̵^6붗SÍlN4ɾzoySﴽUU3YUO6ϖ^k[#}ψ*#P|fDv+VCqrӟnϣ\:ߩ݌#\iݣ`IlaEʾRy,ț.D g{䆦z&V8RD|2łr!hCO)SB-H;WL!E9ʸD)Ytg(A=u* 5z=%7~֊m"Mdo'7+Y8Dk tU{y{&;˟͎vgjd !905kxy(Nm Q1)1ѮJ6bJ}*tW >8UpPW%~E)B\③ꔢj@%uN{q,Sr~~jttǃey35o:ԫVܰ_S[ϊ?NId cȐ1qO{(&tvh`! 6zӟ=DUnˑ$ A4N,6띋hYў+1WR}ۀ`|%mMR<" v)qc퀶6S׸Z1%c˿>Ws,>X:rw{{хyX%1ZP{L4&ZH[P=l0 H1'bClhzi8|۟ZMMۋROk>}IG.q7[yDV )nf֮YBߒv˾ +Up1pbSrnԢfmpXe ?|UZ|Gvf[޻y 2貣o\Mŧ/׵42lUx]3yDD`5vqb="T,9e 6b*lE=dS-NKXc3_$<"gY4wur8G ~xro to:do's>JQUO\6%^~JOSH0L^V<ߟ u2z]&ǽ<0%OrrtIME* ީIENDB`gxemul-0.6.1/doc/20050317-example_small.png000644 001750 001750 00000005330 13402411501 020222 0ustar00debugdebug000000 000000 PNG  IHDRtc}6gAMA a3PLTEd^"4ffhhhp'MtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxZ:Q:$2s-J$ ~}W{0:{M)'dyйۇGZy}5MoPx^Xgߦy=lǺo՛ ~s ?Ϫ<==hF/@IW b^r|*3P#B=/PB[%B$Ap_/k9D3bj~0/BIIg`>BӼQCA0/W5aHȚLRR$6C& e 3XvR:VHRf|C HNStwP++0SL 7JxH%}O;FƼFg5}h3b٩V?#ҧ?O9#qe$^K)k:K j^Ĩc ƱF^ 6QO$>##qVlS6#g[l?וHJ-ȼ2g! 4h#,Rg{]h7lJX$q)9k[ܧ5 +松Ч|9<~HH]}H״,}G#?4%+wy&ջo93QCO-16 NMXMd_ X-t`$}FjM "fO9~HVmVv΢ ̴` rq` >n ,HX"kE.ׅ>ԧe`F_JHd =zuE1.[::r7l`'ye)1z73WV#պ7[f8:S$c0[F2GIn!%<]&Iͫ$Oͫ+a] @iB/o0#4|juy⸌vT R%sڃh״e$7#Ě ObAiۚGe]8&/x' (K?w 겹iavD2Z{9A?xσy3*zשjjS%cƪ}$ռOciu>]ʼVh;Z~KbӁVys7yFLRՕ[ CE/wO6t{3g yK+/P>樁t2H.e>Z&rOcMz5.KD)}U6 |ݹAQ^)}ִa$yqʧJFFHdCzhg$!c`+Ĵy=j65Ҵ[sB{ES8p:~)_] c%~?/"O)tIME (IENDB`gxemul-0.6.1/doc/debian-4.png000644 001750 001750 00000006234 13402411501 016067 0ustar00debugdebug000000 000000 PNG  IHDR ~cgAMA aPLTE^ff%ޠ98tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IDATx;baUw,@S^A Xm8 O#Ip3wYOZMB5_Gz}Uk-m#vioZ2*{J VLጁ O3]aq5Mc<{fMw{V]VŦK+tla+uBKw۲ax0n} G]GN]&aO{.w}s {f0ݕA 9fd uB՗I9\}37A:: zG{z8n8ǥ Ay=D1?p_ ڥm|_0 ~d09}:5턧=4ߤ;c0 bӘ_?c$Qq,i)wKϘxĩ{xG ~Տ A~Ak4fqә<0П11"1]Π?Ƞ ܲ)Ke٠~ ey<˳A> c<@iidФ|(M*Y2`03xg=_( De)]āB&q]d).;>{cHFa`0^ `f]`f_B[_5Kh]F?Zs{+v_W` L+` 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0^ 0a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0J`a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a W 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a `@a 0@a 0@n~?+~gpX,Zj>q\Fߏ; "2vǫc~:m`xQp:! 1Soc6#W:S  cP0^D,Wd/{D<Guw'e[q(4a̷Gk( 8[O'ye¸LTǏm}M{?AMv<"1xHNC$ 0@a 0@a ,O@1?0X5`u3 y o yOڕA `p:  L+DF 0 ^xSa@c D`````` 0@70XoZM7ŠY8Ab%e<ګcG; >n8+TAoGtۆMbu6r6ȷq7e0' o[0^D̳A\"{`yؾrN Q.~?0r5~V'O|lB* n>|tw>zX~pa 0@a 0 0 0 0 0 0xAU% 0@}AG+ a 0@a 0@@ a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@`@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0`01m1X;bvyXy`lz;)j 0@a 0@a0кK K-=|fd0`EmZG ?uPhtIME+V(IENDB`gxemul-0.6.1/doc/20181018-openbsd-sgi-o2-small.png000644 001750 001750 00000031333 13402411501 021242 0ustar00debugdebug000000 000000 PNG  IHDRjWgAMA a=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATx}}PWj}P#H}XB6Acx&LfTj7[3UW5/565d˻};N<8Tpl`0X a!@ߨBqLA۷[}u=wBHT^SUUr*F1pek3hdÛ3W+xBB8taYs9\"ʮf9 pW*i!]sg8UyxarU!CE<#˯ | !\.@3q 9rBBmbK$H&VC 9F4v#vDX$|{;6\e/BH&*q sF1|lN얟y?ޚDxv?L}<"KggC=Z j0BoH d7ł0 ]6s2f3yE;{6e bB^;^X-ZUin&VB#K M0ci!3OSL/,QbIY][Y)PΦӫ{D­%.$lLLYD4N'܆ (a$oӉ8Z :)dx"GbyJ& "ga!Tr 0$n2Z^_YY z=!D"N&S8MH$h4B()_ 6=+- |qpe2`0TrP a 㬬bga+1^U ق\+-]d Ńw7=J .3umR[r<R0 %%<)TX0[ZʳqdϤxxfa6B4Bh MMb NOTbDbW(x>+c\.ҏ<"E]i8:_2 boso7\6D|@!>|6Od ߴIxm'zO>R*Q0x8*_N͸ՊON?fN*Ra0SUVr&!Ap\N  x<pm-N`0_R]Z(7pa!TS#8w.}OT/X!U 8j0« Sr9_#UX_B%%r 9*&raGyPI ǹL&/DǿNXV"---$I|>}_~H><66FӴ"IR׳#.tuuy<RiZ_{5n7VҥK4M;N:::*J,$ MdF(LޮecGrܑN` Ѩ0L  S|>'u\6t2 cX^yPwwcΝ;C!~R#|$/]&ɦ&X\SSdϟ?V-Kyy}{/rq>mƍ$I;.HX ~jWkC83+b3=jGGGq>$qvZYYP(L&,c=7MFT* 1 |ڹs'QաPAƞT ~V;::zA\ˤܽ{7@`0>|RRYWWgZIܻwo<w:[lj H}N,S sX,6pp>}֭["n&&&bfc}zVW(p͛|>_"r9GF$͵bXV\.AQT2͹\.N~^_/@W[7շr)]!p8gR;Ƕ[Ax<ٌaǛH,++?vI?8a8755bh4zX,FD*:vp0q4+$T*566T*JjP$KKK`.JJrvvҥKYv8aٮ.~,:M^<zrVa^z%г>+h:~6o:$=<,H4BW_t k׮4M4h4Z|k&l6/..VWW8L&8D"x\v d2Vm&7lT*=x$9g,fc#ܹssss/z`0TSSs ry]]]04L?Ϸoo.BQJoo/ zj7sk7?4\zUb1$kjjHLRpxll ! Nlv\R^r%@ `6=Ahj򑑑`0v=pرcd۶mAHgvvV**l6D ?W^yI._xl6S|~___GGr*jjjj˖-.\T* L&˗kkk!  ݗ9!t5Dd2MӃ bqqqpp!ĶS^^ǫA fll555:6[[[u:d*//j`G !$u:BX,J$IBQ^^N?gD"!IH$A$}:PMMM.s82rjbrp ñKu:u X߻uhl6EQ_^w_ڊPZ] X\.ww\.WKKK0LR* 0`0bؙ3g6o\SS3;;;44S]]k.a$IIIԔ\.JpqLd|>t@|llСC677:Ox6]]]z{ܹs #H$q\R))LLLL&F)u6 ᔇl0I[kkIVF8rVaׯ;T*3 IJ>g;TWWiѣUUUxa (xnwݼyS,E/  fJAǿ|/~ 066 Z % IHރP(tsQa3KVS>`jDFfs__EQFфB!P2w8 A>T*y@_z`0P5006̙3rAi4}Ǟ|?@cE`pee%J$EP(2R)277GK/t@L&[]]v00ɤP( 2 񪪪yLh4X,h\"1 pB$!I7xꩧ/~ۿu\4ML >/f30uuuDbhhbd@{^ӹ֮YaKB_N>iCv kq݄~ckSygϚL&0 ;p@8Gׯ_7/䰬@Qԁ&&&8aةS>D l6C(J%%%Bayyt655$}>`PP^o6nܘN]V[[R\"H4\.?~xqhU+5撒5Mii)A7o$b~~^ׯi6pP0 Pt:T*裏B!0V5 r8ټ`0ju"7n4L kڥp8F7mTWWW(JJJ\FD"<۷/,,| p///D"kuBe-Ⱥw2t:)xvt:\'Qc$ EQw~}c000`[ZZ@s666MMM` ʵZX,qNG@[[^'JR= Arx`l6t'Onܸq߾}x<R>VH$Q*㵵zNf \k׮=#}>߮]^~円Jb' $ɗ_~9L>c"?c/d2ߏN>mZ/^x2saKKKr|nnܹs|>jjJP|A@$Ùr>O(J$H$255%JnܸaZϜ9rʊ/ dqqp\!.2??0g8{0 |>L X,Y˥\nzzzvv6L&׻̦ gfffgge2ȈX,Ϝ9^!3?O()p[Wp8}ѫWrRi2B#G8ND)fh:=ZWWW__a`zsD1<i5 `_Zeda ?6ZM,z_c>D)JB144SattG.I P<ippvhh7$x<\.SSS$I=p`0p8z)[[[VRjicutZ&lV `gqq @ cǎzK/4]WW#d2Rk׮Yd;yA_ﯯGeٽ{L\.ݝNGGG [A瀚]lNnWքYwX}ޔζ[qQ$m?޷>{]  .W^y<@٬h\^^(ԩS{9~8EQ@PhIIkmmmkk\^^NRmmmCCC}}}?t4]]]F_2<ӯ X  0_{d2ݭh~JK-,,8 Ԕ@ `MVEWVUVëq86MyH$r-6l6'  űc"aPee%I:&>OQt~ttjr9GEEEuuu2F@ je6)4؆&nN6CCC2YR?I7~j~W6ko όWVVx<6|}t:Bhbb (/ʗ3t"|. }\.,ssslR|~bp=;]?wuuki>v.Ǖ#GT*Azkk|裏di\ND,X,0̎;D"c$]v8qbǎnWUU\JU/l=v6Dfn866fX "STB`o4|6:BH=TAˢ8.L 4D4$BVDQ1FAVï0^/J|EEE4M&pb޽I$E\]] loor6li$IȄ3vRP( ,io0ZbE] |v=A#dޞcpPSSxUn*z(phMuV٬j<0---######`;w9w  _g"_:`+BTi rM%%%ɒNqaǢ={&''m6l@>|xzzɓ{왙)))YZZos&i>Otyy9EQ ?n|ɤP(:;;a^v`a"0l-&/i~fp{OcaKֱ9rd-̹6huܞ}-xۀu!sal~:~Iw6~}ox'J!;SBΡCjkknw$ihhL? /_|H$266Ԥj$IAhD"+YZZ:<<<44uV=qDOO蘟0 b=J%=y x0$_4 ϻ\Ǐi$2hСfc&2Xi0,H'?!^[outtLOO|F/4 ӟ4L677i:o60ܹɓaߩD"RJ333lB!"PFt:anݺY+++nB</2ǽ^/f|Ry áPH,LNNf24+++n݂$ld45 |>@dMRB6Ξ=rɤH$B-..8@N o*LF"s MӳCgd2>}ZPgϊp8z++ >22 ;pS:C<I1L0ă860tםb >}7Jrn~gyB-I###6m:v~dn!&x2H$@=\6z {mF3LYYJ㯾j3z|9o6 Z"{>_JdnB~yy j! 4ڵɓf)6xE[!j(wPG*IDAT5Z24ͩTvC0F( y2@` uKQlpP(TZZZVV őrerHs1QܵkdX,TJ&ꑑ׮]TT ҽU*U0ds,s7 r~ ab=9(u \oD@$|!4<3gۡS*`Ї~r4Deݣdj^af1A,*)\.d ʕ+.@}v@PWWt:|Ν;MD" 訨X,FnkZ`@iood---nd2!ñaR(Ljp8ZZZjkkBGr! ݾo>כd1 |NS(666NNNB? v1yX&B衇of4eg^Rjjj^o}}}eeD{{~jU*G}壣R$YإF=cOFᦦh4:44$JfsWWL(:umlmme^s\`00<Hx<555ִZ-a ܟvsV-lq0 .b<2 X,C&\OMM 8Z__yd2ǁn g!JIdEEEEET}2U(bZ,t: V^y]z>ݠ;`[,%^oX pD;`'?U_j{hhWcy3.E^'tuuƲ%ߍ϶繽;<}! W}}CD"gY:zVo}[+++7o&<3@IdEEQ|^l.uaPYYٿvvv qlmm%bÆ ׯ_~Dbb0lnne:unߺukIII>jo|>߾} //'B!TMX,988x ?k\_=gX )a GX&ܵmXrMww޹vd$"4 IFjH`yLkgT dGGx 5Fa3LUU@ X\PBpFGG=O0 Bjb׮]ׯ_xAyHopxPyOP`6550zX{3M\&Smkfұ-[qFm6BEX,vf$Z-a* !XVVۛ灳!422裏ڵK,?w^ZZZZZ^ZZ h"bBd2UUUIZX_-˦MaZh4Ri]]]>bG)))QT& ȑ#xtz<f4w [;w5r)u:h{w>6nv{ii Xl@G?0rM  i6|yyZgٳ>%ל`0XYYY^^bP Vt:\kXzL*A5zBx'x<<ގ0ax#`oʕ+fرcuaA,gϊD~!t bn N8q!>OVܼ~ bOSDOD"< 0PH&fX\fgg"HYYOx<voݺ6Wp8*GHWy֭@ P(TFpB* ËR4HB^/,P(Tj~~htΝ.\X^^^0G4[ʕ+8fٙL&#"˝x8 P(N; BhÆ Lyjj h,ε[!ݽNޮE?\s\{/\\kKK ÝAͮ|,OPG&Q5;;t:yzFz---?ȑ#G&X绺Hڋ>l*`ڵkmmm /@ݾ}2H$RT/bee޽{40۷oWƞ|d2 lfWWW]]Ro~ ?>==Gd2YYYf~MT0SlqsG +&)l&hM$J`UHM.P(<RT* Ph R)JYRY(Ū91ܫqQc|m13^2 ݻw$955o[ѐ${d2YWWpѣGe2٦MjkkGGG<822R|<4t9Nl6 XLBa2 Z=:Sպlۋ.?| \FTVV{B]]p8z{{Rv !k 뺇urL6;;KtWW[(|g=::Z|]ޕ%pmtIME 3Ռ)IENDB`gxemul-0.6.1/doc/20060814-netbsd-algor-3.0.1_small.png000644 001750 001750 00000010641 13402411501 021611 0ustar00debugdebug000000 000000 PNG  IHDRtkqgAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDAThZQlyȻ9NNn$qiX@9 H@Dփe$} Cч/Ch6A@:'9^Y3rקv!>$NT{wf+ܻ[pki,[5c޹k<G1b\Yۓ%ϼq/jQ(.hzB&8~+yf;dWϳOP+k{n{T*zV?LC ỷrmZ13҈PHcg6v) Af[ Rs{dNCsUZegPο0fٻK"jED)f/rnCR۷zZcM`S75Y#3Y#v_-ygn-o^n %I/hM,z?Tk;ͽk9nDB朐l+|W.h}+P_N#2>kuZA<}$?ˁLT_ ;×8L4"ҜW5AJx:Wc@@֘RhJUR;|˒z bcJyThd MΔ<<BfZPp@ (`<, gCf!; zMD6:}="3}g4aa9Q͗8ZZENTe5&w Keվg TT ԕ(br} Ӆ' FNC0tBi X>ykJ( Rq6 N6f_:9"̈́Υd;B6tXYS@%Awu tYTT,[vI3F&J]Iim8UT{UõhY՛.;3Q;g]9p(ѩS+VL*71}eO_#ce~qhyg,`cMR#U֓3\w=Xxlv U olO%QQK&)StW\5{iu$(?AO?x'dQȽcGI:ee;ofOVjV*uS~,4د.tAiIų:BD^[a"2ARnO{: $%ڛKީX}n~ICLF<"ђԀnVmDCHԐ@_N&^I8lMh w7BKɫX$pkIZXݚ_\=Fz[,Ṛǘi(Q 'QqKJi( * 1Z١!hbBF$Bڜ '25$x,d&O7*o+ @NJQi`ވgj+}˷4JV3)kq㪫LC㈫zom X86 #`e2+5 6 Q=-$shʆ2ED/oFq]u &gz:x@xdzXa`cٮMnm!,=K+IDyFh8 T[:=5 FϷIihͯVڎ;z|Hk jٱT{STٳA$گGB|!XyHeٽ- A8³baitzrVwOp}`Z!k>*CfZx-N"=˼& 0\LQA `@Td`)H2+ZTeXJI/#8(z#uF`RKK | 'Kg8 \mB`A+&]G|tRy[O'iQy" 'c@p~S|mww"oF;N|jy;9 k]UJ*ξ;LUwlEQ> rt^bf]U+3h2Rx~oH6}^U4s9T̵ۅt+֖?_v9deH{naETorp$@aH6~$IIt:@':B i'H ha$~\Esw &W{x5OmDWjHdc+I]dR4whrqs'd$ݐ9] JB5u0M˷p2:Y-sT-Fel qieb{@}[ O߻;X^ 6Q$=_ tݯuOZ=k E25e(";8jaOʑvJ o&7Vkwϯڏ}k4frjHWm~UL9:6\XܨC^ݥ4ءPP7:sD#A*Ӆ,"Q0e"S BP(z&rH'~xiD*x?8j&J<$*{7j+$rY4W]a\W_5W\,ƮB8 v醡kY)q׊pIz~fufnWG€+gW c.+Vų=bV)X5IƯ,=IQ:Hr׮*xISPXPwQ]N |kĐ>#Z\y–_qfX O7FŗL'οP 5sRP6fZӶ   Spqi@1E*"%c ,|1TA^jp :b>_,.ScNJM.OyRg" b I0 Wbec^:Jt%ւ&l#[ =c ο={ke7/m>T֎֍g[gVp˧o,~u/w߼6OG6p/מ=7^B;eUH/}rŷi;9.xʏ-P 4n# D?nf)n}Ѩ,-w 5ZOS0V`Y Qgwe&dqp5HT3kd ϯ(bNO4đ΍4tT೐فH*~҉*l=koh}_Ӝ˧~^"\{K0l|#~rmNM-տr1: l_:Y7Uri£zL~\av. =mɔ]dE~LHÊJXPF0jAL7l=y-OS GXemul: Miscellaneous

GXemul: Miscellaneous

Back to the index.



Writing operating system code, or developing firmware, using GXemul:

Is this a good idea? The answer is yes and no, depending on the level of detail you need in your simulations. If you are developing an operating system or operating system kernel of your own, then the emulator can be a complement to testing on real hardware.

Important things to keep in mind:

  • Porting code to a specific machine mode, e.g. a Silicon Graphics machine, using GXemul, will not "magically" cause the code to work on a real machine. Sometimes code works in GXemul which doesn't work on real hardware, sometimes it's the other way around.

  • GXemul contains bugs, and many things are not yet implemented.

  • Very important! I have only implemented devices in GXemul to the degree that NetBSD, OpenBSD, Linux, etc don't complain too much.

    If you are developing a driver for a device which is emulated by GXemul, and your driver does not seem to be working, then the probability of a bug in GXemul's implementation of the device is very much higher than that of a bug in your driver.

    The device implementations in GXemul are based on the assumption that the emulated OS is already developed and bug-free. They are not primarily intended to be used for development of new device driver code in operating systems, so if you do that, then be prepared for bugs and inconsitencies.

  • CPU details in GXemul are usually wrong. If your code depends on, say, R10000 or MIPS64 specifics, chances are that GXemul will not be sufficient. One example is different revisions of ISAs; some instructions which should trigger an exception on a real MIPS processor usually execute anyway in GXemul. Another example is if userland code tries to access kernel memory; in some cases there is protection against this, but not in all cases (to get higher performance).

  • Caches. There is no cache emulation in GXemul right now. Caches for R2000/R3000 are faked well enough to run NetBSD, Ultrix, etc in the DECstation emulation mode, but other than that, cache operations are treated as nops.

The bottom line is that GXemul can be useful as yet another way to test your code during development, but it should not be fully relied on.


Using GXemul in compiler contruction courses:

If you are learning how to write a compiler, and wish to target a realistic target platform, then MIPS or ARM (as emulated by GXemul) might be suitable choices.
  • (+)  Your compiler needs to output real assembly language code, which the assembler (e.g. gas, the GNU assembler) can then compile into object format, and then you need to link this into an executable image. This is much closer to how things work in real life than running assembly language listings in a simulator (e.g. SPIM).

  • (-)  GXemul does not simulate out-of-order execution, penalties related to instruction scheduling, or load-delays, so it cannot be used to create optimizing compilers that take advantage of such processor features. GXemul keeps track of the number of instructions executed, and that's it.


How to start the emulator with a disk image:

Add -d [prefixes:]diskimagefilename to the command line, where prefixes are one or more single-character options. Run gxemul -h to get a list of possible options.

Here are some examples. If you want to run a NetBSD/pmax kernel on an emulated DECstation machine, you would use a command line such as this:

	$ gxemul -e 3max -d pmax_diskimage.fs netbsd-pmax-INSTALL

NOTE: For some emulation modes, such as the DECstation mode, you do not actually have to specify the name of the kernel, if the disk image is bootable!

It is possible to have more than one disk. For each -d argument, a disk image is added; the first will be SCSI target 0, the second will be target 1, and so on, unless you specify explicitly which ID number the devices should have.

	$ gxemul -e 3max -d disk0.raw -d disk1.raw -d 5:disk2.raw netbsd-pmax-INSTALL
Note: In the example above, disk2.raw will get scsi id 5.

If a filename has a 'c' prefix, or ends with ".iso", then it is assumed to be a CDROM device (this can be overridden with a 'd' prefix, to force a read/write disk). For example, the following command would start the emulator with two CDROM images, and one harddisk image:

	$ gxemul -e 3max -d image.iso -d disk0.img -d c:second_cdrom.img netbsd-pmax-INSTALL
Usually, the device with the lowest id becomes the boot device. To override this, add a 'b' prefix to one of the devices:
	$ gxemul -e 3max -d rootdisk.img -d bc:install-cd.iso name_of_kernel
If you have a physical CD-ROM drive on the host machine, say /dev/cd0c, you can use it as a CD-ROM directly accessible from within the emulator:
	$ gxemul -e 3max -d rootdisk.img -d bc:/dev/cd0c name_of_kernel
It is probably possible to use harddisks as well this way, but I would not recommend it.


How to start the emulator with tape images:

Using emulated tape drives is a bit more complicated than disks, because a tape can be made up of several "files" with space in between. The solution I have choosen is to have one file in the host's file system space for each tape file. The prefix for using tapes is 't', and the filename given is for the first file on that tape (number zero, implicitly). For files following file nr 0, a dot and the filenumber is appended to the filename.

As an example, starting the emulator with

	-d t4:mytape.img
will cause SCSI id 4 to be a tape device, using the following file number to name translation scheme:

File number: File name in the host's filesystem:
0 mytape.img
1 mytape.img.1
2 mytape.img.2
.. ..

If you already have a number of tape files, which should be placed on the same emulated tape, then you might not want to rename all those files. Use symbolic links instead (ln -s).

There is another advantage to using symbolic links for tape filenames: every time a tape is rewound, it is reopened using the filename given on the command line. By changing what the symbolic name points to, you can "switch tapes" without quiting and restarting the emulator.

Note: Tape support is most likely very buggy, because it has not been tested much, and has probably also suffered from bit-rot by now.


How to use disk image overlays:

This is most likely best understood by an example:

  • Install e.g. NetBSD/cats. You will end up with a disk image called nbsd_cats.img.

  • Running the following command will boot straight from the disk image, with no overlay images:
    	gxemul -XEcats -d nbsd_cats.img netbsd.aout-GENERIC.gz
    
    
  • You may now create an overlay file, a corresponding map file, and start the emulator with the overlay image connected to the same (explicit) ID as the base disk image:
    	touch overlay.img overlay.img.map
    	gxemul -XEcats -d 0:nbsd_cats.img -d V0:overlay.img netbsd.aout-GENERIC.gz
    
    
  • Any changes to the filesystem you perform when using the overlay will only be written to that overlay. For example, to perform a "roll back", you can do the following:
    	rm -f overlay.img overlay.img.map
    	touch overlay.img overlay.img.map
    
    
    and then simply start the emulator again, with the newly created overlay image.

It is also possible to add multiple overlays. In that case, writes always go the the last added overlay.

GXemul uses Unix' way of supporting files with "holes", so even if ls -l overlay.img says that the overlay is several gigabytes large, du overlay.img should reveal that only the blocks that have actually been written to have been stored in the overlay, e.g.:

	$ ls -l
	..
	-rw-r--r--  1 debug  wheel  3072319488 Mar 24 11:59 nbsd_cats.img
	-rw-r--r--  1 debug  wheel     2465354 Mar 24 11:44 netbsd.aout-GENERIC.gz
	-rw-r--r--  1 debug  wheel  2930841600 Mar 24 14:02 overlay.img
	-rw-r--r--  1 debug  wheel      715538 Mar 24 14:02 overlay.img.map
	$ du overlay.img
	864     overlay.img

The .map file is simply a raw bitmap telling which blocks of the overlay file that are in use.


Transfering files to/from the guest OS:

If the emulated machine supports networking (see this section for more info), then the easiest way to transfer files is probably to use FTP or similar methods.

There is another way of transfering files which works for any kind of emulated machine which supports disks (either SCSI or IDE). Any file can be supplied as a disk image. For example, consider the following:

	$ gxemul -XEcats -d nbsd_cats.img -d archive.tar.gz netbsd-GENERIC
This will start NetBSD/cats with nbsd_cats.img as IDE master on controller 0 (wd0), and archive.tar.gz as IDE slave on controller 0 (wd1). From inside NetBSD, it is now possible to extract the files using the following command:
	(inside emulated NetBSD/cats)
	# tar zxvf /dev/wd1c
Don't worry if NetBSD complains about lack of disklabel; it doesn't matter. On some machines, NetBSD uses wd1d instead of wd1c for the entire disk. There is also a minor problem: reading the end of the disk image. If you experience problems untaring archives like this, then pad out the archive first with some zeroes.

Transfering files out from the emulated operating system to the host can be done the same way. First, prepare an empty archive file:

	$ dd if=/dev/zero of=newarchive.tar bs=1024 count=1 seek=10000
This example created a 10 MB empty file. Then, start the emulator like this:
	$ gxemul -XEcats -d nbsd_cats.img -d archive.tar netbsd-GENERIC
and transfer files by creating an archive directly onto the disk image:
	(inside emulated NetBSD/cats)
	# tar cvf /dev/wd1c filenames
where filenames are the files or directories to transfer.


How to extract large gzipped disk images:

Unix filesystems usually support large files with "holes". Holes are zero-filled blocks that don't actually exist on disk. This is very practical for emulated disk images, as it is possible to create a very large disk image without using up much space at all.

Using gzip and gunzip on disk images can be very slow, as these files can be multiple gigabytes large, but this is usually necessary for transfering disk images over the internet. If you receive a gzipped disk image, say disk.img.gz, and run a naive

	$ gunzip disk.img.gz

on it, you will not end up with an optimized file unless gunzip supports that. (In my experiments, it doesn't.) In plain English, if you type ls -l and the filesize is 9 GB, it will actually occupy 9 GB of disk space! This is often unacceptable.

Using a simple tool which only writes blocks that are non-zero, a lot of space can be saved. Compile the program cp_removeblocks in the experiments/ directory, and type:

	$ gunzip -c disk.img.gz | cp_removeblocks /dev/stdin disk.img

This will give you a disk.img which looks like it is 9 GB, and works like the real file, but the holes are not written out to the disk. (You can see this by running for example du disk.img to see the physical block count.)


Using a PROM dump from a real machine:

In GXemul, a simple PROM/BIOS implementation is usually faked, so that guest operating systems can start up. For example, if the PROM has services which the guest OS can call, which tell how much memory there is in a machine, or to print simple characters to a terminal, those can be implemented in software without having to run the original PROM image from a physical machine.

Raw PROM images from real machines can, in a few cases, be used in the emulator. A few things are worth keeping in mind, though:

  1. ROM code is usually much more sensitive to correctness of the emulator than operating system kernels or userland programs are, so don't expect any PROM image to just magically work.
    • In particular, for proprietary hardware, a guest OS such as NetBSD or Linux may only use the parts of the hardware that have been reverse-engineered, whereas PROM firmware code will access other devices, or more device registers, and assume that the hardware works to a larger degree than NetBSD or Linux needs.
  2. If you are running a modified ROM/firmware image in GXemul, in order to see that it boots up and works, it will not automatically mean that it will behave the same way when you put it back in real hardware again.
  3. Most of the legacy modes of GXemul have been designed to run without the need for a PROM image, for example the load order (or mechanism) used to boot from a CDROM or SCSI disk, so running with actual machine firmware might not really be supported, more than for simple experiments.

Useful command line options:

  • -Q disables the software/builtin PROM emulation in GXemul.
  • -T stops the emulation in case the PROM tries to access a memory range which does not exist. (Default behavior is to ignore writes and return 0 on reads.)
  • -K attempts to drop you into the debugger prompt, instead of quitting, on some errors.
  • -v enables verbose output. In particular, it shows the output of any debug() calls in the code.

Preparation:

The ROM image first needs to be extracted from your real machine. There are several ways to do this, and it depends on your available hardware, the specifics of the machine in question, and how much time you have.
  • Use hardware to read the PROM chip(s) directly. Probably preferable, but not easy if you don't have such a hardware reader.
  • Copy the PROM memory range into a file, from a running operating system. You need a running OS, and it must have access to the PROM memory range. NetBSD, for example, doesn't allow that from userland, as far as I have understood, but a modified NetBSD kernel would allow this.
  • Dump the ROM contents "visually", by showing the individual bits on a display. Then use e.g. a webcam to record the images, and decode them into plain data. This can be used for example on the Dreamcast, if you do not want to build a serial cable, and do not have a PROM chip reader.
  • Hook up a serial console and dump using the PROM's own dump command. For machines which you need to use serial consoles to access anyway, this is probably the easiest.

Dumping the PROM on a DECstation 5000/125:

The easiest way is to hook up a serial console. The terminal must be able to capture output to a file.

These are approximately the commands that I used:

        >>cnfg                             Show machine configuration

        >>printenv                         Show environment variables

        >>setenv more 0                    This turns off the More messages

        >>e -x 0xbfc00000:0xbfffffff       Dump the PROM data

Remember that DECstations are little endian, so if the dump data looks like this:

        bfc00000:  0x0bf0007e
then the bytes in memory are actually 0x7e, 0x00, 0xf0, and 0x0b.

At 9600 bps, about 10KB can be dumped per minute, so it takes a while. Once enough of the PROM has been dumped, you can press CTRL-C to break out. Then, restore the more environment variable:

        >>setenv more 24

Now, convert the data you just saved (little-endian words -> bytes), and store in a file. Let's call this file DECstation5000_125_promdump.bin.

        $ decprom_dump_txt_to_bin DECstation5000_125_promdump.txt DECstation5000_125_promdump.bin
This binary image can now be used in the emulator:
	$ gxemul -e 3min -Qx -M128 0xbfc00000:DECstation5000_125_promdump.bin

	KN02-BA V5.7e   
	?TFL:  3/scc/access (1:Ln1 reg-12: actual=0x00 xpctd=0x01) [KN02-BA]
	?TFL:  3/scc/io (1:Ln0 tx bfr not empty. status=0X 0) [KN02-BA]
	...
	--More--?TFL: 3/scsi/cntl (CUX, cause= 1000002C)
	>>?
	 ? [cmd]
	 boot [[-z #] [-n] #/path [ARG...]]
	 cat SCRPT
	 cnfg [#]
	 d [-bhw] [-S #] RNG VAL
	 e [-bhwcdoux] [-S #] RNG
	 erl [-c]
	 go [ADR]
	 init [#] [-m] [ARG...]
	 ls [#]
	 passwd [-c] [-s]
	 printenv [EVN]
	 restart
	 script SCRPT
	 setenv EVN STR
	 sh [-belvS] [SCRPT] [ARG..]
	 t [-l] #/STR [ARG..]
	 unsetenv EVN
	>>cnfg
	 3: KN02-BA  DEC      V5.7e    TCF0  (128 MB)
	                                     (enet: 00-00-00-00-00-00)
	                                     (SCSI = 7)
	 0: PMAG-BA  DEC      V5.3a    TCF0
	>>printenv
	 boot=
	 testaction=q
	 haltaction=h
	 more=24
	 #=3
	 console=*
	 osconsole=3
	>>

(The goal is to get rid of the test failures indicated by the PROM's tests, but it will take quite some time as there are other things to work on in the emulator as well. Also, making the PROM accept the graphics card and keyboard so that it boots with console on framebuffer would be nice.)

The command line options used are: -e 3min for "DECstation 3min" (5000/1xx), -Q to supress the emulator's own PROM call emulation, -M128 for 128MB RAM (because GXemul doesn't correctly emulate memory detection well enough for the PROM to accept, so it will always believe there is 128MB ram anyway), and -x is used to launch one xterm per serial port. The 0xbfc00000 in front of the filename tells GXemul that it is a raw binary file which should be loaded at a specific virtual address.


Dumping the PROM on a SGI O2:

Moved here.

gxemul-0.6.1/doc/debian-3.png000644 001750 001750 00000010377 13402411501 016071 0ustar00debugdebug000000 000000 PNG  IHDR ~cgAMA aPLTE^ff%ޠ98tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I;IDATx=b€a*}^טZ.h'fF p7q yGۇV{yeSZc[r1g{{zzϗ3*{8RXQo# G +8L|)'vW0?2i;ES}vtj ?azm^r6KV;nnv4̻m;GvFp{LvǸ0vrK?v ' Wp73 .N2UNic6%g g`oϻWu7]SfuCnnv{1Hov渆 qֿ%uyX _3vv6fwxuMCZNwӸ]UkƠEC1t ! s<pqݎ00(@ >cxe:}8xõAمzwtҧ%N'  ~q{%.c]ְl O e0U0x7o H"n \4=͑BRg=y9Əҵ~G ).İcd?854_<0=} O6/F/6 >>?-U^=kgU0X;H3` 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0 0a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0L`a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a g 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a <`@a 0@a 0@ Zo 0` >iᇏ0쇟C~q|gp 374<:9L0_yzR[q.^(o?| rA4[sƠ |ǗӬg<6MxG >#6 qw`: n⨕ l0ep5x5 ҈{`PG wtOȠE<ĿcX?|I<`[tn$?1x?L` xa r<}1kF<+ey/2-a*4_ߙA/J[G~cu<􀱼 0@wbP]mco]xe}ۆ~㼅A}殥=SU!7sO6[ʡXߏj~Π0SYd-l+7swgpqo0.fuɯpyiM;3Hx9ݦwXN?=߫U?݉x9}/M>7}i}XUەcx>ji}a|ªsٌM\GS>Wii㼍AxJAPw9<^YirM9oxm]ua蟱 ;]Ƹ_g)/n8}:W92}Sn_Wsכ㼕A!iFOpuXh3cPn2/2<-]0<ˠ^ee4 㫋naߠ?&V0(Ol63a߸Vś"4h9ێqC0X$R;> /m\-ݏ0/0u  ܃ 7|7Öo\b0124j5h7fS΋ «AvkP_͔ۗA8b!ŠjgP5Ao#e}àjo.>o0E6ՄAK^13 `.b뎷¾T.b]͟vG[o3HaQ *TE}|,0*"hM4o5>`>|A\^݌c9d}azz>㩊Ħ/{8?`-O5}IK/~wnx?{nU?|S3 bpyp9zk/[R> *3ܸ5s3Š w ʏ([/~*nTyhKO )(YK/?bzNM><\D^|}xKQs,T\m ?/~`::9p_ܑA:7_.\{{q8{z)-`[83Yx{qBb+Q2[lҙP ` ;_^ހ.2_k/2(ྻ\w].b:^uU ww6͔ rˏ+ι*ƪy?4w+?'9j .|lSh a 0@a 0@a 0 0X-+dPjcN}9a3 8C38W{7қBwy{ s`Y0,pAӄ90X`-o7Xˑ2}?͑>7M<@ o8|v0@a 0@a 0@aFOݕ a 0@ |a 0@a 0@ 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@ 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a ` 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0S3x` ^_7AK`Xe`kzv1p6m`0@a 0@]#5\>\ ?`^' r{{Z<#=KtIMEyqUIENDB`gxemul-0.6.1/doc/debian-8-small.png000644 001750 001750 00000001741 13402411501 017177 0ustar00debugdebug000000 000000 PNG  IHDRtc}6gAMA aPLTE%8K^`ow  %%%%((((**++++,,,,--//0011224444558888>>>>CCGGIIIKKKKK\KKLLMMNNQQSSSSUUVVXXXXZZ[[^V^Z^\^^^^^^``ccffhhj?oooqqqqquuuvvvwwwyyy{{{}}}8c88EEmmssuuyy{{}}MtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDATxO@= `ѺED" -%`ߛ4{r}(#CCd6%XVܴ,DZ\iN{ _^eTt.F>xyly]/QߛzM}4K;n hACE|9 (P@ (P@ uP7ұ75OlWtIME X&;IENDB`gxemul-0.6.1/doc/sprite-20040711_small.png000644 001750 001750 00000006764 13402411501 020106 0ustar00debugdebug000000 000000 PNG  IHDRtX*#XgAMA a1PLTE888>>>???BBBCCCEEEFFFHHHKKKMMMNNNOOOUUUXORYQTZLQ[[[\\\___`KSaaabKScccdNVdddfffgggjNXjjjkKWmmmoooqqqsHXxxxThYmZn[pBbCcFeYpJhEeOkIhWq]u_w\v8b7a9c!snpt) ś\ixXZ&~FZ ^ ^Ĥfx6z{S'N6+';ċPH|ӶnGm_y6 Ͷ-fN~7,D^N@ ^&=g5Apm(;H܆Ȧ)nM)^JV̓NŻ J:0d1^o Hûx| q2| П4,qM2=@!ߖD? Sջ 'ȉUFZAS,'C,].K,@LUo$}'^h́7"/d ]0.GRD;>9ΞodG}T*ՉZ)LyPV*SvMmGz|kj| 98/{lI#录m<-ݪ:A5v+Pf p:wgnR ^Ll*)썫fM,W.ie:͡tkQƆb7{7z@4-~jX  @W/5` Onr=s&mv Sٟyx!P_&,9wPVDhձ3k-;fۣB[j` )_3eExDdwzՆCl8^֞7Tl'h3AG޻]:RoޘZU ,C~Yj0m7RkWmy ecU݃UmH ÄDQ)P>-@ٝ[{hL%ղJ{5Ḱ 2?kD2MdUm˽詷oh^bt,)\O$c C!'Mkkw;0]qލnCnԫW `M{Z6yԻqT!PSFk .:oz7E4&6^7MS/eHf[/x㢘7VUWm~^@rnL N>O?^W'64qmtIME:џIENDB`gxemul-0.6.1/doc/sprite-20040711.png000644 001750 001750 00000035620 13402411501 016707 0ustar00debugdebug000000 000000 PNG  IHDR4wgAMA aPLTEUUU0`+0MtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATx]mrGoT$;H60k@H ,&qr zffV/m?R bR{7 ?¿ fíŒNugoy9߿ WV 3Ͽ OicUoÌc_A?!Ʊ 3ޗ3ǿϿc<]˿7桬Kf_p;q/#{ kAYy&uWu[yN qs_yqK81AZ'ȻȻg#x~/<FyW=w?ԭ< o^[Oyӄ˗3[x*8%swi%  hsl?ywg/<# O@\]Ix<#`O<ԾZ> czP)l?硧M3m̋noy~1??/<L?\N?- ;~a(8=h.Nw< Fx~=|ϋn?n?'3~nG/lğŌY1 $b1E{1{o311+1k/f;'y{RVc^cX}0n*xwc\?9 p P+pE>y&uWs{yN?OϠZ~mRaR'|~==_g- y䃎呷='NLQTszPH#O|4tlj<< r[jDh3KJe2?3l[ +岈y#9_'[!9M21=裑7}W OǼb+*stۺbEv!+@ a[-I1f'9.`4]yA7E|AڏE>otG|Ŗ7GX]Mnf&^ m$築|Ql4(YȄ 5_O%fXGMb(*^nM/yꂼ t:~V* 7nIDBP#8G"<$|#1zǍy\Z[GSY][ŴyBXmDsڻEmql=#0ytG *ny>  RQer{ı1+ Ym>e/y7fmn;6pl/C>+fplg4T _ؠnv>W,`!_؜B^t{3_Jcy3fyT\խM,?]C*îcâ.C%B@b|^%VE;绿=jh tkAa{@-yt:9!i(Tgu׸@)x7)E@cW7չ*mN<@hl귢lC~?- scwXj(Aފc4;ƨ!_ 5G~۱ՅA<_#M4SA$^.MU}H \?:~cȧ<hm|y$;"ϓ}<>6pl6z+H`Znqx=D\'uMZ'~\z9hؘOw1dONq5d<Ńph.lE&ḅU;zꀼ=(Ah8+v$)_x59w3 _{w ӼV4|خzcז}'O$ją)Q<:vl+Mŋ]W 1jBƬ6vlbOsl\Ip?'hj*FǧfGpŽ_ y-&~D}RqOxC3Y MW͂ϟAGbUMK`DVYy!#жƱ[#96a=g 86~rl"ڣ9}Xχ3./)9Q.͂|Uyvl4scmw5Icq{;=:cqѱqxsO{}"/s`3.!y+ UѪ-lXybWB5Bnk[EWvXXPOYHQWzY@Zꚮ+9ʘk1/L4:G` U^hZFk8f>Hͩk; C^t{3gslb+,O<^ 9Sc]|bh4QEq ^WpW3/'8}7Gb^J T} HnPBdhaz>pNbLy GU;W0~nW*vgz~̚ct{yh͐׾ڹА=c'/Oαo3݇Jx^GvٞWƷ w`Ѐ;6p;m|쇑D96=Ƽ{.ʸyi"cA: M|d*G96e̋n{n{^MxfWKC;y-&F^96~Sbe#ebGk{96Nvz6~ڗjEg=aWQ y~2[î֣ lvG=[֮6ql\Zϣc֒&`#<^դ1ϫU ޾|7ݙmĺRǬlcvqlN7wr]/+AԂruպ؜voDg[Zxu \%SUU^ֱCx'@h~2DIF~'˾_lU4s(߸3W]ظh~]O[Ut-ۯZ;ʼ̱/|BYOf/ l`}Kͻ$$:6sl/k`*ntk،K ~#䣠 *\P:Bݘ?quV#99!slȓ #B'c1ϣ,ni{yu( c(bH_Dx~F1  1:< BA3^ B58yɫ50Ӭ&+*|A3ո7i<_WEvhX4QQ݀>6NNPhmn>6vV^mܘ^wc]Kh&' o{1ܘ/Ư5N6Yk86QF+ƑQkj!JӹYT|4V@m A^G-]=}l.V\K)wu 3](܂+G FU^B<ɱF% ο2kv: =w>ʱ< by86o>tHm}ln\C=sxǛ,'~cul}7Geb׎ #8rl fǷMȃyg@&džZ*Yo-`./}lvQ?g2ٟ\khyʱёu on>K^]>6ܟsT tV6@ɼDZA6&5ie7DZrT˟n|zx`C VG#GOBo I$xl56M}{۸^+zY1au7W96Vcc@у *phoTS:m60-y3(6qW;%a=k< xwcy=yύyS|c5m=GJf?C)  e mRn>{=GA}cs!x[-?_}'IDATeyzxDUaLrFxؘwT+䤟Ɯn{އT)!iӮnO}Ǽ[~T-dۧ}lJfRƆaOQR Jm|gf _3ʕIᰧ!ѶM&<_Ԅ`9ocPXVyWu&smjEkӄU4&ަI[OfU/9S(Zߟn\1T,j` 6+GF.C=yCOt{}[ xGpdxyo7M3=>%؄x,\h|l$oE]f4䃦}lm`]x|zT׵Đ`&hncc: VkG"dž9SvVnRo5LvUU~>6frQNޭCI˫U&*z)σOѧcG_]l]$Je2B1M'Y#ߑz#O5]'9yS僢;:SQ|yismf]$&svVKu/h5I7^m 1sOx1/ R3]{_'-kCX;n ޺è4c^t{ru yohWyMv#PQHԁl FBe+1I=UCR6't&<ڙ0dQc&8Z>6>6n]At{Du؄ -ܱY/w5ȋnߩ ]QbuYFkᘗzx]!6-euþ(NcՋaܘF~6VVoAnH,^_:Dޯ))\謬c m96|rgfY^ee@կr=ULrlؤ nQ7m:6G^ϏYsIy#Ubؔ#~ؒv>r`JM@^ u[by.w`f{^E'k_%(fV=>iƇ'ݪh%?kyۯ$MYmN\VE3y>*Ast$nMb$!8GUlzOqCǑ;3A{}"c32-1[&>| Su͑fuL9;Uw7E^]A^E~M1e"GQU\k6wyvX966J!:>T6`hfZIp!cC.¸u ZVyg!ŖcC"lb(ʝ>R U$fx޻%G YPRFR窪O86,5 WJ_R|&Qnذ|mU4aɟcC*@L@|~{P4Ὣ5 7_)~n~'MEFO!(Q8^yO6܊?lذdv|д9 cëHv?=>mf | /}F7αYd!eZ6rlF"/yu-f)*)"96Jc> DQ_ M(Ƹ= 8\yˋ!> Si (bh.t_ƨ\3r/<<ޒ;~b 0@f!!V|fk 옒ExQmQKQex'Ln̙h^e pƭ93:eByl"v|DRyRHrl||u˅b*islp}k3j=?|frlli25:Lc\5g7CZ96H*^x뉖;0AV'g+Au>֧U|*:"螫#v 9l1(hqyy]g[W<{ ]]܁=>ƫD鹡±a;O4+SkCYWTق:ʹB2G96do  CGme,W vl#1ƴ yݾ g&}'F~DyY f+g&X={I59 o96[93͞ůG(DxWɱ-[8?/w'džǼɱ'/rl?8u>ywzKڄB8!sl8{}iC=䑵z~ֹ2I^c3}}hq|I'}yjt'yuwȱ MlƬOM5QZ{o!oy>96!HkB}&ok2zKlS} :6/r JwzyEn_czy۔"58tlVVh,Ľ9WI!5VcJ 73U 2fޭZbWؘu2&fDm,0K9zx/{ۯ!͑rlcZIhq6Gc\cH7Klp1ϣ&FbT1±YfaK*mqIr96漑jc cq kHu{ !:ZEMȳ+UdccB'aĘ=6kxy=f4wFnݞGYegrqb<{ ۇt\(ykyNVB!OiyW5?9RQtd"6[ʱ˘JdžlNq2=2-2?u{_ot{>,G>Ǧ!p:6z wJF^;HcCt= ,;lG~nT·*vlBųA<P-+Yv"Y[V95X?lƮZN\53|wltYɲHúz~1 KFNh-slJFG3*Zn?wh}ݾhdzU63&U6Ex`\gh/qu߸R/`~Q}}l˾|rn]?{3^A*BRtyUi #_f"bÝOY&l>bdžItoꖰFT?>@gzQt96a2,4 ~by! ۉy~1?<=X yέg>UM@^E/J؈>6[ tcî:f@x>6MD rǦwxyo/yE^y.}lNUE` hcS|uMхK86TU1e7`*ZcOUES^xHOƱ P،)/<_Yʱq]U!e7lWEpltXZmHx>6[UjslVE돼ۋn/ϋ?/V:6|ݞ0ֱAV65yu8yǦg+>6~uO&_Lxn`DdK nf::6gudK wϫsl2wplτ{|cwtlτ1%oC^x^t{ş~+b@xcy{|=rMT4y%cl%ȱYi6󫼺ϱY|_O r=\x}_E~B L3by5JD~/{ J±eE76qۯ?}C_ڲyDcC{ yf EY>6U}w^S.7rrAciܱ!>V _/I6Lx~Hy86;󴑍d=_/ql6W{ )E^x>cBKbdž,h_y!u6NOwGض 7d#kڴ)l6hUg}^):[tdž /<>6T __ߦzQf~k|n8䥏ͨ،D^xN}lLrUyܱ췟SG SO|n}l 6mF\Fj,}ly~}HZ. ۇ7}C]bXy\sZgK4dαc;-63"<_ GXemul: Technical details

GXemul: Technical details

Back to the index.


This page describes some of the internals of GXemul.


Speed and emulation modes

How fast is GXemul? There is no short answer to this. Performance depends on several factors, including (but not limited to) host architecture, target architecture, host clock speed, which compiler and compiler flags were used to build the emulator, what the workload is, what additional runtime flags are given to the emulator, and so on.

Devices are generally not timing-accurate: for example, if an emulated operating system tries to read a block from disk, from its point of view the read was instantaneous (no waiting). So 1 MIPS in an emulated OS might have taken more than one million instructions on a real machine.

Also, if the emulator says it has executed 1 million instructions, and the CPU family in question was capable of scalar execution (i.e. one cycle per instruction), it might still have taken more than 1 million cycles on a real machine because of cache misses and similar micro-architectural penalties that are not simulated by GXemul.

Because of these issues, it is in my opinion best to measure performance as the actual (real-world) time it takes to perform a task with the emulator, e.g.:

  • "How long does it take to install NetBSD onto a disk image?"
  • "How long does it take to compile XYZ inside NetBSD in the emulator?".


Networking

NOTE/TODO: This section is very old.

Running an entire operating system under emulation is very interesting in itself, but for several reasons, running a modern OS without access to TCP/IP networking is a bit akward. Hence, I feel the need to implement TCP/IP (networking) support in the emulator.

As far as I have understood it, there seems to be two different ways to go:

  1. Forward ethernet packets from the emulated ethernet controller to the host machine's ethernet controller, and capture incoming packets on the host's controller, giving them back to the emulated OS. Characteristics are:
    • Requires direct access to the host's NIC, which means on most platforms that the emulator cannot be run as a normal user!
    • Reduced portability, as not every host operating system uses the same programming interface for dealing with hardware ethernet controllers directly.
    • When run on a switched network, it might be problematic to connect from the emulated OS to the OS running on the host, as packets sent out on the host's NIC are not received by itself. (?)
    • All specific networking protocols will be handled by the physical network.

    or

  2. Whenever the emulated ethernet controller wishes to send a packet, the emulator looks at the packet and creates a response. Packets that can have an immediate response never go outside the emulator, other packet types have to be converted into suitable other connection types (UDP, TCP, etc). Characteristics:
    • Each packet type sent out on the emulated NIC must be handled. This means that I have to do a lot of coding. (I like this, because it gives me an opportunity to learn about networking protocols.)
    • By not relying on access to the host's NIC directly, portability is maintained. (It would be sad if the networking portion of a portable emulator isn't as portable as the rest of the emulator.)
    • The emulator can be run as a normal user process, does not require root privilegies.
    • Connecting from the emulated OS to the host's OS should not be problematic.
    • The emulated OS will experience the network just as a single machine behind a NAT gateway/firewall would. The emulated OS is thus automatically protected from the outside world.

Some emulators/simulators use the first approach, while others use the second. I think that SIMH and QEMU are examples of emulators using the first and second approach, respectively.

Since I have choosen the second kind of implementation, I have to write support explicitly for any kind of network protocol that should be supported. As of 2004-07-09, the following has been implemented and seems to work under at least NetBSD/pmax and OpenBSD/pmax under DECstation 5000/200 emulation (-E dec -e 3max):

  • ARP requests sent out from the emulated NIC are interpreted, and converted to ARP responses. (This is used by the emulated OS to find out the MAC address of the gateway.)
  • ICMP echo requests (that is the kind of packet produced by the ping program) are interpreted and converted to ICMP echo replies, regardless of the IP address. This means that running ping from within the emulated OS will always receive a response. The ping packets never leave the emulated environment.
  • UDP packets are interpreted and passed along to the outside world. If the emulator receives an UDP packet from the outside world, it is converted into an UDP packet for the emulated OS. (This is not implemented very well yet, but seems to be enough for nameserver lookups, tftp file transfers, and NFS mounts using UDP.)
  • TCP packets are interpreted one at a time, similar to how UDP packets are handled (but more state is kept for each connection). NOTE: Much of the TCP handling code is very ugly and hardcoded.

The gateway machine, which is the only "other" machine that the emulated OS sees on its emulated network, works as a NAT-style firewall/gateway. It usually has a fixed IPv4 address of 10.0.0.254. An OS running in the emulator would usually have an address of the form 10.x.x.x; a typical choice would be 10.0.0.1.

Inside emulated NetBSD/pmax or OpenBSD/pmax, running the following commands should configure the emulated NIC:

	# ifconfig le0 10.0.0.1
	# route add default 10.0.0.254
	add net default: gateway 10.0.0.254

If you want nameserver lookups to work, you need a valid /etc/resolv.conf as well:

	# echo nameserver 129.16.1.3 > /etc/resolv.conf
(But replace 129.16.1.3 with the actual real-world IP address of your nearest nameserver.)

Now, host lookups should work:

	# host -a www.netbsd.org
	Trying null domain
	rcode = 0 (Success), ancount=2
	The following answer is not authoritative:
	The following answer is not verified as authentic by the server:
	www.netbsd.org  86400 IN        AAAA    2001:4f8:4:7:290:27ff:feab:19a7
	www.netbsd.org  86400 IN        A       204.152.184.116
	For authoritative answers, see:
	netbsd.org      83627 IN        NS      uucp-gw-2.pa.dec.com
	netbsd.org      83627 IN        NS      ns.netbsd.org
	netbsd.org      83627 IN        NS      adns1.berkeley.edu
	netbsd.org      83627 IN        NS      adns2.berkeley.edu
	netbsd.org      83627 IN        NS      uucp-gw-1.pa.dec.com
	Additional information:
	ns.netbsd.org   83627 IN        A       204.152.184.164
	uucp-gw-1.pa.dec.com	172799 IN	A	204.123.2.18
	uucp-gw-2.pa.dec.com	172799 IN	A	204.123.2.19

At this point, UDP and TCP should (mostly) work.

Here is an example of how to configure a server machine and an emulated client machine for sharing files via NFS:

(This is very useful if you want to share entire directory trees between the emulated environment and another machine. These instruction will work for FreeBSD, if you are running something else, use your imagination to modify them.)

  • On the server, add a line to your /etc/exports file, exporting the files you wish to use in the emulator:
    	/tftpboot -mapall=nobody -ro 123.11.22.33
    
    where 123.11.22.33 is the IP address of the machine running the emulator process, as seen from the outside world.

  • Then start up the programs needed to serve NFS via UDP. Note the -n argument to mountd. This is needed to tell mountd to accept connections from unprivileged ports (because the emulator does not need to run as root).
    	# portmap
    	# nfsd -u       <--- u for UDP
    	# mountd -n
    
  • In the guest OS in the emulator, once you have ethernet and IPv4 configured so that you can use UDP, mounting the filesystem should now be possible: (this example is for NetBSD/pmax or OpenBSD/pmax)
    	# mount -o ro,-r=1024,-w=1024,-U,-3 my.server.com:/tftpboot /mnt
        or
    	# mount my.server.com:/tftpboot /mnt
    
    If you don't supply the read and write sizes, there is a risk that the default values are too large. The emulator currently does not handle fragmentation/defragmentation of outgoing packets, so going above the ethernet frame size (1518) is a very bad idea. Incoming packets (reading from nfs) should work, though, for example during an NFS install.
The example above uses read-only mounts. That is enough for things like letting NetBSD/pmax or OpenBSD/pmax install via NFS, without the need for a CDROM ISO image. You can use a read-write mount if you wish to share files in both directions, but then you should be aware of the fragmentation issue mentioned above.


Emulation of hardware devices

NOTE/TODO: This section is very old, and is about the legacy framework. New machines and devices should be implemented using the new Component framework.

Each file called dev_*.c in the src/devices/ directory is responsible for one hardware device. These are used from src/machines/machine_*.c, when initializing which hardware a particular machine model will be using, or when adding devices to a machine using the device() command in configuration files.

(I'll be using the name "foo" as the name of the device in all these examples. This is pseudo code, it might need some modification to actually compile and run.)

Each device should have the following:

  • A devinit function in src/devices/dev_foo.c. It would typically look something like this:
    	DEVINIT(foo)
    	{
    	        struct foo_data *d;
    
    		CHECK_ALLOCATION(d = malloc(sizeof(struct foo_data)));
    	        memset(d, 0, sizeof(struct foo_data));
    
    		/*
    		 *  Set up stuff here, for example fill d with useful
    		 *  data. devinit contains settings like address, irq path,
    		 *  and other things.
    		 *
    		 *  ...
    		 */
    
    		INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
            
    	        memory_device_register(devinit->machine->memory, devinit->name,
    	            devinit->addr, DEV_FOO_LENGTH,
    	            dev_foo_access, (void *)d, DM_DEFAULT, NULL);
            
    		/*  This should only be here if the device
    		    has a tick function:  */
    		machine_add_tickfunction(machine, dev_foo_tick, d,
    		    FOO_TICKSHIFT);
    
    		/*  Return 1 if the device was successfully added.  */
    	        return 1;       
    	}       
    

    DEVINIT(foo) is defined as int devinit_foo(struct devinit *devinit), and the devinit argument contains everything that the device driver's initialization function needs.

  • At the top of dev_foo.c, the foo_data struct should be defined.
    	struct foo_data {
    		struct interrupt	irq;
    		/*  ...  */
    	}
    

    (There is an exception to this rule; some legacy code and other ugly hacks have their device structs defined in src/include/devices.h instead of dev_foo.c. New code should not add stuff to devices.h.)

  • If foo has a tick function (that is, something that needs to be run at regular intervals) then FOO_TICKSHIFT and a tick function need to be defined as well:
    	#define FOO_TICKSHIFT		14
    
    	DEVICE_TICK(foo)
    	{
    		struct foo_data *d = extra;
    
    		if (.....)
    			INTERRUPT_ASSERT(d->irq);
    		else
    			INTERRUPT_DEASSERT(d->irq);
    	}
    

  • Does this device belong to a standard bus?
    • If this device should be detectable as a PCI device, then glue code should be added to src/devices/bus_pci.c.
    • If this is a legacy ISA device which should be usable by any machine which has an ISA bus, then the device should be added to src/devices/bus_isa.c.

  • And last but not least, the device should have an access function. The access function is called whenever there is a load or store to an address which is in the device' memory mapped region. To simplify things a little, a macro DEVICE_ACCESS(x) is expanded into
    	int dev_x_access(struct cpu *cpu, struct memory *mem,
    	    uint64_t relative_addr, unsigned char *data, size_t len,
    	    int writeflag, void *extra)
    
    The access function can look like this:
    	DEVICE_ACCESS(foo)
    	{
    		struct foo_data *d = extra;
    		uint64_t idata = 0, odata = 0;
    
    		if (writeflag == MEM_WRITE)
    			idata = memory_readmax64(cpu, data, len);
    
    		switch (relative_addr) {
    
    		/*  Handle accesses to individual addresses within
    		    the device here.  */
    
    		/*  ...  */
    
    		}
    
    		if (writeflag == MEM_READ)
    			memory_writemax64(cpu, data, len, odata);
    
    		/*  Perhaps interrupts need to be asserted or
    		    deasserted:  */
    		dev_foo_tick(cpu, extra);
    
    		/*  Return successfully.  */
    		return 1;
    	}
    

The return value of the access function has until 2004-07-02 been a true/false value; 1 for success, or 0 for device access failure. A device access failure (on MIPS) will result in a DBE exception.

Some devices are converted to support arbitrary memory latency values. The return value is the number of cycles that the read or write access took. A value of 1 means one cycle, a value of 10 means 10 cycles. Negative values are used for device access failures, and the absolute value of the value is then the number of cycles; a value of -5 means that the access failed, and took 5 cycles.

To be compatible with pre-20040702 devices, a return value of 0 is treated by the caller (in src/memory_rw.c) as a value of -1. gxemul-0.6.1/doc/debian-12-small.png000644 001750 001750 00000003141 13402411501 017246 0ustar00debugdebug000000 000000 PNG  IHDRtc}6gAMA aPLTE%q}  !!%%((((**++++,,,,,,--//0011222222445588888M88Q888888::>>>>BBCCCCCEEGGHHKc 3O!/f0l( J6{XF܏( 3i.BM7#kړ |ٚst&5]'nd]KVN_F̠hv[oRm>tzò!.g 'ЮZyurgNK-l2ӷZii۾t[ݙ36 ƳMiّ4(#"%K;g|)i9\ɥ|'2o8";.y!O_囉` "ZgIa"d_@ӆ5=SGAqx̉bx(1F jb]jpO6?zO{}zB>.^B';6Aa"V+ZPl9'})Zsa.$]b%[4#b4qG@g' }qpGӿ/"Td# 2z֙lBP*T UBЋO:sԕ(I`tIME 9#mSIENDB`gxemul-0.6.1/doc/20180220-openbsd-luna88k-5.4-small.png000644 001750 001750 00000030271 13402411501 021732 0ustar00debugdebug000000 000000 PNG  IHDRB gAMA a=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATxpSWm~86X?GtxױJ/c !5զfjQ̖J;UL\GT㪮tHcq%*fj!)K3jGQ㆖l #lKa._zy"ؚ 'W3 #70,5mMOkff*)fkf֮Zu:(oN-]1LMe׮Ӭ7ޝo,֭+}bյuȹ{nqQ{w׮^LS/}g70V)M-:ы~Si2}ͻ/NM%{oܪZ?^(/a겏._6XLÖWz]겢[+?x8qSkoLvs׬*SDŽ>}%3,oWW?{3/U?q#;tڍҲk/ojΞd]骋?gܙ{1sukR#cKGbi3 OӍk}*O?QKקwh\v";mwE>gҔ^vSQʵe֗_qݙ._en?nĵ[Oz~Cu嚍M+[]T\}şYsyk՟m3+'kLݤIixthrzի3익WߺW\4]̆n^rvi{ʒW_4x]ݍ}CWg,-Vi|Me/6Vl?لEO?qhG|{)7zgkMφkBo>?0~Wl~rx*A3ɽ֍fnGGfUit2}[oUW_aw~b!Ѣ2'Gծb=}'+:1A|y'G[]M (: 3&̘ 2c 3&̘ 2c Ȍ ̘ 2c Ȍ 3&2c Ȍ 3&̘ Ȍ 3&̘ 2c 3&̘ 2c Ȍ ̘ 2c Ȍ 3&2c Ȍ)PHu鄿 (&(_}vԻ $aHl6*$^/Џxd>W\ zAp:_! 1l6_1688 0t:{{{cXofy^˛ւQM2Ơqc(Conn$ At}c'Ix<$\H$rFc*j6|X,[[[[[[14c c\.ƘaXVA ZfE"P(455pxS[[ 8X,+oXꪪT*J{ɤ(Zh4U`߾}>XN$ Ò$[poX1,b4M$0[& $IAl65%`0ЭXꞞq㼚*&0Øl8Q k{*JC/l *:ȌG;^f3ohr Ȍn-$zoOOC>VQqS/z^yqcv:?$@u>>f1!IRoo/{{{a* E/px&CvhmNݗ(RNSfjyGzz=bXeeN G:I8p8<^3g0 A|PE$@ -lݺuǎ6 \].,N`0466ej(Fz>@ N[o577?~\Ѩ?eYD"$;0( c(&) ՙΦ&h4P( 655e2t:FR/FZ<ÏC>KUUp8vh4Tjxx[nf$رĉH$L$)LPYV͟:tvzvaۗrRcEX,S,%7wH$i?,baAnhJeɲrF멩zAj[9~^E1+JʲzO>m6XCC\,d2"̟Z8c:sl4E]nŋV+c1f41 #8{ŷť~˻:ԥx/r~~2 4+(ht=z~s 4c|%{ !k| Y%^*\ cl:E|$58ll#s~?2`|HD-t:z>wq\СCX&JF}xxUWj>RPPc T*~Akvx1&PSS~<455eAԲJiFmfl6˗|0rI uO8۳g|CCC~bڵnЄ~V `XQ..9+!6f!_ߨMSh2X86FM(?K/BA"P rh0l/T(xR1ڇkB?#|a.\J~C_I,qV^GK\  6(˲fewX eb{Bjf|l6U&6 lׄ+p j :b2R&b B)ta4Ȍ2 cS#Q2UKrb´$IRR3T* tN3Z 3<#֭[!G:X`rUUUT{eee^Kh4'(`;.V%\otz6^fH{{F^wSŋ僃?'''4èSЎ$InW*:|";sɚSN1&&&`<$t6n_1kko9hb|zl}}}Zvll{bb_MOOGQ b۷ϟꫯFJJJJ qYwZSS366 :~PLG)OT 芊j%i$Q"oe'"9@YYY ~i>BU 2!anU: 'ٿ?$}}} ."&.A Ջ(R'\ e !)%G21QƈJIPhCBD 9S݉Q`ư/!?8nJCk0-y\FS!LηC ~D!ݍv޽{a#rXUUnJ B$ i0-爹Li!c Hc7oBHӡPbbJE='ldqIܔTNMM-Hn9@5D%VUZC( -//o€r˖- iR SPؔ\B)Wy\I:ib1;<'f!)Af=s۔D>qމ1M&㲲R|~D!wbLqJu i!$Bd0ƾ P>VWW]V山֭۶m۷5 9yduuu<?uT ~m۶Ǐ_ AvEu(8hX ?v>s(Txrm|FnGj60n x`R[Wg:NX5%Ik Bouu,t:A*B# x7ƽ.:t`KTS2g %:n8l|}}}X8WWW[1v|'Nc"f{rAKl͗|0xg"%:n8 j Vb&ϸ8c | kRE^8%L5qK8ShuL(-@[ϤzR]ŶONSqw)4*4{{{:&B=&Orz|r(<3~s9urĦ\4=X [Ws HgI:?sG<,LWo#I҂>ʌN-Kyy _bʖ \z '''zr 4+++cFp;&JxvH&l6ㆭEQ4LPxxxl.pvH`_pcvsmm-<Cfsgg',{N&Ft:s a0lmm iJhl6v wA,CCCu~m˖-===``0@;II<_..H\.Q?S^;Gd[3g@<`̱zr *Q #Td到9>>^[[Fh*---:ގ9:Sp خ]2nn6u:]]]2|v].VFuuuF7\Vt|UUU&ZMMMرr)N 0㎎3g1 j mkkCAh@ 5[[[^5˲ ;cuدokz^ 6G a7H$A[___jŷ0l6R),X,f60&և~{)87t1lY V=Bl?z]^^jar;w.Hp1n4(xZ OAŬ@ aOO<}+\\PU&A/ 'AnwIIICCGFFZ9|o?FFFv.^!N'|uYwܩdY8 |٦@I R,LMZ0T*H`|SeDޒ/۔ݻWWJ3.bN){+r= RĢxF NRߨ^FC(Z,W^u8w޶m|PٳX{QHJA"\@ AHU3-_B!PSXJrF1B^7QN9C1TSR%D>̓W_}v ---=vئM6olZ;{ n>|x||\O>W_?я gpppz/b:NӊO>eΝ;'atDO$} "O&ɣ Lcļ 1&Aw@bLX:$Ƽ1 T/c'$$7cc.l@bL" 1eHI4$dĘDCbeHIĘQؐ V$d$$nHIKĘ!1&AEBbLXĘQfLb̅HI$ 1Ę(v#IDATpHy 1T cĊĘĘݍ1 b>$$hRHHIKT ތI1|Ę"!1&QА1c1!1&QjcDaCbLXR 1&A,cއĘM 1 bjcD116w 1&oS2$$ c2FbL!12$$ wRMbL(lHI+c2ct7^ $$CbI"!1&A,}RMbL(x3&1$$ cPĘDACbLHI8$Ƽ_ĘDNII 1 bE@bLFbLKĘtHyc4^$$$OIIo$\܁ĘDAbLʐ(hH1Ęː(I51 Y~RU9\=ωWjdF MMM믝\LgZxi98׋mKR> ĄZ $I2 (Z  T*ZN,rz^]<}xx8 D0c CUUU$ł e~JI^SSK$`ďhUUUFqjj }}}d}߾} j9L5B/SSS[ls "_ȇN(|rV*N'OC`v&'~/.UC,;y$$bf\[+ߩb3aÆY2$tl6XM| )*}~jOt*ȮNH9sF!~lp16>>θC(7vڕNANl,+@cX zgd---KT ONNb;N;c{O&FQ'NW ٳĉ2 I$)Lvvvՙf 2\.T0v?PycbB-~CFQE0E;.KE rSSS& bLɔd2;E(v\oPvC, 9Z6'%vF0@c[2, mmmC,l6[aI|amX:::Μ9e ݩ,ˢ(b1eYe^& ^JgFʲfs8h4(vtt[x&B&Й'2^^gݾ}{4ռ^jN,n{dd^D"zKJJr?).~Eq|ؑ#Gx[Nx)Q~(O˲ ה nA;wn߾jhZ.Pʲ 'gBG;9njgQf.|xV2Jx(˿4p'$ bv9{ct +^)C|EfA*}+9<5ƷЊB9$ 648N;N>$I0rlb=Az<|CQ ?Z7>+& V;wNEP;vtt:t/9|6 j%11ՔxX&@ө;QzNԄbu1"$ ]|1~p8uСt:[cr$cnD1&栚h4`0rQz!2Q:'jllGtn:44|rws;N!LB6miiAf5'Xk```߾}d2VJNsUUU9Nl0ɼ[>sr L=(O/5 *1xpp/VTT 11.\paF%I~m64<1~݋F555ccc.~h4FS&xcaLLLȲ<11166fZGGG?F(Ԕ,ׯJJJFGGѭ-7nܸq7|SCh`‰R-š5kFGGO> øsNvT*Aq "<=NItE>AԙL&l[ Qˉ]Ɠ\\q'Q؈HulJ?e8ם K/\~=o`9D".]DuL4|T*^ll6t:Eˊ 3f`=EdiQh.N8q̙x՚{;44/ VVV lGMNN-8/< 9_  ܢ9o$Ec2b: AAAfLdA/q0r|rVx[뢝N'X TB6 *>Q<0 ec@@d^d 4SA FvtBMCR!x^z< Wnp$1F!%l0IkmmE f()$TO~_L&!r~?ʲ/]t:\=ry.%ʿ0zL S@ Av3g`i,Vj9$W)AjՅ1&V3UW`.T2FQ%fE%:Vw]]5hjj૷AdLy6%\IөЖ'NE1 bdL^‰+^o,U 777wd29>>>>>wc!;vn`utt߿;v:uJqP|K, *op%S9xkZ\s]1@Rqn9~H 1&Ϳ.f XC 6G;$ z S3Y+ `Cߪ_pDCP*B"ۦc]EZN1 G|tnI+>Dq޻w޽{ג f٬""8{1$cUUUr]x<1yp8 ZN`OOO:NRO{p8lXf #Id$ŵLcHJ /?`ruJ4[݅FX|wT*H`dLLB7[ou̡Sc.xNh5 fe#c2{=x(u:s ޸q/KY_H$N<_q0c]?󝝝ž}Z12czY"@Ln?bn@-u۷oGNFGG{=@pI(N Zݻw3Ʈ\OO%xV`dL3jP=!E介 %1- ̘ Ȍ 3&̘ Ȍ 3&̘ 2c 3&̘ 2c Ȍ ̘ 2c Ȍ 3&2c Ȍ 3&̘ Ȍ 3&̘ 2c 3&̘ 2c Ȍ ̘ dS]]M 59^<tIME 50IENDB`gxemul-0.6.1/doc/ultrix4.5-20040706.png000644 001750 001750 00000036565 13402411501 017174 0ustar00debugdebug000000 000000 PNG  IHDR ~cgAMA a-PLTE^KbvR7(ffxg{ʪܼɩ8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IDATx흿$IM|iK{ ?x;0-I?՞RBŠRÇc Ri.GGdxzuueFFzOя}#i>{ޣ}# o~@;OS)۷NԾm" R82JTӴfs摗9לo_}=^sG^0!n=pv{3f(-!ybp#]b1&]cМ0xhP=cF,lW+^1xxo- XX5<}33@{s 7M|N=hQS?{ tٌӇj4`y4}}v-^A͗_hpO`> X'1w2 =??'/5$0cg3hxI^.0a ˋ]Cv{vի=Fһ9 Wx0xbi >|p+C` `]?*7?<)">Ob!@?|#^j%Ϛ}`ΰGQ@Xu,l-Kf=^"9`^~08Ă1aGDhS11؋.<@cۍMh'jބV"|1h?mZpaFFuʇ ڣF{} R04` ЀZ׋okssf xC_mղ\5=mdRxLM sc7E03ym`@^'KiySJH]#V=Bb$QTEl vS`e DLV"ԿT3oA4T/x7\2O@5?Rw*SϷ0HNИ}S׻*=rvqW`#WxЙ~է0xQ_n=SMu@?L n`gA N5)$ VL<d @+ 4h~( V <*FO3- dt` 1VӚV Fla < g 0гAn`W FMpBԅ|6JR8Y/ݠF׽i ws h10"itid)i|i fS) )=plz)ls+eiLn̸`mpژBap^ǔH!Y1mm[ a`.,3-2㩶."ji irQ1onl+lؒv?ޜV ګJ A׍Y1` ϵ1i<94Ɖ1ֈNNc::14oʹ,)X`0u8~Ơoca'ƒX0#0( o}(X_V K7DŽ.1v2pߨxc@M\Zvo?lRxDϢ fA5K;ΛO(c`܈ ZJx@Qk)3a00NR͓9$YN 1( "iSg2 +} [)XF6W W %׀,dR0˵p.a_A2SvX{r8h  {Ʀ,U,j] f) mH1pi&ů\H*T߾>0Hay€9Q5@O@_ta*M58> 1WS5E0-A#b<5NEt$a C'nX)Hرuιn=:n[Yn`}e0h]Q$+z&2U'<6o Y1؆1n0ژ|7`T0x;Af` 0 Ajar kcp=4`0H`Й|+I.A Fb0)?Nא4` 0c/B` .008i?==Wy1x4>ދwN)'[! [h4<]9.z 0?` 0[1΅ee >\`fY0>0(F'*` ΍/ ͋9 6A%040{&Q[7vSD,`ݼa`n`Gxy/ xqaP*({jӠNy  se?[8̲o_-4e` Ehrɕ/A1P1[ÿb9W #1oLi?I&tUpL ,PD vb!ZϤeM drv v^~1ߘ{E^+lReØ<W}&Uu):AEy\Y=9+%VayV'z)_ŠW>#\:0_t0&u ٰ9x M)SX/*b_}es)FSK$1=^~b Dݿ@%0 j RȀe#X9ʎ%OzRHb*ս^ dF5k֣nGC?O&a~R0)9i^L[r.5}5ݕt i=cV"4+WcSdW# csX4oRv~DUpTj~Oa*8.R`O 0yjO%`xKbu`A D{2H.?u0xKQ̛] c`@B`miʃ[O`c8BA7"a/AnKJĤvYolqi@`IA0h{K7*H>BR-+f_%R `Lnf*` 1b0TJ6(e^,ڄ_}WG =KʎT'2cD[wz>5m8#0XzB _1]Pg͇8c GLc0 826J4%޼+oX9 J4%"4~ !oapLj4Ϛ8>Q@@f2`}P ݍAg ,e: ,_@>Ϛ h45[EvN1cH΀ݞ5Jac1O` kuxE k `]7YWHT>u<϶ 0r,V>An33A+0P{4q{u,)07fpyM}0XrI+.o#94pك`U 1mdrGj( 9vGg6^#1Z)7Ж2`0OLp-{\ `Z"5 /bGH*X{1waWW1*W ݽ(h魫تZ .K#|1FyuYp#{K`) X;5Ip?;jUFTN̺PC܀"xגCb_e~ LD戺`m \, GI캊!.![_LVFTAua *6EESKnGbb_eDJX:0ȫH UG4:|SɁ&`0XW. X),AzNm$G,0⭓5>3., $% :5t0& Si1t0أP$.YTb0HN]O^ DĔMc {1AvT2[7U]jP>I5 ɳb0lkK !+@D:T|q   TA {ebb6DUE$ R~L07uc`d/qkc0^2[yæ3Y$K |+#0H<wxU❃B[%ցyo_dtva>yf y#C7PyD92u1-*mx8 2*ֹ<(. svE0@~K).W '0NsZ40(S a Kp-` zG*8~:YFS#ԔXq 0LaE݂\P#09Q4Jӣ5?GS ,~{EF`0{ cg@Dž&c!-pـ1YHua`C *A,#2ڢcl&QѠF`0э((xN a * atrB%˗*9:ܱrA`VZ}[HL|低BF`Pc`u(uwSu NQc \Kp-` 0` 0` 0$1l&,9 )@ ̿ u b .U q[S`apq[| :wzyMo%rA < P=݄\rc *>Fd2H ~Yq 2ǁP};"0=M؀`ֿA'+%+]l97&%UBk6})d&EDg `*MRA,`c`q Em=N0PM6lWW< RK5`СkŠZTqS< a l{2`tߊ6o A8u€X!|>~i@Ğ VĀ] :#Bi8Bټ"gRP@`tpcb 6Аf([)HMa% n-Z*8;Ӑ@z8OS_)$J(n@Բ8)kap](K`0ʖ<ژ Kfu4`j4 ̸ߠopxS0vy#0NـA10wsJ0zK1_1r_gN~n 0p   ~_Nd8z7`c|x Ϸ_A<[00x +AAZ9a^/ oODA0(nZ)r9׊`ж<`"D|1Rv3"0uZa0P`1H xwЉA^N1;;wc )OHWBAPޤ`R0Xn}T#]hcP`RHD`o/ (#*oڠݖ_)0@M௿e H X10MspR(kcЩe9H,G`i = R,W*}ƿj0Έu?T_nmM j o!`pr 诿+07L w*"0ݯjK&]z'gӖ1}`x[w;`7{ћ2 08?PV`= :jJf[~X>. NH&9 6A0NǀHﲫorǪ#T00-A 7:zKAM] c ̎[H v-Tr h `aɂni*0#.[H}ZtH=W <1H0` `?{sba0{cp '0Ƚ4[p|=@\\0 S` xwRIā'juf 2a#:$ sFf c 043s~b 0Vve:c 2$ɜΣwJQz+*/*FAJ@\oTÀlc0fkNr9 WGJuD(7r ,VL03 Wl>")h|17* b')T;L8JG,`1hzetJN K_0PćJșgbLwJ2E0 FI0(:)`Zh[0 L 0Lb,v"@,R!V #vha(0)ؾ +K :00  14r>3Aⵁ0` 0 Nv f ]0`0;4IO}kb ހܶ#0Oc'ۄ'h7`  cR q'թ>ur9 ~N&}S *Wn A2/թR >mE0ȼpmPY. UQ./OOTҎ{'\ s0؋1 ` GRn nN1R a OA*a@R o[ (%z*0:A@@^ 1 ׯ[2jI F @Ds"_)l ǫqs@c48v:7>N'0ڲ5cB#`' M Hap c 3Z6 ˮLj bPשo;Tv, 0)(WRgWY a`pc)wR` 1ل tX)n v` 0\;RѦbЕ N׀080#n&D ̿ u b;2p u%'q[SL.A8-G_On*b8Pt+-c@` ΎNJ1H%z1&`0[@og*- D7 ےKbPgœ(@6YADdHJ"Z̀ԩsdb@S͊0†ژ] g0I;V}$ KaN1` b6 {񥱟`Kc%/!(`+0a0+퓁v1-e`u 0b08+a5`pR a NATqI }@3]_ V€TPUxwwc;`h€| 0 $Palߩ 6߀ZLs`X v_0)`1aеo` stJw']V&``̗35`PZb KF0S` 9$=b(ݩhQqɳcn5 A+29bՑĕ,Y s&π``f^ t\ Z%20~uA@f"(` 29`P/ [E,$ŀA@ma.ap R@Sw#1M` ` Ǔ#1 |QjV+`;bj19SID;Ơ+8u ﺲd-NjN FZҝfB/ 06v2?.o`,A(V+0X Š).]/yTAY ab YLRt`P@[@%0`oWg Zf> 4_A1 a0:CtZ* >> ,- FNqIDAT 2`]#O Sa8_0 ֔0XnTx0X=08 0@[wv/KcPG^w~b mSB0X`C`9 Lf %1 A ` V|Q5``qm 6)0(A(B䎃Bn92p u sdt9A8Pt%+-clyb n{j13`u<?ԉ8: 7-u` ىĠG}1F{Ā:008€@$1iҌV0&wn=F a Uf͊54 }b!vp@ N:06^;)iTE`pR u<|[@ D g9Q7@ k924ci00ЌVĜ|` Mb.0XHqOa,2f;V&6x8086)o0w`E d9NlD 08z ePVxi Nf` ` 090DjEr&(fo۾"9l ?ウ` 01g208r&c1l|״y ,`Rh};`pn h0c`1 7.u7ovuM ! o~RPO .'Ǥb̃KcPVBZ&T8c !H9ivAs8 `0 c`lIdzi@ފ, T  l?M 1S#qa L^)o q[IvR1 N`E(`&4`P6'1ԃg0vR@R7? whN `ͧyl1t t 89m7Za{>ԅ=@u^ T+g208#0p Aw06` 0H` E}uJFc|QkuH>*Ld?Wt``{ҪPڪ^1H?ƏS߅/wޙ .@_<*+%$"]u닛8i@!&N>B1ПWla0bL cF8T?$oǧZ dCGc@Tb4hc81`?1'Zqϋ)SBb[@ @B*mKkhG͙ $F!G…@i x 3w@Z$=y}MZF6]گRI vV D0&3 0@h@Rۖ:4t-{ h $5M` m= 08<"21`p .h<\1S\N4R}y<==c|ܪ`&gM]Ό(oD_^v;oOJ"l 0\3gp1)ڏ vɞ玧 u#'Nà׏@G Lno}` " -!TW_ݹHC \d.@*=) aO !&jHne?AxGs,J*[i1\)BY'``G0a9U}0hKZ: R@AttI d9tX#b &aK@,RpTEP*ڙ,c.:Y4*n$ă-N S 59ɣtvG3?/9>L=gDs8rʒIƮc42i08kiY< Ƣ=1VylPbiDE4'0Q[dP\ Ds\| qMi2}ܳ zw, .[(/q9f(}vBs?ș0`a689u-`Ų\tx G`3h20ə|RuJzAYqi ÀO,y1=6Rgc5V7^S6V*u\f@uy=gA;И|aL>O \K,1[t41c0Θ6 iDѤ@[6` ͅHFa AFZ PKE$3dzn6{ Kg Y*b 0}J6v $Ui.veNi 1faP# m4 X@< RV %|my<9}bќ<ҠIuђ E4K71@j$1XG3he`(J:"UЮ>3oJDdThoq 6 aF013 ۾ͳ8OcrٛvlƲ յu:KfbGÀo.û;O!ܙѤ橮Y4FlY9f1{\2G/w:vR fp4Rg) &93=:86%cN`J젦I1(hlȅTa}g뵋ē-!`07eM^K`f`B0Xc0of0uj\Ǒ4La0-uvPy5 ,JN8ݸμ3ONݿ`k4ߓ:tna b9&^X` 0 ˗Xb5JiW`= @0x+0)$;}ǀRaV:8K<'ޖeHukǗ/_0#t4&+i4bl1C'V@(ۇl&ʷ&_R3wcṕi/t?``~lu `E*uy/ Z`@\/p*b, 'yTD`t,n0b0 m>1y<xM'Cd2C=i=VH%Qx2&U0؋4S1.[Uf;uxg2&0xh,=` 0 xv \䔏ˎJ2W h6&9B~a ( WmY,jOvő0Xʵ&-CaN`6 L]bjeaDV >%ُK|v Z_R`O0Ζ/En.<'r#QT#T?Rsj+!}h$I3cg9]tWkR֙]0?-`Џ?ٸ-ɸ0QIb`2"[7v"`3)qd`0d°ة TĮ~|:q$?׉G `W+,Mcp'ZlN  uc _kF1ƏR2mVqY1M1քr:< 㤒Td3c,ucb;@%Y(=!,.o10꼂I +cyԍ sb {  |]cDY0bR+LzR~ xq}l0$Fc0z֢HMj?v>Ɂİmz _kV! LZ01?wRؚ 0j|(kOzՅC2rR`YώaPzC 0aD }؜T 63ɋ &O % HuN v >܇uc B $k |yq c𬿰Ab :mS0r`shA` ou` 9﵌aXI׏뫈!wcIp8=aM9%HլplSY0N`o0l޸0 c>~n9NVQԫ Ǝy.{`b1x<` AZr%1@ } s-͍A?bj;*?sc?VpiOvX ~U1g ^)4û` r,[7`a nX4u@6-{}t`ڱ1@[4` ЀZA4},;k"4ڹ]kn4?G;KGj?'OAٟtIME-_=IENDB`gxemul-0.6.1/doc/debian-9-small.png000644 001750 001750 00000002733 13402411501 017202 0ustar00debugdebug000000 000000 PNG  IHDRtc}6gAMA aPLTE%8K^`oqw  %%((((**++++,,,,,,,--//00112222244445588888>>>>CCGGIIIKKKKK\LLMMNNQQQSSSSUUVVXXXXZZ[[^S^V^X^Y^Z^\^^^^^^^^^^^``ccffhhqqqqquuuyyy{{{{{}}}}}%%)),,..00224466EEVV``ssxxyy{{}}ӹNMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxևSPN*Uq+E*T0Rּƒ߳>S**޿C< vHlJppEQ&@*TJ[Є-$i-ǡ@m@j jj¡ꢾ M-UZ5.fTVi]Jb<"FLĪ-Wɨ+uc8Q㉘.3F9wΤ ɹ07-˘:gcl.Ljs%uWUO/~/}k gO=y㇨0aY>/-^tu=7爦S8tW|WF$DEQDEQDEQDEo|7'?> tIME +)I'IENDB`gxemul-0.6.1/doc/debian-11-small.png000644 001750 001750 00000003022 13402411501 017243 0ustar00debugdebug000000 000000 PNG  IHDRtc}6gAMA aPLTEK^ i %%((((**++++,,,,,,,,--//00112222445588888E88b88>>BBCCGGHHKKLLMMMMMNNOOOPPQQQQQSSUUVVVVVXXXXXXXZZ[[[[\\\^^^^^^^^^```aabbbccdddeeefffffggggghhhhhjjjjjkkkmmmnnnoooooqqqqqsssttuuuvvvwwwwwxxxyyyzzz{{{}}}00<<>>AAOObbhhmmooqqssuuvvyy{{}}MtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0JIDATx{T2`: *&X`DL(3@ׄ윓,6\ 2鸌9$3|i}<=ݨ7M?>Uxp?u13[eτ>lkC.wUH]6[ƳvIqg<]Q-eYt[.. * @. jhT3TΔF$ arf% 摮iYJn)_N)jR"EY94`)!#/@!xbݱ,b1R1"GG"=PS."b 8^* c4#`teySk%)*'J9Qrtz8'$$0;氘p|gSoU:,!^2RY\#pHVe XaU9?%Ŭfmg`> xxT xS1U3MEky$=}_YSH_s˗.^zU |sx>D7}-D_`"L}٦(E)JQR(E)JQR4bE@^y5&<!&{Hr>tIME 9wIENDB`gxemul-0.6.1/doc/20050617-openbsd-sgi.png000644 001750 001750 00000021476 13402411501 017625 0ustar00debugdebug000000 000000 PNG  IHDR%TgAMA aPLTEHHHVMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATx]Yr:Gmq TGQ#8Z${-daHfMG{|#ȿm#q GNwGsvp0\?_=Bnc~{<z]n\lQ'cED+\Bl+qZw[E rd:D,xȶl}t9ϻE1 j=JM&7zar 6lar~Ȼp 9+Ɍ| ~nOSWB} vt/ؙ͹T^cؼy]"8{7~V{?MYFni׻璩0R m.R~r{[sAc8;nZt$kz#]bS^w pn*]pyo5;EN֫KT%ĉxK 9E{K/'PR|÷8-9NS؜WP(Ϟ׭rwdVdkUXᴩQ$ro p-'q8E_Se_aap?mBnwW{:qpڅ;9(Ҙo_GÁ9Rsy?CِT J2$ %:B+:6A~3?NE09RdphD^ѾSk\HOpfgؑl)u8@:/\\`p(u8!m@\y0Oi9- 6/q^ɼ>8\{ЖV70pIV5moNHж(ƾ:JX9țZ"oáTؘs. AjQláp`y[_jcGod7_R >aWaᬰHMNIqOU"At?oųE+\ik&pQ]N;?p&iNMNhm~|<$MLd|h=Lf =(؝:C^"ٝ:kTRu9 M op.qyjcNWӐT9ȟs8쎥!Lpԝ K9$pdc9o:\psx8t u1ZiX-B3I.'$j|{kO|$\&N鿊p٫ .Ѥ@ոpp&@"ڻñͯSFܣ'-"{ruWp ?5/N s8m%K kCNC~n^*sjDoʁA lKj'2rmtcs|SR} c?^MKBg-؜"?9/uZÄKEG fqtF '3ᒤu82\\^p^]XbBÕ5LjafyCIhZ7jÐ:XӐ/K L&9 o(cU`z#m!p^p 9ƈ ~NT~1!R%6W[Tp;B??yu<-{zKePG*'YZDƂ7C {Kb"tFNC|n TK!Hr%phTp:Rwϗ`G*c(p/]KEH*mܛp8j疌ԇ"[HsQ1X.xՇc~Fs&/I^>L4u˼Uև{j\=@Vrm~pRʇawQp@}sܧ> L頁49k4Xdm>Or>O"nkp{+ut ujDpʭt8))sޫ/[5p,ޅ/y~2k{-KV =%!pțK}8Jw Gs8MAITU81, ԫf H ܡZOyO )p*2q*_*_zpx8tRpWURaÍx>SKO^ ;!N!Q$9aڗ9]_gY~`ɮA=~qJ<&Wl\.B^p0JFW{rbʯ!?97^kpMmp>?0ç4pxN[r 6jλ4D8u\bas8pp'5~rAnw_:q{m*p[Oˊ 7@V wpX.:l֟áKcVY阴ս~ҵ~QL*FyR2ySu{yy/Ùt3!4ʙJE18`2t _*6GT 9=}/UdR%AfNN9}/k&c &3G^P&/9 ̀A˗ mz'!o94LvK EJ ZԤ4 /T&4X \AKEp9,5owYy;}\i_5H{$nR ״:Rɏ~KF~_Eԇ#s ީGdrSTG W wp5nc?Wa|J{0\|N}bopӲ͉XhZ:["g:Б*3uϟprSi ٧xm@~&:\Q?-9%ڧp8mLpP8Pk'ppes8|5;ԪiNCo]j4`K=U%Ripa&n38\۞\./&pt^{RhG2Ӱzm)rKCp:^.k˩kxUp\זNTcFu.ڲ%*EE8zm5zm}(OTùB:\^ܧTp8.Im*ը~y'Kq2:H3^_ᒼ::^+c  g>+wq8/YvB"ef78gpӤ^pܩ'VM/pܩ'Gޅ%.Wa!r;罴Y^T.R\ñORjDNy/@?U|zދ~:#ݩ'hb䉪8:]4L78ܟeCn3ax}{KeUԺZVR6Oă1+\7d~7H[(eTizj!h?;ok!܉(]i3:Ei)@R9\zm>I@rF; iυ&+>5E/EWo&QV_Q|iV%"Ty9MکZSB[$1s|%\S$~;A`)NHv)ZW :.WoDuN,  ]R %40egy\L /qq %Yj)>웨nՊ5nir8E!2B:ZPVȅ{](f%9A2գˉX ȱh`Z82B\{B`|yKR+*ϾyyJ@ҢTiu]\q SZBw[4eWow;W+7+x{y_l,_Rպ&#|oO rOZB.K w~O_-D鼖W ېҧ:O.ɐDBn伖IJ:Ӓs]9YPuD60ueiwn|ǘPG=`sOȸS*yxL(\*F{^#tu&G/9 !9y@>u*B񚬼9Y ɷi9&LrI]_W"8JdAYF^B*2؞oi .3ݻk{B:9aJ'cC|ܣ2%ӕb(k#ʁz %MOpӖQp_ wwӶ3+\gQhD(AX$3k.{4sؚBi(|9k\7Vi4s:$Lh !,y6%{Q\SKbD4{a#/9!,;p_|؅"r^sl~[u>SZ`^o [amO2اآ˞,k%K\ )9m5\ٚ.gNX_wzCg2/8S4얷wb͇-9 =繘Uٜ]t ǻS'8{)Ct\0D@>6iJ4_3GH{ ªFa yTIor)Pa>Un2&k.cx69j  'U$D(aPj6QHVNWX"_ˌAE6e v |v l&.\ѓg0h3~ҳ I3! vq9v\"\(0HƁ`=rN 60[xEEn5;krAک.#Kn/nAB.s33MstLxyk^1p^%8/.bKuV'oXu&t~p?1lB3m V" 5w w Qae?GPfo"$w(K9UƖO.&EnPqW<ޤt_b>_-YN9ɛgYƷM+y{Y:cx~ryӰQ7C xn%{҅y%!qDX2p?Oh rB;S-1|*x r%{@%SaLR3 1i=fzu)|tScSArtZae'X:$ko.|P# ;lS l>i&I?ɨ$SW(p\s1Z{nXS gHN[9oZA\9Pҩ٩|V}#j cĥfWn*Ҙ6?&caO^_ ^@tsL :xGqOOh58F{GLoB.a^ElطSsD2+g.yך@rCH{;nT\ү1m 3h2Mp"` 3sPR| fˢĄXE_<-r5;#ʼnc'JY )zNϫP&($ l;e",lj9+k 0)ֳ]*l!ukT{<ja6_t#'jwo[ds;a9W@bIDAT7p9]_fEKs/rmTq %"0 z]Tun\B p"` .7苭2gpR#!`ًjaynCRm@~qeDZHj o|3/9oq0 zͼK<:ẘHgGͼ*In26oFVgm}o^GZC5nKx G>yWȿWP= /U-& _j%o{p8xqA}@^r vfʚ~ýݼTc` W(JCGp> MJ^g7 {IXs6B/XK- .U~B-uÅ4wZ7y>n)yvp:{9/`oO0O4ҴrN+8\H}zM%U6"PY䚧?l>l>l>| A##{G7!w }Dp?yw^"-7CtIME,IENDB`gxemul-0.6.1/doc/20041213-debian_4_small.gif000644 001750 001750 00000005527 13402411501 020220 0ustar00debugdebug000000 000000 GIF87aK@ !!!###&&&***---...000222333555666888999===@@@AAACCCDDDGGGJJJMMMPPPQQQSSSTTTUUUWWWXXXYYY\\\]]]___```aaabbbdddeeefffiiikkklllnnnooopppqqqrrrsssuuuvvvwwwxxxyyyzzz{{{|||dddaaa===,,,333FFF eee~~~;;;333111 111VVV555###""" sssXXXQQQ[[['''PPPAAA555!!!EEE>>>vvvnnnZZZSSS 111""" ,K@oH*\;"JHň?.j&5T`!F d1 (h`A,. JѣBoR`@N 80a VJ@HӪEzA\E\A4P!a ]̸#" A# < (PP4^t ALQ%Itq!6F c1x`18t`ͺm8@0  H 6dTA~ "N b5XЁ!D1!0B'XV/PbQ dh tAa&Ad80A p `Z7#D$@P<x"p"x0T V[0x LCdT $ *8gA"89 INl,r D0(m"XI@:! ;8D 1ד4l.I$ 9,B Rn[tAThmP\ SoA |@8ZL=lAM 9,/ .2TpkH \G H4AB6t6BiIp (0`wn.h1v\|30׶] @l߶л^S, jQVy慛j1gnB9 Q7 EIA ppРU,@t#@Hj:l1\JP'-0@~uZt\J`e00h P0 $A@-,a Zx;@?`A_hlR^ST @ԗO GY"=`%\e* 3Y:A^\!` L~a(xF'S5eB8hT ש%# e drVpx]  j1`)XV3-:ȩ  !.kA@d|&(\?$#x8ʡ]zjC'"5/iͦ\jr%1IH.,B.P-ij.L!XY \ $ hP Z8 p=zZ FUv0F70~; @6 !'Rp#jQQƥJX&sx`:RV 5.(, A+ L1ʀ b X@kl 1C@  \ P(A}C+,7(V@-F,ă@_F p'5A?P @HGC6zoъRnJcT-h^@a%;6hV E nl"rQN^B@&ڳD 6!1 {BH p"Y8pѽyA֫V"*_@zc;gxemul-0.6.1/doc/20140802-dreamcast-bios-test2.png000644 001750 001750 00000312464 13402411501 021343 0ustar00debugdebug000000 000000 PNG  IHDR/sBIT|dtEXtSoftwaregnome-screenshot> IDATx{e?=IjIR:a%4r0JЖrestV ht=gͺn<]t5 {쎻Y Y F܀Ah!$dn?޺U]՗ ɳy[Uo۶O$H A $*nauJ38($H A E1fH3HzkR$H A $H0 LLLXg3anau`: A $H("J101N}m'&40W-A $H fq9)4<0%=㵭]Jץsi $H ATug`‘G{I)KH񁷝S Mpa,?7wL Arx L0q\?w XXetx&uG%Hpb ̚ mN܈=h5l>i!r9'ҜYPS5={H)22]r TNQ^Gl E]Lf4̡8g<z!ui/ms3:<O<^H}g-knTsG?G.eթ's;qh0ZSY F8I>s5,m8V/9_ۃӗoz?_;D-wh\0l+i^ݳ;b󣿹% =xdtx˝Y˾\A~a#Yĵ,mj#~ȋ{QC㳟闿1c>Ka 킃&LL9Gh\uo= ]p2e|U|OrO|jeMLLL]+P1Am>1?@ÑWʼ9Z3qkS`L?G$y^dxtsO^ƇdO0ũzvN;q6/~ /H+}+͋˽zvd/^{w3:aqgg.R]3>P1YNY܌Tr<]qF|՛^FMxu?W+/=[~GDzwsU{`Lܸie"h3&: aiS#/=/Te;q1z&=SqVJȑV,xy!ȰjU~%8>0x`X/\)͋g0Xfvc\ڠ_}^ cYU|y]Ʋ&̽oNj4WgY"::6c5V3ZI9\Ѹ-ݤRƛ1ԵSK%njミ;?-w=ы~4xn4oŹ|n WsyoCoG \#︋y+#ziZh⚏] `?$zo>=O}>>kX4Yls;޲g+nc?'s(Ca(jդ}&7]}!3gz,>B/~3#</;KeYPclxo~?^}:oT{!rϭ?ƯP x9M|kN [ Y&P=({ԥk3wt_{3N]ʺoWzǶ8;b qcxdr,<}/y?ƇZ\z&f/XZ杧S_\V۞x~aS169a.ϰ bp9M*=rd:+IFr*-fxCgoネ2߼F`f;d({1?!>~E:u9VlauV{9YO܊w4h{1~s'z>%u*Ըʷ_ ߯:uWy$E|{U4_+NϘIҕ?[SLJX`.S߼ҕ(tQGkJ{Zà )C{m:a4n=\| K>5fݏePA/>#9im62wabnx|31_鼇夵;Z[)ʿ}y>5{u8 /][=x#Lc u}^ ?Js׽q?W^Hǘ qzihZƢYxHե<'K5k޾g_krQnz5z[(6]λl2*Qo,qR_jml'gFC#M+< ;˩ Y❾b1_wHԪ - ? >γ9 kiO#|2k0jWU]O]ye|_1> - LܸiR~᭣ۧ=OcprOgF>4 j,~^eð \~NO5K]p Ϲ毿+ ~+3xП$뇢;*l յ߸@7S^/ݽҼ~=}LG3ڼE/YɧdWA,˒ssOIhUA":(##5}FF+ &&& &K 76 ;w?.ݴ>/.E]]_ǃa$'{&'Mu]pm{w;x闽ߡx6}rƲڃ;V'F }?!˼籾.lh{C#|nt\f[vo˿]>~tOCl]HՕcy/=W?Nw䋯bCSQ?Sg\hF2sY~Nm=}} w9@ޗe`thͫ/|'F;{#f 061f/ yWy3]iЗиx?I'x%g2p`7^}k`||KJ=;>x" ktpZ?- NniloOc5ZZ_ rdx'뙯n<^k:FY67kh3)X|:btl2LHGiy_JC;_.Yؠ.=Y 92rMJ}=/7™'&8Xors&s qHe@%;2=42<+Y,_ȸ3{KjaVQ]!sI߰ۻ{1e }!G~V̯gY+ػ_= O[5>2LN?<3Ƽ 80:i>U;8463g8/n~NO㶟=¼eTuSK5y4[o"۾&olxe e=4@}zöw~A$'Pմ>oNm^9s 0>jicGX@nkga.O#Ք=T67kݽÝbE}~G93Hե?</ppɋI͋s#c̤i}<~jyZXdгKN/']FZ/~%8~`ř!?[?#E'5) ]>U`q?~VzڼslO`7TVmb"׾xJ: BaS׼[q\“>g̤ /+Y||ARFXS1]5 <~%?eJ{ȍJ53{I:/>VV_}742oy>N=Ƶs0{$Ѹ6ww=1{.L3>1.L8/53 1 Ø W#j816W^]})}^LSM{۷s;{5,[8/ӻI?1INY;8sYp}5ɼeYzbٳ>)3O{1q͗~8麹}K< 0o_?e•m׏Ѹt57nbޜY}jwS~a']Gܫɢ~i¹ JirJ&=Q{pRt+YsȜ(%nx-᬴= n0_y5{O+}1csU'kO&&#:::J*U14K8jcOEapߣE/ԍI0~_u-3qFjݷ)ogz>a?{ifΨ+x/?IҴtoBol`NƛyI7=k6^#r矌)Wn:+|ף| w6/>ٯ| nlxY#\v)=]j!5.̌/A=epOxnw/}yqw?W;Kw3>1W>vv?7COk/۟ 닺KOTssdpY`s+/=yƥ[4.j&&&]=̙inx'UO<>f ػwŪ>`>WvsX(Q~/_4&b~ KN%GBf̞s=o=douͷ O[Ʋ&޺ ؇_*xEtBvqQ+9͜Ƶo9.8kv6u:#<5f׮fR49|rKyò&>KOg;8Ň.;|YxUh\̑ͧ~ѷ-~W"w_H{.ⵃb˶27suu):0s_oi@Xs&2NZ߽\no]g?x Qˇ6wӚ.bOa/dHĨ=#Uru]oty?-WͧgA_bٳ.{w}qq}ng27c-~y#6~YЗ{|h _,0Κr]gr;Q{}[4/Ͼp3ћ =sC+L_9>(ӝǬ GS7nU's/2 3um'Lfn|#9+glHRSNS?c3f̢~xLF&811>@.^铔'U7C:碟p_~ ?' +-ЋyMSئOЦ;SN:\io {h*mh/[@WXo9Zۡ+bJE\G{<)S 0 dV%NF2ߵf?MOH)Tm&WUZRp""u$VRZcv]EFr`7^ix]BZ cӺׇi17Q}zF@kRzB$UeP5JI(@:k/n>DԊdbɨI$I-"^=[Pә)* (;Nb*PwXj"}:>Р+>Ysd 7Ѷ8u 0JE2HTV'S۱1 kitIks)/Ȍ.p PW#TPWAuIhfAjC6HfV J(ois֏Ǩ@a*H%X f2jS1"O' &tY=BhmpEY lże3B 5';ב!XE#.$CZI he#Zʜ;P# @T_A4 ,K@~Bv=<Z[C:)%Pj7c.UC˩%[|uO^3 8 oҨ:4Ȣ+ Ŕ + q}fz5)PP.&M-℡AVdm4-LF48hwvvvީ^)&a5f e(]~]?-g]BlzyiNc7:,0tȄf2Zu26"&8$kvJh'ۑ*hT9C+%J m@@E, MR5BT6Zr+j9n ,S* rԝ67ǛBv!ZIU;)О6)ii'd1,2o `w]VF>N,WzP xt~-PN UMj(tzZtCQ SM2c7r,Pra wxhQ|CUB*NB-?Ûy2_X5(r^ֵd:z0QG'A"%> %]\1upt~*7u#t2y=Gv>nyqj}\bڍ2➱Z&qhUwזTϖ9=[(eXR ;BR)0(}\]8rr)kW`? "n{XڴjGFDq^mi_ hQT x}"`e7ST1|s5l\ye؛7B@#N:Z<5,9%䁀.TAq̙&Ձ.KZ r{(!CгΪX+P4eSY54S/tj(P7T3ȨGBo.V^ʇ\WC:CZ54󽾺k4eE:*k763Q {Q@ B{sVϪNβ3XWLαumv涕mTΕ%Jӕ &HNmLhT߁JXݡs9JUS>f(ܨF^;FESQG[T?1Qt*aR.!4ڏvRjo6ɜVBA.?^y"ogpH&bD(-_q(ڭȇT5 ֨ d`K:3j6ʔvJj?\݊Ie(*5:! m |ju*쫡OMmUʵ.IhgEe-c[P@&yX~5m@/=ZHT!u~^ Liw %k74uHdZ/@QV 5}\n`SC<W -QjA%N<@ $ mJ(iySОy27/1#=T}U j Y%E MpB`dT'YnT$Jk 0!rju΀:p\( j( SRC< YJA.Pzh'qj=W>8~bN,_WBz=+999znMZVdRdԊz/|Kd)WZ'P'M%/;oGHUDH ؍PʩP\e?]_{u>[e~. 0ק`^Ĵ>Ӝ@B~)ѢPFD/ ,3/8s BY^?]ZG,R>pơAB [v΍2eLM;GB)^kͿ_ 5ڢ sw J>AEIKlk=T }?>*#UPuuA¿'n=t06zvI.gx{ Yq'[j+_'ISal/`wjVvhT]ҰfN7)ތ?ݤ"P;Ey5t2(3ʬP? @B]up Z4 W*4Po)dFǟBOC8$s*viPGMhTw_6ənjŝF+͢,Q-] Aou~wƧ/ɔSO i jUG\BXΗ@Pn'"^lV-Ң$USLIԴNW kv*w+.^rȧ8o2a:hax2@&yρXTYx]CYj?iwσ::$ |ZeH%ֻ ۠oidI\D9("V>5;izɨK$4L@nDIBfAOQ3VPSC5S6/UCzM|!)k6!X8IBXฟJzO%UIImZY9!=t*0z*h@ ä[(?s[fʹ #XŤ*S:(sJjJ(^'}GWGr bT_G*\ >4Y!rh-ZT(!k3hZ$U $ jhy6h7IS|g^βlжd#OPWi <jo.R fy5*.XtA< r[uWƍ!FR Ex %Z -L>kP-JUpi%pnr%Ьvm*p XD&sIb:*MJ6ՕMeI xbIh7S1R1E!XӘΗN*D`R -_+ĴSSNuӯUz0B9ʻR/lv"9P{#g M @ܯԬnB\U'xf6Df&H<Ø>"jfxAR` ~P6}ݑHoB7$4٩WAX(ζou:?v ;mDVF&bI:&LBU5ҀS0iAG_ofy2gg`&Ih V5zu]$oT 8^AfeuĶ v &:P(H|jS*wgO  ʱ(mPCN'7-{c+'K!.|S|ī?#WGCl4"hI $pVĻN6-:+ SBrJh,Ui[O -GB3-%Lyp FkT$#:YMjh.횢Pkm{P U}j@[6 @B]8[CV,w`( ޞ QtQ TMƔ aiGVm&:tKF" 6'm[i J߱]QC}[Л_C`_:Ci e & n Vp8@xoM:쪶@"Vf޻_mǦRRL*,Al+=MN'`,o !FD/Hh X9Z@62YA)mBd1t}ʶv v. {]'z.[*tmZB$*ZrkXJ8P`q j ͸oms$ԁ-B:݂.Y8549ᩡtX[D@ ALwM -P{$2WR7PaU, yp_cߔS3K0L:AkGYq1kK].h/!ߴbiFݡ;6iA`AY]:ﭡsߓD5hԥGYUq3 j'[  q{ނ5L PAZDNV_Bn PC\Mqu}ACݖ'H4X:֜SzCB1+lɠo[RH]/]ZN 5z1l(=[w"IWzQ;^WdT!M7Cٮ7KB,$3% *!-<5TއX5۷ v?I5 D.P2 MQEJ()'1T$*b 1鎯֮[B[TʼfSM?t⿑I j#eZ*!N=wAmsiccIA`y 'Oh5JU*vuFxϳ^ ׅVf.Ϩe jtĈlZWL)"iďgՒTFzIG uiw ȸ\-HT EMHa@>\ΉP!$68e$Խy+;a ؙ,?W%Bj3dJ (]T$NZo{{{$4c93¸=CMd1#P]: LX"Joh6#37TE"4cWCj@/T)ۻDn|A UC5UJ,H9 :m ?- GfE.TˆK֪1Ɂ 6 8ylv^&0QuӯL mlgkm8p~"`7B6S5WW@#S%['CHݾE{zZ<)JڤxY UR]t낼 r{=Xmq#Z^vft ^iwP|QVТ~x|;36лR`_SoHIiwBtNz$Pr#_I~Zna4d~v26JD*؎#74F fNVQC Ru IDAT [թP*@>5 h=zdII>JEPIB]邼ָIS^OGZgz0vMm@\osq 7kˮ,I eezU#۱Eݑs8-Uv 2;~aL*)ZҿcdɵJZHiZU_ zdIVa^-fTam G^kqUr=ǭ"BkՓOO]qO놆 `RVE5g׹P!X$4L@ޖ8ra_Gh u6QKGBulw䣕,̬.9.6M$\FxPh&j5 k A&Kf(cK*VKp^c~ir t,fh^oɨ W!aEsҶP\(ᧂOOGi^f >–WSǴѨ m3WSaӔnVC @Y!=]QUT-/DB \#[!a0{c{X,gR:1]_TMRQ Hh'!$`^+-1G.Nr JPuJڵ:sVk s*FJM,FQH$@)"~JBs(fFPPHhLt<ĸ[L!mquM2}Uj2)P>nWD3߱ӌS\:3t4>=TncrԤf2 RU kfjA*&AJW''A[PI뎱[y}QMݍdVU4E|۔$4\?+W)% ڂ-ۊORtYƾpdݸm&Y'',juѽNK!Haf4T|J$MPP-$AՃG'Z MV0 I(HMBm/Ұi(+4a"Xö9ܶ[uU&VZDnT֏6d~QD[i 2GhTeEH= Q1Y1΄ȶ`(Յ` k>RPwPJƬ9Gm.r[}BI@0ث"T5A<"k1VQښ)sK"*.T9\p )`eAU g_E*ҐECBsOpH)n^|V*My2/e< **)MaP{K~5) _]B vHu]#Am-pBn?j9S-$unABMt$`DkCi{9 LI6 SMS}Sv-ς>zW;ໝAu4bYW [2Pa1eTBLIҸrαL>q+;b/X :k[ 0cҩ`3!RZCQuHi~D!۠Vu=ZTq[H'' lJ^h:m93>R7YLD@ad uUҴUA-`eojh.[!JIg"20AٹӱVRC m:Z z+M&"P U"d , y$Jrgn(beDKdӔ([*өfN|f&!"zqvIB[(@& 5s.F@snPE0 rRLv Ŕ_3̩%$sZ,|2 o♀!*wP%[X҄ 7Gԉg۠Řq&CZu^m9uN"ZGJ]""_R2\4 0+M`6:KV7>vufq T"N0}hZ*h.:`r "P}3|oF.)>b6P{ZMkz|j 'ᨚDx;+n$+@Iv&l%KFʣݩUGB5SGMUgk; 3UPC]SCewEQ?P:J478 7RAuYZT5`[Ԅa9dYTBP ҮpڐW}Z5ͪuQN~ѩML]e`E5@{`a8m&QiR %˨ &\:01uιN}Ak.Lb(5W.)9UGOR}Jyo!Bte m9h(]ӷ_q=BE5D;+墼i`GDTkX_g ;!oh:*(_. _ ; PQ"n# PE HhJ&O(* J6-W%+Z ΢. 6)ds.g(=-ģclL:$U5TD V)(B%۩@)(8Jʡ 0ƒШD+Ϙeh0wSg|;#04ṬOe=]}U;_& ~ ?Ik9rP חNqtL!u~UZ430s8,|kV9b"#wQͰ:YB)$6qPds}qQ ͗nLpLUTPV&M~D'ڢN_4$$!+C 5QĐPTZc6x>#/#B>JzE7ѢV; .MڝU  vH(UCFHCFQbL9{yWHޕAߴv`$k   ^80PPp`a4, 444|BAAȈȪ^w_WwfF_Oĝ_\lGBӒY|֣#.@II"`T"ihV*mv( ]R-!l*$ԡ전0XUICyQO~&`k$9 dH(az?O瓍{ťMazsN s/ϝ&ZCM߫qf'Wja"%@l:E=P|'"&/7& }V^W7&tD= ]'y "Ƅ(5M>& R9[#$H;Mp~™$n*i KC]P<(ĶZCFAPIiPf3N@@ZM@~^"1^kFkI'0mcFKNuZ9=?ص{ 3E8? #% IbrXd4ih`^||P'B[1Kf^P#i1W%f'^jkoa^WusӏL7gDzoRHChۥda7;0Hb~c˅$2P'/by/>#!I(Bm([XA=O x) =io#C\+N$e X}jw UXk# MI(GJ>9drB6iIbiɰF<@|&ןoiR* DY^BeK@bLJDꤡ@4%EM>MAI &/Adu݊ڞ,~h^޿lXRE@ JaH@cyh쒩<Wm|d}Ud&;^ϥ!%m)>babf) i>9tΝetF%ڒپ\l lB_I+wSprl:݀p)ScU6>Ki!xHz+Uvz?R z +C @ s-G7зN * lG<^$t)/4VVR1%0`mVRih+4Fz4Ó;vdz ICot{N\i8IK(+0\}Z~%oz>ȹZVk|HF =e@L@&u~ ʨG2 8PyKI@74H3$ԩWCgU <h#I͒+I(1y`C7fd! IhFiQ#7@ziAzhzD=G q@ T-:(d>`):(QrJ aRJԃ-ԡF$w7ލHI`Ց@e24Qm.:@H+%X\BZs{bj+??O.9rrj?XmӅ |?3q#'Ou!SO.;~['$`DKRPEa}OƑ'F׿i`/|l:'1u<`s;?l}z~m!U%I#Z^/K@IOQE%,پaKCkI76vkUi(p `PEfE?^DKu-&5qjy P5ҠLbX ߵJudIhGaeRP1 $M>ObpˁeWV#⊑#KmmG8{WsnNcișcPv6' ɘ,/:ӓEUg9u;{3@$,ň,|yauECꐐP` ⏏󤬥sXr䜪̗_ f1QqO|&51}/[`&v`nZDTT_Ho, ';>%Qy7+i }"0- ߾?Vhs8%~p*y2\> co„-sUJBPrxi3Ti ICD$ =",نxiØZ~a4DAP)i9{G8I%|-$tH@NBh1 (YI&mm=+1ݚ:j )RI'ʨN~շQd)HJ:gPڭ:_sJyw x$-:&ʩP>9п$= ~;VA-T-Vf{,BE:'*`<TJh؈@@=h#=hB@= ڃHASZϡGbVߣX=sմ_miW&˥PTW~kUJB6ݒPxZ 4TuPr!NhQ]>4zxi(BOIi9$ ;u&/x 1J-m_f#; IDAT|' )KIt0p' d !xp_DldhڞGEL:TA37vV+t 3n/e.eK{!5’P=gRP({qT?r)`Us=L%dO V7o@>,#Gs|ҴRlR+G a՞C* a<<JL%f5A4Ԭ1T_So]>1 H(ǎ&dg $/dU 䂩$DG.KA`ΰY/_ )iD~YJQ?"9ϙ56\kiw8X C?3Zz!q:'_ߦC_{kRln4p0ő"u؄t' А'KA9 Rڦ5>~{^i+EZA"rpkuL8f理ՌuC:U=A zj2@B*"g-#*/k~KI\QҲQﶦKB&KBF:l[^kCUI{ }ԖIPoG!ni ~^&MI>XdF8'UI@0I+xih/JCh^(ZEM> smolC7,d_Cʡ2i)G@mZ4Sfpc`JnMpjO4JH_9RR U_g{6~/%ʤ*FyuBZS 6 y{ R ̿6r2Iп!L>~o>R& A7£~7gDʤa s_7zl#\0ɕeu,DvܫeUMw&ꐃΉwg( ؤl\yJ$]j' < %ɑФ?5$K?#H[?SȒF!vL[Ǥ7,ssL! M'MEK8Rl=ʎ knzVKHC{lH*WD7N&3PF-~UΘJ lk`GCjI(\݁H(Ӥ9ɨaKf,pcU۹;B IiI5?~ƇP"%MIۏ%;ڲsLKˬ#g?Q?,#W\!#K|z.Фc^I]A O"o.Z1S(Q-pՅFJB)=$Cf fR`7&)ZNP&><z 㜴!CB7;>!EDB$tI,8=l/Ɉ~s~sUsW|i]R*s\tLrgT$!6 ;t-ߞ[2HB#;[qNWEgE'*B٭ (`I(FnX  ƑWP;v6Adt829T|uy0 B ڞ ʤS\@V}nf;Uv+OX'<%KT<"ؕ.<#,o̜"ѤuaW9oCw6;79R5ei=#cIL펬m[j/q#4GB=l.C;KP?>!5wR+(`u%*x+.ԩ$t\cB3j?y%#Vr^$ݖ^mB4(- sBD)Ӷ.ɥHم~n/j-A>,ÀBLZCKiaZ^֡9\B LRNHJCKp)t8v a^#&Y;|UB51I_) ϐ$eT A SdlC%-'fneSn ~&.YF.gLID{ tFdF}<|?6aO^|kIs*!S%R|GSQ?Q:TJg< pIEz6X}t$w7f塄'LeHX}/yyFp⽈,x=fHCDyXBٙgShǙNHh;LGDWZg5THҾ$į 9 K@v!#nBx=ʫY9YR!ϐ fB/Z)ipe;k6Tz ʔ[бzNoz2^k#ZrkI _4[tx.m{Ä(x}" }u z;xiB_uq\=*)޴4JF#1|r2gq^P$@$;#G椛N>c#fO~4B(%Q[﹡buiwsKI՗@AM)M=gi }s9H\wjs" BQQ=?C?/dax3yًҵ;Q}n@Mzߞ( uHI2_J_M$~UV6YJA:{>PIpCes2:4, U{ ~^ `HmziG Fs2r1ODfKC$\̳|&Zj @ig Y RP;@^ rUO{JIgsy.>0-2 ,w扤pW4oy4jYOsnk|B6gIlHz7"RY&*EkDmΐhvfKN%N9ޟWo ܡTfL i;;79+Aޑо%4kk '쀔* 3E޶$H?!mļkan.1>O9ɓPE?Gb gq 'ozWMLBdH.WH&$tEx( i3P @IXZy14 bHk$bM!Ϋd'zX}vͥ0J@/јC@ݤ&:&Wb@@|\0wŇ`KSGa;)RlsD=9%ˎ_n6gɤcy]ƮԮj$~HY՛V@dbx 3FdKiY8A)_#QVkh7Ó'@0W2qGS. NbD%!x9~Kݎ=rv0KJ Dg椟;LzOt=耄x[Oۅ*0Ih0r.B77}/՞[)ū6D, AI!+ 5a~HD 0$HC /Ƨ8Z3ާaXjȎ̜L|Nhxy$!|5mXkq2>eCdB+h|gX.yd!gOg_tGd?)&ΟS[ti2i3&uΧ^jMXxD {~ňh$ }">?BY`P8Eڼ U$P"c J$"u,jo;4#>鑠@9'eW8 33R#x茔e!4O\Xiؔ\54TMTNP<鏑a09!HS9[$p9Z9\ P t%ixQ% xuz%y`yW>|'AB@QׅZ | 5 #9_:|3Wn#WôGa&/@c{ w1oͲWhz\ň耄A'P_VbN-C31Y) 'c. cap2 C@y&6: 6K~2pMZ x!3bID3Pa/ۆD4JTICz, X})yr3e'GB> iH"Kύ mֆb)s*$Tf&ul;+q{+ `,C(~e+)/Q&LڌrDU!_޵xm5r:|h>#:̫8-FDa_֌&) ns>t $ͫ ꙔR\a8(|9$Tڲ#/0$Ԣ]A飷 uao%!k+D{4tHCΎ9(lCk$E >42u }pXW@LwdR?{*w'5iOJ .iC%Dz{ʖy2a*M7{P;>5 >`HgOeר'6!#~WqYjLH{ J58K].㧵}gQW?232tQG|!d ^ 7GBB o # eل,${_)e b ] ^"@@#]Kw*>U3g[Jޓ[`Oh9FzHC %7A%S^Z#0!ϥ_M" Tk:[5 Ŀ;?iF"@J(3VWZ8w2٥Azrcijv)0MJks"ϻҘg}:ȑsHY:uc:XN:|8(tnrẖポӁțkv rD4Qz<8 fPu䋓NB¾l-?lJ!x]\9Ro(;&A/V1$ b=TD@544 aki o]wxT/&ΩW;BAGSUl8O( F%O K;4yWOF3 CA*/)`P:^KA`v;3ꌲ2DT-FQٴ̰Pv'FDKbPm! }byW&QޓP<| $ԬMCz*U߶"C]hDЈ|?vo' \oUPV5.o1̫q*g 53Qs1. ]-5-1}M_Fؠ,Uv XɡtR)qwijI}L $OK })~4¡xPH{;#DuO9&!ϯc@]ݩP_;~0럷{K2u {7(TZBK@Qh\?6ho)uB2 w9J"2+UTJѴ  aPVZ2 2J^ Y>Їj5A1sEQ)QX4ԯld!Z,GF6Dh̽& "`wM+IA9jTQBHBS9t>C NgW%gG8 WU]0:u<P[68 Yu#Oܹ1 lZ{ҁj 50)IcAeK h}|H0Ty BeB59P v0<KDbiug⿺ i[Q~ s!g你N4rmzfg&R|\ m=O4Tm4$c$DH3[^}gŵq3e}d{C<9>Z2$I($=X y%|4R h #k*"DCsI'PM&>X:{w' :ڡyX=Ax(6H7Р?4bk*)m~N>MRÎ5C֌xr2qO廗ƫGl랁[򃏗^X H %+! =ЫPI'#8]!jH GKp|cjb*@KbTTmՂMYihЊK"r$\R#3[D?Gml^68$[p Po. ;(GxwFlD#mq"%#}YRxDP3HgZ'cxF7rRd XL{9nc ϕRULawbrv{e"“&4 arد?)-۽ ﯙcIFDLiXVbpu,Wy<ux?3s$zօ|^!Yp>,'%2&! yxo0- SSKϖNA{ CB [bP7&禋H(`w+L5GBCB8`1UO TSοտ B5yoޙ ޷I '0_P[#^VK% ǝEDB[`m]O+4=SUN@̂ dH}:$<຃pwfySDr$tN2>*OwrH&e2S &I=g [6ߘ$-2N[yf={T~6H;9}S~$So0Ϋjywk>_hr2U.,~hFOqW9rX9L+N,8KD`L[YL CBA{*mBH"6*?0_Nʙl~AC6.# %`kmBB[JBi ~oSgEq&KC"s=_04x|JCь e+o{.%~5_b oZ1KK4ld~sI{!4Hoxq$f2,sI4 uB|sT9p,ZiI*S/'XG>HFɧ!"õA[~cx,LEm3އ/9_Fq^*Sr*89-Y*'% Ux;&uI0^r|-x=vY}12:D$|Kз`Z Q4 3m -M#A8@6 &f `I_cF__ۑЈf[4xSP8^لsROmCg]PDB%Ldȋ$ W *.R(a[X KDs4p C wGHSڒ 2ABQKB˞I$sFb?>B7x?xdI(±SDB]d@Ihwn`4%! { s iN=2<_U3W㴜ޓg}a |ߑg}W iw8~u,AݵPI#9 Ub܂!hHcu}8iB"o ijI7K1Yy5#oRo lVh@ЃgFVwK :rDOo)=lt3&P%m(SUQ"WPЫPs ¾ @7 /[{43φ uZ]& &@ƇJIЎv^%4ulīٟ=<^ el/ *#ΖsJz$$WL>;l}@  A18&^ xX/CWtqL8b>ҵ0`@pzLc!ճ)Y \Oo2kLm҆O'818dtm6@/k9Cfa;Txi棗938OHs|g]ˈe[NGȏXa^@p\ Z9cSQn2Ж6ELΕрP>y H(eAg >lwf0є;l|q8)s<НNBqQ[On9EEY> J% +E-ǜ >h;XQ/[dWڷ+DRY ۢgB!%HĤFڭBDEgPGi(@I++TcHԣ@15/{q!e)$4&iXƕmY"g&%-RQ^s2$~!rL1 #VY0"AoC6͛e. 4~顢s,/%Yz?{$T{畃\(6@8c@s{'v+s{&XXYXͿ'5zM9Q.$3?'jk6ȒPqc&, RQOBH(UPڰX'>}4F%zQ<`T+]H^QX}h mY%_ؕ8_%/پSy)kvQBcj"7tVFIC\yW! ґ~K>*5Z'Ga2 rZ4JRZ$q 0 {#uR;O;}_3 RqKHPd@JQF?E~vVPҼ, DߖJ$64P㧚E|DpG2޺>6`^a7r\o)6p/jMVl惆~5ۛpv[6qY=tXb)ňh/ɯ+攤/ؖ, %쀛 )2: ѳ'~woM>o1PWǸJ{J4TWPoȐSJk߫4̤Y0Ci#! CB[CdlwA"C eH(PHBtAbq ']p$4A #b-QNī7b :ᵉi CxG&Bc%%OertJp)q~-<ci ㈡b {GLL099u95!ѹ+v))h\s=sJA>(vgWVlsu9ͦKC{I#Ls?{Ϟ>&˹//}7#u$GCB،H([X1"GBra7t <~ vޒP~3BB%, +'?K%s*yE$Y|s1DeS˳TyO5E] B $y|#]hڅډ hMx% z4 H(@?eB 哯q u<Uix`0ĥ\z + 0H+i)<ߎzuugj}<+I3ī"GH͎uy N>ljAZHg$,%Ė2@3 3>wc~ h mP'%M9m"7Duԙ~w`Zg%a1 9+}O y9q>V#ߢ2^ o:Ah@%[uzQ'l$b>SEB)l[."@.Yݪi]eq$בldI١ Pz3H(En$o/4oX{K+1K5ICY{6}m 0*KB8j b3wNBAyR.e1`mXGD'&Z. Pr$$T9$jO@Е! uK[O6h7R iCB[  cf#X<PxO C6gۍYS֤pWv鏄w&%Q@Mf2_4WU|[#WC©^!+- rĜӵw9<Ǥȶ$Tȫ*Lu$6'.Z*ʜO@ʸqhWgQň'&TYUo%/d%O.P4$B"!! 8 =`oO!#_b/B: 'y I؄i*8h5~cշc=$ v$Զ[X礡-}JC;c#XIa@czzS9iS^ߙ8~L!sPzw8Yj0i1 M9hI_U|w C:eK),9{5YB'NLvɄthܜ+?&RR wؖl)Gc`w27On$>ԌkL}iC%_s ouTv@kM-70Jw3S< %|qW6bDt@BaHB֮ =q!V"ʑP -MP H(H&$4kU!4ۅYpcHMHxz2dB>LEh$R%V hɬr/Nռ&(;SVIl$Z0 ,P7'{: q8'yI(f Fu-`I4sR Ո4P "n ,l˘ERjE*4.y } 9' k[+wh7rNuy/p:?cc};jx.~%Ǘjօc%Zk$ ͸ c hF+q)#|nx|<,FDcI(dW;  /BBmV~o7(ۦ# Ptp?^ʄ:g[;WjR0*yGB-#gat$0:mR؆&yihHď0RaAI3Aߚ8Ɛtl$ 5tJ:?O4lY:$hUu| ݢ 1O7($@<uƞܴ(  Q"WR2iB V-Kd~'˻ccȟ'#4ҁ&#$OJc6! \`OC5uF%(e%Om6ݩ#j_=as/&56t@B5.~fw ؗ^5ugZ 6ѠDJCӨm} gRHwSAq~0X"s$0z`*0ɇY$ԑ6dR5'G2@B]9e 4Gt@,R"--F6:Lj'$}H-kfԖݘE (16?0R8? 9Hi^5q*)7r<{NиX-x^ ׿Z9YE@:Wmi[_|$\8) ,GD% uHJZ*%>;L^v7SҨ:>B 'H(|$ _g$TSAHΪ%+0VU6G ! (G P07[3!ڴ=fMR.'QI kϴ/5tLʡtFzVO8kv p[+\oG4ȹLb=q~Zg>?K:x-įwqEIBQcIꊵeއ{%M7$kht4Ef[MI艈^ `SD&hs< UA˚hތQ 0֗Hm '[@s:5FN=]C5E*$=DݯWՓ'%?~ꠝ #V5$Ȑ(2ԒP=H%ĝS $* PXAԡP`@B}lcxJԭ$FIhz~ DX%#nGd lpRPX& 6ۏg;޹HD^JsIix!:RRdK((TDIFX!އ탫_ƧHuJ:kIXlM 1U"m߇f>Zlk<1 !|(‰'0/w/Q9IvK3E3*Ǫd' $OBCG@ 굇99+LOba؍PKH|~PM~fIt2~ H̋HUg'[\lZ\ 1}u7]).(GK}8Gg@:s!bD4+ ->Ynlv>t)a]ͩ}Gq"  rosR=OjG5ںrQD%`jMO$5 >! Pq # m>} i/p$&HhPzesmP kl_aH4G%@bKlx/85jFxi!&hCG' (0P&EfW+4(Щ\U0+We *d?R™%[lzN*$6Pzx(LB?NESu9XAG[RڼlPe}XwA_? t{NbC==V܍Tȑ258 @fI'!wʞ_.* y-QNdDBBJHv(_h k 9)l0>"3 J )5 ڴ=BsͲa) }dR E:Ȇ%u$zCR:`ڦH(H$}-IBCB RǻH(7kȫS< cؑ!t% ĤZj;w} IL9>J[ @_ɧ[lh)>R'r.ZUgRƌS IDAT pm&Wm-zf.0Ҭf& v9R.GLJ!O e=e Sn0\2I;:&IS|oz#;k2x @ @UJCs7 +fB'8b ad ,b u}͐М4t|>Kh2+ ը+\2?c|E$j{MyF_8\{2Q<4)Uv*1E8"NSH 1.O8身{FYh1}<]$nG0W!urΕ;?(`˒'Pɪ[- mBi\'\G$H%%)h%j%@LB8"MJS$h Gs*:j>%&EMfG+A>ZEg$-UPfD#p:eW¨5 *y /"24_SMLi ?@9)xI闓JWjSƥ^<ho#G84}- uGd%%\NI=:_j*#gмzP'֎# @BhP@tcd O:+7В%ޔ*څ丂N-Auqa"hhP$c(r$'ז40e5g /jIz ;myӑ`3:" 5 zʎf3S$&ǯDB%?9 pmOP\U ҙ6 T&g½$GU`⏏&'@3,!p:1U<1 iM c*?/diPa?dB34/֙9EprQ"~^"<{5$4`V/CbSDB,8H_OQPY9X/GDτ!ܨDBo9 đI( Uu1ټI2 G%IV$t -EYwf+ |6@B~LBBgNȐP3R윤ɧX=0Dj!aFB%Hh>t$ ޶r>H#mٍTDPw6T^w JLKV7FI0k:8gp֙6<͏0{ӆiE9trNi6!lG0(8N($;(7 ( 2k@?a$0ͅЁ6kN(3JDEzP_ ZBw@/(QJMk'mo!ڃXzb&]!z*RnFƆҁ~Z_&#`Ifpv5Q“R~BXJegHwP:Q齆 0TیJqs M!;ar9[ZrǰK6(Pd!&- !(c@^JQH O*Β'qoJ"IdT7SRaR}17Xڜ$4RENm4y6 n%Q9ߘQ1voZp c lӈxykʼn(| 9 m\$< uWKBbz$^t7$_oy%㴈&'Hg{v.!=Bia[cKuCyE Ozoǹuzy^0]Zjɫa\.=ܠٌ?)#"8&=I[)Z1=vnrPΫB* hlP6m;bHB}Ff*VTGFKja~כK/EtB+搈G7}l{m~@^KY#J~?6ڃjK ~)ik|hLBCB7'W%Qui P?%RPՈt 9oMetw-lFHgb!lYs<'e<= /\!$kdM KHhn4$ԞS6[r$􀘄i@B{&Åq($_5Az*g+ ʚBB{#~Ǒ%3=`Ⱥ4FK)8{+ 3{[නs',XP P (0X p 37(X ,0((8 3}9zd˶8ؖd[^3k-)PAB\oC%=f͠K(~RX[""soAh]"4|?bZbNX ZT ogS'*>Ψ\ם6i([L`˸^ZD3Vms*<ˬ+BsklR4I,=.[?˃ӕH]/H^7lS&>;M ]MgPدB:* +*kO08<ubL}l(oM\PXXY֝H'DйX#!_[Noc? ؉rIPҿ{qE8̜DrwKL>觾tDm#G/l "}i1gwH7zM: `?v\/IEz|;=HvP V:JHGo|Xݜ;^ C?o%Y$@ P(;Jw6yJ 2Ro%+_JqdQ/g&@iyhEMLǾŴ;ߗD]l+⽙Veumէp;u[퓹Ȗ'[]&00ҏ8 fO)%KmM 񢳶%火̲bD?Bp]93lVY6erQO6`ҋCgLd"(a*"4!X,iPbdH^5[lD]|OY1iY[Em/tHP ƕcHMBp:yh|t/=kh~8ѬD_~ޚ4}Mï6~~{[v?a_}~~"cG=&f?6eOk#5ɏ9~~w]2aO2a?1;kя|~Zosڽ벯-A^ctycc2rK{#=~>w3In?oo㱻}ߊmOǦ?~f-[?@,&FK("ad~>Z*<ou2Mz2G%1CL.y7^Q-+ba*s7m6f}1Jȕq<1waGDM4Xule9}N:M]grZ)bWc0^d 8 f;~d!=}kaCٲ:`0ˎ#BoBZedԹ Dnɓw2u `aj}rU:C!wWck"#v2 [D&so?(?1%$v͞`%ze>}dU1{M ]΍Ec6&4eL17YSt̽~_ЗāI6"'fUF\x޸*y(W`2:ʎُ!;/܈K|n k؀q ꬀A(ELfBm؟W߭T 5-"4 D.Bx*B7vu!/XMh2!oяiL3]XW=u\P?EeLeMϟ.cvEdmgʦctޘa*o77 apKP/m _qw([QP\cq.cH0nWAJYDDh~, `pw`7'N˯|3 )_V R͠Wf"ٺȇ)([∭\mò#/n2jsN} ̞gE ׺ qz&-gT;L;4o}ھg|;ooB,BoF ¼si_F:ĤEe;zY=~ +AckCsm,DnY7(,]/U|,hy"fo 72W,i_N]n9jjqCtFk NfE8u>$]$Blծz+Uz)y, Oo^EOv/BbM.BDh~nn?5(K*@ϡ NM&C) aϯ|Z1O̯O*MBֻ㓨WK('W5/x(25anKVМ{wM%"tb wMPhN0Qqڟ⎿ʼn' xǡ7{ǹDh]|ܺM't̻sEeZtMRґ顾EQ2+"ڙ NX[^~iXײ,*#?NUiN̷2Ҷ}DoB;~zޜZ7+Da2kƭ۟Krm{bVv1 WA(ЃDkAФXZGΉO"I .]hH:AH1} MD)wPA(*fb͘3t^ FqSl M"4gjs'!i?Dp1&x]a^0[ڣ6 )N^E@ cC! ~3! =ZDӞ2YN84,d"%!E ̋P| b޷uUqo~ۿSWm%S"fKsrm;м 歝Y7J絛@ pX#a0rB0n7h TZp" V 1#HϤtBH.@{q.wu4I?H/*'fW_= ɼ[LξZ3jvf8 K |L(,e@1+(O.f9 O `Bo['<q7qg/ħO/;&J[OX:j{r@`2ۯDhf qYO'B+|&&MKE)D UDhwi;(ʦ"@3o/[ 9/S/@RxjG`}Oi]ZծQ\aٕÆ(1el"AqA xLk,2s-%8kkf ^1"S( 67m2[dji3+DMxfd IDATVQItp e<5 U׻։P.mVh!?W!>1[5&4J-;Tnx"C>ZFEQ.,>Fn£U C) MsPRu~ :[c5t oiab|romY7'/YR\P?'-=w|%&. /)DŽHĭmmcSA(ͪqNf1]𭄥`5iExʚ³6!KM~*BWRn2B{g M!/N#d^^_8Y`_0y}UT$Ь SRx&yxyzKblB(*tW[G풔H&էyQzLJ³;⳱ώћf`. ݀uub2o`*f c1&unEPż'4~4sLJٖB Pqǃ R_\6EnrQص (pl"@'<`bnX_W 6'|뚏f0 U[#+FWxy5iMd0OBjsS$Bm$yrR:b(JW>}2g_8e+Wl|ңdଏwDŽf/nF@9qXJLB%Zy$B~~%ȮYH(ˠ (E } }C0^'B9 ,XSGBd:DiJzWDh5^qS%2Ii iPx>(elrͿ(q[{#哪=^k&O-:OIoB4`'qr*@Kti6{I.Z\azĩ{q1~w|c*qZF(Mm^w璠=9:&`0CY.P_%v ބhdbW'lO.wjs$^O N_CNhX̺"Cm_.TQe(!I힒k=ɅOa`?L=59A A@^2&qo;pZ& ljn\8:*ȡ}Z}5y%p$_G9Z:Q~}xřqIt&fweٗ|u[$HEQdo͘HUtB֒³'<00o,ގRқ̲ܗ"HT=RƫQ'S*rZҒb䍄߬⊮sC(4yx@F"Հ܄;6ZOZ _Qyҵ7|^=j_C9'U7b1êL-$`LMx ~>oBp_^Pօ"8cb8uʯe>M,!AҪ;,B+[Rȳk1v00anܗ(80~4*l[nR _(n캬t JpN|q#i\| tIɍ5xkg@pjb%˾Ob/seS[;V|G,8;/Na$mH!^8YJLbOyK,M?hq!P3̗L"QOm MobTQqX7SV7 j^C_ @%;"NFkgAL&>͵n{!΍5O3A7~#)yB_|F"+Xͅg,N?DN6`nbaGKeATQaXU>[gw"^pS1 }Bt̼d^|ly &{smSG2yC]kd_+k6`O#'8ץ,=q"t"t(w ͞HC>ej3K(}t5!j~?_KgE`[>}?%svm$cWљ_!B0]qE(bY ЇBO#=-Qx]z%'13///\Ʋ,:3js³NJU,EٯYE> /HO x#G/~ےi|2e"4yF(Ӧ7#"BZ]p0o휛)i* 'D69ۥ{*Bs`OsC[|fK$-gd=! (&dĉЌ,~\Tgtn@>E}LDCq*@wsV[=O+H>4 K]\EzMq2Icb\TY.}m.;q;\K3&Y}i?I3O吃]x d7c6bz%4 o^E G=.kg}ZB/ٽ$KKp5=lRb!4ipgĉhpj^z*vA6m(&,ԧY"`B!<uC327kQbj%+W Kh_2ʘbwcSo~N)pbZJs ׫^owS ӹ%J <,m2;пQA(=V ׽gK!f*\x^ J𬳁ExX!P>Zײ* A(.V`*YBӔ>_0o`& NaZLVEhRٝt)@X DS8a{ QA( z偸 :XiYRBaҖw4!H/D?Kbk{&]d' _$Bshf }ccBĤK5K]}(ʶY7|^Ӕ)C\ũ8['E8'`,дQ>ʧU}ھUIk_"W&H 8weԫ%4Y$7'}~{W~RRPdI8z8R]Z _QĺlML,vqsO8y៟1W>_5^=g]MGIT &deIo^!8pS'BQo{`>m`AEͧ|uώS$/ őaPTD(81xtc2L(Dh[B).]$<[E˖PpN{q.Bgm ΕuYw[g(Mפ"#r%.rj/u}bn8> ~:J$"̛y{O#fT%#Cpig3GpqB&<| o/_xfЛEԎ"ij8F10}fYB(Ia A) %)(s*V:cKǙ P|Bj U}_gjMP1YV~I{?!Vޕddq`-CBB%083;-NtdG@O'1NeB_T-+`l$fV{!o ^JaI3cD"&TE-U*ԨǁAU>ZR *y՞O4rnw'@;S6pBWxa:ʶ)5A>GN'9dsۤ\ 7Y: 8s0p58A3zDpm (ϲzzzS3-p,-{*BfS,x} U!Xճ.VٰM43{\`U:8 /tfz~$%E,&ntCuDb1.'KL-` b4'CS#Zжĥ\,ý8hHWfP?>44 5[6%4)I گj}" @3D(D'0sҩu+qPg4ܸ`CnFQ2PT>LCn]0Wx " =`*,]PRH%^`_s p[*{ZIB)2Ml$ǚ؍ms??xFX#R0if̍|H.>R-(, j$1gAL"EQ~h( Kcq@Y]zv9(DGM Pk3/KXB-@|c_!S>*HEy,˄o[טOWњ~si a|օg%%)=eȄ'NY|ONRPd%TOPW}WDm" >a*jO`*%'|x1&<]kSBj܈t-BD޺G(L ϲ )2yKf~G?|ngSK0kP(,WyKȒ[E'>JFIa řɷEgěNt"g(JóԞh(!*nVgҙ̫oP9\|'FDY Sbo.tETcBsKh {̂Eh,#d,NpL`+ئ-c9MEQXU+ۥ4VV>OIy(BZ!LQ΀D-E(ly qP;뻊%yw0DHX8 07y6y۪^QU>c1iVhEQmR],NV7ͅ'~e/k&Sn Q-eٸ iAUz ÞcKE< brҚ|}k/ 2 L"Ss⒖e `JPmtqɸoLS3.eP3KhWsg!}?&H,f< cX,BS6Hj' -Hۊ U˺!>`$kYEӉ[Eu`` !A]푐IDb s̱)LkB5lb\KMYBqorKh wa^Dh6O]t6~[E5 6ҩ%eWM Ey~+@rS`&yRr(9"/>itN|"B~cD3:l"pBHÚz|9'>"e4t)e]+g>(Oz"R=޳-9I/0鈴CSEJR0g~a gc<;$H^V`j ^R\=Y*:)N;d }RlLR;\ -wqʮ؂T%H{+]yuaȴeO \[y?]gЧv: +hV0n=-A\bo ZOEP'8wN eyʨ| U >>Up -pAܺxnjH2:]CXc@;n!,W׼ }v0x cD`OY$npͬ{|{2/<Ħo 0! è*BHZR_yHLd_*He7^@ WYʁ_v+ SD0HW1DM~5[*&iZXC]$ke&8qe.41;$ ${h'BmLzѽIQQYUQ _3)joxJ#C&{ܗBxt/bso5'0`h߷UPfA4C<mb;#ewV2='8Y9}\tYin9L!InP?  N-G#7g^34cryj{F?3HwV2C쫓L\Z+sb:JOf-;i"y~4'BgvDhW|H{s$?fRmBkk)O2XUCYH"gv*ilqc>1)I|Ϥ:#|`4l+ C`ǂ [>r#\{"#YJB46XBu퇨(B^ϷS! A!EPׁ %=0.g|oI}2 c'Bo~ KhXyv< QEy8EW268|:˧y/Tu dwp|\F%srO  D0'@.[_BznU.iښDNY߲>0rN jDhq O?ŘbLuڍыPh{Q \eh>N"BnӼ24)VQ~IC4cEPT3)^21 am&%n~?"+K@D@ A,0`es /BBe+9vsm $[l:|`|uiD"Ww+rE |cBEi  |`}.V875[f %[_AT`LJc?+8O19A4QǸ:gк+ ٛ1ܝ3( xE@qa݌f^02N%`b쬡)KR?=ωP`cW /8ǩ"tӋ1(Կ_uw{]Wϛ.M v&| jz-K0 q?cṫ*>3}s͗Dȉcf.%o'Mb$(wpbu"Nf1xwq w8}YtnY}`%4}#*R}YB\BOKYE!e9䣦xEM|Ȗٵ }0.:WX^Q-$.uK"\pǏ EbKxrw|,x#g ;>;{)o_͘ >'YHYd%4ʋDTjQEiT^ᕭ8s1 /;R\rUDv71i"r75m3/lꅨ+ ؁ޯ2h+eۭ;<&Y͞+aXˍ'7KH0ggM7o}5o}fbԤsǗ7ߗkuZBйʇۑZY\XFSLal+Ȗ{;_1ͅ(KئM.i: iU_3p v>L-Y=9#Y_dِNl_0?C0q WNegIS WcHa/Y%f\hT(:3DHNH;Knˮ REN ᕗDPȖż)goƮDI'zbz6lE;!xb>7$%XB]"X̑WwM/ZNH/=;~1`'sE-奠TQک]fU<E-|`N$>7%5&D+oʼnR]N%Uc7̞ gYE7N. P.< UvEh[}챢< ;u](a0_?n{!p:4\;oy֕l`|'_eid)`{g)V䱠B:/B#'B3KhvHj";_ɒ2KhfY0חòdMڲ)P/V_FNpoWH'~g9iǤ{>f/ȵ:I0\ތs5`_1{bߜ`_oNU4Ϭ`JIKI}5eVWؿp7oqֳ׳!# NOAl⊮ .C;i)sǓP"4zoŊP0gDԂh~Q a痲+hoxɒ {_|(#R1{|M4% sgyib|̲Rg-$H\YHS>#x}+%ih 'P}|hH Ɏ)uwAh50l"?c߃_ ]Zkhz/R |o 5rn>EY2Aч UbU=V‡'C_WN`o!W6 `c-Ǥ5}Eoqnca'^|<1ā7L(='?q935wYD>*j_:o$s/|J9$uI 4WVQ:ѷTK=)"7e}O3ˋϓsOp {&=6tqU|isқA_`J"C??~ tIVRUimUP g2*E7ut!4]as7q@Y.$H$&tKz8& .ƾ=j_@Ǯ5ok ErXE>$r1#1׊8γܱ̜8ʽ ǃ:jЄP|2W3f+;KWq|zn*e2 PE63dl5? .B3zuFͭӉ%HKS8^2-kݾ_{KR֊S|;;E3ʔ{ݛkYm4Ph'R/à(F-k2_ }ϫ|T(;狕7Io;m*3[ѿ=@0 gD)T\~ V?'whm=!HUpo8 zˠ0F`(Dc8IbOZ~C<!Hsl0w{>_~}(0'0AB̝K:B1s"m}( i&tѼe睭S(Jq%#gS;̙`^;+c9 `ܸf@#YWGy/S;H.ȕB`Y+g0' 5rP\PHxy&xZw6Ps6ѴI-+S`Q&U` #M%2P+J6m{r?z3p-!.?Yb.;dC[O0G+$ef#9g8"c040sb&puFb8=q5\ ̍!`O\kSj 8v)P1'a h9&Ї RO/UƁ*/K۬267T9''pL>&˞n*cּ/:QZQ6}b>Ə3W˾M鉫7:\y3g- B&)Ĥ4'B" &ZE^ĕmTYE4{(/u:4P?ħ% IG^7/GBU䒃~ybę8oz2xDh ;^\שuDL; X[rJꏹP UhJHZXQa~sj;9h~veP|Sjص A/Bͫӈ.eo uoFJLp`IRXB1\N.3>K_x[;b4Ƭ_oRv2MĐ~ʮM/MyקE$BO#5^ Ayw,)A:'7&xw_Šr`/}-Q_W4Xd]Bi*ë3eK(_G.BǘO5>KBVsi1/Bs&B-D昼@5ob譫YI3= e<\mgq5&4"4=?Xi|eL[@{|*pZvLJN^9@vIˉI1 Q Ksh *?oFQv=Ww ڿ"co"1[E(N[B)ńj5S>^EQr謤ݙvE EREQuMX818)QbT"`D!8BZrg[%&tQEi/A=uY`[s+EoB4k3FG(%Xgd O#|d$cpWe}6m%ЖlEy z5."'S ma*0t-:2m]iB _?4噮_3*ǽ\q-Sb&ѣ߁hz/&(MoB[85w(P@px(щ[vbz \6SoEQw.9$(EYC \!eNH}M"IC DhM|>f ^vgz\V \QKn[]>]P. Dh-;v[dF8zB)ωŭT _F{UqK~*C"Z;`O/ܲ%Ve5'cUAv/6{=SRPoc YMf.1 Z88֏p]z|/ܨWbhr'-+D/iM6s(.yȋQN-\0[Dfq ⭶*ϕ:*HקՔ^楿_ z)'sÝa^fVYy¬(΢]} MMY3EyJ'D7螴2CZE?}_o`E]mR3IGe:=Qi01UTmYEy ]L5ߧ>Ryd61Ahꉤ(/ , f!U~v Jy$i'(mT^gZsd˛(JBtA=N *M IۗyJͪEyN&D(6X&V)\,ZIQHEQH[*u|˅wEǴȒTQ QEQ4v]{Q(SG(O H P (sE(OMB۠& PEQ^ *DEy+H%C"qDT*EAߩTQuVRhQ7C޵C/Ͽ8EmB5ňEQ֧誂4ccSeW+vƔ㡮yEQ=u-+?_mf+̣BTQâL} 6+gT(KF(/Ϧu]樳,#>[=BTQ"檂tݒLl]鞦BTQ&TK2)l QEQ^< Һ-Wُ(KG(g -x(2 BcYe7Xփ)󾞄T(̣BTQq۶6*FEQQ!(Rc[}](KA(kQ%t*HEQ*DEQX\-޳L REQa4VQ. UEY Fe2= ](Q!(ʋ@}[ЮV {EQ QEQ^]z7Y@ѧ U˨(/>Z?XY~$H$Heٷ _*f4}{[}DVG(z,fUiz(Pu+lY$$25^Q QEQ]"x UEiF(φEH :WA(K@(O.M|XV̈́$k]W(*U/ӵ7|My(O? T*φe?_TVc}w>4IQmBTyv;_u_7  0XPp@,x@A  v (XpA@ ,xAA,x@AA2}@-ɒ:ɶ5-˲k|}\k@Zz>24**jLE)44T3#@5U|@W 7`zY1B>ĉGDTOvi"'_w/$+uXHw[DI'fawS6BL~  ȶQQQ"F En.}bWF`xDEEA4.{wMivGHQ/x CjLIukQ?J4{~ MQQQ^>)>a LTTA4**Qȗ6语1|#FEE ;7|H@-@O0|_}QQQhT/(++/B~EhT/6 h WFG iTԯh}A=M86">BhTHZHR.j =: E}AE،znB0@vծٙ"F%]CUBQ`(SEc@W!1YD/Kg}k5-}d@iOD|.C8$A4PcAp Guf qqT'Yv^_N q%j(\4ܕ{+`P@\n15VPsQ"QʇZ! IDATz[1Aė \b&hX^gS[}20L' KKk7?4j׼ `iPR%➂LA$ `oR#fu}-o6QQ!w,h!kpQHwOϐ5\ -yÐeg*3 IbzX ȀGUvFA>$tZNx᛾gkH(,(]#짬]wK'īBcR9a  +p/pT%B}FE=|]mu A]sW0?3: <#YG2́zcN x!)Li9Z='6 7\k@ wt]>T]{9*282ARq,|M (^~z3UyƀG&4m@@L4Y>bŀBBr4 xӌ7)>F4f~.u3wkB< R-S\V:1}>gfTZ4Iq1-dLj'0[[!n2ׄe"-Se!]d*-:'|T}"CO 8b 4+D !}~ %$ [BxwXoTolGzdIz0+(E L 5GDz2 h4jWEZEfXpմTaǹU~7*kתGP|%?T  ȘV˙*ɀR`%$*3/9JP^d+/Aut@ r% emBYI7cEU|Ш_MH@Us /.7 0Um[/`0W@hi"9E,!@+@6t7-pvG$#:ިrJDK)k8% .s+"7/II`C + %dPQ4 HD2u-f-'e}o3`%@UaR<-(rqƏ5L>!v s(-bE KT2E& B &o8ht3u /8,8W98V+ @*\S媪2l|WctD0W^$׼1eϜ  `rR*]!p!@λϖ7u`N^ Č1ȌW)O:gH t}F. 匏ƨ(}4 WEpB_Q`K8*Ux9PO OV# ~/嘖˥Tu 5nXLЬ7oX/]Sh5eb g]vo \Θ@:ˁ9q1AfLBT+I' a7_^]יxDE5CoW_X#?dOK`-1@$sVT:ug¯])ƕwc AҠy#hQKωpAm{5#vs2ٹ\TmJk9J]55LLq RTWly*@=B9p{'k.R kQ :$)>Ra>p}_7[4Fu[̈́55hTO?e@ט@:V׳赱vGiOXL¯PQ@͆ogȪ<1@tTQm}l:큮3{}aVhyH35ySlnQQ׍o~bٳ}x裨7LLU =orT4`Sn/|`2нNA PK&8(}0.2.kM%6"hTө HcrQϧO2"]+T,^RS :JϠF'c-GYD_(Q %@ #Q}ܨJdԞ-`cDzjPѨ;T"x:`ZWw>3frTkeZP:3[8Қdh9"5`ALYviB x 6vL~P{Z)(v<2d!4j( 7̨\O rQ?&> .,^29-T95>ʴG}WTP _h{?%Tk4t2LG2 ㏚+paBe*YSoLZP H磢4C%#~Ҩvߺ2#,Jκ)y!˲393 \{A1`&Mk!@@7R@\tydfBG )RikCt9jɼ΀?d8r s Ly@]' (mP.vFIY6#FEҶ"*U6U8u7}w]8xC? pT_s 8ӀG,59pU2VHDV[H x eO/v)@r&?2`6^,$4gx߄RLHRBYxT>CnhШU K]kE i+Q`%2c%WҀTQȉ*Ȯ\1Cnr^TAv5m@dr{U2ɛ@ x9pZH? $j}i'v(嫘[&?t`Ȁ"͕ O B)!32h@ii컝 C̬o}DEE=44O T+y XU&zjÇpU63ˍ*Y'uj++$ HHeVkǙJqSO:lVҕV @Sfe)-z6d@5\Қ:@ η[@I }d2`BOqO*B hj>` ~uMTԏ]խ h'jkRWBuV]v,u pE}ՙ#TmW*#C*n[KfV*3Wǔ@ 7PH~KJio,-?6v4.U P:c T r,fVz { XSGϙ.t}Dup ȧ6$_(W53L_~zU 6UY4 VM@]Q Q3+.s>2HgBZ?9 A9DZ;/J/2ybSAWBe@/iUH&PzK@gKRZgP %Pnw-n}TTԏ`C3i.U̿x+yBZ鸬G?ʧ3_39S.Y 㪮n\A)02ny 9]:Vf#}HX H.6U?y[p9 _Z:"FjLL #@R[@LoR|"B5ڦ9MԳ7,`ia/uMElȌ\CN+V[mӑt/rcpk+[ ! DnS{Ձa}P:a1Buk>xA\U4*זn.}fky2]g4UkQ Tn]@T_koΑ~n-ӥQA?dosB~ e  9 Y:&WT/\LHB@fHzH.VzI @G }Z=jɔ26yyԇ|R~*:WVK:S8\ńTR.!N>u %ol5^&r? RH{&!O5ʣR@ȷ)92~msJ(׹ ^5=S0tΤSpʤ_FFSVis$oL@#`#FEE ߶ߨx@ d 7,7ρ[IHeI +C :(`G۹#f h<cz XR7&@ },6PJgKHQuKH jo X>` 3)[ MTT}{JߨXM<:&`穊s @d Sߜe/KMTվfKOM6uS?2o1ư8XgvDC5]u\ҷs UfC) Or+͚`:e`[REC p[ַ<죢4FWSuk\p 8Uфӿ΁I5lKk~XW'O`G#~TE}ycȲ oQQQ}0_Jn[3a+ # Hi{>q)T W `{f :R+ 9[O(.uw3ȴSsy uû7xc+.jwU]Z 7@D}&> I{PL6~^ DB'| HC@ufV[>sQj9/Cϧ6uGEEE Uҗs7җu#:`@S_P Pɺ1|?襂UrS=}QQQQO1GvWE(jn*߹ЬD( z=X * R$B *z'Tq}D^W9pUH s>Q# \.ErgRT"N=Z( c^vtYO* MQ/'7^/nQQQ/':rh!}9bceDr k`}x*'Szuq,drHwBEAxIv ?kc鴿Kc_+>#⧪>:ӠrЍRVgwkΡAWPJf>,3 7 0d⯬'S: tˀ!ĚA6KUgQ}nf)dM躡L7ۨ_ Pkh!]B0"?uOWNh&Pu-͸)R)B `TlfڿʀsHLu{U> |@6  V!1u"_7 )NQjԘV"pL*'U>=Q3 |-/oFEEC% $+d,AI;&ْԈۯSyu_k^\UPPWX5R1:f J(M!&͸[քSlE -@&XI3颟ۀ ;Au R S17|TTϮ4v/g9_M)P5\Vh\T::f!ui3S}0SV嚝Vsl{S׬='ZI1'DU ۵PyЎ ڙwNAnI1ESѧWШ_MHwKd/]pj6ڵQx8fy"]$B-ѾĨ ?ZZHƩb0ԵVowLZC:&Zc'ϫU'V(QW ϨAHY*?PBcOC ꘠>+ H \wkc#}X3ʣ3YWG1>#$~,J\u@/OLQQQQ?"QC x';Jz/4#&C5uFˎJUQj] nƐ|Z|;UB\B~  쟳]ČS>H{VRw6TC?L0\h@4 rFQμ:~g* BV6jToQQQQO]C=ٵBF@Yِ@iK)UۜwT3_VcLcӳtwgUַ,(D"-|SH-sh үxL ܗc,K>c"ZTQGܳ %YYR6 LY] *uӇ,TiԮyW3=Skm :P9]Żj9`o÷cLtV AgWCEEEE ?f{9{掑J-mN׬{>R4ao$0cHfx`92^ lܔ!ysW_@C V"[@']L&I|p&cr0!?o/79Ȳ$Լ>Gjݹ^C*M!ϯ06]FQ7<`Ip05<\^ CfPrrEmSF">EY15h:g}0=sԞf=P2ؕ5!@+Ü3EbЏ3PZ:e.#C~̚Oj7fzAԧQQQQC dTѠNX3Vۤ/> 98i̙^in9hXh?2#D_e9j?W>0f `+]Ki$f0 ][\e5lBgzAU[%߲QQQQϣ1ܟH_GI L&Nz܄RƤqnʀ[e|dS .sH]e R7rKՆ Rj]q`׉$q2ަ k-(M&uj;(e@0D]"4***p3鳏h죴GwJ4}ϖv. 0W؇(8UuCČ *vc ez"oX-k'Bͨ)'u~ eOާ1F͏ \.E7tǪ[zCVЧaEEEEE&}{(>Ekv:lpMP#]kbkȞ~Ֆ⢥^WWqވe8r2D1z_fXӤgٓU QQQQQ}3i@*>LvwOY햘FOJSsϟV`ls!'䆡lI>d<#?lsFQ 4 B N3~m`G"4vߟI޸:s[6****1_ Hy/Pn9( `tBU`zTu> ,sY=(-iM.,i87=Cͩ#:)>{ɍ ʤQ hȧ(&!RwR$'(j('N;]W(au%#aI Lpʷ@{sW>8[|D؞few!ԦlO̅/AOBXx%֘B!~B~,a!}nx:a(WXĚI03r35/y@CyTHHd\© OKPjadUg9߁5vS~c![4Ek4ԔԾ  ȤrD3 +>1DEEEEB"ҐJq'\)$60D9XK%+}^js vV%/AV=#9|-ȆUZu jӲ!򡥫O{{`uT 17|TTTTυ!u>!}zJ`z㬼v6N%3}aȔȬTᔎYiJ3{fת( NmZ3)5S|̚~'7ӐbA"`#;>BhTTTԯsa39U'jٳ ngk9L>eyA\x$2aʰ$TA_eҧt tU.t4:B5?ar&U O3,-X7( i>OE4>****j<}zx~U i兜nA)O|LK:LGyneX2VršYP2G?@ tx!sT83/e?E|WvQQQQQ>) :]ꚿFmKɾjԞa&+U}ֿ W+XKTzR|2""sVC%8ViG~HѶKe@|:$ }V 2ev {sįM \gmsߌ:UvJĿNY :vVUtk=b{bP! ŗ~LO-/( =Υޮ JƸfr](JzZM4Co Jzk45so M̪;}MX~v|"FEEEE %ȀW 9Jsؖ2g 鬮…R> ݽkY_鱊&` _ 2U%Y1<$ _К}cQS|ʅ)RF3~`FķGr 3OG]SCwc7|TTTTSPWi:%M zA f93}X3 >),(5ެR.%hii PmII+θ䂩^Tz>~\@ :`R=moC J)Nuͻ #;S[]cj' t)(%0J:ÂRjvdP=3BF *JS+J05ӀR;<O"8 %u4aԷ>***** ٶBMStd)3˘s} 2 ɟk$_sWB/ev@iR@ lR nU`bDnNV%p8)*ݳޑ547Y&*****4ƀ|yUbC"^CiQL{oc ")>s̗*}&{WpR}j۶!5?LZft\oNGP @@&eezLTTԏJq:Co0V}$_~Jox(J$ ;BY|Y<*䀟-kT2lOљs^ a,HW8xG.QȑszIey`  i12g$=`CF/P7ajO&t(ˆ ڦƠ-Y]ouX za?uTTԡA~}qX7p Ȍe[7~Zn3pG DU=B.\x檂-SQ?OlΑ =Z% XfKyO$s;O߯{~\ºP*Vۧ5,t@%◢[YEO^QQQT}m?zݫM! ZsmLH 1g4}˾P;= @QQQT}S_ Al:֑CBӵ^;5{mCuDEEEEE |~du׷YBgL@Ob(VJ0"^z rTl t7#<ҏ) 7v cuϬv;.{q>GEEEEvz ~2{ ^PK(24V.|:;P:Q^尖/ȗe토۞`m$ 2Grɗ V cң4dtqU 8Z@YPJm @. oJ4I r#gL34i =4.f[DŽQh]ywtb!&Z&ANjzʟ1Z= W3**Aa>**ꔲ2%1W@ 4mjŏҕ?H FrؠJj*m."rf6ȩr8dF{wv\1#zdnm&?٢ᅰ?qDAD OH쎔UOvV(OcX/#EمOP{visd>>wڧlh۾!u2?WS|KY_<[&-nY}f25'0I> rK/t3 ;ZB\ BNΫOȒie*8u~ /A~Od&YLCԼnqS=)wUsQ Qۖ50ŨbAOxvsC`~6m` 5mUg6G'3ZH:K೨'ݰz['< ajz82F7KnC(U0*̿ @ ,%Og L9Ƚ$q,"b΁c@t_~NԲI*l48]%Zdg|@5{DwmϮm*; w籡["4 m8k=M!d 9COw̓Z9sVKCM~e 4%j`k0P `fjfYϋI_N*Y=$L]o8f*;5t7.ebXS. WM g1fVNQh*{NKi)SzVRC|L2 P, @nG J@) O #8Q>L/iCk|DQ3#ݱC ԛym㻮O:9RNX6Q2(ivvI|\@4L?.@>,3*****깵@VP9gkP@0I ul\r-`λYrMe6ĝ0!UkV5| h J˓]ִv;V {գgϕ,d5 Q.RXS:5ˬebRӭǙm+^Ken;u*R}oL6Wjn_NNԹS(\s/re™yo{ԟXOyB]6ʬz~߽Ƹ Ue/3kY[czki,~1pyϡ^ ƵQT˜s`gXvYܞ#F4bqU+X(}uz?eʭ=P+u~l9fީyoBO ߫y;}#0RՃP0 6!-=psS'T+ m_Dkd&PhqD u#~ m=*Ӗ_>gpkm6g kcqsB@a(?_}g&+mXYvYiRUr? W1脩kr FY龜_.vGϴ^НgݟX7:UUu̖\P(}$s_(`G7dv]8RO'jr>HO+^oNs9/u}چ|0v3=9oeUk{„URn^dAiS/WD^T%IP 3]/M=_߿;: AOVV׸~߫ PUTBهP[m&O?/6kHDbcrCYjTUG^`&H!7'au mYA=~ڴw'rTf !P  HuLaљV'LX@m%s&3 h,WET:qIϢqT@ J:QߐZ/NΡڏ^(Ma@&iR]qN^=lZ -Prڲer!17&OԴ % 03M1`T^6'UBS2')#tK _קx!E};]yҖu'l.gq#sy>OI[[<+|/#Ho@?`R×SUO +V`kwj@uDGd)~c5 .l Uǧj3x&@ H(ua4$rCèQgP(9b tѯ77A۫+yK3\7E2co>SYv@r$p9ug))knꩳ޵9#aGٴV,to6OS"[gz>CjLcjjĻgrMs)$ &j!vՐӖu'v&E=nSԵ^ J"vǺPu_= H˫>GH+]*} H%f N0U$w%$8^ A.6̶І.?12:CkOhieAYD9qi) 8_~JVK)u!sqhůD ڿ{עl8UUn"k@͎۝ V>2&}^W]vRY㥦zXiLEOvTizW6.8X ӧ>GSjuFjӿ(.=5H`T{>QJP8H@+.ـܮreS6l6W":r;r;3^ytPz3ԚN#!G!ym=-\ZJxvsEj#LU<^)Ju?~To242rMh]mo*NzIE\ai qYo7+;La;cOq)_|gMwީ}ti˾.EDnGS KվQ'y՝sc_[S}Κi)צ!~g]gp/#PG@G]/K>Ѻ۶k(NـSQ  )3c2AŦ Zϰk'۩zY |H( Vz7YcBaYk i~6'_ >= lX r? VRVTo45`jB5cȹu$Sn=XԃMXG)_Ճ YU,鱒JVѮg+) ljE(y۬HiD;PJ{A@%KVxFNPOYH]O};mycCaa/ C ~ż ϺO{«k!bgYL5498ȁ礯i'U^yI5`+g_j{mޖv\Av[Vk[_FyPi1 0 aB|i&B.YN^̞/ڋ~9IY JD_iqaPZW=[fYIlkl6P, tI{'(RP HKiRTdu9RZD*JMi@ (W38WiU痯Zz}bѤ-7/KCtWͅ[Ǚc YV1,_VPkžZV|.iھ\M_0t`ZSt3}.}`.3OyS!H 3'jS=L)%VҀ!Y@+[]p$ (1!ЭJ: *  Gη }~eQuV|X' O;ɀMݜ}@:.Dd?ja!X3V߸WNb?\ 7/L#demo/k+T<@7z&7NY}Q/lkh׃Sfs/0}J2P%u@S+y1hX= 2Pz|^*o-Dr@rpS.^ᖿ(oH|cd&IQ\.t[,kx]C-#8Pj\Tl({n7'/W`$PPm PutlL~QOm@)5/[V_{Gt0٢@=Ⱥ[M1FgL |plTtwS)P5X~PN}Ǽ|*73L࠭S~AƧZoC,!2ri=^*[]TPpj <BA>̇r]h7Ě3z}k=a8 uxBTw k-?@6!oI}(P޼OsZ Y8E auy\SPZnAJ;/3ET߷YD5j哛,gr¼Vj|#C\1um Thd6-յOh:f -_czh5rΌM(Yljk = Dϕ5|XP@}aO@1AԺ<@6@긜7 ).6TpʍA' k/4'8qONm 3{[( H [257À R|(x -Àj4.}q3U OOd ]y7|NzJ޼//|OzP5ݞwu#`iߨ+U#ujY6e|1J 4}כ(JҐ%0 1緛߅q[ PMe{Kg7VwU&a`C)Wn,i%m!j_Yf͒/j`57 5bByO _䖱+`H`ͫA>+i(<2eSu$\UTiK35~>d{ *pKSfY~ew|n6܉S|"cjϛp*RU׌ `Z 7xg{+(qCGg_fH_wo͘m-usR`.}Z+[#iOjbD>%VݵW^ad z+xY0$e 9vB1C^eymSH5.LQXEc_m]z_Fh]d3Lj;u7C!0>i(^_d;I-J,k?N/tL)'6mSm-*6 L(MR['<`z`qDy謂Pf]BF[\hv.iZAXn_cArgqp\ 724m\zѝ/sJ=IRe@:˭beL5!մ 1QZ>=R^0;x+f=.4 G3r ׅ":5ۂ[bt}{"uLj̻1aBB0?mڎ,Zvj| 0(yƙ˖賠*u]g`fF NKqaX۱[Y 75]`)T[ɗ >hVjWiYI؆]UF]Z K%JIJrt7=׸ EY|.7SwײV2xb6R{ DzDM[ʞ9PNW@a:'nB="pFS/44aꎡt * Kr+PwtmX<Eʼ` 7,]ԴՍO*]{jlOj̮W5 /sm),:~ܸ>f;5 7l,l<4i nWV~[ 6%a=zׇCh8*)uuiX5q/hr>h5uh[}>Th{j>^&\FLYUʋ̶c/4a|Yoo >y:K@im`Wm?{y0uCy{CY}% \Y,kەtqsĩ/ !:cA.5DvwX qf_HZN!ZXmJиbw{B PjFmT销0C ?P?Xx Zgm^U>cemb?=/igҟQ)԰~eA`&({*(5QT)PC)W,AP0ZEJ0ڢAd,N(5- JOXo_;COzXM"5@'r>9xӧ Ԅ͐B]PXԇ>Y.۬^ LC+i߇<~7)_3h2 D]9gz>gr xy>Ce7nsUsoԮߪl4wquZ^eCR `ȠoԄ}gxo16Fn^5(0h ` ,`H7 ZO,h`8  Xz~}K7{.STqwOw6%3.vǧΟeXe'[њ $͋.mW Lw߮]yPE 82f }S|ծoX >OpVKڟY:gh2D%S#H `a)ߩ m*sQ>ez[6߼X0$S Tk54Su@ebʱ5HAM_$Kفdo*ޭsх/6j9ַ̺sM 7`ڿq# /| JU>;(ΈuP܃yO/Z,%<%4SL.Ԑ~ϫ 3 n.e`\mj-p UiDe&NIs`j >sK QDSj!"AE,}_Vx" ŝ=я(@*4e6Ք`aI94Ɉd*2Dt~gڲ<0b?e֍ߵ{>JINIX~a%;%vFR8D2ݽӯ)vcKls`Z݆uFs٥zۢ8(4=ކAKo33kJ)02WVorExfwm(rkKRp PJNSSAL$SD5=dFw4ZD9K:RHM 0)QV)if}%D_w\sUwTGPDݮj` p|` ?2i1 f( >mFoU-Qat6b1Znn\P:FwY*Qܖ|6wX`5BiTQsUAaUk>bL '@F5KPKV[jN ۘ¥,+S P 0F &Mv`N0)[1!n#OF&MZh{k0*P- LOCiTVӌ(yGԯu eNYUFSJ", =e_Htc8-`w֘ԋMm 9+_-ٟ]qg3И{m>IRt4XEq;|ʚWnߠsLWV^AC\.S:%aA!gXٗ#l%n+C$(Vw_dž3{yi^ [h LuOP'=5vݮ`a))sH`5S7z3$(W|=4܎l鶟ΥZAS2uL?O.2tpJoOŢ'rjlh(K[]RPzh 0Yh;HS:)?ꄓv^A)rdWޜ_{SPڽz ۢxkw5P0[RfS c-q,8ZD޽6wο,;3#IjU:5XuWy2m~,Oq D%5cT ZXZ}s= R\f9O1~%%L{p(AaW5b@N,Z50ATLF7S{. pmR_ǗͥiSҵMכm*@I >z}D>G bx r]{HJە7$nƂ>C$(65 fS%rM ꒣]xLYjf[:"- 8g|_= Rmjr6I {Iygeԟ07t,,e!=)Z{pj_A(QtKW]kvC9施0m٘Ǟu?P/liB-}k؍s< Wۮ6kK@r@J~ۗ90*) e1q'jW"{P(/;1(s6i%F )76ysQ]荍 )I)r ؿJ)@T>}`I*ˀQD},V r{A=YEkeWataЌG\Ӊ:EZ1 V1]B:TKFFGQ@}_i@ݐ Ҽ3҇aƃӥ#5= BsumfFI)}-iF5|kOskTPQ$hJ1 ms(j70`81}N)a1*i߳@C(@W[yC'QkY.srN3I%F1M§9`QXFMJ`r3Rp's"Z]MtN wbߠ')g?_ P7}Cu8 JtpwN*|P_X9%Ρ>sd2cfji˞qA+ P1 mKƘSi.D8Rk>5%`⍽@y`SPI>kdDҢG~AJ(QGXD/! z-i7%n.ϭu)J(Zq ZFc59-].Y76#+cư{i<:+h"ƤiD6krM+!=~)[cMJmcˍW#㬈唅Ӆ\F F@l::JopaE v Mf;XQ(u*-.@ii^)[\1-{wu\rYLY?k`Ӣ .1~ #>Kݻ'@ΉeBEHp" o%4 %2a~,GwoXL1DcZ=ge-bNT@)8m"}X#R(<&d~IPiL&v,"IZ &gZL-qaV: T5Fy8K lѤ\S+_г~d4~!+ vBgOө <{Hv6W&A^c ZZp ,ؑT\s7h]mHGA+eD7{ r/B>4lȱ]I['oOF HoU{!pÁC}*/&<* 5YM|c_JQ@zJ5 ,Xˈ;t'ی/&S.5ؽ!{ ֻ{8׸v25㶆-n?v}k Ji-}`N1²0YPߧg52P][ ?Z&S}ӌh1`4P<+)}@}q/vJ~J 9Udr7@ BȒ}2{΍]O!W`D*uǓ!J]ְwoJdi@)LUX ^Nem27;T2e3絚A!]tq'}bn.moU e >.P)^1 Ub^q ua$K_<?7^o9g P [C^v:I1 Հ6mJk2P;\{>:U;JRq>NS Od/b Sk"sykOҟi":uT Km6KJ9cL኎NG}q(R|nV#A) Jk8ɏI9 :{e1.O@s}blS^hexOGν Dc٘?wazaAY]ç$rՑwR!"iATpg%]=JsO6#Nb\WDQIFTfj#;1IkT՛iauOD'm^~YhUo}͜M UZ-uJikOA[NKOF=xpڬ(`18mL$V:4y o5CU-ӕ[!ԮRum3eu;xntǑk"svYh זegԚVh':-,y\fǧU^ڡ zL9K檒#+dJ|7椪jA)Iv|jZX]}A4#LE kD/_ރ6@GPDLRD>(e*kS!6NɔP A-@Vh(PLB)5)8y+K%.K JݵI<( ݇*J h6ҏݫ^y* Jf(Mh nu-QVٿ,aC &jK̚""chK,m[hL-ėHyTa .ʥɴ(_~M ҨWWŭA;}ta8h\Fs҂kDwksJAg_J<43a|oyp RBŀtŸF}Xo!~QWgiL? ;;ه\}vXra1(}84/2 ԜT c1xtכD9 p:4S| .J6yl:8NPja†Qd-)\0O>x0͝ d`HLOP>3/j*.}_IDD%Mue9@5>t\A CiN յ?6eP*7du5K9zGVv_h4Pqq}JAajl/];OAMK0#]7Czߴ ӸOҏ UҤ#R.-RZB5x ʍTz"59E]f2M]FؓUͷgUk{$& Oa"pڬN0' mF:RYmzcH?{5ܼ\e )9Uoؽ=_ :_RR KJDZOm^\(mQ;--xq@@(ji:n uX9SuHQ_k˵-sJt]MnƋ/TEt4P Kl2aLSέϪQB| } -7gZ! rh Sx `̽Ϸu&o#?Y ezTa'9:}Q*^L/x!Ҁ6N*eUu3<G8DKi9m8(sαVhhT9.1GƇ".^`0}{:?$_[?t,;e(FL>k/n_jʹ9YYD/ia,xN1")Y^TSٿ`hYM]y7EL5q3<K-;i@tA~-&t`1r)Af走}.y&5:?N}@KQR`sTzWi|&Y ld]/!r`:JnToVQ=/'67O7]-1t*HEMIeDpp@,1ro~β{cIDeHEp@iI>|BGtn ?;uڟnv5qI}i̦ jGЙ`vU1 irj-'; N 1ii5V6IDl}& Uw.AJ7l(s!4WH?m&cxGPџ׷9V%P=v72ӑ/^[!.k+dL=x:@h9g|3\" P_VhcJըʊ}VQ*+OZdԢPzK2$欞ƟT0o=[_i{ k蟪5#ȳR(u_/1d` a?Dʡަbg/ɼϿ )v/ \?y_IceP<% B;*E԰ĔDʟS0Qr hP'~<F9:$.,,qBF@=k5ʥmHIJ1CxӮ] J&U ,@o~21j%uPꗮVBJtcN&b) I@zѼy~H,sR Euтɭ5更Qh$`p}@.DcJU^ho~;I @yH?+hLv 4%ڒ̘ 'C ,I)~N\K?%ssyf Iɏ\Oh?D@4L4FQN țH6*8Hi&Rg)_ZC Pf6b=$ jwre^,Z{M<(,|_Ni&8$K D~ BT ]F  7sNFQNɻ&0 @}p*Cb^sԬyqu`]qx%:H9,QXl3+V?8Kz90=4&S--~#T;sON/K{:Q;g6A`r-8(P p춙(0A)pS4"ղM'e4˪TIP:ki>vm6HG24 &eAט;;0W}QOKxjcy("NBi$V[S@NGI l-W]Muc8\Ze8hUJ$g/9%*s  LʁJ4(7YC ^%ZT _\]-jkTJ) FM5]tRwacRV\k5wgE v|M.c }Ҵ҇p>E6.'-{ĠP0Zi2S5D SoĐ]暅8 *x屠{?ކU%:P(QHgMijd`:Ub{/=@8iDsAH8_S!!#A=ƥ!4%YI[f[i"e z $.fÁh{l)#ċBA@%&Q iN=w>צNԭԹfܽ 0.*1"˂(fk~5ixv)?"Y;4d3h<$a6ɩ 13>dl³: L3dDFh*I!kD$aS ):(=8RIݯa RGR!S"*݄BTUq)@% *'MuH,%C 5S4lK;.[kΠD)@͂(Nc&.SW@At;}ghXԷu/mn*4a:\SҏSgdHJ/Zz@#ߤ*`?Zϳ+P|%OrVCtW*RbSBfT sQ,v72N kρ|&>dM|]N9V vz7Lln ADcM w kUj` #Vҧя| VWL6}ib}ƿD<0mSS Ȋ\bݻM92'ؼ(u HH#)VUJpЀhl\ J6M`TUi6\cu.mS鿗@4V[&{r2ZD eGaH.a7lNT"p4]J:$w9p!H+9煁"hJ5+E{d )"y6IDAT.c K_9ȼ6bԹ0J%pն>: T P#Db,o][E޽LV `r{pJڳxP ̓ J꫱!jVM̓Ah#*X|Vk!ѯm؆֑ :@>9x_4|Te*cFE}pCAnDU 4fг CjS3R&P::RvU%m5s P9 A)iK:XZنaTTY'a4p򥂙sRorΘ\XFC23!ځ^ Jł)~S ʍ Ւ/xSy-KE)BъWko*qA~6= $0vns=@$zT(Xb8Ȳ<]-Hqz~@>~#7fTz?'<3юy7W]K-RoxHeX?q`ט)ba򙦻W܃҂J14^f߲_A9/m|FD5-Z@w V;oz] j[R$8/(VUӿߕdȴW 1)!c,U Pr_MM # :0ǣ s㬂8M&cen K[ RKS => Y0Omd1TivT2,_27Id!P#k`ƐfNjRYrTQ,?δZ#9޷_)ZϒbsWO O ^H,5׊dPjxﴉNp-}F2>QT4V (|rs 80 iSj%UkA46., Ss122sU:l+& 쾬9:K5&@֘XOk.zL\dx-m|Wm(0=0;S4d21HÕK$l:is9Kq^U]C}5h{_ h峗',u!S2u<9@ )L[uK ˳!eI יg;tuꃪ-u]5sC>c#fOxG EqDc5VC/\+8Hs}G@t#9MEEL[A'YL"%|?eb=ݷ0.#gq}4!07Y-o6zu־L/֊ $՝&w[]ᷛk|n9cC(AkD2Be!.x3 ùr4|[ v:>&Ӿ1~[Q=xiΫRw,bۺru4~Yn;k)0Ɋ? j@Vsu^~zP[k?go.ezO(πA(@Dv(=?k(1A+Jbɂ1ӜH즽/ʾqRL Tlzz9ߐs S^Gޜ0Gb@f V,pILfWgG4=(4En6NrdʋH VMtMZ$پ54w?.(iI"+f ?}Ɓ02rA0z  >GğFo6iJ}s9%uPC%_`0 iFyZn]bԼ$@(OnE{A1\ۉ!ǩƜkʬDePQT+7't(xb(? yau )Mfck_k;[n6(R-\/&N3[bP[=(韧@\hϓN&'QѩtYJgk5~롼nd8 Lcjawcs[0dKlz(LUpy%z| 5* zBZz8K6' X9G=ɮ aRҏQH`:,m~-=3 =SOֺ͂1t !;BCm}(L* \4{D_OuiǤys!}N/_о|JQz|U5+ >V" FY(@4Pe+y-m?ڇ2WVÚ=QK,AqKd]#{dq Ӈu2D;*JWk˥j|.'/,:o4}PhnJG6rŤ29'U'O ']M*0x.I,SQB$wz|۹.yޠł FV}U`>ӗ5 k+sͫ7.-j#>oei"UO(k0/^ &ڳ~Mjj/k,ŵ̦A7C)~lI@]A2 йw~ʲxQ ek߁ғ|3p ԯZ0ЍQ&`rĹL(gAXGTueaԉg]Z5RJ-^_,c)g(Y{["(46`G\=p_o=,O-7bpSM+пiͮlT)ǜ(mOr XpՑG3#9{*r^"kuXN۩sOיZ7ET sK5,T@A4+R=3A~YYRL~P:hikdZ"5-t(!&_oq&~}hҥr6 =j* YTSITTT4Kp(XQQV%}SQQl(****Wz(********6U@$* ZTTTTTTTTt-********: DDNEEEEEEEEE'QѢhQQQQQQQQIT@$* ZTTTTTTTTt-********: DDNEEEEEEEEE'QѢhQQQQQQQQIT@$* ZTTTTTTTTt-********: DDNEEEEEEEEE'QѢhQQQQQQQQIT@$* ZTTTTTTTTt-********: D ש"ZTTTTTTTTt+89GSTTTTTTTTM?vB*#7IENDB`gxemul-0.6.1/doc/20061104-netbsd-dreamcast-real_small.png000644 001750 001750 00000017223 13402411501 022730 0ustar00debugdebug000000 000000 PNG  IHDRy[`@FgAMA aPLTE pX(  (0 PD 0((  |H (XH(PD(P@ `T( (P< xh@(0(p`8($x`(0$pX( p\(xlHp\(H< H8pt@`L pP`X8xpH`P (`h\8xH@ 0$P80H4 LxX,`@< X@ PH0H8hT(``@t0 ,(`(( 88 hT0 ( ؐl(xl@ XP084 x0$XP(($ XH(xl8P< @HH@<(XP0p`0088X(@X @40x\ 0@@@0((`P00(p@0@Ȁp@PPL0H@ `xx\(@dxHhX(P84 XL(80x@phHx`0X@ @(h\8`P $HhX0xd8 @< XL((, 0L`H@(pP hP !9;r# [0&(?YJ'+i7u1m~dM&ˠ߷!Q^/^!2r2`ZA};? e2 $ɓm&1dXf@ RܲDdE z90Nlb_' fC3̮Tl>^'1ux.}ߦW]I"͘*=ShH&$qf&'u Z /$ezd/QNKaKeWekh[IA$цZ4Yٓ`8Hk^ϰ !bdF%zu3AnDא@t̠hQ|k(d6%u].<>'Y֓Ȅxs@׽:ȈqcͷoךVs_5ğ9x^u˹UӮHi hŷ{NVQVktc'tYH&˝>ۆP2% ۷o3RԷ h0E]1%;bC7 ݞ>V`_|<9;{:y(!9iL?^.Oۘjf_4&^;@%-4k/8=zfo#S Ul\mTAv!'7],pv2gvTR9Ò$@Bv{_;$j6\I#`)[Ϟmm\~>&z=S#r" !}k6cDM3)%b9:Ƣj2D'tCwmtZ~&[]%"3i~=@~ٳm}m|zb\^NN$>6t+Rn~-?iiO W~#jė;*ZX gO>>mV{=2Ʉ0w,E4m$/JRrmɭDӸmcb UcZh6&K2+ [鳏Zggړyb9AF&].Kĵ;i=cNRIw( V<4IԙšaDs /3rtU,R:Ay}*Ōb,\P2 ~Jav-Im=GOCau_qֆuzJ>^u5TzKV+e2*q!O5 $[u7=zZV= $%3 ;F%g̅?o8W|ϯcN*o]\llIڼh.NT\ O?Ndda"//bץg[ Z 7@@fpt]Y^C3ѝ~_7&QNBjzdi6 <קgQOK[ٵ&ȋ6KT>"6zs:KbuwN&\.z牼;u:w3[*±Wk#w :=*)L `6O#ig&{H~'yx>Qpf*< S\T7޿|7Qzmbs;3]+.U0B4ӻU8ոjϾѐٳ90 J_j?ф'WiH6_P5O|uyϣb͑͠–QhkksW{)WKthW{ Aw%FGS9Tݽ_^a{ggG͋&Q(˼]V-qiviP 0jսGK(Rb,  mYE$ϠC~9h~ITvT+67M)8HLLz6ȓHͮC8aXRXY PulVaZUyGR(x!b[\sK>(\vaѢ@z:*1J||#K6xk6ۅMl&']j ?f"y$#./?FViHVUsӗygLmd |{2?̫[B' {0@di//.7TݥU[XPVlTZ2I.h-hM gOvvf>/$C =3%Q=:*j z)T1 zHtA=e/o|@l4Nd4VRYʖDE[]{ ¸V%W) N[wSM1>Ddk&S7URH^Ұ7N}R4GFu..67WF)"wPP:o_=xyccԓ8EښEjmzkoNVpݔ-AYA_Ww氦>}FaW)@2׌ߤYww.4MBx'xfW.6%^^[;8 KLSf_k@sܴ_'q6H]M)A͢'5NUS*͢r D{q";K(%Fl13^|yIKH/tx lr{hjqBuMKnLm5׆ֿ׏1>^QCLj `#hA#~ܭj1?;S2V@t {^)ӔUxܔx%z 5#4Ȋ $$ՍϰQS2q@w:աFwܾsNn秆qЀT_1Wχd\Lhl@ :UXyTEk ڭVKui*UapYz~j]Rh-.a~:&[7FTG1S=Hޭ(}sk5/Y"id ]Gys ttiXSG'P;7U&>P6tT7#w'`v:1v:*YAG24A! zɒ$MǠ;| C{ðKSmF{qr@c^!z Wbnyyk9 Sŗ6\"K:zI|>l>< ՠB$sxxZۅߺw|in-C_/>=\QRK,Kq:ZE~~v9"t.`I5%dBK!>|m?%D%ɮ> 4A1ӓХ28Lۺ3obHi"OJm߷ ![7xl#~L5*P3me~RI e+LzOLj&O;?yPoDžX)bRl13>5 s>|w aOIb+ɦ+~P&ȳG+ak"76GSygp|@)wqaj*4kC9dMB=A34/uʿ q!;|`UI2U>bJek1C7+̯X@¤LM5g|K{*\; >]iݬ!o_|2R,R0&~~ 0z7u|YJmCrQU- g7PǙ̿j@`Uԟt^!쒾XDw?`JNBu÷\NZ\ DFǏf{骹gSu9>fY5Vm7S*lw7 Qn4v:x4Pד +d-ZٲdYh2Л6ͱñ&L95x^{~'0xOE.Ztj>Z2AV*֔XVw<5Z;>Q M7C!?WɈQ¦`[p蠅<v1&T|ͯ()} w?odoǷ O bP\0XTBkdN$U#Kx,"#YCΎ o3SnCLP!W>e&B`aՈ(r\u>cd2\B;]!;\>sLpo$bA^0 AXOɤ,WIsh`_4u4~ ?Ps[\1 OVVҺ)RafMc[x,vu\4*E=k]H Ja ;Xsg+y%tppPZ+BFYq;֎cG9^.Y:}*aP W8LA[&4B!Pfggʴn8SC׏I1qXdcgM2렮)KA`[+|c$f(rơv:QCx&C\)+t0-NW_EI^.15b k ]LggR<]Ԭrj^WE΍q2eA謮C5Xk%yͻi9󜍧QmtJaCb]]]ናɅtn:x2!p){=.F)m-줮Z1?3W$Kx!ssS'uvcχIR}zmsYLVcϷ2ph- ֟etIME +?IENDB`gxemul-0.6.1/doc/debian-10-small.png000644 001750 001750 00000007073 13402411501 017254 0ustar00debugdebug000000 000000 PNG  IHDRtc}6gAMA a@PLTE} t  iwmtoqstv  x !!!!!#"""""z###$$|%%%%%&&~'''((((((()))))*****+++++++,,,,,,,,,-------...///////0000011111111122222333334,444445555666777778-8088888:::;;;;;<<<===>>>>>>>???@@@AAABBBC5CCCCCDDDDDEEEFFFG9GC7GGGGGIIIKKKLLMMMNNOOOOOPPOMPPPQQQSSSSSUUVVVVVVVXXXXXZZZZZ[[^^^^^ccffhhhhhqqqqq{nV|vl~kGڕl: r#/Ț˵ۥ ŘԳֶ#qMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 :IDATxYYKf(#B bA40bb ‘k [-ԆQ) vkٴӽ<@yP{9}:sfSw$}wUjjX𕟾HK/\B77 χ`CVW{O'|?37>GGzȗ߻~+[?7<>_Է`=`c J~㷾vw D_cЧ_OqOwdڶ;i4eC&S\212rH03&gN+UfƧRL3d!GuC. [" G'˜̇@p[YjT߉Uݴ.kU6M}_76JRE4/MV/t4.2J%0݈6i3Y8 Yۣdcf/g$uҷ<%X)brxRb8D 0& qFW~zΗSjp .Kuw6Ku1}ҁܗfRƕ&+~aɤR.pZ.PRfƔ3J)3Y!u&L2B<恠xBiB'0˜x(FJXX?53wfnTel藷+Wޏ%ј*t 4V&[S &YAHH*\J z2JT5?E@QѲȝg¯Җ|Gߌ!]~|JPn3ʹ.]E@>@L=Ӥΐy X|6o`WNSK Ô14aGIsMw}frVsvrs.9n;؛LjRVZ)u\ 'kÅ󡈶V77̺CŨԳ]OFu}vr> Y#@$搘X ! ?# D{A}nd1SڠEyo>Uw]O6 Zt83_%&SPP!PX֧:C|Eq0E`_xR 8]T/t0"Wuu}TW> *[]A.z"R5BVP|,R.gTNA>K+&\zl5S\t|=\䅯 fC3@t ^" a- $@NHA^2vx)K POC L|>04&XY/.nG ]&x AԌ*A&,H(\1bb 8AMHP8)5צ϶YSQpTyaIn5D?A,Z`֦TҀѣ Ne>dnCe\Ƹy%&*70a@/Xumh}_y1P(d\./vV6QBӎ;wQ}XFdQDEm|}ilHOc|sn4bwS.7vkC;(Ga! Qc,ӝ%έd n!6ch4XLVr-@{?XFxQzsM'hl` $oW=Q/Z1X`dZ90L*еWro&*@H !Dr hjp|Fs?"EcΨ炍sG'P-oN{27ߢnqM..חj>^HFށӧ&?2hozFu8F`P=BB1)t T5OW:,f|EMʞو]&zm@ĊM3А(w-]e8 g'M xθb1,6_~:T R%ES3zstAvח2յѠo.61- u^6qF/=SѮ3= aXCyHv$@lMQDya|t]fm#eut6hj\madrt]߹P2P7viFtb/8}*sۥ=!Ƈ8\> \I^{pЃIQ7tGL͙ BFBݷƮ\1O:,m,Rp''(tN(8w:ͺʈ[(ӧA C;D A`1tn b@A I$;֡%JBL>%PCK*!`ʧW[{׆RvKWZf+SZO,⻩Z_ߏg{;/|[D+Ra~}{ȧrTRAڍA."hNe#si rMe_$̿W~|x^H[kHm$5<$2/GhCG]x©{D rMec gUDQ$D2崯|j5w(\!U oJYG{]O ) ,M fα4,#*GN:H3]@vY#a4+ &P[Tܨr_.z K0u<]Ij yWV=IJtKň( 6W6c0}3bzC֣ugpN/A)o@z!Qr;|r@u?lYWͰ|rC_BΦ>֘, {OρO45~bbny`48-o5 ,XfW6vMQV@2qZYZU@ze~<1Tq^:p!p*\RPɋPzpJ8Ao(H$iUQ4ܽi (; mH h}.U؂l(rw犎S/!JxD1c7A(!oSDAH7-QV3LR3DNd՚9H:7ʒUIPiTY *_RŠܬv5^~dy_N3j^ɣWpsM*\FY(l HX-c4ε>gn7:<]YPu0ntpG"7ـWR^_PMÌof  QZ/(ҘbqUTZ!5ryg@<[rXqܕ6`3ij%˛h,sz e?I'}Zm[OCO+V3"+G]G cJ o]T;;V*~67$\PJ!nlgNmY0T\=tz7FγRmV?oL$F94$ՀߎF~r^<"=$UYԶe&oyΥ*2W(7 :8" ˆRH^JI"t HbnLK`/ZCb93gM>Bl+Wu쬙uu#;OL#dnb3RP?Rk)_yc3Bnш5#S4Mk= !u!Q*r&  W*$ $Pg|"2XWS㇭2i}vL4srRp6\5J X#7|Nٟ=~3rA!UZ|;˹֋:Bew~Y%<-ITx<]sTHU"*VW.v,$9*%Iߘ@2xΏ^fif?)z OR]w©-Qڃneҕ b"@!Q(HTCf#$ %J"# !URzls_nkŪk6N K_Y4Zx%m--Xu]!iK{?ʥ~q[ȧ$(}:u,U@ש1awhMǢU22AP!,ĘnFKA>TR1>۳^/ɂ2oH*ЋKpOD=aXI(F0V_h*1t3l@fb3#[ S=&fX;xφ{XTzK@mguO'*#e跼etCJBp7u%\H% QW&e6+it7ԧj3A*o]] IɝB*wZn?jq-B^4.}D˕ۉy#֋:}DG]H#+J#5'Նܢ$qtVիWKUǤ9;ߩSPYQKkwsUe6'd1s)l=#5}? xoMefFr9ܟl"z8vi8io-r{{_ع-GF ΝoKS醦*Y{ysNВe.RF hF66vׇ@yޕP`k?3⫾h}vd_ZiY Ҡ&k90N)( w0KTKsf'cӔA&"w,ox\K$ғ =oop*R75~&߽WV懲 szAʾ҂~y҈';)~Qc a/i F8[ˮh9 :ӨdP_(c.Y6VCh&}!aG[\xΤ[b sӵ>,U{Zo}>5&<6NU5))U Q$ "I.8B!2!u#^FSEK b"PLC'Z4 |lq4q^]=lHb؀p-`q+ ǐ=^`X i !HkݮF`HzxP`F1SUyM^"pjVHOVi 'J..v$2ty26:* ]>*1 A9%ucIdD!uH|] FT T@!Ur*W(*\G8C@A$X8?PJnX\F5tIME 30^IENDB`gxemul-0.6.1/doc/20181018-openbsd-sgi-o2.png000644 001750 001750 00000130421 13402411501 020132 0ustar00debugdebug000000 000000 PNG  IHDR Vs+gAMA a=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATxyםWGAlHDoA ur,N(FRgرk;ؘGlލ=81AF&E) w*Tw1_|BAtg|Wf_*J)TmjZ]i PpT3o;wV)UQJMp7]u %o׶794;˔u\֙K+.?Kgg_?^MM_ڶi[o[J)=> Ov7=KtD)wĺm|K_7K])u͵-, _\80< g{]'2j~0C< XZT])t+ K=dWᛮvjDb%:+y"Zv/ '_z◿a0\y/"~/,uKDq͍LWf_}''jc,M9S8>Wߵ&7+TW  d%:y"&*vR꯫:Z?2jx|y~v/F/|w&2;n1h\zӖzm.> Ѓ쉟tLoơų?g{i(Toeii;n߹gkuߋgSLjjolLfӖZiqֻϾUJU'oC6n^WOً=Tu޽*ݥ_{7:Nh~V#-8|ÍJ-ޏ9~DT&v}ǞM[&nw9jGtvr'nPfn3+7^~ٳuů>[/KW~O_׵gz]Ҏml;ݟЫ7>p˞<n -hjEXUJ_$ɮ '>T&֟W.RT+j^_T_x|E"=g-<4T 0}-..8]ƛPI~u3qՎWs Kj'7O7w=o{K)F- JY\k뎛{?Ԯk:+ʾ{׽ZL]k]ovyMv~O\;?ﺩ?vabnQ=]yvc*$nX~RJ}pύ0WR $-yǟΆ ^w퍽ŨV:}rVnW'__uٿ~+~ )꺝 ܥӗ|~@T>|҂6n(վxwrxtVRJmPΙ^X|Fz-x`&PQMՉڠԙŞRjjQ+=un!Pi't|in;ʽnGG[Tx%0jnaR9oW]bϞ}ms?o鍓/?܏[Tm;+/:k|q-~Ҿtn˦Mjҹ'/nƏ~W/w577n(txu3ܳ{MWM~3߸n=ϾR?gN)a][;-vl$i'C/+hƫ7UU^*uid`jRKs\WOzpׁ-չKa gޫR_~̶}1>}+mRN{'_[K}i 7{>3ɋ/^uׅ;[];>ѼWBuG?)Op;0!q S~llO^aX+g=?<0=yinYȥʞ&*[jJtb78nvqVڕGW֞|j;zrVvQN@"0*ܰ:sˁʋ?|n{ow^^OO-uR[|NC/{ܽq/'gt܅11YSŕzU)׫o_'b%'NwsJSRgگ_sW^Y ;NwGr{uPu:t;jUݦ#gkJRJ)zRJ)/vݓJsϾ}rx*ԅS VO\XRԎ-۳j5vjv{W=^n_=-B[>v]ZxgO_j/sO<9x;Ͻ7mjueێR~j_zo۷Jeo|n9հtˁp'8~p~r%֟W;]ov7}g_yR?t]vfJ)z~y {=mMuvi/;kү^|[/yػYG4]Rs_~:׽u7o歓zen;JL c-kƹśݬz}WotzǙ<*L^t{+*k ;}0/.-wYsnӑ|IwnWraQTcY\p6Nxփwq:J)Uq˯9~2}>g2?Gm4zJ)t:\{*NtW~8JuGrko<{TNy셹R#7{vln}/7JtWjJ\wN<[o_S|:te]'.?uGo8 9ot\}OVqCE-©ˋ ?uƝ;:=ݿcԦ^W6MnVnޏ4S?ot/C O_Qj=%xաc3KWS?O׮l'zݮz슻 oUltHWfcaݍ-7U.<;>߹ZN'{]P_)6n:]&6nTJ-_t^u:8" xF}vO~BD? K^۱aV_vZgR7۱uf!{#֮{q\qבת5xr~ooX/NvmPjM|ZkM{;r[o˷h_ҷO.nr-7߿?љynYWznQ ~:NW9g-;˷ܳ{_)w X}|bp *Ԇo^?ջ?\Y;ɓyro_~p&:o=ݹΏ_;u{מut?_qb铻'䩓ݰ^z"8'8?޼ _<񶪄7f:nC{O^Nm0;/9݈-ؕv_u+W]wpOEީ=]"4<J),wۨG"[oߺ[(ug^s=]w2 zPJtpQtva~y504JaG%ڻjC}}2~9WJ?yS7D$\Yge]'z^9n Çqwğ؝wdBuK^ՙN;-g9џWyQwn<~֟^c9g|~wמu:j:G9k3xQc?w<^[+ՎZ=߿y࿷{vuϟCWהR[Ͼou?kbo|ŷ.ۮ;nG_g}dP: ɏn~ ҹg}lrr]p' ^ Ng85ֿn9pi_:cN_R(]{\T_۟ K8ouyjGUs͗_UzEnW9Q*\ ?y1I"3/Ny auھKsvVW{#VԦ7i5vwUɿ~/zJzo+jwxy:";#uS_ xzaqy8Ww*ǤR=\0zD#ְܳU&yG` I~l o˒F]#wjhFVI;6D&{sp6ޓNkdT2t,c{# Dy:+rΧ4naz@+:vZ-a,9plgIU 0&D}p3@ѡ1GOl+IyK&adaQuq{,,>F+=!CfK.VKկ $yDcǂSZ9dZbfY?ƶ.}ںv+ߟ=3@rTSw?aJ78,ao)o,- QG '\tb[,&^E Ȗce}МvxbibͺPm:FL!⛁R}9lokqgpȟpUqI&)WؑyK',6N#$ח]xrQxlwYZp-kM̐BD#Tb_6$%IfeFa8A&C$KX{ո~4َgl[<݉g?b3G&|V9'ZPޢij֒턽Kd`w.m'[==&=AŅ0#h4Vmk' C q}Y<ǣwB(*U(gE,@A1{ 1})Vsf-twXٸUr td[(. lzt$?vcfۃ?4 l$6l{s0vٍ9  K{ؚy:ƶFvgFyȭԌtF%&.RkF HJϯϙOEjyx?PLo_"g7|'2HF}ckb\u*z8@x, ?7JӍ.}-n#yD37=ёɸ$}ÿ,p!$ ݹz;]Z{xl7TAJuG53+v#fguh#QwO'fEoc'pٳ_&Ʉ|B[X$+E[-{[yJkX~ W&Z$gD7+䌾n% IDAT߲1ųq@xLL~+!<@"yܔ(*U 1u Q@N0{GJ510TJ,VKl :1Bj|ǁh6v jFazӬ4o z~%LG`6=H2,:\+,WlW(Fo;\;q4hS2pؑU%֟+8˻ǙEȚ08S4z^NZ#ӉuO\Ϋ_N4Kj_PtA,֮~ɫ,V+B0㤆56"c4ȃyOR wjLJ,<,%%J6Ch3IEmJy|ǞbL%F$E8͒rƏ@cfra%؝8(Kgf ωȘ?y`L8uxv_vՄRq#[\7ʮ_q1c׏s! 9H@X=EmIΞ|;y+yG$9 FP3s6CVvsa6D65=t1{lVO9N0U|0MDtlW1o+M 5msO NG\T hN o 2hݗXe%9X~.1[߼AF\ l2cF 0"߷O>J;(Ox]v=ݭSHc>1of^8uW $GLgfK?qCVf9H5(~+N "l⢂/f*ֱ$mBlݳV"oipy z3'@xt! d,c N,? JXy{X2λ#<?JAyғf_\f9F$~b#)ِ:lhg;gpkROgqCBWfn0 qAa?.a%ܯA˃=)Wςc뒾=Xզ}_lO v3ݸJ}65]FF~Al 1 _qP Wʡݩq1r=.f #ힰJc0'`hLrϹR=/ʌάIoG*sg|siY0%҈根K6x+*HiK ~UXl A ϒ-B|ApWfxL懓 q A P&u2l:3a+DؚLM%ٗ] /rX%$쇩Z b+)M{y8h++BX9.Xu(̥B65=t1{lV25J"bH~<˥LWa !V[՛C_#){ܖv4}f$Ѧ>ioȿJXVX 8p{HI^'>--̏EQp}ck2.W̒0>o?L-R^;_EJfj#+RaGl P,UM1Γ<~,|DYY]@+r)pY@cKsvy~Na6]M?s^V[؊G7C_dϘuס-KrN^JUys| m=@?O,{~)*@mc^M2Or: _ '<j+ k'fFvb[M %~1a`Rjy IAnCDž=G%OlQ+lu1M[$ bEYL6jheX{> ˶pJ*rIXmaˮ_;V?4ζp?\pJUk:}5n{M^JK:M{{ D 6(hx\FVlL%1X1@q1$¤1@90{ v0u PhQ1=@3{lw47M/ejPcvK{KߎULq}.i%;`{z+hΠީ# WōF@݆~cka$PY ֛\tXc2?]lq0<0r; ^\ZAyYr5Ma9,TE:*JJx[Ii˳X%`dW'ֹ"{NK5VJ.sԦ4f j$&l}<%X?Io~x?)Ǫ"@4He3a}f$Ѧ>ioȿJX@)h4Vmk'>\7~T=\~z60)3(ẂIxqфco ށJ.N^V4}UyXɏ: k>bcIcsS]q>zCyaJvX~ҋ7ťb'"Q,pgpYO_[yb/!zQ%A˞hJ~0)WF k\f/@BWBDex^Z)a"µ_NLJ֡$ nvV\)5~ (vx1Z> DYVDZ"V> `+'ǠozsNt }%6%NFg͌OI wuNR.IPX^v}#V咇sV:՝%}5n{M^JK:M{{@90u Ix\F;6 Ax :D*P>L .fSbQ11fGe;@lxffwl6&<ĴE{Z.7{OaNE@,Y3u ȹz.jOwn0[ج\a p`ŭCa\ǃF3'V $DŽE̸DCl \O#6TQ:Ձsa]ask,ρA~̬I^Muȼ1Ǒ"?aj NT=,F? <<Ǫ=mYa y(?6ֿ.CIFa1:>9&Ix7'zFhNUiuk]-rJ x5̓@xligsg@N1cS<\Ӝ(tc4ϺlB K~ ]RQ$l\Y$/)M-K$g b˲הt'Š "Mc]ﶮoX(Jmj{Hc߭V+?Fq$l'͟?#P$#^WMl2I = Bŏ;9y,9M9Vsdp.aanzͽnOxCߜ}X65F"?24c j pр:s%oâ9\j+VdhyE`KUJxXHy*Ε7SRvg$Yc@qx5nKTBG`)bi\qiƽT''(psQRh_BN>,TҰڶ2'lzÍvǑf1@jf^a$k{b$Yi-H>*ܴ%RWqUf/!K>3/Jnve=(\gܦz..KBҟ z PYIh#n|&L';f/IfsFwݦz^gŝπXsAC "dM;>Ͼ!ź(j!Ց>㮱Į9VO/ykR*Z\kS@X%Fi$ɪp,[O=.O: G-<2ap.}fSc{b=gN Ç7(4@xGe0?V>O{xptb}ca:yG32v3"חά5[pf?RԚRym2|#Eisf},WJIN痼o.n\J9/=vi6{Tq=&YcYWnܹaH%h(5{]ƭ@"ϏfRaVsźR$mkHmX\+?T~̧צqzr} ?Odd@>y= 2910  1.1.V$2^*b܏ @f=|~W{=b2yf0{\JMrvn#.J8{<333/5Qhy͏1¾1hP@.2 Q1zgE%}٭+Ռ11gP2Ig:q?k5V?9}gM%v犜Jha3JZG(\,ARVWtlաQ9ղL! z@j0xJe۳@RgЦH Kʕ +Mr.I{YN1@wF1JoqquZ낲 ixmB<% DK9VN v[>YJGֱEm7/A!1 ㎄'͎JVFWseYrdgY$)XIR~^,Cuo|C9,Gg{6 d#w֬$Hx.1=EU'ӫ~Q[SỳY?{%$nqll^t$}#VG5ʄ5!wb]r:nV]ﱪMMXCi> +'ExU@}65]F<8GtDHl<>E@CR|CXIi.kdseJ8v_-b]gm!ɳ#)]X5J=n b\ϑ^ŭƸ]cnGAWߓ=@Lɯ/`~cPv TMMwijGEg4JOuJ,GX?[va%[ ,,1Jx+DŽEH)2cbmؑ"_źש{Bxb3Y,^_u$fg;0?v80j pQOJͷݚG$23i<^y@x9ןH+I=BI#;W%` $_?jfO(=Wmvf7|0Wdy?PYiwlQq+o@U @DaG6biQ8/Pxo1jw ;A6iآuNȒ7 _[5$KUŊӸ'HNDחȁȦ-c1fMڔFF R Oɢm!Z.1;?Pt}qբ"a! <.oQbcf 1{ W;[u[ pfNL*M#WrTsk$dc6n=i#ӉW9ƠmI#o/aWtߦq2Z/E0ZtБ[V? ZvU3kH?.2&єM dzc$}}g1ɿbn9}ބFhN>\<A!$l5~UW˛ )IG~[uX_#k*?gp WpW hMSXq<6ֳ6,v}bXsrgy ZHA[P`^Mبzpm6)sz{w4{/2Ǟ7-96,"޹@9T#=_S7bfuNˑZnsg nĞ=*o#d%ܙ{6 K& m"7 ;Y:wVMG?64S[#M`jh^ҳ7>{7vI[J-ʳqpxAQWC;Ug16@puQQd1&f(8Ab7UՂXY)֯SMWƺTcա2R:Ҙ=6w , g`!\ }cRU#Z%[ L*3+oX̶o菑 ; MoZA(e\Yx2;o? le6}>mas+uL.11B#x+EI6^Ua%V,DtsN6_y^g+}}}#gR~R-e}P >"gxlC$w -|0oç!I{ l 7 1h.z>/XQ^JU)<'Ǧiu) Sl=As))e?Cڔ L)@T#?D ƕS9Gʍ=_hR.I6J7;h7}ྗ &[IYMXvf0>oak9w}_^I>,۪C޴X88< C.(Ľ5 N1){> U| H`)&Yb`D` rh= axè333<:&hk 3 '6,<,ᥣ0ik 4M-@1rX]kMɺ <&sy&9#=DY:RF>mAr-;G(#:asfso" Lqxl72[+Vn3WF9]XWskLqn뵭pمyf'DDJJx "a<05[ |sXjJ^$ <=쏂4ϕL{&* K'r"#l"C5(q?}7 H ${&ϳ$8ّJS.Il;?|]sɮ퇊q84<[IQ3M q$Ϟ-}l<Ŵ[]GⳬIw~hA &ɳo 9,^ QxLSV I9?1%2"i/{Lgy"f[O:S9FXYǢsi=i"y ۬aylJa[SX9KDrc$NX,TX w+-[JA͹Ԧ4f jr%y;,0ȨJ0}m K5$0'eG]g#ɏY7ˏZ<+Fc5vvh,N[>7p|e"g}$2(Ő?HX(ɯ+< cX ,){X^< gmaٳ{-@wf~y??Dfa?YMLpbcS硧Y?'u*y=@ G,+=a(Y2;Qcr#nNumGr.qN"޸IcidYp[Um+[SF5Sai'I VHkG/۽3xi.<>&Bl_a1 +'pIժAq7O <˧^} $ Gl%֦|'ѸAq?0)YTyT#ϳk'VO$a~+@qy=~Gcnf6[K҉F24w }'Ir<5:Dl=[#,~y% V AU_#Y0Z-icѦܶ  #R6 lnjŁc`#r0Th$ym-b槺R:ƠhwqhG*𸈃$ymcq(>{vle S(.ظl[_oa) | f0qwI[vTŨ*$N ~UXY-,<& |[jn eOƧX"$?sb]PuKp*#cZఱ{@5@xډU`ت?cOl-9y{02WRzTOX(ɯ$/f3bt:؎aŗǠo&e뢈4 2K+aN2 ޒlY쫚J~aAPU,by>6D>.ˏcbcS硧EyIP63c1n/)̦+%ׅg/V{y"@[ma+UȲ@ԍ##g0t,Hwç|d_BIOQ~T"~җlt2FUo1r||JELUh G>I=a4\41yDzy!\GDȚm?? ;&a-,%9'c],?@rfP V25T~1a`R]0ֽ7n$!8Q9gTN;D/)=#*_?,HI^KL?Z[;IȾ!\ڸvgSu$B8c9NQl->?헃{48x<4-'jH04W)K&ͬZ4Q;ՓLvf4׌VuDZQ[a\U|EҼj? p^?_?>>фD$~3w,uqO0g1BiFAmT֕Ԍ\iF޳U߈Q0߼~#Uagr\.˯@o9ruYFF}g!H9qp[H+AyNX[>uc㹼ϝr5ViUߨ*e8w {0_{^[{bUF!5]WE^uvX=_geX7_>V[ ҡG 5d[n5 W9'yJ-Lm2/VzoU96eFzvߛ7҇NjCU'cyroa_|/Tͥ0^grDu,RڨN|՘#eN'*ڮOya|) pDu_C-i ׁW k8M2 68%1@5nכ"{c 48OC1@8O p'veHaγ>`ǩ3$R~|ܺsO'R x6^*”ZE{8 T8 $BA:7')=mӿxleb?m0` -9g r^LmF2Fx[%m8Opqݢ~ 4M̥'1d:8JOaQ6m7K*8+ξ\O]29'V'?I'oD &32y- +m-7zV[+q:;;ZH{Jρ|wձEN*V[ve?rNZXwޘ+k'lx:n<Lٹ5*m8-uv祃fئŬ8Ltn48c aK~v󫊱nqEv~V[l&B3(#:"|F6UU/cSFo7kA=ABpAȮLgkKk8*#\|nY9x+b]_^zllxld_EC`i vKx ۯ{=`^:3&~k!C=~{<^-w%_><󙻟69NOsgn{.g7hZ  Qbzfv8~Ż?3F.6o>mA|C\wv/!n >װKYŁW$͉aeg\56&3ż/Ƣ-*:lʧSF1dk|_6VWy3ja R7<#eX+[T:r +o-a"d jUs'rk2}1!;կՃm.˯@oYyĤe?(x~`ˣDb362ٲAT'}\V̪. ]'9G*i\׺\6T{=1Jj0 C%fEk I5mXs&<_mY-O(Rz#ů)U+Sr^lW}oM1Of{0e]6qrՅ?b澆jvG[{wZuӒ9k{4?j coݘuvnԳ WjJXסUxWq9bquH?e'XeV_p2·lj$6~e;W'{7>6SV3 gX[dEx06x 1qCST]dLg{Y>5ܨY[rU#rbIcޢ̾6:8!Blqd\|-.%)/l8~&n-iu7-~;G4QmӺuOsV]6qϑ)ZUEuйj_\s޸_l^ɀ+u.ٷ`<s+-a^3s.ٵ/~{H,EOdʽݚjOb-Νv)9#7#e6]RZ\=X(e H:ғݷ,.7jWz?c3.mV?ɲJ4yy} PGNqy]+;ƐݳA = è_W>uxD@x cg _;@o9Π|O@xu7?W_W8ᱡ-[EP?ccT뜃H#g=<[cWboez;\Fx|P_@Wأcy'jyX1kNm m|9V-Ifbꖞ ܃x]?LϪ Ӈ[,HV?w8YWj"mMJzFy8p%(@zlLFq<=Ӳ|2v8Um\n_>mn-_S{67 ʟνIbv To@H:~vըNyFU\n\>r|Hp#Ps,T=*no]BmȱZgo#_Ľ,ƸpԻ%N#-צ6=<.+!M,M3X׆Uz_9]y>WPUHϋ*yt\~¿}{%nlv?Qbr\=ܦneWh^z&#C0R3XbzIoBȞxx0A|U޹m,igzv(GǑ:MOm.X ?ŝs$=j 6/' QMv\e1{Νgao goZ0}{nbuy p<V [ȏ cKmCЊn7+L|:r|㵣:RwX­G|D97qjD84'j!ymQGʰ0ܮ bw qdX-;ČMoX_T)Rpk1im96_sFғZsJaIopt^[ '/2Xx:<~f"/Jd16=~Zs{ pbb`1yz,c(|z<7SIڅZOdQ)_*3-/`4kDTuz# ӅЏXk݄fmvAv*9V"\OErOvcqHx0ʞG1ɠH#A޳doӼVadǿ\HV@yXvm=MM;cge/x3nd4xr!3<~ty>vL=mg#}vw`C=<֒b)vuc㽵C?csIv!''*>gp86!@›"4gGYov1f[^hO+k?U,6>h;z_)w,cUNrbZx8,=iF_]M:1@߯:bZU{H˹"44ioq]SET}~ZMv]=m{77{ ^?_?>>s/CȖ%[7p"ͫvOIpJGYy;LzUrߩ^ZWs|ڷC8+Ά<᱅ <1@x c <1@x c <1@x c <1)u|ÛCw9\oZ) )7ƫ>0{jv/*zMəx/g8@x߆af<0_o(=SuT1r;e 8x~ 3SGǷ=D*eV@ώTd:X2ƾ7fb O?u|Wd)ͽ=/xWIj$4gsd>HmzoR"#mlXuz9Hp"OUǻ'-й|%<49J>\`ϋ`9XҞM S)Zx ~r=ƱPbb*d [`m'[{Xs=~X aI_7ڊqZ{p`2 }MOml* k%£wAm^! xQãO15Vm~ʰMܳ({Y5PcGh:x{2a׼ۤ[s Aq9{:dcMEanZ5PUnl/?V<:y]qpҬ vqiɝdC 'Z_n-?#z<%m?I 7yt pO 뵿4`#[v.qHz&/?~GVbnmsY6k @ug*' Uxs/ ؛E.4ʆOb`1{c0c\d(8Ӿ)-08DQ/1!J''ey.˯@oJ6=t뎘 ju$6*lY1{޴&;sUluڬ:7}9xf*Zu-2wu^@ѩ{`{V7con@elv{qǝ,-vX,FMMe\.R:y阠`(;U;Oqȧ$mJ{;ȷ);̤IϠ4hٻxlղDNOn憤mWࣿY${3|go|e<n|aSSATmM{2zUүG3ZJb'8TZX sG~Oƣak$Û8GFہM||wu֕?f"^zsgjڴN޲ID޶hpF8o"xRɵp]n(ǃNI=nS48)-[;E彅+}˴录ce5%jp;kl[qHtZU/3w~!Q/'JjztE扂6*HYmf'}.}۸yHzOg%UelB>q7,gыjblf{%۴<>>\m6KOd ٳ$mΙYl~GE\FDxl:5€™v{.k q8JLOթ' gdZvϵZ_$֪ZYj0OLy"sVo=yi ئvm*mdݹsg?r^٢Ec^%yP[Ĺm&5,j7VJdP%2WUCs_nW拾Ckc c"u6,HpRWUC㊖7 Z+rȱxDpi:p8^?_?>>nhd#ӷqWdb-G;n>cY5tzt?b|?vBJy k GΝ[.Ҫ9Z;\_y,61zrd!X>[TʪxL_xUOIɨǒ. U<+ (CqocF.N <1@x c <1@x c <1@x cp^~WzDU_6j=hWqT^d6nOcEs8ƫ]D U>_U1}`xqmpoP \G3m#Q~6 F{k<~7]< |{|+>dbH`eR)hڪrq8;Oj>A@o>=r7Gsw'wUA2{Ks+de8q=<6{ b6s0 k%'N}MPx"Kfm P=kw5%^|J~~#'dǍm/?~\G<M~>Fk|!JsyؖNs!߇o  |m1>^lQccUE#-!RAvd)[k6U~"mb[]D"D8A;kʻxk~JJ \JO<="d\._o^sȗ=~˱G6(&2_v/\EX?MbbjY" x? ;+o:9r*۪4W,DFZu~#D{VE>y:/>kmc >P[ǢW6UNFrUZ axjйE@BQidVXC\8&~xaQe?n4Ӯ4gr-ʹ[NΝ wCFoZ \Ͼe%*iN\HmWyJU`'apFsI.L%VfjĿU\>ҭ?_mlE%弫~>HbƶUG+dXxDVFLc+6^}́V=s5{P-!IWml15d&w.UPV=_tAΝ~&XLO>!Egq96l?OsyȧVm|`?.P@N"cL C[~y_~D1S8~yoN:W`xz|A{8,Nl0sj <1@x c <1@x c <1l_{c=O c3nsuSΓw>N-~~qգrxXL-Ȝ}(~(m^1yI=߻>UG{ -vy?M` a+#FC">k~/l'9x6 y,7&RklS|Ɨ&2nɏ|n[cyy[+͑ZUF~9%HJÈTzLުsg kUW$gmRRu`S~aQgW>Pק_~~~珏n Xتx_&>n%sgZ |匿30^u)Uj$; J'f\ kuYLs$=uasnX,gÃ`'2[\.߾uK5yvX[CzsEyB] [qƦx\}M=m^$2~.'f?(>|}x9XUdg`#/Wg1UdS]= *0plc0>5~?qݷa˿Lkvn᱂_nW;|=Ĵ-57_]վ/.m۷{#EwPLƟn~/b־](㹩}#KlϹjQ$<ǵsY {vRZŕ n#yo~պdz6:O7[jm7n߇73wcx;XBu,WjkwjڒT1GCD1+,e<kj]WRa`?sˏU~Qs9}KX|EVD_<*缳,r)_@8|^zF`X+~X,eAwtqf]^ۺ-_~bj. 'oY%681d"P%6se@ O7o?=\\*Q 68} 3W||(No0s&)( b*Oݎ6>65'F/tnJ{u'S( =mtKujh. Au AprkFj:0o?-)}օqrVO-qIrK'jxmQb77,$=U\FӐNp:ͨ)ٲq!0x}EZB0% cչ{acbOs ^{fĺlj)Cf %ps>;LZ/O\gn?_yȤ߶V}y++}G#5Vgwv;L'^_ j<Ɠ_~ 'XsuJOz(ge!xc8<Y^xntlÈ `ΤՏ5*|UbΕOz?u\x[:&b0a>!^m,-XXkm^"o}.'֥qKykg zHhLW35乼'^NK ;d9gi$֩Qj mlcVeC\6w,;yʥwuH\7ZՃcr{gumwUk)ϋmuYq*[krJ 7JRKlccy7]e[U`%xlp90ڼ&ϏwXΆ5N}|=j0_*oMNiQ>%4V?у}4h)y:,xnd̀ئoWB.o涼_uţ2uR g9,(Ls Sh:}w.:<\^}pY*~w r8.SN|w@!Ss^H3'ާYY;&w29MHy&s=8}'JJtւNVӼ"jʨZUs0XJoY_[->s~]to >|UOGk6^x<7!tncEv:FF0h: `,!4G6KkUTVWe.Vz;Na.UJzZ\D7TYQiU+:X=>% yӮ@Jay+oq52r8h:=UYerWAte&=%{[{$*kmiZ~֓&Oi Dk5"xR%y}Cq95wݴ}p~{\U *#C"{TzV#ȍkg*䝼Z=:j}Ѭ˯L5woJmՅsM-~-y]4ݞ;OxpO_w5ݧBkb]z}2=AqM}Wzk%;N\(~/@D_t5'p/3Xh; ^[yJ/ v =m};lPw%ύ6mb ˻bV kfvO8WW0IDATOb\+ ;Wo?m7ojuӦ&uƦ u|x'_z,6JNfzɫu}Ս"d}txL0fi7F§f^z?c_]`t#aFIɌkfr9Ϫ~jŵinUW*~.W9Unƚ{ #q?cnhSsͽ@-/Nãcv?<=̻sБkg6T/c<=vǰ-lʷ0I\JVVdͯz |l27=uv(0n.YiDӸ|ױiب<8<6c1UQE=jyNK<]q*Dbj.JCzK8Ys,> + 7}8xpH^|9AY$#A2s=UvŦo6ș9/i^ELNkavuתc6}|z~4;9lb#,>7<֪cτ/LN06N'^Zf]0UywC/gT#̭'l-q6}7q]KbT ~‰X9{1AVӳ  T,.Rk4 1.fk8֑aXjcgm7X AC==DE9wRҪkG3= .J~ہN\^ʹUw7"ǪUeqBށR:D9+.USl׊Hcl0=WӭEJ9|9,]9dy{yomA[M=D!˜dәwWp2wGSV wDkgUDe;\[e լlQ6\?O:Y\ZH32^[7~ar= gq *TUzU9/yDU#|eikٺ[(<ʧ5xx]j?{< ?>> %cϣcXl c@l c@l c <1@x c <1@x c <1Dގs( QG_T=yjU=@x sϧ < #VbfQYX'#MZnyA<<Gs{t#idmoSyO&)9 OxuS1 ’tS|qSk+ͮټ=WWy:й @tjQDzW0{U?6/<\%x!AbȑSܪ|ua&^]MUy$Oxv@qD"Kd v5%>$q<L37^LWݿgﶟcӹ\dwu2l\|jzN.XLWٚx_s&#s8عu' ^q&jzd6nVOXy%P0Yߎ5!=_/ދ|BMɩ܌;]j{1xLNbYUky~d&-oJm4_>P8 m* ~ OF߭#DAߜ]Llυ<<~pMpŲ*䙚_^ܾn߉g&k0gY p>/ݎJI?]i_{Rkmlsr0<. `b׌{ *F>nF,.fbm,ԭżh.H{͎ '5M>x}71=}ZZer'oc[!a?v]6ٓ33U>vwDA\?$6WQ Ls2Ǔ}\8Oƹgib;>7kj]Y6eUp"]WoQ&?ۜE|?% 7ZdxXNLd`xOXƼ6k93]._o^3/) K;8SxDVcSZYسNjk\ ,68ƅSͧO勎>Ъ%X8߃!z2 IZ={ެq7"dr=Jov]6sxǼ6}{gq"ެ`%֎]dt:1hBD|h Smߚ9/f [8u)& x6z-9o/N 9^?_?>>q0YkfebS.O]._o^s6u]yc_i7stIME  زIENDB`gxemul-0.6.1/doc/20060218-netbsd-evbarm.png000644 001750 001750 00000023455 13402411501 020141 0ustar00debugdebug000000 000000 PNG  IHDROO<gAMA aPLTEX`d^UMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxm:ΆC3{60PK_[-K IwϜt 8B~-[}vf~Z ~Hs\~yv渂OGi@w!ʱ.Jsyì/NG\C~}5CJW矿>t|CLA|}# G/w z-Ŀ>?O?Q1U%tW$ħl >^-e79 vn&>[ >;?i/oU>}C3$Ν%K^UU/{;<'7YyHAW̾tS$_W]?臱dAH>O<3磟d 1x cڿK'?|?DSm/Ŀɒ$#>Y 4ٙ4]EZ.O9ɲ /]e+iQ=T`7+XvGU!N8Ys!UyOm;\8ͦԎ J ēΙ#TTLѲa$> Vd qgp19!ySu獳wS}Yp3&n ck*nlIZ{PmM+8.Ns'3\ Tys"F> lEҍA*6*-8w{Y/VkycG|z'cr f.G7mycgǧwZƎ'PM2.^uwv n8&/Z~if dęf[8+:B8}%؊0P`o"'*J8}'efZ YWċʷkUxb*ճ|^uKZ{q4u_g7m UǢImtI%twqٟ !H6"*bk@Jp_lm~< [I[ h cJ⛱s!Ζ83 bklK/ y_8ڇGUZM6m&'"Sm_ee&d#S+}3!(q 3![IdB_ afX+q hZ[⫀g0 ġ>8oؒg@F"?EҎZ&U.6:pZ[ Ij-ߙ@wg@{ckifAՉC}8q4 _ۑlHZs69#}G/8FsL_HtNOLk7sT`M.#l%*>/1/ۖ jm UzN%6cJϲJe;x*v1nٙ;Mj )\Uh*5)xNRd6YggGn%dD <zw J{Uvot>_vv_=ʾt2uf%!.F5rUSķT$e^j-uwqĉS'ƺK*y@cs Nc7E\lujǸQzsO0(YƪQSq$u⚤-q ܹ|ǧ"Z$ .$;U:1ZW27TVwcO|\#(#֞d;Lr_x/#qx~{^[*3 2 ¬h^\"g@,6Y ,~g''%kg ġBZ j-ZPkBZ j-ZPkBZ , gw.P{.+A^2r)&IQk|@ဲo!m 4&$`vAW&IQW+4:{u1xZ8E,2H\^EqÄXW:H=Idi NdY_9~uĩyLwѰ+zd@{p/ޛ&-!^]s[IZiޏ;] z{Y] ; iXjm)nKxŏ]-忏醋%Ձ/쒕Ϣ}{]M\.#p{.1Vj^ F㡓'Ih9^+t}nD(Q:֙~ucN.O5^kٻnxxgC$"g(azRXD ysd切4JMu#piW{]7˧fޛu]M7_1^^ j-qUӽ(P+S5:]2(ϡ56?5<;|jqOy JV]|JCl-7zvb t=xY7vneNUîDONni8"%qʫ=f.÷wh6{Vd''IRm&ɭnm85In=qUfc/1N+7rKr{9hq5%4Wų1.^GMt뀸;fnD.O>B}Ӿ1ޗRߑ+5cן(5ĭeD8pkr;9<"?n{8պn:hU{H408^-C&=Nʒ%N .뷗}p~` C    h h h  ~ali='YnyQ*{]ѓr\_,,>$nTiB&1R82E2q哴 EoE|Eߕ.ڽ'ec|;'m k1: ^ψb8^tw&<_I+uwT84\֤cҖmح&YMYZrAqThBC|='mC> $!1n+mYڕkHS's՜*1V%hn}xk l.' ytOA|5'jo%ėn0mWKx >TsCdmd/64fLN|v1wH{i8U?q)fGCgx|%'mE.uS;l5Bπ,Z)[[?v4 0a3Z6g|,JVIh  h h h    Ov8S|N*] =מSxIݦAR󆶃6GIӺ N@|q6cmA5n (!lgEEJO.>շA| l#qWB x΄-8\xplFG`K8qwC-TLr8;;Iv5,@6d`̹S뫤X݃SH V L _|#P&;qb٦[Q)cۻ%Km7},y1/?Aʭ2IMߡT v''Rp:]d3G6|mL:8#R3k_\HB鹼MRjSVbWkOcV6|LzT`$'h8˰Bcwb|qq u|$k qZJUfXNGz}}]6$n!]bzCbofZj Yҭ?kx|s+G[';]qoanCdB0jkLL~aUbLiсT?":mfΐ$Acc;4F뎯rx*#w#J Tcj-8qF+8S1h*h 888G'nA_eln'zJ"c\H[jiXsuqϫAR *c;3Ʃy%oz='1~; BŪ`c h  lT~N,o;&[{¿?EI26Oᚲ|f;3oJSY2)eA=;n7.҂[c!gGϞO\; yE(KpW^epusU͖qp]X1$u=_i[| }ukWJ%i*SXϰ.)񭽸~T/$#c)PSvEdkWW`èIڐja%n]˺1֎aW2,͝sc/Z%V6V"q4M'oHp[R%Տ Ks&_YC|}/UXѳ*_~)`.'w\H<[^vTv{_7,1qnM)w~Ct)q+76g'Nc0szĩϰ^dw&Wɍt{Syp/.-+qfm4-?C;k186{΀,qͱ3?!s.YsMW*b؜>.7JL`/ ro>ϒ8ֶousdiE(x3,d߫3DgwUMiY5B| =6ů FbSa=:on`Uٖ[$6mZ˦8ur4&M;nPq(4>f&lJ zaͩu>fe6ݕ]vFmdT33N~εk\`JGU,jJjزͷ 0IkB/DԢĕgF{4AdÚ<')l̢o [ӰoRJђHU+B;dܷ%ͼ)>/KH!Y){/[DĿ`}~U/#mHRsQXEWoqQ0WO\T%)']7vJƊS.P&0x9y14&Nbw9ƠN<}4hXuEiȬė K!,hq${N^J B.AJ4&.u0g/ Fc%]츄.UÎ6jVX?ml㫠ٍ|jx%] ?x {G>q^I]J*ӗ%9V TgM A{QIDATYUie5$qs\vƛ#,^0~.⣢4=(SZI3AM8D2lj\g&1J.u^V)"5r|'.{-EAS1n9%Yfh00qM=ȱ~rysf+pUK3r@8!"@E/_< ^Q"nָw{n?V2[5B g&^ұVrg&cBjg>9鬊6;F ^Y87cc\ނ'2&n5׻E:*._Qfdvܺ?]6KjAwyb!z.i[;>IFyk{"[t"O4ndbT_Tʨ)ӝC_e0j ~9_Ť=?~ZQ N2NϬd8ChQkSZU:u>أFb Z/2JFt*qkOj-\+|7Gp4q%_%&C['.ˈF2LTfL%ζX.%!j׏s~9-BNv)dMVnmRѲR?W;L{Cb*{3da^>{=|Rc_(6#Fcs VsSO;۾?i yڝ-cNTɝȑN|?ƃV'C;cޘ4~8N<Վs&gdI39iG JoLbJcy2f@۔Wq3 SsRdMp%ήƧ&(:WT^Hq/h jm;GA.kVpW tvp%KvrDuU/ۭ޽ qndZVq*+=ZWYSXΔu,y؆RIQ}+jV*ZrtZqU,qW, 2FϼkUuc`ָKW+Z8MMUr"Y }^ԏH[mZurMDꝓ 5gtҳj{s/gǣZk.0<l5VECnq?Il *Z˦2i թ^;9_SK}@*GzHDX&OY@;q{?D5Glm}FSs۟O@va@|G>nRJ=%ڃsZ\HŴP(lbh^|l٧MiUkI_˯DI. fR 5rzj-5vTUu[EΨ>TJ,+_,d[Ϩ>Tm u7O6?Pvz7'/ɮq մ[tqVj:N5J!d-'\n1.XBSkY5?N%N nN}>Y.7Zeh%ts$Ac`U0@3 qqkE;3q'>#_c^ݯ9c[CީjtIME -IIENDB`gxemul-0.6.1/doc/20060814-netbsd-algor-3.0.1.png000644 001750 001750 00000036403 13402411501 020425 0ustar00debugdebug000000 000000 PNG  IHDR2]gAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxK:myw@sni5) /NNFR6W,@ϲ=f\-No/ϟ : |3c7۸_z|1=.Bl@w_w1IVPc.yEqu1߃ډO7~G+(yԿ^ev3f!cj8styfo I<}ɟT̡ ߹ԃ ~I_cq B} ߟ4Yjd-gxX$,!=3YY]$;ft$]?.koy<-&!OY<~YIl`UɈW$,~Ϗ: (!".2O656 ~ 9 )e5Hmܿ??~ʟ|=Tm)c9[ok1koF|2r8[YDI7,{W~~=ϒ#5u/q|WSg9Y08ҩZOr#N-_~-0-A{qeD9 G+:ra`9S0v)s\;@PIU+0n2?7l0A?,(̬F3@ ` w !(}*#A5}e$h geNrW)&|`$ܓ2*q@-4] w5& [(YK$^c@ ECeK@J.$iKuKf7!ZgWќXO?u~lKv+h5FSuuͥlUF>N%"%huDo/~[@ZCs-z-Iӊdwc~[oZТ}%Y`{is^TS`=ϯ)T5_Je=5Sf8ti%rsp-}flO|Cc^`6?eHf%yn{92u_g(]圏b{Uú߲˯lg_m=F}_ UmDU}+)>ܤ~/:Ikjj#lz`isOk<ޑ2oi*¼\۶mG΍QSZ;P.˺ziiߥˀ"\8-U'y`RfVXB c-)=3X61jXnTx jƗWyL<#įAәyܖ2d&z+^1Q2*HWj&xO Do@cv_dιZz]fF{&V^pkGcD/%Ku7a>+^| p e8S0;ĊPf3t*@0@v f8g9.meNwø`^LRfW^9| rQO Ei5m(s ^3j],'3mYNSf2kL fVrEg .s\;P3#?2S[0#3 PT>Q0 fRf0 |/eN7rIm-l\a%eNIi.fCwe.3mxs>yU'fo.=Ii.sa,"!Np`vPf3t*@0@v flw0 2{Nuu^@4Q3u7#k\5 @i15]ՇusV_f?uɵآWV,1tV1yx ;9 VɥiN˅ժ3 2"TXfTI:ASEܠ4u]"'ز"2$Jzy;96 i|T cT cHkDYY>k=x=9̈R,s1-mZqR'߫8BJ*CIz\;oO$uiX֏KjVUP/oIGmbO sUW$nHpP5&gԥSRRaUy>2qFB6ɊE-izJKMI\Xu1siuVl!f}(öJbb J'vljh|Q7O6kB%GtҌ2̺gͫ9f&F&/Չ쥮:=;_/vZ9~ n L,H/Ku+M$l_̹,-ɞSZ|ΨUXZ oS ]-~@K1; ZYeN|zշ31[/|`2ޗ 1`@ P( P( P(eP(H2UF G frD.!@;uƘ*]Hخ%C7-wa^bds@H'^?~>2U,{$]5ТD@#tWHPuui,Ԙdϙ#V2>b%)cŲ, " sv1e`TG d (kssI彪4nnQ6S(%ӴJ^ek݃t,MG1{Y.H -*Mr~@RXH린qr~pc`[c3$~irDug66 2&V3erlt Td ^G77Gm.vZnsk6Ԗ [@:UGښQlU9 .A'՗D'_;'̘3!vB)JCiM n ,V78ߝ寮3eYʜCsy]N딏7:Y例w͐yAزCrELy4ҳr>+Y C(s?0/"^س=Z9Pߝ.c}줵ˍ}}iWr`;?V"v;OݘlYeT;{< @=#w8KA[:[fw~Rk<,orOtiYtH>KK6]r[EUv=)PuK9RnA7 e$숍R wkꤕwR])vλz^=uj{i{*so?ZRVZUYv a5#צac=uް>2',̛b}" PGʕ&wM{}5I{.sfzh8U:߳'oYUEJJ;BiZ3O^KZ@bO2fž.Ko{Z;`nl]e |IH eV _$5#N;H+`,@ ^%1br߉JGdOGfůeL;H;dZi5V{v]N;A Uiǽt >m출a浲 /[*#zOQXiEvWAmz#SzǴS:˅9۵q5Aui^?.WѴyċM_i,iQ垮4,ѓkh9n[؆ꋀm@, 0hI_)wԫ@5/W\-M#rV} xGeyƫlLUWeUt=ϦCJ]vg{Wx_𔴤ٕ{e\{e-O^+ '2+3k%!!Yge~et<w7.fF ?lfo`a2IFPY:Ү}ދ@]E"PVۂX]\Gm03>f!м*! $UگA88Z^$($źL:KHw2V/'Ki[_Vk{QX,KVИΧL)Nbpç%N#v=VIP" &/ v.eUזca٠r_MJ=|b<'woL4F'*ߟ:$h^xNG:'i˷NyLZwE*b ~ھ D\JcG+}8^csvy爬2gQ&0.r;r{g&i./ON/1ԋBGY<7:2V(نd]î t߶W m.MB ]^:]׬:>]th\*^EdD3 `Z0;Tv#~!-ӎ:P.x*sQ h?!gZ e/&[yu]k*u ;n*w12=;܏^^y u C&Ve-; W\D>Xo"AEt8K;y}O7YxYP[7ϓCy`)dҎoskt7Y[/MQ;R[o46̴VØu|n4E/-;f\lzF߹V=d-zH#٩rI)5e )xr5Cj={Bס7&r MvԹrr]ƌQzu5I7&i_ћi]Ҏϗ ^Y]ZǣWוi3eQ&=x(L|qi,qdld `2RYNs'Il11K1:] g~GDmXeq_Ǟ:aNAɁsq"Չy.!un/\-{z};wRf,R^%uۧ),~biR?iZ6H u6Kikec޳BZLr)fD~-k[5KSsI<)P|@dUj}$R5t 2Zc^=X#D3V}e?{sN4;j&;uWߍɲuCi΃ڵ2Ƞ¾Cbɥm5ˈ]6kxԙc2Oe7xff|^z*iR/mNVK_CJfsyw\eѻ;m 1.HkX34#t%}Y9k>R~6˘ 3oOz%iZw*~ }~VVvR Yβnv:I}գTmz^CݨF08@ xɎهN/6>eKS3 P( P(eP(e2(eT$NunȂq'NnŲo.#쭥HY_^b=+tr)lntE<JG$M T!5Fy?rf=W3[2LA2͸O8~#^,:$ls7ح,SA $"^`\0K= k ٫8HWL^ 4H7)c )bQՁދ2sJu:(B _~C1?Zp2ܸ䪳ө6 )!Dhcjv©[U d>u mhGgD^LKnioc~$D^Ufv1K4T1]KNcgtgBIDAT:V;Ib[K~y;ÔHOVrL[u#D{c'^oh} цe2_:?8$ͻABy-R7="raYRmX- eqGcSd-: ?162GMK瑹ar]aƑ1cޯQ޷V:%`h-k~Z:!l5"^szXFi~2~.u${ i\N##՘̬$5 k} .@юQSn'5ngW 4Msbd:)XEtS aIȜ,.n٤Kuw"M(ӓ^wF7%↫U]'S!,U4]fޜ} .F*;U3dYZ/N]e e\bM$)e:MfKOy朖+OƀS)ծԎ5j2.Q|$gYVE;.IPFQ\asR"_yL_ dMޔ2*ӘV,vN;Mf:|oQҙLc"ӧQXN&t e2@>C_׎ī1lv"/CŶή|dXCw-2kl$d=QlrV#sC;]43TᲡKTsYҚ&eW bwiZfe:ߍ잞Bp@^OzùV)Zi$"^}lF,`c1]lM݌>/f.vA6zû2Vڑ\3(((DJͮAq<.YC.`N:螖Т>:gz9rbX2 VK۩)>=.rИ>X t*w;[yް< #%?A6K?[P\+j¨cd&295Ԭ1;\z#uwRʾOwBq_k>cW&ayQLYj35! '6PE槻{!L؊=1W}n&g(l\ޯnj53.2@ PwÏt^Y1hlkBK |vCc-O:{l=7qv}{cc:\>N]ICIWyUSFE8\5>Ddi%{k0 *(Yviop5ֹo>UALʸXιٽ Jsk_9[1Oowᴾ};3S/+[iٚi={aPȍ,K_U\[zyFbǬ4^K+jw۶>gDwlf]7LYK?8E4ٵ13ֲ}zmѯ V{׃t|L;T^yyU f)]ǮW_727ܔg/Yn;hPefٟT:1ʲ/8ឝ9/y-jn]'CpIp̾f0>H͑ɭC[1s//[d^9S)^=)_mo% }Z*^i\H,Ǜ>XKυ|2Z-w/ $ub|@/5M[vbZ;?}ZǴ|,i.Mޖ2f3eRF~Fڏ9[𾵻m]5hz~K;>dq]a(=նs`G4yo-Wef}n瀗.}ZP~#іv|ixǽ=Osxy e9nsWV1gۢke_fy'׎Xeftg[}lwYǜ[}ZXv߭>cm6w 5Fy}!6ԙv|`̵3 Em =a>/\gޣB0e2+DHU( (#܈52%>n`ŔA`22 ex% Cf2Xe2@ P(22Nl@0p `0@ٱL#-<}@si <.Iһk\0K\IP]3i͒V\E5ܛ2Z i^iV0Xj,KI*C8Ī^ΠTL( ,z9F'b_[Yꭻ^8*c"2Z\]VC0?͢g?(OXkZQn^q;$5 iq{Qce7pҫ԰Yn2pݒN4Oii077ΨFHb222/xi`f~3U^3N7,iVLp{hն~MwUؘ֪)+~ٙ]_g4X=pДdq'bI1ZXi[%O=C߲G+E,YF⥌Vi:UNJיe9Hëޡ*%i/j<˾3rs:Tj;4؎og9_ =]lhxXjNWJ!M!PJTT[6_f{՚3[g{ϩ3tT/;w7,mZpv-KKrJS;PnZXމVf|&ԠEhI>r4G =3^Ɩh[*ӱ=6- n@W>ei.zeGՉA<Zl4mJ솸uϘzjm4JOkV`L"k^*FG0Xٷ^fܞE[*k)]=ѲF7r;\7u (G:O4*?zE|.0>W3f@_Xe2X0k`:|mR}5OOL<)^{>cϞ_ɰi  kϛ7:`= 5c~q EqI.{88;jucGp챝P;CES4#j8hO3 JV[P_r82öq'Ke`4 n1gwk~UZˇ gj;&f-4wUE# j g#kjj6so(:kٓk3xXMM5Jk0X".xHr Y_$1ұ֯mQ2Ǿ$glѶ-#&)3ao~&R2%9k0(NԲ3 ;MiŪ`M&E!Iơ`/d׵(57[4G_z"{}u.32YZkPzIB`}GWr.Rn=4̼,ZiK?QɎh4sa߅Rc,@j 4(ڬimA=I}n>.;^fow-f!',X˴mV"mܗG[>{Rjڽ&,^l, fʋ)@Z]t mY䟵LL--]i^.RXr麤UɟK/z*mDr옹oz(j.3l?doZk?ŀ,kX,&j$h~lTeN6l[ًoI۬z}ՠw^ tW e8c Xe2|`7OzQdgAVk[jS ]5:p.TO: ${ZSi7P6/&F̭C|5eeŞس>Vb[oۊIx xh?Ze@>>MjlvVtRƣɞ>m7l;?1l~Cw (jMXo-w}`ŶEk(aݬ->^BZZݢ|.,޳g˼_ݝa27S@Ip.Sɨw 2o^`lb+7ܣEAMZߤyk%s騈Ox1dQB(as~զq&gŏ&왴臭'ܨٲ tFyum VkN)!f[왪l?8EKI6ZJ)+T){Mz7)c ȱ9ۘ,h8|&Ҭs>m EeIB#-TW tOǛ* Ȅ-dmŀkSo-tmhǍ߀.n'7G.WngwN3 n騧ꬷ.>[{>{>#{μ;SأGOx}^~݃O9>o?c=*7|L.{`%0w7oߦ;]')PUrȌ/Z@s#=[9?EGMLjtx8HO8`)Әs|.9^nSԤ3x~t?$F ΖӨUySLX̅8̨ !$汚k+YØf@&E՚UD%`! R¾r%Dլ^^N5=۹ђMjOסt3-lgKڶpum^o ms+M:ЍA BZnrvzծxK^rMkz?9Fٖͯ~;o c*3PU/'Laԟk oP=ͣү#oWb|V4^dU±7nlaέ(P2oD!@yJժDβ;[^O"P^ y7,e[)y4I>3ْOhHc&i+Ro׍Vm8y|QȊehr1xRbHcؔ^7)f+Lj8AyO'xnԓpI8DwrG{6IhI7ru(-%Qm'hpYOIJHxIEdwx4 :imWi B9FyN48Y LyF}YʩS/kIa9֙_^hlD?tY5Ht$[yBV㓇I8giaXRJ5Hƞ( u`ۧw5%QUYȅ6U loO% :Mqxyi)ZhzH xq& f05)Lg)ZR͘&q0Z][uIԴ٣ZF\fh@x9Gz%TkYIc*IUɟi Ty)ןHuUf W@SCvݘgCI蹚zEh5s6W#p 稸Vz՜e媰:%ze$ƥ:E[šz=ڬPbZZ~ך܊Fڭ9:}Z<㚮8ڮ8*Z :~ZʝםXj]:l7Uհe8 {!klŧJYW)(%W?ٚoP4MJApǔw& ]k瓳hO'OqwUj8SCvسKowE(cbJW݇ tR8vVlLX{شƴg]Tl+Y˴ktvKOKLI@w7L\x8LYĐh~DM{ůJ| {ḓ|qj66Im\|a59 Yr<,(8}u~äkLñܒ*&u:LûkJ\ +떛|#ɥq YLm۟1'CkǨ2HQ=^Ƽɳk¼\̈ ǼOȠiDy^(JG,i X]ɳGR;e % }s\zh] ؗTsvjΈ΀꘍JLF/u,TȬtE;؉]e4} ͦ>hjcǹ`4[T \Eͳ@ [^Tm⨡>çF+AX 8(-H+K$ 8YMO@9+pu(ۻ6 HcIARںy-J_ #xam),HL͡H&-ъ 茨xZ}ĈbӅbxP]cׁˆˈqJNhMqX!kэ]= #7d':;%[W͕νҟTGs l ެ]̱̂^T]ȗά ԮˆKxՙz-ĎmxظՔz+|f{n>d_ .k!.̂}'L.0ճXGMe+NX߼L4 t"};lGQ]Ze‚ KB9o,=ł f=1Z3ʁ 睴ޤ| ܧЩӃ. X^KQSN7sa뵽#ؽ`g*eB,ڦ-Mzє={Վkҿwe@]Mu8Ўzݥk/sGk餆mݥ-|ME //n&݄0s<;:_Þ o׎TX몗Q~Yʯi}xa>ou=4_n;n;W҆,6r{?HN)4~߿SS'|}von\mԙǛ/{ m|LŜw (@tIW'h} 9e?۹7G.rFQwi9朾􍎘}>}\oYiM%Ǔߑ+W. ܠ-iSzFF Zښp,tmx|pA`yL.?PɫTX'H:r&o n_%:3:6bs|FHJLOf pdz#W,ymR+txv!_fn`ixr8N)iw9pPjQ4 $0ݑآ1K{ D@\ȰÇ#3h]93jȱcCMzIɓ(1\ ˗0cʜ de08sSe%i6۸8GU$3KKD_]M_6V -DJUj^͍ZP=y;bb)3v6. M%봊:dz˞`bKeKewH1nf{՘)d= R&} d3N}ߎ.ڿg5;nS#]TqK]{ ʘq^Mk}C749;{_2*W\,G]ut^Sw-6zMf$X&tM2X0t>ebEXތju,q!v#_Y!7 g&SP`գQ)܉yś_}t`7m! ye:lzg*4NV$Y:^ 07pؤl~Zmhqvw1hhʹߋI*`.J韎)vm,&mMYZnu*kz)tr없^2{j*5V#΂[bZ(#jvT覵ʝ:!s|waLloޥ> ]Flg<ں,Ct,B$b,.,4s87@sDm4JCL;tPG-5 iZg8b+D,4mZl%%ܑYDxh]*Q£Iyjd652ܡNDh.HWLZZ4bN4UEE$Zb"I%i}ߍBT$ȗ*8Z1LFT;Q*zhU#3=%V\lୂ4I&rMt!zՑl9T)Rd4Nwh)VUP#!+Ɯ杈c"w&>)x2 _ܔ#.IEhKgfX?u~[f!9B.т!t5AZ&C06}8Tv0Hp-LEHFNS 0lM]R9HRJH.6Īj̴urFTWUeg]Wnd~'U42s'K+Lܪu|`+ a`d#Zֱfz֯h+њq=jպVo}lVmnǖ6kpwi=rN>VU0Jo.`(TAYm0z[[G*V"|2,w-Ck!.drɢlpրoFG*XgL[Dx(6چNyL'fH8aM~g<({^6|7a4$vV]aKy>-ˆz'qy!ge/Po(pl3GzF l3z(dLc1 `ev*Q8eiHo~ȅK(Zn%҄JkoƤD8Աvv,s"qg '7rd%G;1tR|7r %ŗr+$>ga#f}|w@/'bȊsvgXk'xicgu,BtC([US܈t؏1 VX\WwXN(wjCw#3WhpVyǎ9Ð!3 9W5m)Ʉ~؎UqU:ɒ=|!@rԖqG%Nw 77Dt|X}n@*74r?BuGHYK7v}c~;}gVdži@J&Tb$R#oawY%~eP\m]Un$P4ml5I8=RH>؃PۖHfWh)8%-v PVo HM(F;K—j(msؙ9svHIjJeoIhKFyWG(dLYY֝ilȹ8(tqsInrnpA{7vFd5h ߇ɕyP5> 3@rT&x5TrHYFSk׸ψrlq٣7[q-8R= 3aw>:!3ӟuyuthZ(8[j|{ڧK@1Z?S\YǥSœ:wGZW%w9IU4(&x9w ]x h7r> wZ`(y=Ugevb@7c}v32sƋƔκAF,VzJuTqtp&N Q$|#C5cZMq( Vhٗhn)LEwفx|7GtNcd͙֢)n /sBhbǮ hވD| UYKaJ<$ p eهEMblj8t4y;i@n;hI&d=f-742TEꘝ*m8ʩmLN'jekL y_D$A+:3qhEkYs?xigi+@EI};yf{Wo0)r}qGa׺xvPyH`$5ԔJP#-QaװR[;Xӽժ*Dg~*C-Hky[k1k9t`:NwvW1VŚ7y+y6yx˾jU#m^‡zz؁@%y%|JI-BSZR:5n8gTJJ922i.D SLKhP4dH!O 6{$K֡\&j;W`$jk<m\Z̦Hxt]*>hV=wYI|żȔMAC]*m(J ҷ^0,[Z("{ )̝ƻc\%ۈfr;-{kj,Nc60c |pA,]xBls RhO?ܖ, =] }  m=< })6[ =$}E(Ҹ`,=.24]}8-:>@=D-п@G\IYuM}\Om:a1?Z*ʲXHWF(P;GR=ֿe2+Dn}[p-GOngMy=\{OeXk|]MS(گ}7<7cYܺXّeԦڬچ۲]}+4g80т|ziՍzLXQ㦒L=8 ݾZ֧Y/^iMZCLqϭSSvJ ZݏSi,[jGd?z|ہ;Tzw=9}m (j .vyLִ|d O/3!?8%[LL`*=,VUYkg|`n]N6bU[Nt.z. Y= ~YXoZ?UYj Oy)ߛYշ8ڼ7P[{xƖ=/}5I7x.LeS f ;Nx Ǖ=s3 ,n@׻.NF.ǽl/˳P\!}iԻ]GNipr?]v?xcV(_TD|/D#ќ__›cN@rN,:N+ߺ,jƪB$rŬܙo6fHb׉+dFrw]1䙿̍L.bMXӍ'6DH&\k'ʟU-Dܦ<1" :tl &r_H_pz(%Z5[bȤrl:ШtJZج ,`i5.z'#Q'.UtK=ۅHTڮo/#~m[1` ?jEl߿U `kd^̸wOa4˘3,SkSLi(XzװIf׺u۸^WuNq,u))_μУKNسkνËO3){ƾ{q˟OϿ(h&BGVhfv 7~TΉ(b=&0(4h8<@)DiHި^dPF)TViXf\sޘdihl馛b)tix|j;gxemul-0.6.1/doc/debian-15.png000644 001750 001750 00000027541 13402411501 016155 0ustar00debugdebug000000 000000 PNG  IHDR WgAMA aPLTE^ffq>q8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IDATxu:Ec8''|Tp 7DR$$K8Wݦhaa ckϿ4k_8 08ؒw~d}-y0o_:S8 )ϬW1x2~d ??>.}~__^_~~_|Ž,ӿiiEWsY7y ^K}_ 鳁CS Wϯtiw ?1 =6o` Zȟ\-VP}keUTkQ_wϯ鿏9]a"z/> rp, ҷ+W0ry=tX\=3:b_ erV+$ӻ*Rq}W㣾B\@05}1چʫT|Nw0x8Š\ ~Fbl1؈>2o MmFL =`1s]o8}ck ^y1Thgh߷)L54s?b>=(4LbC`*\_id) _:aD`An 1Ȼ & 7&X&..\MgZ\1=>00  0@`  0@`  0@`  0@?H^N?|#S/./~a~e>ss`p-\"Mpm(3,_10E<+^D2a˛àsRoZOErw)ZOI$`\4rηp&=lx(* $VE +F 0oyض J,yZp5hW;1XE0?,w^j,5 na*e; X1`uћkD04yÏl NLtqi!:7 6 o"d%-08 cYqX46:EmNȁSa!% y ·A7À0mlD@h&6u  0@`>{޸K¹"9y>>S[PRXw?-TQY{"gv+``3K^B>oJ4[Lۢr=ta:.k-n`Kd61 zhVi5 T^&r F 2f1H zF"^{1nBXAY%aP2— WJ^]P'z[R(15@ Ϗ07ߠ:]@?\+gy>_azaj-1Iyk 2"^9M{W.6~ÄP [c=ȟ[\dXK/CO[t1&k0åoB6 ~r{ Rs-}nAu,h?Glv [S̚9â ~zC۔Ss;.a6X@F 9̗[m^mAF#os? 3UmC@GAg{2Y{6/``;yOo:vHBvlWo/M;mM0C2А27aPz,>xSnΪ=|2i A?`[}9`0y !b~2È  0@`  0@`)byjkRjzzЃ{L<P c w``V?3+QCc( [-뿓bp]mq{ gk"_@)@Y#&6$C̙NDqx^!T]K#b(l'#C {acLW#b,; R1DZiJ\r0Y^v]`/xJcՃT,GW0l8Yj*EhCak<DW֊XozurM:>Efǝ .ص$%- E o'1$h1ުZlSf@:>c0U q`Pc`?xF0Wap&b6X`m `:FG;iK1k6]ղ0'a; em[α)%URJ %K1K,C__KLƷ6x[ki;&.6\ٞB2nQ> IEjcP->Hgc:3~}>{'``_[cKQOm`mFwK̆3\f֑@ׯ,o:}Wsn  \/93sRwf P{/HHś{άYYo?{m { {grE1CWH~(ذ:~Dz<#}U ROGUg&rHl7?Pؽ&19Lپ[ _z=;{5TA08`+ j7T+9Lqc4=D.JkLb@۠2l0p. jca %Bi .-nWcP:C:0SuSC96td$,@_AKꃒ3}z?K`?sW4/Lu: ~bpD 0@`ޣ$vF1:ܬ?{o;~ٷNYlr^rc~ [C~(r"[=^w 5s{ i^$cdb5bIǩ i<eTR_jE;~ࡠ#&D@,:g=z0ެqJz ~ 2u d=~%t[}ʜl&wN͢^`4K]XLɩbQv/c <ͻAgV.. Ovr ^3a1 WUzJd6aqS(k:fAگMDW]5?zD_~r|2;0H<7}GMipZ (EtO   0@`  0@` /@~1n@#R,˿i].HN*K2K^dM/S:nU`)__>/Pw0T31 $T6鿼%a;JkR4ڗޮ,lj ]>\axHAC\@j Z&]` r~_V(y}re` >UH,6OB>;A/+kw AY b+pX o -A#z Ut<ɒ?RCN9FA^Sk1A!4r)W`G Xf=b, \/kz^~IgYumPJ`ϝc aŠ+yS8˚^gC/v w;üc |APZ6L vc>p605 ymm3 gY鑂Aa?&֙ᒾ42`PY]XaNνB ֽ5lBfY0֒) %ÚL(yRS Ik#)֖ތeHHM܅\mּ  f0G̝y_x؇^ ڗ`p4 4H_YφՓ Vς7yo,(sΕ9y LX󈉡!zc팠ɋcmqo`pD`SL]\zt^K~ sLf#dRɗXXxlW1NkmsLq}ZIڻK1X(_!mlc |Kޑ &eqS^Nc2r F5ˀ@#؀K> /df{SNFrl. $-Uu[3jg گ~07ߠq(#B.~n~(yW}9r [=L1GK"^l7\Ι%Ӵ}IWLz*?Ts?!c%M0h>ƾ!lmp-դkwHRin*~ 1\y/*û1COlv.o- #M~aSs˹&&`A0﷽6%܎AX 0{-V۠Šy cOoh1H oU{-K* oyW-sfmP_p-EUKv*׻Pu4!n>R%vŇ49찌m!#oz#;J8cvN2LT|ޜO= p?!u^;gLv+/4`?;xg4`k|vUlo03|S :ż88[)tLbjBpp 6Sys6tX 6S0)[{`6SC8N۠*o`!Bm DܚOν}To0n  0@`fzai֣A0hgگ`/93qY |EnUлJj  *մZԬ,Fg@ڀ0xM08'@ Bo00@`vh;!mg̙\}`W$~`mN(ϋF|}%yl1X̝$3`0,`( b0{+3UU}M|Y>]EEq 7@``  0@3 ~0o ~0o ~~7  ;MS58:1?oP{}x0xn;y;S ]} oLӄ5:n=o&?mk17pT7v+nl 7a`ao`[~ض =o D7gVOڇ `pϸ00@`ap AkJϝp>8~jXIga*oPn 7 J6ap$oPY26`p$o`֮v`p o*"r]*"Qo0Ǡ]47І^m7@``  0@3 d=O% Jߵɧ; N̶ F9 ryi|^Z0߉A> v 4là7m c z۽^AoP tՒ^[.kmesa z= nNkK?Ι)|Nq0h.;] v |4R)1szO,ሑY-=%ߠ`Dsv LOaAvUZ$=ylsb SRo c``l07bPc' |ȭc4|$ߠ3~1P?&VH\n`2  0@`d7xo^| S)@Cc}zt| v ^ySGb0 .Am0ͧ fUto:@17)E| b=pdy;176:XNaop'Hh f?O6Z ƛ{?+B?sa%z w 00 3697h#)!PS,l1ќG z ?+- Ao0M:TA{ނ2_/F| } J.F0 $M,-7p+ ʶ8bQSȃ6 C 7pyb[ l>:As)g;A',7p+ cN) AO n9*9]~:~m ɡ`;m{5 d(ͧPw- FAje?z l> ;Bs!S7@``  0@3 _g/G v3Ř5ɱ6ػ= ScdTt(01 )X dЃ00UvcPb>aF'iL{,B`Am+| zXT*Xn(ZO=, (e,z rR-L &mnGӣ)xn, =O!#BR"悮kOA1% ځAol1ع}ji"AX y80ȭu HADa loP_Zkbئ*=MA]:}%zV(B%꽳#5ɤkJj&R;  yQ i̙ekwa.z) |`s1 oWεY\IDATl>+k}yRIkA<G`o>gSz EX x,܅| n|d0ؔON oO~{ `p/)q jKjMĽz|ȧ`d߃" hOS@I6Sه`l.))%zpo>\^fM.7~2Bo_erO>y0` loSȧ0'5{M;G  o .-Bo`k>kJC2|;`[7*V /Sh\Lq boP@N4,?@s9 `0ft#>0YxF)0li" y8%Ɓ۟OJ͵xh7@``  0@3 7H=;~}xaYhm$A*{, YQ o ! Xߠة()`s0E ZYWW)9F /o rm0N0Yh'E ZAASenACl7h' :>xX *A>0cSOo 0@`0M~:o+lҩ0Xk7H69 Oa2jL ~oPf.9*A^ Y <) m[LΓLaF]mY r &Z< &X1xV|T\~8P2kX =r<g7Hߠ)kKd\ 7²`= \KU450xo2Z9L06 %y|J3ێm͌!0  7pmpY`< ^ߠ$Ӑ`p/o%A@d~{0U~- {\uQ ~`C|\3H9?<7 `omae AHAy?~o%}l( {z XtN  0@`g'i`γoT>*Amy܈ߠ3Ą3q~|ݏAOos~}~FPh777Dc* r}~/mWja o%^A=3O u(E ߠLh61A=: `A zMD0x([z16i"jj76nAgA=`Hq?tZ 0@`< | Knljoz=U bO 1oP 5h)l8E Ș^fyM fJ bћV `/h.)C}D{1. oC_5q AASl8&@|xz|wh۸00@`apPA2 7]=+:{a O&I{udr!EHIn#»`~1 ¯`o|S a;]e| $T`0ߠZl| 6DP 5/ͧ`1ph)<- * G`5"̧ 3AZI2BَQMc 0@`0<;~'oW``wcb07byߠ4`!}Uv C~Wxyxarn v +Me$AiRVНl܃%΂` n b]4xߠN48n  0@`f(o=oPV.st|N!>Tobx.=6-_uev8;1v zVk^:Ǘ./ oPUU~~A7aE$\,FOW lym<.)Cp$ nSM7AAmELeSM>_}M?}ޓrRmp;B?^-aݶ&Kcx;Q&Hz-x| 3sxa{o`+A; rri+jI;Zmp+<` JmViAI\J>ŶA7X0 :Xw Ŗ%o1x8A O) 7p;7ok졬7_p6JT@5x 5  0@o]ć`hG/f@g\TUAH? QOk 2z.y̎S'iJ0Eƀ0a js4S.sU 08͸6 0@`  0@``  0@`  0@`  0@`  0@`  0@`  0@`  0@`  0@`  0@`  0@`  0@`  0@`  0@`  0@`  0@`  0@`  0@`  0@` a " N^jc&"  0@`  0@s+bϿ^AH >Yǖ<@sD%lnQtIME3:J˕!IENDB`gxemul-0.6.1/doc/20140803-serial-upload-slave-small.png000644 001750 001750 00000134273 13402411501 022367 0ustar00debugdebug000000 000000 PNG  IHDRahgAMA%`M=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATxyWދ3<.ȪbYI(]-i/V FO1g⸄ "t04pLbrLT7Z>t}JRЁ~󰘚}z> 0go/6o,7Qk?i(: @F>A!D{^0 #(|ӻG-ʕ\仮(#fnHă('N7-(.'z(p=L0cǶjZt B(Jb C1 đ$Ap<:(zQ3]Mb٬LM$ȒdY& H(F(8?3==0|N5$kq4v2,cL͞>`zC03y !?G_!D)I/Cޞ,Ycg??y^h{zˋKyhnn6H~~rf}濼{:9_~xm S%`jjWDy2GdrkAu=׫jiv݌JT?<8nvfś7oNjZj4ͮesY0X]]oB0(|D%T{6ND6K30,̡p][V=Scq8 *9^7BlsLg{f!pc+m!0h!IJm,cn2i14MS4E3DpaX9\0!/DQR<GQYGR4O~ӂ1tt*0okzcEm1M;1 ?BA|gyM8/Jf$F_( Q9L3z3??_[]}C( |0D@"7T&=Q^*\۲bn02(&&JRoTݞ(kZ׶򪚭e2i H&=]/rC\f8ڎ3]ye7jʭ[hK 03pQ;'JﻆAE9Dm%9&HRY˗*e:9nL2a~A4;BӻJ x2m%%ApDĒ@G¾;>B۪%%2c()nP$QL E!<}EP5e'hRr#EQ(D> JEX"~B>i{n*8n|DBXId%IEqDIeA(1ye MGͨ8mϟ}A&ڎ#"5QEv||(ɒ")  H'c+S9Y%zDsg D---~u? 33wD?wqD*'r=s-*rfK%Z78kZV.״seDBP9)c?rhб gp0DIGR.WbdL$Ym[)B{D,(=VI|F4*B>֒$\,dI(-oB(ψxA=#/'c)palFͦU5W+mLNMNOO UQ1TeL: N$IDR#R(0Zyn,U$wd BPԪLBO>uxX?v=EI\>ul>%fN,0(tIpܹgikgƉD!ƞ)JL|4Qe QHēKKDRZR'&j0@D%(AY'& Tss{R"hAkմx9^~|㇞k32 ,RdeRI۶#?HN#qf'_ڎz^T:<<Si <:6He$I6zx*:zZmwgx"kz<-bt880tvsIEoZdv\sKףdsk;.sfKvt*帶L~owa\u{D"ɭ[c@l x nܸ*y[oi_|ETUukkKŵ(Je<Ȼ[._WA~7nب뚦'?y7ܹco}UMnܸ뺦i?odccömUU5MZ޾}ҥK_7޼y\.G?4Ͷ7onmmr ٸkAFPCH1@ tY!&q)msuDAW׺/ @<f<$L&EQOY# BpR3yYYq gd,"tۍbA5%Q"t(p Hd* 0Ƅ9EnWloo PU `aap…{]~}fffaaajj_oT*Տ>Rܽ{ Ôzܹqppj pܹp_zi۶XOnwyכ0pDQTa@$KILV p!$aa( )A`HX( #PE0 ENPU5N[!E#DQl#@6SLB1"L!BG8 #(0DtBGG%8X /;.]zʝ;w0E1w~߸~(w9|PX^^ظ{Ɔ8w/)UhqA\ x?Y0>qѵj_75=-2qV^{l,[8qȊ+0ƥK^OW/DzO>DW$Q<ǟܾNmjJpJVϬ}˛ַ.}tm=]M)[^z>CSOxk]X[z]uqt]Antq??N]X]]]]]֥\ŘW~Z_w75?ޟrasH8Vؼw0$I$ڮC8%7MCHpDM(2!7 E9cF(qv0 x" iZ@@mCB**j0&!$B\%q4]u:BBb0C$H(M#DGѧEj)x7DQ_VWWzq*ӟTUU]Aя~tM۶_qiZ\T*;88x뭷c-nmmAc5C?nܸqͷzƍ~uuն??ݵJ2l?88ܼt7oyoi#z7;???uzK.ݹsg|MM666} CqU5^EQ_O_XXqƝ;wTUן=Mӂ{/S!ܜ1Y?FZ_K|ӟdR( Af3, l%&&J\>jl!3MD2EޱãXi~7Q./#(+Gj:Et*><RG,3o۷Fy\PDQҥKoglq ~7vWµ(_8ܹ38GTUx۲m;W|޽{cuyrqq)jaawlllUQv<x鿶zRZoz3{{{A7?S[$ CxܱmlyԈeZT:4-qLj,(rWӳjt]q'A*Jc[QRm4K  Sض&JI; DOþw-UU] 1({L@jJ%uZnPl4$Ktj42]^?EHۈbI눲 =ܵw08,,QbjJv%2rNaXQ]+ >dfvSX,˦ek)Z[U=^\ZjZb w)jQr,S%eYZ;./-mHLs$k;$AF#3Q]>uqtznRiPe{dJjF=VS}c*W)31?Ʒao1vMR̗A &!"$\8aœ$WI9k{մ,U+UE#b6u]'g^aZD*=b:j۝8 [^/ʕu; u'Bv:LfggXt;:>&`0@GQۑD_Zznٶ( qt:"/:vNGȤh0_W>p4t;]Q:v0Rh8gGG Jyn:T__Myן(?C& A ݽ\.7 1!@DM($„YsdX q: e#!D) " " !qE"d&%Qqa(]<8Ga |CuDQ}? =@G2;X2~a@\yq\]Kt\{. t;-__/KQR$.'0`(z( xiq`qqϝ?{s RT~vv |,8p̙5]J};\*%ŕӧ'N8s<੧FHF#/R, Y];} C;i4 IDATߚ(OwL$/,+1ϵNX\wĉkBQׯ')/k,j9++q*oέ;V:.xE N0O%l^dsQ]xL?g9۱=NL:7ďF#StGs,JmKlBT6nǖdɲ,$}/ ͳ=MĄɔ꺮,ރ%nGxg^rP(q@@. DJO?r<~;#B y#)r)JcA:i5[( ts8$KXb0nPz=eAa,sL&(XW#s4ZZ\= RD̴fa~bj4mۮ&&#e%IX"z\lL&ۭf&3t RE몪ztd3nFŕBj $ʢD䙐0B@$ #a!M! 4MK`laY&QD0B40 i<ϋ0(*"RizzNVAE$|) AA HcD ñ@E!DQ 84gjBB( ( ,x< VXb >(cWk5۶%I^mzJeANŗ_~ E]%QZ??ܼ9.0=v(W^uX,653-I.˱KKau]5(jkN׶崚,ǟxrdZ7{{S'i5/\0zjH Bpfr`K;%594J\(ffraQ)K"1vP,a${{fsmmm8ȲlۖFeyYG!ca,sTy$ɴlEV9:lF P,jFX*NGHhД$+^aQFQ + U /o|뛳3ss1Y9p]\,~d2i_zeI\=q+Ξ$jSOgTujjz\"8drO?s^NL.3dr9EV.?$0\ƥ{ꙧ3l<~K/_ݻ|r<zjOT7!@G˗A=ž;(t:mZVLlq\)eڝ0$X%p4B1)dq8&b1'\d3=MCxq䲙;{hp 3GV{na! DҶmEb~. a_'qTED"kD"ifCc{@Rt2uO }}ώmB( DQ4(:j4DA}:"d ޼z%Njr)" !d( G}`9%Q-7DQ"IQZV>m7|&}hʒ0L aMs JF(iWL$'R)2}/F#͆ݻLNkϝk5 4Gsj*SJ eE c$ vwE1 n,F&DQb0l6v϶񣵏";Ps!` !j5dYt\7$8"B"H4/(=|ϲ'zDQ"MQMc cJ (ZY]QsٕӫA„T&&*ʩ0 / FEQ{fx>LC a34C( |HQ`f ea87;E4EQ4E#Ym"]e*J @3,0K'(:s挚ɜ?oJBIzK/|{_Y[xZD^ׯ{I]^+x0?zye3FX=d}Cdbॗ_"ĉWVe%Fsןǔ׮B vڝo"sX `Ics=e9Bֺ"1 ɦT! ,!0!qhB4y\65+x (R&0ÐbAk4X@뻎B1!]#Fm cqFє8=G1L2E%qeY?j=1tORx8|00r\.'ɿ|<NJմ^cRX[0}QϭWzg0)f9.~xkcq^O+ \Ͼؼv ,A( 7? /$Y^_?_m<ˉ;l5>s~k6]9… aHx}|kpQݾNU 8֏/m^1@뇟?g&Y2yQh8Kn(1Fc\谐v(c;$a!lO$ c%`"+rFqߏ,si{UuM[?w p{}A㰱|j( 8!HƓ}Ea,鴦BI=aֵ`"GGx|80Mk M/N!>b/wQ1K 3 X8>Xot5m@HZV#,:An] qx1v\gp4lZ^7M4GivV#P4=|2Q*ZjFA`}ӶZ8@ wB``tmAGCs0^ݲm)V{ZWp# HDaXbA3MAA,9[R4`~~j:53=??wOE'v^ݼuk^%yiqizfVӗ/_l?¾}W8Ribn.=x߻r MSS/>"[;0Z?wnrr׮= {^^W_AzϞ&f\tgvns|gꃧN]q~x(}e+l,Xvd|ՒCmN%pL%ڝ(JsgϮ!ӵN'ˊ$ (!BP {C aa(I2ihe&AA ˲!R:w> }ew|Ԙ:)5F4B*XA~pepd#27h8 Mt= V}4`n4urLȖde"[Po!0?E80&ja{4Mto6[aG}w{a=] 92 hl޲F[9uZ嘢A7vw{ ɊT3̷py0+2LFkkKe^pRҩM۶fgq &JKxw_BL%.m\t/_f:6$J%/^l5W^UdEūWFa IɥNԓO -KB>_ 8\18X?j0N8Rתm:=ύB?yQ ^Kn~t0 9@b@8ǣ鱲iXe"&Fvpz!lo ,su>hxl6S[[ h5YWeqD߿Oiuj>_[[}sܭͱ& O#Z\-򜃩:my0Qh5Cߋ"__ ~838Qt=ύ!@f3UdQlup8N I'Ȥa.W%cc\^eyTɓ'I}$sR4R,:}굫42իךƍ#͛)=uSj|eopXS+W67nQM`{~c$\|Ԅ$ɺ?yq8gxO 9x3+'OC…s\&{\{rYj1x<ά^xfu1Y"#m.[NZױ(Q>N/'R"s㊄$SIr0T5 D2:jCyo``j K' BQBS sHZ4(,z #"E4U1!!D $fx8-sq~wDêPQGNW.>>BxbB&y4 ƃ>ƨlh Ơt0vqV|wo/vnl?oo`,j4[1NǶmc8uQnnn"eE \wnnj7uBSc8lZJaUb-lJzN*988Tu-9.O.`Lv6heqZ\!oYԤP'gf߽z2J'R0/\8޹p3g2SS3\> `|҈O|eA(z… Λ}S,͛7}?qoo Jl.wfquE27(s̕+Wo`" >0s:?BHQ+˓<pldg}̵g6@ϟB`<;㚦y(p8T%)fCpG  B$8(Ih^2(X @Ք'N! -A,ˆSirYHDcRЀh!}@.P(ڶ@s?TW#W虞i8^]\\8hۭp}}(hX#LݥQZ6iVbjnj"x߹G^cXC`QLymqH'f&Br2Փ'dLO.--ݽI]O%dFΝ6sO;u*˒,8Z( s3aO={ql.6ͩ'.\@hZb~aѨ"t* SO]^s4/@8Jݸq=hrFƇͤy3L6wꕾa~g|SDA 2ө+~[,#AIFW 9g:]aIC'(bdLӤ]׍펖F+ժzy1r\@ynE(XfBOnnl:UUnw\.vG Js8es4aa04`Xe[FD)R;q[vJOԛM˲ FjDY!DTc59FHJx`ߋceaf>_88h Ar4vizö,?=ljni(Jwo`Da6*A:aGQ: NR=Ĺf$ڎ{@VT׳\Hޝ;Kд,42b{̵dJLKVB!W7g0bFA8NsG֓eH%&S# JE˱DA[XZY{KKż$ɦm9 4kf^a>377f^j?NgRzROs1Fiu\E++˖1$ŋ~wzrsAQN\)f4 F)S"^8NMУ \ ; DhD(ͷ̈́tnO F)IX) c˶Fa$WٯQ V ӲZf? dҙǏoln,//X,v:GF(gq^'f#rgPJcd۶iI=hyvQJ ˂ ` jr\?rx, cAnch^ROTkMAƠ8t;4ڝc9jaj-B8fj])۩{{۶Y?GF` f1A\]C f0c010luR:B$0(>ĄF?=~q85QgRqHhyҢ$;wO8'Z2x׮f酥+'T?3v|fyW^k47n\s^pl+W3> )/~/r"_xqvvpe_x/{qpqeyqK眗K/~7臾hN;#yx+Wєt2 }Y"9,픞FF4]/6[bt0Fc8!A3\մ( S)c0'IY0p<N%1朥S׾b:X}/Lz`A8i# ! !ɒ(Kb, 8J6$ !|[;?7;p⸠it #ʌ˂HL~{8QVIvp0A1VDzm 0li;,&Y[["676 AժAcðը;Ch{{Bi1Z o;AH;f͍M1ctcsN1{yt0lmn gEQbagc1>;9.-͗ˍ^?L4YK.XI$ɥٹ<ԓz2ٳg,IJ,X=13;C(lF1w{0 >qv)39|_p\onnNSD4|/Kx,D(I挿WN?.+ csNApɧf !l#}xy~~3,̔FvGNO?tQ= _6ɤ7-kP{ɤXJnT*6F󛛛t:(ph`1Ɣń,%YtZBDWY}?2M &8';}b+ Df!2 cHŘ1I*$ Փej|:ca*e7$QuIWcX9MN  Ő.f˝ڎa1BnZ~Po`?^#؞n6cږ D[nAӡ4j6뒬9pwgK=4i-a$Ah[{jH!flnfqIV@h6M?0wF9::iw**c^qkuq%IY[{H#Bq>9n7z5;3iwM( @eanȈ'VdY*ǖܹsJ%$OϜ9#SdbjqdD"ɓ˦eItғFkjjzjwggv~lŅť驅YM ӒEAŕ'YI$ \`4=33?;K(VWW-Ǒ$'BDj.X\ZVO^ɽ \5LSbZn70߻ɦ<;]pMe:6"b:Զ6M5L|.j\߅Ae!,jZ4͘ Mv^NEilFuu=ivh9㸞qҘgY&s8 }|Sd^2)KcXBի}ABd-7ݽz^B rsN0D!r R~<@ !"(C8@q9"bFOu{mQ:BaBr0 .HD?4"A X#"(;10~&ky?qҋ'NxwtjiiR?s^̩[[cΡP!DH>8ԓRX SIôM&iәʣ~ڶkt.kәph8LݽsO;(-W4 | W޻ÇwmB3<ΝwYD'.b GpH0唤w=rn(#XL.l6]wn6m4QD$t1dҖ9 }v\u,۶,' c,B2-bqQ1$sxc,E4OcTƄ(^6L6|ym; :mH7t]78LnaVDaowRCW=19jvf|8`<p`D3% "A c[qDDr1QbqL!hqD\b%5\Q0Jj ۱@p P%΁y3YVi0 "RYQb0I6( D@YĄGP&͖l=+O|ӯlln^=[oNON767O9w.!"L8fA%eAI&Şi ~P䓕ju=IQJrVs]E 㨪hOmp]WUUqEE9*^zs1t[K&0 |?άol\xИ GzJ%w/W@GP),J,OhWq}绯MNM>zpq!Ñ\F#ŒmB(~k_[n>~ڣe{7O8GVQ{ |ѣ'wO|ᣇ+'i۷o8u x{bԝwX0yʉHR|/xK9<+$")< 2h rFi !c@(y<,ec!11#~r0g@Vdcr0<c B1!F!Y In b1S4L IǾ?ދڃwIW^Y]=wrTZ[]]ZXZVk;.qjt.{nomTn89N:qa6[hu:h{z #Ny'W$D")b;"{;Μjp='HU+Ϟk;Fl޲MJ)!vP] CHc=AT"޽;Z*mm0UYOL>zԏ<XV+A4-!`hm ce[aa8ƍz}ha \uaH0_K'V_/EUY8>~{437X(HcY˃P(ȲnϜ93 J(ad (~?::H$t]Oӟ:NE_<#\|yll,ϟ>}ξ Z-|3A2f?B!Õ~̖JpY5=w~+# һ?÷&O>{ww#AF8b߿tR'&&8ضd2DF*J&FP(d2;wafGGGwvvE) [nу4lg!i/L.JB$IT?(٬K{:'ǓqtZ혓0`BcAXKaPPUUjSǯ_+KHGǰ>jEC60.p}x?*:R̙_VxoZYavUU9̬?Us\Zyҥz;0S`ii_~loojEQT.t ^{~ˬe!(8>jfnKL!?{|jj BxY."!DUU]B,xT4-L&#IijdY$itt4 BH$X}N$I,/--YEa}s/m=)͍7.`p;)ٴ6Vja}htΟ?/ b{9s6'?֟?j2)cv[ö?ַn:,w/,,[oLLL|_hZ뎍9!P`P,Bu:WVV '?+ۏeE:QI'}KA(O˗! !RRz2*$I BEA)1N$$q%IRo3{";w=XWOS$0(1H@0 D,f!a 8%9|"JAY ĔYLba$lӵ!,11DCA;%uźh7"8euB99HC_"@?BMKZKv Q8R̩PŜ3@DgLt@$A E B(00҈s9OB.[c<8 ! -WZ@9 2<ii@_STJ*DϿsbOjΎjX(u!"2 T2#v:^/(PgNn> G4d4)'(NcXXP8  s)DDf]~o+َ$r^;)`4 ?uo0$S "ARTQY\^𨢥]h([]/'o{H>Ј :`2Vsٹ\q&N]X=g&&R[{֝7Z^ !v(EK㳯~~~h@3B!g9 GSj$nL8Q8 @$R!{٩賧gG ٨[aa~U?9N1GǙ0"i5PeP2- Pe`h \/tiAĐA%\fyrff?!w>ĪDLR#-)мGB;t&:ѱ6 !;a1~n\>;˩8乑b[O3µɂ DJUp\(7^~VQ$c ,.e ,plO$4, Dt H,DR "3`y EAT%myq7mM ZX,:wN3>>뺜sXV4Rz-Iz6eqBcq0æuǦFGGu]Ah333YupH;~t7|VOOVGTSj 򲊵Do|=\{C @"c^8⚀ͧvMfˑSQ^SHXCA:ɩLf2v6D8\ti8bA__wt]R8fI֤Rh?)R `sHH li 柹ax7zl$HO=qgb>! *'?x) PM{V !-9^ 9D}ŘNIh]AR!*L[?LLR7D2 j)-a;TLq/٭:w)xHJaiV͈k[ ̎M?#Y./>T=2g/duiV]o& ̊ÈS,?C]~wn-Q=9ZݭgfZOglFt}}5z򅫵ݻ+k=XnuNeM/3%5 0=T9*5_GDxbѻ?L>o ~1c1T,]a"HRT=ÄLRl>׮!I:% N}Y5ڢ8wʏoUQB}c!?ݵ}{]N'Gt)K7@ x$d^BJ A/Fńy?:Fvd u 8V.˿׿[Ll=u1k6.INׂ JV[]I=OM*MJ=ծG@RB:wbXfу[J;nex WU|b<e"XגՍ1!2CF(ZY8hUr!_{v,VXRjE.mEQt]C񭭭 .idY&x߸G/6KV[*lcn ti7` Oa 66ƻdkwIT*3rbq?&HLcYnU|q~+EQ<{(pnnnxxr}yT*~ D Q7 nt9N#$1`զm;ȅеrlQ]-(`oǿFM܈x!cqemH =%hD 12'v=ȳd75֛NU%v\$P$CJ HfX\]D䷇zR<oz}c2M?ypdat\^Zs )喵pBH=o|ۅc+"A2r26*UY4BvniG7ٙ锦ٶ0& VU{ lotO_`8 HD xssJ6WtZ-q( vxÍS;kUUǹp6V̺cE//Bzzzvj `mnn28<`}t:ϿȬHzlX0l&Z^Q.aH`p"<@?CM=!TYDtۡ OFf}#Hy̅2Y,SFň*dqH H oO6,3㛮ﻏ~ za~)@[f=4~iaUsk㓑frNwXzwR, ߽Tmn?ܟܬB,D Sbr k  뮽@OnَhW+P0r2\,L'5Ͷ $c? C|Q tFcN H݂{v+Ƹ;Tg׾Opoo[C#{I QZabY!0fY\\*+"&O?tD]UVf۲|OTxNeV-C}/wپO((?^r?906V>T,º"T;Q@8c5/Æ _omD2rpȉSSil{Svp~C?nM7tܹәLZ&l6{ر$aE'@K L* ޿D0녋 !+gOH ' QX5F#"K1#.{&ǻ2o 401^Q (MST]jT ! VJbo([g({4,]B*f؅s'zG\DY+%twv\lvDGȊ"MX!S%a& )ܖeJZ.oֲ;JRm;v`Lk}D]MTC֚;e֥R)N;syz'n|>ŋ p's|fb:Bhiii߾}YW*MEbs L%#ƀwLQvVo>kd^;ܮ6])`u7|oQ,B(TCBsA¾ư ( $E%_ Ɋ*JQ'i!!1PDBH؏,I((,f aIcY~_tH8{@+*57[MbPBt1aبdM;YynfϞ=((ng}Q/zZhի+Lw*X--PLKXXZ!n QE_ST Wݿbrjt[[ufE0 =STł\jŦeu멓I (&D?}'Y6$ `r%7gvi B(@$|~u^ *=OZ.u\ljH(JRA nc#~Db !-ɂȷEr,;vMNZe )g]c9nLRb2%cqx]vIħ---MMM#x63:D>_BlxqKgBQ-x,QcAr*0-o.XYY|vv58R'|0m.F2U\>ۻw/pqq1.//ݻwyyZ{)fx_h4Z֋v|*5'l'n\r+,]0HDPߎCMo}w5ݎ w I5l5 j-/!1t6 m1(JRwkqi1ݬof4y[f {SP$}CIacBRet,GHT'DDa~ܷ?>IRTEAh6 "Q(RZj*㓻.\U@ Q%8H4edh̹ o{;տYjZZ*%y?ؙ[9JeY;10=:11AX///oc!5(ܶFk׮u#i 1āk%?}f|Pb$bMC)byW6_E12\}%a6]Jlg,I?> FXth, Q2L)d-u[Bo,Z~snL0]dրzxvĬE 0JT*tD"h4rXt]˹&1ƶyds,?뺵Zmjupp F(ƣ#fy|e5ՍILwƻ}<ń6ŚXM[P v߽[oNWOB)E]J%lAXk똔!c4r@e/v`ni5%,`7r׳O?N)3yL̜x'YZ&X:&koqk@F8w1@xHgmȎՍ,WO¿AhIWY21<;JDZrEwGi.1380wN<@EW`HNuRʻX(IR?ŋ|>l6766Ͼ >6684Nb?X ܖŮHloU2tj(- @g@c|RjK^^"Q3( IDATvh[uY1<93JQPCIb@ߗ=t~#r.#rɮAUI`zjjjffZ"ðVj5^vxxujqKdLO,[fCh4vXl6aֶmjNQ,¶Z|f Tx|K_^W|! `WYMI$ZT'*hȠ.1@sOgۑlyS7iZu\QRۮ *k @~~>q5:P iZ%*IRTV{ dGK\e1p}]f+]ry5q`<5}aUۼMzo6\OL$ S`A)X"0T/l6)`Y8O|l^qKV$U Y, ܗΜ.G~w>sJ%( , IRݻDAI]_/~s+&|aAg-QN(<{`hub*=Fzll !K_.O>$[nRBkZ^xS+nruMӤn 1bWOBE;01v~~AN^L> dn~_ !ğ>Rm\U,\3uHz&[n{cql!h׻s٪!F)XX8j@Yƌ!z}wկOێz[DB!TZ/ YJ Eljƿ#$+? ^I0>RQaKBڮ6m!S)?re;4C!UၾuT/%ѢB谷8BL12 MBS^[[+ 2oEO_ϋX\ lv]ĻO>S(qmu^ORA>pO=#'"l:uMKHjT\H4! S!%wvJlg=z#eZqg.\7y ({{‘]Х&+- Z&Vv ֊8s)f=eY^^^NR1UUMӼ빹Ay֭Z ˗\O]< ܪqķ\"K! AǯbwygqAJ }Х$Z%TJ0 0D j\nb)ܶHH$jDXDfDU.؋-K3 a T*{СCe70I|7 crrgV\SFGGxn˲0L$lX;wntt"avOReaaa߾}8v4MEQ:FQ8}_\\[_IxMM dZ|!C1C"CbLO[k-A~vWww-{J -+rlhLBh|vav.N=l]5d:VK+c2oͦ(Lf}}}xx\.2F"onn[qwwwV6vuuh4X,&jZ,m͎677u]b:bXVEQT* i,onn$m<*/y uɤyE *+2N`Uhg-)" D*;mˆ0Ɔ'guFhwS3I%cX̠4e(ݷ σdYn>`$ w#e z8mci;wNUFls@9qDOO`(:AIm/..v,ٶmYz"<Ʋ,^YTzqg/j-QQJylJRE/3gμX?Ǻ:ܻ|섾bEϕf$Cl̋1AR#~p=ggW펗;z~(*1?aH]9dz\Fd3bV"E^,dێ@  KWY+bae09""xGTe^0 EQ|պk! z#G8Ȟ߸_ |큽72;t"bPHf# REN&S4j"lgHQLI/&WGUUDŋ|cgee%L*Rry~m6t:F122ri։D"0:3qT2Ax,F&v!]|&H&g ʬ/Et%QjwUNYAKELW"LLx`?8CȂ؎ e}~(x`!Vk<: Ve۶m[h]y^eYirȗSʯdrssS[nflmI!AhA$S4Q nsYWTDKeZ1]EJVOI _.%9u\"Ko5n5EBq ť E@L7FGR'.V^תX }뺼I"8~iF[nQ߄0 eg(fffsiSr\GOGQz|Ltڲk'˧x`yzɶ:gggr\~FXaOl!W<{o%]4a :a~c?p c}?֫vLMJFiZ7u<{82YPmd4փw _{gN?-A#! cl_5xy{zzt]?~8orT噄2,յ캮ʗk.Ce`oπ,ž>VU3=^y1ݛn!YT\Y߄HD_{Nz1Ow^}w»7lc+BD BuAr_P=nvR`*b6Oh4x-86MZb5 fݑA h4 [yyyY/qm;!qzo|Ud QY HӴq3U6q䄁0uԭ+n}sɢ8aQYD€1x='j7*Q?_ٳFیm7TwWyK^)fsL3bo^$()0 vʾ=A5BI o"#ۻ#fM)_[[m:ϯwzccϏlBޮB0<|vv}~6X_YW*(<#6iD%qD<~oQ)[_#Jq(?.뺻wE1N+8>z #TB 7k>f?0O?ywl69XSJ4Mۺ-o9#6T*z"Xz@X,c!r ]5YØǟlƻw`}4V+{8ogr"_S!jcB0|WI8(&e@]~o +ٲ˃5o^V;`!˲:ޥ%UR5D"u[]=%IZ]]}u @Q),?S,@ ;LJҚ^jt ^oޫ:wh{׏]?7g?|Fº$A.kTH 2l{?jRH_\[(Fbl#>XWUBHT/ֺ7 qA`j8 (2>DX4Ӕt: !ݫ6}ֶm+#MiE??ȑ}},DDaLE0@nD_~OYX +ٶW 8~?/⇮*z"M$q0}ٹ(>C_]~c҂z;'5Wd}EQ.fwwyiUU^ì;eY}}}ĩl? ̤ne&Umdl!g~@dU`yltj؉6ͻzu_}k?q)بW]2ʋۭzL"1(VhCU>t# enַw%skZz[9|y4i7RĕV-,,k5Ap1^YYڶ~VJA<^EQVIlhف'JH[ A8o? wy7+{^SO2Ajj tE(S&IS@g$6;kUU]ו$R`͉oZ===6lݽ0::n~c-Դzygj]/ !"~w|)@X$*Z)i[ePZ#J>w 09k{t&4۱ Oy*r'XX]-/J;eּrV.Z:78!*. (J|>Ârl6˝gtzqqReY0hnIVkqq]ضQGH$ 7x81PhЇrc`$N?ubm_ն+FT]CU#7GL ~I hd6NA4VJ勂.usD$BN: ùKNQ3_Uչ(?>::zan4D~\z . )J %@e @]'m,*U#. "|E)vq<444??-%%)Jɲ34 $I? `& {Gk[64C";̊ PY ) :vlBKD*Ÿ{d1pZC}1E?(S$T9 *Z)WEq'Ϝ6[N:\xnJKPnKH^ 0MϏxvv;gff,-wBjPb3p{w~sz\7&y}9*S 9{*`uenmY 3C'$2QP$9XQhQٳi(I=_XOMM?rY^EzOOK0=E :` Y o,("ME~D&BE2c_~zU.MQ/r dxO(34Sdy(Q瓚U$b$F Q, Fo?j&'' ޑj$IJ&1Ҫ*O/VC|\⶯('($ ̪ CB ap-QB HT_b&$Up &Xġ. پ˕v4m뎛hEAEW' G!jŕg)Xq|ܹuGy^&9cFGG;yӼVNR_"_|1TXRz@'=b#_JVL( PcIQ(d'?p_wҚ]Fén NJnT6rەozٳv썏 V/.OCQGcyةϚm;|>OPJȭy333$Y_fWyދ5M3pyv'!%9t H&ZĘb( (C1pW2A`%Y 91ECSc=5;.Z O>m L(%QH2kNZk3Bo1/~{0 ,k}}}+[^ɳ>~E9!ߵ.REWN_%)Ga H0MBՉ;0#-Q( !҂j"F}=C(egzz@$azOwq`}ŭ`migΜY^^=t:422s ;}XqϘ@xVJ!㫶Z_ʏVJDIi|ǭ7W`{bWA2ufA@)X[%>uEnZJBOimCQIS,uIDATi48:`KuuuyKy;5z(hWhP )BvjH`(SwV4R*4t9om]qd FbCK5de!0\"O-/FSEgP%!Zmw i[D' ̝/AUpeeYyĉEX[7[U҈@8&gۗC5Ee0 ;ot^Pm Hb,d%U86+UII*!c:^yA,HMR:>VQ6h#" \)v܎Ƣ"BRiB0UͲ,޸% .@;V.9w^uyݎ(~~{ݏ>?^V]w#ȹlX}~1"$L A d*I,*iǭC" K >  wyv7?]^\8o~!{r5meMGTA#9d3jB~~xB۶y^^q J/ [ RJym۶u]Weuuu``}q2 #J%y_eY bzo!Q`" `  "~qҙd&% Ll:yV&@vvEQT)%,"%:L5A(l7ˢ wL% PC!<@Qk,i"xWEs,}̙3/uotMj2M*oLQV={衇ݻrܹnԩShތqt:M)-J###<}v``+$IJpd2 8 ,--Rr6ϮT*%X`%t-!%c0<aL`OvCrn`^M܈賁";99**7I'qF7Y^"B.m,@6 vYP{ݸ[Qiyu}v!۶Ϟ= @'Nx/Rʃ<v۩S!ܜd6W;4WVVz*˹{رo:|͏<:gώt(TXbAA*H1dLim6L$U1z?f2n,ISmQSDap}km7D1c29>0HJz|wּaJsE;)Ztv4HQRZz{{yhˣbrfͯo)b D_O#edRBv"#I1ąj]qȒ&p>Y_ۨ TM]Dld9vݯ5MabQ$l`] qk94MJ)8cNou]aȭ뼭"D]yyPuݩd"(Y1N;)Ln> Cت.yN k0X3taYkSAl&S"vA֗b憍@ܲY?3[5o c,t]ggg׾/}KFø}QK]~4+K亮{gft!b %qر˯CO~7?+pID,jBzLY#ҥe 4vb$3חJ#wf|g~gG`1:` <\. urcccpp;]8;|8"cq޼öm^*g[s y[fC@^PG! T6%IjQw<{a6ʕ҅{޸soJ3*B5nju0kqIS>f<,>??߮wCWCq\fQgvD3y_w +I(uuL*iSyKo8!)MQ!up?&8qnqT.3:}Q4DJ7}%vsջqjqh;$pifZ+[s W2,rp|Tf% 0o}}%?xWo/ `#t)Oznm;WV־z_ٯKA3.^8Αpck+K9JaM 4(D@K?ҍ o7JդU`\kd" kB;}%Qɤ]7KB(b{su`wW剟z:`,~,h+MD}5PsV3 ˲|o_LL O3Ea X&h 5"IJƘiJa'ȰKAaݶ՟ŗa&8!+p´_h4{lsnؖQ:aaeIE3ejэctSV.M$~sv*v?ux e|āzFcIDٶ#uɁNׯ;xSJjlNMMEQ4Gye=־7mPѨjm#< ڂsDHmҋs~'D4BHM)ٺ*iāW*|d~D>3*6xS{[0JBADyƃPF!@jέ><1͠f[{Eۤa66 Pl\6JC,qP(fw7M= (&P=x:cF<@/ :RPHx⑙&).-.rg138;{jΘrFӰoK:2aP%qh\9ĥ51$E(AQ$d L f"f:y,"l _l~⣆awyoٳFoj㱝pxz8jE ]Iy.C7!!:f^k>4%vwS]_0MSM+MW.;icO|,N[PHPQJ8<;g;Zfy4[ :6`@Jz{-`aX )86(\o/Tbdb&k F3hks?'u5 rC`Ȯr*vV֖iohoԲ H\R;omqX O~ۺ%aDZY(/๕A8][{˫wێ1MEARA!J#XA[Cw;#)@zʼn>i۶'''laz!t]P^3gxh=xn|/?攗\atIME 'tEXtSoftwaregnome-screenshot YIENDB`gxemul-0.6.1/doc/20131109-openbsd_landisk-small.jpg000644 001750 001750 00000011505 13402411501 021640 0ustar00debugdebug000000 000000 JFIFySoftware::gnome-screenshot CREATOR: XV version 3.10a-jumboFix+Enh of 20081216 (interim!) Quality = 75, Smoothing = 0 C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222W" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?tKa %ĦAa傣u\gk+,6J >,V)DE=O~Qnun[K9~NI6s/ |~Vū0kZɭTKHQFu({>sBGT.q*0mA_ok IÙ_^ujOx(=Ϙ?nC)d ,#F\kv'+ۛr^GAZ}Y~Gql'#8:g+O~ ε+^p$8oTj$ M& 2R S_—w7Wjm;EHbO|}j `2c`s r] tQG-3(AhV#U]RnDO T}VWT*6F?M/[%" XjݼRC^ZYR&y徕?B;UNy9uI Dm*pџrnG?:U{C/~̀;}M2S{ |0-(ǩs% eOSfN[#h4oYW(i;}y^ޢ0~ތIkkLl!Ķ܁z{SEGd';[Pgp _9¢Kر{ڰu[Pq $D$J8g󢤢8)m$GK,ug,~A3'QOAqS1Q-Gjw[Ǚlх?ҞdSV/FNo^!%nHoH[#"5WIT! vI?RQC?DB Is)$t>JBgj i@*<8{Ԑ_Cq';weeu Ze"0RuFS%|TF˥l@V"`>jƞ`,IKg (h3IHe]!0?>p1:Uʼ;Z(ܦQ39#LZzzorl=:VlJi$QnxbސKLBs@ EG JəX_wo\9=?Ya$8FN7]_bgS;2N6#aY63[ >ڡX",ۍ#ΰRP"1UOT&L~j#Z[[6 z:T~"78O/s.20y<Ksfx;vG\:uk甫hqF0$Τ_:0\v ZH{5皠}рNF9^m*HKf\<@V$KvɅHv ][}hRE$,I(FMlN( gθ&0@̭}}z+iue ݃.FCsUnYB`dV`\ |8a@8M-QEE H*HsާmH݉/ԁ#mYp'$FU>0_1{~Uq~HHR>Yvd̀jZL("gD9J!@ mVUY^ycv Dc>`9l,+=J6VWj_@衊 iE~Nx1%I&yq珼(S<賏13sPą`HʀEPEPa,gOL w1t >cbi[b,alch_ǎij:EQt#XSY~bTӨqWd%UY$i[ KɏˆdR)ewb3Enw#ń0K) D;}>\2ķQ%;v8$>Jj#b /ͪIP#"Xcwۏ$sրXKm~ SUŎ49DU8@Ute O_/zya<۟9=}}I}'ltO[X%"p庉e.?^(Q@6bY a 򏗟Z&,%-NCXv}&hT41bNҠ:ݵ庿H;9Ӡ; UOdDEd?l C {jj;GL61~TȎ%rz{_Ҧݨ~vId8b^ -Oz:[xncrg c0ЯzZEx`i1{6Tlڟviol*:#+fsc3V-ClF?((SJmY$cй6,\ҀL@ cc#bik;HÑ=̢I%t$rcc) :UOdE} ܟ4gr^&f@ c*I96p3U>E&7yljEIlM+fz/%r%F{ s>Rɠ U(j]pNӡS/.#kTT DPF~b] c3~ |q'?@PڙMFpRxldÏʊ$e-ҏe}xkI[ɞL̹z,VFyeu<%١>?yq;b+v/:aϵT&L~)ˇW@*;cid sɲ[mĂzמzR˥XΎ[#RN =>ORPX ])PFUc-,(ہ2u8"C 1SVNIGVn9ϯ+Xt7xq89hdMiOUyӠf>ux\ځ`D|g[*pnnFc?:*gxemul-0.6.1/doc/20040710-openbsd-pmax.png000644 001750 001750 00000036167 13402411501 020004 0ustar00debugdebug000000 000000 PNG  IHDR ~cgAMA aPLTE^ffAP*8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IDATxKr<9@WVPc/:%>@RR>v;SW_ `NcM|Q?A;–'`W߿h?,SNdۙÀ3L73?;ૼwWv?3mHe+|E K3f]=znDkkߟLiL1(|}0[>`0  w6 {`zW >./ <5wC^sjޯ|i.c0_A&}0s9x9u5wA7Ԧ߭95VA#} >.{_yWv]C>tϹWh9 mŠ(P߿O/wK1.5g6QWqh+T cn֯a0 oKt`je _g1:} }l 4>\oq &ao{-0N*wyH}@v??L_=La/?}Eܷ{$ OL ܅y8u<W&no?bYGڭ_`~_ &*`<ćNQ? ߷iK 18;Lb@ Јa?1 ĀЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈЈH].o}0>_Bw{Q`O@}k&(-v[4ca;CzH{0˽~aHMО[%ND:wȅ3ׂC: 00 ^?ѹ9.7Z$>:!|r}`Gk0ЌAh [a{to5.}s`` y to@R[H۬&7f1P\>qgBw;}ė,ewNmS2*L`ni;>/!kgװE{vPpob:pmǖQg ]yʯ:(|l41 ={JNb%h?ytPݱx%k y<1^bWYƠ#+ӽ A ?zͳɳO&8 Z .;@."Ո@z+97 W7} ]{n}ĠŠtF 4K= [Z qƠ)X17Sq0NaypfcGgYrs1h{V Ɠ'm䩇t ^{`H %D˓;` ŀF hGyy@1',x%}VQX"/?zD!kz`>$19Gnv10͖kop"kqlvG 32!ˣs_HDQj O$]p+a[S!0Yo?/7Yͷ^}{zC h4b@#4b@#4b@#4b@#4b@#4b@#4b@#4b@#by*w"ZFWj)`A'KE{yo0L,^aLM)@ӳZ(vms.=GebP$5԰!9DJߜ"o l2@Zmx 9FFH{S羀"%@/`cb[m1hv0(y 0"zGs䯚# 0u%` %z$r/i{uR?SpA؂AABZM _oz` (1'1pN%!F cvrܸ|4)`"s`ShיhgHǙ b,e'-G?`Ā,ЈG+)AĺjDy8pyJ Y^7 Ssnl2Zߡf k+ gjˑm\(6v-fgm ܀A·1ifR׶'ƼS5Ǚ`% yQaP0̹jzju Ǘ zF aZoa5ya;7ljXO!1~sE94F8a4q`[oںt' jr1S 1e4sO%g0 S[~\V&t!  ~b~ :t޴ޠ2~*~hv?U0"y +ս힔"dJaPX! hĀF 1(tik;o}cT.ڴcg: uqZ de^3>Y(ʲM{XyU$y IK>?Q.sDuvRƢ6`R[#jj\k&B? a*U(!_[Dm#0i1Z=A驮kdu c%͵uMԦ=bzk(G=S2iV18(jet Sua 6[ZK==fN^}.k *l+]k-zFԦ=b ?ܒ)- 8a|b':.y :}x h,o36|iXE\߿ח_ Sb@ lgbpZ hĀK VXh"grCt, g KABPO/\l#lOm;y'&.%bPaqKr;TW~},6ca=?1oo`5yV}b8,tGL= #1͵֎RjH^oЈ͘¸H)0E `pvyHu 6E_B"Y7116ǐl"'˚FX |ĠHe4[2uީ2E(%ԟǞ[x F NSbX_:jGBrB&atB0`Nu ^(m݅b\9_"&;Q"R*YlP"c- hbpҘ9R Րj4ذ,l-S0(K=` z= 4A* ኹibܚǰsvzj[1P{ ?(bp@Mdq90𾁖 *aV b1$=})ࠀxn<֜'/ۘys7xк>1{u羥I0eo0 s O }4b@#0A[h@-t7vJAd6 %4_¡0PsJl- _-\mfbp8 PA%@;Ap4E<UF'v318>oyV j7sL8ЈЈmx8Hkz44#15|y? %Zs\/ab~dg `uKPe[Z?!EmIk o=׌|5!] pKPBP#כD{r;]S5epc .?YkPνItm=5M)%V0h@6Ѱ$D$+ bAjXҶ/_`0ړt)&]@{B4dUͱm%E7Ai9` 6q5;A+:Tb=jRka)B51\y"NbQ^o ؎51]427Z@]`ߝ2,]\3+'0\ZT"DGw~|OSqЙatby`!\>Gs5Ј`pȜ - hvuVDfu1`wĒv9eιsƴDcޱ7P\-2O%8@=),Dfȗ[(,()P(= H.0DfB[9*̆EVAd5L8SxO 18 4b@#4b@;&qPY 9xi1&t'0 3@/\Jzj+q2XN%P*NDibEl_QpT WPDQBsB9μBX0>b bS"Z :uvTrP Z2"8*rik1(4"XDŽc0Zhc݅ט7?=`M?`a@#c~%<:ŠYS&5c_]6 gt# 1 N0"o7〟s]}$6G=kW81#HJI # 00n T$ 8((ky`D^ds'@CH7xC ԉn c`E^ds &Sڛ ND6Q8L'b9^711<>+brS\'f#\jYi1ؒ:(&+%yk& \ui# ΖU ilk4 ΡX2hD519,`08ozMU{)1M#1ixP7 Dh &fCHi6dIxi?+^Hjbp=PἏANkb1:EQKZR\/1 #Z7sddA<1A5Zp`7{abpo f%mq#Bɺ0qc Jj!H ‡o 3<r2ΔG f",h 0|=)puw818N 94b@{[ | ']~ N\|y8Ap3?sDv1P~`L v$>Ct=UљjsDAoAt&/ g΋,G{}L v":s5?hsĀ>1HЈm0ؒz!ev קPKZh[W ){ )u%Rxd 1[Sf0ХufI i\)M)S\KklG7x_ЈЈ1 u=/2lQ=e Fϻel^]ݹsN~>0P7ҍ/ 7f]6RPRPSW]Ѫ4Z# 4+ٮXzFv1p:/$p:խ=iq'h 2g;(wP"\rў ͥ@?OoYUfnv0("1X:YNP9g`h׉-0ўk'D8h6M9 ,ߨh&NߋXj'q<҉G"JL렐g| KC5}b@#4b@#4bvcT9yn-Ym}FլE5K \P {6bK |Qdx7F5/*tsbl*#uh yiՠYWbIW2ƽɷE5qR?9KT5Zu4 4 隒8-6 m`19\GC|,N+YgR  , ym?nj ̠:$niX ה;]3 @njD5ۼ jjz' er:S.=S[}|4m8(Ԕ/j7?)w5v"c`:|xGIdoZE|km'sq8>[ hĀH\ͼ>ě\mayʿו!#r]kw6m'RFX&TU\YgvzuQ )1ȝޕ>{{f,( =>PDnG1дI}E>RM M: v=[k51P<7q}Ұm51>}z] bV |: JPɏbW^Y]>y]?A] k\ʅʧNbXcf k|\arR~GXKp׺Ј1 ĀF hx:$|x~لhX&v_F m_FL V09# K#$ (0RnC AAEд|+ 33h^91ݟ0H͓+>k-形d6kfW%BpZ.›n,1h} Paj: uYWUaPbZ < :{#e Vr9vŠda`Dpb`a }]oVzd%0G̑Rs'ga]~f p^rmn G6QhZe!9\Kݖ% >m(X(e/1x3ńg1Pbp$ FѿkQģL~4b@#]SHmA5IDATsGLq uLPڄG!܂Afnf00䀱7vubp&{iZWb"`Y 1AZ풫j.by Hd= l ҄QÊX2ahWa0uhQZR3EZv|$pGn^E1!1 c9'JhόE;уznAdQNq`rrExJ F9t6s}B?.-h=EJ7` [Ra9%. 4u@d_eD0WμFh(b@T3BfP̰ ٦Ƙډ~$yfʘAr=/LT߸$u МϑCVTޡ BEDx.E)*_؉~)3=f%)z6 Ph6usӟIZ B7jj`:"ډwty=@ uٿcNMi 01cyĘH ] <7: Ea !zk0hQLqޠ.- jw _' 2n`z "j(- of1= 17865b(ThzT`4X4b@#4b@#4bƩKb)]{^A]Gin1_'mS:$1s@ ƒ0 1x!"JDu?ml\9^E9vw `ԃε1E/Z>s,s%rbZDJ/K"NW MSSHl =P =md)e rmfw 2ub˂NNᛯj9A!G4{ rr @o J]gHq0((vP()HP9Coro@OV b` w|DԸrm5רaɡ3fi285`c7StuGiuPZs^Xvuxs.m^>zy{MXi+ p?w^;ԃ&4b@;;-6=sVxG J]0< e;A~a6MԲI%*jևq#H̗d\NjJYL獽8J'74a`RR!jYkCJ.3ӣx(Ga\CZ,L)#E69GxL |J݂BAl>y=K؂A`o'a ] rԲI%@DoPFUq/0 01Qs5V.uVBOq'-m3{\F1 V鳉b1L}` 4(.@ NF)vXVq8kb e0]1#7`B}2vT>Fw0}!7o/8a 13iY]\g n.ol؇vp dǀF h`18vc*186 -1Xs0/0 1Xs+.0j*kE $G?&GRYk,v/8ZAF 7XLe d%M698ҠZ!XG9=Y7/1 B21Y104u˵c5%NoW [$^{k nO98"w@ 5N;E-k͆2By$0IT|z#DS첕 ׌I]I0rI5cPj'N@&\BApvs Jzmi˾kjLh77 ;Hzf"#&?@19`Z`R HM=RR4AB1Aa%Bg y9]6uAⲟ'".ߩB npa[L'az`$H ʩ01Zoѳ8bp2 D4/`6iD;vnh 55s|0ѼVb= kk5CۙVj0}LqhV"`6?r`D[`%g5јЈ8 X% M/ia&U.tlZޝAhl&mpRZϚnp(̮xb@ 10;t@npbpހF.ٳҩѬW 5lSgI\rc lLb*  zY1"s H)bZ{ d%_O!t_i  d7Af'ꂶ<>B9RYQʹ],,[T΀y1 M,k e=_}H7R6|*%1xBo W@FܩR!-"OOI]mw*yir.I ؎ѧVtUSNM[ŠiP"K؉t,|YٖRf~0vu]>= iPp`TTi&܁$DL ( ԋيtRYIN€8 r^9Oq56P g9sLْm}:jl&b.Zu7^RoEVk?h`P p ΂s:6Qc^w}V b7pŠu3,ӈơ6; 6 *i{('`PpȻjJk࠰ +BsA >&hOIWK v Ga@#bb@ ki'bb-dvހt7(C8La~|=y 7 4b@#4b@#!G2/'@Vg J·AoI A^6º>y Q1PF2]%X5A0tBY +I86)y19EzRwL NL b =S0!&yB#spuvĀ^bp: hĀF n8|ϱdo},u,Xb00ie~KI񰦳-=ΒjSϙĿ 礗!RgbL_,|&.s*i y[ϙ1oAG*b>gY \Ոҝc,nB .b2 ϲ`}eޗO`N.bI1bZ9aٚ>o:~h5tSg#j'l@r:OAb;S@qH'vǡWLfo@ h;Rg~1vͪX|nY8 BȻ_ua_󘒼zĠ ܉Ax=j7"ǁȜ{{>fig5s9A\By͞Ȝ^m _C g<:]o0+A!= bqM{޹G\9(lJugO6=dQVq| TY#Јl@ӎ,xl' zpW 0ZggD缤j;cC@P܍.qN"1Hz+"wZS#$h{ .o${ h }{5f.ԫ. tibI{[ ا~< - .a@`w3/\XEi5(lY(7b$ 0b@ Q:v73:'Š,,G/TH G׶,'1'4w%E9v 6v*rj #Ξ?i[ pҜ0(KM{ֺy׺tL} e(J(p>A&<RyAaSi#^ h {Q# \o`퉾A0E o0o`z/ֿP_xLAгD5KoqьKt)0cMM{\nv(  Vr 1uaeYվ?]ˢuZqNc6aSaW J]1 ͱ(4 /S7^ 4k (4EBl@]|}Ь2(fu"*w[7hB31L +HЈw嵇yI[˦{ 8fbb0WbV/ nJ .Ku-uP0Z6t4D{(ZUtY0ΙL+r9bvrA^Kw,XVͶ̘&cn_Ce 8d8i( KJYLur-q5jR[^0 Y3-Gx b!O 17a0fإ:Aj@z@TჂs<ςv`E`ubJ0kB:KW?`wcЈAkqÁ0Pvk0c0"4OϊCn^i@7Fa{]i{`UhvЕEAaMhF 8 ̴B3bj&0v, л*0s`ՠ"4,]fZ7ӹ7 a@Јh5}`Āb`fXR'-b9V0 )b9G mXii{  ҐlaCIJ0pσB ŊiAPN0x.I_"; G218o5-}-JҬ@KjIXIMϺ=ƴĀF hĀF h0.\z.V?׹Z)"f@JnT8- ||55UiAlZ Dj02`iO"ߵ7PÌya0-oO!5 iPk|o1!+e bmuR1J X*A `3[0f 18aM,浄>bu2jqb_էhr Lkک0111111111 Ġ>Scᩭ¦!qcڏba&a¶\H|uG 4(6购ˆxռ-ư%6vNm9 vL+)ǡZ͒(^ 6Zۑoo`&$Ub``#V&P1m+ 0`޴7 {r$ A.]|98 |0PC ~,Mh4٪)6,Iuc[bVpl5b@ 184b@#Ā111111=# abp "18;~Z*C N7 Ng#X8%@4bpo ~(b`grjk(z78+jĀA0rP8%>X"7H{bF NtZ11 ĀЈЈ:m3fh?A~9 >hg_Ā| XotIME . tIENDB`gxemul-0.6.1/doc/20081103-openbsd-landisk-small.png000644 001750 001750 00000075031 13402411501 021564 0ustar00debugdebug000000 000000 PNG  IHDRagAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxԽ]p\ו.h 6~H@MԈmNUyT*bAD`."@ Ud@ ,ӟiFC ;#@2 @I_ؤB H$A . @"TFus{LF*ol?ja`b9Χ|-RC7'a˕ӓ+;;wj?><||}?3XՏD&=H@ @ o[BT4ad$D` ! ӥUf"cA3N0*7B H  4S[QM ]gNZ'ѸTun1=Lv^y^ן?k:?wM$$r *]?h6aD(Fa@ (MW@M:NՎD T H` 0ƆB,jD(qf$Q `JH !춀tm|>oh[(RJI)7B$q,Z%TJ1N‚/"!ij9*DDSub.hG:Hf7D(!݆=8虲 }}@ ! "HA P(hc6aTR|>`믻{xxaZjiF(({￯{Gэ7oܸh4|t]JRTvvv|eYBx>U42zHjD,j0p4{;k> 0WddWkP [i<"5h's# A79jRnj5TƘ`s||EQTZiZV;N.^iY K.ziP`d21ÑI=]d|;;ť՝?QE/B6wpYL)(0eQd["FQdGQ0V57}:lFjWWWkǏ]]]]~򓟬'?V[[[i{|~4}[jZry#pyb"󅗽s#ub(c;|'R( ( iOVVjh"k+eٕR4c@(Gޅʊ4K@HEʲWRADNBD$0r>{.ZHFQL$˵h TTH05D0u]6izΝǏ߽{u4Mwww(O^w'omm5M*74=>>~͛7G!EjL&\Mhn + ! ' AJR)oegVku%"^[PJIe'I4+q" !%MR.ލ V ,e%I'i%_@)Ri6W2x D  |Yu#QB"bJȑ6͜Hʰ$|>iÛ7ouu뺎H)o޼i|\.s^yrgg'ϳj󗶷$\_T4M=ϛ+tJK%8 }<{l0ju/Zڙm+y6;˞ J0,< /`Eqj/\ r ggq" Ij+bOr\)Eѭ[~Uv].Go|qzG?Q^j8NmێXZv||5֭[rw~{oojr,<<<^#\.Rk;-MS5+hL&MSuKyl6x>gEa1_m!o?yxpuy-W+QI׶ժ\`Ҵ?}dAE{Iz<\h)1 e5K)/JM,&:SŽ0ŔXx Ii]H"` ,s.G֫fR8&www CN?2'3?fwX677뺯ޞ7ƽ{{=qQI)ǩV|o9?~vW>N>iֱiptxw8LaKZTOYu"pRui4Y_{A L03? hz8knye1\{s.M ?qYuαi4RuY`p6y83Xe}Pk]VYxeeu]T*q t9J7nRa2|Ϟ:J (i%W,) 缅etJR4x!L(Q_.!˛w꭭v]8\^~'~PR4Myc8m?9=l Gނ2gO>,؃Ƕ8~s.$*^:E< 68*4 ~tzoݺn?şX\^^Hu_]?dW*FRq&i|K7ONN88v[é˶*B(ՇÉdP(<_Ynoox2;a[zn8 hAӉ(epe@>J<dHk.0ܻwɓ'JRT.[l$Y)?v6;wxwppfwvvVWW9lf[nmvl<ře˅yJˡ@1Q)@ ťr{ Ej,h,/6v-YTeJ|RjD }Nם/laJ`%&̆LupfI1@F¿ĪIZ-߼y3˕J/}K|>yǑ-6]4z-?t)4I$ݮ:|>oSq~R \AER!\ֆim$AQjcu mk ᜖tE uyB8 d 1`0aTbفRp1-AniϛR8pJSDF1TR9Nl6DZ!""C䇡vE? '^'Q&d2}JژBp: ܋-bI!hO\}!],LJh)!l`Fb ԃ*g#ZVu u+˟Q})x,}bAIJ%K|EZ,)U*G{ B! jֱN۝4/sa1Bv2eٮ!b1@Ni2DbzcAVYF̫*#DQmmm9{lT_T4lw:mi9`8_L\VV9nwnTPQO8W,gIbV ;9;|Fg2pELqҞ@YbFOHDH`PINRyw9vo2lĪ6 9o*CZ-'8}G}4o߾{{{\cDbww &q{4mooJ~駏8n2r٬ ]kۖiBQ ^Rq|N!?0㱲,S/X,4U >aN]b-\D#"BIdVV9+f3BR ;ςL# {q8N&5Q->2Rl3 ;`Rfxs0`ķP)U4LmVVV۟5׮^t{WjQ( L&啕WvJp04.Q(O|t:No T66(vGkB,W w>9f:O<_NZXPq/F?h}8W 0ӿ{{{%}?ٿ7ڐ#xe9I#`YBHGQFtNJނ;,K زl! PΥTїU. |[UrJlHpη!D۷R|_ofݾ~66?| dNl`2W*ۿ{>zrN9]kʕcɏrQXHtA>N/-{O-MYg2f :+Wnq90.`mg8<ӇNOO8b۟8J 6pјGQN;:uDRJ3#]3b;3s~f8mL%51PPCv{~:NX, fu7nݿQ9ΝrqǏ we_W~reK7/ʥbh%`8j@0BN\V}m חWWt! ie3NXe'}yDJEϢ^F[./4Â%UT͇4Z^VVr{=zV찜ޞ\p}v]fm}vמǶ$MEa`LEsh ϱڝe'I an?RQklj!粓l6|.p.UEi—̋q+>7*n9p$@j0MS.G3*R2n5gnNM.XqowV*K+7660P25oZYYql? ytKKB8SWw y'?rvKv<<2zi|&DBm`x I#tU23w޽{޽{0 D**lX(L&^\rQDa5EK/\uՕnG ԍdJR5"xd<eqqʠH'xãs] fLuW]lDe#Nc\E߯T*v{! D$8A`eJ ۶m& Z0:E'W*s|U8ն8I5AVz \,}"}^0Ϧt;y0+u!!iA@ <+9E:d8"gû=@\n4Zx\b ܻ/^r! RH1*r6b}ӂ|䤣͊Na^Օ8NS4M+dskk<3[Џ\_ttu/Sg5H࡞粊f]S O>(Y՘߬0v̬Z' 0h/v;S!;]Q&hveͱ`0Or&swE{a,Ȑ4#yK}em-Ib!pV׉(\vm<^l?,ϟ?m `4ٶ}jo0x !n/--=zfnq.k6 _!886\ IDATL&Zkn/Dģ 3 k+a\jH,//)is2\ xZjT'8̆T]g2+++Z4M|X]F?OQ^W9 9V}kV&?ubOS /Iksj \>9p8y͛7a֭0jr2n$ܰ7Z7 |r; VU9*}9L}?O>ytLF?|4fG>}7 (Y--Zgڶ=iֱ=?rD&N/D/-m_TSNfY-V~"D3@Fai}w?1nݺh4(bh6WF={7Vw)\8\L&_Ccіe'I@~e;lMGm;ڱm?mێ ł&IRdVĎ_kAsw Ltٸ$!;dKؐIJ-u=mSݙA3~}өq|<|?L*(|ѓs˷o ? ; K67)I+XR]v{ãc| LokYlPܞ5a?7g5)‡@Gqh46773x<6lR7oۃhiӹuwaX~d2RQ/HBf~FPf2@i (NTێGB䥼_\6qa:Ji^1crɷ-"!ыx,F T2zEncWfl8I)Y5s# ү3W(_[q'p}VaׯNOZ>W^ٹA(ϟ7>zVE׶*ӽrz.;Wv(pLKvbA9J)O C'4\DE8g psݍJ`ixp @͛7]׍8qvvvv5 ƫcw>G6?|Pkj'1q#@yt1SM`Bp9MSq7 ӧOKl.zRׯ nv+R\I(a=n8\Gs~X)=C f!4D !xjTv{qwqBLj[n5Ks}n^ly_$iI?A()PkuuzR,? aj77`4h EF9S:q_\ޮ;|a.r){w6GyO!cF)%'{o_~r~efJ)D?i vQ8 2.0,-YAWjv{<X,T^V8]v BO`HgcK,?<-.c,HDI#LHIS,x%֭[ju41B˕N&ay9"?n49iJijY0 0Nl.3D@DS/{$@ iS޽ߒDeۖR,@'c]?8R%u G#Q@!ʕN>V˭NOs3KټTȬs9 NGYw7$,U <[\ 8t8} D1$q$I:҆,eAyQ(y\fsJL;RR\w}뭷f\fDWJy]67o,J<*kj0i\^^ Gw RayAz2\weye0 yE'~R80 0`yflvRݾx<@ZDDe[ao ,--)5FF#(?4h)juԶH%)!ؖRʊTsL (I!$)AEڐ1%0_'~ڊ7HKDcJ <G=F\.ǣObzj5&8ce_6e8Z3d@ү*8NƾF^dRmۑR(v;na(8jZ5:l;.XjcLv:1f Zm)y dhmP-[Q$.h1,G:(IT u)0IDPk @LxRZ ? @ ڠ\bt@!Ȥi.'#<}ܽl6}g$eo޿oeV;v]hL&˲ߞ-cdRqnf֩CX32>OɆdDDSjz!D g`Pdr2X*K"hf)@ 3)XT*H$$IM*GIƍloqccc>;{nܸۙL qeggGJɟbPbN̈́BQڙl?*e#!MJ\N5()8 e۞#RCbB:.-}Ƴ=`;YD@ev?_\jxYyP41DFˍ}f4o ӨiCȿ#)FAQBH ATZ}{RV^Fc4ݺu ߿l6ݻǦr%`#y!޹I7#j_@b8->kYT(?蓥JußtbL=o:n勥Z`'_rx@s;힟<#SA&$(4!Z'R)nIh4j0 o7|w%dÿqdY%eӁBl"RI5I1eٙ 4JI(o\ Gf0RՎ0i!d@LDdTI 8qO?F`~eYI,KkC4dș aw!`ѩ BAF,J!Q(IS#l۾}6WK<yGd2޽{{{{ZCKtskWBR97~򤱱^V~~d\[9cY-f+5Jӟ{7lVǟo\&qFK˾ؖ"kWolW#MI&(dRׯl6?~.䓇 ۱۝gO Fh?`::>9:2X*I\ 0G:lGZO>dELr(PC'BiyFqjCϥb,"@O0( B4 U>(D+a )hmi2R3t8 R͛7+WvwQ'#gn&ɸ9MReYWnQR(g+>Rx׳ ;mY?荃RRI d4>iűm;n@ܪt8IZLj޳gel.)׈&B Y"4Hk#jAJɔǕRJXYҩc+TJ)(jc)9B$q{~pNvAu9md[)\!_LDOʕR5I+N&cY&sgO}Gеa|0ZK>{Bqgskk+plpƺ:888:j]YI1i||rAXqH]w^_8_U7777e'Qxtr+^V[[[[ P WjN&oz1H` vNTJH!i )ѱT)̩ό^r%\.oTfP\{.=ܲeB)J kkZcOH<^a*Rh2 ҩj0'-EMFN&AɶԃG BMDN۝h2VJEQ|xtl A/:t&"J!`8P8Z??<(8RJg$d" { l)d3"Buݾ8D(HHf ctD1PiMV&ԒBk5 Iff5=3'qV>OWx>{f1vZs^xpuuW2Cd2dRl'j_pl'ɦI<O^}eg|~#dP M@dXJ8@E(PID6F)KI{0[ϟw۷oַ~zoR(Ex\p]W)iRD'I4ñ1r4D@H2;!TB@'c83ؕ޽{7G[L\d ;N>-( L&kY ++GD@GQ,Td4LR^r||@e=oue%IR5"_Y2fy[sԀ 2JqnX\'aatukWW͍u.e[IY.NN;4{:GO]D(BI)4iD²ev1$4,;d&F!j83ܹ=orm{GOZ CmLֲFa;"BD۶+e2&͞{L\,Z' ;WO;!*MRC$Rjlk8IWW֣8>lFric,Kl.t}} \>'1imO;nB۶kN8X_'VP,  E2 YMڄd3j㜖1:MAICFY OwdCw?5 q 9dqSOUVqگa'g&2kkWNZi4J(lN>8=IQ^k!pm$2Bpmzo]8 `!j'RqTx8MOC'!OBhCDFJA"RRZ,q`@R6d$"c%͓EL6*rxD3 ƌ1ܱW&ɿg$-W*'ޠ3:LvR"#c 0좄da9g`ZaO b21|>wu01d$MQύŒKL$4ILh8i2xdwwwy"nRYci v:XU>;ܺuk>׼GnqVb\ޤIFPAl.(],țxR'R`$WCQLFSƱSrZc[W(Խɏu'vϹ7YYYdTlR"e"L靽aC0`/E 20hho ÀmtZE*XU9UFD< HLj}xbAzy]hxv~vnhL @ YgU: 9gi#Yx: N3p|u7ZF=e)D;w|׉nwwwΝ; Oߑls{~9r9~F~ɽ'r'iH)7ju6Ng^O~}cCpҴʰt|2.Ga2 A-0ntMҼs_C2 IDAT'y8i8;v/T{o D{Xc=cJ(^Hej3ʣޯ`0Ȳ("u6i\h[(ܯ+++וN{j7轿( iE1Ne(iqaRDR^Mλ@jDcLӴQjcgI]U<|wQFRuUs>9=;>9u9kҗΚ(&WWsʢt䝎1:˲qU)oPU;@4 lɵaWEf~1BD8I)!R> =-fp8 w}7PZr?ofgc>`H\;JwޯL7꼥LUp@76i& )j4%=~lsmp>Y7xa?OGOoo񺪴1;;;I32*ȃVkUF+k+{_Mē?D*e!pͻtweY/ Xg^'hOJn LTè"3(>ONN$Iws2%\($ɯEQcR JV}Zx/FTe5K @Z(}@ƉQmt5s=@ ;/| ,k .-C},3Q꽗?[G5phLZ}t|(Z eɼ*ketHg5toookkk2\bd;;;גi " 6ƘV^y) GOVwL4^}U@ڶ~QOnmyg;j2%7o`R`8" dzG=X[5JG2v '`8s^PcB>ャۛm8==~>+~ƍM( uԳgONOsD@ث^isF(%rʬvF)4AG)/ jT„=IY, $$IrBHIU;_?Q~<eXieU"?IIcEts`s5 B>C Ŷi1R2j2A H<}F))HRlAHbU[pI>"@fָ) 4eщQU5<5pS:]1ZNB1߿6Fiz޽Ы\7aNo7M3 0gpF@gYpn J5ەgiRF֨g{FovܾqNmf f`<4ZN[-v[M5E{xt|KuUIִ#Vy?'0ӓӳwn5"SEtq̮.ֽ#(Tk9/ D (u1jŏ>Vd>{D5m%|1O#eYEӧOwww$>88Ҕ(g?krݻ;eFQ{5 _,+cr9'nρ)X,e7O#cQ Q Q<>9ETm[l>Nfs_)y,Ru~ow8_!?΅IPbT,ŭ/УF)wf~nMYI(|T6$;!dkkKJ7߼ fnk_x<7n [7έi(#~6_tۛڸ(mvs0f&{ryy^,-R:oHv{ANNSBeQl$\.;0 y|/3bDRiqqvrɘ' GR٣'\%x$Hmu;O<-YݔsZq&(P!,Z Vڟ9bu%~#6DUWmSrW'h*UMf@jb9<8F2ں:e麸d mR{MUS? T$㫫I4I"6"H)gYҶ`{G<%!~Q\:06޺4NbC0<3g=h+,^ꇏ;^wF x.dk{O#DqbC7r͂O8}O4BT+sjhV_m)%@J8U-NONWVW9Ja seڼ\/͇qMָP"Pƹ0,eYzi{8Xc48Lh횦<{nQ,unmm5b>sΩ<w;7y$hqH&ir[queژ E pRGh4ظceo;yRw;]O[&uY[igWgcS!3RxJEb(ՙ'QJ*罱6j=T8ı|t:ÇUUI)NCp~t+UjiKNDmZbfV>YkC!D(Y4p)6b)d98ODFRdr.{Mp!Im5|2uL%L#iEjp4\ΧYgCwX֍X&2o-a{(ըJHZۊp7*?iǣWLyfL=9Xx<W㗿 T\˕븪}oywr:Qj[g )(ʥ>)z(/teQjeF+UY4r>/2K%6wZ)PD e!nnhmg^Ij!DkI{ku;><ژM,֥ܶi%y%̧ g-/ZyRuӶy7kVJh&s{kÜY/{] "@G$(#y==x]|~3 ~˷8Bb1&ɲ^'L~V )sH!EYֶrnkiK&`H @cŴ,7_uV΃#0"BkZ@Z_\'EE)i$M;eIDRe#d882NEBvR-@)1m86}hssz&v`ww7l@ ăЙ?~;=D,2 HOMIY(VrVE8z89UYM+d,oD@{yմqyb(eQ5ZQ^UUYgc4b>{0JcapP?Ig>-..4IGa8䂩VWVkମg{7_WR'ibTrJ!Drx`=0 ?J!hW¢ItWW<G\.qݾu^rX+$m#dڀuu`1ܾswu=Xk~n8.ϙqY¢)寬IN c`MKI@G[j!~uul |yֶ6N'NDJ aH?-)w\ih:2D6xi`E : 2'zO#ʑ3y獵֪sDZcey,Y,(/p(l0"rϫ e*G9EΉ5YV-K8HZezaIL) %q*h A9޹$r42b%8M$KDD]re}fr<$HoܔF2:88ܢ_x|g<{`0HÿI0;WGջ'飏Y,g@th>~VWe0LQE1+%Lo-{YhIey,E;gkV0Dtbz8ICgli+:cjKe]8[O\PgŲ~8[U9(+rzidg3kx<~Q7SkmM&? noh}}ӧ{{{M|Y}-]YYywov@hcc usy׿YTݼIb[XGO[\O>7Jx4KRr<znQYgju<я~m i'̧KURH;SVifY0Λn](ۈ$RGzd,rQhB)Z6výGeƚ?OQ=_LWY%G_GUÿ?/HuQV͍Ͳ,bY.iq\:N^+ʘ4I)bӔeQHmfu76wEY"Rks%Y8bYsRڶ?S޻85yc ỵe2 {(%X5y1,ģlc651mSO?;;7Wol~X_FDdֶd6TEQdޑn(:::icH "Rgmg. dpy>R@<,1b1Z*8kD)նݴI]R\eݰV^'vbyfS h=l0 wd(~k|((AeYOiZIA>V=??_#0 eP ) h6eUO?BbY+byx ƫggg/tgrq|v1'Ivt|{k\4U&h\EޣwFsJzҏz[!9ZR$7UQ{ށRRM^o{{XBnb@ GιU,=8QGQE佳9gѠ(+@BhC%ιնi6u`B8:Nh~yu/P(&0eu$%E6gKDy PN<*UEqVR@`wށ%^c71D60J #;o:ڗS'd^Q>?? A<4MUU!1a{ݹsw aDvÇ3,22k ob_C}WZ]^ͪj#ɩryyUiϭsyVc(PEct6$lzt| z^Ӫ!{LJ$;rLDi-G8JEQTHdXƩdYkY\$"q*H>D{OŎ!pzr0yͻKMnvYYOSO>d2/,q^+pgggiPΝ;M|_ɏt:UUmooyC7HAvvYVݿ Șykwn7U l9[a_ΦnGt,(t:uc3$MJ9 }h>߹}[;Ҕ卭N I?/4 R_~b6-oؼl?0.ϟͫc.=A)ēfq%2\dimf!imTKq(ʀZFH))vRM{/냟_`A< м^}fn+a~L,s*O(eι'?ιHV^"͓'AԶhjɱRm]= oRvUf8 z$hu!b ΜrVZZ l 4dPEIՄšEo08?93%39Vq$Lb(6"oyQa9qD*{I{oWKbQqDu:(¬뺾V c/[V%z2#w(x$@8'"Dgw?tiE( 8jSm QnT큶J#C.D,d$ƦQ˪ui{Gm]EmնI"ge0vww !u]߽{7x^ߺuѣ06٩|www{{Ν;lOc2mJ{eX̧UH]2Ό) HA+oRJSF9-3B9oF c m""key= "zO@l&a\ nwuEQmL,릎.Jy=m/^^UO~{~^RrEiMhߙ. zen70~:Q_Wrﮯc`ȣcqt:C$O7o^=yYt8IDA/fI-:D{HʈqV׍U ӤnյiO>}by P x!lW0(Ҁ@y, o1MM4uCNU5e]YymRLƢ۶m4 efO(cGW1xɲj(XI竫;眦/ L*ϟ4Uy|/Ңyݔ8.y4IjLS(d>6M%qXp!bwY{rvDahm9GBAшLVJ 7Ų^,fηyz>=p]^Ͳ$!}j(R+%%$Rpp?-JҡsOY'OXZggu]Y^F< NNN~4M ieW kw5vi?Iѱ$"Q!|K1X(N"kl7wwWW׼8rg2e@U*D"X,? .E"(2(z8G9rÈ)cHFu\YdEL96 ,=9>r$W2$t8nmɇQUymvq9YV~ly,bX4[[Zw!bAf@rv7x#d veq.S. |\Wj)AL]C@@f01Fm,KxZgͦy Nf Wԃ5e'}"dzUQEQ9r0Eh8j[6l6iwJȸ\̘{2:7ovr[DžL./|6Xk^rʘEV(,O>bN+c.0 2aIN$Y_YU_D(dqژ&O$x\MZ]\d^6˲ ˋScɏ{w}cc9Sm''7bq!8}G{\DIb=},ͳ(O>4rt?{ꉗ2>;?t IPy7kkkJXfGLJQG88IY]͋(,uiy|aԢm(YJM//2f#Ki*][M8H,,coSM9^e*Ύf^"`8>87m2syo8\ckm]-|_WIUuiY$g!6h+*˲Z5Il2bHt,x%ZkNzqyY$Pf,XOwM.ZEYCʺi"JiH ))981B0 Yˋ c[0T7;n\_=uflVq7[vr6u 6(rskO2[kGw蓟e~jB͋ [VWi9>>2֮ zuMGnYw{c]'p~uy "D7QJYFᱵ*Ms|Z.V-Ҟx냴;〸m,B emdvߜV]^LMa}s AU,|kj8Q g\&'s/KyOz8MK5^!r^l"ݣ8ZbDռ޺T:h"",q"rh-Msgbqqvv|wXY?Ţh;;^YNZ;뵶eUyq9OL$sC4dDm.NGs(JD (,i&#QV, O 紩MkiʁĜIg֚21\rdV[1;9{o#yJp9#P?'~w? >]8Gm,:H^b ZI˚SAC#an&&ez97*IɲlQIhP@_g+^XyM'ƪ-֍7=DJ{"eFxv>lLY,rm5k ֽWsZh<::9ZUzhX"#v7m[nc k[Ew@\thTm4:upd,sYk{D6M%Yu*H3oNg_|~?O&G?}3X$ 0@-ic6,r*ZȻE-Fv2 #J6d˦޷-ASQe #ajB~+]0f2d_n;p0ҍ?_\^vRիf*;j ʲw֭^?M 6 uepB)?b /لU¡K+8Vj}g^ONH !X=99<+VW=>vQzkctZv0vl$vt??0(Np`1_VENխoeMf]-D_*ĭqj{~1<\fR ƣONO'#ӓ!s2 1eUZ.;R $dH2Z*E2T(7w~!<,ϟ6\J]N9%,͜,l7IY>4I8|0Rn* 蟿^ ńQu:)P&2,"ZRݯkkmw@(a'݃~\Z4 ѹcw@?C~YLżnQ e|>۷`)ݭ$)+rQ IBY ⽳CiY1|.h(^v03&^T]q0fT$K͵/tIME 3WtEXtCREATORgnome-panel-screenshot u;IENDB`gxemul-0.6.1/doc/debian-5-small.png000644 001750 001750 00000003056 13402411501 017175 0ustar00debugdebug000000 000000 PNG  IHDRtc}6gAMA aPLTE8Ew  %%((((**++++,,,,--//001122445588>>CCGGLLNNSSUUVVXXZZ[[^^ccffhhhhhjjjmmmmmnnnoooqqqqqqquuuwwwyyyyy{{{{{}}}}}}##QQXXZZ\\ss{{AMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDATx헋SES3j#j V19V W?6Ͳ9.M"1 3H`de?}{sr<]˅S4>V,hT*^(FKcXM u =;y#gN+NNNLzq3/MN~3Mrc?}WaG;yBC:::::::A`%xarz~%Mť J.t+8{Y{mgg{ko}ec77w~^uO:P/w5mXAT;asaIb g f)ͫ T\I#H *әXˍ9h!BmRB)erB<3VeO*%3R])j$3VT0ENeP%+-ѱ{tMo?GAGENMINcC꓂ЉI]ir*)Onʒľ2Pµ@&(2ͼ@PE[P*$p# @#3PW &?!&n^ɷAexaaRVc:;&O?qzł dHfF|/  &QYjT2ɘ#,D{ ā OD@lH p6: [KRP WtM䤘8 55c"nj-RM Xx*jb ԉ*V Ȁw[l&Kb,zpp:08|k|ƨDYH7FkM͡g+G9IVs<kn#MS7i5 +ky0F H47= `+ $Lkuyos>RAۍRl@ k?#ΡQ|E7ֵIaxZ@TBrAE{- LJ J))@\wmjv(ֳ+)Z(L)7 ߋ&K aug<{{9%&sI&< bdI1}{fXېQ s:jQ?s":xC;GV4L3W$BxȽÁPxjy32~bUa_Sb()qӞ_9<B*d2N"JCqp=)AbBB%jESB"V1/vQaw&D@xE 9<̑p(@([C)acR(M3ʃ1QDs1C[ 0Wx3dFj!kR3t: b+w +SK\CWB!%6#$&_Ie%n2T19cN+R5;OPj8%sR{xRNyQ3-وӂF%b71k+11`#X.6X_A-7rEHF1!$}8a8/siZc-բ`"0S&29  F4*P-&2^-,03)PIQ7,**v_7<]2RPT%) }c_pwm!NvT<+!k%0(+B͙*PlK7&TQ@is#Pҕ2a}/bMj#Q}%wu_|wNkq[b{=CLp8c1MA1(Ucujr[2jQ:Zq\]QA8-`P8Ԗ## |!!p&K$B$t*T&|b:o5pKTaWL\VL*Ѩ91 6H!&"21 0vCc#y$D<x"HZ#'մڹqyJ*b(-pQW<18t3_1%Srt%eP3t@i42%sJY%`r%aAKq2R'xt%K<&K leINY5#GIUguL̑lODe^T<%c-?9]!(V;j@SlO`j;8Eؕ1L9"b!Zbg+:c0;#}(*,.02-0$;gxemul-0.6.1/doc/20041209-ultrix-tripplehead.jpg000644 001750 001750 00000217543 13402411501 021234 0ustar00debugdebug000000 000000 JFIFo CREATOR: XV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d) Quality = 75, Smoothing = 0 C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?/p>VvyO'@zp`W mE{b㞤w&S85s83IhR:~uzY*4([oe 0B*$%&+N[V+K4Tq'"-Xn*3=%Cen7u-eRH~_BML5;x#hTIÐyj[.Jc[I5prĮ@)?5s )C+sY{5,uVTu?204o:=jUt2 ˸`ս'@F1NGGmtײF])?jyU3^:)i笈nЃÚdy$p1QW42.۩+Uy, >re9!PvmsUQlH#{0s [,6*i"DCUFΘN3‹hs+%GT c og^݅2v"].ˡE>#In8;#+rYEDOHkXZ H+.4t?)9B^l |~PCohIEuaU٧OEXGtUL<շil⅋`zem&j*f,E*CΔKp*I U޴+dUFܕ2;CB_6-9%O@k gQH1R ێZڬ9layhl12#6x?7zEF 24=V1g&zB̃5>>MAS_9彁A ҳ8?`(d`iҤ =j3Ƙ_o9'uV8rF}?Ÿ~zV!qM'iv SS? |TMk{]%_*1HČ-b' xRZO\S;M'&SfcSPڲb8QHnd`ILTP{eOjx~S?J ~*xWyDžw8Y/^qrTor2튒tu(DECqu M-ċc&5?Z{#%:QJ=?Zt?%Ԃ\Fv{WazRԖ'Ҋ(=*/SI旜P;PH~Ύ{QCw@Gz0h4JOh/4hkJ7T;|5V'Fr~52EvX[.~(?\4xܘNF80yNVsKh]@99xUID 2]܏\{Up 7h5nRs 9#\uaHrא*L˜n<9b"YnK02㓞} ȚCnfcS7D]e]Z!lU ?؂:Gn$o9x Q{.f7N)\ @]g/Q)$?xw χd0HPw<~QiV\,Gr*鴟)7uFSdneVQtr&I2TαP1,+# IXQʙgW0v Mo |O_7c$` yt3JO1no̍Kc֦t,zabqed`jη}! UF ]fvj̤Q:NyS8ÍoPGu &R3SMnm 2Vv]9JB\Vk[6XNp2 }*ܥޓ#1 V5L/"q:RDU@z #jqW%[97dߕfXM#)ſ5|YkֶX qM! =RŠiEEs;8x|*ݎ*"% _?ʪ׹hA8+.dKb@2WcZ0?tklU"3Z_Cӽku$F4MvY?jM)$70Ia"8jK072m뤹yo-˕鏕Rok'=r=]CD6`GN)ǹt\48dsE=mC$'yUxmg%Rd ޥ#Ơc) H;TdHq@c??.[RM(=*PX KEpS]x1ʋ>9cxdY"S)v()F>tpXXOhxâ߹`R{3s^,ZLY[ uUѤeQ RӼ2kB濨Y ei#ݔ!61*+Bq#fFEF3*Z"٬ɏ) 9VbQi8#xtTX@Uh"4X^:R7h%.k?:[9@:ֆevMG4)w4&!HJ:If]`UB&HQCKNbڱ퇷AT;n]bo8U-Klx #ijIVF:USO3)^h{_й7@&,2`u.Ԉ9\+ly`R.U1ֶtgpQ =xns/8BRvH8j.'d_kZ}.9LtS`>wnsz1WEx$*Τ~5Y>>AfE9Ƴw ҴB(hq׭FNHOيi)>!Xm?^٬j'?V $Kcsa˖1QTCwEh5bE`c;su⤑~pqM²az75tRuZwi9=]PP }vd48qOD%G<{TM/P}{Ԋŗ}Ǡ|3MjGk+kkډ$gj h?^VSҴ>f3,q+uZMBVfFJE5ʄ0WV< 򨪱:Q֨8kM[5P;iOn*+'jk[[R0á$dId k27POzP̥5Kp-nkTy/uK8]$Ϲ+ISx:Y|z2($xȹHDQSY3>KG]_MNA;Xu!%ګnmv `\뱣1YZM N)V7uW8C]o/y(-@8nUӮR,Xp*ݝ2CգsY_j&V dmoV+p׺8WzwoC\nwɷh wvzqXjaWr隱@Tډ =j C?'eoZQR39Za~ژ!";QHjz!pWEڹ}1"sޮ.>ꔄ9Zښj<ǽ+F 4`W7HC2GJe3qM K H3VXU02zNs]gi4Ռ휒 @}̀L}+eέC>qsȯ>u[FmOehè5ܪ7@95 CStҮQVpF[yi:Mw'PMe Һf%bQ- '^3QjkiN~C]Qp6y֩Z΄qMdLeKo5%-$CGg1 y>y 9{ӟLa@#9*9uf +[-R@^ø6§vyNIf(QSWn"BYָFٌwHW'i^G92E^zW3KaGK&֣u?&qK>hﰀƐ9◷h櫭𑼒I'HVǯa1m{8hJ6ЮUH'=yiݿQ 6>eAm2m{Ƕkt[g*z}+Jc[(&4?wr\@#]SӷkMd})`i/s<tn:jy+"b*6r?CEG}TR@\ HqX{ybo )Y5kv~ 9Y"1J?gsڔ\}*yIX5TB8h92x Ė6n=V_^(Mپ:ԞQW}{V >զ*yi #|soJ2ާ枤[\iG$=`w̝5{mϸ։sKQ>9tk_R6H'Έ⵭gլlwE/<=6qgk2ᝃsmO?+9B3w4dy 9X5'VuԜs ~XJ_ђmHXUNOxϘ\1,إf".㰓Ѹ,⻵E k|Z 5e:x *;sPOV1pH5j/xj֗Boш5Q4K/$1ȩµgV2 ʭZɏ֦-)^zcDG ֓IȰ JmAY#|z7Ԃ ;AYwq\`O8z*7U*qAbTʫ;iK;~uf1g-}:نC"{f;ŅO;@%Y.QX_Kwiv9'޻tjN횚$5fHzUR˹k&RsГ |0y*2N}צjr}<q+ؓL2s֢ހn+cL +KT}h#(`wrEbդ`i%e 43 ¤*fH?\\8b1?Ohj%<ϔV-.[$,O'gX1T"<O]Үl-6;gQI٘+4m!@9<6s(Yҟ4ͨ$`bq@O8=rkDrtd%?›\:ܛWz;ݬ0G 31"Oa]8h0w'*zΪ3D`5ɴ`LX:,$܇ VRK*@cT"18#V(>%TxF(ڠx2՟%S&UVs;zdƮE&n%b )׹Z*;u Y9DF=GR:8`{-Z{e3 W{pHVڣdͫ]|v8wmYODU52lGkPd99DdsCR_ )RP+Uy/J8 9{? t}ejܧRvE 'ǰ%."y 5Z. vu 릵˶e@8KkڇrdgiѬk%ܣp5 K8#B1YK`0B v5?!I˾,} J#Qk$+ :v:?bgQ >j9WQFtdzM4-x~HUu +`+NA]+gسpqߌ VI5g܋9)L沱,W2S > Vteq=NkF!Q..yNY>^2bVJ+6mZVJ$I6b6 I 992{Lʶx櫩@NO5(Z O=k)~@OҒ(hcқҘHL'1[{b" nqߏҵVj$= e3U:U|y8VA hκS['R?'' 7A6p4w0T tSVeŸ$SBNxVm¬v:sʸdk0D0=~MVHGBI?S\W4-9]P\!+nsHJ TG11Y`EDn'V\̙CƋ^O4PƮGw}JqR@?kF\oT)~WvqT~&hlcrOmCA tby.`/ksQ8^̂cnŻu ͤ=6#A[;DPgl `B?*i`woLL!Ted A RWvr#=soܤٳ4шqʗuGNz}E4^ǪQQZyk91H=EKUr='Gփ\2ga[+V-K+>WWʷ7 *F( uPkd3o. 'Ooʺ/ qZpr\#\RtJGʺ@rh@''3T0?*AӁ$ir>ΜOb48P1q@odh\~9J| g3Yg<,g=cb{~) gw|n"??fM^WccǙ2[Ipô+OJMvqkbLѱ\n<)9dm3 1<73DSQG$8OPn.3)5YRthJna+ a%cvu6Q圷c["ͪq]%>Ҷ]50c]4{aˆfB8v!qc~5^-"ٮ|~ jRs$PI"@R ~bo~) YwlE*>O:!\Ko$hhd#k-vab+{h=Joù>p>FƠm:T?A]1"`'t`4!FȨyu]ߍF1+sLw92?^s׷K[ۏ«jGGC׃@\g8i}m,qUd SBqCST˸S\hemrpxV^Vu!cRMFVx9!B}JEv-G8rOSwh\V[_ɩV(vG0O)$<R->LǟLflӊ׽498$ÏTOL&O^}駨zc2WB?*薣yO@>A!-cT5xF?/ɬ 냟Ƌ4-;hFd$'jxzo'W?ҧ3T 9<7ǽI?hIH:sN»3p$J4=4}?SWҒzKN^Gm-e&t .~l3x?٥ "=h E3Ɉ`kRp876L',= qU)sx'8ϭ4Ҝ4&qA)S}=i'F!aB?~t|EèJ@淋H,?6VBr:풣=I,G#S(߇ux|^5O;L˽=~ײʟM|=1<~ӱqm|o-6kn>aX}+T+H&\Zld@8 wq%<7QՙpCy⭮d$z#&  pkC$gʻU!g O4-In[F NDc9=IAzT[1%~*Z)Y6R4Aqsenߘ \5Z.ƺ,O(\6wڗ4;LGJOj=)qIGրIߥ/&>>Ҧs20pGf+qޱOh n_OS%Ԩ5u>/# dfF)tb@?Ƹ=3VѠ%əlm +OQXtIb՝Oͻ1s֗N:ݼ> hɕXWA(:~\JM"n,veIJJy^jm3WKHMYich~}kQg9|,PsYRG.3wg;l}davWIU^x8i~ocDv$/8N|`ںҏ%9-ܓ~5 Ta4gr0w}A!_'*גGOG1Iawl $j1.deM``SBrXv!n-n!>5l[AFOi%H(&?wsK,e5++ gZaŸ$فFC֩-Pq!%Xp r?:|[[`1ve`Łsa ASX<5EЮt4:f-Ɵ<~շ>3th+7 .L=YxH C9߃Z *8Y[= YpA\hJzsޑzth\8fQGbK›zIN:SVqʚHߍ5QX拀E39<ft}w(oa΄dc>YRxO/gSΩQ $iZk.xVl5n#5{-V{̣kJ3Ś v_Pܓu9烼Z[72@uCh@ӏCDϺjfʸŴVfRxrߑ+j) Cj;:L܈֢mrPykc |ϹZ.}?|^*6כ{\б|C@ y.O' ~,j&$>ɌyAa.GGCT /$i)\zc tqa\! l+oFD k e8si=zJ+_N~ݙ6I>kHqXxfgOFΓ~|^rbt{fG>˟Ⓢ+:$РaXOq[S*FqY2[{V&L#+0 ?GǭA. `P# JM<lxI?tnN=k'!9Ǎt/ӥ`1G }[?ejDJˑ ^*K"NNϯ%7QCՙFt g˸+M*͹Wa5W,sŤ1.9Ixέ,`8R;2q׭b9={>=:/q|@6_8mM 9Czkr_S:qX֞#5mJWYdq9J_QrKtƗ~U\ARc@=q= 8{4"GgũFEp>pұ#b`R]1vVw;{)/EP;d:RMeh=B'5x@?J`]Yci<˷pf!Q^H!\+;ď7v+XO,BY~8"%败@#5xښ8'e;U<9 Ӣ9蠟j12 "J\Ja\0FsZvNh\(#  2Z\r*bsѯFLܕeǹF "d?zciq|fm2Pr9H֩q-}`Aik*u_ҩ{N=Ӓ+8ڋr\ 0i MRa#1O]FxOd/g،x) dEYYd?|iiEa+U-phcR1bmocN*%Za0p\lךuG'j„3Wj^:(xWyP7vsT/}c. u8+kO/'9lc/ϭ =2_i?ʪM>5|ןycx@X.)Q]د#?Z7zL[^rA?4Avt\&Oj)$$>Ppi Y~jDZU%搞j4l)[ 6N=# zSvLSpM.yw c=՗\P:,R=9U6(5, =K7sz,}-&U Hgv!gHuew ZMk?'V'JBÁkdN1֭ s~+BHk$$ |ƺ|sOX8z]0 Lcո9Q)"E 8gM,3C Q ~u8)O⛒A3Hpalg?rsHD?2vlywl|rzzB )\)B9$&c]%8W9r(lζ*@G8v8\ah/='~Z$>랗2k۱Sk-zpAW#薸=r*֖ _=MQ307ִ[N7Jٻͳi }bivېz$ =[ЛC6Alj7!Ё$Y{7~=zR#"_'S*u=1P2tQ|sC#1fNMd=r+m&پd>ƫ%'S4R14Of_ƶnM߁{1Nw '\C} kv4!Y/ƶ9t TSdjE9)*I;OzMZZi+N852kX|Tł=kEr\ȫ\֬evO+QU^C~+, hj(g=E ϥz漼ji8ϵ&{$s!89 nOr^&m |:ꮏʣߡ3R|.ēZc?Z8\yRy:l(2 z Z4'ƼP r?J*3 zv[RȢ6]>`r@7NS]Z#ӊihm!mARĎw{|<"&6ƃҩÁ؊HF2q\O#io'u]y[ыv@Ekv:8(~$T@OTyvdSO6qہK}pf2q#n3KFF⥀Q*GoA9dn.*GvI$Y)ʣo?hEEG^yVgC+W vGЍn1;Uz1F}kqwWO}>aa\neϡ)^E8&Wч-h|]`8‿{-89T'?J._+(_˰lFHTe8ҁUu#=(LE piIb@sJp0VFYBs}'sklA7hF0&{0+]Au|>2e/a |Q6zUƚ<~ur)g[%*{\ϺgMKю)ֺaz6pْaWy18k$!}.[J᭠ +*@;sc֪X0sZ%a8=2zҚU#*j[?(M&{? g摢6 Ecgkn!)˫V2/*iZV1:K=NեS1?*Ӹh\#OP0?Z>wЩJ>e DFсC  ;qsڜ?j-$!I5ip@uN=9!d ̊M]'' da5HNrsZ>M}p|{ª(VJ :"9Kr\U聝=&bc,I>n#0Ŧe>wЋOLbpOj۵m8)L8;XQHd!NFp>چevH*U|Oum"6봥tmy;B52 3L1(K~Asʍ]`9ec¼!E5\k EX֛nGj:8xk׼T-.?,Gkm$hE@us>qW8$}""~I]~̧Ob~9ݘij ٻi`$zJvD'm:ӹqf#1.zR 8gڤab$6xڬZI:UM!=t65" i9v1R9xMLdYׯA\Bf^0?j=95lt^蹦})xUp$ۍ+~XI!zQF}1EHvwGbf]FHeYY8n.1pNqZ[zޥA9S9=Aˁ֓&ǧ>7`v }+'j?3NN{{URvdXW#-tL=h;b<^ə돡HX{Pz;^} 'Lw :SʍZM880'1Қxlt-y8?I q$ۧO=G'2E[ӥTZ(Q~a+U=GM.x32Jv nFxN$=Tls֞GRǂv"4ߦ=~F:Rqۥ9Vo(kO֋ a=w6sҳ `94xhrt4çYk'QO!\{c3о>O ܣW)>6u#4Mj,~@[Pv[_<09aUX=t"nSKnPQ! uDN?gGd~M]l~#:MMҸ%b#ڻψC:D|ÑSآd9v(Y62HVx A@znՌmEU׈i }bpqL׸Sғkݹ q!#LԚ%U[U"MC8GQ%aA#Jlaq3ӧˌT"ѳ 敐]4w!=1SԊH۴~(M#%ĝ ~ȝ'5tKc ގ`LYXR 4JvcFqab/¤8\HF{ eSZ͙13ПZ=D;XcSKc ;S Zk0$C9j3*x taL:߆QcH?]ӏָėiɇ|#?{/S? *ٝƦ5F㏚Z ~uWH9w^wWe{"ſt~3)oLsO`G!ڧ#ӥhXyxOx)2Tb9P+ q'N8MVy6jLprqN]!G84n8 &pϦ(mF3ךv{PO_j@ 9$uWz1)2HSC fYV]]єP0[LuWBypA&&J_,5z̕JMe@,kbdC<;@ s,[g9=im]FRBmI?&V񌅅]O*.GGv:ghI<jqpn.?Ɯ҈/ =?e"v; HG̤\IuTÏ5QwʹnUO>őx'q8=t~\y[4ǁsq2+EY2]6yIH |-*JX{ Ɵf)Ўz1eu T&g*ldt(ͼ7Fs'>WRq @ (#[.ԐǵyGo (UڼV;Ksqq^ʯʟ 7q*`N*'o+Qg,RSPz"HЯ~V8727$2dl mЃtXŊ=>jI@#8H 3 fFi'/W\w ?;iڍyU3l]̃zc8U -.4{?ӃHeRH$@7O;G܀ķZ1TV]Ǘ'k.T^^nH. !_4U@&=u `Ȫ*>I1?LIHyh@LFmP}EH[ z }M3Oֹ}UڱSmsW-|eChgt◧~i@G T Y2sZ*ozmUz3A:p95-F{bZNɳB-Xq!\|Vsip08n_'RWgtVjJb5=IcPzV$'R *kB4KA ©5V%=~fKe9rRkET5Q&F!˜*+X8SӚOVBh=M`QJ%[oS:X?ҽ2\=:WUiׯ?p׬J>n rcE5uxOEjuVpZOg"#<}A^i5;ׇ3hnE1Tdn;?֯\xzWW}m#^~P@I?A\''={cNۘқo8=$B^ٛoBDMF>?ݏz҇9:̜yW V󎾽i #?c{F]}Z鳵W P v #zcҮ&bGrML{Bii-$Zb.63:rj6I;vwY{)3Oj"N鐽:V }L?<ͨ\LA\sZSgRjGKb3S]3_f3ָ+ߝ9O`ך;^ E>.x1usҔ]4'v;VkjT%bh`9dه4$5fNqqԒRX$1֦7Ȫ=+] d*Pg'TWrk_O"m,LI!#q-d#f=O'>,RZx6%1üc(`nSgE)35_ 1r_ƽ Bݱѓ]8pFx-[EO66: kf3E~5GƋ㕨1$g?y8z )2#yڥˀج=kc7&֓9`J}+H- *=MQKx 1E?fU1d1N>Y:˺(̒t-ֽ7zWvTׯNSt:iNFAJby~WoN i9"%;q^6禬>)ǵL.J{[O14NM3ҁYsNB:ȭ_qL!oPH1ޑX;' 0.}3dpMr6fZ bNhfD8Hc M\œSՁ^sTG?v|:6aY @+[Qy"B2d2;KwJT%׉-&̣=zszAڐtzUiۑެ{v$i f/\63 OLqOFyKs$j?ӊIؽEnf'*=;e+Ϲt%BTy=^%Ƈ):g~fr;1G@)4`jHZ)0[ X9>OROy\rEz?zhsP?әKfuG=;S3z{2 0&?:$F<`5,eom m0[I GJ%8fcEc~֪ s*gyQ"ҝg)861 8֚FqJוv1IxLzMpA)rG~MHqԋnOu"b۸)78ȭ/$YJ<8jIwQsS餅+r.VNc_3͞8\yjTKؽtv9/\exݤ^KR3쳌=}+ %]ږE;.}8WFӌt} :f7?88h53v}}GCTEr@ƕ1J P~X\$2 W*N 0V*rMLW>Uһl^Zyޣ;}`c5X:\)<`]k<Š?㢧OR4UM'W+ER5}:iRsWZ탵Y!F xAi(wŭa "S b0G^߅qɰ+4d@S49.ԣ$my$Sm&A d !K~A]l#M!$bB}kB76ncY+63ިGeq `GZ1qHf<דcVeuVG'PT=hqXvꯃ217#UmNaq"*dt#s+.\&mS d rݔ(hWeV;v j/"?V/L$d~S\&9OAy9G<?^kVy88<3^Wolsb> }sҵXFJL9`){sP~JedmEyo18A5NN{QCNkgJ t0j6ҠěHWGs4MJ=]U~nj|rzapiݱ\dYY$${ZjXWP1F:Vbj@D9j;iD=S%kAS KxŶ)=i (<޼9L<gNϲ)RjCU5 4 OSX$ߓNczԶtD\҃qHGCƀ2yAE@@bG\ j QO9^ 6rwc1޻_σ1%xFDB=>?NI?AYhR^JiðC޲9|=}68R{&1,r$:rcuR[N %7rKq.ߔ6=bh5tJQ,k"#=յ]QẔ̌(fS+IbBn?CVW~~C?JqVMlk i)\VGeu;r?ߢwZ;s hN4#'v&z]@θJ8tq#kI 4)yɨgSs)I'ldM;2IG)(9qҸ6\k|M}`a{מc'=^ 9Ph更At+3tҫ܌Z®9 +͞؃f~0#MK^#R;zTԗ=;7#8 `sg''iLѿ;^l%bBk~t:|}iwɁ s)ZWux$f28$tֶw&℃U4F墊-8W:3B;ȧ}I'E-^EP^ arޠ giڴ Au'M#z9GOGV9l0<Tu/Fv8>լz&v:xa:PYi֦"T<3=gSlґ_ǒps@2^4̝ăy^ 7g4 ~*['OsJmpN=E W EJm$'#|3lO"qgW.޶7>pX tM8nzt&'OaǯБ4zS֢')9RfIdיg(kծz:. yg#\WmumWҾz kN hVQMFv?|[麭6.N?>ZZ-`9f?SPO,hpo?ưFӱi閪O݊ch<[I6pҰdꞕ4lE ݵB^0tTo߾3*hEٿ&Fq&Igivm)_\ t“Z>&;!65sq@Kp:4! w'Բ` 5\JΪ1J7~ cN mQ Wi#F/-aqUi5*ܓ6lG9 ƞߞ) $0cNUmc<8J.cʅbǚ``e|0#h:u=ёb*)>kš5 fQ ʽim^H"+'FBUXqq< 2Њ޴ޗ>$'?ʡkj6Mќ)HexKo&mP7?O/;Sӌҡú4UnW TNGJ%R!$u0ӄ 47>_30k>-z$-eNs#ka A#\AbWƽ{?11𕿛KrGʽ,t 6Ah8{S #95<אtrB5iԠutڌK8`uN8ztv ;ayHH۸:y֣0oQg⫆lb\5I]؟RwW{KƦGI`;ʌ$99xE&Y =;qTO"wWmH@V4:M[8b?:|j'oy]4DTA*zJ>s3SE$F>aJ #ӎ00)D$s:t G4rXX@Ǧ)W\GO$D0s!נD5 %w ?*BÓkܑ{Z3DuNgU3B@O5[?:iʬ|q9d/id?>xUQ[Ͻ/٠@:d٧'ԯJtӹ?ߕtk[xUR [h!M=:oĚ4(e1] q4FE{Iw($/4(FB!tuL4Թ^; ҆#w8@n6j.)9s|bɩ>xփ[}mmf ǹ `.:hwQdc H bW܎^bm-sYd2ƫnlŐywk H?Y|Gl`0{PrNF{WYuӂ/,/=Ģ5bOZk qyQֵo>V2k|:@죤m'^(i;\IayNARf*::Y%d8`K)1qungT1KqjQ6l6J` ;e^Rwu +A鼎*e-*m^6r:f'lL0snյ;NR %OeB/jqgx3VUUQy*O= 4ϮE|k6uhVH`ǚ ?l+;12Ije*wwG*A=Kk}?_f͆ӰUZƥjWj :F!GeNzn";eivSӃq< ]LYwZ !YUno*CAքiw`d?uOsX Ԥ_n}Tb;z R)ERWL,]ij搌tҦ|NT9\d?0''M=f SQ?:] Ue-/,Q 7sӮOM-FYAb-BXQȮM֯ng)pxC%e{Uxܩ6>x~|M:oj dgN;lWsS[7z7-CM1֮5'5cB%<}`G*@O?+#UH.X˳qHtuյʶꧭtNHQ&#)àjkcӒ"0= UMڃ4=H'4"设8tqv,NW3}n-jID>٤;ӻn!=7s GDwʲZ"x05F ^vZ0?@O觉 b<55\ךNw ?C^{A-r}ږk+B Ϛ맙Oijf`3d?QQ40~r?Jka%Ќ[^!ҒٖZ[|UpHl~dzn!Vak [J:Yz@r3+ޘȤ|ȿ\TKø*ʁa=jŞzR102$0>Tѥ1֠ITg4ׯJUkXhoe?OZ^år }zH~]ObS36!ë@3ޓ) 2zi civ6m Q"EE'*LUk'*1= Lkޒ9NB:W'RmZt1Y$'*(I^13&}M+Rʸq#plGZ&ㅃ cMuy=Z,$ tVu޽nu+h3V5 !g?#YW^)gߠo,?|In1ГPgU,k2ĺ5ɨCuT%+4[Li ~U1l|e]WRJ'l(s {;/^MPԼK1^da+鷉-daw`I sCDsiSsח$PZB-6Q) 5yh9H<FS|cե#+?Ŏj0A-~!Vdl,f͵Wbliɢ[+a[j!asSkc iٛb]/bRJwEoG2dU,Iocs ofH0}j̱JJOZK>&Ro\zw $DexH󥹚M |,,(F83Nb-"^3NA f-3&6>aۜ4ms-$w;^O K-C$u\rjG=jQk5W#{SJۥ^FSе0uvVX(n;R FU®ܚTQC`rdW I0e/9^@P94ƚeHst^T0ŋ\| 3ޖͣC fF=z0h$<"Feʯ95, }E>a#/2hq.JA!jHm&>ƙNj cq}˚^3M]F4`*?\]\jPIQ(?/1Q]\$UF~UrĥZqԯ"wϩbc%䖺P!t' mZ Nl2 cpwe ƞ03Cҩg(2z0oQJK"5<=i$PwjՅݻmBy I$|uHv%F#ޘ29'R ̠jipqR=;Rl8<~: ~s֬4AH88bHvp8cV  梔0uMbT01{MN[$ \3Ϡl c:jͦwcpw'iGJzB~i5GE&)iڔ~ϟ¼WZ:ڜp[?w~KxHg[]KHKqq|Cj$D,`~YZ{=.K)so]yZ芒Z'jL,\hdVM3Pa|#iX =c'LK%(zr*u]F cv#OcZKK-LFV(^@7bcUM\U?Z"I8'RcSR{ wƀAqcgtn-szCZ.殼 ]1aj1.)oXwĉցJ& v!f?CYH׸(#qqf.TRK?*\/*Fƽ}>mc?dM.Anɟ~U ¢fEn%:}+:gfx:8,cfD!|]\V"vc-P?\sVqڼ=܍.qL2)sڡz9HAKW:à?kRʠұ=5'T4EKo&x/afC*cS$ģɬwT7$ԍ͛JU~\Db3I-2mz炐pUakbet9wJdںN1@F3M-y>GF_|ʦ1Je}Z~A FFOJl0ȱƣ%?p׍jW$׊|E2;Gw!j7 --4~OS]l8nLi$sQ0`òNpV*-1\I #{,)1K5Q&f"M@I#phO 3IJMTFo1s$Gj"UOssK(oB x0vx;8CzNoZ(8rVs4ap zR)U~ZO1StNv$ዸ8$[(2z05XC@ʌ{W\MubtsQ0kC,0cFN*_ ~+6! O31&唏= ذ"$;}(ǭT@.BaSb(zRn#$AXp~ZH&3j{{,HBJlyQ=)jx :)`)b{e=6ygwr={TAo"jhEEZ9]bҟhMߖ8%z^aMq@a}j)6p۝r8EF,q6[YPr> q,/IBEH瞜OTX-"@9}|!PpO0ʱ<5-OZK#h5;`=3NVmdplxA)@XOic1H aj d03}@+#q`ҡEXZ&r=0("i00G D,FkF=F@hT@R1J}O7e6 -~nwUŒ`2HČ`aqCCLf'trq֚v2A5i`)O z+J=iTH0xVs _jwY<@ FRI+$K+"'ʧ"IdBʛژ ~VXH!$*܁ԟ! ȹ=NtX`T_c'U\h PFG5xEG eeM!`xU" >dqI '[ =/Yx4{lQXLnr:Qu%puzk̮RYXJ*6k&(0[ҋI;6T+\ _qYO H4 n\ҡI/\.=(,;N- n||\ :,ι  $Q-~Tƛ̸̊]Gt O1-ŐE3X-d4 s}+QNK]&CD!G~*#+TuN L[NpXu2Ŧ]y2(V@>3YKB$˸Ss8hRL6rϴ\U_M񧤷#.}kdIX;qU!ºj}r[g d_oÊWP#fBn6u)l0=+¶WPw@jNۏVZdU@n@Y$B7gd8 ]DŽ(sG͜4g9U  v:ڇN jLJtM˸GI:y,`Ԗ`Fpr~}_)EB#95.W9Xʤ;T$]N8>U bH}kkVFΥTpqޥh77B-VcE>P< Gz _Cy9[`ؖШD {H֯t{qK`PzЮG=2vU⪽d?^q|XU۩,f;OxJ񖁫ڄi)ɛp}9򭹓&ņVdaiVnXGjwAU]1YAdI!Mi!9-m!O+ss3#X_Ay SPc[JQ"~cQyv-/4}Kj;]CTz`Vo:[6:i= $E)8(0zQqXՆUϿYf6@\<⁗z2zԀ̌{R{7XMXFzR@B84uF G??B:s@8;b?&ʐs@X^1UU.$۹F~8JS.<"*6G׊i7H=I5Y烃֑ҊWpT*\zTJ:=F+烊眵6ЇRY>OZ[J9Վ}{WV.!jK fP3LSؒ@ˎ ס*Cr\.m~0 ܻk -Pzَ[2N0Etʒ8"~n+Ч22¶ &:t2 J; %y5X6,d sks@c^ްG3*\CLMVA;#ff=CSm.ZWF*M,9'͌I2I0=Yip]י%:sޜJDsME Գ2 G1gmIp6EbZ\i>qGt1A_aUfLp?:N]sze%ك3l-J8ok%@#*$zwTqTFKw'75#3ә08֕1wq0V\tcSE( sJ<Z f7!G㊕-64"xI(\Īt捨03 S <& \3q)czRFH=I5:;7GDI3n-96V ]t"fm[ie %@"RmFB>HK'/JG he,pir$щsjdy8l3mm,c=>qG9.f@^nnjPutmNIh&F*Xm c⣓@)8ksژbqצ;shX%?ǻ{yHa+~+Ǯ*q΅e8Uz2%G&𩧕$pFV #ffsw)邢ڐ3Uy7e\2l5j;)̂X@֮>i;!@yo29X] #6uv2QN?O2bW|TShאa>g!x8魥%YL,ZA5V-37Lm$zs8d&`ϽƘc0i79Cbnvp)Z N*rԲ^X]\y&؍p©dztGI48"=,"a|˨r>N@ҮFZ5$tJmjҝ+4ɬV_/O~.W ygvc>0ylRnÊmʑF]Iu$#l r\ҪԦ]R ^T@UJ\Wل}s#sўՅPrF*p֗N<kg ں=J:Hܪp s6FeM:ĬJn K/+ƿ #ymYF5p8'6-w0k\zs^ xԩPr6i\ʲ4VCkJ.U@FqRHŴcc 5k-QjI=0:XH“2@qɫɱ˪M5hS&|.Ih $`wcWy'Ho; ӧZEʡ%ipB<{cb5bAUéBb9׆8>glT Se)$ڈZXwAMtHA3jn-Ԓ>f_j[ QGv`n208 0.=}גKu#R]oxTX!T6E"Xu:)MfY#Q䁜Q*?w=؆60ノk8r7+r3_\10QIPxAif28 g֣6̃%[-ty.9Sϵ0L0#,lzW ǩu y=G~@qqvP+E?GniL3N ȫHAqYZC$~Qo?k)/z- ota ŒyH-Vakr7#ԗ*)Hé *ۏJ #'[A"(KX–*GYlczXNH k>up֗;<qdXGwoS޴V6.ͬ 楋S`2<9ٳZ][[f?q W X5>dD>7#т1RhWx# 矠aWkKt5Qd"M03^kumwl.#udd UOo4V$X b&G(lg}:AI>G8jԯMTIٝp;ԄbˏZaڬ S\5y$y8#55æZrqgUuJ 5n[wұΜ7~BSLsvHf΢ {(ٹJѩȭZC +bUs2[#e}xXp< 8/PdN=qʦ]rAIfOJYO?zaPʫu7|sZ떘t>3)ė v/>=wjZΟ+m7_WTPRd`2JS=t$v*QU䲷{}1lsrs${X]F(3ʡjҴut[B"aպ+c8O_KFJsdY{2 >LG$=GzRcc'̶6I/@Ac+A)%痝vWU1Z~;e:hϿ{=oY10?JG凩 )}cc:J t?j9 J+73#<縡=G͒5 A;hUb"rC]H53ݦnL{_#dЛ3rqץ[-% =C'PZKmOV=괊Jǂ*%U5R w* ϩnb^'9BckZ(ki_)iɫm|u&{0.fef>j^Z?rVmucxȡc.K\ ̙=Ԝ~tWfl s[=1h 8e*8b9H⽐!s޴4da:" ֶͲfS=k+aSv1XER2#'.pGPNG6ݍP~/pޔ^/$T jb'@ve9#arirznPE*]q#K19u$~^~Ū-܃ڝ9MXX2-w9c!ݰYLb3JÞns#I2dnõ:;ecKȹ<ڇtB<,ċ1d;h,fI$u4Z5##v M6Ȕ {'!kMK\b4iYYەs)!x..gw.}=*Iκi&0 ı1|Q=B4~Ze%N8\rjYp΢Ndb#aWSn7_py4D{.*P"XQIj$2̤;A4XW4]:fKc N`pcUZgl+A͚E˪vUPFX?Lk9d +;e~>,PZ=ωu9\ BMf]{v%۴:gU:)8~T9ITTvFxsjqfE^H#=)M`XMf1 Sd;3u];@hr iv?/R,wR,pt\\LH ϥ*ۮ@ }ޤ85"[~pT p$&qrI*C"%.;Fm^AuwDw ?ʴ7&DFdՈSg(`}OuAUDU{S`Fqp 2<jx泣=w ޠ^kn$ܑ`c;xA^uI 0 ( ץc۽qʳ:4G21-I1x1]t,d^ I4+w< SUS%8gB[b8P:קx?[.yk*|]Ft/"Fu3G3{v ۘfSna`n?-C%b$;?AjKl<.! xV%*nQN֮VT4*Wm-g%G =IF|I& "iYc>t=sD9>)O/^cΊv$QFzwzivmqk,F,d ֍&i/ČץawcTn N 4Htgk#&׾VjUְ!r#r $}*p*ѳl)O}1\tIP7zգa]Y-&䟾"9SM˰ܷ8UųY0vK#skV NVgSUGTŁGdբw=SY/!JLju Ym%-"7n$q O"$*4ꮟ2[XNİf'STĈbX)[o;՛kfv7 }>A"Oޤ7S9h}ܓ<7P*0JЩb GR9#g*2N4_aBbEbr~HHLb-elez=2)|ˏRԥNǁӭ8[6>c˗^u0˨_9dbuTcLy~- 5s6svsNi4^@՛! ISYF/uUʧAև"ԓ-S,W R;6U?'.z5i+MD% *촭!CLSҫa#jXAˢzR|ȁ1)b*@=RO4tRGj%(HRF}D#zJzHIxDi8?5lgo>U_B z4ReF Iӽ?!4 zTXyeҞq8;;zMgd<|ǂ^h'a8=*WWeaӱ?hkKNK\Vԡϡ=MRO^Kʧ0Q޺b"~cN66{0$d?ցe~UN9'7'w{wFrPxTˬǏYMI ƥKO_.PxkB eGqL( ±TS{h>y$@jxyDdƘV-۞ 72b\t7*6aqV-: o!B֧;\aR-dH@%=)y 7W<'ڙV#2pؐ9~ xAos3gPkx;)FoKq?TbIi>(Q^G1p~~"x~G$TLm`8a⬘!^2ChPҥaf!8-14R.[گZ3v֯+,Aث־1#u Wln0jMɴ>͹54Ur*1qP4Jy쭊?[U$@pד#umm6PO*}jYEnkE\YA)[8?s\=s$Ӷt7ŏTrȵ8_Lݒ#Yc=:rߺl5oh`=Թi{EfJ51ϵt qP5D K%s+*HZ,C[Ma3Ш{c5$řdvKkr$S.t5j]2Q85M7cѳjJhk5KR¸]_1F-?3+/ܕ8ۊaNNNe+{IR{)Z1,x;\uC#Z1>X]Kw)O(;5RVDho;Dr8#s泔4Ї 0p/jlӜ:n$0*]+ xrU)%,9{Ӓl/̼Fk0rh;YUZxz$9>~Xc!0 yӓΨǕXۡ*C/zv%Ƭ<˰DIqjHF ztتI-l0GgIDLlNN+(kG] ~=Iu1BK Z[2,W.9]PMi+cfLqpȪ>e Yp\q2]" I $$VioRkUs*sXh[|?F8|Fqb)yh ޔi㶕bVo9HR{vC$)ad|9R?zmw% J3ƀ/^̑1-Ӯ96vVaΤ[o2OB9B*e۸i)^n*cM\S L @R>ʝ=H,qp>ʝXʺUͩc}T:Mo+C NY|]roVJ8ʜn4&imqQ֨T-0ɫUr,DĔ`3桞֑8hNR(\3$rw߃t[.-n+kK$@`^NyG+ tfǛ\2izW=yb;7n6v⽅ vEzbu}&sڍXt-._C28$ܱDV8KucqVVl.38N[қ[ȸ7n{dB@t mk>M&;|=9ʱᡶ͙v_w|qWc&_I护}դwZY% PpWCCič}r$(qR8ѧ1&qNj7)0N]5bZX\$R:teO9S8)k?f1NUHM!R$\^ t)&y8f s8D{UMǞI$&\H /Ƴhr˴5Hz]vk΢j\X݃طvxz8̝ P8U#򫳆l1?Z#6 {,'F0eSǭs@m# \F\'bt;5(GEFȓޣc[kyS0WR]{Z*ɑ쎖+#$ߺb +Y.ْHsvf*85Zdm-ay*6f55nN2F1֤K.S$jMF`( *>Ph,*O]ԾRIsE3zP9|ڨx[OIU1cu8'brO 8JTSJs~,SJR7/\ԋ3 ``grmw2yZa7gz\]3sP-*CP=;S@`ЊeX<9Y I dX=z!MD3 򚈡C`bOA* ~Zf9t:گM1N*j@ 1REvF=+wwvI2 Fw!;ev|{YwTRq:NWNr:R<Wm [K)*mpT1Ȩ/-nA 3u? V$PM$jsT鑩o4sQaϴk:ݳQ?4`N a1XǡJ-.f.Zg;d#m-,d]Ip\gn:uJJ:Fi,"+4('֟O Z7+(Oa3Mh`{inVR$&[nb(6jj}7N.2w40w/\RͼzoW5߇=α&wI\Z}iAOg3B V}ZN2r=\욄 s0!Ԟ߭h5tx|@PV {"D Sܟ5RƟC]Oa։\Cusɥ|ct ]#|tUqw YBFKLP|dqoe@1zQa%,oHclU]3NhY&V|+f *-Y0>6 shVX0_gҥI qITpj5ky\Fk| U[LVU׷K'ʓc~=0+2CLwv4kSZDc{s!9ǷZNbQ._%>L32+Kԛ JIާ?JkXNh`&eR#Z#hG2v3qŵ2c2A+Gf*G5rIG@=1\5; G˕O+v[Qpy\">ko2"yʊ0ݱɊA503)@p3m=PS猚9S0 *!?ŠlB]wzI1Q=@HvAMCDh6UyZhnȩP3sCNmudu@Y֐ X֠eX5y 6*ŏ9nOZO]3?$e@wx^r:W8!HqN+ӧes:^]ԫ\Z:p$ tZ/=;VL;>Cr8轊w'AAɭ8&`2۞?:aګʫm0kTQr8q]&5{`:yM*y8>$W-?ێFvKq2Fu5/Dsiꑁ~Uswg9,q_h{v)>#lz3OoǏxjF8czV1z+TUYj4&SlX'FiBt @UL0[ c1LzE[dmġ.#9Ɲnʪ甇-Y^} sN Q̸[bʏnV#եYKKm62aa2x9r g3r>VlL ޹ *|˒OB3M6C4cinTglnzp:+QOC:Sե-Jz)Eh6xZOݓI{{ qNqL*1*QZu0jxHԬH#lp)a]ܪxБo;p1Vwj(t\㧶ib0AiC`sHݓd9Lyc!?ƴI#PQEZAS2ʡ8ВBjӁLhI$(&{ MS1gi`;NI,cOtDA&ޡR6*3l|R*rS=`d>Aw .IL[H48aݕ`pj6_jEoQp!X}y`M"J8H=yJ`*#)XTXsۡ۹TqqhH([=MB9[qϯ8v.R܅G4 ۀA@8b\*>yUW95pniXr5B9=Rˊ뻐r;&j@^ý*Ʋe8#4s #֔: JrSR;N8 RGh rS h76kr4{Ea 2@ӵ b/=?ڌ65bt7׌*FiInAWE, >7v^hqZ[Ta05d3lpg]%4 ?cg=XYYz÷LԋU;AwhϨvˍ껖M}c`(+Zku;H x$ "v<{ֽ6InbWUq}:CɢF5̅NQg2,wf;=?J{dK >R(sUM7ʷs$=*gI%R1EURNYW-IsK0q21@o4ĜsiK(j9[A<^T1+쮧I SV5xɷH˜S+"1-B23NdlT:T2l9ָg;i@J޽JYKipk/܎{E\Β]ccС?ZD73鿓W/$ڣxʦiq_0Tq$`֫,:.}yBcLS@- 2j\cړb1ǵ2T BsVG&I`I`NWSFp=:>qa9zr05qFP5-yb"߁Tz$~*?;\sM$ Ȩ7Z]pU#WލF:09v㷮19+qѱ< dӋߏzkaԁbn3v{(eSۯZh +{b7G|5V?j,9?c9I05jfQmcpGV~3+G-:{s0q |a*ᑸU9mf Tc -ݷkJ³u#R22t)G" ?pzSȾ\z+\@>Ah6qpڭ1|ʓSx.*ԂD6 *)#*̍ { !$#ןUK8'Ў*H ξJ%wSS%d$Ou=jg ګKbz\$7{:2ASgFǑB^ʼK}ҕ4.s~Jn{VsldӡGy>QcNzºdI7T2XۼF|88;Ė4|q۽?Jܺ",`'Z%݄A"0ws4h"X9Ax$\w. TԮL6ccLv)W+[Flr|ޘSZyOZǘW"?¥ -AfP5ƨ/2,*#G T a-¸&?Zkagi7c QNx1ʈPi<6Ynz{ou(Veѧ W.mfU-sFc^*VL:n'3Wn-6>@' ^wMLj/pӜhW%W2/pTF)_A=薓y}vOZ?Ͷ#^Hk0ڻTW!hlٲ$}jd @e"0W'j#FJF@ r?á+SFmé3Ystr@ϥwSvQ]3 *6o#LJ86hw#s+o=h$ Ҋq}'36ЧFr=3J)!`ecK`ڦwڥYQIASځ'5i#yU4$G1Jtt1g}whPd=)vtg'4ҥ #&a֤#PHQ`$lJMϐ?Uuۓx";E)FPvw8Ki1;ttBHq%l}>! XP"zU<+'yވb # pgѨl8 S'8Դq#ֺI1a.$K|H 4]u Kg!fezsڀ Xb0vArb%L&#pOpN)I9S 0d {ErlE%VQO -׭gOm^5FppZϖ]қlyFkxJ.$)HEW2+Rc x l[r+8-ѲLuhC[;_Vibq|EW.ڹz>*luF>%v=v #5msmt7o<{T^H21 d8?浍~n{ u5 #'ɮf BBL<ը۸.lRR8&~oUd&bbQNj"A<5^/i%;gW֊42BkE$ȳEUbǚ2w|x֬C9@i i֦(\Iퟥ!<0D.HӓI9a܏eFi PhOb}U$g=F4MGnPc=9}:C03B/4alv 2A')tuD |ĺ #r}<\`Uib5d;!XE[q3(#i$u TX!xYU܎rfra /Jh~pkkyH#?В!Ɍim#dڭ=3GejrXڰ KvWUކtzŽV2FwN|(Mr;s13åqʻGy6dgLht\l:)\͐jRWfr%ѐUFzM-Ggn09Q[V` #u`QȭSOc&܊X-.sĤKiRiLFFZPJ 3K[KgnydJ5x:&"(mvk&(ٓk%4[`FGn'EqƳcr0*}&Zr>cBPve?L2[|sG-B@֌NA!?P^2c7V=鈍XΤ;@AXtbFv)C1` ^sPvM! Wj¨0|`3tJz1 c>6#aby`2? 'Bi EjV,9 'cu1O7#Z:p7x$ #<5|,@䜓MfyCd&x9b‹Tkogtdv\\–ᰂRGUUN;$q,* )V%@қpAR.ʃzy%2`tPxY&>{rzyL+)!#ia';H4sO`s#4A#ғs^gkyVw%J.ߘھ#$r˩Ï((heMo0 KqO r?+>_/&>Y+~)tSHaB\U9>Y8LcdO2EzSzT,YyFK`4-4fY[pNEhZ郏ӥUZܰoQsߎMmmttzo}Ak~ Ze*_?ʕu4y9S|]z. Mc g隌:#Yb2Ó/URTpG$p~E>,u5x}r]նo)n2FO?3 K \SUH[z}\TqLv<dr9PXwl/P[N rK%04l,!N0y3V+ƹYnA|GWQjH|Ok"^n*5#:#VgL#=3 ́l蘡qThnHӡK6GsT]K&ZKR-UؐF?&œۡl85a:LA#ImiezLۣ>A=Asrx” =4ɏ̇bNٝ@r1OYUV"6ΒTQR ie[ILg! t88r;Ug1nd#W$@qZ#v 44v zO+"cqQM0cթA81qR2>p'P@Sq0qH;zL|{#tZRGROLXq.1׽;;x*'MgTq{ЂŢ1z9ޢ@neb8&XqۜRb MF$`R?0 M׵ vqQ36k8##=9 #iސB@)4ʝf Ў,;ԫ cuhl3F\~Y MA@"'=Glb0h)1M8⴬ 2:R, 4 i4 H#5 FݐzRS36> qZ70Q@mNkNiVNVIlC? DߍJ6f4QO\Ur6r UdՊ8r$cA4!0j4v^+( ➉# jAsښ#t aЌC Ɉr)adrqJYGӊi.t]$ˏIJq8uct h„GD@k}+HՒTbdl223ЎFѻ\3_Z00G`I hA9 \pO[F{ʃ[Vp/<@ut,O2|85lvN aFKV'\!U)+>cYpEEp@)dp9 ~R7:ǩ~v?pǮ֏/UQ?U{ohפcZDFo}ȏU5dPA)4Kuj0ه{xuk3b?Dz]z5ts`KMzі 9>f d!b1ٔՄw;^+WLӅşEjWyz(Q"Dނ;M:QEDFe'Xp*{J5d2,EY{YbNn憇]k1tcֺvڊ(݌3qMۜ!hK . h辟V?wfYǻ!AJ(]ʩRQKB¯6=袮 s"܈WXsޥC2c(1zxojfa9c 1v%{Զ3N}('{D(-a%sn过QV VF$#'J(Q1iEB:Td(!3Q1E9$3E*\4O[ (p,Z*-Ӛ!+ET p'ҜQEgfs2F?Jӊ̧z%_\b3(gS@4nP$<8 E DTgjQQRFJA4(;4QLC f8`"jc8`I:UlQC?h*})b&Q(RdеwP. 5zEkdɻ3&[9wVhO;]OFQUKb[%.L&ݎzQO=|HhGgxemul-0.6.1/doc/debian-12.png000644 001750 001750 00000012703 13402411501 016144 0ustar00debugdebug000000 000000 PNG  IHDR WgAMA aPLTE^ffU-*(8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).IIDATx;bۺ@aTo:>`;SلP:}EIzqr$["  H ?Ï?ځNxmK>x.?X mӀQW韩X%ߣV+VpJ-kj~v//_.o6NƱn;y||Nq+fSG8n(Ϲ_sO%Xy6r? VGow/xN}k0CnOP/{)\X+ţzIv(ZT`*46` j.K4shpS+?cӯg_yxf~2={||I4']zhhhh4 h@4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @Ѐ4hhhhhhhhhhhhhhhhhhhhh h@4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @HHt^ @L5xOP/kN`,\^I4xD޿Dzyx^ø??YҸ88>Ch0R<{O{t2>-2 @$ gT5n5ƽ <lVPӠWQt4z5ٶ NkpD`8^)&b~c3q_CtF74XJ4x| nr}4mh0D kpz''u'p4-h|Cx|>bpb<:.ly&ON 'MƇieMLz.4Yd@8+<@Х͈?kN]&qLaMϓe=dtqZ=廴|7Vԛ8{פmo445m>nre7yS\k20f= N ɎyCt;>WiMڠY>ΝISΐuZN|%Ӽ4~$Wsy?bu5A-:aK+'Iqo;ˑA|< QZv)괜k4̈́ojYKѦtfHC6\js V`A{4g4Oh0I OA_ Y`sWբV.3נl8w9A^f6XԠ4Mݴu i^5}u\uzr̓knb 6d9=lvpk%Ok.^kUJNK{ޜێ6Cv&Ysrcr:tW4q3w6l&\p nUi.-۝F4 @4 @4 @4 @4 rSd=\},7g;voR,vgٝ? e;W}1tW p7W1DiT_skܷ?_ag7\8:Ҿp>-Kp/iLOhpoue۳gi*^,k|`kzwMO_f=3ϽgR-t.=ݬ_~Nmi6Oi.|rk^Uh{ 5BǤ۰Mb/uwp"D9-, ]`SݓjQU;wǩaicX{SqiOaxU7kk`8]>qȃiXN!!b&AS%pzBA-dlf Bhv]kҧqop%ftt=CDZ42t-iK-b{:-3%H'4Koމf]Jmi=pc 4E t$t-i3|:VYCl||xAI n>A&S4qAZ&Dns_dw_c nLzVMkМ'm&eK1.gK 'OiPԷS,'Nsdns\_Іj;P/ii0#ʴ/c7A3p)ѦPVSʡ'K&b7zh77p\~vӭp1Z{#ՠ9 %wG`pF_L/A7k⪏[w4X@ ﭧD7wX~㄰ڀ4 h@YyQJ7~wMi0[4 _hhv h@Ѐ4 h@Ѐ4 h^ɘ7Byq{4}V6iԼ9 ybQNHA 6J~y(yZ}KiH $:y h@^hhhhhpYG&Ѐ4K<!x5rl1֧A"lhf rЀmBPb)` @4 "4 CFҋki`^4 V~^O{T>HӯnkЀ4 & V|PwR 3u h@hp_Z @ 1<S+ >a^)^4 Z Bzjx'kЀ4   h&bj0@%M9hF&}CX fz4N_1`=C3VA5)g,6x܇} 4HW&D ^8j<]+`655׺hЯf D`bo^lxU0$qQLi؎"zub.(ZݑoCzePqxaLiܩc3붫\.g6gwk /׵ B'm͢_sPt Mo_oq <}ܴ4 @4 @4 @4 @4 @4 @4 W4X 5hh# .hhhh :hhhhhhhhhhhhhhhhhhhhhh@4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 hhhhhhhhhhhhhhhhhhhhXo4Xk@͞XymA5xD+4 @4 @4 @4 I nd'<NM?45į ?¬+C@!L?g9q'}8z' ي'8iNE['^9ݪp*BC '}8 }6L 稂#{ _7x!) n_xLЏʔ'*/QpBR8+'rp >nUOa^_ ^3B.l8lWiđkN-ĩ(" v+GN܇wN܉ߊVEoSnp7'QU =p{#+/`yyE-Z6T_>l NQwGe,Aj3w^-%,Ră^k BqΧ#*)vWgz f洪^i?[vعA8ɯ]9Y-9Zjmp&[OטjOX!fHnF|'ĝ+Y l^X9h]{:Dz ׭ñZKN|'qUZ ċZ˳VvZKˠ\ ꨵ%D4WvZ+N Gm,!ګ[S-sr=Uܖ mVTk3]@Snm4Jp]j^qxZ(#VY"^ZTZVkc"É;qN܉envcHEƲ'#֖rСiukX0gԭ׺A ȼnjnm&tb{^^vrnm+׭-֭'ԭ-vE;庵乵pN܇/Wk9{ڟvÎZKUpWcVuk-7·lskxQkK[6Q6vskⓣrQVYu㰸YT_.mTk˧OVέyKRkJnFvhYʽЎRkutD>}ДÉ;qN܉eR=IVUBNqVUBIajh.@skvgjmU 5gBD Z+!܀ZMRk=vsLm+!@(uN܉p⿈8lC+!RkyX3F{? bZt*z-qAx{݉Y#~L%Z f)Bu֖ۡ Ri*!׭A6w({^[\VqNx*2zZ`n"%q)\ƋvKUbZ CchcH|^.:"KE|RkEJ 3cZ }*j-3'3v\j-2]BPΤ|N܉pNvG/܆UFR1] V[eB0LJ,ZPh^J[Jy 5h]bc⩺Ma ]Ge^o[ Ŕj VCsk˘r*Of,;q'}8{?3&Yf˭ 0)d9Nު AZJȜ.:W {rk4q[j-r,K. 2`Iؓ[?BM,qy!u45ԆbG%-W!&kjMښa pEj-6_ȭm.v|j-)M{!WMW*6*\ Kվ'}8q'3JZRx&qKPj-֋O8qڎe3rk+,Į[+Z^]d=%VawϭŀxN Bnmjw8žʃrku01]Wĝ'~G}֦qZnm#O=4["֚#n.6Otṋ\H(PnmF8[[>=AVn-rZR-X"n&lrkΑY"?[~Xvʭ-ukOȭv^ !бZUZ qN܉pNgOnQk$>kջڮvD\{;+!p@ܶFRV,{Pr7ȭݢ֒!SyYp2 J]j-I򇈅dC~}n_{ %vR>5~ڡZ["^7qZ^/GpN܇JMjg7?K5I֊8ճ!ENs}[4^VYTZ;'&[caUeJY8[K'ijZ; =ķjL(Z;9EvGęj4gsv|5Ն.7PkeWÀ_ĝD~d>Ǧg';ֈ˭h۪Z{Q4֖y[K$έ}v-VU5[YWkַqj-w*!;coj-dZzZ|U+Z"ͭ%{VŇw>%kB2\=4=$iMڡ}xqWkcL\oZKQkd“Zͭ+YWkQUZ<@8o)iZ, έ(/Lv|cjrkWk]Wĝ'}l jNǙå|pnU|w><rN܇w>3#^-N1NE;?E1Ǭ ,Thuk܉r侊GN܇w>h~žv d.t+ "'' .'c nM >n`qK{.qOŽ8u(XӃO?P\+W,! d1TҒħ"kd:~y^^oGϤ^J JW" zw#O/Oja3KmNT|e q}S&_X4HKmU-/".bk!Ӑ8+'՟1JuYh6Tijw#;x"ޮXlǧ?.?K<"K`w\}W>kWIB @tgsg!gt| ݞ8nF<> E܇q4Mk$1#גRjfrBKaԭ,D0i]qj&k®R +yruEK-GYǻȦ뵙2vEK8Z"M 2˱L)J{AsPrlIR )xr 7\;t;K!NZ,ȹ؎Lo1kJڱcmOqvr1Ir`ѣiw#S\]X,gf]![IBo%^R;z!d3◙Rrkk*o$UmO~w#*m*$_*ŵ(NF!K!]rނ8h>ic^95 #g|g-K?ЅlIF(߉;qN܉Һg߭397jܬd uk|OONރj.6o56Dv"99Ok\h{SX;5ăPBxloӭ9Uf`U!>Vk;gzZsWY;>x2xK3W9ݪǠ])tw3(uN܉pNGEH8~@Ɲ*}8q|8q'}8_E 8q'ğH\uӊBm9&k#o$˲!ץuuTT mY1>6xGk>ZB<%0&V|u?\3G~@qUOZQw;Hhz4]_e-}'|qJ<:o W}ܗ%V!tjLʼnu9{(MS~dظh^\s, <bK֙VW\6{q8J©A2ҷT69|,̱ |^,? {xf-&hu{twSgSXQ G]5qUFspdx*'ʝHTA:(te{K]m:uV^!JJPeγc'5q܈x"|im p A(.)J<2 qj8xl*gk whx<ƣ.,m8rQ2ă6ܱk^ T`v6_YZa; Rw(BtWtRwB{i# Տ˘hڄ/D@P2rn^!{r?V޷[laحӏ#\u⿕]ݐHP:JrJ7Wg I$Kӝ/Y+ՕFrZqI-k[^u);j[%`ѭNokɋ|Qgk[|㏼ԯ_Poΰ1y Z;Z4 MaƝ"q=6oʎBo|}DvZU`; ;ÎZPi& q =zʼn;ǡW\;ĝޡ?N+Lw>ܪ=ĝĝ''n0I9q%p1!WsB.*wzo C$N V%=Y, 8Ťq5~n$ªӉpN܉#oQ]U(*.MiűS e0?Q~Q:u3ҬwWa / G{SWl:B6y(}ȇu9OK[$Ua*s u\}IY"T$ۉ(bGe,ŻC/#.BTK\k*Y2֧s8OrANx^akTJ%3%0C7*e_˯*:#QUj+KF"q AKz$D弚8j;D6 qq{*%-q&xu$WW,.+,]l 9Ci!إV5q͕se/RQ?VK\NQGĮx|캨Nj&JcMH4 /FEŽ(xQ~4ij'!Nq8&Nq'dUCT_rRpi/W8"c/cF.UG;€; k@MǑ6;.||fT  RY p"()?ġt@ h ;$Byywj|2 R{E502C]r%ˇw>C(jw]׀^ؗb-xP`]& ,@n͆LXZV{Sߏ@gt5/D27(7& QTT i1-QE'ƉcL\o]%.]B^u8lN`.|%ie6N 6fdx[21P>+yY"PٞFL%’~ּ#QRDS/ULڠn/Esw$.sDq'íqN# 'ĝ>3Ԙo8}(q/sj{8{hu%-?4@><D(ԗGh0tIME ;oIENDB`gxemul-0.6.1/doc/networking.html000644 001750 001750 00000022321 13402411501 017046 0ustar00debugdebug000000 000000 GXemul: Networking

GXemul: Networking

Back to the index.



Introduction:

GXemul's current networking layer supports two modes:

  1. A NAT-like layer, which allows guest OSes to access the outside internet world (IPv4 only, so far). When only one machine is being emulated, the following default values apply to the guest OS:
    	IPv4 address:			10.0.0.1
    	Netmask:			255.0.0.0
    	Gateway / default route:	10.0.0.254
    	Nameserver:			10.0.0.254
    
    To the outside world, it will seem as if the host is doing all the networking, since the emulator is just a normal user process on the host.

  2. A direct-access layer, allowing external tools to read/write raw ethernet packages from/to the emulator.

NOTE: Both these modes have problems. The NAT-like layer is very "hackish" and was only meant as a proof-of-concept, to see if networking like this would work with e.g. NetBSD as a guest OS. (If you are interested in the technical details, and the reasons why NAT networking is implemented this way, you might want to read the networking section in the technical documentation.) Because of the obvious limitations with the NAT approach, I have also included support for direct packet access, but this is not designed for security or anything like that.

Use the networking features at your own risk.

The emulated machine must have a NIC (network interface card). Not all machines have this. At the moment, the following NICs are more or less working:

  • dec21143, Digital's 21143 PCI NIC (known as dc in OpenBSD, or tlp in NetBSD)
  • ether, the "fake" experimental ethernet device (documented here)
  • le, Turbochannel Lance Ethernet, as used in DECstation 5000/200 ("3max")
  • mec, the SGI O2's ethernet controller

It is not possible to simply attach any of the supported NICs into any of the supported emulated machines. Some machines, for example, have a specific NIC in them, others may have a PCI bus where a PCI NIC can be used. This is very much machine-dependent.

If you are impatient, and simply want to try out networking in GXemul, I would recommend trying out an ftp install of NetBSD/pmax.


Network across multiple hosts:

The way to emulate a network of multiple emulated machines, whether they are actually running on the same physical host, or on multiple hosts, is to use configuration files, and the "direct-access" method of networking.

Although it is possible to have more than one machine per configuration file, I strongly recommend against it. Please use one configuration file for one emulated machine.

Here is a simple example:

 
!  Configuration file for a
!  "client" machine, netbooting
!  of another machine.

net(
	local_port(15000)
	add_remote("localhost:15001")
)
machine(
	name("client machine")
	serial_nr(1)	!  10.0.0.1

	type("sgi")
	subtype("o2")
        load("netbsd-GENERIC32_IP3x.gz")
)
 
!  Configuration file for the
!  "server" machine.

net(
	local_port(15001)
	add_remote("localhost:15000")
)
machine(
	name("nfs server")
	serial_nr(2)	!  10.0.0.2

        type("dec")
        subtype("3max")
        disk("nbsd_pmax.img")
)
 

This example creates a network using the default settings (10.0.0.0/8), but it also uses the direct-access networking mode to allow the network to be connected to other emulator instances. local_port(15000) means that anything coming in to UDP port 15000 on the host is added to the network. All ethernet packets on the network are also sent out to all other connected machines (those added with add_remote()).

As you can see in the example, this is a configuration file for netbooting a NetBSD/sgimips diskless machine, with a NetBSD/pmax machine acting as the nfs server. Note that the nfs server has ports 15000 and 15001 reversed, compared to the client!

"localhost" can be changed to the Internet hostname of a remote machine, to run the simulation across a physical network.

NOTE: There is no error checking or security checking of any kind. All UDP packets arriving at the input port are added to the emulated ethernet. This is not very good of course; use this feature at your own risk.


Direct-access example 1: udp_snoop:

The most basic example of how the simple direct-access system works is a small program in the experiments/ directory, udp_snoop, which simply dumps incoming UDP packets to the terminal, in hex and ASCII.

The easiest way to test the example is to download a NetBSD/pmax INSTALL kernel, and start the emulator with a configuration file looking something like this:

	net(
	    add_remote("localhost:12300")
	)

	machine(
	    subtype(3max)
	    load("netbsd-INSTALL.gz")
	)

In addition to the machine section, you can see that there is also a net() section. It defaults to emulating a 10.0.0.0/8 IPv4 NATed network, but there is also an additional "raw output", to UDP port 12300.

Now, do the following:

  • Start the emulator with the configuration file, i.e. gxemul @testconfig.
  • Start udp_snoop 12300 in another terminal.
  • Inside emulated NetBSD/pmax, type ifconfig le0 10.0.0.1.

This should be enough to see broadcast messages from the guest OS which are not directed to the gateway. It might look like this:

	$ ./udp_snoop 12300
	 ff ff ff ff ff ff 10 20 30 00 00 10 08 06 00 01  ....... 0.......
	 08 00 06 04 00 01 10 20 30 00 00 10 0a 00 00 02  ....... 0.......
	 00 00 00 00 00 00 0a 00 00 02 00 00 00 00 00 00  ................
	 00 00 00 00 00 00 00 00 00 00 00 00              ............

	 33 33 ff 00 00 10 10 20 30 00 00 10 86 dd 60 00  33..... 0.....`.
	 00 00 00 20 00 01 00 00 00 00 00 00 00 00 00 00  ... ............
	 00 00 00 00 00 00 ff 02 00 00 00 00 00 00 00 00  ................
	 00 01 ff 00 00 10 3a 00 01 00 05 02 00 00 83 00  ......:.........
	 80 83 00 00 00 00 ff 02 00 00 00 00 00 00 00 00  ................
	 00 01 ff 00 00 10                                ......
	...

gxemul-0.6.1/doc/20041213-debian_4.png000644 001750 001750 00000032366 13402411501 017050 0ustar00debugdebug000000 000000 PNG  IHDR26gAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATx8ϭZՉ/:?N ¶ɒ쵺ZلP܀/7[}ϿEf?:|7_=Ig9[& *$HYe a CC˜e|h ʘ0&2$hSrS1'NK^SRAOVY_bMЯJD?WeTbw_!됐ֱg:泆ؾs?bB-zፁfy{o 瀾 {LdqBPHv,Ꜽ˥[nH{_f "5dΔṂmX:96T&lM =8[&jgV9ަ^TTU᰼[tfbkrHE^Ar"ϗ[)[2Q 3=|tG鯕?MſޭHcN4s~,Jd̦)lY}^3^yczօo֥dꧡfSrcޮ7K^e4[F˨KP曆[kRkUʸ15f}֊`h !yU8)>|E`1xʟlݬ`_x:CXHgsE~Wdw٣8os9 ̬"|_d[U ?wbjqOiӎ?OQnc2659яVuey-[+e^lyf0H[D2-s$_'$ޯ1YmkYyaOml)?2u`'%e<[(Q^Xb4d=c['3"XCpǒ `@1;X rRCh5KxU8pK2CGlU Rdf9ZGŅ0`bµv6D7۩t.f2Tp59S aOS+}EY6-tJͮDU@i0s g;>pq@(Y[mb n\U1;l ser82-{:to^Ec}શq**MWR6:+*0à!G:Hl] 22!(f 2}pǏ (_?Kd4QҖq[ Q6oi,yg;.2&}X?o;< pbDfRfTb@dجKתM|VdOvR\o z{qxa?XdqMpy,7~Oyf+"2Grd;6C}=oT)ZZZ,|uBFezK_hp_?Gʲ~1nyj[aK>ƭl垩#ތ9b)qYunMԣWK9ue5]>D0:DIXfB^<+AHPjėҖwyRl++K2sWf=v$G難Uv4x:t$5g{ۓ[cPn 2rV> \ǖ9yQ=W<6b7ӂ#m>ez߀*fq#[ Smʲ2y_Li/EK`ho=l& _ZM)7^G@ǗԖj_ b@d8R1p"3)3 *@1 2lV̾ݾ3:Xe~ |lVű: DUFQiNE8e; xR4[}Uޏ*k<ׁ\?0 G{%>>w|:pka)7rd>L3Ljmr?T\ܖ9=dT3!18n.2w?m!3c<k0O{yq.ϿZq1nۥ"rGϿ@@έpϿ^s[8C|w%^:xM%gcḲj<7b@d8R1p"3)3C@1<3j3?GvTI0(2bJ~Ovն"WVmXK>ףϮ}ӏ:$W#gQbvv?-g-*T,cQMy-9cN@{#SrreElx\^_Rl{`u*1GYGv>SS}]j^cL3N4$o#@ q־5Bv0` [掙b~)[<ŦÄG4E3~Ԗlɘ-PHki+U3ɯK7OU3ˏY*l3#A t3xL~V3H?smauAY'FO[-~l~ɖSq2 2 2 2 2 2DDDDDD~Oy^6_ܮJ{n ~n="٠|$_ȟ"b pc3h> udeulI4!Qt?iq3n{r9o CVa 9fbW&XLL{ёeE6둚=$#~T1&* 5xUՔUBĈ,\boQv{Ik92#Lh*6w"Mqskd`sih(eU1"#w,]e;3=ڷU)̥٬U]H~\dҟF'S\2~,SM][Kң\4^aēgeĞ۾=~uxFWC?}gcf!8K#Sr,^8x%}$Ր=-{Au$R`dsJ!X0DL d""""""@d@d@d@d@d@d OB)εwc`"Y?vqDK)DQ̾LG>76.AAB%Qg'H[&9%,IyK&jh)*vk+lR`6Zy%8a\@dt ef8]yS)4Xda(%`+21@dmtY;f"/L8dcdߟ DŽx1-|^eX`qc@jy}}ݖcn$wؼ^I,HE7mHIp\{*ciW5FDX[pRs!yEXJ6-SG%Im+f?-aq\ PXad9aN!ZWfzA`M}-kV S{o-C*],tNGcB\n8,̰IqZE5+yjayG l+L}<TPt2ԖtRvJ鼱Zj3ؽg] sw3;3-3ؼ*9%Mt{S RQ4/}oKä[uj-ǭ$#"iKWSBMB_w*MnGz{1ej|L1պaUs%H6@1:H\ٲ] L*MSHKmR>8JT`dڒ%D]V~pñ3@yZr|X}lþ<]c[W@kǵjbb']7&&Kv_m!_ mˊJ-:scbvKOO?> iԗCUe|J&hO\:B>J鲱mXKҿg}90j:|ie]/2RJ];]'Rz0IRGYƀ2z+C:wc,inɌZ^6SʙXkݚ{-8e2""""""@d@d@d@d@d@d _q_ԧ`6vLځ(*aus׉oRYeLkM;%إdyԡSS:!׹/ǷH^}x˼z׈ocU}3j]\e*[c]TA^<|(hb(DRyIlT)Ӷ-jj>,f K$~l4B^4GMN:'GrKb,]T}*K@OnbkӾ tC{⽧ +qpbRoxgkG ak^a煖gg-!Kq҉}jF~o%-˂68Ҋn τ"Ks{#)G=q몵tilɶ.u~tԱu9P7ܥ޳!+t:4#*y@wEFvRv~;2;~{# +[!;fTfס!(p-6ي 6?`:qϮj+3f>g 1]jQOjGu {L*u9U7t՘6=M(B4|kPh,ӸCۛ__! 9!?.W;@7ƺ.:߯E7{^Uf-ʋs?-oI!HeV _m~umF:q\ږ7sr0Es3kWg!??i"#k3 D(fG[ʿzv޿Ǎ_V&p,N'C<c6~*fve>|w ֺⷪoDz#˱X@[6~q {X-{da*_;V#UUx{詝нf_ܞ^vJ7JZ,C_6\eM qhO"g{,G_i+SC sutF7Q ] / ߰6. zB ݰ? sNnyovzHX)W$lsd\9bd?~ 2s߅Q ״ete-sN/RXB7QBZQH h |:Зj:*> 9f|,<Ɩmbc?Dl5 ? `#2Do x*~Dwk":3Df&rĞlGQ<*f.?Vh5suh@zǵ/IN8DB"rK:v5t輅TR^ƷEky-I>T3@ YJ ,_25VVMo}?BGi &,viyK=8{[Ĝjտ"㟻jQ2-2 <|&P0:ĺHyՄKd >ڥO)A>x[ZdhBH[7Xe;`GISv--PI'L=}nA⧫r?_wCb%SV^$iƷrKv;>ګo?fˬePg]AsGC%L`j%Jl|@7_?U{U˫,ʟZb[U*3?1W%\Fk6_`V_rBUtb^l[~Y7wϬ}Kz H yti]vJNi`C;k?ǖ븒ooˈ4Ǭ|{W *A׾?ڭyCoۄ1Qz+1++1<_o 50%4ovʞmm@xcEʒo~Oׄ\7 9Ƭ:wޑO 1y{xګWLp!sNjި^mVO%Iʳ{sK"=uctЋCS'j+^:J(Nvooj0ؒctJʛWI[[ ^ϰ*fW1'ez֨WcUmlsv6*ϙ?6y}$ eihN/o6sqnp`F/J"D&[?1V/ ?X)3Ay?k?x_1lYN^^-E&Qm4H~dwį2yzh#WWGuڬgFlWԳedٹ6RVG({#Ű5,M3_{LKv8xQ (9[35IDAT͋Ӌ^ʂ?u8-ՖeRZ=xc)z-j;\pzcղe< 2l;f;29஫vh4q8't`๶5t*}L$;y/+Ezp 8~|Zgw#W`P1+bcgeukb"^G=!9qQ,Ʒxm)F5" rãGU̖~%k/72Fd0;y啃 6*`f%3 ^~9ӚeUY[0 ',7`t-ſ ;_sK?F(fҼ[+My]U}Vm2z٩@df%28etyPV~P1{a3W_?m|kQ{`XXZȌEƊ&|ÂutDWd'"MYlwoC\-xZąd M2#? \[x߾W]=?ֿ@ބvLU>"MsvI RuduƭnQElazSB ,2+NQǔR.2+2l|˔fȈ3xi ɟ{)0Oz3Yd|ɣ,s<\3g+8s9PB_zPWtJoq}&Xbop/˓ MG`p#[抐/UDB(to FY<``0d+t?瞀Y:x ֻZ´VgVjڑD/vj(ʯ4VU,_˯Y-cՖS !` 2S WDfFbགྷ&3̦E;]eԄ_sܓֳ]ԖrQĀmx*}*>*> t1JH虫;+uJrsX1"wpkL +f9Sxϖ~.9b,_\[,x`Ɩq.-  Ϳk-""=lxXe@dbN NBȹJn`d1abv䧄B)FM*! &!QVn{s Vk)h嚡0 <@lsL =d&rx1 {ͼ1UF҉u13S^O&6dfUs /sYf<@9((o6qj+/|'V1-ZfY -xR<e;|ވ}*OE}< F=2~þVx)!O_W0֯΄Pcܛ[d[&rr'KÙK Efa?宗•{+<9p=PeS4MQvN`DdsY: K"sBp`Lbf6"g}?.*3ی6DDDDDp qqK`?s|Id{Dp OsUضS(iQ1Ws Uy-I1Pz%.%W+TK[ڵMjd͠%2/AՍ5&\ҽZ4 WEZ1ydp *ӓvпd7Zmt."-2ӟ[?Iֽ%Bcyy˽1b0Mӗɴ- 5gz H[M~,ϔֶy2mNgNT ہIT-l^aj|XUDD&0X#J*"5eg?sa5S=~/S s65%oKWE&r[6לm1o/?Xc&JQ en"3t3M1&2CXQ bvقQŖ <&2]G1|'}bpTYW_Q82DOWApn=vӷLwn/`=Wy82RP~Y"߰HQJLA;0 {z8U_1672a6tn":nHQ xbZQEM\k@@Z~Ddd~?1K`ҖI.}ZP^wvq~PpRaj;K_iKm$-3{.A}C7u)0lӪ׃x/-^^ op}kϙw8}/M _J舓Ccnbb!*"TF(Y#3bvQt̯`pU?}V?eR?  c`i?+pq[?ffQWOރ;"Q _e9B'?*)>̿xߐILm}=eLx>?\-t0xǻvfD::ȁoK=m|8;ttpܹ}}ɻ_hȍ[Wݺ?oѷ׮~έ\r?_4| U/=ykN :A'tN :A'O@OE:uB mbB5 A&6=dP qB0YP1*JT=t!tMKޣJ*ɔ>(=§PhkCgb|.yFW\1F.]Mwn!cRVRWUD"ɬr)8*#nrRB_ĖTmjJv4HAAsJлJo8@ݛ >^[F^)>@VNAg[̎nWyrRH1ŅPYpZ t%րw)*c[7hIͦϾ"E9ҠL%U:Yq,#D'f^P7撇E yeV8YD[ՠ#*&HgRP5ۮƋ4qE"wjFk%9PZi(4R7($"CxiEya}BGj aQLDZ|"%/.%#"۩RS2zڲcO:މC`ՈswcRǹzRXZEHn7QTS̓E)/@rj(eZTViӀ!aLy5ȕK&n;MrS+q4mjwj$*G Lvf[`ʥ$ڦK`6cƴAwLEԲG$MdQjNodžnmX/-uJ%-m\śnͩ׻6Wcl܏P4ARv1dfѾ)Ɉl2Vʫ57(l+I6q#GPK-[ `5dN>/@o??{ ^otIME$uFIENDB`gxemul-0.6.1/doc/sgi-o2-real.jpg000644 001750 001750 00000112262 13402411501 016520 0ustar00debugdebug000000 000000 JFIFo CREATOR: XV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d) Quality = 60, Smoothing = 0 C    ' .)10.)-,3:J>36F7,-@WAFLNRSR2>ZaZP`JQROC&&O5-5OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOm" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?n1@ ӱ)\qxK)/Nd@f>\bpϹ) q)1␞(?X]k'ֺ}d:\*5Z'CjPM`_ Ml}?@+,(1P1;V?Z}ԅz#;hߘ͠fh'KL~&jzu P".<* qa=jVrz8EltP=)1*Ƃy"?#IW 6J0ph <ӓUX &i`Y}叹3G3X:HѼaF kcC@rM'!]lhn.OC\ݑh{C- ຃ߊ\8"Ku3vcZw'c@3@1B/ NQ((?Zn9ҝ@ Mp{Naҗ/}(@jL{ӱLs4vc . 0zciiZJlw R@9N)1ϵ?ړ ^Z_j94zw/J>gZBƝHFFh2i(}h gv(.qLC(Q҉cE蓹8sڡ?JSpV2&.} AY2,v4ު(a΋]RCr{R:ʃrEކQ|ck1L:=1G+:4Zv3jӷ.8R|(Y#-[bsM>F.tizzj Srr?Ra΍}A#=k8HYO~{\f[h Δ#c{=4iG#F+)w.z}k3̓AyOP#LfGY;IJ$Eq5ckx Mh1z\v#tzR`P3.Z~h@4sKKϭ10FsIӭ.?*Zb}iBw)z_ZQ;{vȤ:ӹlQځy cR/֓jB)уjf?*=x)0hQO< v1I@ 'jp"j)Pt00Q^jP)yEi4ȧr!aϬD&޺{c8*`&Ѝ\j˗b쵷bju5f;q_QOkKՙKµ:NG(4X龎J_+#v53K@ssK&w.fs2bN=ԫ(mcMZFx.V~C(!(Nތ; ]DZ)њAq۟oSIzL֘\vO鿍@sH8x!ZҐ^h }9g "G~E -Il?Swa9+=[91d56InANWH ˸1W>N*ΓfǦ~j6"C&y[й!#VVV+Cl늒$o|19\u8S;53oBdںn'nyDs0WYQ?MR)l.*pc+n:"Gie+Vr٠4-'[X r}ԼV'e,Yʨ; Z_Zx`)I^i0; \ ?Ύi8J@ޗ C=hQLgښx3ӵ^H47@"TcJ,w1{3gٳ{qh?:>*WJOjy61OX4@ts f"GE²7!?Z]ϧ4s f]S?#?goAFis#H*vO5o9|5Q09 ֎pEܡ#F;'Sr!ooRA֛c  j1KGzCփJE&J@GJB8ƓցqGnh#LR})IA =AS0RRbq"M2ʮG)mv[?k "4e#]2N3ֈ=9IeӘR 7Յ]80ݜgHjLι« D0浮B)==Ea6ӱM?/9 X*ђI$Cl\̉@sG(/LI_ҋ#MyI*F9F<1]яuz8Ob`3E.A M.z M~Tbt7!@fC&=iަFNF\#J@ ?Ύ+lSn=F44HqO)&v)a:jGקLUV]Nձ0?/Nc&Ǩև N*ƱƞV8Ÿx>Q6o{4usZ Iꧯ֡Y%٥ P+ؗ#ߞ prOU,sQIHH~E}P 9<{bmrq5+ a" /8TKAj&P.!9Qi@gGXdYP2=AYڅCu]"E$d񭡏=`NX(ԚAO94CA**j`џ~ ʯuz#7{>nQ=}s: خ2Ÿc1^zr!0-* :TM=WV:vpEs:v5[,%MoY[&Q2om?oZ\qҊ1V1:})q҃hސ}hp;)Ji4`ATzPqi9Nh(;ph#Ҋ8!hA"1 )QA8.::=E!?!N?!~cKP0E!Iԑ6Rؚp6?rS}Kt>Ѵt;Wz0]t*^:2iBu߯giL$rdAhb^Nn:xƄT6i#s5rGX.G95V̋neS?j'hF8摔2=ҫ}kyXL³7е[@2tZk(aqPW Ƨ-@qc{mbY..9OI0?8:U )\._|\둃K5R^Yt O#gժ;jIn_ޢ1HR\(zvz1h2(EF9rG4F=yRRh~=&8(}h@ '֎iHڏjLtInjR(֊^Qp*($zp1I9QҤW%^5jqj)㵬xzf;|K~J3* )bS+Cx=sNdJzhǑW0 $b1T~P[+@ ^O*>P* u1A+H搸 '#E!v8)B@f iw#Ԙ$I3ޗڔJ4Q:?qMO_81Lhxwz3ޕ$R`xSd$8/yc pjQ hSQlc]M8攎4S3K+F'$fSArqࠝgo)R}k.efrQP0#pFJT2/*bk݀=?+Ųo&Q(+gAep7W;v-t"XN,2æEt7FЎU" #(G 1VD-r9 ~ƵmIIbm(s"tsf2U~謙BFkC4UӿJ+qw\ăIQ4l-*e'Uǡ @4j+l1{SqOjdYM03.#CIW40TAb72(JI>ð>]X .2}})zp?X4u4=Ms>(oZR#X_*TA/ַ4t5.w0<2G@)"*gXVG5ksV6{q_^/{{cⵄ)ǰJ&b?g }PFV.倎sSQܧf 0G|061?f6Њ/$>Vm"՗84kH>6Cm5dGpvPAġ8io"\,vpXcUxCrSE ^#=h΋yEu{l~<^4ZboRwҩd~`vgo!zu4 1GJ: ;!)1ҝ=):4 \g)#$Pg_Ǝ4h"j)s()21R QHDz*~\û_ԁpΪ=iթ?/L2h?}x%ZҀe[ְ+Gj?Z)ސw@Zpǥ׌8" j((>z\`QM(41J8Oz;`)2 J;SieXO.S隖>MD*h6,mC'Z8Nac\b楝 cO.EIwTΥ.aQG(9^N#zΟ7'1Yr99r2Sя]`RPtH/cTmN u`~~Ӻb\{օcp=+.ƀ)X?6 );aIHP`w4RzES_zpCׯZN1?~6_[?ak.쿠TKNLҜִ8 8*< %D9* Į;5mN:q 5B)pҔz` <Ґ:y-\P?i8zǥ/QIҁuۥSx)zƎ*8_tX㳏#l6jsOSfZeZG8*a!ce!n˱=B*F2fLdqY5[5ʓ'&P} e%\Zu{ֵzKϳIjvi)uR-JīEws#(/UY4<(])(DV,V[G ڻN:WVs#r;J7ؤsZUfQ} fX,H-D\ۈnhg䚰ӻ7tU[H!\g,:H\WWY/pɒka;<~+j}jncR!QZqV8)lzu\եՕdF[*{fc9?̄:hZ ?>J=h4:@!?J^1?  7h?ʀ:PGZ^!8(k1'{py1ڴ18K,.i<7h[t2 lǿ}ZOh3[TtȺsxE$FA#\;Q{Q}W_"s^rdV4ӆ7t4zqX$$jzu_N;=?'ҢVi޴<"SJzg)éc/N4'>*ʡKfBLR:_~ :lfP1yȠ6yڌ?'.xZ0&J;g< њ$)0"B+Xh)֨i+~u"ȪN)2H:*TS/Zt^qR82 ͼ:U /.Y_A U 0HU\z v4Q@ A1\-_-b nz篮lT1sXMAIԬ95JZ}K7/ +а%9>\ی7OM9eXR#"z{ wi F9[5, G;xtBIjKA90RI G'GZ;(ќwQۚ/JN;Ez_RcҀ(;y(K:q@F9L{Aހ#;PN' Pۥ!Q8@'4Z`4/HwH*gLg9z}*@{}+/#qDV펵5ߠ^ze-6P*u>?K3OR*j՞l%<xnjAgӵ-2FGty<098残OPA}2iDI=4b>Ҏ'iU?YwsփS?{'JzH"rSEX i2ʔ_bV>RF9{U)E.-0~Y?1O)[ցȫ?ݓEIvO:F"GZWhQ튴LȦ4挜P,(-M5 605:OZkqU`vSŔ<xUE dNsYv@is} f`PeH:.G9a@Q( J4֑ =ksR7AƝ>c\`wmZB>f9粷1̊FޣFCʮwa /$YLIO251ª%F3N 94i9 uޏ—KIK@ޔ{S@.@E @҃֗i8@uZ;08BRc?hhc(@zC4:P@f)_ztQ(ZOG'!҂}(=(PŠ{ (=zӃԫ9QU5ߡިſ[ ,'CQ 4'h~@z/4퇪;ֲ+SΩ2`{NԂO4I$1QS3< =(MԻj2sh4 'ižu}Hϥ34pn⛸HZc$=hϽ3wPhҐX~Q8瞸H[&SQg4>nP[ +}UjلҮ)vSK0E;=j8{S,G?#{̲+Aيg֗PeKځFz- ǽ.G'.yl(@N4}E]q}*v*uǜ> >P8GAP}4 P1E'ZZA@j-^Qހ|qGJ(=921ERIPJ==(Z(L`sLRBh.xx&<'9$PJ9+Qޗ4)~u: ){A@ ,.GC'(sR"`3C1<}HHAU}pg#~{)ڵ>vcYcm4?\g+})9*\}Gs2qR -Zd|_'E.a_Pue}?/Wv?ʎ`F|!@,OVQgʎad*B"|GҋFH{)hTqZǵ/99;֓p l?h*.?`,4}?[~NT3gAs '@?}?ﳏʋ]/<r\?s7\—ۚ.Dߴ߳Ir>?5-9J_(?y Qv?c|?賑-tOy|~̸J-qO=JO^+@zf᛭N$IO8iޔZU m^1'var'I?Zo%0ާ\G`v#9z)hJ`i} @z\v*Qɠ^hb(G_JOŠ1M0=i>RbJ<0hsKQ3 ۜRvDC֘F(դ`Ԗ!7UۥJ:u71JzRPL)Ory?=)󢎣ցmʰ5Ne[>eҎcNsI?J_€N91z9y/jGňJd1?G|MˎH*7>VM=:iw?J^ݩ:{ў:z?(J ' 33A}{qGzNPhI֗N^ǡ֊?:^IEt4RRi:I׌3GJH!GAҏƒ@=F8'JZO>_JiR(mQF3ފ, rF{p=x`&6C|j>TX9Q(@|g:Ҁ.6ʜ(`aM S^=A>Թ(٣QJ<7P>M!?{HӯKS7/7\D=(4߭3^Q'_4x \LGa_4?Kpzd4Q֎ )3/|qFiRPOaeXdc*[oڶ>o,d)\AD[ZosPw(g%dk7_΋`SXxL|޿Uu]>q\Dp626sOE sڔd48hF4~cށ\9G9JɠB`{R3(89S} OҘS?I4ҐuP[o-IӒx并FmK0&z4>ԄߛTMطѼ~ӈd*rGޜsڱq8$k:SKYJAOE+A! d*α%MT i06X,n΁byKvCO8)>Yw&FkCLJ濼Fu7z'?+v'fzhkBDg@h1Rԟ΀ h4v}xIzҊ~tzh uz01҃G@~i;Ri:})@yl޺M wBO~k6LK$s80.Q@;NjCuHZ%%{u*~UX(m#5.+oR\zE>AdlqȬtKx_Mm@ڭ~F~JMM%b;F?.i8| #2#x\m!Z{A }K9m/={ҽ+sY?#Vģeܘ8?ήn;Q򬭻[qw)A6l'Uc_Wzwe#_w"}<^jr=DX\E5&XlC[ԋSq\E?ќFx]fph& sZFj+b%փ]eȥiM]WG!Q~VdJR)ė'iXJ7|]5VW`4SXqhÞ<x'r{.sk2? RUVt]GQ_Ζ9[Y#UϩH0n3]Ijg\#Q{HFV@!բ]\d)z晹;LУr8 Iu$~]v‰ϯ|ԁ:ޛiM&_?qN?SLz 2ݥpixm*hicyq;DЏOHG7z7ԊSw/0 N7/" i>~"_ΐ8K@xր8GlQ޸=M94vޓ4ؠ:J=hhM;\Cխ͛gn=FrVBgKuuomKS`UO>#ϚY V=}hZTYw+ s֑dΠۏz\AHV-@ӄ\Rظeg0ÁU΀9p'H2"={ M &"d?ĊhCO bAaM(K~9>S? <ݸNjHG&8V>)ۀ=i~ǮҋmPqUI,Н5mQppx8}YlS#*jSd۱~PpC*iqPOӾ%hψ`~4D}p$0K9޿(‹iozM,&gǥf^)#(Zoӣ[(۰p1ƫͧIJ0W,9X.m}^AӄEzM/5>[) ;-.iU\Kp{8c9`G~/QKqu E栚 }6?}^!fƋ٤/.{#4}'+qxN6ÏVR?Z愻XE,ldHdZ$q3X?4.'zE!RP8斘AIOaN).<њC u>l<@;f;~tl?4׭!)agKڎ~a_/p4,NUi |@ ̀?~F֞=,;i 7Hz@1[4Ɓ}~1Gi|SQ(Šw_Oʊm>"F361Wrzo^٣N{dUAi"3/?{SN'Mz4` 칈4ٓO[ y(zb>OȪ{`TpmKc?+Xgڗ:R)<X@UOL@հ/#ir5#w2T8]gY>ԴxN1uWD'(p=KXqЪJ}W#G]}ҴÕ4<O셹GuowNOVmjʱ c?1+\x:''5ۏ֑HQ3Iځ@4h9QځKMaAZ(A(ϥi84~ZCڀ(@QJ~B'8ҟ}?:P[;ӇO.MOJ9/4 aqK.qR@298t*MG~WIzdS8f ȥր=@3RԁTtǣ5x4!C~HQg>?IvEn逾z~R40TvFKNSW=Fr~bo>_ vsN?{L'#jBE!<Κx&C/ϵ>pݾjd/<הcB&88f7gU`y(Ü? mn.ACH|TЉ%rVEMvR;g8heYڈfyUOuPmnı?jV]Qg3N1ҭXZ)85*3 ѳu_֑om㙓t('+iVnrm>_Yp ¾VJO/23MEQFNQDm'?F0I)cvM+nq=}K.qT~(ؕjiS( 8h6h~GƣOVԮgʭ)w20, ~c){ דXBdt"u~4Qw)њ\h_֌@P?Z3(ǽ'9Jǵ.i!+U+kd. @O?Jn|t6 V@0w6r{\qȤWIfGIk6?+V_8> ?Qs-D-osKl0֩~O~^3zS|?5|@6s5Hcy*qJҙ,9g^ZuF泜dv%MN9y, ~5eɳ=qߞ3NI5m, u$MArsl5Yu(*lyF#hj@ ި)q? F @TGyt'(FOSޝ% ,11UL$1)*p SvY6QLAGL+#Zh@hUg<`Q^*75vcjGcOjNr8Ō?m֘! /(}){x?QڌZ /?ZJ9QR0h>~4{wA֊1A?4cqF \siJJ=($=OE%?C@<⛓iAic"ATOzz [4ɧdiFA i9#SpZQ\V:~Tp>^9G4v)@qHz`K(p1@s:)rI@0JP=;>\, 'x䎄,hhC<3ڢ[Gc?^.#^Bk5Lz<H:KIE0J(NU>ƬC{tsUiTᇱK.z'z2]NG|=o/GBZX~w+1ԘoZgOcNszMxD1nFÏZd=9Fz}F}A*9y`*ԯom$05O7'VIPWLC('*Or$H$fsoMM4ɩ:r1xyi-nZvӜ03s*^ghQ/cPIIƍdĹӫmݦ]RE;~|sa*sUKk}̯Ȫk3K;-壹Lз#dDɩ71xXCa\t^d?:oY8ڷP.wتZZymQ*V|v@ٴ*IslC@5I4kDɄzأX"HPgcaUo[|KsXzm($4@ni{s'j3)y?i94P4t$v4vG4z=i:iOoEJZOh)LQj_J' 7җ9qIE/=hR1 @k}iA8L^|qzҜ>O)ux23җ`珥8rxh@N9HQOݏzp$q)7)<ў{~r9;çSl4ZxGJL wwc zg8ui7q]I#'&\v*#uڼusd|WI(c ( U=3IK@]Z%]p[nd s<΃9M o~j29)y4jd/?!<{`2n Hr/Ƿ4I7&~EennсB$Ԭ9&D'>s2ƱlIwiCKVmD_xP摕C^*eܣӐ*AxG5\=wjRhϙ04Ж|m{X9jOz6đÊJhyʛO5Nz:R!VMBx&XnU}- 1v,K('$ՃU9la3)vwqLD2鶰쀣V;X3]RU+˘^VGW=z } Qpsq[g+-1=*{))zSO=N(QIG=Q@n A\ӥG$˸QM@uO=@3㎕KôxS>Qcړnr~~g)>)qq vsIӥ  R@ QE(S̆hRqސ^=:!zpx(zRiߎ)FN:xFqZU{fi/"c{qڐl+sgT:;#q?ZDeu`Lh'827͖'vc?lsm&jdl_zS3:4=6T5Rqsv,C`ֺ,`g4#M'אH;O \}dֽ(GxcZwqL? 5563G]94q>k:ء>?*j0HQO/u(XCH"ne8ֶ &{gJ#y9 ;F^Z~ť3.;ӳ{ PԡR$`eBc?RTMBGeY-^8kdg %$wշ? #h敥k;FT*^ uRat[2q4 FN{n_eap? 9X]xTil<đ}Et#sq#'OCH `\5(o|SwRo֡9q ;8AhY7H@A _r(7@"pe~NkxW f>a5s=㐽x+ 3YJ:}J>q3c8$Q$ZYRr}jxcU V!nsBGu'pz!&YT jA㊉-FQGTy(ϡ `S?ƨq 0vNcҨC})Fy1KI44ќ❜diA(ipsLry!KހIG_ʐiF)ɤ((p{QJ_suNuךSq1='N踗T}+EQT*kat~З΋ZC(t cޔcsq@J<>ԇ@ 銅 aV$BY))pyԱ8qJƩORqң=O昂@Sȟy3ڳ.dYO1EڇOq/*C+jQR63wLbY![vi5Kb<*̓NЂE&2kb I֦GN?KO4Kqͦ"?g֩ ,bW?*+bPM3ҳRy}"Gm6xUqOC*UЛ&&%3ԯҥU2X *}A:&?w#QP#K,E(8$9h79֨w;W bh/ #sa`?Sf@59M.Xoo~涤'dZ;k{e꫓FOT>IrK-]K]^8Tc=iA*Cʼ?>PZvɅ$da!|4#jx\Ըǰ)2 7 ~]*A*FxTJzۡpbԙ"ye>Rgl{7l-#iSLL9 wDpsPIh)n*e\gޗ9򓲃7UE~D #t:Zo%'q$MІ)+&.jhz*"Λv>j"G3ج6z0K։y(q* eaŖ%QY>>3L"8=ELױ2s^1=חؐMz[(+r1Jp9 9cڬqiE7#үh{b+T5hICdzOsgOS JLdsiq҂{Ep#I4}=LTTxp;T0$iqTyeQrj\^ ̄#mn 4Cl{D`RFj$frR0=j(AkL6qXmLTdzm~o[&RإrZ/\IYdC=T08,Do1isEf۸*i<:qYX 9rrNx}?Zz70#?Φ"]sLR2p{2犯ݜ =kZU`|(AAɠl8^XGgF;F!I}*?,u }ivKS|p-$S܄ ϸŒU-=Dðmg1H<YHC*jdk"MD>9}1A̬+u;cDž²!ĢkL̼#~=`w0g'{A>ƳƪE4Pk EVlSPMz'yj@wjQh 7sN 74\#&RQ۔**U9dzSeWQ0 e)` 3ޠ=3AǾjRD[,JKaz=B9_ƦS/"Tg`On jyD@jy20=4-y."4vS;Q}VZ>J8`➰G54$gbHN+&7:]0 ֵq}8US 9$R2n $$)֛mfIiB<ř㞽1VAX 9ye窔%N׭F+o7=zV="Ko/T%R5 h`mƀ"9銭P)ol͖iIR7s 1'ͽy8 "Z+ [?W k>7WU=}^c))Wt6"D3K֐0(Z#1wc)JUU BKj@J}j[6 d6s*2iUcXX13kj|rKj<8)A$]XOANzSՆA'4ɠ !OU ~r3%{p  $TP($PsU~Z/4Mr#IKڒ$B(R!=:p^)c~]kEwQjj%HĭjjyKcERc si(np?8 =Jp'hI 8&2z~p(=(`piwQS=q0}{Sc={994}ixژ9❞wzp^yNyN4cQS֜F=)AڐgR)b0 ӊ Ґ)G^z8=z#3W8tj͟?_S"ku8T?2:5vTC(`NtqHqJO=)?_Ҁ?@<? 42)a@#R@#q$Լ)TuG ȨN@##Ա3ڣ<楓ơ9TI{{ԫzR/>B@OMk;VBrrkQg;54Kb[P 0rIBW=8F^C~12A$凡~XԀKvW"h^WPή>AYcV rp3ata@'<t%ÜtCn!8<-İy9Y:Tv׆xSo"|ߥ6XB$q vVc$e&e5M6S淎b .q@4휝9j Hq@\}*Ş($CHI yZl0ud'VHNtjL>dSȧig5*B㩫DO,-0=-ΛulC!̇8U{kۻPy"NLք^!T`c PB:#1ˌlv0x@:WKg&9qy#ߎ8'/7#6OPq$i_ݥcx}>0~g99ޱ$b(q5d4ȃqx=}@Oc¨DN=ϥ08iFý0׊PG3riǯN)P2M4{sP=ij^9恓Ȥ&;[lsby mz52بMT*x"׭Dx-C!ڢ'C*{U"5*яJ<{ PĻ;P~Mjqڲ?xu+A!1+O2),=r)2{o)Z£9*5br3t>TMhr*B$cr:V'I'ץ6 rޜ8ԀHH:uV) Ҕp0zRt)9G4Rr9㡥'(p>@88 JQjQXsM^O^*@p?J\R09ȣN4zvyqO^OG?Qd֥8jXdTDR֡oƩlCg}je8@:T@%Tq^iZX}Rx foicKe-Զ^cJj?z%1(L3j]xI"o!imFԓ8=Sm̆,Âp0qRUd`5(blt&2@=TX#TI>^ϽM0 NOlң<@uQhXv܇yf8'S2o#a$'$t5,(-N/:jTooOP5rc֮#3ONS<፼޶3`47Z3\t$wq9'N/CFr87=Ntқ;!õ;,S 3RJp:CL1?ny"֬?zVSxZFQE(642 `+cKck<4+3Oe Uۖ<[FzCJ(yz<('czѹR! =(0<zBzgץG9.y8z`sN=j ; T`:w=sh8wSI9NP}q)94x>”n{Rr2i{spd#t9[ݥGo~ʂV稇R7EQ]"UN!=y8{fݞqw8I;i¡\pdJL4NH>nn=yO_\dSیӻrysit (L ֝^ii82:sNz^ԣ87֘SAH 4wsހ{v{f8q wɥ))Asүxs^Qe?ZH8۬cƓqOƬ sYVZj$#hRJ^piT!#ژ '@E4is&{TaQHޠhdwP? RT c"ڢ'*Y:ʣ !Dz{T EMwK%~u7 Ʌd:F) qhgk)lcFŵ[bgjѰPy1?@+. z22}+COyX -*sN9ւZʩ;yIkk#?i g&N]hNLϭ(j=l f3Mp84܊\ NMqLCڀxIAhb\3 0`qHxZS@n*5M"0QEq@*FQEt=6&|Pq@ky?Fw {Ҟ1N S)nҟրFkdH)zgjvx\>i:}hN ;~O>SsZ/j:QhLA!KP48ғҡ|TҡzƦƑEW#4 (dE9 V $PJq\tnKur8#N-n0!_5*m>laUSqA!⚞'Bc"Mp SayWqRd~P8 *윜TJF;b{RLS]/Rx< #֔zqQAlRqPpzhȦIGCǎE( 4Ӂ܃@=c8K˜NqzRA'րxңx<`Iۚ?:NqOa ==nwCU|zOSTs C&hSC׊qc?*Ԋ}!= \bFyMh"CRs@ĽW7:PFlC݁ա2Ō/Z18h$ ]2ar8zzVBÓV!ITq w`+ZX9 sX:nӟ¶,[Q:o`[w*N8椴F%Kbz.$ 2NU)cR1'7ŷjC6«\H"M1$(Xd0l$PbF_bI%ܑ'mc4YI#8gҝ%센̸.4'h85 ھWЛ?谂I N;WAnAs^$bfM~H]LNMOA\RA5d BIJZb4vP҃MPiv:gP(w '2?ƐAIZ dcF=iӭeWcDGEW#,( ('x*!՞7;|ʂOB9tR[a:i39qU =QfQ|v=?XǥH%u> ɺo`E9*l]]WJ|܆ܬ;)st842.N>N TAtMn4$ 48c&i"A?Jwҙ9$ SU4NqNj?:P%$MhHmðR2ddW5f:$"$ڠw52 KSvKLyH Tn*,Qg>&炵uI(n5`_̑m :Sarq*ϲRU$dc"$V y.ӑ#o {qwnhY y)SnBXElGHǁVqUОF~t? A_\usgh4dU0m-iXB4+E!XviwSE-ZbI474u:'38杓B Kj^W4cIQ ni}ikȤ'zJ(VXQAhXIOa ήAHo 3?& -:RgRc\6+7Lv&I;\"Pp~~pNrvh%9Szm%PǺTb<8MĹͼðqY:-Y}Sӗ_H5tV# j)8"~frt?H.\u:xXZAn[!Z&>\5rKtĵ2Mٗ9cAٹX4!Hɥ}jŅ2=qP!wA~Eopȧޤ[P1ccc}nid9 ͐}IbZDm`>+VDs8`C 2`~Y2Z."0DZ|U19'ƕFGVZl樳Nd,q>c21=i؜`tvEKvp9"Mak$| Ē8 S'B( 4'ҫjn^ЫAz jkWYl߿5}L"(oO7W2*$KΜK,ksCIȫ4iqVdϘN?J>, T4Spvclld6JLњmX}A86*K҂1sRCr#\sެ]ͰZE!毟M)Rg*ÑS%J|S>ֵ"`1qWE (WqVﮍÝҪW4vZ ETqފ((Ğdgy cMO?p(-xN>+r @8'd YT\fMS+|3y) 8oH 9 4P{&3HqqqO$f pH)U3td$N}Hw}cZi!|9P?OMSm9*8;MuAE,8#?*hA f@.>mSIJj7&49Hr cV:TRZX\|JG.iXe)7MDc?5gL7,=7HiO${frxWPR|Z?ֻ} '<#Y\?~5R"X{}-!?EfpK}(,{Wa/tN j4w.; 4C["[1)/4grOucG4CYn"n?8=:P:)砦w^&tv|N3#~t+dҝ+U]15bC,em5ڌGTx ɨy3E`{1Ūczf|4o;N=)44-'Ҫ Nv;=k2fh֦e7' Y1`mBʹLQM3Z$Vtnt|qLc 9<$bښ>o}@$1j5B1V.V`qקb`Ah&E q})PqԌRabka4KVgt L g>`/lY~ tHPA5@jM`)D9)%Y$EPXk4dq}qQpd]gT@rK/UQyM_MWsғwKj>3sWMx֬f#gZ Ȍ&[4^iXbi'ːlp;[qVH[ * ?Jĸ9m:wVIiNC[Ya5"(ˎ<<4I99RiKTSZmhrQE(8PJE6=@luOx&҃MIhLTH;{|BIrV׮i(QEQEQES&@O[,sY?Zcnk:A2u.Phk?#)agxemul-0.6.1/doc/20041213-debian_3.png000644 001750 001750 00000050545 13402411501 017046 0ustar00debugdebug000000 000000 PNG  IHDR<gAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATx9FBi-kƷ hK+QW,{ Zm!%'$rϚ'1 G?"Y]$<"c{U\8Gp4kP&"w8VwMDD"^8u2` Nb  ݉;= /[""ӳp*7mؔL7ҳl,|xwC>3+<-Cn>#Q>O!Qn^`0}l?Ƽ/xOh!>džmCncTO>oExf3GP +# = S淤dLҮ\P͵O,l6}|G;O?{G9Z)H Jj98spc\ݛ|v ZIo:7vD>>s|~|G߼~|~ZHwg;s:+FLJ?Bbo7upC)?W#4kTN#%mݟA*`,;_ӷ(u> Y=C>&,mćBq|:;癊D7It [ԑ/c7>vg^>>J&}dMImvs#W9۲/K ާ?c8?KXsŒ>pvLԶh:DZgF=9-3 3Umç|t_>TaoSa)c}]|{/kHn]"|8DnfT"  @Oj~d/?-X<^h?3o3FiEїX5M#ҶX,4Msm+M#{p5^"Ѽ;4D^;hK#Eȯv2g{r DMy~Y5mniDт&"_FlE~ɪ7DỈ\7m iޙX#́_D+v"Z:8m䛤 {4^xn_CQo_L G͏c|%-(I.lm_V߶_ ۭϯH{*w&JsVז`@F7 W;b dɝ5݁1k4ҊH܂Y$FmWA4Uim{;J6Ҵѭ589 JgVVZi[5܊!-дHs֕p SMsiU+5[m"4VN4}L2\[Vk89717$iY4栋fgDށh?Ѽ-&"XiΆ:+>}C@M^o穪mxPwt܎5Vo$Ɵ``uAZ_:@gN ߩw{/_snwy&;0}ȹ/Gf],ofykq\G8Gl.wsoC k *bv4XwBT g} 1l­MnJӇN'X`O:RvK.Mi]2 cC$8gل=7z,16_/O\ܞ:I HjQ^A~1*R1L)d̥390g2s.oG ǰc2`RF(+۝jy] nOKqxw0tz9nB0Vm ͌J7>\6`<];x ġ^A=6M>Bu3.O,3HY860Zu}] hI\sx|Mћ26N9'67?0 tGIoDž7O cPAsLR?/w1umLG$Mzك3VM#%]@af3qc^暹Snm}v5SkNE u״ _Ĭ39o]cZoV47#ox[ۿ=0!kRmr |[aRMXӄol^ٖѕ[_ '8SoEqS|nF\vX%7\N-δDÖwO3+h42t]5J|~st%Yma *s90O%*칎PzNX; 5'<<і_; }A=0w|Is}'zp~&sSrЎ+)_?1w_le-rh;ۈ|al~a [-XΧ {5L&KUsR3a:kKhκxqj|kK(5ǩy ;\ߤ0j A(5Kpx&C` wKNOmo!KIJUͭeCm~k\WbMwށk::-k{Lx{NpNEV?fj8MzȗX:4ߔמ tlUX'zS yYz :A J֞' dN/[1R؆:uA܊^XB!f7\N`tMr Iu *r:9b8 zC^@Զ&ф#a~:.g-o2 HI LYv~O P%d1q H ˷@A<]UH 5|8-l+,>pdtui+/l JkIO{!ok'Sx9jyX<גEZPL4ˉt It)R+G02 \>=DUwgPФI~J p`AjY*ibd;P~ |ߌ4ԊLx`gph88/LvIlJG ^]VC |OF?D~y-/T2S'r:a MZQ)W42,7u^; b5YYdn^!(Edz)gtߗZ@ ?Ǟok3Jc5К ϓս΢ٚpxUzqs[)DWJe׻s!(.꼜֤L݇+j,P, ?^nΗuz S_(N'f)BD R>dlJ[P_J'L> vt|Z=@P~$6w[ETsḤRUJ;$B/s[ K=:葌ŠKz}Y0w0#]?ew0K,,,]]mPGYZoA] s Lpdf[XZaY$'D?uu+9q]$sV0+G]beY}f/vphh)K? %jrrk J/ BuĔ.'W`2xғD}7Z3S5}=p`^zxI/|]}80CTOd'HM׷V'}* :wђ7QT='Jo8) }WD]K8՚tU,ߢnYMƉr,u˨JΠK`,wyݬ>d,wRGΡ䖞7ӪGn֋4nx5r3?!X?{-f/Zs]8Dp?=rgOUmy۫$~C{-lk볨AhH: QשjVn,_jɿYW$pzdu"I,]A=ȖG!{*J^ER'"Sp 9%n ÚÐp @Ia~~և5 o$>)r1w 9\ , ( <-t,`b?;0INٙB,.+o3p66ݎlhBb2֢НAz^Zf]#0W}G%7e1s\WP݃9U."D\9NF pzz@}P`R$2Ϳ4g.Aռ8[xHJ'B`V=hjuSάMau HEI32F *lܮjgB*bO`)z&> jpܒXI%hκQ9O0SˍwtJ*kub4I"-_k/6.AJLRB aB?1]V8};H9 C{caB`51UrPi5#L+׻? +ld4a?O>!x߃z-'8;ÐoAov5x Lςxypr6+pb6;pz 4h;sc ]{E/cnXg@6XH&,=C9 -[AH=<>Ou2& F⤁|7PU5e P] 3.j^K"SR}x9`vD:avz׉KwZnB^ ػf!IВS6"C32wxUcUۛi78'D/" { T 4@<>ANQ@IIT9kjSn׫`a gW~ sϞfԷW@BpyrR4 ʹˆzpss ~$%&2E+&Vi^+" ^Ԃ2-tY[֕@wW;^1`5vŏtX)ZY ?=>䬢/.eCy``A کb?A!m h/pm`DNt 6+Xܴ̙xeOMc i)[s[۶4-Iί֡ҘM Z|Nu{U[ R,~ j9p2H}2:,׌-[, (z3 M:nۥCq;zx p1x9: XccZ ӗ=a N, P8['2uzazp`09~Ttj~E~)YK,Nղ F&NށM>d3ˮ6r=l̒x.soIaٳa[\1h*|[%  C03|  5J_5PQw!dUش|~^ZE4쌄zkߝ!M- ;a{ס{;}eF`Y }XX`lHdE  礟 s?Կ;ދ5ٳ05:|G|zVyqT Bn 9X;5ؕ= jYEOoDg@.Xp:t"I=}q@X?Ok~O pjs`mCu3S`OVB] 5zݤestфu_[NN lB t z}uj":Üם[Nx_. $~v8*E̹^\k0eƶbkAu+v~ݨ6H-,}(Z4B10h-κޢr̛5`F{0Rq֥LԼyVK2h81*ڨh`xe92<-/w b~9ٶLf IDATs/"{9 -œ^L) 1ށF,ߚ ,;k0,/ B}a{O:3x]3U)j0LXϋ;:QxwcZkpz84JOdt@?0I'T" qs`gO7'O, ۝.w%Jz6$ w?}zwh*wZxZ޶*Sw8f`M%8x+',Յ-mfi5ZcS u6B?J j5`ff« MO`B} ܕu=3eM58їq@ԯ*]w u }y 6Lt_ނQG1aq%Up{Y|т}x+\6tIl,PLSR &.e\{˝7/OLrk `AxiR'4y\mOغ\3X؉}LKW}Aoq=Vw]oϝxy[tJͬ@9i韭foZU,LQZ[d.о2- qs8B}k|LÆ\ly+\6`?GcR܁,zY~^9!V9]2: a9F|PxS69NV PifL,O=F&xX^ A{r:պҋH? 7/Xod\pu <=sWvcM_O 00.ʦ^,}8oj/,Wn8,x_F\UV>xrI I46tl$BkP\RR,3&tޜfz(X|4Vg殚俢iUBN[?5| 0@QX9b/gR0q߃ k8`0QSףQoUx=5KdO "C*qz pR=8 ok ,}_,,W%YoJw/jBymD6s<;jwFw\;Qx9fF ΁3pѪZHc+ W]RDv17]ȢX$Ꮶ| 0_t$sHh ^t֔W3Ykt '&;c/$q]Q~2W]_?{\>wfz_0QwJyʓ0 = wO?.0 vk . S.f^!g9Snw<CRu]B|_C2(7C N0 ҊF3 IԳp 7o/:*{G <NM0wEgm[L j8LpMGǵDէM  X ViU}pvs`R-8NtvT_> `]е<}_@͛kst b=gBsx] =%]ĪLI=בc8A ]C~FWD%-2^ug?X+??:Wﺱ\:C> WfԤ,325 9s =QYf決W^$8n,Xx7N9>?91I?e/;nk *fuwЭb&v᦬h@0jo~~{_bw E|^~x8,Kf46 kЙsj=e_p?U~|#&#zb?^~{87:uSVW&Lw'9u1-iNpnɢs.]?6Wz $\'=YS[x= '0 |Ks^>2x=nHglwP`<\cf˳XSw8I8>Rńy: R٥~%hg=D!^;Kt,0e{ON޿\חL7)o Qg` ;qra{~]s/N{η'6+zK,:+_%_H!%p4%3_qT$ڢށ D`3"}@J!#HHɭƧ$T6_o"eK-6"B@Ӎ ށf5u%Nov_IdMn,iS&u'_QuBV?^_r`ݭ[ ?gW/|rSr݁ $OXQnݚU&zTr冣HJ4/;!ws}%L&UPdJ \6_*̏=LUzB =  lkR">K ~aHObv nN^&+bǽ y| 9d[x; >\V*` y H8w`}פf {E2 p`?8KڙpPs`vq)dz3Qg?5zp :3@s<k0*1`|1 ]/}^{ZSz yUJlȫ0ꕞ?BǨgX=/ܮiU^c lX$r`n7Ysg2eMW^S{ƿ^wnkfJ4yssRk M;ջ SӿKzoOZ/yz6Y-Zt[`\Uy ďvPCJx]w՜nsfW5z=[Ub8ai׸骙ZfqgLl@qR YڙZuG_^:Ҫ7_Jo [xTj\mZj?^עz\P:^=3&ݩf,KzUi̎dkUآ^稗?'ד?as38)Ou|iHl{"7nBaH\} S| 0_'5lkmW[0+z0+W ;2Si]7,zQr#*)o{OJ׫k9PK&xKyJhEX/q4@;s6Vnx-s`GQTP  ^yk F?sy"f!bn,J*);gz>)x`a O,L6e6+ 9dנ>2LS°Bsԛ15ՕwGA_+1yqkkt{C9ٻ:>Bͩ7dWaM0Yh5#n_~xqno|^Zo>,̻yfB$4~uSȅVaR1)բff])_^΅sJsL݇eC', ?^n_XQq/a5OY&v*"@gaF\H[&w&܏rppsl6_8bVdmG^;ĭ]c޹ϥe8.C*1<䬜էa&R`_?sЙgaY|80~ aYXY>9dy[xڲBi  #BjLeb쾅zPIw(&:!~Ȓ?a{8;,G`t^`msjfp]KL?,:aTgvc]Yb&@4[Pjl U녟+{$F㕽#2@L mdu&%1 3nMzu~k tBsX4wܯ?꨼بCS9a0y?Y r,^ێFkP#krK }{nMOYpa.Pؘ_M_[qGџC|է\y k;,¬ZS*'>YM Co Db:2Эrf *SD {|,gs,rznl;*,,em8wp4F` ީҜV~_i<M" C|`h>;W^JZ8m `~~4@`R B"aEO Y(9W!@N1{Y;qWW3}ܞ)db` Jp`# C5׉Qv"!Xx1">11]mZ;0ڵ^>o~_/fG'8Sl]Mz4ʼح05Gؓh֤dς=Xȝtf` Ksx}esL`h(*.a, ,BВb;Pq߳)Ք،ebe`qÿm-;jwW/1X,dĪAN^ B9&lh[o7'C`qB!5;[s %&; `j&AZVB!xT,Q34]9ݒ*5^Gؓ_UTu΅{^"1XzN=3 w{_Swx`  ~x$+XJ9qjfWdۡw{' e_-P & rZx~|81X J: r ՠN8*Ѣ,h^`*QAo+O͆whXPx 嘿p&]d2׵8 Ѩ@Ud?Mך> v/ْrE n1sE txLJW6^3˙z6 e R/g74=86to0b6 K3aHn}?QOI.C/7{D wwy3SI%땹سAP3[dʆ[;hpJsvBɓ^ӬK"2vZq7zu]\ѝݽXL&82Fzwxzn\>=sU[bwe=7 Xf6;b?/.z@ ,v~aw-JŴ[71c n8 Ǘ r/N9&Nu$1}9e/&=T`n3aBeoaG|%(Gr(0nR` y 6,:-oP;(59{ ~;,&8+[8ǡ:^Na?sFzk_wjw̋wyUw Zp|0pXs`֯r65yi4)GlwAkMM@mVzAx'/>iG%3y:JDoaA6Zs!?@:iV]tf`' , DKi/8!;lkچx]0+pv;uƺ+OBN^zs֍x]szz6 6{^tqu~}{9 N[nSoB6pHasMSxXp%4gUwakg'Pm󰉿9K@%K5jeU6;% 9AfDs ~TXYfDwK-mʩe/oZF hJ*d҉뇛r/UFp؂we%,[sjSǽ!&!4; R'2r"e㌵[.DyQ;:҇JүHݯYާ?qe ہI늅lA{ L/ y*r3tҿzs:?ߋ 93d|Xo6}I/ LUx)eNށP49v)<ngC;'{GeGoh~}8`6czj]YqzXp|\˕/>&y^k;6ת24d~&*x^ASk%2:]IălN_ Wܨ^Aa=r><̢?~pR-WӍ@ܚϐN4\RT’t{@Oљ䡹 li3R~;N,mfŷ8roVĥZ}*_0"9V*f&H̳ـn[~\aA??ޭXyLﴸmG[U `]?VS_ usQ~GoBc> m` ́Ć#EϛQIBid8e6nn &CgaA*QW|;ח/́7>=oO+}9S򝁿9IOt`KZ]6 ɂqu$ڸ&GikX{\6ǧ3olP~o[*gU8KށFhu%grB-R&;qa0t ށ~هFo~*68i݂ 29<uzY𙾎Ϡ2x;|;Aw bkp\0p`a#qM.fX_P_g2ˍC;pNTe~T#Sn3Dz];twρ9RAb47/3t?] Zч}_ch]y"c_lG&Tn1h ATz\GtNqptQAoxùm!'L[VٷUL'z\sfh|kyfX39ZuXsjkΝKObz3 _ݧp^wG}vO=Knʿ?NÖ "39X\SәugxDym!Y 9`s07y gw~}pZ~齃?'f~&" B `Q'_x^ \t\$f%pJhng>QJGΪHJi+9/nij]<Y>>>CCGGIIIKKKKK\KKLLMMNNQQRRSSSSUUVVXXXXZZ[[^R^S^V^X^Y^Z^\^^^^^^``ccffhhhhhq8qqsssuuuvvvwwwyyy{{{}}}8^88EEhhmmoosswwxx{{}}xTMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDATxgOP=ցZ{X"ց*-*%&ϝ4m͹qS5+Gqt-(Fit C3 3:(˕mRV%qGg%+cق!T5Z ~7Rh ZըWZ&?2T(P@ (P@ Dl=D,b.cuBȘM&22j!ןHN.Nd[ེ‰{|7w%n lţ۾#^)Ãِ!3T-7ZgwCuyn#m/3{†:%۾si9v-ݱ>vÃ|>oR :bm4)R f(P@ (P@;Ԛ'~Ƈ`)tIME %ZIENDB`gxemul-0.6.1/doc/unsupported.html000644 001750 001750 00000072611 13402411501 017256 0ustar00debugdebug000000 000000 GXemul: Unsupported guest OSes

GXemul: Unsupported guest OSes

Back to the index.


NOTE: The guest operating systems listed on this page are here because they do not work well enough to be regarded as "stable"/supported. If they become stable, they'll be moved to the guest OS page.

This page contains instructions on how installation of guest OSes could potentially be done, once the emulation is stable/complete enough. In some cases, it contains notes about starting guest OSes that are not complete (i.e. just booting a kernel, not a full installation of a guest OS).



HelenOS/malta:

Modern versions of HelenOS almost run in GXemul, using the Malta emulation mode, without a graphical framebuffer. The PCI devices in GXemul do not seem to be correctly emulated yet.

To run HelenOS for Malta in GXemul:

  1. Download the HelenOS kernel:
    	http://www.helenos.org/releases/HelenOS-0.7.2-mips32-malta-be.boot
        or
    	http://www.helenos.org/releases/HelenOS-0.7.2-mips32-malta-le.boot
      
  2. Start GXemul using the following command line:
      	gxemul -e maltabe HelenOS-0.7.2-mips32-malta-be.boot
        or
      	gxemul -e malta HelenOS-0.7.2-mips32-malta-le.boot
      


HelenOS/rpi:

The Raspberry Pi mode in GXemul is just a dummy so far. These instructions are used as a reminder for me when I wish to experiment with the HelenOS kernel:

  1. Download the HelenOS kernel:
    	http://www.helenos.org/releases/HelenOS-0.7.2-arm32-raspberrypi.bin
      
  2. Start GXemul using the following command line:
      	gxemul -VE rpi -tv 0x8000:0x40:0x8000:HelenOS-0.7.2-arm32-raspberrypi.bin
      


HelenOS/ppc:

This does not work yet.

  1. Download the HelenOS PPC ISO image:
    	http://www.helenos.org/releases/HelenOS-0.7.1-ppc32.iso
      
  2. Start GXemul using the following command line:
      	gxemul -M 256 -v -x -e g4 -d HelenOS-0.7.1-ppc32.iso  -j BOOT/image.boot
      


Mach/PMAX:

Read the following link if you want to know more about Mach in general: http://www-2.cs.cmu.edu/afs/cs/project/mach/public/www/mach.html

NOTE: Mach for DECstation requires some files (called 'startup' and 'emulator') which I haven't been able to find on the web. Without these, Mach will not get very far. These installation instructions are preliminary.

        

The following steps should let you experiment with running Mach for DECstation in the emulator:

  1. Download the pmax binary distribution for Mach 3.0:
    	http://lost-contact.mit.edu/afs/athena/user/d/a/
    	    daveg/Info/Links/Mach/src/release/pmax.tar.Z
    	7263343 bytes, md5 = f9d76c240a6e169921a1df99ad560cc0
    
    
  2. Extract the Mach kernel:
            tar xfvz pmax.tar.Z pmax_mach/special/mach.boot.MK83.STD+ANY
    
    
  3. Create an empty disk image:
    	dd if=/dev/zero of=disk.img bs=1 count=512 seek=400000000
    
    
  4. Load the contents of pmax.tar.Z onto the disk image. This is complicated, and should be described in more detail some time. For now, use your imagination, for example using OpenBSD/pmax:
    	disklabel -E rz1; newfs -O /dev/rz1a;
    	mount /dev/rz1a /mnt; cd /mnt; download pmax.tar.Z using ftp;
    	tar xzvf pmax.tar.Z; mv pmax_mach/* .; rmdir pmax_mach;
    	mkdir mach_servers;
    	cd mach_servers;
    	cp ../etc/mach_init .;
    	cp ../tests/test_service startup;
    	dd if=/dev/zero of=paging_file bs=65536 count=400;
    	cd /; sync; umount /mnt

  5. Start the emulator with the following command:
    	gxemul -c 'put w 0x800990e0, 0' -c 'put w 0x80099144, 0' \
    	    -c 'put w 0x8004aae8, 0' -e 3max -X -d disk.img \
    	    pmax_mach/special/mach.boot.MK83.STD+ANY
    
    

Earlier versions of GXemul had a configure option to enable better R3000 cache emulation, but since Mach was more or less the only thing that used it, I removed it. Today's version of GXemul can thus not boot mach.boot.MK83.STD+ANY straight off, it has to be patched to skip the cache detection.

The -c commands above patch the kernel to get past the cache detection. Thanks to Artur Bujdoso for these values.

TODO: Better instructions on how to create the old-style UFS disk image.


Redhat Linux for DECstation:

        

The following steps should let you run Redhat Linux for DECstation in GXemul:

  1. Download a kernel. David Muse' Debian-install kernel works fine:
    	http://www.firstworks.com/mips-linux-2.4.31/vmlinux-2.4.31
    
    
  2. Download a root filesystem tree:
    	ftp://ftp.linux-mips.org/pub/linux/mips/mipsel-linux/root/mipsel-root-20011216.tgz
    	19486676 bytes, md5 = 5bcb725c90209479cd7ead8ad0c4a414
    
    
  3. Create a disk image which will contain the Redhat filesystem:
    	dd if=/dev/zero of=redhat_mips.img bs=1024 count=1 seek=2000000
    
    
  4. This is the tricky part: on redhat_mips.img, you need to create an MS-DOS (!) partition table, and then an ext2 partition. This is what Linux will then see as /dev/sda1.

    I recommend you run fdisk and mke2fs and untar the archive from within Debian/DECstation or Debian/CATS running inside the emulator. (Alternatively, if you are on a Linux host, you could use a loopback mount, or similar. This might require root access. See e.g. http://www.mega-tokyo.com/osfaq2/index.php/Disk%20Images%20Under%20Linux.)

    In order to actually boot the system you need to modify /etc/fstab. Change

    	/dev/root               /               nfs     defaults        1 1
    	#/dev/sdc1              /               ext2    defaults        1 1
    	none                    /proc           proc    defaults        0 0
    	none                    /dev/pts        devpts  mode=0622       0 0
    
    
    to
    	#/dev/root              /               nfs     defaults        1 1
    	/dev/sda1               /               ext2    defaults        1 1
    	none                    /proc           proc    defaults        0 0
    	none                    /dev/pts        devpts  mode=0622       0 0
    
    
    (Note sda1 instead of sdc1.)

To boot Redhat linux from the disk image, use the following command line:

	gxemul -X -e3max -o "root=/dev/sda1 ro" -d redhat_mips.img vmlinux-2.4.31

If you need to boot into single user mode, change options to -o "root=/dev/sda1 rw init=/bin/sh".


OpenBSD/arc:

It is (almost) possible to install and run OpenBSD/arc on an emulated Acer PICA-61 in the emulator.

Earlier, I had this guest OS listed as officially working in the emulator, but for several reasons, it has been moved down here to the "informative-but-not-really-working" section.

  • The last OpenBSD/arc release was 2.3. This means that it is very old, it would not give a fair picture of what OpenBSD is (if you are just looking to find out what it is like), and it is not worth experimenting with it. See http://www.openbsd.org/arc.html for more information.
  • OpenBSD/arc was (if I understood things correctly) never really stable, even on real hardare. Problems with too small an interrupt stack. Bugs are triggered in the emulator that have to do with issues such as this.

        

Currently, I don't test for every release whether or not OpenBSD/arc can be installed. Releases prior to 0.3.7 (but probably not 0.3.7) should work. Anyway, here are the old installation instructions:

To install OpenBSD/arc onto an emulated harddisk image, follow these instructions:

  1. Create an empty harddisk image, which will be the root disk that OpenBSD installs itself onto:
    	dd if=/dev/zero of=obsd_arc.img bs=1024 count=1 seek=700000
    
    
  2. Download the entire arc directory from the ftp server: (approx. 75 MB)
    	wget -np -l 0 -r ftp://ftp.se.openbsd.org/pub/OpenBSD/2.3/arc/
    
    
  3. You now need to make an ISO image of the entire directory you downloaded. (I recommend using mkisofs for that purpose. If you don't already have mkisofs installed on your system, you need to install it in order to do this.)
    	mkisofs -o openbsd_arc_2.3.iso ftp.se.openbsd.org/pub/OpenBSD/
    
    
  4. Start the emulator using this command line:
    	gxemul -e pica -X -d obsd_arc.img -d b:openbsd_arc_2.3.iso -j 2.3/arc/bsd.rd
    
    
    and proceed like you would do if you were installing OpenBSD on a real Acer PICA-61. (Answer 'no' when asked if you want to configure networking, and then install from CD-ROM.)

Once the install has finished, the following command should let you boot from the harddisk image:

	gxemul -X -e pica -d obsd_arc.img ftp.se.openbsd.org/pub/OpenBSD/2.3/arc/bsd

The system is very sensitive to (I think) kernel stack overflow, so it crashes easily. If I remember correctly from mailing lists, this also happened on real hardware.


OpenBSD/luna88k:

IT DOES NOT WORK YET!

These instructions are here mostly for me to remember how to debug/proceed:

Download a RAMDISK kernel:

For 5.4 and below:

	gxemul -e luna-88k 0x20000:0x20:bsd.rd
or for the newer ones:
	gxemul -e luna-88k bsd.rd

From 6.0 and newer, bugs are triggered (most likely in GXemul):

	panic: amap_wipeout: corrupt amap

The 5.9 kernel gets further than 6.0 (reaching userland), but it seems that OpenBSD was compiled with too heavy optimizations, so the framebuffer scroll up routine does not contain any loads or stores.

Using a breakpoint -p om1_windowmove in both OpenBSD 5.9 and 6.2 indicates that 5.9 must have been optimized too heavily; it loops when trying to copy pixels to scroll up the text, but the loop contains "nothing":

s001553b8: 64e70001	subu	r7,r7,1
s001553bc: 61270001	addu	r9,r7,1
s001553c0: ec4c0004	bcnd.n	eq0,r12,0x001553d0	; <om1_windowmove+0x3b0>
s001553c4: 59600000 (d)	or	r11,r0,0x0
s001553c8: f1a08832	set	r13,r0,1<18>
s001553cc: f562600d	addu	r11,r2,r13
s001553d0: 60420004	addu	r2,r2,4
s001553d4: eda9fff9	bcnd.n	ne0,r9,0x001553b8	; <om1_windowmove+0x398>
s001553d8: 616b0004 (d)	addu	r11,r11,4
s001553b8: 64e70001	subu	r7,r7,1
...
compared to what it looks like in 6.2:
s001547a4: 64e70001	subu	r7,r7,1
s001547a8: 61270001	addu	r9,r7,1
s001547ac: 60420004	addu	r2,r2,4
s001547b0: eda9fffa	bcnd.n	ne0,r9,0x00154798	; <om1_windowmove+0x398>
s001547b4: 616b0004 (d)	addu	r11,r11,4
s00154798: edac003e	bcnd.n	ne0,r12,0x00154890	; <om1_windowmove+0x490>
s0015479c: f1208832 (d)	set	r9,r0,1<18>
s00154890: f5021409	ld	r8,r2,r9	; [0xb10c958c]
s00154894: c7ffffc4	br.n	0x001547a4	; <om1_windowmove+0x3a4>
s00154898: f500240b (d)	st	r8,r0,r11	; [0xb1087f8c]
s001547a4: 64e70001	subu	r7,r7,1

Note the actual loads and stores to video ram (0xb10.....).

Going back all the way to an old 5.4 kernel allows the framebuffer to be used:

	gxemul -X -e luna-88k 0x20000:0x20:bsd.rd

        

The following is not needed in order to experiment with booting OpenBSD, but can be interesting nonetheless: Download https://ftp.eu.openbsd.org/pub/OpenBSD/6.2/luna88k/boot and try

	gxemul -v -e luna-88k 0x00700000:0x20:0x00700000:boot


Debian GNU/Linux for CATS:

Debian GNU/Linux for CATS (ARM) could theoretically run in GXemul, however:
  • The DEC 21143 NIC is not emulated well enough for Linux to accept it.
  • Development of Debian for CATS seems to have died? The latest install kernel is quite old.

IT DOES NOT WORK YET!

The following installation instructions would theoretically work:

  1. Create an empty harddisk image, which will be the root disk that Debian installs itself onto:
    	dd if=/dev/zero of=debian_cats.img bs=1024 count=1 seek=3300000
    
    
  2. Download the tftpboot install kernel:
    	http://ftp.debian.org/debian/dists/oldstable/main/disks-arm/current/cats/tftpboot.img
    
    
  3. Start the installation using the following command line:
    	gxemul -XEcats -d debian_cats.img tftpboot.img
    
    

It doesn't work, though, because the NIC isn't working well enough.

The only use of Debian/CATS in the emulator right now is as a way to manipulate Linux disk images, if you are on a non-Linux host. By choosing "Execute a shell" in the installer's menu, you can have access to tools such as fdisk and mke2fs, which are useful for creating Linux paritions on disk images.


Linux/Malta (variant 1):

The Malta emulation mode is best suited for running NetBSD/evbmips, however, it is possible to experiment with Linux/Malta as well.

The general idea behind Linux/Malta seems to be that the end user always compiles his/her own kernel, applies patches, downloads userland separately, etc. For that reason, Linux/Malta support in the emulator is not tested for every release (sometimes it works, sometimes it doesn't work), and these instructions are kind of "fuzzy".

  1. Create an empty harddisk image, which will be the root disk that Linux/Malta will be installed onto:
    	dd if=/dev/zero of=linux.img bs=1024 count=1 seek=5000000
    
    
  2. Download a MIPS root filesystem tree:
    	ftp://ftp.linux-mips.org/pub/linux/mips/mipsel-linux/root/mipsel-root-20011216.tgz
    	19486676 bytes, md5 = 5bcb725c90209479cd7ead8ad0c4a414
    
    
    This is an old Redhat tree from 2001, but it seems to almost work.

  3. Download one precompiled Malta kernel, with ramdisk, and one without ramdisk (which will be used later on when booting from disk):
    	TODO
    
    
  4. Start the emulator with the ramdisk kernel, create a MS-DOS style MBR on the disk, create the filesystem, and extract the userland files:
    	gunzip vmlinux_2.*
    	gunzip mipsel-root-20011216.tar
    	gxemul -xemalta -d linux.img -d mipsel-root-20011216.tar vmlinux_2.4.33.2-ide-pci-ramdisk.elf
    	Inside GXemul: Log in as root and execute the following commands:
    	fdisk /dev/hda
    	(enter suitable commands, e.g. n, p, 1, 1, 9921, w)
    	mkfs /dev/hda1
    	mount /dev/hda1 /mnt
    	cd /mnt; tar -xf /dev/hdb; cd ..
    	umount /mnt; sync; reboot
    
    

It should now be possible to boot from the disk image, using the following command:

	gxemul -xemalta -d linux.img -o "root=/dev/hda1 rw" vmlinux_2.6.18-rc4-ide-pci-novty.elf

There's a slight problem with this specific Redhat tree, so when you see the message "Configuring kernel parameters: [ OK ]", press CTRL-C once.


Linux/Malta (variant 2):

The Malta emulation mode is best suited for running NetBSD/evbmips, however, it is possible to experiment with Linux/Malta as well.

It is also possible to experiment with much newer Linux userland, compared to the Linux/Malta variant 1 above, by using a kernel and disk image from http://people.debian.org/~aurel32/qemu/mipsel/. THIS DOES NOT WORK YET!

  1. Download the Malta kernel and disk image:
    	wget http://people.debian.org/~aurel32/qemu/mipsel/vmlinux-2.6.26-1-4kc-malta
    	wget http://people.debian.org/~aurel32/qemu/mipsel/debian_lenny_mipsel_small.qcow.gz (142 MB)
    
    
  2. The disk image is both compressed and in QEMU format, so we need to extract it:
    	gunzip debian_lenny_mipsel_small.qcow.gz
    	qemu-img convert -f qcow -O raw debian_lenny_mipsel_small.qcow debian_lenny_mipsel_small.raw
    
    
    (qemu-img actually requires that you have QEMU installed.)

It should now be possible to boot from the disk image, using the following command:

	gxemul -e malta -d debian_lenny_mipsel_small.raw -o "root=/dev/hda1 console=ttyS0" vmlinux-2.6.26-1-4kc-malta
NOTE: IT DOES NOT WORK YET!


Linux/QEMU_MIPS:

I've added a machine mode which emulates the MIPS machine mode used in Fabrice Bellard's QEMU. Starting with QEMU 0.9.0, there are other MIPS modes in QEMU (i.e. Malta); the QEMU_MIPS mode in GXemul refers to the old QEMU-specific MIPS machine.

The following steps should let you boot into the Linux/QEMU_MIPS kernel, in way similar to the run-qemu script:

  1. Download the archive from http://wiki.qemu.org/Download and extract it:
    	wget http://wiki.qemu.org/download/mips-test-0.2.tar.gz		# 2018-11-16: Unfortunately, the file seems to have been removed!
    	tar zxvf mips-test-0.2.tar.gz
    
    
  2. Start GXemul using the following command line:
    	gxemul -E qemu_mips -x -M 128 -o 'console=ttyS0
    		rd_start=0x80800000 rd_size=10000000 init=/bin/sh'
    		0x80800000:mips-test/initrd.gz mips-test/vmlinux-2.6.18-3-qemu
    
    


Windows NT/MIPS:

Old versions of Windows NT could run on MIPS hardware, e.g. the PICA 61. It is theoretically possible that the emulation provided by GXemul some day could be stable/complete enough to emulate such hardware well enough to fool Windows NT into thinking that it is running on a real machine. IT DOES NOT WORK YET!

Installation steps similar to these would be required to install Windows NT onto a disk image:

  1. Put a "Windows NT 4.0 for MIPS" CDROM (or similar) into your CDROM drive. (On FreeBSD systems, it is usually called /dev/cd0c or similar. Change that to whatever the CDROM is called on your system, or the name of a raw .iso image. I have tried this with the Swedish version, but it might work with other versions too.)

  2. Create an empty harddisk image, which will be the disk image that you will install Windows NT onto:
    	dd if=/dev/zero of=winnt_test.img bs=1024 count=1 seek=999000
    
    
  3. Run the ARC installer, to partition the disk image:
    	gxemul -X -e pica -d winnt_test.img -d bc6:/dev/cd0c -j MIPS\\ARCINST
    
    Note that ARCINST almost works, but not quite.

  4. Run the SETUP program:
    	gxemul -X -e pica -d winnt_test.img -d bc6:/dev/cd0c -j MIPS\\SETUPLDR
    

SETUPLDR manages to load some drivers from the cdrom, but then it crashes because of incomplete emulation of some hardware devices.


NetBSD/playstation2:

This doesn't work, and the playstation2 port of NetBSD is dead at the time of writing this.

        

To attempt to run the latest snapshot (from 2002):

  1. Download ftp://ftp.netbsd.org/pub/NetBSD/arch/playstation2/snapshot/20020327/binary/kernel/netbsd-GENERIC.gz and run
    	gxemul -X -E playstation2 netbsd-GENERIC.gz
    

Supplying a disk image with -d almost works. Then it hangs, waiting for keyboard input from a keyboard which doesn't exist.


NetBSD/raspberrypi:

This doesn't work yet. Starting point for development:

See http://wiki.netbsd.org/ports/evbarm/raspberry_pi/ for more info on NetBSD.

To start debugging/development:

  1. Download something similar to:
    	http://nyftp.netbsd.org/pub/NetBSD-daily/HEAD/201310032210Z/evbarm/binary/kernel/netbsd-RPI.gz
    
  2. gxemul -tviK -E rpi netbsd-RPI.gz

TODO: Everything.

GXemul> u
<kernel_text>
c00081e0:  e10f1000	mrs	r1,CPSR
c00081e4:  e166f001	msr	SPSR_sx,r1
c00081e8:  e28f1048	add	r1,pc,#0x48
c00081ec:  e8912106	ldmia	r1,{r1,r2,r8,sp}
c00081f0:  ee0d8f90	mcr	15,0,r8,cr13,cr0,4

It starts up in kernel_text, which is in NetBSD usr/src/sys/arch/arm/arm32/locore.S:

ENTRY_NP(kernel_text)

ASENTRY_NP(start)
        mrs     r1, cpsr                /* fetch CPSR value */
        msr     spsr_sx, r1             /* set SPSR[23:8] to known value */

        adr     r1, .Lstart
        ldmia   r1, {r1, r2, r8, sp}    /* Set initial stack and */

#if defined(TPIDRPRW_IS_CURCPU) || defined(TPIDRPRW_IS_CURLWP)
        mcr     p15, 0, r8, c13, c0, 4
#endif
#if defined(TPIDRPRW_IS_CURLWP)
        ldr     r8, [r8, #L_CPU]        /* r8 needs curcpu in it */
#endif

        mov     r4, #0
#ifdef _ARM_ARCH_DWORD_OK
        mov     r5, #0
#endif

Also useful for testing:

https://github.com/raspberrypi/firmware/blob/master/boot/kernel.img
gxemul -tvK -E rpi 0x00000000:kernel.img
FreeBSD sd card image:
http://www.db.net/downloads/bsd-pi-250580M.img.xz
# Extract the kernel from the second (2) slice' first partition (a):
mdconfig -a -t vnode -f bsd-pi-250580M.img
mount /dev/md0s2a /mnt/
cp /mnt/boot/kernel/kernel* .
umount /mnt
mdconfig -d -u 0
gxemul -tK -E rpi kernel


Linux/VoCore:

This doesn't work yet. Only serial console output is implemented, nothing else. Starting point for development:

See http://vocore.io/v1d.html for info about the first VoCore model. (There are some newer ones too.)

See https://openwrt.org/toh/vocore/vocore?datasrt=model for downloadable Linux kernel files etc.

To start debugging/development:

  1. Download http://downloads.lede-project.org/releases/17.01.4/targets/ramips/rt305x/lede-17.01.4-ramips-rt305x-vocore-16M-initramfs-kernel.bin
  2. dd if=lede-17.01.4-ramips-rt305x-vocore-16M-initramfs-kernel.bin of=apa bs=64 iseek=1 oseek=0
    lzma -d < apa > apa2
  3. gxemul -E vocore 0x80000000:0:0x80000000:apa2

ORIGINAL kernel (from vocore.io):

  1. Download http://vonger.cn/upload/vocore.dock2.bin (which may be corrupt? lzma complains...)
  2. dd if=vocore.dock2.bin of=apa5 bs=64 iseek=1 oseek=0
    lzma -dv < apa5 > apa6
  3. gxemul -E vocore 0x80000000:0:0x80000000:apa6

TODO: Pretty much Everything.


FreeBSD/VoCore:

This doesn't work yet. See comments about Linux above.

According to https://lists.freebsd.org/pipermail/freebsd-mips/2016-January/004332.html, a kernel at https://www.dropbox.com/s/nkwzx5omtx3ye7t/kernel.uboot.rt5350?dl=0 can be experimented with:

kernel.uboot.rt5350: u-boot legacy uImage, FreeBSD Kernel Image, Linux/MIPS, OS Kernel Image (gzip), 1467294 bytes, Tue Dec 29 17:04:13 2015, Load Address: 0x80001120, Entry Point: 0x80001120, Header CRC: 0x3F6D1694, Data CRC: 0x6AF182B5

dd if=kernel.uboot.rt5350 of=apa3 bs=64 iseek=1 oseek=0
gunzip < apa3 > apa4

gxemul -VEvocore 0x80001120:0:0x80001120:apa4

TODO: Pretty much Everything.



gxemul-0.6.1/doc/20060623-netbsd-sgimips-3.0_small.png000644 001750 001750 00000011566 13402411501 022026 0ustar00debugdebug000000 000000 PNG  IHDRtW>cgAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDAThޝZoV>ҽW"EJ4i3e"׊;v7f7Ni]`[_}Z`]̏d6iR;vH%tP"Ex}I[)| Ryss.sVzv>˳ۥԯ{yN^}<7y DŨ_M9Yk>w?~Ohkk.Đ8UE]Qrl*cK.9zCN:W t~2)͉*)D)R)0B]C7fS̔̓$*?#pEtՄ:ީ@B:dEŋFlkJާx5-2ڏPO0DQ5@_*$2:`3H3%t $.s`(:Їv Y܋G_\iTyba)nd]PmM,B 9(eߜ$ J'5Օm˫T-kPxFiXWv$` 1-GR9VEpoV5+(ԀWg\`|1!Jv/Dj%Z0 @q/p +C\J]>y B:&#V|ߣUQN0,k7IrZjIى2 ۻvXwMBmQmsj|M8w /PId Gz38waSkG϶A $񓢃b#i-1 1P8Bӎ`pxJ!x(D[f^o횃QwsW _j6սeDI= :e75`ȜTVz?Dh7WNNrٵ՘AL!+M#I3 h05- g8)xE GjV !bӄBxOM*S &r*wu=#)rxiNjTw l@ooߪpv+Z"WZ{bn_-[-ÇIjwE((pm]4uM2{?V⼁*TGԹzo"-_+scw27]?9 7eQ[&tK&ҙx9$Ĭ5ԇ;oq0[44(S@YhD)"܄8t6c B2t;jn{0{˚tO[ߓUхAY: R=WV=vH{X>,(` Ȯ+-T ŕcux|BЮ)-AOjDK=NtPs)q)\jbiwP^i[ [W%XM,ek* ZW5:X?9Zg9/ p~*.  3TtmkmweymPzYf$}V|Fz4[t#zx"3o΋'Mm6ópk;\1kV|<Y3 p)8'%m 􌞎b2^`1MKrU"IӽiFgYl1H#.U"ְr|ij`" e!"63|iƕ̉(xw8!R/+%魳˿b-~d8T5VoaP/|E ts޼cECT,1Uai_iPKDHêO$rQ'H@NPFԠĸ \RQWF$r$ec@$ ֓6mjoj h((G x&;=xu_Xǧx=K1uS֬͆tgsߦ SLa^4 I!y!3hA$/)X8)_]TdS $ڑAI\X&$D,ØiyfIE ?SǴJۂM)PzwM o׬%Lnj;LD{ Ȗ~,;vpGV? d22"(@J)EQƉtj'K -gsSi;}caPcԱZ'mvZ=/帑gYsGO'\Jfϣs d#F&LNDVWOPJSQ( ʑy{@N֏tok;݄h{KM^]ޔќgKˣl}o즢]R޺÷]9Rb6wVWnX9#wr F\?s5PyRIDK]Yh/̇mFHbR~@I"k$0CK@ q vs;^A'fH"&3Mۡ&2408^:4 * an͖YKn$E2W0Я^.gjdxEȬefQW-$Nj*B)Ҫ[JKU;@iߐ䑈@MsΚ7NAS$^՟ƎS)7$5n`$xo7̄K oNAiI4hϖ죐uDuE2ùtya#ھ%y^޼=S#K$Xؖ&jӬ0ژ\/MiAs,uim5D*>S=4%(Ab$^ޝ\*6wWņJr_]sz[ݺ(^_7D~ŵ++޾K8Xs1wgp!sX/rZ ާ3z둼oK d5YA>_v##F.ĻqB pzRMR!oC"($Da0"+2x`6,ei6Hxh4Df Kgn.4ʶ4oNx6xF= ggVcw%]H繃Ćne+iW* ceNY7g@ʙƠAћ_XgW}";wPJ-aJ&VN-fMs #Lh?8iˡHhyPSH6(j$ÓN,pZXI RVĴK̇jRR -QLE~ވEbIvTjKRvrs.};sX_MM4UsSmNn-.׾'E# y=3cj6C/Ssm{ uy@FҦ4kb}&n.\;=FLy_?}MP?o=kӺWz㧽A$? R@2x*tIME 1WHIENDB`gxemul-0.6.1/doc/debian-7-small.png000644 001750 001750 00000003056 13402411501 017177 0ustar00debugdebug000000 000000 PNG  IHDRtc}6gAMA aPLTE%8Q^w  !!##%%%%%%''''(((())))**++++,,},,,,,,--..////00001111222233444455668888::<<>>>>CCGGIIIKKKKKLLNNOOSSSSSSSUUVVXXZZ[[\\^^^^``ccddffffhhmmmmmqqsssuuuwwwxxxyyyyyzzz{{{{{}}}# MtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0~IDATxs40e֎u t@ H]ʀ h (/ a=KgV&F1:z.Xd3z}jf3 ]<9^(X\._)&cДN> O=gLwtjOj:=9^>SfN~vޗ}rσ=ޛ?M=E-jQZԢE-jQZ4msK/h_Xb{qiv} puC}zƕ+^z)@޺}m["?t%8 b@D?CH!@,@/A(׾#kDtM Xsh2 JtEP7s'\p..a"#bTJ&i5J ىdD MR !|) M8E13!srTހ&v:u oy1BXka9hc^"Es߹Je)b-NXJLTe"(fRJS,DItLnnA ͢:,8Yl ~Їkn s"lPŕ\6Isbs$v]b/U+#ġåc|h/C|5cT~jit|&Os#CCr#{zrف} }ù#ك1m$\NLc3jް?ݣ@l^$"r őbmM|sTgbyI~@'DYGd̟;NfQZԢE-jQZԢ:Hέ?ftdBEtIME ;UkIENDB`gxemul-0.6.1/doc/experiments.html000644 001750 001750 00000052130 13402411501 017223 0ustar00debugdebug000000 000000 GXemul: Experimenting with GXemul

GXemul: Experimenting with GXemul

Back to the index.



Hello world:

[ Note: This page is about the LEGACY MODES of GXemul. ]

You might want to use the emulator to develop programs on your own, not just run precompiled kernels such as NetBSD. To get started, I recommend that you do two things:

  • Build and install a cross-compiler for your chosen target, e.g. mips64-unknown-elf. GCC is usually a good compiler choice, because it is portable and in wide-spread use. (Other compilers should work too.)

  • Compile the Hello World demo program for your chosen target, and run it in the emulator.

The Hello World demo program is included in the GXemul source code distribution, in the demos/hello/ subdirectory. The README files in the demo directories have several examples of how the demo programs can be built.

Once you have tried running the Hello World program from the command line, e.g.

	gxemul -E oldtestmips hello_mips
you can experiment with adding one or more of the following command line options:

  • -t, to show a function call trace,
  • -i, to show instruction disassembly (for each executed instruction),
  • and finally -V to start the emulator in a "paused" state.

If you start the emulator in the paused state, or if you press CTRL-C during normal execution, you will end up with a GXemul> prompt. This is the built-in debugger.

Using the built-in debugger, you can single step (s), show the current contents of the emulated registers (r), turn on/off the function call trace mode (trace), or continue at full speed (c). Typing quit exits the emulator.

Hopefully this is enough to get you inspired. :-)


Experimental devices:

The emulator has several modes where it doesn't emulate any real machine. It can either run in "bare" mode, where no devices are included by default (just the CPU), or in a "test" mode where some simple devices are emulated.

The test machines (oldtestmips, testppc, etc) have the following experimental devices:

cons:

A simple console device, for writing characters to the controlling terminal and receiving keypresses.

Source code:  src/devices/dev_cons.c

Include file:  dev_cons.h
Default physical address:  0x10000000

 
Offset:      Effect:
0x00 Read: getchar() (non-blocking; returns 0 if no char was available)
Write: putchar(ch)
0x10 Read or write: halt()
(Useful for exiting the emulator.)
 
mp:

This device controls the behaviour of CPUs in an emulated multi-processor system.

Source code:  src/devices/dev_mp.c

Include file:  dev_mp.h
Default physical address:  0x11000000

Offset:      Effect:
0x0000 Read: whoami(). Returns the id of the CPU doing the read.
0x0010 Read: ncpus(). Returns the number of CPUs in the system.
0x0020 Write: startupcpu(i). Starts CPU i. It begins execution at the address set by a write to startupaddr (see below).
0x0030 Write: startupaddr(addr). Sets the starting address for CPUs.
0x0040 Write: pause_addr(addr). Sets the pause address. (NOTE: This is not used anymore.)
0x0050 Write: pause_cpu(i). Pauses all CPUs except CPU i.
0x0060 Write: unpause_cpu(i). Unpauses CPU i.
0x0070 Write: startupstack(addr). Sets the startup stack address. (CPUs started with startupcpu() above will have their stack pointer set to this value.)
0x0080 Read: hardware_random(). This produces a "random" number.
0x0090 Read: memory(). Returns the number of bytes of RAM in the system.
0x00a0 Write: ipi_one((nr << 16) + cpuid). Sends IPI nr to a specific CPU.
0x00b0 Write: ipi_many((nr << 16) + cpuid). Sends IPI nr to all CPUs except the specified one.
0x00c0 Read: ipi_read(). Returns the next pending IPI. 0 is returned if there is no pending IPI (so 0 shouldn't be used for valid IPIs). Hardware int 6 is deasserted when the IPI queue is empty.
Write: ipi_flush(). Clears the IPI queue, discarding any pending IPIs.
0x00d0 Read: ncycles(). Returns approximately the number of cycles executed on this CPU. Note: this value is not updated for every instruction, so it cannot be used for small measurements.
 
fb:

A simple linear framebuffer, for graphics output. 640 x 480 pixels, 3 bytes per pixel (red, green, blue, 8 bits each).

Source code:  src/devices/dev_fb.c

Include file:  dev_fb.h
Default physical address:  0x12000000

Offset:      Effect:
0x00000-
0xe0fff
Read: read pixel values.
Write: write pixel values.
 
disk:

Disk controller, which can read from and write to emulated IDE disks. It does not use interrupts; read and write operations finish instantaneously.

Source code:  src/devices/dev_disk.c

Include file:  dev_disk.h
Default physical address:  0x13000000

Offset:      Effect:
0x0000 Write: Set the offset (in bytes) from the beginning of the disk image. This offset will be used for the next read/write operation.
0x0008 Write: Set the high 32 bits of the offset (in bytes). (*)
0x0010 Write: Select the IDE ID to be used in the next read/write operation.
0x0020 Write: Start a read or write operation. (Writing 0 means a Read operation, a 1 means a Write operation.)
0x0030 Read: Get status of the last operation. (Status 0 means failure, non-zero means success.)
0x4000-
0x41ff   
Read/Write: 512 bytes data buffer.
 
ether:

A simple ethernet controller, enough to send and receive packets on a simulated network.

Source code:  src/devices/dev_ether.c

Include file:  dev_ether.h
Default physical address:  0x14000000

Offset:      Effect:
0x0000-
0x3fff
Read/write buffer for the packet to be sent/received.
0x4000 Read: status word, one or more of these:
0x01 = something was received (because of the last command)
0x02 = more packets are available
NOTE: Whenever the status word is non-zero, an interrupt is asserted. Reading the status word clears it, and deasserts the interrupt.
0x4010 Read: get the Length of the received packet
Write: set the Length of the next packet to transmit
0x4020 Write: command:
0x00: receive a packet
0x01: send a packet
0x4040 Write: an address, where the emulated MAC address will be copied to.
 
rtc:

A Real-Time Clock, used to retrieve the current time and to cause periodic interrupts.

Source code:  src/devices/dev_rtc.c

Include file:  dev_rtc.h
Default physical address:  0x15000000

Offset:      Effect:
0x0000 Read or Write: Trigger a clock update (a gettimeofday() on the host).
0x0010 Read: Seconds since 1st January 1970
0x0020 Read: Microseconds
0x0100 Read: Get the current timer interrupt frequency.
Write: Set the timer interrupt frequency. (Writing 0 disables the timer.)
0x0110 Read or Write: Acknowledge one timer interrupt. (Note that if multiple interrupts are pending, only one is acknowledged.)
 
irqc:

An Interrupt Controller. (Note: Not used for the MIPS test machine.)

Source code:  src/devices/dev_irqc.c

Include file:  dev_irqc.h
Default physical address:  0x16000000

Offset:      Effect:
0x0 Read: IRQ status as a 32-bit word, one bit per interrupt source.
0x4 Write: Mask one interrupt source. Value should be an integer 0..31.
0x8 Write: Unmask one interrupt source. Value should be an integer 0..31.

(*) Note: If the emulated architecture has the capability to write 64-bit words atomically, then writing to offset 0x0000 of the disk device should be enough to set the offset. For 32-bit architectures, the lowest 32 bits of the disk offset should first be written to the register at offset 0x0000, and the top 32 bits should then be written to the register at offset 0x0008.

The include files for the test machine devices are found in src/include/testmachine/.

While these devices may resemble real-world hardware, they are intentionally made simpler to use. (An exception is the framebuffer; some machines actually have simple linear framebuffers like this.)

If the physical address is 0x10000000, then for MIPS that means that it can be accessed at virtual address 0xffffffffb0000000. (Actually it can be accessed at 0xffffffff90000000 too, but devices should usually be accessed in a non-cached manner.)

When using the ARM or PPC test machines, the addresses are 0x10000000, 0x11000000 etc., so no need to add any virtual displacement.

The mp, disk, and ether devices are agnostic when it comes to word-length. For example, when reading offset 0x0000 of the mp device, you may use any kind of read (an 8-bit read will work just as well as a 64-bit read, although the value will be truncated to 8 bits in the first case). You can not, however, read one byte from 0x0000 and one from 0x0001, and combine the result. The read from 0x0001 will be invalid.

The cons device should be accessed using 8-bit reads and writes. Doing a getchar() (ie reading from offset 0x00) returns 0 if no character was available. Whenever a character is available, the cons device' interrupt is asserted. When there are no more available characters, the interrupt is deasserted. (Remember that the interrupt has to be unmasked to be able to actually cause an interrupt.)

IPIs (inter-processor interrupts) are controlled by the mp device. Whenever an IPI is "sent" from a source to one or more target CPUs, the interrupt is asserted on the target CPUs, and the IPI number is added last in the IPI queue for each of the target CPUs. It is then up to those CPUs to individually read from offset 0x00c0, to figure out what kind of IPI it was.

Interrupt mappings are as follows:

oldtestmips (as native MIPS interrupts)
IRQ:  Used for:
7 MIPS count/compare interrupt
6 mp (inter-processor interrupts)
4 rtc
3 ether
2 cons

testarm and others (via the irqc device)
IRQ:  Used for:
6 mp (inter-processor interrupts)
4 rtc
3 ether
2 cons


gxemul-0.6.1/doc/20040504-ultrix45-boot1.png000644 001750 001750 00000042556 13402411501 020131 0ustar00debugdebug000000 000000 PNG  IHDR ՐgAMA a8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IDATx=帚&1r AFY 1Ӹ{VocsSHEAС(JǏpG*pbB_;N,ȿt&xw6 S};d 탋;?7B|-<.ܡ{=k|p;$x<_WlpsYn$rͺ3>5m.}sPćKUBptQ(F{֩ӋOSy=\|]mQ&Erݮ_н(/%vdW?8WjQ\X9>{J郋~qnAS~^F*\wT~L˲%NId:drQ]KW6bBnt{E( Rn',oܿ#Y8q_J8O7_ȼ|Y_纺zUϮGc^]g*|w?ߓ \{$+GB0J蝸@_x<k >Ǐ/^ǰR߾7Foo{>hHُ? >0'$B $B $B $B $B $B $B $B $B $B          B $B $B $B $B $B $B $B $B $B $          $B $B $B $B $B $B $B $B $B $B          !!!!!!!!!@H@H@H@H@H@H@H@H@H@H!!!!!!!!!!@H@H@H@H@H@H@H@H@H@H!!!!!!!!!!@H@H@H@H@H@H@H@H@H@H!!!!!!!!!@H@H@H@H@H@H@H@H@H@H!!!!!!!!!!@H^,"}r1=WtN4LOPiПEi{p|rdMYr_/hk۾]~P4m4~r=:փ~7$D"D)GOtz )Ez} Ž׃wQ!?l +f'k-p ]n,/;vsvV.; Ta}O֟<(l|=}k^{N$zp%L"\uOZ![喘۸>RYOVɟ.W\=б͡#BBkEbc[A^?&Q4T<:ԯ<0bxt }sQD9N1̝+LࠐlW\_)[ߡ_9XcȌ\J[ћGܓPy|ʺp>Qwnf3,'Or}{y$o0aБWMyZDdl5<74`7)ؐQyk]oFvuLV?719>mOIojϝ`yֵj!sk{5\wl|^5MN BBoO \WsgklWgsJrS eew^|:rk TǠaihOE !$нn~_D2a!!h0xK<{y9!} !a;.__]W+̿w9x+Ctz}<7&Sl0PaJvvtHxSI:ڕG7MetX\G|n2*#EZfsz/]osAJE/7 uH^v)$W;C U=ڳ^Gŭ5Tɧ nW ȥ&BhgHՠӧDP(1'O/!tq!!~H2fSzs,b]fwsNμnyOGR!!~[a|br+L//W<OHH֠07 _&?zp(׽>NJkOH֚r`Ae~}=9Dܜ%Z+S~az YJ $jp4 ra*+0*=U.lv/C~!aqL}P9VF犳B](\QGץ}t9r\>'P0vW5y~(gOs_G0wc3Xm~va }lVQݫ2Aejem6sY}?LG+oC/\V4-B- ;,I?RGU/G]Sk?wmwtze%[nṣmxz6?{Gg?|l]ᶹ+7eeC(umQ\s cߵoEY0WGmjpQ-ު[zqL/cq\n~&^5k^L84$[K֋Zpr*44ÞεX?W[k>D %`}y0g ܑ%;P#Пw 6q(W *}[ g0,KB=;>D=]~I 7[Wp[נ y;]ֱȆ]fHhY;r߬pYKMm߸}epg5ܛmx^ءO"cP\fyCnuN8^>~cIѻ{gn =8>{9}dq-\nK?z !PL):;76O/tfb7GQ+w/}~xf5=0݇u8X7 %現D9TGs3,ZzF׫k ɡKe?s''#2ŻzYƭf7 Eݟ074a(`pY /|7"FKs{Iw$J%WPH:7amv'_5Yfg pBHc\A\7BT2w*>#O?gG'״_~+Na.*vkaU*ty}uSi}'i$>t<s"nv\sHS4O#WӥwѰ4;|w܎ C p'ڻiq۷P*OTsK>^ĕj^tR="v&a= Kn@R^[9q;e K%|@c%?-?m}~nR:,!a]o+,r ZntFܐ]6ᆡ޼qysH{-4:2 ?/]#gqB $B $BBECu+6|>Gh= 7/ޛ7N^ˡo>;dќ+ EvT蹈nYCCB~ɂ>WG?ԷJDp>3,DžE nTY/řn'U^NsD#^[L2g_&w!t;Anon\^d!a]&//_ɚC   4W^e0g? z[{qRCOμ(rq_XVz]Y[xGhg YX ?Sݫݱj\Ogѫw"Wޥ;^~#",>VG.Cs_hz7oxo?A5-;֗}n~힛!F?LcB/G7y?ɹ#fT^м l>zj뵎o8!aQ_FP|*b!'Y hſL¢eKRKZwrѽ//\ZӫGwxEmZvsbx3p/G&OG;{W~v~)E\ah]}y4œOMWkVyPhK6:]g7O\3bwj'w9P2_TKU(oa#Zmiui{rOBݣ?wA!!w\ܗ]iarooCv@W9&~X>)`ߔU׻mY{2   ip-idP S*?lvGɗ.ޗC^)\NcHE9n B\\(5  GX_s(.C7ӑ0oË`P@C`}yⶄGG-N0} x1fN}q~zaA M0  J_mN_|kg羌3ҷТwB˽Πax{u[;/{j~ާx!f澌z~<{#yX{QviBB7]/y=tgeXX9¹7O'_|c#XnM Ozmi7o=۫HgGem̡GlpPK/grl<ۙ϶.# Uvr8CȟqYd\\CWv~^ߟ c/"P{Jї/?C휲CUcQ2 IDATWzFbo,w)wzz}]l7*uze rBa3-~֫PBs_^2(sn/Y|g57$ԌgeƮ+7Vo9 57|\to?wM5}oHϚ{ jYNhz? M\n'Zԏs[JÏظ=֬_DCϴwW`o\@H@H@Hwxt=\+$TV]4lgξUOqK<p0pr[S6 v:o/olP=$Bl'z.9gbmgxJ=wB}[HpGpiv^%䰸~ę%FrBYܖ޸HpBBMo}q5 xC!!x-pPHR_!!aYνm28q, u:_/9E;{RD ^3$Ea\7'h-3y?O6BBXUL'EB֗> ː uxt$cy=:9"D^]=ׯ*-v=fH˝/ Hrp \yt,ޏv4|k͟loBX. mL$/7rau5GHD?RGs>rۼ-⾲P;W_45}2ɔP ݝrGy ~vhW.@+k6]RJyl=r#N ~f8Pݿ:אv%Wƭ^q+̟|AV~B^*$<ƿO,5}ͿCsC;}S?>So9Br/H@Rrgq|zrۑMͧ}VM/-YG_6m&}ag:%yqD-2Gj+]Gm|7nr j!P3MyYTdv-\_$6 ErźLH^-$b}țb[NjCx 7C{@ޓ۷h}ܫR_ӣu !:Y.BXp&aqk`G/+u-{R.NK [nLN^?$ܐP9M#GRv/B vʵ5=ڍr;m?t|0yx >  $B&!ݞvѕ*㎝Qp|sWn>'F%$\x>yA Ӝ(Ͻ^neU=OrvK0n~&{zypnqܾ{y{4{CBT/G$ϵ?(-y$]Q*B)׷rNH~4gá`xH8*˭,4f?W+^)̟=]Um$y1xPS(H,cMx8vi|jczui1GeEm_e;kx={/Cz|HuSoLNB;VOxt|\npPspˍ|]X_7,KW+i0ϡk{uOC@ $p] z%}@H@H5O \L."K O'oH;mPh;HqXѹwJlN37zpVa/c^a^+?"8$\_?n,,S&6Mt'\{{Rd_O^xߟơ0Է8}mjD p:ruS:' /*mg_;s˞î5h_ljvYfmΊmGN 럣^f3*:W7y5ilXߚߟySw0Ϡܑ=%7rvƒs$r(Z4:jܜK^Ys'gq0.!Q~˭Wҭ_Gť)W״ɇwChzaO.^=8kq,Yc\fr\H,sto2J3T6iu-a!CIzV4/$ |Q'$K| / ›> ]\;嗒p Y]_)yeEC{SHX0L>o\\zKIX @H@HCBiߧ6]/=+7{#$ܺ^ʍ=F?o.\g'&䛕-[KNy Zs~ˡ;^ns,Y׹ ۫j}sRyYmQ rQsGSB( ]eQ~MW8$lpy5hbl?Yh/7/XF.I.8$ܨv@O.pW\`ezi. a:jtҢl=A{). I]~AE?w'aqBhIv<~]bѕ<k 55]qCNHǹ6kkfZt+;xGAHxaGrƲT6>  $BpϿ^`H+{T5>&b>N{Ѹg,^u۸nLv)4ţje ;}+yyz~3^?n?N~܎CIJH]r͙7GL/n1zBO\btpi[{@HUkh 0 C«>z? E9zJ8>uk8FXdF$!!靵OMοr۫ ޸ uEJr2={ѥ ߙӳ  ܓ4ţme0 ;}+yazz99> 'u9zuH] ^s}̛ˊ#o^̧W.1.۽a $@S,k Ҽ |@H@HƆ^o:TWx1s:!xG8|n7VOwqg_&|~ ν~h`lH(/MBrù%Y.g t*~]_M~8=^Y3Vq!m" g*vީ}runm_^m.^FLB2e9HcuJ.Eǡr|3  >e`S7'ڥ+s¸q{@H@H9 $_Ysny*~^y|7Ni5aM/BB;JtQ)XS?tY/aU{irCh7Yt2 ݳ\a~y3 `r{8"$BN(OV<0Ck'hsSSk[qCʻr{%S[ΟU_D.;>pPH|DnVT5Ye50Vӟ=#sw};â]*b+9Ε2C~B}=~D:3υK*V*,*oGiۯ1 $npu`0a*eOW;̈e]a[òͧV.7ZO/vӣ[|U`2a%Ͻ?WgrG\4lЕB^ WwzCaQNͽ vz5L~r}kֱcow.c-T<+isB@HwY) x!xaptHƮ=^w8 A1s*ۯ=5B˝~QtnKyk?vmFdzv渭'Hp.X_榯knQ4ϿП-zyE9zdk.-wϸzԚ^CBܑ^̵kkZG!NyK!x0t B͋)OV^;r?j܈peAxz많x"^,Ur^kF/ni]_.j7O/Y/~ N#o^6s縭[}sݯBuVzG17Cy^l4ǭ]Ot:8) wr@.Pa!O #}}nwnrZIȷJGTo0kHXqBv'de8xDCN05$u8^sN֗. t1gr*+ڟ)7 l  ‘쩒GőwG&F֫sjU{rBa|jcn|ʕ:T~|?W8U $,d{3?t+)۠׷r}Sގ]BNrr_P~8qΐbv(nJwO tyLr~B+ۼڝ|⳾/_,Ú'2 5tYvBBsE[>/dRh[AݎO7_\Mxڎw9cpۅYV^?:}g[N螄gHrqOnCByLO~=EmѦah W! h6}@H!SN!Md! 4Dpo\.̟>wւK 3sjm\L^3$$k{eržE"\6Va7nօ<P'Ğ>UKuHh.G 7\00]TĚ |zqonrkSW ͝$)/ro}k1|B$|J>]C]x) 8%$C  p;/$`zyٗ@Uj3 >\ggW~j7柿ty M6}OBh557b˾_k?}+3^ӣF ?$YX0ӆ JeqmXOv˝hk&dF7ʞ Wv߸/N@H Fhc7.B $B0>$zE:E/OϪYH;61lJ?5F` /G[n'hԌOzUshe4Cxz?Cº6 ·?}9/s*Άӣϧ\Sŗ-_KB-y<+ aGq.?\f1WMZBCgZV_-*!9] st;ą9+5 |$ښ·W}G+گw矏x[S(t#B $B $B $B $B $B $B $B>ד7B?_m {g:'&r&?# r7.|<?~>O{tl 8 ZF5^ItIME(&DrIENDB`gxemul-0.6.1/doc/20110624-dreamcast-gltest-small.png000644 001750 001750 00000110532 13402411501 021747 0ustar00debugdebug000000 000000 PNG  IHDR-D2gAMA a=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATxkpٕ&x3Ld&@HAIQɒJU\[eFǴ7ftlwltލ;gcLD̮cw{vݮRu\TVU^|?@@&N`"%ԣ$QZPN~}[owt]K&P5tt %(aaM&SX =\_XJ=<7$2]}˞<~$٘_<@Y1;8f||}Ʉ@GftM6EjلS~3;o'plƝstp"}GPbBx_ X+ךLЅ- д6IJSWI_GqڴHO^9< [(rVj5n<5p w? __;JLslL/IJPӔ3L$I) _x=f˗S4,vkْetd  ՆOV4Z(V8[syq"8l&AQ$i$,$Á$`lBqo6 Y Wp:3 ՚ͦ7wZF%$u+0+|?C$r"6$FYLZCsn:ma#ϿŢfeIb@xKT}kVZ+4,6ekkfŽR/qT9bbY%iL Ip huUnEcT})h?*Մ5iBC74-dY)5!&*I!/~j$/_$JaaAj}©cن9(??G{jPo& |edMwnXy[BnS>Ojomm$IQTpxmm ka7n+  `0jV$ ^ YPh}}:%l6YQEvrbT*E^o.۲b WWWC 5m^FٴlU*al.go4,,[Th;W1ܗj:|5nXT*5<|$.-.uuuUkUM6١Õ ?:2B$ >Wq0Ó7'\4}d:>|xPQť%1Zc1;mfN'CQT!<i{^;\yn~etTQZ+Htii Ahͦ` PzzzH|Ppuul6әCЃ;@"5|^Q]e9EQppLdsF1xhદb8V*fٳgʥ'\6#Irjz:͝EQTC%EVH"IǰޞliZfZ+F#SSӴM&$$IIW*EFC$)Jq$ife3%#NKS@00>> (hR h4@MQ>D-ǽ۟}ٞF?p$Y@.{V?Sum#Ctwww^i+EbHЍBpɮ. E$ᐕu]O&P0΄Au]Eq0+E$IPJQǏjN$ EQA:t( fs9feaQl81Q~zRJn{' SEQT&v<D?AER,4M ATR]nW0~rjz;wzj jBaɲŦg`&4(,ˑH<>5=zXl49]Fda\.ˊ4L_p,j&ݶ}#ÓU h:}($J7l}43 BN477p@\_R /E_1պu:,3#Xqb!xevJ%@op rXhP/0 áb?A4n ˲T*A83yvI#&EEetD"Jr gNB߻SS_TI0 ttuA>$|^÷co㝝 EVt]o"{w*,܃d۽Zxo~Sx8kZ3с%܉$JL&, 7db}GPGh4]YYq{vnNB!o6I2 f/,h600Nr0 K (ONN6ޞl.WV}>I.s}maEUu]gh򭬬6[$M(;w!ټza2VVVv{RF %I-U д :_}"hl.L油g=j[߰Xp n9{,ˑh^\.Պc8W*9vԄƢ>]l.rD$\>/r" _{ Dg"l6Alal0m}^/`#KZp EQ`^}\)C! UUټ|>?xϞ=x,v|^o!ZNVE#'OeJD2E4ñQeY e˗jI7Bф˩ec\JYn*vq\\HViZ#GdYK<?>655yT*ȒDX,E4 Et&SժZ.5-*+J2;77oYFhqVTjQ(xPey#Q,r$q%X,¡\.g2Ux~y9a$IիWWq=~ 0H?ڬB $jSS$AʲWxUպH><(RVZ(..-A`VILhPUÇqͦkz&JR$˪ʲLD63KKK|xr2H/K]ٟݚ{dd8 eeU6с%H&tlYw2׺A*8Aꜙe;+>K`QR@m"W0  fsv;mZ'&&u5I٬k6RZ֨= q|a:x^D"~ ё} ^hfB~h ###5:"ccc ܽsw5 )sLlηŲ,W EWWg__B0gN84 Cy}8ker6:ZUe$7Ãn߹+˲e}k\N Czv203x._^Pm9'#NzΕd?M^wge0[$D"oFwUYFdBsmm̈́BPRYZZHq"qLU/> |ٳ++յx,l6ߟYHtԩJ EЏ~+}3ә̾L/TsoPG>$9kl6aFӨ7V,rZJY%Y%rLfb!I&4+eUQq7f,V*h; @KYW*y<M4MoZ&Iy$I20\l6a&((z|ǝN'_% \:`v}a, *GXbm~Pd28n%ٽ<28Vk}1YjMUJ(^]]H"70п5 j$ ! j;KRCJ:<v2aTM3 czzz;Zl4&9J%Ldϗ%FRX2dYO??xJسEEUqT*i6;&̘ٙ1͊,;AM Y^o#&l6?4mhhkyAժIRp(4rd0 Iw&U̳ܬ2/\x"F !&47u06њ ,Ǣʊ$IZ4] pݕJZ)J h&˲T*W@dYf)r9]#HP`澳[brdYVBp,,,InwP5ҥRvu o=Y%0 ]fR5$|edi?EQf ,kj133m""l@rt2\Ep8qHm/|z!+$Imv \U#|>ȁ߲gw|agM(իNzJ(nCj`XIq1\N8YUsٜl-6A8i몦Oݗ 6o@[8FC®J%:]\.~g-zh\ETDR$J/z O'HZW4U(LrBA ìd2}p8Z__xWj:vo;CdDV{zznF6iL<7Lze%B3u߹sEQJn̴a::sg-npAxs+AsZX ?A ,i; y<"eEq9(^FWx A]U++J0@t!חZm\1 qL&xN,..iݭ2m7Rww" 6;3l6 ,ȿxo_esLo~7qWlZe/%j:,... AfہJ F/;{+#㽽(2wuu6ۃ(ǡCm*NMfm6jmdHǑz6< uIH4q0r$I$Ţylv{Vs4M_iJ${$}1g--K&ہno]z8[v/V0=Olg{_Zz4M% 9n >ɓ˩Ç\neS+ηJܯ~vB0::j(ټsx[o7 IDATy<Ņaxfffzz{dI,g|6L&\O~ΥoS@ͲoYͬ^xd moyJY,‚˲a( UdRB*|i]%Y &IPF  jBM<ӴVW*<A)I"/NI["(j2Hp]!#qwTJ ,:,4m{H[6z*2<#>1v?۳^odKEͶW0 ]u]iԷƳ᪬3ЁF/޻K/E|>b1n(:::vK&v; HQXgz@``}Y8n@$68x(Umo+^U&gV xan?MLL~/%VcE \o4^P0:z2:;x=x,8&Z-NWjA>q|R7-"DQdn"QfHò$Enټ8l__߾axu .z]%Iz8Ljc80bq%4 E p yT or!>|xZinV8f9 ccXTpAJ:rh4/lBRӧ@d.Ba/ggzQ$Ϟv4`w^"a4MVR'tݵZP(tww5Ɔaͷ!ds%YM& T6k<1>z PT h0d2FCo i3L)Je%f5mM_yR!Hr``@$@u]]]xb,ˡP(l6N,CCGEPy뭷p%Ar`0Ht2{vw2bY6L_$> HjV Z uVUکYͦk}}za;lSUuqq{TWWg<o]Vӎp3155u|,plˁ%v  _!;6O0Zb?~a;UTj4Vlmm$p?i[PSmN\.YTzB '%varS)YkjA"9'Jw:===g̅ [4p aAqIv(j4kkk8(RȲfn7~dYwސeMGvO =Zv+r-; dYVŇF~fxN___yٙX46t,˃nSTPh_oܸ^=wneee-ϿIl04tc}}ܺ}{{H@je75q\nСwroQ(p x܂F>^@[쩲 EQOv{) Z} Ac}}b$I^XX>=3jR4 ,.XTJ$eE&SMLLn޼1$㸒(j 7oIct2e2 {oe7"b&kg?;@T?6fN8 n/x//F]˩cGMOOP06%œ?jUh[!_++iJݽ;I `!bxlC phe%]*:4 +>AT쓂&'&O>fX$Nj2q\xap s:X48.;G#@ ݤAz=O\.@jѴm'&{)zLpⅫW>Ybe77/_W<gf^gc1 iDb=M-8'{{;a8]eqJE)D"f\.M<0y0N? bYYY$l.GD_yt:aDr!ټD?կbD|ff;~'?}[n}o/-/cfleelJL_ O =AaĠ3ͤ 'oe9P8Lf3f6q QX~RI ^X.RT*|&DX,U2열EŢ,\ 3%l:TfkumMeMӒm32=5ӽ)s[l6fLq-|{z?H[`<X^6 EMLLGk/Eaن(naLmJR*۪ =<ᅮ`;Ж/daa7x(@Q(j||e ?G}"hW(l#öZl6ח}|q}}33O;w,/z}KˇZ611922( I JTcG/,8N<J&tlf-ks8;;²O$b^_t!vh!\*?U#(v xj awwwT21 `&J9[1hu]Y__w:v;]4mua@ WxID$gcʊ(` "j[pLuPvO&|ӏGHA,K2;;o3Hķ oiS;񉉮NQ0c$A UJY5]oaNyKD )Hw|Fx, 3סmޞLfnGFitzxxxˇ=ĞTj XZZzd*&"l.H8][x0yumFѡ驩.Qڎ'xA0M]]Ppvn}f7G"+EY@6_sG 1H.˛С:w,EQp^wWeKwo~X䆆˕.۝LR${q˲L\Jdrm^g}²ӧGO>q܇?l^4MdVIdYUUY ZI AhƗXZǭU(k']IFS)yR(A,(lۿHBy}) |ר"Id+ (jfAۣG_)WbARɌapQoL5A$A4M a/<YáI3;;&nnQw@U|׮^kSȁX Ռ$mmUbյÃZ}O|bFygYVcGUU @㩕XjL&q, I4EQlmyLn~*طݘvAgffJ$MSSSv}nn0-&&'eYv:zOnU6M:/^/;w8>9 j;a(nAhp- p/g呠d/l#z>a3h]zR;ȫWBweKa|bEqj$0lE}>_6j{@r#^ 0-Qa,Vd9p/ųݿeP={maY6?əL7;7;w'Ůr_z8psG.ĺb0ہZ!Zrk}_FS'+ EҖη9z>ot^=wƍX^=wNQټ_*b!;sK$E>WEQ,n6kOwi,ba9,R>iUQm>1Iv5t&c->s 2 4X+$J5IbCkn~h97?{؃yAE"ppiٟ>&ƔYr|Ar1??//FյՇ)'}jadY2iy-{.^F:}jG!68n17kBd LLL<\ 6;7#:Lnkj0^&`Ѫx7&y|x /@5D"B@T5d%ȸFfgg";W~#/LR 67?t'[ ٙt]Uj' ܗ޾t=7>q-U=R7y.b۝iiHO֛gm d8F4 ת(z<шF7݊ޠhgg"A/Ow0h`Z=Iz<-BhF`kThhLT*/>l7laNCI 8vf @[&ۭͶv@ RC BTje˨d(ny@}mfM Y\X[XC}y#EQR\z k)!G޾ڑyض#Y"hGA {ENQ@t %f%CyEvH1v;u߿fkv?#fNƉc篿j9`/|mmm}io|W^ IRӴ7uA4M;򟮜>}ۆ8#T-wIv'y/{vb1I"h44}7qj9lxE1 3ё]SdRDЖ+ssss޾NI|73|%r_JgllO?3Lpxum E95= cIյ\.׾{{z|>XIG,..]ORd2XDh7z\)a2ӹfBMPR\S'OZM\_p:= 8ꫳs};&{/}˛#*e< _|bP|b.*W|y> I #b̄>dv[+&.߻:5M(r㲒DvÆ\vc5I̧:t:h⺴A-aҒ,+-..ʲJ72>>lZ, Fpܹ{WQU[25/mx~GK޼=5J=y>>::Z,)Zx[J:FF!B6M0~F\x ^  ;8o||ρD efS>j2\ V ,$!Iv̬j*fV<$U6Cd;;7?OQLfun~0KO::::55a׿L&5Lr&i4X,׿>s(t>D"gΜONNBuѕq!h4 ˜=h||w= l`6=bLc~a+ڡkqqI-q'f:[th,fiZ= I*MUz>??1X,r*J0\[[CQ4 ,Kt8sǕJ@ Ŗjn/Jf9U*h4!j5iiہ@`pppttn&ESkO- 9 kn?w twwkrdBO?%۾}-Ϗ;&5#Džafb(}7Lww E= ,ˎ(BQW^))r.`0 g94xfffM5:::>>.˲i,ˎB# u8t:M/8ҥKpq8@+W^}bQ7HA[VPUq:0f^ %6\Y]}etd2F`4Mo'@iND^xwy9%FVzG[]@__qm:!P澾??E:-_(}iƨ]< 9QhXdY:*1]{za)lYaͦjbbcN[EV,ˮ>~m߾}j^~]!(j2 xq9EUp@OKZ8>48 ^0 hcǎյ#CFv;v 3 E#QÒdRQ/^ ]8uvv2K$yX6vg3x1Zt<~ 4{].Wۜ[w΂  ccZ! jp _"Țj-ي3Ӱ7|L*{OL*|%Ȳ"7L&40 ^g@0PeV3r/kcׯZ/ρ?l9TWVsF7`S)bz/íߨVo97W!{V**} ~xqqu]_p4G?쬮(Bʕ+|A0ooA؀ѿKL`0h: L$$=sVQ]]mΪ|R?>_w(\*ࡠI7a'OdiaZ PV$vz?ɮ,1{6,]OľA,$)fˤ.]}ruo߉ v}x0يb&U)Xl{~H$j֧Aӹ].ż%bTZK*, p*!t…s΅E8̙3rK.A w}~8 zb٬ӿ~I`U4بjX{(i"6rrGrJ(Z.0(f4M?{_CD x#1_0F#\..(>(Q5uj~cfE9iD"zPH2 rYRZrc<A><kq3M]zqqDb'SjYJ^;s7W<1%, MӃgZw P'Hl$@da(f0$Ǝco=(RP(pk5F4zhbcW^FMSLTqރ=,޳ ĞձpGx_`I^/$g.\>~p.= _===uWKKBwIz(w}Z5Mhl6W{Ϗ X,A4lS[\\!TwAr9,~ܹr|3g@3j@%_|ŎI[(W5qBA*t0&9ZGERWOZ$E[:n{kol6[hBd|u5;vH~VeYT*8@@PK:)*`0xZ>~8| Nm<4$VVVdRAdf"X6r=rMI,#G34KX"f}+{D"!IcX r9Q8<<4zhP\V*b !DQT2dMNvJe"@-TE@M/ۙς<5G$ azbJPmNZs@J\BlpHRjY./j#ئlJj"PWWWR>Auh5th0 &J|`i^Y"kP*^__yN}gZj5hS-իT ˋs9bbΟ?ܹv=>Ly2OX 1 9opq[DGs|əmpuza8-x0 b \};{^ dVxj*C}TKuSffhpjv| % 띻{W*V r:әJf9Rz!yo0$14<Xs Be =K2(}Tdw+Y@֑$QX34)U*Ѕ L&`bP_ [,><< Vt: @{qqT*E"W;?55J=pEB_$$pJGC ut\BzNtoA{zzIPE1:$IRzA(J%IPJuF H,Vt x^$M&EQ` N'xL$A'fs:zBOlvvv3T*LڝN\KL6L&Z (Zx^EQpwY,JE"&I6__{wppP0f3)Njٳ74NsGb U!֘.ޅ:8Ȑ9A#u .01%^\\|w@4 ZR .a ._<99i6AC?F d$t:Az. 8~Ѩ/0p{jb5(z>_xNϿڱח y睕Jj2ȇfFSTm|܊s'hC>3|zXT*5M']s>DU6ϒ/,  4t93 )##>V($w>ˍFÕObj8V.0KK/OMP:s///?~?)0q`E!%d  ;s  aϒ%u0\A^\DAcqǽ|o?hJ|utA8ud4 D2AO> `1۽Pvd8`Dvt~Og#zUAÉ=N0 C  shq#P?dxfpg¥B0LX`[O۳'{bccB>  A$SZZ s_~vc!!wyʕ+kfsu:Z`qqll^lw}('H~@^a7V-M)B@j` CT*599ylǁ*zbPGzbPnZW>ViQ0#>VqQryZM&Vkb"ĺyyبjg._=1Mj _pOo)āKq['6?HiBh4-?b;@MHiSSS@" H&тeNm+po(=fff$R)xx336q^6k 2l hT+GF|Ib]ߺuKPLߞVNc+xdy^R|>^VJ%A\.V;66 hy*V徾jjZ]..AZm_B199p\p̓&}ǙfL`8* Rb>77^}iy ܶh,f676:f4#C ͘-cVKwgV4JNr Ml6ezSڻx/!EQp?VOR 1OWWW(r:ZeYl2 .gyo$Bp{6Ž+Ȼ R)<gl&r i„3,..Bl-{wtr[J58tNw2tSSFYCb]m\C{Sƹ\ JʰB{r=giur:>qx,T*Z4܎ Gc1Je1?TG}"{ J.?>bvk4Z[.ymU "JJՑp '''Ng$YZZj6w1Lp $a~dP}]uY8 CٟqS٭#L*DRVdݽAbIR:!Ad2_cc<_\ZZRTʳYkp;,zٳg!yS:ta[tI)FPl6A | n?3T̙3Foej!TqSCOlzw?|}rwԦf;RjcH=_244dۙpA.w-Wfsxׇ5PC֑ ,/ pjFf֚("Ԓd2Yvy!`b DT(l>o-<,\.WTDcY*1 @ӴZVTfCݽlZ (be#0I@]sіhV;w^L(R z/_ {g`@#'tZU<{%1uYq:OI{I0˲LdYݞJ%#˲z^V E_za @z>vfV*:yg p8*B")NgZ7bxRԳc u o5q? S D"i6`<-bb!4Y_COahfJ:OJ[ MӵjFI&&x BLM}h4 ѐH$!9CM9@yQd}F|!144"c2:`0401DT*;vkz.:"PK!8!帯*_Vu}lu{Y-!I0* Ў)n{ĠRezz$&''qo8N0` VlF" 8cP~‚SC+% MUjTX\!Z +z=֢VNEF apF.xH$x$Y-=9봺X4F3;sY.h4LFcl#д(k B(NS'ERwc-KKK4MT $C :I@08 D~X sgA/}Оï'Nwpr$n4MdрIȦ'G P^8 W<}2h  Xa7_y{\$H$jd.;Sl3JrTJePyfc&B/Xj\HJeXT+++4MPHcFy(U*h5[kH%(֪5<R ? z BvWeB"1LH$C;/xu,{[8⋷god$@6Y6xybMl\U""C IDATDP ovNGtX 0 0U l ̰1ĞI\xq9QjU$S՘*PoOOJ"ZwlwZ0VJ%EZfZ,B!Rʥ2'B߯Rp 7MN.ښBj]\Z}B!j6z{jUNsyS(pUB`0\J"I~BѲ*rCBUQ{!Zw,#!u旻= W/WJ 4˕r""_~.)`_Zo_̉ җ@ꕸ ellU x^8\.=9VTr3 ߣKP(忆bfjVQ0k6 nU*qȚ8%+Je^D fYA_*/W,qX522"8r^eYlNR:bYZ^(lv<| |8VP(tZ9%r9vUhh4A}JH@j*~?x>Y^pM^) CA}nn+wu ^}Ɔ隙iZY{~bbqDRRl6,D嗧ޝgr?zFF|{7PLRf)L|^ $T*l>wpp\)G"ѵ5_`[X8{^yN믧bx8ZfJnn248NV˿ eWWWO~1 =lYj'ד$赲,k6YEjm6(x;?$q=t~&IEDBQNӁM^$I]AU:E\=hnjP;y t7o̦xE Q8X,(e!"ϳ杹9e%Ri^gYh _T*J~n~e{:R` Av$U6V%1>G;syN`V3|y$zb%;fZې b,,TBfc_-U V%Bb1:JS6[F^v82K F3JMNmgDz}R ɰNs\f"I_h^Ng0"ĉZMڵ;B\PU.ۗm?zt4ՕVk7M3#>_>O c[-v9uz|)~~KO<N?_ rd,Jܮh4|*ZǏ f JZ\\L 5M4CzU*/HbVUR?pΝga^\.fznhxW BG, H$&IQ!R&S(𠷷leF: eDlHh4 XÂEq!H$,(JT*Hr\T8Pa}YB"iG:R"EW-\d٬ CeErx-HJL&CRh4rς-_zth= /5Z vO?oydQp ǴKxF{|06yb;"1}ybT \Β8%Ӡ ^ @0Q)CX(b?4]Mq VAF[ JUZɤR "#tJc$)S*U@`tʪ b`5Qlod=zfA~666zv#"ۋAiZ4~/EQjtjWR%V1t <`}HIt$IpAo D[M w.nGFF!$T*1JN]Ap;"ȕJ7߼wfiNz{o\Jj8lY3!2X_ ߞYRTQs\#4Mqy(9yY|` &_Ҏ A"bjz ,.˵Ҩ70ګܻUjuVKEJg_j^ZZX,l*Bl6UX,.p'XH c7*ˠ]}oY]]veݼvyǽG<6Ʒ B.(; 0, T[4xv8x1;/! %"2 Ƿ4MpB ]pk뛉DT:⋩T* kW>$ɾ>e=~ˡV H4FCQRh4`-)jZPb1j5); 4MlT*nn2^94"JO8Q* JN؀RGomkg@O8[,l4Jt yR[_/nܤi^7|0>~a6n d2qX;44400Jed&y85D2ɜk68a8k+|d۷o*`P^f@i1fL&!DiGEᣆ`VAT*FZvwqL&CM9t6,EQPPlZ-~8{zRTGRl6:bfM%yh4$Ux\.:˅BB*7sHRffd[ Nw-HL&HpUp:5r:V43Im& 8~<β}}}AR ݝy( FT" ^..F)|!d2j& T(JX,Fۛ4O?P(Z-T.јFbzl@swlÇ-,pd{Oϡ_P0VXQd2jíVT*X\Ľ<o;ӅFT*A-V$/8;;h4*ʙ3gHL&SJ"?zklQ@<,}jj $,s ܟj c#BY3/EQTrzuup#V>V PE FhRLҲP"jY̖|>_k%gYT1նʌ $/Dc1 x#fW\>wcbȊ~kyd*u _gqvbAÑ(;fewĵۊn~%$ەpj_^cY8,0 tj5UM%;P@3Bh-$T*BOQZj}W 6LgΜiLp;<L.E١Uqwxnzb]]]R;|(^O`PT<ϫTCffS. !r(@ t'v;ԍ|yf2_~$!sWZT(J[ZmRN~L:aE*ԪjjFie7660pRҙt</ @6+W77Y ݻw h( e|ET|!_(AfbYX,*ʪ /.-B!ݞH&bRq\ZZ"B, fpS"ʥh$D"qF Z$V*n_][?0ϿbECދ⟽#_:0z[`b ٳg>|p'T~ `|+qK:E1'8߂^WP={>]pٳzMOOONN_ծ={6\|Bpȃ019ʹZhP$ %(}nwRDFfI"֖;Z@)Ji= <LNNBTá(]@?66@I.8;0< ŀGFz>mz>80X\4>Z_AuQ˗Ϝ9sE1(t (YJ%377ZO.iS&''!gR&dDŽⳭ r8x:2?d~=KKXuBv`*߱ZDt\`Bp  0x[d2R)Cxw:ch`v*@ޠ" X3,l6;8ㅞ"͎ZGrB2 `YVQ$Ul==os.ч6EV iwy4zl6: jYA)2*JVҋ3pϰ`LH_;PiܾHA~OX,x~vv_ݮd"6r\Յ[&)#^YmW^wMRZ&'B 0Krd4ݹs'Lktk ^{Ѱvw+F ?v׿sj-jzzzbw;i6?C, `ϟ?{K^/8WpNNN|˅ Μ9~mPKxBŋ@QC[=4`IŢ『(?_O4#Ezb_Aآxgn4 !BG5TBQrQ鴺L60a l6뿜?h"WabeTIg2P0fݻhd4ߛw:\Pf|>~ -Rg3U`:}*"}@ @gh+Y `X bn6O)th%ò{K"IF=d{;1M)h5 8v5R7@ AᦇzR{];<< 1``oMQ$QIDAT:yU0B7#.wvxzbcchøu#p|>8.zb0qfСV;sK W_ylC!L_{w74̏=zS'/_wf`^b Ғ\.Jj:b] WW:^㏯\N dk|~3c \._p!dŋA @ /_ a:^~~T*\|-P7 1ş(:XY. M5[:IgbBWGO׭1 #C䏟(h@7۾n^(OvZ$btla>իW!}A:rw x/=1՚L&{lZOLbS*U( àV+8R d2X/er $Img6j5QEJl6|>իFqxhl=}Vu|?ZSy&#!N]BviIt:堞Q#|SwX&jUHR]z^#]]]Bӧm0e"|>ovryXj6AѴKcOVm8{]][bW_IeHz]վ Cmvq0#wI.v=_RFpOOZP"rAju>N4j@**&{A@hL)P08N*Uh,j23lN&,>æ\t\._|ϟ?&={4F #:7{gfB(`F`T;[T  Àuww'I$ !.HL0 Cd"Ri:bFL&c4ժ |Rɲj: Be\.qY<[ XN:eΜ9s%V'&&rzbo{kuugfBɓ׮L&n TXv&F&:y"ge2ٙI06uyewuYܙT,IR.޹3gZYv@y r9v[6)JKM  zGoo0*JKKZ(kY7<ʽ{<lV&xmBU`77 z}61 ۲###+nf`l6qzcY.Ǒ22,"<@ Dx_^^M0y0HCL $Lt|…_Tfhh0̈́;&-mI4o$% X y)xz\`^ӧ_\^^RqP1ML&۲>bMlV»HEzJk}= Q{\-fsٴd48;[v~p.\@bVGo@p 4@ ˥2E i MS$sjZQ$jZ6jJV34v9ljnju]-U޹Q%v\6ˏUʷ/ zW k0ڗdnw֡j=!RVÇ :>o$BH.Wա1-oov0W.63lu $s"7TTu,;bjV H4ڱT;* eLFE*tFJ,ێSo_6Nu8 JZڱ,\Z0XVJ"Ir|p bH؛L .?p$+}&XɑHZ htjr_tj4p2T*;bzߓ'OȤ2`R ZБbehBER$t:#FwIۺL_|j-[V֔JER-N`VP^),U{Aj |Kr$\,^ H$H4jƎk\J$Z0x}4ёbj5 UUT 24H7$Ir'!$0߾lI$RceWP, :n-i+J/fA(}?&ID6,qbHc500.(w:zg&m8%{qK8.JX~{3hV.8ҥK}3`< |sݑ@js[OvDkXkܹx֎?vΜT*e!^;UAn`P0TլVV-0]r{,+uDfYyhhe^BAۯHƏm @zbnc|&RB _:ΩSyXy C7/<]|74-_[ JROGFFͦNYCS#e777n7B밬D"a>[R'S)p8ޱZNmn&:ڎe"jժz -T*UT޾l0Y8㲳J@ںXsP5jzbo @ *FPD(W^zHj0Pcv'OO#œv b.8/ 9{,&z|P<ػ#^ܖĠ3D*/w\wqّen7SrRfT*תUۗmK}١AqFceB%{^T.wuuA-T*\.r: BYӾ>!LV%Q((jZPF&'''EQ4kkkPT*/..ieY[[裏f44@w+||ryuu>ߌkُ\9ܼyd6(AyzJT.q\.AJ1{<|GRFRiQI\W\NFo_Pi7bV#$p/{T:-Ž ammSjl>Uh۲2t}}=ͦR\.|' tIME 7[IENDB`gxemul-0.6.1/doc/20041129-redhat_mips.png000644 001750 001750 00000054373 13402411501 017712 0ustar00debugdebug000000 000000 PNG  IHDR ~pigAMA a7PLTE ^"""% & &&&***. ...2"2226&666:::=*>>>BBBF/FFFJ6JJJNNNP6R>"RRRUUVBVB"VVVYQBZZZ[<^F^VB^VL^^^bFbN dR4ebYeeefN ffhEjV:jjjmj_nnnpdNtQtttvb.yWy\zfF{{{|P|pXSb.V\Vn2fn.zHjcr y}|5 t'B#۴0@h,0x &iAG-}Qe5OaZ>$0`45:`hB:p0:x Eu玻(Y玹&zgwHv%u$C>kx<$M&'-GNgvf;zt|w^6MAa2 6yҘ\X0xĀRx; wFtAhXLg$-M>d-`Ҿc#QovB> dWbr5LszdԦ9TXwNZFot`2sߝR.)l y]7@hv& }'_/3,x|?݇N|)Yr|qzGTc Kur0X*K!`Z4 S,ۀ``,SxH{(syw !t QiG0;wܹ-x`p@e{{k{u /:M 6ݹ  /> YG;.un_i8aX0㻇ؾ;qv|`zO|o}n"BcO,z]8Ko~Qf ^'wݼ~  ۛ~ro>}`p*0@h0 įl|g~ 4^Ƕͷ_?nZ+ ĭs߾o]8B7>_À) n/ν?W|{3>w ?|uef!^0?'+yy{csZnKɯw{W^7?}ec o_y˯/Ϟlo~ӻ7c 60ܹ􉽭_}wzW7ml\J ߸/>~㩧|W?z'U8πBˏl\>WGt뤆mr$#0ܹx%򃏾졾CηG}w vʈBޕv66q ѻ;4x4@h0ܽ˧o_‰Шa?:n?:~w?9 3 ^;G?߿ѻ׿׿3tn _֡MpvYןܾtv!O@h0<%a*) >" ]08~E8^$"BayaQ0!<}`apdl.ƒA3q4yB;6_- ;E ;k9 0xЁx kx% o>`p4kgGh0ܹtcccE7hhq A/a>n & 4N^9ƹ+ ?`g79smqj+!46lnm^c֤gN'箞2oe0~(㩨v/7~_{cz>q 40O`WKW>FOtr|g yשЈ`}҃[{!YCh4>| L?r,[W6_+~?"B}MoøOq/_ou,F͝Kṷ?kMXa?{7 4^?ߺT_y<l;s1  ߺMA<ןs^?Nxx88vx޽w^ݺ| 4n~xw޻wJyOmm/G^{~-X8`_o /os{I{}~vpx`s'>מz|^x卷/<2?aywU<=wҵO?O}gǮnoi ?ӟ_oXapb _~>7Kйps7.F #a{˗.Q.KW\>C 흝ms*vwB#B AO~JG:0{aOӿi" +4sںc>w3&T fk@I5 M@AŬoA M0Emql\I#,*I>GsH} V/$X?Ƭ1%(!4e⢇PAf"O#- RHA|QӨ|w5d[ M9 ?5z9v230с,Z(&`B gPޢ#k,N:8r 4X7! B  B BѺ2c=eOӒyt~ z\!6@,af{"QoD "KԄ4¢A6އt_-lr 0+ @n 6Ҏ%/lC< ϊ0p6" 3+մoԁZXoGnMA`f =~"$Oofs 2KZhR^o,ܡ<hy,0(%?02,`PG}"4_dfx @lZ@0݁h 2@&Ba 0 5Aa081!fnIG5`!͚lIGAwLNL:BB B 0@AyLcֵcSV4u+#}7'@ f6Y?~VduO0 RM5 `i=` ` T`ȠfJĚiXz,ѠVӫTؒkPʙ<) `00a`>bՅAӍTVXnI4,545 N&,śtEīt OX@m`8rixobyhIu`0s)Z?:jN?b*OA 0ȞS'sI 3([ >3/=` zAT! ^t!{k9tkﻻ+ 2 `Pd!0L28 !`5d)} QB7^w ael2Yݲ~rqy\mҡC U6,QVͲkojv1z:B4àm`vi0h5'Yu<{`ً'V=W9p5P==؍0W9BS}a_P lA0  %J:6ޝC ^Rvh?NUVb bM/2K? 9Gs_pz@&//:$t\,vydMD͍U T񖶼 = KōyxfW޴ <0mz4 Xz 6ϣ:< LZ D}l}|^y" "}j.>Bx;ru} |a % &yD+?r7'{~BhB/u[ԤԺ_h.0X06um B! B! BKܡvj"')Z#!Qx#򈕓;5ѹ^ȉ3 YaХXʌ0G3T$D'~-Jb3by%BCZk)ʗ@ghH- fYd%5 1m71(`^#?/Ap ߽B oH7/n\WT3)}r*Awܟ мam({L󽒗 _.v>u,oSg!+@0 b>a-0g`'U@((7]d~9'">nFJq?pˠw 0@;0ҁI=]1Xl.  zW<2ha%0Vb E頁Z.4S1V^gcP2Y0 2[` B: D~6%egF_?s<>O|=9I30F y]<,2gn! `BD-" B D-'Ř?yE[et[Zzkux<.?T~Sk:"0e}NjF 2֛{x& 0p03 r`0RL#f }~"- (>Ԡz; x:ݡLb-0`!`0;EPeVֳ[޾wDYC \qmvP b5Z+ wx)W` f;J3'}!{Cif$1h`2Jn%-q~֬k/&D'8֌Je"h` "jjӬEP1)*7j8&\X55xc&yRv afꪑyd z`IDpHKG)fD}4zQ0)O>ͳٜ% AhP22/pZ( *V\4o vB! B+ t. ; Cјq\:lu@QN1*M d|?,%Ve&EuwZ I lO}]AVTJaU4T.g1 Nߢ2 <f`7Uͳ B B2#1Dɒu @5kOb=V|dzUu2rK#04zQ t|^2 (*U)~]1`9{Y00 a0֯\ LDX0Vn3AuAlA)30tuAZDtg0z ~,a/>Q$[1*к€ہ0`!` |5uk 7.RoYd%3>A6LsAm *`bEyBe!5@;~[])/$ZNhx]xʨ ]IrBtdP:  ]/1Ϫ+PHRRER*GtI0+*tkU[~"i Fٷ6p"X[Pל hCJ! W%e}ٟм`001D;0Pՙk%_k4@_qlQpq0”/nwFP0HaqF^5VsǨ ch^#ί? D 9'[W[W=AnE~XUwP;:Ci{=Lh:3`px7h 0 L0 qh !`Ն$_fNW{cuo唼y [ƐA7$BB`p`0\h߶CǧTyVK[IZf}&mɩ{hVGc)yq0ڊg *F!yBpoiӛF,>;ن ffDO̧!| Nm%.g_KȻ0bb;0@ggϯ5π;`7ҼF(g0B z6F~t-Ju'0A(83X:0I)L0*18 @/p Й`<v Jlr.ؑ00]]``D4GDבa0{/|a` *ag47ÊE̚gg'@՛ IDAT 滕//oAqf0.yl0^~^0lhv Or{̼߳y*;`YU/]ȱFQxѬʉ!`@Ab6" B! Bs.a5,^@-jo4RN;n/pDdwA%uТ='ZQ<ax+E,`N h9`` ̭755pj+Bs$@^f O}lbǟN\2 WA=?{u~4>9َ? ƇbneZ!vؠě_JִP`E kТ`7Wt200^DU0حBAAP=:<Ī RVd4@Xyy79zό$*@+bA"[z&(6]_r;"BKxO8X|sD/&{o 2[ !ODh1g:WUnwAAp. |0@b}ΜB+0C@Lcۨvcag&R< -/ VkD{*tXa`0 | r( Z2%I^i@:}NaX0 daA7# ߁`AFaqVȁ8 | |+Luk]# D- |u%^,_^r3A~![?D"Ve]ӨSyBS6g3*BKgX6DcA,98!`AVx5킦uPo{}zi'Oy,AKasYUy6wmB_5.^Cb]7 AH'lnAwmJ!i1QF؎! q:FVe&;?R;%y|љ0C- ^ϱ]\0b دQ͐p!} j6 'kz0p47- 7w0СfA>=``}s A;{=}E`Zw;u~G`Cyԁ/ yLG\=9O< Zb"Nk>AOah.X0^ Bh- !`y@ {0Y(B1> 00&GدY9 yʃЯf{Z^XaXXcg_ٴh0(DުnD|*G ےd2pySyB1UA)WPGv^ ;P.[ h,U|pjZ7A<y0@c4hAֆ 뿃eY*]ao%{AG'4x&ppJ Ah=aN|%Dgp3 8̠4$UAPW`P) ~4oH[KJ$J000@7 a`8ˮ9 0 3^7!t B}@=/E+ah{Po~ ؟'sKPb̆ rCănҶ +Bge6aBgi, nB Bh0X`>> s'ͧ:e|=6IF=}X (A=16h`|2/$37S `Q IioRڂ Z7` #|d*=,og oVj-aoJ&3iF 1Al~0p<7@@>grU}7Fhm`|^^qƽ'B~ F`eO*ǰyZ+2׆A7! B!4r<~ygÆhPXYj  BLaLV3T:9 &݅v7dVhT0| 21IN nQ `012Xa0ݱ 0I YlZ 5` ``$  !6 o!-bnBtzs'Fc!ZP&<{3ࡶX 6!`!`!`0BߧӉ]$uo@}zY!42ˠsZc4; ~7VAxP0X~ZS*)57?t&e<~w\?K'`V,L-2Bnk? b JtuXu`[04!U:ޅze|S*Œt}ڔ3 {2:e86&`3X  J}tPtk4=I˟k%@0˝FhBa0R %^}sŊ~M>OS߂33B P7 !` (D!`!`:c4MgGm?ۡuA-. 1)g~S0N3 b# |Hc4( y#>?e90I[.T@b`Fl0pX ]c#`hn^K*kr><)vO rx,k 00 tc. /|$'p 1 2 0HLa.ȸn O-4jC˸ݞ0 jŞ>|90h0IU/dM6~ь ݤt:`w< Jf7 ghV!`) *)~Jckf.y?ZD`Vꉭz*Qb;W[L:B. NڻHy==AHgE0ONls`T+i Ϳc JȁE(Wcd+9X872d^ 0FՄm0 r" 1Mʒ0@sATa 2A?]8{%9N7A' Eg0̡y@Z> |*}0O@8uӾyV5HjNWa L:Ba0fNoH% ZǁLU!`Z Bqؼ#gG6khy_l+rfAv~[=,ij-%< 㕽˕5~y;\f46 l 0 6u?u}+ ՟ws#N#@~~jc]`٤``~)ɜli"'^|yeÆգ D3N%kL0f7M~Y{ w|`CyS~``]}Kp0('fw>XxkfҔ>/ }࠼t6L" |by3 ,`P1O}; sIG`S3o[gZ_gk2Ay7"o1a/}ԨR7Z>uF>ߠYhqC暔}pV/߾N//FO9&y.r~Uw+? n G/q<"ST5L ?sgT-*C.:뜓To B VP1A(#v'b4:Vtth0=O/Tȃ?rLEw<x8C)2«HW+?su sbXB#KcRMCLbD48sc[g J#='lQi)Ǣo9&J%_(zh)a``.; 8=[3 K nZRaнPt v SДǏ-7 챮})Nܸ>+W| OM4kb(}`h-o7Vib8d"܁f?o6E קs,Q$3-`wBh`PZ+!`!`Z8wT>Jw$bhuA;֟a,L:B ̷d y˳ P{FvsWib^'8!f:WY 3wswnXdў!HZF i² y74ePhtF^I7¬+`2'80H Ҁ14 Dz.0],4 <Iz܆Y?#D/BIG .ēи`2h.lc|%!` \?c~j΃XgA/Q4d/?%ޖχ;aL&0لe`zva7'֕ JYnJL{4*Gh4_i!Ex0#= ]hU6,Ry- BjC,%u`<1:M~>0*x0p,h?ifD`3 Mn[u|s׷Cф +Ti#T A HD0D B +z Ns*D';M գ#vֺNѪznߴBc7^2d3if ߬-gZyʓYZ.sZVj}ĮT:~o.g| ! Eàaظ;wcS#g`Ĩ m {i1V:@ Gpdц!>ZM378C_2Ieˆܹ*4[sv|?RtZwA^n/}o bVZ_Wtjϗ̛U;Yb~Iv++<6 P_$z=I%/Y=LO7Lv%͒IDATh93** Gy0KI-ժ Ak%umDM02TPbZQFAVMFY1]J=twM i`=n'a&PSJYU󚅧S5!UĉaݷU ݄`0a(s Nλ AWw7VVwZl@V y5㕁DB0h&֊}|ywh"s0@FBāsoy Fëb_g-w^5R^-hPW`U:B`v: Z`ezEhu !`#=@+ FnzUEu:iK2pj>vh4^* e=8ʪRXωeYzul<-AU(H󺍓`sf>Y5ͼeބ Uy3` P4"Z~o ATB8VStK s&AY^`@?ӼCGy*L`5Jef90mhA(n`j(t߱`b?h9ֻi C" BaPr 1< qpSwo^M;&>fmݺcv30~o[6JSQp zY5f_W{jYw #1$[jY?e0j>n`YFduV^ *8`0X/A3',Ur\Y0w#j! B! ַ7X /?sZx7 NᴱS # d["`F5v 00h0x8iM<,` Xa  `0x`P"0@#餣IGFL:!` B! B! B-0HR_nU w| @n}Z>so̶/6 ջ fqda7! B! q̡~ӾhuaL€`0h=af0X  p;80u0@0@0@Ѐ0hO !xueYnJH dCQ6]Nwj-ڵk3f%%yfd;Pzc{ZS@0 B<-9 d 1Nu!;Np h0Ч +0 <@Da [aA/|(|<ԋ)L3HIc!u'g}n =gC- ҁ ZfIV!`% Ř'>{Bbhu at^00XIIGx0@SskQLsX3zx%8S$ eO96c VSCvh% aFeb؄$ ;:aib 4(Ȼ F8֓KI7- 0~TA9"gg-Y4p |1>~z\`0`f i\'q90@hA5魆1Ј !`QlUsZxq9Bgm# @? B\@   ;Li>r>,?A41  >^6< `Pgӓ[B+8b=074@ $/fYs bjo9o@ҵ)|;\, M A064`B``$0003\7t Jo C)A(> FnE8:Ϋio!GxyZ{`tcq>`-$ D"B B=Ϯa}¦Dt Щm٨>ƣ:} 6Àg݄uǞy < 1:A\2D}|vPx HuZcD@`ZA[8J#=60ȷO1 0vt?r:uhFo,|u;с2L8W3L7`0p yo@D@'YYo te0Au&|HyZdA+vW MIG`wΠ/0в`p=0@hE-HRV!`5 `2r;{lN"dxN[iw61uBғA^.0@`_Pk¬?]#H'Ja@r#Wb1 ~,m>@N*\u Nk_ӽ{;, 欙wuFY jVz~P0{``2 bqLH#\:qJ {um~^_Eכ{"?ӋJ3P!2luWl4#Ow޸5'uqP.U>wU9dz<K0Xt7aEO# y$ JAA(?`Q9~W42T%F<^+0XfU:^,W/2лue0 3- fg=qSLgy, Īav>szgg`| + 4IGb{y铙wGuw{>]s9~~?:gv?v5 D>nD `kϠ}2ј !`uO9Bxso:Àxs 7Gb0FoxsB0@0@0X??<ႇˏ,<|h'mp)B-0@AAx@4Z<& f0h0xXC` ZYfez ݄ 0Xw<ā 0xghtQ餣d#&`0!`!`$ԜE ΪlH| ̡~Ӿ? C5 d?. BA>3g9u&aZHnRL|yRYij]Ƭt{oM 7M~N*SmP8,- 67vM X&CiRENY1?8A3cy}a҉7tka?N6 @-Ta0F$BMM@g˜ma: p "i#O[l]}0Ƴ \ ɤqx iÔ~l \&lH?~2; t }jIeAɹ?K#6% k2jeƼWZnB Bh0(A{?8%|C# gY`L&aٛ xVS7abΘ X|3X TBsgbh Sg|gB$ Etf0$9aHYj|3 e@0@,3Yh݄D5%u>TL:B}{{P"0s|e0/k|^7! B!4N Ϡ/B -0,A/dA`>P&LYȼr$"Zގgr0 P -M " q-8[Œ@*IY"7SZ a6 T$ qI! 9":|a@`M(A!@t`0`3ӷOB  ZC%tB! B@ ]h`bhu` OL*:3IGhfygw&, h`%&<Jhn rh#,Q BLC ,l} `lbht h)`0d>Y# x8љ3(W `M(A0D |hp0u Z%1,@h,5uB! B#O syoa/<#sq0[Nv ~ ,L:B0= ,Vm<@(xyE%&!bPbWǑG m?RI"e Q*\7-͞>:ivl[y, 7BŒz@g$Vd^hO 0 l䟫 0@@@Y>4|ڳlXa@7 t|0>JKM30 aT $`9FZe'Arx@dU:(F!ܨ,_,'VL:BuQiFgC\dcwt9Z6vjQ!BB! B! B! B! B! B! B! B!4W X >e-C} k`(YPc!42M  ?iputIME  :}IENDB`gxemul-0.6.1/doc/machines/000755 001750 001750 00000000000 13402411501 015560 5ustar00debugdebug000000 000000 gxemul-0.6.1/doc/20060812-netbsd-cobalt-3.0.1.png000644 001750 001750 00000035546 13402411501 020572 0ustar00debugdebug000000 000000 PNG  IHDR2gAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxK쪮93f94 7VVFnJ%XkDNۀHI}a^4?Z7`fiBob48-Bn@w_wAbKLʄzߌ3E1021W_g3=j~~B!=koU= Ȭ 3UYQ~~_ݴȜ+1&3?wOZ7~Xf3sJu𛉊c<#? .),/!1߈1G6:oy_qϿ! @_nȋcG@d+2"oj\2$+Łu8z,Sa!@d4l?EDnO<.iQ$*A"I-I*#D>!G!hmoJ 㶈I-m VihWnbMch˰0#2Y 2 "သNx[&/!1c>DJPm=iZmګ6o[*!b KEoSPM6O]FC流VI1 2@ǖExGX [Fzס[[HgJ?F]+Z+J(C\`ȥV7vk8 2g+S#%8זTKEF"㢇~i24Կy5z# %TA tC3U={sm[^4xof8?KU7/ (% խx/Y]ɵ:LAơGs7WkޮnYj)-{QsF:QlM+z.>QSѸڵx?V9-kXșt.] ]W,~oLa<]fdU֢%=ܵ\KXcyx8-V%v-gI]#BuR*bxx1 IYf]-\Yq ƥ]V}ﭸ("c2O~ͷ*XT?Z38i`&z!zFE]e|52R8[}![* i " #(f 2k ݪW$ںhQ#xjy[x=9ߧ긾'헜4LSIsDK ? Dx^2|mWbn֜C?el!Mʼn4 [)~!ZgW\D8"2o?}0u<ϒvٖWM,v&V z;D_w}۪%&7Z mZ|߬*5hzK[}ͨTCqqQd/ՄypF =?ۏ]{G=3P[#:/x\K[.[ʅ#Xey` m!2hr$".(f 2\=KmIzb̳iȤ+\q|U*KW(d&"#3X>1k\nVx j&7qL<3oA#y=~x3ZǖQT|V{6{|ړȬ9};jm9\~V{=/=*fv0?hb4OepNV{@n+(fD3 W<@d&e3"qlغXVy5BT~Yjm7udZ4yjkmFZ_fj',} -*eLeQLpZ$&ij!e)Hh ;gĭ7Z,yiل4|:h2Zy3/iqH~ õXJ5k JLypIgAܺ؉ Ys]O5Wϒ6T2?,_L'Nծ;ZA f}I9aMD+qm4|ҧt`%qG䐡^6"547dGr#Ȥަy/-ϫcɿjƓ#5XHY1 L"\?#x4&nZVјX) H ^5M#:e͸Fh!\w˅Ss|l H=4x#]\ݱbhlkUQowuj)eud߇U6ݞ ZJЛ9N˔Ȭv>S3:+hɻL2|+fD;^`CfGY=u~4-;DfL;0˾ܚ<7TVXk$k[~fNT-f;BP77m>5ߛկ;+>kIXM["iyI Qgo>ni6 ֹ!$24ҋo&<Ъe扲nVkM.-~9ߎ6ڸE}_-wrD1ۼxKvȾy?o˘1 x[sdYٲoF`e-kdV_RbqZDf[r!'lbXOei[1#Y]2?>~Zv +v,!zcܴǺU {dmOӬ|։Έno|jw_wO͡<_/Qgo>_`B"C#qujh2ZD`fѾI!ŎuP49Κx Gh9g`xow oԋݫeG#Yl5.|܇C~Eߌ6|e-k+t`5(0C%H/Gh)t߇Qvqlf^ 򙏏ݭi{Zx9 pb 2Tb@d8?Ȝ'*f YWdN7jI}-|ZaȜ[TZ͆: b\g"le/x?4sIZMm| f落TVL L(fDkV 5gڰNI˚eNzdw"7"6$h'~ǭ% b&h^ߒnJ(Nwl[eNuɞ%\ʨ;%(NSm蒱Zv2kGC\d[QMIt.W2*nz/BhFxD8fW5' !Xe ?yCw˅SFj5z Խ&$`ڹfT ]ҮYBmGCЛwW/2hWSb'2!wd`DN 7 lޗRDUaIKB aˈo$o&/uv׌ @uwZ%o ߶ǒ6 TLSXOb0@d9?@ddV3""""""@d@d@d@d@d@d eJH㔥YG1uJh|ԩPkClyݔYuh Gi3i5P̲A"h+/2%tz7ӢF%t@fXd&޽HV!3f'r_3j0d,,3_lSx[ nKc6BlkdȊ=a-q/"o6} K(VMSWS$֋c,ȶ'Ŭ1`{KUXBEji |qh'Jy-ۯP64Y k>"`b:65I[L"iꅍNs}䩑<*yj˼P5ԱTD 3[f@Qm\+vY\Ss\ 7W8u[9IHZs;"LG2blcS~sU֢-k%T5FHKEƩAdT~PäH&iو=VΤThii`nXb 17AZU""""""@d@d@d@d$A*C/*fK`Lmxeq>L1pOS.1ay9 ʧy-+za.8)1m,ŢH 2c G24Y1F3G2E2VK+ {mi*օ+_D`+fMse QAX@19|к+uX{`ɑIhʾ{%[5s54h2NZgZ%fvk[qnxIrNH> 9ˀgG8WBda:1Z\qZML y7] ˊ9x- 96Ͼ `?[d8֩ng/|X\0+iL3 kYRۿS(:"[DGېX)fjU@=`ΑȌ;ybYb,\$2WuY3ܦԏR f5o-j|L۔u';X+_ɤU=\b'4t,8lg&fl>Ru/dj9y΃m'm>#xkx{?g&EXeT;;eTaa+P+Z[ˉQ -gHնBY.S+Bd(V+T@5Q ~&Q MV&w푨ngA,Dm;v-okހ+D2a  ~>`iJ+{> ߥ)+=uv{et|'N*{C Dl.]e.rol)v oS6<]_~ٰ7o /]mX}-;{~]Y_6;-nݲY͇ۓNًmpLTév|I?0:}+_֧5+{_X{>'m c^>=?XV,? +"e*;xh*;@B=^Q'[5:ൄA%}֡'Z]Ͳ\FUVϳԟW]W'ќƏT1{%9=etWUKLd3Ս\/d1Zwxe%*+rnԈC=CdWGSzDzS{594˅"cl=:Mᦏ{1lZǤlsvGZF˸vOe5C A*]!aD,?`kvG ='*ۋH+=ߑE|_QyޫgjTMi"dz%4/{~ٲyJJ{'<,e_s rV_G 2~'UޛN'IDAT '23k1Vi}e6l}y6@dt<wSyzhȣ0l`LhBQ6 _0YOwc>@IF…2/Y,s2:Ҷn^9t13椄49Sr:Ejfm,4vDQ0vHZB5LKHbw62 s[{kYXv\^.(ܝ,QKH`XLL'(NbÇ'N:v^iP"( v-%k c2lo/N';'sViƈwDSMӋiC7,oy}ÖCWHeX vP7A;6]Ki| ĉ4kf#ʜ99&wN`\b~vޘEL_>9Z|( [f/ynX<D& oč_QFhZ뛄 Q:,kE UlΖU7ZWe.@{vzF\vu;Qvet\1;U丞eZ e_Zd[(S '(%ԃ+DF}a q{fa L|.7Fˆ4w{n˘9X>`0}}?z^Qvԁ=uӾKx>zu]YvD-nrك'> wWc 2P ϴe6I ?} KL9h|NԎUFouI9aowM2Fu)W)f/C nx߮ Ch/"ЗөG{Tdƒ)Ui|/}ZŠGSMK% 8Fi6KʹJTYxLj)FD~-[>-#t[|uPyȁFMhAY-?:HR5l6 ~ڽx| Q\SD>3ڟ=Ϊ:_FCwcPyR*a"E ]ZJho|[FYUgֺexNUY {9EOm1Nwu۟fuQ__oJt}|ÎKd1$k%v}ʴ?n$#;"=z覝eZom镼xP>)*3]o7n[m~FHUZbЈС9+zknSՏ>2~6ۘz;F>,>d-MӺc^{CTYj[n4)1LV̲.yE?zLpj(Tiv=Pw/} [DDGuq+}#_w=vz-TUyڐ'h~5R5Wrŵ \^dBNm Ƽ1e n:D!1i}Y|^M+eĩt˿?|YKU#!Ik2H|(fr$IۊarVv%&zt(pؓ~?PrpIjVvG] \N"31~T oBKznQy!3u"W=q4x*-3Tl!_k>#k9LTl¹#P%SXUt`Dǻ>v.UL&ܑBݹ"jߏ#who=3i'+zVj ϑtXHb [3IiWl3'WskA\`# )\.N,1Hļl Is| =Y2URUY%.q>Q ymU.yaHq`ا9_#ezbcf $)Gddvp>*-W5l֡ ֲb2I=f\os?MOQGz$}+$)|A`emnw="Ekjͥ EӾ!14R f׿ch1{v(iTWޖc:9cC[Y;fDDDDDD""""""@d@dxfҽ$*sb5,)NG+feDzѶ'%@dxw?)=Yr&Qْ%$Ъ/&M 2=i;2ɝ]̋mKBq-ST%%UcIx&w:k~W {Mhκ쓁7PXKtF 6=CZeY^jy4>#el!K(?DkLV8˲ۯhh{p*r-?}L~l|иtށ7V[5[)uWen/=+fDDDDDD""""""@d@dx*1m!?Uf0- vO6' u|^VB)q{SIN0ʡ6\;EOH;E=k鯭_v5H߈C`!/Zphryix߻T=*Ǚ5o*c̒vk=eY}Kpz~1Ul^5o zօˡ%5;q2v]GCae%YOo>b‹Xۑ7W4t mt-4f\׶>+bŽ^ϵ~_c֘/HC{S麡YחF>gҌ6dx)>^Y<[1k6 QOdIK9tr3Z\`{{ZyZENZ 'x_< ,'p2`.e2G<,Fmײ 8wWhK~f*ѩiCknoiC8ix8Ep80"նe 0P@d@d.!,2 2HtEFmG:  S") Dz_9 ,EXe@dx a.cTLLdOJ >Qd:g>e۪s%%G8-G\(zxs _ dMTd S1\:]wu7773o/2Lf/r;oe@d vL@z| ?E khOAz5o6:Ekz.wɹ_R^&%\}u/Z\yFQiP^/[cğ. %44tcdMgTt/Gv{J ]|&>#5j|Qy1AI<ÌoU~Y9/脮{ e2RකR%2mAkę ;f"8|ZPk~h.֥."Xkn*x-)VR; [-RG`_KKIVRmQuT۵7>G6_#5MmH26 =WXr#?8:L?իy5-)k]PCZ{YڡR]5kGmNP9Vj6{!eQfk` _~/\ B(|Ŏ8PhSj_=Z}:.UdwW} VGBxVCHP H,ԚifEj@Ze}ޒ^V%87\Z fw͍M^o|`A+'c"X7/ѕ~-+~VV?oC= e=Gۀ^-Ѿin{DkKu6ޱ2 雡vz転~n(嫘xϏk{6D#K Fy{>t oFװ^}1ε+v̾®| =ǭU|߷k1eos i};zybcVX=bgX=ϫϼ{߬%Wf}*6׬k^g=?=oHߵk5FYfv9Klttb 8:Dۨ/ \~@1 ߸?U`\boG '@wB/` HpOf2.–`Ld S") DqoXe@d@d@dtb Ͽ0|/O!Qo*d|3\e flvM|n?7L cQ٤tIME 22Iҹ3IENDB`gxemul-0.6.1/doc/debian-6-small.png000644 001750 001750 00000002320 13402411501 017167 0ustar00debugdebug000000 000000 PNG  IHDRtc}6gAMA aPLTE#8KVw # %%%%%%(((())**++++,,,,,,--////00001122224444556688>>CCGGLLNNSSUUVVXXZZ[[^^^^^^^ccffffhhhhhkkkmmmoooqqqqqqqsssuuuwwwxxxyy0yyyyy{{{{{}}}CæMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0wIDATx S@xx"W63XM&Rm(P~f1LdF_lw}b3ʃX<~abrף#Xlt8d"<>>n^I^w0};?}Ş = ( ( ( hg'?\YC-4jy0_,J?f R8W3iRR+*^\[X*+5:ūE7 /w\MHrp:7>7/']jviK9m5 5R!eS|NZNe!iT2fT+ JiIbr*H ϩӲ&Ҵ8xq]O E>Ls+.A{.B`!]cd!Zk!mU%KI /%KLN')J^qtSHDMl 1MY6; IDATx{|yVH^cY׶0A\"I6I@qw n D%skKkR*-% P8`@PCDb`a0^l[ٙٹ%Μsf̙gs{"0q9gAAۯm\!  x##bB@$H$ AAA !V%cp-*DHAA%$`h$770.AAn`F13"# c+F6w)Z=@))AA"מQQGOC#/8$D)Ǿ{HVA~۷c2rM2̶clH c#@N9nb|fj@ 7ݸ<сfCtFc:j|^Z+˖ӏCS|65ߏhaݷ#Yx])LNd1x  ZDp:@ze ُhmWꨶoO#;6wrDy6{ndžX5 *ZY N@}CܐHb|dGC8qHu3-]qᴝ0'1p`/&F,lYA5QDNNj@2׉HUk8]XRD_(ڙs ۏ EgQ]3 Oi+xeC//yP/AжCؐkq砪J9Oj*l* ?#GކԗM<}Ois>l]vto<5gǞ}'_`$'gAg;QU{X҅s6)bbbcn6~$V,<[;pt,^)/tdF0ڷ \pj,lIH#x}>?9}X0 `S/7O0S>v#h T?i{kNO},n]Tf倱lGFxF";/ɪNO`S}] 1|;wh߫W/ y77E͌U>{7wGD膋_o0ElҲɟ}~6G`'⫟\+$pcDЫ/\=.Btrr9x#)aԍ/0{&}㬓o߅F̈ys`̎!~>y{Ͻ$8q`auK/N:+q'߇Do}h?ُ[bszd?Au `%fQ]9M'c̎"Z[Ya|d09EPS7˰wsXܤqy&m_8O~ ?=86{> wERvk|1y u?_؞o3|q3f@ӂ9SOp<9'HPgȎbI?"DkP7{f/ZHOo0taD[(`f"dž=CMPվ{Z7K?v.8l틸\wyh4r%0kW_uQ>{*j; -(6?l8Z:1QZǡ^w=ڡ!,]?3h6.7{9016۶< Wz7}Oֻww 䀏ހnހO2EP][sr{90ӸPr`B>_1xM2/?5?f[}8<6[c}kNCS{1p :z||> ߌ " ` oC}5u 2ZNǟ_K<&̆Ey!>B˖CM  ]NjH"+-O?[,OwO*|qۖ'191A$:8k\EXcCmfwV_vk9g\'nkg{N: Kgcߡtm-gVǭGm}sշEbtj0r&/D(,kjď/c:9 Z.;-ZT/lu??R+55*7֍fT8Q)cb"1O&&Jc8ņGm8cIG瞺cCG#ʏ|VL6y5^ UDq!DN8G~\|c"F#a[i_wG݃/_kOk}2<1nlqnbw7!*,]fZ'gb0:xgPg?ǗZ琛4E:ӎO#sxu иl̜3`|V!TpuK/^y_^0+dqݥ-xyAzo!^~YW.GNA{/(K\Ҙ8nh[[7&*R]Ľ|V`Dz۰Kt"\`o8W痸;p >8kɡ3[ã?ރ}h^. +2}dKgz}Õn< 6Wh=Y׀ 5j|$ `~\QƯ| b7BZ9܃]Z.>=Y]Zs2ಿ o<}H4G /Nq[}6g [;_``kk?eMׯ}˚/|_sHt4a?/pQ7ttco̝sgaonFfp Dsb||ӿDU r9r99MԃXбaTzo?U7,_7*^zzy?*d.K*]u182_lpEt _\ix7wJ~^h.}΃Unĸ6D|즟v/~l}kacoO}(< nr5&s9'1gr^z&~ǃws͇042xpf̞K?5.ލ}3kN1 ߲ R8.| 7!zmH{|zk9d)Dvz KӓՀ;I=0I);t~C^`j͙myٹ'kJ[SXxsU?I0y76YPdnOFKqϣ09'?C0|-||)G_@lA񸶣{+($?ustˮ@鮓v'P5$L ,k狘LNd1: {kp=!crk`2;܌B:7# 1OivG#d'&06-H QjgcgM/ _|·Dի?ؙ~h&Q8|l ưpn 㣈ΨěKi :>~2*,<\ p{WEZ(`|lKT6as01:b? c4Kc̿TE"0aypWEkqd`ҳ >sq'{];(c!A,SӖb0-1>x\娭?ك3xpv~K <щ[[yΧ084|"#/i;$3hӱ- Kq4̪í_lY?śyJ?: ddCGx`[bES#f͜|5LL>/urbl *aM:ysD(KsV`>/{/eᕾ~kS03+wl|_<s?ՠ'֜ g8Mg@EC g?4)+Zõ,u.?4 f#2{ōK!\EL.=g#k& ="{ܩvp }1~7aY85's{1 0ՑIB:HzHX85wdždObւ?u?JѺuH^%K":BqC;4Ç#:ԇM}?ZN[8821^0>2%"y:Č"4Hwc&1Tz᫫/816 L4FYG]ӰxϘ@vlқ§[W㫨bԷ^/ây-R*<~ɩGh,,7P0xPEqdy7,oމ< -z>s.ݾ˦^5|S t=֜ z9LJ^}f̞9>т .\ =Cl~2a9W~.-7 Ê7'JCYyW;FɌY @T?NVr231>ܡ͆0n0MV_>Ljd'j5|fD:~D=ư#E+߇'APS? fk\pgdJf-ӫ[z6~tqd`>т}Ȏ3lj^'z狗ȡ=<2xy_>5u1Z IN"Q "B嗮8_ Hm?/?P¹Y/_y>nYܵm'HhK*c'DIw!oZu950b!O6`<;C2|éа,mffcH·~c8<0;l2+/o{GUk|9ee|tLK]?o1MaWTaƳx}hXz*Ɔ] wCbugbs/(}]?qvGǵnj5g1W8-pY:}賯ᖿ0#їo:!">j7x3~ϰӘ1k.ycϾ*}@{>?q"}u6Sko͌VU1>6ɉ`l (kjPS3յ&je%$0I ŰԯIL"RU^V`7FUC܅-80I{Ç?sq?ܪg$s9w)}Gс:؇c!:70i02rm4`9"UAtF=kXhXY)=6:tzٱ!TEkGzՐ:Co"+#R]Y )g[8{1>+!CqAֶ1.kYxonW ѬwAAi-7@p2y^`wZ!&Vep[B\׽\o8҉V|Sz8-?5*D"  Lk!HA bٟ1چ819Ծ$ӅxsKQ~&1D"ׄ[(" ѐd2dJ  /Vt<2t"tfm)%/ ׽ʴAĊV4i7#sFC\~yuIC7 J:=EAzJJнrIAewʐ/)?Cyk"Bo~#ĵ 6&)Io\ʘ!l߬-%۔_vClƊ 6(S"r7 .4AAӓi)D !7 GL{ݽoő࠸q9GL:1fbY.k;oITL&(nFZV&1߭?(>d2HREQV7 HRR;7odEQD*4(kܒl!L&cYFiPRٙR΅Ä/m)y%HJy$Iƞ>AA1*o>SDŽJk mݬ˛!BlL h Kz˛vj]rK+F &-e2texT$hooDkjgJ\wH$\m\Ժ;RQv, (Sv%MīL&m[D|EQԾWc8Qnwu[z$mX{IйY9d2*' ĴܮQR\̞$˛iwnR6yk <pt dH#.̬(Lc\cgẑΖNPI&DU1&"A!@4 ض mcJ[UvtoFr]RNխ=E"3H(c\eSsdUغ<ϣg[) 2]wvii&<ZD.Xޣ[ ۪iT)z<ϣ ,稛  ӲkPf~l(+׌Ojazel r 8\VV&3zqp 8Y8橸mWUqNb;X0MU\@kr(痷cO<\,0 C==év; **i(T'*Iu$ x7/߮JXNv^4  i4mȴuo9n{mf%tmTq(4$ Q-mUUCٕ;KugW!6ss'ӶA1yGuhre{j^88!7p;!7'I.Lfc&wt2Q@ƌ.:^ӌTQ!V^ފ;:16ɯJhc\Y%BÄlakn%jGx' bZ2=h @F/g␣{!@qF6P6%K24C;+̓to2ucs0,kb1L:lggg:9H/HSaq lҭtCjx&O==)5lUX/)AASi)DIL␢<nW!qwNLSvUC5gN&W+Eh^٬Rd$e*&YZS͟交6csw  fQܮ Vܔ߿ .H%;@c+\W7ɍqHlܜP&.u햏BsĬ,"[HU7uVQ;Xƈr1򠌞ܙrYg2|wf2bAaZNVpJ%NVCpvyF)YI!l M3/9?MSЯ54XnED A;C mdG~9J϶H$&BYΒW㎚W2ԹzYA1BPV>22Wwfp΍:_g2V!mҖ2C؆o~* Kifڳ B k4ԈBs6ޮBmOo* D]]wvQ 7_K*Ҡm[%to6.)ql)k$I2 s  0-˽I2i[ E9H7BOˏa4h 2m%@:ey2}$Itwwyۮnu2ayԀ)by[ѽ۰~u%5[4,׉cSӢDB[Eg{ު3vIЄ궚FVe|x,v$I u[.,AASȵn%pB[,ﺩ8RoV7C\n%}aTFqib5,J%aL? lIxv)Kh1^s 35%EUZF!4ˋΔ&"PAЎC!+bȯफ़sH,5h?ъKAQ*Z/K{ߵQ9NGj},;, GeO  02\՛tK 7yQ$MʉuIKAADBPVLn*a3,fI$SWʼKr]6rp$Tϳ/-] ﵖy47zMaQ+DY9gr>.^ B_4QvS:-bWqeBKzNJ0w-9/m$ a>ݪ۾*Fp &+1 ufJ2'L*fKfDK!Bw{^ŭKR=P$I ęMi@'uqss냓 eA̗ŋ j JE0+B_$F9@kve\?OqRÎEi>Ұ+FcƚZjPȼ+ ѰPQWt2UoS+(ICr>V J-J y鮺*Jgz%Ũ+PY1 ey%VNR\Mf@uʽ89"HUS]Т ?}]*An˘笄/aZ˩?TDnI|3MaRFI/ =jHHZ Cp8nyAD=.e9Jnc.*zO$SsY'#VbNs JjEA=w{uGyHhSV Մ۵4Rvyl~vͧʦ < X ʸܡ QV7)-+jrCD}iYiFhn7A^YIr6U7D~Ƈ:96!vTSތ_wMZ}pbtB%iU|}aP,Y܅.>=9l/a qws C+]FtۛLJ:a3MrLۗ!w BȞ {`c מ7憚 eū;UvBJ :6m%/y53 >=Nԥ`M&Dywm5YvJ=dsN+l\/j j,ҋ>)Pq; c9[ߟI0ɃhA2Ũ)bP_xu5 UENμAT}V!-7Ad-TR>Qj~yϬo:H@"Ği鈲PrC0êM?VdfRa~N+AJhY4IMZd<}Qka%/Ũk^"HtuumZ6[i(vM>XExo;Q!*2u*%7ԚR 5< ʸZ{'t ezZBh] %5 ޏ;"FʼnDZmaw+yr Jzbѓ˘o3(MPWʦ!jL&#KZLvIS0+AT){*P78Y24 [AZ)^ yiO.}&HRnFn+]\+m^n4+jC)b?ӷv˝ zߺN|ћ?^Ei:-Z3D0#ed~y\{|7A:|Q,HEo6GǻYbyѰĨꀲT QWDDʐw)j9 {EڊO= Ԯ޿rҒ Q.y T.yJ0^ˎЕ5һӇ5rA u"HwP«;*ޣ4pH,F|1;?F᝼P= $Hu6$2ۺ;{MLy+0)KoS>6'}?\зͩb)π.manYYYd){sG" ;! %)2JT^QCW=ctK;6!˲26[RFeEfU-v׻eDTW$Cz&(ߋ(e|eLX åA(-i1F 7Inhp:0x>1ʜDoDXR.O uݠ旕]A<,w Րe s4188qт%EݑyW4 +Dor2.F1:v~,ZR.H C䚎Qj)" ʎ,+ҙB{kAaWakEI]SI u%;Ba6 ]zJnDŽB_;jUgS.W~V.O! nEQ>?]W P7W4IL8 R˃@JĨӴOf{|{1굊>bF!zQ7+ QZ VK!LC7N/9A^=`t4ӥEZtӳg˫&-9 D}9l(++Ȃ~h[Q;WTKk{~:.ͫ_["v<|-8`gWT伸'DgRWA kbE_PA*g1U4s|Kj-dWu#ARQd {J~zE/L횷QR.g5a}r[cXKj*kXߪX8"⩢JxP3o*DY"KH&x ],cE<t T}zrCM/ڥҎM }'yo#4Yv6<4ۯ mn~){Ei~wLKa,ɛD%22(#HFfݱH koܢ)έb]_.ʚK[SI>Nn8+f~eqx" <'. ߌn/ȗ!FA^yX $nRv}G: R+ 1冂 \RJ}Aƍ X? (V]Q,Fyjv>yqjxq=rpEʫV״D9+H h#;w5:vi@ ?#vI?EiħUԚ ѩ(B F$11E/1dV R sy v !HmQ s9,@ɁL1JA̠mX8m<(!,ۺ;$p. ?Tx FV(R@m0)`l?5_E[.EQ (%87]p Q2!"BYײ6e3vwCY k٭.nyV7$ܘɽզ+Y-Hʍ%Ԃԩ[ތ~_PYP͚t35דS>3 bӮWڻP>b`Eφ–SU#(g%/I~DNM/hZƓ\B=|%[^,N2ep59parI˼ZBѬܻ1́ݤݬP IDATլl eqHuol~EiW DX˜!U2NfMr1^{8$e [jIG{Z*NxZP=Q{^.7z"Ԍ(em߽RGMfs +MVbqC׭dO\V1ǐD(S xt\7!;Ő1ݴ4=&]#׻)/J )#XlI?Gvm 3> Q+ؿ]ZBw/=̉ndzc|B;y.*uW,,džr,Ȁ$cnbZDVREj-Ylc%@PEiAY]QA xV~Ď% (TQwXQ깫|:uʦƶ4T!`sΩ&B ye!)ر|$cʐeY fޔK6(~[oۨg!*B{eI^+nLn]AR&74Ҫ4ta\/f)Ҳ;"ԮKh;F7tZ׾d_BrC}g/k\%%vo4 nb-P29`xkQV26zA khZ7%L8.`U)ZT=l'y4(B]òvX-g(mґ2UlwS]2r!hS9:|/A~<~OthPf&/=$搲>J4}J?RLbNMxXU'8(GMTKI( oX݋m[A]K[œ{8 k+DM+DrhmEW_ Szy2!ۊQ?}abUJr7jXԯCVz6NԏxQ+/ Q̦;ڻ !+HzXX1U2"TT:ԃ˷orIy jkEEi}hBTOy3qk$SGJ]vCK-"XE|wo[NN̎PT68VMJYi`PQ lTM=VlQI\+0'V *!87غ]\QVcS]Q+^nԯ ]]) տlQhRZz?.sAyzwHK{*J2Y enwJ57tk2ai5Ap_%#!K~R%dî~7ׅ,@pX P+0nQtW{pG-$׉ҰV +AV6 cPV/B/HFsd%ZOY]lj R5#(.Hg Ұyq[̈́1ZjAԻS6l+FUXEiIhm]rDSrhD޵ +kNqC/3RW`u ;E"ԄcڲXX8qSWӚ2Q.~BvH$S :? =8Thu306]BI:P88ݬ+ V=Jv\ܞT\:Rz%s?$@s QQٹfXX_ ,`%iz;.XaW/bT$pi(<ӘRHUpIOF9H PF\UQ$Haj-w",AШ$ A,|!KW1XZy^YNBf@{JuvRU|AZT.]4Hiwi§ 撖zk-J{܎VQGz8)C6V/Z،$> s@^Қh"t*NLx]kgvDS[7%iyO=E ,DG>#ajLPc4hvv}ƻxm)VuqewֲDhr4d”(OZ*%>R!jt!1 qWtuPxa\E)CtYJ3Y2S^jѱza"JÜIg@e(LQZycpљB{+_R'*-nԄ'jFqJ^2&X3BM,FM~%`7RVt9 vY鐆q+%HyOb~AI]{> pIH>b6N,2KJ˂4iw`.g4N|^FQIKZ0.CBb:wYzYQHuzT\CySNS cbCE\URŨ4 R|n8_+yy1bIR~א*jqRa~acyoظebH@be3Ra)뛶aE T/b\+jL8K]~_%Mz~꒖R._X-oՋ&@'x:6%*Bc!P = 3%Pn*̲ </fJv[T$&rBDUc}@K)yx]xB\_BNbu`BJ^Q)M /K6k]*J=^@;^4v/u3rhvMz}qv(2Wr J"BY5k$JU&*!={:l;v&+njG-؆^ @Z?CRKJfg5}7yAM*-F}@!z% '1u{IVTa7/}J,M$[UCdm̋ vQ>N= t!?i벘*YrI06OowLWx̏%5E)! R qzQXNjYMXҿ{V>n.sT/Hj[}I`6*ULW cBaeiJ$u sq+M|aZ7 DL^Y~euC ".y|Vimoۺ;pLPMV7M%dY*/8pQq ^Au;ܞHA-ND$3QrUaG^ۆ!J.,bev%t7Ї2#L?K\DU(PWJKƒ Q0:*BY3-ygtXY |\ 1~rLӋ0-4э NUHTΧ߷ Mɰ g冚ːe e*,HPJWeF𜼑)6aׯ/է8~1LR7Q4N4(--}3fQ"@ҰI8U/LDE&~OM)U)o3kՎd23^ }%NPYV S+1JT8uPI(1ݔoXr7U-sj0 \Գ|MW4@oTǖc/6 'YM JWWjE]taEMkJ !^gϫɸ Rw/q=>Y(n"օN>fQj+@p*{fme"kYyى2 Rj'">>7RP 3]ѽ;hYe~J"xMhr[QX;T5WT5#,A!$ҤA\ҠAyu K Kȅq6DnsgLԷMAEyi~S7JϧLRZ%ftjB vKL+ChT^ %F(C Fė^Z=ԬeV XVKj3)nxi0c}jg zw Qju@)[Y]jw[n CT9ރ(SQZRjG0a1nyԄ8wK+A&BX,c;RVd(Vx4&*Lf3ы05Zg^i(So:b|zӴd3ۄ'' h_S(yQJ73K s%o I{q6@KKAJJ|07ѩ fy\۝>w%)sɚU[tHK.F./PqV4 Pi~&Rԯ(շs!_ Qt؈R'^EƪzN4LjNiX4M}Cj -o\cC]AC2?mF0ΆMo\S\5r3b.NT9_~6~g;^9Ph\o'6<Շo,njv^]Q/+tsC0x%`bTe>i<.xU: RǍڽf/pz]TTQڲRПǠ,JKr1.Ѐ4+m^$ $XEhnhzN7^=Ú{kncC3&ʘYH-p\a)&@5T8؋ƍM7}_T( Gp99龞CKVRQ0JIT뒑D=7"(A'-'u'* ]}*J& ҄̀@b%ZEvMO:M\rT\J xDyIX|2a:>㣾-JQ%ꔁ }&js3>@Ǭ>EI&,e_?w<>^j JCKH PuE- 1@NV+u%Bu91т.( vu]IZWk}di|h}^VRc|,'CQ{eݮ랿ʛcjMJ_Mg JGMX9)f+O54plh7T9`y Ȑ yw:'n7ˣHYd儏_t=vWk`׆n1>`~9⾚9 KTj,+pO $f ܲaR K!g+7,"d~xT?uF(iT}zڐoi:a7N>qc6;C9 a=EAM2Ζ02-VGӹ %it[ mI^9OО;? >z@y" .n’# )}&N MX h&L(uXF!u0n\]1/CP6>P7~;䄹O9:L6֫VF\-RG&/뷞~؂!Js^Y5]k^2mq98v6X)6tv ͕ I;@#^WhQT5a~92@ƒ )h߁8ӾcVLx.on~ؗ*4u=므Fcv_YbeU7ϨHKL^*pyuK \n,(_ǍM9cu ΓC&lc#6oEf-\_-W>Y+$_Ӿ.xb*hٛjAg VNm =n"wlh&7Ƭ[vIiVn;:nyXβo#)R>`桳LZ9څMg` WF䃴mmoҡ&5rT}?li;zaYbu#Yx7B.2,tWi|=@i+c5LZߩ;vٓ'8k}?bhT8ա{V-2#{~<+i{OͥqD.ԩe7R)I$ UCocM vCu :k^Ǥ>TE=ϾrWDcU ^no Rgm@i c%w@:dMۀ4{w E*:N4MU2-d2˥}-@Zv&zEo65'E7׹W˃Pl`:QBi( 1z[CO4f׫1W&{`U'6p+WAЍ7 |/ i>|#,ɜtgwD @ٔC3(fM*7؀47l(~Y@3YI{):c`Kϟu;˗ϱR ҥfR,J痼}ƚhqhgM[߷Yu$X-&MJ Rv=G %|ur*7Ɣ+X0@5?vCvQA|>GRdXԱT/- ^9Yv IDATk Ȳ~v_ ,9v軞fCxZEC3S4xTP=dԕPy۲o۲:'6N1\% .(Լ}Jz! .$Wgշ9#u{) cW癗>/NC*l*%īvqlMnf2M҂*$1,K, եWtR[|)]ӭ$߃rVzw[HOFִ* g`IZ֯':< EDΦ) h:;?v_fyq\T !SwQBiQp/o~6AiB["aY>MM<|0 >c3% Abx_EyԦ{JO&2]kyjs`*eY EBB"o0ܵf=X3)ӣ+($v(B-8Ѡu ۤnn5Y # eP)FE3͒64^,hַU0- `墆Lٖ0,ˁha__ʃ@o`2MnP J` jSB]PjP=aɨ K )S\VCtPjjolKqp;$1Xe3퍞kHpl4 Sj^Rg!Xǧm}Φoq(,yK{`Y4]I e X:&W^.'ԧc@Qu4C@ Q{^&?w٣k.+˳o)u޶&(: >VR-f* }5{ eY¿!( r *Myev1䡺ԡ1F=wUx6Ōkyt DohXU%ze?5v]7~Sf8MɦZ zрQHLb ]럐e%&T Ãe[cܴ2GXR_ek=e@63uv>sC1t(M)f3$MXQwUҘKS=Oc/J[U.&UPZ]CTQ>ɻ-;>m>G3oT'X &R;v}2|)mGϊZ96y*яm5%hTTg(ʎ;y_7_ۿ~v_?LY7;krFߤ$>Rv#ZI]IӒf=Vg5:t}"\jW ROխ>j05+WUJTmnpR9W8VtNy(yێ( XES(ADy8sd/W~\q#N:=YCߩh֔sPd0q:.v!j`P0ݻ7ͦn6nC 晖{̣Sj T:}n3܆n|ІanmDڇNX7^ K1 E:] RvOQ+2Bh-!>D7W~煹*τf ڡV/r pAsp6e:`ݍ*aԼ)ko92a)}]N8QM>PjP]PePj۶!%yLy1pX_6Ro^}6t@jp@dXz[d?ާsESa~)Io> ʼnrh_ȌvȖU {=xdP$\6#A T05$ ،aOX475MLc,.(mJCyS)N`JWUiMfO; msJ9 t2toz =YXKS*CGCVnWo>G).4X2^S^W)DI[!E K uYZJS[%(}vtOI=W79@usV,Pẉ5[΢࣪Lj-yOi-NN-]vT*35?AY?v:Omoo=5@[o554D2 Ru*&{h:Tak9TZt3mBg?~PLj(rTP"I fOUO 3d1qy*j }NE1Wu )[) 7JDȊm"O@mrKfJZJtrᴰdNͦvk e}8ȍJ=h2iNY2Rg`˙-\ %U{DS` $Sd@O x;pJ 4Ny.Xj_> KEq=5Jf\ִv8KS%So07=}LcDGx;s2[mQFO)ePX*]Q=;Y&2"z.@BU`~_]0|]@jfYWi}X0Me)B4Ӝ&IL*ϱP[⼠t*Б/-6( =\6( fuha -r34Zuij_{coz@3z>Rcԭ ɭ 6;щO w)Q$6BJS|{v.3Ƹ HQ_El-%?$[RAPӼ L˔HwmlB];4lێ1`jTpR4:NsMmo c>):.:KOC+9kwa UCJuj]1-ZB":-j&T2YR Ch+J- '#.`[|\SCsoZeUgo= +Y>;N[l;F^~88 sstǥUwx. ;μd7s B{mh'X=?QMzʒTR=z6Iބ ZCc( &)_s"-RczF|N)"u4穠30Mj '4@565%~ȚeOtN 1;Y?Vk(Ȁj]ٴqlƺ4Yؓ9uӱחF5NPUVMa$J3o*` Lmo;&y~8xKq~\6CĎY-dF&St0V~F7Y>gΫP:FT2AViJTbNf-%VuWF.L+CziN{2WW:Hs #Y H@lP}=sP*'dVWCoT LNՋ5t:+u(#"S%,V+e;ř2xEku35z>3պ2>TkF992m_s,J JCޡ'ցpGRHQ{KBR'NtĨ׿!b3\]>Ė J;=*sYپoߝ(;vj̷ 8>^̿u}4:znc(%x(k\%ԯE<}_,]:8AZE]! f*EZ}@YjM)l@OS@M\Pꓼa1*H$驀d_B@r׫K1^U9>E&P=ʉM"9Ԩ˟FKP&89:PUϩl27IGuy6Pk5t^ "vpNA}oH^NѴj̳TA+HNa)MẗjO20=m6,0dY, 8v_K!mjJB}q' RWHBCBuGRBHOi\.p:qɎREЫQ0OF U {eId" (ܽ@ dg/!ѳ1dsXznN,wC7cͮJuϔe6-ːe<3qUoWo{dڬ ╃]&t#;c. Դlluݦbc:Q9P &[ tS6sN]xߟ~J:=hv7rxT-oQr7.|RٺtH.=ϭ%86-ۛ'[:_MԬDㆽ}eO_vT7X#z@B #b;;:P|2%񰚔 JRҌ*cҴ\.Q>vXW @\YS%Gk, ^Ph^DΙ R1_}QdULOE*wo\i9:`bpsz/@W.p[[OWsXWf8Od >>#46ǨvVﮜ |RWWGsR-` LsS>@:hqr@DĬS4iD S•*#Dk-dpP>4+i!@}Pz3PN嬠1B/SL79b̀?j'`2v;\__735W@w$5jht=ƃ9}߳؞ uAIaL[R^ʪ42vLTjR;T FmoRk u{YChf0&(C˕{4 f?Et#3=_{/5)\),Mң>]t8jsu6 '35˻9%"hR-l\~ MNdq{[>FYV^j\@a!%-;_qOҟ qKTJ׼^ "5 _(խRCfK0e~0GMNh @>x8/;(:.ݮ8-.2!Ȫħ98}1IُZM>0ڤiJ ObLr:-3MS-{Pj e;&8* "g\5˕v5*E4=?Tj->߭b_ C*r泈R|jShWO0uLS@i/EmȚ]΃eY߳+ZΪxUt^TueCxP >&Tms*)k1y`w @]t P xGX_I@&C{@ &/>F^s-uّZ>&?r{hL.))N}j}ZU|)1LQ2>NURD\Y:R}P0uIBi؛Z6(YCmPZp>J;`j Jkϯ9nջE=|-E,9 C/MzfꫡkAVڡ/<6`)AeE1P6oe@ޗlX.ncqvCIPޔ]1Jj=gr>ߒ ijJ ]] b&)^L<ıVѲ,v}4*YU@X*I`CGt1WLVOi.(n|W(E|{m7T>IBn,CnubgӻrpP,iJR/C7۷Ktf2>71vc LukjhF7yMp:&`b*V)S>/*萆b&&TY@N]n>0)e{Ğۘf- &եLPeYSiSJʔea^]|>GYE|1*>iCilSwRR[I;byCهR[E4kiW|ito99Q wa4a.a_f(_Jl+Dp wX6)4vr<LmPӘXNNS F5nz|fjF&2a ڞs[Scf}gUPҽk h x0-P| w6oQA.dyA 6~:s@K^_<p > U!sQU554D*J(bdIHWi+:ap,I}-Y[Ɔjk,]翤}sP]o{,.)4L[̈́m)5KmFcc H`hxڛĐuBgYݐ2 &(U&n`eQy+y63>%OOUS}P*[M`PT8[l}ǔh%uaxו+UnV<*TgP))-q=z{r8EOx .OW ]۾M"g\Z[jfTR};QD ,.:0:FBF K5F 繐P)|^0YKcA@kC)-{XMCZU٥7d=r9GeȲ j9/-y/PI)N`~`L& ) T<}"ZMN2D'߬zo]qa#QY@NRJ@(6u^5_f_m79"3gW{rp:s.LSjة{}K/NI>s|XTTrq3p^!^9V̦X Za_]Z792Es{ca!IeP4E SIg"=O2NC TdQM5Sn-?^]Z!;zQ>I`ԕ1oYPŇ~,W;x^p:Pܣ]u)%Q H y3ↇW">Sz&ES^&iټC\$(Y6x(_e޶egݾؚ֝F_>wkQIJTPt8Ut`~jDO.N8-ݕJrSUS'(fK^*'L{V+Um}Ny  /z,ѽF^ŵ`:vJ]Oi)e.bj8tuvq H__s*Zt1shLQ6c,*U{zV ,a`ࠂ *  A+6:u|!$ O/.V^'j{p:*kIŁ /\d?l P(hmj؆IMB hFY)Ԫsy'-e5A(uʒ[M)Oa C3լPO9c.W3% f*Nå L B+j@ jJE}͗s@ ]@C/Nտw[3lWAL'  ,\иY=M]Ap굑!01΅i[Q<FM2(!M= 6͠Tg[ZZŊ,/yXJMA|]r?u`k ;YH L@Hph=?ɖ;צt @]T ?DsYFjQRiKBKd~$=Voh^ 2Y16q'1eS_%]յCKj@`ZKm!}*}+6ەm(U_ pQnrj֮;q0A,QR@I`zzZ=M C` Tp &mw`Hb&24֒~n{> i 5@ϡq- p(y@Gı"!7B̞YqLCKBXv)f Y^xWQ_ M^Ȳij<8,U`U첚5MbLi;"Ujd\6 ˋzݝs"tk+P-8_2 D#K6ljV!6*s[1l@.uW^ ӱ Sz1P,xR*ӗ}U ghY"! 9 s5&y΀u3R9f3v7h%7A(\_nSd: ͲﻶiwBv;z@dDm+ꀠ & GsϻT|7Vbi-m<7'q˦ut[Ctn/$ukfUR(1m& |lpu5++ݯ5ڭ,i9}tA=65pZO( JLmj~K?lfOdh&{ uA{er*h)fߏY9n tXč+X"!tOQ]0i{]MSJ>>ƨ=}(v6]ʬi ^5rVZF[6}k)y? B>_[A^RS7bWj.}&nv{ב -ʗB*dKתӢNM.QRLjSRQ?{Q'jn 0#z G$Xgl׋V6 U˼yeMn{8jp&*u`ׁ%dT8].t8Utm z5iJRxϓ+:H5FhBo V >*Lk60Mϑ^XݙZZ-2=2563GZxFe=b!e,P<fU1S\T,EכmVMݧˀ9vx>;0bz)缮[ޞwSG)>ͧR?n?F(Ǩ~Se s<PSՄS@*!1WvYE _}/_gġ[]&4B;jΕvX١ێ Lm ~G **7EXKsnLP_-5ULÞlE)jZ‘]ʰh6YC_E?0{S Jk30X}1FU٢6i Pn=ICFO*bhe[jNd{FDV)3\V>sߌCHa|)L 4'VMvdCG|8|`6"~ćܸ.`~|ZuQgV4OO[b8|.=|S͜tn_,BM2YK]Pw[g wf L-_ {mFKj|\ 0LQ;쾯\ MZU![HA0tZ;Ӿ5 BMrX+0*{ j:nj>MK@t<FMٔ*K[o >ho7p8 LjjR19s1pM MYI<-`m"~pb`;^/ BM[Wfu1D탪mۧY¥l/<KQOmێ"#4Zi uO h9E J:ATJv*c ɫcZx^JH]aX6ˉ L{nR4WӅ\>JZwq"0sB#!*u,G\\o%SIK|yY(Qfe]46ӣ 1SSǍ ٫bwSA>\k[.r^\U5W>sPIƽdG??Dٔj.\Y@wwyoNHjUty/frVϫ ^I*kh6@ly_qtr)5Etn- 5m6sv^8{udYm"9tLl;NmPԹ6BWP+=L_ÖiHz<N"q\U]TIK>2AI&>pݙWT;sz[S[~>?0ꙖG%_c^s2aԨЈt{ݏq@!Q&Mv+f{M7M|"im':k]bB %o콾 E.v z8uo:Ĵ9+Kj:a5RDIG2Tegi3`lE}Y/zW2LI5=@MYy%:`zps܄ kذ,QjWˡ86\#+0jNѦq.zMQ#MbR QL67'ݎ%thUvȌu}^}L&=>uo)y BO#YtCDz.~BY`mU)Rxk b]lpz?b>+i.U'[btcqŹTH&O K54F.0P ̭텀WY/0՝c@Yxt(,}!0]OQI$9ӌa O9$NǼm 6 &FOXW/eR=B9I3<L%ʤ%QQ><4}B2lz Q\pQڴ?NvW4D ϟO%bp,MwsVfP 4o;m LC!TZ)t\d)\ՌHuU=?ot.~&ch}_L 78}Q:훒>rj.6/-u ]BUn۸ $ I 4z%?IP2Fwu[U5mqA^])Cbӷuk @t/Du1wʧDoO/Q鈺}?0C>C hNӀ?uwƀIey(Jqo\FBS1{\0 .q@HQm][+/y4w:SLѡqE1Z엮Y:g!QRt5ԥR)W~fR˴hHZQ[>7n pЈ BAV0k pp§ /(Ur|} { &ej6\!Qt㰚JK(,mP* Xe*&yblp B׼WOϧ6霵,Pj2 4dڇ,b;):2رC{#Fnnhm|,RO8I 0@g ^R't e6q-^Vb\ 6zVFP?}G#}kmH8%K,$ҙke}.YuR)4+X5#s)]{w\6MT Ԧod<YB}t[AJ#JV"X5Pb'c &۰>ƾ kC`:w|EnCVD$ҙ HEHUp &!%P9זLVmy aN#C|{3251tV@D"^&8]Y14} $$]ViI8LC8MFHSr:xD8Q\ LScP?q| "%Hm?N 3\1ڬ2m0ϼ.Uj4*.4D)mF:S(9",$?P׫l lmݎ G(D~dӫ&UǼ6w*}n$Ƽ8ӻE%n3TߤͶo j Cv ҵC\CA6+H[O7e*J˨!^:\ C{,Ҥ4Yk Fc!tdM$hLc @ka =װulsǛLa2a*a"%H?p RfT6z8H0 0B@ i;9bB(`4:dhV[p HC:=My2)ӆIi}]\&i>X.iWp4u]{Mӱ,i=w v|\Q*hS$v_ Z^ucSڔYoݩ͕=}-߱Wu<U2嚣~T0U8}P]c`k;pK@D"BeSSE5@ٶ!!Ghk(z?Ϙ=5 Ut5TQ.ibT'd(D"}2Cp:$R;(p tkhL168& tPyrIHPmPC$ƐqPOm4XBWNk%V@~]2O@,fBb.|y[PJJ(D" Sn\ISʧVhdHr&n翏PPlp6!H$O*na2cQ *zN+ ۑ+da]UiŇ Ԧe MDP;*VO(D" T4N;Ѐtz%-P@I©.#˪ @|tmJ %@D"HNczQh ._ Pc dڎ sK#&@=> "QD"0/P]/v̺QKNR>mRPߖ2{d %ň@D"HIdӛ5Lp 3dPC`HyaY/W{ = .-9YBIq"%H$dz0dMTZCC4ȭq q!Ԧjy=;-gsmN.{h[%Pw;ʎ'ŋ@D"HG Nc tH&iL1::r@%%(D"N.?w\P*P4|pv,R^SQnԢn $RDI$tzDzLi b.MqE!og۵ x)v ^E_NTʊA()DI$]O N #߽}(sm BsJJ)QL-cc'8mR6}8Rf -u_k_{p^H?hX#Dw (0Jw$@2@ nsTuT&;~:u'HG^$I #N@wHA華0[G-rRz e$dU[V\&RgRW?h"T&M!E2 JB1DY$ҙK$0%EIn#0+NRW$w&(t>ݤ//5A("%H$LkEq $"%H$; Pc sPiD J"H$"oTP)E J"H$&<$D"HS$D"H@D"H$tH$D"N"QD"H$ID J"H$D:DI$D"H'(D"H$$"%H$D"D$D"H@D"H$tH$D"N"QD"H$ID J"H$D:DI$D"H'(D"H$$"%H$D"D$D"HhvH$BYD2@D"H'@P+^L T /D (D"Fv-Rl@5 ^TИF?'ch,j:} D(i D"E J"H \¼> X:m ޿PW-2UI$Ҵ"%H$ЍTU*.Hehs`_BèxYA@J"M+QD"9(C(KZ;]x>C[ sZ]5k-*p %(D".U)4TCeuT,sKL>:nT*VHE J"Hi|$źbu_Pn_]4M wtk,D(D"*c.U{T}j O{^r.cڈݓκ@zwGQ)DI#ۯ|;3.~ϵ_H? vݮ]f MErW BG=ն`DJ%Q)zYbGǝuH?FA$cAu h& TJ>U}Vs 9RݟRٗ+~{VgHqAnz)DI}0æcr6 ;ӫʄ$ LPTP1*sll‘K۬YR|xVƗ!Z݇&~ZHɴ\dazk[ BY6p⹲D.r}l;Ee BKe)]}$(hFWʨ'LE|ոg ꣓B22I?d]NQz @/=ͱPS2Sohs鯆VbbQAi\Wz\ۖYW 'H[(ق?&O<,njݞ ɌguTո5bLF*N" ](k>mg6v[YH3 t,BYqYI"()^ݙ37;n\, ,vGW0\^'E'댑] PJ^3OYh2;OC=s|Jݪ[nUL>g [n0znV~Y.o=oY=|{d}ղ}b=[0:-X58ٻϦspmG?{BeuRh\:uj|JDR_:SjG #xa)w5@]߷0ۀ页*p_KȲ=0ߓB+I]qW;*=#@;@2qc j@zטXpgKYln F?ծu [EZx)++w0XW5Mm)i+׳PqD;'`T=>@1cety',ܹ.#_fYZr7Z:@DZ36~ST<KFפym RweNm2~VzAbאLV^,=/e&?Hyf@&!v9P*Vo_)ɴ庤%@b;)ϻPNBK*Y/ltu.py} %we (%xPW|o. @4n qugU[ouSjB)8 |n ?toV]+(I<lH+=GzioIJÞF6ϳ7B ב .ЅQ *IQ6j:x"< @ֽ :"e` y֮TB LL-n8y7e&FArWvs,Ux FB6StΚ9Rެx,.B륔  /u['3SAhJսy`YK̪ryX@2{?P7ߨn%VW+l11l+ǽK`]V5ۂbZSꮰZ9Ͻ{7'#InnT6 |Rpd׿(OQy^%d2FA[9fm5Sg](_;5ٺ^:Ŏ#OʥCabyr#f+C|궨6^o5 Fw[o|. cd>S=~wݵjyCnro<ؾP9薏0eʲ*RChJogLP 6zY&yș_UK(;.c2Pqzə癒.pb9坶_A z9t _Ko+ջӑ*wǛJ )]} z_vֆtV-sـ 2d|!^EN咽w{Co.XɂB,C2{̜ 9ˬǎ[^{ R|z9lF "q,չ3:g!oJ(IXRdPA좻z JU}QEi;Ej 5PJ&m;<_jS&m{@4+;\.3Bb>Ɯpd f>>|óf"v۳`8;B)AoXc(r( nȌpj](/uz-dؿf JWbU_m:PK6<*+\En8|C:.+[v׳F/XWt] x^iS_:^2o밤mo1Au,n B7g!ǁGy+,P8Sj]ar^oRGv]t)h&j:q$[Ƥ|#sOF!=n"c|hw=_s}{a&=kk'L2gʘJٌYEGƪ׳*=FB e2P[ɄBݚF;w- V͖Wba7TԱBEZ9['SȰuL}b8༎%spj{oqStï7<>YlA*Lb{¿~)8j[h%Y[!JFǎ+EX Zy q׹<cNBHtO\epu_K2 6YrWSHZHw_(m?wcfU/uc**@Vj/0H1ircJؐXnJGYj`u(4P7 n[^RELSZl};{s̃7&`hdMQl;(@^tUMDg$:gB `?_MыGGKLS'Ta~hHgru;+X>Un m[+j(gMF8k=UT>8x IDATY / Zme=fU-f8@'PvaܔՉI+/ kcZuͲV:648.tiioma$Gtg A$`@8`4  X`@$ `J}Bڔ3y_;vu#tVf8ls-뵠$2$g6FΦ V( - 5^ژV2NXN/e7c@?GFxtao$QtT6x[Z޾1Hh37ƒPSQ=NF{j Y7Ȩmi"mTRjJ,Ya /DuV$Q ɐ9RH4"D4VMGⰵ$e gpU8(VgMق( !_ $ =EЈ2~eXBOu{!m l64SW^ҷ6(!NҵݬQOuD5CỪ o2:i5[ _A~m4~U%q!0:wjF$STdkOj`.Qk v=}m4+c€w& Lֱ}vah:+ରע2F _] TK 5$/ţ77HD=!b%lNo[o:o4ܚ3`Ye EoR8RIlYퟁ?k=rLAjcnt5Zr|lHdg> q.ŞNBi.zlgD3AP8mYO]jqꯑ/ tinkdٸ7!ژ￿oqG#aI_qX2҉fצzB0NZ `1X-3Ʒ+4nyM}FD˲d#(#y I&hR'ͣl'#Bw3%wPKCh> 9p` JCk>\nĥ$kZT%a?hLpԐsCe<_ vH8dt B$ԺfSxݦ/إFQ(Ά1c#Iu%:~'X`Ϛ8u^wVGSie/8k{궐ѧS̍sb#3U='N;?4l*fNmh( h+E*jDVP$Ү@RT%DvD\VUG=/=RXX߸!%}-8b]lR)&VCT,cUP*dH&9$Jaێ4xvhs3=$,z!X7?;kT6/s$ !ތB9S)$ 6$}+.t82Z_듊 ?Vڹ-osK{u@,Jٔ.M|FAO##EyLsQ5©5nKRFlҞ[|6fQKnB?H_z߅H Ō#6vDQ$sx|O f?*G>uJ`n:16U"ڢɦ\fP U˛HEFuN|][6}K[*]X5|N5Mc4](I' ֳFi#.KAwņfN0I(0h{1dSVfNMJ)αxo<ޑpI v_J/{ȴIY/E 7`t/=D>*I"ϟl8*)kO*}_ >} \>!p t$ [\"K骹zaېj؍hOڄs{^7NB=ԅ Y<b{zzHC{:}w=MؤS;0}wٞruJ S! !<$H0RD'D[s_Q:,eBNoېETu8lelZ3]P4?봨iqHۃC*ܺZ޷0U׉T%cTR$%A:I"B8}8ZtwJ9WԋTT=t:J@~y=.E`!\uPOr?Aq{8Qw(8YuҳQ&15n ?] lsE|!ӛ?]Wim@Fug@*zKI*ϪG@W̅ʠhu9I@&z&B-m= wOQpl'"QHv^g{5iUXLdG48NMy]0S=[2Sg!z(kBg zס4 sQ:n?pPٟoϷT6)+!Mxc cM ;ޟ Xߔ5zyTZ@Lyz@̉0vD) ~wm Әt5MQh)U:Z[/ɠAlJcZ^YRY["wFlSv˖AʞU8>{ ZK}ѫܯ-QcQp~/reYZ]i87Th<@Dm"@-$*? J"uI <TjoزԱFan<\I̴9!l$SmH Dx V|~džkmKχZ"j?UȠ1ڀkbz|;fa F~"Rw9?ĪU':ɫ67,KLt+cb*pbۨ/lH4wUwUG_XtHl$pmx<&nj({ L bwQt\ӷ!D:V(7e' mAlws+x6li 鷫4Gcr֏@V $Lũoڪ?lpj4ntKy203 eKiCL4>?oU<#bxTAb HD\>t5~3/"gi |g*ؒh% "˒/Bqz~G);Th '鐊{Gш9d3GkER&t }C+04`vql,52bqEg pJMK|Q[_7i+b Mk '﷯gxJV:>1h<JAOj-am'@9umZYCJI v6TJXptxI_veOiJ4S+VKzdіR}{y͋ mn[n/pzj^ݲvPcQ˫)ʤ;{I1Vocymnoc3n/+$ QDu[%%YjB*Q="_W]!ӒPp/I|wם"6!|?kDNƀ(& !2T5%@@Ȩ/%-g/B5 LJYr`}CB.I}4,}NY6im$ ȝ9)l_N(Ȩ|ZVZwcN8zYFŋKH=AY* TG+c~ W˼7=k)dԙ|IJ,|zlrl'=NiiݞV$t_`V6y|p/d}hBM˜5cPJˡP \7eM(RW=^҆mjK4 9Kd~9PL Fn|v0,EO߾$N NV?Eb XD]/GrBU or FstMx䤄4 NGoӔR\^OͷmG=5i, Wdd#%Hx6P<I&Q/K/X PRO:/:}ZY&8Yً’Jq* %MTLFKHTYPP-no <C!n1(=C=aezj`J $>rwWP~zώV,;F_:.IB/'5Z󓵫{,z#ul)' {T+u*ct}9WP&k`h6{{N*ܾ?YA$1DuAR,NF%g-ACdADC~$#G&T|hyD{ia#@7-V9{ž>Y꺟 f6OK`'AWy@xg{V8p#<`ɦph$$/0TuŴdMEpYDZ(VW~p;$?|4hVv+p84o dhcvp_er\ lJ:}/Y5nny1fq_FhD<= nKOV{( N!=2x_ZޖADW0ʢbHSp$}*No> E74߰TϬ )զlIQ3qhpkou{:Sy+^×l#le{K4*&S"'rn (ʔM顣>/,U'w uvam ^R2h@5B[ u46A #Ad7ԅ'BNhY':6Ba KS@ -X?V>LW]ZF(mέC2=6J92OƩ44u֔Ory΀?*\$OV=C18w@rT zYf9sO훐M`վ, bj.e"JCAWٔcnj59YIwyb+QYRUHIc 5 %h+`P*H!A$KfOMK/zbw~ۻvW2J7B]WP8MܠJ$ٙ_0#u.{3IE>Ϩ#B=B*ԩhD*2O]@p l݊ipb}jCuh}7BԱNcF/t[ joJ)UjZNS8Tl΁4yyv~'Cܝ$DP/ k(ЌEUm6>%6 |9 \5OAUM;7Rq ;,n/ w]Bb2h$FRꄎTh|G (Aw5֠Rtx!$Y&x*Eh<",4nQ(_a<2\T iPlpNW=ARuEjJZT`.Z2qm(PZ~,}l_;YY} j%,_)JQ7MvʯC|xa.Op +NFndaه/aشl4 ȥ&6XO)M D%v ug޲rĴŦYm<)@Tu7ФtsJzmhM'^EP-?tYʺnj_Z06w&`ےkH4p:"7G?mPAVBnߴ WL44P}ء}˂UO)31 )8vUr|*W 8юxKºh1)w??4~ζJAF ll ڮTCHiLPm?CǎLTs)axP*}gHu'Ð1##n˒rzS+D i|tdSꖫ60yVИ>Ko N (ު.ECk9n+nmي$TطQ=cA ؑ*8ғڳ,l-!~oK_A=-yHѰe%IyX}PC-ߒRR)sIhBHx)딄U 7 ,PzIB魓ӻL<,*yBHmBޗTmT(V9r2Lhgrf)fXmƌ:yiZ-TKuH+1]jޓ#)T%o߮ @'QCP Љ L{1VjvcLݝw-oOhvi61oDQU f#ôq͗z%}ܝO>C/g~< MmLW$ IsqSܻ-Qׯv~O+ZUجū7* @)^`]@4*Ը19}%^@)N'CqgzdYY)GP[(\caUXb ؝h%&)3K9DU2sQboP/!n&);x};շ(2郛ߵ˜=A]HUU`)>c0T&8™58 m|^7D#Tu G*S[n'J-sZTkb-W\h}Uǚ$vs(vn9e 1_ɩ, "|nS=vB6YX-/ HZ33Mkq]~>7 B]mh :ᜊUCF.NBmi'p=DJB{ _q&DQm(=@q\?+K"OKئ~?x]LoE4HV1U}RfsBEAkm*zj$' UϚ6{j.R{GN0)Z#!F'Tx""ߕmaltI 6d{NR'/絑CfQ$z⚎Qw,{Nqv2:bAv\AA$A%eY&9?3y;: |= +![\^F Ǻ_uڋP)uRP+w߁9dTR @V+}v4}`wSD#xZzVωf/HbP; |VZn}Q?ס^vDobЋmj?k9[>_j Ő]C 9$FVi ]B$}6NPt@cr m,&V5ɜ Fm h [_ou P+e>1ة75Rκ ,5}9]_K܅gt ,Y6^.NP 3|(<#+.|Wumzio, xN%7?GWGʻ֡?E*OU/1YA)%McHj ԡf 7" SG+D;.4WأM>b 7hCB)RvP1iRgӺs z9&.46=|s>|0p}ƴ94O\7BZe:}ڙJ<0AD冗Fk~ӇғxqD16!QAW׏)%~"<g:7svNosnp+h|]S`EKh-9# j( eqfxsq5i$XQ-椯Ζu<7[hH詖U&q<}-=VQBI"܃kU~NElsܛM̵bFY͹pN:W5bn@՜/)dH98ȹ멫ujN+u$Be0DђTVyu!N)fM5e@hk,g5zA9B+ /T8OGBMHPj_oPW{t l^_fjZ S?Yڵ}Jo jS5!)Z{M_ ] 58 D苈3vN8j'9~7nm6-~*$o Hʉ )P 43Kh6}Q 7My=(4Br ` M~nSAsJA1VGk2ew] ˞?pśp22S& %~[Ÿ"!jKQ'#6$j^-=X7<]Ġ7[˚sMDZ+Sˮi-Sn> /ozwJt6H(JfB^~XOꈻZ%PKMFF8 G4K->B<_32i1AvֲXFTPѩ>Y2AUs'#_Tt\5"lYl3ok 37krpQ ]!-d R8%&]S?|oɛ^lY,0 L> 'P?jQ@AlEg,*1lhJdnhWwSE K֝ d(O:=4&&]ڍrrrMD:˜+glwޡ/jaw!E8|ckuV *m ֣_/wfJgHVǤbGC {l׍ePg )IX]/yTT0 "geՖЩai`VܑKRQc\Zi?MQ?ͺ _~@qӒyYh{ru7 D_uIjPCjHz't jj$vMkqlK Bpi`?}uo?3 XvlTzS7!msWL@{UQ#uyuyKAwVtJCig|Za#h-ᗆ;L> V2 5%l j(N(r甽}'p$mJ}-hglLbv 봄Sʜ0G IU<|܉wQ`$hf $Dp@a5BE X,us2@ǔ!>|fh/Bpo6V#׋I)kd#>wQ"' ZIȅvnnL\/l߅R+"ﮒKF}xvҪA[I<% (,7~O{ݦa.DvߔNEфェ68w ,vłlgL!z]#^ Hee >j/*L8מPKUs}_o )&*7RKRi]H*JMs$)j(𸧕I˷߻;2*4|>PT%KPjWXCr8RЫidծP% OmǹM[!R*ѽ%a-lK)x[*y H=}e'X`ʕ7fqci|;JsU˸PU4iope˧t~Ntcd<"'.A)PU:^KHj[*qPTa`|T)?cr%O'o >|rD&oSFPu-x?zaԓ>6*>߾*/  5dQP ōEa~w? IeY9Hڠd'ݞ`3͘rOSKPjoR Gu ]C"<&̞dͩ>>qG;͖ IDAT垜XjqeA/youb2!9:#v:ljK'TH"ʘgT@ Kxop]#RND;(D< +6A&RbR JqY]ԀT$mQ{#Ra2]Zw,{ '!v&.xTRy1 '~R _m^FzȻj~ZjxU&ƽ:&LZv*\fӧHt,mJ#??*o|oZp1C Keܹ^Wz")V0,cMF$L0>{=r1MOc$3 11R|5boп>fꕕ-VSuV5DߴYJ\ñ4NTJŅUWkTp!U2ڦdJT-qK9ᠸHk g:5͙z|d uSVʌ)]tO2LFm6XQpTgo u!1^=`B X[ zU7c0eγݰzYm]&0J5ߩ1=dЉ%}Zmj>LI:mHOD-Q|,Ng_dKB']~gvnHZ6u"-ά_%^W.!/| jATLha\d,D-}hj3X{V KPOJD~,Y9єiRÕbBp=ȓϙ%*]=T|r7,zHSnNSDOKSA9S:x_!wn7(PbטG-CZnh8pp0 0 qr(5w&97, )Nuxxl|+BAݜR+6)1[ sS g`Cuݔ:ieo\?oji_ݑFE !(uU1{M_-n%9v\h@:ԡ 8t$ zTi'~i@sbXPN/qXJn6^Ab2փI<^єK=}NkGi'GIF݂zȻřÇ{NF[\,T"z1oP8N!ΰLb3*Rت_]zRxd*KzLAMzfmӃyֵYaʌ,1IM`R?MW*G%}2rggGa)61޷oVd%1a!ĉ8(&!;Fzu WHik疌2!vTKM-\|}Pem"-3>u 523ʵc~66a%ꋽ#o]50!ka <xAid$v`NBDZapTiY׺ 2I\xh|pz&*jAqaqV-in>35G[c_F2퓈V_/ClJ"e)d OLoKQz:ںФm6Վ;ХrNp׌ ;_r5a1qR\rV,7XJORb΂z%dC.T4')lhcEZlM DՑLS4B "藘2eX"L  1{ISoS-'.;#6KXvSBlM'bAd"E+2 , ƀN)yOfLV A[B?E%~Dv҃' 7D !FDז*u&Q1_`. ū%;MNPS&a㈣K5QSl;]n32-B8J_f! a̡|K 13ǾL9}(DiNI@CƒСTaXʡȪho`݄Jq1ID5 -Y y@kOe eG}2j @I^s.YRd5gcq@ܳj#Dq_pOF <`&B ci /Mpַ5^^98 H/2JtYti@z!jXZt%&֡%> 㓩6V~ y_}VJ5_R2 w RfH4"95'L qOILnqʧŀeH,g&D(W*tM "?ޝ ʡF\t)褕JŔi',M+noj2JFm5AJ'HY}לwXLM刦DTIֿPw8"jdlDH:gY!*z X40q~`+k9MӴe{⮌ݜe m΂N"<|? εԳQ:]+RCY$w齆f<+mˆ,!^zL8G{}xJ}d%rS .<Ǖ|hI8e4/u%g+ ՉLAiیB%_7E ) %S~#:Jdz jEqҌ_nW,jIoKswӄJJBaCҩ#NZy*,?Sv17坛d$ۗ(êйÒ=慐@Yfj7ơPBBgF0;{s̈́y  ,LQ}'m ~x)eH^oWgqr=!6\ |1zumn7Zm*q=}/Rǽ6EF'7KT.9}I9\JZJP*Y/3xyQA-Oivy@Yl=82Kܿq/d&*Vy`v`k%:g]HkbkfCVR^:twioͨg:{KM TeZ$%Hj9Mq^oK =o8hţ tS2² s$Q@8 .95)7&5TY][ֆ::/˂HRG;&)e[5p xlUU,Hv^!8{7q۪_)N k7xFޜ@sCFc$`d228GE) eD OZ~R#TSbx?bEa_iEf"]bz[ƐPhcQOF6ccVԐQpRji,PJ. $Wҧ?wкj(ݽlzU Be 6 #'dT=R00xYajVQ:)1*)3dA75I|skdi(7%MNFzm8?g[| >wiOxaCp|y+QxDݟ O)iLu_&MV*v\rSEK6(,S מ<Ɛ%nnϤ.)v';\P]L{="&~ml,Wj`04^tFzgL/ݻmk8+옡Aw{ my~`zIA<"AXzSWIHﭪG 'vm!oxs`ooSL0>Wސ*?5{KB;ЀZ~n m ٦kFqST%A-:5oj-_7x^D1yth۞Hc>V_ƞ#/O*6Է1|ՙ,XqSs߆CT%P4%4t,L}['7psTЭ ؁iwX>L n!y+-.k~f=Xnqkwi b%%aD_9FpnWxxm~dخEFm&2X&5a1kG\׽G=ɯm\W"u7Wi#59տ_ :98^}={0wF9)p SHa.e\e"U{,||{3zw~B*vJs2`y;qۗ\t6inrRbi%ECYyg7i~[E$1*esWG:9&V &gL̫JBK*~c{ndǩңbu.}^DJ%vW0ٸ)mJ-PSae#33i&% Ȓn^dGBto)NJo4ߪ( Jȶ&{q0YlspLnW>ѿaei YuE0\ lX+e*xtMe3zWwj9=<$7\p7P*55%]^9a7%xWQJۈ|e~Qھ̝X2VR|l\QJ` KcyaJL ,E &H~/7l+#1 WxLuQ\S^݇"Q0է3ׯavw&_.tiکuC@sWDyD`bUV i'_q$dg?_- кLF ^\4GtFBvsPb}mID#v{b+u9\_zi6;`2+ҁ!} p$JKb|vag`ô,r{S{v! )^5' ꜥb ɞ6 xoErµC` JNCFum#zbv J_$3^9V03MI5 J<:D|1D㓃%C>57* \#$$ \2Ƞv D|](ndcYXC쩐ñڣĴ7b& \VnMϓc는^w+/ zd9`<0UrpSJn¥Xdq58$:Ls.|6L6v$cAep4ff+mLfz e"t)׉S,X&pʚ.֌M!L@=0CB@II#a1 +7;E$C;Dɬ\EsT"kfU[f0}epc]~)m;I)Q U`RmaQ2tSꪸ/fi2 wqs+>Sr|R<_Y 6dC.|`=6}vF/ &KsZf=el-eCJd,]lhlx|_&l@q7wͣKcq%N5{jܕl[7m]cqMR!o.w{nڹ{^ufH7Rf(ncxoQG_{:k6 E\]j4$^%\kfwbPrr%6\E:͌b)=əƑF#K 6IfW-flom2XeI|' Y^6m̓br:! (, i !vUC5w222?$C<:O#`H觼eddddddd@!Vy1)<}FFFFFFF7YWlG+L232222222o"d"1 2Șfdddddddd̂LD322222222fA& ьYhFFFFFFFF,D4########cd"1 2Șfdddddddd̂LD322222222fA& ьYhFFFFFFFF,D4########cd"1 2Șfdddddddd̂LD322222222fA& ьYhFFFFFFFF,D4########cd"1 2Șfdddddddd̂LD322222222fA& ьYhFFFFFFFF,D4########cd"1 2Șfdddddddd̂LD322222222fA& ьYnGFFFFFFFF7ehFFFFFFFF󏿺n݋}t?峋߂9ϾyOo?||#XMF2+G7 9܏2 -l56['gٻo֙[To)2`|S <VM W"od6`)b|)@f7X ]_;uu^wn:xJ {tCQ?Xn5VOq*I>`\ L˴TY^M=q6r3<oEQ_f8"\`@?nwE콱f +jr7c ,Jj ' h (2y"c+3cՎR)+MaMEl!i0i Q%٫ DjՋۉQV k6NOpצ6 *9}XDm+]ކqlL99p"Vi-6TL\pF5)Td"ɤ`ND݇X_'$#+?x;>Ŝ\O=20*PBղAu̥܌/1x23*=.Qx,FSfx5{qK m0~xFYJ6g8҅Ȣ`28C/d!ZD`JŤi@YEiUtPCw4cD53˙ Ezg)i70|:I9a"V+RPFA-ɍ8 Jt,SkjUTPљmw9p.2x`5.鹀2 h5fIXuY){&1\:OS:|-FhHLZ8 mE_J4g3\&Oz+Zxώ-I0w끒 z;nӡ85w$ Xw=5=jH(J2>ߵFꏻO) L1A_N36Rk΋|M Ӈ_e>;^.Fup|jW-4)Iovd`3|z%a<ߌ L; QZh%֛8Wp@VxV!-fǔ'P }LHB:'we}m`ULBJ\eiB.Às;=7p/l6$0ֽZ` kjگN+O=$Ʋj*4g#Zڊ WE,Z%<ݭ*$m:![y%2pA_J*pl " &c0?r`gqOk5w(?-i)}<0&D.cZ{kK *fC_".Rz< uin+:y.`iXz}<#< -,WZ($'/mi5o{[v6cOKSy<]zԳi:}Fp 򬮶߫9d٢״gTW~l7W[ɋo߹>#VeRp>:.صP`tD/s+ a2%G*f( >WdzU.Za"Vjp"_[fJ9V nZBRtSksi¼Y'(:-[[_Kv k+r" "6s[[ZqRki`}FBܨΥ(c;8–ڙЅDsZc%ׇ' 3!"3 ~I`-#L~,uh ռϯeus  _]ي].k)+ɲݜ5Aؖ؇^`Z#-R&-dp? -bݢUN$yU:]8R1DSfT)2T<# >4Xe"S;+VxW<}u$D*C%[r8&G'%zoZ+VW\K[P=P>">NUxfx1s@Iˢo,[9WsQtF|-ȋ̝E Кq5ޫV-w_(f3twx.AWr4{isdӥgK:*^^-Z2}Tv{S0p8;-O12(}W xSu,˷(k'|ƫ}͓#'-AE_I{TF[>Wʱ8Xe>^ F YDVfK񪶌9[#$ʥ_Z{-6)DFs9$nieKE(~zSq&Тz*!ZFE_bRqaTE7[f-VoXw8`@d>S; 2旟7h6=Iph&@Nػb_~<.گshEMS! mh` L:'!Lcr䵉~>ʖ_l6e'Ҁw2o.8C8[ 8© `/`x%{ϗ ٦WuL{ ~")pqDogYjZ+V*n8 7Z$%08+J͊ i5f-mQ)x-oTU_J}2Mݎί&6"o|θD<3 *fэ_7oHQS%^2Ûts9iJ.=Y̝阏b{eŻ_/|ޠ'_myj\ފb"|*sB=vWRqoWV\cUm_' hW)<4&<(2˯uWxֽ{Q)gԢ9({z 6<`|$.w2NU'q`fw "MJ"@dd_%[eV!/DFv'W8WU4^e v?+jOAcmw?W>P`^ic30ˊ2ٓ mg;3}l%@P2LJjM2$L@d>j2}>=|\{8T13}r7W#3}օ7Ֆ1+\WP W<0bD+fe/fifե<!KGI:P$i^hr^jj<,~ -erlLgkv3t[ߑ!7b߈ܳ~ׄS_B{&;\t$\F"t1J)?_;-E7IQ}DcCIdZbqJL~^8%Du6 >Cķχw x-3JǮңQVS@/ŞWoø< Rd^3O&+9Y(3VH D-/׷"H(7$GY]e;&{ZTn%yq٧i[PJ4Jc -״MizHJ=RqLݺ㵤n5Ah ,SͫEj7үUB$Ok>wҭ3Vyzrmde\Sv(nŎYcVuLlTmh%ܷ<n:4{2k4Kd725Wv7+Y!Myr!'t&~wruYܝg^1_zc:htng,^ӪGnOrmZg- {mzl]Z׷bvnƾ)丛)[T{_19 kUnrڞ!`В~mGo0cp[~heb暦)}eOJin-0~bk A6^SYF<)}il1*k$dkȟq!>^CךcnѼ5O~rgh脕5#[X&1\m$ڴFZ1 ,bh ʍ6-,y(uMJcH -@z ـ Le@XL(f)fOtuUHFNMQz.>ZxM~0~e:Yy0kMdŔ֞QǟߝΌy̓wG,{UfNNCBN(`*8PG+YJUֽ5}ͩw ;+\7uOVBz~W_y1ajyן̪l2ЩOj (bn5xJqX/@%?>O=Y܋i<'h"F>}g>"4PMr1{5>N}UI).roi2O0~U͹.7Q^4x>XQ[K HȬ׭Rp=Y )A")S 4<^6t,})bGꙒ?nM_|`f&7|,/=kǵXW+̓p *߳=Ty=#Z,_-}F~ћ'uQkꅝUj 'ϭSoP MkoWk6QrkMT}0%+Cnʍli77T~~2+jwN>x"|18uVYÞ#,m$8{6dXL:t'^j\l:8`Mns/-ʳg]d7K5z4OHUoDIlmF,H.۞,KU QJ韍#*6}]#1*N ̗Gs3PẎnc5୶ 9le-=J?{m)t1Yy%6 $+%ӗkU3EhertÀ֏$vGVFFyel)%yxO-ba^M|kw֠oZCZC @D$]kI]ʧn(5,]Rwz<t+ft$X=Ap.j襲˕onP/srMmڭǴ}bǬ]bx;m dג6Ս]gfOB}tL[r#բYc]>NԿ_wigvٛ֟Μx {h٣ep.=Q~WV~[fm&R`#Ce~5u[W5yH5, A5v-2ZwK%1*5:ykc>V+}DWl jV.i`C;9.Z ـ Le@XL(f)fO\tw1۩=;nپ dG`HdE"#8N=WK{`-7/"3'B T.Ĭ13i-Ln$>kDؾ!=0Q13ilgצߔ-2jX]Ѳ _>fC跦qr ,lNJrfipga~XX1[`"\Rdo֭)ad)f_]?~-(r<$AWdv;W]vOaH 'nN P-N@<=pUp":DF'ooy*f!` :E<>d>ң~=k~yw&VIo.6]^xo1q/2n%2rQnd|c9>Ch`9n.2skoG!pi[MObFkL{^^zʗ76S%_54}eys7g>޶X?T9Բ3 2pb6dL݊5|. |GdOT3N@€}V??pK8@vn)2$fيl(]l}#}"s le~a#z2Gg.dbDTfDSfTح{?An-]B%qғۭ4Xeҹ;POffif& fOۭm h 1Dff)yRCb=6qMP$! O&6xYB?6 0'KXTt\b+_zE_}kRFC[[3ȳ86 4V_OQ=O+%h *ZV*<[㢆]z:¥[7T|mSN#2Zk%Fh׌ /j ̞/3$4ou L7~Miyw[pβ/JeXN/&ڊ/=M4׼ddd*QvA7JkTeVX(iY2>2/yiwj!:ڐSp 2pb6xN+(f@d"D 2@d"D 2@d"D @d"3DP&OSFi9TN567x}7WɫV˃'֦=5ebiTi!sά,_bZm+~BlEԕ A>ހi R[S]f505 0Tk.3fI(v!k;exG."gPpe,]db]m2z1`]MTYf4[ld,QN}҇ƫ!b:YM; {[Yjd2y(|p|w"Z<̫^T&t+.nMT_bW(I_]KPj:$/pev o۵". kO%iZX>6>ΖyjW%m3UM>ŸXn!Jc)l^z) t+#j|pɊΪM~q.JڷҬVlkWxjW_nD g V @d" @d" @d" 2(@*ÐMI,4lR[m`8$,)8nZ~)f[z Y9eEb."SBC[KYE,Ě0`o:H4WhP`6uQϙG2y-}z"~ɟpoֿ",Pʟw0"U(S @1 G1'qbzfVIhBJX5yct}\ֆ^ PW $jy@.e^ L< Ms9}j ˀeG%24u`0nBꚖn C NkQЖUI y-CִUׂisIx!8^?ydakעhט}sli`:"[FËV`[(7:CHuP.pO-tr߫VO0pFe/2pQzL.+sO)yuIt3+Yu O[b&;r0>̼W79_<1,jo{6:%FKc{ȌG 'uǺSDemyv 9\qNKU[7xWwW޺qA_7}=L]\c%P?oQ}Qp%Q~QGC[L+̬kE|o(<ٲxڌj*ۦ4i2]׮[7 GrZݝ5Bi}U15wܓ]y@d 'W1"23IқYNr pX q7Zk$@yC]s L&J&uS<#Q̥pL%;cm|[HjOk~ vw! 3Q辌k4O( h%$?k>JX8pv2 z޺a͑oel{=֋O2T_,F@ۏ^kW/F_5<屮ڷVv6gיug \Jdhq#=f0O@wS:1tl3 2N[fL gx3[1}‘?;U_w'Ű5I:&YYsqDmwOoW̮ \%%pF]v/RI?0צ*+ɓq$}"',:bL˭H6 Me~PQo!jQj7[vo>HWZ=dϡyS*.Goox+Zm_R7R%kl *4'U_qbub{]Oj]Op`F(CE&ޯiZi{;۷|]Tir]ɮtۨᦙ fsl-&umzdfCO)Ac2}-"DGeC՗Exgh@d"D @d"D @d"D @d"TLzXriN.k+3ZҿM"/#I;r_9d=09i1VD^nR UƎşJv95ٞ3[/I+h jE5Pc6PFBLMHbs(fɜ"՜OzC8_1; ى M5#)z{wb{Lǜb;>\olO 2s_In\&rd#ZzˊCrOM;(R{ JR.Hk\}3[ֲӚ iw^(J;6C?Lm.S,ʸD&yD! =ٳ'չaY;|Hݏ^wXYLxKvZ ں q~+O~!)g VDY:v:nVw?^b>Ktc{bCnw_,ea?ZÔP]#RZA̤7߶c$c*~i#+o+|L;9N=) jeuڝ{ݽR)iVx֠@ *#21vIOcj2R$pUHbG|b/QLgaDnnKZIL["b%iѐ*#Lf^𖩋Bv-Q)Ѫa_>xd&|sZۺÆi^)N+e7PF,ͺQ'v\Sdh{OБ)4^.\2 oɍ)"jvyeFyW4rmp*ô}_=|5弝I^ԍ7*;#"ş J\ה狺\﷕NWD 2 @dD 2 D 2 D 2 [!ƴaej 2q p5ŬeBCnYH3]-tm`@*0[f'oξVԌ_O,-ʼ c8g/H/Ӳo&[leˬ-~y ?W;gs ׌*7r`bvA/D@de|Db&5mNltXek %EcԻƕ"#S.`!1GV`-~? c@<G_W\P8'b- %e͊\ -6b|Diy=G||~"!81bC[m 48θv<'"m^OJ՛WaJ􁭕-7sm_=@lAcc13aHq72,QvMg~KKd{k)V/^``鼪R_5, CS=jDsMdHj 0711W?~r|hsts@{ZĄȹ_cVy_b# :&O놖7~,~Q%lOFhާR6ydʷ1+v{Q!"eʰN"Yϡ4=5yRB=-\֭3g5ʢ7Ws(ϰf[ Ԃ9ՖϚ9b'18o/MT4!X_RT/qȫ ūȃʠ< #]*[hqC;8x8Dpp` 2p-A2 2 0bw BVD%maݑ(fE t Lbx'Ʃp*D 2 "D.!2p&cL!L/Ћv*9>Qd ^P%ϲ,-?1w#2f|aZB|7]pSQLrsw # 3E1;|+YڙZn/2L/gFo D 2qHΘmǔ'ׇ?94͢ex5%+$ֹ#<p?F0v&\hr|\}Fx %FV@]jAƞiwBXYtFunqGKn-^LΔHdCIw.Uv1d؊죌~Q[e\ &niPtnb}T[E*Cy?ZwȾ}2uck<Ɇ6ڥ$CK /{.1[yPN*Ԭ'cZc42uұ=ōҋU_ 9КU/&;fQcPTybW~ZQ x}[}_y(I.­HYNc[p CN9=zDR k];֞)' !/ڈk݅>+ה_\TO2f<.vG=p:ҫ0&גVkůI y-sAGgv|tSIN|Y6"ksG;$ܶeT/{y2sS^h9fkyzXwsw|MnG08 Z֪F#asY7?-I_=u+"j"9jFkG\^ӤO5.ifj Oo5Y}ts#ө8Q}絕Rん(}z^qG=h^9)8 >񾺚ʉP.-ȼ5\*Kz0G?7rb GmY{l2.q-9n2Q\5*c_n{u >W^$S7aM5لDa>J3͠a;V!9e :gð~э܋ t1`90Nښcϕ6UN0 '͜runLgxz'X~֣?sdkS+66bIސʢN>޳wuoQxOң3q&ozԛgsaN<9ơ:xB{:@|.~GtzoqjͧF_W5%Ҟe/՞5Xu5{71+FR Ws桟Nu:PD'y,R#98Κ ܨ=s֟'}VlF p-pC 2@ިƯrkyq2sxUzW*Ą'#uBXDG͕73` l 8Ld`@(fwBg2 @d 20ct̟?`BK,1U g_ud@-_o:^ѰHNtIME 45IENDB`gxemul-0.6.1/doc/debian-1-small.png000644 001750 001750 00000007243 13402411501 017173 0ustar00debugdebug000000 000000 PNG  IHDRtc}6gAMA aOPLTE} t  ikwotoqtev x !!!!!#"""""z###$$|%%%%%&&&&&~'''((((((()))))*****+++++++++,,,,,,,-------...///////0(000001111111222223334,44444555566677808888899:::;;;;;<<<===>2>6(>>>>>>>???@@AAABBBCCCCCDDDEEEFFFG9GC7GGGGGIIIJ:KKKLLMMMNNOOOPOMPPPQQQRRRSSSSSUSSUUVVVVVWWWXXXXXZZZZZ[[^^^^^```bbbccdddfffffhhhhhqq{nV~kG}sl:r #/Ř˵פŘԳֶ/MtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxڽZ Y-,#-%b )`]5P0 S.-/ kcf" tao@hFp8]zԧ>{K[3oGw4nҕ+/ܸq/ܸ7^z1C~g'p`}K۟Ͼ;{|c_{퓿}߾c?Ne?Uxy׻9_ȷ}X? WypcJ~7A_w5C^?}Ͼ3۟9S_}r{WN  B6a$J&}{μ>|EU>*YkR8]l:8i,kA( .4M5v<|4Ե7/,.Ց:ۗq5槱ꤽgEⳭrEOcDd s5PWqs뾰|C-;Nr;% Y *K(.F1PV@_)eM. 释a9N@G& pBhQS'H$ܻ,ɴ}hX~Hy_խUSVީj5|/I @tƹ{&mt^[KwI˙aJ*@ 5sX4F Y d>ټ-><-or5TsvV8n[hoĀJRLB n* rpw?`,ZYj];Cy,LoC}w>#ꦷx٫=&gil?GLki뎺EcܖgtYuQڵ9*Qj0P(J)%J@_)ƺr ٥-k?nVEw㱪:}qǏ$mP( @B!A/ Ҙ*”P.I H0Dp0VwnaؙFurl1XY"Ӧq0 RNk"7rA)t[jz}Da;i}n 3A)+o$Dzbc57^&&JQhjFG\t8qmd Wh >\lḽ>xO IC1ʸ|9x#!" m{x޸ղɉy вyw)5"s(e 04hEMͤdK(=гq&>Dzd•fn?сY>F /R^3 DUK{Ni&Vx\glèހxdׯ_w#O-.p-^}QJ`W(e"Q8(J㝚WWq=O0.4^c umObrQ N`[1o˕-&}q7+7X]b90 *(`R$.A&5K*JJ7e2*~c|Y7:vZtVXay̴p4Eu!G^mBKuiA.%R( R T "ۼXPԇͅsuul0cKyj;I5n&J\Z\Ɗ1~%5Aػ S>SԹ3_@5WՁ2P_&;޲kh6!PSib,&,4'6A@JSphg&n*h1;=iY=.m_uM~qfmg #I L{Ԉ@Ki @6+;~B֯:\x14Y櫨keYvTrEj2}'XǧTP];9eff} /,h1)ΕV$sCpcxpR9#G9QIׁGWk;+K瘹57Dh9Wz>s@uvlCtwxg.]xc/^=Lٲ!0'[u0'`0l׏c(t tcmjj]a}*A%hȇq%:mQk'MQ3*2`Yj-r`1*zeN a&ѻD}ݥeqwo)OZ.(L0aD):,q5k`9v_Xb0-v'[{ӂ.l/9p#PwWR`jUm1T*W(OWcha5tW)(U$q춖p%iqaB]af2TJ &0tSWjLr]z˲_c)@1x6*Ѿ7ն΍(s u|$ 4C3-J)yʉeHL>rw\.c]}L-X6e4͈.*ada8 B,Q1M\3|㸢ԛtIME  ]IENDB`gxemul-0.6.1/doc/openbsd-pmax-20040710_small.png000644 001750 001750 00000011072 13402411501 021160 0ustar00debugdebug000000 000000 PNG  IHDRtc}6gAMA aPLTE$9pTd9V! 'sA8 ERj,V'n7M^$3p(A++Z---37~6J_w|pq{x?itxwa$ݽЧ|8m寧!ɎXQ߾>|o_ 1Mc$]_ u|-H0!ianx? Aojۦ*=qcrүjͯ\hsSU&/*8/JυyuU~B.9qQ7O Gx%oqJ!ʈGDqw|G3yh^ G@~e^¥K0§Q yqCeɛ,Q4HAKOJBK]];zBhXN!mJϽ0nczΖdOQ4'%gxSkW_& 76QTUӨ̧a^@U yO VkyN{OnB. 7Ur0Z4چl63 #=Ifs62{#([YK Pt*e] }c@ZncQlmH 6XfՏ"[7Rqgd=אC)UȳO 7)cH%J"L`͘ʊNJ3`/NP6S F 9T.Z_@0AgDUX+0rk ]BsחMɼ?B"-wB5W@ڮ;A]$3-$h_ tUr#wڼ\@+<@yCxQϝb/r% KrgYL#̸Mܕ'Mc[Iӿ-`0[Qlτ5Wμr=E蕋{ -;J *L-̕Ї=M1=ÄpAGSH,R BY"")@tZ!59O99,!p-\?]!>P̡⶛zC⬊1N=HbVIY"I+/r$fqKs;c\i`lIbb70S)Rk $%]k>,kM̠,0&{–бҝ.1(9?^7i |(&ږ%cHH3/ۀHGY:p\HC8􈘹DwNM<ҐgXm3yqtJ ;ʲ $͎10g?LǽcOYt`X#w?Kn+-1f6 &,a o{ [C/'5ŗp O_Ұbxf&'1H6R51IzK!Ж?7YFF0>%|>Wvn!:-]6e)VG̦NQ*OUũfe9-B@l& !AŶ u--1M˶S5rSRTz .^!q'B0kXnȼ>>`Wݎ%3дʄRbj@d4$XzIU"PώrAcqvxY17y^bɑ[?P&lrz{ =Oyx8Xt2 ߚ8h*X`R()/q!4O!9NZCSb dZq$C€d>2]s1j5-[6mS6DPY_l[3{L 1K#kD]ׯ(?zѾ8g;-Cq4a]M0#o {ew3Wћc_]14xjͣp<'O(t4(HbFyJ~m^z}b2zW}`a 5.7 Ygglb1MUo^ѴLIF 00+7 &Pa$f=MKِͩqI hgBƛ8#YB4U | Ia!D5=23&)V(Dw85;Me \FGk^դ\RglyE(yQ^6gǑZ2 T7Jk"eBr-)qzegH"IR Dы2eΫW̚R03`` BZSrC+3nJIOƆPr%1-5"5i^ jdkM#c`X=b1kzʛ,hcEcVouIbAMeU$*LMT19ZDRKKֺO,Aes`S9.6ThJD=D(;rQ{͑n Q3Gb6edtKЧ%uث ){U1]! ]\z$9@Fx;Klg(|JI})̋qgswʰ@C!+ڎ2˔!D Dqd<Ĭ8R1hYA Ab:fz*t R3ő?@s IuUp4B4|o-ʬM󺵆Lת#%}/5[O%:F[:{qX*M̈#kHbB$ѭEʼ΂Z"N=w 8;f:;+f3֊Gœ8i>/s#+z\6+P6XxQr,ܨմ+( zAW^iJ*Fo_oe>M+֧ U7|GAe}<ƢɊpvަQ2!O+z&QR>뮾y4ME݌[qT3x`acnK/ 4"]R3S7I*ә1M3,]]>)T3աB%>myxdKWߗ-/VTCJX3 ;fm*Oz,6]|ѶʌXH}\h:=M6r+A\Q ̛߾]1[~6:D@ [&]ML/n]wĦmg.$`7tW3$I3.a=a7!ԡw1[L#iZo|uH-16g?f0fF$C$ 6LSZƨq BPfN"3 =6`?Qd B嘀P,lGmwm42ZB1j_G#fv)% <ÂL[tIME"S"IENDB`gxemul-0.6.1/doc/20050427-netbsd-hpcmips-1.png000644 001750 001750 00000027257 13402411501 020473 0ustar00debugdebug000000 000000 PNG  IHDR"xkJHgAMA aPLTEUUUaaa8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IDATx}͒0o%f&yT @j* ]E~nKpd?me˲G$qKbOA A"AHDD$I?+y*"֟Bןo&}/??=]9|Է<߽ 7!ZF ?cG?g,߾!Z7&|uƪiFZo1WD~|"#+: h+T9ϝ&YK!+21[0DZpΌu"o=G.ۮ'"3Dەt?A|5DVK,ӧm*޳\\)DD!VepGmmgSȲjz^r叛#>py YK/"s#]-j/y]k̗ M=G_i$YFVh[@l{#\Y^SD`iյ|Lz-D֊d#ZH"1yaDE߿iٵ5jkr˽u1qǽEhs 6pc7؅#BP \SDD"j4G:n/ǎ#FD*mGw"}+"""lJnBDڟ;]=yg!3x tj"j |m8OnV gcB-D6ϕ^%ַ_orS.=onzkt'ʈS`'U3.=3^RG0MyTE4;a\Pj\tЕE Y Y zO7o+.6 vV}\V_jS?!Rx?lSD V|##BkЅzqL0Dx%v_X -OKm"h~A>@1W-68~qժݪligp`l/XGZ;,q~krho-~=݊>}3D>ϽH]7ZR\7v<'Gp󖀯#r3SAp{wDDDDv橧8pĻ|-n?O >>n?OUV |1w㼗D4DfV kZ'X}xopa |JrO7P?o[y.cj=c_Sƿg"j=c?gl^>cO2{9'_o=\/8r\Wprmb˕kvRjȺ]oh!" 2Q7\fFz9ijA26Dno>Ezɵ] )g0!"Ͱ 5hZcoX_9"A|z'D8DbCǰ1"\w!Bel`-9&썍w8{P7k[o̳=ܵt=zG^携ud.T.hkJط;<|i}CDDDvDG <[޷kwᐓ|c'jU{ O;7pZsrլ3"!GۦݽCN^i7'r[9>6?nN.>y R="VPk6qu3+ﱆ{ EV1ic`>5dr#QH>"B2yD 鈐Gd !B="xw(rxI>ڛ>v]Bq/4A󩤳r7@djpu2F{!'^h\ v]UDtgAvɴC^/[=č;:WvrH_FygW^{b [ܞ][xm.u3z}M({~gSM}&[_{.K^֞k֫=C'顾aA;*!bѝsi>zenK-ܝۀV۫ď2xY92ɦzD* %m)St3GB jϡUDlK\Sq#!"<[ߩ}ka۩Z\4}T{N{Wrj:S}Yw/aCK=ZGϿI..ۉH>.lϸK=׵`5<܈q.M.]x>ǥODG:.!ODn#WqipiX.N\ɫךd"QnDvNBw\~vǕe,{[9~Pb 9~DQ6&;rD^l'=J"U!ϑ*y>"D11е"{HFΜ,Q:U|}|+ѵׁP7~G׏%"WճsCx|}}G/yC?#)ozm<sΈq7/o#2a5)F uQ:INӵ6 uХ\D4+"]橈i_7D8Ww=Lj`̓<___Хk ГM:s%?5!q[,>gL=~%gkr=ٌT]c1"P&!~`N}=Vpq&:QjZf + "VWW9;xrqc鴎[Xݡ$#՟w=qw_j]7~YQ_ PvZ?gfq`#X5uN;BR~IG?Jr~VFN ׻+ڟ'6'8vb%掏!968#xew>@@Qw{Cn GX0ˁO97miܷ=|̄|:wU)"RD$5wvn ?./&K >{x}]}9KnfŸs!">~_"rlDՈ2>Ո"\C|yDsKs*\ާjRh}a'S>$zdrr 1{"^o/Hz{=+Jz{/Νqٓ'gOΞ=9{rS'gOΞ=9{r)ٓ$gOΞ=9{rٓ'gOIΞ=%9{rٓ'gOΞ=9{J#/u.եnX~sq5 DDGsou|o^]:׊Zk*[Nk:'ODrBЫ}̱*sWs;sX &dDj.1y2:K#*"<z nz_vPDDGuҮHGw|8"ŭFڳzKCoJٷj "l=A#Phk+׺غ>cj7H940d]­(s@-<횉Q3ju: =G,}dY~^_tB5Uu9{+CۃrD F )DJ"r"@GZ_W1"#<"UN~'sdq , VsH"r>!}$$]+rNQ] )9G#핞#B- Hʯ`g231uri!ݵcyc5D@ J m"0_;ו4IkF}7i'k]=l(N9kJѿ>Dj9w\#:Vyx2ꌶ$$"|C<οnH<U5֞mgQW R[?HYE#>'ɣܭ+?;MNS1DJ=!j4c%7z5'"W!2؅qT$Wi>Dqj52VBo]Dduzsىv1vqpS5^Gd͍_sڃHeHn E 4#RZ> V#HhYmEDwma7Rf"DDW-!@I]ZnJ6G4 2Wa1ġuhn3j5od FI ^a~yg6g߳~n!D#9C\;|_csG\wksCb"ē-7;w-~Í'"wCTW+.K[7IgUEv}ur5'+ݬqrT|u'[ʦk8{}i33S!}@߅6-B;  <,\7GED bhF`:D_9D{Ga!ju|'"b "aj=5 %/,EkUƏ 2[=:]jUV$.=WwviYrr v-Q g?N:)l8v:Sct-[}_GǷ_T~$xВ; ٽLC~$}hԑc|cl !9k|ُ{5|d&I o ws7^qק>j7戣H;twzMOD$V~!N?m>^[ql}׾.n_Dblʷ!ޣyYk|xVK_~oh}:ۘTn.("rވ=y>] vqTt m$ƶvOV D|OM"c5:NouoX U+{5W&>óL7v;al<)wdÑ"BYp;ʕ> _l)m!4sXlϔ3׭NS]úc;9Ak_Jp偏zQ*$"OCN2GTn-w#ܜ ޜ}/"]֧#Ԅ.o=9UO"48 Dtn>X xrgl*-9;]}"j݅k zL"rΞ1#5܇r+g<_gu?9!g^\= uRNϮզruB>;u5)=VwԵّ{D2^|B>;ƭL[ZIS|]X [gb9_~^IGܬ4~5 ćmވf">)9c xbru;DjC+"^;^CXAY[7?"jY0'O[2G!” "}Q5sjEY=G9yPj< ZqPqVz;"w#b99w}׫ bڀN)sđUgqB~mthDtvv/er 7=8vtz"]_ZkUK= ]v P;Sf8{w|~֛Y}]4W9Y/q]|=+K*^5~^wz1W˿\nEv]bvs'IumUh/GU{_"rDf {ڊ>59C2G{o#^ޛtiϮ;;cRfs6G(7g?r+0^Q5S "'gŹ;>u0:>9]7d #>PHHBTu7I~U|Ֆ1V)\ߪe|pig9"-xn9ENF7y]*D[y`LQ>>DZ;;8# ea9吟gɓ?l !jХ}d<i8;҇HDTԊ^W}$";5ՊC5Dr{O+ajů(1C~'L'#GjT?H9O:R.y" bSnBd;"HmxYCUk3C"6J|Ԍ"k9օ|vbpDf>9zu~gUM+gϽᡣn}.Ռߢϟ_gISmwc>fCM?r0!?< }y^3 ܜڷ=֭;rp#R*5]v]xs1\&=r5v8L455Ͻ1f߼tjm:~u"1i-=o! c2'9g5mԯZLtGWk"]]f8>"SsIӟ9GzK[#9?{"H~Ϟ~כ*ώ9/2gAᘿSNI6{"N>{ݺ [&Z۽޴V{4.v.M%w3_=ys/<'qq.UOȋq`MOXs.֛OgG_8"ۄ54>>#gGʬ9%ԢK#g^Y?Gz]eDh9;֚zt+a'"g_7_?Q% &G s].{"{&]kknʃYy{gODȬVODC Q||e{sv=V '"'3)9'K]-kMyK߽/ rt. NGg~U9Hw޼#"o[yLݹκT⾷ -z[߹7[Q?2 Zu.3΋E9j}wiIeǶ߻\r'-?5ܷ!B'mJTBY+,cD,#s_Xji?}h8I.7Uk4s\!.#eD|g'ݰ;.*>^ /E){?xfp3w퀠]|.|%?]';ZIǻ묟ɼy}xzt#=ŧh=mrc?Tnru)/>Iݦ/>d;}/>uR>^_|iv>n_|i|b>>_| 蔧pvx{38{5,Kp3ɜݎ3_E8F(p"ULD="DZgN{r9.S^g)O!.E8{[ٸIygމ+p.;&us*yHrryBZ2V8iH!#4'D?h7W4r""X < .o?։Ol[h׼d{u-U2._`:xW$nH4apsz@ "Q+bJHm}փ}nVD25xIo.[7#tn_EDJ@$;;ce dHZ압J/w2n5))))))))))))))))))ZP>e/#Xkl7{Wb.;c?A\0o7ts +4ډaKY9I""w8J;gyAP+)s|"*Ȥ?o+?)$_S+a5IDRD$%y'D[tIME +yIENDB`gxemul-0.6.1/doc/20051123-netbsd-prep_small.png000644 001750 001750 00000007627 13402411501 021021 0ustar00debugdebug000000 000000 PNG  IHDRtUhgAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDATxڽoVzR9 )4iɒ,XIMg6̴ v. 6(-Ћ(Xbz mvv'nfQ{&lKlɢDI2E=ͧf\G8|p>~yK.O]I ?~׹+E&97mم-3M5kʣ KSfIk#fbO+bxfV͛t~tz.}i'fS=ܜk /@qrHLJA5,:g3)~U,;4D &yaELmh@r0(tMV20h,Y(L姰cǙ%v4/Q@6SW 4MKK:tksrw66BtCq?tgސfl|ͳ:Os< S5yD%Z;{{oC`JJkiY?"gHy X Z=Pqx=u-UE%e+M3ǖQH)dQ~ o s|%*ɴy@j{ޱrӉ}h .EԵ-*fk`P6Px5Z5\q*y4) dJ=K"# -+Kaa(] l LR֎="qJEm5ݟ#xl\v-o &c1`uPcՂH$)??){z*2 00tr%*h$%Ր+j`>B&~sQ,0;wo pqS\;VIq}}=!W"|( {>ȧWLa!=F e%ZSoТ)zj'=; U ܮpt4:K˭b>Nvbxc8{u ywo{)ku֘@GjF2E9#Bh { s\\i6R! )Tz(K8<܇'4:SWO|ޞ KM4'69t۳'GZk\Qx,<o"S&T t#hBrj& F/ʁڍOuÐyXbPhñBc>iݢ:"^(K&-Ȃ\H)_֘EqMr:YFzt-:1d?F؂aoz}`a7X,S'ч C;+VVu#f I4{NP`$ 5d,'k?ڟsk}t@@P-`P$ k:9b?P_ 28+;׻[_S[me>)\֎8l] d>;?Oϗg~ɱ2qǍxpX'q_|ϗhBd98PGegk[gpDƣ`?;b $a|Ε`!O^e1Ȳ}FXca*21X' [Xp"uV`uddF(E|G[q` &C$' 2`u/ҽSN78lfGÉӯqw66 Vzs b`h |4oq|W97m6]7?cۇٺ9MShkX<NƼV0=Ś(.7Yzr#(쎴YK>G**Y*R )s4ok4>*O7r(N9lNOIbBt lIgy﫤z+wirҍW+0m0WF!Y}wC2ܞ(~vr1{7TYȍnڒ~j '"F~k/_m4kݔpm;'[CD!2>@'L6qL+dSTL藲0'fʹP}1U.̙qw6q"uC @Am&v -&mq-& so&%d0Pb; GW,\Y}aꋇÌ\l[Pl+8+=/_)zo~[lHE6m*}L3SZ\8To3iS_HECJX6vCQn-IϹ3L&C9􌍃:0\ecئ^4UswRz  S ޑ+L0j-Ua+\XJ)tʺ\,eXLcX{/\Vۉ+wg'g;B'] fF+7fϾ `-lRԩ?G;VjU3wGL;ƪ4jCE]byY>8\|$m" ѯPGFvvwv &}[&ܝͿL*`Rދf[<%-F^+Qr)GĨR 5<|#rL!4պL1>I(rb d>wg' Hka9`ۯ)Vʷ,f2> rcy[4!Szeݞ|çDtvwAf6|NUI.5omZuJGW?Mn܃ pXXJΖX9;~돛|(oHTyL+<026$ Iיao^dNG\tIME4UIENDB`gxemul-0.6.1/doc/20140802-dreamcast-bios-test3.png000644 001750 001750 00000373353 13402411501 021350 0ustar00debugdebug000000 000000 PNG  IHDR/sBIT|dtEXtSoftwaregnome-screenshot> IDATx|ulI4mP`F]q(96wF_y*(Q.;N)j`  `(]JN_d񙝝&4>c;;3g^~~xccD"H$ɡr:e +HQL"H$Dre;Bd> gX$D"H$YN,X(wnLPƐD"H$ÈahBa2}顴AI$D"HNpE /at\wAR3-0)sSD"H$qE֞^m 0z.]?5)~᧥u|2G4iGr.ێ!ssFG -1h%up,b(1k{Q,ǻ`d\-,;e3J~p`/w162,^y V(gb<9Ęx(+ϼETi`,v_ASVuQR#,\䳎5p m3nGs "c#yx,_5dx.LYx<^ *XE0ݤ(TܿE^f] H<̿v/d9G[ٸPJkN;ʼX9g7լ^2gV7Cm;܌+_x?'XJY\;X35kkoK w-up㊋N'L*ԕ`41rєb4=']T]ɺUK 2wrgϿ,]sƌҒ>R#ܱ|.2VU-f||spv+7.*! C/?]Kz=bt {+Nͺccda/AUnhS|\3xoeUbQvg `:8U:WpFqHyMw<g/#5K&u0J /˽zz*2ϔqLR:1:6ήCO2~x+Ubvfv/0'tyW{û)O\ǪJ>rOxiBx|Jif0u)?8+.: >xEn9#<>w *4߾oZ(L#D'&I3>鉉"KŒEsm̵|?`5 *gf=QR/Yw~? ?m5zG&,]wo̓9cm5_[܊_Xb)Ͻ훻YD}Ajty Ģ'9%cY,wD YtFx oBԓd^ t֢RIc'^7]3/÷tb׽QVXs~nh9-O^;;<4w$_7YdMW^g?x<i޷'!}9W`Rzkp'_|9+)/ey| C]+^</&O\u 7|U6U,`ʥ\s9+v_XzEx<:s x k T;%Yڏ\̧<: 07C upOY94U.9)kDKYb-Jeդd$UKroﻄ myƟ↫LrϟtP|~Snhb ,R*m}<dUU%/ڛs P^Tb=ɰ?:hᝯPdt!֭Txe~JT%9:޻̗g|pS.jP⻟n K[]k/&^B8qO0-)v׿%z%υ[uu⌿azf5yŜTT?S)_N%_/8u75Grs,YwO:k?v%'U/aA6?>g=Oe6|SRtwuusY+x^xu/Vp2?$P(RI nb+ۛ"wOY9_w8b'B~X oV,|0;w֞7~{"~W}Wŧ=dN$/M_UZ8~kbW8{y~rZK^?Pciwt[7ѱq~|s|d;_v?ʇ:V\~S g-_lf"aS/s篞`ΪNΫXʳԝPu+Uy],Z=mcM˟ rI˙-㉾$??MOdu )koo~w.sGW|Y=懙4̟$xi [cg'#%>~e-30:dM;:{{t'e풛7ﺐs']o/ښmJBva^旗G#w3r#BN_[w[֟3Rb74_ŬYKͧ|U 7|g|3 `żO ME'QJ.ShO Zla:QLn\r:FO:Ocef_d)S^Ξ>Ia.Sﻄtq?#k* }w[m}2BV3ogN֟ѻҿkoI+[~ʗ>V1_uIj9~.p1۟ =eth?瞼N;?QQjE,Z~ *y>ӄusy oWڷp-Mq5uGF_#e ]|? >΋Q,y솶Y+̟:z{ 強L$޻+tgHWLƒ51Aݍ^9/x ۥ+.:~\?Kޗ}I*t݅-=[$G^6VŽ~ ;9}m5_{1>^m&(K)_Yç[؞eYl1ۓtk+kPTOB4xmԴb NNYЃQ yl1j5x&3/怜CYg^#b';6(\uGG'.x;r_e<+α??lz)k==%yNN9]Iz}p۸r/b}9ym c,\MZ(bpTXI>˘H$?K]2rp[-Mbhd/߇ς%~z;/ ?#_ ;7+,Oqm|Sq^z sg?7{ ꥋO_<“gy뛲y7kߥiXsI]q0e {N_NxRn1NO{nf"Bw>'ڟo hJ*Wlcb".=;*l&&􁧨\9_^=Gҙt}/ݧKwNي3g z=LۡBfL88v9knO ktz&R(Qd/r&R3kgtlfznJypyo`"6ǷQyj'.O[rdr]Ǯ=Y~f(/={kOk60^9|W',Yg;} /`,w=ꓩ:4R#|G?}K_=ƒէt퇚ROQo`~yFVV/uF-=Ysx* rUŋPf]+-bb4I=ebZ{z)2Gҵg?pӵo 21k#J*Bdc$~'~ ,=}OOlmͧ0//C9X KkY-sO27-\KVit t.?Ǚ*wOPjЗƒE h@lY{:wRb覔-3mV/_*{d+HYój"_s0YHfτb}8^Rrg|l]K0vyyo%-xҳ#Jx&7 Jy-?"x(C#y>*+fU0e*m^C8tü}ϲw+kWZvNvlcKOp5OƧt?t\_k ԴqdXs~0g ^|ev6mO;OS'kotrY̟e4ͯC+._^|;Ut|s/~wO޺Ct>i|o-CXz7nxw2yEN!c=ݷi3]glڸWp*~"sG>v ?6)xo!~+TiOb9#VC}2tq\{G3cqY}|wW:kt>Dr;Z֛ށa㇜gIg7pĨyEVLkz Ak9G[Xjǟ?j9WW{J*>Ş>%}{%>hy '<~2Y{yQםs.=f튥7ȭ?=<ux/vhd3q3\DZ`21|E7|g-p< O8=NMO-1,F2n;c㡬ry7o&*K(9IOL0Կa_IL)': t&^y}U⌋qN󏑲Xe' w8U.rI,X,F:hѡ<)k +blNsf*͈^&56LWaUT<%g 9D=rZS֝MN5m)Ã{z}H|~ |T.?)gT+0E^F6m(sVVQV>TZTMWϓ;9ͶN_gR0rKy)i[{ܽ$D"H$'QD"H$ɑA QD"H$A QD"H$A QD"H$A QD"H$A QD"H$A QD"H$A QD"H$A QD"H$A QD"H$A QD"H$A QD"H$A QD"H$A QD"H$A QD"H$A QD"H$;W*"D"H$)F2sQD"H$Sґr>bؾDR)D%D"9(&(RdJ)D%D"9,u_"9\H!*H$1\LhA QD"HRdJ7H$01۾SK$RJ$D2 d_LБBT"H$z)-RJ$cL)2%E QD"WȾɱD"9M.EDrl"D"H(s&"S"96BT"H$ &H$S!D"HfPBT"H$3]LDrH!*H$'rvDr!D"H7D"9BT"H*?xD QD"9̤/&U~$D2ȾDRRJ$ nrD"H$M.H$oRJ$㚹苙/H$A QDrLS5.bJ$ɱe&L),%C QDrDnrD"xtf%,o))RȔH$1%D9e0NKo`G@m=m4ԙ4 IDATAxSH[htb%=ěb&݉:"7j"/ lo&&* W\^6j^B   Ėν) ՛9@*Ҋah7- ި->Rj>G׍Ba$g:q)bJJA$9h=N߹# r ӑT=j 4)Q0GA;7i tc(4^H%f '4"@V%uDQ)![zDX#Zd1cf$4@E05P#&xu10EN,(h:V_"Dl< DKΑ§4J`J$sAGBNYթΕH$>,sO/-j6Z5[PSIL[d-$cB:5QtGh=a 6`ҕH̤5IZ#RIZ#-" z *M4>. h ZQ&hMML(q!B U>ŹzQsr!c鄦 )DVj: [A]aT"(lmր^HDۺ;;IT@JPR@ :ɞ:0z +ihoImdumhho H 7<Vf_*`TQ̻ڠDE-:gEP ݶZ!/MQu3 ӉK)2%+RJ$'5Ľ]ӄLP.ŢѪe}ɖӆFJGt3"4Ckp*tBh:j )m*Z #:Z 5"a"Ģ7jˤ95qH̅SLɉɱ )D029Vbt4[h D%Y ]$>$b`T}8 Zfs Z$B* 47mOt 4Hn·Au>+:JP@q;l$[ !0\@S05՘)KE˲UxJ7DrdBU"98!TB3t;aŽQh3(}9pmpO+@ D8PTj:$c_ǧe,)X-0&Qv 50DG`8 q(QLEQ:jL"B}XGLd᳴rЎafb͔"S"9>BU"[=TZM|!R @sZmHT;a:=0 ]]ϖ6DA醐3ǧ_MAi҅8dٛ-ZUn(`vePU;&Aկ8^ )*'`H$s̐B7iףm& o N#Q@rs6sTPjm5Ok[s EMCw-M2tT1S4DP.Bߝ {'4)PA"w`e]AQ{ZP+oT5"4qԠӷt&4VqY(V_% CRdJ$D U$)DɐpVChSD$͆ LI|C]F1 7i˜4N 2Q d!̔nlm]]  :$j1QzZAd;Bn:SSP:Z[3- MbBqL-JkY.gՌ RXJ$c)T%'R 1`Zaµ "oC DW2VC'@Gmpj!$zh/F2QO ړΛzh &ܡf|~%ʧq\@fCÙʊ(~]XLt;ŪJh F c@5#GQ}NkZMF"H'PoH!z(hQ̐@V0 ZANjb&qۚ5% ,L͉I8 {IfԋNl:V}g&EǼ92ULVM-m-_jl/ 3#f6A"*:LaL-JM_U$D@ UɱoC͝>NNWpetphbpפ8TϤWXGkŜFH{LtmCcН,﬌!@ҡ݄ffncv1 4L{JOw Y[v(*HgjD#ŨD"A UцHMm±j,j=i4e.iYXǗ7F% UQ|萄zugTǽ:t!Bt0 j8)pXNEPbU >h1zY PBܥ1a$DRRJhN!jLe٣в>@Rb`ʠzv+C%ѣgԋLEF8/L2vDO-X=A ]MmTRuJ7;ym`c7o>&:`Oپ^GT41,XU]!_HE=21j4)Zb?R!V[gD"HfW~Q`SǧT\"4nO5P)fb[אwDh!ID2"43b>C) nyD"9rH*)ǽUS&WGs[+PlD}}-Dh1b@}`.--@QnVR0:; Ą(kVDi %FDTBD'육V =Փ! ڤ@\ÂH3(V8Ҥc,QBE2ѧ,b$0بFdHeQD"9BUq-D0th"#H⬛Gc[jI8F1_h QP֚Zq<3]liEwQEI_=Vk' U@~2QJ6﫣˯3+wt$8/&և'vP|蘩$yG 0 Erv?6R&S DBEkݑttvhˊRJ$A Z1Qr튠R`F5{1cbjx#JWf4H&W'4:t?Iۺ &`S/LPP89NnF RH}GZb,{$՞JI1ȅ3]}?syWO J-b~UX\D$QۆiIH*H$'RwBTM%W|\!_: ox.4eGGT#`*L`efPc&5m]+aL|ڟ`2XDڛ$X]"6L h5EHV#ָ!{b{X )s!Ӵ13"׈w?BS;u[0SFY]U8eF%8}D%D2SP=l;}ƺC(<}C#eNv^b4Zj-Z*1ERGA\ Y;BjE+IY]MmY2#ŌVT %cu;R XR9G՘kE$.&\O_} Q7,d˵/#vLhjBG}r3tV| XqCRg1KzJ$G)K>%G-Rl#gj к-zڟxxBL*lo.F__G"s,yn X=m@Gmْf\2"=>;2݉:Q7`E𭏠j$^Aξ%CHJb/#*u^^iZOL1):;i tSXےtD|frOD"ūLY)kM2s;|4w-Ո%E~s,Jj/B݆a@襱5;*s&{P0oi _$ڗ Bl! ٣?J|C4vbuTCAGH~B@1ؚ@$1GpTDA -a-TkФ`ݒ4Fh6wGOE8 }>_dhH0D"?B#e͹{;=Fj93iBg_-.3WAm |Р:Zds͵Ab&mIjh5#jHnj vbƄUf("6Mlj=f3n!KSPC:v]mG_)RòLݤE(Z= 0tH$dBuQ|3V6:ZDu=fv-խExH 'Q]O-Jog'j_ ӶA7=u$z;/BGfue Zh@m]BQ}/ܥ[XN:J'(`udP]"H$a}1,"Mmތ/-\Є@KO34P_ ڿŧE1MNm5AfLa}U{?HrsQmLp[t"AZ Sn| S _YtV jhF饔`I".H$hQs!:<ңEl ɐJ2&{@iV"8j8B2"hQZ7p1HF5$ AA' N`$@%>5ݶ*.\~dqSs,b.Q{t&;|ծgEi1XɈ@/g(D"H$s(T\i\ |@NEm f|:60͙7:qzc&Dh $.aD h4"l줾' nst2%)NP5{>`L. >{3St\W_ *N;nD"H$' ǢP=o*\`߬tfG7"0A#Bog3oS_ĠJww@[0jhT51|̂=/iS6"O$+L sT hr q`-Ԉj-${'#H$s4Q=h;÷p"rS/M4̈́ 7ZP]avP^Ͼ;QG<RmŨ'y[ J[H߆1-W"Eq j3!8.x g@#\mL#jbSהH$eBu.8T7zɖNp/gZ&3 j(]!=򾡭ֈڨ1U ZL S!,FDX*қd6#"^4;m bQ+E( ~jD" ӹ[S" G[eDGáэwv;!oƴ1m"gfJYid+oFV8fU[֖RpұHN9ɣՒ6dΩ˞k~N[}+g&_-iY䫵%my1J ;NlVڊ⊹>KOX^^2eJ?sh1w_[~ Յ{.bvsĉt][~)PҒ6[&[l}1s]N[lG J[eus$"5lΧߕps}{R/"NrtcKKڼ1餕ɣ-t⫎vɹ֖IXxpEg͓_ҽ}|2LX9l;Wi-ˤN3~e3Sw*wpyε '"ϫ]WmE/Nf]2e~U\Yj.N6+uDMJ6w9Z9ݜϼuˡ%m+l}?c)p^J>M)/vWeΩşFN洧][3ypw:WVdٚ9 3+O}mⰻ9My)EEHN_fLw({#AfTmM.3S:Ww~sXnWE~15U`{(PE~Њ"*#Et%w___8B%`Wx }QZUQs"#ݫeE⎻̖?A,C,b<`>yE?~$U0 V&D~{?eYK{|dg DGʹ)]OGjaja?^3rsY&Jƾg__tX}dgc:jS4frq+XfsgJzN]Cr:cSRxg#4Nm4> "ymnmR[f(@uן7!E) QT:*`ڢԺO(ILM#n#^eP }wzޜ-Xa B4seR6ͼ[]olc~iu \bКםp-?˘E!"^uڗYFv |!f59[Bp*7FE{e4ŕ̾J fa u/LKWߏnAzٶZ;LyuQvұ, X1hAOT2le3ɯnOKg˴վ$\Tݪ(68s :Jm8"ԂX_կg&2P#lE[£jw Pe~/YLAyX63\vN]:ItŨ#:>jkF\TCʶ8fEXlöM?J&Amod]u\qⶆ IDAT}hn^ZgeGNS㐭;ĵt13!sZ28 KWIb4ysKFf_2 4ّ|1:u(vܵQZA}-/!ΈQEwRݧI>K<(oÄkјm-+d˨=@iBЅV՞-};XFj`)u4c1XECzVjd[Fխ"E"/^ݮb[ew ҫV=?)K݌c7j܂QxСϬ M[.wdgumjr_ gY !9oӐwd7d_l1RrDz)K}T[F?5}.S6V9[Iq-< wX 3w{ω-䒷]ۖ8lU78J%8}CsStP{>C^ 2 _TMB;VQvuQĀMfӧ.da4]ϐ"~=*h:RBUZE5l0%YE3[u-_}38EܥߪϬK_^Qa}& Qr(:txӸ(|ۑ$ Xyό;r{,2.liWBY3?v=ߧD  AHճD՞2 nQ\7>a[fڲ._M]X?$T)SpEҧcEI/98lB54#Bm%ZP53rצi\f!4Eo759\ "Cqt!S=H헅p䪁6"IHrYOFSh":=D*b,PG6w:AHk[c&kBߨ1q`Bb^AY4de5b$͞:QhH ߒ_ɑσ(8 1tƄ1M>yҏGxi1b/ r$TT~=R r> ׀͔ < 4$*s>A:B}@LTE-.g4*G7Rß=z>(d`^X(UG:E r&6|:&N4m ?{™G&O&o3TQ@ч :Eą$F+m籖(I(XՏbb`pز>OYBCJHi>/?e _o `g>'QSbWh%-WԞ#Gl;ST$ f l8@.ΡS!m1& $`֑ܟ왌iު5_#KNpP2@Oj3jP u@yJݓfTEp} 9⧗J".ytP`ic1M#L;ަp7603hn5mtN9Û)Sm2 ;|RÐ*Ẃޔ<_νLI4j&n1'RkWf~܂ґeE*7S{Ο5/\5(2:tͭx@xO3(9s5$ZUltXUKk4u_tnf$ucusBnZ^5,(^tU6zMF7 Nͫpiz:ǾCT>;f"Qcے !}"$.+YI!(}%[p. yHF)r9HD:0ɿޕ<+-4PiPiP7E2.O,FHZߐʓѭKԁNƔxm{,\{Dd+2]N%糾=pJrqm>:RJͫ$@&pyW0μF Ѿυń9 1MBFuwLhpZ*s E6[ 3֘DFS&zϤF*$!dF!G2S*+j *IFͺ%Q0^}uU(֎*ZTј jx'S}dܶ E9>ilm,  dKϲbA]k!5+fUE5*\|oYj_WEO%5  ˏd pYyEKN\p+yI,fQE"8 {E&zjR~orU2}h;%8Y‘)m2hOsTdb`; &)L%ᳲ??M_%}ȘjG0?!2:)@^أkCsx})<1ZaۓS x^_@r!$C$p})rM< Z:h{.^$*axy^e?!SMN Y캠γ=:NAHJ[Լj܂}OymX؅e6SԖ *$*~KLQT%J꒺'yDEY M=4sQKI!7n1oK47B m(Mzv,z1c7q `rd4o<}hFTҹ0k3R iGk-d4DDO1IJdE}O}E5_*"6!~l&iQ QHF1`hv]Q;8K y?~}hUf_|(qxRK\*$E*ZéQx(9(BB;mҬs㾢-KH;HM&Gw2n \}2&YYW> tZtQr #&$dT*FpMf^D/C'p^~[ӪC3biY g“+'ʜ1=Υ#o|J>[[tDm'`D8W] 9bհ-|<Q`"akQfQEaɨqy)fm:h|̳:^YÑC&zKFck[ b2M RյȈ_EE6mX{U%:S&zO*jIƪh訣 p]j}j;yLO> 2j^>/3sLHs߷ #o0YCiW>Լ' CHmj>'+:igzoț@%D ^X2Z`ǒ t+EɦfcKQvmj}MD@ :j^T2Q f%YrjPKyKs8ElKZ̗YeAxB"SJPy>.ɒQ[''It\r!1;8J;rH—둪(o+v١;2oPQI/ⷑ]P<_?1UBqF5 fWP d2j՗#(oq.B\T8h5ї{:TEkk`+{tDükzUQ2ybk!}ضd! @lm'کEAh!!I}X/SU*LSޓ[RP_Wy+:2[s9e[rF\$e8*e щxREԬGЭR٥˜9j#:v9hw؁$H2X"=?F>Jy׎#2EfRZ14P7meLFS5Y2ѧ0D: 8^r@T2 xBjIi*DqDF-r!M4gs=[\flګ/|4JQ",^/M&EF5 i6@&|/k#ykVҒ\^CBQ ):ѡv7! <ܡdDF8cXw?]<U4@7e1Iv3>$-)EU4Q&mrt,LW=QPmgeCwA]2%)f9o'GEJ3cܪC\s:XZ<;p%5XJ e0l iIip]7qpێ:Ϧ M]0.> \rԊ:͂-7v9zQgHCM&/>Bߤ5ELZJd&}11X Kr&GFrku|m'`?sX l?Q "Y H1h)g+m89R=o:8.%X_AM9knqW79 o䂘T=>\gjiRTѕkgϪ`2nGdo|+}6'cɂX9!us~Iѽu29yTA|fj@fW. dw@P[AhLL昦8ukʠ&mB~ܞM9\GLSޔQ(0hFd"GK7uYDD%ƓTQ*}h1pA|oП0NJ rBv. UkQ<_OAd4D!!xT"c!hQAO JVEi)h (>s`yyN#‡SFӶM1&))pdRAO"jIƃ>}LFCJ@Aʹ?5_j;]Ⱥ Ŧ%P3A'Lѵ_V}qmc]_x*a[#MP/yv |`Wqҡ)h]樒.p=8.JO5z,,m+ܶ;xߡ12NSvtTR }HzG\`fLn)Pub8pi Zb{'̊k( Dפ_)TҖ.prRՀ%3aS@^sdAVUXAi~ 66Ot 5e81Up$T^먂E;k󹌢 Ml}aeݬ3>^(P$ן[#$Pں(@-{h[ $/P 8LӨ!D-?:/ݽ 7q޿ѓhvU:dYT[;r&z4{H>h '_27i%%4e'ݓA2H( O0;QrA`wS?;n8s5A+oIUGdQO6w_@ mNALh>cdl8HE9f]|"/Aޛ,td@^TZt!U~?a.)oZ<0}🙵ASrhܬJV!}h &׊ߊ@%RWMVEr滂YuPũ 5ʒ(mhۭV)3=A #j3XId?K+׮}!D;| d\9q4DdCYhU.[g_% M6ӄe,B^wIא= D5#EӴsjuR99~H=EB:lAQv42/ՙ 쳆'pzIh MYs"5?Vwt|EXDur\TPP>\EU\&{"hKFŒH/l'y4ިp? IDATIhhC::f2ݫ/Ur{p-%@3H82 c'^)&{$4D'xB7F@saY>I_:uښt<@k(|me.t9%}Q>;GߋIؙR!M $yc.bazOAK@ȩL\:q:\HRmQYØh.$xI {k>ғQP|dѤ)2HCр3W4C*TX2aE_RH &?OaN1st'疐{@?p:1!uMPK>oVQAc<@0ĩ^D߶4LBj}էf#$)#kG@C ^ }ߛg5BFn_:2ΟW0Aªf<]s[4%+a]Or_#VFE-ӶN*#,$qA*'6:@-;3w`h&G-ٟ$%$ jIΗNCU ̇ s{e)d4!5R>"GOd/+C7`i>Dv}fDmzI#$$߻:g_Q*R,1+~}ސ>dt' j>8Dѐ}sb[bYTp~$G&Ua?W!muy X>$[ė|\ڰ;uI';ᠩpY}ﳐc-*W'wQn`iKKL>1Q=>7mPC-rys;J/\2u$7u?##!m! 6t7SI%8et "_ór}L8SSlMP>*{[¼78|Ś1m|J: 60i.[m :j?YYY >edx@U}) qP59Dd}ƹI u|?!J. =Wr?8UDL1ہ> HәGS}nZ::2:Ɩ= AIykrz˱PI#_`ɨZkJN!rCӄB g67th^=_>DHGQ)g.M`[ XyZ?aS&~?n<<IMml/.|97.䵭JLLTTd"EJ2 mRJ4&riUY\j#A<~B .* ]2Yj|& ﯖ)|ଊhf_ 5*,xs]1 :'|{CZO:Tc!?3oѹXċUcp}wCK\' \JQ,u2dҞQ grPEi* PY;<{VE; >'_yIЫXd MH1-*~9φپ&G!$GH[SᄁKCӫP''SAH) I(DxC5~EwP-*M)`2jqYbF Eb.ogR4!y[޼: Z}lD>'r~g8iv )zhȄ[rf7j~s3lKA4yuNƐ/gk49y$jFFc.e*8A@Hȧy4ev_|N5ɡPcp-I\lsX]%]j8`w gτ{eb3z,\ w%wU0 X$LvlfUT+&U ὃ%7澽w̉|*-Y6"*owʉXj4K9SEWEa*jv˔O/r,qt}QFh'Fۧ!6 J.:m$i+@JPyMMmW%x*n- J)Rˊ+pJD/l?JNͣR{ڷ9oOȨKd4WdTR_4Mb|0$1^ 3~3JL€t.UES%SHOr5}OjLZ%?*_OGʻF\|I2Ft)o?^ 1#PE]<ҙYQ MFPG`H󐊈rljR/H<0!J?|f""څ5;GHöf0~n@ݔslck %+>/ѸQȕK7H/3qy<0]kН T@D5Uj!XA) ġMd-*?},n+6V*@**SfO_X/B5B1nK:k12:zt:a "ԳFg&C сgb{𝣆>Fx, \CF}2ZGw՞Vꬄ6PEǞwN$9I:dT/Tg&զ1B:R6{dx"fP'I)ė-ghv%'jFrG Gv e*% ف+>}=хړ3ݢ@hsE~IMJ8 NQ:|^cϏA^'3$g R@C;_}1{+Lfz\;UQ \B{Iմkf:*4 w 39h8fW#od2څ77>>)`O-UTVSRY,àX}6eBHF }$&HlXuk@ MnE3fϩEf4nJg?~h^Uty]{UF)Y?>;Z&{S04ٚCWtmB}~/Be+Bs*jq:)ei<+><IJђ')I[Qť eI ƺ-8Gg_߀?UPK@qZHk6zc]3QAK޷@焦ؗtc\WEɩ62 &d:*}D_}4ȑѿR f=Qd4 ld>dy{ק0V1Z\m ֐NZdt9pl2z ISc\GB۴~.TGu]_ h=cZ|hQ*E^Ш*FAohޯan!<T«C-L8 0>c ~S9p8K4o>DFOH7 { +#@>> "w@\z&+s KLرEJ3tÁNzAl#ެa&Vrp N[A*z*B>V@}j%$ = 1UokGVEl/b!O ;U^LSɨ:賑PQûƕPchZTl&d6,ɺAHHHhpP`= ۰%@D@OZ5, A#O ](da߸ܓQb ()}tƈ6)qB>M]z3鶿ǯ`% 'j&yBAee\~hd@uD@DssvnؐPEA)p$GxҙNI1#Y[!\W?tNEmdKDTՁ,\1u܁c;O9W%3]j-o /3'^wGRg3_Α?KΡ$}jy4&w- 'j;aMhg9W׆ktO*1tޓ[&u}@YT%U]+{BSqĪ薗hVy=Ԅ,g,U@*e ؿv TP~1wBK}4G;0^=}e@J FTjq*d4U\id`;黳L}hnX\1?Y'F@.sk-;9ZGxG`6\MP E8)Q5+dKW(KXبǛ2F@வC<3K>W(.}cUԼ=m[X.6[֔[-h$"%"~A@"W OЬ>l?ץS&`+k |g-肦h(2uc{>+:BFQKyC qEAk'~$]}];m9v{_BoϗlhmGP$Tєk{\Nm|VGs}\[QnDAmzO%`ݼJҧQ|Wԋᛁޔ.72gfUCz72 !Ԣ R XiؓJFCXBzx.m?9DDL}Ab粥 1!!tr* еn@* [H;/X 𽘭Mo(f gp_%\ [ܯğm}5MVMW&`6о?3Í)M.h.XqQ CO@7p 0Bês"W u Bs%>9\~Q )L_&WPl iޓKu2=fx K? 2_cn0!FQ9ޭݢ[%7ľɭ4`j &9[ (X}A~Ksj :)2Hi )x6y"M䃖H*0Q adT=?eWKMW테"h\zu+!+uR^&_Rn9wI*"G@.5=Ydt b#z) qPEyք6yS*m#bI3D?81}6Z7h{,+&SVPE٧qA*`_((0J@s,@%'M[d}c8}>h'K=W>S0tރLQBo_SO [ǩy>WP]F5K}_70Y)K bU%5ʧl`78l !A}@S h 5~ֳ *5Mo,E} ' Qһfî7j!Js1X)PHLim`潴iK./(d\CR:BL-ќ1"SS͟p%Bρ4"a#֌qPmeHDڦ(SG^݁:kR龪cMo xUCc~SOŹn;U tIIs!}c$dTgĸaB+4_Wh5 Ԃ)Sçɱӂ+-TSiOZ?@^5IS߷ KJt>vH a d4c? *gElRjAkP)0u;}aI-4ptk}f#KMv&w7 T/X6k6(Ί'E_V}UA^cF"ݷ:99E8`)2v^]{T[Vy.KD|2:E }=# BQEyh 8Uԑ峊PAujd9ꓥ IDATHJzߧ[0es#5 3HV~% u=d$2]|YAKiNHͪ%.Y &>A'4K d|`~2c䢌'9fܾ}4!}̩~SȨE/)) FvY^6ҢvhMrqCde I .o ~dp!rᚃy$b #.al>V]r'j!9sQ*9[hWJ <{qR]t2wPPn9ـ]'~BȠ^gmZ$'bݢvL|)Տ[;{i.I6cnB%c_'Ld*E@|?J$\-NnO#$4-JFs뼷 S/Em3׷s]}3th^bB 4r (z "G.ު5{ȽV eoE&dĺDJŔAWM`ޭ]$=d&-1!]"&6{҄GE҇d47nu]ߍw2黷R需Oo<#+ֶ9NtDuxk j>l\&U.*zALFj EhHv B6] X1h[r/[Im_/i6%EO2aL0- BI7:)% *N?-:0S樢cضMIwN;Fm6҉+VbV_ ЧKZe>u b:*d ̟ On-#GX$܀Յ5Z3*9{m+@Zͻ'aKP_#NS&I8ՈH(+nv$Ԉy<; C27ܕ@9u}oN߼LPTLT`Gwj+70|v`2 s(SyO0?Տ[h^atޖbVJI|mp 3 x}`O`,59\{A0_9x5 @nI2 ю٪ iSS\W;](C~g~gPsIHH&Ϗ,ʁdRt%_>2j`Z3cDg-7cdݗcP2 I)?nθ$G@>PNhs"50;!5yU0g dtkd4DDJGaS *$0Db:eVgTEtp_Csf2N^/'ѝd*{Xͮ"2 0K&)s_42Bb0}ashrԳWJMaOPJCҀNv?jN47|wQ)1zAĦ^ E۠ ~Ե'U!:;K PsYإU5\@}LjNdTN@r6:\GU] _s!9heD}QW1- u)Z~D*h)x:EyIFͷ~Ba0M [>!f/]Ru`R/Ԏuh#lmY1r:\c1cK1`vBB7#*ȉ,YٍC&g6:XDZUI|XQ RI.w)E& qSȉ[ef 48(I)ձ $%r$4D`q$]|2hdlcUT8M:R;@H=>XN~@(Jna*cUQ|9FUAђ.[{, \ڿ3/| -`> ũ^#S:NFhj&Kzd4.dbj6$I">;lsAލ`Qݙp6"Q ~HSd'ޯ/v"D)GړTє_^*:ڞ5i8чmYW<6:c6֦cAfETEUD{2ݝ@2SEksλNɄ4脌\1&J2yU_%v0.SUѱ9O)wՕcw$t@4iü&*oޮEJuGL2rcD11)xrՈ*OW6Y! gZl>JΚ|oI!=1$IX +Oe[@h617wUw=;٦ Ld-hCd|['?FE'u> sYq!$mA.ȨuIhp1! Vm3Eh=znj9sq'%2)5}d4 \BFA2jûYT+OةN3h_T2tW;\EߛQ6xF28G} ?c%R^Q(7"*d+ *zQ>2Ms'(>h cpK W 1lKel+C*Yvdzcq6"5[-y -%%F*hIaT,̳:wĴVi-a8vQvnOA|)($^UE O^7x٬dmj'$d6i+xv?Kfcj}c>%x qNehu? جGɨޘId (z!nh=ITNV W^ih;xBcY`aj bƯC$iG"shXVhj50)t7MdI(D,ۗ;B-ƺZ ATbj~B{ K@_Ze0jkI"4U\J*r_3A[D55삶-v7#Q>Sh؞P-ש/qBFɨҸLyZtщhz{HJC(eig(eJ@ o%*3;mQdlK_M[/%"!I$|X<`o+}JcJ"D[ $F(~YDL%@:x5ҥ%TJ2eŊXSwI=8w G)ZT_W@T>.+ǝCqyN8ΔmOӥbڥP98`H"Ȩ\R:_ğWMDF-BR:DL;\ %ܳrDPcwdBFb2j9:Kb} v omhg~! d iCF!z/.M*lv} YnCmM'PF86c'_"ޒQ{3B#~}Y2Xmѹd٥#!1x*λ Y#_PSB"^miOlw:6g:;usRP[=lE'%%xHC@F-jX +\2kZ[9 ]7"j6OP,M[:L{o>S+I#kH~тx2:}T$qks1$h^bPKGJ璃s} #-Qn۳ h|Z;3}0ko}+~$4{np#*J&p:'/,`K 筥Eہ.)Us߷`8]e|G0|N%~.?W O%koW0?^\:+< \j 2!0WYMDmk+(!4p6?Zo!*Wj$?˒WA jUyR#]jOqEv5/;@g "FNMw#Y}d C ~}ۤLSvN>n^j|42_J*0BԼ%KNq奉S4E~ nÎ|fkT[3YЪ4mʉl)Bҕucݥ<|hZ?Mj KkWͩ2"&)[Ql%Vؓq}=y[NL H1*mf_B ?G7Rϸ]m[K4y$?g!ruQM"s7{j5'g5?~hjzoUcf{.gqy:@Lg%uG?!'t,;O Z&> :aBZ'Es jdyR.Cb^Y"T辔]O~JY.WozJIFeנOyN ܎myK-s ?w@E C%N5\Pso\gеhmɾKF`>ѳмr_phSV$}_z6lN|Ŭ5+[=wUq{1V%8So SJ麵xj79e)+;ˀ5;Gb2 .syFm` |c hm*eMSoO&\:C7mYj&i9K`=TFuM/緫 hdTeQ/Lk7lo(nCHFRIg!+myOm;H3rV%J`YjS->'~El]7< axeQBqsxv4'!HA1zf-g[`>A3}{BR_zR1Р.R. y~GH5JHT05R>G^tYNM;skp_ Im%yw M]hv#Aày,w%̢ppמip/W25,lo8ݚ-'7~D4 ,§ĢWk~ CDJ5*5cǿGTw0Obx~GD-1E&P=2?=pxcϧ 9MiL$D^-b`[*Dծ=՗q,)B%sOy CmFj9gC]s%ш:tBHԎ|@Ї$&+=U%Wءf%|3=!gR"lB d[vVJ2m* \+\E1oуN} )huG%pLE#ei[h)(x,aPhJys|!m4~4GD85FPgt@=}9޷>偫؎00zFvUǻĺ1gj~J;2W9~).u6 \JwRH4kĩ~H,ҏW } 9zh% ]ه"8wN·.5S[0hjzp>EuJS:U0@%uzy9BQ#dV%RKH('kcjip0L:;;Yzxv`5YrzgH/+P_[ k \eԖ@E J%4/KZR#OĦO,wl!y`M@lc IDAT{ym`aDGD5t.9d A Yc:!$c)JO18ndm+ 0 `A,xA@T  n o0  ,X ?juK8sR#Z=I}|}JH1:qܜkۘkzXRJ(ZuiD_4ZDoƂ[|]2x&z{,5H⠽-MT}(OᩡfMZfRj|>c8v@A ``b~5F153=q7pK ^.ր6 ZJl ^*W8Qb'>2) WŔd[ Bw.J k XԒV$c(ļ]uf^-!f}hMxq΢X_i@F{ی,''_|_bN%WzD ++ʕ+-si^}FY=i$<6&z`L; -35g~=q_ OMFHX4!>SX qC8m»f9fn~Q`1Jӹ/ssr] N4.6)fo!$ v(J3if}COk.l TfzպF31-h=Zz7~ ~)M~TmjfzOPuq5&//ޘ`WJU/5YBs88-4PGrۗ6SDߝopʦyDi|T=& 5xte&ݒa;/!6?2K =gyB78uP &-9z|ޒ[V<$kxa`MF!m_I]}W/*6 J@QF`W[tyрh/PF}<@%EI}!_2p~pKr$4 w5ԐP@ϒē| ̎MeB~Ѱl^ =W =*mR-ɑP͙pm ~;Ulm^s%+9c+cGy:!Moof&.Ɋ}uܸvݵlDA-/ ʐzF!1" M;>z>@n|N?sUNcd0?gj̹}m}""wM{Ao zRG$dh6Uψp`Ȋn8jw7o( h}2 #{κ}Naf%Sv=VD򑊦5$Wp'+Y!0PjݜbR*r$BK\nQ]sg >!"liPǠTirys_"NyO\Ħ-fy=1]msihiG`+aqJ$zeJbRX3PTԧ Ȧy.W PCPP|4:Fq/>=N5_L梎Mڏ *?מO~E>!a{š&Mm?n#[o~@fdH>AE(*/ӴҶ_<]jM wF_ߏM|\H&@+4:k1ӛsVЫtvޒ:CL׾!H%M^IPb(>?cea3LXe&-#%(+qiI(g%ש%_Jk="_^yp(o\3kg;~ @xc,ʭ^BrC'QxB_dA' M%_$/60Cփ8"jȨ~"!,Y<ɨ~AsȨGDMXzpcC2fc$1S&CESǟ?;FBm݅sh7u}I=nɨzF?|}o.6JBnwK="jm#5*Rg4FF Hi3@<Y& sCM% LpVdK@HNASK{ءWD@UP[UF y#c8H}7WkW-[emd[۞uaPlחw=ӹ}6:&}E{DĊcc? g[M*~nKE2Ɔk!K aVU"*2AH}1Lݒ%pk':yd\Th= ʎ(6vBL=lwtqЯρ] ]F>"e k?!”*9<4@bi:c)7OP`VIb_^Nzy>9J(NKLԪ;?u3xה67zmq\Toa:s`K@ CW% _kYyt_f giqa9Z\*5FQ?dIg[bb0}.$'E\UD#oKt+bm5ԋ ۠6Ԛ| X3{TQCpxѲ9|'w(qwByZ ]%+Ԏ7cr'}g-XS[m5 +msN !̀\ֈpyQm?)0=5YqeS$1L5Hv.7L)QDGzc7,*@.9gjh^baYB腐k{V7ǾX=3V] ]+GjF t%(@J Lp6S1qcJDᎆ.]x _L>bvKO,8"2$AynW% eTيˇ#1WLTFu4Qq31H{V ?_?_yJJEѪ/Sc=lg_y\q# /l7->f!ɋ&a:V35.s;ǎoMRj \KpN$}KQa+շOP~s,/MJP%8mL `ҷpjoxlg\~8 u}MJKYSן%w ^-zc w} j\=}IZYĴ[b`6[y7/뫊IhU{DQ6e -x5)sO,츝ZCqpC͂){^_G+ze{PF=Vkb} 8.*q!e_`FfcQv&RܜFe44nUvd>IF}Ĵj} IؚfhI`>?ԸP!d4OJ17j|LHgntX3lD[iK"!Ly(FHi k4 /`EsD>A]i[[gF{ݺUebywsڌrdy\ω|7|7ES J]CP'fSNqo 3{4CS#EIdiZJ>CsGFe=7K'Hʯo''dxwBI3g(~^NHDߘ7:97&}, _Xn1KUsTn?T@U a7.@И8V7b,TTyL˙?ה!9B}1{^!"97p#'Q"R hzA^ղFDs+ke~7"=|ysmM=C?[Iېdj]'mOfʑAȱ:{rUIZ\LE[Kس]W6@!ҡ!sp1O#̃w]]LCnjR5-ʖb'֊ + b |q>,W^1/_"~ߌ9wO`1Er>BnH)3aD%A3.~k58'f+WEUQToRi]rIoVN->'n[8`sc~n;~qe$\;PFCbz?( Z?o1[b \y~G#wykˑ6ҶdJ)c-$,rՆPlUF (rLX,,z$ǔg"`ګ|=T+v]Ҷc[8L!_-푖kgD 8mO59ű9) lp}EvQK9wK07(wjg^6 ]]UŪ(~SeςC) ̚wؙ"@s_nJ*:iFd}A-.-UXp--;陼/9w5c.C3 ɫfD=ѥ{Л?.LxQ'`)hz7:k‹&(0 g!d4EBSmcclI׽$<ļkLyk:}D1+Q`Ri8>CH )sGo3IPq@JXOF # (d> !55Wsk|0}"urS0JL/0$BRA}[`d.O|P'ӐÒ1gӚ j%/xbFۓ ?ERHD O7FFCNF/}SWEVgy>/5 dʨ1s('2CFʑѝdN#(N ]9!ZjWu"QC(hr\c͐`>a/f]x!rI蘒K窡g39Tv/ܿ lNL-"]kҧ4l(@-E  Qu(^YC[ꖠQ^W<)NA &gdQp>8Ly(A\os%k>'K-KK6R)^`fX+,p-ѹAJj=E[sR.͝|cz92 2p甐$KC뻐ș*o &/ٜ9Uw@J߃ *Zڕr,I[V&yy>]}"):+j r9K4uEqyCw򂰤~ lb1d)8(=#u;Uhuo5E[Zt'$՞j`,Ѱ؋SCz'$T@Y|BUҵݘ-1g.᪤Ϸ纗X΋]x&P.'L({MekբHٷ$ sa=2ǔ;+]|7qBV)ڮHbDM3Ahl<=86پ  tNXCPo)bM':w|R#m ~a,v1կd2ZY?'(ࠖS@pY23*Z@&pӸJz'h}_I3=}#]/ S"1/xSF|ͬ!%T#KB{`kμ<>կ ,~tŮwkžr.zݝgs?]?a ".KKsR5+&LJQ"*$Tb]a$)AkRpP kg`F? 7~#cswR[U=mk`u lF IDATm|7/a\sp4">X|2˷/+eIdDk> 7-l^N3IDhpbutx1ʨQ%o&gSd[OF ߡZn,۴uh'Q2:$NSHF`2 XR-qCt%c(CLչKqBCW1Ҵ3c Tq@F^Y<"d,w`QU=8A=(5H^ʼd)^3s{ CYXd-IFq d_.fI.9YQs`SyZW5PGOX_e;\Tޣ^/w8ĊuښGy:35,Z@27X#J@\cz\ͦ+1'K4i$8R 3o`IÊ}ٷMtcML@<3Ljh 6; gcO*ʀIٿCLɇ`*gʬ?G\Ҙgh&3ڍXC_ySg_1k!J&<6T %${X&!׮x隱ȥtq}Opi qsb9GC~}*1)kJ& Պ9i ^u|"f ɵ~r%w Ey'BަO*hAcj5Pg6vr=J_$UݒSK*&ky^y_jey"őϛvY-^`wSs/<k2?q"|/]kV#&zg\&7?$)rjꋇFzr5@]ZYlT~qE%>wdt^_mN*&?~,i̤?FcL;s7;w\a\  h _ICF :2@qe,6ͱh ʼP"c6JӀ*Q*&}F}$ k/}JԒ[?Q XyqhYV蒬Sm%!42 ƀн$sR9C_Y~Xܟ>2j#p$O 9?K%8 W(n5BQXp|2jHh [ǿ"|iJ趦YdOD,zi}5NѰ2vmMN3Pu(B[ɨz7 R1$9$kξzL6/B-NTI=E:cXbqbM~45-(JF%Xt{82 8BzB.sr1TJɒD[eȨQC;Wjס[{Ue뙯`P_1aoXS%$0ؠܓxΏzc5B2_,s1<ҒT>Fн|v#:x5ӛ1fz;BFC\!, 5} X+'AJQF5KmqF5yAY' C ']`?TXl9ml"G˷l#\|wUoj^yZtFW}_z Ori5EJ-0L4i. Z#xr"sCNp{13~~|\0=%|%~2Eԇw]'i?FF} [f[py o|Wxb0" LJwKqdyfQ~tjv`"R扴aD`|zaX(|OOH:#c/K3.-k j{J3EvcGrc^D%yuLLH~x `B?=Z?XN\~Yd4 iHBSy/89JO^v+j܌9ԻKCdTcU&RC&Wt"{ׅ豾]ۋ <۾>CJ>uf&M#$􎌚Lźj%2Phah>QQ'.u!WBc"!fcBJLX$&)?#{ N[rG}2Op\Fڗt+KrdTT4f+7dRq^`JZu?kV9gj\:|l;[hHD>]79甏T}`HBGY@{^H"~BsU'6{(W@)Ԯ7k _=0*Xu4CB  Xj_f3=%|'>ke:u%7/<ߏ.?9K*hSD4Q?DL؞P/8^IRERrөBRzP$|L~zۿg3$)ݏ?bVefIln,=`O.iD_}p{uGxBF}JTCBM@c_kT/6&dtI/k4Ms)Pq jh0 2!2{31S~>x)"j֏tDڍ!'@pox)2ƼqɨAI KW1XcO:WjMHsKJ'Hh()̿ڈ:z]9Q(`9QCHW'@ύg=U9i(%{~[LHwu5G^ryar%sHh -%Eɩ9~CeE{xSuSg/1R*ڡjG[r =2 W׈|G% P.q'<5tK\$Q`ESV5)@| \ryS RhHQԺ4CeÔh:}iHDvr"S04mQ1J g8ޑsS9[@(jD43Zš~@DMxs0ib3)C k>AL2ڋ" LŐzљ'H2;EDI[ez8_~ Sh& Xpn Uȕ->fI)1"BBD^N"LD'c? I[ɘr\2 1XL*?WLBSE{Y$[]HW8E)IJM&飒ꅈ[ՌZ$41-ld@4PF- }}A|C7EO!%|.8L`[*8z .Vj$HDVR=2#DA4e/TLN>LD{,GFh#XDqX MA})ew # r'}v~!ez.} g KFFo=2 )-#JP`|R:RJ' 'v1m?KS{yl8 #(l™\dtp3\_wQk7_s{ -iz F ݡOSv,! Jטt"1XqQb*h?T(E{ޜpQ#Pwkҥ%$\Nԍ( 0FN' D:f(&bVSh%#d+jf@Xi>AF{octۓt%=<xǍ?|lsRjMk ZbԐ(Wk{jO;TFDn;GF:zCPWCMgTc@D}I@\ bz "[q)xi̗rM2,i\""BL]_d$Q COD;@o HHQIT!tWY |?~QRLxbI(V5K <ijDѴUGA^ *G_zn!")g߉ 5fy=1'z)NA#I%EF.ΤwÝ oП|<"jd'SZlS*K?G1?\;~c?M )"Cp-7CQ_ Ҧ'T謹RQ!AF?'n!)CDy bʟ7[]/ 8OԴ}`DSJc[Q|嘆h$1pm&o[%6FG˖˅{u7:EFߪ3< q":E}/ [rĻ4F(&Q:r>ADqs66>~Ojp\"zf>|Rt)Q NFLj(v,6)MF}2 Q?7)t_q:0`|V]J)F2"78'"9i~ Lg!~ۘj0~ S)b/ R:xѰ5;UC3Q3 Lߐ b$ v+~`fTcQONR395#BHFCE#~)2z/-}F1Q2ځʀp%lb~xSFh )bK@^_*BWi,_'rڽ Ȩh u0u=žHBG"! aqYҗ!af22Jc"iQㇻVa9Bo clu$xPS3%z "Ziuu9A "#~ҞɈOBsg)skaT87?w*}檠)ǘ_TED}t x w4XսU(n[?3F5ӛ{מ )y*#!)H!#[׊ː{~5BQ NFh)+~P'mQg"0p8}կ7\kpL":JBNDM1Lm񌭏ia/m*)GoߚfQϏYSo[5ȚǸ+c15,0ߒQC!YB9}hjā%XHWD vB]pε Z^l_4_ɾ.<f7g7ڍC(6io*؉jS}7ez,vch*79>T=\o 'WChMt%&$ce9vاi>JdBV?D6QOnoQKl[Ue/-fK^WJLaOAz >mMRjEURԒPLVUL>V7 #f/Dh%巅 J)2RnJWPaaoܾ5U6T] *]liašXZ9pNҘI1W#N'Ǒ4A58a:(;BLs\{|8p#I'. a2{JPSΗILL+O;b"g ˼N}8rj ŃL1|io?=HQ&J߆k)p|C}%7e!-_*9w3xJ޻}U ]+8/?ZW䂈L1"!!z~46KHi1pZh~yHГLQ2:+@(gkL(;j) ^(?W4NF4a=ٲ؝sK,`+KBOR{H`nIuK9>ìONBcџ;+qBQ_+6Qx1BjCVrcIѮtod:DC(Ru|lucP3kBar$ѐRYzfz`#cE5BJ2!FN?1 #XI2! 4_gks/+BQ(֗ZVa|E~ޘZ3av}ły^gBBL ^80ISk˩^$osNh!R$46 1FRqAF9z8ufmdY< Ea`?j<?9[\K`ٽiZ&yYp$ (NɺX!K+THRIB\ p/IC[ʾ0f|f4Dž5nZM u^З=9_cY5Xwkēr1 z)Lh*mB;fvG??,xF|_*2{i 3D~)?O%=eo*&md $ช(~v*gbM"UQ O5db0JwSFbJDoЗfi?ֹ>*Z@C}cSFS4v<16Thc=|FQ`HxL)1Ҕ>L3}oEOHce 'T{O +FŴ:1tJ^I{ʪeJmJ*ǢYP"+M@_|G^KTb2~YN Lz L)eBv[;T娍~n3$:cMBȌY2%,1$1ϗSg݇NםjfeԨBFYa1etw30UKQG[OFo'v!/di/0|S? ݏoj y 4Y'OF8!CF>!}g=g71}Qא6G8_\|2 8Rl1I_K(`A1oVIe"Ü΁9/i5VJ4SH֧օ9F} 6@QHLڃ~hVj!@qF"x } )ps=(15@!p{dT8BwTwܧ7dDnsW3\ڊo9w gxD%*\ 8x9${+p/ ww.y[g!Ai9Dd ~ H(h5"5`|2 }r皦%NKr Lʼ`JQfSBS;;u 5I(pdӼoڌ-PxyVJr.۔)?aM\heO%% #FꏫG _ά@QR\]`Qm֗(s:>kȈEuhDKfG먉G`j>5i}a۳{ H c;Fh[3q \NMKL/Gyѹ?K! [O%.X.p\pIhMq"^N`S-*LԒέՊ/4fLh|]v)J|WWD'~)7!Ki'7CN"X=X4`ͼ$h11硧՛3}Leb*jY Zɠ*aBM{$\=o׮l@U@_ȟ>橊9&3Og}L"TG/ g]{ O EtS z)bʨQ X2M@j5/`s )N6O!U* ]96=FKe<[+X&THM`Ld>)Y(>_TPKQ+!%z^p7.KW}059>$ߩ_4GaiLyd)QMiֹd cQ $֜u9TS)2 Lʚdf{sC"ȭo?$i#Oc$_v,$9O>S% [CjZŭg7ؽ[O)b#sYW VxO@\CeJ1yOD@f,}Bsʅfk8bdT=Ym#4趟z NU3- &>v+޴Q%Ԡ(.mj˗K9o.aɩ~`E{?Zz&|JB?11[^?(.򛖒?ۧ,#?𒜜v>+&^`Es(Dmwlfy0T2JB͸sYÙ{RQŲm>gh8_\:(gb3GȦAD~14** ttۘ0h,='e$NϷ4NIaTI)$2{]ˎnJfrS QR9I(thM@}GcIתǞ p:w/>f) r2x @SEOԯ~PU2*2mu<ש@3Ӌ@Jx"}rƐ1˜9u~s1uyREԀ??2?PU?D\a_'QkJ63PG J`*I#M]%?TVTNLH +\o5 R?8LwtE_o_9f,:>4SrFl5/q YZѮdΘt'H[m`__նJMȿ3ʒૢـ( C5$/Aq1G>ZmX Ô*VPW_Ɯm~#w$"XUY~T oP|t˷[ɝxʨQA 䂪L@Qk[*LuZRuQ՗(2*(UÎ1ibʦgnM)HsubSLǾ a_]35`兆~}ꄘ0dԽ`v~zQ6CVk#"G-SK[zWcz:pN 8d3RH  %?_pu4ѳ`X\D٧_ %+%+S8?ytB#l迴!i T@Ö0SF[o!J! ឤ/#G0*igH6FOU* [Ђ_$½gAo-mx^¼>t섄 l ߨzBPm({ưdߍ~G})ʨuY̓%L7RkC6PiZ,ֈ2*)|N)+:03 |1-Oi껍K}wsh]qOyP/{~u([r BJMLjg5)lo2ZJ'`e@sJ& qUG6Ϸϱg$x97j9zC|f$ ԟ(%3ڜDcv)_҃+ j$¥wŽЕ3j=sq)su~)Y@3)\Mqtt%Aow*SjnKgw˒Pcq[d zNŨ1t~ҝFwRe0Z)eKwG Yp +\aH"XDQoUߘ=\ UvK9lys5D擨T11CrLS1co!U\12CS|LQ&wSjM6@G(^ aBjM8pr njȧ7~DPQ'-|O|P xҋPSGX paNH~~l)6>$DRbbɿudp#)bjIGe|MD7n;}~FРt)Bd IH$m0E3QN Ŋ`2z9 OJ)S1C]}5sX>~*Q9iE\C ho Gj!bU+i ,Y!V.9~::JF Fط5E-R1SÖd7 $),DDyyD@T0"zDո, jϵ%XH׆*)ϜAFw+z2s|ˑm 2jWG.߾ - P\h^HZFDWz|"_IaUј$LV70@)U34-uwEn4T;?ӡ2 x5NFnNΧN&M!2 jj`Jz5%Z];NpޭԨ:j?Wc_G)LDn K@HsOFD/x#>r\aIP_GF=S"2ZLYA|u0jMkkpx)E"MFgѱyd2DG-[/F_2e/ ?D$3 sN2jy"7l 1QwĘ$!sΉo=mk{ $j,_eQy$"*ɭ|82Qh"=eTWf#Qo%zI\E) W$)dsG&y nzfGЏQ@h5fx) kGH9\>$iX'%κ{!EH5Z73hYF} :j&Ln'G:NJ]%Qw?I(#~=\@=2y7X$:F,Sil{Jѽ&Vԙ) 2 5}"jW58ߨ>.ŗ'p>=$S@]Z]|:9PWV PwWΝ+_#&QrjMч7R/=$D4J@cXp]޽#(&:<@mn2)`KQ,ɒ/4y2^QCBS(ݿJ}/LMSŶ㗧KGj#>&hQ_)jo"?D<SjjsfL1e4\OJBz ϯ1窢K)}X&bQ fQp'\b_14 S::}$7{by]tSRŧK+B  ⾐6RT^GP"qlC )΀%1[51""q%>rqHS'dnK*y,ք3QK>%}PljW^U%D529KЁX-e{fr>iT[:4m./$HP+ÞP<ͽځb[8"=5ڃ!BzM=2w:9|U[+S*y!,J9N9Q%e~D3g{dG6_YgYdԐP^A7Ev !]BJ٭f% n.K!59W5E߬*Q#M$E|NB_dJP+Gr' pg::mYn_ U:UWêTg5d Sreb0w)"jTA":-ǡʨv9X W`Q3ѳEPzyO{ 2#>A|LM@radw7c2 gRGGQz q?!)d#WbSm[McbPbL+YQPS!⚀-!;Pԯfwr)muKBoo=jN俌[w}'M!EL]cP?3^_wCh{AR0Isɨ)"dg~~-5]0noQfL<}"Ðr{CX@= !7{94bz_(ީ$ mӉVPQz>}IyO;MY(Tq b}ߏd IJ#gmFڶ}ˠ ,X0/ `2p  X @ @ A@>puK-[jٞY-%CW_?kou0Vo2mg'8PmٮflQ~l|6oEWzCD3A0ވ(9l P$"_! u:46mSz.d]sU:F]*R>O Uժ mXfx54TsL_v,o?ŋ ZyO0zm(|UPè/i#+d>5 BdTaJK@DCj X m资 td>UH}N:p1 No~I^^6^e !(ZDL}7>&ofp[~+il(б2&JUljRU0@(2>NQ`@5|Ieǵ%oRgagHZD}P@-}%؏ڢ9jkIQh%ow; LgԴm헉F~36"5\jK+P=|a !E54퐂 .t5rtwCzȹF~uS6S~%JնV ` i?1O RKɵ/JPS f[G+ rƐvNT&ͭ[Q6X=0!)ġW{--QBt,P )T kKa2u3J|]LAOS6~3vn_nqo/p PE m9Ks^lW ɻ{Z,$TMT[&TӿU0nEVA< ʤtےTΗt^5߂r>P ]:$Jضv,>+Ok u#4>sNV~X+v!\3 dRP[u)eW[ \%=D1+(F, |VowFY6ӖY^YKnp7O-OF-Qw!cY> VR޳^Q>ݥRTrQoO125ǝM8j`ʗڂXTPY6lS$7^P-/w)$.CbY@mjnG"Ci"JsJ6u( {&H w uҍ-()*0Hi&*F92p:BFnS}G'I S; xDPUꦡh9H#]G4uxlO+T L}׏|Q Qn3J92cU'N䕂ʴ DoN6&9՚|~\k@imW `?Q)_P_ |Y7}#N )rE'u{:mP*OB,/dJ3c Lye朶^S9YCn;E֥nO:WV)*1 9$%UGm Ua3^}$ P?PW@.UϭT?0+c70V:0G|QUemܷ WvTP^9_]#_SekfAvz)+G{M]ҔU +xEVF݋ayLP뵜~Aѿ*/JUtTrqS20s}2so}`? TJ'+Qnj#*˨s~D۾nK}*뮷.m걎5}LƟ :ʁkN !p-ZAǖ=~-ȳ. hD՗\o)>YS=!, YmӑgKv4ͩ\=WV-?N|*}JQYU; _ %;Rx+FIjQ)"P%Hɺ"+Gݫz͊`5dn᪓ۮ* hsύTE4Კ HoDey0㗷 h؍k? 03ɢQuVX3oLo#:$U JNo% FƻJ*F4v b=ߠQDjH>}6ӿ AifMPqPu=x LCVϼ f ^}}r]*=Q~rUsic[o u@ԧQ@jUq&mIY=U)ETJ=KHOxu@Kf/ K7pjM{+C}2 XQ삹B5,B -(yF4}0-huwLҪ` 8.KR: ..샨@ /S-_H;D(!,H.@[}Z.FQQX^RR5 FB[F3}֖Qaўӊ7nfe21U[Fi}nJmEen0vǃD;n՗'MUqFCMz0ڴ>ehҀu=o|` @'sP:́#P?ԎF Wr)D+UW2Ձ,vK.@-לySM5+7BG+hTS׬'r9z6XS= +ܨF@T$/fEq5D[_u.PD>jR[^8KY01+Uj 3FSr}@[>q pP6^ϕ B_P}N&r \b!F ܗzJ[HQL~VױCA4*A&d*[_6#Ђ@mhC0p{ A@'RFZVrq 9_C`Hq^g0! e8ؖ>óDKiÀڀyǷ`$> 7T?4].BA q~l:FNɾuR'ڏmc}| ;Xm05VϗSņQ.*^ eJmX .m9tNP+50* fm7F]]ƚ{A^JQ\U7NкjwD>A5B 5b8v[m;.> LRuRߓ-5J $U^ߨ?z>}0RCjHaS;Μ1A$PF(c 1_rJ3Eu4@} E) &rUˈ>²9^}?1*hTUni5M Ydl++!U5.c@'ǒ|a|G~}^~Ӝ|r_p k {7Oȴ;JQYvrQP}Lb~46:A[w]P?UEJaxp[TA}ojwa ICn6V. .//Cm =%܉Vt?r`4R1`%[,=5TJQW u-^@LFGA'*Bm}i}/>˦z@P1boQ)hTRw!o/;F?Å4ĽaG 2e~hrwT4{ǀDp=bMLV@Z7H).m7@([j`4TQFEQoRڢl _}.0\@%%\pr;TX}`ԧMx"FE=X9cR ^VQ{ FL;}BO"~44Nե]gTT .NRvWԕ 55c i;Trƾw; {H g1  n+υpy0,~&c{l(Rle]~5 ˓vVJ({J-kixTqSr *A%3*Agx/EPc 9kwS14!}ϥ7ᥠ-Qx _Q6+r͐%VArk> iWѨ{VnlCvxC}CeCr p Fq@~$fD;ɿ7ϳVF}r@>0|oAQtv;_RI*QVwUHN㰌~n5 = ?BA4մf eИ.Eg[v}GQ+hTԑBaHVQ X$I.(Z_ o/1w/ȍ[O 'NyEs7KkV%)lZHިC%<=xXn`g7BnDTSQ?/[`?VYMGp$߀R4Lo.!3^@|[$Pvs~F) <]ѐ/%5!_J^0DZCp>L^NrC>sp;@ $?e !}ϵ_SC}&zԍB4W<c*2jߥ"FE݂B.rgԍ)o!jH8yruRH-$0rq<~4i2~-7^Pu: v l䚖 ܂I| <[@k0A Z|O'g@($qLofdYQ]dz ={ @C}Ӑ}D  z݀Al/#dE;\Yw hƴXA:;* u&(lA%'ք+DIJ}dMWϱ=,+ 2v!-QQw,_)3oiqTEⴎNrw{86ƪ"1 տOmF7Ũ#(z<>mmS V4͵!p6΍BNs?ˡ^)S߼6rFR $.V8ҬK;=̓jVP89/AjoOp`9&)DOOdt ,%u^1Ned8F[H.o2$'9J`'/tPNHAѹ@RPy6궟/a҈꤄B#%먶ɶ&+uNJ AWc5&KB{P1T_{t-]#{QSeV{UFEAXD}O4{;cRn9"n޷U@CneŜ ^`\ѐHYn],`Ԩ R& .[ڲbUWɩ nZDoZȹdgkِuk[>^GѨm\\o{JQCVC?T qg1WoT}ˁRO=|#0-_HQ`C9YQI0/N*xɆPIϧt'PȠ~)P 8Qin6ߡ)C4j#>:š;RPw5v}uȰoxphОek{]=-~+Q|GS6v,JyZQHt/<_3`{ d9+$'.,?T? z l:WTGB0:dmC-!>w|CAЇQQwvD:8^c߆6 V7l)ACosӍ UD=>$A )) &^TS> F^RRlLts2 d@ Qg[r0U7Zv赏0-QQQ< 1)ļQVB%NN ?uT.:9?QVܞo IDATϓ:9ZRrd g]\'Bs0{j葏}+>wLD}Ѩ;cAZjuhcQ)L'7~ME]wP>kԥK䔂PP HC] ʅ--kYGuQ)ʱǒ+x.cs5Ϲ!*:BnJv=t6hoۖ>6t\dz}m@ྠ!WT!zEQ(( Љ_r"UPBr_?90Wzj?cמ ^+#>D? C9AMY#a*ZDP!e}e.8ֲ?wl[QS0" ,k\uTΙU%- ̐m) MPd֙~BE4*~PA`K}ʶ>v>6 ZQ07+3/Ruoݮslχ!Cө B#RѨG:$nCѹ>z_1WӉi(6>2WS>Sf>EE:84800E&h~r-m+y D"FEݱ\56ȧfcK8 ۷u>Aci{YCx>mECC柲7D8غ i_{f}4X!q)hT=)'χ7Q{oc{WL)fBCE {_>>Ec7>?ȶ~֛!0)hT=:b3^TJ7?^:V{=mE'ovmm_죺:Bc/goqXii?Fz\>QQ6h _׾ 0:dz}x:C#D> Eg)rݰ /OCWcL.*~A4*H:EqLhcxYeu:/Cۊ}R{\c?| u7TQo־ߗ6סYhZ[9 {V|SRѨvÇz!>$6&]VӔoe=CC:v u 勖m[MJ!V+y}ZɟBi +1MhE\QѨ>C.O6V6cqq4*7rAm0g] ՟r+hTk(kl0:{!8F=ˁg? rQ_DBLEXԱxG^EzSQQ+EEEEEEEEEEEEEEEEEEEEEEMQQQQQQJݨQ DEEQѨu n؄97**n棢FIݨ˥3Ƃk_[rv%**v-QQQQQA 6|0\[ٟ 2=,߶-QQQQQQQ@; LJ.k>4*棢rA80w}:];n{1a }>q>*v-QQQQQ eFu6%ۺ`56jXKj@FESDt-6F>k/ކ}} mSm棢gt [g vo CCQQQFEY-:QFav@c2.d,cAe4*pE:P!ICh(([sb&+' l:Y>6 G:LDP_Uhco?*ju m  }io'$)dkQQ)hTԀmߔ"8F=$ǐs=ߖ >@4!V(Cc(hT~ R(4n:fY|r72pTKvMWڣ6dJBh M2c0:=}s05^D~J fS7m40hek]YiJpܶjFXTCж mWԎ3AT[D N}A c$6h0צ}:8pjylP ] jIm/'5-Gyܻz"FݹuAV4T;CE.k}0ڶ }hCJ 0&ܝ$l>a/}K0+h1 \ Q_PoX9C}Iʹ}Ӷm౸ (6>A4jo66Q-SΞ qw.Ѕ>ۺ+C @_؟(Jf :R6ػ|JOdžP= v mXDٟ9sI_fM߇TP }D@ @?z>_*l! u2M2BM}(7\AK` : ~!@z0:-u97.R~#YE$OYUt2,F@mJGmgP54xs|(ӱ]fgՆe>n ZG_܄<A-S%5A5Tf½wyبAi *caj[_tJ `9x-\􏬂c:FC,t r6goR@W` B 8o A(/&c94iyi\j|< S?r lr `)!'Y~y&.>P;ڀj=,Z l_Ex}z Ht4GwvթczVo[@C|dX7_c( }g(<ˀMu(c"5AD[}GA7JSZ (Ÿ /B-)$#-m[O kk ,[nh춍qmQ( ?)duP?g@I@%pn,R &4֤.$RΒD#-Q_DB;Zgy69V y5t١<;f]Mxk|  |+EP ѡ[<FΣH悀EUl-1*oF3P\EKpi9gHf snYCnN iQXXm|^'32Lԗ iR! Y6SSz% Knt.p!F@MJk SrB!> g:@[SSa p/}$0ɝ'!Cyqx 1xdoς CL%P"3CHRBAp+?Ko Fy^R sUBo'{լmX.ƴAldh5n37t83Mo`'66 dqW` `\uN#&+&X^NTcHi((`*Pj4]rK`S4ʨm9YRm,Ö}^=.w;p)1ͯ2#y @VKpO&MH (U_<'ϛ~\1 De΀SAZ}av?{Ayu]  /As"[@] ȭSsT@] LͲPiiCօ3B" +znT0eFf}oCAt.G6cP|K^(e9ͻX.PZ9ɟym ڗԚ@#J+5Z¬FtcӨ6C`@DT4 L> B@NEZOk+u|.Kmu +=dϝ|ngJCq# 2gH.3A|^f_]"= S1/ @)P؉:ZI[Jm3j]} :\) Czi(i_$eɀEf!>.{Z[Bk؄AT˿+JK&2y!1Tt5"tHoDI L0g`JRJ%}dn(uLߞC>I8eƚn绞Q;<}~ REV&-zmvsaB'o$<&9фS<#Gk|X{V } LȀT{yT7拰O !l^zxN2kNezbJbjld!ɵ@5{:`5+#0çRQz LD#uO/ow*ML !۱ ?UHP@#Bpzn*t zvsmh8I>(-Dn&@\ pJ`5)icӐ$@!:pXG]TMdMXu }44咾ZL43ڞkR=_ T4{Ea6r@ꔡsY$co ڏ  "GǷi5/LPh]3/upe(Ҿ1"3+zR3|J\'ew^o Dʹch{6|/>Q9PIԬ3_Xg<}` A݈jLA-SlcB(P[D S4Լa+:Pzši>[>>پ@C-avf8}ʁVr=48?ȗ eFZ&q3ﱚF9Oa= ×4* 忒-SO\vٽwGȗc RHJ,cvLG OkP /S vgZk༡upD܀܆!b=~m_ViQsF~SmK 6h(E!N(E > /SA~v*@G]~(sʉ;RjVִr-ϗ=} ԾCsC @oC R@8ۥ@crk Ԛf5R#P@NE||Dђrm&WAct\+ <[jH]Mh=>FOJ8 rRckK G^|)N6oRB,R0K_'Nbⰶ*< hA'k2mNGia4DerRQ5F 8jc\ y, =4JW)#P2lů} *_ж;P+E.~(PQ4FWzJ1AvR/0~ F,^XXBX>}C0x(P >o=\֝&F3V K7:T_vP`Dg={MwX?2/$Wj7 sDun}\)4@ wXvt$H7Mܓ\S'9pH:(U`'I#߂zD(*M)9Nϱ@jj9KDިҲԪK ЅnU!P:>ן]@kMPfT)t0et9 [Lt戩k;Tn)c>4DL[T^(mBcp@iP6^'א2hԆ/ߥkC CtDo¨sx"|@ZN_:D>:/0촟(^(+5#[V=BY-E%vxg!%]S/o 0\0 rzuF?.Z *Wpvzcx0&hAdڠ Z=P[uVPZdM9A< 1 O!@ANF.J%shzT8O})*yQ ٌ|m˛ J2T[J>[͓a|C $sF),,ݎc%=Pji'zT@@9dAdPrjӍR7~.(]Դй#bi-u·_Q|0K ^O}Jcc퀨Bj3z7L'-~Fg xa2ϑ|`<*55`5<鱼I!vu6}O/ ߖ4l=D 9uyC, ػꫠd2P=l^ֻV{ x˺NbT9BQu~E @A d(@ DPTxBvM A1hҾtVaJDo N+`6pTmF(gI×ޏ5НtS;L_cishzo1.k 5+_)4t.mY$g@2~( 8g2 _ҭ@ ;E+ n,@N7 jTXЋQ[@^f7:ɸJ7L Jg`T4Ki*&*/g Aoq QJz~:UVJo~fj13V~݂`P@hL' + FbPO ZW0*[Nݪ}>?quRBd7pj~qٙs:{~ٝLue IDAT]A/+>" t2\}P5cW3PtH{2p;DSde] I~%Э$Pj*)M) [{(ޏ~p¬O(}tz)ӊe99@ |dtVJ)(J/3B钃 P R=PYP# JgO>Aby9r3bಂ:4oC0@($ɿ׊rv5e/N?H E^ߊgꛢx.Mwc=5`0-|E~Hj5;t^B'׹YjTZ SϜ@v))j(ets\O{HaD3Gt}́1Oh4oH]ɵ>ѾG@Ak> j98u7/UbءjOmI֨Ch%I|%}~Pr(VFL?8{/Z=fb5.yj'E:V1  0=3Հ>6ֶ20, @:|5Ld/Num8 wv(u/JޗG7`Ӗq9B6ž +@PTCa)gg3leչ)bPg A8u%/*C:ZPʮ浓:&?:M[.>e HC[">f CrCZPd:[GV9txUgȬ vL`Z HpghŸ/@C5>۵DP;UÅ/^Al)E. &*Ԙ`Zכg_\V1 tRs^Ou[ }n@J;^ L@U1JR+.s[, חOgLWok NAk,p1O!pQ`z8}΀ rJm!W[ S>` ~5n UPE S(,7<]VE On3<^g' +`ה7~bpe9tӂT[h'Jl 4c  \ L+}oz~ Ջ($=M? -TL4--(M.`TYr/rF7ya|6:X4[O}0t/+6V`kŻ Ȟ:fZu_3$:4u:XŁ:Cc('[; <pP`^g䧢ԴOnނ^{K*Y9p rA#<[yņSZRl!~_(r])+WPgK/Ks;kP #W!r4Jƌ ? Hc|Z)õʚf^Aj!:jt{ԃ+b{Y@M_CK(9F@v)t*+%J9pBy@3Rct:&?LU= V[@n*W_$x(I0AC7kj {pYJ啠+ބRNɲE/ IS3dU_q˥ N B˕c[6mmKm>n<0PgAΩ'/r)^7#hSiF:(TA44n-m`c@h >ۻ`KpD%pmϼZ Уd˧mYW >+˪kz.0w Rϓ—nQ}Ξ ׋: okt5)(׶1M},yU\p 4T꽢k }9N)yͲ)1$.ao#V>0$4g`sQ xH0'i^jX4O:I 2k t2Pt P?CGTD(TT~3.(/!7P}`u\g my}DC@e/}d ,Tf@v(x>=Gï ՉF[QWt|&aM͙m}9 Q h3VLgN=K{a}/ܩ-S3^p ,CַQ''8 -c{۲aW>@ٿ K63K[Ϧ \Wc:[=`#aé \zPJ> ' SKN< Lɑ@(U s]:s|CB.(5*z()v\`5|(h-o[qg-14&whHAtnL[jҹmU!y-PWGdvY Wٚ j7ڷf_ťJ Byh6 ~W™&-npyn;i-2ު^Y:p)rQBUZZ@[z >jTt'ɭNݕ'ר׿ pߕ@eI7Sض)Uy&òެ=Y,6Z&[ډX^^MG[ͦ }'L}78IEj nQWIqhBT`ʮ賯 MG| ǶƚAqP3j블_ ~:chuգz Km>Id3a Ҩ Pf'C=P:_HmF_eQ}R[VҚ6AB'V5pUǝpZpsiLgzZ:X^[n4ԩ~.վ:eΔvf;gںKPKQTTȽ NYpNs`w!YDyBŬ)_PR[7KZ`N:&P *y?)AԩHBPѶa#oTI_'",a%`rVu: tn-k.6UQUm D34/R! ߴ  ] _+:7rƜ@Gyb,*P42\8FO!# +lsP(RW%0|E}+k62گ3UPyf]z'%v8UX\P/$],T;p)ǧ.h;򣠛V U^|aȪ#,JYNq2Ev@i!,86r3 >0ZԒ|}ч>?1RЊG}m&ۆP[>Kpo~nT퟿Bt+"݈&Me_]X kDN])}JQ?4*߻H4}*}~ަ 4{%ͺ0 n:jP@Џ;:=ڰS0H E!1Lܶڗ\#Cyt/];/V媨xGtpe2cjFY7VJv4S粮.i[z"jpM$>2`AT.Ю^kD{2 W_J:EwJrZ UKE wOV=> 4=VRyٲlX-Cϡ/CUU* 2+8tJ0zHU`Լ/ 1$&Wp)i)w*hHR=t7Ek?Ov:ն{^ב>5F)kVX\:Vp@F3$?vOmoh~h6#{U ]2c/Y/"T4 & (Ŵi V&KT45R bchG[ [s?ڠZ7KUQ*N/ 6vX.a./(-~@0q!BP/v @X)igAv} bpVd_:ELUTJap.&T]0池tD'Sf%-}@FӞy7#_jik:@_[ xT~U˷ΏH1PEm0Nt/CZ'h3.}0^Kr*~ʔ5.4D7VMHRYA 4)OEu!~j+ hvNF8n0s14ի4:`@ Aٱ* }O[N{ل56V.W=wyZ}TϢn1@M 0h: f~k["O}Qܑ٢v5Xuf5aZҺ > ȉQ(/:ޖW<:)UYnV'ԗoXtU-* ,=Y-#>;iG=g(iA)Pz+Ny _=m:H} 7-VMv%mT2[R)g^#;TMK+r'QYR[V҅z T@ >]핞-OUbcGjg7?n ,@ .(( ,8 ,\  x;3:36zKƲ4z̙sZsB銠0D(iGe `?شZRuQP:D?l+F1/@)f֗110Gܱ3(.ߍAi DS8K0ڱI:K +4t TMǷ[Φ La#0ӖȘpSF9S͒m}')yN646ήm+OIRo /vle8i5J-諽}uoMl-)!ywLS ܜyYD_H鬷- =h`D`8gLk@c ڿGH(X5L8~>VT(gP֌~J᮶VeǽSX6n[ o{x~$4zt)F3TL봢`` w?^oJ@Pw@swS@T#"A)o(^4!@kZPv2bi8y,S()EH Ch d?,- 㽖U-i5hr ƲXGf* "@m>ԅ 5*UV3#p<<-핁QllE0J6ޙrFQ`'5IM0gK!yZDo1v7ƌBflsu޹XՂ[*&:@4O,3~P>[BG~#vBq@}~zh%3*[[Aay/i[?mBT0Iq,}î̈"1տpq`3Yas|Km%?z@rgBs@T{|@W&#}DPrsO&vIֈ2w0C&\ߑ}(_*̿ȍU P?cr …2#J YR,բzZ = m 8Io)XJqH#}ݼ!md-NzrĠT0oE?Sr+)dn t%|G۠kc J"/<@&LqyJy"L{EB`l&2Bn`,[3Ik\u([)iS×4*}E%Ah: ˌ-m_ʜ֙;Q3$|[f`gW{<\IGZy Ckj3:> {pvDº;4,|OraG/eftIyp RܐJm<6~8D#?v2hFoƞs+a΃?>0g4G @?:_X;F_*b3Pz:5mLw֯Ý+~Et?RKZPk4LWvB=m]NB>đmVExnn=/%E@*ZIW-R.YՕ"_lvk-k2E"(3mm춨a`Xh P# ZvF`|:{og_ (xȀiGh.0ҥ9wjIW028ĠY@4~8Ja)/m IDATPB1R(:YY 8|'rk2u87"|NSE 9fPr,M}> rf'%Kow82 ½f?߉]+ԴΔ|ygf/Yco0@ n &c txn(kA);k7p NJ. l)nWc߈N\9f LtE,W65ġp>UDfd qB%P<E`꠴ ,a#@))4|P]%קno}@)0ӕ[60Ysaze+Pd LQ!TS۱F>D#`5jN_5W9R0s&@{kQmK0;7>⎿(Ե(#L)결 (?œ{ 7J`mz$}9PDk]͂+\#NH- aVktEToпlohfztm B3,ebi`!K>qg,/|h Rf2J`t*(M҇¶Tʲ o(ϺLyR5w+~b^Wj1,/ۿj@(g^sE8M_(!D5ԏmZAU1/@u abr$}7ms Cr N˦~CSxF+ɹ'Ӕ[aҀS饇kʄ&j8IC/+#ZRj Ej8Dse u>nj̅g+65M3ѽ6:et d> nNi;ѷT%,+l#umIYUp*[Js0R|ۺP&(&Z71TE"ڛz Toh`) $qaaaS oaS+#b mD2|$&KtG&[G:+idO@EWa;3v[SnIFaSPHE=ٓ2~μ'׵n7B jX)DKZWi<) u s7IG5=_urxwjak:[:5r!ܲ鯲:IR('I9&s&)Ate_Hn2c 𚫣cewi'A)~9Zf8%Wj]kz?ߌPSϴ7~[w]dP2ψw/ *ʁ(`BzCN1 by[f8#Rgza%@NIyЙG9:fHpu j,=@3*Gյ-gR1:uKC@!gAQ&)7*2,Pag9N?v4 )ߧ#w"7~wtNIcqqe~۱޷Y{yEhϊ9!q4㺰^M E@B j/(-0Qơ8}ťٽ7p%hq,EZ(U%'; m/* D?7Pʭ-T߅ve 5k[ k@Z Yz2<,PS`ߓBi ޛ2c~^mw%@Ca^E.Zsu> mβ*9߳Iv-;~ ?! 8E(#f}|/~7u@BUgXK4nKBa0iH|{)% :8R! 0=_]xO էfuLsȭځ( YF ժ D;YpTfy~2Z =]Z2;7e׬ Ψjk4 :W`'\ckq+l/:'ٺpڹzk%zHTLUjU_ ݵЃ^TeoFgGO"8}P@.\wSSHs,/YT. I5[4雛oCڶ$PYIיּ߁fsAzct^ Cf9w90mvSy cR%k$\R=<:~m]mѷ[+'J\O `g[Y+1;w wrbh p>7ƭi/yJ a="?-R;/9vD.J{:ߋI;"'  +g9TׄuksWk>}c.w2a4+"mg[41t\olQL Xtw00>h|UҮ|N<]CMoo':oa~:@XHmy>lߧ,p ;5wW,By'0etaB3;OKSY 2ߡqq ~Ar>u$B;5-82>~o)~ %pck#Vyg>μ](WtA']`m.W03(:=J S|E'=0#cHQ1l0blkegA$ޙ4zySG n@}G]~CR)N2nL'C{{[+~co-np`̃Ny%!{a5)SyYEgT1U!TrZ ~00;Xgօ㥿lEuk /M 'ڱG/CbP`߸E∞*S1N5 *x# Γ;.Ɔ=͍yLR:ߓ; bO.MRK3Z{oF>-Lz4EOE,YL=?]0'|(.ӕsz g޿@؀qjO7!ɑR9oEn'.wF 3*R}z]ga>~XQKrGh Kɲc)ej{NᛸҾAs 7`ICZuuꑎNt[pRퟹcJ"+íc#JjERZSP,f]d,>8g;RGYVdN魕CFn7{^@)Cì[I'ʏ@PQ Bcc "0ŵZK?oL.c&~־=y픡yuIJ#ʁ)#G:ʊ6&E >5\Jy&(o.~~B&E^y ﯯ8.AM0VʲL>m8:(gɾQp+i>jʸg}S(O\Ⱦplh@u#ZKl~3Lmw34x{tW%*0'@}>,1 lZG jEv؞2@jޚo_ٲl9?s HH!{q<.eT,7i9(,oY@1Fu!'x'@\B 0arZ:C5`}D0F4Z+g>VOJuM([n*N)T?Dk|b uR0CTu2aRQuϭP +VOX~pRߛoxWT` |Y'5|WZXk# y<}JP@sR:; .YRcA#:af}GԋB(Rk?VG P ]D3߁iG[ C)Q-(,̆9ўuR֏>Hu 0$`llJ/+I=V zɆTݔh 'QAɒЏS.=i.]a[XFKVѩ Z;)k7p<@OXPfC{-= ĺQ-+u-Pf}C!6dg>,?-bp1^<8U1΀iw@)Om;j H0R?Dԏ\C@ ԋExJO!8޸: mXWWxa %oO)Bo8N-)>LyI {2)Kd62NvlފJה˷n n&`Z{|`@s˰t**鷀 coׂN5N\ݻ +@qɻ8cSS[NgRX"hOC43 m;R`m ^ޝ`a;%2%4ݷzŔ%jPD ڕV[D¶{AK00b ZKP_Chʶ ~>TꂆѓZDAIFTNۖ˨$10Le ?giˬYS`QY㎽C5*iG"ɞ~bDߘ#-? Jwf%X8ru>S -'Yo6P1…m5i UZI< ER8VgBT[y$$̲ 8NPtkʚثfvFo)~>;۲RXzF~pߌ5; -Qr3]:3fH^w zEAs:} r$z s<Y j:y}ۭSkiP+c=⿕w/A ^ր!?( ?X66=.,vPgBZ}gݻ.7gR:D-98 7bv$M|)3*ƌ7ig7KGPs<[_gUY;Kv/}[kžA <pGF6p'Z̊!l^vIvNeCJH6#d޺Z--dK& em`[w&0EZk ,4)sO _!fAkh>Y#kf}v]s,Jph;Lu1;>MМE,9f=7RVNyFq%[L;g)|Dn6( S(YKwg9`晕p(,/~@m ȌV F h.缴_)*,p'(w.h uFߥ~TVGX'Ҏ<%ԅHJB7ɖ_-#UwT" t:hGsKw#mKlI]fwheEl4ߠ_'π+lD嘸Hw0l"PV?%ĎvT]mjqq(bxKuOfhv/ Yv?R^R%Szޛ5IJjɈx;΀F{D)g )Ez f[ay3L5MYu։\1A=WI`:3`@>s3݃3)s&< rde.!)2ÕikhZ *\D%(}0QS٦z"|%KaM86ԬC!O9T BevM=@eea:6ujMq7yEoW]hWض]MWGM-z@lKhΟdjZwʧ!(`-yMJ{Axq+X HSk={2S@LSuQ24)JPty{{f:> 'C%dkP- L'\i}{ĝ IDATǘjsm,,[\M51h/lT^C~&Dy0"h6>YN,h8J4VBήs׌=ȳFӕy:NЬHX3)繤|*@AhC\Tz 2%M](mKz_bLj 1N90uDzO;?pP4 WS}{-gm |Б5hXlz+4Η@@m3b.PHp..ƧeXtN`Ef&Aoɀm 4֢&A9m={صەi6w:g~lc}ktOسpmQDGyJꎓ<#@u!ʺ} _[68rEܬAԩd,D暕^稇Q@6,,w kit`~Yk[4K@qQE:aF~Tǎ-]1#/#?%i/Z |߶Mb;~b/d#}EsHM'ˬi<)4GG @iGee`_^Hu =ѷ*KQUF^$v8|[m/JL+ff*ł 87`a ۃC5qZ QUbu϶T[vk(8Ϗ/6.[~Ks}Cɋ `L:i_ZinB0.\o{2)migYVczm-[S[o7|TmεiLٖ_JOaPQKF4ss*Դ"w>ؘy1]W-\.w/ %XlePK?k-X=˺ FSS(5cr۸HcqP~4uE3?lL$(Sgق|X}6R \g[G>;?R`ΘFfl/R.*sw:'4W>;Yd=])0Won]x'3`#0uܷPŝpΛY,bp܃lT$l`DuFZ=k8KS}I}5:5}y/I' Lke74/m]C'~>¾'[ӘbtZ}o;^qpQ~9y̓N~ 4fsԴ_Cy?^wuU!U1z 6'TF Ɣ$ZQjg)ʔQ !> 6Όi_J9b(V>rY };^zy|,<:n>ƩV(Uh,M՜Ck DPNefGQ+춶Tw}3zU8p05!z ,լ1>C~g NwB9km*ɲ_pJ Z0Zcu=D4|CIwc>s4O40 u.ˇ!D񧙎g1s;R +8ޔ7Iw: cEeufˍyh>+I&+W{@`NRv܄YnlJm(9(C$e!tn_l׉9wCXPkk@XN̈́Y9ufT L: >Nqic:#i >ﻳ+[ dGKvdwr FqeVZAgĵKRn-"OFdCFE+XVuRn./[&03a,S}} *XJ:9'}?is>nER(g MN} -+)b_ ͥ=7cޜa}t5UYj|B~ğt\alvW \1F:˓YD_S1(wJtgg@wC?B L<+Iwa0Z7`պ _i"S:SDsd2ջ+[9[b(u@ZjwrZgNms"ܾa@{ L;dWt}L#,'ݺfk+0#ɶݶ9G27hwē(zVD# 3@MRC@ JnG 7#R ={@@簍xgՁBNթfeYuP/SYCKn S`\kfSj1̖e,m?jL9T[7@K&n o݋To!/XdFS&DhzNs@g4d|sDkG#j-C{\ԜvIՀ:'E0MmOJwu=ۧCȮ$&ˤ" bLO LQ&{cr 1SˏoYx:M%)ɳ!p@\FۨѳT;45v!1"wJ/Nn`AZ0I?(R rx2Jmhn)u[={` FKyu䛧Ѵk2UX<5@(@ԩ(j&Sfjh-Y&MXqO#;vvSP@00gF&`gIET6<0^mfub%,wr8ě!aYCnW!8lf{\bngD'כ6B0 +665ݯy+sG4ld-vӿLQ`Fsu%?Smiֿ&5oͿ~0 %}^tM8m0} gb*`Dt Y`14wUzXR, aFXxWؖu43vݹTB[~^Co 7픓 `"aPʂyۯEW@Ҿ.~çFǀ@6%fݵZ2s'Wp19PmT(MOrX4XpgZYP  (pbk飃SSfURKl7CW0 Emk2kA'P O2EOߟgXAY%˥Hh~8B0E8YX Z#}J`t DK:~GsP ٔrP @TRcB9M%m6LJfZW9VنKSW?ۥ34=7T۷?)#'$" s0ooº[Qn#2-.u)> <C:jݗo~7l'O@:gDGgvqnu!wT% peNp XeLpZ$~;Jt潆BW6&^gAAsY+~ֶ{LWSM|1g_X\5$kcȎ(Կ8ֺ-Ζ/͐g% 氙l J{KV JeҰ[*2CT>mˮPWlbR);I;#?).?= 8s10j/YDaA:/}aԩ}VKgj l{Z bҤu+X~B}c*g)DTv,|U.=lJ@abka]:iݹkLe@k<۶C wvp(-e&j8knR(ti!ZI G>Wa\RxqF"*rJoiOdS@ovACC@Y@|HM=VC4y }~[ľ ]&Rj5-B _PJ];*Eͼ.nHhwº&( 8!` F 2z7jtxՙ7͵<+ 7ܛԈ 0'pA 5ԝN P:PWؖP6i=W\V?%UoM4f!̴뺑}"+jgOa >%ºuE@Ʋl]w#38ԨWJTҒ]۹iws6\zh 5|]w)^$m rrp@(g,7ˢO.Ӳܮu j~#u v;i~LK8h \spk,&L1MJi `F^?Fud}PF~S@Aэs&Ȼ;1 Df`.mƄ%ZKwJPvɫo)nttl;"z(In/¥ZcA'FL:9D}⦐?`Clۇae|y᾿[IhAuZu4OΏw˜>H2o\~xLo;Pzwxʾ-Jj#+@)jT*lOt'1HV%++6/ֲ9-o塴CQ~辅aC) gZZ!нE~U2Ϭ5Pֻs7VS ` Z߾]D~g rRU 4tűq&f ,u'' S}gGP8 mMN([ܙ=Nޡqs>MUeH>& D=d.Fvh6v ALK|>WohE9M~axCj>*$e96 s2°IY;";K-S@}Zڿ6x} BsH;tC$i}Y龒vU,YFc CO_7~?SOǍDMxDtAaXs,|O`j@XWCdO&&Ahκ"QWgWz둸O|\vq VZ XԷz+b@t0:'-D' N K)`R;)B(`@|v!jd9M'݄c7x[YPXc' ipjJWt,꩝tlsؗOe50HykfZ_m]e}r"hiddrLf¶+ٟT]6,}n' &!yq maNwy`0P ęw[J}Bs%5UDXxvXZ[!{a[N [ ӅѴ{cUPv }@.m%3#-*4=ԇSt^d ؒluL!u _RƭP{5 6#^4KUdYSZU4)>}׮@j [P,=OU-Za.|̦9MņKʁ(`QBhcQ^ tX>Q wt~23[2k䍘SfM*AuJl76Sҙ[27EWC1#kIK锖:6) YV>$+JO;ӐJLLd"T#uK3[Z+JEnRqCP|~{dZDkdnEY g!KьfE@ $fBgU2g5ymɒ-CUdGү &+Ƌi)Q,%<# %Ե7f8}peuJ?/ zFok9Ԏlx3L݅h{< 72ֻI3e8wn*ʾhnt+w#50Zc?j|_?*,$%0pۡ*e֩-}K}=CHuK~Oe!\ֶ۠KqkנNeZ IDATy%K)*Km,mD5ZNw% C5{E=>k`j4&o9dԤ lvT~ IAx5.g l?I* Rr; m9)RF<J&y'6\a㹡+صr*O<Bi'ؚtj4yز#lW{*7d2MQ48kMx^7ѴQOB TCi]^;c AUP\`h!d?ym@sFJWQ Q1<ʂpv_\ayQj ƿLT}nM9%!rWa,FB$ki+L YEf~ crIC-ٔvcRg"?YXPPolQv74RrK4 Dn$_?Xj~?\gTciny ˳'鄶[ DП/PIScG.,*e֫r;$/K,J"ŋfz?S޵53!t3 ~ыrN߮O^cCMy AƽO.|^yܽtL94X]fTU q#g7MXTDU9}86HwO4 klbRi>lS̶4LKKljֽzHsY$%e$oar2|iMLJ' 56!?{,EIT<\o2reF~V 2pͦ`օ!mkNL]^9媂ߍUڏd B[ e#_h>$g $Ii 8yNz0_ TS*/g,o\gҗ?䏕~IH\0”W;8m[2s~i0K6}%Z "@Ɋgꌆ |O,b$|PF;Wi[*S#ѩp`TNZQ?$[[]ɳr x:AH'}؍rEp#))#LSSbr1~_di~Bk?aQG Ņφ-:-'Qjo,Ԟ&-psH 3ʵ? %ʿE{Tk*YG,_Ӓ%j{y'losN`3sǶˠ> >;^E.p\)*5"闞Q̏-ET lU0 '=DdžQ:~Nbц6/_^ם@BNp>S>ZqF?S! ):EW@o(R`fdٲ[S4os*^-JTBnJ1d:i6\r!ZIݝTX8E3ʐzH6(.wN0a>M I?6~qe"l$wJ?R88 )@jE7i/ 958Ts#S| TE~ CŽM' hO7d>z#WoH-@CQﴙ9آCYWޞŒѳYo+ZU 2:Igsq~۱vˋ5t kWk7k&6_|_v3fn>l_Oml36"$]U}ݿ)AU_Mrթ}jsCҏZv:S!DˣNV*t=4ߕ/…PpTiS@4`hl^޷x͕uϚQN:olC(>c-6WJ5Z{}IMۑkk<_Zp7ٜ_tRM杯ƦR?]HZS^tj90MtsY8T=*B*0𗃙[Qz;>һVXkj'Zq|fQ f6 :64x m|]C|e s[Dr l k' [_n|Ċj% uJ}MЩP9Gۣ|R-ЙNroF?&ƭUA+"7 0y/cʍXJk43kL,N.us@_lU2Pu'#sh!/iDՐ[ pZuh=S899_1+{Tt~њ_l6j:ym6dI`Dr sV;D*:.34_.┟gя,xχٓ(@t?Nun7e1DI@UVӔq'{7)ʅJCrX<2k\Gy p c'zj5 R[rǞs~{Z_JcP?4?OR_7աtIދI}g1YGy!{p,KjmA)0>v};y3\wc_J1䮄[ * tS_tT 9_,hJK粠Qtuc )VSX:zk{CA4̱!!ktM栆oC]Y._Z0gmi/O _7fe@Fh`R~*/'pNYR=0=i"UH"~eT!T6<`n dxSgI;7};Ae눛/<-m~SM[.RofA&[ c0.3>Z0ߖx7{ކ{j)$7k9V> q^$9j=2o*e[z_oXc>SA9}9|*k'_\+ʇi?W_{M v# K`YIkat 7%h~ D` eo ^jaˤC}_WN( LњsTc`\S@}s˃oњ/)/N _n*hڇa;[9#[h?DO64>e_ ewڀ҂3I ]1@M[4BJO#S+u/̖%gNq5ۛR[504uuɹ , g>Jn&s> sp!:9vS|]!LJ~ҙw0%yPϱ/- CU;f :;tYqOub+}~604)?kHJy,JN'= e-'Ô.&֗@dTٞUҎ50ݖ(XBM9 L.Q0\Z%0.'Tw1mRvH0gyz.)V̵4E?j`7T(O|s lV|:MyZ,%}XAjKuh(a">f i?K%"Pts35n &e&0o|ݜ9ԹBm.fb(Þ Ao6PJz="Jt ~WƕCl&ݶCb pzZ=aIP>$fBݤ옯u@~x} uRwr/YLj |INЩB;(Rz2ʍPԺ{՜kڿ0ܢ$,䚏5Ky1O;1/rr~yoq0`}2- Eh!z-o&sއ5VTc35cz|˦XDAt]Z/ӨteEm:T՚fk:;"ڤ`a,7k/H~SX2iG!r4g[KFsv \{,^SHL܌*![춝]嶭SWxSB+q@Zġ23赝TSd,Qd)vBczi vC͗cUġeR&A^,Je{T>܇{ξsWi84o$eICt2hZ\ً `T!ǁ)=aZ%ri6s/lק@^f-s7w Z6ϕmU) iҩ /7'5[ $0סkE4=^7_6QzObO>ب/)0 1c^XD~SMJȇeWEJXoW!= j~,8`$,lOaԷd)HA;oaY]0uR6.P3n[$@uu^PV g~ ?9@jc.}vºPz~pdo^nC=zֿ?|UuP}-3俛uء|@1 ͩ-9+4M2_33 cPt}uT :89{M/#'-pMqCt8 7 ~K,ȗb;bZG5ms/C}DNY+v1י!uC0 A~ºTk]xHP79z ([;aǖG*beRjQ# gk2yBS s;g9wqA$n)ME(JuzbUr_uO3XU.ǡҏҬyX@2Y5@8E h?މvJd$'>l}[nopHsuˤPiW8_kvP_6ʾ/P@]f&Q[̿}%BhIF˯.1uqܾ-*?DJn? Dj3%K! l߇7`n|(җJ^vWuTnW3B2 hLok6IٜXhN? "N_tO)9E;iR13;si5ve[Ysb^Wa3݄(KdO뾒CI-Gb@Di`!pB @ZR|_PZ*W\o (x-Yϧ6k: 5r3ѩn>"HKg:M/jZ=*-MՕUjS~i3sk3C{/y=/LkighW[t1YJ_R0DNr_Jv0;(^ <1|t]mwA>X@u,Ϧ?"^{FctGA_Ȥ GgdYb~i)ϠV1_/9'C@TDsY%>w?UčaMtI؀Oi3Ӽ~kǕi%fY!j'kăs{5C2W[FferXJ  Eđ;xye JD{eW K<y ul]\Qf}مe`Td@]Y0m$\%OlHlЯS2@^[_^v]Pk7yQr|x0 FVM(([1'r7 ˍX`A 0wl" [y  yrߧ9T?G:'du72kRZnui_[rW ! E es].`s XVnI> iO&7^;4`^߯yWqا$LqYOS&SOz,!J76բ~RJ{X:7<ؘږ :ݯ{"f<@)% ]Y 'LKR'RAq hPhLOo~t?cA @"kIǖ-r'J>"T9aZW}kq; n@8̽0TjYJV;Oӿi0?ZV =9>"!ZVGxq,Bt:LN\a:f\MJ)Gg.X$,# X\7v8 CKz:qՙk/!LݱwͨIv̮ q08@`gn,m0 :|+=@t*쿢 W%/KhǼ9-7$S[p0AmEsn=@C;p=Gu&֊#VnϨU0}N]q!u6 L#>Jۋ&y~+aE6D і&@rR'h0pӷ?{b>?,a!h+Pc0ǖ? GoPn)NVXP*]Lˉc淭Mu:e"*A"/x0}s/viQZ"F#B%aIv|e{/C~qXz^cZ}v #J tm߅ %˩; aq͟!̵,߮ {!] u?Ȇ-i q!04Х΀vHDľh#ץw?)L%?W;_ 9m>t&j+5WsXY XaJM,)>~ 8̇sF"X0=azE(Hxab1F͍; %@ݮ8۷ǾMkc~ql8uvձxO>𓅖@X!w9_5Y6+.5G<'?#Q: (DKEix$>`^~>N9AZ1KԘa_=~PN&q1:>L/lYoOA=us``2xdpH[x2+lþT^j;PȹlxVhyQhY [1z7+5_LPc]* -ЍO9njg)+~4:ra! g8ds Q:Wrc C)DחAq5&Nwq }FrBIODMyxvXM%80uy5kMAX}_O´jyt}#&1ϐt1! tRDq&sr_9}N|5g^מſEV7A"?t('Zhɠ}f4d蠓fU(ݐѢ rj; c-m~bJy9C-=>W@갯@xm#Y]GS RI:!E)vaڹ,@.0=ybO’ $J>UA{佇(|x\{)VV~c_ N7;# E˲MO阛9Wyx~E=x^QLˬV![ѣ=Dq"’SAz';cnldC\ƿ}b̋3"&g =DTRS5E2(-FR?{5 2ov5aK#qenD(_㱎NqU6<^΢踻4XccxL/;Ir/8!ʀzH QjҤrkҺ|W~%Ve"Fh[6r[cq E٘pAj DT+_l}s 92O,tGVYlo%ݱpܡջ->M SE )OQmt8ZE6ҫ3d0wst|@!,ST: ;lnҢB4sfyJh7^+?0_ڸy Q)bqzCK.vQn,#DZnϴ-ZEBtNcb{̟{h/'yYPr=HBU8y ܛO9g,Aht $8h'h@Pc)@j^EI0KNW}`jo8c=4h`FqVYp.Au?m~ژ7y'6++WDNfwuС >(\jʚG g.-lDFg, D"죍P@DA' 9 \ )u\>l9>)JMGRߓ ZѾz |#arY4f'ZwK&* K`A GIQXX?MO.ow4L-[$]?Kb6̋ݔ[nqImK<ĽG^A LZ/^^T^̵f`e o,#%n)M Qsf'AogE*M^j&)= y!68r~yRGLc nXsS㪬}lƘ,3׶O L1ZhsllQ.#z/Q%)[b[?/6wiA<+  X)E ~Pʇ 5Bw @]\SW y\-vێxi?@-U6shEpbCsΉ|,Y'v{cmXQA_re% nj/۫"zTR3[T!,1"ӹQaCI&ݟ(&I g8ApV+=ta~.$)E,k[i7 %kS3l_pOœ8O߱\yUVq>8݉9VQr@PIϱ ̲bZnwA[|W d]_Vxv揄Nq6~U- Q 6-J$J,o=~+r "ma C7]$_&K $q!f R95 ~[ؿpȢSB/ieDf%tmf|sk7L.J쇒TtXrr|8*US@6 v,f2Z(F]/dp^6´݅ąy@?"7>Dف0MLOiP_1٘SoBݾB9R6Qn7s7ϟ;gPz7 S. h&1zi0֏L^F.H|(mZJ.!J!&4ߐd1ȷp~K/pi.sYdžև@u"^x'.Vzy8i]8#˯{! 08]YyRci S^d gDyb''3Ud T)|x|seځ99~a tL=Kfh>('N[4:|kt JaZh XG^󛹫=z ۯ7?zێL 8SB1.29)޷c%D@1vPmA[-k I7þcBU.}4AH\iTGD3d Vn6Y:?li(5a TVV`(YFiyk70Ż6 :2M{QbǟW!Si)]bs++G(8aZт Ӯ DeSŵw8 ncm=*P/yo*|!L @ P?~{5FqR ˸/D ~'T%Z&Lc"oUW=XXMM3rR)%%Q^=VlFxZ>X_&ʠU庖 UO"_kg NmS3WX9C[\++n{^SaZOcl-949QJ׍;Q7@p lq_3"L l]m0?J%qlk `)nxA5,pW"jemH|A8Aս!.Ki=`p}G*2NF!DGmX_>jf| 4Kf+Wɥk0ز*'N3RxlcXOC fF@,4u P폿`ܸTzmV2: aJ(O VaOT<o?zO(g`i S|qRE^JXv xh$ c`2 ZAnvaZG^-ڸe}ۈq%oo7pQж^,/UρcLh)[er9glX&\@2wRPVk^0Wɴ:M~{췄[QG'/Sqgv ٮ?~:8؉݄1ru 4Ɂ#%Ĭg *p,?Z0N|S^J#\jR)~xK NbۭXfWvﯬ|~Xajʑ#J+|k8HZhsV6[1U'L[YrE)Oȟ#HJEqAE)'N-t1IӾg?!@gs_s޺VT6XG2dpE d|>DҢˠԧt=,g)ͿnM(?I ѫ-;yQQ a&檃(d.9xrqBplR>\eIJ[~*'cfeNبߙ5{M[M{a~5+Xgiq4;#ymوEM>R{m^h 5*;S9I&~"Ei Q!VKs&pIqǭ4XRfߏJ;G&xK1rVO6qIDATAC Qw@\~30'L0wF;c} <.POzl6nΩLh@<^f@sYV] J|iNҗ`-w´=ۋ~s)OL2?C[E}?I1Mp,CqUR'L)fca"؃@Ю4[D Iuq; i?W`+N83^3)ߴ N >J^F06",xSQ<虙[Ek+'D][ӱ9GU(i<,L(!X627p4 $~Xc1\߈P(WƜ9Z޷',;hšyܓq}VyNE-.'6^u9ލ [Z:ο7vz}Js~'qR,N;<`)e]e'6h4#:7y2knbq)+lᶑLM;*+GLqz.E0NL+g39` >C)ĔJvɪ}^BClRt*~rB[d#/ۧ2.oP$<Fqёdž 7XS.W2,Xbb"5Yi)EbS+gB_.ERƖUe%+u eI9T[Ϡׯ?<4Dc|Z(L1E ,'0E̚ TVlkNv޲l-M!BPS5YVp;jCސX{喒r2Nd.d2{ʳ~[־PJ9;/v<$|2r=BK|)su)\0yQH]$+ŀ^l_@5ڛ'6?@O~Jܦ}Ir`WDr]r" (=_mYυ`e^_0H^1a؅hжDu䨤I(91 \Z輂|#BpHAkb.$ B;\ҵS\>D8]rr cO( It`qs|.&Rs&&&[7*)&ܰej19")l_ꗏrĦ+_u (̀;*S%a?\ݥFgjtg8/ۏG_.g*8s䎶~j΋mOcH`'~;P@j7} >e~<3V"Tˡ~~&+Uu\)b:d.^^*$L|:"oA:F:,{\O>jq8>L@z E y+p.?$ֵO~C_cS["9 Ui\ih -@ @z.ur{Ƽ06oa :.PSHoUGؕ ̷ 7-tH{:xاM+z"(-cs]4]%=aEe *: *r1!; >"ϗ&^ 헃QU#u$[CJ,7I>/aM2ꟓl\vdE* ݥhpFJ&Y?1`nvT|&ģ.!*;箑Xhw7OC2!UY\`/ `H{fGK'D O6F=vPܓpWb!w3Yy VYRruY| u8R]f8/3K7gqw˅PS,4gm#䂿"~]H so$qE|=8'sGؠt LVXµtQVkm C$x,)T+"aiΪ e ^iK-L%Dq뿗zb.3Dhr{,'DNt?d\"XJ8-2H;w-Yf|un-tcg>|եJ RLJW_+tN9=q偞1-XرՕrJ"# A|ya`w3bt|QQ]wbT#jY>"!J Q"S!+J -%j@)KP)5D]QC a0ysVdw`"~K(1ر@LNY˽5|[*?`MwZ8 )7pǹD)|YW]$=CK%{'8g;$&JUmvy!nºlZ00u)!I ß=XH1,\/RRaZpA}(%B4t?"bU8$[/  q߳-jSS&"?7s7a폭-b%falU5bKߊ N:@Qȥ9,} !ʥ8-YiE%c(O1u)B 雺dsoҥzA4s, _ 0O0- +&d~R'.ψH|vq.]|r G\o-ۖϓkyݳxB}6ieٷru$sƬ3ӸI>vlON{'\pG`><|Ǖh 5k@o.5nD`ؤ"4U8,,4V\wO`sDA*+ͩ//O*Ќ5[3; Nj`;Д ٴ{24_[JFn| _KzFYB =bXvHVa6oj&n 3rũOf#e5&NGV JY^MI(R"<.*x/ceOK+ܵc/MYFU0huJEfmnlX{{47#)s1mehK?L뺳R܄%gQFl:ZqVR,H[_1zW^;4jZ3ZP"UA7.f2eb6(H:(}+O\Aݻ𻯙e]~uø U ZNO33߆<|lБim93Yjd@)ˮ0ګTR͇l2VWUUEDzPtREhM>S<(+ͧ:\#ۦV8ʂc cXV{-dvn7d~rBT|2Lx9҈"p:$4[i7^`?z^͈,5a;je>ݕ~`F`Z?E.cԙ"u"flXQ f`J U ؜d{j;/TFaY23ݼ|6O3I|UhzG^Q5Ol(-ʅ? #Uq@\9x)k_ݵ-3 g&{;k^%Y&.PyU&Fw"]XX  ,bIINvN,;OVRgl"[*qIU?wk)MQeJגe+64YI;(*0zwc.7rM~ׁt(5'1K(ZTt@ZD?(!_ 喙(_G9YV4G"]Ւrݷ"5m!-E$ۃ킊h^$2mR(r/ey߬sݏan?'b0E *{_VQ|(\?,y ,<͉8-QmDfDϹ TT*(_6kAiqJ8iecQ͘@[o?tPuUd)h[uZK;6UaRQEQlAl!X/wz,;9U :fJYryT *%>>>>>?@}B tCCGGKKLLMwNNPtSSUUVVXXZZ[[]i^^^^^````c_ccf^^ffhhk^^qqqw{{}}}^^qqssSS'')),,..0044>>IIVVXXYYZZ\\^^ddooqqssuuwwxxyy{{}}UMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDATxS@z+(h"( MRDDQ91*yne)I JiwQ|e^ox}>oWR+-bl;瑼7q݁ꚪW/TVUCS*v9*YeݎG<ҙ!׃("("("("迉NwU~0Yx]ȋ|aJS?|a%8 _X>?-ܛlq8 qqwΒ0ݝٗN󾮾GٟDEm퍍ۭZgV"q~^{t :SIhFC E h80(PTXI`@3Z$NMD[R:2BUY*aT܎Q eTni+@eNfk&j[1upbfȦQôva҆5upMH͜C IDATxyE5MBnKV[A"n2\~2.p*FTtFTpAPq܈ K4&ȢH@͹tj>y<9ꭷkyW]'B!ڇtn ^[B!D|;?f5o,pk޲B!9n1v䨱XFċp3#B]=Hbqæ^iX}a  IB!$o7מ:k7|_Ł'!:kyJx^%B)wyK0ݠjtں|қk0\&܍{"Sڧ'9Mޱ'`ѕ Qʴ,; ϟ㪨"ny}T2F xeFKG~õQ+2IG.Ȕ襟0NR<-mx'E{Ō-hAzC/9oSmiG4`O3onwc]8{$: [qO&|vyS9fd}Mƻׅ=l?nI|L1v pLꨠo=~ ǖ\d6m,Nׅ̮ԆĦ~g;6cqJ/i~vVpۃ[TLRM%ְܒwDn`w?Z޳KQ'dWk5 agj` õS`w+0=8(ߟxZóNs/,ID')v|8s߼n3 aCĿX˯a։g7}OŅ܅wܼZU98|Lۧm9]tFY9Fv—^5k; xv{jtN||%~pU[IӧM_^}O7w?jn%*w''W\O]gƇ©nØβ|bAn] .êweNm_%~)sB^>wଛgZٍMD~Ӱ|w l>l-^m#~z#sZڪ= >d}w/N Vg0uY:080V. ~TR * jȌ 7ᑸ80bŧ _}(&CO ]g†Va>GᲯe}ԫۿ61C8ó-c\ۣxG72s'}Wϙ8wq'b*zj~q k;+xbVGC;{ŗ̓Z{_:Gt U:w쁱3Əx>M8ct&ϜN|w w{Oޏ /\uln?7)އ/~o\|;j|#3{{6_:n<8fQ:/<{d7apxxk?/~'YX{{Vkf~(V_m:e}ĩJw0b,^wkß}_]Ƭg'E {3Sm3g:43 6J_^/Uoݏ'OyVCmۀ_=?ZU7ع2}#3QËǬq-x~ Ϡ.v=ߴ_0{u`ӦmG)4"O.漃, g?"fG2N1Mٗyޫފؿglx_];tyO_ookæu" 3jãvk:pY62F}䌢Ύj0R xk)x6~Ǡmt>]]ڶ}DHMs{8qT 0`զV@T;f;/;Uހ |ls+NS⁕}_z ~Vs[1nx#3֫Nbݔ*}Yh؈K[ v &L/z7|kWk}%wU<ۏ'bhd_-?fmt\[y3:g>p<6Ώ`7aWMkqV|]8o*3ށw,lB[lMf lC:377xgaG>iYO^!]c,Ho$kT;0}^}>W\q9@6W\q84Uv=u*::چZl7100Ftw$bl}AtoGc:an|۟8/?] ?؇Ӻ;`s[6}BG#>qϝCO޳@0z އ5)0\ <۷'Zƾ곝J{ MMw\cv3p~89xŔpy/mo+sߟߋ;:cg~A]:ИyKP3w^H,c;w/~ zcau;deW~6 q_D1<\ tch'$,sg?tk*;\#K[ 6o*:ڊֶVbhx[nE_PƍmI 偁l1Rp{ n1ߊt?z&Ӻ;1<&aVk܊ @e#?G[7^SZOa[1vt:w\w ݾ?c[}# TW*Fuj>t:ѿEl10,ԃ^rjkYozv %kZAWKÕ GfȆm <ڎ…ڈ+Ox qvg1;ڴ,z\,ъe}Sݯ/AEtO֭}xMCwu?\\j:ZH//PæM[pE"#0fj>|4tWG.Zg`?o=6~Ψ?yj+lŖŗ,:| .;esՕgշއ^'e!MsrAt̙q5;f:qscsR6ԋշcpRݪʹON!c0noT&=ö>b(%l@Ǿ{>CSG; |[zϩ5YU>i1/7T9&  [k=a``pL-}:;L"O[ lPQTFfZQTeDPTPiipS1v8(IA|>\qh'~o/5H6?x/+F.oo>{ N^A1#o U㞭=TԞzGTNSj0T*mhTZmcYuk6 c䑎snf?cp>SS_fjǟk@[LǮ*@mL/?[+r^˰2㘋oզ#{/ݨM?2iޫc'MβsN oاGی>n *4wdM>TQiBncܔio/;}Wp??#/և;oylf4Ln hh]?^y߂z!.=uXr>Ch($mS l#*ڦ[Fe8~jj]6n3(TT{}شwm{Ki{m$@swVۈSce;TuIU#s.Ntː_q<}Q:ٞREy"oPV2i 5Ԇk8i"tOAggt5q)sqYLJ_obs5s'Zm래Pyå𷏣mm /:|i<7y7\'3\V:sO~Jq9*-]Uj[q*~N_'^~\m3 >7s]$0_'jh=JeNix)_q»Ϙ;p76 Ֆɸ_6aEˉ= ^46ooKt؏vWO\زFԶޅ oYYą>|åW C1fсJϑ4wвωR8ҁjמLceէ'g2k@m ٰ ?؇W1G-3_Lw4_c#+ =7mǟkZ v_&i¦[coXűǎ,uׁ$Ԇ%.mkq }>y%~_18U#zʯR =mw))Jw#Uao ?/J"n hN2?uryّ0PTF'VwZ cǏŻW<& _$ZRÃ}O)/:W1 cZ?G{;+|vUe 7:`tN ^|pԣ񭓿t88m',O_9!ܿ)\sѷNۍ)/[^<g^qN{ \{ц &R kWކa$l}KnAu/\̞Nֆw\u#>s.sN2$o*#x/OpSp+)ggw~3؂ ?i{wl/y>yЉa^G?~.<\|d_W/S°i~c፧~ױزy[[{>* p:zm}vN_nElWtxޅ-np5=-򑈨նlae3}tFt`⯎>3W񗯟mN֬mOr\K?)?n(Vom_"L1zqsAX;lCDmk3Obj5ډJk]3}ϭۈJ[}(FKt6܌nN _l=7a3੟,vR;2drmc?P?c}awz&FGϯG0<ЏJ[Z'BN<-Ӧ#l{Q cBݗ㹵60aС`&c]y;lBmA)蘶Z:@e~/)3ѻi٤{=:}{ש*C0>4tNֽ*@;G6T;'}h7 -{[kQWea=u{ozAT'utvJQh<Ѹ%CUnei#k{dz%cc+*mк\tNcP4ިPSxB>mC]o~ ӽ^} 7w fL}/;lFNݎʸihm*&miN)Js(йV`ch}t?mAmo$Lɨ6PTiruϗ`ܸ=Q۶ed٭u 9" Z݉9hdT'? oAs-6wA~@kjZ qtjgx&貺QvAeWa``?3>cj#z;=Ȃ_Q:ݴlϵ={ַ -hOՃs{0xCe{Zg4<OFeNF˔Ј'z^MҖM磲ۡ-#2ΨOhk~>ދۇC&GHLT2iLGXujZgX.=vs:ZggaDʨ9WS6ಘ`wӲ1:G^xߡ8G/ GځIwۃX*EuҾФ k~[2y0y.fS4Gl}C7Hp*@,$6X:HnC--Spg?emúDBH;/>aT`̴ɨL<vH4-`5u$mFK;~Wf5v?]rB#0ups+!M#BxN'M=H!emB=^>CLgvȗYmAsIB!DvqY{ͫuuiB!Llxoh$,ظ~EeaѢeE!%v\):!_l+79>]"0Wyc䩟EN7ݻn5/YjGLVsuL+QL[nX~n䡿}/ٙFyՏd:"SF^t$.s2|ѐۅM'~m0K6jI?KT%QMƐ$|hcN Ln71Ϥè‹O-O6Ԕ_+B!:d 1C?|5LSI-[9JcqׯkTLǭf/B"O2rYBu~]7]l:(M<ţ˻|eȦGUrӑgSMP^ IDAT0ŷ|uz4}Ye̿.}geV3($}6fS?Kg|.HFXj;d&\}( E4?>].'Ȑ55]}J>|ɗŗ%$l_* &ܷAm~/g#!W:.EU'eڧ}OuMߥ Q>1YʥgN_v-M Sxd7BWTTiei@61;b rY?lWD7KtdͿK6Iߴ>ߵmP>oM5>ս/UYڏIl3u/}ENUd1@3Y P=`VΟm#q}K,٠;3.6пOHۥ}H?4.3"BV*B˲YϬi»Ɵ' e(P1ٛhR|yZ1j)+4KEhL}g1e(bɳ'拦6ϩ,2,U.cdR4F/wi߲pE%6?cѯeG(|u Ɇr,ޢE;șy"(|x#"!!1_ńz!h)*\c?7I!_!i Eݲ >A5k C$lfYQz6muT?.mTڒE/կ슩n|?K6I?L8di':J?fdLOː|FVv'&!M:cwߵ}g +zʢTNtlGiKץ/{N"~Τ߷qc3Z0&㷎<2}I_+ ̯-_ ׯݳ2XdG%J.{C#t%5T1HbLn]3wj,^4F&#1s7lF5f+~5~cKŒgcw!BX(Ueѳ0k:dq aH iB!SuGi2}_PmtͲU~^t?㚆yaB!(:ѣ_FwrMuuF.OcEf@uB!f4lhF0$B>l.Ϫ:_Tudqu9ٌ1!l Ťc9XG^Adn{DK"GiLׅW"Ggli<BH##]zNLeXb5Ttܹ'Qeԧ 4 !Dk]gq7y6졏 !BFz9MS!OúIQ-š>~l"!Ҹzn$l{(Ÿj|B!DLSE"]>B!ء2KY4epƬ9¡y&B!Oe+Vaol#{&~ϫӻ:KvX?Q46~EzQ$NrP}uB!wuxRݳH EB!l EQ@#B!?ᧂF i || W4Pك(6j` lR}JPeÄDGW&2+s690g>l/3d(s'( E,3k|>|OmqbS^y֏3S0xTGv^L-BaR !;~E jGgvS>1*9h.;_,E_ (}^|+X!,AF"wavyYM!Cl|̈Dt OFmhN ZLIWUPe*cm}粕dd E%iNֆyw/~ -[n(莅Bz-' &qLC,MO4Mk,(!͂PMs$}i5-/b61D?:Yb5+<4RRDh:e(eMH,\0|*l\vbwJSwj;Ԣ괭 4K?ߢm›CtHI۔ꙬGF!KV/dcrgN>Yj&ڪM:?-^NaRt,Lӈ$$+z׌],U>T$;R,AeSc%s) EBRHdsc% EB"24+etU-/LU|r&FA'(?揋!!ӟA 9_=CWC/RB7&,6OY7&ѝ^^嬫?EUdY뗏B؏b'TFi ҁcԟ1l/B!̓W!iFcE̲ŊKI!A,&~,&(J'3oDY2b2|mYQNuMw]OOv~B`lۢE˄{dh@3K_^SoٲE}v6؄U/E?6/5>=QxYe_BcCv 19$bbe5Bz@|ɐew_2lVv#2ld1}_d"( Eׁv99졏*5eFW|YlrD! 2W踤_\ݖԱ՟o|G\ h(r6B {]gwL?fbG 2"MB!Q8&S#W&3~2"@!yP Eqϡ·3B!Y,\0|*l\vbwE3,d5!BvfC߽Vc񒥍GцEy ،VB!'?dgTpӧ ٷmgT/bË~w^(|BLܧnOl>}kYMRv"YA(_qer7"C@skYۦ]-rQ~1RCWwчI'"T : &/:B.2$MG<\DPу+Z>[d[^}StibO@ð UH%e?tR1M_ o"_y.y@H<(](鮹"[O"MNW,}^ZW\#]&td( z;Mh15\ ]fӷ^b|WkmN[#F^ۇj_d7lG|2Bw4G6q7F[ײʟHrw#5iO7c[chucWϢ._YWHbԉL&)sLEVckEEoKlgKoSt]V4 똈M"dKv-3mۀڟ 1(fE65,MY&Kp1S.g]B,Q>NC)q\Rty(Xt/:}SL%tKelGg(lGMs,rE_{E]4򛠛*@gE#ʐH2ΐJU%s{Ep1M){Bh(gUix/,cdDvX[lkatǭOW~WQ"]liixLAWlH.qf_6y?_*)/ċjFN_ij/ҳ 2 lM#J_. 5*h@e|F+kZdfj-Յi慩eYmgǬ Y cʥwn?&ԕW8leo})YWviϺ·UoۺQY`~mUظ~F`T _nt(+obϟLgt4˗b6wj,^4XL!9ݸ2QAi4ĆbS϶Kab"q.3v%3!Bi EeEX7sB!EB!""!B<̢Q&g+*;Y:]7!BHH㨜! 0si6g_'.B!$.DqKy~9æBCMB!3!Bij5-!BH#4cT 2B!43^q\l?qmxr)B!e[y9&'M㩓 [_v9UM!($1! #{hj̙OŁvS\['Y꯮_HcPMN_v4,M7urvHfȳKLSd3>缼!]b-d\k(dr~==١WWi6b-~cnqv>6 6t1ub LhIf(iүkz釂 B z Q.=H Ŭ|VCO2|UY&.uf|7K*zD?MY۷li+ 'o_Ey3 ӏ!_^=WvYkH?OvLP21N]Vʑu*}۸BGs~MTlnOU>SM«7я.~ҙ,{ʃ/s(N%3鰪K۶5]x]lw#L|(* 0L.&L'6K&4 tt/ɲR^E$"N,uU^QO,ȚE9>|ԏ_|oiml$"kG:^[SFN=aZQTGGW<6 ˇmf=|3&LfDͻ|}/ KxEf]/B+{qp?RK=Ȭ]!s2lwt3t#&Ft.F'tͣe"lӏ蚄idh(fbt x]Ŭ`N/嫨mtʮXE,rBTVqtUyڸm7́.=\yWYOZ&BOWpWe#]~\wEh(nL6@ [vLY!(PEeKI'Տ{ٹ;"_h3E֟b* ̯-_ ׯݳظck֟MV7ETЦ\C?gdrksBq4m=&YITg+-OJ%vuȖ=+~qѯIH>W=gSgi˿|&xsm6q'*MoyF5{׭%KՆ _o8 z"_J] ZA#RVqrgɮ!yz*XvI33V$n($dGe߃lZYÁ|xuqfF=oPSe 9}]^,}YN&}L![!͂~\Gh}Ɵ_D,[ۄ"PC1`Wc5H4TlOݬ"!Ğ BQ!́%H/ CBH Eܣ( gOXr#;2|e GMtRdO_d:?g:L7 o#/~L|ؙ^'CWDz"NFǦ|Me;LR?U᳤ke~RC1ˠܛ"jdyQK^?uSkG{>{D36F?U>SM«7я.~21}Qsߦ|t寓7v\NgI$JU?m*J'tugiµ|lO'ۙAUe42\l2^؄Wőg VqTMT GGzFŇ63,Mxv6||Q] %/|Lanz.At F( 7>RG=X~5]QgM_E?LgB`R>!WU M6F?tʊ4m31|Cbt]0MG'_bU>˸,3l?쌕{~>61}#ʳ|+nϥKEտ=1b1'$BCѴYl?]' [L _'mG/K)"=r6(ʶ >DW?B/e2z; 2ʢ_ӌKMe+Va{VwulC^QxdM329|l9asX!JMSn0k2ɟlQ?tկڂv`R>2TOWm**I(//4dy?Kϙ?Y崍ߦ|LَiDлfwXdPTkʶq@޳ue#i(QOb ER"C1a$ȣ!xH$BLb>_U7E̞#BHGd Bi^dYg$ X ' O! n(!BH9P4%=Y| !ܣ[(/s&|Nw&~\\Rŭ_OGO*B!$P4qlUf|:A;'0k&NUf]u:9\BB!j^,zfG6qh}B!$>lj(zreb IDATm!R,RCQ?[E"[mu^~B)="T{h9NߔXˏB!qܣX?P:H4j4K> !PLME:}]EGǶ|B!0KϞnW@WTaTyrJ_. 5첼|4 BHsSY`~mUظ~ś0[h41$32I>ϥkB!лfwXdxFQ擯cbPBHt1,#,+R>ϖb|Cؐp[Ea^}$lhgQ4z.k E@ܘC5_4y~g7M(b3 6} }Q'`_X$e۷IsuS }lvc뷖?)) ¥gsuDSF`D2T5}tu{ M+!L'z^W=L/D)C5^iWg7&4!2)۠ &/_%cI$kC)(B}A(Dd{rDSK_LMcW"?kt/B"c9=%Ÿ(KLGKYm*M,Ƞ%1;Y_˞I g?CHAH|gKl(!$aU1OvȮF,=Y<೓J")[?60*E ^=,NY}=*~ˈ++~hyOd CHT._[b6_;zgr3ur-ɞND-ӧK':U|e2[lzT4T2WiLWTer:ҷ}.YJ3 ̶otFǪvQ:.Hth"tm]/ k^~ !fC߽VcrC1vB *ݳ@\tb޲q4E뽮}A]7h(hCL.2w&3 4yiWDP$0"57S!^nAgH9 c<!5~0L" "YCos#+!4>޾7B!SZC[TSůʋ}Se%Y_LVY8w<3)Ux:?ukB{Un6q g':A!}]:LFWT Y7Πbf5Dц!oKϾuaEu&}>BEIH4M|G!zg+ѴMl"!,( *3h4rYyv;E˖E2X6Bʁӌl/T=)F(7TA!p0I}*:ߺ]R?+^_]OcBHd>HęŐѥ'sϒ~$ONZlrN瑆*!u{l]f{KϢxϥwE?=96}2w.k*EiٔJ@fo>/[W,K>B!>,\0|*l\vbwE"#39+eNH]͹B kF[KuC٬D3ҳEz `BQAC`ʺTX6yc"ݹQtrFBb!qSVC*$1(~BHd:W:+6LhBʜ<~^fe_ x3!CIcB$ZCIP$4O?o=4&>1ƴlq' (}j&tֿCiXBO'I&O_!so!A!M.(3qu2I:tӏ|M/K*:T_6clNBg]'4{(zME? Q3:dƯ+2bzlC#B=NwE*:}[),u#|.!4.RC1 N^˖~u?QKMg !$n3=v>уO|IBH(if-Ir&|6ksM:Wc/BiFYl;m@":ժBwJז<_?k7PDCXy͎!BL"!Bi|5Cnk$B!FyO?9sʟ*n?GUx:)&BHH Eѣ6ʑn[(2ݘ86B!$$o= (ӯIl. s&B!yżgB"!Bpۡ}'Bѐb^>t{6cB!DEqb?a*_|Į'B!4BCQi3ç-/t·~!BHӆU/r2kMM&{UqNSEB!Ie+Va{V(ΈQåkB!رwux@TCB!$1 ?]6fpƕB1!2-uk(ep!&B'Ts2.oGNuKi-k7DQ_!! G1LemOB!85e3z1 a1B!,(M| KS*_S]]s-].~* !R@nDru{,deZ>&{PG2 =6]~L:#B=Q`Եn4^Bi. wM{؄B!uh(zl{t{N !'C+j%g*S#C#B(2lf|RSk.quu.^ C!5 זX׎^Y ﷐UӘsQgJSeئ֥I_]-+ nӸBH kF[K 9&͍rP$B҈ @$"B$BDo(6:1 Xvw _v8J!Č ZƁ8OCeSh)c"AJA0P.T|OТkφ,?~~7f9/#!7Q$ =eb(Kl'Ҝf(;M?4ZElBH9QkR]_ON~ut$~||g9~C!Ku5|e-#B!}i/]82wr%MQdG"Qo2lS#әNTFH壒.I"Bbҳn u #]u4oIBŭ:TQbfL]!R{`m&NG 2YV6B!P,zELQ͘XwߖuK!EݞPpAQB) (uhNNKxPB!cl(&ہJק| Z=*~I|Wkp%i ݾ!4'ҥg3uBS)"߽?8m̊L/ "m/_/R_]&Z?ttDCBHT._[b6_;zgenpTCrٚBȮl]3wj,^ԯ{,RC !,n(,pFB!|0MP5O!rP !>(%B!*}B!4:NB!#<"r!sӢh(^"C}'B! 4U ie_9b璦ITFa2J^B!"qZzbB' ! G16+6B!DEɷ !Bb! XHB!hؖ !B`l(?:q7щp!O!bt9m|\\҄#r_L_&c4D>$u{GB!1SY`~mUظ~32G͂8\&B_6ݻn5/Yaf54{ !RDGB C.?b E`\T>BU&ʮ AC 2(9]!K=|(9iLLçBa$O>}S':koq>Ugx辣^4i|Z0 >gb/L>3,C?t:U!>Q?gX]Ch E_AU~})l/%l^!Ed{tMkB|%tc#h(F3cZ~:ԏm(k+[ ItmGayf| aSM‹H| Eۍli"閆Ly_bKzkA0IQo&fZ?\,gvOIl|O.Mz|"RdhZezZ74U,p%^6d(*BU߲K>YmM|jE,(ZlC([f}ܰܰ_O_ 2ZII'o\P4*}.9"[z[!YAQvUfىb &ޙXzh LQ+oҨo|=NhYcPe,Ē&w2J& 9,#|E/!2 Нm^u ~-Dr5$teC.Н՝r-6y _4:c̟mu!!oz ˥}RTڿ3|c_'!]zm KUxQ\E eW%ћ.eIƕKGiYC D#mgeaU7}F%_+ӣ 6#ESzbֲ1Ȯ,3}?Ld)R>,S)';SY`~mUظ~3DnO>}R^'6zQF֯i޲/>R>4fɆ5{׭%K7 !ƿWu#vKCHh(kiH !a^V7#>uڌcgs1`#{c!$2ql6 t S]?"d]c-K<>ڧ}'g|BH E$SHvMWؤ/MN1Ƕf5~:}Yۧ _K3!$J5Cc2Z"f˒f!qhzCoﺥ|yYd+: տUK!YhjC1fh(jG!$b8E2 Bz׬b2㞳<..LۇkMcC1t'(:irJ40JlNJH`EmFWj! !' זX׎^Y @K/Il-:; Y:bxlgL6toClAJۺOkX]]N8;^&%ߴ|t#qkZL ><OQx= HBH6ݻn5/Y6c =8B,ˉdp#獆"!$"C1,1v齂1HFl 841S^_tmB!YPQL/W‡ď/_}t:?dʗ7Y}jīuKԗ2k4alS?EqBiv(9Unrϓ eK!e3icNT>&Z:ݫs=/&NM6:cY8BHL/=:!Gb:a[fHYE3!Y1T1D!+8uyϨ4뺬guGBGj(Al~]3ѿlߥjT\^%3E#tcկ9~4J>!4.=Yff0+ WŮg#_B!f1ӝ%ĩjuM&Ihd2"G,/%ҌT._[b6_;z?3l\*3*>q_vOǜ(~F1IWܲUoZ&3M[ am${a&.l y}-ňB kF[K |͈w2'iInRh(BHD{:ICCBMC#Bi 24rXB!@FCQD2.fAϐOqLcH,d ,Bɂ'Lb$??n uȿ.}k>eT?!x5I=ۘRI!BRP(3yĵQFl`[7{#BLQKU&~ܲ5'c5?M$B“0h5*]O^S9{5;/dΧ}r)B!œُ)TK{y:3>җ(+3UrⶕB!߃{{ḫf].!+JC1O"AM2T3|YhP2"B@3plT_\!I>U,iY,+e"BL~Mvjh8UmLO>'Ew ht[BK"cH4 Yi-! oc#>:, cG~&iB!,\0|*l\vbw(!_IYх8!cC߽Vce)4 !4"Caue^B) E~@Y"eЩYW_O%wٌDU+!3*v!:,Fb&\֟yN!F&8ơ2LBHf(f-H4{]iv5{ !āpYB\:?6|/UOkQw$H߲{}#~U)M{ !ĝ{C2hѢe/=MRi6uiǀJ<ӽ΁yѡ?+uQpdIDATEF)gT !2-=1rDUiȣ{F5Ӥ3Ħ~C?u*lIEՏ%!(x 6ƥ Z3'FAi("t|QeAB2GUuSM@#mBɓ(gٹAWLP#hBAG1e001 OFDGOFQ%w/CE!0q)P[dt }/;.gMېK:/ZB1'ҳnpAC7@vp#l]&},+ R* ̯-_ ׯݳ[Y;fϿ+ͮ/3dĎZVNB kF[K7 !@41D"!QzΓf"N =e/oH\?"C›(k0y.쐪Yt\YJL1LHuFQd$=L?T2B259媪_c(D=Qt2oe Ȗ5F(!OH:`f/ BHPT B pY, {l|xC~:YYOP?1_Wő|bƏ*:?2_E#溉!|?]IO6fkkXxK&,}=f{Ddi66]'L'vtOfg:..}ğU?Yҷߵwi&uԿR$qi׀TmI?)J_d*.}}/ʏÖ3_?}QBFL&YmStԽi ڿgue)!Yh*?6hc6/Lf|lq-•5lfBƯ"DV?\}X\cm(3[Jc&]VʜYZ?Z>}|Ti01pLWOY%DeI_GVbˇ ]BOYtD ٣}iYEݞ3o!ެ}q!J7kҷ /z^vXCw_$پ?ӃAYȣ|\Q>ɔ"ڿ 1ʗ^fͻr߅z[IHbpqы=+9gdd]R|7Cr*H?FMnuQD2f_Y'}>Gܲg}챒TuyMפ1_.Ʒ|Y%5Lʟ}STMi4#ϐEVsc ,&@ÀEpY QbUOIQV"~/ן/o/ssz4Q̏PM{ޭ_ 1^vXjck3g ^Q} -lG:F۷>_gKgm0v66/6&v<).ߺ<_L-y\Y AK{`69ϞJ?=+z{ʃ|Y csB{6==<=clGc3<9/Zj6%E9_-$:[l3_Y>3g9UO>؛(Ƃ&D'k[>4cϯ>4gW^5/x4ϭ355cmr {4JMX{ؘ֟ݣX;h,e5F}kъ}btFq^֏FJ +SI[+j>o-=XϏgmy~;?a]~|?ASWz~i]Zߏ0-GؘRn(o1oIVIۦ%>;~b_/=jlEs[O*U֪'fk".Y8ZQCӛ,"*\z饟lEW;?޲vYp~4i٣s+ydGª3z}z"R,{OϏu~|G=^!Vګ<$3ǵG^{n,S2~o|_|r+}ϰxg5%6T&v+- ]_ lcNߛg+-o3b>Rl/?_+u|ߣv<[wurjϚחZ~|}On3H'+Η'}H?%]OSr1*y onٶJ۔_0U/GcTV{ "K_^?_^ǧxXKxq͈=Z^{EzngY4بKHb,HF/dE3 s4QQ5Q\{b|m׻]l.ZzYL,'}.ZSZ8*g2Z<%tI,P /b3^f&z2n畨4>̳n×ƕUS:RTߩ,ZsWAcM,M t U~) m U>XyƝn%<(o,wFuEm :Z5˴zi9倫V3R e՟U3R]|푤=D{lH=RޏYT=3`Q f?^W^1a/{SƜRƘՖ3.E# Md{kv-?uimŖgޗ_;<>+E˯?/~͵|g=?m)nӉ]um%`bic?cKxzx=QK)U.i?+ʖ$6-+}#^J9ޟ z<>=Zd1*E@:)Pl>`p,`Ǎ `Yaka@,bV`'̬i{Ɛ勍[ѺŮcjm3{@2thMZJ&hO\#ĒgVV?Z-Z&qK<'qyFBǝS?#ag>6jXb{Z4xmbߦ*H첔st1ֲ8Ҿa›Ʉ k'Xi:vfi1%닟>kqjp yǿ#ϭk|/ן/o/s@񨳅f?>(#I(2{4{n<)ZZ,}2fQqEg=`lڋeoIkn'VV+m?w0E3l`xuS'ϝ>B3'MCz]ף:xEAZ/~=^Hu~IY g}cyұy?ZH}3V jbQ̵cҎA{oZ?5/;v+g=zI Prz|J!tӎFR|rj=nÇgv,$e&^1^Yb)e.\pﺈ:Z)6rWJ;ϟFIii3ֳվb{ P(Z f $-XZYر²j#JĂ96ԓDJPWIԟU܆yl_Vs\2@Wtxέc89AW DS׺~s/O k[K ccOPTGjmhva#h(Fhο_PGk"BdA<غ#߰(6[E7evNڣ)c=3Xf=Ѿfw8wX% 2RN΅Č{忭Y)[FcxӑWN˯?/~mY}Du5k|Zt5 3ZR:Vc s|)Ֆ$yݮ$O>u޶nO϶mZӧg$ϗYG9CXE)P~2q/FlN.|u8qtMF~|s2Wp:==UϿ<s,GxdY#f0M""PH{I:uJBLywݹ!01PKE{S0pkFgz.k=cr':+(=2`TI() GXemul: Description of the framework

GXemul: Description of the framework

Back to the index.



Introduction:

Starting with GXemul 0.6.x, a completely redesign framework is available compared to the 0.4.x series. This chapter of the documentation describes the core concepts of the new framework. The framework is still being designed and implemented, so what you are reading can be considered an early draft, or a work-in-progress.

Almost all of the emulation modes in GXemul are implemented using the earlier (pre-0.6) framework, but the intention is that new emulation modes should use the new framework, if possible.


Components:

The most important concept in the GXemul framework is that of the component. A component can have sub-components (children) and a parent, so the components make up a configuration tree:

Component classes are registered in a component registry.

Each component in the emulation setup has a path, e.g. root.machine1.mainbus0.cpu0 for the CPU in the right-most machine in the example above. Often, shorter paths can be used, such as machine1 instead of root.machine1, if there is no ambiguity.

Each component has state, which is a collection of variables. For e.g. a CPU component, the state is usually a set of registers. Each component also has a set of methods which can be executed. A CPU may disassemble instructions using its unassemble method:

 
GXemul> root
  root
  \-- machine0  [testmips]
      \-- mainbus0
          |-- ram0  (32 MB at offset 0)
          |-- rom0  (16 MB at offset 0x1fc00000)
          \-- cpu0  (5KE, 100 MHz)

  accuracy = cycle
  step     = 0
GXemul> cpu0.unassemble
<f>
0xffffffff800100f8 <- 27bdffd0   addiu   sp,sp,-48    
0xffffffff800100fc    3c03cccc   lui     v1,0xcccc    
0xffffffff80010100    3c028888   lui     v0,0x8888    
0xffffffff80010104    8f8b8008   lw      t3,-32760(gp)
0xffffffff80010108    8f8a8004   lw      t2,-32764(gp)
0xffffffff8001010c    afb60028   sw      s6,40(sp)    
0xffffffff80010110    afb50024   sw      s5,36(sp)    
...

When single-stepping, all state change is displayed. (In the old framework, it was up to individual device/component implementations to print debug messages.)

 
GXemul> step
step 0: cpu0: <f>
              0xffffffff800100f8    27bdffd0   addiu   sp,sp,-48
        => cpu0.pc: 0xffffffff800100f8 -> 0xffffffff800100fc
        => cpu0.sp: 0xffffffffa0007f00 -> 0xffffffffa0007ed0
GXemul> 
step 1: cpu0: 0xffffffff800100fc    3c03cccc   lui   v1,0xcccc
        => cpu0.pc: 0xffffffff800100fc -> 0xffffffff80010100
        => cpu0.v1: 0 -> 0xffffffffcccc0000
GXemul> 

The example above may not be that interesting, but imagine that the CPU reads from a device which has a zero-on-read status register. Then the output may look something like this: (this is a made-up example, for now)

 
GXemul> step
step 2: cpu0: 0xffffffff800101f4    12345678   lw   t3,256(a1)
        => cpu0.pc: 0xffffffff800101f4 -> 0xffffffff800101f8
        => cpu0.t3: 0 -> 0x2200
        => intcontroller.status: 0x2200 -> 0
GXemul> 

Components that have a frequency are executed in steps. Those that do not have a frequency only do things if triggered by some other means (i.e. another component). The components' relative frequencies determine how many steps they will run at a time. For example, if we have component A running at 100 MHz, and component B running at 1 MHz, then in 100 steps A will be executing 100 cycles and B only 1. The GXemul framework makes sure that the exact sequence of cycles is the same nomatter if the user is single-stepping, or running the simulation continuously.

The frequency mentioned above does not have anything at all to do with how fast a particular host executes the simulation. The frequencies are only relative to each other.

Is the new framework cycle-accurate? Both yes and no. The framework itself aims to be step accurate, but it is up to the implementation of individual components to also be cycle accurate. For example, the CPU components that are available out-of-the-box in GXemul do not try to simulate out-of-order execution, or pipe-line stalls, or other effects that happen in a real processor, so even though the aim is that the implementation should be cycle accurate, it does not simulate any existing real-world processor in a cycle-accurate manner.

Is it theoretically possible to implement pipe-lined and/or out-of-order CPU models for GXemul's new framework? Maybe. But that has not been done.

Note that the component framework described on this page should not be confused with the dyntrans mechanism (sometimes referred to as "the dyntrans framework"). The dyntrans framework is a helper mechanism (or, to use C++ terminology, a base class) for implementing specific CPUs.


Machine templates:

Although the framework is generic enough to simulate/emulate many kinds of components, the focus is on emulating components found in electronic computers, such as processors, RAM, caches, graphics cards, etc. In most cases, these components are naturally contained in a machine.

Machines are registered in a machine registry. The end-user can list the available machines in the registry by running gxemul -H (or by reading the documentation built by make documentation).

Before GXemul 0.6.0, machines were a special type of entity in the emulator, which held one or more CPUs of a particular architecture, e.g. MIPS. In fact, the entire machine was of that architecture. The machine also had hardcoded RAM. While this worked well, it was not generic enough to support some cases that occur in the real world:

  • Processors of different architectures in the same machine. An example of this is the Dreamcast, which has an SH4 main CPU, and an ARM CPU as a sound processor. Other examples could be GPUs in modern workstations being considered as CPUs.
  • Hardcoded RAM required hacks for those architectures that do not have RAM at offset 0, for example some SGI machines, or the Dreamcast.

The 0.6.0 framework, however, has a somewhat generalized view of what a machine is. Machines are simply templates for how components are configured. When adding such a template machine to the configuration tree, the result is a complete tree of components:

	GXemul> add testmips
	GXemul> root
	  root
	  \-- machine0  [testmips]
	      \-- mainbus0
	          |-- ram0  (32 MB at offset 0)
	          |-- rom0  (16 MB at offset 0x1fc00000)
	          |-- fb_videoram0  (15 MB at offset 0x12000000)
	          \-- cpu0  (5KE, 100 MHz)
Here, a testmips machine template was added to the root component. Adding something without specifying where to add it always assumes that the root component is the target. The name of the machine in the component tree is root.machine0. The tree dump shows that it was created using the testmips template.

To make it easier to start a new emulation from the command line (and to be more or less backward compatible with pre-0.6.x command line syntax), the -e option can be used to start an emulation based on a template machine:

	$ ./gxemul -V -e testmips
	GXemul (unknown version)      Copyright (C) 2003-2010  Anders Gavare

	  mainbus0
	  |-- ram0  (32 MB at offset 0)
	  |-- rom0  (16 MB at offset 0x1fc00000)
	  |-- fb_videoram0  (15 MB at offset 0x12000000)
	  \-- cpu0  (5KE, 100 MHz)

	GXemul> 

(When starting a single emulated macine from the command line, only the emulated machine is shown, not the entire tree from the root node.)

The same machine configuration can be set up by hand as well:

	GXemul> add machine root
	GXemul> add mainbus machine0
	GXemul> add ram mainbus0
	GXemul> ram0.memoryMappedSize = 0x2000000
	GXemul> add mips_cpu mainbus0
	GXemul> root
	  root
	  \-- machine0
	      \-- mainbus0
	          |-- ram0  (32 MB at offset 0)
	          \-- cpu0  (5KE, 100 MHz)

(Omitting rom0 and fb_videoram0 for brevity.) gxemul-0.6.1/doc/20041018-mach_pmax.png000644 001750 001750 00000031107 13402411501 017333 0ustar00debugdebug000000 000000 PNG  IHDRH>gAMA aPLTEHHHVMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxiv8 : l6c%[W8GD@nm?&.]d?{Xlj\+7:fߘ4\|wm UNOz9i~oiOya;n'O=3f9)9G|v[|&m?ޛ[# ߭?C؈CyF~dn}O` ~ğߠipal~l翇G>~=cgc"l~ 3 V~{齩{Q緡 _?n5CEK[~OA C>t~n>|O~`|gg3=0vMl0OzxF`aw:0XƟ $ !wh Nb@1Ӈ=?g෡O= fGo@a\ x4w>z'' ~8ߏn\X}oǖ G4M&~&;L?ah|iQkM-s.;? MMwTm<?"} n Emt^<rhd|/~{2Ӕy0)73xL=~' 4lD/_~/oh+c+@3n|dq`wxףa|j=x= x.0Qq.Zµ 籜chLIw~~ ܝ@ 3 0;$`jx`*G";8'I0nSr"EۏFXzzj]avr;50,—9iIqFk6# g$> j}+}q?zxcwoٝK`d[Yɹ0]`ڇ!KNn^";tX@땆N"ŽQ$8U !co0IO`Pn D8:{^/\ lIóSygznVvڙ QL_6$goV^\*%⪜l&] F `v[`vYΕNj}ÝqXB^Ho!&X09!3yZʞz߶VD`ηsY(_kd[XQdc.Wk qza(<0=3Դ ŵKt33j7͗z# 9R C 0-ΫCHG;ɾ`&Ӹ񺏿$C1Bs4tpi\-_ܐQҙRPEDEDL:jJփPs=@ep5uGQfҐ 6N3zjr9 fQf`Z7dn[Z份:Ί!_,HC4+0mQd4);pҨ{N4Pঁu[̓Nג4-(d|ҹIi1DcW Nq(.۽fD},Si&Pq\mH{sr9}VyBOvhG] %91b*}CZkvN (Z|`xaW@D\ ݵ2@@0,*?KNQ&-W@rW-:q%wӗ\m^34<X9ZOn0YCw$I@23 AVf\<;4n <06dsE03^w(;q9\|'_ ۇUD|VfǛ{(=0 0q f=@=$9=@YX)U:@9m Aq 9Z57o````3o6eo|WS$|**Lk$?ܑZƁN!dY pi ``E Zў{*2؇C{q33pZد<1ң᪮p縯pP_r۶ @hU*hS<>ty7|@Rmz-PeT "0Nnx<,# B@>ƠO~]|U"z~'jEAEW($' C07dfSX@^Յ%]P~tԟ'}_H]_ ]`HGLKԶO&A+,iWPr1է(m]cX8JoDV Hea>G(^AQLv\Զ-kú/> p%`k]Lg\<s -yqv9Uw`5׶D⮷4TlA6NSۯ©.:Y[2CXU 1(PlfH=Ó,s.F_,WK1z*r0rʄZ@t f^6֟sV6&SYVN BZpy[-sJ =6oƍq9d>" ۧP3lѱ+T:{GpC+F U/TCmf|M8Pc{%ctHUd߁^`x4@z;.VR3cw2 Q~б~gf)g"‡cN]7VP%'0ERUW5DMO" N`u0mKz>I44ۓ3Q N Ȯ;S s y2]82` 8z0*4PO N @V{UJep@zwM pIIupj`# < 41 8% QZ}`8.hX=k n{_Qv@`E@pC wR9P}vO8nZ*vi ~rªo ;E2ma֍1$9X4^gkC@cR":="m01R\S0"g |Y|`JɠC*> [pE``vmץ/#+K>vEpP2K}/1H:1Ȣާk؁(g_Kҽ D`L:` $ N2p|%C8GTJ.M@uɨa{0ՅܵDe1IhY;Ǫ5s3xq*]F1!m:.U%՝~Z`@NS3 hoS}|?FIS; υMtHù32Bdu* 蔃ݾ &8R G˫ $m[3z`;I: )PB, #3 Y+V.Ba$cN#n_&97*Ā,`~%:05Cc[ ɺ&vI'X] Kը_zE'p.V~jH_pm+v!WE®; (\M9{@pOib y,f\ng* 'n)Y ϒGflK QFn+_*]l0CYQhm~/ 7^۲0~GZsIuelbzM #N1 $f^2RoC 4㶬bx'BدPRTzx/g[X2665n@ꉯ kKƺ|ӝ@ŀ.<\-,\R2N@>K 7\~ yC= ) j&.=̺4njW Rk8ipe!n@J\dL0T2ѿ ]9e/ f!H{18G$sp"~ AoxS @W N[Z79 @$דCֶOrj /Cr0mAg`%wZ. q'`T 'q>-ql .5)VQ=9]7Y^6@>rZ+\Yg`S(jڟ,b 0P]r =SYUmJXO_hZfOޘ \k"eGYO 3Pe.lcn[kid@qT>\v=XQ;xMr\biW[XGiOGPC+`gȵ}mp:OQ; \K,\=Y;u?!(<{ҵ A+jKzo)LmaCGf%/#);SOz<# nՑ %s7UkvlMa xsI8(FXGjiubcxqE}QzJhVMNT .P68(T GzUP}d A!=Mt2 :!@0ԆR_ɿZvF# #x#Hleatg00_= /Ә! Ç%hpZbҀA\ @xD#>@N"M2\&룅}cb\)SMJFDYhC@͑PU-vk0` Twy3@B3ԇ\UıZH3nr]hZcй uozaj_kL3p<>Ҍ9c @uWmͦ ?ִP*,Js@6|[@[`H.l֐_@g `&=%f/_T槼 /&Vxrt0dwC~NZ&΂SfJ>G\fr8&Ld鳜] )8pk[P&;U~RY8,~VV|Fq)Yuaya7pcX y ˿j*䴚'a5)9t:E=agz/R)ڞxN^5bLGsc ;JM{W!cavOyؤw[ջ *@ɖ1e7~h .4x :JJ!]s8hyx!4Q}3"7G&8mjeiX{sD`4;,g`jWGRSb` P/`$NQܱbfa{Q c``v?buȸh_FPp`K. L,Yewf> "k^] ;+}2b'= K~qd\ZBixʠ}@M0;9/RIFcuj組X.о ln0 >Pl@^c.=l.^8_HGv-,c/ε}s%_ia^ٚ տ9FYRJܳ$p_6o,#4(?YCrMWǽN`Nu9G)eL(G+z orz 7j apӼE{>e͟@V|odoO@R9uus9Ec˺}VnOSdr9Igh66mL@!`}5seRB^V8N̨SzN\S0Pڽm&o-N|_}nRz> $o{k$[n|C`"6qlCi%:zF( ɖkx<;V!:a+;Y*[HXw=iF4-8B*_~b YD\Vy=ӵotrp5r %x.ȩ N朰~sCL\qCd;t_X~#/#6qo${|*} =z}K' @/}y>XwNV`_zsw[#ȗbVaUOH\ ]Fxe"ѻK;x+#ma h=R ^rW::YPi &sӱo ϵ [pY\ຼ"hUqת!TjWġ"=CHYW92RU,+:vpU^Ɯ`pi d^(᜔0<s QS/:ޔ"i]q ȩ}PlRŅ#({dbS k @2S3I7]y\cdy9Pb+"IhObajw`w(: ͪj&q\ 8P=cl?8<{%F0/=bE7`9gq0ysvPHM$N9.H@;zn$"mOMa 8gxOq&n?'UvHz/v)f[ \\۰~ǃ .1i qp]n5 >:x,Qkvaܮ5 0i0Skv]'0?>Skvi Ĺ@g\4a!ZNP^X`zd70)kjReR^5خ 1$w#|[bZ^ *̐"'Q s/l<2afYO 522S 6#ƟE4uz^8c/l;XGy A~'ǒ"<}#LW<nC040<=_.bL鹺M3 V$oErh@@h,Z.,9=8A O0iL l<؜䗔a`܎;8.Q4ie@(R6#Խ@,<JcND-ُEC0oqlzbUajNk-@QGpi]Z6Pm=Z`KR)::1ش GkwQ=I䦁y821(wq]ӾBC@.%ka7n)7``W`6Т,W7YƬe=dRTe11q qG)KWpN'Pɴ+eqQ/ W%`U%a]ұzI( 3U XZčuDωӯ6ZK%,L$/bӯu7ei'KMec8iOk8S^dܖ DyaUKaG-_pMNFtR.zZ: AH72'pA900Z5ˉ77eh^4 0iэuY`ozL,qJkNꝸ$ٚю[Λz^Y67]kj/I&nP'j$^^c^Y<}~S5ò9Lϫ0BӅjCТd;7T"iy`7mC$I6]d;@%rVm(y{$Y@9Lk[I8 ^{L[8c ]I,}^$y``Ԗ=^p^~Ⱦ zOXZ/$C8 #2,H{DW^@z/ۜez W5rcf%2U VmEsĕ> &L՚RJSB]>o}E䬞$W*alvF}#e]2iEsug}Ds7 )C}jSߩK8~/8o\R/9ܛҿ!ĬƲBρs>^ڪTj>tk⃞t}5~X )| yv!,1syN,jrn0Oj96.:@MWr>(<,pe'Pf`f6e M @'0 0v#L`pWܼpo1uf|7nfvpi1=XnZaAtIME 0NIENDB`gxemul-0.6.1/doc/debian-2.png000644 001750 001750 00000024541 13402411501 016066 0ustar00debugdebug000000 000000 PNG  IHDR ~cgAMA aPLTE^ffZ8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IDATx흽vΆ١ i\ Nr {NM|ٟI/IXȠpے,ky`wWu0P ^)_'G#`0c=_?s=3?_C^?f )oԐ쌿<*㻧?Xob c2& ]Xgqko<^ NOO C~+<`yO0(wx[`0J *1{,i1<}! ,aSa>7<o(?v\` =f@ /0]% ;"}=`1%}2w1[> Q8+䯄HOOP7?A@51|- 8ǧ&ɴ(Lϵ V^=E2;'HX>Ez.Vh!̏5>E:#0JF1.lY-P æO 0 tg]0`v"΁~ FR4T_}SD g\`c22@x.Vå"z`ڂwM(E):h `d 95 1P0ʢli ᢈ[Z!~qr40؋+b^ :( y`nm8=[h# &}q0̚T";r{F0000 &w:`9n}Msr ``E .S̢U݄O%oYPW(,&d, Q|ThE.Ga7پm; 0}TAzMZE s]l7VB] 0: &4 ` +rO9n3()%xI-u饰3TZ B^ k=CUKRnA쥰_ e zl?M0pAR3$8ĠKKM=C7p"R8'y_QYRXد^`@N00x @`wjͧe68V0YKMSIs# e,k \ ߠƠN1Y4M,5jR? g\` B 蕂GߠR $6Ea Ljj%a B40$>h5+Lw'y(m"o`)lR˜pF``P->`8dA8;;탁Uuߍ\tvTM4o0e3v 6탁; Bfn_}00gsB`Qx03hIw`_`m FA(dG``X ]t4 wQ. A)/5LtN.T y dCH-+ ts8LlGiu D1ْoc*H`X :_ s0xDgXa e rqQX"Ȳpn(w%Prz- tq:2UJIⱡ  *7p ӡWT0/z(8A'Jo\yǙ B}M Z9(`f=4:0`*(Ġuy" Va4EQU`aLqS)0ma]jQ̳U20덆 GK-$9Fd'`7> G CR + >Z*fxVoCsY6ez)l4oDـ ^֟w=^7GC ii9k=BI. ƄҜi'RKTVdr9<ʲ 0GZA~j G-/`So A]97x^PeQ:l J2Jo8`gpVo -k Vzn+`)Hxd@$(YwRA7R )&zl`pf000c w>0pa\v >!|d/=OQJg`0YUbl)T : ¢/èMخB:^O91S+^iW!`բA?08tk @m1G! GH]O~E#0@ Okn08uVc @vƮ zb}g10XhJ=0pZ 57b 1аk`V8 D0àT3,VB~b?Dm lw \3 |*7_fhi% E8<`N11@0p7hb<XI? >5tu 6`4,栶_٠lP헺`sQ( %X- `>Q0M6/~7$_QePG z0 ````w@{^;oxQW d^ɽHo Ew*]C| \`Z7ҼwK`S l1?ʪme KMjS @$ֈ5~ I_{6R.e5:080}` p}Gq|90?|;``wv` os ,A? i5bVϟoi3f}0ol_3> aiiz70}g0}Z| ӷ?v}0o0^c f? g>]GyX|tA7 O1'펗}00008Sb= |`02\l{POOr\ul{* ud6E m_S:.|J60l`?05%( z*0`k0Tl{* `A@1Ѕ1hThj"ٞ S |````p 5BDQG X`hb0 mOMU O0nΛuk?At,1(VyK0ؽ&Ck07p5ZW\D: Y l8 ]l0d00` 80Aڴ~sذ/`x9k k4+`1(Urs@wPo3 BA<κW د7(gM8 tc6P٠2R`  ¹l B ``V'F = |R-C%LՆ &S00niF00000 1\N7EA L:iHAqP9Pm|]ud5 B}>` 3 j ;C0sATo*Up3`p z sgNa{" Izz8%E"a|`2 `N-O  =|`bY؇) T@sɲzՈWuNao w0x ^0x٠؏AxEauv609<1zgVFdQD0000c ``ƎK)/f0"PJeULP`@E߃t(nG4zr4ifS)f BS3  [azώ 3w8`1ta c r1z3jA-H`,n7stNe]0gkNZ$ ,s =V`@Q0x6v`/ennNf*7:_?``Jk6wZc{0P{+Xh6Oq`p? V Jzi Ri E0 4U?6^7|lѮ {'cP,| ;cv~nᣤ n@qdr |` ݇ \nsX;{Q*5bV*frЦ5ǀݢ "!:e a0%kyQ0h5L}0> C7`T*l)>00xd  V0}-0pA@M `Yjb`j6лc'*]d6=w`جC`",{VAĠ,`nQA1ggW+ҺmPjQب1;WK $FKx@^25[ *M)*S1$IEaHn1@0݂H`2Cb@A"J!䇜 v07ĸ_ .G}aBFJg`W g+)[ pv)#wHK[a0Є=FBo $ \/ %o;!!\Į$K)|Ć놱6k##! 0 9u. 0a0008 `føx`) 11q;0` vNڟ 0XXF([-om^ڲ1 yld֌ZSض0p(aR`il.1и`Sض?A^)l΁A;z 0Y? kj=BniA+s秖N``78!2P7A1W4{viZs NX. Z9ټT n0p,j\ f#Yop'Rw0 aMf X|hU``,uk`zGά (}vkt\?a;0 ````caWS|zܠyAӈC/JNT rmaU_e('@~C>J9h/5Rtﶇ֖_`I) IG|C\]0p"JҞ0]ʘQwp=s.j2N6T;0^@w`K $a05;A5_(SC󼸈-u _`H>]`hơG F08Z IUd6paoi_O|߇@N"ΏX?AĠ6F0lhv`Zǐ6Wϳ=04 *2\6r~\R(1$BT2MRe )trjRAU%™AȮjl7TZ^(> 15QG}:]7kkaG0(~G"{`ᣤ7: ^T!:tޭ0Lå GNaz000 mx%)r0  F  E~- ~fA_ . ZJ?px@VCƹZop=0/'T0Vo0WCj {`p/ N *hpqpJo0w_=0>FoP|Xop=0[0PXG N uf #@zV`{ør:cl6np b30`0A_ x_+0Vg`A~c  !O[`:G>8aBTY{X%m&$` =o`AiN5UVg`0pA_ l2yF)t=+ R%j@`گsL`,øb, n1H :h ~28Ġ+K0p,00K0pZ]2 J}~_1l ֠op #J` 3g$~(`pD vrzAN lC;\/S zf7d /sՌ~ 9#leonz aZzHz\#\d Bzs-Ks0o J90~+OiQ%?i<@U@NI zsW05=773pŢp) 4iUS0zw@n`a<A*kC&\ؼw 7s󽴩[mc(6k{z L>-;Qh%9GNaZ}08r l 2 n+uv\7k`\7k`z}k`.xRo apRop 8m|: n 0 㛇_Nڧf? 44vSbQXgQ0"jaj8Rj0 D N&'wBt97@ohQĦw`ITH"/kT3ߠcuOA<}MǠ O׀Ի`֠hշ`]` ָ9lf91( b0..\D5Ơv'A[LkPcP6Q S7(f00Cb+ *=@ MoУzSNz a – !,e'8fz0pS'>^o` `s(Z WDj6P;t;c M-i7vF`dQwՙ \Zk)h;F008<7$P0pa\dzL] e00--~1 ǠM0؏AI`3XؗꠜI04°Y'Hw 048`23 -+ 4d=%, n\[ T}0P vKT"|8]l엍c$`@jԱD0pAgTKV00nnۍ087`+|Qz:gf0؏9 vz:gv0ؽSspIoki`q3lx!%Ei0@!spNo`9Ѷy H-1z 1*#8080v@OMgITfDopu`)ZcP` OAֵ oФzfq.3B!~ ~ ^m6!)u8r;7 k8`H*=ehEmAng"=zG``L_= F0008 [on7]18`1|%0%sHG@u #l0&k9@Io5`Z 5zd^vm`k0tLƖu \69_FA7[u 4(xt&7Šu-1X5gA%o[u lz(9000082`p4 : }`(>> dSC 8Bza0%z3 -``An7Xط dޠLY,0p&n1j67pAu#]0( x@0in\ko`;z7ذφR{0d00Ca ]^0؉]F^z)``> #˾ :P/VKI``ρi_Π9l3qlbR [SɦX` NAyCotv&n6he% ĦX=1gB 7:`W Fb}; 2Cu)PH 0G:08R?>;P'ֺA#kT!_ u JD?飰A. 1:KY0R@C٠N3W ~ k L.b &#aRv'`mh^נ Ut# +`k`Q HN `b܄׻ ``````````pL ~~G;<: ~ ~zǀ1w \ppppppp݂c_3?~z?|?tIME7jIENDB`gxemul-0.6.1/doc/debian-2-small.png000644 001750 001750 00000004447 13402411501 017177 0ustar00debugdebug000000 000000 PNG  IHDRtc}6gAMA a(PLTE8K^w  ##%%%%%C%%%%%%''((((**++++,,},,,,,,--//00112244558888>>CCGGIIKKLLNNQQRRSSSSUUVVVVXXXXXXXXXZZZZ[[\\^V^X^Y^Z^\^^^^^^^^```````bbbbbbbccdddddffhhhhhhhjjjjjkkklllmmmmmmmoooooqqqqqqqsssssuuuvvvwwwwwyyyyyzzz{{{}}}}}hhssyy{{}}SlLMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0>IDATxZs56@hMO0b !s,zH En#= :C]fsf|>W#&UVML\=zdl%kحcc-Yҫɕ{S.8jNr#+~葕򲕷/_7?+޸9mr\sȪpؓuI ]zsCrs?ēO=>Ԟa9 [+oˎv|UR?>XKht2sፀ=SRX#yXМ r^@yVٟZ8Ăʶf̸,tn$2]޼6@24VWGVZ4B0Z)'c J Ӊ9 [pW^h6P$a$%MC6&5YW9](k4ԀXJYφN-~.P(1NPHiRLb48@RP.)p/uk@ZsϵNq6WVWLcyY,o12(oO{BBh*aHp!u"RgۨOBAIU8I %Ie OZކMeh37֮/}K-bQiמsy^wfA?݇|;ck<{m8 T +i*ɋVn|1#N;I-dX+L*|ԃ#Kb[4!iD28P|:>+>*A,TV~]SB'PqrN,77Ұ]˧:mI,o2ԢO=;8|&E@% T_opS,UnQ湗H%[Rp6WU*T0G"`5 %HjB&]$mV4"CtAkE-p&4UƐ ke{VKATuTQV=7FRDS .\ɬN|x5D K&q@L0) y{tSb`9dks1݇q; -󝚮 h1~' >NFFw!F3F3dsxcOͩB]>%A-TIJPJ[JΩ;HZH4\0TJvMgE$f^69(k*tfU: #z@wyg`8GpqIHY7^UBf@u|}>4PTa$AD=".R&Rmz#iގT}6קQ Tv3[t>p4yYzH"pY-d5.2HF20_">)A ͋-PGp#}CFO }vɑA7S̿MtIME \IENDB`gxemul-0.6.1/doc/20070308-linux-dreamcast-2.png000644 001750 001750 00000032127 13402411501 020644 0ustar00debugdebug000000 000000 PNG  IHDR sgAMA apPLTE  &'''. ..,6664:& :.>6 >>UWU[E^^\fRN6M7Ф|Pg0pa ^S os\=xC A\!B+WBp W*^Ns*UjJo/[M|uf^ u̾p(C\Jp9|?ju:pn m7zR c뺂ZV˜ڊbV^_߲GPV-~28 3y-qۺ}PVk<(A0G #eU?W-vpup(C\kU c#o7E u ۃ<[*Wp_# =` e+Z6&ONyg]}?أufric\ W(S\57 ^3N#DnzRL{+˥[Whtxá qNaFꊖê'Pߊ끻ʥr+|f|_u7&g*0 hSi{sq\fK3a=4]^xá qm>$pKPՌ!:N:rjb*r *k%ő 2ĕ^*yCɩգy_jӹn@y. ʇ D0-0@ָWwyg<5Cwх(dZs<1J V;:3潭hybQ-(T;<uU0NiZGcNZ8;)z|' 'x~X8$7UϩWb•q|dkSi>wyC!|KDk YppDW(K\Ux o< _>uz\~z _y0h{|lgի ժ~W(K\C unj@ө V?20lh=OU4wpT]aF]ھ>nĵv»`jVj;4]Y{~9lO] a F4EٝSk Vt޵WGۋKg:UMv{=YnB6D A*?7ʋ[ۭvZ\ i yӝfz\LqHY N}|0$t)uqU ne"'r۵Z7ʲgƛIܐ"Ksk!gW[lmk+bwh(ѕUCY*<@L 8!|\TjRlt5yZkUP=#@G+EUv6PowëuGE\]lZ[J}i,K5X;gfvxmE--W 7&{[kHΞ<%P={w7.Qu LX(k\alV>Ue1u4k+K|)v4-?$fxndCP.[hRNX^o(8:{ruqqQ^9Q,.PntK/Ζ+ե5 n%XQC2e 8^EPל-)R<'Xjv(rqO]6-bQ(DzZ/kֶ :vwy~nOTӌES aq2UjzS Jn{~Ĺsg>;3J炙?kEŵ @ DKj;GϜ޹?_m<;^?;-P5Q)ө9G|O>Jm>?kj/^dq# W^V'N XR@Q>r~?uN_"E2ŵ[}+{|}D뱇ķWW>O;#&$8]o8!|6@ӭ՜oĹ(?KTRi]?q~3s'Ԇ/PiԪ8q.O}Z(]Ku'N<uqsLTo8%܊Uk?sV;u3~WgZ([\u<7? uo?9;7&ѹWcmjA KܼzEͫ7… }'.t{詳mmv:Ɵ};ׯ]g{ ~W([\klٸw;9ynonz/ԭ6'pwn_ Yek=ڹѣҭ_t ^yK.^xέ/t텍KWkWM/Ծ~B(K\]9j;o]V>y˂w^?^{RWy<[lnq M-(K\+۸<a2wn P/_a{/0zv4~)W(K\+H;wx@}óĿ/?Wns"/]c;׺iz/xF~W(K\Ƒ'o/EyyV/zCv^%/\zƍ"{_F3 {rOӷ[qˆB:; Wm\pXvۿJ6!\w eFǍӥe+q>=v7~(5fVCAs׷ӟmlο竻ǍCB9t2vSEŵSI{Q|kI!W@! Ǐ'a I}{獠 W9#X>; +jZ/W ѕ:AS Dap.ؖ@"G Wy1:LZq%NNu0h0o>>e{Ůܕg@>k F3kޣ+Wp AŸw-Pt~b +~WA`?8j$Ytv;>?dIa_1$,HuAT2Ɂe%bL_~T"?<ؚK\l.#?#)cF`:컕j\S'6䫕 ~%麤9,2oI7HxzSGCZǷW W#MOL50ʈp57f"IELra60u+G3&mczSPAp:\+hȂ+W&`JJjbSƋGPLdU8}qefK +Cy|T tc4׼uؼT* QՋͽOPtMU\ubS&?Uڄ+^lލP^pMnjWS? \m7[ )͞GV/6>UhRM-&`xbS]!Bp+Wn5u̐>햧44UP4$ CkfW5)PsH\ iƀk]Svftaɧ•|藼kFTGFҗ^:EY_>%J1$p5R뱦YE˛D]+eU([1}}QM&- 96O4V\eߪS?l_e56,ulU`ۻ~:*ۥߕ(C5- +ڣ9iE_w_̲VFPU0@j1)B02\ XM*+d=pQc5Jڿ𽚮] .|5z3y|qT,| puu ̌3ԁ@|\!BSk̢"PO@wUsiV,Lɥs1Ls toD nH2h%FmtNfy9pƁᚦ#+V38Ig\W( ]3µB +Tکuqd|84\MuP)?Z&uU3`K Q+u)okpM=)#)ưi[:UUOiƕqUbu:p%cШW(k\GXW2ʚJ)oӈ+43ՍT5lRI=F],@i5HkA %`+Wnu4)QG~\N A ]G?qe55IuDEU,uX9e)cXiF\:Ǖ2az5zwky]uŤ]RUœWk3u>RW8!r݅+2CapENΣIDATjLXSk~WjFv>__,z,ssC5:~LnW: Bp ^nӲgg藥d(k|]+ݭ~}ռƳ[X=qUM&18 =~\1z6V\-+dkC{E|]OjBrb a5~, ekG:hRp5bOԅMXV!Aתy4i nڦ߭5e 'QOyjU^/L}Rq%^I\6q⬩VM,9!:ƕQ>@3p%+Sj*8HkڦVz\iD k!/ Yz 'HkB7C$V\-sȠLq wcɴOPIP`E&ƛFb2o`ʲF6EU"TTuX5)3ig3;S&JΦBU; xZʆEj\=1'afM_']U?j 6,&kI`P3~RzJ.^:1JVܕ15 Yp%~'fVbJ7̸ZVӄrW;#d L[v-?\vlӪ>.I9k:˜ُ}PHzT303nz@+p҃Z+WZ (j4W;GR\<\VQg)a60r7$F`q}RFVFw0(cjұ{\:(詔 Zܦ69l(3Jߥc6TGdrlXK*VQʅT* ]MK[w\֢wd*驨uڡgUMsJ~ap*Z⚮#\upSudѩ+qv\”: =jTi@&) 0k1= &_dU [ 31<]!BpvĪUtW~ e%g@K40ҸX7Œp⚸\4͸g&J"0j*T<8 M`Of$3#ӋQKkZ]c,@]㘩ű{;j)5?mL>\hqJ&+ (k_2J@ɀU2`Zxێ+c@:H.4Ÿ&5&iw4v 񄒨O-UV=`Gk]/o1J`z^-0ZwV-04j (V *Td+WhWFwMݡg Бʧה~W={0k>q5nug03HknzPaqMwet]c&+3m/;<+257:ߕ:|"N3I]juY]tw w{`8+ZZӂ9? ZuhWXܒL^S8tIp@[ v^44 mm `9cxiP#U..ǂkH?m^ }qL9Yr/KLVEŚA~(aO$x5>w zҢtD^$qS Jװʀkqy蘱JqO*lM؎>ꥄFҧ\3 I0Z:A\{T%դbyKߧ Wu0 >U8I<׉s0: ݏ_)'ҤRPMejs4ƆK weJk3uL3w0&\N)-W1eעA4՚ 0X)^4N\薰ҒךU_Lz j8&2WI+$hu Xv\t3%Bp M#eraQpyT]Y˹1zWG^)yX \1uW*W1 kk+q ;d!_B>nP5r\ WÓ_ո2-E_t-%^hqeJTf!Y;\Uiip5ghp5dZŠ>+p2Ry5R\ be/(>وȤp)S# \ *pW\)ǕZ0%&`,.Lفe;~?N{eTʰ =i+CUhӑ8;qU>SNZſX'j}XJg/jQ;Z:j&v5-,_+2&˴I~\'TP\SuK5VP"Ά+Di ?.Z]tGe S5q\bjp\c7q*xh\M [p +y&p37`J|)sW+)Bi-~gJ m@.ϜU:[5ΌR3g:mB5Z+p A\!B+WBp W\! A4\3Ҝϭ׋5mWJYc:}n;95/b2q5hc-)pJaضJO8j$ kTA~aM&p Rl%W[=xZFy񛼩nm5WM-Sfִ{~Vv&iƆ*!G-lz\Muk{Rj!lπZ#x渚_1"x`5n-pYGRl*}&f\ՋZЌ%E2p,wT/D}[S\h8DǏ|xuZD. lwtdg@i"ke{[Mե0Ao]X4^UPg@YEck[+՟hܹ+Wp Aڵ}kT:gs]Pp5 g L0*whbXhp:2FkN {yV3<{Y}CRU oBa\A[O.8ڲLJ~^a(cɵdm~(˦ROkUJmaي")楋.`5뒜[E&yoN{@;HlU+*Rץ TCUGՐ4й27*K\mIrBaSԞP}zWP,Dcv3P,\G,|pk&W8+\!xVO5u֚+YQm$Y0A9y>pM,㛺G|jzDW6*^z]׏ƁkʲWlQpeCκFWh(ZOv]>XFTQ^WdKel" ~W:vo)]^ N8 WW9PP giKǕIWmQޔ 8'$qe,}tM. Wfqji=&\%N#ˊ7LY5ڏuP\:/18+?Uj R |WץU gDr"ɗ+#CuAi^ps}j "ꫪZkQN\? \݉y=N^gPP5KW(C S@QH*#g (jW g2`*ZuG8pƇVC^pM{d+M@ WKqu,+4h ^B#0׸N \p0=|BǵaAp LODWž MGWp A\!B+WBp M?kqH h2B5WB !(k.W0s[ФU8rlCVtIME 6G(%IENDB`gxemul-0.6.1/doc/20110703-dreamcast-gltest.png000644 001750 001750 00000072172 13402411501 020646 0ustar00debugdebug000000 000000 PNG  IHDR&gAMA a=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATxy`9XPA#FML'&&D'Ѩ&#;jIPDDwtUwykYRU/p>*.O;Zqγ)B3gE;7v0iխtY&[er6BBtǏΌBa8kњ69,8K۹m=9+>xm;3fC!>};^}u~M>{ڻ3Bp[;:x<Ï\‚sN֕i^w}8d;N8#m9gΜqW]楅a!D( y˚SGGx@y2axG[m4/yOy=v^-¡Çwt{.` 4.KO]$O3#JU3>o|UK g'̖#ͭ, Zm/VNȥP%=8`i=h76˦e)o\8Z6.!V<ߝsO(mןU9[ڶ|cۜ%MM٘^?݃LhMƧd7v7zOJͭ9&@ R)|Ů4sp8|oƘ~O:hiiSk6¡~}|5B?W^{g"!޽5k7$=^ck^|-_[]#OL8G'+Ǟ|yMrEҿ9u566U/7_k.򵅲:$LP])$Қ ~4,Uٕ3uHozKK}ˌܼI_;U TUQWO>ˇ{|cO:g* [_;ۚ7~gLEeI˥//5l9ioO0xJXq[ӯo}|_ p7Ol|+#?ȿr݆[_z?{ |ZWg1beƒBׇǟe?+EO?+x#O;"֊t.ګ!E77O?:وqguzQ= ~ŏڝjqqu~W\o:b/6u`ន,@uSq⁇ןȵ5ՕYՋm/VR_+7 {(pMꬳv<ŅB-ƻZ}LJ7J;㘲w6y9g-/7^r4!D[/Ba? ۟-ASsEzÆ-'Os/bҧy=?X򯖬oogڍOCEO?C˟]xW}/Y Qi>8x?|ZگMZ9~tw{?3X  }%ؕVT}ƭy(\dٚSBlٺl޼j9\3*;::ׯ6('''cC !Z[ZY%~' /) ڌzw^`و6km6:!Cƛ/->no =46Wt%C=-Z|ұCWг`نl\a<;VRYظ9tѿ /u-|gӎ虿ztQ=xqCrwƜՇڶ~n !4ܺCqy#_^ACgc>Cjnޛn⨁EBCO=_xgg+{l.˛p{L9\2b90vQ>2sO~MnŞqhs^^:0Ho?7sǸCK˂7>o]30;v|Ovcګ`H!>&»VVR_[jS{ol(df臵Fd# )&7`w +WݫZN6y 3*[[Z--K` 4rrra!¡}/X7vXEUU׮:֭?=WZs ~wї!pX;mQ礢Oro<:O~4W=kk4I{W~oזO-[\Q'¯?;[js͛nb޹_5ޠ۶WV !1Dѷ.56oilkѵ~Bm^9Yv})G-[ˮs8Bz%lShњO7"Ou{HQ{Ev,]z#ulŝO} LS>jۦo:b{d'~Ԉ ߍW7cw^nܽW}uƤ+.'sf/mG,KW?jֺG9믿9u@.w9ky0tE=i\T5rʢ}jC4Q]O=~дe6>搢`xM%=lب՟Y7{¯yp1Z:s 'Oo/KOi?ong?er)r\NUo(X\[c/SҮx)7]qzmeIU aTi{C !:xBqg}t0B#8Vpſ߿B0n%]TGΟ;oտ1˯|\;n~Y7ʹǮǎvӅֶpoX`kj֭|>~숣:v[.book'BcǎphB"S\8 :E]cߛl\Hyc3]K+,kp%+W;nBkn]_Xg9\ZYHxk-/p`0#_ !Dnnnd4(싯êk"kzս#=f-C !,\2=;訁EBo}^QSŠ[_i?ȷ~ۊbQ݈_1fxá.C|8GYL\ӟY}#`E!ħ _{}{Rs4L8TqOw}tQS%˂gs9yeo./#yM-W]Fvs j`_Ohؼ廻͍4`Ѐ>VT4`|ɖ[;{_⥧.?1'X Wd.5;BwoZvZ!z !ֶԏ sT3}Ý ?]^=ŏW\,F z7qh!ǟoȭ=gm(UU]cWxUI t¥B{362.8 ]&xW֭>g~` B'wnyߜܼF &Q.ϻ yӦ.LiF{GW'Gd1b [羷סF{2G/rB#F޿42yPݍOlu%A!zvÞ継v g?̜4~V!!D?q;zD3A}.^.8dpc>4zo'8wݺVϙ_{wޘ#G?w= oE9涿>6OL?mH{4l~xa8g7~^}QGDO8 UOB{׍^Ӿ=OU {b䑇m[#qWB,@𼒺n{m۱G7Ÿ[#s{Ghٺq5kV 14~G(0){:>]m;ZyM 6oAuQcMypoRodiyZ!IJ՛~`J|`(v'K+9mTE7?q/Z[sdrK[oFaU)N#?w/g vy.OY֎Hۗ{u&*JΘ(DPł;v8MѴwmM{o)ѽkf}ɸ58?BD?ˋ #gSO>f߈ӬO3fiсգiOAa6u{{g uxI5vg< w7~~ǝrZ";ggcFfW,#[vlݸ} *kD>;֮Rfiwh߷[G{ۆK[v:M("[D5%"2B榖֦P(TSSKqtڼOeF;v&!p}aO5M1˅EXUFN]ۣSPYU]99@ l>u۷46 !*wBlݶcǚz /"8mTܲU è(\8}Z7}KtV_ =Whޜ|mSY è:P뮊eBu]6/QepqI]_ѭ[{|`0Ѹq>M;z:d[k{!꧞=c]zMصx(C- :2Xңbㆉzlnq'-7J*DR}eߟ4o}7V2w 럸 >^]]A]3gk߳~έʔS^c\4݃U{.UE5 ѵ&^v; g)3ȣ,[Rb'ɹϏЋCz]QS]goݷ_3zq 儗`  rZǻ*;䱇 s5ܥOpεD:YN)'_|ۺuB߸m7OyʊR˃=޲_a [ZZ6E},7BgUb8{kǍ=OEsV.^S^ׂ:t? {AIoyɵW\2ޗnڿz_y{ 5P|#W~c#rd?zƳ٧=~m⹗2vnZ[{uƻy#yգJϝX{G}ȯ.uRNAy}+++F](r 3~9yysJm, |*!˯O ٹmc0Kbê.)*)ZJl Gͨ.:iDEL٣O[}X^^s1gZT#XbAy!b#ljܭq΋&^zޙ>7?5M"p(gv{fœW,.Xv݊9O8՛[kg?UUTUBҭ=Zc .)=2EVx۳+G5 Ϙǫױ럸=/|ޣ_i+#?ƽ>*ßtV5))Mt.E)KBht-0?xꪋ6lmB{;[u}׏6;fD﷿w'Y<8#G9t]яmmk4qԄB̝opӟ붟}q{#Ovy(/+Yhs/OM?6Y~:o>f/9|mř!8[W !|Nw| mWVZhJ!i'˔$;!HN17~ʱ={.YCEl~z7q哳w νJJo~-;2޵$6.Kl~Ísh~9?ooC=v_xu}m껳s !><=T8P[ֻ.'Ǹ}-?ԟ\pj ܉5ݪrGX[}]t'gz<~!3m~W_y10C?;مY桢N$E3E3m{Clޜ6`iϼʆJsyv:ap֝/k {?hA84s˚/-xiC+.\s&M]ߣY~}--m {_p b~@oOQ1&//vY^|{gmp8fͪݫg\n@a QMK_^kbYU׮lܰnGB-;*={[:}Ҏ /<$O!(|!G !]d;-(/;zף|a}h] ݃E]()BUԍ,{aHߺuŜ)V-6:O]kl\=-r+wP6#',!kݪjUw,sķnPQvzf_Ն59šⲊn=ݵkg˹Wh,(+;rDz>ow޵~ܶK: URӿK/_4{YM[sD^U^|=> 5"kD-ݝK^Bv[epϾ px-2@0׵.jzӉV}LێE=e%= .,*uSlkΝ Ⱦ%:)O:dbZH)?7OyC򧧮+MѸkӇO]֣:WԸ|g?n̨>./8?x.(癿ŊϾX~9'ە&ظiW\bdNEIIFuuMMu͠A?hnKsˎOlUZmpa!rrPu}Yp5?k^]vk=[E8i}9f{ho6 K4/I9|[W?8XXٸghˆ^nO,%X,z O[p8_TY%2qNQT?dh0PKB|e='Dnk]Ғ]_[t4nZ[öuijwQXTZVQUZViؔ{pUy Y١g0rnEevז}=z\Tݴgg8&COҲ;lܽ#*¢zKKӮp=FS䖲^{X{&[#C]D^!DeMWCuauOZhڴ~UzXszӉVeh{!…EU5uEEO#:w|e,NQBN\SZkHힿldsi'O4{kfaDHfiyoG4r gƷ+.]ynիv#ܓ$+++ՋsD6Z5'^Daaaa_Fm~AA\Yqqqq?9]vҵs n={ʵ1UɡR(OL {)ž}t /*.Uj[ZZVZZgؔ<ڪ*}XoOZz6''M4oiVqopN" )-hH/`]wB ,oG8@^bc\e /oiƷƸjcz3@Zق;4Q)K|a?[/`S @5;,o^5W {vmqp/͈6nt~l?[fwmz,₍Mw;m~ܴw2NIQ"B_Щ? p8mӾh2fՑ/6]+BL9+ۿ kN@< BRҜaY04(ˉJ[Cݎ*K{g>LB8dÑy7 #_H#S)-i3RHSyϯF&4遄~:҇)%l8iT~-<0$c7R.9}OG9WS^^՜Z {$?)#eFЙom|s.e햯ӍUW5`˱1|,$Ge9U, ͊NFtǜS2x{qSֺy"hO{Io?8@L)yѯy }#ou)i*{-!P.١bJvm|ӫ[VlK@r׮B>AyAH3~$#P}Tݧ9U;:Hq$pUڛJRzn85+.|65A:H֖?:սp@]uC9@̤ΠKާU2)Xҟj-SG\2nWkBK cq8TG*WeWNLzIw8@&Ytd:#I,BΗY  h-$Жy0*[# Q H-@Bx{E*q/V-ֺW̯/9 DO;GYNtQ #+s{q:de  rGs}OLgj| ujY$ zQ N}Y)2 -`v{F;dL9+C/YorʕB6% b 1c>G>3(~+ߩU HSntc^_,FKzt>&]awa4ID D{u ɡJfֹ0)]؎* WHs0eIV#vs]t1tΫ3!E><2y &V72w44$/¡]t~r]4W)vj][BUb,3*P:{]ՙbp`ČJd$yPyk9Wɋxv D0{߱M.~U˝KJY^4eY8$4/ZbN9´Ëm#vq:XZ(_]_nHqXR 8#VHqLX˜=is\gg :"f'jnfc$(8co%.cXαUvٕ#G>Gyp½KG@dfT"ϼu2u$F|ki=Gh6t*̨ČJxL_GyInėS:t@ʘ.ܟд|o-((y)SeI8Ӳ  0"1-(|dΜd|Ύ4X1'̜CcnqnC3<]S>PWvs:mևHqݼ%b[ٿxp=-D>"k7_%_,r]2! ewv?:G4@C@,pbAJg(W.ڬr"M# H]G'A(b '^譮dP[fr{ @{q3ΙI) cUlW٘4 H 㒃W/=442xX.WY /)io>@\faͤJދC\͜لYrSnu)'=*۬|)7nޣ݂+1/})@b8. T RYM tF %ͫqD=˫xõe*Hqdɸ~f  .FY#Hq1 RY7G M>( o#dQ c0tT!f*|N#8_3[ ]e*V䝯uy{k (XҦg 0 IK'n b(wPlN̾~@@Iϒ,i!֬%hhɬg8,T$ px5it^JO:Y&@\B0xu iήevXz1ծYӒv=O9a9)~qX18,:O YvX.Qkr!5ˌ^\gc70h#l' 0  Odu$6)wPN7 1 $E|W\ˏ3x/vJ;= J,Sxe &ΉN Y<7R/bɫѹk>/|V723*S6P~Ss|NB]שHhNtHJN` d pR'x+|2 IL̲Hvg\81f9(pk]Hq cbC]WB-XN-G&=&ҩ )@gp\TN2͋QF'TycU1+#3--W#Ts<-]\k;SԮ,'p\FoJ^Ϣ/35†L?gPqgl\Pb @3~@co*μ~p0nJ]3' $N"-oo3%ץC 6&m~ߺbj%T[ iH{,b I/˫eW}L9u82oY Ct< o1ݩe<,)տhr$q3)- bXBkOP:=K 0q-Hq.A?jbR%e Е$Q[ ?& @`H Hh2?ЛL9|$k4iUP+R*RrZZDE}f\gaHG>Zer3RZ10Oʫbp.DR~ڑ K@@TK6ŔcVޞ=\څjN!H@jMZs |脔ND_i[õ ͥT֮v0UiDWNp| I( D8gzvC̨; D1Y|&AfZ\]S ^`iJst^S^%GS-)!XiI9m?ٝcy-JY+jPY%n|et8ǡ|oC~lc8_lee]#vo^Zrj墔W Gѹ7P/-C/ȔhYOHPHqT Hq x[0WmFu,eU<>T|UaF| @b8ȲY8\cY#reLג5JrƳ3S)@Y{d8w-Yc:)?HqZΖDd=#ʫd:W_ȅ.ӴݦvE쥮XʸC_z#0[?e /p}tތ[n3>gb^$U3H><2Hq ٱ>b<6 & tΛR{vx[5!:(YkN9:S_mHP9lLLl!|XP8Nnގ?y~G^E\.gS9#(pCyU2$u4[0#>e$cqrίv\SWLc:+8ߗesn܇:ӹ*Gԇ:w}2|Xy?M@f*Gp,J *c45++}q0#u)k͚?9#RvF}L&nʢl#kY=Ryҥv8Ѭs c "̋8Jf{t~VN@qlfOGtvU"6F=L }i4pet2yet;uڣ3%'X.Ax"\gifK{d蠄Fgvsɢ{70_=ZvvC(\[谅yJyU"2ʉ[KNT%ESs; ?&*=9t/ rDtM;&({gd8?%fx `,謔 TǼ7eqK\[(kKv#Hq ZBbV۞7XsmrLwZi;5LD@ 5c+˛nŚZ|]Eruiq ,j8D/$)aYV{ +G&휯vė 0q-Hqy>KMs{hPDό*oG*,68 y5dK{ g0JV l@b-+?~o)[Ƌ[鎈p _8 績]mya fv{ X|:[Ìs)%ve ._2Ls/E33C)@#utAgILEzUjk^?.,Hq@ qt|N-XZ\jVΫ#dp/GC9C)rz6Eg LG4?ؽi>+뒇 \TMs#ԥĵ A.09dw|k.0by <ڍ)R#ϟT^%4^OP^"wrh~:GKj3@NT> )A.M1Hqr9R\° 8:!okE&՞+znjunXk8:aFVeyLם4˱ݧw[.z]Y8H1V:!$"ohn1rb:*KHqrIp//)')H[(<_Qgw8oIU.f&~@@tKj@g dJ; I A.1?۝&Bkl~ծ@\4b5vOt G @@كtC%ދR::+1[4żhkok^#Ceɗdkfħ R@ZȲ%.䱶Aʲr/l׺4JSlÌAH@yr_W%H[dGfb V71yggiGUw.|ek2y˹oSjVgCz 8ôk#ʫd:W_ȅĴ9C] iZ|9$l^q?v?$Fa~ x4nž/y#RwFg67ҿS)c<=ʃE ;7ץjBtP.V.৳Cta** _y/}P{&a&`,t('7Z|o<#"_Sγt(kJn]pU2$u4[0#>e@=YÅϗʤ,"q$H[fGfħ R@ Q ~< ,HiUNd3YM 0dY\$͛ O]Ν)q8SC\vD"r_%4I{͗:}%eXl`96i[;lMgt8ǡ.= o6db,;'mZl@YW2$&U<z%@'lx#XS4V9̵6[l'.9*˱6a3SsoX 8IRı/ymV5@)(\:OW]v%ǟXA+sd ֢QߺtQqHdnOs&;4ĘԮK8۽G(1|c|LVrR||Uv9LK{sϵd8oHsV~d3rKڤ:-O ]/_c)D3|8)a B&1刱_)$/׈ HWEwߖ:8.MxۚL* AX,AβKX49=olG,))T*֫@iG9j鈖=,Ǖ6Ǻ6m@H~3L9^9by]S)dL"5*@#'g0]&T8\PN \ˎs^w -3Ӈ 8kZf9v)!5%JYܥSfQ c~|҇iއ3*JM$8}))b-G.\XܗbK]"Yc8>>wA"m1pHI3;CS9קF'cWϾIsx@A$Ŝ̊|A }ՙ[4(:sy*t2u9c=ZN98W }9҇iBq,iW :e9Urչ;ܻN]:ގdZo)}>}t7sA.󏇫݅~!t.T9R<"4s.U<҇s8d my6@C&488GtK2 N4|AǤ̊@X23- |Ey9U.xx-?WŴ6N` tJ8Ḡ9CtT-ƳQArzLHn)HJ&dh&t2$W*['ne,?ј0Yx/xk s ,w?U~/.h@1r/;qy::jǓ|`>My_=ZO`e m1'aJoq9=9GEǯbLʫ"G%' ipHsšS`H$(Ϋ2:Hq@f9.<Ć8pХ\9;y! 88.$. 1ʒq|hNzcPmi6& R.DY_q,~bOaC9-HqnLxSnH&1e9Add |1ܾcq:14ROͨtr9afrPy%W)4J@+˟̴7ݴ=$iWJs ]rqC6R4XR8gD8'y0 = Y)"sfT,&Y ę,m\9 @aF?XR_M>O@&OhԜ(ϱԟ=AލR~ qcqH kS=39 Icq-S  Y)4>}WR@AμXHdr%E'@Z"Htn]ErGXڤ3`,c:GbNH491_s_|Hq>I,:9 N܁lX_kh_]<'.3EeRH9I:/[BrfȴlS#IkKr@KH]wND -"ܰ$ԥY$@CХMfY =9%ʺ,SRl Gs7y֜Urk(qrQ ꒯+#x2۬|o~.7;k |S  @ *Il2Xc[W?GyuF#uꆅQ vI@Ӷ5.ݹ= ͫ?^gRo_AM#RsfIr}xuǿxN\>f=WicņK&7 Y^GÒHqGa՛WO]Xor{c8L1$,ZX<EYpr|Xia}ɺ$y#{puHqoޟw8nSp\^-|}pUN2a/XNuy]8$%v0Hqyz xQD0Rܶ,m\_nc?|VHqΨO F%;FFwu GUSȑrJN5= w^lL;i`6 TK{-.VR"v? q},ccqW% pvfT7ڢWu¿-#G̢),P p ɬS,͊u X u 4F=#cE%7ϑiIDATΌJ6w$yc ISJWW}N{rNg~c{zU9Nܓechx~9}Ů˿[#и;]q& <'y-,L;`ǎzJ,&z4Y ܎R_.3*֩gTؑrk홛 8#aogmQ Rpmrɫ`A>X> 2~?v_t8uS)9{q6{O^<c@~UW"Z/d9HV4m V )N~W~N~_i Y"\gؑHɧލe+#W)iOa`+V7wÀʴձ4W Hq2cqM“czW/@,mK>U)J8Ωߋ3 1|? }knU|бsY%H79buUR/هm!R{3Mm7pȺu%aHdܪn=lׇ]?)e,P>6ppu{Y]"G"՞Zm^HތWчm!c>d~C`~UI6 3N|4 P![' !8?c&Ԕ5Ysix$/Nitzc-ˢ}}x"q^`MpW[XǧdO`lw=ˢwp?ԫ[lطϫ5[>fggubJNɓO_r[dj~kWmH9)^5{wYµ8ãIY9S|&4ykI^WpR\.hF ɑbS+TdɻhhG6ȝ^O-3d,e8bA.ykHW݂!ɺOctًmTYJ#5rdF~_(r m^r8K0rWC)1ْ-P̨mmVDHqbi6O_VQދ.c>KG4%knUɃ`O^orn{,}x"{Mm7fpȺu%dj#aIRU2R #i[D+Ǯ[{WmmHތWчm!cn&lwcip+e[D_uURo̽Yq!$yjRpI059-kM<?|/i=?yZ>ޘ}[2\B*̨dfTnO:~ 8쉜韍KsݧW<` 3WcJch|}#3&Pų}?B5\M/9M^0QejrUvWEƬ_µ0ﱼZwO6d+F,9'XWpR\.f=>pNH$ 'WYuUF}ӫ)ęfDGnn+8P9h-v&Rlsrdr9%7֫CIXMzv(>6̖ob,R?N:-yuO~lIlY{>q;3߱0]I{vŏՕ|V9c?y Kn^5Ng}eGH %R*}Fb@026Ӳ`VŒ5#63=[X=PR2pRFyzBT<$W nԞ̼tov;jRܒ.ϐS華tyVҫ9,10P)k;bUZ=6z^a+{ o=gg,n$] /?Q /HbnVRYcHqWKzbG6ܡk늌HqyKzyoR%eoۯyv&Hqޙz?:Eݮ)un};; jYde~UrxU*6WǝZ18gj.ӟܳTo _l(WTGʇɫ" qז䷅%?cq /Oz ORrPd/UR{=Ïwl;_R!, `tpC6|+ZZY-ܳ7vf,5$Yf_% ؑz,3x,_ R4ckω\pI?i0ɫhHqǾ @8A\ٳpdV7 "HqMvlˏOv~[xU ڇ; ^U<'r_Rpd$$h^5V{"x0 wLbyS' GQ18;IDcWm>'ެ[;Z>bU`7V7 Sc^^Ȧ-|_@3cq@7L>7ʒ*^8 `mm<_h[n8yQ"UNj*_c_c_̖|Վ-׍.FfSJ0')$al4~=RNmpU͕84֙#y/e:±/}[|RΞ#;Tɞsm;q*oVɐV]k|-'G{V6^+CT}?<ڑ]\726;jik_J-|_}ٹXx$|(ίۢޛD>n;Knh}G䂅G[/FV_uY>U/b^sg'q)\87%kcLT-U5$ia6 w9ն-G7Uy_^2s[;Rp 7af|c ?ˉdEJc{gpUkgO[] Q|a{*#O&ZBԎИPΞ%sZ;}> cRRp6sW)m?R0,HqQ99cjxa+q %Y[.X Y"ɆqȌJ`ڒh'Hq%Lq`88)MYD'w\e>xro^r$xUg#>@XWܕopx9\fTtY+9rU|G cqO5LdXHrNO۬<߹)R.{k+>/r{ׄww\WJ=zd_w圹Nd'3%yn1!3|+y)]jg5wWw'|-?zLu߿^u:_$P~ Z\gWiOiz̕(q%u>r_zLJް.\-FYrͽu,L벂 s^yJ쯉lfYQ/U4];g| \i=уnؿ'k Ǿ5_~&5$ 9=_~%GY>\>+++++++++8kIxy׶6- ?WV_*9ʿ8;j#^ \C'([/}vŵs>Z\CWg ?kW{^+,03.r\ |++B'Dףq F-:2VԱTRqcC:WnѮ7pF> {X\; "^ur*:˟38\ rW4AV℞Jd3Wl'.91W qcF_/׋"̡ ڧYm܎Ծ=\{:Өg\|oz?4XibނkKx4= \Zų*5n<+>; czh#\ʳjϊ6USZe3m7׬YnhqxVPYvBƳW-S1Ʊh o5 籇ͩ0#5L"j'LЈmZfDāu\_Ls݌EKzEqh~8^5v@ц:}qh~VjqhC6@0WpEWpW Q {Bq.Ru lr܌PeUb7(~k6@ɕpMzGB2h͊)y9aZ\ڨaϺ~xȄ*\Itj; Zŵ_Vk6g6Q o)6*7c x Y h7r+8Y-N;Wyl\뭮?+Ʊ:/5($/GWOo_s$_I_\GWQ/W6o^5 b^=wq,?jc_?הoZMRߑ1.No+,pW="rUޕm:,W7:lw^q{ek/%:Tb^k= 梾 nr5jkK3v\U-@G5..㪢+BBWp}ɷYvj8cAN;ZnۏhqAօ3ǘ r72 ĺ8•5Tq*7AUb}ۖqV7vcM=enf4DzEgcuWSY9\S.G5\qK@Y56ͪ^W}+@D ~Y>+{lϾ:\r=X_h?T:~ = \u\K5ؐ40\Clo56'hJo=κ4XS: 6v^Ys}+Y\s4ؼOsq`Ck%+:pWY /$߻,'~ڧ5f{9SƷ:ld>xrMIOrg}hT6wE4\w6Q36ƼહV64ZL6nsqG4Тύm$9^yj=88v_S>?P,pW4'N3[Htn') F>w(uzh6WJQ7b:T\ikǯ })8W:W[ClN*_5"k+6W@~V'V\yW,cb>&=OMzh)S9/,Uӵ_UaNl<(zBr>G_alsUKOq,q?<W^qBWU]psMyUEVnsL>D}閼fy<'(+)⽣ʘUн_t/sok1+9f{}*6pe_ŵu ͕wp?6 CRES_;HV%N.;Ҙ~"58\õq\k؅6muUW>9>W5^p3Ϥ,cڨrRq=}xݭT&/KYgrk`u$uWݭeش#g<5v}p 5C+k_Ϭ*ftjr⃩eg{C~`-9.( ~&ggdQk o=5r:u+,pEחs񁲦VN18z^6*輑J  u/،Jϻ\7c{y/8_`ukJYCK)J\osj_eΠ[*>a׍xYU&)--V\^yCzd:ӳBpuJ񱺖W</;#iAzn4R1۰;Ĭ܉u[+s8ظ^l1mC\Km|[\ę'݊ U̪_]:ʾ&4捓gRmOz1* GֺV؆Gqcw脷st[gc{n揨$T-dk'&n 8W?mgUˋ?Ј)_֊I͇ Y41.hyx<(F {~n~>qhozsY mz] ^0?M4ȕގk[񢫕Vn嶩랔+wM0%7'kz%puO5鯃\qu꥾VxJBﳯ;tS-4ZrDb{6?+><+ɸr^F;x(ҎuOiǹ&)׀Zq%ޛj?Ѣ<ո@my{|qp== \I\fݣ5j?~gXgHȜ*_&USyEWWlh[\< z?t]KEk{z$;kyX4p׷:뵧y afRf\;aGK\.@Ckm:^lJA,9u]F˙x*2ڜir<*97`3kGb݇Fnj#גR2^m.'j-9XyXh5+pW9M?~7~Ck+)n&*v%빸\]Ugr X198ZKpA\_PX\X\X\X\ߐ_`~/p}8/p}\ 4pWpEWpW4pWpEWpW4p m~A z3\hGjh{\U߸= SDj:Z tIME$TIENDB`gxemul-0.6.1/doc/20131109-displayDreamcastMemory-small.png000644 001750 001750 00000004142 13402411501 023166 0ustar00debugdebug000000 000000 PNG  IHDRƏVgAMA%`M=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)|IDATxKlϽ$dփe)ilӱNb3u A tQp)[.(]/l]iQjPhjXZNȎMS uN2hmJfj?p1%D:%Sԁ&d" Y"Z ߰%R4|GAaG:D%bLfv4M7-?&R,&3aESE9+\?َ07 ]b^D0 I"M3wVǾ|{& RQ3n{`-&RE3bcхP{2ġW4(N<2_6ymzvP.ٿ~QLz?"}斈)0O<;cgѢ:y5p7JKꛍsm[߰bދ|&l5)zYE+sGRt4f7p=fn#Y˒}XEm !Ӽb*9 L&r鱏?w1[2J䴚/~ئMUOliJ˼!ߜVf1d6Fhpj:yKl9Ngr fGfOeܟ3q~?#n+]2n%=7}S2<nZ_ɧpn _IA$M[aR hV;0nE W3 )ID^D;b}l7Z\ht&S鉃#J0K~h3d#ioM~,,KD43juT~b'f _ȝ?9]L3uN'xBm/TI" Nb*dRo<]1Jr cE3,^ʧOfN{푬U*XIMʦ7ʯWۊ~ھv h7/ "&nx ]rIRƪf$>0<\(PT=ۋHb8'ƉHM"jc8㜒$B= -ƕD\ո(2"Uݔ|G3,)cU7E1DzwhqEFaw~fZ")IT#ED"H ;LyMTض]V~'zxBVYl> u[[9GR=jPW{b{?J.7uzލT*O;cv^r;Z3۞N<24wʵG_O9c޽A-zūRw Qj^Y~=4j]sPFlѪT>]bދ~پ <xڕgMtIME "S3tEXtSoftwaregnome-screenshot YIENDB`gxemul-0.6.1/doc/debian-5.png000644 001750 001750 00000013357 13402411501 016074 0ustar00debugdebug000000 000000 PNG  IHDR ~cgAMA aPLTE^ff%ޠ98tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I+IDATxKb㨢a߳A'B2fb- oZ$,;vWW:~#v2~;WxS~e俿y< hk6 J 5PSx"~f)gMg8_n6^grd~}9n1zrܶKSϴs8dty_:5 {l op &k{L\Q.Wx:$e%gxl ?}~~D?v{5hI} ?~Jt^^>O4H:cڝe-]C4s`~I9|O48r2}*58v!u8k[wۿLcZW5??COgZI> :,xtzy)0i4'i]pHӐvz[;~I | Bb_ƯkQt5ꖯS:,7xAt { en0|;ޗě>!HEחG~LM˩ݳ6s~FqHk>DS_0}%;d>PZП4IF`, 5рH:=AWNhE;ս&&]u<}MALЀ4hhhhhhhhhhhhhhhhhhhhh h@4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @1AЀhhhhhhhhhhhhhhhhhhhhhb4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 4ߖ|wi 4GZnQ)4.|L?As %x?AA->.%hp\WokpV?雿߿a]گ](iǸ}{ڷ?t>[5Hn vߔu Rr\O}>mɸ?K翧}Nq]k:w7&\Ax`H8mWjЌ4Ϡ4k|y4x?Ѡ+Ҡ߮Y kU4+A7)yYEK侮Alp1|XAXD<-*?_*˜]e/{O?S/U[ Repo7c=>a}|5w~4W5h"р4 @4 @4 @4 @4wwƕCy^Wzpaxwr1;g15q7Z nָA\x48 ^AV34 4_Ӡ3nLРT 43&_>lv$}v~CeǍԠ]t^)JOaIgᙖwIאLuS nnD:V~>Rxcv-V&AUIݯݺco/yئ_K td?]ho?%fi05c.cc~nyOM~byXudg_xw /A3`a,'ˋ y~7߶8ft2CSx{$N4\xOR~Eja\+Vn|7("}ot#+wi4dF c̢?މ|CFZh솿5 uή#s5.N4 m1_AiXk0EOaE4q!7m}f7yndA>|<[m$Bm57m1yjP ԠLjb^C kpR6^xofeXR jYXՊqX8b T)SqB1.B1{}lOZD_ OwlWKY3U]h ZW]8 gXe0T40L8ezҖkn7BnvuL~S9jp1Sy8i \֞>>s&̲एB g`vS(65mkC|y@B|dM+<) ؞d R_U`]f0iL6s9C,]5+s7Yd.O}MlO-mm*9Qu546u /ӠZ6خJt|A'E m藴oO!玫Q+?=w-@3{>%te}}sBqT) K}ϱc: ))Ѐ4 h@Ѐ4 @4 @4 @4 4i۠A@wPl<ɖזŋ._jwe-thp2B8w`iqkSEŵ7 BMiO4hkǸT׻>^ĴoAIaeq]65op2wBSټ i2OY<$ f3+Z)ȦAf4|t0a6A9oC qmӝ_ɱw|0>y'0Y|lkv<+ LhɣNsq:v% ݾ1cTgX`1x('aհ6)Mӱ* ,DK N~^Ѡ ;]B>Š6c9נaYz<0 HKZA.=,jl`qXOsT5vFl|4 8)4h6εpB4X(tc4_`!  5P pAV(7jpfiC9@S睌 A\ a?2 "i1A}yjE4AQ C yࢹn(qjf Ui~4e* C9_Sې۞ð2oC6B3 omw)qy^a\3­xkIs0@۴ա$Qnp|ˡ754n6)(˧%loW5ޢ(]X b{zX zl eXgkpEyct\9}\j0fl;4n*g4)/?As7koyp y[v noOY;ȩO) bX+SYِ [ ӨyjͥA>'rˢ-6WB0C䬟j_fv@lnwm|4p4Ț_jSjomOjps:WBmA k͒5T4Q<ǽ)lr\,6;X`J|E4v9"t)H2\{y Bn rܠ:9Bn44lAj׿H}%+eR\=@d4J .qF µ 4`m>3 NG$ynpŸ4Š7klp6 n)q0n@y/_=81 8*qh6~xL4 @4 @4 @4 @\{Ѐ4 YИ-Go]oA1+o*O}G]aӵtqHZhpLg_Ӡ{OOpg B1iyM}G+[+iGm␕ ewѠ ||jskF OkO9_:M{n*7s^s&+A9P}+e43 bܯЧ~3ͽk qK`7~n0Gm n @4 @4 @4 @4 @4 @#PThh-\hhhhxhhhhhhhhhhhhhhhhhhhhhh@4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 hhhhhhhhhhhhhhhhhhhhhhЀ4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4_ ] ]?~' 9j 7xz ~+"@M hhhh gOL[41atIMEt:|IENDB`gxemul-0.6.1/doc/20140802-dreamcast-bios-test1-small.png000644 001750 001750 00000004551 13402411501 022443 0ustar00debugdebug000000 000000 PNG  IHDRƏVgAMA%`M=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)|IDATx[lǿs3z56lm T"Z}(>$K>"5UTI^UԨC/UKӴQhҨj c ۻzw~kvamY9ߜ~g36#=?5iY Gt`?xφޓov7gmU2}&uIΤgv)u `fۓtHD)7ǜM iͪWקH/)c?cƆջ&dyer+>"zoխVMs?|n߾}Ξ }N~ι3ꆪuj_}(~tdLu0V'fl6qȉ-r_{QkqD=}}E/1Z-t?59ݣ[ >ZUq飪_~`+/~#߷{YSw#*~W.T*ٶ?Gq'|˹tOD4ﱜ{ J:r>s>#'+U-~l砸`^&WmL!u]vdjņzM6}@<M@DBܱ>UjJJk܍2Va~hƵݞ_|BC@gz雦Wn]Dz6Lc膱[T/寽wn.'_0n ~)"w7u 0%gSgό34&+T.jؚqצǭ$'SSGhYNgڰ /gq48osm/kf;xgޟoWhpضp4U#rnEGn%iVoR1BҠU6 4(kg-,&@C 0Ӗrz:qV{Y*5ō.?q+q.͹ 5Jeֆk3([z. so 1+oF"ށ', vH闁;BJ$ V9权 ɗ샑Sd&?G}e? cm(6ׅ`H1:'Y4:bvs䉛ܺ%|[1s::p_.:>?pv?m5겂WuW8cWMv|+fg#rVՅ:֮kbcx U;UZ`ק&Hω? AB&w 2RI0UY[V$ @AI֡JJB2pnXeL|Y7ku8xsRwW rLBQ Y%D+J懀؝ [" V1e}sߤM&"T5X MkMm$Ko{csY *5EInH#8J?36b3'Ȗw'YX?+7G{װ2dOQ4u,^"}\bһhZf'Cdlg`8d)v ]gtP}m A=9sPc^v9?XU*.NR|?Cm'ˉZ91V}N$giU<5C\$T끮isB9F[ c`Tւ*~v䁒%DHlA=SbBmP@(Y?>Ǫt& ՠD;.e3QSiC<([H@Jh[4.*Ň1SFE @F-?:zҵyBQ"b*#S\VT2?# 6YɱV=`sluwa4qv>gY~*)ŕcI":udWfM#{dw>qYw$WZ4UH!=ۓ34/dō1{ d[T3Գ!f`Ed0382&@zs(:LLHZ(qlM f2ww}Nݛ_UJ>OL2{-b|xi[sЛ]d85g3k@ovg]%ssGZ(qY؍PTɷsiٴPT*Rh{p6|6_z8_+X4s_ɇKGMe:9L+[7ωH7ՠšWߊϞ3*ͣ O մi:ӀߍᇂŞ~p,}4#UY>؉\Au+IL iQx%E+CWRĒnD-t2)6lwov[erfucJ[ZCʵFjP6Y$N&V[jr PNqDքJYwek`W{,,QK;񽌻_/@H P!aIAH= ~#簘ٿ(KOS܀4UƞVqڍ×;; !%ix,_8z+;ƞOHMM~Vu<0g6HU".M/f#U29^HA…es699X<vt &1g Uaz8MC?q,>kS۴NV#hqL  ^vAl 2hԬ}Uw&bۗ{C.iǽK|yax+~(!YWٜ# qZd#GRpR 4G.r#sdJ/N[C8ٞ#-qyE.#]&=9G>ሿ?" 4EEőφ8ҁ(u#-p$*0IRd#Cr)ȬGeczY #Zx=h}+F}dPŔ r6ĶGhgo}䌊=[rBE九#sd9GZȂG#mq|4ΑC>^>G҇TuPlZGs$y񠔫(86ǦGܿ#qgGc*"*Zn#Y#&+G˵c$;Y#fsژ#!qm9#v}+@,~AUWQ[}1et˩J~{ĸ~l}AKҹqiC?cEnQ~g4O[Ap2Pnl#nƊ؁"6W$h.YPĄǣ"VViydHGGˈrETOISPf134Q")Znq#A>[Wml#@\鿗')"}Pרﴛ1wy+J.FdSz*mK&yˑd\H8Lx4/{nGDD!nˊ<|QPd#.V2VD犌ELRĖ<I2fO(GHP.Ɗ49Ӱ>rTֲerɸ-vTֲ!3Z{tپG|?}5~dOՖI%Vd}H|(G,gG檷_J@֧9l#$Hψkmˑzȑ)\W>-BYP|dϚq¦^*z/? QDv'ʷ wm9h#ƈ8]!47:S$I2/RS UnK'}Yg'qDRE|Mu!!JN%EŻ۔ϥB2%{4ɸV?{> XѾߣFj}FX#&ox*Y.WćOOȯkxd:UM!^c6)Y[Ub$6DuYQ#G.lɾ.J!GʳÐ1ɑZ5b@Y  h{ =G6Td q + 2r--s9E\ 0|"'9Msݺ.neU\S"pgbZ^)YS0da>=G$V᧟b麺_s_a3ǣ BCPe-MT7t<#1S2xB韞pHsW+S#Kwmtz#IbkPGRiLi\y[Ɋ;G}=B_s˱j{doaYӕ*{dbsɥT4zB:ܮX٢^4#τ P8a''G6Sd}PDK.͓MzBFZ9"GsG1m7FEF$4!NX i'F>lH2bzFLDQv2yU 9qwrdy<*35(zIE|r8HmO c+ӛU6Rd'q>gCˢ2}Ők)-=!'F4P (_4Qd=!'FlZG]eƙ;v>~e^H\-Yg;yE:\bSmƗqh" (8"M(8K-*ry-Ƒ0[CN4<G# >B}d>"q)B\NB8Ҵ"&sX$_NH9"s$`R~-{O oG="g55Z94^G=:Sh#&ZLc-H%4&Z*z<A#\ˊuir'\{G.rIGM68 »/1%㡣2q-8Ҟ"zq)(23aL.Jb:0/kr}q"Li|j9 q$86f}Z9ϒJ rEKdxFg}UiRfeU+#bIe$Db'1?|VfVlP"6Sd/ ًk?@8{׌*GKeTOeuObV&o2@RYM.;k<|CpDH6QcE'q_Uڑ/WV須"N!gnELHQ7kaX/bLpRŤS3(k٬dshH.3&V@2Q63~}$}=¯g!q.bq4͆<_uV1Ed\Xpdέ{ˤ{ֻ'/A~N`k^3jQ8Kww#W~)S0#Wd $‘MV>G+b A8s/:,1VH>y"?Z= u>y}D璺ĎX&ޕ+}z$.0J箼[Z.c#Se"Ȏ>KHȵX(u5br\X4N#ө3Icg1Azj{kauŵJ OO( q-8"qii>AǞjv6#qƫ=~\KZݰ)}\kWfWsˑ8֞Ap$SD_=qϑ$, p:;!ղ"JF]I}#hg?"GQ$̪G#p8"'a<;ApT0/ A8GP#pE8"p#(G#pEA8GP#(G8"p#(GP#pEA8GA8GP#pE8"p#(G#pEA8GP#(G8"p#(GP#pE>J?" i+8cEHs#pEA8GP:E#5y%GJp9EHs#-rt^Fy9g"qƑ_>]Q8-"+li#)r^g&~v ,oل#wW+"p$)ҽePd"i#NZpD4i#(GP#pEA8GP#(G8"pEA8GP#pE8"p#(G#pEA8GP#(G8"p#(GP#pEA8"p#(G8"pEA8GP#pE8"p#(G#pEA8GP#(G8"pA8GP#pEA8"p#(G8"pE~=5F#>_MGVȯ8GNő_>]ꑊqZEnӊ8G^U)r^G.m8r(qG쑚r7JA8G"#xLr' iHt$(Gٽ3 ZR#g#q[}QZOiqwY#R"Z#‘=b_0-b Y#g[NƏMv#k{ix="Cpdu"xdc!9G}dk qc 3-7HAvR8R#iz̙qpGdGqpGL֙l8R#ӊfʶHEhMGjzd8h8R#&'#<2mjHS4 񥟘Tsj1c`-8R#Z)\/TH)rTq2!8R#Ş%J-76 `"pG&f܂#<212`8R#ScK<2[q48GoyG*xdZIH ,:6 Y#3)NGYGVY^]yE i‘=2i#{d"MȺY$pdm,Ydd8G^ULk< 0Y#',20y9bM'HIRKǝRRBQEH("$9"tIME 9[bIENDB`gxemul-0.6.1/doc/doxygen_headerFile.html000644 001750 001750 00000000716 13402411501 020450 0ustar00debugdebug000000 000000 $title

$title

Back to the index. gxemul-0.6.1/doc/20040711-sprite-1.png000644 001750 001750 00000035704 13402411501 017050 0ustar00debugdebug000000 000000 PNG  IHDRy^gAMA aPLTEHHHʋMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATx v86tLb.HJ;yձ%Y3??hnIIO|߻s؟48b:AS=poA$l#MdqhfӦ9 oQ~\yz9~<˳zr˜=.ʥov . [;z4h=Evii ,o_nxkU47\kͿ"jc\Nr@-q|A%oF} [b7M~o88H7rm+u:(;8(T:t\uw_])վ->i()p o/|6@Eߞ 6wyďu,lOr]}g.c8>hx|i Zz}(66Oge!˹˛kj<|˹wzim a|pw{L9H= )Yrs`?6^Ϳ/cW,ͫH 唐bz4ġK~!`kh~~ : AƉ޻>vtƥ/St΁1Mljy6>hjGh826n &ژljaMh'M[H{s)#/M֑l{i}r`֕*ߣ{:4r@{UhA7f_1+cVk%+h;@G-[wh{@jk5%Gwk'c|ϐ=Go~Xs!G khnUZbсm*!89HW8q7{Wd1e @viq, }Qrp b]0?H[$! H_c-#pPKz,chߵA ~۰}7T~FhƁa>! GZ(e_)(%NM2Z?s {"T~6-x^U${h"?{RJ]k 7g m:ȁ;8Pmqheooj\5tm Ż4@;@wsN$kE][:;/quMJ$1>Mme1l/>c`Q@)r `udzf6ZbC5jrMw{Qlџs4-2ju 0*(Up`Kč`@ꋣY3 22W:-W\5NҚ90"~ta,>q̘:-Tm=@:m-hAP:`/tv` j-̜/>>8Upp ~9cU@9_ao2yc[Gd/! a!6$OdEaC""_:{I8RqQ7ԯaN ھQ'-ޛhlk.Y%8M_5'BphZ4;kG[Ң[5(^iw+֎q?*\ʐr邎Z+14V9>juԴrPc1`MA)7mS69XfY[f9-\hVrB9nZޖny_ tQ{}*I-oqʹiC k;9x2>*r:׮ҼAKx)cNV~o=/ %ȥS@; P3ȡB93U8`p;~&v`2.%9-Aj;{AIݖ0ap;~aLj9w]댩3\MB->OY@;Au|`F#Zu1>![mn40K{y#|>ﰎ,R/Ok9kҖs{-^ >kyRק !e|N#s]YXܸD{}Rf8P9Z@5a=$pF,4f&u͉5P7{%[pj6'̚?A\R q`?=շkXڪzf3,f{|97ƁS=u+V/lN:51_wϊoϯƚ~SZ,Sd]p&k •ifYyCʛA iVo7do7yĽ3V~a^~XH4Xn~kHq]#P9f3וwr@#4r@#fL]U=#ѸtO'Ӿ[IV"\,N$9|x|-:FU4q"x<7^ ĤC_'Pm_([Qԡ׊=hZT׌-=CKZ`0CЦyfk>^Cf{s!l׏PUF&:Uǘ,spоoCvϧRkzl 7ppд޶r|p{5p0uה:!aOq'&Tar7@AZd~Ϩi|8ƍe:I+_*M>?`7%&tx*HXSjGW=jO* TS(T|mi!䔪8h p_u.Nԟ 1 >8(k?ufɹF~QCZ6(~I,;dz hMrs}>w5M!7vdϛ/ƟNa}tt3r?o1 'r.`Lߎ>=%B,;xXNhr~<`Kt=X<1f9u 6981$X.%(֒b-8f ;qnD>oFb}b<1=ov'L/ycA?> #u3bŹ:Y,[` 3tH?#c u1\Ў9YOT!I,5"k=um fڣ8_xRuw&s?nY@ڷp>PAZ T@,wَwH ѲأV?:zL&=>z-09!nѷg8֠}qfX?9zcL%蚽Zpz8|>L{"2幖nLvjǁ!G3 n 98v8΁o|A4k=w~H7k8o`Z3~kM1j-m ږPK Z4m/;譇X3Y~w=!L9 u]90-!ʴ>Ճź-)87{qx6 tdtqje6x AՁ^/`-ju}+KO9q?992**ϗ6]:ϘK vjBg߄TtR /ý`vQfO8"Hi/9vZ\k>KŊ[nk!vؠ@ _ώ; k|v 5={jڀ%x_P,l5}S*9^;7ĚޔzAS1V"6]Z/' r>9PHf8ū´o@?H)?q'^/<uf %Ҙ0wgۯJyurw]A2>X~ڭA {\~ATfuvWue^>8 `JS&;iO揗pS9K Nhvhf^W!/Y9O:RS_ت^W%0U ,Po ]esb -栮-mGpPkΠ_nd^߼,ŘvJ5^]Sȏk^>S >׳$j_UZ֍{[YgU-t"{{61U:eu]R`M[Z{gJ-ֱk7"7͝6(Ɨ%6Pת1vl?@IJH@,^!D]_qP~J ;ǻJ%NAZO[3rtA_d{̕!| 8ȁnj%I BX5ב~67ѧ`nBA 9~L1IASsjr󥒃s9h99`mMr)9c ~;g4r@99M Sъ䐯^!$טNy\2C>lLIN1>U,vrp``-o ֑_HP&=_ 6®urr@;"9N2m 8o1|p9&q:XcKc#k=N4`AUMvxe1_vghߺma /cs R~uE/-^VHmQ9ȣNڴ%mtŵi78ye [.DEPa:2,7覫{PQ+>|G.p֒c]]Kq@959vd@<^(mn}Ƙ!bb߽TMa!Mnq?z2?#r 1(rF $3ژyPbJM#ؾ1j.O9(rSHADoNSL'1NsL[kLӞδs=9}Xr@#s0˳-ܛv&dXWTAa9Ikj+v,϶p%rX1s9t)MFCD-HAgk|`9d~ZQ?wAg[:_Y|yymK~j,G&6a蝬|s y9WD^9MD<ˠւzMu8@}iqZOdžx5 KA6cv~[=$6ӓvyWik^`=>C4bku/7Yxq|pu'-2cOx5pp:9 fFh'_IDAT~[X1'9mI8HXrJ u~!v^/#7[`K9dX }NSkrd:M {ȅZY *ܛ3dZ a v]PԼ޴~!8cIA !!)i7mwDC[@688>pX6m֞7={7_(S sl}que)_& ?HhvRkNc~\c N/Ǝs. InpP;+~1v6}ǯO]rx^djR;#;AEͤvzwK5lqGqwbkP;Wbz/xhj~1Y#֚hFhǜ75p/58D^X@68XN~.~:Ok/Ϗbw^SI;0Amܞ8uer@#4r@#o]"L ^X-=|"Mrt4oS&&%O@ĵ4ƞK-ǿ?mۍ/o@ĵd<۩^_bu>s0w4͞qsswȹM+csho/ -Mϵ})69y99c9ďs'ԼM[Ś4WsnJ/5rO/;^}9]K{6̛M*>_9r@z=rTjT No(;ɴs!A r.y*2~ ƅ9R<3&'ʕaGnH-fL;AgFhFh䠬!ή/hV-M.k[}r0]Eҕh[kP'@~M eM19ǝppaPr)j8w:#/=)8EQ$^ō\;[;mHնeAN̬/Ɲ˚?((qp%\ D 8>hVI76{N슃s@68Vu]e~a=)WιaiQk xQf v~pm݇eu7I2,,iM(9s0;A"&@nϫ*!' 1s3qAnWS -h֒rpYbݔ[zg< 988WΞ yA̵!Q9wDAgF^_;Ϯmrp~Bss@#4r@#4rwV`d_?D?~UXqs.qvrmrեE'WZ 9Cw^j;{6݄ vokG+I끃v͚߸(;P!1~p-XkQzzxc.c9xv=f=Ps]Unkqg`R8G4MjAwz@cV8Ǜb%9H`;ƉkڦwVv~63qP^33ϲvMr88؊;Ce _hZiț0{?7aЎIfA\Ղ ű%H7> u%Kgw܍yŝcm簗5מxAc\38_H8_Q_ݿ_Gpp4wߡsLI_؛Di{Kyd9^oȁȕs5ls64C{@dhlWz#_?9ӉLՆs𻬿kX/Z XfaY[Y.Lwp@lwϺŞVb#8 ՚w%f;8ؖ->;@C\W-Zct2V)A\W'Lc8 ;8 -n϶xl~^˭-L{DUW?Z^ԕvՕsA9(qg[.,hE곡얃b?e1ro#}8Iv/h7?Եvrp ƌ'px(J7orP 39`sDRȲ$ČK_8ro r^yad3o@u)՘1~p& կ#4r@;!T׃(O53otE79qypth8;cӴo7Ffg8e8ݺ27܈?1%1ܚiڏ otmE硝Ġ'_1d(3E-tr1tp%=p~at3c%0>qOFy.0iX;zD^!8y!Ww9)v82f9qb~b x##>SyrA!Su?+enr@N1_mhpk=ww5qMXVkoTߋ~sp/64ݍ%?Xw1GB:Xs_@Bm.Z f#a 2pB-Ik<@miA9H@̼r w:  b_rusƲxskƽe/u/\^qr@#4rPú<km6?sàDo1u-09ӄi;@!81s!]@>nڎ9T[L&X 9?8-cN+>gqҔnJ09'W$QuƁ/m<8Ȍ5;t9so41opxU{tܰHB܀!GrlAƹ+r0͕9iy8y^`|bQ,^9f\% g@к hRۙur 1! ցFWXY8^Z,/?+g9O}bK/0jQ@'hiV>r@Ay)r@#s?n]s,wо_.u*˳uMteNn/U[4'9H qǓN y4] Q !SYiB:A\7̧\lfItmM1p?[׍AA<Xbl8hɌ:{iKZE8.1r}E21p? Az+4L{np+8(%ī~9(@Ԛ<ru$xBkJ-ww_'xh՚; g e[- }!n}O ]_9u}šNj? ո,74 Mu@mMkqK_x9VvAܴSsR L J59xo9c+98 *9 Fh6SnIcQ&ts`^i4z 1겝 [ kQr`m]Uq2r(,>[cl+N\$@|Eb]?hSzsY t`aoJ깮s`uta8 emFV-#>hEqb8__FA옃Ϙ<99ϫz)|h[jsJby\Po`UzFRlY akf?C,Z3KWY-īr[O kHSٳ$ڮ 1w{Al3>A],9yϭw9v)PO]Ui״ԡj|6Ŝq Zpp] |i3<%Ŝq88B?| /Tu$"~p@#4r@砬EG,vcgu'™9h Fr@96g#v*R:_vS9~5Fh`*x\Aku=^k=Z]q Q0Bv5ֳvh{ =Յ(UwG#~/\^t--v=rPrWzߋ>QAeh{lcM9[hԁpgȁN+@?"V3WXA͏4 `)'tħ?{/$4}s +4p9p bmh18>!v4oTM!?Ϊ=& q˻hMp%`O'կ#4r@#4r@#4r@#4r@#4r@#4r@999r ,ݰl铴o`m롄׾ڝ[F}쏃]Z4jQǼl[AsI:Zs~5ZӱN-XZϠueʼnu@~ր#; mrL782?|ec?Td~s˧4 mkr5O8T̷ :4oZC>Zgѝ|GqT54)u:e:ǵ걅>QVW|nKe#ދ v#;?89WA9 4r@#4r@#4r@#4r@#4r@#4r@{q~rpEL 9X;sqw&'!p|pVfzgrpJ/ 398[zgrpv8>8+3098!#grpr'v>H/98{?CN'ҸOFhFhFhFhFhFhFhFhFhO3Mh'm_I|p/988x7vwr@8h:Ŧ8sR| tIME )3R|IENDB`gxemul-0.6.1/doc/20040711-sprite-1_small.png000644 001750 001750 00000006062 13402411501 020233 0ustar00debugdebug000000 000000 PNG  IHDRtdr'K`gAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 }IDATxŚ_lu?JR3\ZQ##)?qv$o׋$@ /jч>}.ݢn-AAd]YٕPI[cyFP+q>hEw-R|o= E-4O@`7Dn+FUO#qli_fJeٖێC"m:-5>m ]qXzw{s>E4}\\ݡ%Q4RM0Ter)j"`h%)^ѩX3C==CӞR6U:T"tYd݂P̿m"'5R#?kO/Hd&+A0oS͖C`TThY <D@~5:m񆬇+ ?CwƗd7X(7~i`,/O֗޸okw2}$bWI_{0|. Lk%9/t ;ߊȫ~}#:-yѼH 'tə~!v3}>@  Ȳlʆ w9`Qu!LvoGWѾS$HUmf&ޅoLZ摯^/n'uvݾ S>p U7`_r#,H]>d6wCpwfei^x)ZY-aᔪi$l1yZSΈ YtxnAN!li] 4",'S}GUXjg-=.IO:Dti@۫Pls^]˼eBUt'鹒6K{iqYv6;{R^ȇAG㲳`H1 gb,:^6xp^A}4J:6vu,Ǚ7 ?kFfWbZA"kRj9ߣ 4D")Uᶲ|4qTpʙ/ikRBmH\kEFԓ;) Ndb6ni+R3Vu[;TI#)b8R xڵpd$1 /GjZIQ*C-[A8c)Jm*ҥ3fw2݉/ e>q/wrlʎY#a.[tZ:~yȣV@pm w6^m"&ŠyP*9h>s_/e}qZ:[Ĭ{h'lQuIcZr힎_V'ID=1JNIQSwMe;mv-Q]dŁ ph\%k*}*; -X~\'PUN헾|u_Pw 2᾽?wrp]}'X_/kԋn* R0Cx`\$! heETL BH1<)L~~DS #ЅƑZemʨ"$h8R>d^z>diE-$/kBMS,Ut} DMu}؍p@}MJM[x? 4(ÞzEaTlC^=S,p[QKV(-nKc0M}Pv{g#\lhuz +IJ:רaqQZu֭@g7X4u6A~6.ڟko!qg=JɅzhmb*R5pZOZ2KFPHzй2$YQq,pq?{p.L૤:])8i~:.ySǗ }#xx`%f]$9qPďڮ<,k~t+0nuDY cZЁU_ױcU]~6P\C}8WZ9@O` z9Yq)5'D{eh%RknKU~ zl1;IԻ+ThS+?12MVqkot=> ]V%4tIMEIENDB`gxemul-0.6.1/doc/20050427-netbsd-hpcmips-1_small.png000644 001750 001750 00000007154 13402411501 021655 0ustar00debugdebug000000 000000 PNG  IHDRt[ gAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxݙlyJ|O#O$(QDY%˒,˿-MM%MȀeE=,0(a6-nDْ6fjb'vl9%IESIt4%f޿\њ6^aytъ߽e; )r7~ͪR -w;s |浪 Z k7/*HԖ'EcbGJ%nkDmC y&5Mܸ1ξ? a2!CVZB0j+c3W{:(,맦N1VXe7p8˅jo߱y((ή~r@C5FVHs9VŪzj=PrӢ77}?,_oGGC>qo\:-|gB 8Ù Sr5.f8 [S=OՅ u/gBh&kLfJk")4Z1ᾉ^-`Us@ Gqb>v'_9=NLhEȐ[lDak^Q͹ږ  ad؋6|?(BpD'WPvт\C/km-Bϲ4!y9g@ 9$kX^MOTyupn9֖t.k5M..=+j|QNT猓jկoCO ?@KӞ6D꽔OQ~ǥڔ}~:ks۰w73 8 }W\.>69f&GIg#rܺƝ|LBDTE6|$:b\αWnv;~Wsлw_=VX<"y7j=#1uMn0f|JދƕcLָ%ep(i)2 2@e_ՠ_ZPUڃǢ#enJyp'KB ^+Y˖E%n,#8%i2Av6|7S# f^O)FO?ž`_|2JH̻fJĂt`H!KP tDpO۶6뾒6 u 4 aW _#}0xtŌk!k6Z[ՖN0%H9f~6(ho&~7}eۑa --]:;=~_ssXq; J`5ݞH7kA[ &9JiXd"h6kh buDL̏h A}TB:'~ir~4t^ l޳B y_wd_mN+ѽTX{Ϸ%RصV^0p%ki=jM.ܼ$ɜ`Mz lS 'AtmI-sn:tf>u׽iiu&rtk|GƷٽϩDR瞅UZ03Kb,TjV?둎d\W,u&Vh"ǒD8D-DJ }"E+,Ö^(xӏ+.ha†_)CVO\]k׆7k<6E$ؼJB"hK"4;g#ǟ)XE]*l.4d8X 8, \tĦ$N6B& YLn{ KH*XppMOlF(_c J=+A9fIG?&]ӽ3~:ʵ1xzme0Kp0>^¯#L"v "Zh^tI.0(~c^s)t-{7@ge4K "RUBM%ؚ cJ>iH߭5O*`[t9oA6/Cehƃކm*9Eg}3kj0p:z#BAK5!hPyV ~ L $I+]M:sj$äK^xpw P{P/ЂXJcHix4F3ʿԍ^4e?J-'2 q4pv̅9'^w(uvi & hnY{Ame썽yz|ՙfVàң0/KT fS*,~Y͹$tIME(IENDB`gxemul-0.6.1/doc/20060623-netbsd-sgimips-3.0.png000644 001750 001750 00000103427 13402411501 020634 0ustar00debugdebug000000 000000 PNG  IHDRd?gAMA aPLTEhhh848`h`,( 48 008\`0( 0(@`h@\`00 ,(, 8X` 08 408XX@dp8\X(Ph@`` 88488T`8`hHdp(480PX(DP(@H , @`p 8@( 088`x(L`0\x8dx@dh(Th 4@8``(88Hdh(`ex[ sx}xG7_^xX=X5y "cuDȇ=&{ك{/g^]s/6MǮ|5JN}=6GÇ{5$_I>l>@ఋ@A$ 3G[?/`!EW<8+c/tU }(8!<@4Ƿ8 ˾^A5@4%mG^8vtl ˑ{bFBB*\#$i;&GyB6K>~A@"0)u|@`bM5Ip҇P{qS"p$>`~L\ނu85[/i  F $BE|0O©ÚX]`$ˀao*x/m6[,5 kX?qޞO mp/p0{}Mooo-@'4x+{z`6' % Q%p }oyO rom@,ٱ@a^tMT}A GOP3,~Nq*fT7` KW |P[ܶ4"!JIa0VG Ba{dLgڭ^YW#l1QP|S? \%6SgW{mz[kfL5]`-7 h7cXT+Cwhx@s{j}qF1@47D5L;! PZ(m~ FpmHtBoJ> UU߸~AoѤVꦿ:F6F%+j}|JJ piο E5)4胨][p%  :5\Ё \kG%[ \{UsCu8mG?\";| :'dϻx4 B1jU՟WMCVO@(4X,}giKVϯt(~dWo"rѭ/(xDK (Z <&7 ( eyPx@mugu=>+~SKd/T9;nQ6 oF>=d#[y?[/P{P5?-}?u7>K*eeFmg3s+, &ހ2`.@V)O!:רkYxZ:yP[ хC,X,@w^`RpX%RV?V[cm}J!5\!ڋ;3ɟI֍_Y@j FHӈVU}@.vȮ ąBəȸYд= 7S,%5q ryͮ xONΗ,p 7O*@.}Wqk[-Ֆ l%9`0ò 6` DZn]qeYN=85|gD4U23 0&=8e| J  igT@"Q5qun*2!`x@ʞ}Sqz@@lD9S@@8|g 7qgYkUcv0+ Kg ϯ`@& nZ8?t $𝁊0fg{@R+c@@pI H~Ĝybf!$ Xp cq""LGgZdbs;wQKʮ1X1̰y6I-=]J˶ wiөP֧^sr'%ۅtwJe˺CT;piӱP (9 '$:,Q m쇚=lp |7]yij|Ch \ jZ{} u 5y WYtʣĀ[uʘNIђh n%B:t2|+75!*'Q$8li#$ <,ضPRͦ\!qOP,0z{"D5pC!i(BY,5\y<,4̌/vg.P pJj>-4p#&+O#ןX7c,K\p ī`0w(6%6XU]yȔzsbFbg:BUdU)5Q&[s Wz :3[W߾󐼒lj/ CůE8Z@4m"2UnOY&cũ<5fYоySYX1̰ԎM޶lϴs 0ӹ@2 ce \``xu 0)P8j4-:ُDe<jl % T5Ͽ2DxJ,ݓphpgSx_j? H!܆5](Mv4FXtpr֠`CyaI4mU =)FLU"i sKy ƌ[[!X```G2^w|k@|@ܐq䶺*l]DUI*3{sPK3FO1QR' vzpR9ʻ`Tt#%ߗ&P%[PeLse7T8.);Pꟕ `˟ԣ@p9 ך,ҏJi)W4$;z;߹:H9WU;baYU?hq]=}yoY tϫzjwR| L[('g[xR0ݕVUx @O9`]DB,:-d}ߧf)5hN[2Μ+ -@ݎ 3sB&\ Կej'-03w G?*/K`bM|=M3L/48hΗ84@k`(@2?.@`J<0R!s !2"XJa ?%F/ʜB9 GJ%`PcҪ(0xI|1I7d}2Xn AQH, P 3pCvWR#H@gK < Zd, j  ]Iʁ5(<^`X@F.)% vP~V̥\M P|  d6"X}`J$X*+L O:'yo4خʽ ru9ubn2kCQDQ<3`%GXԕߑPX5"VT;|2d@! L0QJܿ{`Cj낆DOBƳǴi35)'njIb_VO+BZPO_Ei<5ފ!.00ɑHOnAk4ryȹ #OXƳb OrRD8`Mr40Qe\y:).j'TcƳW R&9U;+vV`njwpjf~BLͯHy:k<}&`/g3Q+c(< kWgUw=\ HO ̺fUVU}` Q3xɉ׭V Pf@F %,֠XUNoI]Tg%V3rpR"UmGFdv@. ;\uJmR *7*U"VvYi:SҘCIf&KjkG4a+a0͍lVII BaQ@̍tf'5\tX`(FVj@xڂXx54P)Hpl c37Rvuc`wh]l`ylOy*zxi ++{&=+@w11)BncP;ʈ!=ϭL}9Y ZXÙ mzf*l$ؾz +S| EC><)2^X5N$y s{lbeJ =w V 64X-L,XOk }k>k[k؞>YZ s%3kHwƉ@DȽd5<0Y a J:B]%mϡd3h/Cm$qX!-k ;;o}V (7 1Vhs;ZNTmf;@qawtqj?⧵թ0'X7ۢlYrJ T[b & )n>rO#$?[hWe ȅ(@gC)EĹ{a!YFxp FJH@x&#/"?E6нlb 0sA ADL}qRj"P<(1 ߑ Fh7P T'{=@qMf;Isxf/Cb*_rt[OSZXR77!]S 1fGݜԚM tsљU0Tn`*h'xid`eYE}9Y1X0@;?ce^m&ܛ@Z_. um1f *qN.ʈY{?mNO2f|MlsjM{`-#.ǑJ,+#wrڋAX%A+q+l ͤ8(&  @;k(2v;a㎨D+$ ݆w7J$jX1b1Jk1&+@e[?i/֤ Vm+ڿNN~C@M1\8ZV S}ԚX0J/0'xVsVwů;v`-ۈ[ *pu@,z0b  HfbPs@G,QbP ČtZȐD Y|k1&?PeEް`OޑV/J :ECX71|;b/n4XS*@'7n@fD&c@ţOe!\g*iJ&1:H?y6w?M^qMꞀl(0L`Ƕbbg ()$4Z@4̨W p>=[3 >!n)4{MQ;.8SF>16Lse={{%mSi,  $<4!v"mt 7; xu[uoVU}3hr='``$͟sl(}r|v]v47z-' }D*2&[ZRLևRՑs2LsQSlϥak jQ o"x{)4m)AWf1.2/*@g8\qP uҍL96 pmKF[p1P SO<23_$bM* K>KA_@ X'@e]U'V 58(0rwuq(='~y!e%gprNAgqʽZlE'fdFu>L^[|?bY:n;w.*{sP+`@V 3@XO{.Ҥπ91H~++er'i],)Fnܘ_SxbWp%w1ۨsV;KVL: {T5& )@&;"՚U?Hgn J{PGV&D@erA+T9Ekl{Fw@:w/RD ~_IF>qD$Uq<$}˜OQݒZ}ȕfR'qdFΜBUT 6Ww?!Áxf@yA~XE^L\?]zP*HXIs nry.l$"+D$se[u$-:ȝwG)dfsտ$s6ľfLE=ChG(qhW Ω!$@Q Hd# yT9rؼ*zog˲'C!:/ ]wuUs1 g "V`>h 1$ ;EVo&AD+˘d 2!?Qk sW=8ROЇqPP7(8NiB(ܒ&ù û%mV7+$XʮOw^N @ v. @%OlI@ѻۚŸ>s:D;fU3$#'+B\@j:IgrXO%r"Y  A.BN|!r%0 3g)V@[ mg,e@;ͼ-[\qʩ oOX~Zˀuc;jnm+k0+,UYU o MA럧QVMcZ> XNS|zK1R9[VΪ!`ҕ,]1o;grq'WTЃbm`zkGZDC} z'ߚ %?i/lbVrץG00H h|uzlPӝ%?}؎@0HvhM?CO&N$zyUPvʎ2%8H*k=%9DWN-~&7ҳG-Γhw*d}A $82'=~]f&H z )7߽ܝ( Q$vUY1ab9\".&q̋(8v9HAOw/t'JyCm zy@ zɬ$@u$R_4K7 a $qI @fzάGlBzDO*V=^iJ#T4'<^1YqTU(!66hNLg; V[XM=ie;Qӷ` XЃgAH&`*no/gk' +Aψ/SIY3M `eZRo0X1D_dc+{6mfVe@ֲr xՊʮE"杣2 fu gjelCe9@֠aXoDGNn o@*<.8 x[ʚ)~(pk0VF:bx| ķwe%eXC _k/KX@-1P<3N0m@̕mJC(ԦD݆  ?ӍHDVF7'J$#'s:{ [ d7!@'łJ2pmXVX1?l|Kb +@qc@5sf{(uC &SYLz*%Cu(@bL>,$w ,3FkceUʎAg`?@V&Z;m J:w)Pn1Nk7R6CA :w1XWZ"$@W@J+yވаx`}yĬԃ=vISròw\%aCwqLN &]sc%3)n "%+c ], x5ytDcMY1&qLz\zoN 0(@~P%'<6|8hz#[6;z\|{b cHum;](lOv̖{4C{zv1UUۦ  +[UD!g%bDF?d;tS| v@nQc&QmhS0nڷ+q[rݨDcaex|']-[p8C7[4rPGԡ=X)\cn)\Pjq봇o0\Ě0f) 03Ē+)@F~/u$ݒf8GX@~;?w+Д4+;ф!݋y hC!-J4E\1>:@IAS}@NZC&! Թb>eɛ%=z eݒFo(s)pDaeZH4"fPI 'z-1uA Cp)= l`EFS$rh)iy-iL T[$yeT%|]ٛQ[' Ɩ0Pd_O`@{*`A2 GL텍<~ Ya2msI`~ږ.qhx[zy=Ϝ,~Xk~+*uw|L=уr83XY$TvOwWI8WahsX):@|`EvGߗgF vT\~֌`Z+"P3М +E0gIOd`egK@3f5ܥy_F @7Tg+ihYr+zj4ԑMe.hM7^u;` tD@Fg. *,vNSF? .5!뿹0:Zh?P0lЪE.r{O'r~nV'Z*F.IV:<,Avf_V \(]R?+G80lUU/1r.< ,; iB;9BKa~]@n-~\q ~HAMYsM->V?"s/2  WRu+]bg5'ˡ;948Q+6$FbsKc@E.gTPߐRoTnjGl\q'9gOr O$j;cUUx0mhG a(xTyHRC[w@Ssq"TPЪoyIs-,sT]1ǠM8Nic@>; 䄗4qq"aE~llAK##ZUg"N.,ph0Yi@jUʌ0ЄJN!ifSVU7 V ?gb/)| ` V cb0 0X1`U+`!l ?`VCD`Om'Yh&N[8Um/&|"v܍'r1~\Ph>m;h^ F^7eW oe8~oK3W?r8.m)>;B'H72YOmPdX`!t@bO zF#KG"6r IDATVVMs ,pe=}K pwg9x̩hDg iOmD @;x?ù r PP.6)sI`Eh#b 2%>(p?6-leDgjz5[@ @Y7j8 0ZDs(,fv,V&Mc@<<'UhHzo|o|=Q[Pl?晀~AKNw?k sN ϊ``e`e~ XQ1P8*dz<5p'8Bj$nMΉfL?!+tr;\BG! &m"7-nkұ'r9Kg^ؚOr)2[L:eHЮgJg/@ 4 GKEw&.T`%߉\) @dw>*Krб_ T%퀦%ּBQ!!ȽӎO r\C$G XB$> q;Q)C2TH6;bT5/D܇qo y9PϜBEU"~s*j}"5p]@.% %IҳVP!PUeg)MN7E(fA&tD)! _U8]RtH# ?qVx^(|L) ̇Q,jxCЌ}~~$ݽ S=d(Su#Aх\ AE.Y!9l"i|Z} Uj@vHԻBvZ qC"o|(ބdWJ%GhzL @j2j7Q`W5W败9 xZ!q cu5H׋ХK<yN8Ipfq3*SGNTt6, WYLrf f-iyG,scH("$y0v \Qɑen}Oiö62ֿIfk<;01qJs4ъ`Ď@ ~LhuC* L蘂"ߋ|kr@+o7)HpШ0*c~o X8gd]3;+6:ḱ@%7#);%~o/6uC,9*d$MD2u9NE)~8w/JA07y턴+)@Rl2%@r2$7vi0ΡJ@X jd ayBSZcl:5|DIX»SPe[I`Qk=W]@$3NL59XTD`C>E:"l(]o($M6cb+Ye$ؙhOVsSf,R<Ǐߣf$M T(&T2R 40L@uh[QFìp]e*I +"s2f c  5zdYo* jf3PWǰ\;~9mo@Rj Z@cgGWpL<Ȟg[5=;6= \#v+u(X }= 4ll?CcAԕÐ5KLlȆt&j#sJ?]Da|w1@)r.d #6p1D[ l"*S<H*m;:]4,+Q"R`H 7\<~sBжXh59gМT5``Z`-xlHKh-6oV@d&I7M \TYl&i ^?eZheߚP;1PٲDmI'!'P~?'r(J"Vb l[GZ8)[;r`OwGI_PZoHDݴ#1.A_+Cmb'gDN8B..HD RFsX霢541̰z휁%wH)! DiwIv L`C~NF $ʲ9aFNs-dOeN;\ js5}V_HB\~ /OC$'}_8aC&#R=0F31EVf\L 0GxHVttĻSoV6r6^ukKHh+K*w %Q-E[:r\:7t`D%pC%9 ro#"p4# 6|vp%x @dd 2Rpx'# CFa,9=>p!vѐ~H4dD?$"+]D*6TAQՉ "GNu6B*MD0.2|g0 ٝa%s~#t@pAH r &PKR)15͈ ]+qkl(J@v z|ne8K]KEݡp8ݑ<B$ϑJP[ /s*QW\jM ?J(2@D2kpq+BUnkZ+ 1|;-Kh?.<SQu4Tg1i1J~<3CH6 Sl\<80Jʀ?t!*}8Qeۅ&m΄ LM& ^*nfLq555nd```e!R){ 1rfh[6yk~rmC+>waB>K:\p\,C 1KU;o6Xa@ A|w rRC/φH%T0>ԊqR7yW3]5X!(x U=hAiDj|@ JK&9+K\qD鰾6KBJ)ۻh'1B@On<JNJf,d"N`][ 0۾1Lg!)`2T=@HQm>PjC$`83Dؼ饨 & r. ՍAq\,?|"@ȘG߿D-z ǝ01Z 6PbU`ܼ&K+Et#@C; UUf [0N N $^EPo~g[pq`xb_rQԹHgD[0 ^ -!e&Rv- Q(0^+2xO~&<'U%eC#} {buR-d -a?xվ ps"Ј8t@ T(Mpƪ\64v*Ix Y`b )T(qRb '/%T`\pe  g XI$T߆Glh!4VOG 4說J-`Onl V&7X1JMaׄ?|f^]6f f /wI18\G-:mb% ed21 [Xa@r MM}@d7l'[1,{ߥ>K3 R VZ VT$Bx> z\klJ@'!&'"v0w`+3uMO6c緪kg VaMYB"!r"x"!9 Ǐx`bVb1`-6D6/9P͆5xt1@iM}E*qPP (l_iv~kBG9z0(!!A@8MiPRAV1`$"T2&.p2@"Iϖ z"P& JHE`lЮ/{OII qW6;bKѠ&SC Dl[Ur 5}tbm[VONL,ʯ-_+M5(= :b W V6#?w"/"3_L& ϏDk L[wSX$@w Lu%5Hs' %8ldh4\U< "!;Gd996 Σ ww/q6`1 EȹU n訲0M$FyA# ?w  6wW&sRγŝM+[*z$a>JC"x7գhzi}K*"W^?Xϝ. y::GO @J.oZ IDATZګ ߙ@4Zi#5xw<&>fe P@ xB=U:!-弭ߥ l/ 9v<6z AL1;JEsP_粕$4%.7,TT>wjQ& @0эU.IN3 &Ҿ!qNr?r[ۡf80+PpUUrKN]J\[0 ;lP7g ȓ(g!f,vF.< U f. 3NBr2 ϑȪZ& j\wNMY%vi3BCiL K YI;- =?ob + E+P5tHpfZ<)xSl.   |\kCۨGZ)@O@v@<'?XOv ]_}ˏkz(On"s~vo`R2LECnGV;-S7 ]>3ڋttTr:cR*mTe@1'h#=F:<R:]@֎ > (F%P" T#-)u}  %0D\Ej|ϧ"F /׍пxk][<>2h;TV pm0*PZ>‡\k%nAV6XidDB0 MAtiR"!UT(BQbt ^1yϝ"`"K9.,Y#<<""j"̉H()*҆ÐrT& 1hAcw<.as$9g?wz`e"!]TO"P pOYpϝ$<+u DB$mti3Sg3 GG& >w \Zo>?ud`NMcG;X`O|`0_"(O_9@CjGR˂&s}CoW0P^`!@A讝'v$`B׼9gxjOILX;zsX}IA+T&KMnfY'yEź\5KߧДF h9%n3+hevh:ZN6T1 4=Q1g #g;"NeO<m30+jdC( rL@n~(ԲATDw`%ˀH|@i#b(Kk_j.>}V::t%{ p&xVo(AueC^ }m+jNElSvAk (,&R*lE=}&!E$;F:r?$Dz?B9UU--lhaC% ]GDř }Fj"2@fJedKvz@Y]Mrِgn@-P6h1ܒ1rĈel=Pм=@7 AYߥt9?]:1wv^,ҷO1f0^Ӻ`A_|#Á]7e [˴M JRSU9)&rB$c h\CjVoeU_0XL|`e NQFm){3{8 ;-+-Bh0\.bNn{XJPZ\63]@x{pHcpr{SZZE_063C.p6]HAHz;w IOdd8.^DӠ~B>۩6#{15 Ij/#_0l-:SODq3I'DBhP%Pݛ%Ӹ>f VpIw)K=G,e% 8 5'> pٍO7H zgK]Y#*gg>Q \n!3 ιT_@*NjqN ;WY{Wv$42I648*e[!AC*ddSj4D<x/eY1N.AR?T 񉲍I+MBdZ%R-m iX9E='-Wp9 ` $$6]Zd@Ϻ2!mo4K@;3k5F51D|320&֔G Uݢ@7! C* gǺ[XsU꿫$,b !=ހK *gF~3ژK9P VU@ PJsPj$bWq-@46 @[jD.?RE]Q;7P< Q 3M:$\cG ٲV+/a% jHk5\h Ar6)R]AX=&BUU̬I@o6V-GEybD+lA&2pOnQēHM8&zt2y } 91P&J5A69!IH ?MEoбOըէڙNTRˀ/}< '6YxB`eB#a×MD}!ʸ#mT+^,1O/JpDj޸%hK&i966+5N]\ T9X~_#@o|9 DÓ9`@mEP$pqy\\%{yZghb8Frg -"y)yM\1iXO3PQU,p@SfyD0٤Ը"@^ $V5Adca&!TSVYਗ਼pZޔN(OQ&PG\|1he2%rj٫!@ޙ n)@I (pjs$6k%zލ]$ šc-pR$#9 9dR @X jh) $f|4cI)E&&2&te@ߏh'?~WMvx&`cn/;<,u:Z1 Y@#hwӞ#1N|,%uIX%>l @@ft֦f`ue(@ٳR.ĦضF>C$nfӲoR+tM*Lw5!y[7$ A.Ve baM`VYIPVRՈtq׎2LePxRKZ5(քF-JO2`a=fiͳs<`RrUeDi!-}f[7&jr!ZJ]^Ki)x[pu̮hޣ$(2z]PSN@>;5pwUX.JPç,":˪~K}rI@R?C#(Di +wWDae^CE\Xkm:"^u$bpwNt/t}YY`ּk}[Y`{`Q_Tm@m f+]; V W`(0`20 @Wd_Q BĺHyi+wY` b54X "0e‡$u/k0+|PF V5q௙J2R\5X19ٗ ̠TM+S~ܓrWr+[%X 1L'ڏ`_j@W([Bjwrq C\cnuMMyƏ٤ٸg_nnV&ZnrN=tGyW'.O?Щ굓*_[w;~/GC[S?=kϽS7 n8ukpns]wSםXs7,_XŹ?8CNw^~kN{zc/UGهN|bߢ|n>ɋϝi;:y;N.ɧ?o??'oYtOHu:Su喓O[ogno}Ӌ/7tsO{ؓϝ{{'[oz37z뭏?~嶫oWt[<}+_z?|+/?rG8}z/]y7=z9 >~{r~YT/_ËV|K?a.To</o_{{p]GWwz}G>蛟Xs-r鷜8}'NX\|O?r#'/s]kǫ7|#:rgξ~ϙ#Չ=rW9rμ:|o‘3'Ϟyٳձgo_eRuW~'?rDui.=3>‘Gro˿wx'- խpoU~'Z'.^ʅK_zxq/]zK_꟧>\廪#._ꥯ^;/ի C/rX'ŏ?z ,#}/>tʼnw?~U/^.V]aѯ*,/ nxSYuIm6gދxϝZTz=SxuK9NVxC/-zC'_?^z襛/.;s "Rw⯋wtRFcl_W 0*T(p~b:wSxӋ]1`QpM؏;w'{Bgnz;z/=;ܿZwu/8E-:\xbm^9}e?ujp喙E'^t,*uJEZuή"¥|xT8Z O/i•sѪ^t/Go ,'~WYuO9‚?8QuUYc٥ǫ |Ȣ_~Ǒ%z u#C/> lT x߱x[u4۫W*$,}يۗy@ο%x_wPGN~s%&?s?kspۃNi wW}KO_>wӷ=ۮ^wݹG{սqQn׽|uŪ.>ŋ7..'[ }7T=:׽|}|ꄋ^U>USnX<_{aqXſ_8?|\xˉ[_8eG9}ݏ..|xׯkYDUX3Ƕu˿K,z#yȭPpl1'~'^Tk0zanEE&IDATU\^v #_gyE*oX %=!ox~zNU~s#_Z./"EGĂU#ɓU|?E_N"dr>[N~ ɗN^x?3?V 9Wus*\h?Zǿj4UU7=W/'o7SU rp=gɕU_sK0jOwV^o[?xs/s+ٿ,Cj=]}#ÀGϬP]=ϫ>7?(UhPEG_w UsuÅ꟪X<?{ߟ<^[ۏsћ}Ug7L/ƒx`T/% TVg8qg1đ/G"nϗX`, c™=qd+@V=oQRU\Ϊ_~g/U̽rX~UyKW+|#mG>wΓ/~j4wT~?˗<~ۗ?p'𢡊.mW}{'Λ>|jyGz\mG^g>wW_\_{W;#MtIME ;^XIENDB`gxemul-0.6.1/doc/20050317-example.png000644 001750 001750 00000104767 13402411501 017050 0ustar00debugdebug000000 000000 PNG  IHDR@gAMA a3PLTEd^"4ffhhhp'8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IDATx63Iv7$ź"Q%t2%M*qppp\4A:~7w qp<5 ?;888<<uRKN[;qpp. f88^o xd+j" 9珟ٽA?/Tj_Wwlx  q?}~` ?~>a?]otϯ_*iz a@/ğ/TO/$?X#@& uB5"Sc@?~(\r@PpQ9}1?~>5Qmrsqyy '(84e@gh}?J,oɧ}xJ.@ {IQ@2D0_z+Pp#ߥ$lj`?h9x SSC2Ho{B{*E@L6hUN؃i)E@2sHY H=TJ+*E7(Ar @?̂quGꄑ,ɫ5/'daO~g>Adhp^ߍ:B<) }Dx!Y…q97888@QFdxd&rpp\6.#/?5&6߃Azצw;W'wy _["е-賿ҖϥI"z^u(7yWseW ꑄ4I@ r@܅\\(~!8q>"OXO _?;p@%I|nϾ)n }=" "5@诿f@O r@BE|/F@'F@\K*#DU9q@w`E@"8ݓE@@^TT΂eo"BD@\2K7тQ"vWZ Nj~X A%F@'E@\d>f=~@E@G{B_q<z5xh# s" .|.18)7aܫO|/}+o^ r@on @*>+*Gb]^Ms&-ޫAXVG|NJ#s>.I7{j"4+r|G|П{(R`i| %4{,GB<}^*`u ղy5>ZcBOۣC#[6k^~p" ѷr@SEFj:!Jx9r@?|p|P 7yE7_Oˑ/ʂy/s ,ΙHϊrڒqw=}Q{jz#VhzH|@A}\bpNh*عq2+ }Դ (뀦倊Ł7hՄmq@hZBD@ROtDzlqzTc(жQB,!į:k&dE WT}^8q+txQ@EUPf̂9VHG߃jK%0_vWQ廯/B|VYŷvBc!VQd_#~@L|,XPˋl(2Tnx^$q@tE T=[0V5܂fZ9-@^PO&ɂAE찃vˇpN-itoF!*?i=t"Er@*r@6%> ,8Ԃq+F8$e#:+c̃tmۜp}Iv Ay{-ުS, " @7vT[&=ބ>e%E@O=B9j ׿~"'jON>j`+Ti sjuN\|,X# C8}IgbHн\1T!2QP?OE6^?--R?eHVr@+$A4o |gSIdˊSb9 ~A_{׀DnlHgH.9yP= #F@%wfheݫȐp8.tP[`"eYD@,طTiS ɷl)OS6X'_*7'lmk-fSJXA@.Nvh#6)`j[1D͹qetQt:&>$3()CꎀRS=[ SJS!9ޮ9:W /1 :W ּ3$B&LF<ȈKόYgTF&SEhR0d¸͗9FCp"{ t'1 F ?#Uk]Fz֎Y-dQCb= b* jOP9\qiɞPnV]kQBhqdI 8o":@sj4,߃O }n{w V 8KwT02)f*e-B]>`xEb r@qa6!j HH:ibeɤJGB/PNJ5+̳h9KrpaaA9~@nP Rht]@t5-`rE$"ЩfJ-ǹЅD:縘: ,K""DhZ1pH/JIc/PtC9B"bQϗEH Tt<Z|:}s:q@Uاy,BPZ Șӕjd r,@]5%#y @<6_LWY0dM9Pd+Z6HG@_": @jVYC8-X":_ /O,S^k46բWp@62J^6έBˤjԼ]d׎F6,I#8 @䀮{y&5b ts@&〘jz+AhJh[8oZjkJ9Ƙ -4[j@ojkE]2Z-9&5MLjpa|Wurj tҹ@-V?y^MԂ^ES>ޛŤǝ*ɏ' !j:&55C9417'H;WVװu >cL&Hc6gQxZٜ*F@(Hc1ٻk,' (fÑo/XnvFmq4M Au?yT0EQQŸV.V}$/ v3V\?/r@Sr@~oTlP.kg{Jj R|eJhot3j2xw(Ur@Ss@^Ev AJZj(fS+H[qmó:6v1nS '|!#@ Ĩ>%p x1v@5jGlߢ~/ƻ= p@9bԘ?vSet lQ5*zcgT )=vL. p2e_7y^bk9 {Ѝ9 i(H?"ĨN@EBJ]zBk$JWCbTr@n:0]"F^|>z/1*9 r@}5AĨe Qz,4-Qab")F%DG&1jNY=V) 6A_ro/&d'q@NgߤAЃ9X:aASڢǢl 8Bo?@8 XO16]m+d1N&(WZʠomh ;kg)a'WE:}Y[a7h65d\^APV pxË ÿ-r'QU-WHF4n Ysf?׶kmˏu:yi[Um_ o'ɟ1IN1!-VY1<煌'|뵞d1jD ʗ7fZ[Myi`qAhm~B~U`E@d^X@էtW>@9Eo1m6}d*ԲCr(' @8 ۃw1% vMbTt\ h}`Th3 +×-ZNr0pmm@Q펔7Yu@h{QZ`Qۯ|XS;%+Lw+ _[>*ev\ ^:HeIu0 +_au@{Ĩ:Pl3oz<1^|+?hWJ㺫oŨ; -ب.]3wQ Ʒ\WN-؋`_@1Е̞[zM)iPЖr~# mtx(3.e @ՠNm9 ]0gKXEl|+іcNn〮evݎ>OWr@8kHmy<텅 IDAT5Vý!qKЂ?Y.ts{+rF1jc8F^5{F:4lY axCD-lQ_@1[%ZyT )ksrhtFm?y"69jx)y}_G" vF=G*WoTW]kH-XВT-x:zr@QO|ZdȚNck|5 @&p$lS/6}[o6h 1)R*ApCBW"HbzBRi{s@NSڐv9-F J=nHy=Џ^\ Xxu\>3j97&׹]+F@9deB'ٽ+9B&њ6aU(_єU\l7fa-9|LebT@pNV^^Yl>՟9Sh"i3^#rsH[-+YXKJ_0AEbT"B,;QzؿrʋD򿡀'Ʈp؞8tu[]^]YuPV:-BoL+XQ G f\Q.?w _ŖKh 'J)&t7f _>/׻Q#oCS/ؗ#x֮>Yk] N΂Q (E5{]ZZc`T^!ڭȞ@oZ0!\tQBE `R1j^84Qd$mrY:?/L$q: Fݶ@+8 |*=' }6r69jxOtL%͢L7PJQg7ڮr\^5~@/To%Y:d? , r@Q1uo f 6[!u@gQؚᷭw)4u0PPj{Ĩ;"1j>w5/&mbHy }Q vqggTjQ qvR FZ0bq6W g%Lj3>n-Ƕ]1G'HhQW^fb Twar X;;GL:WŴ λc xZ=bT$ܯާqyu@rꭽm4 Pxg]sOM{Lj"1jӘH:I; c^1-Q vN(6>iK]yd )]+F}Cy CzlAiy3*+UDɷLX%d1p)B1 _Ml %ĻЫ`OtkLYp=Q;~@,V-*VY@MF–Y&ۂ=*۲`^JS9~#:Hj ` IШ&^m(YEޜIR'ٺYtҲa?mx?gLMZV N>߈\}`wvFu@{`/Nj^@Ԃq]qL'zxA h[k"4E12xih:17J7錚TS$Fk6Ez>4:-A^ ]S8ZNbo5VۿKǾ0Ցn:E]O=bQSh~1TiKd윰`~(.[%ttΑ/_:[n-إbTpDKBFe.(HJZw-Ũh~1j@.@0;J]@մ\g;Qhb1@1B'[%4it3jqC@sQ} 1j2^tk̩Ղ$k,[%tMlgTM{𘻋Q7^sůsĨ\qlȍlgTYp1-#r@NjQ 1` mhmm#2q]\E%lg ѯ5h6 V?gQ1YP:<&P"~ vFmyH\ ϡ`OQ-DӠ{J@H  jƄe1j~:fwZ1+p䣹: ӫBDUc"oZ_J5MUTAݵ^:Up@IxTtoHʧ9 @g+FUMK[qFMQ TgOEJ35>Ww(9+# s٧@-Ψ%EPq9 GC,stTDQOShdYqe:*S- N벐>79[p@G8p@-Ψ5~cnF:p! F JQ؀53*`䀨^[`F~%_0s@qL>n>my#%ԂUr@ {_ j4?ˁNo'Kq31B#F`H97fo_"Y*`Y%8Ԓ5/-W<]Ũ{!Yo92Cd$OOzy7 ĨJ RAP*"p-tя(T"Trb{CUH_+(UqLF)\Jt9KBSJ-9&M nJ-9o?ǽǣtA-9FZt-}~{ǿ_?~;<*j 6m 8̓Iֺ᪲> q> н??~aPF?o}'ڴb38 D,j^5ضN-_?uיZ;Q o-oo􁝧9b+FkM: $7}GPnFBߞ @'Q1>p@JZZs/:Z)Y}xn~]ln&+an?,pKGsQŨB98瀄Er*V͢Hf-}"8+G@>(p|;A6D  E@;8g>$oP<1*` rBIFȔ͢G> Vȼ$s7ah'"^@!c(瀚(X D@B5z˿?w!_S 6s@Hp@M[0>=3VQk7D~,Xq 9R[0%_mvp@ ?QGE@9WҢ<]*H ʷ99f"Skr}YcRz7bC7+F)Gx?d!瘄ߖΨԂ 6q@oʖ+Z;`fgk8@[z ~Wylv4|Hx"F5|\(7 x: ъ5jtuXzEs@r-MSڐ\'Í@'6(DG,!kYOk&SQC|G'rͯ#@X1_HTrυE ϝ`;:.8"fj)5V,or/[0$#V`YŵH¢tU,EoB zܔ470hxc`݂}1(܂>,߹ݝHq@Ru)iP ~tٹ4gr@Ox8^"zg=P 'n*wL @V zܔY 9T]XؒY$qA#:9@QiY$dMY4Y0垡˗2 "|8gdde_:;QzҍHqj)w@<~~mN܋lٚ_f5n՗z;(AȞZ0r@mWXS HA.y&xwxCtѯ >Gw&b:C-9: ]] A|+ E;]nܒ%p7vZ0r@QTw ?9 `̖1 ɜX߅Q9UB sU(εgq@4`ٛ}05:x E_Փ=I, o~ق( EPd` iyܾHnA ]@@! ޗ*`+jD`R6B:~-a 2d~mDԫ8r:Rg,7`*og6,Yo;6WQG2Nz1QcZWzP''+,YU_-h/6%r*Q&A2h Җ'"SͫAgV> *x v/7s@ Nta*&_|=k\%`DLnk! ībL 1~=h->QT _eZT7q@VjK%+P eYCDsUl'yz I%`-raۜg-̢ jޫPo4ͬ\]͒DsubԲq>IPBf&M' h7Y=>W/ENZ6N5QQ*Bi-g5x u)uܒ;bԊq: 61j4*жAӈMl5 ?&3[-b'r@7,[jp}@Q#CEeySSx^r@֚y1BH )-۾1 IDATp\m,w= 6?!;^V /˱3`nCg}Y~^r@ Qޛy-9Fq@'Q&kR @M<+XDvP\zuqt칮pہ&m2*>-y1T#P+@@(7[jjI[sĨk6wIu@Zb Uш:%sAz|^G;/LQ;e{LGmmM E$E #"ydy=] ~dT6]#F وuXS=<0! BY hrszBê0VAhX=[V .$_5 ^#5QS$%r@z:5k/Ɲ}mUNLp+ lؼ{yo@)'F͖iܥBQZɇ+p 4]=9 zrd=QGs>O=ܯp@̅ x;bA8~C瀄9>W*#a?ȡbZȩ?j(Ijvl7:9#8 -FQ;PM^DyC%O($1hůUۋŨC1`W~5j^cm꽵`RD-ث"_9""@{85de xIzW[+W{8E8;&An`2m.ڴ`+"R qiĨ[H>7&Sc.5,-@ 5o~ +xYq1XSl,y>IBOBseTzW|^r@h\AbSQS.FP,%WZF[a5ei8Ml|^r@厈^ajV;,ڑ0#WYZ|,8^YJq@ߙ0wdV=/9+hUpڿ|dcyP  jY3Ih Aq=(YwJ%R!1$8]Z~@Ga\2ERe };vb%Д^f-SU~l1U|Gz=u@cGc}Ԏ>!J-epژS 64:ZmubC-ǣ#K`gTKi3S1$z }݂mPIB-8:o`t39r3%ia}^QZM8:SBkzE>$|JaΨi3hSC"P̠vL `0gv1kmͦv;[`"rF-msFAϩw9oߡD_GAKd1Gj#JJ s8ubuJOy)r"/5Q+Hkn(h<9 <Rkj)o kpE߶8MWпN:{ ~@;ŨTR HBxgTδ5]kc-S`gyNM%s@>32~Y9.&w.FU~@>9';Q&t%oUr@H߃Gs,§@B/"bTH𤧞0Nsr@? / *ep,>S-e˵cYOB[.:bƀZZ16ǥR VkƀZWu@0QsX_8oT-Ǔ#y ǪTDS' _6_u"/jzHŐ9Y(lȤ-%HclB=giDI o2Ӌ>%@z3M"F]f[ᛪbRАtN o-ofvjvFS󨏠񄠾(q:uj !} HW3)JBHB$Ψ'=-s@Ψ-u+MAD퀂;ł19 o%msF]vA\w:51r8l8٪f϶p6}11/+DocSk5u@4+[2 24Id9 lR4MFPDmI Ň'*nE`A@@cYkƢ:'tK~iX 8D6TTФPW-[6,h* Zͭ45o F+LPR~ eϯ+i|Օ_`hfSpzdI-;GhZ")AzP.m+Yw3*̟;jMChL\.XQ/鶬'&*+53G[HcɑP(A&=蚋ln. U8 4zn ,ú8 lMPd" yS4P !ΩjKcS5A֧_*+Y=5o.А{(˂6f$B!ق]PTюᙆlD+CC'THlUDFTLE6GGu@A#6PT̑} m9J~ˀ4|lBO n9'2)M;?2 ߨI3h:SD:I % Q ]L?`[F-_4<+ZzT5b lEO+zB# 9 zSEA"=h D"t~G@a'-.ҥA M鷩+x,4$b.d' D9ۚҗ# 9yxlƞ 3 ogz[qr4z6]l#r@ixԛ/"ۮ`+==hӠC9 n=~wt2DЩҷQ @'s@NǶXz{9 r@'zï]ixMjix9376_:`9 r@ߝ']=ێWyW$Ʈ`9tѱh/k;}ݍ * V=(c l B(|HEԺ2<LߘB}5rE2[+2qkȫFg< 48 *3jd#E5יg~m;0| Ul- u4Dտv*wᙆ,,P>" ("bG0 oe>z{vBjhvkdhlJ48U}9F:JkRޡ5 AgOJիZ:SyQ3 PBҺ +gxf@rSΌdI93L/w]VHNjm-7GH"NZJ?,X4=h[uFEഩt: cnj}>?D-_n N l:$ Qg%Xl>ma @ڜFρG?mIfM{P[toho-i] Ãt: џόMۼoW47|~Qun?r@Ĵȹ*|P$Fo/q8@;9Tbn)ߟ/wՐՒr1A(U0)AN3_r-yچ4XBX{Lr@MbT+ DY_[`BJ/94|!_LW^MH6.wș|"I.r@A 2+P)k]I@/9Nns4|nn=.15{ _@*Qsɵ\H^B7‚OoyixzcY$>RA;(Uދ@pm8fN94rb_ Z(!*qBuȭIBPM*e"OEBCR&Hh=',;ޠbjx L_JgI x54|-bwT:# j] RL_JgDoxr@xPcYF/N3Z9JҽG1[6'P7lZе^rsR}SȂ fPcD~T:# Qm^АІtBuJV*Oi@^HXW4> 9Sm ~M{KȖ|YNXata}VwS>eԜ)嘌:# o=.mm$dב@〴'f20> ^\SE0T @ss@Y"4~ox ̨bx %d)?шQ6-ԬW5ipoxhC|DaP.i+)%M5ý,A8F@p@9+6&TH 4w%SJ$ ~}lQIA9 z3 A,orڼhGcSzgH59W; _Pa(52 oN){vï4 Dox/8 _̂B,g6c O9h&oMM7g"Ԭwg:O~ 7nax4V05D~"2*5Wssehox,{a.ޓww2rd.jL4,ȲJ @yïix,4-ς1tX-mEl\&*Kf_TVJ@:~[Szm c@Sr@YG˦X>9R  )Ѩ[RlǾ:4˝* M!>ͥ0t3.xQߜjrcVκ1k鎀s|#A J:G*z&`2۴sDΑЄj6ox%0 <ՐnSw@`mNk,OEUߒ nf<z{PGrmƄT/#VkBz7|X:Z/ۈN6U6zLn>옮 iu@ijV-XfD[Pg yoٵ,hhKڼ6gHFEjr,`y$Ra^{E>L&ߨG_ Qf@6'q!~[N{]5~~=NYmmDox bp\<4n ߚ'=i% xj4ᢩ tL~Y:'p@aO#G9ixu@83jIAb{ǩ-g$݉jV JSz<Z3VzrV*o3c8C/:OfƄNQ`JR,uށ87@4Uaf怺%eCUjڏR39 F 4P`#~`7ђ\ņ|n卸Z\2#x%r@9{X4Gzg$ }s%%-tW/Ѱ 4}Y5$(oG=Pd@А ]cm3 ;Wl*zJ?-U@aVJ,hbj4}p@HB9 f'җ+>(,`h{$K ti雹!=# IDAT `yeA^WdL=y-FDhTZoٳhX j&i@fi!*IUْ.'HhXDi=R 9mP(2BR{L @~VWSwշyZ0DhSοIu8wdT|v ϶ޑݡ @s@ Y!^W_bZnx+kpQ,qo| o=R~n}MC徜 Tњ7# r@tm,CSFmքAfK@&@Nb`}f9M=Ѥ/eNv@{ãZ0r@]%>WdNX7h8҂iݍ'#wu_c9^q @^9Ux,#so8܂Ƥ~U=^k2=ދ !D&P ^ţ\ QLk~!,C4F"D~@N`ٝ٥[ۀ*w+NIs#k@8&ʙPT˼]V ۾:}Fr'ӆ,XUM+'⸔¢u_6eVpoQ nԂI/~-щ(9q6& @7_s@"s@+w$(q>8G9 b$9 F@s@H{F@@wVt: r@Yuvqz8@@"Q q.t~@ Db? 9 q\"'4='4w9 Д9 дhR 9 Ь+" r@ r@8@"D(2E")kf͋Mq@ r@1HNUB٣ۚDG/l+}>7~EIf;8 椙ʶE6i!_yHyű+hn(~З^kVz," 8_Fˀ VqQ.(`68A V;U?L#y74Ji|r  /Ѷ,dμ /E=FP@P0F@pI,l:V98QQQ `٥Il~H"P#| aX`8 r@Ԃ.8Q F D"9.S-gl ZLf8*ϸųe^>Wף+΂_r@{p@b'}/.cY-/W^-"9 -(9Œmdq;u>-aj0F Zt8*2֍R RrY-I^.i$L ^TmgN,Iդf <7jTãi5 6GO);@&cC@qq'SP|;@UZu"}Z ݑ !ڪ p8@.?# i>wi!zR[7νjt`W% X@߱@;`Ge+L~}&Wr<.RkZQj䀒yDE2J["P&htMfUi#Q yL~+dQ> @`vOnՔoeRwl`h:J @5D 닯tR?؃,9Z&TCJFs@os@2'!|ս81HCy[?;7mZO4iDkŮ|1#aGי!<ӽ*o Qe.+−"Cr%V >n,(:`4ҕ*AtPAH_x e+d Q(p`I?ӽPd[ʿq.*,y-ڴYtSգkI X$1 T$ Tҧ~|*-ʴ|AS˟Pn R$ykѣꘊ\7@i|B&"BQYu2OPp yi_޺Ll(/tL~5M|YD @>_|lRF!^}irE@2KY8g 9T JmHa[\kP ,]L4yVlQ@X&L%1j(ʂ݈#4!ۯz@ss@\@UR&,z&ꀠΛXGšb/}@s@<;*|߮:S5a!#]q:&{t vMHC*GF-~B3*|cR `FVC9:aXXgDaP ^=,)wdAf3e~tIO:"2jB?Fܳ4;x=~6Z0嘞f܂_m6%[GM*˒̋-dmW3v8 i*H@}F@9e9 }zNqZ0_ @S ֐>!5| k_#_Mh*xB5<hGPq hM7)?}RPG?H,v"/XK}RP3tZ08lr51q@9 b%F@`'9x4]~-`}8@#8 'g򟻵`?dNF,\`A5?`Y{SQR4cUn-ؚQċbFND,Uϐit)=Wr=+Jf& @+@PT R@22{bs[I?(/Rd ?Zib۵`R.+|oeٖ !y($!+NԂ%@^~@9E>tifviz 9e";&P@k~@y_"HhS?A2۲цݹ-&݈rp<'7<h" "J_􄆣~GQ@ Gշ0v>9wf@Z0T!ihqWW/u3) 3/R۸j\B/XƮhUR|YHe̳$_AE7n_`I9# Pqlǟt~@ܸ00٨! # oK V(g.9J>ŌxEy/BI<hDڀ@PXDJ"IrA8@{9 ?]`8 Jşz֑hh7M@u!Db? NIDt"M\rv-XݻW`̹f#DOiS{5475O3Ժj @jx?ÛgiAGhH4P.ox!=5)}_tIJ<³* gp1)= @r@K35OWO Vy[d$^DTʳ8 !3 5P09 HVj+Ԃ`T+#y &{ $- ZrBxFBɯ~rqd~BIB_q쉀f@\ ~8Di3Hq+i4~?9 ϬqAZ0! \m@P8qad;(K^Duеs2g"un/^Ħ 9D.D.i瀾:YTh*xT/-2c_ @䀈?"Pdq6:n{wb#gKbU^@WP'l r@G@W!P]" h#tyãMs uOe4Q:L j r@#ԏ?Vւ\c֪^"9+#hÜ]*F@YDM?e7k8O3 cs WO '8 мB=qS<:mIoASD]) t @~39 ^9v?z{@qCh'tUB~ )=HB菀Bf- r@D -ǔS1"t@Sh[z[j *F@NDh?s@4Х@ox@- Fjwszo&wsMmF3~; 4|wF0n[Z"]@h7<?ht4>f[/Hx/9h ǟR{04ؒ;2ULMJs6 ǟұTJw@ހ@G@oxrZo͈?ts盷`[18O"4'M?46b[sXVF@䀮Cox.ğǺV"{47϶Q6X6,*F@䀮ş6:Aچ+%~Rҋ S#[VpqU]@Ho)}=Lٙ9񳨦AL@BlJUMkH0 /ǽT_qj/ D.t,_E@QSz>_ASz-r)hJ@䀦?ᷓ:ֈ\5ɫRp), NF {Dh 4<9wG@B:h oHo*𯪔RHF@Fg7|I*A,P(o^(bt)t4ᱴ> ;tWU(3X@o5¶Zd!M @fR3 GqKн{ ¾^W՗G!# r@#PLp@c$t%M_ղe MaP#ᙆ'Dɞc9&whB(4?<DR>;v ?iEX(QHKf 9 -Y=:gd75/)Gwٳ%-d)=9 %l" 8n-v4VcDaY8~d:(vF9 ϱ!pox۔^1jiPq-//&ƟQ2z3 Oӏ?m7|8bEԦӝ#NSuCY~@䀦FM3u7|Q$% Q5ͦ'f@䀦.ݹ %aD9*Ko,UՌ8gAt- lt[ߠC^$ TIQ_ O0)&z`38ozP%e̕J{I]5vB7OxR:_)<-?Ihr@'#v8 ykcdHr&Z6Gp]ikΪݚlQ50"tf*C!t,lȲLrm r@457bsl@{ b d+W/:˪+ 3}]|YT$ FzS䀈@Q'ּT5?ؾ·i/jHrѦ>9 0XT ] G{a SS-!/K4|%D:A P%bӮZBճr9FO4*BN"qlf}=[F)\a? [Z" =ۺPaQEj r@hX S ;q,"|K6 )m'2 ~Sck׬7y8.ğcܔFn*6U*l*IBÊ򵙗i1_͢Eg_NƟO "5:&|9 ӂN)g9h G(f%09ԣ e<D?'tIeU<gtT~g87ev"4䀈@g`r@ Q}:dْLo*9vo r@GG@`r@߸ܧ܂!D:"Peq \ r@ğghԬ#&t/:F"P{D3Z@ r@Bh@䀈?C r@ r@ODCg""\@[9@䀦Egm 7 qN1D3= NŸDDs]DDYtG r@ r@ğ ЃTٍ@DŽr5q@䀈@^jb ? r@#h/5p@fq-K"]?" |,JtٿZم@`r@ğgE ?~%߱Ch;3[KgGs@E=91t%lG \@O|c z@reķ$9 v"P9_+1 D:_9 7-_8qnbA㨏# r@l[q A# r@8qbA9 r@8q'oGcV^FNjvxqpp~KJ.HGtǝ'qpp BZ#Q988^? tIME 6^yGIENDB`gxemul-0.6.1/doc/20140802-dreamcast-bios-test3-small.png000644 001750 001750 00000100242 13402411501 022437 0ustar00debugdebug000000 000000 PNG  IHDRƏVgAMA%`M=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATxy|[ufqIHWdlK7IĖٚ^//ĉe'eDzK"i IQAR$ Ar/3?yڼ/>33w9g0%uw}oETRzg[#8? *9g6k< ٴLU٩)a`#jrK:&\$Ytjj&40@2Lkf%uyrZ@UƸnY7sп~22: K,YY4i&z[6)BƑY قSق;JK3-EΘPtdw̃%dd nr,,sEeJkRhkͤ5ERfp7U[Cn\Q66>cB1UWZPyyҹ%N()((|[M L_ y<_UnIS,gBNHENA>we*;= K*6&b(vYcBZYp;U%tmPxkSu[еbvna&*Ω9뚀sXEM0%(U<+MyhEE!#[j9iZ< c(2jn? -]fq|jB*2tn1C 3O^.TL*X8 gMaA@ 5 %03:1Zc"Z%f 2sLLdT861ZJ!sS׈`1rYLEL;0aSiX9cTd(z!9uyz60{\%CbB1b*,w11u Ig#(;hB`n&)U*MȿG @˵]Zȼ ; ] Hdw˿Vtȿpd1_ᾧs~O?{G"'>x7/⁽}qUz`rPHk&X20hB{@ZT޿`+B=O1LF/ `,k~& ;ЯUCn.EQ޾2wgtN6ߖ|ƵV:jC reeEͳSsFuwgЃvvZ> RcN"/jXYS͚dzEUNtz`o=Wλ^ʿCC4iH\6V^z6m%u#𹬘*5 \Vso[*[+Z )tox*Ht.+,.W M!7x Qt`M{k#VI X:CB UqWDpWt}㯿uj?c_ܹG~_B79"ӇM,^ꆱ2=w}|[PC*?!ĝ:( m j),vl9qTz2%({_M=JZD 給 48VHee,rc cor9=gn G.r??_x)~U=wGlId8um+]-,yrȾXB2 ¸.L_)9>;r}L#oY>6m[}O#o<=vDȽZluɲۿ(p_mzg ͷ}rNC$W2 B<9xۻ]k y@O3L7?uGD$ ˚y@Uµ.蕦AlU5xSI-]¢OF{y)J<\D8@ \,DK3P*/8Bt0 TBy2`Wq-YDA& 4" etrh4&ABYkND:p QfViA* *JZ@UlN+W*Jy O@T^9 <OrdIsiXH΁@(QAUA@UgF& ledle@ *0Q'L &3"Pl wu{sݎ<+'8w{֡pPl[_oXqD+#fWTku  XQXePP4;$/NJừ<0zeLAog 0)GH]ȱ9Wrԗ9>zrV̪l_4y-:?"`4kE['-oR 0` /{M+ /Ywѵe&%detrºU\ÖO #@JϵtYa8NqTKWسYbh8PEOÊzf0s1Y>.ZUA- y<<NU Gz Pa*k*ڛ( 4+A[E8:Sy#^ot]TԴ;- ?ug}o?,po,L*2Zzя҅,iH<0 c.TvHTXK̫!k*Hi|XNOad6g c @inDmƱkx1[3tg"4@\'%,\! ȫZ|p3/91ǟVAx+ wmV#43>:M\a@M=)Rd s- BFT9[d򜅚B£a1d|4۩.r6XÔ YB{ 乿&F:$6YDm:Ik_ ߵ*_!ܝڀV:B2:l5lJq%C\,v ZS~Z7dPyt $ %S3`OK&X>yT;B:p8tK8=dYPW8_GV;H\}KvjQk>k ].Ԡǽ':Ӎ_ :b h DZSP`[2 #扣8sh"J|l8>0&.V1C IuD]2$ E۳F=SVINAUrI;wͳsYҌ̩4)I[ՃLQ`ꕗuz5q:{#Vi;/Q`R:}w>q( TPWwVM+^A\[Ё:7(ÒH6"qxM#PVfd KT:;+iTX˓sp e5!k_rq@E~lL0鎵F97FTdL>J+4 %hVev8YdpzC+yaN WlB_ٔ|S?+|{͛r…>^9GL%*r=qLU ZuJ 0mB &:DAs 4?MҀJfה͎t ] w!&{` !vEE#o!:03gOQƋ*?T'Q9HA؂ʦ!Jo1h̤J̌F%(YH!I@t {’e+%s1›k !\ 2tfqe2L(ELzU7 H՛xpғi< bF-LXR$Z^b{_=PҲ@ޚIVfe@⑘qWȠaRO:JFvqS/*Z Q^'K>< s E/R3ߟA `؝"YUaMj2f x|ƳivlKܫ1v/VhUBYbU^@rWJM(>Z*R D@VC$]L.@ =@NXBƄQL*s `q3µ)(FVmFW :§ |.Zbp]'4(FR7 W __ Xrd. #e"PsQ R<&?#>oቺiW䒚VIL?$Sٺȼh&N8@`݊J ; o\D)( ҆EiIX{ 4fuqqAÒԣ8XsYъƈNǹM\섵e>ϥi/p4J0b{ v-߶s _ >?CE|3K|آ`PPTj,,$HFA0x[aB%!MC'!v< 3!4sX@El E„sxd<wΘt W[+E-BMHÀ%uJG#?[[]VMylHZ!ؚ SNcG3Uhjy%E=A[6[[Μ{X,hl&z,VҮdLI+6gQJeeTs%J=kl=LLl:E5kYVZ%ʦ/HF4(4H# qGgwBE5+4Ǎ4;RB 8d$!`tNv/ƍr>:B+p" ?pQl9$~-5`sC `@Ul_`N7avH` 6 d-D%H*gR6'. g jȭTq?[Rtҁhԥ-u> pׁGăiUJb¦-|`%e.@gÈ2kxn`ш&KYK]*ܴX(Tӟ\^"&`-R|h-5'說;Af$|d˘[oBr2vT\V1m4/hgHUGF>ABwXw6Y[1 AP.*Fv5s&D(%%àHrp _ƁT(A!l@Q?C>Ձg%"K #U"R㯻 O~ަ(k#jmmzf:7ng=p dbžRh0 ].\$\GLa8_˥I(L8w[J6 'pD}?اiZ$x=^ou}r$SMDrڴǘQրVs)~g ?/B `<^ƊOWj_8Z sxrVkFyZbqJBG?:&qܟ~{ " *SM9$8[A B'vYm'MZG}C۳eB@ܬ֋F]hcSV@,#x`CdP4h[<}f8dep+Dȁ}C [:B-{Kv`}rڳDgMٳ㗯acEuEϏW*g AÃS!#Ft}C6a7M͋…Q؄6f")Bph>z[$ul鰪j22~2Iz'Di^_s# ]i:E+G+eL#قxkw,UXz&p_0v|; QaK$BEnXOb̿9:5.9pSk>y kʍ<> UyMDFdG t0R{x:{]ȗ.݈ U1z{ߘNe,+a =4 3nkq"*0lk}B#'xr{C{iG"8|谪H$عCQgPh"4/(nUWIOSv5± Vpq7t(dz6a'du1J <1C9&~ )_|Iڽk/|s]=!O0xCYOr1Fi$@c\Bva&}|~ l3J2d e~.5tl4m٪vܴCSP(H$ƣ>|}}o_78{?Lmq$E3Xd+.hռ ^ XdCa^-#)( )p;1\<[*y iKF0hh5t|(xav3$>:$IR$g*tޝH$Ξ9;?=G}ٖ֖Co`}0aH(@y8?gV *QnR5L1*mih,㠄Y=q5,i-5SY'|;>?br2㚖Դt$2IkkKq*eJ(p~Wct*8ץ3znD[t$>Oh)u ImuEwQ8׵1lf'-B'tWLX1s9Д{NIx3zc,FUH#c8|/ߡ";Iu]EMX xQڲ0^*sɎ޻J}pd04çֵCǾ#_;9UUAIbCD[{۞;TTTb]w %4XYHiL+嶸Z\sV0^VCf܊ Jx2iu`ZdR IDATh3E%7@"p\]]_,@4*c}?$I|Q8:eBcJ˱;Y&?Gf$/;va3B[Qjh73.^;/,!I4` pAa!!BnG#m6iS( כ{]b'*ȵH.w._T?._Ip7?{x]h~\[2o .)h՞|An%"Zf^Ndt4nfIl[ eXxܾ+`}pG"|rUM͋Ė[:t|~`(4mƆ`}Dgվ {Ȁ f'A:)5a>NTPjF>UuEfr3E3 Q)UK YܾGHWgW$iiiٶ{W84GfeUL[n%Dn)KaoKV mHdȲ"6r[yaF󙕤҆87iDmKl8<_GlU: BDd[KV~@uw"Z5J- /u"9}kA(s4!2)WӣdcďVX,XII|6D&&@LH! $3UU%IZ^=^O,bW{DI cX_o_KkˎvmmmJzn~eYo DWS@qN;fe`7IZ$V 5 [=(LExNpHP\}?z{Ec˽ڽ+H:[! ( p9ȓ?y6}_>Yo} IDbaoK3״O?'Oɝ0l+'iq9M ΫHp /;dJEC ^Rx8/ɑ~r_!sjҷl@TĚВcSrMޞ+8|@jdbpB d eBK==14yjρa?b$*f,qA~zVX.36 u7{G9?+9 {rЪ1{Ɓ{)/}Aa{W_y5|K_H(pܦ}`,{]V5H44}`UwnGo-;A/@; hDsO0tPxg=7k{m?CJ[A'<ѩ(r,/g0ri.^}z4-V! (._3#NvCgrq8)}v'>\A3`y4LI`mIVsr2n٨@C9\9fD=1s^ƪsf=U[*^n w ionqɋȓp7~=)Cmp!xe.7gŬI02T8It;I% @,zH$P>{Hh3g;l~/XTE`0c>.ٵ}MMlO—w?3nÍF$eHv\E$X KhB g@0xHR=x%36 :Oti?>t0R48=O ⴦o.1S IBu;)lTf線*Q/J 8^w2A qtiLFYD=4d"#z> i] aȱ;ֿ ǬX·pCxZt֛Qޞ|C<vު]AqVy<E^4c6l 2'lX冇rކȲޞ^Oٽv8es?؇eyپē?w/+vM(]zuǖ?wmD8&g,"zP_ ߭NjډY^an'd85Dnw\=^tsy~Dg65B Hx4 nZnЦ7,[BQʪ/k'W? a)_Canҷ $6%%1_tV fW{қZH qYk˭iGJIA 1R'^2&LcaX v ,8k{[¥x/YYkgWUseS&-M뱗1=XAU Q uxz`X&j\rpDe m}0(Њ ״]κd9 EӴH"IP0$i>w-\\߾ԩJ~2` #` z͊$0dVvsc~ce?nf Ecڮ_/.75/Ў;Ξ9{M;B$Ҵ{WÖfKGk͗yI01C~^>D{YfcS4t>=`H|q_UDVXcP0/fQ̨r9W9pX;ͦaaUsa]}~¯|͎ gX29Y"UV}՗o(*nJo_sKK{Rմuڬ/C|Hȸi$c++1#W#;7׀Fl\'YF_:133@c-Gy{mɱX[7|^=' _B >oǗ`ʮ'. Q3p\<;X Njt-JSIWqUK% Rby;tzY2%.ƊZW(A&bTQ 8o [Fb&&`J|nM c rUF'OaK7H0آ]XkyZ| ,&n޴HVo}|e>}pC3]ii~ | Z\Kt\qWxӎ@  G mQcFcHcKKcK?6IR5 'cp$ PhM;Vxn3tI^,㨄qÇzbӜj`O*qz3NVoX ڤF/O9cT{ a>/g].r&ұCCHQv~>-[;wiC.DInҊ5!M$+3#37v>L$.{نRX7ԧ^+*KNcm(2=4f΍Ȼg2B dx3$U)Ï=Mqg)2όvC1aG`@'EN՜T!Ty yI } HB 1^ysVUUOtr_{E*Ɩ֖Kb5+W^m7D׶R---<4xa}`e& uV-l VyB`7&TN,VJhYưp%SIƿ-CHx&.]IEc'rl_WޅZA8k6{aZRYct$hn[ "]&3*I詣$FA'_EVAtW*`)-;iƧ-\Db׶|m(4kܯ?*/#͍KA v#PF]D9HFy'nR*P8೫9PP/W{ͣCM?dWגqCss_oL^%N>L߫jphh7?kkk>g*硱v4~uaQ/X -E+jQ NGPmӬoXU/mC"243uǕ% Y-nݺR-1n_ɫjk+4]A sO oT}>DyWF3滍<;uTFsyVC̓@7])]kN9X};9$5T>ħ?>V~+3GOT'%\ziHfP0:B<|%όB@hE.yY}B;픯C-ܔ"WԯooDl$J[X.ohnjjnٞz~{غmk0h[_Iich] c B/6?γS.2WC|JTW3ZhMI(, @QaD9Q^޽vS'O\23v>@۞TT89/J*ƺIsFd6EYqgs?++@S+cKpec5;QJhxOR]j0,9r̉,$cM'@&m|;W.2bsK,.d *椦_-z%g}| #:7v뺼![v+qÎ-~]>EQ:ty@?rȉξ޾GE"s9}poBI.cj>gz-K>Vnxs'18 aX6 ,#4PNT>;(v9m!u9y4Ujc0`1 l𻘺Ģ$?}z+ @^Ç?/?>;ٱr5 nWW_0;[>뽔|sxݷ|}~eYQXnYN4\r [𷶴tl>o<(3+ʍ}qBC {^16z)⿁̸IdEwv5=L ݕ"y,2w߂tfD5%Uex돔4l0\.oO|S͛P4?6H9Iu4r۞3~bUnCq>{=RGY6ռ}).2?<:JιnJuK%Y-ɒ%OUllB$Bd Kӝ^kkN: `J Y\4+T=0t~?j];g};_Ox'/w GaqDI^fOh]wܡPݕm\kCօ 3]#^#…QI1^yft8UV`!wCGgRN0͡za`oS+1s-n^-&]㤬*:OAQ|߼G>?tD7OjM'::tӭ+IԼ)/~,ńG&'Rs8qV`WL3c4)/K/_FJrvs)6m0)H,^qe1zωGҫ˄L7Vw!cBLQ~m!\ab&aaV ~K$dFc@*\runE MO|17ʍ(AGTw/'=1s8,}aId L" YqO^N!/i~98斑W=.M4~p}}%'^ 2H^HnkK6G:Tؔ;stuNս@/ޠ(Jaã^go}8d9&|y3f=yAf4bщ n΁b<2G[PJaQ[>7# Ym48OmSp,|N$]sHcTO$|k~1bT@i6~qk魰 !N$#2`ml1;zo̝ͯǂ<h4s7C0`pEeɄվJ ki9rEq\O;'Ċ5)(1!$5Os#||WTs~lf { b-:N.p.4̥9˿q|vp"R@{(Fm,G#Ue p'ӫO9F9q:  *70R4q]Ƈ#Q?꘻) |)9KQMY!=YDސ>qܑ-XȔvDW I e+BeϦa=#{bS ba6߆<']^r^\Ihv9`͡]zL'. c ĬlOJ/+7BCcLĉHk5oՀ9 44ȀK` )'=ъB:r2[snkA`z3~69:~Reŕ\N侉8z99yn}=t,wnq-l{g=]ˑg{pGF9KVہ"&xi"4(B4$yqVTG^ cT~mn{nvWkJKvx8Ve?Q2;tP(σc XMWGS IDATO2˲c{o}qEmMIuh5? ښpfumm_nP&[44'뢟-d=`LQu>):C2n_f-d+xM疥,+?"OgnRM7o`,q\^K )[%/yvviخƟ]b(JMm]ҪkVfff~4,Niښ`((#JOy9 L_񶯙݉R1M W:luw{+"֒Ӟvc_}oW|{>{Cj/vߓEDP( Z@`>۾ WNu}Mc;z|}pOÕMƓ7{e?|bSD_~^kk|OO'2>?󣟻'QG 7>oӵ=Ol< mViP{WOagCO͛ӊ;h٭u8?OnUDU4%k)GKUU-ɗyژf55vU_$F36zGC;}k2 .ޖOozd$ C~tWwSsE}PG+nop)2#nWZC?n59ć`޴/wCW~2TnL/Ĕңו$El{)orQqvt C/mZ ),+-PQl]bU}[?u^Dd٥Y9iH nJ$dX1QjA!~vXA Kd9K'm޿ަK倚gԤ%SU=ָw4䅂?v֟„hΉ!=93 Eؾ-"OZZB[Qpf1o;OͲyoMc" XSSKJ a.z-oxR~#\O3SmL2|, D0)ΐJU,.-(}0Uf B=T[xyu?DEȲܰ;6>Zݿxi5T*-KS~+6 %SJ'u59`zlITs94 q Q5%r ?Fi1W.+S5}4yh;C֖ŪzƑPۻk,q{w(Z ʪ:{[5d_g5RP&,+M?a,,Her>.p9?A^9&> g77f|4|ōDɼ`cF6::CЗiic_,18WcE""S$[:<6rr S3 $]`I]ya*(s K^Oȡi]k=.V-[N׽ ~>\wlSL1)Oug>1<֨ID%*CB^kɿYv31 ߜMƿܹt=nnܷa{tR45P`Z׋s\V —:+zD zajSRȐh$x9 pL 7\M 'Ìd޴&HtHa|M R uW&_/z\!Jpbpi${KudbXhnuXc$Pl<~IO˫yn6o ̥skGˮe pIc1kC ޾ ?X<}> %k9ص~Wg'y)kcEͅ%Sd]dEц3iA?B%?fjoVNꐺDU%5pJX5ijnuGgi(N^#t}X,a+6IT-HtKx&bs<U.| kws[:ۺkhXs{we&{;֏ۯ~3]XcpU/܄1X7@{3Fi =HY(:v(JB.;΍kgiH@d0S>Y(oF \1|me<=IoGVg&ع`!N7}5x 4E[@%q DŽN#cta Ǩ4Wv4dH7CG)!eRfP|霰I (^b;?ޔӼ l@ Ea _)!,"Hey*zs+ڥ$P_0Mt2!@ "e]5ufu ĐAQb^?˅V݅MUXWXbn:MSi|SS,b1%ܠqOy*/ :#T%(V+tZ<Gb 8>& 3$ϙI]5Mk|Ev~ե(?]w4LۇB{}O4}yˤ-ug(ظ.4E`ʙM_4۾jh (9.LlJБ<8F,Ǘ:-rJ\(иbdHLFH6Y/^0 }.Vw~w7g ͜21=I<52>/ϒL3Ŋl5Y/j1rᘌ0W&h'5Ѥ|p>ՈÅLIB$Ϻz3YQR{gӞlZ,#Os ڀ6ӗWu"z*=c,wC;kL'BulK{RIJRN>< xĀ ǒa2|7*"HsFsS\'R>tަVMkhP4KևB`mL$`UatG P rvzT9VAHC:iul|3\&6J2 !3` R4@V( sL% 4MJpl>~)V`-y0]n|MJ'+|M'}dt\S-]=T JY~(_Z"~Qѷ%^:-7LEag +7 6VDch|f!<~ 2B=.W-?9;g25HE.+ K@Z T2X' wGqİU &+,ggC3\%Gd"<+F|[(fh:LN"Yf O.._Bf,)˚`a1%~5]y]K9i=(40,%U!8SSBlҙC8 RF,z_rQ2M cۆ\eX1??N; pjdb1YE"VF.͹E`B_5ޱm) ٢yx rvffП& $c3Yl0G@%EbE߆01W?a۶oZoŽwzS}(4.YƠy@pph xoX?oz &`` Ӝ(3iH&؂g/Km&84&2?|X SEm^Yu9ytKE{㧷q8$a$iM7VӅݬ}֦Eg =qgטC?r(yt%u>]-UR]ݟ)M/SUYQ̨a I/R,oɚ=?ӴfmUK靧|x;\}+[ cb1lky&T.:1"]rEPdU"7:q17ub}ۚ;%m1W G /#LCz{aT1]xS̫b!0~B!d..3RpSg5P kQްt ^if4ݧCM"W{ ,T{zL>*ZyTUzϔJۼĕNo̢<>YHJ2OrRMLmHpm`28JvM>i\Ϣ򙃐 1(aDimљ~F7^!Um@ mVB~o00i0b9XBdTKp&]JdN#F3I4 HՀq`HLB 4OsC7Ѓ\`&.Usf l9 p_Ne6=CPΜq\J(?-9X5;eDxO $nCtyU;tBTNK'mŽM7nz{W yӴ>&뷐$ARH2tJ8ntF Aʢcn1ɦ3 0-FTg.Rroݴ;H_G5ؾ/C5;iIDATw}]PE'#?i bp%(2usxB$" bH0i"?UDMf.hVG4K9pm1=Y֕%SH%W< F"0ICӹ4V,̑dXTxh[j*VYdufWhGŪ:t- ŽM7\u]nzX <9NWHtq>ZoZw:.+J,F-*ayӁ}GNs9zneX'h0If_i0oO (pt !dM"OǑmQs$PKQƺM[ꚮ|E.  -v;kkk >'/@EEVeE)2o}qulV# 7augO̺d>ԗo5xL R)Fx!/SܩT0CrJLR*V>)LQSsz8~X1#"w<W$,_`3wV׬gwJnW-|LhPMomi{mR紴_~r0Wv' rMqak=Jj4u`((DRht^q$mmm_#~-uQ%>7+%|bcd 0$͜f +΢|ѷg;:06W:5jokmh"?gu+ O'[v!8x"}Nv"՗-bH*gd,Nduz+U9;@k>%LD5IxnNNddA)77N嚴1t£kd$F ut|Q PZ"Ca PY;4m4-C#u_Un ]h$ڴ&iݑr?z "M+jkjjkd1UmM'/1uVY{E u~$?TuA%q/jSC?pMmM:dyUUm=Wu襶(h֘WۼGΫoo0_9'>X6dQ=P@݊ nC%b(qzc83~IS1ęIZC|b9nW.'`gRBf ~ (D"].u@̂U(F x' s_̵&-:fi, ^1QaMUφM7F#o1]npxC#ѢZ65,e[{UHŬY1]lڋv>¶˷:ln_{ڏ"gQmͯE5^d)6}EZbd.8^0T&Sm r%v:d!:+j^ ALg'ڄBwSfDJcnӢ8!Չ fVZjOsfw::|dX=fΕ~Z7jfdڮ:h0HXz8-|byo92~b4̂/9IxFaHDLTyyڪXfp>,iZ x{ O ~8ƺ4Ly90 ]AbY |2Bv (z;4淂r^\FButM?GO|oc9pӈL\鬅o0d}mb$͒~Z98q̥(HbTP҈SE@J^ߜǒ2,{% d]1z 3ܿ"R?*B(a>?b.C2[G&f'[$L} YGj+g}Cyo]ڭ 6e}afK78܋I .9HG/ q(<'%Ts2i0ivdZXc0*)R}$˓rr H$9LN@ 0aNy-@O VR 1#<:lydO-lgZ[Zmv2վ񽮾涳<љi.Mf[">MO`nmiZɲ?|4{k77kϛMͱC )nRd b|<,䬷Qt>4m8z2e8hK-rb1)QIBxz, =W)EĜcBlFpzH.# e5`b`Z Ǵ9p +߀3u[l|o=cmY=4:68oEa5٘/t;<aHqFc۶o Pl[wMS>eCndl 8!W/hgDͩ~޹⧵kg(f|﷬3'SN"^*gݼ_#DvˮM?4,P .\L ;^ uN= Z5od΀CGn I.z'q\]]^uEva{tm?pBPzQđ=oX;nK5DŽ1 gb!p~ y "sBz*F;$ oX*a/z|;p9J~m.&cV0 |=8RA*%QI8"dgw?KҜɱćid)J<܇*28Kj5Q{6"(J3cP`L@j2m#_ ?BlQ ?ҁNC<ݻH''m`HLo#K ʈaL Q?ޙ&*@% Ҝq U0O *$Sf ay)d.pd^ ᭈSQAܠcẄ siv9uzi08N>ˑeX'#)%XcC; GT\O::NZwХ |HxiFmtU㳜4: 5cIyDԵB:>NɬKc+Y,(u؎ʶT–> ]1cy2VcHm1//pP䑳ାUWp*!@ىJ U ܊֯[ȞJV-hR9;꒑k2W)X/;Wr~x<g旹PjJD~mz>mH1ɟJ2jBнa.oGOc/e:\%N*7\mq+a4uC@3IHt¼,¦tClq6 tm᭲*!D[34L30.2O =c_tK=SZ*O|K2W⬜&GD{?.G̣E{T؞!2%Ϳ?OS8Uhv}o}!vQQƼ! _@~I.A{C52R9G`0#G;3]D յ6.k I3U=ʌr6m5Xլy2 7EH7%y6f i1#`lw1'+r#q 5bmZE|V4@X_T_jEKmL腆wHlX%isUœ޿^^v s'v-`"HXӶ,V!-ݙUU[+b "Bם[prp5L&գ`]'CAXe?wĸupzI5K1rK5]1Y.<#:qC+DeIՈ*^!" <#}b%q4v䊢Ez!K†GWD:ʨCǐ4V,XTBﻌDx94Q!b[{^Q6D0]QBO ºGPnT-} 7]U8-Kh/fXeJB7686  hfF G[TXXEZ^ɘLfoEPЅ2~f!'eкLulz_TG E.n~2)=z=DB†^$T~^BfP*=YeaJ>iȲkL3)rOGf7+f J -p;Bk^X *E%/t󢏟1W'}_5MBtY>!`6ԀʒXYCg״m[)˦Rc->mnj~ZyO[K %d@ q_"6s͡ho3>``]l">]{@rUun6@_|uh\:g j@駴Wa~Њ \C_4؂!y* ?GڱRS-U[U ҄?; N̅׍AʷDފ /ЙXׇ3{P]#2+r #|Uc%f Ɛ߃4: i.D X<:RuKW^'9q85flEk.4X9GP w t7l|32*"{S# "5BC} RK݌SG~QM!ukkz/N >ălǮ4u fcXoD#67Ȝ^t{X1mWuNj)1ɦwz*V<)sO-J6C{t0HV~Pn{Q*׀!f9P'*!1prx(ڝ mКGAl7= 910NIzWjKY톪#swbb54[: gx& ^Ԉ|b Ew#EsMY,uSjuZjn8/6N:lC&P갺f-=okFe 4zNbxi!5*Qg-kQ3ba+EE6dwSp<*AVAG>'J%NRޤֱl9:`l R ȚK{HKR~XWJ5W)_\?ۯ ~tw}"نcb"px%0PN<^]N['RU:k^.UU*-}v/|}j4s_vRLUE,{덷+(ga[(cR)w I?I$C3cf2L._A\]` '&Ġ.~Ϛ=ӴB(AϥpʷON2Sgx tEXtSoftwaregnome-screenshot YIENDB`gxemul-0.6.1/doc/20050427-netbsd-hpcmips-2_small.png000644 001750 001750 00000004447 13402411501 021660 0ustar00debugdebug000000 000000 PNG  IHDRt\aNgAMA agPLTE ####$$$'''((()))*****----..../01kd122244455556666pi8889999:;;;;un<<<<>>>????ro@@@@rp@AAAAABmkCCCCDVWD[XDkfElhEFFFGHHHIjgIqpIJa^JqmJ}KKKKLLLLc`NPPPPPRSUUUUVVVVliXXXYYZqrZ[[[]]]]````cddddgghhhjjjklllmmmnorrrrstu{zvwwwxxyyyy{{{|||}~~~~½ƶ MtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDATxZ58y (:QMT&D2\} S(1! m>&&jObKQ/, Q1ٲzS?ew~~|0&rmDe@SIGZZy=|ӱ۶nI˺M--y{y>JN|>zF(@ Phnຉyp717uuux˷f֭CcsNxf++Ϋ\XY9xV=S1jգI\R)(#S9P+Lǥ\VE=:~s2.ȌSTI(2Q'&ЅjZbSaJ1[rԾՁS)7vDF;SJgu,(PGFu(3L4MuAD) MÊ)caX2Qmp'2zBap2 q(魎4%aHQhLR`(8CdZBO2ENZPK4RLw/8ZfiZhlV QZ@ȓ9DBL!'(鰭WF:6)KHjhͮ_poh)sV_cKO\iS7WW1MxHvE 9])ZEL˔|ZlR2%_h^0&ehMsEES}C]䍦~gՂƦ7\ҦU^?kփ=t?!14#'2pp6#/:S>(eRW]=PxI坦ʩ2ZF=+٣s^V^ kNvY:uBO5eu$OSt.kڗ]]q{XmJ=25 …\OC>7>>\vjlF:tIMECkIENDB`gxemul-0.6.1/doc/RELEASE.html000644 001750 001750 00000004637 13402411501 015751 0ustar00debugdebug000000 000000 GXemul: Release notes

Release notes for GXemul 0.6.1

Copyright (C) 2003-2018 Anders Gavare


GXemul is a framework for full-system computer architecture emulation. Several processor architectures and machine types have been implemented. It is working well enough to allow
unmodified "guest" operating systems to run inside the emulator, as if they were running on real hardware.

The emulator emulates (networks of) real machines. The machines may consist of ARM, MIPS, Motorola 88K, PowerPC, and SuperH processors, and various surrounding hardware components such as framebuffers, busses, interrupt controllers, ethernet controllers, disk controllers, and serial port controllers.

The documentation lists the machines and guest operating systems that can be regarded as "working" in GXemul. The first guest operating system that worked in GXemul was NetBSD/pmax, and that is still one of the guest OSes that works best.


The most important change between release 0.6.0.2 and 0.6.1 is:

  • SGI O2 emulation (in the Old framework):
    • Graphical framebuffer: Previously, only serial console was possible when running NetBSD/sgimips as a guest OS, but now it is also possible to use graphical framebuffer for both text console and for X11.
    • OpenBSD/sgi has been moved from "unsupported" to supported.


Please read the HISTORY file for more details.

To build the emulator, run the configure script, and then run make. This should hopefully work on most Unix-like systems, with few or no modifications to the source code.

Regarding files in the src/include/thirdparty/ directory: most of these are from other open source projects such as NetBSD. See individual source files for details, if you plan to redistribute GXemul in binary form, or reuse the source code.

GXemul's homepage is http://gavare.se/gxemul/. gxemul-0.6.1/doc/debian-8.png000644 001750 001750 00000006120 13402411501 016065 0ustar00debugdebug000000 000000 PNG  IHDR ~cgAMA aPLTE^ff%ޠ98tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IDATxKzVa,G^A-Hcy `˹M:@uk3  6~9zꟷ~9`N֏Kdo+ v{p.nS4r`fϢf?:l M6ibiQ׏YB:Jurqtq܆0H sS{LN}K{_5}~ȸ>, ( r~h '|_7 ?0M9 P_3h&qVL&e*yxu37_Aë: &gznxOKAS 6я;#D1q]zK _4;A~ih>oB=?C=/]2ϯ!M q]4MZZq2W 1 `H^q,y)wץ{<~TחG,"?WbEA1srr v+jԝyh٠lk7ofN>yuXm\ )jAbz_0<ִb[^.u`]݋2y)' ie=1nOoqX<L'/ZYU  0@a 0@adpk0೾f ||`m߾aMa3 <:3>0 cLTȯ 0 0 0 0 0 0@~unwȝ1xEV\Aӄyg43kUUq-3JOϷ1 ¨UyVx״.qkU(q JLC^ea^nay 1'<3goӛ@ j^M`UAw=ti6(]bpn:0Xӕ̠÷ϼu 272j>5]a 0@a 0 0 0 0 0 >g&@a ~AG+ a 0@a 0@_@ a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@`@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0`0Z081:~` FgblyR|1 0@a 0@a ~]b^o;7#yj`ꟷ~9`0*(^tIME1"rx&IENDB`gxemul-0.6.1/doc/sgi-o2-real_small.jpg000644 001750 001750 00000011263 13402411501 017707 0ustar00debugdebug000000 000000 JFIF_ CREATOR: XV version 3.10a-jumboFix+Enh of 20081216 (interim!) Quality = 80, Smoothing = 0 C   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?tj@qC"kJ5K$E3ǘ⠴ttnT)歉RJ6x?;L_ ͏Ze|E Gg2dRtbїe1*g3(0-fҧWt-(>)-ۍ@J{8AI9I:!'q$2ƅ\lkK?a|6:j*ǥά=WQs5c4^Eh[Sz\Ee ɻqztȸgt[M1_FH%è=7 AI͝t_q< dxwč8o_Y'%r*G!O #9=3U|9!KvBGʺj1kS'&i0jVd1UҴ ќPg*6Nhc抶S(:!Wzu}kB*U-Dln<VYBHqLٍܜo?΅< POҶ_ǫJ Z_kGI2pR5 S!`Gt 8fxݯ<)om[wEc 0*ֱz;*p6<%ii"G#z|%]~Z gB ׎{hM+jFVC ǎ.*Ǖ ccUX-vH+6IQI^-$NptU͜iU ~uwojZRv)shoOn3bTɫX9.T#5,Hl=kf6@\z)Z#8;u*6!PÂ)J5Z8X 50FAE(N':l7E$EF/m'EB(j)hڂⷐck:Wr񹙘#l6B4m|ҭDžJ7_b%5jݞ(?T#On/G?Q5?gxD|D?ͿrvNpEp[?J.:AUs -I1+Jo`ԁUZ<xȑ2G[5qNs78(';~yAh0% r? bݯJ H}CEU 8:FE1J3Lj(8j(iڵ຅²}sZp$lv8+t+K[ S{=Ǚud2:֛7}x<HFzO3X jzqTxkOU)yQGxX8'Rմf|k$zqIߡʮ׫|é{<&dv$IsX^'\#5ycwj5\%X"H/cIWZTIk.mR1ּ~DEd!wWC/v6q=F2w֎fރvG(4;Q8H .D##ֺwD֔uyCen)E "f_* 4Ѫ?Z\U;}JwTMWsݠFQױH5!#?1ʁh򢘎:H U=5O׃Amj[x~hCko)FپbF%1~p[ZmJd)ЎxJ’7t4IYv' 1=:U禑i0b]Ʀ9#3䇏=7rҪ\M*d`($8=Nb-b`>{H#@s+S^񍆙++*ʇ+/.- <Wv}@$kfIe@Xǵt:dί!?f '\הڼSV4HZ9/ uN:y\BO䷺Am?Ҽ#ėױ\=!*ʧ tm0h BӦsImPhyKRgִk2t_9[sdqZL VN;l 5xqW6nx1ǞjQY&\~Y8*ݲ9yQNqw("f7qV,!`<]:ꦘ$~}EZ0H'kcMv'Yڞ gI<KK?{[2>J#[a@ Xϋw &`Iah" k>3A1OZ jψ\`c DZ?+C*(?+z75izi!݇S4뛤 $v}.xyϟ=^r]ƋQJI~,+s+SH Xr>j@ֽY@6fȪ)5=̕ZmO}{P{FMTef?aˡh55iR?sK&:y1#G4mαt PH?J+jYI =j`V.Q+;vd099J˸<גlܢ#&H8M]N<Êm 26N:";gCv5 9mRI  =k1\1]e?i? HT??jZP:n]ɒ#8Aq,#?>:;0ֻa[hh8 p )_֐uRnrredznCڥƙmq7<2Av? *rzQ\hgxemul-0.6.1/doc/index.html000644 001750 001750 00000017437 13402411501 016002 0ustar00debugdebug000000 000000 GXemul

GXemul

Contents:


Feedback:

If you have found a bug in GXemul, if you have comments or suggestions, or if you have questions and you can't find the answers you seek in the documentation, then consider asking in the #GXemul IRC channel on on FreeNode, or mail me (gavare@gmail.com).

gxemul-0.6.1/doc/20140802-dreamcast-bios-test2-small.png000644 001750 001750 00000062252 13402411501 022446 0ustar00debugdebug000000 000000 PNG  IHDRƏVgAMA%`M=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATxixy.VuuO`iu\ w@h%Z#[׉gq<7OssrO8q|ۑQۢH-mA z^)2٦Vftw[[5 P׺z~ _6r8k]s_AiB{&/kٮFoEVjA@!mq"[$+D<˲KRB-*g*1!)O}NDXV PRm;^]k; YQXU0sxbxv2!䝿 9:_^S+e;@{s] X._T ߚo!^?K+2 4uesCv=3c+)T&S<;3+>AU?# 4}(V~5߶S<=]RA)I \TC{eaS*st5gΙuerzM%DVU|P BO,n!O%Fs erqJS +lBBz痭1~0l~0A%ۣ-"%KPea(?PT-ƈjB @ӄ,$)H(@ D_ '%"fȴq!a5c%Ab F txdUWבq="9iט11Ҧ2&T @͝v4 Ӌfg-<~o猎.0r` P¯yAr R0 @JA4-tHC`; 2fT5WZPZk R'.L}ƞ %!"3f;hgnoo?25J|!M&cf:k\X1Y %\n/})ԓ\a⨏C^,Tѽlo-FEv@exՈB&3&x *ƚuh r6\@|:vHr5#@OGm|H՘>-ac^!϶R7lrȝMEy2 Kjp2)O&ovݏytA3y2ŶoD* ;aگ8I?S#@^Vf~/N[TVo{M7fud|!X1\YeZ|9&;}ђIJG5I:ioIcRtP]w/K oD9^aYEi+ h(dtv]]me**P>.uS6qdv^gw\%Iёs!M hvOw^'к}C% ڣQ:.A@a  n ( ±PLALclE MOJ}ĝ8ּTaVV!=H׬=3::%;d0+ƂBߍK"5L>([L̴LhKj,&$K( Z Nod55Q7/ !9w_&%H^! Lfey_]%Lpg.r ^4%Y폡]SzL>^Х9ǜl^ ۷bzvo[𶅸vKf n!qTƂJr'FRfI\;atwy#t2ʌ>7&__L,I)LfQrNj6L;-f7\ƗtEF*J y4@Lp@{$T W-0a Wf}8&~+A@{ƨoD#k,@LpPrRp%}[ ZX\܉uV8X]ֈ2$R%迯VO ޫ; eUz= /Ua<{͚qto4J0jK63y0 $8Z,4IKHD2"R5{,ZJr+"&ӯo`cSvN_@\?uCwdFz4 !<Ĝ J# ðJ~9E>IuYX+(^WMq@P#w> vQSܮ)'6E^of^~֢T>bOJ#ҳr7aI L]7G&?ݴ+j!$x^Erwu:̨#cn)YoYogz7Hcpνۆ{w u b܄H Cd"gq^: @LR8錰\9\A6k1;?JŲU!\eM[EFʂ ~l.-6#} 0me@-l_zL44 P` UKI#XX #uY >cȪD DZxܝv^5\ RU5"/D&\_EBvYb`?gpu:r ;qlNrhDÓD#cynTx:=fz;yZ!^lb->q*6IkfG|Y@f: g'']1v O;,L@*B1:ɩR5 zWűAiYu #4(1,.sGHNOA.S3z\.::4˂ӼVߜQQ {0f`.9$TT2,vy\H ea~π00vq<㪞]EKHEXb8r$p* {7RѬʠ4óW:RτR$9rHeXOrJVjTkC΁҂y)װwd3/'+ 'r@*i)6B`faafCҁm 4BNњ+-FK4{ YaH3^$!ՌC#0G4Oܽ܆eQ_@p"ޅ};+4,E&Ɣ:.-GZႌ0qpP!:\K  pS*7q:2¬i:e vX@K 9[ !I{ȅ`6IT`QLR]RXjrR6EAc j0E"fO1#&wIf_)o^y*̎ۀ>ơzϲ6PTZ6jdjɉkw o[D< (7}wE-HjUo}rN2ngTu@ܔmI=!%x-3l9ZA,CT4E'SRZ"fJP3Q/A4/H D:xUR7M1l/.C@"Pf:*ߕ SrL_u0e4qjLe A0 0@*TPxàҖ5doA@P>n?$Ɯⓐl4 lywGuHY,L-(o Y;HZABC1`➲YNʆsp]KE7ZGV&U>}ZYJX-o$05o9}0!i␔"8&@ 6YQ4|W0F5i[Cկ fw-l!Z(& Rl-B\ ^=:I߼fM,܌1A11A]%R).4؃I͏FuY{fkl`gQ|F|Ě(25.^A/gg[#T&R&R a鴴[uzf\U.٢2o 4l1`mψkR;T&.݊sjS*դP@z% ,F,ŀ< w7!=cD77ܸ2|PsۻHPL) P^k#79CpM&A4I1uqZ/meҔ@ڳVXcm_M:1,qHx{C"I4z |yFz_Ć(7ofI{´ ^܇ ԭ+M3_Yu{^VoSR,q3j,ڲܤ1i|9Q/<t,~.!6YŏZ* 2R=Ϳ[#Vݴt0+nZKTk[;@u -OC4s_ QqPwS< A4h HtS|h;*;7I|aTI= ByO^`/:@CD>OEhPQjܛ6FsDiZq~#wwew3[g*+=vGޱJQdUr3o!,X"f,=!+]hȑYZ K^5y?4Aup \hβH*]s:dZz!ƪj@1A@L2T:HA=9PǚU4a8`@{d+}E#1 X"jCP [;(X_ieBEn  (9Ks.R=m.ax11io`LB@-DBQ*ȘOҫ y4 @1̙:0l"+0Km9~I>k uK+01&RW|n=5Y->j9wG7o IyWᵀ|+.k<g  MXut9phQLB> T>vi`œ\EAb4 %h' ѦÊ@^[ K<gtm>-,5AbAӐ2 NfZ`\$Tq TaY`azV.-XRcXRɩIV׸]U>̕sI $K`vlRc"y"׃xAǚ]^z^8GEiPIODi7[)]O$k:\۷% h:: ZgEMO^wo(u-i[r.U&.UJ&Eq"I`1%$smhrsqB9PL)g7 Yݔ"iKW3XB|C2n[x0VdzzwS;`D 4-cP5^`\_-̨u!ܰcQx_J&H]?i,%-&GsҲRR@h[uxv>u,Xn56ělBSdՠ=:rE+0HHM;9)8cZT6 q'Cq0/& kha u?_ȒE݅D mASZUxm#PT ~R'C%Ei=L3

Qˁe: 'z<jn#Q&J&!zc$C o~ZBLG,GM;$S4.w1b(n-{7XHI :V2 G0|Y0&ii-Y Tv?=A zo:~ŗtaͻSz/Gp +¨Px!6dQ$:da/J*ɈHؔ&mz53 %L@ht6~ϢϙZ4F#Wa`[~cg_+ĤA aGuNW9-G}6tHlQځsXG㘶)H/t@JA'uӺ56LcVS6saX0g/[kƕ)Hj1ݵ}9T$қh"um_n&uJ˄RB j:* 1<<+r2Y5ȴ>-~-A;#Nĝ|0_SC֠RE(j_DyI cǧĽ "][}vVgkJD. /W4ZeB11tiw Va3⮘וYR/+ ODCxU|rFr'F֠`é1Hb. 'A4$z1'Lߣd%[sJ܇xvrh#8}TuÚ(rrv>gЙXf`2+:a?#Y' TokB:cPzCj[ck͎) C(?^[MA\f-NDt^r$f&+w(Xl((M:-$C6-㴩VT#p>q Ӵ a:A^uX '^uf {_Vo{y"bTO~zZ Ǿ@n؀0]0??_SҠnмȤ|G{%"Y J p- 8F1iΎtzK49`q֦WǢH)L h%NXFN*iPrUr\u<#8, [%JOR̄F7 U+%z(*e@. W!xFυTEd!W,Sqһx Mב2Z/tHnYɎ&xv|%ARaL[=NyP= 5EFBZGg~a\xOw W)oPB[-[|<6gU$cԋ0Hv6z%eCv4w<c ti8kn= >E-w65UjzOZsM.3 ٨%i~/L2e kf|,5|{yK.<Z{TXPu~+nFY\-e .Bµ*Ɇ%U{پ2µwäq)w^ 6 +#G:YMg LeBS/jx>U\҅#*Yqt{ݓaZ7:OX9Cj.cnVZ2C+U*%i1XԚ'"KG%j?gƉ]JIUW~"l, aѶS9ߘa|^rH֌&{Am]h¡r5mZEqSkM۳rي٬|Uԭ --21Ci0_[%Jpnܒ_KcZ1Yb;H/Ց.WZ0 f(lSfq%Զ. 5p3L-$O&[ӓ\*<`@M,H7M@fy! jУp 6E&&PQ#zQz~.^\4+ZEN{"cLVzO >uRy$4*Tq3q yORoŀބi~<Ů$ƵҎd ]?h&:T94߽+Y'= 5Z/JBj*Ҫ-@80; DdL&̈E" 8y@Z:TI4jz4Ү5ﷴHPH(*Q$&F"󆦩"Ӵҫ,D4 Lؒ0M}LQfNi+0ɴ6H Bifcួ !MMV=Hٛڶ K:D  L,ws$5Rm#kYzB^ϯ-C_W5I*rݯx#@!d,t3xVeb iMM@?ɄyCO 7zɾw[`Pfj(~#5ݞ뇑H퍧n8L Nn`s2y󩷾,۟ڱBq >{D5ʊ" dMi89?kvo(36EI7n{ƽfༀыF`_*lzoK_ 3:úA9b0l?KYN\3nr˹>) *u5Z*~XgdH&*T<@#/ KϤW~,dI(Jӝ[:Ms\}@ͩ8'$3_\4Z:г'P(#! D;<iSO~5mEEP|1Mvs@ܸp-j$_ ʨ˳|SX3$#LX i ֐t8>e{֥E 2qS|oNwQakJ;b+t:N4F"B[:C[:5M3M3L&ےe_i?T4v@|Y< Js&Q08e]@6+}LuSF||9H$Ǖ~/OuT#P؁'ɐD"iikokni={{$4Mb]zqp@Ol"g>2 -Z@l\3jt XWbE,%W5)zo ec?t:]EZ$bk6_~9}ۃے]2R>]j3q,xd9oZ,X ;Ny2tP:BlzMz $rf:R$Ʈ45HG}M*kNc&r =NCu$hk jEnP24)wgω|qf J`+6?_0NOTC@ 3w֕+ a6L9IoID{q|oY/v6BX{=nDfBbh3`9-G"t*c쏡ܴx8A2zLӄ' KƵ$Oب c}o[&PMSGŸL&CжvڝL&0ۊ {4uq V0G:]lVEIwU 1 wx~S  /#a\&>y:PX:ȵ 50Hk(N=k߽ki߽kw1ɤi=R=sKgĽIܑJ~%ibSޕ ! ]xeRN(,-FD>$G%7d5KjDs2f&oYoOԿGG/dc:ɧ~>D ҶiA- :li|)4ii%yb?TPL tosZvDBx[1.\gҝu"EjG;C sgY;OsZy(T,X@@Lwn,H~zfTB1ڻ~,;iJv$LɓYW-]<½rؙ_QȡOp+Eg[S7§#SO>1{Bbܛlko4 BKޞn2\1 W#ވPÒg gz.G~L9W&ܵH_{eA;;T{. ~kIq bW/j_n/Nߞ=E!um˜,W4:U[$‡3#@Wș_ߜ@%>c9Ăw/~Yi__'3~;S? ٙի%_.\SSSSS3::f. ~uuu'81jܒ;DD6NCuhApܡZqI tc]"SyGUۘU6?$qw">ҹHydVl6[6Rd.\B׬.RυhO}O|w\!'tD"VҕǁTT䃿@UI6^hcl^O,|IZ.oE3ȺT#̇FowW7_ƻwt_(>R=Z**k$ǟI]w\J(%\t#O~hjOyoO'd_硰wyc੟Qܽsn\%ɞ=t"U+V+*W>Wfp<+u9myG-{{)ٵ?Gghl5[N?"MP(uqQ ^LŢ`:$#OrMpVTN4EW|^FuJ`/)ZKG[3TNQxm[?"!-TOcXBLr܉au?{o?@1|?2k 9? s<=֒ɹyVpy'ܾ{n[n Ԯ'+b0M}w"}cݻv/MnLPO=*w%} s;OS{SO>?c-WD-|b/.km0[ Cun|SWկ~şᗩ[{ز<MFX2,.Vy|iO}¾X'.Y"pȮp?ғ)^4<<g   (ޒ%Y%Yvر#8vb;Ovsl]g7g'Q(3,Y2%QR) $H`p3=]Uc(ے(YU?tz{#|Zknqll^J\>;כ K9?{>x͹wrr喯H&kk~:;DuIqnyd,Q GEڃy?"qG:y+%CQ hy&=$EkYKe;.p]'i"w/ ~3$x˽mW1r r=pk1),(GEb$SEYHKv?OQXzlUc_’dۖ9Ӹ$r%4҈W]{/}ܓ13p̡ 9:_ Sj ҤZc7Q Kp r<'.5i<;& Ks>k௡G,-kn;WlR\ǒ\H IDATTlt* ?7KgA{oм8(͹q +%ii!]JI19POަ+PtvT`0Eeyyb+wZ}WfY!] J\TjI4u;J<̂D%;,G ) H6"dGq[bOu7`&a8?8Wl*Ƣn/b^[k˶rr _(LI+i |H wH]+E.8#6I ~}cP·*#M BXQn4=/EǗw'JJr+k7Ry˭ʚ0tdȧ0]RYSM{ӛ'C/ɕ+PG T1[^̻ ph hh%wψRq{:uꚄz2ˬS2XA(dxQMw! YHi<9A1r*[f;Ejiv9HGE,R#_Y_P_+[/ru >RYG (Wf9^tja}©s wx#ќr$GnZi}, \N|gXvődjv}]71p19 [@t[&IaP %@F.FϚvTX&iOg^(bGRf&c&FƗ2@ftrZvt3Mp'od@"i:^]ѩ)yvT )Zna]|qOitgfYSP i{'mEp088&Wɾc(7e{#IO2!3J c^yuD"Ym᰾ 8v:0FFLSrW O{'h1%\-]ᰞ$_HL2 H/FRf|W0V* ul[M OF ƖEғ#!9ݕ$萑!߆(Q搬g]`"Qjz4?C7C$8ME 0P3%K1>{w*ݻ?kw,ϭ~t{ 5T|l8QAWw|k]eDX aM˓&0]'Yy\]_C2UIa0M+uwO[=5Z l3$]Bv7]3"xGvǖK^ 5w- G(ENӨ`!UR!5K]'uSكw~bcmZu$U 4'Ń'֞sdn+*Y¤` & '@CxVS &5zDN. KW  Nъ:c:P%UvmAG wU!PfؓAݬ&eK\IҔ[爏շ4QE<.CB6"x][dQ tpTZ!n=|]Au3h4ޅt0d|Gd|"F wVU8E ]1<|x!CzBtO{c  x٘QH"( #|hm;iHmEE"aAb: !-ؐ]õz8O3Q֐l*} e$8J&Q#cp\RG& g5l8z0a?Q$[7AFӡq6 IZH()l*bmZҲ`\t O#?s%"O|V-TmT)"Q/y'-sC$۟a%Nou&5L8"I )ºdQBCmL"Ni Ha]Pzh)-Gk$!yx9JFT2&b!yWT49IwK!z}tu%6KT}z+a!QRK"t^܂Rҥ%QMYOG †e=`2]G ^cMp0Ğ-x')$xlqd 84CRh; U[3q9]ߍg,jsqӘ70ȼ=,XLTFD5@-b-փrnJo@1xGP3#^%YeʈH蛸TNrOq"6] "MgX)= >`x8+A\^)eS4TH, @ildоyD}}~ !qԿ3dE5ܿ~"X;ⷫTVmO q, }nvG|:Xq()mes.М٤eL:&,g6Oc"{z魒mOWD" 3M&zE&ډKi6+*,9 F8o9UOہJ} 34 A4q6-aaƠ0nl)Ⱥ'6ZZ$|$NtCvUCir1!ÚꐥD#r>$JJ!S EQ,d6x#:~t4mBDAgKNXF)ml"GRNj %6H" ͤg 򉈳K.j =THZrvmc8vYd g']ZɆA1~"]N|V C$?RV(Q50pmRgְ-}@:{4q6={ؓo~zvp&y),O/; @Q?[relj z~KY✋so BS%k6[Ƚk|'Lj^hq?(j/+vH¶Eyθ+J8lb̀uҔ@, 7q"ffI{/y1YZǺ!7-uU,l]݃c"}[ng_Tm9!$}Uι 8 S7?[%Bhb w+X`-G Rd{X-'TSc4a?mP`xdTn?ImM\Ě*qo(! $U*QPNppIER! Au\=YxCPL8QcN>Ck贏yzqq5I΄NZD<~YSNC_"JcX2a9I]~.iK'ƥx89ĦiS 7Jֈ23%):T܉-њZ_J*CӥonTw- r"R=vΔG ]2i,MI ^;kTK#M>h(5f.#aHáyje+1iWcYq VsLɳOB%U*Okl^zh>HJqvdS"?JG B Ջdg%ԒϤH JajX6*Kp:УBJ gRfh̋V! jv+4iayIڒjQԑK`"Fҵ=[ÖbZݐ&0It `Jq7KY܀۰W-)״CGlXRԒA8UyMjCZqv0 ?D&=i &WHnm?xElR@d&<>0=DjlQ]WDc Z ]M"=#AL q1Tf zunY1efL0+0K*iOޮ71RBPK@[ٌ d=O US&VaR6tw[i7+<0DBZ\EvM u]cяtIRMYl\K@hIĶ~KtUSz$oh*lh'Me2/bʃu_eDEO2@h!o}vǝ5%q=6̲׈=WǞ ?5Dҏz^q*@k\`t7gn~ܡUTtM{nVX\i +%(&6}'#73^bgE NxŢ'0;o(Jvm!MAyd]-()^thZ:D/ +*H8@ @-Ytθdb'cpÂ8? Մ}Ӂ( tSY%a u"qLr@>uTSy D@ JABuZE ;6ڢ۠qp-D@Ƌ[uqr T[cXuRˡy @+zdpAȚ6qCU5KNj?c6(E3[zhP0E'B,'F=_d=ً=:QE#R o&<`A٧ܡC(jE2bx: ̫n%qTlƹc]ѡ~1C2nvj"o#k0Y*U-qlKO>Q QT6E+}rSr,Ef՛qwlgZ 1tNKUNTro&p@M7(\Pf&5wH}L^2GչB(JPiz^Oഋp\y_Br*{TvS%Ps Tpmu GdnsG@?1MޟdQknq>Dc?_/"~4` R h:iel:y/t?֒ 8GA2=/Bq /+ĒAƅb*Y\YNa##xS 2 #]%a,c=(U+ʾ?ph2޿$i^t!]i}Ϡl5}Cizp֯6ix PK9qe ,@1WleD71q,,ATJC҂D_ +a-#R) ;? 3BB!8Jr}=Y$y^r:8MȆ`8h00Bs GL#90ok#a]P☚c*׹LD۵ilPuca Lq<(Y9a;51(3ΌJFԿiEZQ"Z;!#|fQ|+;. {Gf@Nzj0!L8B>PZυ^ R)@ *)~1z Xtxn mU`*Hih{EQ)Ȉr;u<*`xӯK]P u&‹a }ZcFDij64 Q6%C86q`ս yX 6]'[3 s0〗` (G )R{ۗe D>/$@YGQ ~mv['W#0`H@(j4*=zUq"HjȈN5hil;ē@T'IDAT';M"P(5^@$K{)+Y呐Nbz Ichۆ!8>d](D]na"f@ĴAOQRviD%=e8,e25a8"C;zv`q2yg]FuD! xrS# 8E75;S6NR&ICB q.EO.&ѰS.(4R=p\*dUJs; v4Ly"G% c/$KI;EX;_z`C:ׁu_onO0lB|?VގJpj{d'}mڱa/Mp6m3^݊=XIJyws 1 &i(99f/~<^J?=f}q}v/|-1v6qha8P05m ߄Si$BGBko, i1uKb { `0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@X`@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a`I`a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a %` 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@aM1hnz#ӼN`any{Y_wgy>_iIox}\lA;"umo{kw{m-}r{ T7YB_^m~e- hF/cPhЯaN431A_%nП2S=`kG m0nO8< nlOa9-W `Oa `3h՞/rG3y|y{8_གྷ+>=M :`p + H`0@a 0@a WobޟYr95j}y j}~a_ B{TUv]Y ‰ +0E:O 7;|n2^Wd sm B\2n:_okGq&.鴷U!n+C]OkrZ"MwVɲM#ˡqV'ˤn Dg6ݧ*7p|y4,~yYLfA^s1V7gU9o |׳y$ &GG(P:峯2nfab=2ɟ>ufvj4h KG)\Ƞs˭txgOs &oD1g, 2eU %0n"d1 tdlj7CL6曈M%ttqU) 󱶉Edg3gk0(v~gq\0m*7Gofgډ*:;yh|i^0M7NwcZ㼕;|\>iY u|y1odU('v ~iO-~Ky1_e 0[?1vk71:Z_p:oCbz8 <`Y|}J:1=qvn?LJ^ӡH'ʹ9]k48u,{~`ک~zx[]<& I'>bpi\^n9`~)LOxn<}AgαU7c?<|0{3~M~ ~zxGKߐ+vz4@a 0@a 0`p9t4s?_ ?gpO}ߟ 0x'h lƶf ᣼mO@ 0 0 0 0 0 0 0G|{ھ@}o߾oo6taϾ`+ ~= ߻a7 )``lA};a?*_jFFucrNA c' 0 0 0 0 0 0a 0:e!u(~8V~@~ 5:` a)~Tgs^ ૺ q mʛ`s llkO!= 7h7 Ƹ_O@a 0 0 0 0 0 0 0a ~AB0@a Q]a 0@a 06m* 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@aa 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0 0@a 0@a 0@a 0@a 0@a G<=`u[g,->>BBBF/FFFJ6JJJNNNP6R>"RRRVBVB"VVVYQBZZZ[<^F^VB^VL^^^bFbN dR4ebYeeefN ffhEjV:jjjmj_nnnpdNtQtttvb.yWy\zfF{{{|P|pXSb.V\Vn2fn.zHjcr y28c`S8*pDw4'`!dvaC?28jgo>Q7&v?J2CͯH1GNK4 #4Ch$ Y7o%$ =!6IwvS.ҿepЮe 2oo iqm8I{;.X8mIQ5X2p!v g0qoO[fWL;iL6'gv6=p&=?1 a{,md v2O7`[g2-oۺ_4B±`R8A6R 9:[y)3@p礛d-d \e߮4al<ɉRH饓""31Fr3m9 lCb:RY%d 2Hd'2x  CxH{0gKO dp1duuu2QyG]յͳΞ\_[+o{޸qK7d0}ՍWo]pƮn}Wn]@&=|&|/}'e "eRҗ[WV>{ů_0\J\y0nꏬ]xɵ+`{oM>֥\Y{2~Sk};x 2 `u뾵n//w\{V,՜ /Ov~OE$sV> woַ}`dp;?+w;W9YT28{{n|; .`dpa#z/[;*}gerimeip^c<++7>pye t H[.N~?O=l\F`id0YՏ>[=}Ͻ++LVV#V `idz>̣Ͼuާ*\~ !ՍK\>g>裏vyPC9C uE<b* +v 'w/uʍk( 0~zcW_=R{@]eyow%~h/mbq`q͕3 ۗSoݺ$"e0Yۺ[ooH[y ,+Ww㑮www>=OVri1`z'~N=2Yqr`qڎ V6ڂߞN+]+ճ/ln<{o}s UZ[ev 4w_{Wַޠhe0Ytses#;l]ڕL!U;;f% [׶'SQfYOVVVTa0Rn^5Y3 v eGa/ztn`sr~^ÿ7]-|He1X_!½~G}~o5 d­sg2xquG70Ft W7^.Ww'epDQ`N;v-O{Op#dkÄGS.H^A#Q  z8e0`2ظ+7V&l{ D`ʃwC+(W"_ݚOm%`u_=o}֢G>H|vaAzdmk~t9# vttvMd0"Lַ.߸gƎ !{k7ϱ`D2Xۺ}'旋2xo_˿!HK˯}OL>m'|;w>̳E`O|x׾owJ=b-EF38{/y3;/%!/==/Yl0|)/</K?xO{G۹ l|_'}+/w2Lؼk2x o xow3 g0"<#dk:Aͷ?##^5f`GoP>Kr7^K<_ ֶn}9|͕~;o~gB?K?&.xrP<$dמE F"˿^;?{٫%gg?|mHdp7~vq?KW.n'<]=vxΝW߼tfˏ= /;w+<Օ{>+y>[6Vq8d]OyֹC_>#!ez|lm1G~-*֥ku]M N.|M\0bun]tu5%0Yܺx%o0.;p# XN=v~eޯG?_o(7Pn>_#U=?㒁jD~cVvlR^,h `, Fkh]Ȯ4=6E3 Æp4|8YL& }N5NC>ӷ2jGeK7h)yc_z~]fM}ǐ5Jfon=10:o|92S3}n =ԺJUAYRz?zΠ `l)+wgaBaAU*3 @󔁷 I}dȠ  <&ԣ^xe"2p>@5+'.9aGzB1YtPZ,T\4Mɩd?+@?{?׫&eie'>X A \`.hk1F\  tP9{clDk<9㕭G th_asASwf cĢ 2(<6O1~!dzڶ' =;*nNԣjP,ˀ Bw@ڼ+N 28 U[ D˘U < H^ S'5dޒdj2 9 o, <"eoq s*#h0e0أ 2QL]2d8(p|L<ȏD^)I2d d g/o>:~ fCw3^O,P2_@x#" ˠK> p !|1AB g0|n+s>Òg0A[>0|>P*J>!eЖ Upe0|!6ˀ|3N593*3hg@ e@>@ 2dȠr>H3ϋ|sCgsg#gp28|VE%C@Ȁ|s3-%AKI3P=iΠ-A BS>=OD-2ho5k>2 <  $ ?A"&2d Xf$Oˁ3M tf"3 mP. J"-^}TLw)eQ ƺt9o &#RyEu,sy.`00!Yo%9.PV¡ s h?߁ (n xц]N U!aٍ#"< Sq`t<d0 b2g Rn G()g Y?`EH1so4G9o=(dzEz 2@ 2 V{b7`NK["|^Sy!Xu s4D.[; M=cB+PdM k-2չʠ<!8 IK|ir@ǯ%RgGH51MF3S-yB 8Ad Zj5UMC}re"a/C$ 5)0B!_ͤC _h"mtD=qVAވ}U! qYyZ3<2y@ BM8՞E pB QwƦeP?N7FIqfjг "X<X_d ΜA JbQsΣ:q\_j2 0/blΛ5o(Q?W/G +lkM=%Pc c4${P5i<|a.=d˹Ќ, zpRT~o  W]n,})r@`8v *=Q q{@6,ko@_:A&~GGd+DAF|:fUQV%y+zPj Fku0Ad{+F@G@7f/PHC0ͼ0 T+ke`ed ܟ j"ρ;@ T62[+'_6!/o@P*@ V<~ {i|iBt ^`nA{"yπ5> 82HyYA#, g C6ļNm/o/OHYOX D@ d 2 :ܯxDz2(MOV,_Ըy?{ Sc=sN+I\{V9:hwmAhhVpur\YheXk̍28H&%i.?86FȕE9KpT½@NfyyG;: W.ZrlaUg(++2_ҝ8t~銣2A4CβbIc 4X2!ꐩ +1Zyߐt~y&%Iכ{fOܨi 6R1Ðeo7 dMyXN `FxK2p]bMьaa-֬k B,5YAʢ 0 WE5q B0dciղԷoj9 {?Z -ʼ 5x9 ~4c?GOf:\]&DlwY܃N& Oմ(yAgp Ӏh<'.R>e/b-6TX+ vI~^#_ ECˠg>}^ BeN0NR}x=ʠ?!\`>2Zhҝ?.T'T|d&Zd0tgW 9;8fA|^ك  %ウ 2Q8@ Q,0 8-2*@)DkLr Ѫ_AHBE]|߸*i޶zcLt@S$Ģ,MS! X S 1NZ"o~D7_j@ b hMW1guEH.)(V%Ӷq2er Z{!!:jIJfb>r[0|3d *2p2L0G$#onAN5sK&*92^ޣ^2h&/Y9q޸A1-*6b@&VO҄2ohR!'`.bb@[2@ @PAkvΏ8{&f /Qtjprl2(7evw#giyÎ_d);4 '`>2Py ڿpmy( kL 3 sAJH=rRZ)KǠ$XZJz_ BPavg0ox5nhJTcWOqw!?yB}T0 tH`r+`j U !?Ϯ{2?G[A"8fhladPtCeO% qѾL Z2?d_Vd"}@wnl2p0eS76g] M"*Vb'w$2 ~3ApgApȟlp ㎜B IDAT;_ q:_HOX穏匌B*bG`q; xd n<0LdE1_ڢʓ(m" SQ-₫3 #N_ (p{2X]h 7ncIbڔ+ݚ\h. nvAE1ɠc +"F#BLBI146[x4|<9n ~o {+y3! dE+lw>L(t۰'[?]lve^ci$/C2ʰUgC-A6QV ~ RVNWO3?NNR 2^ʙd/q>0 ^~0hD(wy~`>^~ Gee2"xyݚ3BiJNj%Ag [Dt48cc'=ʗT#g`$FxO9 D wjz2 r`YՊiٰ`ٵA?; e4hXɠP<3tn3яɩb Bе,iUl<+d/>NV`bCe HaR4+ǯXWU^Qg0 n:L1"8m)hjGGCOy,2r$K~62~jEdPXd>22 >>kz  d @)ϓQ+C| }P|a~" #gCJlUФcT `F%LZcAQ֞!1 UbqoEY(8!%t^?:e,ʱU-jXIu23a.W<(iZR1Z[m@6O}6hw(T!?!w s  6" 1򷥣"=ʥ~2` |QD" Tt32d`=Z--AXyg%A8= E##@UM1D9Uz-tY^j2'W͐M?K$/N ėdwLn tA9:)Hdt01ȠVّA(`96dUegmsd^U820C}{ ݝ@&+@-0dPydh&bGΜ%zG yPA-ɄX>۞ im]yy \sϐ^Hz2O|4ȠԱ>$ָdp ;t6Ld\m $N fg@>X ˉπ|0 tgx8{3pA>X^|ѝ`4e@>!\XN ||0.3 Q xF"||3ˠԱ>$  @ 8 BgK  /gcA|*o@  `=?π|2  g!җ|3%AKN>e@>2 3H7 b:֧d@>d@>d22xz,XG uP0^ M8+N+6"ˠti%~ޟ.-(Ad`[;/N ~~39]22! DΑAB 'Oi~3e78#O> b5"2IMeczAŲaխ∽.J~N[ fC:1@(2,t@*$vA: rr&aV-2H] BeבX2p|&w]"[mmd;#82&A>dP˫ `e`L1sQyѢJ$:gPʿh1wY!:2S!dێOG lV\7^َCuw7S"(EG #C( t f`48u l- K{NpR~o=6 y{dv!>$=@? MT=] aQm fj1:!vw0mݮ4WNWt!΃>NS42F BتQh5J7?%hA Y6 ^>#v5 n (t=n#Q@w&, bQ`1dPGP0g R fs#I9iC 4!ENrۮ_zagEvA)`g d  OGДz[ڛy Q^u 9:("^nRtrc̊tB1q k7jA@m2H^X+4$0/  N%`uuI&0 I0q-}Y*hT~>d0 j(#e )d`'9UE#(r4e8BArW!Yw'<@N$Ve`UȻ: Ă| 2L&]30?~6j%ED", 1yqWKɛWo0ZsNBsJׄ `2D+XȪ~_\9\ńcG]K`=}04Xt3i,Pȣ7dLLR 'Мf̖]͕oב 53kK=Ƞk>T򁅕:/ BVSq |D  32(/g4 身0g39םF!ou%S@#282Ϡ}Z"oO[A|cO@-9  d 2d 2HXI_Hd$'maW53ЁNrf#qK>?Q6t Qdp3HVMG+p-&2 ՚rkެ.Pթ^2z娕HB., 5Ay*׸^wMgm*PthZLw 25Jyw6>>M~FG@]lmҼ#Q:뒱edᠥF,v3BUET'D*Ǒ,+FªX3NU׭{g$GnO$Y+ҽNi]GzjDž1 n}BS=n2ꎯ:ŕ;u=#'S(FN a\][V_O<_ظ{x_:{ZQmie`GM:2z4ɠmb:Cd~\Xvx^'&L2פA(=p.ˠhYd -z2Pc.2:`.282h}hݭ㹟sS;.U6.:H:fuFM'u5=pfcE zd/Tu뒳 ˱v=ˆ{ 2@ 2 >9\}m?m@מAVc'ZO`h42o-(@L zŝd}[ 96 L :d)&(EZ2#X6(dp2 Ӹ+3dD6 /Q_ AL&w/Cʠx2hH $; YKȠgSf8n.KxZ/ u%Cq@מ m  d =@ XMKT$┻-(bQz'Ɨgh .8!,Zg1I  d XhDY5xOY&(܏A_wN4{gLz |bj6m՝}0Ix" .n#y^2nZCMP n߿jѩ5]2E 黠 y!YYygcA&Y" d+/w;Ǟrmsv~(ɖNG!/PYc3=z2p ` 2K(^ͻˀ `,2"oё=kc{#_BuC< .:+Og(286o 2 2/Wx5Ɓxcqϲ]+Df?{]Ǧ[k:r2"0%äE'(lT/&,0!o!*X!ퟋuQA(vD+sP@(wȿ+&Cb D񽷗ZOTCY0κ;BfzQDteP0^%\iiE3o|QXEdIfEdg]7b0h(!}"BRqD;] `9eeH$u>>72Md\l?[d`ÕA)Awx dк( Of1z?ud F8"˲w=0!+ d" @043OaNT,hK_ԎCvQV>>7缬ˊ|DWNDU2gv@}V.Rͬ6+-?JeW|U\rNV ˑ¢-p?A_d<:pz9K2IL)׈0>6Վ 0aBPdP>Ae`v|8v>q$(c$\7;F82Ac>Z.iYp% uRwIBEJ2ȓd)' >!_d'&| 58pzfWBah߽skXb dЖk٭V ;qgP81L.cI؂ O Z7oEŜd+2 2nzd %A[ѢC+d+jAa8|hބӱI f\td> ޢ"hvA30L]G,MF'3x93ヶ 4 XXG\Kfh,Udڭ;6\^EI*d*?m>4׻bACQ5 *] hqn28=2E+ˑy믨S2p|XVb\f!+Itq+NN7k;}95`1RtU͌MNJW:@E~p=\I gmn) J*bG Y6;L2>Fd'?g.z d^)usAt `dДw2%؃6 ×A)SI]4MCޡd@>XX~Q+g*N`7p,x j~tjv8N̯&:; '3XZh΀ 2lt 2ˠ?#[v*P L9ˠGP^B 68aBx5 3$+ C>2t[d#0+2FS[v/2@Ӌ܂ZVVLF! "82B!a{..F58R@ ϑ@sQ-Dwn4 dp2ps6X1U Ȉ NjkGPoVzP \0М4Y,h;Z4̨Ƣ#'Am  2@2d2(Z, 6֨}3adb6 ҃|Q`=]f-6:EGAeXt''@ 2@ 򢣙&%V~YѨH_Nd0€;;`z*V~*F1FS: AZJ˦ښŖX]0 nl2pF2@{k &Akas^*vN ,9( wM VeH ȠmΠ*{d1 s&yd`uEX)*Xh/m/,(Lޛtr zW2g«ў3 bcg/cQV8A-Uʠ2v ZY ar\Ap2P_%ه@lAb|&K, |a}XAޘ2H7sR^y 'XqE s!54oo/pWwNM2ȱt4gcGTɉ|?iB/u]I!ynoX\düTҶ2d, SsR~qc-0vu'Wdgxzj暗eg˴0ɾ"}>9 A(4fRcAk`Moj ):7 jGw{]G7^$ `2HKUP̿N>Xo՚v1_H)Oq1" d~l0{y;aX dn5qzn=FQݬX'oqdMԤqZ(˱b0߬y 0 /C`:7Fk 5^(GPwe`^_Vْ@"Out `FdqJxfSDKmT=X^ow׷z-nitYwy`qK:iTVd}WxMpƺn'f.}~1Y `qԆǽ_6 @ 2ŗA7=EwkN5>6%2Xzt_һxG/x+ o=l2h̖N$#d``++Ȗ<8z+_'@S ATbm? 'jZF.lvB4atb)ςw A,kQ^||Kgrq#¡^ڳPhLL+:S ,!C%_tI&^ L7R 2D $N=MWW08ĐsX2qgJF"UvSAqnXpV+b鰭D@2PUEf&UDQ) -՘`d. BVüp ](e}L^)ʠv]~XGQN]ALʕ/Rn~ 4 y 2sZ({@or޼s^[` e;6&k/郬A | Ẑ  s-`2 Te`m_. LyD)h%;DdIQ1v3]yŕ9I" gQHh%j9$O&nLf)u 2@ @ @Mv>Bʓڣ:1$Ϋ7j=/m-OB c*RP̛',d!b#/Mep'@f~b`2(MN2Py8 0j)j l ܹ /otX{9^d`pW2(͞AhAe?U@%'ZM 7 IEmy`20 sDž MPOTo[td6)F(q&@{`hm4v @ `d;~~A{].D]uu>{o=0W_XuLk52m*xpEO')-{L閁gD솗<* %ˋ>`a{lH[#pz>iHuzX8vٌGRX?& IC˱%2w~(GU*Nʨ/3L^SNgz&,<ȫ, ܒN %i-Ro?djN& VGFc+ {%Ȼe`(}4M""5OF p20''/|dP;k`f({c8=2wœ5v |Q Äjxyzp\2(|1@e+a|tlnnn/6۹u{,⣌zND>iX`pw`2`"y2 h`@ t@DZC=U/=6兾SVWS>l< ۏќL[Sp)@gTJ` -vwϠy,,|vn !` ʒ١''IyVe uy(K]s`iIC(2/C%+j< 2 2i0 9|;k/vXo+H@5f`wV)-FmY`=P@*πKׁIF_pd`%T3XB{Rm-d D?K%7yi T z'A dˠ^}<^ރlshpR2 ]cŢ f3;5 b,o.MG үw - (Dȋ, yWPq>_d 3g !r5V6 rÕJ ;`9,x˄&6o|gA\ɌUm` %Ѱ2~U9?_d !/ZSϠQYOݒTޱ+'CJ2wAiA-/X0i/\d. u ,S)AA~NN2(x9}&xי8vD.82o'{ 'TAr> yt%׭/Xdʞ22@2d2HC/}O1XrVRw Dj;`{YӐ[SL`4\Z|0kst_">~F#BUt]_u4<b%/T%$q&2 ^څhzH^9 ` 2N1t(TrZ}cd"2UDGIy Ãj`M TUP~|baմ XӞ ܂f ,3LA[_{o3G `9d:.[H#AѢ2t Är (Ҕi;v z/:2dyjOάjC#|c 'itR39N v-\0sl">eorje0Ge&' b p2 jad @ 2d @ \eKL"ic7CXo@tAYnF`Z{'utIME,ܒLIENDB`gxemul-0.6.1/doc/20070308-linux-dreamcast-1.png000644 001750 001750 00000011626 13402411501 020644 0ustar00debugdebug000000 000000 PNG  IHDR sgAMA a9PLTE{)))1RRRcccciii~HMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDATx݋v6a)-it@k5X! <y&8D݋@W|*Y[Gu8T[rwZWHOt3<ϾRWYT 8 =rz]?ܚϿR46yIOx.~0b{XlV ]eG6I3s#bx{x")zu'o} ?һۯѓ_ GW^[PRRߢCo{}ο}o,kfx-f}t =LL׍G6/5 F 进3躐wƪ[f `svm8Fߵj]k̪X󒛙w庎8Zপަ-ԺP">R-;rO*z6зV3gt~Π볙X{zo+u]tLsSp~nΦogG{qIu4u*]G9vN[3gG~Tc'nNn˞e}( g]w]ZQTL׹6M6ּԬj6~:sCP4ڌdy(O[yY0յ4-_yO uNoލ.yOB y']L銣:}8_a ̼.p۱ ؊wf+p\4}@W_wu3]]]]]]]]]]]]]]]]]]]]]]]]AW]AW]AW]AW]AW]AW t t t t t t t t t t t t t t t t t t t t t t t t t t t t zG@W+@W+" }׵Ku7>xywd]/&aFGg2 y^Os^Sw$K>>>g]ϿxvL]k5 Z]Hț.$__O Gu!] %kWQbju]\סCI|yt]Ygs]κU ]_4WN׵u{x6u'kWDjug.V8t6=t]YK)#]5_bug<1յ]׮6:tiu#]7T#_KϛjXMǧ_=ǧG-nu%^3+OIvᚰ)S 0kVam?Pѯ*%W}پZ&C׀!{~Ze6ENCgC>efRޫN8}Ǽf^*9!vZ]@i~N벿n ~n,Ѝ( M~Q:6k?/ޑՆ4pJ]u~nEi8X"zhȫjUvV5Y@8e!v[ߝnxl> T8ϫA5=2a6麵 `Y]ݓ5篁'-7o&/N7QS׭umSE3z]`AfOJ,[7$>麦=,> 7gl\kuV;,>  3wkBŌnJ GךI]bҺ@ئk@Rׅ3i]L8 _V0i%e {)77t]T벚^wҵ>>oHuG뼪}ztB׶ZOĪ@ +@Tknp?~?T+TеT+֦dGg:udŮ48,6 $ >5 4ktQitmmǺ4VuŋԺ ]@uD] 4ucXّUy).)t-+@|䩠~ap͙u_\8`3>[ׂ,2 JMp󵃰Q] vzr]43K3bD:v?EY`]5ؙ{.躼zUz@]Y]7\=Z,sN֢hkapM@CO+Gs;j\=gZ麨`ZCh麎Ysh&#T8p8], LH;9m` b3c^*Igҵ9#O8Ett-薾5ѨKY*e2f[ClHaq]nTTq#PdV&k\3 d!K9)C`۾ BzjۦvTp~ 0PALI\p] \PL`m֦!)i;L_ຖNwL9,vV5;i;XLCBžkTate4ΪkP[=|8]r2 >$ufg]ǗFTײ uXk6 lL;kRRyr+xᬺ /.>,66`477kAGV c>2B9ƶ9Ök Jׂ,- tm@0AͲ+ʯp]lh0 C'* } :%v]K UvdWF־G5y6;ʮϒn}pCeXkaHQ׆k晴\u(5"N: 5=[@3ZaPXZ]˦U.1qrm򁀮|"2F A=zVZxxb!]3Yn#kd).:zAqS\R}sXVu-J]We4pYM ,u ɡL \`+uMgv4>B*]3Y' $槸f]@p ]Oq@A~m`E KRth HKXpy߭^PC"okw]VWu 'J:= l~uy]ʅ.no,<^6zzuy `f1ąm& $uHn-{ԥqUz&R'2,:^"bؗb/~85>,NAϲK-ۤMFL|5, U󰒵},Pw)[s^?B{~&({_?I!*1o^ÊS뾶mr\T41=ao6BצV2 "KQrT+iRa[a0mg썐ے42Y`UkVommPTH> uXlu` ]?Ld|Y~i$t&w|]|\%ƦJ:*  JuM-#N@Z\_W#;:SV}| =5ݑKu(SKuJ/D:?^k_h2՘) 8ӵ+ZEaY" 4wq .ˮ1#O׹>* T'zյ{ uc_keu3Ŷ DAtÖ5]vovatڔ<]auN =@ħZ:xN٪tԵ' }C;6vqLV~Z]k]k_7nVLDR3 W.i>O@?@W+JW+JW+JW+JW+]]]]]]]]]]]]]]]]]]]]]]]]AW]AW]AW]AW]AW]AW t t t t t t t t t t t t t t t t t t t t t t t t t t t t zG@W+@W+@W+@W+@W+@W+@W+@W+@W+@W+@Wκ><u}ִyx+ë+4}v tu=]AW]AW]AW]AW]AWf%!޻W_ekFǁ&޳74Fx:=xopN@EtIME96IENDB`gxemul-0.6.1/doc/20070128-netbsd-dreamcast-livecd-2.png000644 001750 001750 00000016264 13402411501 022234 0ustar00debugdebug000000 000000 PNG  IHDR kgAMA aPLTEiiiNIMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDATx[ : HWjYX\=g]f[% uܶəe?$  ~E>FY[$o\(޽sx(z<` %UpE٧=\a&+~1L+:^{\^ֱ )v{j__ Mzm_e\w:[7+++++++++;_>^gA +rEUp8\7ג+sc qbxtlz诜p:W\/t \~6s*ÿy] \5 ~| \{\WpYʂkcev]=0@s]@<N 6;ou}( ີ Ov޸︞ 9,>ۉkX8%\ٞ3W2ڛ:UU핵Jy~fK\铹n^t|,h_Nqli c&kˤ 'lj P ˹&{h&A!fӿ-tK ZdGkRm?;}_V.K=-q^?|}\\@a4A-u:Q: S[7q:qe^EqZ\JU)T_seK:t"?z|Zo @}\E+L]wRu>I{L'r۶9?' &񡿎љǁ= \_\hWo ϳf4IΔ50 \_u]½pг\Q\'in ꪛ[qgX,0n[ SkuS5vs)~봾g93ຽ=\dn߫@@p]+Ut-:X! =+Gkpݥ+ΚS_4a] [62 e\x:ߪ3fV\ϫ__K?_iYW\j|zJ}v[Wfa_Wy:h>pͿup~cU7ZtѶPߌå]S7Õ4GxN\&MZLŅ5=ٵk,ƁB ;.,SK4#?׆v< \inrqa9gY/ksafҷSH9$ΑǁYxqKZqq-uՌ +ji|1d7coGjf\3:}_&֭b¯h\XhXz= \u7d_F}hcq{o`p\5|7YysTOWv^9WҾ[" *|`xX鵈0[9fՎ= XV"j3zGNh5 u.pg:NkAchKU"OwHgWqM~mӥfq5UkbJWy 1.p\@ \f2>Һ'%a{:n[ksCrQc sO }uAmaiŸjcpOF\BWpE_pi{m;e.,._g'-\@?-U2Vݞc1R{0!@\IՅtcsY .x>?|{[vBe[g^د-l<\SLnuUg:,p,,pW,9zيu \.).N2q](]{`duZ+TP3k~CXpz;K+[;z3g{`U{Fc8 Wq%*g!nq8Ӿ@~&)I:S=](+ :V)b@(.5c]? kL;7*z6WU?1WY+Vln72k@s-bK}Vi%Wag[aY "P'Oq[&W:XǢ++ +++ +++ +++F7˽Á>JFZO+kW\\D^cLjJ§rץ1 \FE=;l͕S,DŽC^.+xU96 ߠ-3fN\ƼYs<٥{H2Wz5Tuϗڏ[<+ ~&8UK-eU{؇\}vwoIL)ƫUe=Jf \= L ,\Y1^ժۈ #Ȇĸ^YVLC B\.́&Xƪe*fdd`YW:^p} ՝ ,pWpWpEWpWpWpEWpWpWpE,Ix[_ruຝk*Obi0|]Qs-}D3|WWp} Z9/쁍Xpzf;1M&V6qoU.X븜jokU k'd :[Uίqcfo#l;ܳ(;m56<^Fx~U󏿯O1qu\'؍ܞXQ_%׹V}5]n_Dq/ev5ZƁO} WU*ծ!\2v •*y͘jGGكk繒 |+VäO{: >k. Hsy8"e2TԒۥlwvD̺c؀kK }͵\?@WpEُku5=ÒOObcvj߷v|X40xv<`jĵv+=ȕ>Xk 6궢nRjZp\RSŠUq޻gl-Xm7q k3qߛkaxJ3\kGܶp! slCpÌ13,i4Nggub.aj,^@\7z)ֱ۵h)TCWpEyk˟-sk߆-֖_lԵ;)[Jm?Wjoh\ZW_k}>N;?ψ~)?a\ Lp݁+Z:.M+S__v_ʹP?؇vo9OSXrme.䲁>+.y__jT.;[pM9ɵ,kW/]ɵG7O/U\kЮ}K5ךGQ% k/k|Z,ר s}(Q<~W,_)le;.wqNOm>}nl=GNp}3c = \\\Q\\\Q\\\Q\\\Q\\\Q\\\>0ӣN.|lCWu LNk;\9qf\\n%W}y2UۮޫO\\.{eM>7b_\amb6Xƫ(~4װ'4)%ƅ 7p qU8"֣@QϮsFVsWv;p9Ogyk# 7ֹ휇k9H{9\\a[b~`r}\\\Q\\\Q\\\Q\ \<375S>n{zj"}b̄|;UraԳ6=Eaʵ`Ƶ4oyjy;@X;qm&$Y*^U\C^ϋb\`\%<צ-@^q_^aװFCu+ zPx_Y (W{]Bp=׳[Ո:a_յ͸2n+ի9\_wGp}Tmc1qlWpsqN }`VGqd^.cȩ2MU\k-`k_u3WSm{S[:/Xpz2uzI.]<y4O{)ĒL@yZ?<19s4wj/S8ŕuݔkw)Wgp55Qп%mlA(r6ƥ\u{Ծ6W_~*dojn}c͍m(f}5 pXS)3=٦6K:k>ksay[ײ|͕\8ʝqsι=El*V|؛i|kZ'\#lO{\ݤ WKm}|{kbε,9:υkpoͲn9~,7ڷ5D<:?kYr~ۙtb\E<۲?kÔIY.ڜ?ڎ"ayܲmLmVuM1nYg\ܱk܇o6SyUZf7d hHs֬ 6ShkRށ\O;+~WWiYq̶O''7a_=M;JgcidY |>ljBڒVt1Q|G^:3sfj_lqb٦3u\5iLRkF8JldžM9}o]=urd Xki稾fgPq?e_qK}I}`:UA5ְoI]n]XW;TKzt~\FBc$"S2Ek+Y\E,FSsO:^ogo^s1eE\Y_Ť+=zP%sLX3ŵ^7rbxs*Q/|Oԅ'bMNF_5Sdŕi-WiHRkGuIWWwj6y=y9..[~Lm]=rlKȡks}N[:O}{zjžИ=mul˞] 9ōxKG9 zephhг+Joݬ5ΞߟkZ,[Ӥ8> 3rm}hV X\+I{KhcJNi`b MeygǴ7ݟgq x1y?{>M}>Y>MN>4Õf|L WywUwǴ7{&Jw$Eɧ5j=hvr>'[}zp)Wp=[>Њ qmz;+u7fWp}Ԍ k~}-S ~}Δ~4+.|߹~Cڝ+t]P\\\Q\\\Q\O e2qO,l/5=woemQ\o r)灢x<B`Q tIME: IENDB`gxemul-0.6.1/doc/doxygen.css000644 001750 001750 00000016740 13402411501 016170 0ustar00debugdebug000000 000000 DIV.qindex { width: 100%; background-color: #e8eef2; border: 1px solid #84b0c7; text-align: center; margin: 2px; padding: 2px; line-height: 140%; } DIV.nav { width: 100%; background-color: #e8eef2; border: 1px solid #84b0c7; text-align: center; margin: 2px; padding: 2px; line-height: 140%; } DIV.navtab { background-color: #e8eef2; border: 1px solid #84b0c7; text-align: center; margin: 2px; margin-right: 15px; padding: 2px; } TD.navtab { font-size: 70%; } A.qindex { text-decoration: none; font-weight: bold; color: #1A419D; } A.qindex:visited { text-decoration: none; font-weight: bold; color: #1A419D } A.qindex:hover { text-decoration: none; background-color: #ddddff; } A.qindexHL { text-decoration: none; font-weight: bold; background-color: #6666cc; color: #ffffff; border: 1px double #9295C2; } A.qindexHL:hover { text-decoration: none; background-color: #6666cc; color: #ffffff; } A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff } A.el { text-decoration: none; font-weight: bold } A.elRef { font-weight: bold } A.code:link { text-decoration: none; font-weight: normal; color: #0000FF} A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF} A.codeRef:link { font-weight: normal; color: #0000FF} A.codeRef:visited { font-weight: normal; color: #0000FF} DL.el { margin-left: -1cm } .fragment { font-family: monospace, fixed; font-size: 95%; } PRE.fragment { border: 1px solid #CCCCCC; background-color: #f5f5f5; margin-top: 4px; margin-bottom: 4px; margin-left: 2px; margin-right: 8px; padding-left: 6px; padding-right: 6px; padding-top: 4px; padding-bottom: 4px; } DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } DIV.groupHeader { margin-left: 16px; margin-top: 12px; margin-bottom: 6px; font-weight: bold; } DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% } TD.indexkey { background-color: #e8eef2; font-weight: bold; padding-right : 10px; padding-top : 2px; padding-left : 10px; padding-bottom : 2px; margin-left : 0px; margin-right : 0px; margin-top : 2px; margin-bottom : 2px; border: 1px solid #CCCCCC; } TD.indexvalue { background-color: #e8eef2; font-style: italic; padding-right : 10px; padding-top : 2px; padding-left : 10px; padding-bottom : 2px; margin-left : 0px; margin-right : 0px; margin-top : 2px; margin-bottom : 2px; border: 1px solid #CCCCCC; } TR.memlist { background-color: #f0f0f0; } P.formulaDsp { text-align: center; } IMG.formulaDsp { } IMG.formulaInl { vertical-align: middle; } SPAN.keyword { color: #008000 } SPAN.keywordtype { color: #604020 } SPAN.keywordflow { color: #e08000 } SPAN.comment { color: #800000 } SPAN.preprocessor { color: #806020 } SPAN.stringliteral { color: #002080 } SPAN.charliteral { color: #008080 } .mdescLeft { padding: 0px 8px 4px 8px; font-size: 80%; font-style: italic; background-color: #FAFAFA; border-top: 1px none #E0E0E0; border-right: 1px none #E0E0E0; border-bottom: 1px none #E0E0E0; border-left: 1px none #E0E0E0; margin: 0px; } .mdescRight { padding: 0px 8px 4px 8px; font-size: 80%; font-style: italic; background-color: #FAFAFA; border-top: 1px none #E0E0E0; border-right: 1px none #E0E0E0; border-bottom: 1px none #E0E0E0; border-left: 1px none #E0E0E0; margin: 0px; } .memItemLeft { padding: 1px 0px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-top-style: solid; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #FAFAFA; font-size: 80%; } .memItemRight { padding: 1px 8px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-top-style: solid; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #FAFAFA; font-size: 80%; } .memTemplItemLeft { padding: 1px 0px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #FAFAFA; font-size: 80%; } .memTemplItemRight { padding: 1px 8px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-top-style: none; border-right-style: none; border-bottom-style: none; border-left-style: none; background-color: #FAFAFA; font-size: 80%; } .memTemplParams { padding: 1px 0px 0px 8px; margin: 4px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: #E0E0E0; border-right-color: #E0E0E0; border-bottom-color: #E0E0E0; border-left-color: #E0E0E0; border-top-style: solid; border-right-style: none; border-bottom-style: none; border-left-style: none; color: #606060; background-color: #FAFAFA; font-size: 80%; } .search { color: #003399; font-weight: bold; } FORM.search { margin-bottom: 0px; margin-top: 0px; } INPUT.search { font-size: 75%; color: #000080; font-weight: normal; background-color: #e8eef2; } TD.tiny { font-size: 75%; } a { color: #1A41A8; } a:visited { color: #2A3798; } .dirtab { padding: 4px; border-collapse: collapse; border: 1px solid #84b0c7; } TH.dirtab { background: #e8eef2; font-weight: bold; } HR { height: 1px; border: none; border-top: 1px solid black; } /* Style for detailed member documentation */ .memtemplate { font-size: 80%; color: #606060; font-weight: normal; } .memnav { background-color: #e8eef2; border: 1px solid #84b0c7; text-align: center; margin: 2px; margin-right: 15px; padding: 2px; } .memitem { padding: 4px; background-color: #eef3f5; border-width: 1px; border-style: solid; border-color: #dedeee; -moz-border-radius: 8px 8px 8px 8px; } .memname { white-space: nowrap; font-weight: bold; } .memdoc{ padding-left: 10px; } .memproto { background-color: #d5e1e8; width: 100%; border-width: 1px; border-style: solid; border-color: #84b0c7; font-weight: bold; -moz-border-radius: 8px 8px 8px 8px; } .paramkey { text-align: right; } .paramtype { white-space: nowrap; } .paramname { color: #602020; font-style: italic; white-space: nowrap; } /* End Styling for detailed member documentation */ /* for the tree view */ .ftvtree { font-family: sans-serif; margin:0.5em; } .directory { font-size: 9pt; font-weight: bold; } .directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } .directory > h3 { margin-top: 0; } .directory p { margin: 0px; white-space: nowrap; } .directory div { display: none; margin: 0px; } .directory img { vertical-align: -30%; } gxemul-0.6.1/doc/20060724-netbsd-netwinder-2_small.png000644 001750 001750 00000006604 13402411501 022212 0ustar00debugdebug000000 000000 PNG  IHDRtX*#XgAMA aPLTE   $ (((((((,(0000000400400400808888888<88@8@@@@@@@D@@D@@H@HHHHHHHLHHPHPPPPTPPTPXXXXXXXXXX\XX\X`````````````d``d``h`hhhhlhhlhhphppppppptpptppxpxxxxxxxxxx|xx|xxxxx]gMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDAThZoF.,$iH Fj60’(;Mv7wٻ9=I&dԋi]MꩧD#d요wg#o -Kǡ㌟(q2_ި'tNI7*:XbFЂ7"3Go^78ڂ_۸eAˬYοw?o -kX`Yc[c|}6[ /0z\utX  $ImpFmKu!A=bS5>5 "Xp"ش?k7e!RNoOj90-*b ȯJ uct'1NiNdGIs= bx/TyDh4!0 hGCѡ~ "QDž3+g5W'&?tft:Yb0 /]x:YtYhuHc e8RMcv\Wꭄau "޾R*W41fJWqmkCU^WwW'vK|GӨN%CFbi Aaw՝_+@ѡ`eUuVr]/muq0JGG#dtT4^O Q>$"Lp9~"OXLlI]ۃ>^?!!PIQ103ph@܄ 7c7̣z0' #Dq BơM~ԗd]a%ݶ9 /&QlĪ r=p^TؘWCbIS2uAn_}Q{Q40z $Ić^hX!Xфo5*( 1Pz ]1t=rD=IYGWsF$! 'cNcf>y輌T-L"ĤV,V5=zc&Y6 `.Cfc0zcOP[ugky]yZ?V5d.֛(;ץF%]<[joBm`PݥG]"sxR.g̨c eNG"FR/";N Gc8!0\2[xs_TqlF?jMҘ=G^X.nMod<ݥÁckC(DL Bo(t`n0|>7>`Lc`].,&̪-zU9Y l˴"ws{23PEP̞݃b 8ߦ;lgW~K˧<E4D&Ɍ`H\t}WoR){A!ܖ c@k?B5†R7bxɚϼyB醒l] ʮmrX@w;}>KYV|٘Cү #C*RH7" døn^ɆCOg֯|+X&.Qw1I"Iu֋Dz#z)]WN嗋'2]jF__Iqݚ`c =Ӹq6Tyx?zG4щv}ʌsVJ9e],d_i>2>OȴRGR.<*V$yyBe2WTp b"'=T3(B6nKi1C&$EY!f44xeIh$\uC 4S'w3')amx<0a^tD@襍n-Pb<Ƕ l8nU=<,R5מ-]N>ſnrü. 6]ZgtE76G[ͶmLF u^jKΣ˅9G^ޒU~sjE#)2c77U:o걒 /\Is{:D3J\Lgod %5aM%uo䰻lᗏO;XjNKCWW-p#?'KGǯh5AFji IK my(+AU5u~ExqêvypPe1(/_owh WkbZ#nťCM7>5+F򸴈xIhȦH*Ga L7NE"`,8R $(.NJx&#=@$&D$MɣXC mZmb 3 <ę̿m쮉k GjtU *oˣ'z kqYT=MNdVGdG ~c'{d`KEG_ݗQ%$8Iأپ$\\ftIME *R31IENDB`gxemul-0.6.1/doc/20180220-openbsd-luna88k-5.4.png000644 001750 001750 00000114136 13402411501 020627 0ustar00debugdebug000000 000000 PNG  IHDR Vs+gAMA a=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATxwU3ޛJBB &<*EAGDl` @)#R("tH@$nL9sfwv9ggg!B4*64frTSEhb!!h;g;bذFàFL׾hQW2qL-dFȭ}i;e ^nh5uߣO5aŋ !^;loGخ[oKG2uD).ѫz^,?X;:aۃ۹qK9Wp~&6g3קa{h <䗿d3ק;怩#[zW=2i[?s>m@񜖼@_bĘFn%QJ޼$o>kgߕskퟜJ #=]k,gOye |9.X@wߺpWgt~˙M<5tݓɊ'wݝ=;.7vLϊ3ea͗+ߚ8sk6_~eo7\xpu1/?WI8\?;W7ctK~lTе<:=?ۿ1 cm~he?}dMB/v۳?3aÄ[ȵzww}\THk{s3?|ֽ~vk0bSOxmn3kǯ^wQ;6;s›?W:m+_iljw3 䞜o/kijZ1 OBC $bIssuG|չs%e۳_ZY۟~oƓ ,6b-[WR4Ξkg[FW檷0?Ʈ~Fԭ%/so}4mOz:_ͷO#8鞭Wgt󩟿>vyoZ&_4ZGlG5 !y02m- ޾i6k2Yyѿ !v=賍?QaQhӿuжS:%otL[g>롃' !{Nc^ǟsߏýSg=;o g修;+Ww 玻O5S񋍏e[."'ͳ9dv{?z/Ǹ]R}˚ݯ{cas+yWS߮No_͛,m9Cךz } whm[Hן{[w{ʝ/.?7gn;7k߾+oBeOh 1{Co4}}_="m6r´wќUBJnln𣃑i?smf5`iϱ[ !?)D zzݷ%sk)M5Yw~3;>R}%K7<9w$o6{Q7_y|K^}gSb}}Å][MPx>ۇmW.-6c}GN =M'q|vgz&Y˟j_s=-Ohӧ8?\"~wӰ͏5գhB\|Lmw^=rGۍ_Z}^%;ػVǷ=lYN[gTԙ}$3c9376jB~c6mm?r75hdw+?8uIM摣 ]\nS̟_hxwCּ3n;rJ鏌ki'{e/ο~#/[#0mfc{п0 k]|M>}BϹuV2ضdim133~k +fqnZ+nV'ҋ5( /cӴ$b?z?WcJ^)X9|bOO}' v^w99~krs]^u_>'󆛗 L1rQ a=;gxЎv4f׍lξWnF_!3]!DC˔ᙁk-Yo@]FL{̯{V>s#&8w]g|׍MB$B_\_$?.MO^އBMO zcvs+]LxN?+k6XѹlVo&f9 krçX:W/zk 0~#Z{P0њBQOvj_fmnMc۶틷і'|ai~}VC+kۮC3 mb+8o]~UMfn-du/r_OuB{yDFFq}9wh=[{[Uk֝C,/2,iBtk4fL˄qC^n^s)v= ֽ<}s@[K-ދ>]UZK_zћs_<%ouBŢorEѽv⽮’75<J?43 ݸZ/ 4(ؔl4-ϔFmv0 L{:˶4.].a"^Xl/ׅ]WR(K]_S?^G5do//v_9kwmI欘Gu+YCFW./lɞ_-F#]_8{ڟ4룧8ɳUO)8}cf {/3^ߖ -3+.kNM?~T~`<ޫ'7e~8/[>vsŭagN>rf뮪?=)o;u>lvOuۘ6KKqNÇ]{'5Y6 <߽]Qm?ɡSlsr'z'JӤx3n<3~yMc|ҍ[[\~`tV#_4d|o砱<<&~(VuoyȝgB_eڦxu]kiS4oB+>2|5y:33{|nżVRpnB:zBy8߷=ki,:; B#N>/O?ֿ:B=}3 |>7dB1'hkw mٞ^{ᥗ3 m>͋BY˞[yg#wwo/? fWk1ͦQcmworǷ-c}#ẸukGBr}W7<뾸c^/n;9줖=Nouw(V~Ϳ[4گ}3b.xٓο%#݉~cֈ;iMr)u6zky2AQyipnkGrw?PCj~7|dL_:wWzդ /n䩋Z[JBOdFn* ?|6cfar h[Zn׭Ƙ-ï66OM?wVO66 IU&/dԅ=S:׿ǽa&;CލgyևGU>Э_<ƱfϮ[ o0+d}Uک"@}FD[= bhǙ}.c…@͛9s ,f !2c @<x 1c @<x 1c @<x 1c @<x 1c @<x 1c @<x 1c *+ IDAT@<x 1c @<x 1c @<x 1c @<x 1c @<x 1c @<x 1c @<x 1c @<x 1c @<x 1c @<x @e5PHiHʣLyI|דI[["*JlC ޳Jԛ4M,{SᘪHk+JJk-V?Q 5؄akv7R2wmwgV=!V6Zҋ}U}gJ ŽH_cI,i맺5ŗlk2nRlڨ@HaRuw*;΍ `i iu MK^L'gcB,Uu82suiH)z6t^ kj8qz].Tji[9V)y$ K*!'}$WaېSl1Ƶ\cLjt.A^g{!RQk55y=WRE#^KMww݊k]sS㢒zV^] =eҦ)1Qˣ^n6$'T+ j|vW}! ½Ԅ1@y|ߵ׏-е6VK{$]nYk8֣Gu/rXDZfq[Kc@1~Z~X%sXDZu!cPN@;GL`FU.^ϊTQ0}xrFx+6n}K'0jC)8Vy@gٶ/oP1Zs 8kOAq9qXW:(!c@^lm9FaNIɷ"ՕR)O-1^lm_#}9f's~VJEh@ -25^lmCg^^lm1Kl?j~BW{-qq5TOY7gSRsNf#FRb~T)2UjÈ#Sg*Ri2:Xz?;ɔmU׶zJg[yin }1sy8X#z\7n+I{EɴoCTVlVmzEsQH|U]Aqq5$n8dh԰p[ !|9DVC%GEyNR5r1s`GjٖC>OȺڋm޶@P\\ ՜̶R2kʣr[Wb6RzY{b[l QpiJ'α\]Ha_)-T34jTkWz~rJQĹXE'cYTtm.&~B G$qq=*O[]xzI[ynM2}chHJrkCr Y3!A4lu=$'pðWHCלz|}>1i|tiH.ղ *^\핍ϲBMo=-_$<17SSQ^^p@arWֲׇV%[lے\dМ͜L^y:7Q3xYh+[^R|Ň9CMߺRٯTEQyvqL==~p1 3زp{4Y=2I+Fb%[Z{/m;D='@.,גO;yR2+us?+U݈,o{9)O+%@}o+ܮic>ﵭXƶ?cTr<]- IDATIrc`̜5[7x+4ԳJT2㱳r\WWl5 ow}o+JO-[߰EMת|vǷ;;m?j|azo}oCRix|–mAq\|[sl[ճun+J>;8|?cE$ɹkTDg)rp,[|x*X볣m7mWם҅ 2mW *IΒ}R[ATUtE].TվUǨV&*&38rBϰUϵ'}׻fyOU [*TnhxT-Yq߫tHI@Bvǫ+&^)U!v=/W*ľ J.GXFokj?ZaĖ T j W@ep. i(҉c Rc c=F݊e%yy FQٸnb}zwxz|LO$ \\M8B05.lrK2mUrgz-麀 OIiÕJW{ =VRnO%ɱi/Z_ȗ)"V^ /.FXÛm[)4k<6˸1@<6C=zlXgiܸ 8T]N[S,k-_P_/¾,֛xCE$V+ .?ja8婥~߶+uֻX܁[Y➬+t$^iwxqriۭ᭼vE_{qwG"߲YASKFwp1$. ~[l[u;f]-K6'";:c%^z vV웝$o7]Գ\EC:o.b{iwpq5c @<;;:b%P+-Iʜ~۾2+֏mvk*ҟtalfNg'ⶓrŬ5S"Օp{I6^)ŐY~k&F#9u(T6N|)K9|Z=BrCecI'=E65cbQ>}-ܫU֪ Q]-yf[ 誐4à[w-sI&6Kk"e[Ȥ1MWj/=b=3 H{dH|gE-Fy@O^8_WY2bEBWSk^mUd6hU @L=F^30Y_oj'^7c-|N~gJY(AZ?蕽KX7?B٦[ C\qƭPL *C#O s%:ɐm6T=#Jx\ŐVϮ3 Hc97 8hg-FMo6ǝ"آދt-#Eg"5_<*ꄾTec:TUk9gc?Q@VcHNI6v׺JȾMdjPtטd2Lؖg'o #{6_sHZvAcJlj\S!Rj,_k%ٷ~ w%_-WC)- Od]2dRg׆˹*)kK}RYx D> ^gJyŒ(Pzoʷ<kQg׽vw YhC;J')'d"C.)NER|?L8!쇵qT܋;[3Ac rȬ44'H{ZIJZ?P ݟiK#Gi @gو^wsN~Gf^G Z>} fR]?Q({IiW ~ ]{Q~`[kߋ*YpSbZ 栧 Z9HRiT.v9ץW=+73@޷տS9".FU`ԷK4I^hOe:̀R>fkg:tgYK[h,^Ÿdc&9؏n1}NR-}w+wX}S1(ۊ?%?Q'Y$1KXK^~}[),Gi .O]7\T~^˱@pqu= .+_gyWEI]'ipqJμ裑|?0U{y#=a*:|q@@ෆ?_֙#yʴd*{H3x (^s2+I%yG/_xvLÅ1mwnLoyT^o w TT\2 o?!}&C숮L7L?LrvNsUs^9޳7b9[)e:@3ۡ:-gV.R>z[z6u,"=qZǟ 9M~izj3@1z$Vy2Uָcj #QUo0pq!> c@YBjRzB0l93uSR۟^һ;nzyQY^8_WY2& װTJn\#| bx\yJP} $(-_˷UC^u˙<4k X2@<(un| plO:|?mj)N9mvLj7) ˽Ki+d&̪kw 1\\]!9)Bi/Q}{+{q Iw2gj!Z-u?ˣɼ-z9PEw z]OyF(2]RuZgAV,<:7$׮6ǨGe1 :pͩG^u G"G,a|T.x 1\$93Ssi!F`)|6o2-֏@~lH"w8[7-/#%E?վgc@<*sJՏZ'j4s `1kܪI!|?5Z[@<H>U1-Kkl\@05F68>G>xⵤu%7%%8dshIʣަnKMtYr9E^ɾ]7BJx gcy-S_[PYP@y.[^s9I^Q/OLhKzr,߯rUX^Rg&pRgr3DsZ-%&_z{7t}žjWCx8Ӌ2iFKR'%KəkKRgRLbn`94U' \л\Y i~QbyK. yy2Ϟ _Fl/$:Tl/[RxL?W@7hPRydד zbwK[=k8|cm;c{U,pHc[1Q[(v\[hu,-bGO k%#yŷM % Zwja}ku4EquG=9$?R&U[]GC C* T}d x\ČmKȱcU~xo@K6?埾lt]5.99.> D:A7S fr}dޔ8^d^vcKd *4Rr>Ɠ'>:0GI٧R&]ٯrn..?ܦzS{;VU$mcEۆ{^uQ*[Le9}u ,K6lxb t=q8f<*򝒐#nd6+}pm_eǐ3҆rk.&x K+덍匇묺ZMIf8 x 1+߱p"e $x*hY4\լ۵1߬AYcxn߰vR`.n,zLfm\)MYM· "njy#=dGjO8cgy O@POeTGۀw, f$aZ9cc픢;)qs>/@11Ȣ '%ƑU/iH}'p&W=$O|u0\ a c?߳O> SM_ b\]0ypIǬd =AgT>ʊ/.js^kAXkmxMH90+<{,!Gnq03{yT;%!GȢmW~nھ\5 !g 1H9\LLV5iYug(p6@<c Vc ",EH =U^IhY_yki3cYw|n!1(S_ݠaD]X6>,3\RH Sn{`9o#VEܜF?z>fy6)j0);|jԞpB/[F9I =xhMߗIhL)n7~t[4Fxקn=mLQ o`\(F*';Ťy82|vȫXI<fs )E%w='O948w{SxQ#{}ڽ_bc.E/OJ#G7_HɑO:L{H`Y'9g~K}@<we»h`xreOZ}WᒴYozyG+>|No1_\.缚ս,1ڰr-`V6yXB`fj5wJBTEµ}*kCH>bcȑr1_/./,jʯ763⯳.j5%1j3Q$l&Wx 1|EX52z 1)fp&W:^of|fBdcQç¿»A7I%l|Yg0rA6.6rf5 s 2F*:94"|> 9mR`LmSVw=ᜏ[m_+>r{ /qИSfo0;#iV9#w+O;>{:$f7>j? s\ͣ<߬ QLǝUN<?7fw;7)I5Hyqd@9 3?JSWmޱ,7y8h*@SJz Nrhp6#F&{-{ X\"^0$GnV9U IDATԧ#1 u\}xL5~'wsvŇ6e˞ۡ %i .56W}Pb*+]y5{aYba5#[l채<6kQyv#9\k*.sU08ϟ6|Ɛ#\s19c^0]ė_ZYԔ_ol/g<_g]jJbՆg4H Lc)X%4)k 7dcVyCS$͢ Lfu|^߮df ͺ ãO wnJuqcԳ`r5Km#l\Lmj @<eTXups&WiD||&rۤ =R{9{o? ۮϿ Vxo}$%t1A4 _&1)`vmGӬrFVl]w}طuHnko}~2G-xlY-ns;x6~nHw4nRjr@cYn0c' pКU΁;k0?l&WGMEL[i~A>D`H>)1ݬr~O#%Gc<0!yîjpsdH_}-jܕO  ɋmʮ=廷Ck\K@~zo]4IJcFh<MBcRNq#jħYܭ6»>tto5 y>N*LōeS"8, q1嶷 3)[1RaY͙\-olgocj{p8̧H |,:o>2Xi#nj$x}?Ƥ6{GLO[mw}c!y0Vipjfmbd:r1k#ѸIQLGʋ#lWhe$AkV9r`RTrcpC\}G?7%52{n9ק(@<Y!8rt>d껇9̑u#al|{c pW>\, &/>')^gp.IuǞWݾ"SYErΫym_;c ))fe0g%h-aYc/ʻ|$HY4o-\Wq⽆1x#6)皋 "ʢzcx9!-:VS6<Ebfr5 xLw,\HY ! "iW`r5C:ov-m&{7no-D6<|j +t|7T2ƧEpYj)dbmo,gVS1-cª3ZH#G3,ϐ&E p2xoJ/jdr~O 1P x%CIqfK})9R\wv Ws#$GoT}Xx7mL^|OnSv)߽Z*\61"YmC=}(E-⋋Wھw%Z6^S*gnŶi|ۧ{}[ƾ֧[`.yԂ6W8鸳ʉgƬtG&E1F)/ (c槲]i*m;3v0YȱvJQ] S fr}dޔ8^d^vcKd *4Rr>Ɠ'>:0GI٧R&]ٯrn..?ܦzS{;VU$mcEۆ{^uQ*[Le9}u ,K6lxb t=q8f<*򝒐#nd6+}pm_eǐ3҆rk.&x K+덍匇묺ZMIf8 x 1+߱p"e $x*hY4\լ۵1߬AYcxn߰vR`.n,zLfm\)MYM· "njy#=dGjO8cgy O@POeTGۀw, f$aZ9cc픢;)qs>/@11Ȣ '%ƑU/iH}'p&W=$O|u0\ a c?߳O> SM_ b\]0ypIǬd =AgT>ʊ/.js^kAXkmxMH90+<{,!Gnq03{yT;%!GȢmW~nھ\5 !g 1H9\LLV5iYug(p6@<c Vc ",EH =U^IhY_yki3cYw|n!1(S_ݠaD]X6>,3\RH Sn{`9o#VEܜF?z>fy6)j0);|jԞpB/[F9I =xhMߗIhL)n7~t[4Fxקn=mLQ o`\(F*';Ťy82|vȫXI<fs )E%w='O948w{SxQ#{}ڽ_bc.E/OJ#G7_HɑO:L{H`Y'9g~K}@<we»h`xreOZ}WᒴYozyG+>|No1_\.缚ս,1ڰr-`V6yXB`fj5wJBTEµ}*kCH>bcȑr1_/./,jʯ763⯳.j5%1j3Q$l&Wx 1|EX52z 1)fp&W:^of|fBdcQç¿»A7I%l|Yg0rA6.6rf5 s 2F*:94"|> 9mR`LmSVw=ᜏ[m_+>r{ /qИSfo0;#iV9#w+O;>{:$f7>j? s\ͣ<߬ QLǝUN<?7fw;7)I5Hyqd@9 3?JSWmޱ,7y8h*@SJz Nrhp6#F&{-{ X\"^0$GnV9ԧ#1 u\}xL5~'wsvŇ6e˞ۡ %i .56W}Pb*+]y5{aYba5#[l채<6kQyv#9\k*.sU08ϟ6|Ɛ#\s19c^0]ė_ZYԔ_ol/g<_g]jJbՆg4H Lc)X%4)k 7dcVyCS$͢ Lfu|^߮df ͺ ãO wnJuqcԳ`r5Km#l\Lmj @<eTXups&WiD||&rۤ =R{9{o? ۮϿ Vxo}$%t1A4 _&1)`vmGӬrFVl]w}طuHnko}~2G-xlY-ns;x6~nHw4nRjr@cYn0c' pКU΁;k0?l&WGMEL[i~A>D`H>)1ݬr~O#%Gc<0!yîjpsdH_}-jܕO  ɋmʮ=廷Ck\K@~zo]4IJcFh<MBcRNq#jħYܭ6»>ttoyG;޹۾H}I 4*8H9'^ޕIɍ}m/$fr}s#Ÿx`j$B\:^z׈o7Dʙrվ}c[{ڿfb[R0ƃ]ߧɝ !nyϳ͟H}f58{_ڔl)W:Nx/2FSsH[?m4Z J5>| V5^XU/O3X*kWN󧸜᷂ tIʟ6{ײn]$Wb"-{wgnj}ﷸYi|0!815=b|ײ._.MqcoQP{mJvhv}/d'6i|Zr?T x̣i!'c<4ޯ{`G&fb7_vl/#sl_1&Wx 1 x  _w佾|]n>|oaf^s_ۆS{} Ǹ*AA?΁ӳOrg) }]mp㞙P֧SXׂAq6Gɴ^>gdGgd)ǮCxl7RYE5 |UЧk,ǷvyʟۻMƱ ƾzmh(> Κ~gBN`ٶjܸs>f,ԭOҕ+鸤>c.䧵+6'ն8Y3')p_g C)}d#'cŢ>c(jḽ-^YFkVHĆ:V9w>=O臊|L,}Oso|1i$jڰw1z K-kS) aJ;:IDAT>|xq\v_)pek/u5:;Qj/O?x%^vdclt4oe,={/ӧCSwGNS@aF1n3bpb4^[\ 51_ֶW1ӼGrES#lƯ*yzx<8&]!~nױ<ѱ-8"崏1~r89rDgJc~r0oKۦXߏ'~W9f>eJtqtukϨY{uҍayW"6n,vtFϱv>p ugJ~g ]}Fm9n9KF٤E]{  ͏dk<w?{{57x9qaiBvY5>գz iLr^pK = Mwʿr<:x50!yXxVE*h/~yR Vnx~t+?[{_:i,3=߯U0c̺>w #E/n~|V}m?#p>>Y;mlljv!b)&ٝ?G>ƝOclܲv~ؿ?'1z|;[㷟C/5[MqȾF.߭-2/6/.xM<?όMvas>tΗ>Db:vKM)Fm|s|̱ O==o-qMM\T|ܼ91R4`3FG{nxvxrl0*^Nc2z}1cg^(ymg]B9cу/EܛMnKzj15աuLŷW&9|:{K!t֯OytڻEu1^QůXܹ `~dž}&-<{|`bQn sZSkۺݶ/>wfۥx;eٮs~ dz`}"ڹVk :vzh{[[h{lS׮lY&=pD"IV s㈌hEBN Gm6]93]KO3L[W!]l/ze|ݪ_e1I-O.1C&sr{ub^\9 .^x s@R{Jp{OT@ZG_ sݫe!3y QSމ>K/>_0_IuJ+xug+/tuN?Voyuಋ.VX?jÕ]v#aԛ:;&W~W[)q{Pb}tDzys?s~G'^rp=oBNl_K9-^]-bbk,5=3xbynˊkgoe|d< V}o9k?~x̉W~rd@c }ihf|?x;fg®Cz?C;a>j¼>} ц `B @<\ m6p/!c@<c@<c@<c@<c5 x 1x<x^>vּ<÷s>R61Nϔ^\ 1/[._im\,S{W:b}*'ʮvoo^❔6R ؑslyxwZH._O#8R&NFC6k:5:lDmwWsC\=K[|͚\%_yj)]C|il{>Rx 2/X> r&W^6 ӓO~;4uN.V35eb$?͊HN;O`kqǬ93,>>Zf{qQ^Ԕ:7Jk\׎k־ [Z+vntKQ;c1&)@dgi E{>k92բp6[n?6whb"E80v"#Hs6txw\m|cc'?֭Wr?`5"K<ԑ5`W_3~~n?S[͸Ƈpcr /j;_ʜz}ϥmTqmNZ.Lu^g_<+~`շcx}On/@iFbbmLdK٫u9>]ypec.dF9;=3ޥOwD`.-Εy(=C{̛ɦ|(`9.{>kӋlB\CGF_cV_(6 47䬜 :koكg-!7k,O޴>RƵH(#ukԞeM=eУG:g"uMo$!:7n:,H8}90?0u9yDr)ЎIo(G䍗::q sʵ{>zͺ:_毶A6 3?EWё>b.~9 ܊dWRx{ {?"ow*Uwf:V5w{DrcnK vMm<9xr[M1aΚ[ k%}u}*_ͳnj^=!ٸϟW N MU7>=/S^S bJi:)}Z|(H66c>|;<J1'wnoemڶF/ֶ9on_t87i5;EkOC097'#;8|fɍ6c?O6NjX5j͠)hgl ǰȔIHN Q\x92,Ʈ}ukb*j.f5=Aʧx_v'6&E}@6)\N\hJHx}/?)gt?ߞk ym&WċYAPXVq`b-cg'JvR_hz/>=pڧ:+zO- SjӃʹ3z }Kh .];;0z ?ix A| x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 x 1 gKj1}Cp/>x<ǿSp[ 蜖4KtIMEIENDB`gxemul-0.6.1/doc/debian-11.png000644 001750 001750 00000012506 13402411501 016144 0ustar00debugdebug000000 000000 PNG  IHDR WgAMA aPLTE^ffU-*(8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).IIDATxݿbHᩬR\&ilO9'w6 FI(z^?A߶}2hu4Sijͫv%}^fOa7b0hV:4LYc^[ 4K(޿`lqm ͼT`2 " !1xǼRhԻfJⲽ}emz(+ܥՅ]|؎qYvy y(>Q u A7 ZHvB{]wB ||gڏ'Aq>?p=Jw/ ^~MO ~8gpezDeig@ߟלn7˅4l쮧dOݓgwjnZ x92د'%>uAZ`iu0~i^0vpĠ_o8 _f|\fgޭ"ӟt9{!\~M/ 1Ozv/a 0@a 0@`` 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0`a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a `@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a`0@a 0@a 0@a 0@a 0@a 0@2j\L5׉ql\yk:m_plN1XҌwjk %8O&71؜ z]oޤ%D:9NיR>YGBuB֌Og߂:?ͻb nOx:۝^h$oǖP+r?Azg&=;iI.gf:_u(_2HfXI]u4J:.+$1˕_T n/T ~u?Kf̯;<< G+u\ +¦YhNo+ _[ȨtY1x7pOpޛ bM`>a9<ߖ'c4o"a` 0@a 0@keS4kV oY.r1c7 e?A8ߍĂ{J&aqxJêt4ctݪyV{l\G1- X !槐yX ǫn _Xe3s"1H&;`Q0_v ˓E)(SN _dP$WCߒA5ƅ3}ұcT#L8݇КϤ sH?ݺO9 ϟ]ï<.>T?t1N!}{qW??y,,r=lok3XMfx!6>Aa̬~S*ϟ]ïnݨ('xmlqJxҸC1]wabi0uoo龙^ctX /`Ee1`4%ޮx|r9Z~vBq&c41gp&rXO72ȫ,?A7ŠLeOkA]Oܮ쭿%:c1ʥA]̱Lܟ3eܺnk{RA]T03tO{3 Nb9|)y!"IvMO8 uOz24nWzj`X/f 4lqt hdwvZ)hRP,A5k[-aWu5<*vMRːW+8x!!_x+!wO@I rbifwwfUG m> i ,>ű}&o_yGi5Dr o7yI[ *ƕ[ק 6ux~wͣߺB1Mqo.{"?+o}nc;bG*Bm.nFO@m9 S bL`ponZݦ7!%phy4DL1wa}|v׽A\.bvq y; cp> vˈ~7`=,*7='L0u1}ф 6pAиAO71ڝ_bpz _9Adp> }߇:Ơ3?w4}z+b;=Z=xb+jOt}&eG U3-15rxf_4FiURwaznno~%_ ym 2_Fx^YܴΞe_M㱅Q }qnt3?N#{O_]ks^72?}x5K>1'ny EhNb'm>a<m{# /zh{xݠߏ` =9`0{,Ѵ7^)wUzzymc$ŇrЏ Mq&0x7<:૎1-` 0@a 0@ap]Q`33Vo0xj6צ e_$geg A GXemul: Introduction

GXemul: Introduction

Back to the index.


NetBSD/pmax 1.6.2 with X11
running in GXemul


Overview:

GXemul is a framework for full-system computer architecture emulation. Several processor architectures and machine types have been implemented. It is working well enough to allow unmodified "guest" operating systems to run inside the emulator, as if they were running on real hardware.

The emulator emulates (networks of) real machines. The machines may consist of ARM, MIPS, Motorola 88K, PowerPC, and SuperH processors, and various surrounding hardware components such as framebuffers, busses, interrupt controllers, ethernet controllers, disk controllers, and serial port controllers.

GXemul, including the dynamic translation system, is implemented in portable C++ (although most parts are still legacy C-style code), which means that the emulator will run on practically any 64-bit or 32-bit Unix-like systems, with few or no modifications.

Devices and processors are not simulated with 100% accuracy. They are only "faked" well enough to allow guest operating systems to run without complaining too much. Still, the emulator could be of interest for academic research and experiments, such as when learning how to write operating system code.

The emulator contains code which tries to emulate the workings of CPUs and surrounding hardware found in real machines, but it does not contain any ROM code. You will need some form of program (in binary form) to run in the emulator. For most emulation modes, PROM calls are handled by the emulator itself, so you do not need to use any ROM image at all.

You can use pre-compiled kernels (for example NetBSD kernels, or Linux), or other programs that are in binary format, and in some cases even actual ROM images. A couple of different file formats are supported: ELF, a.out, COFF/ECOFF, SREC, and raw binaries.

If you do not have a kernel as a separate file, but you have a bootable disk image, then it is sometimes possible to boot directly from that image. This works for example with DECstation emulation, Dreamcast emulation, or when booting from generic ISO9660 CDROM images if the kernel is included in the image as a plain file.

Thanks to (in no specific order) Joachim Buss, Olivier Houchard, Juli Mallett, Juan Romero Pardines, Carl van Schaik, Miod Vallat, Alec Voropay, Göran Weinholt, Alexander Yurchenko, and everyone else who has provided feedback on previous releases.


New vs Old framework:

Starting with GXemul 0.6.0, a new emulation framework designed from scratch is included. So far, only very few emulation modes have been rewritten to use this new framework; almost all emulation modes use the old (legacy) framework, which was developed in a more ad-hoc manner. The long-term goal is to rewrite everything to use the new framework.

The documentation still largely refers to how things worked in the old framework.

The new framework is described here.


Is GXemul Free software?

Yes. the GXemul source code is released under a Free license. The code in GXemul is Copyrighted software, it is not public domain. (If this is confusing to you, you might want to read up on the definitions of the four freedoms associated with Free software, http://www.gnu.org/philosophy/free-sw.html.)

The main part of the code is released under a 3-clause BSD-style license (or "revised BSD-style" if one wants to use GNU jargon). Apart from the main code, some files are copied from other sources such as NetBSD, for example header files containing symbolic names of bitfields in device registers. They are also covered by similar licenses, but with some additional clauses. The main point, however, is that the licenses require that the original Copyright and license terms are included when you distribute a copy, modified or not, even if it is in binary form.

If you plan to redistribute GXemul without supplying the source code, then you need to comply with each individual source file some other way, for example by writing additional documentation containing Copyright notes. This has not been done in the official GXemul distribution, since it is in source code form and already includes the Copyright messages. You need to check all individual files for details. The "easiest way out" if you plan to redistribute code from GXemul is, of course, to let it remain Free Software and simply include the source code.


How to compile/build the emulator:

Uncompress the .tar.gz distribution file, and run
	$ ./configure
	$ make

This should work on most Unix-like systems, with few or no modifications to the source code. Requirements are:

  • A reasonably modern C++ compiler environment, including STL.

See this section for more details.

GXemul does not require any additional third-party libraries to build. However, the following optional libraries or third-party software give additional functionality:

  • X11 headers and libraries: for legacy mode framebuffer emulation.
  • Doxygen: if installed, source code documentation will be generated when documentation is built.

The emulator's performance is dependent on both runtime settings and on compiler settings, so you might want to experiment with using different CXX, CXXFLAGS, and LDFLAGS environment variable values when running the configure script.

During development of the emulator: configure --debug may be used to enable some debugging aids and turn off optimizations. make test can be used to run unit tests. If you often recompile the whole tree (make clean_all, followed by configure and make again), then using ccache is recommended.

Running make install will install GXemul into /usr/local, or wherever the configure script detects that user software is installed on your system (may be overridden by setting the PREFIX environment variable before running configure).


How to run the emulator:

Once you have built GXemul, running it should be rather straight-forward. Running gxemul without arguments (or with the -h or -H command line options) will display a help message.

Running gxemul -V will start GXemul in an "empty state" in the interactive debugger. You may then type help to see a list of available commands.

To get some ideas about what is possible to run in the emulator, please read the section about installing "guest" operating systems. The most straight forward guest operating system to install is NetBSD/pmax; the instructions provided here should let you install NetBSD/pmax in a way very similar to how it is done on a real DECstation.

If you are interested in using the emulator to develop code on your own, then you should also read the section about Hello World.

To exit the emulator, type CTRL-C to show the single-step debugger prompt (if it is not already displayed), and then type quit.

If you are starting an emulation by entering settings directly on the command line, and you are not using the -x option, then all terminal input and output will go to the main controlling terminal. CTRL-C is used to break into the debugger, so in order to send CTRL-C to the running (emulated) program, you may use CTRL-B. (This should be a reasonable compromise to allow the emulator to be usable even on systems without X Windows.)

There is no way to send an actual CTRL-B to the emulated program, when typing in the main controlling terminal window. The solution is to either use configuration files, or use -x. Both these solutions cause new xterms to be opened for each emulated serial port that is written to. CTRL-B and CTRL-C both have their original meaning in those xterm windows.


Which processor architectures does GXemul emulate?

The architectures that are emulated well enough to let at least one guest operating system run (per architecture) are ARM, MIPS, Motorola 88K, PowerPC, and SuperH.

Please read the sections about emulation modes and guest operating systems for more information about the machines and operating systems, respectively, that can be considered "working" in the emulator.

(There is some code in GXemul for emulation of other architectures, but they are not stable or complete enough to be listed among the "working" architectures.)


Which host architectures/platforms are supported?

The goal is that GXemul should compile and run, with few or no modifications, on most modern host architectures (64-bit or 32-bit word-length) on most modern Unix-like operating systems, as long as there is a modern C++ compiler available.

In practice, the ability to reach this goal is limited by the amount of spare time available for development. Most of the development is done on FreeBSD/amd64 using clang and/or GNU C++, but every now and then the code is built on Linux, or NetBSD/OpenBSD inside GXemul itself.

Note 1: The dynamic translation engine does not require backends for native code generation to be written for each individual host architecture; the intermediate representation that the dyntrans system uses can be executed on any host architecture.

Note 2: Although GXemul may build and run on non-Unix-like platforms, such as Cygwin inside Windows, Unix-like systems are the primary platform. Some functionality may be lost when running on Cygwin.


Emulation accuracy:

GXemul is an instruction-level emulator; things that would happen in several steps within a real CPU are not taken into account (e.g. pipe-line stalls or out-of-order execution). Still, instruction-level accuracy seems to be enough to be able to run complete guest operating systems inside the emulator.

The existance of instruction and data caches is "faked" to let operating systems think that they are there, but for all practical purposes, these caches are non-working.

The emulator is in general not timing-accurate, neither at the instruction level nor on any higher level. An attempt is made to let emulated clocks run at the same speed as the host (i.e. an emulated timer running at 100 Hz will interrupt around 100 times per real second), but since the host speed may vary, e.g. because of other running processes, there is no guarantee as to how many instructions will be executed in each of these 100 Hz cycles.

If the host is very slow, the emulated clocks might even lag behind the real-world clock.


Which machines does GXemul emulate?

A few different machine types are emulated. The criteria used to include a machine in these lists is:
  • For real machines: That the machine emulation is complete enough to run at least one unmodified "guest OS".
  • For GXemul's test* machines: That the experimental devices for test machines work according to the documentation.

Machines emulated using the new framework:

    MIPS
    • testmips (partial support for experimental devices)

  • Motorola 88K
    • testm88k (partial support for experimental devices)

Machines emulated using the legacy framework:

(*1) = Linux/Malta sometimes works as a guest OS, but running Linux/Malta in GXemul is much more experimental/unknown than NetBSD, so it is still on the "unsupported" page.
(*2) = The emulation is enough for root-on-nfs, but no disk controller (SCSI nor IDE) is emulated yet for this machine type.

There may be code in GXemul for emulation of some other machine types; the degree to which these work range from almost being able to run a complete OS, to almost completely unsupported, perhaps just enough support to output a few boot messages via serial console. (See the end of this section on the Guest OSes page for some examples, but remember that these do not necessarily work.)

In addition to emulating real machines, there are also the test machines. A test machine consists of one or more CPUs and a few experimental devices such as:

  • a console I/O device (putchar() and getchar()...)
  • an inter-processor communication device, for SMP experiments
  • a very simple linear framebuffer device (for graphics output)
  • a simple disk controller
  • a simple ethernet controller
  • a simple interrupt controller
  • a real-time clock device

This mode is useful if you wish to run experimental code, but do not wish to target any specific real-world machine type, for example for educational purposes.

You can read more about these experimental devices here. gxemul-0.6.1/doc/20061029-netbsd-dreamcast_small.png000644 001750 001750 00000010133 13402411501 022006 0ustar00debugdebug000000 000000 PNG  IHDRt[ gAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDAThY]py=`A`A))Д(6$?&;Ό;Lg:yCO}K>tt<$r,Ʃ\"M$ȥHK.@HKv[$w=߹;^kFVTDz܇ep0|ApFOYH-*h ϪIXWy N\WcTJ]wdszF˖Gh4Yg4dhхM x^5_Fi +&N%ت u+[uUg&:f $)hv(=1H#(=Ud8.ӢMi|Αw7ÈIcmriuz*0͗+1H`(Y{"SM jݎ'N3쟤a_y_Icg;cq " t,?琒T:)aڵvqJ޳0qÊ$֣slh 7p!>C u *^+MȨ[I`5HQ}F.1A#=zu+vkH^Hlѡa+E:fqG/wP»PS1 w^ЇI&9K8h[|;ܱL?8y: }g!7?zC.e6ua/:H~ TWL (fdSV4!5̭yn[zoxԵƜ|͛X$BVf!D3ݚrAXT)y%+=[zQ|{i~ O7o0=#l/u4eux65Y VKc!ZLu4r ToঙQAQ7/!hkڃ}Wa[q S].H?<ǦnTs1] ttxj |OWHæb1T4vsAX mu.'vb.љ :]zT^ê$~E$.aD=,CtJ;V_*\t0ET"PWs*bM)aWByX$$*YfM ˯ TñO7lQE/̧dߚ-%BV=$x}oמ\]~Ϗ-.mM!"xlyu_H:[ip4;R ?yn hN2v,4}Wun4#N`~V3LXjU$ ADQu?Y%v] 9FqOϻlP~Tt[[%e.ǭy ?C&v.?yNGOf͏'} + ذ}Fpj!LwfGwuċR+aV;=G^xH Uog3==B:c>uUv#X )~ = ~{Jߞ~_5;РAbw}is'+02@~sO K1=HO%\coĶC:`q m-猽12lyjSymߺ(Դ29 <fw D_)WC:ʬuˆ45G+۶UގX r&֍(i@ S1* RQG65qo9@7wkW'W M2Cޯ&T㗎xe:c[i8:ůqL;2)%K_@탡 ڕ/ 5Jx嗍+YRl`^y:)l50\-JKW?^]},( xR;.Rkqx {K (TnK[sL^{M;f_ {mA61Кp=쾺8軣 "xc7oاJm^:ě#%uS9*<ܵu}P-%=V ŁԻpgvka]hkfґM^>)xG~f\.]_J[AdỌ@ir>NJm'R{S#?](E\}&AzڼhgexYm5ن4DsĺKewJz~S{)+bB|Lwׇ-!KGj3v#u) 1k^'V|*#1P%yR!6<) ;jT|U9^c%Ef[Kʨv,cKڰc8hSTxl.J`uJ ) U-ykZ*>n;'yFZY-Eqex @*Bl$, Ř b'7_3n#^)j_Hz|l;/DJ<_=$74_y]!3V6x[Jȁ5FSmTƒбjت]T-[b6WU!1R P08 v~/tfEv$d}u8N\Is]k]:=#iN-DڵߵQ|.J#8RI5Y72[Uy a3saU0F J fpXn9nAȧ.NkKL.{c1R];1;r9kb/>„dŗ˹?MM ZNkVɡ葲-mY}"(pMW\qH:4MŒkzsz2׀rwj'P$_Σ_-t륻"ib;AL0 u9u"wjxLg7yUEx,]ׂT j]|`ҹUMy.`WJr=Jgx:ݩ&rgNH\ڼ WcZm/J J}Iz*u{aKa=QtIME 9\IENDB`gxemul-0.6.1/doc/20140803-dreamcast-gltest.png000644 001750 001750 00000315507 13402411501 020654 0ustar00debugdebug000000 000000 PNG  IHDR/sBIT|dtEXtSoftwaregnome-screenshot> IDATx{Ṳ29T& E2@!4QE4ܔ]QYEaWu_vw]%p Eh"t&'35='=5?NM~L~xޯ׼`N|9y2lWַ}bX,by\}AWf\puo=J?,bX,Yi͌00"t5A&(bX,>PqTLF+B-bX,"LF~ս`,bX, LfS2`g+C7vfSiq+3SbX,k$՞@= nAe<?;-J%Yo>50gQ~b=TfhӌW5uWQQғ$QkˁJZLSzoLix6gr.ǙXO莕esN4<50e*S;e:է6{ѡ21 d653e 矠a-Ns ޡǓmr:Jȃߏgb XrU{ld(za$vBk;c΢nFc*֢i2gr -g1evn1vݖsٗ1*k^g CYSh> !;z7i{"4I2}7L^|Mx yʴl4M̬#X"CiٕLӼ˹2Gp_Sf2}vlIuD1̷?n9l֜q{@}gtËRS7{]dSspqIfF`TV~|nZ>nbtB{n&s=yj{Cke:(:zp7G6н:#χ޺Y¬P(Ϯ?}dsC饍 xs_Fn4~"]+ /rPtϛɆxkW>VvĒ}}ˡ72}*]eMy=c:Ζvc1˚˾$'1|txmygYC5I8g rG@6kH;'c?u<&l:VfldkY Y!xj:CpfK1qS|#g3_gI$şL{]}{oS?\+nbtOOA0z]76* 8u.G^dlz~/h"N=,c6ݽZ^yjIdm???aF[+߹zYIEgVgڼC^;МgF?&/}MfN\q}/;O0uZ*IuI)32e܆fLN9j&V^0j NK+raLj~[>w-ړhҘaFE}ə<:8}[c3gQ7K.jް`WL6ç}37(7KmS8{Й{ICeZ=\`\b㚁v϶c OOu&O1d|uA y \͛b{[N*L&13N:}d>Q~G&Ӵ{(Ռ'sto[W g-m3hI)= 0q#/H6UdpgLiǮVZ4^NcmZygĽ>KN==~(?yN=N:oz!DG%N?}[<\t-~J)/daY.Ϯ`9}2'OI4 ܙѺ繻ئuH_`vu,5㻟89~ .&*Ms 1m&w>{{r`v;\rō9`v;A{=sB4d/H76Ep=d2sOzy,4/;go+̔.']rg~#co^H^G r#q/5w4k}''LE=];yʦ1pg)w{M#5|c,;IN"yއK.YMc};ފU'w,Km| \>v>=Ϳ{bϨ~z*>|b Ρ:vzm[}gٝ$%K_wXzmY?"23evt[嶭|^n{=0ݸe7D(w/;K&iy,깻h)@Ӥff[7/cA}tLӥ2~{άPxbӶZ#LA~8UyvN8rՑg7g"Sl3^@֙D>"T&|SN;zt팶- ۏ_Re|K8(ʆ5[a|>o`N;;;|g|nȠ?|O}k-)ȱߞFnY?ˎ'^֩(ՑuPGYZguǔsiB&a2&i{y20ZEgtꗸޭss7?H> {zJ?c2Ց2;׬oڷLSZ\-䆻x۟ʨzq7 F9t8ӽO\?=>> V=9R~w3/} W6w$:ޣcoX89_>{znk]ki=$wvFe}Dep-p&9MǩlyZۮ L}K,}N{\:|1/OMt6ʆ_wyis },y<]*7^TfA{'k߾ <:\z VG>SYm+WԑGy(eBxXu~db^SׁzC҃x~BS5~gBwG<: lǟ[}Oe'6KuG䶇8hri9Gǟo{A ]jIt~}/񮏏5RIy$7>/ lЋ򁷥_?@`Fhxj:߽^m1|[4W_9mknE6GWS?C>XS3^χN>}x\dw=ƜN6mӿ'U>0@˴ұܷ,G}3{7sr #/m>>vke90'l&<5%W#OEWǨvTMɛdD-X;]w2qc{7`&A6V獅|'L&ç} oWi?df*tLw5e&- p,~ :1j:GuTYcQE*˿[ѭ^+oaSm8F3ϥ~{f2{ü%{;4axr Ri'pҢC 9cMky]?ou5ƪU)?\|0q͓p4Nۜ &=[8>ͭ?A>d7~r'sYza\h`eOOhksUo:*oəLRՍo0`jO0oМ)ɦϮӧPnۛ{rd!fxd 'Ǟ;>.9 \3L6$zpdiӨf'v0r}Cx9lY>֮ffG:D͗9^]zymy,$?35w>5=N{HFh̷p񥏼u"a&5SXa%58;i2d& m)v=)VrZ\~am2k墳M4_Õ8#%7u<n]Dc.ms:fn8gwMqvܲ)*Lj zͬ75QONLnv`'Jel4;*₽gTGQ?-?=^yYL&Om?r x}oY*wĞZ9mXgߜmktbo^72>ۣ<ѝ.g2}MLfC`C}'<8@EWĝp?/gc1m>]+K۬MOsN9r$6Yo{7^}'5!n?lTӎ8OϿ/? .Je_ YpZϗz]s+Vj:_[)ه.8?0K>_>H8+1Gv;suo/ =sjXvґXǷ?;k'Vij2]wn⧷?gG=^}?cCk؃a?_8^?rޔ@S3JYop;: <qҢ%#*4py~džQ.|OF0|vū9>ْx=OS{ .>23OϡWj^GLGw!N˾}AyϞ7ěߨ䊛`a00.&µySK{4#3^Ds6$4;jۜN6 -Ljq:kmV0dt u/9Gpq9 fM<%XM[7KA7gqv>/}#l| ?Ynz[Vz96 jZ;eZ0{O|3k,CN2_6{ż!w?ʹM^ ~:ՏOo^'T@N䢫OY/v1v..C'7>ȏWf2)/$3r(˝߼o K_wnx%{2qDFo^cFo//6kegȕp=gs'0|+;gQѦjޙ<9on:c+w/ȠƃO{7>H!ȩ.zT?'=?},-CNo4Ir0u|}KOdzp˞w9>tǃp_isO'6 sG4bϡgb~oe_"N!=pѷnM೴|`}L' c&ӊx Ll&ǡi$&MLSm&ٳUBLVc*LLv:906<8^Syq qPSZbAGH(2NÝ1SM%nZud#Z/akixJT+CԩBk;cV%лJetËcguߪR&KiVZ,ZgmYiW~4"uqgc Om5޾ޓ/1R~DW451uVЈɱ ՌUd38eڜ ̑/0s‗{ݷD KA{p*[P -m3w+B$sy]B$2n_C:}y^Z,6ɦ Z0ͭm{dfߞٸs!YkP>>F6NV^7*3ɒfd49qe|Sv,bX,g6|i`,Iд6~bX,b14X,bX^-X,b]xbX,O QbX, QbX,~ QbX,~ QbX,~ QbX,~ QbX,~ QbX,~ QbX,~ QbX,~ QbX,~ QbX,~ QbX,~ QbX,~ QbX,~ QbX,~ QbX,~XvF >DJ F X R@! \m3G@8H)TB =5Zk|W5Q̿tX5}ac/\ sWEJiw84HOp+{`钂yMV}+(am%E?CeeW+6I) (^gW4h#MW P XQIzC9yU!'ɻ"`Zk 2b6'(!0!(HWDD*)%yW #Ų4sOXR( H_s0Ձ|O|tQYB_"\Vfs :)ޛGJ{Lj0J+FvuF% h|׈м'vU"-bi!OE@( |.cABbX\puo <,|$RB>O¾u IDAT<8H)H5*mĩKT G8@ A_"#V*}#j]SXM#ZkHʻ{ ߓ*t%liP4 r~#be A *+D#iĨ,S)LV)ME,K*6ct9a)D&IQRx(hQ4DF'F W@B EoI)#&!}PBhDA ^5jQb₫{iZ|_k\,퐮*cE :ѵ'h>q%=\:PF9'&8oNyCQT$57m/ҳj89ݧ|:Xp$9g , #j I5u]jFiJ1xj+ sxNJeZV1*,D)+QR!MNC1Hj ^mv(]D5pJL!8$Vo.)rLWGB31A{B\s9G8ۋ!+ '@׌`Z]V5UIpqd?mbcmDr/49M}yWWci])Y @E*47Did4.}}E#bM>QJ@)MaDW]D8pٹv9ߞU}҈HPҤh+FhE \J!҈%D ";d*hs~R@DŁ\˜4Ke3B* R*it4T+^P22ͰPx*NMwaR/fRqUE BJ0|nb\puH]9~aW YX.=F@ aिA$FTd uk֦@G$ 9 `iw`][tJ/;@!0Q01Ekt*R'r]a/%"Dem":!Z5uH[+3O_J\PLP ;59F(²\*P\PAރbY@36KVDN)LDJS(QD4e٠F ^ٛbX,_tF:%p}0X6J yG+M̼GO%z1\iDT4,]Rt%+CQQbS Qi 90K@Md G#R'=I#I!XLFM~Bе`r%SK0Rfiٗ>*0Pnށ"Md1Qe%1A %fIòAFu+ cTz"WxBdNt͵!j,t|#(Ȝr4]T:b,$]<')ȅ%4+$T/]/)!bMX2$! |E٨b)`×e/4AE-iTKAlW Qi}ѱBiZ2zBS4oׅ0W!]>Qc _z&J$ Rd6'tLgm!%.herD})<˺oCD X2/TNߝH70QGFA@dpw4a 5RϞ"+4K 9nFk)P KIua)LNF \J . .<;y5Q(R -tPq3bph+I RF #ԷScFfI4>QI!PBFQ%,ǫ t)JћեbQLa+pҊ|`:/aA "Vƒ/y[Q}{{ksMc:7&|s,ENaDmJB?^҈4^.;w)+{^GB^6 /ThbXBrZ@^b9y?1bEkE_6&2R)*0w!$T+>+{BPX L)sw4 F/%E_ I3ڣȴbs5D{ӨH:})*GLt'S eڪ7_)%jszhXpHO/9ﬥ,]\/ EѪwMnk-6ҽ8NS Tt}BLTJ|WrٹݐhR@~J)DꊀR phX,6VZ842p<!YnâFe Rzw̾]y\: Bn`.E*|&UV;|T Aooߓ'.TKMMm"•i51WQ#TQQ:O"S$h˴J`iT}24-DUB¥_8k/{qB]Dy6AD^JUC3jb2-haB\cmڭFJIVsN~p(@zaTبbƱBr@! |[8D' z)\|%`"9][8"Q7`l|O6BH@BX)pD{D!1!%wDdUh#=xP5uQJ-LL4oQK4u[9/\s-*6]WRݘI׮`⠑*}N&MNLW0&&[ # obTԪJ2a 6*jX,iX8U#C %A %]fY!10$Ftp4& hO)+-TvJZU!=wt)ф%$IHTj)ՈzǾV*'i)-IM7M[r.4^R"AXq_˯]>Ypm;s|<ғ,_c*޵fͽpn7Ji""A# @Ao_hSQ:q5]LLSe _ qZpSrFE-嵊 0c yY&tj$Xqw/Mӯ]&ϳߴ4D^^hJ*t4yϘś"_>Mgbr)elዥIJ }D)Uձ"PIH_ZH!AGt/\{9sNJDPJ ce 8w/6],quwibZRG SG(F^NV>1& kD5X{by풹tyX,@*D]i|&/䌿dd*H@iL 9J)Vm#SK*5׀\yJ|il&v|7e)>Rt 0$g)0k2FIbiz:qadrHh2ab ؕTK)@AOI,Y1+8HRy"M39*EWɅM;(U+{z #p%" MϪ)QeK`>+yNNzs򕽐@Ϫd6O*6H#L'Iڦ3-ƙ0{rLJh["͢KKK@AvuJ˜תqjG"]X)Vƾi ~">+TfIXVzv[X7Ś@B>ofeKkz*V zKQ)JvybX^s\pu/MO; |hhRǁ|k;͂(R.霟ivpjqEsj"}%b7+chvAǔ)rizUPV DžT<)+s<[)]y"v5+V=ⷻ֔M9ָhMNVSCN(*r$1?R H(gBFZ PLP1\!֕Fdi, XUvFx&,bt-aqߓ$5:<@BWa!p]]IIKtXQYr\'/Y,iEW5󄋮%M\q!,щC\kVu(k ͦNͅDW5pP$pJEdJxa' 9Q K#M\UIK.Q6;ѻZ!P'bX,*VZ,Ӝ $$=⚆O )5H pq\m",t/u]!Mi]L2=}DtSDb6U{s£<޾ $bqhҠZai۪yˁ@> DkWJxDxfY[@FNu.]R@55ybH> }cs$]c${$/=hthxzJ!6fJ)RX }LΫp J B++)뛚'T+UJs@^0/ I{+e0BʴpED*!Х(8:Et &m`"76KV^»Z \ir](,4}ňBL :K'4:N?MhX,?*6"j9`m6A'qZqDmv຦}Ǩ! Y7W⺂: 9x怵Hit%!֚RDRMp[ 9 IΜor>c &X5E?'q=I@ߓ%}LL40r9sOYyHWʃ8=!51* "PR;\_U.DrЙ#Qn BNQVe9yãF$A8PL4X|Icfu ,q42 8yᢝMAFq8IB\u蹷`R̓℁!tDoX,lDr 0QFOBD AO>8ƶ?4皴DBEj4F%cdpD1gTig%crp+#: tc`*ez*Nm\Kh@05tw*VLH$5a" cfaKoD0eՎ@VZ$j|J JdR(HG nUG4L'1QUHP,_c\>gi+n3ꢷ?˸&;WIW6>Sb6Q8&PՈl+=\!WMuvgC& @c!<jPFeɚHj 'jNuaUшZ\% ]J#P*B'l# "f\GΗҥ8Pj GPZ(.97WH*$Fp/4&4$5ԊTtz&3њW8,)YxOL:!^"NdAk38$I.+%0Iq*ׁ'fs>9wMᓪ{WQ1L{, ~]M>uRReJi0owҥLHޅkX,c, 71:ULL3GR$$Gi]Dy+.+TǦo{$)VAL Ḉf@T*muP&N4C+㩤1Pt瑛)h6+n(1QI 5޶ݥP$(e9QuB0u\u:% x,4qdNBgיA$I#8Gp@I@IHii!X&!{ bCPPuCЇ>auCR y(8$S18Q8R(>{xՇmet nfb?W˟,&Vݳ[8?rV˖Y8<91kEi.Du:-SzYf͚N3~ֿ 9,jY:\aaeqt NwVm,bԤD @5X5Ĕ9F@cal$r EnQ]ٸq5UAI!2oAĒ(1ƈ+1ZxFH4U=~Z?]^lt]54z?9+ 'Q S&Nqos竞2}ƣ"N4:r@2XFΖfaZ:(?FB|wf͚5/OzoC-h=ѳeGzcx\2_RzͧG 38BHʌwOai5s+T9@0ɒ, wg1'B҅HQS]Uc.[}n3c:08-FfI3 9s={)O9g.b[ٓ"^3x!Ż/~z;E tA2u=0]є5.U:#%i >>XcF5/7uW SAL'a5k֬Y?Bt{-0X#"s1F8;keӥXDo/W^ϖY_Gifh{//Y˅.9#ID]>bd3jAյˬ'wV IDAT]|ga,zᝃ!h.jdp~ړW]x쫾C5s S L5ֳ( &nƆRS7=3'Y!j,BHx6Zf/ي{7 2C1pXt淗|/++_tƓc5k֬YG޻]4N Gh~0qԱwZ|ZyM?;_j13ϟ2|R; kŤ@͓]JwʾK9c)7۠-s I `~ԉc tk<.}թ:9&\g+r\^ PG1ZBE| 0 #1gv|O;0B0E)k=U +_"zc+.Ο,C$LIǯqlvA W!5͚5k֬LͣY&\-l"8)\m@sV4Qmj5 gsqk_# VyCǜ齯xuEg$F'/Վe&gnNlk!l뻎3}^wYəlRT6g!F˅'&Ǣt|UU]c_Vhcd eP]z6W#>[1W˿{N"]=l6竞{~qْa}SVYf} Y]1X*֢8) ;Ʒt[0%2`?,>v,>mFy1 ?;? qXdud5tg:|E,mbػVpR愥Yf ל4vuƱ;V"~Dsq67 !a񡢅w2buGʺ31Dy5"]w;V=XG qw_4(FݍcNg.Tbt#zU;p]:9]qdvmF@w2 ,8.ct{Ͳb1Пp>Ƈά"#oGt AF~mQqR 5} VK)0j򮚷teŚ短X_n諃o`10Yf 4wDgW9+xg99n #GY uL90pb "B*c f]VP)g)1*0>g 2Mׯ#"%J1½Rp~d 75'CJa`Js_Rg̡ l#7S#!R)o55Bwܒ){>=>n0P2^Fwc9@1 wT|8ؽ!JdTAI3)He o^~mAaMCnȡNO_G,J~L)g)#aa24k֬Y;޻]5-ew汨:Щ{(R]Rÿ6;9XؕD+^t5L׺'FMdx 5)!#bddٲ*_ N;!V^T~u}AZ9 #tWDDGuw^M1E.UC6}ѩ}䀷~>)swEy,ي˫нγ·߭._mxa3YwVvWň&N@&7A_VLYf͚ޕsfT<}q/s3(?Sr9sukιHk4qH U-ƘZs-hV HA0Zz-K&5`F8OEۯ [e?;[BIb`LYBLz^"\aH#94Ն~hT*'Dx_1D]ES$LZd;t9 ]@ SY_.;50eZ÷Z8Fp6Xf͚5/_s!:O/Q<@k-`O]T(#1Pa 52!JG}>|jԦvDbTa=C̨A^1I]uE%NAuܮL][ީ޿G'0""U@WJ@La0h@+کk 5)gr=SТ_ @|(().C |݆U3˓UbryrՊqӮ$'aԽu5PΚ5k֬Ms!:!_#Dt,njL:i'biSQAڑ|CE5b@rfuN Q/Z:Qhp l)u38E/sQf̚uPy*\Kѵ.7#PS!De6y7zr3(v3W˞ /"r.bN2@>>ȳ|gEƝm`z9߼du޿zޛrQs}/%aNS5k֬Hs!:뽪suOFOʮ3@b)/_ -tI-#c0FVK!}_D9!V!8`!e;NrBllq'ͨ.yz?]{2b^q+/ !q5k֬Yf&1+Lg x.7lbMbX+ao"XBm5@6g-H6m;ܡ:w)aJ;Gㄜ `n~q֒c ʁCcTe)e2|Yti؎Ak˃'4ȑe)[u/sh\u0ୡkmirڷno.Xaǫ'Dxܱef//,]8=YP Ru-4a^ bZ(p 8k)cq wd{RMWyr?NHڑM6{p͎Yf@4gW9'Q)MfL.J|wop !n3rp*|ENiE} !}L툞l: HVG!DNZ6èq%Z^TN@qF R]g x[zkt1eVj 1V||́(XcM0鵏1#N>Ӊ*j3 _бfĔkaT.}952:ף%Ԉ<O3j5'`AI_~>+Lr0E-LYf`4ޫV.sGLgMyviO.% 'K%Vs0Xt䂚JguwgR4g>y Xg3XY.j:#.V8ښnɓY:(?V+ ;6èO8wոL"e=鵛X2/^ pqfY¼3u!(_0Th#Ƈ\a??WZgK}oXhVTI{5%]Yf͚k.Dgy 먹y'>=Lz@$u3TOQĒ7—OW{=Cb=l1)^QC޻C|):or'$gB<$XuM=ʳ'L'}(#HlQ}юpGVKxa5ꂏyVTt^SHdHE?vVsRNf=rY;RwN=!BFg'={Y_fv<1^0r%WμS\g|Yf}` YEڅF˻V qt,Vu 1\u){9ae9;Znpz-/I3eѝψ1Vٷ{2@HQCWY(MBc8⪜5ZZ RaTig Wpv1Z"p=:Tv`])މvC l:vVU?=Wv]exqq0A9uhwϚ5kև^A,^3ݝw5G^HBg$9I0ax"Bjp霎C-!U 1B=dN]2!o=QH~׺wFc8NZP+8^U)C儂y^bqwΙӮ+穸''z~DпA":zn5#tme0n^LV79Wy \nFd-]ځ͙a\mf] D}?)f͚jvz/SGvYխ.G|WhPCCr${rrhwRhiSLBJ:j^O#X!NY3x]C$p5#=p`o2Q[o,!f챣5#w3sgw'p  Mb o"%Gb @7t6رadzC+#cKwᇀe;E)" DɅX(_Op'-@6S!N&QPM- !$Hꢷƞ6ǖ64MX5< vG>0Mv$c-S*q*{A ' )nJLo)Yf3hvz/X>&v5#ͨBɺy0B"g';yfW BgL\kT&hUO(uNc8cc:Ny'08 n?^rwy*n)cԙ)2A!\obQ:;q]X:Z 48ErU' ]ExH%ϥN؅RƳjI=I:u| GA]-{.O$a3dV]&$P\ec5k֬Y]Z'ی9tX+pd0`JaBp5ìN;Jp ȑaa) 0c9ctw؆HUG.Db*\ SLC5;0Nl"a^ 4 !C^_68g<ߏ``]t74c ǎYܱC9l bl_'O1m;c eH%3ȷm LsB+Iwtwl!Rʴ r_0JQz86]cieErNlK+}ܰc2h,zOZ]awL)v.Bg͚5^$- D":%lz|bW_c= gYv/D_;}N8*{w&<1W7;rtmKN3єNv_}OjnїW9fY3{O̙U1ֽJﴋg0P#K3!::'PNvI֮e%^7ZHJ.ةIW'lcT€7!=;[\Yv1fc`5QJWþ+-jg6#"|ū o5Yf};~tCwG `BLBAG͑AK10aE7,G摣6o@v\9p`?e&p_hnuW/\O6cw#v!r(P 73'' N>mǎm-r^_6,|]awt9ƷD59gei6OsjqG4bŒKusaJB5ֲ d( 0a "=RĻbAʙt)0;voyM:YL1qiKIN\;pru??wGZMی D,ҍ2uqYf͚oοů׿Xk:/t8:4S{ʕ8UǶҘrMKѽXwt:!0\lfǯ %11F\K ?j2ZX٣2.x h$h09͹;gO4=Գp ENל{sBԝӱؒVs5eM\D\"/|smwmC+F/EqN̐l8S޿ CC͚5k֬GzqYxQɧ-@wG m$Eq_)["m0 ]t`Ew/L1n ,`DL6##l“O P'YR/)0O:D}:L.gUS"LI4jዟ>92vĔ~w۰~9[UOsl)!M4:Rc@t7|_5@R r.zΠ?(;)LxQL!&c T|TK1mycܱʼn%gs2&A0:HYuf͚Ai^ {u4&g+eWP#0R/:p]f8iP 'SM7R0D]vE缇ڟ?Y1V@/IMQg+-\c|TGbٛF|[)H_Sb?u!K&:-/N{b4%rq:ǰ2E Xz_.%k5k֬YBt֏*'3;0eVʘ끱v1"Nw1e}\ndIFCwNw;WzD_&y]E_V#N#-b,{_#F9CaY1>v0NU}jJR4޻ Z7|9j? f; 5o1fbc{!pPZG,eRW;h_Cdq4YF:!Oo^gofWv韾f͚5Ҽ#:G>raq IDATȡaְӓrVy'Ӟ5lcMbA)[GJ1d('#lCg&ǖm‹9Nsd?{4% mi9dq7)NgM&J҂!X߱N>i?i5c|5UF%94\a.Ldc0 SJ11MO8n"~/l){[}ܱ?jpVbHn R.s B90FĔ)Eӛi(wJ@zCK`wkH7-W1nwCxIIf͚5|.DgxNZKs#[RΘCڛ¸G@A;t˅gd]ʽ1'C)jX*F0wr$p]f)tmK09( VXMzRdz oP(z(ڏ}y0.t9|Io3ȡїc4hӖr[8%#0Gߏ# xkjQ&uս5%u'ͱ%$]͖b`SRՕx[H OE>##'-SHu{iJ{b"C{TؾIaYbL JȪK?e^n`z;G{Κ5kև٬4Gbjja=ؼoRǴ!hH9Exе!DzTD0Lꈷd\oΩ^e4:.^mWyj tUzMƥ9_P2Ϟ4v59Fź0- 1BѼ{ w c뺾% ts8gNt0)P2cƭzw9|Y.:nsYx5WM "˓NqSVVwq&lYf͚5wDghڑwoa sh؎ӟtG% 㛄9(&챐Nt{]!&Lr,x[h#ϸDXh b)1G~'n86V訶mo"M{1I7Ca(ȑ,%1Bs%ZX|14\];} RNӊVN(Hn}i kH)G)kGx2&h4EJʸc!{#o䨰x$;!D씫oi!^ -\2xh{udl_OglӬYf}G~TiA(ܱ9}{4HCCxt0#VH`VGǹY lHtr0NB:q~V_O5BZV'v=k0;L݃4!tkh7k SL1s"`]V'8eM:N:W []=pNMbI{}>nҼt'=qC-j )%ҍ>=3 /@x#bA#2?$Z߰:$m<=M@CRrVS4G{8&3Q аƹ5k֬Th~֏kf(Csf;5t=،#IG]!%{XeQǑ ³%v9]:)FUrR{=oE(YǑpD=NDrا?QObN:Q8ap>㋰$u pv⹸9? )ҵ>N;uߋ0NzOΪ?jo|_>S8k֬Y-i/:v̓xmFD'ca"b)-vo!&›y%S5)2xkp69!H+<;][h:#sFM<ب#Mj6qz͹݆_}fj1s7&%D+3ȥзƪiDb}丼H.k7u ӟttmՖ@ɜ~!0D-4Bz|#a .3)%zNd*#o"rPYm 4qҵ߼xI6 1gjDr4~ұ{i,0f f֛-얟5k֬VsGt֏&'v\rf#x^bҟu,c̄UƦbn0ƚUޫyiSDJWG߾TCP78#˾ޙb ywZ9bɜ gbMKv~2u{S@]+6P$Ӯpjh'1Nq?.#Vk\bV`06,Osl!ZG؍@,z1rZ:sθsq=✰b<$X.'@u.zg͚5kև#:G<mr[(2;aC'MIt)CNb2S6X1B+omazN0lǑOL5Ӱ bo_^aDy'ݤ!&}ciA7|Phۆcs2bmliߐSb Y ~-W ěȓeEaMo"9'-d90|7'ȡero>Qk89sҵ8gڎ8jW:ev!¡`Mfs,/6&>%#@IȡQXH-"4m '-G1mCɐn'?¢mV|Yf5fh`;ezN"ě0(EwNM6 rS45ȱgJ %EWL?L81 cI;߼Th)8Jk&N ru "Bg-&BaX,S|ϯvXMfqSB GB6TÀ=u4o[LIR7F; # EA d1tqj8g]iM=r\ rCw? },?ķr`{}@ }繼X%.&ܑPa@[Ӭl5k֬YN_z?YDeWGFM=Ζ`KINi񡎛yF2}fGO'q;ck{)VlfG{+jpcjzV'=1gW:.yH:>1EM5m ι=gJ9w BW S_}v4 <{b>41(osֵL+4eNnLZ$ԑ10Iɬrѱ^\.{⾈9֨T=5t#rJsDX_ )hJ֬Yf _?Ik""H= ouLIGR.{R1tGx))orC2?dH4vIגRx\bL1}KJ㖘drM6:I:B4{l(j*hG-Z#fŠm9Z%f}5a&#BKȁ{ZBLGN^Oȡa=9410Qb#C΅iZCѱMH˴pqCL m}k}Ƣ׼b=OdA#B8W5k֬\sGt֏d)g<&<"B|a !F* (q!1Lhγe V;|1FXN3zu9(f"v4c&[۸7W'r󮛘S&Lz6Ck)Y5h؆8퀠`1jPz`)r~W=9e]GH-EHF&2k3}!*jrю:l"r)RTY瑒GEge 1y59?A;/\Κ5k_z=g3Vpi1&r%J-RhN2b=cH NErNiF ,22#w|xVFFWv檯q98qN#<-{7|L9kJ-~cdHKVWz%sy=ha,@Fx~_zͰ|WKua\&]GX.|}OF4ʉcFlGv&VP:-kي~FG~ +5Ft_4+`֬Yf/#:.a9DqlGjpZhR2)Mi C0a0fDݕ"*~߯ ty>ūNj )/a 5!afIĞ6ZiG#V F%y0TW$qL#ι-v<$҅٤׸<^s8p>prR@T,]Ji=|.9ώ}tɋW+pF!snh &-@e薒IzsJInftLCJhF>9,+^:CJaM]W7;Z{d2̏,D3+t5u<\qKg\Ҙp2k0Bb8YQ-."7 Wg.ӵCYI;RrnRHώ)8^*vGCsyzNǝU!Ur!+gɕta}@rY$x78.|b* D]JS&਴b՛K x"/OY֊[{X%`DZEXm:L$IL(xAv^HayX_x*cXuC3L!3+F#)Y"z*Yйgkb@>9Z<ʛ.e]=7;/^RTW$T?sTep u( H-DjV4O|B֭%/'8[5IV0]I1z\%Zk֬1=]<ɉ5E\ai;br"H ;JR_ H%ݐp{Ǝ h-Yb<@o1eP_K>ْxyʱML&2;hAnt* Ew'NbGL%@CT !"1F3(K gkԢ4+ |D"uU6E鷺/񜳋c"&0\{Vv4,#S~̏TC CFC*4UaҎB?D1õlL&ѓFBI;F ""-Hw ~+n5b*#n#JNٚ#a/_H!b$jGY<)Z"4o{ h,JR zWcJCQh^Z1܄@I`GN"v l,Gx_ZXWb*[]m׎$ W%Mˬ4uzzge0f'nL&sgJ-A&U6ZImhǕB 46A`k;BuɽtaJjpr ]#t@]W)^KJ;!Ur <,9?;U_@Jo{=YPBti+;uv.6_Z?zԳtž4r<]51tio-M,fʿoR 㟝2푮79d7?nt)4!p<7 =ピ&?Ŵ\HGS.(8]ӍZں)hzҌA.L&Pnʗ>'H>ZI<r=ҔeAe4 v$ݕOUZE$N]ۈ $>B+) D@ }~T zb:h'LyqX oT E𣊋ua4j*-;8Oh! &ف#"U|ż:иOw5PAi=U뒰Z2 xp#InrYh] H ɹ[<]) t,J-J"g~@*f7-1 hqi*?Xֆs$9t,EUһ[(X%L&aC4CqZu6,%Z٦K;[bC!'uI.5j7C_X&ehmӞ("UT(*<ώX;cg4tcO{ђEgؐwFOSarOcdAVr)㘚>}~R$znx4M.Xe )xڱf3+y%H:V;(;8ގa2Uv)Vd ;EH\ߪHw `I%%#uҒdJ*P0f-|&|@c u ht IG{Ad T5H;ZYÚ{a%L̹\TR̐TgI9R%aFi$|-_kͫ5Rq6|"KbBk4CjQܽJCKX,RVW+ ]oXɩ5Ki%lttΥ:ұͪuژ鐅N]1PJֽc9KQXZ4)#u)y~^3 L&@[e!HBM A>K]_hpAcY=lJH:Nn:39vKH=n_TiVX.O;`{MגrHKrVޯ b!&92%->|yF78ut$P3X]4ɹUcO}U.~HiU&] IDATbj 1}Ƥ{qzN UiRsUqLM"p/s~ŋٔjFWwTR&4h-9YHG쿘U6guL&+>3+.a$IݐRDƶ`!8)1$jD9^[}Q43D(UF'a4]eLW2N!q B4uz "ZK,!dQW,Dե)HuQWTҤ_*@ՕI4^RsS]\@kJ;''^V/_|_ ˢE!UV E)J#%u]q6{f2L" KURwb`a$%c5gøYhl]("T*mRNIхTy?w{xrBpѥp+z0>"]#wMl y$jG29U^i. dHGC uyUu-gӈZ<08"*tMxFZbI jÕZ9DΦJFW?׿|ez`KĨѹ_!LcaQV,F3L# ̿ 6PD"tCUbslg:9 Reݽi?"wChX(;u*6Ӿb )z\E1:x1<$j]`b/u!tX#9uW(n3$Ъ"WZB4]44m.4'GKwԟ/ߤ/Z=ő5VZJ$5uë7뇵/u>v?P t[r^|-N,Z@>[e2L" ̿:<[JRFVI+t| ĩ1:6J8!*FEu! ѱv4l hִ)SrVĨG|瀆% EPpd>&֣}7L{:kzlC oxI78VMmemwR>\:ˢZKqt>J7߿Φ(&cuPϟ.ߟ&1|1d29G4o"UiRCgG5x7v D$~+(ż4W8 6TQ$aGXKLbFJF V%!tru( f^ 7pBޣvʡ Iq!|m%Bm xT(E -Y֨]IPp; 1BCЊgG5f_QjɺlYξI.%!"&&G" w#Cnt3~)/$}=yh̀؁YYR?Jtv@*WL&]燒3 y UBS% MkqC;oݘ_5NWR} R i /& iwZKVG2ECIp$Rc {֦*5LOu .c}ƚϴkjF]YKpz0:.KIui!pz\gC.-b^qZ Vhk-h!qcdSe zh-Se&rUathޛ.:vKsR&|X22\; -pQ_;TD@hgp9(yjXѻS0Ee T0U,?;")`~@jttĝ`h]Plx*&md(謣zoq NyĐ\R'UH]y.4"FڑH)(v%j'sCHxP&O 1% !%*u#nRRFDTZnF'@+&n#L.0RbDfq@$'6nAJpDt$MB+!BH6!LQRJw5գ{]9bɭ&5N"ZJzƚPثc8w.[9_9Ϟ.` msɌI8@=A4@Yf2F?:t` }2gcpVvjn{i;_TewBף󪘕'%zG$OE 0{ boAQSPS(wS0GDہ{peK@@$h0cώ)L1wh{&Q#lAL@pvO@ Wĩ :y`x OhE;$8N$"]?,ykʃ~px-UXlգͷwӞj&d>QCN3i_&]0 pPE` \4c|‡тu.tc7b^^ӊ'Kf%Jv{|jBTOpH9 'tGbd'S{r`9'꓈6Eђ!x!i-b*`5 k;#F Dk|cߌW7iEJ$Aw5rGnEE H e1/YI΢vSީ]K?L&B4Gi\DݤEb łM!, ׂ/᜙Q? %%:OW`4Ҟ AA]pf2;H@%Nj#!9>41oG`PBnq̮E"ƇZ>6xRҼ`"QJRbW]ێ_G\4-H!شR++Gݕgp>L&󡑅hS4@9bV{N w'8;gpЎ8-uY'-($UY0{\"&6>*̎x"Nhg$zW"f.ppwjy ?F:)Ri;HGJ h%g4:qq7ALiȩ EʃBuF.[䕣,!]D1¼*Y}k;!aV٤wweAuPx2I`v Az*?mڞv)w*d2hAv}{O~z`pnM!uKC$r~o[OBPkC7XdLEF%MM;/%fdi*ú0c,eYEj_j:T 4QD⨴FhM]hjsh Ah& ɪ,XN{20< p죕0zwљ%mJ)KI]o2ՐV ZU ٲ&KErF1-Xm:B /_'S~豳^) tEUd2f]} Fܑ@yˏkGێ٣#9:x0+8]wZ! l4zпY|T_g%xySW \mX,fmhQ_{tR@Ma-F+VyHzr*)!oy67btWP ~3LJ@?8`NWEL%z;(5^{O _:S|p(Sw> Y!cੌ!N'֘} SIZ̾|RIbŦ}vL K;L&G[pĒ*T ޑ4{6yףt"@ %SjFo=オHIww=0ؼaÏz(LqB)Kɂ݀aIpA!BHA"9Hj BI+1R N4iw@D EFC^J\ct".^yVP2 ]Ej=3DpmgGs17+pP{ su.-`c^pL&B4&]ԏIw9$N%xWIMeڃ,0EBRU%f`Vh$]HewmOi wúm(KBif4_<3f4: *a \Z*)t9=|RQ/jʢ<() t7":.DO $L6HS(*D"l.6U2GoFrIDRC֚@'r_3? H[PK+78 Lp3`o`hCr aT{P1ܽ l ID*؁@j>5z`p/Ru1TW?xG9B#3@]9Zxs,JҾYSh; E.kꙡ* AA&s(IPŞBO#\F̞@ ׎P(Ĵxݣ 1]nfA_ws`+ߥ')$Q$8^} O# !S3a˽ƥrOfi̯%6rzRyUt=;K.-6b<壂B+$5^m[fUz Gqi:h&|d!bo"վ[Icv&1h(- c@M%O?]_ CGkJ]rU=E'n%J{O%_YShRlYm`ufq/߬xAnuguѩɩx68վPZQj")%_|~rH_YOWwI )f7Փw uYyO9]5BJmώȉB)|fs~ R"n9O)XR]j / Bepav6IH kobV!1#n MQ{^ӊ}Fr|MX"R/PS3T*qhIN%C iz7oW]Q)XoZ" ~lx M!8*qpi[6M/PRptDL&|d! pRV߶2M@kR5hǘ:vMgGSˣc *TG0:]hb:ιtL]'sVߴc13xoATpY ~SʒaZ.*ο1R=EjMBH"tM=N~Qf~-}/NFa"}MuQIډF6m.Td2,D3(xm?{TV5r`-i\mh=.B2 %/錟v-+ GbG@զF`"cNW 8:3LQ0l8~dhh?]nb@T=]pZv8==U]Euo'jë^qh>1;0=C앣Ix!^4 jGq5.)e2M"6wp[A%3\{?_ȩNW1uˋ+4Z98Zk,Tm|/ x=1Sa~`n4o-Mdm=QX.bg~`XEOfH)Q ށ)UHsc8kZ ( ۖf1+Y BB\)4H]EC3M}cఞ^7t6f2̇Nd2?0Yf2BwY]Fo{wFIv)s+QBltoCsJsqPu Y ꪠ?J !6RU3P=!ph{08@Sh']h쥣^̰,фygc`v$r9**TyB1+ %O nSӬ4;cCi4M钗+B&1r.bo#UE;)a+c4rGvFGs~/9!D74mg2Nb8>i-g_&:^}S=AxJ6,'G ξP7_SBpJ91ue#G wq墇7_it2#16o{N~ E]ba=bמ%ŎDH T" :gS]5 TZ7oޕH!"ygg6mWgL&B4[Ow9ZR+!P "\4UYfe:y/kkMg BBDP*ВC#` !n-o{!Bpq=I JN~:-'%J*ھCN%"l^ IDATA3 'o[\ͭUki?*z;K{G%) HC{Wp,^)x,2{3FL{-4MfӁ6Z.W0⴪oA-D-kL/KAʭ0eJ{f4; 4-Ow`0?KmnZK϶/5FNO<{-W?TN!Aȴ֠9zqtϢ Ӭ|]ƔS F_*vXVLSd4/[v&߶יV&.0#&h~5UUU7'Ѫz["u1Nq*H)mKQ ЛĘ+* +UUU4_Uo4`A^L)^*a!3" !.ZR0iQ%g49%UqX+wWO U mkS|k0 5,4qx%CQZkX^e0l7J,NIhS-V91$24'|s\kIm~rd~SHZ.5?qĔ@!͊qsp4QP#1%?|v7Vʳ~R؇D1Dz`E @"5A3%̊zri7 Cw숊ԋNUUUZV[oJAXGgSz),C\8|3K*Y"Bgr~Lj.;mB '|i(C"|>|H)("0%Gaw澷$U ) URlaVIe5L Y7!&Б 2NmuUUUUf;Ar&X,<1uʢw˫O Fl˧2rǟgw Gr*Զf]Ʋr \~֕! gTJ ͔W{~f-jH&Œ\ V'ey1F7==DZVUU+j!ZUoAJf./g=2xB,1D4Ѻ GkX@9?>k/rD-A=-kyOKU\۫\HBI bX#-ӱC ) i.J}g]g,Np4SY^JsBD`ѲLQ؍`m@^IݨzGez "`u2` cDn5\ 9{};B@s"jH/ڻ͚jYv5yJWc8yHaJ wx>CM&-Uג^(!kM0syh"w {o L׷IΑ^-XkH f⋙D# X)Ab8<[0ԬѪr?[oCT*!aDRe}Q-L6BSyN0UYJ=vPs}X1BrMr2uOJY>t;Uߍ]c:delȦ/4K"aRfAE GP|kqmYǀ6%@*9k)_ΨH~rʷWVUUUՎhU}ˬ=ex} 7%;ۈ#ė3Mc8g~,Wu&XhcX^*_ƽ4I߱Z8L ޵H܃V{~ղ̉O>3%(w c,˫Z q)OfU"24B|АI¬<|#SdY2aۂ$0WqLjˍҊi͏N1pUBUkU;U(kʦf6Kow<DS"tQ8kΕc,r=Zmaq8:B*d]ԤG7l=u{BJ\F0")riE~tZҡ Mbm -Zz1-b!/gϫ.+UշLU |[r7r%F1vxs3n{P؏ͺgg:TKaxȣ z,EqI!%") MC_rdWU{!f=>a7Y>ћߓ'@iQ!KʉQ-Ͼ>]l.?M zGLxx".,UUUѪAKn_" kuSdwxr%Fvޗx1RNw]sb8e ǹEEcĵHMe[>NB9ScA 9ШǏ'Ox􏟰gXkFH)߇{=q)1ʷUXX+M@u96TPhUU_:#ZU2d;B`A6~Ef7k0:Vޱ]3TvW#7^)\0?i/3Ӕ:L!L@|sgiL~ ,2r+ Y^-r}pbcNBw?{>Wʺh[K%~˞4;(sJHcӳ7#ӞU0`%yfװdrZgSVUU5'>[&"p|4 =2yq+׀Hb}^ p_6Cns~$Ω:'j;a 5Ծ]P;U-2MFDX,mAn M#d2+]@7ˌliLsǐ^)E٬OhY8ٿyzu0N׶,/r!߂8L¬ VÜHK&g4,1諅|;Vˉ޷꫉g ͭ~=Os01`yy'ߝ^.0/O1 %Rjs\B,[֔}H_͏R{6ch|"Ĉx!܆;7Z 8G\[Ӕ-xkʲԳb1 tVBHl*cL8p%LUkbL<:.ΖryG.Z1BUUU5_Uߢ?qδ(aX[1)".R6}g8'֧=:GZ)i^r?r[SR4S.2!FOTcL{zlů_nΛTE[. ɥXkMg{baMM(9bJe4+kӛ[))gkҜppٺdaN +OJMCUUUorRl ~%g}lh.b9u! 0 EߖԷ%>-@k1m1BB#ٜ0HL %IUK&i.Y'B4˯@)$\RIaD7K[:;aN8WԟG5Y|d:|zWzEw3BĘg]ֽ/!s9ytϰx ŚZUUΨ[U-[U/Zo θaC)wKe{5e"_6ɼ[zxua!-slcyPbw>T~ɶnWUUcjGV`=8͜p0sOЗnA|>3/%ؾ9)F ͙FѴ/&csf[lw #HWE3[ R"&Mɤ+tZV]||aY6?:AUo/>慳WיtF/iQiϝsǛi黎6w mgX^<@0 /fR;UUUo@_*)cVŶgeK\+xV8_ i(HXOR}e-Ŗ#JPqör/g@H1ge޵-r HYڪ)oߝ)CD&}=dEwM)6ǩl[)gw"ӔXuAάgFM\FE G,R * Xo+KvHJZw8Q1'{eoz퇕4Ê^%Ezԭ*qνr9i.)ZG xqg$ IDAT CCBV+T"bqN0kE},I}*.("@ guﱶ*Cd{52%grUb*,z7 !KS ")_GUkRf_7Y?NϷԅwK-D[`;J=쒴 ifݗǷz(W92JGqC#X2DR3&c頞 f\|rWl(c΂3Y./X\ߕH/vpkҒ,j gy>bf'KZЪwP]Vo1B`J40|NhVl}dzV]@ iI7uC՗SݠayenXӒn2N|;kinALK5 15L#20/|o#1' hVZgږe9|ڻUi ӳb想5+2*QQy"L3Knzgo4-}/8S(Dͩ,4zǀ2GjMHnh.0r Co!zOo> a(K'][xɻį\n=,KIĿj/R_9O8;7ϴ$b$rH❔'{I&(.%pu_b~ ڒw%0>i`JZfXhR#QoJwSsXkqEx zYK 5 0x:T Ѫ&BRZ<МH{ZB擖/̥kg%&\;SeǵeC2?PM!A9T{;vׁO.vluZ'L^ gKߖxgqI`8^:V\n8viqu{n?"qIoG2RTUUUOU I;Tl]qK q 'C)J{=*bSKSLhkv׌xJ/xBYzHP|?BS )MVʓzSjJyHs9?zN)Z|IPo.|hUU;U R4Gg\n*X9a>Y؍XM8WcbI +Oae^hĤ=|ǵYl[-GEc.`yW_9C:x'On_:/F))E,rirCᚔSr<_lGTM+sXTJSVUUU_~۟9Vi<)W8$RfDw# X8+qG(E ,9)bL]9IĹl{gQRN[c  X'"C6"14q H4|r]ɻ?"QPKwvD=?V7E;v[Cd^(Ow#L\<>o5{}0 =bg_!7޳|;; F@cﵘ gЪwO>hU}SJwР93Ds 4%6'sG~?E_C+ gtsc ~E;>yCdҢ+Zc@sـݰT;K XgN L{jdya hyA;]9:':V޶83\H m6m-01N3Ӝ #رA!- ,3Oz8 Sdw52{GX濎xYRJlYx4Bw]H}9=:)a)RbʹҏyrDIĔ|hUU;vD !- 9?_mi091c:3i[C8<:_. sMtq^gLn%0ͼ!t,#T 8޳X۰^y~?1|׳,ulzݐ'54zMFw-+'C<' 4y1|q]Ibw5hVUU|U}C1uP֭Fhc9_Y> ǻd?'۲CYN1Ly|:UٸC6jR#O=ЇB9YRG]ʍ{gb_ ~~>*o_>ٚGJuxsY!L%mD֖\ZZ)%g[UUU;|UY-!=꺄3/``z'ݷ]CC,4 &#FhYd~1ӂ0H/mX8F3eUE*s(% 3. s[p)wcJ]wgKᗴD?!R"-xG8'El<;4p,!}]PoԿ݁m^,4@rSOcXu8i[_.4@ZMU>{lW#J'<I/EYZkp߷/˫L;Ҳ7m 9%4ER 5ZڻO~ó?N:c ]wqqVrUUUӟ|w?]RU,1M\LЖE%ǮkotZS6l\E";Y){'UY bLm>lKs|#ҜxVP'ym"־$"مL)qH!;E`pGO/vxgw#·VUU~]-Dm|VZ$, K9s+c4zM<ϩlSØ=n \2DD3Х<TNlDlpy5jٚXnͯy%N̂}rT攔 <#y$FCp!(t:YPP: s(=ԡ:A sP-}HXE,,N4N8MEP(C80Gb{wfwg{:SRYz0Ƨs_o}}sa,y\)" b4 U zP!7`DB՜bYF TB8 RC9XϪ}aQhP&\CJlꬳMfvȣ!e$)9y hݐ+u` ;6/C*+:=͕9#ၨsoUeH;T*˒e1Y`wCA!]m$; M1rr@ʊV.Gkǫt-[` Rݠ!ɶ }Ϥ8@ԹTQ [d6 0?;k  Y9@er~&ζHQT2_rZB )\柔ub8߷Evђj*= >y AM B[/(uι_?!)+|3< c*X1FbtP^$ˎNv)byG4΂:-[JQ!v@˔0-L{ |8؀Relm]CsG3Vș-}Pv "Ⱦ2B?Ńt33 5Yֵ Fc#v߾!R{Rv/@wޱ}`tcwιD{XO&MCB e٠O\,k\?^PS-kh&h RCKt(Vp*Я:t~}}"d$Fl9܏3`ݦA0L`Fl) /Q[Ĥ\P-hcd2{!LY!N rlpjB.J߷Ws?&:#T|@`l*MBmShY\`١ȼ?JdUJʶΩ Md/j°Oˎ!&EdP<uι Vr67tgv6T&iз j7>HKe7%TԂN`֮ 7 9~T<#tLDz~thHEO{kLki"E@'鳁yz)Ku9w <u2Rʨ?%jrf ]R.t :[s?B:n: bJ6+%Cl"CQV "Rnuι!DsAfPDت h%JJ_ :܏ι<&̷(9nO;sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:sι[ၨs9眻:{k'p!U9ʺT؎Jm?s9Z.R0ª P%偨sιRPZ(Lh"EWvE:O9Jʐ mh!4@FB$ek[BlIB "dl.J>T=:umJ9:Am#%0 @./&Pj|t+E@|ʹgDsνuBE$BQ !ʨźJb33:W;Vw<*B nt,d;Qso\ - ~!(LD)*RXu!PƂHIxE \E5 CF6*!<݋P@ros4Dsνu*!1?y|Bˆ)6TFeݷlvF *MB]/nH$Ðۖ϶ |M2>."p*5u9:XQQ-䩥ԁX)AUI9s Y2]P 2°/(-;B"T |#<4EEË5^鿞Oha;|'럝~sLقHTw*o]ȇB 57ߎq"ӵ-M#Yd|5"UEy|) IDAT϶z9q:~ a|5ҼWs/0g ҷfG Tj=+mEO;Qso Bh:>#"2ZTu_6Z }QhH6N׫ra#tˈO@ "G_Iv0~l¼TcAw;\=>gDsνUtX4B#܅ݰ?kU 8Q^MjT.__e'`ug??kVw+vӵ 7,?]H55,yfϗ @r)o }ioa`p__AQÃ%ꌴ46ψ:{LjB $.@}f:7vibiC(Vg- IQeDv7ˏlgQUB,J&Cʔ )Gt˖틁 B#;;b#0n_@=k~|<u9pwlekI (F= r(&TΤMK26|͖5Y*Pfkmm O3v)Q-lq~eEw׉(B)֫<ED.@Dnvtm$ CJR{y sO/$6F6;E@@%|*OBRC T,D  ZJHMчZ(ҋy'2"tm$7G>gJp`R?hk%) }kZYk!böEk-B>nS@9[CPDڹ_SmPtuL ]$B-x+-NP@"wT&[7> Ke{*Odv*bŗz/?+tRKk#MBDXzvC"en W/ vuOR)+BҨ6'AZtRU g;(/|X9[C*XƈN7)HkLL!D}2]0T܁.iBMTwh aD_**TWpkƻ ܩw&noؾeAfkaЗʡb oR>Մj~>g|9w XȹonEdESSW~OQD<=e' 54@nosW/V,9"uG;++7NiRQD>!v׉2Y^lFOsT) ZpR_Yk ȜmcE b(OlKt C,*KP eRщS o#]E }Zb-l^ 8 A(jZy:xԽ]~gDsν=>9_Ҷ Ay1pL @! 'M; 0ߏ4!PݭbUaԉv0/nܫnE|/:6'}D *6T4$k!ܫۿי7,Ʉ"TUŲ[՟_(ⷉ7xpQW@HщߍTD\e$ْHyR&10X:*5eTƗ뛜sν5@.%jKvaJ@L@'9Pd:@ Md:plK2"kK^NIlA$Q:Qvb jc'D T  ^XRrPBm͋2uc]'tR֮K "LR[8 )g&W22LF!vCb-;!lBH~sιT ggKuOZ;.Lw^~EedAprjҡɿ訪o 7 }5 cdQ BNT@jTIO[SgӛX~mH^Y45AF_ }an/\ubzUn2*g\hSyEv D˯xhW ,c!傎4!틭 DeHh3Φ\E.[IV\WJVX#Cɞ'g1sK21G'WWO֔\9?\~bQ&)("22) 9??#_o}X9ݐ`vidzR Z #,솄T[:[T 8)mNB vg~T6mQIKKR[G%lfʦ鵆u 6 xɢaPXXS_JeW['|PRV5..AEUJ!3W;>ي!e^$Jm#"?x a`[FBlwɆn)p/ca},e]LЗs4sF &P݁\6xO8HBW_?yOU [?z7V,G ܱTw&Ju$sPXFi"ۿa*htEep(t&n2>TAUkUiJAXbQ'p~d&@.ީ*aDj7{rA(?~ͣ;p(YK)͞lPSߩڲ0 7La| L姉4*ܩew'6e3:{+b77W/vb`G 7iOsK \}pzWOs}_1~|Wȝ{nEuȡ***&Ut@ubZMrRo nT_CZF脾V݊^@V254u :"wN`f rwTU w&+{^`#(7GFib`aE gmC5zc#zϧKWaL_paC\0Ҳ:kH{nriG9ܭku-WmkTþ6 M ?5#>Yo[~ѹ/}4:SA*A'Ʌk 4AXldkz4/Z ]A[:BqbݞEϴ T!ԜvEK[ɽBT <бpyX_^Ʉ:pYyأ/[V@$uVXw\\]nHE BKZe \x@c>sVQh-Hlϯl萑`Q_t}R2Z@›^Ӯk Et s}ޡ|%`7/Bm}Rv0)PaH{AzEe, RQu[0\]!"E)Ev?AaL APA#l~&(Bw!۟oh(:Y}g,zQRB*޿mV66|(|pm}G[B`'elm#&|.=R_oZ RζI|(ֶb*V>V*j;6R djL;řd_k@-˚J>dEɥXy\BnȈ9PYV@Q,sIIɓ\ KXnE T@ "HJ\l> lhnώ&seuֲID l.uT J''6ItE2y%-!X;TX8|)2)!>7_/ҡ/ .;JVR%<\Qy i?XY|בG;`,{KC-d]-25ʨCC9nS#'`}П ~l4sV`v v ~{S8 \mbIZ+ cZG igAW 1MDP22 z6WGNd4Q."<}C0+Xx#b%)Eɳ-]bBt:#: Q`|yG)*K[T YUY%LjS1MWV&Vs+T=]k2`#K,8l+M?$@@ Kб`&lb9|U&%NbOCgHy:;.FjNy:| CX'vnѲR'/lsU7(Dd^u$<}m#d͔)&]DN])eT`HY BU0"6t,5:fC~S`L k)L&EjꨶE9)[ eBt nN*HҊ 7堍< { 9H-j`AÏר* Ke溷p:s@~N !~}J̛ ;Q{u!FelavJa. 1? *lb]v&>#XTĆ~衶cA ư lc^*~7$y'c5Kj{6nKe>1 _u?O1`G){5eΠnگ(Z=y&[Ube7ͣhgh symU}g9C8Ka\Ţݤ -XϽ"IJ Z?l ؕQ{ǕN/S'j%Bl\mZ]VCf5g[bKک 9M JJ.6>ZPs,pe ց4OlMq9}lo1LcMN"U 6 ڦL fk ^!WWhv؞VS=\ڟ ToC3\[тJ)}Zp>>Z6?$ta!%{ 媏*HB.L=] K+Uo jBo7;C'xxa? KJm+T. CP%Ջa^oP[j6tl>g%́H_{o{[lkcX&|'~'K"N2r Fo txz^n@9ai7=2'kGXeV78*EV%t\U%BTu pu2v)9^ʴp |hAR wv&Zv)#;Z%e>9٠Bɲ21kYS+d_v/6ԵS.|V>]6Wՙs)0k[n-EOn(d+ s9=>Y~8>/~ B oJ.l=eݧegvk) za( |_*aؗ"}@9a0}]M`7/Q|eWe}QJ[!eL6c׵H=W mc+v)Իf/-#OMWM Dqgf\0g!RPNub( 7"s/5=1}Oi-{ǞRyJ.K+KXՋNZ Ղn`շ~^u:~dTgdu*W{4by}w)bӨ6̞`j,chJ sɧZ't#+> CK#s#*ˎy[?xr0du2yT)0d6{;A7ٲociQSA` I_fï>;;iaJ[+m_=VR {!Xi*qOϤ Tqy4*ή79ptոM=Y.-l.]<VVU|sY){WpzMVkAi,S1ء IDATnׂ low8d{Os}k;Gj{^55rKyOBevCe$~B/wιwX-:\{^' r>oO./RL|mVg'K̙ź[~slGj)E˒iWg.JJdã@Zo6p@ h)&Z 4Yt\^?7cõ}V<9(N{ˮUMzt\)t\CDձlN:)Ajߵviał9iCCyKTt(s&U2֣z!_oQhQ\u(.,>1Z/+0s@} cwX僎2Z梴d(QTP˜Jl(e0 J NJ LTw&ѽ[ߋ[wAϽG9E\E#TJ tgKfg{9GbQsȰO *ʺ" 0{EVN8gd:*Vj,>\mv<}Ś/JTh3y\=t̮`U)Wtsuw+չxНheW;4xʞ2lc4Vv"&-s褧KOWϭW2Fb`.K}^N6"تjA?4'϶H2_.ʹ@y@+bw+%OJ~A:dJ.<޾)_P[v4YR*둕`_;\޷!mmmʒ}S6Xֻ4t̄IIjLeT}eӻQ{PY6G?[ M& *a^~г)WÐxRCt Dzaa ۋZ[(]ئBVX-[+᷶n'[>Q@ ʴR`*@ J$lK+*}kS]M֟z)ᗟZ@W,/\ns mLhy, Y/la8@G+aP &`Ri< _v!?HI%|p"yr=;e>-i;-uy>XqQ jYGp`.rZ5E"D_<جU'l^$>9umeadm{=^/zAU!`Y[_ a^$m Hl=I.~z[g@h-Q`7* egj)l> ZYֳ:]^R 6޸|:;kdeղ'n7@`T3 Zmw<-\`Yt^yh[DtK[2* G6X AxN?t֙]JVYڞ9Rt^k5s&Skƅ n,h.Bgx\ 2iڮW%6P(cp߮(Q1D%Qx_*9M/jgNaKݚߍXb Wɮ}u[~,v+#ֻZ[4H`RͺS9n?YR^bmB#4犃! qH(D$pM0K %jE-rqE-E/P\!A4 1ӈIH  wez3^%wqS(m8!'?ÞayҒn )E̾c2uh0w|gxΰy-o%?ݛG5faEz0wXvCKu|ۓKa^ iO*kwfUuWY␈xW>rVzø5{P bBu&d,1ePrBȱ 3KogWՁh%O* agB4<#Oԕ% c )j+ 11nQ-!o @"ǽ"C$+4mt Fŭ1&mC]$&U"e_3\E#e6݁Ǟ1pZB!_grɘ=C̙!%vC>t0SI!cf.df6b0YRG&RB0 Ip|$D4{7 N &LxߠO U#{j.kZK\uV]aMI"Q>\~;>䔐"nbզc'j/;dUVI5nSQws.Uslգ*zR!^)eɎ9(kZ, 1gs<ӥ:c9s,OڑՊ>h&뀧u?VohƝ\xwFPw5im=x'|ݑ,cGV޽dScO{3cL,8@(BNf YT'wg2d$t:ޜ3혆Xmi~a0a„bvՑn_aۀ=Xn{ 3'?i+IK-!Ԟb "B1e-C\v odɫ{̡%@uUOnU;˄L-`},]zd0km*T͖xSH:ѿUV +R*E5C̅ Fc %? 13 xX}>ق{g+F3CΙ?\\n??&LKԕuBLQ&5ƌ?dOX#P4F?I7 VT{77B1̍Bě7gg \~7FWʞ1x JQ9] 3v71fz[ؾK iFwW%Eo'6}ɿ4N0a"{\k1FGr!`l B}؅av_03*>c }H#^g!,9 ʞ \8xIW=f_\FD뚜 6SaOj_c!\%Wb!FR.BK|w t}vW4=YPwҲ,xW=mOkPJ_wcaɓE3+^_v\{U7 jއBN a HxȺG=O*)%SJf3n_eC&n!S}TM5Bʙ00tR;8mX]!\'\# ^ !tQ36D%0`\9MA)At„ C{OjmnǗ.3ÓEͦ۱eJ,P0<6*:t}b۞91@yCc keR1(7WF"S2 o=C}n N`@g*$}E]UaRt=Y yA4ؙbC"WyY 0L wx+҇jѫ;0d:+aBfj d<1O choYbU&#+;ȑFW~5}jȷugtss7pqoؼ*0úqy9Xfy 1a767[}u|Y {fLC( ףqS=D^Mx0 &L qC,{Eİj×pwuBU9c41rȾ:Cx#'Mmy\a JcvPz%7 )}˯>>|xR 5;0~/b8$Go3㊔ n_`!EP95FBcHc.ը =.7:ntUw;]sf׉Ň Buh]^U,)@w2]gyiM=Zun7``#H3!F%WaH 6QY3#}1FJ1w.en @+!a:8 z%mp+;CIJ`NMKCTb!>b0{ZVkp7#R!ı7toӿԄ9L&L‰6xp9f}qvdZӶ 5=1F>O/ִc=e C3%#mJa<;mXttdN-1D.V[BTb9Jh|ơPkiX"nl`@=F;bTO.钘P:)ghdxl*5 Am5ƣvތ!^ D8N Qb`qB|80htRLYbA]}`y6 ]k7x˹+z֫EHΌQ9Q#}EUѢKuMMVoOhVONjpZz8b'`9}hx5x4Go{´11&LAG?yC* 摃=X'OOX~4gTBǔ]d.RZu"^'T? v՟7mM]9xr:U=@.8W)= [0|U 7mj_nߏ"13Hڳ2z )jh-VW<0{`EcdL@] 7.wÿӄqL &pmzVVZYƌ2Q!Fm q}`֛/Z돗\\v<-1B44͚Ezd>FYEǏ51C:մ4н\!/hpd}FξM!]sNsGǼR!+1@;r<׾׎xo0NCKC 8'<[ji cR{98YԂ8 1h>՝^4;@Qzs I%3DrDkvj ςV&:!kCUE' &LxedzZYw=˖UGxڏ, M(Cvꭷa FX]Pxgiy9N0DONYt[.ZO?>՚pct({Vz8 ˹b# Yb5z?Wk[QoڇU69r7{ut[ՠ6jpC,LCCU'-+ե.{ CPռ 3*{9k:8e2H*ڹ~xp mvj0=80sj'::|I3^Eex3:Ь9#EX y,6Ps~pQt1Ňb҈N0a{1pHHw¼8i@-TN'mk[]aּzK!a6_o1F#vo# {`y}<=C{ ?Êؽ C/|qW?o*R)5Mf8,f^ c,O>kBȞg7',~ֲ{;cdח*g WmP=s=AcjZ\? sx!JzhM:,~h|3ySc:Нwcp;!Gk}1{H)Q LJ33oȥhvjp7ofNx4beuŗ=2-lP ny' N?[p|TypB)#3mi?l4v. )ed6}cfΖ= i}1iD'L0=CXm?~]q6^xsӓtϿ@Dx~$`5XccU"f]֜Js%cT֏u,4s}> ΊVBUϦu@[9PEd!=Fyqz8nN_:W+Qqt{DXTnЌպ'̒wP"0v;}xv1NCXpnw)eJ֌ɘ)gR.[ @(pP[nX^o{j_})'̈́`ꑣ>cw#fa`8 IDAT?kq[+C۷TV8}鲥 //ؾZs1p+K}.E@LC 6K]1bg1п =(9ZmQm.pRym.aR0H]9ҕW2ݻ/нĝɧT7x1i.RAon9=L[%/5O,i|oVxRXTk~!]'cNY'?kuEmrkS(A9%*}80\nԨcbD'L0=BS}]|8b=//Dm'-'}.ҥ |\E۰z Fٻ \z̦|✶4u\%=ر2vjLr &#)Gen5qSmdȷх lj5jY\:rOeu3*rAüv QjVPgՙW ,^zˆKVzO>Xٽ O>dC6O k; C5oɼv˺[e, eǵ7 ǻ΄PXӜ=ȷ]H哳%<]-`x}r]a l,?e@}Tᬐ c7^ d`QuoN\e1ƨK='m^yhI=eV 9Li7bȹ)̲XϿd33T0\g~(t7j ?} daȅ34o ְKp50̭2!FRJȾjr)F1S;!^O; &LxOτIs2BA1S8f cbWk^%n߰7?& o){݃tM]͠:,kl{ y]af65d0 ׉; J#OI VVRU+{Plt,R"~'i{vP12 /Zn ꣊vKSbYbi#5BJ;Ssx7`gCqEuw:aCwu-s:rHe-e[ w:Բ'd6߬yuOm M2V׃'휪ra`#QEU9m@׉^wtӶFn~P0Y]'۞rD~v)@Ǵ0a„1fZ9 tgO]i<^qE\c,1ApbA[7J^ת1E|9yq!cԬJWy| !L,G#N[]fcw!>Fk,UO?^%zc4iEAZ/ ϟUt6FP1ri)h&h1FtzErzC0w鱧O(3o}ġ_s&dAMH}Ȩވdhj nի9JK>b,F3ڪK*AClпL &p ՁPc̩;>VTu "w\f6n 2{]YX'tmi7|l9վP[܁ѿ}{~O_^l|}ez?T{3d_k0P9*#Ȭ( =s&zТ!͑FkHA%>nh^s~8XbIw!^'4bHc fow+@c,O5usG/6lw۟ LAr0ĈN0a{,29F clβߎULk~)V[x`&T{C\\NǺ>  D'_^٧g7֊ֶ 1Ś Hj mhjMED5CAEcbΐ6%qoў̘3qz*aQKhPb9FZ_/j ICZP=\4ٲY*gM6\UN{OLyvcvJ9e8TyB9B'5 N;b4`^DPh-hgΞ,j9sֺڑEֺU_]VZ{MRdVKĈN0ab h;jvCbq*a:r!D*o=ȥhHE`7 ]bV5c] 5l7&_S C*̼m _;}*✰<#; "ʾ:ova`Ff5ꘙHYACcJoB6L]&-to4ީ3 wln*%̄ݻw / W]Hd Efp<<{`gJP .߿ 1jUQ&4:tXk1wc @ٳ,-2w#KsCcdM%TGgT/C>t䛌),?rfMG4MݷؙA 'WC;C̉!Du&\E66Q!Ć%`bD'L0=뎜3sst} )l.6g./i;H8.ޏIϞ.'jƾ[ozڶw&sN';=vg2o"l㛠ug: ̤GIԋ;Fňf"Ήxm mW !)u*Cu-"c*3A54< M<$D_@>Hx:v Ci;J֗:_{>L&KeR~Q8cyq6z\!F/O1BTS:_DpmJ*&ע2k|y8XWgum)i{DcyXT҂<:0LaxX@4C͛ذ ? &!"G\~qݐxќR /W!}x~TK(3Tb.@}devt1jӳy3pc|˞hb]%gN~PYK*cΔL'6|b%.DڦR0u"^'1};hكLyXۙ0J9a WvRf+#h- @} &eU;sQكݻB )g=URIDHӟx]P^W]? 3B.. iNA,"a^;hCJu*܁,11^3JsҼ͎M3\ #Oeǚww*1{oCL\(`UMWS &aMA* rAx0w23ܾSٲ=o+RμZuP]Gfp6.{͛@1nyMx"!a~`H_oS5vV8 K~T93Ї{c 8'$!':E5M+8Gs1}5)w> v^V]N[({k:ЯYBHV~2`i'&Þދ|[(q8L*pGCǍj_B+vCf B*{Hwxhv)7@*G-ۊ /^],9!ž+6؅@](wPnCW[6fR)P:{[kA-t(c)9~HK&abD'L0G '*Ox`ugEe0' }u(븾8=] >҇H[{_Y7F2gV]N/j'g|%d'=1fjE 1D;D4>99MM]kl+t1a%xtIL/Oz k\4xuAN+Yr8h[憤$*l궽18X{3{]ً&1*&~!G9 c\1)nq--NL1dIX7|6?}83ZQl=~zT{GJ4(vatƣbsH?;+u_'e¿eooz}&L0yC"~$ <^hgp~kE޻If{&,>gS:XoܑLC>=[=mkŪc@ts!'͸_gjٲ}ȸ<@?w YE*7>}9i;glʅ鄈@,ڬĽaɌ҆1;c4)Ȣюxt%~Ϟj)c{TθJc0nΜB۲m4i|@FZMx-ƫƌm`Q }YpL7մ0a„+ e:XeRcX5úq<ɷy\Cc6Pg]B ?CPLt//ִ.3F,Ju#aXwsgm j܁ro0%kzu(#n1@tp9']g&?k6-'?5@ż>RW⛞V5+-6ÈqrGTJ܂&1\'R|LnuFDсuf()2 f& Y#(w4 B}Ta,Ja 1yI7rûc 8֏=3}Ʉ.୦ ǘCWkt}ǧjj"kYy8<֣>\~^F5_+|rMuL7ɬ4a„ ?BE>e{-2! a 6i[Ҕp,%pVǓP٨F5ոzQSi<8ǒ±%M۴ a COoFz׻r~ٍȈ\c]O5z?^ IDATDSPG Z|l%NSno^o>8W -ێƌOc48VZf<] ri_yeG>:*@S}a\uxnvMURT8e}48=b{˕0ԭhٟOQ:^6PCP:֎ƛ)ot͟d$q4*Yu:%L>vn={53"&z>uSt赌[w_q!糩,]uGj2z|xgTW/֚j퓴a6JI:9NY4);ʓ tbo`-^⇔ חSO i":a„ #Dot^麽8JHN>)q)EKS4ԣ/ 6trqמu"RW; ηv)4@*FhkS6ccI65TUUx?M;X%IyNl'|3NpvYw qM?\ c)@ۀ.O_ւbAbIjKLA$N]}@'21 &LE'Wigl\XtEP-dL\̘teғ2%a#y,/\_!Ex}yRvCROju1Fbtk(ֶcWZiTck#)u h`]:L>V1FI`O&Ctm+]hJJq&suq:2.‡ Or;mE:jr`EtcS剮nǪ.&?^@>*(Q]UGfnn^ՁƲ x| QsƵ`1)d\ Ijh,i<;,߼}Y4 M;$hVxw@80w9k9ÍnFL*ge&׉!e]wg[g~O'/&":a„ wwq@c,Y"gp0нƌJSh2 Q k @B)BuTa aq34E*hv?1|0oM e)zfGrz='Zz|Q24xC;GuI)c#*c%wP@3ȷu۰$+>-J>ge-qg c!jxXY, IXyc.tqgg eCoim<g 3O~Yx`8n@7V,r_737uM)¢4O099 ;7,kH wPf\}p`~ǚDD'L0#wj~^XRyǫ5o./I Ep:jC)ع=ah>13n2\YC?dAEe,v] YGKዳqE cȓ>1jX5`WM e4Gz>e']njP*LuR"?y/iL Я[vul f;j?U԰Z5*^k9~Ջ:Uy7VCF^ɨwDIW!8IﷵVԤGEqagvLk2&":a„ %l>YĮOM"c< x|Ęxj=#9Ϲh(~*jʌ9I`zpH/*OBhK$y|=.&SSI=b=ahIQH:/.t)ߔrچ*K۷[HelY/[͵,QD#NPxM8mE#OI3z _^k۔n4+^V԰wb%a}|rZ=]!auEZbcU dY4ިUgu(cS \W_uNIB7S%t{T*|^JxP}Iޤ]9;}y`FZ?f&W Pm6j)RBN׫$I+Excc*xcz:;i?dv9b`=K;}i Ƥ0a„p ]?OW\;$ u܁U}xg)VoȄg^!;AuPuJnCKBS]I`%f" XzA6N{uů-M?-l3=EԚE-qHx /VaG<~*OSYV Z6Wz[nցUS1!yEN @8 h  (4MLj/| 3j?Є?c Ʋ)<Z[p,E?txgu+B}QCE4J:#G0N wJ(J9g1䬦|+Xk c]<1` a*簋NAFSY}qP,cqB1C‘Z:?91kzJ)~z6C⪋>mw+2W@~`q=NW (OUp'\L. &|D:HBb+9!{u8c-1#ƪюdj^\vOEN*m'u$GvY+D5pnL<]dsSGw cW}GRv]Gv +oٺӍvjƪ^)>Y}laPscG|JcRyoSvc50JfmIa: Jt4#y˓dAޏnHZJ<}ݨ|N:cLt)bbhZH䃑]PeG|vGoZRڔI˹^5ckN:lj5%eBS|{5}uTwW-qzIi6 ņ]5]Rcꄟ6 &|$RX|RAJPUttZعaCOA2dbJG W>q űRTBzNT8| AI=r)BW҇_ỹ7:dfi=tw_Yj7Q|g0O诅z%1 4 RHCPÑ{I.xY,W.THWӒ`0sVQ:4xnu$1,S1IG-gmNsηS=hi8(쯅]2:Kbհ|I)e7{sՁ ÐaV'`g wN ZI+V0;3cz יYExV!wv#qYK}hpgÐ>aeE8Ew`0lݎ墦1}҆-Z‘GfPU[㹤;9 TN,힜3s8k< p\lW?hSaC,Rym]& 7R]~VCzڠdy,!3U1'L0#BB[yl캎${vV#x^M/UvγN%t}%/o=NX+%iJ4 26y^_lմ\l;| WhOQQR4K<XjէVr>M<ZuVA4Wc(uTĵx @c?[XtY_%%X9{lp;5chzԀ}GDr ⌴lMDޏ@MGL!,jX'O['V @#)xlvTz]lZYҮS$F8^\C"&mdT &|HuXZJ,]GF`J4u`sb^( 2FY4gOc:n,F-SIH, ]bZ^_lybIIFjb.7\F_i}#Nhd,z>}l1bG x̲LOQ:@]|QbJ6Fi=Fj:wQ]R5W 㿪Z n5[E˰B¶K`_/_$vZ׭ SDr|nA)iQ|d} uZROYiyu6*6Au>&cSN4Շj  &|*gX-vAw=p.7 HR&$z5P{P,m X<3:Tsyy,}/N%Ձ5*vrIPmٿSr;P㐄OtUt 翿Q](;(\?NҤQWw]$f%8JZ] XO+{ӯu˿xE7D~֜8;[cW8?o7 _Zl53|9 IDATY"|.>t&K)&bzF O+貾길X5:a[-ݐV_[$ '|ʇ~s)ܫ#< !"i:q]o#>xK*yV 8}lZZBHlwc/5{1#|bVxoI"lwV%ק+D`ժѩ7DC'1ՓDMǔ }"B꼏VWZbOxz4I&|6??:&L0aIW'm0v.>H=hp{7*WDhuU5tmxyr˪m#b@ohP7< @h9X5A#4VbED!de@V_A tu(+0="iiTu$$9ezoǠ5<>e%U_7_""OZX)HQݿ F#zdJ4zbUX-ngZ$"p~P$$QmČFWr?֭b[&#<1'Pja$IW@4C'N0a;̘`MPN،m a w鳹,|9N&uېrb A'w( E5!wtѶ}/^V MTjAHy>N L1+x>x)+}lUKGlN 4'XonŗklwJWf6ɨbӁK%i? 42,캄D,F(?MXA Kw[BX/{i)h?<_ISIw[@'ǏGMvkP}蟲VWi.&R3LYXy) I#:a„ 0s3 mX|(9~f|_0d2?/ pȷ^BauefpޱK@wٓEePX65ovqw[ʱwncq]0ꇎ6y왷sӚR! V8i+uI3K; b Lȃ"8kXg 8 ŀ/  (2Ʋl LS;Wd~tyg+18(_Ԁa.xՑ:o+ur'v}3|'O )"[~ ^lA(E~-o~ZCB->nвB~+]așgEGəݏVH|/[Q;5/\8r&9Pz/sAÑPaKgݾ# ԁȽ՗/x:߷c@8Xw$7C5INd8hVN5҈!W2Π<F~~Ɖ/32MD'Yi„ > Xk)j~^]|YWhwzƒ$pj|ˮ__ٲ:i\5jݾ<]i~'xŊgAv79QOkTa5j!EʳEA1FVV57&ta[yJz˶Z%wv1:O[^XߞoF!ᝧ;Fҍiv)%9iKLez41橌F'+m-W k^sb% 5=,^sM7'mۄ`S[y"jP4uhTF\Ţk.*aUP;(/H)=)7e8[X^_5b҈N0a1U#(1j)-BEn4T47Zf4he:vQ?,>p<޿: ߼Wc[Ҕ^s?^O)%!!ggn,=/"\uz?B!F89&4&LGPi%"ѕC.pocp~H4ceu\^?7߽?]OZcmGc .˯_ڶwc=~yyҲwrYMٿ`wօ,r/1'$܁Ej AY vfFjrC<@h4KXx ߫nK=O<;XKuYV\\ݻ9|ӆ{r3dqաcP:5?cfz=j7P9J[O+BUqݳ7ཥ:tȽf,,U038͆.%k5y{*v?v C<]L8gY7nX4{dfX&^-FcHMvQ)3pnfnʽ`(|3P -ow\Y-`vC{9Y,^^c3"rCgK'D `)"d)x2`("3^+S5 g'K<5~cC}}^!9SL!f:^N5yL03Hy"0a„?rvV0ܒ@gX>3\Od '-*Gf=tU7Pr:S(չ> y-xI2g˖߼~×/,?kX~Zoݎ"b}Ӗn=|S^:Ly_0K<+wEuhB`ΤۤӲաƻw! u,{pm)TGթ]}YbQ9˓ѩbh T8m&4rͳ ?+_9{E*$9cjaOz1G~rl Veו6]eP@ VpPZ6ێEY@̌:,T떡Oti,]&p)0\gaZ|/ )J*\v<ˆQ r׏3 49YҽKxV0a„?r88)>&S߂y(:8wo2un3Y2yl$ Yt²)ӿ-I{7lߓ$Za? 3|0w?kpsCuKU`a3r"? c+!SYmJj}oV:kts(h51TU@8tb˫t'9 }$yM.CG8,^يe oC)t_q' ;Gj( ^30dI3~PBh#`"rV ěLMXT?Ќ:Tuy(1c v#Y&~7{`?ǞY`I9]GwI0br/\uDB'0 &L#("[L!GgZ'di%e B̢ВRU4dw]rE/u:q)6_g`JX5U5:_qZݝUR&Ka(v'|/lfwu(s[psC) FcF%o;Ճ‹mS̿{{ž,W¡UU]ϛYa` K)?Rl>jVi89BU0 Ka ލ=V~¿DD'L0#]n(`s bp uV@mM C:ԐP`aL̔,kHC&$xx7" B{^ړN1_. z3 "NCFJ`29Tph8L閅gVka#@$l3B9*?KBǓq 7ϔ[+){"G4KsUFٮa`bQN |o(-s:Vo m6h1Aj"ma},0{ϯ HjB? Ji5RoL}Iת5 830I36{|=9 ǣVΕoo1]i=HW;)>zsG @ C_KU=H#B5cHStF53& DU$Uz;P?Qd0^ RB R i1[)qD*- h5X14>EA|WO0s:%rlHJ.~Έ>HNC×(f9"o4Hm]j4=LU=IUa1w<^Kf"\p&wq@Zc vW^~,Ua|$_||HbhDg7d Xk{T/.6cv{mԹ}ϫ݌.@l'\;|c%tymiqǪO7Fd lh{n N.mK +ط tf_2NY7MD9琒0 #/BE fp)^tA9\T&'Ҧ\z! Lin8E[/y[ J=5VX/"-'a`oQWB$HVQuq3 =XqOC:^s__{hn";.^JUf' [7)8RJh4fLj LmEq"gV7O"{ [ŵ\6Οՙ"lʚo6p.H@V&osR .좕 /'e?M 9;;Mo =ߑD8 %jԄzPH}mt)-pUaZWΓ$~ yyL^7_7'6IF4 ~R]TuP jStsSӐںs`34JL>tgd@.,F鄡Srl; L->KgƻxzaAZf(-ntekb`nCsF{Y$u@zAf~a m6B-ϭϗq3*WMl$*@i6 ]w1߹bH7glMO7?P"3ZUdnV}L.&gf  1dՓ1OoKs/ Y(WχvB2 R*y((7{O,s ^.Pw#"̋ݠݺGROߗn2:ceȹ9qBԼ TtT:j.^ܣ? LS|15 D:~G~yFOՓNGCxy{ #>U:>o_KU7*]>mS {?܇ ~7ru#u*Ƥ|")c޸9M\&QZ-h[+d aRr1xn(nI\rxмSbϟiѼr%}1oNS' 9+‡?#"Q\;.EQ |y>YSU}jCDZy֎7nQcw coBk3YN.I^@J- PUɘߚ.mPgB4 tnK3MjeX%茪tFE1PM(sK4E$ J-ϔOInߏ,~2` oSLUfEİNLS[f۽5}&ɀ't2Cdfmjj k?(Om"voʪ՟x50Sa3Ũv?OMAoT͕rrљtEM6:_iozv)|ֹ{F}-T[lG %^*RxGw_SRR} cmQMć/n}>~ǢIIDAT+٦*zRJ*U1z]4eݵz4џx5Ьp 'F,Y <{ˇM[[!7 Y05]緦^7"\?٢fSg#0!44̈́ ~g$Z|^M2ʜ| C~ ƾ3@"h) d<Ľsaz8V$O'sp3ᮐWXb"@JFSUE{[;>|ywS6J } Η^HψŇIj#o VAƜs17SUy`ʰrgs5v3rx]΍F̊t =:o E i kVK[wjmk;z nĩJUK7힌4uUz΁*s}i_J" tJmondQ)M,pju<]M3RLJ%2:7?= <Ɓ**CkID܇XAx$]s g~Yz[pSP;7-cAMG}b~TLUeS6Lm梳41,> <׌&>xq0d>٠7j0?>A)\^ރ$l-G_ף r|(3tԪRE%wɷȻ<톏>9t{!'e!=t'c\5'ܡ'[ݑIY'* ?O{o.7W3zM~']9R~oCO˅ϕzT^#˲':n~fbtf b:s:)_ 7vl7WkޟM|&ʹ3_ ˘n ߝ$ ):5 U5/QKIA)>aLq=P>o'5mOQ:N^-Zf6=U_?ͫåV#:^yHJ~\:',V6f>;=x`]_O>?;i'ۭ釭ARntx>$ޣjUw~qn_:wW3j52(j0v;u ??Z+gJ) w_?ˏ*WU=g5^=Rkf?Aڃ? V5-?tj =J 7AmQ .J+(3"=@mKdQ6+T)'e+䜛Px%}1GO7;EnrRNl9-JC\?iA=)QO~Vm1# y@vZ:x߼ܨ$)1fH]@N'5Ķa#HDZgUq1ܻp W 9LըZǾx_y=[71`fȶjT )?\!hAs572e.B(O޸J2?LmL`Qq~;鮴{zưju'7}ތnZwD.b.'qu-9`dfD XlDVvưvzvKrroaȟrwys:<ľ}5mu_|>7$~+k5?~' Ϯ ±X^`|: ǜJ6-mR*<6ݽ<q}e@oL2FRۉ IDc3TZ}"Ʀ3&sXZ:O%ER9$ aZ?870sajJYIE9:h=T:gqlքo)EL~Z%;TȭSoˏ}4\nGMggCcN9?ϊHj@`-n)5 >cgTzouU!m/9q#AQY=fH$ ,\Eͭ2FTEfӷxރW>9=WZ&Pe:_:wMZkssav _'5nfX|y%+C[[lEEĸ/N=&\wlixd.nEs(&AO҉'>TQY$U5[ dR5WA$5(J~L^ F-ҩRu;J[2ZڽYĻͼ2=am5y>-ͽL|. ?Wt,T6}$%yo %'ltϮ1SnnHS67iPT>/⏟>m ڠjTUW~jPOVilXU޴xx=9kεYI~8 [SqCC_BA_:`gۯUVPgHJ9,+İ(N! 13S0f= )A3QhvWiMCʓ<m尺ME/^O8fRG@i١7‡[f?i(o6ۥfni+R )a34s&$ت1> r &P0tF^;afqf*_M؟7WLL4G$@木G \&CnF<4oHJ3F?ScG)%n?9ԄHI'9T5l|i:  +q>%Dشv Oha]hV;֮zL/E(9O'R/S%H9]7TזM*JͪQgehθsRΆ=TxP2G#ja*謼c'o|:LINIVC;M)p|C[tQU/=!D >fJiNⷧ ThJ.S/Ȣ'Ijzo>h3L4sT"'٨vŎ_aI}VPzpIVML֣ߔaS"?^rR^֪۱ը'ttAN YMa==Aגf('IȧńP5C:CĘ z]j3u3G5& Luv7;rT6wPP3vMLY Zٌr)q@gn^n^MmGly>+в]֓WN՞"hAL6z^(Pf**=(^gc3$K>PgЦsWwS$wS p8VD ,0\$ P.+SE T.}X'PgcߛWK1cKh,Mlw >7!D 3uaHo0+t BHH]bHBMtefSTo)oZV-OT[h^e=)TܲIg?'ЪY.n2@R X[ٛJO3`1 0#n^QIݡTou K  4Sd4daΆ^Y tr5`޹`0wܷcSVŨ'_=8/ ebn@ fS tQ:$Fny I˜ښ?sA ⛂ O<=7R ߟ!D 8OM2smĐn!V vY3>ρI<uJ]t&'=;ޕԏ'RJ~rI;O]aH.sja !D RS$3OMdtz.SiL/M9 JNɿR/(8xߟ>]O7J =A !Az%]+EfoibQۡd$FIH/oASt{Z PbPrײַ̛".hj`I#B4 $*3`?=wL !t>!Prl~)\\yզDUOLN^7?AA%P ~t_{J$+ 'TUTuk)=؇  jpiBvgOTϢl 5@= ! ;SJL^p'hA|Ej|I 0UX%Vr2 e6>uN6änSJXe_bBA5.d r C,snpW>y5Dh$hA|M13$)3porYlưO%hA?mJֹ|tx5PX|BAAv$6+9%w#hA 5л@s|O   zB4  xBAAB  A!AA<!D  !hAA   AAB4  xBAAB  A!AA<!D  !hAA   AAB4  xBAAB  A!AA<!D  !hAA   AAB4  xBAAB  A!AA<!D  !hAA   AAB4  xBAAB  A!AA<!D  !hAA   AAB4  xBAAB  A!AA<!D  !hAA   AAB4  xBAABxAA|/gLD  #  p֞σ>  k R(nIENDB`gxemul-0.6.1/doc/20051007-openbsd-cats-installed.png000644 001750 001750 00000016422 13402411501 021737 0ustar00debugdebug000000 000000 PNG  IHDRS,=gAMA aPLTEHHHd6MtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0?IDATxk븮]=S/#A*7\$N7սQy8Ecy/[ ¢QhgiѨ_R>~,+s܎ciT^)_ﯗ.';=T?YVs;dPQ^b.yg|TLhci^q4Ns`y"||7O:ZIUB!ô9gcnup>19I 0cV 5C[1GpX7kp)1l]#|gE=*8N=r{0c+elf,\p};c4qx~︟Goӹ|-7v{qW7{s|afD DGi Tw}V%nNXh_/.3VW?6ߣeocsYz일.2*e3'(kݟMäb ?0=.s O擺^Syw`?\TG5~ޗfg$̅Ytc9̍s#"yXӶ7~W.>B7S=TØcͱt4ϐ]fAǽa}$iA?#t#ܥ FQ Fz?L1~FG=OqTm˴sci+J'?.hl)ˏ9_C\Ϯ>8DNzx5XQ]Sk} ϓIxL7Wr cy<䋴ǯ%3+u \)WY77JʹJ Ne*yc}^B]b PS=OrTg?ٖH GE+ *m_ -G(E#7t)eciTٳ9Xqla{Q.(+s#\1cTb8i8򀣬\H}y|}}qLku|mW2]+1ؾ,k!RgQE'K9=JKXnךs]Zk joŃŋx7^2;uQ+=8J.~uԳDžc]z\{\7sыst9zq9:Gsst^rĸ'ܦ*^MgҞx^WyٴU5̓aWw9'8md {oƑ#o(ꉠⵓBmC'k.NS dszqD͵cnR#K糬@#X3xqa}(aPkṉ=ի G.I[/8%rsȱCr=wې#W49sxG2@ts,݋#v>#xWrdvG>Ci GEƃ(>Krsl!wLs s_<9c2A,|z iKE W+w;s\ff[1>z/9=9G/XhxS|5M?s5 8u7?Stu3/yF?y FLmgIeO"0hB$uo tۍ{Hoa~MX+>97UK_GR]YGݑɿR|Ej@T:S8rNi GhQX]moglzNr;^Gc_ LUs ?]}X GѰsʑwU5/Ѩ}oahpC96יe>FXڥFsij}sR|8{dibM./_x~ݴ|)ߑ-4KK{\7s^4];ǿ8^/w칍O R>,Ǟ7.Y_D3lZ\jl0p\8sTJ%G>#w8/Zbto.)hi._CiTc9D>koJ KCqy`6ͼ8kq]3=;z#t~!\G 醛ǡfі(l^anC?͑Y"/rZu+_${QG:fgGd1Orj+_G9VxUU.y?g-GȠ(OҨv`8NqXXJ 9_#u#a88rt?uGY 9Wp:3p@//}N7v~s6䃍YG!r\H.Q{!պ_G7RN: c9^u^Kst^stыst9zq9zq9:G/9:wi6 >fƟPk2}r/5đ=vWo-GvR: w? 뼓WU*}nj7gԷ 1d! -9y)wc >+2'^xvSrfDGjιa#Xz6˹ޗ^ǰ.83$ SV]Y-a#n'9d|HGX0T}s 39>B}>GXǹ]qf\Êi#x5l6y=QŪ#530kz=cl=RFl i8Q(~`j5i8ُ0|77=Tz-~6ø{~t9:h[Grs$xBXyt$;^kb-x :Mpds,=#\oXQ?:IÈUYCuL 'o$x߰>..~-.W{p ~ݞQjMs̖MHlcxwj#9%m±YOM&/]']_m±~װuҲE9*]'I9"G Ӯ^ {IRtju>nI_(q]3SC^f7mtG~ ǐK9x.޺n{rTZ,:ߵ~?*¼n>=YZֺ&l͈xI~\P=9a1<GXs ڣ7cۉH)e#Q{4C]ǭJ'tN|ʇ 9>Y}Sk3M91.Z.0eY-bHumsjȄdal6y16Xh)/]J F猲kFXQDzf9cn\aڐ#EnF*IJ!dN^ǓDair#Κadb1:G<?pT1dvَ{Np51#96^m᥿ޗ|Ԓ:uT(/0h]ɩA0!vNrdW}uѼnCM7nm~kmVs{C+ıNwu5zHBr2JP/uz4I緖Q8xum{YYJ$WT/|i#? }^qCLV}$GQ8\‘{{sM?31H8B͸}nϩqhWv1r p7Eq8I~4~v8ǻs8GQy4? \h@FYU.{UyʔM}+}_{1ɒ'^WfQl8zUR {'iG+;8s>l?Gu_O:#Q۷-ߘcw&eZT8#)k/|v9Ѭd84=n?^# 8Qq KPַ<4%#.e:g^װbGQ㖙 cMG 㔻Z*I1J?e#r7, q(p+sd,J.lM"TWy#ɕcؑxf,.q(#*GM}ĺ'uPScIO1HR] nmjM9b]g~19ni8G~c}Cm r-6Y4em'? Gs1FH-- osK/DZN+K9.v%PG*5 {CamNiadTzbY;([Sۊ`ESA|菖c]]LzQ-6q,kOx菝HB~n}Vq<_m{"~f!E}9G(qdՎ{NmJ%UkP~m<8Զ˿h[XUuG{8GccB̋ ϻs^8۹=SӾjQf{/h&EH/< D&Iܭ8G&L&Qa~ɚ&!vxS'G1/%u(=/~\ܭy΍>X'-LLOG|U8+}#so?%Gp, cV`Hsμ:GG/y8~q9~x$eaQ&,- /)eYѨuҢQ٤?ptIME +5sdIENDB`gxemul-0.6.1/doc/20081103-openbsd-landisk.png000644 001750 001750 00004254731 13402411501 020470 0ustar00debugdebug000000 000000 PNG  IHDR8JYgAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxigU.z5ФC'f !L9(b40|xQУ~G9(T B&id NCߵkxֳuyN ~gXko~ cJ@@3a_ƛ{c?` =0~ H "`'!go/@,E $, HXNYYT Ms$=>zIXn- ~R蝰 3Q @ vA1GA\F 3)7T!ƀ77(Lu(lg(^%J% ALYXD]c˯@@DލAQ pDt-hc T 5' 1\%~oZ HBk=2%D"{~w0"}0k$@ jH&NtSxxi"ݟeC)zZb":RDlz,Ɔt,RuVrն*B O|$eGY' øtF/@D BN#.P+ 3uQ/a\a#x1밍j눋ۤ9^ᇈ"{:,1/eӊe!ogXvgb#>Fdu"Dt'" ]b ²(ՋC,c c)#JؗVHu .{ܲUDhQG 03ǵqqpk3[z"z|7PP@w<2!D#D$#!~E "K#cQ0m,B X$>Kr#@=I;8@b봰A s|[`pݚ!BY_l!V_CXbGԍЗjVĢPg~#-e"̤M5X-T23 b:[ }R[hW!s 7ci-$o Hk<%zؤ@HDMC",m,N&YedEE+h+(Xf4b-0&>" mA :D#k/Y2>0C|>% lD8Ւgu .¶2i\^PE70}o链-Lo#K@ h~y(clCDWpd>a=иeGoW\8 `$= Vj(Fِl1ƈT+4` S'bK~*B>$XekC}eQJ^}C IMC =cFn*95-F >>kO&,O+,VqODD zJdb!%P,% %A!tF[M!mD@Xa(dnYnnsٙ6\ቯ9ؐNMeڙĠҷ)?UcYX*"BhT*%$M=[\!" l|-93Lu"k1Ȗr*,i/&zEOoMJ rn̈6ȉmTR46+i4-N"i,"+VQx'gC&5Y(\#licnK%?L3<1J5"VI˝PçGU*%F8\^x$zJH{IF p(Y,sS` ;/-8)2JRkATVj v"ZD`m)RBD5<([YRO7l= ){;9>Ee'".Jfc,Q(UV=&*x$EtrkCYrE2KA*QL(ɣ!]1r+"(IUE T^ҢAEZh9Zo­}2JQ)h *ךqJȴd(u0DSGd)g!E ͖ٓLX-}bt#Q_u\ڀ)XRǒI/9q^Edk[+RUxcC-GmE+7 d4"\Ѵ|P, E4k.e/8f(kSirc,>GbE 2bjJb"!>uU+'$Yx~rH&vnj'OU$ctW@57կE):Q3*ԌNPBRYh#G9]DI<@]%V:h$}ΈB ,4vjw#zl\`$W3aُDR,7,Q );nAc920.ea*zSIŒb*b@A/~D;J$Dh3>QFcAs;Z O XEHأce lynY;T+P=1K#M$*X=YJP DU _$SpPJ;x v^x+pTC-{JhJ5b4HԶ-6| ALeh]1Q7.ȹvPUd ^aCf59-Q9Az @5(ș{6JV1 (A!TIEzc+La8׷@gx [hg'0Uh nqIua0uE Q*^M5w1i>UL޺G-6OX^iFOPA)60?akUrZEgm[1E8m)} e3\.hQP5ۺ`Pc"(=ȟ!L^ևT>-l%+ax  ۥKsZmx%(T0;Cp^ 6Y)"-eM(o) ֡& jd]*t OfkH-*EDYz戚JiVr85">Qse)7,`"$Dbo֒q)>Չ™9=ӔBm.8P1_7"<[R_0s5-!mW1#5GO5W%bqFb8 H>6EdE@ZAcGϕTXa(PVHIP"b!@jOhr*␬kxɼYY'vX;J鵟'9Q8Уa-!Jâ] SvWp@)NzJjw,LG;l FڑJDY[f; 2#c/ jDјފrS6[[و!h(kh@)d.U2`8ĵ%Vnj kVZyFArmY+4.L )2%6T&7D {0||R2 qBAŒi(W"Q%n?B8(.8Li% ^rEUu:1B"QՁ* &T8".5u/Zz\%*DBPeS> D{lu) V+~s Vo',@%˜Ł^y>RT:Έ\4՘cx< y)亴&]GKCT|P>=i!eXK*9ZqhR1OLDRg 3cXF8ZbhR-h;ztKvo=nvFA3x"- +-(uBaZJا"[<5iٛWi6Fk\E+ J[j#STW0399Ta"5`ũ-5_ rVt?, 5ZLIi}%G%|q㖥҆N/RqWUI8*{#u%┱Yefb[a#1`H[O_nc^(ODcP20mP#.k%{3K-"€Avk=}'L[ MɀXUQWJˁ:J^CID3AJڶdj]ї..nkLmPŷf)DNp`ikDtZLTѪX0zMڧy1L\yXFb%Ġˠ5J)1- \,.ۣTY HD +y6ƂEy8X4%`ZȡΑ@ղa4֙$@;W&ioj=Ѿy#@C,b)Òg z|I%:X7VNΥ?ڣUXvIIl RvR!'uR e.&¥)xPz]"12ҁ\:t`ħ;|%il$D' ^,zVXxݦ!7Sq6 ~߭ E,T`4gW5!Sng—m@M'"ҴC0H?r:X!VRDk5F |"K uzƊ),$JaS֩BѶTDƢ"l M7@QyV831!UB5GҮ ;9ٻ y mB%+AĘqHbm,Z0QO<:엱Q jE@M!]@QĪ R FK[,r+E6 HE E:i֌Z jȼ|I x3.#78Q =b\@UphD5 [̡8r~w51R`sa}@PRK(ER%%&hW 2b%x\PQP# .qYfB˹R҂#ьMb5 ffƜ2.-j T(F\d&O8%IaGU pHm(#d%OQ ƀY4x*~hA@E [7ݸ9TL?Jׁ@ gahm3)0`0t:n!"6'>0n87Oz_ufla72Dˎ1R>m P5G2$26 بDAVuNq80X0@0 RR cғ&f'V QʴR j!iA kjrTRE1@x)4S%WsZ %f!o!̉M_W !ƅDxl?g!!۪QɄG!2$UI{P1QZV5!0ECri1 BZ!"FlU+z^r9q%6+O'y #p-5 s4Պ:[:Wb嫖07c]D[IVPgm8'P5kHCT=.ғj(aD:v:ꨣVz#gSQaw⨴aܿ@%ӼrWH5wAq_v$ P@m|XrKŢS63HC DZdMNPx #2ւkot6H$K}íEBP/pM`2o2ꗑJE IDAT]=hMX:@ 6Q"R/z+^Tijj ( $=h/LރNo:8׭[0]^^^ VcX=snWYH׮Cݮ:06Po&z/uՆt&E hQБi9aDz3w8xܜSoS;$U1H햭8-`4q#O6g͖XAtF:%c&/S _ SX/..A4[I7ך4FR)\~sFb=84D[j$iPdYO5`FX-jsKX*++YAc( dXy`1ƑY{FԸ|κWu $o !g5a%]X QKa4dPC0I NŒ =2MX9=}9rePث)d6R °Vor`-!DɈZ3)j(4BF"DlAdh1XۍigMPCpmPA$IVBMV# BaC5$"U-\!\E#vE#y/j3g!eo])2z>Xm?., ;5q}ZFFV,dvbtin;Lt_ VcX=s^O^o=|kbݺu{tG ~;@C; é)g>~#ٹs]lrgzgy'''A~K{ / \{۷oԣug}Ӄʨs_䲢HrLr26gKB6+嵰xiZ(m+M}& fA23\Tѽᰈ3ch` eB *>dӊ g2 dH ʹ^95HΒD oEQMׂP% Q/n3MPCCuV=A(9vXɩѕ,RZr $2;QCtF"k/Af.'TqND\Z (]pJԂ02). 5"Zs"}0ȭW B#ba  ظ&&Al83QCԚt|ty "~1XDGQ"YN SSZMQ,ɐՉaQJr #"DE* W6ö++! oW ɔbę#j 4*D9$Tj$RN],!f`wo6s~?כ~[XX-Xz=-=M>fga[5xHcMy^cX=CM pC+/ǻNO<~ġ.[nm#_8ܫf}bꪷ'xOOuQ _.³:)~FoSN9O|͛o;wܸqg}iJ> zIu{tDf\}JjKZ9:lha * ' yD\liE>ub)a]:RĀg:Lc;HX{A6wd>7 lfbJ[i ,K6,U6V舋~7rpC2p!D@"q|isfkIYPEP̯• K}\'iRpUH KC`wԢMH 59nFn]P0ϝIUTX ϼ-JtX6a;PmrD~.՜p-m kL&m`LxRc'$b yHr!7l"Q5* RCrdJy >i`62vhj0SujdO$V[|Aʬ'SԉR%Jtcr҄2|1Q>Ot7j4pRȫ"4 (ή5X:mKq 3*HBFS8/2V[r=6DO;--&G4opͅkz0^lo?Ba7-gُ|#'y/;rW%c/~03[ş|ӟT>}Ŏ_/}=wfظ;9 .Xs_|?6opm=r3綮}[df7uƩSŲKCX w}[;g:,loy:U6\*Ks zgiKX*TwlğW⤲9l50WR:a)Y-}7~{Jv=_ÒB"b>cJtf*9FBq4/Q(Kkm@*f^ 66 3&Q2ܔciff!$ '# t4)Tl$@p0ȒmT/PӠ9k< 3UVMpضm4{~_;ovL," a78\ؿJګ/wq[lY oO;L"/moYdx_Ͻn3ٍG褗5v:@tYǟ=Nx޻_}}sdy߷s~/|{aNn9f۷~J;3~w_W|7޶̆-'<F>N9qc7C]Ϝ~Ʈ_#ck;=Xr#?c{ƟxB~v yE8G,n[>fw ] !gnJođwz4~ύ ێ;M]ۛG|o?~hH7NcɁY: T6"iNSt9Edi-Hk )jE) u taAzW$JVXN?mE911ֳ5yJa[zx s+݆PuřۖuV!敆{۶"2:$"+r['o;zLt&  X{ыyHHza^ZZtx'?+ Sk_r >/_|yǿo_򶵍g|nϡ͏'7|O;e=Yޗi|^r/SO{Ї~gvoo뼷<ǧK?|OWe=x?/_|Yq}{ԙR{׵-5<({oc|_~Oc۪{+w&jo.IG:@cw4w~vm22֌o|s`0v{;~c4l njanio]ۻGnfvE;R *wgAе%B+Fi$B$s*L8 P49":O Oh(3,K9!}acF"o Q#6SMD*"Yp%3E,@$I+4,390j @VɔVX fh%$O3]Ӱ$6EwJE[/T>t7N`k^T@ *S>'Ϊd!J뭫ց&"n{C,mDphE)2NneIyݱbFJU^&V{mRK+LQ_hA!J%*!;n%զ>2A$-k 'Z)6}aa_}pn1X(шb*o B@NWHl6ֻX,ɥyJc&'cP7E6b%ύ!b z. d<d41J͕ol іS /Ԑ`rfDh'ls\#fC7Ʌ'TMisFrC_XFeAeC=wǝ7vpq77ߟ ,uWzm;~ vںmj0w;:ٿpUq+P??:xO~ΛxQ't lC~K_뾗'puW]ș!w ;13i.CT]y5޼upP]|\P [-^ZcSBoɓņ:cZ!Y:Xxp&$.;P JAYCMK"#bm1\ԺJa$R01bS4jP17HY'WXI7%`b1s8L]){^J1[e5|wd)nZHc2Jhp.LV(S9¤ЖESҖwFjEb^Opnwi gJaت@z%"ΤK$FbX} 0 49$y+v6 {6= <8K  VjPJ` IUny4.E#$u4;@jS@}vi]-biŹPѠz 7}I ) ["^2E'SYF\JXD! r4IBAhВNLP>i-UdFdڵ΄T9,C4'zw]"?0mk'&`b~a:-~0?=ň[6liM`& ΐЈ\Sw36wix3sGw~=9y}Ŷg"3k:|l'O߿dϾo>۟?}/{߅_3b> |{٧{Ͼoo/<3 _¸ocHG\o\vN?Ӟvk;M&''^yqbӟ7~86{eӳG{:iz  cGO4[fZnzC vw :ߞ1tpr6؇Np¦fsn7 w;nk|vڦ Cs4@1k:p /)R3!*D\5J)1:Vr4j6V@(J xi.)R URMw ahIKkIq.2z@0<2?,I G)D1UF⮐6dM #rQM=NU& oO#GJoJo \0M CSs$hgP -z4jCQ< Ti+7d-vXAjd;KxYPBs-ִ+"4ĎYKMhJ?<'Z8 @RU{‘H2 "LԐ۽}$?Z?I3e*] SE4LnHnVI8X11_W+sO9azO']W_O>~3_}0w֯+W|3_ e682n{=G~~|A4?;^x9s9S/~?qǟ1=f94w2eoƤ۸f|fӝY:8f8F{_ӡvw^/J*hFY=׾-^P79./ (t%lQ%KSʌ( -.!b/ 3B@"=ȶ)\a6Y' A@h(vbvfƊ\Vc r8W\H8YMRԬ9($i+<3sR;`$Pd' IDATaz()& 58 o^"oø6R wbBa2E{T*=2FTq@GnҀ"maMCؠYSD9<s9 yE+A(I٦3Ŭ_vgtn8nQ֟dd 3iaD BíY?rɬ1]poTͧQDgJ5 `ŀp!&łA, lP :Qw@J\ǖ\8Z=6Cȯc lA+N5w(R_""­6sSㄹBYHU.] j?8Q1"Ɂ qJ8QLKEBmD0~)XvwRr MC56#FrA$`۶z^]nPPE E89޴&®ݻN~q?XT:-arv3 /ԝ[w]=ؿ o}K {SۣǛ)Ï-(|Uqկ|~q/Oʗկ^xG_=;z`2ҿ.g9眳k׮S8߸󉛿zܯpjf㱛` ҅{al= a|Zjuwwlyi+ ]3cGl2f:c@k&:`kx]{}VY/,ܳ~㺖xf4w03=3>dgicwšŃة"u=KR֚1sAP,tyI^A}f(.(be4r22H0޲l,nj P9M$>$Bgj»"+)^jpȐ|"c*G FAQ1@)0#VXظpQ ԸNA[.vx -!"҃]U%g,"T,[Xy1H5: uΊHR!5v1|bHUXIm&tB`FSMjy9FC6ԈJrS ΢@"Na]}$Dv<Ҧ؄$-(̢Ӽ c dh.6;ΑC?﹟kLzTOLxPfzPfS/L 2BN+|Um)B,n b5YʂQojHDf`,9W<,6p6 bK<]$"iDBu]*:~]Gjz8h_'  ݫ GcoY6e4X}$vv+(CT:M-&Óup8D81X|AQֶ2*B!gN[bʃ }"c]s5]z;{vvF2'ҿ{-~׻{ޖm[2pz܏R|@~j?"z!̭g|ɭ/nY<%}/>kwnewcs+nakUh xQ-aXmudw@_7%uf|wΚɱtq,]ן}Xo;̉{SS:۩mpf a,LE,{{>)Jx2 D] ޫ"@!PЋ #Qk%hgX'R\4(:vTIBXf)32@ds"IBFm ]⹐Cu(,Emf$w)jRPu }{.&rˬ0;\ϳ)zr1. kci^E|GϽǏ g/ZJ{QAE =|h՜J(ޔCi>AdH+\,:S=$<]sO!є"UDtD(V{q X},T.]~KDH۪&B3Cl"jɡ P6po"Ae[TL.S $I"Ū]lBøJHrba#gE5-M42 @}c҉ tq^(&!jIQs½&B:G"IuϘ4hDZ7}xmT@i6-ٸԋ*HF.̦/IVayen3*>̞i!#9䇝|/}>sqqqͻ.̅o}#Nq`~#U((.vY_zg?W/y2{NW^S6>I{Gύ87?gvo~Old4is㟾|/_=+gffU'=U/O=ltUK0"\ng]z}p_Y:K|wQwcuڮ8v;؍av ,&Xxr+#35k'¶-ۯrO:ZԀ2ԡ=7r`O?j1ss"-ozIO1\:7c]X;)\wޅ;K8c?~rzF~?͘0ob7:ps #E.hZF3WeqѳHn[hJJa#{UjVRAP)YߌnioP, *YǪ$Z+d RM`43% x82޸(ZJPKn#$FrH̢K5%Bp+ @džl0dC D<2C 15 ^>^$38UmPh (Du Eau!BAqU %sѲ,QU N Iْbo)0ceA!<9nb^)?ئb.:6ē \@UIL“2տ!ma& ꆂY`0s$ȱydkX.Ds4.y;I Go< Yn )X8S+\!]E99'`Sh2X) &k"m`SCƪ$n٫x6ԍ c&`!HvMnaPJ+i)d.BRM}ܝTY`0-Go9Ӯye_& -@۲e˖ [=xێw}scwÛs8M|߿3E%e\xN߿ʚxܺvOةcN1>| ܞo=_}kiCg??GySFFost^wć>+~3Ϭ|e|A wue\wԓfN8{S6~__{EcKBӳ{K?uI{asuڮScs?rU?5vʉ3`|yt;߽⋟^fn6L[R5lz#t'.W;8l@ۅ2~uް?BgƩOM7-tz78M߸ƫwqnnߠ:ph8l߶mkU`ꐋ0"E&U&,=Hp,- JwdleTTrA +G`mE `ÄҸ+ 7ҶC R%X% &YPbۚPgLd!YWFqSҜP9 ! > _AhJO&2͊;8p!z"FMg[CTIP=%[Y[J HqV+5Pq#4YԂJ O655d93I#_IFmaAö%@Aȸ$fQH4"axtҶڜNo"j "RC f vQYXw4zeEb?g:ͮsD`O f鲖Ic׺rXp 'YHŊ@-y_|2OieX; 7#\EʘZ.| hlW_읃%r#Vܫ&PħŒR+9h/,}IߋqIt'`Y=[N6*SqA)n +j&r'ʒ)n=nb.u)E$uRf97d͠rsȥۛEQcyiiiii zޑsG68{\S PDgb U$];;qvn\oV}Aǫ_j%WRDG~ۻnsρCN_fjz俾q/;w6cCXw;_?pO?n.AӝMowu[zǷӏ/y·C˝\/y>w_36>aˉ9G}}>>_7p=[NwuMؚMۧ6v+;G~=d=ȅ=Ll9 Ǎ6L,+u; {/3{{ow̱榧/|{wyM;vCOɍ(42&tff>`o}W>{?7mlj[#۶q||*o@.($$uh> /CQ1<9SK Q΄"3~wÉ/RbPT>z܉ uJpm8 d$:g,rH<,'sˋPD l(X6NuagͪkڠRJaXc@qa+Z2E# g#WVT2e$ @)>McW/a!vEV%,dHb .*Q[YA WA5eֈԄ>Ek&h$Ԍ:-,l.DG7! p$ [8cj̶ْ3 uXیe~;<"(.3 LHz!lX*% n ¢v3R85}-[ [.1ӑ!Bd,Ⱦ1̊ʒ}OE s2=ܪyQi:==OD'~;,7-lYoעCS< ٺܤBE6Lo~I;v<ǟn4Rx mw\Wu7\ؿwO|fQvו>YUUD]b N" ")&ERIkےeʒ%j[ZЖ5--lYDqq G$p/2㼏3D87UBֽ}N9]!cGC螦3oI9ӖIN?PzP2L05j>9| 8q Cɩ&r*Ȍi1ձBADeQյ=4 \gC#*' \QcORF׸^ X7 cͧw3I\(LHH.`17h6h A+b.Fz˗#vge.G[2[>\sLl=S DpĪ+?nvv6ŝK_L(xluo&tzvj u8S:˖f82R%1DVav&b8eYڵkxxx׮]ZT`mdQ%ݙM 8rUBQ1&-4~2 \!r󰣭 ԸRSgf`% ρ YlcVj3H~DYD()-ƐHŀklMS0ENT]83VoԤF>C ϜLҐ*9U|+`eO.L}RHBfO(VMXڄnCfY)G#C dA.OG 9 vXBA$bUKYb"/mUǝ;V`$a!GWB!(1"f|x@.Dq,O G##je1r̍ZҍQK]O,CNg@LaPvt ꠟ=\)XU(rG_gnHyUu@1xDĆGN YS4c9K Q+#2}&CBK2NFbi88'Z̓gI"Fr < V}lM15Fs$Ǽ)i1ӑ_ IDATWB)f#!$"u(+StxɅs=LɬeO94rFbdyL`" p6u]o߾=0;;BfUItm=snoK.ѥuۋFB@Q03A"rxh˗WU,(0̡* ޽1P;v4zXv^;GXrɒ%\q33l F"B7MGFvN1 ;0(=D : x&k*rCE .1q\nF];N-3#M@gҤ1+}CI:lejIM(3KKlL$_[{PjGCr{vAZJ:ْQrZDH([؅|-dTF].IR{0Ăb dW6D7D]"/i#G _؝kP(j%!>*1$y^?Dz_`XF5m#B% ,erҦLfr*y](7f)K<%. rW[ Ƃfs!}nR @qdzqncUDTĆF3GStMٲ:HL|*akVtan[gcRQ Y%֫^9[0M$#cyjOBEI9IGP0hd% bJc$lpaT$ >'Tދ30ɔ@RBa2*D` NI܌L>V k 2RRT2Rj',e1 eG ۉIeY';&q-i6۶m77hKQVka?~mm+0rh,ugfg zע,zQNkm IУ4\i0gH\0 C/W',jb4m/DY 55 \SF#E+/1Q*+[[pvEY`s#!rZqD9DdғU>E0ܠXo_Ij-qdT]kd3HjSۨwC].Ȩcb.S,/qa]l!%2x ;5(x6g7JnE հQeLͻpKyA2SR\!(q=3G(F4BBO5=56@oIpՏ99S#+[Y阭,vy5`i$,n)dOIcrZ[Wutiw6J91A\{[%Βy+6VBǔL khcA!sTLj &_<-H<ʹ o) !j֥;!IDd `Q{(AB7Xױ`Dt9Ƥ%RQPuk /t#$ʴAI #f+ Ʀ}El"Bb]DE(ɣvy^~>qK v8͍(rN6L?Yb"Y'fo(nNBH^UCdI3(YFXRI7RC8[2p?|Y≹<MklRSK&.iinВLr2J6{x'F(/"W =w8KeЉիW_y啧z*mݺudAAt[r%3_+EDJb Wɖ$K҃ǖ^VN$1pkl){qP1$1GUHi81F!1PNN2M궄e–ZN}RºJnrB7 ~GU)19׿JJR`0r2{aBʴbE! <.(U~"V9 [I9% Tյ4N1#qTcFQE1!IZț"g АkPJ:r!F0?Dŵ 1#m ` N<`Z-1'l+ 8mI"S:,EdXǨ@A<{jS9Ĩ̩P1QZ-?v!I3J6*i6B IZ58K?rTe6ރJ*kڣ+GHU(wd09gߤf'? 8pq6(+58W#uX¬|˶8Eo`%CrH"gwWIT:^C_hԚ(" *89RΔX3 )2eoOrhyau6Kkj:SU_"4홶Ҡ ڠ ڠ yH,]&eFt q(ќ<22Fi旐AVeeSNڸn"R+tbcTȚVup/P7~$/uR5dH21 [rVi$F!Ӛ5Lɍ?VVP\5T W%RY뷘űEM>]ɤ\ xLY ⊎qә0ro&#"%L牑U,sSJ Xu(z eSa.DEdUMg+n:ԜkJ!ndR^ s,kagf(c2$C]xoM T0Q$Dg;DR!,8Mc5e*[& h$sؔ@"1n\pJ # YݦѹdT|&>\KɌhjgƧQJ6"Z8#fvPfr)2%4/µW*n fֺ:֍TxzHvpu.cammPm5t0le^2&gOɍC0}dr5{!ǘQo!z_D}E#+pPIYyd2XddŎB :J0lZ l9!fp3s&*z7H'J*D5.P 'BF`l5rµt00psik7 RpnV!j|ZSD.H,(FD cK1~0kw9gpz.%= J\gc [(geM# Fs7cGn) 0Wu͎\Lum)P0w@airJC1!dQZBцn &'荓 g ¦ )X$DD<HA 4I3.ww rB#瘰:Ŝy3eEeZxjXPh37*4ܱ34.)AHGb'UR'BblrfJ>S{Rz!H_1ӃeT:i<奷v 0hPִO`IȮlȇ>HTc4A/pT_Fv-1xvB6s5WÖWAAbԬElH8ȸ1092S)f4fƀhIxRSdv38%j$˄Z{DLK>&tM;3PkfA֢j٨fXPh$G".f`l$ 9# N>[Z:ߤ)T6 S?! %Qs PF>ȄH5sWftEU*|O5t7~ Fӛw}߆k?pg?osc蛐6hnnjvJl`2;]ӗ:DK:4@"b2dopO;喗z`[a$"+V248Hl*G|c&q Љ8@_d&;$҅ЊFWԖY1^jB-WSB]U7FуB[Of+3[͈.-bb8ڇp's?s7/Se"#BPוx&;[ L@/(ښ?ŮE̝]ғn\A(6"^eVAU7'2<\s1_Yu>(ruTs'HP" 봚RTLrrBfB-7Xb鷾NXas*\|\UdzlB AB+#{EB{"W E䩊d+LTR4:. O4%%Tw1a%DN !. 6V(Qe oͰId fĘĽ-'auݞ 9TJ]jk7_jjiBP6IT/9_W=d~ۜ3rP?;~H`VH[]/%dm=ь%뒘\UgrVȟêϬٲ7zM%CCѬsjis@Rܭ2D }MpTVTAVB1&.b&}A f %cZBHPRTy FBN^KX6*oCZćve ~VƵ3 -ҳQe먤 $HISEMm=FꞐd ܿ*wm,9 %wal2s]'5QE!P* s*\܎X<+t,|!3id4G*֘8JɹT,J%<Ps%G#7YS^Иy4=5s]MÉpMqA!sQ5ѠTPrǿ%b}IK Ф:Ce cEɃ99!AP cWN|g+FEd>$ǓҾWڣgkDdŮꤰ Qmrmv@?W{Lm6hoA A 6)EUi}!(~dkb@!d1Br1ȫp+ӥ"h"hQOΔL]aiDX1_CEt1N4B4YHeELOޑ/_{2Q XzYF!!cLIA LCBgŒFZIā 2ʞ[<h%pɔe' °b915fKސB,L"G}HG3`FT!: f(u# X{T/"Mz4d:YGAlQChɴBe@kՑS K)є #w 2U"kV ;UtEE<:=HchCR'aO;<:J{4-+nT\ YXjA5ٓIZ^ }dPV#1x'2u)㙞Ȅ (Hfpj*DZ!*_QpҘ.RUu電["dҹDMk!'c28R Vܟ r9eӻD3́YW1% FBD]f@k:sn]^~ZHҾy>zweO}qhϛ: ¤BY5Y BAC3g2Hq?cn(FB+dG)g` R,r 0olQy$Jeg~FlܥȒ7gwYui SܽPmm!f+us>G+q$`%M/UL܋KQ\ѯ{АU}Acd=Zu;[6$<"*38UyF2wPie$6KY,@@!뺮D!~vaܼ62r7['HTNOmλU+y=sWGG@QxߠHdV\") mŞי'i$Iz7dk؝ܯʨ(TGZTq=2~= D YpTfXPp=IL:'D!OAy)$hJVyjOPXe bQ"#;WiPI -%{ϴsE`Y{Ͻ<,dt{}kagatg1BmR;dki g^#r-PbPh<]jJPZYYڇHQ(!D1id`_njYfv-vrG&H#J'ȌI30(1)\#np)3y[P "y6#$Iy(a-eؓ0+.F4~ɿrNaSCdu (u /1Eue) Al]JڮJbj Fe=GC@DJpIHuy'0ǚTRQuScc]"!V~dwvޢ~mPA XDb>3PrI7Ռ Eڢ(=w!ˣ18yn19QQ ' %cq;?Bb"?+4ysj[El(l7*H}9pΧlxB;`wFLKsaK Aw \)4#|5F,H]Ft]) |r sfld+JnY\槊p0*\qM5gek L:A.If&$1jIB>*EY8v1McA9%*(9!r#$ņM9TȖvb-+G˩51ogUbNˉ*PMVtݚY]a=.X!$3Ǻ&JHTd*9U9`ɑ-M~0RWZV0K2!1ݮ|m$]+@p~E: s-%\d+!Pm2SL dZ!BRɓ7eCR51M*sJ TP)2:Õ73#8Qܽ#ԁDAk AABqmVLWhi=޼H} MqqnUHd&qsdZ7p}t/z$J9#JHJ⽎1' I"< 'P!IRV a7&^6X;_JZ+db4Ei?A=hepI^e^7 )J*e r#\Sj A !OY@Z(ZQ$Lj-dT *5X鄘9 0בX.C'2422iDaC9Oun6,`wdL̾vΐem(I/T)HBWŁU3f0CDMI籊( EfyQCAtD`D*gJ8L2ɍZՌ%p:Vb?Up*J Şke&%2҇K49XZϬQv)qEs9]Y/[ªHe Q VË0#J:J_PUA =9*.LK y&E'&pЊR/ZOH,*GAH12E9VOAXL$2>~4K3B~,#@}Kvr]|S՘}2 #Y`u$ {_ҳ/Yc -rGlO#Ay|..zPF~mMTgxIL3S4Ĵ^$P'HE&4Pg Ch'& x5m(1F`86l. ܜE#qZd턝JH>})2(PWʥ`z(-_ hc>="J$ V3pVC%; Pj>y!9"]9%B#jY\DcIJ]Q扩AVTZȂ䎸P %+gib!sT;&(kQ$FrVn$4\AI99z R9 G9IѕΛՏEę9zA3S?Yl5JTPc=Ag4 TS᠎s":kJ hŎT+UD&dzB1w")S v`*7.SUDD)OG8!_!OՑ`֢H6es U-,5, W+&<ت(!lA82Mv Z +6EzxԳ"spL?=]/$:ӕYiې4DʋRm%B~goޕW^yꩧ֭[,@`3L6hrJf^~u]OR!eVʔ Rf⨩tUVK' joOūzo5M:7UH`2l\E-̒75``A5NC9sP7*/%XU =ZxsprCgrbrW| (+t>=fR6aMPBƤ,`D^tVޜ)hX{T fX+|>=ͧ>1Xq*M,2|oFN<ԯ뚈 *ŸSy$)ݢTFndy ŧFI,3W9cPUFi&T&H[_՟##)B a<\ȵ~lP@?:]{"Hj^rwB#5("0+i$5A/(44ɝHJѵW헂=xV*(Hf5'Dv⺟rFwh_OH@M 1Sn<2FՓcmPQ"%9a?9jN= ]q"}J6?f`" oݛBk?Wx^7N6h6hou{bz@ UhnlOt[hm-xQvMz)Bi6J(D<"i-9$AYdi f2|3 @F+Y.Ib2LBbCt%1w? V('T^(fzk򬎞(K$1g  Pà f ??mU{t?Q[@`s9l%A~o_h(O?uT5J.UîʂhK0eNsDGf5HK9"6 YDuݦ̩ơH33o$2?S=˘6`Pv9j>̕\:m=$A[X.Wd=П=޶@;l6AݴPQu~<y]ȳIna04i2B86r#\Lpj}A^"3zd%!mu뱭H 7 J'I= D^L?wԓΑQ0SVJa1qn]5Ls%*cdۿ?Ax! Al&qdke{l6``nVh-=TzNgy6*[+Wu{=)i!Z`~ ?~tξ5hs $$gɴ,^ɹ1**U;ݼR 1q799l]P!Ux$"ll(sS>,>'OEn#5^ع?}ߙk:TYY;x,|<}b/Wymn댏*tD{'6G#Һ@[ ]3:rbŧk]7|?Ivh_z{3?)6rl(Bg7-֚t[-F'zUn=WY]Вvu =a,!v;5B'iZn`"rM& B 9d6oT &2WqlAX+ 1Gm3$/2ܤ"c4Q8hȜ{d9jָ#X#LDypI>b/Ccw ,s#y(Wss{xU 6hmymkK˲5Y&wt'_=5q@KD'hMNO_=7=j٪X[~(}zj_οvʆ|WڱWWs[wNUg_YؗspsOv_o.K?ͯ/fAFކ}7rS})ͽ^ݪםlh5ڙܲqcgy%  }a=LxjDu!2 1sf,L`@wƯ`\@sblm($ @((r$ʺeD\ ?E*F(rV^/ )3)FUO ;7ZzR{P4G w2ȨpЮM=9jobdz({SϼkТcOgB-9+?Go|2H۟G7S8Cs'z;{moZO;Jڗ"/_$ C#ˏY{珍yo*.g Oꡞ;%{m;zVkuʑi_ʞ+7OW3WPicmm-YyſuP0} 9/>z~yy<Ԯdi}xO=W~}U}L75_xʨl?;SN#a??no);_3Oo;/\~Ѩzoя|f W~[~⩩'Nf/J6|x0P6=tm:3| o~{l;hd?z ;g??]e {e-=^,t:hv(V{rr3֙dh*?г{iQ!]BozV̢U+phfANF"&)d`Z<$`1 6(A[&#ip)䱞ؗ$HbAJµ44:P9P9Ji+}йtӾw$<m=¹݃r< ;:V -1n[ (ڨ(ۨ&[eכDFoU{e%VuzqwT8zhnoNŋ0}!꺿es9~c1Wһ}}/~kQ>{//Z|ܰɱ5KbǺk̿ҹ?~7k_ضs^~?__?9SN,ן.\=塗|ߋϝ=3\.]r7n{3ίxݵ;GGvx} l"87~v㭯TOZ֧睵W_+_|`_u_Uky;|_?N՝_kw܅Gپ/_|wӍg}`&~}7޼8kŘ镟ë`\_;ԝ_nݵ;|6}ӫg_߻eܟ^=_MxӇ*oXL\zN{;mxEغ蓟˥6v/WQh[s$`ǣ~otϙ?Vlz~q՗ѮagKܰ5Kg3>~'׾ |ӱڻ(M ^~s_|&=-ny 28{9Fuӽ'G>{z.^+V_wK;ֽŸ@ [EG\u'ov+t:m U^[:֖v %Z%ڣnZX#YXQߩnD R* Q) u]Gߪ\Y\IcRb^&DWDhHYVe$8I$D&Hz$a mK>MZ+?*+@e9e ›ř;~yOik}9ӅO==L mj{hhm;A:B?;hu+` vg &MNMIW_ܵ{ӯG^pɩ.pwĮŚg?#kco`lǓeCoj]&ټgsý.3.<5yO}gЛb>޲yGa?5n5ێ{W,?yDwt&g>}ɗc5[Sx3lѻݏħ)goz[>/#os@i,k&.pw/Ǻk^'\_̉^rpk99?Ws&oyq_sϜ@֏ԫۧW|9]?ٜ3'&S[| =ϩxo,:k̜79\y5k蚏g7މS8炵ý;5\~3?x&>mR>d)7Φ~Ͽ>r_tmY^|fw.pYFo, .<=w˧k?Mx|x ܰyg56[o.I߬tTb>t{> 9]xNЩ]q[lܰ{+MojjE7xW^6(1L1 IDATqzZsdfKvZz%ڣ*tKZ֙1j*&~ zVzF9V)\WQUf(ƺ+J xv._BԛYd1)ViŚ*BkH٧d@WKT/銢p#L(Qr.kD,r 5T nI K09̍-Fg=k/y?=dzxSWyڠ-ƞ>8^Ŀ)0qZdVj!CuB?:F?PٗSiT⡣ęO(sL R6gBc*>j(sϞzO|[aD6xƽSl1_?]m5ӫRc9~eIp=3|li{mGu 7Ï>:u϶x+q/y e0Jn1W^r#Wf#_4^ygݼqCu/KO?Ql `=0Z;~cS~ٻ_U.:Ng]TRKnZV U;mu*`ރ͇7]{ΩAR Pk9"FD T+RI-aan% {j0ʬE\U#OerhN\Np] 3TC|RWgZ$LdGe4Ed[ ڻ . Zhg՚ݼN9%GőEu DPYHZ-ƻBCospuwl=1\t8",*^_]OJ:h9"0||JD@=R ർϕ qE=i6.&Oo@{[_v'BF}GU.:{咓N[|Sw:3|22[oꡰs54*?|4]yՇn+cȧ8ϝ᭯>3w7/~;g_KǮv[/3w^ך }}w=! -?qlM{<w\,{A}s/S兇7Mr}3F/Eehg00딓)굼O EN}PeU@_y ;߾~ ۆpi\nj 8\߱qhoeL 70FBv#^>֌=ç?iOb<O`ݬ@^DwGjD5.y(jt|j^okvՁ a/6J$2,.xlBi Ԉ IjFbAJ=d5 Odo If$~1ƪf`ST ^4 rbb,B6c srG}Ry)KV][ 6h~nG[-w[_'z;TKw,C*^y{>bd^{|;|- D5T(;o?=OPw?>Ͼߣ~>|Usr ǟ swW]|~ {EkxxrQ}Gѐ߬9}]ͷj'MvI'Ж?9 aw<~9#kW겳~#?Td淾~{K~aѿyXW6}+n}f{A}sSev euãCnrs}aznv~Py=y9ӣ f~~*0>/8^hY658 ;F⨱_\=:~ɇ&u+蹇8瑹{YT?*,?բ{vÒEK|)7uQͫB~9= yU:w<+C?ߏѵc7_BZ,{?<N{w0TZ[-55LzV3AV ͅSPED%d(ix%~,ٙ:F TP($f5ȈJE. \"Cka TD̵Dbdfb&DB,%+IPU EpL7`jSn\n41mC&o!|lծ!^ :ЌAwm<hOb$&ZXwjw7wWu[uEHHG+jZҡv4z>6|v-~t|5k/sRٓO?<3S]߮E_q|\GFCG~P{s:gbL>= v?o->`r7~s[ZN\ODA>]KnX[sW[_tJݙ7zo`@,`S[xeCqybS3rkk|_~L^rWs2TɦF3kovrc= =*-9ow>|.u|Z2Ryɹ_:qYosvݾywui|k?m?/=>qܱr{*Czqwui̚ڮ֣nm)';YSw}`\GLvs:gO/қgCY{1t^s>q׿vCktc㏈-^]zR {>b>aⓗb2Ə?=^qC?q׿x?>sK>өWq.>o_r|g|ox~ًreu?/^6y?scχ^ײ ӽ ⲙ%?y[Ck3.]jqkaSXzίwoԡގ^nѫP:SVq/nzNCTt]hИ9oɪ=q`k TcgEXl*Ril؜JVs3U:]~r&LSF5q@쫎1ZjCj)0대Jk#1E߽+O=T"ںujQb|gOE{Ž_7RAVb W|w10 @wj?9Tv .- }gͪ5V2)]{lzzb|7/]ON~ޚ5G3]/m|Ʈșm| ܟDQm{7soJ^93Wj]#?eG>8t1$zlxkĩ&{[lNwNnoZvFIރU/y?ptqh$lFj1P@R#nA@T383 [sbB, L!F* 2SnDj FLRUTk jhM|(hA_/ϷOf7/,Th:(~<6h0nwtݭ?іHa ?C`]wWF>wu<줏EzݿWXjONOZ^'ި#x5>i ;0փ;cpaё="*IG!Ħb٪ ZA7$a`ABHTr)Uյb|$1(I^` 4Ol%1bAh[AƨOILh(ZW5?V7Zk{VCg[?{ݬs9q$\DĞ@!uE4q!=Qg`eRDb)(MLD%3blzk06~][[wHjcͷeիW/.Ž+ KAGAV/4U";_d}AҮyfqw~]4^Q#FC7O}1fzN1W|~?tw?aS$ޖvk/܏>7K0uke{Ysk;OzCWj߱,jYn/_\daaex,UEDƙǓvi{0(ĥ@Tu@OF(5kFOG =$VJ.:J˥z\Bi$/"KN8N)ʟF7^z+A >ͤꛒ3,c iF`lL>De̿V*seYkI,6c8ǟm[۾nBRb\' kTV-nXݪmX`2Eyfqrݲbsc5qx_aO-[4O-vYu=v-ux î?u?՚-ҢwUߓV[.V$ŷ=NЕAK, >"RuR@b/PodOTM Rq_eOI%%DB5=`q%Ť$"j sI.@@^FD|2JJ-1U]*8LPN0IhP2 . O%wQ2OxI";"ghk%JI4#R86{2G2mͷM.21_K!G_[y{z뺅Y?8q > ;%u ;.|uIwy,ɭ?\beŅ,HN;=ܺNc=,JMx 9WXLMz+=Ik,H3R$V c zB`t΅(s%m;ŋ`@fB|}8r? (WxD|>i$'_)P#!Fq,79|u7V)F/ۿ4X[f-qy`m]6X{}@zmoaNж{hbds:g#(]w_/ͮ 'Qw%ڑ,7BMlܗ%34FvmKT>_]te)Vfdy態ð ­%o92[Y+pɇq4Z}ecM;o!56Ѡ9q]HE$H۲~`t@y)P\&4x'omj thQibNZv}4t.@%Ci39g3 lv'[YQVo :yG&BEPM{DB13 9k%Y`Єٴ%ĥFOo Y6;v>p}t!8ب F*:^>-({R5v>7r9KDUS2+meeQCc+W-r3-ty]Rc86Q:UîN )֧NW)yf훿XT0PbY\\ZrpH[&k%0B S )3L+Y%Eaw.dheZJ"GNyJ` ̒䢪Dr" Zf1lAV>Y k|&-5u [b7bR#o-5j"q ٦ tx".׀2pZDf]dWTh{2eBv`2,C쭽8v}GsDBcEƲl2rt3 `?PqM 7+.g6Sg0\K!`N@֜H'VJ'"‹GE,Uaf§'&g80H0&Q `X""5oc6%s m^dq/pmK&GʕB+)TI«hi͛a[YeiףVX6?֝XmmCT@va/]w՚`l¦N Bi,fX'`0?-CgE Od᷏[ن+|U2ާ%m`Sl`TR2]XS@Rд n5{FD@D4Oi4jOUWz-COI@%m:sñf<u4.70!PlHzq8B)"CWR{ NIpbNnE7v"z$!jlP@v 񤗹 IDAT]<R_AɩXB:djpM J)1k*J $ձ 0m4DrҨ]"`$0mf&m sXG( w_6 @`ou˱L"pmpcYz<QaL%Vʵك^|W tvYzmP'+@ TG~fv \hTsezkZ5`)%($h n*`9nh)iNM`ݜټmڵZ-2Wb:l,oQ(3Y_$`da#@x s+\s!2iƁsy|shV+^?5Fqe B8CŕXp5OA'5η6|'EU=qw?c:٧|=__sAC,g̡08޹ Jj/9\cU#dڡ*n{/]f}(P.Au]S[I 3tj S%AЬ{ ӷ^1zҩ)4U0IkvTM$%[~zv1,_Ϧ]C ;UO ZamlPjkmg+ F,$-ѹ m 1.(0k9Ղ(}+"pz#U{DJ ѩ ,aFI>A| u-թ{Y7ge ^kw\ѣM +U<+g/=9e/(,1}YRENDNzi-ԣՔ$ӑ^^OG.} \QnBx },:z?bJ" ߍYNȑȈ2p^E,98q$d"iXPzu E|`%FU/Ȝl6 f8ycgW=o1>S i6~ݱpze˷s+ǝsW ~Mϧ/\ZcUwcǿ_LDD0>c>qǿu w.dxݕk^7zK|?y]yq|5QI}#םO~a^w՚]R"Yq骵F~c;}Uk̟?/|oP~ܛKמN>tưi{qGu8=JhtPPWu1,]12]6@X5>\)B'+[9tXB85cT\; mB:l")[)YD 9yTc"z&*#|}׏&-;f}eWjz8K ~:@__(zIg(S%Ҕ:LMaQ{.yN=rd2?{Oω3L'(LK` n d2pVL2ٜdtuyd}xFp$+XE8N\JC (7w=cFN,2!&dmL5ΨYײ%F#WDE[l iv=_^?|{~󫧽? |zn?8G~q̓^{ێ:g㘧<{rugA:P"?h@Q?fWQc5$#8sz$&Tob gLxThY٪̈{-)7jt5s։ip1 $5Hcj"SppҬ'e%dP/S7 *4X[[H8یD0M~Jrbe+s}2ՏըB\ʛ;lYv7umRƞ󦯔QrwP"wݸIIA6^z~|_oˣ :榟mYљo~'\邛~(n]+; +W>wn> =^|wUQ 2:S4O6:'"r?YD^~<~֮'<7lIdEg5 OϿSZ(==6;7~wv}3g3N~'2OuX/oIE+5JA]Q}!h$r y=A,9$0IJ6FPGzSeZ";!RbYBrધ VR?[kuz`i= 4Ռ[hKF;;3TyvHd,P: Gޥs7SY)5MYzNkCԫi[i284޴7u߫Li;)A7}ǯAKLAÑ4r5T-T̀<".W%᢬[]l.f,e ŵ3DH?Y69܊KTx<35D3R=EY5GS(((}}ŸUX~kߴiSg99VؕƲ:Kl~enec874s6vNey˭YfV3jcZ/&Xݰ8 o=9+J-}I|ӏɄ"U/b!" YO ownaZSc&.j^[/eclOX" Ey!Ƨ_i}]P,/'q~a>/߹"|{/@#%bk6v•Ydgiqo+g?E&yձ!עتZ)מP rEZ^f]mZYUmV5d# +N:}ƼQ7ҙLȳJ̘] jo^ﵸS ro4jڠV`=m^Ċh_$;4O6,P} CYuesc8V=,h2ý*(`L7oWo=dvyJMS*Khm a}QK&E)*.pD>gzצ"BIiq5: B'N×};î;tJXr!Q+VZZh̲ʦwn1\xj4fyWʀ&]j?-:bA!"O׏_Eoo羰: X_6O/<.窑/Yc}/Z/NF(wuPz=oApC7h#__z$q?uI0|c= 5>TE3˨&XTzj5=jfa# :Jdlfc ?Ƅ> %`.P64}Pa9aR֣Sr('iPǺ%;@_z3h.?1f[T:xc ,m`"ja卺TZ}Z6$jeM6 ӟ|IXӰE>dVyImNyVe-l%Wɜ'5%ɅWκBIT𔉗IQ<6?I$;фFVD@>WtzIZ~Omk=wuG+;AWU,} W6[a @Ѷ07lS׵F;,;3W<5oy~?/[ho":<N;YyG綿7%Т xA{v|eNjG[#`zA}ɡ/;~K!jr"/U~C_*S~ ϻW?vN~oZQ %8mG.chϻcv}W|}qr٦B M7Q}b,' Ȫm)_bjJQ3V靳m[0r7dS):3E vd*mL WMk.P} Tk#I=mנXKOJl7s7.DN7ݠ\FS/diFlk(hP-R FDݩaJPcdzU\AEVm >:b{h$:4&>#?+C< LQ#4B\GmqD({kZ "tMZ+6$<WT+[/8@ͩjl3&V#"NȄ '^~`}^=4T>O'&Љ#9:!8?!':/{?S^CCN>_8ʼnlG}?O<@\c}xg|w[X >.5oǞۋr_wڐ.}y?,HG2k q.OڰSZ!SDKؔ|c^Qbq}s}E<=ȿ 7~߻_y/dOa.zN5_jM{f^@%Mx!pc1R%cwar$3gf!JM991U Ż|0Cq#bX? ;G]4H7h i^1 &p#d`OSMίKa@(H9UI"*tFX$Y[2Sr?;oy[%3|kNwrD3"H,{3Dfe7x pn,c8EiY)Zv46Jglx/eZ)+Qe,XԹ瞛{s,_)ֽw':Ryõ'(,$Ȃ jyrFsTW&- BWk쪾bJhJ;VQ]dcc%ҥj~>OՈ%yehZ:^U)+AMhWaԧB^b00C@۾j-VsЙCs8WZdRaWfǔWgDthٙR*l(ī4[%ߣ_03S@$I џ-fЫJM+n?CTgvjىݾKI^k׮!ObrZyx8;p .&&"UUzDi{u\Jf'r"_oTba>5)Kb%%뒒!jGAjm~/1߯_{a V{j0=XY^E̱AUI0f% r15 -vput{m0'h;OUHK2׀zl c'Ifsl)2(uG* K\Y8tW BEeȂUx:E)>d @"C3c'.xϒYL2;#ؤ&6})H `Tzn/ŦY|s3ׯĽ9&-0!GS{:( B쩰5Gi c0HѺf:1 qGqe1&!(TM_JԱ{KnSJ97 ` Ed[,Ce$}bsS5q"Em`l+˾ӃI,Pi`찁5L!h!E xȸXMFPhSVd,4,u[eӒ%>oh=ۂ${ۋk^s+ʄ]qBeCMjc{3YB mN8sWX] ў7 rֹ$)^}5'`uwf~ԇˉUST.30ŅP.tc"t 8>r0to5}t Ko|D{1WlARJ/]H1d3krt:"zׯ*s$+#m]j8-z{}/0d҂ h& IDAT/*֕%*0Z@PTCc*Zo1 wr|ĭXLޒ%{.PB}x$*_IExmu>TD]4*Dnv(uє@Dzff-Ja^+쟷 POw٪$L5 : :$ ƫ鶜X۳'GHb!5H ::@ʝf#rCQM0@2/ `۸6G/ dġF F!({ӕA|6`IWj!ND)` u%%ӱxw*[{.Ww)q4~Q;xz@~銠qs>|oN=Mr-˝2[fupGzL4ZRCKuΨOb;}g_铩ȲrJ&6(eޠTȃ--δX^v&Y+E^%[n4&fmĖU(cz ?0iN]7޽k'~8)SIT ɶ]YMG VEAXK,nwꦰd烲jT>v ^ l0Ϋ0vIPe`Z8Rir:׭ ]] OL׸ˤPM\ S i|9%*/ik1;CPׄPc$3o7%0Oʗ^ec2)Vͼ"tzuy0>:*ځBP@4BT^mN5>ôٍ (>z;]婀ZҟTЩW4:!A bݱ с$W2e`F.>zTKv5JE\QdpHJ@:l@'vcdS*S՗IѕΣވë7u/D]>SSl['jqh(X 5QDkQFw|6 jmLu{:`Bgl3ΈiSBۚH ;_AN1&k5Qk]z4+QLL 1uXY(ļR@A.q"vE}D'TսCSlZcYZ'&|*X ~p uAv&IB8K@]qx 3zb45Ao`;Zn/5}h/U)!H7` ]$hUȌoVP**HX2piԱ6&BTއq0ؔE-Y4%nk˅jyuA~ Y{zWvKj`x3/~(+M*$NY& UC̙ʐXp\A%t_fAW=.'D/^l¤vx {׃+( 鼗-fޔ!N(cq.쳡 (ڗy~G?֌Zx"7⪎yvKB$ P۔m p3F 9 ݚat>7Nп-z]s0`;#VUc*D FЉk}nOiI="_KT-u/- TNB  5spR)-fZJZև_4l"*$YM#[r*`5]Q$ IVdJ+o{#36ڑEY zʻwRj1 N?,&1st帜 j]CaA&z5u1IQJӕH-abiX5@jE0T|@YYmԊФ 1tnX4 ]zrMfSrMmV2D򬇐]"W͛d':@fԘRϛ'UtyhÍJƓ/#~C'-JAiS$^'U %,ۑFAƞI70`Aj;L<)4['Q)Q2ڬ+qA }4MvVȲ䴡R^pYi{)+bi餾=lpvFza{wg ͨ)֌+pv݌1>%N1g9>b[xmhZ9l`r."]fϽ0%ъ`K̚9NPT :wN@s7m쐪Eԑ RZAzꞵ1"M +8 xM݌pHB hETqEҝ՗Ux!"*_GVE~ICMu<PdUuw컬buS 4igQw m[H۞eoaSdh, $Zg"Ή@ _byg %Ѩxj`KW!- ո`b]aNԃwg pkǬԹQ XBa oS>&(f眈P&ιd'/7G]O`Py^\5'i"z?C%#燠Oj#$uzaKU}2*Q.OGN^lA*zҝM6L+Ni4;X³S^5߬Q23#MU>Pf< w2 !21R7ʂyaaaC&a#Q >n4FJ&Qq@Dz)F"BNzWIbHӒtYl-Vn[6ilzhMe1V][ ѷ VS>}(=3egrrjFՀ;W6WpڪO'>%εW57{}㧮?pz>-Ⱗ>b/WyIeaOx ;=ǽAvo}z߹W >bxk?[6x\wpF]&e}ȅŗ\~gᇋUӕP*DұQ0BȧEeZmҭ Kgb?W,hK{^5,4$ezS(UN+ܞ쥱GA(`ػ_T9A*N5hAm=Uev4pwc 3(YXiЌsS,szMvnM@sYAPJEI]. $jg_)"1_BY9y tۡ#[ˠVaؼlw7MN-mdX%Ό#jW៸yMbzstBiAD\9*$] l9^ۈAQC׈ "{-?&R"D6}|؁^[iIO_4NO9f2ny=37sG_툻c˘[M%pcP^rM%seGOz+_~>G_rαCO/zv?/|׎<9O~ڽ~O9їs^p)x=B>rܻN}ťo8_zo{8yo=b|ga?8_ٟ"]v}W-|Ż/x~{rKuk/ݲ~ zKD&vҡq1yKGM5>43쭦].RbLBmE$[fBv8 ShdnǶPiEMWpfv ߀1ՙO:>.A{<kkN9 y3w=uG?_Z3OQs_ܻOy={<:7LkS"A%`uV䢦ۋbR9) [s"tYvbjoVKTg8 `0XqZj"z客YAa1AA:fA3+CA i۲ fuFP]nM ;_(72UsniJb]5Mtn` bT\M\V5]D{Ãҭ n5=T/I6v"CȾhyG`2FLqOB}ˠ}n$+F$YOlŲiLIm5jH!l?Շi&S >QfpABRjLMsv-Mfi0^VL2êmjwS:CG|3٨E vDU\tAHbs B'A}vXG"Ƨ_i (P*l5 Y9tXΪ$Tݔ j) Սxx=ͦH˰Ox3P3%Jy6Enm_ʅjaq S˽FfjCh9EVUrQTv j}TرS?-갵T+ +ŪHݣ8„KUvGwE Ubdw-YXJ5¨^5wm[igg ůT2/Ko5쭬 E@UG[dg5YP;.b.=Mo`tmTJR{yVUID:Bn0Jr#2C21z,FHG8re #!(')# |Xr `BƉqNuQ\~;_q)shcta1kU;`gk'"nVy?n)ұܼw+/s-jygMct۟s=7?'JΎw?u/^qե_ֵWk"rUk3/=|›+/ "^f}//Y<QO:LDμSo݀+.~ԾO Ny( [v:L"͘)](pv lkޫ5)~R_ڵknM%f6Gb^ a&k̃&%#q}9HPFQC%? \rB[%SSpʼnHL&\Z .4$f?i8rމG&r4lc"+`.[gXη-4[L66rmnnlLϥrgyR]hP1cwtn^|h; ;9?w0vh ?  ywW?'=uԗ8W9C_ƿ,.)/d:K& JeXNkFWfZr@ir)! ~ e_!h#hli'By [5S$]-v83 15&Y8 {QeK<ªE#E@09a4"Rh<sn;q#ʈ2p$p#H脡P$Az)89 ཟQ8(4K'sb1ZFգIeS^]$$4܌b9,?nIj/}7~}MI_1v_c-G9jI|szCnׯN187q~t\7w_xLjQRb4nmmϕbQ.Nhao=FQIfMȋ ܑ߻UVS+Vht# *u|;!֎nosQ_”jEEZG9RG)+Ɣbe6L,_ kʜmDz(4Hs-5BdUa4}Ns$=ΒlYx}"|omͷ͸u2f&H 2b [83e7mGPW6q e&Y-CM-d9ۋgE|iEշ-a2 az΀'@4XUt;pV\3hk6df63{] IDATӸ*E|vf3b`5Ӡ,Z*WLU1O.cv| iO rImKVtUPbzH~7+4 Z]so*yˆ*-? UKům^u.}RF@RI^< ;6Y#ݎy ~:Bæ O9]^"hahy軖)0T̗.{4%!1"n8_ؙ)Hmͷ66]U~V1_1LejHѯ;hW[(]J1DS|+TD JCX-2 kTurʫjR! (P7|O*%juWt50> k'U=:C,⢲4j'~.w2U?Uqk6ŢN*G7:œ'1->{X2hbTE ^H$oҳ0~=64' u);fS$X#;/7@Eo~)Vf吕kVzVcٛ3&  K-bVTj*8i$6 $h(Wh3QȀH;) h1ɵDI'=WR>౱Pui;H 8Lq #ظ 3 T&>ru{d€82CS*"FI("􉐀bŬ (N!(tͷ6߶A j 7q1Rt'U9iO*ST-F-+6|o p(~2t!гu!W 3%.n,P0g qJ ZO[Rl[jxJGfYء۠8-ziҁ@@h-TQ7fzsmj'Xtu d]f5~Ta[DRdB\V#h[D`UOx+ H50ZPFu <8ٜquu$Jb!Mc1c<@,^T4_NIfMQr)5S[B}P\1OZ>A6ZzUK(s"pcO4#msZKa"bٳL g%:ȼ :|o֦ڮ ѩdOQgQq)id9 oZ \lP"ơh /;Q9mtGuS}4ֲN5 D,)B:uT4bX bh qZX}d QvU_Sz(P[`֧AET5nR 9Sˬ[͍r3ˬ"n< @PZfbrA(DLfu&5]Tqu RpM bɨv80ok:j, yum*1=ȢFu˾&zyaؼeJcO'%٤'WQJ6HMBt6NhX 45/>p/Fa(ItA(anNNKX 6׼'\^Be^UdkE19?宙 BPwRMW۝,NF4Y]"s:|oچ2)WPoA51]k-!uiXz)`($}WiAy`O.c|Ϙ*MX=J-YR*BH-EAA֪7S p>!@Bm("Q_-ڬS9$t&T&@-Ӟ,{eys<7&*ЖG!{=CNd_ =n~Vm]JF1}r O}iI0#|~GD-䈕V&J^b] 3onRfomͷUA(tHe* ~cuwv{{@{! ^^H!Љ3~A&"Z&CK1+;1&z9U=Mr xvZƩtʃP*^lrib0֦RD|R3/S˹6(69U'!Uf)*G zmͷ6`)Pgh i{qoS|Uj3ax)BiHVT0dE Vl5Wc%; Z{`*.Q|+6yV0C`Ƕ)ˆD\e16kuCp ЁEV<&ꮸjܚ!TVVElHtt(5#J٢O*O늝 s  ;7Uզgb}p-M o"[ĎRkU"eTs͔vpwO73);ۑbد D!vVJ*[sEl|SLhjh}\O8MYцRED,c9*)ҒJwwr (fBXP |1 bCpfAoݴФ feNRi&uj*1ݾ3+jkhXP4vj$?KEIE'FEM9z&v !v keTVZ2 X%U)ba/sX<4GYq6HLM@8q#s.B_:9xO=uH4-*Adq"⼀/p 2Vi^Y9p`oͷ6߶ "׿}U/=T0Ʉ\i8ۿ~K{c;׽#^*u'^gtK5>Cov`n<\숟?Oy?+YB{5f)8תe`t 9cH7Տ(Y DzyFz qSk䝣^ʃixK_a"󂔛jX]]@O4/|7;O_D N7#1 :Ltk(2nWdWT(ⅬLѵT$w91.>(zX ףQd&s?+uzUTqҟ&Դ.,g`"3B_@(ătBG:NOS">nB @D4N 7xxi=x‹x2z/⅓™K%Ke>oՠR JI$ K0ޗ+3.6&뒞:镟Jhͷ66QDgɄBlw/zɯ={Ddσ?=~;GsuQWTr+b+ֈ*`{n8U]_?M/g?n&^Szwk>^;5?""?{=rZصWw$R8j|^Nye8OM')śnwߛS>{}}ikqrte9aT4LQAl*STx #0^w]s!W>qvgW/~qOw՛? ""'sag]wsQCXQJ[wOl$%{_?' !<}nk6"tUꬋ|zϛ^_gM?w?]AȇZR"eP]q%z+: V4E<\vh?תawVյ>~(DTԨ&ޘ M(c)*EEĂ+-D%, h3$&QyZ{P31;>YZćdtsܳ9&΅eqF"ZCtK$?No,c*DY)>e.#( Kη<# ҩ.(e*M#閌lI''@/(ȗA8uysV[AžXRf5TPWʲjduJe"Ҁʛ̀ JFh?Ylq`m1($BaEЀIeqL@@T.ee[unխ}u6nvݱu تM] Z\\m.GϑUT9KrƝHc 0' n<0K޺H%lgCoA *|QA@3T $Oc6~RhGkkGҠ5 5ꭎnvwWq p­i_}H@HS4_!utbҀїQi,AkjTBTIçgi^@YKdMhBk PT6ޜ^Gp/d|BVU4j[C1g@<" BVݪ[uOD g ZP/cH~7 pM9"E$Oŗ{"̟!zB,c WtU3"$ KsEWYS#DP-b('Ŝ(I|J G'K1Շ͊XA<sJ;]h^\dOYA%N/P0.\Q*Aǎ]HݛXdi$1n x/*~bG2ͽj'6Q/mmQֆ q)ЯQBeT֦8j L+ 8qbRFyOЎaqm|Q\"*kQVK!"M 5) +R!sNԶ;TϤU݈ [=?^ty /yRo^fs}r6^ EpFKfNkZd^}AH?7T 7&o´}?=׿IBETZQpkI}e3\TW1; ߡs]~ңL' t|3SL戸/ Y DPj%鯨g.Jғ^$4bMfT"?닮`baU@՚HU9|yUV,~5w5ZSs mmܳr8H8+i(\q,J;U?N|R`5XzJq5Rw<}=mzx|&] IDAT\Yo9n3.l-d Tj6n-$}[ԼhOar>mz]W&XrܹOx@{ d,'BA[ozt?]Ǟgks'_x=[P-~ǎxv#JS@1 Qe abcE xgM{5Gf4ywkE_oOՕ'b(ɤ1o',#,z%(LͫyOس59?7}ni=XCǍH/{oxSw<.Rp2xضʴ۵,bt#o1!ULNÐx2 gc T\qxi.EEo(+f_XDNɘMҦS@p3)B`R*\C$dof#˼ScI#gcdžG+kO,FW8yZyj˴,#(*"Sc2T>i~6l5@k*Ee9wJ$ç:M2μP4kyx)a卄Dq|Chg61 ^iehWgS4t١[ZؐZUWMthOAS챊S韸N(%ǝ-Zy;t=j:qIJq3tCn4% = fMyyλ~_>\Vv^.i0y~Sm9"3&z|q_EuhAG|\[|\wĠ+s*gMyν~_>\֪]ipijg<0{k[|Е|8D>ޡsoY3=?]]n󬦕WuPjAWY1E\@3_j`NoS_=O:l30ŇNw>{ N ag(̅(MN؀Cyo}nq L7y?>-]z۝9zI.!~.aV$܄$XBZ"j1:^?Lʞ!FW(ID|"T Sp|8))H KĎ W|4t_XEhSc(bˡbbBRVFcZ*[ILӕVNGヅ)M`dؕ8^zPᔒi7vrnVHTX5l/6E?cyhj+FWN6Lcw H5TAd-4i R37HMk۔uf76ʵ+T2M BQ$YWF6} ףXmmҐ?m[5_r}o|4};3Hj3WMhwVkW.}uc< N:QxOp8WC6M|O|oD:Qw~Ru 1a`"<_-=4`2^"L#Lơ݋W1-a/>~Uֻ5usӰк9ō!2RB:2*L`B3`;epv.3NtaֺEi' Z[*dcsY*WfAyBj&=RE!DyWJd,N9D + a1bN:BRf @kxP]DbP={#C rC2 V.f‰[寇xje +'`q LK )^?$]-lA 3e#ل%[J%ti2B+2GXtUIU$mk жXk"@؄ YQ7aʄG%ӆPoBӄ^X7C?(nP]ZUoH)!o\*_{g`ؔL[׻\U7 QaڐZœƛYXH1绁4L0U^ cJiLۡC>~ק$:pޛH"ʋIJP \_h3־Sw?^;vVri$KӾSXͅhҹrr #+pgnSz O*a}%Ɠ hԧP(½#0.=ˀ\"*"I<$ FEz)=UBy1rio.rRD ndLRIaJX /G uKk) AY) $/8iLF&#ĕ@N LZdg)9qyYRgmd^FE5*DPl[VLᒴ`Ph B^4Ү0dy D295R8fe"c ؕ)fSbKlD^{^tBϨͅo4*ϺMIfyݴu=zW`sgLלa$ :[kWip D3켑Ied l#ۭ&  mLIa(pևKd|n0'ܜ1IJ(9$)'65#n4Nf;Ŭ&VP3+BpgFp. ƣDvT^TIK#?^p9.`{M-3:Kadz "X,"qБhx[OM03;%R,;=~trk%% [6SJPBeD M"(^N]ֺlEIt =BTBRXVP5\BH5^˩!1wV̟wIN[e'`5%{2ۿs lXQ ITM?N`fU4ŪI^iZ3lt3C(QWڔjt4ҿp44a}}\[VAr /G/\s“lBE%MTPd4)*"r|EHǓrA٤J>~KP=4}cs,0;w0֝)Rb.vHD[LI(LfQz#;IŠ 8s<[TϝF  &?toO.]PTH[, Nb9oGIܢr i53 $~2 XcstrijH)EEIT([i%fֳ$ ɿ%ؘ n򰵚~}WEWURT"4EIRʸ~r[ 7ʟpPd Mj@6P7)1ZRŒO o>@{oD裏։GڼF5L6Wo3gK]:6NR2@"خپWPrF޿sw K'"5(Y&GKP yg&rb0ʼn> : 䐑i,"rY::4D !͊I8g: w dП>ޒFf Rd!Oji%hOxNBd҇%zM)$H8`]h(B\nHJ)2PA(\\@NB6nçc1PA($.H^ Ü;;3GR|?ޓD[o͞=;`PJY@+S֨}-."J`%<4;ò ԔWJ("ZcOJ)Ŗ~da,6͜slq uPC  GٷF_+uᛝX/խmc92Mz5sڊ,;H>e^BY%F`0J{^&˜k{+ȩ(h~{FQCPi8A^R1bȈ3c1aCw@:k:Nݔڛ;j>Ȥ\ -N3:3DZ @=Б {'-F.T)ASZ쨂0TQHAʖ 瑸YA#U\!BJP&һ/ҖݺuymooNB<=k 5!FH|ZRMUR#D<^AV QVDD?!׿@4I@T ,lIAj-|.AT%P.ZՈ R yH Am@zNvOV2MdUo[umWY 9VWɛ^6?#ԻAg.Cv>O;Nm}+~ @VKϊXbz;Q-iL,@X`&LcNr G?!BV77i|IICJ\ёBJȄ=hk2Ev -Bluc[Q5<oiY[h30ԬշO;n?䍗0i_WgW,^7ΫN݊u07Zj+[*+EPrF!D,0LKP*"Nq.i#V(FKulb+q5V$+-REoXIkQH Q4$EY"dZ&$ Ht]vm`rDd rYx94v)eO1M1z`Py#&me<y؊]FH#![ۈ#@60k/벑#BDRIR B2 %’҄Zl5*'$2]%e&%n\&-DT)&*&VVݪ[uJm8١O'~ݮy J @_+Z7o_ ߯A=O8@D;w7EVe!FH" ([H$"Tw޾swRСswSo)bY1#W r7b"B FtJF~!!JZC r'} ԶV"1%$9BlOOd7(KyJ)^`A~4oy^_U?ɧyz҉.{Y;'#n={Ztࡇ=gGߚr&g}FNw~t]jAl4/(Y $7sPAIr,>IpcQdR$&ѣIph*{䄔$[@:$J=i/E!urѫ&~e~|(|/ (ay,@¤B`JKmi=v`豵/^ s4dd̞aEPXҠH)h mб|o&,*Ҩ դ5F"::a BPk@!B)<huK0kFA߀l}(]6*!68}Sm_+F=+CÂFq M7i `O^x)gm Ҿ]wܺUf]Vحץj7m9w;Wkh dԨ{%cY;zG53ަ~g?ݻ۱ch. Hgst9p䣋HP :HR>6LݻSv_2qodC 5VKntȡOj''$yW k Gf+V3E Ў 6c@]|Cܡ?O[;=Wudףoe[fwχssHX'g dBXxzp@ףWԯ>kI#ڟ{;^[BUۦ]~.~q0gUwސ~;uŏ y!% ][Ƣ(?97 H[t5/0+M9VpHS0 rjա @piQf?Vhj @z]n*/Т6]2% hm۬Aa33YȜ !tR eAv EaG V)Яž7gS2Utcl02߯X€As𬓿?ģ׭/,cRK _wݲ4qO뇟նAc1sGZÙL>U9N$\y^jįй;C_HFKpU=oߌz1+t},B8kǟpԂPdG v*IOc Ltdx]dgE 'YFSdQ]wkZvn\>\Ux5>0exo;< =nqtRVj@LII{퐁i|#*E|$˔fERې fe0ŜP2Q)LD."g0Dq=ZӁikQ[ <_7ב_2ݴ4~^^(0:NN&L<|!n(P1tLڐ*eˈSKUgA?34=unTզq WM#mR2!N?PU9BcéUISpk]S 7l[& Jayl2Mmnp v̙-[Ӣ]~Ӥ^ofg-_˘ŒMCO)vXڠ\65el;h#~yO+VB7[Sxؗ6N?j|U lDg& iYs㣿LײukO FIx_PBDܓ=-bYOmuf3&~LV5ZX #·^[Uo\滚=] g|ҩukeY_z"dÄfTDBja(K^&w_~R@5?|gW~ukIk3}lM;t=z-{03>g=SNH^ &!; P#=e %]tb+C#%$>1y/FB䧘z̖y62З7FK7)r 1qfL ,dT2UzrffJC"J}l/OLNkE*Pn&%rd5U{mK&WV>'#+Y F!nhW+H7<ʩRP!iMdŸĞ&"MTXj^)׎| aoZk*\@T%"Tu|w*%h]`TY};GW-+Ph "蔲' #֔Wuwg8FtF?y9hd:j݌l}>s2um9Uek!M>$Ȋ̮[o߭mDЬ>g0aKϻr_}j͋OC}%4#_\xG%yR6j ͘Dl|Χk+ bJ$zr G=V4)/:)>]D)Om++Y> kA]t&\ED \Zz*!$,u(ڐEKYh؋1;u 7tqă~q|Ŷ߽YT>}2OƝir2$y6a##(15?$EdoЋ~\EO( ff/ZBoi86ȼ. \f[!K<זΥb}]3̞,2] ^j #k^GJfȬ1@zTZ1~VG %MD yX4wi{4hS4( 9*C&%t! Y2@$+vd%9pQZ  m=h4`T/)ԥ4)4SJRZ)*!h @ *l#6+̺fUBU 7,Ҧvp[ x}&&8u%RbȦtKnUU]{S{S~nS ZI)oDP}$(^Ԧ% h/|\4㵳'BZm1ï od$9Rzx/׎m׶.ipSw۶j֬vǜ}F%xi_+O\S_oх엜EJF1ҤWuWMe*SH4Qw[(Z۝>j`y Vz݈3ĸNH QmR\WH9˘}[Xtwh >=oMDpz0-⤡1tFgC*u;U6x'^>}w_Q7/\%ǝ_UmvxʉN;ݶjʥ1sG>zy?ؿEO 8pxQs;ι[X_^ݔ}i*]yƨ' ;w޸oƵzRyAsc.n8eIqN]J_L<`MD+TQEOȘRңX)W{PbnJUg-a/>~U*5usӰ˾0S@)1F`WLgP`}mes5h=1 uσ{Ltް3O}Hۯ5_b<7|4[2Ŏv Φӱ9[l B鐈5՞3ø>(c9H( ב7PEb'O Ay芞K/~~ȲgQ&LM@$f;eL"y,ifdi&ɾ/a cpnr\((GcjbRi-ת ]a %5)ۣ;zd܎RL$;狢UcZxYOXDIxzDZky|!&&γl ƞ%4Nqty tքJ!i$˺ Pi@8//{ h(Qr)=$mo&Dp{'hD@ʿu0*0~nQH0 7Q+=7b\K!{ &H67e?2Jť=M{O7M6: ӌ A~_&_2zWp/ri[.嫝|lpE0sc$˟vy]m?t]ѽ}( _M3FNL_v 苏x>ݎ:_Er+F9Yfmr(mTCnylş'^|Dw8^#caŸS/aN8`TN:ۓ0.Bl,>3nO|!+7qu.RN΀<5w@gN*ZYV@JA0t:rb n*H8@$O)'AK1{^9J"b˗ E ~ 4A'DBqS-2 ãIzXlY3 hH|Ķ!ckpAћA"Zvg仍Qŏr tC,9Q#B'(cxy&,&" q+ V.l? rU~JUg*nV=ֺ~BgӯkΧx\ѫ(ONgXyTRϬT&;d}(vUD0 4R,@K78%}EX^-(CG!!88ƃ e,2 $pP(FB5եz?B3g`]-9s݀Rqȟ֋<2L)#vً>w&sNљG+{j(=fbR32Xy# +#N/ 0?rR-YI1ʌ$B"zt:}klE)w3sm+7U֐(Yt:¼jqa3(S\d~ xR*,$SpiAZ!Ҥ|)ɼX[(Cq2@T z9Mnst86ӊR-ʌz>I_݃e 3v7nG_bQ=e"担h,J~LJ)dHN w}K}RV Ùw"$}[e$)]r<0Κ@W'So~-B W! 8mv-lf\UahuC!nmd) gA)=n&[!sգq [,5(L@!S=rMc'eCq\J4JQ-Z(ʹ ZPۄ>qeT!/! Es#Q(ƶ2,v$PfSItH+b)_ ]ِWGu0\|1 iY 7&C\av}\&\W!q}f_+3mܒ:w0pn2ߜ !ZԉGА"*8Q%dļx1c(Y2J>I?K|)Wjte8zDpވE[PFִz6( +W}}z-.F@j(UTtPV9 BDQt@eXbjzQH]A nխU{WH_.2oP&Q1v(cLb`I#Ue2"Z PZaʯ(d/t`#M^ƋW:1%.:M3&Wfe0#$!w;PDDtEO:(-;ۈ5<)pQo'%E!42!uFP*q _00gRK$#!ndb9$Fm&Y2୸c\ *aM3~ZJi)) >ټkoD5lJ93e-#5 & I 7jT+hJeZ4N ʃLҺ 6iO!% ,MҌHGjK^͉K.l5$Lf zV2CM"M2[=X[à`}y} IDATThba#1:&vFG@3Vݪ[u悍0nס-cl߲]zXńҳйG I70c>e0b^ BM/N,Z1GLv?.i vD~L$s6 ,("ojJASPhBpYQ Taysn枲"Z0meJgxňT8b拠=+z`%B1 !er*$D?#8u*NsKfRRZ'!(4JySÔT,R#+(X-RurDvvʉgD.]%o MR` J/,^!#]%ff"P+_+Tu!*&eHyE+3`NybYMDˤP0ȶ roFgOJPP h=T B"Ռ"'Bi@IBq"8偌l%tmN2#<B҆س{ AQsNBaL`Hㄿ@X\R(n!s9ueUq=0ua:|w fxTV~TrB$5oYOEYRD> YzF鄡.gȯѲA&jΈiĨ\RK,9l!rƺ:d|>O$ JL;RoK17LV5* ̢ Q]i(w0&*N0 Ȁn;‡uea1aIhg*ciur\o*nnխcPfr]׶[5_'o) ܼŧg2ơpŞ|hAq=ۺy}[fnϳsw];Q?oiY[h8,g5E_f TCҒD-)^ID!D 'EYk=ډ$`I6(yTh 5X#ÉkhW PfJ`OycVV^&LH$"Ú!P&j!RXb3-*UC&E_)f!٫Ȗ e/UtnXGuy ^]wF۵Kߛ5㺛}3 Z{>7Rϝ ?ݼ1:_< #м)͗%UZ}-˞{R0yG_=KwdmAE$TYû+W.]_xɈ?kS?M|(b[Y.qu{hg=1$0dzM!M 1BڸK; ~b'"\^Gԫ;]_#ogg91?NI}i.qۥm/ Y[uۇY_]Odij?ߚ2v#6{4}5y;ߣ bJɁzs9/ϛ3jڣC{vik=~5aVw_鲡(aTܷq][$ oJֈ481]#@Ӵ 9.f ЌGٌǖ$T_$J-5,c g6OLPuF$9k-h/f'; PcD{0F`^^wfOh*dr% TPm5l{l}4#ک_~ 7ܿd$:=%'~νN͐U(cBf), B%?J#օrOFTbNo􊟭s9xgqq0|Γ7sM?=cL\w7{F=>8>o75~ ?8E~To%?+pO^zJ7sgӳC2 YW{-9Z ?>> Tѩ2V{-9?WzDxֿx㴻ΟG_҆J_  yZ?D *FL.@ Xq;oֽX c s/q\+q)926JM a Kd*XZ_$MMT(cȅ1OEZ9f)łv__ SYc7',άg! (^,+i@ւE){ e[pXv @d,7JdL=&"5#֠r5@Ġlu,6v}6R$݊}3q~uUfAp3խUﺙ7cme~ gzn- 4,YxđI6LRj],~Pmw9b^I1O~Wxe=Gw_=ypǫG}zn-ԛaͫVB u WE], ;vܹr ]ɑ-#A/;԰PX169b`dC,I( D evB,~ !O#~βLM^qXsϵ?0& KM]hW}^{k`͇Kp=Ѵnﳂ[o4 X` .oVNz|OCKJw>;bgwݲ4GnKAOz^0~.'s=D{J6269Lъ+6i0n9G*兔6(7q_yH/TaMC45hio-+g/sE?/ ! 8d=;23?y4/,nJ( Ԕ&EΥ 1"H>J/3?gg ?c *?ZP*"ľ"TyKN1&g&#W'zw9"@KZbnCWkgh ӘtPls]* z61EO7fEP*EOH^\{z:DQ#j :T&ЄjHڕRQ5P6bD PAIA A(eĈ4")X[G4(0%vDᔁٺePBfԥOiYb M2~ңgϧQϦ\Eunխm Ӧ//tn7jiU}-4肗b֍)TO8@@_]nf\UjWB5U]ZoG;(}J BGT|F˖,|Ƌ?yEN`uG-yW\aVZuq@pITLQ)2 "(28ESAP#5Q( tZjڇ5Ógػv]]9qM]2IWXR"Q!ygP(b2ٴumf!Hu\uР  *4ٽ]? xYk H5wf5~l6˶0,*?c,KAfV1]JqUtOzFjcƦy֚?!(%"J"ZS)CE0Y2r&h6B?mE )De.^,h .i&kFa#hD TZBPAPyό8k>c#y[f=69e ZQy V\ݛVrL+jE[|k~Ӣ77Q&K g&vgsN{v_T]`jDG{˔V+jt/'D ^~q/d2 mO6Ф^4jIƏ:g] b,u:G/}!ȔwJ3M +_`l 4edbw*Ozp- `#j)GVuKg)VuuL48((gv[_ ey0Cd5|Ul(`أh1ՙ7>8[.tij7_0 dd˫~{mҨBaiTWIk,QR&EMuE E"<A+@ ξ_Nf#RYZ3® Kh#h]ʣ<ʣ-W\F &6N>ψwhX|un "gnٻv׭|ssG5y/? sD~u:j&ͫF H3+a2 %\C>#14FbT GMnM7Z['Oh}`ŸmdXθ:E?[߼+kͪ,2ǜ/Z0[T]`7]|:Tnnyb_|c]Բ^9U6D^b] ({ bSX-QtNH8oROpŰET & XmPL+D1K`H$e}I/[MDhzE>*<ȫiy2RUbUq@my_;0֔!Jb1'5)$ qy!er!>sZŦ9UCDdT KiiQe ڲ3 j"5KB V˼ yo}䍴< UnFy6Bq[1t;X1[W͎ҥ˖-+~QQ#W;"LHÖ1SN?1`K)+L:*piiW2ݨ /Jp SE%N .T]璄8#`gez,[b,,jӾS.>Q%Lb ȅC NFLFȬno|bh8sүS Fbq(&}#jFP-. \i.T$8y; dD%pÍN 7b`'B>iL:wvo4G%H7cP;cGX+'R|B8ZJ°)A73N[K=R 7a)d$5qޛ9s?WxV IDAT}IfJXqۥj4[מ!"* ծX8!trf蔺(8[T (#_">J(cKvea,&0Q-+VA.d@ Low83HK`)Jn$nxaR@#|AqEp7/"eQ;c ,kH~t] 9ۖsmy݊"x+E.b-B,>D\~$StIDa"21z3Z栌=- Yƕ.s#*`qј,mem/I3({h+Ƥ\ މ/2 xv5U?wE?4i{ Qk#X0_@u"3\^PL MSBy;@hBG%~SOWcoyoGy|߆R>ZU"kpyl}c!of\#g0;G^cBd1Q@|XlJT*]* q8̕z6iap*}[44`_\c BkJٓ0h ֣k~-'&+LUDׁ^ ǻhGfI`I[RN>/D"AA\!JTA! 1=Ν`0ϸM Qe-!m)˹2%n*NH5{Z`4!< pQD|R-fEqa@.N(kUVl. |h+X1A b1- BٻjZP+ul%BF;!9-/e U}*v\!2&mP`'FT>bQ)  I%*x{SԲP$%JA>k2DnV<.W< `RKJ)[$i6O/XdH:3a>VֈԷ6p??ЕDzǟS|[ǜo<ʣ<#>)/-^Z)J Z@Xt(jQqPS:p-EU"IvmQ0)C7f)EDi%/ &NXl"Dˮ(=]gJy 䙃z-2HDN/՜AfrrRwP(d.AㆵasC(SJZ MϽ\0FA+w )JD4Fb72-4NX-`m8JX˲c(S>}BnPb4l֋!v[EJ% {ČX,d CD2)R~=vHЪpC [l;Y;kFH&C6SL/ %*ZE*eaQ)KhRL0(ˁ=_LhʟK;CK$Bp/ 36ޗ\3\Awckꗰ#tJx%š#2d&n}0gcRsY2F-^ 0(M *iuDa# q~80 "uAJv6&KaT |ϓGcɯH?Q DXk$ɚ]c~BNL* 0x3nQb""&+Z #K *ۜZȡ`IAx]$c:A2%#_x1th鋸)f(;{= ĹҲ2$rBzt05oJ 5c KpkTRz6 roD7DAi; Y::2M"_ Q6|c Ia>'07;"b"g3Q^]ӂ['%>,=0qUiQ'p84zv ]IʕQMJ@Һh8Po#G'4#SL$jN[6 Ӂ f[A=-bؓFyoMoQIpfSFQ{`(2] wTT2 lEj{0B,r䝂d;h"I}$('mg`rcp( P'(kP%!bc`'WŰDG횧s^\;(B61F$BRt}ŮY=In\; ݕY 'TqI*$CPɗu`uTa wt:*r;|9O7O'Ke Zd 4s07᪶~S@{5ܘ A"&wq8&(leD0amC:i917س0(kKˑo/d3|寮)v2Qu +AN !姁?5TfcPʘ`3 k+J 9-"i?ڻR|u5 (+K(|RwBDCڿ68yqAtҟu+c$o) 07<"mGy~P,L26?;Fvoިm"H #Sߵe1lcߒJIan1 C|P\b"2=n9d(`"Ȗ9 )E T4mٕH sA+Z26;RJfS@x%p&" ܌q9RёѬ>ޫOiQ]ٺMgB(!^uHNA> Jp ]5(J0D<7bL(e]1 c(Y+8ozJ|ZrJ H -iHQC/#U5@|IIo@g> 0}c"gFZ<1ho LW@ [Q[t;c1^,FfE啊F[kfBuSسY Y3 Z(@qumQY4`B.I%=ti9-ICoty2?"<C,}ݵ~G[%WK@$ʜ(-AjKO{õ:Y僤c|G#Ş9AaI;E^D)c-JDn ]R5 Sj/ȳΪPq4l ZF>4ENC`T@aRDB:vu YJ Bu)k"G Wn t|Ran@c%w`]>)aS[ &IWP^[lx B7nzV FacXJ-F"PhkT\6艬BWbpw3_D%꿑/ʪv5o*o3gQb};Ky$Q 'T!6No 2}fWug:rP !ZHΐiV`eXP4颶\/:TP!Zu`[A Pܩ-k U15e PԺtdTQ!*4PD*ՑeH |oVÿoYLo}sȏlY>-yKQŸ[-߿Gt:^];{cc6l$>ضe~I 8#:pTr Dжc{r8s+'~E k#}zޡ12g޷=ebՎN>wi3u8=w̠5v$*#!P{og>gvx?ke{qood3 _xo#m䐇&K9y֗7bTAJj0Q7X\Mgv`39#؉7lB!;>Ght챛'\@mgҵ!h̨Fm숲yDKMsjf$DbNª&]q_Rv8li S?P?Qd =/e~?wP9)WyAy5%ifWM4 1ؔ!C2ܗ"'= zIP!$MA=ҌRB2*݄%[( z )FԠ i"dU(B@\lYTA)$MX"4S.1FUݓh萱털2iOOo"k,i' w}y)(]ܹ*_t1{LA~=On6Zܻ̃sҨȾtF-_]ݙvkw`N _΂Uj^qt j}k6$ E~'?0"K{`̐S4ܮ ۝3hIqNpvT9guͥ|!A m4z!EɺD |=!.04ݼrkV/95EҟuNd`C.[m8~ݷ0Bu@V|'J)#vx~ع/c5|EW{+w_5׿9p]詮w>kD_Y:1O{v8u6\[ûJɒg9M'cLߞtMP<{ztԊοcmшWgy-F{kcBL?uo aRn%h켤5B1x`& ,'Rx^$D;jcbh( %!` #dXgW}yO@ y 6# F.CPJ؇RƤ^9bKnTL '|L^q6PwLhXa዆)'Hve!`)Tz5eI=EȘ6tQ>/FlY̌F>mY)d^]*L4;37詺nP j-1\PNUkDZe`R1adma*B. @qfNdpi5elѬw+kδ,PT=fڊgtYhwŢ{ `G_뚫7lDZ_  $3vB!{r5ٰf OZ~j8wOtF ;{ܹ?zky~uνu!=Y FXbYN/knXt}ԗcnro{nMj,obU]`aMze"rtA>1eH6Sm-_q?sI+i|wOghݶ3X".g^[9ĉ^֕?;`A0!oT ׿nVïbY ݀ :.cua_u[#nekjТ͉}/뎫qeo,^ްٞǟphpm:#p־t{>a]|y: 4uvQ_OrKs?~s{|uο+zM遧t\쮏iA%H;и )јc!KwԖPF ໸4_L&Τu\.n$ףs`$19'LK0m#RàtZ#Ec#]r_`f9VrIH M)T4")bpKpt3!{20+VlCF`lC&"Ձ6tU>=XȖFɵ wCT6CUlv&,.(>2Z0 hL̐uA (R[tR SCQ%9S8?ˣ<W=;P%/_p {rNVoM+>zd qgBV}Eo~Knq珼ϻ{a]|]-gSN8SYa/tӧ[1h&]wW8JEy|EIrγW_~=?q7 }:rCi+,:vmn46a/QO=Ɜ8ʹ,bgaY4&ZBc!?kipvԈ3&:xd.׍g> c/.%7 =Gjc٠iu'˖+^H c ;T{((sܐJ+է`K nrUٌ_ {wt88+l.o};ۮ^>4|FE7?/ rlўv3?'^0꾫??񊹗~l]-g067\}%7<^Glm7u3l(Pa 6K! :"G9%%& neťh| =qI/Bh%Hm4Q|&:J$slޠoB$Gpl٘:;}Zh NJDš>rTJ]Oe\"R<{eXNZY1 @*&,TTbQ;r+͔q*6PjmV"eswzRtڵs|ʥ!td>HOfd&4ET #ۊ2-(^SƎ} Z l߭7tbZ]9xFl8%.IWyÍEXGy޳]Ux:FAH~*&:A }҄Lq;7oʽ=.lUMwi߭ݎ שׂ5/]W{tNf=%|ڢ\}G^]wߵQr3?sGDBhG`J!2VTkcqIXhR~aWM'sGr_ iOwτjT9`FE#!9'"' WOz IDATuz5~!_~; 0Uךd!а|tПſ9$2 ]7W~}Y"E&f㔠s/I.T>Fҷj H (b>'`;c )tP!RBIJ[,FEޡIFLts$BE Ce'!j|W^ȗ6$?#q5i]6 -WTg*[ԶU96Uȳ"i~㗧kVrU2tXtr<7?52[ Oa \7#e)OQd(0so} ֯ 9w׶ݡjΚadOf#{R]TY}@΃DzU'E] xة+`DA৮'!*l;{]?߳_M5`Cknyv+yK`+;?] d! "aƿ1an5_0Ou+pÞ~ϯ)_鳿x쭯km`M$|Q$Ϛ⁍*X_@wfӈ6C=c` {OX`!m:)K].(W`' [h0fRQVrz~!R76H\%?'p|2KV vJ]:0< &a#ʁrAuE ^6SA.y y6N ql#ǫ "2y~R7ixVT Iexe-%<)$糙uFDƖ(T"h "tTdQwP)dbMF97X䎈.(TCeR* +`fHk"Ik{!D'af_Bsƍo/7~SuUo4?lV<ʣs)o A?l^pۦ|M( 3g1sQgJv?^ͪ ^ ‚3̝b;fh5Ug瑻7Ps9K?nF w}'-7viiS/E<6@ iGڑ3p"H(z tBmiи~27dφ)?$lmSoPBj]ʅ.bqzbׅڞ% ~?ţV+T>f@E^Gtw}2VLv}Ɗk{{jhdc{^90a[' mCݬR 8Am֕=Mm:nZ0\7WĜv>QGtHL_\uWQB]UR 'id~geP֝͊ୋH]^ 񄳒핂݀NCq(M4ЫB}u #5&)i;e 1 0ʰ[aR/ZO{NإSH"U D:u=ҳU٧A&EuZ.bQAXPT X(5h4fS PAd9 /5IaDQi[&s2l!hV:1Lh7HYٞZAg.Sٺcw5<{;L][i V]X5bBݚn\Sn84Nϝ m;tu󮿥E!c٫v֭Kr.3 U>6] ,hۡ)pwzhllSHz&x[/vQso|aU֭|\ā3.>^UL3OO]?eazcsky2o6]'1[Ј苶*UC@ĸ[ snT?Y>tm5=~&?>v]BL t&9`{Vԭo;!a?#ZInЅts_X2}[0 Oz ~F{g`B 9iʅͶw_6 FMnM7Z2[d.k-x׍o b_|cs_9ޜ0WL֫aُNכ7A{}džcBV4Q糋^:ρ 9YE4dD]MF5'Js`D^5*IIS^ _YL>fʴcANB4O#f.؉~xLT(%UjI#5 `QDTtbY>ˡxcR)ubr$"-$I b!  lӀiѤP,9LKyGy|Gq[q]ru)x!(@N1NJS7%lzIC)*%l|IDpT@ɶJ;炒LS1/]?;3=Q|#( K2'~hPz駬T&T nzbU%WcPʼnO"?T [hR&vIr :5E VHV6ZS+qڬ(.4`R'v :(4ȔXĄs(5c7xĶnj}(;2gB*(b)tHd)?l\"zfΜOڃF4aI{DJFxLOLP{Ck\HkMDP0"K̅@J)@fA r!N T♮츭 * agm;EÅJ&AN< !2&=~MT&Ы71oWEGy|`Y01|fghe@ WpiFP #URqO6cf%E$pHA>/AjKd"3]i_L̛ӮhSN䒪@B1 1$r|kubGH ,U B% WCH֚ѪB^@sK\ (uuW*1Z;8evh3FBQkv!H)\(vcZrэsK$dw`5| ˎէ^fh[&ZO̙D\%~O<CɊ"-EgړsUfGy|%[rNГ =FFL hb'!mK?2&AB$䐜yR$;e1wf&dE?nQ7SO?@)t k4t:Ă@ %!3QA,,d|+)bӉ j١GVi_9OF h96?W[ PT 0 }滄C ;>X|.]X؊OR:azo_5#:PPwglsI@L8tH\%.%:y,InPL d,d"5DhfvCę"Kg؀;09c!6TWu r7g\qs !U~$Œ2>5G~qO-b,$Br-ӓl8, Yҹ@ 1WԊHgdE}P}vP8) j H c&KKns ̚(@)ZM]IOM-]/CՕA$0o!a, Tl^ow~[|5ݨggGy|G`}AN3b2&OSn1YGc&Lb*S%=m>*3"hC9Yw̘^!dT'<qS>x&?I+G,:lB̫rX,O8̐5@&\ԅeaU)Yk HPXlp)Ơ/ 9^@By息g"ajcAh&mBܘDa!}zE`:r➶ ),Ƭy;L5T \;9 (BݝƗ#jg^_S#qL`JP8de&/y[c|HϦ`DHҙI VX"!@@ܰsv :Wc.n0BUpL(3ṖSАm5'b$3 J)DZk{*esYn_c-#^=Ott뾫t- f-ޔc $yDМX? {JF9ȏ`1H^eKLS&?o~>LuLAԒ,>ǀ2ɾd6]FaE1onSA>Qjl0 a/ {+R@hLqLj$Mo"O1px s$oWGK G;B̕g,E&csoUn aA =o }# N('Ԅ;&Zv:'mIp:DbE!CF_kחmux[O1)PИC R |:$ݾmHEMeŧ2B'lDrlFx*|G1^i^`@ *Dm0 "`*Ld|@[ư[{,N[Zڿc:i/ "Fy@n'~M>&%Ɇr86'>g뎹O9/6<*CmvYw޼Qe]TY tLrR߉à? :*bJpX)-1\ĔRi![V!KCH" _J,D>olML(#Љe1w1!]Clx5h(uH"Ok 6Y4vւΜ\$B ,0 {s{hL4}r>E9L,cm9G"6zJF&;}\b+rXA6H~kdiΟm^zhNm{3O:4*^ɢy3&7me13Ȃ?h,)ե9w@ ì.'I(ŅK9a⽛Kɬ0Jh\߾kø6`=`]Gz8*<Ȗ;ؒKlM1Uudd ZIPh:YEyֽѦ}Dm]sv(Yںjj]` ^TDH2b,qmj:dͬVJtyG(RVh$@* DQ2{F"ȴnOQ~ݘNkn5oWNLfgjHGyGyǿuh ΛwO^c>[jxgθDi߅^zqVV=aŶ(Xi{M|]J/\bЧ}[]WUMvt78c;wu%}11>9w_pz[DX쇿~Ә;/('"oЇXAdt <rqB:O=:\C=%dT)kl)JY}ڵ}>`ًnݦ3":P{gxh⻟~6;rK6EvgKG>B&:\D\-2iL3R&{/%})<ء 8BJLrdg2/01:BZ\KQ58:xxdؘ8/z@t^ɼeڄJܘHSBpۑ!VƐIA,Ei+(kU;F\/؋5cSS~ P|u}L>W$h2R>v+Y2p40=c#"RE+X+SG5Ԕ3/fݞ~zkeȻf.zQQ߷aG\Y_cଲ IDAT ^c pq={uݚm\dڔ[n:f—^ lTQ}xܥ_|c.AUAú;Qq S'=hVkڝ#|c9+X +%.F-OU㯃60X*E|ȵl[c?.o OCtڹ{^'ծdڤ+Ξ0GcX86l3voAZyAi<ɔɍdG# i6Y Y$}H6T Rd#o p3Gļ.yBD$zm EUaaDb`|ԏ~bEY6#gk@%R:O(. +P/ܙ1QNHI#W*CA9UR {d$E=z؆fGF)#WɫL Cf'edm,Ѡ@ZUL9@*TBA)e z6QpUSsP0RhBziT 2LvGvzD,;-(>M@w,\1-whwh鬡+{wftזܥ1\z*V־a;;޾y8?}]S7wƌ=xM;V 'sڠo^Ag]<iZ5õk?xa#I]QCD8NDypsъ=Ox9~nu?4y#۴j/W͎Bv暮-sYNGuug{QbBwɔYE>p2Gֳ:,İ~$ ,{ȯ{ypw;7:d\tBǓ.^T~Ґ̋~cy5\_D|)[j as@3~m;{g_ױK6{y#yAg񼽜[=3{_ BO&^3,s]tsPD1)p mbfŃ/ )2$+4ch#qy9@J +#[;9Q" waW}Z% 5ҦrU&@L=/͡&nW|#h|V!@ZTQH.@@), ($T XB HP1!i$ZcEadp^vEt&ЂT),*JYͨ5h@m S`$M#TuN CS", iRJR*)::Aٳ%)0Y+oH 2.(3gOL{zܙ3MvCg@s{€qbq?P!.zM⎍'CǣO`G==\qM[n_-{ P a7u? @+gM}n2U Jy6+*snۏVmr=׵e MEpS*nZ*!bs{|qYkW|3U0ϙNaϷֹGy,TcpRAUXt,ZNÇ_x>Wh?׍}jW7[ -?לגiO\/l?JJCh2r R3mF@BxC#uޏz|jE ~ş{~WvE&+rb}m͊ ÇZpڎ0J/j"%$&B/kM$EĈvriva$kN"U8 {͉ՠY 6xD\4) Oǰ,yDY"D31H; =a"ɸ$`0LF[h:4g)Dqx|7E@BY 2 = EO_"QNwMA( jxh*BAs&~ԨG`A)(  BamRPRdP P  2,]񖑈]ÈKs /f cQRFą C=P:m.k(k [Q<+6iپ[IO:~Z]9hF΄Ie!mN_y%=2n0w;k5ğXuW?rǛ^ VlPdcqw@AK]Dע:C/0cFM<%τ!!:rК )0oIRr- 8R&)ҟ5APU%@FFpLpQU?0q†s_УYֽ:sum`%+9c#6%M7?,ݏ{ 1ZTU^0|;xIWVo/M(g4C6|]tBuNĔ*D8{5Иr ir5 $'S`$2ɔ8ERJ䦒}M אNyB%sݷjxՊw"^s͙D̔S@ABfK]gS7FVK2$E6r%LNj(rDGDwDD3"swF!Z-sĀLF&G_PN/9%@-$=*D>\0rZSHV"c 6bڋ2V K&+{륐Ӥ3`e9K{yĿ >r+m!%m#ܺO.(&' azA׭dcϚ;kn_šQ3LC?#{c-IgM'*\_?8j^~ּԫ?3}nS濯6ߵ^j|yFQ `7:ןe0$WnvcƜv{ub /dUR͙&@s7tCjjlf>GNhՕEF?۰}ٔ?|:ꌽޅ>y,IP WQ^ Eкmݏ[ߞ8썾O.c_4la׍<>e5Sw$yrL p|,.D _X&PD,Hr] 3pWmDM..PHx {"tH DK" FaBlAۚ)A𯉯 /^zQN˜\Rv\ȝ/ܭĬJm(Ȼm[uܧ"x'֙.WF(83} hmM:0xIȬ]{2ehp'4(_6UcPQhc35i"uE5ʵfd@Q⭲,CĻ8!%mr8%yKweK\4J 07((okͬ5'?Nq3N19R|+&Ӛwuſ?z GmNgN}zzq&FX8e;>֐L5ncc#06nJf_R3)AI?fMy {E'G A h:LAܩ$yd{3v66GOC/k(hH2+di^y4ʎ_`Y冬&)J'ޠ~k84yL"`eu͑Rm\nFO'>nVrEOӵ#45雀̮a!U yoE"o@P&N""@6TUT4TZYMأ4!D'I9&""T@6((W]&_جqՆu+{?y5u}vkqՒg&JF~^yq־sVyOlgظ{jݦu+\܅W?2pƠᓟUUjcqg@#;rR#?{I7ϗ<7eo|kPU:ߛ|Csהwl|;ONّ^y1o|elUN[~9v_}s^q_O\qUyhɷ I9,b)ASLVEWoCF0д^毯soX=k!]z~M_62ABl wT=ÁS~cX۰)f:_pmۙq&t5o,ݤU]`71+d f_7 i),>٠%Mл mz="ăM); NYLHVV#R adR>#ɥM11״VAy&ꪼFr' PT~EI*A x6#َR.a(Mڲ1H.0czc({ܐynᄃ\s=9gi-j"$q)A@?ilʄ6.F^̚%XK;iT[kwp"DR$[+It= -R_zk XҤi-I.gc6 ۢe$+}Q}G9z.]l2`y!>?7A}go,Q-9[QQp<#n+6&qes yYGEQaw'0q}s}8s[gg=Ou){!iJ!2cVn4/Ċ QY0wQZ{ c1Ǚ I0ŲP L =d*s]QHq >fvp;>uթ N~J!d懗9Ԏ.I-X2-A0䭛1K(i\y kS)  f@ +)~ 1r^$ ٶ{⺢w%2rIqZk'B>&LJHu$* HRD{K%b6|!u-wKP04OI?pL^&(S}Ap)~*k=sؼ[,,^ ,z\5@ҶX6cI]AӤk@[;t;FE ޙlWɛL),PWh8tYDeQhlsi*@[j[mZ6`XؒXXQ%q$ x `qW*#(*R`8abD Bc's cto q>1?\D0egr$QI(w;]_<0yETρ<%ik+6`T4t$2DyLcSܪdF6'QݘL_H %ȂSJ!l07EM[&$ 9IXb$a.PPxO9%K{B ^bSX5U6c6+<b*f&:HN}3ˆKFGrL3|<꧛@" [䃓S+Gg1V*tC0VPBa(<ϱ7. YD'(M{e=kiMU.y &w#+(y9c2CV@͠@ _N:vC(rĆ^I&fŤufbҨ)بF~%ߑo5ZcaJHNzhbIvNJ#bN:ijטj5T_+0' 'z_ҵ@նV۾}1.ΟG!> Q<4.q{@DQejH"ơ茡 +ml$*7mN |Ju>j0Ry:1DM)Έ]BpCЫfb_! (t?`QukHQ1 Cy(ӣ!4Qn1dߕbNE3 LU(wBIj3`Q)jjR96'%@ԭ8d$SP(\p/!)`L/ʹHiv*!ەTVǴ!b,:+:dE²29@G:y{PCN%&=u#dJdA4\A@CP>E X+IluY y0@Lo)u ,hihVlًekAF.u[-zF-ܑ4jہT0) MƇA!*hӋEYH9[J<*ߒo0a݉rնV۾ ƬB.( r6ވI [AIIc&jK5YxЖEyD,ࡆѧ)$z8B'O,ǝ5fR-"I!I!Xt<#&MLˠ zX\vhⵤqTN:^s&KĪ䏁yU)ߚksA6rT eꋞY3 ZR`P\-UT.7֦LPP9v?WA@ )y.zF+6J,-V-[T5uXDlY3˜ۺ~&OKDjrE~**sO廓*F1[UEư}G` T| xN>@-ݛy+đ MݓC2M:^&PVDIb%T1QDj mN\L -Q(FT"nIGB+s0dh%*HAGp&<x|ݕ71I GP*!+Kbݓ]k?P0)K]M j!9 #= t`,Km7P#:ú慘xeoh!H<Dk9 fā] */cfLdYX9 O鰡RP7 vG^v)JB:d ,(w#dЯ6 ,5JEa Djq՛|E+ w]$ ucU <Tm=8484[짶@P !ljO㮽+(L}3or I۵:O_][2}wZpw5,"nyln҅씛n{FkL.CG D&MAW041(&LYG2NV"yKHC)GB[(V@p)h"()K%tjjrNdJ%T%e]&T(gBGQ4QJ@+$TB()4[eZFm"24"!i$R%9V U=b=PPh,7*C#.rQLue*^C}J%P@hm_L뫸cRWWy?_WK[}fQ ioUSǮao0櫶_8~u>GtΌ?恬3^չ;⚑#ڰkbMk_rp;w=lw}pQ's ~yެt0=ߏ9ӫ!`i,uQǵ}oN۹[Gkl\w1|k;|l?<o{dp˾.{cz"ZF&%POWtHA>lc!U?NS`HD ӔB%zWQCzSx4DFXFɛ#&?fJឝ٩d {<>Vqϝ׾_V{ Y z\b̨v@wsI`{ݦxbXg1u|@)B#Rro<~'J'渒],6tG9n5n1Tim.lP^:1]N>`M v7Є^]߆OwЩ_<mvotS^ ~r9ozhwCU*Z-¼ϹA0?oQ` ,-3ξf?_~/`KϘ?rM3>0;ZG {DY0bxcCl+R4ziE2Cv,b&ÅP=bmW,VUvN\m-+ %*`(6fxӡPd%BQ REM20BeA;f# ؈D}19GF⃹hC.+c^NG9Ϛln׋Yjz&]X}YURuYk]J)OhK[VuO*qGmUN @r㠭I "( 4i7"j׎ܣGfl}T4j."{O6qн.*?!0L+OW4ORtf-+Ou+16Y^}/hL'g:٪^VV#U"P 7_u jq}8} vG\~yU8 [oa ]g{i^)z&.ɣox2o0Q/M>$|2?|g(Ғ&`u vv/#p_EF\cdfq[,bp cr_bhlL=MBc$N0C1/.q_zv0yȢ[>t>SG^ߓn>' G5! ]u @\wSOxo%ߏ<驞رg͸l/B狟Eo?z bHkpKߞ|\x%ʣ_y^=Jacn}O:{̍oWn 4~:Jyu.yfO^?Կx-|I*w{^qL?J(* !楠2~TX$M#Ѥ蓆IW)_Qܰ~5#^\.ߨK^f K5}`ф<2GG*pޫ^)քKyՍ?lu`m~+?~ycΟ&D#qpш`}Yo`l6">]0}}]4kߝk3x~z)(됑J9*č1<̖ҥS)H,c/c3=e.B9Y$qT6)gqGrbZWHAA _ΏԌ&.F\?Y}D>PHgbA5N`*QYLeK*ZtҪ*yG4mԾe?D[F. ߋE 1͂˘|^ $kS;TAY6 7\\])FCA1Z"vdmμr* *r 1l!h9m~ J_˖e~SWw]2H[8vjovo@cι>Zu-2nL=K3IbIejqq)Eo?G=]k+Lף!)ÇUOd5ӕmuis  5/cJ'jWj-:t?z?G7/{F"XpQ3L]!?M0ZEBxB YPDG&i`Lg<FC\4ZXUֈkje~ fk?9޾LfyYFs7r)|A;٠ aiD0V_y# QQfïl0Q7 .eXɂF^4p(,S#lVH+RdbD«ũQL[aD4Wn{򐙴 8c`ih/&T'Nt(aLH#Z8'SiFXUHS3iHPHl@QXRN$|d-4Rib3fd''KE&u>y 7c  (*ڹG)ekL]1-X/(kOڒ=C|ʎR+QPCˮkIOH#iTPBHzJKTV\rR JXBrY7˚H֎lDZ7eS/UJ)J 1ي`VODlFˌ.躾~%A{5W5ܻNGL'IU`/OO5|f7&>şuy&yE_?oԮ̳3 QL-Y#(?WwnSg$_q=aO=d?1Ck9ʷPc}'ZM */]8ћ.dhڒ5:x"ȏ;?d}1_+PYY!ׂ*NUD 8/t…{=7 ]ڭ-HyB":J]ԛoS>n {ovل3ʮ Xޟ^yI''9k &,!^;!& aTc+q!^HaU|[L]ƅEh?4xJ^^zn@P O@u6D.v2*5װ MEB0l7n|NV=+@\`=$Eg 99:$ĨwcпqED@5[ZL&9a!nS1PQ^EEI1?١H&_+*o Fj?BK-q/¼(򂾐PdьCx4cr`Q QF$@!rcl"J).DZRR`T&]mٶ@Z7u&0ЀJTDh VLȈJu2u;pMI$:DF2ЂlS)LLJHk$*-rDa qs\'q9>$[M~{KStYټuV|*ӌem͖y[4c՜aaKOKamkY{%_nbL Wo5dze'o~Y9EcP@uxåm6|hc'GybǮ'ޯwe{ .uz9sse)̝5L 3ԧD Yj^@{lʋ/mz ^dx n?ZfܖKesߟイ=eIjZcB 2.TJG,ꍣ.ݝdM{ȱ?tQ!+j=oF?mkذg^냘o.7Ur"xpwMx\WZn4  jU^=ՁĂ}u/xIï["'/&8J0%Tf(r"V)%nRL޾ixC cɜbJs^]k!*Fav`2S,e\oT$c)[DeuWQK;i #__eR,{d? TJm VL qUA&jMӟ8"qb^nA^RUWhճLPȖ1-+a"upu4 j"mZP2ZkA&Nz}>pNz+ $ u9}|%en6cr42Pe# ?x;q*RƧ6xݹ;߮gmz7co{sZm6[;nܤ;ƋߚmooL0it8w>u]~~+#>QF:sQ]vi c>w{wlţSd~d ]G|DBYL~WG۵k]ZG/{q3h~+ܓ#ܿQý~۫s7H~ih$ r-V@l * 3%Tv]H ClH'|vuM|(GfOv}:m\Z'.e4U]=5gZY sgO߫S7ȹno?}{?_~A֤QvG¼Y=7[J Jm=w=kԩǹ^v=;}N݈b1e]K>y5~Q+ J"ZȬo;%D?dH1'&HQBwv6zD)Tm8/,J",$0y QEnKЬHqSA e%:./2gDqf 0,S2> IDATm;Cⶄ&_1ߓ]Ŕ eSH K?=?|ͩSyu(E;bJr:)nƆgkKKVǰ}kh`pL+Db<Dm{u)pimii5&ݴ .%j!@x ֶVj۷v9i"F220h2٨":2]KYQ%( ,>FSNC9"L 7rtHixe8gAOeXUt!`8"NnӝOor$_2kR NGh-)ט oe;/2`)]pHó%EeV Z7I")w QZN~vβǜ >w7ytt0bhaa^-NӨjq;)e3ɯhJ3S$~?6)PcEP# 6@IʜV,D=/>4)Ɩ/lDUQ5*;t @(u*B"-TW36?350:6CXb 5)uCcmuB%@MP ȱo4m PcնVj׾1'0PFD%X0͉d", Rn6%4]J|9`Sܒ 7)/˙$<j 'Pb]4o+JKn1E:2~M.y;:nU4 n!8DB6Nlo(; MO]}V;0~CB# Oy o&[0aLL7,KؐR?σy;ba4C1e ^<(`1MOL 4Ns:8WG4wx^jadFr"Z5'ShPγ c%DQCbUrIM&+\ڷK0fi K_ %dmi LJNJVM- P.ʦb^]+ uvC M/Ņ4,^܂lF-4Hʩ+ ƂQWhOmնݐ18ɧ̻U-؆4|b7vqTN g+^t1t8X˪(AWH,{,D51`Ģuf06thbSaG,*5A@i?#8fGK:$6QU= 1a/"S| $CC9d"^&-_drLԄyYHDe'>|A<"C΄USށp'VLyagJCPDY$'f+A}~u%kd4L/@iu1EH R -5we=YWx,|"̔4 W@Cmŗ i@+T*ZVNbRV>Nf5jZ3"Wf"Y5NuV1Ce q4텁)Σ)eU Y3^ÎxP [(Eb?we3|W*~V rÖW9[jIU 4#&m4A% M ".8le߱(BG(`T!ߪ| X%2HFMAz>eB 18xe`%Zt_7[ţ( 0S"UE qfNS$IIbS r0cFm'l-хp\WTI$l^(]@Dw=V \o^|vQ;QZ[xJ4u*/DkZkTΝIƠMiAN Yhy,@wȲfz Y.s"mTpP6^D D- A} l0W+~ Ts>F!x~E[nYlyX8[6[YA5[Bˇ%)I Åw3 bqlsZXA((u1j2AVx#\yk2T#P)$^G l"HEC]3 "ZM><$*cͅ"͒Ģ(Jb8d>>lWJ"1TX+ͳQoc‚peIwvLLy3D"8]p٪J>#1C. c 9+8M8esNw\sIa@Mg U."a|J CAi3D~jq"$%~a_+M:sDzƛgńHp&%4aI =ϲYq f+23:gڤd3 q{>@5f@>Ǩ/̖<ïzCZVP!gOI-6߻Kw^I^B̞3waNrZTBW(QR"DeUh&B* 8'aŝ1B. h! 6hL(#̛5}N]BJ\2rECylR+xz)Ք VvJ/E J{X%&5Dc>KzoS~]+p|/̞G9NaTSM1&HI2WisdvZCP(Ei*ĸ[O¹\X-@SnIߌ ŗ60dE+Ex! {o0s3'-^g~$f5&3s;DG|v(O b7]hAꉵkޅLQX WA xG2Oڗw0]&(74Ud0I[cbFS!G>R}C JÔMiQlrA3 Gl2eyiXXc׵}0úV±7BlgIѬ+&V3[j6yKQrS5ۉ|p1_^\4P!Bl |J p'إ`BfdB{[u\Z[*RҎdaM!gG#2lj/~d7bTsF uƠ1WԈ&+AqJ͖:LyG T ա~|/fBu 3ކ2D ݤQ8bʚPDREd?< w?!YH4{-iI, (J|((eL(﹃D1=FRu64qBvrg[B'RMN>+B*SP VEXa1EkHE9teqČF@Dgj KXѰڵPaٳa"pYPDZ*)E@T.MY ufVKEBHAl ٷ)RP/r/u<>+>ԈX;E"roS&jzÚQ1SLlE7au )„_~֥6k𫞇<7_vS[ljO Qv{άiftN"x۵Owxr}wZpw;G~L:6(-] mgڿ7 lӺ]⣬xG^o&B\ 1?:匓pil͜Y3oՇvv\σ8{M=Y#eʫ&_>rn}wD^V Gހv??!}`ԃ7]7UR:"@]s'zv;bmzݞ7nj۵:trZogߟwlq%{9oPH[F%^ 1UI%N66g QDbrP!"i&3D@Zykm\eH/ʠѴ*I%3qnJw60{u~DߖElZDw]-ӷRd"z*ΰ噥_dG6kkf]tfrz-Yݺ]N=\?~bݹ;̙5lQq$Vv3f~#.];q`9('LfT=coucκ{z=ސ.~stcP8^|!C&v<Ɵ~lN9r1;w9s4^Nz7ng=q\&Ѡ,dd :(}9+@d4Q !dlX6iW:\|/NE'UOgzl z~ӯ.<Z~5Wމ^H8r5??Z;r-t;zfG 7{zw%[o=w{fuopٚ;t^_WYl tt-0 .Z#Lj'goT8֫$S%j*.j2r]V)µB/Οc>M_gh.gEe9)I}rDC[*0,FlfP15(+`Z&)^4MyS1CMuRVA{MkIU^DSO;Y'JE*(E~"k@ hlKJ%D @!JHP)T @5JkE4@QRr3 "Ueaa+d¨N"E qgyɯ-0>U{:M:bhYK}3f? ̵yX͛AڪͅwN}ʲn\O1b-mfu33L0_$c9=?kǜYӬ>m}5d$ƌ>ݏ93iS]wJ6;k`!1o,1;pŵLyrɏzuN?rc ڿFx/?W< Ə…qBK}*scbyVm.c,%>yl  p'z>=m#搝HS3ajfuΗ?qhr743{SSzvy ߒG}_;Hnf?=m#P(?u0˾P$tF[zbʧvK},%ϵ2N^)nJѣɱ'Ղ>elȟ{v1h?"ߑM0{3 g 1@khU8qOTP. +,$Q E 8++#j~,_נ5^:G^abF 'U7 0\B%KJJIX(7шUʏ Qi"kI@y.Ur.PF(#hDs+5MSh:35{Sj<wsw5}BH{I2*&lǔENËjb\ V,*"]jU 5cWz~ދ w·һ\V#LUt4>S-y>wZ|V B]zaeZo~#O_-#/U8ެá "7S1CsfjXq__o==:n <{~v[Mpξ&.ĸ;??~+iӟCu^k7wQeWٺEp5YlU덷! _?;c;e~[vcϞq/t}ǜ OIٛrV>Q/7o5hͯDgv}g1`Gb>s .;Տx٪w _qa.qڼCNCdJ޻SWc'6^w;~wUy֤7<~6t!eM{=m]P}b e[ Cخ}qg<akw>s2RI#AX HLjsH)sE+?M|*8b+1ɜgOLn l' Nk4t2ᅞ0%V(1.Ȧ q _ٴKPzv}Od~ᔬ߹< Z،ƓE4],^y lf[=z0#hp4ڢ2(RF{iDkQ)GNϝ=}/Jzy٦o~̫x?YLZ]#Xy<$0 +Y;u8Fs#@g&aC&k1lc'V n}7O<-_??wĴ%kpD5M6>/5} W>Zfmxq y;Lס/l?{ɫد+Է]=e3د+ 0y=rʒ. "~9yѢ޼,6E ﴨ9D}JA.2X"Lw IDAT29+g0GqSɺ?u*BDOz͹%~SYūh}7+ޖa` A>gǽgћo9u-vm㌠+R6j =áApk0lޔ59+j6X 5:+KI3$ClzKTBbB!zEg"e@t1nVq[*Rj6/mGn;Cgdlo&Ҧe s ˠ$yE߽`M#.d#/0y$۵*yp篱8v[8hӫ:o0e KMS>.1#}Fi->ђխ7j^CƍuikUVȝg>:SzЦW >u5!NԤefܺ?DbDTCEi, ,5+_k}r%t}a>~5+4y頳Nc~o ?}7N}̅9 :|8}g]E zJ):Pm>5G\ΤǗ <&M|g3fL9{}7hU^g뗧>ÖefJ_PYܨ/p3!yh1[ \Hӈ@].6'B8X_@b2ATU11),n_S)UX@kDUzZ=̣*rl"tEt^"r>Pk釔K-(H$?{Q)E~`rȺUsiA6-$"4-(ىpaE^齈?T2-HZ 5 E|Il\, iPVR扼 VRn-cpͨ9BqH1-тenB GW/5 Tj}igNxN?Ô$,IQy97}ɚ ;oS a-v9oEwW5I;ɘ]%i:@oMz1eih&v3UnP U Ȥwv>w\:>w(IrV3I_w%IUr!MK+p6;7zYv:&҆مGM̕tPWaYF%lœeQ݆W &ӧ̾ghҟ¡;#i#LYV&"XI_~'E~֟dM. "o!:j`yum}c6v1sa,C_҅!cHl(@QU9%p˛2;M^<Zbb`99 O`n>O@!΀yA<7[*<8N"v?(b~.ql1<mb=6twCi*%U iפj?!kJC(F@ (g#U#4PA+&ڬ'܈ iY@]" (4 !jD Ȟ֦E̋DZWj[mm. A۴M UM{HW- c~uب}}Ilۣ\d#yFUzq/Ď[o7ܼC3//;-׷3cn'wh|5*wc0! [O$`. IJ;}lkY_}~uXتy`u9uܸU*T}06'ZDLkPg{}Im=.]שb}\CF_5d\ ܾuEFyTM>_,czCw߾}=mL/8HP 0F_tRǭ7Q 6NcϾnf|a=hS^-5_ž:uk~]`]=f۷_6l>D$y@ a<ʸPZ2ix]'BjTBkd7q?H6]rP'[.J?`qĎ$&׈@odJ J!QXrQ0 Xw\DreC u*WAGj;״C h3I6y+<8PbX?,2<[c)Vme(AӤ ^F 4im}Y@Z aХ-)/a} J:%ER n*%ʪ 5eFkmgRL)ױŋ|F O26]dxQ1my~I5=s-"6w:Zk[mmڍݥ;׮CN6ojocosZlgLq0;4O#Dd0Ҝgt@طi]g9EZ6YÏKf>4^/iu/>\"<&D"ʆ'^ߙco{sZUWgs~ky߳ہ5huC4\Va4AD˨R#yg my}:oRgh6Z@|U[m `'&>q\Ϲ`CN/5~o/sZ!Z )hƌP_H(?7CzwmW,Z0{U8I7 0s03wu7lzŧoqco{cZlwڛFF|=} xDofŧ/?c[VF'sQ]ug3uȀ/۱Wn<Ҝ|^J q-N2Ze$e1 )?^VD1+x9s[ƫM.?ΈKiU_$P~ vƣh}X*fVX](#B03* xܙq3GsJMQL\XIג_|i ~з> K ѬIDD |(* D Z d-ʵf{<@j (3p&;$eҺJJz! h 4<BgMl):}}]Wmm52SLM*i2VG vB Z'+[ڸ#)˕Rkm8ttX&A\q2/t<߼uiXMi#: U oIxQ8@sQ1S6e翈7XgM֣f߅@D}d{(."'XQ&IaB:& Nr2۔jdGwE,Z!BbdLvi+m&-P VxQJdt.C6|eGujIeRa|Rm L`U)NmMX`98 VqIg(Ӿ|*]~XqmSJ;x'/uOTblJIMҖ,.35J34!v2@P$@tE|F'⨘; kZG,&A6c3Q~ff֩o]_j_W.ȏTBk[mmF:Y9 I, A"+J4Y9R%~`P(qܔAqhЉ$UĊe]b#vKB/kF2BĂ4ϝ!,%ĬxҦӼ?rաQ)㞃qD8+;*LtSf^4}XOx^ B1$ euillFQi cdPy@P*NrgL7Qtr%EVB*M8%V.ᕱdd:o"k/A$"' m:+Q7 a"C'V oxvB"H.+(kz,JE_Ō\),H+MI)ex =mRxi0C@J9SRX"n46T\NNJcr4VV0N@!/kHd6{n\Kr֔-;)i[( Aț|Y`yѷ,-U8:w(:&ϹXj[m7|_h)(R8MYq{8L%seG/YA21>/''AsXn E<&Ă\5.mA2ĜTqzr9ax}(H!W1f2qkdC_{g ^)2I^[,xBlRHLMF \)a*.)F"9ENC2GNZs2O.zyXߞg0iF :ؘ6]# 9tFE0:۟;RH+e < (ᕺ9q*=4̭>LJ1$iMEmy ew 6CP3(iC`Z0JC)TP""d b0Rיɾ"|N]˨}5EI:.搜+1qJێ ܗ+<#dig1X k~mi9gնV۾v^8۠E> %UO ^ClKmJr& ^AQ۠tk L4[-Wct2TiB@A,@ ↰]쟒;L$*ǰDJ'AtA%&TVx`+@~AH|R/W"]D%/iHɡmSd`l+qǍ~1>/$>"OQ6P,Ooe `!!k1.[Ɛ 1Q4ԏ֦33)d _8-vyKD-Je-x6r 3C$,䲓cUTAlM1"C7eGi-m Xd 62G1&w8uTMWrR[c]R2xk2`I Vj[mryw$"GlL(?<xE ״0j"l"@+,(Bۼf"VpxԶ gcLDFB SV2H^SC ߠ,jx6,(v>N[" b1NL e/g_V1P+OṲP$70P(5ZL,+oe5y%O\Q!R.yPCH "c&zbAz8\W5kcQB2.]pJ_* ą/`^-fH(eFOߞWZ4lʁJ78ևzaP 5D`so e!FAGAYAPTqH*QDc&NQQ@FADUݽ919z6omiIklQ8$T|g Pi2dasR*ȿ*B؊fA=@CH6;Rq2ts`Ͻ.-]_zM5>:ʨʨ/>rOK<.ʞ~5qIʞg˟]%5u17~gZ yQ[Hևq 1|#IbF$q~ po>>fvD=AA!eI?- *D(Ws~)ɖ%3X@> pG*J$v Vx!$ݔ+}2v ,0D<򈎗:)EnI{E 2*2zyH]#'eftUL ;ڸ*8$l'QJH_/q]C&Fa;eX!#oHhL1[\&GfR!N9CT@w x;TۮDWndH A->%>s`e(@ X;hvZs&$@gE -B$VD$l bygY7LK#b%{&"+:O^?)9-^{I#R6 OpzͲދ_\P6>ka*2*2AH:`mn6?>7릻ز#x`҅ct I=;=85뿾w݋ׅA:Gg￰[>?~w. c[ڟ{7Gk^/^}J1Q&H7Tf tĻ)Q- )  ' 7riiz;1r8*݅o,B7 ;$挦DDB&jʳ*^)C 29\++Qom%TJJTYa TF*#4BYAYAPѼ ˈ5e2Rh@ P %& ZJVQU\ "R%Gʨʨ @4CW/̶y|tȌN߬-th٦L)u^ϴ@?w_}rp3۴?UwTr$PD4#ծ)M[wO뎀wǘ_Y0Ymߕwo1TSڬ41{oJA^i `&-s,6~;[ &-em_@pGK;70?A IDATrG̘3 %OFV\Ƃ,K&(qnH~b238d <^F 'oLpE^%7iq]c?A{nV,= ѓ @=~ϼ?S7g \!wʣ&dxѱ~7ڳ=2]ٮ+v.3i ؄K3g#lRi1fgNMܞibB ,+ 1P S+\-8ks2 +JBPʺ'I">%Vd( xy>e̙9; #ggP?]y5z##Y!3/jBM?nemD BUR%$MLlΐP4)EJ (er|okp: =(@ح"S.kP H!>8D裏*_eTFeTW?x۶#,\t'l.gOKv_V;!ONs~l}잛<*pVr9v?5ԙ|nVqNXIp>>yW-qMy&;qA)zFZ`ŲE-[WaK& 7?:?; [w0@;`i° jc"GldYEO{e:5odۦ\Ĕ!mF^xֻ4膛pMf;ONͶ#g B..A4-X1*Ɂ<2y1=8#+"^QdY\Lj.9j0HjM.g4sL򬑕Vu3(P)1(+Dk GF1X^ChSU)H$C J a5;J;PS&TEN"*LuPfySѱb셹 4O㬣2/[ 9-O6 Oh?fY32/0baF' UFeTAsըv#2~ak9a;XS{_1 ڭtQ׍sP~nq+ם-;?zi>.^|lϙcZ\ӫ/[ }65Nq+lӁvQ*@{c{2սv+]Ծu/|}զԩۮ\eWmgQ?G)WzN&VGp(` mJ @k $`ow}c2R zpg 3 A)HϦ#t߷l6y׌U}PW~]._b7l2}pO3v?p:Uk])%7%Wq-YILV1sGGbXL L 7yRWAS5 ?M.b5(NOb^8^ pܕ@Xi=P'9+3IdCux&fT2摷dA vY{M :=%a7ʮs;+١  atUh$x"=(/[MPG\C)9RY˕TV'. bF"X ArYlwbIRE%cD Z岑%L,*eaRPI=3@wJN9$7#+2*2 'OkbN.Z]zߺѭS"{vy3-wT |.cm}?iVm(޼'_Ѵ 8;kRNpS.x%-g h]bҼVm!w2iN96 3n p%-o< `]7qkl!ymh___&y;1eZuܩUOfMjwL`DX$j퐡͇ EL (\(Nl]\ُ u׃?}psoq>*>$Pv?"{:$Z#敭eF_1>ؠ|h F/o??PnCqAlszV)7xw$CIfMQKy'&]IH#)Dk% c:g\1%ōc }1\B3֓ }1@~%njYJsfFd YK_rI3)Kf!%F@RxAƳMD~;ۓ5iɬs3DXI>Hp||s5.eZH!FU&Ⱥ?m[3*T%J /ɿ@VP M^@P8tYe,+_3 $&-(&vFSS#SGfD,6U4q3+kN%z?QQe+&]?LeOyȅ<xgQ=:Qe6D $^ں5O\WWoqqWs[ :nv T%;rq7.n3,{ 1z72)w>cE<u5@t> 9)P9pьܚYjpPqTI:3L?a#~iΕWߺlI1f9He 5Jhb/+~7dHGC0k7iG?a;dŊ]K*цIp#1α HGIYt$}{4IME.6|k(A—Yq-b4", nj`T2Bf ɫ8&H){.SGc?]dgyUVpDi;װ2e`^D^jV0\<|V=0yD7*UիFC]rX*'}GzJ^㧏(TD+̄/7:w `ýuĵݖ=e_ȗ<0Bʧhs7R^L\מ_aQeo*0sSQJe&"(+h| z(槇^Ua. ij,'{ ǜHAt!XN/QK%EdJQ(1Z n T4 7[jIb%T`1 ^N8VwO)eJ#|tRL 2]DHM(hrY!)DXR 2d´VJJ%ќtm, %5S[U5}'BD $T 0)*Fed>Ȗ#^/ד ,d҈)/SF1lJŇFPyP^!tWK䟂T/h#r]JSQ"ph.اQg[ֽ xѱj7f{o_nriU EpT%EHLoz)oYs . xy.;w_ths%~Сϸ}68eLeb;K"=tL}}бϸ{vz߳>ۥw҄sω>yكlAuO ҔZD.X%w_W={ʹ.6{ldK-o";o|1^v>[₩I)q"O7$Pʆ"ra&$/)b`mzyREY-di_ vo A G: 3U "E +|Jh%nDq])ױue.5e2ԹXH,ݛB7;hv@CXpǽ Z9' ?kKIva朊$މFp|QVp ())]$6۲{TR\RUR.[V^}B ibUk%id< !I: r/JH>@c YB06q*2*2MYk^JpC;8EQ;<* h$HqJκ[JRDߖk뀹H*}0(Z/I!CɎPḌ%w;iZh]DEDu4xCp֙O)9tgB%C;&Q7XHrF×=PPYޡs2m59U(83GʽS-1·INE$hfdWd™TeB7,H aHrɧMSC05EBõ]M0t͟a?ŔN?:Q Y Ed',^&#m!-~6φ3&QЄL"0ig;d,i/, s{!O ZɪBAd'yYVyIk?<` #kZŰO00ElbxLɎ\=8rĄpXH5s*Dਢ] LrZXxIeQ )䘓 ˳D%BmE?Jt'>Z0&IhL,)Fom1akeSVuFxvC7&װT2bD|׼\*d5H<w!fʴMA8PvM,Mu@OȋXEYqOC׵l$ ݢ%C&2v)D-mHaTs?'_Yj{nW&ֺTgeTFe|XTL=42Y")+anI 1v`GZnB{%%XUu<*>1p2&BtGM&0v(x\L6azi[t*EyaGNZ#[˦qsʽl%=FЅ ~n]AKgv00?(AAHybxS^NP>!^! _X !n*,H'PLd)_@X YH@ \AyT x34fd@f(RI18Xde#9MtSYϞn<0"&V*W7ȟ̥}b)rh*g܅O}02*2*k<8m-UՑ^9hY;Ju/Z##GD:-'V7 )tĭq `C{Hgk $k^܅PR.CL eHŋ%|Q b-aAi+ ćl:K),Iu(yAI#F$(x R'՛p@,N8u)(;hԗ[8K$6!>$!р eŔJ 8t͟}dM2e ӈnM bLM rIq=A2b1ȱ&`^d3T(7XfV^~M:IDIX\^Qrwh~-:TU"((eMlVsS2f9N꼇2-DU L4-fhvV)f6VI(#"(򉨙2YE\nl8눀*e^QQ^ͅOqQEi 9k>]m|ًb((fqyKb~v;#ly9}6sKM.Ak҄ $3y dGNh6"\r3,YSIkėűLy!1u[ UJ=Rb^4>!|J!15'~3VIl1Y91(ISkV-y+b`b5LB` e^F3$DPcum'6Fd#̐j"'_L'>aJ;)UOՓg֥xASנ:*1Y2l8Q)aAQ0X'#p%],0 IDATDL'Jx}lM9:hDDI)kh^LŔh5y^ 3,j827%ExfP#(ڬ֤֙֠ʨʨ/wfeRάܫ(w؂+.Lg3,ò,81JcCT >L1RM;1$`\WZ:`4(O0Ȥ bgQ!;[i,@/[4Н..=cMٙ!*_ebIY| ɅeY/۞>t;[Q!2Na㻺;j.6G@wEf9[,)XưƁ/1V KDy{Y"*< ɄK'HVr" k^ OhlZ|}Eoj 7$7̬3bwrIǞ@`)EM>8SM~_qjz^, K=, &G^+n+zҚSB4!s!@eiP&+=FRU\Q2Q@k*3P*"B2Q>8_lh`0* :-[A6ȭy5*2*2*5]e $4ս][\*@W%K&k$FBXb-AIym9s2jDH8m/cuL,ĕKJZZO A[BĠ+ieDC!끢:o=VIȱ~,SZx1A$%Cfp u3BM*SKX֘(qyPp)2~DgKrȗ\TtL5Jd\#2x&Jhw%,HZȏ7/)&ɵ2ጋyߡ1O @f.+snIV |C'b dDbMTOY)Ve%q3] )T:)jTJ)Z+.]&kbiutm|}U*2*2S5l+ɫny8)ڱchoS5:e[4"_1 rJ1Fn2ZGRq}#s|4!e' WYGMP%ڌoct T&$T 5F22TK )N*mrZg5 *2*20Ϲˆ9m;7rG̘ݟk(CDزmǖm;5vKM~vc`gm~WQbNko}j^']S97!{9>ϛ 9;jZVՠ=ڴ?נ 1wOj11>gi~WQA,m+߽cdA+D0Ab.T6DD7v~cml[Iu|)1W$ Y(1'"+؈vc'p`EV:Bt eq1'k݆μꝹ#]\$JNDz}_}bP^۝w?t^;ٞa': FdI12 {GRb}x.?~.iQtUP,u_ۋ|@aBM)٘+O25(ةv(_$$Pgj&2N#BHt;XRgJ; TBCũxG(/ΆvM$S|$a8 (%0lM=z֯*4RUUL` PTJ@UU@UH%*O&(kҎǫZNN\.h*w1J%Ī*IgR0Sn X ][ЪM cbR䔪|ݿљ;+(QQ Љ4vS[7zjգ{ދ8>}>׽3n{򯹱ҨH aoO6{*DX+M9卋]傶>xlָaOM0ve-Vv5{pҖm:`~D@pƐm{;'\xC{{YKVy9q=nOן<׺!,j3TPl! r8(^z}Mxō/on﹗Ʈ5KtjQTS"m(2\[/]1,c_t[i)6<ѿ/g~Qs ƴpI_W k[B;fO J!ާ6tt4tڑ%i~L$JrV2fp !"&ocPv;SX\CnAQn2{,pJg1L9Px&B(TrJ4V6B ٗ g o,G(AήkE-Žj@ m3LY"$XK א 25)נ˛vY$׌i veBTxМkmh\k*9-Tcb6iCfڇ~!w1SorM"PxR]dYL; \@WvLMoZv;2*2*۸˞:5t԰i'_x~qpn#oL9DO|e嚫ic+>ڴ~ǝ>t91C(g29VRҞ4;Mo<gxf՜{;5fm^Gu/wy?yӶtK漝=^@nxqx]d r(I QxcUSG}}gy%NvQçӽ^Iu`=2|//u&')Sq+{HZGlyY~nzȳeƢKGlۙ9 YĔ/ R"rZ'8G*v0gP !ݥK΢}JP2d$[YDL- }]VLy^xY|$&ՠFAf'$59@VrHs[ɨtEo˥h:Px(6^u\$32eY:QdN#uL܁HPP"BE5L닐-fceGNs{h1-u>ϕoc AP \m=ڭtQF׎ 9S]K5θm|^<M= 5o?eg(/s C,L$}A )>*)ۼ >kz=x Z`vf`5[wx(:<0 =ShB5ոIck '0MgY 3vvl>y=^}PoqKr"hd %A\+-aQ5Zi[5L'CSssLr=ɴ0F 0vY=#.Oh"0"2K$axeFP2D^\|'a25/NGD),k&G܅JY$&.'32L3aHq0JGQ#\%+em~;az`V@P9P_O0ؐ&RP A)4 9Zh2< Se/k F:bn84_w [ֺzg}._>ʨʨ X>yZ܇>nr@.Coԋazl.a. 5zܤyl/}`!եl<'vl}%zLW2`̰a@)S->Y&ui]~yCIL)mP5oeSL/cE<,p- zqO2Sup/]|llѺn7m Y\1~ Te[\!Hy ~ʢ['Or׭|}ӧc/Fo+ٰK[w@F?p{iDb"A\V @I& z3 !ޞ+>l1%'$H//ܰ=L)SJ{)=}L(QyQ΄ܓTlDUNJN~,S-bpP1Җ )ΝiR.SbT1\5֬֍Nwy sa#S#~9iM_w>(><0,K4߆\;Xӻ! bTPB@T6zA !&u榆mJF{7N;ŏA'g-d:ټΩ ҆fZRBN0B5}Z{7s1@"Lq@za^LZвmm:lضmLp1uч_O{mdIi~dM:.,zG/d ^yS[[޽oܺmGýu6,j֒.~~ }Q3.lY?=½># ;윸;J*в` }[nwLvǴjwLvǴn-[s/[05֕S>&9ro5h~"`q#^?N@gg졸f N8BSC\!EG96QOS0v:\#gJfF ׍h*Q~39*@째skTKl2*2*+yӅzyӨ-^_0|t̄~~Xorq[(~0ÈW-zFO;M|˺[pK#d_ޱ~;lg\GV8h?U8=Gv&V1rv/?dk?|i3\ zM]6uw_|nW,Oޛ_+lͼ S"l䟍p& 'J̯ yZX#1aބQ5o?~pgw |wڼ>^,@[>Rjk,z@$4FR$zVo|o|wQT2U\3˦=-?vq4o Sv_gQĖeD k9d| %.㒯;YpN,T?]`ӄ`54TJn*!dT~5󘄜KP" )S]O%FIa$Y/RHS/TixtGLZe;E1 FOTDUش^vQB%Dzal`#V3rU!^ywƒo9u^nn%"cBeKͲhdA"Z{V7,l&VD>q 'qG}UE2*2*#<[cҵƄL0btAeb׬{x  2fL9(/?Oq oiBH00mBEXk$<>d bY!b冐 FsԚ{f94߬3:8a>sO&m6ˆU()=9Y$⫭Z7')t4HDɡr_C{S!E6eDGP8@1G8Ő#=SM > rfB3 +(70QYb+ U /a/]0!}dZY"zמ~o}8 G)H3:(fz2 hbn*?1)!TYDYE#(0 R%+f4hRPX2eʀuHQHeQQQE1&ERѓ9*IB +W@ BtL{C" E1ML!塆T%Q(K=RHND~s=^ċ0BHNr8@Q&WfQ`hB0Sԍg^fr]0ݘsI$ϊhEPCaJ"L"LJŷ cjE3KE\0¥&BJZh'7^8%QEĀ9n%y`>*Q +K  J|WA Ӌg"'jn@H+ e(έL)"$R(;0~ IDAToQSȏ6T튜d(РUؑ5I zQeOJ2iӕs$*8b$^n@(g*I@WD9kQq70\z:!e~%B[,Gp+^eTFeT "b8>!2BAP lIU1C32$\. ( ' R3JGn.r3EGV_g(#d{GG$^ŒvU.&>W5TzH.$&Qhf&uPӟ~Y3 j1ذ?c%ηlIݰ) n֝؅;FQg;]8ik䡂(7EJ%&jг)XxhD1H42a-DeBRT@L\X9U-']M@1-)U2mbѦH\ۮ,! *jr7 MJ٪C6Չ5ANj`1$,֢F34Be:ʪJ*2*2*kB% ϫMϺ0"p' (> PgSZs,lDoZB/PWM "ZA0AqϪ'bTADHr`P5{y#*H,L{֤tpW(1q=! XlN=D9|m2 ke2N%MWؤBsVX$cZ$cSIã +5y"$w (l8g-%y>%r2PY:?$*pPoT)B"Mc;HK瓚-֌W 7Hڽ_֏ ެ]tSYE[c>T BeYDlۡKX$"1k0]"-sB\FZ.BSE%̹SI! ^,xO?yw]%XeTv9RLDѻEO[-ʛuZ"j ̅JxS2?*2lo3Tte>m,%uR w"Grίi費!H×!J3!]۟.I9ifS9tk\]/kUFe|GB3y<|P WMF2X("}-I#(D>D!88Gm|P $p"Z ɲ(D-ED%tC QV$x{f19}jtڞS '_ľ*Qkfwݐp8PN[@0YL r*ly՘"*yKA^o:DS!;i_ #1QM2x%qIm'3,(!NjNCaڋJv F.H5Z引viQ0f^^ eltI mmAe2xO&"ҚY T Gm~8ulBP@hZLT)()P K C'DDEh2hQk, _+5ܟ/oufy}}ceT˜/5c:d˜鹿~rg! 3j+B5Th],{ԳBf"X8D&浱f M\9t7oE [;1gg- ,d[>uLH]3lVl -ɂ Ac~?=7[\b}sKv&rpqc;WytT<:RdH#6eY`,$"tVQfs7͛X1rvܜ hs[DBaFEώwR9*o> ~ICޡ`;[;}~Js]\9v!{ݮb9wN[+FQ::bA!jUJ6ݘh扦WO咊GP A)RJ"JDT U U/]茉 KʄKv ӽ +Yq!O40)7Ȩ-Hj$+MStZYoH@0KiީXeTƿm0xn>@2yި.[B?Q B1hIcQY eBJ$8RA*rTak$ BcoKkqK5Y)<"ߡ"iDG55S `0n'`5ZMWBbM-) 2(L, DK!ba!0)$\CSݿ(ٽjME(qk_u<(lwC.A D^u ʤhM|Y9l'[ uJ  Q!FMeT.) ؄AfDJ 'RkdkÄ{4+zfY<$J Do l {`h(U='Ϛsx"AV,[|LZLa~nx@_Oٻc9"2")82F&-8*tCzt~6~o?G15:lla٬iwuGy~b1=O}gS0'h@{M뿺wּEhd=v?G&4@F]0o;wSrM8S* ӷ-`Qj.MЪ 2jkBʱ6I߯&(rfu( 4.M97k`0/E ΂!2SN&4r js;/G $> j梜tT(r2iӸh5"iŋf#FQY ?µk@H:CLTevQ֮\/xv=y:F/h%eUFe97}&~2N:k&Xвm{\"p,{ kTݤż;/3c-׬޸}o3AizJc}j'59cϑ}E%"ֽ'Jgg2u͹g = U7iڦЛ 8 TFrùw?nC~2kG?⸎s1rN$=t} H(F6gM3aXE>fR( ƞ P6Lu '(mȳv$R&C}zùߺb?nyS_\+Be&4~vΐ&Y=:lt9uQziV,[2Yrg~řny#s[&޴}w>s0,p@ xw:wl6xٓ!O>كΝ4nڦ_pB|{[XE1sDL =#PR0 EP+1@X,FUG혈*>D@Dy/OmZ g^Eo(ul'!fH )%b Q9 nbn'΄|-1$9>T2MJ?H$1?z1#sM0 c)E|<&uӁlTDE7)k$km7OӌЋZ* \ڏ뭡A2લdu%_ɣPD͎LfBfDMJ;ZwFb./< H+$ph_(C2*#t=逆]|js`ˆU 4}3߹w}ݻsӜ'*/–F/] -t0rS^D6ky嶫!81]٠q]t v7^1l=D{}wo|7nwXʴhۦ#10 fl}(hmӛDD[;']>Xvm{dE~??}y+r^~^+s\A𓧸Dx(p E(GՠX%-%5Ҟm-͸۬ V,J/[e.ڴk7r?vGeP r͢SFe-c|q- S{wvtn!bQw\W]/hx_>ٰj.u :uno};ͻybZeK +j[Zuۯ̞8J̫iGj#=ƊYv֍ {>xu!IILJJ?I NʨMV%{tˣ)6!"CQ9<78,V59#qƓTJ- SPXVyeǔw2idхW"9UpWH 'M6h!FWP4)xE eS t !qFyNW(tOE *u hֺKJL)]y'(8DӻfaKJQ# Ϋ/xIg v}{n۶ñm;@K}}xʭf;g~LڽIN;#;|'q }>g[Mfwݦ,wK!rx6ŧkƟ~t8g̚sæ\>];sqڌ6`#9 ~|>'WQ[\~캁W?m&ጕk&=(Ć{ycVt4wLC vwE > Ӻ[w;vӭo=pozX})D.9R.aB yw4;{/9|z8jڨ%=F_Ʌ>}hij;=;w8~}u_!<t9QR"`&11?0L?}Ӈnxvqzh_>Y_&q&_|^HlW7,|hܤ;PIbB!<*(\~v-,#!"w'jX ?n<”ŷ/?dݩsrV-ǟ^|C:,"Jhf$oHkeqФ U`ꓷ4 e_;<:YJ@]L<.`BE2ֲDI1?ylP׍8篟~z˝8jUKO|yݷǓ4,|tg湦}) ֕~513.!ȫ=yDl8 P\cOR {U)(,9:%F\%+dAG)fRn0(Eh&=?Q"4ˍyY|cơϰ?Ye=iI';][do~޼a',nnR<)mnX ޲4 k,FaPH)b(xYڔy5*V:m3 u8izo}b}h_gGo\}`٣rY]a[5.}KoȘ1a%?h `1jX3͏c%A!|xo3Ɂ'^+L48 V16iOڿK>am6זW?\on~Ԁ>}E@Rd CRGb".ke3w-vPwBߖaW{m)e=sض{ o~ХMTtӊ>'~azjvP̽g?y˳̟;}ȻpjGsL۽OC!GǗ&S,u`Y8]608;BmX5"B%Phw}3ESbYqI>refAv|btU3y+OB)EuRsNEϪ xUm)!Hcn$HL)+w!T傫34 0CB + @e@7sm*15#*P DJ*n,2=*2YYJR^*kJDH@:W/Wv^jbnWՀRbOwNiEQv UaPmVmVmFW;jv U;fw؄MRms sUqQ 63ܾ "nS.w"m?1lٶ ثAϻ䋧cmK],WYк펽^eybfi&6m8@kڵFm?̑k?Qw|֛lRmauI/y}}ٶxu_M񈺟o]ڤ} p 0b!^,2oB׸P(@tk+\|kkJ>q؅ͼs5m]+3خ륛:~ zpE-KXʲVq qx̊qR*q+3}u֙R+; /@ŮGz 7 zӢd.cSVԪvGŢY07.XwnnT;2^`793)Mo)Tm퓇]i0uǗ ;nV.NNԩXvY?ٱ]+DlvcκE&Z •ɼJV'P)@v%7jF xLBG!x؆})pK[J9X$k*#Iy,ܛE $%5On8WEXli) {J$@=)恗E,ZVH@,ɇŚD1F Q) jS 4Qf#%ZS9ǫ@DDe'uuYֆ\(? iOӼz>OTҤH{UX})4u~W%5hg8∽.\X5ڪھ6}twwjuސV-֭^_;|=N8t_4< uK5;v=4oά]g:4lKs7N~pIV_xyϮoѰlp9n<ڿOcן~ٴCtw^/9^NE?X(&m:oH.|& *.xԀ 'sAþu% >֧ mqE_~v6ܺ |lRĤ(Pg`֚v狗ܶ~y+..w7?|-Z"!`vO=}IZKv1grA{;k\/ID\0v bLa$otߥ} {h-|N1LˌF<-f-֭Z߿r;rNS2Xuw{:w ƽcAN6_^~,n*F:-~hQo8S7髰 6iנd?ӊza^jŕD*P`X(i\9l㣔`t!,*'cxƤG~tS mS ף?sI&P69sn&D܄xr@j ^Z.#HcG8MWDDo3oGGꮫҒ&7I2 'Ň b[c27.X6n\'+9_$jĈyZ.R~/pMs/" &EbڔADl~$.doL?_bXE]|?y%y=!h.ݱ@֮%j6 ͞64Š_Ol ؖ&c$ 3%SXY}O|( a >^,/h$v ܿt3\0*" l>n`3SIDE1kb@  xm0YGTI'*RxXi''0&ψ"FSl*7`#EL*9HY_C57d"5ʩ2qg\ELB(w@LbBŋ ~tX~7<_`r#Sy&'&|l\Sr8k~ {M,y"s#s4 ?eu#'m"Ϥ09!ڄfڒvYߐ"e&7C'd7N+)9J%G.3^#*R:/B8d6}3W܂$MJ&LH_$p6 ru: WbZJRE@(GcGh=ݟGxbdF0D!b lF06e) *T<DI=I8MC bY-ɗ:;8g`Yʳl0ŨJOb\&ҹy6rʺ%d0jL5t2$`9ʦQL llkLؘPjbID(ҹ!;]#-Ym!=ml]>ufY" :Wee]suDWLAHeBׂ6¿T0ß}}Xy kFk 7V[U{ǁ/k)OEB)&a@DB!=Ƙ`iV#79}O%Acb0p 1IХas:җ!L6cVfWaײtfiO?:ʠ|hǺo{\i"{P%w"٣pdS W$W`RV*Q%Q`@'TQY#.| њ*"0djP27BXAcXlF8+ #'JB'KD< )ZED1:sj\˞,}q(( !/rJ+Pġu9U*&?$u>FDe];+)wHy:y]ZЩr\SJe%T6bU9/^/I45B)2穷n*' zJYP,dǸiE* U7SNue{ȡQѧɤjڪ"Az% W~с8iR9f1+ 1ZC[ vT" pJQJsnYnq&d c6TBe]>bH7PtS q( A/q2-5ѫK* eF$l;{vbq<]6ࡀPQgÛ8i4Ȝf=wF(bB$%ZYQ<3'pyE.L^-33Q^O$GU\Wϡ"1aQbɱ: /"o.C+(ж&`X +6q~ ~D4ҝ7ٍ^ ^g#\#[VSr:ZΗ"Ku_g2I"s&)4U=\ H2J&@ک׌3JyIQ 2"d҆2K\lH(CQdW7JO1˒$THB1l?D6:|!S>CR;mUOsW7Im&G J2I9jc JiDD?zŇ$sb 0Qڈ Q($HDܔTfyCpKgb2PbRZ> +x(VH~7x5Oȭȕ"ZT̆7q&6 ERj#1%NM`f}ZA~AJ^P<-L\(:=I)j(F)$cup1B 0"B\DY+qVH]$$GD)8;&qѪ9F,@;xsd MVB)X|^TKzGUzrԔ0(Af!E>OL0) DP!fkmt-Ii,Q熖wY9w&,+eSyBF@zSMɁJJ)tȅjs [WjhyKץ`ǒ9QSmr:ȮHfKXx9o޸(6$Gl.^})AWN N3_]mjN@2Ipc$y Hac:8Ag;($@q ʃك )XnOV_Ǝ|(Ÿ@$r4H &z^&D|GN92( b )"ǂ7d$`ӈ׶Ya/a)kdqd{\,Ĭ,&\<`F…D Rjq@^\)thU|zA%T.|=j,!CJ*Ă}1:81 *W0mD"Av,m{3A\]NWQhU|`m~0<9'|j9Ã{wڽOcgY/] ڐƂ` ;S8Ib7HD9)LedIDJ\ <_ pɛR+EQZqI$,= d\MyO  !ȃq}z٦;jjw?{H-֮\ͽY GW^#Wt;iq+={ߢS2dZշ~x)'ۦUbG;B`̹*O}$JdF/Λ33r'8]ljǖtO8އMʅȔ[z:w2*J]!W :0ԼIt)cҿY؁A)[}k(D@!3%; d±_V1nz?VuKXoU=s7IzA=}WXپ>>fǖuVAVpX6,yUxqOB@ڃrހ<oLLTH\.)P'K7z !1d̊%yNt]Nc=Yb CLSK0%]eJW^cbşܗVDj)821)& *b>Lz;ˠspijʼ R*@seY=BH)Z@{j&K5٢dɋY $bČBm1wu[2 R *B\xY j+!I;+S;\V6қ9Ϳrs>+oJ؈y*"jv>ߘOkf.' s<hgkݐ9q`;eNJ-͹ nhESӤ3>8O>[i{ѽj~:a,4.?DUhwa.ݸ+\<8hy?pȸ3vuyg[~g]33&RХ;͛3H0 !SuhMy1enl>Hhcqv&*?zیuͪI`_)&-C(H,M,MtݦOoi}ιљwΝ6!$h1 yv[^pO XL¶H) >=HX[$C ѫf.X_q0Ipxr`um)4 N?S#n[ yl8%с1tω?c0 \)K! [&:K#ؼ=-HBqxbI^Dn*) MZBDLE#dj\ 1)QJ ^l;ɫh"2LZn MJ/`Y&_e3^Rl51mȳM 4iҦs|u·F> j[\U[U[3AOkWj/}cGy@q:n;nUق~qӴgjrysѼf@.͹yt6u5#f[1]kU^1Iήyh׽>5务/p\'v}ǭ?[n?g9'mT6Hgo{O正Á't\4Je[qfBV#be =9<] ~ 4/01cNǏH j$++QeY$/i&<΃9bBF_ 3R4pFVRxk$d5F鮈wUD͹O 9aoUW0 5~̭wxsvjDlg2|TLrg7T6ħDC!vyVF#S^)`qkQ(Lٜ<6a**4? U""؂OyڶY2g;t)IE\x*hf$#hUFxl ir9m`[MaNAxelU(UmVmu5"@E8l//|m-xů8֎{-jշ=z.2cK:ZhSVsǶV,g'gáj5_+>v.xН3V7MF[ǜv<[=̑ &b!gq"b Ǟe'ۧvNXD9zCY+h˭<@H6Q0 Z𶓚 P"c' ahBC(Mq_O.^?9~Лj9+>v=OpхM>=\9|| M)CXC: 7h<E kdtn9ZwP35;cu֔ UT2D(#|(%%'FJK ?PDgB RCs7Lz{ `dn09uSF6bCPYcXg3ĸ!6P +M15ӼOP(T@Ti.ǁѭ MFjTp$UP oTNᗄw3h VwFUjK\[&̒cJYqZۂK$@tԨJe!s]t¼W xNzX&AA"ynw>Yz8jڨ%=F>zrEtvlr7nvx-ړϲuذ긱ܡa)boK*ŝ'|i{Oyԩ}HuMf0(5Y L/$墨(puX2X02EgQYRg':ן5  aٝn4u^Ģ 1tAĚk(Ԑ~B4(Uwb~َ7p#BX 2]apMܷVO.XCdW+##!0oRmߥd|9bQrO%qK[3gk 2uؔ*.FT2#-Ãdi:J٩36f* QHFU/rJ(hc &S(7V/ @$eeMWE9FAoj^(pF}[bCh*iǾj82f%TAmR9J3&}`jgMjDDHY2S25j?24 ¨|Ma\bdFh+M 2 c P [!BNhxjӍ(q*(sX`L-4 3%+dzQL1 @RV"NEhca Ƌ-1!j.sm{ε'̺ICPj10Ӳ"L|q1Wy,DSΟ 嘓)S y}:FV'@M;-aBwaHMՕ!co/b hnM꺰}n>/ zߵT#D몐C*|4gwMbIA 6>,yn >.0(ÀPV y* NHQJ x3J)Ta344|ZxBW'l1PĠ#?+~8>vB&ҥTch)7^[(w??*h:<1WG}@%_w&ޱULݜV!8Yq e/96x`e~n&?kgM=%HQ9zU^UQFIi+WCҗUZs"Ԅ:/̔RJT̥*jIg e@P+$P!tD1ocs'T)ڪ_؈k۵Vlԙ#.7F݄۾F-wuxW^ YADVe驿ܮ"nY;;n5na`@&x?5:޸pb݁mSv˝z_0м93JVe\ [pU7=bV.0Gґ^zwg*f]qa/NLxIQQ„b s6LΫi=^O0sڮ{#gM"/`?Y+-_N:u#kߺfmz]4YSg}z5tS(*DHL h5#Ky#)dFT͘K*˂D2RHhRywˀef%PeLn T22 -&m "ЌɬcN>(.)k6o[뤇,MkNi~nh0䥒S/EڪڪK|%wnUboaH=~Ɓێ[/{or'#}elDD9|2 tlKs猜 \EY-I:tF?.8@'y*"J.sf!Џߟ -{ݰu% [~|'3:t^@*TfIIHLRd0rIhxbmW-y;0MO>qVe]o0z}_quglR:E,AHLq /Ŀ{~{]j뾸bƊFI@NLQ=ԯxm%(R. (HTWd٢C_BL\ږ`&: RgtY'G%!40Y͘' 1BªDpc#בDE:1F1ԉ}菲ڵVˊ0|};Ej` \h1(\ӷzCQoaB(8ILCAN1DTez#&K0]ӎɦ˻C0҅gΦ A2Žqo%&`ɟ6^Ub;W֌ k x";Xz `T~KDoϘ1c};e]-$r#G"Oʍ r{ [4aars ]5[pDyN/X9հĝMD  Æ+§W Wl$*ۈV9ݷoP7*ڬjoPKȧ(*Ly5JQYL5CH*n9sQ$&d$ K Ԥ{@9"bxBfǁTsE`Х=8"{irMPs~ {[K:xXPDx%|lM)¸sg~HjYl!"ID^-n=H`K ڐ,~!u,ľyv+N -c%N$,;.ѫUrؘR(ذ(}p/$z+42Ѳ qLSgiЙnS~I{%$EPO V$5ϥDAJbv,&)L'=1q0B.$a`L!\,4,[%MQ,449.PxYρD.h Ee+c1"˞k4C̼>c=LRM(HЈ%)q7ax'0rO?^!b"6~$dx;I0X(l f0!A_ qŷJ1f.…*ĐQ? uvPe҆DȜ{^RN7Nih^&3rW 8cUk $2YU)e8 ~U)y{,9& PVSgAfC0^{b\I뵈 *TH@,5zoDl]T[U[}-iJ'֚dI7WݕHL*CP(00 ^ۉ\"q͔;PP_JE0.9p²0P(/ `L+R(ypYV _4D̒bAGiA.c< "EdRo@CaZ"T|; %6$Z\ G셀%`4ÁXxtx4̞bX(Uڭ<R2ɂȑzsHk sٌjHY K1+Ì>^E%B<[#طEHJRxB`Ut{%_:& 6wq/Qɦ-X< !2'c(;D؝ڭT6LHرRH&R3C#jv3秨MjWL (aZY<(*54  ˜5xJ-`e:)}N?ڪ_(VhO!o*O| oAY2d\2-|Pt\ aT!@Tb$,kTTL@fPg$m4x F,ʹFEMHbsW,/>2#!B@ܑbqYYC{͂"ec"-yPE8[S~lH1H/8Ene{S$ebwd=0F#QoO-R*K˚4 RY)L'vNCDP-~RKږKeC%?0(0G@гFE 7&ԼZasqcHV mu; lsqwQmVm50䅅"3xs232UfڔQ*UP@apkEʂq,b(9V;LE aDktC33H&19afSeC{|aGD#HDKbW lj2ڛQ/qi@)d*AT. !$ #|$,  `q5&5l רZXK8v:$#2O8 EpB' :"c }+K#3I!} >GC cp鵺+|y1(%};, bܯ.PMq!?Fim)m/4j+gRf5*TF]v,X)҆}f<$,À*=QFfݨ )҆ d3JjWmVmà.}xFθ}Tj:t펲1Y42_3cҺ IǷ}i  bCMP|T=s;;wD X(G201{ 0r.;tdA,0(9ADn߄S}{Rrصf"wc!鉍KD%FRԪ֯LCf¼vRn4 P}s%0p'S:#i&VU3"(CAb{M&‚'lK𵉉Y݁rED={Loh4(,Ub*:!q +"4j'FӋ}t { }!#+AɰENL3w IDAT)1^Qfy1(&Ph{U,`0`5nYmVm`h $@LxxP_e?dU<T3@Eb&ϑ a<)07E$  1< թQ %Fd|Ɗ4Aal&9) d9 HI/^oJXdu*Obt=El)" EG(M[VƢL1.Ae"H!xd|Ē ^"WMQ+Z**w8"•$)AЫH&f@0B1Jɔȵ,\MB Fyާ/(I.y^M;1:Tcy= tn^*ia9F(5I7 u,ɝEbe󔣼M 2jh`Uls)#Q5P %V\2(?HC y^PH)tTfTBy @52ѭU5 ZmVmMkTSgu=`7ov?nm~gu4^3֡K7N]۴8V ~Y};p[\_|`/f?Q}뇇r?mZe+}rǓ+!&gfD]6q H(vyѝgVjf ԲF7ା/fAx[ҥpއMʅ[_2D.h EJuT=CyÐ 5X2t I-$[0Jd4A"{<1}nϧ@D" T)9##A.?5wccvlYۡs7q?Dy 7h)Kdl21\L`g 5/xR7p!J ¯ijX02F>%E/Bď+ τfB)P)={(੠񦄓VC$%&.b]&&52F `@1hPܺbKT*E1`YL@~.CVA2(P#!hmHE&Ed".V9.+*+h̰P+sI͘h" U(1C PsDr6JKWWU[q7~w!N>Q'l߹s?> ;tޡKwo'nz]h{g;nG}g ^`c !_ydpvɃs}z/)!d&l_K@d& kO Y.ݏ9y{'m|=# aMrw w#Cn8c;<{{3-s|G!둎}@-ԽXa$وa(;Qzϧ& Fj=;<@0⋩iI_kCHXn(#VE"eX&[΋]a .8xC @{|fNrO8NV+_ɏ}<5k2*}ȱ @`_%_gkV'`v"e'( ڻ%GIw@[)(#T@sn{?mH bOG7X!B8]Y\>Qߜ]kGԾFcqvݘi$)gg̮^3w]5|t:{fb7=8NxW1qY ї͚>I}E})Cod'bD) 9h2#9gǟnUg ~yi ?9~N;]͝]wUMsW|&z䟖ـFqA[џ+@eq=ע|7st:"6K|;m̼s؇~m䀁;.ߝ7QП?:wP?t/x15 D$/ d t_Ez\/ɑ';1l:s+(#KݵI6 8 rcB8h"OX8FNpKqmy,R=0H(9feYfK)StCRRKyD b. 3hK7Ikn @ *Z*DZY"ʁ0EI+ e'q2@٭x2Wy {QiȃJ*jB`=i$GDܝ~yNcʝo/8ڧerӮ;Vg"[xUі[; w[S Ba˂! 8EDd (d,ytדm[wat͚=Y4z`<~бv>\h'ߵ8rʐ|`omD-\e>^öa*AtJ<,2 Lb/s"`ad∅Ani9o}ǐS?X5F7xŷ/R5[65$3 6BIP\jCT 1,Y6ŏ8~`^ۗRc1=_vu«pa;\E=2n⹝o_.J*!d4ypojM=&g|AG8Ǩ}M#1Λfwo}pev;iW/=beL\(H:+, @VDW,\U_h4M*@lB'TgfzI~r7 b"#B JD)ޮ\rV܅rc/՜Ѩjj9{\;oZߺ?]e:eR=o뚋VH Sz45+A}W-#<; `-?Yo kd4Cˣ9v7 >wϟ}^⨢<(R<L]6uXǝx.kԣܳ^% ŀg'0w>h 7m7>/Os@6V7,~s&WEA*n* )OΣ2=B_ ';uz"zZ ?Z~כsɒGo2nY/EK[5 ּ"Wv6z4cV>Sͮ+6_5h'>`u٨^:~殱ͼѷ4tb+]Ђ.P{qy}ZռJVu{yfQXhGwF,rn+2DdH|A3Bx>gݳ 9~"̙ݡK>[{sX $lByD!&D'|.usMg-w%DnھkjZӸ}}Y^[]yy<% v!{*Ϛ ipÝ'zF 8y6Ο%Lb)WKYzGC*!-Hu]9 ++y0fA|!Sbu]]uҮChױ /-Jل籛MCl*wm#Z RѠ|1zB1G~+jSj =` = ^$T BԵ|x8dDU -H>:I$u~O061[S u菜+zL[q/xCS xݡPLϰV7O pΆ$bUP g)); =մH@O,Ukhc^1;M!뚱V63 ;<Ȫ+$ ]SLj$H0#QAB"J$2"!! $!P)CBU$@NTcu(5!d9~ITAArrY[TU Iɞ '%'ۄA (#rsYH"q0w uT^*\-_|}!!x捫lZ_>VxK{nu5()\h߱FC.zjAO}Vn۴OKpӔa\8·TU]0gtN![/5uGT]9sUٻYUooD̉8,&BfIϽtdW |}m/);p3o˟{MZx䋫2%u=A1(%8JU9HR!xo7ZK̫ fx&-~l?lC~53^=o4k=tuj4ys#.> u;c- RPlD`WxNN WOn5ɷߪɶOּ"Md0xU], ]srHDSD}C]GR|U M >Lp\(9=l͘H; d^t SH5($g6a*6't 9gAQu7^ܛDE3z{ZyW&-krj)\ɱ%`r0esȔܱ@A@ ! 'BGk (:d&,Bh9tGT$͔s_,ncSO 'KjMr/ܲaZ~m9+?t ^8۶m+VXu (V\(*AGTDS+P~UW*f͚ebIL\Swd|(,#- 0R}+L"iBj\< "  ( x68 z(!->j_Z}h!w|W=嵩D-]]ǮO.L0"{9~ۻ~+ sɖ6cmMbRiEXҊ!TaEbJx8+ֳv,?Xq'AQDi/TI"R)aK vv\77&IYnxG%ųĽ,ӂnb#ֶ ?!eK믿svssȭOEz~ޟq\g "E>'OX󖟏C gӔ PKMt'"%&O꒥QUajPa2lx(A'V̦2FbPbF }cѱ)Rpi%<`v)֎BjGA$k5{j#B!o̝JH^,&F¥b^tVc$+)Př_ʈB%3Ph57ظ#ja\?zh: #搤@K j Taʨ)S uRB'R|5K7hH{].Wa`ԚP/_|\AwZYˆV:"HK$XJz iK҄s;n%oKw=籇|F OaTƇ0&1B (xS]CL@U Kg %^ =XcM~%C|%mA] Sx ɷǝxl9DI'5x}fMccD*e ec֕ >"/ AO dÖ4;B'=hBpHQx8LT!Rl %J R0S d%-bf v)LɠSbRbkgRK_5ݣdZ RJ#q\Ú%Bc#ZKƉbWE@.:W*j4AVP$J]5ת` })00,4H<27"0/[z|5TKKe҆Lm zk ׏  Uf kE0B-jB *,s,<^u 0`{bACA~.kIX)FyRm>aRq0 G,ܔX{3LclhfR @Deӈ3 !д%7CXTM؋(;6)*`CݩZۤҥA$7țo=u"U Jz 6 Dz`ђWif<$J L4.+%˅DjÉ mhJ;hyŅbK:`%L+$@w6S&/kKK @*J^BnJ @G[jw ThFT*,]M$ut$H$+H&@P/ew@?M~02'2' @j˱}y+AUW"P,2pCåYά \[:MUb ʙJY[hn 1FVq} x2QDR+(Fr6Y 2s=AxM[T( *`OtK\9ȍ>a(/Agc dt(ʑf 81.,L#CS #]ށWsE,Zx0wb/Q-[S0T bA.@yKv.QjiGA8츟I cBf肝tU+T W2cIE>Rф#Nk(KDP hl댘 3YhnHnxAhIgi$cR  @$@Jz,$Ȝd2)1JXT+Q7ErHqJR@ RbN9$H9R2GC! 2@s' MM[rQ._o{{Sc"[>w<˟[YN GFg>VŲh{Otdt&[*K"Sز9S`?> C?LDj̓gt/U!rZxtVjzE Th,]:ER->,ԨLƣebŔS1 xqp.5`hwYT#1u\ӤHv*Y~fXHy|`L֫DeyBfj!$HB7k*  DDuQy$[B pDȈL"0gh}e(*d&?$TU/\KoK)4$T`ȶ|u `FLݮ@%ϖc22;r"_7xY+sU (1a35vź-Utf 8×9׉}Ǯ$dgj;hƬ\u}}iüs1l&U{t>aS~5hV o\1r+o/wݰ=5 &(0>NLJ7oQkrqϩۏc7 i̪ [w߷müs}.n4. {bT|Ǜ(n1 a*ISY935/(9FDlcLjLL!_It佉!γFyn/{ʭ{_y>mLGjG/~àƬڰ>m>^1'&T*"] ZrSSZ(F,b}՛Y‚X ;ڇh »!^T [|J)Vw"FC CYƗB)\xK#B1 ۟JNcF@BR|.8E7a B!Y##p2k@£T!zÄp?zV;p0Dщ0,RyW}6֜ Mqi JTj^ &`s:`>pCc´k$2(HSX˵t> Ft /l?'} Ӌ;kNW)٣щw!#S_nYڱWG˽(_K0m+6їVnܠI݇Z6;1m f;4x:$pDǮtWj2-8tXwԟ7xmf=FLk7Ekݫbo>РzL[q/KPkhqߞED}ɴ{W-L%<蓭vky΂~58+^dVa}ܢ(.2c GF7p[b cy񷴟{%S1e>#'u˞>I#&4\{.{ YnxͿ?\. yߜ;2Ggz[^A@C1 ~ȺN玿nrgnްtkk VP FBIVLOð ?xh$% SDfIƓ\J4t%!`B$N N%`MBiC9 b tEGZ9G\L䁆y"߇ L̓#tRskP|pbi&"i020PdMFaS (71_nZGٱЫ06Tc! Я딕+Ra(\ *"BB XyPTXCol)?$ 4!{]J/w0hZQ񅂓:pj\kE鵶(ߘc/vjX*_uAO[o~o>y~}go~Vܶ&Mݫ!KIѦ~vnF]nhԼqFǥu=^a&0-Y+-7˹g@J?țTnphb"xɕl&atO9,@T~o|oѫ{&7p \1>=Cg5U6\6D$=G6?pfz=>\c?|X`̯+zA'׭ѵ vos|3\c|Nca: tQҥ1N$ix-X"V#˜Fs_rd1@x/Fec8ɏ!La%m6 F! dHe肜BM-%܎)C9EHLɺA2'pYEDl"w|J[Ӆ*#F;CF*m@X=RqT PӰV~(r#2%UY^d Q2K en$Rc89D!&mV Vd<_KW%Ud¸Z}~ oEݣ. k?_Ɵkg]'Oh^nK{t1t sh 7le#6v=yy;ogO ^Zr?}-0>wJM[sI&;{52F귖իsboh+G =fqn+o\|քQ}Ng[哷!?~yznsol(DӋ:0UV: x· O)$ͭVI[nV}}nY7讀 zh_5U08Z,mK`ϻEƾQ^,W\JWo䭿xf̖ IDATU 8ȂݽB&.x}6z,eJ/5FTq)}Z3zے?SEPC{R.(sQa=(xU)&vx4 Cܞ\M)5fF#Ew"іQS߁|ZbqRda8p1NΎxNGGLW#$dY*K_ K=RTlV'&aB^<'l) ^kԃUS "iy%0}!It,D,Ƨ6V  D" u$pdt[!Aخ$Gi/9|yi熇/ 9LV[bZE|{濮ۅxPԂo71YU_>ڧT~k.HE&͟776Ow \r7_:6+l@^g1p ԃw.=}i:uF#E2ż C1jvE@~ jxgKƕnzm=OY_cZБ:zwU+ZMDࢀG* qÀ,m1xVV˽ߴԃ=?f]*=u[vS!+RPHRW1) T\t>tJ? A+j@S}?Hu˅4 ;3`[㉎pj"AgFre/+1Xz|^ -rVP1K(T!Vg,AN8{)h:2xtT)E)Y㊞#tkDw2S)h ZJa*ur'.{ q5+̔0q**Id#f($%@9R e2A"#ZPJPA4cZ$:0@%d}ant!*%1I( W*_|}.m`̦$''-8K~r` Zˮ9IZ~/.12+_zBL.#Ϝuɧն'߼lgGSK}OqWgo7iP^;kߞ;uҮSvXEH=TZ==UOy͋Ev P+ML1Ђ%8RAГ̗V]4֍ߥe zvw|xϮg 2"Xx [~Bƕ8|*P*u|l$ܟS]t1"+z{?&Z//Y0w4Ic?q3+ bUze8=wWLZ;'PJF_' 1/Wn1D[THž?}[+4(Wu@OWɈ8a &km<*+ $H E.ꠉ2ae‰^:$6mMWTίi[jiwO{DOAwz-~""CKz*CO  zaPfI\jGbB,"a|%p2 5DS.QT([$ 5RH$@ Zz:55yMN5B&@(r\Bd֓FD1Cj IkǠ˧'%4C0z’1-(r|WEPaEs7ڲi|q3_˧wk})6a%1?uJP.zjAO}Vnd͟^|z/S=w;SUvze]2oO?wkm\џ~7YS.wkf\ߢ'?s%7qMQ 0a2 zeDzsFu^#`SZdW<=DpճsU�[>G?ϼCQ ԋJ?B!6ǘo܍7+MG:Fɖ]7F> ᳿Wb?eݳ!+naRmNw~M+6e#mXc2)KEHƩg>EOO+t_%F?y71m+w`Tp)fj5.y96"8pK kUt/=dwܚG(1!JO3x$`("aua8p4HR4"Y\Q-"EWz[& ?# Ԙ ?„nf==XfF"$SXhC?[̿cRu*o? XvqQ VH)@D@ i>⡆H$IRo&e ç R^BH-J/p]g2Q9/xv˷5)E:6i`yQo2.E$% 9۶m+V([~|_fͲGq{+,XɃ(w95zuC^t,)%a(_`Shcڴ4c9^J|/}%d /L.V57)O2¨|DH1hH8D0iHE JBɽ0o?cZqMs:n\p_wuLSD,Ka(u3 ?AwE-ZmBEO.^ LiMD1xp@vIq5dWn?Rwd,%J?_*ү!D'NeF7(#>݋ _Od~"xw aeRJD-_a18P(M#Pd4dtnz%RJ")}L!/10# $rjA5 H5`~ ID9#oũY|aO|c=rZi{>8_.^.Wfg(&(G^'Mj"rİ'vE2AȪP'C9 դ&ȆѰ"i>{?yYn8b ?ymx0>\S90B S.yV7kt(E6 !mA;ZS8>PT)(N/Qut)pXI`㕀0e' }]mM3H]@P]7m3’RBFATRNlp3Az ez(NMRk+ :͎ۘt Jo"` .-=oݝ)' A&H !#H9P5`"njDF*0 s$ M$W*R G pyIiP PEfJDX뽜dk&K r*4֭DOA˅;is7 }, BnbuQ؉mމ7ٱ[}9#cZ)_h>eUw4! E=4M|<='9Eq BβF%+dA3% 0N~b]].uLv~{@?e OA!DNr" ť&ϡ~D7w HE@@_Dx9vw±" 6&YA,He.Ĵ<;&VBI_l4GpǠ;EcKv Q/I)}Jvx:FxFZy y8mWg`x#7*]&_ɓz'5\!S%e"V=> @0(s 5+Y1Gs@I蹄Jg$rdHHRwq^} r?ٽ!N_|mމ 6hOcujg5x8˱U ܴ0xTQ1(Ka66~VC%&ȉ"Ŝ`)4K`G-!h B )0Gq$f" c!*fG Ec`stz!Q >d;Ji!`*$ 6 f ByيàE"a/,/eB/B/LEa;+W~֎:1[ɐR|vy xÝn,=!oJv``lfG3!'@r1BTc>"L+?~Ɔ݅*(ܾ17̗0.ZHqk]f۳]mc|zU<2 -_uf8rCVKV]X /߄K@(7+! 4S*߄#=}[:.fN\! e"(fu b DM)@Sh)VCzYxΐg+̝B.wi`TEnʒ AF7N9Z~֌+{lTyD.CJIk+Ȧ4 $CM Q|ˇэ4Ȇ1M "tԌ[ t'A],Iۺ1Z!E)Q .9=XncG 2"Z\zN&MFڏ1=z=dC6BAh @ıE@G%EVRtHjOV*T)C`PP@B D)kPB 4PqJK]kp*U̠(aZA̼sN|YG  >/"5>,p%Cp_\ w~~Xܞ/4JYƟkh`}A>s;遷7/DJixoи2ڠN0᱆9crw5'BBjN2CQd&RXzDXIB '@٘X\bU!"RǷCR)f",lW3sy=x{#bɣmQ u8"dDEs+e#FMѶ+@ߞfG%ǰqHjppA ܕ<`  "X3LERѧsL5>ضŮU7yOMթTWkש0ԯλU@e>OS}MϿ{+MAw;Nb^Y][Cmi'[l[n{dmMIN~A|W8lK,~N>jV7Xܜ=WZ1t/| +{\n05%0?t.42҅# u:vu7kzlTzhE(i-@Jԧ0p)Gr+?;kA'Bg,>76m#l? ?%_ݪ[!hlӷo?8DGvCaխ~b.ؽ4>Cl|Pav.em޴k&K0OL,/,D?9Q%d+z%mD/ 098дy5#edm ?i(X~)z‘#'&w鯙 opSl32.=Ha M:P 41Q[X74ˀձ=Mb[A=:8)4{?}gMk>^G:4H"HkcbfNlpƬ\n;8tǜv'IbC@-~831z乯f~p|| IDATɸ놽{}ՍGm;uWtW-xENV!t@mXĊ9 yѧ4%"kx l6LDD ̘@%VG &SZpظ3qȁ?du=5^ۮSA3'!g^ c 0ti[CV#br"]fxVDw#9!̡OF 4/RBO#|"| Z ! rIg,JqQ:6Y3K}4XbԀm۶bŊW&!8_UU5k=Us <ȍ8v]}~p\>'t=h[?^]Sf,]<]n t|ua7Y'vi/5= /,Zpb׮smlf }h5eSyiɂ#:vKK^7>񡿙AٮgG^5~׻*|!/?ޥKCh ]m5l;!z0\)@SËTH-B Q#>Xy{j}%Ig!'=Z,ESC8*ڤ EMʫ)G% Q+Q)YD0GCvd{`W=F{K[^{MUJ "!&X6̲ )ܤZ*DB9" tRAW![TJ(%Px3{Wd"'#qʑy^@"b#T,"kAI:F~)|ڮ 5}=/}m{T:-[yůMx6W5iվU˦'\3ͣV6h/OsF0R:u ij2-0tˆXi zLl61b"DQBܵ]{ qf\Y4I@|cڲ8r£/\I݇Z6T;lhsD {6o|Ch'I)V5=趄ouD)ud^OX:Bt cy~A&=GL6紐3؅DeQ)#9?=EWD)bQD'֢)2r{Dplom4)4ۧZQ>>g8r#KW`Ort@kKf"ziB*dFMn|{wVaѓn77xGm֡ol__+y YYάCC6s5o|Q6=cꞗmq=ZMa7prͫr^Y^Mo':Ӳw౫Z1e@SW8֛8,"=Vs~ƫmˁh󧌸f Qn\=/9?mǁ=)*re! 9hIQ0_ΥLF5"9-YUs_ 2ݟЊM0Ch|qWV#~ ;-[$u G)^ȱEӤx'^eJ6 Ɵ?s=(W]zgNln{ʪmn~u>}|oiP&NEDwdFG5WμruQu'2;NPߨltT%Gu0|7GvaD@ġxqHv{<6R6$K~EMMD$(!Zl>H (YkCm?Xy$!Ժ" r9$$$  "J E DHDB`)A=H(+LL(3m!  ɜIR!h*_|} (4^:cqKomXh֤9 ~ ȕY[#{?_KqY.mUڧqPN];t>ܶbU{Gx~ozgJ͔Qcζ:y/W8Lܓ@_6OfUղu=SG܈Z@An>xm.|q,5>86jf,~Ooݐ (VT4qyd76UaQJ9W'>[~!qum TԂ&I>0.Z o^m`ۓoht Y|)8_t{R[6\~+ LեG"Ԓq|6'q;ՏUgTEݬߔk7ξ<@BkAOn ,:t ΢+?œ !7F 8FK χ~mLX˴<#Ao$>G>v~,<& >1ЃLѰimrq(.}6T#:@B r]D$9'ZI 'DHJ\=K1KP@jj(DQ (*! P! (@T)Gʑ+@V!sAR 2DAYBQQk6n o 朙ts(JL뷲⎙7  *חNU۟kے7PL]uxb6X/o%G{ǧȗ| ړø;}TEҟ߱WeJ M]VخK vӞCQ{־?p>Ф[U|{?n+ā*77iXOѡHDo=4ݏp?oqEW>dsNޖkc,5!8=qX\,ٺU@Ƈ3o9e]&sI7ٿ5YwN֭٫c QtaHZ+e-d0E ji8 hQ8 p?Dzh?mʆߩ&OӔ^zR˺E@2h{˦^ 'ݧvڳ9aamP/sE[z˄Wlr@k$lnxFW?z ~fC.pggw?o68-sſІ*}ԃwoxɗ,8CsO}mT@̐GA .=}DRq&-khYK F-4ŠcLHX:쌗Ɋt>J0S~, \ƎW SJɇ${خ(({L`f{{Wweؤ?8uvoc$UTo8{ɛMCl!6i_ ZǙ0c#߲Qeƭ{^0x1?V4kWmzI<7N=u-m;zٗ,!?žGaj69o4k!4mϟ}`.~| &/8Q?:@?ڣ !Nui h[vv~XI>(up>aM*? b(? ,Fr~sD/,2F?UzZ0_G-I)xtuK4ݭ86iPeYFc?^d.YcH?vOl ]~QOx *tiO~#/ Wm{5k/?=YPDKGt4oM2I(VY(* 7]Ywc8$HKXǻ]GuUZ$d]]]}{بف\~7+7@/=cqyL+ FOM~a ^W9|Ѐ3[4ܣ~ `>|_6[iY)j+~}ލb㽳qr MD87ؚt=$ [ E_2j;J,/!Txb9Z1ZU g8ˈ\[LFȺśQDږsEMsܢsmcnTVBE3\y QZ #hGFI d0!I]7ÕTť.2l8f-ٺ { b,VI= lP`PI<""P` %@A $S)@$J pKU,*)`5`5`A$BTl#Y   &HD Jd~:OC~7JW/kF2bWps3WdDy>ڡ[9>;t^2)A?ݍy+I3y+(7Yj&tg'߳y[7OYz ?yڿ=5}L/Yڴ;!p7߯נq^6ygs=. ߏyK/Ϻߪv.ح6m|w^]г 6b8a']frI'}MRd1.~aRkz|Y5t@^z}q]P7OuƛVxk'&Y{Ӵ6ٲau{g]U/bΐOQ"yz򺥘| ~T)tF~wl;i4@Vm;(>}x06O0яh84)lZ;zAW"4?}n7Z'Nq' 1c 3q\|brx=RYVZch s _1t^u[Q yMb^vFtZċuߥj8dOj6Bf8_FmV3z8 B\DY)rA5$3\toDI؇01/85u%:U_ ;8+Y%qz3V'}|烬=+vJN UܣмVEe-P=]X+flZwa ߢY虲/,;,ˋ#xYr h9(?E_#;"waIޙnmluFƵp.~gwFaytߋ̰t7yntBSrK1NhTcQAd`,"P 0KJaJ%;`>$ *(8F;"WCEP̃TU0b> ٕw_~ܟA ݭhYUR!:ƊTPB4Kʫ \ `>\\"r?Rq]ryAT'}#grCX^$b*yRCc1D3Ȃ(.wVUtx2cEks9.,Z)aջ=)ybZ-1QBpțfxZp xdǼfoHLY b0IRs:$^:Hdr{ȨP_˜"#n6ObإӐ3O;5֧?~7&G.8;]ḡi-DrDJ s/Aؚu摙]c8n!GY,45Ų4~pnWG|GʁDI砫 'Zʟ0^0'[`lPʱ)sVrQh뢃w׊K9F0K2fI1rp5}b^@Ҩ:wȈͬ({EI!kĹp sݍ<~6D°Ѻ\ ;&QF86+hƬS=DTw~WIU@0%I(PI dB~sȓƠj@ǰЗ5:a"r'lN9ܧV6)l5[qf;QhI=VtqЅ[aM`h5[5d(!:hD! CgS IDATDas 03i1ಏ=!R)'(LjGi<"AW-| @yӕxw'"Yf#ϛ LSGN4p|(I0tS5βܛikod2aqfmvS0$wZD| O9*aPKo[}!eNDIBD r!)¼"8Yev$ITK+\ Rd6(B&SD:IJJT*,@HA-~:vR$P%R%@%dޞ`ECH$6TIDAX?e;L)3bPOQ~aԔbP桋(nw,OU;eH0xa;v5ZM+GSeύǪ)t-з$Xt)2Bu†VӐve`y-#U5-^;ke%j:wU1u3RD^!g-jvb9*,;cIلeCPœnf^2t Fl ḘMu>[wjs<=8њupJܯ=6. E"LGL-nRF9xo?D28D8H%I֎!Li!u}JDH!"rAh.,"I/ H پTi$ DR'RPZ9)ZHfF:d7*^n6Djgef>6͊ȨnIY&(/CiʼyQW9#>u q*hgr kt9Zaމo]kGa7+~(ɠtVwT'|nrrI]g 9fXPQ2 ̮%BNB2 EGn{uOnpV$ʊxA rRCxJqv(RÑϗ0!6"K:fQcBo"Fa RN0>\"(d:&2`/Io&68"X"ޢ"'M\bb͗&*ZLMPdYц>,\žC'[a*{yL|ĿԵQxkQA 1J9~WA['770z f08BVJX%L;I{9uhTdZVd;:8+Gs݆:p౮)5SVTKLvS%iA@$Ɉh%W &ILк4 [ h$Lz%Ѥ2!O(5`?QcDMJ5WTY"v"]?9۴V)_Gw7_uW_{㊸ڝ`A P&fꍝZ4lն8%dFN,]r-Hsz~{]yr"F|`t7rsa5E!H"?+BahFKf[IM9!w>2e\#}] b>-V*1X*qSRg񄔏sGb\[oᚣ3w{4ve2_ ss{TGm?g@ˆLQ~k9Ş,U_zKs/y^gxP^H?lQ= f΂/#u ޛ֭LQH}T͢G SҊDX }2j<7qQj5Q b^ "B)e4fݫjnɐSű[ܔ[L9|t Lt܇1bȓY\^:Y}_? E}Vk렺P!D9_Ay ;)7p!BDMZɇmKA0Hh47uD 310`niʇCq5/=ƚWֈ VF;ַxPd -v|X +|"\m{^s(7Wi~;\s~tKrt' 5ԅ;vqj Kg6oApz> aL X2#]aq܎SϼPpx8;8.f]MpXڡ @ԵK?9R||-i{a {w2M`> \Kb6,"C6dl062y-f&Zlpي"ue@VZ"9T?[((N%7araidjaګW<pRȵ[BRy<=ëz3}9NغEU[ 2}ֺ9PtkoKRfW<*QAI(! A$AT(B R4_+(R d"@ - R݀+?$P& V)#(1P)BP$DHHH*Xn67RAn궺m7ku˳/`ONTɞvPE3*rt7}zپ]_wwצyMcO׈MT=L{8qzQ2RB0[^}o:? }yAjS65gLXפ+~7@'4?o/<ēprՏqw0RciIUU)bED5`(%JA1+JE"vJ3R"QQ8 (%HB@S- 4@0џ$ uAJ)A)AH @TH!BJ@z$J;)L%)Y& @)dL& d5R5@BJ$UlRőY#N1u uǪN]08%SI]_}eq۶{#nnN)ݼp_ON|̛W?$2jMU,]E/E .Zho;%_$z'M dK_Xk;gvy~{5,lߟgxӣ:ck} .^p-QT5bμ?[QJϽƦG]mX>'~ns* 7mT_m\^'xM|UuZW];IP%*!WTjbdZ{B:Ӯr 0n З-y筿[c{pԙ ?=в/w9<'^{ўg=?͠8ېGhSFhQa7Q7׎K 5.[21 E &.EoJ^cْ.0-xzHc9sl?r%2 6,Y3jт^|t߻\o,{SGt ](+BP'EO=2"pħاr ('J(rZE.qr'kp:M˾h=p ,a12qorZLoOv$'>T[sǒ}Gx4d_'P$%ICq"7$r+QH\=--jNwMoyRv!I7e8Z3лhy?v>}(LI@ T̥$P')B@$X Ʉd H$)HJRƠ{7H\P*|󾛓IԆ>\[6ZoYhWGA0[R@z'v]'/n%SR BxOY\r"v#= N1% 伈Hf[Lun,1WC6jVK<EV^ ]CBӠ6;a.vs(sͰA" <+<]TJc9!$ :@if3JM8E8ǹ`@R bєm$F{*j<5YmY`M}"5̘4P<9ee;2+AR@LpYy2$DBH5R\fP'B԰Ѓ ã!r>Rtc.X%3jw8L-rX+X֡~Ip4;R"Mk?{@6M-XW&BvS b4-Һ*@˖\2Zrc^9&Z6\fǿt˭upBY4ɽ? H_ɜ;Z0hKlZ^:l -'.YrxfХݲy䎢G^| 8\`J|8$7b qJTmZo*F\.ocU*S{= g~mN?yM5|kzLoG+8"cKhxB #eƩ0Ϲ Z6]n?l֞(n`(`+$$ʔ3 IDAT͒oÀQ{]9x2dMUj(FS(Czh±*bx AC J*GoZN^tޝ]E/&+]fPf%fWL+" h1!jJ8Gy:6ajby=,DS7D7Iaƍ$ lmFRV iCWdhWK@ J RUJ &HDx$tAH$ID@J07M )m$ @)B $FHHEz#fGekԲ$9eTrgۊ ~g\G)K A/ݭ F-smO'Xz4[O>Y#بA-+^5vO@H7?ܾcn8d*!ZqgWCzF̈́ZioME >+٢@8A'14"iggMZx8UXx 4YMzm̺dj>4nu>HwY=GnF!`Mߞ۞к j0vTgƾwϮ/}A@f&nj>$E"$OSfCiQcă1=@?v?2I{HǾXXhiЀ߳r0LVTlң6v|] *+8"_3rRZЪMVmګЪM{=ɰt¥Kt~Q+_0ay`SW/oN15v˓ɄH0`Es |̨Y9E.Djfmo،6G-1t1tvL9g C*7MĎ'4>@dz) ޱG}5#s--""T, FK ߸ј;Z VTS9fu61s#Z[Fͫdyp3t&+OUE ]>$$TBL   ($!L++*%TH%6M`M$L(31P -U#Ҧ @@LATP!BLВW.2G@BTD BTJnc 2fZ/&'QJ5SZa nm?߻;lQ:q獰v۷;c!:m}/@}ߺq͇o-n@ZW A֮ͫxz_(]eȨH`o~.5qރl۴%s{@煁7Xk_5ߦ!3pan݇~i5_gPSl"2+7N@Ȏ;.m~hԄ{a5ٶq;K2OQ~czi-o\ "p#r" Oɫlò<(m#y_$ QeN>>{#IamNy&ɖ?s;I>L<̓Nz~>o{7X9V{p >ޥan0^S8gBUwj&!KqvierQ3xܽv\cYdJ%o6k~G.`~Ȍc%ȍW0N_p`CMjwWm-4QbFHn'h)OlL$̚~I"|@ՁY,c!Ql~ 4@mkCQ`+Ndt&B_KئL l@ko -ҐDDzZMuVN0.r^v`W-Nw8QgQDӨv豢hg%fyycv pܠF=_rON ^ئmk_۴0_.5i٬Ii[N5;-WoMo=O`ܢv`!&n|Wiu+,DO|aԛ/0pe#e3'-98Fi~΋ D#Q$s*BYAKFUG ٲ_|OLj^EvP|ϼfN>Nm~tN/;{ǀt} N~DH@uByԟQJ!i_6c8}N>ĥ3'.91{zI Ȃ BD3(6;6CPq5 gszVhlY5yE̡8vqˡ_OV(p{WMU bo)L~ oD{%D;:yi4)\37Ų#q$2rR]>wS D2HJG*rSܐ&+qX k4)ZS_gCX!⢅j_)u !QQh4Ȳ$Ց۔InTF0k49P zIٕrL..r\& MIHP1i!b95-,(4:0x?עvZ?[e~W̵Ts<bD *n\o2wc|"0c,3B&-bұ37QGOb8FZ%r(ܗ߅:G"#E*ٌE%>1[\‰"Ps;HU'cEGJ8l`4:]*8Q/mM1/b}ttq!F-K\ ׻H`hлy%Cd$1V]ׂs~.aڽĤq!&`j.v+kWjQ)ԢdK? υ9ef_+.lh0iı.0q{20ԉ5å'?`ߚ6}Ojލ'.{sOUZ\ Mæ.6RV%b}1K@6#$HaA 7fͷ>VDY)##$@fPjW%Rz/^1RDve5//yQG!W_}UmIT%۝z33uP_r1cyiہ ^Ac<Ȕ! <F}!0X2bƍ$rt {aر $u|=lZtjuF'tʽsPZTdŭ%w8S8R8TX!GÞJFxk^* Vr U0*Œ?)2b."'S8@rlM_WD4$.A4+dboJN@b@^6m[!6/4p<WsxcuRu,\3bHF2]TzlE ܌ hHa3ȕ+Ki*{M&qVnKRI PyHP@@$0!V]R]Jh p4"bVfՀ01V$BJђ*) @D-c~r 1)g\mu[V}kqb"t(|=#H-6m9**ӨG%3ĆZ-2X$*AzDe)?ADa6!!WٲLcWaKDp}Lʅ~2[BhZ )8pt^#tO/ t\8Mj@4hP6`84tMSyE4-S}pPX< y9]KyobN1r`,gTd^xh+HjTէuęLC*O+d5aA)R <#$ 0u-nٝ*XLJPfB, CapUeva$)jR(5:͌LS0QjDoEe"\IQԢJլf=_iJH&Vhg(eo*I:WQXBBCTm{tACݓ9흴Vv^:U۳vCy[YyG/G_umjC #QO/N-Vik{V_}b؀(1Ǩhk;8Az1==e)\!~0nA'2Rn0!z ͈/odvg_5qZ_]016l*f.^H~aV5}_4ub#VУμ/"j'[9O;ykigo|ӯQo©NrCއuV~8zF lFssX^q5;z}9 ҼzQ#Vn*`ɏ1'hqV$lT]u/ t)q 2:D~!SL.M65"!&fOY4JeRs?d`6탅PS.+5hw^noEh9WpZ,2#Vnj~Qg^؏wOr72Ht|&afTt:#'p/GH1FuwȥjVbbL*tSԹɣ^ AB_|GNzz*N,{ TUzᣯ6Gg]yX#şNk)2[ړ՜j\ U?B[fP$% Nr^f=($ Un@,$Uͅ"W/BQGf2S)ʁT1஀4EA `J ")eDp<"6ME@izȧvF;xxg$ĂW +|G];wIUTүht|1'wUXq~$ta-yZ^dLߩ >W/5p .x0]7өH|=Ο 0s5?RoaTMǞ7?T'N߼3 ;Mg%vzg=%܋7!1'+PͅJEAIZ% gܟƬ;owhNkut#e 5D@7>⟻9chbx" IDATONDk:uا֧Ҡ,?NdeP|cB0ڶ% ݳ=h&0w#nZ}DF""r~uo9]`۱0UK+̎;j[@v5 U7ud8:(j;0@"9K0X*Q GLѯCTm}@Yh{!0Ƭ FO\6-[FP;Gj Yp!w'NL99aҡ' >ʺ=MdZ, rZ?}' #@duKZsj%" iLRJ\Cy@Ks#qU}(B#I$HS@SULRJIz̈́&G$I"Hо*++c#C}v#j.-d I*y$'$tdkUv +U2ʝT&6)֮ yJÊENr'U;i>|(Z4?錵䜁'wX|F8N"ߑӍ z3SߚTv}?/=9k?U-)s}"A^2mx|FB6G{O769zl2vS>ȃmٰͅόc^>INu(֪Tȑt1+ /"V29GYD^ !)sEo{qÞ@8.JT)TEO)fkrQn=<VtT. 9 ȕ" Q4ub٬l 邒cV \j[+`?c;V̚0 ( $DMe窄O\W2\U [a ;DʌWE0o1i+~Lĥ%rzn"@Pj}!$˘``4J$HH$IU+vSui;cwviEnNTf;ݝ6 xw=r`[ڥs@ﲟ7m +?yxL܌ore%=OlA]>rC}>)7:w'x9}ink1XM~ g+Oltˠ>ƩW3dIiնFXDr#m O1nt d]OU<uuӄ{4l9/ZCA I7y%_NxNnZ1L@^E6 U0o+G\j/ uG3rݏu8`a9_nXȘ]A֑p\>eq|ԟm|?M\%`SG'6c7 y ?7".}ĴY9mXBܖi]V #"Ѹtyfdג n7Z',F3%NW%ldÒ{ ˪Ŗ?IɣoRTqjx>G"{MJy&;$?i!Sew rA-P+,0"+YɌ; Dp)6AԐV7[ 4f+Hf7H-N eRIEiPUe~^LR)PHR QB"D S)H R ς $:[FO9 M -PwlTUzKMo pe:cE~_ds-p匪Ikk:r>=+]X2w]YX,(yc'4~eJ3OiϼW9#ӰrK({e=k r{uVxxu-~[?yoszWo~/W jۡUw/}Y뤔_dƘ!-~ڃ 8zqX¤Aո~u?{>~ҕ^Y[{?|]A ?yxu-~ڃla-m?ttwˆރߜK,?M]%-yӍ/)/ӽ4gIF ̄#&52 UHV Q_]@MU?L}˺Zo}DUّۢ0pmVǭ~ESAv~P[#F9)4Q֍[ Q!fT^bTU3>\`,]E,].P67@~-FRn\bmW:gYxF,*+߻TUBWQȖ2žVΧ5FA$DA͎2]grD!\a}F&I32Ν7i=R7.6!z9F˨,XSrw) c 72J=,.y6+ǸK ֌GZ|RP  @$(  bFbVJME B) g%I Qx8P@EV$H)E* %HA$gۖ8-4OiT߁q$Ѥ"H(U_eF̔V@A 2%m@&z*8IH 59t9g {}hcۊW>S R5c+-ZȊ5-~J25];pz]3܁wn!}_ؐlZw`nӤULO'STl&*.!?oInXjlH.U+sHyfH[&EGr>9aP #Ͽanr/eɍ٘{"!N-BˉK/Xxa- zn>9A M0Sh ^TO4|{S5T6>uŃ|vEN}rCJ?hTΦjlxta_o^52![l8_O U:4pxe<^iUڦm{.bN] V"y(Ȋ/L. s7)fdb!t0,biUc̈%k-w=rL"`==46p\,7b[c̩ӖK!$YEnB.",`"*4qIj$SIF RJB`VpPaDY2+HP V qR2u%$"N]LW( :͊@ PԦ䨡cB:ʌq RˉkGRhy5ybŇ^s9vW9)sV?kSWxW-no. U[F\~9XMiwU[V ߝ4n'7;W=:*`ww:aeO5?#V=g܁MAy?|vKt߃;wӧ w6aO/53X3 $RrBZw'A}N/uOM~u ]?i_oӻ_T?ܛ*ﰣ:n U|*-YتM{W7 <h[wП5cRk\K%j(~a+ 8'As X$O.̾o^8p|v 8O&gK&A} =?u66Sʒp|slxȞc~܈S3RSw{xu⍗]?iΟX߰gt)ps" ]>: ^=&$FYyPjmraXW GFNWveЖU\cVb$@ {X]LYȺ \^a!wfS!YsOC!O .qD%Q(UHjV6tBWhf޻ edT%nfʂ LM"z1oP<')ͥPyښ˛˛f]%DDS? R"E *l9eE5Al<bVאL?ݞdv崛[m&vG+&e=oݸ÷6 ?:hdڭ˰ Լj튧3o'Өd#~ >_8j~}l۸%s{ ?ޥ~@;㺙cC״A/yuAn3&{{~_ "tQy񻯿~q`'Q3x!>rkI곿.~ήB$(ʋ$9w`9=Pd1Tt`#! 9#5oС?٥!|<7PSn]8zbb0nCfР`b/1ILTK R~v9s$/ٟܙ3vwUi}h r0#$("0/z kl=`|{ijWf=W͍)׃|V!zLaIIX9<A+ n0d71)PM,1" |T}[W uHJ!Z11~';HAfd<8[4Aa`Ų%{+WVkVkpB{w5fB݆MN>qI' 9 b?R\)%U ER¼hTJE|P,b zJJ !V룂`"b!Wh46}dck/%1}צSz\<\q}MJNOBAp/-H({t^>R-.VXZ942~,}N?Z9I(a!/ 2V5s lPZW 4\ ۹}_8jc,81Э"ٌiE>K/@Dŋ9;Z(hY Q**X$4J: <& 7M֖1 'Baxt$QL͚ۨ" iUR߫E"|VkH[DY,6(Q ]i[4 q?ęad gBo BVoRB Y2킬 &k4t!Vo)|yn#/eQ&b܏Y :_5>G|w yQy EmDOIt0 LcfD/1Xc%[k84&#(s!-$˶Tt O^7"z1rjW $vÏXAQ~QBzCAŭu"c7~MJgȍ!ۺqbږA]1!@/RM%Z'%Iҏ4tvdEM4z289v5zH PRWJiZjBdɀHRڎ -٢^ s&Pf<M:aExY%Wڕ.B] ^ܮWjj~ Jb8=,Y$%0`" #)VVLM f"0,0Ւ KY7q1CP ùE^kF#bDŽ);+9vUD4b#W߳3\knCBtTN;x` nO#핝:W5F\Bf^9)h!J?oUbҤ*إ>v_"!2R8JQ VaPaEGiWr;aPZAy9h$l*~0Uֻ%uW/Rp8RHH̲fxs{+Ys?!̎a-{Ka% DBhm|I<)<DHɚ2wRt$9ɯQFHcu3S')TDA`z$ BIBJK%"@HRDFö, ;qH(zUT H(5I (sSF}IPv" jYs?$?|NrĈDMįT߽ZP#ǺDZTP]jK>$@&A`hJC&)"}+`k~ E': Fdb)E8{dqAhYzERL$02cziP%4|05i&fG*^u#5"n=KӆqH"'Ӹ)QF\bACQi x@ H"/RPit?\w1|+"h %D%ZK l)QÜړHwPz{`Y<`a/TD|ya :3!R1~8%78In!\((!ЃaeA ftP O%b%(r]F4=1'[{lymRer rB= @h~!M$Af!HB  '%JސHI !AH9 IP$$! BR  (@C5*X?SUAJB0+gBAet $ tQ"2IH &}SA`3ܶ}aZZ[Jianp1e:Ap <CbqΌ5}aCdJ91kr%B1a졇s/mnA*"V'<ݍX^|;Z}הT&Mǽ3nȝ(XFp,-jsOk C,!fAV*Lr '(K % )2!W(@dJ"sI-%@.cHJ$s8s%D*f4(Pg"( ')LjMhQS!( \+(AA(Y*;У"HNS;ӪN5I *VTRaw/@]R-}kv.AJ`XJIxY>&Tb@̓ ;zO"0e4x=y zњ؀B/[6pfGnJ*htSqR`%TI~# IDAT.╈QB[S!c/\Hߔ$Qs(rȁ ?M^MMHW"@Â'1{=:C/$E*ڠ'4[ZOPA@N?Fi$>QYmkP% z^1v$2 l-r %)>`Y~JVDl̰wZl`л,zEqTGg) Ώ( !YJ JNU #"PQ!J6$Q8NZ\ZY} ]@HGta^a 2$ E o.2W$yn c#MQ<<)Q*HK*SUZ깓@(NI+=ɧ}.RhtYꂪ5x^9ܙNkjw$/Gb $-rDI# l>Vx [a< _w&Ն?MKh. WSkVk.isMeVbUc.E3}o}V9uuq):nh!Y,9s(= #2L%?4$4!IaX||Q9Y BhEbsCk%a# p(9ܞ9ZH(T  :h:.:A}sCY$(*!ttWIyA5_<b覈\> uFtXȑJ( S(uW7\eCE+EGE< 6e Ga@V"kC1pްW"Ux9w-&N #0>o!b%Z O#\cl`"p$ R974((KxHxUJATIZh1$\R=J* , )W& q@(9R$R U$fst|ǀĤo*gkSkVkJ0C 6o_-aւlGb gu]kF'}J/6n~}݃ڶh?=xO)=p=ѩǩ't:MĺU˥nTl#\?7\Hqn>^rU][EwN=ӶUosݿ߇n{ǒ?A"Khx֡CLbß HLcqvyj bPlK/.[zxA95՚}is7$`N-**r;zEwϹndX|#xdƂlV+-UޱK0Z6: Av?UUسq3-u͒w ՏN+)bD>rLU@&m$.Z~+ڽ^ #E 1G:B"Ôi&Ǣl2+< ۂC ƕREn7$6A~5\<<< A]/THd~k*+IDV~k}f0a#pzGJDϸK1Id|iʜd": X:8dž ŠrU䌧.7& ,1G1$cB:s7~`np]5;mr`V>;;w9G,YW=c|k7pnQ>a۫ }F.?7F A-a6dW>;ӻt9ԳG,`9\,Y(BI!Vu/Rre6e).)8 )mPՋMLi,4/ˣElMSgr4l=tPl0J: a,nLclg ^o aqy.Q9#dQy <^9r7\9U $k&~H4dH!L a5o BQ݂ ( (P5+6j%du3$!(C)P ( ( GG-ބK5>A%JEZ+$JT:+X"&疄Or, $TAJ(uJ 1j s+H^™jJ)E&IeU',;\w=ExxZi D< HeX4(9E4x#u_Uj*X@/6q 9\0wR>ݏڗloy"nprSpDiyҨ Uϛ2Dc&[M,`ҘgXxv'mZ[&ulSY(p{u}R]f ~{ZNy^u/]vS '7;̻ѷWo2<"(G@xT"ØUYO5nlnm~Cc}N :g ԅEYq/6x?ŁG?ثy}uτ9㎓&sMg]w&~pvyǍ{Ih6|~˭3.BXy#б\ɣޜ6S]7NܱO&7`vur_ _tvyц蓵.e҅g݃8qT(J6T㻳֒F^!*‘+={]MZ5{ʨ: ĀǓd[A^SD&:5E@ +1c!W =^6R;R,Je{\+*'E n/CN,L3qĂQBe}V5.=ԲJD)6 >^wO:FDi)WPD >Z. "ʁ0G-T&EH}jB @3DT7%P Q/$NOB;*}%H6$D>S͕`rޓ|C05j"jRj>XͨVW yZ|&>xs8e_܀tbI[.27W7ncs|㝧g-Wjc3ܳL9/sb\љ&ZrӇ˽tK.}4ώ\!,JҖ9t+׽GM{hbSF ?cg؏Mol6n3bÝ}y3ܳ2Ub =% *0NBs)d5wqG1?g]@8eޱsn?]Yck-tۧn^`ik dEYǘk4nƻOO?}p%?<'澴s!;:rKWO'm8yo\Մ nZE_\ =s2ojU/?9|TO5??Kn=7LQ~) sVV]SGzzNJ(s+CH8zc t8 xL!_.]au:)(l.4XSP䔩<qVG벁}И%ŽRx2RYy>$*܉i=AayAz>h X=%S3%]^7;O&QQ(l8ZEJYB'dmE3ז tD vx* i?Ib |eLݫNIQ4ԏ"I{ @B݀AI,Ҳr[$ ҄3ThL航xS-cggKGo {z퓷뷈̳N[~w]34602&}{ >qf>i֜vɒGqeVm+i#rCۼAg @^:7Ŧ/Ț(p*?qVt̡ ]YpQ{\UTTn['V&Ӈ}mm۝5ਦS/7mI&4ii?^RI:nR1L`>uY!|ٕW2o+kKz0"i}'w?x+f]YIr m:6 #9Zm_Ya}{סG'mJ[zs(٭"$րˇi0*:ǩ3L-T | u % GUI,<2n)"5[bc. e)A横h $*)|\{$ $!!QH(I+c Y=deD BDeHR ˄e9!'*1$ԤIJ)([W?)j3f7{q'ع?8^lvxH>Tg҇ ZAC}ڲ8?NJa[ ]Wemd?^5~ѩxy_(MΘym7q;w9'_?Wp%g\"7@sfňR1z.ouE?({ucrp{_r9͖Gѩ?n]$_-a/#䏤]KŠŽiOd~Rdr! $C1WKEFHMֹd<(䨈)> jSTUI75xa.TLoŸL[# +GM:w^ ,¦]qD"8z| f;l!eOA-gx|RՠHV de/P@(%aNI$y QHeTViʨ* %HI4)@5 r\j!@jQ7RJ)}=$  1UB!s23j-5# V}gQ-˒aF;JGT+3qjj_)Ovc.׾I->^s]݃c҈B+DmM9?II=JMH[s/nuȹpwwneqO,8cBĐkhy_m'hS.MbMݜiV7EG[ܧ.[sOS]*4VR+,7fJr"Gڌ,(F(r%]hT1ͦuꗺ&7U[0Ŧ||6yO2y;/1Wv"6dH>D CV&'>rWGh_kTYN~q/,oZ/mu9H]Z42h((BOʗyus~H7` سl}XTK˟>h5awn$7}R 9%)n:[+]˚a[\+DOQ3DNRʔ%<6Z,%*ZIiŴzʐ!aL $X{7zfș_:Zc T闞wЗZ טyyް佱Ni۬n{ ~ ݚ"knSοb%V:{T 6i}.tTyq/,|]{@@DWo{jMZ~>6Z7<޸mZK=Ǝ<+' vc~vK\=v3;u7Mqco3'^Z[Ad2E &rxSgé6ntvvkiF&N%/ 3h Rxۛs׌9{صRVTŘ! yGQDkRLL~j2x+_LdWxXjG2!sp~JSWo{Thj]骧a={τhzgj{L҅JlK3&9hzIjSPj#:8Ϊ;˻5EqB>]T@Y;<=6Q4UL`B8]#pA} :b/$Y#.-8WāiI V/rtt>o6ud6 !'38:Iπ `YGE*&9*|9Yx֏@v5 ʊ cTH C0)/F w,5Z5tdYycHek S\LTII)@} Tz/beLJy+ [.R;#zT IDATs o$Ap YiL3u,%U09tX> @??{r'Qu6t>=kaP w4o_ #77|/=3p0A#ϽϑAz-!fC<~c;N7ݤ9vmsտ9Nuf~{ѭ@x)h-_Kx8 xMQ@5M &g#v/&C\*^tV44/$o~e*mݳ?w\qǮbC. v^JO1㾾OV3yEEp Jɂq!DXcz+Loo=q9Nr喇/~MyiN8e0#^'7gfؤA bRpDL겲<ݰfߦi oT3 CiS0#]w/x}a*$.)>vAPVr|Vq aqu|5cu7C ZT 0ǼDh!Xzk(QԲHJW'>P͛^:\M dl l<nե9ze[7JnEq`oUJ^-HW/#2Z^6n<(͡E' S`QF#xc=Fĕ+Wn>lPrsMeW V AwkHjV[p=9RΠIKE>oh.Lۧ!&C,iq:_gJ bp@LBY{ } VMb"/<1R44.X6NI1$C]JDPNdN ۴DE|**x!)MOKV j YZ\Ï#t䨗R %SoEI |3w4smU7/XFDŋ߷ìVODx ZgdFGǷ U[@O @\UH#BǮ[cs&9zNȀ9jZ#HKiƈ:\=GYOaX{T' x:xE,CHɁ`ѤNW#jmQҲ|",ɢX poX "X`[pl ,.q":w+Q^]B Q jS7Y($4iYsC o}s%G5 VeX@(/GAxH/ i8:$GF|0%Tj `w {H ` ?529V|RGHKXBbO@ ,DI%BrBEqFJ\%IJG| .0G_J<p yڡPaӄ; ~EezCD[bgh%_)+TjH=NO?qs|}#"DEKYO(mbeKQ &*:&IhK=4$I$.+$\ !jQ%bwL茱ZA0$]KÀ>ã'V Wj5SkVk"0r/4 4*H{DR1#EG;L. ?vc_98߈rkaʼnSQ\? PxWړ&xj53j:']0rU^sZ@ ]w'I2II}U/:֊%T $IɋJo(r22JJ ('$>4,B9IRR"B $ $V鏪xd.HLQTUg6Z7){϶}ZZĵ!}Jʑ51x)') iqk!S$z [I* X]mM{.&QyC Z:rOc 8m. bkr  E.gEڭ2$%Z4©V,a)]`@7OFK"x6!b;X aB!!_1 B*4bPȋVca3R!VSJE8 1 CLHYJTTz3m JFa0F{J|BDBN4HL?д㐍VErE? vEl_iZSĦ;Zzv&a:N_'?̓ގX2 $d\deee)'P/!+GbՂTRHUwJ)s"PgDB9A$`((#ʔrNg KD9dlҤ} h7B&'; "_CR9H%LKؖꢨ{P Ppe9+@ qǮcLrTC@DS9`=mҠTso}UٟZZfALZs~ϛtfۦuwY<0|񅥇wFb/ҵ~ۤई9 ] 锦yVq0i1y$yDDKY@&¢wt5ߒl1`$ H"B(G8VoM3JQ& D B% ʣhd^bwѵY>pRP$ 0sX L!@`TT@&U4x eyO/\ԙ зRǰQZ۹0+Q  _t= D/OmjvUZIgum$HmU[O"L *"Fqe;qtLATbG^(ms' ە￰Y>$)Bc6b漒%o4{3b{v<bљb |wMʓ0=؂[SE@$% jSw8 {(Iqwub|tw%% /0(4<VMyCOql{UnM@mJ8"e6 9%QP(Њ5 Eњ-δCNgGSz.H Į40)%gu׃ٸY:hӶUo/{܇~&8 @F"V6BH,14H( 7#8lx={rkWhJŀOʟg6j'l{!&Ý.rY39;+r]w֠^G>W\5fy0TYѯU_) 9KtkgF-;~.]7Ƈ wT림=涇o?Ȯ]5;=rxE{RZ5"I>N1CY~%Ҡ m񦩼cyM|ɫHCQ.&j䌧ܛ(w2u3ykT-W,rНC/W5Qkw1qk 9g.?3F^ b^PϧB8劮UrQ%/[4I[ lØ,׶Քd,Z#jѳ-QBGL-5N[,H:ryJcw!U\4]n_;YEF@_ LN.JiV tN*2k e.1TVxFe{IW}D| XC`$ $ظToS''Y&Y&)$`Nrky[r Re9HdNR$?2B  TE!fN@@H@IXʱQURGP,Y2bDмd)BRRv䴪9{jjUŦݲhCNqO2i\{fN߷_rm3n|564 KԂBɣޜ6%~y"Z=nn{zt@>}${G<1 x |#~@^b+_Y&QXRDQc31x}}G:O洡/yO}|[8iPzw]>T8Ou?qO=3zBBHK$d좬ԈKPeL/4x}Yߦ,'wQ_[?z[fߵ~;o=7ewmĸ^GsLr1][v^:fLNp'thۄ n\U/ @玻Go5=uU')q |)?i—7pvut_^ Xhw˗:eW W' pi8+)e3 -'jk9 4d4 AyGidx_ETx)UXrru/S/pDK|orBKnde/V!.~9tA}43"b֮6`Y=eDǶ+?n ]&00i ՇXIb]Pb%*_ŐQ9a 3 @$"HK.bRT&]uRT?(ɸ$̥%Hj. PAD-$D$r1#.Y T"`\cXRw55Z%^ZuiڷjMw1'St-SsQ=Mx@C1~#:+yx.x$<^xŏ.|ę~gĜ6؞9`D B!vN^{3rJ3G蓮Y ?g"b:j/=#e%6{4@}/}`G.7]W8u\o3Gб Nh7׃ƻ,' EˣJDQb*rRYju)&%4.>Ӧ^~ZϿ|AlWVqs9u=X}޻IGF8?\c̚[7V>{z=?F}Ǟ6FAs㰞_F#^;ߙGgcgZU?CR` Fn|3<Ǫ?s`G˂sK{^7KڰB#&Š~GS9a%QE DژcBW FC%$|NFfVsJ3n@U>%e _GEH\,v;gN83$R/ xB%C?=#|I! g(.)>8삐nڑ1 >8mt #EٓXVT $IAfjG @OY D Eա4.3W馨jp&d™ IDATb5LKJAT)HR;KAp׌ $a?IJMٌCG@U :Nj=j%+P<܀#w>v`{t?kj-ey}>ߝq։\Wu _0+8i]G7rl?q{|&9%cXWNnMP*l^g-TŭWو@oX AbށcM[}7M^%uM5ym$fVjЪ04L"t|F\v4u{a,/ ZO}=;a_};׉\|W_`oF=[RaW^uW7mZÌ]3XigXM>u?㞸`9:fܿjc=ʻ~~;ryM|6}2s]0{ڙ- NG#'L>9tv.8O뛵̟ԋC1kjH)h`x+ XAF;KĀ3pg=IagdS%KHRTXHKYZD7Vg ƜI1F _@ib#&x,`Ed0G3-XM),c4ctTyBF'*k }"̐r#L+@ sVՐ(|qNuì'7ԍ\5v Lt"86yΫ/Z%6^TD^UN]Dv_9k kyб._۫Y8sIi~2 BwX.U9r'0y[[rX;k}ՆWdng .e # :1] yDŽ= ]3Lyq`d.)")c{jR7rݖ$, a l`M7Zj?GdͽW~"]ƥ. ~i̶OZX!DkuiV^~{WNAxu6G0i[[swM9OHe? "`”ų̶3p \X2C_:6tI:s]ȶqӐ $g,R e,}*aAD/{(ϮEGm 1}[j1=J\8L I{n>ً;Ji^frKI̤Oك>BZYM?sY֬gtWPrP.u? P.٥%.*)#:*SrsQdsSUίufed0!Gp3GQSnum?&"/D#U$?^s.} Yn Sp=aJ:SH Kn1%LZbh0PCpBJ?VoYʐ3|#ֻSń>5@[b.g<`\:^Eb α#LVkJ p ].!&gxZGԈ?]j8*k K9cxNBU}-t7W(z%U|7+')fROVW 7%h?R-9=f;sgvѬ[/yڿ +Zc`6d[Ov_4ɋ*@L>D1 |6H]\ * cq//uoglm҇^[vaÿ9 Ϳ~;~uUovmS뿞v/춟oSD?(5bCFYXp$A_'ƙ\z{Nn%oj[?7? dpPYwsX@8PB8,vJaf& k! c ,LHfFP@yRT{@}MbګCCQF~Ȣ|xm8;c몞] $P cI"LF`x0&DA" "$ "( UN=}w簺a:UΡt>x]4:ouu띥z5crv$3ۊ CM.I׭5rRo]Bh(_ҪNd۹mKBC mܩz֕U\ѥ2t(DT"V3D!>KlQɬ 9_.] V,n`2!mDMW]'ZԚ ;k!K":M3L#Vg 9%RAȦᓥ>FJIQRc0s' w=W}ݛsT^IQ;)yԷy씏 !(:dBYJ?~6hr<@;Yk- xP薃;3qˬL33 )>s9E6>[5UQ524)ŔDn >|KQ2DR'U*V- -$w(2$)|~ Quj}w³ﴇ N#nh=ȩV2NQMù^t|FS=Jar'M̆ ]Df9 C+Eje $k%'hiu[H%\y`6ua]q(Hg=`HB ㉨q]ehaC>rA˱ctF{ RJR?BH9F 0-Lz*:Qkk릉n8`BL\'".kgz6( ѡJGpGL`yj/\]eqZi>`>\َ 1u\Y+ȯ7FO)bKC , \Ji 佹z;|Ft9W 3.5 aVR :3d.л."m~^ Dls*LʢBZbIEz \8(4t cg/tl ȤT-@ F Qu-|划^MG.Qc{h85Fc4h[ o@beVCBE*{Y?`>eb0~1]\ CL(;mb.+~$с|'fdWly O=Dcv݆IPJPN12|Z xޯ65|,CP<@{]n*I^*aE~ R?\T"sA 7A[a KJO%8eLLLmY D)XS 3{ RĹ! T ][[jW-Eɒ r1bGXMblG`:Ne$L!P:IAg)u#(NnhUUڳ0f1(7BBƱn3@OTʴpꃶg܉)7s뙶o?`rVz5`=)4BD"7jREnnl;GN116P2O @%rHWa @<@6+nyH 5C"{uED,P`5OfmY;P.}>Hn" q )i+kmdɒ %&K:`* 4KU~3yK-ψsDA 5Fc4Fc8,Uw-6r+T3ԾJ&K+[_#P/*|Z#XJ:S!b\(UT|:Y˜۔.C!hkxد{;GbBO%dqJ tr RZm1r4q"(eupɉjԍJpaRLDq[9&$RSyj$bNoXlJ`|Զ̤eB6pP,z?1bk?_NCS "%p͹V'})RZ]h|_S1y^Q+ 畭{FP)?Krȍ6!,~qh {yb0ψAѻ\IǙ IsO0͵5'd5)]]sQ. k`,Vݬ”=y61hh3EKvyնDFmYba"ʂ UyNeQg[^w&Û"Ex {^{vZo_h7xS yuZz 0Qdh9~![k-kW.n3hpVPM@]6Sa ,LC5'>ŭq撔-o˵#`1zNJ5 "_Ɉ[8kSrL\W$xK;]Oܚq{[RgH`osd^gOO1ԅbaeHG! {# 5^OJ# >"ș8_5]D@EE ` V"['N ''K99ޱB,Kdqy"c,4?J`O`;gtu,+/gt^lӝC2: 2>jG D ŽE6c{cjfWߥxZ–bܖ>Kl7nBd=$}[ ^~*]U)gx=@zI,1'HS,la$1}а T faJSk=D%eAR#znR)m^grMg>tS==ʱG:W0_Ɯ1uFWߟ yPR$y4b9 s5wXO#b _x[X,uTLOxqsjS-qm% A0 mBAT%0(B(m¬[Mu6nqr0 @Y0ӱc:1.@{(2cIʼn_倘Pnp"nN#\NR9%5xXIՊ fA)%;oys_ysWҘ6C)DayRDQDE 9="S6.iּ@v*ZF5OP01bP'"Ujf#b!1JD\EVf#!pvw<6_\Wnxu2Ҭ?-~-7Fc4Fc|moGfIEsgm`/կsp'0 lUPHIƦg3#Ք7ƞu0l?}h폍mgCG:4gg^{O0~磻ore}xz+*i`X"(gCNs5{.?ig7>`%+>xw;qmD XNY:]7x2Y36n*a\+#Nv_x[:KvW=h|#O=wx63qV [w躟m#u:=7[|N-34|J7T&oȐ'=!J~jsC 1+DbAXg,gs$R]TEr0Hz}~;(aMJ^ V J:b_cd(lŝb&^i|T$քKq^ @EQUJy9k$t=(2!p}|akNusYZr#IAY1 %e H_Q3 V0te!|B+ DaF R$,G2dg" JI DܪZ ]o@"VQ0d_P+j'(Ы6]CX6fH+d-v%A[nL=α7tGw?Ռ- &Eev>>rSRsNz7ބ;Yejkҏ?cO>peM+Z\?gEw;@CKm3߻ J>#@=8:gBץFy:Ϛr+]c^OK׼Y{&[:Xd}GmaAGLrŔAc,'D NDKᾓĠyGl{ǝv~c;ƏX1[fqӡn'7w9wG̭OӻG;Vn?W;yȨWR!p͚tet4٭_tYw{&{lug)om q [wޫ]R.r#. { ;"gL}/=A7nMaslT 2 ɞcORQӸ(RRD{yb49$ 4D62'N\tLR'AF 5N8{([(dp?<1,y׾vt(%kh?J]-j-)ˢ አ,AAhKpS)YX^*䙰@ HjWDa`͝tePK˚1z"öEo$J̚ jZ+&k>raAĮ ΢,KS kpI,e-M>Pwo=lh?FxiGsw~qOx#0b݋;:uʭQ.V\Ϗ÷l;bfۢK搳=ߜa[.qozNq]p&sm7k~+E{lN~5eGpSWtCYq~^7[K7gGn3.Cιsc' 4%EA0UBӌbT8dl˶^o&` vxja 4ހЌƒHs08CvHuԄ+ 9L&;p 0V|]ޡ;$ge2F ȿB+3 B_Re aHMP`hJBNL^\B셃 s bZʤk;_/R+"osw>K2{0V6j!{k?. ȳ 2bJzrb<ZU&1g"G!MH<)$ :Ɣ[ K%(~JZ,P/¢-7Fc4Fcݎ|-lc^v_rtv=N%#L+ԩg^qY|t' e-#cnU&MQ-}E;m{VFwRuIH.Rek iiL|# Dm9}įwB6:$x}17_?!F9?JFhf $`\ME}䦻KR$D,$u$M8w+:ߘ[F:?gcw~~?NwFos'= ަd&rq `I9CgC,n\|UA n8Ps?pshs u/`W:꤃'"^x)5RgF ` \Lb:5ԜC ;l%,mԾ(W2!sfAad҃%P2S&;E ٭68bt o5Ѽ FK"!<*SSSmAo%%VO)C_s>/D Tphj?J_ʅ1&#"sqd{@]Ie_ƺA&(*˄$  @AeH DFRQA$&%PeHTTaܟ-!IPUBWtV* dB!H$!Ai*) "%RRRQP5 2"oΫnڻD.^:j4bp Z6]v>tFwb{s ž+˟}JNz)@ng<3i2ID# M|mYi}-$kިGRGS:*JjEnk_2{o}4Ϛ_J*ӓKbA[YjpR9~.Y"4LZUK5WĤ]{\ʻϬu6x b=APzZցq.w>0*j{=4P6>F޻c 2ﴰ\f ̸&ӟ3.Pңn/GbHJKy:Y}j2&2oɄ)$aFTõí5B Ml WhnTuu#fpڰXbSc; ' acB[? ܵ^naDR\@lgj]0k%EG=ĸ?NKR$% %H j'gK{]h"P JT,@;ɕB%2D($ #戙gP5}1Y?̘9mEQ(d(BB)IJR @BB<꼎ι͝3gάYfΜ5miӧM>}ƌiӦOvڴiNӿf֌fΝ=kUtV;ư=o9sgvYgΙ;{֜3gΨ:XgmoE_?=]MzCg>m%~5y_= @ڱYgŚw݆_ʺpƃIҒ}2zǟc>?lj5` ٭фKOfm"3;zΜOC? ǻ ?'=gr~a6~QLg1\q'~z]U7fgⒽb?sy*Dpq[RJ7-5Sp ZAo8h 77#$z[qp4Z"P/Ǹ~qn7@A&TPoN:n=zr_?{Qy[=x%&Ie7y@ϦJ~{gNcgFR U`oqEmzT kZgk >||1?ݖI%w\ŝLcG@s٤K:p%t楱%@ G;{Yy͜gRjΔ|-hO"GjdAѡhBmeg]2ਓF߼̀fS ;1x>[Rf1}wa/ۻ%<ذn%"?μby?*mQlܑ3C<`_ng]Qy+O=p)ȇ~A'=2?x135bkBc̨y5͋7nōp=T@ [l~,>⬋?ѷ6GU0e-r/yT %Ij8(R$E[g$j{JFjnʻZf'?Cr?"Ȳ {O+QJA6!P QR}U15u0썌:Jp+1|y`zmmn8Aw?o Qgi2HȜK/M1Qs:ua |){l\I݂M)LqXFx#DjVgOFR u[٤~i-yR;)A}Љ6DZmHz A'䓫2Ar~dL K3uV?DnюMAv;*Ril+oĨmE"0B'o 0S)0/"jbBT(m;B } T) +H0< "ry)D天 v&  IDAT`11?i̛?ψ{`^مAq>Գ|Њw6mPC5zwRR3jvo$2ƬwuX ؆@ALh `tA9Kal5EYD@jdm XD+11܈Dٚ@D j1 N」U7\s=לbJQknĩ {<"8&Ƒ3|ygO L G/JڽdV RjQpZ=G@mΉBDʄ|"nBJ%~+IBL, EgvURV0j)([ @D{\j;mL0E֑~ף?K#moUte?/ ɾ"NF]^Y6)iZc2M &E. ݨDJi4,FD@E1pBh4TV1>Fy n}ERɳ,˄3'ưй;LeFk=iBbPzp(l@@krL)QzQ(,"OAɅ>*0c`ؕ Aҕ/a)ѱI"]LLTrV],T[r= /"XV7 0Ag$ Qc\pBa~sx1 j~ԄKUe-e_˄ˍwł~[Jfz1$ V$2=2 WF0mnE @7FZt \ (@{pw҄TSeDY "*GsR>qIM* J[HL׭4nTAJy P +Jiic4{6DX?9J"Uؐ#UY+RcR"ѭAY&*Bd"];F/ӏ^RJͽڬ49Ξ9(ǰ }da1ڤޜR$I"y&€Q!Pxl ) ċb +`^S7,&?P r^k*$ٷ|XY<ϮGe*^hԻi L2z?o PV[FV* R 0XdRJ2yf蜧g,Jq$T*PR'U%υȈ f"˲LdY!NEB`.@*EJB=HD5C)ԽDVnط4qˊ \\ Mھ9:+TR1;-v{`\P1IdUi*5Y#;=%m:*.ʆVa7#B{A^ 3m)IJ)P !N`Bu' A ^" AOYp, A^ fS 5)t>8C.0۩,[Շ\ǥID0å-( J6ԩ@q C4XU[ (Ix)/,aB4vPRc*obMN35?WZ-~:dByTirJ39y@1gŽ:6))I8eI ZJ"M`p+akU1R>J =(stlZR)%"3Н[#ڴe4Q ZDjub6dq jYh9q IG'W^ـq (* 25\rJ.`RJ@V])UEg%Xs~G%3P?+%1g P rH)yPYWJ 4( $,M"yDDT5Q ix0ۙ|{A osnVoHk۷Oic4WȯL`9Dr&9lt؄ _gUV.-.ix}(4DHтrM4R^;Y,b;)m) "2uJڈ@Ja(ncq: _#bד8,><,GA)o٭lCǥ|g`c",`/p?ǹX1n*WbH$'AϵXk#zlZϐwg5A jLSu ^:lBK CJ;u-t^0|;S} Ti{LI^*S͚X "Vռy]"PBdгRE&@)YF(%/^ɢ }&1p ph3B[!FA0ӆWWl.?ʺ|ag5{ CS nӴތ03IJ*%DI"Z7,ׁ0x>cb)BވO <$ڄT– yH6*Ч@S9@ХDo",dHR'WۭItg)gߖsv_w?*(*Fp6NTESĨ_={gj2BJKEK H)TfEDmI@RZu> O~wYd%j2m\I-żA$B(wA˗>EP=v!hk&5pb-nn)e0dkFRR5 YAc&%M !31UPj@SJ!^3TXG z,(dÄgrLĦ-eW5J,YNgZ􈵾Xok)C[Dշ4AWP) 3hzu$.3l|E,cu*TudOfy.dK_17*F7ڬϗD mRba*#ETcIT9)ݿaڹs adhsKr&6)Plxĺ_lDآb/аY!5:)- 3St}FH\n I5(% d-&FbVJJ)eIh(hM $ nHPJ)B`^64+@ GH'ҾO$B BnZ̳P P) @A.ũgJ^77Dts,Ƌu|ou:{i#m@PV~ʑ7X}@y3~G/9g_gwvܲU=o}KJpEzt*5 .:`W[wO&{4I[?b!;nZpڗ=MRE 68i!+:?P}V?^ӇF:ׯ?Eg_EyG|yTu)z\sǿ?^k{4x_| 5\AJGA#CV$G7Z4hӁp,SV:xx WhzS_^xn6Jz.9}`l* ]:녠6*(dXsq[.· 5sGһ^!(q@J-[-g~3\xջQ6(.!+/>zWgb>[OiWhƶ-桇:n;wpfDO J]7ZZnM?nis]s׻(cRP(A@$R{;B^t$F("=}5t/Ť3;$AIJ`X0oG^r13 `.L$tBYڣڊT <Ң` &]sҰ1TRʢZtuuEQT*J @OdXtO`j{盀LXe5k1̎H_F hrD6"hBTeVOIfBE+49ZLӇ{B2/iJJ ZI4%IJ~.vPHbid@M )߉~ʊ8DJ}R@f$?;U`nn115p?}쒃w=-|nAۍ"d~^&:,#Ϋ"Z(Bu?}73&^r匮~ˬ:SG4*B`]sVpAy-b。eSB2|(`_O놟w<={r˝mydo ?×>}&7sy_xz6-,f`UV̒6RDZw?>q/m9ҋdQ/ вQo?i_kwMG "mcJakRQ䱻P&:# bE6??]~ѧ~+1Bg +t5}tKQd4'l|>G%6r57>hKBuҳʙG3N.)vAX8N_l ni fRq"DdڿJ("ʄȳL)J3to$2!4wi@k7 J0h<K-ք6ZlORE o5 жű{"E K}öw ,S l2O6ZVWI" HI Y\PUT*y^BHtԚD@ l5t5sе"[cxrɈڌBIJ-Kag`BpJ?U-(X2%o%wwRP$(B AUvWS[y~ps,JPzUeaLR`!UH#IADTT/[-:; v$9}H1[F!*h%۶YJ>O:fťw~\z̿u\ɯ?}{2aŧw~=~+ !gn8 lk}syٱuN,J{|٥te{ ?[qU8/O3 Xrƒ ;m˱̐ ڿ+?}߇^d tڹ{lvl䦑!O#wx|4tsgcw9"Pbf5D?E UdJA{ll1Ig@GCb̺(Fđmկ?yۥ"w^{IKߝ7$>+o}=Y'ߘp[^IYŇ8L@%';~緦O7~]Ө{wl}m[' >> v-oTw_yi{S;vW\Snf{ߌtJRzۯ_|`՟wi9ǿa{S@/<씳r#G][{P]u+)t}}cO=}eqa~t_zYp8UOiI5dHd (8I dưcϞ-Y5PJ"BS%LLu%''GɄjtKQGeY84! hpE GZ+[2q @EFLc_Q>5̎32cX0hP#2!PECռGSg[ J A], ),SH!":9^g:>%2|Cl}@))Q02HHTȅhԣR_EggwUE$!0T+y.P%.?_R*[Ԙ\dyeYRHK m$ UTI)!GKKKJ杝39hRJ"r|{(DB|^}IŅ!K|&W@v&PXPQ8wUEʯ@kv)3PVJwv(SD[;h*z!ێ[,'U}.G0l.>P?{}+&+&ׅrQ4E9i;Zq߾g^9bKo"![X/0M; ~qOBX*^e@Qg:`SG}~[%/ Nqvo@$Dء_~m;U `֧sJ;TePb.Q7H*%xUy$:@q{Q1`ֱ6H>g-~'ȗ`Fw|ekdcGGtJ|է>|⁧|3_:۟͆3Jv8椃_z˖2C!)tV_}G/2Ows~[uNzՈvw32|ȝ(L=wg[,n'}̥R0Bd"#(J CX)oʶp!ӭnhA)^q UX;:w< PJf*%Rr]kuKRlٗeB 질K*r+^[AR;Bg=ZZzh&"oi^(C +gd\3fٌJJJl=zw[dJ27_`W-&u:sk=rL@x4i,&[Be@T+hnjTY% J (E !,LOuͧ3m^(ERʢ(C,2].yDGje2) 4d˴ !{~@H}տ-V*3f͚1cƬifTEQ("T*-mmmmmM=vQy%B8m!4#@Z*]ՂHey.}B!4750J @ssB h[[[KxUrIjim齑Q+ 35LLO PBŻunMEof11gDĩS6oH1~cn)^n5 k^jZv!Y>Ӯ)o❿Nr+r+N5ɯ}č']p[/4`G\[5<{^~y0{֤_e 5y_7V2SR1U5,c|UKE1&NM~ڟF \gwVYSADe}[o8d4^|.;S>i3e\YOc^ :^$Lbw|e*N{ٿ=7[quhew~ržBlsfXweL-VlT*;YS <02{nI~U"zw&N33y.2e(2y%oiimmmkikMJ%T,~&75 wVgΞ5k]={r33*ndSSve1o~K֣_E{/ @Ι3kJJֳgkKKM^Yi-HAIm[H+"(mL_d&t6HJe^LE _c4Fc4 Kѿo[G[}`j?C1 㐋N)dHg:>0]uGtVh2S7luzT.Ad.vr75Z+P L (JNlaxݍm_~6m^"?}Np>q -˳;uD9LRKVǝC~Yb+R=[y @\de}}nؒJɧ0WeVtıS5+'67M |#`73lɂY-? UjXg+pԛOQ-o KUw#&fo¶\]j>g;D+]Aaܯpmd{{G"Km/UmX4Yx 2"|[UǞx fgu #=|KڼQٯRsӯzի_15cvͭ@|lR9ϫTrfBIIzlkimTrP r E2]S^TX82R9[_E/(I?H,eI#O ޔZguɫFR[LVSBˤ! QrWE=Ĩ87n1*EdB1ldQl1@$@d@Gl{25!.*/nʙAz5tzyp#$f2**ZZ,D+ @PZvE$"ӑS6|YS4כrbwe,4dˤlp0"DN@{onUUfUϹ SiQyP3to!Wz &@ATEDP@v瞳wU5[|~ܻwU֘c12KWV-U~~*35Č$ ;@!Hzݻvٽko7 ڢb}ʠ*q+++;vbvb3 ĻkǞ+{SOU +k=4;~1c^=/c>h3k]ۗO|ο~\t/愛ERե̕Lvw,f|,#-Ֆ!{ $y}ջ A 'D׉=}qG]Oyyr<쌿|͋ϺMf|/+Bm%hեP eE Aጫ76㿼Vׯ} ~r'μRJ'ղ  WD,UZMm!:e (/ng3L+>/vr/?O}ݿ~k?+fO}TEZ&1QCfMLPs_sޛIx.n{r>S?:靻cO:H=}ͧ>\ѷ>w/|x#5M| UT|KDna18ry҃/vc~#~GE%?a'wȓWg{ OO?_;녯{G;w} ^mp{~¦=e:"$I M,̘UI^ ZU(k Z؍>4bcZ菌EǿZ8?~0Idžw>-)8kD?m50\%aHT[{Z3H~4P:XpC"S۟s3>uU7_fzǷ> ~3o~,"}ƫ]rح~'_~6?}NW|+fG=oI FI!r`aASgOy;.գ{t}mg}%zupcN<n;m㘭_]Wc}㪵n;KA~ՕKXɡ* >Rl)"^I v_H4CBH"*isHѻ T{lڶuҙQD0x?ʞdiC9vВs LjA%V^H[+ \\yj%79kG[+XY)MT$HU\Ҷ޽{ATڶN+++"}> bV {Aڶ!TcAH`5>U;{:boAЇ"k1 Ef|4i! "7YtBH5S CX/طwu픛F )Qޠc" XB}õ|߾t0Wߩ\g^M(7|rӜw8+Ւ$nޤ&7=2nG`Oζ˫|u> ~l6{>yO>CgW]O>@KN{;9qO{o "wϽI{(vI~)tf/}洃()C Z9;=}읷Ϟr8O.?/ _tڣ?WN>zq .̆[? ,@/9 'y‰o9:s>ጾ^ 59-xl8ڦev;aN_|{ϸMf{yY]jd}8*>jV.`Y`Fsjk#Zg[rED9dNJs :^mVkB$$% lDG! IUBŢSCv6+s>@tm{{&vM6}!ShO8WM$"1axyvl<%H!@M$>lEh-HI8a [p-oA~D;ٱn%#"FDvn2;vȪX̻lY5 0 >zjݻvR: J !kuLEb|)(:v IT0w(I ZLԁ[HkPqL(A9WY] h~Rƭq-3)KMdm Av+Ţ7!b񩠀B#YC7[t. MF`鍃"L&D3^bB⃬d(g3!(P*bkÍz P%ځ(Y`&M"L{6m' F ټ>m~'vq#be NZ7'|BП#ݝ[k&BDrT9ۙ*LV*P&Jm]f(IRb^`iUn{Q;7Lsy 6'uLb \EmB+_/Z F"='%?TpTd|dYv[@@`K'-VOYpYc5r_XFPQ܏>{^9^@HH(zR.]ʆؗ:ztĀ'X9ɀJa}Ff2t;dUP$ ðo{rO`v@=Gr`Z 1Lih$ͦ;V'mWcNK.qVr2P0bWEd%kԇ&# Z YMNt篲s;VwVV&mKQ*5z@ܴZ@(!};woΝ! []̚#B14LM9 84M4,Y8a`DD9׶t:mۖٙ: ͗&&3a̞1T nߒTɾX=T5~$ХJf^lJOCT1O;VVV[b 0 sd4͢a0BDmDN#ٍ֎m1 *>~[`\KfnQk+ nO1]ӹoj*cU.lGރ $Xm̳7M۸Ipٷ|}Ny2UvW ($,&Ce{^uŕݢS=6#:NZ{Y0tΙ֊Urti- D"(GTr"A& ~ZSh jϲD4.1PM! %'e~ Qnܟvw~6oDcHI 0rob6z_Ud(?H‚5rm ̱LMg^B+Ɍ4b'$g2/bEj%܃TU#"1 FN,QgCۓ`1 r@{~fOE3fcZNY:ϖZ*d'/0unժ7-2Ɯ_ZZ q)&س3sj"*111!HU^co M&+ıbٽ{ъ1496Y&xA$38L@{AB`Ą4mgιmi v3/DB4*2t=}hTc{MW$sH!{֯(Y4O 2!"GӏHlR*֚HDc2ĉ8iMe"AUwݳg/ 2!{%N"/Ţ~E yu1A1?LNoJQUWQL68aXxoi9y өBU{nc;ucR]ևT$vʮqsp-5BVn{+?幡@v2qŢOKݢo X+M!xfniWd|{uNl2 v6s$7̎D{?^ɤi9g"A~"ShJ414tQ-4m#ƜC dJ!x HRdDJY Տdk(nOCwԑ7N >Fn!7vuꡇ޵k>_HE%ϝ<)C% n1^K<ĪҢif#[,TIT@h|)X~q.| "zm9nfL븤x\lc'-sC 7zf_=o9I[~k;Gx\/ͫ#5ymW_W`lɲlu=3aUA_JԌUuLAbW!wV:-ٲ5̬`dXJce$`3JZ@2LU%Z_VU 4ؔ(k4+K$]E7%"vaWͣUJBV!u_ȈV1Ëkfvc֠9ldz.^$(3#,"ZJ%as^$: L2/D>ļHr̙јF@h۶F]BjS4B|4a&[0t*4 9$ IDAT2Vfɔg}_tCekCB['Bg,Ee6/ `s6Ouef-QR|5J*| b@ەu hfJר:LUJ*y3XS!"rՎ]zdz4KO !63 &KDR`}hbT)6Vq~ÓUƙv8ʵ 9~B0Oq S/1"0 7~> hevc6ѩWbn&avM&n% [jZ6yPu!F\K!|WHN|?cslfp<RxET) '56md2iLfaM^+AEARPt(QɐhR!8Cny7{k!Q++D2CmWS Zn|'eB$dDBJJ\a$@bc6ӜAIUU=@jiI=3[.38ϞCmV_l]:뒃x6a;Gx`~Ắp;t;u]8m m׍ 6[= [F) #M{pIfٮpd+ ̝VR-F)a欠-v:u+b6q@Xbux V"v/bBGIRGHfJT#1/ dq騊Q3G=.v} F\aq@ !Ժ!$и!lnWn"N&S !]iSj쬜AE|/zs+0s۶iUչf6kvs+a$ $U ^BL&gP9tgSjO"&(*ikwWlk"Mb]FT"P,/Jĝ4$3;\dcE:0d k) ѷ*ڮ)'lef:Ngtj bљ7/xb, Jemmk~N0A6bDƦB>GVE,'2b ܆0y0 5x?X )rRҳIGWO4dR!`%})ImDrfq|pF#fLڶik aco}[ԘvE "Ek\CIA @HoPMPY@J1E! fv%~C@P6YkL7$Ϟ gnn?l[8*.5-t0~tC0glGBNa:!d͎)HT\jQ-JMjUZ4\;Pk h-2I7B16BV9cSo5 M*JYĴ2"Pp8LkԢ0\*[ u 嶦,ά.{ADl#i]{؎v@%76ķO izV7.'jی%6SKg֏ \׹__%YlF)M*bH B+7:>RA%Ts|,s̳ŖBbeqXRy, jvM(;Gi,eRT\&笓8<6T@YvKqmm}6ȧ4pR1r8{ bFĸ65,nQxe!RkSeV KG3"Q1"xGq]k"#: CĄ"[h12" HXD hM&Gcw0{UGJ o̔]VD-Gj ,^%9"Ѝ113:E ;˚Fmp҄NjRO~QK%& nyblnve78Drε6婏XJcBa\R}qH6CrkN$hHX7 ؉G$Fu:>zS-)Y4DAM@Ι1BU"j:?d\DL&%ST1vT5GXDL+ $=cY.db1D1ZhԳD}bU *,4F c!g)d=L07-7! D|hB#} Q&/c" @}?]]m+ӦuDf-B&sJH@DbCnD.6? ECJhO3[CL8oOxcԧCw-n(tn%}zWS1_})%7sqså6|/]m[L8b+#Y dv=3%WaIAǴT9l{;-vGZY)eS7M AAJݞX;]>#:>e33+n4 ح F*).Cn,.%"0KgF%k^#:TdzPP0/Q+!x?o'g5:J^! \xed)H}HЧU),3P$g?޳(O}-isDmqީ7Zm^pQNe$OD.*WK_ˢg#1m],][cVd*mvW)Xj[X/Nj@fYUौ gF{nda'z4PZsj&Jš PEQ3? S;iJdŎ'ƴ¤4ͤmUqxFC%v#f,ehU&$8B7QԂ"qIH hLh ֛4ٽj>JY/~ Q1V9c1;/(`2ißQBMQUpcMD:t:I}{`tڶ 4 |1_,kޛ 3|>vҚ6ATcv4ܴ|iޱcc6eaw;˫)bb7dz.Ćtf"*jHDtffB"As '{!)YBPܒzi)FQJq[[2WX#+o韶nds]{?-sB=#ମxs^[zb;y0-`|x[ 8uDڥU^l tHG`Lv-~sw\zᗠT_#31XBm0,j-صע-8+r]F):X~$KZ=:efyܶZ) zGZ*msNy/`6,cڒT(uS`MBՀyx*gUhTL_FU\x U ӃAő#k0eXc^SqT1A(Jj4U@N Ԇq #UfrlT0ͮTiLV7jt-: H=/OV̭4:v0 {c8HTŀIDj*ws!hUUDR-acyH$;JJU:B u>t]} f6m;i&m[f@/aԐkz!hL&U{?5aE;# 'K&fӇ]CfYntML *>7MkTd_lllt. zblsun:xCO'OQۇW[C}N&%Y t2Mܮ]{55}]hرr+O>"A`}!2;dQ"ښ 6"! UAGdBiZv ȷ= JfM9T<3a~9ÃpsAwe-g<~ч4W^we}οO{ƃ_E[f{mϼc]+EeVY#.?{ǻVإ^sZPN^ $u(qN? Ԭ.my`^J Kda7i-3aL.(qJocu R/ y0c],wێ-,&dƨX%@wXrpq Y q %rOhWTV35EWA$n5ۮ<,{L\LA|so;N H!HL nX\`6ܛ]0l`l-eABdb hS~*6| tw5U|kj~@Y`uYhbl{|tZMo$`/=Fb# &l6-ŵ\w(LgiX@a5)8;DZ8aAADEVYM2c*%ǜB7G ewY%yb@Q U9^Usɱ:NŢzTL'sijiؙıC>PfEcQ!Xdm rw_HQKuq!&2~ٱ/C6YCȬ]L/$炪tDw|br۶ L&Sf"AEn+l [7lj~>l6abu?Fj60 M!$X]رz!X(KEFء#E19'z80^HI!ė4"e1’YUHKZJvIspCmn{?3n)MG>r™?]G<=Oz#;AY^czBwbtAI 2+81:ʅh U@_d,Bs2tDP"-ct0f9:ƶ#":C2skevA2TxJXNLU45X%M%#:u)j)ycu?-,jLU=:H5#2U2icJ\,o؟w<&q *g%rg18?3;~'ڌ!KHvÕBhR(_.Q5 MQiԄ k|:_wMҵ@@f&̸R!w3U&☄[-8:*HIATJq 5UN+IMIcb|#p ɽ(nN9Xt]7H&Q >޴DKW"! H[ ԥBt9b}0,B~F$7,!ep: ^ʮ;o T2 l~*b*_fU޷)?ڀUć 5M4a)/%(M*9" q!>jsER4 aӸeL"z[5KQ(7/̪H}w]GD;vX=䐶mC{ $Φz k{fUW^}ŕWf*>BZ(I]nc"Dd@`DV20k+|Lj(vQf:Z$cs?n?ʓqc߲_:OgDOs?;xO~N 9ɧZ>6  :VKV jvc-dPVVT1 d"`<Bz<+nmf*)Le֔1{{t1Y =bB$lU{wSUxQ.RPJ3%1,W }X?LMϱ9UֵIjsrP?DsI*R'S/^$dLwmD6]?x@n١嶙Dm#!\Ji-/dU1-le8TORr(2\)doDaPHQ ,딜b AAXT[)%}S AqIpxЧnBD0xィр**tߘG]4@>x͎1o$H]*"0Lhmu a-6kd21JM:n7݆{w-@B;#5MC'EabK]yN~g#<#7]l̯;w[wIn`lH !(v+0*254g}6m+*>DFĜ;ZLQ0jhdĮ%Ub2vp;n?M$_娕,yγp{鿜r?_a˕?~7?M{ɯh;_=W^z }ω{OA*ZHdq;E6Udtn4/h,Kq[JoXk4d~ 9?nՆ?76|Hm߼p;i/{ ;_%k="O{^.vl{s8Y}vn 'kh S࿝/?r_8??cpbΊ( T=op߀+&C~U KJ^`j5L啲jV,z.B-=X9kC䭪S)L!V歖l9m%QkBX0fipy՚FQ TYb (U9  )}(KḸPqbEa>*&e&È`2ѕ=6κAD-DMk[{I͚1nqH"+W^êQ1hT ,Ǻנ*A4k#tixgf}gzX,,/#yzuK U 1LG! HD b*SSA@\S̡k?^Eea/(TӼfLfPZ3SdZF$AhzplE \6w7/!*7|ǿɯyKcwQ_Zm UȌ sAg1 ua_EXHlB6j8*d)y_*50՚pb(Ԝf u*my@bc9?w&#aF+JHZ!b-$lBbՑBZoUC&$(6[,+ }qJde\k/.ËڣjNKPE9eTaSBOb6śW4"K+I# ’/@j6s.⨸`63p[w8fG4 J$l<ΨĨNO5KVh3 jmbXjh-鉓)U پ5Gԗ e]ia5GA@-DA4aR)PO0U6Wj5$k|sw>*sy:@ܴUp < SaG_r @2Zh.E(ݍیRD3d HɑIԱ8BrdJ#pC>Ulr#3nj؆ʌkD@"Bd#? 4:JаsLdG-9135 U~J,p*r)p4&a2dnQ\\/CXiۑ@*ϫ-3>txp7h􆦀[msߜ/twۍAOz=1gvV񘕇}Oz8o_7/~ԟKn}{>O>TS~ŋ>á?uO̢v }?v9?#g>+6Jͽ4lRcEnS&f U+\3Bh$ l؛%b1 ¸Yv ƪ,SIX_P-sBE|I*G5rYgBey|S K=%=wb)G:Qyk1W=,$ǧԷ92 YqlHZ2nPLnVS*y7 kTG <9 eWr%jWͶQlݓxAQŬtDzZt7Գ5ZLtZL\ ZGPXq_#f<0RucEtbAY>xo?`qOiW|A+"$?t"a11Hdk͆cr:J Ȭds3R#,IVj*7=5~ Q=kS/އ6/UXUq]y41^MIˌW5y#1^EQ̬*!!$Ɇ9LIED"j6Q]y5Df\zF&tZ< AAA9b-*[B1ƚ"!1XJ{Q/@"Hz7MoDJ9d>Co7 -ڼ.~ҿn)??=u8͸zۇ73x{w[?lG56zI v:݈8tsO}?p_~'_G]8د_{ox<}oos_{N^ )oz #~碷w?V@ĿzK/}塈x;?e"KǹQOUF#Iu#R O kfb.R{Fc;PYh+|oYHT隊\%KI@SSZ~D)Ts d%4]c#X~ڋKG '/˩Qt%Pq8IF W)L񈼍UJdUdrq,;k|cӈbYYH6Fڸ&LRef|+ njb3;ܠX6S7^p V#v5s"O/DI!=ŀ DJl@YSP$=K%DFfJ޸\Ai N@0 ͦ3$bKbuGv]7WG~y!fn>p4玥Us} ]B9%:Jӂ] IHLT%jܘPx0l,eU\ʈ ZxL2өsCiy(2$%&`q#PʧA"h2Nw3j0>h%AF^ +A5Q1!KPU "{ee$ta|5ED%@ ԰c&2o~(9&$i;z lU ijC2>+3XR&Wݠί'MzgZc׋mn~zFl[Ne|?vpzK~?Ĉ%~FU[WV$&pk{kk(3wDb[@/9w:n;/<_I3)y;+ѤcEs (D,3?{oWU?3ksISR.XM=T@ OAH tSDPDibC7Joɽf~*΍OЧC9go+]$2f Pt 1 1ף1I_CK-dJXf=QRIun/$;,@si n]1UxTSU/VA3L&'BBUU W8JKŴʳ8Q+;n N4ݝ ~/X/{!Vs3A+ > w\u I7,]9rSRh4L?ifuBnd+Th{ bV2 4%璍F, UjTӲ7`IJDF5a@fh FyExAcKC# mqH䉜SMAJ@J9N6j&BaagyI2KM߭X5K$R> CefDvD p2I]|2i[E;7+|;1ꔣ# Y"fMp~  Fy! :vArz]1~+"!ɳp` 7a'~H9!GD!eŀOBi^N > 6`H1潰hCVH5HML'YsNWn$9@UdN\DNy@w"R6O35~ҟ[49Oc;D2'ĵ_2zE)C%#'GK줄dcq}ԴU@;,_LMЇ <$x22nS+`#:,I$.J&ߊO6NTS+2ѷÒ5$%G> a H~ 7p:roFI5|#S-ιU~#H KŢW: ԍFZ9c/bL6P#)ny/Lt9 ۛpБ93Y"RDV˅ 5h( XU۹T룺pLɡiJm;#s RTd߯ ˧<0KxS!P鮖8 B @z=F3̉ՈL%Z*:ll~c@q=V=ͱLq9V%+vpz 4q~""E)l; r(>T +B0ͫ/k @U*pXhX)IĜqxȑBGAaDH(WJNDXC@Q!0!Hy=(樌 @@#$yD>NZim9’$nt"3Djh1(pa}Bci92=C@}<r'q>}Lo_IZyICPҁ<#7izywvh“ۿ̦ &<O`zFK%Zwp,9]Pj(MlkYJٸ RPK՟hAY#+03VV* _I XfpoqDD`"HN,T\3@0dߤRPJgpzPR* Or-5u5Ɛy[ȗ*FlNY4Μ|j yV$8ٓT})%@c^lQ]OiRa.VrOŁ,ֻzMjQ5E0w|=WA6V("Ξh)S̪Q8 gER}.@)1ը͝fh`V9:-s N:Xf* buN_t1ڶey',eKVD#,$t{),/ӕ%L(Q5cP.CE,&v\E/绗H#-իzb|. m:"wNW\01%y\#VqdGN9pPS$i@ m+#JR1t s>|CkKȭunvm!؝cIY^ˀX۶m@D]seDH d3n[ #+Jm'ure'Ol=uG/A?KIOs{DgoٕTV?#&<lc3)BMżh )ѰP2&AdIHyh2{XY]ԪaʝIDUHhluю1h j@]XabEi$~Rnj9 CCd4!ʨ1R9 "# R$[@XܹV+QAxbE9Zum۾0#""G@ϙjs"=O])9I;:(urח8R*dKtKk"5C"fX] NMCy=F0l&/w9A X~ +s:|"d,::2+kV2:gb-Q538FB尉lZNq+H"3^Rd`ж,.{f|Evg]'TT̿/ : ) `IE$:Ud9<\S&+^3N phL沥.1_U1&`u` IDATp RP$&M+T̶L (STQN̹LVt$$Op) 'c mAsV:`'12ѳ?kddXD}чzxt٨L}K2E<]^dCG+VKE%5 ex1eHPb2zqNyjcMݚm1[]|@'-^I5Q''`2{2Io]," ./!:vE7ffl| #Ax|| ";=d^G6^۶<@,ж-,i9G=~o{LD{vIA' ́u;N`Z-%).RvHLS#p!xG& ~>vEB`,_ :/9Wyrm-K@p@"T nI9@bۉdGүSPzĢJ:$u!H~͗Mҏf%#n2XV;"y&%ΥUDFT@ȹhJ% k4ςsP!CtNE!B2h"u5c5{wrtm(uI!^Y~ d"p"udA # a rL 4Ggq%\ۄ3D̳ S+L+5AUmQ7I,#/Ɇsi휥R8+%(P[)PnsyvLBL6)QR6@OOž,vI~B &(FEӵD6s#xYiM+U`3'3#au,[U0"8H$[1YhoZqDY?$KM1HDb)ٛ8Q׎]Qh=R_"2'2`ҧDe wX9ֺ'r` !D%DcnR4ToPU sb#&HR50I hzb ҾEk͘-z qp3QYpmK֚1+%y'o ݷ޴Y9:wwי ~俭7GG aYF"-x.!=Mo)܋xxYRȄ$b Df6ɍb)f yղVH$LUxһbL]<' %MQU&$255IAEJofZeXD>4Y)E .u{uX_D|3LN IX&0i96fZ,ӌ0[LqT~>]JcZyUBZrݪA*c&D"t1&oQuGhvD< O!rv gBWRN2.mf,9$B! ܥ8^^$! -bOjI?gmቓ\{o_yՕۖGsAS\)h0Jv EYa$uswh&m۶m th&^4>ËH)Yvr&mr:M_Ԙ%v\ZhE Dk:_2&EgᜓU *ÊAK)@ mTHXMu_-biKR"ZGǣ/&viĠ[4N6Ѽ0 %fnIE;&} o?-M4MDma5UF&rb5$R+\h 2Ӂ98"Xy̡CY=CX.-D Ja$ј`dhH#sbzzMpP9 PEg1nNI'l2m670IJX CmIQ\"TA`6UQf+n϶Br Δ ΄Y6"QwtZ&kN&q\Gq[iՅD,r$<B۔',Q9)!!PL_ Q1!>0Īz%; $jI6Ne^&{Szn'‚oZG"6V  0ʓ;8Fxis" BGyw2LN :@t聜okQжmBc]%"&G8MfQ-V{"m{!DriKuVﵞB+"І n׫Y%$IUȲ߶ ㆁ[xj: h[8z=ybXD_=9g^E8Q\m5n&mr{[ViRCNf΅Aܳ}}vXo|vg]PCz #3-[H&0Qq+ǑJʜht?EѡUYDtG("Kw==_N?س(*Β:9`-6^mGW?Qsc=01IvG~5V]7c|2=)l5VykЊl>eϺ" :+8iiϙ9[$`^_ XR&c$ҕRfhs.brFL )?ɂ+LNBz1:V]omjNd Jp KC-Ǎ; iS|$v8'rXT^Pbbf%]xQD-9(-;z>3KJi=$ffl"r|Cb~e-''楈ƅChe,/r&t@ ^WeRz)8Ch9v Lk9!j,ABH[+#ش>zB}fbδ!Rur! ),=CMm[aq `*,>f"HB2fy!06轊2BzB ! 0{^,Dsƻn3ePIddɰ! n G{}/e`hv:9D/D<00ajR3;2;<\'0[yt?6ގ-덎ߺ'amrqP [rѢgMDX\+#qƁ#"ɑsnp޾0݋y(Hx?޲8-N}7t5n9ᲫuWen|~zŅ| : B5"  9$24Uå_WO|rvpW?x9GfXA]pO?c75eOm?8!9]k鹇qҝ}??\wl?g]޽w'ܱdKKy96->ڲ<_9=nNivKn?-~"_~݃g} pFS:ֽ(@ F-i퟈䯞{Wr~qީl5*|Ϲ]{Օ?>7n̉6ss/n7B].83FW|1/'k00s&ːBٽ} t7ݐ1QĽ_cOnֈCyI0v]_[|pͮS/+;r?^xW.#w$ķ?=n;\;?KGz}[]|x终 !nyȗ_Й~e17;_>o`ͩ7}w!)mnbI ȀeP(΄z2@r, R\)ڝKP!s9 #}YJtPrs#BE?OQw )>3~ #j5<: ("tB#DB(Hz@}RIrҟjϬ :yt]蘈 CjEr!=* LQu#DUGD9l<5;5ȡĝ@4MΡ.9sj8:Uk\bS&oxNXegu.'2z!{zџFx~ӷޖCGD$.Dq9\f)i)wܴpxY(9v>MSxxїFV;Uo~`/n}~ ?>|вUj#GYd'-/[|;=q#-yԹQ,SV;gU9k .u~o;K1g#ukϚdҬ/A؍09j7-&zT;M#ngt IMg69ͽb_{fǃN[nyOpBHKFv>MG9e;:]t㯹[dN:ywμ+N${{|ht/ο;}w/냡ABjǹ\,Eb|@'`nmF%X1cv.<R1c6 pIWM%LOr iA)6!"+1YX(33mPe"'2`^<-H ǦcaaOlX\tsB* s) dQO4göH,5஍Gk#Mͼ"2).Y*Ųbw$3ì{D3AbhĠ>yRg~O30fqh!޹Nf|||Cn]C DF~+mσ(=gF5B]ADf!"釠2|I;uBFF>KGyts!^!R;Gi˚ =Aþi80!:$V:NԢ$9=B @fq䚦߆~p%\: :[nWq'6Ou|z*c Nx6&mrܞfsAי!uUlg,no#aw\}Ɂs^ | mQ~s/37p{8&w.aM7^8 K ^ "\y_K 뮽Hݫ9v˗"tt⏙uyǒם^}KXO/֙Ao[tfoh;sҟ]g^on[|{m=g 8hwM_{\D\q]~sg}aW}Vsׯ7%?0jL7v} ;,Z{9مix_6[oKvK/*UOVER71n`U_Xj"A,,oDuf%(Zf6lf#&R Ma |Wʩ:#6-c?hv =PŽmFeT1?,/\:7,YOӶ凰C ՔtM44T15 j=@BG s^ IDAT''&ʕ6 f8>T&X_3RGU;m?ݺ(~; 9x?@B!JF@}8iVھhSt#XiG1~9tDp.EoGn]ڽ6B\ @ 6-lYM !  zmێ1 KnC"o{c^+59flʉIQ'3MnLm;x^͟: ._ Y~dN`) {,|dzlϘOnKв)k @z/"KJRe6v^N3 #WmAA#UeREK`LH6c9͌&s*L$VP+X(4 M#;Ϣ&=Ner5)I0_DH=lS~)E\@[byPܚd1J45xBGD(pA$kڭC4}6$8ůHJж(DP\e#R:jXuA#= Nn7iA@wK۬2Ʋ+)Wў t]#(?@Ь>}_ jXzQRd^rH.S_?D3E_bioU=46%!3g_SRNƉb썬O>Jι^3~s-6k~3i>?i z&|s>uȂk|K{۬2tуcPo?+zC -4geK]htAWtM5VC2=_pɟݶ,(q?I~{s޵*Wn;]su9#w7aȩkfmw?E rs?yl?{\8+mȹHs,/$" ϟҹXMl w{b /ڹt`0x]5Ke8׶ϹtUf}}!#vs)|~ҾmWskWϺrps6mm%:t!w-ksdu4z1!BuPXUENp"DE5'r`sr+^Ia@Hq}(Uq%bIEd7JlRy8po"5,(MP_&mr{[h‚^6Gl6g͆hڳyۇ#8z[֘mMyw~j-pc  Ȁ_?{c_1ku@Zm?7\8lqۢnZx~=[;jo?$!13bZ]O+N_wN$`#84ݦz?sF3l4c3fo8c+3 DI{v^3:W}s{ŷN?a{'nf 5:ϚSVy?qAģ?{/սiӟ_BNx53?~ԁ֘Wg s蜏}~咣^o]OCQϓrᖟ}8cΆ3n&6`cu.!X֢Ɇp^~ǡ'O;r7YiCqibG}4oY7+>y{v oω>+z^XiFfly''Htwӊ5w!U䴻a>aU Ҷw\B:[>6,HU#[%}OhUv:o'|`SqHQqQǝ+;َ c55yGd\!y;/ӈи0)~$BZZs9Bީ,)ząOJ zω CX8(6 mP ;u;ld2ub"-ѠI$0XMjoƃ^HEWx 66{ЦBڶmC:@$0cu9PL\qMȋ@ۆ~ @iH)fJ wnn3m\walFᑕL[ydxj3!8q}QGk\ǡ'D]iz)G9'Ju@$+ku9!! G"ݴm"D(A}$>eb91ZCՙ%GhA)L |b'VQ>qT>g_#].k`mr7]oMrs~}1'sܲ=j첋a$ĕ8|'.\;ja s󹧝pW_374M8"d|cje}?H+z'~*n/Ei_RBzQAHu^\}SO8qS~%cKg^w "U7nنW}-Wvi:;ݙ-v{a+w}=@ͯ]Y#w/ꌓ?vڏJ}žۼhwNJ`&*&w[]g̺s7J}۷yH>M 06;[+w=sG 53ݺڰa?`daڀEl#4gIa*1b&XfXK[V"r}ʎ%ѿץ#T")dA'iϢ5VZ(}})OQ 9R/!Ke9X$u3#Q+ @W)*֣0eץ^"hokEu)ŊS"a,7Bau8,®R U?r+y0N2KQri8J>d.Ƃ6yEȘ-IL09X&g|6H$?}frO~d"wRIȜH*o XGW q]UH%O+OcUnҒɐŃ88@,U#CYn9Q|L:/@ue 7D$=$@fEzff,bq%d2f43CvqxY5H͏c B,E?>{ n%fa! 4ޫjyu%SH3(gH,i^$`{ mD@1PFsGxE"{(!1B7M5Mɍz>ADC->-E19eӌ B jڵ,_,tw=?yr&mq M`rr,;ga ;Uh"ArcdJ#&k:dd2*.E!YĨJL&(^|e" |)3aDC}8Czg;(9@X ک9'*YIToJaPq/š؊g,MKI4@R>k_&4j4 -#9=H 0sJ9}.1DZ @}f.h/Q;X !@Ԗ9=ARU\H䗎!ZA0*QB/HH80jS T,";tO$NBv9\mmIPDNVH[mr&n91) ϛ5GTM@0Gi߆;,)@3ӘA+S[oKn-s@YEJIa5ZpBRd }՟#~eC 4opY@T 8rPPYmVZ@ hY$"!t(F g@,vמa.>!jPJ) bw -w*F3MXv5B#"&y'p -w&tQLZ7 m-f1;Dt>{*4[@92 KEKPIZIVUbE(P* f1U[SRRK1Cg@@ !^WKR9A$4B'0KÃD>>y>TQJPMy DWC8`g)!g10UXb1Y3bϪ2,MY "$^2G}bS0V a.B(NFY!TSfCFąM:Ɖd[6D@ތ=dҶ^;;!¢N,ʯAi5T $F{=i|$1z :ݮsu/;PL%ƂCH$!:PV'"{j CO|<D2dۤsr&덉XX3pJř:#Wtk_6^`DABZ,j[F#H_!ʂ2|K8Ϗ#V4Pj( i1MD3h S HR^Z:B+ғG&GLtN(bJ+ ”N*!(Ym(f2䜔:E ]&QFn_6DYTlJiF|Ƭhhug.9|R 8^lCD0O^bY[+y#Aذ']jTr]LQ *SP(fQv1JZ%0_E%38_jkMGZ0Iu*AO('`UdIN()|&' IDAT,Ba&$EaN6FX*jy[ aYQc\]z^%U $9BR[6N_$_#Hu\>,I ?18#+e_MWM5ٳbbVcp)9<)$Ӭ3=1`jGcTY Jjs5M@3u۶mC۶HsqLC{<G ܀ )2霧D?DsqwS4ȔAѓwe !pXd}|6D_$N.Od‹AB !!˓j5Ms)ǘYZ-F$ߴ[5u6Mndd4Rx9Iu,0%+b4/;}N]jj1XT3&hR=S60 OUHr}c\kބ&_LXo@!!QwG( rdW_:2ѢY% H$%b毦9J[8fDcL{.,DfSL庠Hkz,IomSǔ{`|KI.Y`i ƜZSWi]ɇҔ'\XHdW3sV$+R&tS(3eS\rdoIdn~MFI[F GB6*(%w6 4qѠKєGA!MS {;18I9ErpJD!=2% PB扠,Y/3^ icd綌@:qEy0`>!k멭Ϸ>ʗ:O^kTt u&eq`XlZb,}f&D"HԪXEh4mX$@ 6W9"fwO yN>FD2XLHB6} r MEgT Eәo!Y\@F"{nWU;Ƙs}NURUwA:X(!C""HA*-! %Brk9c9'>~E ^{1ƯK iR ~"Yy- Yc>YUgRnU]pq"+Ze.[-!]򯮮5zdG3U|ZaTKysȮ ̣< , 6 $"| SZ詫޺%•*X T>0 `iӒjZ(GmRC"3bGN#Di܉y ]L@Ys0#V|G~I-ZupF4gEf<':@ )YB(6 Pg#8MFo{sER\nRu`^~al}[ɼ(G"z*gke#OM"D#v`+CSX+!ShW™̬Pa1P,* R9_yom@,\z!]]]CWư9sM wÖ]2Ǐv.f1l-/*$f҆$Oiz'f)sQODtd#G|c>aK_y.vm#j->5dn>F?u#Ϟp~Wԏqy|fs^?Gٳq^:g^p>go0w~Mn}qy{go-.$`DIpڐ`Ŀ?~V;lxcw(҇tCFjW%^#{W?_80Q2?gf=ٸǒ"ԀdL\ˆ:k )0Tj_;k[tE;_=HNř_)f,ȸ_7{-ճ{5qJ%e-t`FnH)p'7MɠUrOkL8Pаr9fÇ-_]7}cu‰f,H.Rfdczkj2Ԏ,R;gw>5Õ\XRSUkmDf9 g?n-F[ʳ3I %5axYNok,]8S&䍥lh?^[\S zԃ`ެQ[ӄ0Q9dRTHYEg]IYs+?Gq̐KwCgDCFdjs4t^:}:q'J`to\,k=fr@gP8i|$?QDUNڙh|뵂|BEh4x ^MvXQ6ЗDרT5 rٱ)5zSԨ6GD R,1h06 =tF ޳]V^W{{{cBD1XRjCk3d7dZLĕk !h,"V``=#ЌVvYЁL|k@'7nkV)1}7/b\kpKAP4WR-|t{!Z  i:CzzcvzïZ]L1;H)b4lp3*ZAhdg`ƺ0 "Y"Fcn]}N<_>vf\5y^YUA2jelno~3 imr =cvsËx':xz;^v#v`)|x.v{L|x;MN?~}1ګ#¨[Oyg¨O:9KҫOZפG^GͷrYklN]2O#ϗM G{?X7t5%lC ?^]SvSlkfґ;Q24x}!+%Sa*z1&Rk,41T !IJ#):"8gmQH NKLhDNQ3f&duF4$5 U`(7Qi j]cj[+#M39; k>ǁSHƂף9^痬&\oY]yj\P!̞%RC*wmCDD|@}BBK`( 9" 9bRtO;\pN;^<|_ zïn|4wdt/؃s^1f_w7^c_( vhKHP/p!R땣礉N规sO/D/ /z~z{/ww})K&N*.1V$!Ql5wFt!21:+%=k2[+srA_-gYpN;HO){HֈWgq236 vC4++|Y c5̾*Eotf(ԾY;=$BhXݏc,2{&Bs}UB &j0d*]߷l,p5k1taCW_{!k:뭳z묳ZkfwWAEv *o=h4aWU}j,[eK,[׷dzolYO*Ǿ Tk ]w߮ [\{_^?e;\K5T~x]?zg>؟'LݣxIk0'(n*NN -Wp~S29Yϛgv윰C0!ZLn}G<{r1y{]O=̓\r{{{VX޳by_oOꯪVUvgE_w:>ff#+aXoD8lwzO/bq~_S#ÿ__;3OO)m!;|/ >iN;9)w7y?9l^w|潳^q^uO{㔳~=kaW/zor=?=_z꺍Fa c " 0@P&QW@pIDswFD:<Κ?)!DcҴo@B0 ZPaT2@(BJZЕUl3;MQs:;̷n3O=4hiw;t8>uC_9! | J8F ! TJ,@6\;{s8$od4 C]FWWhv]]fwwl4}AVh~0$|A,@Ek;Bvc,`C%0 p*;}t7T=^1sz",{3>x[Pq37 ~Շ9oI0en:|Cr=E[:ơïA D8d-;ޚ{Ð3<_%psܴc!\]Η/9䳗|lͣzWs^(W&]Eu|m [g-P2s&n̸M^?[&=G9y! 1U!u..#v5^S u2/ !RĔ)4FIF9o~7ͷ|?RtACgu#,ú7RfHۡ\6[77 vlN>)Wtܿ}5tӅqY?ǍmGrrzoz'mYO|?5zC>rt.{榡ï3_˿\GsvP;t#{dCן!re bl}yXrKÍ7NG|{}V9ĩ'I:Me@&Q0^bEol:$bZJq 9v. D1 upmoGXQ"[}u:>Q+"&][e(hne3+L§"ɜ0:NjU Aa 1]}NDDZkmaKP^s H .k YƔe3"/cuLfmTYsmq`PmDރWz zOJf/SZk a^=qB  21 y绚@M`JMz}L޹[aԸ6*_5؅5{2L8SoE\5EM8SzI_<}wC#kpUL=R^s8z(#q{hq-^x| /=cNX1siqÉLf4 Mc[m' L60QRH#RAdN9._p/u]+3O֗!㮻KcK 3YK#4Nf/d~#D'^}//Sc8hJ M9bn/pѠ IDAT=/xR@fOC&qF4hA{ל7iekiT؉u] .Y{(.ШSeSgӍ\I'j6Qeﳦs"ɈP@k1CD?]=X>O7 _~C2!c+K"!Z40)ΟWzJ7LtgCr]'GHm9JMCA $e.$ʐ,+g_ WT/^sބvy8R`uØAjOe,,m/fdoni 07b9&21Ltď>8B# Zhq筻L?G_άN;5 ?V0gŐs΁g~~<~ٮ.G~/? ]f:id%hKm3Ιt%j Zt>N KĈ-<܉'LsC Y+ĨPA]DFj l2v S1S"l3p O-^MJ}ͥn592 qJ,9&KnŪ`h& Δܜìu(3{b5 J ۙ,c&,O2LA˝Ԟ,*m4 Bd\`f$DUY2Z4^гW9LL+/T^Fž]yoE@RUeeUMr{y$",@Cgvi[XcιkLaX"\\Br@<"K*0mkMQ@kz&~8@3v۽j]U~yp 5o,k|hhㄷm[kE=aI9)S|Ep zX|BҞ"3GD/p{ѨV0 5?u:|=! q)e}%C1jWc3Q"J~oo|L=\˞y[_=Tne~o3𬛮^zI)MݤfW7,*y< 5 jnk6iA|4]p~ʉz࢒7B/:岮.}[XS"k -*y.|Y(Lsc._jJP:n֢/:1)[1G>Mpy%f=u5 Ooh/"Px CqC{yvU%7diY+ǃXޯ%_km=Ɣv%I@C EDda+]N=m}}vonAH!BMj 7cn-jW?yRb"tcz!"8HKK(FJ!KHJ12it` S,CHl^xfRۇ@pvo-/ePμy-Q-6y' "ko~#6]{@<83wFZzi'_|szrGNX+kõ4E%oXs~/뽾\֚𭳎[oRv Zn 5Eq6pQ:$jÆrAg7djբ릜xO#R!Hֽ22C+."6zpQ`doЙNz8!Iʸ`++P{ÈH-4Tno fVE"( (\gR'fK#mCB5bU;PF6@b΋& Vgo51J=; H֚),!"Sg!260Q}uDX uRP,\nWU\R1T/ф!.[ABzJl6ȘVlWjh Qa޳"F_^2"bt(ʲ_rh68^9,Z_B&\E/姆wџJofG?:DlVɐ̫Y\qZKl xC~mytktЍb6R!ȩ煇.!Dz>֌Z\!^R^8w&RC( /?va|Suݷ.e[mG/\B'm6lO|YbO,EdqG63|׸7}L; 0fOUњ[ݻNS3_V3⳽V{`ObOڣ]|x_Ha_L2m0Ƭ^Xgo7Xf"O{k `$dCȁ,j^=Xl8JC//E]lj$"{}ԍWoaEjۺ9=wPbfRelҁ"{mPgCn u6}8}pGV9l""CzC I5gjo,#5EG `c D\؆]2m.VCCmK{ӰcIBf0'om3O, })<`~ۿ}Ew즯}~qϯo_k:R!mf5M=;;ptp7,\<񖲗{L6BI([{h+ncA6A?8@\}]%(NmPASI`z&DX{=/,b_~j4 (!-ZHD5U#%FVFSGEjN\Κ,Z^s^@ Q汾sW2:p_tL"cbfW7 :fAk3Kh;}(^2P c'fC: "@cJ-[*_+.[Q9&ctUl-]֒7^[kKۭ#:[UjVveۻ/l؆eDrJf[c LVk}t=e]-->O\kp+׊V={ o1 ިc.^q*:еPas|j_oM;C]k'9-l{)6ߚ]^54sg'ݳh5_͘[TZ(V#%JrY[4fצcd7jMƌdMF*DUeվywŅ;o^םnmmoF]{Sx.飻 ct6Zc['|+2z.ߚ]['|2v$!7};'S~lHcv|c8jFpO|wƾwkkU:"Z2?G/]NrιʻC{BNgqΫTH-`0sλ;YDl} W+,Jg:lapڸI_N`Y/̛f9J",@##@CYhugZ(˦~n5 Ys^4lQKH/̝`S =Q_RIAj}y`vYe٪;p1ؽgO4J% >0W++gf?s K I@2,$@DS9!*/K&6bXc&Ohv~n~vٮҳcv"N !#xT0q,ُ3ׁEO ¼ N28B6 |E9\uȼܢ@}ⅹOjX.XCtQta ) X1x'v-cfE-Y\cã_gfi5VQ7C⛧mI6cGm1v-n٘7q'K>6v!`Nߚ]`KzslKEWze򒏍AdFWӉwH\O̟T}Ե0ŭ׌|ѳ_qGވSb>`N_S8m7'p1GCeEx V_`Qj)"Ad? R 7=4儫6~m׌bѳ3E/A4GZ7=?9G_탷? Ə)'^}g1lgo~ _yhW}m׎|ѳ_yŏ |&|֫GzC㯾Ö/zv敧^CQdf[ Ȣ㯜ya_}|#_4l:vki <Ħ,c0 !ȅ}b5vv]ZFPrO/X_{tQ4 7"+Ƞ0dkJ<;c/`3ھ?C/ 67֛3a   4dR|L{Y/~x?G 7O+aHkadzP#ºA(|^]- 5@(T%̀[ oW1P˓:+0h5="{y//i#0oκєZ1Y- 8|`7̟;6tT؇]DG~/ᔍ^3?p]X='zԋ۴p=o "/vW7ۮzNℍγ-Pqv.r?vI.YQ<#_9U*{坋nOu>WڵZlַkN,HFĚ}T5[1ţ#D$cRO |bG Cd~YAgt8ikϸ"Щ:hɁa:U o*03xdRW_Z.gel"J>>֒E$c`9 ڴ[cBEo^."HTryf"FQAEQ٪*]RǬ c1 4V BhffFՅ{@CXKUY!Ц }Ǎ-,4\oNMl쬿m)!dڧ@ܹrSW*3f ۥ#*@DtNH/ #6+v@'S-JL,I)62 I#םYM%qbRʁ?#htqzڤ6fbCYK*Z;*B$CIf(㮒:` S[?uSGe[`NXLx]Wvԝ/ 83spd"&6`2ڽ7 DPC6//`\%ҴyK"Jא_ Q^w%[~e]RO'LeDQqi_26W%,}ͽƞj+1A3^!!0{ ٕ$DQ^e[}yOr/,~ '3FcoklܷEF{m>q˽%|Bf(3hj3T.jVCtRidaiH[=ې. xk$^]T?mr-eQ^{-nw#Y?% :s>k_|Nxʔb0{oR8,2h.(ȅˁөΉ][™1n$\P 8yPIpl;HPf1lj]`l={~9 ><,.9jV•"8Od3Y Ǟ2>X)ƃ{ a84ֆ nK@ΗUېcmϺZ b2`Pg'!Kd+7{ԣ z/,䜋! WlaՇ5lQ[.Z}eY=:':Y0Oe!+=0A YšԩJ;ҺAR-!է +URɑ؜c;ƱJQg 1MH)CMHBT! &Ɔ꫶ qmbjZm N%TƤ>(ljBtc&12n| Sӏ&QH,mn;{ߛ.3a5F(c8yL296\N=g;?gN5o XH*y?ี}('sdz*W.iz52V`xXrx=q\WF'᭧6z K'.4u[ 0xB '| +$kkdH9%<FOx 0c[|!v c3 I  ɦ'M8h2s+ ~Ǧp P;,f@>}qͱq e͘91@d0<5 {f( `@‚`0R1x{1(:(=Q<A:)*=ʉGMMRZ-6|%{ uB"K BĬb"^M@{| ^֤b%X!Y2FPss~5k<\kp wX,>M}m!O?}9tBjKRaXSze/)  PH%v~"z5CD;qthjBRQځ%:D-9À!de n5ђ$ aVԸk1}d `u4@@ UYTal mj(#CuK2J 0p;?N!_Ǩ-g@ϧYf@m|T9jy9cP:ἴtATfX'|wG֚KJ4\!"L}Mm8xBF&|`? Ct#*vĢ5:|GO%g]A,_Q9( IDATĂA٧AP!g@f;@o b72037` F3*1i DU |?DDݵ|Eq7s0)H 4aDU%9;~(L#@j :z%}D_gc$6ٹa 2!c-6ԡ80ꀐE@C1l3h%d53v[H'>6`bH5IH'z٭:h#tD8~ Y*%AV!RsMOJD'񎙫;,WBV x#Hh B # /+A!+#,"f]wĢ(Bo !Z-~IlhdtYc,>G<3BDDC!@a`<{'ٗUltcL,3faU*Dj4!"6d1v˩¼]LaOV5oj ~NA2_T80T%"CO%;_R1DP'L'6Q|$cB' ̡jD:(Y !km`5؉ ',d(o,E# el$8NQ7; UFbJ}4$; U LRҲc+ iTh:&a 䴈I>[؉Pruh v0kLŕx(I'i/nP[xw8!wLmf8)5r.ЙcҥsdmaQQy39 w6IkL XM}i,(uf%`mKGd^C 9U Bcx im%!3]LXeÍDzR-MRzIxCRX0;%HeNb2@~t̬6:S4AVL8ۮz%zZ[+8KF @omh({WeUUNZ#))B [F2@5BCfw}5 P2CH%*+DEQ4t~v ";BVXB2 efDٴ@3m ~r +7h_Ypp Bu}z]cPGV 0K%Jho9W/h6#D?0t@%e0Ü3RjR\#Jb̩P EdhWQwŘ|X$#sf#DPM03jR*f!Ƙ43ٓhge Όʰw}MNBXG[Α1OQ M0jҨIbhk줞E V $KB]3'^+JKǬ!Ÿ,Ǥգ0e1!2gaX5.-.Zst15 $I%azК`.P[El)E)bƫ d4I9!pŋ3̓Ii@0(or؇XTiZ:@@8Cۖ\%kCfL:t9B=kK]HH*xo''zHڢ(FLbrplxtrb6[Gfڐpfԕ9;5::xM4\ `v2LŚ3qͬ3Gx0fn6g2{-GUJE5:էx窲ԿԿǹ`a-զPî 1d^;;.U<1fkȐ0D f6(ܪ<{W!mhg*&4wΕtw7 kPo7חhoƼ83\+LsldA3ൾ~ve)klkBTO8>jAbLasE^KU;aH=$s>6VH9 C1XXcʼnhPjŔ#w:o;r&dzHpo#Wkl6fl& Em4_g%e(ø8~4!R-\CIꌵOo yDĻm&;$@ȢϾ}3%Elx9m1jԼ*1k S?vF<M!̟A$6XgOX[P %J^@*eD"C CJ92=j| ^U8FhLK"HXO$ zZ$bǫ jHù"fg*QWo:RAqCYk&5MW4I0c$"h"wP=A` 뽗(Nfd(:͢gVWdgWD2K@xrErMg/&63yhd\,2 7tu>x_&H2r"X$!+[JL 3MՃynla1ƏJ*Cj޳g_U^l F,2@(c]D(f&eǹa-Ɛ!C,ap1,1 ^kMk tẄwc2 ,/3ƪo_o__? 7CWjR׻69$zX3h+C(6UQW沾K][lv-1Ϥ|ו;A\n#3+ EDŽ$!c<\D ̋uQyAʤNV (J.0`"p(MThV %sXH]dUw PB-1EpTbu''8s-Zu5 _kФRbY#42-gg=#$%EK䒤y"Йf]yV/ZK)):ѩ&X%{7g;%ÎF@ƽXhd&ghP\1^Ba25Q%qTQ! !pFiEfnJy$K P.MLX魡.xڇX{G,/U |fB$&#FE1gJ\஛@N/&EAJj}@d@{:D@w}VbWb 7F&ѪvUUkϹdDQJc% 8vEФ C( HBH "$T^hJH={cB̼>!{)c PXcekCw$rKQzurr[A8}6?jA%7RO2'kKA m{ fulSKYc;>X)vP% qj HJY&wKL"IthTY('10"AIJ9Ɓ0RLJ+Z(34cageШ NRH$"`r#x @DeQZFeEaD$PH 5,]m4ڝ=*)uPTJSoXٲ*znV"|˲`шJhFUo4FS mr6-޽OdN{WEg5U;;ӯw=M(f+DX hrv飏gֽ֭\q۬iS{"Au^W]o2WD"~k] :ћv p!^ulɂv=ḖvŴ[=E(SF]~cxOξp[,NY[Hv飏{ǭ{r-O< iN_֛¼.z[ZO-Zc81K݁l:f"RD_Ź7Kg ٤č`d\oBKL*R%€R3[ ߘP#<\ek0ΎN&Yŗq7x!9>Du`Ju "9_g[׆끧ywܺ׺WV6kڤُ5o%XFOnWr2@8-!011y@.W$U <&EI-W֯%rʪ ΢p3H)<nP. B]:it4,?z?@(؎Nr!y@Cतw85t(kȨ׊0DdZQ@6ƸÊdloc}vȂOn*I!@ڍEzLIalH kBA!A`jSKiII᭴ZN]-gF'jHɼY% (%mu~/]A E)E=tQ^+ˢ9-[YG&!f!"ʽTafdDD%UD 6A0"`%I (*oVlը:.74m%^G4ḛPD]. s0ش|=M8"(aNrjl"Sp6yBG|p- ;w/>縇W8QH@D?qvw{mf\}w$"1zO_{O{-waǍ;wޑY]M4`̲|ѳV|Vz+jRWrC# uKp0A3y!f)) "QMMJQlRG"(MЄXqӛu-X@^{ebH N80{-\SK  ؾՈ[><⧳.|lRD:$!g#W"E"AɋG"#)R[F.KjeiЉ2Y!pe!iIDbmr`>08xĭSNoa$aoI->Sŝf!MT XP.W&569QHCY RP6᭡"LR0ڈ-96{6,ggIAnT:i@n9`L9D-Q?5#h})]9OxZzJSl6S(5i@]e#}s?wCB 0e(F{ŅOqəZR01=`nu2 G߱k׽'C|3GsCiszBB)o|ӿöh$_~vآŲXfLkLe,;[z ߧMXn4LQcGSK[`ecŇYDLHTc 2r(2Ue1URWJ)Xf30"_82Xֻ; %b(M@!8{ 3Xa'TTT!H,~r [`ְqӺ6<3`] b>Y+2} B V"P$)Қ&Hi RP,ȂVвX#bD*+se1̎ !@)-7R/ʍւPPPEYBi#ɛhZRkimimkimmie"=9nҺ(jZKYZ8ߜnJi"㵄k! ` BSb%6RF ({Z[k(Zjek[jZFG{{gGj V Jzwsg6T5i([)4Qo߰qkujo^i:+1L,~+=n@->1Zf^, zk^kRYh"]H5/7kI"r\oleu4(,ʒHuc -cMeVkELZ?#oo=ݣ{HC/pd)?8%+۶ʍC_]b#'^ug> Rkl='yi IDATa-[].^_re ȟ3&xHy=Ck.q{L|3⭶^z\$G ɇpMBy+/TSIu`-Zӿ[D~˙Guκ+-<ꂓs_~m|s~ {E#;N9ȹKҲvF@Cҫz?g |{y򏿹y´_jd 0dgt? K<㐏1  #qG3/]bDbvzbԆIm}?={ h^3?|c}D\|ȎqģK_ibF[w|㥷p']:w?v9S>~_xacg\?s;u̕޾N\G[y,ciD/܊[mwSש-8הz2o|/'o6r} =Qˡ,Kwl;t: VwVQLYxϾݪ#&4Usٿy=?aj1KuΥWa\^{]r+C*\ DhE;Z@whRg'uѭ7W (լ8U"ץV`*Y@LqDt7Ueiw f n%h['tbQRhIPB@8!$w 9sSDuZDfEÜ;v^&QD"@點%.Cp0cKbrqaIf\cL &q6<]@Ę攼=@!^fm e9,5>{B0xKCZcŰRAU5-Y@3@lmZ!EgB@ akT+j֣5 >dщ~x)ZJkRʉέeW7FVA#) I,k:;=\:Co^c0ch_!CqժU݋=GٳgG("7[p?q,GP@`/|{蠇7Uv]0yf~iҭ'Vܶ;,aҕc9TҧwSװi-0@dѼg`_8} ??dlN0"Qە&AOS^"A)LKXSe/~4񸩀Œy 'Xx?twf|׮XVxeKnqzxso_kM{ mmG/]4pǬΚpdr'vE3ϻjor?;mӿx"{ɂy; X!I3lCw Jv%.jTp@-}>~;n/ӒI8 /+殻7ozeM./_{ӉGywމQ "+ktTjl7pO_e TK%^. ¯}fe[uşr+H lCw>:p(("]KiΟ7>/ tCYTG<|O~sقyk -Y8p+8&T.Cv7>t_{кh~w9 _ݲPȀXT}_K7Q(:"[3oY.Ox ݥ설9B dD7+lʷv<:3&  paSX}G6ڨa*р͝Jwc+Z:OHwSឧ63{"BdP'ޤHh [dۜ wq|`C)Mf$ 2D l>μr.wq dcZ%w0ȳM.|ZИ?) kdMQ1!/D%"p7KntJRH Ljc1eg\B+)Έ$$T̖56uZjZ"bi&B`5MH &nBYj5 T-[k,[v"ҥBD˶X PH uQkal4fXf@,օ&l|YOT8#\TN$$PShܯ/#*{F;GYHٞ5e=zmpHhֶ P5XA}zXi'G[+čZQ +Gr2?@L-aGcl+\nlO0hu3IB@M1Lb0&6e&aDV5xkM/6CRTnÍB_7N;nmimiq'_^끟}߼zG>yyİtuUuEfUmQ/tڳGMQunVDk+>_i՗b'?~UI!bg%;!MPoT\%9g!zn>r8G*L3RJWs)ӿvV_9iw>QN ZFR-Js'V̮ A Tlu8reΥ[c*q֋cttv?W?x?e;uEv@pŶm-ϷNCTT7V (xcM8@D@\ݺc^ͩg!{>A RY(FcbNWt"Ix/M!QI9<N([gI'$MY %aPr.M8cz1xg,W'K!D`g9"j'eF{eAiw{%ᰛ<1%In% mb iNLVH$b`fnuQ,~;q-moOc~ʽeOx/ur~Sw \W6z=-EP঵G =ݍkn_#;K\i Tg񡩙H e*.c=?<ƺ*.wN{ 4!b]CcwԸ־_so{Δjs]qݏ,~cٜ ?H]>-?x_a74Vqފ)T OoORY̮;,l7Q<>JQJJWPvɞ#+@hPK垅 ?a#;=q΍kۏvּݕ|n\}kӗ&=0辗lTO=">e)E p>{/S(c/};9W:\fg^vUz)`NF pt웰?!!6U j]4M>@* k02J]RUb y*t[.B3__;)qUDq;frI:lu懌'Z>{ @m9cX6xĻɿ5%4|{ïG̒yOCwjBҚ8Lpᓮ_˛/I LEo8_|Lfq"Qt47n{/c=d͖Mh;OZ\>k.;.r7tDOw/~񵎶>qWeE&^Ʈs9n̉!KwrsRk͙NzjnJ|eA6ʭsvc*q5KfO=޸|mG~Q;~?򫗦;po8MSg$+Pl8= O%9|bLs^r9G[[ѡ9lO6"ń vlAwnE4_}i_e+>-3fߩ;p5;gA_[.mSRZDwo[cnqa9`-Ak)Jk |\v3˒ASr)Ax4!bE!Z6ã&K9)ӳ^%Q'X6))`T@VzotS""Zil"Xr M"lcTl_Cbm2e7T7! =<=3j>Ɠabtk9!BfkTDxp. !t9uFR*HNΦrgQZvй:a`rGsJ`3tf0#7\Zkw=S7DD<=[[\hR2a"ƚTu$EAY^ĖmQʲZ+2D* AO04KR]hٝB bkDUQ HJ*˲zWTUE–-BǴF7Q4n)ZV+JBAaJkKAbb-c|b7T )9Z Ahyz&/b &sܥ+ϼ˷}w/v6$}ϼ_3.y۳vwrw=ނK~9!n7r/qKwwQob|Ą/Yzs_tN fnUrqS2,M1>. s F/{͵3OArl#)"= ՝>"ХWkzeyӷl^r⤇_~~i5~n=M\;r~u"0;h):o֎<|fQT?8vמɵW?tαfnUoIs_CR/}Ƅ5y;~| opϻ7 +hԑ j[Y2 ߽sڪW9 "`Cܢy}tᷞ=ZYaKJ~Og]8cO{!vCvAg/>r qïP۪O]5} gCc-!֯Ν4j?qzw/ozQg~un#p~H?zϵNyVx|/}d-Zi"}c|EH9DyB1C ֲӆr9 :+uA}XM{a)I7,giC-$HHMOɁ@[P*Rv pr$#iD0-zC1x@D"lSMx9'HbfNnHi,"!P2²sz8 D~X sҪ"ʕ[eF8 # ? 9ߝ(}O^8Q`xpO/cb1upMɌLNX!~4\R0;Z;cftTV,HV+J]XcX5VFUyYX$(40$ԪA)cX0el+ @@`r`23 Xz @ROpnѨwv"")lQ?l+fL]=LJ)9cz"jGAalXӀx ƢNe0I;oӫQ=:߶|omZqu)6FmA7;;Vw=m?hhfy(Mlɶ; 9[D#$g)-!6gc.^\G f-iQW&.aJxֿͪ&6kXU~SĖy. _,2-#WecVC&릾#QGobTXc7x8r~e aL!:{:qV +1MO}uu (*cTr8&[`69|9%DZig`k(!/gn#Akad\1]`Kf2FD4 ֤6D(]1EReY)+@K8y em+I#P\?#'gDM t*8K ~S+%J. HwSV)FOdBų!M"DD_+G 6TbnMBSiTzh(o,)ĺhU1c/3U) j"4hUp&+H]V*H dOh$$%G;g^hkI*KM A+aڨ*[YkLjT=iC֥s10+Vh*Tq|oֺ,RH]2" "wwlV nPkmimk-uˢH95XRwnl0iJp;EIJ(ˢPJ*Қ݋\xئ+yO ̿v-w9w:g`P IzUJ Xx`޲͟U$E9b^۔-P0p pxm-2[`abLhWq%s`,1A" C6}M1*>"7XfN" K ZAK%] }>h\ %_Ge/Y4P,(}8 7b/3_=kD0C(JM$DIIA<%?룠[KH&1& 4_ o-gZ0+眕DOTV9mjXk\I= uɹ IDATᄇnH^܋9ޛ&ka'{-@@HCt\m]獐 A$@O[ >qJ)To`(2,d탠eE$D][%.vQP6)`2Г[n"{Ov $("DXḵ3CHl* (n:Y+yC.iܔ ղun>Q$@&\u5َZӃ2Vɰqclg}F-k-(匜k= k+$XW !`-[K,+AA%! J)҅Wpel+ b؊m@x}W[%ehF0X" nk+S20XzZZ,.W Җ%0eTT;=|mk:wnس{tÄ%xǥU|RcI$AR aAb7нqprh`T;~ 5ΰakLOj>PeW̥5`3*tP5NS"u}nZ\:Kܟ>,X=y+=G E[8q3@%lσzT_2 EM\N*11%2@"k}\24敌</anA.=ZfN:*9%BY8ocs~zFcL2*cߢrca]`T.@8u<ȓ!),˼1a5?LL@@O$OW9?`ptPJ&HA_4هX d9x#_. mf 'k|͇/yib.Or ?8^wGBM:M%>,Ls(<"$&g(n:XRb%O M9> "?QjvβNftZ&"C .J(|-bI PhI 8Dojz}tX;Ald[Mp2 Nd ;woL_ 0ӥ%ޕڕRp&vL>ÓK i RED$t^bY9d$'uABOZfJo?ZBPQH5eRBTJ"Ak2UU Lȅ-NʖamaeQ+"1(H֥f6M%u  ml"Ė# dC)t+Eg8.t,ZZ< GJ5la"U"E`έuKNV:^lgϼqomz6۞M~f=6(LS*[2/}q*z=Z!FW14'hf`S;Cj~K#Ldđ ХDL/I5cpn uID)ΉQykg!11FRZ#7Rg(zgz!uxn V;"!r{hjfŜ\A nx"&e aqXpΜeɟz&Ҷc1.5B3/عzVx2iǧNP( ֲ[JNP]$Ը٥=%#6Mp;l\\'a̦Mף M OM`9XmЭsCkyI )$B Ghvȳkƥ\;&2y5gҊюhKk|ޕRsCJkw@XXUe4ѨeOuF4 f.kEYRifp>f5ƚXGS`k=O$r-BDX_ݚʘ}Ύc U)k-ek \ѿ %$)ˢJBUՍ1geͤ(0X?ɊB+,gzԚ!Aǻ@7ݣ{tѓ$:k3ӉV1Oa[+/kC 8E{;!afuof(ERnVVWz Z+,F4!-@vkX++{&HR7.{#F#vY]U=Q\dG7\H}g/h؂xpI_*b )k `PU7IHNj\QdD}iX^ME2ƄQlZV&ȴ\.q09%/Nwĉ]p=~?8 P&Bbf CU{~m ȭ{9Aq"K?Ð]2]!IJYr͌ 제UѳT ъ)t!̜P0lt!Ht /ӕWTdHB:!+ɓw1tpo B_rrr6UoĨf^+bD,#料d4A GHqu.:3>78z0 \ݎdPy䜋xMzb6t ~cEPQJ7f-{C~gKJ)tDMl_"FMJ4}vT[)S=q*a̙4=fݤ&]ܤ+JFZ@eLG{i)JEž')J)]Iȶr`*SիT1ZݱD`ETJ5`T LDVikިZF5JJ/Izh"zJ+$Zk LrWTZ %,GķkGcVSݣ{tg^±Hrh2O㹏5GEga< 9&\n~WH)S +5[Zj,qb4$"u ȓCWխ~)6;ml#ܺ3kB,Td|WbW,62ݕ6PXst!GS$/&C}M~;.B@kIJ?]L[!0 !Yʜ)1/ŻB"<|nֲ7=9]`wņ}||"fߝu藯X.W@Ggk[QH$YX&rGWil =:R@n8.2PJ0|Ĥ ι-'d&^D ʸg#9=q#`l.0MjJYmRÄIQHX,4xQCf85#]<)BzsdLh`j`Wyr1LᔹUD`@xd0J<~&{#u6>Jv^!!k!i#ߒkZ(O}=(Hbk1=%Mz6$q͝2N'ZSz'Yl}kC2U^wtT:3eYҽ.c~OTnNNj($*ֱִRUUY*REQ(lzZk tUUHTe^z#*fiT g8 XjX\pnq}QeQh7׵R Xj$ǯRJʀ(@WH@G{t=qe]Uˎt 2({'hɟ;[~s[/2'"Õj)C>hbXEk 1Tz39 b {~#qj}$!~Ycƀ{['OO* `p֑ غ׺o9kwc!g;z_wnl9sk1}^c9;έOz ;g묩g?Cvn|G8?ɳsa1}vܺ+2sk#EhӜPNJU$7CmJ, mcrY}b(%R 3ǭq0|q9Rvx/-y-ףqp*յVJccX?=&45&y*iaJ+li D ?cw{{y 8깊TXmR\(}qS'_9}t&OGIw13~ۮ6}ֽֽYӦ^;to|ʔُΰ}>ᾞ2y*~֭\v~RIlKh6YgBs52 @UץXKP"LپDvtf wmd?Sibėwe9Ay,)o^ CGwB&l<U\_KKSAnc ,e!d+Ѽ㨑Qj]4!ˆ,ҰMil; ]oZ:|%DJ,[#D@l-WZEdFd HfpI. [f]tlXֶz4 6rkE^)mM%BT-`U5&jX[HI̎օ.Ye`qͨdv=SUw%831DcP[ Do_qrG|pњ- ;oq/9ᑵ!`P(N*MIe^=kLppL+ 1 ch2LJ7K~';%k>u /9az N<9V4˧Ys|xqI~k6^cës.DYwRų#qֲzӠE+p_Wg^{O mއk[?m1/$NOr\ RfeZ_qRQ}ϯl/ rV7vn \  UZ  rfv">ʓ/XwyŹ/~̇V2 <]$}Gq\Qs΢[ +1~WzhUfÒWO.>nŗ]'\vb9gњ-;w按/15}Y^\qӏ#{`њ-8ʋZzӏYfˁΛu_w?jЈ.t{}x#< G5[Y3~+g=2r_y e;6Ed"&;Y $ /K!WD ;*4+"]Br,^)8 %@{`<ԉsUsDP%Jpl\Д V8Lf뤴Xv]q;)uAv+, *jJD(4iU΍TeV5O:"EEFƨa}ѻ` aZZ%!P DAa@&"T=eQ+Bk53$1ư'Wy lE7Y,RPJ槽X `1f0P>؊PvD%h>2`{I~O;d\⚋'wS"EeWKd.~`>nZG]'>W~n~펃If.̘{?y^{}߿r1"~Ɯp}썆{N=d!?;Ϊgϙ€3Nl)1h+b5v EW:n4*Mb`P 83z~M|sgyjC3'߰ o|ٌ.9a6u>zK.ZJ|}ٞ7OEE je{kmI>׵yo7`/O]Qs.Bċ~reGys}vku4߾pc^kkwkzso^1ow]߶s. W:1}vm ~B+*[)ٽ׷qЬoz{*ޭ[+>7׶~9[nۄ߫~S IDAT\߶A3m #H/疞?a6/o=һnj.ڒ-9KG>|er݂7X/y2ooVkE*yNl.y ~7Vקxsېf|F}~W< G]1w}Gq* O~/%m+8_1;79|W'/qybs=/1/]]m3ɭΛ0}U>}g1۞vg .:a˫=0c :U6ӡϞ->YAu h|>uNÿ]V?1k W޽a |gV^}澟^}Zm+x/θq#a+xƋ/REHOff!G&ʊL@߼TcXm[>7?{}ۮ:_1@çǕ5Bw_z7r'.ug?_k1owwm_;p%}å?Zy}vþ7g_oʲ9[|˞c~0Hh oo?jWny=[жoF=&m4߾p!Wi!}ͭC#3a73Ȏ(f&1L+6Gή8K}wO9*(Ĝ&?tsÙdVܯ2eTggFw:Xgpޝ6x灧Ko6ͺeœ9{P`K[Xch|h|`GV@1hP:P,8)l@I VFf`]VZiy[@ !S5 dYUՊ""J$kdt  $H*CV5Zk]]*bfa 2F)vu~(GB6Ji1Xbf+h` #)Ӥt7rݫ{udT#g8N}eɊ]N:9>}{5>s tW= Lhُ[uɚlyQ47g(<=(dI_7k{|;R5L!h^ܣͣ[no98[~~)vnnr?d#};]-i ˗.4|ܘBcN[׼WMY Z-.vdO\A$mU26W|fԾϷҶ;b?vA(XsIcg}7zZT;yFwf'I)l Iw7j4 Bď.y`e {tGpZs2擺λWaOLIxl}I6 = s% l^[$3>۸N?:࢕-w: g:'`ʞk<WplLmw<^; E<G8o4jfEb<y_qէ-$I؏5 s$9zĒ /a;>uϊk޿a.ҬO#b{;gP_} a] fP_} Ri7gu|w__}ҍpƥw4v{m Kn'l)!|(OvŐ8U)yQ)D$fG[5d)%.J/uɘPpMT ,gnKKu] aYfͯ"|C|>^U}s|d=74(B@JiNۧP)EXԬl.'6xJ+Q$8.dM0+b221)kcB3Fi5k6 0UZTBDQEF7Bʪ)֙UbH!jXo翛--O(Wy`[˶9Wݫ{u病;U\Pf h?|37dP1H#ΑW6m'pybƝ9 NRe0|Ƕ.@:42HT%ǑnjkNuUQgO#)}U%笑n$*3ڎafv ;yffK}$08pS3gKjG2&i; YwqCUQIO:g:R$mZ4FK9eNR]!lZιda{#lWҖs$3I%f8j*x[%51 `+=IYI[TnMLe3v$DtVJq4 "$mIRvv#YKVyg,Ky3BLlFװ8i ߨOnߨ|kWd^FNld o%hH/%=mt֕]{~`>jL)քJrV'57wYZ;zrg_l`!rMfשXw} @JBU.3қK^UEO UQIO=ڪBAM !)uև,W˗w(B,o/;%tmx]V Z x}cWޡֹ"]&!ɾ-1 ,/#[8*7I1 6|C.=),}\O;fy9ar@F)I(Ysv)aUU,$ȍs]&J3UJ]Z+ֆLj̠f]YHbi  " (m~,HrWC'%q!&!2IeF Fk1$oN(0 qDQdΚ_qG0#gƉuC@ %oݧ "W飾 =_?ٰ[ؽW^-K H]D>|g+ˌ~Cu-%ܥM3VJB VukMדּչbHF Wu=doOCh_˖NiɐT T|_'<7vUYYqÇ<EБկkK"#uiSQ Cj4(`X-N Vd))`UƼew/M8M0W&e¢r9af~o63N}kNLii'ΟrwKy8{-c>b'矗8NKR@(4| _ ` mwo=䔎G;ZyZk)}ѾCc8jrd NaKG&%2TמO6FP :'źA(M(3<rA޼;d'-2-cxIL y@6FJb5 `sP6*IJF "!6̆ V]6")B DTZ)#I)#AJ) c413 0:թR(X0oȬ)܄BյQ\UE,k1! u^zw~v; qǝvmدֵU53#uKk,w,yw|?k5mX#&՜h]RiUY&8qRjf Ś=z{/kB#|G6ֵ? vս]JmxMsCp;\e aDS'd/.]{=bz&NMwL~(k߽#1FT*}}d)CލH쬓\>{JZz͆RZzSnrr3[Eеg>2"m6"BX]]]S[SۣG=jz9duA_c= c ]( QG2XJD`/~t6>~O5/2zN9eyݜUGQ$e_=cC$ 3xjⓆ槏5}!go?ERMxGOw`1g^o;쉦4ycfLoPVf4/b>khg^~SGE{ڝ8YG|B)55w3|jѣ-8z5 Fxۯ}ƙG>5i"[HBUb Յɂpv`M3eN"SК5kw&U[xZmPNU 4oܿ gVۍjRъFЋV<<#ϥݡ5µio4tǁCED("!цGqEN1m 2k2'HQq}7>唉cO~wYUBő,1T UB$o *D=?:x%;}[pwlC:#i^TiX@! R RL}着^۝5u-I:c> >H Ih3̺C#!gD"0 W" Xi-ƟjU#'MAO>}p֔ꪪb*5_㪵hRiRy𰝇 eva2|]&)I$J$}wh?js\4Di,#ZFLjĴn?:#~q̬;l!mƙG=>~x`Ϗ{ö%cMOȨ`3ιwA:?&?x_3纃vݱXq6''>~VO37JͳdcP AI" ""EQ$1"Q,2dXD@XRD(I XbX,q,D P xATʖi9&ՎtN*'igWTNKIRN$Ui4M4d Y76LT)hL GDEH I!ݩII l\XY3(J2l y*l !`h@hA`t !8>,7?_AH!RHQTŵq]MaսzYW۫VzѳNVWH&]iڕwv~Q*Y8QU(ʥdʊ4 CiIulܴ~>WNKIy;V_?O>k]rwtˆj HFIe]mumuX$ $EGlm Se;20Y%ؚJ!|+(m4s} IDAT4lT[0n̉֞N`Ad4M V))neׯmI"h_ߵ-/*v/H _ c̚JeOp߽z7857s9Sf8ͱ}6x"dhs}#3{ljMuD$eSmWX<HKNOSiޡe64 ̼/՗^z}Cw[ZCOM (ɰfV>m.o3~+7jAZ/L+GxtvcMm>6k~O×,9n}3Ϸ31=8nS۲3Οr;|iY?s~uۖ-)/Ϛu;cc;6h{aY?{غlMyu lqYW>\4׼+O<{coy`fc֥ o;ѧ6=7?p{cm.I -p֬Ȝ~uۖ-qZx%B7|BBZ$7^z8X,n}=-;ض㞰L>Koo}K?R ڑS}қq2U!2X" |`EdwpyQ?s[-I/éܻ~{2< l Hhؘ1&Sf=[uk˿LD~s??ؙϜ=V($1C`ۯLAlS|ݯ_*]f8lN$#XzO/5_qCw[ZGfLDfFͼj뱱u٢N}y yw2(yyxÓϝ[<9j>` 3 }W/uZ" Ehaf!{IZh ,cm#[ΜuU'ccGo;Ղgu}C||{ԃ⦑3G7X8^_3Λj!d-g̼zܧ3UbD{nضlO}3`^ijg]9n#s6-[4i_+hSΞ}5;NGn5V"\nĝo?wKBșc<1^﷟= M c2qa ȥyFa6 $Baݛ20 qO  m XiMP=3 &6BRc $gmnS0r\-Kq١4n ,D)8e_Rf?YlIRC) )@Ƣ,C0$- XHbQBn].R(-lPH)RZJc]l9Q[aMa a l4-RWGG6FFQuuuBP I(m }=w}j4MJR&GB)%I9I e(˗m%?lGw۰ۘ}E{c[[l/RvսV>eࡾXשݖAw.3pY+-u@F4=/%W"i\>O BSfa@X$RAy{%O>3/J-0=f[V/Iڡ9ʛ; `y`.| $2ho_ps˝RJ5?^`@,` .A^%oհ%<+7Ϗ @Vg#f!\>HxѐO~4|Ld)N Y.Gk9ViORieܔr:F|eg>j%a9Bőy \ "07_6/no 9]2*ܞk,}8K1w";H&nvp{Q]$LrLt̫dfnq>Vr_3Ohuj& \p$m*I.0ǔx8%{9B IvlVi9%Wo(1Nc``Squ;9sśc^ߓt7{U7D&/Bn+l"a߅X@EyR$Y̫29l\t7t feJyc\$[O&u%L Μӟev{g~>ES3l9r?XTCv)"y7.u 8U_\bb%C`Dro\ yO_A s{ &.5$އҎlnZ'ɑ5|*q.ٵm,|dYy$Xr=p-d*Q<ǒ@!XsS M&Mg}~Yy&r0@C[Lrp\WHp\jPc^L $t_R M,CD gRf>p!IJi";$,:լH)6F1l H!y#lZj$Q,@)%hmֲQF+((rr߶4I] 6&I֚IV BKf:ISJP((:;;:>O 22SU\vz{ P(Vqmƚd#3Z[f-5YwֽWYֹЃʳy Y `;kZrh;ֻCi a"UdQ@4f5O֟H™!&Rxlt89,-Z9AY^mME{hAPYj19+P"kHBH0! |9\iD>?+7wҾPYs&yf cg骁̊4(H ,1ھH*sY,SݻO4F$7+EHxm=G]gm|.aXwB򘟭cb3FMcct`YS㹅.#t8v?C@F)-#1H؝7ƇSN9wAS"@!" ؁iFkf0閈 1 ;1kh*J7C0Ͻ~Fw( KOu=ȚbBYloeF*h,&)$!C›2Q{(@?<$1vMҾ,0=nF#?.9@(s ݕCׅz6OY\ 蔊)]6[1A*;=3堰Egaك/d_?G@23kS1A{Ԓ5I d*8~!$sAdfDl v 6FTu:fDj8U8*%|F!EXHF"@ j+6v+(:߸q~gf-rsi:p0[O8J~[?]JF͸DŽ brČhОDd,m <0X9ewB`Lf]M&79k#7|V, ̬mL R=]*!(ݴ"QJP=9IRQRf 2fN4I$Mr盒rbH BX(8*IR.jJRW\.k`xyE`pcFfk~2_C]z fY,0x7JJGgN3ZI@Wp_ec7ZN`na@͚3[ H Ɯ1czن0GlVur, &Eە`'#OR]S!͇yڄn0|xym`aPc3bO+)7lCU@$FGztŲS)6S}qU w>fs 7k9uBwYonP3dmh#uZA g%P `Y4Ydb=dZ98NQ` $vޔ;Kՙ9TɼTgdL1b=(snF-". c7m&~fB8W30\1/8o @g Q1\ 30\ ˏ[G"t:vlfUaLWD(cOp=OB: WAY({IaxsEf r&aGHANDVȤf s]D& DIVi2FQi"GQE$ѻJ"ABDQX]Se[b6eHc""*Uhm*&3c3 ʥR& D[fL$Z+."HDQMv$mRijQ LDXG2ư2BMQJkrl !V_9(PI\*'eclw1VP^\=jj0Gf㐠V`>-5f" ֬3VWgylЃ|9N1|yX̛sYEƜ7F9"~a[!^!F$HJi 66 ;Hlt;$jr00F)RH(}֋<?t/pyBP\@[y>0 QFT!(_7(D0ӑb9CI#H>e\~׵R9sMvI!g[.y|žtb5؄N.v=eҊ([@q2T[|W#=ؾ88 " ݘDɐ?y*jL sOF̙f!95* wG[@0G6 Ď%0cd^ٗo9!!$'D Kc=d xu;*AdBh6rGJ;}hMhf@x0Jw:,-Qd|aK\,{60Tl^hlRyppfs"0X30rD@v:yF1$mh'zXZ!ZPiBHq1(6J 05RJ˒h̓4i-@ @FvZ5m "euAR)äIƱ6ˬ[qÆ X]SSWWW* vGLH!")E"̜ cҙhSw ( (QmFJ@BhQ$-(Rڕ$&?^ݫ{_0TzYgjP16lXBE <ѥ1L$$r!BP0Y6 ` >Kɀ(mfl$SJ|O Ga*.O0@шlJIr_ -!D -6˶i@(I&a${&J' uL&Ġa9#:+̕ș),C8V?η}"DBF6#R%bFla'@D!)˟7d>%vH\qe .(_fCΚ6w`V fny︼ DdVfoP Xg͒!sUuEEiX~ M=NeIQwvHy\ 4D]m9㚢Uk[Ys`c[VǦ`?paUnZb@H!= o~v;d2uZ4X6sQY 8:7A ۼ<;߱z.O!p>AnɛVܭ% . y;n ޙ>Yހ%puRHm17s``4&ΐ`8IXNWt67'SUI `(&4uT["@c{hvG! ;{hmR])3dSܴc$PZwvv2PPZ]`Z'I)3I)D^[WU%iIН 5ObI $1i6CR0 (wIiGBQ$-"u*e$!1.tK)%e&)']]iBM`wڽW[J%z޺#~47HX1#sx6i}sH ` Q&͕>,$Gyl;k8 Q^GA 9TfD"lY&RRBjs)og'w3koHHyeչ+c Ǯ 0+,j< ̱TFRJkm<2l+/Ͽ,f1}s\ ;HɎB;dbb3 l9n\ʈ0(È։^u9a;r`&"pF% _7o)U渓A卞l|tł1ֲ~ST^QOaG7 y%"7Yrob Zy`VIHBJ(tGo{%a/#aYjLYj%7yΧ\O;}B ;3t٘`̡]1y{4r&X5\!#|:NņKm |ffʟD2 zΏIO522Ee/@l/}խ_Sy5pj=Å1"BO&(g@Z+B+Ǝ[}w6&U6}~ta}j-)7޷J,ă.^ٲe/F @'L|h⷗weT. j S0Q/ةnCZ(, ˢvݚݱ6S~߬+?ǮU7 *XpFKt mM;m??.;y<89Ko^U]W_MoI^wm(}~t)![W5?Enz`ejDxAv?i]3¶u8aON+ƍcgO|U C6wN|uU8}F"64$˻Yp#8c?ܝ;l wn𠉿_ PPY0-xe80 $^4?;;xi||ȄWVrzրa`L; ?[UgCOp)NfUo ahE{`}w^?̉ȌytjBl3o|F^GxCGo|#G/mkars멗곣nإ{o7oazEޞR0_oV,Їs9 >0?YboHLY,N#fLx11& w;]rΉ/,Y]?xi|r؄-u%a; GnR{睿yg{{]s&.?~5yN:%syS?9d+?}Wڹ?WW۷iO_t Ͽ~i萦W64?'Ͽa͟_^ٸ.Q'dU}ϹO}wյZ{sϽrQ]͋&%**UbbJKUA4*[c%/gEEʥ[93{c K{ |ϙ3g=kw}}eҮܸpAW'V<ν^RCFkעw]z=/ck7(nA-TR,4T$v5dVX#}qG'˺v:UƿR.uVв{3[r}~GqFM~-:s΃^:񟭯nҮ\޴T;Ot1g5LCЉP K&L^2gNX uK/_kN;%"xW{Nok?yؤg~_ӄ5#u{4̙^I$Z"jsDݗʺzӽ |~wWqCO7 >势m6m{␊Ǒ^Ϧ͌]q&Նl[tƜ0ϫjGv.[zsߢm+gͷ1JJCe/hG |yn}g-Z8&:uwO?271ܮW\ޱ{o/E!K{S 9-MUkޱ_}$5qhzՊ/9f9]{ti7w&iz//L~XaZiЋ 9j"aøI/yO&s#u}^Q{ˉ"S\[ö1x.~ {٘A'wߧ4qsZGBL 2A?za?_z}wnQ&N\v٠Sz[߰&ݸ]D|5yey-^P{S=9G^("^kW2ZZW Ug?dP*nju>bnEI/Ϊc{?l˟?N\NAth3M%h"DXݣל{y^1#Z#kꃧ;+Eyd`D!:9jMiOi' ƾG}[|+>v9<7c=?5,%?Yqp^[XX)I՚v8?bWkV 3&;npdo-.輞mKƿ9"ƿ|~-O.,?v cՕ'p)5SҬ]Ɋ_tU*CWy.?Cԗ/L4\KZZi勹^CD>g !O6[$0 o0t{RkEq֜!cLpuL&77<4$3 ^"Ȃ)7cL4kDƱRJ)Xk0STĸ a*!@ƃLJJdȢ8*80uou5uq,Vg5etA+)eqlrkF )Ruc@8 gb;)ӏwߗ3=icϱ.T@:0w#lia1gY71ɐ+VT$)ӎM?!LŽ{KZx1ȩ4! 0TޛFs%̻W/:~2;mZ~WqdM6m1n/?dבܳwM)*-> MW}%`k{k{nrQ>b$S&>7kMK;o/Dz;n9/wCt]qf"-(ִ=b̶OBkpfh6G&w״֝q۹1WyӪ;=zbC@l7kBx1m٭]~׎|s7V=.|l8xC$U` r->~k? ~lHglN깕X@rŮϫC箉8uY0A:W64/nu%W=/O_w¡3YᏙT̖Ao7~|wI|)2;l털{KZ|٥׆A`Fb'ީܳJ>R)E@>_\Mg|^ߟWB~YH z'wZDŃWpݪ{Kh}YAlJݰ|~I]J)>\0lsԆƼRy CN=w?h:Qg9m8wCRwR!6vk?[ڧKOu/;UE 4@Ɛx%w?1~??Y~Gwf7JC^YwۥN|urM7h·wO͖v<@CȐ4P˾޶jRRL.gsm1[;}9K:Uv<‰x ӵCѩ~[M4`6n)+; ی-S.wV|s RREz=,-=1&䔟m}nK̽[Skdʛڻfp\C.n_^ٚiP7v~u3KCWnQҶoZywI;\{~03YԡJh+f ۭmT՛@t|ۼsrcƧvxl6]mMSeG*f3 ɣO]uϘ:?;tȔ{,~_ 7C3R1<4;xF4n䮒V 91us.ݽiIæ|U`vaf[@݅"3cPJEz[QŅ83$X[L"LJGbAq.S*2"Ma&cLR1'RZ#c" H`D 9G0_Z)]+$1 \#hΈs &eAQr۷FF>!0 ì}뺺0@ 9ghLIV*cC&\s.`H 9i$FBye*J! dfIߛ ]~5o}!9{(9/9xI}_ݔ'P׎_fGXͽƼ8&TG, ٗuyET`ܔ3(e ZtM)4y&M.;weM rq&n5yI0iuFOSYXsgJyvaQse3 u,dkbI0iӠo,l%u-Xh1W|]2_g<9t!'<Y5w`k!;Gn?gJ?;C; ~nϞcϱ}( nd>-V5[ݤ D)H˰5)dQ6 c86hTƭ׎,AUnW=9A #^Pƛͧ)1; $Z+I+.ePVQV>{-W G~vp7|q֑C^=Cq΢o{ei.`34ȼ#9ɚD C jء^ nvM\ltfś~[աƎ[6MZq߭3աW8:A8h} !4: C"D9iJbƇZ Ȭ'&jn H(|0s ZS7N|ӺW5&M>:Z_Qz9/s*_䤑8cA^:ZUn5yU1r֚g**me^U%r Z ׍e}"DE]xڢ!P@q6 H֙!xgjXD]ǡ_om(꼃[h٦飧,;638b6 w: ,?ӡ)YpҵJ*|MNUp΋VQUk<`Ckj֡h}6xqQßۖ\Iv'Xr?ᐍu*Cʪ WϬ8ty_ <{Ő׎mV&uiSow=mϹYnmlBۦv^6!2'XZE")G@sq3_oɕ4oKq94hCa LJIK gŪRgi[楃:me{ ) YS\01G 90Z[i: ȐsVR\BTEɹ5AdF0gֈ,[4jРUɤRLqXk)cG@(ڶi@2脓򵀌4Ԥ4IT@TVJgLAQ9kkse" D  B΍/\K#+R[jBЌ1EX 2]u]AeُDw'|kkן|}UCF{=Ǟ_pcjOnɣK&w4(_Vi)tCF51(`lSnT78y j7<nڅ;Ik} mih隞Kdcݨ'.j]mx Sʴ;ʟrd1dC ,HkQ֪pƺ {|F֭_;bh+p7Al}/*5m#7_>m  ߮5/: ?Oc?/ ^@`YҐޮNlyjs("rO'rGwQ0gҥs&ۇ,_֍B1S%mxb4)  I+l /]0Y4%[dy/W}k?s"s-b@j7,$vN2 q֛ئ܅ZW, EuM 5p"݆׮_l̍d‡[ isti<-ĀwVQdc΍}d̍; ]T*xcݰ }ٌIn#j7<ƃ`ܨM'.߬u뗅aѲM {&T1ncmKmZJiMuAґ7@de^>>kɆ JzJӶ袳1\NG=эQ]O`-{\PaYҺ1 }5%7?')b 궮}֫~`wSkÖ|=OHDD,.snoN=/dqq1.~iv ZP)vMtB9/L(6EDwSQ׽|KMxD{7}ui2_}>]i udJVن1 0g M7N)E%Vֆvl3y+_Lh\Aݓ=7wWw}^:vጁNV-٘խԹyu@ۣ+| ΙqC^\g&e4?lSf?ܾy#\9gz&<<:;W?ŭ~~ܛIG\y4tUOtNоX9)/`+˷(WMu7 I4Ȇѝ_SisDm#JŹ˶@ˇf_65,JE=!"F.Q$+̣5;?YZO7l8300HQQs2fP֤2ٝ0W5E!LDHqQ` Z3h Q%0ØZEQ,Jk-qbbi E|m]M]6Wz[͎ښ;oٶmێ|K`64*nТq6m׮y& 7*nڤ8@نM5lڨq[jдEPxxlIæE 4hԸqƍAf2 5lݦu]{_ٻW^:un[nӺ^[6h-299}2?{"g'ZMnQPJmg9Ե `K7姜y ? Q!G*>iGvod}90)Ƙ);&qyc x0B0p"v<0g5oaG̼SӞ!JiIk$B"paar.xu^?;vݧs]{vڳ.WȊrK'y7ݽ G֦a7D@3pcԚUus8s y̮] L{&ޖ3Vl!|!|?<5'~vґ#}NJ%RԊs4 3 Z T7ƾɷYyCqdK;xљXzE3ˎ:*:ҴKT&xPlϻr.Wsߪg]Z#QI/BҠ$TA%JJY(su5;vؾm۶;o[lٶu۶۶n\SS/⸠If5T<xY0( EQ 2gwޮC׶viovձkN?F#VJ<\iw\x2 ,wm<^(L{fކsѶxbRxmS\v/Ԡfծ#f [fEa(iX&)bS~s>e喚BP(d, .gίRRFq$( q\ -5I" 8h.:tnۥ]{ۥyid192ŸOq y䬹(_lf2mXa7["B}񩭛dI.Y)ToV]qpD:lIR=gTO:jϪfqEqdƅ=5Jg;+;T{&֭]yÖxSL5l-jl󽇗f+* s`P# Ap&Ʀ3gs 911EkSX(VHFJ?w״9I݆c1E kD Pd2A&AQ&,.ʔd:toнOwѧCa"0"lLw8KK ]ֵMwl#Qp̓+Of3u A+uu^|^Meg\|C'9{ 8o\ႉw<ԣFENZg('g]Naq xr k,[kQiǑSX;rHYlQFNAAdg.u\v%N??q=gD18 2 i8c5" !8R( Qaqq d+[6Eΐ3"龜s9{VЭ9K=-xi7,/"| nÌ7幷x[]̻eiOe%ԵM_MKm;|w,kT]z?&:3?7HcX_?4s̈́KO8WF܎ ޲|[ye{R[6}3 D>`t Nl!5VŽ:vSݲߴ])emz?ݜ7!cOU~m]k/yo˛a玹2Lw($ުT`Gw'GZ~מ},Z jy[@DJ&cI-/"(eդrw #wjpǺKVyߛD4Wt_ך^]=^#.(v]4ڱn#VÆ]7i䩝[7ܱnyS'?BӻpoÆ^7aĀNeV/]pDw5.Щu/?}onC^[οt|;VW}쮙3|j[7Q7x`*3g yB,qcͪ;t)S` XS_6gy꠩m.y(h}mBfDJӄDS;5ڱnӧ?6 ♫ǟ:m"UC~eժQndžIۚ'_y=nU^]=z_G@GMp`MUK nʹ<|Е 9ޥMm X'zf\Sj{_;Wf;}\g]mK}Â/D(행*]'-=G+%"=|D_KF;}xI#zugמ|㛌!W/c}M\[qYj۾>wӔlAW|r[7}Sn|;w'ty}7Zk{u ;f{}ųе眉ƿ~fMO5ګ;xuw,kX]х7xm4=v'bwܬʛ>ZH(9=kW3 F8ea_zs~ Ū"GH#5DA !h"%J3d\yDg2aFJY(D|dVV*#2TVS* "7=`xݍ1ƉP((MR(*8)z :$a(8i-p8." PWWW(H9{(LQ6-.)i)*"` ):RI&0{=ǞcovӽYIkBV.lwn5 `RC[ K  ZkJf͋/I{ȎkВ w\7 yo/J94q4=<&ʇk&XD%UO)IѝyGLcB4랺jJn v42Z$LuZkLNN)0{ӉM2N6P:֤ɺ8#Ӻ96I%m7LivtH\{~88 qGĄWSa Hi/ǟ)<򆟑ӮKterFQL)rdA7&9HKvu y}?xbPos*BWvEèN?3yazh3\rB^Y@Jc6]]' M4Zb)`mftj%{gݧLf{R<Mݸ50SraR :9x(Bbj󮞨_yUgpF^("hJv|ا{4W;+6A@J. MZ*IUրI%eƸÊ:5mF)ǘ52). ']bJ a)kި+rX R?&2e>:em|дLh_I 1 W _*<G+Zk']%Hhh"nz~vLC8CbRV/3% @Je/wܥZ^d, cJI~b 'lW);FRui@:s<!`^R 2 &J6s@'i2E+ ScgXCxcwAv?aHYVtN̪Bߜ?7шRް>L;}1mia};L|F0Nz-dsNtӆ"r 7:ND#ߵy0qMű+9~ͲXg3V)T@n39MaΐCU<= Pmxcg3Ә fhP8 ̾u +1 AkД˃@ISEKp% OlJmZO M≠H"aNa/_ le wZ"ur&3@y27+n&PJ SM rY.]#@1]ynTZ-+fh@Ƹ&ȘA"!2nkd,< EJ*bb+m|]x IDAT7,Mh$fRJDB pc B "_ȉ\!qE\> |>_J) (dJe@d2`L1@Ƶ ȴ1#jRZ)%B ZEXi"bq#$`L* J ƸY@j'YoJ9K2I/i:'7cY^}o::""֞Cl&5yB '&{qW5礔J[}mވX6.ʹ&xJ mHJT2((VR"gl moQ5nY8`,MաJ#uSjz1p&E MBueDf:Hkiri0Z)5ON;<9/ lgl&O#*YHV\5PJRRjs v҄ K!.dž%"DntJu{pP'ػ終緻|?&sӖ淴rUŽUJK)|OG<{S}/xO$t):q6 NcyN„,-@ٸȘ AG65&i 2;]J.G߶_'3ONDe8פJ;j%I).)ٱ_Z wSdO}斴$~=IEPuz)0ףK# ' $8[Re}'OvדN~7?aN鏎n鏎wΟ;c뻓F;I鏞;=ǿ gkd+"mѰG;\8{iߥ3 A].KSspM'rF.^ XghZ) KXJݤb֬$tuGJ)Vu5qB RR*d |΅;_)v0~[A!˜LAkiن}9y\v[%)o˛r5y.rCl/Jy{7FLt H0xƓ7tS uRʶjėM{XaYs|N؅@~($mrvI]JDQ qYDyb=y/~SĄcW}˺ j̓4W}f-jTF 4vhEZ{t,W݂&|dO2y/C]T"  5Lɟ1#qiҸ)WҤ~$Ohrθi::u|$N.ntm6.Z9cSqjۛ]65WI^/-5 cE*+i$5aȐ\HIAt0'EL]s!Z]t3(iRlw=z$8)iة_#~cJƑٽ21 #I4uh2b9#HK dHTkNJVhKeegYR5[4xQ( a"`d82G@ b10(* no%㚚55՚ "d\ ) K;AD(˙Ս} ͛Vׂ3 9rdEY A!頮;PJAG;\ 9ִN-3m9iߔ`gfH+C2HΔn` 푀R8Ej=ҭ )m.fIhx oҊ)lr!{aW&ToGӴ}r{~\mUAtY{9.Ú֠SJm\ՔZ,̿,M)5)J@oF*R\uqݑ2dRZj "DZNK9gBp7.[ Z0 dlD44pSA39C!&G@0$RDđh!8(2*D3. ɘJ4i5 (d0,.)3a &8CQ[fEhǎ;v쨭+Dyf2̹R,m*2 $)U,V8AV !!ooQ|gvg@R$<W)Oݬ)|_3ߵ ~sQ(adBAS[\$#8.tQ9|( AΦs=Q6 a"R s;r0Iti<"kMȴ:qdʤda7ZL5sb}vIH:PƓ7kiz\"9)ƙwsRi*wĶ(('gy6~$IP9N.Y]pC gX8Ljs'noUH)$pҳ%8sMd=Nɕ `\V$LW64&8nu!귳3h%/H e!If[" qNM!Ӷ2,PL&g VZ *8Z*V 00 C9 ҤU&DIi"@Hp 3RcԶzRJJ B/r(րR dl(xS^.xf8ж( |~-#4;?3^ϮyWXow˟p= GſdwӞ̨6#Hx"k=4YuV}|[ 9G4<7W, C2&O YhTM5:cN_j|Jt">zu!yO:j%m-RX۲d{7MIAL="}Zڒ!wtn enhay/YI{~OU4iMM  pRRkxk)c٤5!gL[<&R`=d5\e8r@!gVTZ{szpeAMrohQ)24M36CA4 C 1ff'ifsjCU1{/zxr8Uk׮FUPDQNt*G*ɐiCP(PF 9'!;F2d*)Orr5kFdQEQ$ ̆a}&Szoܺ HFREQT}8~*RELF)TʓQj?wYo_:GH.ܻӦ,_o^2}wu٭q^\Ѷ]۟#~K 2͊dCjf4*-օ9']xnf{w~Yssuu obO"V Qi_w:^ }G aVS7Dt꘎#KYܵYn꿯[3kҽXřX#ڱ.wlXb/?!]i|Ϗǧ+>KZw~WN{w|sHvH=tƌ:pcyN=u../N_:"@Z$OE!3z @Ox\ҲV a916+ nTϽam߳[KWӋFMlGg~Y|1նg\g+K^m_M_n}9Kڲѓ"K"Ɛ %bhMcy1w` FzMeE=Yo%E }!j{4^9jR*%%b["0rsRL9"猡eH*RJfj3CaQEZI Qp.l6Ec<ΩM)΅"$&0 3GmQ{>g3`*(H#1R7b;4Fۡ7^Q3r򝯟w9oIbe߿.`ӞoO~ˌ}:7xƾ_v~ _nj#wJSkdlslCKdqnH9qCAF}uk7.l_\xє/-kwpYD"d"Djd ݷAJpR2R.✙4i\ΝD_f+R'ο!׼cq;.+´61WQy7>onݢm Mg[Uťnk9bz~f.Y4eoU/qWݴO*,㢲 jkn]оrMXWUcC[76Vu1Zvî{ssMAʅ &}~Y_j MXx[˻nMupQg=+ck7ִh׭rɼ/)}kI ǒJI0:ر2M`XtTO;C PfWA3$޵ T|$bHt/Y2m~GU<|ߪAf$dm-nEg.\8'ewa KoniǕ Lٳ҇u5}TUԡǜOquU/q̓~vSMA9KNyķvx^ْn|M :ZKު.QV#^vg.^0egϲ .jsK?9҅7uկT]оxβ~|ص4(rfxGCv*2$-O٧+8w~/S~V`q%9ShǤyG([|kCyccMa+ֳHнl_s_&>z. Ӳbkծ1fYV)m8];3{LC_P\y?,\Ǥŷm/mSEwxF3*oCNr]<`\%2G7f1lծSRQvu?\yF)GCrDė a׭ݴ}N礷kWh1,:oҒNe/ظ}9-tص 2eѭn{='y%‰>' n9z^hO/݅%omuǰn)h߭rѼx{wasu66};zN~uB@[>;b/n=~cW^9%[wr~=zkH ÀѼ%iPPܲ'FU'Ⴧ'4C-HU'<_pdHET2Rb81ƉGΝs?dRVK"k"~HL* >S=_" @_ct($T0+UPzQj $m K "I9)?''}uqI1RfP+)݊9OӜ"%\ұcGD=WzJF˗eQ|]wSLͶs'߻}@A==y-5YBm:uqڶ7L㥿䏺t^m~VًU?P7~>tr65$YC}@n2O{=z[ư'fz m5ll*64H6+Yz#O/~ȿ493z`WS~?*oy#D;^/KJ>ا]_]usGn==K>ا}BIͮw^߰Oh*^SKXVޥnޥU?t5G_YaN\Sx靂MذWcA-efeWڼ+[Et g H]1q~wk-#9gpVwp]/>ا'Y/Ϭ:璅V{.5:ٻμpޝ/dyײgUu_~;J6@/ͪ:#^~;&cow-uvU׋ܡ?1y ;w\:5:h~?߿mZ \r}4OKFݚ1c7ݿr.>7F/ ^%XLH/‘q!+Q !XJ:.9"p{uYSݿOyG~}?P7yǷ=@[oQ}1v w- 25V̝rWZl@;lLnڶglAYvcp7t+>?-ąc9CgO~}ήscޭ[>nٶjd:+=a_l2ާ&f#G.yhux7輻륊Wc򈱭J^aL3oePЀL4 t†}w쪳/k{iɋ)ύ{䂻W!c#ּ?ꊉjߓ㻔6˅x{{>l9S^Suڻw\2{t⬊?[gzm}{k~ԷծQG᝗|_yZt-i殮syneFwO~'ц?~Ϝ]$~?IF0=zw>^K2noc_*#Z y1>}k֬dJRL)aDaa$+(5=Eq}BA-*(IJ)%Ց#lVE28DssrzI ) %UE*KJE{BEf!t+dd1!"F2Q)1+tTɄQ0 BtNCFÇ @9g(IտUֈ\4fDOSƑJMCeN36VIw\Qq 7bيtz8E9gFTm}8/c )p1P:r8Z~a^@+?yuʟ,ᑔ* #bchM(b]J6SѪ}g2'\sCA/fMji` RK?0ՏAY ?^8rϦyKͻ&?-ḃ>W`5~;UoX_ȹ_j6,_ ~9>CoZP ǹI~4/ EΠ@+`In#_"ՙL,$5Y1Ό%9I Cy>K/_{c;'tߞ{ϿQ5kd<-8-~޾sKCqFJ]{Z3|0 nbt?ZJoayfχ s  ՇYMe?X$E΀9㺔Qἂiu?-|59aMF4>GҔv8`i9[,buvu& S`UL|P19K@Y}C` /$a]vB־dԥ{#;ĹA(K [^ղ]GAp~U;(/7On_[W/JSjW}/r_Q F~WybTVں-"ܺv4hZwPDoTxj|:7-#umA/7 ƃ܂G3 c^= Ylͫ7Zh]e 0}dU.a:g<nX2gq49q=YpugT%"\{#6/+X`؁1kYWaEίz#c^܂euuO#`(񢼂eϿ.?Þee{M~S1pdCyQQ|o 9{1| |7`kKD 4pƜSrSHf0 TJjV-B0\s@ nw~Z9㜁'|! PD Rf@dl/W֒IB!'"FQaEae09by0nnL]Gc!B;-Im?ryٗ#ۖNĭ|Hk ai~ԌM>*$@8o[fD]/>cDu3u}ýu~:N*:h{myDJvxh_i@\Y -_6x ><%7UBTBδfQl4 I6T~AIk͵7^uMvO?Y3c>OѬֵ&!i3::أ4I *gY B.q.TkvТW/%DT䳝RN}|\ҨK1`E>YԇJL2_pPll`Ғ&h' (*8q؊fD/_ ^$*_8|4BU)/[8{_N|@,_8lTU /& _0E2R蓰?rV`סi> g{ NqgÞu1+Ÿr A`Xlp[ǭ%Pg;겒|~ =w|G.S>O0R~?۷'vpW_lNʛ|WIxݞz"|qn , q /GE ܴ4mI,oZ5\sNR' rr~^K{'Y4٤"ҝ MЌPgT|hGܷHD%(o~ooPcs$HL vbxFDNi>FD]-CljK>.Hĉ&cNf2|2)l*y`OZzm\WSӌ4lCdPDU:c;2QЩ1u;6H:UjԎ@ ePup@/YY6BNRA5Tꔴ4#ˇLUJ*}C#^Ω*«Mr? s8g?IY\s0AQ^h_ 80'{j:1QUa T;j ҧȠ* @r!SNAU} T>OѸ T!"} [#"R`y-f-yM'"EhԞP -Um7fW! 8NnR]c"=db@CBTUjOꢲd$y@ sΔghʴ&-ZKڅ?)V*Rv镙58p6 U b:( G1DdŜq{sIZ2qpBP)tW'T$wm!(,^r<=IMX"} L_Z- UL8o)pHW,l{}8D9`WUԧпy铤}NK h-rsYTT)*P-hЩ" |! Bx6=!ɔ0[9n>=;>\eHPh[ fFΊE'Z7[}_"V`*T}]I  @ ΥTAfA& H;3D$I)#m|'0:=EO4YO{;t P[J=YS7cƾW3wOh?z5 TMݐǗlG@Aw_[RԶYɆa`mjETMǖlدÝfmV"dM] ~}kWI)5nœkԲUhL$bZD a!xLSu > $cl~ZxWil†}msc] J/܇} -lk8{ꇶk6q^Mmv@]JR꩚glا~Zp~X&nا{N0z@ (#R|umuJ1Sਗ਼g4^~luUOFR"c'_8/kgOKD<^jT9OG'~o]q5c˂盔K+dDH (3w.*e@3WFC"bV=Nm-O6|Zv*vX bg[ ! /W^UuɄ;_lOBlQ[o[~qP]7Mӱi`W{/,/ֽ}fɒתJ6եg\W*7/oeM] j]n~JpTMmZ|OC; ^q"HDlѦm*xnhf%9mV2@ !6{X*ot.6j4?\*37"v5I]JݺH4VB46 %qt7ܚC ܪD2 1C(776ޫJF$Q dFJ82CFP1ERH*%`q8s |sNFdkTduH)v)Q$ cB TjSƹsR-=d\?h㈨@:J3ƐìL6TuY0O6ix^Jfm Ghgཇ[vpڕC??{]ϿvS]D+'+{ssu~~{sc.DOToggONzy )]}yW<7rOU/4Cm)hm+s6ԁO$JW#R)EmFfѤz-v]eDb]O%b"2uΐ)54''= vsu~s/螹)O[@iϫMuR?WL\} {~e99g9oRnKM~sE.WNz^Rnvݧܘ^Bx+'׆yw~n^ܨˤV\vSul՝?=RWlewaf>x3#{jwRIKCn3T2i+*|#FL݇oy=WU_Wki c ?XMUJ*Dş֦UbPoTTd~yDgGL䉜{U?ӏ<#xn~qNYyx{q\}sI7:c*C҂ًJzvD ~g|I!iVq|76Vv8oΒ+W3@< `疏Nm g mY*folrj[75cJ^tmcͭU)$$ nLfN\*!XO/'Js^8a暂3zfԥRi+v;\/Yp?u>[SjRJIm H!§?n۹+b չr(xMYx&K]2օMWm[h߂W: ُG>1nzLT~cKn]t̡][gX*^զC_m]1lZD~ѦC\4}ܺS2MWm_xƴ[cJjmy뉀:降z.:pՋ+_t3j+(^N~cJn]?1uz}F 2k%s0YZqCz)lzjJщΘ|=4ә_wlԶ!64ӳ͉ͲZԸՑtMv+DǐH)q!bo\|cr>gL]n\5[';9>5;s\ٝu;؜CYm 7~w:EfG({|ln3ٱuc˶StӇ?"Em]"P=`Ϊ|]|8z3itҨퟄ2賭O>d-8W+ngF9ӎvp$oᚤ+A9^#Xݽq/a ^z^nn{\o0ЭWϩ[QmEӦ>mբS39vq6©S>YolyjᴊGOė6 yW9.j TFj19*5}t‚Ja+ R0)hh{GŝF[ 0.n;JFSdjVnR1r-Hu`hkERdBG8Gl[ $hpĜ7 9^dC&_Õ$CLO& ؊b$D<-t\Ilp= KTWACDfvG tԦd-s el?qs79Cι' cV.w}>^٩ٮԛ#Ę3ԠIRnp5 ) ض)6eٴ밖&:FKJ*% t:ń. \gR GUS8!\ (04|%=a^S)DӼc H+E2-l& dEa(#OTN(BBT*4,$`RJ؉Q]mm6Lc:f#XxJ|?&5;Pk$IRqDv?E>u٘p68B g 3ykDtڄWՓt4%LܐrbZWSuf HMK*X9zPHܵj7V!h_bڸ´&+ֱl 2*A"I0!.UEziT{ tQ L AX4 Wъ&O"3.5!Z%bd _2yfAǚ* 'L$P")%)$Rg c:&!d8ġ<2uGWi 8c!09ӫ_*HHJn-LXX\ HF 'Wಪb&Ck>jGΒѮ!c&ޒBhLN%9r 2-E|?aNOauEY.$dT'ޑ5U+4ҏ!ƬSK6%c%h,8c2Jm9tҪD5%Fc_5쯀ݵQ75ݽ[03>h Y a3.ō1dBRL R%+'I TT;2SP֦le14 zxșWQl2@]+C"%HT*Pdiu-ǭgLp lq,^2LCw\ V0D ( !" ƹ.ADd|өTNʖdaf2PfHN/@ =Hi@/ELR o$)A8< T& 3XϏIe3QsNL?O $(RNyMxnN58-BHV)wXJI 2_EGhqwܴ^$ "%D7c87/b/4AYNJtV߈Z dkc@lcH,WIJB-+!\ےB]M bБ1-MjJIPs&zKuHObP?vq-#*-3[,lKL٬P)̐(8` 4@{HRF7T(cwfh;޵O 6hD&p8sۚqG}:SRaEb* <2|)D "HT<8S ɳuLZW iICw-7f1 jiAe8AXNFe2T't!LVo̒EL'$"^ojnDa y(2@91RdD*{)P !@:?LBBDTJC),G9)J02AVROq8C cL?pHAARJRy^nnnNH|*R qִiq*fuO!<ÇHz3o>@"4Ln+fH ĸ&NQzGv"9S4\q @Ĝ $)9ii٤Ĝi\tGcqVCIb*Ы'mt)rYґ1]q$$qN7c\SJiO`Jxzr%2x'P7c?8c4-ZƑ40ձ08bLMÕJ2!m$3[>]K #$Wh2r뒊3ZRʆ\چ qM)ͺ"I̭db9ZBt$U ()D. "ja! u!7$J : Y %^ڱ9)*fR*Lr(FuGs@Š`Yд9wR4fD6ƍ6ӳ3nj}d/qd %!MV!ۡȪHv;e1Ob"=I+Vwc&PtkDb֤y*%ReV@O$ %PS:%&S=?1T 1oV.ke!aunbv'āZX37x#gq(44+0JJ *RJHDL+=)1 I-1ib`2Pp Ij"(]_0PJE$k38Y(n22"E*QuuÇed$giFmuM65!H-)0(Q T*7 0 C@ƿ|vS68wNA=h`]mۤʼn r3\H%#˥ ]SQ{gqhd;XtE5 M4isQq :D*de#Қ%REQEn%3!"]{wMS[DPw-jֺu2C/];rΈ@wEԽHS' ,jE7y)~ˊYg'?y&:@",,佃;t(H0` NWWJ} IDAT~fA7 '"9RVsZ7%Y8!+cOd2X*q/X2jg,&%s ZJ4:,!LQ\KȢ"2Ob!:Cdmɘs ./6q9Z7$t3MF(ѥ4m,!sIhY*ҪuE10E Mtq kC*ʋ/~Be!{7I1 I=!H .h*TuՁr:29d)6`t.-n;~Y 8k˚'ls=!cT\buIX&!4b <䴁&xeǖ yeH"xy[z{Kڷhp|%gwtI ӞعV䜻oڽ\BxwpUN|#g;Uz=O*i9X;N3қ>p>R@=;q[6E94.j.I z)HQc8xǼBheɹRҙjR `$(gss#Gj"q81nĩ5qԭjבBc8>gqJH 0!c^Aq(`ƾy~GQ7FȥzV>b]׹щ %}7kmSi }{ĿVjZ (LJh :ǮZY.ƭνn쓫:i˟ UR܃M1k~Oh5=CaC{awq3.vA 0%qҐPoBrV#L8T 9,S!gYV9LACΪr r VrS{:rn-ȓJTXԪj,q`/~rͻ79Tig7|ũvp <9w'F#E3 KB;t=-aOI-_m/Sذضݫ $rI !YyǓg.?icUc0kӽ^x&7Wv:}b9)-Np;vw>8{{3N+̘kKw +ǭ~ݚiWsw{Z^8p+no۱ u[v(""`܋nǯf3.̓x=[>gߍ}o7Ρk,coh5dYz[@ǵmFCW!:]GhMUv#;vf1 ^cW#SJn]ԩso?{%g: ڽ2o~ouI v=Μh川 &mT.:g2vԫW#`, O_zd+J7jԪQܷWObRַ ΆʢN=f.^4uYוbaV`'D&!\_FBiQ7 E+!d(:# e 0(J*E ʇ TcyKHy@v7%# PJvN\.Bΐqd@=Md( $m€8yLsyRK\NJ) E "^tv+**QHYuunԍ㩧r[qn'vïsܞ-O͞0sŧ@m:~מkC ҵ9V/>tbw"}:izbfyˉ?Kxi֐[uC+}α=r ?;??dT7 Yo>cV; $Ѩ+"8@׌,I/jvިƠf'MxcVIgϻV?pΘ?=@''].:fٲ'tc~]{[|:<js־߶9zu@u;t1M^?Ӊ G,鲓z5ݝo|xלs\#xw-~>޿#o<5YPL P24BFm* 1p44`3q!԰7?)~/29z=t޸Wɫ,|ww<y]ѝ|cTYϞ7G\048gް>*_3ͬn}r&:6;{+~~ah~_ON*{cVIgE?{T_L^`EfXig=4>۟]~^|Yw}/)w/rG5e6ɰXI޶y1!uWm;us[_k F}uϚDUZ- Piy^w^r۹د]O|󾊓ΚT?pWS_`)V 7gL o[ww@8ψ&Z)ڇEw^P~=ͺuFſ3:[)[~ۡ}23㍷m7e_B聾c:j t=']H;ۚ3vK{{|ʺ*96f[k&4`ueq!t>uW7<}1b{IhmƯvꦤ`?1f؞jL9 mpԵ!OoZ<{>ߧW]>Pws}!G?ES׌,\v"Oq%E5͛ǟzsDK) +٪k}ǵmv{\X>Oj3O;]ܭMQn?Oc}=oRwi嫗t9Sr󕧵(/Yuˈ*"E@^xcدoJ|9"nB 82@ IJ)Y8g 4ޣB]w %iDqi$'"F(H,qƽT]"RH њH䵚"ŐIЭG,rͺES⊄R  Y0kz"'GHxcQ.unRẹ~g7*(jw:-?ഽqNTptg\<3p}h҂-&6?!{Ugn;T8jwg =7d59款ekgrktK_uXcn8uf*@]y }-,9e,rwY{=sM:N?l.!MGZ()v:mM.qhЦcWؾ붝Ϲ'Zw茈7~ӮSWHrt謈ݼ~6h-Ƕy)@`Ǧm;uE+A1=N:)܅q]+]mU-}F,<P$  Hi(e9Ml׫uNNg#^]TwsKWlXRX·׌zw=yW6 z8xDa\[tUQ[Ц 3ʢ̀Ui nZVXق+ rȺ 0ઢ[3 kgL]Uw֬ESo!K>Q~hP>.*追&kuOmxg 3M"|y۪ZX81 ę#V'9rvF2 -Nv`Xu~Y_VFCf<죞#C:X0Oۯ`SyAq(c+(.#fxjxzcGuʻ>=ǯo3\U|(}ٙǪͩځy5esDIB ˆ=W1-K"RęRH3NDpOR;Sg0Pbh0"*Ɛ1N& H$R !@x\>1TU=9`#9"8-֏Rm*0i[OG֟aS$(($EhUD=֑V wD.unsE4vo[{jTUۿzxUZ.Ɩ.*Otdq߾CFJQR02B} c&",(6R&KadKmw\!w>WuKmy+V )ј["%:@lX]LxTtHl{u>RTptɐ‚7];mݪg@IW}M\F:Ïj{ιWƖ1:6, !_Bw.*s /C='Sp€3ZYFOc~P(-ϡ?ˁ0oj߹:Ǝ;d B2, 8e L:D J ʗwڕ~&]~w5}*jʲAh; }P6p' 8`;#9qłb*D(7zMITyq~#*?jK't C\9 Jq$ dR aqjԉ\zm|]wi qeGHy O'&pBuYj3$XQNÃzvSA)W}>#"A;7ϰ덋/{A?켓ݗ`+/C\:hw{g]qy&سtؑK/GIwίݗC3y섷+L8ds[wW7=S<8cG%ۋIe N:p/ZdRQ^#⪋֠Kc^,HJo[3ȘP뮌Yfj3RE xA/HHS ҆K>AFo  HBH R\.w!d~:"̶1=_Xo`$cSoR$}\" 9DT3  !0Q*JA݌RNS&3X! ]NFDIJHINs+:?<Ug@v Dq׺Q7ƿ. Yߗ#e]H(8 0+謤i>$ Pَ?t*"ccUX:8=Ԃ܋U7~ N#kA}>Y/w sA ,+hy:behmuInUߑeZȰBJI@6>;gش3ЁSb%Mj5;1UG.-TF+GL8TWWLz=0>L1Hd K98ek>v̸/تIf_=;=wnhNfo%QFdsd )BP˫7Nǫsڶ#zӊ'Ѥ5"*1Z#FWoEZ؎(<x +B!+B ;p""rDl"T(tDﯩVѷ7xRZȰ#j џUyY:x2xǪ*Culȉ716_KDB03Ca>92έ'`XYEl(ǩA{#5ٛjDNX<?O?WWSNzݯ9}x('UG ۗ>xo4їm"T-V# -UX LǬFЖWݏf&f2R B'dcbCfkJVfxK1;n<0Y9ad*up3Oћ]aInXxN sAҕ]^K~U/?oo}9/Y5sojKO8^=z*qt{F{L?;Z,nԽoA" *Cզ0#M=*t@7}bIgd9lٽ6CI R>7W$0!Ud&K:UR@Bxvz!r$H]w=?4"bEsx5c>^4nXM ?<"T_f9d*D:xJ+ ب:fjک"䘰pp~ %bĥ_eX=[O"s17KP2LcՖT1,bO }y1w\L*`::w{/HKZLJhp@.d+1z6&-5j1XxNuj,IS_7׊Ձ`J'L6!kc@^3Qf~F?tF/|WK ) j4J)evԶڽzUDʊ=ŔWjp$4|mu|VgM׽wJ=57wk2}DwXSIS3}үh&TWRDܱ֤Օ+g hW48ylŞ!|tXS2+|bs# ;]_] ؓұ/jؾuPg;>}Լ}Bj4"0-YQ+WER$,gM WZ憎 t&5i?9CȖ{eT;[3vR- аkء_Uڟ{w߂&返|X~vTP{M-~\4ެɵ)"s6cԲ5gQ k=N|b۰d]Ǯ+dth 5Яr"W PB̻fhwG@k0YӠAceTrk7:dR$IVO8|[w]cvTJA%x]3m_DB55Yކ3vM{}aJ|g ME kzioV'1@W.99iuU!MԬO4 ^ܛLWs*Q7>8[m.BϪs7{dw"zvOub#W]*P1d $/8Qjk$I+,ֈ,"zK)?HA*b 0\$!T$4VI)qJ2Nt@FRT$DdL&HeR)gq94AF*!"]UR0Jrd>GEl>T=lXsо=*[U}G8|:_D")X:< t^tæFxF^Cac, B?SWبYӦE 5dW )WGB<㟼L _aϺnԍ?rRɳ?loۗ @a6-GfdէMeÂ~I ߿r~?77Ʌ4>vЄQKLٚ8CCh{ 8c7c<g2:+bZ]Qm-RM[+֤ST?K<{>H*ʋ|6WS>RsH-iZܢqF͊5+jԼq>|( i=!BH?^6{)횑T;rWPiL3zdiMB$2<{t)Hffd 0SPΤ ԫרaƍ@&6iܨQ ׫WXXPXPPT:d2t&JAO%)RHigS_E:@QP@$3θ‚L .H2 IeRA*j6A|#ܢ|>pՌ޶Ǡ^cd$D(e$e$D0aEQkjkjdkTTdKk-[mq\Z8M6GTgl>̅Q6c_l#aIS{ V !?aO3>S/s!Cx쏗͙qJJf'o%/}Nؗ/=7krv֜W=WLxyյUǝxC/Y]^|3{~7&{n+ϽN%VO{p%Vg\>wK@qSscVDa?^>gi`qǞ͹xu*Dxn+W,yVV 8gg=ƭL;)1O!)ҖBi ƴ|0r|&W]}pաCPUUU]]fCsW*b GΙy Э{'g:خӉm;uk۱{ib+gT\1:dȋ;vߜK^,{A*t^8Q_?7YPU(e~F 24_P/xHDRa|.:\u`{ܿ79՞ |UϧBO0a*)ʼnF2~pH9\S}$[0 E$H)ƹ^:DTl2cg3i[|}?{BEJüR*@es5Q$(fB{EQI"qs3.,ǘy&1&Ijp)e )v(j_ B/ȺQ7Ft:6=~~s{>={㞮Nq45cׅB',|xcڵap%؁Gy~AUW>2x;?!Nh0 Eju){<׌,jVR=m`c\ <1QqH!T)߿~OG&aIUW<2hr5>y[x_?8N4L ^@3 $MEiRjli-ںUʘ=,e CildAIFY`~U{z\@̬@ htn59P{rv!3XPH J arYCEưbsG-xqIU[Wξq{Y k-5KO wU%-Wo^I] ;tњe-WoY9)U*~xkܠ9K\آ-fa9&01W,(iPUy7NZV9J^ܢ~UUpc>D~㤿aU?pyϛ?2t[?%xq{tI:8"8LI9mp܀olҗ`_sG|o^%"k8I) m`ٓR71Qg-r9S+Gľ=uӳZ1^׃ S*nlk}/ jѐaor{>DS:g’U[W>zwv?QZ2vƲ:lV^>DAn{dj*?]ڵG1׬oVyih8wY695L00o9+ͼ=rÔuaNZ'Gd3$w*{&q[w[8۶;;@'h- étt{Z]㾥CEʂ@D;.0wyϷ7kw1Ʈ{pn͓7= q৮YU'4LjqßYswqLj%Co '.=W9;G/۷QڿoͽY~u5rp=.]ж8{F9|9VvU'߸@ŧqۅ_^>w~fMf>YH2عvywr&[a{5C:(q(FY<Hi ܈l7.|O 0}{JIARr{\p RJfA% f{OH"vƘ"B(煔"}3 6RN֚=jje= 30i:gUZ[7ΚHʤ Lk\ i o"eT(;>Ȋ3"G`E͞M^(׊Izm1Ӟ%F(2j䔆tkdsqEd mphBi'| ⒁D]`$dW0:'T銝^ZlU"E=S(ݷb'$ڄMa憄!W]_n V"8kMw.C3 4r`k9dEٔeջrQ[aM-)s+ZRV݇PBl/tR}kܮVK~-M' l^|JI bY"3)ڶ=,v3&d$mos ퟘq+/E6Zbk y!QŎ-ΔϷyNJ)%9OiPtI(I#>sLSTR"ː0$JC!Ƹ3ucLTBRWOm^y.ƹB!mGl|@l- 7mmR#/,,LR觅SW9j EPJ!V9#"H!H)YDߥgHj'[:z۷9_O?5qYy֍Q7βݸ1)6cQ#" uh4Nd4D)"Ϥ{|kd1%cG qB@K &͉;k:Lq+@B;E(7NɨPr/NK$%&cSD%̎7#!ںp|-\ F!0P>纝2U?ЉCJ)JR]C0s qCdq;PP9W uQr:gFy5Sif*i P_ :ڔ1DOT< [-*ţʩ;DNȩLHP5r~ IFX"$ͪZDDf/5=z<9.IAD^9pƔt(/ !R5G("%f<(BHEB)Pg H'BR(H09c<#qHCֵPH!'I핣_8]4y7.un4mCr/f \asi%HV9&N#)IJ&dLp8,҅6+iU@gsΘJ( )Q(TW|(D$({$#GBD'Fc!z\DBA !0,$!)ꑐR)} |OA3U OObunԍ0pS_kжS8h79y~TmBc(m7&N5~`O:C+fD덱t)'xpԂdK)9R"s'LX6|w~5&4XYSdB4"la'qP$!@Cxx \``mf z0q(!'kscxbJU.R11vfU:GJ{'nr8^X? ?QKm(eN9 D­IiF$%K*&v;$E\&:>ueI o$ A 1fH& 'H>c5o Q LRźTR cB gG]d ;q d4}'EVĦd:R p~dj˾ha&w?G![(!Ɂ.X43vhҾa)(N'&ۂZVV ;+w,C}I<6JӕL$Fb EEJI%$=FJ(~:J'y'@)6lR"l2;cLF\ER`RHc Kz r({|#qSAq<"}}i a$ٜC 1qgs qZ]ZZ_RR aL}θ2ߔy%unԍ#uCGK./0FYLlAVH|ҍHo1+;Bȋ['uݶ'T[sML'w(I ]q"1P""$LDgKdQƈ(H&-.n3lϕX K GkJ9@% ̠-2W uL`Z 4uQ2RO"}ɧ!\vJWő\$287ݎ:MdfqR4t:E 0JH^grvA3D!e>S|0ⰺq% $ 9ud^8:攜M6GH6l#">Br܁Pr U;iLIEpgu:&]c/Yޙs F׊(͙4Ě&zbmEHt^;i3]k)ɖb{G` $BG-Z@b'pxA1{qЈI ',=1=,$VK]ON t_^\mt7R1CPH)')@Yb9  c8V)񎉲GnL vme֞(E`!R-#3UB{jWjs,=R|>/H*.ʏ R){z_D 2gh*k@t#PLa9(#)r@"A'py%yȐHI|.sR)@1TJ()|E"T_)<"*Uv=q@B\6R~]W7w[U][Ϲڧ܋ti*Ho#AD"TU(6^PAhJHZc/BL޻_n=s9FVmLA+X 6BkmT0W#?eU,ݥ+%ۖpvD0H8E dBxu~R.T[9â֣C'ƭ|la0JR b@YE` m1e *>+"J&MW&N7R=~b[r7rֆ1d;Gcc! !at(O]jM(xXp3XXRaȭ8 k'LCĀ?E CT1ae 6M Rs+#Q,rllfZ҈5= r_nHm߲NԔERQ4 a0IF/`BD]?v@Hq鯾-m8RH""i\Oレ0qbm`$$=9Y7Ԉn)@@d<1u Rޖ)M\2 tLG+ӕ}l+[CΘWaљb06HCnRҕ=%ԮO1+WgδmUjֳ Lu.X>nW`d=3ͤ13WHP@>@@ΐ39ղ]K&Xg feclbnjrnΑ [QcNH,Zc u2wG5` ZVk[XJo: 7Di*58'"֢Bt:#"RX$%f0'p! !SLp%p"C"K6? .==O Hj\4cB͍ A*J!0*RL*,7 L=^"SLܜd)D&P!(D'=/'1!)I#ͣT/uʤq3*:Z.eTb 9g^B@y#mMA*uz!S_N_>E[VgnAǥm9sx4"oehLMiSpd4ʤI]K]#YԢ [tz? $ (0)b;I#q dcdÑQ= {H%@ 1NGNTUO"B))$;grnJ!MmyP*Q qNf;ZT!ZZM'`#R‘;-%cla5kIj-E fX| 2^ FMs!<9vslUDnj9φQ@nW^TL.߿O{uܓ  mk^nbV6ųkȀԨPͯϝ0/ݘr1q6q+V75>|ɜC|I>/kIX,""V}:erVX6驗'?8t_\xЎo/zf )r㕒ZI_sA2L%cqtK*9g<4dtDH=WsGƁiwZyުr ]q};| ӈuNӐ5ȕ2Wt4ޖ*8cY]e<]'J;w+/_2]ph+OyDbw:yz&/(  RJќHT|`;\_61>Nq#^RClxu Vs.5OEZM[ׯ3W FRgQNCx8XWz/ .<[DQ#VRCl\:s؅_dV;ӭgK[tKu`e?>/nv٭qEuJ;\ڤ_˪w\yq]}?iŲǟZ7#psT-y_8Z Y^a=^]WF?CoZAQjzǒsF+0wsVTeVAmsՊ>c"eY!6nh[kU,~hǦ3ǎZʅZG!("h|ۃZ]}9_tܓ &VGK^]֢[h%ck_:u=l@ͥSmP7b3a(l6A܌xRT2y ֮#!me [֥`P(%8y3] \"Uh̓ GT+0;z@Yh @%]eC6A;2B&s^zHNsu􅭦UHTB ApL'!C㾻?]\FfM? &5stn&m甪tcዖodL'f˳zT-{g R$z97<>=bKͻsؑ3rʰaXa{+)W&j:݈ vR;$ N!6YY$ _n?VZǸU&,|zS z(g**!]AcQz 0tz@;?YB+'͞5?mL=>-?fӥ+w̛sk;-= q.\qݾ;/U[xcNvgfyGyO^L~c^Q9}V9\#K4_u{}>?)]ڷ5#MgU_tn Z|=7T hT, :faEq$YتҌ*I+UvvwW<9ƨMl7!y&l!2/n9GyR65lR.* Ɯϝ9z=y2og/\v¾7ek9.]ƾBw若g4dWRIN3clYKP8dٜjMl_frKuSa^xMȀ FqX®̸ri ğyA2LX@TaG+cRJg(JqE*DH$IEF ( eh81P~6P*~ !02zq!4\НD7nkKR'ĸpNJ+BJ |?cBx"r.nF@:vPHx\)_B NrxC]v>O['"͉~w8ı't8Sԟu=-ڊn-rKqZ~ݽi߼~r=^|v_M=2_B[7VڴuX]_aGÖO&uePN=ovttfiM) o=۷ό 2D5BE`$bo׬i(tF΅yT[1!< 2{ ?t=:G%[ƿ7ܫz߭qCMĶwӢFOZmY)zommϫӷ 1F.ʤ50mb']*b(qu=d`+מkJ3c)Rj*WHȘ?\ھu./0Yd'r#\9Hhu7>e/]_?zk-&7 zoY׼[ޥ 6{k^=N9qWLe9/unÏwyrM2/1x!OQ^7?==5dKAƾ۴6g~?/7o='R Zt۫cr|W?_T[ݯ]4gvֹ9շVwsTrq~lXO;yɣmo\^{jlųtfț~6SrFQg'J ǃdMǫq}/јO'np^/c_ūYOzzlӴnr}[^6noNd%֮yVƛ~ӓzә^z ~0TV塧y nu߼[B亿WaVo)^яwhzInx͙3ZDuj>J}"(u5Jq)V@mڮO.*ɏsDwukHkqw];KAAĎafy`̼10k5W{HI":WOY3۱ǯ6g 8c/h}tlQj̞M/>3|ҫkawК+ϛֶOdVA֛ښr΅Wjw+j7}Cp%7ZKcse(!JL+&9sȝ}fרWW6lpا#uyN ښ1s$LZ/Ȇ$?|CD?76M0 )KhY(E$@LXZM+)RɄ^`šB+Cd#L@I낅AH" d) g IDAT  $%)'x"%!؄ΡsQ3"J#둄 ,pA(" ЅqS$葶7yŠNO4su7!dS 9ƶv|x*~=ubΜr(-i'1T8Jw?~z~ Meɚ<ݺg^#|Uj"?֬W]hkG_ .c.yV3B]}Jb)( ÑZGoiuÖb\eL?6BDK?N#0H* h l8|U3J(aڄt)̜s3^/?Wᄇђ@)F';鰅rXd&mxa?Ӷm>_#|wWJ]3κvuS9koax.c^\<kw:uAܸ3|;\κL9hy-?Q29so>;/zzMr[oafn?F\s% .kdývӡbͼ@Nn-I)*{ۨg3BSRXܽ!WU.aTRy~n .׮-ztxW_TjT=~nGjm@+7g]RI]oMG:Ұ cJh dL&KXqCf*%m~WnC0t؋5vfq/@6`;rȋ8[ tڝ Rik'; XF`׻n|8љ `un -?|2CzYZbw8[מxήV8i;80Ԧ|N y C!ynn䴥FLDW\DJ;Mڦ{϶ۑ.WC#3 Iqq5\?A4iJw5__7ek3зѨٜuMdϮFSr-3ʕw=0U8p|wY DsP]~U(}TH fh'pО]o)dčoǸ `R*B@~a(%IyL #WGvo5+XOk=?셣GtmڌQۚHQqcRmg@ip.UHsھ{g a1>d)@NVk WchUl]<'UJt*/*&Y y,OT EafGVcW1 95;PWK{{?{h>ȇ7p{yWy_"8stK7vu53>]Gw+-uVݮc^ h4K>W~6(I.to>/zJ=^y gvԮVZqFrh Н22qN#S; H`N6wnu,ϋ"fR57x4)#"*$غG}Ic{pnAB.Z MM/rX[$έ.[ݍoeٻ~ 0f~Y7cx5mx&/ݲXv?yeܢ߳'bɰ3FYۏ^:`OT,Q< CQX8n҆!<qUU'-@mh}ȐsǷRFb1g5k[x9+1%*0d@/{=_ Gj4K>ڛO@;=7鵲_M-tuꉳn g~r6СoW=rMS$nXIEpC ,MPC[TvQ4Łݯ{eʇwmFf$n1DQDJJcݣg1pn{m 8"T45-YLtyg|D.+~ޟ[:{e^m^@F4Y'X;q冴>Cnvg^npVtĹ`*q8XQJA*7{0h茥3O}I [UPe_۔Ι[S;!mH\$欉 AhKcz0 2Gs Rr˳N2oÑ>EgQԅ薶9P&ilܨ jg ?wٜ}"]U; 2>ۖ^Y9ϺUK%:gl׋BL/]-?ڛfU^`"] ״yU'FYn`Wfso;=wxBs]Pt!*,u?;烉vX9nq+:\jy{MjU;^}87O-4,L]ٽ'3Ml+vG1Z Q43VhJюÉHΖά_o{zi޺:;!XA?Hc,˹{Qw9,z)rT )%RmNئ|[nxcA;Ȑ2uz]yq/ Zk `T#c/XtjrʜӼӈv,K)O.$4d-/[jstasA"p~2M\0[ ri!8!D\J*CoBP"p _J)9]FIJ1P@N /ńH$REg L ݛR|bR)!٬~6 )')%( L&(%Č1)T ^ti CaHbSIDD2X6+ L"SJa(ez$l6 <)3ቲg?sq9_O\=uͩȿ=^S?9žӏS?u O@IaAQVMoT\E9%. 6I*by/.h{lP~з5AZ=_eSh0 Ej*OM pQP uR/87qJҁsؾqrZfKt)"Ҳ}]kAd˞%d*^3ku/` 5^?J@[Ḫi#zLi,%+T}yԿt@ vnb&Hz~ȏuw}/Yq 947wCAزJQLH+fgv N1VN*!fslO&Xj%qϮ^l2f3_y-W@3~OJ^J&Fv#}+?ܡ~%rrdק:7/_-Ljr}uKøxzQH~Z}Կ*EDD!8`qfU=<srr8j݁&ʭT*I-yaG=J߽4bQ =ꡃ0JфR4.860F* 2.{2Į jի2g,1n<|ըЪO{5tx}J97o?ZjN;uQ4,WOU"cXo'xo4-/.&>dK5]1Nnxୖ|g"pS.MoΗz7&RT >@bL 26D?~ 057514i8Z"Mt;Q] w$@B 0I&&AqO<_b Òf/ ά_W55uVѝh4}pθpb/56 4eJ@߆k?OW)O͛~dK~Xxq/kn:/2d by>$ϸqyAKZ| Tc ?x{b,Zs't@Z&2`ЊlvcASI%2l&1Ĥ ӁJJD"KIˌ0`JQ I6ql|<3bP N̐a jcAnn78obh4&Zz|B".}I3s p[|v.Wn[㞿7 ENy7{׽K7i錅[+]m oߗSfG`l ?4v˞۲됹c:PM{Ϫ_=uo}YvW SvG0vʪ^|gVoܝ.{;+)lCcf,vDnstس?X6TV&/fM+7P9YKLOY VI"$I+ب㬀RZ` MgU4jXvJE9G3O}YտYR%ESZ/^qe-0U,pS_lؙ{f;6wtGx^{^{I]5tWj7|g 2x=gLo~WOYk5/br,4~?@۟ CcX3^w  YΣ|_k;X,b1]ӌnl֚oy>=yKWY{(k^u_Pw~@T1 J,pM\Rjw?1{~nw:O~7 DɷwUo]pY˵!yn+ rʜnCfLq)+̨帑mۏXJ>r#=@РώGox~E Gaz&>PdšcSkķ?>} @ΣG@^ߙ?fuќg72/d:r49/ Dc4YtSy4i/VD Ӊ(BpεRRfhjⴿ5)0 $)UAV@J L$I<(]+Y|4,rh {2L%D"L$iL<_tPJAfA3gk&XuL" Ii\O$8D2JT*% P)92%2soN'mE[i+[ml׼^3364uk`>ָ.7Wk贃ZLsޱŧzz \vtzGvmzucc26׮6cr2S3(R?mXWf-0l빵OOb/tE~ΆFFGo7XiTXjܮஷ֨PȮMKg j?wnb*DvY%jָK(`О75jPx:?o?-8|ҚY@Coyѳƽ ض$v ULczkXTOzⳟi}mt^r}>=l_ٶe9V5y@DpNܠrNz'߭\I2u ?D&f,D4L޴uc̙VWz z;.}r-V@NJ 3d3@&|uԁ 'ظӐ1QR^:b/9yS IDATclq-6+ ?+.۽Oz⛃YDvumV}[^2r+_ah`uڸMz_y+f>5aWpAG<ئAw}G'?/)}dצtWk=OW7_Lh5cjkjvnNdyU)?TZzJ TlYVMsKj^7UhEH8hX[kT(gUJQ8и'jE\mz5eԄ_u'9/lO6ަe/]$IK]$?nY `vB^]]}sƐVTZ%2f_PD:W?ao֟&TН?-vF6S.X"Tᾝ?ǿd -t]=7G;}wɜ1 HS1w#GDADX'v0-zhu7 u*"I5^k|"v\ݶ{,zvԸBD7;_~8]WyRO^u~O$?oxϙl\nڮ{cCctowf 㑙#D}S勧 l\s0c3H69^GXZD&ݱ#jw爻-/0vAJII@}|`[3'fVDa* ð ~Jb99r#T($5 2 gȈ(RJ(,U1D"97?anN:7''LAA(0 Wa#gHHҌ^qNҺ %9dRx2 C%UD!p9B(|?c~KU? mE[VjDXhn]C:b)a B u]2Gh:<-SNV"bA#8 n135ZLhvԥF e mGE 4TD)@"YYӦqN}Ɖn.OEX+AuηvSl#f3*ַF(LwYhI#bB^JB&ōh*7jh]xB1\,2;.Xge#J2ƣ,36u.MVULwaӥBs u s/$CJ4g㳃h"^\=mmژ#" _v2j3K-T,5pK=U'#9&ѥblB?d:|`co<]λbp7їq' Akvm#3lS@(?0~D@R&Q,)6 f]\SKx]F sO _g(BYFXt)Ebaw#so`.Y,T9PynƧE`ˆu~w73٬RCP7*rn"=[u`gM2RRʀ#gggD: RIƸT*DMdQLi$5@I%gq!G8L c|b ~&abgx4< \JR\SȈ d&g@牔IJ&@ !87d.}E[Vmq[̉$V޹:XpQ:760W*3-{s @Iz23Bj] Rh!cz#FT1n CO bRjO)QO)j׎3I(wIil @(XC!lʠx*ֱDJgrcm."lG@F|IĘ@A2nĜ&"B%r`36^ܚyj2>*8 7eFZxֻZBs$ĸ^oSo+c&Ce );耈i,_ysS\0HN@|Nc 5G\WG@v:mѶ"C5RE=#JQ8C;k&M6#1#8pPi uֻ3&b~YCҶec\Zƪ{OvwZ5ia*Xh 4lkL{2ι@ qb3 ns2e]/%ӪLj#e d td AVUfV۴tg, l H;۝s1aƶܩ1j6l@lqW<"L'KUB`ijۦ VgbtK rF39CnL#pθ b@J HJJLD9WX0fق챬dHj4D# ~B)=e@SwXJAYL΋aTgƑBq{hJgSRj0>GUm29 H/b8OK꒭b=v"đ8!2/dh"(lw!C>]E1PVEh1Fܼ|MˆjlmaV>i'#H 65(8PuA4$!\͜BP1qYaLm֍2n{I: k1Y516޳ fr֊/(pcy;(>3#PJZdtuE?0(!p[8~;e#a'ь1黤 ТP7FoYnLpN֖8yLbQ+.G1wW8n99%oT2[Ф`ňxOE9f+Z]MPЫrrsZbJړ ,:ak#_m/ :uu܎fNYīIRz(2/q Mf)PW҃T*I/nV0{8C7g\\( A=Ȁ %" Bps!$)ïIJ*%eam I)`< Cƙa0_!.e:PBw!ÓVif_oًJusbi~d!q}+LdΑĖN mqe"6-WHJTd+W )d<צ/t+_~)` !p#aǬHJWB`#L1m7h^8*BwSA,Ja2 D1chb1ӑ1ޛ2׾#*M2 E|D64c2UF)TnxH/gJo`LJU R#ϊ/% Rįz2't񯄎B]U i)BȬ0DײFDQ]ڈQErpjs2-&8 5"In-~H.@}? D@Df[[Ѥ"4QƐ!)Spl<5p+Rg6n XDB8BH?W1U&s~h ; 2{b9QDbFz<q3k?MTf^E~Oâ4/>1 Ul<_SbXHmک*EFΣ=BgVJًu$@J%RRz<^I) 0" 8K$D2ᥒ !XPxc/@,)O} DR*eVm+ʗ) D0J2$!HEfaȑ 6z3 d(M ;d'_"`c-{Zksn CbDqN^' N F(3٘|:H ayM]ٴQ)eN"@D1h~ *͌ (>$~wjl plK^gyX~ݿ:ߥwpAeF"eZP &v)2Z.j9/N%G 6jA%  `v%QæZ.LD͋ g6¥X}hVKl!k4(hx\k EK^&(J)R$-Aqi̙ tn >> I?A`EkˆM?kld  laDDaZxǥt P-CO;D'.p*" Rf3BCll;*\nYRM  h>{"NC13`"k/ J%lndqn㣂k/xo݇idV UπҳUup@Hifb\ϗ0ײX&S&@T {F. }xfQB(h:@d[8B(YɄsΈmz Q(lFfzաQ{*T=ǶѩUt*`fEzUpxpf8Q.CWAs5Xq,lj}[G(=^yS1~vJé@,|5i De˚U^͖b_@϶,o.}#),C"21 .FD\10W A@rN)猐Uˌvh(I8f" (PΉB|.V #Tr@cdIbHt"A"$C?Wj  M.vUJ!\T UX%Ըe?n}gerVc-Y{*n^rg.iW2W{Бf .v_)[H:5W̡7$$J=b7V.Da5@Ձ<"B"9hNF4}{Oˮ(0(L1tI#+W(\ `(4 Ã5NGv 8K 0 L@CiuT'Y~R xP6'/qq^a`aI9 XDG%"6ٯ>tYH;sW"ᅎgpvD6BW+65 a~7% ubm:>B6ɵb+REhԴh5G-'2,Jє^RD![7"ʹS,Dj*Y4%jHE?WbsůRfITsЖ2(6L lf%0Y_"ynavU˯9$sG@vX!t DQʈ(e̕q^Bsj[947ȤjT]Y'RTY5@AP:[bbS8A^\΁eIn]lF.6u%PFܑfX#N2`*ބˆ13#bM @Q1VJw f('sJ33rN K p,u}Ґ!̙>!uPF=F"2s49sֵLn)@qg"D&BAXR┲l;tŬ5_xԝ+oeL_|͜ؽG~箢wܗ+O=wVϟ x 18ZqĸhZ.F#3" cYt UGl .;}>(^.SGF5H+ mq@0RD.[1pZڧQܩT"47(GNj#7'm45Iih g)RKR BF,z\{HP%a\ίz1v(_n*[2Pc}kzD+ ꥼDfE YxFKq4b "H1](=eqVO[J^k"[ʱYtnR09{v *H'+mkނ3b GPP&B?~N@l,hNUtPuV1,AfEZAuMaAi12+9\c'"/ d(H[vĦIZBSk]jw/(d ⣪dtf"%š>Pbua2q _Z̔H(Y^wĸ#p֕F$u ;7?:+:6$! ^]RLgRQ΃o<7f2vtkGNYr޻<}0H$tS3',uOϩW"do1.3-7 XE*O{EBCh/GBr^;MX\iH9.ߛbc! :WDp_X=hU6lДAO(Il[3{rm]_޿5&A~ ]m7 G/Y{SSW\}r}?/5c^6^zYo>W>싞;M+_3vp4Ur 4 8]Ic9RaW[] t2IѠќsJCfZSc"~}^<_8C_AP&JhI4NK4eX:T\h36Tj+nRn%C+ 'GٛX P $Rc;-_[#9#[l*u-RL`g["ѼLwFȖzhVN $ 3\#+E8m;E8K׋fjS쥨*ET̕qmHAmoI\Ru{hNyn[G|B1X7IRkPZ8pDJ}jX WmJ8bcEmjc.W8W$9'~8(dɡ T8QM%~ IDATM*=q$DPp[ Ο[Pu{98.-jsf%zs(7+e{.@\_%3_Pe6뽥@9 TƮM@ X ޾ND4(9?Q[L#HᏮ %S:ƀXΜk|N<㔡onْ勍 \'!bBT4@ΐ<)r"b(?eYiU+#@nCsٰ^ #utHD.b?< 0[jaVlay8Ð^rE0~ATY﨨$o~rH9w"Ǟ wïhIj뽺w}n]?;, ?#돆ˣ~ O?/=c?Xݞw\H12申"j#?ͺ?Jk͇.QS*8^ePu,4^\k ҴjΆԒ!>pף_ϯq={9gCNFH"j VѹQO-RpxeVQmtNsFi&x0`s/I;yuD2_DvD˭l42͆:;V  @%kȅiJbw=kkM ,HӘ+ce_V(#L*Pfkȋ$[rcݽ,ud)-p2,i^ˢjιĒ0ct][dJ#"Xr7Rܒ|q Q ~DS]Hw!P%&uœ%ҕ]OhjH`*Sáe TAP:k=r"@Yej뽀!Xc"KlU׉;+BHf%z깹 >k Q ,T.R ppy( T3u,=3smA RxSaI@)ZյcS@앱%M݆@D @E$iH<$1R!c4 jO&]T6,p-G!S !J#df!Re!ҧai)唄3 vq/z+"!Ll6M&za%hAq<% EcqF%Acu1F\ &ݪl2MV-b}?ېE'>qB뮻nIyd6oy]Rm敗`liO6],sUXdv>{uWqۣxO=\pVP5OxY#p܈##_Fk^~g}'>dm퇾k]vxPU;"7,}|oя}?X3)>(v =}ˏ9b-[FC`$D<⢋wxSO&fm ~7jJ9vE4ld hXex_FsMA6 M'b avlK0CqUcR \gkؒ$\8lM,ل^.k}r9k͉  j W/E(l#U̗|:k=bɈvcKlCg$G\$ryYD5]w;L1%-,OP||(0>{c.t+bM "l}Ɗ#dX@dA)DN28mY-+~[_^S\M#3zXHr jnmV>pByA%"gVJdrQC%H;.ZA5"=7oȼm`nВz5~AD*; uD7{Dgπ0+!"W\qE]E}x0\z@:RJ !͇Ţbִ"L@`JI>B13t2.*~h &(L:`N)W?~k<_E׬k^޿XAs@G=7|!Oy_ُ}o>iu A[~| 筻e'=qʑr9eq 1X<αs_oK;_~K4}QZsRr 1X $a[FPv%JAB5-|f6CV3ocQ 9"DzƮ5YUH6W#Šj S/X j)q+%,NUɉ!57Y KbG效K"?j"eQ.@o" #S9yEAjc_ pv8X+ jNIͻm)Hi+n ֨ڍg#?4OoVmf8a5SJzBۏmb#>GuXc׮hmzȇBp\N;Q-j2ZK<㱖HwBKZY#kD (FU}ZDMJVI(Pֳ:Ջ枢3x,hh=]62YՏpY  VLGJ( =U>7z3'?{GB$W{X˅_}5?O}fƜrB`@9dAVOޚxz2n&;іR27 4EW'^(> !cXkGD <sxȵh.FGϤֶHK `ќ1o_)gDFt+ǾйVWV5Jc5S`RWNiAmGpc'@csm1JG%І }(UK o"Y#+h[E=ȨSOԎT nK+vZ AcpO4UUi(ZɔCtU Q2od$:]&;qSOTGwop؍YJBD1a)@l ۴i1K uq&%M. l^L_Kme^f(YUv@cX*?Ne 8KA8ERfsQճgo1(ԝVz=.Rxnjҍ6QaE/jd2aSNt:Vy!3 ':%s ̐F@aH A1>dm0"!aq C?I?H_0}eJ8CCJ9g=d2bvBCD`Hiom| ID(o߰>ց CNg鬛-7T+ʱr:o {ߗݣ@6=1 /n %@JTVa:!ڔ` @B-.^ bka0 OD亞µqaSK996ds *yu,3uiأR*21⁖v8v4ˣZK<40V'cbv\#jIŬK`BcZ%M8U[:c̨J$3qb]j &TtVVO,-9Bt|^1{1EE/:VG XBQ׎% ='%(j'1D  ~+ʕ[.A&4hKwޡ*7Q:g<  *3.'-W7p$Ӥfo+}5rzŅ?5Sml(jO,)%\QŊ YGtDAB'qF7*Y4YU `gb,{$RBj"K!fުO9kFJ2z7Hٙ=.Z#=mu< mn|nNP<^g,TlSeX,+<5S-H֛D#@pV:Cq r-8T@E833s)i& )~9",!vl6M$v,)^vPgR]c Q[D9W6b1"Rfg[M( r|8ӡu]ljt IIXrD!|qcd&GJr+9R#W|oV-~Y}hW傋~/vy]FD_}~cnܘv!Z!lȼM[pjw0`~~O|SCs~g_E\}ZZ Xޝo@\/p^v&m®撒}fgWd"I kQ'(M]X"K$cG4KtM8[Zuv 'c Ű XjXfO,. r~!bⷶ.*el 2,DD neO"PqW(:c,|RlbԘWO 'ЈUe _WRTpl[c̹&!ԹeW P;Zk9G 6 +v]}TF1ތ 9 c\T&IqESpf.LDZ>qA.>&dR2G;چ6 jEY\?bN-֯GEFY M.HEu2ѐe (ڦU+! =sXT] o\(l#ze#V&?mE6PNPD:U r?C "N&ݤ.%f}wH%Y1 qիB Uw1Z%䤌DAZQp9D 0Ai+;[%d~|qqb?4 @0 ) yJyG;?Jsӭ?ǭ.s(Oyx^,l!{[?A1}m#o?|>Gv_kRyXR:']Kpۇ=5oi7~~Oy>ZOz>7/{W^w'R(&|"%"5]P9A (LI adtG4Va,J>Qϊ]rhTm뛹:NC0hQZh,P!ʫa+  p߲ak%yN1W;UeaɹTzLKyңzْ[j3zVgC&(uK|#NZ/8j.=Wrfbu!\0sJ3 b1ĵ,) TإI0TmXwbh:9̖`r՝B8ӯxzƖ4n" }s.1ZuߡkUz̐ƛQW6(P곔9guP@K7#vE2eiSN90a#L&Ja~/1.nMr1v1v,>y*>rDR?pJ#!g~1A ӸjaoVaNl&B fN)@JH* "1! Sꉨ% gtk:_D8 i>~ysVY0ªt9w] 1g8Qߏw> M[{_V n'é~էN615Ͻ?~O(@ſg׼g?9ϟw'[uݺY'`Ěw_?n[~po?d"% o~皷?wрx3_UWl4~eRi-l\`_jX p>w~m]3%?v]t^*~J$@J@7@@bl3c(t2 b!& bT("RcZg%V*E d7+4:9vơC%М rzE9s<ՅRꢍ%* H.BjL%圫bI>pyd"eǢmR˜ -/*)91YԴ zPzEalj}QalTwMٳ} -}:~7_>ґK" Rrlx^gjFgzBQ-f#K33]+eNv|*:/(B`[U(WĤW 1/T!wȹ|N5'kӈ}a5^3HZʤ„ՉZϓZ⑴G2x(g[QeYkeA庥]rMNXr٦U JiU_Uy[}?蚷x!Pb&i{\a祖@y}":Ml@ d:IPgXy>,cLg(v`Obχy84R9 $X20lu]&f d9gʧ3m$o95Oh5.;wYgkwrfBE4E IDAT"" $Dy{0A]F"(Qh8Ϝ0X<bfV0b`u 1!81 sM#%XqN)gu'o}N(QE?=1..I"Qf!v]'D]-K'RHRB(o"7p g~n_$. Wd%He~?Yͼ,/Ny{vol Qsw2?y+ǽpp{J^4C4By.)54!@^8hRo JPJTMgُ[s)JFNV{1豿T[r$Bk,@h0 VG&0:jF8i.D\G7*h=1R[Kc9gnbYi $gvm(þەɤH;'SZ|2dyAlPX $ 1Q6Ul-^ QsrYU`$R[kwDBE"!b X(,",)ԤN$Ci j]5ThK4etczGDOSNƹUDfu5'T |%s1")Jʠ-&+ǼơEŠ2 &u|q.CKP\lYW(3NtZX%\^Cc%@H5W2>eSّMJ=ci0+ +ieQyڍndFW6D`7&[`w_ 9z 'XL,g4ѧwd.R1OhTMX\-k, TAA·ܶB {`B SJOp&@9!LbXX>h6@YB quS  UEcD9@Jr䐒BY2.mNoq?= #B4T j̜!IcflaVDZS& !²aM$\!..Lg1F%C#^&fA6ٟa'K~ͪ%]r^y3gǝ~el7{mIsMݷ n{ ayNgʱrGNjŌ"BjQjr9ڗ>x(6%t5e˔KxIN$Z8k_{]X:madID! v-] R@Tܢ+X,;"gNƕ %քwi r1 )eȬW؛%h*D &IÛ 2JY9U{YYHB1Ӿ~ƪDͅ@L+`kԡxT>RDr\VuJNA5^=j%YxHi%%qQ؃p𪆃_m1\5ε̊PyIR\v(,\uX .<2g‹?{,Ƙ TI, P'=,,Iv'gqâG 1mQms0B:ZK AD1URܸi1VR]+YflPAge' n #Ue7ӷW4͖F mhq;ͺH?XylUX`#؁ GGPSwBZvaHYsLXHI$,|[ʷv̀D!bN'da!B ] bPcxq/)eCN)#F. rN9圙S+!vbJ1[d&<͜ )aHpG]=|W^eǖPw߲5ܲ9ߥgxgWgZ9ca:KX`$3B|r``Fi 58rVN& @i?2N)%ٱ%: l@l+XMOJY$ µ,%ShVQD M8)%9+Qn@?T lOd@:mou@4캮/BPCK,Y)Vo*,!P)]Ӱ_qF:k b:-Q\|T$hAU-)fs43Xg3>3x2aY.")eA*չ-')hUY"b#iР/ӎ4% 9psY Ш8jХ[h`]D0|6^&Z #4;Yk[興0"XH6TfLNov;0˼ puJ: bm"+?CԊG2󱡾cHfFs?@o:±$L0*R %æ|p7e)0PEc5r]*vnЩ\pʄlf1y5G3)_vRrԘB3a~%%-7u틹$I9c@ xH(q)v ZXXb3ęyHEQ P '@ݖ<3 )4+@# ǟ~"ʣ,)RJyHIce)F.ߠ9<0Y/"@&d2Mf31t}}@U&š=i6tI`>{+lw ro(h-5]+R BeSX͙5j9,-TlFUkY)5u IQ RBS F:3^R"{F'Mj&fZDZG ֯`g"ƈ\W%OS0‡Z +eJxViM7>c"hb X|f^z< E7~6ky!"R Q ѻ@Ml^lsl}H.HȎfU&Wm.hYN9 h6tVݶ zM! Qޙ< ++ւF.EmIin6c0s3\M |Mcj=~c~a]JM݀T`9v)q %Nd 9a$&qֲxse{.vwݗ;$\!,KyDHR C5)m?ʜՋ2M V/ƥ4T%5b'W8sNէA)<ETb`C?5K1GWd6ڞc1!EҐZJ\KlS|/S8 0=yʚֈ֒ r1alȁ< U7kd(//{\\lj3"-tCAf޿k Bc*ƴHμxmm{t.Q*5W+OxWDГVZ2JQ~Y%(oͧ514A`ߵ6g``(bhLZ\ !z^*\hB؂G$aI6GYTqstL ,ZaKiָY6J'B DzseM1LFSp70 -ruR-sq5ZOUm̜ ;i 8C'TsAx!7Ӑi؅)P `ZXls $v3HV&a%8HY(_pIjC>K~/a-IS7SX,q J $9 d~狋ü,9gecSgy@f. nW+p""Ь`DʱP'`1vD)PNb1I  #@iyCi C+UaEjYl6fU[oj6u]Z4/#څH"B,A4͈1[-߶~1 2s^f;7MwdT:~ 0e6'<%^-ƯOz]fy.S,gpk|7pe;.]ӕc[& E9ԡ SS6Y -@kۯ>ًl=y{$%YjD(f;+MuVkAiHKT]!ױ7[*Z@"6 ֺd@ dxٱ՝Y Q@Ajil' ݤh|XkMɴBRQճrf#l ð}~g[rpƟ0B% vG5&\*(.DSt[{AF>hy,Zkcj\P1bY}~ak/u__O?Ř5 Ĝr(?> ~ؚ'cj֏*U.EOk/?ޕE(Jpb|52.[Bʶ]i@'q޸YHqjj^ؙ0BLt:ƃ⬈2 c sfWG]?qd6 o6s_X3GRn£d4›0CzA&gbځ!Ϭa;ba!3xGo #B& 2%VX'mr*y9MY|֍J\j\W,:QrT 6ʹ?…2 !gDZY;d 'R!Oj%c3 iGiF nQ21PCa1 r&gam֬yui Q81 -FTvS(Ip czlt,̼!CJ a (L:լ_1ƮT8( 0$P+moɕ^:|(#ث\1nC[iġ89iAIE6bK)dc |ѷV}yWkTq;d!Cpmv>~TԿZ2ŜwO+jSj$UV)7Vk8887ΰ4p6g DZ `A":+a]Zq5eAK*9g ?s_ w_k;ni{qmo~ͯSn6þqh:J __5JFsѵj#ͫ{Wɛ6pwF6o{] ƒHJ+j k06zQ9'lL5-[ x"8ڋk#Hoft7iOAe%/5h!, $mld,Ɲ/vhndF[VS,`C/%Χ@JDJ4cg5CǂM>"&\:_pY4UP!ƨ]FBђGnգV K۷eG'~ګ-s~+rA8pB: 'ݤ.v]uT~@dGM9s Q,C]~Ib1Ubd, k|N;!0PT>WiVJBT2$ERꛅq2.Y8sJ1=U9'$B`NYҐ9>-Vaoɕ>8ǣ˜ۀ|2'7Ca+sr>y|a}Ͷ73οr]͘@D|Cg[)7oAi9sʷd2F)lfd"fE[DAW \XΘ:ՊWsq=c5\xidfxU⁇{K{{Wՙ'/x'Ӷ7 :~E{'}?x :ɶO_xΫn{jWsyaOyrn=s{.8~)xkNx3w__sO?プ~kU(mfzSi޴3>&)~ڇfY=fx,RkTrxCqi "RKͧ ;#w˅,#ٯ\\){LiU<0gN[wi9 7PffRok\O!A7S:[;ZEm| XjP5:YM*P,-l[܌b4(s9ṧ~%2i%C;e]xap ^w‹ן/a渺o?zg~׽}iD?y#~_y~9ÞNu}vbuWS4FvQGa:wenvSJi 2P7r+h.,Q쿆2\9R)bNY1u# N|>9O&d89 )Ofy0iԠ+X9IT' ! o(f'{/}3>u|ܿ̃PA"W2U mŔ+>R+$H΃3 Jmtl"ѫԘ0D `Yl1f*,=|#^Տsw905W(";p_ga}/^'~|vxo탏t{zO_q=|}7p/*Mg[09ij~3_Þ/Wq IDAT$Es:.Z tPGQ@BЧ?۫A~0PX`ˀq]@껮IQs:t@(DED:9iHÐPCIPCs5 @1. #$.@yNp"SDf{w >6)oS,Tt.߱fH,5|3,Vc"Ed2Nf1N@bAݚr@RJ,{^"+ʱr7<<w}~Ae{G?){kiop_;='m/>[25k/m}]9/'{MZAl>ީw];f1R啗}ݟ>F_ѓ_%ǟ}sfD|>O;}c?PK>,˟ xѓwuY7U_=Oc쪪{s˔LBH&DNHJM  tBK T Liss.g߀{2swm_>}QkDu@^bu.2d{}?'^9C{Ŵ~kә-o=һ0wٻ&p^il}ou&:Or֯ygOsw'~zga5b^<kCU>̓!w ?>^ʳn|=3sĕmK4mٸ޽enXrl}LNE!KA ]e8jj<eo5n69ֳ.= 'G\ c/[ Z3fcW/ol3T⮟n~'ڝ?|ˎxytgqtqo1nM>qKxMӖCj_OwKˡLќ?5^zܨ[MIootk{[̱kݺУdƊr=act0%3`@G@6!ˢ{f)A2g !:K&ߺ$% V>8s3TT'ZNZ O ,%?dn ܸҀ&sea󹯺u*OĝdTZ+;@(TR*-~,f$*!;Q̹TZ3@ &H%e PrJHjk}{vԧӳP cCIjRZNq"`@u777>iDJKCBK6nv D1;TH#d0Y{qVBΞP o:VX W$@pwK. >^0^?kSvem:}᧟7Щ~gtCMaN5gO=QP6ZC߁}Y = OD<{ah-v,x7_> ~?!?c=I ,1Kgt[NVt)5ӈ|{aȲ-&.Y}ҷ@.4uia  CV0X>qwҽ8dNP}ƩwҽxmX6q:gw)#B0 P6΄9C^k'8ծ"a~| ~bYEw2qT͇mqq,^=lW,gw.$; D)4ɿQ/-+v5I`)0[A[?Y_@#!pp?"C8a|w8+wWG't'G5(՚&ڕ>>וDԴlO;[˰3'jvS}4p" 1]fTv[ߐ ?٫FT<󽴦>k1~#Ozv4Z>|.FSnrfSzޚƩq4š+wn;Ϫi؝'w/YM_6nMSN^~vJc(% "w/WnKi6>Da픭UW~+1~Ց3 3'Wk"嘙z0YWڍH()e,r%WKcvNo$5&2KɞN3>K f0{r EaHUaw ʞ^^L60f|  ?#U U*(#g\Dܜ8IUrL0%kB'`< HRiڮwZ0TNYZ̳{~=ۻsؽ}[[ks"-#0FsaJirRI*ȹJ)R2A>ISXBmh̜rxd#[JWD*MJ$$R9wn΍7yr9|r9HÎmk[&: 4cuU(K4Þ}ּNiW\q]FdSw2 DE`㦎p5Zx7н>$'p7.{Nnry=&<>0ie_L@h~Z~җnZʖv&DeۺYs9_\r]+wmjqgkJG{/q5»آQ1ǣ)fS$pz7Viy]ғN˖ B/}Rp\tKw;&jEo6QJol/%E{wt+܄?=ŚQLذa1Μ۪\$z{e{"%TΌYO|}Y_LNp!dUJzcW)#ݿaw :c\\Ɵf*I (F Զ6OydSep& x )f dgq"tY7{CVdB0@lٻeE=ɪ]7)c(qwp$ֲI)5maŒMTV))bfwYLy̐fUy=G% &;ɨ61 &:z9AqGd &?v%70#fRd"7iC'j=yY9i EZ 8YH~ yn|cȃ+VZq񊀌L8(ʇjaU@#ȰdDȘ]3?1cX؞fBЖJPos IIesi 2w:iaZONjΙ,T+{]VI@Ԫj8D {%iK{D];w2>:iDc*yd@`uGnhWjgeD`bCNOܝ۽!m)MkGQ쯔6V:pK17ED5=%Sp~ow3ӻ68uY-,]y*Tusk(3ɢl 3k*`lkybZF\pڝZ."` iM۾u>d{ouflJE/moK4AˢO ܶYwؚd!gjy 8䴙+RҒr|ME57xS'-]v:<В}r|MY5;XS%-RCK"]>Dno(-Ur&J!Q$z=UQk1=^ݮFQa_llkoߘ.*Y]#Q~`K+K5߿PG^:i--SWX.ϝ,8}UqԤ3gpcXV%߄֊+e;3G\TGy-ծZ#pC?$V2P`O#,3 ~,kr-WE%DT>cF읅{?#T+3͈ARSS`,d_lFmRk% !RTI395R)(E4X\,pƅ8-=A0ڵgScB!rQ.7w"jVnSm.U**$@*+&JTR(#P FGQEs\TҊmK$I+2MF`<( J%MbqGZkd%I+r%IK9cbM!G+~ۣe2݇&jC|}>!}OPom?h/>>.wՎձ:ֿѫcؓJO2"be2SC+]E5+ T:砆^bbH[#R)'Ͳ;fE18|ɼ⢝ uS)9 X/w'_O_OR Bʜ CpmQwOliV ]9HDtWgiws<41oXP6=8|s;("v7q@xls};{}StԈҦ'j5~z/C8KY٧!m.]o1XHK-ʯ6ˮn@m׃JʏQwv[Cm9y%BL9K>wsl s*6U5U+;+t\yپ$C)ҙXtDڄf`б32g׿tc9[yoj>M?4s]/ F2lz w ??!gQU")LR}wu;AYTaa2 NkT) ]~,ѐiWQbJ7Kj"-mv{4_qHD/l.y[̻u:xX[IH) g/í~hSiHLaǑG67&S4CJ#6\V`~rD呚ښG7GŴf{:zpSkuRÌ7.8[9j7WJCe_>{w@ki~ѕ2YT2C^>BA#>*kh7 Zq[%*3T"~lgEbJi:jaTK64ea[č8ه-Dj9l9^gYѭΦ|l]xk@dNr\&8zg'd϶L%@PЩ$I%Jj%L4EJs8FJR\H0$b 8GQG<\pR2,9ڵ~ݻwPg0CD$HBPömwصkn #1iF!"c,s$IvVJ1d\Tih%8* qGYT] 9tD+MRDJ8hIRn+Y2sq1ԙ#J))V<&𣁻I}OߣWGoχ~?MGŇv1aX|i&Mz[_YRrI1qwMey-m7L=JeQO|ʊp| :`dWC4g6a OZsֻ|Ԙi ٢mrMm,tuEfL8ZK5Ï6vrhU""\*l"c/&nyKZxzE <7W~Z^g^rsG[o ˿3k=ŵ n>ugr _|S_o?uJ/x̓s_{O#s͜0lԼe-M0'/;6s{z?{aK[x+iITRZf@LxM1"-xƎ*+2+ny5{?eVT?fȩcLMvK" ,dd h%teɿȜ?SFy"/ko wgfϚ2oouӾkgb9c-o N"̥q*4\L5%gc@pCH$"TEɉYGA0)YlR~iD (c2b6!3u>Vg3dy/ @9'%;IO@@\0δVhjY6bF IDAT|HJEqǹ2Ib։O G8jDP "#r jl֩SMb1_,bB;vJi Bm}]m}MXs9Q *DfDC ҩq#CehM (%Mi&V$Dʴ\)'IE0B>'buȺkg$LFitL|RRKUn/Ki*d|o!!0hYݽ`+mՎձ:ֿ++n}~[V=x\$W5{b;??D_wM.uee$1"j?;}#w۹qCo;eWYPyL攘o) \rk{w~g|p;.ƙE9ЕWMy/9'O!2@NY0=*4;Qc~jFW<&-̐ 2|y a1S0^xo;'ٟ?w~SF9`s#=fգnƕIs @0HҔֽ8)MyܜGo;2w;lGoqV8w̹SƌtL^) ׽ch6s9}Rj@D&Ė饉۞;/nO}rLmCZz^z 2eVID~(o[ 2b_хO3}t7]zMo]9&d1W/'e3]/ܳm6-lUWFi8w*!"y!pK;p#bh-} F~O-x /<n|/븮;6,gc9j7{ݽw\zDܷO?К4@3 FA: grۘ S}n.6_?k&ιz#@M &1wc_0yA l;~W9snCn;qg߹q÷h 3fؔw?c~_7iA+7g)O}^1q{Dn|cN616-tԫF]-+k_ڂ6-t]WiMZV>~Eq[, #Фeb.^u;03 @ MO…f!!1K䂨0!tv LjJR*u 3D8<a0KlV~"iN|lBRiUEu6@\3   wG"i+kۜ95 >!:uD(PpggJqeG UD\("\.+Ȑ sĴ&JJ0&LUR\ܩУ{n]4 ǂGJ9)lo N]\>km۷o @_2RJJVZ)Y`@@'A?Ei4UJ9 , 3gyqAELZ) @֠&5BMM^a8"Rs,]D#s(yϿh]HتncupA` \젾wwkq9"8>HZ5yKe*gѫ٧'%y5T~UZȼT´t/tfYm*ݧSDHCY Ԍflwvh.@ !qlAȃl`fe毃HAPυvTJ M+Tŏ;Ϟ:!<8Yvo._ګ!%NlsZ(`oO}CcX H A @'/|W H_'p'mۣ˅%~iB#o?[Zi&"cIx9s!J5%,"]b^ Xv]W.zebuz2gD"YAݽF.VQ9%H°x=&?ϰok"߆ 66Xb,Z32NӔ8dvT_5QcKO"ޖ?X]:[r#vL}-rLpۑ&Odq$kς{Ta'T:kA3Jƻ dѬNwA xvRI{7 j(uI uW,e{v5F[Z,xU"TqdϔZ%JIƀ F8 r\.\.B:ЩЩЩe$ 10M))mҮ;w8B1ߩsC>#Tj/K*M u55BCEĊ֙(K"T#\^VJTD iEDY&,1.0GL tJ È80c3."QNӴRح#kmY9B8i@cG#XxTySgi-EH#T&Ya_@80.8Al@5G@:ܣu j%C0(Y@*614Z-v &Enf&7 w68b;CT#l38H}wVmK`ۙDSd U*raG}3q09Zf]!HtD>k5vwCPLi 7J%!"7 d&/;+تCoId Ñrn`a0%إc>ӚDqظuS;&_D[m+IV';O>NDqƄpdh#CRR1 EQȏ EbuofW.PGh*Ęiy\R:v^{x%$Nؼ[YMZ,;Q@>ͳA"!|BʚLގ ŠH/kPLRlΒe~4G dFe\Ch@u4fmO5k!^۱_f0j0Bb.D]~^W) 0YXN^? ݋~* ? ,X%yW d" ݩ<d 9CBXIj7 d]C8CjQW_k\$8C@#@LL)Me{[q9+tRwյK!_xÈ!CbZb$J*IR[6tT(ߗQT_WWW .8ȈH,~-k"lҫ4hRpDTYȅ|ni*(PcH8B(q+IňsRZ Q$ՈRYB XK-$5}&0>x=ǿe}lG|VCs/>fWA3|cÏs|:VXs{#mM]GHEk7p<2ɚ>#2T:6V" m@@4hZS@ⱦau;ns]Z l,W8CpՃY3|'UO42 d5p $}hdf0`y0QM(@Ȫ&]x|2}!Ad < Rp^kZ+كt8,= ^J)ҩҡ%ej"@]Ot WRiW{%i/+En]4F4M>}(&g,,NK9|RJem&Z*=TR"5I_9*=I)((8yɏ׿ke|Xxi28>}?;" ꣌ihB0.u{*"QSV~3!Z[F#Q/Hr6wݶ<"c SPʌ_0EXΈ3 l"'dYnb*,\-oYk#H 5u9ІR Iq,穌&B>T W1ٰH ({2||-^"ƨR̂}vk\f\*a>ۃM¤ $"ۖMtq4kq IIVVU>\ԣ)tzVESZrq&`*$@`?:@8B ^c{`?/m/ Co0>+P;D:ݡCƏܾ3w?~/LOT5q3o ʤO^93D"dq3 >ZMۘKt͂{xwIr2eW@W#\Ü 'TΆN~e{dj0[ς{Xus # !Ϟ UOPŝ:ɎMʀ3wu2x,Ky0\Ys1ccThuL]P{vB\8H "1L0bA担\19.JdR8z66vPqX$8@V%KJ9Z PI'żSjETj^*TXD;v{25RR)%eZIS9܄H dI"|r8"s@$Ι3"k{&i(28 1N$I@eϫ Xyxs(DT <+ lF5ha2zozRhU@P3Veg:5뫡OgLEd̪nάx汓ix`drI8gF>&΀+t/s)5 &D@Ȗ.0&ZR n3MhVZ{WIaj ;T^FrLg5*CO͜9Efc3,YL2FCXadk \èMAy䱐)1w%Fx5PPvS+E6}+˪@JiOVu.C8lBp h/J.h\7p1wS@n&uy*nS NBpzp; ؔwk;O"E["ɛvѡ}PH+̃Y[8{d+&d8`3=$Us&`<63% ֣ 9]c$N ݣ4n_%PbljHs:P(GTQښ|^=jB!Wk | y4* g< D7ڱ}wR)ŹHCZD&]TWW&\IAcPETJWۣزihFHι;0HD@s4i۵lJ+"b\0 @)" :Չք`{R+II(1E&z4s@kIXcv>Mkk̷)mrO[icPp`e4,d5"iDDEJ)I34T{ξC9L3ҞUaE؃J4#U&0vV8΅=[ȪOўR* (r@h{3R"N6hzuss(^k2e({0tށ$) {39;nxhpTgq]]Mkj B0D+2f"̜E Е"Ӕ3^ݺ65u#@+DySY%d&p!c@c[vk-Y;jr68L瀩"Q^5bwsXpqP(qu{ܐI)1"n33^IRq,^ŭa*S*R*۞r%mk+DGQڔ(:VXQ WR+_i*V`c!V&$RO PLuv MDQ>qy=j}M`  b]̀@RMIGCgޕ򾏄EH@ȼek`JT*'_0ƢrHC/^" ,7:9AL09 =[1X 32-4vNڸWC8q?SI.*슪 2[iR$}ڃi4NpAs_ydow{tͺ"Cm(VBOnit\uNh=SLd;يr {,Q?|=9uf?LMh"q:0eqwb>y"2k5.l= AHcL;( ڤI F0{ Q}m{<4l" apQW]w`@ض)T$ 9s&JZaUCvmwL;.ڧ&522h1@sMy6`%9&,Sfv2SfV:g@_C\ܠ5m_=v3OyiW33P7Dm]F2QR"P@iRNS$40b{nݺuT_@i ěћsƉje BUP&KN5uQ#bi*mr{)eȴB\ b![ߑ /Cn hhRSSǑ3\& 1DƹR &fcDi*J%I*ihF)Q5(b2TI%TJR%R&ZЏE+w^3>"_v\?Wr]+9ʴ߸3döi ~4h"ejQQ>⫊~&; 0L^?lG\h@5'VZZ^I`"BǀG ")$5|F BAQ RYB%oST:# P.Rjj:YS3HL=uЌmT/s#Tӈ Wlsu%rFbuְ>.7m!871424-.j+^FqHVF IDATF"ͽU& ;aw<`Fo]'y\!=L/  w"xpD@Uxsgh+LYmk( \0sg=66So5p ~xPeibx+n`wkV&r2x&p^87x3cH=K_hԩY/͗üݛgOޤlXiGN1#ywd-˭%4 '{G $Ԟ)6E. gvt`Xf#c!t9/d^" >wJ2u'*wR**թܩc9 0P[ӹsƽv H*eЇ9师5!N%!gb{wdLpA%@*TJm˦r3*D]C}Mm]._dsrֶkþwog/Z^|>ٶkwR3xvkWxco|I.(c}aѫ^N>P QGGW֮|yO|Z+(T2J*%6FK.{lVRbi\jR%L4Idȵ+]teZVJIVRT-/v/Ot2UJݵ G8jh^T\.(:ygk>PD9'#_/Zks}=_]>=åҩTi*<n_a++J{ӯݼWVXO>iT%IzęW=uWqgAJQ*Nⷳ_zg[UT҃r&݂!rfA HMzJI{X!qf;(MҤRi֯J*:?oke7\rrԖ$Q2UfQ <߽p7ⓣ8 jBs ?PWVXܧǜE3z~V-c3.eW?75+,ѧ&M+R&z/,zuoGpfwy૞o>ɱgs~7{%}'F˯gW~KW,Y_(bMXWS[_[[_[۩!ǜ| k:{J{P!"cׂ/XA0>O泿đqdG7ފ€#w1 8hyꕋ?3Õ&M6~hYn/L<(.r\x5b?e㺥>7a2#gچ+Z3?/D+  ?7[6/Neb:f˯o|w0ƭac_|/׮zsǝE1IZì!RRJr$i$IT+I\nTړJY$M׎JT~P8H֠J*2ȤdtP /BNbG0FjC\(v޹u-޾9m߅\Sv'~/|ÿ/p|ȣ>دoM SdR"1DTJqf\r9,Sվcm[m޼moU$k]{tۻWƞv E>I\Q}ǦΝtԩEd RiDƸ smY0CuHM$,*IT*r\*Dč{-<"9"@PZK '('qli265 @ ͺh0mގձ `DR6UZJ \sOtsn6o~ys'qV#V\wLGщV2ĞGMyq{%qk׼VU3 S;$4 lG/v✷75̺~W,lۍd=0^ܥyִk|}Kz ?.~Ҝ75p󬻚W|u–&MA ޜ[ yִѓ ~wΒMM|=7 [{l~ ;iMi}7{옅=Mu=qM iIk>~Qk~sOռ64ny]ߗovׄUǍ]jk/rbyz0 ęYKw i&֮\fV\F ]ή cjQ$y>owf/iqȠ7mcF/h&4MǠ;/'~{;ec_s`y_߀k-l9hܬ.M3]c6 ?^ 9ŷ6t;g]b=rf/ii7cF/hy~3{馦~nwƤG]=wcwis[≠杣G/ܴѓ 8gɦn5u_z*MޟA_ں@_a8Kg2Șyƌ1OZ7~ޡ[=I! ʕi``ȉ?Nc:_jxg\C3~noF-4ڙqg/im>cF/4p`w,㐁7Ϻw6vѦエEÿ7wɦn9mҚo[4yz]8lj?ռkc<ޜy]cV|u&N ~wޛYU\kkUgn(2I4滿DD\ AԌ2ϣs4*8SIP$^IPTz8U?j`"7~ʿrRФs!ᣣ\@3}܏oƺ\޻toN߁1$7psc Vz)/XqUڍurϊ;Ngþvc]Vv4]1tڷks|ժ4nݮO]to?7nLvc]Sx;Nq/lݩ[wS'TYFw\M1fڸk\kM*r7i;6X(TMYvgS20ڮ\x1i[p1!ծ2 MSdj߶m۶eeTMV#!e RKHK% CxʤT*jPjJ'Ҁt{JRe4fiRP(@k{]mTi&i-C R2EB g|t&yT&JeVT 5R6I  P(Ҵ<z֚Dy6<Ϝ1dSRa(J!B3<X[[Vf%-:aG٫$)p4r?O>v')?6-?h}|a>~'pڏ\z\^<@tw`).{p\ua7uߟh~?+D}Gn='c;m֫7~/מ5u1_ bB.m}{C|}e<2钳m6uq1D/Zw[N[b?˜"&oDG9a^u8q ՜/so>uӈxμǕ3hjDvT]$?wsN{W>s&pu?yO^vىe˿` ?;M^nCg} 1;~yڛkͅW?JoMڰׄO_9vkգϜ?N5c^q1+IVw]c3&lkI^拧-Ɯ5f;|i37מtƂ s,OkcV۷>89ܶi䭫'^rm[G_Im.ھe]^'fCq1Jݭs`=[9rZnBoyj\a@Ƭ {o3g߰tvg&TRj ]4 Ǹ Ǹ4 qq#yTP |1s&VԝL1e67hijqɤ8 Y2m0b~eXRaHDs!fO:~4S[|êtO IX-G#'FA ×.CtfjwހvSoxW1:ykYY2DHB .vǎݟvlؽQÞu➡Or 3Gm˄}fWJy'XBDَo:*{bY{ʪxb㇟SӞ}c 囻O_1al?r "6ozi_zaUv2[Vf=EX-4ٸj1Ue.ݲ_c%^Piz?wlr~Px^pʷ6.V!ś=o-vfl9Yb^gcvlr\`G|w'-P.r+ +A4𑉥ݺy9{! iJSf䷯,봒;^;^[ ~zW.(<ϬŽ{r*s_wK! 7gTe/~{8 -˳/:{F lJ.^qDv`J]T'k/*;dk_o/V/nh-YAfsvC|;{'dO3{s|ZuPA?ݷiQp3D7tfmy}AUhLZlPk|Mb~7kC߯^aRYmܲzi_|Quvػ-o{sK˳K/^giˊl2\XxˁmvO6_X8A[K+ɫm\ m^^iU!X aD  7ZQtd9vlحw0 5_zSW> OõҚ]ynxsa2^Qr;?j^{QuvȶFa-Iqˊlnc W_7~3鷯/a^7諏& C647V/gx/v#߲z)c. +޲ުw~‰!ը'!nS''θFPa>ĶSO0"{qܑRjeRTZ0KRAL uAB9G)ҁ2RpsO)߈p@T*, BX( =Bؒr@,PaaS3ƵRMKeXa(Px$g:[աQmӾG$ ƽ v׼v΁=w, ea)J*V$Sʶm۶o׾}6'@kPUUfmT*{0$f ?:Ib;rhR[Qx'w}|࠿SD='RùCT͖ O1?8#jwxxAO6tMBcݶ/s`7KMww'3@PZ$H)9*ESLVJ-0?J-)MzֻQ:J+%e(0  h z _('-X,l~.|y_SXlR:~r>{7H3 j߉1g?ޙtߩ,IR O^)_iNYeN>r &/ԼfW|? qk)Nwy |Ϊ1~'d%k IDAT<$2.fePlgӀP?~;| b Rg[545M]2AAsZ/* t "`s|}~:BIZ1E.vr?lG> B9eф -1?*ihT-`xX^錶F8 % `p%;}0et&~&`G۷K/]Q͖e+3t*{g\؞nֳK^H:!|2CR1*E/s *MJ϶KRSLR>l.s2 s>PN^4A`_k9}DPZ!b̹gҥ72|*yZ| K'+{% YN{c/秸& y0\g1/|K1K%R+˦*۔o[Ѿ]vLlllgL/qƤ!r#_lz PɐH3FB`:e3 <ު]|LaB}%1_(666556575b|Si. m*?˴ 44ZC)Q4j Kawގ {j,Uf'rH Ka!o>X,Ք -DJjjnnس_47AdVj nc4,h!}~"J\\j#8!c<VDK!oLa6XER4[yfGQM5s j"tIVZibU&bpn*'E9i97bxdf{6]}&D jKA~྆kë4Z^@w{%=u.:ZK[3/ffiZT .DYZ7|ˇ& "u js-p{QM6LzWE9ҙcTP 1)& D j Ym;|GQMlcKwA-$; Иe@L5, dq]8I5j #8 k'Ѐ#I%(ɚ>c jʈ৻VNDo߸Kw4{06};T(9?`w: t]1梁V*] `e1>FYmdĻE5}ld(RGjŇE5)̱:My6=f-K C TrgG` E jT*(qODﮂ&ӱpT@b]JETTT$U@HW:؃3{'\ݵ %${#E_Qy yOuUAn} (Tjz֊j݉Î8tKZEmdE5el@ jC)k};jYDZVA- t4{3.J"MزB89ȸHZ&G|{QM6Y5RiW!qL{UPkH$P$o)QTSO'uRAMP tLA^ jPю@Mt:tgԘ}zǷ䄡H骂h`pǒnl?s ǙI zBG*d) G1gJڹFD Cq5xQtm"-K<_BKV1&.}H 0,I|H=w4W,4!H!NUVءCYL+)-߂(dlY۲ . [ͥRAɀ>MOFwOtDFNpiь.i`XL  l6fTP-R-0RT*於R/^ʯ(oJ K1&TPCȴɀhPE g[$d&Y_|O>-Ϯ=Yȟ{8{?w*uL!~v6j+" [8PPMR5TNycI:pYtJDIzmR"I i3+a~M 'bbG ?b7 Xuƅ#ѭ' |gCΏY1Du|C:3EsN}hvGtM}$}>\]٫bʛE~#Zc/7;V/\l0~G}OO4y^|?aTn k?~^R72_xw>mR^#򵏐GWi;=J@ɲ5\٫b†Vu?,_ޝavh0:׭ጭ/\ѷݤ7̍wYKݣL+O8鍽O]-uޕh`#_"_X,/v2=Զ5^*;fʛ ~{,Sns9cHF g<  " .$lwm_jxӯ ֬c^mƿ0 +5}Ɯys6~>~ǿ,Ǐ׭ᾷ>/T`{D+=*p}~TʉMk7 :[-8[]oo6먾#urW~Ia2#y0\)ʈLw>zw/}kZkuR&C[7]_x.ƽ5WM~GyQ!G?>̓wE"zhw^m{mR>װ[Vն<635?U.m}/<;yʉo3|՗=Jr|Io4G/]{4N=Z`|/\{,/Փ߰aǓ~{sZUB+ێdp 0֡ilkHj2ط\sDDJ+M2Bx۾B%'ڹ} 4xƱkq| IJY*[[bTM+ J~s߾B .+/خcUUU\6[NȥBBA|5K5cY#bKAJkBLDbb81HC=!0Ԃ ?B+nĽT^xWR 04w*BTS)dT:Mb ιa$DC&]:fN">5e9~=/5'OB5?ijg>Yc>͏}czμ\ɫ8W^1}uw&Ӿ?tƥG}ԋ.]8i_M+X8Pe脹 "'?;b78s~y qloѧ?҅ \HE8DJoɅw`|gnuj 'Ɯdhi+=Pƒ޴0ڥ>?j7W0o'Ǟ9>vo%ק,=Vɿ߲;e}rY CӞZ{ lU}x99]*yߔ_{oFL2J7->kΐJ>0un|߲سӞZ{g.~K}u ~⺳kf<қ9u\-=ɱg{Be҉/nt˲ ɿ~aэό~s]uSOBDQ20j7y"z䔄t$uFZq1$L@"F8Pln&Kn|zȸks޺h hjjִo)z?›5lO?GN^~3}O<:i߲;orܷg<̂5e}_pc&‡=vMώn\ߓ/س iO?gGM}iK}U-سiO]pFNYπ~|ɿ^wߎ~~o';3rHlf`0jՊ4E)r 6a(!?[4I/n;e=6tdySۯ?bW)/ɿ^ uܲǮ9CI}_~эpʍg27?7jںMu}Oa';E7>;rzs,9}ޚO?GM]ywuߓ- [G Kj@ FGGw끘t6 MKo~fujr>qLg>_  o݈665ghMN7=3bMuU}޸'=iOgO\)W2N+/׿v])?"o\ro.ۻsp9>M~nMό~\S/س4уӞZgGpO\{"_p{nGzsK1'>3L:{6(g1ӊZii)ȸezg7IǒOӔ3Fi"9c1M2ď HRC~<^ hQI3 "͂@aQhڒxSEABTv;tEvtVx)`~>Jk42d{gJ776oW(L]۶m͖ i H2OR(USҚ "c<~2μT3l?Hr鴟 BJ2 B)VS-e3t*%Y5#s{)_0?[6٫ &g{"d?mnHN8vw[<,a^0|+ӻSEcև1u^pӘ3潌'ޏQ1 SwC67!OqNd.7s̛s+f}iݹM㮭=cƽ/#"x٤WdCwϜF>#zwhȂٳVb}h=d\3D_6~>}tɼyj_zx_̟;lGȂV,AMnϟ2OEsfzٜOtsfG3Z4wa^1MfY/0/ :~ٳ{q l3sQr#sƘ!F>^RJ8}O[)0 @k͘l֪I+IU:fJ|J1=ϴ θÖRڗ^qT^Q͖g***+yi<ҐonJA^D!QHJY RX,y)?)ˤT4W S$J˲圉0M-5M͍RQ6Ц,)cpLq"ݺu3"fԘb !b7g-hΡRP*ǑV{&N)K &چc`Lzg؆nԈYcDQ5&-:O lD;63-'@+? mD083#I"2B͑Yq$=4X^x!!}m=X8#R)㌍.9 N=໒ IDAT@(eP* oG)/WW)fXyYQ**x~ˀk8_>览qhJ+,͔"  TsϤRK1&  @ l!g8,J|s\ Dص9\ :4{`\p(CU$Bh  ! XT*Uоo?tccSMm=0ȴR2("SY Z)JPim3|~l)t&J MgR8ڀ(\ 2΅{ 4!(ԁ 5 i e͙qMi0?g& }\G#ב_&QB]?%˸U"(N'.c_@`mhw"2@e`B:pCNm`(D5]XQk)qjbpE,!|AIV+DKl\e>z'\@C&8`18fdl71dL؁ IITRjR`[,,HoԊ  ǺPNF&hQI;!FяqXV%5i&_cQwW+И!!c:PdI# ]61k]׀Z/CF@!*DwWOL,1'c"ءh4iCpd DtT1LeGAt;uH#IE39\HPZR'JNi8P1mp,DO@[Nu4%u*!c@qFѣ*jV^:".Cm2$s(@ĘCC:lIk2 Qa+ St,Ly[W>!zG5ZRVdUf %5)>Uy<_ƈHϴŀL]2W> |8gD@"* XxK+od#5pbcB+rϗBk@ưsVVGFrx{F H:;*PRs Z90$> D8͛8hkĒi2_A-K9Vs˷fZ#5={R5tnGEVC,g'@I zCL BM̖OD֚y.8"H0 TJi )B9W20 8cLV,xHcGRy{c4,Kb1 0Ak ,U)lצ]2=BYj7?wO="y/d;.1.1D(R|R9Q+RJI%{YPʬz瞔sQYMY/WWW_W/f2",M  B/b^kÕұ`ȹ2^pIg2*;![V46h PmvsT0ZESiay˿T2s8BP{$;r>TdJtPT D`&KHm|, [=O0c<$'O.EBM !$ȁAIFYqA%PVLGWpMdJrkn"bKgH8Q+R&DbR2†,- hJR4EU .87v7r7vy]@CפFӚ:\RZ*el~4i!.h)h+ lB☐ R|)2\Nӭc^ΣGq-Бvk7[R8 R|?L.34n%F6L(O,Xt-VAk! cc8Esl\$Z1ZɤK#V1HN %`w;z.G&D$ӒVuphJ-$LZ"A;9iCbOdT?Dm徢oS]z AVˉ=jA`3ҶCD 1֯"2ęmxnii͘BBd44A(*mky^OmkX4*ufZtB^5~^frvV ("3%67~͢n D )@dJʖ|>B))0Ι1ڜZA9C͔T*$*ȗTQ t/k͖gVLk`^ LAeu( c "2 938"sED Jָ/C#CgrrtDJbd<,Z%ɻ S1-ݢ`" +Md,o,dDĸx'8 @TD]=]E-.D 8Ji6:n8Pcyp"9@GO.dr1 :Lؐl#) h9ЉR$".;q9*F::Mj !&$+[ԚDm1ř4%8d}`R'ЃQ%E k;:Lq4 2X̽`nSie@%%TO 1<@/#¬ƚiѮEͱMw1Hx#n@lѥMQ c(W3nYcDDd'neeA#c<oɵd,RP{ yXT*9s Z) RĝP4]$_TJX ԉq}7D TUC7: K5i1S+_JCM$^s Ii4& =<>B ji d IжrQX*Z[[L`,ӶmLT w7|a[򅂔a,]QYQAKK~oښM-|!PBc@EJi6ؚ$".<g*F H(TŒ JT H|&ZF D~&9!o#h>gOCpS|^}~> \{V:/(tq#R"NL60#kT}O  up5)W=~n@5m>fCO#9wFS@H}NB@=(V+BLdPd&8p' VҭIӸs)) F " H q7e,y '.48pɲF')b`H󠫟~n=DvP$_9 &nX՚l6Сsژ~TC#4Phu>$N JO9`VI)H6@",Y֚UbRTSDouc23 @ 6gĢ5! ]fIMnTukElPZ:+]Jx13#"iŀYUdO6 %Υ@:jԱ7;R2!ic*,:YҿvI#E"K`> IaRTiU`0C2+"fEQ$JU *"yAID%#qA0bfUuS=}9W_Ꜫ:[ \C:nְq\I7C!IV0qs=:T$ bX:~e pP--#C=xpKRm@'BW4.&@ Vx0ըp*D"qWXI &cj vإmĚ (mۼhakkuR,%gIV]t"wcRB.$kD50g4M[QOqE!D) K*q3@`%I>_TӀ*BcK  Ɣ aQ4H4a^PMR2f8jGM $O2)"\yyʪ*4禌X0,pBPٯ` s۲,ۂ8I @#HbҪG9giٖL`6$˴Be[@!Ar !Vz^k5_K_ܙҥ?8IWRcvo.~Ӫw'2nr]n? !؁(deutGl9S?7ʸ2 ]c*҈=cҍD-f"0um4Ej2]cHG"z8MϓĊܥzl7 /'(EDI#Yj9VEnٗ򒩆 TbXHe)se9 gAE5p#3_ڭݲs9G/V7{Ḁ]fuavT9%N;?5WpЪ2$RuF3=u`Kq>.R'wu#V"7 !fHݲXgY&Fլl{P ի2coTqF`1U={ܺ9B0.TpSqι` "0I ݰZRnWCB@uUUn\W H^Ca7I A+!R!Al½RTd'at8e*oK;/nYy]פRyAF5˘B r 楮jf\/o<$XΫ˭c5LJ[XW4\Pf R@ 0F5J5LbJ-R*.ӎ!" v1-+VvN(Gs 䆇#bRϫo]pe̩I!R0۶i@I<L`WBaB0F\p)BWU#CmJo8r]M&1ћT#)9)1!!0 Lr gmoOsz)R|EdGn`meFo֏weޏ׿ZnGow'ֽF~#y|Lϖc ZGcOA/n2۟WKٲ~呼_۾etaQ#mߝo>ygģ7r&%11˲h4Xi[eYimfݝb_TPBj >,;x!Da6ƘPJ !Tt]7 ]7tz}>ܧ=Q'mcx>ŔbJG&j$'Hg=?_-8o{ JP5Ͼc>ޭ&hjmՏN?%j/[~g߉cG~^Q}Ġҭɶy$ /8{8XT\,1å%gΗDeqƥBJk$%%Ԭ\#֩W}Stó " .$12qnٶmYܶZ]_(<έc_/-@ 1'("XBԦϨ{>/WK[cĶ -# Ѳv)?o֜Q<+a^#>޹X>7M9=кϨm;͎#K$5jێ=xwc72&oŏ?s`[vٶ,}F}wSw02m3LS6-2mӲLuQXeی3-EM+7A CBFF%H 5li#'tE2,˴,1[J)FBpm[00 KYFR祔:+QJ NbF<>#)9V:kLNY#z?͈*Vs%"X3kH=^ XB 0ǜtJQi4j//;_^fQՐǧk2fs bM4J>'!K4\YUq"TQ((0Tm߸ijf@f ]ٸqt:^u/V %ӸN&F H F۲9mKHƒP $5@`iFb %e+鑈iJ΂mB]?XW.~'?CWǔw}q]n5WKfph,q80^Yh3n3wy߼'kq,=ǜ#Cw-A2F?*xDJ.fiLܰ`v15]SٰRȸDnXoy8м s9X:!T2xfg,[2_]L]8x߬K˖N9q%9+歧/[6sxobinA_m/~&>]v( h5vWc=ޝ?;Poz֪Źڏ"Xe3˯/~>9;2E9ym,rtxHX:v&cTi*pPaH86(edŮq+S% NE :a-?L߇>8y__ϋm&/}:c@{vIkn֪%9ۏ(~חL:zǘ/ֹib6^4P;uN\9(s@ۍ촿7dv%iW֒yYnC3vg`Zvs׬~ՈAB0.QV)rD5 6eYH]/IɰWX*_ӛ4_?mx+c'V %(b4Lk;as`iE˖M=yg@PRR]1(cPGv,Ikfڒ3N3~w՘UϥKMotԓw2obp}K0EWL-kʞV9f 汽gM[[0T_ԺqČ /J4y׆kgΙD!9TZIys꾳4t s>'$_Ƽ4oϦ4|>{w^Ic_y.dکմ#!!#c!E>B(_NضdU,D`])!\]S mۑp8G(BR^]74]C,ӊ#Q3b3l^ c*+\UW! ŚN=^P!݀IXy`YŘX<jcl)@4jUW;[EUUgΖ.:ydZTG5$7hX7f<dv6ʔnZ Qr(0uR  zQ4M۲b=ʤ H9w:691A©H-Z@% V*?oWK-wޱӣ3fo߻C5i9N9B3FqON}?U!P&mf oլF'm#|[ Z+x~>#8k_;q_{oC!־v9E~w:Nm^žԁ^D}v+n5/ ya5?Ϩgl[ԴkCPۇP Y_RԤ~lgԩs]s[ϭ^&ɛA MnzcDO7kw6ߙsKvNkjJc\/@\Ƥ?*;G;ѵ?:YG$w|+^;wLMyj]3EWgkeJWXmӃ7ܾpMzΪ@5?:;F;?>z˔B56 xO;FpV Z׌1;ؼ?(Q&g??ߟQs:O9E?S*L7Rwś'Uٱb“nT;g=]R.k{uǷvS=.UH9*xx$)j nk];EWOWh3]!eMX~_@T)Qg|=Ms^{ 6C/Uzôgն\3:.|dG}Co pϔ|!w׾~EtX8ӯ92% sfrIyϩ c6M,ˊ>=_ʘm۶"Ùo}: ?USyJQ?:c:MLW]7ݰ֘~.S5vbNKo֋TE(58zW)AUUw9GG a5.c1Հq'QZqWTG"lx<#14-dK(^t"O裏qٹ3g!TG^^NJ:kό0RJ1"@-B!H "+3,2A2YUUUqiɹsh%QKkjDXJGϟQbb!%B0_U$ {$P sܲöĄBAHb9qp rU9n)U[Q{"/fj+7s/\ʯ_ lw}W?u{{1b/sw,#v]B6d֣'+ϟcȔʇvjZ]_,kfs[Fv9b1h@{WRܨ2o׿Ry33E^uj/4Ȁ.@Y_{_ }W[uY9wNeO P*LɩOE̬y%܁>rϷr{VǒK)Iȯ)vnK65/gp ,^Gnyg-e7ُ=\*SO}oG/u{:ʶBJ76?z|,]]~p7:! \DSj@x)*Hk>uplCfrf-{} S_ڳ|V|6tѻA0qO‚%#C>+!P>2:׌J:yax8+py˜o%m B3eA%ۇl;r#& OF7i5Pt}VXw6.ft(nr5yZա>2_}8fqePRyx/uFݠfʊΗ=WYYi/,! B 1@tC)@f1,2-fN8gm1f TAT>:B .QJ. 8>GP\ُڶmZѨ6LzI\67?sq(*//l7n}WUZyu)aᥜ{J/;:?/.WMOzTa;@V^0!8b-5"p a(p8@&4tb +r .Z@{q+3]ijT]%0 GUF5]uM(!D-p0$%zަRew0SOteYV$j&gZLEAF_u֩۰N݆P޹ʪPhĂBs#UGumʷuy虣H$bF̀ Cr\`F0JI&04 3h㸄y kQO @)$a(u5\kPJ?4BqOsz"R'HP3s9f(4 rCy k))P Pʅ&PB(8lIcT+  /X%# aڴ13U-:g˕{:59~ ff7jڨq 2gdb\4t"1ыF،[SH pl3c/urܮ{6 Lq$+Z@hNs1x & hHl6n(۶G`4t,ʸKG ! )sRXH p!:9GZ,Z4 嗇HQmECGiS^%~k%t+} @( @RtJ4A %Us*y,tjLV@ D0qg6~NzE"(dRBR2mf۪@_/_/=AfFYӳ7@Pa1!rWC?*xdʣ,YJq :ږmv@C۶/)ti | ߜ+ϴՓ4MǠkii0l1f_1ֲ|ϟ/h#=wLHKh(2qKF63ǑR4tI+s0>2Q2#XKiP"0=. AfF  RRrcmxz־s#:D H?uھRH.9I`MWVӆf7oԤ0cn39fH UEZhSL7uuHԶLˌ4t|y(T9jᰪP! (OXi ?E%}Q n#gбPXr{QpaDZOQP@&sFp)]hDĆ;#XQ? "CB$)?wi dbR:fi猛Ǒ QxdU{0!9BR8۪Γ#(ƆF}a(($\rhee干%ťr)ђk֬MM BPx=×`x|K^@%@5jF$@l+*?̌F"ãVV,:u A1L,, GBe%²`e+)^fR̚5kq`;W^Z\~L4zXYy?;z|I2v^# :B$b0ΥB2EcAk@&DH7 Lm%IEBS*cNJl0BH8kD@nL=_ zܿ1O#rÌ=?%~^қ*¼)Ayު=u4]a) # XUN-Q L1$1 +:j.*mJƎkX1{z~Wiiʬb -3ZSf[#C|N!Kc9@iha# ziJ)?-x*DًFB18EBS3H B,PG"lL\$5q+(DF ]# a{ ϭ %qmVY7@^(n|_B8,ՑhE{,xY֬* uuEGd)΅OnfY7^.\c&-*c3"yp+ Z"ӧ'_u 鍄4 -hdш=qi( 0h:Oa>%)!ž "H0Fԁ/{}>7VqBBBj%ԧ%x=XOVH\acB2/Ήq`܂q[˜m'了xbs92TRx/6F[늘o-0FyNZ 4Xh8˭2 IDAT^lXvաr,@CG|TqVQUUI6!L=4-u,dbl߉Bgj4huRDION%$`}>_%$ x ӹDY.!GFJ)ʊŬ&c,Ƙzr+ ZA  ] .E] ^@"=MXAx =$OMy'Cu,r)R ;%,ESt0]0*EakQx2U Z4 m{bgߛ.Z!\[~YMec3kx(ŘXjɽwGaL0kJ"\T}MkgkKgzM3ȉYBue- me)^cͦ}CJԈ9$7.XW̹O*ȸX[~<=lze ,smiocm[1yRvP kQk.ހ`i{ kH0Xr BJ^BpL][{"ֳBtM)թc ըQM#JF JxO9t}(<\_kŔ4.^l(>3mi&kJm^SC5- Ư:8ypp|MI$x>qu>IMA֗lV 3W o<JCh5k4ipxsbrkJ5o+ hZ] M׻,BݫcDDA뚦4ki:& T'bLTDsmaif1l5iGVĴM[\:hc/8t!!Ě_&)`@;';w P;JO65I7 n53"1Gg"'" f}¥4w&uh%'g lF#[JÏ6΁šMK6KF7NB،ۜ%dnE&ҽIMJ7_Q5Wn@2یD*BpҶpma Bc# !CX8d Nt-F?9!䭓୕P B-2KΝ9[e랄SxkR=bZ2| 5k=X3~zF鞤dAa [V(jWQ !89Q^ZSOZNݴ5Y?3QvZЉC%%" 66B Mשzi(*3d6V$DL3#p8XѨmYsX{SI'&-(bD@ "HEc34kݴQVFYMӳg7Mj \;.goQ REWwdf+_}뼥YȆZ6뎫mttڒ漟Ѥrqi $U7-_)&0@ìf1pW2 4T!8Zp8#IQ=ώj4MuWc/ .lcUG^#ruJK o\:XQã;l9tͭBԪQ/Zz[6}﬘1mjٲ}kH oX2u=j[1oĊ Lzs/Pٺȱ/{<|Zul# x=IVh${ʢ LX[ֽG>@lVUۺy^2u}ت~IKN^:V)J͍ZӷSVZbE`)SJ{ƯK^[8fj1@Aits0nfSroNlz!n?zhϻԭiVhq6.&Sj%!Uc?m[_I){.CF7}7ZCUjX3z6IK8}xܱw)Ub~&=PIj?ˬu|~݄̭zwFjbeqo`!D0WխrYr}k z*@ʥj{ۖuk7l!S@E $4`Zh CɫXI)mS( aY1!1ی`H!y !0H!@J"2, )FT[>Tݛ ϮiAy @?__-p5 0vms[.LOQL.$/ӕ$;^|'>N9P5n= `SF}p t"V`1Χ%RlF1ęjR`}8}ɆHG4)hmOʬx 5~E u/E]NH!'% 2p1i L@v"&L1g\c; j ^86kJt&ʖ˳Quy/Cm)=@B-DQa8v!̵\L2 !ss;VavG%MJg,bU&gwh8I! CD@cQkAD "Oi,(LLFkcR&&2b&sDV-I( ` u;˒T 1'ĕfK8~ Fv\ W,}eY{ORZ2Aa/% nK@uܱW*HLl̳19#J3>F|'ފKZ\d)T`z6Vd 1I{͈XspH E~ؖQNqD6JIH _ i!i Q(!()S_NQ%RH)(fz~ϋgYRJI yZ/IH9bc!$1*Eq KvR Oy kdڊ,%M)u\T y I ~ !c+548Xk0Fa*ϯEJѱ}vC:_?o~b HQC&$+EݥRy۶NTӿ5BeZVA{~s(rSBT.wvt*BF "ͬBb"Xё zD91(#<"wy PRJ:ܭn{/p"Cl(.!o_ ` I4wVȡrc>۳@J_G~fs?7;s|w7kgF55QvmmR*q9:@M=nϲ0Y>(c+̄1+hLKX1澌َĸ,{j99e!zDNpWJbppuG&3&Ғd1|$ݯ]GXNUK@DC?/ZH˒&LHg%WSvΚqI.S f""}ZٰLPivpJpȔ $@1^ڔ@PlLēv؅rR=Ԓ4CΣ*  IDATRYHN!s^Tw~@L<2'!G1Q8z6^C&.v:M+&L*SS J+L,"[4IC S8&.@ʑ~p{KqWb@Oݬi/̱.6eD\{=`R9@FaiI)%DzITJP񉚃j+pfa9ZS+e͐DdFfktd#4b`i[5)%KDRJFH['l*T,WR*I)sF'sƕ l9St%2" 55$7(D @`&mB\'Xn>8Ռ4f\ i8B50{yS1 # h\IəDZXGZՊf cs|.\v믂|D)3K!K$V-Mmj W;h\Cm4qU=ݕj1}?gv!)'}> Zioo߸m[b.RP,UlSgˌRJ7;Uac@!8@)<[VE\TLI3 TYzq,Ar8!BcY8  9v'ָloB1Q 4QpYm@`F;\RR2ic43)\ 8 ,eR10[έXgDbc"MD( 'g%uN:э`LbxaN1ȩ֕0PXmB NdR6ƪ(ZǍȐ%USȑDN[s xʪX-tYɔsͤNLNɇRz)LANrrDųdn'xNgNT1'&Lk] -PuA2b 8Z.c)$ATo9FbC (>/!9ʹvfQ03Zй'Xdf.2| A@sG`"#()< zW)s8H,/b.FaR"MdZxBaq %:<޳`e-(@kmR;/6h/qRLWBlN;⫝Q~8 玿WCwf.wgpgώyd綝:]l)zuC?p)E![/NR4ւ(=($2[DWKL[0HqJ0A\ uf ,ދMD8ҴC_,D&.c,bҎ3ky ɂ^FT`F tVRгtE %b=$L&mKNq:^%cFljk v61m35D+@5&8 R8 )T{GDL\:<-XLh >i!Q)2]M!i"bCĆ|pq BHtr4gN#UdݘrL>J$n/"g'pqȞ6!8Gdv:VlM74d"e]|h,'/Zv>[BGJ):;&IcR8]A!] tYӆjϐ2bEI; D&_oA1r.#[p"cEB\.(rA+OHGM2 quDy\.ݔh ! )TlAi>}ض;RAAXT("dIߐ$3"xR@&DZG:TR/RʑX EQX:r>Uދ 2PHwJTI uJ*d\LoKg8DcݕA)%MDjE*EvvvE:b")lj{ـntaCd A.0D,tmDDTodIZSDQTyJ/$V0(}/*W+]*onooߺՈ}F kؠ bRBcX :D\ޖ@OW-]=rU*RWgW׶jXbkjs>A \NID[uĶ-P?I!qDnn 9ᵴQ"N6D` M,%ֽv&4;Xvdb8d;F~8p/пR&3jgϨO'5>Ƣ 5p0&$+2u"0˭\5mrH9W;sQYf:`@Df1#VVɐ!n㖣i[qGbdy 6;n}^Rf03N1lCͅnO =4eH=~1*q vepe (*0D#. jB@LB!MR)-rvZed3™31` ʤB ) >vwVDZL]wD hӖUU"* %=0q͒"YԀ &6; ,NJ8 d"?_yvc?l}Pܤ"ބ'ؾAPJ)NӿI`&E)d%$iHήήi 2.zzJCZjaE)yZHTJ5uw H}#BB*!=$ (U&Kʆ0QDp;,TV;:۶nݲ!" ښښ|> |!m"571 RpTwX7oפOvF W?~>b3`q ܙ#ܙ{4avpǝ|pk臛Qu4v'0[v~>ٵ?UJrwX{ѡMFq1c7V"Q$Ϝ|#/\k `dʳW@(l z:_ѪɊ9] AJJ%$}\}˜ʚK婇nbtrB.fl|OP!7 a6z~_yWiK"` #Ñ&maK3y(>yE~lᒷ^џ]W*Ui2|kW.yG>SdXkґI=uW&jތ9h¤ǟyi募ݴsAXf=-mXfux!rvՏ.|i/NT%2jiIx+#W| e=d"2!9 ( #iɗ>s/yG&Eƾ:{ڳU>y9Gק;sϾfמU'=Gzv^{WQU'^?/zg 4r'}ݵ+~wO\]3hCjXTKJOR*WK\Jհ\/U0m6dLl | \>r\> 7=TW9Ou֔E//?~Y|\;EL#]Te~aՊ<ȕ':~ Sz왿[r3N=$ ]ªw&| cOg_XzgzʧhdBϼ^m޸zKͱlu| kY跓O9Md>h-|aʥ?'}Ҙf"JP Ȉl;)#ic(: uV(tץMkm (JW_(\>,[7~㍷0!Ml^c|k+?_(ۯOmھ55}>|A~,œ<ʣy_\( Opُ //~׿8Dct\س7ß~wWWGԭM W"ΟVlGϚrO Jq'$ȸi~9?-kGO}2veS?gwNKGsYuĤEM];o_ mnsȭνn1Skix\0 _}jyKCYk?s-Θo5{<,x`c&?ג6p“^bMĐ^ t]`ɖJDDL50YP oIq  ơִ! C͘7qwNυZr˃s9r1fICueu0=T\ `ej?x܉ÿsמ^0[q֏:9;vs-Ns:aQ4wuM)s~__|s豷,ꪣ<:s1qԏ{97{[N}37׏:9soxgN{ZFrׯ?rs\a_O/k}- ZwZ0adZT"np~U"r}΃*D+9>bM&-|LR:[Bf4.c~n-g謯>~%x+(1RU62 \{/> 8xԡ7,X0}ki:.|oܝ>sŧbsrݓ}ᦗv۷_smKo;hx%ל:gmO_xgo8xɴ Coۯ?M}m'/v3/;wZUMܿxKΛ|_qM/6{Jy~  {)\ˑIbhՑB B )RBI2wkNbE#3RXc0R Ho[&K"1l{\B&E-m-ׯ^vڭ]m!>8xϨ}RAXpEݕ 9,|]m[62(a\)KQTear9?W􃼧|),WQVz?ֽS dKvkHV`Aۉt)6jKOg(sؒSuǎ3w-vm]ۮ_G?JeICN _J}΀kW,p/?u^?7m3#wgz`/}W01_VzXYѴw_{[lf>wgӾ~g7wf-Gsӯ_pUo%yyυORwqW/bv3連K}vL͟nn{&>f{ƃvME՟̤ >`ۚ?r=/ gYV'Xβ=zL,ƕ?cGnk_Sv~2כen3T.Mbl.| jqyw>~fG_`~wyC/x.x ӷms]-z/{}z{M{˟aQfu~υ _mKSb$wۚ~E __l[->yw6}Qٞ{M#?we/-i8nKuz}E_po'>Y<{lAHF11ui:]1 EO^ѱWfg>qs7,vGKCG\sKu|mV:xy.)o[e>vSG{/]pmvS6.Ku76ۚ;pܹiԡw_ {6ߌ'nnıL u|5hk|s~Gw/]|UoXx[.8fv;9Y3a/5xwug('|뭷/W?jHxIS|ކ&+VٸD#x/o|3.;qD:T('ިt7uj䬟_zfߞ\PG]kwτ~9}f^'f=< >^}oI)sOwuW͝'N;%[0;fʯt߼T7{Wui\:7vIml1`G'͝ qҍ[(F?37ןz˕>uMGev!|$0im2h!h #mI& B ryJ N^qxjk7vw3fCdbHJTJyIzyҥ=؈~5հu$Q{C ) Q5ڼu{--7{*a@5l=Gg Ta:t_S |XQ'Q4554likW@Q.j5;;i@)抁TBJTRT(lsR!9f"?0U@A $d\9X8L5hm0$|:OބB(5 IT$3׶k۵vmk6K=Ǖ/W9S7ɬn8C6C3f,xdLbmM80au<k@VIr& AQl^h8-=5+>=J ܰ_6m)75~JӢ[Teo87 aw`yyŸ&p-G5tOq\}av뺋+}b}%mQdLk+4Nϟb`s WWb+3n_2P?_뻾QW8(ދضdN~w_W8mNEmb(e[\fN/sb\ĻB^,Bӆ=HrP3J YlľcltJe0c}:S w8 ݐQ*U?w'&fŲ˞#90~V9Gt˳j>䳿І`\]w:m.eض|Na nq^[~}wT_|[bӾtN~Ad:0KM֜Bm70n{R ItH)X0w3__NUۖ-4g˷ڧgB|w3LALz'ns[[:7n:҂D "yg|U5؟wSNc|>gy]߻$d!>pm ڗ-#O?^1p o9_XځmT޺t^~N֯mȞS+ l6-K瓾넺-Yan>7k{|3dP9y]ߨ˟v{[Zj{{n~1_W3n݆UyO/Kqu|X?;̶@ SƦZJtq5#T.:J~]5 7umm75E rEFAuv}o5JUm45=7?xvzsSPkݾtvnPQ2 .I,FEQX 04q#>".Si(kwu9DqXhnkЄV`렇  z߿yƍJPkPkLUom޲[zJ%ͦX(-@y֮۰a!|A 5Ś/ʪzz\ccCX0;;:o {JC]B*O*M.' ڼWRBP Ahu8 {o0}8SQIF_/k"6w1 |n3O"T/ `*WKD x/$!pWoMJəJ!L=7|&W~'''|.(s|PBXr9?eWyDđVS,yej:s6~yמw]-8#|ق!HH0|=|=b1#3|1fT@4&7"Ex{zqS>R5 u6mݓT*W=߀B47pf>WM5b96T)m~Cx\)MUӹRw!vd(*~nŻU-f=8SV7M&QRh!,Y ))($kjM68KYOy|~ \R &^zߊSi~U[iŻH _3jfҕo=G;tľgȰ {Ȉ}}CLֆw@Qܓ??']4 Py쫙 Ч˭ApOr&7J)xеSTyW Due3M"]^/jw+թ\eB{ XW h)Ío 2 4m x2SEo5iÑJ5*WPSMd]R ?_(`}j~ Fyᅷjcg'~ΘPĬ`)Dd c\Z&BS}}~?>FI!}ю~!_):R:G-q?4q}yO.WS[/}ѮbmԹ0OMYx yT/֜K8,b'nڶ/P6! `?}bP[Sۿ>5}%z]]=ne4L 0P]!d+@ah'gQ)WV0 5Z(Ȋu"F)!RCW,$yo٣a$$]ۮ *5Y[CaccGjv SK25EH>4误Y߹A y,{-渐Dwpya+JtB:𳨵)l};?AO7m/ӯ>u{ed3uAE@li0Һk@Y!Ö?֋Np6pQҞb&lF VvSΘˏ0aKPhix†* ~xasW?U~8-!(U>=0–B1oy]E_^'RU='_2n¦MP-KOE0܄mH%vgqZ tlu+b:^!;~s C&O[oo[n0_ES&3^$TҰ~Zf~ *^`˥/kskM!ݷjqm{^a 搆(\SW6en )\[igRRza&l)Vʹ3p6 M!5e=iT`VF6⦐v*O=ZDT6#`sH{jmL?Z4G_[Ϛ"@,W$jPn0 X\!%erŽnZGNR=5U=)BH 8yp_Țܺy0 ڗ[.;;'9!Z[1SϜ R՛9 usH{qo)1Jas>k_ל=K !M M! quIO0 h&m)sb}~s&"`76tX^-g@ 1a3(\[Ϙ^n6WQSHجU]\ MIA@҅ DϓJI2p5kNG:l8ʋ||O)C2fzާ R:b1RJc1 3E YBI?` Dm@F6bUѭ tAtkYYӽXwٶ- 8HuS|cnꪪ*PkӷCf/DZkyUUu.Aq:LG12 8!rL%T\Un= ҳg(w6mkŪ`J.6 dD G"g3<{] c fdA(#uJ8J dג5d-XbhF*.#rt4up>~ 87eveG|jCT3U!\ k K`l@KMbłKZ Y55l^R cB@AɄ*+rl.2a )l\f$Dd.[vQuϿ\ήh՚&֬ްWk_(QKUeS=xbgRkSyI|e)Ƀ,A0]M7//9. ۡK[_V#0$|^`r IDATgRc¤YR*Rq:ZUa[Ee  \ 0mIKK[ XQYY]SS[[+-˻tp'{WwVTTWg+*30 2)Rtqq B|>ߙwBP1QG)rQ~]7\ɏ޻#O}eqV+Vcm^uӺoݺq햍kݰo)?ݒp`n#.7/fs\ ^/ B2Ȉŭ&%w |Ik]TnN7/FgZrn/7/ _ܚbdPP`N7/ XܚlD] dV0x%%[ Cjټ/ޅ1RCl^y%^8ZLIϨ(. ŨhgcBpa&#eȸ DK5)eJt!0!ǔa*"Ct?0\62l斴/?! a&+ۡ囗27{+jӺ6_ijLk~2dMC>={xk >ψ!|AGQ=ݒ';br%pZg(XҚldaKi_:(8Bas%GI)@2q|R%KF9(8:|bLKa՜` ;?߼G pڪl(iUwv=wtwqG0e0 0da P ZmMu jWU+Ok+ߞʀ m1VoY82w bSQT,Q—W%T ?1Jrgq| 4f{YhqX|%j\og[:Ϩ}wn~XB3ζw2D7jlGalPőjShq&bGaa=30e2]^o^\(D?n-3¥VoYLd|5H ڒ!U#,8GBXTh$Θ+! ҦPb+  A[ Qwv;;;;bGֱѱVQ;흅8ȕkJie96΢\{TUTIX[ۥ{φCuGѮ]J0W[UӽKlѴuVM[7Q;Ё#~Ï<?l`Yٱ}u֬^~ݺ\6SW%W .%Bf2Օ!_ȷuvo6h؀!ÇT œ o,AҤim!4 P\6Sfa 0f*LN Ads.8!ik\I Z[cj5f͸$kh25zZV/̿?=~>{޻#=__XW5??en;|t'J˚ޓn|$R8Gls[u-_9&XK f{G^ uGzn^іVn՟%CVi+qGB#ߙ#0Z!X0<" $RJɥA@H)o/kk=}2^;pHgh oP3~r惷2g(!#Nc߼`У~YS;k ]OzfO7ፂCFt}c!. ?yDOECO끱˧.#8[NR 5/,y6i/-w!cn7/F=5r)DcnO[Jd_/=wԠJӗݸXԴ;gP!nh7==鮅㞛620〿1)yLd "e+raAAȅtU2Fi܌sd5GU>k2#0 J2WAg@!ݭW]}ϸX|g>p먁Mð1w-|곜LaO,sg8w=zdj_:g,A{w??m9O.?-ܴ`L{|h@CF`-- o?e!sxl=.υLPVWUtRӥ29-Yc5sRL6l. p+8qP|g!G8&6V G G{Gۉ'Gz{Կ|\Mν{,°bؼ){ͭ^"Wgo;jD΃CF];3u/ŋ 7qHmG[v5s> |T&4gф.=}=إ1S[#ǟ/ Hǯ~//"-?Y܈Ȼ 5eiE|~/N{fO{st 6>dLAfuOgׂ;u9g>$]ZD9"G * qT:$!yq:֝b12lQJ+W4d 8ѹg];޺kg;;(L8D.Z0ڪX|gggG{ؽ[u>CA -?u^eW6Td* a&uֽGCƞ }$Kq!lkwnӖmZ-YH. )ŢFi s=ћ7o\k,vw;a;07/p(XR4:!Rh$bvRJ"p5 ΅c("zB1(c c(B0Bp9!Ywc\MdD&}8_wܟro-dF@dc_0SۮCy9safSq= ||axO7~ͤͿ贮paԹxۛ=[Ϲ+oh'_{wEΝJ*rܹpOpd1N4T7[|Uso~򄁍._8^s؉7^{ UmMk_4ůgs\&#e99lDqU*#{hQJPqF1ZbwvE*dY"cGQT,8:.6rLs@H䚏8Vq{#Y?JqH)sI*"DKӮ͛^g*A6 FTQ狺ӂ!VVgӫk]Ue*=;:֬^m{(BYX)Cd2lFuGӵkmjf3,a& ap~n)ބH&Ic!R3/҇2 Ðq)SkEQE"p)RJS&pMs/`tu}+`g:&׿57 ~o!_9? }AduptGuL6ƐV!Mz/& <CֵEKdK#JHaJC:YZ7AVz!5TJvu <\ѤdHܓw uJMC2-sT iQt|K=oIYlo~0j}gi';DLޥ#(J3-R@j.Y6YƟJsN02/%}&&?}q)sГo#Aƥ'̉\yG ͺ![ֈ3=D,-L+ (_6 $N5N $קq| 69$*AP׍xV7HLH 9ڴo2q]%oXړɘ5ݫuoj{)i޾^kTJ(A8'Ǟe':Xcܤp93.@;DD!KNcߌ17 CEDΘR9HA 7 q)7IOc1sp^T'O!q)D62bJ|g1E(+"rִkBkV%&8C.xHΙ3Ȍv!@Zeߌ-c2d t j)r #ߦsJ (VPQQul%qcT(WZW䞇F'; "`a& qb*߲UkSz՗? Ɛ5h-`xGGԴyU a&)=ݹjQۭgV3V(oNi捛&հY<,䚌a1nܱs{1*p{46lX>}Llvصk=;ndd=HЕx_h'(hF`R1j$ @8Bi#`"9au'_o\*+"|@pur;9p_eqMz/?q~/_΃ۇ:OYxŴ'$%3-1:'[\:=-0|Mz r/R &[4<@di{="g d1/"H,/ʬ j*>tXJ lKF %1? 2iIs\*wtJ/@4=)6G䌉<) a5*)T/|j\Н~AYonԗ&?"`R$p *'s!k Kj?ja{U|c{>L&+  *knuD2H 8RJ"ƺS Q ZrsVrRJwO6JDZm1VY B2D2Fm-g_Es BwXUUHktEdFX;15 2 W d`⨳#/!e[!2@@dmƖ!ZaZ539 /qhfJ!Uˤΐ111 .X !WcGjd  3a. PeLHs`U1 ƕ+<ا $2Ƣ`|q3aE8@kaYuqHcZYԭ[wnټe歭ͭ s  C!2V["FX(QF2a0tn{{݆];s\ww;J4!k}A :I*"p&T ֘tAASwdM *"ӮK) As\omoߗ{/*2`=?pSv> 88 | Q9۶m+s1d/>&({YR&5{HVkJjĕ)"0tDnl0ɺJU(}t939g½X̛Uii| u 8ȡrJ?KiFHP$!$ 5d-c(8yg,hΈL%ro/_e JhJG ,pz`_MBJ,:sJi'\h8 ks%26 3ST2S$Nх U IDAT^صs=vf*rVlE&̄2 qQ>_t[&VQ |gնttWTda&إGMu-.sq1 cdkcrrq=Snb`dsHt[(oj0DO~_T鲟WޗC`}D`oſ3++H~@F@PQ{@}9v vpksMV>^Dd\*#"s I,S~*1)*MC'+Kg% LŜ^p~5@d uS'wl)-p6ћ6^Ė˔^I@!Kc8j@86cc`52LpG  (*SRYi8鷎)a@ ʀ/SVC@6N*֒PrfB#%!G@jcܔc%!5bW'.s(#K<5y.Ҏi$wkC'g XB%p ʰST9A zRC"Q~CH%9B".IZSPe*S! y*MNJCQr_)IJĶ]?5W3nPu rN/rN2H9=Dd"9rk8^~1@RrƬ%c6D$ 8R\"B)%SuYe& p΅R .2G~|3Fkya(hݝ3+1>G 2!6$B1׭hnss sH; I?M6f 82 ,C2ƙAaFQkXdRp. )KZXmH8OE|ʗ x[t3\r5PpEX hEي\aJ)\­g|N,BV;u1.x ^4&ZrHQغeu(p^׽[U6޶cT۵{ƞ=zTdQqk[޲yw eb+cȈLl]7tRW]UںkㆍmmB,ck"gTAw dP]uQ߳3CG !c%)"FQ01&V6Z)$g ]xхHLHȂZk qL1lw1/A/ eG_`>{aGww+<"Hd[A~'λO vE-[ :,D%HWJ'Stʒڥ#|; ƌ52'9x%:[|L`-qTLƦe ssJjpEMXloVpɆ2㎌q9Iq?MĬS[s8Ĵ]  "S//Hƒ%BpfG?6ozwϞv@TJ+Pu >C*0FöMkVݴqSks FNm= 7tİRd ѻooy?lk83"LQ@3C`0ӥ+(,jDvW@ cRZN.g9 t^ 9iٽr2 7qՈ EPZ4Wۈq!Y_c[1?W>V6%HGheI;?[ (%@H8!K"VʁLRJxdL" 9|h}u3nEXJy6L􀷜!CN[Z-KH4u*! jI+E8F ytCt+Ƥ206hs\cc2% pCXFA9C,2nq-I:X )dܩ'.^ڒ[Ԗa9+EB-R$;kO8~"]eRMQ(^M%bBJ.1L8R^=k%/c (V3uBV₥'ʧy}NFڐmH!_<"g,E%ug/8sҞ r>2\I N}dHU3;6 .]L~2IGD@]bΐyC)Y(DXDžB!"%"Y)7 26!eR4%fDA 3 d@2Ν(k 8VZfN~g9ȹpy"k dJi4!<ud=:ڐPw_) 8Z+k-"RJgXVF[WI&|(*8+*r2)y沉=Gg8(M`^keq--1aںښ.aG=RQ>jS"d<55]7h0EŬ}OM[6ݰm˖ζ=̠ & hl1j-M[wv4d2he )0F0 IAmMm ÝvؓoKZr?$zuwffAAIZh\h֋|ZKZ+wr_OV0VJ38ֱJke1q .?kۿަt\R?̜rc3,rLmAGρT z?2:󄫖}wrcew}dc $#+b1Mr4vv%mk-c\H2oj$u2#* rpNyhɯ:u[|3U|!n%OiEa)u/'$jgBrDʳ$D1W,krce0p؈ĬWc4zg|=94k _*5sr^6$6%fcOd,Bb>I2 1AރøO cc"KBڈ0gV)eck]&1\R_cik4Yc54lB@tpwp;nM0*[6唔 ; KWO[2Re7T^Gw P.&]}y2ѵmbN}A5tG1 ؒLfJ+ J' qoNS΄:cYZZD1ļSXD%0u:M%@@#:X ]%ߣƦ=}rlk<$2(H@^9E_=ѵ{ȩ"M;D̸_YV od+ES&N"zUb3;(,"B%{jCMk&Iu 1F'gS0MJJqDGاAs:%Mo`e4"G$  Kt}y#kvKəA%%42qz"L\s:ץQ'/M C*Ĭ(P[K.!.$1>B%IOz8r9ǣ,]I8<(BD 3%9Mhǟ"whY$.R FX2*V)& 0 d^9n.]:6Ⱥh76bPp$ /q Α1%fR#74eZ90ջ:CP!C q(_,b(1*V*` &d cJJ {Kӆ1@1w99/@d Y\pƳ .C4>a†f  K2MlQ*֎& e3 V{8TM9P 8{ y3!MjTIG]5]|3\82GC=z YKhȷElذfc֦=md5\eW^7X(q8%l5-(BɍQum:"!V]NFyP'7gc ye ybV7ֺ'1J!қv #1 iim %2eqB,n>L3T#e3aD*RpkDkvX HMP(";pCwo][=:0, 20Ԉ &fl*OI+/֮r?dD" Q/mx]߱arK'[YD{ַo`ƚ[.[4疧Vtcwvl:np5{Yp'W(e`}}5{]p_sx{Ԥ)/0g-k?0c^sC9fҍӾ>aHϚ[,]8s+Cs\kvoYdُac&tE7ٺvsZǝsԋ.}pΜV:{9M׺g͝JTCQvWfiҊӝuex@i? 'T5q>` ~s^pOd}kݺ^\24> YuMkoh'VZ/ c$DI&^7q=t}r.Y8kM9Oppkěo<͇g3突n":)uه{u7ǝ&MYOpEQ^?}澙{Սn~=wM}䕒9Nlepp4|R/eNx#1< QUV2lؠ9t<T|O:l|K&U{מ?vPC͞k{d'W8LNDZ"kҷ9狃kvoY<]\&|Å5ٺvC?1gp7޺湇f ןسnֹnk^+:VDtY7^{A 5{cs|(VB]w7ٶGogZkc'?v`C͞mxOJ`cΛI4T5ٓw6QŸ1gC )0fsl.2kt|MaBItǖ,Y^_/pCcƘ߬>Oy m&I.&tg likZtP,heb1_,"QZkɉS\z^5]<`$>Y7\A ~韉/eWmM-ۙ\jog~pP<|Mm ;#ϼҳзiOF@O|+>o}uG_-.#Nl>۷GU{_EϽ!DO6k6mk(#b!EDuAKA.˄ qIX"DIg& &Ed`I\.Vk4XxxLѥ*s.*t;"e:;I@]YFvuܾkۻlصcG1_`]kwRWmݻw777jr.G'F)u1eUUE}}l6k-mڬ!θ`1ŨXblb8p2)M8&)q:jy; TiyZBH 1dRs倵FX)vL+\j~?4>wY>m<1X 6Ĝ~i[ ,7.>7otz- i3^m)9IT- Ts]%%+i7C=p(ܴ?Yzyz=S-[g%{DPjYc돛e/j1lԭ>8}i3_iNd>P,:~Ƣ+_5̗j>EyST?zWfsaG_Ҷ=v8O<:g^nyGp/zUsxNZkѳl?m:䩯60+\~/j1|/7aGsm#9ᆗz8g.`˫78~37}vo\D%Z7Z:s5u|%FzMNO~`kRNԱx9x=۽ f3ُ}i!Hp6{Е.?¯c[8mݩ7sJL{wj>XͿmyEW /~?4kg\?fCWrW^^R?lEimn3m̗ji~i_i3ue+/Z?lEL^ii=u_ǰQ?pSoMs?v+Λc?[Njs?F._G?Y4w2lx:i .`3,Ø%2jIJ)a(#FZK7 tWu޵{n:Y WRRØY\ǰ1s-içf _E:-c.V5sWW57<և0}3_c.pEv{ÈgЌmݺ17Eo_v+[ꇍu#3Z?;~7^v1[o4gEsè߿/ʚC̺>=7[뎙K]1񳯬8[޲qӾwo]<7{ 3gS72ֆQx յz]S3^zÓ)DB 2aFB; H%1 -gV2d\2 8VJ ؊߯ݳgRZʝF BqC)uOƤBBSイ)yWj]6s(GqG*笉aIs~gon1; uUg\7wfm;{+̑ IDAT֭__u:jCw_9' sVm|씻nhhɛfw_Ɲ #N\̾kZn7ܽqqW1ͻ/~cκrm{Vn;;I[cy]W6?lw~N'7@XT:6F'-pZ@e )X(j(* )E"WUU)H˪X0NH̒䰴i6hm-@y'b"s*#Y bh,#-)m#m ƆU٪LU<*ZkTT,lݲy[KӶ]\E6vֵ28umvkkk{[;Gp0)b U\liiÌkl˘`8dZ,I y}?t{{11"Z MJ-~RN ;UξD,iЄRtEk!ushBJ)3.W[,?GjYЃ<wБN09k|sߣزϺcDv7'޾dW7| nްπWA͗Pgn>vSsOGC)om\7xD*ݼw.rg;ͅ/G4,+v_tTf_u?r/no:}y/\pM?#xkffsmfyĆ%hT@vcNE,  {MFAP-p){f1{{]ffϞ>yyC.~X \kU=Fg{ JեGNSC*uu{vſzMzE=1j%/'.s㦺}]zɋȩo421T~cs^]եGMS{zqQݞ]ky7fƺ-䈉o69jW>_nÖvBܩSTN$U>|1.>޴k2~`u]?r;d-T };m˝nD׫/=&7Mz3?1j)yN ]4੫3wpjW__\T稥z%GNSoբ]zɋW|7_g?U1FW [YO_S~z^6zꟶ#s_1˙cAN[A:Qho:.#7dnظ'ox]/;1Of 7|k=v/2ݳ+Y ?o{HѴKϼ󊣦ޝrP福/Y=)f>jseVrxS}3lr{~ꚺoy˅zꘅﶸ5Uw[y췕WV@Jsƚ [~c/r?60rO\Sw1USVvc }-?=f2tsl=e<+zW8P6|xǕ=n~AG/Eb( S~C]G3Ͻu\o{T7oN\ǏU/q‡_Z|6?kD&ґ&ko6O]jr{()=!x3,W>q+77)Kt伧.I QWޯo7|>׿Gzɳov@ +i>cf^gozQA_g_5e̵Xcl=f_?zܭֹB_)=He1m-m;w O6Q("]Zc\CC}>EfXMր`CjjkkjqmmmD_I %b25QV-ƒtqb=6b 2ꃄJ%j@$ | XZG"댁X,c` iEdg~ɯ>cGk߼Ϝ M;]|]gl9|=ɯr=_r ߗ\צ~3ooκq]mW[ibz[N]p/o/r3̃7?wss~dߛjl"e*WظC$;_[u mmZS婢}'~13g3j8c!8(b{gpXB)> 8*5B*)Mޖ^żt핧\ pāk] y|U?7cXZ/,>*};-@ -TdZrRU?7BܹL*%JS{2+U6RBflL )VX>c}SQBP+WO]bIlytB.;:}6יq{gX]:8-n E0t}33yՃʃbyT:uicW)U?-nٲϟ>T>zT^}1ԔgxLሆC͐US׷$.իYrBU?|ҖbKrNJ6Y7]yIUSkNoTBXrRUw[]\+2w X|bU ;xLLo΅ﶪMLWJ~S0a߾5N(EB >l3~njPL%@i{o;g?l+%>ii)=?SGߣ1~\}smd"k%%~O+/]kwQȿ?R}&hƷnMWm=?y1_0Zuk=n[`}@ VSӻU+eLewNJ -ݖxגUmW9 nvV \>*mJWμll5ABntJ?XZ"z Rt* Q {2[pFdQJ!rpк {S{e`BGVGZk Qd{amѲמYVJw??.c:-:̀(7I[Q}z9BEQtBuj[یa(v{Kzn92u- 6w_L "@Sw_fE1=ߘ@TRU`=S?-a"MP925n聰"Nm +)qԴR*'Lݼ6\(ԃQ!v (arzRPu!"n"!~ɤSaJz^ͮP KtH쬊\Gƪ9Gb/&ez CMG6^(Re*ڛ[ZZ۳F뾻Vճ2)v54h1Ҧw-'WZ^^*NA$JDQ[ZZ. L:dLZkS0Qmm&'W'_QO'b`!Q*TL#QHdD-e2DB%Y"!kfhA2%҆fc'їҗ !.v7`CXc'BU TRH!{Ju >J?_u>s/ȿ/<߼cb_?_xb,%*Sٯ~>Cٿz5G _ڮh|6*g]v|ͅ(jWJ*ʉwliv֭rȈ1xÆRA/Ns{ MkZzt74ԋjK 0N}*hkf6ho$DVj-¯A5;m$|58g6^EQ}k"]|n+lCװ55تWrޝO)j~M_|Y0s`¯At? 0 S0N3LII$SJe ^\KXm66rS榎M1F \>nrl{>a<蓏7cK->8};xDzbGEWLrm-:ۑͶmy,'M?syk ['+f>M hk5')5YR Jj}91US-(Y5Rb/> ͼ} ¯I~PYQv{T¯-My%pm|O~X:CBɷNQS(T*]닭px(&6d]~+)x&L:C_zRX)K?q㹣*˪zQѭ4J@,2k zÖrS];m3h@!w:!F 5؎Ryj3l,ZٺO5~,9e间 Qj_onrĨ:6 PW⭆W/NSN*}`շLB'«bL:=㎹J)֟ =#grDb XS-B˗\E}"Vp|m,`Y& +Les;6&sKuVVZyF @lRuEl{{@x@` :'$ԙnalvS/du=_GĒDF( #;7qܱ燗w<樃?qQxQP'Vu(OY B>g'9i]4on(rCK{.r2I*tVybCcˎg$f[?^Ok*O4KʤZ6)WUhU˧{ǦNx՞DK'«RTzbe^V7 *=P |܋%5JO4XDνt^xV[|.ޞmo϶wtd B@, ğB.Q'k<%J2ݻUR)m3a2Nn"#2,&Q!ґjFYLά)\G(Q7rIJUZamΝMmmkSeeҜ$riIأGE՗>ޡ9*DFGDZz* Ò}7*|[ZwvlW>xk{h;2^T * RVW{<|r"$"*I 5d(6l]5`0"R" JzJ$J% AҡHJL_ WߵG'+:k~N)c(~7v&do㷵jr !))x5 ;_UdREzìrtD!~6/"n*g\N3ߨ!zI_S[xJu,B]lH]:8jߖ+lW$ G/mC2KQCnY`˕ys}D}R꣜~\6rfәHlTu.$l4 ZC0o>e%+6*l:j!c:)gg;SR}lTz|\3ΙCQ=[[QPmٙC!U؏DɆ_h4qDΟ3I7Vi}-%%2Gzzjs{~% O!26jMu6mTޤjBӼY1fBKz*@K,"yG!_f|XC*Pz-B>j|.ƞRAST*H%RTRA Ȯ3Fl32vz}J&<^p_d .2yҶig9.t,XF^^lMeTiD;" 諀ЯmJJ6<׷W>}+{TAzˇ%[%)QtYII[5*ә HehHplK رۍsRYݙ ";1WcƘ2F1D@%#8D  J߻w}nugxob_ct)<u}zuWM>YHcВ..קj+Ggf gIrһ۳6&W}ن5R"n\cB.:1PPN-.G 'fu o]|^O=;3I/ 6rCʧ∩݆ѰX^8Eׯ`QwO||ޞ=ohٔ7}U ?;۰F\==&i\-O kKJJٞ5SlvWcgQ~f{ݫDLzߟeٟU3&E{(RޚuF 0qٰs e\6fV؇eT6wagt4ΙqsHS2{(()Dq(⿒RA@!hιXk)ot<-{o4!D>ljWYg|NuFhX#<={njtZ=:/L1w=g@\mkO<ژ=gDnRzyfnxcv°p|n#n[G mϞ6l.R1u iK&k mkxC*f\:G ۞ IDATXlL-;(WueFG! '(~܁<  >wך/3av]csiq;6ݞ=e̜wZ\tЄ;v>c€`;Yϗ\ROy+) Xڐ,08εPHdRJ!)/dK m ב#KNiTVU8n# l('u!5_r;͖Hkl&lkN/ ϘԪD[=w>5NDP6G0\s}/^ F?m{hDZGJ mxv,^j l'v[f6|L17S'eKoq%o| P<ߜ?n@6Q#W2onċXJJt>wJ tC9 a:P((M\.…o늢ݘ[bB)%  @6 CrB]-;0P:mo~yEyeEO>ږ/0 *ujm" J``lTȷnhCIiIYYiI&f meښٳgϞAlTJVVe2tJLJ y)/L{2`2k'c0NktYYH`}!_?n|WИgn gO0(oyb |x{ +;Z0_,q97G)K 6b݇s{ }!#<|wxh]sаjK]7A]ȳڣgsp&zpS/[xȈ%e=Ftg<)v/3>{ng< (e׎[ C_6"O|ᨑ|떍}|:^=qK)Q.uOlAjeCnZ1nGSG v7x'pƒU#CoX:eDڒ҆bTHPRzJ5>C=.φ9!rJXX |'P*UwYS~`AC:| ?dXOE{hŸǧ=*2#O9}kW !ke Y^F]|sK_\7oJ3a=اfE0kg=1fGV{RkżuA~|!KAL]p׬'y=hD__u1{cp>KKqE<=wf휧 ]<əkḩ.E2iF[m!:vlmo 68Kd:4vH|!:%R*)\S0 _)`4pAw4A ݻw^UUU55}!⇦>>n ƚ,Wۑjp㦎c(-)nڣ'޽r̷G5O*=xͷU1sy|臧?1fzʫyȼ[>9s-إ0FHQnJ=5 8'gR<>1p>2钾61O^g =4co^*sybjWxw,=|Lz7s㸗N^ 33v*M*%RD`us]0)޽Gn=**eJK0|?JwTT /ˬ+{Dy>{Ϳ-y#auAGrk;b}w3ZoԌua:(}K9n{wxL~tܲ\,1=3B.zd3Ϝ8g${rOxإ Q~м㞘zњYo}=|٣_/Y\ VTY{v;a3QgZK~9_qzF͜A=UCln0>uΚgB>*̥c\/(a#$ ]))/S|N3T*+6dY)/ Ӿ $3Z1 J)|!h]rlla:ҁ TN3%LI*<dbcܪj2tdt:ycX揚Z2 n^Կ>*LKCMl`sݖ(uu_ u[>nknѹb vh޼mk'>[oA(ɀ|G}ǎ-L,շo oھݺWH$&(o G>̹ASd KsF ,qe)r|kB#T';/kD!զ;0r+Z868R9a) wW,]+>*"F%B_Eo㐿6Uk|+_Q话 H+׻d&jOĽm]q Qnj_oxY ="|ݳozb9{)K51s౷|7T]uɍO4L8qCjK[>Xs9hæq%sVc_ش}68$~9X6Xa# w%o E6pƤ?nef*3yoNz# L~ơk?~WrSύw특s}مߝ0yڹ -m`y{~紫&3vpMi[kVΟ{+pyGn߹q&=g͊~մs-m۸v傹@θjo;WmpY?:nh[߿xڌ^XA x$w'܊Ҭ?xπ ,sZlj?gݴ/eݙiwəia+/>h኏ml?;b]1wЄ Ww+Bxdu߻![?=mۇO}M_s~?3.mUsn\R)cT5lx|՜ŏ|!7O좓_Uڶm^xknwez̀ҶmڛVFgXSVѕs}U7:ugTSVsO8Ֆ}nŜJlBIpEMJyJq5,}ɧ 9L[n۷#O•`n}'NǤ?ڷw/WMD(]p zn}is~'?/J)F|iՇ>N;^kU']~1WJN cՔms>𪛄9mҕgTSZf S&]qW[uVk'O|j7sߢk_7q⥗5vPMik݆V̺:AgϸqJ۷7]kq{辕%7k_ \~.̱jK[6B$%BP%=0%rCNEhB)+)*[kq%{JCD.aשʱ5hmYk ={KWym}3Hne5{YUQe l۰|&Qrvg)mu!lDEʒ4DQF+SLJTWR=** O1 "!*d QzJ*#ZkA82,(Gd R8!S.'pb6ԧTݸA2DT!֞RaH)f&y (25#:Q!oafWSBb2 klg8Q !̷$Eb7'ȸX l6#ZRR X<=F6bښ^kaFw-[?ݾmm;۳RB1XfB&XG"S~ )C :m8y2]+{^:^^)) S)ɂ5`@NT"* DutXRpeV\&ϲerBH ؙvLŶD$@FV3(2YcY) 4vw]mWl#Kb 0P!b TRtν!v!T $J-ɮr'ZIKKp;,EdF.N@_8UDdB r5FdCl h@w+w⁖,EJ<Zr[H,vZ3qO'%e5rܰ(2$<2恣*MBE:v 4,bd2/](bq\,I9X: v0S uf1`""ґ ڲ0T*F38DH.:NĜH wH$|ubEf}BU &0yv. dP @p4BxB"1uB⬁/5D@%0D'y6vm;1N&: l>"geUY !iN$!~,P(lX 1gVkM.ׅBJ)eȌ[9AgvŰ#;Y dpNB X/O|`4p0YKl>$k+G"RiEu V@Į`/]&D˕al vow;c)c ¤ Z̀evf.b@תLGR;Q"ƻ8H!bUtVIBJ#HcZ@ ?]\k\ј p;Y)TqbnN P)%uh!PJ“X [lrlp6+GB.AdtNC$e4'(`RȌqP\|_1xDE BDQ>"2#[KZk"P$vv\83Ac{8SBLF[`R*%{IUekk9:0͘0030 "&DEQDΒAE:831"鮪svX?9={ec詮>uꜽzc 0K$'td+:\I֡] +g1/5%CwYsS>"g3YK,XYhq.ɻJ0.3ߓR d1thHy1Aݙv^tk:cc qRJdU,3`Q c@]g(~CQaFkMhXʜT]?D1Ycr'GygrkQJAj7"*DHlk\6(As.?df#<:k:+Ī|doީB3ƸKdQ,aHȀs&=/H$Iܕnq cj* \a*6ڒpID PsFVAyH^ \ <*lQ"\aQVe_T$ E+]F6Ƹ@x>2"Q[GNM56uDK I/Sl0 T*=,HWWTWw-**)k @K 3JvzׯBˈ2.s7K9&s$K #5:?1y!uPGMH}69/;y"L֗ֆ0RߨorvJٱvkZjiF[yc`F^XmjDX%O莭A91ٝbC.};M"U6VD>.Fng6}Ҁޣ,"v("1mG{7c> ft8 k(w"8#ӑKCsՈVPkMԹ}$1ڑ3<{=1ΐ!$cTiXk%a®X6t"= DMyR'bQ! dqRun @A"xC}8Jgr/b*DvXMLfD`]iXB 2!%R*9>Hd6A:a^ c cqUL4σo]QQ# 4YWLFNmž!r6t.%(`ʽD433Ľ1 #<^2' 練c\>bW,a`,s l<5cR8AGy)X޲,&ܓR*((%-%d(YZw?!.KϋMDqJTƊkdAlI*hwɅD҇cn{LNYbycXU;x Q.Fl thWkP*.ے#?K=pٱғd*L U6?QBѽLbi~^MŎc#2Sk; B Q rurɄFh9Ũ `i:)3nNM4i24ϖ󼝎qWt-3]3^ sui,qĄ T*HaJ!n$nH&ҵ\2<\ cŧc0sVwH@nǥ8L}QlBr."oɹU*Vj,G=?N+rLE %U'd!Ӗٶ)ަ"ڄٰ0ֳ[^**҅La`Y9ȍJg2@ā!:<ĢuM C'!2dƊ[k1(F4"""k,Ga"RqW =k0~2֒R& B~,}ȹ-8D\.ΏqP''3${7'֏2gQX; 1rmk8!]0o@5"Rx蹉"ȅD?{d7=#g^'\ ?_u[kc2b,uF٨3|1I) 1?䌈 N$oMlENh%S]$rF(ߥgh ?ꔐIZ'Df9Fғ.UAJɅ@!ءC'Jj;\pہ mrls$NZ` BkGݰ궣D2?u=wp)t> Zk1kt[[;DƬ! WJD^ l"d\G!r#+mVZkk;vngq,q9܆ޥ>D#U ƂĘB&*UGN(kl4r5/YCkTD`ka4Z]5oAe :CTb1Q&ƒNwo"܋tQQ(y1Ac1s#f:N.k 2!D(@Wjmq#3Y"F9yWPÖ4ERT:'RHcB. xR£>1k) l&Kw6.x2 ɝ0Tlh;HlG% : 5"4w׊QqK\FH* L+e3l{{֚!c9kz^m)3ƌ5` tRt48CƐ3)E2}_eK֐ F<&A$ŷܻ,chtA*N )=\h$=1#DqpV"{gaTUvrIN(lY4 rzǹƨ j3=t>~ڗi2&^4P$)CdLh@%Ӊ.%"0uMyBx$$BzN X0(53F""EZt' hș=1@cd$kD0ENF`XgnqcH IIYkC0m2sUe;>D iBc 0``-1`?=ssJHk[Wo{?wJ~[pן\Ͼf;lۼ~͊sV#<_7촾UEu߼ȭK׾-:1s~|j Ys_b E m=KįՅW2O}x_`YrcδqԜcLD.֚C}Zk7۟|"V!P.ٺh3Gzjʢֺ/=2S"痧<_zxk3ڐ}y'*jso}x?_▚9!Lrٻv/ٶ'ЛBH'~]mr)3Wn,!/<3u+޶&L#?jW ׭x럼sҬފ]֙9i휙i⎑_߲qjYkDq9Gwyh+O?0iڜ#oO89;D2hѯkq˖ O ##)Elc&"8`E-5_=wQ7~̰}[j6s嗞uRϪz0\Yh][lxٷ>ixqڹkqkW?\sB?bz]h 4 S)ev:ađ|%BΤ~Sڷ4[7go2ku1wf7eȤ'Ry4>',^+z1$k2c, sEs~ݫV]BJK Lq.][k7nՂ;]4',^K.ZXQ#ʽYp3pD/Nu'F}wubʂo_y|}~āў\6zWlsx !ǃ͸it-iU~c?3nB:@$K g5aP)(O؎"uXd3BAr8ijQ"Q}50B$ )B m@.WXJy@2#'ẗ́a.WZ&eV+47m~FkB~IIqO|| d*H&~Ԕ&P4f3m: R2? _6 (Vw:Oy :>I,Xc3{RaD5sl/+P wb29q _ n7F{v#YP6?dzS5]/o?wD#CnyǎP1ʽ(x?JL]9f.+zbf1S^~Ym^/]fޗӖn-~]/|䟾V=s#fӴ7?1q{~MeՂn{nsloYxg.|mcoD\DpxdVimVZk"('=)oṁ}I`C)ܱf* 02ƥ\JN`-ĦP= eLuuNYF!V ^ }gC}.OeɨݦC'ͻ뇽lC.mA ߮+?h{7+˖yW>Qoyוv;WLx܌7jz7o嘾cFkyOk:qՇM]quF'?;tɯT:k^z}uc<ȂovSf᧿j#nkլ-xQ|i1Bx2Lgt^~:1Bh$k@7{\Ʒٲ-Q̫ˉ FsCongo2RKG3bЛ+8zotܷ㯖X%̪teorkw=lc=~[L>7\q_U~wyoו<}ǎ:u[*v;rƲ{'֝pDySF~mSiϾMk|إWϘ}馡wX~)C{̙0 }v΂j_n}n+nKYC,_~~3yʘs?ڭcnw~GPL'ØP̅(Jچa.͹l|O$ҡqT 9VkEY`я?u;64mWɒ }#tLZe|#>l'M{}{c箸fלi8nf7;t[F ]~ccM|ͻmTݹ+>l,oszΟ0oJ49~3*~y=M⃯J?zߟvA#~Jw=l]OyvČĘ IDATNv4WqMn<p I9dq "d^Nd[G|hyc1JCƙD8Hke!2h'7҉ ;"CFK ~$tA0(.V* Pf'TB %BJ'LPC2Dk c1ƈ1c8796o2'`,kcdAvugD@ ΫMdF!4n"ڄZkfs)б˚ƸXQ4I|p( X;餓Ϝ:Ç˧NAW~z 3cX֪U_'#9{W7ދ|o|.=2A+.yىJzfg6:\ όpMQ]Lx^fLdoz`](#SԇžzRpD`V..J;wg.8hn]ǧמp݃f=wNfeU^Z @LylZïϹX>붺:؇ԝx]yl)3?itꭲ}Y{iˇ?F 'N p!fV푧,74Wxt{ssqc&~h-P;絥77u$ !x/f`A'q?5T.{M{a~̀!Gƌ/*C愬.em3 \/YIDMM:.]Nk,7` K}͇]ʺ !Rzc<61Z2Nr'^2'cOI=uڣN]6hKC>Eد>7So\MdGue=wvbcΝ7&]'+cmTfs9,3w u1u*ƝrˆV|c:'/yL)Ǯue#K_.,Dژ!_:(Ŋt*ƖZc6Z)k!Kn((*<:ug[0HhtgkXW-?e˾ta]S~Qg=a]ӧk@t!5}TRp즻O&n5}L2D`y;Rիw^ԹMiii[HWLWQFSg+K7+>im|eo_tryj* idݹ7x_pa6p0DtI{?~( tdz{﹫5/6n\tKcQ',m3L뎰IG "w?ԊUun| U6g>C^OaRfc GB22>X t6pmXwb1wZu/UB륧U$lqB*{UI6LU%ҳ*S}‘{S)]U{uM_WVU8aWCԥZ<7}~w>m wNcaXfKZcu iϿ.]CysIDRcccbc'#.CDT1-r5Ppa2FYK۶sէrPEP,q*ag']pK/yiԝzj4"5F-X떧*@v+6I)B{SUzފ3*ScyYO$oa U`\㉲=41k;ھ~2Q6Ǘ&Ʈ2 e>x|ibwۓIڵɊy~ⱓʒ'l^X|wAX `t*HGn Pg02ƨ'7?=/y|㙿~=do{ԑΫvXoKxNGuö/VnkNK⨛Eǟ~{qjEjħu!z\&ںDP߳vß[{o>`M<ׇʆΨL]6#m{SUş4\k_zeɋl=H߭˒n1nX(Cǖ&~ժ+mú巅j >ҖS+Yyw"qiP^]ld"{Weɉ G2x"& %&F̱\Lqx8F9f#qG>FsVu1#$}I15rw,駉1q 9sa Rz(F) U%a@2^20Z+4,ĜDʂ@ #qCZcBd^BmoC h]N)g,ZCN5c83#1F9Idq-Ca \R\ikJFk"3=YJd"Э?t=c;O5_gs߽ɏџx?Q=_ßs wkʶgmzCoEϿq6 2qvYyIii1Ltw-_}Ә^\/%籦\D{*D^ ̇fѫd3Lŕ%A l0 tƚ@|s?x- l@f5Tlf{[[kKMyzM͍[g\ U2Vta:]JRta0Md|SkYl~wkpE_ٛ2YC>6#2)Ϸ%UU+^Gnݫ4wg|+/RZ0„/׽K7uY涒⤷{ y-]TT\2ytUJ à+UL{A_>KxR4W.LW{ȅ=O2EZJLNH(y"j8-3M.]8p%Xtu)e2L# T\l( 0 VAv[p~p/rA .*%&4BV7L𴛗>F޴Jp 2:e5B֖+d2-_flnɴgvCoQVi=đ_>9ȅ[DYRِ1lYj.x[2L/ѫR:pck{=s@ЫVJWyնL{;njmmm_^۶575776lkɴgV sL-r0 uQ͗t]OɃ.!yi%m2 bE`ߌy>{C=cڳL=P*^RRTTNBKg y-?aT sQV !9lw邳sϿl: *7An ,-uMj%'} euJ"ɹwŬk0ShS.>ؕs 2jPaP&6Te7Fg۾CY \b!.ȹ"GjQVr 9Z.=&\x,&.5jlCzM[ZkX"J DeAcCsmm]}}Ckkk.Xn=nwJ*+KKET<ϗҗG&՟_?G<^?t22NuA%=l6!爜3"!IB"22jÿs~DY3w9,?e[7c,zhڱgtA: C sΥ'ض|V{ 1f2Ԟ.7 7A]h{$hsKmD2R;/SaȂC뒱[Xyz/bGDP9nmhzb}KޠF ~Zw7cÈ8RAv7s"?p 0i[g_.ٻ,wozȹU<dž]ԅv.͗N3ZYi-L&4]9l2l}6\օO:EW6eՆM=rcLݬEHx߇깞T<ϫSG>4FAɪ:DVloszU7#Lt|4(DD,e癟V=7rRk7\Th!'}(.)qX=9q2-N58t ?([g(ZU瘙_?T5i3ZpdZjP[oΙۮK_mU]uT-KOr k 6~3S/ɝlX osz H${ذՅG>4/~2LyL#;&Ӟ M` &mX 64hԄsYm7& tuƌF+EQf:*`MY4yݷڼՙ$ B y| %kUםvBDιcRJ0`VE3@dT:L&a=;Y϶vk{tȣ8N Mߢ-z{eU%WgaIwD/Fe+߬̒1UVՇaؠl gjcMVޖ@9VK$ݭjHSMvO~KZbsN-Ы!4(lkkͼdzeZeFIv*.ĝ1'mlگ*:2U?²(,G2Q.6^kVdxAఈ\=ȴm ٱGZ]UUYYYYQ k{ѣgsk›32/o{VGw4]Veu5 a qiqBx!sB 85"۸ ",=8;"ܠE.9;<9wZQ't^2`dI}{۶mMm-a. `92Xmd@Q9:2!~$rF` pi&.]J }Ce 1DFic%MdLƪ>-?iRaSa`Є  Ȫ0iomԺu[-ɨljC&J4\.`1{̠a{dTRYB$͑(== +J\/~ FEw8 # RXZkCw%\p.eDOGw<v DΤn1* \R )q2b8_ qwkڱVkiƭy~7HgRu+ªsE!gsO?@Xt?3Ӗ.8f ?Qۑ3o?IZk]IGh2JDDHgN=}̘Omծ)B &J%d=ħ?$}ݏu:?9=f̟y` 8`hkf>9G{7ggAOz迓[g-Bƞɷ:_|ȴxjcS_8yUsƺ~䴅8{ 2xiKܾ}x_ۑSk6.%BZZ6ID$/٧vŌW-uɜzwUչZ{s@`Q,XbCbÆ Ri*""`G x$4KQAc03z?޵rw{Cș=>M=1/\<=oVu\n91c]\Yu=3ms=31c=ܮkUnGLʼnOc=fDow𴻎#F?s]7c.]n?xғ!~{o9dM"oOnG?Q,$bR,FqLQDZ#"P!Ld$R]^O{^ow۹6N qTL IRX,$IF@kNݯ7`_+b#E YB RԮ]qM:ofsǝy 3}{v2٨>n5:gti{nw9Ɵ3)nSZ83næqwݦiGrSY2osתn=t7}ˇ^;j:GD]?}m Qmڑ{۶~/cٳ{Us߫=/*—o} zoۭ']MG04+?6cK{1eV_O{TU*UUbXH qT@rseuW)+@JGqLҶN?^wvب]%H464s9imS&?;w†4iU M֮_zk֬\fm7&qnzlܭ{7ZJy9wd-⸰?|[gͳ1|5Op{*+Y%}ᄍ϶wOxzQ=1cyȎFQavό~B)gko)ݡu3#uL;n>`ۮDT])v f޸mIݏt˱B;^=x{+Н{s٘fغ|#wމ@oG_frȄ1{o-RQݖWozR.776nhhаqJ٘X(Qi@ǜe&MӴRI+iV9U($Zo&#bXUU]SSSSS[NR1B LYƚ4dN$:1"M;B\ NGLU RŀPŤ"JSDRR,%BXgmZɚ VXb빹 5M63dZ8}ZeÙ#ZVBX!H<k#"t0Ds59PVnr-Km"$P{W[v.]YIP'Bj BW685%mm[ֶm;[DܮuHt֘+9n]?s㕓~YiOL|Lޯ\1j:ncovn;_3G:w=u1{rՕ٥fEO5aC WZpеH+໭}O=u~_ͣu*R.6[n 4u葃Nܪ[ş=6sĸO0}FQ%q$dam `}vN]j.u?;7s{]̴֊0r9m٥a>0uƼDW '{;2g5>No~]3~CotϳaϹv9g>iXų'MivH'$ʮ B`tz%rd ˿|i?>0{3?r;޵󹣷׀W ߳Kmò/sԹo+,8zZ۰tѳN]9:eذ]}S2{;{OزkmÒϟ{ ^+ԫ'n3iv߁95j:qל{|.5.mf`v>۲kş=q)BBIi!BtݝD,8ˎ;x/M/Ǘzv{t9^lo }v̅ՐfQG:u8&0fڮa0+N1_>7{^u[>u䥏!sCNYesyȲsS]~1=k.z}q(v9AݴSuʯ=tDz̅W|5:t'fHٵEwW|_nz߹߅N+j\&}k߳k g "WZOGRRui&kjj{:~'޸@k߰=Nwܺ`$It7u'.[/+͗f>16M4˔;f.777+*8FB\eyq=6,]O0q/ɯcz]˛yd߁Eջ׎:]k|c'yKδ;rqOyo!08f 7$*#] zoห={}m/_w>:rc.<=FvO:bՍ+|]8 N9r ˿|>!!P)lLE!HG& 1.NEVBtQx='vΟSBGG^c)p5I &Jz{OwspGR4JjD˳YVRՔ#!74-#c0Wt{ %qAE1iBSHlL#=z02P@{!y[d>GB0|q?| uD_AT.oё:"D!ڟ?gm[ֶ n&묵&J>d픦iR"(PÓjhy-}Z4HJsYYꬕֶB,Y'qH+RXjU( c`* XA KyAȡU1\*gY~|!` {goxPGDH:B?h\VH\3iYTs9X<ΉǰPJtc@FE Mx^"R"_z[A&$T((7Wr"gCzxժ+[^"^9XN!?ImH99ÕVO9:D(IEZ)@ R"#)kM) ^j,I'~-wauo0- Z'Jk~%8^;~1'"v ~/=tEZc%!1` ZBsKD*_rԪ! t#9BȹjQ뉰 8p)m)_ HI )6%Ӂi{;.yuMMi23BRR% N\.WLfgkLIV/p3x|G$ѴH116˲J%5֊7̘J;]r5" aөŁ#iZZaʏcqrFiRX]]$`7П,Z iqhX #E u֗4@٣W_JV$-+9؃"xr34>9kODH_MAًB?,;" ܻ1j"1gYV)7W*͕r:IbXSP9㬱d63@k$'XZd@@\@҅Q<QEYc2tO0d(]qJl%iKUt`~,[Ѐᶫ(fi*lڶmkڌ"1ˀY.$V><:v.k#-KfDN(3Ɍe| Iǎe`=݆|H:qQ1l]%M-Zcԇ@? y,͟g ed R"iFN+Fа'Jbas@' #@@AA~c&DT:`"̨U*,HȦfq&j.k߾!*D*cp!;`ΐ5)yt)+^Sc3̈́.Y!i"kCHV~G|%H+"PHۥzɁVZ3cARQ O;¶*۶mm[O7D#I)Z+ i-9阀 cv̌uYIdyvZsm _*V #z``4]G:,3& HZ{&GG}SZ10 IrY ]P2E<07􄛏i'B?Pƹ4˜DXHLbYJ !ד3(`c{V |b",eZ)aA)EȎ1&D٤ҒV $al]YZc(ءGJ?zU,ZxqDQH\E.$S e`f.N֞rL(RZPD`rs.|x332$nB;f6-' HEJ4#@d'*ϣٱW|/O(d|;p9u-f ZBxWye,p;d1&3x䔢bT*IVI'ӇP F0VPAs:8֊;ȏ$@4TҴlDcRF.@%) [a"P)ْ8BPDJi&%a EF bD @km&͌$KUG72ưעrs~agAFXgx1Zcu!QƩ򳊔VCߔc8Zs:'c;Y$^fv( I";r0"#V&v!+H-%DE\ɬ1y%Vjljd6۷ؾ}5͸nɚLuBvյTv.[HG8.J!3R)[czdf69@z2D .@gG""푸eaD pB?je&\# 2i-trɲ, +K^Jn?z͏_yhS|z??ᆭmkڶk[R8HC=f-)#;VUW7gֺJ)Pȱ&"Be&"Y,s4`RH+W "4k2眤/Њe B`̔ZL((m9ZUI|%D#1Ys^j :0d{c|oMiIboc 40++U/GO^$ nHkX,gmJ[fŸ8ᩀd& |lYPP ,kll4 $)igs4\xkT ,zKHy$ϓ tB'BFhs'k=cD#ʑT/9g3c&C/x:K ,(}7`@QO".G<dDTJ[+X,$I! |52籈D[e(aiKQ+6?@`di@bWv )D<#T м$~YS`>b]#RCq?ݐI:$I1sH,$EK-&n13v.K45Ld@(8JIkȉ},bsΥiVT0ι,3rҬiC#`.ai)Pe :)u9V0U}D"ZId62`rbgcHJ tPI"Ch%") VbcU IDAT&"Xk}{HǕC(T 6g?rHDIQ *ID:c9+7 sEÀH:4K5kɗR.UfAۓ n(Yci2A0Z>Y(K粴R)J9M˙X62@V*VkWりdiTɒ5FrT;tZP|׫VqLIAuND+&TQEph+M MMYBuuuXP Sɬ4:DCe GFfZB;&Q8}  fy*() Er [y{̰ :EyQhR~Ow(G޿S?)Zy͏_H=/m[ֶcA1M"ҚDžbEzɥT,ˬsD#' … 2kL%Ēٯ+"5/Te,VEQQ Sf~ ,0qDQ |OA홇:NXӜ3Kl *Rʷ J+5 u>Cpb2o'W+e-[>^VcY 4(l``.jӁ `g-"`!)r̀h`&D~I-\D$*8`urKc _e^v1TM"uD- J[go9C2Lgt@Ir;oCSy0"9AvXjbXN9 KVI#$$ u8PkYk" #(Yᵚ~OH1VJ)EZ+fg 3$)DZb+/Y ,5st90˥,FˈX~KJ睤r [;Bei%knj.+i,s9"JbRN0;y[\Yl#`Nґ83bJBZIع V9HJqIsιrs +=.c%B"g]e&3YAh].Q}g[V$ԢA͑fFꓩ^ȁ$N<M9eW*Df`QDQ$eݣ޴l؏0G9Jb RQRp*Q'^ΏQFTI%7wdsJSSd);#cL@B}LOFR~kCXhvecb~xH رu[m͍뭱ƦJl\ huNٰQl(iʨlljq65is rNkj I8v5XI1S1 ]P1YfR)׭m48fZZki`C ! >@E:k\T@1bVHL⠕!*T2qhlq*|LX) !{2'b/o"EH϶ζmk۔]@D`&QfiZ}[kU(Hc%if6K+)"*"FlN39(3813ƒg2 P)ґ1EZHGJkDtN/;ɜBPBSދ D"ixECQ).WzCV* @#Ҵer'Q(| !dYP$abYi"6xΫwmBt8|H>GtWK!Az+Lzѯ%vA(ny3:dp :T!R^гu53"UY}9q1~q*p)ʎ@ɪ(ͬ?B <>43t5I]wA+R: Kզ!Tof[6K֊s,gRWܜfYjm=hJ PV&?]郻T;5ԯYV\-YR"Wr@H\-'W4w- Wv̦iVn.7lhLg%i\J(`fL~he$CpJ.Z1ے̭[{)W 끗?xӠ.[o9I5vaIQ3psssSSSsiբaG?E 'ȸEσ Vd,FlwY/uŭd!*-fT]8 %f 4JZ.7e4NbDZ4)6zH(0Lbi~rPv>W@ ^LN \g"VRg[kJ*4;qO$$fqRT[ mYk3gLV.YX(KbTU]USSܜ67ץ,ʚU*ҩ[u.R&ő1&3b )JH5յT W_elnlbZ—|  #K. FGk\@^맧;N TyJ)C6iι<}L8w IzGG_߶m? 4 g-)RJqZkvHR%)f5i%-˕r9ˌDBBkL*bqIQ(U%9@Tu'νOOWkUי_+E$ ٨"AyցN-;2:6,%[,R:"HbfiZU#4r2#B%g^VZs͵e,;pkTG 3bςr/=]sP_br9BP/]ZV1kPlɡ<)o@4rCtѤ:?^f8fw? 6lXo1& 0HkMJEHi[3R$0RU)cDJӴ)TY3c(+\| (ddYe)kK%LPbT*H3炭7:K9#`L&"kٱ I7eiŘEB}T ֭ݱg4%ZnA&ˬJJk_ >:r:ǖٛo+tm_Ƙ#ad3gSWT1 4)QF)zK]j嚆rSARuM];w۸s獕*d)gb RR,q W5X~&k]mUT,rSSF$Re4kG #D | mq(3EEBkqw'1@s_fVPD9P;Iߋi_)~J8xTжmBi#DRScsú Y(O,Ȭ]J)kN^:c޸ڿ}:oֈIsh%( QMRE Lp|M/h `fE4"`P(zoMKǵ{7+V D+=KazR|<"' czv]tы8kK#|c2cѾzv-[dѳOeCev,zn^x{|gӣv/3el^~=Ԯ[ٓ=@V{6bmٵݺ% }yҴC/.z7?{<{rЁnݒE/̽~ƼweWI#uH@y;CҒMIV s>\ d??~|.?P #}Nz=Ԯ[p=NJ^!xe0quvkFOymҺkk|ެkjϛ0޸o>7)){'oq|:﶑\ Y89fnݷ?uI圫dg5(c'?s;s̨Oت[|&] sƍ<[_=nC |Zw `s ,wAֹV Lf.vu[U;'?睞Ҋ17*,1W*i~e߳K%_7:0ї"bW_~[6,˯ΧwΙ'y}Mò2o$p}/8lXիO̺ |5 K˹Ӧy\Xk{yev̽M{m@bQW׽v/3{_2=ݪk~ԝc<G]s[umv?yH'# *r|%x[inR*fG߻^l=0G ;B,M(VW"N|Ȁzv]xSwnHG(J656,̶o׳K_fv;KO?G}mò/kތ~w9sNY]M/_~d}`]p mֹa;'~hsU7,9g< $IާtlX+f{2ܥWy3g?"{}7{Y@$0 %mLk1-aquFļ&ճz,{e&o90P2{9f9v¦3[&#,u o q2gւDQT]]'>Vw$[l LRh߹аZu\,JEIUbHqR1;BL,Jf+l]CSsSJ@Uեb\@k֯K崩UREҝj ıд^a)μs02OtJՠ FXS1PIhzQ'MfbED",;kZ:=g߅y?ϏԏjW))&=+oßm[g[lX5W^DeֱxKLR($J4M3c:=t~tr#&|7{'"Rt{+}aB+.bY1*j2,n< vɰyfOm{櫾S,o _5ķ>[^q_t}Ӡ-]t›.o/.4Nx:m;jA\Af]s'ٲN[?{F|w75s_}o/\icg>쫟NY[o1^V:rʛK;;AG\t_fѷ5^9J8(? ^4Yy*PQZ"WzލZ,qZ-VB8RRvϻrڂ+:m{-[r~#C 9OXez>ャ'KsF-g۫63 z9_G'.sosoyI}^xY9ﱉk79W|a/M7Wl| _c?ݧ3eq_;rϐC߮^ƽI\㒳z%|ÜG&~7u3Kz 9yiv]~}79Ϣm7c._΁_3pRkȚ:6i/Nq W6s' gQz+ߒ'Ji`RSܚuoSY6̼m_`YqDkLhC&xޖ㆞{3jKvҬWvo:a6/ v|̀Mos\~=.4/NN{ ;/VWm7_C'A~I͟Sf;۾7z<|f{\=QsKx=.=o?YR݁S3ƽyq!g志qo,[`.eLjR D5ϵ դFZv[uwkQ9O6:$Rt`SEvf./ trQҺL=g^4d&KM9cR't^K8Ouyn}&xnѷMxЕ||.a~N[x6}L6Omc3nbq;>\e#OQdq{\=u]>n}\a=/t࿝r+:u76\١^Lz|e=.%bE-2 9ᖷ0[í;R|CY:FT:RQy93\J,YbuoZd;|Zk KG+0";Gw=Xnjl^z]沵JBTJJURUiT*1.IRXn44m",0rӚUsbI1*FJ]BPƂˠ\6YfJXq!&IӦ,-m:v;tܸ9[*H|sVCZ 84|^$JZ (cVJI]R\rHQkj1{ {^߾}~{D\timkڶ{[9s۾G5rc}ͩ=tEo/ic@XrmB/]KFp;_u5λ_7/`n9J IDATFi1n`M' %Us]1?nAv~"^r=;g~;le (T Bf2Xqys :;bk%vknqf07lx/}ⅿzU}ph:2K8򎟿NGNhQv??_C~Bλ\̔—>wkdnqO].~#NhL7g,»u#wE/[7^'#o?7; ;ᏫO^zw'A- M~Y]18O*w^vow{c޳(\d*:D}T5 ;u#uJ~/޸dCo=qkgm2S_^uW?D /ݧuC*we7mg}n# / ivַX3ϝqV[7>-w?+[.0n[޹{vo8OkRι;M|Ż4co>BcFL~ows˥se|NMyyyRDviK{|PRz+Y>W6yY#czؔH'ϸo0$3)gi}l| :;rk-m_L^vw ~eŻ$/N vq#?3~y't]quYCW 8~3?^eT5 xC< )Wiuy7.=g ~aAǫrHmkׯ=?cO4vy ӖuAKJAww;p%E wXR[q$*WbEN-rgn`ӍǍ}%?Qgǟ~{y-:!bTJB<:yj]CSSsRi&`Ė_]0UrYweʯ/[Og6L;if>jê>}=ƽo{%q/}Z7>]_*V%q#zm'n#v<ˍ&~gk@n+ozi M9Oz+I&(wy 1\32qeMdb 5D!Kx}`mܑ oW^?_WԸ92رcT,EIVJHĴnV~+֦e RUuMMڷߨfoQΥZ bK)7VMrs9RJ,֘1e"4ERZXH+(:b'l],#Ebs|H!*&bvXHD`2#` $1,o?/nڶmk fn4tueMm3遣`˱7 wdձ]:P(ĀxZ4%I,?H7+RqoR_>ED Q`^+|OeGX9 =1z랛+HDZB]]:6 ij(LN?|C۹E /[ɽ{n|/ t/Oc;l]Kuٯs短-]Υ"-Vâ٥{{+]צcc̆Ki}wΥA6P)հR=Qtu҄1ƘTw\pZ4_5?PaVҐ5WT?#Joh}yzk/ѓxCVy;;3 D+-ǟ}})kZE􃏽QuIBEι߾=ء]钿l Elܸʍ_ҿwwAvgWR'O`p2?*uyJ}P,TJe߾{c󈷜ڥ/8듈7֥t qK?Ϭ:imOGXW:~rG̷X_rA Y2yc<ӏD,ž=~Mf?w{/p]]n7-;(YZXZ-o>Ua1JRgo:+W0W5Z7ӕ]+ƨL{lk>s5IľtWu9-.xmȥ|ψl3I{άRoЕ]f1ynR׵R@0g+2:Deb5:ė[5A1xQtpSfy(åla={EfYVhdskɨ\Ie}pщ||9zm#:,Mӓ5Y7Ϋ*JV,͔Rӷ-mz#o涰Fos7}G\rõZp_ {:Q TjhY[`:횫N3nKeɖ9{׌vu;lݔIw;awB/ʙ"⋗(QJ 7^E'}vMnC[; G}K_,<̼|B$E'5 k.ADGD ش_%@KIt'ƢQf*&m蹁&Y:JzJwBEtV݆zs XMfw( kCPJ!BmHR ID~g8d޵=Ϝ,wE"(1:1azaG-ۓ?x);#*Ldj۰a:gYM)sv:}]rY?4U*Sm#gn':*[k$jmmsn^KJzJ+jʞK`#4#4ē]/>~1aa:;@Vmk%-3/1~^GK ,x54% =wev{c=ws]wy'g7l޴iB+OQ2לu܏|;;qə_]]#jQV5wsUdF;GZ{͢a#:F#ƌ3yi*2yvzn*rV*?Oft^N腦soA\"%=ܝ  nڢ4%= /̹us/d TmZ['AR{.( a5^:G. KYtg_7 $ZZTZkDװa4#_꼑@u$&˒,KLɓL޺gmLvS';LILړ̹i~%I%c5bŏ>_㶯wA'y7$WrQ2ca `ڧ} I|Q޹\9dQH0Pec ?7#37Ъ"o精}z2ZtƂyf\CftZ[a /֐# iEOoܸ!?gBf( IcXG%Z6kEX닼oM/eC}`c=[d$ko j]uT;pj 9cV3+"H?ˬ?V`xXt%(̰%NM8E; E )2#(^O|_qM_8B~pVk,a2 =k|۟+JJ ERa^A|GMKI=3<6Q/O^*Ś0woQp)! ?=u6m/Zҋ9\DDVl{pњ^hşZ*يm/3CP&ࠃJ9-Qp۽?qyTȈZ7T_{>$Z geswC9/lڨ!Bb+po>O,VLࢷZkwmz[^>8gDiM'W/x&p=)D?tsO(K:AxM'ҧ.tk_2F.V2YƘ4c̚K9lETi7Kނ|.||A&:-x|%ya1U:V~.>6T:5=Z!Ɲ@bf @3/xQp׃j[5`b@(s$J / 1l^}]¥41x`Y6Z\".x4gq\bvJSۗo:ͰJ\kyK/=k1P2ZyQv 蠋ڍ/oZSpkntv)T:ZpԼtWii,jk 1pFz ؞=۰ ΜbUm9Bmb5)yy T's"Yu89Boݹq;c%c4!8^Pg}|g:늼h4A󬵂Xē.M$ޱsgŅ'bUlI77?7 $IULowzzLuJ^gy\ֱKA@%ٮU[& q5:M)vZoyQ/5_XRؼXނǷ}KLu"hmVhmЌ zF*νTvsvl_dwKmդ::={`1*3{#C@MaROQgёh9ZfιsGC!8D (M)MZ$ʢgQڤ*GoXXB_a?T߼ެ[o!M2c:,ͪͼeIfT[jRT8#КbFQ4+<[)H} iVkyah"9 D DI(TA dL$1[&MA<)RH1@u(l3sk kY$GB|2΋e4* - ̶^g^7>š~+oyolY[֖^RŁI+RH j^TRmtҾk>$4:ILJBE])CZ w:Zhk7R?>w ޱ.(RZ`X'8bOGW?h9 J;wG~_Ǟx?<w4u6:IMNy=_!_?^qI,V++74Nڡ -F:z2Ԋuf?RgX8~p`a>z=5}HqmOX8~,k4w 5NnDfrR}=r}m;YG& Y'__{O&E@H!Qćr7}9Rg 315F+(`}Z+mR,`ϛE7́@^"_?cW//#= pIS¶qĴSkjZ6%'O}WsZmvXssӧK4MRT׎[?ur5D0f{U+k98r3zԤ]8mN ɍuW7>,KhFL;v,__?iTڻ p۽:|ǔk `҉0H H)Z42s~H'0_nh%$60ڼwGȣ~'~?驧|4K[W?cIf,ɪInޕ&.:Cg}s(-܊n ȓ.GOpYg#][?ept '6-s̓zM7_meuSu,rjnϼ|}mdĴw+{O6"49kDekݾ$fĎXs{jfygY_tR*m /Esm1*j I)YC}u@c uu{' itvv>g3y_=_7jɓlӹ·O9}`^_|~OlV>m·_n4lѬO<8jp;>a/7܉ ڶ>~M/oڴa#m?~Ԯ&|a[©-퓎i_rIm[\1;jkUj77<E|`U㙽BγwpP0 l IDATgyfdezxf眵El4y^@faGt9ktGLj4y"{EdҴZU$ɔN[Jmb>/z_|c?߭}W6WkwvVIg:mFv8i)S&OӳU֩(o%fV\AYfFz҄mnvۍ[mI(Vb,k9Y3J2" BZ4M41ƴ6y"4mH~&FZ%*"(M;pV`B!`tؼQozI3vw}O6uvn]V~K}j"vKe"pݢ~l/qEq^:oɣ5vK>;<;.Y=j/Еs6kΊ\Dн;/gho^>oƤ._uC9+}blX/|cČqKyxHx>p}VDcǜzx}ݽVx=&;&y}g4p">؄~$*|v@uk.>-^٥)w N91K|靵LgNhW,l6}F8Dؽf]>{ό=c=wI?XQ{ߞw޵sOYtU ;]~WˎNKo8Y˳,w]w۶&+/ߡ5}R{[m^qQ+}׾rN5_#nBg}wN1ۿk҃$\6wAK3yL{]1gʃZhcw{iܕ^;nI]z-3{/pF$Tj6ls ~f_39ӉAEf+벹~HWjιbO4"y`D@=vq]wcmz4+>t赗g׉jn#;#G;mW9/-W{e!DZ;_<6,O)bClSsmv=<6k;ϻ떼stw;␕+o_}yzO%/lk{i>Cll5EbνpE+%mMcvx%_=Ee8쫗kqZq#8.Oʄ]޷#ϼM˜'A&i[(jk|3/~cqcF>lt&o:__0O*8}ҔIO>yLu-(oXi[[GG-d&5i(RQ(F:i0MJ(A'!Ęx ~B8-B,+jW)J`˄nQf&IRD "gyq[㲡q M}UR7>of~>ϫ>}7sM[ӯ7ʖڲPGܭH:iG럺 (吥u둛W3?x;M ?2}7.X|O $@>o`ƞ@i^jzC:hx|9Y3qֲ3wDB寞NιH ǝ;'[7._н?So]6d}#7~dgwU7H ~g>zt|w^{w9|4 ]i߻m'*jq֎6k`h3 (6!:yEa:Ř$ZY)Q @tu` aVWC~d#j2?}@ .oF#w xDq!bIIf۫i(C;9bİ4)2!;Q -)$"윳-98hK (L5'MD"AB!f $AbD"MQ' cY eU+"N{,KbWJ G //M5aCп#z:S?5|=z5?~ A_Wylytڲ9!ӧIun1NSNVDAE>!3Rob:$ J(h˜! !f̗B ѲH={gecF[ܕELx*R,=;kcpH)KCvF^$e}q%L@DiSF!*C9 P:kDND s<h$ S ~" ]|fM,O8C&[@hyCZKD![ŴUU+EQ4\ \_A ]@eQڀ`FW` m""r9h$ؓ1SؙYIht:Di_p hAkJͦg&<#b um8Pز(!Qi8~(&,gC@c^\B(Ɛx)kE*Rb`uRô{Rj]T. 0>ւK6|Yu9皍-sN hoqwx="q@y>lAl)9 w[ZB(bcL~8ÆX˿sԘ$u,HcA:=@HIaY)F0QI* a02J=jFdIT& 8qH#(6oEEiT" پ>1IbL/ -lH1:$2I!CѷF^"w"Ѭ3 jct4j2R!' e *[Tbm ; A(- #ʍ$F[ BM9gafiᤀ?Ìt\JS0 o)`Phb%:1ޗ58ccJ*F9٥1FiKN4a0%T;fARwe -Xּ)_8 C*L х|yl4"UǸ]@ B\xh@Xi]/(`0=&j(Z'*\X"7h?aHYV3Ξ֚Y9ъgceȉwfy8 2Gб;IФ(B"P 8yXVQZǰ#a2"*E$1f@ q#-HTB!ԀTaJpNBtZ[b qZ*-# "v) drؙ7eDp]9j%R CA $TF`ˢr# [EZ "QoxkgDdFk"B_PD}RNi&F;/0M+ZƠ%W1\ƒ.¬uѱYaE#Ѫ#n% v Cj J*a.1`0!0;ٕ}5 u-2:щ6Ef#R"ff"xF$d0SJim}-u:o.{^OzW\d7oNtM0pJ>sxZI4KJ%T*i%IHQIH?4b H%I+FQZg@$ddR$  EJPM@lD8&}hEHbjGV8E!Rۢ)GJXEas{]zƦ"$Cx!*Þ-rڲYa9/B\1@HB ##p Q+3 lIz%ATkE@"P&@, i^'̩Ȟ,/5UZ[J)&ĭgƨ&1e*g^\aC߳mLZڄriz֌{/J[(͒$1J)q. )D>TE2o11z!Էű,؊ ŲRrd'z{ou>hWQi8[x_2űC-JO& —- #hudT@F)IqFC8ld/Y1s>@G`eq*0̤,g2pY=E!, |f,JR$F] f_o]e-pQ󃙽?4@IĄ0Fpd#&)!mABF8䄯!s pz/wQU,VKe/QDpښdG/[.D% cv=$AJbG_,^kcSV4#Rb.޻P GoB490t H7}p6/NSh1RcoJ Z>gfcya2iŔKaJF #Fƍz#o6k:{vD,Kq9HP#S;뜳[MubˌD5 .FEܗRʄײ/ynpyؼ#,Yϱw(" Qie΋\nE4O`\h"RM<{pJ'HL ЦuVZ׻jCFò`Zs؈]=ÇVjɴJ(X*"`ک&!B )*AQYmh2[BTD;BTk&*jDAa,e1.YOY@! (D@RR=xQ? ev E"d(VH"Rh$_@п !7|M7G`לܾ B-kڲ^oa2Y";]"uyk O8i@L1>rE:H }pP0 V@|Qg,̂{Q % jcEa$Pǧ}@U"X8T~*NgOY* KG8~PD}l D6/F(JVYf IbD)%EI=A&"32o-YT62fHE]èhhM&&F*f|hE7](XABn{fiji0XDZ%3v;9o޻Pd", yQA+eN0H,/OJh-s=!!D<c"5@P=Rh B' [`ڲ()PY\cYRbtαf eoqR'ʃ JgVPS@n1:M …CRE& ̈pZ͋htM3fhJD@.$3qk쪴. [{ITk,y3z)E*4ȜLHr12 ) ` tkmՎaÕR%gE@8zoĴ4AcXoHԥ 'F>8k+sֲ0"$Ƅ`->IbZ̤\_h4Fs1;ֆIӬ-IR y $DKZwB#VD:QDغ%c!p"f,@΃mIiHIEͼ^o xkD&xz$EgStԆc IDAT~酕J4"3[kf1WJ)2I$I6o!B]h4KP3gyׯ~y͈Jĭ4i螱m$Jģ8\(`d'W4$MIiA4F^X؋wJrvc0ėh$&f&UI:A q05cvEk.vJDu*ocHPBMQx@@X1glq*X(H³(cZK(MNA_wCQ3t ewx*fo]׿{U閵emYM2H(bׄTH@x`a,%dFS7%b1aU? qBslṮMYYJiЈH(0d 9=pdl%7Xe`AQ K'gQ>G^ f3(JJ# )1VBʦ> 7B1x%$;Xh3rHCֶXRؚ|&q"t·mA _oͼhFOPDE'2izDub5ҚB=6_dkba"JU+\-1*D/Q!4W@5lޖy)g-&CaL\8b jMc0b#_xcTJiimW2Ict]uw76@ڜhCD!F&&VsIf148x81.] !_ۇ"&iV(`,A ^<{< ")d R$̹]EMJ΅, L+ 1Zs!Ȟ˻8vkGPLifi! Z3aA EJ!*"iӀ9I0CK{`9zP!xgzZc'ɠIVIjVT$"%(~0U ;ר׋fYW#ʤ&Mp_A҆D9\i*D,Q) Iћx O'"Zr,̡*;ώkSkEC  s`BȭPe˒u-`){ff?{ 4Vg_w:yaYߴ7Q{WhRPQLptr^г &abGco&t#x&If{(){`DŽ$(""AAL!( HJ6{yz8T`0Lz]_5zAOOUuվ~@hhZ)aS[ұhq(iJˆΛ=d ƗVZ oI-SO28[I42hR"%LcRK9Pv{*a5hIa]Yt^2)?wP[5bRiSMBƄ $녅<ЎJLr0k!BI'7edR;B! e$!(1/#j=ςjB=$Zs)uk'>ZABXP "1Dkc(J)$g"AH7(cwDcjRZ0PkZ(6uЂy@2z؄ZYFBSFs nϊ0Ҧ/[0-ɻO5CvoԷCo/?u*un)5JJ!acw ځOXD[rVeB@mɵ*AmQ[H?ʲ)sb'I)<U(;@pmcS=r^2Ŕ[AhZ餪6j]>CV>͖!bCB\*ii6UK\B1s㰧xuhWV9 U !(9Tk jM{h%TP).Eh* hRHŕh4IIJ4w~N?u+5B1ОT]OZڍSب\0ٌˆkӀ@(%4q)0vlMTFm0B@uՁ Rwk3]1D H}5Lcݿ񁮛VUއ{,ˠ[ɐ4@"D)q]7%5Rj4R׻[R`)#dKk`!+|ߏńɓBt"HXϘЋ $sl1PJšKRO*20!Ib,k3)5$imG2Y+c1Lh4%%1yQR|l5~*7/U#( B<x}({`˃Ht h+k c Q6հVoXA1!LbIb A ? cDuV[QRSOp{o]vv&B )D 9p@g,{RN+5س[KT ?=ۻ\KTKg.>x&hˆely!x!}ZUwc:OTI*fÉ MxZՔ{{ۿ˾EK\Ox꡻[Ք%[jݭrjJ~ݷi-_ QI)8d'ǂ֭ -%PEZ[3n+2D`9|>.lC!4d5I?w mWJJ1Re"m>9vPi'>ܶ|'@m>`vqe9vꮯ4^է0sk_ N0oӿeʝADp6wԺm[i"wz_9e'?|cًec.+x|[ߋ+w̉D"W{okZ[z7c[+F[zE"\H{*1ƨơ`BXm-ֽQB!ZHRZIլ01Ba:J9C"`< (C2\G ;-Zj\*%Qj4PFu]c@ A>2zGP(m0sJaBi}2 N D)8lZ!H,r@thIJq] L}1>mk֐幇H" 4 lLv_ #J5[inna5հVv196Lp&pJ)0cɊd-,m[5i>cd~Ec۳JY򾴸T;c&5ua6uj?C\IHMFڰ0eқ;}H1g&-{㹎MGh-(LH!Z Il BAqe}_RӾSOݶ늿ρd"0i '=1em;N_=?/2cըVFᲬvg][|YyƪQ-{g˲wn~Uשp-{g?ew>TծMJY3؇zϡ9)\;ˊ7-X9|y,zuE/1ȕTw|tOpYfNk6N:}ے8u Oq5}&'/ya3C8\)M:}NIѮBx>'o"2̌}M0 Zmy"ԡ}#FMd˧G܋y{VФV>0& pl}:q$CWJ)0@c09 Wi5~tϏ2}g<ҜEFzzD?^Եŗ1닲N3^)ϻk5ctN3W9/?z̐>>\{q/:γ4cو/2k혖cC<%=~UJAxRJz 0JjkvF)(6aoyiJE6ɇ<]egr22g@H0vx"Ac 8['.I`7+  8AAk'w~˻\t`فFW[2Q}ϞлJ!i|sJ޹-;c`{l6{OU^}O_s1>癞~3ʙ{vcc|m3Cg֌z@sNR_6ŧrG?䌻u֏6,$3Kn{=_g5+ʸpNwy {N~V~~2’kza65A?{$6 0ƽLtcA|+.%'?'|exk2WA+?FBa YRk1z_(>tr2/gni;V]ჱES߆V;oG<@Na]\΂XYS}6h߂X~{wvqŜw'':O翿^+Gc^B&̫/<n5|٥\ٓz;Tee_QeF]7 af~\h3.ufwUFi$~Y>C/pp|i1L=cz^ڷkQ C?첋TR 1[fPb^plYYZJ}^ !C xl'(sR`| ~]cS^7eh؎g]p wkz.seJ~yŬKjd?swĔuw1!.)koYG?){㿩 DH,~x,&.(c*ޚnGFV}HlέXq1ɿ rs& eeZY%C0\NV:э j`@}<L}IK&6־kwj輿#:{mgH)}Iw,5fimZrӝ+U,"u+:ߐoޟ1gCgFƗyZ_~3=9;JiImz2>\eヘ.fB!n~;cC+~AO$R;L6gF)}:cѼYO\X^0p79㞥"™NZ7|Ûlq);OnxгM; 2ihR1"cBliR@c1ƬCXEa[Ay|1СC~ݕP@R @!hIjfhZMTjb(laʨR\@t(s#y0L=1m@RnhCBP6m h"Ptl֋1LC@4ɜ0KjV+y0 '"IUc|B8,G԰VjX]KI ӦQّQC#gdoj=ّa+ګllpUߜȰ8j4w!kw}k1Ơ4Kn*pׄ| ӣG-\*EHZ "aj$N*~^fRs,|1 &CfsG #"9X{>|{ <4{n0 ;;2J?p.߯n|Qo؏BF5 D 1UY}zCa#)&ɗ"Y^yxk`prS$eɎs:+/.S1 I"JXcc{ϼݷ+!.<7qF^$q=qؾ)%z_|G{fI6R*bu5UUU5DBJqU+lemUWX1gWOBIyg޷W ,0ϵZ\N})k&pI й (C(~:@S!*!4@B,c>WZM|aRA Qfꩉ_Ws 9 LEu)byKHɧ4ci1 `8uL@, Щ@jeƭ 1)ń5 0<9 3fع_5J1T& xihX>%sj)e.}Ʌx"cLzVʪA;hyr555DBJl!Jb L!h L ף7^ܽ=n=:qPt^$e܊)ii.C4b,yы.¢/<5C7j(j322rS=/qKwDsҹ @ !?Ȣ$BPh$@kmF}J B4[JIɳG/y*%!'ahVNq M9lʥ6F?:i) N!C(ՓʹT"I%BCYšSI!ń:q qܗ<4۴%ۍ C(B$ qM `|h;16a}bOODC`%801bkvѰkX a5(\ec* % C@3S$֯ZuPҧ kE!C>&ziY|{vU?ǼL:Ǥ1Ƃ҃Wo|4:d4uu+>E+Y2av!ZC`)x b5ӼD6⧗^;3a30D2{nf?:#f˸nh\KХ\!p,! rSk^.FN&d4/BqA 8ّH-4/c):?=X KoBɄ9lKbx)WYFrCSky6&s<co9;ax}۱`1< F ar{F4)1dx'߼d29N A;0 N7FiP{JEOc (:=`[k΍ Yu.'>dz-/Zp̥HU$!M4/*(}Fʉ=l ̉˸j.=QZ[.tK̀02{䷄(>Q"-(E Y6j#r5?'%\5AACZt)WPt"  !DN^-"YĘkHSK aӢMRBnA!V!(e9ږ)NIƜDBAy@'M a))))))Ԛ}m8R8(m!V , ˕TkQ(#߽ܓwW2˅+Yu-@TaoB.;HݦZJ˸n9j9bj^RW]W.[WWgER, z ֐kQVW+:KNZ8 5/QP ݲqS עZ)tӈ/W=Bi%%OB" c1LB# `n_n_ -M&67+4c}jg4ƈ!d,NAwHwd]!11Z)}T+ Qz\<J( uu)c`FMZ4KM cLs p)B1ÌD"qPR!]ˊ@ c2VQDkeВ%FCC(EA "aj ,F 25A h,9y `>` G԰VjX]˶^9)kRyykDNU?.&uX],M3@m\Coق!mP)`Δƙ2S:6R_>o߇~:Ï' B;+K"@F76 n_ 'tȼ-e1y">m#VFkfXl͊v `Za·*tXhZaF]!2lX+vxl DpgE|hƈ Ps2/~$^&BhweF%2bHlfWE(%Qqr.},^c<1ƶ !ȼxDl+P09P6N*!d /eJj%o5SyJIk3T{s) JWOojڛ1\pΥRr.~\u͹sG;zǏ=~Ç>|.FY./mZ"cx,p[ !R>]*emGH $ǡ jnX|;FhgEv&zhlRjOE|@)Tٸx6FİK/5%NE;+[H!;{*C:d$}#x0D[ZR#7qABB;(Fі JvS6\p'Dg_?}~LoZZ LTVRH)MO>7{aI<.@ ]>2^ݕ!/ێ Y}}$^fE|htɥBK~dl;#im?ͰXJَcfBHaה;CۤhJbIηŇIq-z&A ?$/q J+cL[ " 8s5DB+)8<(ɍ6AjVD0 DRJ5Neg夥5vG}J$ .pDx,l@-- k|swO}{&1&))^#G[HT6@Ю1#dImPl1foebp ;64j7,^]U @))%N%ihj*"!QIcX<\\HJ, IDATԋF FRk D8L%blP&\׋F2"iAb0Eq 9iT Ummٺj.|'tM˪b%UeuŰf60=; Z+VUU*e\7H$j"Ju\@j_bDc^+C͹BJMɹ\HJ kJmԤ=O.VZ % >O$V-nլMkӴmfm4Mۦ.X-HoY߾]il^zO}OM]6aLgNm2Rmݓ!Lv+Xe/>oU]9{)X%0yn`o6E^f9ͮdCv3Fwjav6g.9FߵbA`\r5{ IM{7QRe8{ݻ&^{]<%iqխK[XtVjTR((--Q5ZXP]6_aYETDp|碧:GX 89?`D)vc8a 7iiղY6-ڵkz7 ­Wq3u9hf]3{ {i%f{ނunujjZk\ڀ@ _VMoͮm Cv{%;4q0k~YY+ ޛ0]}.6Gkᦢ}ޙݽϿu<}Y+ ޝq;rY[3Vwv.ߜΕthBmʂKl׵hjy{L~E)n`F]0~"aÜh4Fa̽g7;H)?C"Q/-=݋F h"˜8dQM $YoxnzϏJvΝn];v7wuKWE,zUtɃN]x;;m|VeϚ?fQF2Z9]RL_ڳxYFU tG]t5f`7>kw#%=-[BV{.~޼`]ީ[Qۦ.XM/u~{I=}_Z q.M;yiEK /ewOJykڞ~u4;﷯- H HJjZZz̜으F%Ő%ypAE˷\eBC)(h |qҒP8q(aԆ x tG.{uz]zuԣ<v{ӮmE1nvM3Ѣ#QQUˊ\Ư92R=q=烥;㚖Ms?M=c&Pì6Vܽwʖocɬdmrw홻1!;gk7S2eo̞~}L]76'aY+.dw_9z͝}m\Hͼ+ޅ3 iK is2h!uX$%8=5==D"q1u0a3qGZ'D">uYZzJFfRR]%Zn6a\%h%$ZIQ(P( 044YOG?:vUcιbAzW"(]Dz/RB/N\ЅP,(/A"I("IN9{9c^=gcڂo.zw-ZQ5HUOW_{{Ѣw}ODjm-[ٳr銥+{郫׈6{|ͲY03Q7mh냺j\`SDؔEhtZΊիB(Z։’-Tz*,nW!XkGNKqśԨp`g 5 ivorf#n_uqCo|g7`X̚|w ~O<dUQDc~38g ^7+cBD2f/~* ^xF:T>d'_N[vuV/}?z߭]1LQx1ѷ0Ywqѱzɂoo{g3eY2mcɗMz%oXB]N2ƌ^<ٗOIk!Q]tGtt/YЭSiy? ,|_3m\rAGtt/}{_>E;ҋ;pԈ% {˔sycƍ;Gvv/^wѽdwn g hξʧ%C]Nr!"YbDI"B1qҴ +<[ve'4: 3~Jk՟?x+yʐqp丱G8jDG҅?su-EqzpWI2D95{9eC!RaC/:FXx7OrSݑ_9F\x͸q%xO:L?wgqHdq  1gMxRQ_g|SD݅?7v=˯oX&qdf+>y^COzޙvî5_ѽ೚YDz:Ȗ|/5^dt6~-?q=iwy#_|Gvv/Y-W"9nW.9#;,]{f .hϝq{o0{>ʻRG]vѽxwo4*\r̾|O)WcǏ;1u^47w1.yVР( di m Ww \7mײPPv2[0 KrVS?h¡U<[տWiA?GF2-Dd^#u5AXvk i#l\|$kΘiPE J(1`9jn$T3q;K@JtSH)m`d%mi#"NBDZ mAG)&ΰGhtL\UdB!DDC*Ϧ#c1 aWOQXiŀ}j yniֽeQ6Dz>TPT%Zk3pB2'Dku! zu(ECd|*+YeYek[2a=NZJRK $ T$TA})NۨmmlE >(D&rBՕU*c efKMzΥޏ"IDqWVnAc, 1-UB융NZc UJ^I ѳHF=Ո 1Z1$'" rmI)]v59}PEeAG81@1jp.CPCwz{b1K=՝kctBD,\0kw 5J&Rcvjtt!=b"Ʃ\04(LjU5tdűZ2k>@ *;[?#EE"a$#IҏEuhȊH,{\, ֥pF2~ < @@BιzIdf_OooOT:."1J`d9SZA#U %kM֙QӞ RfM5LOY! Ӊ ,˰{M__BD(!+jj_,Pt1$$y'M]W_jUYT*4LKMT#ZeZib!BUd>eaOD,€9g^QZyڒ2(V!="",%ˬ&F2]Y<DR>ɜNBeS'HA_c/Xf"3z=/=$W 1F DD&Ę:'sʇD"kLUjojZuhg6`gFT[Q&uM7Vc$Dlp9pZ@_oSH Jn`3kooj>3Yf1qbY6"{:}Џ[c$2y21x=JC`#s,YmU>D Zc,'{FjS: uHT|F=#@LGZg!EQPZoR3D"cU@C"͊h !YcP$ :w"^A@jyȤ9Bb"b Ygc!4"5"pQDCl 6jy=Ϝ1+@В:k6,{zzz$8j.c%2B\(1pj]Ȥ㉀:SЛ)eDDI]H%IgFZ\& 1Ʋ(bd% %p5Q9g YEuړZ jBs D҂(M*HE39Q(>gl~c>V*ERgg@@ƒգ%4CQoV3d(SڰVN=5b tv ,QǝԦhHY5}}"T T6:Ơ6˲Zg3'@`|RគkL{k+W.YOoiժE8h@5Boͷt.7վ\dh >lذ;-fUo֨ـAyՊEFm 8z@s@[@ks#/g+ȭ3wQTa崀,Yxc@J%ǠGP*U5\1bhAZ: 3EaA Y_տ׿bE25$ !F_A>5Mm"BIŪ !+PYu_}c\9gb|-V95v](DoY" M־Z)?xB"-p h YcOWu"F!UzT% (0s{VbA59e:HQ Js.+1H pjf !c,nIJDKIH44M^t^`җ1t&wYgYnEӪᅤ^H:1FcdC__ӇED˲l "}(/ D` Vyy-s*/f`}Ӟ޾޾(EiWi)wX$*?u8 zh1@:bFjn 92Dk*!9D@Cz5F"CXYxICCFQbzXuD&1!y,wYVquCZ pkx+t ϒZ|2FHiyޖo6[ULJ#Qߔcfo-e.3Օ KO,ֳ\pADƠ!1]LҾ#GUS , _<Ɛs\FI+\uB}!J({z{{ҧ "1`,UDky^ϲIXgjhHo'zB#ƛ~H+WӢ㛽kz#5YX媕o}ÎAy^hoo[m4jС#,fM,C g5@^38ިebsjy# kucs$kB/xϾi)f- =GfB0lSQΑ1jh TtqŞ!YQM MHZm_eam¯b;mޢlBUAHY*i zB D*sT_Jd1hIzA"AW Ps22i,}PBc"-dE@CV!k!Hk໪D4%XU iRfNu܊D!RZ>D/HCIXuEeP:ej9"QQyur.=c^"_SĨfKZrTD%_i~Cg:RYcAe,S`3ճ,3d !"ǀHhCpeyIPAAe9!W;,T-`R#fYPI-v$FCЎhC J)~^t-]ΪUW,gɒ%=Yޗf__liue 63#?^GGG5|Cjyݠ%s-:4qTo7ۭs 9Edfcm[{[ǐY-9k M[81pZFXIAI FŭC^kXkbb&%$FŮ\Ң ֝V 3KTI(?FxW׿Ϸ_Uk0H(C,9;ƨڂVPk k&L(10(VOZHdaZ_b/T 8gTZTAsL:W]Lˆ~4ʦV"ekBQueN MУ] ^HbTX3JN Ғj҆uUᤞZ^3VK /CQafZ-[#%GXYJZC8*0C()!,-[%Y2REޕƕ$)s9g E,QBjqCHLdD Q1rP"AD$C()PCN:Υ/˪y6D΂:Y"W6Zd,cH&Rv8z-H _# skmF aŋфVgDTճ,f^͒ƘR+uՕ8s"تuO#P7:(,@%pTY3T d)U( Ғ?sy- 6"c%z:"Kl{G[gܜ+Tt^E0aNX4F[C5TΰZ,)l&ažEۻUCʲ+2 d}M='Au329}Msj= B+T߼baf20uE>k$Xj-& o5\UBeAŐH`+rׇ:8"iR1,|,cऐ%Z^kzjKØ"K`a2k`b# *C$!zQ Bd.Wd#2AB-˜sN/QJ DK_p*֭C':*qoxҗhjQ%od1cDiyꦫkЮCC-F}ᔹfrm.ˉȘdXjmzf32P{ DcD+t/&Ru5H^ L&SSbKAæV4V ~%KC+Uwb\6Ci6Z/+yO/{{W_vYTD0lVPfit1 1$jw DKYH$c #k.ȘL1ߊi WOHA$RY xb( SP1|( /c x1m@it,8%T៾0Ǩ)U quZ]b*/#6Q9)S]VeD2(|aMH͏H CQC譕>OLF^BeEYzA$!'ZRk: ֵ(h"TFu|Q+j!vk4+%C BJ]kB%DfdD9gkuZT¤$,AVVVAL=T4 #H,d&u5jb* -Ÿ<`qΊH_ٗZ* . *lv/k(/gK5$1܀XeVk$cLjiӑ稏3YA1ɽcÄejr}BdY֨jʘЮ/M*ޛ$N&&Ce.smUF}CҾ;}eR$dUGĊt \N0aL׭q` )Vއf種f`3k K^ ff9c\4h8面/C&$!瘌7Ȝ2I)SUyzz Ka4DzL U"-VT"HFv@mHq&yn<8g#G-ZCl@0XehNEV09svRi $ Uʼ) %Fh3!B(KN}aF2YA3FՃ %I!!bd CF!,w.3pBOoƚdN(>Ģ *FJFXP*R'xG.Eš 1q50(.U8|i#۳GPv6~lXqE[7Z˦ԇ}qfTʜS8 e),se9 jZXm]RՖA>0yJl! Z#c(.YQ)ͬuXEQenR, `@NLn*hC7X1#K{v?o̓ڲwBX0^ǣX5[ Bh}җ"h^¶8&M] 1ZDkWczs9 sr M,<&IH@8 t%,G֐kܴV9.eSQMafɥBTU⪪g1x2BjTzkԭWD=#?yo?{|H4湫j:f. 6!GQ6!p][굺u6I?> 1F6*/2B buncd΂5%}-‰5PD9g4 cl>:gF\F-2R/cY+CDhKPc<Шk ^-Z<7}EO ߫{B^7vh[okkko0` ikkucd"00HI"YKA؁AU'dcE_hPxҫ_%",e9 -"(4"A@ұ_p ZgQICVCFC #0H5$H UE"cX+$ův;+5vO7_se,gy9+½}eY2GUj k!FO"iR~%[Ms5@/2RX=l?rk d`8λ֗V8[cǦY"^̭$llB+%4h'D@! Yli V4DNI"Cd(Pȱ[MkZ4XDhZMpꇮraa")RKZEZlY[RŸ$#@!1;]WYAN'!˜RuI MSż6D*@c1zpQCD s20GcDPD8B9]E$ФR93#9+ L|z*o0FhID!2ia-cSDk]`q.ˈQ4.  EϘ*SԽxZE#E@Rv))rKVJ bB"=dyC-i" @G WPV׬1)Ci#T=f>$p DA* ¸BE:HN!(9另BdQtLD)D#,85U)sq.QqdM Lw?=zKA!,d +C)jL{G{^KA `cQ'-_!eTg>Ὁ¯#!W{1V_*5y Dz,g DQEY,u)ƐFİ65Zջ[e}'眳*/VϯdyQ8WN o!N%ڷ1`Ѩ x͢7F&yd(`Y1F}YAtfoo[cI :pȰ]#: holk FI-3!A1p(z-@ffk20Ȉ}ɾ 5G:2$,Ȃ̾ uhހj I? nOGi@7UCS& 2)'ӧl6TN&\H Ag-)- 9{?_Kt{}4-!@pb_lMCd]$:3TmaLƇH@;9cx䀕om㯾7P*j#cZEV5-)`PRuJ ]f`ȑ^mF@1 XhCjSCx߾w>Ed{<xU+nZ"Agnձzk?3oZB?~йcU~+f# pV-^O_i{wߟ~71}Y0hD$ Eh(m;V :kT;5Y^SqvFI=/{k"i }[Ƈ2("(3? 16C, />@cU>(VȘkR:+ᶇ{aYcͲ7~ wwJgN9Oo8cWr5<"83 wv/yGw_y~ƚmpivK_yCS3O9| :{jgr ^O)<}^Ofw >/^sJLTYP^M4Eubbs0F݂7ݛڌ!c9yi- >Id,Kq6\}[s-;(M"Vb4ј_cXhVԕ҈́R."}AXTS.KÑH%ZQ QeDakj.EE,˾2"QwZ[{}@GFƱP pDSխs" B BHHbkё!MF1 "YP֍(#roPu7CꙵSu]EEIO\*14tڇXY!i2lBW@I@&?x(n#.o4e_?r~ڿwI{>Ͽ3տe 4#ʐHDQ}}:ĭr$rB3s׎Sn8m O?䉗 '?(|ˈ:[nP" `4DR ѹhn=B% o>^0o9g{u3~޶:r·فp{Mku͝kӝ/qֹooӏ`G}ew,kNS{]</~3XԵNu_;ِMv<{ґLƞtXҵ.nu'=49ϐc-_a[uԂK#G )H3֙,ˌ0k7"ˮ;oGxVtOfNs|fync];NQr//l)7z{M{z~ O=j+&h/~g jGpܗxEC6i¬kN|iO-imt{f;#>Yן>fy׎M9fiWW WҒ|ŜyeWOxG?= X:bןy'K6um^.ˤх8wҮv|]g.SNxwW=xO:vé7>Ņt=>vKJę2P}R#{UDlYdk&1zB(8*Қ%F$v&jZ^\ݮ+oY)>QLns'lU\E9X6Pq AlDB@ ƀCހ<'%{Z_9 IDAT64FIJ` >{%a˲7A 0 АTW 2e`*Z*o9".Ylr `wbg?3`oņq[/cߑ]{oQGkM?75X]"_=oL>iavyWby%natG?Y :o{GCȕ䵚.1cFW<9 RoG=sn)?<.!{uȦR K !6xmPE19C{n}Q%$%iYu?B˔⑙>Wz{\}zccu9/w疫-uol+{]^/"sll:{Wםw۸yK$2 ^wy WlG>z͢vꙏ~[-][_KvS~s+'ŴGf.qɳC.{⼥!\^ן燝 ϯ`Ǧ>z͢vm"SM>̶iLe? N{ܶ:~x7=/lTūJ61fV$i|#рVz{S~ ?5٥"b+~|[_cz:xb{Oy윶9DC.߿,1_U3~lׅ;*Mɏ\xnc.w Q]x?'~^S^Zel]6v[,[Loo`ω[12-?շu&r&Y&.(OZg2{е3_yZߴ~!4>ļu'wY6Iǟc%hm}Mn}᷿v[o2ˑ}1qq~=}& Ȅg,acz8`5mw:Ƙ+qAι{=}~9nN}l/㳳Nܡc?5~\vscC~WA`5a'?sqj9{Lzn rY7O7w4a>~G~Kx#w9r}ӋLZ羳b>ujImiS{X-~czwCDK?yzOVRs"s^xzޞU]Y,lͲ,k d?ۿ;x׽\iC>r͗,?ػ>ʟȮsl'L|XDC&WE׾ٗ,sܡc?5*eoNY~7C{_E1p}c/ _H1M=u?{k''<\Cѯ.aNs]1wTH?tL_7𼮩߸[ɛ7pօKG!ϗhmr7Ǿ7:gz^˝s1yGYcg]Z.L1>iZVh!r1LN x5 ˆUKIh,Ygu5g@Fat?K>1{nO( lYN&c"DdqZE퍡4(#" 1(zcd6o;: !GNQeA&1URG}E Ee__go+HR29K[)c%ai{`.zC#DfG$p z<:p?؁6_[Rٿ*zbMs}coׇoӧ囿]?4}@ƒ7Rs\F|+ o>#DKۈ9U?˕ʑlx?AmEV9dW9IW?y/oJJ_kLJ}&6?;ؕ)eW6'_\1UIdP1JĸO|Ww\WA$߽jfDm%˼0an;[e{O{}>߽3W{nCOޘtM.?m߸=>􅷽t!B1}&5O}UQbכٕ󦴎}$Dc+S7SZ?ܟwݧz[o8hJG[FqLՇo ވp!SZG=__LiΑw5F~ $ hĭI3}uISBBgn؛<'ǪP&{v*3%R P1cU㮧S )9>sYeY3opbV?l& `KJ9bϑ%p }BBdB%R$Svc`IR@B$ )AJ.!)vbb̻G*<$$ɂ~̮\ʲ(c))'TR"9vyg]IҞ J5r7b@TfOUSRs:(R"րZo @(fI4^.>DX/ư G#emYߗc->i2/>rrm.^i_qF7r}`f485犨 ]Xe~.#iw3q/.UtOe-XZ}ƯaK/>la|]Qʨ,zd(nc舼y7,odymV\/}M64s93vawnmتv3zQZC,^܇v_g}!xu0:E%1yf>5狰yx\zr⋔Mc+Jp ΦO%!G3̓lZLa0A|}fNMP / bsM xFXvl fbӒ5yN)gscƎffÍ,;&=e@/~]r.ȹM7+7l(]Y{*C FiUr2A{ǞC?= +q׹3vsgv.;nˎv)=" ]xl?sa࢛ˏژQd\W狾<&$eӒԌ1œ^,*xH0 EL)|i1 /P6-8S" H,~OT8ѳ"I<+b ӔM%©, 6mʣM S3^3eH( MdCdLzfմJ7ϲ,˜77𙟽Cqĥ!W!*N>Y`ϼ %)Evf,_sOIwyu;~6uA@Oc~@䣗;//wq{~noN(>ygڝS6RiS!~âFã!?84i׾+N+pvv)S3;q⢯.?yp`LI~jn*C NJ֓l'{z<{KO#T@~JaEL:eg)E51`fKZ QE&`r5e= ] (Q$JEcf̺`q`Avouzo:syw{y{9}9߽`5eO/<3#?YUS/{K/=/,}%qƜOMGCC_}`F<[xYUdzf__3{i޻AOkj.=51Oٴ`FOuR o\bQ =N`֦XxB"d]K~jɞI>uIʵ'+$OBD.<r~`__0;gPeEB))DTf@ HLرV̘qhYÑSSƘq&0yɓ&N4vTo͠HȵZaqQ:k"K*ѝvؚOz:kT2o[[ALOq'N&B׷ K<dQe\S?(6.dE9̜r ;Z[dJObQ 5^#jb\SgrwNk\cL=>,bϮ9C5R9xq*(d}3\30fRfOL'3TU4)_1)6ig9R6ФUvb,$Ooԕ1,y0Y`ՃnJU c2ӍH9\21YYnz|ʽ+72fLͳen~vO匿nQ eX[J3uzZº Yqv%'^g9fHXgOtˎY9î5e*wO%;m\_>L[IXG/5A?LD~uR)_FVzb/ -z: *["{Ym̷pXŊZ] =DsT09BwaEV&%3Ah^M 4I 8@&9rj7#"@Tcv8rNn E.evbf@jY6J9aHK,-g*eP[ڇۊ V|!% eLcjO"H*41!?̶!Yf3HRU>WR 1˘Աӽý_֟x?yz;?nş NÉ^o|yڲJ!/kHHI4oYh6Lzk<&#)1wYY>f IRt:?^"Te ue[VFJ'cUBfsp?GJA,1bSPTθl4YM4B19so=݇+Dy>>|᧞ֵ;VRv;Eg|MCBnGG۪(^>jljJ1YǷq޹F7i^wG\sI^jݽ6uY Vӄb35_cmm]3\ṭko{׷3^T(ʢQwTmU4I5i 1e4>ZJ&*/= TKsw]i1}, 4c8?ѱտ>}׿{7?==DکYi7rB{ MC?v>m,Vmj U:]??&B\} p\{gAf1qkP;ֵaT,2f1koSwis.,'t|{ k}c͡w;ۮ/!C;;u=qu+JaA: !P]<}EC͛*L4b(CYnQtc `")X;b~_W_W/~g~/~[](R0u:Wk^AO?N}4PTP{׷tTtO׮`vĜ v;EkQknSw=^(wxo+m?!E(axSmg&/o /mewmϛ$pQtc }Q/wo׏dٞn`+Aၗ;Mv;|l{D@3Q1*AxbF|'Kػ^|x,˛FޜG/?|s)Y3 {4mH)zqŽǴ׮`GĬͼ'o=rݶ7n{tls0I}~+Ξyh,;ݗ@tD ԁ1SM`.9@dNr١~D@d>Ȍ޻,˚V_1fg7APjQc%F eAR}5%#s,cṕF߸1M? Sռ**2h6ƎkM?!ٟX} &f sh􏥼.p]BZyO40qB c&N3aI&L4n'yrؑ6 =GuH"[9U˷UKJQSE@RF2Cb@`QV1)"*22HLSFs 4&be-_{oKemY+odLxe?^x7pw:Gy>̈́CO=O!!}/w8Mm:B@#]KWͻꢽNw{V- ǞzCDuS ,˲v;͛7ݵx.Y_r.cr<` !xqcƍhdI^;wKS;rn<4gkvyV;zNOx_<&W]{誅g͝pه}~wl9ДB\q_s;wJ yk>j!;{u5f=^tI>=s|A$} 5MM[\-UlŧϻY9 ;𧻓u4[s~YwCJ\/{ۜ,[h_-߹2{YWg~{SQtpϾ߁^r5_k:u^]uwνo영_w;ll췝?&e{K0c &4_87.޻-sֹoM/,W|GEQUV ZH/1cdFf$gIQk'ΐ3r?{$F^ƭ5_˽MbĨ)Ѫ+Khey#oV_lޑ1V%p^+(P1ń ISY"B)E:eFQfsn phʘZc ͛Qy櫃ȳf NhSM8kvW"1DfrgWɨUbJD<U-pԤ*QFdGBpQYDdqݲ-kڲhG9ۏX#?0wnn}y\z?/.|a%v6-ً]`G,8̜60=[ق"S= lV;}Ýv !Esf+y1o77ygfLGuP9嗏3O?^3&3'%Y.[Z͚>v }~Yv? }?,{icV?v /'6zǗ|3ٴ[|m1dN=CgOG_X3N;C\[""Pxzz_1[>c9mGv<%_: y+,Ď~W.8U1qV٪܏*)q'vCW5󎽏/̝5"Y ?v3k1ΏomqMqo^uUOlt"ňF#˼]9!]tчΜ6fhp=_Κ}Fʲ {~dc?8{M/<|%_\|?_|٧?2kء5YP,?>4ˎ5Kν1StSV?~ՋξVŧ51<~uKϾGDvӏΝW/90;^jiw] عw9u`h+o<2+,1HVw9fȲ!zSg~ڟ뎻<ЂA# ?wEǘHozsf1Rn{~=xOٗzwxjG/'u֬zN;yܯ?dLȷ|Ο9m̦Տy⳾c3x}QKG~٥wl$o8/|S6~,!c O;;w]G/;Κ>vhcߺV?`)=_sϭ ~Oafgsj,"eC@V#ϝs~g}k{@"m~![p8~G~~Ï:;ܪi۾vA ST@}CzRgwe_YK=<~;sIۮ:7xKN9S6{[._03{?3߽WRE;So)CkM]y/,;3?cp`hpŷ$CN?͚6fhcܼkg9zw%7 .coέ~e/6o:d_<[qWyR޲#Gau.[eVO:PE|~HU% B/g$Y{--6 ;&II2UBI`LC&W!I!ŠDϳ!ĤHБXv e727o83q5r5IEQT $E͛M~61T:Bem lvGf%)U/"q*qje^EoF9&-R5Etڲ-/5cDd$Wϝ΍%e$*1BzYڡl- \A-[bQmULHJ)uHMzW=&YwwBE.D,),{0ұJ tR$ #VD賬 R2 KL)[-! T4"%јD1jUƔP&$V@#|朷P+ $) bJZWS9BTs4Y`"8dvclsUڃ$BYĀ@U& ԪX;JT aϸCA -^yΓ:9M'!U ݲt+HYFHbкLUQA qc1sJixxxMHy1U~֬9IID$Ava&j1)2he7Nb *)+wrI!&1h ٱrQLc;֩U`AU1WHvjY)%Ds5(E( |s>2ĘRd"3yyޜuRJe%U?w }4z-|Wg()hG,PAT%޻sk{)@*ۤ^38s y| QEbQ"9k6;VpYV['Wk4vc9+7WDxdx!`z,vY6أ~l`Xn!713T{Ag TݡXFi"1EU$Ik{kڗb yhZ.0444y#"5F>Y1͕}` 1ĈLΑSUʘ ` dώ8y"FbTU(J"$l—M٨6{3c9>I)zGFDD*#zNaoV7(b}@o\囎-kڲtreJb7%c-*=<"?ID9˘eyӆQٜ*s(b%"b"Lϼg\%:Y({ψ 4 ӈae @:BS:aDBPH DZDQ+h*<{9IdMV}ZiRvc @nA$@םcf$!O@@ɱu9iHmK (W&@ڱȰ%{)UD, MTգb5jeX5JqXWĈ*efio-*7Mc ! tc%VQM lEM7 YmHBRDK(%!DvLDP*;DR@缵% Z"j(3wJdև.RZ/! W99<8p=/m MC@|BY"bH_#j a !*]=V.$β,r&$)AF޲ƘT H4:$"a̵-hU%h庍fqZ@V|r@HUw籑gy7uLbCv\$hH4e4p?"B"H("e]0 >cG= ;r.9vSWl.HY=Bena=VYME e CTRٟeYejTH@MuT&9c3P(1h"F1@2粆91({X5IredPMIDp"R=y$K@dB"5"bm$P ̷'jV02ʚWlĎPpzcL1ˤcI׉ٶzv%30am<+%˳e]tTcL)ք3sI6'AFe^.cDj pvRʢ,AEqXSRUT}FDFy#WzI4}_7-Z@SuFPtb'o1EE*XB'ÖZoڲ-/lBJ  0slyF~)yk~$A,Ȫ1*hq?R{ԖHfDTXh) $A"l |v4J `%f&zX7|Dڍ$IJ # @4QH!&ٸcׄ*<ø F66_UzTk3$ISbf{!c Kmry2v72 "5y__{SP qQ6$P@ 4aQC* IDAT_/$ILEs#˜C5` ޳JѸbJPB( ~9g!5 }3o$'9yq/19;bQ ɭ $FP{P׏ncT`EBM5F9)DU =,w*Gӑ䗊E;IR!`M?ষepFss]  f2(JH[NB(1i ВHcJ!e)1C e(:e4bIYXQB1r@Q%CQ KvV75=L\jm6o Tnb-QM[֖emY[_N ԛ%(cλ 5idȲ,:T5Vm!uH$z;g^ؘ]dUTB5'7MR+I;v&ctN*u* H%S)SU!f6&kSJRFB0(!6B!cPgJu@Yvh$2e)PS?#XX@Úg##Fl!k($4s5s]j!ĢpB̥DzQLELST̐Yj U=ndDoh(BPtATf{ٔE# jRJ"!k{W'A8SDF=Hv4!Tأ:y7[F圳ÔeKm9D l$Nj$XJi*ZRD800e  !(37 HC{}!fw[G'#c!.PD%&e}>Dڼy.P8vL{'f- (XTWu5YUb BDޛU[P>>epNdcTo{Vc$0bE ee6l~Hn{bҞY!dXNbfDr;CfM1s1c8B(DFjg!UZ @ lh(uN21k/;%U!#! )DM 4Kq5f`F$P$FeYJJ;=;X{j!Pov""{U#XۦሏZ=)x=*AQV@vjP5tĮLDmc-^28{H1VR)e+Z̘lfܣ޻Gݾ^u}~k{sr' 1 Bր D@2rm[JD@B(4 A `aV:@))@p.{kg^ǜo'"P0>d]9j:9,MƸfdH|XVYV^[*D(E*L$㌔z1eG*03gz 5a&3-^n3 rNwzQԁS^juY!6D8` vwn]oc dY˙bXՑYz%!Z6BTC3 dD@֖ l{]s8;0nY+,I h"ɭW,c<`^\Ҫgغ C1b-'Z/zС}TH*8șٽǷA|'-SD^0q*ͽ)g5saβ,5<f/ue.[@fjALE cܣ-m]"r 0|u8G! f8漮U5[߶yܽ{x8%Q$-Y9ZocX´"$!Hk˒(Waa2ŰpS:s!fMHlC2sjLl5 r)E8'e]DX^"$-BȂHDvwEPST er!#Nbp>tDAql>hb8b#e!bG88z#Ҧq '#WM:3sz5B :iz$v>@Y_>qsFFf-f4,Jux2'ܑ`Y֢ [S#pO{o42E && 6M7\!/w֫{w׫#6R0Se >du5' ƠPˆ&H GmmbPHI"XwgJ1Ħם}'( #XK hwjF, O" .:So]vݮpχ"Ҳ.  }>Չ doĢNelBA FL7 bjM No/@L@>ȱ!J#}sUT1-MѬ.%d{H{K8ϣHTu9A> 0k8wOOFj օEY{BKNUMMZ" | (\P pfJ=Ռ⺟O!:B(a)T׻CǼ5m[ 5UL}On^ep'Bfj@`jP3P`!p!2-*<'O5e3 `fJe(|}#1!S.&T Xt+Ľ]vݮlpK>3Guo'/~+#^OO|? LSSܻz Wu6p/,$ ׽ڔ@DNf7$D`AL`a"DDӪ ~DOhfZϧyi#LF~wx3QӚT!aR\Mf V+20kӹW͙K 0cf$@3!Db"֤&%w=q53 ekb(b 41?p+q" B-$D >Dr2ƀfQsJ/7[UJ2 K"J963qNb4S" Xa iYec]s23Rܚp9ѡΔm™ y3Fp,-Z[UnB` L7[~?{57pKc&T(ɬf;dbV˲H LDa)Va!ExDDm&.+8k]iaW;c ӬPwL 4##f9="TFIn֖ZKJ'`k!gp103Bd]>6QM J}eVL'exaj$"MdNUgU Z!3 #P^%=_Wn*K%稩5͆Kf--c.d waC#" QlYP\ÔDŎ /ALd wŬV&iߩb=1fwJUkn{:T~]R! ݢQ,po0/̔w|"?340ϸ{C5Hy7$V;3)HOp" `DD pW CBY #kunzZt|}+^I[#>K_x셯zػ~|8~{|YߩfzyEr5'(3YZTua,.\ަK Of/eiVU=7p0$>IGrfwzc &>~z49zj R{%]WnKy.%P̀¼4!Lk0Mo-uhXI @t=5 3n(UZA[r嗔ԬF 40w&c2{XETl`[wwi0q{lTTAYAT|4ve!)|EH1do0b ݶÝIp|ZR=D:xRY,պ¬s’:FI%]p58zHDSiLW8DnYyx*Ӽ+LYZeYlTs$ *Z8{ u= Cu;oF1$da6N-emzj=.e{|JI-}njQePy݉J!m-cTڈ@ZзַQs)gƅeYÌl⎲ `&UL"WLCb8[1k9&,e{FܔDں,%|f{g!rv}h *L-\eai,-UL0'O'zfmF(Q̴ HPL<9u4ASR|.k(T4j3܉.`:s.NBn3&k{Nܙ|yFDq"dFD FLr0Б)1gun]sΟ߶p?Ǿ?O~K/e^#"@>%S?{7~_q_ox_?/zO|no'|?7cW{ 篾wzcmi`#}敯xի^,,@,IcZ:W1eGU_~0Qch2GQ7C*-д&h@jes;6%R4YP7F |M̂3Y97#M2$\LH&G 0Nfmrk) rL):⊈^@{H3#sėr."27x{T^0+"lҖ$[ ar1Hs2^fM[Pɜ{_ \4K)N<&uŞJ[#hɲUfjpfa^Z}f g.&^DEַ16$! dde~rXMLM="],rH[ x ͣ4 Ȭ45C$fx<*i;]{Rɚ+kj ~0΀UԖ;z+q1M=A !eR-.Ux^i*=̃qD]&Fhzd.TZVbZpX}m*#-:岇Xl"ܪEZH׀ӱvvWf:$F#^gK  2bikS*YsZc.UNpyugf+nA>D n'i dɰe4ev)x[ӫ ;b={< VP*pC`j7UaڇnqX;wdZwyxJ@r'tdFfd}d_og`&FSGq b)` tHpfetw"&,dVJ8mF̌tg#d㪦5,٧, *@sEfקH7֕>?}??}7SArM~{/}пOo.}L3$e.T Ȯ-#)0M1>ok]oڈ!)!˲޹sX#p"9+MY `0'tthc޺ ޚ=uKb/s"mY0ף+,mK(RJRSyOJ Oq9n9a>z}4&a}hᒂ0̀4֫GS$1Χ0g捰qF1̔Xa#ÝITys,7j;bi6C2!uE)sRy7o.)Q0[rן IDAT,| fB @Dږf>f"gUD~-ݙ)uU{I[B$Y[KYrw }]Td^瘣BnB5X0_,o5-ubWhӕڲJk̜2cDv-D=Pbr&ly2JsPJtYwӧ5Y`v!R<0=g膸9uŖF c馥хp͂Œ ",S)*~x]U t鴝{v>E(Q_غ.<#>zuuWek='DCQ pzXI@y/3C*!JߛT Ldzw4'%oy)ҍ0okFpafSKo " ݯye@Q"1-t8C:#d]Q&y{|# k[L tRyPݫݩŴOs@-`M zk ,vݮ6_w1D<=K&B @:<}G|w'4=.qV ȩ?_H 6~N0[zڈ|) xXRm],В̆{0{H1tt\[ĊABmIrh pin,-[cᵌe,0Wdx%gg$SR!VE7,3S;kЛJUBd*V,k@P M%h$-]1M11 ݆ާlR)rc$4gػmsԉʽL)_3A;9ADV;9:ժ%,w~iYZNߊmmsH<˲"к[Z[y:H[ &'G"2@P[xx@zsfejeQ p F!MБ%jf 0NSOȶPAZɞ+ {W`[q9%E%Z9vᦂL*}rdT4x^H(ܹs8[[y0V՜׏&wfn$B3BFZY"yrG%'YΑ;?ab*$~R'9o=]gNgߕ9`@I`%I =4MRӬv %-ntTbA CGauM;ꆝK=銯#8CNK5ʼۗ,-R]0`D@K1K2;yUR "u&86x=[kLJP 5IʖH4::V\5PZ$# u9r>e1}Y- ]K&6HXD:TLϫ` S>i L@%|h!"  7b^gv=9*\vݮu }K~{>S^7_s"\O_wxG}_~_Ƿew^Q,_09p:x|N_1¯!pw-~./BD*z )?KOZ @6/4ǪH'xs1sDrMEv9_74<05W,ܥ5=ud;e7KkjC=HE-"xL*`%!YӬcExQܦ+#/0&K/ޮu:0euVNE} ,S 1d4|0Zln5tߖݼ4tcdn6zcӍ̌y0 C_+g53sQ枹-z<#>p'Da)IJE4cf21 3f3*å1>)ceYbΔMrpU`$^z 㕬ޓN",Sp:[4cӁc&^YUܿ޶jfanUӔ1TB{ݛ UXv.V΍.Iyf*{f~>O %1ZŔ`&tra]ꊘmhc; D$]HadB}2kGNR5=%wB|"YJR岻'&-j𪰚6E)SvP?_5_~xO~}4|;a_">zz"`SHH<3)# p<0K>UMoz*̯-hd@@0,XZkfYX>OJ5u]+ib9yp=t# 瑁-L.p(áAGX '\2=< uSWU+ ٿ8L`줙$:]7$q1β4f7 +n :UVP91P:S XJ("W;"&n^SHed n:l, b, )"s4>Luw}Eug80!3qc!)J]s3#cc1zסˁ!$%и$ȄOgQ$&nuYR` 3+D3 b䗖Ҫ9lE"j";gNF ((")tl anҸK {e(""f}2ys*#';7=MU-Z;@ny!Dߖg33\Q;hb5{-k^p/BJ[fz'H3qe}m'=5nKkZtKO.^iJoyϼ^DtVdUxγ)W~D KXvYvXL}Ώ;)Rf﬒W f` ,(a / 4YŔR ΂K|N:Y w7WUUCkKk s D0c` @@l>WBifȃ!"LEh]n9Ȥ$ŃyH& Kn1KU$fi˲Ý;WxX榿7گ?~>xu裏}˻ " oWPt՟4ߴ@m]v[MߴߊUsp<&j>7kǸ:vnܙ`7x%%֥ 3fHBFo/xKD^2x*{5J{CG{|ڋU{ U7-)] f!1(L"UzǬjBZ[p8"P} ^#$\p@$S۶ضMuz<f˲ְ y (iRJu:3Je!sP YyƄ90Xڲ.GWaaa.nN,^ܫG;g OĮ=eZ UxrV)6ɞH |cCfLS[-9b̃1JU 4Č6n}mM\Ir U7kE2$K&y'\w3;Y4dkaaZuiᰮ<]a{["]b" Σ=h i&@b0F=-KK3_1R}mX=G5ˬ o(q3I~ *,P  nLB),U.Mr$)u;z#,24"HYR^Pn[?͌D5Y0Ln{ΒETDp X}۔{|T,Hr4"Tz읝 -c]<\8>J{AEݹs%aݫG}eYtv{~\yC3DJ}i'ezuˆ\FPԮ:@Z`(N MK&Pv-HCv~Ul@bUWy{<㑇{ч;wWFM6k.{vN-z8>|%'JvBnDxXNH>F7 Bq%]Kqa@J#xp>ѝ<Dexz!ܘm玀":, >g)5=""6! (A  #0p2EM=Fe3~{>ofgDd1n kJ8 S7H*\­JeY`F)&F(sPքj}NǸ(3tf{y^σ5f> EPIڲ a-gqpN D"]sYsY 4a*)h&Dc "hIMZ "@@L:&@O"̛T΀ p<ÊHch<8Igrz\f7_I3m1̈́L!*Lg IDATRRdfF _̒6%\"r8ǫ#eO1:3!rX(8L-=n`ZSi_P73r7-WW˲0 !#G?BLʄVԩo Ge5YStX"ǭ6ipۃ01ec3P%&LĢ hb+4 4b@nSjnyɴٺc.U:O 拪5ZQ)u8Y|f吜av"Bq>U dA #$μRU\8Kp#&n""M9ݯ@ܩ:e'{ْ}__1|BP&B7S3B$6W ye> ֤Lca W2OxC4Jjjn ,cy>nu˭ɲ,Ж,4,R=0Ot>(BFbd&P3Uu!혴a[G p{jr"c@w9eGxnZw-GR9.6ۖ ^ָBkG|8g.OqK2r(@L,xu8vBr$JDSy&3Jt KnS'Ib j)EDl4i @摮^LUu;o6&HD`cl1MAO`z/-eQM1?/IIn Ēք+֒%cB1ٳT_k_i4mJoc;oZJ!|"L$9C4aTޯ<Au^]3'RfhXy2Lip9wdZ3+kѨNI$YDfO~'F17q4*{G~{=|C{%"u,9S??uŊF1t#-GY@ )p s EϨ.GB ƀ0K 4w~_>?g]Wծчm]FppT/OhDM8.Mڲ0s h6™ժ|<WWW5I}]f.62nvݮ+brCJLŤ|nx AA@3̡2ƴR": 6"b&3Z#ǭ0#MʙNS Ek)eAD,j1CyY%üǓo&,˺. Mj&޷'](a{͑& ˴X@m;]_gG'1(5ZR,"K8i" 0M Mǘ2D@ntydY|{_Q/bJaӘ_s5!eM&ۮAo=,C{p˪w4ssNuT (("5*1&hBDBDVQ-/(`( ]TwZs1c]o<Ͻ_|SNZ{1De-5MCyAX8WARK[ŔbL1U_TBbç ܒDL9Ѥ<P\FR5YJhXn?"jJbup>\P7W;&\j3CwML#ɵTvރ r6f~Ɯʎ^D5c.am伫Aw[%GI6[-d|]m$D!D;&$P3=1!c3XT{eiYBzXAsF(5_d{G.XUEI9A)7hx6wdYTA9L)U-lEuUEV!`ǮEYE1A WxJYtԜdvAS eM{l&Iva/ m;̜n6oG bP mC~BcU0o~1aw5˟lwG]qpQO>֮_+7n0:֝={lEiR];tΈc1hWP#B "SaUdWy*jRD;v$Tf n`V;>Bt& &WEAEu]N,ZDc4"deJ qv۝6ȱ( zA0BOl`x$p޷ZE4cOg翟:ә5f|mzMHbLã]cOAs$ d9KpWADB;Fmp LC*IGTU y %)E;RRs&ol <(sHH u0죳2QD+[2[_֨1U؎3|8o8c-rP44R"0s/4|I @2AS_B~L  $6w<{6 ;r3W3zOlYdgo8 'CЦE22jj!+Li!עkQ%̎?jo@Qn`f$Nr#,IBL)Z`,-PĺcTPΉ2BBfi"2cBs]*(¨(!!Ԯ9 Ut)l.n&3ljJABiAz<EĢ,#f43qk]!DU0p]N05>>1>1 g-v̅vwn'EI1N!l?'g?Ȗ⟙Ztfͬ5_櫁(&1JlؚafJF*-i[T%U4C] uEDؾ ;N"!;f4%;sF U?N#[`- YSF3\!sk'"d*{=b߿z=;g:R4cYPo{ًwh GAP2՞=LI=)j,}af׺ֲܣUrqҥ$r~\USȫ"һ(hS*H=ET9(BvΕ/[3F >I c6ꪞ2s I6< $(֏Q( _IEQ:SPjP+  b$⺪*3R4_EY-|$CZO$  {EGEgD0 uL o "yI6NJҨI5G)TU"HkuҰvHUI!hlB\[e?M1S$E$@me$"Iq!9 NTl :)`jZ:Ǝ-ՔR]U OJĪscfv.꺮SJF]QXX*:ɭIbJ f#c:AE$UλnTOLRJj;#F$m6C 1B6$K)ĊA W#5| V͙yOfkԜwv] ..Da+\eǐFq\f.I!"JwT 0 O>@A¢UE!Ť)596ڮeG39xP-2<} fі.;6KøPG]moeeḪjyu``/#ΜY0=== A/ňLcfwGF[Hl61&@{]nITUnVQ=Cv@@_:ԦI;tGFsz6\ҹ(ibz_U! 6l","k2y|nѭ'&&Ƨ&&'Ƨ&'iU-팎Po_]? *ԃ`bbcFo5 _$L3kfͬrg/R՘39gh:UMSc`u{sN޴~3϶)Fs%:n.TZfҡm3/F*``xI ¶/=N#7 F0!PұB4@׿ΝnKoaSh&6]N;v{W=]xy 0\ĘR2{֑qɬM+g,1FQwMO?$s>xǭgoZۯ^{慷B<䬏}n={|܋n_ȫYGֳW<^|O&wuqɬM+sgmb4ƈNB6x rw9l/f6a̢&Iwf5 B2*q:$nH8:~י ڴn8EDS [ h6i$e1qWwڿx.oX߽Sy}ȥBLbWoZ5ucҭ_~m9޸^ '&YM~Q4j1 gׯyY_\z9%M!T5;"BjҺEU(^(dd;0/$)̞ȉ`RLu~XTPael/;}!t" B)ARU^U6ϙ2ID!f#`,% tA]MLLNNLz @DQjCiHJ˲tʶum7D 6`$PS˲̅Q1rR]#AQxv̆$b$f3}; KJ@c")B LD,)B]YNC %iB2̖@eb"@UDLq$ps;U]gpW|LXrsݭvI>i$ IFU$ޗLEPDcH@J\:v} )5PߪnTL\SHιҰҹ*p>褔$(Q BO mjyz^W,<}h[ї[sٲw{G-zޟ֥O\x:mw{7pƣ[U _ owՏ[=eg/9-_;n{f.\rMUg޷RES6I:v9 U0,Јړ!EH1Y{ndўtQ_<=rM7_y}rw\fg#LFP`0RJ+|, IDAT'sQrc;w}ޱQL,a2$%1=c+7u('{*71cئkƅr9骹4ch0I<'hvDJ?4:j;f!XƅU$Q@ɗ,vlEYz >grh$=CU5P$b5*[ل(8Fpʲ0I;Xc"*qhUxAUbMR$)Ә,}SB DhUˢۗv:(!:T)eڰ*"g5uct.(A fI㪀J IIڎBJz>Ǫ3^Y@4X;&V`HnݴB`l0"kRb񔘑8҂-+U]`'޵Sj$b<1Q.U@$E @(YN}hȺ1>KuML!t,* i+xi: h(R UVk+ WA}GZ_xGl̮=2[% ׂ%GdDjŦcRU޲Oa5{tGSO>t5EYtFʜk֬U Qb6Y SLr "`UαqvGEQeYZ##c1IJJȭvC]Ռ$H329^"D\z5l\aά5[neR`\+󰏝w{n:keb;?_87m͚Ֆ8W-y'b9ձ_k~. `VìdG:?_ݧVLBwgm^x8(0_vkԵm6lϝ _=^= }Pw5@N]TzQ޹U#2 ?yzv?5v^q{ȩ{5DK?m3>r" |܍Xܧxp[#^]zpч?pY򡗟|_˞~+.8O/zKNgz+ꕻ|1{Dw_b=/;GSX D/.U+v}%G_!Ҝew~؂^~LIXxʝ_}V;: 㝷tE}f|3ys?޷щ|[veB1Wуߴlǜ{U5LBW`\&9 )-dY=r)[o\U/ޡӗGFo|_FWtⱇv g횳򿘜n/v}9swpW oX4k}^6 "5bη=^7cߏ=Wwwn>_=_Cxw{z_e|Aġ!XmMIuStfA9 +V4yئ͚`=:< F2fT!YyDV`Pi ? Q$5PԤ]3eY )'JCcRf,Ze-ʒ](n(B5Aoj+DpeheYz_XӠ''&B3Kf$v )$jSd52RfZvĎ(1B !ĭV-6$)I jL$FX&&*[Vj-a5UcN``P*s;B ~?Ĉαʹ`"ՠՔb]Wu=p%DT;Gİs0ǚ-F AL@ 2`X&]  $IPQۭvQ+rUC4p6 S /$\f߼燪ۧŠ(ISJu˸WU9̀ʌ)I5l]̙7oּy#vI$kER* [=aR49(f-hӆ+Wo3226]t_E=PЏ1:lܸa~@$ ~L&09sΛ3ltCB ']YvGF##U]!a]W*9fhK8f̚Yo.`[o|g~kCu/|ky۾+Ws3[?1紐hc.lfU8dQn$yWWwCuz!N|wѭEyA ;{r 1}\9qbdݯ, Z9 #.WcQ'nی㿽KmOњ#,ÇPB!.y%~g_Dz_}ocWC"Qj*U ۚkbD OnN6cmbF,(9j>dOjLIBJ"C5*:jVv,(b$Lj$ @e36#n"PdN N*B]U͚7'TKjݪӳf͚3oV2e7=Y}D$VA@`0=ݛ z~կ _8'\D$٣N8u[Ee!stFڭd(jP߰;+(j$_f5f .8}_ͽ/?~_q~|C=tnLy]v}WI&|YE )TסjmwD%;_%fti<)Os5İo;װ7JRᝂz#ڏ3?iߛ'}}~l?ٯ7_|NO'X ^>q;(S-*xE$z934UaQCrKt9u%KuQ+:OvNcT,f 7{OӴ%4,a%|٤')TBlK_ޣ?_|{}AJ7vҩo1I|Ər9r!X<% &ds D ZU "ٳ/%,b HXo}֋9q_s~ѺN/uK߁JHZea+Ow,Jpw"kz ]s@SJ۾k!ILg눫zͅ|$6ͬ'wmU@Q:Wt7?x]WC12E$U!uH6YisU2\T$ MkcnzsƘ"B>(1$&*nhJBJ1&Mj5u!g9iC Ea[e3}MSUUD"j3Heq@(+ ~(&i$IQwsQvyo)UBV]M͹1+10RL!8s./ q?|svثoGZ6hG;BD,b !1Pc@v\5Vל:d7+JkL"<~<9λVi'-):HLE#1IιCއ\iEKB c,JةjBϧb@!(|Q8W ,!C36=12mjnɕg1&u4/$@ B5Ƒ(zU9[VH.}[va{+_1y;(\Q0$!3#3@}ʒ20!$D&Dąg`=v4wpv(QHž[e㦩MzӽP$(Q뺎bf8ʎ˝ :ʳ!>|t;w%[_0T?`LLNա'RZ ?-AN-?23ά5;,v^=ZsSMh3컻VѮ'ٖR+mAWN ^i)ݰe~9w @nVQto_~E2^y(%IT7UA :gEj5}1%I!UuZBi< ]9^a\l'ޭ7ؤYy[98O=w]/ҷ_# TA :m]O޷ۧz"s)^U5,r*.=tbIWWiG3u88+cLMXt{Os^@k w TB2Fؼ$d"6 , ='l}7^va;U}QݻfcO:1iub\sŜ̑JG@QΦJ B~NlʫkYRӕ\O+z̦+N_';—v#N1N·ZH,[u3|ˏ?W~9Tԯ<$DA EU[>̿Ct"^;o' <+7HbFMH /h&OI&6 /{/:tlg_{aSJ6ԦB Ak#Zs\ Q(( 4 J:τ *0)jSz]`PP#`*C4&+_=KRUX-E$!sK_E*[ej39DR0U] M*T @" žEQHB-9YK>607R !b!*3wλNVerL18cW,0y$^$1ZZxL*ebv0OU~c U$3%~H9;Ƞ9hJR1ԡ!?%#Ir|v<~(A1rzD0D%tcu,| Y2CJ5,)&V)jP6y\ ҉"zW8CbCH4p`3ƶ]1NTRjU2o8ڰ~}l2;_vkv5e$Mݐ$1EMڔ=1;rE;bR/^ 2hvyFwTE!!(U!bG%b ,$q՚U!N{ll 4g{_ZNgllכ89fwΝ;55~_Ξev{||bMӽ鱱nw,ZixߛMϚ7o]vzmعknذ?EDC"RyFGET#BD7?&xQ2J`39fo1"toWL$ f_pJ_4Pv:ݑ9{ .TU? UB#/(I$}i1/u/7:vV%E a<6kbû>=Û=+1cV䐂JCi"%LLL)x? J{a5 ܲwγOuӫnO.}=b:e ^}BRՉ.T;4(Ke&tQ;:kUDFw@o՗T5vsk,G{kH)ݺf=))*w:(r;tOz`hBԹ;}Kpa;u!dN^}s߿u{Sov0{#{ofGhqγ*H Of,s>g/Л.񢯼6%u/vȽ*c4͎)"EjCՠRǟZ׮옥PRJV'gz`WUTw .~>~J`t]k).˲p~.'s g< ÿ}n逄[TDv?wpStrkKO7{!{&fUWE :Ny%Gx}xxɯēxw׉sUaCވE(y/Icc1bnaih` /5@6DI֜u>\R$R@SE6bz-׀PT5ٵCvkll(K<P"#J[L:|cQd*63asb@*б{`uc"&TTCcl] !(s>K\]!&)C!mPJ(nx-j}6$ZqsT( _hH׷!*Mѻ±Mn\)!UzT-cY2\F["0#v #3j7@1wjN:%c)X&* ,2h[ft >;j\~8s+mǞ=rޕeќgQo۾x;ߜWZľ(֭Y$ŒEQZeJIEX_ݏ:ETw'^:O18bI9y%XS@ IDATRkIUUWUZ >9ƶoxY>};z1H,Fvꃖ|/lzj}w>v=w۷qԊ[AuEuk:-o㯼췋-|7]|𾇞Y7^zK'؆%/{~q4'>>zc׹p籯1.;?:>v.\;?Htw^uW+.A_=1NG_?_Z>p]'nAS" bU6{ub.[~/NDLaU*".w|ͪ0C>P&NIUm *1U0줖ퟳ)e.en2Z R|o|Kw?~x͂noz{ o_-{p?yٍ_O=c/}\)K5O|/[+6:3{a&֔;d!Jj{"#&fr Q]V')AcTEmU!Řb11S&g͟Ķ$$@ޕejHYr7ULʲ勪Ib$g?U'Zn~h~o}ʯg7;ae_?YvΙ/xn~K/'?q);/x'n~ƥܓ_+t_=ٯkOZ?wsf's_7|'u;}KfHe5Ӣ{ mX6}ɏ?E?zX}{ɏ݋~Tv۽ h@1fב|C<-84 ~~s} k}ݿȗ~Rٿ߿1Ճfo;-u>+{?"ٿz~}ˊ9&fdY镴X445RDJQ3Cp"wOQIi,+nK6J)T額*`@D16W45UlL4vj7tmb$bBV2aH< IՈԥlֶ-0Mt0RL.qYM]!Z4yQnFcP"%`Fblb`%mmCfHcFMMS*93\ on{t]0S1Pwh"jH1&B 4 Up+lHNò #jn I`?3##iTTj*JD ʐG#((:T5RvY B0FJgfTMU!2R"R@02`|037jRJv +-RJQ-~Q81*}An>y7wVQdM$kÐK2^DiaH3h)0늫?5]>J2d 4RZ.6mliڦi-GyNa"ee11;؀QeDf !O>D4YM}ܩǑ"żY>mcvM7iMUJO>VQ~1hѢEa &0d))[K?Hw^8D*ڏU]bC!}bLfjfc ap r&z>A0B$/GYxf5l%yKI7!WD0 @ h ,E>=𪦉M&r1f޶Jrll6[Y6mu L q`FNQ1f<#j $RLI$yb*E%19&@waCNe!#E$RrFtGsJ){ULK@NXph/G"brT_Qbf~A $)8:nZ*Z+腲\s׵"VT l`Y$ J!Y2 8p$w$"mH!CPā8pըcƞi"T:$uE75@"H\u#&! +7Y7|_q`dB%E.k7r:5)"g9qirMv]f)Xnްyo;`D1h"a9! l=eaEn 1㤛 x;nT00"BڶiZ5b1Oeh~ Վ<ǫӒhðj=1!6M`"˸I>$D#T1QQ0fM۵m41DD63XP!4ȒҐ~XR8 H۝6!&Ph] cdf"Cw~qVO*bѕۣGIpl"HؓdK7o@ )x#ۥRi)~:ݹBlsa2v@fXRI)!HEs~mڶM@ ERʪ4L)=EJ;FH@fm"qd1j+%jMJqCR8phbibd MccKuoG>"pX=bhj &H#0"\ \VPsNAJ%*.px3\ծM z[@7tw U ӐӐKuj,iBIg9KB56If D߿}=T2Qmk* BɓI7]ti%{t:γ666 "i6bDf"@&-"CJg.àEJɥL1wt}?pС~1lnA/i}Rlmu8j !rX@N8ad25IMv<+Z3Sc1ƱR@Pi`XдAnYRURE #Os4%ODl@k z( C#>kɅhPY*++[ͧW0Bn\RDnԌA3?u{OBoRE\^Cj!,RMJC6jRb1+Udt*##6bd+++d4) 9K'$wKTft`ΥHRR T)k. RrbjDu][DpԈe됐DAU;T]4G0U )DA\2 s6QU"d#@,3MNÐŊ^0C!t]7L&$XJyX i>q@>sA31hMdx7+%~ \ڗr>$E,6B6=9;ֱnS%BC$Z@[Ro9X̨)#ƀxY5 b!4,LKRHRK]Ay's G-5DtRꇔ`پTaEvmd:a!dEpAHI%RH-""@T"K:D+hhU HLGJ8C\&5qZUgh.ff0Yj5qCӺN$FvݑkۏlEӫ! HaŰ!p:SR CvMySna53f4#@BRR#JibM'$`2VRJ{>x 6MT"p`.>PU%d}%+41v]9f 0T>ky}}|iwH"2k׷,ڶ hwt]G_hBgd3DcV g+ǐ8ԄFGꄷJ:GRvlq:&$f`/EYQUQ@N!>Vc^-U7c7|"4C fZ$Q2t "X_@-Bɴm!CĈjF5(X&,POhBibSǧRL,G(֑4_"FD{T)("Igf1*00a ڰzC=uaa2J2 \D՛6΄cX %ː#xO@ &p f\ǻT=,װ)"ZT%aE.I5KTte>-2l-BL͍[ak(vqR8 We]Gu&?01T:rf,U;p@ߧ>x90S1!*YTشM>0%#%qrl.Y{ !Cm&SC$D=;dP5;։pk/RT? ` 8yK&ڧ fn_AST4 ðvollBu78Rƈ̒#LIEd&x=b%,HL*ZDk.j54B}jOD!"J9Q-\23,s*LL$N-@éL !pDެD0/ LLT]qciDr"mMCwIfJdJ)8/4R28;4mmKL.ۃ48ףuGHWbr'H1NRCrJ9g' #BlHϤ*`L1PZNiX,ЗR*Tl&~#a\i,B61A\'iN"2~,",` NoGMU,UJGlǦ !yJ5j[J1Z.?(ESʋEȪ)+ıYF0HqN!)_H1Pg^?mӵI7q65477`ڻ{EԔBhVf+֊ѷ.۽9 Hɹ_G)dLD@nt?D ]7N++^qY$ƦL8&5^ccݥjyhcCַwӶi__O8ĕ}E+HD󭭭öm,M3X߱0  vp}#]%媯> ۷}͕^p-{|=|׫kNOoWԷk?N_Qt^u.۳|t;k\D^lVɢKW@[.{zY 55Ei.VݡچP]Tn_Bq54@39!P%GJ4M۶m !䔪I Y-r@GeqƊ+ KnNt`ov9Mf-^ꩈUBPϾ8aۖKւP &m;iqެ^{ifiӴ` y_KH5tu, 97C_-E4{T]ϫGT#2!06B UvE::|:B5#Re؂H 1vݴi:@6ji tvDAb򁂙SJYԈq%x[[sLjeiKptR)EKb1&sgɢRJp&-&ף*PJEɇ*.geHL'L<~UkMndi^Wm2q}PKzyild:Iņ!-|xX>>_3⁜ut:ahIzA"a׍RJl_B7k)}^@Saq*1f++i<%L EcaBfi;HERJ*BJ.bksK\@ !mMaX L] L C`B1PmBY:ł*C`P BdgMJ< 9͵%7/xvCS$WuRG sh"c^MۺC:$ӯ$y#q%岵5_,";9>+B`LqJa1Ցo߯wҶn玕uj[TAJ1e6 8]8 a߾+.;XT_m"ZTap^@ XP k$McGۅ4.ut:N];txІjanv8666mWVW&]k[|1+]1M4ͬx o.qu`*(!wYtͶ)luu}Rθh4߶D#k ek@#m{m7u-VLW3W{辋9^K'v-Juox=G}z\;j?ۦ :oykdUSM)圤(1ûPڥ0M#3cf`Ԁ@}Z i`R&Ĉå'AQDA AET 0$\f|;m ]G̈1G[`a]ӆ'7tɤmb0$r_jx3r0"HTmo/X[s# p9VhE1p7iR iH%1F5] q B2VTB %8Zmɧ:S@(TLT&vm<("Q#̕1p^%8hnY*pYVd4 }? dzhl871!'DA\`T3Eaq}}U3*\mX{xRTT1m~CH̍0֞_Fc6͚"1j9 >+\`[*r8!H1̺ne6k{K `_[_Z1UX]Y@T-@*: 8ÿgg\T-(@6DS1&s16H\0mG}\TRF0@"" @nETL8QyH$h0صm5m:`D4C]pS)b}s ! 8ntTTr*}Vv 6Rpl;bKqb@I9CKK (%D9ٰ,Y21XM9bXr Zm&r΋"AE|> Áؤa0yF*E@C յ_,'[f> M2,ӊ|\YLsj}wڛ]~{ivHu?>׽)BiOm'yM^7zչ8׾n(fġe7SnH!) VaJ>`wz؋ ?u<"hYpVH \B'E? l嘊BeMYJIJ9'J-|*h_ǜ|l;/\|>j[[[CPiK`"o?Oy~=v}2߿3xE[ҴoTjr?~?pځ]{jӞ{GO>x>=RpW ɤtDStYػzkC;>7~j {'n?|_Xf.0Z#ɘ {"jPX1@bTp[IK:~jfb\Rʐ5icdE >*1=|(6vԱiBFbfFvv}'MVqGǭn\տxϽ3NϾǯ{xgăɿrqWg쭟Az#{{^)?ŸW|1t?7NM[=tWB@gA~̤:YUHXҴLsmb4E5-(>QÈXөHv\4h8еt:Lh0dusj:fac#BHRhb"!(&Bn:y"FνI1R#&B@Z&|p`bb >ȹA ZM3 CQRt:.8RIZ]]jcI۩j)9Wv`V@D١i(@#:-RF!AL eu̡zU@R{G)29WD$PJЦu^gWB.. 0J1bRM |҈7jE\MD#B ȠC\7 w.QT3-Wr4 KɯzR#*9T/:)!XRiL 8P7.ƶ1S`n܈J7rÐ|KӐE&Z׮ FIe9 %I_l nAȘ "!0mW҃9ƀ@dH~T\ƚRVh']7\0C i!Lvv+US^o=S6L5]=[ٱ7c_otחi7}ʣ/\z­W9z_w^__Ўǝܭrm x{X$qDI)om T S"Q'NhFuc T[2=#k͆#(0yDp]^'1'?uW]zmlk;1ea%ryW?S^~__z/;'GOz.|ijySs/̞Oɳt~eߎg沓;?Q.;wyk_O ?u?I5L;Y~anzO/w{w])3yn„#SHMK.aDdH"@/̆ LD Pd Q% C%Sfƶ92(Koq .2#eiuК6̺af@K/SaDfF:9_Q%`i! "%Xn+U+ b C ŵ 1QH7=oc4 iS.aB`љLDP=mlm:(ZLow7jږ<)< C|Zng,͂F dfM ), um03k)/e̓a}Mlv2|UH QLS\PE\QXSs5,h9< CJ͜Gu€cM#&3>{qǭ"l;3 r| ?x9w9(1temu;3ͷm?|?bK.׾/^򈗽ϱധlPJS=izozb|?s{ɊtRt2 !,G)ew!~w>r>c;W1[Ͻ߷cݟN^3#>7\ٗeʋ~7γz'Oz}|33/zݟ?_]>w7N?qϓpoz)8ww=N!o|O||~p1A뢏ػT̴.>3}IIv~/||o]ts^F9k]Ow_}VDK>?av|y=5%HuND=j%mO;YՉzqw@I?y'/SJ>'؟=Ͼk?g=¯\H[_ǿxow~s__~ 3_= }?}?=Hpŗ>_{|?wHQ-)9JS@O^3غCx{;>޿R*l cDsCĕrȊ$jN6L8jVi'g+(VS)NEVrN>+Z[_LN_UEklD11EDƁƷbV1Ml6M A͈6*&-J R|:粘ϓ3! R< 7Bdo]\8] T51X5E¶B Nb>ښKțG։HIy"]4UҌ0,CRNYM8NZN`ŽK"@YCĖ\JI$9u\Ripf X)܈kxC7mjJ?ܸ+SUF IDAT8pfy3jUͩD$%@ͥdC&Q~P\J\y@L gBñq/^"rdTPq[^̩nHґ6)alVR}7@w-cDڦh \X$p;m 0,BmM&y;F{ȹJfws}}[uNڕ"i>\KjIawpLÐRO N MMd5_80;c@776m âL[ ,RӅfLV+U3bls6;icz`߾C.[뺕1]{U0cj/]п7RzUu^۰*.G:JvWiRsˮ-W[W~q?/~kv|"rˇdN]⳯3N79n}k̳wٹ .|'#al)9_7:7ƎᓿɿrkGǼVO1|y͔%UݼLC0k,rcOvmI_brW*3LZ (HI2H EI$QI{uzw6z &jYahuШjfFh4ff1)90!!>t/m]R]R׵1:g;A* Á;&AQEwdErѣp, u]lnjU FȪ -Lid/Yr9U0P"75MـGVM,YR2"zm7Κh4ΧڶM;s\?P p|9I麔 ;Q"ZFRL)eIJaUU.1إs*JD(fˤ)IŶm%>n!lfdJAؑ@JWNPa Aq'뛵JdT7@ه$++A$w)*9Tq.{1XtL"bjn Dٶ,(͡p}Atyۖi]ID0 -! Y:ur#*n3% Rbvam IbJF-4693y4xPKdB\f.R7M]1&F>z,,nYXZjcfGKŪ kkӍIcbv)E 8bDDm]qʾq'<ZM^.`q0GRR=@T1F9ٛY6Uj|5{p2"^GLS_;]~r=k}'w8z78r Ͻ}hLҞ/u޶_~ tӟϽmyYP5 >8.M1#Ẇ>^Ḙ:lv!6)u]s9s'p{_}l|ڥ_n<3|5ܙOs~"׾ٿaKݜts$xqKVaPb2`12ZwM.yCۛ9H=؞VD }/sq_=;=ξ׉g&_?A96W7N?{љ,7q8^8t<`iuػz֕[ "``D80c~)W^|~ݮ{3z?:aN?yl9ԗ1m677TɰL!1Ɯhĭ)?5_k7u]G庯t?Ou礔 s-!f4NM! ZY!"]}$TMPjL@ :U/xٳ.U$ҫ^mxoRdH՝_xC_߼.;i_J)/W r.X㪤l^CR_aHbmI2&"956T2,M%adOeJ9O0'XatJK„8.`.V IUb(Hg0cP]9*`rH %IfϦEst pDWhp6Z9zpc}u:儎Ŭ˥F $Ż<^pv ٛL9BF䫭ۜ*(8ڡujBev4*""(`t)t2 =(Nmtit6TPƘئؑuL׶X]]=z/,l?fgvᆛFŅR:&')i[HSeX =DifDuhY5kfx4]=KsWy{~w2%ޞ1vuoKp`4~wmu3Ὺ[z?~`kNiETPIB-]>iX}gl&pbI!2w;Fnr΀Aޣ؇<7{'+um(!@Y7aɪN=nQSe k*`α sa PUk.v}{Ns}T,ݭW|ˡ~WxgĜ-k=zٿp`s>7y`1row9gr{dsޗ̳C]G1_ݶd"@dn μys9=8^?m{9ݚiO&#Rs_s?R.lYfg*GgWx"{iyO8qsy/A$eks |pT'qo:vcǃ$c라󉈫 h8!0#UX'NNwrɓ_(:@:D9INmEӘ̖u,سdFTz;Ͷi-YR$RJI5;?3%+łsQ*Q¾VAPyBY:T {&G{CUᎵJI%&E*fd%=`Y@A%վ>gU < l2]IJfeb}۶B6.v BuDH+`J 9OH4m3ZU@T!UȐb -)H"vT,چAR "x)׳@-H9H C9瘢 ڽ'9UG(A󎨠@R4)Y,j1 .*qR7Z^st_^\غ'=6R5"Ȁ(s" {bG :xy%TLQ,\1r^=p`߾9ED0+ :h&wte]vPemq2\Xٱ?]߿ss6Qx0^Zܱ{]766nEQb;kVVAMgzsmhSҨ$9kD=*ԳkU U@DdRƤ"]6d2MgmZ߼ھ 鿕V_}Ϳ  l==c$}o9Rz;l|wCt3÷/.m fA[ I;Go?0CAE?cI"44<2He2B7AȒ@}u®|ls(dXxoy=wo]1!fC~ =p0~-oڶ5ߴw/?+[=ϒ@me6ml.ĔiZU3"JJ ׋xՏx/o9{<<3mӦ{h`읈]Y rhm Bl:ra?s. SL?vm_~/EyQټCRuy[^ VcⓊ˔(U[39kz&0Jy8`:%_\oWiK]?'>Ͻ벏j7m+?3OJ'-]C Y'>^ygצwԧe|Ȇ;?|;WS>RFw9uj$zJ}ᵫf?r\ݧXxHc>0{E_Taz+oz1. !1뺘*X1[b66/TUm$7i@}pRzM0 ! b]uj!B^uT0gf ||!xز}ߩC4m`4bJVkL ]tAJ< VaprL @Y/3/el΅2]+XpU*Nf=;ژ%D 85mv]{ ؛qLm#$`;3/,}Oqt4mvv m+UESVuQrt%ARɝ`\(%Ij SlYAla02? 'ySל;VI_ʸ|U2Ft}/>|"-3JQVT%Tf̘cFf`F$%Ffbr9[Oh\jAg)Rmˋ` d3h^Q͐;I-`< `8UHEY{ps箭;g^t\v͍9ILNz랍Fʝ@@9$AT@u{ZZs h<&t]ǟQԓd=<GqWw )n[Yq0FOlaEisT2.TR̢ f8 ۏN1v )6t++{q?rgdm*m72=qUw;K:}ُ85taIK'm#o~Kf}ɇ?<|-;sϿ~=י隋\Ϟ}w}I&!sJc{_ҏ<91w/w9n1vb@s2Mf)9gS۶)E KZ [UA%ٴUZ#""=Ss}@F7تbe}1GبY5;#5PSfF$*C@u{˖SDT rkCgZf D2!3ϭ=)gd7QڮM̴8TUN74LV9"P <j$;|ŮuH ^R*YZɭQΖ-Br:DOnM4-(<\CSuVFH5϶yv:K5UxfT(*:P;@N6^uvQrssթ1pOy60/>j;wRʉl?]H&28  OLTP\ٺ7d `ݲTJQ67#p;u1GIcʪsuUG̒il:kz1떔o߾s% VŮMi[)&I6m4M],( h\ =8>Pj4t>-;<ԦFP6vd2qUe\ cyl:N6UuUB.̺iڍZbfQ5ZZZ\\\TꮩAh!VM YUy?RY9Y/v& Ů Y{\ZZFW;KG=˵V]?{ßWfl IDAT'n|鍗H|m>C(>׽e]=~cNU}YϹA. oxW~Oܰ&|kY7>,>ɗONU>##*3^>xVǗS{Fh Qլ1FUet;\x6~mE]7}a_׾a}țxOz`X]~CZ||}n/'7/%K׽)Ew:visWy#fw;sqwmޏで)O=Ǣ2:p!8^]YYXTU ;$@jiiy<^ bUeg_'ʓYWOo{I3ƍ>qY缽 ĥ^mw_zWkqw/]}38/Kw-nQ&o~qyzͽ_ysGoћ?'w_֗^w;_ ?pyG?e|vTG~=O}ʮͽ_}+ҏjIOK7keBSh:9vҊc{iA-(L֤EԈ*1Q?`[@dU{v{>bń2D,.>Q\f *։G UĪSJ1g,}M%BMS֩\ϴF sk9=1˳S%Ks"ycժ zֶd)h-$p̄~ R&a#"{Rz-Sb)c/Q^,~R1v]Qz-f)yEDC}4R`,Y?uӄlbsN8(AZ S6\1#wzpQвߩa|*9,To,$nU.*2.qORєrJg#TRTP唵$8mlGv߀#R!C=ki3  Aڮ:$Rd2ٜlnlZ `۶صui4ys;tpGBͦN|E~奥xTUGpH\µٴUnjRp4CF9nfs} n˖-yVϚ)+ 7u9F`Ps*iڶd2ٵsNFxPlihꦋl?)%Qt\#V9 M)|beԒ UsRUDy%d HU%*L?R=̂鳵EQ%b$j#8Ҿٙ"g)EU9%`4ڱ}DE z 8ؕ[ڏ63^ũU u }ε?@G STDޜiYY"d,blcI)Bo_1B53rNgM]shaaM̦ɦ ԓ}4))ŜpDb:_ރbJii9sV?60!i)@*:Vm7 J0Zz۫"w9vh@xfc¶濂)Sւ#XzcQEEf'DCk89mPƍαr G*2po?^{= ][7)FIcF x- Rl꬞Zh xcZ̉VZ;4X]__YPM"]bnr#{]2^X/./,.p4fvCB/BY[=o6ٲ#ȱK)\=DUr[.{[L!YZ1a4s W~0 Sj6G(t=l8=۫$)e&vG~Gtε(2_$س>x<뺵i\>AJm[lח#f[YZim#|15é2G00hX4}(#P3 DT5viE!,,,TUeM-Rl$˃Y3C|AcL9FaDއ@"RӶ)F RY]ۓ9jNfT cJ[ʾh L4]PS@PB,dPΌU0}*"J1vIT3IEeV禩 nG"83g79Dʩi c]!ޯ B)6PəYAr>h0zLֲxC?2Q*rlu:P`P0oIUC6] !Ęڶkܾs_BьZV)3]\bOHJHOa`|bsyE (*s!)]c닲#<;&rH@D0Ub8l<**0[uucmdYRH.T y %] 4.#>zoL#$͢J(ĜcLa3ʞzԒS۶C5v\ŤMWW\6q:fk$wBNȩ∫`-[m]^T0% #d6*G[U:HQXvh*H~qai8ՍU27?VsM=k@C 1TPOYR8!E@Pfn`i(-dl@+%0. XMI[(–c$<4rGP(J)L=Ctm'Tb@˄hndDyG&qZYJF9k(ʭL) =,B" Y31&(✚I*STv;/^rΚ56$GBV4ڻ19 ,Ie d-Ex4-/-Cs[έsFgEABE(ʹhxljsX/c+]9'"̲cKJkT1A ΁" g_c\+šf&) 2W`MtJ9]k>-IHJΑHԵ}l$$rdp[eAN7GÑQygҔ"D2?- 4W$[ i0 Ȅ &]\o۫TU86&]ve~~S@ 3@drX1>?8(+2ٜ34G:ٟh(cFĔrJmyqvR`Bwl$\{bJB2;k^2D8 WS۶]E,g DZDx *OH]Ωb۹7^[aDs;9-l;{T@;PIG?mQTbF6璝e/~bƪHs^@mH;c7v?X QIJ.P^=So'͙V?Tu 1N`VR` nv6jhp4" ٤[ݬYMC+k+++kk]׺ Hrn1޵{cv,..:fR-dL쀐 T)+h9sj[G5KŽ]%I,MY484Dž`<V5I3s= 'uݶeUm:~(蘇UHLU;4X6\DD;D8ol`|g`FQvj1ޢT.bܣTl(V[it yq?0as[ AİNY]p.7> gr敕~kn=vh[IcRXǩ mǮN9~l?ƓIU @QΔ!z:]_]kkisS7%cn ! $Z[__Y9Fh4**9AܔCimsn<)pp!&Vs.94F$S"0Kili8\X޲}ێ{ۣ뽣q:&i1g_l 6Pyǎm{$(䞪ֳn&RTZ@ uTdI>$ |iE|P,%TS۲5drc]w7T(U&9z1vqcs3xcvzHEAAF)2vwVqD} FU\|Fత`NѬn4,ũ[*$d:bDM#ɶ>gǠ8Fd㡙oU!0sutK1F sv\A\6=S?M0z*;XM*UbzQq~8sYm *"8oYNPQe@"rdŒHͶL"QBbrzHE$mk6Z E4ΌXU[t1T^A@"3룿ş^hO[$o0ÿ3(fE&9w XPKPsq4fP x0"6vۙ]*khv6Y>s{xPjd*aK8gP"߂lV.-Q"ЬY$cL"aBMQU_Su1-uƱ!_-pob23;!6 DXUa4Јn$* DT.dqLH(hC|B$ZhUUL5%ɩ)ʖ/,%%XF81PH Eխ 9^o?lЀ+9V{{~AJGDY>w-=Bږ!6DJGb Is {p}8j<"Q8b^ KjsWAૺ>ŎT*0VD8ۘllm6&O֦nijL{><Њ8WLYN8ᔓsUEbR˪!9ȀD *Nfյ{RC*LĞ0\m ÅŪ`sscMf3z4B߹'ĶmB:;N9$b6M9ٻMg`PN3+Y͚u@0F]"`a0WnGGУq^:ETĮtV0L *H 00Ur,Fd"b5T@;vBnee@I9{zHN1g%FvSJMRJ"[bLMSoL&޹|>4mJLdvF. L뚦VB!#y,Ys,-VM Kf@̎1M)TjCbH$1VXY2HNAJE :5QEQ9^A䜋ndKsL\%l;qF,^΢%e8+C SV!D(eۏʵdkG9s R^!1[sa|`S*fL\bRN DZ8ԶmӴ̞PM1]"UU H\ ,` W9!\.nΈm9nʘ;s#u%6M0ƔceT`hy`DL)DH\.13;_UUA*켷1'tC~TUI 9#35a-+5HRnjə [hњ@*0'OӪʎ[oxWP1ꚾGD%]d{ku-,,0]cvn@Rg3ov sؑc$&$r."EBbF"سٮi 3;W4KBaPs xIԪHJŌlȅ`m#HxTsst\ D-dIe=sXrTL%êO$u̽4dPAE_Ʈen "4@O^3d3aQ5gG %9 9k+][wt\ x{ORŶ?~h}1M1mܜY!+U|#& ~y' m߾ɧ(AձB 6,9CҬݬnnNקu5\t21|T$.v̊^ei8F ]յ Q m6u>m[{u+U5Z\\hccRZX][[__i)w0I-F CD1'Zxa &.nN.jH]6 IDAT"T;.G{ET0WUUyZ7k`0BU@v16v*c uv)2-zDůt3ޅ0Pbu)$#BJ$b3͔C@Ep QsRL$"HN ?{ofIQ{""3PU# Lrǣ"** 2 (r_fAE2Dq*3;Qkew\ s@18[Ea &֤dYfLBEr%{`w `PT ՆQ"+(upu#& 13ΩL8v'#ه0RfJIx|jqXpՎA%ooT4MNh P`GzipjܗC"ʕzAQ a|4bįiAh뵻VwbUt{|0"xTr`a!-&FXSu#35ouמ5{$Ij$$]{rPWѤ2D x=g-)50XG"RֲhݚlkzVOӤ QLԛYs {W[j*@7k (4MZ$J{^=1V.E)"@Fi1! @[Ho*$Mj9<<80贗eqoMfYk֚:ZE7T%O"qWdY֦S^av#J9>^~sO;x_9cR0ES/m5ii{}-[0@L%!دCcmjIIZE"^>+o]ryfH$֗:gmsk޵̼޿|r>󮷽efC/7eWܺp"O>拟`㢫Gڢ(JP/"|lG;߱e,q "C4Vճ Rb5!s9@6w=g}{`c40( {]> |%ӯ_!fs*3Ql?7{㌺_~n{cj?g)[Cv!_|ݏ:g ֆFŎCM65 2&aCBt&Mx({04GT2D; -!n"T2AHy*mLG/K(rJh ɔ$IeAJJ*a i ft1J8:(U@2-4 8od@ 9}@B@J!{H%&Q<{ lxi", [6t9]`w$`);Tbk9DKqeхK185Jm+UfJLr)>(HcTO-2䁬^͋Y7EiMZWhCzmtBKkYk"/ҳڌ3gϜ3Xj;v(lzpyuڮ,5QA,&,[tʕaҬT$iWh-]4KRc&ژVEzf-;e4AVbxxȬ3lMOZ[e,fϨk\tk`6: +VH=w@sh`&!yr励篳[֬5kz,o(ϢB6{W`IEC ιVyI$"Pep޸'GlΙo_/>y9&Z`1" iC #VPDp&R&B(] Yeiˢ %~tཱུh/[e!xDT)m ;"i2 J= Q0yAd+*hm{n:jÃ/_2'<@B%nT~n]ڽz;?O.y{κ/'>XD= k_ G>޳(s^h Hy1j`6@GDZL1uSJ:"zZal-N8SƘ,ĄqsiJ0V8 q6ǞϺߣϯ6ǝaw0+ c~(*:ze/\Yg}n<hG>g~|hKGs+7|ɗ]zK;]qvE,ei,NE !)pt !IQI7\xMs=?}}~7/<].~lt;;럶pG[9 /ȗvwF]f9QAU,u+ 2dFڰVQ Sm 5{,BTE.B, <)Db(+v,+IL@ R\DVU'}Fo D.^z.ߐ K;DjpC&gKqް6IZh4` ^Fqk#@q)R 򹋟"MOc'{5^ x1Ws_YWGu||~nf;sVao~Kw=<˨w 37;mѫ/5(s\X%O?'|OeP8kCKeYv^/,;TQj1{7P]kݾ۟$M2Û~G?7>qwv\s&":/7` 0{i|Ggq+®ŌMNi>g}Z- MziweQ*!t=`?<`Z+P)uڲ UHApsw]\]Ȼ~O,ˈ {-F*γ4|[+TAY-ŜBvluO?stԟZ8k* ӕ2k3s}_Ȗ |b;߽5>w_uy#x}ktHGǺk/a}?>g /nA"Es<;i~ /O}79Ï _owOXss߹_Oj(P°\%٥]R{w}pTB'!BWP=q Kv2c0]*v/_t8N)J I}MOGqQ?lv e Jי=em09gEPħYfI0H(Q~ï=x;!G"av `C|Oml[~zm===ʲ,mY#[rٮ,NtE#A%io`}1nW>qc}]V\F|DDJI2|Zo[$0փP#6];48?XGlc.:sO-now?n6RJkIzo/["a瀫A$Kќ`oF..w?|Gp/vN1ܭ|6a$;rno\78pq$FDH֋wf_ {Ô70cO}nwLIJr  :l1SdccaDJ0we!BhBXb*2= 2 fL"&mJco`(4M4R;,?"󞳥kEڨ$5$@ IG e?!* ;ˋZ-NK (@ H粰teA:GI-ͲB}B8!zmgJiR+\2&şo?u\ᑧ:sf/|j(USuSaӦqD) G rP+T91,I%FjRՒzVkubzya L9D:ID!R*ڭN{3j|ŲMԛΌ]Zjeb ?9%(ma˼v{(XfY=+ifHMd'^4M%$yԴ2NY:e9뭜18 ފ-\-:DTjF#\̂-}u2g}gVEo\k{t-Yk֚fs8 Y+ )>ufq8Kv7{I9C}(4nu9'y"+*Y008@D޻֝KҚs6̜shF4Msy~yC߾sVsיJL)b^qN''?,hyy IDATGSj|LDN÷=]g1?sNqW{`2;n9]z]QD-aH䔛>cT@i]Z*? *ER1B*="ig{A#j_3 -&IjYEuxM]t:\ ?@G~lE!V-EbB1huctֲDG>]O*,N ;fZ>C:rkUB0ynwgYPi=0~}?|NNē5>ﴣ4RKzUǟ}ξJɼ$KB,LDJ'CC iӠUJKsHpI'.?l}O \]] PRaʈ}ovYk-HQ&IiR$G{-CM}إ\ldtZ{j;}A;)Qz\{^t;uwmhInK-#3fzS8/<꒣.v19Qݗ.SuyPAojwg2b=fa#C!JEdžF ~=05+ibpR}NU&sԥpm Z3ݸ8ǫWʲϟsC͆.u[y/y{yQ Q jFG4chݢ}_xY5"m6Z|0T@ZDK̞n{vó_%˖/vz֪z]1H&DJ9<2k'jz]P,nrrrPBJ1кB|𖔝#^yQdY6PjeY׋.gR5ޚfYki10s hǼFBUQmwGMcyGS`I瓼XGt0l#_rl,r)h=RZtC1Dmg"M<{mNCd Ze cfVlo?ǁL~C7wϮ0 H@fUBA(MJ)E*Z<{"~U'{2I% "|Svo}zk5;_Qg +(D2 }4FDbA@ YɞR20 xﬥ$W̞h5i8: !UyEϳ+K ߆/l}E2|NkT$z-IRt RQFY<{EMz*6PC{$)(9gzG.(RA &сP{qed8f&*9HiiT@YT:(o"F,-J;g={ B4:I*)203[(@I0S@Q8wk]NfV$D %8Q肏hǜ[Hk`CUA=}pugA?0uNaX/>[ٳw:G!UVLV2ܸӈQeۏ03a 3xŵmvjiVK;. v,KReJ4`sR޻蕮\.W 4Ӭ 5!ǮhMvnݞ0&Q:r$MTkSwRZ_t t&iIN;7ǕΕC0ڒΗeCzHO΅"Uf037` ˲</G>?;) ?Eղ$MC~RYZf:מM߼~^ؠy6&Ik1 b{W;yѓ@gi؏M?<(r{~|ybN^x9oJs+{/zr2Ԓ 8xhN.q >+~A+8:Sn9nǟO-^zwcBY ##E:w$F)]˒38jSnXw)'.lq,ݏwl(.8n#Q):ƿ~>gw={z{nO]}z9H\mZ ~kuK!I$+Λ7#'-5P8V XxC\w=9oyvͽ^)?7}Mdļ"rq~~a97ݯl\!HV:)cU$ S&'*Jr(KDs v׽鱗b%p7C?Vz)7|:s$seT" t~rhIy^xH$$CDˇ>Ty< E$@`e?[t:Gǝџu;#?˳]o&1Y~'J-v<ܯ}7}u+ iHo{蜍;ڎ Pu!EkP*pHr'D"{q{ ի[2N [D:w#Iqot@&9^ղFf5":<ˏ/3s{~l9vnZ_ȵ +Ͻ὞ y>i?=o% jv ܓ7\J+zS)ʢ;EQ:r D,QhMVE, YaCPWH%I/B9Ҟ $g]3I2#UZ%ix g_Nž#F X#PP.!sHs̟S89V 83bdMӑ P_ ff TR`՚o}SZ넁RQZE<0 !HrY)vcLbRznYClCQ7R&ibRgqbu lbKE篽t;^i<_{ f;]Yli{Uc"̜5kܹ;Ǯ6 @CѶdve:Eg)!Egl7hO'oMNֳlٳREQ;2/4IK i6H -}?_BL ȯ_'^z8E+ioՂ"">sO^7>}yGa>/Z2Ku5P#o%/ן@[x莵&^}v9HL ]P=0R.՞sr?ƒA|Ѯͼh/uaOxjay~_Gȅ^rƫO>to>v/]ѣ tI߸GNDٳ`@wa7nS>_o`hէ83_2;{vq}no,qjߪ_{_vΩ~т%OuΧjBm(LK K#W`zNcEI:o_}u?Y~y?Ky Ga֒[gm?ux*Vty_yݯNQGm0(ҡA~8$0% ÌXxbHY zyәsڣ/ܻ+Yw:]J ³vQw zpYXDy'N;?+9osĥw_:w_}^܏x eǞPZfF"iaS!RO;}!C5D|{elbMxW}G58><[C;uR[[佢e4܆i&&:A aYex_9sљ/wqW~"}sW|Ĺza7?|gSϽ%uMGv-W~n=+gtt\M)py dβ X5 q;/4iCJ pALKy}o0&%KBtBD&QD"ޱ-Yo(JI$IZ$0zE^aB\V)4I$ )@Uo^HsB @/Ra eQEY䅳. q2Pe3a5쳵H; C.HM5N"*P #BڨH}x'bxP%0ʔ`6;Ji VfiIASp] AࢾHp_}ym%g9@ @HY:y|g4 Pŧ VVAtޗ-uf6$k"lzdQ9 җ(RFª{ݢ,>]{a)^Y{Bv]Ҫnw:e6FT^8-'''VZl6~ӆk/X|җ_yy|Yf5us6e^o1<<&[آ:^ZEY3@100VkllȬCiiJQt/S(y/k[ǿi3~_^'w߷tz(Ȍ"FbV~"B5=T'S|E9>(p੊ǩ9N c'^Dǀ,cc푑&Liy GThcO5@AH/R"s,sV1F81+:M,0E"1#XI{6 Hw&JαzWY+jt*ǣP f.=b&CeV A){I4MUP-{vއ9`a}e1>H  L 3ya"mYrn0rؐ(1&jFp2YEهV_)2&qΖEyHIZe^"!"  z8@+KeᐣvYu6;VY)= IMg]ֺvUEfY:kHeHz$Nc/&LP ,]ؔ -Œ(R*^Ab?j(H$Ęw:*, &,ˌ64 w?cj'ٌ慩1rc4՞# KO;*OC|I!B$o.LQJ+N*oJh{pFrn1BLDk-"λp!I֚BTnaҕSQ}}7T*ȿVHl>9UH !L_ 8?ml!xH1"oCݪb,PއFA)A2hK#G֎Ga!cG];1p7HB@ 2&5HY Mo)DާU]NDŶ(K8i #Z@R2vH@Uy h .V*Jb9vaZZ‡ ̹,ˌ}>:j6ݠ^$(wcQ'HFhXJ,c ps0cdac*ЕU1dsYg^$%|E&*"́ZDbժ!Ḏ0 B5*QSXCH )"V2X[vzCD&փ$ DFoK\!"3uBd:0eN#uVӡ# ZkO>XC!pUyΒ#YD#,5 A/ 2sG":RZ S]((0i0G"NRY !iT&P%@Sl11u]UM4]+}dns ) JybMR޶fF^M28@%!Ĉ1vru  ȍWj`f$0HXC7oM5c Qȣ(3CU]U1x$th,weYXQضOϔ@d|TA _vz0l1DȒͬ&FZW!pH8!"Zcc5TDFnQ>!Pu4:yQ2+Y!Cdc-Gֆ] >zۤ_%XbJI,3&%>K҅:v;Q36-aU2k>흿)FFu^b7ؐ1ΨH0BBh )|01(eQeC۶6UUW1YYNY@ G\al`O~>WUYe^ as 6{b ;7f` -"/ u`p|!FIc$e9>Fe qnvv| 7ltֱ~0u&M>F:xB{eeA&DZab/~zg-oB3?G K.weRyW|]|{=URwu({꽾ݏ/;~4݃oW}8gvpϙu%EӊD]1`L1K[ 0:g6‹&RWfB&~ 1Үmn-"S SV!Ah v'"m=_ ؒKXWL=S0I7n%I'`CrF133ɲTO>'fZK&l͂(1>ksV .P+Bz;85͇ }_N0&c22Z徔X32X12D Ķ](8*iB 59HZY$ FM"@dy!VZOYu,"6ՔWL:Hi?[\yQ4eh KJӛ%ka!jAe16-S, i'4>4,Q Ͳ"/˞ L!Kc5zc$#P9\RNo"u]5X%~}ι,ˈ30-+ 82hucj3܉ttc3Xj16bXreyFCa4q"" .8Dkfn^1JQdEY v?A$)S+li$rH"Y4"s|Fl\հYc:u._9}(7BFo|QCzĀ0S MuBl;9UBDdi0010d(}ᗥ`雧N(Q`K&~DžɒVRQc bj~BDHZm33\%cL>F$kvX0ee&ٙh,̆hrPH-gɒeqPznIQt$dw=i,MVs@BEpj"&,K2Rb_oThtݧ9F$bCluJ4E5xFBe4J/ r2C-Qb(Pb L 4M}㛠*CN-QP 8dT]%G6ι,2gE[Jfjo$g C9kMWX'&Dlrrr01Qzrl֐biNxX !e.2MRsxРjGS(90c֚iB"%bD8J-NնH iaWvZY2)ƨrDr:DW+8Q!csc6~<F1#E EQ"GQLGQD,dXYǏ!nEfScCbA+c˵2KDW݉ $eQ,ˉ 3IJT>ƈ6EuV&ȬfY}aY4@Zm(Ţ!KHD, M>Ip/;6ץ/073 Tu3vfC2 zp6ڬ6͏gv̎ƄTdZ$C@Dd7)%x0gml}ֹ\>S+&ɭ3)0 f6MNM3:njjĄop X,aQeQfYpX/ ofgggwnYcUS;USX qzbjSS6XFk3BֈHUfq011\zݺ= oZ\cpQy}]?NG~쿪kڟw%5Ԧ{^ᨸxm v]RJ4yHS&Uk-ͻ5Adf`1P3oDm3#2mQzBW:PKDd0£M111Ħ46eQap+ ц)–Td&,ac-ɦ̋\ ! :+xT:% N%Ns"9HJUӹ<ϵ7O&4VSvLeJIW@b.D$,!*D+pK=]i[=-D#4&:/ ,/i(80$'2y^f*h1dc>$%v2$քڙAXm`HJQVU+EHhɉH4Qog;z>T*YY e.suȍoA ̧e1cI0p<3sgyj"5 _mIdo:\f3!z#57M-™)&8Kkm emI`[QqXg~*Ðzb"HZȴs6:(aJ֪ebQ]xG}\$1"AWeY7!rőU򁨏9ZN5(5;23' !AC&H16G 0κEnLV eY6VC!6Y`LS,+͈,GhꦩxHbgygYN192Ł9&KC$ee&7Pwe@:uHݹmPmܢNTD ]In5N.D1f"/bC Pc~~#QYyVGU]  #q98gcX8\=? 1rlB mz[chX͎qU1^ /{մvzGLQdaadGzUΠ83͋5'z-[ؑeYYfU?}HC}}3;A ˆհ M dY/ˊOOeAθ̸~oВ`Qpa< Q ־}Y/LN~{z-޺a$g&_g+:~|_~1=_9]k,sw9/~+*f_]6ܕ}ػ_>!0kK-H߮:JOVV֥;ɘ䴁t&$&c]E_h,b~SRO`!}{tokVƑRM쫅ˆ G'Mt|e K471J 5OvX6VCh_-?@#Y|1ƚ,B;QJ6ˁwklKRwXGdȳ̝X8̋E\ huD }JA2EA@g1F=C0ĠW@a<.GChE911)UU5M!*O=m^6bH`m."& $A#2mJȥuBLvVfV9y;gF1qSSĶFX45G33{+VLL RCA}Q\\9D@F0`Y4JgTT} ,S6MhֶrT"cȨYȠr](NS8֤P7\\9'fE@HhM:/iB)Җ{iU2Tcx<UBH r7( Tް$,κ,{eY( D{S۞K;TpW>" UXHd G1pY̢ʗUf`d:*DQ3ʌ51SL9C 7% ob:rc:#"2c-%!LF!XitBҘbMm`̋Z2E HQ/$aއ -Qtp10i b I-8vY=`ǁq@ G2$0h2-Ռ1E($:HM9? AJR!F8h\"@ lZJe&u_֫ ;׿CmbxDRg\EV^W_x4uY9; oT;w9ĹWu pJS˧%RSxX0y}m܎nG6UEsg-U V\mtY)jYLU":ǀmh"U]`kZ Ja&([iiO,˜Q 266]w~m6ЇnY'$kIЙ[.uLG@6ؗ\@w|7_qCH)5D?:\^EEt(PRFbuQɪMM su]Mϲ9ۆZ&6]!h~Lv2GiYz}clSx<77ѿ#T:sYeι-iA[ڒ$rlhsP񸪪J ue9w*j XUpb De`bbʕe'^DmFd1DBKѯtJU$\EQH宇I!j\k9M]W\ԄKBIcl1KeԘ[Uu]Uc!xL Q 4M5Gf"rťu Km'ΥS+JM=X,W]}kCp K,םMxcdҲf( ~UcX5-hJuAӔxˬ=-!߮wkqkAWx21RYʢ("TFL \>џt6GjFp~<AZi[f !2Άxnvf˖; NLEeo05l0XVQ IDAT ;ܸa!Sy`쎙 ɾ h0,_bz2cΙjx RD3Wxa8UMZ3荵y33ۛW | a(LD~rTeL&&,׹]a~4  Oۯiۍ~IvwYu_=BJnZ*QchJAAW/-w=p~O'd!*kc4:*rqͳ%~aD|׿c~O|+ɻwcL1bDj}",_h}tZcL2DS^3_s޹G_g}d%C*{܎V #==_9070S#myK^^77/|bG=昗=!v/^t@-Lő, AhDHA|e5׏] "1qKKADw:FR:"c}uz8?.(Q\PD !G121e֩5KZӉAzb#Dg1<Kes3.6M-"Zey:Nlџ_tA8FcXr[ꆽ~h+sO_;9 /$xQǿ9Oo7_RB_wo3s߈!y?uS;7o>>w`/9Ygݣ_wsꉹ;nO{euԏzƟ׿ WrhVSQQ8 QC46MUU1t5dι@ԣj"Z+ߏKQD/6"/rkhftL1X!$˴PUUUFD1tEYP!E2Gb*%sF":8,Q4Tr;-Ł]~>eA`].8; pC칛>b'n 8M&!eJ6,1C}tNjȪA`7ƒC ]O6vWVN|YwABZU" sT\R[ >wBEDi&K^j.莉n}QyeV\ch6 󣅹haF8Zʌ~919YK,k=eYg3ֈH沉eSr*ݺeMn zk֮ K+rzٴ4ƺ,_beOӅ[ok-d,}0dfgfQPXVfp<޴is7dv;k"#~y8EcUW0s.s f01f2ٛw}ȴ4[?}VkC:amܥURcP|;{<v_#{wy.:C;fnK!k43CQER3L23"{=/;q_5yE7xE1rW"N.!VײDc2}ۉI>xat}*k,bxGAhH/.q4Ҍጀ=};xc-{>|M8㫛1l1F.σZT7=͛Y'|!{3.dQEÓ>\oݺen~G¿ҏ~>M[|ٟ4>NpP@C`I<@@D ~z)/~(ϻuG=~}iM8F\T,cxQ_x䃞r9o{57X'7𒫷.{kzo}ݟ~[7_pѩjoqg~8WtUሙ,\|e~xxv9b'O>?_W\mC#{槾*%JTȉ=&*\(SAM"qb83"BXZChDeV "ϙnYb1c!D`*SRQ dy幀Xc26#3m4Y*%H_Yt˧k]+"ULMIWt+4HHYbdC uVg(Ycd^DU Gd}JI4*- >xD,\5ЖjZM!n(2/22QÈImѪaQꪩɜnD 8~Ii9" !0g,9e"* KWA1h\vSݥqUUsù+_rzqjT:MobĠ( Oy>fgfw֭sYv 7o|sv$C Ez%4~κin|W &&x~nn~~~<-,̩,o`ruSOm[-]L3xo|s?{^?m[8Ogͪ+C:AskN ˗p5w٦(va_u;WwXrv`_A>~S(oz/;gq+ǽ({N;9xM/}*ؼeW}/?p7\cY"ڰif=`'_v/x_4ZH.KJkhY ($j}c=ኛ׼]U8+}x} >W-3<x;N}1=`]Gy~*He7|>{aqƖg%O8c.To|oz+o_-`Y'D11kڹ~~pշ&O?iVK9]roSW_ȵh,??ӑe+Whs|+nY3O>[|9reyOw"Qo\oS?jUyMbfcrE^aUU@5GeYZgwrK-_诽dيˏ^{Æ"p\u!ǜA0d1h(,SۆsxC7Q9-PN(Dz$"ZcVP!>Ta1DYJ7)I($**!(N%zi/S6lߝ䰴sfUٞH=00GDdlߔ AP,:ƘT"*",bi}ԘfaWkY9u5v dYWZc roPGȠudˊ,gnSk@uAZ$`6VY)j&teO D}xc]BH㌃ T8sy+''1patdž[n߼3x#7n&}TcCոB@_06f p8eN5&A|Y,RVCh-EU3kzv߾L/[vm7ܶqㆍκ˦& y4Ù +V^f{,k|(ʁ 1 UdIu>Dxd4H!D^^oUW1|lۼef(wek{+WdYlwvoh !OiFlN}rq_r\pۇN>׾O}|di Dφ/ͭ&Stq vB$e ZbB^ʳ |3$̲.3 "o9TM'eBsd867~Nxcu2w3ޮwCJS'NqxuXۺpǽ3)@m1>?x6i1ζey^gm^a^"2Oo?Q_N=?|W~ ('%m 5lL)yY~B8OcFl!DV#D!$cbH2l|@n;7Ȼգ/z1~/6qƿu\ O:Տ|ebVUnG}yǟr="> 7Ovr5m>x^Pm$Z?kP7cL+̭q5p!l&Վxn|x{OykEs+Ւ?((UqJ-BrWc!LHuP!4MV.nEg9H[#RWu0h iv-aD ~@t--Ky%Ū ]F٢9V XP BDF "McR,&%Om*i[4VZ(`~ @4eyQJZ&0GCZYg9&=~Ѩ-M!0D2h,g"3dbiByYd 9ĄB!l''|+G Ep؜(U`29t&TU=oD"j 0en7򸩉+ ~lٲAb̎[7޺i~hL !ٶm7)sYY˖O/_Ux0*oɰ}6y2_ϞVs+^SLOSrSc{U50.`W,]o4?OnG^8`}2G[6nA&WZ]&8"`rzbٲٙs R;a*B02 Y^Xc*_;6>}p80?P,X49f4~87ZIhܽ۽vo*AQ1Gw)bs6ߴ{WPѶ nj>ghUI4'*)\&G~="bl~>q/OGN/ш@K gccם|ysП9-&1D#_?u=sRq`MO8礧:eniJDj~v," \Ǟw̎>/x1GpyJLE,BK8芖9TIYPsk0!D`i[;"klq}e}[N~apz=c*M >ߞOnɲ |RtR;fN4(`lu92 _κ.6?||?uTWyy'򁗟`nw >"憋;;_6$l-mdq_ h`envvsÃz=,ˉo"X!2 IDATymx9k[=~2ZSa.CuD$ b̩HEQ .Yjǣb0I86M#"ֺ" Gkr-1csZ=΃R$GZqNcͣ-:o{Gn9VCC@P۹| **2#BY 2*Ј"TA1!8IBFHa{0I).m +}Ƙ"v@cULyWŜcfUD"sPT;gSIRVCDg$P` a_˅TBVs*RĤE3h@EP&H8Mԍ@HyHyfn}ŷj;wsNƾάZ܌xkbm;>vƾj9u>ɲ.vHyl{s6Y.KO6O}?g.38iֶ&'(2m/f[Y"3Nbmn1rh2>xx2x[s7p,Ŏm-7I`@GGr}wmw9ьH"t2M|\.*$Y3ރ{koLG4לY~ۭ=⯙Y6ToGo:x/iЍ;?~~u\*d پХvD< Gqɟ;M^jUc&6 cHOlP}Wނ.W~ܬzRɾ]="H&47ye;?}m?* L}r T)'%X|b;o<,wΏ}{)ɼC?߽,K6kVfyko>:݉ ߙK*8Z֧w>Ο'ܰ+ct.w<:E=K|gnR]D ӻ@7o<@y~ R @-!X 0)Huf&hbڈr)fOB@7ߖk'W=|3?y #k!+ K6sO>3mQ NK)1SUWuSϮowqJIU&3 ^~rq#q.b-8JKg^/Y~/o{o$v>Qӌ"}՚sF/9IJ_f{{-'|ڸ }o/#$y|.N-˟ӡ9Gē<`y])朳؀ xǎcDxϙOL-OsfyN_ųMYU#JGKVk\ؘg:2*m0 [mڐ 9a$<;g)KJY%kb>9!"zo]2Tʋ`.8`t9gb$UnjJX*8wK@+y2n16gZ%YX8WCG  !cL)32 D.YQE,`ҿ}pU]y8`.[>zdq%I9Wյٰ%K\dT)ŔW, ͸vW|6p7gq&UtMJb=z2GiFUI*rƳ\铧Es# 5vζknޚumc͗1/s({8~GӧOUtmn{/7tMǫ:tru5꺲cΒb !X@63:GYʇBS-oGP1woPx szt%xK^{yŋy~oMCD3cOydrw`9˛/{^=҉w\?zwMG~p5&eחuk%j:k]_}'?7Ǐ_Qj%h&CF^GW?W|mqS'ϜWye!8>K4it\v}o]_cECLѬu"FfQ+cTEF*·\c>cG/<ۙ7w~Y?tw}?󁷼ۿoQU\+N?ٟk~U} +K{{hBU)>3~KyûR;/y/|՗?Pm#_՗|X$Xq@f\?a=ς0C'{b 8~f6ʒaƳʗ1f1)R)jP,;gQd"Dx_l_]O5jtʴyL#1/06|{sxJJ7zdN۟}cw.\~btwGpLL@H) ] ١ 4>^u~/x/;r{Ux/~;p}ǷO}?}w~UBU7C?>/~uyǟO-n}ק|}}D{|ߓw!Η~g=cO~g;sq g܇w_ƻ_ss}fWR{|i/ug6n{_~s~z?u7nw'3mKk:v#BAAWkU| dT)$i(z"U ̈dŒ>"kP "@ΕUv+[5=2%i 1êd bc\pw"d8kY4Ysl%9>3;ǖʆ3UR99QXi`xbDЅV( !䮷{*HHI%,)ŶC9tP4\ Eaz/Z?I]wvrg>k۶P #_mlٝqd|"h}xt[8~xECuSf} vvfEu}L D5xDd`r>UUu#Kum'7B@W9| S_z˞o ًo|Yi~^}lg٧OWO=}~ v Ggcp[n( 6f"oUH1ǾCD2?!u'~W~u۾Ko~O@TAFW?Am&#)JrUGKX%® `Z]u]R̚P:tBHSNP%2$É:NqH. "e"DV K&#,'%˥CCQ rV꺮*!.1i1m7`t13=`!O94@UMfJ>w_s1mL1>0D(DAs @\m GɚRF`MN\>}#$'ʣo1]YZӌ}L$YRfۋ;HRGњs5KQ%̷$ !M&xYsbyw5.V<"Bvw*˗=n93&Qվ SZ7RJ9'@LRX%A ]xC(:GD%0眳jV&2";烯y1}FPɹRQaUyv9%PةE&Oj BEsGj"r;@"DF6QsN;Qۚ ÕVuȘ-L wR#+Md3?Su}SJ`m}]WC i#y@p 9S2L޻!VSN04Vʼn8T6*, TaLA[F#"سÚ-pKeFyZ )dϔ*0JxB$K&commw]KE$sP *;780OBI@uj!q6-rSTɀBֲbeHwm}/YFd{!bL)%;doKX%:OCqh?If*.RN9 0Z1CHS!Kky2 =zZ ",g Tn}}o!Q/˃@xyP1( ⼚bFBs۵xGE4l{ JYUUt}߷mJQPͨLUU=`G/䴝4G.hng$RєssK"/ݪw\?}ԍ7ݸXΛftБK.ԡ魭s[ng[gO98w7vnzb GLD$[斃D$IN||kssksܙ3ٹڷ44i=Uu\p_J}`ԥL&5uJ'Ξ;ՑGu\\yק\.zԄ'Gl8qSv6~ } 0eN'zܩ3')݃S[9d30@[{ko}-)} 1F9pݍz-Sw{1dz6Tî9 U@"łCF*D$UN,&B*b"͜[(y}\,-5]ցA+)JNTUC)b.Gӡ3bL9'ΫMs "y9[dI"΂ü*J8T5QK蔤S]Kʨ%X@ 2И 6t)VW*CIڶ {޻UJ.,UH\6[[rrLzь OƗe*`sN9gF,2D @N)J 9C&n@s̎bBTnbKcFgK LϢHȕenJI$SHSJHBŎciqzU_j7!+zUJs)ͳ3LNZ,)'U>4MCľﷷE.KtL-/*bXnYW猉<],18l쉳2P/ַ ;M} !IΛ Kd<ݿm/F5o?W*Wh軶ol\,cs;[mȚ=zCO=y8:ؙo9} _3WՓP-\okUF 9u9>Q&vzИ]lee*?fT]曾z_;W![⣗\D ۛgv7cתÇnuNǓsۧOpֲQ=7+dBu][{ko.B3:98sY <w`\h@HK)D3s.lxFDwQm%9=A6ݭv]sbQM]׍%Kߧk1ҒJuQQ9ETs)2pYYJΊNH䬁w[p(C$I"v)8FO}_wo=bz [$vlJsNR Ω";?`P<H hESImO| `G B&v.T܌i>rJҥ.uهYi B0 [p޹$)gќbBNJ19El>VU;b ZKY(/&1WPb1ls03䜒e< IDAT leG F\L<Dm%3f }Y|Jp! M4}4OnQ$#*sqz^ʪU5҉9 "*8ĔYTt dYǼDvC"݋9*\6Ŭ(q@(< *حbǻ4Ax=E÷NKC=\b 9K9}۶}%g$Z5grH mۥKBuȦr%SnUu€6*w=tAձŘR |5Nv\,}hClel:]$5USM=UON?q367m>1s)*dbFU3UY(eE8RLrr{ƝLxƒN%:eы:C@NJwzF1t6~/f۳ŬϱiӌGx{kͳ[yD'nu甓T:z`@=wU.dgIDf1)gC;fgZ>点beS,<"5y?H &֛a!L*kL raR #LVۚ'CZ!BIc$)gI5#.rL<4 -,Q;oC @A3 01]HԨ}|6N'ӵdm4awΞo@Vx;0zb󺩫&Rj|C蜵7Ϟ6v{{kou71SQ&&bX*ѰP b!1SUyD,m*ZMXvA옡0ynև? u]Pvmmn.n4Gi_Bo--Z70F0##ü!TDc~ggb΅A9U*hҨUj  'c̝`DZҔxd=!]TWlR2L|Ț[ D:DTDre %dD+jh/,e .O`h(RѿqB 4BDgp4# hTb,9SDZM%&t0H}.F5*31()cSJL? ŧGU릩ؙYԻ@D9Kߧ2Cb@%T nPGgWе KcFD#ʚ2WUTQ! CP)Y,(>dm d5Dq掅U(XAU}sMS+Ύݾ7 E "1,l`,mΆsCbK6Q #B!04g[Qwڡ)[| $p}pޛ,A7Bcw` @Ѧ!3k۶sL *:k@I  DfnۚcQd@g3S"ιU[P[ͰZ10 l~ :MSED2fffnN9礒M|}ohbb.}d𕯪*D("dfnI-0S"PjȒsS)+odTf@ ,9A~ٓ Rc/͝3gUtG/82|TcٚR.SpxnMYzD1ԵsjTa!0T@h⬮!ﻬiTeGuB`f5c>8!$1看[ZDxBT<"تnWJq4)'c|-2f`1/sPSkL9i!% U=Ko*K16G-qM7bJ]ۥ!Ќh,x2hAJ9[RFZ&bW}9F@ &4l(5!z@m"]u}j6i]Dī9DRjb-fפ_j_q@Dr9v޹*DTƮa""*"d$b1C0YVFSٍSQ̜f] 6mfUu 1g)d"+"ۅ`kH1}XV"tGDKjoU!2D*sEykw,*Cg_.r"+1)'jB{a&~̞߬Ӿt<ֹcus[M_ -SҮN3]Xv}Q"tAr̙ͭbheIu=jF򄀀oʗҵݨj6oۏr즤Blvns3>T!TmEVMGކ]pǎ[{? :ۤC(Zf ƾ/04#Yr9"0F2>HE" ՗!:qfBc!ޱH.P6#އAuUAD@ԶY]_7 âf݈vU5eɒSr7>Pu,SEձsWU 5=UI9JD\+-gJT"^X {Ur*hNTq!!V6P`dX,dnk% {A1crh'*3S1fQ .s%#=XJf29Yԡ%QjN9SFY?{헾nwV/mh5vΖ ZSV$DTWO~/T$k۶P+;`y, ؑ(}6@u1bJ-<"XS~r9 X5 qCՇl=Fs*&SLjVuS5uS ", ,zC$"b]>}k! = Um1Rwr*hB4F}߷Mr:_o\P "c2ON"eHEĀRJOs!x3ĬJ-VXu(> QWB+#\55{% (Y|@Hn%m!Ք30" Y@sULc"2mp)" 1{W`aY4O)%Qpͱ9Vs'b."oh\JY0\od;R]܉$E3v,Yrޥ11F%&|UU(YR4EAO bĜ~7r]vHv.)tm=2qSMigsnmV4Ň=}c4ﹶ$nKǞKm-d1*|mu9bު)jeeU>}mr5sg;ˮXߘMHEs[;}ƅG왭NL/dg{v얤HU{msJH x\Օ&t2+`c{4{g?y~LQʤQ]8U:xⴠWQPF/H 4\Ior yƜ[X4# ջwCp0's$$Bv,]op1kDc -QJxP\`ۘmdB9hȘX$) jNyl.*p1( 5yNrUJC]Uwˮm33 {8_&W H`#f<;")KJb")Ԭ Er}L=D*)aՍd{Y4%U8rTs∪rJ}Ehx8VYfrk*5[e3v8>(9!9:GHRV)!Ym;ZڕU//YIK|mdݡ2`Hl (@6D C(\vsbv"\)E*1Uu "_ Y3AiRfl4*5PB/"]QUp);16ME!'$* l6k'UR^)Kk+ "{\FEDq29Lxf7{Arb?/5eP uSTA8;s)ŘcJ)u]Ssv64 va1L`ɫ`pK#G8;d!cbUL)%g\h)dHV@U1إ{@rnFɲbY XGNsNZK=Dr)OrJ2s{c9)yv_sgMS|B]Ղ-r/r9j2Bwwvvmz}}l\}vTU5O[߿bImU:Tz!|MbOFLr.|}3ڮC7ku`}X7˯'|(UTuB1271"ޙ@qfu)T8df Gc8̔f&+ǻѵ_~@٧G.$9VL/'=ֱ/ϻ-1hq<;}y/{˧'/%Gmw_x TOՇm7~W olW.9T`.{#[o\k?Y^69;޺=Lw}hn~O-$u1>2⭾G}=rpLg|og.٠񴎈rSv<]:HAͫ-3E H b #@s"|]W!0 [NSM\33y! eZ0]λPU{tu{s#L H|BYޏxukǿ7\k{_}^? <~}OȭLwoeosS~/}ѵ_y^w}Ti{L pŜ|-9]ǎR98|:.C&t 7=}n{Mzux_K&d 5oOͨƣѨvݞ}׶]lU!{H@zũ'ǿ;{k*-7_$}wUZL9{sTT KQ@QDK b)Tt$t$sffǚ9Qx>'̙Z׈]QT)D)k bRtG@S?碃߲g?tK7?qo_, *}=(m,=7ǬA/S[(&K~z᷏iZsy+mfއ2'%Eh?{ *cdIRĚȄYV{9qd(AE*H o$"F3|iYvK|k۟u 7y _ǘ䈟\{+v|W֙nw[<{G<,|1gyY}'q|{O꘳a_GN\^;_|q_LJI/|`K@ɤVl'b&s IDATNsӎ=O Wtܹ?,5ƾޭJ(@4R!؝<QiXk}*%6|#^Z:^_#{{:vb DQG6yQZ)FTL+:#Q KITBkQh#/#T*x/}u𞈴Vz1%|`l6NSZ󔣾re}l>c܃uν@+sEAU.>I|{۠.Wg7s^>tp5C_u}lq){uʬҾ7;z~]COG?>=6VGΙs<󮅫my9=_0Md84a24-,K_y4626`jE+<YNQYk01jT]6V$ÂZH%=3KZiGB~F"aT}wZg~k@jPܻщdq`7MktP¡p>!wYΩӦvv,rMbh6ƚ(֬V612ܚM.VN5ttt[hQf`խIMxkZ MX5ژ]8:j}=Τtk=]*(UOSȞ\3kO.[fj͢7;UW2mi>eڪS:m77[x wדO>xX5ț55*_z?/?WxKzc^q2ύ˯?1^oLx\ _Zxq }u{t#yஙJ+4Z=ƽO =̳?QvqY_4@ADJgsW~;Yc5X≗My`$4Q$oQ7jޓg}yj6&3|eK_zKgw/;Yl5VjYPeKwC=ܕzOgWwwO___V]olޟJ|ȼ']o~}loNVـ2JwGW^} Q!0+.mwU ?q<(]ᆃgaBOacuuNDQ_aE܋wbC>{1cbV?-}N9W.,@SLҚN.'8n ӏ!Pi\\y}iQsj o./{` (B>*d䤖:jI-2D!jm8NHA׏sqѷl;$_8<˯:u84EEQHkD;#<’wtMc;̘~Og Grmgl{bbx'y3?ađ]y9Gaw8mRMbм5;X6ܼџL'~1op͸a]16Mi qDib[Ԡ%9PkAΌZʵ%T{"Jl_TI6IlH>hrHRjGKM(?es7p ԈJv$l&H*q|gQsԨzGqTD6Ni|锬jҢ8 >@hdNQّiZ%i-bYZ=sI⤍#IZ%OYV(lhPr+y;Akf)E^8/ģ>S DZoooOO*Ux_8Zkc1:w@Z&FO(wttwtדzZL;kiQM6&_ C96mUVY{^}76e`Wwё]Ȝk#KG,]:167&Mܕ !GPZ]hL6Vp 㨫+IbD4MXR+>uyYq Ty9mV{ڂ'`˖)Įή8'[hլ띝]8PO:v,Yp[7H? ~^lYo==z\=_2ty?S+y+3xY^x2Yl ? /֞ݏPIW|)or}xqwn{m[ /*}ZsO'fӮR8Gx7 b(a}W"@1.ڧ~z\=!x7);do:vʨ#N8j'djv fQ=s'^qũĻ9>t3u>y.gns ~0ynsϹhƍۜ(S1~x4P:Z+.l@L~t/&o[.@VF~k/(v0ŵ}ȭ7t^}`rM6gsELd`J)FPX`퀧'0kSwv`+!xͧ/ ^`4X"I[/\ZZb"Ci#DK"s0~j/s!A3鱗Z/ݿ++~aߵk=YY].:scwC*`fk iFbG;l;0J>?1;yև婿M%@2H/scOh (]kѡWXp8|E_.N:XWxӷ6Xb\eի`MG 'N[tKCpi-0+Igg*`_vI;lPp%AA';7F\dF$jcFj4Y{ϟW4f #}å?/6K=KHo_>>D8hKP<(,VvzU/9fye1U/|`8xgpe(;gŠU/>wGcӘC[WwA)Xb ƃY0 U֪_eX,x>0h F8b5}d@>]7go·3oA)ٗ,l fkq}OG/7qϔXh'ξ乖';/;69VW}銹;M䀬2$8h}! Yhõ2#^)Ń'}ŇDԀUp!g|f|Q)E_9W~[[N_I+Mz{%!FEn6wCZX6`y![xU/儠>omlʻ* åQiFĬ(Wb.pr&9P̪8 yQ,G҂CVZG6Rh]VQ·F+#Rh jެ!fT'Ie o5ڌ@@ X\щ޻eyV9d~MQmlg^b"Od @mm{DQ ,7[bf Ba{_6qv!c*Huv6d#ih4ZY :;1ZĹ jC|;,Q,yj7džG8(f:{;;;Q2^i v Vs1൅P(8 Q tȇ Ye,>(ZGōeD(6 fȠv 7(LkbK."e޴fZRRM+>=iWgoWW_dOhE*ߊZ ׾MC?f'\w/7~xwwD_kpG&IN#[ZEDqo PfHj&SEEg2:󳴵QzT,4cʂ=(xO'\ޥ(iZǻ:稝οL*xhj5s=E$xZ~ۻ7#ruR+%dcRqRDi#%·*w 7='Y"kc ^ u[{%ܐ5:9ml uv x૮}.@EK?RuJ)=Mfqƾ2[̌M3)ڮj.(Z}S[n_u#6ꃍ.yh;羇nZݳ^\"nWsjK[`GG Y͡_h[-='=Ĺ{߿g/Z{Y0 c6ܻbj6nXg=L[{^P,3dɲ$ Y ,@aqHv *ZTXJ/̻ < mҸl}Nz6yB>ܣ>mw>2rQo~Kݶ! hy_N>| Wl]8 xO>seBlmgW=>WZFmeO9=oLkJiymN.\wK$Eօ)зu1yPsusjF޷~6[m, IDAT<' د>*0^Z^L 96]F{˧[KGT/mS2 #@;gKoPr4c`%r H"JJ.͜gTOdw\ŘBR`t/!+A&.EeUZY ?b1-EO2 m InkUR{9ˣBEj9Pn!I`s^dQ DDGPƫ2je(Nbm v*S-PRR6: JKQp$0_i6H#*Z) M*CXu{>Z}JL8V2T{ThCwi9Qb GBЪ$FPf({FDo RPC ]P2B4JXVB?[""($&2"ƿN%cc5SjZT@ql45:L UcV6JshA^KW]m(NsY+BcV굤#c#˖đ4XpQ16lqhTޑ&)4Mqֈ=qbɱ(҈6ZQ_1eV{Hlqԁɬ1xcfVXNI;j5k "7Xd)!iыiOhCE+f+؁O:oo~W?A|L{7;Q^W^DVJʌ\_lFp%Wq5\|Ed.teg5|)=6eݝvwf}LJSNge0s'gMTrYvξ꒟]#O4i` w='<9wtwrύM]=ݭ'Wz=/}c/ uG|Hu㜛.s}Gξ贈}nqITKN?Noҁ{9s ARgEImdԛ~vƉyCό e˃O֓v}O?_O-]k˙'o{{x*v8'.W.Ue0ʂW+Eqj2h]e2J"e($#EXu*m+1CvDP+eA5Qd Få /Ϝ9ğ66(J2!pU" RaۢJ1Qa"*rD$;.>!(9  @ IXAQ^xkc,W f#*1I$=hc4ݥVnGcyx]!Fq3C_w.3Q[|#ͫt4}a}YΉOǟyh3GNo5xMι7w5I{׮鏯59941;h{Z] qx,' b#]pQZ??fبDJ+J^=|q{S36_s|V #ΖCuG|z^|ysimV}^'WZpͅ|˶|צ pmηM&$>L"Jig֞9x?sUg_]ukovF묞0“'f`=99p3v=91uUvOnۭ9cr7]r?9G!lrP+r0 #==]4Q ]Ѣ ϲtY/_{u6x͛717ZH8{{tZAgmdDZ;zx-6 >Q1q^F3ToMP6-ˑ~%PX%}J%$$2+ŅN(HE1x6Ikwމx ◉LyQ8=*E֒G%|Z˅FUμJkU9%"WA,+/.*URhJc; ./>xoi40;|iB|epYE$LXע8Z+T͌K'dbw> Ē(,0MkIjmATaA$m;WJ|2ƈ23 c*#J,R/"$qZ+DWz"r_i$%\%D >"^Ba2$B[AAI1cQ TIUH ֬+x3;©"cx%iDUXJb+8p&BqLj '!_帊 (T(s@ER 8׍5P >"2űf;ߎ#ʹE!rο, ĉG**70$@j$F!HVJw L]u@.D;fB е҇.GJ,sPr_Վ.q m{)\uRVk]zܖUDIĐUԩ3Xբ8Z[h"~6TүG1QDՙ2S%K$ȋjˑ[[ r &gh߸KGa, Q`JkM 95&'' 93[P9VVGTDI7٩EmWRj %3RɕK)u*CML4J"%(VJ#`D+sS%PU/m(&IIP$A2 $Q}9!x3@9AȇE6`RdT t1}QT D,`馐e"@XٕER#"Wc+w)%䭕zDY! ;SZ2P6)?%E{q)CGTZq$]+'X۠VۊJZitͩ,TWWLw.D $<.MNN !X"lFQ`PQ6,LCڎ#,˯XK,!Z0gPgSk{ h#kQʖHR=0RbCHX=BA$zO3@5q$"?f ܀Փ9FM&n ۪j!P[m#֒2}3x _帱djE'|eTk`)E,+r&岢Q1fSbmQr lW.eٲ@(8Z-\Ȗ5ppNnB4Ve` )˭eiC D$֚hPne0*\ki`7(4ȁ}F>&&F"+|M54k 1%q-2) gVCB"]5"6UJ;cZf ǵ(e|tbt9ڛ%u˘2Nu(H!ZчV'a'Mtߛvu֒+JZ3IlWg##k,0K6lcd Qd*;YԺ;L,%XuԑeLwo_WW!kiH7&LJ.F=Ë>=96 S(s"/*e*QFGݱܖ @*WGkRS20JZ8n<cZ 'eXp·4I<m+s7tѦFl1-FQjZF( Q#"Rxi2>0$bkT2^Ae% QtG nmۖGѶJtRhtYȺpɕ5+32B@!2]乧q&iJV$|YB]Oʆ͇@!B!.j*XV(QeTV B UQ9(||>c VGRB.*PA0F;ub PhcpA OlT擈Pe,@bB@hպ(2-W%s(;0 Al[ZD0ژ)Y`U@Ȋ#ZRmseJDI.ϳF+OI}\!6hf0idј(:ON8IӚV)ӕvt;zmdzZKYt5 y…K-:k,R5ByU@oٚlNNfnYkd&IԢCIg_<\Z-55DVwkI-]:,+rFdYF4?!#ۿ ;v#Yzm{'4NF[c(Xk~ig%7Ih$C%4+RoBTFZ$C 'O~@@D(<$=p?>9puT*P% 5jmT1;Ԙ֓(ԶDвoVBބZ  >}(e7Q lNAx@L-,DBog@~9ETmEP < ]U#bꚘ" AsJ(250x2^h|$)s  X'FZv JܫEޗ0$QSɀPVI=A *)UEmgh4jT #pUj+0S  ` hg#Q+D,5%0jea%Uڎ?!h!$I> i@?}w%U9[U/t IwgB@` 0d9`XEPª( sᥪsu!ԇ?x_9ln-Q X[0BY!xLbAN0*DZ$_FS?YeYSg@α"; x 8Bj-xT;#"24IA"yE9֥9sId'L*%5{$TZ$1`cF%V!uYVBw[²(w0r)mw$CĥX6|p>Dw7"D`G!w[pZjNj ei&M ʻ7Nfi;g1jE%- >~Y|@"c40AVD j> IDATh(-|d"K;uՎ DJ2c"BTaS:;dJJ+ݻ(mMDçATe(1I ]Uӈ@4jQȸ,^K(F-\ 眴r 93FCF:V9Pdbog*8!XlVIBzzuڱɩvj7׌_V RtZ3m*Yϋ`و(3#!BsQ >00p`fpE8Cjk#`Y [gs;ʠE& qc`N=> " !8ucFRH@!4]V:140!8퐒'U.0J =aUt$Gh4 HLiP b]D ^5iBZz/j.m!PZihcLJ1]}gqfR"-BG B(`mjUQ R]++$Fy[JPWтw&c=O7}MY^(TvlEsB$j>E PyAәd`sg=aJGI NM8 D[SdkS޻N >uJFX՞X;12g]Eѵ CcLH";.X\TJCmŭy[g$jz!u6T+h[TAcwY`a>8kerH-hr&B80)$i(p.q#Ɂ$)ȅx +"0&W}K3"pGLƼg¦!r};02 DK#-ejT%Eȑ./lQH&MJXvy?M'Ǯ2DJ(vv `:mf6[]%=x+{i!(s:]z "LR X!BU"TF+:y'/ \Jċtgy!F72R҉RBUZ',3ﬓ&( fɋjVw/$gVy9gz|#g#Y7'&;yJVet%URD (k)mLcjդZJN*H0-{_;flh7\t hǧ&I a٘*9BL :A#j*_;>'T}}zV0-|%I2{hYm (vLRxɧϺ| O{n !u_ Z}+}£?~vgbS|{Y'UV9Ą9q,/0$h(GA%4A`Dc'0@X ;-f{A e].T,Z!,~JQ!iMf;śh!B;(A؏%#"4R0?Wr|ޕ,- 7L:("K "i:`M!i}t1IR"oUy"\e >0[UWRT@PVژ4IT$}(.gɛ y;fX)4FTuκb'#8CTU&-8I ؑyZZ{ ;v^E/'HUkYi IT΍QP.?tk^V:M6jBD JVDtgXݔ ("]y}Ԉī'2RB) Kmme` H!E.qB n-Z8\X߉6$Ӣ<"1Cg}Ѱ֔UR9yfvBtdABH)-_Ũ蓞GW8~f>#$FE<{oºB+Pf" R Vbi}@{ r\#DRkΗn! 3Rqư9\!\^DTI/4<T_EY dGQJQT^BRaZ[Dπх{w:.BPJ+hm넘S`/rn(nAbtMJ򰢮]A3*R?Ĩ45I(R.n)wb^dl"Dk$ 9kvǹ( @1q:}!"q$1i&uN TJ$)sU+V70` ys  HLY9R(YY)49ODiF4Gaf,O"C5ZxɁDع0ڶҿWhyBrC,KMR R:)ZNJ+%K? V;EfDY 1nwu?<5P4)\Y~J8.FJ%!8WsN)26FkyPEDFӬTGZ 9fJlpIԀwaFJgf(,5JMe3!3$؁JHp.3o\Ze 7(t$.Sbl9((/gZ`;炓ȓ$•$ F"arے!2F(/Ly2 s\T muFDVDWK}l2)HVů(YF';&TcIx VU*ýgG )u֬ҴVVJ{πi6X" !퉉IM&R鴦#c!8*Cd0&@tJ%Wz}JbߜzRJfR)].l^XͤlPɔ9:sX;1vb|lZ$51>ɉfsȝ=!x[6JOmoc=:5h7 wVVIf&091-ڭv̲4MĨ,MpyM fSϝ7"OQ;>yFEsZmg= ?Gsd>5|u%m:[)tFE ,I$M2B gοGnXqO.:A Rو"siJkl T#̜ms _߸ֻc$&LBzEݩքC !ӥXZ'PeȗJG qy^X1FIh8'\cW[p>b^;m:;+qƹctn>Q=lQG&Vw7O_?1u{x]67ӿ{)%G}⽛7/Â^3f&VӋO>7# wU)ݸPR8I o޺( 1);PJekLq[R&M::0J٦Y.3ң(%x|pg'JcY&aQ/:xϝN ?˾tѕ;wX83k}ݢJ]>k`ι_>pgjC|ܳv}ÞG67O6>l|pM{'Vwŧ_ہ~ z&W?xYWx];g?#2ZQR@>$I,KaE@a}w9 49xDlǬ#$Pe qD0쫐ʈ`yiEC8w.XkmUDı [DHJh@0Ұ|_TV5=CےJ b0wXrI6nQ$q`+ 4Mi_Z:zJ,NB 1c)ecUsc]Sk(FI7gxǰEn<,pLr%Ksbƀ&RmVG{%r._U.讙m5hdw60I i7 щON8" [vmm+odDnι"/ڮ9k6wc(Te$ ) J?h5FitzƈS|   ;o 7Yf?` ̝7=ۿzG{lU+]+laT$5R][ybjmUlzzbtQhc>\ϙ[_՚lMahWL)]ҵ fۓ\O~~]-]szG==[VSJ  2ՊN9g9G*кhww[N`?k唯rͣ:I"m^FB( "8bDx""Ue_{m|Jw+-@T@QhsEKѠ"΅uDI%VOO~'<)kX[EDBȭ%'AɹsށRpMǝX1gmOƗ_j* .B|Ӊ_ƒyoz[N?So[S]sx^tCV n{W?OF7|ۏ?&w:?̏-8}n~`to8>K8<5OK}{Gfoc^p۟m= :`7.—=Ù7 >^uܗ/<ᷝ|п,.߹rޖrE_;w5ZǠiܮ g!ڽu96yMaE'"1њ"YYr38#(Uj"SEf`NQE&i#%kIW7gKBo >0h]ÿsͶ9Kv=i=hlۜs|xsfh#OFZտk9}7r|#<糏}༛GvltܢxH&=j׎x4mMb]z922 kK5f %f>_0`Yi2FkJ,fuRȥVxڴ8j51>=XY r=Y @B(b } p!4KRQ q( i5jEdBrb''WJDْ]#/-͸s!Ზrz"$Qn1to3N7E$ڝdnu|7t۟oȌGgͪEUW;w :Ijq#Uf]l9Ǻ;{ S8U$JVMZ{slӭfax#&4/7h)lzc=џxΟ4;{y_cq=;ݱ 6"Snjv~?i[n6;tӍ*1 o>g]i6["Yx IDATNqLےzZQxm|c Lrǭmk;FsbblEBdI$Mxv3\ۗS9ZoVHmƾ~%wҊ1e)-liW^^yGEaO Y_n[]{ßo?֎ y[x(rWt~+{-<PM&I"Q<3h4KŪ[EEa4MzooO^ϲ:wYO>y/o{Sᮧ!mhS'r>?uncvGsYv;^{#i5zӖ\oL!1aս?k޾̸~~Ēݽ*/e^ѻs̎,> `GϏXۻ:Gn|ޫ4;߳yQk==i)SllQ8sMϿ^a\zcllh6wyT%I2cR|d޷PU*3]%_:5(lwKv=_O/}ZRJ^f-x8Usػ4 DNXR^+2# *hn|`Fq]hs񓓶Gʨ}'*AD;/>{VۭGn_ϽjmWxon{i.GpGmWx573՜\~,GSz;yI7޷:/Tw?r_}Mɭ}8fUo_nCqK~謁=wУ Uw_Cz>tk9ww(l,jwXE 1{ZKZBp΂%18; l=`i>/x3K$6BRYh1Fs! I#pFQd5+$BffYr|A^0(Ydi$ZrJ@\_щIddZ'J'JZ'JY 3$n@ q`TJ$YB90ie*BPFfFro &4{і"K!A|׬"JJ?D\nM2ỎSцG+}]^27 7FgYZU 33NjBѤpMJX(0q6ZLNR르Y3gެYzz{Jhث`1Й,&L,/w?ϯtZ*owC‘e aQ37gٳgWVX\"dmQ/+dcbj BZMW{zC>8}^ wH!njYSj$κի;*=>`ULN6foFkW^dL)ZY$ggj626U*]*[N4&'fժYfOVyάE\~g?ΧE7gzc=z2L1)~g~~e]>G<ޱǯ]ggu=ٍzdO6Zh/{WT6Ke{Ip@G $tBS,aD"do[L"q>fY$$F!Ea/h . M9ׯ2h@~$ױ/[~{:ƳąNA8`osY|ϟW8M1~-'[[gc{e<QTmw7[* zgeUUH;/W.󳾽[ߺ]Cg7P)NkZm.mkBƒ{VRwU^EBd9ius*G=NL 20r=k9D]WU~` s` }N*7fZՁK@JHy_@wOD)DJGAc/;dw?2Uo7k]͛kWWq_l im1-#o#/ڑ~? -н/Ӿv{ g˧5j3MJO9Mtk顄 g׏_7(w"wQ~nv}cy[8/^S?8]{Z1s*>0.@4fi h~ܥywf.{Q7.anȇ ^S2+~uǹ5b _yxE2r*U~T}!_an0TneRE`H6&1]EiT:{Ybٵ%4WVmBMMiH 1|Dgdc6^CJ;I\RRC:WWΘ5B-L002LtAYN`Ik譵zdbTB'];-|88gAث*+Jᡛ*F@Rn`9QHюI](i&w3 6rn!jР#`oHF*?1+fα6B`T#I30(C`Q'U?fZ׫I+:ISrZVnb}]5jW<]73Ξ3SAM J6&M+JI"Ѱn73EmzF58u7z~YZ w친Sub<῟u=ǟ)??֘j!msvH[)ʗu {:뜷䘯lyַ*Z 5%f" l wWudH4W4 .2\6 RGqoZ3y!)S_ė?a5D'B?#)%(@H*u[ȥO;"HnjuX{7oޱ':9oe_y7@Z+fD֚{yk_EK6i&)be/0G;NIK>rl(d>}w9kV8ݯ]l Yt0Uc.+ǜ%Xd> z{ÿx9 LFjhڲdҊ[k/MJ)ë_[J{xś>uE\x؁:Di9Kn#r:SY=Kd~ܗĆSROA^sM+.tFTAûAh]9+VBʜgh p/]t.d2,yœ?˪Q|F6 $gFHx/kG "Ҁ3s]zy{9ƑB"NCH1M}K]بN8 qIF,8lI XPiXK3̀sABVG% bݞ&jYKjq`@fD9T)@,O@ ՂE(8b$:!)-'!xnhc@f鴻ϘV!$ǧ wrqlUT@by);i *? ,|8r MƮq.{h;+"|mtҩ/*PQp̼9j) ރwgȄ#WI %)l1.zu+lp6naj''&vvfٳj788/f P6ϋ<B(&!18X!Rsf6J!̌ѻUSY9Th蚘8%&Q\'o7Sy1)yUkJ4Kj=95vܷ[s>NٜBm=sΛ5kgA\{vd|<`ݚ3 PS¶LY?gV_݂gw럠'/l/l}U=wm3I6 W\KR ̮'] &j&PXmLN*a6LV @Bʠ*X⹙37gW]R+ By^4[؅{}dY)E(QDݠPiT!Y'?l5ka9% {2#;)TGu?I;m.=p'6[78J) cAFF)Ri6ϭ󶰅F)%$ ߣ_߄w( }Rd.ؒ7/sh2ѤWay4'8g C_]2XgpRjϦNچϞ$;b=bzyp}AkMA!a>O?Ę0amaKc?31*8H4lޢ83TjU- Ū~U槴Nͪ2]B|#" 4 >2Hq. NM'G&nXqR;\Rƈ!VdLBH6lT<̗.:{Oj~ö(|ͻ{vVA lODNknw:#6 efRt`GHW΢͆P̋"?lJ6 vm uƨt`W۝E;L `v>lW:^l"RaZ,K9)/!y!Q19sR#$F*wK,t2q `I,jT@"2%KEK N.ʬ9.峋]F:#b]hne\Oc?p`X'$B A>8Ɨ"b"ct@#\z۞̌'%61^l"O'B. 23n2J,]:JQץ)FtIREs!@fFw!5E*lܹCZ'}V1MuSWڝN?fKz|E^96Dni; ];^8睳Z&y'׸=Z۝IJ_ 6/V?i}x3`0B[×ys`VZi*qy!pL]+#1xZs`ӟo[_k$1R?L!U}kh6_?8Nd6[-gAj%"'z}m>Jcohkw:DHJ%:` Ql>/#m|՗T=o9wK2xOc 1ifӭW iߙ 푟y7rE`\m+RWii勺He=k×;mh٧޹Mjwǣ^ 5-P{&uU A `(9 `ya 8 vhLD$j=z=ISmtjtV֪Ij}vi3"a9,:ar"dIQYf9)J3ZkN8dP 5^bJOe{t7yU+zn]]JnpM_Wv-T*LsBB&C6SW)ڭ+{; <Տ/-Wj9+[CFmZ(zme־:N<<+K^q?WK?C󪉮~]}V_>9fZnIVv<7hЋ|ҝ:G>Tw{-$=8mGJZ8ǤY%K,dY%K4lWUx+~/}KobqمCG$:sXsz>ri\qVZlիGG ZLMMER?4q_tΘ)i7vŦ 7df l`co ֔$Zi$1 b76ڬ[nWMu+N'sg(zv:췼d,I7x[{~ve'\ujmei;*9;}ƛ_0Qz;jp9߸|-x;\u;y3yo>Ӯ̓߼FYǝOvϷ?m_>'^ޙRT~UUݽsΝdtM4MA ^F4&# IDATQO$3FED&')h4gbh2sӹggZk?x$sgսk﷾>3>|sCt፟.\,eٷ ,eF ML'+}!jJӌ",sp8Tl<>W~i BLٗ[Fe1_zdk߹kß³! >4&MS , ˞S6TXc1Β% $2G귏}o?}#= :1Zg§^ʣl^ǜ|cxg^o~qo~駟p_-;vO7{=6{?s}•^מGe|d:Y>^q7Ueq~[^==)7vOxS?s^{̽dy|/:{|ͽ~y?5g%~U?G(,=?>c9_:Sp𜯛C:}O:k6{7Y"D}4uԍo|;mį$* :RW(S?!pw1FY8H <' hk}mL$s.)5"Jkd-*d2^ZYYD%rJ;VO)y3!Wq[Rpi=cM]O'S4c>S",1Qΰ\DƵQ%ʼnO뙙SknMr>Ŝ$6{N/ʈj :Keas.XPTȩ-EUR- UU5Hƚ*^UWPYe6g?ʬ1JƠ1ЈAk<Ƃ+7(7n031dӚ&NV& ;\ؽ86oK7Oxܟ+u+KWsFk? Ϯ ~I+Kы! 啅 ӕ a$I5o_{?onݼepP %qp8ᆣon=7߸eÖojWf Ad2+˓emk 14Uu֭ۊe{W?X_)OsM KKl:vpH_wI~1w{O|/s> WMY Uz㫞{ǏVGSUQTI&+)?E_||}i1 }ٟxnO?&tfUo{i%%( sEQd 6]C1JYgmJZ2B" }~/s7Z媋7|mgQO~MY;gƏi4ϿۛOgo4٭|/{sN|^y4O_3&Uv)+_eO7}}1󛧽/9|æ?gȘ/>%}޸eʿ{]ev~u/yƏeϿ޸pe,񈌵R%hK{8ZCiI¹3os܍z'nm~ W&H@Q3>z;Η>VyS׍_<~"mB>%@\]x[JSjQ!%RiѰMsX#qKO{ͣk>¹{Y_pvqy^؇<]^^};?go3~W˲嫧oO[Fۮy{o:iO™_AD;W]go.oѧ?ጯnЛu/;Cn-o=՗ެ7}%yk^~23q]#˯}?== n3OY_,p$D\U sRD%ls\ɢS;BWSdW,BMz,"fn{* Ru_mFeh߲-V pTA`M6VE$scڹm2J@ETwh2/KJoYWLYChd=Ulw#E.QQ *؊J[B4YL [ze[LzW|QC;vnߺ9۫Ikťʄȹ2!*˲({`o˖ug{"%x= 6fiqq2Y z`{aF OCS^bLe sO{@Y;w9:m޴a˦ktUϮ8I(l&fܠ7U!@YVp~oEga<^nҘ^e(deROb,KW8kQuc |~ E[4Ug"zAq"Q""JJRan#TğH1 aIJjJ3i hayjAZ)DDPESlʈ1FF Bk rjf8en D.[ꌑ% $† YCN( !&V|+1F^19 "‘%!WBim?,Xc"Kj0#""HDPc7"RH#7vN !tZU* ɡZeQȜD#w@km9d:Eg]Y"⽏IAc m[*p:",t؝&VNg agƒh,M'9 rSyd(\Cvpuڝ@5=JQE(sT&G4֨$5XTy2CeY sYbY"sE4zާc, ks>$X؈)ɠSF >UtDScd*LHO0 k2(*H c% j4j9XӨ3mGbۭ49软Rc_Qbf֐$- S!{9]R/hסVM5G"H#XPm]MTH䄅BRT  \[2asT kJS…c ̢ ŶQNUVoV|SHJ+ސ5ȼ*ZŶB]H` $Eٱ[)N7VVTX@/B/,ћ?Lge!@:s rwZP*R]E4Db>)ʝK٭nK;W9I5[vLxq~aN~ >x$X7;;y8F䗖8% ӵ1(jH(P@cvqmoh4QXȐ*2DUӱGEȴK^``Cd-KT muG /ciA{dRN9QH`Ɗ4o1&z\VEUEYjL#cU\d5  >xuZ`QA(̆)DeMC {puUTդINk'̑>DT!$RE@,QGĪ1Q3|VSl12vM0uPF(([o b2ɢbjC@wL('FՖpLUIb"Ndwumi6w/U%U&|voتs$cYM ]f2Eo R0D*9&غE4*)9D*RgSHD)Uas DD v``H}ƶ H=zKu(\ZSA؛.zĦ.3[6t6sΐEJ=Y,-,UWJU^^/-.k{MoЫֹ0d 0EaP9o6qq_ibi]//ڇ]@Mc Kݻ ٙa:] pMww}W \Q p4wG~aUuM>4f6qӖegà 1\鬳t0 ӕX7a1 qn۟i{:{{3IcnMr;xs/}{ս9;RFp糺oG~?.r>:6z*طcun~6$cFck\Dc|5&Pc WL2P EQEa HMXcUCud $C$鈆@DfN'jȠ1Y]q?IEpr̤QC12G <$4dc"F3(987jaX9k]fŌVsTX4 ! dUIo q9:}PaX"+h43u>D@eNM+%8|:1f9GMKzH $Sǔ1}=sY±IOKtco!bRFJ!%(SXj)Elh}12z{B:Ġ"DRYVEY8(dQU@XMEYTS_ <=Y3DH20KTk0x\r؞! Ns<*+J km}nXkXU2biZoU HC1Ǧ]$R3'm1ݵ5"Ψj@bff]z27>F$\̰%'p((d,\Kk#%:Ri,!"aQ m;!Ǭ3G@gx&Yuob m/:QJ!QN`(H9k M|oޙy!Ɇ ZDj@sd[j۵TXc2ĺhέl]j/Rjru60fVE[IVն3:F*XJk/rNj\5k{S̓T*cʳ"s7XabP=mӑPvgC[@EVmYIfѶ= i1dORo+=;kWW/ԽmOB1oz\{^;SOrff@ȤC j:![$&H(,aHDc+EMSUMuH)oHنW851C,YRiJ\0 (0sxAª_UʧQ\2Ċj ]ju֩dK\cQBu==4Bj6)W"\8I?1lDaNLmYcq27Ι`0(*iDd hHBcLAH4DB *֚p!#hYL 1"Ҡwf9Ji@1v)oD䬵Yg]QVDAJ^ v}jOBD Bt)\ĈQs(U{_M49Ӯ\+l+K IDATcf$,.&c2 :W!͙sOBZP4pEO}iCK#Y1@J"`8bPU+ͦ;@qk+3f[dO Ic[HB`%5ֺLpcLa*,Zk AkIĘ"YSA!^:^-ruG"u'opN5aӰGPi:Rs=gBS$GY;m'Fشf!WC,BlCPR/z+bk@,YhEkؼkوҼʹiyuPH^k!amGuV۪}ƜN#Mi mhH}=ϳUjb}=4A8t2n?…pN4ʹ߯l`0,ʊQxNAĔ֐q@DQA5Jz17]wu8fGg_/--,/{=hK*c%^,۵kRac]̨?Ci&pThfo]+cUٸqp8( ՕzBhӦM8Bʤ^n>Y7na۶K@4r2oo?a/>?1ĺ;޹(~~WXS!bC=(&EYZkDgi4{"zUׯR8o|x/لvXl D8W:kN;jiHٲ, Wx߄"L&yB>ԾuK4Nta^"TȜȁj9rd 1%KK|lIyDCdoU69T%6 c0ɮ19S Ka(LUU~8Y@QXYtt (s}7q+pd'D$ls+B6ԝ#%(D%\)#ktgu4QɐTѦ^4CM b)9],':4Sh,cH(DJB-m'sR\bYkLʱWԙhSuȑ;t|Hq(NGrYgrzLVVi!3UJʹY7RdzRO&Q l0֚d6A$DQe XjY02a*" 4$J-UZ[50zA =!ԾDk5wI]bCPN\+ʷ-%HWɿZkIAD%, !H`4HH"zX" TMH;#c;g3*) KZBPPN= Q?܀9(_ڙa9u[*=%=ܵؖL&gsb[~uۚ"KU+ȩvmz;E]UHX6jwa^Eho %+m0֜jbdgwY)Xj'JV9"fIcn *>LV꛷5.,G`SZ(h8[ʒ?z,? 7x⤮s\1nL{Z5h>Ơe*Rزt%XC:cltiaRYVf7om8jjM"ZBYY^$As.u-)KF 1 ˛l*[H[lڏct:OjD]n]hd2Y\ZZaáwGUU㥅#Fs1MWt[<j훛ok_t<^2M}?"qݹܟBhϲ??cgk"k~zowݛ:ޜ}啻r{:riCc1`3"`k1duH~H _Od(ZyM2,r0h7 A3)dLFY8J jUWeCAwc1D㰃dtqEIqsLX>zp"z 7ysjhM@j0y: HIi͢H$+WTUQV`U= B Ȑ{`1 !|?lVN(l 7!Mp.(eP<䘣$w+Mu&YT3jBU7y~rȖVf'%*Hޢ1x5^JmpP%Cr֐#4*VR]2cԙ Z/CA"l04^$rJExDE9;xd)%2YCVE^^\LV"\TE1r^"o{OeUTU\Z @al~Q,cLAD5И!Đ } D@Rk+m|uKR#ChS 􊭿 v[:EVRXmH" LԩhlLB7"X jmb%BUT[ېs8[8k%BU߱qފ~3iotmW$h@'ׁ,p+Z8b[g~f\*,[. *>V׶ǵNĝ[uT>ot HV ˵Eq][v}#~4meOGkX̓}ZfYi;fJ*tԏֳ(C&wšV"I,idnjaqi}ŝK;m3fff8i4yv4;ր(jcJ[[P1K[4,UJ& n\Czi! f" 0Ckeͷtm+Bʒ{nٱsۗc sC{ȁ,޽8^/JTk-a*s׍bDn nfiV]\ZڵkʮV̐)WK+o:xceQ 9/-n߱xi|wrfC1mڬu'$H9m };;~dOe9vӽA:v }Pny㺃ߺq;={3mVgwPYN/9( cl" L=U%4Wl1@^o4c+DaRnhqSKU5;:;T$U9@5R "LӔIduD!GؤLWdbI4cָj_ `7h QU&1Gc Fhr9R|֒1"XU` eY2(9/ j!r!} HΨ${)j"K bAJaUgԋyEW-&75fpeڋNДDs#3kJ!MFeIrB: @ ʊ<䪔! nYj#2Q7h *By yNQȐ)&'C>d"t`PfD@!#@>C"*peLjj 5p>LUDEQ }$lYSu-ľ%fPEL=$b | !Hh-I5ia U9zFR (IIIQmHJ4늲 ")1d qL`U5Z~ֶ@U+ 3̀EM\XEQeQg1U=E$q+ݒ@Ir R3)w3$.v>m숽Ud6y @mMaӦlui'zknک_W kwU[[b*wpUWL."eM_%tK~Mh t *kзk]-rJ>'1鶴Aݣ ˑɞVM͚톭8Lynx~7):rq77SV=;ʡ) TV_OCH핵okivv(dyZ/f, D * \a6lKDu]+Kܹs~T88͌fG`<صQիʥ]^#~zZO'鴞~76߰{׍_8kz͎lUC I-"M/̋HW,wWv^Ѻ͛Xtay' X -՜xof}'>eg'{qަx<Ȗ9{sVEޙ#`{;+3ß~{ﯸx)T^ ~* %r) *Lfs!WguUUjQD&1$Oҷ7#dMJ,?sއq~AQU8N&`h zQކMG1h}i-EQ);`ZjuV|]" 4!@Za?kN|4p?W"1UuBG%DNXmk~17 ۮw}t>d!cV&/r<|\70^w>zY^c=/}.nwڛ>M!JG~%K"kmjAA3TOG/&iڐ**xf]5Z`i|cm}^/țE%'~K\ <%Tx'>-3KۮO_nȀ}?GۮEgCD3fUQPI1I,,cJL~t p)!(Kgq!eEhcfUY3ԚB<@D)YB:V:ԫpH>}2ܚmC`fngJMYhL+4fpIwڂyfCmj%IZͮU  8f\/e9YÓiMv%fɜRK@خej0ƺ!10 a'J5;U+BC`` !N~^]?g_}7 * MS%l} fa6syy?"<dm*56Ƅt΅oTxf |Wz߻a MoͽHA)uF| eUEi<CH^UVeRD L͊-N[mI<-s(\*@P6?e!/w)oyv_}|aDΕeBV ef7o] .8;'#|sB֚VJD|ӎO}³{۠v??픛̖K?<][sy˟Kuӽy;3mo=wnC_v[NuO>eWx|<'dNPm͓YBl\ AEiBP1"D8Db B9FZ Bk3Eˋ)"`i)+5ZI8igmĤf࣯ZU9M6!0B]r&*'0F6۶***,1SՎf H?-sjIp5PeZU[ouw+JZJYU$-3dtzc AaDi1(!Y}GNڴ&@_[/K 9 )#QDXc"*T /-@JXz^ЛvD\ uKZ:,/kDVEbie\};v*\CFeUD(=SǰaܺFsêd:޾m+ ֗ v d7rv\nvLvOwsGss3Kˋv,.zK+eU=Ǯ[~-.ܱ],ܫ̬އ@U9˓ ܰapvhi4MS7$FE4e\DY~kwogSq]}S[U_rCs]umy_pNNQ7lǽ#u}<ּSd*=q{> 8K~\a),+FN<ͮƉs$2eY__E}+ҷ's|<F+Gj;طoӧC]gd̒mvo]_w*ooO$xŸqfOw}dEA!WXKy؃/[?\9Mk|_Yrg+&Jz'=} > ?Z !ӿ\GEg|E ȍ1CJn:]mjLC? W̧aW_Wm.x/~ʹg S?OHp_cyf5?~"b!ĔoT*ї֋_68/׿sm ַGgDNF@|czıOg֝?Ou1UxY~y}wmUyWZ{3gfܹRE(KL4* UC) IDATޤ)%*co%;b+Hpi眽Z~όp!'>Μ{~g9f6l|%Gmx|y3 O?W_&I*K I,J l9%3rы${b"Y  ,VT[Bl HC^Uci]JЎ$|㛜5 Zl(\Q6ڈb6̖jam!&uKZW'Q2dL8,p~߃mù &UNfG3-^je*h6ڈ\m b;z`EˀIwJD0O(R")&~ދ$S1Ʒl?Vի_"8HmKS !#ccntD-]/V_v Ї "tm\aNqαe銲,ݢ(8n-Qbwvێ3Q (l7_ۛr(zQ_\DzNyfxz5ҰPKk5+VXw_\}ƍfӺ[MӐJWyf Rb||B]QKASa~f);]uaMA8WR]N޳ݳݳݳݳl)gW :Wzmz=_w~  ևW 3>ku_fCv׼Tqqq1"& ۺrUДoyؖ_{^tiW=p"Ƀv̬.?iJ Q!DI4?2ss}GWb;OqՍݞ}ϸ Oj~~~"|'oyKy8Jn˫"߸֧zzzeZ>+}]5\>g7|㪏Kx^E[*z'mx!}UR'03!2kܵ A\=I^zeuŞ'|[A}Uԝ:w³WwzoB!7^uqwGU}Cf!sſZW=9ǟrK!|N{HQk Q15YG1LT"QbE޴C_{ۥG@m#=S8u]hT`z䮿i'5:}򝺩ȩ{?כ^x{/ E,ң{g8- q uzwz?YV5&HL߻Ó 8֓nj\9rmeKV\W+g^~7Qx1\S_rAW^s3W*[^gV9{_s)#xx,Nq^s[r8A\Ĩ!VA<҅Wu:̱9K\w?gu[|71o>YvK~sB~rSI41٤d#h^K!Ԋj\ч}(Lirih* mPW[A,\Y.S*hL%&4FI%P"ĀdQWB6\.p S("̎"E# @DW[mi.QrT-X͠G7e/E%bZF-8gf#z!g=@ *$&P5{QWԿD8|㽏ыRιvwԥm4m KͧyHsZz:p=8sjtY5ū) p8 mZAdS:=`D HlU6T**tVE6.&MnU?&XE):k,4d!. 6o1J {?/23E+&{eCE͎_&u&l9bWLd몺52ƨa='}W&6HB7f:^ĸNob 4%BhFш ænGD댪t{'waSr=l0? Q5>056V v[^Ͽxǻ wyrp+BUg>qqͿW )|pb-<w Ch sD"uC.8Oܶix9Xb΃֔e$krs;~PK;UODN屯O~/;]a7}&YD7>`Ab?Oy[r^ H^}̅iaO8~ܗߑpAguw='z~ZFH+WMDQ zNNiǽHvcx~zL_箫B}˞l5%6O|E }q~N9}7/cf>q|-s^M]W1: sߞ෱tQ#yo<͊DIbYAvI:}kC;UkXg c#uݤF"i%M1ǿADZ8M(; `=Л/>sm2 YD9*s{n[>t o!xwR΋;(Xꯜ=v"^VTS7}윗v'{!{u Z"Ky_> 1(3UG MZ;󠋎|udW#ƍ'tqaE{`}Bp{^Ϲbj|WeaW:%/K gs׽hL֋jaǿ?=_46%+v;|깋ðҵs^wxO춽jK3ps}Un~gdTuI Hٿ'*ưu$q7K! IB *-4D5 7CXh\_(!ZFn׀%B/C#{4{D@Rʁ4uCD`@F| êvc֪1ffc+::;;?77 WF6u,|ma&0Ć .&aSfͪk5`q8à1֠!F6qƒhyxweDb12v7{r/mcnQ ;~[hG m'9kTtU7r~2b>#RU6#_&iw^;j86n\֤Oc*lrAgb.\nIy~n(!<Swt3tv5tŃs!yv/mZ& U:7H1;'[zv87$WH}yST,ok#$- P;XxA<>unO\׏|ұta$2`>t{ls_):cpUCZ/^icb Q=ǚ3үm\7ߩ:[,~.I Ęc<iŃ}|Į3D{_97kR2튈6[vTc++D\9I=켗S21ufy4B25Z_/O;t:pDL' ڥHl5D QL()t)Ts#l&ع`od2ڿ᳟YO^3o]{ԖJUqI:ukX>gcYxo~#ΰ&nٲiK[>!@=:=ּ lBPmמI/׺&nuU}OԮ7r7Q4ۊPU/㾾D@)i!H*7Z6l3B.YӒDIgq߀*ER03vVJI)`Z?%I1RJR]:|uSW!zBNas!n/kիmH,' BI3X.әP֒*emVX܈Ӧś e+mp[ʎj sz]60*1.9:.Qxr>( h֏*[e0!1%db mw#B0G鵏I;xK6%N4>ČE~nRղ&'Ǻ]g Fuqוe:c(>xhD4ԺM(*M۱NM+a}v˲vK4*S]OlԹ5>1!`؄oif0\az*@M>*b`:vbtUW1Bd1jF`^bD"1Iw}H299i[{M7τ5Q7ֽ;YuE5x74'S%Rs{N=g66~5/mxĸl-MaKeUN@ 8xθj ).l 3BT3ZYW_C蚙 y8|nf-&尮RX nQ%<~?C.Wϣ_}W~qTWUZvxs;(Dզ'>}i|go*goP_A[п̐,3Jz>vSޏ9`SDȿY> d8a<7r9*?wk{ U` ۭT30EJdck_]WM;ɹ 'U }scnfH-=?O| #SkM_<|\y^Vm!Eз ;>k73tz}}cD7!N7MSy !3{sBl*r@:H5@ru޹^=DC]Wuz.Tu?w^>h,v:(W^σWfݫwO7JTU~ˆ>vyNu hlbNNn[R c S{MAE"05&``IG^D&D4ȇ QZlJHYԫԦ]zP!bPI1jxRY4)( 3lj @LMb<7aK5' KC z/7u͛ph) >6ة} T̷#f6D,LvWMܲnU#1CTձn7>p]Wu4Mh3 7n^w˖MfWiǝw>lj6lL޴a(w9~O>w?sk;'yymmퟟܽ?A3{-UV^9iws;u؊֜;ik>]o>{Jw}w8{?-}|פםtXcO_œ?:O:c7;U~o;k_>Y;){-w#}a^9#QE#g~o;{3Ň\'U% Ld,:k]RD*~tĞGtFD&lRE\9TwΆE۬6`k}y^ey ^ F (mjTF{x ;?bW| 3o=/x3]]gA] ?jw{?UG\~#_w) >qGxOރꃟ[+{ԋ)Iӧ?k7NGQqY*RUc*&fgfUMOЧ?oCu4u~q9:[eףQ4slrP#dr哏{*$ѩI"Y8Cϧg}dVc~x9ihq?J1>~4,оnd\vW q4j:JԢ,El[J횹hr;˗q7>l_zӿר*qͳKg:"=t\uLf{< !ww+ B1uy/8aGo'zDxг9^#_xWIDӕ%]?xµ!NgqяrOn[}'t_;* Ⓩ桧~VGNسͧ}twapMY! ah#)ۍZN(CTrޔy򞈣\-!$HDUNd"#SOJ+M1h=ΣZVAH@@ idFWX)920*.UI E*<߰("I۾|hYufN$~&& )тxmsklv!g8(*HEp`oXFrI0.!`'1d]iらe F7]=p;j"$Xӭ4Q3( )wf䟫o4ErtQ ՗Ťjj@bdDMnO[03Cލ\ (""Md5s"MMSwaӓk}l3!@ ^cPP5 c(8`CFR@E:panf~n6J},kQe[. >(ߠtVYByJΒxlzcl`qq_,'';r˖Ņ]rSSxanֽVދ- Ekn sSpm3fjMg̉4hۮYݛض쬚ty7~X ,ݶm koZ븸}ܾp֪b?s>g+%[nw|,!?wn[s߅u8mûpܵښ;ޙwSp>.].rRNw&9 IDATnµ8y>g^NM|ci{o\W~{_UUw^x7Y5/.?@x8-oy߶º|La8vj@Q<9'e)KDM]MtvǟT3[l;戉 ak+L_r's| @S>pԽneg ^>Ɯ$8lDuq#O/.[h,Xi 2=,w|sm'7^rɕ ǜQ-_Z?Nz|XU~~>KzӵdUq%~ g]sK>f/`~إ ߰tKGϾ|5 {;NKdNE buiG^|S Ի\^WU!q m J5Eb>PUAD{eY2e̜OJ6 bk-3C~΃o3фfP$JzccC.W/we|;O|qjao>vё HS;h@S[4{wYD!Clٖ %!9n0=[FEEWU훆_?ϚōeoĨ{rF#>3O~0Nu셻찪|F?l|9.]@8;_o4+7w+X{`}}:Z5W?YI_~>]Ӫ^u~Q1-~q 5 ~w@L|#.=?|֚ |o'EQbQDQb 5l(]ĸe0 GGcyuÖ"(JդHsfssJed"6L@(j YgʲH=@c{R#r:6 ",yWsX&Ք^*860%v$Y4Gv$HRfnOU(եa"Yb:Dc^ "2J 3g?jZ[jC|Q*73z+0jI%E !Ä QB2PPQAP$͖T$f,5BHLSէ+r;`+؎! 4$ pVUxݬĘ6]0F?9[zDW(W;n4s[֮qL\jrrrDoݲ~^+˲`*'\P>J`b>2#!xɯyڛo^BtXSz젪 T N;ỵ>pꪫnZ{ [0 `m{3i~vΘ]{ml3T? 6|ȃjYwˆkMUNrd7\5߸qa~F)/R[P޵Vn5 [YD[?wL5s;:o!CJN] nSOSw׳qa[^G<Gc IH?Wȇ S i|]UêB,Ǻ]M?ݖiH( cLaqqqXUJHcsZeJUZk,nkĸ1f8bS1lZgy ٰ1$$ܿ bi `H`!"$dy@YY mTْ5r"Xg gL":6-nQ̆!p8ZE0ź1f|W*TհiPM[],QRB؈9@ۨ"b֔<bH1ERHA$(q*9c:Ί+\Qj]U-bn\nDdRˢl s*MRzQIϰI:rlLr2U\Qk rB!$y#95g PPB"bP `01EY, c jńD.Rft:ԍOcCh4u]Ң(+l'j~ɥHxƷ, ?)N鲱ERo[m>[s$4lRGR,Jhd FH *K۱c1D@"2XJfC@"mC sgOuSMNc9g1UĴյ"!|1sbFUb 1Nc2AȔn S1Trx+VO-IǟpfҠj1Ƥ7sB8ziBtCtT&Ծ ZִU(N2Xwe+N8jon/Ox+q,Tu]P n Zk;ݎrwK IDiMMkkQwiJ*"{[~&&a!b>(_8*eF$#*ɉɢFA?C BMqu3aWEihU fcmJBK𒦃>cHn߆FPͺW> -f7lYCS:l o|/mV޲ݵ80flje97p5}C~WN37j5?nVv@:c]倾 kW&WMXꫮa-`W69otxGzo[sYиʗ*Q>E pQb lEn" 1Vu훦n< 8\a-3͕ Ik;=Gs4Vj1DHY' *( (2 1A!ES3֊Dy Y4%KZ@[a3-4HOܶ20cpZkHD&F+Ϭ R&$8*j:kR=>0:[NC3sҺGQFbk8+ؼҕ{ODݱ1Fϩ!A Cާ5qb;sqCb+]i, 犂3))Ф"̒'Є QV"RC"eêČ#.i""l lNGFJ7xkTMdM3ySXK xh! " C& 2Q !;( bKSy )v l LuIc 1 bH9T)p!q ]midI[cvPl 30J/mb U%R_AZc -KVmId3`LĄQ AkﳛתE3[K 1) 4dLc(MlIbZ# ƶ6Xclێ*r%D@Q%oy Q hpF3}"2ȴLrtuI% Xu1s6Vu%ҜlKDlм "4H(QE(Kv!'̔Q%}UE 3Bb(B&$ NIDOWg"4Ud@F[g|TEhTUi`fc?"J񋋋"vǧVOC]7 ש`aqabcMP"ؘ `[M1#VdF$Zf527in\EMYY@0L,Ö_ڨrvMk٘;&Tݱ |uƛY;11L<66ĺiV"ҙ*E\t{+']c FKdv뗃weySbqszll%OZZG=w﬩uO4ai#Xd4|HS4RE)KW׍`n%`%\:h]\1ɺtRJU MԵ*ÝN)\QB]U{$,l1W33)c+"1ĦiR۽Zg(aѧ%G(q P"B-yO"lDXR>HiDlY㊂rb"At%qLLhY1ްeibH ( PE"DXgFL چwC>#_I3D= 9<|"" +T⩀Y4 AӺ/VuKEQeYޞLLpIL&D,QѠ)}X@!$yDdbD"3L)e:d d ? AD3QqDbe4R}2*1`k$8D dDJ/@  JƑ1=I7!-I#@ qe\:ew?֪QTCcQv"R0$$ɮfYF"& $hp1y$wYXNM]JT9 GZ&Pma0h֔ QcK9(DGyib$ڦROeC 1 TI5ڶ~ 3|0 (Vt~݆ٹ9c-\1bj6vp@bM&d\e` [Ǣa8n)n$o|*DdDp/J׵NiWY TrzU|zܝ/\X,+WOiB0PS+VZ=1#T[6l& 뮻6Fq\z͚NI)EvؘgAkb3ٴn~~om)n:ZM cw*w+mo}];۹^s6nn}s;[ ԝp֟ۼngHZvif,1qf ">xduc.y@dB;T-#'yX]"JG\D`81lvˢ:9Bs3b*ߒz$FU%SS^_fkA^1-9WvJl""$TLl2KO XTAZ)=o90痂Ә^oB$a2,q麊jNՔ6G~qqqq}ڢkFT[!' KaQbTQ%&2zbCHV/Ĝ%̐ izXUCX2a( c hS7UU&1 Ĩ|OL$LLt˲\ (%"% 8-6K Jزє`#FAbJ}&I1&2Р.@uDYrNXd$N:Qoj0 nRĥ@Pta5 [/1EOeUꨉsyl/1u&/Bi&Ġl%cH 1k 2AF4j^P4'R՘oٸmYbMI"\%ՀEI ,m h8?4*),ZHT%ƶU0]kfQ𓓑FXEG(!MEH_{Ѩ mZ=c *D:ji( ADXv Җe(;cccհAFcWLNLLvA`0;??[䊉nw@1quU]Ņٙ/-1:WQd- c7M]5GO}3ff CcU''h~vqMn٠zv~_o},1S7末jvn Xgu0_WLq|ff/,,,Un|qǝs 2l^ G's\0l"r/_r"%zCs)@TYe(qO|h^] 19$D`u:e",,-+;EDĺnP`ÄqQ[LZfUU'?i7#S!H㛦NF!)֚/ >vvqQ#uYED=Yk+uTDbr6LTM!%n[kYb?62e lP!M QU,Q$4ɽ&i } !8>BZhQz1F℁U!$_7Ur'Zg'&&RP^@TmcI3ye2$ !h֬V"y7#LJNjtW)7`I}Tl[͂1ĺ†N)m'A[ӺFaI۬|jsϊE$Hnŗ!{}7M%ـuXc9 ITæ*D}ĄḎ3("Q5F` rrr6rI%ɪ\CKx|e&bdGs = ƘVD2@l3 [%Ge*Z@n>`YkGSJMMJX\S&q ̽xYs*!DE"T? ef9iChe4ɚ%)x/fAT7zedMlumjoTťl764M A[5o,iTQE9KXZF13HD#;t>e|޺i9) OSfM- 9ز4N@[f%O{@D9LD#rI~,2@Ò^XcM y7yA'{ټqp8,LʲNMMuʲS1t˦-uU:V;ݱ!1f[v+_U`TC (lqsq07;ojomi3"P+ƷaX"Dg }F$~=6V>4河&3191֛q 7PUu5,,.__E79jꅅٍցI&䛰~ݺ"SWs>e)EQ|Dp'&'r }aRaE> Ul===$o)&cP `Ӳb!& #6a=&$bBۨ$j)EDb28k ŅRZccq&>僩]5*) in5qj'2H]jX%U3!CfTCD% m3(\Y,,,C1um;">@b*L HAE413j346ITokl-ukǠ<(+$aQ \Ƙ4~H4{w(DX2Ѩ"G_)3*IBU5HvVkLQtF(CǘfrhEEi|E1h,$!~ɑڹ(("%gH8c+0 @ffC "هC E4 9 * æe :Ψ0Cd{j@tE9gMcSj{!U IE $4Gދ!R)Vݺ^k9xwf IDATtU$91GŊw< e32)<$40[F%)3Off1RC* D2$*^~O03бٍ>:^+UT m ,wّ̕S_x`fqo*"9u nMl;ECLJMsB "K4pj[SQg,>*"Bm'yEj{VhLี"]GZ \@5~}6%:3PTwUH./O:e= *ֆЊ)63cP-ŏ3➺}goaqcWZ#R_d_A"Ȣ&Svwv/\Mդ:Ck&ӭc }GfCC狡[ڡcɬas'#ͥ(XLMJmlڦrJͭCnN:{< ak}o]l2!ɹREH.9𑣛[[RlPPR3:uAx\YJ@ΚGˋq:%Y`Dr_UbH)!b)w{{`(ĝ/_>"CL9H"]gwEWO&ӦiʘqaͬCJ 'Ċty13QuFxLFn SWyvŏΜٹM)QD2YTݡ5|5xQ98Uĭ4A}W8ufDYMA "s0GCk}78ȳ CiK^SbCK-@UJ1q@s/B:v .խ@c= E8h8̪BL/UuT%Kѡh1fb1958H!7-C`V*i)fPDwЋ!AJ)\1dZ}}6q"XcɔL(Dnr1@jc! LȐj!b "K8< I)DH^VXB2 R rHiR*q}@ !r>$\a(".Z'%bBDUUW9K35, Z RĉdiuJeR ZA,EF`: (#Bdg'Hu̕|XuB&@6EF4?nl+1qb(PB2)y? ]&XR̕qP]Kt+6 HHqЛNjR}#iYƛ4>lJcF32MQئPrq x)?@= -غF} \O_KJ." AHǁr;ĸ)Q†Xڟ!Bq/ #G  MW)FaҬv}4S!D B2luesmΝN>Ek:zj"հNVq_(24{;eX ,\צI osgo|# KI!9~5++mo5͓IѺ<\_,vvv35@fpӇ[]߸|1s q6 Cyw|\>._1f$BY <Z,|%@@:V-I!8뻮rѵI7vfcmcT|Mq^JL DnȬuR*8P0sj@$xVr`$ͱJ~(v0a8G:TCvQ 6 0]?D1N,8qBׯR c9g3Qќ#Q@"5;bcj|nk|ڿt4"dt 2gj'RP@Ȥ𸨬FLO/`ͨ8k9h1za"[UdԤwRd>VV( !{踇PGe|\%ՉL[9}$wᩩ,L,HfR8v:hfbL\z31vBl~&mzƘnV{BiRjGD2tYPJ\s[c8RRJ[b*FF ā>@n6]<=BH&ZWg^O0ay!1*)R( QKs~^gtXW v1욯>qGW]׿ů>><멯p)7{|/}NgV}C/%O&PɩjSV 5mub} !vUc)9qqêa0-RnɴI }u|%ٗjLMEQa 8T9!8%+@e3fn۶l3at>: tȹ:_{v4 "E9uGc{U̹,h(dDRcfÐ{B &)ŭi\߫ )e:j^uE4D*Lu%VP-X̜ڶAyRMjhf"JȌT5꙽@SVSjLдqٺY.6"4 )(!bJ)& " H!Ƙ##9קLEsɒkh*3 R oc n5ԢRB?cɵMՏkjV!  R$b3iсޥqM% Aof3\h Me@hfZе̲d-%E K cX6*WRј+-D0I^kW+gh/ݒdbUPq} _ocCM̀"#9k&4RlRjbL"s[P]K֓I/{e7)<C1{SY&L]NڙRBŜaJ0"n=u;8dք{pt{{iulToSO>{fXVMQ otءCgϜ1Hw; 4q;TJi6eg~|}W}*Q?oM5'cylsP򰻻SDLc![o*HtN 2 qATBhc!!-84\ bCeڶ1P"s6X"+c@\4{ˉ;v{_HfFDTr^,"f:5m~C9\T50&0sbojPW/'~ʋ5FT5U_GՅ,!yO:;&ʲD9,i@FFv&P)8#/ 9gJWҫUs ?>A(SzM`YF j)2 e*:|2 =b h6 h)ELChEcjbL!1\o+"›?h?t1&b#$*Eck+"3Ӥ\K)N# Ȏ(V5X}u`Vh]Boͪ{P7<ԁ T&2 -H~@eb@<;b0ԗ[b9^^ZNEnY6^Py뇪-m5L 9N P ıeP D163i}gdVbi#{} MK.>A2;kcu)&w_T 55~R!1"̅G302c@_)"yȒ6 vp}]&;gNo"PA"`MI;M8yb?]IWa6}A  (cZ㭇Q)R5!a(XC`!J]8}mDktڶ97&-~ >W]ytboԝd3|MvdD df]R@ȋН?} psec\]nqD1>5/7_y_g6O¿~۾%/ޓyC_(=z{}z*csۉӿ'x~^?_E. 7k"G3wwz>lf1,9__{ϟ?߿y=Ijz_=B{s~)OWo ~UYOx>vwi\%4)Dv` M N:ebufDC>7ЋT]A8ng Q|CsD1`屒 e"Wץ:Xnj*EK.0Hq|"2ҭab>ܡ'GeFyThg`6R>K"ّr)DX/B 1_V: @F6cRn;/Ow5L_n~?ܣR=^<_>+ؗ'ܘI;M&o_K??g&#~~ߺ|^o}}n8'?_ί7Mo?EkveuUC Bx+1yܯ7oyg]B@, yZ$W?[_z=eo|ٽ!W 9}~5oWƒ_g={?x㩍?'DxYO[e/[_έ_ݧ>7]Я}? oyO|ճ/G7}?~{ȻLZH ׂX{M@3 p2@5C:[P94H=jFRf$X\-QC ́S ыOL;}<_$_U5H 4hPH)C)fnRM5`ybm:MGv+"#VQeiUG6 j !x9L]6X)P[^b9Xc+B]|03UnP M EF˰A`b#U4Z/~..V1 ^'S83ZZv ;>炁oLU̪ՉC+hJ&ZvUm!.;Ru6 XM6\VO4JVjEA Mfޞ L2:4Q$}wwDtb>}#6x budѵl9n^^.16ͤm$@9~ řE֎;vGw;b7bhPfI9sXkZ9sҶIA$ptmD%/|4i2)9lڦM~ELD,}?+++:՟{4~1O>|1ͺ__S'|KDzM/ ?5݋uy |`IEp6D7z< g7禝zO~oɗ7czO tݙ~~g}>"7Vq?SJx݇;d IDAT~þяxs^rz֋<lǕw|lw=w{[n_+^앟n+Ḩo~{?3u<&}?KUW]uȃ+ 9g{ه=/ݼҵg}C_}.޻_3{+VWsśSʂ98cb@mAqXu"%z[f<;<詬Mފ`s_rMC`汆ЭZ2rjDT!眙i&ޥɅE9;SY bpUf.b u.W8>8v2)[??B*)#=QԘA}QA08x/G,T-ϧ")iD.@})}9n43I:35@=^MHpZ})F!0Yvj"^T|KF(|9*-YVTvH{cJNBeϚ!"j?G{;*}SX 1@ŀ!piSGуQDg$: .%g "9{:.yW쓧˓X,ts'^kn貁=G0"pW^_s[8e`ӽ|_|'s{wr%}-w &N)yTx"&jwvv+Yvʬ.iI;i'!ćNo_ĀXjb*J5͹jt*> Up+fnQ}(W0B q 5)ToT꧄bC`qL:8Wh\BL!AU2 "DR j(@Ej'12W׫" TD1*1סIʸ\!0b)P)5۩Q~١6rhJɭ"62rSTB6MID^JP5"/:XF&@PĔ]UBBӫ{6H"C`Hs f`z٭n>zc2hn3qQL, _RVr}GW#!0PT6(Ȓ{z0\|#{M |EdA@ J*?'.앰51m"(BK-Q [0qһth3*K=FZt}HC0"E\4#bġ\J1mFμJ.6 PŤF6RdEbT$C)Yeh1i*f S֞ͬn`){$ 1"#ru-:֞ecrm,*Lb#1 m&VGQo?qzawM}lsm@m1hFZ:K>~szg"14RJ;'Fw?M+"|I%0@}RBU&mZ _ C;[D>qog<9/!Dߠ6<_Lq$Z)\ʀMl&S!SG'.R$4D0VF' b0Ce^`xU ] 4% 9b0F"D%C,`DEJՔ!Ę!q8UJK5׋$D(]ײe8H[Dq@fqHP(QCT#xc4 h)Ƅjٲ3ͥ GN)Xι%;K80Wﮘjl"e1|^*a Ydo lXԂC0+XTdz1rR>0bQBw%"G#-)1L, 1#1JdUao{/t{40u}֭Cb?_]]92Cݽb^JA̡ a2nعsD4[Mv:"a-nbޤtk>v?f{gg>2ͦt2LW"wnLb~G#4.k.<4~:R~֥_lq|sݛ~?~W@vQ}'}{OO~E_OwO{~QLrVfo>៯^O||~ֳs!?jވ5{;g|cQD$)9+J @h{¼z_f>wUޟxXu#2 7u V,ưǮ8S@D/t+x?/z[܁x⏾Y ՌW+!3sQtBh)%}wZ#ʶC¨Ԁϧn+R. 3JmTX7/j#wtivQE/d!8/IƊ9檖),!E`Y tIfbPQlRD)ŦY1hLtq"E]LXAZJBai5GBj5DD )Ƙ_ "-Np97. X4);m 5QwA! S'J-k90cp[DF&kw4? Zayj|#@lVhc-E"qf F*6Cl&"YKu2WEّd[3~5ʀ1ÐM/kFRXGW>?y\h !YI]pt_@ 8H"[!?l󽉸h)E V"ƙj&VB"H5q \~kq<ٲ89A؋&Y}!OM8uq| Hrkzjhlw&'ukɣOC z-{{|`RǢ P-ci= Ԧ捭\cDJ2t]8"!w#S `#[+leyH4/7(T @0Y  ( y^/qСHuB5e3g;ũ,莿= lv3lW)!b:ЇܿI)2֡be{g+#G֛wvmiݝom;v™3N^qq߻-yƒWXC0מrc5_z=ɿ{ݫꧽ?2#4UIMԂrW%GvM)x[wvvaW/o| _ 1< !ȸlU+E14Mէ>z^zC;w|~G)_Y|Dx ~_|+>?gI}5UfgO]X^YYL[h.^;??—-Wۿ~~&~ "f!!ƒ%zFok 1_@)E|qI81Õ9;Bu*95*`@/j<>UNAA@5K-BT6oT,ưdUj-j ZLHl*=]ScHؤXl_4MӶcCU '_ȢwuEU'Hy("^cAUN$ y(k ^B(hDӘ䒭r\1DnT;!D"6 *-E0R@$Y[/Ze&1UuKG}bdR*hK$AУŤ^jRKY]D_qbW`D7WiQS}!/nTBtV/9 3s <ةdHFEZ{;]1&c+ 0})A+ȸRELL t{7-G)MRu4N9~[9a"tv1"rGWF&URlR(U}8LiVKcb4^Eͥ񾌎,P/EP\vTtheCċ4cDTv% j(*ZT~SF,,ZmZ>C (bRA79v!rǎ;ztw'o=&4i3i S@abo-8X7_S,FjIN/n1pTE=1bƀ*lo;{ngenF6vvw;(}#Ӊqb_q!G?q;{H413gNuϭN'B\t=oll.ݝR23Mڦ/޾z͵\yGƛ?vߞ>}WǎyjߗS;m{ΟGc؇=axˋs|w oX>b'x㢍\8Wsy>x8) &MՕa軾޿7A81|Xt9gK39C*v)Nۘ" J)Ԇ=,EJ!,35nK4-s0Jq| 8 ;h~R&t:mf4{sb԰~φ!gWc!pCO.)5KV!$$WTjs$4-W{~|BD1 xÚ.b 0J}6V79׀^,?", BSj6+vp)S+(EpyїI/̐sÕ{ +ɣʸu?+P[ -4Rk[i͸}M`5[̄8֜R%~z)1冂JX`˾뻮CszFT 2/ݸK|b`,#xy 1b?Вl$h9Przm5#aiZs=ޭ `bWVVWgvc#Y~E;F-UbP%8[m7W7W6oZe;̩3 1׷m]qQ"{wv7rԙ}Uǘ-gOkWڦzu}'$U,w` /`tǎ;vUٝ+?1MŵBbRDmrd1&{b1Mfii3ScJ <,bL+Ku< 1&bsg[RJ T 'rHkuc`@q-XVC tuLUgd2 1|%)vr_mMj%,7( ]MSuV+*R)R=ff [m9D >~c\kJQu#r Cın{$.M5ٶ&n\*`f?b)֜Ej%20 ML`WPǵ4mӤ!Kj1W]}YW'#If0\gdT s>YZ\ZoU۹t鞫 `Gq(N-G32@# `lqbűrUD0qe3ӗgwzz.YݻfJI!3d,,|P3kv{V„)I B!UQv9/[#9v3q.(juN9^ //>-;$/'kk1}h:(jNj"0@Ϗn)HDU{t㉛WsL0`{*C3" ],>(z:"Cϝ:Owynj.K%x[D-poz5Kܢ2Y4u9rIRH93@Zv<ջC@@2QMj> q IDAT3!%d"b@ꂃH$4cp[#h$(gǿ&QPCGoUvl?^e ݎQ`P*)n t([7m"V7`Drssjq& voh#LY{^o//w'm>07Mg}tt|ff)d"5A`!<*ͮfnݭu:9:&BSkXT51*\[3QAq&L)7zc;SvoVӚ[ݡ5 p' 'Q)(95;)` *T +aJ!ܞT(:?pZزSv9z$RS}63YN )BJ q.r B26KtcKIv1~.К$uM $|\8l,ղ$&O!R2{NPo:,q'Х`7]┍=eq́S {IB쌥5 Ƚ1s)F/uC$'D&b0 i@mrGXBuM.)ye*Drvr)5QN[3S._WwS1:qp6K%2##9z\[dPݝ;{0:13#j{FLŚ#2SN9iqV])e齚ÊT縪ㄅx|`?SNb%sKSptt4nK5Tv5%K겣s{S-_#nKg$̤ZSNo?q]zX$f3cJ,)'s$ujЀFda!#.{fvѨo( ]Rie؋;o0xVx΄ PgeڪZƉ 9уF7?oY6:(:aYO'GS)S QrTiVc vysIV[ z+~x:=9whĹz'ty}W_y镗~oכӋ!O8r84V73;>wvr^~ӟq\vy~ZchNWlONssJ*S:::W>Ͻ'OEK>{sʏϟ<9?MS.SʹǺeO|r|TkQμ*]Udݘ?\oupU-ZU4Rj$HD&RXJxkF@ᐶT=@_D4ަU"cw<+ZmQNqYE繚9CƜr NTCԙI~1d4v0)adƔɟ5s2"O9fj&f`Jɫj)%r)AUa8`C_F?pD`~˃tѲ|Ǜ4>Z .pK ]<>!ǡamǻOE>։bN%;7.XJ"Ƙ.+uX9AT4T*bU8V9dUDCJ9LM>Wi 9#BWxh/< RB綵kg_˟y|{p}lzWGHT6<Vdg'o^ib|"z>>>yϳ<̳(j/=~籈>0_^^չ}}ӧ^yų7~|d.U,0كg7^{nwݺ[W "sY !q"FNJ9w򨻹2(櫔:=@4MDn-H/P͵Y9DJRzeͺw HU%Jhi0ުS^9O@Qb; "iA Q&)u4bP4;0q&#lˈh|sQ$+o10B\$fjMD!g`Q!Db5ɟR;gRI) YFwoMB 943'3VFUC1w5S ,dF48a>ZUSJ)1.qg*!Qn-:xL0vpG5W Ұ} T5U5ꋾeBwfcȎD̉C-$9A+iC*&1qsqZ8Eፈ4sNKLMSJy2!`LESw DrWK/1^ODovk[ oh9h+, ~]k،DbBw5vzW4^1cc.i5MFUJLd=clsU77wvqėR0>TUTVuʉl;`ȔLȽ5"LQs{91ʜ())nܻX K.cŧ;BgmΗ ˺ l-f-vś*Cj8!:Re1IPMYU92g07PQC Ӎ-p~37֚uӻrGe Ġ^:!R&(B$d6OAFwǔzJ|A 2yxӓi~o=~u#:Lxryp)цh 1NԹ͇C]ҪLSYo6}񓧗f5m9*Z|Ziȏ/|zXbkR`]~зß0(aL3 )=fN* +DY'BWx׬vhb @` 14DIA GE>9g8 %84xc.+>xq\=nQ IcdBB#F*@M0o]fOVRig0nMQTQ3Qdf*c3aķ X9̮}bp(Qkim_NGޔ o;A#AjNF"0 ;tpa@5EungD97^9qx[tNX"Pn0yeǎ®Pb?ܽv\3Q 5^(4'^лAd' Tѕ@|gn{V( DI1smua.j?wDvJ^7㫗>מA\]^un[ۿcdmuz\ѬnY''J{R@Szӟ{C O?9Mn'WEn)#B~b{+8;=yg>|JDrNYwAj Nj:)' ,{*NvA]\||Emwnݭu>oE_v?.u#rD4w׎QApg*e[F't_%O:)\ 1[|_ti^Dža)v0[*,`!&7Ws Kfݱ&&r{Y*q^L"^ܤ->aq:&qnK`uqZV+f\$\\^b J!"H9n5Q-r/4.ڃ+w%.e0s/28}mo\47pdLE#0- vv}G#t8;c;4N@@a:7fN~N>*RoZd⍉юU2(03i)q`o֏'?BZJ7neGfG 8Qk=j"a;qwG\]-?xŒ3\ˋO_~GǛӳ{R=L]]P&j&>^"FS3RR׶/䙗^~.[wj;vWׇY!"_3)jZLDz2nCݽs6޿wln7PPW)g__-2DG3>̃j"O.Ο_\^]x{LzC>ݭuG~HkD,SctwR*(9"3J_єy`Ӫ\jH_E OKo Dn$h=ei=j:_Md$_Y7"6&,r_i」 WUCG< 86mñ=ٷ}B17U\CL9mlg*GsݙsJUk͇Cksk J)Tv}})YJ-*.ͼz )ba)q)I3_3%Aܩ9<f-#V@PUrD޴Qm-2eJl<L%%vv[ =e=ǨT6ݪ 9O9*1|ꮵZSE4z sX{gJpsj8 ' .RFbU%tmVTB@t֞٘m8x"D4o `QHN8O)1uY-5pbc")s4%#12Egq٬=%!GzoUB_LZGs2rf"qP֚~MÕW-F ZE(LB>Rx`fq} Q̴(h&bI?)/ 98-;LBW ؛xy0h0ݣX-:DY?.qJ᣾@.r5,a?>Yx`F fF==v(H]5Q@ц=L> Ktm\Nq`z(sYGd.iՌ=!3s\(!=YxW)dCA[M a@8{ bVRf^F((\)6yX<w= 'Fٽ 7v"/?s#"?ziG+T[w LL"mb.C5EGr\pl7n1!`21%L%QZW21ZyʥdD/:ʔN68eQ3D27uUT%bOi8*[kqÁӢ)c9NMKHk7*Dpkܩ~SBMz-qJṞS}|苸s.nzN}zbGcP8-݇C=ut%dIG[l]c4n c $'VwVk(7fԫo <(abJ63N2wh~z ﹺڶ#;@MZ]6Dc"$w沯fyw>=筷/5yGϽh}d_{|ndН!aY Awptj/||7)ttz̻PD2fF޽~׶0m43NL>M=}{oN^ow^?WՔ 6M ]]vwnݭu>OVB3<4 !zV 7U*)vݬVk%d΋HZ5=\A>QSʥ E=.[ -MP #=RJQ7ZN sJԫי"ϩ'%6M4iU,`YY&D]Ab zS[^3`Kk}7i*Z[5wdܬ7vG0wHs ^skːjq;D] [2,u pRk{t@e%QbfnZjswP7 5$FZkO&nfa5s؀csE3\G۽?T L IDAT`ݓK=9<#I4ַϦ'hI'Bat ΊGNRV6PG"|P3`4$~DnvȈ9'7oY[[^ny]t7T?*q ˲5a}60R0 DrɥdΉZ4CARIkun'931 6pw96ժ+ 0_JYz^p"GL KD)2^W750'@ą:3:۵CDG0O3=BS1t䒓qܭr(eܨMꎷL# Akaz53 D r٭Rw  aO@8A`987tcBʙD@]5sGtb$ΈyYn\R#%kS)qn"\ ۏ|/sm|TQAZE^ۃ珵Cݹ۳{ ogga~_og9Agֺ۴9b2Ŝ˫[ou8"G7:x{%B3 (or·y?8FFqSf~k.ysy}r~~qqq73.YWoS*dB0Zgݺ[wj!8~_?#?W_F>ww?!R[o?^e0"OUUo}g~'oy0j3|ņ5Dpv m_??~}?u;Wo{Ǿm?я|uoO mOi(ljpB{ih!XX&1#%fXaF:S$\T&*\JYF{iN99x5Ĉu'Kk{>M f9wR3)]̒ckfyQ7fPiֹǝB!4MA~ {ɒ 3ČH0ޭpX]D#WQd @9LL#ԯ9:xv=Eכw s˺fH%#4i\瘵WsL.NDȔsafscMSZYDwĜr.)s" Q%o878q,1֋=0v(06]nxD 5* n[6zhDˍ}*Be t nZoUuvXhyvnŇ6[ qm- xx42,Bb{{iɛ_&~GuFSp;m؇fQA*$UCUs=0LUYJͭ%iԦuyg?=},5-vrgM: t/"fƈ:0ցv,L4MQfmULEw󕻯6߿_=&>:=޴*07fs*ĩ69?x'WmVeG/6+W:{taők?Zk"K1&R% G/wLmZsZcrT5d$)fViq to|uSh#n2ٴVub6jMD6wcCE 20g\)jTkþfj9qy^^d&RJt!sYJ<>Tb$#rT(hTZN 8T1$ !|46f~{&;(7Fo"Cƛ{8N Ѝ ϴ 6bx0\=ޕ\֪H{)e2 -@o ;: {oi*.skÅƻL}u-ZSpǯ=Zkq|!q@h;3Fb@2siZkmbQ}͕..׻Ʃi59:%,%ץ~תjTpLǧ>޽Nώmr'LIfFy*K)ZъD\wryJݯ̞(řE5UNOϮw7|9NN;2Oz?g:lNNz~~jп \ϟ\>~ nwݺ[_#ſvW^{$s?FD_& aοu5?;%+pg&J%3qcƷ`p~o~dF&-{qǀۿ篼kw㧙eoK9~ӰwZK̬Trw=v*M†DD)wDD)kjZJĭͪ p#}z4#"` 6B j NӴlrfͻpPp9 &O)q.e5M)gf2s515 4Y(B D<ݮ݉SN䇺WS K(8cw1%JlF}7HRK覡F{f͖@9KpupW4Q f aIOD;ɴWȉ0K0jI3Uc&Hj)R'*3w;v~Q7vm%U/_B#:J8#x`0Mف{0#M^vpW]=EKaSjy SG{|4\7__\}~=)J6G+VωZ9?ܳ=gOO֫M =38YJn͘݌׻<^ iR-#S)%@ 8#cz*qTeNoNӴڔ\{+/;HS1̵z^Mݜi $Ğ|'zpz_;aS)jvWe)I&wuZ">}7ۛM??CS&O { bGH{R?'_;/8].R "7FQ5iCIFe*a22%NHC^OLe9.%/>F;TU1*៬9FVRL#HR*ƃzD$UID|'ti>M-,B'\xZuCkMDz4 E?)޵s^X&Ĺtf1'fwsջ+|5rɡ "&#;a/Q3UnbZMD&&MLj\<&bJ\35ugD~4DDW m#FHZ nW:@rT,ؤ͑hZF JWW=4Z7)dv85:fsɫDL``/f}LHeɓzDunMRɛ{gTv{zrz6:WH wYлuZ'޿wOl?U_w/vn%yCRεV` ɐ~O~?xDd9GzV-(-̽9S'cҋ8r.')%3?j-Ԫh]DU5R.*%VU%U_u9x(-0[)"hذܼQMN$Bb(L[ۉq!_z׈ S2Mi"D"+K̄KҽϻDWj"2Ku^i`Rl5K3Ĕ(R\Ӡ V>¨!&H5Ո;E({DLSYR 9ᑜ8Z+nQ芘!0*"5%2BD0p [~blm#u|Ca'f# Y"8DzSReSu7k^)Eܠ5ADjf-@҈ѪiL{(4L9eBRVkFpwދu)DtDj͍x=Y50}nNr'D9s r lmb| [[!@` 350TNrZ㓓R hjj^{Euw7_pv(i^utpk_]!-[XX1{G49(ǃ]4 eWM:n"I@n v{~>` ĀSJ+Sv Q2^o: 2,svi~ |z|gvXfwH= 6;:XbJ<-0<0|%A~wat8w]ǟ{MUes9ٜ>stzܣ{bgWt8hBahMH@Yq:>P^<&铹zSVGj94y?&&|}}ݤ'^oM:9!i޻ͳΦӓf8OO=/}> Q뛔^|/?>::?kow"zYONNvá͏Ab33rQMdBk|vZ۬e*9v{wnݭy6}/$JGr3BOo/ʯw?aӔ͇C8S]+`ܟ1=}g?YδLJ~&~(J(v=]9݂w8s;Z e*^:2x @fun"f:B F#3q"ivS1EA@aUs31vr㯨9b+٥xj>IOV<9˪blM2DB^ԋM)&bVs(HGaG6Q(÷IS))3"v5'f8*o0PF+\H3Ub&sEFpLLKOҲ7X$h!N؊DLbJ&FDʑ22 4iؚ4ܛ#L~\Z ]CT'6ѻ>e6706>10^J1{;OMW&ʍ+7o=]v5iBŜ|Ӎ7O?SOyы非9a\v9Y~`*S_x㓷oGivuv[Ϲ~r |$UhAUEݵIH "jC镝5,"ĉsѵ#I踍#lZEj sA͊),F ݻ|R ukP1p{qIgȨt %q~?(%uȥQ@m1`I)TVQS7=h6l ފur1'"bj T81d$LyQmi2CD%>K(~? IDAT)J)s tSj)3bV̍q.a~ZjkQQJi0G!5ӥXp.m= iyyڕ4OV5Zm6s #r2aS6/xBi,!A0B!z{.`hs֋:Ǩ4bh$ :[,94tOͭ\w7*qԸ[ZutHBLeλ+~w&-J vRS7x- #1fhdKȡb1Vj4ѕB}+N0x03WVDYG~r5cu~? )ZZښo3.}z>_qWOyn#$ צ!T\ 2bd3(1aXC[jnVx8;w $x$_0ڞCOh*S)ݱ55uUkMֺF,y]rj5p)!lpbB콂!q"Jؿrwx(s^ 8P"Ui4(8| ޫmERʼSl |nzL`Y%$ShSOpr S0bLv?ѽW01ƄZݽj7/)Sெ@`)ݶ)%gP1_΍J8VpQduHը,D}%Ž^vr:HAđgheVh#5n+Bur<4H9Ʊ UU[m!x= om4I{-uw0fNS%J d5"wysJ٬'>t6{x{ b;Xё`]0rCj5zh[SN̄Dic"ipDz4yfE=4zh觰un i͞ړc秧P!C pr|9"h[۲u֤ӷUU] Q v~ڍn]̜SJ\kc?DLJwpj`k@<>ޤ"am;;]zD% VO߾sν׮\D_IV]cv4oqM4,QFvڵW^OwaYR`اW ľNM} hM]e+#<?UյS" 9JjumPJB38&R[JHO7T Q}nXEQmD BaY8svg37i*?!qUf-*Uݼ́:~8Pn `ЪVczD9n{%E@mJ HhfY< h*_KZZDdȼ]`F"BFDGu&fAc Mo1܁$^'IVOQiN`HK1SdV{UBX"8&:,̇qʤS, VJyJ#ziBD l9mBp,$"'扶ԨZDf )Ql8c'b[eJ)9v^"m'Xm613gOۍ[{ 7%6nGa&l:BAB4p >^ΏqY"oj*.e@b̡ZRqpEt4@8a@dB, h},x`հD]n`BCނ_'1V|AEgDjs|f&fB$w_׺a9jmr&.Ș2l  N,{pK̙ZOU+ <ިuwqc'ӆ?@p\?7$iwjs'K].KwwO!B)Q=l`*(Kr6|%X.g^g)l;F40Ҕ2zW5p3ab"ມDi]熽jIMp w9+W_ Wg|94Wa=??թ)M*RԲ,7^FMڝۇú\:aJS՜<}z~DaLum2#:>v@[.4f,""-l}nM6Q:~q3G*zlPM.p<[GHYrIHF֪͈qb}n="F DhvSG4vEvȿ`f'xnQ5$[F$3W1mݼQmmkmEhEMEܐ0e22O)FDض(Xzts tO@ʀ`kDԚz<پ3QfD#G7+HknFWL;*)!nKw޺`b9%Fʔx2Ze$2N`"~V;S ϘhTT911sH"ZBf"UeDLs%VD$"-,]PBB@s3iL.}u)n\#o~Bqm6M̉a9ږe2%]_v ZϏ˲T麲QbbT~7LHo*c>@5367^NuyAA8Vn1OR4U[jƞw8䵯7PfdCi@U<Ex(xjf8um*8qG0~Xuڎ29js㺴Z͌]DLC9L#FܝS9GI.Ѻ̹lJqK]k0Udd䨯ͷ~ $ Ib4`j/Kn ƣ{ Hؑߋ|M璙EOwdF<zc?wO«ƔA1CWbL"BVCIqHPpls sh.˲+C̔sw9ePZK9jܟ[71 pgq ;Ə649:$`|y7OӔR (ýЅQu{QSZ],s*DNMİHs琚[kE@B԰a8xD)q9ե..2ʎJ]LR""@JHwH@͜9-Ҙ)IɲEڠ?RcaRkBӭǟxI MBF Ԥ{pvf".FPޕX8)H;oD1RZBQz0:,4w7s8cݶ;b]/ԓ?#{i(;޴U$TR,pbdm$J*"Rv=s!Ĝ,D9AGi a.OC 4 O2qJ*ZkR[K3324?Z"kގˊTr.DȐS%V Ow_6ކty]^굝KonܢBHs/U gD`Jfղ~dT 6Uasay(ڼ,&)[/5&+1hH }Y81jmVB%OӔKgnkBUw0N9eB&5S HZUSiIݮ#CWdJ`Vv02Oq*#S%#ݰ7С$#RR4G 5@鴞GG^dG3eqdba7u=jTZ&JeajbjV"DxZ"y:wZ/VWڻ4 |ѹ? ^ƏWS*Ӕ]:%#2U R0D=T=^Z h0PYVk^y(0'c W9d\Ä Ny؆l~?RTFSNl֚auyޕg-S Y]A>VvD-XGalc@X*ױ 28jCC[6i!H8VyLQ*5 RJoӇMWb8r h8Hܻ{ys (@FJHnЪhS#GdڧM!xaؓXy|>8Cq@J~b`S)EZEEZZn"v$7⇡CިIkQP@ FwmbORBnM9B! 3GÇ+{b6sc'Bb枍xjn_w &8!32%PRJ)S9O q!ڴIf*L /SnM0LHꦖܐ1U~~7n?m9bɜaWn_z;/˺/yϽjH%@ؘ#}1:v`ʘ99Sɽ)tl "9}9.5硋g,Wy\}87wxsw.WJjښg*s.Ep 18w>o~P!C ܢ=24Msm)=*vnпQOwyO?T.Syf9}#ܿן|w;ꑟW~ 81&DC1a(rzDd**QQ)ef)1 D JtLl ÔN`~4Qz8.I@vk dqC',& QnWD-%&Bw]*(O(MUDsrK1r^(h&@<|Hp4QWzow -43i"S.y9x8U;*z ٺ/p.0GN1٣tvnO{J1fQ WvHd"e"~P8ơd])!]H9_MDfFJ*UI%e.%_0[&-ʔʔr!#1jԈ,8a.㉎Ȍ  7(VVC> Nu; |BaoɡуKP s*HcŤ޾X"Qb4Ó>x?mR)bf&ش:[*i)=N~Zkm"~?q|]lŮx'6Poj+1np_ለw/vY'n/}* "=ʟ/^ ~qoќʕ[_ Nil{@FO$Ly:az9XRWJɜ1GIݽ[nZ(m>Qs=LWs*Č4=2 (~{R zY\b1M <*Yk,SyqkښF,Ɖ?ҧ§7Sl ;D!1\w0vTsiۗ\zK38c7c1<0BG1y0ƶ !Ph3 3Gdss#7Ej`Äzo>⟸^.Xf)Zaj&U\Gs513 OS.RNLڨ0 |tj -G8sknM$2Ӭ??zXL>v(nfb:vjD%恎5SpRt<"~zSm0DSH_E 'H餰l77D)Yo}ѣ&Hb0=kvj %̐EEM <1xcTZEUrvv6sJCB(:+QʲqTL D2 x+&D7PVEZ֚w Cڕi*|ndzon^1?M3B<Ų:ZDR<+iG& FYZ@Kr)yTx8{)Zz?r.ɏcۿ??x3O᳾}>|/{V~?/xg|o{~Ww|W_~U?n/?ziz|~ʪqWg[ffN#g[#=_C߃ a[;>~e}Ѱ~ۿMkOSg@=)1Sm]kL}4.bLMܽJJ9( =>jks%˲tX+MW3i.sflK]׵9i.Wή"bЈDMG "91նCzǝ.MUxnwV3d^;7',@ېt&QP %Op30ҭ/J)e j.͢缯F8XzTjj!1w{Go@y-[4Iu3xfs:b*Vk[׵攨zu|>12]{䟑ϻUd`dp2E&.ebΈED݄fdD' s*H)sҺ@ܷn"`r\Z;ͻ=s^;ڒsfi;>~퍿g+gW 6Zٺr8]=̏_;??S"]KD ޹qԍ͜sJ9Nf[[q> ~Ͽ_~o7 NyN57rG|gS?zry MjcɿM4H沛#\g Y ̎% 9սb VkS1@˨;)]ݥLL@n(e.O JF«wN*n# H)qwBPfu<{3CR.ch=`fE0 j6* =P:H# 0fn b.>w~¡Ubݬ5y}7||Š4Up'Jy7/~6)G~է7~~~7f u 4v!ށbM=!a2׮.DH1F-t|Ј=[om_ XyE{*:@9:t~{z-@OW'/OSJ&A pk#sEm]C@AMTD4D(,D`b̜rs0#[.~" ʔJ)Q4`)X4wm)P]m7>.jwcvve?p\]67CT";LBS3"r.Ĕݻ^s{'wZUĕEq9<ě2ϹYJy~7pX9eby'hǵòֳ7hz쉧 @Uz\U :3vݵיXj;_ΫUL>SH&Psz0|=sy]^pgP+{ԲN>Wf[y "26=!]z]YΟiRkJ$Ǟn3#2-.,dnw?+?O|z9Fp0ri*F#__=O>^?+y~}W|쏿" j&E(tp9gmEk7]|WpyU\jjC0ԵE8sƉKo"LtEMDdʞeqn9. naI/ܶ͸#A" ب'(@*4% @\Uץm(KjT 1!314Rzp@{`m׻w~wL8S)I Hہ2vS:㨵Ԗ CqVjӊt ڎSĘ &X@@ }z׻s;u?!설"^d^>ʄ >RZv?!ոEŇKb)<Z['gTO2J"E7JϷ=vVf}w~g~2=0Ut띴9ίx7Oo1YbƲ0c?穷u] ׾;Dd;BN3D=+CU{rȬ!@ȽAvY9IP!\P c}3rЈI|:fgnk]fLTL$Ip,#yάO%!"#[7뽷;J,̷D0|f"|U H83Rn(eLo* F(S0DTMWL:ZxFE3{8J5Z]jdsDĉ,>1oi8wM|ݟ/Z+ܽ{'io_|;F_4!s+z|NofyWKaU{?||-x#":iұ6hio?_k{ƏRXխ[oR~}u}8d O1>k{Ϻ2#H@[ze[P3D,9tS.ֺQDv<!<^k`0e*J GLkVl},ݪpel Ό< q\IyuaPR `Y(Mp{kKn!nytFFUOD,I2yKZkkoS#B˔S 9ij%KD dE@3Oe@Hmgi)\3g*n{jT(LDtk{M" ]UͺjX =anwK" 3(9ȥq10ny0%X!arPy":nTD?v߄v>􋣫9@%΢򞳱,)FEˑ`Q3efb,fבUx8ˢ4թ֩[k-o[mR,_JV}5*-(o:$B9TUxe|0FPDO8*{rْI䣦{7ͩecvpkï<~pD2Dm+"I@1 !3H4-~AL\82,4F@` fYXwKw_𼛥3AFNFk7bc2EBRdMI(e)J@㖙UTHS]U{qaCt/UX(̛tEldp7u]xa9ks.#zjgcw_9vw#pr0 w 7_צCa-̻Rf u.n_\"[׾ݗuOV$RZnwvvƯx+T倈"TkS攥@Z:MwA_YC{FcA, /P_ŏuX=\^S-77m8Ӓ=O/o?iO??7ʟ,˹#R 2VW_[{go[y,!J,RkMqo~O}]x:׃ZGy7Zk~1__Uo}j bj=,\=s)5{?c)/ٟ|G aAKOʩXyHmTkrDTCFzb8ͅ+ypv 3ht$:N)kޑНLK)yNLt<"Q칓vǀdNk%0Zz<zPZ]ѴyegͲ4ڕ3ԚfކG=o<Bp B݆4t~&q%".{|)D6eI/"0Q[׵0BՈ&6ቐʹ$rEJT6>>^۰SR &8%?Fad X(#@H氪R)Ky`,2wsHHRBN͜޳LHv]aY6s'}L t%m"f4CgYJ-}fO1!%K6U<1'،Y HۙF[nLD2UΆr<.˱L@@Fͻ%H[8p. Mr͗4!u13bf!D7o0'I Bm&F(ZgDս $t:UR1u=eieAa=9(u ,Rk[xܳW7TvqX7Wz/^Wl/\C_}YE.pwvs \_\]_ߴ+L..\Un$ ̌y2 γHkfa,ڵs_ÚRPpw<]^]ݿj@ G?n˃#Ӄ_(#ًԗoG]_?%>/~k~p=\յϻ7|#޽OyD7UtV*3o ݙߐ/70 ½-2Gs)e~2‚[C/?va)S%]{{k?a3ZT%YYom_p3)sa銈^yFb \:D~apFS'D4M\0SKz 32$h@Ѫ{:3>TLKyWK)E$i2kQA5=ff֨g f#<2ae6U*9Nә$ZWRڗ@-^'8's9y4Q -gڑ`JTv0NEĜZ|ŎTrCE>x n@g޻vh%F <7X@ 1T6|v[uki4 ?DQ-/[޺ayqvp"s'LBy63T"+?> 3UK/ Ho"bQUGۘ{ה0O]ƫm}=u)6p֓2^HUn益oSf‚"EPYVRxO1~D"1,q*o5mw@@wDa rt5 ]rkJaXO(mmrxq2ʗ灇0'%%nOc* A26e"ںm Y Ka)2W&]] ΎH\dմg{EQ{1!jbNY@ p:-xc,jTΌG>:ោ}ۧ p뺶, Df&7YgtR4Mg{)%ڼpT{s䁉^S;.VsE"1~5$%BIOcImE>1.~)v 8|X^aP'Rsk}Mc3`HɁAצ%FR uKm0~&.{v3Vj)jMۺ,RJ0wB'' WɆ9,6r nh "L{׮YCHL"@AQBz8ߵV,Iwȣ( (̄4Rxb"4w^=:n=cxl/S&JyC mAAH[F;lɛ`4\=&e=df71'?N8ؚDDMc.}[(LU52y1=Ӯjf6<Hn]:R<,<|13ǥ䄄@fMA "98BḊ{o™\ B]ЉI ʔ!T7;<5,#.hخS < Y8e2U2`R^7ս/{.{Q;|gB Uv0ss57"BkٝOyum!SB\h;%չ_V˟|\.D,\$-k[!4n |/RXO3g_x{DR˴vkv # @0xwl,7WWWqٯu i\j=|#g~v#<#'j&|/>d~ůFΙkse^߿zRd2 Υ0!F6nn~ڄ# yh,ֳS'm3;3Z"s#H S+b7@omȒMuk">XU0ܜ@e7ϥw4&3B6eLnʈ^A$vc' 'R2èY7*#UZtPs7ez zmĬ˒ZRF>!SH`9aK+TnC!ȗ}=ӼѤͧuY{Z`~@IIiSi)(|+I{9 eD-Q;ToiTRc'βLlZҴY`#ڛ ,3l(|x8-@UeQk HE${`iXIvl%U.؇x"pD"% QXjQSGPwFbRR&5]zmόD䌨L D",{)f Xy*,СA2SR(3YZs:nRBפ0SIԠ<G!kD8]K喜䄜 'K>gmdo-U%cdƁ 3K߄d뺺fQ8ĀHDµ:%L(Ke0@"6CdR%69Ƭؔܡ➘6MU[[z<{[TcT"c@CL4MӴZK)_ a mnG|@cKfnhS 2qk܎m<^߿~{./_޿:,ҎM OQl??|7+y>A2nOxyp:-P@9+rzM7ő,>+>SGqϾMkjKƜvq9vUf""!aRBI3GV<2C&r\\DL޻J-_湎:u_p7=暪KvR.[ "&|Yz{cZkB=8`T"r:RO%fȺKBDdTT{BY6IJ z2>P$tU !nfTzH̝^ Bcv?©8 E o-~wQBS1iF#9Wa1Gnw[emKDHl* S F`K/Dn{K- ) J rxP='q؏,>#>c }D/?b>\^rl}\kH? #Xj\׶벮n1а)Zkm  RJ-Tܾ'S sDB(1`$6-b0>`![ ;w_D\k3Z9#tT{NK)mi'9puFNlQ ]i ӱ8=!Hh#h\9{_RDd"%e*' d1\mYV@K "zOL\j癘7 B)UDݜYhojgg爘xkNSRak!p"2LfœŘ' 6\ Td1?'qh fq fUJ-wwp3{ ff?F&j.n}yRUFu!f!aB؞@jNU&F3_V@B$|wdS9 8Td`lpJq x2yn~<M5[/SI-1 Cjw'R K^ 5֮o~gĈ&~63Iayy1Qˍd mbD`ӵkSSW%<ێ` IDAT0b6Z5>Am\6ovԑMtspbBy AH$~<XkZ="yk}iO-;wβ{:)0fkt0 ,ÝۗIJZ WSM3z? G%bAK!_FCvY)5Wei>p{z5iw>,u쵆.QζOD2vu#lZGUV'֒7Ū}XsRewֹ޹s#z}}PJpX ܹ?/.׫j[5*dVr$~YOd`ĪJ)bֹ$rͽ-6U>ژb+-jeHC1ڭ960QspLv#cWkk'Ӯ[{j[{o}mmYP )S0,=~"w7 6{ p\74:<=#:'4MS$~1bS6ZHH)W[2  D#c98K TwݼwRǸw/~xC]WuUE̵ujYĜMy֚vE)3˺67S֩N4a2'ǎkzd ijV "R{7m6bixzɀݓf[df-̓3UMljm'\w wݭ5'<a"Inř1`ClJGPxgeD2ʊn bbpn`Y駓p!Rhxk#LrF%Z&1F??}͈,'hr;k)5bkC _}w9J-c{iu'[^[?'woHjj(qƦyD1?S_ H0|Cu[X/s6ܞld 4? 1wǗo}Q*sjn /=;AKkkn>:W<TifvTP7 RY"ԟJijr7H*1f3" IpGƁ !d@M_ £L&KIxr<";wD#Z hprdZv98&*dǤQ[ =#jb"& "" U]L# Yu49lJY, Ğ8[I\%:M.a'5AY,ČĘSy@md n91# M7uYzJiCB#1p<_J(Y.3o A-de]sSevVS],=gC,2O !ukvq)3p<x{2本Cu4xn9BXj-nZ+Xg/~=/Z@Jh]c-/~AN_)ڧ}ʫ|坳;t8z)2+ 3emz DIjȷ"Jps #7Dgk (rǐ4_Or\0gy*  Zk0ʇ'nUBip:X/{euQz^$ y?%$oXZDrL&@iE`L4ɓրr-%rS`[?mpw3g(E%xaK{6lo[YR0B zd!'"#RdluHuRa>DXW=B=9oAղT?Tm %IFm͞z(0HXD2ȃB%OyJUZ§^owD#$O!R,%D (dw +`ެ3H/R/kY4eщn (.N$"?o{շ Bl"",Hdfn 4sb4ߎ0oM^5 ET[k1¤Hւ-E$-@H,pwoD,Y\kA FGGkv"Z%N<&T[7Sv(;ۚG B$yxAD7O- <ܴ5K[N)x<`HXd<.xO})?Ll9,ARH#2BsJfET&9ڻm5+FIzP8-d0 1ٶG3ߌ4aZElXsHpbλy/\֥]_\__G&izk4R 'Q#mfj!0Qn63g;2wחDR' *:˫{W7˺Qd@İ-HXN|vv6W p7EԐ ݌}/èTbazj2{vx\Rbsr$̳iҼM1C@xoo_MWg>oyӷ|w}{;,&v6gyOVD <_zO}o?ݹ;|\}g/p~~MozɶD/oM_5O/}o|%Id0 37xr#CE`p׮c:Ol#"1d ~#nGqV[n?S,n|) ZnM SP=‰H<_S;-[@2 "8*nݚTߒ)ߑܑ=f"!#Gr\`c :t#Zvny7q9"yS?=4|++iBGvځӍz:sw Wcs85,yTs* s5u o߾B#'s\J'{#󐤱#ɹ|3#!t`m" ¹B(us;j;V_/gooxGxo~ZZ^g7@!\֭Z2?i{/;O}^~֏  ?SK_5ED=n!‡~w)U܉ox{-,LU UyUyw=906~˟xNy /Bռ9Uyg?o<;C#~dmm[ MAY{z@9W|ox_>g%\$ +reW<5x;o8%29E}[:t.xWzO~Kԥ .z r1Q{tOp?k߲;f[*y_o3}#W·Fz?v)o."}|^Gz+.t'&J||z5~Kû=✳.[G+/O> sz{_}?-?3Mt&v_-)\>Թa#[v jM>*FDDʜYr|4DT ]޼HVZY{W+@E\lփYOڹVtpAQcPERm]0rhuՑ:d1 rFi>wt 1荄`H$'6fa6֨K)/ !4i^A zSOTZJss'ET];ppPjy|C5텓/r%60(>A"P%pN)K@>qiustv0ђPE&KwYbH \\t8窍dR%1hM ,9բ`3#alBl" s !y>sd4MK|t!xfy ԩ`C"{\;h{D!*#>s<[XDAUlk}VLXi')"ʮhIig<&cӺ@QIsI")(K\=D @D𣎺m;o{ۉؼ7'%?|MﵵZ[kkm_Yr =>5 h~ȻL}Mtjj-c$[_v;朋YRFPKA`$'qg>! @K))%G=]1N˿Ϳ?.2 "*fo%xQ7#_~ɟ9E-%ҧą!:2Ϙsn:.G9}/>yE¢K+#_GK_c?ӬP]s{+BםE_ZӌtM^z/~~{4T IDATĩ}3n/;Gocp_X\?Eς\ι"\z/88F 48Wo_<3p{UAw3 FUy;6$,~lAUO}Sox?㵯}+ηl1aq΅n?};yן7tǟE{'}~S~ /=O ģ_/9Pa%I_U>mZǟ'K3k.RhZ_gl`0Z/EG{1Ʀ]eUUm9A w{Re1++{x/P@dq7m;j""ΩrJDc ה<*( ٬XDșub9' >4MB0s3(84KFi4jizsY ilD 誢"iRk Œ( .E`]Dkܻ*ZRن u}eT] -*9<6i#!8]+orrέn[!W%f䩉HQ,Gr*΁@R}=j>|o`0hU[ZU8'9ܴ16qhk1ߘt.9QΫPb``-/ϹYObC&ήXaQ?riuly'WK~:) &v]4Z^Zý]w=FG+˫K+ۖoۖ{Ƶvʥ"k|:MhF>%hvKQR:N5mTW9)v$KD4Z^Cka;B{?--9+ꪫLgl&\Έ??T2򒟡Z/}/n}uTTKOBB>#oyYivV pN|a.un'r,9_O~x_k.=O*%._AUy/7WUom Pɩ>mիuUnoi0v[ǼutiPTPW;_}绔AJAjG"j2KR2 X rɌ7NҽqW:s!l:3K;!yJ{߂fSse7:es?T@3tF/uzΟ|+$xYdӼ3IWW9D[8-̦R"Tp .HC *,bG(Fč! **FխkD@18P}bc+bEXTJʪc1DՅ!hu) 9]EйccChΉ٘DK.)R8s)\#EߎG!F<٦ WiA;bns{7o6m45vm5;D`DX' K{GC={}X+.yЎbtHʂ_ۻ9= ֋KEŁWܗ\J'@e\J/@W|޾kQ78F79je6[$PI=hAԯ%RNRFG޵c.aܿ}uM&"\YYYݾ<vܒÍ+Bvi܎TC7+m̜J]ݫ`2{]J96Rƕ|6%O&y6|ͨ 0h<,/H)EYFm(Gviss~1Mf\ A}9ԏFk~'cb~CgF֟i#JAUE__"RTj%@يFs*ϝU5^H$E߮GGvA1rz#e# 7n?ő"y6ɀR-8Ta.lCO8p-gK潂"jkDުL%"$}π0u"ոzB<ra]Ī9 >c&J"p f s *P@R$@4O71œk2b9d-~"iƇt];1kU=O]mFGu];@;n߾Ԩn˿.ڎrӶ+|eOz6TvW뙿Z[kkW\>:$h30"p C_2ݜH'rT{g q-2cKED,U ҧ> >8#epR[zq:S1ԶRkv+q^_>$:@/|[ u[P'&զnR<9cl9٥p3w=mZ@p.MSXR<ĎsʭIxmfD  Ks !8$(% A ?T:0lѐ,#0+lߟZ=3N`]#!€Ct,"D+m_ޔ:)rߧ }*0w6 a*цtN~ʵ81Yo>pDf0~Fm۷sa-E.xCM,’sZ da&˭GUht{ !Klp{oxW_u+ym\!fW5gY#'H89sW 3^ЅU#8Fdeb,P2]G"H* 9yԔ{Vp Df缏!ʋ.:,NhSP-nMBs.s0 ss.9%RYtu1 V^"*,%SD#Eg "RuêH!I"*@)ABz%$G1T̐n"f-ETbh]  PgV.L*J*5.^OgRBȅ]]R\v:su|>K)zъu. s}w0xʆVViS*Nx)"Es$ *d%H!P`#A.8 M%g0.N\2DDXtiDRak7VG,%WIcQrd ڶY^>"i)=s. gE.VvmځtGlkN};wnǕ~Wxߏtu{mlovm奥x<VVV@Į_uU{]}MӆGML)]y>>vtaG咻>W)"CD$DnL|"䖖ƻvX;otRCl)Hl;w@Jګ]ZZڱ}ڵkd:UI'ǏZ[kkW\\-;;yo=7~_7<͆?:y񶇟p~[||ognɣ@S_/<珿~پ^'=9']G|kp{ՙ%*ٜo|9|{fZu=+jA^xi'<+G`-~i'=+g؇tzߙ_ww~N'NUI&@asg̜n^ y}|ۧ䒺'=QZ@|lE0|boԿ>mG =EHc)F֌i=7`L ;c3rfH}f.CDMӼ?yOziۓ{^ђA9 T%"\[cU~t2+8痗cAiOӔ2!w[ዮvI"Q-—v:߾jLUc~bow}n|^B !7}>F#0fK)֏\z {G{Gǫ~ _ V5$adcRĭvx)8N ,K NG_WEq4chp"mιpiQ&ݴ/%C h?WQDZZkj~+Pi[Uefm6 N)RpD y^PQecX&+(]J;q%kWwUXW }a ;)ЈdJjf%WP. VYblClehP섡jc0r.`e+wG =8x+boy 4.B%RrAFKo@T֢؎GXkϲݬO}f C2dlhGjLvS)s%Z 9-C^x| |4tmw+%#zQ!֢ĥ:*$̺ %!!Z@B`2ӷaX8'5EYԑEP~K}hՕVsGEQ&|@UEKx/5qm|đm.*,*^4}aGs1gf4E"]лk.%1E;clB<13@ޜf}֝Gviiii<q۳@Ľԋc\^>RTZ HTFQ.es:{}> jo;GU9~[kkm_k5!">tsvʟ~n6}?+c$w>WU{k.ځuQ}_w/|t5EyBo&ՀG@f"x#?9ps6JNub><'OKj"'*haD1Ǿ[ȕ=_r'^Dj<r6U,w67~|0M>3 `)Edm9U}˳O3N;6d꓅`ǖ-4חum>R/}yn>0L&<,-/ Y'=w>5hG#GH'Ve|PR#+٫Ͻ߮O_="\}g.|>/w>w !_=ksϻ-LO_w۟w1/xk^{{xY78lW@m7kvr{9)'v.лNAWQZ+ygN8{f{u΁g>~ϝEx/"9_/{}ଷ~L3 @l;8eI>sx5m# y$)L$"ݼ< mAQi<2 UEѩ'׶wB\d! " ՆV`C!k):9 ѠgY#9R2!tDZ]Ala>Kl KʹdBG!Gh .!x"Mc0fUz(ǂvTCGǒU4So\7,Y2K]Ѧ C+Yl~wseieY֓@+PipRRUUT74Ԓ\x6ͦ-{\icH`G`j14m4yW_=KrV`b T>3P5D֘Hj]$8MVDevX3H}̥p.gL(L.4KsR2:@B̒u] 9oDq1#8rmc($uf9}6mc8ҔJI"~;l64 '!1ϻsJm2^]]"!Kh4An']NGܻL|AEfY)=.}lO7Ywm+Zl x  mx4jڶuhza.y7O)z;8vBMg?p`w$3#zC9lR"BWsXT3j1HHkYw/|Ѓt[D߿ſ]8昭VxU.% q7q_M]*̪0-JuH8PeL4Ⱥ1 be~eWcꚅS.RRVG2T}%gk|8q`jɥpf 2!eB@l-cԿ Sn֧/,sC5guYK$+TKP%Ky'ZG:*?ëVD IDATt;@ru}K.h4ZZ-")f)\Y??qyxHD%Sʉn<3ol%{E|ێsBY/*JAsNK)\5P"+{9U1BbxC0V:pvwjBfc.1:Ky1v!msdGpPEJ-Ѯ("|ξ?|+R {BhCD)f !ՕUSs 1ِReoh<(iHb@P/-F#|u}眘39B7$gW>>,ɤw9]ј ۰5.jNy:J=HRa%K2-e ,P`c:{c1{g2! [(4O &BkknR|mmt]:ây`EԴm :D ,,e.K|6NL3f.M)\@ТUfpm(Y5:C K.Αg\ 99VtɹO],>j,hkRa4/--#EMDžvF D(X|8pԧmm۠-!"RRN9M߻TU~Eg64 2Oػv mu|[F7Ν;&KdcsԎ?|a;vn[/o߿o2(ܯFKi@Ocmp)ݼ}7YE1w"PJq#0t$$| (2 GYXU-Q}-k_@b RJ.R<&XZT~3#0OY9a(Ej`\JQЦ16`'*$"'=c?o޷ضKfU jm\t,BUlVCh|5( ƒBysPV?x ahbQ؄# v}f㺃|ͻ>I|SOw#9*Dlڶm[3$}O}{-"([@ؼ]` E+@[ g39_*l?lO&`#9L$PXF9f#)Z"!9 ޻RJ*9sɄ׶164d)|>O]CȖ4·f>g.\i啶y PDw6R7m?%Ӆ=;?@r$,&3l=tG"z N߹+.^G67ua(Wn+m5ZT7ۘ_w|KC0s8}k^ͻm۷o۶c4t}66g+_ݖN6٤u)pV,,~m+vMTUЉpg;G%Q; sͽ{۷op7 h1  vdB";N97#G 16RSrJs`c~&qZ[gffɅch>ª]`%ku9C0wJ.U$W}U$uV6RYEvXv̠b/bS-fتt"RDئRĎaS*EF||>ؠ"T﹔`k6H9A5} ;!Ʌs"JTiL56pF@ xVVQNlϧ, b-}}oe9s"ٴNݥS,w7y͒*" MʮC شXK_aI6m6$_ 12"h` 9O1ͩWbaﹰsθHr6|(-; 1h/M""RU!8.a1}ޑs" K",,{ts*#2e#\ܜ\\}FzeV"a|:}0*WLmf'N!u;ώS}5Ml<T0ii;{ J.QУ!;hÈWo#*UpWAՎP%g8T_$s? .#TQTJaɿ^ %}a., b   7,}"9!Bt!D=m=;4PG)X=¨@RglʅAh|CDfjG.DTN(dڍ*\Yߎra67]@D.u}WֹZd(>4>xOH-7SJD+ )F:[%gn2s)cΛp:EQp>J7 zTL`SœK*K|Q\9 G"?5n۱@%`X~m9۶܄HFK4fR֐Ny?#G~JQ mؿ={ٜLp78Nɬˀayy2KӮxDnS/ov4.(erƈgrl+){_{7nu(ځ׮)D#zdUfBi3RrOD%ĸt]gf!y:(EE$DߎZ[kk'A!ѯl$@$R{v&CB%-Vquϥb'04[!#kF;Q3qhf"#S~>9禉.}>*`1X`sU\s/ ńS)%)@ΥUkşJ#'稄,bF1"g4Zu~ {>g+n(MV YU@0`TA/؛oPC_ee8'GޓCdj; Pj9s,l\A%EhPw~yyTJ99B3wf6f)cmhb:GZw yșQWUMXsι*TnQ6.db(&xPwe>D9}b %RfsH&[1 PhX2>NJIt0"|kn$ˍ\Z'"YW A;v-[8)\ `oGH,ln23 kYP)& TAY%3EIsskn"[2m'璙>f4nF#<uxu j4E@9) 8dΓUGbZ:j, љ,H92\2LZh)S)) +"Co@DbۖRrN&vqzlݼf_O)Ĩ9]8H!LC5(R@C@"璥#s9e9 췢с"Qsg!TY(BaWtcs~a˿rӛl?lwD<#X^+Kasf7mv:5\ D؄OA̺~*~|QsAk8\k>W`ĉDD`i4.h7K?4I}# B\^m t:\16:.t}D KM@amנh*p=zO#sBp14gTta QElmZ[?ۦMQrkEs8X&h(#0" ⠊@> q,K)13.QQ9l@@TH* :B3s-ma'f"y.%b[5Jx:@/Xa&DJN]bGVXkTע9t\IaAD2J.,"!DWE?V.l*03D`7(J%$!bIm0aPW"A;jޛU1xCX ,m\9lLX;VhHmX$Kz/%1%'tp""*y,Ϫ ιCP..P0h6TtJXg=]wC5$"\~לJ?w$ (J"("S; ( 2ETq@mmDC#aH 4*$d^kk[%!EߧNOr;>TLsVg-U2a BUU Fi-ŚӖ ACjZG Q~*lh|"o6Y[vr*9RMHdMU&z#K*3uJ)Q"1u @͸f&z4Pd+Sf#NISq\2J]{"wj N[DG_ɻ?ѯJKqL&9ͦYV]},*8qTYK ǔBOB"t9$H}İX Y֒K7ܾ7(ؚQr.PK&$.A~ O]ZZsV.͘j-u{gW9y"9$.kiл^ j^[$f"$G"+J0ZUtЏBos.(5Rybc77NY.bwwf }wѤ)yY%kfԜ6U8`udbsΥ"p{dmH jqAv'ϗq.8g׀$PL׼W>˶|N@N'%WO1!( 4Q9*D]Dju= <"┾HC2R)i5  +,0XYsA)1M]j]n6YU"m513"[LNUJؤe\%`[jfƔ Q27'J8p0U)(sH8CL35=A D kE@9 12t5(pH3GPr1ZT"mfUPTM(01ϺбxH˄hZ ue4p'xE!8U# 1-dgrPy)rSTZj ]dfUf!z_O`|]iǼꖬ 0\Bw~`6a c!bɄ RGENE!t)u]Ԝ|0s"R9&$ys76B"K)>z5iUy8pb1ωjRɬ_w;&q͉ V(h`ڡzVS %x UoVW2Ue*xԼ&y<7kԪ*n=uݞFU)"aRcwlS@;*{MNL6OT0Zj.Ej }QT2cL)g""d7d .>̛kbbZJH-4֜ܳ9B kVQ@v"Ub)ŘTVѪZ$TRZb66{xUeOIbB-Z1XMvl"1Dv3K]Z__qfT\'gϾIoYAJ)yuhqÇlo{W\yamcsޓټ:,èeY%@`UuƤĆa:}Vowsq( j-fkL\^uˮBJ|cߞr, %gbZXܳK{K1-˝Az2MGZ8cU $OߧK)*9/q,6:X ǃeT8v6"5os^6}y==e_t8q8#Dk;RJfpx֗1+RD%="3)U@6CJ5huwZ1D,PUw90=ejTjSLlӊA]eP >w9tԅW]kFKSKú C.w&3kƼB{R)?;6I1G`Z("D8wDZU@6_\|3M /wuBR80, 31v}>|=>"jE}Yl$UF(}q]){jMt-Շ%F5z'].T@7Uxsp.Yڙ 135903V_ĻAZ1^T7j d=* =ΊDy"bU͹)jDSmȺBb$m^J8Ę82Zd8 a\}`n$`DTjkԥ"Ӏ|.b\,U2! N?TWo#\ڧ]$<_ 򱚰WpZ9eܶ([TPJ"g)l61BCBV"D|=>jp#"FL)Bb Sgb[;OqX~SCzAAmO64&*2r9[w=0.w]a2)gH !'AKⶼ7!BEK\TZk hJD*fjh /Z%\J):s?LMQjQ@q2Q"5G AmCH]"^i)uoA2檢G_0a|TZ/BmsV 1g,He,f)qp7}8军S2xv9RGK:])锓Ok#h"x{u %-]8s/^v#GJa6wk'àZI>y)Ł+ƝCڥ 1Rs\D͓,Z;rxs-6Q2NSRH]fQMc(.K7w]sb*+ZBWաRDĆekuf|~_VeqUP);;y ,u]:$Ϻٚ/g^kob4_xNӎWi@3;η&&_Xc]^/^ڝ("(siCm `&ff L[S8!3;Lq\Jč IDATĄDLyN1U[#0.8# JzbKk z;؅"T03 *c tXV9ɷ^P큀~;$ED<0f~6k{]bd[jm8c@B6qT'~l6[gTӺو0qr!Ԅd#fއZs.yT)(0KXFL$b1Đ|Ca5)"sd hکeȃ{m@ād;E֦P "SRS0%0q(ř9䉸Xkՠ`Km;P*W!HE@DMy Z)WLUͤR!B`tfD@-c! p1Z i`r14 ۜ"jۚ~5TzoNFh 4'+=Ggn,5@3PC*%{c%PsW9B ܀5?y2yePHn4U@!>c)0+(5kC9A2)LAX" "Pcv(z D^]UCZ)u<|>nү?*RbPD@!2"j+6#12\ri b"-'0u*LZwgi`ā[jnk{9NcrB c@@9(!ZZR+`IJn:0uq6~f`!ЗCOō[$6D1 : Lrqtju;!4I@k˶}pYj1d537dq"N)ADdB 1tVݘJZW1r궞JmPCCFHNnԚQEWBZ4PهrXC67=v.ljqb;@f"x'"/DpbzH:sQF'.LCٜ?.201a4 QZ+HsBSTpqDWT FÄ`cfh޴[:5ߊk?jBR׭O"7S_ߢϴc@ӪfDj~ $ZI~]@P5Unݹ݉~Jm;@H]t}"Ksq 0j*U.u)h%ל˴ϧb isI#(*Ii]󾟥!c٩BPR ~#gAxUw8HLs`wX9/J4ٳE>ude-şھS2qqXJb4%&Znͻl6ufw(bgwCGLhޓՐG=i 66wvwJ2bjf$_@q<0 `i7Yy\nBaϦ**498tع^=us~qK1~|įBtqjTAY\x oN̟'W<{s9?5_;^]x;3@V>{ړ~oF/ğo~g}Ehf=wO4Kb}/ .gr>n}_p7oU?߾o'?K/{5䍇?zoͷuiz'>+46N:RJK"zG?wз={n?_%?}<~Y?w1hN9RN0:3v!v$WH h8[O&k4YG=fV Cõ̔@J.% ,`bu}Z__ۻw6pv|89Z2ȡ٬RTH1qJ JQKl6u?/ j;m;JD 0 Vhn5P}tguTAyoģj9?2*8N?8N=v_^i[>5X,w.0\xgJ%W ܇{7G~nQ9~9~6_uo?\G+sޟE}۟C9ٽ?r9y{NOs/=9W=KN1oym>KuH(Z/x^~=CWo{_?\s>uݯY9g~GFmGh~uw{_?ru󀧾T7RZN[Z) jbKg yՃ~Ae9z^ KNe9K} Z؇q)ZpQ8Fl)X7N"R kؑf-w@"9q,u.bv x֦#2Q#cY1r;B ,&8,K/D2Hm#D0[ˡvx޾&RƇ!8IeJ4Hd41gJ 6hc.˗Z̪)Ԫ"V3qHS%?;8H`*l|&gGN*j(x-ytka% S#$DmED= "=D^dv#UjҮ+ڨ>֤%95[(X531C|6Ϻ>90\T1 V<b)J#].IJ!V` vxMaC.XJ.ƾC$ Č`@ ERF ZwZR fE <ܸҫx]v9F!bc^yCJاHyBL"As:b2:X87*:rБ"Q)C`Bcgl6W8}:UH3sHZv+Uצ}\}eLW7~əBO'/{tܟxҷ腏.v3ͽs'V1nͷ~?ͧ??4C-?8G~Ű [˅e^_^>_ĵ.#M1}o^wpx+G_9~1p 1?ZZO|߽Υ@;l։##ZdXOMb_zˑ/V[oUt)v[WWG^mTi/]Ryg>oʃ1s 8~}sK)qYL4*F1/@&F/|"ֳlzJA#MoTj^QT4RrY8}#Xf" Su}EpTuj@M/E#ww8~k-;ulʓe}yФMi^Ѱq̥ZwW eS^Xn71t}!1Rg1&j^q;=1qoI*(.!sRwomXvNC!1}ZcNh>j%VZw[H"!Bf)NU+! 3YqK㾓OZ[BOHq{6_Mngmc;(ay lVRy͛v|>áCnr 677#[i=[n],́39XKeynZEДi͍m e`P)}~[n-拃[;%e/So׼IM֛2ؘ@ʙ9x<^TH nmjj$5 J~Iyw߇v[|#^7G2f(YRnjd㪉yюOG6߸8՛"q?Q_k![§'Z0SnV1<_p>O{C{Mo~Y~ɯ]xCoKE fK&hz-1{`4PYn. D35YȌ,@Cnd$#qsaPU& x /ZjΣnN{8 Zt BPzg !M7$T*F)#o`l=. e9i1.<L&C->]oqJ/n4j~wu͇eGhڮ5os878~gU=j9q8NGC3_z>\(%gwZkׅQNA-\|C>#ԝ~zË.js[ ˲ioE1Uݩ5AUZb>{_8701u'㹯xy%{GԇWsD4LQ߀Zj |RrJ%zƞcGFS U/۪ z0 r-%<Tͪh!g=b kȧ⭗\8wcrbmm4D9\y_|YgA>'{g=<?r6Wq1lmkk_ǜpß~֋ DKLZy _7X$7:p`wSou_<r)@WS@׽ OڃpI~Yk)Uė[n1DDC7?|_^^hİjju:[{_p`m)0DjHy*G*_B޲]׽oˇ=c=HTJmqIՠ,UjK)kFjV)eQTQDSl?UC")j<R -J Pk#{-a%bb@7 !c!\ hÒ } k3jۻ98-Σ5-M4SByyaͳe 0T*M`"esɪh3Uwƽ{z2V0X [$*Ҟ=W2cVپ=sPQvem767YL̶w,D&kkkkkW_~c^[ܳoύnrʞ]lޮu軵Ԓwko߾:B}#bCk֧_qywoo[wG^q"Jga2Kuc%"k-Sop~gg>v> loշug/R#lg;ݶ``RÓ<|ӓ_l?q?Ex?eɁ_}Q!xϿQgmcoH+`X. \ n8,axw׼/|:~}o{3ॗM䰸s?+ӏ~}ͭBg>z֣B:yKO}p$^D""JFAz^WC/D3xdz~7ݷsρ]k1W>o~ΛrbW1*\|%~>^?#~mu?sy_?~+¿bwclߞv7w۸VwW>/yo~ٯIHvtĤo[q23 <>UG:aqJ5TbK8 ̼]c0t#D!9V3kɰt\9FPT*\ ۧ"ޛ]veϰUJUBV` JPfA" Q Dd&@Tw:g<ڧ뻾nx?ɕTg=ߝSʒ !6ٓlńP+՜8=VthbGf|T؁8kPlێ]O9286 ?[6Crѵ̌HF!0RhE*6r+A B׶ϟ~:!/3Dbm'F4h/ZE;!0dQ ATtu hQ_GBv3V:$a՟h%8uC$qI|5 Z+ds-TnӔYlbtƈ@z:$INܨsTUAlS)6du%z*76󜲗Utы^R<KHEC)' DmDM%!omtKUZ3VDht =2 Ǥ*%/rH֧#fh*eb(fmv],A=ȋYTDF1tcۇsKjL0YiC஋m,qb*K)fFcMnb[ð0{{9:+iR8P6]XX+wZDx&\M49gL !`za0ɭ3^D*: Eq0p 9"e8\NLliH0y%MC6B1ǰj#4$t_[eQ#3|g^DnR(9xAG4A$QIC)^x.!Tq ADʗu3bv]7mVr.H1fB8eVCDbv ߦ8Fxkj˩9nv#"SM)mmmh==SӶiW沿zE{ฟ8R5Ut gvƴr~o4.`ĺ2,b>_ qj-[J)!X4MISU1d\c%bwDՓ?3QZBTɧ-0R?l^aY"C M<%QӴ TM )9Xf4oԦmB !DfiHU+R0Dit6̈R6-y5PJ)4TA>жM?hjhE-vZiW/;֬9ay~_*W;U/Mf:]YO"|۟hu!wӐ;풳Qf3m ~PEtaMajP?T_]Gk爛*ZLK9Txyml!Nf>͍~1x7r VvQ15mB%סIEߗ 0lB=@ZF?47\o ,ǙH4,z UfvW~#Ϳh)/ !Bt2uݴmڨ%KI$ &duw3XY[#\DVgݴSBjbtB fg{9dQ!%o`:p}m,eẊy}е~3l/ԟ<&7эN67NnnT)ðM@0$Y]]ͭC7>v#7y>5mHeolힽ{vskskk{DMCy}*MTUİk]kw_1Uz ;Lb BCޟRr1M{;ybƱ;w:ӥm/ot)@myWjm/x܋_g8>ߓ^v 80269El u7H*LC8Rd0C͹uqeVӡOԦHD¤ ֚uXQU@<(@! 9PCPh\~lKS#ɷ_0&H(RJ.RT Eu23LDK3Q;U쨪)0-&o^~#~?}jќsJٷоӊ)SU/#c1~8KZj ,s}"X%DLCNcf3K?zN@S&C`cd!(9 )HģF?%3+v`1rSJ)% @C0!6MӴupl*%;.T̏KrN(?cj`B=PS@^iK @1lD:s;I4vv 8r,C~}  z`c#yWr`=X"`gg KB)HKZ "m&0&O BR:\\JewScBHjM9T!a|ĖJpa6T3QT/aHٻtmiϖ2nmEUluu|72hQDc M U(#2l_u<%}&r!HGy!"YSU`ss;xcJ@8v%8Fwj"=z?aYb;!<3۶iژvdsskthi1̱pMSW)r_6B nKe1tiXKz=?+` @N{EKQeQɷǺ)PEoqt1I| h-Z !? P*r;:MrUqqsJe^!hPͷ݇q mNg8C&* ^-Gv,J8a~x6=xށv2kXHE kq?dglu}2YAnҐy?M1rHCo&}MJ2@t)2|!`۶Ӷ[[[ib8>mّ-ozi\wСnv-ݖ IDATӃ?vĉb|ΐ3ᆭ͝ՕsWV?zwybѯNg (6Z~0q3yξ3޻?tm@4t:k6ΐxwݵv׿eb LATҐa0ZX'!Hr? rMA@x!Jaf@T;Z.Հƈ9T}ؿ!-m@UIi]HɥȌ :p͖ـ!05HLB4 O`"IMLDM (D{Gt}VC x xo]ֲFDW2smH=rNLsɦL]׶m"RD8#Q^A1!!78R *Zu1]gRVRx0186A4i4#=r.!tmchfT- ݞ 엊*xX[A~ .i/g6p *Rv|!o@! j́C a.MWSxnBRJ9gQA;!'*?V'$[U#$q4G1#n&x :yk3 g&ӐK)*JH!G<4mHζ"%Pi)%EZ@XN):|VfMFUԻ?PXx1 [q%"j'/,gՑ6 K0 +Vcϸ YȥTh1Smn2LӮ"(7BJbƚ">je~HHd Rr0 ə`Yii@@cg[O}Lt g2o(#I%]S5Zt zZ9^PeD"AbU2FB #Fc4m$3/ZR,IʹH*5 h-"#|njO0j پE ȐK.܄=if4A5bCChW&kk`8 i{k!!p0Rꅖ ?k6]A aUA*0hii6[=cpt:۳gwn8täVWf&vjf7\uG 418twѣ7l<3\̷x`# }wrþ3ι"vÇpv4MIJβH}c'WVVWVVoy[i>VO  cF@490s[?X}D7%FVb2ޖT\(Qw`*jTo/F:S)NT*$ XbhcRc`v턦0񔡙l&_w" 2D) "M?mLTcB2OJE Fff-@u/'Z.7[4zPEU mUjfFTUeVQ/0& AR%;VI@̈@F엑{taZO#ɢڮk'LR\@%G*~J;BM\Uu[2@/RB3  I\!U# st\rf&F`Kܰ}`*jG=g,,N)~P4UTdH$pD4cʘ E$4FN[v=!]DmȄQJJC"9hmKTblBXf8(7(]?pZ2c/nE D!bRJb\Gǹf0Pc'k,D.}?l)d%Y[N3YlSavDB kl2t|ʴ><'!EuOmW=c}m޵Eܙ\On\7nz󛤔Of3$>k:U~hڞ1[ kpw5#Z?˂.-]kw_X3[$ڮLc8}*R!q\+jU]r :BJs4!:|H Sٍ|8S.zh D 0GR<—}!Bͤmcӄq8Tï\xP'V 3,;F μ8Ħx4.B)78azD ݤ1d`HMu8 CʥT24m!\?ֽJ)S"M!*!\ő8]RDhY`DfM 1ڈةQqJ}c$"HͬH!`Q}ԥztolS.?⨨2V&)x"8!0fi臡O*N?Jt\FF&řzѥcJRʐR)%0đ(DHm׶m>&g]ZwȐGBtLTJiѱHw܂ ZJv{!SI/ &*VԊhUG@6;O.p- TjҠ2Bg31S+?UKY[!YNx9*)o pelayC_|JTCR^:A'1cR8Rhӿ8G?!ȁ&ps14m !jn_^G1ĝ"պOK}7w?q"4H.;~0Cv6GF&.LvX|_oV?> *]kwZMw%(+TkiKw_'@Q\BKt]5NTUb1grf#W`f̡ibY-`rbt5T{pu(c(D^$"e"ⓡ(6nQ333,˰1۽NU" i)MfcM9z&3# \"]3:*U~TJI"7!آɁyrV\Ű=狔7's?e)"&9_hؤM`RE}?RЍ&JcN'bBeDDHn:hSV\`9&CS @dQE}>I(所 oR!^x٧G8<'Z ?nM2Q%D 锈WXgE_g̱Ne$A%J0C9/,a:4 %"M^$N];ݤ d6͹,RDc)MqN0SBAĀd[?)-R?liG/狅3[=t*Ϸ67Rr`ZM9+agB`&N9aR)aeegesJ%g0mBl<.Rj2vPQ-޵fi(W]AbERCD whsfyʲvUݵvwJj4L*ECfmlۮmiPc:"9眥"ss9O'*lq'p_EBf0"CRNDu1SyWjLٔ9)%U !J-)qa60 (!0PCxnBT5"1DiZ\ b$D)}JɅQ9AusV5ϵQTT 3ԖiIrɞ?9/"];N&z추2pUǺyԊ0Ħi:D("S]HH\t L6Иwrwc S(U裣kX}r@]`Àq ([̟˧"L""#z‘c@!pӴ锐ՏQћ$J9Xt883!6Mj?t"tY-A 3yߣ;;fLK}e])4۟!i_ͩ$NNR2IJ))'N9QR D$ f)ۮMWbmNBB_ xg5W K*fs~`%lSXڭ"bHO{?oϱ,|LjZ=/`H1R5Y׶-1nc^%kJR*`ca  B 4JńLƶYR4AK4DCb mtӮk >}_&v]7~uefBT;X~LאGm`dP"PC@Ln l)H5kWؔjRFq j ko3Y,T?K#QSG\Nd OCr[MAfFjLqtA=OUF}%+ ,vC923+F!VڮٷwD`40Z d~8q M6WXW:x`eűtPl2QLƋVW&9}o2N c9l?9[󔆔s?}u]g횶mik;assk3dvft7mbleCh{k;K)umPUu67O,+"]kw[<%e161bLhJZW@K__z ZD4$'n~˛zt+>/COʙM`SuJJ_U ?v_Ǐuj Jkj%ڃ7X z;_Ə#yG?G< G!5ZeѸj9)"Dfɲv k1@Hv᭔rg/񁷽Y~cZ$@k¡!*81BiiHC?ChLTN[FEe.Y}~otH(">&jj)3z}=%kN:Sq+QF"QmՐDяʟwRhrO}~͉\?y92~+]mq _ˎgS)-"ڮmzqo/zKE>󃟹xu|S;'} zVеQo3|ՂD\awW;Yn? &z/=I7;uťyKfSݧ>?rkM?\)pׇ?w~A7;ye+JC~f6]?{MlBw|ȓ~{{ضG_Otۗ/{7'i9 |$3M&]j)ŭ9}$ =$ kfHFjD }*P'ˈ3O8MZTXےT%VS%-Ks8- mbR*iOP=q׆vUPD2Q@[;NRWV[`Y,RٙNheX y,C)ņ+3ٳ6Lym A)s!"jdE/GyYa8X,ž={6]ω7Nw;deu 0€fpڐθ??at;cǿujCDFD|?py$跽>1_<>+Rjzrm aB rN>y#"@q|;\7=Ocg<v! ћ C`@T 1Ŵ3b5ª"a B&j䒗Mx|I0bsn芴Y={^RP'8STԪ G\ɩ)Edž^YιQMx>V0%7$r;"/~ "I~e˞}{GϽͣKw{*O\`|}OiϺ~/[P\54s W}~ڍf߃/ p1osMvҦm _y*͓7}_.GOϟ^~? W>}/|Kw ]tO=__~ş컿_s_澛^g/wyKygC?;G߿^~īg{#r{}~ٌ*WC? 5On`&cpTS±:\oJUДb~({"ﲚ5#X<&sNKG7"+ /V,V*¦ x.L9 4 x7]T+"&]S=y8qy},BB!,Ń{j<حLJWZv%iO9 `iH"ɿbL3"nnmlllno[z<&?wm̢=X& *2o甴LC%afI43mLn}?nfgb?!h8L*M{t GOlWVV91Nl>\gt:e&hۜb'( 3{Y.G娤M;NwdǏ\wu;;E]kwWkҥY$ &i̠ܲ۶-FdE-ŀ1r`"R)n#Dǎ11Mk7p<0'TO16ؒ+e)Ƒ}r[%?G_RM!|z]o4&p+_?7Γ7|ſzguS!"9JM|kn1N8BõG=erCo}.T9~?}gP'GTq8U9B_S\?͗/u؛w\`C~U³ϼ{q$QO{=?ŸȉOf=?]ol7]c|g7ӈ!fy}{'?gow=^O/ۮ_~?r;YJQ>gN럽yQU5U%PP@"NerܧjB;uߚ?ww>@ਢ*&O}2o۟k7eDbݤMoKw?O\_MS"u뫟kF|Um.9b@" tը;?ljw]_T`Dg#Og}~_t+.yՇUǽ×>U|Ӄ>_3Wg=o~'+7h{O/Aoy3wO~뵪zO?>@(9.{c/{; CJID۶mb$?y<wV8t͗.{S_p_Ԯ{^Ȣw{=&c|]xG$ >p\t!"R{#ǧ0\Go=^[̋_³?U@\{cnq,oo|RrJl^՛ 7^~/`*iV"wHH[ sOxk^p᯾)-]DDKˮ#N16UTKDZhi4M۶ڽi~3/?xp47/߾nz M Vw_x#,c p{_?x=+Nb4CsMF),!ڏNWp.ޟ|dkIon36Ɂ73p̷Wm4M3|/^Y#pw ͷBraT.^|9/\f| 6zǣoۉ=o~?y^q9+Wޛ[VUޣsi(Q 1M41kbnHL͍bQPhlHT416Mnl&ԨQb@h ;g֚s~s{1w'}. '?ˇ!_懅x+^=N=iN{-;sO{79NףrٟYM-VDQ2+ ]ϼm'd6H!&K!al)/d)d2I!2d[ d8$_.nf@˖,2o"dhD0c!kZo^5Gsfŭj`pSUwɝ D4 !6!%u*qC";ƈ(OqJUXL4b6l^P82l}7.R۪  NGFpقߑ\$s-Jbh!5LfI]YkTu4Ϻ"pwx|x?W#.^3Y^:DCH?uy0!]7C%"R<Ky;>+7?2Ļw\W/~k*&*O?0`W^Qw^ؽ17^Y(+?߯v"G/?~o#*>9;wk"ョ7g> }$ba'ujPLд'tpg|f԰w3 wY kC_W'oq])쐢RSDjV{s=(~*-|Mۤ&2AuGo! ~w>//s03 $Ub&-HRu-Lv|.2iw@8.|x4"tC'%/y_?#6aT4 @#C !BdD}Cȳ]Gu6` 4-Ec7US3v$u C 19Uo6 .ZV2Rα"6P1Y|3UuMaqEG =$f` m۴MfsN=È-H&̠iյI;eƁ"U YWkSJMڶI FQ@&X*+ Z"FZ9qLڦ1ͻ]wF_dzLM.yc6Օ+,Ka m[[no'que\n9uԶteJ6@JTS!14RU iom{oCw#ǘ0eIAci O@$V't!BrBM9}9ܽ4RĐ=5;`5챿"rjkMGp{ܶUmu/1-fbV,8L$5%EGNl ?@,S(Cx ̩i& x{_dIwA/d樱\Easc1QuW~)]߯.ѩ?N=+{r- 1Z'7V4Msb~C +y;w2$^ijC Fb%AkMywgL[E SEBf2RV)ZUKC4^zfȴz=Oݎ_kc:#"߆eT;9z-{[߻@|WV1<{}쟞)Qgr/Sg~CG<]3μ9]vJIJK/h^O=P7xϳ?p\mxKcG~8ͷ-Y4iS_jMpKMu xӋt=ܼyУ@-S_c`n"r wZތ3. f5ҏ~ދN?k:,c4P{)/xSُ|;~w?Oŗ}11_δIx,ᒞe@hp\̋_{)Fi.bg?̧>䧜w${ɧ~ wctX\wgk} 9|ڿ4Hͻ1LW&)&bHMr w迲[qfZ@j":0 CWd -Ɔ}TR3BDsҶ/VnPB*+ G$O>! @8b*#͒K4Uv41s<L))!ԔmbÀ@+Ml Xmng] ,{YU.M;]YMcDO Ra\.f:˗|2!,9o k@}Lq}*!J%gXYYӮ[ll,++҅;Wӄ RTla86u,!ݢ>硟χ!RB "m.҄ؾm듕v.+10N'ĨLh}΋nIyЛ鮣mC b7̋n߶9a3#SJQUK1@tuҶMܗ~Eg FmU{[glքX!i[a9hqzO$G> iRH"fwkSc}XUraaNDVV' ĆDD:T`Rrc{KLxe)8FLKE}U_\Y}7\VCg^wZC0 c0ĐR)URJIE9)fYE}Ѻp:  3}оzo"LJ1"_1)L~d-wz4mi^p+|)|;A'kw#=WӷWϐR2ӣ^k Alw7;ɶ^ӧOݖ0M@PQ j T" WVMN 18!h#LD=_&D,YלC H(@i x֗wlJ's6~v*%`{;'}46bpco=Wֿf03'NzWN=oCwm'yyݣjD?]çn]l{76w?D/m'wyJחRN|24FLPY]<Ǜ*j;OzboxI>?>)DZr."`BJ?m~Eu,u9·:j QsA5x]'wƫgI]/> S/J|?{O>_y]hvǑ86[uL1EgUsDUjhW0fj'-N%pY&G؏?TJ.}}K)E2(24)qbUǤi93!mDTĈ2 =b iC&言~gkVkA S@9&\'  < 1:S==7Hd` *W@t^R):ReO|HխA)`ˠUG7M3i)%0AJ15DcCM(. #A3Cǡs 2mk "s+2,f":LaQ+R)V$/0 Ii΁^1fm=rEu˄Fb̻nqCh& L8ZY#w;p]G-7xbϞ ɽiQ-dq fE¨MsRXMjj44#ܱm{#1 4hI'ӄh:qQGblRCDQ IDAT #PTۏ?SÍkӕՉy'?ză޾8q{4J.%.iDrd}۶ۏX6 !za`R . /zZMq/}P@ &̑O߻'cErΥ|L|lۆ+@R4Ok<}߿է#R\I}k{V޲Fn/bfNяyыSjO>rokVWVVi{o oͷ%R=fui^<0U%璋Ou""h)3x#&jt]s[rE-r}骯^J.*<#;E$}s.9K4x9Ϲ;Q-?x8s>V3'vr;zõ}T鈣O睻EK-F]pL'Ui'7=^OcO׾OGɗp :߻(?E\7+8ZH o#w9Ԭkkr|ʯg]m3s_k'>PXqOpl>~w?G4k<'5qr|i{W)^ܛ /ż[|mno=n%^}}&%b u_O=ͷ}=pD 3#U¼g/t?;N+7yHh~߿L P5 0XEe? ?po}/S_t_x?Ƿ #򝷼^vG_.3sɓ^ ꩛uۿ}ǯ^Wg/N;,iD\[/Wpg+ \_m xDỞާw~GNnɷ>3@hf~g|#X-.8GzUʗ+7𦯗rm|߮|3B<씗~۷,{n/yWQx'=m/]gOx7jY4\&`? V .u꯼ԿBC~+_/艑<~_yÅǬm\u|իzOwڵqO?7Ͻ_ /wu?=WXdz ?t7^yųs^O>/_Hguޣx)Oyqb_|+mC?y?Oatwn Ls'9a$\OoO~#gM>*-FVRT}w_{ݙ/_7f" mjRll{#RJC D^%Pv_}߃7MSG0"J98id2MM}a<*Ta*2%&u;.k1`ϋ!1QzI'w*:[y+~}9љ5a y(9nvZJfJPWhEշ @8z Ud>_8bw6MZ߶4"n4<?ݜo Aee^tNB3I1*ɴݾDCݻw߭Hj*G!b22۷o77+t-5*lln~bĦibYOLu EJ-#m=Ӣ` Z/(2z77/"#UAu0PDӄc˵7^+E>SlS|1D^p22d* 1@h(4Umu/IMb7-jKJ@\-J,b^(^dSb6`ETkNe~BJ D+}PP3 ("w.u:fwUʂ!sNWDM5 *x&%" ͳVA D[RM}ߋiJ"ͧșLSH"Qq^|.D'y瀀)$@RLSx@V-žcqSR0 }w]DT6$Biqyۤ#+YM"uLD.C7lyަwZ:iŢ.— PԽcZID]SN8 0851&3STF#*8"q{t`v:0d!R$.5SL1e׮s ' 1D2(*2oh")p)1^o*>6/"`,"P1^͖],}%Dr0>x^u\qS#EB R\G{9QtA# "c୍H\Jɹ.U1DLAr[B@U4cɿ*Q @MLP]%)jÐaC"b CΒ"S`>F @H.q5ym@V BvҦI !*3j3Ӓ6!t[Adz!UkzƛRREݻ(("ZUW FDdGBθ".DNV =PJÊP7ofh[Zqy# !骏`JEH!$SD -<ۜK))mfsV5JSOui+.h)PI³dâΞƊPoyVzTGM~8 ~ޗ'}nh sLrg`DьȈQSQJ>jYcpd$am:11!K)r Ĝ02@V"d8X?dB ! 2H\;wu l>6gl}S3ɽ2Q$P!1Y@R p9SB"Rs]JSR[狾+Fjln.H@Mu:BtR xn6=c{4 3{K +IE@C1HV{XQRʐKoh !9 | o,E7'1@З7ԄӨR e!jb )5}1!@D4% S\D0DWCXB`&D1ͰdCY *mj5ÓH0r0-"&"B@VLFyRn XΒK`sT6zHi c_OJ *"Dfo*vSbq0-佰.2~bRT 1:9@ ~R^"aÎݺMCL!uٜs_L@!1W,r|wc Jl2߻H clb164f9a]n!wP QdkRS QzwRrH!DC"5"Ca"u@B`ҩAԤu{pΝҤ%D__9,"!3-"P\<#׷qNno={N4)5чFSKޫ 8m.s_D`ڬ:#ر}枛rU[,~9DNSZm~jolu~NXiuE9D0!ŘIERJn1V^!DM۶M)Uv?8t` W)xK_$yDBLZ"5ZDmvLm#fa)0J]&rVDhDfZ\T !2yhT qbU{@3' 815/bUC4$&2fph&3 @칝Z QD^0UCXH5}%2` ‘],d_U03/h1VN"=/F\E]nz8Υdw*kHĄ2 {5 \1ho``TǦi\KWUP<50\`(cBRR:',KL~uKb7r.Uo~{K7ڪ^%ŕmd#T.AJ1Pfr֫OPhl'B)FL!Hh55\RSEb}Z5.8"/;<7> s`^V_|NzE+`&KP IDAT/*!P;Ym6Tfˀ4>\ '++znݢ/(M̺rp-c6;U*=)QcHծn{kw`m ӕd:Lm{oɴi4ݶcg<6rO&M6fRJ!766666ZHjib)m{}av`omƆo3ꄉ&Ӵ6Mkm [:[gR^Y)FeTE03O"0j&.Z%9Adf_-ի2T`zm* \iu-GG "I71ibJs."%rjqPcj(yC)m X,dasU*0a7 i`VFc3q;ŘQ;[LkT|za4Z5@Rf1\k MBd8M$0Ԅp)o!K&{#s E擈}ǐ}OM*/%LTKv)<8X7WوX ɬYN:[PՒsSu ̼\3.%ĥ1պ|lhUPcSґEk1EbD[`IE㐂0"1 2S6j<փa߭YY2ȤNrY@lCιJb>g[nviÁDG5pjij :ө"[mUPa2%2n3B =Y3n.3 "R~0 ݸ~bjp˕i-n=q߸;e33vb&2UrC캵kI[6j:US5*s.I;AcH15 DnE);4 (VkT!!N- rYVj`epACiꎒnFN!TB>"yEC9>z8Z+1Iw",L} oDfwdO<(J__\{m-65b& Tr|L;vV rLyK?X,mFRjWֹ|h'0 |9/C}&vHֽOz˭iIB.e}7,l;b{3M1E 괨d)M$ؾsvU)TOw_ջX"?M] @B$3TE79v׿{c;$F)%"xWg,k98;*!J1USfb '5oTRLiCBj@Xd%^OD)v4)1Wo;CK}wz#Ȯsz92#F|2N Ƞ!FBGԢV6ǪRHz7S^R;"Dj׍D@ct VE-Ŋq)sjpCxr釜K<& &rmVTB5UڦLm}sm!$̃:]R\C0$To$@DF/UIՌGڐmU}+oyox_d&2BZTWbp۰RE`ʁq'|:əƭ\$5hr9n;az:P18nt3ѭ2txиnbF 1p_E$J1~UUB ڻTbEWмmDe:~ TFL$:.C$0x}&PV㎨J.}KќMڶ80}/* t 8e\ˮ"{sā@'@!<8QD 1 2C@<}yQ0?YkN׮|{s t,Z|l3;gdVkFR(*Ne[*f_;_K<10-AZRTJ3?eDܨ%"mxT]B.lԋœ7I*(蒐Qkˮp3c"R*k1J%$+PBk JPuEIB? @i``Ǎr\x>j"r HBo䄜c(mkHzVqD &pAbb.;@b\LsmW,#g((6U:СZ;.X2yK,2qZ0%UrlKFS G/[Ivi-W+J[V㏥Kf eO;D.*B@CqV;jqgJsU*RS(ILfI&qB `aG_Nݹ:W\jI 4 DQޞyǖ f2Ts4Eai32;laQQˆ33ޚWRIлuZf/0 TUR8gOYk8$ibLFD&˔JZP*P˔B,36a%l' B*x!PaL`ɌqN w(~ c)UiP~EX't!=?16 +5BRHF P))]LRȹ)"ׄ$ {\^aM RBH_慴|jlLsǞJ)}y=%"hA߽`koT롹eTF(<`9(qV'")E|n8z W(r Qs!kY5vL@+(Eǒb.ȇEdWH9Os0R9"g(#~9s) UΒAT"Z)"8"3 rRNuOBHv_PZ(%^nPLϞŃ&8)cʢw 1G)jG@H+Ws5=Bbz{yuS4P.yTNrD[fW̅ PHARZ:Z޸ R(eqZx..@ԁ@U@Q|[9Z ˏ(H0Fc J0 ?ǴNJ??s*sFH=s!gQHK3EMyHR 0 B(= ?|?h勀؃}P/I4M2k;F%K\2uTi+j@ "--O|cav:Tݻw-WJꚙIfr6dXZinm\m?~돿,Q($\"Pa%jڥׅD(D'KIR7s]%zh^{]U 0[0-eSw%mMu)hn.U+r9j*Wzj 83 PJdF"H@\su?<[< !QVKRc[L|HZjDIf11)(QZ)e:e92zISjfk>=dUB*P Pa:G'IK@Q#$M )K)*?t0.`R@ ]TX0S 0XYJ+() k&˲4͈7= )40,sSOo"s?j,Hrh ɾ(7|%TnsңӺ8zr3k "xeHDmH ( %R*Yk_b KϹ" p'<}S}s#g+dY1" B—""8" IjcSooQ*|t=Y `pAjIJ!Qbqh5$V!}((rBPR{/Jg5lo4jc_|ji[8'PzxGހ[ VB*Zwz[z le#ߖ,YQVtiڣ{n]jqkuRqss]uRi%Q +RSSYHbJ[AIQ574W[ٌ8 VU+euTKrsKKKs7Jɲ$M,YHB `VljVws\ B-D#Ͳj-vmRJAT-FR ɹڪmK/P:JTa`ͲØwyGչ:WZ>)<#n y;#Xk<֓Uq^pj5,Q8W%:)Rib[  1#!|Pn~ܯ׈cߜrvd/H)s9\9YJڏ9b` A3dh,':`VZ$E8Q"PJ&~DkמޘKOd޲:rm~'K8 cW:GN 3ns{~Gɡ QXJ 1hGk~Kk-kmrĩc<&3"HtF2D?U9wb7y3.2H؃pP(ߪ3ADK%q-e>1Pˢ$5ؘ=I!qe6sΡ`OtQ}(@j-ɠT(@Hؗ9aZ+!(/e@D¿*(Af,N\}`^BzH1?6ʂs2_Z S_7(pL&&d?:|5"FdkP ~]'AA) K=0z8_crQ-q sGu{<"!@Ďz{G}U떨gJSU+ҥmKQQZiijEU Y[e z*IڒRC*R2cg-%զ֞{t֓Ru$+hg%\wjsKkv֣VZ TT %Zfv@ "jؤɌ1Y}(r,A%G,QU(;Vխ¶0 Z̠ *eMqlvl]+JaklHӹ:W\e9fbA]3pnO%?ߵϞ3pYQ|߷ߴoS|륯0rB{4νÅ 3|;[ۄiVR?ڟ=>~Vlʍ'kN|!glvׯޚyǰs}y``uߙO߆fMg΁_-͇SQ=qĄcݾ䖿z[ĉJ%GdY{,w?ͤ襙?#_볧YlmgL|W_{oA2R|鷀(}tda w=7|s]pm x=qZ*{^~sgZKGc; :=eg=/)BaӮgQsCm#⍇YgoD1ر/<{^ӣNzY) "!K23޲P +׍޾cGϷj@d?rfJyT+MPQ]fR'|ėVBFʈ#gZC/>4i@R*xYOw{\?N߅J%?~vyuZksR fǰ RZ' *eof_ZF>iʿ~a#PJQ녷'>)F 6Q~HrZ@DQ91m-)Nve ~9A- FB@~ĔLO3mȵ2~?#"aC\t4oV6? Du(}33Z~CYR 2 7,-P.,3Dԁ8Ɠg)#z9n[a5&zY[<ƑZ2TVYk|yx' :TJT.G:ϊP>ڐwAH!ιzi_cMܪe(C5`2[cDJj5 L6HQئfQXRխDSjz#9VU:q&@\cͨ\ڵ{}Z]$CdSJZR\.qֶ*3 SPa$Ȣ, 0&3Yf4mwV(BD8iB(SΑAhT8n)e un:W\i!C: |\Үz=6öQAXkNF )Ǟuxy@&6>1{]s92)Q6GQͿ쾯?5a1{e: 'Ϗi磧NNalK?c8c1誇@d-}p?ׂF=~U8CrJI@4YjUs?rdZ7 g{In+%wā-/ IDATɓ8}7myv&BR5v8v;<럼PJ,ziSj~|Juw7gR`m/dP3k~#O#z ޙ8ndu+ 'MJ*ro+ϯ8FM~ 件l'^-:96 6Zx^xC(68' lr4fvLh-wy_:9`7[޸˨刋*!{<|}07z%'PN!6o%wͷaWpà7dBYR@Uz hbZiDx{}wB&ګ>Xqsf#քIi Bu 370cQQi&'v]e[-^ÙNp̢/bx7{Mzgq)wk/RAȦ_}Y|̵8SSZKMV_ۢӮ;@;4| Жgߴ[Nܵ|Tv$?~pU)eGBRK%sdy`gB"X@ Zy\ E%&ޯ(! pōBbcBMnt@ N?9J449%S ZuPB)Tgf+߸k|]H&?U k 8c6 '@NZ3/qOKV%m?6qx^/+ %Bkldzc7@w̭ǭ#?[}pOݲ9}oxfRzTZmxo?ZIf׽ld RIyt-%m~*(\9C|Coc/3Gm=r^[d?dt; <Y{\;+cӾYt7>ۦuݙC: mx͕w]Ԟu,Qv?Ls?,m_O+ް݀Uxdf4K-F)/RvYy+>S֝;BgM~ $B(%mM[\?w^tϱCs`Vo$KOmm[kL|@vqqYs9!: uru9km"d%c}aԛ'2gJL[_A1{*V\0L' 0RI-ksdZK6?k_aLaQ?;0^>^ T+@@:'D)~}Gssf!bՒGF2z-BIȻ(7)|ϷSɲzj hCb9/!?m)H@NA0b铓VY9zױ+M|ķ_>qIR:uJϐu㑋ꉻ/p><{J#c#ž ?%[b.6*ObkI*x*'Yy?yKś4WS]qy_4ag8C}͢ǧ]xˋ?74o3ZyXfzD[Zmzl[}kVfyUHܰL, 0`%F"Gm|z#҂B_]J PێT0#b"RH)@J|Z!>k;e ) R.6C,kXY"M^t(n]ُ @(=9@{$\j+rfLmw\yw(7q:}9:it ?4{! ).R/--X묔B* EJ)ttDb̾xL $~@,COz+!vnm#Oj?}[fu@ڊ7`U9bv]OwG> )g0 b_k< ʽDYN"rni"Dus`(bAiV?J@(2e~VZa>TVg6q[uZy)(*ƈ|Zu9E6/cR MHi)(3/JA1"ze Dh<!3I Z+%H__*hܖqkT8ܹ?K*QSK+*Zٲ+rSSer%j*Eʋ1Ltg#TSXa%*AU-RX@JmQ89΢#rLdiFֈR%ЁOY-YgnbmYR+_dZ'IgY$M$1ErAGG6I1 \mj2斮]vګg5zUؾ6?˼~^ǒfcUlʹϾfNnsuչVF3^}%Gv+i. *:TJK 2NcX$7\~tkJj*X.|ʻ'uՊ(@ @@J{;e9HfX|8lY!&I)̻3R*w[g `16r9wu{Jlߨ/V9Xk?xpXF KQsk&߿bRIm,f$TR)) K8o~sNUѢ.zj(9yIRu@e=cNp.ڛv3RJ6}ߵX)-B!n{Cv@:趧~<>]rv^U-ݎ=R0K+XѲL#(L{fUSnnj^2θ/wؑǕ~z!/z/c/ow죇sl/ ;招_yώd3>5%:M>+4G)/9wK=( 3G8qGnIMZr1uFP~@3Cٱ,U G@R80=8cc&9G΃#F-@@Ȳ3K::;:0ЁZi%_w/6_nzG'{^~4e>+fa'R.Y}UL9N߸֋\w׏8O2\s].zov Tȿ<v!b1C( J9iLAA0:&Ieιg'wZ3wp+&ʴshR;em^o-l) A/|6[Ua xnrV}{AزFuSA4? *GA |Q{oykI icDf0|^yJi Q Q=m[ޱri[KXrEZי,rL1{l% ܋?k Ȁ^n.v%Yq#vv=mJzlJ0z=MHaT*Gr)*a9ʥRTAY w63 %`խX8>@& Urs\A Q3Ky/QS2 \9ۀ} a{r M$ ͲJ%0 //]}vh8Q1G>2~얾x>dm'5x-Ona ZgFቃ9%K*p6E&c*D!r2{~uhj_9EBXCogq~vn?zd$|`!PJƘ9+&]a .zKhﮥ%f?$.i?w9u[ϟ0m7Ftk[ݣ7g`Sy^-{徱ϭ^:ߤNB(jzm|%rjpS3/ȊѵߌF-[n Zk"Zݶ܋.iᤧ1|y^ "o{ˉn=|q\6,wss&ι#'^mn;y =xcS.y_ik?/򆿢kgxνgɆ9.奇Fyy[1$  ^2O,;dCg= xl]=G> 83G]st+/'7Bȇ_5zuX? _)@r7Mpq)GJJCI \agԾh8֏)% DQu# )T$$^&#e^Jx!0i._5m[tſVݘ_0a‹yK7X$߿k~=T#J;$G_Ԕw٥vYo+vo㛇''@Mެ!4/j. mx<)r+^}]5XcşŬOg,JAT\0PkMΧcf !3T x&)@i ,8!B!\o戸p_\s_?pRn;;&_OP1efLZ!Xk3eY=Et}1W;!J'J@a"4M$I4Ͳ,M39grsKsKK߸4|Au^Ӯ66V%PJډ9zNDJZ)α蠔{ru7!_GCXk .0Z+D$16 (*Ahr# 16N,ˤW1 C"o~5ധ( PiLe1V)V7E)罐"3xs(;Yc}+HRHjJ騺O>ӝs/ܯwx9*WMM`M%f+cE94ZcJJȾ.{l=bƹsYiy0 EgAJ+D(F&2q[cR:PZ+)%{ƶEe&rD:@2gcB/ ݶv8Eγw5o B(Q|TJ_/._2O1H3#"(oc# QucFaZ0}mUyS33KTłMB5*Q(yA1F jc{D# *r̜Zyg=C? 0O w̞}yϷr_JArkCKE,sPAȁMdWgYdnHFT!"h;"ޏ1ݿ]w Y 3<acqa+K˦z҂`$d)tUWݿ 8ocQnA4MJR-921!ZDـZJuef}9i4 Us9p]]/Ͻs[{Ď|ŕw1g2a!6 9- Ͻo!m[5륔,6Zڱs"U]Yv2nϻETX[:[gVQPDh&pMKJrB=KvNBX,rsb}S5M1!Z,mB&M"9TrQqG%gSמ𐧾/*B ! fSuHUw=']d:)%+(R ٴi#wodLlNDRJeEj/Bc|#S}RLOY9|ec6-@u&2((2CML.8ilI/Z,}~ߌhQ|xK * D" 1xЇ_tXmJ3$ 8.>SfWET3&EC2Œ5sN}]:FC@2DfF$%A!qFZ! 3/`fgJ uhLt)AM5C8ĦA E/~%/wtp{}}_O9eQ/ 1.lc3i'1:Wjo:j ! `SQS13bfD8GB&cb4&i1X' @&CDQQZZT`&9A MN UCІ+Khm1S'lpi$$?/zѫvN~ -U%RݨVj L͘j9h F9D/%!"fflDjUGo];`3'聙]Cшzk " #5QFu-MMq̘MLq]W^G.͍ )%jBCQx>lEL kn0pl2@HM2;Kyk}jY wrѷ<w7?|yyh 䔥P9FfђSwNCzVa{c0VzŒJ3П`"YsҔ,'Ԃh"!pZJєݹYawؾCwl۽G05lC &H~[kfMlҴ䄨E> 6ҧfh̼mee@\:[glS,J:MWiRr"Bm"9Eו"8 {EGջbM!:7ZDJ p $j-FSJE#jsY-V/^XM̀90&i {!"Ea>&0VEU}YcSIKSJ)Q$Zc4qCKܘI LH)0@avߔm Ɛs *X`\uahD`PJړ^gofqMS+1"t6M|&g^ɛ-_y!,,'lߞsB` &R"VHH,tTSŨGC<";;z~5_sBŃBP>|Ƒi )P L:-Xɂ` :ǟ<3[Ou +8yiW1[J../Iqŧ i(dHM@2?Dm8v2M)]Xt"YETJ1P@ci96اځi "nz7,)|?W$SSb&YU;0ߋfVR a- \  u)  2#w:o @EL-%J.:<7L4%.4cQwYڶc-n{̑7?+hEҕg)2iZ,MQe#]Y9ty啃]x i rK7W)ZåTSRTr[Vzd捴 >@!"عs}Lfl }b3<00qCBpo'"#C]{Tjj1R\.EmnM{[glłj-ZNRVPe99lۆ0\r>vHMހIl" ٰf Lx[  qfYսEK}5g0bv+3H`R5jV U"Œs9Q"lJg0b&0`@` Ӵ}mhzQ6RCǀlS8Ty VxiR DK)f8/=?v#Bj lEDDA7#Ѓ@r)1#Vmm=;Q?qɗK]Iıi\Ki|us!6@CIq]Z4z'F⮺ u < B$OU+8ӎeDqELC |JH%$D2ՠSa3kp?m`RJ%DH9QD5!r-:#SfQDH15@u@50H"4 HM`&ETLTA b=IJ)A .X&TD\8 6e)G UeɾL'M <9D`*r@DdҶMJ}J}01'd2m6  B܍{nXݮ֐w¸0M.`m#+Z]_j`q7WDC"@S:lP5ZXQjQ SuND RW8i<)gӛT+|UQ ǨV7 ZwǾ1=?2 GsMo@RiOd\~!y[m3T%g.ٹ{}unY^^jM}Of=l;Vnm1M"(B9-~>"10X %*Ƭ YKsKA+Xs68 _ZUɕ8^11bĤPez^BĦm\4mۖmvb&HIKkRX]lbF}ִu:U'5 EO)žC,ZJ̄^x@ڣaB$`"2h=jFՖR8 bf1MlVVO*ϸy.pօ,qp9q(; QjNTh:K))e"HY?ZD$C6'5uf">8P Ie]¼ap#?Injsco0D2P-~=1ƯҰW/T̀ ӡ#$|uqI골 bbXՇU夺S8@|sEIAHgX~W=`:N׃In@1)JX`f+qjDM̊,Dr,(ԊQ2Tc[(-}{}"SU%.!D@W7!n JQEps.ZS>7@om w})Zd-cDBfr[{ &R$I0 !27$Y  G2̋\徴ɕF5fN`*%{'繈L.%RJe2,N M TRG"n aͥPL k[i\cy(K@=8epWÌUe⠮|KR?P#D4b 5b# C0b皶kfZT{ߧd5E_XSb#S`"*p÷YH@֟EE* ducw-b$RJ AQ6 *f"KvN7⸛r^1|=wX]۵ƽ߭6ڵ8mb~qÏZ4$!(h]\}S0B$rhϒ$[[jdb3JIZ#z+Doٶl$EKξ33PHZN'+++TUUKlb4d)@-[} ת*Dm;vWDLUjK$lej[glu~kN 0!%J) H)>V1og@=3W H1DXK0"(S?hjEK1:i {U"3%"J)Eu 䃩.Gp"RJEENj!@52R=1 fK.A5UQ(^#UuuUUvq--")%D1 8xBTth[8+7\!!qÁCʹ{B2{P>Hq"NHWE"̔88'Y%pI!3a6V + 8hDC3MLOsS4瘈{ 7:Q>A>uBɄ#p1Rި߷qꅫy<nbt¡O]w"H! kDxMH<՜)YCV>ydi@ ^x K}U~+)yԧ@x:1j)u9VPU?R+@Ujfk`ܴMu37UG#oUfR 1S4 4"ST"JhB6iL̈\QU,sWCDlG0 7q$5 FH ÁCddF0BlKwװkYw,C+mZ Ehgא8uF P}mF}^'3.I~V-+ ̠dI>_ mlc ģ`s=&$"4B`5D`r+ p|NjPӜteƑ7pTĒbro[~_߸g׾'M[)0f4Mmyzmgh I1-*VDTrRH%Z q8YSR?y7/Ed]۷(U3h(D2@R ITfr!;:ꈽ{]- Y"үb&ƶ 6ٴ4my\D7߽{NHy*FER&b&,Ţ,du:5,h&ŢI8zg ,`\ c\Ɵ1j PZY5K.`PPPeH`VJ 3NH)&(HURy{z&ӆcӛdU !Hi )HL Sݪ>adt2,+O8NL`?]t+ CJ, ]7:(Аa.C"JlD/%{K;ѬK6Fn)RT:d>Y-u9"!{]ìI !fn#W,0|+~{U@sqrgPհh)L@E12Sei8sMU+@U3VqHqGR ^ip{)V3o'\?E IDATk1"˹ǜg#RYR)'`d DXcB1)bNblb,EJ♜H8ȼ[1V;,0X3QưBդzSaF!rդfV$ti;`:u:[T~W9BH3$R "r&א\91$$PPl塚F+Zk]Mo Jj7Jb,W=gK(@q>Md v7+e9аQs2"#1i&^ԗުUM{뒔S6g,zhcWw;1,0bRKM1v2R2t:.SRsLR҇O?ٟ9wW!sh4򷝿W oR_="LEqA A"TEBkOLl*Z-fٿ6Rm \At"! a|,0jRA؊Rlv\/w'[5:j`j}0Fn ̥ VD}M3/Vӣoj2TG!G{5=ּ]вQHC$lw.i0z}P: @,CI3Q^0Si` Wa,!#x{bAH)cl1UKw |?iNBM3YY!/"G}.//(}_٤hAdݢ,%#2 #t}|m}X憦ih [)Y(JJB 榈hK)*BaCt+}+aEDTJL鴍;ή<􈑘il6!fB1t9C:萃y׻wMp:[gl߮D f9|RieZJD9.zU- &Wt7=G@0Ʒ?_ww*-"L9?o|_庈^~O6~VɜC9dfMmIV}){UsJR"a4i c-K)oyvn{pͷ/]]Ex=ڨ+Ə?bOe'<ѿ|˿ " !j=zjaf=FtG<;_}l}#/n}Gw:h\w?wdO$tl\UI9R̤i8JЛ% Q6LZsU1!}_8A/CRշStY/Eb/YI⩫q3,y o׾^G>?[}bn'l24@GMJH6b61FD,0*VU.22;QJfHT]5 6L!* Nop%s|_e?mtsO~m^/_}(Wg1:aIv}owFLqP$|G3;򔗝yҽ<_7=T+_ƣ_rkm՗U/VU Qu~sqڟ]˹-}}=2-08MvJU(93df2_v&"9^K?VC`#\Yw_g</^۷rNbɰW?߿Zлbf,|Qx>o QCHDǟr޽^ٿ>XN~^u쒷/W )Tg{|H!{nuҷ/~rip MEm=g<w>v[~ @Wxҟ{~O,uؿ#mnvhO﬋.>/|q7B㔗__ c _οy~QW+fzqӟwr믺~G؍k?a6쫋@RTiA#GL\'TĆ),y-})Ƒ0 6<;սmzt j(/65(9p _e u-U@ "lRAEU\-ɝU?J"Ex*w 3!e**3}K_A b;mKD%ɹx/9E?¼!ZJ"9o2,ۀhQ;GҔ9RQ!p412:HQu(߸vdaff*Wƹeۛ@PFuAZ]M}IUds_g}!t6=ou>萶iv[6(YҼX$ffT*1R=p˞_Ϗ;o_]T3X)%#h,\{aƁ=US*YWAWUsRzZkIɔt9G/!ۿA_.EJqA=^'Oyo(we?< a }/zbg}wsg>W"C) sͻac#+H ԸH.EbCP[`*4_dmm;m M03C>i+J =5-vHef︩0vh;@€c+YoGȽͣOip9USu鼍eNWd("?!}g:ٹȔ7٥o}k~dkyӻ=G/!洇}5_Wx2<& r^-o|Ǟo~U폽aKMϪvrM,z8#.^}|wo4joXhd}S"T؄iJN}/dDdͩ-IYׯO=~z5ڰ%絫/r)xbP+t P `jaz7{~פВs"8 1˷}z*Zbq#?W=!1XHRϾ}`^SS)rM۪IV՝kwʯ)Gx/W3_q /{S' ƫ.~7RpHa!b󒷼i>t7zw~+*Hة};Y^"E?/D`K0\HD4L'C #ks[ H ",0"B`.MfY6$%Ԑ phcC̮͙skCLcVƅf]5^Vx:.Ƣ F͌T(RF&^01c0"D F6'ߤHVM>xSxn )* &fb(%JqO IDAT|5 8 n `L[BZ6ʣg c;T0WT@TXS.wfX[kDڐV^Q+Ys.j5/ܴwr~<66SĀĄ}W9_ӪR:C:nu#91}}Z,w$l;n5 W,w _7}j~mZD ry*-B> / y#_(ObO 1ظo>_k`QnC!o}Sk{hˮw6kOwRUJ*I,e!$t2<0bCxƎ0w$lChMid1rol$jn^k9߇E>x^F5Tu=G4&/m~w-_m*̧~FEN|+U?Va?z7s.OwSUO6A 8!!Lyy?rJmjm|_iy`Jı$*Z;W ]ٍ+4bYY/y?~WiKo~T kfR'M+zz3;+ID]I^n#YH)޳ߊHV%=g>g;~|?mnjS*qeԻHUcS^VP׵dɐ-$2DT$UE *T5qdL*VreS2p`gjc Cb7J)@EѓR< IE7́c>rCI>b$ 㟒 8{yV;5pck"q6j*qc '˜;?%䒇 (2E u@0elyS D(_veihqH2)HT﮴6vM DI0ΥSvNXt:iJ}JݵO7Ҷ APGݥ/>6x;pn:{Vk҉)-x,I=~L'i̫+tؗnսݽY.%o۾ ;Nmmo泶m|qr2YWO9RMq "RlYK)m_bS%c.Ժ.K5fM3mhPP՜%9VQLRnԙ1:sf{k?^w]W{׏W(00Jn՛ ª&&(EJ^ *$!̆Vr9c<4zᆧ>?Z]-n*W; >cj7|s-Rʩ>ERA":@[Ϟۿ ְ7K Y?sT @W>G .>6H\w:1NuB `L|U?3B;mSʹORHA(JѬVT'z_s;8lYsp?KW&*ZDT֯Ou/}Cʃ ՗_o>'>sF' Q`RU_֫!DDKU"4Zs&kO !\7objcEH)%ghRͽ ɰ"GfaŴ z$"GC)c !0\0$jb>>K.E/LS8r;=Ȉɦ Pѹj` ļ;z]"b"O3sQu↴C߱S5lц0 vXV[=P: +RӻI60y];x<x$ QFCBKV-)x0( Q (>'h䔤SMq!1>"%g>T$j*t18ڿK.Hɥ-‰go3>ӟ|קo-TG{kJ[MZ}sR a2hyyp5umhsczw~3^-"ESo}CG'}?| A g9oy/ u9K. Uim#Z/$xӯ|ۿu?{~巼`sf[sPJD!^>hNm;ކnė*y勾}o}7T< mn`,mܐcp55S^]pGcm}sfy/\Bx}[_p"_zW~eH@8OO}ћӋ:P;OU_{Ot2A_ŔXD@}͏{0Zv]G}y׽2w_zxw/?MHO=0G7/x/x7_7*ِG`j@0Ni~=R9TsͻĨBLO{SuO "}0cgveu aq:2"!E(V"$\D 0xq.0- V1r(2Rz{bU}u{c5+9?OF([#i '? QbKJH8 u€oRkaa@d`4=s`FB&*""2_KӲY8Vc?{~7^6Iˏ gu;cPJrR5!sUo)?{ uXMg3+_?ʗzO/\/}EsXߎLLq b zFذ)ٽy &0-f` 6|SX-4zGv"2 T0D]\EA8@Lms`fZJB7? CHUW]u]w0KF뱽-Z|>oSw}R"/]yM@ѲJظ\ @cz2\rq]p W? (&&̈́TOɥýr.)ukc*j]W  :z21pRISvGle|z&lhֵ]u)%f1rDV[z<5A4HL 2PB !pr ͉PC |-ƝU.vK}yvoC䏉&612[?D}Y`6j`&aռᱏ+V!ms!&i47ixwy㶝n,XD&䜆Mpt}_A4>B>o|}|;qGVlowo] h}iwŭ;>剷z3wNg TV]Zu( `&fDa\WuIsڮzolZM'rmv,jZE \d!俧eB,RaV؄b}̩V룣@v|£r&-&cZMSO\J s'锈HbbsA׏!*NL(1tؚunċCe\j8'*L !DDʹ(3a+(` X2'R4 M8%^6hN"E "0+oAKJ&`!'͉9TUD$)e"c5CТR_HQdKHbѦ*2K8vdL FR_𤷿+ $7:ŷDd0~ٌL&Lɧ`*40%uf`sVպ8fڬ9ܳ+ET=U%)!rg,P/|{~{!+O/od93KR22@SG?oIG{Ҽ! #AFx.lz=|RrQgny 5y١#"ެyD D4flL,g" ̱XI3!hv%R BD*(6W=qsu~z%GD@wx%3 L8#YA.%Qy?W-fȁ48.HD!ѣLDM$UͳJ`M2)lRIi ,/LP IW.w!eQ~_&s~hS.ٽb@d%-ƦDDHCdlj(SJR$Fw;(*#.b,"p3 #Vrb/a"i#m 431kn~$"?_s ܚ%*1#j)cXN{cU!:rc>I'n8];/i.(9qR̪*Ng| \v&P ;4i4B&Y]ʩ/)Ffœryn4f8" %gI}6U+ 1*~PmzݧQI]@B̦R2.;h* 5UPb 6ŰuLEQD>vWwr|4M}rK@iYr)/t6賂(J)@1s(HUN8]Zy/;\ IDATuJ}R_gN?s2yՉs\v:J`@5 ^6CUU)& U>cU47GxWsQ<܅^,r.9k`"ׁˤZrS}!0GCuj$!# '0b  4ցB$A\bEx,/p+EF XG :8۩z!l7-"8_'ŷfh<8`UqۘSqY0LiѩE464&æE*C]UY uM B;[^!BDHDoz`2;˜RUj4" he{?m!aYp}KbM(_bjB xno2L l\k0@a1\\[\C+{029hj0TP\rnj:D>~rv8?a:l z _):ZՃG|+$#T T=ê%y8*VÙj BXT|^r.>1 X((8eU߷9H*%wmж"P 1W i 0Kɡ]%"dFfh.E\Q~I\o>|>ݽtÃưZv'Ogxĺ]jsnI-Wuw)gCr M'|{`!U4dI9x+W?S'G8y'~'=C CHR- -"R\XU1V3*UNR !cK4tC>G{")0,9 9bx|=zoh# uSՂq5)Y1Azݵ~h{&F8e(`t Ut+57C$G 22L 2fb)RJNɋR @4!0WzhIf 8 FDDž= "nb?<6Ё0ABQMEw"fG`RRVѢ* %6 Ȏt10  D|7f1z# :"+ Jj HIJ}1 h7:Hxcq.Z@-CH@ dc߆Ȉ9LcZVjśd\2Zp1P^ {)ɦ]7PIaPL<̓xhVrN`bب|cTp1LUՙ@ jzR:p c c5-%wsZ Ic r*jhD5+2~G.٠p#2ڨb}"bZs1.O*b6"UsY>*-$ (9%UʨQ{*2edc D` ruy xs;ozs.b kga `am4{Z&:up& &}{0d2&3@!fs50ԥH%hRו˹KNڷX1,N{ÅU$IUMN&65`jj2U<eU/h6549\JR2tD$b/kKߧN(Ro]!\#Ȏ5HF׶,z,,pSN3 .=zÃÒR1g}𡏝88[o;?{{WAn-WO9s.vP[=g;n."US}oYsܙ|ePQbD798K%~#,WM1::"ju88~媪*~ 9AD#>ey瓪9 Yu%}߯V˺s$BX/Rח"G˶4n[n]woۺ>w}?Aatb0/N8{پO}|k|Xr05bZ-;F"8ݫ"R뺞׫ry^՘'NA(Weۮ uggNfstppt:Z.m)m<4!X`+GKBC(fETq6ͦ*Vzݵ0d2NgUU!hٶkUMisΉS'o/}zOl-w;pS7tR2hngO=q{S{>ZSsΦO:slo^l>4M{W]c<{MM|>zulm-Ν;7"K`/f[Ws{z"O4MC)RRJϜko \xO\|G|聾 &fVMrs'V-ll糪 /^#Ml h9_8rLʼnӧI/w\/_.E-o9yD*)*E9TU]._`|-f"+|ԩ۹HVfHi HuU\<#S*go<؎b/]~/

э|ާSw#=GGGbLSJfl>_ڶ);\$⅋&c R4B2nvmCben2큇0R*5 beqD HH!Hm9o3`\'?&U84UR>@ c}!pUWn,1{8pxful̟͊H LE}$ 5#Mq."PMX!R۶]k֘40b.F6CNPHY.LF"Q@D^u'%#V(hxs-^81PpQ_Ҽζɻ07$Rv># nU"B^qfC|}Af :Zo*Ĩ5~XJQDA@f K|MU>(qb˘ ?@f$Tq2kRU: T0ZmYUs.])DD.f:Raclcev>y:1f> (pH9k.&!V\: wӢ$E $Ea96'4JlL4ar1"5lfhl.` C+n/HI}*D6n$05!TZdqw'96pxy`QoB``fD+Zyc!z5YQ\0s%X"m$לb9@>"dmSvUw}^nVH>^eMB3M9>>> TB= UUq@{KY ApʃvDXg; XCHU#ʊo,:Z.RJ4]&i>vu)Nj2SD+NuN]PU\UUJ|L~%-9SsJ{+[v>?3?/^ n͚S'o() )eÈܥTױUNxL)yooo)R߮jMH[[[M3? ˃+'vzUaw]VLgO1>XUl25>]DIヂI4uw}bcQ%ֹs7q.]z 9Qu=izW|}`ߦƈ W#mN>]u|^ESLtzpt^.S_qT1X#q>]qBi]5EJS*X+G'n~9sqw>>d4 b{t2 jEb1kshyL\E+V o,ۧO^ٻz^Ɗ#y76![4D"uٕtGG]Κt:ͥM{Nd{szى˽Www bgdgNut+}i' V+[['o8xt[bWwլT1I\lMHLn|>ͻzᾪM#5:D.b{Du)!tzR}t\]}LҪ朋iULQ@]gOHj#r]OSɊUrfbի^ݿo;LFطyhy^4uK?ܯ~٤DH)XWMYE3iANYT[[.5jyPJrR+0 'V˶*"Sj۾Oc>yҐSne>s; ёw>ƳgR/>zISW/:mb UFnٯKPkFDQʇDqX|c*Dw(3[N$q fW3yKRJIգ"ai68:S9eW.U;9eFd_V!&73_! ^f`fI%P>='@ЮJu dHՒ!"1k& d}}wLCPohLCvs*YM$RNYJ!L3HDڶ8gq6 ՘gwPf:0 Gn,SS= Řٷt0ЊȌ9h!3LUaV}6l6jI7`ASjU>Y) Hު۾o|"p릞M+ePMl>9G3HYLEcD!{I'tzlvz jU+Y?|>L';;#TyUWu VM#w0ݟo3gΞ9nWv}-y6⤎Qs_0^4ͩi8jY.WB %\9`(IGmsy=lݲPP5ĩivv}W4vwfyݽUD!\+f  vU3>3umr"YdZ)\Zc]e B7OdݝUE2F⺮S=ȣn8}я?Tlt:_,d:V͢gE1JL&S1v,iR<)7n5bz8h!r]T CT,C50tUu3 Y[瓏a1ے$.]:ܽ*oSn Υ:{;ywR*[o9OW׫Սr1҄W^=X/`5ʹY̙W}_U'[;WQΉCC\TJ QzIGGtk^ձ|w+}uݜ̍7^,=wuv>,iS#ݺϒA)R>)KifVϝ)R'LJJ*q1O|p\tzz5o&Md@"uqCJ7>fc%umWW[ame #+&iBUir)R Z|>iW]ߙ p֤UQ$ X ´w/T1Rc|4wefAu]PxKC͹x5j%Cd3Q-XvdO{ST@$ 3_J8ǩI]U+0H)eR˩ #5uNTUq-9!1Οr.{C/<ֶ-;͜sUzUn]Aܠ(J" H!D((X$XJ D""8& vb@8p*׫^f5s1Fk};}^k}K!Q,:6`8uaȑ@ʁxq%j5 bl#^(1SLShQ2rDTzDRP(I_ RKQW2瓭3 QQJ%O#˜ȁ9#9C=/,ܕ#f8wAAg u bjbh#B`v˄,xm\Rg03sbsFc0t< ԎitІa]F& 19U~Uih=:[(E=2}˹T)"BL)5)&aU!婨jbT_*Q"'2Z$\Ku= s&!:F͙3grZ+117T)R+L)9,b@!2!0M8)H6D@eSfX ctc廀5<SK5ZJ!$D IDATJ*9l'APF"%ZQ!j-B4C5SJٕR/b%!wښ~y!D"r9akVKmnΝ{d8\K!J"#df"-`*R 4yHo1 OS9~xWUVnBqTjuBr8꺈qqM+zci*f(R?iNz9Rw 9,U;8]z1֊BĘ!'n-Ĵ:q1<|Ak_. /y,y2J^q^b\ͬ+ 5cĂ~8EN L1""GfcO AS#0hUBZAϪ"%w?:;۬g6@`XjT/i+)#'Evf6NnSO9:U3k[rG߿<:<K"f.?*XZDpD a6M)a"qX*ḁWm\-2 "h4ŰYh6g)k:I-YMb1mT(! |}Ǐ}}K/=W޾9vJ(P<4N.7ˇoU_՟y'bcj۔R` y@F52*BjVAUda8@D]۝n +_j20d\.Svw<`MI!B# Hgyn=Kk"~vy?onR0<@S"b'jZv/| U Mi&\$q;oHꪡj^:?;)0n<=wv~[...Șs!Qӵǜn{R;?$'Wj1 )2MٜF*{3eB4~:Vr1ncEr)y9K}SoqѰ?tmyg|oϽ+*w`bMڮa@fэ9}U&"sH)uN鞭S'±Nr.hrPVf8 䜏([uLۿkc g~@IHH8dfFd7 Ν!'li#!y\q(3Sjmh8KNOrޝZTD0ƠAEt'!]"*@ŪށEe6ڜRt-Q !p !2U9 kLgs+g ϕ><;<+^dTTb&х)8CͺmS6pP]_+6@/?/srsF#G]9ű8JӔeV欦S H*کZ#S`\4M5Z= +@&E-#ז 8GUQ0eNSv>]3@KTl̓TZKɥVU1P"Oс̴ZrUヌvaIxjaT;iwlC~7xQ pw#c.V;ID\.B=a=]8MEk>b.Z1S9kO}}g?m(bBS=JZ- &SM MC7LA=mABbJXC T}8 9g1iR)Ʀia?|˷|fqtQLatqPKuFfCJ1h 1,jr-E hLD]S'8M*RKEBۤ#q~y/0M3 R1H-HȈX@cl7듾ߛ~wE\ -r<9=x_..1;;O 䲽L)/v.8|替固e[oMơĐ$W)=yzzxg0֗U(0$T5P+_=~9pd$Y롔:2*|/xބ8!kzе]4]n\9DD#&S?[ZqXw"$MӚ~Pv];vEFEM1IRӰ\^moo&2\n?+7?]f`W^ju8 T&x 4kRpb)F605C!`BE 1(Ur.fd7b?T+0M#֊iݯqwvҽ(D~rUEmڜY,{XQi|ꫯ}~o|k{30XMBmHuׇn{Df=+3ZqS'E̪+Ag{zq0ȘMg5db`2Q5FbSUTPM\ B#J4մP̷b#PYJqlxrsy/-,KgGCS}RU4Oyc&ĩ >Usq0?K".\3IבsiN*jJj3qWVL]CQ䞋s}@Tyu|jxbd9C)Skl1UoU8_WRg`c`U~|nZf@RC/c~>VV]3SWb5<8ٔ1P,TluʷIռ Hr<<|x/,cY 9j" #NE!0&u1"$Gٹc̑btya(*Զkۣ˔LviF4 nUjJ-s)ĦIXGHQ"LIaF-XkpެVðoK4q T:Cܼ}=^T2C_xH9לR$P UJYŚm4vpؙZ@ l"LτMۿQa?L:4mmRtb*J?7!f<9]oHXEXPv[E:;|^}_[_zS}~.n\1F9߅˧Hyq""ZD62V\aR4 ta;A^O+8\\(aeלg'PK0:{iH)or뛫uElb[JSvZXC{nDN~a j5/V!ivg^ϼهUzwp\qnnO_NLubr9L@@'@41(UrqJM:;;;;?oݳϮon Dk *C51fKS edݟ=|h14-'}1R۪O^m>K[?+1'={ͯ7u?}݉6E؜kCc_>i ZDkHi-DF)"tz: Z=!1ƦKju? S.WrEa(yIB#bhxk5fXĀ@b2M*Sk[5izI?M@l@S.7צX.#4WDq()c괻]\\O}EM:9ǡ׻0RXВHL,!Ć(rgkobX<\,VB)Hf‰byr.pu~_M [7_-?/ԇͧ?w}׏%詝(MV&"(:sL EZE$1Mob1gvxUͭ~wܘO4Z%.}qTxm 1j1&]("ҿ4M*wKU I kctK)p_zԑ}&ם"@Tc5w"3ch2Zrc4Zrb1y# |\ L3*&qjl:DK_ -fpmg 1p`?X:BHZ5CUL'3h6D rD}@VUZ%K.H>]] -jQ /v5N!^D18M17mslU]ޝJ ):dF?ge ~006ZQpԴNn$QT`s][LX Ej>l6>1<>:Eyr9Fnu-U`rߣs=Q0G{ɛcWʹjգDqBnHjfRR_~!8xӯa5O͓{!((-P*x?>ͮ* o#r7Aq)$l.:v7Ùy#1aV 4라&f0eDbLVm0Df\\s[$jNY c [7&Ȇ DcjaV$ $ 1,gl1FUQ5D<3c9?z\y۸{댽#Dj)ס0hLpk*F)2OgmarLP  2ЬUI!GP*LM ijZ!5+RT0%F2-m1җZ*H ~IلL$U:r8JqL6MbbOMhõ#UrLԩ%":mJy=k7<~7|_|/719=?}㍯=y`6 9^]צāQ-QfA %D h%tzxMw ~{{n'9xzQI4< j^m?xi?NS-(DMM89gjx\,"6D 1!) j=٤ 3O9_]])}C0D1"#Q$nT<1cHXo^oooơ9b5Z5:֛K/t}0࣏n[MI:5]*ƱB.ecvisl m?2MB @TD"7ܤ+t clS$nnSuyh^y"S[5go?y۽91ۜKB327Uj)5݀q0={zU*vfsdhs^Ra(Đ.gJj(J1-a5X7['9D2R%4gyKmVֹvbuPZfE)tZvw; p؏{ 4yS2vS5k2a[AڶCb.5W/~?}д9gAHcvYc#(3?'ֻf0}~u??;~/C`wk~?Gñ ?7;G7vÿO~;[w~7R]]޼c_ɟ~'sX.W Qejfms9,V'Sa轿K]T/64?RSJMD"t>ԙg`a /J}ߏTK !*].ǎ"mSjq`Q2jե94QiD80h9pS.;CToJ@S q`dr:Rp.0̊Ѽ9GJrnTE@yv;q/$"@8tiRs1beȜBԄYv}w}?e1# HRZM|Ư'{%otx)UD8O007M:waiE xRJ.Q0pTvWk%˯py}LaZ6IonTPИ qR< XŎv)!J, dy 8eU]X.->ڧa\u>zgz_|[M'_^ 󙨢aHw `Rjj!p%;rqq)5m:m\B(2q}f\rJ)(yihebG?|x-}s,֞uMW7~2 ,.rXinWJ]jcP*E#@VS%DNL`bliAENO_}O:+p}u^?!p[Es8siz WY}jc P)5imBӔR[C>yW۶.(I!SXsZie-N?[_|Zwv+e݆Dܷ~gǯ;~Oc6B m[v8:0SӚVSr)̼Z vgOn&ܿwK]<-ErC)51"ULf#sJ8ؖZnnnж)5 +C ED*w4zlSLvQVeo14T82"XE,.:aGD:?Hȹ[f}vvF̡mY.(~HšEa<;]V&PBJLZժV)p8NʳKaX,WKu|:k>O-ibn6ˇ2Mɵ~x{BzѲkEݳˏLENnQ+yL/;?|vt%3ٓ~O}?zί}~?w ~u???;O?}vca7Q0eG~w'ڏ؏ԳSAbRr\%"O "ϛ~uf̢G;Q+saLFњEDJ5BZ -s7#FUVuaJt©ǁz@+K^=GUBRRi*"Rl83qV5r2&_=a `4I$"Jy@H>3ݹvi?Zf\݈S<*9O8Zfs3cgUM3SLvJbB 3:O̳ U wBQ=/iR1h_DS`]UMsjyc=?6FrDJ<|`c X(5)%w ]-V6D1 KӤ?ʹO8p`ufIzSRGXCD1M]L#`pB3H10Q-RJ5Q`cd4~Q1RJͥ U 9beD*Yu`d:0LZz33bdo7@Ev8u.#I "!$ %RZE|#ĦI ѡsog8cRhH=t=RLeV7ri));!5F"f4T1ľHy<֤SJ~]ZiXj|K0,.)kLE حG~L&S.tc>iuVfǖ`ӆ5H;f_Uq:yRԲn9O&1D(rL99]KoSӦiѠLe±3Pb.&Mh:~BIq{{RL)CČL1Bxf`zdm5z2XE4##j&"DXsܜlb-V fnU\ju#3u^(`d DXkc)ݿ׶I_>符Ma ,S30"ʹ\]\\,EQan+f4mv]K̹LL jm)#W3u}LfڪH)UĚ?,B|]{zlY2%*Ә10# PQ+S85@EmLǦ ]׮V+ dh4?Ob? _^]<)XPG)j\>z|~z&Ɛ )(.̞>y{9Ziͦa 2UD-n~w.1j5]1Rv]j] DB!Iv>!ZVv8TQe4Z+  * plU7Ua kX&FP4no_zWnnoՔ:F6WU쐦,_|70˹,]`PE{IbJH8 0 i:g/ 5e":)L=~.fyYW}4]()Zi,~ӧ?r]w9Qvޙ{LU)#h v*X dUn.5)abӦrAЅ˫m$58H_86ɵZmbj"@Rq4(CmoozUY6?<}vzzu-'^b0vqyPn$K; vryYmr0}?I6f6M]dc1. ʔ4Rijb*M)Pµ"*:\Hr2gO=Lc ȪPSCy_zt~|\X?А""przvvv="~]w×>ƧCO>z/{8=|k?}w/ufs^tkS`{s3N`uv"eL<|}A~Ǿ?GVu?`|l_H]fXq|AFGJh-z6]z~='#I1p\m;XUѽd8ŽmȻ\O~+=i*%q^h/)6̊9bv7J)'* **ȁxN9('v#VSeF "XJ-c"0LyMbnTP 13R "~9zHsRgVQؤ)Z۳iΪW9>`jPQЎ\0\1 l-DJ^!r_EB:l!F7FD5#϶6#o][Gf _}O@F%ŏRbr۬ݙyH |3un;<)Ř+ 3iXSu~X2U!]6MM% DXP"\0gܔeEbD&BT BT@0UJ)ޥl0q C;y/Y96u |g 4g=Sdj;uƩr7U<9HY3Re@@1r j k)Rӫӓbx!sMcRJ)j35`Kx\ `sc4!UY gq H"MDD_B4*$PE-e u(~{-:w,]H2ɤPs1/?z˔///./KLY,V5sRqϞznBz:wi<}|k@N_,~̷]SXA-dUeaMNx_blҫP_za߬GuN@OO9=W&RJo4\0WZ?ݯ;oo=:ۜl~aǜ!037]T!L5e{ Mh6u = ޻Od}k71m5bZe4]l-G5fq,R~)6gAJ)ϟS*Yw.ł)0qjRjqʇ`դES#4M@! 1Tymv79jvWUNs=}LaC (IFJP8&!D,ˑ!!v9 '9 Jbk|Ulc]ptTjךc|ڋRȈ4QzZ,''1~8blB+Y8Ŕ9LAU4[t{ѓs¢_]aiUj?zytszzv~vr~~{O>˛rwm5*ETc8j8٬甦'Oٜமw=c:km\ݘRS< 27|EAR4rN]8MO>MS9x9gbq\XR`~v"b\vs̍coʥ@)FbնRsnjd/0ƉbB+"&RF iӾBe kBw8]֒T-FUEwm۶rvFXp,sAw;szXH4"(xq >w_{!3{O-d\w]鳧O${p9)qHWϯ.( Ms)RD}1E(o5*#- s]з?g-_KDs)E<B&3 weFh]Yd9wmtoe<rr[(*(4^N?|=/d9Y9a8d1Cμ ]ߵ]6jvmEp@!M%'q4 'r)f PP9.PoMDfASCHSQ_EMqauUVD%Fzﺮ[nۦe~)mX,BcsαTO!xh׶TCf * L\MG9J)T[̌9U[=s)@L)g7m2՘u7Li] frΫ*R*RLጶ# 9nڅo0Řr)":c=,k{\1ǔ~>CvwO6W,;ᗾn4\j 貦~;CWˀկ~G[x{\⩈e߬waKDd ^?{zfYXT "GN s0|4m4cLc464 -;RTٻ)UΝNw`rnZVH8#h?؈'fZtmbGso~]___z}m\.V>1LLn~ 1[#ׅ+LӤڶn Rh4Pr1j :TJvh&[oO.|l?$t'Xo-YFs}׿^ ɉ\$gIfs:HՇe.Bۮӳm9Q:6\$tsy3Ŵ\Z//S)1g)ysy䉘aT"^>PQy~u*/w)kD9ZDB;": #[ܤirV՝;ݢ+\89_]_]\^bY}T AJ)1khRZve,~>=lKt3^_W؇Uޜ0\[VEnHݹs~wyWqIR~5`0S6b$dޑwUË/'qȸ$X?Z/Eιqi*%OqBЄ_ÿ{O#{?_w~~7?KoxM:OhhT[ս"rZ&`F̓ihhq y&"bھMvɰ"9rrs4CYKePh_כza:8Iˢsm߮ӔD!K&ƦqD4 h%E )O9$QȒА|q4]^=m_so_ ]v]Ai0|ow%pι{\c/H;&ZYzɻwv{>`5+9?<|Zq8Mv]R??o]&N_h;fs?Cow_?{7}S=;n}O?/}'?_V@sϧ?=s0 o||4iv"Gۭ~=VDe^XEGBwjI&kai'-zﶾ`TvqZ4C6 !WM+H {4MZD1ՁУ6buB`f-$r,|`bU#<OS&9"B(+ |n2ʠs)͘gwcvMԠԠ/m<{1`sqe H}y)5`qSuF y ٔK̉vtMy}h93hѪT9.e059&J,ɲMGƇE3 P5)EKJN_wUBK9b1NeYbGL{o޽ww>p"ts}|H)4NqJ>{Z0YtX=9EnLJS4˦=lƶ7׻y45]p1էyM9T44[4mB-Zslh@TvC 2[9W;r'cxyy^!0jVRLqEjٯ6o[4XwL}YTRHT.rJQnP7rĎJNR{Yw?uk2AΘWx:U}*@r^oBaZ.W޵4] Asf-=;J=s= wŢG?ͦ{RMTN4XYpsޅ [ע`EFH4L{ ,Nq]]^_9Gǟ|"7mumEsJNy[ftmMТ///rIHZrZ 05Gz)zqJ cL 4M׿O{~//~W iO~w7ӯ_oT.h}a'/s?cη|s,b "ܿsTFr{=&\΢G-Oy炯e}PU}off %Mkjceyth(5YS)WAh*J-B pcWQ}/#!-膄Ll V=(I*$8)̈*2 ﬧJ<1K j6mf9{9JkgǥsiRJdS!tq3[afŌ^>kػ7 f82M֋&%䖘'%uH1B!pgAja}8%HxX̏GD m1Q'e05D|;ef%1PHU"n&*wտKH =IQOGh"R=5Www;r-^fhJxR,%Zf:J'Uf.D?SLSJQ8ǡMIa١܊vXI'8ɥlL G@H*U9fc8XJ)̳l"9Bvn#r2c͑Z# xn)z}ԩz f0Jɥgi\DDW~&KΥ⩚) ոMmj 55:k/x;HK՚jJl<fbp Njg?&3Vs3*̀aMW7ΘyT35fLUJs1$޲ ήT oCm&3#(uMo {v7}RDrɩ6xni/E/ ݔðOqR)Mb\֎f)ǘ4 !:fN&SIa{M7197+˪*:%;]!~8j33YJiǘ iCVa;)@M>V[.:N4`F6]ۅB8E{~z{u}3SӶzZ]+Ra;)Yj-!nk5S`&iLFcfdWl@k8MqjsNp]^^jRVy41~>4SJ1޹ ]-9H}ӴMMח0 BYL,)pumNr:S]%M)1δ,\-ݿKqz_ʻ_|ͷ=zw>x/gxzvzzz'8&1H\`rf:01~iǏ; {4$YWSF4ZBhk&JAo@Pn`Fj8wJ$Nl[C1PA1RF9d]ei0w8uNts~vg]^_#OƽGº[03"f,gώHRmB0jB`RɘQҔ120[znz^v޺y}/| WϮɰmPe//?Y,;|w}w}w~g,/|_O_!ݻ56lq~~;7~]1 'G%&gw40-~IXR¶[jV۫kW'z\n&0[s92edl`OTfw}(9M8lit=Ӱg5)Ǒ-7xȇøʡ2\hܚj`CDWӓ;bV~={f;"N6zs\{I8QQe]wv~8 qL_Wᰗ)&RhBc>i'j|Wzm[)V=%O%Qs/α37~ϯ.]|1N+Nŝ;< j7Bhڶuh)RR,I?Ԏo4*ts}s:9dۛk;ڹ]/=Y ?$E34 \-כoٜCdއi]\Xv8ɀPȉa*$jq:=;{gw_}vq9]<1krޙFd1SSӄn\69LcpUm|IeԁshT۫˫Ϟ18;vCׄqpЙb*svLTfb|BMiw'~7<|S IDAT)1rRmhۮpnK ֋rm_{fyFYɜ昼.4ۗF5Ncй@P#@RJVhDJk\p,[e)uty7BѹsdMhL9aG T1)yv8r7z(/ESF9vJٹ*Viӆᠪmۮ7YV%b"phj烄*Treki!>f3~ 2i%tbQU(Pp>H1*;VQe#Bdb.8CuqHcpbcˍN88QNTX=gaX [9,HU5zu4?[I9ńH}lNJќJJ wLl9DB" R0'T!zkU,cn#38ŔS)*cv^bj6EDfjt[ eZésP{JDLs=%3pVȬJBe"PM`j/L5>>ŘJyKtz"<:s挹JDq QCP`eML>xJ[q拡""@Smu]ɥ~&X4ƔbNj4mևp4OrU'Z=n`h U@lc 'E̐M n(l߶mv3}50p$NSJӔuЊ vj\mۆ7fsZ.=;I9"SLcTQ2R:7 44h:4S>eǡOX3%5U&tΩb~b(Uw]ɇqɐrk4󋫔k)ކkSAm5Mw\0xN7'_y0ù7̞=ٳO ]cfYu)LX)d[,z+,@=>9m͚W7L.5nE MS^'"c544<8_/Xuq}x~ɳӰ}3G<|kVpXDM.eSεEJ4MӘtm\+41Z~##pNsJ雯v?bw}wowv}}1쐠F޹֫;Lٝ{y2Ӧrz,YMaWo1Uߔ"@(f=hJnyٚ&lV+B){)eVp3"A>Y[vިcb$cW>z睷_{fy}|+_G"%j]{vrO &f0vﻅx̬9:p2ši|&욶=?;U-a7&xD-)}#!]-cJ$v9Z)w'Spخ'60 8; Yr9%+YEUCןݽ+ q-jɓǟ|^/jL㐶ȱ$o{`e)@fSڅ_ZO>p؂%24]ǡk!ŢVbuUӰwnErѼݧݮ[?ߜ"+a }9T7 f轿{n4dJiӧO8b.Vrٳac1,NMQ>Iww7˫K&w{wbFn8/+ g,*s!9jF>Z5ps=PRb̹ԇi51΁E$tȹc܈>Z>fi0B۶޻[!;=zFk_Z5Y9WՐcJ)#gmΫ8Žk`-DF۷YݫP4?yU',i]rl)3p>43%vyV3R9g3mp̀OBRɨq135wY$a%m/15GQn /췈fZ *:3g=ӹ}08cQܬAΑONi6-HPD1MG N ATbD rPp.șQ/0ټzCei qbw/cЧKG:'LkUޔ 8 b9G,sJ81\jxfD3B+-x>RefጕĉØ. y`+LOecF$΅\9^ S",˙m4b iǜSN@eaU$ ]QHd 1"0{n(Ҍ%%s2*-,M|l\}0 &KY˼c|Klf9TR0a9=OY)v\J\4qfZq,csq^-s4{b(SƉϳBiR200 .J$*(Rcsn ] 輟 FjB0|bڷj8T~~ 碮tQ떻bRH`M9^ *b3/tS s@NȱEsΜFq^nov rarL ѡpb,sHMeJm $aLJ͔R(!d18H\xJ(TJmBΈ3~As*-M)p8R AIɪc{h]<Ċ8#TiNq1xΘqw2VhL%%_iQpΤ얒P!(q$֭R ],bu~"Ŕ2bs%qfUb bj-dTC1Ƙ1ayN\B By$#Q3 K'ƀDRvqZ/0rJLHdu0Vw?wm4źkJvZ-ɍ @V@O #ssVU1q 9 ~z:2(rRJ4~gι(I9ǘR ĸŐ,8sb]Lb~k-5| g-4 Rݨ-aaߝɔjۛZ7L޼s?bL-&DYbmͪxrII.b HU|}?*-Mu)#I…>ov7o xY9 !yfmwWW?5٠݋?ꏿŗ}_R/_J!W\q6  s=&G2JbpnJ1H)1 9Πfaûfl6\|)zs%q |TrˈW=|x$mS׶xgTADL9S;=>hM\؛o^p>.JA))%d!qb xo2zXڜqS|QIe05q׷q:k5]ȉH̓Z\V|30TN1vQoo۫j^m!w)`Y#s0 >zevt eλUwUmmeQV)!r0Ssq0!a8<1!gp /uH4os P!TFK)aE]TFJޟI 8R ŏD1yG Q( RJ<sιG1zbNRRP<R*- T'+-?&-eDƹTJ*I .|>' b.4`1.]I)Ss`u)9gbR0D"Fr*[|)gR|њ1[Ym cJe4$9k (:Y<Ka.K9â0'ܳ9%R”2`K ~`"\p0̜S)s%SHIVf%(.bL\ =y TmG_%!Ԁc(Z :F5Mb?%Bc,L%϶]ɋ bIR*s*+/93ˉs\2dREMS]zmŁ/%Ί+NjwK~S!k:B;>_~'&393-t"g(hAp$nqL.Zd5$3H7:Bѧ袟܏n" ]c}*^; J8٧eQH2Q2RqFBZs`BH&BιJHxs. ꪊq^يq ,ٔr),"o%"D>|eqp2i׫Z]U|<8(kJ5?i9JH7ed)SW˻ۦ]믿v~f)@L_rRJ)ȞywR'|̖ʹjS[YJavXfWD$lfy| (FX\DUӘna}8!H !7>I~*I)13vhZ~OBqdt: nnT?ا27כh#(#jv si/] *<4ĐA&ƩtRFd% P)bιPkajYu-li඲2ƘQJO3!803ۻk)9Qǩ{ctL>'ج7W폯x|O`JL PIVUfd)S1ͣλyCcشff{T3_dTKxGrdFX1RrL<ilCZFi!2A$1a;[/ZuBP)eh3y7af1C?%onnn2fviK9S$SX,r޾|i:D2N Ifr 4j-4"CdtWlu]PL rf}G?3p}}^i9dmVoSN4Bl#b>d3H,ã^\"cazPZe.\g1]bHGąRYcRcgJ)"%DdcD9s!5]+0%O_ˑR*;R([ ɹ)^|Ĕb!Ő1J%i'TEJy09RJ  u0 ]+q-uU %2ys \Sj+D4̓yq>31r xBKeJȮZVWgqagVhS\rN w,it"R\-ۺ++9#ə c9K)fY0NkɄDJ80'њ MAc9cIQ5PYU׶rw0R!Nӹ?1Υ)i9qruW!yBD(8'c8c Ut Re'Į뚶!BH,>W1q gH9  SL 24JwZԆWj##}#(-NS &\6 b̈aCU}| ȔpBhBrnѓss $rVUuc/_h)8N)a?K)"fƐ+]g{zv秧x:jQ٥\H!RFk#ɇcJ]SozZ8`9~{j,-U]!L޻yĜRt|ܽ:onooiL 嫻/>noOG,_׿O__=|\oR(lev7|1Tٺ+)뺶q~^-B0{,x:}Vbn_|Iӵ|( IDAT0Ntsz4%oc4aA~ɻ9S&FhSw}yQpf1n?v}^^8itNc1:eZH^]R !%sARs. 6*g>9C@Ͻat.ƈzQo[cu?1iЏV Y??&>w1VRʔ(%җ\?yRmXtcLI\t14 #0+2H6+8ȤRp8N]?_ٿ?[G6Bge3\?{߇K_3>\NBѾ&WW_~_~''\J1"0==>?@u]7u) gғOsc쇡ijňޚ{Y--PFɄѺEݝSB>jm9HCJ:FsJB@|V8s3昲/e0,fXD8(1%IV6]^okTr^oj( r\mM4O0 R骪ooyGTֲkUS[<\p0ɝ۶֊s1an]xcDZZk8gqi&Z+E@}?PY ,8#pO d9Rr \1.fD1e!`X.v{?;N bb:Ole]["GW01͵5Je8J)ۨ)N|{x( ÄL103I-z\ߏRgvQ ⬔E8g9#l+8#J>xC 㶺;nBR2T2~qbtU'I)N<ͫG),)]1b}3P~Y' hL"<)yQ'7?u}:}?䜔v]m?ŢP_緛j) e/_r_~O2LBNqͻ@B1!&L;WorfOwo?o۪*ku솔r\ s!d%-c"}ΜM?&2ۛ]v߼iq #RRxb!!qƍ궭:ysM-)]ژrL1cُS/߮7 D)i{w^rr!4L·Bꖋnj!<~I]+r~{[UR2s[W1LS?g&!E? fBZ[[vZlK v>?~:0.)a]לN}lC(`L8W81!MtT^ p:QM]UvߓWO0ok\r\BH)}]7Mb(ZW4ME8Ӫ.QUa4Jm$䦩[Zks85a%׋#pƹ)M!B }T]Smi1>%eGdIJ(qdr.ǓtslVNb? D4 R6z^.ڦURy~o&jꪮS 1\)8(|o^%Eej?y /yڜwO~|{fٴ]?1~Ţ3uԕy:eiq~0`mS)Qk)0*Vnn]I)u{{9!:c91ֵZVI("1RJ) 8J>TÞ)a y^yއV=klm4'.b|EUW%1+mCmSK)#)3ч?\c*[Aa14Uݴmw}߾0P 81ĔDZj0i L@TiY6 OjT c@\s& 8[tj\;+xc޾HxTZ+܎'= W붭ΏGt./+-׿׌eqѶ_˻ۡvow;կ~(c?~1&B alWJbHk ƄZ/K4ͧ9r%n64=۬]yEe$p؟sN1x9()%WJ[Y ٹlVJI!L,KɄ¥V~ڪ>K]?;WTz,Kc $?~7LsY Iݭ6m,9',.)B3& mmfe"f`deյT*SQt:0_}j[71 !uU|ɧJ~ݻy~ӻzS׭w޹c*8ΙBKu!,=>0@2#3y\dc(pR \bRJ(G701zZB ;?87 VyR\!9Sx E(@۷?877w7a43$V &pF,S@B!T#?2[\.׍6J[kleM0~lO'c]R_VBrT!)8л \Vm>0[m4u4m[a#!EfZm*Oɓ[D_l8lsjS52C,vWkb@fR[) D "Bòy׵j%zfČˮURucŠV&d#Yk0kÁZںc0GUS \H1'b9gBJF@ncinoo}4O'=Fo}vZRpٶm t<G4[tQ41J+eF*MRBI)\W\_1c_>><=|~ٮ^w=gt<~O-]6,2=.%y͂b<~x= gjkhvQR1'k5jQ'ѻ1 :c6u+6s .QmJ붶bNvce˔K()ZDZlA9kyO{f7庮z >81EVۻiƘ(Z)3$xf ,'M?N* !!%wBNVmqrι"`P!)ĬRR2bA]<x3bB*#:1()rti_l7bYO1B"ɻi $BH2PSD`R#s,pe!yyd3Q #Zr.3 -9sqM\]]-m}{}}O\|6|oLJo'}g?߿{DĔ6wc뛛W~Z/V9yatSUVƘiAp82Kզn6ۻW[LU]5|BD<2ZIɕio^o붪ket8f|1*&#"13NSp2J_H X$ 3bXWwr80||{>JFi-li 4u4UXJ[q1z*'1y@W*rt˅iLG"|mkɨk,kB>y8<'s$FT3S:7K+.<Ő h]29m~8 Cشm-l3ϐU*)Sp<Ŝ:Wjiw Qqv3p-mjS1 2C(p\RΧӱ{mjӶ-pv:a8GBL1,sID+LH~E]5V[ù~:%E{fG5t:0\]_߿zz]躶k&я} Aq]#1BR&CG` R0r`?yuws!/6R)|?ul-qKL.g2r~va !ns|qu&2ж^fb&BXc69ԿԿ>{cQ`2\Ɉ8˔ !Rm{{Y__ G> Fbd0UZhɥmUù%̇emZ4VZJUbV["} )s)rlV]J)Ï?G.آ^^t7wWUk#vnSJoR6UU9? WUմ i~cW݋'c1q1w-C<7owO|"AU?WM[39 F-ǿ˿DJUU,x&dݛVW~a)ٗ/k`Uq~tޏN#ϜZ NY)' L\1D3%JqrRII@ƈ qv9!Ҳ:@RbZ2&HD 1Rjei@,8_.RKc`cg0)B, , 0]]U۩^!fj<Í1iC5T25ʥX1͹p%T84%$~B @kݝkZas9S`œ77ZJDÂg<_/>~ۻ%429G"VF+)@e/!ĘkR)m5苉ZQJDN|ǪSOn9Dz~9zAo??7[_櫯,vlӸ2]~.Zvs{{W?ӜB$y:FDn~ӢOO߃mjVn݃jF5Bin[j=/xFZYHf X^R9irCX5c}o6z |THi,8CR\KUKkNsN4Ӫ{_rvz~Bζun%S)+W0ڦq|=W/P~M˒/OV3V/Jɉ7q fq"kЂKItikWAu% ) ?]')ר_SǗ:\6`QJ !B9gB@Jp.SI@8$tf|X?k׃G>- .Zm 4Kiך\Jqvn7<|u|c<8唅hvC4AD uYtFn/a !-? ZZgڏO1FiHdK 4e)E IDATʶ/SJXaRIz^akZ??M엥mkvw{j%gڇ{#t㲂:_j"(1\RIYkfgzwۛ~TFcTkfm\?|~='i۶ͦιQRO/>G]S`kjT.I>NuOvps?웶rSJ!.xvoDKJi 2]YӬXڔ|@ ہ4?lXUrm<4ZJγCm6MךV!,!0[h4BbRϵ% 6~6Ql^[ " "Ai!0b%VIYTrdVm%P ΔS @j(oFBT_1-A4 W,UG ,/Q"6V`PE bMnnq,D9R+ZK*8Ncap{w{wwssf+AdgڶoOhgm^c ,6eκ mGD%Q,ѩFV?5 W'62XkJ)0Sk%ksKN25h2VW6*q 5UY,()$U> F5\cRAhťhc,v~gm"^B(Pa*̄L BK,j4VJ.r9۵/eq{evuTt:%pf)cRk'Ugb2Z}fm/0ﶛ u~>}|99Ĺr =oۍ.\j!BP(`DTRk31pZ% bR}14R){SNDUæoJujb)J)s)iϣ=M)iO2Tj / r-1 t(@R d!ȶNi㛇ǛC*$ be2EIPN$|LgaŻ6$}ŗ\JVY)W1]| TDѵֹ~lя#R %,+ꬲV)%fem6Qf"Jv^_;]M똱T1Ki;#%k-0KL d.)/T!A)$jNK#:Mt]?Juƶuv]笕P lP|}X?Ki9FD̕)@J6U*$XjRCC%ZbH9G%bP r)%/ *ך_ig*oUDDRmcmK1cN)ǘR9[OO˿Hacmz\*aW9DYS*ĬV פieKԕ*neWӴ% k͵8S]HD'_Sa_|}f|~?|xwF>j_y|K~~iV59?gݦmM*\ (eT JBXHvw[-4gMeY㼢LS+Mi%$ie۶ΖRhyJ}\L1i9 BT3d(*92ܰ&@U&kRkvw{:*~E vsl~b.M8R΢R4]_VA}Uj RrM\sRj*%:{OL1uMR!yZ%\R8HqYzw~7ݶV2key8Xi&QYAy59Pn?lX +1R*c r>_kVJ!RRcKAV$0RJ ( Œ:ݺƠr5Bq/x /2Jje~KYj-,Xjnۮok?z|BmE!Kk)@uA] IC7H~󵳍DF]Bĝ7fE*i~`p-bRKL3|W*Y6ibRG!k~묩Dd!,p8Wf:le nL%VʗsXr)ooTD9knPOg o&fJTb R٩NaN@T UF_Tÿ_|c'\r?~9$5~|{t}=P=m}!niR2-KLS KJ)TJʾqy6ZO!k~3H!-EEy>%i])e)JN%'}o\ӗ‹"2Z=ZƵx(P:eUk@`NJaԲj-BJXRKEk)Jis "֕ HpRjIΕAȦqJ2^q!(%S i ڮ;ncJ5M6sJ!ZKYY9XXC-E\K]Tuk|:/? kh?yz?XcrC-Vٶi+BMcc*sVeiJv>ۦqH$QP+.p9es1F [@9߾{x̓kL?tֹ뼄sN9]Z~ߵNp~k&.LRTeAٍiR (  H'_St)e <`/㛸mcۮ7fӡ)xJ(%|`9_/z#5m㜵օ dm}SJĜJ)HkQT*/sp^L_qL)X(nAe4Z+d\63 #b! 13 J(46D\1N5?p(KrIq ^*9+R̵1&ckal?HJi""1Q6m;(cyy>QaRb,}a6ζB(=xmV*eDRC)y^.%,LU+TQ*(eq3lyy!LuYhV+M *+_e.R%;:>>~9sTW2q 4eZm5PHgU[J5SƄQ9r-\RT Hٙ}u:?|ZΚsR^QsZnӵ (if^5XXtpJa*D4t 2ƴZckۯ~ww{6-NK!w^^_<-RB0Wo߽m7kZJ,a9qvRƜsε렸R)K.!eF _"b-e97o??j$o?SN!S)ZUɲ1]CcaMj_fղkLejU"a^6RhqrkzB\۶ZzzZrW|wsۯ޾_x*j *1 FĒE!WZ]bKR^S:T !Xk!9GTBor1`e΅e B/  $J6QK/uĒ0"!ja"&ڠx\RʌJEBDI(B~Y%kIDo_|͟,@??QCv1t MJ@!RZrG # -u5Kk:hR]ݙ$BQ*Kԅ8cLQ\۷߾tVMvs8m~???Ƶ4 Dz:R_n\&cUJyW9 )K._J*miTZ,(R DVrN!Z*\ )P=MKfDx+" $RRkYUjW`*5DQjvðt[9r|z}Q!tC?z7 nKTxRnmJL ?nP: Qum[o:E"Br !ky9jzUX+J.%5ٽo;j抂L?^1wwðpz~~/x.U @Q*x4Mo6˒R *1-t\~D),)cno6;%iq51-ay)Q*C*ڡqBy4.a,ںݺMHe+n{F0i^/WeR#c./{v,M4r|:_d+0%eq>OOCaR/O]XRai ~kwMtre%B eu5JosF2<)zB\@&"e*ii4TEh\b8KM8WJ. @X5 HkE%P $^:|b5Si !rV^}.$+O TR)*$$j`RᐪY))5Yf;Zc Jq^?v]IzRF;k\DP&`A".~4 RjҶ/D9gRʀDHTFkm$ LTx]gǥZ+m~m/ZJ˪3'fRhY s^sĤRZNA)4F;T)sNQ 6=UB!ʐ2O1zDr]9Av7JI\3,٧T8 (V s,8\TF['Zj"ie)Lkݠ` pZ**%xrL%Ƙ`vԙ5׬jw-)\s 4AwHjs Duwu&^k9% %s> DTQٶ5X^ݼP*\4+5H)kN+jN{#t Kau)q(jҍֺy_?_Q R"XРFr={m{\tpa2*2k,QqCʹRQ2SEԍmqT`.Iג8u\gAѦը!x5Ҁr)5kbJJm,*ePi}Z)e)eYy Qk \ DDt>_C\3ZQb  D-3:&Yao\S^ySf6= m')_?~cRBJ)V*B) Jv@0Ȧqc*dlP)[c xQ]Z)VJ(W1xPj ҹf71fJTvnnu]^?OŇcX" qw d7J(>D)R APJH?#0ִ}sssv-J)}IO(8w^BZ)ؒt>=b:O~7~xo{lW3m*Di>0ϵer, jnw|ݿ秧ݝ3VѨUlڝLx^_?7on>9oo=m<](PJ" kZ3Gd"qv*KQQ(C.sfA]F!u]㺦q)!uPZjeRJ%+ Eh@$*jH1sr*|`5! >HTBMw7; TR )3OP\j Se5 I[&6fڶç1F(r>iLPbX\jh6]ع5BRJI)-!P(&P5t`l; ,K!W%Rjzp)4_$ ~/ay^>ϯӹ֏ 䜻=8T?_./)%ZmnۦB|r@׵ka8AzKΕs:% &h&0r뭵1S,TRL9@ijZJ՛mR.9Dn9Ě3K Xe}>ò,~aqƵE%N\ԥߴݦvpkf:^^O9m8#5(X )Œ3jցsR:\kI5KcSeq6VHmt 9, \9F;߾1=Duy}vfRg?]ǔRr߿yhھZeP1DÕjDÇem=T&,H S"NLۤT_7[XBH F"Jfu..ӶwvUz~HXJjA J)ĘF"!Q5L!.t: S碕6)*JDiw#RTB(!@Qz5(QJfDB(P eY&?RVzh˚kdmӵj}Ij-4唴2n4i\J- TJh69b b"ʥxa%aۻƺVkC q|NP*ZR>Ou#P# n@!$$Tx4]y\¼@Dʈ,unF3q?ʐ V \GVK)k*X$Xۮ)4 m ( IDATu;4j+Yt4΋sQ*KmA;I[41M|$cr#Q(V l*l*<{]轿\<Uc56R\ E)zb~^iF+!f2px8c-ɟOOϟk*V)kIaYJPY VKY:y3p80,V:ąc.2pZs KKR ,K_ (r-mSkͰQJ%D%QZ`@R-0cmcy~Yf_^?2͓5Fx8vW_}@r>_}q3t9rq4^`Y(r=2VZJM,ij)JuR "zlwvq1keq8>}ӏ秧뿖?/e.9QTfw8XaCeiH"Jb1e(vnQp웻3}{Yġ?X痫D6Z*~Z^>{sٟÇm߾ۿCǗO?iwvVÒK֕[rF?]ۘYg$$g*dnY,))ՈXK2{X;WB[R^sN%g!@J%Qh% KľkErD;HDJ\je&\|+B֋dЩfM3ԘK8WN0???{?`q(цaOo^_N1۷K ZF(D9R2lBuV!ʶԜKJ91UD7@$V341nA)i K S(I*dEZ1^wݰ~~ߍk? wwWy un};ȇ Wp{Be_wJ)k-|9KfPNBZf(D(1^_㳒8 R a5\k!&J[jcz%E 3S(:m֝_.9yH5C>D,&JVD\BX P}mZ?g{יv|l\3|O8g`  JȮ0no/Ӵهھm\#cJ&?#'.oZ+@2R!W`$ᗿz!/:qBBIomk~=y1:bRi?yylۛt<<9UαdV-#k@kǷww%dmB>@JB!ZkI)(hMWdVC? pS)um׷ww71ƮaӶXJ1ODZbӧυv;OOJHE*e$5lwu:umYp9Ηiכ~B0J(ev8sjѓ\ѱAk08S4T:/0CC EJ@[4ck;Di|1f?.51B)RPyvt>4vwp{<Դ]u])׸4r:|y k7ʵSL/ĴLU74S1F-VR*%Ng?/)gJ#B%(ޟ *U"w1/|1I0Uh^҂0dzl[+6hm+q% ҩDǔ" xF+Y%.sppZx -u^Ҽ %JJ`2//xOǗ~fi(zTzgXVqJRZk"f!JDdT+03TXϱB ^ Th̗x<~FAДg_*sۻnw%?4|iR*8cv(Jś(CY$vv `bZʪ^"Qm:D)e4}H(mhfJIu^9sCg uR#5)P!F),1Jn}o`tC)奏5yunM##uPԔK,1pw>9Jjy)S)w_~ŗ_0TZ̔s*WJXJ9$vJ8ūOI) }QRI;wo8Ok4OSkۻ]ZwTUjݽLO޾k/l+q^Ic>]+|H1A@!u:,+]?”B}SsixPJJksOm͍sTmU ΁1 ĜS1DGD"\!9@!#gY4\v }`1`13D$rVf;\91 qӶ>tϗR"ʐ~")Ό"ujjs *%Еj2drnuViuϟ~WT˸'%ѯt~/$X[uLTr)T !eαR,)y!s)7 ! +W you]kRr΄ZInܴMۘuǘwouU}tMϾŗJ~ڝ><|eg;Sv}g>ey]͋wP5\ж~kB>ORfS .k),2#PsD`PLUwUSB.ֻMeB QGxxe KX9'JX"(QratƋ9M]ncd?ÏOB5}m>P}Uhs?tm6Ȉq׏{<^|HR7&% !?ch@n 9R͋޾BJSȹ@r\8gP)RYS$):!&"%7Fյc*=Or:^N>oooo7 !TDMt4W Å 7s!PHeJ&キnY\N1.8'څK|9IonTdO }OR˲s*Bɜ4o~z뮔b<-1/q|,B<Նa)h6ª^<e!Sqvۻs>Tr.eC.R2$y*Rʒ~c, nFǘBJ!d(ШJhc 1L\u՘p8]v.yq6}T  8(p˼N8q΍umRKz<ጌ|g}Kה@i7yt˫Ͼկb+)eSnM?ϟ===.̳RZ q:ukuvqnMٹ~>p7#FB Tuwsq|| 8s@7\b)tM'jN<=0.˂QqA!B12)'C9(?_C)6攽)% 47n9I.2R^8f7ٯ~z.\jz*1F ! ná+2K*J.\p&cs$>c,<\p9\]uU1D(DHP 1@82 Z; gL~M[oZd\~=R͹ۺ+ DXyam>oTe~K)%( YCHR | ]uN1J@[E04\;OJJPɐG"6\+P:ALY0Pi[) J%RridN)CX)sݶ.v=.4àah>9oPUJGr zK'Y3K"9%B(P.9B))UJ-mUm,M&%q\0&q18ذ,1F!jxq9H 0d 3c(0RPĜ|J.LPpɌu6sA Tr)gh[eѹn׶q/k.m/!tUWst}p;/Zav͆s6qtnM9E!Fqx>o~K|>| i)L1_eJi^+B2]k\uujnjsy!)RٰJ s7ww_ko~ݷ[iq7ˇm7//xqYS7p>0Sx?]uii9  :]1ƘBH)!dYNXmXey 7Zs ޝB)Jr6Rm2ay."aB\fd9rJJ %r.x( BE.9mm׌8ϓ!k.5!@dLB@Ħ+cTRp>GMw:_>Ą SN!x.\ճgx8C%10NOZ0zB@@ #E%CLޥ1*kT(usJBp:Ok ~57!G@$ߞyjRr6ӿ֨*Gmߕ\/ӳWϟz߼x>01D*+Yj]2C2-Oߜn{/?toհai.i]vM?>~|vmmSD 4O샯.Ǽ,n6U%'(PJ)+PGd<g.9'.d^{H3\~7|˗/wk!}7s|OoޜOg~k.e.<-v@RUЇ>><!7@CdȔPXP`S ]W{osKY`RC JjJ)9g92r΅pmMU}\e^8c4 ںmv]Eb1$bfZS@ 3d!2CVyo]Sv77t>J)M|/|S<8c e4l:EC1[ökwksίHPbN1!:mo:ĺ.۫).2OAIK9f%w۷t*t=+ S*H#wv O*ij.R ˭nbIĐII!lu,1%Jk ApqSt>uх421U4]oS*V\\2Ƹe\悤%Z0Nx9yls %K%kK! P4 4N?q.RW/^}BJ5uȦaONngrLDvey8ev^y횶ͦP Οd1w{ s.TrAd8;iʘR%IhƄG&=ݭlNƹ`p<CݶoۺJ 0\& xʬ$L rfvjsvݡZڶھ) 2qբ\`{1_%8/}B,E&$Rpc(T@[\N .%RH!궒Z:86-R d׎})9*Iei!BNPjke(K WH%'@J8R L%+jdWWZWBT(Ŕ3Ɯ7PwPB(mJ: ,lvݯ~j]BrRH))f>c@,1eF#(4mXeƠR 5M3kĹS&"J"RJ ];GDȥ쉈g%H;CrJR\+$0,ZpsH+ˢR vXًWZWv,#Y e-j dU#2F@26f# !b(>Ӱ_뿲kx'>{.w6F 95Z)yȊ IDAT9||8 ^+\jCk@J H cȹ5\$Tvm"@bTxR״ͥS.mv};x B 94u4`1@P!te2ыVզo_;ςs>}̥h-3"w^~+eAӲz.xBʂCLX,S <1x)eBJΑrսZ1U0T(Cݵ7 1e)~ꫯ~9t޽yo~x,Vl#?__߮zadTqrS.A ٚPWUU7v뻾4,Ks,,&tRSU/@ŝC]}v-#c^i4͗4P8`!ƕ2%Y*R2U*ܲ<Ȯi\,$s@ !#$c J`Qr.G@ 0%SɅUæW9'뗔RnRՍ+FB()R)%H6d˺,"8cuulBhjS-0NW@u~ (Ca88cJq *6,?Q"K}|zt2La>몵Byi(iJ-հi^_⫾oS~epaJ޽~n~w_ȘWTuv4ͼ??OW/D+-TeD2$%B [Ւ+ߞ>q~ﻞR9'$jJ -U}kճe?mԊ8ލ8RRh}-q⺎-u]ƀ8rB,l}!qAIq͘e-Q#!猈 RJ1j}JIJy栌^֕L183\2Jbr1DB| 1/8ԍJHDQ)_z<=<Ӵ"73s)R@(kӴu4CD%`NJ`" ayJ,,#jjwMR H1եT P)B Rٳ~=,}u WKTLiZfΫ?w{?/7t|~?O7}X!4 J>|g62ߟOCFRtÞ ޵md2Ksh"Lfcn tCp8x>ct#h6Rj@ rDYR)!y^l۾o2('D kiC~U}CN>ufJm6m׶ºaȔ6ژZivu]u]#˹8 @ȹ 5˲1E)n1L0k9Sɭ>b\]ًu6(rx:vwNJb{ T iU C.D*DT BסjĔ&%Ee 0Mg^aM(&j8pYQZcdjk!9!r[ׇ?%)RR8cJ7B(6n]ݻ72m_f91J6m|CRkair:@S)g8Y'µv]rHMݴuk hǕ2U"t.sW*Vu`m6}uS !CH1& VWTvSq8]yZy'X7lU]qՍ}kYW▐!6 ve.绻ß?_&\\%pu.6Ĵw+\SV8gJŭs ȁ\qyo~wj5B47guq!@ceZ}c̔B@a]rqk ɇ|,D*amg,?蘁7;mw~k sn*c6ZWU->rXwmBBmjc9X2yos]Hm*c u*%sjcX]! "VFJ2ƴTJ\Rɬf];?8McR7?7uBȹ\VXs,H7cY%N!4u'(!#d0Sr!XJI)H)ҵ 1dȹd1 IL2JUAJRJή TU~ijaa 9sƕZi%B8=N("kI2)aALp-EZdRY Lp4";OOO4(RPNe!1SxZVZJlF2ưp%Q&ksQ |B%lTm__LJdSFDX8C05F=&dq)4'|)dH!+Y)! B1)ϓh77yaLK:R r@@,QHjzS5"S~дݶk *eY޿(<}\<J1d!*f9LO$/?sKF Rrʉ2]7}WJ^ͫs.nv)s.:r)ĐKF\Ӻ' s.ucMs8eiJK) amV)bT B@Ƹ/?na&EݶΥ8r C]W~ݬ>S ^ TF6F)Bwv2`i8\}N(SAͮm_f]P8u]CRLRy}IJ,qA1^r֬0伮1sNu9\ p&s~u6nǕۮdJCFM۵ݲZyZqY3!3uݶ{ox)1K.r(B(%sζt8MS 6U[71x\.ú؜#CBTF*Zh]MSZm_v9=Ͽ{?U/ p_ş7Uu>޼y-xS@_/w?;_mMg/^n.eo.]o?_ﶛW/^߿x\e6'/?e4*M Uvͼsigx?JMf||ϗPRBJ^i!̔# raSIyBB sHpnRp5"o緷1ty˗/i~8=? Hj.*A O6#ewe߽?[.cX/|cn21uY ג )V2'*"t˸vۜxIJQUU6mKe^qtN1wۛm)41ĀuuW2]9F/0ɯ~J)!xkmr)"d.ڦ>Ęs !Dgưk[sZtM%\JThev; 1e\Naab.,b@qӦ*NǓskܼ,tѕv[\JTRhԈ̮R7e@dEP"j!9u]Sd@ѭ1ZUwg,ǧq8 ǧe}ݼ|qbRY//nƻae3NBRJU87|zvW/MK%{k)yɘ@O1d,J-ꖫPN;{RA8ZsR.ũd.e.cN?Mt˕e._vі͎3nߺR(Bqbfhc>]e3ujWϳ(OiI>x\=VTlwqIׯ޽y??i%UJZmJ"gɌ 0aa4 ~&|})40O0ջU_WeoZٕkdU˱Y2VAK!kO]4g1!U|Ǘ(Y6vCTcZU]B)Q" j+f%"aTlecHZYJ*( vUsI)=<ǔyB4Mu-3I5Z[kq\emeYQv2+MW 4LORy"&_ͶjZ t>abj )|8OS>(K%F" " ,a*+[mt5nc}\QQ/[5@SN*qNQ55|\N~BzqQ4.vMRRC!\R`b)2.%@)QHfg+ֵs$DBjKjXBNZ)u1sfQX_}׸J)P眔u[KP 1^*R ښ$ %!1P0-q"n^+msN*yɃШ5FpH@!!0*cLB2HTDSۦCq̙4 Rj8R*!3_,ЌlL ~QB pi]92ιM̈́r 1!"KPJh-VV+"FR$#`|Y# `DK.MZ{TRdN|:F7뺪n۾Bv_wQˌ۷oUL9HH0ŗRj%xi7ռqƑV u8M1iCP1*0Gi^6F+ P]jך5 Ocr|yF%ȩ,s%QFgk~OݟQUsR!%e? JK]kӺoJʹ,5* D H)S*Qb4SJɇJ֕Q_MӶM˹%;K3d8/G?.B1V  R#t:<=(buOT96m4h \dES|&B!6זּ,cтJ0) d +- JZZ]KNY JD`UrY)4 |秧귿ݫiĥn3V_[i8~o^}BiNgTU52m/y<|zXZ@+B9~㌶BcZ=C!QZi%% uMsȑ ic1MW_VU5pT^{ϜDR4i:!e6S 9&yҠƤR$EZkJiJ T嬐rI%xbJ)S.R+RZ(Y r !?Jff,$$BKSFs"+YI!Qνy{sCFYoUt؟ _|YV[w1:H9eZ2K/$ѭW}WWkg~5 ǔUvic6Z06ڶ=y2$ %|EA%'4F i5RJbyYjy>_|7n~V+}|BHWBJ("tu IDATnM5jc֩ />B(% (e>yyxyI>XW]2 VUV9+e]5m-sN21DLM^__O'xvۖK8O}}}KUm^’RN? Jr/q]o6[` Y5|LsO4/JɒXy *P)LQ.!%TBJbD!hs)"|Rds}lJFVJ!ŘRcˤtij74]M]Z"KLHVƚ8Nq$d4O!kΚfML)${2S!$")P)vMN9R K-WU״qsU4Jy3jAr!yPwVOO>||xxp:n۾_/և9P%g@`JBTknv}W(a>n_zN0/9f)(90.cDQHFj^k{RJU; sR :8[sX@ad. _]6o^~ӯֹ8]|vug VδMkSR TuU;W T>ii Pk*kmqe46zwAU߯뺲Kܷ9mS@L=쟗iD a%B8i>yL55!kJP?e!J_rbXbD\.wǢZc P8OE)mSP*eu *#y`t1̒]U`__~x,dv}뷟w?3y~}| qJ)r!"#PAfĜs&"BpΙ BRWieRZ;,c$TڪZJJ! miZDw?>B" Yp%11)A 挊t%*VR(%RJ\ #bL19B\HP!hb#ńʌ)9%R!8 T1"bΥ$ s45ěhn^ua")T(00הaE!0"CFm+fri %}16?W>? #",Ғ?_׿/~7_~ç}9ą2}Cz~ۛo^w{9o_~uR|+\r)jmĔ'6RpZ:gOf%⹔94 @jzS,%:`E#&)p^%5Dr2/hէOOӲ,Hx:D\v )"rD|Gx?9+X9Z_B웦j9 RsJ%ZIa2뚪BH!FTv~4D)8NgFF;뜫SKI!URVf} %]S7mbFuWtr>{ b~ΧxH%@nVRXN2QND 0p&J)s HuSs٘p<'MYQTP%qc Ap cLY*N} jŗ޾y-x)$k}9Sbdme[̧Y7MPqH!u(WA)%b$#vn7m]*[<{BwTJB(5@8qާc}}9dtWޚJ}Nab8>8i2)ُRqnu۴"@iʙi% d4h@]۾oh&Q ̗6l똜uBJ K2ϧ"&O% ]:Wienm*P!jlD8 &L9O! j΢9}8tz& BEk[8f i-m[QaEWժ+  1Ap4g. dӂIC*hV]X[)%&lk9.PiMDd R(IJDRjmL)T5`H!,sJBRZiC)#bJLBOC9/x:z'0AD2ɅZlX )Gk_m~9>z:=@.%%fL"%9% M#QtcrGXOJX9SWUvZےiyAs̉R90PR)p]_}{_~*ÒӹTr*ZHDxT0%i>CJjWJ()0.BuksRDJ*!DllJ *)LJ"Y_Lm#%-_BM{wsWWD@YJi˘S"V2(bF(JY c<FNXkXSq@z{SCpB`92-Y,SNI)ٗ_J!TMݥQO]׮ׯWWo_9/M\//i̘r"(@ܷz2S*PJ@!Q yiY%3 &ra*Jb)S)2n}:Nhf&hrrNjJ^iOBw\7RR)Zk>xd"%V %TRBJȳHDbH )s)kڪvUcRCI%@) RR L]BI()%_}VM0Osm ?>?Q Ͼ/i(#ędJJ4FcTr!c)YiTյY]v]䔧N{sKDPmRO80TVZ.~16²p/NǗOQo嗿ݭB87)89uC K!u S6 34zIiFPY+R mԐn2QR(8e>3B9K&\u~yO)v?ny|WF5|j~Z]ﶧs(iB (6C)c9Ec9+22u_FBBu^i^/<-ɇQkXe!mF;CxrvU]q@mZ rXN1)i8ֳVK Dul6;cK%0v }6}ATNH pY_? mۓdRPUFjIT@ (z\]W&]J (]}zED|:>(gLTflڶZ)DPV;aZ)Nc7]#|L1{!(QB_4c`I|IZԮ6J#C) F]osNͲRB)eVSJJ)T崿zBUnZ]nl]!QH*e !JSR0[JI5y|aD: JH%FԪ&(\9/97uMeCL)efWW!X% $B|;pS:O?>jnA$ h.Ls)ec*1{(:QL@OyZ׷Ry,6B!Pr '*+̘Мb,p!$)_Yb8)Ra1'"h38CBp$&L1B%0E04M D4NF2FSIW9unz?$f*!$DPi]+>~N)Wf'oS.\ h)ez~|p8RJW7몦*\ǃZutg|uJc/|A()\qWJI)Q*tC EJQ5u1 ٥`YZ)4*R)΅PHt:޿j+%*T ȧ9N<]1##ln6uU)kuƙRXx<1WwZTTL<<,un5e(%\r*%]DRIP|QM, /g?P 8qh5K#)6ƚe pSyJ)j~Wy\N0yS)1r)G*Ea1p|acr΄>%0ǓQI]ӴƚBE֓S, eJRBVug/9%RB+q8ĔsB2p<N_|]մpv]uUU]׌0˲4Q%_80 8M<-mv]b<_Ml֛/i|?cR%\Y׵a)ZnZSP 5 dü,mQ)r>^ysgp|?njz'˷RRk<ȧ;mDL RFpBP7j5Sb!Bεuh1 `1ُJR)2'Fж|\5֖K- $צl҈e^J,@Ze)RѴi뫛_?|t@\8mk"q!$@ږR.Cet.QYs ĘKu0NbvݍxEKSjWwmZW $,n2R&"B8g (ԕ(zPi>'-MjT.ear9t޾y,fP]SkktNJ_wA_O]Sǟ}v !o??Ykg8:_Nݛw;iӷR+TV??>|4}~ׯn?1H9uZ? 8J|V7xڿ~~TRU~兙1 `:\P$1(C) 䌅i秗rmZqBY'*ċO2"8kՋb@VJj"]Zov>%ܬUͫWcf\uw_~q R[窶뷻t>,նiV!e^2E%R\^,4c̅b.~|0 νzumc<>3sTme Lw?W}}sm*~Z5+WM,A 0B\lxIh霪 !/~f)/,4QJUI'A0fQkVkmYVs~2rQJǔCj5!ˏ>~y8wmWiZ(-6U߯pͳ?/!@Sd)P ev)tifFm`u  ED,Q"^vz֞qy>$)1#U]w;g1pq?L~@,LSB/CV(1KQf&ct׮10=dcXW7TU !$D˲χj+7ӂZ"H!35MEm%2,)q I(}"xdU9WW[YL @2!1PڶZ  no_TrBa@P282S-̥n\o6~pȠAeB S%^r3bJS:1x骪YmuiB,9̉9gJ9c~*vqyZ9(Q$dB*RS.ޟ94 vl?eBY y a_\rg muӷU4}SUNKSJL  @gi.~AJ]Wu RJTB)er!|)Z䥈"+Ui"x/Z+)TDJ(b9\u74ʕRJsd&B<9_;P5nݹ)P Th%y<NkCǘ@RvnWZZyFfT9g5\eBR.yC %1c,hP%i ?/ӔEJ9ŐS%3bkkAHРV)sN)% ˯nM6umU훫59. 3,5X2T88Jmݾy{wVoN_%%P(G΄ R`1Sf$cɈ1|aYOMu((d>ǧ~ݭS!)O2#.xaY/XV!0ΉH_XgriP}B))14R2zf1)iS."P8c@ }){bVkZ*4"P _17PRTUץ4Wdkr_&޻jWvMH50$@ n1IC*2\>i]| IB(- Z鶵mۄٯ+heVIe U8g&$R"4ko߿=mC)P iEFD-fSI)GtkޕEIctw5F A-Շiu-kJLvWFF |.g旿GoobV7q8]$Rr$7o_}Owo9c %RCx?ǿ7?p?bDa󴆰^NW)Ŷs:x>׿yU}ݏ?G/z2S"!V$e\bJ eI+!HH-Ғ49 &R*!5yNR(eLӔcXyVR:guZuYToRJ(ε$o~|0/{<?y+ovi4L̠]cB>O/d.1c8'`v12O)R !H 2-!I(gHH/k1Z2$B.uY7oެZjH`nV .~mݾq-ȱX4\θV}ARiJ-B+kf/|\rNf"ΊC6KtF)9\BH<~6eU*Zi%DY2U~,\K1CP ļ(7o.2K-k" S\+S;o6ƨ7cȗ@(Tι~#a !+'o6//˒blll#¦\r,8*M{{޾ B!kXR7?7|\TQp̘PkB+$2$MIuYcbfB@ѫ[;"B1i ;mgkFI+nݾuqϥ֒|yRq~Na-6׍Z}J?\ u>].!/e>\@JY!eKΕ+d5P8BhЙfQ~|| a@kTrWXk6+mie~Z&on!D-ecj,RM 2K-쑉V (@*BD`KAE蚦c!ĐSΩVD$)BP vJI)$HX $ ct eN~M9a$umt:-ZB9g!Vk;B >EHmM'N RRjzqUԊtv8kH ,ff7 JRʵĘx ~wPr MkrI~Br%\yVaok %JM45nMoUJk6DTry| NJSf\j1|q]g1Z >5Lc$c͕3Zjg PJII(ZD`2n*8g\o9R >.2kUۘ6^VYnSJ{߾}W۴g1\(׸NQ D)]n%nZJN1q吢HD@9304M y^9Q) ! cHr(+K$)ekwv/0ZJI,8-@] 85kۻe~]b >(H9>?OWΧSi]7Ғ@F9I\R*ll T"fMW49!axiJ!s5XiALR8TseY8sM}" F8Ï~xq/R*ˇMiӐP<e4n[2"C &&VVa %KeF`XKR+DR\=WA9r%br!T`ZkV4:<|\5S "s)2s._IQ\JN%R!0kPJETOm:"hkT+T(kfV2އyM)T@]l6a|:o*c 0# `^vw CmM5\ZS1+15_@ uuo;|z<]֘MjZF+ 0ϧtV$ 2ZIr1B$h%ww_}_ioݿu_~?j)69g)5uuF+i8w۾/~k:24-aRK?!/_JRKD,g,⒖ݷg{ss8>?p>_WcJFm۷!R ҄+V(XJb1B \Zm1ŭuFH1q~acak'?NxVJv/noiL_~fXS.I:' RR2e.Q C!E+PBBB ! 0ƶ=0֥P޾p:SJqZ~6PrYV4]ҧ%Jiva2sdSuYKa!$->NyZvcW^R2ǚHb\B 6 %iEZ%(6Wrya.1,niV[À$Zq|?Fkef=DjL)$bDELc˔kFi95cJn:8s*cd k)Uq]=3^[e2eY\ RP֢]>zRmT 1$TS\\ِB6m+Z9H5t9JqMKɕRr֖K>2C!qYYi6MҲ3\N݋)]h\BPj(AU*eM 1ZbE]߿{BJ||~:Ӫꚃu瘂ZkM$jyKLkȐKL4K!j*Uq ! }u~٭ puݜI_Uu qƒTCVB62*00hnR0QHBRP(Yʩŧq3e8O4YmsP L`h'Q%1T|އ5jߵMgd.ZR*fe8t.)qunoLOTR*B~kS]6]o(k&( i%W@\y /&+sPJ*!5"=??뜶%I/wJiاǧ3w3.o_m i.E*TiT6mnm֝O9ӼJT׈%_B ֦q݋R8P IM>rk@@Z ڢ̵T 9ft_J2b,+"1RkuMӮ/YiJiARHҲ,8NR-RR !BB)~shdYR(FJ9MeRп@0!mokC.cEoonn^xABw}}RڐԺiiΧxVJXHW^9||ӧq؅tmg%1k&c5BT$` CQ7__w} //orc?_~oÛm^K-kdn{Oon׿$u}|lv3ǿ7_~zx> 9J)+ !%߼{t96wLs@@3JKm q./n՝2s-]%"Q:O+rGc(\WIyᚈ SIi\u]\˰kIV`now~,|nq5M;S*T6Z_{Ӝa]Ki6}|>L̞_>tkbJː(ulvnn)0B$T1 !ڶ9vB`Έ$Oh^%:Le8?==Zv{ssoSaZe0:}LK5WFpy~||~zX-$J)$"H%e\JF=- 1gX_rM!Ʀi\n6i̳1'Q8~]׵7_䫛L)bnvV9皚24R]nãVmܶ{Oe }i?O%GirfJPI (:+K.̠TJk~Z~)Xĵ76r<_yN)qZj*Q t[뺬ȬB;R*iaeyi˻իW$ĺ_=FB(!6r~ps&21%_c@"pZ}Zg׵*4Ԙ|@H(@*D!&$՗wPJ*##s%'H!eu>њ|9 <#Z[ PS5Z+.BRJmm-6xyz舀7VK9:C1FJյ-&0R;se˲flk6tNe̗t 9g/pc2V挄J13V`bXDB(ٮaS7W1_bU*ӶN1q l"b`*0V ?y2OLykaM qI  8뤒RJfPb1iJZmtH|%\5ZeR re12L2fsθt ǫ*,kVB "9@ ,dX.4zJi"CGJW@BaNS!]TJkKڦom$5yR IDATy D!DJTJ!Ҧ(J)b*EeiKaGvg_~vB Urm iM>~5 AB`oS aiZq>"ѪUm,CP$H{%_Ʌi9'fR a5:9yM>oS)uB+!D,3 F ,1rbBB[ gD`5Űx>_qH) D`75ƥT&!@*mkװFч2@%*KSx.9kT< $d.)!`,%K%u5Jd!Zkʱ\kEAB>cPi]S :úr8>˲4mtm*u\֜cv_~_ה=s 9Rynۿ8l]*u]J)\Ԓ>\bڶ۶{ubki|~pg$rEnl~~Sv/7mzk!e(@Dt}_7 c+ǟ/Η?~I*U?ܼ2>=>>?=ufa'"P~BI!0ƔXk-}E!bF !R%$"0FM\/!Fiuk]SQP|XS(3 o_v?[E?y*4_S+MBak8*m]B^SD_V!Ŷ߼|qM 4FKDN7,riI1TW}Ͽ\֪0AADjZget_;nWa>ܾP")Q^OZH>/k(+Wٶ!.ʵBP[P ~_F/Op|^n]ZB9R By<ڮi}Xk&54]rmlwMI,%71}cj.OӼ\~_ۿ(UAZ2b+3:+|_/5YK-9֦mho2?|B|Sp QJyzx,y20?{kNAvCNkEsMMO$2))XJTgָ~7~|8;Li~I~ \}\xCuڶF5|@,ZUil8"E4q,j5l_7!5xcl۶kƦ>=,ӊ@ζ$2CcO6u] ;r X P0s69n_hcR!qL0-ivV(q Il7 lnleK.kL8O9m)(-sʙTF+e6 ~r0C y>OyZK`9KR1u^/8%"g5CJ(R4RԈ}JK gYeYZlهl7]B%C(%ԀQ^鐱"8۶7oOϏ!RoJ(1k.%ͦƒrŏ=?<| Im=Y%@9,ڈ]Yu|9 TB)J+%8#3 (\>>~ʹMJ6\R.1RT@JĕZ|8/ww/v~Zb%3 Jm]':Yߍg_B*q1BBR\{~]eªUR m,sA%TއyZr$M)e\Fv۹Zjwm߾!!iiVK}J@Zr18 84cNr9?uԺQK9D1K,RI ;McͩB"VfK\8]׸|!Jk8θξ6@3)RRI\㔖5$E5k*"Ur >,**&ic1Z)@%A\jsafK}8O j]~|vB )d-4\1$U,HpMMI%RiL2/\֚CH깂 ""`BVۻ[י~w{D >$K,R!2ׯR*`\@19}NsckQZL’}J\rM&!nt>?K>!R28uVڴ6vTjJ9g* s)D ǐj,IbeԕXjR %#B+SR!pyZeiH" PNuH51 r.~11笌^ Is!$Z2M\H{>|zHa-X3L J)sLfFiYcR8k%i޽F*)^U H朠Tdj $JKEB)lڻRbR68MZFIu'?OtQ/Ygۭm|<>ji馫)eKa,8 SY\e+*ЈaͲu/9Z k9÷?P7ro?~Ç皗 WܟHƶͶoFign7o.\R`ŐjF"B]ΜC^cb6N S$k92!sE"ITq0Ce"DJzsE)Ip "s^uYqcRȮuWka]"Vֵ"O)!QHP\6Ms.+W ݦ'$mm7ےkJ3-ct:M,pmvGmݫ}24]Or3!5:*^㸌_1lj4lo]uiYRTT*3U$(r*~!Qꪘc?o~?׿9h4] דu,#-NӜnZ 4{J}wx~,O)nBK!\T <_6Ue*3#_i9/1%xq ¼l@d?̘kgMߘ}UE ژ*%i~w%!y@b!Qh $9ʵy9Tʹkb 6! ⺆rJk:`sZ֮kHM%)Tc:.sOV[mbXj>֔c1hVk),EfՋ62_}ma\KVRmv;vޯ>"VB' PJx/ǧ'@ۗV^Cq0ŐV>\3W/nYfu^gvFu6bsl;x9e ڮn/a "mhRL!z*BCN(8Sɥ?Oۮcs)u}96R)!U۶\kadBH/jj+게1Z3W瑹"6F ̵̈rJiuvJpY񲮫fnoڮ+oMRXD)M"d2pÕUJY)dQF)R mlbƧnr3M;;}5DS"R)ks z>4oVtUR*E,7X@eYuaK9۵Ni=M nsS6RHe:O_|B()A%cVPcvcYѯچB ,k6,+̵&HH&* <>qiuLCBV!݁'<:ŵb+yMa$Fb%ה:}URy8 4umSr[kZAa\#9kXkXblDBRJi(r\33HmuqefS)(:RWu]c|10 yQH*m(pU80%hVn}һ0318JK@/9#ȹxŦQHK )oJH )J,^Tiۺ+$"99 %*4CIE e_t.cpsJI-1Zr{d]J ! t7TUmmyǸ̇O,JkE(10CaRȤV5EJ( \Rǻf[*ls-=cFi((JɌAAQ|\ؒ TFWJc.DH(S"7UUǏ?~ ȍB%m}>5&;|pSUҲf9nsCu??="1@%c!sтsdTb F .6}L9{.|X2q6+A,kiJa:CK) R WZ"bd6RDtej!\5Kb+]Ua.iBbvmFDb}ݲ/|ӫG?M=8J !Cޭuݯn8"C0̹@*j\Meϴއ2OVKUU yN herE Rb1'`%F/m6@aUCBj9*Tk!\3]C!6V#own+Q*ίYkkUq窮4 x2(!hai>M1e|9cLF*-T-u+r^b%&J)9(G  M߭Ox<0LJڀP!<Tpx*7nj.% Q!đmJHv9?_ΧHq?=aZ!cI!Z<,RBzwt>[h#hKIĒcNtm^o zl Q&bڮ+VJ ɉ'JyS0F5mׯJ !))2W5*Cd,3,}aŜBPJ(jSv10du[#FD9 εҜ%"1N8ͧyYT"n.C|O;k/o}#%c H"8G.9TI뮪Zpk[[)_r~*TX)EbÝ ;4/nJ ٻ v,rniuX hQL9 )+B#*K@Pr!(4b6Zt|R)S-U%ZC!v 9Bp!\VLpd@9s.@FRh'DBebr2D( x 9YՕC^l!18>ؐ|-k4Em%ǔcJ%w.$r2LK4JU1 Ds1(%@.w1mt۶H.!"R<: H )IĔTnUK)E9x^Jj \|L1x]NXTuJȐ0(S hJI9SLIIq4Xuv/n9KNT2XbL:!buV*jeL&`1$炝gشK4s\NZmvI0 r(\2G"rܭf]UFp\ CJ"`sԪkTdRTZM+Zi\%u9oju-"@Lrs(3Fаkz!P*~,ˢ,0DD.EY?gھ[ L3eC)Ws)E5L ƒbI @i'?!#DZ`.%)V(ˆTVk `r=l0q>6)fË/M2ϖ*S)S"v RJݴ۷߾8Ӌ>B?=^^xWx~oO*șyS e@BhSuWqng7BY)Dxx~VOU]<|vZO6]ץ/x6(3Ov_uJ6٥93Z %(P` ZVpiYsZ+@a$8}`) WňIDAT|Br]mǘURUZ}_}HaiB cL9fŜBΆ77wiэKDDUq H!9 n 禒@aZ<E3]39Ry8ð|8Jp}J)G?'?z뷿ODQ DGDBJ%jˉǏk/jU!2gX+VWRi޿mk"bb%$ID%civ%n$?5ҮWRr2JHBΨͮ-At.$u"aI9ݡܰ/W_2ou]8*#QҶjկ~g}RuB}q t|z~Z+t qڬVn7Jh*x99Ť7Ba>7mK))LDq<_|oڮ##Dqp!cc*)S]@<|rٗRR*)}ۻ/_FO}xqssKń"K%)G8N;K1Zum眳;-j2\.| 0bun/ eq^nn4+%*ao?|)XYw勻~[-">: ).`mھ_#bNcʉ8LK"aZ/)9wnI922JK!cdbPJѻhq^&f^mC4seڴMrϟ>=~Y׶-ﺺ8cJ)}"#VDpqqSLצvwG!qFSJJ '"QV: rs. {ecVuUI)Z$!o*Rh1G[;% 2–AApdicL5A̅چJEI*ERBJTr,1SB 8咜[kR-x>zU8@nIשb:F?(b·h>LȹJ!]\C\~ӴF(O9757Uݮ4P2-ðfۿxx2.~_"%9t.[fS"d 5*^un*.x!@~״5,FGT8@1^撋jխ 'bD2*\(H\AQ0_a|7?Vo?MTUZW1eL r0Z_~n?Oys*8|ͫzb%sDeS֩!D]5ZB̹C>@;ZGʉC150|YR(v~+-it~FZWFxTJa (D8FJ.ŏBsDŨx,)Ңj~v\NOOl!ݔsI)!GHϥ 9̹Bz $"ƹZ]M5!wue w7BpsJVUU:r*T*cV5{? ؜2 G-P &8W!:a>OsqXaa}_J \k(Pr)0u)&ư65K!_އeYRJQ YsB@"Me8 ιg `Ȁr z0w.D <QX9w9_ wQ029\U 6Z+1 JJ1Ȱ1B)dS67\lqv@fXbFT+o7SN!*+tԺm:!eJi&"Ƒ7Ms!r,1QkUKNH1gS KI H .2x9<ŹE7;. ,KMUR)b}PUv)/e9 c s8`Jp!ʀ%URw &Uό2˧O|z?guRR}.-D$PkJɔbNq.SUﺪ]e}ksR.}{9`UpuGp8 x@=Z뜏)2U}zx|nw_ޮ̩ޟsIRr|pu=?|DDwwo^һPJw;ZypxFʇc^)%RZuc餔L%`#!(mDe +V(٦pǾ$ΧlL{w{w;>~8h%D7ZC)XbL@9[)m@ ^K)RsC RJe; p,b.9i0|"kKJi (%jӲ 8"+r S&ל 䦒JoV.LK nov3 < O<b 1P+pw?>o=5y|jtNu+.wp. PIT 5@*sZ/wǧo߾V+7BIiƵ01L9;O+ _?~/{>JkSW# $eDZp^nR2-ۭw|:zŋ?~ym2l8R ~_{d3֏֧8b7_~ӿY_|"(\+ĕ3ndedLaKR]|p-J@.}w7[.u.@Wc9g;*pano{Ho?}})^v[{˲Ĕ281vb7_ѧ4jYC(zFOw}h%^RI,\4]`1V\e_p924]`]]_5GB!a<<={gM>ms~<sFP0]oe]2(e9fk-c>nfSUxx<2Yye׍bN^R֕1ʘ"0ƥXusy.cctMgL+Ťa K5_&w>Mmf3!iZ|`7:ab D>%M+)^(%{)jweZ]!@^QRkZ2Fi<=_>X7K)r&5 Rشi]Tx%d:R8OGNPOǏ0ZJBן;N4BiFumն1x|L)}{䔮f۬*-eitcrww7cR* M]J\زXvWUR !]<>|ۏ{KtiY$۬owAiu=g8 6զWCF֛]iN䭵SHbp9277w[mA0UZvOOOe.eRFBwmgRHE)1+D1Jji9S%,캶mjS0<ʺR` RۮROG+ ߿}'XDfj]h(v}E ( KtVPhCr*).(R f[|9EͪZ]㸌c^ͥ6-D\B!c !q.ڶ\b@F2PmZ30 ~e ?=>>=R\)(\˔R. 1~xL)TZ"#$JW2c()N bKQUUӴv^NpZEj*¥:qœJ:iPpŇ˻ّtIME 29 ztEXtCREATORgnome-panel-screenshot u;IENDB`gxemul-0.6.1/doc/translation.html000644 001750 001750 00000041154 13402411501 017222 0ustar00debugdebug000000 000000 GXemul: Dynamic Translation

GXemul: Dynamic Translation


This page describes the internal workings of the GXemul dynamic translation system (usually referred to as just "dyntrans").


Static vs. dynamic:

In order to support guest operating systems, which can overwrite old code pages in memory with new code, it is necessary to translate code dynamically. It is not possible to do a static (one-pass) translation. Self-modifying code and Just-in-Time compilers running inside the emulator are other things that would not work with a static translator. GXemul is a dynamic translator. However, it does not necessarily translate into native code, like some other emulators.


Executable Intermediate Representation:

Dynamic translators usually translate from the emulated architecture (e.g. MIPS) into a kind of intermediate representation (IR), and then to native code (e.g. AMD64 or x86 code) which can be executed by the host. Since one of the main goals for GXemul is to keep everything as portable as possible, the IR is something which can be executed regardless of whether the final step (translation from IR to native code) has been implemented or not.

The IR in GXemul consists of arrays of pointers to functions, and a few arguments which are passed along to those functions. This is usually referred to as threaded code. The functions are implemented in either manually hand-coded C/C++, or generated C/C++.

("Generated code" in the old C dyntrans framework means generated by special programs at compile time, which output temporary .c files; in the C++ dyntrans framework, this is implemented using templates instead. In any case, this is all statically linked into the GXemul binary at link time.)

Here is a simplified diagram of how these arrays work.

There is one instruction call slot for every possible program counter location. For example, in the traditional MIPS case, instruction words are 32 bits long, and pages are 4 KB large, resulting in 1024 instructions per page. In GXemul, this is represented using 1025 or 1026 instruction call slots.

After the last of the regular instruction call slots, there is one or two additional slots, which are special "end of page" slots. These do not count as executed instructions. Instead, they jump to the first instruction on the next virtual page (which might cause exceptions, etc).

The core dyntrans loop, which executes the instructions in the instruction call slots, looks something like this: (Note: This is from pre-0.6.x.)

	/*  The normal instruction execution core:  */
	#define I	ic = cpu->cd.DYNTRANS_ARCH.next_ic ++; ic->f(cpu, ic);

	...

	n_instrs = 0;

	for (;;) {
		struct DYNTRANS_IC *ic;

		I; I; I; I; I;   I; I; I; I; I;
		I; I; I; I; I;   I; I; I; I; I;
		I; I; I; I; I;   I; I; I; I; I;
		I; I; I; I; I;   I; I; I; I; I;
		I; I; I; I; I;   I; I; I; I; I;
		I; I; I; I; I;   I; I; I; I; I;

		I; I; I; I; I;   I; I; I; I; I;
		I; I; I; I; I;   I; I; I; I; I;
		I; I; I; I; I;   I; I; I; I; I;
		I; I; I; I; I;   I; I; I; I; I;
		I; I; I; I; I;   I; I; I; I; I;
		I; I; I; I; I;   I; I; I; I; I;

		cpu->n_translated_instrs += 120;
		if (cpu->n_translated_instrs >= N_SAFE_DYNTRANS_LIMIT)
			break;
	}

Why the number 120? The answer is: this number is evenly divisible by 1, 2, 3, 4, 5, 6, 8, 10, 12 (and some other numbers). Long emulated instruction loops of those lenghts will thus result in the same host branch being taken from the same place multiple times, which seems to fit with some modern CPUs' branch prediction mechanisms.

The complexity of individual instructions vary. A simple example of what an instruction can look like is the MIPS addu instruction. First, as implemented in the old C dyntrans framework (pre-0.6.x):

	/*
	 *  3-register arithmetic instructions:
	 *
	 *  arg[0] = ptr to rs
	 *  arg[1] = ptr to rt
	 *  arg[2] = ptr to rd
	 */
	X(addu)
	{
		reg(ic->arg[2]) = (int32_t)(reg(ic->arg[0]) + reg(ic->arg[1]));
	}

It stores the result of a 32-bit addition of the register at arg[0] with the register at arg[1] into the register at arg[2]. If the emulated CPU is a 64-bit CPU, then this will store a correctly sign-extended value. If it is a 32-bit CPU, then only the lowest 32 bits will be stored, and the high part ignored. X(addu) is expanded to mips_instr_addu in the 64-bit case, and mips32_instr_addu in the 32-bit case. Both are compiled into the GXemul executable; no code is created during run-time.

The C++ dyntrans implementation (in GXemul 0.6.x) is similar, except that a fixed REG32 or REG64 is used instead of reg (so it is only compiled once instead of twice). Also, instructions that may be reused between emulated architectures, such as this 32-bit signed add instruction, are in CPUDyntransComopnent instead of MIPS_CPUComponent.

	/*
	 * arg 0: 64-bit register
	 * arg 1: 64-bit register
	 * arg 2: 64-bit register
	 *
	 * Adds the the registers in arg 1 and arg 2, and stores the result in arg 0
	 * (truncated to a signed 32-bit value).
	 */
	DYNTRANS_INSTR(CPUDyntransComponent,add_u64_u64_u64_truncS32)
	{
		REG64(ic->arg[0]) = (int32_t) (REG64(ic->arg[1]) + REG64(ic->arg[2]));
	}

Another reasonably simple example is the M88K bsr (branch to subroutine) instruction. This is a branch which also sets the return address register to the instruction following the branch. Here is the implementation for "samepage" offsets, i.e. branch offsets which are inside the same dyntrans page:

	DYNTRANS_INSTR(M88K_CPUComponent,bsr_samepage)
	{
		//  This declares a cpu variable of the correct type which we can use.
		DYNTRANS_INSTR_HEAD(M88K_CPUComponent)

		//  Set the return address.
		cpu->m_r[M88K_RETURN_REG] = (cpu->m_pc & ~((M88K_IC_ENTRIES_PER_PAGE-1)
		    << M88K_INSTR_ALIGNMENT_SHIFT)) + ic->arg[2].u32;

		//  Branch.
		cpu->m_nextIC = (struct DyntransIC *) ic->arg[0].p;
	}

Here, the M88K r1 register (the return register) is set to the return address (the current program counter plus an offset in arg[2] pointing to the next instruction) and then the next instruction call to execute is set to arg[0].

Although it looks like the bsr_samepage code would result in quite a lot of host instructions, objdump reveals that the compiler was able to optimize it to a reasonably short sequence:

	On Alpha (compiled with GNU C++ 3.4.6):
	<_ZN17M88K_CPUComponent18instr_bsr_samepageEP20CPUDyntransComponentP10DyntransIC>:
	     760:       b0 00 90 a4     ldq     t3,176(a0)
	     764:       1f 04 ff 47     nop     
	     768:       03 f0 bf 20     lda     t4,-4093
	     76c:       18 00 71 a0     ldl     t2,24(a1)
	     770:       00 00 85 44     and     t3,t4,v0
	     774:       01 04 03 40     addq    v0,t2,t0
	     778:       d0 01 30 b0     stl     t0,464(a0)		; Set the return address
	     77c:       08 00 51 a4     ldq     t1,8(a1)
	     780:       38 01 50 b4     stq     t1,312(a0)		; ... and update nextIC.
	     784:       01 80 fa 6b     ret

	On AMD64 (compiled with GNU C++ 4.2.1):
	<_ZN17M88K_CPUComponent18instr_bsr_samepageEP20CPUDyntransComponentP10DyntransIC>:
	  419310:       8b 87 b0 00 00 00       mov    0xb0(%rdi),%eax
	  419316:       25 03 f0 ff ff          and    $0xfffff003,%eax
	  41931b:       03 46 18                add    0x18(%rsi),%eax
	  41931e:       89 87 d0 01 00 00       mov    %eax,0x1d0(%rdi)		; Set the return address
	  419324:       48 8b 46 08             mov    0x8(%rsi),%rax
	  419328:       48 89 87 38 01 00 00    mov    %rax,0x138(%rdi)		; ... and update nextIC.
	  41932f:       c3                      retq   


Performance:

The performance of using this kind of executable IR is obviously lower than what can be achieved by emulators using native code generation, but can be significantly higher than using a naive fetch-decode-execute interpretation loop. Using threaded code as the IR is an interesting compromise.

The overhead per emulated instruction is usually around or below approximately 10 host instructions. This is very much dependent on your host architecture and what compiler and compiler switches you are using. Added to this instruction count is (of course) also the C/C++ code used to implement each specific instruction.


Instruction Combinations:

Short, common instruction sequences can sometimes be replaced by a "combined" instruction. An example could be a compare instruction followed by a conditional branch instruction. The advantages of instruction combinations are that

  • the amortized overhead per instruction is slightly reduced, and

  • the host's compiler can make a good job at optimizing the common instruction sequence.

The special cases where instruction combinations give the most gain are in the cores of string/memory manipulation functions such as memset() or strlen(). The core loop can then (at least to some extent) be replaced by a native call to the equivalent function.

The implementations of compound instructions still keep track of the number of executed instructions, etc. When single-stepping, these translations are invalidated, and replaced by normal instruction calls (one per emulated instruction).

An example of what such an instruction combination can look like is a 3-instruction memset loop on MIPS. The pattern to detect is a sequence of addiu, bne, and sw with certain registers. In this case, an attempt to identify the sequence is only necessary for certain sw instructions; otherwise, the attempt to find the pattern is not done. (Note: The sw instruction is in the delay slot of the bne instruction.)

If the sequence is detected, the instruction call slot with addiu is changed to point to the instruction combination.

	Original sequence:			Changed to:

	slot 4:  ...				slot 4:  ...
	slot 5:  addiu	r5, r3, 24		slot 5:  addiu	  r5, r3, 24
	slot 6:  addiu	r9, r9, 4		slot 6:  sw_loop  r9, r9, 4
	slot 7:  bne    r12, r9, slot 6		slot 7:  bne      r12, r9, slot 6
	slot 8:  sw	r6, -4(r9)		slot 8:  sw	  r6, -4(r9)
	slot 9:  subu	r2, r3, 32		slot 9:  subu	  r2, r3, 32      <--- (*)
	slot 10: ...				slot 10: ...
(*) If the sw_loop code is executed, then execution continues here (&ic[3]).

The sw_loop is then implemented as follows:

	/*
	 *  sw_loop:
	 *
	 *  s:	addiu	rX,rX,4			rX = arg[0] and arg[1]
	 *	bne	rY,rX,s  (or rX,rY,s)	rt=arg[1], rs=arg[0]
	 *	sw	rZ,-4(rX)		rt=arg[0], rs=arg[1]
	 */
	X(sw_loop)
	{
		MODE_uint_t rX = reg(ic->arg[0]), rZ = reg(ic[2].arg[0]);
		uint64_t *rYp = (uint64_t *) ic[1].arg[0];
		MODE_uint_t rY, bytes_to_write;
		unsigned char *page;
		int partial = 0;

		page = cpu->cd.mips.host_store[rX >> 12];

		/*  Fallback:  */
		if (cpu->delay_slot || page == NULL || (rX & 3) != 0 || rZ != 0) {
			instr(addiu)(cpu, ic);
			return;
		}

		if (rYp == (uint64_t *) ic->arg[0])
			rYp = (uint64_t *) ic[1].arg[1];

		rY = reg(rYp);

		bytes_to_write = rY - rX;
		if ((rX & 0xfff) + bytes_to_write > 0x1000) {
			bytes_to_write = 0x1000 - (rX & 0xfff);
			partial = 1;
		}

		memset(page + (rX & 0xfff), 0, bytes_to_write);

		reg(ic->arg[0]) = rX + bytes_to_write;

		cpu->n_translated_instrs += bytes_to_write / 4 * 3 - 1;
		cpu->cd.mips.next_ic = partial?
		    (struct mips_instr_call *) &ic[0] :
		    (struct mips_instr_call *) &ic[3];
	}

(Note: This is from the old C dyntrans system, not the 0.6.x dyntrans implementation.)

For large memsets, calling the native/system memset implementation will most likely be a lot faster than emulating the MIPS memset one instruction at a time.

The fallback check makes sure that the rest of the code in sw_loop will be able to run. The implementation only supports zero-fill memsets, so if rZ is non-zero (or some other dangerous condition is present), then we do fall-back to addiu. This is done by explicitly calling instr(addiu)(cpu, ic); and then returning.

(The example above is 32-bit specific, and only works if a direct page address can be obtained via cpu->cd.mips.host_store.)

To find out which such instruction combinations to implement, real-world code (such as a complete guest operating system with suitable user applications) should be executed with special instruction statistics gathering, and then the most common instructions can be retrieved from that statistics.


Native Code Generation Back-ends:

In theory, it will be possible to implement native code generation, similar to what is used in high-performance emulators such as QEMU, as long as that generated code abides to the C or C++ ABI on the host.

However, so far, there is no native code generation in GXemul. There was native code generation before 0.4.x (for i386 and Alpha hosts), but that was not clean enough to work as a long-term solution. It is better to spend development resources on porting things from the old emulation framework (pre-0.6.x) to the current one. gxemul-0.6.1/doc/dreamcast.html000644 001750 001750 00000042253 13402411501 016630 0ustar00debugdebug000000 000000 GXemul: Dreamcast emulation

GXemul: Dreamcast emulation

Back to the index.



Introduction:

This page contains information about the Dreamcast emulation mode in GXemul. It's not a very long page, but I thought it would be best to gather everything Dreamcast-specific in one place.

My main goal with Dreamcast emulation is to let NetBSD/dreamcast run, similar to how it runs on a real machine. I am also experimenting with other programs, such as Linux and simple demo programs that use KOS, and Marcus Comstedt's tutorial programs. These sometimes work to a certain degree.

Games (especially commercial games) are very unlikely to run.


Running raw binaries (IP.BIN and 1ST_READ.BIN):

(Note: This is very experimental, as GXemul's Dreamcast emulation is very incomplete, but in principle it could be used as a help when you are developing your own code to run on the Dreamcast. For example, it may be easier to debug things in the emulator than on the real Dreamcast.)

According to http://mc.pp.se/dc/ip.bin.html, the Dreamcast loads files from the last data track (from track session 2?). The data track should be an ISO9660 file system, with the first 0x8000 bytes used by a Dreamcast-specific boot block.

When a Dreamcast boots up, the ROM loads the boot block and first file as follows:

  • The first 0x8000 bytes from the data track (usually called IP.BIN, but it has no name on the actual CD) is a boot block, which is loaded to virtual address 0x8c008000. This contains executable SH4 boot code, but also some text strings, and the name of the first file to run, usually "1ST_READ.BIN".
  • 1ST_READ.BIN (or whatever the boot block said) is loaded from the regular ISO9660 file system on the CD, to virtual address 0x8c010000. For CDs (note: not GD-ROMs), the file is block-scrambled in a specific way.

Execution first starts at 0x8c008300, 0x300 bytes into the boot block, and the code here displays the SEGA logo and waits for a while. The code then returns to the ROM, using a system call. The ROM code then calls 0x8c00b800. In GXemul, this is currently only done when booting from a CDROM image (or by forcing this mode by jumping to 0x8c000140), so to boot manually, it's easier to skip the SEGA logo display.

When loading files directly from the host's file system, the examples below assume that the binary TEST.BIN is an unscrambled binary, since it is read straight into GXemul's emulated memory. If you have a scrambled binary, 1ST_READ.BIN, making a complete ISO may be the best way to go. This can then be booted (or attempted to be booted) in GXemul using the -d name_of_image.iso option.)

There are several ways to start running binaries:

To manually start at 0x8c008300, i.e. show the logo:

	gxemul -XEdreamcast 0xac010000:TEST.BIN 0x8c008000:0:0x8c008300:IP.BIN

To manually start at 0x8c00b800 (Bootstrap 1), i.e. skip the logo and allow bootstrap code to jump to 0x8c010000:

	gxemul -XEdreamcast 0xac010000:TEST.BIN 0x8c008000:0:0x8c00b800:IP.BIN

Starting at 0x8c000140 fakes a boot from CDROM, i.e. the emulated ROM calls 0x8c008300 first, and then when that code returns, it calls 0x8c00b800:

	gxemul -XEdreamcast 0xac010000:TEST.BIN 0x8c008000:0:0x8c000140:IP.BIN

This does not always work very well, though, because graphics may be initialized in a way which is not understood by GXemul yet.

Note that IP.BIN is loaded last, because that also sets the initial program counter.

And last, but not least, skip the IP.BIN part alltogether and just run the binary you are interested in:

	gxemul -XEdreamcast 0xac010000:TEST.BIN

See http://mc.pp.se/dc/ip.bin.html for more details on IP.BIN and 1ST_READ.BIN

Almost none of the Dreamcast's hardware is actually emulated by GXemul so far (sound, textured graphics, etc), but a simple 256-byte demo works:

To run the roto demo:

Another example is Marcus Comstedt's "Serial upload slave" program. Extract IP.BIN from http://mc.pp.se/dc/files/serial_slave.tar.gz. Then launch it in the emulator like this:

	gxemul -X Edreamcast 0x8c008000:0:0x8c000140:IP.BIN
According to Marcus' page, ? prints out the version number (V103 in this case), and it handles S0, S3, and S7 SREC line entries. S7 causes it to print OK and start the uploaded program. Here is a screenshot where a hobby operating system kernel (YCX5/dreamcast) is launched this way, by pasting the SREC entries into the window called "SH4 SCIF":

Here is another example with a 3D test program ("gltest.bin") from the KOS examples, which more or less works:

     


Experimenting with ROM dumps from your own machine:

As mentioned above under the Running raw binaries section, the emulation of Dreamcast hardware is not correct enough to run things that really rely on the hardware functioning properly such as games. Even more picky about the hardware is the original ROM itself. Even though running an original Dreamcast ROM in the emulator does not really work, it can be fun and/or interesting to experiment with.

The first step is to dump the ROM contents (and possibly flash memory) of your Dreamcast.

There are several ways to dump these. I wrote a simple program which displayed memory contents as white and black squares on the screen, and recorded it with a web cam, and then wrote another program to look at those images and dump the resulting bytes into a file:

(Here shown running in the emulator rather than on real hardware.)

If you don't feel like writing your own dumping program, there are programs already written by others that can e.g. send the contents of memory over http over ethernet (see https://www.youtube.com/watch?v=DVowfmrifN8 for an example). Nomatter how you dump your Dreamcast's ROM bios and flash memory, they should end up in two files. Common names on the Internet seem to be dc_bios.bin and dc_flash.bin, so let's call them that.

In principle, to start GXemul and load your BIOS and Flash memory images, the following command line should be used (-Q means to not do PROM emulation in software):

	gxemul -X -Q -E dreamcast 0x200000:dc_flash.bin 0x0:dc_bios.bin

Unsurprisingly, one of the first things the ROM BIOS boot code does is to copy itself from ROM (physical address range 0x00000000 - 0x001fffff) into RAM (virtual address range 0x8c000000 - 0x8c1fffff). However, some of the ROM memory range (0x00004300 - 0x000052fc I think) is still accessed later on.

It is also possible to attempt to launch a BIOS in RAM only, skipping the ROM-to-RAM copying, by setting the initial PC to use after loading the BIOS image. For the specific BIOS image in my Dreamcast, the PC to use is 0x8c000120. GXemul does not currently emulate the hardware well enough to get past a never ending loop at the start, so I also have to use the following put command to patch the BIOS in memory to get past that point.

	gxemul -X -Q -E dreamcast -c 'put h 0x8c0d7df6,0x8800' 0x8c000000:0:0x8c000120:dc_bios.bin

After getting past the never ending loop, the "set date/time" dialog appears. Presumably it finds a mismatch between what it sees in the Flash memory (stored date/time) and the emulated RTC chip's date/time. After pressing "U" (for "left") and "A" on the keyboard, the main menu is reached.

        

The graphics is wrong; it is a work in progress, everything has to be reverse-engineered and double-checked both with the BIOS and with homebrew programs and developer examples. Wire-frames can be turned on by defining DEBUG_RENDER_AS_WIRE_FRAME in dev_pvr.cc. It is also exceedingly slow, since it is done in software. (A possible future enhancement could be to make use of the host's OpenGL hardware.)

The following keyboard keys correspond to controller inputs:

	             8 Up                          A B C D X Y Z = Buttons
	4 or U Left               6 or O Right     S             = Start button
	             2 or K Down

There are no analog inputs yet.


NetBSD/dreamcast GENERIC_MD:

It is possible to run NetBSD/dreamcast in GXemul. A NetBSD ramdisk kernel can reach userland, however, no network interface is emulated yet, so root-on-nfs is not possible.

            

The photo on the right shows NetBSD/dreamcast running both on a real Dreamcast, and in the emulator. Unfortunately without a keyboard...

Download the kernel here:

	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-8.0/dreamcast/binary/kernel/netbsd-GENERIC_MD.gz
	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-8.0/dreamcast/binary/kernel/netbsd-GENERIC_MD.symbols.gz (optional)
If you downloaded the symbols, gunzip them before proceeding.

Start NetBSD/dreamcast using the following command line:

	# Without symbols:
	gxemul -XEdreamcast netbsd-GENERIC_MD.gz

	# With symbols (makes single-stepping and tracing more meaningful):
	gxemul -XEdreamcast netbsd-GENERIC_MD.symbols.gz netbsd-GENERIC_MD.gz


NetBSD/dreamcast Live CD:

According to http://mail-index.netbsd.org/port-dreamcast/2005/04/25/0000.html, Rui Paulo has made available a NetBSD/dreamcast Live CD. It can run in GXemul:

            

The image is available here:

	http://netbsd.student.utwente.nl/rpaulo/

NOTE (February 2007): The ISO image seems to have been removed from the server, but you should be able to create one from scratch using instructions available at various locations on the Internet.

Only the ISO9660 filesystem image is needed:

	http://netbsd.student.utwente.nl/rpaulo/livecd.raw.bz2
Uncompress the CD image (using bunzip2), and type the following command to attempt to boot directly from the image:
	gxemul -XEdreamcast -d co23965696:livecd.raw
(The c disk image option is necessary to treat the raw file as a CDROM image, and the o part is needed because the ISO9660 filesystem in the image is offset by 11702 sectors, i.e. 2048 bytes each, and GXemul was unable to guess the offset by looking at the ISO header.)

At the root device: prompt, type gdrom0. For dump device, file system, and init path, just press Enter.


Linux/dreamcast Live CD:

            

A Linux/dreamcast Live CD ISO image can be found here:

	http://ftp.riken.go.jp/pub/misc/Japan/m17n.org/super-h/CD-R/lc2000.iso

NOTE (August 2014): The ISO image seems to have been removed from the server!

Once you have downloaded the ISO image, type the following command to boot directly from the image:

	gxemul -XEdreamcast -d lc2000.iso

(It seems that this specific iso image was built using instructions from http://www.anytux.org/doc.php?doc_id=1.)


gxemul-0.6.1/doc/20140803-dreamcast-gltest-small.png000644 001750 001750 00000020571 13402411501 021754 0ustar00debugdebug000000 000000 PNG  IHDRƏVgAMA%`M=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATxɯ'I~cZ{uWOt{fz`<Fp 9p@ʁ> ,4x{<ꮮߞ+̸=F0y՝ӓ^*32>߈7"!`o@ϗ _ q__ pշ[#8wwYk!&ɕnǦme@@Z[ =P@씫m3LAnl̸Z*uXàjZ{0PFvHW+̀`dg!UR!a]4"SϠenߣ!+Cs]#gkYTA1Ql:nTH8D_xos߾Gy09l w{cRyn2ZS/q[r-G+~!8Q: ˢЮXcaQHIj~ovucƭ1Dd>< > 1ݺ/0E>pǽmvb[6vW]%nl]fKYQ LtWc& DX@w 80]mFb&VVK*B9g +s"L2Ō#L9:L " aFV{Fv2g-aBL%!Dc틢^\E10k&ݵCAL^eDBΗ X}ݾ"l z=_(4 ƺQPYY]Q vy )k%(iڶSU Je@WTP}o|cj4a߾wj==6-0Fy^AgҢ"l[]0tKkGlU(~!Q^wgYhӡ3P5A`2 <[BUyUH1(ժ4_?&q ί)et6OOM/ š!hZjY`xZ"e-hJg]xムS"1f͇!|bSvRox`0g㲑g 2zzC!#MzMeU]MQ][*aE6u?kVN}a)FF۴LbNZ0\d8MYwh ;e,j %a0 snWn2$r^Yxr)oxB$ҬDBE0nR1g@Gw'Y-fVabz0Lh!Dն!'Z0?FGM^GiaD @ݛ)'>_\e]5Zu-r[#`"ʠ(m$LJF\(fvhlcn]Q2 &a4pYos:c&04\nBz٦w|;VU~r-;;JB|<=Mf66; PYeur٪a V< }(jLJ c|o9c&mBvE5GכȠ]Z(;Mm \yQD8m!U`ȧ>1>Et0C/A=,weӨ(8c"_lrr8}uYB0 @^wfO$poҲlǰN M&A( O/V!O`6Pzv2F|ʮ%%k:a{M;G1jo3EY/.,Wg܋B?tʲzIboҼ; gg+&!$}kL2Nz A⭵:xo Ԑ`Bge-g|3_0 (0q1J))0yl6;&XZ4QG?8t5ыm}M׷Gk-`hN/r!" |atZ; = DiX-7F8,Rnx:}tkSpIB0NneY+)4͚AKRrƚ Dx>=YUUZ4_P7w{|>72ZetaӐ4*1i^4Eʪ f!c &ev#s/G^]U{h?ݻu@)+*kL0(Ƀ)GHPAcl{Aݯ-PƽO.yh1:OƑr' μw[nowEZ5?=yՃۇuNnjAS=b: gp6_NWPɓKK<P}NٶO{[:> Ï !r G~p_|+,SHyNWl1nQx8]~gW~z4hc _\- m %>(ŨRݾDo͓whҮ6l˦Zկ ${IqF7E]ןJnӼlR2/x`ČbbQFJqZ-n뤪y-y2^ :N,ʪ<p֌SkͶ8ӡGN) C<=W[<@!'z#.k ;]V"m&f:ۯygsu0|,ph2 8e;޴M]6+9s=|xk&yM,>!d0LV].8k;TWEQWe:Ox"ۺ,c]WfMjv#i+9Qm+|nt'1{c9+8aM.˻~c{AeEɊ:+MQH7P}>>(9[ÀYa!N̻WV~qU#ۮ Y Wn&I0F$AtMƞO=֥[W'|˫j֛ڪ֢D$范֕lV7߼˚uoxIZֻ"tK =Ƃն'qR:w|Ir/>[^"kDmT@UwD/үܙwL.6y>U b?zrz:_{xw> ʦڤyMH|I1T]_o'QXExNͮJ!JAÄԝYg1:Gϯ{ǯjW1SD{bory]hMcT[ZT7 AD WW2fx7Hl ChQUM#!GiUݫ<+;Svo=FD4<3fVκ;eXN՝\mXABlb7}?)-@>RNBۼ8RJ~/pӋ{z=^|O/Ӌ{z=WW_HQ䕭lmW)ӫWbBq2ej&onvJ/YәŶxݣQ%vynyٕߋف'âna~BG[0Yu3ID)ֶ3|dvA_yuݖUeVmL/Da,8f_}xG>B`Eڤgy|2˪DU9[l/ Ӽtqf'xZWt]-wQM3Qʰ캬] (%zӝ|Zluq@[$bvG[V6+r>~yU7U9؟"Lgk!p9ꦫ[1`v(r8qQۼH.`L[Wz+CA!D@\]exnQt` ;{ONWϳz44T*+-rz\N#ŊRNJpvn:Y~=DR$]>_f8Ekk)^_։ xx6V"*N#@4&EY+ѮûNۼu h)4 _cW dUFp1JC)+Y7m/%NlaTP9Z$F7Us0^dǭs>` ӢڔѤ(;j%'zLn2Nu$ {D)ͫ^#FIL"mӊ "? ʲݨ,͛A]m3_hPxl˺3ZZI58R>[(%rƩjpz?y"ЯA (F F[e^筲D#g\_pN89`u˽j}.G#\-]<遅pTm뭱d/%Fvz4fמ׻Fc:!yYmv`<9Q䪺=_јPI@j_n$1ř2Qr`:J<ƨr[R(;_`|'';ikZmܦjt_,&AqB mfFKh1)AI-FO.7 ('hCw4v>uZc} S,6Y `i6n;#c%JV#QKՖ -DDɲX/Q,QrwM' M;)!*[w&}$ Sg #XuhN;Hgً䌑mK!Ɯ]j(tmܕ?z=!-䦛xG:\Uw8ΫBXd R{®S]n&/۶Sϯ¯;h Z upe1 v"LVg!Lp`h  E CCR@dU6scwmz/ÉψQTPzS4j$ >ݛOޝխ䣓k#hVE'"-c_k c^0Ixk4#yluAYcs#|2z/$/K/Vu];*e 9:kc@]Uo>< z:p” \mŶj{P)aRJ04 ~Uq!tFoy4@+]7sHIe|Ӵ-%Gwq\*TEZX֕;'OϠsiQ-r 9R cYWTǭ5h\na-N[8 UmN7-i,&JEZ+;Kp>IϪ:KDQQX^-ӢfU-sDYFfGI!6@D2Bq\\׶'WB\um/%NP'£SBf1AvcȧCy՝I2%qgss1J+m\V6)( J;Ry\&Px:9ޟtTMYq.Nx:7]Q㫼5Ǵ:}g]aV5XJf:(ڞ\wEXiϮY%$axkl7GB"?ʑZyr2MZ.iWqQ0#aq vƞ_-5?w'#1$FLvj䑺OA|N)pQ@nڟcJ6seXKVakѪUXdƁ@j#AN"ΕM/Mhh';Y,AHkŞ9E]n1 4u[vEkuTz P geDfe ( %6:vB¿^\P/3 N)ʖ1lR>zދQƩ+jp>ǃ%{vA>#IB`۴{#瀶 tɜu]^$d*oF_ jj~ Z`,(/k]sJl8 2q Znӻ'']V WۢaKk YM1D/wGq$xKǡ&`8a(6eν=SzDIDATI A  R;F81F`\u/l86:m WUGƊqv@e_%zT^E_群{=^|O/Ӌ{z=7_V__6U&etIME ' "tEXtSoftwaregnome-screenshot YIENDB`gxemul-0.6.1/doc/20041018-mach_pmax_small.png000644 001750 001750 00000003544 13402411501 020527 0ustar00debugdebug000000 000000 PNG  IHDRP@gAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0IDATxX]o~x)QKeɲl'NoMb Z *|5j 4xi]؉#۱-M)~r KVK%}y<>(Y.&D$@b.z+xD2-x^8"Qy ogkp9 !c_ 0+A_u^rdv 򿭜#CNO,|S-NM__8.h,3Bk/e%1'XB>Ϥ%ͅ贲'ki{­;2TYӂy@>{b.z3` nQ4VΆ鿢Z؈D_xG<D2:Eٽ>/TB+,lWvrۋ_m JȭxK}ڔ@=*net+*+ngCPZNh^ ^8ԩ#g\u|tK]_$?O{lNGTuS$KďFߌCB#atA`Lt&\@ނr׶AY?Nۑ4^MԔ֊;[֨9Y/+4G!,{p@) $`[byĒU9vy>ₚG wU{e<FAY?{S@x٥壟̝dAZPzro@n]f&LI isd򈜄8M %LZsфu򾭀yXJFulgd$bqk Yꐂ%+;gãm%B:,J@@ANpz_47xP_$ ^|xL矱L-~jb4Rr-1Ӯyrj=fAP.hׯ2|#[O,ȫv12! !&@EhX>Xix]-{lSz5[^I>>P!tZm ^jnlRײq1< UA8}t!RɄmJD_ l}26sm¿P yFш6%m_΍߼ׯ(M%H͡іTe')ʹFNkg(:0:uR=f@'FT?^$ ʥ{`VIF=*F趨c3 ؾ!*tzo8 3BTr m."Btc–3"0=O͖ V@Y4omjm?x /tT@2?A8iҟb ϮoxݏosߊY+TSe L:!MRvd@ke`&?vĵɽ 21 vtLH㵴ܺvfA.:_H}W4~c~gף`NMfE8/أGHp|+ݥLp%K(0󪷗)vnb;iگ̬jQ-?Uҩqկd_32F+ޘ>4)sG,~.X9NcnŔ]@[$۰ͼj~;9:qCeOz%^7.fr3_^C%, xx)ǾItIME 1IENDB`gxemul-0.6.1/doc/20060724-netbsd-netwinder-1_small.png000644 001750 001750 00000007517 13402411501 022215 0ustar00debugdebug000000 000000 PNG  IHDRt^sEgAMA a_PLTE $(,0448<<@DHHLLPX\`ddhllppttx   $ $ ((((,((,(0000000000400408888888<88T88<8@@@@P@@D@HHHHHHHLHHLHPPPPPPPPPPTPXXXX\XX\X````d`hhhhlhhlhpppptpxxxx|xxxxxSkMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 /IDATh{Fr,^.`QDz>~I!L>Ô.ct*)%~zObO$;;@GlOc"e@meL_ 3쳇QW.ApC6ÞT쥝=852Y5X8<i\anY:[V7SFy ۃ ، ? ׾lL`?}=qNg0V$ބ/0:~s/uk=<:T02CR01Кy_g5e]oTCSA@#EXCM47;DRtG3&n@%@xڶS}uh`$/.Wg})])~Jx$'B/~#ahCouOjF D""u,uƀ`[]weD8O9x>9XflGrţpv66䔺< XlA Jq#.nNԑ_"R7"P&}ݹ>j'vojD7\ɦX$2\ɻ&{J`?#&(vrikrCݣ^{aֽfE(M)O">AHk,bҍGήm#a: xN:M Ç܏;0J,#hinoa$zFyO9s lp1нwQ*+$x~| 'YhU\eym1 AW٨ة I-o?3[5N@ "GЫT R_jA"nhno)mțn]M ~&B6阇d8&Zl!䨅PGA%5.WȔq8p\݀6WM ^a)rF,-Wi4|y'MbvnҮQTik OE%Z,"N{A]-m(+n; rn350`? ;7?xع$^="6iI d<ԬFWG]Rb , -8PqcT!}@b<+$m yaߢn'ۨME8@UZ⃖a'sm7-Xfi4ʿ>Κ*OY؉-PG|o~ &)T!zZT'z򛅆E a'_#У68x/G)ͨElaU=b ,UQLeY Op4Fbtz8/MҀ(wT@GUg{<90: e9T߽x9xX{x__/V`.^?ϧ}2G0]e]-xOhqM7}7ï}?9|wٟ/Lr"uDX%6~J֏`s:??Z-g?hgK(E3'Kd+b:p:9]/_˟r8,dzjTtJ=K0ic>(a4L1ȈԌgeYYQϏ6ae&NTsU1rpT_Ow0tjZnh10p8,T0lN ũLsO ϊZbt<TqYmtzqpW/W?˳Wg54-N+ `|;zlʱ*\E5qUΦ`M?68!:sP?mno򓓓*??AA:<=OPQcgi[]]8MrJN~YZZEGG^_`񠡡uuw|yᛛ578abq]^_GHIcfirtteff79:sx~qql}:36茱4;Qx肨씵|ꎍବrqoWXYZ[\؝@Aؠ366[[PTn69:[fughiLMN 䴴 ײ~:=?t跲*1Ht²k#ry룚rp{|r=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATxolg~(]sdsJy4㳧C5J]G2056xL$YJlR^PD|PFmkȴs%*CIߠa'97~7̛OyowWwyWSf{ A!YdC'7 Ac }J>=w/y BVЃ֞8tE C|_ɋg=E}aBUT*?u6rCCP|*7}:هB(A_qv+D XEtO\Wó%% Cjomӗ{)ƾ}ol_r'7z͒%NnN~@&,LU &#Յ֝F(xN\ŧ7ծYCϓGJOG5x^Vξ{{VmWD̈́Hz3[H/>z)b%]e*tãGVIK:&%`(wrkk\Wxsxi냖+bqѣb'ҶJ|H#VG3$.~IjSV`}*PJ=sC]-yE-6O;fiLJ<~Ah;>GF?Zmwʙ3E矿/p/"T;bP*ħtΜ1qT ?>NIk6U.QkCG]W^[ pE+5 LZ" GI?K%//O_J\?nk/ !peJI_V|q rq͹  U9]%D|Knmrko6r"2RGq%`B޹[~0:!m;K+J|^wIYg>J1,%">Ej%E[$ /LO,m}=ޥ1wgr߿s ZUvDO8_},:O{(n<|:() N|p-)b->RUڼЪ~?URZXmlxbS\yj WΰЗ|*SSCرynu_&PCS@o7cܱOEq!B|d|Q> oLlgqwc+K<JԝU i}%C9}D$>6R2x+cbJvŏ(9, MNߎ?O٬mZ3ثyЫ}F@{z˛Gwdpad^wwE93q¦3rK·EqU,OzG\~=mOp/K+.9qGwW<~+g\>(|{]|=yWۑ{Ҽ/URZEkTVN7wmV#FW_e3,%BHyc'r2'$'kDžb1~_RFEqw/V?y|K*$!m__'Jʓꡬ(I)\KږUhd1iGxbZ  |ߦΓGRҿ{ugH9i<5Qdg }='"9>O~ġ/.oݻ,O_l} rom;iӈM@EL/t WY5O_Py>/gOriypUӸ] ܺWD"URF.,ݮn"X痵ΰЗ9ǽCO ]$%cKZ"d|Mċ"Wg y2M*v\ߚZ*:( UWm+?\mX,L`st_[C,B+I=K<"3GlF[:<;}c# P!\ES&ŋ?%3"Ը]m҃R]X]$Fcw,BOv&)AGة/C[7Oz3b|%SͺDyHBw}?[Knspe7+RuiGSu)VCߡԶF k7u+W?:7E?%֋m*c#W=zVҳ+%R>g&RAPW T- s*CŒS*B,twqnwzfya ~X{|QtID? Rď'xa}pȽݶ?yVX|P 1/~[qGuZՋ*J%]ݴ{!R#IR? -nyv|WǏj+~ttq(}x<~\15!~*r8t—7ǥ \*9\E K%^mm*n]P[}ONO_/ne.h<W/ב+I=K[KugHS4͚nJ"<.%Um^pa^ Ћ~KhzGw8xZΧ?&/xw>xrJQ0WFm !i|W흟 >>, ҪTװmZO*jX]۵M.6BmKNH|gϯ&"Ehr})VN*WkjwU^mÐ]mrY0~b(m27!r{Mّ;{ߝ8#&vg‡x ݩ( !)_(F(IGWqŏ2MUU?ċ^JV~P;tyj e%wjo~x-T\X2M ԏ@㔿ooM^l *??EeA]OϜ=,%|!mBxQ+W>xQ ?-J0iEWխ8EZEe*_K_E]vQG+V|岿$t煾ܷ!(pBO4Hu/-gg.yeMtQY'clTc)t~|[yh_[TO~lORJ"tkʠfC8,r$U?-XRl`3 {_o߅uR~KT6 #vJ~K] D EP"B".!(:{ (zeAPo|wx"%oB! P#B! WnpA B@h)BAOP}䦺4ǹSaI i;ǀe;uvvs&':gUZ͸.m. ι#W_)^XZ*P5LG]%X&RyoiɄPr]w\vjaVE}uތB! 4ºzd>"|'=L|Bk]Bf;01-oN%z:J]5!m;Nng׽R4ߞHyJB! 4JG ( lglMȅ?gRBD (Hewrq^_ouTψOLunvvkܵl(If?oqݟ7c\o@(FT鍹3@^!{:w88.!)ZCeGPZp\ivNm'r]woyB.Ef1G*k{ݞ7~@(FB,(Q/-}oiM" G{\4a73i3??n t;5kr!AV?uy,% B<(^F:KxdCfSj9E`n9.'O'4=bt;5nYBh?I,Զ6餝\=r@&-,|%dP}D-(HueDj ?75rq?fVüa`/DlG9;9yZN^I MTZ}uތqB@h.݇/ޘ#$˥0оvM+'k|rf{]h=zZNms#'ivW're;5.Ium3ycJ- 'ɶފJ]@(nW+m_@(BIW'l͎B B kEf jHCPBLC}#kp7B 6HvB#v 3B6BcPu~3=[KsDOՒn=կNZNƵCp4" PM}-ԫ%l<"O^KGZ"@hʫJPʙ3՛KzZ[wM4mEj- q9ng׽.m5DB[NW{t>:;Y9Siy/kqLVc- qNng׽.mB8w/ RwKtfmzb5q- IL84Pǥt;5uo{fB[H鍹WĻ3!ݚ3!SI]=n㚭 zC=Ul-}vr]kFl$m-Kj;)MP+gICzhy 6b{v Vђ4+Mvvk\1d %z~?HPf ?Ql<.Y9K*Փ5Y[&NS*zzĴCvr]kyڊI^-,Y9n75Z[2㘭eQkiqii9ή{?tRt@hkyf{]ʮ+DVZ6.cm-߯M1YERլڛE5mZlg=[_{폲.m; 4~O  E$' BkPˑ|#PduMC_z 7BB!3 CCL@(z1Th(@(i ihh%ZMq-\=B9  N8-x Bk4 N2׭uc\ƒWWKduUI5Y%BuQVunsⲖuZ"ۭm/!1%%I9P߭5+B][ -s:ח%*dפ$O5.mݺ΃hq~,#yiH8 6H;VAkaQe.]:X䕬D5.mݺ΃NZNQNY)J 42b1L-sXz䕭MZk\^u΃NZNaolDp4XY @h/Tyns[#D5,yIi?|uE 4C]C2ui1L-sZz5=Bz6 jl B;i9GEKdtRayGȎ߃>@[aj:׫%/9WY^~-e4|i(\hl9}GNBų%U3ǀe;8~\ή{c}Ono>Z/O@hSɫղ\2fn1t;5.k}6i-mvA(W'0dzdݟrEDB%V BݶDvvk\K,On<#_/c@(ꤩTydjrzuU3P6Jyng׽ƵR6 CP )ޘ>[-;YN Tcd};Oj9ή{kR6 ڌm"6B%zZvkYyh!Cj9ή{kR63@h}4u7(xZvNkzĴC;)Uvvk\uHħUB* &Njl9}lD&jլK3.QNN޺9zP,Ono6Bc@hsjrZO-UeYU {|)nOdkvv=uh>tR3"B!2>d j˸@h@(AN˰ 6q BP|(B i(_=:b$ B!Hw FOˊP䑆d@(4#BZvhkN69 d@(F t5ukɫZȫ%zP_ls4\W]%)Zڭb+Z+l\|B\?@hcĮ'B}XJI֧jkկNZN5kxU,SS@j#ycu ْW^P4#j}*v~vr6B#m4 ihhZWK^:xDylѭ%,ԽկNZNᜅy BNC^-yEM_BZڭUIi?ظvI PCQj>z;@>G~-yփZvr6yY%O']πVLCjoBzv IDAT]hZr,B Hp-4$50B1ֵP,! #K B"o.~ l$|B! MڔB! B@hd|)r3B[b$σ@h@hKO Z^+gN}4ƹSVc9l=Zlg=Χ~ehM%mz~jTrLzD6+w.)uqYf=qG.ɷ>PYn|k}tvRr%zDJ-mjW]t'ZN^ZZnU5OY`(O ԵRwKtfmz "% ,w.z|ZN^ZXnJ[,ɷ?Ps;wKgB:5+gBOz B5VJj,ݷK>>-uq͖ۄ\[?5O\8o-~ B%ztޝ&D!Ut,+ȲCr]l}tWpkl9] 7o9~D72f,pWWONkzr[,=K:>-uqMۃúV%XmE~I^-,Y9n1YO-w7nEOvvk\r;=?56G@h[@},gץLr)nOdk[U h5.E+u֌|)7?56G@hO VtXXfDh+,[= 4,K^:F^-yփZ`㘕VɃ:ҒwwdkRn=_X)`Z%[#Rs5BZZXJIn=_kY)< @>uْW^P4#j}q)փ[l\; GؙHy@( jk䕭GDߝZk\Y{_9 'P B5Y!=oz[l~q :;@>G~-yփZvr6yY%O']P lXRNjih}ZڮU-iS\ZB@I-j:.B! B[fq! jjB A@(B B /5fQPB=*BPjzvVҝܨE;eOq+|Wgڙ#F+hrʣj]|om£Z0r'-%e?Iض"SfSN^zߺU #~,Ud uf,8>Q[k2E+hnKwt;5=-P-D YSx3]f:gMVԫba+jBRi[k2%+hnmZ9ή{?~+"0|Ps;w fuGs)PVԄ\[a4W#YArߟөZN^zre/uF踄PsʊZ>koqdCjWvvk\{[ G<@h?¢i|[Q&N{kGL<]ng׽翅j=cF tW fu91%όVMM~Sc븜'usL-N{[/QB#r_Gkgv7YQ[}ZQkrS׊T+h5f)S^ݞȞʕzPkm<-J& iJrn1 GÔ;4ڹŬ.?B B *BP P( Bꙟ*BP Иw%>4me@h Mv' Z 6 B-םsU`JjԒn=l\sАC(HYŰujZkv{٤O;BŰBWֹep&;&w7Fǵ[Z ,#~B~ih!bX\28[>m*8zXZU0>RNM}@( PaYޭse%A9qj/-F GؙH}@(;`0Ajg1lYkV{i96["-y:*2CB(tòΥҎfؒn=劵Ahv HCd:fZVO |HC-f[P3}| ihS P P@(:B&`1@(6Bc i(ڼ Nj!`(ڤlP Ԟ i(yx6[2_=)ʩU,,}ZJs:km!ՖC395  B VdɜIqzsI}9jz<~گF1ݒ$km5lq |E ]Wb6Z2Y%rjLxt;^@ lrEIڦ~Wyh*А T<2^cld&;`:/VTnGKfʜx-Ҳy݄Zkn\v_硹IHC(1#HޭyiV"T.VTnGƺ͋OT0 өnXkn\v_硹\냽i( Kald.[tqrjf_NǣN [a~W<4ً?BA(P +f%bڧ'O'rjlxtB&pWm76#ܸnyh6  B>Պ0tVOSftTZ(usLbmGqlE?qPϬ%3EZSf~tF jS^ݞȞ=eZqyh7xP0mFY? @q< BK@q=>jj( AX0*BPjQ#h' BPk"#aaԢ?:l7]BP|_ Rx2P ?cVG@(ڬogpʴ3 Pj"ԧ%ULݯqmCnj5Yu@(53 PjKגewM4 n=R `6Y9uH+fih R_K^Xgkjrwc4p\K˩0b$/3P[gCШ"3 K^XgK'-tvaS `6Yâ=)SS@ jP|/'fXMˏ7ǵ[Zq*agn# | C+" UV>5Ȓ`U<"=-]l k굽Z;g {9UVRdk*~=$x\K˩0n:0<Zq<7ȵP-|(:%UN0>߸vaS `6yY%O']JݦШS_KkZgvzVK;!Ƶ]j9Pf-z ݐ?47Fpxu7}EBn\g4jPBznB@(B B!j{G(LPjEZ? BFKMPi#P I@z@hDYYOZĹ#%53dz<~ճOh>j@szjP{3ZHCкȫ!'<}Ң\R\Ԓ qfgZ3>NyZq C8M \W\VCBnN%qjɬ]Z]-ơY"CYV\v/q{ C рP &JG ~,2ӹ#|{'VrɚZ2S=ݏ6[\n,B~}XeZqu=ŵ;̀X@h-ޘs$겏jz53dr{<kum>Nm'IFD]V\vq{s < B}X.+cNiC%kfjf_NǣVy+IyD]V\m縖)jP>H4 @~rYY^X?g_$I#%XkŕTKM~jtSZ@h< awr:ɫ岺ޘg򳜾|Sf^-~յx△ni=QA׫W[f{ 4.Bu/ԣ3]wIw-[UkfjYُ6cܝD%zҥ_ m7 BBf5?7>BJCP P6Kj: P ZPB!ʇ BPk!4anO Bh,T1m @b@h(IB}@H#ԧ%/e_Iڮ^ kNCꓡA F~-y k5L'p\K8f%: P>Bq-4 hK>=$_Sڭ^ZNٸ#yɞiHxzMCcAAh@_$l`7#n=rj5kxU,SS@{@hsYR$Ksڭ^ZNٸv3P/ A 4 WDxiqb{o^P 9 'P 'bh$կvmqzPa߸vaS+d6yY%O']P ϦChP_jK3;=SAڮ^Z(qYpk={(g#L'ǩxA ~6=Ba!\ݸ3Be!PQ ABPB!;O P O PCyމS"zA꟡Wʟ&_ F(2v.BPl6+?2[;}Ga_4hwՅu1BM?>kꛀEvj]Z ( 4Z Mжa8h$9%L7m&>|G/ua] A-PJMyYGY0_=EG; u4 AҲ'J6IwS B}OIE }v: }mPKb{5J6i3R7~b}O8[룳M8mRy9[R#}@(EťE =~a"I{ޤEhs֖*էԸ;á"4;(.U^)sҵR&vq4i EۤLZuV,B\[KU5Hi<ȇ>cMȬ0ᴥK#WwJb ]\= ՗1$:q6) g>iz ?>½hwSN G-^=7˰B3n٥*AEBB+4]j72B}=fqk,5MM:"O `Ҍ}DolDUOI My*i<sYh"5>\(.mIoRfa Bg$:\.- k׈fL2R氕zݹM{4ނ9Dwpg~C9mh  ?e֟xFȾ'O t3sB''B y' A@(=y P#?PB!o~q޿%l<BpZMnʠqf;%l~>@(*>䣂P˦Lj lXJn&juJzsqmMrcLBmr@BPE\f3K-{KKFf]BݟΔw{K]·3/!9|, rYOi΢Y@sKcTBL;rbYNQ)ьjGDjBY1+i|@BϨ"ԯ2rYݼy=΢Yv]{!BvjˆD/Ix;+fbhBZ.vgRP?er}=&|[3^PkP.kr&8#Է2Ehr ߞ'S)NP+fM IDAT@(|-BZ.ӥwqBGoeЌ%BۦX1@BkPk? T ޭ9ngiL'Y1sNBq1ڇ| ԯ2]zĩB[/!Ti75ڷ2\FPӉ5KCð\VNS%z^fPکX/g+[Y+f֢_@(*>)YB6̦2 VTB1U ^>ߗ8޹" 2># E6GQHCP sQHCPu0{" E2 g" \ǁK@(? m%F  PMQ|Z=e^ _o,%7edX'=f2 i0 {ihm,!B.P:; %HPH~O~0,359βS㻫etZL0ߞ B&>q>hay=-! #y?}(2k-]LGh0S6"tz2:Z-W&vPD]5em @3*ihKZs?Yt΀P8eHuZL03#mf? g@tY[\g)HL/ú`. %$QݞZokv4fpЖOC$uNCð\q0LPA#eZv*Zt)1nb: BOi(_C\ Bs.诅nu ge5[-vUl@;ynaIKd|mlA @huY44 NjiŌ>q.}d@]P2mtA%)MoTr>h[my`Жj/>\?xF`MC뚆U,P { B@(T%WŞLCP}1{I* PG|+1 B! Higmt"!5k&:Ц  5|󥡁-9b*6ir@w-qzdҞ_2E^mtr<ҮPj& EkN)˜٪Dлs٩Y5LG=] B3RΞ*cq-rziWe5gZH ԫ2}pSg}qKʍQ8zh hJٟDH6S]Ni78Z=󨳰,T{_/ j|rYRY#tm91:KȩzBZ.tjlhjlnq !ZUV<,%j5ҤYhmdp$_442RճTY28-zzkYnR֟Z=󨳰,,4ߡ!@(H,+e;)q28zkn[DOK #A_e' bZ'q"BmvE4 " yS˒$ wRdE#yҎ>jl"B!TgP˒$ Rg4) =1PB5Kef{| &tgrYl`AL˕_&?yRE4" r ޫPĴ\'dE7o>;~AGePO5T\v Z=)8~nӰu3lhBZNUP˚PZ*9Y{W)%rTw#ԭ2BICmgޫP˚5BiZOhEYC姅\wUm3Bi?Z-CC(nB=t}hBiN^Ƨ=C @((i.gPP;_$<: < A@r6CB_c0 5Z{*ºm-~JhPK^rS B[ Z, uuزFrYseL*ڷ%h]|zj}&V 5~xu=V\&$諀BC\N~a 4uvW8]q jh)GYV?W} T-T{!\hN d֣K]=I0Po5M ry}BոJ}nB3 唁]Do\Y;o?]A@hG|Anu}hkܱ8CjSI<#T_7s]tj,+K̹sAѥV_M<BZ.*OӸEx%q?O;&Ag. [ҷ|zt, kZ{ʴo rsxֽ(:+ |BvꐬX0*ZxRWB9C(\ : ԯVbC5Rus,9‡9 wrׄ]`vW;ynaI֣K]=Е5C#4G&bP)nOdχ.yFZ-gW`v/ToxAi= kUI#t+B74АР*]ЦM?͹q1  H?+|ĻPN\ B! qp" Bh5mV@(uJЪJO&F5ykI-./>p?0jZ>B3y}v Bՙ3P4&m<9y1'-WlXJn*)\k^RBCBH3}jpry\vja֞JX?{KKsI#Bsu+e 4vch3#ԯZfSz+bqI i=8OxFNo!guBwz #J ]ZהD_p5Bi.Ot5W%g%ʙ zB!*߻WJH☗4ѷϰ&v@h3P6kvd@hS%G5B_岄~۟-K1M'iަ(Bi*}ݠkn;А/AhtZC_;)y o}-K:󦛚4+-?M]DɷA>?vX)aAh,i(\r9u;׵iPSϧ7ΥCUnWZO/5?UGmvX)a_ !y%&4嫚GyO) ɶ^ *BCu>1GHLUFh >17ofEh,WU2w Vk@(V>P B[~6SGE(_[=B@h9h?TK|V5 8\BP %W|Ǯ ZJH# 43F:͂O~-MK_ZyZp8R4uPxnP~%}ꬖ#PRPi0:Et÷ɮ|E_eu?<5 eBdPl\p=L||nNZX3kV@(jϷʿ Ch:=2?Z˕G;?;8oaY9@h2  e4 ej.B-+N̹sG5f f}#ZuvU rg'BYBph. %$QݞZowS02g u7Сj eL°\)mB Z B-G)^t}>hodv9 kfI@}j + _t?kj*5[.v4#wWH 8BgW|c岺ӌjLㅌP2=tA)MoTr>hu)ۦX 6.By)QFh0ERWQlB~` p6z@hf  / MPB# Dh#:= BMr14B! .B3VCPBFІ'jg2`h5B,BZ.U>}+jYZ/GEG;ev퇀P J ,BZ.UG35z9n'mh! h4|kLdƨђX^EΖ˕d9,C@hC F'PjTZZ/PGe-6M,C@h# F|3(jؖL2sr8u\v:ruD/ۥY&K퇀P 4SdrZ iD?-~;(Pz9:Z.W]V.2Yn?ᜂ'PjN=;Ä$CEre%I"N-oREh+٧BZ.Sak;@^ȧǤtY/PKm⬗.e2m?V1%?e˪հ݌NjiG)OѸr5[.~ijLV@(dF(Ďa WLB`( @( B  MP'5*BUQx;ڴŔ<ZK@( U U\MNtj5O G0#9C)P B"Bɻs٩Yq$热GH&gq(HCkPߖJ}h=j=]cX6avޛ@hmr) B卲qUjo<2x-TNҮAQikt pBP˴PޝД8Y-WfeڮJW"i'-,|5|z4-1Z6C@hX5d|(W kw'ݹMҘIBre:7*?f=`l0jHCP(dBm.~@(Le3Z Vxo՞@( @h{]P BP@( -P4팻Р7%UIvm,zç` $ 64B}%0WCVrY Vw,#PCb,! O&:ZKVrY ?IDZ2C@h@_Lv~MNה-u1=׻K;\bunWk(ȴ}vC! :_ jP U,uat_@!'b>qA852m~B+.;ZK\^2)P b]:j%BZ.KOBGK7o>@v;: bk !BZ.8Q b5`nթl8>v|@BߴB-}!BZ. \$yO/=Jzˮԡc-uBZ7v@hmr9ӳ*΄;!Sҩg zg Y2 nS|hGBkP,Ъ!K|hB ɸZEza Œ|5@(P ji&P>4L# BVF&Fh;O P׉(|"K! (|C(|FID}B/B}Y.9Ћedi\pL?ܞi?- 67KDyP_ĥ1H 彥:`<ـjLzYKq?I#[;}lt^'z{~L2ֻ>:;[WY9J(|6 BZ.Se5Bu~6? ׆k;k|^)E"!cJ1Atn]=jLQ=> ԫ2Zv"Yӫ#tx>FNηOGڏsm\k`JDyrZ-;Yk~b?kf:,DI\w{>hݹNik8UEa2E/g$rZ-;YkHJPa$hv*Zxf_u3u!b ԐـjLz6B屲_V@~vjM]D+-mg~L[Xj)[Z6C7~/O>P˪ղjE0#OoK⅌ͮ.kkĀPقPI73߽[7Y6+< Z Z" P(d BlBB>PµP O 0#( BP@nI>P PWO'=5Z&jcq^j_ T(5" 4}6?{ԧ@H~jz=xDr9dlrr@6]@7DwhlT($ yX%oOXT Oy $<Ma,'mP,tm91::zll2nʎNUOPV3j_S=(|}VÄRT1?LJZN+yarY\z@~oyB.>BmBZ`owFh#ta`~_bqҾ}/ŷطKMb-LYLluъ|H,. *7ݛtUrNxZ/kL^#zZmSdt` 3y vy  }yQ niN~zmUZ[Zy܊_zKt)7mz+%L^쮫uWsEZ+ {Z3%[;jG_e28=L#,!j^vftg:,+O'qN Î}$čZ^^yTwwѯ[oŋKgMVqe^LkN[~]ls IDATZKZ=7iu8P)+>J(BM%퇞9Ѯ1 }oC|>Bo}v vE SQO<𫝂Y.I9JOiq]WKN` UUQ@h'~+ l8K ֧ttk}tvv-.]*\K3zB{P(m>P>U IEpLӖ<61zBjE~-;6Nf>G.nBfE;N[:ruD,cg E.^P1kr}6 uϛv:qd[z*+on2B@P5D;io 1k^JcvKPM;<ЦC_eWoYrYTV<vu3T́%t:GL$1->VB~-~^eq0eRN'qt"tB9(vO!F_ek[\V-MMJkqh,ߢI@hj] eq:;4Ŭn7f ~- ݲ8jLoA^6Y2[iu3T=rFf:xiz Gсd$bq%BtRIT~Z/xڕC5@h@*dMk7gxÁޏ02:Ŕ>FA1 j,!%X2G #Y6X4fFP:M{sz_aȈ|Rf}TYWf~'2#":R*t(5 6BIA(B@( Ę4= "~8)DHPr1y"ƍPV U 剨4ݯrK*=N/"|؜5#1-\PA,lyErH,12* 8CI bZVDz#B(A*y@1ĘqT2)ktxTנbBZV|59ewnPO#l?e"O*Y(toYB Zqc(ezL^8f%CW] E u-@eLew1ҋ$yo@^gyCޜ u}- -\>Yߣ N7w&}m af*\UׄРj9RY9./c8/=:{㣻i EQ. ˪fԄL\JYo-*|:j#)Ĥ!r*圡~}2wqHUvjBhZ.%?m;hۤ&- ᵉG 1i-\{;XzTکgoRT)D*~Dex$z/ChQ2U%{&FNcO4{7ae~yAhjƲDZT,FE9PaIS/B_}?wfq/Jl?uEhQ` )ϳs-vEΫә4?T%ղ;ZP5c P ۏИl(va^y hֈ|` UW#E P^#Ba hBsBj#B&!TӃېLk+(G1=-\nC<UMwHrӃF B@QWT#-\RsYaC7a#&X.X4BCʑ{DeQ*be fcχY Tӥ qyʑ{Dei*bw/^gy ˯%egys/I%ɻx.H?ǯ{UV^V(q#tLi*b7B;=kwk|)z_wQm#wj헫KrB N(B@hrz0GE׿6:(Gn͔%ɃN Q^@(bZVRnkh>83z3﴿x/4Ifcy5٠r@(|U.T]_كD^hJHW.}3ʌ=Tn7 p8ʘ9^.ɟe|2!5GiDhYT{~:PRݓzw࠷ qrw[tVx"ʛf tLPM(2jj珅3v7ӊв#Y}*ztz~]?B/ґ3rv_{5mSyC٬Oa@L>IӍ`51:"j(o8SвBE;F{BQ\S.oN bɤj6t<[G(K*`/5$=N@(([PBoDcDEEr7jCSp=/T{^ "-@c^_e'#P 1E@(B@("PG4XlmDOIQ71Y{2n ]q}) IDATMR-qȀP(lj} v5 =zRS.iKhǪB|cμT.\Mb@hە[/]^,+ Zϟ1>gZ>{_^xe3_G*PM F:Sd v}؎|t޲fK\Lڛ-3;UM1ߜ 6YoxjT:˳._#022#Bc5#C%ݜo7׈2f_PW'MVpj?"sڠ'omD+άu!4+ߏNn=AqܹgG/4S,SBKXB9c!(O_d T]Aor"hS<7?/`zO;]poN;u@w$MF }uϥi?BY$B!ԧ.a^h4wS·݅K?Bٹضڭ)H\rD>L4"D:E'h: 2B2BPT"{+s ELQ/Yɪ HBPĔ u#PA<+9L(s>-RJ}'wIE0ˈ R|Gh΍פ"g;e(#FO-diJE[ZimgZbZVl3iFmGA͔˖ vDE%w*uڊ{ aju۠@hYv{3LPCkێB B(ԉ. yB+*Ernh{)M5tvC1:+R FICpc I@h2 )gՊ˦:;zڎBZB3r@ЩEhY2ˉa#5)M5tv'yA4 -V.S= ˛6tTrRCg%VhȽPb2ǰٞvﱆMl#n}D~эn+B*^HT- KlurQ#՞ziMgd ;DU eˢ^@T-7P}gR mv-WBYO t]C6fsP~P t"T{)lrfz[1V/ "녲 vzF|9V/ "@]GFx_ E P/#AzBP#nW~{%G*ǥf{E=LjP 9d hB+*ǥfWE=y@TTVa h[ZVag/RN]Od}n,<:; (&5$BRA7-\ǰL߿;ک+x 7n)} DfU.طSͩNmÏ7_\vgwIn>>MvfqxS0% S=-\&ձ_,6_NP)s},|9$ۣ$9( &Bw&v;}>;K"_cCh6hqR# e˃9ک.{waldvBON-!z̢>/Zy:dOCeˤ:xyhffR^g_^'EDd}e+/.o zGB#:-\&q0sG;A(BWGo !=tFl8ɧ`VkNjQ .sCy\y."T{t R]! GhY2CB? ; BfgTB_$.q9R0jfy=EG<"/s!o=Xo|g̉iHxD rT!v/u[q3^.,// e&ggIRrym ֛ fC,SK#͙D&HYj:^ ya GP'H=y ʙŞ#C({bN7B9 "T S\~p'r#T›UPfyo#e6BBVB>>L݇)9INjIJ>NB"Ӈ@P hB@(BF^| 1#Pz+ tob !T}wf{NbKh-(mrY'skʄ?Re/qZp9y^wow=8w-ryXާ&n Bwf_ ;|]=V4.Řt/rQnmC'Yyayjoum,}WSd{ف ^#0׽Jek;~֫w֭sD_ٞ R֘䬚WhU.S婽wV;x5:;lltJek;~g^(/[!Q@\J"_/TowB'e_q=;Q @7q}+sv{Rڎ*Pu^n9KE\jQ}!/~@ rcX{>8#+~NUka*Ow4腎 ~ZGx wSUbBc8:-\&婽gTw/ݬ- I:,vDcz̺' ۿr4!$MmN,U.SyЬkozZWO|eǕO,#5"?65çTF?5d'$u@(Z9T?BF"@(E & _?9w=N{( "D(1c-و:ɩm#5u? 9'YZ@)ǥf~B HNE,:@(:ḅO@[PU*X%\o^(sO״'@h:*(gԷW9f5vytvֹ'9:EЃx$$BaUTRd>2O\UjD[=߼ypoL>{}⑨ܪ7MЩGhYP({xR9_]Ï7_\vgwIn>\33ߍ=T<㐟FOUVSҾgK#S #EhY2)e֧ o7gB˗Nh#\{mkP*4җFh5rv%SÍ{q%$N*:/ja^h[ZVL i}_}vɟݻ ;f';wR }qρQ#?o{u}sEhY2):OٿT|peu|rg;Y_B,D*:. <AhY҃8iB(BWG1VWk -9c8il+h B*I}/4OBfgc,u/w_@(z tDeP!Ԩ/7"^.,//3bjHIeTD3Ȼ<6+QKv}q6Dk;T-B F TD)x"nWr"Bϭ㡽#W"n{fWjύGgg{_~;8ޤ BYًrVS;g>NӛD 1ƀ*3r| ^w}m̓o} fyw_#MVS;waCx&U@hCibOZͩ6:W$Aq]Oje/p^̲~v3 14_Ȟ@! n2GmryȗnW.͗V7*{S,Y}rIGIrQMM}vL-gdxC|̜92"7Ƹ,vKikU>3UB[\No@;nxX2.CKޝddi|0<)arzKO ;:*8j:=h>Ye#aB\&Eq=MeP\;Bry//"]u"v͕ yYώPEYjjGr,B(BLaʆ"z+NZ^h6S0pB>D-ڎսGL tRQ/គL<*=8 >qH}]rR`x{,pu7ӁjpG/Ֆ@OT 2mr9;B߭Q"rayy!zvA()f(pj`6xO0~B-5p#GlÊ33}I|m0˙Sq)/>53xYp$PIB#H̷OD(B@( B'A51GZP 1enb2zHzsnYE@97 wBuTQT aI#,}!_Nb yd|p ]06^PvKE@B^I .m2ǼIE_2<\|wտ>i>I.Bu!z[AhЃe; 6$Yz y:t¼,1 "R}|'7}B>}\J~p?ƽt8g~8^Q6#@(b>mqM?Uqtz~-t$NyMä"F PV'EO=@4ѴG)GrjPB(1:MT%r$ SqetM=Y<^Pbg2wp,:oG*GBP$}Yw%c]RX9Pr@(q!( c\,)V09"G/tiPCKqއzBPy$E(G$P 4' zuXk{q^;@ 5m>Kqʑ0#$zɳ+Fv$ϭ~š+s8{k9ٽ0uqKE9HĢKIʑyNBj+]zo{3s;WwEYbZ΃xy4mu<#@h4B_οg;N^Ozd,x`A(c*͠v^$ɋkyQ|Sޜ\lg=O|rjqiäƞ45x"ZYRבRZgd8r+1`r\>Sq̕}NybmN/Tv4ϟвqi#ƞ4 hBf2䓮V~pn0B f3D/=7_.<|6B|SA%B~ BcσxӆI=ik 2@$XnVчor-1fvgkoC {t!?g3N%BB<yBI^h;oIB1H%:;-%BW's|?.^h{+}3:+}nGI,"yA㆓GqC{ t-(&Pw=3 OPjѽЛv$ŲT'{fמؕݭGl+v'5Q~6PG߹?˝i?RTW=35)LjPVf=O0?M]yІ~?{6_( ŲP'{?]|- $+1_iW-3M$,o94>zZ/.z,_RcOz)  {0gZ#\[dy#T)v -:۳koV~!%töBoQ^݇~GS.(a7S[/]^S}+B@+b˾rB9WNл̚tqLWG8xvvya/K<[Wk{zƞ_Ry(w|2 IDATChu" ퟾'>یPUN$,$ӑre$D"N}Fg޾WS":eRʙJaR(.'O{w~g^0_/8x摼9}Cutݎ&Aߗ]h(/lҼPJmv(Uvu}-:z1 t”ˤ"3¤P6zj>\[y{o!ڸx/w4 PBaP`F*$R\|8̓O|@h\0_:kUщ!T݋WBRj_%ku),GR ~6n yw!_VmV<{xre${F"3XiֳZ]'R_ϐMS腶^L/>審Vh tVV?l/?/P_jٝGgqc5&6PX\l3r+퟾'W^(q1eq:S.?T S3r?i݋GVuʪgwwC(X] RX=rEOߓȫ(j5(ܞQ|H#K{ȷ^v@4ju- 129qNyS BLjb9:ZX7I@(wB!CLB@(BP@BYًrVS;'u%Os@*b\]0Ѓ7^xy;d5yxwAјV7 ɷ0*d#Dchz;=]tMyL+}]Tl{+ ǜLÇP:&%Pcbug̙'+rohGdyUB[\wR<,okSuNe-䑆CS.sOk&%M셺Y?\Su0Uqt{J~2~:S@h>\NR0qϵ}CUfHUɁ=F'j_R֗aSF.Vyʅg~Caq~}cu3! 6y/퟇_kvc8ĥM:\&Ub8O7ɽlZ~.ObE+ܟz|.!T#{UT?SW{0Z4y tyAP.*XSv}i?I^ĺTf퓺XQ&yyb0g~0AhP{'1u.j7{ѽPu& 鹐g&BY3;g21BP0ɐ-fP-u 4"VQ%IzK:e^~]y$ˣhJB(mrN7վBLByhJgGjyTy$B]=}jzO+}B\8 &e@d_}s!)\56MT-*.>5s]yJy_{$rqs̓>}Cu?ݏ_0C˷=bhM@x}%5.yZ˭5}kM)B*ҁ:9r }I)LB^G(呩ydvwHy4<Cer xj<)4Wkʩ5\V:P'SԾru0~F9ﵞ<蕾46Kq;QkmȘuM#[P!BkW.oN#/)\5RT-*s̃>3~Zmm}̃^{$r϶_z͓^X{#{Q( 0rm;7z]F(x"<s_@(dwI\ޱ];\}Qm 3$'kξ0""&r'SF]I,g8j 1j5h_ "&YS|' C4/PW "P i@|y9>m!4gD5E=W2Rv@ 1B1gu!X|d7%!ٳ%zZPqTf__9WL<BKY}K˃syi.)z7F0K=Ƀz1,ƞoyOFS3O'Bw7Ba.-W+A_ ~;a.),GydTO>Z>+5|ʕCٿlB di[YQχPc"p[{!rY(SվcK&l* e_>䑶Kez|L%2<4/SAMoUȾA<_MVD2|8#ۿ8/"/])7P=Ξ'l> =щDhQT7ҳj_I鲽LЈyk̵@(zez7:6>M b_;}rϤL^?;_ձ2q y#؜F!~GQ2GC tez7:{H}L:Ď|To^g+Ee*IFLVUǚ8'_^13z.ru18t~,I=O:d+?&Bб)MnvA1'0AcGQ&yy;oy(*cML4dMu(s0!7)3rNr5䑞:?yjօ|M ez7:JR5~*c]LgLUNJ87_>1X[>1<t~yjB@hÕ !1'0AcKo~i|U)a22YW/=\0gz:=j9| WCUH/m@(\ TBٜ)RS>BkGomk㇍`S,ϤL6T×OuL4Q-Ǟ_5:t~)Bb7XrlԁU.cD*aʃBL_suړp~L2)nT<y镔8y>~<|WPx}$oi\{В= HGYSZc[W/ ~ĭ QnUJ:Xhr~ur E :4#u:=c2+1ʺ8BqOn1vBG΂^%2PG h(B=C뷆PPB5#gRq<8:AuUѪGՎxCTﷴҗoonr<>C0W*!wҝYh_3#v} fkZELbk$<:~: %/T+$/_P|Jfء~}yǫN;<>7B}yX#_ 5gRSP3%}-e/FhfĒ Z5"_QLbW:\m Ų._s\(KQ2Ɩ:q@NjãgAkByzԆhÅ|BvhB {͈:8n,L7"LfBFByH35쒬" ' 7CP F"4~;BSP:ZSO|y+*З@(b Z~Ƀ硝?2AjCg<{)/zSm *9 [,~!urvh}աޏWoo8͐bXQ"GՋ̓^NyFfA+iA IDATC?Beo?H; UnDʸٞsCHBu@ ^V&  `"u{)$KXbDyZPDzr2B yf]쾥B^UC(|@g1!/kW.]#GL!_]B()pݸ'@=Eټݿ-μI? 2!T(?\B @h{4s|Ne>؎S-1?'7)sY5D-NB & e9o5`_RMqkmwL ~k_ejĴB 5{Ro(6;QW E &4ӒsHD{9^TF|kޙ1!Bi!*BP&jY*u*a_KfMWXT{-U@LN/Ԙ_̓G!;-X"t/D( "T-ʀP Uœš y垡n'u1sLJn3cDY[xn/{y B1ѵ9Җ{0s3d/ϴfHڳ4+^x%ߗZ]¼К÷>7a[m؟S/{d׏8 [}zX4Z^?ϫ[v~=>s2Wg@h!ЗGo=鵻]uc?Lx0Y9 jgEwgQ_GG(2W7IrYI_nItv<K1hB@h9s"t{){|p$Y}rQPpnd8I>+Jxdy}'b"PЯqѕ(YȬNܟhG_鮊~4R9|yݽxuKys$~?=}pnPFQJgO-o"=4#˨5#0=4# oe'Buf^(d;3?9}P*G6B7u>;۩74饢ΎGBۏбkF5#B0R, wBPB^f>uz1ys!+Js]Bʼn>^h?.?^% B^,\{FLF/V͈쯎^3b kp/>Lv>F?{ݣ^hVGv5xT`WQ_GG(S>Owwz ڳ?Tf#r85ޒf~fD4#?"pdZ(|cQa;_ƷoWd}u2WQN7߈zp&w7S޽s"4;YޣFW N3 F76'z[9u+B?w z;~Uq!?NfC3Q3Bo[3"xFQ@ԂPhF: E A㎇x<`4Gz7ta;BX:!B%osmlէ{ǯ{[{s~?3_gڀP -J&V, s&SL℟_?:9Q.:}4l[s[B t7^hw𲗇L%~Ѿxmnoy>;mB5D̜4fi2}.%+DTS&O84&@hZTLBDeR'^&n!ܢ.jxN{y[[E _#-gEYCBC=+"biLuO@* КeR' .&>vi7܇y 1GX=lӓ>@|EY,őɦrx@ۋz'5 d#xd+'?'=`x/Ӟ@@Qrå|GjW}w68RG͜^*$1!5&$~]^!P1⯓/Z/?BU.BI)'>'=sD|O}zr렷J೅W9Λg7_O7~S uUVZg4Al"FFV"@(BӆЈ+c\;@(B=B#P@h9 @(BG2ٞv)צ[0n6V[m؟SxB'*x9R{<7kk(e  Q_~>8~tqmPMpg!Ҍ>#S. qIU\-4G$*;9}u$ULj_n 1,#wsZz 3P\*>ґد"cjyeK۶;盲wLޗ/ʂR /'}0ul>u Uʬ ySC(g H,$p%˫鮊*)y^Vڹ?d Sʤy}+龑 c.y1m1=U#Vr֨\*ミoB7t/6u>LƊg]7>#:Ymۅ| y tde@Л _e?>~uBʼn>^hBjჳ 'ey]|MT1˙pH,T%GbJǹý1;P/2R-5XZ/@h˔BE\R|دu^݋GVrˎ)I|\^^PlB-ܽs"4;Y>S,#PZtySP\@h}yj/{ Ќ 0"<~rD.sDBPT ToA-&tMP 1n]щxj,5n(:f6)oBFP[!iBX ՅPngHPf]'2!ADueV1?R%t~k@譝' p?ˤ]Ibz!^(:^rf{k]?_v5Wgր;O-Dsv6[_zޗ}+y~hϵUǫG}&6_}~:Vq8Q/B=y;4:~wq wv_U=4EW.gA-*3ձ/L2/WZ5vdйurUx2|B E\ݼO;O|Z{BW;}$ *myVw`{@Lzfàs{- VW.g~|zÕ TSL˾e*+yJ)s!T@(- Bv$=ϼ^rGD:XB^ג0c9&8nwz=U ! "&sDL$ĥaީEd$sh”Z$۲}cP|p\69:b;l}~}{<epBۢ\&epҷͩP6)Q5qϢ}\6&UOW䓩G{~lsN>k:?gUϵ OB\&eW:\C0|_OKG}_9{*H>CϏ~]9{;\s{U^):m`(P2)cՕ3y~O׹텚vwWErOv:WwU}N\>yT?]So'k{UsIL5P eR2+ME'f>?9ktVQ)({4Td>CϏ~9?iu3Bx^(|2ʫ>6. ++<ח?bpBR#HL>yT?"Opio|.~!/E #@(dwN*\/@(B: B 1E P "P "*e[UmsU@(Z(px*gF1ף1i BP SS̒2ĚP6 t2˙8ŠJ8wS^<(0w(CTWG9>M-K x BՇeӥ T٢@h-eMEķS^%ؿRJan+CTWǧQx B,o: !x~a >ZrYU֡\NUžeU ,vtW@߇ǓO!Tߓa>P޸iBЊeEE`UPF'> eoD(GE\;j1v(\*\ R^~zeͫ:?T|L4(ǒOUGu2\na9IڅdOy>(Zr{핕˙Jط?s|BJ&x7ו?T@P>2z )U/@h+˱UšJ5Er|JO{,_xr:ˇוOMChǐO'5!v*cD**sBH.OH)L#,~Z;?d|| h>Z~$㹐G!@(E ڋP6 h%BJ,g#+X1E &Z, #)s;Ua*Q-#)sdz-ez)7KfDʕ5D\yv-XXx 6$8+L"FaT${B-9  V#3n)٫jPB9 ֡\TU|...Iˇe)r͇V]V6PǾ1J]C/sZyQ%gZf7pm%Bc+^>n|4X]?1c||c !{ wU7(C\QL*^"5*)RxkGAD]znF8>6uGo>#Eh$ teR񆢪$||:'O{wj'Q~^hC::B[\&o(*)P> {3ojGe x>FIo5 O^j!=?9}"+Ip8qX)܏Z =S@GG/{~s4ЌcV.78^QqLy+kU[>2q{rؿ'tPqL#r%'8"_={|fmrYx0))R;/:g)s+W2|NgmG|Nq  BPIMЌ@(Q44#@(dw  E F{/ E JB9fB-O3?e|ٕaJ E-V.'<(RǶR&C;|c*>?e ]l׉:֍sE%uDqўh9mwRxT} Ol>!NuOWMA(4#@蘕_c^/jW׳D˃v©86SW5z<5;o ]+ǏPhFF*տEsA>>*c1E_CS)O<\-OB'J1BB\3C/*|{۰]z_@)*IDATc#S6vyt=IէC3R,~ľ â _Q?kP |LeqP>:?eIs|>z)R2F boA/ǤT}BͧF|ݹN"ܵ!Tfmr`c3,.6 |,eq@>!=?e^X{R>Bҗh%weB3Bv@  "*B 4# (D@S[@(7' cC(LL E LOz@(z0 "G "& "ƄE[gά%݁E>B_ n;:>l y3 q_PDkI2_֒duml ~q;Ph lݿX$=7O3 '{m 1B@(534K$ozvɟݻc!O~uBC "Zпex\|7CY)PB-h39Hb(G >\ӱGh B?<k[ߜDf٠X{v~k7n󹑤}:aBO6ό'Sn꧟-;.[ kcѣ_n_2#0u|B+tB8h9EOǽ3~L+|X2ln^ѧwV{.igk?/n%Ñ'_y[tvƷH|ĉ/{\m{?]nwneoݹZ{Jz`m}qrrQgolg@M$TăǛVL{xMy7ҧvg鉱ztfm".Ts=Z>^y`3iU/lܿWn|O|~z/5j}*5:bq[5͇ͥw{?ʎt﬷әmѝŇjc;Z:>o~x4]8Th<*wRV_;i?3/[]ӣݭ%6W?Q+qv_T㭉D"Qk=:Ӧa-5 Ԕd:!%Sj tEԡv#D}:MK2DjS2I4Q"Lv7i{mhd:mj&z"1BDg;L:krOóΆmouM ۔L&h{lQ;N!#Dbբ6%S4&"tIQZD2v64Fהvz+z^oٲNU;vhOXT6r݇lf/R-tOR.+="'D$R+;hi=sVgwUݒ5$믅'oWgsKD0w]BϺ=[QNoYq/CV*>vyͧss׮]nI>THK1\X GJѳ ˬejlb{[(ׯ/_/fq'V7Zmux=A}B#$"5lTxx:N^R SJqUsm[q."r]i6HՙJ䅐WmKZ[H)dJٜ/DylV\(-y+HP,"wmCxBvr8Bgg<]_f[R Ƶm%e{|OT/%1u|ś]|K繾"R\.fzcʡ l pj9s{.8 'W.<KY-HkۜH%^-{ )s]k,=??g.ත"am4tt^ ,K^Eնu㶹Wzc܉8eiV(^AybzXQ\'%̓66:K0sܻع0뺞W \y`i1 HD' 0WKy^b`࣮JeFJQ:Bԙ?0'877oRivv$D])[ʜenjF^^Mvxw  m|`'%/Ŝ=[딲=ϕRr &÷,}b{:.S8%j -RX'@n>2MAvVV>~>ku7BHZ[XuyoZP׋of!oS6!""#DݶU>,NTR HPgY*eyD:CTu]_TB|3HvFpy imI"|7*3.o,ȅǴ /ۯF2W,^ehݗ7:3f.^:O6)kxM!9FР6_.σ˵f B~q}}X)^}d,-oo8ε|> I*]Ro@i R'^WZۮ{5rsso>S 9Fq7G `!1A)4o[Z۾5V%UchS3M& 5۷@\ҮŤe D*֠a%4^J57ekcٲ(>q6Xw8.(Zu5yAG,gIstg씉0 Le5g[!MAp3 ?wM#KQ˘gLg}}ԩeZ kl[Y X2Ƴ;1;[2ߴSNY'ʡ^SLX:d2kM~>;Z8Ar5eULL:R#îE$V;æ ߚKI.I,۶UP.Wp|z]!$zmmʕJY[b$)J>= SnGeoat.(eA3Ț R/_FݶUwTNZ+h$?odI|M+nQOQK+8QK=<@j*c繎ϕEiZp؊Kcm9t;Q:-ªU_ {b[~ "&>W^a[3xZG% [إi6'wj3Lhbz̙E"R*],ps!eBk (<%d25D$L3RVK54 ,+h6CW6VZ- >ji6C˂UML}T"!mZe&&4]ΥZ0lrZ-퀭҄QYMۮD 't>ҔR}A`; ðljn?djJ=iϭ[g\w '*aYl*%ML9{wt'K{KB@{u&B_ T@{vZ[C7kb-2MMi, Û,יR(Z!_W7C}~8ɕ\ߖ!Λْ "U 6UǶbqBs܁u'\Q5̸َ\.j~(ҏ+8E>`޲t\wjDWxw1Ç-97vp of;2a=,5׮]6ŲŲmkOma(n m@b ~*B\Nv&Tl˨z rVV& U?f,ד2#1s06w0cf1`ii"/&L Zu.^,I)J=FsMe EVl'c=(&kk'`k5E!4yYUl`իW}1=q6Yl}sU1K.rH!Zs-7 =?Ҡ"'+Zl8q?qqP /,zb?+SY+.F]ֶ(VfѶvj*ֶiwfuz^qj{xs?6/f_`T,n'a@\1ρ>bT]\n45u=ۼśf-*cH|`THE'х e گx~nʔ fgK li8a24P ժR Qo"ӎ2jj!VNYXۜ#x +GSݍyMme;1|,ڿ!"fcJh!. Gݘ:XB(ia9S)˶5Y@) z6]'TʒR0*GxeۚV,l'6t*A>rrz ie2KKz$vlm+5Z$Q9Ci( $B|}yxVl(oRdG.dxe78ZDz:'>5Q`s7;tǶ(X> ИY;nW1{׈KGͺz&|6x9!1yX @=3)@.+SS5#]nZ:E)Pgo>hmaУObӟv=?e,0Ř d qn{1sxߏ8ePay|6Z&7#jr:rƫ*gz;k%"6W1 x3ș3l^lbADai4&0l%j3a\tlN}04ƄmL&`Y:DayV*,`oU˶U][-.cB(W> lb,KkIt`:gEY )t!478:pXߌ5ie]#8|0>lC~o-]seY,AZmJ)kA>uʆ1E7 l2`Y1ۀy`KZʻ}uy3{}tqfN{eKa]:f1 1aX PC{.p=z;[cqFr*G#B6btgG;xW7kO:~Ge݌FBDc %2ԍͬf]4T]Cueà VQ{NTFYvpF\׏ ? -+P\v͇'-֚pw Ûa?c߱%zOD^hюmE@Pd?>Q7 xjݻ.$P<~ݜf`< ZlE&c/ۻ5+nCDy6|7tdjk=#nr/Jưe2gg'iol'J4S-#f3*gLiF;+G龧_pb3ؾ|>86C ,)m8}J= & !>|4lHzO cIyl]U{X>4i]y0rsOk~hyhk63e<1n54x޽ G̮׭FK'ѳM4oCh\pKkCd3~wEo<F~Jl6v=ч1f}"D^ɰBAt-<M+8XvMjs3J)ד?a'd@L?_#,}2?+cIJ=bdF|6\6ϏsI'y$pG\BdssJۉP}ĝ%8N5[ﴁ46( O=77σpAN;VM̆Z㟜+OO>, SC]<:eJŒgӱ^UU׈mVmY;,ɀfhGc[t?%kcAtHSŖ޼ zrs^ݤ\HT%0F.ϕcX)[J۲x<9RJQ.[ZsL߶%οlF|*mY3C-JBRl QRl[[i}8 E맄رZ; y`d] H <*@SXrڗI̎6@ T TЗۘݥ |i R/?3:". ^f8(k/ZLn5:06@;c3=̓FLwgÜ8mϙ2<'>@VNeo.ЗҼ ʘf NL&tO~(iЌ<\[ZDFYG ȲZKzb˽w\Kb}=OQR}9&Ρ/f.lLc{, o&ru&OЩ$zGk*4m5_V=yߘfWy MDc w$Ǔq ÒWOk=~? m}RlSy0rͻ|C,D=v-d'Cf 0,6zA{JQxQI;l]?Z'mOm˦f- o6~w{6*c~(eX;ya.Mori|OqS15/OM2 x|X,cf2CBHJelŹxAf[F6—Y^>UMڽJeqJeƶU&13Si6_.N9Td 4@^IDAT:l/Obp̉h~<σ2 ntFCbc_R uqE8Yk }J*_(ׯ`{}\uVv&cO ['_cBH0HfCtpBA|>N@-˜ w`-SS5kma4dJHh$W(xuX |#%E֜Ȯc zQkGʿ{B]!-k./,xB'vKȦMq7cyr yS'8X, !!+sf'-rug V7lr6/7#{zDb%eX>[ׯ'YZf`@8TIQrn a=6= nC.X'0c!}lejf8"lt+<4زT?`RuL13xÒw}ؠ+ f0:a#KvŤE=5`R6&w㚛GFb>*Pk H<;[ILn2""!Y"X[{ID AyBx_f^ZѵbB;;&ҎXx5i!`s7flv^LLwt\yvT˘D=t3= I=5]OOx͇1G&Z-O6-x3c;;Oz;P2槻f`d a%}ϧShhb1#`33;MGZnmc48a&""b7yo4KDDWz=-٣q^V[[ilxqnƗ5gF&XJu3?vr\Vmp t ~vg'Rx>1"ax8&TNF̯t7؏w٩btGXH1K118 pjՙ: aMmJY:ԤɆ&Ǜf6t26isMirxϵy]׃~kmyk58_Cܗ{qe"}Xd5 Şpc.sԿ̬IQL#=\X!~@DSݧgXJD姣׬~Ỏ=HC/6j<<c7rKD{*V {~7?FStIME;+tEXtSoftwaregnome-screenshot YIENDB`gxemul-0.6.1/doc/TODO.html000644 001750 001750 00000141730 13402411501 015432 0ustar00debugdebug000000 000000 GXemul: TODO list

TODO list for GXemul

Back to the index.


Here are some things, in no specific order, that I'd like to fix or implement in GXemul. (Some items in this list are perhaps already fixed.)

This list is split between the new framework (written in C++, version 0.6), and the older framework which was written in C.


New framework

Legend:

[ ] = not started yet, or just planning/thinking about it
[/] = started, either "on paper" or actual implementation
[X] = done  (but usually these entries are removed from the TODO list)

------------------------------------------------------------------------


  [/]   Cache components.
  
  	This is hopefully a good way to get started working on GXemul again,
  	after the long break.

	Sub-tasks: (write unit tests for EACH of these, while going along)

	[/]  State consists of
	   [/]	size (e.g. 4 KB, or 1.75 MB)
	   [/]	associativity (1 = direct mapped, 4 = 4-way, 0 = fully associative?)
	   [/]	cache-line length (e.g. 4 bytes, or 64 bytes, or more)
	   [ ]	replacement policy: ?
	   [ ]  write-policy: write-through vs write-back vs copy-back
	   [ ]	Small memory area (the cache memory) itself, consisting of cache lines.
		Cache lines are:
		  [ ]	data
		  [ ]	tag/index(offset?)
		  [ ]	valid bit
		  [ ]   dirty bit
		  [ ]	PC of last writer?

	[ ]  Implement the addressable data bus interface, but if data is contained
	     in the cache (the small memory state belonging to the cache component),
	     do not call the main memory.

	[ ]  How about simulating cycle delays? A read or write in this type
		of model is not instantaneous, but rather a "request", which may
		take arbitrary long time to execute and return a result.

	[ ]  If possible, for each cache-line, store statistics:
		nr of hits (reads, writes)
		nr of misses (reads, writes)
		on writes, store the PC of the writer, so that on misses,
			statistics can be gathered.

	[ ]  Caches should be added _onto_ a cpu. The cpu should first look
	     for a cache as an address data bus, THEN for a parent.

	     [ ]  The cache must then go downwards TWO steps (../..) to get
	          past the owning cpu, when trying to reach the mainbus/ram.

	     [ ]  How about multi-level caches that are shared between
	          CPUs/cores? Think through this.

	Or:
	
		machine
		  mainbus
		    ram
		    rom
		    l2cache0
		      cpu0
		        l1icache
		        l1dcache
		      cpu1
		        l1icache
		        l1dcache
		    l2cache1
		      cpu2
		        l1icache
		        l1dcache
		      cpu3
		        l1icache
		        l1dcache

	if e.g. a 4-core CPU has each core having its own L1 caches (I and D),
	but sharing L2 caches between pairs of cores.

	Problem: What if there is hyperthreading, and the hyperthread "cpus"
	share L1I _AND_ L1D? Then the L1 caches cannot be children of both
	cpus.

	[ ]  Test with caches attached to M88K and MIPS cpus.

	     [ ]  How about a command line switch (or other command) to
	     	  quickly turn caches on or off? Or maybe just an optional
	     	  argument to the machine templates (caches=true or false),
	     	  but that makes it hard to switch during runtime.
	     	  (Switching during runtime from no caches to caches is
	     	  easiest (?), but from caches to non-cached will require cache
	     	  flushes...)



  [/]	Improve dyntrans CTRL-C behavior! Abort quicker.
  	[X]  Implement an abort instruction call
  		[X]  sync pc should take this kind of abort into consideration.
	[X]  Rename exceptionInDelaySlot -> exceptionOrAbortInDelaySlot
	[X]  Get rid of abort_in_delay_slot (handled by abort).
	[/]  Unit tests for the above (M88K).
  	[/]  Function call trace -> abort quickly on ctrl-c.
  		[ ]  There is still a crash bug; try interleaving continue +
  			CTRL-C + continue + CTRL-C, with trace enabled!

  [ ]  Components! instead of the planned plugin stuff?!

	[ ]  Pretty print of files and disk images:
		
		cpu0  (5KE, 100 MHz)
		\--  file  (netbsd-GENERIC.gz)

		or

		wd0  (ATAPI primary harddisk)
		\--  image  (cow, netbsd.img)

	Should these be added without digits primarily? And then
	starting from 1. "file", "file1", "file2" etc. Or is file0
	better? Just "file" is slightly clearer.

	When adding e.g. a machine with a specific ROM, the ROM file could
	be looked for in standard places (/usr/blah/share/gxemul/rom/therom.bin,
	~/.gxemul/rom/therom.bin, ./therom.bin, etc) and if not found anywhere,
	give an error unless overridden using arguments to the machine template.
	Like:  gxemul -e "sgi_ip32(prom=my_therom.bin)" netbsd.gz

	New syntax:

		path_to_add_to:component(args)

	or
		path_to_add_to:filename		args is: "name=filename"

	or
		filename			cpu0 is the path to add to

	I.e. DON'T make an "attach" command, just use the add command.

	Maybe change it to:
	
		add component_type [at existing_component_path]
	
	and/or support the colon-style notation as well?
	
		add [existing_component_path:]component_type(args)

	or
	
		add existing_component_path:filename

	Think about this!!!

	$ gxemul -e testmips netbsd-GENERIC.gz
	$ gxemul -e testmips netbsd-GENERIC.gz wd0:netbsd.img fb_videoram0:sdl()
	$ gxemul -e testmips netbsd-GENERIC.gz file(type=raw,vaddr=0xbfc00000,name=prom.bin)

	Same as:
		add file(name=netbsd-GENERIC.gz) cpu0
		add disk(name=netbsd.img) wd0
		add file(type=raw,vaddr=0xbfc00000,name=prom.bin) cpu0
		add sdl() fb_videoram0

	[ ] What should a component be able to do? [as a plugin]
		[ ] Attach/load/add
		[ ] On-early-reset  (clear memory etc)
		[ ] On-late-reset  (fill memory with file contents etc)
		[ ] Detach
		[ ] Monitor changes in component(s)' state
		[ ] Periodical updates (e.g. framebuffers)
		[ ] Run in a different thread (pthread multithreading?)
		[ ] Insert stuff into the event queue (e.g. keyboard keypresses
			from a framebuffer/keyboard plugin)

	[ ] The Snapshots (the clones) release the plugin connection; the plugins only
		work on the main tree.

	[ ] Plugins have to be compatible with replaying during reverse execution!
		(Maybe they should be disconnected while re-executing?)

	[ ] Think about how events should contain changes such as breakpoints,
		added/removed plugins, etc.

	[ ] Example plugins:
		[ ] File loaders
			[ ]  Move these from src/main/fileloaders to
				src/components/file ...
			[ ]  raw mode: file(raw(vaddr[,skiplen[,entry]]))
		[ ] Disk image mappers:  src/components/image
		[ ] Framebuffer displays
			[ ] Think about VGA (charcell AND video framebuffer, being able
				to switch live)
		[ ] Keyboards (host -> emulated)
		[ ] Serial controller -> scrollback buffer -> xterm / other window
			or even connected to stdin/stdout or files or terminals.
		[ ] Audio (emulated -> host)
		[ ] Cache statistics viewer.

	[ ]  com0:stdio() should not be needed, if it is the default
	     choice. com0:null() would disconnect com0 from any output.
	     stdio() would then have to be a plugin which handles multi-
	     plexing of multiple outputs, and allows one input serial console.

	[ ]  How about "-X" behavior of the legacy modes? I.e. a machine, which
	     when run with -X will set up PROM emulation variables so that the
	     guest OS uses graphics, and without -X to use serial console...

  [/]	The testm88k machine.

	[X]  Implement 88100 instruction disassembly.
	[X]  Implement basic 88K instruction execution, enough to run
	     the rectangle drawing demo.
	[ ]  Framebuffer output?
		[ ]  Start thinking about the plugin framework, use sdl
		     for video output!

  [/]	The testmips machine.

	[X]  Implement basic 32-bit MIPS instruction execution, enough to run
	     the rectangle drawing demo.
	[ ]  Implement basic 64-bit MIPS instruction execution, enough to run
	     the 64-bit variant of the rectangle drawing demo.
	[ ]  Implement basic 16-bit MIPS instruction encoding, enough to run
	     the 16-bit-encoded variant of the rectangle drawing demo (on both
	     64-bit and 32-bit emulated CPUs).
	[ ]  All the other devices (interrupts, ethernet, serial, SMP, ...)

  [ ]   Intel i960 CPU and machine modes.

	[/]  i960 instruction disassembly.
		[X]  i960CA

	[ ]  i960 instruction execution.

  	[ ]  HP 700/RX emulation.

  	[ ]  Cyclone/VH i960 evaluation board emulation (for uClinux/i960).

  [ ]	SPARC64? Would be nice; multithreaded Niagara emulation etc.

  [/]	STEP EXECUTIONS, REVERSE EXECUTION, SNAPSHOTTING, ...

	[ ] Try to get away from using doubles for scheduling! The scheduling
	    must be made more stable, even in the precense of rounding errors.
	    See e.g. http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=570899

	[/] Continuous execution forward.
		[ ]  "Sloppy" accuracy mode: it could be possible to
		     interleave large chunks even when components "collide"
		     in time. (This will cause reverse execution support to
		     be turned off.)

	[ ] step recalculation:
		[ ] When a component is added to the tree, recalculate its nr of steps!
		[/] "paused" cpu state, in SMP machines during bootup. (Non-executing components.)
		    [ ] When a component changes state from paused = true to false,
		        recalculate its number of steps!
		[ ] Removing components (at least if the Fastest one is removed) should
		    also trigger recalculation.
		[ ] When a component's frequency is changed, recalculate its nr of steps!
		    (This requires variable write handlers, including inheritance!)
		    Frequency changes are tricky, especially when it comes to reverse
		    execution, so think CAREFULLY about this!

	[/] Reverse execution/debugging:
		[ ]  When running in reverse, debug output should be disabled!
			(Also, update calls to plugins (e.g. framebuffers) should
			be disabled, until the target step is reached.)
		[ ]  Regular saving of state, and limiting the number of such
		     saves by logarithmic removal.
		[ ]  Disk image overlays!
			[ ]  Unit tests.
		[ ]  In addition to saving state, all modifications done to the
		     component tree, and e.g. breakpoints, need to be stored
		     together with their time stamp ("step"). And also all
		     "external events", of course.
		     * I.e. if a USB storage device is connected as step 1000, and we're
		       running in reverse to step 800 to check something, and
		       then continue again, the default behaviour should be that
		       at step 1000 the USB device is connected again.
		     * Or if we run 10 steps, change cpu0.pc, and run 10 more steps,
		       then running backwards 10 steps could work, but not more?
		       Think about this!
		[ ]  Simulation across multiple hosts?

	[ ]  Cycle accurate slowdown? E.g. when simulating a 1 MHz microcontroller,
		and a TV display, maybe the host is much faster than what is
		required. The gxemul process could then yield some of its CPU time,
		just about enough to make the process run at real-time speed.
		(With warnings printed whenever real-time is not possible, because
		the host is too slow.) This would be useful for some simulations
		involving real-world Sound producing devices.

  [/]	NEW DYNTRANS IMPLEMENTATION, ...

	[/]  Basic run loop.
		[X]  PC to pointers
			[X]  Dyntrans page allocation
		[/]  Large chunks is safe vs "single stepping" dyntrans...
			[ ] Only "size 2" so far, i.e. delay slots. No support for
			    longer instruction combos have been implemented yet.
		[/]  Unit tests.

	[ ]  Memory writes => invalidate corresponding dyntrans translation pages!
	     (needed for full guest OS emulation, and self-modifying code)

	[ ]  Interrupts should be cycle accurate, and affect the cpu's
	     m_nextIC (and other state, such as processor status registers)
	     _immediately_.

	[/]  Helpers for CPU implementations:
		[X]  dyntrans pages?
		[ ]  pc to dyntrans page lookups? 32-bit and 64-bit
		[ ]  memory to direct host page lookups, TLB-entry based

	[ ]  For instruction combination implementations, the first thing
	     checked is whether instr combos is allowed, if not then call
	     the original function call instead. This makes it possible to
	     run fast, and then "break slowly" before a hazard.

	[ ]  Try variable-length ISAs early on. Maybe amd64? Or AVR32?

	[ ]  Multi-encoding ISAs, such as MIPS (MIPS16), ARM (Thumb).

		Commands used to compile MIPS16 test programs:
		mips64-unknown-elf-gcc-4.3.2 -mips16 -O3 urk.c -c
		mips64-unknown-elf-ld urk.o -o urk -e f -Ttext 0xffffffff80004000

	[ ]  Optional native code generation: Probably don't have time to
		implement this in the near future; everything else also needs
		to be prioritized against this feature, so...

	[ ] Instruction cache emulation
		[ ]  cache component on cpus
		[ ]  For each emulated instruction, call a stub handler with
		     the current pc. It is responsible for updating statistics etc.
		     (Only for cycle accurate emulation, not for sloppy emulation?)
		     (Or should there be a separate setting for cache vs non-cache
		     emulation?)

	[ ] Generic bus load/store access:
		[ ] Pointers to host memory pages, for fast loads and stores:
			[ ]  host_load and host_store (as before)
			[ ]  host_load_user and host_store_user (as before,
			     for those archs that need it, e.g. ARM and M88K?)
		[ ]  Pointers to handler functions, for:
			[ ]  device access
			[ ]  data cache emulation
			[ ]  breakpoints
			[ ]  Investigate: http://vm-kernel.org/blog/2009/07/10/qemu-internal-part-2-softmmu/
			     indicates that QEMU uses similar lookup mechanisms as GXemul, but
			     uses an additional bit in the looked up page address to indicate
			     I/O space. Investigate whether this is faster than having a pure
			     pointer, and a separate lookup when the pointer is NULL!

	[ ] Conditional breakpoints before AND after device accesses!

	[ ] Conditional breakpoints before AND after CPU instruction
	    execution (somewhat different from generic device access).

  [/]	The MVME187 machine.

	[X]  Loading OpenBSD/mvme88k bsd and bsd.rd executables!
	     I.e. implement an a.out file loader.
	[ ]  More initial register contents upon reset: r31 isn't enough for
	     mvme187. See old machine_mvme88k.cc for details.

		[ ]  Soft PROM emulation, if no PROM file is found.
			MAYBE implement PROM emulation as a plugin? Like

				attach cpu0:mvmeprom(187)

			or even just:  attach mvmeprom(187)
			since cpu0 would be the default component.

			The plugin would then be responsible for on-reset
			behavior, AND handling of PROM calls.

			If a software PROM emulation plugin is used for
			emulating different boot loaders, then that can be
			specified as arguments, like:  bootregs=linux or
			bootregs=netbsd  or similar.

     	[ ]  Ability to load raw files (e.g. PROM).
	[ ]  Serial controller component.
	[ ]  Plugin (?) for serial output (i.e. a terminal window), or
	     posibility to connect to stdin/stdout. Should be enough to
	     show boot messages.
	[ ]  Separate 88200 CMMUs? So that the two are really two
	     separate devices.
	[ ]  Implement 88K virtual to physical memory translation.
	[/]  Implement 88100 instruction execution (completely).
	[ ]  Implement 88110 instruction disassembly (e.g. "graphics" instructions)
	[ ]  Implement 88110 instruction execution.
	[ ]  Disk bootblock boot.
	[ ]  Reimplement everything from the old mvme187 implementation.
	[ ]  Ethernet :)
	[ ]  Dyntrans "user memory" implementation for M88K!
	[ ]  xmem emulation (set transaction registers)
	[ ]  Instruction trace by using bits of ??IP control regs.
	[ ]  Breakpoints: How to indicate user space vs supervisor? (Also the
	    "dump" instruction and other things need this support.)
	[ ]  Instruction disassembly, and implementation:
		o)  See http://www.panggih.staff.ugm.ac.id/download/GCC/info/gcc.i5
		    for some strange cases of when "div" can fail (?)
		o)  Floating point stuff:
			+) Refactor all the fsub, fadd, fmul etc. They
			   are currently quite horribly redundant.
			+) Exceptions for overflow etc!

  [ ]	Address formats?
  	"xxxx:yyyy", "xxxx:yyyyyyyy", "zzzzzzzzzzzzzzzz" for amd64, plus i/o ports
  	"uxxxxxxxx" vs "sxxxxxxxx" for M88K
	most likely others for "bank select" embedded archs/microcontrollers.

  [ ]	amd64/x86 emulation:
  	a) Non-dyntrans emulation mode, as a "proof" that CPUs can be implemented
	   using slow interpretation, and do not need to be complex dyntrans 
	   implementations. (PC emulation isn't exactly GXemul's niche, anyway,
	   so it is ok that it is extremely slow. There are other emulators
	   and virtualizers for users who need a fast x86/amd64 experience.)
	b) interesting because of mode switches (16-bit, 32-bit, and long 64-bit)
	c) interseting because of odd address format (non-RISC style)
	d) interesting because there are lots of guest OSes and other software
	   to test with
	e) how about making the name "pc" in CPUComponent overridable? on amd64,
	   it is either ip, eip, or rip, depending on mode.
	f) override bus reads/writes, because amd64 transparently allows
	   unaligned loads/stores.

  [ ]	Memory/bus reads in "no exception" mode (for disasm and memory dumping,
  	and other things).

  [/]	Symbol registry.
  	[X]  Add ELF symbols (see end of FileLoader_ELF.cc).
  	[X]  Load a.out symbols.
  	[ ]  Include device addresses and hardware registers in the symbol
  	     registry (as in the legacy Dreamcast mode).
  	[ ]  Cloning a CPUComponent should also clone its symbol registry!
  	     Think about serializing symbols...

  [ ]   Make sure that BOTH old and new configuration files work!

  [ ]	Niceness fixes:
  	[/]  make refcount_ptr<T> support const T as well, so that e.g. code in
  	     Component::LookupPath can be made to work without a const_cast!
  	[ ]  avoid exceptions (better to return failure some other way)

  [ ]	Call m_gxemul->GetRootComponent()->FlushCachedState(); when a component
  	is e.g. moved or copied?  Example: cpu0 in machine0 is moved to machine1,
  	and then cpu.dump is executed. It should then use the mainbus of machine1,
  	not machine0!  (Maybe not necessary for interactive use; FlushCachedState
  	is called by consoleui before very command... hm.)

  [ ]	Cache short path names if evaluation/generation of them becomes too heavy.

  [/]	Mainbus component:
	[ ]  Maybe this should simply be a "Bus" base class? That way,
	     it could be reused by PCI Busses, VME busses, and others. HOWEVER,
	     the concept of address range and overlap may differ between
	     bus types, or maybe not even exist in some busses.
	[ ]  AddressDataBus should be extended to allow for direct
	     page mapping.
	[ ]  Unit tests for the above!

  [ ]	Interrupt subsystem
   	[ ]  Components exposing an InterruptPin interface? Think about this...

  [ ]	Timers
	[ ]  Host speed approaching timers:  a device that wishes
	     to cause interrupts 100 times per emulated second
	     will interrupt (approximately) 100 times per host
	     second. This is most useful for running full guest
	     operating systems at full speed, "virtual machine"
	     mode.
	[ ]  Exact emulation:  a device wishing to cause 100
	     interrupts per emulated second may take much more
	     or much less than one host second to execute.
	     ("Cycle accurate" mode.)

   [/]  State/model:
        [X]  Variable write handlers.
             [ ] root.step to move to a certain execution step!
             	 [X] Change backward-step to set root.step = root.step - 1.
             	 [ ] Only allow decreasing root.step if snapshots are enabled.
             	 [ ] Allow increasing root.step always: it means to continue until
             	     the number of steps have been executed (a kind of specia breakpoint!)
             	 [X] Do not allow writes to *.step for non-root components!
             	 [X] Do not check writes to *.step during deserialization!
	     [X] cpu.model = "R4000"   <==  assigning to the "model" variable should:
	  	[X]  handle writes specifically
	  	[X]  lookup if R4000 is a valid model for the cpu architecture
	  	[ ]  Better error reporting when supplying model using e.g.
	  	     the command line   -e "testmips(cpu=R1000)"  should show
	  	     the same error message as when running cpu.model="R1000".
	[ ]  MIPS ABI selection now works (cpu.abi="o32" vs n32 and n64). However,
	     only the NEW names are registered as state variable names! How should
	     this be handled? Custom "aliasing" variables?
	[ ]  Custom ToString variants? Useful for bit fields, control
	     registers, etc. "Verbose tostring"?
	[ ]  Loaded files should be part of state/model! But not part
	     of the component tree. I.e. state = components +
	     other configuration!
	[ ]  Disk images: reverse execution should reverse disk contents,
	     i.e. overlays must be used if reverse execution support is
	     enabled.

  [ ]	Serialize symbols

  [ ]	Serialize breakpoints

  [ ]	File loaders:
   	[ ]  automagic .gz (and .bz2) file extraction into /tmp or $TMP or such.
	[ ]  symbol handling, line number info, data types?
	[ ]  argument handling! (arg count, at least)
	[ ]  all the others (macho, ecoff, srec, ...)

  [ ]  Disk images.
	[ ]  r vs R modifier: read only disk images causes writes to
	     fail, while R could create an implicit empty overlay
	     in the tmp directory, so that writes within a session
	     will succeed. At reboot/reset they'd be lost.
	[ ]  Make sure that there is either
		a) a sync after each write to make sure that the data is
		   consistently written, or that
		b) (for the test devices at least, or perhaps some others)
		   a mechanism is available to turn off the write-after-every-access
		   policy but then the data must be manually synched by the
		   guest OS every now and then.
	     (This will be a requirement for e.g. a persistent Single
	     Storage guest OS.)

  [ ]	Breakpoints

	Breakpoint = some form of expression, which will be evaluated
	after (or before?) running each cycle. (*)
	
	(*) Implementation-wise, it may be optimized away, but the semantics
	should be this.

	NOTE: It will not be possible to break INSIDE a component's step,
	but only before or after all components within that step have
	executed. I.e.:
	o) when single-stepping, the breakpoint may simply set a flag during
	   execution, and when all components within that step have executed,
	   the resulting triggered breakpoints may be displayed.
	o) when running continuously, the breakpoint may still not break immediately
	   (?) because components may be mixed within the last step? TODO: Think
	   about this.

	TODO: Any state variable change in any component? How about RAM/custom
	changes? How about register _READS_ or custom reads.

	All Load/stores to virtual addresses?

	[ ]  For all breakpoints, it should be possible to break
	     both _before_ and _after_ a change has occurred!

	[ ]  For all breakpoints/watchpoints, a Count should be kept, and the
	     emulation should only break once the Count has reached a limit.
	     (Usually 1, but should be possible to set to any positive value.)

	[ ]  Worst case: Checked on device cycle execution, if necessary.

	[ ]  Per memory-mapped/addressable device
	     Checked on load/store device access.

	[ ]  Per instruction (for CPU components)
	     It may be easiest to simply turn off native code
	     generation, except for stuff like "check if pc = xyz"-
	     style breakpoints. Those can be embedded.

   [/]  Function call trace etc.
   	[ ]  string lookup for args
   	[ ]  symbol lookup for args
   	[ ]  Document in doc/components/component_cpu.html how to use
   	     tracing, what the showFunction* state variables do, etc.
   	[ ]  trace command (taking an argument: nr of calls, default is 1?)
   		which is the same as setting a breakpoint for cpuX.nrOfFunctionCalls = Z
   		where Z is one more than before than it was before running the command.
   		And each function call increases that variable.
   		trace then temporarily turns on showFunctionTraceCall and
   		runs until the breakpoint hits (or CTRL-C), and then removes
   		the breakpoint automatically (even if CTRL-C was hit), and
   		restores showFunctionTraceCall.
	     Variants:	trace on	turns on tracing for all CPUs (but doesn't
	     				run anything)
	     		trace off	turns off tracing for all CPUs
	     		trace [n]	runs with trace enabled for n function calls,
	     				n = 10 by default?
	     showFunctionCallReturn should be false by default.
	[ ]  -t command line option, for backward compatibility?

   [ ]  Stack dump (of the emulated machine)
   	[ ]  A method on CPU components?

   [ ]	Components (general):
	[ ]  "help" about components could show a file:/// link to
	     the installed documentation about that component or
	     machine! (If it exists.) Fallback: refer to the machine or
	     component on gxemul.sourceforge.net (but warn about
	     versions).
	[ ]  Limit where components can be added. Like "drop targets"?
		E.g. a machine can be added at the root, but a machine can not
		be added on a pcibus. Similarly, a pcibus can not be added
		at the root. It has to be in a machine of some kind.
		Think about this. Perhaps as simple as a "if parent class is
		not blah blah then disallow adding".
			A machine can be added into a dummy component.
			A dummy component can be added into a dummy component.
			A pcibus can be added into a mainbus (in a machine.)
			etc.
		bool IsItOkToAddItToThisProposedParentComponent(propsedParent) const;
	[ ]  Exceptions/traps to CPUs, could perhaps be generalized to sending
	     "messages" or "interrupts" to any device/component. How should this
	     be done manually from the command interpreter?
	       cpu0.break              cause a breakpoint exception? if the cpu supports it
	       cpu0.exception [args]   where args is VERY dependent on the exception

  [ ]	ConsoleUI and/or CommandInterpreter: Make use of COLUMNS environment variable
	when printing e.g. tab completion tables.

  [ ]	Command interpreter:

	[/]  State variable assignments:
		[ ]  Expression evaluator, +-*/, string concatenation, type
		     correctness (e.g. bool vs int), hex vs decimal,
		     prefixes like M, K etc.  (4M = 4*1048576 ...)
			(StateVariable::EvaluateExpression)
		[ ]  Execution of _expressions_, not just variables. e.g.:
			cpu.pc		prints the pc value
			cpu.pc+4	should print the _expression_ pc+4
			cpu.pc=expr	assignment

	[ ]  Minimal paths ala machine0.cpu0 would be cool if they worked.
	     I.e. if there's machine0.mainbus0.cpu0 and machine1.mainbus0.cpu0,
	     but no mainbus1, then machineX.cpu0 would be shorter, and still
	     uniquely identify the cpu.

	[ ]  Help on methods and method arguments? E.g. cpu.unassemble [addr]

	[ ]  Right now, entering a command such as "c" says "unknown command".
	     It should say "ambigous command"!

	[/]  Tab completion for everything:

		[ ]  tab completion should use the Shortest Path, not the
		     full path. E.g.:  cpu + TAB should expand to cpu0 only
		     in a default testmips machine, NOT root.machine0.mainbus0.cpu0!
		     This will most likely require a change in unit tests etc.

		[ ]  syntax based completion? e.g.:
			help [cmd]   tab completes the first argument as a
				     command
			add component-name		-- component name
			load [filename [component-path]]  -- filename etc.

		     This will require a uniform way of describing arguments,
		     and whether or not they should be optional. The tab
		     completer must then parse the command line, including
		     figuring out which arguments were optional, etc.

		     Also, when such syntax is taken into account, the
		     CommandInterpreter can check syntax _before_ running
		     Command::Execute. That means that individual Commands
		     do not have to do manual checking on entry that the
		     number of arguments is correct etc.

			[ ]  filename
			[ ]  command name
			[ ]  component path
			[ ]  optional vs mandatory args...?
			[ ]  scan all commands' args at startup, and have an
				assert() in place, so that unknown arg types
				are caught during development!

	[ ]  Command aliases? e.g.
		d = cpu0.dump
		c = continue
		s = step
		u = cpu.unassemble
	     But maybe the cpu in question may be changed with a "focus" command?
	     Otherwise it would only work with 1 cpu.

	[ ]	recursive component.var
			Dumps a tree of the "var" variable _FROM_ the component,
			i.e. including all children. E.g.
			recursive mainbus0.memoryMappedAddr
			would dump
				mainbus0
				|-- ram0  memoryMappedAddr = 0
				|-- rom0  memoryMappedAddr = 0x1fc00000
				\-- com0  memoryMappedAddr = 0x190003f8
			or something.

	[ ]	recursive component.var = value
			would set the "var" variable in the component including
			all sub components. Not all components may have the
			variable, so debug output should indicate which variables
			were set and which were not set.

   [/]	RAM component:
	[ ]  Make the save/load of state more efficient. Right now, it's a hex dump! Yuck.
	[ ]  methods for searching for values (strings, words, etc?)
	[ ]  methods for bulk fill/copy [from other address/data busses?]

   [ ]	Floating point helper.

	Make this more complete/accurate than the old one, i.e. support
	inf/nan, exceptions, signaling stuff, denormalized/normalized?

	[ ]  non-IEEE modes (i.e. x86/vax/...)?
	[ ]  Unit tests

   [ ]	Userland emulation

   	[ ]  Begin with e.g. FreeBSD/amd64, or FreeBSD/alpha, NetBSD/something,
   	     or Linux/something.
	[ ]  Try to prefix "/emul/mips/" or similar to all filenames,
	     and only if that fails, try the given filename.
             Read this setting from an environment variable, and only
             if there is none, fall back to hardcoded string.
	[ ]  File descriptor (0,1,2) assumptions? Think about this.
	[ ]  Dynamic linking! (libs from /emul/xxxx etc)
	[ ]  Initial register/stack contents (environment, command line args).
	[ ]  Return value (from main).
	[ ]  mmap emulation layer
	[ ]  errno emulation layer
	[ ]  ioctl emulation layer for all devices :-[
	[ ]  struct conversions for many syscalls


Legacy framework

Legacy-mode Debugger:
	Extend the
		put [b|h|w|d|q] addr, data    modify emulated memory contents
	command with a "s" (string) mode, where data is a string. Also
	"z" which puts a nul-terminated string in memory. It should put the
	string there one byte at a time.
	
		put s 0x80008000, "apa"

	or

		put z 0x80008000, "apa"


	Extend the debugger with a "find" command as well, similar to
	put but with a range?

		find [b|h|w|d|q|s|z] startaddr, endaddr, data

MIPS:
	o)  Floating point exception correctness. Compare to real hardware!
	o)  Nicer MIPS status bits in register dumps.
	o)  Some more work on opcodes.
		x) MIPS64 revision 2.
			o)  Find out which actual CPUs implement the rev2 ISA!
			o)  DINS, DINSM, DINSU etc
			o)  DROTR32 and similar MIPS64 rev 2 instructions,
			    which have a rotation bit which differs from
			    previous ISAs.
	o)  Dyntrans: Count register updates are probably not 100% correct yet.
	o)  Coprocessor 1x (i.e. 3) should cause cp1 exceptions, not 3?
		(See http://lists.gnu.org/archive/html/qemu-devel/2007-05/msg00005.html)
	o)  R4000 and others:
		x)  watchhi/watchlo exceptions, and other exception
		    handling details
	o)  MIPS 5K* have 42 physical address bits, not 40/44?
	o)  R10000 and others:  (R12000, R14000 ?)
		x)  The code before the line
			/*  reg[COP0_PAGEMASK] = cpu->cd.mips.coproc[0]->tlbs[0].mask & PAGEMASK_MASK;  */
		    in cpu_mips.c is not correct for R10000 according to
		    Lemote's Godson patches for GXemul. TODO: Go through all
		    register definitions according to http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi/hdwr/bks/SGI_Developer/books/R10K_UM/sgi_html/t5.Ver.2.0.book_263.html#HEADING334
		    and make sure everything works with R10000.
		    Then test with OpenBSD/sgi?
		x)  Entry LO mask (as above).
		x)  memory space, exceptions, ...
		x)  use cop0 framemask for tlb lookups [maybe already working correctly?]
		    (http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi/hdwr/bks/SGI_Developer/books/R10K_UM/sgi_html/t5.Ver.2.0.book_284.html)

SuperH:
	x)  Auto-generation of loads/stores! This should get rid of at least
	    the endianness check in each load/store.
	x)  Experiment with whether or not correct ITLB emulation is
	    actually needed. (20070522: I'm turning it off today.)
	x)  SH4 interrupt controller:
		x)  MASKING should be possible!
	x)  SH4 UBC (0xff200000)
	x)  SH4 DMA (0xffa00000): non-dreamcast-PVR modes
	x)  Store queues can copy 32 bytes at a time, there's no need to
	    copy individual 32-bit words. (Performance improvement.)
	    (Except that e.g. the Dreamcast TA currently receives using
	    32-bit words... hm)
	x)  SH4 BSC (Bus State Controller)
	x)  Instruction tracing should include symbols for branch targets,
	    and so on, to make the output more human readable.
	x)  SH3-specific devices: Pretty much everything!
	x)  NetBSD/evbsh3, hpcsh! Linux?
	x)  Floating point speed!
	x)  Floating point exception correctness.
		E.g. fipr and the other "geometric" instructions should
		throw an exception if the "precision" bit is wrong
		(since the geometric instructions loose precision).
		See the manual about this!
	x)  Exceptions for unaligned load/stores. OpenBSD/landisk uses
	    this mechanism for its reboot code (machine_reset).

Dreamcast:
	x)  Try to make the ROM from my real Dreamcast boot correctly.
	x)  PVR:  Lots of stuff. See dev_pvr.c.
		x)  DMA to non-0x10000000
		x)  Textures...
		x)  Make it fast! if possible
	x)  G2 DMA
	x)  SPU: Sound emulation (ARM cpu).
	x)  LAN adapter (dev_mb8696x.c).  NetBSD root-on-nfs.
	x)  Better GDROM support
	x)  Modem
	x)  PCI bridge/bus?
	x)  Maple bus:
		x)  Correct controller input
		x)  Mouse input
	x)  Software emulation of BIOS calls:
		x)  GD-ROM emulation: Use the GDROM device.
		x)  Use the VGA font as a fake ROM font. (Better than
		    nothing.)
	x)  Make as many as possible of the KOS examples run!
	x)  More homebrew demos/games.
	x)  VME processor emulation? "(Sanyo LC8670 "Potato")" according to
	    Wikipedia, LC86K87 according to Comstedt's page. See
	    http://www.maushammer.com/vmu.html for a good description of
	    the differences between LC86104C and the one used in the VME.

POWER/PowerPC:
	x)  Fix DECR timer speed, so it matches the host.
	x)  NetBSD/prep 3.x triggers a possible bug in the emulator:
	    
	      
	        <0x26c550(&ata_xfer_pool,2,0,8,..)>
	        <0x35c71c(0x3f27000,0,52,8,..)>
	      
	        
	          <__wdccommand_start(0xd005e4c8,0x3f27000,0,13,..)>
	            
		[ wdc: write to SDH: 0xb0 (sectorsize 2, lba=1, drive 1, head 0) ]
	            
	              <0x198120(0xd005e4c8,72,64,0xbb8,..)>
	                
	                
	    Note: 
	x)  PPC optimizations; instr combs
	x)  64-bit stuff: either Linux on G5, or perhaps some hobbyist
		version of AIX? (if there exists such a thing)
	x)  macppc: adb controller; keyboard (for framebuffer mode)
	x)  make OpenBSD/macppc work (PCI controller stuff)
	x)  Floating point exception correctness.
	x)  Alignment exceptions.

PReP:
	x)  Clock time! ("Bad battery blah blah")

Algor:
	o)  Other models than the P5064?
	o)  PCI interrupts... needed for stuff like the tlp NIC?

Malta:
	o)  The Linux/Malta kernel at people.debian.org/~ths/qemu/malta/
	    almost works:
		./gxemul -x -o 'rd_start=0x80800000 rd_size=10000000 init=/bin/sh' -C 4KEc
		  -e malta 0x80800000:people.debian.org/~ths/qemu/malta/initrd.gz 
		  people.debian.org/~ths/qemu/malta/vmlinux
	    (Remove "init=/bin/sh" to boot into the Debian installer.)
	    There are at least two things that need to be fixed:
		1. PCI IDE; make Linux oops.
		2. Implement the NIC.

SGI O2:
	differences between real hardware and NetBSD's header files?

		RED/GREEN LED: 1 on real hardware turns off, not on!

		nr of bits for the tile ptr

		20008 vs 30008 in crmfb?

		CRMFB_CMAP_OVL = 0x00051400. should be 0x54400? for "color map 17" for overlays?

		crime time bit mask?

		NetBSD's crmfb.c crmfb_set_palette says rgb in reverse maybe?:
			val = (r << 8) | (g << 16) | (b << 24)

	clocks:
		Both NetBSD and OpenBSD drift over time.

	bus_pci / O2's pci:
		reconfigurable memory space redirect?
		ahc scsi controller! this will be very time consuming.
		http://mail-index.netbsd.org/port-sgimips/2015/09/24/msg000711.html
			has some "pcictl pci0 dump -d 1" output which may be worth comparing against.

	ds2502_get_eaddr: ds2502_read_rom failed!
		PROM complains during bootup. Needed to get further with bootp() diskless booting.
		Onewire protocol that depends on microsecond timing?

	netbsd starts in "enter pathname of shell" mode; should start netbooting
		in a more automated fashion?

	netbsd randomly quits 'startx' without showing anything?
		sometimes also randomly places windows differently.

	ps2 8242:
		openbsd's X11 doesn't detect keyboard/mouse?

	PROM in GXemul says "SGI-CRM, Rev B", but my real O2 says Rev C?

	graphics:
		allow other resolutions than 1280x1024? netbsd seems to support it (?).

		netbsd maybe still triggers some acceleration bugs when moving X11 windows?
		
		horrible_getputpixel:
			GBE_CMODE_RGB10 etc from openbsd's header file?
			performance?

		actually emulate "pipeline" and detect pipeline overruns,
			i.e. require guest OSes to wait? but then, when to
			execute commands in the pipeline? (low-prio)
			get -w 0xb5004000:
						LEVEL	RD_PTR	WR_PTR	BUF_START
				0x1e029a68	00	29	29	28
				0x1e02baea	00	2b	2b	2a
				0x1e03befa	00	3b	3b	3a
				0x1e029a68	00	29	29	28
				0x1e00a289	00	0a	0a	09
				0x1e03df7c	00	3d	3d	3c
				0x1e00003f	00	00	00	3f
				0x1e02fbee	00	2f	2f	2e
				0x1e02cb2b	00	2c	2c	2b
				0x1e00b2ca	00	0b	0b	0a
				0x1e008207	00	08	08	07
				0x1e = all idle

		i2c vga data, for NetBSD etc.
		3D graphics? i.e. depth buffers, triangles, etc.

	audio?
		would be the first audio related thing in gxemul...

	VICE?

	video? probably too complicated.

HPCmips:
	x)  Mouse/pad support! :)
	x)  A NIC? (As a PCMCIA device?)

ARM:
	o)  Big endian does not really work: loads and stores are little endian!
	o)  THUMB disassembly
	o)  THUMB execution
	o)  0xf "condition" execution: see http://engold.ui.ac.ir/~nikmehr/Appendix_B2.pdf
	o)  See netwinder_reset() in NetBSD; the current "an internal error
	    occured" message after reboot/halt is too ugly.
	o)  Generic ARM "wait"-like instruction?
	o)  try to get netbsd/evbarm 3.x or 4.x running (iq80321)
	o)  netbsd/iyonix? the i80321 device currently tells netbsd that
	    RAM starts at 0xa0000000, but that is perhaps not correct for the
	    iyonix.
	o)  make the xscale counter registers (ccnt) work
	o)  make the ata controller usable for FreeBSD!
	o)  Debian/cats crashes because of unimplemented coproc stuff.
	    fix this?

Test machines:
	o)  dev_fb 2D acceleration functions, to make dev_fb useful for
	    simple graphical OSes:
		x) block fill and copy
		x) draw characters (from the built-in font)?
	o)  dev_fb input device? mouse pointer coordinates and buttons
		(allow changes in these to cause interrupts as well?)
	o)  Redefine the halt() function so that it stops "sometimes
	    soon", i.e. usage in demo code should be:
		for (;;) {
			halt();
		}
	o)  More demos/examples.

Dyntrans:
	x)  For 32-bit emulation modes, that have emulated TLBs: tlbindex
	    arrays of mapped pages? Things to think about:
		x)  Only 32-bit mode! (64-bit => too much code)
		x)  One array for global pages, and one array _PER ASID_,
		    for those archs that support that. On M88K, there should
		    be one array for userspace, and one for supervisor, etc.
		x)  Larger-than-4K-pages must fill several bits in the array.
		x)  No TLB search will be necessary.
		x)  Total host space used, for 4 KB pages: 1 MB per table,
		    i.e. 65 MB for 32-bit MIPS, 2 MB for M88K, if one byte
		    is used as the tlb index.
		x)  (The index is actually +1, so that 0 means no hit.)
	x)  "Merge" the cur_physpage and cur_ic_page variables/pointers to
	    one? I.e. change cur_ic_page to cur_physpage.ic_page or something.
	x)  Instruction combination collisions? How to avoid easily...
	x)  superh -- no hostpage for e.g. 0x8c000000. devices as ram!
	x)  Think about how to do both SHmedia and SHcompact in a reasonable
	    way! (Or AMD64 long/protected/real, for that matter.)
	x)  68K emulation; think about how to do variable instruction
	    lengths across page boundaries.
	x)  Dyntrans with valgrind-inspired memory checker. (In memory_rw,
	    it would be reasonably simple to add; in each individual fast
	    load/store routine = a lot more work, and it would become
	    kludgy very fast.)
		o)  Mark every address with bits which tell whether or not the address
		    has been written to.
		o)  What should happen when programs are loaded?  Text/data, bss (zero
		    filled). But stack space and heap is uninitialized.
		o)  Uninitialized local variables:
			A load from a place on the stack which has not previously
			been stored to => warning. Increasing the stack pointer using
			any available means should reset the memory to uninitialized.
		o)  If calls to malloc() and free() can be intercepted:
			o)  Access to a memory area after free() => warning.
			o)  Memory returned by malloc() is marked as not-initialized.
			o)  Non-passive, but good to have: Change the argument
			    given to malloc, to return a slightly larger memory
			    area, i.e.  margin_before + size + margin_after,
			    and return the pointer  + margin_before.
			    Any access to the margin_before or _after space results
			    in warnings. (free() must be modified to free the
			    actually allocated address.)
	x)  Dyntrans with SMP... lots of work to be done here.
	x)  Dyntrans with cache emulation... lots of work here as well.
	x)  Remove the concept of base RAM completely; it would be more
	    generic to allow RAM devices to be used "anywhere".
	o)  dev_mp doesn't work well with dyntrans yet
	o)  In general, IPIs, CAS, LL/SC etc must be made to work with dyntrans
	x)  Redesign/rethink the delay slot mechanism used for e.g. MIPS,
		so that it caches a translation (that is, an instruction
		word and the instr_call it was translated to the last
		time), so that it doesn't need to do slow
		to_be_translated for each end of page?
	x)  Program Counter statistics:
		Per machine? What about SMP? All data to the same file?
		A debugger command should be possible to use to enable/
		disable statistics gathering.
		Configuration file option!
	x)  Breakpoints:
		o) Physical vs virtual addresses!
		o) 32-bit vs 64-bit sign extension for MIPS, and others?
	x)  INVALIDATION should cause translations in _all_ cpus to be
	    invalidated, e.g. on a write to a write-protected page
	    (containing code)
	x)  16-bit encodings? (MIPS16, ARM Thumb, etc)
	x)  Lots of other stuff: see src/cpus/README_DYNTRANS
	x)  Native code generation backends... think carefully about this.

Better CD Image file support:
	x)  Support CD formats that contain more than 1 track, e.g.
	    CDI files (?). These can then contain a mixture of e.g. sound
	    and data tracks, and booting from an ISO filesystem path
	    would boot from [by default] the first data track.
	    (This would make sense for e.g. Dreamcast CD images, or
	    possibly other live-CD formats.)

Networking:
[Obsoleted; the new framework will need a much better net implementation. This
section is kept here, so that the same mistakes may be avoided in the rewrite.]
	x)  Redesign of the networking subsystem, at least the NAT translation
		part. The current way of allowing raw ethernet frames to be
		transfered to/from the emulator via UDP should probably be
		extended to allow the frames to be transmitted other ways as
		well.
	x)  Also adding support for connecting ttys (either to xterms, or to
		pipes/sockets etc, or even to PPP->NAT or SLIP->NAT :-).
	x)  Documentation updates (!) are very important, making it easier to
		use the (already existing) network emulation features.
	x)  Fix performance problems caused by only allowing a
	    single TCP packet to be unacked.
	x)  Don't hardcode offsets into packets!
	x)  Test with lower than 100 max tcp/udp connections,
	    to make sure that reuse works!
	x)  Make OpenBSD work better as a guest OS!
	x)  DHCP? Debian doesn't actually send DHCP packets, even
		though it claims to? So it is hard to test.
	x)  Multiple networks per emulation, and let different
	    NICs in machines connect to different networks.
	x)  Support VDE (vde.sf.net)? Easiest/cleanest (before a
	    redesign of the network framework has been done) is
	    probably to connect it using the current (udp) solution.
	x)  Allow SLIP connections, possibly PPP, in addition to
	    ethernet?

PCI:
[Obsoleted; the new framework will need a much better bus implementation. This
section is kept here, so that the same mistakes may be avoided in the rewrite.]
	x)  Pretty much everything related to runtime configuration, device
	    slots, interrupts, etc must be redesigned/cleaned up. The current
	    code is very hardcoded and ugly.
	o)  Allow cards to be added/removed during runtime more easily.
	o)  Allow cards to be enabled/disabled (i/o ports, etc, like
	    NetBSD needs for disk controller detection).
	o)  Allow devices to be moved in memory during runtime.
	o)  Interrupts per PCI slot, etc. (A-D).
	o)  PCI interrupt controller logic... very hard to get right,
	    because these differ a lot from one machine to the next.
	x)  last write was ffffffff ==> fix this, it should be used
	    together with a mask to get the correct bits. also, not ALL
	    bits are size bits! (lowest 4 vs lowest 2?)
	x)  add support for address fixups
	x)  generalize the interrupt routing stuff (lines etc)

Clocks and timers:
	x)  Fix the PowerPC DECR interrupt speed! (MacPPC and PReP speed, etc.)
	x)  DON'T HARDCODE 100 HZ IN cpu_mips_coproc.c!
	x)  NetWinder timeofday is incorrect! Huh? grep -R for ta_rtc_read in
	    NetBSD sources; it doesn't seem to be initialized _AT ALL_?!
	x)  Cobalt TOD is incorrect!
	x)  Go through all other machines, one by one, and fix them.

ASC SCSI controller:
	x)  NetBSD/arc 2.0 uses the ASC controller in a way which GXemul
	    cannot yet handle. (NetBSD 1.6.2 works ok.) (Possibly a problem
	    in NetBSD itself, http://mail-index.netbsd.org/source-changes/
	    2005/11/06/0024.html suggests that.)
	    NetBSD 4.x seems to work? :)

Better framebuffer and X-windows functionality:
[Obsoleted; the new framework will most likely use SDL. This section
is kept here, so that the same mistakes may be avoided in the rewrite.]
	o)  Do a complete rewrite of the framebuffer/console stuff, so that:
		1)  It does not rely on X11 specifically.
		2)  It is possible to interact with emulated framebuffers
		    and consoles "remotely", e.g. via a web page which
		    controls multiple virtualized machines.
		3)  It is possible to run on (hypothetical) non-X11
		    graphics systems.
	o)  Generalize the update_x1y1x2y2 stuff to an extend-region()
	    function...
	o)  -Yx sometimes causes crashes.
	o)  Simple device access to framebuffer_blockcopyfill() etc,
	    and text output (using the built-in fonts), for dev_fb.
	o)  CLEAN UP the ugly event code
	o)  Mouse clicks can be "missed" in the current system; this is
	    not good. They should be put on a stack of some kind.
	o)  More 2D and 3D framebuffer acceleration.
	o)  Non-resizable windows?  Or choose scaledown depending
		on size (and center the image, with a black border).
	o)  Different scaledown on different windows?
	o)  Non-integral scale-up? (E.g. 640x480 -> 1024x768)
	o)  Switch scaledown during runtime? (Ala CTRL-ALT-plus/minus)
	o)  Bug reported by Elijah Rutschman on MacOS with weird
	    keys (F5 = cursor down?).
	o)  Keyboard and mouse events:
		x)  Do this for more machines than just DECstation
		x)  more X11 cursor keycodes
		x)  Keys like CTRL, ALT, SHIFT do not get through
		    by themselves (these are necessary for example
		    to change the font of an xterm in X in the
		    emulator)
	o)  Generalize the framebuffer stuff by moving _ALL_ X11
		specific code to a separate module.


Release checklist

  • Build on as many platforms as possible, including inside guest OSes in GXemul itself.
  • If there is time: Install as many as possible of the guest OSes in the documentation; the documentation may need to be updated if there are regressions.
  • If there is even more time: see what the status is for the "unsupported" guest OSes as well.
  • Update the README and RELEASE notes.
  • TODO updates (i.e. set goals for the next release, if possible).
  • HISTORY (mention the release).
  • SVN branch/tag.
  • Tarball creation (make_release.sh)
  • Home page Download page update: version number and date.
  • Home page News page update: new Release.
  • Sync the homepage to the web server.
  • Mention release on #GXemul on FreeNode (IRC), set version number in topic if possible.
  • Sourceforge File Release (upload the tarball).
  • gxemul-users mail, content similar to the RELEASE notes.
gxemul-0.6.1/doc/machine_template.html000644 001750 001750 00000000757 13402411501 020167 0ustar00debugdebug000000 000000 GXemul: Machines: XMACHINEX

GXemul: Machines: XMACHINEX

Back to the index.

Back to the machine index.


XMACHINEX machine

gxemul-0.6.1/doc/20041129-redhat_mips_small.png000644 001750 001750 00000007502 13402411501 021072 0ustar00debugdebug000000 000000 PNG  IHDRocٮ)gAMA aPLTE    t   " # % '  ,-2 i8ykwuoHqc tXv x!!!!d!" """""z"f"###$$|% %%%%%%q%&&~'''( (((((()))))))))})*****+"+++++++++,,,,,,,,-------...../'///////000111111122222233333344444644556667777778888899999:::::;;<<<===>>>>>>>>?5@@@AA?h@t`!:u6PNB%\08 .wg}vË`×tw}=~}[|{n?&|cNGk/W~?}Gn%yx;.|Åg|sa] /|x}S-S{?~x_᡿87_?{}?E׿~W?OEsސ&8Z/v՛G6ϕKRi+6dX.%oUK+yn J^BintvU@/<{fd !@?1A7]]<0a qH'(6!.gӂ":29e 6TeUUPzvulx F بQc?P c@adŖWR咤e:.@GGuPj\i; ҥ^Xﵜ WFS i%`$ b^Kt yXtmJ5.e`u(_cƉBoC>t[i=Eƫ` k]mCL ]a$lR;w=P'Ӵh;k54@ &Ө,-U<}0%> vvNft x/m-N>)@+C22 `BbA^q `2NyV|ijzxd9xp9כֿwi?qבS!`,w%ȼ}圾gL=;6TJS|@#\^s_,v@m0F0D ;KÁ과an0=xkE2uб-h!}G,eT%6raW5&cN<  l$4v؃0Aax6_]2rN.jHj( ]Hѫ3?t|4S(CkzC ;D2+]hIVm,gR=/Y3Xrğ&΄8`c^Jܦ l6KT#̱Q`m8^eNKPۆưjCPlw{$10e>lNd;U[B\`Y;^S ͮXN V/+GVr\Yʃ]%Uyn'R({8 DO+Lyc6:9< a{Exp8KE Hӣav,# )$NOQӶVMfՐԲâ`Ҿ`/Ȱ_1—_6\NGd%O_}{7У ƻ~x }HY8>۴M[oiZ]3Z|x(夲,7\F- B&qf=m[R]kP/RPHrI=%AI?wo?L,SNw@6W|φGkb,GԵ[mR5m祎cA7\ᎍ8m/^;(vHT=ڍ}FZŪW*$ެڭ*,WworN<'l=3ʹ'^؝T۞_jrCA4*QR %]oJEr)GPV *=AB)’~C4qO$IaXx '=$6 Aw4% +($8ҭϖw\-1jᝡ{>_#tIME}IENDB`gxemul-0.6.1/doc/20110606-dreamcast-roto-small.png000644 001750 001750 00000101370 13402411501 021430 0ustar00debugdebug000000 000000 PNG  IHDRORSgAMA a=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATxyt}&U;hTc_ F7p'\Em%q;f&,''N7DZ$vl %K}G)b}GBWߪ{v׿t8] /7!Aޭ ,`!ػһ`YV2In=ֽw\_PXX\ܼyL]mޠ\L:jzwz^jjGGLFJwwv{vJ%7ojhhHRK.9u:?x{^BFG9vh2yBHR---6- F"QJeˆz  ;;y__ GGȽtoݺP* 2DKKwdܚee@ `XŒ th4 әJ&].ז-[:::6Oohmunr:]w?Sz k˙H&,F*ӟ'? \ֶqwooMu /t&S]]P_w@p+Z{{ۙ3HO$+:6o& SOFr2qqnwg:rnq}қM$z.pDѝ;vH* {ZfsYC}x'l߶ҥKPt*JN郁wd$NÑbh=R߾_۷ C-NZ`zz& EFD"H8nmmټyS:h4 J8˭[}linjZX\0pxaa1#}Dt:K<,uxnn>TJJ%NH$lXYYq:Dv9]xt\NBAVIp_!.)`"\N ϳqㆴ_H. 2s"az̙~i$H)fyJ^_[[NC`ݑ}awK˲_. 3̎۫~Y[}jreee{vVե;P(vY]]hvjwgRرcGukشtT*2tبjMtIW$ʐW<o)1?^y~m<}bCkkC}䤣9/LMO895Eje;;]z`0MP(Sd&i**ɨTcǎ666@ H.v"ap8h4V`{vﮯ3[,d馦%ޣ<2r: ]nwɴuk -6[e(g?Ff9|(O?eJ>xSRɩ)Bt4;Cnܸau5hȣ zqo\tF]ZNTl߶vu [>rnEccZc~g p*h4TV۷mK$ۛϯgkCy'P=*-&INkL.[ry}]d<3 s%,[_Wgg^WWW9;koll|9}lX$ӫ*FS_W'N|aZh^eh4V+r'`0hj^[outtT٫xW^gjxkj{H$D$-='6lh]Z\B*8.VB|ojjRT,GM:޺-2n6B+Xl\J' `KG~d2)~Lvd=qaOee%_仺dӧ}>_OOOCC$Hsp8[xAtJ>DKeoԩǏ+ Ǐ+=YV?V?( @7B?{ڵ2Lwd$JEr,'SIQflVed2KoK>Hg+yѸgׯO>"ӕLfޑ;w1;j4ҟ[zѱ#GnܼLz{ɉ@ @$O~h4ad˗lI$uᚚo|d?G_߳{O2?u;"bQ\q\0"P(dlqqy/^\YY 6=P}׮׮ fu:].^yxIEsppR,.}#:r D~ f;1|.+-}Sڍ*7I_࠭|x.W˵ł/Ws˷[d?L�V50meeVQ'=ǴZmScp'Bcc`d"<DF^juuuTJׇl6qErh$c8a28CFd23Iv{uu*yUMMmmDBTrqÆx"a2ZV-++KR^Z {H$Vɤ=h6Z,T*l6^Vb6j4?яz^Aa1jrdf4l6LTj J"J{vﮮJg2UUtZR)b7llkkp8jU.\}P?-[LD"Q__fZ݆ "HUUUe-D"U0/g/\T8Q ׊IuMՅ@v5)_/ViB0ݵK„/_^ z 2ZBѼAL"jCJ,qY]4kF|_ir,*TY刏NLLssy6  uP4 z5lWiB-E,SuBWdB. yXay P,V+yx\ T5ˊ[Z+jZlF![Y&m|KcA+eB6iU`+B"ͥYƱk^Fe.\V .Il\eˍk(B{iʅ o(0TPclW+4fB5Z&z ofUk0te!3:ښJ[Fimmd2o;cK4.$ y<ݳl6k4jsYٵA--N˲.SRY-SZcgwtl޵sW&yey3g;].]Ng}}V}Xkk/ݳ; _J$!h$N2,YK/ HLOOG"cGq1"Nz۹cǞ=_ݻTɓ.W"ttرl6dVWWU*U(:~Z]Ue6UVV* B]fW\,=Vh4mmU](| ڑ5<2=䗾{xdFg//ɊJx:\\ K+IF]5UOv7] ワX?ϾTeQڹWq\]Qm4م˗?5Oz6s<br@LMLm<'rP|g 5k_}äSlټEZH>ns'*csAfcӎ+c2h/}t߿_ü[?>}zc &7~ģۋեLN;~s~|>xC/'(ϞݵmG./uW־d|sjeI9MyhOhfVrl2cǚ˴ OYo֒>1NT1A )nnݚCdjeY1CᨭMN1wDϻ;;CƍWVVȤsn qx,hvttZų8qTJBGQ H$H(JY$I~bRi1qhz`nn^-(ǎ-dfS)UtmphHXt:IJ  4S̪$UɗJ"2b:%\>ǖ|KH$ȤlkJ$:K>.L&ʃN&#>X(8].AIg+cqֺ<}-MRJǿX>7U9j8wC_ՕOG'k˕m0~lЬ~g6wtS~ʲo1򼳭nfɳW|,da"NL&+IR01TOL ͝:nũ - .ћ[\.ϟ4'gCT4yUn:EXֆHY{fF .-i)"5,OkoJAd`)^&{i#3s :YM'K-Dd*;303PaK-,.-grkȋ@b17*S3s T6oKUUqPAtww4nI&/\uft._6K~~n*xMe(Tԧ[3pכ*BVzkҨ_WjLRu)4HyM[<4hJuY!y-Tx>t|:@ksRETT(U-Fdd CEJȦ[ChiX[*K70ZTbKlS&W(ɨj@5ФPR2 4ffM]ROTwLb5rʬhK'V՚kE?"#STԴEC\.1X\VqqrlmzMJִn*_]u*d2 C^KˋEu-#xݟ~ٺ+1AZx8Q‡ -r7ȨBzq05b1:6T1dž^\*3HhQS_Kٗݐp鑇'>"6B J!Ѣ $H(A wITѨO ~\@ `n{J C[ >ܧy|||{CǕJUˇd2+[J yYLѱŋ.\vY o H##sb+7o׀trr<ܸq*z2T&JbS=I A½.-&F&[ X;[ r劣!I$] kCN / {?+m ?Zy&yARSE|E"?dn0"~?B8pL&ZP4\ޱˠ $CJ;jIY,RcU !Z$p:G577o߶mwo/˲g}' AGٞj%-(bX $HxhQl'[ $iQ R :D0,-5$-J Aw[0'g|OQ[S^=ŢDDJsz]?}{8x_p"Q[~#\RR}'/u<$hn޷oﱣGF8_3t w7t>}ܸqcǎy9>G@L&wJωI;_kܑ>Azܡ"Ñ_NP(0Յ xqAV[VP(]-[9fFc0x+W~EyVz{7=#aȈd /(ZA X_!t eYReh4VQQa*3”d(D` FۭsdrK.߸qs׮]f[,l4#mJZ][[+޲lx / \Knfy^wFb>t׽+ދxJj&)RYk?]w33ΐO +Yy[JβT*@!cxo?66qwf[OX?j``97?_[[{gcZ˲h%INt29VQAS8A¦MW X-Z=??߽uJ.[Y]5LJB<((,KJ<}adN g'&ŗP7`;]2sJ ^o:?&B!#\.GNW:}edxd2id1( Bx?vT: xn_hn~~~~m#Zzw{{V-4c;'rn7ü]NS.74?^wx>O}h۸ѣm7VWW{f{{]NgsòlWW׆ b>O:th b!Wvw&Ɏ]8+=dݩV #gqpiN[R Ο WhkxW_}Mf.3Ju{5ONڻk+o_l6`0XZW^Q*3gJmoo{饗Fl҃!A_ ,˺\Net8)-Gmm-eYֹ+(Jy֭%OT־#T*kZ[[4 qjkYhjj4L7oy>N  ?}?,..9tq1Ce#cͯ^Jqt(-{X,}ϭ[$:2L9җNK_& b@hlhT*R)2Ţ-[:BDccct2;0*J&F2)I$7 IDAT.wX,IWV,f(og05=w:.֭Ǐ'-cc҃!A=riq8U:w=**B++J${WJ{N>p{j%$J(>5AtcG655?vshnv:2G9vСu8zȾ{<>|$Rܣy#}}2SYɒ TnܼӽƍJβ'_|?}?9e8kok# qOD,[ڭP0_owY\?|{-qc ÄaZ:u\X\llh8N~WZs?t?UUX 1 u2ijeVoֈ1~N:c"_4 -[4G ﭴ^$mذՉW#p8沲2ΝzcǦxYZmUV(^M633s$Pѐ5;.RӑuEEN|{?o b4})6UTcYv0h~CwgL2 TP+/\!{UU<d~Z*n۸Q?99+ ץOLLpH&KW[770lv>$Q~`|: ºw\t:WVV~+W:RvDtWxGJ)B#ׯo޼''_rr %HpGH>Hh &~]OIz >LȲm# 6m߶M.?2bZj"*}$Hp]NbY^^.p_z)ɤ3(}H$Hϔh?juچzLFfs2jjlӧ}>_RNdnzm-Qo`j" z A'-OX )p-ZΔߕzc3=3c60 .LMOUp$,eI ᾤE/F_xy_MbK >VccR$ $<Ңj_^^Hsv#[ZZZZ/py.T[,*w=ziP'}Ho2 T4(:@d9 @@L(| (~~K` @2 h5qRH$L@Pf 2r0 0 ȁj@ Ȁ@!DQ(8`NY@@0 D,i#.3HݷwђӹA(l4eY٩K.ڠRw}NdFjkk1Њs˖.AJY8`6<Ȥjʁ(UCn~$ҀPBVo,s%%ݳ nyWA;kzjxttu6GdL.;yEqXee%_仺dg~ڵk^0Zh4^wx{Lx^'M_Ѩ 0@2Tofu(i#TL dU ǁ-H^E =25  -P'2@F:;)*0;J Ɓ5pm:ڽ390y$QK7 u~sjDKR*B-xP[!lC%jvLQUjSES3!(<dwQd̀Z9TsC:Py:#OϺx(1y 3f*Pr O'db{s J&/pPQF2J(?"K+@Ȭyw@4 LeX%K_6ǀr@(?P#P^-Qs4QCo/:OX3PXUd4@ B}J)ѿ.l1Z?9yٷoN{9pkz>jxua~>uԑ#k/kSSSw4qR wM * - 4$VF@ 2Jhޛ,(zS}U48yu4 dtdʁ.p.Xȩ/E Ry i,Tml|y= XK---UUvc>~VU]Vfq`0tʕښo;DpC-G$ٳ{w<_-oڴŗ^>'<2… [nݴiO~wK25ߜ|%׻kW.cJr羽{y|';OAHB"(hƋ(<"h< !Y>HC Zxg{Q8Ks-@=L"fޤv`x`k}P鉋0 +<@F>&r*i͂o벒L9ʻ~(N[y2;7WYYVj`pFGp:(PTeeeeJ2 \*Zz>?X|:0 h ?b`1C$%&Y`WJ ^LZ\.}}d"y){`q\y@!Jgk%5MFQNNJn&0U] ۮ2@PS_ n r$?ƁXnRX^Deh @_bEP_9ĚP+Io$Zܱ}aC9ft:Cx qpEEEr9g>Q]]'HFR9[-]̧K#,> gIᲃݽή.Ç&:c[;695^tqrǟzJ&] Hy`(0(eV(!E`FG()h M|M$T`HMN*IzO2`5qeg?%JUD Q%=IAe,0Oזf G5 HҮ@e^ND`heٛMMvU*vb,'ݞgܝn>ox[ӣR^~宮.F+O4&VBx≉t:7TU^Ph%JI4 6Z{7EEJY:ԗB,W. A稖j4T*5)i5i11CI)Y-Fۀ~x;JkJ.^Bus/(HRc3)h8Z\=ػg??x?@bKJ` ;2r1baa`(fz$p5ZZ6LtLNM~{۰uqa1L,,/[n%7n$JW$ 89om==tZ ?P$n :`G 8?V&>-려2Hq=+V[NC @ HZ [ch* 0Tҋq`D& EZ&Gka䲷((8 oy/.R[OS@!?TP f`3-Q#^%1ҢV!8(}9@zg @\v oZ N **@%\38Ay3OxRu^ /~O9&>hA6yPu$e;% U@G]< &0GUz8 T(3ޗvQ/I3+f [LPiC4rF,0 LӘ!@iJ,iE }έ$5҇BI=WRpoI܌(̀|Q(j`fh(yq V Z8|W)2RT<$97# yaFToǁ\b4m 5qZvA`D3[k KD$|X>:]ֺq``&B9eC#u~h7!`z֯W rZz$$K624)7@ Pr4!G l@Fnhp:s@[qq@ #`狧q{ Ѣ Vdh}02j災bI/P7@>Qε j^XlR0Gh"u<`Ab `"@.H{i آ^- @#Te`$h\QRD4h\<$>'$5 TKUSS  ,ZQ#]3GuE1- AI;>gILf2!6 `F#;+lNNxH ea i$-J+=/$-B=4T|N=RTq@R PQ4GDd *etf KhX5e3LT>-,: !T@2zq'0JEE 5fm䐽 羋E1䝲,?1WTuIJ@Y"0 D Р) N+ߘLFIEҸ*F+BiR@()f)3KCTU'XTi⊆fĒ8%2`ڀOAiz PUIj9ZE+|+_WO}jjjlvnǟzTOwXw̙6^uR̵% @SSS:==DH$296!‘H$v:esxfvNT em6RyYvfKR |޿쟚v471dE ۷7~M&ϷT*!n۠שT*B1rX&>,PxdJgf՘9W򚖲[-`2H!HACLi-mqůU?/:w㩩~ܹx">00055D bQT"'N.]ھm9Ruƺ:VK^[ֽ{ܾŢ7A۵kgcC鬨8wիהJ3g{vnlp84j`p8Jp<08 Ym2r{{[\.Rjβvt޼yqr:Hd "KKiTN^r'@ P:rZgAMviZPA<PHK9i@G=- *ʑ҇>`v$ST#&DaZ[E$5;mt1ZXQA 4l3~hD_k|6o󍏏|Ba:e4yIy`@ɋpM~M jUvQiIRǡ&x4QEeX92@etF m],@W]>fm򟎺 DhJ'4x¦؂* Dj}Q5 V4=YdiPˀ4xr%w%ͪ&*y&C@rwQJH)UC%LkAK >E  -L;DUj%u(u>icHDKk8J$'F ʩxaSR#H ujkKB5`3upTYrGјDʹ$q4PѴBU /܈-V=KunR w h5 RXpIaxx& 9 )9խEAfn@QI)hOXF%KCTP==Qb$RBso@$!GCKBvbOsB a %HpBFKa[hsQU,p M#?)yLjwQ/4<;N{r~Z'zQfi6X/* ڍOSc-#fs4*O%' n3e;OD$=y"x*) wZ@[fJI*H5e1,=Zn 6$kh^;h뭀0j xIzezSW&zȃnCIw@텝%Ѣ Nhv.f8`%khCRBF% %Yh҇ZS cKcFiA8Pӎ@R(H⽑QXL V(zo{([ C 3BߓfGn@KE\I_zlA7yo=:4D"A3)1DR@*ٖ,]].wtyÄ0=ճ;nOLV3]*e%e $FQb#?>+0e(G8+d EՈ3T7 -,Bj{!OLބ xr> :5GƗZ>/ $ҳHR@_F9"ETLPMIy^&@ V$F'tɌmX+ϯswz=øl¤il7^yF^ݢ aπorxJa"6RTLRDdr^#+ C]D*i"JjsRQwQ%!YaH.tQLrSS>u>&`"@# i?QBQ ǔ,Y@&h)s+Ӕǁ$Rfbe]2w d+:1$;^;9^rG#Dr1O{ H?*z=V”px:]_R??)%U(Syx!J|@mXJM@5z~fj^&̍p*HRܾ'Gvo2L'HN! Gď׸JJ7 7do*$nRRjŪBݢO1T0-`$O;tad=t"TZn&:GuZ*iy_s~ ɓQ8 ~Dݔ\6(+NuжLszC>3E ZEb(hk#%/s^ Ta'F(+-`M@9eS$e*d1a"vH_ ܪ?+)KBԇh‹*hE KT#])N)(^15 txj1OAzH[$n:Sl~Flr=K$X dF O i (9 \^"8rnDy O9OMDJɧipʗ1a1HD5<~hRFEYN/[ )'%oJ uTҸPZx$?y%9 R.%@m҅0{+@ OO1|H'" *ᖐbOdj@KZ#~7bԒ}@/&T:Y nQ rJ 0aCKD)o,ct]r4r (nѪub׏T G(p:Db*DO!ETBKi9Ѿ!׻g@J*xP(Ky%`,lZNh״`״"˖(h $ H䵗򓠬!,MƹJT򒋤9EOvBw@DPsxLA&$1^%*dR: nѫ1Sh#RMzO9۶m|nА^gM C z-rrr ě7[/`89&YiX|Lf!uPP´SvEDkqC?OP\&v%I: LPO+:ZhHlQFik&;VSjzfEy I 7[Z2YaAaOϭZҊx{^_bc7Fcra> ׸*D9\SO'%ZGUD!Ao*D|ܼR @&O'z(W(^ :xfK=w 96.E_Et%iT%*'O/}T$#%EBno'}8J.4Hk؊ȯ!Bܶ:yd3GFF^SS#0@ޙm$*IhK+!˹z+70 ੆J)dIz %`$l̇"U#ư33.T;!" zH P<%D^K 0 k;PK+8o؉r2ԏpCE2>ec'B-TEHfHQ'j%d7W-@E "}}#,E~kLHK@!aÏ> ~(t:/).ƳܜɩٔH8RYieF<;;G_LEyY٥˗rsrɕJ7_z\.^ɹtrYyY$ ~ ق?+gZHc Utˀ9WqXT`O A( @8Q1]i52 '"-PRhhLKjf7J(|qh˒K% 1SD aǍǝN޽vl108t9wt|>Mu͵c 0ñw1%ٳ,T53333;399977]=%??h4[[SzI(ݻ73?q\ ޽F۷ z`~}| PBA5f@J-%nN`RYbO #@y B~ ݎpW73Gg1@B@)$l (s$s U =q*'oR5@ঔ KS!z /l0Ν 9DbbNoV),k?wxmx2^f2 @R=D"eURR1C _GGTBe\ia`XY&`$*!ʆ$o+SH*)d} tC::Wlk4;+5Yn7j~PZ?~_@~~gf =TB^Q>ڕ+| 0E@[$$r@K$EJȳh*@DL!<^0 DL׋AF!`jfP^:ʥPZŅ1^_ :CAqA+I1haa̬`FG***|nQ"l jhvv.\k`gccMMMrrR$*+:j+**hs-Akn6mzꫯcT׵lbb~u[8]|o4&&'漱.f﷘Z$%%gÇHT֌80))ibbbd\ y$xfy}h4 GѨR|g{znLP^_UUr6o|7ݦw^};꽽q/o#SQ--5(i(DP 2i$ *! : TG@d`T/ t"o\(%0p|ڦjA[&ÀwaIL+@$E4<22b1^Anٳ7m~0MKM333r|ydqF9uV-//++/K2z]<{#GNxp8h H8W_ikNc,Y++^e_ljoow\;|^j,fsQQQqQjVkEe]n4OM5m M6[Ͷkg#p$oy7ncۺ59)yy7>v 7 7MJ7e,Y]0OUI{r*B 2$P!1 Bq5J$LAUiOy* jDFunC KȥM(S3fx}c$mG|oh)R Z,qAzfkssn:Y^TjJ-J%bbγ;6l_ZΘGQLDHb6߷~w^v3q{6ggH -~hxMjø9aVx^H$z[Z>@&g,b1۲rB 7Nkvv6>>ަWwб1X_Qa᪣6d2,ɢ3!*f4y%OG' O˥H A"l)$3Da6R2 H >Xp T @d,6 hR. VO5LEEp sCoS.M6FT*BxbڹszW9,##CP[qU~u>sa2l駟B뗖煔 SJiy+fa`ׄ~S^TT_rv#f~&"Q%%({'7Z)tetE@E+?pNfij& QW?]:_992va+@) Jm_KNUYGlO\ .]^|@D)E^KFR|Jtb7"DEJ %4B?cPT0Q03qCTAH$1j5b-h T_&a/qQK/ȑ')GZ\KGM7^ _sO61B 0Rϼ J+D90GMWdT!L@q s#ڝU\/Q d40tc̓S"*HfJdy3TF'{b&saڬ +! Ɓu7VJyd]6 jMNv7cRk^XgnΫ*2_̰OW-z`0q!H!#FXBZ5| BpL+h!"]: *'(̲"ZeqSTF''Up¤L 9 _?iXj mȦF3N^^V9zX}yr:+8 OW +eZ YNAov!P3݂P+@ E&ZX<\T;SDM leBDJ^'=)_,F^x(O>p8rw\wusl;vWvu򟀯qy-m F!?@"z aieT7"(0N<9HP $ yj?n*rt@bA;, ۀdN9O?nBȥ ߽C<Q*l^+udΌGB'}=Z9uoy)x}Ve}raR$0~.%a!#²ܙPRf*MX"9q ~e8Rc0T IDAT@-FZܻwJLL+.c`1.[A~jmimJLL<}}n?lnjvO c?:rgm-7[Z~acUJV_(,,,uKXFGGV+WVi}̬f 1gff:3k<*d@U" JHm(IF5eoR@y$l.P0A\@@߬hHU([t<4[ @PE() S׀Sd&MRlM6۳>SahgcczzH$*))HM6[~~>wX^^Z_WPP(rsr?ښ\YVYY1[ݳ;ɐTؿojjjΝ rm0Y0V\]֮쬬ɶwps=뙙SN, ,}>-5+w裏,fWUUi0>aU9K/X,}~VufvQj0`֭ w>f(lTN ?ED]<%5qHm: z yـkT@>` I0Gm>ܤD~T y`]͗e(lPyP0DH8K"#`ωGnT"e_Qtdt4Z_addddefr}0 E"Q?ﯬ~vϮUVVa|ˌw,--[Uv|>zn9w<::6G"p8̈xBHSSbxhh/t:MFɟ/WVZceBv9_6Q.,.mL+)33y!{<.J^y:R"nRm]Rob`tG\s#@"H +"B ^(dvWA u@PSuоd JFmxߓ %'7w)IބTī'}橩 }r)pN,dZ*U@iodnoP s@,="g"=DsΓ[*HGG S5 -Vʛ{šL*RDwRicߓ6n)ʸlܱRk?Ay\@&%4fH`FE=A@A g!Hk-DrI@$u2 DaPK $$n|J *;kAI) ,H 22\d>H> >0?f4$&Ybp ٰ򲲵b4*˺1{CؼySUe%;bT*U}]RdF:Jfh426ȄV{`Pc@K0|S1{~O)4^$@7{Kɩ $0(p~  2L2l%KWUA; HH؂2|iEܔoa 2 #C3y6I.Y&`dF&֖hy~իMM WiI[n/Ȟ,Ɇl{(kӟ|:---=3ټthmc+*,vٜjpgƊ ˍ7-fsjZjkk˻wo/1.λa̖-oY1&^ݱ0<<\Ui=xRVVo/Nc[Cå˗o){X.25 |㵧e6{zj]Ɲ$7Ǐr3 X}m1wZpÒHRH<22j0 ###~@ `6fypp0>^tmˣEf692?b2(wVq7˵1%ICW1w~.c~h6E"ў={t:m>#˗3`c̵kן{ٖVfLKK<3===<<̌dO~UiNMMK%iKKSSSoS'@ ?86,OSG$ `(}lxZ!I1V]4PS]b%{YZZb:rFQ*ee|C0*ɩzKkOa߿vCVTTUU ?3 dfh2)B]={v+g&=-m_s:1z~[CÝ-aZ丧?{ G?14j^L&^\\5)dj73hʆ')c|n9T`HL1m۶1.ZyyyIII|B>',-nLIyZ̬h\ØΏtZ{IMMu8kjk6mڼd;6w/DQْɞ[22] T'|'cT*_R##Vrnv>)))%9f;.h4z<۩&qbbn_Ydnkk[Zi!y1WZC ;t\^3^KMK~Ɗ(Jn_a\.Y1.+dfdbi63)))䐃^x< KKK (TUUvttfLqQQ0gYYꪪDf=CHxRR.3up<.nQg>q=ԽIIIVih MM&P)ĬTӭ[xmnDSO&"jjj*77W"ᵻllLNN57Gavf_ſ9{pIIgWWVZZzH4rpH%Ns+̘̬LZ|g` W}'Fq_sիWm ˭[/=ʌycvc3faqfɛo16.rc*,5f&;+K$Y+*"ȯ~pl[⢢%[M Әᬬ63gβ W64ll߱b6KR<33Gr 7ov{x`x<3SS͘gH$mv;;9<ώ9c>ㅅa>hJZ{f`}11øpScLQa'ONɓܡhoo&P^ АM&/7W$޾,NK*2zY̗jhhH&tڡᡘ7npU;pxǎv 7nܻgL__;KTnN΍77otq `0DW9JM5eff^p_1zo33@rN={&&&;̶‚xfLffD* ˍ1r%dz d1D‘{v13Ÿg;w&355=cq:ߘpppp?kC(d?)O&6h4r=z4?/(@S^gkF#|ؿ v{vqmpp@C}h^Mnj3)7'q3R#"/fCgG#-7Ř1;f2W#,>J-shb-ѣ{lʶl6FsƍښW_?AUU%ɓTn1aIIɩӧKKJ^8zGkkk]h)?Ȇ}˳ ˍiS)I_ИkׯǩT1 Y޽>G;Ƙh+c1ڷWp=7& GQba1d42M\_ؾ}=Fq `j3,oյȈ1F&'AcV$ xxa^HX+Ν---]ј0N+psk ͌Nc)Na1a|;F>ayϹ[ܹhZڂM  `F8e*Gƒ=3``С7oDs6?ʤRX0ذn~Ϙ _sU᰼0SO @'}-@peKmJbd2YVqT[Ts[U*U֊8P]UeB3#e2يfF/+yBOɹsvM6[jZ`FFF`w8n٢Vb?/;:c9e=׮_3u[??XZf+--YXXHNNڵ |p y᫟~rfL&NwUf-[.^?;~}6̬]6p {zz n{1DŽKIIa8't֖d"!Aywhh===U^_:;Sx. HZVT7o1#ǝNv hKII?.**R>8y'kZ wk^:t2rn` 6t8A__j}\\-,()=H7n|ȑΈf8>l6s3#|nxq'@W'D,O[D}>WwT* X7gd4d2siiw~?}]N۝wX?Xo4RSP__AA=d'iq^}S)?ZZjTNN{/V IYYed~aAќ:}Zղ͛Μ=ynϙgʲ>v .AnY/~Evc`1-fjoҦ-j|\ֈM#(D}biI ƽ )wn{xxdvv ##577y^l{l6FlP(T*CPwwݻCccuyne`b~==zeSSSPucz?:.77Ue6h4w>;/㮉 6s#@S !2vɹseeeI|rN !"KHX;C 謬JHN)m l6ձZdHOKVTpt:njn cd/e\ZQaHNN§D[ kkjl6l>8\VV&ݻwI$Cs Ϝ=Qka򺺭۶m{\/TQa)?t z>{mdff477l{ yw"fjmԺŸ8eIIII斖 ~?ב9!!~rrNNM&$$\x!7'pܓ0vy$)**}, Pi\x@2wggtqf~#l'$^n`vn'*+ή.vzmM篩9~۷ -)n|brJVsk/T*GFFwlttu^>95ɓ8q`~Xd09\`hhELtL>2:*× !-#Wb} (@MD"Z֭M6#HggV"5lz';++>>Y+* -,,$,--ڵǐGFFfsii;38xW|&A0b;w8_c/l6Fɑ7[Z;N>]yFYϕ⭷/f\XX_Xx, HGFܾbZE[~nV޾}J$K׿0KRndRFqdɛǝq=e9~sEŧO^M*"/7HJJ n?+++e2$ qnvl6|>L;v#5 :;;۵sʗMBҿ$̃'Bl駟qI$?~F O t0 |?&9 TFSuV))sV#V#̌Mp;sKJJ4͖Zñgs7ǩT24//lz]SSm0‘ߵk!1QѬ*ߗj;PyYYQqFYM󢹩IhԚp8lJ55_xiw_EM===y߿uӘ⚘>+y-mȅFF{رP0d4W#j\>??a~aa~aJ,IDAT< ye5A -&'#.VZjzll|۶G{{fff~~3gw511!H ]^ZRr>mLvyWS]==5=6:T*FFF><<QRMNN O?L|bZzshmmIINk>OP]SSS+*,~8 )t>oǎ3iZ6 j4>h4 : T_xĉJk[kܜ^VT xfftvvdgn…  ivny~~g׮0:6q gn}-@O["8s0xR-tIME T)tEXtSoftwaregnome-screenshot AIIENDB`gxemul-0.6.1/doc/20140803-serial-upload-slave.png000644 001750 001750 00003270465 13402411501 021270 0ustar00debugdebug000000 000000 PNG  IHDR=Y1[sBITOtEXtSoftwaregnome-screenshot> IDATx'U>/+uA@tХ #A}tTtƀ "43  $G(ADGG&us/U:gE;YZ|^Zꬳk}?jԚ^uǚ"Άs_ !&b3656E7RFM G@yU+()kRGgSfD9$7QT y\^;OnRfǿOeRb}2]n`*.IQI_\4o!oz +A:7Y8E f Jy(+:e6 t>]ȳRWY޽+u9:ٺ}OTBf7my"Mz1ar#)|4W5 jwihxtÚV>2׫U&NOb¼j2&QY/Z59.&M lsn5hZѹGANj/wKXU8nf>/_wx}5HV7vR꣼U1*MX+ѬSY__<+.#ǯ5o>ė?lɓ@-PJbPE &aԜa+GiQ/-,FnHon7!;NPԗg4⊶9W&S[o,K?{ݓs/;4r]a*G䄕{M]ۼ٪Ij޶ЈTԊp,5M(2(!;‘Jð'M:D5#%Ū`ݯҬA\tQZ(*nnb_QϢ'vDß;%K2W.dP;AUIGe*mM2(kwJe͒'pa=P4k\90e9SVqV92k;*^Pd }iVvANLtq?hvX[SG+NCԪ;iW۪C#W/,.t[uS@9ThEQU'NW$bvX?"Ḻ ӞZբ0i/mVOZ20(@HLE)%$`R l!Zc413)"akՈJ*fAFBj<7M#6%J%Z]"dac* 8J9,BE" bHkAZ F $0(-bEUZflxϞ=qVJ#Z"Jker|/avH("R:Tpl@VDd%""")`IlKk dA@B@AB)KqJk\əX6nih8ܷAA)T @E`Z8Y2ev]y"TR-23f.+bQ$Du[Vl̬&b1K(N&&P̑{"E$G{( x c\,D- # 0;J"+"bXP#"fJ!! x-9$CkKڰAEʘDXkeH˗OWࡽid B$6 0! "zkՆ-ʴҨਘ_-@DR( b>v YU"&3EN;i/_*s-2۩m5꾔eKx|ՋR?('C+8fũyGN^8ӳ qRWEcUXJ08~TYH6w$RN%βZ>H{T%p)/ {:. ,::+^Hoj'C< (bfnMg***Mh^H}M2 UZSf&%~ ͨԖߒCpqQZjљf#D[9^ZZB棥p7r@@G9JIRt=7IHʊ8s y#ɈfgKcֽd|5bَ=;w;UVɋ$$ɱVS Rө_j}-S=gw2*wѤxadžcX9*e۷Q#Ƙr82Z^7kԇ4ISTn$J,-YJ A(}rϞG⊲Ơ6 jEȔ%7FkV8Jʉn{=wQGj{ `88c'|[//}~Գ aNN~v_OZuZ@Sc")]%v*hzN:7l3>k I+K­Txn[$Ir3ޙ)]k 4]1{p>pa8ytpPَGy8"ɋs+)W q(&T+!U܃GgMZ㢈F) ZU퐧 <_QOi6gK!5,O0r*HR|1n2Pu*eBXA[z8IR KcI,VuG?R~B,cj4bl藼'UD"5A Y"@@"M E-$"LJ) @.@2 3hG+EX"$?G^x,0Xf$ؒH! A^()`" b?&ӡҀ RfEɖYVH0Z`RgC$r([¢HYQ|,D4(P!5lREVEذ )ҎeA"֎:WdN^IjR"XA@@ 0*D@+λ@H,%*`D@Ai- ) *RF 00k RqE@"T( 0X#l@ز1̊"$”HEH)(2(eQ0# RZVD   Ujmli{K($l8.Sf9Z+$RAD=kx(jʢ@@ˢf) X+5 (Zప4:mk `5ӤP"d-H蹊M(G[@6Fk.0"2EYeEv%1+%3+Tz E”h̀X)cc5iHRcv#Ҝx-H΢(s Lnūڝbi \=W;4pX+ %ڊRЭ>Q3Xl@JL+A#Y=gl纾t,+.0UFIlLnK:Hl2 2Sq6v&a,Z6N"TdYS燎a yL<U?гsq]p%2N॥v!FgGʧ,+F,. { JG)0?H24ĩakNU[+a)1@^>7;ga6i*cl1J)7#$5z..0hԛeYX^87j^Y\ԣFAT[s O=ۼXX\<ܳ4*cz;74Wkg /:S9yO۞V+QR(e4Yo^Q$sK puA#cg1e6͓%٭qꩮ)r]L<;旆QVfs:0M+z3$&ڔj_Waf.֑G:>$U WV :Noq&Ô+nTZB70dܣYpshZerګ^&æW7V;EݱH"etS-twQ< (7Q i癧?3Z" ۪EN(azLojzěUռNX>mߺ9SC[ex9WV!e[ΓXj죗|ڝ[՝^~ӟfvz:#dib{ tM-) ,\T. NgyYr+@+%nS[XOxZ;KC  le~sEk_}{9$%DڵV4 HLEvY|ͧQ<ԞeUk,olfg|2)|c]?M,k6Zlc4`ŪU.}qwW qxov4w?2Emb*x1umhᙃڍVSRQۨ~z:/i+IHJ|l㺰")rӽHhnw`\j*"j:J4z(B'!0{K Lњvg2ˬev7Ofe"eQnc-cF滕MШIyq(]LM*f`l\nAؠYIF,N8b4"NJ#%-ĘB8 CeYqj0Q*=ŁIqO5m>ʰTAޞhwK4bQ4XuܪǁЭsʱ&m2C4:J.Tjؐ<21dFA9ܐ)xcqiR;|9Gc-"M(]ofE ,IZq+ZŁXU yi; [ ,j7S fM=x4RڌL9$ ٹsqf?4=9&''W:$ U0yZ#"`MX0;D蔅#SdRQfi1XG!3(eTDJ1 0+&TXBTD q\c @-%HeJ;!i4*J@uHQ)R8m%qFid!F"Q"JFj4E,KcK62*>VemaMiKSR)Ԅ Zki%(DjblU\XmGҙͯxk?s応xIE44;wΎDb9wTUuV"OrޙC FSIjzU\ aܫyxcf(Erp+R#Pk[[ Q`9&BYI,g]" uT2=}r1u,%TՄEꑐ TQ|sWt&5ht>, 3&NUm]9%&dz]blzcƘ&G.EŽ"Xqj}o7ܹOsL.eW3xn~Q6owƜ WT^:][7Rš8o{ͼRVxВVqn;b bR]5˭ku'<%FFG󭊎tFw"fg  nMϳɖ$VSdI( w

鵯O|Y!keY/LPBjJU&^}O:j P pa |eF fBP\/ŭKS*&KLLbYM\BV8HTc a' +#^}0 9wåAl+4* \]$"TҴF7Dp47V}_z߿}Uwrk þ3UZjQI6rUm)YQa5UaTH%NJ*S,@ݱfEzbӊcZU]f)[U}ʓwGUhg ud ;JTóKBq>1I"Ʌ$O ەc1hZU$zǩTg+`gK/t9nn[ ʑbeg%~YrŏaEZҩ;EtTɉ!cӼRvGYGMTTk̭eǝrpsD\8,f|љh`il}QhlZX5 kRW|򲧞|b~anna'?^ZU|ȑCOmШV)M!Qqei,K㑘@7n~ϡxn~bbazzξ?<]z1%\n\;vn袋,""yi&{RgÇg>whM&ieEYeg,pI%IFS>pM'p"!ڲo}{ hong4 x~Gm{.k]њ>Kv5vn߆ ]3iOop[Ї>]as]pv\ر=Lm;wwe ;m m.bB|g gxbyecP5xEo۾-;v|.g͢x3>pev%n(ɷ^–>xےpܳϞ,P,ˍ_쎝Qܳ.8lA_3Q?_؊e).;8}n_r )0aTZ΋( S7~s瞽(zo G")$ɬÞ1Yۺ; }|[Yl:07&4+H5xk_w}o kh&,<ǿoݷ' v 7SY G0E|jgQڳo" EIǧD($coa߁}7xSF*u1G ͊,[t0D]fKuK ySӯGV'?5_z^|gy#=o~-[ ɉO\sߑ[ QYH̿w_sW.~[n]nK?~]61 (,=W3ҊY<[n{- S+V]~eN==,iv`LɦX?b7-p{w}m߾k_ѩK?SNy]}5֭O~iO]~<+6lēk8o{wW_Ս/~zkׯ\z饛wo}WznܺN]+~oۯSO>u{e{Ӧs\{7>q뭷\|k.'N{~y[o]UsMeش4Za宝<ܳS+&.c't9?K!YRn~aLȽ޷cknf~~U_N8U_-8 iA)y߯y5'&/7`pN>Mo|1q,jO~iΚ{߾c~un~nrrO^~)/>7iKEYIZ\G|޽o__~:|9hE(@t}ܹkNtƍ|ownGG)矿 yz˭?YD}EnwUe7}o_~MBz/ƛ[o(os}ۙgyYgsnq8Zu9gYG5CT^oE'DZF%صc{"RDiXˆ ޚիGQdR^|o2m%I+GGq^;ފӟN1׽; fXTv{Ժ?nzb +ٲ@`,:-lb@-#@&c,Ƙ_׾5w} _b%^9꟮jM~Ƕ<̎rPZn]^k׮{|c$y.ly7֭TN;m}FuҮ_ږ~ f~hڵnG"ѵk2}a.J֯_O֮_塇~,k޲eun{Ke#ׯs=g=蟭O`˖׭[oY֝GA D "lydڵ@H,mrꩧN9\DXd~/vwi=QZ ǵk*֯_c+BG)1_?vZk4VA 5 M6}>T|OAV3t]*Ԩ-6V|]W}SOM^a/6oQ BłV"m ǭZZbj]wp.EplvyӦjzJq-[͛61y@Rqiؼy[8z6o hTP[ktZzzUܕwy'cZeey$͛/NOr|oU6ob_<<=T{t HZ,ɲ,II$&yy/Il9Ų$ʉfl"QFq/e']vLPB H,AΙ?)J%/nSUϹg W1ƶO=mcއ{ ˥th) IקYzꩧnΎcö[o'/*Tcmss%{bMZUpI"]5& /h$N٩z,ŒPUAAO`L-:D`,f1Yb bC}qqX)m"TckTR_P_3749]5i)0{^џ[T(^PZ{W,_嗯  ! h""K`%K6ԥ.[Ώqou7\饗- [b_Wm.224HbahA^SK"xZVU  +???O|覛@RZ˅rq9T* ^U16/477 u7XT.X~^wwq&O}3t1EDf-pxcc# f2>:nc|HA*T}?)2419Hd٬Wpqg',d xg#l6L&399..> f'&ӟ NNNfY>NSO36 &&566g2lvbr³ԧ>m MNN66fɚL&Sxg&G1|ڨ\*544g Lfrb?-c{'2K6?:&ŸO౉cIljK|J5q]][늕+-ۻb&AB0l!2+W<88/}/DT@}-0olŊ}q\9xh`7TZ9!EfYwW,_* \vex# "@@=[nfffvxu`MMT/`aecx7\rr׷ʕFag& _b}}L_+?|-.ITŠG}GƏ\ ˗_}/}׺'ժxU㤒$ pݍ_r@8bu7S{˖ZZ.]l]]]{\j쫱:/IeXDѓ%D mhU!1S2@#T4+b,f 1obtsvNLf KL]·OLIU%`Xӑ)W+EP\-oڰq[}[tC.UgPx[QZSfřB(j?)sGGݠ"=}s;e2s`rbm\8T;v Co М |1Oj1A[?{_@hTGQ]JQhl/֦)Dvر{I6ӰhIwOϮs޹bmy뮻γo<--͊x78͹\!BH@GN|i w933 +Ƭ9nnkMX̵M:N9M|+ s;M`o(ܔ X(45coZ. \Kk>_0- -92?W0'X(rmm!Emii) qZ(@ {ki bFT^g2 |addP(ԥSpo B;zP(45DuחJ( <  &D3ks% *PuQQ]JE iU{wqιgr݋zzzz`x !e6?Գsŋ Kwܱ;@!`Dy?˖.ɞ}{v=TԱ8xDV}ࡇvxn%l]=>}ATa`DV$>QPU}zv='pK{v|_WY(ćZi.[Խoؐ 0)%V8‡?cǎeK5t/[ڳs{!LعsgwLeOƀX"uA65ڵxlaiwΝ;a7|O<޽>?(0TTnHE!@̪q("ÞkA %at* a| NUXLY\0iY_;Yb,~e pBMM-Mu8o^Cy_ioy_O&M66s"|:^(1 JqlPc_ t}V*nͯ:*O%) wDdɬ% E;m`gQ @ӻ|מ:cW36y;V3, ?ztťIiQQTpET@P~jŝ fJyzx-~dhYq'xBEpݽjͪ/XC+vUݻWX#_@^~%P}aՊK}+ѕW^ۻ@s<ؓ*W l֬]߿V5 ڵWyaO*zq W~G@EݽᅟtՏ=X%`ګz{{UwիJf*fwf={Yuŗ%"T+̻֬{wZ~Hw{ {]ET@W^zOooRݳg͚+*5WٳAooիGUXfMoo/#fTpvՋ,(L@o}ZG`X crW/Zxjj w?D1og&QW_dr$wܱ`@TU yfVk,^4}l*JFoցCy @(ګ.^hz:4xGgU&Ad@@TEKM8d IDATMCGFFn$ T=46duQ}&'\s]ՙc8xm :䝫NlKXc\s5-B;44tG$Ӂ D`\^vΚ;bA SS?wG喿l 7\~7 ^@AT1o B`+yVaofM5S_qY<>1=wg1Yb[G=AĊg†OԼ+ WںIWM5]ܚmTJeH('d?еpA,^rז-*__ݦLx}g(8Z@TU"]beC\K/-\ve UW޸ym ֭nٴႷ_F5l޸i۶{ޭn޲eL+ڼe{*˶ݵyʕ5WݸqwomgqUW߸a{ ̶ڴikLrƍmY-[\zUCC56m|}j6@9u  *A$ .zz6lJ mذgǧ*8^cϮ;߹dR s}Ϯ"an lAzv\Ec;ڻ>~Ν;kj X,"g;?SE;:oڸsN""V@DYqC炅خ w~gxa_:OREvs}g{Ծ7)" ^Sֹuij5? 7mhAgvɢ "!Z۳s / Cp]ӳq@.w|;;A˵߰Ǘuva%_?ŝ{06l`AD̬MFDH(u,Y ,2,8Hlۻ:5L5˝~'`5&d8j',쩖gjrktS{.d@ׂCCC7n?}c^Z044iÆ= }'rZ|l޲G%/+s<]5:7o|kOkysn6mz''nmkZ7oy!_r.tu mذɧBO=D[?588x][ӈȣ4ixxÛ6m׿|+|kphp㦍O>d-TP<"*rd][~r|[!8_-k5 LgPw s`!{\q6M7})ˍO|߼ZW =vӖǭo~y{AϞøZ0Bk{6n϶r|w,v:Q*DwF3|wWAEٻ䥗`;gԚMLg} 0]=Nwҩ4zwㆍ᳹iU t=oѳrgyk߭*_o_Jww}{W_uM_@R=hRT< @c`ʼn'!Rukl~?|rsco7篭SʽG'˕ ԥӭզh8#sCMI*e !sE埌 /Jk-xw~\۱`9uXB0L-Xr'7r V]3ɣIlus/׹^{)$~{MV9rj  3m:s:p3;qr Q*]6cRѷr%s~~(y6җyxE [,;/G+g~c{;;W^kx,~MysO' xe{Yݧ25;:k 8'7uNct'&oWVfdOw`YAņ"nq"EH%AP-Ķ!L]*Lkij_~ݕA S)/c #x FuhSr,HDETXM`S@^HD%C$s-_! 5^=0%d,wĀd@P4!5h aʵRoj9vCC bv"JaO**¬ 4M J c@KTR@ER'( d d&U"ަBj  LDsZ*b8JƠ$iC`x6T=<̪JJ"Ac VCkU1{EP$$` cjjȈgP dAQDTURa)(ScU OxE@CF6NbRB@ B1VSAIEQ`SN%KjfUZChKDIYPt]CfzbR}lHԀ #"zaڣ@H*j  "" *E0 F'=z j  dPPƤ)If@"HR"ԧ3A>TlWM)jXA M@j 4XEE$ET  Vk= ! "A̢2("Q DAP̨ 3 ,!B!"P$9$ g:#{҉Ϣ&T^vY(Δ+Յ :f,y8lK:m>![zB~^x){qW\jYzQOEi®g޹jcWN-'sr&(U_=}aG0]P+{^tNOm~Lvgg}ѡs/*φڢ$C_vI,{rˑh_}B>\u ^aνWZ~T*%8!r9_jhg_Vih'Yա5% 7*?| #%U!X&.TJaDQc\*aRmY:u,Dт.߇ax/dLO8!%UUT^urT}BHH@N)(m"HUjAcB2L5Y Ij!@DaAc CAD$ 4G/LK|l < D TU^LHʈ;-oYihhj8dGTD{1dj#K]h*Td:?e | γk,B/ *'񱣣 l**ut̩/Bʄ @EkՐNDAҚg1hH5ƌLO *4'AԳX(AX \n|MLɂ=BCj\A4sd&,( U*(C͙F94|XQB&CŐh "(J05!_''eLm8f!Q0dUijd@A|b,DFCc}X.쉈wF LcWD1JYc*""@TQz.`'bqPLB%"UN0I"rʀޠ2 " B(hkAJ, {0TERTcGDhj~-('DT/dš%k-*D aQ` T D$faA-}HEXlysؿu^7mk3doY TJ78Vvw|>86~.x GFTQ*޹d~ 5}9 ܗTK-Gs ]ؐm׼'>k7~</.Dy /= j9<`O/\&D 'p+3p5ks">8t`¥f q6[" –yo0162rR. ijwƋ_,"mjXp& A->GǏ /9N^|ۃ 璉@t, >U(BF.Ӛ{y.I;K8i\ʤt:] *HZ@  8 xcj\2HFA\ AL YU29XcJ; 5OUk$qI'e s@ı skEaEX@ ` !*("s|dRӕ$ toi[DU\0({Q "LySsATAE- (Y1ֈS $F㙺əBY )6 P5&Dڝ+>r2G$U%Q;V yUBT!+À2 3(60]Bd2FCLՊg@P,CsU2Ġ"ސA%VD{o"JH K`PsDhMfRF`&c 1!ИmrIEԢ(L2"(cP"@@D A +6 Wg@vBUCF@@0rlg (*A@ªbN0̊R1{b@ (q5Ak +)D e΃* )w%p 9F$,Z["BKbXǂU5>i\(XZZ0a`mѝjsZx{7\*W`n[K6ln[@Y&GennH떝w˻;r.0:|]odȡ{p~Ǣ ɋ.0=Rs/'_ܾv]|j S=RkhyƼJ󖟚,LOF _Bqz( M3Y{!}'n}@S ,~cӲ_VBw{e 8w->8~d&o8kko+֦GG^ usjrœwXKd=QtiOR>洴#ZNo]>Ik۾`à AQh_l^C8*'W3{gqc#_^vP[{Lk)?=2YU8E5ѥ#c :ӤcmͽI*jlc!phdcdXҺhR4`lt!T-x6CMaH( "OLM+ժW@%ìh HdCUL`(g <(wh@TDo՚DDKl0LD4hHDgv‘M!`B蜷OXŭVlzT=T`f( #")(`-s8FDAaeia0L,QCyPZ#H*VeA[k2 tf_HHH"&^DX a`ĘmS 'ZsTȰ*2+BK&h\X(oN,FU RƦA*)h'. ^<2ִVc6@dIUj?"h*X!qhUc *`5qd$ "JLD މA@(Vj9Ua ЉFX "*!x6`L]51bWg%2QGBVPRE7eGFT PјHDA2Q:t"F 0YBBA4f 3A¬*k % +Wo$MA5f2 kxfJuRfc-{dZ0"ZT{v)ki`SD2@6s2k@X$UPE@BvxAA:&T JlqE<?D*u;_O's< ǫ-'k%-ylj&Ԝlt.>Z۱`)8E 8Y\-sR9qۛqXu>yKF) %g]R>D\|yp\.2vg5 .%$h}+_:WH/˽;>3x-R:H~E;xM,>>t>6>vμ# (ao?c;B  66Ԝ*jvb:VҾGG.DKN(̇@n[f+OXUweQ*_bNMob7+%Q]:1v1.׳) BUDHTT_LOM#Qy 45g<*=+~dB #EJ6;D9% Ƙ{ JD , Bk cqx𥉉TC2 hj<6B!t|6v~QR1?51J׵[pJ##("ιTJX4|:-y?cSt9M>f|KA?}_NiG~h2ѫ#|kZ,LJ8q$3/w-I|.=w`ߋw3zƑ@yFTna9StK[X-rs;N{!J/^vޛﴆ'W2{gqQqkJ ?mY.:_e5mYuZoιQ5I .ư7YpZiii?묳w~GSuh s-31/yDžK/>o 'g2yG'+3`}R̆ DxQ?Z&MECDJw1Z#! 0Tk PU@b,8lJTPQ "zX!@=AX *jk:@` Y,Y Ys0!:JCRZ֙A*l+JO{q P읂QT L\ͧF,*"c.Jd uqI{1벝 am(VJ+TRqj %TH $RBbA]W| %U 5E,b Aa`{6UL 66?J#JEX1@mhԻ 0Eb&BD#ؠQRTDj}0(+H{H" ;% @ VU<&c"6&f9ZFUZ9jqH @M;ք F(X2@5.Qʌh*k5 O<ŎZtXs^8>xp HM$^B"Id 0;ZPZQePc6clR)uޑ!00Q>>|-DJI} a'5b)?phT֞lov;Y&ͥFuim`M9}ޱ[qտ_HR)TOߠ_;]złcmwkY':vԽߙױZ=2ֆqOlM8a _ů?{u΅as~ιQp%ŸdsL}&359ulщ--YܜC}|(Yґ/TRaCis;c_u5?~ɉݻ-NקOj5Nr9D@ RuŕjRM|%NJQU\n?poPMl@T}/%mmsLR)㣓Gxȵ޷mS}}o^[q\$q\)Ə<4 *wo`Xܿ{Z[Հɮwؽ{'#Ďck_ɩ}{sO l\j 13jۼ{~=^ɏݞkn$*Zq1!q-/mޖfD cJ9xA P^8ֺmgJ}}w߽EYr%)'|\9mHkklW(=x\ )`]YE 0¸ոW7c]~yv(y?c^ܟ 3 п?]=o) ޵X(ܹ}|E) _pۛo v}՟sQs\w];GGڵklu߱(,5\GQDDΟ}ǎRq[;ͻ1,\0?~Ǜon߱c238'~[GGvuͼyay^D\0c݃@6 0.Haxp IgdBkqFRp>k9LD+2R~'"(菵{8%I+RLzB[ ;?T:{@=;Q. -;k&anlZ2Awm\)U q9k}?J%爍{w>D Sȡ#@,˥b_ϑ lhn݇C=Ig~oF|N>}onl{woߙ-i8kGGޱ}U5m}VfRF߳OIw0,6nZad8V*mOVgjzzU53ڛt܉#672zt{( ([ҿq -'NRnO="I PDH O$FLI'"<8fϚ]WW?g0 }Yӎmfϙ]W߰xW]u ?;/li䅟dDҞ}H"*DZ{{}ک65^ Z۞{Y Q <m#"<|$z(={NMM܏emzx$?l[(c΂snpj<#г|('Fۨuq<{ΜٳfGQa([[\%(o\љs͚3;M&*yb%מQZ)}υayug93 lM"RPJZGmsQ=D9 b@XQGxg0=gv}c|T{yvL"A"LDD_pѥ fyNTzg@kiJ&C&AM4yEHtѥ~}=مQl/omQq7,?}oˎ:e >]ğ)>uw~͍M }]_t!׵5/ZK@K.;/:aa{=sE;K.λZ`E .$iO]r_ -jw O|;n55}=\|\vew|Ez+{.R%;߰c[xw{%8q\n4nws^,,]|% nSN;%.Ts]^|D2x^&G?~ࡇ L ?Hx~"HS}+A-8,9YǬiO*/Nzg߳΃]=hkmkcG-~pXҙ)ǟ˷^9z0|p܊l.{X,4k;@omi\U[L%_ݵX ɖS޹wA路]R q['&sg}:GyAιr}Ԋ{^\`ϑw: $Ƶ́YOhwoFM#d2Z?=~ϱ։S;wu;co#:Ih^u>gdxScP:zh;8Fݹ58kcΝ ǟy?*8z`S[* h?!Y;{ocO; }w)W2~Hw!R ~0J(Fmd]\_:^d"s>o81?4hD"ZX2Ge Ql\*szH#(y*E+8F%JS_CHUW_}vo|믾eaPFW^5k_ַ@ >sՕ̻,,FRP.* ᄠH"rGUWe2 pG%Rk:yj_8v o(q913ImFZ&5mVmUuyL 娜K-F@1' l.gކōlB*Kh-w` #ш νjZ3MmL"i4 nj :NH) )<'w cR\v}5U E(=F";;i䡑D*[~O$΂V I |UUUv}}xb°$(C \*{ш5z$htxɧz/RU9?+kZo[HP+?}W_}GO~5/B|3W^sݼ>ç|/(ˮ?׬_{K]{G~~D+>sy|soX[zЕu|O~O~0ܼk'^}z$Zs_vټk=m\I W|z՟{WZ_J|s}?^vKnkSkuwιg{?zk^_ ܥyWs9?O<Է-W]y5w5^ZaյO?w^"_yu^sw`4 uc_O>tPARXf447$S)/-N~t20(=֔Lʣe1)%ko(KR9 89'\#c1}g_ɠX̗G 饪Q(W3rp*B1*,5aER**vdh?Xh6*m\z翰aH"!d:n\'.R":0IbVrhWm]mOOώZ~@׮x+[jj_oٳf|&D't甓?t;$断ot45kJa)<"VTӟg_gMNў:ǡ ҊYvZ)qn884/?W_Ww7窪?h:&`V1߸_ґޖ[n^Ͽ> R(,9xʅV܆Gh[nkq J H[>#755-[vc*7oz4FF"b֬]/eppf-TW\{lVEkGC2#֯8?藿}[nY0a\Qshc$a)Mmm2̿ztdɊuQd&$ÂZ{f}r57rsUU5]8W:Ϥpd%„ڪD"倎v| MM۶rhiv87^ȑ>mwlӸ_l}N~"sm--xyzzO٪ښ_Ac}mOIC}a}S믿2HW'|#ʀs;[v*B`Ժe˦Ɔ޾'xBWQfFĖ[kjbv Jd Klc===i叫iPJ@>}on#nz]wdEBJa58}Ιf-A'IeRd" 6~|MCo|o1czbp3Θq򛅹Pi$@$&rfk:rZ+RB, #"\|٧#w~e2G r1, Xg8,8JR9Yԍ7.v{ {͘(Vh5 NDh%8caX۹gz+;ZjfLBoӧ/_$渒Ύ+͘1}߾ѡ={vM>mٲe<2?wӧ-_~CM! +O+pBLdٲM}#pӧO;dTd!Q XTx˧Ϙ=[~ϧ[/OM seHVde˖>mykhx޽ӧMeF)  XBaT*}zcw0 *}}\Vd!c\. lv`oRlf3ف^Gz{r,g3B1呯P_o6el6;8O=uQOww63Fgay鞞\.™L!@_.d2Gl>/kT##\.lf'V?cds\.f2#C>*{sﶛ-YR{wfs*t##_{D:956fCÃѯ~rl]6'?G\΃( R?J!r9"Ǿg՟0..(-#GP!*~ J!0ѺRx I b)-FF~c^:ekjkjkkrt:$ IDATjic1c**s\SWYed4RIyq82šO_ՏÏT^6틧LnzTNgu$Sǿc?JyگĜ{Fu DN"8g]tM ՚׽_L<9N4yk֮྾FĆm|cC"tRDA>0;apNH/} /To2ꦛndjjä(*m/Yk$j}ni)  |>$hқzxx:;:go\v#GFjjҥKml%56 %K`c]}~x#:B[oqkk<2oWܸ2c QߘTU5,ffWX?<<#Pв7ڨN%u~dd\C1j79Lfd$:( u 5 tr렮qxxX)Ϗ45-[vk_@UUftdS[ #h%⤮nxxZ59rU;;lj_[d'<+So8f138r9ʋstAcH߫ljc1c1YY* *LJ WN'J#Ql1pc[ۚ>q[$H)TIdϞ=vǮ]o%d6WUlT%wy/}^Ϩ\Ƶ<J1JFalk#"ଳϙ<>'|T^qϽ^z٧V}2;blUݶm9ssul`4)( 976n8?0Q A! X#Іh J9ֶQ":x_s_6 0i|ރ("9瘶C|n]X)y>!ZH#gu Ãwsׁ}D׵'D圳ϙ8qRF;w߮f`ӚYs&Mŝݷ={ʼnRʲU@"-;{4ib~p:w;{Ͼ}[R*tG8 @>{ICC|~{QkAJ=(J+ :keg8.s=  Bk<X)eENvl;w^MC]}m?o׎Pܶm}^|I!fwtt?;̝o}OFGO_o:cַ~;cF3{ζmیؽ\{عhsv2{[f<HΙѡve /l߱S.eRJ IklDXBXbˌ98. Oc1c1c&1OFG$A˜ȢSl*?ko3xz%4`.~?ϝ֮UW㏛6mdCtҕG ?>z9UD>a3k׮+G[p}LN&Z[WMcVܷ7oҪSOy~T`/̞+W~R9Y ૮?˿~x?1/s(b0cvъ*"x}˖ŶeVl޼)BBZ RZM4!Ֆ͛{ &x=wmڴ @8٘6o|OtRzB{`M(b+X$PJe۷?CO mM6! ;Ag-R͛_q_ &'Lb}7o&Œ+ MVRz+Vjv}+6mzMXgj(V=_x x7,qO\ٳɏ̝]hĪW|h3A3f?'Z/|?М9gӦ?\egΘJΜ={C+W^O]{-KgΞef1|Ǻ<?r̙Uճ}ᕫV qǿK.y 4)SX3 Hz"NXHCsHDmm9BvN:wt?{x1c1ؽ)ےNW5oqZ꧶LnK7OiiҘ&'N@][Nho`kS93Nv '~b?媳ُ}? J}z|USC'>r➷ʣ_i7.JOy6W^bqhhh-틵I~mㆍ C֯oii^ S>s]qڹy>0esϞ L ^ ]44ԋGe|}Oid)~{s+ ÇmXnbkk:H1ӏ;c~s]Zn]kkco<ȴ=3W_nbkK:g嗿{0 >~Æ@wdBm7zІ LJ+Q-m-7l8~ݺ'xdimmm=Ç(3f [x~$Zڞٸ:aͩϦoin:E$$V7A"bc' 0`B%"‚–q@X1C'(@"T@!+&ѾP(E{*-c&EI־0*\diHf.v1X48VHJ!4b%IQiX@QY#c !6FXۘDQ 20GhǀJ8D$Q"ca$v 1"FQR.E@b'JB%qJi("@qek#y1VrUHYgQ+&FGBg-[*e?Ca Hb_)(=Jc1cˈ$RU rCE?:pxۗThal ZD !wuaF"Pc%5Y23*tQ~ʱ1h|oלf8:o߁( iM"$MBZ98B43A@ÀW}]U_!@=G`QGR2@`YKc! D#t([[.\ȪRbQ!s(8$Tc++>dTKWc0 VVV@`AI=p@Ȃs ́#DC(X(L/m/24]bZXD^T.Q4;TVI{8Wi.jSQ|꫱b1 IDAT Wf@, I z`fQϯ"p=GB1 8xH`[{Rjb(P0H 87?A8 F)%Q` t״RJT@KBZ>Hj`G}52gQ%@Ze*,bdglW[G{skuyE;+!!8y $T#DQar+\|dW} 9 `HI" _Ǒ1FEԖMUZYCVc)Q2!Hi>̙9RGǕ)UWO[?=1,v4'Pp4_@ER>)$ժDJF#J1! ( )VX`DP@1FZ# )1D$dc ,ǍBF(Jk;z筪D$Y9 I `C $ePfD&I6ޭF J1p !Yʐ˲pvlBů,Fj\M"d> `B`Q_EGB!DPB 3dJ1;$b(@Q)/6JR$RQAIR rIS1=? o} !ADFcD! 0," `gW/e/9-.Ϟ:77{?]1_޳jVf @AJ\T+dY-TBvѯ7/N~᏾FȂ꾾;}nzqip]Eя^YXX|S*@Z5eA0J7߰wN|= 1˪˾Vɲr281.+YVjJRYB!|7o?B2Zƹ!4=?so}|s$DreiTib}[WïzO^{?r:˕JEdi2zoY\.:;::$ }vn{]xDGgG;3gy䑖_D幙w~{&odW|浟^X(~Çwt(cWVW_ $]jE =]c|k?~+51 DYTZFJs}3g˧O9zx-FTjj28\3TjլVU*jՈHJw8ګK哧^( Dwy׫'OknC wyW*+?6^DF;uS?oG`yNVV^=yrBpNZ^\+?ہQ(}ϫvqa;r|1Mс;:W_;!HRuם'OzߕwQl7[9w8SWN"b;x{n}=o!u:|굓@tNʏNcO:U^^:oC(㇧N-_yo߿ -U|uw:ByG^ۄ@f1vxǯO_=ĵRRYTVZ-VkJ(HJZ֧9b YQDՍ[~%vMƍ  l0oͷdhs=Z{?q{n\٥w?bs.הk?>6n,{߼ַ?48޾꒑K+5i֊5Y$13)kLddhPoo$=>^: N=#W]Mn#)oR=5_|d6^. W|G^+ՕJe]`$Mѩ-B93hlh_YY1Z)e3(fVYHi̎JU5\v^fS.;zPjk\\\J>/ )rM![/ٱ˒VHZJ%DFDDYwTJXRFT u{S3 !eZiKrF)f6:"C(r{g9ҝBk4;e̜O@揄6|`=}ƥEmTvwMs(B+*˝IK˵wt/..*eqhk 3kR(KryՒJڴ4...*DU%~6Z[kU\.t8WHҢc̜X)ebyi_*+j:Z+k|7^ k{;[ST4&|+tvZ,Ikmsk[33I\.wH$ҺsqqQIJ)֚TC)SHi;9͇bO/!RgnghR)&%I.m_4n(MڵԘTٻ{KRiמRIktm{NJ֨ɉ=vIuƘ{?PNJvSst=w~i)LN#)eݽw|)ML~4'I~wRJݻ2߻4^RBJ];vi2\>ݳgwTR&J=vgۻ{D/٣HK4Q*޵K*RNݻo|DʌOvک Ym/Rs.IJ2D-+r٥J$FfNLbCZIEhCH+5)PHTTK>ߜ5F"VkMWk'_lWt^y/_w m&lEl^?ܴvcM:>?}ykk^q-N1*sY%G}QΘ[R Iل~ZvO&v&Eg׾s+?3Hٰ!7*:Gnnvnh@)=zpff& hti"J)h}_9 3$FkC AiZJCDJ!iIs~k_y`M>4zgyg5 l~ÃM>}i$=\촺Ji"iR@_{ s-ÃO;#iDcC1Zٯ}< o]>-ak5Igaf4Z$<L׿f̱c@*iYEl&DF~y#GT*NTꫯZ%BP)I")JL}ytuu3?vw8~gqNҪVte\.Q*U)MK !4S4zV%J)MRCV+ZQjZѭnw6ߠP/b*͵vvǏJ$NigM̚1.uB{w?Zۜ on*efHB@]SkN!gMlHhq v?'u4)MRs9c3k투$ioo?ӎ(5yRCl(-친8ڢUʐ3;CQ5;O8_Ǘzz#`fve Z~۵D=I!+/GMi⽷FKڱGƌ%g^+BHӤ?چ M{*PLVÇ1֥{)e5M$D!OqX,zV!\SA[76HB⽷ZcQdǧBR"|GZ\{ri(7zx4uL=|HYH!92JN'6;e:;:d/~^Ze""IDR8&4%i*RJ*):\u~e,w l//T55ʌik-tqC5㠳8s7+1sEO|ctu߷og=l ׯ:$Dt@gf.~o~}G{]ںa%^Wz9\еjU-re{OZZPQR#I!E̲D_/_?~DEes8iM ZS8gU&rBs>}''}O=E ^V#OW_z饵9Z{ǟ*#C Di<~'֮]N8'!CAHG57?_:qՇpk?GH"r1J7?K_Z;/?38ku唲"-u!qѮ6 /..*.Fb{k:::c --?ֶbaa$~ᡇs~~^\X\,6斅B@<Vkj*s bȲ/|s!Z[C ,ă~no^XX --w~,kjo[Ņ < 6?? m-<B4 !Z:|̾K] )y2bKk7P_畄ڥ=RXh>,.. t|BjhςǎP!d'N<1R$o#CXI(ZIهcb՚nYD**v4[~%v|`˪k6|d?x7 lYӾnKrҎ#Wo\ӻd`=|G^CW]?5#yZٹല&2Zk]^^VJ9ku+"MhIuZI-Q ^xKKK8mSg}mVP9mNݻw)ET%=pw-BdJ1HI)IDuOxuuuZ B.̗]ڥ*e Ti%%3;EV)VZ)M[ZZl R5]uկ-//3R"R5!4;;561ڪrlɧ)8k(mY^^YHQGWG\ZR}j6h::vFVY.IYm$m.[XEJjiiHJrlNuiR:#eH[m>---uvt:҆TG[{\6Z)T}ÒU*3Z-M4S.c&kT}M\>uV3fiiE""].ݴu֦J["(MΒ!ԤMKs;w&mIik쾽{Jqm䮝2Zi"o&ܵssYۻg_i$ܹs)i޷ooiDLΝII۽4^NvmҒV{'{v6QȽv[''&vUHDeIv`4ALLNܳXXkڷo_T2HvF;kSnw{iߩH*$Mj=hbrb^1;wUI}&Jɝ2Θba߾} ҹ;(OV=K497Z6{vJ---wiMIbRrXbA[AΙ\QDd!)EH)M6-v&.oI)VkMK`F+鵓/_/d/К֮/oj* vm-XѲvdպWSWm{W ~ڵc/l*^nݣ>o|)u矿yM]z|x^xA)$ |Vdq:g?V7}ַ_oZ&' u#<ȑRɒ\ndzz*ŏ}׾笵o̙36]t?=\{Kw>$%J""uss_җJ)C*5Zfȇ?r٥iD#1sBd$EJ- IDATJ N<ZRdff/0yȑ!cGLLL8 U4IMؑ#CÅbؑDTSo$Rڼ0£GY7<87444vxIkGR+RDJjE֘ѱ##\aXTr*Du 3+UZ:ONpdllxh0˭DdQiz"Qν7{u×8  9rdrb3V)M.IZSؑ#CCֹkGN&$fV 1RZ3s.q ieg~O4n~Զ[1۷z̙O_c[Sqknݪu-gϞ|ݦގ|7o%eoqk7m*7];5u曷J2[oٳֶ-7 9{M:ۮک۶iov̙-]tݼuRmΜ=-uӷ:pg6l~M]R(^e;۶={v˖]ݻw~whpd[Ϝ9MBMuäu3g\eSSKMם;wn۶Ko~̙k7o*naԎ[n1Zߺsٳg?_oԧ?555sǾ =m|}Pkϝ;woݤI޺}ٳg7ms˖SSS7oJ&''92v(ͧÃG)&̜6-sN+.(DFԤ2Z[tu!MθԤa444444Jz7]W?u\24j䆯5׿KZsCë{ִ~G^LMޑ̧>~n~nnee̛ovwu;6m˿斗㎮Nm:b;wnſ_^^?q{w}Ҏ xS?=ē}}JĪ >3NeNܻg֊$wO>]xWtԤ5uW]Qfp]ݝIqݗrH'$Ƥ֒ѧοx>휲?_!շcΟ?_VO?䓽JIm~~ Fرcϟjϟ?䓫׬JK"սO{O}~z3IocǞ_w< qeI ezR½,"bDMY|gp}Zr!R"D1## f/Q(| Ƈ @-!B  )#3_!}( 100JkBƄZ-d8;^}V !RRՊ|J6]J»糐 Yp6g{"ч#)P2KŐ10" d1F@"la~#"Ԅb}"D~j{Q"ZS"G!0( gRӉ3UR2G1ĠIEfAUi"ʘC(!dDʲ%r@)kY$A:S^d$JZDµ<׫2τ@ԖcMT")1d12B )2pZR A cQ2,b FTBPbTeicA@CAKD12dYVE=[ed#`"!C!A 9fs$1T" D*x!(C#I$깐ϼrv~gԺ  ^+}dVD$}${2c D*Ym ":,JJ)`$1)I0,0"*YY 9:Ij_! (B{ !P )$$cY@TDdUcz6444444K/WZsINby%ߖcI)d^_˚\L +V*{-cjEK,d$,!e*2!DI]Y^`"U3)Q2F@>\x/F82 "s@Ȉ!,F%{_U% "H 1x$X&&B\~wrywAJuyyiA ϑ5â( 8}A+%@I*DA$cjF^G!@@5HHIGP`d!D"CT G![^100E@J BR_>*eD %CQDI9gu5b "wKPSRIZVRg(JD1$-|gVRᐒʋ"Bj̀> @D-ͭ& "VBA#3# D "J_i %D(A b (eBmiag5,E- (%βh|LQVY>D< YFRݷ@0H"{Q` smei\ffRpTjD!" L Ų#TU++s$p̲,2D#he2" PYԖKU+ !Hbi@$=FY f)Bλ9"!^+O6Ija ^(R5\^D!RMkȞY1*!gs9mrH8`RfYdF#3Y} bD2/(=33`BEׂPAb!< J 0%UWbY}!F\YYZ5s8WyI#GDZEIBP zg`RT_}$@ $"!T2 xCc B$ 1Z43ϳ`}NF J c$E=ǫr QU*@%1Q Y\ q%BJ#|Mi 1FR\.+/"@!29 pD5!F(E !cDD{RYHD/zU_Dֹ10PbΨΖ,7C"hQ0JU( D>@A(30CuyY !3&($E!LVD5(E> #s(P %FITk%s.r<8 g1 "x}!"Fb,1x࣏(g5|`cjtU#2eM뺮ݽ^k܋g$,yHlqgXęE g8qJw,HٱDR$/1i[iMXI")KEH @bq/* NZgsw(QD)L_ 1Hf~12 6-(PY2+g,$T $sLڄuc}J @P ņi>| 1 T*_[AF2f^Ry!DR*Y@b]>[\\䧹VRJ*U-) :HrhcP!PB03HPBp" "BH%P` g(IAQ JE!YYTKRrƑr,R*D_d%%Ǹ$b67WJIX(+'їC$#K!!d R!GP̨5 3,ҁJ*XY 9<5*Os9RKiZkCK\.K9DB @ A YK2`9E %,b,-. 3 AFYc R*rA* qw޼\.E BB\" e TQIV1*Mw2jc2Ɛq!*BcB  TBrV PP  5!3 EB 1pD+]"G!@Jdŋ_>bvaፋYJ1% "x/G2ʾ\FTRɰ d9RHڰ $(f,\X\!)T9Hogf//\tu),-`s- %=T. !P[QBYFH)sYYqVGB 0 %H&eRDQIb,XC,$,"!!(g*1 ! A*Rp !BI-}'!R̼TBmU|e@K eeM2$T`)@3w~;+G"sX5J]9GβBRJs!A ^RI)BI)B!C0r&^HsKK Qr`PH|P2r)zc!rd!AJERFYGVJ#DPH$ $)P13TX'"1B!t֠ksApcXR,J\]A2XIG` R*b9., rQ)(YFR2b"ҥr&R AA{)FC B^8?+22J3|J9ȗP0bBh}VB9 9`2Q ,R9F"Œ%rT&TJ dTB+E/PY% l $I,-kK ϢD K Byq1U.gJR! ѹR}T`J `AȼDU~aiI^ZZ !J{fc6{5 r&/Jrna6&,@RRHcX,_Z.{ f7*UTRʿQҜwwlJl)+u-u@]}Qk \ BY$o{Ͼseꝩ}ȑ/xw}FpJ,d 1!L(RT^X|Vnnizܹٹν>|Pccc# ?''?Î@H%;u̵RΜ}1)E >Ry}̒%G'7߹|^||%}{ӧ_ڷ{IR 3g^~y߾"F%UcS+pmljhҾ{vO_K鞏4Kݿg}v# M$t:uϽĎN9w^J1NӧJ=K޿^:3sکSg~J?}WK??JAwOµOڻgodEg=?xNt=!K.ԙW]=}g!sv3/rܩg߻_,v|fft(>{p?ݹC0GAܻW^>4?w̩y^B٥]|gbمRbiAI!fT^1Bc M##g_?wunkilj ,`qi)r'b Ы^0 7TYe~iq%}hlh:84ʫ^r?~?6H1J.8sRfY,FvksΝ;|pSc,rKKB0>uᑑ[Xxsln.r%Q奬\T0=s}݅|M.|kKWPwСΝ[\{kCC !$,TriM?G"2Gy__|}/nz-O}嫯?7??/P~޹|E)e|"JBiʳ*UTRgO}P(w55u46]=wk BҘo74wWvոPZ((4?\Y_|嫿p֖wm6*zg[l7M""Mdafg1VԺfvBc2|ၞԤ}=CC'N`V p?=}nSٱ{ƍo߸qrrMSY%҄}v]]ݹ\b"mׯo,4n\qrrb릻6;vۋMMwl899mVzĉ$>qAڱ}ĝw\lc㝓[7oJmߺu…oln(n\arrZnݸ IDAT61q#wY,4ݱ-[([7op?rɉ͛6$ݱcׅ m(ׯ011i&m['&&n#-z뭋۷J\c.\]xGz-[PŞ7l,֭[?99yצMd֭['.\ B&&'7md޾uۅ 7^T~7ܲmִc .l}C]caƍwoL6o1z(effk1MGGG ,\~#C+V-{7~XPM".[*Mo_Ih RFP  "#ΙBm}[c[g]-UTR$/~mZ|mkon^bpek`w{`Qlo) kV.*6u54v Ū?w...n[o~ iԐ5"MKs"jBcqD̄ &ёF 9"Esss͍VY, 2;;LԓO>M mk[gnϮ"=66hKH|sIι:M"Y"]ljX\\D2cwƑ҆쾽FucٽK9]_gޱ1Kznnl5Yz|||5޳wڶ#Ħd~viM3H{Ecccv-ʜ}wimǷoߡRОcvځ]Z;|~خ=;sε77woɓp|ll]ʒшv%cci5P}FG@;vqHY{߾1]ۭE5(ܽk!5>>c6""}jk;9>s"t.1޹{ttTo߶%Z2{GlgfR%N6FePf|{-uh&IIw1m \ JИԥd X٢"ӹbQYVYH53kBB@877Xh2HF+0;; A@HIHFb8"Cֺ֖YM&dfc!B֤vnn Аn*6Zg5"*cfLc?&5sss=-7\kz;naڛo[׮9gksss 25657(D҄ӄr5hHH\GG,W($J].KMj ʟ_l*k ( )Ik#Ȑ6 ")$hB@&|ow|ͷRJ*ULijZ66^kyO@_upS_sW[sCs[CSeW4u(t.~U~.uIM};Y6IT&DvW~_zA1ZB:mު o}_FcW}9='8}뭋1tΎ+҈A}ejX QMN[ƒqDve_pzzH2θ+WhfffrN,VtuMMMiG=ޞ|rݪCCG%E3ӝ흆2]]SSS03=٭*]==8==E-YKkjj MOOwutDCH 333DHuOW+4?3==mLZ;uW\!e;;5bXS[>5uE"$g!155e4ܴ|% \BM#:LMiffoX>ШkjjT֦ʕֶޞ^5)eꚚLOOwuv! _r-9kqFҤ 5jbftٛ7)P#*F!҄ѣOЁOM]Jdf6rO=z{lj{z{z#GQhcff)':p@Ow48=H@!"1sZFRJ}z9yGHĺ4M{V Hz?:Q]9&_[:6 __}\{CٓO.Xs qkI.u"ԓO8p%I@߁?HTfFD많=ޞف>q(]tSK/tܹS]M>ҥK:ujiik?$(""5X-dl]wu7r{o]mUJ*UTS߿y{ukWZ}-uw#Z:V4؝7߼vRkmj^yRR֬?|N.JN?kht2|3b3*486 J+Z$%iM>w~tss?#=?|shɲ6_h2K\}o !Fؼ^#:M1JҠB3O7 u!C##Xm=jBȧCCZ|677?#=/BCA B0. "M*B34<,Qx B>%6>d{ !li;22Nk% !Sqxx:'C-ar M{R&kG,$i{q!4Dm{o Zθa;OCui@(u>! !kj9<LZ[[y=1YV{@?^‹MА03J@ H+j-_|j%ѢATlY 6^x_MuuQi J|"T_/յy5SۻaͲ~+nH]`W\T2:Sh_KTmiK\%5}-Gx׾J$qW<vp@qoxhرv0dYǎi7<2t״%(M uy@?~|e#׭69Y2uNyw 'F?_͇FF?-IR̤ADEt᡾\Mo]Z bfBiǎ @OᑑǾf t㔱y%433K$(t圩i2ZAHSFDҺ"&6IjjZ TRJ*?|t[V u5Է7ԧ-MLkK[Gwuu͹e]˻Z;:{zz?ӎȘ$MM\E]Vn CBj).,,EQ+C23)[\6Iĥ7=}45jKiXӊ:!RhH&kڵS"(Cn])J]$Ed5c5*\ΚH.,,4'wnߙ85Z56:f߹s&"]Ɖh~~PGK 476!ɓ;o(m̮]Ԟ߽}V ֻvMPqN$]viɓ;pd *Z۶EZVj=0~r|퉱9cͽ~|ll93'eP%Zk;w<1z:ɓ|[n&ݵ{tt ڹY]FGG5A"jm;6:Kr'O޾( bؘv|||HZm4ٳktt?}dH!cvu("߹nMs೿;zf:X3Ơ1Xbf""&8SW׳ruOr&BJ iRM6._72a4:c֕r"5766K\mnn\O3JB9??ܘXm5QSSqnnH?Wd13*4Mz~~`$ܜƚJ0s$Ӛ4??lRCͭx R523USلi|rk{{;is.̜I.M$1764j"c *679k,A`f9DH -bcanng]oh}%cgnggTDKs&drm$@IZؤu"MŶcFZjmMAEWwwoRJ*U~&yoχ~4=׿vʁƺbmuŶޮbG]>_XٱlyCUִeջ99m۶˖sG9-jĉXCS!MV~Og &emΘs%Do/|>_O,ɓ' \_Er٪ɉ濙4m ϯ_a&޼U+Ѥ6yf6$ zĉZ-\U?GO|mݺwq{iÆu&6qzjׯ[711yMgK]68pqmΟ?~m5vۅ-[8wlz 6011ob]aϟ_m u611}n$wm_}m.׭_~bbb>F۶}6 ombbbMZ[> J_2g.?яRl} .lٲ8m=?яą ڤmZo]m͆ /LLl޴Ő޺e_-8zϯ_nÆ ufϟ_wں}xb–-u^~}}]Ms?}} dbbr][*m6Z!e5jD Y!ZkF48gk|%m :yȡC}˖jk~#|3IsykВq03!ZHr8!3-J|4Q8mgN>rxܴ{!cf$juDtCFs׭|K_76IlR/:f&"{goudy__:.w`Y48xIY|/o@w 7}/M.IMabSPWhmyC:42>>呴֤3;c5xe}C##cc {9otÍ$bǎ}m'N|M˖ڱG&Thinr)hIkdH[:4uͭƥ5UJ*UTS_ݟ{>t/}V9>[T߿3_\ٽ?zpm+k5_/}gffϝ;7<4T,6:ko_+_OM5?Q`5͛s-,,̼cR7&v[qWz'/]eӧms9L}rg~V9}9m6[忴41'Ϟ=[._{O3H}\?{>`AǏy];xzKO}S?} (hԧ>kΞ?fk_O|쫯VxAI~\σ?`O}柯z>hg>?hi믿~F&I?k=wwܿ҈'~\ƒ&ăgϾZ._}ߧ*WϖWϞ}5a._W M?yRƘg>' Y&I(Tc\i>QA-A?7ƙǟx7JoؑtrrmmoWZoo+r… =ZR=e\J)EEIkR)J#$!8WK8eoUk~[k*UTRg^>-ۯf-C^@]XR$޾ΒP"khj9ϮomAK22XTʀ*˒0wK.%PcRʳBFQIf,Il,GD}3sJ mt)B%"e!Xτ dY QA,@Q`kZrqiQ2^pZ*``@R b\J "KD(%D8 f$%p>=I)FB iKeڂD|9 sR!p1%B)X,RRIJI,3(Ј!R@8,BXgoN,Y (#HF!(A2Kf"pT bRH,B Y He+D)AB)+ΣP!dAB0)̈9"ϲwTF!$!dR !+⍔6<A2PV*IPXΧ IDATQP%1T,פ s3\P@*c"J2@(Q!}̂Rd!x$2(9$-6So!d1-,P`RQ(!! D ,"3XH)"3DYl^k8?2VM0s(2 BE%R 1(코2 !D!4R^QM}XZ(3B`B2u &BȳosmJκveUe+g^K!`AF.ɵiW^ayQTBSS0{u T,Y(CV6BJ)9)BH,Jl)6Tw*UTRʿ!9,NM~S(-2gu}m8;}JL}!zs:_߲DKK"._Z,Ȅ\^gYjh~qQiCB"r!L"F!}T^*!%d`RQHFQ*)$ rJ)r ,HS`$pdyd "pQH!dB)G@(TRR$")콗@B@c,-EQpȇYv" # $QE R"2K)Y!EXwޖRpItV^KR!*K !$p BX29H b^#`d.{ QD 9ʥRy9)K"*cYHf BdTJ"2 0X(EP^DvmB"  dy!9 D!`RQ̱eZk bd@ ,%(!(be)E 9rV1fR$Lkj43D`! "G)De %Y EID!Ax74bs;o/0G/X(rv%PP8(˙R!BQ(T 1 P^\ R)+9x&%}&d   1 R$AjC!F!zcB ȗK!(P)lq)+i\ơb`@přdDRXDBe  )ch0 +gqe5T(Q r>Ȓ D!+s BYTa駴VRJ*U)1=N&Oaq bט,L˥yRԴZkKko%.}ђY!GD$ 1EO,DRJΖGR"F*٢!} QRhc3HF557/ !d" ` H1DYH)AFXreTP9>A!rzJBAJFzJ B>ʬ$ RxgJ!6BbA2d^3d!T+,EeI!#"| %;DP!D,@()RY!" FTADPå"D!3 )Q:::\zez7)E̬0"ɨt)>D)X)Y,D&BHY ,XC`f)A)"rbL,A,CȘ3)YKCd B0+%ILTYi"]<,bR,J B f! Kd,3P˗.^\(-D8rJ`flB䵙wdA"B{/Q!TwTS07pmvXGJ()% !(HE D ffdf!U"1޻u\uUOO[juG'\@,N0 ! w&w2"ˁ$[-$zL2j)`.w&q3PĤW95jJ]JX4$&@JB !2"P( !3"43UU LL8?vKy-?{񵨘*1)iJD@T9AZtTUཋ8 = !bJ EgUcPDŪ R`ԤSPFEԤ1S FB"F#TEHLb@" U1&@V1j̳eUr8_*UJfT!eIDI( !Sn1PPIRJ*&F16QI"0e:%ȱcǁ"11JlEc@@D1j QUX_QLR7 I(DEDLIXb]z HCN;&n›y_'  FNU"")%HĄeb" y#e\)dԈibY$괉P1ASƄPiJȼX1ncҤ)@J*""FLT!1c@DHRba!M)"D,cƘ; Iia~~~a>CcP0) c Ɔ4bsLUjbXv1lJg, 5)Bfl)TNC"" "( Aw*O=+~`>s9^l~vמ/v%/S˓Ixy-d%,:,=#"cyntI}sYB`$*zG~9cPC@J 5!Tb)$"4iDqʢ21%@MZjRRV"i'!'s&` 3=[B(5% VD"FX***!')UD@U!l(%rtNƺ:$q*DXSH,4EUY11CRTB@UQQB,BBFI̘ji -V adUT|Nb4!!&$RF @bRH (Pf/Y".I 'Z'"U 1%cDS ϝ>#0cH9P$r(*,D?ؿbJiKݬP``cʲba)&}~! %H 3Uwn0BDH!*:)2Ơ C⨠12 (BJ )xm/bLcwRr"&P[<80ЩJ$#Z!cDC @c@$1XM@>:)*ʎJ` U@CS\SC$IQISrHѐY({_={B/]>o}וtB[nho*/~ `kveO.C6#yY($@/@$P&FĔ41 B)B$T P 12jL1"|ͣR(:TecĘ*jHQ&D%T˜b I@YJe*rJ 3t zۋEB씅X1 `_}(=\2iԨ1EL@ 5)b &E@"&CQ0jRz~}IM ԠI"! jb֓|Ց@@H+ ĢlG@E#\%@ $S؍IbT'S" 4Yk0!!MPTeBfc7O&Pdss`,5,&'̜m1"kƚ1 UT Ϝe@BB@BPBF:HUJHFSQW ISH *[)Pu ! AC!jGcE$ ƈ !4>'ϒ`'tٹ'|<$ )Xcm T4ցb 5aJ#[Ei`xHΜ U鐬v'&!T&RR5DXcTP$")DD `PB̬%6p@+64!Vs;Q*/t@F3S([bɈQ @wgź,/ʢۛ)&L1gCU B! U42 #SH1*$MUb)ёyı=so<;h fqf䓧b,ϝ;n?:?+'Nܱ@4bcX"H}7?Bs؉?:1&Ҫ,B!B1EGC!vʪUELvQ(H##~-8x歏~屳?~lG?228PeSQVeQ; O}#|c֗Yo *v{* """@e󖇏=rlq~S[N )icSԗ䣷;v|a~ĉ7էJb>KLc#cYO8?bn߼^zq;مGN<~Dm.):U(C(YlWU IPSB 1֘ϵ^?h-ows~?C?]V]$Hv쬪 7߰,wޥĜ3Vʢ|M7 75;[cbadC"MjٵoMћn\)v$`P _7Pchs)1=ween~CUUw"B$xI" S0197H)||DTsu QgOYUo\_sϞ`e1"v7axx`ڵc'&w9hb,jλ7F߸aCYVw1-4le4Ų*,m;ʪaoܰ*]v]xM7ᆢSޱ-T%﬷ٱe4QAA (2eynE"UH!AJZf`@rͥݝ^ GʼXŋy.ݨ7ŕ:/fK\.%y^A.]be.~ _l%x1ܹӗpK߿R%,a CgGǦǦN\]uP1|F_o^[=jg ~]nw{b1fqqQob'qG|FV؊X}}tn;c WU1 ިjwt23NXfYq86‚wƯY3[߿߼5ϾygVD3:"9{#"b٨1ҭ!n6ug0;ã V7.63VU3QElG#;ZYXXY׭1*Lq.˽B#C Yk^3U5{ZUͬͳ܊b wErުc"+l6 a‚>2/8f&a2l6##XcXl!kIĹnyoZ!fh4̹Bs8KL^WUKh_Y;>>uW_3:msy1/މ1TwK\RUl 9clև^79?2XXXp9Y6N k\l֮/,Fsz_sUu.Cc㵾fYAfFki6FVˌ1nbBiQU8/b-lxOưZ#[_j=,Fe=y9gevR_?̫򫼌/,eob%x^:E__ l\Tĥ+5N%,Pbѥb*LޟkUyfVrRDz L\b IDATX=1k-o}V1@  t߾6޲qԔeY19y6ɟM1 Ia5PV$ػwﭷl_>f OLoڴ?t DBd$Bڷw[nm['߲i}I01?q߾[n4r:?>>q{HP1v7*!FwM+&Wj>{ ZX rM!%*TLhIOkmܸq䤳vĊlͽ{#H1FD@Ew߾6O,g•SSng>c")$z߾}6:|B'Ǘoe}YcHSB ۻ߿lY#i{_޽;Q)c˖SSnٸ{1 Y+b ފb}}[olFGo{MI@]8vV}˭'Vlt˾{"L)uwV UoM|`b|EVY[Sܻo-7OLq+6O駜< -04$aJ=0b@Ba"@H)D=#Vl/%E_BK~@+年^&/96"=/_,v J2cޗ]7/ٮJ%, Ѓ_C?ckW0ٵ&V_l|Tohzr>k,?r_癛놹AqV%>kac{Ddvv6sn?sX+VUE ƉX\ =,840;}ΙUV !Ԍgu;0jzڵ>ѣGsdnQbk#;cZ1BXFGF#GGFu<.sΈu&vX6Z|U+Ɖqƌ5s?8X'#Ɗuw`%"v`p|GיDɬƨ* Q:K<88t9jDߙޞujsFrc1R?r7Hg17.3NU [&4<0pA{GG5f=Yg.Ϭs[3Z?sss;cU#LLX&sCC0<:tG ek3[ㄝa1hZK`DX 9 y_p}zA9LmHJ\W_b/5VT.Nź%^8T}0\~c|xnΝ;MyA9(V e~ [6PV'_= Ahm{w^}@;杫ڎB SUN@_u׽ۙ $V0Ȉh}xJg? ;~`nf꬧ȏGnr髮PSk @z/qܹs PR DWfnn(|7{zIe=w\DS\h5ےm掬]wUG;R@H" Rdێ[v@ڵW=rt!4&DN);ȑ3{gV=r;R(A aUSrֹ5j̪;! $1ؾskfV \v#G~j "UwܚU#>o=(u CNYݵ}ܺ==39rۄm!YDaΝx`f͚o~P16> ;)xs?vf~" ȝw5wȚ fܑ٭eY2*((a VNOzV>۶q?k5Rڱm?05:_vܑ#wة@RQ&ޱuWO^=}۶3BbT&FUPŠwyṫV{=rA#2042e5o۶;<=3Uɧ9cN#f]xfL_ȏV`OLMͬ]5o\R1E"&P$$DVBk0!!鞼ILjͺ9߉/.By1M^<\ŵ. 2yAPJv9$ /b?/e^}:j cbf?omƍlĺLe;'?w]}߿?kL=ab%k挵®rE?SqYw߿yGl|5e.Vk>2g^5&3xgoej5ƅ$w>Qi6;gyoOOZɄlr+jM.sFdfi\ދu_7[1Vt5# 7M睫eZBęV540Yz\H}yB39#όlƴZȨ{k#F̲1qh3YfZZXE,#ԛf|X 晵7j  A猱nh6y̍Z{ի^by>*#Ygؒ͌ug^1ZWUK30Z:gn>nݚ߸hc#FThDxciZeZq68LUqz3j5FZϲf)X擰hfgj-X"bl6p˲Zo涧j5Fg4Fͦc{XU:gwyjG!2$f) &αWU'NX1LjuĚFd\8w'T5q}~CVk>,3&cm6YuZ#Ief q}=˯zw\u͵ZYE-}7͈ 3 y1ZkLy獫9uП|+qbKX%,,Ѓ~}c_=:>v׎ O7kYvͲkVfzĔ>5ј\;q޸C?n͚Z׭]sw̚WFG_}wo5gr+^L7.g# >^wzfz֮=yOjto>O >菽{7=N=um m?zuؾڷ>o~p7?sXuƩek}Ny3==;峟\k3Z$Us%sСwqu=5gggߟeY7ֲUUgsg6;;;jUO-_n햭[+a6zFXU9g.7ϮZ5{zzz'~UpY沚sl2=33?==k㜸wFa#$|-[^}U}=Wn޼~k!QUg3gZsСU=Ym8 n\YdrS8eֵ3}ޭ|ygfz'ϧVݾyzG&ZFb9h2  a3&3&w[gss5]CK%,a KXėzW/nzO >vW]2\3vufLo׬\ >uܹv}ĉ͛g˖z'>qcǎd^˝ 31⹳g={zؕv:uTQNڱ} gnUW~/<"_G?RUc=G5`zO?s_wuo-=~xYǏ\fefȜ Ƭسkש'8ym;&2u=o7|b]N*ɓ;v옘pkW\Oھ}UӵZݻxɢ(N<}ֺ [''wom'Od k;w?ym&2EdwVVNڵ۶o,s&f;O<>;vLLLZE;o1"$&aL/ga]?by܅dpts=+Oڱn7]4Zzf]S+sr..LLNܵ߱c|bxkƏldjjz]'nm&6"~afݻy'8umw<}ɉ;v:u,˧zjϞ=+&pxάqάX|M۷oέ\bmƖw3#ƈ1F6"uY;;+̂Zw_]s?u KX%C7ez`d?9lgOfٟ>[Xc2PԬ_XqJESw LJL҈B(@w.*T+ՀJD J, PBF$h/O>qg I*%PU UJkyl/V)!rbqƖS@1c=,AP"  EIU!%fI1pҤ BhvPE@"&eD"TPf$a %ĘcDj@eH ݟRRL"(1D$)"ĘD4 bY@BL@HBB@&V A&@DՔvS=T*#j$UJV RLDI &5)RHDL$w` !(1#5CUe)hDbR6U@QAAOфQD @QRJH`XIAc-CLbTMU @,)(""3J}y v SR"D "ge?{[T `LbZ0bYI!EM!a*@U4*&MoZO}zoo𹲵hb)K M~n gq@f&"2IcHI[Ҥ)!P)J82|v: TL eY1BJ5vPU"P*4)A#nt"!& (EdSR hYSĔP!Akb [#E-bٚ8Q(h41PV02$1~2" 1ǐu*U5ݩ0*tPUL  1*2Q*%V@LhLJ@ {xMHD0 ͔QQX!%)DUd*Ec)Z͔' C$cR@$aIڔTBHIXA] * t&6.:QQP BL,dWIԝ)  )ʤ%1XcSRMJ 0%P$J1*D)B$d *)5,*HH R)*TEqSL@1Pͳgl*P$*c"H 0$D )c05v''HSBBTH4)"r1EU1ղsg0 cU"B'bʔĄh)%GiX[CfP$UEU2E5TL@A "S) )HݮՄFLcT0ϝ}+'@ޛGםUw{3{5%]I窢**S5MCi,[ : YM;zﭕd5]&jeN$Hy W*KW.j$9g?)h( ;$Oo}L{nQ,",ȿZhE*.Y0nqj~RSkW,{iڪrZX^%&,%%ǎqyua0R9E3 nRL󞙔``f( ԴLW^|@*-$ %/ K ȣ,22<z=mLAũ*~ı.|-ܾk",ȿZ*7|U}M|U"ԋ,̼?Tµ X "IRN9%1 :"i%M6ֲh-wx'4 kBKsSIH[g礠v- a hKE*af"IH%(wNH (Umm퍙"3V c PM`ss",Β>qH t/)IJ J- :1"1w X[' h킳E@BIKLZA uC $ĩ-9B'D^*GbhyP(ERpkB+%QڄhM:+,@XUKyfobpUXK.[^{Jy%?kT\,",y 8т.1_G21oNgzeW̕+pfKTJ󎯇U.W~WOf'^y!>q#e'?d3/~;qȞ\.7o{ǎ/,o4.={ܼ?ыSn>ԹcH}}}qa;/'>15ypę3RHdϝ6p#;a/>;ypzXLJH<~n噗OfO~W}:[)xٳ7o8uȞ=@?3O=_P:bkS/n^|cG5.[&+WO>32KcN;~"g#?}3N޳c9{ܵ쩿ߵkD01]8?W\8Satݸ~!}xsgn=v dbG}sS{g>p9Ξ?W\(?{a߾}DTb8$ ;&EIiaom2_,$Ib"އ9uzgw#R"#>sv~~ᩧzd>DB.̙^|*ιbr}u}:s܅ FFF}:{7g mĒ:}gϝٳ˲ !{̅ s ϟ۵{7"ysydT0Rvw)-$޻s7Νw@J'Ofo޸vľu3Źs/0" Fq^/{pֶSWߘwwEQekU+,]\Jҵk[d1O[q}'&׷[^$?6m_5$mj?^?hEYdE~p6[ uwԥd鰡cTXW[Y/ɘ궪e5[Ѵb岺{:֮Y޶bǿeO=wqGM55.׾7522iΤLcǾ/AP@HF)JѶuw{]oTQrllGvdjRL5R]"}\zU}UzkO__*>8VTUvr1;z=Sq* o XޖJǎH@CCCTowWc}]oww.t׏)`.P[ַmzz_(?ПBrں\nԖچ\.77)ǧgswÒ;v| ?)5PnwKomueOwC(e@uu5{SAs޺ޮtC@p ڼgzz>RԂ$핌j( =44nRUQۻ%7=gꪩݼys.B  Mz{6o\(}hhjja֭0}ʮ=tP.7]YY՛'Qoߙz{{j7NOSSS]]5u=[r{Ș[~lXٳyt@CͽU]ӃCTWOOuMuoO@T{sMMCwOonzz@pppTnvKt@6z`jjwzzm¡TOWgCm\n=T@.7we֭s}y$6za-\ 榦z{zjjznV\sW>kZzUEEMK_rs뚵ww}775,m]=,d(nm[ +W (RMMuK2%()raoOҫw.ܦ6i-~.",/ g+WoYzo[󝕡hmnil_moJ/]Wؘ[Uw~^{%-wqƆ- ho$bmaT:2BJ!eK,/g#G) `f#FIU>V M*5VTAڨhsƍZJ%ׯ_J|ӟZDqDFRac سѯc0^λ^3km$00&eH(%KewةZٽwttHHQJИ0jk qF҆tC)B4/~FlR<T:pcc㡌N2Lͬ8{ha!kQaBK=sdltT KADޱc 966623*ݻGBcƶoVJ)%;GF]F@-'ƖVo=o_uc]ccA?1sRa]m{':qb|Ȯ()ΑݣcZ;JPk7Gv@Fx׮ƿQ4v]H5ٹ{lt,0Su-5-J@H@j%$3K-S80:M w펴Hhǎ豱;VZkԮ񱑑(R166h566cF@{<<:6np|||! @#;Fc#;GZImԎѱQma)J {0wU*DSF޹=()1{訑z|l|xx({FFFGЌ޵'NUHw#ƇF@ݻFFI;H Icd CۇJR#cc];֮[e_Ahڻgj|ll6%Fccc1? &PJk)(Uy_{+RFR 8+kj (+*QQ*:w)'}qmtO-o3^ߟdGxOs{_]ZdEY_.fkV5mxՒhEKufYcehj^N7u˚6ܳn߫ykM};.8pJ c~/>VUVFFki4ZtjU'/ RH bf% 2R0 ?_*\y/k}}ZiBԧ>~$֦°cŊ|'R<+W $c"R:-3mI2*nk]&tM%H 2aF00V?/Y U(Z;2ZiݖY>1dQh|+ ??~|龜•ȱO}[^]ޖ ґTzPhkh# _jL~&4APȴaPJILK&a BӲ&22%χ 홌J*eLЖi+w0ب@i<f[ib֬\ 3UqJdgf k׮wKMѪmffl[KS(E* kt\mNVWaTsKk>?cHf3-hIiʴt:;ے(%#8jX53SYZmnYfEhe2m|^*5Zd:C̬ hAQ:*^ ThLf&R @K%hܜ煢lay[&0mjo ЅB#c!UR0[hmoZJ%LL>* LF )RʴgffnimZ# s흅BqiavuyFki[P(dڄ6L&F ֎U*ؠlʹyֆ̌T0; MsK[>B LJ(.A +:8XR[3|$ LK&4&0hٞJl% PJ-jniZ#Ϝ9^SSVT W]ؔ # MqHWҕU55t*tQ2W-| tk|{Q^m*/", gUK[kWl^{=M_덯zTY[ӼaIwTs;Xf]ݒ78mjl6p6Rh! /[4& d̬tTHEZp5ms;81q%wml M$I:MQR+ )s.S? UZkIHc"RF̬%%#cRĂLbܹK,SR9ⰒP;:0@@%/U j<}w4h[圫M2GW:NWqstd:Օ5VJιtuUC}GeJkm(s.4!~Ւ0֖LG :vXhte[k92T>v !Ekms.U|;WBιT\Wǎ+tEvww0'Q`J9*:׽9XrDq]EcǤa**YHotu8;V,?vs?vH BJ * t* 3|^kQA#fNZ+ qBDQ5'L3;;޶BMl˴yC2 0 rܨPji_8Mon^dO( -͙D(5gB-aL&Ӗ(BE) 4y%tPhZڤVREA؞y!P(d["*T|TP(,k IEa[k[g晙!BRUXcffzIf<@aQ2֦"NwZ=S(T+f ֖1J)Wj0ҜQB%L~&fv42 N,oP(dZ&,Y~caPUQ1;;z*R2 t{kfff&^ܜ 4y-tPhdhʕ+fffT B[=CRmE>?#]fBD^w̌VP(ZޞBrYsS>WDB5cҁd2|^e˔$%DT(ZZuhtZr"L{>ζ(+*--/ tERʀPBR( PJaEEa PZ6J*)+"%T)WqEYd*U,]~ٗקS6:KMhB%}<3=sR-,k@$= "@g~ H Ͼ[ߊq\+@ dg33`b]T:_(%>qչix3y=3xxN6mNL0ȉDOWڥȨ7e5Z>ukFWM&&&te 6ΞDvb y)d<511!n`,DgwOvbd'6m MVBB7=1q fܰah=ߒfs'OZr۴+=-goyp' N\/<9 ɭ;xqӦMlٝ~w#yM:'&Df?e)0ʞ<ɥҩĆMK6uny2~}(How={?1}$;Rnܴ1p%7>q$2B'&NIRNMlD0wwvf'(عy@yÆ 'YDfׯ__ZX(卝]٬f7m@kV̞,-MdO<FTRtuu/v:?矟{w~{Uh9XU+}p|;GQR47<sϕJ_xO772kV̧?'IrܹݻFRahy#.]*J.]:m?Ү _O?;u J(#?s~)PW?_ظ?+W+W>Ԝi8~Wr$I.]zȑG06&<-j: y~aa(z.]~PBj2G=JC 0&Tv/:tHII~rХKo?x2JH|[_x1c^R)c)yҥ_|{+0R:TRG|(U?=W56,k ჯ38޳2 xHJ H#(e(K ( /]v{B8ѣ$0" X*Y 3xOރs@R8o@9' I32"GĀ6b(DTD(Rq[ <#"RR$y&DkKJ)Z`o  Y&K!бw9W$JX gD "I R4lRZo[[=BHGfXF@'E ΐ, x6 IAy 8&"Ioc亪{5ᜪz,3`#!@H%y/䅛02ؒ-% 5@d 7r$ ,{:{(! Yjd>Ԫ~k}v^{IH@ATD%M\K!M|̡ E# UQ$"Ĥ12*(*"*4}9999ȐRjKGaO}m絯~S] Kf딧,dg&̶&] $@fhLϷ>A "UDNldh$$@(*c O?[6\ވ A2`WGg [CVl;2,bPD$tYH AUUTv@5F"2aTPQb# !6ƹzDtJD%6dV[fQ4:cga_ A0 baV71 1Qނ$*2g0s"2*@ldXQE *D"6l*`eRRU@ Q!U"QIT 1dY3l3!4AИFYS.J}D êY \|cg1)Tz !*XF d@PB a[2LZ4uD@@TA "! K`[ a9gؘ2QPh0}ι@QUTV5ߐB QTc&$ QAD44CATI$"#`5D0 J: !dHcha6H !FЈH@@bdˆ( 5"3ب16d2 f"DM]@@DHDHU$H:H5Bj$2H@ (f"d˭b{112Pr/O?zppp?zp{wpwg۾z;3jEG^l}[rlm4FLI2i#dO4uζ Ywxj,h\}ATE 5JAT-S^olFQvLϺ SUYEU!jddC X7B$, m]]h`߾l>"19hdU8* ` #Be4`V%@@YǦÉ7Zl4#U [*2b# [B 1 D̨HUc`V@ѨTT j DfCmꓬސ2"Ie@A$#j` Bք Kj 9y=G:Yn1sRЙ RQPcX*5|Zf( 4I^g36$*1vqdB6d[F"M$Q e61*! H6[#$K2W fj5Lʶ^A%Zb6*@lIDUTD"!&@IFT1DaB $6FDT$ȎAbDEb 11rl2%h hlԥQ<+1XC$"""jdB!c $DU P$ b DHZ#! (1*J&"@$|!bCDT QEB2 05V$&m-->I2ijΜ+>s8s8sŁw51܁j2EBVf<=}hkJ}QOEU΋1h# kW秏i-s|Rˢ15"#Fbdr>788`QbP#GDHZMD%z6'@ * zH̀1&B@R2!L*7U:tP1L@5zg1 *( H%*2D$P$!4AU@r}Ym64jL5De"P@ E -jh>R")""j@̀CȢTQA*fa2RLS@DgU&TR@d(sA@V kDi5jg F " FeJsZwl&'EP0HLTLb Q0սOQL d,21 dR`sK9h)e"!j(13uT"L63[QP@\m :APE B̌YqQH@cF@ 5 2 D@D$T!Dno8j4(4"@CYA0Ɛ5D̐jPD5#B ( ATQU r#OX4ׁJe ͛5hTQRFT(HHHFC LT%vrX=rȡO#"*DT"T"JsM-<9999t ?t(Lճsc:+GӕjC!Tβ{}s:UVXP$[D ,4bVLG8Jbz_:l "BTPCb 1JQQ2Qo EU#JhTI E "(hD2j'>B|*2+FCB Q*X%T$4@CPci,djn8bPQ$jj/22wȲ{zBP1F@D"!%2+ PCc\A U::zl f(* bs&7IZ!FTAPFcdly`p%_ھw~LQ@#LDTbPbr387D EAUDBsD1PSA&I`C3@hZ 5_ Y홽'dbAUaH QKRGPP`g(#[B,ec [+!@ d8ƌU~({"11u.6jH jc-ʲ@tQa)*:|44kQ@LֈY$"#(@U AVPQcf DZh Fm$A@P,kHYoFt'o3Q!, DJ bD(YD BP$"{019Bs1"FlL 23jQP窮sԫs֕tIV8\Ls:JNWT0aJko/3řįh]?yFqw;~\/co#w R{(V{->w:W$[X}g6}jg"5(B Ĉ*1d l FmE0uU% IXgFi!1 Ug-h!4|Ă1D @BV1Y H bcd)[S""P1D ! 5bKӖ4 E@Q%.k6gIbGoo=T0Tɲ*fժIBbE6YR(pY>ZZd:N̔ABdADƨ"B#IPBP!b=:k1&5Fbl>6YMbd @ $BYA hdBE  5k^$FdVK 1d2QJ"Ze3\C (VҨFFa$fWkdQ9 EX=b-8. IDAT- k6hZDB2#E%0D"BK.CC~ x_AHji2;SeTb! 2Sc} %CDiHlN1d0`ȌeQ"2th@51"DBABFA֪j,B !abk$ͭ$ )e[XPD c=8ppvvv׮]k׮hkmmǷ6uXNޤXU=\ ]ٳaݺweWlݺuO7ǾoI?'xn#glK9כּfժ?я=7}?wӲI]rk??;t`Z}'? /"h{jw޸a㥯X(;{۽+++|Í~-{i~ݺno9ηC6nu 4Isc5۳aÆ{{ٰah.ͧ>\Ӽ1ذaÞo/#cc]\gg {)i||pp:whr>|ᄏ;s-5$6uw ֜zj6׭cx"B6x׭߰Zn]__?9>` <[a޽{ڞ=7lXߗ^r饉ڞu׆ 㣋KҖ}WE>_Hdth[FWi-ve4Yاu>C\Jɱ{{zuW>ڽ{uzzr Xu>16IrŁ_~pXsR&G[ݻ oXuugKK__3a 1UZc{$9kְq>uI lm|{ݩ$Ir?!g3Ϗ45X =GW ?~9xP⚄J-vQwxz^SChP#Neb)V+ -[˿˽=+V,4~>;տ+:?s{=[FX,[[ ,L$I|Ι$u9˖­[Y[nz1eehdo_^u͵]]~{~~?|l{ޛn?!TgL.6,Fy|uWo~sS6:֟zouwuZfFw|οW7_w͍m-wܦlծ[ym7\C?8ŀYc`dE_ʌ;?cx +]e=~^1I|!\=o\\ѱjze&!PgT{gcW\Y*_{F}u! YR@U%bDڲysVvʮW]Ө?٭5!!A.MӟԵ]UauMKR@.M#d![rUuu uhס1ʖ-[v\2g|s 16Iav&X3Q8ac ͛׮UYmg+j:l %ޭz}u\reָgVc-.+ QdQFqז;7ks} DbĻ| jp|Vw7^;I$9*QB|v3 e˦z׾Ѿk!۴yG )4Fm{o=ˮYkV{>Y0:f@4f TwkWm+-T}>@lݺ5\_ƟkC{ۨկ[yMrzi|ޙ|>a6ImO& bd QsCƲhPo`e:ۈ2|㪕'??eIOhD z?I $Nd;_pߓ ɟDix˟]^YuJ'ĝ]{? o}~O_З{: ~)RpFpҿ`rWgo/,}|Ck<.Go|/[,%3r+8[Quxᩙ(J'dP \ _dԔ6'hooofUjYs^ :444\TF-xRG'RZ26DYE>hl4HŖm"P! B ucos31!Us΅ĤVB^x'JCC4JCRZ9C >|4q.4Bggwx^(K],zA pёB,tڿԓ]]YTK.NO%)=tP5m۷7?SCG \'Y ڬQ?:=3::r&m>K}F 3sZ3 C#C33@mvP5HQ gȳώ,:|رc2vv`1l:T+H8ttfdl)Wg%K~~sQ@ZQzO>֎,So5 /P !jPmHl⫳B= h-D$6j9~xz|Ast?ugVZeA .J( atdwH*%KD=YN=w~~2=׷zmmomB#C&I]|C>"_,q}&D5(jT5",;Cr@T ? C!F%<]X{뚇!~o햑E#߻mTgkz*u,(Dƒ{ ^ hT@@DD 7 YV߼zm̌HH` !D3ܾ}ͫ  ܴz`YCP2F۶5ko`on^s5 e-Asrm߾ޞ^kypdoڶ};9fD=&%fpko/qn!%& j%˂DU۷^zxh$~k_÷ݿ>$6LD2!i D"1Xm۶ݲ涞$Mo۷#f< i6Ḿ۶ݺ斑!c_}˚s, |vEm֬^ק7y}F`czuF՗_>mtuow;fjG !fumkVi:rT B# Ly6mnY{k_![fͶ31E4@P"[nZ=:4S~>C_hGfz6B2VDneh8[~{w5d_=ۗXS\m۶ᰙP@@TyΏ1l]k{IUk9$eQׯ~շjݓ> ʟ:#gT_Бy.L=YeBSW~>'^ $0/ wd%/yԜ$y90u λ_\HΔ>GWz矷ǖ ^/) #cV .]:40zox՟غ壗뮯r.o{Gkڮ]Z{m6kL.',zR+|OU5s$MMcd"km3o~57ߜZW1q\d8ɲ=ߒ#H;5>XrIO*IZ!2j1w8)Gto[b-"qO\/yo?@`30?99ɾrO¦JmC,TU/\e]rފƖ^G韎?sgOx59kU4璾ryr81ՙ'֐FU=bsa[.'N(RX%*сwvtrӜ֧ksimW49zboY[:QdwIO}Ucs}Rs9'"S׷bK7{, wܬ KYꜘ!q8kO}m]i+-t:vNK_u1MZ3\j,yoِz_h+u4uxǖ[gcZ[ tR'V{ˎTgNFG~l((W}|>}rI?~`Zݟkާ◷c"?9b()r=:l{ow9<"{:܈흕pKŎw.ݴuaQ qRk˗?OJT"ڠyZ`ȑC_W~PY?>cccBˢɝ7K\r࡞C ""`zzSC0!VV3Ȩ "XʹBwiຕ91O}>77==~KSSS^*]pEOL|StIOߵcǎŋ[ZƖLNk:$0۷|U+s+.X~ (b Qxxɒ֖ұoB 9.Hwu;-[Z,Y:sr|8[].Dia|;v,Yeyw>2uwD!f5؎U7nKZsK휜\a] $DUټuĎuw]vU;yd $FSa7n11dEKoيK^h7&q;M:ÖQbMb$-tv ZT@ č6xŋ%cc|du "`5$zElҥeKΛ߸L=|ݻ $ K.no-\|y|ݖ-KƖEi dmbl4ckV^woy뿵kmw܁.ImK@U`v7lڱ%c>>cbŒ->]֬mjzFT0F2^7cr⥥]k׮~􎣇|O?ɫ~ŅW.۱cƍsֲX<)sh1 @DHXB Y:2%QD! c ǪbTXη35/^)Pxg^Ϻ98M^;S% o'/2_gxn90$GYn ^9#gYۻEwuu]zҋ.*{@\.][Eu^d˯KiQ#K]_o+.[ݳ&>PL/wLOO{OIVsiKJ%ާ[|ZHÇ2JĆq3;;KZ糿O}8$ykm}\|0g]DU{$>|֮%/UW,^4Wk1;o}}\!\˗|Z4_TʽI⍱I.:\4TUr1ͷ$|V*r˥wޞwx]ꓜO M{rYY\cNYwR;{)0{ʳ4M͵ʽ};hJ\.si>M{zzfggs޵&gȨs6KuyV*$mMs4_.&'[cU{gͥ-C#jRh)\JֲIϩIb}b}Jm>|\%^UYg s5PU-YrΑ5>-._q^|=y&b6JTr֤KlXo+X2K|ec U*i[Xh-wgggOwIΥWUuLW*|t ׼nUZ!U"c%nm)V*b8:w+njzUW]u:T:X\RT:r8Kiggg1Dh󾫧OR睱ֺJUH}5D-[bgTXc,dRtwr#KjZr[TX,wފ+*%sIj- ˪J[KRTrŢϷ$)fggUeI "K֢ZgN|[[>/Κ4M$uzoҼw&{ r-$_R=)}i\rwsbV!ھCLs!_bk5MWt{7KVyj|6 8֟0[]4:я~_[~|!h;}#,Y@/~?[Z[m^~歛׏;?|آ4ɍ,Z[&'&k׾{?84&K/ݾm;};/zsyk޺ӟFE dQCʗoL=kwNN?;?r]UV;?OO -j262xrr"09[oko DQ1W>  IDATtfgfuƌq#zھap[oD$A@ea.wNNq#Krѱko91aTc.Q@X̥>;^*Is##k׮0*Az28t(P}ݝCk619ITd&H뭐ܹ[of޵wܾsd)(>:9󖵷ud==]k219bDD!D,NNLvڑϺhNNNQ Zb&b !z}w?\>O cdxoɉIR`iJEY'wN]vltxh#d=s䭷ܺ匶h=x߮]us̵F}r5o힭VJ]zϻwڅ"T"hɝ!6pֵk''&T"Ơ33Q9#;wpiI׬pbk 4$Ckoxj;O2ENZLBKo}wws}}9EٹsrpoPw|xbbl ɩ0H\XL!jC0DcX|o9_#ͯEI̯gvt?y~ͣ1O|Nmv4n;ų_Σyy9otv?yI<,8gv¯S=_Y9™ [G~N]r]=K+{/Y<2֛絜]X20|I7P}&Jx+/mz⍳7_ѣG~Yz=3ss'c4?Z:yQM~VSSS;w|UHSGfo[[ݻqxπ\{,ַ3u}O=Tx'D$^|\p?=ZV?hM@k3S?:-ёѭ[ܻw!g}ӓzK\-[ߴyXrK8w֚-'g {riGƖ~=zg<'ἷ n޲9>Ҝ7R~ddp{E$oKR74ؿ8gO,:ء߲y6o:24В֠ddGȉu$$Xz}>MOCoaG'?5l nڼeާg}/=2Xw2#}EÃC}_O߸.tIrޙ_O]._$yv`p`M?iޱ7ܳeϞz}LJzxo6>>>?hۥ]yW ~߶4>0:$v`MgϞTH,,aw|X>m~yRswu>d-PGߟ>un8/9ÿ?wM(]pumsŢbfr%kC$PW_j-~k\ [5"sA"@!6o)$Z6'$P33xV5J"uFU4*2sQU;I833!CQPP6DIklh@!61?{o%UyX22##r/UeUic 4TI`0}l/mw=vwTJ 2mZT)>T[n,A@[26BR޽e$x=w{/}\),h9V^ć8=3h4|&g͆Zy]\_TP-cN) s֌`hFY9I)81S33UF"PP Er-r69ֻk`9( _#3ٲ'Pd0 3bQ^W"dFRK@,9 k JDHY;ƜH8[/eVU30`TUfͲ3LsΕ .k"DSSUb$3S2q JJ M,'"CPb2:Tɕed,FR&B$ad85ΊJ,nl|`v|YU\ÄJ `̒4;l@ô̔4,SV{vllK_zrܗLP|t~r˖sO魯Cg@Vo֛(/]|L*  %ɘTŲ*xS}YDYVUE\&fa&dʖIir"JGf$UYQ@myG>*꽯D"FːP!V(*[3EA/jR5&d'5eCS0 DҪdC rFu Lb@ U9J˄]J AsRoL=77^mð̴&l^wCAn)\zE~G%VU\+by-}ӟ/|:8ӻؒ9_SIpʆ e r&DD⍔/<^#\"WUVD]F,3!97J& ceX4q؇qBвfbY٧P s YT E e02BH(s) eCJMU@H@`@3fK$U.(Wk1pg  `j@~5p$^ba4`ʎ*) A͹zQR,L4Ro6#^1 ')h yDKYh$s- U4rf3՜YVDUI-kF*8 L5+A:{iF#fbD h`UIԐ!Y60r g=F/˲rO<s,~?^WlhD2YVdwq{sDR HhSJ3>!iIM %&`@22IX@<qLjg {΃SrrV$֬9ý'RJHsr|_VO]8OX*+ǎ9 RR欆 4ғ>!|. JV`U 6 N9XFrP Hoq|vt{_k1>;4|m&w6!0F'l8K~e_~C g5#3DAEMFT$NP3 Ơ" t T9F]b4]_8]ԊTTT1W#FsdtO* y'U LL{E"rU)†ÔH` @@USl1@vjS5E'eYk˔ $ő- vi& 2$$Enxr%¦9HUVdnyD>4Ο˃3TUy544d#2-q/XS rejLHj`](7HsX L NRR΁8WIA !(T+BRH/vY5%CC2&)Q* \%+ @ 댏^<{2(1e3%fEL9%#" ȨfUgSUFUB@c!MP,@Vf@D$&M*푑orM6dM6Gd&%teU>E̱p>?5) ij%/xwO6AOgR%*SV9P%ѧJAAs&$AI8+:jT_(G朓1W CqEUEFCYVW93s+CT#4͠ -6j)x@59U3f3bfBDؠw4jjo.e1sUPz Y"2䬩 !\V$\$Υ2'B+(XJeya!hJh@ F0<:fs4gfBBBx5SΛYeÓX`(%BLYI!f%"0RF0D9V e#CR"V)3"ĵXvJ9X d(^s"B+%3"*Ɯ"QV#"MUJϩZ;rDUe : {&,BeR&Lg(T0guEPgJ*KL8ze˦jDHDUU0̧J9UBhBULL.EgPc3&,4lHhPUè0! ǟdD^ʔ )c44KU"S#R@3ms>2o*0<5s6 ʊ T+@2T0I A~&l&|(ϟm7.Vr.) V4(u6AFv`Oɘ0,*2ABP˩_I *C"b0fFA"sefhƌJ(dr9W8<jC62K9#T&?ר"Ɠ2!Xo5 И@IsSRH&..z;Mes~ + ^dJe9:$SClB)+jKА4V)g`C)b"^dltOYJ@ @/>A7K*Iժ)d"eUi2Y)23*ce-U J&D $9c2̦9+0%E @̪ĐU-fUBcf3x:T jIK jSO| @sVu@Bd4BJ43*$ &ʘHs (@(-A@1CJ˾fedGRbQm`ęc sU Nh8HLyxfPP*QP*MGF_挚!2J;@Y ,\PXf`2(f N,b,;W,d`9) 1&D02%Ԓ4Y+O0 zAP 0 o&l&?}Uӝ/noꅱw>k?;1יrnǂ:s3/;w^Da>ka޽{?Ϭ?kkq=?n?s۾[ǚMGȣo}[^ԂXEy+^?Sn޷oD]~y䑲,yѷOTبmŝO>e3"!?ݞݿSN-ݽ4;3[ͱg|uGz{dd 3sJKgg 6blBdvvfg?tlgBpYr缄8;;w/ԩSMOpAKpq )N.T_?+55XEff~vggP{=yf_cv|0!6j:;w`iw/Fq.ju zHl4=S(ΉqaC|ffg_cNd3iԩ. 1F|f"c(ff}3嗖f;Q|or!Xk:[m߿c=4;5Un0_Z:إbi܌\ٹϬgfgփA\C-?xc-ݽ4ՙq{ꓳ[8xg_Z \m3sBAgϝ+PVϿ_""EQ:Kp\ ! !29KULfW~a׎]W]y;}#/کwv0k-j1@clBtV#YTf_uueY.9b>={ړ'~w󦷾冹 ׿B9!jʜoKv3}S?iM{ jE=sL~`\u=]_2iJ#EQk`Y>2^{w{W}[#16j5@(H{|dy0(_纉u/~c2!q-X]>RU_qduu9AQUY 0-߻\uw`e&.xPOel[UկzT:ę12aUU хE#;f'rU1^^.gu_]UU38暏X'6 Ţz<cЭAZxwٽ{0Y^ffk(<ԊRhʲڳ{Tgu{#GHD3|y9r,}}{|_1l>J=0gZ*݋/UegWUU#@&f'޹G"!5=|=eYlx=Zg):Pi6/3_e[lٳ{wNzpT|`x3޳glllϞʲ(2(b#jƯ~OU/q^eljSZ62:Z+ \s\7f6# ˡ, gZP IDATjMa'LrV0МX ϯ L Z Wl[6dM6|O/N,NM\ml83ytfwNofΩ81rf:g'\>۹ltˮm[w5ǧoD"E ΅X+M\QZȋv3S3$2 0-]tI̬>F?R `z sX-bͻZ.t>N5R'GD5M!76"77k.z5}1Y=¹n;}sε۝zkL59jd(Eh4kksXifZmk^\m;.D"OO9睏Ab=̋cdA tkwL1gޙY(GNXn5Y18!LNֺ#B0fiZGnwjzh} ښwB;7?x|aؼt OKC D,9/NNwf!tZc ̘I<9ϑs.!XCG9Z` ՚\[[!C'3f=5 脺nqNXtN9BQtD/: &ώwf潋EA1tvS"fe-}#̊戏u!vv9i^[[cq.H qCxZ֨5ɵvGj59L<'"EMNOcqۭښZbfkuw^o[_{QpjmY[[sfzW\x;׾lslX{7)֊Fs,zp!8s:R NHDh-E_kdM6dMF[~g^4u{S^Rtq7^Zc-A0e//lG{70;HfI0eEx7t,*0مnGp^O cǎgd{RfgnƣG+U񛿑rS$28Hk?@x/|^:ou81gB\1n_~w~W/暕;*?o/x!~-oќT3ǎwl qnvy豍Ae(~w} Ą, ;v{gg59K KHU^@Ǐus3sEۺpӭ{=VrI(2|n]_٬7s7~1b!"0Q#(Y A=z{fHxnno9~8oL0T UoTffn=rT RPД4S5&,@, % `8(;zl-7fgfnڻYj8"@qhC@\*j@ *+F,Gu߭ss[;+SJ*D?ν7=v(#fHC4e>vͷ: sS{?T @ȩ PQ;v즽{;ӈ0?>0:ed ǎݴ!޶pM75j +;~潷̏~w~'n DLDFLc7x\qn~v7?vQ8e 5 790?-=Aq?ܙs<Ǐ=g/$X_޿~o{U 5lT r !iԆ"1^ em_M6dM6?[[#-Sv,tZMwv-n/~ cVk/}KoA ۭn~1!>K}vnz&QYoً_-uA$8E ~zf;_?{MvzN[-|UUVs|G_89瑱Fl6R"{L?v'ur>PfVz8>UWVV&&] 碙"kLN>|k{/C33b .8…[zvI'> RBEZ[+# vR B03_EDvguuYNZc4/ ٢g$ׂXf}ͳ "Wʉcu_B=0Ga<[!"Y8 1Wտښ̮ ;E_3]]]L@ŋIxD{r\R s|c1x&;gɓ'xދ曮~hf8 E-L']C'Wۓ[0a3s޻lYS]h睙! ѵZY+c { !x'f¡(d+b9Zg|^v9b ?? !F8'\DWyxyA 䃈wZEARuldM6d;.U>h 6Q'688sΟYNOT &J$?QZ! I ,!8AJjDWZ.[v}\ ֨{\e>Epo|<B EQy(":ZZLO< q!\yo^oծ" !mvpafX+z^kSZ5Sn o1D {Ę];vEd (bzsSf#:4t]fvEC3fZ}rzum!dF}v^(:i!N\\__߱}^Dx?9v؉cDhfK^_LfV;G!cfdDW gf@zN'@ȎDjZm;9?y}nF|gfLNX5kEQgǓnY%x13/CGZ;zz[nP㋢03qzwE/D91͌(jё^7iy7iwݢ(\_89/Muy _;n9$Ď̬E1udכhMEhtf溽 ". 9vAuZaVv9"q>Y,xCpzDK>d ^HcdvfYo._u9f!v?{W~UđxΉXXH.PCVoPxEyq7M6dM6E#[ӯ˺sz g.ll|:c~/?a}B>UUE۷ow?#6/{wOZyOXATA &l6;36cǏ۫oo{8`f'r ͿWWWH?/~'ٹyC|7G?wu~yQwa"Sd?uhe;Օ5{{wgf[^Oqw-9s"}d@-²zxnwݹRV%'T@DeN6f9zǾ&&eF@$$:7;O~[o|-+YJ jɈO_VQo~59x`xUW|]ﺃ 8GHX.-~bWo^mW6jfD1"•{<񖯫{l&lߎ?ЊV_mzx{Gkg]7+wn/z~]}Ջwn9~G?oll| _x{7ݞ.||+#ȅ Oᗦ&;^$>+?Ɛ]f"O|ϟ?z75z33sGO:= N:}٢[cyի?}{-,,,lዾǂYD8.8"AHxa~{7~|8tPg{%s](.v}G?}Cs1x疟^صxRN>|hf΃C߷ԓ%zP'M )ۀk+ߤ2{m@$ 㗛<$$o$Mh!4 IHB=sk}_^U*y:?NήݻWk}_4Pd ںvڏ^'N]vjL'ř8l{KkO|kִLs?-brVMok]n]'XDKKq\_8:{gV纵kZ.U,ϏysEQlo/GvJF;LdLUl2Q65\0mZUqQ*"k"RJ)-/o}ѿDE?8[lLUUUUUUUŁwv_qo(%*Q= Mg1Sۿ ;h׮_k6`}WZ[O }? H,(@E6D}J ZdRX`<fuZIkD(B`HJIچz2cry@ iJ&`64Ej cJ-kT)-f@hf#KB@ iq6)'i(DT&$x) +%Zz4iffa!4ӔXX} F+́5$QJ0#*e8H Xr G"kL*:IFE >%T^b2B $(&RE#1{DQ+EDq  V kBV 9PNRҨQlR%m⚺a- ACJQYPH,E(DDZ*v)Da30 D4)HJ `@Fk`B2&Is2 2@("H#XkE} ̤ H156K$lǒPdXJRFBfA NJ0 )-^FmH+RIRM$Ɇ|!'MJLqa.7k©|n9m:2iu]q+w421>1ۘH2̊Ak-Lmj0򞏜,{ A&i@$6F4ՊX"^Q)< L<S >M3yr9%"K H+VƳ">0",D@4$,|)IiBYHsu3g $)xdhl.&ҦH@!@J+Eq'&*!(k5)B K`TH8T,B?iEDRYD @$@A@Dʡ HJbs@fVJYٳ mD!$ FԇH)$"JJiR)"`xF lAXk!Q ̒B `Zȧ)fRΐ֘Ah&&%x0(H(xN%r(j$x$" aPDJk}axO@e<+$LD{QV'A`""`#! IE=&R LD  pe2Qz!D# 0T,c` 9hR6poy IDATTI{س $X$^@ l}H85@Pcs` 0c\d BĚ|q`ej@qS@ r4JMAeT/Ѵ)gR.Bftbn(ho|?ZsE3xg߾?qY8 a'( A<"ދ"Fr*$ APLer 6zʰ 9Fʇ BZ+$RX"k؉3QYD!D8Z ē&&YHjDP)D{`CDϜxBiHVOIL&WW[;1:24:Bڲ2gTe%T*K%`&`ta VD$0)(`,Nij SD(FF>F),Iӄ9V I@X A pX.V@@Yg"`&E+O(Tʊ"aabDPZTkRƖTXъ(33 |-Vp0)S*HB&BLHh30vX@D• $BV9h ¬A}0!xfQ  HE.Bbab`aJ906΁ں瑙#"̘@,",ȩJkBaJr>QAcJSo+'@ъxuJ+$RF3CP?>8Q4Ym Ț ^P!5O.pOFf6VC>I4)ъ|9QTӘaŔԔ|6wa I*+"V0#RP.A1)Rd"Þ4Q!0h0)o9VUUUUUU"8H^qBv߾ӱ ׮llR6J1Nѡ+$$%(RED5uYEGD|9ʡ|UfP$'{( gP̈xnh`x(HGϏ2{ (Hh^H1'Y僀Bԃ#YkIQ\VH SZDDEA8HJibZJ  (R!OQ)_JEA< "AD1@ &ɤB Ib4AB Q @`FD@!yNB&$^ HF[$td`MAvV+P)Md.)*ʈO5B$UFS)D$%Q$h,őD)!%R,Ygpq *f F&'}IXFV>$D Ii@O( 32aͨp5H!MOu">DFHir.."RsQ%*\1rij"!MX"V]  \T"]tI@8 ) qqωxizX,00{5!"bEBa _[Ӫ_֮1$rж\JG& %,Q:ZI>1c%*[EX\fR3'albb4>6-Q]moB9 с5ܓ+ JW9*( @Z(YHheG'&0"F !QheNBLRHH@R XTtntt% WbvʇH Jr+O$GF"@dģ$@N!VQ!)J4-WfJ)@`8a)4 [xۿhP(q\qΘl><;cwz/)8wf4[;E;;pɡa ki*QXD" B$iJҔ@I`TT`YX&mijFzD,Y>^ (lnbD3gA&])aIZer2<0!( 6F?6VRHSʌ E3RSU%e32)BNQ.j| QZXʡ"Z%#YTJM4%c*ӎ )>!A9ao3"P ٖ6ʺ<܇Cu:x'HBiJc]6d3q|Qɻ℟oݹh˖~}nkk ^yŧ֮[sؑv뮥Km>jS"S+iT.4Q,KI8aʕ}#Z @OWךFFFv~{hp'/=!U1)?+Ǐ}t{^$ )}70H(i.rK 7NZjC:⑕&5"O?v3|kK2,C]3{_,MoB+;sC^߹K$ձvG޻oo)xUW>N  ]wߝ[[[֬}/ydk[䱓'Ϟ;\[5F;;:{CykM_YpՕGO~042[o.^zO"2ttc~ok>ç:qsw߽8I='#+_$]?_/ڱܻEP>780023{͚'9<::_f/X{{Ϯ]{ݵ|KH/''O+'םz~]pMֹ_駏`7\tiEFtwu>ǎ:R{7DW}'ׯ?xGvq{BAu^f?8?:g_a9?=u]{,^$W R}}ƕ{й7oJkמ7|k{j5̝3:xcؽgo\}kE "3:V~ȑcuM7KI$D۷[ڳqwգ;c:u%K{{rqnޅ6o~N}[lkFףӑ}SNw䗮~J] .{/2oݶ6j{;{Vz?s/8u}ݿ`Lfy}}}gWv̘EQwgGW(69e]lμKmfok9#{g=/̞sԩKt.Ӥ׿vkOOos+\[pS,^ݓ.䲾B}?jz+Vz>uU[pK;z{3gn6[ӻU}}}N9uwϙ=;_(̻x^_sn~~{FόՏ7Κyŋf .ﳑ꫷~k8ѱrm6SN{=sggs_\_+_ꪭ5kuYN6:2W8::xw*n䳕])km[l6J֯nݲ%&hmD$Viq8kL&N8oݺ~"S[o8gEt"MYuBdIGGL1q)іLSb8~s7uHY:2QֹXiSedqrX$O=/2Dd"W+d]3(kzb1vgjj|A}.l&"u&v'7EkO=u;g:k:c1ƺHkci:X,ęgz;9Ttd6"eMř\&uFŢsO-\&2 q>eL!غiSؘgyfѝwl(igm(;1FvLk)hXsuэ7߼|&3휋\ŹܴbH=3w.3rQd368rq6;&(:X,(WEEFVȺ\&.d8k)QE)bz/#+crƦں_ve^P?EnRcCXlO/im"D (c4FsQi:X,j O?朳.Ldqqj9ъ'78koI69[f]&6FQ&RLgsSۊŢ_/ZH䍩D.2&2Yml%6Z+=qJX4>Sw~!pJ*8e6(AYT3ﯕ]dFPZ;EQl\ol>K..ӛ1imHTzPERkrk8>=Wh PyXQ&>J4!>t$IZ(|}# (nik]ᄐm9BD>?=8xM7kƚ\~֭?p{KKǭ޳t J>@"UqѼy/+rY!jW^~‹.Ebljg++btĄiD~nۚ&y~U+̛7OF?8q7|"7mx}4iӖ޳tӦM" Bgt<导wW^]{wo_.*)9;cڶeu]71>Ϗ%e3.< Ύe˗m+"/񉟾-:!I9˖?uVD&&|kh[lYZdD)҄ѱ|&&Jowdbl{>\5!2G.BEm[Z۶j4 ^w~x;e rYlo?p[R ^;>~~׎FF|a*0 Ѫ}zo߷uV$59T I};߹4dB@"V{ٶm6juס2{{C<`>Zr)MϞ0;?m۶_{=:1vwxL& d|tgxhm/oE뮿nb|]o۷w&#c)Loowm6څ Kŝ?55@FB6u +wu~ܡ,_Jx,{m۶ ,#>XMBI5O}_kS6/o?xL FDT􎇖=uVmu]?>>޷G|`FR^~m CHȿ-|w~@ЬHzmRZ2$H8->.wC0-UUUUUU.xgwͿ)u<ʯϿ7g^Y_P憮zI :;L;wW\6-4>w.Jy[S"yNknvΐؠ")4d#2d4vS'Onܳgh^??Ύ756DΦi:yrs.Sp$29(hʕ1Q!(Eڊjʳvic4CgNv8m+u3qL4<mv5VEqe{׭_qgGF::zb13ε9sZ)JL&5s7oڜF.㸶09gϜf]mc]676\ffukmظFfddCrYgbzE|.:ٳνYgyy:cI)Ndjm1kFv82Ng+ El&QeA%bEq`Ɔd=PS`r >!(DLJ=nm >(FPާ['B%I!p)-#O]~~ '?[nҗ'=PPNc=?}}oz=wk"!MB fКAJCG'ov5<4ȧzϞ=q%2|Jfnm'Ns9@* d#wvǑGJUObPHTI Fk$:xn;r;D'"|@DaF,@ #GE{_۷oAb@: bJ!(R#vcP}Q, Hmz9zt]w{ pwޣ@EHA@+ ($9{q{۷J{`ak "b`@2>{-[W~mL7D#"&'=84xɽK !̽SOx]P " OzEw:r*}>:{CH`E"BFFj&k w}aٷoF0 BV,! !M:xm:%o>(0 Qk AgaHËnѣ̰oR9#  %};yaC;o8g55i>rm:z@ܿ.I!T H%O@9t;۸qdc)S5)P%>Mwۢۏԧa߾}顕g@_NAK_СY篹v5.\z}?ʥ4r"NER!b ؇B9?^"[UUUUUUU{8ゖDqQ} |?WlTIqəh FPT\*"0K[ïΘ>=dۧ??O//ڗ5==wwA;֪rD^)~~.YǞXSN;v}imJi|;_,߾?--NK.\?ЊGV>l_xl.s\z=$Ν?@6"j6cNy~P(Ag/߹ ZĚ֬{\g]Wg#ˈϿҍ78iR&tw|;ݱc_n꿸`ɍ]7j_|7Cvءį]իgϚ{Ybæؿ 7~EQoo/۹s'>f_<5q?Ӎ6K?yojjF͙9sxuDX?x=N;ls7~q4,7vJRw/>lY`(‹Mꎮ-۹cB\aN*DQc>'3kTsT% 1cI znf eඍmv{ bt#%a7o~`sc3v¯}kDwήj6imwx A'?z֖f$ -͋/+ {wߺcX?Ovtt4#/?P,-W/w߽/^tjpp޸y#"… ?Ͽ}HXJBR_riM]RSGO-%:ˌ9JȈ("B#`5!0೬}ΑGoՉ^zm6 : vtduSZyhx [{,]x\s)]ݟkGl<55UT^kv8c>{- ;sjE.:ok^MBvwt_~Ϟ=ju[,Zy+|xޮ/G>s,vܹfEsZJuV޸qyy-5֨\vkF$^rfffn4h}]?8>>>?%:s銍:tpJHͷgY6{]wUWנ^z~|y7Z%I-'nyYqgy>N;::'ŶOrˎnojB/;sMl߱F{G*oyW|ll쮻jiiklj]M7z::QZ˛?ok:s;ړ9>q'o67%F/;̍6ϵ߱}fGk5:uMgpe˖=;w; :ѳ>|T+CJR\Gkg]zg[%H|csۼiӡC*ʮ]7;ڍκ?;vdY{Qy37vl~w7Nη;+-;ښ[PVO;gY{lw}PL˖/۸qԡFK[r;,=6vǷ,eK>|dvvvǎ~GGgrT_Ϳ~v}jmhBlO?v>7:ڵRٛoyǎyxp'6^r6~m߱;lmk:n\Nolj҂}ٿG]ZֹĸbZ^oknV3SJۤhlb u6)XkJJTFYcTRIZ*) `(ݶ [SSSSSS׶m= YQ%>sK ʿ:{xeџ^ޝo1RZuoknlŷ~E@|,bH =2@A I C`@PDA 2P J$, ź}ӳ3Aey !!(1dFI׊C" C $,QD51DmHIB"H@B2}x"ϪVkνŀJB:sE@@f G zψB )FB@Ȟ" VQ%ϝ5,#}1I\[GG#T*b#b :l:Y9zzTKB1G/\DU#I #G}d$)= N$, "1=0!YP"rHy `Ze>I1JxQ{0TP1Ia6h8" @ 2 8qxfQ)Q@TsGX C Y"1 "cF >}HV2 !*eyl.RqljC$@CYV=A̤> $Q~*D@U3@#E\(! K @@y0JfL0yVgH$ `GP* d2!cU}{ -0c@PQ2 ,C(1<3! D1 S${g''',D#0+ !g E<[E)0"#E}$5e61U"#EɀSH&z"ISڐq^ 8jl*"DC (M uhZV9`P0*ҦRY}@ PKSQ29fQC&ώ4668-2}Ĵ(j|lS=%$L>ə HW5뽲3FHAJAk# sZ8$S āAcQ IK)5N9DG@@PB5(bȐQPl(wC9s^Ksf02#@Jbd'D# # Ix$ `"iK H`#3$J瞄@@bQ ̠Hd%8W$11FI*FRxY "#0D@ f Z92Dc5FBJ^E0[B# bA A8=Si pFF Hb|dc)-c`ҺgT̲^yDPHBYLq0JsTTi L(󞁅rtZH,=2F8p` ,P#3),!x3yșIb:'%i"%%RI<`y Iɉr9Ftgg!c! !B H(#0R 4 {1'!1FGL33D L!x# y @`$EͮXllEVj5R#m4"l($ɑq'F F>PiyLR(DfQB BDV*2 R* 3!F!L D6+˽(νzD @d6ByBH<1 as"qd$ ̳rF-f <2b{E#D(j]ɲ B<$C`@d Zs-FD 9(E8WSL=͝L%8όT} B`BREfB(EAH#GF!1DA6B Uٷy`B`IB@D!$92`q*I)AP\̀H#A)H i ɈRԦR4I#<@={Le8zBHT^1@F@&69!C(枴z Py{/TB "0D @+(PVeFD bD(Qf  PD@ \SS A )!zy~!0U>DZz/21WA IDAT@`LiMMMMMMoR`=L;Tgb43Ʀ#Ӈt%-xĀ "Rg )Cj1#RԞ Kuu uJ娏 ,H58!C 1:!j##GFbI(kD!6D}b@@bRpnv47-D#Bf#j0RZHj%T% έBK\r IEB!PJ jV90q@!+!F`@B(O (2dCRVgc$B!0#01F!\13GL#&f*F%j*$fdD)DC Z+\ A*}5x"" 1C#$fFj[ ^@)1Y2soB, #cWH*3J@$"`f!2gm5" 2 I( ȱ2 l2=r<]L(9yCd(A@g$f@٣G'3B`f HIPdvi1ܹD @Zg3gυg9D,YV@ԚߖMANL WG?5qVA:9AaNXz7 J4{{P{EJ) sU6HPf8A̫hes1"$$lufb2rdkHV倞YB@y )$RBD" &dɼrd[ktV=e8H%CD# KRd1D0ƈhw ѺsAb 9`̪2Cg@$`)F(!f3KA@D"ͽ CDs{T!F`D$b+xD QJ11U`LE+"[P A R @"OOa> !'3?c so@,cBB̈Ĉ@Ja6@RƘ6cu:3}0G !?8w #)!$$ґ̉>12j ,sQ q 1"} L12CdP9EHD\ͪH8।*/2DD>dr4C%˳AH3/rP 1-ȄHB $%$%A;MC$b`"!!"`$! Z LV GB3tl^& 1sϫ>)%9a$J20F/E<ϫB90A`@`fpj6S9 1Cr}!D!d2#S#@[k}kjjjjjjm[{z;z -M /1:uQWw}e;;{;wް~x%.?Rh!isKґ#G~?:g3z#޶m_uR g;J(_u]ٱ{SI)X04Y+W]Jecݱc ߠ)kߎlmRNkeYzY<T,)%5׭پ}Ge۷o3F)E~={,{W/ࢶR }7Ύ[bY>틷uSCZ phyU4jҳ~귦FAZhC=4>>eٶm.:BҥK7e؟4vopIKV?7J))OXrl!)v$R?ZoК@ƍZBZR3UYBI%V*( O维;pw֎Z 濱[nexhQccsO~KƖXQjhZq /XjJ+a2Z^xU,^M6[k.䒱lhl^qcc^|qfѢ{>db9}̟W3qnpppdM1 Yw-^X__:夓6mܨ|W^=80dpppڑ7Y/޻w?E Kp 'lܸ/<ի7&cwȦM ?i޽  納7:k^xᅫVTHsƍq/>v޽g/.N<7&iUVB@ȦԥB8Zi}GM ?U,nYvwJ.x>鬳V_|ZëVvv'pxxddƍR33[WLI4RJQe^<66b+5K/dl+56կX|l|좋/^zc^qŲe]xK/;ܕmm+W=>6~_蒋v/[~Vcc򳖏_zХdll9+67}Ί/Py%m˗ \|+/ohl\y]rqT/?6gYnij\y/8_+y%^|ESSˊ]x:-~5cccr/Z/4uұݻYqeccc_tq5ok[tu׬sE %.ݻw8kykSg婔+:;V,?k||]T_e}eM͍+V,b.8Z3F*)a~*gRKFQeP$BHBDJ+Dp^cmRSSSSS{m[O<}^T՚LG{[g[󼶺-Z{{K}]bwQ߲b_{cJJ533h)eZE#-R:!M͕J%HejnIKyF:cBqA缣G*sJɶ#G|Ƹ1uR=::z tpժ?ܨ"Bk̬RʤITk#Q(R흕J9e˖˯&RƚUFnxtí7MM.*p̜b駟~ɧ7N9H2(SeemJEIa#DJ+WI{cCi-QҲ>(UscSRQJ=a-jqV;FJgs鬱H;*ɆG6r͚%PV:)EњyyJ]GO~21(*P)*4UƈJztãFH3J mmRHJuRY4F^Te2$8m IJJ3ڥI:3UTs[l˵RYꫮ2\bk($oK4IkDJ)+)2R>|訕g?+Hի{nT e˖+2*c\}sq461ƘիV?1[\qժƆ$qZU2jܲeUWjk(%iW>2+.6&|U=vtt˕_nZ cVxQ??ªZkF^~ϕX"a+GGGKrU.Mmĭ^zttTje˖/Ju^y壣&-̩~ib~ʫrR)p+{9¥%kmUWSe˖+/ЊjϒTk+`f%J*##m3)3 #HZKE)a4hXvJgR:]mRSSSSS{m[߿`|{h8>minnohkI¡cK  v շ.;OX|gzSW6~SO-;ge8krB*̝{gItZ:†BM͍텴ls_{~K.mohݳG}׷  iO_}ח /&$m,RmSSJcRo,Z|鲗_v/ښ[6֚R!}WWkWZy7o|Z'xrIB)Y+̛o޴O/5 /~'G֎8Fл79f擎?X\8ē?SkFY%mtcщu|͛% #.5%wk:o-}N:vBHj䞑NU*P_JV֭s[WƎgłHB(kڑz6*PjO =##FB:&040t̢~۽{ !74]vb26P{u{BhoJh-K_N'aԸ4)]1uՉWJlj*qsv'-vΥik[G+VHKh6E-555555^۶u z:{Z5ϫCPH;dN<{`hS ?>7LسȢϭ1Φçr'XN}x UjLX2u… |'xBKgJ0s]R0ָYIG:QH*zkи`SO=ڷoDVFk:759ݝP]ݽrY+eiHB)Pvθ?\k399՝Xg]岑zjjj`OkYHمCC}l?:.yϢEyꩧ39rIr1?p?MIDkճ~g2)[ڊI|IJ955'*zzVBXPM.\>cSSSJI3oh#&IR*s̒>'MMM Ir ߿ٴؘP*)K,yhC?DzqXmMwoϾVFuFj?ϭBֱKZR-ƙb]]?brrW)2Jͽ EĥihѢx70KR*mR֘>+$F ƤS]]]Fg&13Q.['V-u_O_\6RNMNv\H]]A+--֚%-KӢ3IgWwybB399cNZyOLL(%':2R+Wp ZnQZS.LMNvh])˂hrr/IKƖO<\.Xi NLLҺR)uš8SS}BΝ*{{rrjr``(蟘p &'[_|lr,6:gmhh ǟ|q'֕qIR`fc:Ha2ijBK1i_(;:;ER4&M #՚ߖ>GR02B:БY#yfl$%u*(9=S_uׁ7&v|I  #LOܲl2&9Ulǎ>"$"U! d!D)3DfgXW_ܯ{w˖-ˣO~rsD""#0sܺuw"toKD;~nc$$H 'nܕ+/}xFRx3\u/#K/(d9,̼g[~WK[wɦ IDAT^?l2d̰?w|[YRx饗ǐ0f`)DȪ#ч_'osHJK/!pd!A0ٮ];oԧYy.1m@B1ZW+?sg>sV^0 9z7|$KZŹ\:6v)te}c[(Buj9sY͝y ϙ5f$;쫗_ٞsgyᇟymۗ.]ZW[Mf?ē/F cE 37GZ?g>\?Wv?$z֮]5#eΜu;wJvNk_ޕοm?ZbY⅋jj.de)i2Q̉RR;^%K\n֜6qٟlV27H(3RIc#Mjjsq"[ЖjgֵvH)AFK 4-eeeeeew6ww4wTvlm:::Ӧ:evgۜʶƖƙ:iS[ֿ1&2ܶĉ|~cC2j7oxW>ZD?-BHV|W'&&FGG_qmVF'|bO>D{kKclOϜg~رciݻwkڪ;Ko妬1 h#y wlin6Fk|'ϯؿޡt O100n}mֺc~|[Z /ܼyhjh&&R_W}t΃$p-7OLwRV?]{w`uJ*=т͛;C}]Vim2С>PXh-[81:11޻}Qcz˭Xi ~};ijnkJ)kDEdU;>:wev2JS]S?dͷĒqr&m5B};>~7iE5bU1B7dBEvomݦeJrZ$QZ:L6m}\n񦜎 J̝˭ƚDizJJߔ_]يj%ŝflΪJ}m}\o7tK6S=cάxdM7ߤY%r|tOϬӻf:NUגJ)E&F k#$UOm몭nU4'IZ)Ru==?tZVVVVVV;{}Dү Gq6{RckC0baP8q2RTYCGFF*9}p3zgJK!K@9 Sf{ЄƖq%ɹXLH  B R Bj]]d H],LhdW*R !@XD`DL]@"!BG'( 8'!pLjҥD($D  R!d$W|BD@!SGAkU A$?Hg@.DΕRL" 0U !w4D!-{!`UtE  ѹUUCCǃȁ&'1H3#"{>0I!4I8_('Rԥ$ @,cqO   !GiN$PTrhpH)J)` Bp.D,DiRJyHF2H$ CWrZX@P20k"0H)K"03 b,   WZBZ(J@)E@ "\`QҺR@6*;>0{0 %H$u!SSubTϻ|>8 0hBN+O "TMi̬BZ J`9Ja[rf1-yD"cD(DPT,rDbP (&khp!S;BJzf@ ,kjJ481kNkE* 3Ux '@&,s^WBJ'GR ~^UMSIF5 SYIMP͌M>xfAP$33!رJ"`4xP:`, !2~GB")@@`_H҉qpA+|HBR1NӒ  g"@I< BH!P*NZY=pP+*'%<&I] E;LγV< J% L\H+@x\*J.E)X)`AR.!H8X`!#HJ!@q"8)$r{AH]`DDcL{!P" aLu]ca|ؑi(IL ;J 8r1AK*TJ )(tiJl#W]>>2’)]mMUiX$$ x(L>AcdP,$FRyd.p10N~oAӲBCskdMf?,J ÃC\]9xGNHe{U}8ڎ;&}rYg%$G& %хCT@@"yr#b9PR+ ʊ4ˈ)< ]KJXPRKG ଐsR9VPRQi]@!'$bd%F*6*:y2MJI`@3 A 0%M}M[.2GH핢_b4! H RQ#b(9GB OS!>u EXJ1q)R.H. "I!ޕBɕ @2&b 22ck!8td0]T%&3"wA .xB F"@ 0 n2!C3)5HI`c d`f%""@BJCR,M~(A 2y_qw{! "Ji1/I`)E$D!"f_* #b)8JH J*xrm;j%e1MI`f`;@$J"$D*T4VҡCR 01" "L$X /% B {20!ҒC(0BA >!4!`Q@y ){&$fHcfUp!xAJE'iDHz)%;/`X$JF_7Dd#ffPJz`AؓB`'6\ @@!xb1`1;B@ !<{VR:XJ])M} rΧ'Gp1/GF&y:`@ LDȘ1_8>!yG BۦpY*UEbqCd"&3 " J.%Dx@(PɒsKII2 $H el|Zk)%q%Rό<#3"3H;:Uʃ;Phfv.0  ̌ 8(!0z& " =0H"U\(40I #"@ !g\(D$d #A@Č|!"$"" $ B<w$@>7H뤡)DqM#)ʧ^"$@0@>xfD(й4xvc9bH|`&K79_1pPJJ ($wMp/'1%I y|DF0"w!S'S.iZ2ڰ@fIǨ'jH>- G\") (Rh^w>M{Υ!%  ɍGR'u͕©b]MӴ;5rؘ@R )IP RpB`! Rh #ug*$!arXP"!S|i!!_*0y|:xٚW8>*yR' he}e~d$ G^(!&<`ɝS cb;H! r9Q # %YZ%'&P*ZIB?@&B``!  PD  $J@0 "!4Ɍ'F#$fr+!A ̩҇K4ï SWDɇA"J )I29x/P ]RS$#2:;## _!03 i8@`&Fd.x!$" *$ȘRZdI0F"!%13PJ$B d@@LL ;;IH>o>" ! a`RCT !)yr=rB(!k8iH@A}d.@ "{QD;BdXH|@DD^H @)MN C$B@ǎܵ X@F0}RQ@ Хpr/ "D$@R(eE& t|l, D:8O@8HGɱ#fF# ӀLJFOdBOZ)W* ;T2'D!!i6N&b'0_ٔGHt]VX ?x!'\qdd?^tx헿:zge…^ԓO><8228I<,b/'"k;;Z[FN OMBZ'Ni)2~￷W[SLm#?|hX~썷Z*A$36v}{Z!0{ KF|8O>9<2:ZLl}Zt7ۧN=^w- rMRbNJG}uu=݃?y=ݎm-MF7ݼwco(sݗ}^{0! wsx[znD~Sڻ疛oA@߳oÛ? IDATc$7x[o5>1o_{uo}:uꭷZs5Rѳn;91w^ 2 qͷy{ةzs͚k'Wb[n7w{o5Zw?9<4}s_IBHbiPp'R)(&N ]]۞W^~wǑ oͷ}}oQ*|g~_( RR){9<zhx{iSჇOMk $S48xdxtFp@iS=؆85>o}χ~'|߸?MnꔩP,8Ғ/]T+N x)J# Jk-5 H`TRE1Jem$qrhL+RVVVVVG=}-m-SZ*{;g3gvK{)=MgN?}욤jJ[{}uDžs.4ґ?O>NK٦eKm߾]k+x㍝\fƌ׭ۺu3UM-jE\tN9su3Ϟ6.T6wlqcZڵ/blΎCwuwg\nE?&Z|C /O.]D+[iffmV1^ٮ֬g2]׭۲ysdK/\\SUp%K,SR(Fdo_"mqslbzWW;OiiaC,/qb򁁁ŋ-^xpppْe ,^n˖/ڬXСC -^p+Vz``K.o+^r+._S#˖46Y⪁ŋ.XppppeR˗ \rƦ.[<88|L\r5/tpppɒ%Rʕ+ Zxaum]:80bEb׮]^w]GGg6Nnݺ͛7+!(#2ZK"#(2]i]Qu͘ۻu"Zr,oӗ~q"k׮5W_=-;׭[uV#FK-JDV'_Bڵk͚S[HwMݼy{#G3fEQrglټĕ/nᦎ)Sqx=@s !wu5Ln;sZoo6KęG{zf'IsyBW^yeիg>rx`wtuuylQz5׮2=smo͛:r__syUU}J5WnoksZǺ[6o̚;>w}9Uܹ眻y˖(p)Q&3wV=s9}驩:ܲy+r-wϜEvun*s{oFwwɜuٛ7oJ3J TJk4F2ftwP&J Ir(IRTjd:f4N362֐RJ4r;{54=}imU- 5YJմgkʩMlVut qJC{Sfd(;11T_đ{6ecdLǑiXߐ6*LX1s}E"Z[:u2sc.IPBi&;ccc 5u1VK-eC}Srg~{m$0ZiF;v\Ji7ݺ}#UTц4LVDXJ[_WV;wXj+\z͎;R22F qwL5ʎUF֘66:u*1;VZ#I)֘իWo߾]sΫ^X[s͎+A;vjDZ(hu׾}zΝ׬Fc۱cfΝW2hmbp ;vT&ٹs5VUqlLgOwؙ$;wf#kLdu^cv;֬^eN5kvnߑXs玫WRh(!ڱcU$kccZc֦![1JKcjik5 )cF7(vܹ5 $5kءZ')B|>դԓ>{{IGZ jFGwRX$-ƨmF$FikLl|>x!Z(RJ V$$(-k&BȘH)EllLE&I#Ay%ԏ~{F*D:Q[dsjnhj֨/?3IJKVhkBJ)RJTUy{l.$26F%DR9_($q/?=wkGFƑ83I2mֶiZkdCG翸nZ*6J~_Z+DFݽM6r9'J+2ʒ$TR*"LdmTa$[Ue( 4RA)~KYYYYYw6TvUԬp$j566V47fUڊ5mzZji]06TlnjVU~6mK+k^U߬L%uul6Nٳf?ȣ۶nBjm%0sU6"mIe)JKW^2?NUN6}>3Lѣ=]]$NZk)TFֶvER+eiCCFj-1VZU*BU2VI)5Gݺe@(nL6mhhH*)bRF̧*駿w̜QU|~[eԱS YcFFFOC!RV)mmCCZʑv@)Ցm>44#đ1mhhH+522nXH944$momMLdM1cxx*;22֪:m2<<k5H9mhh=22>])YcnokJ45 B̳=qT"&dُ<۞W$j#IYmQqdrYI4T~Ǟ$mkk"ґi6mhhH(%V$3G7l۲-kb#PFQo߾|SV8J dEg>oۦ>v؝wo }eE 9e2gf<۶n:vmq7w55֨(Qd#l۶({omuuE6QJGX3&أmݺUEQtѯ{~P(o73Q$)TI.裏lٺd2GSoUd㚊D 2BFJf"=k#6}{.;vomG.3$[E]>֭[RGoUd+"cȑ#Ri?y+jYeTJ*%X2*%HHF&ՕMmmBV(5~KYYYYYw5e45]6)}LlsN*彯mܻv"c"\. Dk{{8v)l.uRl&R{k2z׮36g9A{dRkqbsh}&5BVe+s$ޚ*WJU[?s$lno$ۦcwZcmι(2(I m}͍R1J WuV&6&ҤXg9eֳ:"ѽq^%)2*錄.R9e˖3<3vϚq8ߍ߷YۺmO2nܸ7b!5wι[6ui(=kMk׮FK9gqZ&Ng=_ii mݷ9u떳>+UtϙqӦ޵߳N-[:ltwumܸw]6UD9} MRܶm=ܺsشq5ZI >O޽6&LiH06JX+kƱ l-qzgO_SGEKceOJTW7׵e SWTTC}]k&a+gfVV۲`ƜʖSZ?3?qWOuιgZSV8䟜OozvcM6)Q&Wz??L&QbT"k%Y{MӻfVUw]iӦ8~Ѯ."'V(CH3:2>]#$ m4Jjk3L:RRfԲRk#elT]Uisg??JNҦTBZڇ4N2hnns=_(V6mZ3gLOwMnҎLomS@cL{{P#j>44,iknWFmS5mZDVS"iFGG;;GQlH[;usFۧKCCCi;j\3$lah[kRJ%Q۔֡!4222cjk}АrddmQVBuwk0HIJ8JfϞēO>YJZYE&V+2qϬ|HS۲IchhH+y^u =oyT<O!$$Db'X@H lCO@cWK0~݀V$C $RRs~vwy-Y]ꬻ}4uR\p?:r2wNd'E6W* EHb`c=fe {͌3N8*2B\H .|?x-pgLg [8y򤱞5x*iy&nxxxfgKMR3:N8}eB֔Js]=cIj:gZbgq czc /ba…?c=çgϞIJe39xWinLʅ'NpZ:p1Q4mkm9m:9;^=[՗V.Gb& !,]tޗ n;|3)+noy;C#7WP}}}wLjIbХ_ק}}}˖/e}}}H׷/bCDE.di_^P䢋s^|K}{(}/}/ ,{/]t)|yw_^$#BMb]rq__Nŗ3eYֽ|K/߿(䒇-{ o鲋FR /H_Kg$Dؿ[ntj&yC`@Dpu˭2&wK1pEݻTx_VD?oEcUcKyCze]&!۷A#@E "旿KWFW^y5XBxM"&KH@X k߸[.[}+D%!~_՗I} Y+J@l@C!!.L5> "O,"Q(cp:x[|U_~eEZuLB D^k~KW JQI''"0F 1z㭛oue+@Uj!1EEUjYF6H`,*2"LRk1j5C.-%AQA$bZk51Yo4iҤI~'j_gKi)-]mӧ` MKͫ-lYfhomiX9뼶̛3S͠?<{ސ֗uwfsՕϙO+ҝ;{֮]>T*/^;J[Uz>oil+.o}gϞ}ׂY-˗|댝7w944.}.g֯?֑eK6WVZ߿vO>u y6Kg|Ksg.74\x>|ȑk֮>I?sO86RbZk|v}]̞5T,͟?޵kW1Iׯ[{ȑeK[Wvw=zv^y#GZliS}G?5voҥ-[1{tuoV+V=ڿf:f~ݕGn_|y+?sȑ˖56-^߿덱kׯ9rUmMv_f1u{eׯ]8 9rʦeGׯYZ 9|ywc}Sk]Q(]}JR^pу;͘;WUs92؞N2mђ<{v6kׯ?rUSZ[.]ݧ9ٳfre%;|pϞI!%8qmJ?!g5W|R,wΒwسgڭ[wt\PT͟?/$;{ֶXXtΒ|p=ƺk]ss=\Z`Osj^+-:g;vݺuΝ;;Jhт'~{8s/T{[k,\0;vL^{Οs)K,~?;O54Ew<= vu-ʋ|=&WTʥExpݻ^{Ν;=x{:+hnm) />unۺ ΫϛM\5 IDATO{۞_Rpђ;ܳ{'u;wMt媿 ).6?O׷9֓KW*ŢcG۴PILRXL|ꭳL 47̘[&M4iҤIڷ~v-h[psk,jkn-7tLok֮%sf3u~^6nJOѧ{7|󮻾7mj[ҥKzᱱ~۷O^L}mQ;1d7[|ll/xIX9<Z<gzɓ'<߿5Wm*MYq!q8c+\2kζٽ;OZssDÇo߾ s'=oɰ7;g-[>}C=<00PxpǎӦ{睷78eÇoۆw7o߶Ym>:|8˲C߰}{LM?Ço4-tӟ& 3&A*[7t8n~Hogo8gw7$lk> o+xe}sz۷Ygb/_3Ͼ_?o>e괆6U4M{8:۽|SO?3<;wL29}'7t䭷|hk\bsMv|5MCqw[ۼ޺/~዇ʲhw,>]o GGY{?EA$O>豷GF-QEP"DAUQT *@%Nܺ "+r.V%%y0F@Z LY1("JT*Go- 07~Z`j,*hT1Bh"s4QXc\1-=3b 0*#<'ƨ 2)FUEbeYePbCAQAPA5s "0FE&UAE2& i TxbDcHBDY J"J0BD9ԳcT c-:w=#e0LYvʔiZ(* "TYUJ 34iҤI&:tlRA_,Te_*C$0Ver3cgk3:F @ 9Ai- Q<"_HʥwS`$V$<=!@@%Bj H Q1&bQE* (Zj1+Ab.U$&`@As5@4IU$ 9OJ3[D±Ό#Q ( U$ e@cH "ynx"T! !"DUEd TsU HDl@@EA4&f9Z-"Xj)"P}s Wj5&F"P޻,3"d9 ** !3C0l)˪(@;Ѱa*D ~fȑT5d *jC` iCŐB3 )"HqcE$@D)(0!!M$yt(`E@9B@BRQ  "ٚ* 12)6QU s "1 (aUP *>5ȌlBU`"Ry{dƫ&KܙSQcjΜ9ۘE'M4iҤIHZGsh*OkOlĘ[o*#o7<٫ZΉyqd/K0z b9<*h9I1jАDQ *Hx@fAQ2V(.CP ɰDa2l0X&kaC20C^CCX3LejTetd 5*P"101"2  (Q AP HDD4@x1H`0c.Aj1CDDDQ R@H gƔ MXɔ5@d|eGvns=::X<920uzkZ0HyDvƾ;1DBBƪ!2 L ccc6H,QA" "":nBD93B-!(0斳gQ#e\jXB~j DAc90(2D$RT, %0!'yA ("1 P $"4$YJA- ccP ! PG@ȫ# 1VDt) HX"1#s:6QH#@!PQP P@PUabL٨Lԝ42Dղ J D(Xe@ Q E("H`D@@ƺ!%ѳÚePeH6&kNR[s u, LAD8VgFFD̳D&@l jPcS%v9 G0WJaFL<^71RQUQQF"b 9%g]F,b'Mlavj5*0( Q,\,aA@rTD41=UP~[3I&M4[-̉0k8Eo3b_q`x<ܥpB; PcE AĆ\X884$c."16YV# rT@A GzcCC/Q,H4n~޾_v'Ml{w{#gG~߿o_{ٱoy{wآJ.^#;~|hh襾_}_Kc5{yՑy񗟺r6t҇yS'Omf`ǎÇ|/F.#?|7~_-vuu޷CoU_'ؘ ?v/w諒_SfϺ__~o#FUm[çG^{Ж͛E!%?w7l7 Ah֭/[? ׿z`W5m׽KϜrߦ-[q~`ltn{T4?W_{}mݶU@1px}̙߶mkVec1*lzm[c%J^`-b745 iRl>XHgL2c9s/ẌhH PT`FsMeҤI&Mګ}:ZvX02}Kg*,l:unm^s҅47̙2qaki¶i͝5?=/ȅSf]ߴꙝ]Jy<3ԧZvZ:bKMO1gg]߻gNJZy]wlϞys=/~ymݗ, tSg_ĉg_5cFW}\NRUM\ZI)q_غiYB:w{駞qoܰʕ--+W]:00v۞;w]Nsfs]w-5}wuwOϮĥ 9ϙ{w?ө-:vmݶ`J]੧JzsbZX`ю|g؅;vkW*}O=ߴisWWWΞ={ySdcǾo,P'Okl9X(̟3޻y-Ztر}k .( \pO>L/lݴeYBi߿gzڱY`cǾ/YT(>ԓ;U-iZ(͝1Mq[*&3ֹKv G^}iV YaP|֬5֫j5o [b.)Jņrl\h+W`ݺBaÆ+Wlnn^ruiqÆ G^yԖKׯ_p+WOYذqC W_jU۔}֭I W_겖)^z```ͺ5+^ak֮q\?eSSի֬YcrGv/_ظ|Ew+7T*ۮotEkKի6__vk\~k׮ί_ѣ˻W75t\o]~}^Xrժ7m:cڌ-W_qmIiL[}SˊU֮Y_7ʥrr1'|g|)ɳimΜ9cƜ?я~#༮b܅>{G;"dxi]SK!8oɼeҤI&Mګ}3fMmjԕSg7ڧN=sVݼO_+~vJϟ>{yMu IDATs^ϭ11cccڽO>-$.I\l1싾4}||O\֕*T,Z0aNvddx2mͭgϞM}GzW=\&.ݽꫭM-k6MRi`:E&-7㭝>u||\nϞ~۶4ټesOOOHcCagZ2m-gϞe6###͍M(a*xzԥ8ޓ$$[nek]mmb%ΧΦMk6>>noXM|&ްO\1λ)SګjrͩsMRଳX .-+Sڦ'G?[bry={lR禵{cG?_5?duIE*JSc˼ J墵XCBj35;&lc۽{ϖ-ץIŐ3ějWOO\ALRc jR >MrRBڻW;묵Mڵ2xb4~ͽIػwM%ﯹ]viۻ>-%i!)$lջ'vwo5J%U6Sw-s4>f]=ƙ]fSZ(˕BxW8]z6nh'fk͛w4qC\;mj?8g6mz׮4-{9$~"N$Wm*)Sf|===λލWoLI}rkwvsӟ|q.Tʥ4vݕ]z7l rcIW]gggg׆ aorͦ]z5ƹr|9>sNK źvU=Ʀ]/>8C gu ie֬}gY28i۴r5>2yˤI&M;Wh۔,Vihn蘽e/2˶\;mN̩Mi>Rg+*%Ī+4q[g|⹋gy[N''-iS EU=~xeoO~ܧ?u3l}Y3;KicwGMlzys$Yr&9nhhhFL.MOuITU=X ;}s}wguvI;#|+Ԣ)tɂE>>\rɛ>gZV|okbr z˕Rq;3ɓ7~}M&!IZ,-XGӓ&ɓ'oWXlԤ}X`PL'Ox*(luZc-\p?3'OK_=tpV~c]seBZ,B'.9_.Gi!)PMSsfBϞИBSC1m5FUJ]T+k'9̠i$i٧'pWLXo|9kr  uvvVJr`MggMPnj񩱩sΛ KX,&084cY+0ڦro__Z}Wf]\w.-80uj5&1޺$x5S)K:Kɴ}p޽}/,b[c/_󼡾b yq{Xl1-K.ϦT,X0lkUԤ)Ժ'ԗcg]weԅ >ill/?/ͭ_hih,&k}8LmBx8w?<ʮ:޻sz<3 4&`'BB`C;L6veCl/I`,b^lh!A huzSG8}/kyߟ֭sֽN];.ZSO߳e+)DN?$_褧~z֭)"w9s"gx3Ϭ-ϝϞںejMoibر3ONZOoٲE*Z; Ezy-^{Żvڶu~3PF6+=(IrI>#l٪>r6࢜ɖ{Xjr>v۾s[n!(eVm|O !{o 5EKB]PS{ ア*Pm¶mےjr\BHꢤuv|I!_3dm.҅\{o !4mݺ= 55u{t!WHn۲E$;BM+{}\.޻8! -[# 9qI!.$6l$޻ą 5XqMI{&CMn˖KBN9lL\WBMRpmݺ(y8P-E%q7FE}n/#m_~衇"ij-m6E$IꍉlRN6XSoǍ͵m$"I 2\E`ڴ꼥;ozy?gxիf6ųNklk9iʴmZ]<ն,}y͝{ZCuL[6i\C}L"w6Yg#>SVkcMR1ԓO{G:gbB2ʊ:;)L@FH۹g ~q{KO?}[P[[;k-[~i~0o$rQ[;Yck;:RF)gtggv9k'ٜIb9뜋bm;mтGy=hxxxztmsnZGASO?3g\aYԓOO?{;gff͚ug~Feb%.9y)?~is,EȵO=z(iE1ؘb>hႇ~ɟ=3udi3㣣Gqhs)'t Ohqvtt~QF\,X?Y3g&ӊ$7k֜EDm56''/?yq###4w3N9>gGΈUhK/XȠikn裏N=8RCCCSu5JȸΩS:m:::F}`95MSgΙ7wgmdND\dŜs9G93]͘9عᡡSb>Jrf=cF}XHE]d;:($3CCs>}^Ǭ&.tΘqqEC3ψ#':9^4<<(23QA"544ҀNiSm6w^]˔(\0iuƺuN688[7<4nb[PvDI,Fς6g~OϞnKi |yciKBY+"qk{{Do_}Vt)׮S ZV===Ko&E|ٲDD  q`?k.!9" l钞"\b巾񭁾~po+W+ͻG|W˻J[oyk֬{ x$ADc&O"Av5}{q=*,L@(Kz_^ۧ'2>9QC|;.Dܷ-@B YkHHwy;n`oftbdlb!) /]=of,{]r9@еto{wg4"˗(C+I%{zV,]TtXtٞ==w߾h===>7zz.]B $%KQ{zz,>ѱeK===/'JVYt{ Ad;(KٳysgQepι}9 aɒ%===coYt tuu"}677,{Ms6@`bbԇ DOK+q&JŠ'*/9{A.j[0,YRUUUUU靷zN~9gu֩~5g4,&'5mRol>!n.g>K.oZ\w_~srQ2^x!v{%\6zezZrEss+֯[s.6Q,"(qZ[k΋/ZXאw =x/je:յve׊K/ZGK/}۶yݺݻ#۷m=sF>͚9gQ;w]4o>K/ƑkvrQ̛7駞wݻ^)$ .x^||n˝g~f.<'wvMzΝEM-BIFEW_}Ν;8ԺBaO>3ڵ?֦Bz>/ڝ;w|Ʌ$hIO=ԶsQ{׮K.Z|^zZ}՛wT[kǒ]<̽۷;E68m2qcrItI>(q$[{hҥu+Vth37ZvŊ}}]tb&\;:g55"q]l+DIsm?w5\K/1mpy__ߪի?{Yn]oo[V.ˌQkeW]C+/(/߰o5--Wuʙu.;{hEWb6v\Y[߰|ٲk/2[wUWwҵp]Ι+V_r.)[w M˖/jj_~Eo˗57tXkuo]|yfŊ4ƍzZk}%6l]յrJkg賓җwŊƆ+֮(fK{ZjUcC}ײe]P}!5wll bim6FkkRVkQqZ8eejKÇ+၁|C;iG?w"[enW8i_bmV~?eJ{獉@}}}?2+}{mm-qbgo~TȈHd#mdl/~[n1Ƹ8VH[F|/ʯD"8rqP`љ\FGVkG[W q˗;'xEYsoo)YKo4}/~BM.EΚ[n]xӍu|!DqtNֿ/ID6v77t}k27wbg?nm H緼']44X} 7M7^w#B]˴oXg8JwpQżod{z.QLr˿;ntNG|Kd_&tU_|^kҤ}ݳ:[Vqryw*GQkqJTeIi3fFKbYgu$qΚ8Whh3^x߻cü֪V->7wΪAx#4qRf$硞֜n;>uώ}߯% VR\֒pdM[kđ?`&IkR_ > "@% !&!FCD! 5& zm Gi@Q h{ XD)-  ϒz1O2@"D D@~4@ QP`r"<)dfaњ&3A((B֧^X{o# !%, 0!AD!(,q6TgbMM}Òe8QkmZ)#63,@(@0B%c! VD JK` ^23j#"(e1sq,L~"bA@aYD+TJ@%Sg4p@eD-흣cc! 3πB ) ix &JuMu50{`d8*EڔA!)@! wI޳O VKVF"B lB@f42Lkt%KIg>SZ)" ZRZ+,QT)WVV4#Nkc5FDE:W = j%fa`Y dYq:  IDAT-F'J@PD)dX!Ba " H3ZB.7>~"H@ ml,rP 2Q+FF}|(JkOF$=UUUUUUU4xp'<(ёa45q]{O[-|.j7{k޴D&"mnhk:IMM- RsYPV&'3FJf>   P PH `BEJ @iD8%dlDaaV!x" A`tl4dAV 9LA"‰4T52+MH(@MY"%H 0Bu` 0gY&3iD I *E,^Zm1i,D$BJA9aSQ "%"́3PC !Kj(Jk $@ePP1#!dB !&"1i5"B$&*p9142rTAʕ,V[0 + Y2ϩ+RI\\Ntt61&VDP+*2D1d`Q.HkBDCI3_)VJ RDD"! ) D"T%ya,ԦPQHfTnnikljffLٳQ5y΄\I}rI BSZM ^HH#xcN>%D.'C`xy3!RD) L"Nk01>@ <B<cHX/=wu8/4Z1_RS@^'Yy!w\lÈU.a_3H'$!!9@"eVڴJJ!XLTY" D)R,h48 AYX&ff>So5QXzZkeTAPH3APGQ|,3JT!2V(DB`V4 {mmZɌR(>$MqB (3Q:@  3 @ BJc!xgm)A)x!B, 0V3@M''/lV~ X] f`TAP@ $$0)ം"Y:ѤBƈ))RY'a DHy`6~?B* No˂úFۦ<4VB͑Nt^{ӋO˂b> F+aGYZI0X8#C@aN@DB$B G  Fp I @D (Ze5!6q9-# )2iB (BD쁁 xLe[$C<"&J!"82=g!%(E92f2 H"ŀ+cA@ 0JPHd"9D2DTJaP;>:K  8 ^PI+e# "@(A> Be (dADBcmC jG*|rPNSD2ԤXRiB{JI` @{46ZΘӡRaP( ZC$WBEHIe{MN[H@2&e2 }Z) YyűR9K0 Y>W@4#c叇#!!2GiDE8 PtR,L"V&2B!( @9h adD@@rDF)!C'&C(", @J $ P)B@Dh$ k@0` )A*Ѭ]/~bYu4VP2Z|PZ!&JiD yKXV3BIq|d8%`FDd>ϤT@?^GԪ*ʘ$asΖ$L%qUH}4RbJӚjϿnpf rRW$h b`zbtppH<`D:002R,| ^t<[g*>Rd` @ (8a18)(J`  (As$" ) (f_6:@Lf >R$zƖ2J\@ LN\DpPLs&ZDƥ>U$`KWB5 1s&, Y Ї,&caq5>"X(0H ($fAPbBHG"Bр,((, !V AP3LZZ}1iV!b)i4TB@)0`BŢ$xHS"29e]^ȍG)D0Q1@!P"^i/,M ~r%V 6:deDp@Ȑ欮..ZԤġz ĠLkk]>+LR.W(qL%C .J} yhku6 5׎B%"A@ "+2Ƞ(I}&2y81i@8pZ"mHJ^XAˊ4  XWP+\s}48l"`)\RƘ2.O@H:B! dHki R,lY=6΁)I`T:;gj8e%T ɺBT?UUUUUUU'_%Íb"NLi VdžTJXi"фDP@hQQ  @a$%(D@ 35"J)Y4 ",H 0!1  UWƵ˙DM("HY(AT@AR.NNҠ3h# ($OVW80 aP̜"@D%$qΎ(łJ+Q0(veQD0^!aD4g,84="`!@fFV,%A#@`!"RDH`!(t` e``C(c XD2ԊAB @'@*Z@X j$NTA Ч^[X{FЇ,&7FE@@}C&Sۛя>2f lR9,5(c="'Q)N\Q/qps9JS?@3[gHU%S@2@̢Ό L:ÀJT&Sҁ=)%!JYk%"D\<1Q h>ar'#R Q?p`?>HRʘ(WS\Y8:8<ёAQ$dO+?{ @D@$!` Z=eA!A 6+!R%e\j|D9VUUUUUU ذt܏27tl|]Tt4v̇ ?1QR44;v"R+nov|h'|b鲥`?#G>8rǯ]_Z.WPc4i%-9 ^SfYR)ާ>RSmz;zQ::{ߛ(ܻwl޴_FO+7_EBVidYryU ~期>ȡ;_wE>l={zFݷkXHwG7(@tϖ{xtCIQXµ]{'N\s-N \w͵o'F{u"뮿n&|kߕW]"Hn;26ׯC /Ϟٱ6onxG|k\5^}o;::o߾kEA9::[{jݻoۿ}͛gE扑oy+`NPY% >>8B ZU*RiViVnڷ~D9}w6_}U(}]{ DZ)Jxiw g;硇9;plp7ݕOf̘qݿT>s:O?p|7w'yf9g=Ѓ7:6߼j9os<Y~|}|՟93>h#C{zz6#iGJZIr94K'ʨ"LSfTd>i" /8dV*2YF=I}@ ?fno[=;:ZZ7[)QmkM{ی935N-\qV󔆤~V}ujkkgԓ>m _蟟x⑇YpAkkmO/˝q+6nYΚu{XG9gLl8gQ"H"dTb$_n-sgɌӷlg׮\2wά[65_gk_|Zq]zi1$YcDYؚXW_rf4Ν3{=|֯_߿rՊիV \v]3O?hB;k];wmg˂ٳkr3flٲu׮nce/[bUKӔ5+/_{EZu_|ecC󪕫]rVjݺu}+V5L_n]Ն/_qʮK.Yk|kVinlZr%_<ϱqk/^/5u^fE6YnzW77^f```ݺKح[Ŋu^=?pEk˭[o殮.xm!8g\d3Z$'"̎HZi}eV(WXv}_)֬_w%6"ҐqNFTZ+6ָ(Ei_p_j{WnSN9sޚU~;"-Ztȑ 3<ƱyWz3j[pm=#gvG|os]symp/|97.;O#ԓO>rȷSNZX_Sg=dW_ٴyӌ9sr9sfor/>zyG]w͝;7+v;v:夅|Sg}jǎr~ V_pɧ̛?{}^ s=yIGϝ7?J~> E:c E:IlNkc5r.JʼnuqGNX#cmkk;)Cqζ4շ孅yKUUUUUw9uܹ3L:Xlij4cZ)S;[g6\8k93jڦMs,lrZOuviolX0cڴZ711bvZ2ml|>ikڵN)JDđ6"bEm5"s.oXE\l|48k$2-?OW.q)guYmSʫWnRW.ś7]ٽkWu\"qֆƖbb[KKRݻ7^9+$7_սiGuv0ifΘꫯjc'/-rqttݽ+,\]R\߲yUݱ/}ƫ.kbotnݻ7\љ(gF7_;ݛ6^av䚫6weٽ 6DF睽jӦ]v޽~1V+}ƻwr|bk6orWwwWmwUSL蚫v޽ WXeq6^ٽ/nb&rqd6];ˋ191\\T(EhWsqF ޽ኍF1vMݻvE޽{ƍXb iӕݻvi"hduu:"?~;'FC&vQl\T)6͝T*EZ?c~&ըZgum%+r MSN>r\HO;ښ͝ui>}gs9guN=s-3Z̚Q.k?=؝wG.Eu\m1'\.6u&QcvuV[d YcQL&M-R)?O_]Jkm)ֺBEE-RIY}iMdu>Eq\,GsFg\jii~66VhR"L⢨PLgrFdZ)mZ/"[m6Z=9BQOڦNm:XwQ\6Q]R(VUUUUUUM0Y9 =gP 0ԅ ΝCb6z&/W'I6w߽矿9P 00#N>nC B B@0y~_ɘٻ躎*a{ιfɓ$K[e;=%!=MMC@p&n^ t8q~/ıle;iزCH؉'َ-K,sP{cҺT:֪}Nծ瞻SM\4X~=)lٲgDFϞ:}zWv糤;zzz1I)PQ)V+j-:k/_p_DDߖ-= z{a!aׯ76*O~=gi?g1 Gώn=g+;wlkmikAmD m}}={ = l!ƭHOOϋ/Y{ҷu~O/X`D4{m-={Q ,x/mAOO$sfwRN-#L===;`噷l2'.\Z j}[͟"L^W JΎRH!e,ٲu+0(ay'煭[A }[ar?fS֊Q>H 3?ˠ̒%KΎ5r̾/g]P*,0eJ]^x/]dlbb^{>!M IDATѐӦ~ӟ,Ylb|/rjxx竿(\VWWOZ?+_[nE/ҳcz~_f38c314lWuVԸd҉bq+;Ϟ?dsY@ vfoٶ ud/3g۷\ATVM6km۶%K4}y'ʼnbqi=oВ%KFϞٿ~+_2ym,Xg8Qb|D"m8V/Jd2:`m2P)x(?Joֿ},ϚHeM9c6PbVZ+{Uy普9L~E?ܴ)MȚڟy uuZBes.~dժLwڄ+f>n]l6w:!TDYܚUkjՙ8PYVZGY5&3fՑ q{(eVgb}U!BgrF+Wq\˄U6ήZ*B>rBE><*eL"罏Bsk{Ufy}6]Q~l!;zxV68 !LhZVL8kVq]?C:mg~Sr7Ϲhsϟ_QQپWӨ3)o4M~xMRم?~oO?2}zGߔ曗/Yry~i5Us{nÆkd檆]3l{釛,ZTgWZi*QMx΢s* 9s:ׯvժZ#Gͳ꛼7mZ3?uv^?9Ⱥ߭W3EN{{΢s_ᇿc4gSL7.\(Λ۽~s\/TKo?QdqMiR`brMfg\lldՓɤ޿tn9n)+++++kw.u^S%]shjn8}V{]cj~VUQlVWlk3sǮSęl,"19W*#\&TVTSO?3Z3[Қ!4i]EU,o>}H =gs֖$RCCCMؚӃCCm-LFupUvhhezc.3.>=8h O1#rZgtzp03q`PS g&`.ㆆ6:m|2L&33f6 576Zm#)3h)666>} "9gFQdMgMj y igLd@)PCCÍӚbG)Z[O6O?s̟,]Zǹ(r6558;ctdV!2hJ'ޙ3{*g#\"y=3Ϯ.nki8GĉFYZkL&~zϺ fc؎֦XWQVVLU6s<h{gFƖ'NXrm6)dg?nݳ>knim+kfǏqerNȘ|6=駟zvQ U+*r|ĉDFjeQnnלuO<~\vxx"MiǵQYb岹\gkᑶ[cRjiOJUr\&~'3pSS3jM͍-Ǐ3qQ&3JeD%"J)tO.+k\^[cJ9Qd3Z)l>(E!2Z)E)o:YVVVVVGKܨЄ>1tf" 9;RɪfE9U͙k4]q_p*.9yrx8EjDDտkgo/\#4Io| \uU",("  &JwN 8q`A1˗_o|4Gʃ,_<$e뮿N|[1Hf޽/ԳeKw3^ATLh۷oݟUW]P޽. ̀.&K_tW98۲E-__;z<|r\%]¨3/]x~f߽K. ij ^zY?)ܳ{E/ugFν~eK i/Y{eK/[̀.[/2@ AŋwL/RT z%}H޽˒4^dŻIxwK.[QIdK.۳{w_rçOp|=L ]!0(m؋O@XYBF]K,  Fŗ^_ƢsO0jJh2y"Ԛ$*o{,(R&& +4}Wك@9 hd ,߼+C_ݳGkD HQRo|K~I@ibBGDTBcݕW^y_OJYR 9x"R7JI3:;::f7MED"T@$ywW髯f*>xBDT"AJ>9s_X+if/!M9  ((@$)! NuW]H{J6e&'!tȸb$Q` @@Ф@¥qh4fRD44M @JZÖ[(Z .s^eP63rZGuyM5S;۪Ιy>musfNZrim"k^ضxcWGg.5?9ꫯk ]]֭[6Q2"u.~aZ\rَ;O__eldժ}[,ٝGYqtjjhXx~:t55/7^3ZZDZD}a^}m]ݔ|żyk׮}a ?:x%K*+,]v믽ސ{,* s:g?ǎu͙~֬~#ɶ^z˖QW\Q]SlɒÇ_͵Fn˃.^+<|h~K4\yLpMo}pٲ˫j.]vС`݇W,[^S]|C]{Ցu7^w/[V]Se\wM+jjO뮻!vѭ/[]|CnZ nz/|9|p憛nx-vo / XiksZ;"bLh7p.[jj*?W}+]Y__gÇ]HU>G63quQlnǎkw)ҚѦosߵ]PWEXvmZ|#}}{zUTfZ5kWr^_|1e͛z-;os=裏VlLR[Shގ?׷澅_7g}GB_ߖ뮽aʔi\n}|mq.Og޼B.3gN}8r}}]k_m۶Ș?mW_z^}m_ߖGy7o|5R__ss_m[SW sY>5ko뮭.ݜs= >O=BkgY&okaJ6_1o׮ݶm1֏|7wyӦs=#q&8gmE8(QrJSe)ScX rZc.2\e6g\.dQ\d"o*-eeeeeex sYW|eմuӦTΨejWeŅ3Zg/<{asKgS-MM 3o_3cO'?ܴixxxbb+)S2Z_lY{}ߨkV(d]6 ]_?/r(/ ϭ?qxT:zȓO<1sF&l=Ή4M_}[([['?u`$I;([VUˮݸqxdd|||߾}7Gߟ$o(_wс=.[3|ɣGJG>3(f>;|cehw睟|ןqǭ2s|w{l(M=X6ym?yͿvVu7NfL>9p?Ӥc>qf$ow@F?s$Iؿ_;{N6(;D._&"mqkcuTD:RFDb"m3.",)R'z;>fFXǟnj2q"2>2Fkq.X"~'(qvْe6lƴ)Ӵڻ>wd;>|[z"k^|نoo~sԩ sz^GU_SW\qcd769sqg?$I:CVMi|5'G~~mM&СCַjk(Z7^SW9u+<ǟx≚*mԲ~{?zmM|3y(#K~}yhiu?_zh\lqoou9 ]m=TSSebXDDʆƶEs/rN+5NG2.Q&3LA Zs|e>K/]9ݵS^;c'`Agb2!H]fxNGl)%bbL&#K]ħ.%eAP)gmR*  (mE Hg RZ|it464aue%Ť聕Bf &#"H @`@@%zVJi,Bմ)3RΉc4·ٓ"AE"ZIV*,Q!&DH[#āYB@@ցED5!pJgQ8JېF  q`T:e kI)  i DX!Ja) ",BFY 4fENi@D"DI`PJ"Mc%@!(  P&IԧHiAB\&$E@$,8$Bz$EI}J)D0Kx`FETHEDi2trG{ 4յu޷WTr.z 0 is>b|H=6qVg3YRHK M+A0*$@{P<ʐ>u|9x&0'TH, I<"b"RLBrY |DA`Vi4 N P 1 )R轇@_!xvQ U6X9*iӖ"`L`)(WNδm{TYEkiRGVj<_)?WK_񑊚*5OC266{D"A+%>"$$E@,I=# * 5YJ"X Mf/@!`3!2ZHJޣ(aT@D"d#7"1H[p@*HPVzOJ 0d$Ѥ>IY3B2  D8M"$H R$ " E4YcJD)¨3 A! Z d Ї=',"F! "#x? IF8)aC iR"JBLHJ!&  HLHBdE9"h"RJI]眛(U5gΜI H` +E^HZ)`e8V4^*?>vrhQR4(mI 0m!dT"!Zg3gї5 5gF$uXfFVH'#A5i}V":0xRcc'/HnR9!x`&MҠ"R$"L~t6 H+IDgRHkC&E+Ț*<9B%DafJ#03 " "!B 4V+I ""T 1%B@JČ4^D.\JR@P #A |]GHSNR8E@R%%B4 ֑reLK8'N4ffI9^4i@٧RRZ:u(BIe,*'IlOJlҁEڈ\!ⅇGGƋcS e >OE8(DN0H8" R$5UUq&&a R]QetViJ)9"5ʠFKGs2!9+&퐤b@&g53EJBQ(*,,=+l&ֆ$M=$iBFYBAk `ERJ) !ME HJJkD@M$C`R:g"9Lp8ejczTG~rqž756*:djgt;80z0LrN?0;dttrI,D 8R[` A !F CAP [*V "-)ϢR: >I(>>I0BF@ DprN&4B2,> 4$Xh9(M3" " $|ĀV[#hIyrR̴) Sj 9K猱264 IDAT/$2 UQ$)'(K ,,@Aa({Bl&̤ &mQ!K|WC dr@ޝOETJ<"LX AўDPq'^|z]ÔF44) X|P@ Q!t% +Te # xTDP84Q$$04MA cD b=2KY=ur  D10#[&" gPAi ZR SY*c5eB6O!(`sD2eڌi ӚgS[%VJiRABTs$ )Fd4P,$"!i=XYDőqDXPӤI+F :"$ ࢸzj}BYDQXPp @H'!VJ u}@dM r,X ʊ093ptl&6LL\/-++++++qfd7v5`*8><^ؽ;x%(fNUQmiuSXT F+ׄȬj 33sg&Ш4"! i "j "j0J[R>I'T0**$ED/y D< ( ̞S8 $`@Gazc#B-"0 )Jp$BŀTJ!M JX]YS)"KB`R$ J!&M@4њ'=҉*C!h">;1 >@! g¢% earҔ:u"̩@ +i JR 0!%@ 02rFBA 2Zi'NL8z_4@|a Y$e7d.`hmDFTZQ>FeHkEƒ ҄@I#ҔSbȋ$>吂O &TLJO3B,t6rTJh28*xC,iROj(Ց/C@ʧB"N0Hʉ"&a┵@!lRň$i D?hhS`I@ "JROTD*5KAX @T1MV}BPAj5ys*P   KPZ d"4=vlH4*F(*(UXq)RAF$H"4=E t < L>lO= 3 @ !jF$ A"fBT(^ ^@'֡O+)!r`I0 *ֳx 0amOh8"S ps#R 2*I PRI؟9N/PSŒH2::Js *pF(A| %R(DB8 (f ) FEijh8=xڇԪw0x%!(A(i( H,te]&%bIP(baJ1XЕ ǎIq( !VJ+*Q=z 41Q?N~xl;V?;6vLqHmuV~k߁G|c>iS'if#}ЁΜyeW!Twٳgb|Wz[nA3ciixt%]:z؉_q.@_{^3tl/u-1D!rof7! iPHUU5}hxdС^*ww=p_y #Oli{u/grYn##C{V HD mkÇGx?xĉ{r\Zۚ{l93_' 9>Q/&ѤT(N`s|zw~=_B>G$"5xs+g tŗ=飇wyYCuܿo_eK8]/y붭_?K/} wgs$IqZÔ<竿O/pSO=ց'ye?)DjjiG}}ϙ>ŗ^'9284ʮ+1@W[k|w/A['ױ'O 3Y"gu>9}jΝIK/yrݓG=58+;ͭZIֶG[ޞ߳{?AՒK'99<|8UFUUU|ѱ3w~!mpi0B@D<[RVRbHT, tKsl.՛z{#YYX?뮻^|qLJoyf>_hkk]ލ.nÇ]u5+_~kh}o5gZZW^qcoDžڪک.S֒V?Oss;x>Xff\rcooyG]žƨ;zm-mgYjUooB900wsmپ}Gn#fu?Gz7ή/wܮL&`т 6D6nޚgnڴ) ,8~YsUoqۭϜTնf͚6vvw ]] Uwƍl}[o%ɷ\wc1c``K>=;+wy|~ǎѿ.VzWu{ YqcѴcǎ򡦦\vV۬Տ[<0sVJ%Ϳ'#XMbD&lll(J ԧ>"R($|oW% R)R?窫m&2I. 6.Js'?Ic4hqĉ&VGsJRDu5$w54I8bm26mR]dX+D^|={X61Ѭ պT*55|}]SMlС |>"։2Z;ZKR]\*R:ؚ\djldcKQ٫NJN"G6#ThKJttJ%m=>kkmGXbcLd|%&lg{GTg>B.VGR6ƨ(1ZS[[[TB\ɫ6DL8őKLڞ?82m,*HEFYcsmͥR Wi *k&() M? 6hENR(m5&6X,*Zqd"kؘh)cTf69mr6VJ+k\b1Fb֚B"BNϥ=1ӆ&=ig.M+42Hm-49{wS]i"5"dw6ݱzչ Aid!…  8  2@<ۉO?xοBi%y~==s̎;P[{)dH1- bX|#Z* /NJ wXYC$@>f~]?22WXӟ# O/"@_>~s2vnN_/wuv}ݾ}G&@\HG ёի&'{ })c$2d)s{?Es]533󫧞:===v5F$ (&j^HRyӛ435)ǎ!;|JZD6^s#jU3;kV0~%|I9'szk "W.ΖrW?k D޾%/8眿_;"zA 䆙V@Ro ϑ0<<}|J+@F18^UVMNM'N8tK^$IuOG y]{޽ hr屧<5yСC_5q#&bGLRzy^wsWy/&d[U,>ē>璼865#{3^=[}''=tjcH3{ܒK\yB4s@4dբAkS=P¢J>qN{ˊs{tZ_k剑?w6|Gk-8{ⷝsNo}μu9]M sZoybcklk[u^O\X_EYXСC]ZMXEQ&Vbck::;ēO~sG<_45˲&%Dl .6*|9bmX6"eFk<ѕS{__(޸6t.sFFw߽c`>;_5q>ilLÇuuv*sx`psh`pǎnhVWov9|pOHYC\yƙu;vx뭑4kTءNs>rM-ˆW?M65j&r=Cg<>߸h`m6mlX[hkIl{]g\048cǎ7l{3/5'N\.1*TܵRV\^N:;ڭa}>3nu"DZsjH[m)čms.KBo;o>~Rsڵr\ahjBSRh/:Gzܮ]xٽ;~xX#YήjkٵkYŋn߾֍I.zm.msnCV>>hHXf8[4h-۷ݛ=Fk82fN'Oll5FٺEmٲe۽jc+Y5q.yQl jd[n߶(591bpag."?~"_Kl޶s05vϟ׿6VkQ74 /]-[ݻ;11?hml?~\)FVkI>7|x֭nWGvbrb|kY+hN'N(&1ڨ8I-Ye{mhc=s{8:P^6u{mNLLiŖ)g'N/Ym5ĉj2u7t?ןiHru_WߖO|LV̊PqlQDrsm16EKkyKMMMMM_<g[x9Cu6 ΋\K{Wn7ӹ+/jl, .36}[klMdZUG]SSS Q+mIiVY,5$"дrh 7Ĭs6NXm߿ԩ\.ikojk~?mm56RF)=::}ƉL\z={=D q>QjkD:&6l,QlG~"kK/ڞjWWgm<;;љeHD:h EID]bG9m꒸k||<'1*kmud:;b?lyQd8=wނ'N(uU*őmbQhK-Qtwg tlmYmtbh޿ŅFVf^Hi&lll.Wh6h+8sV3>>Ņ(3g^߼8tvEBVz뷿oe|EXme;:Kb!FGF.E(ju.ڳgfYesQXkjon.)Z}뭷~H"$Fi2DZ!t.:;:bS}??ן=`Rw'l3Fnqήbx#\LV\i M]mb#?[ĊMOo߉'&icmmbQ[# Ϗ8/\p||\6:VV#,kY,g?qYkLdzO0Xe|F+bhm#{b1󼞾z <3Wmmlmo) h#̝ۧ$vwue,8:ڛcƶb~?\86e9='Nh&pppG}; A+HҊ4J_O}53RĬVQl|GZ䈍ammuCS#򖚚J>&m{l_ַ4u .|9u,]p^!3sKoyl#jdtw`@c~h`o?nll޻guAGGgCCe[{1$1Y-"m+7+j.=Ɩ7ٍ_Yxto_j9gss6mmddXxЋ/a'/ymg{y577_x矬tcFDH\D&޳{υ^Pbһڼoh=쳫VrW J]կ~Mio߾Mmo luȈbgw=sz[xhGGGcc.|?|xEClh;7vagx׻Zr˖u]E5k~˗46/[|玝~5j/x׻;Zdhphw+?t={<󬆺ŋرcӦMLj|׾k޽gŲ3 ŋwywhww>ɭX6|]w?be ;wtwݳgn_qxx#(oY|^jkiKl(cR}/hokd͛77}sW66j ?({]lkhj\x;7:Y-]rVl6F3{ww8Z|w&rݚݳ쳚Eo߱iӦ={vhoKrK6o޼o߾Xٳg˗5 ˆܱswݳ .lm먫k:cwm<::lm.;wn}iܽg.5/YͣV^qYuuK߹o"g 󞎎|~;<:O^v?<}(Fhg-?K/-Zd2[c5|X1&47FŊ)QV!k$C Zl-ot졯|s]tkgAwo[.޷r%g .y=g̟x銞=s&twc׮ƍuv8?11Q,=z7vutjmy\>Z,'&&~_CMv};~xܽeNFZE޿?q"˲/D#3<3nݺw/XT~|ל9FVwLNNVo쎢XO|رci _--F{}nSkc x^xᅯ\b[}Ҟ9=7?_}7IoijjZ:wM7vujo8v|sC}">o[n3W|yOGdž}OrKkSKW[[PGt޴z¡DG=G?QQְ֊8Zz}n쌭>̱cig>~fV{y9uM7bG?l"Dq¬V&''#GnNcaU= Ͽp77嵦s=rMuO|c{yW[\'o>o?1jtSWgR?j כU睷[nYP>}z[VSc|=xcG[GQaßϭVkKc.zoƎNmfUW7Ʀ<vZȚmp3׿^Ԡyyoy'''KѣGnơ% Qc|[ X[?hoz{.8|Pe{]h Y#V5+& 1\.I($V)(ckm==.^Zkjjjjjj?v <'&& Ƙ* I I2ujle- Kۿshj@=R Q\昵޻@`fH( 8] H(D |.IN>fQ BB9@& "[i LU<$|B"LČA"9u @:ij0 % "J ʂ T@@J f@k hj@ H `\VH#""pz֬"'N2" f.(m2OR}BК!T9\p }@$RZ !$Hd1/ B}cGkdcGg>kBڇzV>x*KSPF9D@$x@ {O.t!L\u^1UO#~dB.,8@k%eưB hZgJCI,eD1!j!͜xѬ3pI2^\%J;r05Syw/1KeX{ t!c" 1HD(|k˲8J s^ADPA0x!<iԩlv @ q5+5b_g+^0 x@ AH&eYuC}]>R QӤHq9E |co6z/bFKv5555555Nd$marr6T00QT3K013;>=[vyT03c[_~yRg̥5A=!B@E D"<ɓ'!@ \ZijzbvvZ#feLTI+ p`l<@* Pf $2qA xAAD'!sH 0 z9!8V! 'x'"FiO,B@|@{G$3«r"X.1BA" (,@/˥ D#Zdeqq:HAsN e^1 T# 蝣 h"C s%VJYVԪRTjJJރ2@tez w. !* B#b] !0& S %P (B D\u4 (FEi㯼 ! Z06+'$Ff}BC@@ ^ d#$EU9ט+̶K61 HHC""A$⁵btpe i5dF煔BD$B A|ZeD043ӓ @DB`֊w!̬TTtfH@z Lq HC$V*|0Ɔ\_ZSSSSSS5ڀֺS*[U%{W8 q@!pf ?~>jCd"fMO/͔8><^""@ xl$aOMM,:u $\Y1B&sU0>He'9  ",8bRGL$CYD+E|E %H{d+(擯4K2&&BrYI)>HX#J ؉H̻ + #bH Y"jEg,@sWfg}ՄDdAw9o!Bq6ʸ̃F]KuAHFiDa&DJ RX[cTD3'!A\$T""DqWG 9/B Y,c <+$F >AHb>xgIwuujb@ TX+bN2P^$H(">s VVx!&/!u H""bs_]Z„(&H! "L(D D ށxHĕ+8&l@tDLga,K(Z$!,M+C! +Q#3*Ml!x >x紱ZE,ޣϼ0O,MJ@;E$|D T]V)qN$ a%3&U$TΪk)B }!LMOw{@ʜdY沴\LeT}a^r6 !JBDՉͬ2+ Z)$2IHMLMҚ?H7xRX艰0[9UnL'e7ݷl{T ;HCTҲs)9]ld+4K3Zxzj*BJŇ@LL!0!dGL]DrkQ|K[!Of rru-@6 J($A@Be}a#1"" AhfB$B23=KLHI`DD48H+N4WSň %$s" HL}B=*Fԥ3?ui@)ıCEi%/( @DDS@@$ VƉ$C;oIy).$r H>Uf&jhldrif!12Pe$ (0dBEXۀX)Oѹ \J)P W{<5i,33!&"@Xv"a&E; (&Ѭ+3EG( XV*d92H!s@D&!JVg+LbSD|\x˲L<8Js{LȇI4d@H +$ `NHR ^@d2!s>&ui PȈ(R+&BkU99)\.QSb֌!(-lqE)-N@@ #pA+ S.e"J]΋" ! @F) t>TwbϊAw4Q ($ PqD IDATRlEye 1Ѭ;A d**HW!SJ@$ g!8!. Y0T\LJ~vvf6-g&&fNM|UR`rB H輯.! SUeA<"T-E|HQ . d.#Y z$q|ٓЧ营;O쳌X{W#ag KӗO y }`D"%DL1-E>uDD@(^<*cIBUN{Ԛ?qS'}uf'|B~j'Y1ĥʳ955~uK2 |rRTJ_R7}Ǐ>ur'ERk׮{jlzbSO^v{Tdffe+̱GnV|_yG̷ykkC3@ࡧř.Cm]-}UO-uH)W^gcGY%xx5|r8{5kJ180vhf<6vhͺ+l.>=vx\zK.[+Ye}Ƀr=l?.V=}G>;db2>Ϗ=ؑ\fR b#c'w]tqq&+NN,fi\,f+bV)#>Le6*Lࡲn凞>P>֬/RJIeO;<]*>|hݺKRӴRri)M3l\.gYYfT4R){4[O);̈a>4[=0v`Xk<26U}+% ~O?yK.!km'7ˁMMrte)jQt<2vtbӇ.dj::3]<2vWFR._{ő_ŗ|Y+'|rrz/R Қ5k|⩙]]Nxu\FY:469=yȡ+"Â֯;phlrj"Ok׬;8699up]xW^vთ]|Iu2+}ADT(dއ ȱ$  "D$b\vKMMMMM_;wa;:Dmg龸\ )jdk,BQv7@E#%N23Y=fͫI%H)qq+O28&@;(/<R,.X9LrCW}N|}Qkv޲'i䆭]CHw#{v޻g7Vv>O>ckH>|ה:۶Z8q]rڵ#|3Z猪:k3t{$.3ٳO912釿zU{v-//{ծMGG|+_ɭ?vd|d_ɉɕS֪c2o7'Yl]> BfvvZ29sC+++wxʐ/wuJ河gN?|{::w#Yojur[MT3G~_|񖉉͛6MM=s#jСONZLvTC}ݛ&&V+Sٙj:9>}-+++Gf>?v񱱞ɱɕjuzjsxfZt^x}7̛rdoWVVgfggWCmٲCVVVOO[T%1}/6"FUռT.7FDY,iݟkll{rrree;uJDF$s3XU%6r㼳ְ1B<{HZ뛘VSOYX_oϡ[Ffgf'&'z6MNNLOM9,W'''NNTO神Sŗ^}wڻι9Q;qٳses3w.7ø5?7g;z&s=:9wvl~~;[{=o7:z̋5ޙ'={ٹssTʍ1Ǐ8{v[zn&\n2XA41G$1l ?~ٯub?7ο~_7Msdcǜˬ˲,?~Ν+esws֝:;v\gw?8#]:=zd'Ξ=kN2w3;~sTʝ5rgѣGX'b9~sgsssG5VŰ}\wa$9q9#rnɻ);<6wvND;ʆيX>vsg8&!;nSO{5B[O>7^M:'"y>\]q86v -mmmmmm?~rakz|kvnޱw뎁mx-C[oYّFJ'nտmpÃ#^w}铏>'/+gNmqά#7Ί5f>zޏ|#_7Y:͜Sg"b󬳯WU_|f+_wXc~CCÙvˋ/=ƈ7;\\Ů#Cgְ j5CɜͭQNwbZW]s6vשֲּׂsΪX}[[rEz󵵵1yɺ@Wj3684 u57ܴZ[WRܺϭfVLfafey6Hy^fx1ÕZϝpVsJ}!jZRVpeV]k.^ޮpmuY^neD{dj^쵥WT*ZYshWȇVWWz>cPVz>X16|jֻZ}:eZRq@YeRլz^XgFdRYպ;zcЉcݞWWkھ}G+5Xjȫl+ܵkZ8'd쩧_L&˼0yk;Ky9wO=_Y1"Q2P1XBoZ}c΁bw6s.Yлus{S'l~]n|Ύ8eooxˁ=r nQ)wvٵ^wõvm۽cx5Ɠ>}nO>Yۓw=S[#ĻLUs9rww[ooenww[7fEݿE\,޺Fc\șGNJ;reU5Ί>˝sOܱmc;K&Ϝqvu5?[[~ܼ$.==9Sr6K<'>=;})ЙbRgySK!cT]GcW+X.u[6gNvFJ> !81͛v{˖Bɸc)0ƞymۆcaŝiCY* g1r^r֞9s8Q!xcb]]e#;wKBϱYnwޝgNqYgAbn16RgQNL;Ӗ+18=lHy9`Ib̻3?;[Z?1λO?,,|cYя|un !Xkcy<;}s+P}wSO}< !t|q.+?|6!k%9sukSWZc,wușG1tupR9+uyLkLq{ogsrIc2oyicLW3e.X{ib*`ӧ3]B9c}GyddxJɭq߯| _(1eg9o]ɻ_ AֹRV.1eN,K98؈q&s63i3;-mmmmmm?~rᦫ-#[TTްogӶ--;l=PضC;w _uΫ?ce{k˳ox'>??Ϭ*2yV?eX:眳ވv8X=}~5={y_g̿^wkR)wFuBưYڹkǎʵW_wמ=CC%HfL9yƸVa;kc؟ٟc832Z9Rֱ{d?/~Z3O_{wvyG>_?٬CC8g3v2Z_}g2ꌫ;[[Y7z_nKܹܹ/]ݍz=wZ^82gvjeq…7M{m2c[X:+{VkNl+.g`+JkkPz>88]T'>{FFZ^U1";wjZ2սYL֌3`ň1,pEPeV3"zRJ/.vjFh^\VݼupVZeZՔknuu{Ywlw8gddj&3&3fxZbve+uvY[CĴ_~ϼ$$&wRc`_]z_*Wm޵kY1VXelϺ65Bh3Yo(4?N嚽6/5j&qǀKWo~5ۺtu]w/Ψ k 6}d Ĥ1+2>>T)*B 7_rVb%JBQ1D@PmM$|w_|Pϯx_S"XŅ޼/&EO L1$ E&&bR"F`Q<_C)b7u%(BlsݷoNLNR5%>oO}4/<>o9fX߸|`lGŅ_\X /߿RbF7_a}DS׿`890>% A$MGAuaaa)aRJO/QSƉFGGP񅅛V`']\\ ("X\Nط&-MP_\\Ņ̈́j:7|3(ĔbJoݷTŅܼXHF_\\uQat1扅śݜ߼aqGB`[xbM)*߷qaQ,,,=͍W^Yݷ8`\Xxo}17 #HHLDOL!EAୋO$ozS )D}=?S!$ev O/sf~~.ffzziiiM'&÷M,=zM=S%k]ZZ<>6^V+q|ii}c92341~k؁juyzjȼ IDAT /{GVO|vs-vNVoĵ;::gxZ9f[^Zu`wg#373Ӈ&&n41>^VobT5˼{oD ϲg%uHw./W56~ZKʝGciii|lXZv!M{kmVʍ3,YUslz2dfffii޾[4Yznit[nVSS#w.--MLNLNL,//qd&̽'iiiitzq=:tjzxjYfggOWӷM9233-=7~@cjufz:ıcK-MNUۧsiii|||Ӧ6s3KKK'{'&Ǘ˷MM̑饥l<|xj:~juy1<3;scF{z[~xz[9v奥'gL/-=CGw:yZ=j2ws=˭?Wu.s^zws#饗l7I , ٻ̚w̄LxPq;ށO.ܸkāf7W>{/{^C}W q5 *k+#7쾦rǼڟ{۾/\pa}};çlݶ쳷M>w…+W<3{qۖm5աٙۿrʅc5C^xF205lj>~EQ|[:v]y+:|<S6B_Λsl>vʕgm6N}g=uuf^O}jR|c{F|dp`e2,_Ay;yʉ˲z?LkCW2ԕ̻z:g=8.3s??yחxZ_ryϼݷsSf=##{ripf8|fCeְйya6Ϝ?{aʖ6^lelT糎޾-b3{c3y{NY#v8ƻ~X_'=; gWgXkϞ甠Xc3=3KHHc4XP5(hJ"[Q VbJ?>&+kxq{ox?NO_>6+()tv\ji}y"!aH)!]. LQ1FA$SHC L,B:Lq"!@4, (HIccJRh@CJ ( @#*œB2DRJ)1* & Z@ A AcJD1HF @jʆj *uY~,R PPf@PbJQXB b$iJ!%IJHLGҢ"1h h < Ač(06CC4)&@p+PUR(z!,Φ4*$UfH-.v5׍H)&#B FC .7BH!4BV"#&` DhI#pPaSDh4AQGi^(J,Ę,1 d,&E2H1Ɛ"!!+ 4M4b 9Ĉ"XPRU@"PDbTS$El+D))1[X,2P@Lc )! bRDĤ H}==.˾ZV33ICJȮ_^A j-w֯\)60&%)̠l4sB#BSv7@!hRf!^p)&¤)!8f77f,˚F chF$PA@fo-^ܸb1 0s @1'#BEM_ܿ'Փm lILº|?'_[^Ѩ7.u6\.n4$&T$b Q"D%H )15Rl &DD [cb,TUA7\ֽ8@@zHJ 4#&L1c D@Pì PCHl SB&Eh633 8GJ H,Ƅ )FcDbDXL bRDDaJ(ƨUSHIY@lDb(b,Ch:'L)P4C )([cD21+ #1@/ ՗_~5&H l#2!X`1&ai=QҤLIDWKkd`TfE!2""ŠBSlmBT4lPFf !ւjl6HXIL LP UդLQ#! !*FDBͦjbƔb RDc"""MD "`QRJSPT$ aBP&pbJY9gS+CB1"bH1B 9&kZi @PBmbL+ "_XcS1RJIXB 1"aggW_֘ 4!1EL $S E%RJ Ww'PɲX@ h EIŵr}i[[[[[[ۏWR\.wݓ W6]o/9Pˆ2N(66xS R!$EbLad``[S};F#PSJpQ0"h @$S3@1$0 B`f(I5`1Ɣ3(@f([sP y/^ḎY$DETkW5%LB pi" jLZ4:Jƺ+ btEB ** RR%C6QZ1eĤ$ bJA!(0" bJČH0%%" P@)""KC"FQPTq~:HcBƔ+7P4•+ DLQYTM1&"R$L)eA)DlEbBPPD!"(HL0"bt%%BF˄C"blҫ# *!%b""Sb1bHHQH&$JʖTC5 MhH@0$6 Z͂t%H)D5@)7I5&Bol=B$K ) BCTz)0#"PE,[c "s!47P8)`ѴPdhC!$h|IhE-"6f_Y4FHA9AJjUA4C1 r" 2hdӋ5j!F@&(_7O$ӶFWzq\[[+mW[sF7eW.oJjCRHA y_&4Ę@BD"˗6\C"4hk4 ,,"!2DFFPbRU!8SXbX!iL A_}ubA Z&Z",LD1iWu)_ŵ:"0&MhDEPL(#FP+)hQUTU5Z1b"ByǥW^y #1"QB*$U"J UUe&(Y5:c 4CT1!+@$W&TH1$aFSh6_|E/&&$x5B43[R "Yg HE0Jغ])2QMШFE&%(A!"B G`ETԨ4(E(2c{7態/GUJ,h#enDjTB+61D664FƚM5F(U[LT747U[m&0h)11$T%ӚgDc2F& "6Jn4 521"LSK #2[JD1Ƅ̨Jbd*$iQB#)IhEPTc-:w0`)AJDP41 bL 35bte5fTH1%Lw_?LjM{߻UM.LJiW8n8"mkrcJJ@ *h 1n4 ! DM!H+[zc q4E"L.sI%EE@M[DcԤIQIJ 1" MB̂iXPEP$)j0dQ4R1i+Yu`b EJYHEQ QT E("he7BQEFXgή-۶(@bh1C`)c$2ACLX46@,Eh$!Wc *0hMHVj N1 A6R ! )z5$4Eg)Qf)DU(J4("3E(8&Mؚ\Ģ[TAԢ(@4CR$BPDlu@1%e &2Ҷ%$0,!5JLBF@ MV XSĠ51hR(, H$ԑ͛("iԢ c`UaHЀ5"Z\MHyiKKEy)#!RHIQ@Q!15(@d%␂b+P Ec¤)i3ĨŤ1D_ B"Ԙdrwىd<80ۃR!FbA"W_S甤\Tf!5 "jl3d&HICB"jBPFBڸ?޴imcΣ쪪x}CSjJj@PV"(okˠAJz S%d@Q BTRz޻PYr-W}֪:u9ug3#U@'l,`8*0sMu\~ırѓϡ?4I3s^x#GkyBЙgUwowtR!I~lxtld~<;FXnpᓣ\>?66V?jҥ}[ox鲒1475ܻ}:y~K.D%W_}^=}n W]uĎzw/eQDD S/F|c<WOX!\a,WIx,B\tB\;2/P|ջ_\#Ȑ_拻-v/| I._+8I~,+Kⱱ1vP8'8^CG?Ү]7rS$lmk[} mv)gsr?# ;~]/r-t;nj͍+}oν';瑇:/_)-)y~|n]/^xEܳzC֯[T%+V߿?˽‹'gЪ=ɓ'wo)J(9e{_w‹/G|pÇ:Ү]7tS& mREy]U.[mf_ܚ eۻq6ZTlRBʔg˘D VJ)Z[,^9֖{g-Fwlmi.˖={SOmRR}Ͼs?R]WwK.4I-QVbf-RADQر+njj `{-۸aCY6Zxg>t_PUV;x/=;|k:ܳS[l^xq{K[* [[s-[4;o+&jox^)UwgÇol:}z{Sؾ-lkjm8cɲ6npƴi[z:KRsNY~2gv|~M͑ ڦ,]dCeÇrӭSSڻ~};a禴@-]dC-9[tv3sNYW} hjl(I:w߆  Ç:mVFz/kZt&PсV*m"!BAVJI_K?s;$[|_|fV IDAT\z;K>u3K!h2 #k5(%*xM]mxv…W55A9yՃ+VTvtM;tMnܞS pܕMͭaLio[r^TWw?eJژ93_ر+SA8mz{R]=[ttg23g]/m߾sW^pJKے{l >#7rsGGG:N;^)3۷_paCC m%Klظ!LGӦM;|Эf3O=w);Z1LmS&߳xIooTvSn֮)%̬3{{{رꫮhiφɋ,ް7ҦgrC-Z4yr[YIɬY{{{3oMv/[WH}E7fJf_<ԩs~e֎=ԯ,`]L9n޴k1 (0F+ BAt*RT$(! RV+Ɗ:h.[&L0a„I{^VT^>gzUYu]MSEyMG3zOi_USKm撺_ZӘHJˍa`Zl@XaMFPd36u6d(fՁV 2aTaAMuQ^t*kBicn7ADiD ^eVe {,eBX 1Z|>o׷MYe,\p떭Z~EBkՁ5VTWUV蔱ZZj|>hJB-ELhl` LuMu>7J2VDJm+ QHՔWy+>؍`IaiBZ)BUEe>7>rmDJ(ec)haSSsOOO>WBi1R+/֭[/2TʅWnݲU ZRZ!-I!6]^EY)Mh/`YBs>vuk%ZH)VI BJYSUIoMHjRjB-: Z{nJ)c PV h)&c R(%1DRJR*QU|>c=oߠ l 6F THF+!duMM>??V xR  jQC'"'bI5%q2\^Q^ȉQ3D{\n΍waʳ5wo3ϝ;772K/  y;A2#JQxoߺu+;7sx}v[*݀ QIk֭X7o/:1xWt:dpRZo}k_#u֙G^h>ڞ=QcxBp۶>~yŸ/^ݳۿg-:R44۷m枓ˏ CnVt!xk߁b5z˭Ͽ Q`BR`žy"XpL\$IH$ 0#8h-'6a„ &mꮦl)4噠r鶚r)-NsJy[4A-++^{t6#޽.EVPi+53[e#cZi#?+;Zw瞯*Lǥ%%V BaJk霋@Idb%T*L'IDRP)̑V@(?5a8ٌ6z%FT%I8e)-VRJZWWW=q>UWj5<ٳ:4a$gR=֭Ytɒ Qhn{wӤF%d$z7̜>+*鞺vڥK!TJT[gIdㆍ9-;t^f%ZXeR]]`t$7n=gvyYvjw纵k/^"0V)?}M2I 6Ξ>2[:{ڵK,M!FZJck'KB:2ٌTrҥT:IﯣUjɒ%Ƙ( $1Z?ׂBIqݿ|뗿x$Z JϻgO[k[U$7l9}FI6ݹv%Kh)"]WW#$眙36AJ*>8uuuR$I~qsN)))Ꞻn+V͘qiUdhZmu"1sd]k֬Y 'J&IaYsfeٞ7kQ^{vwv9{v*\v?F &MR$y'̜ kVYdIJ757L)$_|Ovʬ׮]xb3SR6֭]7g( Ϝ:VJRJ-%RKEZ+)h<e+S4eq˄ &L7iϫ&WUVח7T6MiiV53ҨtZٝ466fftji};?qGm_Zs| IZ*!ڞqڇ׬YR 6 0^j՚5ka ʤKَ#H2JFʤMZOzĉΩ.]}ʔT:;}%K֭_o3=ݝQ*PARJ8qhYhxq 037Lj`dRΕ+WY&2fĉƦFM`l&?nh4(X 1zݺu󳞮LjNw޻~:)aN(mZ'4CCfmmdio0F֢4$d:=mʇ֬^`hh(cQB57k҄B]V|'TM mu%QZ IgLWGʕ+׬^mlkmO 0֨~6RHdӺzZjMMVȌ1V V(f6FPhtFGΘ1=2,1F8qIkL;>qDC}}dQ" ǏB2j-IXeJ*MUUHPk"F k׮Yjpp-ZIol"eMԮ+V~ `kKkh#kvǎKRIUV~Bi388ܞZLcK@CkgEMK:ʤ:;W|pOe;ڭ$?V+-IK!KJ]+W>zJ&!P%lniBcAh;{:W=jڵʚ&1A6iki跁TZJ!fiSZjJzZG{с֦a?5U@WgUkW6MQn:T[OB2sXRFAg?٦_w޵o߾?__(]Q`JR)"bJk5Ɔ0n"n0a„ &yuWϤƺIMsϽ]~]3N;9쪪ItΜQMwtL'˞{͹Kva`ڨ ZJTWTυa PJ.l:~XRJk-"=`Ri!{V@%j$2&")}-$PTPI$RQmee.ӂoљ͔twv46=zhxM5\.ӿN?c^um nhj8zT6)-Jhr:H;gϚ]^ q``% LSIEr۷45I)VRɆJ m #4RhrJgoojmZea4PX-5U\. ;6XaKSсVH) h+IVWr(vQ&i```<4R!HHTueH㤆 FkηoxGSLIEE4m6BX%tIy!*0HkT0픹q˄ &L7iϫ67ז4UV6cuΖSNΚZߘ)kT1})N5u֌N?{j[isfi( p۶m^)S:KKJ:'wO>z˖- |6N:uOo{z(,Ud9mm"_lIY>g}wZcm۶dΎΎK.ۺ5ɝֵ׵謳/ K9JK27ӆ*0oDZJIj-RkfO|mR.ߞ;o~EyGο]v#pc[[GiIYg' pO/[v֖%KlٺUJeO}jAMUeIMy`ml^Wo޴iYa*\v}ݯUy /&IuwuX۞\uՕ7o>e0ٹvڥ˖ [7oYšꪒLkŊ/\yՖM̜]RZ=}i޻^͛?ʚL:;gŊ۶m /\yӖYDagڵ˖kLeK.^P]UI~[sSfʦRSN[G3kk'QM`J{եH3y{Ο_]Q~ܹy /3? '?|SL2Vi% IA$!OL:2&m-7S +RY._O Ϟ:Td:^!͛\taMMu*ֳbmB~ʫ6m4{쪪ʞk,[L+y,QԮ3\{â>~a::Yf%F-7/X:twwXmT׿cdzgqV&Yveˤ7ojj2ӧX駷iU6m1cf63opͽ˖Y6o|KjTOO+~ikzMfd2z[e˄lYKLNtvu.m}}_͛6͜1=ž=֭[6odlkyi|+lqi*dut[ޥw0*҂ҶΝ;M`׬Y3cT&~ȑ#ӧO @kN$ ֚hk6Rj"A`B)%2$e„ &L];+[.基)ۦL=Ƈ=}NKkemSm딙s&wO\|ʴ_Z3]ZR][O [|ڪy{{7  r{y]յ (Z]~eٹ3 K7T:mjj_* |]3#qګ_P)H}+_7o/~ɐ>P4 Λw~oo`>{wΪL`׾7||A&'wM{G8޽{W,454\CBСC|pRCs]?48ػ?Vo~덽oGUUMhr{}]i͵^oswGQ]2V H79;}OKKJTw?޽wڪ*#Td?4R'?]wY_WK:t?TTWY03"c(606R tWOp÷RZ(k2WzX,_-Fٯ_(RlRAh ՓW Z]:ۚKϟ{ΆC|~޽wuWm$cSQEwUhGܸahh(˽wwY[SYI^kyj޹`~~r睵AʔW-8Oᄏ<4y|p}rם55aDΟ?~-J%͛a}P.{U5Hķ/8dlHqs{sҤzc7o-~U5Rݸq?h7OwgKJRw/~q|~U[[m ʖ||.)f%2X,:|X=SU^={q|yB7L)eSZ[cҨƄAdkJm 6;go&L0a„yuׂ_}ii*egfl]\HAjXa\p{dHŸhCSȏiqIH)d@4F'ΏEO;DZ;@H.)I9O@G'|$={ȠrX*A$c%OgR|acJ%.=^ LjJ@! J($NDK y>9<̈Bx a,. )H@g@r$% vs@$ q]$s>̎س X(P$ B!e'^ *-Ȗ!q{@ʘPtb . \\@KDJdޣ̎H{DT;vlB.""D %ɄK%|‚{z!"Q$B(|Pg±ckM1I&?q,c%8v-! 缔 1 %Ǟ OD\n ւD=B$J#'## $=EG@*AH4x(H*M$z$!2 "O',#ɡ]BBH= J<,$0 DB.K9 !H)T+XIH%8KrQ@`$a*$BBF}\~l,).9D$)E8qԄ%c"i%qc,@=0Ļ\X y% \+q„'%13XGb#ñhP43b,Ig!xD"8(\0{FRyτDHDP8@H<8d` x$I@XLba5`>M vCC1;F$5g$D{fJ<#`ż+XCIB H)O!@<c+T\!y.\*|xvJKL>ODwlZ9λ;;ώ8]P @"AB0xO@ &L0/O3zIFUlHʠOY?ɊN=Ek2ڻˆ_Uw.NbFAL;@$bdP$ax2JbH{Fq1I"|쐙}H$5g @]1yD3" 8`GH]pGFGr'OzH2)fGJp= x$B=cgH$cOc4g @v $HKrR !\H!H![!v>B'RP{RJDϲxA*b$!IH8\Š4{d0 $yH`Q )crQ&Vycq{@B644VWUTQ 3c8a(itp\'0q1x"mdmH!b2 D>ZH'"% { $ IaYFBHƸC$${ǎ?B<O/*)| I#xn;8^q.@>v< D@$$zX*$G{ QrDHg@R"J@/:z8)BaёAFJ'`(s9BJ`fv/$v; &L0/-OnP :-2"Q\G-̿𲶖i},D 04uػlHbR$T4:{YɳNHbT>XH\BBc ޳@耽P{'1 CacL b) )A >aE+2(&1 WD$Iٱg%g&"02<0*b\B B HBT($"< X 0>]sq8&IHģ@]!X'$@L6--}HF!d@DdfXq8!d ]!C"@^9@P±s ₔ ЃREdM02K|g`M>aJŘHq_<ʮ<{oUj$Y0T%Y4C:,˒%X  axo~i@J"4IƝ$2@cUe #U=g?Ο/X穳v{=g~ۇA@` ʒ2:0C,e IF_-֚ђJʥK>[bE2FAxDc&R>d,ći]]]]]]ݿK&IkOέm5wVPMgK"F^}~~Dz f-b(CYYGD&-m*\My%QDQ 1*˪>T9B"c i5XR,S> "$21?g!)Ar!FFT̂VRJ !'ZxQdcd2*yY#rC` 0,ϝ_(% ZT rg\>Rr,%I 0D(X!R<!Ɛ1 (8DVQ3! Pȟb%DFVZ 0(Zͥ򬖃1#Jr ,0 Q@C(b((D^Js"@)bxAŐIչ\)hK CrCUHa5|/Xj,B0 )#G"BdAru|Q<䑣b $̲G@ ,%F%UVP9 !{~,/MTPxb!Jf#0`ȲLQ]YHQ03T`R2|@B`Z0&A0( JbyALB}q" Hf|Jz>֊3A`gJ"Lj #XY:6rXYfA YGP"3)P"y5EHDʢbaJ5*żZ* =Og'/< k"{`p}᧯:ӗlddD~[?OZ~uXH<ֲ<,PN_rV[e̯Բj^[- ),onn;#/<}uukC^-LG;/,,.>3wqG`,ieqZf/- !Q*) oNre~4"íS'yНw_[U+.yOSݝ12pllj /,\|?(|/ rϿ4uav/?ٶ3D(55}?>{ S/=c̲<˖e!dY-++a9V.ZueWY&%EwO>9qǝwD,{ΜY^^?>tB 3J\+fy-ϳZ&VkKZ<3?\^rI@9M|GK++g;ѯԪBw~-,?sw^ ízKg9s{RxgϜyg>tsBq]ON^ZYsǝwF2F~Ņ3Ϝ9t{Xi}O?ԫ~K!@޻?sKKO=􁃇^z|3gw"BQ{yLue3O߾v,ySO?Ks;~W.^|g.H|=O?}fag&٣`;xrrbqq駟"IYB/U9ѣ]=QTr}X^YY=?|QB @`s6WwS@fda@-uuuuuu;31Mob}ow_ou7t^i:[nƫp՛l겗 6l\۷i{cO`'kL??՗_PJׯ}{Kܐ CǏG5RYeRZJfVd2 IIJD3Vkdž B@߱cG SڿwHЭ:].onmjڱ}Ν{ t47o͗mut>M-7m:22\)ڽK+̨&Wn{t˯;zh X=6:66J.%NIQ65cc?vlPSCoNUg)şjmcccǎs;zؘ"J%R2iҸfӕ7c.TL9_?F6sM4cG Iao#{lPb%lZIRF?{؆52sjFRZJ43\jNM1Yg={m7tl߾cfff-nݵ<==uk{{M۶y"̤I[ih1ZY)e\m:Ľ{LOOߴm۶͔˻wVp/|ǻ 坻v2{+۶nmohؾuxfffd={ȶuٹf} 7F;w&ݶw֭[Jۆ̼X].4Ұc];w)Rw)۶cm{׎m;fffvIzہrcdx]G;޾}\޵fe-͜?˭5ߴm{\yN~[Fg;wLJٳkzzz֖m={4=v| Wl133{NDg:Zov̔wIRz˞ryf-m߻gwխR.Ѿo/˻v$"fV:-Z6mUWmV$Ym):VjbU}C.MH:!*хƎ 5RRJ(qK]]]]]ݯLlgt_wņ7^^?<֞u͛ujhC<86>.I3RDoΪŵk;S6ٮ%ZkR䒴}iicMk!5FE}aa%8l!IRfNIɶvMZknkl]XXSW(&EfN\+k~}iqMJiʬXC i 3ӆ!6R'ִt,,,$dlQ$%ZI...7&ڤj4=ozÛ916M3JII&J):uj -6w:tj|}j||6Vxl|RfN2֨4ij.,,4VS&M"߿6hZ6o~Iu;פN:o>%D`||H?p`_*2>t!:5~V+gSЁCcB*k:t)y8c6䁃ǕҧNڿ_ZHK\Н?u :};-mFt15>>o>Ipnۿol|L}ԩn?p)߿6Pk~۝Iv806&bfhH\gdjqq}![l4d!NiSGMRCje6*tMJzDPOW C֯m-7o:P,]k:״jni=]O|26_7ͭ[KŒ5cv&)ָԥ7m/wm29̚Qhkf_~9˲3oJS/?xHooOT?*J+#$f6(IF$M7_u J_ʗ?OJ򗾜Z\Js̜8GRӴկ}\ySsccooߧ?,5\$Ie$m*4..|g66{{|ȗN>l1h]0IZLt֖5_<`oobL_o߃G;9 IDAT>u'1ՖKRZj(ꗾr3G{|ȗC Z+9ZiWr3G{Z[7yp_/5K/T,1RN(Mbk8MWPm陛FW*}}$P!ٹ4qZ,*2h5jubhu I(RJ_Jr3uZk{{K.UR{gggu4 "RsZRR1VIS5;;笫T*ݝ]J1Vi=;;T*}ƒMu{nn|ӭ92}ݽshR(JN`o"YT$D]~nv*]T:klZxWqnn.In;1VwvuΡPJjZ+JݥRY!Rtuui%!2wvvVV*>:zڻf-Jӧhggg)f6FZ$&յ~ H=ʓVKRdRJIgMbM!RCYIR+JkH)" "Wsg&Re}ړkگ<0}7^mEiCe׼?Zڋk:̕WohhlVi}?VO?}XkScѦ--5̳>۹n8 3KX6F#I5]~rr>"O'x)ySQ+2VgɤMKC :Dۦ&ib V)%3;kF%8[p}vuZBc(;:zPL{qu=IsZ#bcSV5J+օ 횎uOKd$ B:{4B(-|K b)ާ΅bQ'Qk{)3S=]YBL\[/[HR6+%!cH6XeR)!)BJmWsg&z/ruxWַ֖m ow\kConpՕWM?<|DZkG NI67~K_7$9ՅRaN<=V+0Yi[HbR0dPe7*yJӤ7҅ 6mvjJ$i&Tz,UfPRi,5*z`IE JD$&Ɩҕ_/~_ѺRtwveI{&1Q֐65]&o~cS?~o=޹vpb٠( So>2zlacyJ WΕ2N?跎>xtXwbt[J<]?QpTJ2"Iŀ>ᑏ}OG9@@!H`d|c=7R}yfpPC `!9jmFFF>OLMO-WffGFFFC8?|"l~՟^YKD#1o{\ǜn˖<'&~tuסD!'&~\ %  "29JfD[nЄR\ BF| 899!PNLLQ zD891q@o,&&&#+޸ubrR|kZfo_T'|~VkE:<2pbr뮝{핅K|[819Y(ynQķmqbr2"hbmo Bk'&&PxݯF nƉ 019DF|OLNx&'ặe$xI<99quCdxxx䤔'\CTTh+-7j> o1@ciMsK{gw@|;uԩ< ! B  Xbc19Tɥ[~%=wfy]՗_;S(к֎7oxKƎk:; -ִwwl3s۷tnb`[#>}[ 7Ӎ1vll߳~R՗_>x)MѤY-ؕt=Q;wX~ 7'?I-ӧOLB~Ϳ֟'TLڿ_j22<2ϟ>}Zkwީ۶67 wggjtMcZ8`\޼rӧGGG Ia`SdJ ZՅJVJԄ?'6`_0Ӧ\)Ic?Cښ$MdYII$cSǏiώ85>N(q3Z(jy_00VtAicae7t.uG?l̉KKiV!ejVֺbZt:}LMM4ix]}YǶ-ryNkf&H H~\ֶkKljwϞ۷{N]w1S.ݿ<222=={׮4-ܺoԹᑦ-[7lֽΝnmmR.oٽ[޳gsnqȶݻ5{n35552<622R.wޣu驩wn|M7?;έuxid{tu}禦n42\޵{7ikϞsݸuKSKȶrsN޽{ ܰux\.ڨݷ9755]K//WVV^zcGOi]h72˲gNbWW5V?\D6-4I

6oHD,%MK4QRRcZg#e("- E׵3V+[_޸_gϝ7Ai_]3@-GJARs%%V/V\~m[;-..:J>'w]\G1D 9L\NV]2(@@Vy_#Z5BDI#s $Q!K <1X" !DZ#yB"(I $8(11@ʬ[hr# @B I6ECP@H <3 )=(G(R IG 8jBbd^ˤԹ)DOR !j$"D_4,!z_#)EfH gFQdTdf \;Lj+:-!(ȑ#k8xM)]0j*Je3pcsK 1ĘBQ!pBRXׯ 3ȀR` 1 EQ$IQ+ wMdYdF %1%i8_Bv ο2JʲjA((I0A9sPZ"ǨCd!WN C}(P B= U3# Qyf!Ud#3Y-R+4B9,# Ic"CRYB ^ZBF"P(QRf B$ JR ,E`cڎƦ1JiCbR=5B0 I 4-*Q) Dse ^gD$X-!s$"pBm+jX1*/bB&-c (1 gM6ֺ_Z^^2)Q+*.^DB |`j`!FYKI 5JTkF0G` KDY }yΑQHPc@9jkȩuZ5Ȉb58p}Q J5$rdrQ@EBCR ܣ<2 !FR,|@ #/@(Ͻ9I9 ,P@ σ>"`@(y.eZd>1TbDe\]Zb!| R >mt`ҫFZ BH (C+K+ZjhV{WBB0Q]Q@G"}1`!HIF11D,B@"R,"R B1Fd@"GR:T9d$RK!FB)bdɯdJ 1r-U|xYE A9[0eSJ$9X{ն5+|,C!,}@c{)$̨D  cW(K斦.gy@ATCZH*j++sGJ~Ӻ=.Z(6}` I36IBKSUmS+hy9VHcs bpY.kRڇ#8|q!d#HJF%10I^?E 0J%  Ju%)$YVW~B(Q%J1dYE`F!Xǀ r2$Bz,@#3Bd2gRH# *Q0"!G)QP=0@d$p ((ĈT- b \ X"e8 IDATx"B0Py+ekyȈ:c!X2("$D>gB 3G)R03`z=(A1QK!PR(C Q)jեD/./) %ed`(V1E!ąK9"G!I<.C`FIR,,G)̃H1DX |#J)y"9 y|4za@!GsiAAAAAAL6eǴ = .]nhn(5Č~z64rYuy.y.os6 Br[0BDrd!$g o=1\>#xO#z"ycg#g,o!pD{ye䁼w#{k u.gyq"ƹp8Nq^2r1#ń.s!: C`y ."@[q@d|^*㼏 "'t9z"aY%0,2;c68NNsNJR8岓g Ɓ'dBJyOKD>*ǜ2Rqs)y"PY75Ji=8 -G-'{IƖT v2Bg#rbOH9,1d r.wBs;8yD@D b'$ޑCTR<"z"d9<:$DĐL ~]c<9J8v;a٤$=0"cY`8G}&3"%ty! !\3b>#b``{@FBp &b o=#=;u6I|i$P;Bt[GX?㴠࿐𮬸rv<'2a9N K%i46~[~ڨ\YE N=C@$`[w;%h zo;2DY$6@S=.eGs#gNsdc/@"!g8zQi@`r|\Yd{Gށ z c09 Qsj!82]Y"K{`h='=ZH0ŹBrȅ,6%8'%Z@`B+-Rb>'qBrH30g11wG92(d`h>\N8yAxǼ<:D18s;">{rv2g3 ; p#ҒJdyK"ba\2&w>@rƒϻ   Ƭ8Gg cq8"㱳qL9?2x`20b1n(UHJ!y9e QVWOZ*R&pRJ`IE@Y{'ws &&[eYr̺X@y$Z?v|c~)3|кupvۑo_?r|1Dϻx"XI]`y__G"pm<6vС-m& i'rD>Md;v8yrS'N}[*,/Xx ࡇˢdQF2c<}*sy>'*P~O>3g?}|葇dZXw:K__ \g9qC~d19Ok{O>5xyׇ>'f zz8Y\YSSO>/})H:K'w?u*}z<7vp'?ip͵W=Hf׿xS8r!Zw代cc}}ӟc_S#O{'N=36=hlDDvF&||6|ZK};;66:[1۲uѷ:r䶭[R[n=roۼ6g`֭αl6;m DDvۖw=>:v[zƸ\[Wvahoor 2-G 466s#^:t-@Lmcۑog=vm[ۘlnm9o5F"yǶ;>ztM6 ߺ嶣2_l޸y-t#G6ml]|澾?뮻p|`;>z9sl|'{o߶dp֦͛ 㬱';{x_ߡnzJ754>΍esZyGykU{o!sX*&wjvQ:v&5~zMm۔+gZ4{ZXZ;nfmcjJyP9W_3gihhkl fhm~Ш?3<3gT2QSSz===&zM645%D[s[^ini:LX*&"-6:0:2 (j4Ah!dOoώ;gt.I47ww马Yxs#tNk+-?_ӳ`ݚٕWLk;/^e띌iƤjf"R).{6o^mm;wHukV˖5]rUk$p"Z))RJ׽cG[skQ[ޱo_7ܲiskcS"ښ hvܹ|䑙3G޽Iٖ;ZCw>?zZΝ{䡇w$ܹ}92ӇK'?o~yJΎs=QFWΝ?\o1mm;w|WT;g;wx(;g޽{o[6654$i]/pZ;C^&͝Z֛[6oUj:[ZݹW^)(6ܹs<3gLO&Ï\y+/榍Zwܹw^uǴiΝ{GfNYLͻbޗdfvRBp)EDa Z)nt:|Ҋ%KkuϦK(Xb 7(yt:deWڬe%E+W,HYsvMtkiWIYɒe7^c`u+?Q^Zro\%ut֎M\xqk'/[9W^[Un0J~x|ҊV^700U񦵫K.)-)^|@zݺڨu֥V([rdF֬MKUv-[20^fz tze+X%uk+k̍ZNvڳe}betRݴn}:ZVZQ ijzGٳgヨ֎ήKhmϜ9\RTx'R@$j*RKmd1B)i(\C/m*--k3+LWLu7T&*+o#nr欖 %UM5^dem~TH-R& Ё6Z%Q"4eb"[RV˃aI2IDZ J+%I6 w'DWͻsjk.|MY22K5Jؿ ,>oz@piD OlBk)zbb" n 0ZFnucoOOrZ@LQbttB3VRV^|q-,Z32FTOLLh{< \#SRJP'5&@22L̽lQC\D9oޕUW}TL<qeURJ%LPAcj&&&=RZh)$WFI%E(@@**&&&"x@k(Rq0 dkcMCMXS]311߾A-Bk2Q!JFlbb{pZJ-s&0QDDAKJ(" cͅBI!Z߰nBI͕ٸisooRwo(QBj7oӫӳaΙ1ZyM==Doou$ z J_ E7NToo  ւM6߿u&T&mj~~JM uڰ֞7_oVneSoOw-VJJMIFޛׯZ qƞg-B !M{zzq놄Z*#妍0){_HHi%͛oD7ߺ%L$n#ݿTJ 羰A~O?C L1|gؾ &(!Z PHCBcȅR+iITY*JZ 4TU򖂂?Jǎ5g76Nmo={Zz^Y<981{3[TmqT6c6ajն]?+SEEz^K/\DH5ׂ.5%ATnL61'|ףDRrJIHjD*Ο?{}[jX~'Yu7ʨ .̝13hAH d2MuF t46 **D L`QLDRGedc]+?zPL~"a֦ơA*Bk)ւ)o}ͩ@u43R")abFnj'՗_ Dp…{ȑ#lS_ c2RT\Fa0s<WolԩSw[TTRs;:bΕsfΝ9+$xő#ogS'Oݗ\\Th%9*AHm?x}:|%YR)%tJ -Y"͜>ǟxWU]o0|oKRZHDeQ"5c=W_]p=a_KKJRBi.y0ڞxW_Jq{o)I&0ID`Rr$%H+RZF͌bÙ#u2"-[5L^(-eBT}CP:4k)!!d&ZW+ hhh҉Lf1 B(2+-3L]}]'Ӈ~ppЄ"3k#0l6shhH2dZT`J˺FLAJ%766 1!3Lc-\qhp0P;E0J|#CCCJLf)RrS_084d2MuA @ )TLfjm`2TRA]봡L&Q^d67U5kmlo2L}]*H$̻jh(cą ;;[A䂡LrΟ?ʀ+6R*#uL@k&2epL))rY}n}d$BRPPPPPGѾƶʖi%3Zkګ۪SZEM Sɶ26gk?ѫ:gוMݶg09sz׵ 7חf=W%@jD5cǎ545a 9Z "Zp!PJ*#QSkCÑmS<~~_UFq\VT 0VZ*9W*°{gT<km%RiMDZ@F@H9fJhs.JڨeE kd3 -~_~%%J eQ"]3zցW_?o^E/ٳ{G"Im~/1ٳs^}e%ӦM۳gώJSE UmuuGxJJf͘Ҟ=;9BHS7uJBk+/|+RɰszK/pףaJrq{ „hΜ90Ҟ=;$yoۿ۵Sh%WO|饗vHwwީQJ[k_~'R_ڳ;4O?=nt%Rz]eӚ[B\Zݻe%ŕZΘs8۵[HFEZs΄jWwwtQZ[VVKJ ޑZsHkݽ[K]&ι(RtwZ'RDp6FYk9j!Eww TQZq%{,Z-s. d=gW_휋B+)/ #sN)uZ)s.J;LEE$SR;C$KJ:p% ;EVrK|GdI6HDq'B%d%U%"d$* !TF&(Ja* dDF 1()k)RJ0ΡQ:v6O_mڒST͟R[]_UT9.hH7Nmih2$9"*KҤ0!jٶgQ">-R PwųO??RJ!$ g̜3 /H$@ZKc!TJZZG&9mpTEE%wK{pεFpVZd2(00R64 *JH4e ӁF( PѬY3v? /N1JJjZ%cD5Y\qp`ꔦ^Ɏ- ɨegΗ^zIB9]O /%GFFZJyscŋ: d LFٳ>/4ҥKMMJ…F@HT%S3:w~^P:iniWJm x"cRDeqft>=/)5<<c4Rwo LEDx֌9<̋?x(5<2\`VL*&.\ B)ɔ&0O?YI122JK]_WE%UFdS_"744(m:0uub9 IDAT/\BQ"0 -c[p@ " Jr$3djL`N$ew W"LZ+Q*(-*kjhR 35A$*io d2 BZH(9gndڅL&a&ZH)Bꇆʪ*3S0dFi!xSs24440ɵQQ477  *2L}STB%jhl d2Skj%RFAsc`LNEQeC+>O~zdd$Jp.01-MMpK{Sc}M2aL]s ҍCCZL>Bjcڧ LN2!Z64 /\fBЊ'.?9%PH:A¨@@Tkd,0R2QsJimP4F !82ZPPPPPP_ J$lqyj֜< WBjkS&aʪJpURp9o+KJ{sοwe]^) wy[!sC#x'O{yp#D=[p=ktt\rN{kil}OO W! z m>_p!  ƌV3B4qƑػwy/~q-\[π1d.Z9 3!,_?!λ3#tuuyJ#gsǏp+W2C dKAh6Kt۷߿lLfCH8C1scc\r%#'ku%gHT '+V‘#GpG/co߾+G3amG8x@D{YGqO?WN qa<@@@D`y,ػ|`V"Ç3dDޑ'@*Zg\ ""`Ks -YM=O -\⅋s/ZUU]98_h>o}_5\y`_9pgϞG.^!]pa__";kw暾>@;ط`5Z؂ E P0-E \k\b;{o% s@s>2tyYԩƋ/B-jpv||,^<_}q; y#p<-va_A}n\cBg)sLH8Q1_qgdzD;mL. f Q2ʊxKAAAAAcG:|yNumCԪ+Tl.URZ|̙d[EWZ0:YS4jgn3T7Xn]{[k" fL裏k==kV.)JΝo?V ð( (, 2ǯO|<*cͷVVT??ZֺX{ :_|`ܹs_?RY̙3˗-+)*YtY:^}*y xh"aPZVR*׳zکSJG^㏿q@ͺuΜ9bʒ]KUDdt`\D6Z(-M;wv775:honyG7"{7VWyomKϾ}?vuS͔Y/]R===o\4jΓo8{;gvE/qʊ(wN'x %۶K::ٳ]Zi͍W]93;?w8ps;z{z?>#SJ;{3u4Y3i]2=zƊj3f=ē0Rޱu}ϙ=;&:;^Z}znaUEEeFO>&n}>oҒY3g⋏=xSK+iRʄahaRjaRRr\7t̙]]eW,K7ݴ67;}̢ee+LMY&4fMk[.\uMWݰJ vӧO/*.-^li:^fM"޾e3g/*\ty:iZ-źo:sLҮʊO\2N^6ׯ?}tWגUͺN>tٲ˗gW]vӧ,Yt7@^̙3K-*N%.]rUk(ݴvsjkU;ϙ5gugΜY|YYiɊ5k֯Kӛ7Ѵ|7Y#^v͙ӧ-]4NYV+sڛO9U\Zxҳ7)ݴ3]**[ҵ4}k֤`ƴ}_8uǮ~W3;s^Y^U{5&RPI$6 )PJ*ŁIJ ֺ*-+)jJ%4tIҰjfkܪάY_Ec}Gi:ښjj;S3fֶmWzWFF'&&N:c)S˗.ý}_Z]0JeE1Z֮ן||||xx(**Rڟ{srs=Z0JΝ7=8~wnt&޻9qD>?~Ķmw &$|PjݵkޗGFF&&NWZ]^Utp=Nsĉ;( tҲv {ァz9kû׾ʲ*JKOa'?gVS[_YQh}ソ;@(gNN;CAPTZ^5sou]RK?ǃ(O+Kcg}8yd9D{6=y8 " G,?8 e*)eߏcw8C$ɪ$G|!y&N2ĥpq =p`<θY @FDz99B!b;BZecޓ$"Gy8r$+.#@@8'F 3n!g>ṿP٘1yOqDyc4c1 "Α,XYU]*؝>s:k{@A .DL[  bKD%@PIg@@RJRw Pr 1g qG :l sd9'1WǼ=mlg1By2w_Ș  J {CC-xD3el=p=yB`(8"E3f O8g zqiɍ˘XrYy(*f242t|T4<1> Al^II10 _lDkGD@ cӣ;luHȐ\8LXoTZ!;qd;D<1.AJ \|9$ml\{@$N2ybɅs!Gk h%y{bh%2ά:8 cfm~|b"1.wW^p. )|Q <}bpB%d-2DDX;'ϐ!9}x[ ѺDXo9:"{q=2dYJӜugaTS=CB@@p3D>+=ȡKt t!c0& KA[7qؘ'O>qVI[υ=g``K!>1q1ZPPPPPP u0Endb4z #`;?Ll:DD19|m.oG`zgV9Or$LOd;zR0\p"DYD` HcBmh$D$L$Z[JB8`9O(1F='X\\B.&w=BIy s \pЊJ(8e%d0zTй;}}{DnUY^XID-IYn/A q(Dzc}<Ǟ gc-ђYUiԢDIdPUYYޝ)kdG3ϫ/"{I4R #A*̈́@J( l}R"`THJ Mi J=} I1f106){%V"jU"@ި OF8tU8f5mT}BP@bܣt<Ci@: )(E(BKcrӟKde;bӹZ]S~N9iΒcʲ#ƺPkoO|$MK?2*GYẌ2@D(H@JW1MSD P6k2 n6J  D |33@O04kAI(J(>Z7$(HH00LHBꁈ$DR J4x(VkC`YJ`$xhpW8IQIU@Tj90"MM"@Fג R@H}@5 Qq6WSA30 LCSR/H$H '>ā@њ 9!B(fFDA HP< g/H}* )@)$$B00`LW>Rx"!|` ^EBBqi > r B_$Affn4ZK A*`T$P@$V[kK"e$FI! 3bӧD@(0E>$ HЩo" 9(ٳGR!`SNH{b$Ԓ$iH X)2* .SNΝ[X') dH($fLo&*IH@f&BgHL^_7WI" ϐ${Rs`f JBj-PVCQLRFK$EBH3{fl<{2MA9An ̞[C+5A @jMS7`lzH$@B4[|!(xi$()!Lڪ j& $ (uT2Z (HZrtJ!MCfI1 N~pDD>`"$$l('&ZR B^=(%I"RHMHDF|@z "HҔZRc%"Rf"T@|neu\#!zH$ M)$dި749@ԃ(i֛D:'8mkkkkkkWP.SHwj Ր$R*{VKk+fW_&ouFNrQHa. "rk.z@J $ Qk4}4HY     ֌HB eK]Q >T D1MӔ I $1G)I30)CP(R+AH)nE@iCkjDnDG1"2Ia00 !c3MAP3IZ2$Bis>xED>( HR*k $>!$I!IH栴$BJdAa#O=fa!"(e+' IH)OHZ[-) HԅONR*R0R֤2 !"3{D D$$ MSF@A<ZNk,JBdAx.r$)&@^ !vPgbfR_YYY^Bb$@ A IDAT $mzIsee9)!JBD@λOF3IЇVsj4S&BU{XJ "')2B$|Qi-@bdfX)V50C Rjm5arBpBL[ D `F3 |` @$4OӐ8MC3@9$S49 غ]},IӤo²%o7+K} rlJSfFh%zTF䞥mmmmmmmZ ҆4jZJAiar|3YL,U3QY%vcٙ(ylg췾u;o_01X^`;=?o~o{yV_m6F#IS b@VkjFVoTW뵺LT,u_Oky|~_;R}޺uGNr-/x7zg#p34iV \:ʩW}??+iVR0*EOk>??wt0"4imH@DʐP}_Nm5+j4l$o!5)%hTVW~\e{ X RJ ;gާ(IJ [~*GOK" ޹kgzߴ禡\&{LM/})dV3+%5e 3KIQdRL.eegf&'rgck/X왳wx&M_Wn~k\(7o9Q:IHko0Z]ڵkffF Zk V(aX:gY[[pb_{v=}}R)ܞ{fff4쌋Lkgv)TrW)vV i*v2{W|+.삱ћvggfwܸ)kǮ)ΝYkcnڵ{fzH{xfv]fg333;nf%;v=̴RQ&cݽkl6=<;sNem9i;RR)7홙ah`iϞie۷;cQZ]v̴.4J)6Jű+vumx3[%RV.(1(ivv;V)c]gffw$4FnevfDQQ+ GZH;1Ŷ 37R)UZt}]]xo~‹q9kffgMdUH]VR[$쮔WVV\M}ذVZJmTZVJYٱ92Z0s.rLPkWV˕rF524P]Y!(iQ1Q)崶UbK a8]!Z()3[3lZ:RZkroZFqU8gieVJ8'!%*]+++.fΊ2""JVbHJJrWieeEkiB(п҉Q&VJ;g l.6Bn>vĉboY:m#R*ԱJg][.9UYk]$1q\CT:yEU+bq FzzFFrqvv Fz**}GPq9'dF͵Wm,thL6YYi%)y᧿B&RRYeY+cQV*#7h6WՏ}lJ[S;6>eGGGԡCȽ֛lN!š>697:2t܂RZciRS[!Fln=O?@_##|!\l9 3磜QZkrNK)uR'<}&& ޽{:d?_˯.`ё%bc \XXR... )Vѡs r&:@َ\&c‚jqqq?M$fxxtaaA ߧ5I!G(iRzxp‚DX\\vVkldG-,8R KmPFS֑IBJgdr]Zktl]Ec#sX%ZX8gl88ا4R[&Fϝ[0,)R*Ik3KUV;-Es΁%(f6B+JtС{pG7mK_bcdH++Ud#͓O={'ƆJ{C_򃽃֕Ef2N+cO=q{=yTN99lR+2=wa;J:w3Q C7<<GyϿʺX))I%YKRSO=y`jj|t,3#>Гs6If С'=ŗd:;GCg}C|Yf6VFj%z}Ȏ ۷С'LE.ɠl|ĉ_6Qduƥrq'O_l)gsV0٬"sY-H)QZIE$RƨLdD& qK[[[[[O_.Fc}ōv7wЅCg _??4;q- ž\\)HoCp`SBi]??^3h_-'OvJ"9aVBKV+-$Kw~c-ǎa?G+;39$I#o(2&EƠ㽏V955)Y4M4RZ)Qml"c62a/810П{ߑZcLMZ4M[oߴT]7+*٬+./x7ߙ#rJ3LF }Gbz@4M9ё38{giBF+オ:`-i:-&''f45Z{ ٬rrjJ45Ry&NNNYƦi*g%159֥i/^dϝ8ڙS"'ՃX-]ij̿؏tѿy*03 )HJ!bpދ 7 96RHr֔?[ǎu;qbw&E̬F+)*~W"kҊQYI*}G?;Uru9ru1R$iryޟ1JfZH-J7xJ]6L(R%B]*;+L&+(r0sdR+!*T~|](vRiy}җ$m:TIc+w}O?eF+嬰F 1cFI-ёՑ3HZ'PmkkkkkkB_=btҨ嵥R;H.[m-wv8dҠD:,j@+KK↓y;FǾ^*!]݃^s{''CJhmk Bh(vaa_~-=><_7!vcǎ>ȣz;BQ2{=)sXZ^ZN[[:{Ai3Tz.c޽qyy9{Os/ UZ^^.uU 3j픊#z矿`Ǝ80:cCHryii 9{>riii)@Z;gH+"gl1yᆋ?prFZY^*aif,r m%R,-//O RI%EdV}85cq @LP "裏} B{o۟qP1 Q!I=vlll,͌?z?)@7 Rvm!!C<rO<7~wO*E9,>|vl|豣<3kJ=F@= "m&!CA $$@ZX;S& rgxm\7YG r9[_q`W! lE׾'F/sq+)"ER4H]ŮXbrg{TٸTj9㌔\38/JJHJsZwwOc+j5COo2JIL48ntbnm޵{zz)lLdhV[NJSՔ;nQ['޲s׏<~)tF-5VF]咖+rGGZz;o(ve V{v<<; sdv:=w9|xZw-743;=|oi뤰VܹczzFj={ 7\oQjv3339w;vX1J=wG/R&3궛oK_k{veJj#M{vOOO+fgرKܱszf=_`f )jնhR2V*)ZbfJ!9)WWW$)rz{jFBmM\t4DZgBsbjJ*-"f6J)mqdj} (W*jU0DZ:RKmJ9UrFi#UdrZRZ4U#$Z*8"SVKbL+1,*&wqT[]]??6VZw+jU*klOHg |3RjU.jF)c\\VR)E(c-3;cJsVmbH)\Vj#:0y`9"')&?2VJ嬎qHIZKH+e")HJ)i%ٌVHZ).2q!=/r3Ύ6_:q΍=Y{ᾟ{':rRi{|$7ziaž;>5Z9<} &q >Y)Kȣ>rS*FqlLJ:s+яT:?}k'U||p|lF#i㺉|C~6}g~ڏK嫮jnnۤBjL-3!1HM?3T(ްq#uonڹ{n]n)u}dUssswqx\w^Msss[]gپ}3g>sze[\'vgΜٴiSXmݲU)ZkC@Fsl#8/L\mϜ9yӦrWʫ6۲u&s3glё;wm_Zӫ26]AJkn-e#c2FKcRYgJEFk>'FG'ZI-9#E*2$uȑSS]&]?~ZFRiU^9<{pjj|t4vrԁuc ƍ>xYqF[53T<{KK릦kB;9W,#k=|u㣙ȍxYck bf#QJ)}كfhld?޷zktݺL>Sr)gs%oVWB(cѱ3F1Y9cjksVDJi!6:],@T:y҉ ׭-Js⡞ݣý`_Q\~yݗvn;>gq|>wwϟ_[[{W''zzz}rV{B'x 4mۺoulz=IkI}womR}O:'!mV?NĝwFZm'OJ<}oEGjtEl!OSO>w]~ʩnX1B|ꮻNqovB"JOӧOQ)[eQeTUKw沅e:]w};{W?q]N)fVdr|pr)a4礔h)?~Y#ÃO<믿޺{g])%4DV'~{A%d!ҚHKE@GJkOB*FG=ď@OOG6 UJ >Ϸ? (?^J$F _zG=?ЧRa?*r``>#?7=?Gk[[[[[[NB=m,SE[zZG+efD,(Y.cjt1!+f$O< )3H$OS)YBij >M <' R$BH{ "g: _[Y}}$(֒F= )-j6! e@{L|L@ d4BH`NMt0H!pm쑁mэi9P B|Xs'=ϒZ@9xfT} Ġ4j5(ZD6,-.BZNgIebI> m|&'1Z2BȤF!MH !rL#[89H IS"030zYؕwfn"19IDBz٬B APاMI@$BH2P  ZBUN;+s`f$$H!AR> dBf`fB4di= @fB/ JC@ 0ElQKתZ 8bDD} D=P0" "2@$ ́B"dk4ħBH @@B(C"W(jf "EF}aT FR F9P*ljV=LH((M>ql#y=#IF@l&RdF{)! FLViVRӶmo9kkirdkju;~ϗFb`WSZke#޹/šS/!DJ՚ 3@`cu>zӧ)#HRI"&bDQԬ7AH|$) D@$BXHbT tWwyԇS@(pNS$R0ZfIh=# @Dއ@80K"l%֚M,HGH}"Y WcWχ4MH|){@lW|YJzJPBCHתkk$IDQ$RrXԂW|ezsI,PH@9@s 10#"@98mfcm+BTB5gR$@$" 4Cx7 @Fк f"a DR %O& !`""&4Pe6f3CPIH= !Th6 8@6! Iͦe$bDiQ#mz@ A 3HH~k_Ah$D3#6uaTWԓť4M?8@L@ GNߘ?%%@J2@,![K${o)%0ɻ)#H%@9*@bK'H! QHI>s =JUW µRLOѱ|59yïvU&"L9{QN2 1;wXlm>\@{(@L0!Fu)xPNB9gСJ1\!ہRV&xbd^Q 2g#ʀJ= N&bB9E>Bq =ΕѦ\I~<o#F,+:GEr@(ay.pE 1F":(Bq\L8Z14t.{B8RjP!@!aTHJx!ꨐB<rY8Ჲ,7?1<u.\H 4rP)dn:pqalh3DZ!TpH)xk#R "0{8("X,Pix㴨,koFc.Ţ)%']۳<# hC z~N saRQcq!3x.(@{.8ABasHH)vpfGN w89Bb$Q;}-!0I!@:{0IyŎ@0 h0%9#4c$RB(9KR$ ʤ m ;@$xHu轵3NS":`cH; 6L1FcIQ@DKz C@K=gD`CC+8alHG[ Ș@đa["Q0^yy z$@!QlQ9oJ8A29KvDѸwN)=eT1=8"&S!"/G R<2I0H #:'J@Z3uj!8q8PN)WT,NsPFrBP@w4I!\a#.gs)'9"(.lj<IB6E= |*%(AB}S} S[O {3ƕ҅8|K>M'q(!10S&:W.ȰHbOj0%$>JP1 "Ņ(e`ym !蜍qɽ-L0gl6Y}(xh @u aRy FJ:K9\`ƀq%lSΐPc9s(BIB)RI⽠RqΖL42 r!qYr!p2 c>vHs %QaQSMa9$2hlLrb#BJFQ\(F>qRt%%(Qp"AB8HУ#Yc`̐x4DQL!9PHbǙ%P[+QJ=q=, 9t  w_{G ![8#F2Ŕy1;OrJ&1>6 c gdn8 -0([9̍ . Qb'HyX.*ľ P șMDR>:2)=}:Z xDOƁ [JB΃' z@qt(G$@ 2B(z.Bg2Cx l&sY Qd^>m#86Tpb+q8Y9TN Z=xJ'uPJ("aq )cDƉSR%x~x0?cB 2[ Z0Ydɭ <a~*XRyܹ񜐚N~9?D<6:: 1@wJR~bbRc6v@8#$L&3#E~ȑcGWv|b7~_W?/(pp[y%8k֭zBn}Wyjmm8r+G^w6#O ѵ#d9V~Xpȱk{Ƿz׎ yC b(r- 8b͏'&D@W^^{==$L<7{?\qmۺO90x߿L&S@1cw7|kllЇ$s^m'_;z7/W>p&[M 'OWl߾흾ν)lIEssG{SG~na +߲u %qz֭[xѱ˝a ߻{=޽|d2)"JyӦMڙ/u᪫ܲ{{{ϿK'N$d|'O9^#~+ǻ9qwͯD:%856Η~Ι^]PQOLrŅ8cv۽g{O ;Θc '/ #PB DBR PFdJJ|߬Kfek[1}n]]2{Z[˛/\Z>!5š馪 TTTm3{ohF%+nXlI!W/ܺ~MU^|͛٭L$"f3Z1eӈ(UPB(0m|Fgtlܸ>AYKsKww]tzy?9mUzzzzQEIv=˖ FPLhRL/Y!4eӦ={v$ZjD(+?{奥.]lb}}+V,YhqYy5\ۻ|2#ժ?=[VpK*!VX>~Eiٵ 9}+FZWW/Zcn2e===-ʦӋ,8V~36on[ojժvw,\.YĘ`?X]QqŽnX[+ʲ,\ۻl2-e{/(/+_ؾgK4+V,z⒒ .]SjʞE -ޞ%K(?reOwE K+/\ۻ|2+zzz^vJ^ӳeZhDpN)J0$"ABK(\! :п kWnO%3[7oڴwnmXk[˙g|t:Kv-/ƛM"2}G IDATcӞݻ9-3[Μ94'K/޽kfW|a5uTutiٳϜ9\:4wŅ/yjkk :vݛ̔]rΜ947AgR|7]SW_izǦ{&ٙ-Μ>]|}vޭ_jt<}cݻw+-g9}o4ݻvQ~/o^q 6utݳG+v̙ .M.]v)%_xk֮o9킎Mv٭}3g<[/hK=v+R)` ~T&JH'QF)sVRl&%8J PJ)!Cpƥ\R&6K5-yKQQQQQ_׎v6TL0]>菷3K]v̺A2XsIYUu-ꦲtiJ5J/on߰EDey`sŹ%UPHeJ*%l*]^9eJ.JpT( CEA)% "6c\%RQ!\iaK+FGG r26&8poK koIQ*m"&-5Ԙ1FHh!eyEe.KҲ<<] a*F s˚ zС7ݬRq֬^}lVݨМ:Xsh!{$ʤ T&eR(֜ ^1eJ. Os= #a\R*JpɹJI-$g"im~}HH2\Ih(.2ZjY><%RGQ)Y PJIRJC&iYY6G?UB°vje6# 0!\ *8* .x≻" M2 $s-eJI$&ROw}DHjP)9Z'fJ eGرch"dh#)LHPJRB +\)&8Dq)#@Rp%BiumyKQQQQQ_׎v6Uϛyїow}ƲL<[QV[]3sjCku꩕5SRS;Y\^? _L+iv9T2B\. ɲ-[<@@j%<5{݇?,Iƞxַ76&ðs !Zf4DUhͥ:`]Mmh-eBBd4#bBRea C t-[~PT:HLnc2B`hpvZR0Lۿ۷ FӧFHAy]m@ lhpp0,)-WB 644jcVB~`mmm*]$JJ5Z jԒ~NńR*1aF `m}(L 6զS;ww9r$Ͽ_W3Z )&`?٫uw;{>yѣG|wwϿRPJhE)H!өtSSc}l3Ϩ0w7կfY42$ M2ּ<^m̹sKGe2BPL`{gy3O|ȑ|7WO2JNaB L'f<أ{QqǏ>)eJH*N;v#0+o3g~R)8T )JI%\k!4"PJI͘B2ʤTR)l,[*v򖩗/}ɗnʿO了TTՉLe6SU]][Y[SRUSީUϙ6c9sц/*&8c??vvvGӗ~jEy20\(aR^}J)P*Q26&U6jJ~ήxK7qgRYtee&*Jq+ %AbGaXk +K+ZK3*PiǎLfe ZiDB%5ιDLl|!xZNTy7q7)-q%(qFmL"֖ \""\vlUJXkιNL~,fZ!ιTBwttpJҥZ%s.M'G6jRaZpΕeF;8S 1\"p) MZ[bs.)Ѷu*.}vz Rwtl2L)k-9PIdGF* Ck9dLh6ut!ANn*\I*Lc#B *s 7=*Xkι0P7nB'LZ/g;'cğ~zرjNv=^~i"hmk۹sG6J*raݻw]I'Zۚzj磏=Z)V=*jŹ٧ɰyf;:::R*${=gKKfϾ੧vnЉPOkhnZcݳg%\Jwѱ M3f6L3AZ{/d69Wq&Љ +-B))1R& $DZ7-EEEEEE^;/oZ6yN ՔISKJH4Wg5LhVc[sŜk§7l~Q0ř0B%K/t?䓚PlI&gڶuOT2YQɴRF!Ra04Q!1BI|y.Sz䑍3ČMv=+Tm,1FahJʆjTHdmmC?j*%DQJI6ƤmoގOied*jIBI p5- y]OȷOOR3;::vz3<< @)?(jkmAnj}s}@d>Q@) -C0VDy*a2 mPӴTRHd}C}`PmM $RK.:ʼnPBs맧҉dFWTekքR\RLoR L5ʄRZ g4%NA]MCQjhp:B Q[S߯lVH)L߯ZsƄ5ƄJ@dyUIl* :T\@)ädR7J4T%akkmxIcCCCӦ(i5ΞUJk(n8Tb۶=T(=444=R%eMʹg@B ֖۶?M )UMUپ %P6&NΚݶm'PbhhnZm1B*Z[WwlbZIfmm۾g/_u5Rc|Zuپ>%PAYmԆl]ɟ:^YbG;_\x!#= QZ`HC]]Ag9_5ˢk_/} =ݧ~vm~|񵋵V:gݜs ]]W\ys+_8knͱW_94vA묮.!xWgysAJH3}WWUsBbmHWgnrмys:;;k1By{{{Wg'Psz@9>.9gGΝ;)wƒ(20uLzLPB[sKJGeS΁)B\yt}~"w{µ\;|p]ȄZbG(箹#G*g "H:gFщ'ޫ=r0A֣t;$@#C}*oy>oNn|@)0!s ȍ_=/mow>M$%DB)yѡ'.?r  ePA)c|.W_spa¹$R{,L<~q@juގ  Gc.R D8# Уc(;K(\GT|KQQQQQ_׎v^ 2pZn̶kʈljnNפii u\Ou%S6l~1p~K7M 晛7gR۷믯p-[<mR:5K!go?7tI6S1wN //=iLqFM<\^uU?{m3/vwZ`A[s뵋,[rB !B Rr%(ׂ߿/f̙mAB-)"+W:ujy%e,YL*qС֦Lvz}}ǦMJ&K>Ϝ9\M&,[L jSN/\hqOOϲe+RV,?uE .^߾箻/hjZ|SΫȔ.pi>ћNu}~{yy{zz.[`ݧN-l_--;ge˗֩eE MG+rSN͛7dKƬ\ԩS,Z\S1zzz,[f:`~{E6xe˗)WS/,zKH.V,]z[e2 t,ajoVyt/af|N3=SV`.Y"BD%4)83(K+Q& SF0|7\y3'߾]?4ٳ.غe롃oYܾ.R$fرcw#޷K+TRY\u^ nݺ}9deǎ'7o,ܿu_W^^Hmm[lyCr˾瞻SarfKێ;7mڤؿo-R>%HϚ5k-?$~ /8L&ZgܹG7o?ՊedK/~|_<߿+ߛN--3w|;=Jطo/) ֶ֭[7v}fϞHv|jI%{K++EmݺСZ۷K/K$2̜SO}B0KKqʸ0gז2_y /͇4)&2Ys) 4JVjud:0⼥kG;/3\?5UT{^z tq[sim-S/jV6Oi(hHW7Ե\X_WaFd|k3<4|͍lR%lo{׮Ǐ_oWFKr_ω߽OR%avmgΜ) ojkk&?ٳg8~ر57Iwyɓ'(zІ?/r ڵ{r'Nx衇++$WZ+^ L|8mn7H%o~Bp[6LԴʚ3o<Eɓ'> ԟԧ0Γv#d(eB;?ƿqyZ.pj6e1*wq矵LqP};OY{2L(<~Æ B(t* >ymKahOYnSJ0AuOOcP)wipdRr;N<1~m1Iq'n{Ԍ3)y`c\DԁL%LJPPD(%w;44<11qVM6J}ӟ>qDE===|l9s}(4JK?O?q|2NgJRs۵{dC?T]Ua$WRuN8nHgS\ڽkhߋUNBI'gNw<=PiIpO{*tgl Fi{=6UUk2_P4m߾{?~o|Ӫ+Ӊ@+ywo|l1:}?CߨH?s'{~RU(ճ<{wr8gsK'&&~Kc0h#tI0MH ʔSd*TKN*0* dHjj۷g\wcA:w$IVh zxo_UɚRщ1"_U|*F-gPK&`'3DOHVcc!%zoyș9QFL%dvt|dt|yUy#F|!H(!<Ɯ贩Q ;gm{= )zF% y`[kq:{18g&S^s-G Q6c)jJQ0 Fѱq*yG=$6Rc@ ]hBXr.B:ysE38e.@ԣ !ED A( P8$@(A3wB9/bDF)G(ZD*)JK[ ` M41P$ڈQ$!cz'( x.F=8)X9@(zv,І IDAT񔑉|̙$dydRFɿZ%G{Oq\ʦ cPo} ?<ʮ:޻S{{Y!O %BB }xvsl4FA- _<  鶄5t{ϩh'Wy{YjWiR0, HʃcIČQY P>2uM\m}!%r$C&!(HE:8LU0@\Ȃ*R@Ā@@R*t޻4#$D.xD.D PJK+|`a(1P ,LJI ez&3KȞ3! `y$!HI @;P  `)4 ͹HYouZUUUUUU<\r3#>{MR?3:^ّ)O9QB`4-;;b& Jt[PJ(9| ``w@JeF @: >>dT $A" LR""pp.EJ*g$,U(\Jc)EBD%-*SOς8M3="NIDDHH$aXI#B$B!"`c8μw>xs\T )pX#JB ';O$%;g!@TJGT}~$D!2{v K"`vC@gNgĀRB!>  !*$[̞ "Qq! ϼ<}J!$s@vFIfI!@2HѺ 1ua:iDdd`B  Dr9SV,23 ]@BhN?;"GB(et0s դ4Q.AfZ@$A* CDɄRY*$`5H>x!Z)" ACeH!xY&xP*B7fVR^*їiUUUUUU1d ʒㆺ oCYpRre_77U^nM`ٲ4 zch_S3+A}CHH$QL >u%" JiR"'!CJIdH+Sc! PJP·)dD"CD3c`,L=3!pI0BJ!#!19An\&}Ka8ΛRH`pΣ htH]88DBJ:X A.R>33@D"80K3#! IkmiNzZ!22% IX)eB0g d+Ug`"'A;@ "#3Wʂ9pHA(epN J 09b`H@2 !Y. Vڈ,-sZ,s!A(A>" dfF=Ki"[S(?{6x IDρ]!ҴR)&t.89τ A.j 1O7ϙpKD (h >Ex|TbF JIѺs|;c9fsHYyB@8``D@@IP)Y 3@3,a:wJ2\bI!98_7q !l/;$14M!dD&-12˂WZw8~TDLӉ1F 1H.D$3L?e3Đa 1> H]-UUUUUUjkkb iI'y=vDuM4*4z/lB%QfμEWW=@ "0## dBH99{'3"eY^K+$d. ؑDB@ XN+A)Q8e"!22K=TXH F2 )N $rC@sNG" ˜^G ?OR;I0˜VJ3'(䭑ԩ2:#bMm'3"$dJVR10+!E d IW! I`9$ԑ @DlYkY.= zhh\F{f ^JB@P.]$ ̈($+)+lXyI  "@ň4VH`ꁈWH!*1cٳw$P0Cp^jI8 !RgH9M83/M\*<vY$IJ\%<"2`^ Hk#s粊wv""0hIH Eco30N+)`@B$,h0 4 bbן>L?+$DDLDD(+~sҪ\RBsPι%&#/$,O}-JssTNi1"VgH>L8jjQAJi$A-EDeheW>qxeYH#  L A+ |"rQ @>B T9  ٹR9yώ) ^iynhp`.0BRhTBO/,3e"Q{P:*) H!Cx d B>N S'O*1s D-#B!sܹsR) 2(l:r'KɋBZ:L8%d^*M3wR,D`O;R 0I&0>p@];O7w~}ĉ' rBs;SV,_cc&ߜ@IPP94bϾ}srzJ`f`Vp. 9y_yٷ,.  $eJi0PI+.!%PBK9`@Bx 9Pq$nȴ1.MC8#)D(Y HB$d9nj x|pĠ0u^jMj r)O >'Jg`μ !QVI;H m4ke,pD(;'L&Se`wT&"RC|ZO1Dr>8$ι$ReA*$Ո9F&í(P ""@`G$ʜ#Jb#S)0W*YZQe>2ITq ti+i*2 !# }(Ix;&,M,$J1H2߾!2HDR! k p)ːdAL` !xBx ,#&NI9YYL@9$$!\  >C$d4JD) 2Ygi л(@># 23"9H O4(%c @:9!ID4]8U)y"b@9r!)]榳aJJbcCs栒MdDt!03yDd hFIx BBB>07mp?0XEy-VkDqKdN}Rk&_~S/LhpIOGVZ/?3}+~ߎGw?9ι~355E$uZ)xȑ7Oz̧ͩ(˕\.*r9K/^Ͽ駞?~_}ku ZERw<_~Oo@ÇO\x;7mdBTi|z&3xhg&.yi/( x+Y^[6'KR9McϖJ庆nosk'm{h[Sk]~g_ssRI0{m/]|Mǭx|oӟӟl$F aܹ_Oy+nR{dc'FG:;6|?Or{zm_/UJ#/tM˯xy;o??es9;>q䅋&ٱ[://|zϟ !v>vԛcgO~F;G.dTi\IrʓdZHGСѣGgJPJ9ҹ玾r{̀2"'=lzɩ ^yy= "rs+/:zM( /ą#^2"3Mw>TC{(>Ryjd{H Wrˑ#^8/uw#c{ӽ85yW78~cG8rMw" WBĀ9lïpˇ^Yw*.6s~ٗFf@ukn}uKS3I])gJfT.e.CdDe,-S}+ |R0B 0=.A* sTUUUUUV:zx+;ۿy񌎙puW]qIV[Zf645ϙ7w_RzI{ⶎ+:ݻ+.] yKm.7u?`~kSo߬8{{lٲg^#U(VJ351rff\]msW{<%CCC7o3o칗,]_{}CJ'N|b̾\l`_Oa譫WkH(bfmr6+e= w-xܹ۷ojnRJk1V"21e3筩ITl}x`soWom̛ٿyCCCZE?zG7lۗ۶ݻWI9oSN̞WSSw廮ڳwN  z{r߶uSOF͛_a+={T?܆{kj/_|#?'ceYp?̞S导]{G sq޼߼={H)͙{\|ՕW|on矻뮻fۺuO>i;gɓ?]8+ܻg~tƻgϛ?O=K/;ug>Y7^y٣{wmcB>ݼy={Vsf>u>ws •W^{{4=]w70sf6ݳZRkcb4b5''/k~ppX\zub+]z0zڵmoRYD8wśnIJz+WYufbl~GO_]wY,/[PWw ׏^s1m)-+?{oy;?dڵ'ƆhU7+֬XƆe˗GZe]FGGoV5kM+V^:aX~e[Oߊ~gtttխn[x|@]C]u*-[o=qen9b[GGGowޱSo[P̑R Yku3̼p6Z+dlU"R2iam4Z De"m&yKUUUUUog͚x+w5%}ξʮkjZgv6u70joi9gVh*$ f߻+]+JVu)kQHk1BRd#c$eF2&fVRe")/^l\sSk]mCcc 1_笱8gT$8wuI)#kw޹aR*c"k8cfc15Z(#*\.Uha|!83)u_VV[ZJ#-L$TFJ$ҦT*oORHi$)Ƕ6$Z.1?} qݬY gk$:$I -/+KRWwvLGQbLR_רRRJ!`$K[}OKYc$)Q*2(lmi,JR3 !$I2H?p`;F;7߿6ߠX)s; ؿuVz ׯߠ5&ܱ~CBܵΜ5FV -߿nzi2F߹qӳ?|~wݡ1Zlk#c߿ۍL3IƍGL62J ƍl8~Ý F aÆCژ[6FJe#{]w k7r&mrdž ٿ;HB߿#%7uI!Ij4ls50$4&2RH'a")IuJ\/$6QbXFIZ) A֘HFFJ |pռrK:uַ5\ڳM--͍f4;gwή5.;g^랹`gx/kM lկ}$)$zڛ[.~%3g~Cro|o #B/|ǃ=SA IDATS&O9Co751I.QR[꛵㡇~iE3?J|7*sTDF*-2Q<{쇶?SO%qtG:T.x˿,$y-*1:6?g=O+cN>ãGV*'On51Z4&1wpwOO?tg|>oƗ-DR)eMIYso詧$N>#)(Q.fڱ㡽O5af`4R+!#623ںTdR]]cccƚޮH%B鮎cc9'ǻ;:JHؘj||C)-lSJwuvY#Eս=cccq||;&6&̹YΝ;EV+[966QJKǍ=(6ؘ411!PHdWWؘTrbbd]]cccJΞ.i"[5vR411v65[366l3X3JMOuucMssCOwؘb||$?̧NJttnE+ebfc!đ?~jkM-QZS\F)J iP JH%DaRAWCo5otEW\ŗiN󮜷unS`\2ΞBosTTjIĵn{6'-M->2<\.>/YSCcWGgKSb#iok71̒V*XX#b]uUYykLKc뛤Y54lR+XcjykL>Udl٢:笱Z[Z))jm'*#G;\A+mafT$DFFV%L嘹eF{$M u?8476YXlǏ=oܞ{rqCm9s޽uf%V9ՙ$9޽W\8gK-ؽkkjjkI׹UK=}U-.X;g֬]vmݲM+#ѿ~̞޼ι>yť 5sٵkז-[Hxf)sO=5~U^~Ӎ=7oQN"kն6ksn޽]^.3g]۶mO"rMp=wϵ{OKC>kז-["% FkOSKF{qe6A6w %r[ԉ9+>$F͛7k"kcH-rqS]s.&y|✋L'y-Զ۬15ι\{E62v6F9%{6͛RI䜋$Qr˖Z|9W7$_۬L9޷hD,m#ڼmlP✳6޷77tж#xGEz-d!N޷66;|'$qiu5F۶nMl3&2HmH֖xE-Κ=ZG()665|dadd(V̜&6əB36Ԙ(?X.w޽ݽ=Qm۲m$ӧ̛c-hR'':;TVGq;;v626,0QB R"IK,ܹ{|zqRcu33(Q2i5Jc&9Żw湳Ysn'LrIdr$׿>icccF}R Dc:11>!Zccq,;;%ERk966&D$סSb[?ןl2>>֡6qA366&ۻzZz{gFvut)&&&f͜kM;vvL)11>>;HK566Fʨ$'%%!;:2̬Bj{|IJ)&!>4RFbdIr55-jUUUUUUĤCo c[2uax蚻_+P+ZeF-$rAW\~i?Zly xg?ׯ{!!@ PXX牐(/ٗFO FO?Ȣ< FF-Y&F0W|d;@bDo43q0dɁeץNi1@GJ 4}x7/GG_g珿~a%K0 (8F >{~pr>V( p` d@_!##KỲ W_wȋȵ\-[䥑DYz͵#7r萖bxd䚫^ ]xג^ɘ^|qKd{\d`ddD\lqaҁFR##\w5J F^q#/-[RPK#/ ##K\'q,KW,y _{ըIxK,%^}K@*VBdґ~xdkV@*xxK>_zR&vIpkFe]%kRXlp/^s.TΕ0-]60yC+?t[Kl,,[:!c,23+ Dq_5^*D2iB .Ҋ8:RUUUUU[Y}m}sfj[Z Mmަ֖ںHw/?:/zf/E{C۽^0&2&:xkΙ9P7s۷O6̾UjnjIrλd;8R#k93Z[lIO?@ScS?_n(l?&_7-[8I-ZpX?D__.)\{͵O?v?r榕+W7߲h"'9fcE$ޕ+ox챝>{*IXc1̬2hc6&Qj]cZkܶuBa۷?xƘ}r--Il/G}5>r= u .'~p[[cóz--87Gv8xbw?3-P[w޶uzUP|Gv<97gޮ]nJ$ {7554maKٱكwoܴo߾ŗ-JxΜw޶m [Z[jk-d#>ʨxӾgE?g'v=} [ ܥܱكѝ7>o_.\km۶ ݼjU[{{!_Exgw߽g|څ ~o۷Kzͭ|͢K/ȣ<)̑QFH)Xj͚5Ǐ[dIM]URk֬9v򁦦bvB[ꛚ_膵kYs۱cǗ.YVаlpĉV"kV>~/(ko[Ek׭=~ M+↍ZZ׮Y{رK-]X51qT*7?692j{>911155_Z"cDZ5׼ SSS?ǒ|u;{Jrrc>:?R4o~ϜβW^szQ~_i_cQ:RJX%+ڳܹsSScǎ}_1C2󵎔(P6"Ν'OSG:6"cOɟki'W:[zft_ɽO8haMd7{%uzn݈H$( H<-H b=Z@g?[ Рh(JO"dDRII"ntW{{~4%녟Z^Zg>֭jc>g>}{W[ggl9kG?O/M&Coo8w޹[_;O}S\7O,>Se۶}K?S䧖ԪfE_޽{;:[l׾>ԧ/t"[߾3n˹~_˾e$?o?91;:;}oK{#īs0{Xo1Xyx ݐ4wӍ[z=s7'l\#>sBcnfYj xKO?dIZ?^{5t=ZűcG{ݵh 27_o9o_:futMO8M]_o 9kOn_ަ%^| 78(N8/}ip``i9ÎZwifYןݵZxc-[\gg֖Ɏۼ]PľJ[͘.BCTS{WZUP˾$يfm/}ͪj$BH XU( l% 7 FjNO/aV0 SdВA Joտ85l@,Ab @$* 0Dt@ b(3Pb 4D@aCD(BBLQـ*"*:c @YcYH:ETPTP6Fc @@Pbl eӢ(@QUR)eDT BA*" "sY$2 (ƒH  D )ƠA6XķL&fUwuɅLe lHYcd"*1b`DBQ %Hda>Ȍ4΅"H=/T)( L N/AOQHX0-*CL!1 H!F, Y4|F E$E"b[BaE@ D԰ J*B@(iՊ'e@Pb(T" F6i4KD%B!FADBT(4DL X61D$ef ! 4D*FʢU#@4E([l%*2DA"R4mmYכ!"Dk]"`! 9e+WVO2"DՠSG-N-------:fBώsN9 ;]JRb?lYW ,@"]m4BQAbDPbذ5 yR0dBE( % G`"F,S3MQdQQf4VT@  T ƨ+/,˨lY *B<ˍh!DUb,cS$,,.* (Bm E(#LJbT@Ec%"ѨL1Z"BJPHkԣ$1*5BYB*8@PF$%*& !a RJhXEE2D,1"*ec@@@ 5E QUya[/71%( *G`-b,[DТ rP*%*@ATCed1RZAbIưqDL@ޚCdQtZ1 zO+wuu0,JX`PAEUwDD9@D" ̨E"0 )wrm(lК D@" EC|5~0@E@e@cXQ::jmU ig hGv @L\E@PD("0"A !4f@PA$j,F A A$"М^( E0ֲJxy&XUزWٴW|XZ˪͆ ?5?] X_bgzff}幤fbl!2)H|!*Av̥S+34H#Y(!Pzg h  ֹf)^!"`(` 0j(!Yu$ Ѩ(` ("JlB@E*Ȗ%(5lȀpʥR&$$QEBARd(d9^gT@AF0LLeDP("1ju^!R2B #Xl09E|و!"qYp5DԇDA(*P bU($" ʖA""c21 A( d&}vvvgg E@cJPfFdP$kР !" T԰Ҋ4k..f$QlJ"QQ ŢYh,$ JEY ( &h eEYl(q ZFeA, iL\0(!B"#A%[ HQUDfPF$%1HhL4H(Cʫ Mm.XfBDfK>@֚XETcg($D IDAT*3͂IX"Q#hT@2L5 A JUvjeTQQ!c=( (Q5TA G<?zQMh!R( h1?g*6ě03?1lV+־m[V+=ӯRΫ,,̔WʨFcIZcDB`xAc I"h1AS!" !!IJ֘X*j K, AP dYE$FY5UB %pP@f"ʢ1ybriI@W @f@qlB%U#2B"`IDQPEQ%R(#bk+P4Y)HA22PDBTD"Xì!(aD%c0FP1bԈDLvFX4 D"Ģ, EET(̜&whσ*(Y3ihQYQT$"(A tQA%jDE4Ƣ %#v֥]=9Ib"d T#)0DUŲl1Ŧs, |Y@l8 "() 85"ֲ$D2!RbQ@BUa"UQ!&јVV*14Ә! Ҋe=ss mY"j#.2(.M (Kٹ$b8F!bFSUI|LF1 @PSss xd)  6JUQA@e'" a]ʐ\ZB`65(QDu(ɼ~G$^JQc%!10!ei,cwwW^DC Hle Msj  I9O53L̜<5Ox7on֞UՓ 'OR9Zb!F2 %BK* H|3fVb( @A05` #!1(J:Q)c fg@F$URAPh T`@ e\c@2'DL(*%j,K *eT u.2yk #hDC!SC@$cM%OC(HT T H "͢X\Xl,,""hQ4jTQF2(E2 3"(Dbc8*I|[kc@TSeGg2Ġ$F6$(18F&*BƐXG(Q$P6CY(3eYN \z劕d8ɽKs? /)*.HDDP1R44I4"0R DdM eƥ;0J.()`e1*F ePTeDcBh G$7Zgs!$PeY..kV-[148fAA,p˲\X, Z %) AI@ A!Ă6EKh$z&B"]:*KhEQ%H41G@`fLe AE)5޹+Wxs(B(D HQ Y,xD EEЀEC$Q 0!cf(B0tG>K[ZZZZZZ~b.I<ʳGm;g^YIcؓN}#7x쬾,b,Ӹv(˂ RM0DH@Q ,CY6!) QfD-2" C EY a(K&\]%F1 H ,UHBP"0' D/$$KLܖVUB" "yfyպ[eȝHd*4H,$_`A!6RmMTEɖEh..ZcbآFRaƨH cTaF,1e@FQ(CYFU`c@!d&[UFVoXC1  "RJK2B\Jx`,&KRR@ M $1DP,6@a~ `)/*Aec )7NKAb\$j͢,譧,A~01!H`¥6DbiDh,GUXJ#"CPDV$!b D[l4PDU"i 3"A1"ZHFHd IJ@UX h%B1324L)7E eA\02Y6P BE  "o%v<%d IXF ETu)R(C(P8CЈRP (F]CO[ZZZZZZ~uZՑoJO;t噮~oۛ 3/?xBmjFVf??yW^>nݺ ַ{'''NGS -,,,̼ܱS흝FsY,/-6BY,.̋t}SO>=5=}3{(28殻zȑٹKl]sfx+\DBf **Л|ν_wb/pJ% BX6[g?u#{ K[]w{}bO^},U^đgOz+.<ƈxu?qGl2;t}Gj)Tk{o;VąFkWylϞ+_]t-<=W^mdk|OgyZ/^njy/oiɌ>>Uէ7|:02vxR  XNT5;D{Jvxh}ߢud-q5aoYc1;gIU3$IWwI<_n]G{ۺu#f]zÔZz˦8K>;:/≉mwɉv^ _rEǏo߲/ 1_tĶ-{z/~;w:璉;vtuwn߾e\yݞ+OLN^reWLNdE}ݗ\411q;:;v}rrrΝ'v]691}Zg&''.Kv횜<}oue=/u~|NLL8۷MLL\xᅌt΋&&8Z;ޱcrrr%;y{?u떎-[ONN]]_};vn߱crrݿs!sΉ-[vvvm߶urr㼹&&o۱c]{~/cE_2q|bۖ-]ݝ.8rrKwe{Ϟjeڡ_:[a; :;^|d q>MĔxgI%OeHyk=KYxd$kkVґc{; Ӟ,qVYuikZqikWv^ :Wܰj`͚ }05e{b$av41%[5Yz::+v]a;fw=x0Mvlqxݣ6:zv9o}}bу6GG/rO1}šCݗJؤ.++A襻v4ɲZbJ~С]v4q3/첃ֹCڵsW_w(q|Сݻ.y{^GGC_~9#+jtt{iVk]e]H+_RK)"A[u)3g795LotPwe޽o`ͪ6 v]?4g:7so:㌳>{ӆ376|_sgyηytwu;c=Ě$KgUtÆ 8GXtb}$)U}犢xF݋.Z{闿;;0ПW/~ӦMy^JZ4uYԩS;[Jͽֺ$Q<,.a#H*=߮V_җcZqúo:+7.q'~NC7I;}׮]o}%֓ڥs8q>M/}K3k$Zw_̹Ԛ=sYgs+_w1fR[70}_,ޙ&do;޾v`߾3w65>>q^UI<9DUޮ8ƑIg"k9eoUՒI;Ƙt߾}$}wq߽fz*s٪Wxg Uul5.ulL҄\5y'}~cjjzԩ$OԷU'O2YcZfɓ'pzzzuuCSY⦧O Z5k7n<}+V9ęĻ5'OL$RW-_=7ݿ7 /x7~F3ٟY{g0'&オ;3dHK9%7wNo-------.9|>֑W-,K*sOZW}8XjU5IxgRֱfXg\^t%/ҙg_ַM}}_3{gT5.M|=}8{ϖ]]>/?mo-4YJRr˻{ے$rNT53)!2ƺއ|,uiRgfKh3vv?OwOƐdYJܲȲ]Js&_?7{?>kj2MoPޚβ1LV&?ZV !zͰ1:Bƺc-8##M {k1jl<`1&Yn9pͪm!J%1<_>!o}?ly0$sl0QWC9Ƙ*y|vd}{BHj1rJ-c02jyBpJȱX9B׿׿aJ*)[Bo#Ć=Mc.񾖺޶Zq! T[ZZZZZZ~UzNl^g4m}%15iNEY*2Uލ1L21Y,6@ 쩙?O=~:cK}_$% Xh&޵>e\: LRD#EqgǾo^|7tr_h yzچ ?CA_yήBUΞR )\bvv+0(q&JDBg-:ZqY<w! HL@_[zב#GB_8ӻjozk?O #YȨ7{~׮]fٚ5w}70Y 2G?p[np'=te3eY& RwxڶZmO]|C"@h 3#h瞻x 6Vݟ\Q"(b=uÕ:vC=}AEِ*@: IDAT9`$hTs$O2&QU@Ybxuõ4{ͦ3~|`ƲQ@&LhI&Ʀdqvv]UnDlkk|R;:ʀwtu7r+uT֗Ax>(]333َv[Ύ"H^%c>O_b,Ã|@:;gffivv+r-lLWG,3ggo2lwO7"|CbĮ%mVzf߲zӽ^wwu!,ʎYlՍ7|3"uvtcgg]][?{َny7]ݽzpx~n~Ūdo /( a5}ݛ~dunnOfG馛~1F 1:b1"A 6UjjiŪ:fі2+tvTӚ ub#IWn۲޾03/Lj!K} Ćg_zÏ=|p˶8-c-E|Gc6l1K;fa%j{ [n'n{q)mغm:4r ϟ:ؘo~[Qoy#`mא<"dʲs!ǎ}#c,.텅A ȘR _7z7v9ozbmNbQL;?sfќk6RBХWm?y0N<|-H9 Ag2m۶n/4'&?ڶm+@FE%Rںm>g}('>яmݶMA9 ) +DRٶmmijͲ9qb֭[d)( mn8QOǷl݊Qu).Ab6F543k0 R4 eDUضmoWMN7P/>?=L"A X"DQEVb"ۼH{O=ԅGyؘ3v|l-o}Kjв^n6}qF"o?oؘg[lFTTn9oll,869!Ơ""s06>>Mt喭[t||nFkDٺ܇~X{[D,n9o||$mo1!,zqD߼@ַȣOVo<;u=t[ }CW lZZ[5Ûvu]yֺ+Wa3kӆ zkgޡ]*w}[*];w.ϓڦ3κ9wvi_jޖ'%6ַ;;ںz}Sr|{ :Ё?85'N<::/ض _r{}c`Σ:K-wya'@ S")ْ8EOw'DbkuŖ,k%d+O'N)ڜ'8Zb;>!@RmJlP)nroU}dq99=u]^[}3;ܹ,mjZE$-J]q{w{wW]ݷ,)n#>kk۱colڼcWQ(v^W_ݺuKGG˶޹sW_[n>v=۷wvv]zcǎg+^}]rmb{.*t\sԖ-YٺmUW~ګ]һmY{اN\jz׵MMmݺֱe˶cv]q!u厝SSǮb%oqy[۶nK{um字^:}X};v\ٳdg`x˶w?CPᦛi?]iS}ƍO<޽{HDEF86*kt}n$iZZnuV-_U.ָߤ^?z;;whH,()Xұ߼sc]Ww_u+=ʪ˖wݲ;1_ƹs+2z>-[~vܹZӟK,ÿVgZ6;;w۶B -_>~x<~C=40_,./8q"wKR;ףG_ɲlqW\t/t ݕJoùso/b`r 9ocG;|W?ҥiR^(u |Gv^3r]׬ۦ /y}rJ)B2nɷ:.[zO~??~mőlo\>ztr2ϲW?J宾[{GJO}c\ϭ82F򏦎My>==FidBq?o-V,Y6M73*-׾_|ťN 'G:đZuihI"E\Lmm}m%R9cou]kKKKKKK^z}uM35ܩY mK QC3ҧf]egBj{T>s%!0 @⁙]p^Ds"X5B f(*йAh .H>-$˝(>h"DAiEġ0˙VFRltDF^ΓQ5#qAEV]3DGz# ^e! wF+A%h$@4HZA`^$ B6u^#M<!bY@ N.HL]p'Ud1DJ`YR.v&h)66.tTΝ>SoTdyd F R "xq+@bsB(קf.3!put5 "(I9PG&mmf , AqYH1Cc=HQF]PB<ϵY<5'F3K@s.@& V y9@B@ABx@>3RsR@BC"$> BOb ڐ e":t׷P}iY덌hhp0ljմ+\0\idFp<Ĥeʲf@J)UHf#'=}qW^mFXYtT:xm&H/ ̬16֊rr 2?{M"!F*Ȉ;yVڄѣ %! ^D-(5-------R\o&Ͻ٤)׫g6 v/9YOJ)6Vki]=7ę5m `1#*ra DHK ͪ0\1((N+w91 yHH:lWkFT򀂠Q0o0XDžbR(6Y1hHVO z/űB53 . HH(RV]DPB `YXJc! x !(/˚BEfZ1=!@3ω3C Rw=3(0 8`"+zmA,ԛD$x 3!RHs(yVQFyd (l}C@D&bŨ} 8rGHAD)TkuA񀂥B|5x@"F"$T)#y|BőIeJap;D@H (B(L98@^@0ꘂ'tV3#BssoybnnV XQ3k\A\ndM9 >W VUJxR[,νy_K"@Ț f >A xϛo|#ϛL|p #"#<',˙f9'$Hf!!CDB2Zb&B qD.~jKKKKKK˯LWqbUɡRNgksMUnc@ϝNۗ;<{g`A1.yn#%DXMFeV7y=(sFdF@0BV6IsipYp ź׳&83cy&  A=QPJq:$1xMőbA+QR\Pj %xTsH,h !"ynz 9"qe\" I,woebZ@!$$T^ꍦ< |Ys/A|.@LA+2(&%Fd$ li4+},FldDY܋kFAU ,( JNzӱD6YhTsWר!{ y2PUu%hj%wH9R3՜ >@pu`ń(FM^\1I>A>9 d.67{!j̚j ZۛgI,W콷#" > nv  L 'O6V_gGR# 8/An!*t ycy' ٙz{[ÀeYpn) }& q x9Da1asd])WN9+>"0|`@UӅD@#AsQ#eEZӖ_!͌v|g_ɭiN?>kqmQr}877 'LBК%%V&91 "2=,~?}l] \Lf.r L( >D+# k7F)HכjIf0KVŬڒHkD&sE BB3!#!:kuOIfA$0&FffhiU(j2DF$&lIĐ;BL%w!x!&H@b פ$ ֳ&, oB,Kț.w<x].)BA "XDΛMA@ Y8u(IFmڨyj*>BJkMAB ]A$ $J1Z)U7f!,F믹\NX#(jYC".G (y"fBf%˜81̩7"2!Eژ(}xG ^ } 9ofa{GHDkR ED3Nsz  } )B/AX(:wh" 1$ml$DٳU  D|tCfΤ\1odJ) ^1a[[qv.dY~|E\%δWQk?ٻtXxd>WOtԜ]8~b,4LlkR\tZ#jŞN"I""L ҋ;gMM ,I#xPk\"( a$f$R?+EDl䬡|ukmH̜,Z֨eRfR@  Sd#B\~xTV H3! | fb Xyʨ3or+ IDAT#AVD""m_T]="ucHШW Za!8fF@J k%"F@vA8HC.k6 3" "kSJ (̀,(1瞀V$5MT$>sw{gN=qW+[oxM;CG=J@7jFuElԿlȚhv'N8^oTYh8P}'?@n^|qvatMׇ|?xggg_x7Aɳ-_|n@"&do^\XnƀPP.y;A$3Z5sqO,jBXm6jylMCy,|~x:?o/$Ml6,X25fc!jF}Vkͦ!^dܳG}O5;;3ӣ/LNNݽlx9l>!KhXxtԱ{(WDjF V yUݳ/<{n/M_sYe ͢F^sG_>{{zChF#)A)Kc{Lrt~~nGG::X)Z^e{s9)t|yr~O'?YgW$Y3od~Ho={&_yZ|tG{gNysϽ=tp5k-\n/|z{ZHI+=CDZc&~nkJG>zw?<2V^>{tb|ʫ|;:.۲}fzf玫 Qrݮk/vYoG{_63=֨W޾ekom9My{oTo633}Վ+#mv^szzQ޾"fΝ333{W)W.~̎+vev9==][:u5il㮝۶_ܹ3fUWMO|J=~B!^sǦlZn+o۲eff檫N qĚDkQA1Zk#šUk..GD"mZpCFw?oUFlbcE$m6&"bXE&LiY*I?R,ċrFFYqd]jk;>>&Wmv:V4+}FF׭]ՖCûwOqbѤQQ$~Ϳm~/=6>>6#c>qII21>>{`VXgttĄfe"ݖp}/.###'&B4N8E$&Hu&C/ۍы*&DrobbtttI /_>:{b|_qR,$VKFԬ4}w/YѹdccEZQTX{ޚO|m*XhBJ)H'X(-ҊQP֑NK56 k[ZZZZZZMzo^v٪k_ryK}:\le/8]w÷~쟮l9`h5]#+l䖽߱ qZz{:R&6qYXXk"kRؾzciQQ&6.)41l"c.T{{8ꨧo~~>.Dyw4M iXi+}t /39t͛/޼⟍[֯2֚(V:bQMF/Fk$MtTJIöuq8#ckjOO_'ZFQ\JΥKEDѬJjU*D:V=??UJYF)Z)qV۲e%\]xHZ6RHTD(bǶTHJgd"&=FEqjlljGjC6]y++z{RcE$Z%&V]ݝZVؔ;獵FkŅmZ+e2qqaaUm)z{筍I4,5QZqj6:; +QQI(WTDf&4kRh6Fyq'FͬPiV[&uNJڭuw-------*3gf,ീ\mȊZZ_WDXsg7ooQbD Z?'|уH(7B`zfjvѿ7 O}{X?{|h۶_q>A Բ)>jժL ^@.[LVe3s}~%kT]LJbq+^ 8p|{gof[?O0ᦍ!ZoܴAi:ÆO}""6l[l|3[){M~SB 7"Mͧnܰ7mx`bPd` $6>u + ab|bƍqӦzJ1p`b Q`Ӧzʋ 31~7m7nx~f&VH| 6fr-FSVPQP8Oܷ_rϽsq`B J{|ڎ%=W677{_|ɦҁ+{r饟 'vqӢ$qjN#FQfkɒ&]݇CbL466.sIjQ\M=5i9|z}ܡS$Q✳yX9ޗ$;6VJ윋m/Idؘ1&ι>Sh1MKŢs.Mb}))&㤣9WR}֣wRq4KFcZJ9ƱBcQ,"D8rGkVw/xn YCttzCKFM"V"^i+5IGqVY\( R_ޭuǬbkE F{Сn:fk#"H'+W.]zƷ?ե#EI \~C_ʵVJ[H/_֊<쳿PΊB`,qdu_?cK`o[[ZDXkD:;{gmD$"I+|?#Kz"bȲ7seͿzQwH[k#iib5sdPZe YP=T[ZZZZZZ~Uz#͝k䮙&r^)9;dn4MVQb}.mOLvF;/R)_wÍ#+V<ȃHZt!7nXg=&^ [ԈBdsUw~˖}G9tx՝Mw=>szz8Jo:׬Vr{z$|9rn@.>ϳYFbVl޸C_|B ID(2lX߸gzȡCkV(\=2?7])); Tʕ<;::#:f^r[nG{nvQ溺}NQsNmm!b4;;!]w}E::fg͕$#w./WssAd~n;;BVUB(wB+VVQϗ˕]w+fgg(U nR6F+cuk~'/V1a/jr)]1<ʕ+(ZbÇY( & \/=pСˇ+t;b痌ՊP1ƒ_zCW/\u=eFa&YDgϜ (J$DZf4 $ !i%@Ňanͷ nw,kk۰vz֭Z?Tl_Ra޾5VXjp5 o[s5N$rwqEq377GhGqYkT__wV3ZcLdE$JJM-tdlX'-q 7^icVOڮBiYPнdg>[.U{*E}|T%UT*7)OH-IyC**{N_;ݤDi$-*ߢ@!T%$*{9w?ñ1Ǭך7m%ij3i~]wZg͛3gp`O?OV,]~ƒK9`)3V(MŴ$EcbۊTf*$uֺ$I_Cb(PJ.q+sfffӳKI"%)fuMMMi)gTv*ڴq%޽{׬FI録Zm޴ydxDkw Rs7n3lYqޞRA 3,ٷngL9u4hif5NTDM7 N~b߾6WÌ֛6l6R\sz%7d{ͺkQMwۭ7G?.6{|RڸqqIb3 !X뷻,tj\JKiLLIc 3RnkPR B%e{{TbMb̅)֪nlbmjN$MKRk1)efιvzzTli.%Λ$ֺ#UbgRIzzzDimh혚$V+mf^ ?7JAqE%V흝SSSmb+*O,:KJNȎ)lX+P~R DlJY%SSS&5ITMERni/Z;ڵ֚bvMMMb ) Ml5Rj")hzz*録ִuOMM))1Hfv(!5ӝsRkSkMҞSSSZfN\ٺuI[n-3 r):8cRHAAIAJee J)$X._ۈ[(EܬEMs/))/dyNJM{fwt-<{ْY9sg{```Mncĥ/\x /hnUcW^qR5k9gaokςEi Z%V^w~dĩJ/os묎NcEVڽkbbbffotuu%JƾaS{J^}O~򓙙'|r˖Kł׏>\Վ>}crKbeg>; yo*Ҧ^β?wu ti]s׮Sfff^|m4qoL(Zk袋vyoۭuAϼ{zÇjcw츷O;-/Re/ͷlѮ6Jn^:pۍ7[irF'ݲ_ IKd˖t@[oE;rVv7tC3ŏ~^|nf6Z+[}<7,P*6G?ndkG[__G|>z͉tFrsͷ8qUH61 HcQZjNq>Himo~{w="4BJT=LR9k"kJeۦr{wǎ9]s0DoL0]]skeֽs眷d_lllǎ]Fze?8W,4_oӱcرcv>䤜;g}6cǽsuZp 훌Rν;v̛ZjUnycB9={XV; ~6444444O]'"a6-Ug2qSH j2=ӦTNԺӮӧOiST޿푙@B}d1Gff@#CRJRG`)esdR$!eS85~H#$% d5&#0) #U-!TrA3@iy5ˈG`g:LUNȂ#1ssd&R \ U@"(}RG)e }@&TrR({FT!^J#dȳF#, ( -PjZ3j+ՙ,2FOOMR!ML^g3TOK@jG@@"cD2&pIvj-qvwWȳDl !s$rZL{8 #DR #( DH/q($ 13ZT<5!\ >H DeTF& cO#4I\pwGq,t-B[{ SWhn㴡/UN4Vg| c۬LwD>x0 @@$%  IBDf)("& cd$#@̂&9fSC@DY}ZjnA+-ITff"r !`XR:5:-DXCJ bĎ#`1B"2RZ !@dAȹ< 8gP H-d1`׎>,! eDU%)&`@,׍f1z!Ĝ(j>31 V,8@)s,Wж=ks/xW20,1 IOײ G!!R1;EB*!H H$dGU= q L I8 )0s$ )3F )^0YPhĵ=Q%aR㴡^ɏ~, =P>>sjlPjqϪUpG` K%=y$13{o(+ DbFiJ$2_b=""KPy9 BDI!Fǚ  2B `Cٔ1DHB!ϐA I)NOMLU& jy&!!F"e@) bȀ {U$3rD,(1D Ր8B̽ `dB@(A $ # By!&ƨB#b^ KA<53EJ(1sG!F%;)0 "e>eVS3EB> B0"Ȃ Xzӵ<$! DF2 @!Bws^yk+yTD D@DfD!6!ƚSS}!pd<!c=_ D$F(B཯Tky1sI9DCD#!Tc`$Q= 5RA@$bJ8%jƨB*D"&,_?2 #@d3ӓSJIB`91z$KDfR ύ@E F"ɈTn;ZJJ9`>W<@ bDɐAHAC>0 LMj'z4}j>ՙiqdCCCCC-gb_9~pfjPГYmJrbթr>9vx4-[^p1摈9,"k>xIi g#H>DuIPOQA$btNC,DW,LEZ  BH yDL3B9z4c (ud)E02#"IbV3$JӦsH>c@@-Db@ I(!*">0Rb80T¹/ZW@RfyN};8#" (2!13ȿS_av/X/< `JerDs ar٤R~|j¢LIIA@1c(f<B!" !I>x!EV(Q^˜3"*5AgD2P؇2_C{$1*)0"sfzBPJ< 13= m$ڼvPɇH!R1ƈB2bSSk[kN>rzC$ (xR3@JY" Qͪ(DI1XgD= ,>D!)DR"0/Ǒ <9u$y(($!r#"' 1UR20H i:"2AJϩ7#!Q)",B@=1@( A*dV!'OղLe##BDDB i-k %"ry>J!"pM{,0 Bcr̃ ָҦP,D;~3R$ ,BD@# B!zAHBD`f1r LBFDbQqd!"@>qWB0,!DB>" "< !c&9@1"jAG*J`dBP"!`!dL$|̌D>dV37 x=1ƈHt-FdfB$2ALZ<1Jb 8Dk!J!w@r\8`ԉ+ۖd3D"z!DA9  Xc @D#PZΙst}<5^D̠BR_#blbrR!3FcȲl&M̴1j0HbM"@@HHDG}Bz!J"#̜?mhhhhhhpW_Uͳəlfc>=!D<R٦sL+MƉW&LajFR/C!ɧ:>ګǎ?|wKo|3g/ I+CqÇoxg&'N>S6m"bV*j23}Mo:;9~'ŧ?BX_QV'3i$ylc<3ghW:::z/4y|Wnik럿#[}ᷧ*\L?>=3k~=eZs>399!xB{n_ ,n믻>FMxó??~Գ눐6nSOMMMnR7 Tݼ B7\sN>scȲƛns3퇯c|=̯͵9At 7=S&^x~ _OHLpz>r7瞛>|-{ώgzOOqG$1Zg>d!Tkj6S>=z_>_|/K8 {}rpff橧~?yok#&~>w%D{<835맞?c|yW;4vĉ'OSiTjjjmm]88x|@efꩧy1v9ys/r(50;zԓxK/}-oq}^>8~~_|/ J'vۗ^/~?A};}u/>6'_ y6onWKN>/"o{xգNq5 y=;W^:0=]}OBCG^=Ng?={μ9=ͻg=/S=gXWOVgNYRNW,sYu&kytI!1i 3;1N8fv&UXRV(cyց iaw޹V,[zС?'/XX,/G}T[zѕ_ޱK^yu[Z. *IٹRgc~nشy.kݻv6$}7ֹJgL1-'??83[ shaR;}-=ȑu^jؚ,X~ Ύ=G7j֮Ysht=~]vUZf襫.ioo_jW^i^fCYuqGs˪ W]}Bnѕ+Wu\jᱱkV.]͆C^|I[K_466zWj606:vk혵u YϪU[[V]jtt+DW>4:jm-+/pttCW&aYntt Wv]z%c_yjkFt%--+WQk:w4xᱛT,U*75]+i'~q m۶sN)$3;Z*JJ%H>7l۟$ ܹH.\ȑß̧ ]ἳڹ'ؼysKI:^֭[wi9c#G;@Olظc IDATn_۶|d+ط#G/>x`u9ݹSOlھ榦% m۹sW!-X~Ƒ#G>-^›}$x≍͝=;unжwR减g?h`KK[w۴?ظqc&K|uǎG}4zْEw,\8X.tyv<'ݸqܹqoھsNpѢG(s=wΝ?occYs;cC_}{? #Gqg-^^,{ƙwJ2sy FIEh$VmcF[dSFqNS,:JR15J2Rjannk\zfZ*or444444QzaS^88xXsi(7{ًf;ncdٙ=#z5[:igmɸ3,w?B)mnj$H1G^Ͳ+>dB7 |8i,)9W,}sSHL꬝{ #.IrK 35ZIZTDbZ\p{Mg,;vu\*q&3Vqgw91J|w-H  /?֦}s8)RsN8k&69&[3tъbZtF>۫rR} -h||W i6ϟ %9RJk50'Tgq)=yd^ci3g'$I Y) ihᢻ{Fkf6RK!R -!Z%-Z0x]w޽Xu[ogW՗_~ _bs*F*%v,+w޽uر-[n}g_lkj)#KݏW^Ŧ&)3k#UB1J)e43~ji&Ų+1ƹgUJigv.ui8[Hd1!hᒂqpFGO[mA4^xE\qag\p>[{z/X>._nZγݝ=is .~sNܼhђ|;ۆ*p;W ߹kg Ņ ?}g;J?ࢥVxw}9t^~9Cۆ{?.&Qtwz3_+::[fu:[_FKcURH&%RNuNGsXDNjh?FGO-3Զxށ zXtY ߾睝m<{ֺW|zͺ;>%,ݺ;Ml$ʥڵ Mwg=w4aBkk粥8DdDi+VPl26ID(^pNXm~;~bRzN:zҥ˔uhq΍%q޹'O4a」쪮i7}F6E#ͨLL̈f;t₩o\(Ƙ*6v@nA,Nh$ $I $B fw9{xx-wsϺr\ںPclsvdْE߿G^ݵw~8봈D\V-OvmiȸZI~h讻]ysϣWE}}8;;>>6wlcL'uicccsYFYhllsnGmbFuc]s:-&1X֖3f9x`u||C&Z{1٭u]dbݵo߾BZ#qne?桇4֍OLt q8D˖Eq]ؙ$^pI{)2FGDs޷MQi"Ys~qkC]]9ܹsٸ˖,8N(uq9{߾}J+1Yu9ҤH6Niid5{eG/]\Lbkuʥ&.NSkRq]sÒ%=3c{SQF5jO.Diz̙R[Qi`tHC\PLCk,t qъ?w dA8H到?ןƆ ]^~:f95"VH8].+kш(rn]52j=r̓+yIXRJiuO0cI'uxk z,,+`xxk>O?'E,# |e絟iH "t\΃" > p[n9^P3R)OݏLb&¼vן~" /BByA繵ٹkg?SO9m{(,bzV a%_iq^D">p1It2;>w͵v:mA9%a޳JVc7sLkSOmKtM!m "(RZK^Jvk9ӬS۶GVJCYJgΗ^uםv)~ ϳՓ1ČJs>(k H<!gUG˾\*2 Tb-Hz B͵xK5jԨKۇO׻i}KZNYܻhn{s{[1/Zt]s._᫮9 Q f̙Il޼_`~w8Ƴ?xxIJ#zEJQj*Nd]mbg4םp O?~o S7}u'}SΚ} FGG?٫74p?4=C9eɭ-+GGG>FN[Mqĩq9qgyF{{{}}%KާP(I,"YgLlLB4iZvYuO>ԷV{~!J;MOlڜ{9###+GGG>,Mt獌 lnn\rtt΋;sGFFN?ֆwsY=NZR8?::z9ȝGFV764c7ȊV54>gY38cF{[K-S"R"icXDZK ؍?̳ZӺƣ~}߿'tZ?ؿ}M.{GW߳q3<>M-^{ݲeK'裏?˓׷GeH?gqƬY {7?cc?vGta_ߣ>zjƍ<㌙GqOF{#<-{ᇿzuS]'6}3ftѢE~{7o|쒏?9X.\GW'6nc˖-Kt%>ȷly>-Zzbr%߸cst}c%yիWc߸3Θ^tѢ|lE?cˏ8nɢ>V+6NDF;k6F;Jg?{>Pxq}z˖;SPWX(iŹ(#]Kʼnrqh@1D0{RF5jAgvԷRc{Xkܶ9]ǽ%sfwn_i٬?^;Z,* ͟1g?(Jo9X=880~Ηw~_koiXb*V)Cxyg?3===11ܳ^q is;ܷfϞ=J7>l2WӋ-Z?طo_wȅ\߫ͫfYk׮O^zlqw9gf{$uMM>\9b%.EZYy;zٳ{߻wά5+.ߵkWevr'>QhrW]׻ve+v}K m͉W^y;򻮸21E\yŮW^y.usql+~'K/+z>q%ʚ(R]\z%4+zK>yqH_~^y]Jŗo^}G/;jAoG]U_;/iQi]_+c`lJ\u~ΘBd#WyK/Ligt4bphÆwo|sf̬$#uj1Dhhm;;ioO?]w~ 1+W/߸ήΎ9ͧSȏ7nf I+6l~կ͘'Owoփ?}W;n:;wίjkiHWs~m8>wGww6578OZ>;_y_"|fΝY~lliֆN=upÆ;;g͘iKWWޖ;1+OW3ۢ(}SfC]CCH䬳&g!s޹~czzz||gO&&Ib[i"E:r.o=/NMKf"8L"Eq ZuZkԨQF?s=4ytf/*eu9FLdT2c< 2Uhi84 đ_ܶ+O@R@$ "9 "BΈZk!RZ"ePA (Abf/eKABA¨u(BH1H$0UJF€J&'9d(B" Q$2Jr&+P3w^<` Q U|n{D$R!A4yrAB NBM *%3,Rȁ1 C`dTB,0D ¨P  @ Pf`B1Jg7FyIs` b DR$ψ)J]WA3F)])MKH1( hB/ Q@FHȁD+bE o#銀VD BDATDt9r!O j>DJ VEB& Hվ#$=wzzl[xμawKQF5j1U9T-աl-g6NWlsCcTΰ"7}Ќ$I:|hvC@|55? BnqqrxrJ+ 8H43kE< HrDރ^Xs`VJ)E:˘HIYsE*9@@d!+E,rae4'jQ5*!AAŀ(PG Hi DRI,*0 {A` 4 &H`&A"7dyX0"sfVZ"tIT*@JQzR:=rQ|D8  "D(U2*H#2@Vu8@_Ɍ, D̼GD:&U9$UgVH@J$h, C0  *A"@f&k#540mj=0vU!V@@iyIkf`! 5 03d'@" #*2}^ 1ZeQAƀDP& 9 BV 9{D@AX9g EL",n!a@(DB7J+DXX$EPW˽D 2RECpʀ`΁1aDajhi!Ħ{뭃<"-)1$(8@b<˨"=@ȌZF5j_"ϳ$MJV>ijl+7LO@GP2?}hV*8>,3S3RHTTDv)$$"|% EDX)BB>Q@L Ҩ5#*@WB93ŀ"Ed" <@<"!RrֈDD:0`TH"B"шY {Q̜=sy=Q@!cY $ "՚E UQd1  Y)@Hk%>p`)MU2&MdK <5%` tAAH I)fjYaP9\#RĬL*ePY!x >s (Baa<˧'DiV#+C13H@(H@MJ1⫮"R7#T80F RHZCZ !hIk5$lrP]S ZS9D@R-(E *%yH @IRfe BU' "YV !,S֊P%PhkBPmJ y ,"B%"QZkVhQ @& {Q,yZ $$T8 "(^¨.~ͽ{C>d OScSF5jԨ?MV}i%_3v`9l}E?UΦKJe,EjeSKw87v8*74! is>sD@Q8p% Tc/쬩~L#YP sF!BAE0v3Fz< ()( Zma,*HijAB&h,A(`**ym(٭mMJ RTT<T4Rr 1 *eBxsjH!BF&5yUdJ`B"@;DDAk"(4" EBd΅V$C@m BSms猠(~ۦF,*ʼ Zi 5!(E @XE0 a1V!B2>6FOld9TTHA9++RJ$%DX!mJ35!SXTI {)'1di i2TʔB2:GqpD, Ja^M`TDQQ>ΘZc%AeՊ/yf$> [gY9`3 ccc(FB ! ViXiE(PתzqrDaAR` P$(BkM ^X;9 +{`Ԋ $0 !*`f!@ J"P, D J!W+2T""FCX 6ZF5j_ u߼ȥ?or>Uݳێ#z_xad,7D`!JP5ˠha(UWa@5*miy;3FыA žC^ ,ĀA,h4r)aOFe V#* Ug% @Rц*rgY ! _Hʈ0pY!aoL˂CRD("$8kc$S| ,P*X"RdomaIk"aJ"f!$!BBVZ " ,hऔ($ h54qR,D*xqڀ<2]JL8pƦs(`a}h GF`I8 4T",|B[5.qRBZPXbC૓o4@seJ@(QH(TZV BBϭQ3oDR0b%RE6H)< ,U$xҺkΚFPEXs+ydzϪ7S,@H()kL5PkZ)@a<e "GaRZmR!ϫwhRqDH+m *3ʈqV[BåBBCPQJiRZDHh4!5sO$@ " PbPMQF5jó;Zgloc:vβhF]0}~a9}3u7^qƦsZ֩yg1NۆB>^xC}N'''o߾ښ[]?b8s&"bh~;G_={Fs 7x#˲;v\x&W\V󕝗]vY&Ju1I\(Z>G?|뭷&''o~M7E űsiRH#1{w_-{^{9s' ]v['''ov7)e2}k7|3Ww .NXnoퟚ|qǎ[o).2o͚_}Oe۷o?3cN]y];߾jUSC3qdޅYgQTyxSSSU-iKo<=Lg'm{n~-45G:v*y[mgy椓֮]W϶mnHuookޖ߱}g/"͵߾+֭];|BjwqYgY~߿rrj7rkKK[ؾy`;پmm\Yܷݱ;?fp;v˭74kR zZkߕ曛8xEY׳,۾cwAN{cǭܔ6ݢ޾zU~۶3?FkQBD99T*#}3fΤBIl#l3Y8Z5im)qKk~K5jԨKۇgwU'=zgΚYl2{yͳl7g®fD†goQz5kXs ?tޖ'lkx_\яuvv%qһw=7 &*Ңuu"Q$"8qqg{fѷ>{{o߳{~ 47W{ʕM-+W|}ts.&ss"3DQ&/~}ήiZ?{rĺ8 "bHZc8ֹ%QToj]i^7>nzz˖ .HgGgC]޻khhݻpqu͚}ahie˖/PwɆ ыW,cOorEtq4~=w߽ah(nI½{|֧ţtvtgAuhc,ۻw7޸dY]}/~ӟhi .HwOgX7l"hq޽{nE5?0~zS]pтu z^?%Kݻn8fّs;O?}Euuw54,=|?OwO7~ƾipQG 2(m ?O֯5ȈȜԪBwuu}_kjꊅ86DYTDVQkƹ(MQL\9i5F5j= mݾ57kgޅݭus#fjlnhn%vn|X)zե4J[ft64=iG#8EwjƍhkFDctiRFcR)Z*bk## "θbDD\Xc6i'P799ҜV)ras4EqTHSkTیRHp?wuuņBe5Yks*6i;T*֮k"muFk\\,6qj(rnRh[wWGZ;c#ƚ(N6NbfJ%gk%Z㌉Ld(2db紦8KR1N]}583qw]xIGSccڔƩihY*"]k#99b`hլRGڵ뮽:mRq䬵"%4$ڒ':cS92Z2F9q!IRƵ6J%̺u뮻暺4i2V[g29mg a{[kT[n5^8N &M/YQDZ+L> ~ګ A!vQib : isMͭR)[w54w($uqRDJ+g9g1ֶl/Jֺk^}͵6KuTiݬsZcCFc\sskT"?X^ȹ8NmZFb2XDi^*"nu^DQSqK.JY;bR"fEaWع(]cI)"P,NLLΟ?11بv΢憩(rI&62d .&:vڸDN8.us:[ I]l )m{i{SQF5jO>zeW|5/'77շϞSaنƺ6@>i!3~b!0S[^N:(EHv>|h*Dg2j_7oz2˼{i(^X|/\8=Ə}ҴQ;=gά[n鑇A D$xGySV AG! #JB,"Јuw<D" `ڮ]SS~z!#xM3ghsκy` y Y@{zzK6=a]ѿbrrgysm/;4[gR-\/}iӦ'Ps~_zU(s90#`Wgm<[?95C;^|qqBhl;ؼiK8tsÿ>4=K/|mZD%(c::}զOP^btW~ԡ_޾jխ3$֘gvwλܴ۟0  h:|hzrK;n$J6>R z۪͛6) ÿzW˓/zy# %dVժB*+4Eziwtv~K_|MhTɉvے4'ĂB=~Ǘ6m$ niݻ'ӕJo5 IDAT}OI'c;^~ƛn"{&E"l7o'd8|xgy՝/+:BmM6F^',_Cc/ª>:361n(A oi&k`T~ڱcuLJ0].F==qMiE/{n[o?%@J"sE9wm޶iӦ7z{~ܳcc/ؾjmBp䓟峯6gӇJe![}Y| JkRYs`B"y%O.KyO=̟UԨQF}xI]mY<K{X`ɂ93g.;bh;{ZnS޷wnϸ865ݶjp\ޱm7X[UpQDwvu-:RNkqq$hLdF۬οߺ[nItẄ́:bZoA'J8.4#.XmT䌈8S;m#5I;K/1{n\bg ]Llb(9O>ª/ػ(I`ވKfU2=v@3X6X`< >w>V#ϖX4fHؚEHl?K|` BHF3ꙮʌh@>○s+2"3NFEM7c4cGXb槟;aƒ>xuժ7o<| k4yq}FG!}_uW>thmYc(k=Z5߼y~{җ{}vuV^s?ZiCo'q +!#>xW^~OަI31i᡺:Б.MX+ϴO=-ݵY>|h}kW^ lzvnް÷oX?LJGk{yT+:}vfDwu+2kncǏo32:ֳb҆fֆ5k6qcUyw3o/os]rΖgϼ./ڸn~SwΝwQ{?~/U[gg&f{/2W_Bfu]5_߷9޳Ϭg}?~g\QJDب<3ΐVG6f=o0wg{6os~g7m2yZy9X_xYvFO>1y:kM{-=p>64=5ŬeL,,,tW7ZU6ۻ}9k&'ee^uײ7,.hx-&Ǻgm޲;P/={Ciomo!c1.ss6ݻzϜ%vwz?99ND,*φvVkj'"^[ծܦ l,Coڰa޽pk?9L{k+.(bfHiy27a]8 -^tZa|dtg=[o [ceٖ[ڻ饥)(5O?Zkﳊe&}y8pviiir|<啼nrzaaiUu#/;}wu྿,--+bM<=>`5Z6{ۿ̤hƯZXXp63= .{8@LKKKSkYgo_XXpYe2gn޴a߾}$KKL[a³lºu ˍ",koٙ'z!Ś1ֲ˭J1Yf6jVH3]U yKGGGGGIO|cў7_vޫ6N''&ݸً^~ܖy\|ֆ#Q542<{ޫ''~W2Wae6N5%˵J̲5Q3sgZML[VZDHwƳʝɼT*yՖNl++gwgae,w{9ʬheaҗo~UjM-w/~ѲZWm`jrڼgNgVm4VF+Ϝ[l6[XD5C瞳RɘhmҨ7>R%s:\i6/_pі-V*jb|tqa!cӕѩY˃f}IT^g2cg~hhlZ}SӎMww<=1X|%*ksCfyΝV s̆"kYffˏx}%Ϭ֓#Z[g~lxl}Ic㋋ygEY]6MGtX";qx˽i6duS3[mUZX\z)VJ2Cfi?#ff*,[K/K+^v996ZFֽ9yX!kYcqgp˜>WfE?/z]=Z,sZͰ^S+Ufy"JDP}tv,H,Q_cl믿_~5Wf^Ʈzx׿2  eZ{#Ł.C}n=&vڱs֏8x !|uW6333xѣGSw>#Sf>O8x0J:{kG&ׯȍ7Qk]v}ƘɏzCzXg'&n#G~U޵s;vlذ1EZя ʫ^gp 7Qٳ{ϝvl9,k|_wС檫^_&Rss7xѯ{vwo_~v~С?oZ%7Z~ꮽ{s 3˛6}8p$C_uk{{{P?GҮ];yܬVνw~҃WzggpÍG%H{vq睳Y6a#tu +ϪR~"ePlxx|]~˿%lCgݕemX#@I PQ(j7t[::::::Kz_W8g96OϮ[?;}ўuGGOo4n .xo];c_~,--~߾}T૮|߿l6z꩛oy||Zg_e"ͿOOf饯k;~5~z|b]{N?nO?wϞq!s酗yɓ'˲|hIwE}x6wb+bjܶxne/[~7+_J\ZZ׾@N8nO8g1f핯|Eo馑!ͻY{̱cn-=l+.EvM +w5}oGz{ 󫯼3ܙ3gO=u7 ]q'N|[{+3z'i}>яvպuWl>}xCa[s;\s۲Wn_P}X{?~Ê/xZ'M57>iregm/߾oEQ_Ow&eg͔xX%"Z4E+^.$MW}J)w^㽵lۮ5rSO}('޽woj֭9OW9;9YWw8~td^/r닯[nyh4w^B}nn/_yg~x}|ɛoyxp(b|^(}}}Wگ=ϜC9̟]﮵'>v@_3oݺO߽喛1g{۲yrtw^诧曇rg?-}CccC#O>]Ȳe>ēֿp1EqSS[6絞sϺ Q(^ˏf1פrqUo{?=M֎=ojtԙS{jjMɢVm=jE7? )U4x]x) 1k ˜J¤ST!(˘B ($EĆ]d,B $ $ deM%GGPÓ}"Qb"ELfc !Zb4Q)!"ȊʐjD I3iX4eF3VYXm֒b AR>Y2j@(DSZqL 4i,)I5Ă BD5 nT \6#!htYJVk)SZm"aߩ'%#Ra-Y" |jXJA0jP Ԏ!@H`PcTֲEЊS, !DRƘ(1FEjh.BBDPaYZvnrFI@e@m2,R%k-5PZetXBθU(h0%y.)U%mZ)Jb*  &Z! )Mj+"R.WWmm8!)EDP3W5nI"H! ZwvjcYJ!1e,) (h=ݹ)O=(@J%(YH(A 42ʺP7Ǐ|H6¤4%Ҥ]{)E%eFPDtJ "Vb$X&5߿|RBD *(XR@ѳR;::::::~~g@=?(oXF<]XQES\:f$e}yŇPB(U$ H!D$FBvڱT(!CtC: ALDeR$bCLJHD@bRȪU˧)BI)%EJ@C@XjME!\B"1B Xvh#hHQKBE@Ijeʘ1&,EDD c|Xmj1%ֺ "11R "!1&-Q# 0RB(#%HLWO@-?K3&4d8W $FKF\-REvDRDRh.$Q `Be JS hH R)9@lX՚DY*& Y*cI"% QRīՐʜ,ehEvB $Z R©25CHQi”P4$L) FFA)&Р sL$ rU)P$f ,E0$D`"JPInDDRR HD*WW@D1$ҥD!Y% "U&yUTc  $Mn4 Jb4h Vk$j պO<\(AJeKP@(A) dP6OLL-"DdRPb,S(%$LȈZSJb !@R$PMUZ' ! 1LJ %F0XFo_s܏b&j^6 zY̗[k 3 ɞ9:0:p٤M^?C@ @eCJH*!ReH"h%!&"hT!h $"l@ 7cJ1BN1HB@v2 @"$ Qvs(JHR!$"JH42P(1H)XcPAJ !$ZiaYG9$)IJ XjV4%H)"!$JB:Z'Ժ, gyWe>t4[e $*$!$ĹNIbL@@B `UeAI)&Ѥ"DP$&HIZ$@$ @JHZRr)@($ 1*Ee@hb*KkYbZ%$QDB"DB DP$$ J("P1B0 )Eavm E;I@e *ZVD QX( Ty^˽"nG16ZbjD*!b !" *D2͕vD!2ք4ږE) Q$"\e)I{uU+!HeQ([.C$I1 Z^w [=WSc BX;!D@P2(lKj[26Y^mWk]ϟzSH!Ť)SBN(24sJ J H hUlDHD QEP),RA'_`s=jq9 YyjMwqCC!FJk\m@kEDD2()%R)%A 1ŀ1"6F)BI RBb(HR! bJ)@aL $bJ@ %  (%P(O! IDATf$ I "ID60Ƅj RBPaIbHA@J[A bJ()9c@ԎYB(JaR(R8XAH n IB)Zb4+fsXD$Z)bP!,|Y!$pHa $DSXg D Ea%$I@RL``v @DD+pӫUDDEdE 1&Ybe !$ 5 *J$I L S1"Rx@o R(S X&ŨH )UDZ@)AHEQڭڃ!!BVDD1(Y)0JT<"ТZ$!A )1&D ELQbJ!FL F@1D!pmIB(KIn=sXZU1YD?~ CXbBd )2Ln &fBUVs !N"$b`A %J$D}hG$|C Q HL(!$1 Jk$ D$"@ѵv]RRD8I$R*2jh$""Q(E0"X灔$ 1 ȈHA)dIYG""C $" ' h{zbVDDR R"b11Y0D D!fy7*HL"vPHY( 1!RB"6)JƎ# DYhm%DJw%QDHH+e%RD@jh+PD @@&1QIVLeQH$&T()H Ձ4+32)J 2(kYߐV1?nʢTk@&!HHeL` ]"`Q!" %*HT/h {n>rϮ,5P/R.|L*OQ3NgNzsƃ9`12IJLU4 A0FW Xmf^ M,"!b*IX$JQI)b"(c*w'9D++D FS1DR Vb@%! D0 ;jDMh1$H514H bmؘ֪vB"Jb 0JDva^Q\@)@5S!H2*l )6\f`jaIHifPJc)Kg~tɅ&*vAH),c  "(MIC z$R BJB"JH$zgU J  )E1ђRBV( PB @]̩Řb+ @Xk1ER )Fqfybn6N/-!3$E"ĘDք˂! ]jBb(:HEOt)$:yd!l]s)iFЄ&\ hElbJZ[>}E@P*JI^(K@HtJ BZ[.BX(PHBA.2q eIC@8| y]Xb,eGEa XA$" 8EQZI@$ZC#& dXR(5+6.] b$I:&IIBHf.R TJ&GF:y;:::::Kz\74aj7>36qrӹ7mxṩOόOϝ;95qљlldpbb|Ԩ윍o+Ugן~Vo[Z&Be;m@e8q(o[7ܱVv WydžGFFwܹOyccjRy!E&8۩]v?~wVOoZy5׼n|b׮?cǎё!g{Q>hFkMhhpd]?-s׮Q*fΏBw1:2}1~n{*/f{Ƈ{*=cS;qV̳ ݁ͳv&~NsBmV&Bsc[ֱcvܹc>XkgLnd];ڞ'v=:2WCF$6[722}ǏX]cs>uyv GFvyVuرw962_teZȮ;;9>6y MQy7ލvg{~ꔶ/4)&1fhtΝ/ݻGܽЕ]y\ٹ'c;w1?&SNi 'ַuΫkyùuFk֬5e@vÚ3&o*/zPydWV1Q\ gxل%U-$* jwKeڋ=w4RٳgͿ=6:~K^qϧkީ~‹^>:2r0X}I2̎ $Z3"&;3RL1{vŕҷmvk޻P陙/|7/޾;ߑ~~7(b ;0!Zk\f&&~{Ů9sΰH>ēOҕ2_7[6 eq/ob[JYI9ǬNQ}K^ط_Y)RSힽ+.zv{ϮBYuPߋ;mWl[_ Jf |BR|)By \q} Ʋ$@"߽,/K/ižlfek,[mnmf2)6R*g tw)4> WY_77vkΝ"qNkFڒWw솇&{GU1!!MJ,//Zž{AR*7 ) )Jh=e.zտ})DL9k e1߿j]˿ZoX{wޑb zz !}!ĭ[Kط"fcIsqvK/h{KEJeY9BؘV˯drdU[/;h|ݢ )6 HeAB{eq^vvJI);-ZĔf޻Qo;pe[w'ל[?|ΓWl{eO[mocCSZ+H%[cj* $4DHeT`g㿤'١Z٩ 6ͯ]ƻkCCcyp솙ѹ Sct9n}_ɜ7lPg:ΪVk]Y216γE9a&ZD\3Fkʐ5~˾bjW}oyyZw⦅z{g̚R_ojY7J5i"Vg[ֺj:88[1Ʋx-[g5Sԟ韱{3Vl4F1Xﳖ-[gl(69촲Zq++@)vlsZe}fܰ#ʴ16 3iff;\Z^^g<ىZZhG;J[=84za缈8cFkLϮYc@oњIeX92{ F10,{g}Zΰҙ͙-jd1"b1l5Fkk3tǺFӧk̍ft 4YRL,"Fi&kJ[Ʊ]u^D]˭k4uk5ư ///[kٹLD]jZ!F1߫B9[^^6ĚKD6m{,kh4ꚽe[s~zdhyU;oMuhpXD[b6ެ'2Zf]X^^f͚YkDգՆ@g6Zށe{'"̚x5Fcxbd>;^3vX]n4Z+f֚弒oaW^o}h45c>ؿ},ˬeq )ԧ>ϔv8>ꭍ}S."&-g?EGypSXUF%H_%VDDA!{L?>|^$%?:6fL9tP)Do3 "x܏==t+Mb R\kC}{ރXkR$'~xJs5tП#c{{8_4ʲ:p}"ދȘ3"35 )eKJImʐhl$!-c,&KʔmpU`!)5!HI9gFsOPUkk7κqzV^XìJ#|f護ۻSH@TG馛'&q}c/W !($e" !۸qGo-b(y9r %'Gy#8WO7ݷnTJChT"1<o㓳󛼱..|{n'o9r0=uȑn^ݻ7}tfz'fbjny߾1fl~U2]t/Z'`c̷>h5[OYQ˸nQKMy 5fg&񖾾Jzbnjbv606;9/زB}Ν_<af~s>1P~眳e 8{7&6>~7;ΡCOvG#{`w>[%y-U5,R''}ML_';72:Y^Z2DEQ Uʩ,ggRes;ėKmwNU!e<`ĉA3>;a"I|fϼTut`dh:VN,YiZT\-uf:ayxh8[ΜUa6xoh}ld{,Yg$p콫'hȘs1 z?ՙ4&.VU~ $ RWU";fCTf>C58ǯZrDlTR.%xkJYZ~z.-- WGR$9缳33./-DȦie 4a$VG~y84>6❱SV0ogF*I呡krj{/9N{:Z5rƳOzRSZ}5[.%nRNLU2R&6Ͳ-?:܌O% XUͼe&6ֺttdG46Za_]x*޽;Yg{oFsY ի\ &TK\Ldҋj______ߏ P{? DD2 1=uRE=@Dr/]D42V0=uuRڵkׁK ʥM~($A"czT1}ܷt$޿f1b&@cC&Ɲ_ZZ^ظ8XڴeyyyaTfbŢlZ\(׬TTJY⼵O-;"ֻlӴ!H@Q0"Ycvڵt`yӦsJKK칟ѱf/<7QJRg,MKYN)$I_-+8F;)1FQ%jyh KK6/,l˖KD$(yn3J@B&޽k4==??s.`3=g>s׾v`~~c vyTDEw׾9Kvd4q (jƅM[6/\޵sv&` SSO>7yld?oiRJSX"D@@$8-glq@UhuCП+@g}j>~{˶BԠ*(EZs&"hB.E" `(<ޯ'COS Ĺ^xəZ ΙMalNkYe{}:_J4J|}X}mmg4˥%θԧD2.iZJK,SUɳs1!{7:ulNMmڼ>\-Yh$i}#Sl%I>_Wie%g5{̧%do IDATam)Ija|6Qv;+gPUUGkŅs7osާK133ǎKll6uO|zh423ƩI$$fkrr>M\ᱡO$1d|٬mĕӴ^h4$dWUc>s6k6qCl huh8s7^Uٰ;$l5cěRZk4rXcMU5I+֤ԗxzg ёFSxmbVNXjSgz5γ{cseaKy֓m6՚7>362h4P%\Mφ/jow̽P`6Iwi٬kRysln4!Jj Y5lǼLӬV7 o-#y^ޔ%㝵~Tj6l$qImh4ウ'jXmN%$M,XѰlS4.녕&f96:|:1^o4 nڒd:;49l6ƪIxcڱRzUM\r5MRgd~ql,ΕJiU'l֫U'~^o4ٕҡʎwO{8_N O31=zXg:ge,{c/ R,59T~ҋj______ߏ1etǢr|p}6FkッS'Ξi$eyZJS;7_f??3/|pp I͛|_^Z0Jy( `2B/|˗_Jy`hpM?s{v޵syyy9-r㍿~^3?/{O~JKxoQ0`PH5_Wʯ [lٴ[?|0@'o:673;?;wXZB~?* KKwvԤvff;n[^^@H$c h:oFk}iiI ө̎T*$!w9 w@A ï7(僷q$ۖ{_:FmvUPB$*AREdAC30rԴ74PJ?GX:p4 !1>v 7=9um-/-Z+AD2 h9T[ b"//ɟ}kfoeRT#xìbTkk˷IcpffjȦX`cIX.v[oui@1*7۽4j Vd?/X"3'8" Dl$.\6gff>v8xiggf~-oGR>VGxϞ=}tanS}!bkQFB計FDTƢ043؏Tz#%?y:;yq ?W߰XYև۴e6ndrSu|,Jrytlӹ{åPƯ_3gw91Qҭ~_Py6{mK4qUW^?j9sILB@S{|pȑn{ȑݻvLOYk,s6m>_=Z3ٵsk׶LIlⲁs_K/u՝;wMMllw7մ"cOY)5Mf\|;S?8#w힚J}>4MwpVUq% $imxk|B̽PϏߦg Tcزܽ{ޯ L4hMoس{wo];&{׌'C>+n]skƗI0{|>v0l5SkSogzG٩)guĦl#MM9ySMNOzόI|/L+#IZr;? y>|/SCCUk֥ ZƻRa%!MlVJu{RZl2=־=w艭!̖F~Ѽ#y'/%#1%XNPwyU TP6"/Bht Pr  -\sACT (RNo=`DČAbEPQ L4ZA)BA$$BTÄJ w'438!rf _'ǻg1N-ج3'NI:J8YxQFg7q:}X 0JT% aHJ B1F OQYTa H@F ELV[Pc@K" 9n Tx"?q[5*i"`Q:c(d FP$*"]bB*Z6ac!1䊨JKd $")kFHj;s؉v;W&UP rTJ E66.=tSdzΩWeTTQT *5^ k0P!-i,"lH E4 E0F&c5ƐB!VAPB ٙBR$6(1VtHAJJ<4B@' JAA$DXvY"11vvfCڧϜtr!B!dc^Gl()PVcA1g$E"٨ 9`$RXH+U|e}TS"0+0yf#E%ZP WSwj'MA ~F٘Zum A('$b,H"Dl[;vtePC7QY@vBd`BPdbUݎ5kt"3!("pCKr0d07$aEEfU5"86;F88@ɱmtF]$ 1ʦPA 3BU3+ PEW-'EWc d,EQ0LH̜Wʕ,Iu6s%"L((EEɘ<%PEBըbo,M5%D1֩" D"ʉg#gA~0c@FT"TED,(EDAbdQA䪲^h4DDFP%UP0zf#1Ǣb"0E"(DRTDTBֈt ƈ3H 2HB TUpxxĉcĈ"JT4"#xQRlLac4J# QLH/%@t:AZnw:f"PtU*S@"e6JƘv嬑PX!ܒU`@89vi UAIcM BTgM/?<4%թ3U(w<\3Hf 8AEq*D!cMVriiG_z9ƠΙ<1Fm"qU##j/ ^٘"/4E!AQQ%H+/~ @BPͲ U1zT ܰ1ɪJ [`D$B 14 c,"PDb [NE]O~| ۡRBp 97x4/8t|p<^kV(VZk!AcCPU% rUA%̈L@y^ )2i92r4080I}>>:**D DL LJ&JPJK!y(BvHDHlHIU !*hq>A@*Z!2aTE BD"ωX2E"@(bD$&$2QА_>J$cA!@а("#2#AF+HQ$j7G AbDU$TJ1n(T4D͋c(BB`"$%Tk " "Qՠ?"" C1 {/ !( "yO ""C(B l "`j<%zzaRlpA"v]DI3;7]vIf`;=?7^c yV綾 !_;s0b)KAD̊Je`h58.JJUJZ0$D0!D(DDY%1h QQT "h 3V@ldF IcE Ab $Lh#bc,2 H ""@$ (bQ66@@ A!#[UOr5qAm[7Tjg_9NC=멈\.W+m>8ln˙Āi8kk P(bC@b1T޻(!v؄3$Qz{@ilz_$(z UT8!tZJRr9EyR Dkcs,""!3#1@!1$dRU$Q ih`DϞ>]xhvtQakD""r60J10bz,^X`ET `D*D4NWD1c"WcI(QZ EDeBh ɵ@U(H)ZcC^D2k!~ %" Z@ЋV!b(ҍ1")0!6Ĩ pq 󢳲=UQ"P(' -KN! 2F "ABK֒JPCE+!RjՐLjj-F t (! TH8jXF/b)$bΞ=~Q!(3PS"ݮ7,KD;;V"&ET!e91DcE #*j""DPP\BUz9D<:BDJED1`vVUHTI5ɲNvZ轓BQ"F.A$ |UE.O UhrjҾ3׀[ d|c+vV*:.vɍScՆ'f*my@҇>'KN>?K/ ~g?˯9v_tSel!o[*E7/Zf'6ǣh>w﷾SkglV 7n\w=/>l߸W"a~uz'O>z`ko5E4MivVX%R6g?W^:~/}78iwnQtCвI|wFCm:"?~(jcwm|ڷw~zTfEPtN+Gv&ʠ&ԧG}ᄏ>^J'/:Nw0;wk־nR!yC^#ȟ>vݾ}8+N.N^T4"S RyϽӧAcnrkl>:|Ϟ>}wjuUA[V 6 bޱ|ŵ3wmkV3T۝!3ãcտS_VWy;Un"?j5vn7:h) IDATl]bh4ǎ!$6 $S֋(BT)8KަZDOӘ !콺#b&g'[~*=wف\֋o 7G8ҍsӋo,,qnrFoRV0>97Ll{6?g/,&'g:c?ӵ^ed0c/~ֲz]D&&K]fw>4886^P߱}r/}Klu RUuzIe%zYSW@ef~{Ց5iZg?v,nɒw߽clM}[UJO!G߾}MJM ۷x$ޤ>Ig''UuлORIcرcnz}]>hd$&cXt>޴i`y`w裏ZN$ҒNmrAVHc~ϖ-WGg߽G6YJـ:zƘy]+ʹ[ιg=̂)$>qZ裏n߾cq~pV>oa?|Ա5`JR6t;پiah`M[kʕ__޺+>6WVVn:Z޺շ̧Wm{K/d:uūoT~;k_424pm۶ʕ+[/:R^rշ^ͦ+XYY*.xeu+ȲW_ydz%lZxWt;2M+ze\222xɥnvew}K.xtxW|+fWWV.ȥ_zm ۯ×\|huҭ-۬W]}.VlՕm۶ree^2<\_^YYxgꪕ˶^Z~_Y]]v۫rue/oK/ٶ-Yt;޾rj_zmoq=cL+QY9zﳴDiV}@U|]Z6̖K21:fX698Go￷Tznڸi_7nF 3I)_6 yf~us &6.qnV߸x-o>xjG3ԗJ &O+$+ykjv;Il}5>qy2UM4-e'.-Jɧ޺F1::&%caWg>|Z[JTJ*??\{RSﯽ溯 SyoĻ;xLSo\Ӊvm]bUủK/9_.uy,MFcdd8I4M}Għ޺뽪g-.MSh4cow^7K5SZU?:4yoX-MĹFKC oT 2f9Qy6cW׳d[k=ދORg'h4Fc{NkMFifJuh`$.h,I=rV(WMӴ6r4Z-R}wArW9ﭪ@= A)CidHQ#7;2$B Yifcmy"4(ZI#iWm(j CR"AhM{3hS(BQ߿7+ތ<7s=+4ERkR̬)[; &j*]70?afA(PdIGe]XX9㜶+:畖;wR%ў={ƻV6s)F;{}R+]RHlobڹ()ݻƬc;vlKrR%&ٽ{jlllǎR "ܻ{3fb|bǶ튄UjwϞQIr||l׮IJɽ{v:FvlߦBОݻFG.-KÃß鱱1];ڹ1gخ];5-gݾku)5f6)iA BoI)Yk%J*36uRMp46k: : F;ǟ\+> mC^ԹbpEЅ߾C146ʷ}e^|Qo`O??|[q3o-˥1VԺ6VTْ6.\޻ηAk-2RH!jkZ/wϽJegϞwJazGnk9~/\FkN]vN;fgg_!-;V tv:[t9Y[Xh*ЩK׭YwwߖJKv9Α(cq3V+St0л~H8p`hpT( z!6 fftN#R)%PB0XvM?rǁ; 8pࡇҤZcNٙ$Q*U_?rۇʅP<Θ+,OgfVR+8#8p /:ro߿ WtwkތNSB>Çzϥx%~CO?_W40SUH+Ӥ>cRzj*1vffgJ-(rVNOM9ggfzWXAZ޾)-L_6JAQjff{Rjz.2R ]ՃSFޞFJgojj5kXHiooԴvlRʥ]i+L2hNMJ %IȏZ)bf jLSqή(8hi4V EJ %%jap-wϏ?y[/y׆ wYYl*ppڕCl6n~߆Vwź- lǵPFο駞jǏ?b(&_UݝHt0h+P嬶tOW~cO?ԟɟHζcǎ2gyg`rjS)M֖R!1dbҖ{< Ŧ&&@+T2RHamϟ~E !djmZ'3K!S眖T.kcMGe>?>v*Jkf֥9-:Z5ѣG[Z[Je#UɘBZ`֮B95د?v4)jӔ'Z;:~ގh{sRJ(1F3P*!V]?G6[%D)kA1F2q<NjUJit!)yg?㳛7n~׻w󲷿ZJ JiO~ǟ}v` ߱Iy!R9|8I]!u{k\X,&;|I{o !$ ;x0S,VBR,I!1r8U:I1:EICNrWBJIoܕ:R,x7\.w;޺ΑrCFRxKb!qE-ȡ;b{o !$V-GFiIbOSBhJREbHPl)7y!BA)9rxĦ.MB(5;x !KE0IJE}[WO!-JCFKR{ !ԁFFrަEgSu %rhܹsWl@-qf6R9mZYI"6MmMT"I҆DD%I HHeu -KF7ss=705h6 ACok^:yb Ty(2.,,wm--vzAKa5Fҷ]t'cB@|#0 @ȼ/,{߽f7z~]nu{K3}BPY=GJ\boϿ\nR @I<56E\O:|HICr|E 0H--͟—ynB'bxpXX34tر!JB@>f{=:4<\lj>v=[$%TR@P,9sk iahhy}D"sy|t="u=?zB880t{  xw=vl  ;ܧ >Dy {`1whhhuԶzxc! $"?O/XTlxŕǏ?''| ]>rG?y];ܳgVU@k.BXQ,Xxw=vlPɏr]0J\.m-@JR.7o27T*mo@\T*- }mmsss!JRniZ| 1bkGW2m:??_*Ͽ/-ZZ֜=sꏾbk[KRA|v@mbssbRoHzk inn.0W*[RpJnZVj*{\o:::"sRijnoJbwg\`T*bcBl׳Jeco >kmi|KK[oa䖶|s[АG$Aˇ{wsOsvEm{/MR3'$-Z)8XcJmۿB))ZRVHf6JXkqB*6wz'TAjˤ6*VnYXXi3HiUVیVZ؞‚sڤ]m$58jw{Fk#Wtv.,,$Z[Ӵ)uxs+4VVY{aaAKe4$.'1uVi#UZmokRi%QG[‚1F*cB3sܜJklZ^M"Sƶwt,,,HLll"i\)hiUbKۻ{_\\|;u߹sUR%H+YVWvuwwt\fmoYwlV%YhmZMRT:iKsBX~t|bmFigͮ];Ƥ0;wJ$$ݷol|&'vn!VJ=66۽}[3IرcttT[5;w5F#\![NjG'ݹs1lrF?gU0TLr]cccJ;v%Dcǎ1g{vk -GGGĞݻHkbLo߶Ukt4VٳuFO~$TR*v9::*o߾M}+&&ݾs1Z+)ڳG'LǷmhYHsj]ccƘ;wjkJҞk>]K/niJ`f#vLI)$#]oEo-:]A%MiD J6J[kRV&wϏ?YY3V\9пn}O_ʶ{ t]Нv77hYY^e[U ]Cr=mj311}uk6]x=%?]]miu%{ߣ>RRcڄc|;ȇ;[?cW1M7~xpC./;η ^y/^\~;'ծ:uԖZl^?jZ;:M.aDT*Ujltm/7\ȃ7$h$iZlB$R/ݝ$Zi+>zX}Rqxppࡱ1c6Ybfc<4uk֔[78t]wMLL1I]9u*gbb@ÇGƔƙBڒ3'\P,7=:#w.s|QLBf"Z %QLLLysիsd||L[+tIa٥$IRRɉG]w &dpxvXk 3KiN4Fى񉑑o Y_*Y#<߰wMJ:-&9|xݺm/{ؘ]^h\$F+%dSR, 111>rxd``*fpccBӶל}ꫮRmۺSG::7m|[%ik:uMKMWl<}O}*vN޴eSxŦ+N>nۺԩ6_VrɫZ}ӧOu+N>O}RIuU[Op;{ ޡ ;V4u^78vu{ߊ|<5j|[lV|{W2Bm|7/__\"-$UJa޺u?87;=o*bxx<{l^?r{.\\hyysڵHy7tDe'NRs*v߂1ܸR^M^-}h#;ͷbMTl-[Z޾~xgϞ;_˧deo#G=sf9#G6\rU.)z9]Hy?s}ۣRFZzanp`8{{}Ä҈_O$zWz,#IRZgΞ{zZۻ{~-1ӳ92jVt鯗dbmO43Lqi61Θ#G>Ϝz{z6Jn܉|=" IDATz-eA??^넱6qF7t⟟믻HmML_ӧ,;ii7p?27\RH\[oeyn)I,o_ +{{]n FnkiSRi%ɛoy/~dWfOؿ:!o\NK/}+_m+6[Jo~^:q[Z\Pjs7sR?f>'^|)&65ןkqFYEHaJ1sZH%$洩Õ:;: iMlK, ָ)R vۺ;~vv#JTbjJJJD7T JR097ɤ৚ZlE?oC!RW] _=3ȳ+$T1" sHVz&>h_:3Y[[?w`^!@@91z)dQ2JAb^<|8xMSޕAJC4Ke|d(5HуQR-Mǐ Ɉ"HyjQ8 0:xH)#<(1DP0 Rikf%2R{@&!cdB朽"#f%>0!)!*!gcd@BZ>-H @R47WBhGy0AT^̀$0FP"GfV D-/eylBju"D"DHB4--S1(b $'1{DDtҴ6+zҮX= H #93ITGKAk)B]B>75U%"qyE9"BLJH~MjCCCCCCokg;Ң"Yh)Bu(I_{(W^/7^[,mjib{]+ S7JYNO1f2C$CdF! ky\)s"Bm)J| ׉هBb!xd CD7^DTJ!H$DϡQJڥ"XC`&! z /|CB<"D"iy< |..e#Hb-09""R ^ yR{BQcD,H@H@H12 %8@QH.+)" cPR"KdQ *R> !B1DB90GV.2Bb\o BX QI1!z3D##zz^g ʙ(Q)Q˳4Ic9@D( C@h} XJBf*)$ D&B@%"iZ92ĐG(QՃ!ȑE^ˢ@D8JȒ"pC0I^IaqmY bd"$af ̄9BZiFAHs)k@"F07c$ɸ(#Y02  FJ!C|@DR-+FE @Q 3D(%2vӆڹʴ.-NEL'_9-VB,rGkk-YQci+oXʗr?;P*5519ibxWK͋K D1zG%`1 `vBBC (`zZ<9H!>PD'!r`RQZ 1"@,1`C A#q(0"93"2@`GlH`^Wd2R8FbJƥWDD=If`!|B+W|})@B,aVqjuADܟ9sr#υ|$`,dO,DJ<kS-u!υ9ϼQ |!J;ں('OR 0G@@!(%9R=gBpHi%Wh)˅lAHч˥QYVR賺G3 !.H^ YQZ=#Lj"DR !H*x+E!H0!#Ԛd AE(82#` @=dR)1QvqiP2$`^F, dH D-Ӂk"0F D!,HHEVlM_x #0&uggs/b"h=$Fs| q*""ar0QD /3!ȑcd6\ !,DF!bȣ<0hm#CN"i0fUkm02a RafnG#-͊ 5!u,Kgdb4S59'_AYUh*[Ϟ;7=>ϗ*KKI9-i8xTZG@923GPt#BGf(bLCT]T[ʢyDPDh"ffrfqؘ6444444F!:gΟo/itVH]ӫ3gd=fZuľ)VKȣ}#k1FX=p`F!E{f% X,+s1ύ1!s$#0E }.Fi UA!CFI2|n>ye#jk)D@@d#G`Dcul]ZGf9 A12 $IBH2|FBF3"1rH>F1[}&x#1b@$ByC^!GI{DB /-eJQQs Vzug#"DBHrD0JEbY>e^|!$2#g!kR$kRDB&!z1_sϒX 1A5(hy搰APE``Y="P^ja > $AP(C$"k8BĐsPG8 Ę#" D# GAFII>*!|Dā HH1GFJ`^"$dgkb0?!@c,%gcdbܹsc&%db\Dd8j!9rd@ʫS"yV+|J!"iZtF+1z@iMV)ETHf9J!ϧ^WoͅCH6ry̙k"rR#B Z={mGqi$"A Cd$9 AR5 a&_yE#W*M(kuN*4Z"huȼEzWfj3o8- b5 ")sODC1Tpvq0q "Q!Q*h]} >! -OlIdR׷y| J)C$ zB :f!0`̥ y<}y."0< KC1zBK(.wB@ZJyźdk@#G1F&Db qfu"A"#12ay2*b}ṗf+#hMSt 2ב@3-0XBIE|yb"U}fB1 ! >HĥjR\{$jY&"1B&I9C(˽THIz:OL E`eE3%jun2!b Bzy\̀C`"#d#!D"3{ CBz3FBH&yN(B-7 1WfB1-k瓶` }놺,,,1DTuU)kaV6RX^HPYb}KOo;woo7mڈ{#LM?V,6)|ii-,֐9[\YYu6=3].-փ ->y幹g} ;<+s/[ջn7W*sO>}{}=baPۻ=7_X=k}s.,T;~3L9lϞO>陣??t&!{LL=̳]9Ḑ=Ogy'7\w]Pȟ3?O>f Z{L?}g᳟<=7;S?>^ո*j=3PJ*e^=qc?{_xnn|Bu1HmL<577H B4W_Ze3 uvvy饗f+'^zqࡶGxRyQ JHI/|rna'G1 1yuiZ1@g-ɗ&ON<8N zy4jZ[{]1ʋ/xxPksgr)--U% ,$Zncǟ{noi)u-EYVRŦb'NVOŬk_b}>uC/>UY?K###www}ݓ&ykn,,p9e 0H#@J" bPY͍[~'=V([-G{+w|~CCkz:VK.k߱f|+kSk_?oTnꪫFԘ>]v ###ַSm f6ZYe9M K֒HJ@k\rE???%F:}׮[z?GW_/~sW;?9s暫N6Zje\p&*5.uc=w׮U=ĮY=422o~(#I 8fN$1jk]2:6zݽyC#ƴX30dohd{K.-:?=3y'>%H_uӧܴugΜS4J^mӓ[6ojmM'Q5[N>|6MNN^Oim6yzr+Z?={˷ںg5[lik>zޝU>˽w;FY5ZB^1 $l'NNU}$U1a,xK*o;DANA;H u;s9| ^Uoz>SK>|I7o;颋VwK6m:77Z.}?h-ss.>+;ص~K.;k>|˶DquֹC {?+Nl*]qpn}\0{Ç'芡˷N<8w ZZ7wޡ46vb˖t?C|x֑VkGVDb&2VDҸh9jI-tHl#V*bkjbc,BSܳcݺI}KSSVH4$*ckrkzzlܰqEWڱ&QkeXD Œ3SwO޽mH$Cwo۶{nk֬H-VmwoYS, nQLJkDV[vv##F##۶M(k ZƑ1f۾ѡ4m۶{n&=C#cF/sfMLM>9944۶MMM(9I 3jMqOMOݽ4ݻw[FWcb\-?{-o{YWioꪏ$i{[ko]}G#[s5Vkfzfkzff[1j}͕WNOMQ<3==u%ԄDjk(QƈVX+"FQlu1Iq^,FqqDDfjUKTY IDATmɢNwwT*N1L"8m({W j gn|[ׯKlbHV:FwNL q(ŬUZ-k5rgwwRaMdLR\!ҠLıZZl+&Q]VBQ"FV("F1\V[5mljjYG˻j0P3'q\U+ֽ̱ݕJ%*LE,"a(l5VΎVV)CJE-H'I$"qFqAۈV]]6Պ^T,o|kv[Gխ &oے(ئQam1:NIG%qZl(jkLEIj&1km6hM9)[lkjjjjj%J0CZ:Gώp* :OyMaZ UWs* :vª"P(_="+PR848_ a Oz嗿.?|m"c]yǮvѦM!elll߿TZ$}tf` V{4{q>\\U ć =-7NMaȵpvvvgDiaبTgcY4>>E1SS {Dfggڰ8j>*އS3s7n|1G Hk| <y܇N("χ}Ю{zڵ+oܟo@*T;˝Reȧ>}KwO7)̐R!x@|~swߏVyz 8y=*Sl :~ᇿ_h+noڕ ( ,Bv]\Qɝ= !B%dgY~ʾ}׮ok ~Y B/>CwygߊkUO-A-ǣ>~?3O ŁUܟ>P6}k׷]{a>y|©^~[}h$IFq Y#' $&:ZN a9@4ܳ\^72K{FIfrdlBlBA3mV465s2{Ӹ`4o%[aoki&I -9Eߙk}bO [z=~}λ޹^}FSBZpΙ8޷۬''km 9ז&BjRwm>IRk푍sNkikkq-#gic#c Z3rS?{\n531EzWM5uS=%8MF"11먽 Ɋޞ(DMR;*vuwO[GbFl,//RZ%]=xۿ+M4IQR("RI -Σr{9&6*)$]eL;ְLL DfYoaLyOߪ8-cZ^fj]J $]}o3Dp֙gݻw$ .g&$`P,cFC8r#]z뭷=޻.ᑡ{y_pĉ]]= Ukcp-N]w]r "  )֏nkxƺO>7_`(!3@Wv۷w-ifʽ;X;ܷod͚j}ŕJ%IZQ~Ӏ}a~JӟfU./,,;\V[oj+%@RiԪG_=|}-u{W<T7@q֪"ay\ "H`QdLmL\(m!A0iB@_q' tu+`FBP lW;Do޽k׌ _^Y!!FQrߎD$ T +$";۱o5#ᑡڿ+_'O.y +޷wޑkZ:V޿o};sG0`ʎ;62RLի?};Q1""8 A($ю;;<2Rj-N8Q*Y35( )2@8q#͛/ċ( 5FqEbR_x7Y1RHJ,t4[~%Ok8]̍GVvt FU+FV{:߶7wYu_{B)&-g?mgG4M4D{zz8LĊE$5QmAbd5)Ldckt5c'OVvQ]j`7?YP523N\y"+&qT($lXŊb&F6N4Wt#V]E#kccMYaRqFVuvҶ$)DQgwwZj=6-ޕj5={N|{E_@+gfbN\ iPzbbzhvfv9TGzzjڪhvf-[#֖SSSZۙ٭W\Ii$'jff&fvf-W0ehfbbzj7!\q4M i~-7}rzjgffb²k]9qt)N_}Ukں'|wO=w~9<眳9;o{[uϞ=W^uu'Z,]sS3l 3{\q&2bbzzJHXm&&& -3[lQ髯jjzXG65&::6ܹ<}it$ŤQj-ڂ!-"H6-jձqwgWZZ(a"Y&kfSպrZ(Z޶~CVKUV8k&SmZmllt\.wVUQ"VHZYj++YV-5q*"qӒelV+VkUjhFUPkeVuDQ4b&1(êTjZWwYjZ(R{ 0tUUV*hVZ$7yE6cRh [ Ѳ-I['OcZ[ PJEm5ZXc:$ƐBX3y+G?xԲa`Wתgu5]+z; ŁFW\fc7_wt8c`Xе<Iϊ|í~{>o|_zɪ=$=cݙwߞ={43JHj8Y֏<xouwvv~em23;{po1XС?̧֯YRz_#Z-o9pॗ^]>wӹ.Rt%V눕QlRTho)NO_zޞ wܹg68NDZ6{|_7soڑm3ňgrؚkܱ={nݲ=}]m4wpn%Nl=xo:.𢹹K/4͗8p/hmm=sK-͗^z^p~Kt}KR7_~{;J-n477͛$r8sZ7K>Ak/.ž.pnnnք[.=RE\477{wId]~͋O?g_}>s>W_yW~رu\pE+z?;:tХ^flq[_>p~޹:9996:V,]}rrfzZkBja̚H+nmi=c;w윝J0"2hcI퓓#ñcc&ggVi-"LQgvvrrrdx8m3ZKJ-"?ZH4eV۷O Q<84/yvvv5ְRDX9933mX3f-"VXsbTlyvvѱB!ؾ}rvv6)=+:GH+aÆ0VlYNnN\5}=36I{Ӵu5N^X4Ç7>}zqqz_boo1Z /! I7oy'O>nHYx>h4>E&2q7=>;1qRl|/Re/'NGq>פ-qRos_uo q1׌ڵ^˲;w766n|W8 ژӘn^xa9?q]ql4妛R~'iAF鍷‹/'>c5o?µ&4F8_x_w=kQTji|˟kckc7tO?ؒ7t?-6cŚz-K7]Cg]_;8>϶4n䦛,?xpiPP:ֶt?/^qѷp/}'6hmxۏ?u00.ql[  h$L-ȲyC}f٨ܿ<^+V*f}V_d|@*DO:VjmPҖHz>th>|hǎ+VZ;n#m"VCܹsxpȲڐMUC_Wϡw޷jJMj^~C߿sժ6iQYmW\4Quk9rd<ꚫ֭?SO=u E6EiK!0)N(IY6FvY5׽bj֬e_ZbkMD\C)&PĻڊyEEQPH,>B .g BЊe^P~Z=wΨ{t!uK ('b\PI-R@y] @NATȂBAr">w(@IѨ#֜;/{&TZF})hl֜;6gAQ 1D6 R.|t̜ ԽttvkG_E"=)B B sW8\\r(D׬B "k E"J@y=3np(bB\N("sMp^$}#kBuAbLJe$k!198JYG{"zQm$4$NjKժPE@*x-_Z".Lβ.ψR,Z%+\3 @0{!BA96\n5iF@?QltJ xrBvY BAm+$J;l"(ĸkEeaa6/51A "H,gsDʝcB*@%%Dy xbAʖYI|^?! XxXq]f|@DIrҝtZ'a3 Gj`9+WH%JF#"v!N$} T*F# | "Z7DD1> މF PKgd2I<)AJ}W*ZQp@e~*J5H6RA#0ox IDAT Fo3`bqգ (Q؂ׂިKpJg>>xpAD jk)xV h,PfPx!Z}̈ϟ8~Թ*o#hz#GHfLV[ZZZZJx]mH= I1 (.V천 Nʂ7E<#@t. x>Jy޶r1^|eu%/a11Rk8v3D6N@( <@D".=zBmuc) my@IYmϼ($J)P̑ yT%HtrAJGƊs@DD"D| ْ` h6 $C"Zcݝm6N8u4ϕVl!ʲj V]Sؚwnc:{P%k;i@j1g"VT*.s}5Guq{@ 8УX blKOԎ+  \೜ A!xCQy,Xxmyg^x@b*ݒGԐ H(@@B0@QpZ҄{hԉ*< "/! (rk EyPW.R#V0x R]ʜT5"zOȇ\ dEs "%B V;V !qrT(GT36N"!ϝxhx'ij[ՏՎ-y2D,"#//:aErU9IB9Ed28(!ɝs4Fe'v@+ml8am ~6X*C {%!Y IY u(t9!rX˩ay 3q.vK!Qc5<5^D"b'yt7! p>7C@:YY |14*'D*B `q@{-@`ye)XRAAN0@@VI˾6555555,ruzEq)|ovj`;yA  O>@F,鉄{VR(u{ hẼ(s*2"GAE#DR!@@HP|RR[\ >8%*` EX)缐/NTO<#")#UDABQbmȞ? (B9)Gj+'O|u !x"DgFwB72cD!xd6C`Ø"$!H胠򴒰}CcG2Axt^)MLZ<}9!,v)׻垵P>kfAX & A^B9!(E<r!jz5Xy|!1(HA("$ IG@PƉ׎;z1 `.b$"3֔;;QsB_N!ژ%DB<s A|I=FEz oAnjjjjj<=3F{Vwz{G):c}o|xY=?Bv毽bRMVj;Jroſ;vxZSc#3WĘ$)h&f+ʽ_l4ڵꃯje>[mٸp'?gYs_Z?\ÆI[_po;vZ>쳟:;8J]o5{[oilxp|ȫGѣP%"7-7?TwY{M4}Pƾyy\re?txYkMWD .3dįykF߼}ɸo>.S޴\7o/+\eC=7-'_Mc?G\RI45kі՝{rx/L &3666#UH26`(f 0v`*1P (!4̗oW^,Wc΍8'^^*wKX7Mc=ⴔ38v옻W1SjZBBUQBf~zُx^c:~u0{o/| ^}۶la~ff"uiǞ~ӫb94Ub "sglݺԧ<+޻K_o7pÓv]|饯xEj?-o~k.};.ⷾ/| \!z\sO !`Ҟ_K^R}mK~W_O|l[H0u^׫IuULu4A/jv9}*qL59?/~^H Ɖ'^ӟ>0y ARvP16wmVrVլʈBm_\k[L2eʔ?n\tF_{٫1m]v[tWU9TuUl= .>'a{߹^wo鬇;n>`7Dfa88.~ 72ؼ}n!b- ߻2rH]Αɽ{ZY(J\g>go~~*YC_+\߼+%21hv)`\0T;[fV5Fۮ` .S{'[םqi)+ZT?^o^~jS[6?y (*1Qi:5U#yo2eʔ)S~Y>v_bSjy œǎ,DAӟ:?4o9^kN6ES?OyS^cB(W7]ws+WaNf3TŪ Z:y>Ƿafݴ淾\}ĨX&U4"&p pXMnn#cH)p)-v '5Rv Iu&6!E 9م͋$$U#f0J\- Iܣ:qL= F13b6wwH&U"B`fA ݋BܠC H =sꊶZ,1"I $DXI8x?r.yLa ύԬk[u a*]aQf'HN4Sg "!H! ,pAIu^ [D+JZ'qiZ#'Z^0Ak+ 3`E"Xںm3.)YIE'?rwwHЁQ%f8U g>7tCo?Ҥ?ʯ󷺜$1I#>uiƤSx4*rVʝ4gڶmsT2eʔ)SXr7uǜg=k_ģ3ݽ{]{~Y;N~ig>mܟ^wɇ y-77o_[~]~L[oeub )v9 .|{!ŭ{swo;D-}[?{֥~9/*ȱW+Uݶ3Ͼib{*RJU+wg`&TMr-۶/ufMJԃ~ogzsSǞ}%2eʔ)S~۵?׾m˦=w~W.nm [=4 :Ұ!R{;QTs룙~s[l=pk}?zս?:m;w‹^Tn04sJ&DDf Nsk=W\4֮UruL;wgyw{0 6s^\>oC̅@p٦oDm, WRgnG9rh}}] "m:6@4ncUuS׵M "8; Y+tu7w7cmTk!4*ҍ\z01)J:jG)Dj^)L6 !5={mbj' Lq'GT3*wXy^=ufpQ[.DbfN]U$dn,LFZAnܤZ*8JV=h!<1' iRnԍǥ0'NcӰB`:˅G]N^6.//="m &0~R Spn0K 9|um`Ғ9θ۲آA-uu5;Mn;qj7۴0k{PI~ E&V6)rn}r?fP? ȡP2{%hٜ Cɜ&aşoݲ?_ןԧ=O{;ԕ03%*ee@ Eu<\U{ +qʔ)SL5jrW|@BMJ.E3[8FNn(j v͗_1ջwxo_|=w~~v{{믿$Ptrg??^y&`SӢn wʼn:-m&0{r qs̢pIQbp ܊0,R,8s9RԌT D '1b A$8p$ɾ8QjMN]Us6+FfLЍGa;˥Xںk瞹*2QL%jLpG̩m;>`-l"%MQafvxc"",U4w+J۶m#&~S :& GtV GCmP5N;DnND+౪ $HOf)An}$Ę0F`T 'uκ鋄w bLzdy}{+/zŭ~b~'O|K_e# Q;ol72?|k?ۻW]|n^ڿM]׾|_6W\4٧DwN !A؊25WW^ Ęĭ*7 @ 9+kk.pID8D LE`\:Z !s fI&:r;5G׍5B<ѝ{RL!`7]fV7;wt(rq5j)%S`3B3MYbra'QdM-J]83;f @\BUǪa n- !Uvs0vxQ$UcqБ;"Daw/Y1[SLub ]0 j́p1Obm"&raJ)Ĵk1=xV Ҷ4L80 Nbj !8D;͋ ԩG7 $,"Iiݸ7(hõh1&&&bЫe/Řm۶7ḾO8q\(0T\Hb g!JsR&!7g!wg8mٲ8T>tx4ni;fa0eqIW7V:Kj!t:eʔ)SLQw=Ӱe|t\Z;ž=[/ط;2 >pӶ3߹_}ˎ>8;ayw fr!839a1VJL`Rj#t9Z$tVUM$h&qg"(ca0:;3srܚm[A&R@ꚪ?3#'7ՃG-7Jfj" \D(E!+T \^mA3*\ҁ(%%vUvH 1z.tRt&81E6-N fJɉO1B ,YkSL(ZIDG;2ܻf.B5Ę<)B!"Q+nE *-9öݲysFDf`fU%P`b2֧ǣ in9&#r "S`]ײO ++^|DRr.;%"! "3K!^]z1tl\S6*&5X&R0+YG$DDBlU"<̇?s|ξٙ3N;c 2[moM_[[[YY?*=?|7/B DjT: {w+<8/yT.T̠פ׼nȡ/_S 1懿8Q ㎷>㌙L7^w]~K/uj~?yG}(~t}Ι,hWdke?,Kdd&ɽ%H,Cpo8b.I$2-Y3g$/lltW(&ɽ]_s>U]]zZ=ݹN6 Y>oh%+!^~xu|J^g?^^Y_c^NZ% ~m7|/zϚc/QBNonYݵ+HcҾg6ҏ@ȼhD"ERban~)ՖDzx[Вml-rlKP(uw/iih/lteO}suF+/%bBk?S?ټyK5ޮvzѿ>e|"\K|D4JiOK AvݕH%Zv~i%Kn/ҙu'n)_fW~Ⱥ5J{P4"RƹJJ<-z'bv=W!$H"ƴʀTJI裏>裠Z(xb]j)6vܻ U7rZ fúre*Yku6 +s F#k׬֯__.Zd5 IDATW)lZ!Jnx[\֥W[|׭][.u}呵kj֯mxêܺ[?~| &o[~xxxU o^>Keޭ/ry[}寿tfʾrn-ql\.X"Ntc##w}.\qp_]*jeHy5k6֯/}+L_Hy-(komxןˤWY~],BDf2ZK% a@"*mr1?)--9HD Fd\+(D!RR)P %?Sp&zyYߏ1 SHA3` #VJ!( Lj.4JQ  `F @~"eTQQj%=<pAk~O$3\+% TSZBDQFaBjm$c~CK,,k}ߓWKDO$T[׼|tAR byozkߘ`I<}/ݻW)JA:\xG?rƍLqbY$Jq?x,JyB)i-H$\ll,ohlooni)e2Md1 ޷oߖMwp <-[@}oؠ1h[6ݱw^wlJ}e} ۷oߖ;Hwl޷wSށ60ιTBc^ž}7nҞ|߻w|ށ6zZ~gcOS \KoyP\ؼqc"Bo߸w^O'ۼq y{ܷ/nƍ@sO< o߾+B(͖;jkm\Q JJ7o;6O"J()RrhRxm~C@($^hJ Qs%c B(!8D)Xs^k@6%d#L cKƒJ V 5ҊqAJ+0#(T 8e %RRk0:R0)DJʀ҈X{IfH%Ft2K&c 3`(g }:W븖g2mwgF9g&\q灔BF %9JBB2 ŶhD"ERcԱl/3&U\ӵd^ϒ5kzW\X[SR%kںiH-GGyUg_y?H%2K%=U}x/VՑc?o4gϞ?xGG{|/҂]F1`L22xGk KKejA6 PRJ8#vWc)ɵ 151c<}۴n޽Z}֭J|[{?jo+64]+OdϞoH)'' QF\GGGbI&^,*|h!h&&KŢJr%,拣Zb%JፏOJ[`||X2Ji%3tGG訒rb|X q-.U&&&(K)?9ecccFxX4 + &''tu)ƥ%Dwkill|||X(*!`o) !NjMp FGGAzBKRk-D< ʵԌ !@i1H0Fy P6 $٫VSRWUZRFkŸRQDTJKhi(#b}~6_<%+&R9ߏk)$`TPe1 9AqzF `LIPRԎ Q%AjRod7R MorP d<&StmǤөؒW^vŗ"[.!y+$HOkDJWҀDԱ;KutCS22;;O[ۿ/~_/:11b)/KTŵ8%\BI%09$["H$(:8(4% L!O4u.-xӒb_[l'.|a J₭)rO;x'x6T 95w/ZMo+%}`V TA1Р<-f1.T]0kws!$ph@)ױW^yx ^yRΝ:ۻ:6{|7?>>^qSTv%B(k!f||М1_=66i||XhUT6::yxX2}-ڊ@xKS^0\jBqtt/ 8Rill:11Z(xJǔ&+zD}261>^jjVPR9>>^,P XUB4 _Ȕ2Qb||T,d[Gؘ0>>oj Be|qllqrrreΟהJ@FGGшϗJp)yCDϤbc L,QUKZkJDĘ4J{JkDDIRJ%L(F(*JO+R{)D,4ւFgҩD3υ 3 *H "g193ƤTy- @BK#L@&7QxLׂ]mZR)V"w/ZK(j#s.JIj7Jz>FKəR%^}WRDlfVTS_+՞ OCL B*l$b\SJy3/yd۵Vm;w9GDyx 2o~3-mLh83 @A%Zp%p(e@(銽?H$D4ssUtAPBUj13ɴ .',qxPӄ $a2gmV#+WtH(eR)ֹȑwU/\mY :g-c|-`:VeO|<2so1F)\Je!uHU^y晙rW]ya__?c/"Ǐ}\8p'9D`\vRF !.[|p/€8;88lQB8p8p`냠 %K-9|pppي"Xˮ's)ˮ~'O;08l k-A6X{R }~~@0q`ppQkm׭\188 ^tih -lB_2ιXvЕ׼UFeԞO S)REWL۹ʌ# €2huqJbPBbk tW[T0JE˨B 2B#j`m=B|ιEzzzfjz:7Kh Zc"6 CBd:tZk`HbsHs9BCgÐڊZk0 Bsɓ'?Z6WȈjJ9ea5$PBZB: !ِP榧N+Bҹc*H*yPJqH!aBj <=5333G) ae.XDyd$FF}+WdBX 9wosSA/Zr#1([Gqh,"%-|K$D"CLC{i*6562oKWl,^ގEٖ] rMMx})Ԥ-[Zu AJ+.}?Tnߴ9E=կ>I!;=]mkZ::|يt:bryxZ0ah&f'Xw]mTrɢ_WܿJKɄJвv>GP M'vt⩮v0ڬ_nʕbۻkM\rƍCCC7ZI5*%߶/ˤ}75knBmX~Pʾl:ݷ|5kvۆᡡ+W$ө5k@u6wt&|rvZxvthoժt]nŊpy횵F  [ի;ۚ2:tthTowQ ݺn+Ury͚  n["O\\.YFpvۺuG]|e&]\.YiㆣGV.[NVlޜRmw?~]]//׬]c1DcI?j( RhPLR26J ,Zr%队yD"LWaJp"F5(R0!TqC|cc2$Y01JGDͅ`3B 1L]"N&3dApWБJpNQp&PP6! ug OLwݹM@mw*vljozgۻr]m۷ˆڶی=7l~_;_\<^8Z[O;R@)DK-4Hi)BԞSpqݏĕJHY{Mo|3 ()d,֐$<#PGDSʅ F|c xE^SkWK8J)TR{X:OF*P1K$GD!8h!$qB kCS Ar.8̹0JΙ\&L|SPF(Oj%'Ҡ{(#"xZ)%L*Y{L)L9pP(Okg$/Cg}kv||H4KT}.geҹ&OԞ63^LǓuM-\*@ӴWE%5D"d[4ő?Ӥ*3^ ,h 4L1fI's|V$giVV:𼙹YD•pn&T H ] %LepPF(22sQDbtZj !.2)ِqFX:1F! flb1JX0 Aʹ0rN@pf#\hCK\R (:JBBuR($h-$APJ !#c gR֞VFG cARa0FAȐ,%1B:AHev.^D"c܅!D"ț%|drf|`?T2c)!gGG+B{'}|5gGO½bѪBGu"D8=3wsD"H$f:19* +um3n+bZCvnn'iI5;5/i2$0#[#ȅǼ!D"țrilkLB7eE&=1;=jۙjo6ư| ھTF riBg>ET*u7?zjÆ \.-XtiK͇Nĉ[n- ZBu'Nt-[477K)ϟo}V{.)eWWW7vy*Z[[:SY;>ɐjhh-5:["H$(:8TꩫϩXyŮD}2\ݛ/ͫkxKJ޺KY~[weɄ?aw]Sرh׬Ysw<3Jɓqҥ{VGݾ};.B9}}};vT*;vC^xX,~}ꩧnD| ¾}N:500sX~իW _8W_}7 Ѹ%D"ҡMk<-tk{wZ.,luM͹ŭ-.vɂ.u^W}5Y_H$r[w?DDcدXi++?76n}bbx,CM6}}}+oܳgʕ+HC<'&&<;Oj\yFQZ>y 8Sr.[kEH$D.J.no'Sd* =-^յ54./d-hoe:EuBԒe]OkD\z}̜KÇoMMMҲzGyV~s=rZ{g͈xȑ7J?~fرcL<<?44~?Oj\yFQF=ؙ{P(y<4(>o}ݷaÆw}}#+|K$D"C:7[u*PhH.(ۛzx}2߶3qɼO{Ԯ>/BR9r֭[oFD766VT:oٲeDJ~ 7ONNNOO?]tދ˖-۾}PZcX>??{<åR'<} 'yf3 ǏckΓ'9DžsGS<"H$:1|!D"țed0 dL%7*c / a*f&fpl\qoyO%RJǞ{iH2N:uETY'_xc2D.HyvXHǴgى" ,ᩩKI?|!!dnn3̢Ex*曟x BSO=aÆ\.,XO~rzzk;Nĉ[n- ZBu'Nt-[477K)ϟo}V{.)eWWW7v?3 EQEL&C^chh,:Iy~_G7o^gJe7yѸ%D"ҡ%+ڳ^9gIoC(eccc:,xC&CS2uya^!>ؕj̔~ړW^wk߾}333gRApoqKSS^G~sO\Vr{ټy3"6669rͥRǏcgJ{Bp7/-H$\|kwW-~%o+R~բK;{_Gu~{f׶,-0`l0PcB(q7q m\jNh)1sB%yϺUXBVȨoffff=5JKJWxuP-VFjk#ghi;M0JٳaCc>;UUUjG\r޽d20T*!$I8."Hg:[b\t\P>_f3^xw=ω'.z]*u ,K]ׅ uӭVyÎ۹*X7-$jsJ͡u:K`2=y<4AϞ:(ر$ٳsϧTv;p˖-(ڵk˖-p-3 ޲:[b+_].'|2[,οgE^?  WL`NR,y};ᘢɒ}}$HѨs4𩛬A8pرcEE}=ztQiwygCMӡPh޽755]ĉ3Ǐ_` XzP>_N{ٶm[ees/}vbAY:;ju}kVԖE+KbhEhs(XUY *<@yIU4hUc5յ6[[NUo+[ZZ6n!lllSuڵ_sC{zzA8s!loo'Od2'NإYbuQrʇvvvzd!|~f>ffUTU677~~C=466VXgn$W^y?x`YYEQeee=7Yyh=D 唿qƗ^zؿ~ yʚGAABWgǽ[,yӕpt.ihrrZX 𸪩7a4(E'aR^N?׉Ի v8K]  W,\vlpD3HP}n4duHNow]>D&8I6P7ApAA+8^gtL^_>:/JIsOzD!OCcDeMF4)aVeewA c  M4ARp2ṡD^43W>#ThyR óɥAA+EEӞhE i^Q$FsPPqU(\o(k6 Y8@{h4Z,-[SNm۶t X,3rBӳ_67lii ,hyW 񶶶h4Jt4}61թ***{챾뜻_3oCE_ qfa<E F- ,uuvx<.W T^Y_8JܮcsUVքWFR㸠vCYe'RrWE=4SoΝ(SSSGijj]CCC$ڵ; [[[DQhmmmllB<ԩn B ?N{@ 0{'W Ν۷o_0O橳~ůg,˃O?t]`qu ,K]Rw4ƕZ"VGu~?Ly 1պ*V^}?iՆ {pZN=D"D"E'.]`>?׿k3[B垞Gy;gzE 6w=88(Iݻw!x<ϟۜbYl󴻈:g/y,/.^l|Q;gW7|3\,PZE- ,uuvî`[S[pE4\,-1WKLa!:)-h;s]v{뽦&vIa*ڳgO]]0555|w&''?5(21G]r޽{!daf; T BH$sWq\E?!E lwu^(2IyGENj/_l {b.ω! QRtxm# IDATDh"bYڢ8R %%`]UIpf_)ii;M쩃(|;qIΞ=|=|j1絺v;p˖-(ڵk˖-p-3 ޲:/Xs\Y9_\y=3,}k_/[CA1FjJIbq䱪34ũ R.Ӛ&ǯ $ǎ(*۷ѣ /(Mγ> hB{-l}'NY<~x}}[\Do/_ ̜3H >ɓ'/A[AdY쨍\P2,x%Q/:uJ{e莕\v(Bx-x7B9H$DQz׭[7) 7[T*˝9sfڵO=pݺuv$cž@ AΜ9S_O(~Ƌ3EQ>+_J?\,}LJ*k~? \U:;y[6,isi cq/QN22v9Ex,N%9<B&TZ\+?}ȋK+gGvAA֩y 4|bi͑Of95n?f_fPpq4eg r9tAADn"TizpdEQ1L.f\ʉJ<)+ MPk2q6K IⳳA|riBBah WeA'rN bǯ4t$d"edK y\K]  WJj4eHLb:`7>U΁EPLK2vU/x+c4'u KLǖAA_t:e##=?k$;9 H4mN+9:;2O e2\[@8㖺AA鼜7}#Y~t"7;yS&B ?>HLg38?:MӢ<06SPT =\mmhX,[lywNڶm4 Xgrߙ]6G!>99 Y ---knn|4MԼ꫅x[[[4i:s_g!a:ճ,s;fgΝ@X,vȑ|NWQQcl[,X/U/]D{^ww 7oOAΝ;o߾xbs Nb8 Z[[AdYfukWUZZk]R絅(wf򠾦pݜ/f_Yg]i u-m)rH$>sbH$Xg\d298==m0 >??7Çoօ4t,VrZe<n]Пa-_*X-]pAG+cAAΎ;|_wreͭV{$UUktաaOECyR_i n% Tn) M 6lݺ|S Y{zzy;cy R7lo۷o߽{$Iwޱc?~nsedddfqxxf",VrϐeѣE}X,0L$y 966va-_*X?W.xi5nAAeiպrGӽw %P$( 6kjvLPhEyi-{YvYa*ڳgO]]0555̞TUUMNN3Ǐ=rʽ{BdCCvR$I箎(B("AhSgzk| /0 M6}<ϟ;wn֭/^YIg|/V6>.b8D- ,uuvzƛn xVG#Um2k jwk+bPiH3aox[N~AQ>`ǎw}$IgϞmnn{\nCl/b]l}2:::- ,VrqUGlY-<sW\.x)[ ޲wq܎*֟{'Ad1q52K⸌C0M8T 4,4CL% O;pcf)F;zˣ(J4;φB!C޽{ ojjjoob}}'f?^__Qbug ٳm۶ʙHmm=/7\~=(>R_js-?* - ,uuvD%{ee q.f }+oI Ī*H;X[^YYUQki;7[nWϷlܸBxȑD"!bWW?nݺynܸJR\̙3k׮}ꩧ ֭۵kW$Iׯ p̙oBO:ӟ(vww߿obTwEOb8u ,K]U`~UEE F yUV7\puH+( ʣE*W8Booڴl6,DZ[[8ɓ7o6E'|sk֬8l6ZMUUhssi?CcccUzzzovI~W QUVVvС3^j,Vroܸ^3/Byy9EQ`'f30LyyyKKKooLEǷX~_b_j\{G/jk5u  EWgnїxg&˩inT\wu} dJύgْԻ v$n/u  \1:<=7R.'d"@=HY29Ք *k|BpV# S9 0SdȥA㤺5  rFetjB凧t AQFQ@S$|odR4R@ z'A^AR&Ȥu<0$|Ny)˰$#BB8F_/CK g5  r` '8ڀ0U"^˧sF$)8Sс>N/N \sb l_@ M禒9El" 2.H*p\O3%$DIGFz'A.驥AA+7.3ppQr&d3'k!=q#c irW&㢎YLńp瞫5e˖-.ԩS۶ms:!=3\4;('''[ZZ ˲`errO}}}>隚W_}okkF4MGї_~yn,$Sgz.K|n16mq$B:[_jgΝ@X,vȑͿsfOsbH$XTcaz>L,NOO >_~k6x[ou! ]:sg?eyzR/CxWOϟ ]vYೕAY:;B%!"vIYim?pՊڪCy9SqC@SO/~vvڠA7lذuǏN)dYyGOM5\x^~ xB|w$ippp;vz44d6~ ]  ȲQ4:Yymm\Ws|'ewMD+KV]aGA"~7;㹴_v 0JٳaCc>;UUUjG]r޽{!daf; T BH$sWq\E?!E lwu^?穳X=+>^}uT We$iӦ?smݺбK%c{e}GwqGa|Ύ[AdY(ۿT|u4Z 7Vzeee4µՠ0!❓-m=uP>رcw=;.IٳgOM5Vwwnnٲ_]vmٲ{zReu[X\xOmݺG]K=?/[:g޽^ٳ′; &SH)2!"ЦgHm*J #@ӣ,=ܦAAM7XqFq0PYf? VtHM\b2IH$Xݏ:^q @ ] p}fAA[7ZhRJ hf$6xǹ?3! q܈N% by eP5  r{/'@Xp4ǘtf9Kf%I(`KI0uj|P,hS&^;)s=W[[k4-˖-[}]Smt: C,{gr\iwf׃QONNAe`KKd}>M555j!FiF/&f[cǎu]VU<3|~Sgz.K|nvX|~ٹsg i:9r/8N*^ fOsbH$XTca-z>L,NOO >_~k6x[ou!  Jq7Y,rŋNx~{_b?bǡYZvE3tu ,K]@elE֯=ްfUmѨ/ⵅ\Nkrt@$Z>_|!=qEJ]PKi!6lغuE,<#wqǧs[^/EQ~Æ oF!}ݻwJ488{;v@=6gXFFFfm6<~f>Y,rŋNx~sb D"~0+W\( IDATX({yrf򇆆fnY ?ot݂  RWgG D+cb23]R(K~t#=F-F&Rv&Ia*ڳgO]]0rONUU䧦E&xѣ+Wܻw/0L644l!JAIy~8!|!(S'].WWWڕX() Y@2Ue&ꭕ>s>RfzAQ>`ǎw}$IgϞmnn{>5՘ZvBe˖~Qwڵe8}ٟ?Y)I7`0_rX۝bbf6fGGGne/V?ʟ?yoE"ab؋/X8~Oĥ  ȕY"xJ:Og2V3)Ed`5B2KP9j1S881{A8pرcEE}=ztQiwygCMӡPh޽755]ĉ3Ǐ_`/|_z/VgT2ϟy_`t? [r\ccٜy ,K]%VZ7{C`ii h+j.v71ۜeH7s[h`dli;m`u[nWϷlܸBxȑD"!bWW?nݺٷHlܸJR\̙3k׮}ꩧ ֭۵kWw 1֯_! ̙3'Of2'NOX?O,w]Mf~:_8-G?QSSG}$Bs_>e/V?ʟ?/v^oݺpݻ={GB?[AdYZUqzZFՑZ#wN;⎖xVK<.QT*K"Pt/!|7md6YD"xBx͛7fO>Y9_(׬Yql^jU[[fOӴ衇fӳ}vMduu+RfqNW[`~>&GVa8I'*9Tl:o?q|4t*Dݩ M@LN0NqA8:pY4ridsg'Dי&0(D>̧ M!e #qߩDjpϙ1CӀ(tZ0(Sf#nwcS{ǏtvJTbH0USZamsFrF&Ip\8d1I`8^4c*el*NpWyIhĔFB(0^ TiP$s| ^V;gi@iLaV]\TA4(*+ ǚl6Omk}4'On}`j,ӟ>% CА Z(ALytw>䞌 HgHK)OL&Ow h@,-Qx*gqG ஬幏Ô&2KSn"0qTHPd^`95jD&Sڕ+?'s9yJӄ`o_[?}loJ:K4k`3UFjprZUe@-_oOsCPf#擏Nu<JY:tJhY8ΜKe87:We 8YcDEXOsPȼ|vGxzjZV|TvD: yfy-6`8pY#VD: fdȄJ@^SS/)Oh#ny&)# FK:tUϰ$N]j}; p.E#]uQw@O(acAyQNfi'1W'Ϩ s ̺{]s}@f>LyҦw"c3]2UpZr7X#(M! 撼e? M@Sa~ܬ mM^QV97nC%B1&)/i2b1` d[IAE~ڀ1fgWgs|>\YJJ@W|oF9*zeA0 F1b0}}VVGZSiէ2 6lV) I!sbaq3Ӹ/(2CRx9i3+c O:]I+(Qiq!F2ҽ_XvmGӧwɜf,,(2!c:M%!e0Bd>(3"0314R Pa$E'5QtDa ]i%5(d9T-Xd getjeUE3R#psI&ݨoW5k⊪Nryh=}/><`D؝Mߴ&s:L8RUՄp4~1AoՑ +;}VRBQT=)"ВOgHfPM,Q/AXQ]qƯoR7mR7ķn6T1#,T\!pes:[^I_U@yݰ3 d ֤tzfDAS84"M5荈,AAdmɯ#v̧JhU}ND06\bM7ٜӥZF!jDSC}ÜHE2:HM0KpxQE "ɏht3yӼⳔ^Q?+*MNh0mƑR&y,34:~߬v pf41(BNOL221>H:άRҤ%sP֫ NҌpEY<~{&o+^nUus5J!]ƨWW֗;pA9y1"U3G5JVKd_:~ӿOIy)@;V8mJlzx?~uהLV^P3:qkTY{muצU ||$DMH򙡱t*J:;9JdҀ"3UBՓCCU&:ld} LƠJ?;__g淞yo=v<ahΦ39hhб Hxn,H 蠊c$K `K@UK>7ˣ8 ZWb9 m m%SxHFHfuH T j>1:58:79H:P$4g5X2bZFx` Tou@ܠT 'R ϝ?j"Ԙ Dj3qIV6Ñ.v ??S9P'Y92Nd|{}_w~0d,==  !/iH:q6QYSq9=A:Ijf .iyV9iәpJऄU;60ÿx%qܬa g;YE|vXӳs@ @t,;rϿK_y8j$FuTa]]b7` <72H eL5s `A6PV&mb*יI gKI1M+P$x!EViGOẸ38u؀NFN|bDNea6|&Za{F[vgv{MvVV a0$aAc+`0̀dc mBi$Z[}=C5|0-?zSUO#MhbزirSdT#MӬ,EF#Q"Ҵ+SUP*t Q>ɔ%Og-8yaX*rQ]#}'vYygUT%jiF@A~{`iFQ6Xn$XXAXfeb蘲pJ, ($9[S 50kp=:mn8nP%@Öl|e7e\S~OyQDJaEC(9%;-=VAɧgrF&ʭW_qɥK4f4_TDAiWVAIczđeX^pֶ|ƁP lZ+s5ӵPPPN!SYfKRݰ E+j.xox˻4<ßbiuߎkkFe;{$u(VVPjM5\>S:O8jԚ~ Kڝ嵮,q\A"$I3TҀ9`zQ 'l^nø ˣ;$MK Q2) @k8pwnC=yK^'|r8s=yk7r|ykQ塇 Rk_pvzG0g?/|pw~>?vmwu {,rUW]SOF{gaaK?>|߾}<Eї/_V(_.ZhveC9cҽOO{et( fZ͛ @x۹GR1YSюZ{q^xYi`ȊҰW$7lgQ@vQxu:m%% SJcNܼkaiPcMrTYYYZ"qHlLRY*^b!) $=OSIS-϶,׬ZfɺBhjh@0 %:NVkNQGP,>(M0bcFaDBeee ʆlu&;025]TQRլ LLGS(`(H yɓլaoNS)g\08 Vt%TUa{ K QR)+9X i YOQ"Y0JkP֖b6Y,ձz E?/<_p֋oOWzp'Alܹm? IDAT)U;y:i<$qel d6x 0DA ‰0n^ L ߆IAZQ*R6j@ΈL9Izbb}Mbb`$ii8^KvgeDn:2 Ƚʹ)ɹ 5$R\{lw(Jڋs@bD԰$+ \Xv=RMD kY`m#+|. oz{?m_xioԴsPYouA>t<t'&Z A{ȓiXʴVs,4g[o}zwܹ7*c@+R^{r~%>HpdS*άؓ?OcaCE1KZxS nx gH}w#2@KPRˮOnJ:p93i0VwU_ř$$ښ&ԦhenmN:e7ϜWti;Ggluo'ʆ8X$h*g1OmEC+*mljT׻!cKӓ(ylx+T5ORM@.K~ ic"F%J G_PL]@'))fm&1 Gĸ8#J&MӫGUD)y*`E`h*H$mo5a8ZL;2$s85' sexYM:; aNJlSрY*UG56e#RxIRJ@YzPV63|ک (@VDlHm?3?C n{4/)\oŰs*;.)(I*R%)v^o2橦iߋ<4/y?;.K0_X ,Հv-?iXh455Eu]w '_7_?/D|al6z9cus k_{ꩧX j?prgrI+}1iW6k$^7"r/}x)0aJ9B}2Uq|hYU_t`ĺI2|}.u>Ɉ%8H4bN t[ gyVa'%0cYWt1k4js:e?%ݕ\/-?cuNUmFNA>̎3 jlYR@5L=zg߽Xv)n]+j65v}VYf*QȠQeKy:dZfՉFLfQuZn2B@=kB^Q,fWnaZ S@x6(Kc+ ˞W $q& ˫` BY( Ys}WqXkӣ8e.#Bi(uz/~#k;JY >rU&jE!t=#݃(T3۸b٪-Sm IE4k)QJ/ݰaFȺm$ph!+RH,SQX@LB؎ uMq;w~a|T,Zdom O 4Ҥp\O2 )8iuelDI'ͩ$U72{lW~b$ Z $K "LUR 0ZP6]qg7 $r]K+Z$Cc;R2emK$/<A =@,w+NuEAhhnLZFd#X~{+͜w~ Ճ {Kyص؆鱱TRkq,="˲T|Ky:菺 ]'gFqgpPT+Y2߹Tjdlq//-j ؾaNZ7=YA4ǀ%(#G[ WRAըX2HE:VPWH>>6m(E3U봝u;OpkPU-p5|uGstw yLFB0fP }u8()yŰG-7c"h)ݿ'?|f)g%EΡ@7` uȈ+XRmB>4Pݿ9Y_|9gerӘ[[]go/>yl8 `"IE"аdSґH*MtA<#bnj,M R&Tm i2H߿O?ηHeД,H0I Jr"_5&`$%IX1ѨI,&XY5r([_,H U5׺$ Z9Qi'GAQ*=ϝND/}oʸ2CXn TsK_S]g=CK.g 5k6 6n:`08iYEA*eY*(2Sڎ{9]j* èњȠRfcIPjň l+Kͪ2`8*ªV+`k0,JZ *8J"E$Z+@Ʌ:XL[e?ny|PJ9r7_|/l>Cfrr+78 /~,q}y 'h6;;8V~aZ=prҴHz"K-}pEęHA4,2McQ tOl6㣟"2-[x׷0(;+i<KrySSBdw}:]gYeRѮɍ M=M4V2 lQ Sm._MQ0V0%(+1R$"IAڞV% W/a[ȰM2cihhJfY&(fsڮNMGxIhxoIU(02ԨcUJk[ņNO·Z\DW $jEKt}w bYсl ˓]@zS3mBqP'9+ng(uA4 lZT7N 3؎[S|;-ȤL:Nd\Kk]"LiE+o,zTh!yP؎oFBCL [ [ѼV-Qp~$eN(jΦ, F*U"Q% hfmܼѯ9ehyiU͊mc 0 CQS-W$EAx@6̹84dJ<9sN<˯k66 #,MT [uW4$ǃ;w uXC$!T s%X6{F}Y/UE&p<37댳^4̺1}c0jlJYӼd,AQxuW_Iz^s3Inrҟɭ؇wl?xYFXu0GMžPdXf4@$[vC_Ν;ǿ,oڴ?+eY>o SC=455(C=O~ZϏaZoj C:w^`c<_ѣ'|+;w@~aZ=_.P(B )'CD#N5O0˖&Ґ`N!\~ZiПclm}EhhD՚ZȕMw$`&cKƜ%AFiA$ .dӖ 62MI'%J2,"_yy`T̷NE%)T[{M7u4ŕdF='񦚓7|?A[$8)9i@5aE L;)+Rt]k;|ҹ5 ZU_א*Y8TɀB*Z~ΓmSܒ3$ڼQ1 $ A0,e}t٬$ d(R1$,D$헽$NkN=ǝizcÑjN0yp Gb^w}v*{ki?w,aov(iċE,szXJ$+qtTqk P"~bYBL߈ŽL5v֓vl\lˎ%믾*n9ھGqA%Z#[XsįX&DJȾL" nMzR.Bخ+z,2T7٭/on)a0#8@V_1`HUj)`_󦛮].d閩YNV"RS0J(WOnh*:K l8I˔20V;nuLU<<=a͟o/U_~/~@`Jh抑N1 צ,k3P)_Kp@ֺXt^(U@V=O6kb)q<-$P2y\+eBʠ̀ԓoTZ*z'p)I+y$1e`lE_w] YN~T 1[gpgo.St,^N]~|v-N,/T_p7ajII+]VUIR1?z{>spNpc r7NWR7u>mynnkV rTo\zD$1 Yb'ye\ޔK떀HwX]B4*#3QwXgw}?;zS~9a $aKԷ)XnMBICsMe^jCZ׾7MBrwJ8U(V㠙Nd=8ђa]da Mwdd¶M{c>3"*hth!̍tubTU58O_zƅXC5~~+u&Ԣ0*I50o8io}KU昪Sڞ[w<%vnyeώ]VM+Xa%SrJ3ta;|ՂZakV|x_ɿua(JZ͚`۞Nj6J/_v&KWJbQUrb)lݸحL;ٰ_tmv]廈#nu.9\`b ӕWmry%G- n?62%`S3 m76W1)o燌*@m1ݖH6>H=҉u4S{{?̽_lUXaR8kVO4sU ޤ(9h, CWK]eJ/n?{{$ڸ_kIqݮ7b8XuFC?Oµa;%bw_'NekΕ#ѣEݷ?X ]Q#.i\POӖ% IDATU(1aE @PT@@ @7I gUgPJ*"#Otd։gg/siTIf[ư(cE_,aLRĺI^u&Ű6NjarkM- ; \2$ 8DꞅチF{dw 2͎|9C:.6yYKEװSNV=}m4)@­pyIP2^Y8{uR}bSשӄF]#i5UGh^qI_ףxnGHh~Tw 0t۵䦎ji_oiʶ̚ 0aLC_ BA1;6պz.0җGpR~ղ&kT-T˦B통4Zxu{b?R b5Zg5i,90tiP0 $z?Tܧ ޹Hbe3)NHN~ I RDDzުVih뵑LUSÊ>Hk덞2*2 hGPM:!v]r!Ԡrpuܹwey˖-Gesؽ{iEQ?Pn'дy/,=/,u5;놞naL%Z};0ҪRxP(Xt(/]BveqS U+Bh?G>L#\S)C ZW欗eQTƷ&Zr+/3Xԑ㑂d۽(%qP.^6yNKVZ^0Qd^7!!e/5$ôs+kc5O hV&QN{3VifYx¬,.]muJ>Rx3nW2:iab 7Oʂq3Dcs)2ۼsۙ[lynqղDiםuVVQa* BV C0$$ })cx'aj OÆ R6cS+k{:rP6zʋzPRdň5=&]^neIMü`)'z>Fuj2`Š,e4q8sr7.Crkk!Z\V6dС)>྽P~) ÜY3͆i#:Ji!stt`n9nt6-ǙzH"Lb65s6+xcH f`ṖCM |f}^ @h0Q(Ӽɗ_Fj%+!UTՔTm;O?c׉?~+a傒NUqs&"1i, b]rW\|#OC~E7$tJvI }ɼO?}ɊB M$%I{mG9C 2E)4WYT0TZ^sxB:Xbҫ"^N.{O=WATdEw߹Ogl>XpK?_&ˁ2lKoA,S [!E!$OLH =6"ZXʂGWeTUeʌ؆염=B caT=(2J|whEm*KN7R]X1[.Knm *+\#9_gmG}i^y7Q(l!`d0k<-̀l e#ϛߝʡW@͔+Vm HL~EW?ܚ"ٛ~6h%8538y}Aڔ7cA?rZq@' {9t|u'k6-gk;u/'Sds,KG'} c #K힮xs߼8>%/i콤5|oE|/X/D8I3KCáY(3p29RR)κjm|ss0ع?9sY[Ζ$Ofk E[Y7Ra,]+Ao8N $`}}3dMj 0Tb[qln5@RިV.:YO%|p@qy+NVY~fb\iPRI% [%uHB Y)JR1G9"! .LK2~E7W>LywOخ-{nAhe\yI.@'%$*Q:Do5#۱⍣|ޠjsW0OS!%X]W*LiPC`LTT$( N_.yvos;^g0mpYD7džYI;(Mj́m9ar ~\ hM関Iho8/B1q0 HG,F,ԋ&.RU.Gp67"̢,y At&|s,֨QL&̔9S/,bti'Q? Ȗz3xbD1잘Ȱ¡SŹU? °;}s|;n67|od]ַ~2~o~;駟u}ǎw}%\2 Zֵ^կ~m۶{o[GΝ;?яnp}eeeaack^_?W9Xu#giը}Vk,sQ1`PvͺeFYq\HxAnor‡~D K2diШPy$-=۞j'znkqު͞wDyc:AR̜2s?׎u*{~_< O>m8aD9("N'>%,uɰOUY+I84Q]ӵ׽-ɨw-=u. &3T1U& "i,a뮩iJڳ͸,u &AlW?V%[vY6$!sqj$Xe2Ij69xd(uiQߪCslƃY3οW^|,ҍA$ &H61jfuUQf m_ڶ-[N`KN寿9.T5'Uy_$4~ߒ:en”NuGag~xbs3NZ/o|;%3nB?Wʗu-uKG z+6ek~ɏ``sI0UGIK"th4Uff:(&*cwW]uǾ~?-g|p!?y`֏NݿGժ2/àQFв uy.$.15m*Z/TjIqa4@E ٨`{}||KyOy\r>JM14ᒀF۵LXwMDsYAǙ*3)̏85SG|WSH 82Q3O=\9OH18# '!OǘbiZiW򙩩gNmA^B}\Vc'exUp5cϵ; 兦Z/O-E1"Hbe5 EQժuƧ/̣_]I0$o6:s`{4V0* i3fZ Yimzv9%9-7Ǘ_zi\pMzh+sec\[knuh}(qDu2.&Ch$ v.E0|Z㵮ZL-/2+UhRElT\.:q {<5Z(>H¾G|jޥn?X>q՞$O6ק.,IXqR`8 dh54DBb?$ ߿+,<<_)V]l;awE9=ukz [}v=f4˳Zk>D!B1-*  ,6H5M5׼?-$x: ѩsl3,e xiK.͜[5k9YY|}~[(A9MF;X-5:$#[n;(]y8jY8ϡE< tYRsf$24450q$:%q cnp۾cݓq6i:>\Ws>)m PB(@d "Q$c1 W'P:"Vg2֜GC#T9#"o.8nBl@(yA==M6 I0miJ,xȂ11(1,6Tmݳg6UIQ{w) S_ۄD͂TνCF^ӈʜ)֜np6{hլzL*hllkBZ>{#={e[:g8Ѽz_KN[dt՗< V4Q[^1!H$-5̓ÚmQyW_瞿.tGg|GV=Զgڱ}c7O8|{c̡o~KG'S7-3cm,,q>L2NH٩bٗ`ԓQلH,KAZ2r!gSG}rWCv`i/~'gww 8BwkE*=˫T0rh <9`0H  m{| QS.ޚ-:S^0zhT%(Iu>KJB]laf$GBGZcN3̫.8;OZ^ܱ+H$IӔ~EwA/rJHEi\/D2QXhm7 IDATu/ydT+5D93D$J(jkSb;ޤכ4, Z4Sk\W,b#(- ˤPu3 h4k&"Imԡf`] ,UΊkn i| IDQ'D)Mj,Lnqp$,4ghS!Z:';EW6\5+I}M6û|$* Y)zm`WXD'8Q,.9(/9=}O?Ͻ6-׏mEW\i-BƷ?$li:Yb9NҪ"ƑF iT*7 5ʫKڳu;w,2̳?u =#;^ykNZ>~COohsEe۽qfíՍ[o|{oZg&NcQ[=%u-ӻXwPlnih߿;61Rދ.咽 Jfg:[:RȚk"b[6/5tJ5J$g~\]vu`]i@RsJ@82{Q­ēTv  "")@5/azs/#㸏Di!==U躀td%N|gI P $W[45I%tʼdBi6ds Q䥟tOFqY9R)$͚4=bRl.dfGbֺUCQb7GILT .}=?[Am0 Y"7k.ёE"gPzmȊc"4emA 9(t Sf°P#6'\if1+/{s pc|Q[q.d9yBB9ȣvQ ]\=֦lߎ=no_I'nmZ)~g74}' N3Ă6SZνwn~ _xSq VmqߺZ4IxQ!]hfTEH"׽,"kA u+_~gtڦ8*[ZU;3lé-=|b՟lp`D %-ww߲5-.!6榧u!S30dX!\z{qH]FX+KTtOyƆ6pwcѝ$׬w hֶ 1tSJUp ("ohңR$ X0d"S[m)_()K(?5/5u[6{cHVF, WnfQ,0} H_pu492.c?qJQ š`v[4e2` `.vBDA,$%Dı`AKW}MIɆkP<YVZXcZ8A%9zRHnZ&eLֈK˖䉟I5,ʄbũL$Sl"iVj>2ιް۶#׬ ͣ/ A.I# 84M]oy׿t-[w?o7\mGG:"٘dI74RYTR%Y LG_M(nIxoqAlj,Y2>bZj=FSJֺGTʉ$Q:;3CC9v0XLC 0Q Ԝ Ynqd k V6eXP(Uo7Q,vrWӈVr2"lK]3D3ѩn͞w)C)KRjNMVUFdZ8/{z0M .A @U#)+MNYf&*-ݶ ϏtTѤҬ:(o,.x K! l1В 81ĵT\)E>"Ng*׽m/8NÏ<ص|{Nn׿+"a - ]]xru t\uL#myY).qpCPBBI5uJE)(WfkITkE$ke l7/c *ըA )2*gU +(tݬPBU]PlL{è+Ac$RiWYCViY=s޵Ã?͛N,<|ֹ/G/:_qf:Lu:^Yd~M@ FO2rT?\kQٍEVfIRȧ~rjȨZ쁟0DBKuam^iYi?S=W\ 8w* Yfx,M,k[z'CJ1@`(Tyj8%ٺ4e0$V 3]Ӡ:D̐,S9ik[2S[Ͷ`y.*SGjl@-N5 A@ޘ9׼ih7t0ݞ2lQlWxsby6sw Kϓ@JG)'z$^_\b+4M?uZ*V *&GqV, sPk\cd0T ^4%nxol9^X,5t Ԝ3ɓAȰF[JNb!(sh#ib̷=S9/ óͪˊfyPOS߶,)HBE)ƢpPpU"‹.\=rbiNnQ\õn!8e5?;~{p"8#TK` liV< rb []vŅ*ǃ8|##L*Wn(\Lu$$rhkfnѮkKx7o+ʛ}lC"RՑ瘗_y١#A]Pb&8,(fH=,QRQZNĎj& DR Q*xZElXوrܽ܊#TVHV" F$M&R,Ӏ`Je?4ljP ]=>Sj;Դ0BRQ],ZZmj!5 )`ZPE/8gnfa0HWWx*}7 $6]mJVE$OZiQOkdaIќBұVąPDAIh2`T"\r⚣'WJӋ$D #MK1DDnjNiNMtxxmc<2\*|sy5e hp{AI BjncCTMu%gBQROaD&aX(n8Vfc\e4]5$Zq &!zR*F`m#I3Vd1oHTXs51h|z`w_t, luSm8 c5O'e[_{ӖkNDYdN,<D=9a/F}۟L 8/S2m-xoHwo;5dz>Ie@ɋBF$"e ^R5 9R7/Us[v<У_}x5\w?qa!˶wm?=β\G|@a:dETבY*,uݲ]YePjNdhO>飇xTt?8Ӽe,^«o?#K#4F&qfls9@we6N &TI F` YNJZPw~>o~K|C3|S4ސju!_\wwT$P%?aE0 QB7Ugth` Rh2Ux$6Wk+,KN[~|{?g_M sK_PV:?{RgV:Ps~OhZ[vLSaq0\ !T,*nJDmX sR-;+pccu~{{3AVuHZ+B7*]Yb~ȎZ;F:Aݫ.4H IDATzO &~&[̤ Rv5|f̣\dґIGWfa4:\[?S ;D&Ì15|sU3m " U7N@(IčLZdcLtz2+͙Xj\K] \%i5b8MP2 Օg{u]33VS3εf رmٵXhW:q)XNԩ.)AaQbcz>+Nla﮽{ʘKn:z7gn>Og 3O?_$qu)N]ÛsC}{ (֭^[{J  #Ǚ$2hR>z7>{MEnJBlQ\qk-;v޵pץ;AEUkeMlȢt[ !h *3 FszŞza125lH@ j4-ɄHoow3J@zgnZ7j9o߾[n%I ? ~ni~~0ni0lhiimo{̌{sN]w/}_ny>WUZͶ{r-iy~~) _P'Nxsss۷o/8'>WPϿASSS~A_ V8 tluԛ$W]zW^0KRgzm6j&LBSdliز7 (φPkx9 }znzEADHA81o&1LcC0(FAeh3yyU/Q_{gu?Ϫך P o" ;ykt}(c[58:s8ͳMw~65Fuaϡ~R@r3KO2d1?,Ip1;?˕~?4JU.o;לuf)2*3.JQHVQݒ3(Q`~c1CUdI^if6t0L<8#OX.~W|KK2<)j>s)RB"#*ukdU@'xh,iB'=Xȉ_/k6nZS. ^lhn4 c/x/{ݫ^*9ⅅ˱HvBNGeR@1lؗjۏ䱣x'=7/Y"g"4u?;NXyB/:KE,ZEO۵7E#YVnV/y !#kN(Zn)>PD,'go}t?/͆N{}7n^,\RRQN)JnƋZ_k զlٜiQ\&P~v׭߿ t[Gz=)]3 B|Go $w5JMs]ֆ-J4}D+G^'ؒе/{?O}n͚Se:/ir4aI e$w!@s$jZ Qaԓ{ڋ )HMYԝPF-/5ى {ď<aΡ~/9rQK Nϻ_ 7|Sɏ/gɢ$#X{>xɏo!)08AŌ j#/:ᬋ$TQ!+c[Кp]~;t`i{z=8n=𡇟gLL̲ ___>S4|]w?\sa' j@R)[!԰ ALh*c{sW9*-ec<0FQyX%]k8z#eԲ(1sQ^? tW nWgVǝNF BH(@Ȓ2pF啞ʚvI(UT4TO_¦m5+Kr>xo~mnق`1G?2"FL0%"nR"-ӃL;޼0'ϡ߼+R$ICbjhŨ,Wcf YEnkabwq'&Dj_dW`%^Al:!(ǫDD" 4k~_yR2J\R< :=:2l\O~?|8Fe k֭JRC)*-L-|~ 5\I%E̢*-56mDty/4TF~92"ɒc^Y[n&h8SG.N eOY/{͗nP0y2S)DRg4bi^V9c/uVD۹FTJ4ݠ8# 6[?`B0U'OE%n{F1*饑%HGnfBIANOv[ahi)dj}fqAfaT/pdEbB뷝ww'X;$Ù1A@ zI0򈲍͗M/3wLNo~𳟺wL9r/:&Gjur( <`䯈DPRtA<')_`Ҽ_R~o?Ǣ`1a*^@Fv oy O "'Z%UMseUp̓B]al+NӔSxMT"G` #ˋD&NԲ8jmʸ0$7ɯ;/$W%?do+۵O:`?m9;/j>8qv[iuܜvvn}(t#},U|V-Y< j7B焪N;-OMGKO_^ a?+WT N*؈o8Eo-%lC|FҤXMlʟuuO Ikt1M}qTLIDJ>FY{KmjD M:v4b\H,H^.$TܴR-iL)9p !$=3u`0t^ DXC4Ì0~\91OW "xI?jT-lq_)"J#C24ɥVxRUajDyBD n3e,ElOnlQe$n'aQ7k%E^\%ŒV+AdҬp2PEEQG=Z}^DH蒷8?G}e2T|Ezo(CCqRd qUT$jM<5*6ԬC bIKZDeI/Zo= 6aLE:a/%KH&4|r6Hzlkjo0d a_rVkO5VN*%|Pu%7KfljPaLg r4U;:bNFq$>< ̗q8 V; )z72 .^n΋'R1SU;՟ﹽi&GDiѴLKduߝ $dDS9wB1q!ZB( BAM( [̈́(ㆉF}E0g!3ϒDn #`ZZj$ã2YJWW1e%9ฆas~gI'|[󇈂?O {' k1 ;S/xٟ?s7,Gu9TR,#`Ya, 4Mqv #t͹M !F2Qq @]7?,zYW\[ ~! !zBQi'M'5+Ԅް&ruJEWU!بԘ5h,{o?pßk߿?`) &L't-Y S:={fgT9dPUQrJE0@vR-#k^7/∊e-lsR0̀5C4m{7:.~_}.IhntڮNUT}tU,1ިq0qa͸M=9(mc5SiSk-R5hB&"ŎQ6'تcUҡ·br!B,B46aNHL2ɣ%pM uK !4HS15:֘P#IR0l:dN,xߏTShȴpC \..Eayܱ8K%""y4k<@ #6JR_nHedyIfq?c^Ucy4!To tS)\䱘>pVBi0ZgJ&JReC|?o U9vVHF^|bbmhS`I"dsΓO>>ϯ;xK^s`~enڝ%Y@n55S: ܲJ+Dq AW5C #ɠ+sV3WV:AgD=LcA }x[+HbL? 1h8HH DxYP"ʠ#AjmxsAG?ޱoߝ,~ϟ~Coۥo$n0 -yjV*Vs(ym^N &8ri28wv*+5R?0XF), uWyK P+kN"HT1FHZJRTK@~' EW5uŚBS=YQs|\4r8/0%TM8H tt?@|chM岕a毴[9{!<8pvNuKT2N+V4 Meg݁O!i[HƥQz|q~EEJ9l/}쓝# HWI!"Š҄,dc&g{);1\#3ǎ-8u+Ǝ_;mk RЋ¡#{ʧ-=i[_|)ؼ3 &F }D=,㶬v}*B[L IDE2Ira(ytɇ| HDrpyk)Y^!)FzIRk/Fn*B7eQ4S(@&Ȧrrsl0R+P♔m+@BHLh`daN$6L! u (P f.w^+[(|a8)c%g IDATMM$Q!(tK-"(xy E.V EC5fE,t"J,jHf) &"=~]O?rELKIzZNo`k 7_/^+!@I(+P(#Re/+f̍<^-P@XәB)j*({Xd!@Y [2%*+0yNϋ}r>{ˎHB4g~-'޲FB/$TVx0a(IZ4eIVecA6Zn`]Vox}{K֭[yQB(u~?{j`yo߾}>>޽{bb!411{}s~?::q|߯T*TU~k:og_MjzPQrlj\0e0d,J.IfB`Q8\SSA f.o =t,i„VW+b44$AE<*0 ϋ! &\I 7:1**H\Fgm7 APe_<߰,~C,3 PĈ,(9dfsh8w$p#:8a2I/a?3w$^*z zcQF-(0YUmhbȋ=IAkc.'뺎{QzX/)2o.zjTS&͒2VȖ t%;E2;vwf gARD#Eq@M0IhމO~/ԁu3Cst,r"?~o$k@ |i,0žZu b XkĻG7?[+ԙT*Vplw< *;}wnk5C*u 0Ӝ "bA)t]cWմt©.k)q0 cFL4/ ] 88J%Q@&RŞ)PQHB'ص}|dž3_|w :3SSFwp(+ڨaV$m[M6-jNKHT24z݇[~bn|%dQ_y 8-2!CYA, +42&#HS$e$r E**#+iPO{+bh6IO98Ȱda a| Co$74K0 D $)٬u}{$m\-۪Љ"ìh >j3]wZ,L!/aW[p-Z1^ıhK31y15CF`n*1jiDLӼ꫟|(o=zK/}`y~O?+]ZrWn? N;,O9唷-6FVw7Ms8>s=VӉ1Ї>~?ƍ_MjzP<8+VY/^OX~|;?^~jols%\wY=ևNt˜]&SD"AZ40À4Qd,"N ֤,8:PHrWNь$LN?ob4Xp`vn착ȵ x. 9%95f [y^״M7q}7yT(-|wI%YhBCܖ!$9ݓP0hQ[eATh (R0mX9Q<f1>vɦ,Kp Ïw J}$ Ҡf Zyg E.5ά7!QҀD0pYɰ@}N()5F gBq$+$_ON$a MS0a UYEpE$ ,+RxK |Sr%#LFGtdV eÄ㥁V5y0k~<]pIQ۽\5X*`'Vĥ;| [p ,W`TwS%g7ǁa#c~ꔙ 1ٞ'fx̮I70{q@9IYtM6,3yicyd(Qp6쎨(㛾o{A8?+֋AIʷU)^/wG`Tf6Ѥy$Oqs#&sc&bt{JQf sA V}BiZl"$4.2G$d#T[@ΉE(b@Qj;=j!+F+b;-(TyщNin9-REJwO@dsR@YA?⫯EŻ89ÞX$TbEWGlnCY3-r`DoEeЁ$JsDV"@LSH߻ܡ!-I:" `S!s+ IN7$)[\^ڪܸn JLm/}ԆMU/^4B<0 7}L=Ҡ6f :D \ѬJkm( Ԋ%3\Dɭ`ٗ~O<6vyڰF,a>**r8\iF xη (Zu=ԔqT4gf#&Ja PD{-#j>o߾WgߪW?^WscᆱWޜ?'^Gj7@Ñ s-KD)$J|aY!]Ca.R%ymW swbC]n=a9XӁ?TP⇩7C=9rb8)ipJLJrm9BqVE]ɻ3%'ʅWbu`&f ѫ~rTѦԗs)Ƶ!iйbD9xƹ6u⮃E^7Kvf׋%/߱fC#')cHsKyb!+O\ qX#n>"׋f7iT dS§L%&n72Ei8Owܩ#G;DKK2O3Ȱ%|$ǙS{~cJJ@C ,ᢠgIsFJ"WuY|!,hF iJL$Ht`={=7LgBr81L` Z'_P:qщ3^g iLe%* zqdKmIX,u*"/h5+$!bRԊ$LE9հ/AdXm n}-ۧV Qv LѮ8SP}V-0HGᐹ <6Iq%ɒ쇠) /zr`D95 ʛO~[RݵE(iS\)S>+LPr Nn`Nt ` (|QI[v1>ퟃdhiӛ'%R,bmc*sIp^{+O~|UsӕgV cH5XtTsCH\HDI*e_dt^K&8ѳu \m F? J& Q*Ұ:9H9+K'e H(J%Ef+NhET#meKP,]'Q7S$YE;+'.qbRLR 9q yv/ [T.|/8qӱ}?S@(Y( Rwk:2FE1(A*'rLzfA(d $u=UTY" iXi^DFvѪ F`d#894|L)G T*I0ŢQQۮÕb:$`e9YC iB697d.ҁ?yyY_ꪏs95\c楗^zyY522W_(__Y4j-"1&X,NI!Дc"` LM2VcI p{00'iN{1( X^hj%i8zXU1 \Xi;7ְHa^UŤBd`Diċ"3a,q@25PSTǧNw?U ,e|gs$q^I'|:ѩ'lΈ=}Fn|ͧؕuhT2jx7gt0_d7eX*7'Tj0l)\v{=y3 u,w獮MVUQ3&qU @Y#dĤ*kn ;||oĸO_ QRGY`(J@qAgiA-l@qa91 l 󋣜"W-BVu}"hzwgn?ol\uC8Z{܅_ϗw60iy5t6:U)` ^zl3Y91끻v{^3֋Cb5Dw3.#OӔSbf}.+5 ނvA(ȅ nrpl}?=}'6?lq E"|醽ͫotW A/9wѾQ2(~c=A>G⍫~ǭƷ}k.|'=f`.u׷ y$sJq U5O0(ɬyUN{`-H2 m휻~Y@F[z@yA IDAT?裏rWWW}cz?d2o~~nyypʕ~?l6;uG>zK??+bX,'-m<|Bg_~}ee|ܟoY'CZ'?Z?G~b x|{K0MyP]W6OtD٬s7c\B>3fwzM@Y#9 |b8a`TR#qB@xh(r.nO~귭m|M.O/e<4R9*ãN`U=$IV_CwলQM7Bvٯf'vHJʽ? \|~2Qsu?Ҫ0 Rg4>oFcp}V/Ǒ;nQaܨ.Ԁбj[cۇbjSK`[T.J79ZM7@1{^qO8}3/|mffEeE-/P mom;k?s ?y_)%ab2m-)aЇ$j-a Nl @@c~X\gj4\D YW"M<5hU79`{b^\?­Λ\D%X*IJvt{q05R( |Z:~BMSM`Bm`2l`6Oj4/ao׾G?Mk4Y:~Ep; 񒱍ټ-qFo2epS={߹W+_}z: cݒ #]uQR:pr}܅*!rxu{CAMSIqC cVTʊ1 I]'!H$ӕG?K;7Ϳź|/76(,@]Ka_:ywӟtW^yQ?C)` Gl_F J HkgyDp=oyF_7>3%J+AU:뮙(6ӽcQ?dNQT%laԖjb:rW:խ7S捨ZNi,N\>u=߸x_iխM?.0 R7xU9xnqM]KGFTK.'#~* !gsB^YW%ZQwp۩JcWNU02&eE4Os E \'] E:QNyS[\#B5wN U}uwWn_[AO'ij`ks%zQЌJAJg (uj؉to~{o<ԫ-(YBʤkUSw%uo$:e/96_,|7c^}P/xSV7Չ:]̋;I 06  . ӎvև?e懳CRa=rm6Ţiփi':(4(F%9IC;tlL ܭJ $:ƔנlBN `PUQ' #64\I4׋屛{7hVi!ENHÙAaEn7^̀aVA uC(UQDA!%]jdă?o~?_񲗽e_IUP TbZjD\=dLZ `B[ 6/[ifku^Nbzm4iG+L='y;2Ha2J p.c!3gzfqGSk/VmfՃ GaU-a ڥ~q@:~ȧK!'Qg?i{'qhhU]O.Z"itk8pt#H]^zW.>gT)RTQv -$pKCfyi'l^( %gNB  BȈ7ݴwo{kcKKO-&# +n}ӻ軿;lt͛qٵRK]ꇞ?+J?^B<#Ӏs[nd&n8MO5^G!dmX ь))- QPp=FSU\/N1ƒ& ،8yC鮯?S|ʧ 7I]xRL93x|G~1u'qQ|6FEֈ\T3,$oV6&flQ5z!Q;JUJ-6Dom[W|ӼB@TkXTR[JA!A7 hN)P[]b cB6J.\4)ka8+X4q%)c-چX3̣>u]ܴt^j] ukg2t}y.Z9[\[?o}ps65(JLY-T$l-Nb/|)i-pY,3kWlrH(tѤ kM8eY1)s:Kdԝ}cg064J 944fJeϳo*4ռ鵫6:Ē*M+4PO5Ot""-ZV Q%xK^#XlD3_c>xdǾ TV\p Z:I^k[gǶ!S@6^YÂ"-JJiY+y7BJ%XVV$&2AR6W_(Yzv &aڡ\ "PrˤZkv"aQIqY΂ȭZrkzAkҐVÒ)[8A道ҜG4|k1it(Fr1 |Op#[:nmS{Qq6{;;O]o]_G~/cy^îвY!<7q6rQJ SO1HS7xc@4L[RI c'Idbd]"K@BuMB^7$DLDRmRFRKʹы5Z=mms/xir.-+v߽775 1&T%pQ5O./g|}Y+o y}_߼gnk7=[}pF 8˯{Q" Ԣa\ wv4uPJ"y;?<:re-j@d,D"vw9h?*Vي[d !mэra'X6vaiG^84 \BBCJ OFݕIxht|qu;?T30պQT 2nA(!EFGh&2{1dY֨KRvkmxjF*iYHAJض%P,FJ7^qO z\Bw]zibX:t rDn7dvUa|כz{7sϫZY|ŗ^:tַO =O^,E(jx%l&!rOʹX-\S܈H4B%u|:X;7^im/>2|x弇'ҜG=we|㚇~ .~%,\,-p,A4$nw񡞎 j)3 ^Y4|o}w~gӂz/KX7ˊ1,q#.zf`:G$9v C" y^)r[EKWsc#awOmb{&,/gq5 l:yfoyH3mn%ԉkfZ,j}ቯ?̝66~/(a:|@p%[J"\Z_`S.8FawU]}6^Ы 8VWq"J)!>RKi|.%\A6ͪrqS<۵*ݙz:"gNވxVNBA:unX1aub|x;[~|p5޴onz!r D75PRXC&vހ2a*ˠY^_%WEIVXT<|PuK=Gc w\bMU>NyBQzh|2O&w/& kEpXӺ4-))۪mYAcE p%eRuэɸzifcQʹL'ꄆ C0 iPV|> 1 MTD] s0URx_oL>g>~/|?X^e)JS<%Һ-ZO:ӆ(H9~P4OEY֐㶾ms}ՃN`m2m:Vk帞ԙ40p[E=M"g<ՋㅔI8Q$G]5x W0jnKmqN;ހ ]A7$G3o$їB6_[N~??s}gTe9_a@(fe AuPj  o*tX[-6 a4g5IB\`>ėXMpRˊ4Њs@_L8Zp%bzHhxآR P?58U|OxE TT.i[x6DaTL'k |U^'szySWaeY{{s9m臽e(0ϔhZN1Db^7;xᰬJk[ M,d% k8ڪ2IVP#cg~g irvoEe]O9;s/<"YZ~0LHqDq.PX W"n_:< 6WŸ㑢je+f{ë4>sI@8Ӽ] h;?be7)rb,P6&u;K4pE^#7 m4@AᕝFi~d%m@GϿ$)ӏ.}]MFe ()h+6p0 #Z#Ƙ3Nnl\vEi-Feg~9DBN7T~GU[ga\ǝSf(b-7S弹n8c Z cJe $38<=A[[ZkUHZq+n}.[3)/{{n`sVImɈX)@)9x] M-C{,2Q*5RE1z=_:e!V6VBEZd( C zVڦn}#} $w~/[]=O6:jڥs8$de}廾믢* $A@.}lm˺HI{8d޸|bTɪ h&(رZ>-\Z懈@)%ֱ5Jbg@Z,g?ǿP${⊡R1sze|ϏcFx?FL'N*6tq c o?W?;_~V9^.q>\N'<a/hcsb[\,j`cRii]M:kz}lϱ>yS{% wde1P^9<Ĺo̯9x7᛿MFӣKUG k"D00Ί0lTf $f-A VX鍩UfLq74&|>F؋o쎒$:ʪXOHk|vN[ IDATl|EقVtxr$+Q>%RYA5Y4cz._|xpU~(htW{/WU׮KO *I4I!0 _8*@ysq'ѯ߾Wy~:i:;}xHillFә(2_4hD}b1L&KReS,Sሢ,LBxq6|]Eu{Kif\è?M'U6uOz.|j'I Ÿ2#B@ >Z`<ikb!B#^,b0vO;qʭv G>Ϗq&rpmmawܯz-yD T}ph inj8&N_[oO}/cy^^o@#ċI@ ~n;'ZZ{\=hx!d}l{d2>J\'p ­͋tj,%hDKᠣ ) 4QY?C8> B$v)NݴNu:a*`5E5ˀј#__|by8/^> dRm-BAXyYX i Cj55r/$Ԇyb*+0DJY j.!51AUYM#8'!ڋzux$yl!h(yՌGqxKM!rA^$qptb3nג)_{k?:'ٯhFm\zNf:>S'N8;丐f1ӏw?# Ш8~iڮvwۖzd-ʲZ]\߽R6d2+r5D;G{S-gj5mީ'Jx֮/1lA"DV\+yQIl1Ue:40#9cV86~t7og?ŝ|4э+[\$JBJiy>v.xtrD +.“lh:^"[Z?~E`?,o!17 Ƅpggٯc*cCYu,8s|"05Lw[M՝c%^_]կH{ϟ [^!3>:,kɻ}^z. 3 tE͕EH9ql]Ed # jG&{a@`y2:(<.MF3IuC%Q Qyc M߳wKoyŽl:+^=|xE}G̨, Շ4֝m ȭɗ,?!&ԳnKn߼Ih9*2`Sk=Fi#XDqy˥mQ8QX45@$cڶ%lY& x9 c]^_l:ѩ=Wx?tQ۶@+`@aBIǻv6o]y+U;fwUoq[ܸiٍ0x|o$?ǶorMB򢚯}g=s=a`ԧp4~9pVRJ1nnD, ɊHa lڏn V HCEf" Ehfi`-f Uqמ ,b 4pT3f^t^m;q0 f08nc ȕȶu~,- -FdԂ(l瓩2L6JTm:c][ݤ8"A;#_yQul%I0B:YeQ9!#t]eޡRFi(i{hum0'^O_oy^,^67Bd`Bү}t~w>uW3ފ5nuwfx.'`+\`Rԓw ,?${w-}exb/&&h\Yv(4po\6 my}ύYn 50A6}䇉[xUnL0# @ Ob]U2YY/j+Rݱb4nV4M^G` ajp5Idck#=z =Ggϟի.jH7]ho2ҵtjDmmV2YP{ŢWJl.V +㍋A6QmuP- gݶ\ QrWJH7#q')9=-󉫵2PwAPD4]ZQE| `]`:\MCo~;'.ٰ;"M( iY\h,O<∦t͵؏I+ju+j=/NCMp?#['xn:?e?If}_E`ks`;]o|s+7w2ww\~ /\釃^&\oy,_E.vxhs'7n}wy|`tAaU.z{;Z__'>~K Q5 B'V*ZMlD$9M=BB&SmӲn D1Z*'r4 w4^cX.,,㫗M9't#w}sU2'Vmm骟>[#DZ$jQ 9Wż3b^$kfe,t} .b݇XzԅL8T.<pyx:*-JnP6R!'1 }*q[AvtK[CBkhж~qw:|_"G}7*φt汦'zZA1"ļ!*M&YOh5ƨ =<5y,? ׯ:W]UZ]{SohZiz]w]$'{ 8+rnnNUչ+r8|kaa-oy,˻vWz?uVYnz7>s;|eV3 c׮]]w]ϢyNϬS%>Bm۶]uU ^}^n̖''ua t -IR_1\C%QVT+4f'<(L4>tхCYy>'8(&;;풗{AId\EJ<&!sUE*6ml&m5o\^7ꕗHBj׵jvf麩q8LwZCo˜@v|e<q{P IĽj E$ UHxIdIH&8IA()!Iǃ#ߧ3ڰMCą)qq0\^[[ ,L >zы~-[h1s/O,zA)W. 㺼2Dz?h2anBuW3q=~}o]wϾ}iYQJHȤU$ѮMe_}?x_B zη6V, r6! rCJٽ~H<4Eݾ"._2$eTWt0J LI>3 ab+@M4*1J)_z< '( ߻/?/?XltZ춱ű/5(dE Lk/8): ֢Eo),ޓK?+G ǗNjVcgyXqq+I3Fq0lEa:U!(;_uBrub4^\'=E[ѐbT#K5%VBQ ] $a9㱟 ݙZgh3N[K??{7/H4Jؚcqc2[33R+wη^ۭΡG^z+GIy!)cn i*4I v0f70&Ix}ȕJL<cZ V 5ze:c0'd%նZ)/:4tťs;FADXdw| .կ{-s;]ĭBP $ b >Cq FpyV# % +صigԚ0R$C%0Ry?x[ч8Ԋ( U Ful)+k+&=&mC/i(D4x?X.̞jR^H=e6DV(*otz^<ܵ{[DYHJpBAUfӍq'ibID̤D2mkv  {C*`n2y? IR\\ˢpF#@^~K_ziӗ{?F P;VO;?M7pϾԖ50(dl#FJ $,g][ZU贛ڵzӲ h9.c@FܐjPI62 bRi\?W0:Q DW$RG4Hf]OUEڽ l鸚 =K*K` R''!D]*^b2(#FW`*hֻ~] (,ɆV͂b(i 3,M2\Z!7,9wHpwnoنa99ċ24I@0stEۥM![Ȫ&^sozӛ韾x=ϻ^M现'׿,۷/ }ɲ׿d3tݻ{ nҗ曯oq<p ^{gYw=W_}_#m8q$~=y?SK.qx?֭[_:tY_/_:zbFmZR`4&D47 RMU d]%Қ V;PLRow1!qq4,鞲u &Ást"7+NwzyHhFc++bYUY Ӣe '2!Rq/ט_[nII mQ22^A lNMR][95Q\8F}e4HiiejJcM[<l$~_±kiy]kZCP`&ن)jY` UL`ܚ`<̫J dۖYDcY|V&ڴ̓{=L539Ved2Jŝ;+ƵvM*ŰdrX+Y`܁rƒ N5e"-'pUo6Ų(zHŚ{Ͼ/o8G/`n0?Jđ){_?uG? "Q 1gT.⧏-?8 *eVi]MlCTLu7d.CEZڵh0h,MSlZMbaԛ*A 3eXhu S֐#_W@@vS+ F z8,)Qlذ1I?t0B2۷22L9 sf6A?@?yUS'rȵ\ٴ.}o,,  `Xj[Z3rOD)ؒlȄ[:JI Ud͜9ɄAypZeIP@:OW>E^غ{9ۡIT 6\nܽ#$ !dǽ;mnן_mgdo?/o BTd2>mŵ嵉?" Vg4ˊ0)q՛_qO߲ᄐnn?kYI/۾sKa-=Հeb@e]( (qٚGcɊi)1%b*mOm߸p"ȓ KoolM "ٴFA@^V-gCZpD*xFwy?y#Ma]ɏh29ߙsMq~BӬ FM]mpMW4,X>t`\wQ۱c򱣹 befCXEDNuWf#Ih!c\eXP0  }J٭՛9e][꫗)ӊG }h P0M5T!q|RbSaw8xi:ͳq?0)μ]øGy:ŦHGc FIt6y~O\%Q {<[7 Ց akͦ糵zhJUNJ0!dZbB AY#^fS7U+!ɫ*<]D~Dd8/,8+w/yO&$ J0E'МrE(Ḥ5s Ŗ"hq %œ0 T`0V+N9, \]*8RVǖB0Q^$p]Vgo}J -KL7m8d4ʢBTE +&*+N0/bOt=2i8xKR@e`u*# bVsۗw]*̪D]r7Apr<ϝtx7==ej|3MseeqEQ7yy{~FSH/|%g_h='a9y󹞟*pnw'<˼ŧ7xw}mc Ktܓ1/ v%vڵA)D$WݭΣOZ>sݧf7\VTEE̊+PȓTkJAZ䠊HIvN?>ZA de Y:q=`rݽ埚2BBR7?p`Oby 1cV*Te+;v>*;FtP*hmkr9Ys\2FgɣKDRLZdv eţ1:BiV%#U*E1:g%<{Tf3Y^`Jqݐ I"fee83\XLPlLaXIF&`qX1YJe Q(+ݪu;|F#G;FrɐEQݝ; HHie.شՑ@4N'$+Z[8cAz~bhR?u,p5T|J fvf}A Qrj/N6tGs+Wμ4EĕU"(Oݳ8ߐ7ّP?/.-c 4EX?wη?lЩQ(U+/,f#Kc-ۿ/B=xc=|ϟGvZa YM"km~5}lQ (# &\=*駵v1gJZpDs/JEU7k93Ju ^[Me`ʹed;^+tHiq9ݶrTWб$צQ̧ێO],VvK )#v{E95D$;B=x;pf4@l׳"E1Y Ԛ,KbwlJ鸮+%# 3CD{'?y饗>K?O?뭗tzůO홿pqM J )-9_Z[K;sF +xe(hv[\q V+sUuPई"r x}@C?H5CM!zqK_tٯ_$qʔd2o~RSS%tT1Od(P"Z8B&F' &RԢʂ2ȥrvKw޳Z nJ&M!̺T[aqX5#*lnޚOgr>^AJZaV'Ulh۱q =  utM2c:>>vz ISUwjՌ%CuF[lm  ^3F%KzQ"q lؖtQB*,k`GMybK9Tj +Ĺ)wЉPpfj; dD XSӊ[7f祗’Nef~Q$5?/r. \e0,WQj D7;w`"8% |8jSO=/J@%Iڲe=Bew>>۷onnN幹}_`4=$=a6 fe>o??ԧ>,|?~7o>ٔ?Ͻh4'O~9|~ۧUɷn2UE36(F1## жe^ KY 0\CY0)KcNju+, M!pE¬*CY)lڶAYF񀠈xKS6`XxDbPMG+j_}5٭񳖷Q3Pͩ;2^0J 頺Ԕ麬Qrt-Eclyb_,Ud9d KdM41EjF~b7AfwV1q6Z0b*aR9Dd)aZf^X* Ī )~Xo2v~~۞nʴQwL*MDI0|ԭvD pXUȏX>/?[p(akr~N:x(?_z4MQ&ysVs!އ J00,ktZʧge\\b^ Q̬,ʂ!4$n)0hp4)$ *zfiG204yh)pjKv?i~eojb.YV] eDYHaU6l miJ%ʠ۝, OM,YTPER]4l}RZPOߵc7}l8=uǿMX5@hN_n+ xt-wrKdyŇ>1 N2v}Ï" уk2RPSs2)/$H.1a*yi6dJ~U6du\?Ӄ#;{ՉS˒lʸK`4 A%@&IYq#ɨ϶S69jի~ CޓJ1νȚS+)0heɒӨ5tê*RQ4C0ݻ78*$ P5YQVx?ĎJ3dkvͪy^#YxY aS5bu:&*X\lUM2kZW'n6a2JkfZ>F} /eO":J{7ؒm)RrVrxwyRp8&ci/}{Xtw2y(4[߰c I$: t8ɑHd`TAix $y/j6P uh+ ,M:5dYTu)c+ĖWNAMHV$n~ Y6jgzzE#M%=zM!TXƹ6ص !UdH9*QM;8I HbEEYB' Phn~,ٴg<uT qc=dX`[WYVyRa1k )&+1]gشFرq䙹),hEkj^Mض}5sN R/o}['W\q9sĉ(N8qgo4͵g~ܶdg>FOWYOJ??[m,|ʟd2?|OtsC|~ۧ5 ͬRF ƹ/Pf$P0CYB HuWnEwfjJ!aRȆW ~B,n Frv:k)S&#DQ6fjVVPp EW8PzsKm6;sr岎  8)d!R EK9X_`xig\ I0BAV)U (6lܢ4QLEJ4Z5eP%Jj2 4]9HTLQ&L$ZkMh7s!%@@:cQF`A,I\ $*M*fYAI7]>`I@ E7xubOmB'FBV!E!+PAM\UD(sPeIu]L|JSZIBG:mV_o؍p7DN^EDQȠoO)n168,J u*d0IG"&zFM6sv#*4XE}o4b9hv+Y"3\Oꫯ~ް}u^r\f>juerŀۍVQ jiT*҉L¬EY,[9<1$Uo"JI& JI"+r91qז{,M%Q(U@p2*%\1T.)g=L? &ˤTQo2a4iAұ.Kh];MJD$(PݟP3,d^:撜 5,U ,U ܱK"NIN ]C N$J!E^3ȫ T4-z ^t#=?Pmn~GUepmSRwu*Ѷk!$VIs5lO$U` ˪LJ#Dq% $$\WGIi<]lve̶lXmmN&iŠyIɢ^-;z)r òŖ]TB dwv'-LQ gn$`C`\q`:EsY(*˒(3XM#ɫ;'"jIx~3L$IZ޶ MI҉&̱)5,sч{ʢO5g[\GRH2U9/CII=~/h/-.dI5-iX"I)(8/HƲef0%)GT,~wΎމQ4 rֆ*BoRG!#U"T8.7ϵ(P*;µ~G%Q$@0x@9J \&efPIF#"[I\jTsYRyI,FZLNo|Wq۶C0"iK0!  D' + IDAT./$X A읲q{>p .~igz, JBbn`]ʤۚ~@K91Ų^)9qݵPyhki>pO/| fs-Y\OuPkP_|a$0tLH;~V:..9 s@ng.2I!eB\M3͋g(Ǽí~f:{,T= xf^b%bYVڇ\ԙK15(HeYH&RJպW8M%;wYׇ<}x!'sB$!`" ڪ[[[m-WV-Ze*X BB|rN3wy?uǽյjkg?kpjO};cgRjQw;|*…1ÊmI5,ip⍌J zL̇; ?Է 9Ҫ$o|Zq,Jwjb#w6pp4Ti;gFq1$W:?.wAH7؏]8{р94,W؅ǜ%Mw+ZTKӭ.ED?],UUoxĆSiִ@1qPS?$K|8ܣmοo]wuә#eNgsBmwunK U*H2w Qgv ܵ3Y&xm+x=$VNV&'EXoA ArkzWַ>mn,6F&e&d`OWcQkPG O UQipU䧿y'dˬ:rkFxw:gIh]/{ @J\^闧?>O;xz8ܠoMNA| ]:!l]u Y-m%cH('vOwN],g% iZӭq=X`Y&ǔ-*ʼ综.23-WfG<Nh'ԆPJ̷E0'THZ޸;jO܃.~DG.lhpU?)g;6W@ס#Z8#6_rw{;C>𥯸 [_꾜׉ѤМHǍCg1`a@)}dwQk/ol^;mXҶ\zU^ZZ/TXlZO(J>#;=^5 [mъ4bsoͰ̳z;K7z?O."tM3s`wZ!`$iäBNFЅQɛdTTKvYtLt&S ;o|7ڼ y!h[]+IK; XH;d)* t+ "FEdyZ7. !LAb\% ,3N%l`,,&u:с%AJ o<~62򬣫\ZL(&|[ r={7 jtv }|v*HL F2pb%]W\\5)fzD3!W,qKO+PMvfoMPBgfK-':'s~wO~|~ws2}}'-:v{|~nx^~ӟ9rG>__NǏЇ>x[:Lnnn8pwxT|ƣ|7_u|p$p=K!m{}}n:?:ӿo}km%"pjs@L:m"k:q8(?ē~ ~CO;-w8ЃbŌR$tZKb V-vN[zጃih'Y r)=DE!* s;`p/}+[TGNpaGNp;gYgtMpG:ͨS%tJ6Q Gg\c^=oni9:}a\A1s혆K4ﶝ%r>icכ$W^_V5S +x1)VZtNV<:{3㝭 M=ޝӅ{{Bnk1][?bT9"HT!Im ZJ,qn-3lGbe|Oy|_J*9M,@Sݽ1+O94ZӲ COgrpbi@Ȏ(#ƖS45W`Ba7 !A+Gl^pn^r0mwr pJǠ/}?_>9_W_(ʅ4\6^~3.FcSŹP%D:٣v+pP Yi 0M{5ef,#q9۲,1I;=_ږc[y" t p-Fqq0РZzc/Fc;w {L\l]؞tux,VT|5п{oRllCpv|Ky~^QKr1&y}GVX ,HYFEw"o+g#բO{˺F:͉g (V$mIaƅEw`@7ٙԶ:@?cܧg0Ȳg Stּ0@&.Rlua {Y: XƆ XJ\ЁND-ĹF!v\4DA͠8++S0[anRw晳tZR`#ɸMUY>{8IO𴚟4vƨ(sXfڄ0:ӏn_+N]9i&pۗ*f#=zV8T^Oᡵq߶ƮE^%>ysPP\* a=uoҒ@B\68 B캺Āuo_:6Jq]d.iukvN?d:u\;0{:?7 2c ǫٜ|? he5 F-i-blT+56("If<_ nxUM]~^yi Oݎz =[JeU֠zg]X|;M~n}sO?=.Cd1Yx^ mA5IKI%u-QlWc;r"Bv[@Pu{ F j!JLr%)s9-tA Bթ??u c;jE/z؍;A8%h^ƫK\yE^^͛Lh/,`Fa_58HS MCT:K`$@;5Vt$ͥPC1܁FDv 4 d:|{yTl/+a:=x؉{c|[`c2\mt m HSԐZ ˽rIk$rK4$R'{tK",ƻ AB $f"EŒ׊AoyggArvQdMLA@<ËY -d~d &+.u˼K٨I^v=B(+U9&,0^2]ڔ)ִN Ki8^]*e8q4`EA[=&SF3VW֚F32lQhIypo2Ni `V3- uEU@n=9_,b`Qݝ(!V[6Qk$ݯ-B LwyhXE2upt$ڃ׽3[=z5cYLZWŠ' ظC k˚im mUc7-5(IeE(IvtaZrќ;6V7.z4C,l3$[Fg=A$G/r41UTw7;% Mj?P3Qb{~t9ٟ}~{uP cAxe??oS2:Lľbm|a.~{L\#=o 6B#X` \-no>5ѣ|I-+l]n1 vn7T3JtjQ QX#Djq#EH+ jvv^׼]?7FYVseZjFu뗝FZBF nE$+"l;U}dy޲?;Pнa([y6F6{_5`VKMNLkZ9`;sO\u?ef9piIumrT| RB6R;eCD0 ՜B[I_Ίى#}gđEE&Y$, ~}j}_yғO=țt6א۶ xy-RIJ.ί\o?vѾ/~>|'Km˘j&yMZ9E*@tªU|?ˏyc?hz˛o}Ku*gۼ E0[5+}Í7^u bǟva{%Һm$<~۞ˋ^;pS7EGFwl䐕Ɗ! V]KI ZqZTIL{,m7)ՏSzjNyOwo[׵,hwWFZEY:^;8-{Rh`QָaXDD^ZZu"VP E7(nlcbu/1l;a5*c?ӷݽiG!lҢ4gi &@$kת|pOh8@\UA}\jgg~υ6HX i*%5~bibYZn)%BϏz8 h4MU ^tk7vآʨe0Vcç>c6e4+ki:T spQ M#[EK"k*V1ܫ*fayU٥ѳ6fPN\Y  _w6/Pיx~gM:[_iUPV*:"O02؅ڀf:,AhY0tќMyD jymLN&Y &g^nDKl$3[4kbQ ܠeP9M]?d!2RgG{>ge3;MRJkv'D=&Ջ;x C]Ip7yK8׼W?/: T  zh%M@ɏm|m7^䷿5ٮXO飯C(B\B(T2J9T1ؓ;}EfPV0DJY#ʩMM1 -9f2o*@x@t8;>Q ; F_v'ٞ<@C7xE, v%9D @bl~#GOɢ0WcY!e̵G7MZTA;lE~)|@țÇy~ֽV_~;LI/¦bʙb̋{wꕖBqs2%KK Oeyۛ2"tcZv EPHefQ9v uE'= KUC#lٔ{ݿڗ`Yt f)d[_k6|ق%lmQ$F vW]~Ǜn1^YOfH VF)HLuToKˊsV 7k7gyf;~SV7Ew;Eh$(v':rͿU&@ ,AB* pUq 0qX&VhӞ{,o nl 4"-)BqPI(dAƪh0XH+k%Ě72&V8,ށh$374 B 9/EڱmK oOxVv׽ @K- #1Wj'{p |<= IDAT4+|W^C;O_9y(? YA#~OH-kF>ǾG_ܷE/[_{+gUjUaPE3ae !AmAF1S3nu?1/=LoS2e "z-9q-+c?qdv u("+,!5Y~itS5']ƢQȺhvzhO3Vi g [n=Nn,񇟦v1 )'~-!}Z#îQ'1~Mjt8 mg]!D \?lׇd)c[iV&Y8o:n( JlN(/eC0A.?xhsscWRZR 7 tZY.#ymEHAӈ1؟Za?ηxR=٢kpc8C;ѬP<MA[*kV`RXlwϳmbyVk <Ö1kfF)>~<*J)2ph8l&B=ٻyq:(KQҋ*-fYM*gC a \U-O9?z2OAO3PQ 8Ki3U68*j0l"?J c׭ԉ+D\?Cٕ#׭ NJ]JtZk%K;٧,}bSYzkg.VGO?n)IV%O@xyJH($ƮÌl"=??~n>ӦMQ.V`m?ĵKw\T]SQ{Vg?dX+Vhy膗\ +.4Kssا_~sO}?ǚTA;$>J , FPjx˓ko~_#JMӉ|뫧Gq5$yڰk_q[ RZsHQ-j۳ % jkFudy1ŐtaW|+9m F( *j&=%u;q*@  ϑeYx|26*:8qseby-m'˲ vj",㨓ڮ%, \ Z^ZڙZn%q C0iI^\ /FEViaYȧmx1ZJGaoVM|7nG= `)Y#^'-Dcmq:y=YTa@E k%q5gC-=?3U>ZĞ/|:Ҽ`qZ4 rq81 \H]|7zA@ Gc8+K"RoǾj iFei#TW 7:+/*7X.) ̶eWۭv`a^uZt>i;r?[pD Ead\}ͷpްܡęr^e%7j#kliqB4p)=th5Ykq5GG7{ jKʛ/5Y:NJpmBlQQQ `%% "`߻5>s "/2!t4O+l!66q*hw[{;pQ {nW_~Uᶅ5iC;VzPc x< byH2Hyc]qchgll:DH+ތh8X`M)US(nH bpw3?2hk#UQFG/l(E_y;I\Օ|^dVw5?{34/L6yۛvyJ䇗^8fUaE~^q<ݼ,I73ի^vuW_EE$ny̨З~="GzQ7Fե[z =s׿.LeJ2\Iێ':s1 oEH_淞k ]|^q|K-3bVi9jwk??3?;nW*d~ihTf1K Ms$Whyue+Jƻwoc4@ۑ!  Au[.!%ZKI@ PiY"њ׶kE!5DJP6@??~6QaT)BRCV'&N;iJ:y `eݟ a(F -ejZXlj<vbyы^;/L&i3=Wvg5+Ck[T[h߷ !@S".8*]糽gSaMʲuvLn&M 2{.lmxJ!I 0̶-` 1ϳK=^4؁JILVuj[;10ZMƳxj:87ʘK}YL;׮}> NpOyЉuv=KqtF <+{ *J"XZ~+i9{1n 1:0R:P7@^TLh Bi-Դ,bs;֯UR.@jTTcSN-סpv+eY> 0(xK=ZM6İZ.f$|rhˋʽYL]/ 8*m8+j^bwqBLFHPPT_Ȃ7EviU!&Jwh^ԣB7M]7X` ͡L퐹q+nݽ#g&B$B]yn>ݫŰ)#_>{iU|ݛjo{Z Yo Oj6*+rf,d42߹W>yf 05)`E;vY~o-])1Ry:~g2ѕP{ԋbWr>q&괩3&]WxuR1yQ1T+,ˡ nyvxе7W7+ =rzrc4ohIKf"ܳ\Ax#a2M^f$| zsϓ`+ͯyU.g\04T20׶,۲Ot# Mĭ/P Q  =lڤ@jXN\K~c,] L+AQ1K}NRc+F?/F]K`<+]7Hxa+By5 "jTM=Ku´N\~|qV(NZcyߗaX8P\'7+ȧ>o8q{eprstq1(Mt=`7޵>#V/\1E~=3^okAhM[dc]\j"iL 6;HڱZNAx~k_KMU;kyws!?f`5n4ab5QrzNتDӏ/KMSI#^=1,\JVʁk3;{Yږ3t0TI?\4ҵP  B9}qK98\UT@A+cp]. !Ѽm(j׈YMgUJ#x2[eZAY>p0ݽpFjbU%]ۧ@VO>{ &GN<<HͭSGh! n Ro|_E/z׼?֯~7 @` 3 #>bTJ zd( D7uMXFjZ DPu]ZˀPlqjbVbL~b\{*t msdQLr0ٜ̦1cGܦ U;n|=%Cy/Ojv^KIE;ʷ-/z/i1cb^v+EjIxp{crF9d?ʿo:qI^eGVVgJ&yECy#GOY^[ӆ慲=wn74)nLeWƢ}K<jsvlfAD0$N%~ 4^ =,k `3mEM!QIJaȥUeoy,L ^؞KBy~w/j08D!rE`a(p:=9)vwdܹ\ts KJm-< IOT[NmIa/lOmb;DX,r[vo}ǛĄPWCtpdZU^ԍH1GuWuz~6U%ڭ e۟bوlFU;ϕ}/ !nGslm@F"ýg7 kidõb(3MO_anVg46>s/|4xnjA1 ^#۞o5Mc`Z9v8 X6'>KnHШfۃ%%Ұ*}{x)H3R{m~|g̏J88؁Wi9 3W !zGn6ژ'KI`6hLV~4uUUYqE]'E:0wF:@lx3y/.=?JYv=n[I9fJܭ0jqҚf* ē d3{"|j!moQda/6N* 6c2ζZkm:Ɛrj/)kM: PR 6,1gHYitCߞ W}ǵoz9xټ+g>>;/}ƫ'ny e3n}eo~!MA1sU9PJxY9탗46o 0j.p6(>=E8l,`S\vlߍ "gɣ-Lrxi1Nuvݤ? XSU]t)`$`(r@U Zf9@KlCZ+k'ЃEeSD̪y:.dzগ߾vZ rh{7wo-IQn Gdד;z2 RI8:՚ȕ՛ 7*";ZEi$$q)i:9Z!šcaE+O?(n+Vhfg3Ϝ{bQU˗_wul2?<_ j.⡡!Q.Vu𫱱 /Z<衇}oycgqeYz]w]zx\[tΥ y_|>O_\~+\oW_@;#K7gӟjeEW voH%Yq>i22cXdUd3'6\#1:Yv4<2O>a񼷌 -Շ/YW-/Ŕ#qYHjST@N:v7S'>?ĭ?S{~/_۾63ja Lc!ɮc,T44 IKq˒_'ڱcUZFr5}:{#Ng#VL+TQNf%E[F9 Iel,#oGvaI*~vox޳rO AhPg(@o}󺓎>Y'q @cN"Ha^WtM9ZR@A$Dp |&ʀKc6:ﳗKq׷$`8T8td>RqVy3w3geQ !oyP:hevyILe!CS 妓OK#~ʬR+;IFāgOeFjF {79d 7= A@ ͦNO=q߽Rb'~‹OmTY8sVG?ugK;cDg5I#eA*)B V:\ۍ), h#~fC=E /ӈ"$d[@NdLJ:fwffzeN` | ,2(qU01:[6<ϳĆ'a./*C )1VN*U .~orDNظ`U5OC ?u/JQcErA=Y@irƿx IDAT;د'Muvflt&;[|-}^dyNRu8,,/I@ itٰ$KӂÀH?bxyekcvfbIy._6)IvlxG CJ89DW3MHo4drⲷg.nkw1[ٹĻ6391 T5&%UVxjc]—gBaFn8}^mgK_{y&($F)0RCNfB`KH+%U\9/t3S;ꣀwiAhJͫ d$Y83ٙ~ؓ,":L{6 fL?v9~?BVk"'I2e#A @L z{ ²Id> n~e^[TdM8v&#{+&•˨8y;_zדp@Sf>ǽƺc~W.:TT-ϲzVRWvl ,2/p9 `l=mnUL8BA(XGQK`yd~Gq,Rx}'ZItUЀxqnO.i(9Tr݋I³1ST 4 W6?4 4nX\0rR9>Dl昄IHK$e)фc4˼^e$>Jw@* OXE"G I+ y błY.?+>/~QF";qlVddvdxXJR4aoz[I?%Z[HLԌ#C!|o[ "pڵkƍNgtt 7xi꫽^n46l8dPJ@;s=8=s`ll[j /8-rw~]zkӹ[ڟe޹t^}ׯ?<>>~@e6l:3ι;c-[O{=vmSN9̹6W7ZϹߨ,5x߿mxaw27 锓4(TEG{ 6z߆N(o\L ;o@3=Q7˲GTPJ]+LiL"bO!tQBa~d!8XQ(壙|Kswp5^ы,dISD:~!$74Y)a,mY$s Y^m;O㖱& {С/Hhw%B^iPT^N>Zġ c@B]3y_/حqT+ġwO ujz+964).XRLj5Ig)(єUP[uSf.(RdԻ]Sg>}+1~o<ۅ93*)~x[)صAخi7s0'kR5oX=e8v CR/WK%FuĴSotc8 I,Iʰd4i>6:g{F- m%2EQqH?6yLX@o RLj*a8gZi*r)o,VE1R1zAUC/ڎTqCm,,MB╟0%ڱbvU(gʵ-Sm' ёJe{OegzDzصjjlִmO0  3D`=v(;:8O%ԻOx ~/?5({/-ΫOי */D!+ Gʲ1ňdNI aʦ׶HȩTw*ϙU8j$%W48NOMk)0!3S!gN'-z8aVͱKGg}P N' y"40IĜe @%7u](Ҟ A֊[t[Q B75Q0bnʂy}Q>8E9QvfldX K&{vl¢Btg^ 7}+3!,(MROAb,mjzaP+V3e vG NfTA,[qX?2Xit2vzsjP0g>]p!`WxW]Fe^K qJ Q]`ȹ;m[? .S5E1E! $, @Mp`3h]a~*J\ƳI1l߆ l9{Qf>P\sg>?'rxaGB ~h9gY蓼"$ M8دTn(PI @(2R~pś?֗{]{^gw(Kӊg0J8e1KE@xF"YW2.2r n>1v s9u'Pa8ݏK 0_RÁ(B' .?;" W,_w<cvg>dSN_N>d[J/?ű}:9.N4%lTzӁ%3 \0CE+=H6#j((b9)tc2MS1d)f1:+ڍ.^0)#?CeDIFu2<3599 e8!MTLFoB;9u|'O[iED$*[*b'J{ ,CM!d'8L*n'JB$ | $ʰ縒ȧu;ݾDt1E)eD1LvOftiIY;Nׯ*~'wmDcjxuo:3ꍅ\'R/YgDCN=nu+g[0ԁțWsJ 9O4.9uO_{uljw?RN2P&!>l"Sο}S\BQ-?;0}63O\pD={/#^Q6TKT8坧uQwyW77)Y'@J\~jk,͙k1! k5)y׎gxD FN6.x?vwyΏÔH"8ov 2^0 'e!U!.k,q!&Ѐ( Ceł8b<ijO|7uDMA@qUJ\bz6()ʓ$s(a |N,["(Xױ^9 %=\:W*k{޾} /KVXq7z6W7ZϹߨ[\޲eK\>8^|yȿ Я~??yhx tRT:jJFn34#MRiPd8|ZCZqUS?fzb^wjoE^ m[;v‘ߛM( B~NNxjXPǟ{肏u}IpCkoLS?s!(rfvY^UY}O{?OolzNu\lYвeOQ!M 0pb 9K6^g=J4I@^J&e1MREѳ Z;DMP^<4]t{Hxw|RH"ea&0$p:ӻ6=N#V.q,* 8!$Tn塁2>Ʊ Œu~Km`>/+.V y݋c)ڋ[R^rf87ʹJZɛwR'a;qB_* @@$ 0&p"pc f޲m҅ɹ2'&Vq42T֙g`ұ $* (31‹K3K~IvA3UiŘX bhj&no]"Tsc OJBbIr!V4j8V9vӡ60<߻[lplmznFHxvc;&1cB 0;?G)GV/}{{8JW`"]Yјiϯ.0=9YXSQ^S:k=4 K?qg/N_wK~1qتW-?vsǟ|$ BBB X~_mOQ'd16TTפ~$+,X1ųFKyL&6[J!aP^0hTqrxיuњ}MF$LKh&1@9E4 `(Q*)/R3)MsȒ؉N{hXBK ~cvc8qB 6q q[~3ʥ2Y2&$3͜EC&0y+gˍ0;ݻx7_ܽ*&N1 P%i`םnE9ɢPt+7\5J9]Vf{ru7DB/hHPbBn0au$XbLL(LW8PXlܳ-$ށ8Q(3:߻$Ў2?Y-d(m!k@uR(S#$X/]/>aff20lhKR}ݷrK/Բ˗_@ -\駟>x\$Ie˖._׾5{nhh{.n$)O}SB`u7n˿offf>u]gysK? n_{~wΝ;butM ,8i+~+_C>{uY'GGG8޾}E]oז]pUۦ&z~5 v1_PNX^`౜l@'n0U*0eLw( 8߻gx@TaQ7)\O"MRiH()Y۞d"%f^V`mM/f ܡǽ5ΝDJV٘*(={w2(;~];(dSb'bKTݐ>1a`I KfOC;XtӃ8qD{mA <@-RbGZQӐ΁K#0,&-z'b$bJ1V-[MʰEefSUZs?e͕Vmam؎gBMۧv'E[LxV6~F7=~s/t܎DЎS4N2 4x}gƶTXnd"FT@wS̓~$2^7[2+0iKJ+}G7v%!&i_*%}.\u{]woϖ,cO_j)';$G]H |7 "4 DI LQ< q|E* bFEms}& 1ĆY֙Z1[A![既‰@1IyJ{|(؋CU6yqGa3cUS9)ˋCViT9ۯzkoQd+?pm_~^Q$Ij^߯U+ڙQ9-^zy\`K a#Ciz2@ 3ɯ~3=H'/g70/ ) K*= odHT)W݇X ˹`ulv40|!];Ge P]]s↵O!VLZ00;e$8bkW?IL1( Ex IDAT" \N$IɈK\>S?wux AqLc<ܖW\{tu Mc(14vmN$U. 3RjUˈď(K\@BI =W1pygj*B X(J &iY^%. Y2_ddbo*4%TTwwO%M}YggJzȇe@ O:z=/-8$Nlf׋p2²e~o|bLS&F-?i۞ *'w&$Y1H+OPS"U/cTU9%R,ۃyێy>Wvq|GSFޏ$4E6-nwJV6,qg#Q"aɒð`DU yH583W̢Hd mNH3R8 }^QbS-p''F4sNڙ5*Pp!zFZq a㛖=e;(L0Na9UqZЗx3b\0kY;>sd[m?uxu>Mӱ}kk[n++J^׿>==ߡw'4M/w}<5k|ϲͥs.=(i۷ojzjժzvC9䩧ZtAf.͕s77~^qƙE]r%]w`4[|G?0#[iHg^eP"K d1 =sa嫪\@`&}n;6VE|NOYadYBMω0ϫ X$I$QHo ?]' CȊJS#c۷z9$SEH\v1+$Dˤ,"Sj꧳YN]AALz=L7nN0˘:~v[G.yI_@myK>{pM^*x^ں,@ O[ӏdMb*H* MsCWU>d|`%AVѬȳ; V=i-an"p:DbaX\-(Ty^gNgeb,F3)C7E&f(|X1q rRDb_ًO%%%+Tk8ҵ:7O]^iB2&%:{{{٥#X{Q*/lټw֗_R@LTdVmG>K>A]ԙ0Ovy: M*29tX]5 y5G>#rm᷽%1aKO:|">o=8Eg. 7׷nԹiE]]ϼEU7 8`ŶB1BQR^ HY $(\lyV_1Ϫ|±cv瀤۶l{V4l -4 qʋdI0ob-*|kI .`J.ͼV( XDSg A@ʘ/=t^P(ir)p"@!.唐jB,#F^$ih(4zIBb$D)l)X o;qae8fe!$5ngS-EnԆ}ys֟5RV.p{^+ɱJ-ͨs`>o#9q?TT]aD.2 kC<;8FQ0qppxkqF^Gg;kG~9Peh[i<!(xֽ~ gɋ^+%Pj<0Y@Ĭ u޻R)0UV,al~"EׅWVB/-#yr4N$aИ !"WYqQڪ7b Tzs8Aklvz?P$˜~5r"Ny*ơ{ cKbv`NeI̲y2u:Ͽu@\c=|'VZ7g:GGG:;vlڴ`«O9>9ι+VBlCY=7-`n͕s77~.Ȳ}Qm۶O(KH~-G,aO1\99y"&( KJ1@H3c*BF6^QX?(Oz[MU2:ګ;ueU2 x竬D+Q34TN=yTG'vԁN|_I˗]r/Zyы~%$pvhrW>{K,!ȃ4Kxv]ﴚ~sHaɇ)3#ǔDA8Vdz#&!n \@?63M8D C$PL5eϖ^KEu39q1Fu!NYݵPbA+U>nSXR?JX zk2Ab\mʅFўXd~qv"&YQ/uNZf|v҇dtZN X`2`8e/B3@3V;|>xH/K0%C2%~F@4,TMeB.J,"w:?FmKpɦ勘@8EUlcfcd&P^Me q|* UEԽ4Ie8()!T0 MɢyYِ1rLش氥Y>cQ*ؐ$BF5`ci۞k:&A G  HdAf BP7a? $Wf*vZͮ i`[zvs Y+0)) l1PϏUk`Ūu};6ٽ,8I. $v79e=xl!)! ,1 ͗ QeQב8!_q# յ+_WUUeY'&&Z]?tIae5\#I҅^zqx;Q,Kx_|gy'?[n]b?A VZO|aZ&M>wy^uUW/%\rWr!s;λk\p7߬(w\{ιtΥG]wuW6 cllK/]v駟v~ƍ(~\yh=>{lׯX0w?o3nM@lu(=BHv.I"'6Zkiz}DdMGs5Wgi[q7Q/ #>ӓ͓g4J(@ $$!cpqs,Y %FhFÛOpUޭZ~s]]g<1 |5띘4X  #>˫ 4Zϵk=ͫ+w<`ձaUs1TnyIrBrwuXW3Ŵ:xyZTHKao< 5 nu֨I57mpps uIF,Tɠ'ԡmI &7y?WaW,4+.+V-ɽP;;#Q#(K5w֎?Sn\Ҹ^eEQ)Ӆv$1㬉Ga{YIݞ(fBİGI;1jmy:D,  N|W a$0Д.@VxD2LMSPr0L()K~q /@8fm0OB2Tu! mUulb+aJXriD4pHEXho,1TyE.Tҍ jD^Kwq:<_vmp.?cO`fꪇ# M*ڹe%=+i6MAa eY'IR4 p i5sqNE6 Kw즚na~IrZ{kL*] TMC\b=m4ׂ+C>p{?|2f覣 퉆%B *֍əډ"Fy_GL/~7]{WWjҨVk?g>SYF\{\r۬ȅ9uNҹ%m/_<-,AkNGbV{џ՗z$nS`9ڭ䨧MNksof'K^P*o~J lu2'>:+s 1'ݮkhUQp&)\GO6RsŰO Mk[gw7~{- i1ۉF\ZZN-ȓpL>51u{~u7ΏÒzu/ֆU[پGX|3qeCqX%TsY!/Kb&"r:W'.Z`E3+ kRQV@ p * ,ϫCX M:cX;PdjǦ։4Vg$#z4'&֏ldYќܷ*qHsT^7~/69>{ћ_{ÓOO=m߾{^}c^zioZ~֭[y䑻;7< w///򓟼O|o{G8ire}~R; 7ܰ499y73qя~Az?mwRʷm7tɓ''&&^W>c۶mά+mz2i1Ez @!CSb08a$v̆ZokяWN[>H=߸?~؞UÒfi\}ݽ?@uT9oFS)UN!RL&!oںl#yϭ>?o?Vԉ^Y62;PJ2E0Iӳ^O| |O)Ace@mG Ip`l bM!xTft{m͸UvYډ<)+u8f:Qm˖W*$oDq<dIR |85);.t%[վwL4;k| IDAT.z3-u6J\̤I C6ŕpjQ݋_r҉1˺%)9@X80;q?|w:[+nyFZ_oѵއZA{gJBt,~JQ̲dz C!*͹궜z3-'W_{OBz[ߴ `{s7>ZQN˱ըNBiVSy7G~ߑ[uGɕԘKT2HqJM[*6LJMD;%DkhmݲyɟWrxaw6HmS@҂wlpF3;כJґ]뽥͛I^m3sYn0iwPVC~U>) a^*N5gn"RA4=/L7}iz8eZ5@Bo%Qcq,kA"+&LH4*F3o^U|x q*I87' &ؗ/zы^q‰Om;[!떆Nu"ݑ 8O'ũ#x'j>Nœ@'ˡ!NZ8nZn'?ɡ`v֖^~ف2ud$]@@V ^˹{+Oa\p\@I\i0}HQAbp].*Wajw&m"=/qlTsFsdg«7l`Օ,EHU;f óHIi}) aM _+*?g{ɥ}ԜՌ3?E4/QXo%tO-₋yS+kKpfc GY26|TȚKrHe})}:ȫl@\Vcc'OJ`ȊMDt)b}͹]K*[00P+:iSsVkv(/Usq` Uci'z3^c[dWc(JxUE3;rJ_.:+s{WE/V%db΍KyfSC'VpNtزA0]pkEVeT2CxMpT1l7--@Ao֛ߌIr`HbG5 Js[>g $$ 8hdTb#nغ,;gaR2rl1EU"~#1-is]( KrjcS{BLafވǟ| a?bکco[? -6tCeo,\Y7L|~θ,=qhƉ?s2vUS42-+( ,$ub&;lr2| ”oWu|i@hY?|㓭ڨHQEBUP,VAWm9kǮs.pyG*j_YȾ'] $+I Ik˽?[dҰ,a,iCCXHU 2*M1}SSXw߿_a<sYkFյ1\De6 GR£ UR".UTcPU %@VqN;'.Dc dEIzE[;$q )Fݟ{I)r a4Y[Q(O̬{^|s Sڧo[8RAQVw4"dS^ *9bhDsWt~ Tu6dDK. #f+PR-l# )b Kiu\ZiK@HrPUaУ4mN_'FixĴ" ù oVU)JWgE^"U4u-EY5"B>V,UW-] $4U@E/+`W/olQwוo??[^StP,iǿ]|KD`x(5_@%+hRZr"Q|]vť8މ(3!ah0]vͭ׿=d%/,tlƒ4Rz}q5W-Ir5>(M"HDIhXAXjQQ9l9"eJYQ*C% v& E\{>J>NlkP֖rF2B :sΨ*j%QjZeY%r~wُݿ۳9ZLRчٳE:g$  I g-RJ))(ZmByi# 0K?^g, ZPk5nH@֡j% 4,܂qV垔vqT{bgXFQ;pO>xjd'Ʃ8yE\$<{h8ڤx0q} Ag*SO?;_@ fEߍ^:Th<~Eu woݺm4:\}q滣\= Ԣ(4qn\W=)L]FѠD5 ʪ1kB"&IGZmQ7,ѐi8rZFPhۦq3Ssqe^G׿==,}V[W\vδk#"W֎ 5J$ͳEi*N1* ];wnl ЫBE*ǟFQ{52 -۲=۰<,ݧ́JZek0E7m[tJY+$W1ܲ{{A]e ,%oOYAD om+=(}?pG2ŐZBA:`A@fe_׽i9ԋͪI %)'#8.Zͻ]u}zf0ʈ}Í\jQ껵QX)!b3?׿.*rZfSc#\wUEnhD6TqY/y:}T}~jL$̢(Mx4d0AU m L*O׾B(+$)3oL4h+1H"˱L7ji0E>VT#@ +(esVFiCl{j9.41,gۚi[@6|j"HRdUX->'41W\tp虮AH")ӸfBl4t@AȔC hKB]+tKhvQ𙃧>?>w g,vqWUDTP*+VꞭ"~oɉ玜PzW $IUJ}3YZ>e~g pm _{^kwY5 !  H P`)kLJVòo4#e'Yɪ(Cb"N Y%H&&{7 (?̾^g#FT$ 9Lۻv6&*spѧy}UQa\>< 5Ϣjڮ="H԰RK"/S{Z~}j3+qrl PTt]Cab*HJ%aTW Y24/yUp iw4G g_ruF$g=LHuAueh-dZD% Ӷo;F:IztQ)@`Sc.ZQR$Udj@cyfj/ % e0 +a4"RL@\yyYA^Uǭ͵wm[/<階~ʪٍTBAfL4Ϣ,%F:$Fi(pU 4I a!TY@IkxبqVFI+WaǝtO_]Y дBChu*, n/-F6օfWH( UlMմ 譶Ѳ+IFQD׹Ǝ 40믹ꑧ~iITTҤfa$0fl6JATUh{׿oGR4,>H8H[3U%e2%%X7v_~͝w~?:E/Nm ᘓWwsI@ )+Pr5Mf8,4K:.8ȫ4 H!3R@IT@ JPQװu@д:ҵ8M7%3krӖsKUY&MK.ڹu>L'Wp٦tnC$76oF^xqgQLv\ݐ%w1 ?r IDAT Uaֺ)Hs{@?==k-(I㩉ZvFqeYS 7m#/]P59_plIh=¾=yJ3 @0*k:]gs6`qo<|hǚkϿ#jnsוgIƦ+FN*xPw=76-C4)JNȥ/9ș?|ɣJ(2EJ vlOf5g~qӟ<__Kð^I3QS%i^kҗ^]m. 3f'%]HId9 y`'Ji E8kH@u z"5&9%04,1TIeji!xlUʫ/B5NaL7jt iJ.Qw4M/j8u%a"yf z+02Ctz0h4*brf>.+"TB2>j0 \/(8{dX`D.PMb2ZHwymg^r#AζON1sk: !)UХ4bs GHGu'!jHhYNvµW\C$qOWy%ʰ !y9aZ:YmyEI'[eVL Z'Dr h@ivr\^0V:xin@!44ͷU]Զ]r4?vA~3I38a2P)ZRjK.0sWlOo<^y=$yJ$*kIJ5DadYd+lշwytbyы^LFd#>c<EUTk9IBB8Uܲ+FF׽7gJE CHdcCuv{͛(U7`ifYemom;5K.SH. `:-3EU")-ۃ_߭SJ\)F 盜0RlX©2+N-Z󭩹 UFjJ im`riaϋqYH/5<[I1(K>dɆ`SmlnNp_9.]OA@*;d$ I5Z4LB.w{q\xcm"z'*rHV a45wK[f`*Q<<_5HYS~ݛg&@vɟcoݍ8 BUHƊѐL՛ ޚvgmU,G~',uQ%20RQ6'5|L34qtAmnfʲ:'O.RJ9 e 1MϽ 4Ԧ*p8;蔢ZX]1lTQl,j~0c~ޜ}ʊ)$@3M44JEj]k5^/Q%nXV2#PO GvݶU)6Eи급b*zRw0v53+cvZ}̮w{bVWԂ Ajf!lha6tn:15mWtq7Dwm]W}$GqSz%0<8-Vidjyюwl_e '$n;~cs?Z&  <m3 Ȋ<P0'V`m=E{IԆJ (/=?/q9^mgG_\6-R /~y8'8McqϽ_?/믾~m6Ҍ MHܳNT ro~?oR @rՒE',DBSiI6hqRfo_/wzh0ޠ[?ۊxA]5[M.^} _8ZO,)eOEi@cR$TX|>ehJt&Vbr% ],dsrkci66mUw]MsP\SuS5M=.M4,-@Uii6K"y^A.mo~b-W4܎֪y>󐓁L ` $2)rimb42) &*!@H $d8əCUzm}[߳UvٜlZI m;n@Y3CpSґ@*,J E`FG;O:Sii%11˓᥃ա*֜Z1@YIӟpTt\#1۝V0P)}Id>pi' GS@Q;_ %!7&\-8X n&gA4 9d(v; IH@P]'wAH|aܳhO=\Ij~SPr+4ܸ!3`t<58d͎bgN+p9Q$bY`t:^2̹2 1)%j#N,#gY/gl/@ł^;-LZփO?˳JdGq2O`tP isr1dFLOŔXy;=kYS7Q#13\8/u 4h͚5˖-SEO><sNReyɒ%_|k*o7j.¾>.VwͲŋona,Ο?n!^;t>C'tRP$i_ tKDX,]5::zy,dɒ{|Q,XpE}w {?6Cۇ? {w\]Љ!yzr=J^kvvlgMqkt$s(dqʻ3t@~heZ.-as \._'~.$ џw"*^ ZUs/EՒE6#PB3yVQ霆Ԛ!<-Ba-T5e`wBezTN0/A 9(%d::@ V3OO:跿E OI%#Bz>% LNthdY?s86f$L87~)lF Üc%Im{fF0h Ud,+IqXFSۧ<3<`n|F6ƫz#b6<C ڱNewKP"7Ϝx≛6m2MsݺuF㬳; Bo>le|Iq|Ie>l1bŊ~qo[n}_җn&0n?O`}O=͛7[nݺuKJu}cwuG/Zhq7|5sG}ߠ^˾{k?6-}O^::.d2P4,q8sI (&~hG W5cgo$2ՙ4rV'5EOK)/ ߝ4N HjW,IF8Z.dIfv!onws2vp5X TnsSDQ<@^}?|.7IYʦTgN4[%It}Ҙ &gH%40P&JʓN↵e$W:gwRqӱ! f{F!)! 983B\,w<3 )QTu_f=x5r1`Qf/IM gY)cZƔf DqVlR'8>:.~|w䎿(JXҨ, -+RE0v Q,+OO޾ۓZ0oMi8⺺h/O6.}5Ŕ-þ)#fB%bö1U0S1XR$XqB@aKݍ_Y9,D 3IJ3Zrej9(jA/FNcO8Nc%$@3N;ut6zR%FcP˜1e8f$#ea5Q/ ,an~} M@ s8eSLnfJЙ M8gT%EoOOt;k%ILICךaߥKP0Y!fa`pݽ`v YLiƌ%JZ MWdAQlӡhgt%$^($il9UN iq5 ,_X=ov1NZӅBut[޴C=3^] kڊZn1d5Hx!Ys'sZx}%Yf7yžUo^w|mO=(LcYTѶR#t,g9x8zUb8n.25fg)GH+f'9:( 00k]#t{nB! &1~Uܳ>xQ>n(S_JrcY%Ney Tj2ך$<TRJ VhT{i-Hr'|>uȼGw?w)lOW*v!: r]gW|NL,aҌoqpd#Mq3t53l̊Rm1E}K" S Srرu.&AO5Rӻ9:V+w#3:]*i Ǵ:톁h5g@Hߴ0>я+{?mۍ45PII(3im#!셩I)i!XJt*GJmԨ}u9k_@˘Su YA,o^4\xmp*\Ϊ׺}V`PW+({^SI|7dtB!,ͩADWU:&7s~"gV>H0&aTyd3 T8P-ԋNJdٶuX, #ű[{vzߴgOl_HAR%VBɩTp_9ӽ/ o<0M; 3ՠZ^*,OOOkwѲ>u/]=؏|#cvm7|K@o<оtqzs_zV=Ƶk^q/"s9/:n馇z;W{k?6nß%ł6ۺ((h3KRP a8Q,ȝ" ,1ÊJs .=p[=^>H`rgVӷE2d$ yNFeWyE,J`FD<0әRGkB *Rw/Q/߲u+s,Ǡ\)cZ&9*|g(#>h׿3φjF*@^3$e+ȲΩL,a aJmYTm Qؽ]>S0y?HcL⒅tf4 :V*ImwdQkz9$1~k8Dԉ\S P(}PYF#G1-)uԛR&=].Zk bȴ#U( zyO阛 U$^Ix75YX^*8ħ7MB(C!(ɹ(ș1ZaOp9q23ow;y"Qh&Tܿ``vfNє/ F+܉sܬ"I{P)W/1 +"J.SqC MC(+$yKslXT T:t4Gkq/Ҙ((I)jrl{m8"v-2OKV0Hd݊ì(U]sc X!$ 9a #}[(Ad$TE6o_xpg}M[6=;Äi@s&LBWC IDATyz7(К ӠK@>v+?80oj KjIyUsZw\c;vo"J~6DykHJFJOt. /ZLB;׬yeGrSb9 ɲJٙ)Aʲ9(O[L/8M:9_Px$^*" MiNY3(R+yn-d/ B43dGr\}ݢ:a=Wm30 |t8>p>'~-^^ZK/ᷧ㉉5kLOO]v_vZ]tG?ѓN: pJ/V5ir-]]]O>+ [nڻ833l20~e]Į=6R9Lx Rb0}!X:eMc׾)˲>ϰgż(7LqОWwǝ9bhәdcN(cDJVgA0Ha2hBwvga7hLeiWBOGq޴lv|O c2l斗'攐Lr,p[ڳ*] soO]*+-zvƖ>7-]~LQd%Jh:2(vv CQᩜY6 uMqL &nX* "ghAl34ݜ|ejT֌ȡZ>ҙx׋>/Nuw|晧(^I&1Ը5]W~[&Om03G6PHi X#u\51,貒n~}w}㥒CAv#Z޲rud_x<&KQ!ICc#e^F]AIKL \Y]p0xaX\K j LEI=sC!%KO8_Ԙ9];75̂$8gu0J~frzH`EAJ$1BLg|ꪣͷ#z|A_͆zt>~ˆ~ZV(0!!K_UovOn8̰)DiזsOBTMKU(k5QHqQi/ d('vLBLUKy+p ( G)JBqZ-lsӦ6L{>T0'gI%Yʎ*edk51CZwB6hNRZl92g:PS"CM8 U0cC(wSB CPloA*#S"\E Mf $iww6m3 T8an|JPGoYLZUYN°>)AR@mB#F֧zps@Q,qlKŁg|hhGqϞ~S97jDB c8n8ˀRǃmIH2:u^Pq7&i1V늀N c7sR-3Vh4X0Z8Yu[ G14蓿|$8$S1"f t7m^,P{ ۷DAK  J%n+O1cJbe&"Vʈr9q,tΗK 8-kiL lC\짯ܼG/s|G0'7gN3)QABYM'/Z% [>8mxLʬ\+n&|(6JD K 4 DBIFa`( "*^$S B{J1,YLaR,wVȯ]/7IL$Z.c ]C+Vß#N:ZW"y6nԶE {F8eO 8Ofq 3@[9䢋?W]!I&d2L,@rh0iG.-^4qǟ텭;6ȞmK)M/Xչ/=+W{^=^z͚5###SSSW\qEOO_:{1Ƃ iz.-}GA-f6>&Y]/zy?'D.DCf ӢRTE^8# ̴].fhƊ3+"{1{z,\bɁo!>(LD36lURJ\yj^oOTaQ)eaD!MU*f~[M?v߃y}&a7WkXBQUS( 9ޒE+h`8y$9931=F1Y[0s,m[ U2ĀO][i ~?ɫZNn~ð1!ծj),GdyIf:\;McZ`SSfw5VV }M'ũXr_B/ag$yЏV{]{<˧Պj<;_zǮ\~=Om7o+O?Vժ\p''m׽~_q,!9ԌiueM8A 2ͩ^|&XVwmWї0*z1ő(K&UT N:4 S` Q8J,1Ԉ V efO}32E6 ,c73+ T! nif>˜Ɲ[놙Yw{77ϚO!QA, Ԧ휋iHRՔf/ Z>0oOW>kv۾n _0Ƅe&haAƏ*qۿ/oiFRU%YI‚ljD( $~*Dj`&Ʒ'y[`F嚒a@UlOWKZ9&cr2E*q$ ; D2̯T-{x- G=g\u?.\㇢ZpPT)q\-R 9wN[<}@|̻c4myMX"ؑ)%XUUY<Yp` Y7U#$$,bO-{KfߏGwO"(TI_ܽmg94,3 =1$"3 n4UU+Pi9 0qLEnk5 eaT.wk5QDY)O<Ï>S D<9x.H2ϓaMb*0rdJ4-[iC3a ѼD۰\#P/.9M-Ј/vqrIdy,ra;dyaZrYp 2}$EuY->GRO_{?~+>o}3C JBEպZVZ:j?yGoji$\_Vˆ֟?&tN/زY@IRoE]/%YȢz T ,N{vܰ?`Iz2? )^s56m}oߵkNP$ٱc~!Sbz{kwy+Wx||C}(˳Np߽y3M/.[vkOZpK׽GYoᆥKXn0  tణVztPvǏ3dYTN%ȃWnر![W/BA̓\eٮŻ 6(Qyq77l3з3byx 81@9{5AZrڶݭdmZF2"hAmgmp%G_ޓ@EKU VTfjEokP41IBmvw1M_<_Jן] կF޹?~Fp;x΄ ~g=ο?<ϰ;wUN:?`ggf7픻v|ޜ?LI֯''1,VAmY6\=ӿaˈ#7(Je9eЀhBipȼ@҈0NbxDPqHEb}lh?<}cɚ$plt|U|3/tYv b2D5䱝Vw7C^drT5[N32[E%gXÎ7/m<3{&,KP|LrE0차Zw K sI%RPkV$*%&;cXcK[*IK6 ˳0́xu6?7?<>/}K{su]}Ċ+֯_g]|GWX:g}v\޸q:o%sYp᫑e˖Ί9WZ]}/?O@ 02Obz'ǟxL+i-߇ I%1%@y` i E)s3FG.5J8~\~ xq~vζo. C[^dU 1EӁ|+BP/mߓH5rˊb44DqN9S0,qeÈxL}r e0rىSN=Xb1R1&W,Xn ά^k۳O>PD_~7&~1>wdd:~H0hIVM/ZPP ۚ {zPY476^`){fba+HLyPd>b"$h? <%Yӑ+ 'gMBՃmryy$de+f $a%Fa"2Thv$!ŲN{z{ +CS AUh#!i ߷ X0ĩvD[{R ,\"I;phX.+ yʉg84Z/>CuQ?K.9%IWzaAO8K/#nٲ. z??SꚝWw?9ewW͛7_s5֭/:hƍ7w_:oK.g?~չ/=+qmm۶ַ .ַ522299yWv0+Ik}ߠ^˾{k?Q.yXi QePgVR$a8N?˯Mg?~\ 5U?0wn%+ AfJ`$zj8SBTxL#1čY%Szw¡޶jg #/Ә9c0dq y+8 z5 ovZgg꽷w;ޥ՞^$R98w`w6o (LPq2P$XyN3QtLdĘE9ALYLH):~oyDϙ$|(Euhьc۶f^D;Uz;ni$R#%p|Q2 dXj϶N{J14YHQ+뮻 8:o6W_}KO{ps}C\s͛YG>|;g>sGZJ; _ꫯ^faϿꪫ~z>011}SO}qsݻꫯ~LcuKJOO^ x;ϲSN9e||^~__㸾;|z.-Ӈ? h> 5owU& (,w(|rtݚKayA iI׳*pM2$,Pdu Mb]=vBdف2' dIn"͢PKPd8Y+ ƶ4hLq4BHeB;Nڵ`m[:Ȁ٨*b1Q1=NK"LB @s;sԆ'w[Ii='~xAWunW/%㏞?c4Kmy{?#9rIg?Bi9|`3BYe7" )L JlZn6g(%<tB#0B+FaFש$ .iYs(mhuujX-91?ɞl-UA^ĶJIz 2ˀrlؚJ33f@CYhB>YƲ(}JhoFTuK=#L;@4 4uEPhPK<)0iGgn.C!.|Vw|?;̊%2b̅JK#?ѻxεYr' OR#9b`8P(y~QhL:\*I<|]d# Ѥ(Y`IrӤj"`@ fZ(lF(Y!c3 !^@T$rj C5Ӓ(>((V `7n6ݔd|"t :qpL D vi餱i{q݀EUz`b<0wQ[VsvvkݭcW~EQO=GkXsq~i`4lBMm)t21vT๪Ge6QB}aC^}W/[! ;IBX YL`xna;gzth IDAT  %+sW&Gf#0(\GBUbAq@<$tZwuM %G2I&U)D^w< Ҵk"xB;r {A5~ށ=_4h#E]1fz͡@sb,\(R)RiyV5?Kœ8/` b7M$A[Hf*042NU02r;ʫTZyLeqT.!$ Ve<.*vk.l4"16BM@G.:hK;;!Jh+(:\'{o/WQשSuswͽCHA$ApGQD tFxDf`|FEae'A B ;Yo~}ΩWdܐ ^߯UV:V%iBⰻ 92U 5qD7 <8pwW\*w { 3 n Kgnٶ]|U6mڴy0vơg7u=E9dQO1hBQx`+30r}8v.%GR0 'TbHRQ;aMBa~PHנ&^ǹ0KDj҄^Ǭ?{9FMwv6myp]N9VӮ߰ZcD;vK=m'qm(T2pBseOmn驨Q07麗7! A.fBBB d/7rs0 M =ٝ{tev*ES,ňr,<qJwbj{ΆW=e*^SIEAvʆ|Gf!Hkrs S>f:)YC;w; `YxLƊO$Ap yn, *i`qBa);K,۴i*CDs{&Keǭ#Ir,2HxI*GC,۔D trȋ ]K.{=sމ}\X17냐umٌ`"-y rm|E1 2\*̈m+6s499cxo! 1+m[gJN=U-M[sL:Xo\ +q1P OunnV_T-N`婢Ϫ o{lS?b /rj_q08Ȟlxf9sR9C_Y'*o~gor iGYHG'ަM60m!r4  E<,*a+hIċnS@$ ""Ȼ.s17oozG\9:x O8j1Z%|810`x%νx>T '?ruw!JP?@e>}WkӦq MyM c96TQCBڑSRvXwp#7:J)d@dt⬮%)BÃ2Iմt$ыs9]M6v N*NJЃ l8AI1D\ԳpѮ Ѱkw'"R}!!4У%2Fsp5QKJ: "Bl0n41SlǦϱi4hAsD AQ)S3Z4fA!PR:RJ] NE1i55Pnͳ{S}O_"]mQtq"!k* G&HퟴpVdu ZQSDc8`u;PտXwzL +X~ШAI!ReKh.'h^alw;C|", 6:aĞ}%^mk7Lr Eԥ'}7ϩL4FLi5۴mk|Cn\Fax#SX7Q` Yr6V̚a 0ѽ;aL-P>| Eִlh$MZ$f'ټPC´R|ӟӟtRjxxxgg'q-/9msr7w{&lw&?WZu'IY-Zt-83]eppꫯ8n=Бɟb?TM#}xVe>o@tH4o޼믿~xxd6SBI0ƞo*5VėtСOjZ]qo.1k"(ke(:""n@Zv̢2KXBNT41::6lT땧eԨM5 ՉNZI hB0٥zd}(~HjtLt*15B=)>}K&J!hcձۖs?k^۹khr ܴŵMX2:,mxbpA.[]_  ?cD?zA*+5B"{f*LTjN\מ?5 cE(->ox:¸^)SL!x/>G_y+]~751~xԫ<l^e,yPC]~XZ @t@EK,y.\2[HT9@Ѫؼ~3D<)g_pؙW7IqL$MokC'*5!DR䳙ޞןTk^#AD B `KqZc)$3 aAl5%$y5pr r܆(fUS8"a=3V3+t81Tn iշmQĦc>g~W>i NTM-P3ܰ" V'tV*GDD,xQ-p X.]۩gF*^ ݙK'/p%J Ѭ4*R/CpY}3(ha>QgZdV=I|6S32"%y#ID2Ss=Vg@ 5 q I#($ @XS4QjUT\6Ry SB/{pߘҴce8EXҒ\ \VM14j>rLɈy1>p1d=++fOm`-kJ!(-wRvj l@uXugUW9ֱ[ 6Wo/<8:Ӥ??Xs mszqtjZrP̚=!;Pw!?/Byk[1G'1%P]|a'G5O,>ٱyNV6Q (twqI3 1!˜ƔGS3FDEnfC^ 1쀓 clXIR )ҐդHt*gRRQf96 *z2f4YhqVm'ek0捖D @ 5iDHe8%,!Y lc*'s\NɬMFͫ[::ϵW4ٌ`vLI fcپlLVK&`rXUn_J0_ Z$Izi8Fٔ0lj mjS{%+IT3Z+t- =G`\sիןo߾}kx; /}M74>>}+W~<"7n\;6mzG9sdY>A׿>ɟe?_L/2Lzsd?x/~~to${D }Kh֠Ujg|@:Y~t'ݒ5s̨y734$?|(U8ۥ ˲,j2=i?_VysٹeYBw&UEx qD=0iTK6;VWʓ$ 6ScJJi" ƎmTXsZv|C^z}hf(AS%ع{ב˛҂X#9ØeGEQgW@UbD`ߋm_౒iv(~8P`n4*–x c51eZaJ0XĊ@92 ]5vr98Tע3?ҏIN%u=!2Xr)nT90>vD.f{O])H=;iAHt&֓,bz`/`Fij0{xj "ic6;AFM}C}| M &$jJ`׈ek S(~JD*Jj/b${$o[8,t;cժU1shq Xr孷q\oo﷿_p<-[z}e˖e988xgkdɒ*N~L/47tUW] 0Ss3k&=X#so?|y}>ne`HDVmnO׏~?噘)6Jgdȉ~Di?_|P/R]^Fuvȷo+0^zj}n~y% ]};%?_"ɪk{wnt _r_~퓓CݽsՇ9ORlXHdޜ~xdk_3۵o΂7#2-lOW]6G,qpLaǺ3anEUQLoo`zL&u]ݾ}SbsRɬb1ʼn^,-z˒T^'Ie9ue-9],vVV>bG@OZv/_w}e)/7ph蛁Y3Zc4)e|&I#e4EPu[X&h* èYD1 㨊iؖLJ0}꘱ṻJz1'+}ĚzYٛ⥽;/X陪Yֳ˱-Z1py=A p g}6 .~h4 ؽ{WO?ކ\rɓO>i8ׯG>rN;o|a~ߘ7o}z׻}m͚5e=s7ptL{ꩧ^ve>h&~ڏ۷o}޽_ɟeر馛ߙ)^3ysoG o[n曏F ϋb60V5!K]xu54*LມƼf,1ցod BVN;oa4՜dCK0tވ)jR0oˢʰ!٪ ,D> ,! ߽{-ݽ9MBB+|Yd+׿ŧ~lڴ B.v4o/`g%!2 "vڲy}?vPŪ#ȈoAybߺ+Y/t*'6B watcwiӦM7FV?kٙz0 [ycq)kB/8 $8&V%!tPfU(bD;o<5|W?orl$ۙk5AFXg523RSZTG_×T%X"mC$3u9NvjbNCq Eq V؀6'jR"q*OP*fڔ(E#q-gT_kr͊+/\lZTb"[^ZLM|>g?ܪM~ȉZˑX$6㻙|)t\N+W;֮]~GGǥ^z7R5k˿s=AwwW\q7?x͛93gu]wBnƕ+WV*l6{Evm|o߾niʕZmܹ7*]w}ottnL~6 h~wy###B*ɟeK.믿V{yoc V?d_v{zz?nВG 3/D.oxS-?ZE NRC0d|,I'P"$MOjHQx~BIISJCVBV&&x 1?|)CA 6vd)UN\JÌ84EjITOo^f,pz#xw7q,RC)c4؋\/N,2lX2y%Ahe kb4Y3-^MR$Kc[j? b%xߢ3CK[U`U$9}oӦM6&Zs.d!%jZcSs&0OB>YE! >AŚ(dt ZŧghKD5U%r<ΰl|*}ަsժYjԥFx*>!&✤Aa1ZF,ͦiE$sJϦg+?l[zG:YfjXP/;me$r>A㻻 R FG N[R_uHcE"QD!QT<DŽѓ`;^Xea` debxw~\/87ڴi/Рu翅n޽ub5FU!} ,1 *xwYm!]p'{xx8Y14JkH٘ڶG[Hx%8E8V}8Zq{~HѠ qN+ixKPLc{t )Pݴ+כ-slqgdwKl4Ѡ%4KUQLQ;M#pj6pMD>eAÖ4x:6_T_}zEziӦMc b, ˗}VΞmܴ P /NXnVq,!$d%YAmhB׌ؔiW^ڶqKir,vI@Vfs2;gUNJO1NZI3jӕ={Ë؃i+by h(k|?HSC?)6,(='#MNU/ɧ'lȏLCL,X/pzWפ>٥}\> {TiKF LrL|++7f2}?sbIJ)24۴)Ҧ=ˆ6mڴySa1r5]Q,&Xfz4Z FauŎŌƸs9ͶM$bIЃ!%|LSeh;k9ᶍBv!ƼE%Eb0Uy[ L@3MvP 6vl0^ڱFl؁爼:9Q5ZٲeN0 M7Aq;DOdX1`fyŰSWHM۴i-㺏TK}|2N_ٲpCZ֛RET`5y#C`˼\6*VD<@YbcAƈ-gE휼i[ڴi歏;#ZXt"odzׇv1>ɧS2+D~lLߪqO+.}ǻ.ޛutsnt]]RC1RJʊ p)A]iA]/G5+Wig%3cOM NT5M4M3bqHtL9se?@)+>[d,d%G@*̛5c5 DS$"ӴDcⰩH>Øz*AYq9;+ٽcsiNTׇLJcjD^cγ}1 `NYU#d٭!1-76BD$N)ULC>B#a]5IloxM6m-9MTpZ5NĴ{`)He$&3I^"xJ}ʲnTww:1h(EU'p*'tO9~AFjHV"*%2j,0)(pqೆ:RjTeDs 8 ly^*OϨdձ#Ӫ$ ‹/(XL,ERͱ9 foj1Kb!ʃڐW/r'qR)Pd)'uy⦒IFQi-׾ xu is 6dlxǹM6mt|?|&Rݬ9G: 1' 8VyZM m 2`%'/o6*)BB@FlJ* $b?hq\Hɉ jB|?Zv j`Y'dH^SSMx\/b9m'LꙐ2r&v$1tVJ); ݢ*ֱ IxM6m-9Auk bR4r*L5<ߠtxتUr*HY׾kǯ B (Ĉ0p fň^Zaiz٤.Ɋ{ 0F("bLc'#HʱH<߬j ɦ"ihjšppoɞh9{3A+ B, q=-/e1ZJeӦMT$T*iӦJC]wux~xoݺT*8^*󩧞 %Ibfpp;4-}.Hq|vsJx=_{d񡡡}VnDe_lh7n9<(֔nJC 9N$J#+W(ė"#B?\t6NGFs̒\KSB'Bl@LW^|Wb!U`alg81gAʉl*0/f"/Cl6/I1)rC"p ea B$JD>'bb)Mb9 1\E `aĪ/_ 9ɁMQ><6-_~Åwl{ꩧz:{qRr0.P rQYNGCXEF|ilܡUHu}XZXbbb eYJšp(aJZ7ddh%l..92X l F(_|߆O2Ò$P.lzx6DR@a *Jlz蜉G IDATFR|P̔pgH_ 7&JXCd9*/KG'+q&Y9VCL12pl4(ҙth4.|S694f22'۾torh}tpvBFM[ӔЇڝ;wYV{ 6zzhjjʲCm޼c|x˖-ׯ}t{u?|߶m[*zgo~d2裏gn><|prrry_\p7㳛SŻo7{wu׾} ؾ}bտ?K K}) +/,1lɗҡgd6#gF}|DŽDZ,"i6fRxa('b8 b}h(,gr_vY8I7XqP*"bRFd}x4'JCe9<EFR>)Fy$KD1T_/Dx"b?ލ}VK&86m]0}zx:Ii_n2 l6n6 e}߿c=GG7zuֽ\Tբ(Mm8>9UvW|k_;vnO4O}n9WHC <#F89-rk֫J'`VIƎE .13[_&pڵ!G%($ [YA,O˳Gߌ1=#=#=rZ"h뮽̥ Cri^sm5XqacI&c0f_[tTmIt|"I 8#Pׅpo Jq8/|aݺuopTI&7n~/nmjjʶoK.<䓗]vٱI^z5kk׮}S7|=(z*x00I|[o]ltw'[symtw0ooy^5jT`JlZk<S{(g;|\zJK$O(23ԭZ46p!0ӳMH( :W-m’сb칅ú"9a)eQێB8;*D!EHؼ,C ]G6&V,xB![ F J`U?@R4{ pU1N"tJҊT ^{cNKuHHQ>mA!5~T,  ;h َ]3 3aJs- .@{$kݯ:SjqϜ=BGI F0]!DLlyHabbzt0-KPrm\Mԁ8RX3u1mRWy! 8d4RԚeV`Ԅ0@i pI|k>On\d] Tإhua 3 C qiG6E7P\ աLC1ɠX `I| hLKcTiNDT* p!Ig$&0P_{;¶j9]!s1Cۋb.yBP-Wz%$pF*\u9-OwTR#=#=#G,L9Ɵy;ּzq]U`u&9H3 #, 4MG%38fyb'wґgC)>,T$v`8-a9ȡO Vo?ON?}G|؄[*p`IhͶnzѬIk6Is>p|(R f1;xkwxu T< #~ $idLU0_`PnLeހ3aV Sk&ΈL *9U8;ijav3<˪>ꪫ˲ٳrM6@ qG}{\{iNNNXkcwy^~@Z]O۶o}s/Q^E泛SŻo7,nݺub'?9N-~tn9<'Zm~ټc`ģ2-1U<\?~%9Z=g!B; "Q"Bd13 _O/]x0>^@x..yDP;.aM,k!,fʢx!BP(TRQ-䣁x$#ypmW vzp>YVBa\AB7TuS]@K?>7}$AH%x 2u=?ؼ#[iuE$-7So]l٫W o:!0XR]qb bWko{fw)x*f4T$g 3ݮ6vYGpc7\J;&q?ab䣗~BZ## ,\@h@Ǹ@q(1 h=W'PƅɽsU"a^ i{Y" BxH6tI^1a+g|wM۪UmpXGk4BAFF8/'Lvm(4Q&+m8~Ao|O=9aR_/Kay'|;L8/ˋ7lذm۶cwgn>3os7ܿYgcǎ_|qo ۮʾn~NvPߍhn'wω9Ym~=mt r4p7~w?6tkwGg/]́}+ظ+-T2IEĔӏn쎫s;;ιf}/3VұP1U2cI+Mȸ.r@L«W 3tyMw|31Q;k4>ܿbtl8ZU G.lѴ/RB1 %LO%`c` 沰t֬Z4> eR*GxZgkYvε}e=17=#=#=r˅5Q"vF".e/x%CX/Ųd.H}TTN &x"$'xR%.w_!FdT).\s@,V JT TL~u49Gb"U<;5~y:g8-T:^*Hr,tH \"X*}bώDő#r ؉B&A 1&sh1KL2U R9KF}h~l`KX_:?ܗ.&3BH[6L 2Ha0LsH`ÃR!Ldnwjm;|_vmg+lbD&x&)$xo0/ e/+M>_D:tv0<3&"Q&IL8̥,|iI#Q NJeV~8ct?b}|ʮD<)cBX44Q.K X4FB"…&BaP($ ]p) (fBbMH(f%+Vesp3id^}'> I\n˖-Z\p EJoy/Z۶m[r%EQ ,[l֭?;;{u% _?77H$E |;yn7୴xqƿ{g7?w;"aTꦛnRO4[X9<(v^wL0m)B(P՚φpv'_o9]|#եĬ( ugcsv<ޣyX͗~tٲe3usTUI.:D:hHgEiŗ^w?Pfq@j{֦ x֝qlb6֚i6+ 5X iS^o4K7ݶbQ0i*0#6=HM#jD`a+'<0x&@'IHHg+/Y3ϞO@;J5,@0p\q__%/Yڞo-SS͙zgXMs@qbA[LD8J>h&)MT4$TaU07͎)`"Rz5f;h0|&If!2!29P[6 ik318*D VdE]hXwGy Ѥy(FR替o@O=)²8 I"|tl͆&sߎ]{_X@Q G `ЎBK/旿\}f]8v. IQ᝻;sok2R2TFɒ) MEsbp |}@8@0T[m4 0%< @ vUzm*2IHK cAIkZAјꦇ6?BE$HHH7Zu? +|y'LS)4 8k}x/|VqWL#yg©N]% DzáH&q2\^}u. X0b+,)J.P! >\kWaڵ]0 EQ(lIG )3dX&gnKyB`T!=u$\8.E Az*f^B04TpYa4NÀTTjaz-PGIlfk2@l|l׮}^}逸zJ{Gt `V˫!L/& v,#i Y3Vk jw|̣h!a4:yXb|`&gS굁ltfFcDD}^%td]mAy&/~v`$TgBht4Q†!9_@1Tu|̉& jCm-c!"p9/4<)*DBV\Cļ""ձVdHHxo$v$M]wDG)=pz`{LOb nbP # &MȢ唉6pUNGa9m+^_ȗ;F  e[T{!JBg<`:9M6VХ`\, ! _̋^!X6<P7~zs'z@1U!E lP`Y69yk3՜n#5œ|&v檾g9D4*uaFa_$D1tH&0\SI&('w n_X@spy٪Uf[{ꩧDŽ@8Gܘ:U l1WQSUY6f3! 20&B(#9"jPҤ 19](a,mWgqrImֱi xs۝XĪ2(y`z>bVZA|U]H1-BV ̑6jU\ 8&m1VK HB GЈЄ 5;6+8!g8U YC3t8.[|zꩧY۟>y*j3B!..NF$X93bZ-&PoiG -_[u_L0FLY⿿{\9|F .L;$,t0KXƋ#/ ((ucWo}z;ÙRn?XYwli#k!4av36dhǥqq\%ʧkh8e7\K̮(U:"zA0uAel2 WF$Rz+NT9S;.W LК[o'Ϻw?zSO=](Cz`P/ct,6`ցVu`p@t_9ɰ$UlAWj9ci1TԳ!;3>qM/ɪ+ IDAT1Wӏ~Q>D#E"M8j)dzH-,*Ui Z8FP"Iba/4X¡M L*8(Yi Jq},׫,1*>fhFSݔzꩧޮ~۝[6\ij⻀0FHѰ35kn۩,![Fma!,>Pʼļ/V >DzBj 9׶+w#mܞ G;i醦96YK쁧&2b, (1UIQc* ͪi PGa`B0+![;M驧zׯՠ  FP7ZAh-Ճ`ؐjḋ$u_m[ F\јOD` >cHMQ;v [Gm`j~mI'q]zGT|nl7X|F yjU㍽A6V0*C|褀Q948J2dSiă)R:UѶ`KL_zѱ`G:2-䆲_w;-BEᦢ,x`\=  P=FL ;5% G@4ySO=`߲Ifҿ:2gj6%=:$o-,p$Yv@qDP(nKS0"Tʵm:0"t!PPf#4MktZ/_|madi2|Lyh&,"&2/ AxB*0do"7] X  qxXCL4H\ )(Ky@Ë|֭R R~%޸n7O=ԅ^(I0wqisq߿kM&8 =cǯg7~yNVZ;ٍsq(ɩPL$1$2(MdB }L ŃqFfŘHH×q1B"hT*&SR:b9#H!1X?\0d \0,_;gi?KR d.,G+OeORP DiKˉ|&.ӥe١@)|0!3l:IGrKFW% \,._d4P+Bq)7>f+鑣ڽcxc6l}=ԔeYڼy޽e+}_~-[>lÇlٲ~z^\pqt,7?{wu׾} ؾ}qug7~yNVZdwnݞSŻ;TNeFVr o64>E14shpVI02]Gxd8Bmx&CaIq͊$5LBFd7[ L:4䣤:|SľHt:;BǢQ'Jb0NlY y,*IuXȀpƔhr"Pa6VMc0j혐ف\\Vȁ=iuF,0\緀S[=#=#=ҍ]T. K  l+[0hQGDDȳG74[?0&}U<@S]j-JˆѾlSM˵mCgp , ۶P4W-] XTۡBs1Tnd{L;`4<( jFPS>(gyY6sHf ǫ;V q``+DfCġrT|_STSIC5[%طp4P4|,ɱtu4㭖OEIlTs ,K>ǴM%IUш㺮wkܱ}\˲ӂ ,n6T*to_n'>|#?|ŷP7jhTӴn~n~N濛+rٲe޴czv'dşuOV|9U nuku'}ҽ@:QKeCrJ3 '+5I(%(@1kutPU|Ì@F C K8LSX8Q`H"#,AŠ}ɷᑑ,32fu0l$YOšSn0P# ޜxzH (!2Aq= ݅|ӹI0qĞWt, ,t=\@oӁ CPa",Ϻ69fm+ޱRrٶ8Yܫ7m:P&eaԴ]Ei/Pt1}{ec݄=PXfhjAPB P0]5]G9Rc W  "qYY$jU[r,AJ҃Pswt㳿# qÆgLm)Pڶ^L=S5贴Yx'NjvM5my*9qYev+2RFԼ G@5 WdjM9s?Ǿ_8nݺ 8O$ɍ7g?[_|m655e~%|.$/Қ5kn{/};>kO7w_aa$޺ظnO4Ɋ?U랬ջ=?\aa!> 9Jk&ȁpj80nVvT= ᔥ !ff+k$aVE E-:0mr'.ѡ /3f5aJ#, C,vy qpQ:h h*C3̉aZ4 3zU2'HdPDuQ 8qt%<&1:5ר5G8@bǖtTHHȢjSUVZ -B"2 N1O$מۺk{ȋ׽l4'$\6BP8^ef$>z*9;U`peXCWo8鑷${vek|a0D)1ZGȸ6˴`< '(ɴ!:yȶ(' FSU%hHmB80mXo6x!qy -D&wUT&e>"ZJ6-Cp<#94(`;c %^oOS{yCM9ɇiZw!}{gуH7 C5SEI\B5u #mm5Yd"!D @CW|$wRZiA QשGo9,=OήksOyGr۶:t]wjzER[n%}ӏ=X,{rܛv$iΝhtqsfffddV뾥O۶GyG/_dnE_O${͍ug7~yNVZdwnݞSŏV& C0LQ'PBј̡``kh͚jQe9n:cˆ jjcpFP V,>p(#00 |H*3@,V-?c:6C׉D9MU-+#Lh`1y41I!c!$EWېДPσYGIljaZ] e}SNtHHQbrJ&hR0ڐl]Hsn֕v Z8Fq\`8iv#$IaВ.\4B dQC`H7VaCPa|tB).As|T;Q&%cI9Me/}۾p˟^{M$V,9#?Zn>0FCAn>6W|uY;vxoZdnyӁ/>ٍh=Y'w{~N?Jdˌ$d<(rE?w=XyU斖sXs\B"Ya: cx!MFD6K2}ᥛoo _Yjl@Ɂr>VrXybg_ԕz򳆓|cn\\>  C8ԗste%+{wjUs՞i[eGD/HnH&FF0j t`B$#CCvk5~N xRW{Sk"3lnO بZ2UrcjgRcc~|4%Q+SY5.sLU˥sd2sLzƩzgMJybC34C34|H┖gd:_uY+ kgLώ5FjN.䲥Du|Z7޸u6yƱzNW3HR+r6ϲjNIV*99;UH& YguM7qu믿s9ro߾=㹹|>뭷;裏q޽X,>?ybk׿.7Es_+Z~0M^{BÑ50\h4V:;}%:ݶIFυ|ˮ|DH~&wE{i{9&C=I~bW\O|znwo|ZeI#QLBpݖR>r ao])3weo1@`̗vwk-<#z}W̮M\Z\AJ f7k t'2dȐ!C^쎿L IDATě/| AfYF> PLRS~y@>ɰDhNw㸨Jac lG(GeQL(cWeei~snb$^dͦ3B!$Y]L-~?|xqa|&cEb#@if}EIƎvoiym,8rPh{ Xy4 C׉ !a؅0<, (u]܏8EދPxl"TDF @]}fs N^-;H<C {Q;~40Q}nOlw(Yxkp'u$i EȲc %p118SeHtR6NI'"RqJnB&TlAw/~ھC??V Lrl 3Dc؁?B G1Q\ucrY7a&Y1_X b]c {a *P ' v [oz:~B|d~~oz=> eaFI(gT9n30無 nd{fH6{Q~r(w̠QS8VJGHB¼+^[di! !C y@ӄwzr]@թIh-zPDJӗP#aYV8>FQf'8AsY#bvWRlIJM$أpJSEa ;$\rB}JvԷtA`"!A@:NJeŨ簜Dr22rs縼NVWeD|"m` #םwWz穟uGh*+f$!Ib="?#O,H^{rO7mjѲD*{dDFJ!sxT^l*R?2|O "M 8( Nh[k~߿/w _.Ø ).&c  -kKx<rKN c"iQTKY]ͣ8dEòDӆфf-?CTD;p}FܹKW?fhfhy8wtvUZ=kXeݲ_6VtBٖ$w6D(юD d;ƜuY=<[+U1a8SX<7v)QFi,v`}HHHZ;}tqYB\(`:X(/@`!m]eZz FL+[+c 11²&$@ab~L[$,>js}G> (D@_ć6\rnNQVm|r7W=&H^V>dV/Ųy.02d&c~!it/c.z} HҊ@>Omo!,G2GR/ Ve`8XN }V q2)ˈ=O`Q*xLe^C^?R.C34C34CJ0'h.GJ@ˍwۄ@pd(VsC/ϵlZ%v^pz"W,c\aS8fmery8$J0\lIAz$)6W{rzL>Gv+4g*ϰF_Yz5SR|[&a$O /:թL:sBwJ߼GlD%"HLll6 I4V?e& d VGV#-rHP3p 2?Ձ;ܕ?I6ux#HU8[1lui!@p?P^pafeX/pb쯴zD;1A ~GpX |h!PTgcZz}h#SM5])R !}aE 4F$<."˧~Z+ cHʧi(,:v B'Nlu Zeyu (Btb94C34C344sOOvl{n;NL0vF1 (A]i2|>oO۵dN FJEctKk N"K' A]EF20!0nZ TSx 0`pBNH0n^ϊY‰ P2.yﴻ##KK.im j"a8S.I81<ONMMq'⥗^MoJ$,NLL|#1Mxws[lڵK4$5M۵kW<Ç_s5lo~^qS˲axb Fw\+K<~IrJhʳV~[|>w*'S]ϯj!$$}8-ɧFJHU$ >r~<5RV\&rHT5tNaFa<ʧU)H*4TNJ|MR*TTcD9H*DRHV4%+MdlMg'sj5D"7UjeTSG\^K$%YTrȦ]Đ8⊷-{u]j};w7q1>|_tE' z;vp p ;vСCB[o=rm?k_8wޭi? ~Z98<k/8_r%m'ܹs׾\+KOu>תT?zZyl6gu?ޗW_S]ϯvV0@)4* \PKI)#gr6/kF&iHe){g7lN,h>N)V*3MLԴ,KuZ}dtoٴ\.hYS*rijVTT]NT*ST5ǫ9Jp}$/J0]84~dT(F"t\)Sx?65S-%+W_sCyd)4W Ɠ ֪Y-M'jk|ifZX5J^#Djr9E [^tއfhfh5~myæ>Ԗy5 o*UI2EI ח&E U*]cyeDj13qf2}ӼA'@#dcXgh+'BG.FQ{i<6S(g|7&hȾn&P8۾KKmc}>{biAbK98 K$$L}ڵVh'p(  ($ #1^zN;tt/b$ p`j t?yX1D(  `qqaD(0(c.7g#Ǟ:+:b,@m^׵=<<4>$!F pH #Q+0}H(f\@As9k}l/F?s=E8w޿˿?;vcǎ}~~pWp[n=r={m߷Ir0ϫT?zZy?10$IV*|ޫůU﩮WiG8]v5`):p^0LB!;p׻6Z*Ҝ#{~ 84A Q0؉2!@OC]?6vip i?ח}{EϾL2YfxY1Z GaW_L{0m]ߌ~d Lq:fHH b+1rqj*1 д" rgp~WEzhfhfhN\G~eZ<q@AzvwB8RRL3YM$E yBjru"X(ʳi+ǹ6aÂ#~0Т`bSF# Tcg.jbEYT@^!a [X!ɤA횮/&S_?>aRp̋~rۼoxHpBwy̟ɟH411я~>0Z>C_WqyOGyD45M{G>ZV&y8@Q 7PU伿Oݻwx㍷v/׻577SO=uuߟVεTE={jk$[=OO^ۻwM7*k{O>OH$fg纡0 1#C`x:!K҆mbɑ0Vo{G-$')nv˜esw|A tT,+G>NǦK2f& 8A0CHF+j跖KGVW9)=XRoC8zVgw;$RjSmOۇުMUp5A|;Tm8JJ*– 1~;sH }⿽C?8L 2Pki'&6M( 'Mp:7:\pJhqI|#K5dȇXáH$Vo?+LkeUd/!DH($qO;wADqT V$M;j=# #,8`yGiWwq1`%R;bF혆R B0aY|j~1Zb J:!"dXAmK`g8ᙝe;(aٳӟwu Ç?|;' N;VueivM7[neaad2rqqqjjnhNywuƍe|ͻw^\\j_G>rku}a:ֻVʳV~Qz\.wůU﩮Wslbf " $|vl+-Ѥ`(DQir!iE8R$n<ӎ"xǰiڃg-,ynǢJBHb(B7hu;0# \wgl8{yN !EZM#4(ndqdplCKŠ,`! B:+1.@P@n3BF.C34C34C<8(% I.B~ Mrj -1Cb$NhGoB&6-?):6Ms!r&T3V"3gBE/|xdyYH$T9-ɾ'Y~ 4Z_O}cC7lm1%bFC;o`$ pti:X|KGc6by4(iiF#ǡazå2BpHz+zCKl IDAT@mZQ9 a?wg>ðz_Y/ aQ~|- 8 }c߹sݻ_xvvPY-RT6yl*!9M-͌$j\fH~v$1ZKr%jZ+ e\*J#Ŭiݒ.KYT*ՔRB>:5FiZ}1MN˹l%WZUTgh#kZK6vYՊZ$b:d:ʅb5EL}jVNT V͏T_t_!C yǷ*iMK2r+sogKdv65iZZ̗fȗr&9ٱj1]'R$Eb,ggg&\3cB--BLB)%YMjjB-Io^ 29rXߴ%;S٤6SSlqF,%;.7ZV+kdHn?2m۶޽СCPx6Tږz!!HZ˳bXjJIu[&'iz5'XJy׿7c&j%ATL:UxלQ>Ri\&.zuc/TD*VGG5_ bN6N$3h cG l\̤I0BAm !C yU7nd tnd>Y|:$A\JS|ҋ8g{`'/RWKJadd"*FR!TdJAdYVӪTKeb0Vpo2Z.9VIʊ@RJ9%_IW/?ﵓ|5i嚐 )5<'dLRˎWr{{_N-努8Q$3J&DQUUrJ"θo~{[frϗUIH4D<U+\xέMjb*)!UhcC=_ݞkɅR-|5411YIJws8.BAH,7pCݎA(^=q{-[P%† n0 8^ZZkr\k]^^>:J(:66vw__җN,=Z9__u??(f7?9IεTEz'):?>mV0 4o4 UO2_oʍK&l yJr7<|K(C a! !/vo:,xa-~t |fbAۿ>3t\";z<[!ܢ<?\tUv:w_%QJk} B:t pfCxV_= J&$EH*CLN˧ ~фšVC~Yő3) pHknjm DI CD]t.kĠ1 mVC״w%ƞxrڷ=6aOBH{Y -ϋAcJ,F܋c@A&Ph)NUdJ"6sNl1q͟>bQ`41ᦘJ*1i< (0|$D-|yv] }&iWZC4N]8Š$LY!a,C#Ac{l . 4-e Hk} p ryȐ!Ck4rint'l?dX~~ yOasi1̈́E8M*1HU Kd ̼Boн>2yގFQV'k  }:~G!G~H } +˭ ]DH b/EF` Q%`aN3##gΌ txe!$Q+yhsm}@JJ EAЂ1C0t`OjW91h;Q vIE8A؆Z \˲Wz.* B@  2r?"4[;eoB |wŕc9qcnHn(|םaiuC(MxiY}C+T8bWwl_7r8y%4OҎZ}D!X0LDZ(Iz($HxpV5Q0Fa@PҷLA{ah߲)#`a) d9 G}  _2c?Ű[D1JОDx旾cb߰H'rn6݀xDqMBѕVkd2K^uCGBz?-O Zp(ݞ0è6H}g0E:oC41kAcҰA2dȐTP=8K]Y(txpYV~ 8pq@ĄPN$ <0ev~O-;1 +@_ë#F18 W;m.W,c:h )[" r:;s ]}p>qhϓ! CA1☞o+tp bS$we$ZYdSoȀ.^л jgqgx B(S0pY2qz4 PB#ݾ+¯gAAhFv\Q{.C34C34Cso~.4SMvR0щcÇ6! 2YgX8N 3 eauiq!T{'GaOmgvwf׻ B CpQ6!l21.bY !QTN')'8_}~ޜfeіp 1B"Wc2v0x.^A~_6jc(l#\2Act=8%">=΅AK}1YnFI2-!R`ᗷСC6 C<iLrcg[pc]8QfzܪzE 9 5#rك@ñy=bu۞­b>VzA4j[_}|qv%k.:7r5 =0kGJ5E]<%=Ei5QO9h$B`N3! F\A:-Tn8 !L>mΞ#cy옎阎cL׍5~򫮾r2@!T"PXQ(+ c0vr;h{@0^m p! \" ` x{:p h<"--@v B(WC3XVI !IԒ|E%&3Yd>}'PW?Bt¼qcj,DAR#؉b6(m M.sF@x`]6.d@#DRha$NpOw2"0lQekFt[&aLӼXaڵ>,7o>#0}}}7pi3 3{-M|gN?P(Dtoo 7ܠ[= >.7{g鏜(g1EQ]]]^zaq<\~JV??Qr۵kE]H$0 ۴iRVp+3PxN\XJgz]JXFEJJB˄ńV%d=j"'U.9';gpITO$4wΜ¼]s{2_% DhWw;bԼPolpaf1z?}/ӻ4gۓO岵kO9;pNu$J+=n+Ҽªjr]}{>sy{8B W)<۝R#1If9""ɐЛJr}O\`PS ظqc2|s=H$~\x>8s]={\r%k֬9x5k֬^O}ϟ?SO=Q;g.xm%ɷ~zqw5r{bM7ݴsN4xC_ UD8+Ϋ)O ./$"Eyq0 X(AH"RujoW2NHJJGd qfRJ2E+=İR SbX9U±xw&սX}x.gʓO>Y* ~qAO|GzNQr;nK6X#VՃJ!nJC< SuDaHHrѬNq(CQD] |F%k(RBFnT gTŰs Z~-,'ʉa57A7^ڶu+VHo:9y0moCK"o]OUdܑ^TSm>"c5t&G'^"}!n|X@(>qeO>Ƈ~ "XKIbMMG#R|e<?V"I+Xp!I;::z78p'?lAPUrF/O? /P+R[oV}WUu˖-lͅB۷:86660003Gs~xÆ ?Oя~t]w=3+V>vڣ9[?<UV%Am^kk~EWzwܹ3{^{ @@8 $E#$E m=(Դ&* jimP#U2l.!i| ]HTz&3HȥMg~'fy]{|vIEL) hioz_|:whq睽7A⠉,Ds֮ZbC &魿gY^s?yׯ [fsmx"奶P+9뺞hg]+0A`ڮPkt阎阎9}>GJ{_zmBlvXT]kz !$L2ĐѦ PdܬBy%.)ckY@D5Smfhp ?ܖ3?g64osǁbd ׽crBwM0 %ho;>ݜ}=ڷ[S#:FRѴcj6aap(+9iSfZmg A.P|@r-óa `92ej~Ǜ5=U)~wrʃwPе6 c }B}}}7x灀 h>/}5Ccccmoݺ+ko&-[$I Ò-[.'Il6%I`Fq~>7n/|;Yя~4sv'xbFls=\nIAHtgEt:?g˭\.?䓏>h^ꩧvqUW9;vښHp#M +pM8(l[洇Z/0j0l,,ѲBU wSv1mRwχNtD VѫHIئ_=ٟx?R84ڠ,c3枴o܀I,Xpo|8l5.=$ Y $bi=/Հ~-ACk>OP0 =g۷|W|C:ce4]4kQxͷ?}iفz&f<ΏN|:oZM>cÆũ ,rX8<6!ʠh6eVY$Z1 | 4Ѵ= qs2 lf^o[r\ {=0$P&009mgSm'p޹{b7a c>GZobim @Hf%'= S5LP]!Kм nC}` qB˃FN$dzew、 'X&S(/ W,o=۶mjqnl?﫪_:N,Zh||?W?XVKҋ/}󓓓vӟr᭷ފ3GV~ h{NqUite.4. bYUyKA Fx*&>+cFMw4rl,ĀБ1}ҕf3pdjyx؞ckeY# nygdr_5ʵ8JN"J0z 4}̧xɨ4%91,˷y sy5aB0@}C:/:ˉ<צ\7>i>As צ4 DA~9H Arˁ eEko#WMv&J GѢ [mݨ[Cu9$P=96٬ (WlQ5G7u7hVIG%)Dr /r,V;⪀Q`8*(ELxk]k&x@AD00N)[5Z!PPW{/DXibRt8& :̉؎}h0  }|g(PX,vm?>Q}~o1JaJqf+Wܸq7>>?a}ڵNؾ}믿>sK/455d@fSSS/Q?W?_|lٲC to|hc-ca(b~ T x,eSTJë.+?{SkA.p0RMHݪ-vjv^aau'҈JrB{tXD"㮍+8-S((glDND:RLdn%cu޷gs-=B7U@}ڏoWH NNg2!M3f!Kr"G\o)JSXb06/$Ra S*% .8<0}}G-}d⡮|&9:tС1;H'=h.,rťs欞e XTjjw~ZN fr\ (CG񨬆z'ILѢ,ϑWov+[vޢ.أaUz*bl"*IE5L"-E~)vIqV)dsc|3Nyc96J-(\q0K<'8(`ǕEEPCtTQ}==]|V.tvRɬ(T%NH 'RYYbO-]1UV?o4+K,ꪫ Xte]6^{˖-[]w1::j+я~47_|j d'6[= _|?.^wuW_}Q?WEjG0oYΝ;#k|+rrm۶|g[ATW3z$ͻ3ܳ,Ǻ0ۛHB&/A\ĸ$F9RG NMX,+ŞP}^zǗ-_p*h"NfbJDIRCueW┞ؼRNIdKԞyr:Cl\7wМT& x(s%z gi>ʊ,˧rU3L1Ct!c2-I{Fg|oms_KR$:to8h"NfJH2ńE)RR, ŔŰq94Jr,A/qA@ٮt'J.*E^s_5F=/{\|OF4 =Lg Ι/J+ODyޡT1 K"b(#`6RվBw.,QA쑓ݪɉ#=,咿[ۭ$U6Q<>כUłv3Bb27wQ\Iu%EQ`@**)5JS]_00x3$ E>12V,Zq҄󹾂RL,wgRĺ{_Fq2zcAdW* ^|5kȐxQ#EC0]k~S<'|O۞&8cFCѿWV\{o-@!tU=d6:t_k4h(҄hv;̀7_2t E,)aJ)P! AVJ v $|s92o.dY@g|7hYgސ%PG }d S׌z-TX"] mbLn5B1QoL4z0$))BqC',;-} 0@!:L[* ߱Wf} 8ݻ^o{[L^oQ6[Sa]P阎阎9 m+} rMZ8C8Ͻ;N>lP3<3h#)0$qO<?Gp&&p;L@r9zp1F;]3I= C{vW@K=)d!PTw,:Ba4p42 ( ɗ.LF^Pwp2ߍ f4q߶ܖ8P8DbD7jm~ݴP0ۏApf{`Y;t ғSGr$_7a$ IAY4T*:}S3_mٕf֊r#ս@B༭/{maBNcF1xo5ӽWLIؙ2MG`0D!ڬ`?Y@kԻuLv[_}/h3m@3<+NV1$Rasȁw$bp T]'] (V(FN&2y*S.M1$Szj:q@i&iۀI(F@AcЬLriҪSznyao'HСC [w3mc4ȣXhm&bTe+/ 4wVA0λ)oHpA@Q|Ȼ{w}Z  VNLM PpI7AM1$gb]C4Wo4:fhSf[s A=hxHVA10P  ZV`8+qvŲ'(Yil޳nW9E6,) N)8~mn-EdLCutLtL̀lf`$"&AdYţqi7= Anv:Eb3!:܁] #0ܦY|ʫ|){`2hۍc3q8a$T0QH*#5%p EƳ  Ҵ‰H3mw-Ͳ5if.Bmx C0  Hva( l۰4t[&Ѝ -ǐ< " 4_o7 =$(FZG p}4]Df)|>a_^GwyCO["9_{7 a`Hm!_&NS^޻\õ4b4V!o6hȡiZ2DJCax aA +5uSQ }]Qwr 3[:TOCaAt :EEB4m@X=ߍ""vd"4,qO`B5+hbFjj #tR4+}Zȇt+|11n*ɻ- D=ٖg'+AՐhQkמ޾)" 5?P$PH4QAw1[g) t6=sמOon{MIJQ7 $FGiwAOTSz 6@!jO /}'i F: vZ5Lj 'I;vwP'@mVe*0Z,=lSu)76ZuM7C3pJp,v-E9oFe"&^?߻7K&~|3@:q q4 ׼(6(ؾן#S>M,IP՘MLÀ,1Ӟ2sO$}z?R:xp@5 3(q,+_0Zs͐i2z`xJ &Kc0%ȦKH%ha :425WV}T&ݍqP (Dm[cm< q>f IDATo!C(` ]-ȖXx^f>dg;,]6ͱ|ڡXw@5Ѡ/{Ua(L0 ( 9tbg c\NɥT&( rQxb۶ݾc|tcbi|, vg}͛7HanAӴ#9ƌ^n]2$"L[nzzzW###_|q,0{oX0X,Gn3O]R&|:gީV|ˆ)S* }}"NuwcMu'3RlN2DhV$C݃wlqg.\y5T"&ӊ 8U㜘Ky%$H '.SZt1T}=مJ\2SA$YVwRV 8f&MzbVc& /[n9~ٲe< 6,_lh>gh4$IyzNQQcϖlwޭz ',JAw'>#s ϖl}OAiqw8NӴ{!itK)x ͒/\lƔi@BQvi6,-߾zi`}aٓGBgTbGxǣ絵/5p3|(61W>@Èb$0 X6AjJVM .JF.N  +#I9>'+CFb"G #>T!@AD`pN҆Ӂ?f>阎阎9A}}cv41Mz^\PmOA AY{,{/;k>5U Ʀ[9"hlW !=(2ZmqpSzG=ߊ25~mXP=ˆ=ھco @cޚybd&NT̪Y՜F#lE3f !VuwUv-gYD)m }1vFa"f1Ch9Zn`ۻG[THiओNK^xxk{/˗/m^3|r&HZ'gy_~qկ~駟?~J~.]e~}'|O>~tt뮛?Qcϖl/h'"a;W^yߎ ȑyƚ5ksh#mr-?ylvO?a@8 RT0A aTqȡP@CEJ۰ :1> RvtJMgگ] GbBEbT"(ztG\D=8gyg.d q`r4f$=| qPPE'(]byՋ@Y.lݻABT8  A؏HAE]̳uК51_ C:1ٳo!aCcxzeDĐ\Hf bC8Z&m_R9U1udWe .@yhmװ(hȣ!(!U!вa_Cwl=p=$W,^r9<<=, 8mrҬ`@&*$1qOwݗէ3n4l`2.Fmc.NNh:̄а@mOh15Qm[޾J($P8)R7Zs cS $\ X9ɔ{`W]&;mc=644> x3 |,1۶nzW\{7tw}-[$adr˖-wurYU#l6%I`F{wq/| wyt:?Gs~5?[՗'|GO=Ԏ;CC{rܪU]=ARf?v2l9%{~]k<>5YnYsH|j̨+ʨn7mFYaT@+pE$M(p9Ѭ|g|R*lǝڦ+9Fp`B &_k[ñVuzjZ J1^ϧQiͺ "8wt41]uz{.gvި \0(an2 =0[;ߴ6ب١C؎b8m@`(Zk?ɋZcz`[.ɉhlՊ5|Ӧw Y#Bh(,irVsL>쏲Qݬсk )0*uAZ36>*AUvo8Lh#q oes}}߫zI YEG8 #((ˈ0(QPITAdMHH'N02W}s>{ͭJս@@baDPbt5GU0iK}&Y0kp@ҥ6PCiqm[uh{ 8k𩫶TB%F@`DYj3:3'~q/۞aPRڡ:*VCկ>}{=Oeٳgʕ[n}+s'͛npEXbtt4e˖]x`0899y<7 -j&diW^~?y\>}۶8pg~y ;Cu# bT#c a"xց٩bҗM^Uڌ@ Bn 0]I`j"ËDQgX ,cy`fj5[ؠTMo>cEi/}|ulXF180_l-`!|Є$+o`h[owO~o}|eޱMLZS0FwLHuxp3~;]ڪ٣G=lid6;E3hZE?~ۮ p҃If;Ri׏rS2EدOzm3sۧcz]!J{5m5wq}{"UkLۆ #6uygn̥g[MZiMEm#]aギe\Q6 O`~?^Q6t +ā1(\4f("`@HOi !ZkaF$2"cCl")1`D &Cd ti~s߿sڍ־E!jnY p›o{0T*}[z衇 b6Gk4t_\6mڶmۑ;.Zh7Eߐsddcݹss=w䗎Pd2^{;s<7?_k?44􆂼W_}V*#?l7oHt}au?333l\.733Oyw/HWFɥ JDsk~n}2x*]ɯ?~jryÿ?/ D?&Ţ|2 U1>P\:6Cd9B 1*hbep&Vf LXl9RVoXuš% V`*T,3'n^SZT:8<JP8HR䒹DOUV諔Og" $b|tl Qd|,}t陞cw˥6a2Ē"+|GҐP6J Q!N00MsbK./ ,(Vb4Kxڰx?]dV1R5 PG`"d-JR(id( QX)' ES@ ~x0,& e D!HJPa).O?9i|_;x8;턳Wd>ϗ;_]64O_ݻNePGj% *W Bbbaa)߲ܼJJߊLKa:,K1>dh9*i1h}ݺu۶mۿiۺu͛}߸q_5W޽/,?j!]M3=v+|?ko03HW* r6/C@9Th9[$l*ɤ >:X(D)Fi.}Ձp)˦b຾c?tʧ|Su,Y˗ (X<8؟Bb@\|ѢEKD,le'3\fGKB$7\x8=s%9friHyAKtQ'E /.=gzgzo|߽Ra8+.,-̄STXI.2a$-꫞t}a>#@t-. Ņ}B&h,_*H6G#x1SYl_Eq8NCh0pcx ObL1%#8Fq.KY:ٛVxIP8,Rb*]ȅr۟"pGySN$\.wuwqi @QTT+ܬ9m۶+WR%’%Knvu}ߟDK.eddϏD"(VջkvmBa;q ތfy;ott9G馛"aT+Peo޼[o=T=Þ buoQm?J]}\~gyg+?΀6]xWYx KݳăW{zrhP+*caNDȖ$$>ɲDo-%ȓchxѬ)O$r^a@XS8"IFU\V:O{pضȌM> F2L_\rA fx9FLk&d }Ǜcl"N<{;V͠V%tD$Vu]?)W^wzgzgzf=^tܥ~켋v&e6ϸxP3_҂\$ (?نe҇6^݃9v3zDՃَnh>+ĺl>$!aVkZC,V,_`ـZ IDATMWbxG3 I ]EĥF,#"2l(jmSMrݱ 4j)Efz9N:{Zn]Po{?NLB b(>?U,SW$>dM!( voT2],_|=3=3=~0v[Iq1DPloVð9;& Ciw]1Zǐ֨0jS븪N1xB,€w2 3LH q 50]וpf7]d)Ln;`u\mYju$HzbW]v6JDS%!uKt3!4QL !}2]Sls8M(zF; Ofi"I7m>| d3aD ۃaXu>1*C+0x]8>AL/^Dѣ_@`A $)BQp'5S&kA( A;Fw1 !`A&I4-OW[],A63RR|㕗_5LEiIrmt5լ2]aX.`$^wof&o~`OeH"3 {u__zj9=WO?{q0#)VNB$xuY!ͮP82j4-0xdLLϼL6=n@ך-|w,lf5q|ҏHb+\oO!/kؖ!ol`` iٝƌmwĂ\hvt1@<ଥ۶a wMس 쨎:jA\ %I%J=8n*8J1 bcIǬ+IhB§4] 5v]45^f5mZp4_jjV+dPVAKaxl5fEPdˁB$FXq19ԋP6*]1Yv,}YDV-]K, !uLˈLW @]#:8Sk0ЂGV1EIQm>9KZPbiם_A=zEA)*ь0J@mStlŀ~||_Q^y VUPPFm DpK4!/WJuv!B6 9 H&-#zg*[Js$g->PV-OӳuQhj-EhZh(4 ;me5}f1 F(5+sMia C2]de񱃳ڊvPA 7; Ƃ@$2/0f8ĝ_?dt:S0AQ8Fথ۶{51JܖCtMS({?~]DnM:tViY=z3} Xk$ВHtBKgwwꖜ̈́"J gibiaP$ڸf; CR8cD jXZ1t,ᄂH:l E) G;Iؐ;S5X ZSگ9>[ؽ+uWuvC3/,Tc@^$X\5=C¦X.:6MDI@u .=3=3=Tnn*>-Hrd֬c6^I/v}Vcm'0G4G5@rh&ńU,>؜mM@nN|@{ͿZeQmӴE!DndP3 #XO{/D 01:Y Yb5Re6!eQ,XVYy&#œ}XFXM<a&ʒrَ +[H C[0L%\Q# ̮H'aa`¦"2[m #0o q'g_s B, \s590o`nݺ5J$Jn:;;;W8w}KRC~r>c~$I _s5eܣ/ϻb=e^dd䢋.J&8 <b#Cʲ|um׻NRM(W\d(w?]s?ڻjUqB0#d()*K%3i7[l^ppf` Q2œ`"t}G`R"9I.]60O|p/ KkL&% `x}ؾ-x5MgSr1J b`pCqɐ$/)dbd/Z. b5UʧS\(%jd54ܷë.j?s_ j8WX"1Y-=/rC6ޏKh0$>:BRRBd3l,XE/c/. \*`|ZLer\(H H6ԪvIO·_ʢB8JT6<)lQxZsSt2ZpN_<֟ R&]L+-3|FL-ΤV%/W7?t睼iY0 L)"DYdPe`՜<`|KR\fbr?~m&ҥ`>rR:櫋X6\9'ob$'˹H QH%YϖB&\ r[n|ha6NӅl6ʤbb!Y-ǪT? g\4yB\|r8?|YnSZ͖E V=z_/l(&W+}}dUR(Hg3p0MUyDLёl% Iks$WIlb:9Lko{cy̦SBь,x^$L1*37-VEiP8rd)a9RLѡXU*`b@ '}T.,;iվeq1LIX5]^L^|3κJ<> dB!.3& tPh0a锈8 Rxdini_yI2ط܊%LDp0+ո\*eCo9e p}F?NJ I-ncjl6,\G_~я~aÆ2|9hEerΗ㝯7jz|jjQy[a|3 MNN_zVvmȎCO{a߉H"lj" 1ͩ'nWϦv|u@v['1PJeׯPCy@mLX",(8ltrkPT 3{8 W8C5C|ұ[{8 !SRY4goIZ( FYg cTd(׷P tu aݍ8KVYCF*t-՛]!gf<ۉ0;K.d\8o߾6l8}*Ln޼?<3q۶ǿկuYG}\v?oe=>nݺ;_[㝯_W $/Myn[]^Sz]^y7^zwP9H3!p W7&wv ?4&[QI*d›78k}??{Y24ׁF#8 s"Ԧz3;w)ŀIl<誦is$0 IV %]PwLQ<XMnٓSfmG;\Dqwbzg ||ɶ6rbrJ;f=z3#)΁IyXwa'.I£~WY*]36ЮnS !Mq|"s 3e>;Ҝn6;.ѿFqt([j`ᄆ\S5u`H3x kcQۺ^8 p,Nk&l+^TA Hv9O,''im 8Id!0{Yp?iI 0P(7)}bb²_|3̗뮻p-<T T*O|jX,vd?N'.r@0l9zm۶]q7tQƝ/|y-z%xV=?[#122b+}}AH QmDcc, 4Y 6ȺikӮ79enxM#ڲqs6sJP 5;qR4 (#|[aՁڦE.d@B3aBiN eMeLצ|`zKs:Ove]@P4|GHp4ZSE&v֮!ᨆ!v0Cev`U0V&ruKu3=3=39zz0uCtQBo$F vU54;΄ƸfT`:T呤Ц.=O>?tGSy3ɡ(Fnvk= e+fkRZmv،gE8wjbb]ķ-IYxǯxW:ݙr ŹLjhj1}poX 'Z|,# pLGP1Ӂ Gժ @B x>ótM ꊝ]^ ]ezxǀN7 P=Q)2 Q{`Ψuݗ_~nvaoNs}7Ȋ+jږ-[RUW]FC=X'roQ]vEѹ͉z?9m{_t)`q9_ww\G/;_(+DbOMM-Zhjjj?h4;*yY^Ϸ;_y|4k_ڶm&&&e]v5LMO1b5lsCí̳\vi00o8jJ>!GFF>яL r`wq @c(Sf3ː nB0(1+Hy2:]V F;6 e,3<00A"$eQ#9}0F)bqF1z[XK5ۨci3>}mLLfݲu2N!1GmY.@-3YղkJ0t#Jڡ1̵a?c?GL<Yei'iT-{)g1@H LCh6c,'O"*!!-F`:7[gf뭦ct=O'FwMOQ>#" r0;PLt|\% ;29{=SoF$xĤvM V? > Cw;Y}܆hMmv䎋-ھ}|ѢEoq79cwsͽi9ʸ/ϻ1o8zÎs/߭s\}{7-G\Ϸ{~k?_=ig/ƍA}2Btioi'&W$Hd˾+\T/]CI)RNJj5Jp\")? R(&ƪL< 'LIZ2P.7O%@$VeL9 _r"pf88b" "Xb|&r|I@TİH4% \PFwq_da!yY9:=Pɤ Ӌ+)V̰@%p)RxDBGA3=3=3{ ^'w4Z,ZRJ.(0 Gxi HXH' h_(H4_.VCRsb61p&b") rXX ) rz~K+Oƪ; IDAT(P2b}ryњQ)+C/d ןI S !T$,d&Ct!KFI&(qY)cŌLFc %d80d ұe1r$"y6(hRb`"!љxŦO~{Nb4OE1E2."Dt*Ed0}ݺu۶mۿiۺu͛}߸q(f2jΕ+C*Err1 A9-^ja$)MFcD, 9Y)8<ܿ0䊥+OZ|캾7ṛbNfl"ʤ\%)&H,%%%N]rCN|1S +W~P\VRVd&[6(gl0YN3$L\ ,#(Ȗ9!aFPѸb@K`$ &"1E?¨<)"I\/رNRtWz=sr۶m+W(J%K~?99y' %\2555DPVwuל wqɑΗstܣ/ϻ4eobaX*+Eywo޼[o=~Zc<_=cCw'25)`IHf ٪zíF6 piW5 8c0/B9(-Pr3,eVMħ[mi4 `vXv$]`b YYn*w?wy}gzgzgz0J$i'%dֽ k{ ,"P PZ-߷lqq)*c;E@-υ0PRq `x$ ldz\nṳi [:d.IqF8j`c>dU9YW7 GA1r-AZj0Hk,@CqQ ۨM9}M2fd[nG"XRc^w`R}CϾ8uA] ŽAv˱ Hb@Q4-p}G<)f<ҩ") $l'$J .qk=zrٔZF?&Cڴ,.d5v2-r\6hy.Q,5;m젨cC+6xmμ^7*'xC`fwn"$֭7 aX Cwu;*{jhcc5TZЛ ᶯ<k!MCs?@pqM5]e a}v:] Epv ``$<8TGs陞#-Bwx=PMjp&\$c/ @Hy Jy$p)()e ]TsytE#y[1D:I$HRpѱI!)Ꮬdiw_o6H%߳ײT[*Lq!iD 0і'Ya*EQ3S5&[ tEѕ 'bkMH0Rx[h>4o"3=3=3Ma\&t8Zm%pD~|QsZz]e&^ Ȃ==6NFq !;N]_D5 `LVk-/0{DY4][k!Inf)Y|SYxݗh΄!4< 4<G`<>p[F9zlv",yĎkY ̮{3R Ofb}|1 0ZMD.cCuxנ Reǟzz^9۪K 4I8@=zKNy86!^؊jO8y.`F7~Yt9j*-6$ˀ} ` imctahFq-x늝 c{o/I]z׾]]U00 (8\A!xQ( F`p޻k_罓y?{ΧOt=47lp7Gjy^uۡ0D$ fc) {5»&!Ţ&bTxi_DoIwvc>Y[uqHpdrſ?d#0|bNtMMߜCA Сن9 3/۟;&\ Dz-\FM;$q8 3%EA_>Nc.6: 5q7,E{m6&9Lkq5@`C@R9ˇΑ}6<ӟК^tD"ւ h$'WO>}a4ˆi#RK7HC@Wұ?;@A9Y=hqQ] bwjam-_p[עısFݠ, Xg G]^[poL8!w隮z!.T;w`K%07_Z)"%ooo3K4 ~+.ZۢcZ6 -Yf6:#\7mπ, 4ںqC )xvj jt`eXHG#\p8Jag9>yy[|@:n֛ؖ%)-\=P6\xu)caC"k Invx3Z9(Iv滽vb@N)vm: DžZH*I(KY٨x<>7,L|{$h9c0N " >Jdf~;}q.j[|Ȕc8bYZݱ\%ȐmBBr``HдU" ݅:L<-xô)6 C,=n# aX c8a=61kpT3pcG'WNOA-#kV9TE@c6=3y&z 8[s3/*Opt:'_&oot0+6tV p]c!nYZ$RA({1 rZczq xv8ؾB 8nf4>ٔavxǘmgun4 SX%F䁶N)&_nIR ǎ-s0 ІʼH8HDqȢI Bݴ#K14GxAl(l{秧Z PJW-բjy+s qt(EcG Ai@0öqa± EF'eߧO>4v)IĚCDldjj,dI:6o;(2LcvQ5{ݞm#Zm$Xl Đ} ^w= &$)Ҵ6ʓbH\##8uӞv_zi4 S JHdz>vGo3>tQ߿9?~BmLΫr_>̑F]p,61$].V|7mǟ/x>}"!nE1% 6xi(ا8)FS9A/2t*iB.fE$\K,1E'`P@Lp 6 h|onCw|)9k0[Q S}6b5BRCxfvԺ=3p!mYTmpm:U2`$ hH8c0xZm!N349׃-Žs' l~qjjX˚: R|ZbN6-str@P}/r$N`w922² ]v~3|ɫ*0 SVo6MӖf?8eI,Zm6EQPe۶mZmWGaCCCַ[*0 +JwC8ry>裗^z(4M vm?EQr]zѣG]̮>sզpH"2-- hꨜ1I9QJ(Ŕs}m>MdW\qŵ^g˲>y ֯_OOO۶}oK.9q;<ι瞻})˲o~Apȑt:}=;v0'|`ǎ(޽{Or^\pԧNQwqA4wܹT~6to[n袋.W?_/ H6g)QJbOWbTZQd&400&09 |60;<0 ,T'*L %JZ<+ Dc!qi'}ڀЭ]TM})40XT#AGX`߭-T};`8aQ4UX`a`#H4ig9)눣洃^# V"MD!h^~sKb0 (k:bɤvb8H2gM "<0`>5Va(L_o}뎯~:W|<7}7}79 {Ɂ9n>rě9rzk/..'%\6`"<>̑(.& fqF`QR0@W ̘,6uDw( q35W%z8T|ޞ z N[_p,^86cjlvn5<4 ;V0!PF$fζBd-"x $ LBYҁbBp012zlXiD AXG0 Q2nΛ^k!1tTSL J3ߝ7^GS=> xչp]6mڴ|-3Tj˖-o$7zӎLOO#xG7|{s9q>y?ذa~֭=)\.˟x7twߍ |=?i&"CZj~6to<ȪUrʕ+yW+lxɡ۳l9UndԊCF87р 68u "p-r`6 !a1AP*,X G#3=5P 'B¡.hVkj.D}Sh7τPjwZ ,jtѫka8%pۋ[+/M74+.}7}7}s:㴻 w-&PZ 5}x 4D9=_뼼[t#5^W@ IDAT̼R^P pmkzh6jC0ck(e`ְ"H'#], p-O3E]IPۦuvO:)])޲Hc /@yhIJ:k b|Btv8TZ6BchR,2L$t[- !OP a3 Lh\!P z&j,Su,&eB4'8xXVo@AEB_k_ګNٜm{׮]}{?q|3yꩧE0LQzӟ4z=|n+I۷o w:Scǎ}'OQFq%z!E  R>䂠"Jb4WA), AvT'͆n]ƾ雾雾9 5.HA\^Ks4+ҌO㲐zVuĢJ&6Z>Zhx"Huf-I'QM /:`dƥ}p0HACҘ<@5fg5BB]w 0ZD<5k0>ԋ~绿Z:VP^ך]1rQ-P軆@ P(O] m;P岋x!wZ!QƌUkuy>;eZybaԧ>裏Q-J'~7(#o޼yǎ'8>>|_C<ݻww[i9zhƍs|^/ĭzUWbqz.GFF^anӭ׿b6A0-..׿>vrF֔+dJ!)sن͊O)Ma15PMWFG8tX6+҃y9#)GRR$JiHzD DDNrcP">NǣB&''ҕL(])TB* #TZ I!%'B0Ǥ1x|_[Ϻ@P$<8+W:# $T!(i1;>4~uW% Hs#, Lü>gBёLa9GY "<q<q>PRPdKI JĒ ^#?3O>|`̌&TeV䇔lF$xQL m>-GAlذaǎG,۶m۲eK{>l6-ڷos9e˖'NGӴgyf7|ss΍7޸^ǎ7nCR=355e3G8H!"Sld8>+\uɉq6b&?T(DS THqt2Igh$H\4_MKbx4}_*SEJAh"vUÕ|&ZY?>4ˮ_rf%[ڴzJ $Te9#Q* e3wdyVF֬+pf@I)!|r\oo8vGH"/|<գݥ1*2-DPV"0R8$e.UrMT&!+(XT)R)OJ2@ l|x"1Y)EQ b_rp|x&U"Vo~/#t*)%xuy|E( 2E*RD,, 9$H4+ ?;o)) -P2!HcTAc2!UdʙV[$ĒH$P(-%*w>sn833q.ьec\u,UNcÕja8ǔGBm>MD?_A07Ҥ vTP>R0ۿa>ٳaB01ԯCl\¬H<4df[*RpXdpWWGtG<9mt˶\lJÄZtuI1ntڽe$)np @602P>W\>կ;m]XRzYEḠ7߻Q=>}y]@Ze`$ /m&dnq߸5!`N`x27"Cbc8oۅ`Avw)$6@+*_PAf+-gV#aF$D-@7u"45^1[5LNTC R{Ԯ-m1fE$mHŬ =?s`qղ|ańG@M PQijE:.}7}7}s"0PeY ۲ SY>Z[0hR@=J` G%g^i']7kcO<`bqؔHCLMy%PWHʺi(lȋ ivIqi^>`T} =L{F@};0 GcC_X44J/m3!2,PXs-G\`x:7tl]z6G1n.A0M&y N'WO>}@oJu-z6E$M/& YASQ\8vSU]gY!6n84ሣ/?s;^$)Fӛvmw0 kuIħ1Ga.,81L: uhI *VTap =UwA\ Hߟuղ]φNS988caU@s %unWBۀ} ǫs]oo2Hu5 Y0,Y(BX>v}JJlV]Co(c8Ƈ{Ù&A9$C\8Ԥ՚Q=w5Zq4=|zmks4J$EE @|z`6Th6yhT5`E(hTө8+hâ[>L!iapqC5%Pl !Ͷ`Dx2Z΄a6u]ouΩ``p@ht>@Po4(ovc7p˲^}ζ8kw!")2!ҡB4~Gm2;$ 6QB,JOYAkg:VGf0ֶ!Ep fh=صI)P 1(I"7v<2߲Vo @#=v0M@3r:ģJ &!FWk/#EQp$A#Iܩ8hb !P4 0D~:'_&oot0Weοh/5.rlehHaBK*J'2Qbf B z2);]d12 c$@"ݞv[Ӝj~3so;7[k0_kX{֌6] Q6Hm J[οq[y':_:sõ0' Eayv(mlmC"q$|˥zOM>}Ohg]Mx}d_2 !k0837]XAV ͞c%G0}O?A@PTAZ>+ `$rJQ,8,0Թ^@TMkv]ǯ5 b(Qf3p4lF6,CpS3<Ao_[_ӧì邎a|ˇ_ӧ@o}֗8H8p(gMkVi.Oh9-3g2)e`B BX h[s0+0({R&fE(j{)',15F!~*'A 0PpTk NSW^xHBt @ lDE&(a>yɂ<9! EMU2ާO>2>/bgvUd#Blq]M 0lȳa,`LӼ;GFFX.~O>yUWE"amݦi <%_նmۦ( Al۶V-ѣ]w]"0lhh[֒{KaR;y].G}K/E顡nMWs逧s|$r络s%;&"/8^.?q{ozdTɗ+b5 0\,+r2³ Y9/fJ5W('q1D.++coАRF+JdB,f3O'$K"St4"r4iY\>ƭV"hZ)W+JvzbHntB!_ȗ\a͛ X~?==mѣGoK.ӷl{۷o,kjjj{nGIsϱc x'? vء(c=v_RS;\֭򗿼#G[o>_qk}wK/ݿa/͛j~b+2|nX11D8ZĠVTW颬 Fr:I2Qyp6Öh< EhN,'J$ddT`Z:τ8. L#\,<@ +&'BRtBL و0W֗Y^D>4S)9fA2t8Y(r?Ovgڰ3.yO\wtTMMqޙr|&SC!AW'ϐ#L)'/|a`j`\I %[PP tMœŁr66v˵04>r )<X&16C\RbP \U̍3c[t^ 'r9PjwEG?Đ&DBQ.!qLrr\H(Y9U(ƙ^T\uWˣ/mZ5 *aND+}J$r"+XAdR6#RY T *2br)p,g'K d2r4q&'7li Il< lq[uMvfb&k殻:9~ƍo6m}Z.%:I!S|^|N77߼vD"ׯՊ>eخXt@ Kw;M09\oH(th8 #P-xn6H# \~ suuiL(YT>l8ۚj]0?57%$C9 9o[ݶb3   4#lj7 T"#dn*)߽2a,MR;=uY+G'R:{kޯg(GNMMߜf]^{mӳ1ʅ,no0ڐ@X,֖-[H|{߻zj|]\ם;gff~.7q zFoK/kFnI充Vk_Z<ꩧr+Eqx|isvvvddhaNַG\;|?7|s='IȲk.YVv>@݃7{o&WY}ߗӝ$d!"Ȏ QQGATň2:,Q 0.l!t{wUg_BGp"WSOB|Ͳ0791^x~0Y:Лx}ߴjU= FY͆azCkC$5iV[?;gt;vBkS3 }ŧ=V*EvCav1#AHNN C^fWGzkf[׬ ٍ=e,hnNo>/`a-R"R϶`D EK1UWF89`+P:zӋ<Pf?u zM5}vMtMt`hNHaY{:cH{ObGO0@F$I8()ӻl s@4hNICcn, dXsD߳)StA޴GvUU]tpjV2C`,PQ O)&plvg/ZyfۥI K&W:)Dh^/=cN>@&>gHc5S'AP$*Jڴ.d4icaS٨e{>O{A@DQ4O ̎ccce˟/}_[o}g8axgw ̡[MYشi4#ܲeg>o7qy;yom~llK.뮻>{:/2MW_?~oqmYIMI]?=+)F#D@ R0)O+8 ` Y U'sp5}[UZ/lۦyYG FjZv,3"wpRHepWoNpmɀ^ReRÁ ԇh倮m0p_T֞Ld`ᨨζ[U\kRKV8b "(grtUwMtMtAhRDX l"FYt̄ `&:F.Pmy5uh%LY߹?;Xˆ1u` L+u4 ׫cz?uW\ ;;YèMlٽKClvX8!0N{0Rg,]m NL4w C;%RIu-h)2Bc^ qނEC-w )Y!λdEE )=]i\Nطse ^sf@ȩNg*, 8ky;=ܳ{?,kΝ/ްa6$iݺu/^ E-Zhxx4 ^x(2>>~UUnVfffx;-mW]uՕW^ CrΖgls|#'/_#[V6=x?s֯_ @w mQ RݯtF.2V93:r:> ϋcjNc6:z˵L0Zs(Vٚ" M&{"5~|}{kߨ}n5JؾwG?}'Z}ª3ac$ 3TlS ֚fہm5gX$pxT  r0F! ,n1"Ua0  r-?=|o|ᇁ c]{DðD"qu|5klٲ nzSO=5886CCCK.ݾ}_ yrΖ^yV9ȥ㡌xe߹|qs9H1&bQ=T6f P4)yξޥH|e!ٓ+tݖkؿ߲;7?س7~.]5]5]_ &rH<xKPJ2 2 !`)۫d6d<3'Vu~g=o~VL/X&"DYbTEs=t,SX8)l NΕ \BELo_&^ɲ?yL,%)AX !BDaD$X4XHD:0<TzzT$ $\wђ".Y]p|ԛD$$=K ezeRj8JqM%T9)O_zu1( b`0I d7,O$3j ̨r}% 2^ c{>-ʕ+lٲw^4ٳaÆuz￿Zcǎ.lŊGhܺuyFte˖}}Ŋ7n13`Isr.ʢ|o h<+XBT fQNLB%1)?~ͷJ0 BĬ3!.`0ye\.6M_Kr_.r\*%/&{s?6))ŕ@D<J3R:&bз(.?{g~v?zm~n{ĵ N,XٽXtMto|߱%!$< )sz2sȉ jDN'D|(]Fcp<«p49:i`psX3~8ӣJ,՞X'7PsL SŒ,*l /FX?{LiIg`ϲXϗp1.B2ܓI$( X$@R@2*xBa Nٰ$GPSr  Y*{r)ˉl_ye;=:a響?xߣ\.,1ِs狹 3lP"#4L#تyi2~9@)FsP>!iOd3\0 l)"-)Tbr($X%*h7l~}Sy'I2_uUr˖-/&Io޼u]/h4aX4K'&&n244tAAzzznf?rqroEV{K䜳y_. K0p~q'X{xtD [S#(V&F̌A>v^wvoya6@iA )=S!gJA$An;&ˈ940as4Me>Мiz *ӕd0PVw,܆NFvrntzZ -%f@ijm`FQ8R`G'Y;p1 mCfCI !td/A4<u ¥C9mkkksT9 (s{ WźV[lkc;ut1 D=Lj`Wx׆:eu?7 Q/W@\4S`4ӌH9R3B4ŒNݨ%=_sv/m߿ ٖS:_Eps) b8KbJ.ٴaE֝&E1@ K'Xm T&pB057J0bO_u 1yB*ßihjq=yFDܺz>MO3aԤpkd]oÎii&\m9D,жܚ.n]t`<+xFl5j |g^ >ԶID \LwhVuHyy1W"ɰSe ?&Ig4f#6'Lէzd9 St`TI?GsfZNfCcOyi1g?c3M_hfi2 mE%Z .M 1tpCwچ㹝ZS5íI@k>YV *@l&%ZKdHc1`Un^K.]ީ45bx4,*{}0b rZAH&Z.;6ɽ#.r]=S/9Xq޾끇ݨ (D4LF  uOMkkv4˲!qmɉ1cyt-Tk6nqty+Q8k!F)]tlYm݅2@0Y Kj0¤B~u=5:O&J45Cat܎g6:ud(H⨶6S=Uf* (RT3}_tÁW #MO&8V4  BkW) ᛦ'IQk5htLt곮e DU%4ۧ7Mctp2ցAcTNL#*hTax8;PNII& VLhp+.o|¥K.=eV0n4't`8w!2'x}FjP%Qw$ ܅MP uLRD82nP8X~cu+&N#@iٺeNM e%h_<]e3Q=M IDATӱToK1<ٰ]`wd7_;<Ò$Y9:?_5K MH( xktҥKcc(P$mufǑx(ٰ٘8jPvǑFOJlU 8uC!֬îTf}1%xFp֮8!ӊLȁTOO=E0^dT&242xK0X}t!t-! i+BtF 6mbE$Mf103Zk/QhC,T םCC~G'lG:pP `mXȪAȺU˞xr+a 8< v0A ͕#`(^K.] h<HUwpo~o\Д O֧j1mTetN146hNםqtzlΟ^a)Ȫ 0tXhȁ AnͶQo9aQf~! %-<;xZ>B3,膶sT<àڱiѝ\szL6 FPU<싙kkh0 $Q|^eujl1U{:@ ـdVX!mKbXq sID=P V)CAͶ!))Z0:&& @Pm(<Žөj%'Dv=`mftf\oMmfnmnGXMCeP7V!QA@lMφp4RQQ%3o`=T`|m }ӟyg·O=L8x)UB=ȴ L`B\zm" \79i>߽{eV.]t_,ӲR2`]kQxUW#Ns&dp+H!p("Qi8/t`D0MLNbXyG/ L`MPRU%Gƴݶ* 3}U`z_o Ͼt3Qi0!ا>>)qVhwu' r#(jmFpA-q=1,U?ʾkkkބȒ$(,mǧk 5cH4mkdaFB Ӹ \|'`v4jgZHBֶMOupݙt\$nDC#pϱ fvfLmiL: 9@q[v]i "1X8.)d2=6֘q;b"0C7MP ǁ_o=?Fbr '}AB聡W9ms`Dvq+S:_yNXttd%[z6ZU gHo@D v=>VA``0믿eYA>g9TUe_j9ƖqOOOoذ!7l0==}}]|őHðr|=7oG-?~iHt\Wi[!3X*LdR&\i B/+7xζo,YMʉD:X)JP]5]5 cKg]/'t1T9¡@$Oj&K%KR1 d5J$Q5-8aEbYkcxXr$}Ly7TYUQ.&JT(糹DA Q'ccB4FTd|HJN|H<&Ǖ3gQ() xa |AOd\I)BC$R5x'=@*aN96Lz[䓱X;9[%KqGr޽^z驧rΖgl}v[nu~m^m=Ow׮]H_ݻ x饗_ @LJ\r~67z7NH2%@L#=p$-GS=|K!YVIieeDYUA6JL 8_h~$KloiAEGc3\S-~Χ>}g4].X7Ç8K+gryN{|SV?cSW,hɼc{ Eb"ΗJk?=>&d "\>Ϥc+E)$ժVAk|Ct^?V1 \p 7>~ժU?=뮻?rh$rΖ6w<===mKyz-Gz?o}[o;9n6uĜjLOOQőWkm:m$;^fӿkș> vM歠L;L3$( @28Om*J!?)>܄mݲO^&!v˛͝{'_|. )b( Zg 9oۍvt?3=>6>e+;LO0˷pC(1v@A $kk < g۶Z2Ά$6sȨI6eI@1ԣ4qk7]911 qTk/Us\gж5fm۾xHt\6peURyikz Ktؾ~>Ea:P6 0: fv\DRZnWO8vIJ&vJf,nD<:ko_]Jށ i5ȁb!B)I8"ǧ5Bl C~D 7G8/ҭ[ٳsqX,nݺx<3ꑑ۶GFF3<{>E^x+Vzjժ_|};9߮\ϖs<w窫;Oy9Gzx}'i L&/|a@82yjeL Ǯ aN)ɑl.<7dCd4yLN+*2b>ȇNժ@5JTo؁c|?WGiu~{WtZ߲l2&3y`g~{7+oK˹x89u͒\rE6 ,$ 6l~W_=00ρt:7 Rizz}țny9ۼfGzxM5 ׯWt]ߵk駟~pwD+48 ڵܦ8#nuvX޶i_# Wj*f f1_W-'儚&gJB$Nmp$?4YLl0t?f,M;.B,2*B3$H7%h 1b:0aW.\4}GNXiV^}CO$A2.NMh  @pw5׼⋝N{ٽ{[sŋoذxHnݺ_袋-Z4<wg}Cqydt\Af&pP\w зd9i‚m=ZsRAـ 0L5z c)Pcxmo]5]5]FĐe5âi*J8Q HeDP]~ tGdv&)p@ 1 k>@BHLM0`0Xs>Y: (@"xK;kxN(&hE%(h)ҁ@4BnaNBhupH a`d;3cfJ|9 m(W:ʏ_Q4 0@KO(( jfW_FLӝaD@iL;XD0`W0<00p-Sy@qP 4ˊJ4ER,Æzũr2*© BJp(8>Fbl\edIJ%e!>tp4]5]5]5ob3TZ/ 2|>ʄ"}sZFdP,DzEb.ljRO, Gs/3Y/H%x$ 5放ƻ֜{r Ecd:T`)Ȅ3l>+e IZb}"WH4U*-:~ҵ\ tV-Z5U\pp}ʕ[lٻwi{ٰaúu|_z_VMܱce]bŊ#oݺubŊ7ƍWZP,馛o?I'e˖d2OZ[y_yw |󼷳f9[m߾}{(jovwk6v\'?YfͶm 8x'>#wq"=}dq\З/Ȝ &p<40P_J%p&dp1̥ h80rd*GL\IEHEbdX(|(pIMj)R  OI\V`cDQLR`N%| ֞攕X;vE~/nw? ͔Fb%HH<ٓ)#N CYF4U\*,`1[DϷtҥK_:ySB ) K5Z̔±$R|"ʗzV-eb+>-}hXȗl4{bY_>C_Nhw^4I>e4dWdU8fцH%-&Ù(:.yIʇ@@REG;6@eL,^ iS/S>}?OX E PrqsM3Rռ\^ؓK&rgbR@zN5m?O9'}_q'[o]~jD,$D<%:$ q6HL+@ #ED7l~EP}Sy'I2_uU[lYx1I<ϟ?ͮ?>>~GQ â襗^:11qp?? "swv[6EQ4~[w[Qf9g~oY#nݺo['ϻZϿnَko\.h<g>ngLwikW:Zez@0(WT,Me ) 0Q%@`qP0j"ƀ dkgǯ7ofYvzxմ<ͣhXBh)&GHa:ldRq-0a8a{_OMQq",7?Ð9Z)ھ?$Lٲ[30n$OLFZar=;> IDAT[Z6j?9oy uҥKԯf ׯOp!mZTm9їں3li^cA pQIP?/;끟@u."gZ$("h_k LUs& BVZO[UC)EXa<qE<t2b~)o}&32bw W+ 2Z 7uORFk<KZ:|Z0\|Rk~)kJ{dD_ׇ {t= 2aTa1@ǁ HiϺ;.?β]t;MX&95fX,P]dnYð,f yi >xL*\mOhN l&57oٲ aB$1} 4uk>vk*!난DKtJ~dTeut3'Ya ȡɑ];Flם16NMZ91ah656.Iq|O pj[1N%mt8]ٿnJ.]tyxi#Q:0BV.:xxq` f癗oK oD0A@j jPpWwZ(@AffJ&3{\a[-تgA>5jkt ij;=4X_>tϏ]34n(@Y0[9LSbDqq74KcDG8Xng?>9 Iƍ銏[ޛUgyy3OHAԂ1TXJq}^V O,mEb-mXDG$$995G'$D'uu}w眵{^UGnlH qkۗ`Iَ"(aBbnAtܧO>h9vNnv8Ql7>p a{Z=;p|߲ $IlgI !I: EqzDB3{-QZ  S ER(H!EXRkUu(9ZmI D SqZ 8Q96Y ˜$xv{'sv ME3ک֯}C$i鎦O>} ڢ9[M ,UBղz@ 2O'QgmCI"RZ$38(<!Liڎ_w^5 7j8iK$1IQ tvٞ CӶ( m`g('<BB˦V`곏hiG@p4,ۀPb Q "a V7} ǁq0T﹞,X~$ `1,aAhL 6U10Hq[~󽿻/o>itpbhX,8g /|_ی5vM5+򻭶$ sZǵ8 S[)]o$b@avx٣I7۔TaxznMtH29N4{q6v/ ^fl};qћwܸc5KӍo<$tgܖ aRFZ$CC۳pߊC!uT iCyH$8~x*l$CS8v߹?s;gsq[/sƢ'D`Q=hF@,pqpu:.GTD2:.fY  CW4AScW^D>n+ =(By":^!  Nxd|8rǎ!>gy> ݞ^CYEC$lM]#+b(lZ4'IcpHࠞ©m 9Z(ES4uv'HfA=61w阚m,6e^v˂K0 F 鎹O>}ňPm$w%ZҘC]ۀV@AVqy.ͥ%&+"P{&CE(زw|#PQ 1g"8KЊ<\otM2  q:KUeL^0eǎ,x?}h `,d+k_- pͥcحYƧt9fzDT6 M-p^@k@_r W^J,Of $!`?z~wI=_o7pF=vlVoV3&EV*3 0 Ës%2x=94/Z'!ϢI&h-ۑ8"z$YZ01쐇B4u U)rwzƤlXN~p҄IR-qg{P!jAF#*F{j=kEY." \6Y \6hm[ i !bvc=7A(&gHt,j6HI\ daxsӧO79&[;tdO41mFH4۪Γka( lKmϞ_٠ۘKIz!sH"jw"p4!5GZx X7X 6|h"˓H*:D:j$qxi}Qߨ|V]3?vx"R.q(84l9RP-/B\*Q'МIni7L;+Ә>}^LML=mf C( A&TYřG2v{~U&^+,9& )g.5v罘&05V˯vᯟ޾Ç.~A9k,Z$iSS ]k bxfs=cQ ~OR>g4Su.ͦSʼnqLxmSb>4nbyHi@B@iGXRݞm۶P(jZb*Xa黯-r=_7~(#?ܑ 4P9 mOWcfϩz% xOsH eZOw}PIRjdֺhYfBpJ!8X]2#<7ךK'"8Z J$'٘;aNشٲJ[_=xz N+ (RUUe^B"54Xcb q0@D1?|/d"o|Nvn7u߳3K4*Ft6a{h52띎[Yo4eCCI/?+韴:|kߺZS4h^t!bZfSk 4/ՏKe"jHo3bw1 A8rOf4KЃo|y#.KAB(A|C"kם4ͱ,؃4/ z]I4)%zp,$k$V!  BH,4H*Jg47^8^)otͪ5<+ܞ}"0( *P X$AtLhu 8 w]_D24бᓘ 0 `:>>.,˗]vك>xǮh4?q0/^rjk׮L&Ct&ٵkWZ=#G\{d$ɑ{績{JBdR뮻N^.s9?E_i]]i^ڹsg:&Irtt;W"}' QwD]{*2#h>$eˬ9\\+9! ENS1NeIJRbZ͍NnȦlNG9Ͽljy@:?I˃k?Om2KOJx:BIhydMqyY>:^(M?s͕ץ#HfHI҅Df\NE㹼.g5Vxe 3E26=XIt=ѓJ64=\,R1%jt.3UI&Xat T%/M>R zv}nm;z<ђVL'\~xyb$Z˙x6E:+lJ$@(ئ˯w~Be_sν{:Sm۶A7o|w̸{ȑ믿/~qL/ܯܭ[p ӎLOOp [n>|8qG,۾};{d2?py衇+?q9ͿƟ.}u-׷ֻҼ8L&o喃ڶO_r%0J?+_…^xw?JZ.S פԌ.lF+FJŖD4 R\Jd<.'G#z6Y.YN*d'dNq2Jx^twIt`K pa-7%㩲./y''F֌[ v{x#~ywB/ld8<96ȼEUO(JLbq@hB|c^^`p`K*9bFc\)+iI!eE%3ျ^=oy٧g5=aP9Kde|(+ ь fcJt0ʹ5I]蒔Je!i~ N梼h_B|\nWZ ^ҷֻҼn_n ڟߥy'{z_/ru-敏 4L*:M(R6B 4\a0LX,Z'2Bd K ,m^=ms a:jK lEbp4BLM&~ǶQyNϼS q1Զ*I87l2Þs9\Xn}@UPٳ:`3P,nwmH7?;y;W9Jb}x~3]va7ZNϋGtg8|յ\$_9Y>D9A<qje 钤8@B0m4& $qb;8)Ⱥz2udiY!@DGo2Q (υ]:Nת ls "0 < t,lidQozm!)H,ѵk[?xeY;v`99o}{'vE$Hj5]ƮK/p5h8-..vmf_z"x KSeϞ=Dùzܺ%r/sK_i]m4x<}_W^y73 W]?>>~wرd{ڟ׋\]\| :> !ʊ\c@q; V G:n8 6\"mcX`(VxTɣTI9!Uꠦ :CY&@'LYCٶOP(vMgo]|sP@,Q[鱒ZڰnxE5fS)!efYZlKՃmpU]ByJ  B8e,:awfra/\fy>۬yОaoONNWetti'@ R'!s]g>p7r-/~?x&!I2<_ZAҋt:n@$iۯay\nWZrޕUo}[V?޽{oSWڟS?K_RX<~rbѓ?rSeZ.SCm r/M43ҜZ$y $3IQV'X0:~ݓQ9$*$:ӭ ?oMLn B. 8B{Qe:8sRsuza}^w@>С$H 6 D")Q8"pyUS J)IJ^@y3BVt!_h4 Ȧҙlrz<5b8Ʋ " t IDAT!c}Sƕ\Fz = :$$Uż.r4*4`_}]?ٶk(n~ LEbthTXm4b%o=lx m$.K];E ,^!)|$?/I6 xsd^ f⬳7m\ٺ v1}q1 ;X'R|}^{AaO|"͒$f?O۶m{OzGN<|ᇧ^/%r/sK_i]˱zWKF[W?~W_}<)﷗\HJ.<{lHl01,J'@%=+7Q1Sh.xځaJ0\TgT4>RN֬=sλn.ݶ.gnX1r65Zn\99Q,_{V0RZ#/{YD(Q)Ƴhg<]I$rlt*=ы#cSo8 /k׮;v@nz}5 qumٲ1G;m0|͛7tM-[\Gu]ѣ_y!mx_g:pϞ=xligru-X1-)Y1E,K,r)QNzr,?!N Ja0?8X*MWZv.Xa ?֙nۖIƣLnt|9\zY,7D>GFSR:?Q7lh5rqpRxQxWGT5|ZKAY6PTb`r,58xӼSnt>}ӉxI&' TnC{7Ty7\uN9W,M L^I)j$&EZblbm>XnPnRU I-]H$<_ >sZֵ\Nޕ}\.d>zSEO?+w/6/* { \E9@9Ch 1(ħ K-O41K`b,dIBju\ѡD|9'V&6_Oq]=1hոoz#K.{d38q°]Ms,sWmrեz qU25]7 Pacȯݭ#\q9۬Œ1 /գ|t$aw:&E郋 !#=JX?ɗ@ӧ{9Mo 0{$#V-q n'* ;/1Zu3D1Yv׏?7}=cavݘe"b̷AhIi,JFqp4c0px % HLxcA v{~c.;~:( Ԃ:Act Rv) {qy珓2b,iUmϟ_g@\N@Uji-@H6svmvwӧN5Ūx,s2ɡnXi7bm:G=!@7$!Qy]P(OYޅ=χTNZ.T7qv{}i ڶ^bFѵ^?Nc4.nYX1 ,)bn"㸚P~KI 4Cc=j|CӧO>QjR;mm6,-4Q{̑lt6JP-.<@4< 4=bO`CD=kiyl>מgUt!$kpFF)ATw؞Zu&cAaW窅XiVh XT`b[-3$'U~c՛4"4Ϻu?9^M<~=^_c١j@jڵL:VNx-! % :6>q` 3![EFd{o?= ep1jwt q"Ь5?ҧO>ԳP9Z4]oP"* :^kr 7mIƤr%IV:nhJ 7Cu8?ĢQC{I`d(EMPIb[3J؈LAV ; gf>Oz*0qsL[(⧾۲ThUC#<H,ۆaљ9IP0$6egC dxcdә'mW7dJ>}y檢$pi\"YIڨwMk)].baRn <0)Yr*us],h4]5j iB_1i٧>pn\igyj0"=sV`EPF@}/~gh@o,5gE!!'s3o"TYB&pE B 9DhVZv5P!EE]m0 860ii) J_X8 t[MltYPG%vɷymW`J5 ]-1ݞ/I\'0\MQZBqC!raev 0-c[>sNPӧk%F5oqɞ#rXhzMN6dCHFJO O] I]@{OMD(2BDbmz$@#t)lb_lNoJaD9s璀8 3kT6$1AqP(%3Vfz s;.0@1Z'0G*)ɡya%0 \N;jT6H H;>OQ8tH(dhڍtRF:K6&1 ]e?/ 5?qڶH=: }`Z>E}hf{PR[3z 51f0z4fqX1@eAc'P) Tc)46<!Ԙh JfShP LeC } #J%e&ʲ">ѽPO>}~pAײ<㱌K"z mDʁDu(iB_=eIhZh3hE\!!IPQ(n 1&"zǶY 2[{'(o*)a,(K mq̄A`8ÈmWkFB %DXE"%DiDv eEHf=3=ݡӧOJ@}IPHfQ5|vD?:Dip9և?24׆IAq)4͵%DMVňj {"vҶ#@iv,Z͚oQ'qZʸ4&ɩe/z`Wϐ$n2A"zF=lT̼TQյ`Bp#D16zm P&d)4\Kiu1 uq"%HYsV. 8GѦ SO>2-Ĵ$5*Ʋ8+z # ;F/pdBkDU<"$*3pd4J]%1>z:NouC* )pL!^o{]Q(n org:[$0 RТBpɠݴ 3}BNj|<4|ҁk'c"A۵^ 7 `0qy*J!z}lمSYV9Ow(}終pIgl:c $K EVxM7m&91{(B86źny q%b2ar1z_|2’.= 1(3|Ŷg,먪o[m"_Tc5e1#K0$AI,,cF.F,)8-WNw`! B 8ڃ I{iŖ-бFDp$QໞI5e;He,Q1UP `:>>.,˗]vك>xǮh4?q0tI׫]2 MәLf׮]j9r&I$GFFݻ+ IJ宻:yϕ9z_o˭{С;wi$GGGW Z~{Y}' idE) [G1=LV& &GB*$t\ D %~uy]_LƢ8l1|OpꑑՑtQ!5FF'Lv9)Dx)1Vȥ`f0M REQyZHIhJ-g&P9?^L%jqt*3+ ¦\<909ayh)QȦWV*ɤDdQJ 9%Rg  Ja@UU5Y0FPNK0P:oyEA-}s&C"OQe-pUD-DFUt*^.7m:ks>}򦛾JǴ1IJ3ٸGH1Nu;#|i$ZY%RI2d#2ˈ2.xa$DxsL:bks\2dS[/:_?]-Eߜ[懟]ZZp|Ϗ:'Kz$5-IRe(JTDE=F1ܤdU>wu;S51bdY5UҚ*hCb$dzl2ǓXW99zr8p Lr-m駟K^aJ}~sy';OVqפhFcD49Moq٥|f*fSzUgSE߾mK>uW'Gl9ϥrL%Q'Ѣ&V\#O~; BΰryՆG=ܸdAWcTL)X2Z46>)Ƥ8Frzf4FUug7JlYK Bsl2SQ'q59Bx&Nr[. '6__r2*%t"B&e+dlQʢk$ABi4JѠikcq\:l<!k>O<7yw}翖/s9?g\?WZK8ѷֽꪫn9WYi_?<aEvI$!dv]k߫G~CO$~_}9[u_(NhB*Эv-RL Z8߿bO=vT{';tg>d[$6P=6r#I"B6#P|u=,+ E9:2Z۝f#XHH+V=s26^??mfv4!qdXi8;v| O jN!%ȣ?t^ٵ{g6SfU_+/6x7BJ IDAT.{Kd i$0T(QD'F3 $a@K0{ lnWs۞y܊i1֝zmZHRJ)gvV x#24.~蘕mK@#S6K0T ,97=/ի袋VX06Q]s5<^L Bf , N>d5kTUs̵^noBaÆJEٲeKPسYV.\l6g-}|`g灎wo>+o;vO?[0oYlUo…?W^f{oM?9E0L&Jl^(УhF3` EQk?!("-niN7ǯ/Mӯ6rB Da۵[G4GIYo0>pQJmnz11$= _{} qfݜ2M\cT6"tmaZ_񍫾FqŔ2|"DC8)3#h)L8DKWe:V4ƭvСC\yi ,/3,t:DAl@JDFxܓ+ZC9/hx%VHs$U Ryf⡳?b(~Ag?(cOY)&Gw:4}vóu=lҢ^ճh넆e՛L&~&!x$g=.x(1[_|aSz~Џ-B;Xcv3tqRdڭ5"}wn<؟B38@2eRkZKN8F~.^+_(w8B BD_Rf j5͛7_tEַj 7ܰaÆrLd\ްaO~@{z PUvZ@:u-'l>l>gs@;[wh#lݺ_>Wt}}}{i;7o9Ɂ=PZ- jCcX8LZLX 奖WƞkڶY>_}1SL#4Ӯ5]6nZi3tQ-E Ѹ3."R,T:uĪ#[I$X1N$ifIP$i Lg^{#O;KRѐc IhS2ѧLV`TmqQ<$ƘМkc~u_?p9D^7СCM? 819\R|O'Q% RfC=B~ο9^\g~`G:LȈbBHi 0E&&Hx&(ܸaf<cNn}7dFq#=v4* _"pða]k{]ԏ.1@qkrcχ^e :jw@į5ڶn#bJNDd5\RPCD:atU\-xX:U4H"bqn!CdIbeȱU۞1L#Zo.%Ab(^y7nmo߱cg o~awyST*z|S:CGGG}]|9HSSSo(V p 7$Iol>l>gs@;[fni4M xwu>WtOպ 6@߷ZɕQWP;U蚱 GD@j5.srnx;uSRGQ'aUmLѯ8KQTHуAw9 OW%# MNU[4eBPQV^ѭDNxI7싶ծSԏw »zԵAbe'2q2I' -<%,0t.TzXTcLϨDϭ_)zm!3㥱vtP,}K_$M "8f)!R:8odBP@&0ѽ͏?j0GaKOnU"#m4H>ج̦jp:$] fXLBhUԚZ!S$#igM3iaܺŰL8:t,nQR)$Nܵ#L@?aŋ?裯 z AI?~&I{ޞ;uֽK,yn>cK,?ll< y߅ =UoYl@h~4{+<̹sk`t} {+~F,;rh}owsb6;wxš|~Dm=?KsKys}|[]<4RʼCYK^N,|)9WH/wI+?ʼE+ CΛsAdCDS{wo.ϖ7P.w#<.zKLzA /Y:4?+/3uY΋ɖeu[1D ]T&'elvC˕s待)/9獵i}֭۽{v:V^ !r-+7}|`g灎w/;_<^G>r#@{@>lٲ%Ϸ}6OT?+Wt ,X\E&Q*Ev73םy1J8ܓSH<ɥtq)_HK͔J0XT;[KssKX?~{*?OMHTe̝;{pnޞʜ!N抅G,,]T̗C /Nge~#R,%aST)䋕L{+J8җ-U$+vÅR+EÅ!G1J:txOM|1VtͩK~衿/+c>Qt+*ɋ=C^27ٌrǤ ?rڑt-,XO,:C}WJ9ҾEx?v?W޿2`{B?r=ʼ\9o˿pU?ݓ죧}04T(v)]J\BҼ\"HBSJ"I_>ӵ|},d]$P+˗{[TR .NRB6)YK]lxѵ/9G4aGyO$Jvf !|'I$a/=:|M {uva H鍊nB855O$ɮs=wzzzWvygr9͛wmo=no;9y@GfG?Ar_eYum6}?o^ExwE\6P1v$Т(A$ %mg^{~mQBB'hzUBL!XNJ8R[mw7 "럳NԎn=p HD`LqҀWF֧y[*N(IUC߯;$֧iլTˋ=Yē QQM bk/#.17P$7P}kh*2܀(u$xg|}Mf»o:tСWJ }ߜB:LY\xT GnQ߁'0a8q߷GSjW_^'"4$k  'kRJ0ΰic E"cbiZ:B@;fe9$jezXkfgKB naqahlWAHGMS($1r&NI&m~qӓێb NxvH S3 )B=E!kN%fm۷J,Ey$ZVPm$i @:h9^|҇?=O]:2HMcFICPa(qcZbZmÉaX},JBMwcDd@z\ 82iNbH"õhR]s)] !%xAD&'?#i7wުFXZ3N a,1ʥ);0^"EԄ2G82%$4<["81D.Ø% oI!X-.J:t_2lMyLB$t$jtvg<@Q"#3J<ˋ ntWLP@ b?kҍM,<_]xE֚&F3Y3S8XN9cznCZ" E@Ʉ@"pMFc?ʖU53{Cs,nj(BXh&IDZ$ -)GD?{z@4:tx "ku;h^M<"$)mq[)TP4V64ĀrmkZ1Jn?]ةU4xk50„b842$֩,2$HO5mE$B' 3,ġ!ȱLKss^Eb|ph'Z6# K`6VjFW7BR3b$G4Tf0 AA:U#EСC4iBIRqhR>-GPQ1`$ ]k[>$ $QMfl60*8v %[BیBHaNwm% )kS1Ue=7 ]*+Q!Cq#񽶋zvU)M`'ij::A Hҷw?V,(|$YU%%*4C߱LE)%؁~ U #$B ѨUBb{{;_wo~F$:wС1;= 1;H<Ϥ`Jb9Afظ9S5gB鵚`h5&zsĬ0imjۢ]z]c \}F2k'Y`8^Ai霤^i?$P2bEd! gL>C -g|KT5-.jղvS"SI.- 9zPVi+ I&< ue!{G?yŭ"#CŮt.J:t_GbȌ,zbaL|F$ |D3ĉp,SGN.0O=|tmGd#L$FW, ƛ Ĭ)K9@Biieږ"4R؉1c7bpl 0y,ng] Gcn'Äg1 l{zwjJ<K2,#^G 30p'0&s*%E(}k{*=7:e8J(sMA$8GgzQ{aw͉}2ݮs:Fq u@?II|MH_gz0" jLN@H1Ǧ5P܋ܦvevOMa (!ِ\pQ$`1e{4v 0z鴌Q@[sUNϴS49_8Szs~聗_{ڀ =^6D1$ pW,eߙsaө2Bgk$ V^NAhQ|񧎏mo<B0҅Q`5:m:t@Q1MS$4Ǵ(/ 7ݶn( q4!"? ?>Oob-\/LhO0e7>- 14 In51E ! ?C3Pp ܾňɩ NFe Ӵٞ8a h &I~` c+ךn ,GQBqL;M֤'u*= jtC'K˜.?<5B),.dX=dohQϿRC@F$qVuСCw %0%j 4@X5YXʑJxB9J$ElZ{ǽFj!C4Em&d ,rE^_.p]۞"cפHHG*FgƭlxEA}$e,EьX8kNbO_2U 48۫ # iWv<4#FJ/ɟ6\]1*aLBx1%劉zҡC(Fi$#(y%v]g!he|8jjq4 [_x20㾕]SC 65L&tFOPNд2򑄤(0IdҏHl2E+ZӍ={+[7<&S2R` p IO 2?206 'g&Ŕ[QA rlZZT."v4^5\.RХCB3Ԧvg IhnUCqJ*ry=ҋ]dQ^UkBٜ$q1@W5Wgr,LjfL): (zIМEb3A"%Gbh"?_ï}2Pa`h°  Oԧvmy9Kbsr<$IXh $/Z4_eA (Z0<8^HemOBDK)hlBP:!B:RΒ) XzGn?g\k @L; %Yihږs7FcԨ9?953֪EСCK2_1$ai:p8jdL|>ͫIJTAc@(!SYL}١UF膡dU'r Py\s… AeSNӟx'oԋb_72𠟄ݹO \AY!^ -hn ¸`zCo qC2sEqXV+T %>9NEViFCh'V[ڭ)I"cqF# 1F8fH/lg j%WP#(7cTJI#T;򧍚;FaV `% @ uzOҙ  k֬ٶmۺuΝ;=ko|Oܸqc~gffN?=ՙox'3 IrÆ alذ$38022r%K<ӆa|ͷz+஻w-4͛o;=ܳ~g9~Wz꩛6m4ݣs6?|oO>)Iҙg.ϖN{4 um j ^G(( p8&n f;X È*09b3Y sR3ZVCLivC¢$l'.yEk8  OwꢣeYvrrRQ}nEu* {y~rrR=e49 \r%o?c/=~_fo0|>8l>gNM]׋ϖN{+-뾇u&EiY/ixaMDA#\\'!QFqamS[^;ܷ66gGZSS/C 9,Ɛt>C*(IHwI 0rۦ!8`<+ $),ƻXNEsr$Zy?" b@BwZO?WZ fܚZ8C74\r0 g .% 0\ o/:tO# j`EUIb6-# ƨ@&f8_?k<0!Ll4}O,! c屩??p1Z;~ HX {.˫˜x2 h*],@"8" hh3/X\ZIb$zH4NJaд@$" pJ44o'O@g[7cMyJ;0_ǖxBmztK@s!Bc5-$qD54l:s=#]v]zs̾环Rzoxꩧ^qaNLL\yG?O_|qʕ{7WZq3ܷ裏އ&o˖-{gg'=?[ʊ"uL20f|'8IDI)4Ws"#LPh$$bP 5znsVH'XcUFߧAUĉLoI`aE:^8Nk2 bAI;gЬ$j4#gBO>hSbĚOsR\/흮5:FAA~d l0*6c<#߹ҡC?۷n>c:I Fʂ%ZMKN/ z %) !q_,ЊCɆ&E@Q09v00PqGcR;ܟƵ)*qi&X.)P8 &LֲjH4J#-1]57ˮXЯH]Ni[p4H 쥗^O~{=._GE 4iwqc.Ik׮ `Y6};}[nڵׯ3gl>gNoX~}\yC|Tz߭ىo޿T3Ê34XiZhcbl*\h1 r%)N>(I4cw vFN ;EJ `V`y7 *FFQEPTp.G;Ih<{n𞛷44>YȲEl׋מБG>"0 p(mgY$I`1̷N[:t888"V§v Y___zaS$tU3  *seqD1v _g֚#]15E:S/=N Al*FktuaAKTE?ꉀ)]J$M'6C@\mzj1@FhhB_ߪ?_rO^%#XC|[ki~Le2q,☜ډmbb1:aât>%n~y׷ǂ0+IahJPmQ W^qF۶o;v}{ ! `vy睷?KRWz>C=ttt˗s9t:=55毋j7phwes6= Ë/k_<0gΜ};׷# 0 GFFN=/}KblĿQq| &hlBRh!#W$YܚX:_v_ԩ߽fIf@⭠MaD(R&lzX~yݝnr!5D.Äp-OkbGڶD=;cS3*aR3]Q#]0߀ԧ %rnuhT#+,b<F8h1Ni7ۻ|fy&ߓNK'Eĩ-[d4tQUdШ@ Gi 1vGBP6+V˜,`xyE5PDYC9BrvG#FuQ"M:m8d"DLyGu*>\C_~/)Piܬ@ɴdPLć.]l8iZwwao[VT={ؒ%KZq,mT*Yf͚ y}˪U?O~{6o>ܹ߬3HӿկB<-]]]e[ފ˺an?AG4j U=NvD&e1CZC5q:;Qyc&B#Î.Qk:<&` )P;Cw'vz ?VC{4. F & E@[V: ܘ#|v[2(TyA,0)weaNjKB. ],(># e]Ŝf|bOt3=|Ro/:t6I]u0vL?zgӒ yޓ9۟@ISq +g;6R G\. 5ۚQ cS#TMC+f9sDpǛ¬L Ib+{u]p8'f 0шxb⭠@v].E2LѥהeLyc<:9H9FmC Sw[&b S&, n#SBEB h#ʰ'X )Pjԃ?g5A彽 F∜NGSRo9U뮑 v}eq;w]{%\bŊ} pg=묳>/_~嗏a866vi;O~G?'p /Kׯ_oYO~B%I$@"IЛ$2e%DᯝsOCnl7MD1D=uG  U8*ihp\s\{}< p~ֻkߵSU B,P2ٞπ"sJp8,a/bw]YE"qa]DHcm 1@-Q.,1` 1ĘkՓ$:=?L-gB]C\DV?d:{[hw~4  "M ɒAty>90L'xV}$ɸjcqT* [8 =7ԭQTDRd;M<8V([aح*,[.)a D-'}Lk=qJ\QdY(r|hQ28n"!Yt*ʽvfhF 4uƽ}V @"eC1\Z<(.%E'8ǀv,22KĹK, (膔TZD8xyF c5WgHX(25/DYA,)ɒdܐE&T$##kf7# 9)eal._~}___$xѱ8LAsz3؞)H,Q7Td$h#aq'r`$(~훎ٷo[&DRU5-UcN4a* ^!&Ӂھ0 D0 K{޷: [Ny02} axPaڡg."[Hf[W)Ep IQ3n칩l7Qo)K]V#ݔ(pO MsB@ss؁az-װ0ųNpMBBX:p E{ ش0 z5)&g#p: )boЗxF49^Yb!s"ײr^eti=v|_9"t1{<|[ {.2ھaHH(5*DpLzKbBrLԉyJdz[N=XݳyVU#徾>1I2@V0C{=ZdhH0mbCL A&%X 㲒ϯz/\%O&R)3|)]/14E,PȤiz0FAdwuFtS^+yaɔnBI0ν8ǦMgY=5|@ bI WhƏ"z=A3JTUm:gr K& 907 n\ zfD-6EEvmc!rE, (A=$lSv_<⍖c9G z t) <}d%O֍=CwlnfcIUn;KuG5z=B+Þ$v'MC'9QY ‰Y~ ;r٠btqSfÎiYN%$Vcø;"RGve[e=LɅAX@1fjAUX"_PX%IKp4Nz..+$.iaZ*ԒesZfm?8'fޛ{'~vpb{~/8 A&!M.In ͘ctbbAҿ}f>&5s0 ^4{Ɍ~=u0yGluQ\׆1\<0WI/ ƧP8t5^ &Z/V____ JK2X(⸈}.CgќDX  `8GQdZ dmݤP$,R%W:uC J1k7 pYed"+%ݔX>2Cjȉ lkc!ɃL",%Aai._8ο R%NCpL jRy}}wRZQhb$ 49e7DW>npNPTrw#oˬʴg8Oy晻vvsO^};{+w =i6 i=y`nnO\n#pQTefr>A?A^j1 ˴d% }ݶ@orř\4kˏweM^)nP(bð|DQ\^^Vb+˦i^tE333^}}C/77ym:?\,[no|w}<$In޾?z~8N>ߵk׺uVWWy,|m٦ز"Je$M,A!@.fͦ@ _ANVD f%[ߏo=77x|"U xc]G|"N˷u;ꨣ}ߟ߼yE]HR\]NV꼊㇫pG$n:w:}sf!o!_8??~P .p"E1T]SZ6LRYF8v10<\ p4s8Πc2o4j&c242A0crT/QH 8I]iBF*dn?(-3O<a>q{FͣU6}ۿW~ a8Qr K̆ >~?њGu^84"g G0lL?-}}}}o|{w?}s<~x|hxY$8cy[sacBdhS 1!V#gRIU`;^~b^Rx)JyL֭[tAX^^VU/Je]xᅳAЪ|wC(!E1-žsۥw{a-cdX@h|Լ8c՞>۫ !tc (1%)o6e____<?\MxãȑQHk5{pO[ˍN 實 Ca1 q؂KnC;G:< T"e#e)QٸD{74eB5Vmɨ7$w-WW9M,$*͉jpӃF-'e˖Wi駟0 q}}7oԧ>§>CsW_?>zg/+/iYփ>.{qW?\= ؿ?kꫯ>w;ʗyfn뮻>ϼx]|3UŎ<*% 2`ql&[g/͝7;*ұirdmaMO_3)v̬6=:QP1XfvPn*en((%dž+T%U @N0>yt(L<:46rJsSs߾󂷜|A::}*F%r-S osOI%+ e&ξ}wwm2SHNU>N#6Im즡5CR9L+NFJձBNlϾS|f\(dDy亩c /u?:wl|Wx3/)đB @nbv KXib<12<:PHOVU=:#|*N”RlvHL0P^5SNJjNVd+TQ4S@6&$zrVbo:VJrfzDL3l!7 d e$%]I̚Pq28Y.i*jv@frMO~rg*²e]nB>Yg( qG+u q[n8NQ7tMB%\R,i.^ziV;/l6K7C/jjz781~︇Jw~(a;w&6kuLyrN$7CDPdGOa Il6ptRV45Ax;d" jexH7mZV+Ġ5 <)in 9"S" N&i"bΠ& @FHH5Qȍ81 ;EQ+=ŅdՕBup, K~3 'JsOu;a T:8@ÿQwb}}}}o|{w?}ԶÖU)x% n_{̱b;+ MJ粙B\TDazIgY>UY]BQq'܅=SJWE5ӎ߸ФoZ{3N[4.,] >ƙ#)ܵc f7=09fqk}SxElДʼn,2&8 }%= җy҇.iEl "(R!8)a[-tC2lBQp8N7Me='Y9b1$CB C0w IDAT {$EQj;۷?bXȥ9c)2V9Y܂裥t%HjA/,-T~UXym!~`~25[6) aHP!lb,ڦé-" >PU}F``D>08 )Ӫ*%LKQ)muD4D %q<=/u4U7kvik>{\/U () >Adl2)R$tS^+8 "HQ"Nl"lY[9^!DכrC3GH%C3G "8 HhE* e.F:|;6&ʸ62RIࡻtLƥdǨ&r"‰WсN9=/@45- ĂCd.,` %JZ@6 bQAL`~@`AƐGRr&:Vg8>13@X~B9$8w!8M{x<*Z 'HY.[}h)9, !hYLpB<'2wVb  t~{} K^" B d3ƃOjsk75`' O'OqU7LQda;Qvme%%eCX"| h"S1:tvkĿ,WWEx-!XUJˉ E60 pmdNu8Pr9#vሀaQ %Q!hA251#P49i񈧉J1/-u>pI =owօO|?Co{~{_QIZ̉)-[=A Qtt9R8N/붦Dh}~ÍqeiDżiUW=xGQ IHv@e#4]K(WXM0&F"v " a.8wC'x9 jyBn 1t\ D.M2$Ec~,H/F}peztsVyve8S ƞw?[[v߲en\1캎V"2V`Э26u;ޡ}^`*9NIm. E0tm͓ODL(rEc!D DnyP3DK)DŔOBe^W.t2Sc/ )lg!~[L QAzoM=dAQҩ` a b-B giBK@v!W /01I) YR q\D8C$QEa 0z6BI81Yc:ݪwiwnv©g}6ALu&LNXY"dM ǂw/",Ijgنe\Os"ѝQ{5AA b 1nAq]T%˧ Cٔ PO{zw:ֺm?}H 'U}<7cjƶ 6*TR^Ӻ_ĽP_90XʽX3K{eeUr(KRiY]@6hà2pZBy /6YKЩY fxfRJTH1C"G1r-잷c{o1/ l˗(6P,9ևg$8,SDD! n[vCN&B@rZ!Gw=sZ5Wڪ$ON:QTuvCn`|pd͉[N\?4a,B10+$0DE؁N;ЄV'RIg"ut) $ASܾ31mX}QOIbuh}T&-VA& vba,N84UDRb")G$JB9E"xUPʞc8`nwl:5%aV76 $6=ĥqKJ @PZ}=#7_&ձSf5Yb Us)2;5&'3ɊT(h.[N$|^59n9]18rlVJѩjv, @)7=̈Cuó5Sc##Tqjp6*L „gJbXΌLe܈*#m<]*?Yٺ:i9ʒ Vr-}}}}o {{*%4kdžr f`̏>upjSeXU\Mjuzppbj,=\O YGFGs`!Qpc'gRR9-sp<[Vf 1K'D41[3U^35'=n8ꭹGZ: T'6rt#%$_KH&eeK i d,Ưټ~rtyl&͟<-gڵ'{_^cdx:Bb8L fcfNGO d+ca-7U(S8_o}i]|I'te-,,petIV*믿~~~u݇zSNAqr0 ?yTw*W? í[^wu/><\=o^Gsȩz 7y[ㇼr?`!;8TΗTAS2g?yMÃ|^g^[b$:fdz}ifzxre'c,"T2MstJmNLUBiTȔ JP&|LNLl+n=Ed>.RJԆ٣krƳ+f'7n*Y7>5v<]0fhʔəh>=hy-űtyP3QGLjdƪ\?)ye1)kfƧ&/o~=/ް5b11RUFU5?*V CE1_&L#܀,,[JkY17"'&K#c#&'B乁٭S[OXe[8%ⲤJYI $*jnt@XOY5볉tu|_R-c,q^4oˍ~ w'vw}oT'>Gd||ngLrNv5@iR0ߘYE$n9?pv٬pD4?TuS[t. (D!p^cD1!N:p@\}@<ծٮ,N@):bg?pnݿz K4m-Bϕ8Cv.^)RhA,ǵ= CWa" )n,4;l ϝӧOi֖󹜟E_nޖkA0>>~뭷nݺeb=F2'ጊcZ^fh0t}c-F<|v<^ònn=u;&c .F#1f"v6(!Y2ϹX>X"48 b~{i:?߽߳.ЩUm$[?t\R254 O(V ha".d@;|@@C}4 yײvFzBz>t[~vmעג^(z=^j. H.22`yȐ8Kg 'I{Ƕ "(Rr}!@PEC Ctn!kzʱ4Ƒs̡q# PpwONN^uUx㍖eA Jҏ~;yv?tMod2$If2{nT^H4 }vVo|ξ=뮻r|.dїc?bxlr<}=GA\ jxVOyYGDjmQUiϧS&;]ya UT%:3 Z K䅅*H8?*)*Q~s{f a5'xe(aQ4t8Yl/6%Ca=.} ݝ]WnEQz^}߾}_| =s֭۶m۫NUխ[s=Ǿ~饗r)v]k֬y u}nnEQoPV%IzNywg󹜟E_Z>?zn:v0U_9z}e<@"& WOvoh=9hmI!K R,lA˲=m"F("%JP"Fs!P#GG4 N4v-A & @ I܅d^3-<<ګ6fu=O%ӱ"/"?9c\ XQ >I蝗ʢ]E#M0M1$U jy3,AQk&߫Ep$}?g覢Ҍ(s>l:C p֬D&5uN5CFK0qo6(ܞ .2'6=[*MVK#K XLasJHS@`dJF:Y*FWI(f,Y'd=3 ݠq~_g3#٢LT:0z,kTLyo IDATeMUI2Zi,bbfcϗ5x"JIA)L/O>}N ~4 A̕ Ͼ/w5OrHi@S詩x9gSYM7%qԔTJ$E˕O˿qlxDSt$j|~ ⺁B`Rפ+T}PcSGGs# 8#[2SYR5h-E̮ɧ*: m4t Sh ^JnL'))bT='!K&#Dr'{w?ɑt~uMC$-R4Onw#1S5IK$qA&p: 4*;RNP&FSu!H%+'lvdd й:e箿NO4fP4IU+C%,QZYg!Eꂜ!lyOӅuW}?}_1!2Z)E|T 18< Uk'Ϙ^gA YJetK$GtH+ DYUPtN S2Kr>5i+*DCWrʃM{?Kg oq <+IMӅBaZ B裏wy$1 STc:s/9o/3Zٺu87xߨ{IU\_>:g+*S!I>$HD=aI:pۀ&P:QQkĸf$dGOKtBGeN+.?XCЍK7_}!zl#$EJq`Yh6zK:b"Lj3:%(I6-f5HQy,. T;0|GQdkD"i;6Zzb/ +ҥgj0vx,ɏ>u.FCnf!@QdU9秜|1$j"]N'pi5 l/u)F<ܞ5Q%赏NӼR / +Ԛmgm7UBȘϹd6K^`% O@g-p]# h\$IQ`yVQpi2J/DԞY]"9 w;.??[#AkjsaWX,?oX()Cf L׏̨̹阡<N$''yV4I,Nݷj;F *"T#Qb2\`;܆O>}Z4V$K :AXc[]0PR0V_w9E9EC պG5'(nWFC tpziq֚mqbXgJ51=aI M q@ WV^B1cX-31"i),HL]CB2DH-BigZ~(vxI!ΣTPI"p{uY4nc&.^w_L4;mǍH|qIQLs 0ws>}< xm q(N]ǭVӵ z_8$KGgBX zǐ C]A򼀢4k4-D`h/.ՙQ/ϫuFEi׳XAVW$aPK*+ z8)b#vC`9af UCpqfqHE]m5^S꺿1E3u4}UEk{ a׋҅Eۮt7Mj:u-.i^7F(`DbbK!nhKK #j^貼IJ@n9{W}촩~[v}k9<#diVgi&X%9mMNHYD!7"dh( n9dNE "? -˲]O?PyC$A\91U[jvm׏d n.匘OR.p1;t4C`cPºۉ^矶i*5~3^NO>ڼ+J-:*iY c4S.1ghM50j~vz8Nadt%=W1p=ܛV(p=2[WUCuܞ4kv, wP#MV7YŐ|H2PU:]8 yk7VGp!AR) @:̌D-X=;:h9v.r"%!pQc ]?}wJ>}yܩvM;"H@D8t˝|[Jb h(pv4wF0D@% mCE ,,,LdB8^%x')"Nl6J֔άXU`7}CIQO ']ta<Ϗ~zyasANm۶L&Ct&ٶmұ_:t.K&$I|_?qJ$J/}.^r>_!GUcڿ^NI{gYv``CZ=)=矯( q###G-z\SNf \i FDA2q3΍'͔5+VVU.\*ŒԪ0YX'rz`8*bb0d81uFyHk$SJRgcL$&)RRJf<-\Ab˥" )t1sSc)hteQ1SyPc3*dÙ|>;ȍ$BO)LHj*49!kd>}9)ػif6aU0)MYIUcb:=Dj`4P13&$J!SLJF^Nn(r+7VbA0 =&D` ZRd3RX) ?O~֚Jh)?~9QVM9((tXdCJ6#I]+FBL4Ody#Ai]5$5˙TpADrꉑbrbiJ@LB颠f2Cta(/\*SL2J)L NNT#J'Y[;NrB* .ާoU&KMx|JK/tϞ=V{΂_:zy+ַ0&Ole˖۷OOO;==}-[@_Q7sO&7tӾ}y;8?-d2g}u{}O;:v/o HViFx-䆓R6jal2Od*LҦnTI |(d\z< >l&E & \2tcp~P*B U̙H:X!' j~r?LJzܤHv(xFN#S_qhaXU)53XkM襱X9+$HH:SD~xt Mrt"X%%P\1164>9_ӧIO\>.')i53h`4*IU1A(G 3MWFE%L2yC.:̬Ht<52<^MN%ӅR.(vժ{t҈ tם_ƭz*bl<+$jCpJ^T CLTVdL1hy; CgLrE2KP+z|@UX"ËYBJLx#6Jd2eG'>uih+7'NmX;PXareMi)Ɖ Nxܷጷx~8XicF!$+5x|Ba+Ri~*-5F}4ɒNG$U%-6;&J,KXLR/1S(40 s"@8 %E"4?OEk6[UYbtV6r9ImBxnTgbFٵ, nA!.@M˵ y嗔 Yà@rDI%\Pwi1;15Mw\I@D}ޮ-tۮ{c#hB] =X\Xy晗_~Ν;m~, 8p?͛7|jǾNn|_ѣG}?z 7p|??:'|rÆ Nj6mzꩧ^=s9?oTv~3q㸱1__ sy=#{}_}ݷq$qZL0Ӈ=PdgH %6P$l5e vtn_B,ƒQD}翈vYN顀5@ _Q=2?s|C3 8.jj8.2x(c Y1M_x9 F2mHv~fL'<ȱfcva:nJA (C -LG 9ť.b/htNFTF{fTnNq@2`xu38VZ/`szb@O=]8iק4vlh""CRxsX?е:48p IDATŎ,P_ɫJQo׏ AR?W򕗉 B8;;yޮ]7to2 ILj5HN4 }vVo|Vy?_,nzXVo~fسgu׽K4Mj#ߓBvq5|=V-oADґXv 4 =/$YHrj݀8j(D Di-B i2RgC%yPzM<:q>z,(7~'h5v߉vi@t(4Hf}{YRl=wnLMlz !;Yjڮ" <b$ۡykq< puxL.+(v@ؙE]X!o9ZÐC0kK݋oWnro~|3N{9Сnn>#r"/O9jzd2뮻.|333{o"x ‹.TeϞ=xXqvvv||Gϗw9r~ިb^~G),?3TXq~~~jjj~~Eq,,,LLL,,,|O?oWuws=WVPY) xuaBĎǒ4%: 1ެXBjZ߸TyFT}aA|<< A͈Dj ,& $$ݰ:vD@ "m N~CGhtk3 K H1V#Cͺy~u9hFPtDABbQYHwj0Uhӝokrӧ5!x8E-jC8L "i r Tf3)=qi**)Uޫ Z>bbhd_跾)!. I ]?`CBh.%P* \CѴD!9XLWmx.xӟl" a`q !K(&7qԦ3F#\sjTJN DǠ4kCt D@Kmc3wѯ9 \Dݮs$`=WO?A^k-4D xc699}zNDR[ xl$l6Xgu֎;NpjjjΝNj<ԫ%}W7~믿.:Hh^cwM6מM߿O߽{~c>IQNr2(eJy%VN$ZiW49UJK3 x޺?w>ɿ[=&&F&&L%3Gce 6'Qf6SZ9+뙕R𦷼췽Gcd!YjM&bI9ϧ3!*˒FL4\O9!IVt282:@<ɧ1#%\p-XH1CIf#VM \.2z-♢VTCrBdb/%x/O>}N ~:HqzUb|b`m 2lrZ02rŹל[>H(tju\yLi`%isD,0EPK4&xX9YIR駝2<8 錖`'W璫]r^/eb9I|q7y×>5p|}0sL!g2FZW!J_Quݻxx<_>묳~{U\ggp]w߾}zw|O?oWUY?DQ2lBO%cq#6ɗLc0ϥX1F&NOF\HRb%30$ `XVÉbFd*rjf,) b!ɗ3/Q5`I&F'K.J\Oijz&SeBR/T:W.4ĊCj'㩄ldLK\=\|<89tz,Prkr.Iiu`}^O>}N ~TUH>*9 [)SnS7ux2X r:椱ȩΖRؙ5g&e-d.H'2Ǭ-犦2Yɗtm84F(%3' ʧyO}7*ɼY6\1I$bFv 6gȍYO|ň>` XuWoa|\ʼRHJYG pnjökopIal }ܪ|>ϥciMS܊R*!1=k$ɘuoUwWWW][,S,3c%@&RGBkq?AHQPG-mC9e䌷jn"x0a)^ڭFDz1>.x׿+.ŐB#vg+9~螯~'|_upհbK(&xP8 |ȺFڴ~HY N#k|*0A`V%?D=3?կw^}}}}'~ҢَI塵Ϙr~ХYe=O< qw^Z(K G0j3f(UuͨE ("zphƋ$LR8d2%dnkOsDOvCa6\FBHwF4R2[4DZPf`ĔD{En񆃠a0 H4R s.v"r̲ 2Fp\ .>H x3^(M{V?v=X &}h&3EWj}^5<7?B{qDHy!6pE' "\IJ|qv)+ݦلL8c?CDd# JJz^qnۣյ:S9=ktX e$D'v^h.HT`'tmvIg؋N]/>ԈSrn'YZ0\0 =)N#^ 0]t"LȒ#$t v7GKw0LdӍpH  \zG?ecЍ b\euE}Sءryyi917TcF;xJ5(Ɖ"mbZVm.Z\}߮(៻nqhXH`Z]xۉI;V'0t9՘=,҈$q "bB0sF`h EF$`D X[hC Ix]WjFnM____Kh6IZTOܴ{"͢>mdsL<мSE̟s޹dD޲ -egP:+x(ƚ6yN?ul`j"&fDFGiQD.E;m iZzX~f$CO`q"LT c t'8>n2;ih |ꄓ3z״J%3X >>ƞHZ):w MN/ub'*33L(: I8f4hT{nb 0TBvDȆY C!Bj95YK?UW *-,14Y䕮!CCÇfڶ' L{i Kŧe3j3EVxņp)٢0'o2xx%~ͩdDt#۲''tYJFV"tY)}X;)qJҶuY~3-k#QϺNK؁*Lu^?޿_p4mQ6W{%rd A#, BBiQl9 ـq6AM?,D g0'xN֞ 8D6nסp=mEz'P$:lqqI.1Y]iO/>UzǠ&OI]X$^<^1ϝ%D (F=`6<v'M bsK !MPmZ͆zq Z CkaUY>f;I`13LI}(@Yl~E߿m2y/*P$ϡ) GxQ &zX3VӼ\-v=g.-0u"#Es1KKkc?$@1MQ qm}ˋY4^Q)P]C3 S8I,6 ȶm/HƂDD*cUFf<fϥ%]Գ A-v 1\݌¿M{I, E0$MD<˵vJ2%AV4eDD6ЄEya"$(hR`0औ‹"Ig} t-gL61# lBQ&y4?£$`dz;fٔfu[ dLckyΘiu}7p&\a3 8&+ɛ7…f8tm$gT Y܃̒>b\vMцADpfvcf}$HAQ=@$߳=`$>OLNN {w瞋/0 ǯ:۶t~e ///ڵX,4],wڵ|KsIccc7|7XI_W^8λRΣ߿e]V(H[sˊ\6\* qButD&ULrJ~UE6VsTqHꢜDu4P9slh"f2z6_-ʖ|ֱv@dIȍ+i.猜.镔s2*YI9TK %UUFGD$l5_]f#%/T)\+Ixz7jjVftrbkLRBHMɑ5#[ M|`ix0JN\e`Bf8nl#S^W^v~tK!WfʢXʥuY>}wL.Mo]U|Mז3iQI˵42]3R[jS6 z9jmHOfGJ#c##Ϗ eY2JJe8jhxPόR^ȳh\ք«hskWӢ+W#'Kc#<˥8EҴ" !h91; V3Q=Z5Vr /8*ǡ^Lg nH\pe=S7[ne-[tM333A:t誫:M/Vzé{iw}ꩧBNMM{=~={;4_Bם\)Jg}6]=y>9s+YҼ+<+ϱ?<Ǻ~ϻ8ns9c IDATڹs>_> UMiE/)s[&&}q)CZiX}bt(}F ,rN0FR=]Kq)Wɗ'GO~ƅdXI窩Lm |q(+VICZ8ddk?8wLZȗS׬ZF 5UVB^'ȺFE?Z^RXA.h]srQ䍫&'*zAt%'ftE6|.~U=+ VtRWմ ^HUuCRU'V7@}dS)[K)|9j%||A׏l~o,B^t5_ߖm[3~I[.6mY]u !UTF3IW2uOȌ䘌IU e2p=%gF35SR.SՋ%U+ .ebuPJ^W &=~bai1F*C۶2<;V"0F3kל8^uAiZ/ٔVEV^:vy[O~/m۶otMr˙hP袋>O+yɜ0J_)Js5ϱ_[outt4 #mxQmۆ "A3t+/L߭" ҿ;U\B4)N:V킆/8l:s8$c4?kxA!Β@1Cc!B `}o2e"A2fǞllʐjhU2T)/C)WUǁ~v׀@*qW0E;! 0=,ǡ8:+iHϾ;EeX> (\S@xxgn8K$HBQrRŨ^H>bOO8ؓa%cx&\DYn}E\r̙'[Z!Ie4Qx>K/>di>v;a42~wRZq:4#ADy!Kb?NыQCδϣ8",&kfCvEc TA Bׁ(Q,=Q4sK 82ADAۣE^z" ओN+.}{N9唣w( ;v?򑏼uvmox^x~O~p۶m<˹Ϭ?9iz``s\j=ρaNg? ?^5nD t8pQ$D룁DA'l È"Hy'äUpB&]&8rq:1 vp("])1vy eBT:YV!kw82r0QȐDTY4Idɘ tF^~(Gy188_QZ! _bHdX{?F6}yL4 {nn%0+|ahzw:~zꫯ>JΕ= =>hXkc]o]?? ر~s=p>wWekG|JDI .ySpfZ?m@°9 mFu=o?O}Zqp@M=m۶UoH$( b$lއnt(cq)&"53ĬD) yAP, \yVUH7. RfR4Ef {fk?}}}}}L}[7]מu t +65=$B1ƞɢ #@MF _n|+RAE,i29-_x&n 3謅 :>(SD֨N0jpAud qE##Y:iT3W'&FNUUP.VVMnx]֟tKT7j&_^1W+|J(VtKɨdz^˩FќQ,f/zϺrr|D]ե7]pgqWUVe@fЬ!XANIUXy<]1kƏ<ڐb64pb #_4Nn[V'7|{ϓo8]7/p֭{9xصk׎; z-j||ɿ&߱cOnk~kV@^JbUSr1]ѲTx1e%u1Q/\ׇR2\:kugKŁrTˊFkrZ!W(d u"_Hƫ7yܦCkM|PrJQbhUTj@ *jAl%[Od>+d\rI:q|tt[֑#E])QsjA=e=Jy^ҼG99Wۯw/~||pxxRHTF( P4$ ) l> 1'0,  !023j9ӈM={0M $m $PI7^vP'4x!gy~te b%@Ax ];ŃYTzij ~! m[1L9V.B˲Mgu(CQ4 ^s&C%-އpq{vRT\ah/خ L-G8b=Uu۝۩W5}}}}}/XPeyAbmH=wfш}8V:`8/4A2dY~ 18 zA&RV-XJQD 󍦛$]g/'0F"ǠSmߺ3N9ZO?CNkD 8)Ę o)Fb7u}9R0(@ #|uaHZSNr6*^""BdLjt|6B(q6R&%^^n9Iz7JUOm=~ .>@Ԗ7=~۷>adu%A=aʍYVzϵ$RKB(!L Yy~y~&OJe~@;NβpH8^syJ>cE0*_>2Ac"v`gF - HBI 2Nl? Lؗ1~gf;!Ee,e&Lp"U=7;@V ch:H;$c1j3{G߅CT*>7nJ____gGF;_WG0$fY ݈E\ Ѐ'iCV*jE1&9toGy!BI#[˳qZ ?KGQ^a g=^=t8b4ŌeĶ"libq1/?YG!J*b-HYIBNkf22G"9g-%1qE]>b.E`-A|-/|˟9ĎL A-U 2Eq٥nǑ$2tJ5!RB UްvsO@X IŖWl,k6.Kш0χݞG}*.F'Xb&89mn{NH:M'-,6=ɚ tjn_$y^aǎ3ZKDTYow$B∢)<xq솏zBE$BR0gl„yUOEߙEV yә=?CDLAqƴ$JeEN'Q  G3{)?<鰒bUdXZ%)a4cyE+6EM-61b˓9wqBJ8#p&aB'g8h$$dϴle^4A24-Z(5DW,2"uy H.ٞD2ޔyS9I$[=3rQ"YQHBVЈ26Z|2$ 'bm9i)Nh{c$9< ǚ^Pm8{c=yn=O Dn*G(~[8X7[ &0K$<#JbiB |ZmcGB&;Pؔ |Hftij6ET%3hvcY< ~y(v]9jZQ"c x>%Іܲ(?}Ņ), ADF:Y$Xl-4(_Ic;.@qHNˎ3W)}}}}}/גc4hn4i{ =<%}"I$LAv$}ݥY^DFGn`(ʱA&mGp܏:מϥ9zKt):VL('t@C?+r_a1!m}r_Q *gzؕe9M8ߋ7$ ŋJ"s$J4Ez &-H6ZN-0N8^snl13ߜY1 ,ۂQAW}}}}p Ub"4]@ֲH4ÖDLΰMpL0$N`N۳C QI#AFy]LPĭ IDAT'H,5A $CR͋4Ln8ő(I>7!RRtzAڭ~u]+ zA%=u!m}v_L"q$ \1Ӷ0OLNN {w瞋/0 ǯ:۶t~e ///ڵX,4],wڵ|KsIccc7|7XI_W^8λRΕ/̩s_eQXW[t}}wܩ( qccc]w8LC]p՜nx5.m^w7Kb5[j@z:>;kĐSʳQ4/2(km̬1J^844\Xuvo?\)*sZJͤBAOL9/ U2hTD/dJZi kԴ[޴?۫o+ W*y0>~ ڪb-}}}}(O1UReDOgb!7R-kCׯOk[Wj"Px1 :#,"x.Tyk6pܚRJe2Rj,[,'GCذ^P)f9u4Vej9W,#W+؄^(ՙVɪyMM+ FflΖFN ČVIiHmL0`rZ2U-#jQ3SgrF^CHTA|R R:U(qNcg]SӤfrJj0WOT(A1s9' ~b]҂R)Zkؒ>_Z@ sHrnsGEH׊~ogyOf̫ʇ~uRs0=*|iբհU' SfaX|Src<_|fo**̚P86Y+o$ԺjUsV.'^vyr^(Y¹'jB$K"u2?W\kaA0|c̎͛i+Wɒ&BKM-Wtg皍\A+yMJ(7?Gr[w&&YTy-1cƌyCp`*|ID$\ -SK_o C0[,0fE֪\фG[j+jdUNo.”-ET  TMVFY+Q4*Zlqe8⪊"%y۴K52WZV]T%{ªV&ȒU9m ޤTU+g El5ru9kkskbHZQZ` ɧo>-e쩉F.Wj륚e6HvJE* [TfT1-A7g˧yc:odZ"״Z55.ͲNt:$_l^y 0^n˲leW]um9眯|+/l}{kYhMMMEQ 973Ͽَ_}^_#4G"H1A 2&@ 9?Q?H4.04M=aPlcP1~8@1( H:h?ec ~2gWb![ޡPnY2HJ')C}dBba:!^(u8P (q!7?WvJ`ϝ3f̘_~y jzrng_߈votZzٻwO}S+z4fHQH,EPQŞ'XJGg C91GX ؜9a"/2A4\f$qD$Ȝ0( ~ 5(azTӎ h(NGfP$eIı4CIꭵx(Td"E`%&9/DwAg BZJBpa E  E) B3f̘1'0(&("'FHRd)e $(t8#\t;o-v;;t+NV t2n#FIz9_y8Ȁި~4 @X @p:p18!]qf @a1)ƉG[QQC'L (\gpa%8$Zm eѱ0B˒0t? ;!mZ^ð$&`;.6 0OG@bHy6 = `pyO<8=^y/eY<̎;vZeyΝw'?IW_}'/..Am۶=UU_r;;Z-A^uэrn;-r<fze`àch!FBh Ch%N:X KS,Ǖje^eV:Gp&Ȑ~g; PNtSg;71l>q" UeC`") Rx&CdE?K3l+DUdh@+%Y,93A=aF7 aio|bb}{} ~6z衅׸|YGG~'&&^0(ؿ>xz9xi't0J B$fu{2K9TQZ+1396W 23<ܜЋ%ElM*rŠUQ{ϹBJ7]X+37W~oTl9TJEUfkzQ4ƄUf'L\z[7itnsoSu|RJʴ$!$è^PUeV(jI319ͬ,LozZ͛Չ|YLV9o-l-U%M"~bcƌ' f1'J,mN&O6b.St[t_6KJ1ݴfs?|ӟ~%Sw}x-m¸KyIYR?m2Es,;x`Pۗ|/,[*yp۶zٜ\}6ʹQ}~7ϻ/Fsۿ[Q?򑏤iy\̫IӪ\'mK8I۪ꕅt^(0FR\s´j֩mfQ)Jz6]*"ǕT\+vGM^>eݭ[6f=_J1Yk4jRA1TZkrs{(lf3'}"_-h9pd[ $J%E+U*jAr˶dV\԰sԤJ>5SNS-cƌ'S;Ԝ֜(riS\Y-]3*f:-Y^MC q Iv^[)3Yzõ_9B*[ 6_؊rcڲJ"ENQd̳0NFeD*Ll:7G 'ϕ$4` ^*TM/,2/:9Sdm 'r(i&u-'f6P,+_mSdQ+qJtdhVUKgqj%P3,]3U g~/IA)q Kb]W^1ci)s5_4'f^)ת,ucdYo}/$Jru׵,yK.Dƞ={%{ݱcEQ lݺJ$˲kƲ,-˺kWVVW^ya(NMM}_>?jץ|nܹ|^!Fyvohќ_&?k+G HAḬ ~(Dy!Hdtc8#hNLWF gi̵Z^D|%o;o#ҢqYf) NDezg1} 'f)2iCB8!]Gr90O~EGdL#ƒhԓum= E͏{QSBxa @i߃'6f̘1Mu ݨ>צ 2 DEq(Hk$ 6\:\ES !b/iR@qGGF)8szAqM@A `8;BicلYuS"JdYN߶ZPqxNdF1=I5~h>Squ{ ydZ@2@} 7Mr,w(c,3ZB?v{=a(cE!N3gp}fٿz;I  ;-P0{"@CM!m_'dna P"?Q$t*Бt8$@A1B 낞M1ƘiSPg$A/,Ec"iZD}OD8N4'+'&6OFtQǡj[YVwԍ˱F~S~JdP2&|_tAАۮ2˳OA0fqw2ZGKC_tcƌ522.=#/u֩8!GC([z IQVehU9 Or!P1ɈB!1Tp8h!c4$HȰ&Io"ז;va'V'1\{o.H sϭb8}O34$iEmr82}Q6j$4i%?fha!Ƭ?#$oZ^>[ƌ3 a7"0 N β'R윕MsAҺHIÄ*pV/ |d८b(Gm(%?4 ~? r,Hґ(Nn'-dpٿ&{d H,p??y̘1x` DZ48"P%<ϣ8mV@EiMP 4 /{~:p k4X$$8jXbdP=U9B?H-%s1$uJhL#/xhQ铭}w_a40Hru.sGVu{11FN ( $Q|AnLژq&n$qe!L 0C\A/1cƌZ\+DY䧑$yp$x}_&iGYȄ#q-@uIL"$KR" D$4Lg֗(kM#CNCheAqPശ0Q^)43;rxPpt1&S6IWTe~.ˋHp/|3QR!!fBC$&3I7tpO9 ҼZ`0|g7)"+ZG' IBEP6F$-cƌ#bouAN ZJW6)N$ 9.e, ʿRAt62 F0$ $6&Ћ1?x' @3"ߋ/Ȟ(2{naok{RVy)"#]Y pP(N$4.8NR$Fp4񈓈dP&N5LδF44'a$H8cpr|G0JG``V<OQ .ЅqYDȣb c݇/QEW:ިt?~xesrA[ounn8Q/|;~5McYvffOp^\]vٶMmۻvZ__?Gkm:-RPy4\) jCSĖ7?#}ʫgUؖ1Ő$-K-ۂxYxI&.BrV]T<):èLʍ_=ipr |VY@5 UZIhF% 727mVҳO;y2}jڮ4˲wW_}O?Aպ?,N?ȑ#a>|xoy[^\8 ;/˲Co}qq\pAe{m w +?pl73'o7q.䒋.K/}ٿp{m5=װU˲y˘1cƼ!8VNJ8aY%8nI}MyT [\iaӦ&gOMDT5\x)rre k8R<ɤB\1yUpBbYg['MUBQuښ4˶bTm;V0JElp][O{?~k>qG?_|.X9&7|NbTKE,ƛ"ڂ=iM6*uJe SF#gJ-kHY2fҨۓۍy:_r;aZ \,b& R&3vQS5gno{T 4]w=FxeEu:W-$b[z/lv]e,ꪫn9|+_ya>s_BQFy}ќ,s{yq[~~ aP,RGP1 MI"85KR0 p]bʩ G$ %a#jX>DEa4F*},˛Z[uOi:V+[î[(5x^){iz{&:u(]MqW;á,u*I5RuOs̘1cƜ`N+t( aRqB!d7?}8}^w; 2F$"ᔈt䎼8Dc"LyrA YD Q9 D?1rjRIFP!ɬq0ͥLi _:?q&a& [48"%ISI:.% єApIBQQ8is Cddb$]DUVPK#qIY {_/I7 E@aXVwFdYvر0 znᦛn[wy}lqܶ}qV—3 E\wuUU~`6RQFyubFs|_=~re?+Lot8I$Zs6 8ߍ4 PȠ~je8+2 (I M1h{௯YL q$epnJDr.*~/Bab`@!XzA2\:mAPN%H72]^&ĉHZt oF'08'^f ̃bW@l;-f4܋<ygcƌ3DB@&aP$Lbh1u%)J@3џ|/K& UP2kOO\0"H9R%(|3OAAI$Ȣ'NhTEYaw{EW^BYa3رc׮];Ywy}}\}'|b۶m{{PUuyy/yN@U(KFy67b׉9MxT/ү}kiB_ vo/ɂ9AcF$Q 0&0 JUB0uݨp*f4A0oۃJR$M.LV*IRaie EV*4  $'("IB;`B!Y4HACpZ.I}EH =Q<;H[$3¦Q'iE(ț1 ^8 ,1cƌ9PfAx}\1̩jlP cP* /P8n2f1iJPƒ$r^ra…/=(:Ac ܤ.25" R(ͥ$], ~h`߆஭?ϼAB"=~G@Nt`꒞PNF*sD1Á&vsNpQQw0h13 ^_\`b7>GOIh9#/wDd~~ӟ>baX'>o|7a1obxX>v?{ ? =k\es(F~BЇ>? PmLJSJ" ۹L3*6ZŬkbX(8!K.kmW'zV1͂YP̂:`|COj֚|Ujc.E-D.O3b f:[OXf ƒR`4 IElh"/ rv)gVX=P̲UM518Qebϕ̼)v*'P\͛ud4Y(Rzn&fmn7e̘1c ,`HX*&M-_˳ ]}kny^}[ޔ'9R1FTmٟ\\3S 3&7Ŝ !ss0]6N'ܬk*2gs0$$,X,,ּ!Ϸ IDATMRiU1߼e&Iu#/k9c'+JU̲*j:CI5LmK:ujb^-%_Uh媺 )Ք™U-y]6 3"H\TR.Try2\UM751{lq:O`$qNE#gIJͮYV-/*XEt9]UĦ!̙ʮ#(*˲o}[_| $IV*뮻ngY#\r% Ph4sg/&ܻw;(a֭wuW$Y-//_s5e8nYֵ^r%+ @Qtjj_q}V. ]eΣ%+C<2Mb;W|bG+E{4 "t!y)8k*}AW "i9؈eR^p[qˡ |Ҹ;T+M2m7bp.E0-a=xivIk6(5{LBw,\\`DŢ"v /򣻆ӷ'M'ZX$b9Y(Kǯ=v߿?,b Sl n[HױQ7=`Cqd0`Iʥ,.4N ⬀GNZ1S5(CpQZBzIggvIlLJ"fB[ABVLuct}?%XAŒg sB,/̦ %Dr(8A.t([4\y3A@НE hx=4 QCk}Y\m±Ŝ"7<῝=kC,24?'aNJ;Ǖ6/,z$i20w@Kt`-}ozMFLtض0b $C`$$ss|2eV7']x!EN1ZZ\eB'[PLeFġC7"QBzd{Z3 ŪJm˙pvyA*k-c:,=64444AQtBN=眝=@ő"6p}P&_t6he!ϩcXaMP$doQ kC8AK&R  }?O7o~= i-=aahHP;"b$,q/4=xcґKl$B=QP66cH4#pCI+\:uvka X=&N|8h\a? aEK촞Rxj @@QqGa~hXJ7[ M|$U144442ÈB^Rp]& D,%4HTd hIt;}s㒦ƴiCɔ;I1"bBQlt|Hb `8c "+RtlH0FYN~l a@Mv/KMz}0 {SFKR4!,,Qlp}hhhhOF`4l%^$V K|SZn R@@($*͵[](>(|ۦ)9NwMD-h4e]{ `aae@|w_/-&ٽKZRVlyv#@"0Ȱ GG$׏ↁ(DtQ n ($T^Y "R d3 ,à i2q ! 0y\6 A3qHrZECd{ p%,_kԞxi[Ƒh$˼D. {CCCCV ;{ḾJL0b`96 cV n#CT& !D'Xa(w\-R9r%gb S~eXNqqϗp!hMaw`Rȧ; m 1EIoϭ%>3̃dV8yHto-5+)YlJ]R(ez0Ąby9jb/vԝ\2]ND=rÞkMV\?Tjc8V#>9Yvζhpl3C@.u(Da@dKF 8cI"&(rX Dq @:Dlm-%pxP W 7.}Ȥҏ|8"n YVhfb dryn!ɲldXoKa I!30r,Tel٬ AĈ }{n#h&f5ZBZZ^5yR煬?)Rz`vneȋȀ1V8zyhhhظdu:M"#f4سhF6Uמ,Xc"W5Bߧ8" Z}1=t$(ĵ&َ8; qL회[y1"$LvV0! :ΙT8 c2/v/(diD݇ '^[O=SKoE}'#\ȩl`ŜGI {(CCCCC|3q^B"H(d,o?oeeN 8D UeS!<ʊk/-$H ,tBl: E&b\ 8z`"b ۇFgva"KνIѲof0Z 8U>2ΒрE<^0ZXxT$fgA,.\C+<*hxe :NLPCyN <1lQ`p*NO~ۖSޝ_THs(cy=b@gzOx!КKI^Z*qٛ^鴟.Ic[MtfDH0B,зqw&4.ǹqBÎzKˊʉ BFvHc,صc7y.C3h(f˜@ EЊZ=7$慘OPN ) /<Z;xcYnB҆FṝqThAu>??J'EcCCCCG QA LvI|gQޓݽghd"$I`0P8d%m۲Pv✚NG!$Jl|uLN4"b^WLYStn,)tV+̈fMAse\+#t5F %5FZaVi[F׎ i'5MxJ{楧v^6\wunZ/e*$RF\&F2444tTص\*0Xa|1lؒJ&]+5&HeXBbYt>Y''7NԎ)jj~úBϤeIJ VeM̤d=)RIMO;+r9fE玛<=2u !H*x52c׾]-;.3&U(MN-R)"ϗѩI5syMT Z$rP糉TI5rNi7vZe}]KF-_uǗ#zf\ 4QxY Sh\'6ƷL<յDRB^*Y3~)7l8(Up1TERyMM %]vC./g=kZwuiڶmm677s=co~z7;;{n߾!R/|=&ey:)kg\getQSuj&JT"5acXMpb#[U2IIj^.5kfmЦ F.75/zEI('%sL*/ cI^XVZ] \7Rj^SL0ZGl5+eKhIm':m=M+'Ts SBRΦ8!QS}ύZ)%K1LY/ZDQJJa-bYP:0/{ݮ .쳟KO9~?N=ײ|Q۶m+ԹZ=G_?GKj}X-x>w/:yȑhHgY8{ikreqI"aRBGAзJv̀~6͎"+\*vCU=;)6-EUQDqh[4K ",x0 |BKT?|bе0&fzQ{qlU<-)v˳c,0 l9]=h=.N:Ϩ}9EKclSRzeX3>R_;9444oOn;t&ښ#Ac4MTA",7/R˟?u}rϤi& 6k['l@{hСgŚqc̸4B0eǚJ:|a{x̋ *u}R窄 /#`e!v;*ҹ^Sٸ_{48UR{>VJ#y%T_1NpboIWIz:<dǾ81!`c';sYg,}h˖-,˾tatM?Oc^]eVJ֬YsW.L믿>N///sv7C=TV_;UUwܙf?\XX~GP^WEt:OOMMz\#VjGڟ%>d>O|{rgv 7,ދɫ@?GKEsvm?O?0 >?jzeqؤoSƕ 1ԈMu GjN )M ýa9Ò@$K "otf%Z"#HbD~DDT넝َ?04#} Y,G>Z-ó0p%*H3̳OuEF.%z!rblryP4("CZ! #ha'I%pdxA/"pU) s脼o۶m_~rWz>t>ԏ|.vF$F%>S{9gC7]@Br IP#[',Z/@$|e1ێ2{wo IZ* L1$6Ph(ҐXnbVdɴ "@1GP[Xʑ1It> l2]x\BTBKdpRZ |nxQ:'1Kthq~nݺ~NMMx㍇?~a$IW7 #C-,,O~C>nzX,RU,z衿Z$`0upDZ/-okfff<{ga:WH`KV?-aV{^~##?_ҋ+~?GK뮻_M;ܷrko׋@*ynbO?4F}.4'4@]-x9nzkʊ(c11_r$0~bLSP<ᤊvd !Bw0hK䓮и0,AōR㘩%:y=A01ft~:n pI. (ڭ%|FdHЊB.Eoy@T]94444#qXZDbkБPN8[u IDATݻK/}~!w}qرNӴ:?.c=ޮI\eN; rnX(<":]64e)A.љcTEYo|J߳̾0g^Rh=y%'7B8`|B4x@*vc3$X(w~ta3,fvGd9mf/|.3펕PtP qT+IfxO$^D '_s׭[/} $I6w}k Iqo,JEJOӇiq/}_ioq/[}ݷoO?eY۷o:WHY-HsfEuǪ~^8`ffNعs~M6 (7xݍO+ӣB-Y^[,5yUQ&m]by[/ȍmUy%*tKb.W&*\+j>RR$SJ7 cFc5ksH>VӉ,CIKE-s **#H>[*Ie zRիhMOմTQ%Nj\.+ UxDaI1/2Jy=MqcJIeGP*D8JR!Z*W:*DVOt5^/5Fk&7dq*))]Φt>''&yӍ]2r Λ| OEN 8uqq/?sֿcv>kׯK %DE()L4]bC)ǟ崖!șZQΗR5cr)_(M)IPuRKɤ\NN>Ǟ_?o"yT.)N(HY,[V.:Mz-oȏ=ԘJ>/~[GJ"E״x0U$8є|v2H#zflb+tO?ںRQ+ے=Fnq#, N>;c۷oǎguBhwuWo|BwqG\~ ø+Ol:W_pO?333ݻ_98X~b/9ZWjxiٞ={.}j#(__q[n}ɾ@O'("UE>>RWJv,XW* %rtS;(MoNK -Jz.]G̨"3Z%;ѩR:&׬:>%1%e}heVLLוMk7|=U-eJB6R:R9AW %ĉɬdErzVՂIՋcr5h ^Y=rJ"/7dL&NJ鑱^%JҚtz"ԊjI9h !9OQT>+dffK/MALLL|;9W222rz}k/ju;r]v޽{o\#~s9*_/~z$bxuיGu_??GEev7I\K.9x Ca7̷:$IXt\aR$R(,*Rsѕo瑻w8o$ h2}4qd(1: @-tv:3$hǝ푸El4w֏}xmT8̾=. oaN)00Ф\s_GwX㼮ϰǤV8hI{в>&Il V9}lx??}}ܳv#agvy"B1Dl8vgo .@M#TQ#T(ʱ?Hoe?0})rsA BHq 7XrL3U#$ۑC#V<Q'(plC8c8N$cKJ Αle/z~N3,,XR VuDȣ};W(=^zKЇ2aqd*5.EA|>w`7ͥ%D5}B H=y=44_.,G0Yn~RK]AsXťL~/fWM1۵=ѐSfK ,GVnD:ԧ>񙘉gW(-0KcrICvNMNbSnҷUJu$M;g$h(b8 p,2jz~D8c ۤH)QSy@d8"MDI"8n8)D' 7w'KKLR島m{~}OMna1I7@,e쮨$aĸ &!'\sa1ݕEIB2""DX? EQ8`=o-B! CBei'Y82Gu̖^acq$Iqx6 (KokʳK^w$@F\tg9X!橒cex7h-ʡnyeX'Q> BZYZtMdL(CFDñF8V7 X6[AǼP%ؓOYGힻ\ib(!l;fY\nӾWvoYQe^,w f @$#DQzyhhh=BІQ!B9~Lb.B8K&n[bsҠ˂9:MZvg0ߣPZߘwJ@T7Y1tr\H} 8w ^1%HH!b""q~gH0$Й Jxk8.BM v/wzj0 h4G7IlB.Sz c(V{(CCCCCUM#GKa+d|?s~#ch`ZpBӴ S#cv0zH1Y49k?AؤC5CNp[/g>zsi6 5k&Γǀ59톞 }$XJHJ0p)wnO|Ÿ5n$AAϓ8*DN6 CC(B$hME{CCCCW A"ˉ^{b1b#w{D[j G$ ,I!PKyP2I`ݾaaن5!dybPcY  `$wrA9mO>dz*E2CH hł`M)X@DfDTw\* +='B$V*ۉ,c{7 ?'6444Zo޾lbDgiv0sF<%,a~p&PFv#1L`J|[<;Ƴ֬;phnuܙ,-ǻK t&uc"(p&NGRRI$Ux:ӈd}/XIe M/𜠀 1 6D &=,<3rFm(>{J7n`K7~)$TQ[~w` I n$a DArMv,@uI h&z{CCC  YtgI]ј%\ز"gX2 yFdXWcz]L(rLоł Qd{``ݎ-@ߴn/p"[ 5{M$ݓwALA@٦Hj2TЉT]Y c;I^%s`BfY rPqF`t\h-ے9E0 "b]aki_CzDn@ r=c ,|WD@5f\4Nc*~Zr^Ko|5@< W@皿=O>g$[lgnslZJ:th2!Y KcMszLgtv1qvcWo! E%$1'k$h  p/ɔy(ܿzU/ڽWS׿򷜸uScl_L&A'?iY`#^plرX,2 S,wl6?u+"Q599yr-FFx~WzzG^y 9}W_^((뮻^?G{s}㫭ۗȨJ^7|E6۰a|z$;RTٲ*SBe2\IE,el2)ٔ>-l&Y8tږMrٚ^(:>=kD.25M*ZJ)uQXU(F4ݘ.g2 !]O+h'T-WsyESd7Jk2RPMR &UM;N?y]e}{yk~!$  I(4A(Pڴomj+P9pTRJ=PWP8 ʠ%2=i{׼?r\`=ΕظQfm0Zcd.NdL{Hgqˀ-K\ME=5GJe,+IdZfNj֬HY\)կ‘\Q`5.6Gr(t{ro O͌iEt[7b kxlmQ)Yq'e)E^_ ِΝQ&]LCKb:6og$+]W\pJ.U)Ixa8p׿]ߐ?͛oᆃzwnaI߿?}sss~?\$Ɏ;l~L&s}'Wyr[n⋷m>W~ޱMN۶_}Փ[uwٳuݗ^zi֭'۽s^}u_ pPehL25őUÙrSl.Ŵ蓥s/yQf%JΚ*kEU)/iU捂*&V-ij*-*jV1ZER9k(mMJd rJaC)3cDnDJ+ Cx4U6|VlWb> 3,#Y*y]Kgsdd,CV]iftHR)3锞TxVp Z9lFMȱS;ff- `+/khf%0=e)JlQ5HʧyJ9ylho'l"f LI4$Yڱw3iԤ+F&S=߹Sw^Y=JŴ!lvOAhِEWrf5嬦IFLJh4DZ6|ӏ=zTMS IxI%b،@ULOKz6-V) l*ȌSp+sUϞXqƇz>iӦSh%'9ϕx+ ԟ{[@?J7Ga yQ v1`  vA ׎UB"%qV^(a źH{xcJxEkBiD浝DN,ڵ2P `c)߃zNwC* Ca%8j&(S_n.űKaT7 9f1 ǑKc1&,I+/뿽0` w:N.JJ<7XR(YBua]'i'集ݰۤihXvsݥTFիV$&`n8p*Dk0Ez&Pl@"Bnu~8j/^OAKe4 Ӎ|0 2/#dduoGBCDE9A$ F9 I Eh^ĵkXZZ?zF=E<DY¬B { ~}}Hxm({]w3<00 |ӦM'O'2̖-[o/[nA>|[o;w+N^ذaÍ7⋧fVysBf͚;wJ~N֭[~铌SO1 311AdX'?y,vW_if%F9 G!MɄ(JbSz}q bgLXY> QAY^@!ȋ# K KnB Qߧ(HCpvH\}B8á P w)~d(`F'Ʉ=|(x6T =x Ўӈ<גN@0#D0u~:٘X>؊7 QpziK3 ȓ8A0Btc1mKց]8Y嬬Q#^Lg! }gP zFgqȅ{UGgV8ٮZurIdI=z_~cا>;pG?mq۶} _TU4On+Z7]0+|C.%\rj%+9EjGWl6x]vtM'۽s^}u VJۯJC>ӝ?Yn NkG)0DcG'UMcpv_,hbcq~GXV3g^uX$ 0JbT!pxGG$$^_` }4cti2P_ßW b>Ch,Cn/hwj]"#ض߾Zt={PôAP5ʰ&p!$HvQ19R{1R2ڏ U;|Db"iIjDlv:F1@`&aFD7;_V[o_t+_ʞ={A$Iknݺ۷Jv,oٲ_]wk׮];77y~'|^{j*›N8oo۶ m۶G}4\)j,d|ec+}?oρ~z-xω)c3l/ D}w(BjijACӨZ2&?kj?|ED‘؉NH$Sa'pVk;zsaa!wzMEY!Ðm8WF|DBYnQsF=GXQNgJPA^(tUt=avH< }ן7(:@))D$n~)pws'{NkI$YB4èT0 F ׾~k%;^T~a~~'~O^[\nѲ,*EH(aϛEcN&#*08G)q c؏^xgO=쓠uΡA Zm/F^#U$y] 6c( S$ϰ1p-(MG" 8x'$AU bfdTI4Fa 4mHdI}| u]FA'|u Æ{0Ν;ol6x6ۏرgffyO?)>E疖<ABaii;ϕo}[7nog My-SG*m*f9]riz׺s&KYۖyvضNf8b%S4$Q4aU)im}X ]6 -k##*BJD.h,& gW[=ъDgĴ%7zƍdfʙs#eEk&KSw ֟Y)3Lv x[XLkeYqeA&I6eIA˥Fu>12q쇮u.#,u53P8jJ3=Lc2)p6/Lgsnz>vxPB嬩ɍF'FXA[a&RVQr6'(VYVu%0I‹떤 #3Ky*VJBK"VrϣZ*馘xU)')SWxE֋ )ѢXRU&6^v|T1-rgLgfmƐRPYҥ׿wn5u5]tjJxJSc#$9vر~۷}-[$IyGy^{{}C6l-[W~̞y{JK_:_ wݿj?WZ7{bȚkKhleLSȚWeta͐iˏN_Ƈ44gCI5NӊbHs)DꙉPӦm Ք]2ңB* EJJf̎ꅼZbJuAJa"c(-k39 D))&[f!?YLMfRQ-\) dI+yeW_>uh4S'(ja>[ [ 0mW^R)},[Q&!IU,U A =K9ANvIįIz__MgE[dTi;[1a&J!RAַq/ls?wyYbZ.Rie>mKnP8jsGg)iCYY.rvfȶ 驌bS[.tWgiQ f19tZfհlDD,y:S[CMYᳯ=yK&%syLKjS#;5SÕЄXU8/n&IO$Bp 7j$I}٭[ @QЍ7xLON41qǎ֭(JիWQ%I2??| N8Ncݻk1 E8w}RRx ]JzROz|̟'7ԏy#\.o߾}\.cfuݓ^9OҺ}÷&ɯ T6s4Mzlvkq ơEi~7b0܎'H_h'%G$H &?|-tN1I5!l'~z> 1"5 #g[:˲L%-*`3C04-Ny@fx$td)'\i)N/ܣۧ^E> ǵjKC w~::2:}5`~m/^mfe$&+N (X]0b^h@rNv-)(MRzTA.A v;t;_t/:W,uь^6m[?g> DF .> ?~Κ-3x=G KpKPҲ$ (qZ_{(lH$r3!1Xj.RS#4(MUc~ć+a<$Rξ>)PgǦ^tW/vNw ڭECzPoHHHǠfG` qpBGP8epި9TJKVHju$b p,*a'gab飇H.ɨw|dk3(ܡDQQFɼ;{:>6RѦ $p@!?tmP`"E'!NA.N-H x4CD :~5?)T?R)dDzuU{%H` ^[#t<`)i/c"Iē,C0F3Iۏa [8tzC2ÓVPN HFR~1p3cmH0(ciH2HNCaq{A FۭZ F.@ A4DT0܇zZ1ͳVƄFMFʉޤ==sx'|Jf9Sfh 0`P.>7_$!*^Ѐ!F0!r]!PIBo;,/Df7b~#G[5APaq&Ip'\mNOQ#(߳wzaá;]~[rE[~HM#{_'I B q8J0J *P8Gw$BP4& %e>)*)좌i0t"8Ĩ-!I. $HI3L7"$hXj-tN3P[vnc/w't=` ,ۭzJ @n&p(|#ZY'lEdf&=MqDAT瘚ێz ip~@s ^O3[l#71"8rC Q!W+bͤESsܮSo.8`Eza3G S(z-e|E]K& G2Ȣ:V5ǟUv2`V]) lu"!I%p⑸`G\?cx.1$cr(F$Gıt'#80a8. .Ba 1w[5v" f '%0Bt8Ebhs:G FA0,HEBe$ [vz2@8 Cq눲-OΜaᆪfa8s15fºݮM$"0u0`uPI!$|NP<2QicWwCCQc$$;,S9A/(M! z7-/c&a ;(CKɆK` /,aRAk"?LoB Ƙ|PN^ _XUwWVFkɩiъ`O칚h`KKSJA\v؋|5RTt1֧x6Ԫgw> @]i!E?{1 )50Lfb($H4Hji&`w TSEP./ (C(X)c8s;=W@MOoocS_]$Z4dZpZ1kCxw.SJ&}xڮ.S"n0`hKxBC&[wMK^Dž{DtB8 kG>Lݥ(/H30 8BSShNȔU;n!ă8$uY߾S7QT'h"5z L<_xO0bO2 `H%pNgZɧ-9Xڮ4\ڻzЁh ,c W_z#vua+ʱ: e*˵%!uqQ"&C9v~3ԪF6}dUΡR4tD'ށ-"ݘIKA! .~H3d9\CXeY _r:8kR̀L6r]O=t`i+"4NEq󝥘 2>\r>12%N]n$3zFk0\;"{aC$tօ9뺵PrN 5,: IYIЭzngTd0ӝu/Ǖâ1$JzD'aDR"NmA``L $ьb{ }XkDԩ'۞%b$C³B^C| OZp >q&ω`Ѝ0fwysۊV #7oų'|VJ~P?,i=MӕJ8p$|ݻkd28?#'\Vs 7ρ~z1/B/~eEˏN3ZbJU3C–Jt.-yRJrcγ|%>r=Y3MX2nV)U׬9czO|_yÛ1ΖcKe$9C=RyrD43#3B!_ps2U3-ٴ2J*'W*.[hnī~ew/ԾOόL1:U.MU^{~/!7!glL).l|iˀ-Ke2C6aѩb2^)N)[|J+^jlPMrym4-(TP3iJU Y05>S.OO\xG=o):GaECg̜I+q8Ç}?p_wc~ 7ocs%?o^x=sc~mxwߧr%?+]Jeq{q]^ںuIWe%?o5ρ~z1nzo۶  Ewf^sxsbp7r)Lxj,?&*29N1I`C,Ki++(DjlV2<"oBJ*GgҕaJOTC,KR*smST REdN82rTI㓫$F ᵬX>gYϯha{͞q4]?{|ӓBZOeUڙ)YԘH-h|Z0t,?xn0`_yi6exVd'eMERpJdSUYm(1MYTqD nX;RR;` HDNg]L3!K|zhfrfhX-Lް̭ZW^*YQQ9Ѥ A]2v e?qMNe|+7MOs%?o3IG}ttt4x+'pa#KG=뮻goE?iӦvELf˖-7^z-r >|뭷^ve;w^q' /lذƍ_|SY3+<~oy͚5'񹒟77x]w(z׵u֧~$~Vꩧ IX,~<J+~Ns^W8>;w- k֬ٹsoQ40Qݴvd!ˉTP΋yS2gG҄&LYjTÖLNÔK"½^3 Ώ\ÕUά9kÆq;.Kb9=:\92ozYBT(Bo0`_yi<,*jRO+33kϱ*i,bȥSL`l4t^UEdQ06-i|Y ȼ*T~k̦eQR"e0H H粈D)i2"[IL<96q֪h~j25R4TJY5:Vșb(RQ7˅a1JFZ&YS2JfV شUΔi)VcS ̔jLiLJ.RE)%=as.޴ӖE i|IME1q7>;fϺȭ6eēeQp͉x Fc$iZr4AcccǾ/q<###˿X?kc=655u'Il6ggg3;;j$AQx: Þ%I|$IyyWy+KLfϞ='񹒟7/~ EѓYVAw?믿wXJ+岒7 s^}$?J{N\330"!G,0p vifOPw^ýnhcl"0(‘ Fc0;B@Mр`4p[ $E+%Z]d!( na0DK\Sp")-uKcn^ (ydǍ8v5jU+×\r5[qgnhtpAğ?g8p|$Bjris<~l v0` .b(''z#6n#@䆠#N|m8FC)tb.A"YCA9/)"$&'qHBZ7cfŻnT$@&K2Kss^)@N/"n/ icP$`XAÉ<Ō^K^"!xPO %(#4X"b@|? p E<p 7ƃZ.Lk7_rqz$'4E(c-⤘</:|eϞ=\s $}^[nO%;Yl\{k׮y۟jP.!)ĉ~ǁ$1f`  OAQG`&MFC8 OQ8 ? `") {yՀ#N껐Qߍ@rZ[j9(48Q&N8"v^:z0ܮX {yowC1DA ZnQ/!H~. -iB]~ߋ(wL`Ӷ+`B NuުwCN!IG!hC q'yQ#.E 7}{=;by:qR= 8n$8Hz sϓO>:aCCCwyc=v bv>fΝv[6q<~?wq333<ç~zffg|C+(rng=ϕ-rWַqƓYVrrW8\RJSW{nii)CT({OAR:7V,L O<0Δe4J镬ÅahA'E9[5EҴщƦ\͕1LvYV1daZL뼖"%HgdgLLJgҹRRyhvߪdu]A#\ɦD=lFUR55ӓ3#Ӷ$Y3!3_{g~]xު1;QX5=ɡjJ5=2 W" ,u\آڃω 0`ۂݯr&K?J%+l!3aYH4X -RsRl.!$Bah-HRmǧt5E3s}}S92g(o,+^Y]Ph ET,g)ddmHdՔ6~]eʹ/x`EصkΝ;B\r]w(ڻw 7ܰcǎ ܹF=Cw-܂ڱcǍ7x8>|7^tEW*nȑ#a>CW\qBhzs{Vzu4MO8ggg}i\Թg۶S\/T=Q۷n{~Mճy睗^zSk7&WXタğz[n[lW³tӪ*UznrQRժ,ӶaTta*"vSҚ\-zC7u^̖Ҙ6Yպ}tn볋 5ٳ^Vk5U픵)6LsNV'oyYZc8q[Z[~%3+bYM*:%R1FS3K )v|V,JM3FvkڜIɍFթ4ΒtҚm-)Ji빯mL]oL-/{OCjZVɅWz'OJ׾>}ճ^|Ν~3*vk׮Wi^={6Z뺧ƾWz_|Na|9==?y?<33~YVi Hl*,4bN`]!ŋ81^)1rxxaG,IqҏFl꫐ X?^t!*(Q\̦W굟(|+~#_]]1I<8y]^:iJkj(0AJD :B0xlpDQ}21111l7p=HɓAs`$'IX}AAQ^8+k x8rKƑGGVie.i>#@q>A?pq`XEռ$xĄ#\\Tad$ ,؊=zX,0$iҬ I4$2OeyE>;iHjΝABhٱ4edm*ƣu$iM`%^2ӃRYRw56+^w׷LLLL<'$QXDBXHR$3y㞂瞧I$ߏ@I ݕq؏S?ϒb'^(:$',i8s p^Qnweq~qnk~뵵9YL>Ux?6vw޾,8 1,ɰ$$(, %Qdh; 4R -.z!F0 IDAT8D+p~q ]wzz[31111 YӰ²=pX ^W @ĪѝN;"3/HF!/n֘x>$6$YH{1N UFkJGy C,C"Y"K,F<{}7GXDΈtQ$)-04` W8 ;~&$<)p"!VNv%,~&Vv<Qa=%޻81"@HCGq?w8>g5DO.qDʧ?%|+}ۭo}=11@81yqAXf*|ot;Z(a(UUq 9J"aaISqH*?=#'v=u}ުL S*OpQ0O,ͺnc2Ed~=eƅQoxȑy睹vȣ?RX$đlj4@Pa;a4 c&65rJIcaw{a#As$?z߮[&&&&zO}88šG RX,W 1M Y'sq P~p! 2N}, PceHrc<a0H4N97#g%@'#yq>y𜇰 q?HpH2x?yB1H2w˽8p|y+~Տzu'&&#MbPLe$ax)@UQ[q =r 1F\A,q)T$_[?#"M{T>~cf SJW_~w(7P$ۿ=ȃGwCPҍ걿xC( JNs'Y  $`!Z#Ons" 0H ɥ/ HJlPX4t.řǎ~_?zbU(IXE.d|BZn < 2II ]H S? CeQr kIrcB9ݵ!,T^1z{A(~Yᨿ+ 290))])5/Ǿ IA*PWWnۼII% hG%EUbтqLF~q,LH {q32K BD f]DJy3/v鲦jF(qQg VGr$ xGGtLXd)YjTZBaRT(&(!ްntPіGA0'A(&sg"7sN$!d)>Q {_Ńr6n((/}Kp5) ,,,o04_BV.WʬPZ"A$JM,QU+)m(qvݜJgEKϮ6FUpsS3U5H鷶5W/kFca⦙҆0Sf|mU%s߾ʥNYިpagQ)mcasmah,\ӤRiҎ.ܸ3b j4+cÔh R˶nZA)VXiA(o&%5lZ_msy:GچM LLLL HS-mm,ԔTY/66l+*Bieɼb¦Ybߜ8U^5 'QQͲ:$Wb)KceIFMQTf7/^t6kdkTYvY۰슾-mvkTnTluҘ%CͅUʴ٘jEmWB()% B)4[Z{ΨL͙ YvLmfΘj-^Hd$zCR5S Rm^t9[fkE*J!r ,[ W-kVej*UQlh+V2-8 ؐ2x Bx^G}4n{]w]z;c8>tЍ7m`x\r%7tӑ#G(:rM7t% kZ;( !IJlM <5,-<' y.3̓'/g3zuzWzPO|enn.I$Ϸ㿡}bHںicnul" e*r" cJ55ŒB[Z)ojVsfmaR(څv=0_)]TS,LuJA4f[)O ) RavA.Tj=J,Wjm2sK5TQk[Tj Sr dR4K9 LZAʹ3cYt۔ MKZGMF9T$]RXB+VeoxAػ@ (d*b3o[m`Y؊lxQJ SݖK6!XU(tѬ^p4YnnfVش*7Jj}mД;>ә}1Mdް%[748*RT_8G1^|v&AU)OYfb$nf9I}ɍoxiiժ`LV*j, ,Y˴Uv!J KnTu8-|`kSJ*fì%JWD6U53JUr0+LPirc,drA6+AXVݬVJ\lҴjPuǃ$#.k{}ۑ$7\yO?}R,!r/җt*~|Gѣ7|u]mONQ'NI Prue%\bnEnbbbb7˰$P8-.u I2J` AqaLQE%U,@87^^Y)>"6u'r$ 3*cUE/LO)AGAIGxZRUVxtbǺn&a.|z|q׫sz^('}ڹsa[gX~׷Da8!9}/4C9@|!wq0M_"8h.<'pk4#H(4ļ1 A&ɚ4 % %%YBYk"!O ţ^ eJ,=1@IL B#w8e؎Ø} uyʪ*6%!p`D4M|jx0v:<WgG =C|8HۆU8cqp`-SoԣiĩtF#O1 nNf,ADhzlnVTE9E"UP~49cd4Ma"E4~JE?aDS 3N(T b$O~>O۷k}8۷ڵNӴ;w?{^^:Q>|x۶m]w0姟.IR|t]YzWzPw]:rz0?}󭿿o&KY& VE:ix3RdXh\ @W52-L10Nj&\sn Fo$*Rg!%aT# rd'#ze8 3"ED1 4bI( ~ʪFRL'7çPl<` H(*ZyNa>#$)76l!vnq/+#w`ue2'/71111<*Jx0Cbe3VeMp,vA'HSeW%Fi2MyA4 J?&r3(K@:<ͯ$mv## *kACB\덭jH4)t4J{Nk^ .P޴Tiwtҥ.K^.RI J] rYYj^i`ffl1/[MۮȜntLjW:9 *ƞ:wJnxe͚gE‹gX4TʖMTS}]g]X? gX)3aKy+ϻpr} =r6rI+֌J\4lW^qfkհ;2 (qBP5W3_gnv NŪX٨`bTSŒ>|ajjgnmmz~IfF4[5_Mcqn$Uٜۺ4yRVY7*T>[TmS/VqiTvdVЮmC9i37ѿv4-}zs[E޶E}lkBgciRh;}bE.%RF,|y44x榙fVL3nV!oPy3 2]7u*Bt6]vu9޳!dB^xݻ<EсvڵsN%\r]w({ 7رm;wGy=yw- vq7>|8Çx]tBhJn;rH=W\ڽ{w^ǹ{'^w:׫GٳǶ`y[o& /i[6ԦktefvjʨҬ֘2y*hjETT7l7}sk솙 3 6w6,뛧ՍE`mYl[kՊKv{^)]kE[ V[ih*dr0;[_ظ٬l&Eqӆ bQ%LjV7VDȒMm4.X*4iQ/[ вk,Xd sJigl`s Cu-ɾebbbaGjvMgղ^*R^,PauU,im Q`VPTv{{]Ayt$SEM".SFgRU}yss׿ 3YUXV%iY^$^eZlE%II^T-lꕦmKrga/̝TIP8S5rj\{ɱ_jA+}YRV s瞹^)ۊ43~xgyb<0[pR)kłjPsZ[YM7TmlAA$U֊"טU*ڭjqiiUV漤7,iMAfB7*Yi67tSCw}Ts IDATW_},,v:7ͧi9ܽ{Yey֭wqGe׿rr|ׯ:e^{eY$I}S:Ї>jN]ɅWiqOSzP;w۟OO|5~}=c況u,4[>x Nb8cȈ Ţ~O$"ҰSFwp߫_G? 8 thN\`Qn~'4di99w"@I$36UHa= A!>Ӿ"PJ%H"F8&Ix)N38g8ge$GY{GY\w{bb?;<0D7t^[,ʲ-%$Z01J41l/$KM<~S. /Q3<PSUdwm1Bab1X/tp " ޘM  1Ȓ8!Aq" ) 6Eq$* 4iȉD~J'qIh#<8)X 1 z_/~0!`4'\Ucn)5F0K< 0O 4@"9 #9X%+okz{AX!$H(O)7pXb>V q1qDf:JHY9TZ=WU,5#Ǵ#3!A9#_Jx )2@( K+R`Gz}:"~_,MycqN b 1#(37|pC\AoMyFG99I- *q,:/h85AFEruS&&&&&-m &Aza ˉX2B+9R*9Q Tz02]zEhcO`@#:dUi"P`ǏI(ѪlDIi,9 FqHDYAbuK*E [w3 ]?sS0+8 c?@JAʢN'fdrwL)iPS(D,` E \},3t 򀖸qZ<08. '0&}5k`/҉_g5}XtIlj4RIB;G "sѐ rW)YW'{8qE8PWF#Vdd8.Ћ($09F^,@0 sr"AALhpqNs;vM//]{#݀RE0,+]s[=q_ZoM'Aɨ!{A(b|aX%)i yF b@犪vα 8F6G0Ʃ|4YVa^(FiR s'0 ) c2|V0ݔMvq2pI$ LLLLL<[(I kݡ;";& ~'<FvG,DDNȈs6︼]-?$Û~?~N$GA2~oir4PT>%(q"d9 cHqs> l#A5l,i~bυ,'EqAaAz/H&GgIKh+L}_LH ?p#pRҽ'%#ɘdžp<`(+ LJQʊ~d$B]vC$ 8*J# >OLLLo:0B ) A" .u;2o?lqJ^ⷭes}K[ϊsQ¿/Z地  -\K^I>M(!H4γ P\0%Y4.WE)0f0%/ +lLH#%,sQ" ac'\ 8|X5 ([Ha HB\wgbbbbb]IX 2eX^ 4%"6i{9亥3'̆^%W^'0Sefr"I3:Xe gd^[GN$E+,@i h<ZӶ0d9#/Oh$2RI:ev]'1DY&wHlv0N(P;vfir Iý0;( )bT%ʻ A4ņNܜb 8% !V0'P9]H"LpdM ʣ ?$6IU&&&&[$ `DNPġ,l~qe{}?YUM=D[] "1EA8'w]pA!IƸR7p/0 $KI9 \fMz@W < Gkdz4d5 "Oҙ; RH9RG)pOU$H5qhw,1N"9 H%,pp"E/z(VG?+gfMLLLL<'| qRc  E$H~!aQh2 @(">r_^28y+Wz}1g2 չ<)~BUB H`@ 2O4{,K)bfM5sٮyw7U/ZA[GMPQhGרclraNbQQDDך{+Ϸ[s?3W3sYGÌbe٩{߁i^I) emEҮta8FUΜU qVjill-"ĥ`30hw |ò1KFYdxEQ,,,/.ǘ_>q: p n?Ї>n\sp{=_~9೟'>񉥥wW]uJrc<&moٲe|;o}ϓI{~馛>O|͌K/oLN;)7$P7+7x/R#c}I^$g0cWAŠ%h0Ch ⩪54B`Ni!4#*)*uѬ V[ ՝K&Ҫs("\Tg*p*W2a_r+~p0BB a,|sYEJ5q܀@ª>>ힴnMNT+*eo%zWM|k߻ i<Kr6\BY?}g\w}Pl1'$77s)Ks\JhNjBn0eȒW*9eXqVbXws KFz\o,^qV|Ma\w(p,3۵jJ-Au?4o%'po]/xk^}u]4Za4\^Q9RtE.j.3ww/Z0w5K¼bѕ{]=z4mn7֋x?葁I<3MEAib;DcJlgf޽<|Od ϱECdU{}<0-oȅ\BX^o J)" dJ*G/yˁn2=%'215I92=j$q**@I4,*J((rRo)88u"O6 P"ڠ!*ش0Al *5\-,RY!7,`LRC ¨g&%ZTisfp<:b>sEϻN&ȁ*b"<4 RKӢ0L $zի\׽vܙ$-я~tz׻^t:.oۏc'.;on>]ve7tyַ@ӹ;?\~_>?ivwUj6/~UX>VVVo{7x}X~O~~wUW]{kkk/o}[gxO 1ۻvq Kn|xk^cfj%3("KVZ|xyϮ;+EX&ʸm7SUSJ8APj 4$ȲG%刏 v+Ġ*f2,2#7酅ttzֱq&,a(1z`#mYV;PU КK\ZQZ*>gZODͷN x6`Hj5DZjyưN\޾p.Kn;wh45Y$6$ qbQ7Rm( jɶ٧p{o:O9n뭕9`Xn@VYL@}R,[Iˡ󾟥QZuRGDM6!;.m]O5EyX ."*j)7U,3T3-w>Qv-BEYE^`MuN|]w/GJBS+el0i X@I5x ;-/dR3  &6 N,\o^?܈:(=7c,:p2!JeM \m`qǝvߑ{< mi,V2e8}7p1ݾ^w5OnnDEEpNұAHFYjna<PݺEÇb5RDzX, S]{?ZQ!FҞSR5UŸR$v=-nkjcT Q xf:[`aTQAU-w=jBsаG+incqcwf0-5#O+̨d'w;`Yx5iKV"iR bk- 4 u57+xp7gsY[[>XL&(wԀ [|yZ ֭[$+N:wOg=u{ݥ^K_>б|>?atM_WX~Oqq<33o u_/FҦx',/ eYv8]P5ǜLlem0̸# rD) .Z gILJt IbaQR 4 48p`\2݌d:X_)T@1/vlxLDRe5D{;|uTTa  X-4 IDAT k.UZr +(BAEn5VnX(F#(w۶Ob&:Muhٟ\An][PUZ1 7 F4ufmRL{+͠.%9;}-s]h J='x"7m=e Bm35l-3!)M`I3pBԖ?3 vL)H) HU \2}y dӼzQG xf5vϿ* C409Dp.s!.tº?sGb,VX"5ۃѸYoJzԶ J NFGжMoT5KE4lT>Z]=慳g[^8дln{ҁ?7tArUNY)T1 gKFk?7Nݿ7Փ[eU-\;'yԪA6yU.΋C VJDP*@'q‘x^}UeQE:a ɎӞq/7 H+9&!yk[O{=!Y4 mZڈYdRAG>7-`qIrPcVv3rEAQari m[vgZ9|ltv;2ZABt%d6v΋ RA-O3زj%҂!e!R *̅Ԥy;v~!2YOq g?;?Q !*Pg!vE3`M ͆šsϿY'_tB-P\6VJALPCӈ̇R"d}2F"rtLʴi4-G^ (6ۚd0vku:FT'79#O!1&.QƑp-Pnhx][=ůzÍ{[f SoDgLtR+̢N!f܎Q%{.;_X8brNlͪOWX1* `{htzSN9essX>I$]'_nW/6B֭NzР:ţ Dڡ#0Ves0wtnۺ'A!hqD5.דEYAD=PR ]ȉ12<,&e/S^40l:'5 `f2Æ20IJ*Ç,LB,5U mSGc6E:pDѥT04Dž0IYjٯ4AgK.NTߗ煶a;5mըAa;MOhr|eW\oE dP IrG O:~?r|ld,0kD [VK}B3(hLhNK6kZh5bjl&$*PzΓrsi AxSɉ]߈oѣk`3o(LӒ@2*A%EhӜ?gϾ#kcZJ⸬8Қjkb&Ljî[^\"jHQ˚T!eg)2bFٺ~1$T4M$IQ%=@Xʤv#0b#0 V Wy^UyY|*gqVeQlۣzpD$ňO;"LmiDd}=izP Jb%)Dr46m/ҍdRn_PMDr΄\ϴ7f5pLTbJhK_K_ys_E[ mb.ѨQ13 n:nQs$pk8nRy׷qeLsfFdo}\t>?sh*A;J2X *,e5|q{#43[HL|I9kz$-_&Nf~*櫃qڮgJEg\Ìb 7x:*㜙ĭ{O;KLp|G*H505!kz`"=ש;YxuM~C8Q1'k9 EtwػgiuRy67̶?.u?킋C1mo8r`6]5MN\7e\'V r <<*yB%!i{ڐ)_zqƻ[[h`BRpH :+3ay{&PLDa\"@ tms/K1JJk0YE~Q>Hl*d!H fq"dU B&ZV-ږ)2\l{k], ng9Zvt* jsJ'QulZd5D-+$i!*KB@6®L4ttn}9x4-k 5t׃՘3Tk6A>mNKHvmzTh~YIǚQ6&QSN9OO'~B)v?䡵^__gw}oy[~#\{z֭[ غu뭷77pxHeql6ozӛV+ߘ{7o6mX~O~e]wuo}[?OjB;>2 SڅT<BIʼnnЌ3&ޤ]UkYI43Yf E(p\4*~$]ӮuuD) $"Bk5ǵ1TL!í-ZJ՞+NL HL=$RYza{RULkʁs-$ü,yfj|YWCB&GM8=%v j*Sk2{/=[w* "!cܛNm!Yo}6cQ 9otڤQ>2ڻ y5q[-<ݐZ7xys=zGr̀c) } 7&mziVdRD9ұiY"=UʰMǡq>P*HzW2 X0P mYQr)1kmQ G+g;f^Kn?ܾ\Ufl 1zhL*2|@F$\\ CUš(0 gIݠd T2L%D, TUV)+SWQMlbH7W%NP5p ~ W1gӖ} Y6F )  Ї/_7_-XF(n ŝ8͒ɸ Je(c* u *U?}4*bU^fi>3}_تe1Q.a*b0lS#, Tñ{M]zɧeiͼl[h5?#ָ,:CCVT T A4Y7&I߲Ti;aTCKcI2Nj:*MH c 8f jy͔3XV!o),095 :,|F!@Kk{,|СW 5cG93&4K.___g<KKKUU---qW\qchccWA0^{-`8>֯ѱ|FѨh$.~Lo{ۮ{>~k|vr`Q*N)#D5A5eWUxѣx;tYk{lwƶw1(LL<˜"RRbBUeYLzۘ Rΐk+?==rj4(p j](+24!,UwE@—]'o|?]t4iUũֹZ0"ٶn[1+ SA4!\Qm.a+Q&1rI;i"!.lmk`L 4L,S XAq\ũx*&bɵ=UrlLfBۛL'fmʜɤE޶(Nô(Yq7<3j.OdٹF2 ) d&1y{|DY8e5:/ din35vhof}nHf(>.?4=L7fUS){>pK -bMRn#󪔚Ze[T|goks_6ynRrR"ӻfѶvm~"e!PU[_Gj-քKiQO7%mM5חNٵeuD&C]wݱB[Z1Y]9F#ݚcf!U@|8MzM7ž\ʔWIcke7>'O; ad!` t5nUlzg20F_ʫy͎xY/|saP; bewg>I|GPI-9lFDxstԼ:ok/IE1;ݧD?)^R,ljtӟ~_Nzq RHBlfK^AC(eRo8ddfXG7]}?޻LGY}9(Yݘǘ~oic3 24VN Z]=L` 34 4 ;=zdǷrt^.8N"]EWV 34|ux6^Ӈ{QXTM9 ED5 PqU=&a%b+örbM5d>_^A `ZPK.y){kiY Fkyc5^mnck#.]c۶|Wp.BرcFo4f}Rrn<{dui'\ ߬2Ϫ ,ӸWn[\pNS @I,;,I Uq9 iFnصp&#)s@+TX6M[iiΚ d2@!*A-7NƾH(!Ԏ[?h嚠1-PH^P !ũ*Tf!5e(¿0Ƨr__tM){'?7grRJ;go?m60m_x]wݯ.я~tꩧS .<'w?A5guց뮧=i:'ItP囆EL˯0[ܪ7(DmQrǘ"&yXs` V|_L+dA( %UA=הG(!*tcQ[˽b2g$6"m <v`lY i׳/k&I-Ӣض9=/i6( JhQkYZbH,ǂ-ti41j9- Gj_p%om<|WoϟvMC@,Q*+őDejz,ʴ qt8خ.#-fIƱ6A6LKeMc90d0E@ljD2p\BQok")iZAO ө ~Y4 +0Cynƥ16)y5rs;$/)] ϯE.*J"ra&1bY 5\mTJcZ$A ^L%%B96(Q:GB&Sd;5lQ7~w0I8e[Q1S-?U ByDXKN-)s|E%KBKyͲ˘yؤ) v3CSCE*a)" 4Rz]w9TYO'ftJI <XfֳIY/cӀ#ͭyV6 2I"͍IJS\ UBj"Q!&p:Ӵ{{msLܵBVQ#xsiHTYN e#lM1JҦҰYN}up{7LH`A>qY߃} F,h6 i#++Zn;^qRoe(rb*u^˛%2k |뫓E0}F=hI5p4{Ue^8 b;ɑGnI5]9ܧMƉm6xhq8X,RbȢZزmq1(Uy52$qv)dDi֜<ﮟQ`{0VaЦ_ IDATC'xh!$0АX kDèؒDE`١G| ĦsrkqO?b<o$SWU:FpJ,!˴J2/@hVyCULX٬*J[?^[n WaBJ&mwMjs!RHcs-as9[]7uPk}Gnş~ȫ-3D"L |.hUyE\#Seʋ4ʋ6g;vPrf;栿#? !,5-ÀJ 2iEsSNdTVxk_}nqmDbvq ȋ# )L$$!a EMKg-d1(4헾hQF"$%H2l{gA WO#7 ,pBW` iK'|$-VuAVEUBKK)'f3<g0lZ#LMI#Ug;vM[[\\я~s\:cy?__+cǣv옓p݂Z L[sR62Ur9R#`>hmϨ_p Bӱ VR6zF>)kR%kR2fR՛M Ce.JQ{fjh2,igPڳqtTH%̰Sꡫ&vOrZ) [h:95wd3㲔nۆِLH ρkXH:Z>G5heN^R&ڞk!'˟r"HH $&iqv;\=3tqq3gli 1I '|sAUyk|wujݜub ї>qЈ#UّV׳!;D0ij_PR?PWFdT i 00ּ57<kŃ`kڀL5=__җ};~}Yz&ujtSR2p:}qDvo9gJCRk)չ@F_Y?0=MxUdN'I4ʺ,Ju*Z\B`@2ڵb6+)KΫFeC x4]GlnmM]C{66|wV7@F!")a)!t !s_C<ԫEU+l h+m[̥`Pwg8aN9}RRTV:  aa'XeTB#`UeDq"BI){+Tln'gҞ5HTcnEe`t*EL&RF, {+ Hc3 񨿴;{H S0P1S۟Ǹ71ҨB{$an #gԉ*0h'px߹{ |Y탾j{za0f8]#?G8_x5O<;i{ Dg*FmU݋shg^D ` ,L]PϦҩiSo~,^V!hkJ4ut[ @AQ4`k+D jYhF&;*=Hc6}8|q0zknyq_/~oESRՍTugo(zf8Bɯl4[͙ixuƷxgo|d8ޛ`vyxy1qDRÐϋ}uE1ľX_i,&#}]^tSZqW/ VS@Fc /٦yNتXB |:+{cG7pSɦc1ͅ+A}?v1Ӻ b~W .`Rҗ]?}W|ZKQnTUO}"zcQزY6Byycj绻j'ڈ7_-X/1(u#bN\&q9lj;BLlW5 (aP;J/ƒțY2fN ®$$k?#?p:q/-ED)2?:x`.¦ D(u7ػ@$?sOd2x/>vYaBJ  "//SG?*|[OpoƇ>!)~%|؏گO<+~nE??'UW]w]#ȅ >O|Cs~С7 >C}C\_SCO_Əje{Żً' crcʻ¹ݽ;H VEc^t'znlh,g-J$uQASWŻ.ՒMh)H7|`=EѸ٫i:IV5 Ŧi:kIkcx<\jgth|P'Mjõv%7.V0]!v%6LB(f8iXN,{xEn;`t$}7nMD r(A*:QTU{m}/-T*}QW(xoڡq_.cLv ! 1~)rm=Y?aO1ka 6Aı!jT a$NR96Y0`)~?)lػ'kllD9RT) ~P*D#'NrDj. 5G_@CN]yž8חf.A RNlYyAyݑ{T^7:}Le+fFZwu*hڥ8̦>@M8GYx_ߟq񶫖#rZV6@.%NċL?뗿M3~'{ AŢ9y^*I 愮Q,UȱUJG`rh=PV#N9Ð2/dz a7l+i$^Bmy|mץFq^q=wsO=͇"T'*hp}Ơm[ Ο;p4rk#kbNÃqz}K}+__bNt^!/xk<UW_Wj:_|>}[_X]%W^qG>t^s9}]C@A īQ!.CknYrӳ0ҝr(-ryQU}9Y=B`Z Qz"gum=fWj !2x_*1JKWm|ϧA̋bC/:p CMӉB%Ӆn-rJh/]Cy`|YYCfl 7lLLlm;>(yJ0W3E-$Z) Ml sp }VVn\QΗEm4zDa$}]7NKOk'&dV]C_tI$M4 !#gWsh4hRjVN}ފÞE?3y駙u˞^DMA,.t"G9x'H1;Y;h.vv@b9/6$MҴ/c_ۯ|KĘEsxY$J/[ C׆gkڹn+gxE5kW /NXHt1"Cuu'iyiaЫd=:Z$er@6jRHTI*K|L^w`P "5M&ko^,*\c[wAiZr雮xmq7{'et`#{i3dBmUf0Ȏߪ&kFԡg8]S$_ykw֛n\?|O`p0b+oG 5[^~yDQ6:BiVA7othU (ZN"l:88fH3z cN| Umo{ݝs/\9%ZObUI$TcԢ|rܼX_ܝBp)Q]ú1+)Pߋ f]I,RLVP I). փ%4NP[!*Ο=;]̗'O.3@hTBQX/FV{~C.w].:a$I1id'v$ @ #d{>`و qUUAŽKa)(Mbe+q[ Ftڝ>=vH0XU4'A1UJc(1뵎" S4);4FgMGР0&ӽ{p9]~8$y у0 7yt t>/9wfq8 9"trGpU|7]^y3bIQjHCةr+0;ihjGsaԘNd L;Ӵ:"qw̉>-Y6uQ(KQyXji֌0z^@JvtRW^EE 釿 ϽuFZ#/y,tR}Ѳj aނƁ,\2=z`=o(J^4cEFi",(2a 8BU0m弪W5j8M U[Їl{VicQ#ȈC]-X;x{?k,B4bi0+A>0EշcW=v_r-[a c^+#YQ4EZ&#g?Au] |F4-p}[,|m#KAģ[nixwĥπzޕ}-L /Xb^{sBqZ?Ard}q֐ozc^@(s~u{ F%P G$} c۶uKvNDJCL9f*t}{硭}uf0sA+іf!>ض$WẻcY!c۾N7JXp|uՓw}_k33t~. Hew7Ǟts,Jr=M0dE 3{ɟ8pٳ]"kE]K+6y28[,M3ԛ !ףշqTKn`-)BI_|Ux=,Z ># TZ3(5NC2Ienzo{.l/nx 7X?,f(ӖӋhUBYXJ{e0mAà5A IDAT2,NNA22Fڸdb{JU_u V_ʟ9v˭Ǯ{YnOcP }σkxhoOdI߹^bP/N'|1XP=iȋ=Dͣ˼aIjM9OGZQȳDBmR7Wt9ɽ^Q2i&o U+E7k4#Qr(dLXRNFNNN;C8 n)]#׳u!"Wji#Cm 0KDPod3_ƞ A**vx`y %LI!a( !ie#Fѭ7~{y5ۅbX'\ kXXݣy*-8:*T))BQe <%UcœgŲ g]ir/wu׶**nv}!q U)-%2Xѵh [-蠧#ߓ [9` U ,PKJk ,p® ZP7:l&qm;YlWV}Q;d1@֨>Td#(P-Xf0&ڞhv@ep6DqL''Co]}oU9o/TN(٪OQv-"gٲ-cB_PQ-Wض>N6 FcHg/+?mRZ1Z$[!t)u,G $$?S-~)PY C?2I[G w ؗǹfYl/Ͷ6 Bz0{We'vY?BrW"Ͳz9M\/{U/>Wfy  G\4$Ihl{Wj\}3%C.$jA Fa7z9+ ~;f( >hd#uPE[?w I4[9ԷXYS\{']ve“G|xD!Mok =0ApJDw橺EjJ4~ ӦɓI꺜ɖAwz( cjڽ''!%, if{Q$ :K}'f;KYl(yaLԅX:F~ 4 a|\ki$JQDgo?\ QD`2\yEōj D!p?o[^?UrD@}VZ1O Gl{R^h(͒LCJab1կ~57SbJ &0eӊ(LU .˪,'Ҝ 69ɚB``}6:[OPpW5`eϰy;tSֱJ5JQ!&t㭨볲VkZĎm !EĘyJvaRkPY11A ҭ'[ASUֳ?VNoDI]{~ۆuM3۲B~<:jY XʉO*B.yC>_iâRu٘Bu]q$ "Ԅ gGXˮk{ۀiݯF)Ar5b:qY`)CʘZ~Eb%e!n:0-ϜzΝ?yN0N^ڴm휳`Z " v!|U20IL+ϝ>HCIa=UÃ0Ab Li }7aQZoyý`}V>tW함~볏|9"YS@i^X:G~/nOM9 ۮ:ȀjVZ÷u ޷w|;]VUبBz]5AjQ!r ,^cްZ6X]pW5?˼<'phi9C2Vt~ĻJ*6Jqj#(%+Ý 4ŃX,c?W$Rgպh ɢ[P`GJgO#O?( GVzq񪮽(mEdҫQ%A<yo?vb u[“u݌֮2`Qg()۞"PFY a{FjP?Զpzd1fdU#wb^,mߙBaG8 b]֭Lht<ŲnmVύYrnzM¼^>%Y7cʗ ?o|XFxӭwɋVu~dV9d~ӊP$ P ]ߪ }{[6l[5-j2LVӋ%BɁ0C<CƷ@V/_=IXKmzcT r>ZIH0[.0!y,ge=ܺB2FM\ׅB˦/CǮYbOjCϏizzM1'}SNB[a40C8HEe1RtM[w^-c !S(L_ePSGRAU 5vnAӋԋ=Br޴mĽ$o~wV3oMǾ#*^ZPA b-´0͔uD7#aݖ?tz/؅NOt0$JjCW緧E\c{-Vacea!3 :CBch:޾ѽբ9VZB4IT5 kTX@bBcС7Du:50^G#JK ZJ猱:(5Vzz)l7oz-B-PE_tVXmqFQIQS$Fa A2[VKIH=/(X%Cm9Ψ&席S?j3jP7D3ݝ=#̩ﭤÝ0 ʴ{;c9 jؼ[> `lWQЖp_VhŌK`!ѫ7wVvi8aS(߷Ŷ2Ɠ8_`v]]s &g#$z aAVN..'y[EW k10&di^x}Dr5.[<8h<N+aRH]xw1M&NRA wy jE[gΞy졯S-HFq2"%][-:#qz㭯ۺ#v@v^"r˜\?Qv]u0Cవ;HZjG8R`mwa|X4dA [D;gB/Wx#ke U;z̋lO|. o\8슟Oֿ!q2Zx6LB_Qgcf+U΢Wto$`D&ȋø5#-V Hwj@Zյ&6W]?ru~c10A% e&7ʫ_"5h:P#v6 RYy}anz+)B38],wPW]u/)gyy>6uyl{}o|>6:pcҳO>wtrnF?jkfANG7~?rBq+ֺiejg< Cg[Ubu`]c|ʣqHas{9ql'O=sgܹp[}cq/pp76Ô$`^#t8kmL?=qß?~ᄚh/xN#0DV(` ̇^ nQE# dPёΘԒhMЀk!+Nh:}Ě'4^3!?cSOۋKq.`lQ_#fuliߊ蒢}UUf[:GY Jۖ78iy}[x8`Uq]αʙc!0"mM*_;ve(ҵ*-|Bo^<)!Hib5JHY=j%~_o\VdS٘2WVGr(0YNQ.ժivL]Z\FFE]riD8Lq&lilLHs$lqWhx Puk Bƈ}m-dbfޙ6ͬPOgۧm>wW~'tJ}3Tː闹縵 '>r)L(KfkgjdPO}m[Y SAHB4؈7M߫Jw}rUMM %dPq I{O<$IǯJk5鱍^{bK_wf*Uh)q̽j>{;(zIѵrUpڃW _yIH~ɰbot8R4Bhcrw,#ă1,^*yYGN汵 ;{i4wskd/>2K'ku%Z~(NWE{qY )Έ'N-B7ڴ*|t3;UUP@!Q`%&J]Q[1nGYhl'ډA1b QKD(z띞=c&|m\Zk,񣏎&k"ɲ2vS&c0ܰkg͔U8pICG?po>|_U5,'H1,,!C:-ƴ=esN'I791T4 V_^0㍰ve!XCbMӔf"@ieR%,&-Uy4IQRaP 7ܰo>0ꪫnv)W}3u3?k]^^6MsyykǏo‚{>s?az~V/J?v+_ʥ%]{7۶w׾veeٴ=E (b/8kl'BjsڮiY5p!cdA ),7-gÏ;dE۞6qV-axnzڞ8vÐ W9&䞇\<*mJ߽9WתR~0vQVNu'@Z +`T]PRXq'tq4隶dN+kAg.+dY3l.1H҄9~MڞeͿַ~%/[[<|h喦+hR)kj30m uzbhߞմE = r*\_ՇNţQT֤ ( KkeCa[džu?PU,+S&R*.&4Uxa3ȌĶR..{;b-L: ~m<TOOzo Ӻs[%oRuֱwG?M^OS2m[Dc#{8ӵxU/ ӚEL:эnCq=Ӛ]QWX3nѺIϾ5Woi-γdYUǥWƃ=@34圷:fSx;;"L*dRTu :yki[e=sH3:K_:t{LNgq"|"!s=aSח&˦T ࢦ Ss^AEW_}rwPdLTԲ"iL$1iT)>)Nj4NNR4Ϊ'_;|/>,ۂ4$r9@3YM/x-?pd`k< Kowtk0It-hzˮ}S/Uӳ %Y !r='t g`PE`eV^X0P  OlʊfYs׾۳YZllE:Yo:6u _BfYM\{8zh '\nh.a/F"•BtW][SSUS:6; M蹒 KA0d-:..ϯ?[bQ 5"$+S۴r+O&Mq췺eVfv;-a+udtY 4Z銬6K/y^o~9ڈsQk tכu~-GO"4`ʣNݹcgTgК57M}˝Xϓa9:010[nqvN'OɁ2 ˫$\K2X['êybmklx30[( I^aB! Vng;]W4K$ U -.l$@ycv4GҔ "PN!_rqn馝;wfYv]wp zֳG<}3\p/t:??y- IDAT޿p8|Wvm+++_~믿{_5\gG^~w,-->|mo{ۋ^iԩS_W.[o3= mE0bb5m'Փ8a*bXTTiu^SH!&vsң:eY5" F*5ʚQfFjAFM["(U*9 ho؜*ul\xX3¡*NgEC Kw=^])v*5])8Hט iVhB2 VN9r5KBf +hQMt-R搱x|6#M&4لM5(DCi3  ].bU\e MUek( (R#g 7Șy2'BJ\KywoPrA. ErKD\8u/}=~C};5ro㓇ũĘ"M16CwAl?kXTgUI\3RH Y)5AN=XK;,r!ζ.tϞ{nRP[womstrdlon[!ʪ,#Nб-gkgudDhf$X 0$ &S]=:/#Ũr4|ۦQmMâR5t[z:5VL7!+M, -@ ^c߹+K< ^L~8I:iOlz;`YufE%jh>結DC5j(* hqjw9k(9ki+^%:"yzTossees¡&Yv8//~xB67}-lAby,z=Vayh ȁբ9 6*AF_cWKa?JFpZ,3CLeXܱ2+q¡r@q@#J0 `BACL0InK# f|ר:5 A&$eSNnH  /daVb y?_b=<|9_u]CBg5yK^g?O~~;[\]__eY8sַD?-ο>gk /|N_n?s><No^76l˷s^OH $Uia4Q@FMi8Mc6\xU5|&Ao;s~nt&P-PIA3䳕akw4dRR^k>urǛ0;\zRh&#<.m$*ci8FۏDrJlh6v5lF:tҨU3LBW @s/_zEGv2 1| 87%ƨXi 6TYN'TG[+? ̰()<5Z/:6.>}9̓R ʘ9T-@!H#n~<ܬ`"gP%Qӊp{~ R`h#ɲm +;|+}o`~drj]p]s7Ȏޓl@#0poܾsUE/mc8LuDJ 9z4lu$mS&yqܷ̃IZt]qd{i0meJznmU)ՙ ;giIXazO*xfQAXóN9k> }q#{ч4rO%.)i;1m""F-xZeޘgexi a.dž! 7̲ ]^Sl6VDnwp[alKe <+*a6 y֢kx}b}~c/G/b>S uOM7YOᵪXY:]Wg|>[K=1t{{ő[TyTj$q*<47iv$|~n%/yݕ/>ڜ}T,3L9Aj2mѢsD}3zf4B ^o2-fRoD\18N`kYiV;iM Wy_;o_٩S?txAP斧EeDW5N;l*PPSJ[95DkvtSjz͐b1iweǹ*Mmx IXe+^'Z ӂZf:H!UB1.-#"H,w:_Q^H{wL dxo~667m,<6ff:~Mj}eYo|/b˲~Rp}}.j=#nll۷o:B'I?s^]yoy[|o߿ig`w#ѣG^򒗼o,'wo{'?Edmzgq1A ۹?&a0/zF@fk֍ryZ=O=ZPw;'4.A@R5&Zi1CԨ&ߚRfM2ж^ߛ_ٻontlCVcB ֮c٦kݹ~ZDJ /4 V`vzjokg^koO QRژk/Zɬ4v]!1ӫo%#-~9?s9.X=:|5G߲<#/_p*ms|ғAt f8l?Q69SRq]پfu46(um3[6[(,ێضZn) WNO?s>05QՅkXK۞5mmu+*oͦychBG"Ksd3Q8:'a˟_s$G5YEyxT3|&CdžNĠP'~4{>4?C2'܆e\ЊhgH,.-q5! K1P'e,)]%Iu$0rZ*&IѼJQraI X%$p{0%4J@2M ׯ K&NFhV554nƌZ$HzbɁ׹ٗv=UHcáY ]352BnZ2Bݕ[Ѥtm(F؇F븦2 r_q+b b>M$ C; oxCڻw{,R|ݹsM MNx_vIR҇zo|??|#ٿ d2Q?'׾qr-~N<ǁ˝E4kXbt=Maߛ Ô'? 1.kP7R8osr:ㆅfh܋.Gtt"KLst%&&Ĭa{!#VMM Q2駝ux((62nvCd㴾.3h@\iug>ɷwg\77VKVyiQCYYVP(m\V3?]/~ß[1>;eo0!d@,oyٶ wwȤ,/9;8}ljfF\RG@q@nH7 CEc]$I}[Iɀr'pͳXf)*Ǵ-CG 3 ya1Ǧq ꢱ[ah\=9LȗR[-5|lGwPiP kdۺׯw>t0\PWQmٌɨjE,\tH !`&P4,aVKo$RlTd3ղ)rN>KM4 N&Kk}γGAq~Y}K_z\fg}wVСCOCرcOyS&ɋ^뮻n0lmm}[__μy˿0+; 'Ie>6]S( "$-bR{ jDCD%M̶"z(O#/?m®3Z/L[!b\P-cO#Xr =!ctEXGY50fYP*)˧Io ~r>w3 ,M`EJ hh)trjbk c)U2Yh9lh] *8.m;QUb4MFLQ5NXSYS '㜣3p IDATRZELw}c4PFPIJNd㵵qBm۶s,/1/ݣ^d9iq\cL6qnE\i+К VWV1hWq~xO@T j.yg`YĢ4A j*UEI)k#(,.HrIƣp>,b&-|= 59UAP"Z &&X6YhRze` VGӶQl"I~ϟAWLVpl-(QTzq\.~wLE[Xu!K!'//]z%;}¤AMáh l h8υF[zRJ {Oh&ĚV֑nrA(}NU>i4y瞾l,舁_}Ǭ!vR8JB 6 Ң „%Y,#oKA|rD=a= 6E229ĦMVtJVi  ,L#dT-^S@L3MEAU̐K.c14RVe8#u!?t੗=уtmʆikBG5OB !ĺn$éb5m?RBD 7t9>œIģdW X8C3!|44a5L\{:JU$ݶ2NFM\qTaplձNȲSU aoyŋa1- 1h;ŀ8N &.Rγ10k0c۶܂V(H-;gou[-V#ΡfrkRRNJQR!lf]DI>m{:tT#uτq2k:BMOd a*iSfjY6T)kuO(reH-c#]XWuCC o=WL"z@ǭ?m۶|;n~;ǗwqFD4)%[o]__|m۶KKKg?7tOowQ}~W+O? lz6" &A۳:d1 ˲ٲ.MҚ_ڢ66FLl*U%Ep6.(460DPR&8iJ ] dUg;t@$ɢvg޳.{^xh8rc~ޚ)]1G* \GP Nt4@ '""ZaDM‹o۱k_ɠ,,yʙq:ˇ=>k(Jsnk *p־bags~"%鶱7u\7gl ZhR7Y*%H8ʵ En0(I-44==5Gngޜn,7}2Ŋ+_g[}wk<_l4SR6I}.!-.hkRV1l6II .gEٰΝ_8+-27: W u↑Tcu sPH%"0UM5kN1Ѣ7/}uD)=]hB,V0Cd5$FE^jjcv[\q/WL{{|(9:JG;Xm2Stװ1psig~-2\+@CU a)2\Ҝ{}pk}kƀt\ (8Ai5aExuh24.hw8SPR"^-AhmlB"9tq wיl|Dn߹$ tӲ)ґE)?ctiBk'ײ "%[m1-/leRh<\3 tgX'eloh,d5WnتƴRPc;1n'1i-7t-wώ1\CK;Y`r=329- G++;W5y$YC-w#feT)!>i] !7D ]6V+^bR*]3<CiCa]+DG-w/kP)Lcn]3S@6eA)n :A4$B:DˡYQg9GPM8„dckrA4 q 5=鮥t5YRlkB'S<p0Rh1G@rs_xՕk+G}vi]ݹ4]۪LNj:nc,)JsOsTtȫ[oLl&%k~,kXDvS ]Myrͺ)\װ ?vg*TbX!ر՝YMT&QSHlQ[iġ21IknOj$2ĉFf*kaStWyU.0lMGV%jhJE?p-*iAzOiԔ" cb@ Q z]4bZ׆i4[\'[klұ(eG@Tgj$T ص}gT 4mShg蚵yx{/}tq 34Lg(_K"ʄh3^ӧ_qڶmn_:GG7ti?ro ;w׽|g=}!^uUysnև~x߾}_o+_?}-Bhqq4կ~K_ҟG~׻1_^./xePJWVV>Op 'f H!XmgEw݃'"> A=g=~JRXr`k:EgyzATU6є@ 'y1ҐyrgWe3tZZEcZ MG9Y9?27b|ۆ"]ޱ yS峌g7ȱR:$6{Ӭhϵ-LJLk ANޝw7 t7{7;V% jt8dJCBƐ̒b jTAV(h7`M4/۾AO3f&U^Nݺus?u>' /z% 18^Nl%q:Y6C]M]Wokҭ=ME ,hmI>ZpRˮфܱV(!2l?U\zp;{jeg}U9mXeMk>V.PZa$dwwY_i]bk΅{?7VVmg/:# kyEu dL7f#  Es̱u5ᇳo;?okz|]dI+|-:eUږ@QyxᴞdNn᫇7YX_F|tyPͲPr>-*fTD@uS΋jcz^ضn+ghr!UB3- B܅˲Sۓ}?fM\b#i|X7nK{W/=5b*WI^D ђdcYת^QʭΙe(4qqN͖Aڲ'LQz9[}K6Hހ.ZzQ$HZ:CAs[;ױƬU!^0C!W>eXE9LA,ygPj'1`.M &"V!z%ЙHْ"(ͲWl=On_|тazn\3i.`%a1%Ae'Ƶ+5SW< cjFqյ7{߯+;42.A:{ЬNrLAF7x枯z%tvȮ>x22΋FAtQL""NOEvl0FK!C_~|;;;;{><&~W~=ySW%[|'O|{Tw}{~ٳg|'|_;c6mll5>gΜ;7~bwO z?3?^G~ҥKoy[e!N8W:}{~Љ<$5¥0a-$WpΪNio6eC-azm'd3xoWy,e';9iT#/v>=q¬2Xe_rPxg?Ok >GbҠ(h:ĆSqxpnʇxh!*7V3o' =D@.MPjnhLMFZoI\pMtprZltMojgAU,cä_ϙH\8 Oʣ{'ǯKΘ8w{n,ڦag'1CE}q8$!mPDAicv7o8|LU~]頮 ]:.Qa9P#YlSJZ5T:o;Soo?p;Z٢VAzq@Fx׏|,v{`4 \IO s5;Ǯvk_Ԯ~JXN%F -6y5uθŅcp A9 7z9xrybkwUh|hO"3ZyDD(oㅲ}kSbTG[bƄ9PZO0S$51X9ûzUYF+~`¹ClOi٥(IGk#0eLh@,9AS7lOP?EWFQ6@&9*/)ed,v]o81=.hsT.;'e%SQΈz;yRYx#}y" C*Fʎa _ɎO(֘o@%f5 ]@pܲm:מ=umx`{_3撚/|$;%YЛuA]h,ͬtx|~;:*5M7{߈ܯT-^o`g3Wdqa̗wO\{ca٪mmQߘQ3+HC>hAt6;FTuum$8*AoYe0u8p3w^C+m~[ǘ%p(xE0_ʗ+Z&ͷ5ACmLdl87$K\90's׆Dl:s OHma*g ;Juڗ XS2 EFlDOˏ~KfMTIiF|pZZ_;i$,u 'Vį|scQb2H3XG,+ \ӛ*$`Qہ GcINhnY9;iQ5m|7_Z>]GZ=9RgqUAވAL$=XUWWj{ Av~7܉~KGxD LG[$ˢiVMZ22( $ʢrEA21YS=͑Ǟ0 tSp|8yD]GaϹe-/!\i%,b ֺ+SmS֯ Alѱ #X]XP7=s>olU+?*A2M9O uJzIȠ4H˜u՚;3€S$Rί׿zG>ٿx>rTˢ!uSzxw62M&cD d'~d+ַj$=4#8#wuXZc:may^u``V:؟$R9 $ aPpg<\|U4 !+?FGE4+t2,}BE'bVbjml.׎3o0#H~7 |jlXqE;cڪ^Q!:m9m#dUVVP±PhZ ] 󤓾QcR<U KG&8!! o=^7 vm`RW67eVPF `q& MQDr 7P(h(H@w(< 8 ti`TWoD6 '*)'Xo\GZ)AXȥGP5r]Qf8 CmNk/9Wx2ozܖkaHznl muUtMv)M17nx+ŽyC_[ҴFj u&Bx4ê]3_1;b1cbFt#!mQWuҿnoLvO,VMSUicCxyд8ڔkӯJ۲uJFrň$kC'86nű _$rzp1\+ -au(aLm؂|s{thDEzK^?=B#(|h{D>|J8K$/.bI}#U]߼{E0`{L VKfk31dۺ V&TżZgˁE1U]*0k^5׮Zam'a2_Vtg^V$J:Cz-P:~_ysn^ge[ IDAT6oZk/Ӱ] \Q{Kn2ڦ\K|@hyG"7m FJ:$Q9:+ ~y-~~D(sid;d^~D1B1 #h,9`Y_tQ ڦ3u J@"' g3y2u˲\DUY*J¾"FlRcb.QzPᲧA1<< #mH*g{w/W{g|s0ZWK> 6VwU]y=ߓ<9kj2^x{_>\KvJ:Yka7Ǜ[ t˺)Kba6>O̧ q[ ØY,e-jsh輡a 8itſ>j\w)͓?Zϋ0I/lV+4F&Nʶp!7qvAPXsIj0 !YH`j.AqBrGLG? ϼ߼A)Ԭge#Ѧ,};kﹺeI-h7e2в}L@ mo>3oc[7_x˗=_?tla3?E{+}/λKwp rluIDsOv( j)!F[3`hqPb;VͷrmU6~[*S?SK°շ7]xÿ?Uiy$+h.U3Xrĉ+ۊ F i{8ȇaUOe1JsLm_k~=4m.U ӵ>̆u)zQ Wn3D$Z#A^ pC,Bd ԯe/>O}>?r@z"h DX~tѰ`.R=(C=q#k<ƱlJpd-ZDɫ}Y9]W.^^;o0#1gT9Z.UQw"hA$ҭ|؊ x`Ra^8w^s~ujx TֆIصeWTsΡ8ʴ+z}CoDP‚FA:͒r ;̆l Aەh<ܰuf|kߨeg;JT8R`ۮה BU8#pP7sE2/|^{aM]TTIܨiw/޻s'/>i4ݻ J7Qᚪ" K'qy4]. ӋZ`4P$!Oy,ʹQoT2m rIV< zY0͉*\S'_uVsJB֤kpBaqJí̓0g?C|dSN{m*BL:QRuW E?yQ.[&i(.<4 Zh:=:pmFG >:˸7u|c,]u>  뚍ۆk^|˛_GƎ.$ղl+7Alcv7,U*n4^,xBhtQ 7bi5*\¸w$H8咄IRV!\z% cy[3u'](AqO~7pT1d,i[)M(94Y],vx<4Rx ^t߹Ec:[؞a0@I+u.By߬CF}=w7WMa EyYq8RnuҔ,شM Nݛ~oooFIrku}߽΅sGCD^k<ʢwbu@]̷/ŗRPm=~0]<u,;VuFUfA*IQ2K(W-gGa7 \(ԳEM¥]5/JjcT7qs)ãlleUzó$K, K£ahIhum߷A`; x% 1 8MAk jhcpEec V6M $U6[cqxD޺mk0E,MIG|mlO4ucl“`4O?u9 Q0:~կ}kn=G/=q#7@6 6ٿtC/%.8KP_PЭTbcCK ` 9Z1-9ʣjsK.,8JXk%E*CB>O}S_֬mF6m0f9ɬ\f+=&X02KhƲ>7_RQ>>~&!Rݐ;gݘ4p7sAO\gHzڱ8ZWU o;ӁA$儨:e!G0'#Z|xpHe($6dbN Ј+4ܨN9 ۃ=G|$'7Wz5[l7a,J Q":2ZkFF)s~uN^4`q9 bd8Ȣ Av֎N`Ͼy}{Alrh<uſUth³A!kcj)<bbjgB^3O6Ƶ2yXzDGemlym/V)mRĊ.;쐚HD@kUX) O}Ovݡt; "tkrނ!8  x73n9unomzx`y8@tĈ4`;FFcL< @=xw`@1LP̼u#`J3{kj3LC# F3FQJp8JҥF#@FgPpwJwZK,KLV# e[,0)%J[O%q[)#cG%9`0dQ @)"B8g1Xs! ŀ={ly(66w ȭVG^zuc<<F9w0rF;@epcG1#  V5!  b8X,{^Mez띿}˵g7 wÍ-eXXWMW> kWՅ{ „4λJA%#rʲwŻx~kEZ+= B Z~V2`,gzSI֕,alZ3 h-uGș);׼nxƭzSֵf55hFrku^.MA n:p㪵VU!ak uC(Fa [ճ%aƉV5JYoZJq%JZLh-4WMo$jTDnUw6lP I[`{ݷXNYmZ =_}E5aĀX7di޵Dz罟O_~zWf0>6lۦQEZJ0MR4N:DB(n|lwj1$Q8\EhC-f}k4c,Y 8^^;ʦoZqsSK\S(M-^xͷpg6a@á-WKPN0A$Pj#p,틢|zmʪHHpʁp:{_w?>'G@yGtp:k- ƎăX}wshwPwxO1J}#{ Fdgw;!D#c `mZƘxg.ZeavbB0<@G;gG`B[UUulsV$ bq} 7}{Grό\Әlk4sVuSߺ_׼5߻7=ݟQ??O1.u$vߊsԋoՏ'}NX2ߟz,F _(ǂySJcp( Rlnm0FV+{1&xi\+eyX]=Нpl?C!Oo?͇ἢD< ߿a\:[u*NjyAo}铇t=Tÿߟ>X\d͓qL"uwkR[h'J[E&v%VMãX;C,{!x <~3_I8^)"`ZԽ$J JϝH㸥hcM1Lv6eמpjG&Ͻo8Q-/FӇ/-RoƓu]:"v/ϓl#-{!FxU"@l!'lgUspEmƙ^;, U]]V,̛7sOg{֨,~]8wR;v3._:Uc/6Rqfgr]mPK.ME]D,V3GڵmP eӏqdrUk F0lLYp͊2vTƂ,&|a/ENxugJ6\8wa}Տ}ӟ A&TD֚մw>^p zg=y Qb;P'Xlf)V ^.!v<@wGMC0#4j5 0Y_6yL7 Np@h_l_m~c훲\ KAp*4wa^~g3W cm("JlD0$',4)x0N2s 8:eJk 4ibAz!^ &ME x'4b6b Ԙq';{Z{wsſ}0o}@w.Opދ|;&Ip?fY6_GexH',-et '*84&gcs]h:=L\|(8ql*AQAh6ZF5ǿO\w_ֺUեg^^$ IDAT"elTb ]s{u9[Ү/]Wn6K]FIZ,DLhU`##AIEM3xG! D !DU$vm@4&RhAL TPP1sc@MU5"#1(H`}U3B$"mV5C#3D`&R3DSaؐE8L;nɅ2Jd"DzvLH)ɠ01*"+nùzE DR0dLFS2g&f* "1(5q.sNB$r!2{Q148Qe[ T}1""3˅c3Q@"03Sc$UP@&f&H%`9Dd"b[ĥJ*L[P` & j`(dQ% Ol ";o|/ mom Hш`ƠHF([E9Q@gϡf Df611D"@I U#I.Ĩf`Ad6]-qS jS5b&BDA1ƠD*ffJ8?6#ucf~Z bJh]L4AK9FbhL#) *jynnCI18KUKsZOdogQӽ}եk{{:]Q^tnux#OfzіE@L J˴Jխs .}9. 4jQY{ URLNwj\1dhȊ4![nJI8.h{q/#zP̘MYq7Bؕ+g 'qпvCO]:?_E7^5׾|l~N0g]>]C Άe#|I'~^}[ nK187f14>,Sv>I.zTڕ<˕͛_'i娴K61ȧj@'fs|9{s.o9|޹s^cg>mquC>uc?m pѶƒowwѦݹNb'zҦ>߄]twbd2~G{uq/J_MtillIɪRY'3ϘͦB߿}Ëu7 '{kviկG_[g k7QͣK^w$K.oSIQUJ7UQ,ί<}҄,;~p)>)уc0wݛM/5DC5΢7bѦ>usgX_qhwsfKn>KKVo!-^hZ`릜N=7"f2WBIݴnZiAhlGMzyz{jOy}o,M/6Ï [X.i%2zFVm5NJ3Mo$ɴ$kEU⧾]#jסnMSM I}L۾O3BOcnvve^!&go߸7tO>_|sWBۭy~x_D:.nDnnІ4 MTTDQUEHNof HyË́)"!!"h<Ef /m+֤5!bDzN$gEP#:3h@/Cw=3m@016Z" $m&I3hۭ4F 3``4"VAӮk"5tV3onj6g&hf ,a4%SдSԡi'i6 -!3J !"x&S%=~ُ&;D:7g.M6`)V6Sd¨f&> ` 1G20SSfoDf1 'D;U짦}'G`\7UFUB˳l4 0(^~H} 4(K-A Y^ـJQ4"f&T5v8 1hr9θ7KkhN1°5E "3 "b@uu1;41bРEBb!Ȇ@ze&,LmfJ춥eY*h`^ X{ l٩v;̧gCU"h޳ yb?/vIENDB`gxemul-0.6.1/doc/20041209-ultrix-tripplehead_small.jpg000644 001750 001750 00000004510 13402411501 022410 0ustar00debugdebug000000 000000 JFIFo CREATOR: XV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d) Quality = 60, Smoothing = 0 C    ' .)10.)-,3:J>36F7,-@WAFLNRSR2>ZaZP`JQROC&&O5-5OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO8t" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?V`"R/61*e=ʙsQ%141(rT3֯|RZŢp G'##;1I;" ZZƛ'528tI. ډghf6ի)4Jڗb@sꎴRVB5OA\S^ *Sʍv3ptr MW.m}m, !43q2c|89i`qD/аeHKsRq K&KƞH g%xI-m$T`v?:ڤXdܹ$)PxV7Iܯ֮LtVյ(ؤ%p0Ǿku;:%,1h ~UǯYJq5)>o D@WC(ˍDeEFW?0EEuj7 !ʿm.4Y#-?\257?>RҮ fGS& rzu(mن@T>ت2hHzMI>.?A_jU[Y.dWjȼ2Y黈dʉcQ$6Hgj Y"H|A+¼pNsW5]N4ɬ9A>5JMI2y-t=zR9 Ye_#smkhSo\G[7tmFO 4!L2GS"GgQtAR>Q2.J*/Xx{c+l+P߅fɣ?e"J-ڝv}AS^G#J,8n'%X+]5H~PA=)?RHM6?Eq#SB^Hiv/C44GC6K9sҫY^j7_J]I.-`ks8E-ί#-נ%r๝764;dsZ12tg|F3یt6ڕiǘGJ\7,gi@FQS֘nSIzS^F_&ABG;pgDdƲe$q$Wc.S?*7D;w{"8 D"K؞~MiѱB=OL(0b1(sXsZm$D hQlH+i3.H;]F\a&STMG5BK+ؽ>qdQ{lNM }3+Uj-"ՙ\jM˞6?2cJrPoshvrrNh,NŹVj[hGvmXv6CE➌qm;Hqc#U^(^|K;c7jT1O3EzȾFDZ9)s۽W-52q Fs8b/-#lюܼs i9+Xf(/arֳA0Sll~^*(`DI%I n ֢+NvUgxemul-0.6.1/doc/openbsd-pmax-20040710.png000644 001750 001750 00000176170 13402411501 020003 0ustar00debugdebug000000 000000 PNG  IHDR m,gAMA aPLTE$9pTd9V! 'sA8 ERj,V'n7M^$3p(A++Z---37~6J^X  5'˿|Ϣ/ekAp s}2 & W;vJ0{`', ~08l]?~?Xx36c" >w5m_oPZaJ|vw=|" +4oU "pQlsφYVo=`Ee]k[Z2PhzoDHaӮW5i{qkA@<] { jޣlM`5% ^'C!?_Ax1c-(߷{f׫(%{; ~000( l&aT`=o)o B: V*K)MX`a ZauMlRެ lF,Gaȫ WP?](c}"] E5bQ}we{KT|p^/-=b} 6o0HA6$ d00($ .6&`PqlI|n#$lgu7)[&+1£l]CT_]ql߻m̧ > iwt 8 ,Ͷz; NxՄZs$ ƂcD07}[P~80ߪٚn?떦Ca}0 0?ZЬ>xV\K9pΕZWr/jw 5 >sJtz]ϛ>0Ld\w_0О`?E OU0,U5uE MDLVYߟ߯' 1[8 22;߈'=|vh}؇[, VF,/?w0x60<(au= :29 D`چ?uv0WU30ً#dؼ W3g0@z_X0x_v@7CAW`4 +]y_+O^07* E ^e"#h -0Pe!\%|VJQ {E^quͷXw :=r_^rp(_BG]~MJR=צ~EP| zܡ[J)kWYL>wF|fi<5 !|LHJuyk^4&|n.pE:4*5ѡe; " U{DPvuSkٯi&c+AޓPkugA\@{=Jow zH!J w:5Jkm_R?j]`0OI>4}/!TM7u J R `S3*a,KT$j}ñBR WHT>**"``97ANAHJ"*bJXz† @d3ʛn9QINAݗPIZJ*)jJkՈk#Tv-EP50 0휵(Uw%TłJ0(ZV/" aBM'Q;0w0@ 6r|B/ Rt\ MiJXIoS-X} ۃ{OBu^LTz'UAP&jJ,bFʎ%apG0vNRe &5vdJ(8 )RZN0T _:<[ew5MzH4ϳQUw }Cn_'%GA%DF 00P.}#UAcJ_WY$  b^J +&tT!HU{)y2,0F00{*՝PP׷o+Ts0kFXIJ|#P^J۷L/}ҕ@5uP@&>b$ɲDd*T*_»PJJ?0 <6x9R &aps0ɽ :B 40,MR_V䟣 UT )T* ,4M )4@l&H|^JՖP&tմLiXaIR*$8c ۇ임Jo_w=󛟨at!P,A)";m$|ŕdbT32磄 [tnb4PlZQ&]L9x&&apC0 쾅J;QzI@D _8"J00>ϻoNT"A10!!4&apC0&4H }=$ $ Z&a a -Q@6 $ d !TZ+GR$a ,B%eA B%   Cǟe- $ lW 4+T*E*K"SnUJvtJsZ͠YRyM.>>= Ņ6*ap6KTW4-TQA ”z11!f1FElKH7+^EG}S]ϛ>8EgQ1!MS$jY};*wtM *Qi| +Xto5sRUS\?bS{ L`v|*G>P6L՚`iaD(& اOOO Bx1L"vH}"OT.*{P9=>LCwhp~PJ4l~7`q ?50~Z&rM0tBC>!8f18 #CSÙU[{ ھ?Ʀg*)Im1X _MM0,}y 14K&SF4Dbrv:C!*EB%a羚_j#8r Hi'y3 &,&)7NNq0N_VN}B_B%[+] B zϖmZkLj2C9uuӈdX3`JU; *eFUB⚆ۑ+an ` \E>D.Oh8"ISQ`4c4 #zme{;¶&4ے+`n+2h fY ! <,J LP@(s_3rD L]۶O;Զ-oϵ0x0&^Myn~Ɇn7]3 ewp=˖뾶A6Ỷ ZM@>[`].p!pC]O۵mCsJ)qh$ -,lM<˶A!?@@G&IF1L >GYJYqwM™7t<]Xc%qWۇY$JEQQV*#=k-~a-0(Oj`AtuMy5Dou lB?fF#5|R7 i0$`6(ۀ_[Y$JEQ_#QS[Aﻃ=Ϫڇˉ ASE4K2Ƴ$/ dl䡡GpmV֐Oۆ$J08MToJl6`^,8 zNTu;qN4,glpg"&h4p8K0vXQH59 ] ٣ #QT{uDJ}PXOP$ Z[`8f^_8^}@ԷAݧ8%)8Y,sE'|>_z CG3U;lQ'U?J()k=ߐ*Q*AՄ`jjBJ,pB)>$0 ^ق&b1_d ˙,ΙwA:< _OA9y)€GQV6A,(cOa0㞊ijflCϡ͸*K} pߗAM('I6 J9P*I-^Mhu|Ctx`p6i6CH"<1xz_xbœ'O74',0$ IDATcjm΂ m\BTzRR,T܋`3b cF; 0papƓ2+QE|/I$iJ|063Bkjl7"@lVܰ>`>ko{7T][ס݅(O!(T,%~"*sٌ3ϲ8 v80L: 0kAQ<}j: օ>0%&(K&~4MfjjZ0?Ml398<6§cNQtavs((࠮*-:k@l.f_ 5tyd )C]7:c$ٔ}n4}D)Tm `=t~j .o4H:}?,˒l!#xz<=h8d\:ݤv,AuDVuұg)}+R`M©@VMSxf}5)<,B)X;#ugUn4}&BmA`z?hu:Sk4y|:4i%"O1KgFcT`v,AULlY@,JU0hu| S)C P 4MLຸu}?SQg$zGhAl}?*nPU,J0hu| }S5~_q aռ M4qfk\DC-Ja}/B-қ)i:avvzۄAM7uNNO AL.yJǜy1*Ȧcpg9\n{*[kS!q:k"kS7]]]01Q8}0@(On:MŜͳY 4g!;K7d<9!"v֝Uݦ>"n>J)+J]&\' 6_"2x,~_ f7G($$ྚgYa:#)<.Y}FHdlk}7}Bb&!J][3F^'nk`1$a2%99ūO14KxcxCq<<Ƹ5-~Km)R`P~ T~An¾hd>!ԏB_wb qCFE2r s, q 7n[9 ~K\ ]5h z MiJXIS< )m/$q[煓ؙJ4cZ[~Kmwm|{˥kAŋ`j(]u5|pSe1# i>//e.b&dà1F1'o,> -aa޶hPUiB_nwLR(ShB_86&E{ {<<Ji§ml0P}/'* eB>aTbiQTj$Migv 1+,d4[s63㉳TsLHVr֗{*JK aޡMԼXU\HU{)y2,Q`J& Y&r*==yDuల>m9*^NTxwũJ{C}]9 Z߷תJЇ(XS5dYHH|&EsCp&#OpYFi»3J Ry7)TA{j*hPJi[b&!Pc*KL|Sog.f'3M0c$$<=h@6k BGSso S|42 ~X?Ma@8;_c(T\g<Ȩ8Y'kq{kf0$Kg>K}^NT}5RD}]tC޽ip ~Zjui𬊾,MR8:I!' LrL  c 'BxJ屄a0$T,*+UK>67is| JELp)!K1KS0|y\Q܁7BMfp`gLѶrv(ڄ4j94z?~XjZ&NAc(rl)0`sJr!039Ø3IJS~> zG% .kiB{m.JP>kcqo٦! È wWƽ./ hS-|!dț !3XTȾ}|[jkk `WZfcL#Ji0Q`*یK 6&\;-ayaAcCP;EL¢(I%L,dXͽĽ\)9` Q+%liFdzm[Av&ܑKOP^ӳ.QJgLUBVJ"~CyHknU0Y^P~H^}8isGi&dq6O˸Yt$&3̜UfT[]ePvzw- kV+ zjd--ݬ(%Ph**,VTsҷA{.@`ѱ}*%XyνThX*Bdk0XCXPOwqOrdP/NԨx\rX*dFky' j@0hs|iJz?]}?Kbʨx%thY&I܏?Aqnf'$3`U0xtTEuBҕIs;L\!K)vlc,X.h5eۃY~J#TR u`_c50KdJY,u[Q4LlEXIہ޺@3} DMR^pC"ȳef5/'g0 %;sapV{6/3vhI5sl%M AK@A~y01cX D08K7߯Pjg\p Nrѻlq`P+3-)Rt ߇4hb'iJW̳U,@-k)Ox~ f#dFyl`.l }08L= DZ 8fK8j,֒. {*=6UXW][lY|Z!z۴&Là}0 Z!Fq)FbXUEXF #lgd|lM+2ؚ&*30lmYqyþ060hI!;C++r*mC<Ř<>6 &Z"3\\ f4V#+*L} Za@\u_xZED(AT<Mf,"{`o4\Ay^08Tf? e9ag<>~b(P[ayEY7 AZ#UiMbQ~|͍C)JZ)`:c`" |.<~X//xONx^k1+F86~` WWdFҢHm6m6^w!L} ZO .XxYqkj1]U< ޏe_W *'[+s&`A8D >Q]!LKrЊL@40 v49 ?szj6|A]%E{L`ڄja>Р5 \pxTݹfw8zuo  0hGIhӕàQ Ku^0=pa[cWx0([jkAsdJ?%0!lN:~KH7Oi48mO0ɔjꮉ0ƶ sMbJC} ah_Yґ;JF}à{fBG(cb AIH)k _ ʮcӛ%R08 `p N,p gtȥR sRl C$Sa528Y$ap^4=48u[Tղf1͐@ԛ1iq0a* _cߧ>WC08I%) h~qO9I' ɛo?DU SxS4N?6u1>d`SJu|⡷)~,Tw='4?/ 7zZRUS\?bS{ LL _a' I9Y TU-Y’A Z8 em4M]wM "ӧ'MO!<&ۛV4x  !YR(a  4pȶ#UQiیQ844à'xzr c$plnMɒ64F`; 9IGà Aàrnf_cۜ] G!IшJƎC8CYnhn}ߧb4 KZZW)7LrN0he|_ @V ^e"#N ?cL@c82D050X mIwۥ~!*n$ vwc08͜FXNϲܗLSJdB?eiDC`NA!!g3`/㰄Ro`9rC -0hi|7+AO9esV E$4<AlQ '8dg`a[i w0x;; `{l2]=F҄$)dCF&# ⭿wטlAv0跄A{0h50XQ""@'h4$K 0A1C Zr] >~o~Tr0hm|7 sfY ! <,J LP@(s_3rD L]U\ >VT$\G[n0A{Q50x0&^Myn~Ɇn7]3 ewp=˖kv4`AeVO?08fav0.P]]]ChdZ6A_9} 8p4dTinapIҁ0hq|Ͳ@@G&IF1L >GYJYqwM™7t<]Xv4X`PzGoRt  ,骩f,j4~̨FkloL*aaHvW?L7{T+ w0x;' `}irbBTj}G4͒l*EB00%yh\Un n# `nogdA% zNTu;qN4,glpg"&h4p8K0vXQHn|ަMӏt@8 ^}@ԷAݧ8%)8Y,sE'|>_z CG3Ux?6{; n#)]av>T @N('>Q$FK2[$],,a9^9.H9ÞIPgwiakoCt۟/4~  fA0< Lk0bi`4',b>h.Md=DQu`&a6w0xۗͧ <,]UgYD  TLLV 4c# z,lUY6'&|s:-77 m)0$1!) a'V>#f?] Z AUu+UDn.a9/1AGY2i*4Tʲ9p041 CqGHi3@ ﳤ X( :NA}TUSֺ}M>!Dnie|Nyᙰ>== c,vbG {>ie~rRY&K*~&OWx5}y(€:k@l.f_ 5tyd )C]7:c$ٔ}o[9orsr O69&lgAtz@Gnfj}8˛94 N}Oyv5˲$[/120OO:3XKx^ IDATNN!$8I'*VWJ2Ku m3,:ł=fu'S` OW9_`)~D}Evu%]3@L/it8 h64KE2cōƞ%䩴#!ORn05{a5_|4f+ruce"ӓLT\+; l"T`ltK4JЇ(XS5dYHH|&EsCp&#OpYFʡmEG>Mhq 6l0Pg}?+4 c'UYgdSzl&!`@Ql=Mhs -Ѡ OSEaט) cY>b:by2*Et rޚ` ɒ*-aal 0ii a*4IJ$ $0I2I(` &s0s)Vrؖ00hu 6&s4Xi#<%{)fi916;pQ6_`0F 1N 7߽fl{Ns㇥etD<+gff9$Kq>ɑ30 8t05ؖڄ&9O3OTX[~@iH0bqݕqoqw3 2Tp1G'&E~Pi'$ W 608hqBS'qbQ&i$",G)wY>g~{&] 1X8)BMƕJ1\xiBcD8A z~0@6_4 ~ф%qʽ ,_0/l6g$aN8"ۧh'֝%t |W9O3aayaAcCP;EL¢(I%L,dXͽĽ\)9` Q+uq'@"ap0hu  Ӡ =K +o4s1Ē< ww8NUd3ʌ*l$TR 1x c!($T8KI8{i13F囩tqOTR1&waf^ڶ\ta<GҠOB2*'fI"|/ $ ͏a v<>~b(P[ayEYrtmM0ho  Yp<~X//xONx^k1+F86Žۖ00ho &Y v€'V>^fV;ZLj/|<߶A{c04˂i >Q]!LKrЊL)!*TAO͆/H+cf%lKH7A,8 x{.DH8 cy|l)'*v0hj Yp* jm>D%` N0vʉJ= N]{àF 5l?DE6   $ A[,80D%$ A{,8.-&a4 d 400083 el' 46\% $ {mMa=:0#CE4`,  [[]j!cNQYJ-1_/`m1XBdpFC֧ݪec!!L7cӘ`FaV.d[@ 1xVA퇨:?j7]}2qϢbCI&3i~)' d`*Lǫ,U5uE &1A!0'1TO;a f ٖ+% pn4 em4M]wM "ӧ'MO!<&;wm08; #UQiیQ844à'xzr c$p^жA{cp .CiPʹ}}nszv5|!b#$E#*; gmKH7apHZz?-&qvh !}3fƑ!LĪ=mׯ@\[ix )T󕺡6LN}8Qr30hi B,8u0#,aJؠĘqg9#m"Ja2rx}Aۻ`v" jà~+z}8 Zu0 A zϖmZkLj2C9uuӈdX3w@)]}jK tm]T1OƦ_^|`jQJoOY̊J]yYMGm\Р ʵ\C#di:0~&8H30X{ 2F(޿':X_17=}>``P6]iBi*TJin(k;4(iBUad]T{jaCt~ꪪ}>&0 .f)eY5a gvQ,cY@T*qob]^, vր. {YSLT/B{骩f,jwN\W҇~I^%0Kxgz%H:!NYVUB %E 8ੳE'Q 9 4{t^&O}Yb- ƃ_ ZiG7@-"AeZWHKk*fR ȨSJJӾ0K:?<H4{sgKJ>N5Dqn JfP<Zs"BB,2W nswb0cF ://9!ƒHwYx] :B]`Ր'GAHb4WIbuL9!E}dڿ$ 'fozdB1z#m{4{=Z`&S5g놻BDTPFb$/Ch-w1A&tڟ`p ‚z ^y0FBN8Ev_|]yˁfLs2bAK(h LX3w& +i0{fo0PY$@(XP՜NAO[j:\bHTD+!-i7`1M]"vWA0 a ]qD8^: QVв ySkiѹiH[ڗҮ&`]y Gރ] 5gh9W8};ZE&eH"G1ѷTUS7mi_AfЂ{`f0&:G0!'ɡ_Y yT',qy[Ñ ;CãIJ"PKReg1}[[0`pG,-THhpy cL^ 4dn.}%Tđ%I&걥}1ӚA _ ʃf@sWكnwNW1F|NLU7p]1V9|JN {d(uWN%ni_H\38n>ZT/a&ܑK^~$ ϵ50X i8 fttST $ -uSh Kx8}96 IDGkwS5%i IDATB!oP~1uOs0'SwM\$ C͎ji_L@`pW,Ob Hx|-ܙ4b2G${ڶ5ˊXRiKbh`pW,/n:c{w{FBP$Dʣ90}A] Q$6~@K(/vT`pW,7~ gQ"DĩG]&#ЍƩ*1 1,(Ӿ1.h^%ni_H%ƧpG,5u]OE:RtMrΙ4NDJg2>oI;abI8w]o7f-hYˎ;G_tg&ܓ}a[PA@Sq"`S/`;OC$CF4lYC*$ a_HKR;0sN _ '(ڕ >%CgNiﭐ^G-U}lj&KnWBr%WJn*li7v ݎ/4.+She ij< s= EA,s΄ E%5pФ(-4Xo%aأL1j,xq,r&q"V.:ə.UKƱ@qǡCڭ]l~R0}|ub 'ިo/ٌ7+[=JTnSXڥ``m) Y,YɍGvuҾ/׹h|Z&%oΞ==UDg\$JUV~O5}WmvVͰڮ${Rr׷M:[pO}^?@a8vҾ"0`}￯a=FK洋fЎev Z͠-`P"D%Jz=yI,f3N`ЂAfpg08?o+ҕ`-m߈[o3>ۂ(T`[\=x=k5CkX+ _9O8(N\قAƮ:{`ЂAepɋ!2#+TZ y Z0f+0u%}.^"m;̮7 ^4'3o}Ҿ 4qj XIZ֜Ԫ ~튚hpk=z)ja`yzx0C"4؃Gӡ -T;% ki7v 8$T%–o3:-F?~`e SCt)qYt)JUpB}n Qſv[9\.O [8M5W ktz#S2Z͉a`zc3 Y ߷ ch[򀶴EnnBA ׇ IO9g@i&PU .ʫĴ>} >UW)B Fx*YS!!EiKQ+&l3"U 9gW؞V/ZAs}y92m©ܫlw:Eh1RpnB9!סa-IKQk&dP. ǁy>=BZ3``:/=9bƘ +'25&ē{5Zڍ]4!WzHĬ|}\<3 U0 $g7F:&roR2 Ӏ(cs|{B 3-9NX-FѾ8RٺAb+ڏBsz;_~&ȴ'h&s(] ) !$,Bk:wZڍ}qnӤ snjl"lCDOS(Z`Pt86,]9-FnsqV3(Nh4A#SLj+i"G!{i&xAe%;DԲZڍf- v:?M+I[s]! }́]b 2쉧[#(ڵ*n} ?296=n䖸NsOeP+UukCAk؝N9(#21@csJ$1JGөnZ O+^Xm!PIlVN\?7PZᜋ2=>xAₗt:=M^OThulB FP q7m#ƅgl9-FѮgp)rz}pS:!;1ہA̯G91kO{kDZcR'"MY"(ΜX-&ѮamՒ9GM?ӡ褳 T^0+{ң\ٌFuU [>.qj8h OF&\(V.;/@UfOx.lJ~M"8I7IIf (9aKQkkE|sXQ#9)YLTRA8sYmQˮ)ofaIN?̉7/dtz@&#edFLp<%Kn8L4q'ACii7vmAa_\^cmΞ9;./2\p{5mk-09UAG1'C *mzbw&h".u!0/faaa٤+.Mt:Zڍ]4l_3@OT])/x%OPxT􌠸ɹed~~"eT8bwVg.K0Mjȓɣ $p`QƉH|٤`:RE[ڍ]/ *2 ޞKN:rN E3n9@ݞe~7ل=p>᪄^0ƎŖ8֠Hk^Oqp'lM"0!)\ >ŋE!u/3{9peHi5gTU ]BiDX`؟3iJcUگ"8.UZ &\>;yéœS4yU/3O0 ITN-Zd,|n&0鰥(mnB;Θ Sò8N~7y7͞=u4"k }1RY<nX)#"IV ̟(ڭfЎ`061cՇáN.i%o4#l/E.ܟHwnrkEJEf߄:uKW:ǍT*) %_zg~lsU=SWzAw:ѺM.A„nvU(&N;U*ftBvhtQSEP˿.$>%*Ͼ,b:! ֹ" fBra6~=:hPaBs`Wv ?"tơ'Eu(ڕk VI WX_DRj(Q  ~gTzG8}-Z.cJr<:3]݄]h Q+96 \׍5zI}[ڍ]Y3J6Xsx_rƟO 5l AOӑšPRĬe=B3L$Uˡ81tuV.]i:2MŝFg ɛi 8 D$Ihwt[M]g21wJيAFEPPc  ے/Y<ǂsQ`@A婲'1`*M儴KՔ?Kvu"S]3VPLsv*Skw᧫tDGtGsC05(1@>dAVDWv]YdAb>E'fJO!@D+[c]ܩeﺄ8qʑ-;-FѮ3mk=svgCC!^z #l {hEp)eﹺ7+D"a19#.IM8 DbEN  #H3S l9YzaΈ4m5AB02^+d2~LD@Uu>󹕴EN  #-c>%I&gh5[(BefȴmlMjurvhA;NP⯜:A۝ecgD96rsNL8h>%'f[Mj8 Qh)ƐwU^~.<ִ^WL(bq,P}j6Iޜc+C#ii7vfp iMx6_҈ՑGTPH E(Ms0'Sw=s&< )yKQ[͠`>'KkᲤ"@'.sq@zZ3i!(ebS%#жvhA;NA߁P^ #L}nuZPyF/8!$BٰﷴE q H89!DiGqQv'tqmpL-H (ڭfЎ3GV o!8wC멈XJS9FAW"^YgM"y0abI8w]^IrfjoU[V3hi0Dȡ"4{TU@#$NE<^@TpwgIhزW3w.|zA;NX}JH덺V,[G< Ð1j F1 !|N}!4+i νGUm܄v"8[gog445dEԀGZy'iJn)ĉ`<8u%%ܺv Uzq a,e-\Η3G&YV _l/I"7MkBӔc8 h݂A)jvTj0 @< :NL[wy|RdX)8QUu,>'&M}LBTZ݂A9^Um/ ʊwg LJ X*Y3B8(ٚs\d&wBnt3Ƣ@ROb#pTj*iPB<0v_| J}f-]V{{TN=_X5[s,oߋj9gsIqN-Yjʏ] 8ԚR$9N|yp2AS'Ҭ2<x I3<r:J4~} P,l G%`ݖ4" `[\lY`{rvzࠀp(x 6]d!S`3Hq$A2XxDeq2v?L>?z^p(j} E X΂Acd: r0%,khX1q#b[ l-V%HJl65rCu (pePQ$:bds^IAwJ}fp ٮ=S%>]W'] wGi:ng-jz~j`%q }!MmgxzGלA"(%̙P!q PBO\I{| *>`+f=1R3z`t(YhnqV"Ʈ=ʔQ6i'LP!đʡH#e*T,ӄ_1?0Μ&T[k ے^A"S.ON iӄR0t)u'0H(oeFu=&0Δ/G*6]+$B R!/h7(ܶ*T[5| gN5u*}ŭu fu* w3He9T^ӿg͈3ƹPiB ^ AȏP%ۦ1s"F,\I1``pl=U[6g|x9!/q.e|-4P\*kH@BA,_JG&54`\IA`܄j&4йEÿNοGL/UyƨHbAMTn\DROH:ފcr%62TZV3hǙD?xخJ-}殥"<|{ oB)RAtQ֠zA;Θ ׷N\wbK!]d0 E|\^\IvTֻfo~aw8C{^%?C=™eAcr=A],W;.HJj m8%T2Cni4gj-8G Q(? l˳<X گpgxv%H*Au;À*(5j M0?NA|;dtBʼr9`Q *J7f,6(͘w&}m)QRe`pH8(ϢdG '϶ ys>తAǶt!Uhb+ӞIU,~R[Ӑ( >689;szW?Me @QdͰ ~K/8`{&α@JA piPzt@c {Uf)_C$s33h Y2;weX ^XPᨩdܑTCd&d63.SЮm!9(oXeXhoZCp!|W9i>{wӄI *3883EKa0(‚_ FBm0PlQULd ş+ǒx#7 jGλu&dd`P"NJ̈́\)3-f gF5Z5!LT{վ`rj˹O8iMmpxԼ/ֻN߄̹~1dm\BdX; ?q0ts=ZlFqց1S\ljω*SYk!VN]6pQ  TCd 38pNL [A#VU3`DLC. Nȷw͚65  n.oDfέ {\R}DyR{Ԩ8Lx :z 2yTOT䬦0rPp;@έvmQ`pDۜ&TJTU×T8M̃py;y}wms38J*$*,ΠB( (xeJZ-qmĪC7t [df#4CC оBܵܮ\67`piN0uhBxdn9F@pvZ䮛}vzA;n#Sו1OxL8Pp ]3{n5v ^^{'naH$0%zשhFNܮYZҕnbŅƏf(Q!F_GԟyL۞adHUpt]k3Ø)˝X^UhZޮFy?jnwJZwJg}`pSAȤ&AيB3{-v[ͨg4{FuӣȡSLsspJ-D2hMObE7R?Q87+y908_H390n'r' no O\dAZ"E)75'W}y+~.]z k  ˨3uƃA/4>"ؘ gh/yHۭiG.Gy?rnwJY790ձg&*fiIT*lV0w;M(JjdiAw]@J\5]~RoPߘR48cvzTmph_t[aUl p}7Tt=%%xx/JaNodJW91 L8#Sol5`$˾aa -zKӾJ\y?vnw#[\S^JLKO9Чw5]>b:.4 h5bYޖ"48vz _ Xn6sdbۄStc.$܄ s4w B|C)CZҾ]~.YV3hi0f}Ȟw@ cLK|a‰ɽ7}_y+~.YV3h0 $g7F:&rV2 Ӏ(cs|{B 3-9NX}oy~.XZaןj.t;;Tt Rrל?!}l/Hc41G=AS4cFXHY X&a>gZc@йsK y?cnw- WQ^mnG%ɕݻ@GD.SsnBll"lCDOS(Z`Pt86,]97}yG~w=x{"|7P"g(% 2TAqUI _XS'hh4 cDܕ4#4``BsŒHy"kjY7y+j~wM͠O'#;*e3.pX@Rg<~k DN;OJR'&BN\_H5ulcs`b¥/${)ȹ[u48V{k <ҡ8KJz"E+ip@,r*zumh#hwu ө9G{D&&blN1Fxx:nGY`pMv_Uyw ZF̈́߶L-3!l 4ϥyiz:ԧEcP0B m1.d%玗8c˹[U48Vwk `{K0qӱ>ZAgb-NAItEACh0p,yy4g꺦M%?/u)',BnOu(8وbY{+ڏĝVwk&N5ق i3Z ءҔ|i?ܵ!\uOD(^Cn6!%Ѐ >m<̹\za/vT*EtaGJ.{F]8\wP@80 "sUXt;=}ij/Mnj+6$$ 'A&&x:D8ysm-;>xO(!s #Y;//9!ƒHwYx+ b%bqNh>0{fo0P$@(XP՜NAO[j:\bHnTΒ܀vT^V3hi0 @Ңs@!C7u{cwE!q# ߵK >gq:$y+Gy7en׻ q 7_☁Gރ] 5gh9W 8};ZE&eH"G19uzn*%qGy7o'{UmfG%PbpKTz HKQbYgwh4u}0С=" ?LB(]H,H|Ǒi8nf1̭z_,~}"\,Y(D%400Be9dNH&d~M }-1]{.Df2w]BE8ȁጝi?K޲W4̭z_gP QXh;*gƾ%uK/@d6݅=^` 4̢P2\"ǘ&Z"1 @05̭z_^ DA"5ȥ+;v?}C l9YzaΈ4m5AB02^+d2~LD@U5D\M4E@~͙[H3ȇ|S:*]C;*͙G1gud-c>%I&gh5[(QBefȴmlMjri7 >ݜU];*@3xHGm}3P ;@ {r(|WNh {2ƈ13  &&`W$YGZ~ ݜU]x෷n3xDGU>1 Qh)ƐwU^~䮏<ִ^WL(bq,BX F=y=pch$Wn wsVu/gݖ&> t4TR!$BڡCt4uQv:U#R\C/# ԝ&| OBy~5y7 *HQ8tT:41y_ 49|G$-}MpYRcOb Hx|-ܙ4b2 thմ nܪwx?ˍyb߁P^ #L}nuZPyF/8!qB$Bٰ_K4G@vM[nsq H89U!DiG qQv'tqʛpL-H Zϔr~M[n5vb ҌzZ?뺞>3i؋0t%Μe,|6$&sg嵴 y7in׻ q %QrBF?:8S)P0Ւݝ!Y!#ᵴ y7in׻fr1zj-?[}y VIT`8VRif:<99zb-e0dL2DaLe ߸Sdr"s Ze&T[pWV'Q)@;J$*=NDKXlm9LԈRRERh杤)}ȧ"'tCԙb—pZ ݤU\> "|7B!LJo&* c@=HMR~Z25|y=sdj$r Hfh,!'&M}LBTZH0wֻf.DlcD)DuB+uT:.@ѢeY-?#mb#/MW>c, */u$ K_ŸML%Z+nS$'T[z>%s=0Q)}a aa礃kIT 9! < jCXi[L8iKek p(x 6]d!S`3Hq$A2XDe.r2v3`?s3ֻfP zdR& $*S"&*= Bn ZVGx5[y x !ck&I >'ZstK`7skW\+*]gp[ptS>0Q(⺎J\k'*4aVt`X|3FE l"5@}r;"zBJVki7 伛ֻfǁA&bMMc%JG;9^z?&R }k+_^=H[P DP~-;REI=o/M]gJۂ<6Q( 4;Q \J3y.<Ut@s>dv 3W˜ki7 :M]4<(F'*uT|yOvǷ%H[Ab?BE UP\K`vz N}l(|mrS &tNPMޮI;S%Hbtg0r_WQƒ^Kk׻i`P#Q dJ?QVW;\YywR2BTRuv z>M*^JTP#;*Uhb+ӞIx,^/P[Ӑ( ^K>T\z GEPE>tgU&*mn\G>mOܿ6Obu"\$ 0߮j5jF LJJNT!#Uӧ>rw8]KjPq܄?H< JM<,dvȱ$j|ouF ? Pq[͠7`ϤiO:%`_}¹OkbAmHNx,dW\V3hǭD)S,Pqv+tWo.nV]nAQy~XDmLzJ`>~;x#NZ;~s ׬Xw[ӻNG|JE j>XApMIRdqu/_y.]:`0k ěA68ܼҶf߄ $*jKQ*lP0P5zϸIkF7{VGfPMx09V6 r(mI0אmz!\V[YQ}BBC"aK΁94#Z3J Qe *u>xHQUŽJۣj.9~@a8vq@QxܭfP MpAA*z;* QEoxؓ~ "My-^. _]A`&};r'm5& >Qiiy3%*Nʪ,`PYVNxjGEGAqD=8_g}Nղk:*Oׂ뿎AxrqHT`p__3hG5+? %qܡo8hjaA[/8z`jh}|F3ȻnQ϶.[܎J&*hhNf6B3d:S$c{`%݌n{92 Otuҩ[6 :/?t)"[dh7@>YJnF܄m$OTScd꺒W95 tѻ yAIvTDuT"QZ~ۻpڥ`Ӡ=Ot0 4 C!q.<O=w)s{{yJOT0gAC3m{!V}q|W`@(0hlfujYndtYQ.%O0}m)L hSg)[0REEw@G;Y |݌n5:*As;*m/Cm: 4Ay. 2xN0bzJro]%׆AV38 t$&,8c^E-McOUs/cXnؗF;)@,TzPSo룫mx}BIG9A FЅ3J!I@9E^,)ϖr)8˙:E3UNiӼo%q{igz]0b08^gm*5tW0S"D$P?pH0ʲcE4+y^Roe!hTyFq=[ۥ}fmvMBM:]˳*qӔu!أUk"-P'?BaHX2fF<)BK)ə`cqޝ[H^~ktϋtZn_QJk;-q kPXj h0ɌcL{8+($Ąd$4I8νtVZLP5iޝEn?K}]u:ڍi%8PigN0`챢d{}S5q0fCUgLpg2(r3γ!niugmy [}5Jk;3fpZPiוU&m ekYB`BJc8VI( r!Ҝ&݂wۥڮs;G>PۄnBk 0= #5# NAaX #hva,u6&|&L%B*ifLMxw!u~mwۄfv:\|ݳGf.n]` Tb tp|k0%+e6k^PQ:4#r\[ֵ TT^F#f)!O߾; c^W3rl0̤_R)nĻӀqݺo[[NXIraixzn9F+uaCO,8]l9y(RѮވwZ;utm 4Ao< N7Sn>L{,qJ{;]^QRG㈊"2rg Q6)oWvkvϵ t:j"PV矆 v/./T:tDn?OQ!4`a#_?͟J J=صb P Lov03PT*/<ږt.ĺo\ˠ󺧶)wBN4TT*T\WMN!L#fе7<[̣DZ XfTT ߐws̝f}]gZJM7Qy0hP`y3Ld$˱D@@ d&4iJM狄Qo{xݹ5>2x[}`A'*}}& vjdtkn>="3<@߇Éc9e.B8L(MUoB g/KcV"y eߔwܺ_[}eh=~jx\RnJuBǿ`̽A0&;&&-߷?Ķ@2*ɲb9ObB"y6K!ӂd8nZޚ\wkkdϲ : ^?DJ tj *uVV-oR'tr&Ib"LdlZ%`ܚw5Y,ٙDQ'*(u30ؙF7u 7I2>@Н ~7GaD4"$IZ>[!΄?B3C\K>lsoλAu7ۄ`pBknu:GV{mR0ذ lEț2ƶgpbcc4O" xs u',ɱHl:nJn~_g1ƨ5.3Qt$36Wtփ6=,Iϳ[ Ee c)H$YN&}.ec{nBnF̂[g ޘQtkƷ ʸHS1f8wS2'RTM‡:\KJ5{M`D䰹ֵ qnv2n&<J-7MkY)"Pi ,T:Wxv[߭9! g;4hGCesJ;5,g3yNS̨Sx =ng ڝ ^73Ŵcv}x47SCq "OeʲLPҎl,TBPV.1cٌ`=,6{' :ݱPi33ܘVEξDMLzތ |}hDFR6rdreRRTON4Vֵ 7[,>AJk$ㄦe*+ve*RZXpReťy 4Z4t}Ry:JY墲]+=TӀcLҟ%wxk@S`X_H]lmꞋCUH#g*OfJ{Ѽ[k7͑`* n\NPiɅ9 ^VHe̫rdzLd g^^4V>kg72 Cc&*uQ oh@Y>qLT'.u%\WU1y94{;kq3wfkLTJuOK_҃*̦ f,!g{./wJУ&*mg+Tz:矮jɥhNۥEUs}gZk;;16[ЏUww0xy>LpJWq gX }_g&tםyA 6 Y8 lW<*+J骺^.%k&n7&*]3h{ 0hePR3VM4LQi ~4>620Do\tMhU][. L(!,8Syߚwۄ%J혨tEA |1` !Bb?/M}#:Z{nDk?܂4yڄ* 4}(Җ& eI&,bt{P]  jZ>DXῨ@S+,=Y7^VT\yEM-

1”))M!f1,Q3ϛ>|PCJ n6z*uZ OO?F_e!4CHz) !2y('U^ϛzk}D;Y5.^/TM mXDV0Q@$%(ك GS4FlPɯS?Q 34MzO#`@dB挜~b("h 7jOȱ?s8"Zp.֖`Ui}߇' !N")Vh =9t$u }Iyk@Ӊ1. XV]]$9c,ŌSJ McړӳDߵLՖAJ5v|܅JBO>dpߪWO CA<}2ʄb5c,`՞?OO -ð524W뷝wTo0Q$cq| > UOha@p ). .ҼX L)G^ adzH`e8eGay_it2:&uJTԩ#tbe]ۄu]'a`J3^7r 6Dq'o)a}Rkbm}u̠JAg;&JIF^ u 0pPoV(\iV2%h04h|}/΂= <:`` DBpBJTJP.RJ[&EdۛC0Q"@1  kFuJu:73`4``H#L9y(Rc' ӦPxzn9F+uxCҿ,贝svࡅJ;CTnR3h3jg w۳?%;u+Ee2Ϙ=+R] 8fZXiρe:Ny3kStP ܤPi-y32؝Թ\?DyЗ)T9qag'8ll^,y:-z՞xm zzORwB8&ӳm}Dݘ#l=kRg#9'*u1}0V0l1bǂ/bۛeR3\퉔*=P 1}q]3Zm}e'vP0IDDMc&`i x<@[}ȶg;K^קI^ft*5l/FU({U{2T '}%Y%7 Z 3<` NWeR瀳pmB~!mBs= Q A_4ƬE,g1@ eW{ -Dl pXo&N gS՛Ϛvb_mvv^OUjPs^5ϝcZv?V_,ILH$e"K0-H@T{2c=Om ;]߲} Cl;$.Z[g ޘ>|- ` ~&tu&Ib"LdlZ%`T{yb+T/ִrM0Emk439q 8|C g,|W{bD8*cNDNŰo"q֖Ğ-ˀAƥeGQ8 r]wϒAϦSFޔ1-T? Éi]nQ%SNop\J VpioZ ۮt-d~- )gט{Q&*>w܄)y-:k{"f Nph$J4jOX͈*#7!2n0t! n;b{p׻#?P}ScMTh.s Doic \EvjEY^`5, |o=m{]z2 "I[VlRE*:ܟs#Fg JEȦn#1 A84L1K&!l{՞3AvM}ˆ&cl&aYC-}eo|ΉJl̾ p); s-rѲSP1Ì̪=h@+sa 0U0!21c>j䱅Jb '*n~~&O 7aO`E^YAhpZrЂbyޠ4;d1PGDE*E5I U -]6aH,Zzd_|vvu@sA893N[c0R)WtَPưHztsN|r: hu2(K,o"Or8#f3썶UtqHIMYImk4o`۳STHL)\ ',i^P`2yH;V[ 4x*Ib A33/2A ̤)T=SӇRb]ǷˆҘqR.EV 4y:` EJM',=AHҤɸ\.spjO#lBTdPJT-]6a#se餡*񸟤P) ޔt+qS"ESUÙ&ثNneo?:caK Ir޵kj^l;u1x[w+T󌷛Թt`,G&BE^b UړрQ! qC"41MhHm]{& < 6D`pBgmŒ4RHӅrYTbUaRy Q8B.JtG0¨ψtF%_St6_g~RglP=Ko5\[:'ˀApꤚ*ɗ /IJ*W U'SBRcÈJ=Avo֏ZkCNkӋ* v'*pgnDIk9kֆ48DSCwlݻ* *= *]ɭJ*#ÙJ}ϗ&7!؝L8NhX2[}_ .7j*= ^^e 姲+TꀭzL%N$\{*%6xy3HyD}jvTzXũ\8T@RR)Q)e&Iޗ=&R)m]6a[_w뮝TKvtRDm.TzqE0%r!RU*W0k;g-6]te-p]9PTOq΋h0h2XiSwyKX 'sHZ>qLTw2v޵o |kvIDATxAJ{NLT`j` 'iKșJ 'ҵ'ʜo;3nEA108vzm 7abB%j0}\*z[H tnMJl;&*7TN- :y Bz^54JX$K#RyW ݼubMLEyE)]U2˥,Vֵ TT5qc#L/̤hI\~N5Tlyk@ǝ fX%``|ipӅm-M !%X @hKSϴ :[aNc/Tz|BZK`z*zyAg3Fڒsug.T:3[te٩Hh :W$muJ6VFVc >gFқQ-@}-FkPY9NTڶ\ۣq>WQ -TZ`nh0`pwˠ`..Putedu PI&˾{UyPi;|z4{gwC8~36oۺP=òCWCv޺6჊ö֖~})0u.xixֳ^ϳgxRj>=CG ׶֖N43&!qQC)E=jONRw[N{dR 4¾@#!!8e18 m[ۛjONϡ| 4a}@e Q&86FRz#ړ?aAXRv2t 0,APZRRGS4FlPɯS?Q 34 4 < @dB挜~b("h 7jOȱ?s8"Zp.֖`Ut> DҼv b߉BBY$ Q<A'GBOߜҿ0i;omh:@=??N8B )R䶝 4ip|0 /geLIWLBZ z7 sPA(8$!ߔet) RAѬy!JVYSȫ=GdiF8$MK(\~:3~ 4{xte@2fF֔ \L1FP*7ga(4Ec!A] ~-MǥΧx<&D:ɖ~w!?(2F3AQH"'31I.|7q\WQ!$I WC}-M'ceCU LprD|YF՞d{}S AI@8|3|= 4 c6cX ` :qT,#!WbQR}B9M&ثQFXk|ww- ]F(==q}??mh:-#؃ 7b4+8<˒Ƙ`,HjO~!M>N-tĉ`Blz^8{PoB:&蘁ףˀ~"XΓHk)D`Z Y;d`{`ۖd8t}-J^OPqN[.[*, ޏQ0|0 tv&Ib"LdlZ%`T{yb /rM0E7@1 ʌ1MlAg #Wz&qhl981(qY,س! Vp-Н ~7GaD4"$ޟtt @g jj:س%A瓂AƥՎGQ8 r]wϒAϦSFޔ1-? Éi pQj6,)!8`8jO1?v&pvdN(8z-Ezѷe쭁A(t>>H'\(=R^Ӝ2e#`՞c(>C4e,y.0Жwˠ`a0 B2-w V l NP:M==`UL,d~- z2HNOLl!IM$ XRQiW;``t|4D.~kY< jHG/kt>#@!ҔۀZdX 7(B($jOlxl !Hǖ5[, ~RCTe=Q*)F !2Fbnqh%,c C=٣)f ?0M(4L²4T] h3<'|)`p fTn<=n}8Cvy%qL8wWַ  6b`PQ^emXBPV.1cٌ`U{v/*f041q9!ReuG7=-Ry/S l(B$B +Kt#9Ķ=ow>> g|%G֖G9-%V"/T! ͤp,a.P0jO2LdJ4p #Jc Kq=omhz$ޤOBM>,UZAH\ɸ\.spjO#l߂C"iyB)R&\!Dmhz oʿd"*yX"Dċ23LWOx>t;”2t2i\[&hzt`ʪ,GTBE^bj U]ړрQޫ ! qC"41MhH^+a^Y זzmxy~E[/ޅ'ˀAp * U9 %UJ*oX l'SBhcÈJ Av=DEԻ/I0`P 4_c_ hRXT<%b+VCTyJjO) 8ɂQطqy o%E[/=y<_M<,J!T]V)s>%bV c^!BabB˂om7@~"0Ж׿bˀ窨x"˸T)bHݽB^O0U bJUށw=7a-e`o4KG=/`_6AH^ɫRhUb|iQ쁢ړX. GpRT]*Yč:@ӵҁd Xu\-=eA20{ j* c/_ T-ћ.W@RD9OEbs6N`ӷ!p0$IUCQ)]d۳׿`-7Ҷg2&Y_2PoiK9MF)j[eqAfw! ٜt?̯}.vi3mh@$XyE2ީHmURdG(^7V7Wg a@ݼS 4]m|)0yeW\T[4I ,PdqBS2|5zyiNA&hR:^^e e+ݭLǯ.'TAVW>}528Z-Mg?|*ޗ?UqTJkJ{IO߇ &6HSƯ}E %2д K~ڿj*mxK,Ya^L?//g"UyNGZC`WZxf8V(}]N`i@0C}j 'iKșXJ7'a*\ Q t&h@*}\H_ At.nJD`EM-M`cF }C,KW9JyeDnV?p=Ga88[KZ_@ߛ`Uhg*+J␱^./UJ' k6 𒫣 ej`&4\C_o>IXK@iBӅT< %%_'Q#D45S $>DH~Q 4)¼5hx`P?܂$;g kj =t4i0`@&M 4h1F)% 4i``p]"- 4},0xM> \wH0x6p'>7}ykޚO @([ּOAţ,0xcXzIFoykާt<3L#rl۶a)c'[ּ̻6<=?L'W0&j+ ([ּͻ.Hp,AX]81Bg8&gs|hޚpޛ`I/Lk`ҾiҤ~~}@O`U&M>m 4i0x!UѤSF |U<׫`atIME IENDB`gxemul-0.6.1/doc/debian-7.png000644 001750 001750 00000013140 13402411501 016064 0ustar00debugdebug000000 000000 PNG  IHDR ~cgAMA aPLTE^ffZ8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).IIDATx;v۸avlo.Ӹgl!ǵh|ثҲ!QXO<I b3H't 6Kϧ?{VxIS4h5x|vkM@MaC|F)l}RSk4N58㿄C:-vn2u8[yjM>u^{8._i8H#9d~~:6)8L5&CD~}ko NW)a tJ3&isԠZ}fg%{o AS=D Nϧ>ktǩ^~Aw{h9koIAKjݷIGC!OT}h~;U=<)t3 i=A+ 2`&?p դ~׮1tzz0h4487CS6o2&_?os~^a| NĶ?i] j-~O4hZ cyn] cs.񆩨s{ 򀾈49נ7 ~05&>4zNs_77CAd=&ڂ@ph+ݓ>p?݇>#UABX5h@FIo$6h 818jo2޼"&ul] &h@4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @@LЀ4hhhhhhhhhhhhhhhhhhhhh h@4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @4 @1AЀhhhhhhhhhhhhhh[ ꇠm.4 h1 ~s~-}} ^iooulY7<iz> <xhr'qilD8Az9)M8lP<y ګQaVנ58Qrmkd^fsEӠKuԿ`wA^ܿ^l0l -"%EDfφeǠj󸻕1l^ne:Ld:ՠ>A*i^Dl]+;xMo6OdM.,eA{k m7갫vNk GrFzQ~?k5H՟K,5%s*KZAPgAg4tk )dprk5_ԠJu1$a:\yNQ.]5Hė4+sqNzs {^;E }C`^t>/i0A9*tq (Ӗ'E>_ 2nwEnL1,h&Ź179 FQ`SÏ|1C!ms48cb((.K S${n6 ZW!Zmn^YRTX_a]N*Y$oukj~[sx=﹭fߪ/ĺlx|h5+= ?wiAhnMQ|'47(O֠pۼtl2xn4?]ixch?Ozܷ ]9铐AO1xO{c0nt& ҫW ih0,i֙4F4zN5N/Ma6~YaYkPButY `ڳ(?ar.s, u5 mJ,Iȋ3h؞E_/Yi7_ |2Hdc4+lk̿'g_㗯a._`m2msd }]hp.?7o}z,խmYqt퇤}~+|Tym\d,5Bzv.Vcp@MaNi٠^zoiP>4"b&Ӿal>Wjpqd::iN߱*oIPk,u}$1ڸ-A#AG?|4 @4 @4 @4 @4 @-/W {wCx<sc;տaxe|lBk'8\\6j|L.s hp]nP`_X@5n|"ݗ _*=jp 4hkbhhhhɷCЀ4Ž]]l:oKۥACr .k%_꾧ćݬ5 U7:98,ۥ͞wР}nn˒sU ;Oj۵{ uh5_qUw3ivMœ"kt%ӷ*T}NݼU5ATuh0h/]bjWX\Uץj mUjܱKsqWIsoUzL:4WPT2qV*WkcA;fQ =X6h-4֡7]])f ;xNN]ZL\߻ =wr5tM2o w&{^UYM }).kPG+5 "Uם))"Vߒ"Tk0SD.kWpEj7[alkP0V#UTW=>Jb=~Kw(c>7nQ)㣶G_M=&ڝya7-U4-v9h5(= 5E4t,rq.~aHowA3ÙK̲p&נ 6W[ "2^{ti𾯫A qßzLŗ 4馃.h adc=t˒{W,"frzN٠1=ii B9|AP^("E;xnnC]aTa!V/C\V]Ta\[l~9׷r4/vxic<~eP>09VY3?טAG| q>`1hiد^ne A=gՈAg` '\n#/ v ]`3wfn6۪6g^nMٙn^Ҧnbw Ɵ`z3%}`4.Iȇ]3k1xB'a?i L#2x^> %1HfC ^c lM Ka̠T= 'bPo)\Π#_4>R84Hn .X7`)VoQ\7hV v,a Ɔp{7xW2l͠ 0V'ׯRӪ+OLJkxaa4Nqt%ݰi}ޏ0~<:jxoltՈA?wAuAu Gս|a'G BپAatӛ{FejyÙ۾Y>t4-mj8>~s@ny4 .>G3p W]"U5w$sG.T0KQ8|Ġ?wiLl R1n7L~~h(?Μ#pѹq ap &ݧ 3hwOm, 6lR'QU1f0w@mBN", R6fcpAsT:ᆥ>Ř9c1(ogpm^c0w@u̹ ά`|8 UP~89_*b_aܻ8q30YE 18(̞'\x@z=17`3 wȏwH~ E̾N#p5sxCw4}x6~%9 7=3 d~L!\4ݣj/I{;]Sww7yvyFa A"\p0n%- J 0G0 "b. 06`bi!l.\bPN ?`xٰ aoFRd&~v2/nv.^7H~_V?`~ڛY^]Rh.oӒb f]* gȍ`l2APY_8QOTU;, f$w4藹Nu_Z7؝e-PwJ[ 0`~eA{a&~v678ݮng":ba 0 > AX0, 40 0@]͠g 0 0@F@a 0W̑s5``a 0@aoeE0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@`@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0`0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a 0@a +KgZbt5;{` ެ"b`Kau`0@a 0@@.2.{. 0XP}JK5`PǞ~M{CtIME /0WwIENDB`gxemul-0.6.1/doc/20140803-dreamcast-bios-test4-small.png000644 001750 001750 00000062351 13402411501 022451 0ustar00debugdebug000000 000000 PNG  IHDRƏVgAMA%`M=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATxidy|Yr]iNáHE1"Fq$J, B A dh1š8P,f$g,=ԭ[u9G۳p"̐B{w{ O{xH?1tƅg䃇!~WF>[|f?w_߾Vg*?'1xL:b$/;1sKe EXMz+*լf~ 49 G1oAGĪ\{ |q][J7'=+ҮQr TQVDc %~B$̷ћF#!ST,q%[տϜu՜_M·|}Vg7+:γ9$G;f,+u{: WBp@ӌ6nWS+w'_ ?D_英+^W]ԛlVNRɕCJс{ώm;'~ң_z~]{x gtfՊs{GF^J8gBݙG g?pg#yjc[=ÔFjLG ok/xsQX̔ <ؿy9[k s[oQBSvLGVOi/FV/m #+)Bٽ~//GVyyi-]mՂͿJ;Y)_xj0 uGegFŰ->yn {ُ?3 9"J| wBIBY.e|puߚ_G?h'hݙ}C?5ӄ^ v55:n-?,޾:at}r];Oʝz> 8u0G C@~W>] sD&?tMEʸ5)!4x&8Ke 0)N;ip68#:/M7 @RjdBL$4Ke@I捦BLQ'L5P\m*B)]>q &S8iEX>R&/oI1FB8㡿Fk|Ȉ4YIύFcI׮^v3{ycI~CU?????8};6"g_{cx+lc@{_Gy/[;Q|z/ZW|=;ߡ !/_//^t:.荍=\Ce4]G.t0ƽVzǏ;;˟ejrvc !R Beĕ'oM/<ӧd2)"xExk._._7|mcU(7aZoE)uҚo;cn1F'o ,ig>DoIBIML?wg)]1hۀN&59F(Rl˅p,cyY`UDE`k,a-]@zm'`|+Dtt0ƔMSu /:@6*Jpe ! ƨV@~ϻ(0R9(ө*K >r -@T$GiDfMӄ1&Ƿx_6pM,*/~cg% R&l/ 1B(5\8#D fe`e$["ԥbע 1,x!8@)R<8锲<)67QWNa&L @ 7Vby.FVn}=$AZp:j$@]LRcDıKA7p Dp Ƅ3;YPH T[w4hPV0=^)ӕr1弗f0"!D-KE{`hZ|Vʡ1kyܡ2! s;LPFO;u^CE֚J kZZ}N%(`P`-%cH>5vt =Y)C5۪(I0{.'RSj &(dQa : "03<|ͱ:Xb P9a i,%>Ʀ1;sx<3t =h|kZ@caO* pN\{y,A@$T.D"bK{\fJhOؙK!bWdJJ`U>ua~ 0G!` g0I9Z(&NRii4ǎXNY.ptGPQʕ2Jnx9 0CJpP8Z0+ ;޺;W: \ I*SF'pD>s.MSgFٙ6c8%: $_ Hj@G)Ji<*cBjy0aZHrHLMggWz/fKlFב"Zz\f]"@5d*L&%.l"Kc$UZ0=f2*"I)2",ȅ`AA92(hH`C@i8cPc t45^bP*~A4[}Pj"ryF#NGQHfYNhL5*T.MӴzC:y 'a9 RJ2a$jDC$ hE,k{I;TӶS3ݠ(e֪dbntwf n@և,4! y`A)ے{F$a~ޡ,WOg{a\dE;m+s<u<". Dupר7VH&(T5(RɗN.P1ye4ޞm>n~dLY۬{4B8  cK|M5y֑mZSH>i@(˭ MZ D́hPdJAktݑ¨^oC f<ᖰ c GhZH %>jb^?&n.3yL kXΛf:MY[kBtڕI N `\N yE8n6? n c)6؂ `8^n?Q7V2IJg.Wv\W_Y~$yTz8jM7O5 @)5VW@*')Iuehǐ@@ !g-',Ngst"{B1r"ltog~v&E* n/Z8Hٽa۫DPO H4` Qj'U 8+]f!eQl B,~ZV87Q赲ԍdG߫H4&.ۋ,J}9h$Bvf琒({X$POvv$Icvxwo߬Ywˋ5d(ef^k^jq;:mz<4Ӵ&$4,e‘6Ӽbܿ`-{dUH kx \8;jlip R@J+qU D:͚CBH%YŠ)k?(uJ]$%-f緺N:\|vQU| Rʛ\ ՙGV9qdbOB HqCஆX!uS?[x:Fh3 z1d3D]%.c <[̚o\}oOvv.[(5C F 1.%P% .&!L;@$ܴb  ))c|B@)Bw/6h\nBAc = 12bYN v($ oN_14Z ۺhj'+xyfbߺILJ&Dm73­.\>x|䌀&(bBHS륷vK#fo˧/JHUPM5A1,i&#D2g@)x5  (ȍFmomwkHQkOG+g>31V &x98E'A."s #KepTAA,1!!B@ʭk-sw!N/J!|=:!%uˁDB HJ!<p\Ѝ=<V%>6F - !Hd!DSSCAn>.z'AJ9LT J(tVVy~3K:-ADgelwnj'1{X/pr & & RzҼ%Z|$j &Şb, -@(vGPƖb1nmյk$X8iIeKUM)wDڡ՘T 0# iaA9 0'VsʣyiGy!pϵ& t{OT*xIІsPyHbx6&8Cc4:K:Dl|Wbd=J=<=wn{6&2@)MSn@ȏ+XqHBArp N[rP@W#[:ZBZ8霙NԪդ w&S<(e!zNbVn.BG .;s$2k'K) kpÍB>BPї{m(XoeaK?@_____P|YS+)ݥiʡ4` *=M-v2n[raT!,ˌvy^hChnvn3zNhr:x!aE'jwh/d;OJ$8tʇ IDAT,u3)^o &M{)gzJh=[X.DYH(Y#] nWVġC)<[/DеMC &2{O,jsZ7.O5Q$Fa8mjx[.W}n7ʵH9. F:2"Φ+\PF$#D;aѬQD[r<P 1(p3T A +#gdz ZEJsy|$Ho4\Ӵ4HX3_DcX^?n|R;@׾뗞ue"xk|[P94 zv9,E^!h`4 e$"!7iL):J"ZW MZg?.&/͍wⅳI'dz1)č3H_"E"}~ZIf&{5іf/Q:kmAb3DdoU歎2ͥ6HΥ!FZP[ X%S0!=[vȺ|g\N'K=,ur((ŕ\m|+uOqJuQߺI^lfρfH6!+xrRz;]lbnRBIĴFŽcEl^Y >0o߹>Βe5g)e HO@;<)w.TLvS7+d)G/1dMr#"R?SЌRFԁ__: ͥp`8TQMLLk?|wyh{G_pcF.=lT??Dw{EJAl[>zr\9AJd9BH!9Adu Th"E[8 khhKClx~ccL~!xT"n/O1C3FWu F#eQUi=(fݾW]\v&n٬vbQst1 _82 ȢehweZ[׾G\:snZ]dz$GS(9g.S✧,8,HXUnA"A1_RTUul8Ynj4N :qmY_:O?%yN쬑 F,&vI=!ܹ5 G 6Đx~N+ctQ0Q8o AY=ߙ7foZ;ϟN8#C IS8{lƢwW&?1?Mw&;WǓMSgv@\5,C 1" xⱏϝt}~Ağ1@="1_{=Esxy,gQs7L >X~\rnCNΞuxmť!ibQ ,ݹ3ת,d8HZ$Bx"xyL"MMa8Dm" Fjԑzt<+ Ja2lЂ_A?t;@3yn7E+cӰ~o#rjJ|`vW+_\ e!޺_-;H#8(#(Gk@fOy>X=d=q=u X>.T6cJ#VUyI!N7&Fm 4u\jXg Rt:$cP~?xԆ1$zɃqN NrHɐѸ3gu/]{0‡N׮=Os؛7~֭|dtzݹ?-:TN>m]4GGG߼ bwtZ5yb%ر)OZ'>G o1d!\+,;346S0-6gB+ʲr0 "hS⠬W>Wg__'7|=c~ۗ흺8>K*so28&_{'0=ѡ!zn (k<,m-\fe0Z}.7N(1N !n|g %,kDGfH"9= ZiB9iAɼFrF'EAA7֎;ĥ:Cp$)Mi un? =Gv__7_=ؐcڗެ~s׿s/W"mg2|a5箛힜mƼ$z,hʧE.f=oQȖS>f >br}Vǀ3X%~ǟ5_8?N @n~pstա+v&{r n&Qy._YI6 #8ӂh<tP3d8C1w~ݭ_~vgv]g/SۛGY&޸qZP[O>rz˦4og;|2 aq!H9}㋿s_2' {eӏg%GӀFP U C3Zkot85g;8fZXeYD4!zV\ry##M?_^aO0fwgƩWN]r+g._ySϾrQ4GIͦi>Ro|c6h,<m3a#>2.4ĵ8|do/s_ݓ+ O_+뗞!ܻd1ޛZve}=}ιj`U,M&[fK )@QG@@ ߢ$D@ q (A` !#J,ɉdȱ"uZjfWY,w8 !}"%ˑdAPon^{Z1J1 /EɧkQӂTqQzEQZyb1k՟?am >ٹgҍ ;׾g|"D7y(1#Y-S!^$;jq̺Ӄo_]:;[.D3ww(nxwΓ/]zsOK/E/j9cw-/\ҵ_ˆ? |˸wo;ouS:%o [066xYŌc:;_5.]B35}.>7W ~/YI Rm /#&F#_˿Om-+>]We+@߷H~?9xpn?Ͽ7r!:u|m>y?bU{xd(r>y&c~'tܳ Dx=T8Wn]]FX-bR !^}ʕ$g+媜VOc09RZ%bSIGlZwr8Ĩژ(?րJRxo=z*kA<~Y6 uvϢ Btt>-]ݶI!>(ôm: 5Q8f3;]f"6N[Qs-87`|T?JC>z'̵Wuԝ]WKlMͨnId Xh- Y2(png$:xo?\tHSJK<~ӎQHRҝ0|bIJy#GF;/9׷Ӻ$|QH\2g Ef4:CwܺCL&d ppRI7,O7_?\~}0 RNΨj}nj=WUJk-2FY:-;ƥrvfu֞!%{o$ JU b,Ͷ ɅW.':o7x ^qRNn6:O zkc:pd˙\+<GyB4N s8!O+ZլzCx"߻s(/1B: p|6,L6 4/ |iڞmt}mm„l >x`q/]Ū[,dM]_Jqچ'Cnֶv25)MC:NJi2[d@Ye1UЎxi_ͯ/>4?HIP,&bn<tn1G٥'5sHk{6q[: &MmLѹ)W;̎mJ'lUz$T):W;'dQ6~>*_DY!$hI@#Ӛ%X?l]ܬ$S3w裏X!Hssֺ2V.)"FXGeYy` SOq}y>Zt>;@TyM_y|w-"P~6焈jU->5dnϜ-(q{4 /?Q|4\Ni^neB44MmdWvf2-3-RBL[wM!"vg)85&. 4 ^=_y}S}PIYVJr<\VH i] T㞽j;I0F$(2+.Ãc\Vs|˛{E:*cZXK?㣫n5B}'w\軆R;߽3-}#}S䈑LMT8ն*໿KtO#4,_hΈ.7RlS~ 8]W; .#;(8\]>z$ 8|/iqjAם  CnVU $*J6cwp᱂1Yn tӁ~f!$FH'\i:JcOO1NdZYA a{;o-ƭsF/) 뮆RS'@po\ 1~0?nk}m2@fjooHfW\&v]X=41}avG]^nlp4H̴Mߣ9|l~ݷvSVGN>+V{w m;5h6Že <{ %swedvq7j˨.fSIȁrw0LLidj􅝑H\ $$Wob;r÷MUrsNU>4!m OB0>~~ꦽKO<0PF PF _囮x/:}kjh+(8txA56 vHEbSek[ʓD2u> &}7&uTv|?1 dwm$)0N!xV-&c\PhΊJfbpwRW=W Wi|!FZ{m IDAT;W^{lܙ듲,68tXX_+LQzuNy(Fe )v:Dz@A&o'+4e x:v78{S))Xx/_ ȼBY.Nq_z[f^7gRAb6GޓmA,MQH!r)AxyTF2$V! m_0=O=@)8 v\N{u F2Te#2={ʫ2th}ap!xD T'Š Ve*iV{ں|k01-t$gGUj߽y4!ȃaUc+˓'_f/mn7UZM 8w\ܼw4 %nDx RZ n6sS/¦ij0 !6 Ko|z|c_y峦&*DsxH4d }ǡ(NQZl֠h7u3ʀ|t!+꺯X1c2 \%lft)2 +OM;J΅(Xo(޷3({|BSAfT-mS?뷲lcToyS/oT7?sl lB͚:d cUg7Fٝe:@z ,FK;G'Oߵi$:uQ3`VҶ6#qa|dIʫ0+&֩&HM9D=Uޣփ"eI"@gwv*8 ds9}-Gs=$.}@2c=D'"p@Ww7C9[H!dێԈâ ְWm- :ZDn  E&oYܾ1>|+[8?7~ݼH8]e]8m\Oun5O^1\(2'QD%t!bѬ;X߾+(B=",WbQ9 C^.W84Nڀ ob-P5JDК$C5~54%(2k$[OOo uWEEFշh /ٖc1> W7yыrYJU̅PEVĈm8؎gHwZD>V"}"H%PqHQhlWҝTFETαZ.b ifFAO9D{'xOU}4QurV]td 'e?՗| MI;uYr aT5$Bse_ {.^o~'?./_Lsrώ m$'B*d=pgx<^8ezniʀ $򴖑,J>ުA#tH;_'4˞*:rE&T""U9$!eŝw4CD+I߻|\di\9 #=}AݭP&=83Y"4RjU@B itn%$)IXR9t[IZ{էGM/'Սdƣ{ߏZUKNM6AE"6ƺmRRY2@dZm([OOZ dHɢuiE.Ӳ6olɶqsgPV`_tr2,R:E.f4d)(jbp{{R)Y)mզ VJʽ @ɴFy9BB}p+&_6sKu*9sZd&x2UIQp`{*h3%X7]@XţmK:th3G]^1.|eXs ?<D}(XB H{|vTpQ v.ә 5+Кg/ab&h'J 6FHఢiHǣ>*ֵ'g B"Ic͙RA*K@)46zC%pwg-ez Q,~rF"u"Ϥ$&]W$Y]QKJm^U(|\v>0 pޯVe*Gk940Edh BG1&DWNzxXomi*;?w ^xTl?'6ܹ߉7Y #Z|>FR%IG;23k1K"Q*2SkYDE38@A=] 1g=\wFk#$ L>tV ) 2Y5ޯFIv&B)X>T 2E"ɴZZ7 Ȉ8>m`CAO&Bp8oRDGqR'6blT"6Y~t_ \C41iHD~#ZR7*#3R\|a0xјLs8Ol^h"NɉfI?VC^j8ۈԵ?qJJZjsAPqxFDDS%\TޚA송vypsSB;l_4rxF46}mt JϮBuF2mkRN&׵ $3BSTTBTu#k-[mNOq,#Xogb$dQGFA NzqNA Isko]u0kC:K I) Z8o,WGjWˏ@k?N:O0@#X*W}pcC19_ [fϝI.rV-wMxy+ZCa1hSl8 0^ e+ Xm_sq^ #Gԅʠ5EB[2:Ϥ`k: P-:d Rbmz!{_> 2 /ϝכ]7-ZaD'@<>i? 35CHzg%.m|(-> KaT aS (N7 q1MSW}Q 6_ߋ(n})ID#])[qY8_V WUO\7t2[=M] p2BMfU<.(07t#"DD``F\'C%@Poۤ郣 U_DkkmQ)$I?R4VDF"`Hko!^TN / Bvz֝Tn5J 34oLqoZ\PNPM#W.зv"2{yf .| Њ3߹J@"[ CAŸ7l% .]nNTiw+AHHUMn*ZủgԶڲp eKVB0lz~YE6kq66:: "JSS%?:?_!s#J1:b3`{liHzGnnW_ZC9 x>Z]Zkb,\+P/xެk-:` .}pq]Dm=VTVHɺIXD0iJC]RDDjID}$c)&nog΁Pq nj%IcLP `4@J2A2C+=m\YjZ*Kfh-.l@@4s $KY"'k[seL3YwkJя1<=&FbTnɣ=&I@Ceñ Q9; Bd(0Y0:6Cs͝zrGڥAj Y7ӗu;jw+q_wGΦ ";^FК R a>۶Z`#QQ>y4뤔F4yCY7Sz<>{'_ MepH@$"I^Rd!1'VZ ). :mka:U)%I`96ti@ E,֧|Ń326A%șvJȤeߏ; \ZVU\5}U'i5*ub|8ʰIiv om{^=[T>q'tfՖ+I+1IV:D->#m `x+ y#6)ֈT}9[!RĈVܱij\D{M 2VF`RbÉWrQw9 W.E,-EN-97w}UKgG$f''\tz|kfsEk2!jHeLpa0Aq)ЗG9qhz#%#*҉psJQRkt:sD{,ıyɪɽ@sZDX7 AӁl֟vt.˜,(|rƈTrJ5|O?du9m'h92O‡ɉq!{Vb2̓DAG!E}t@֧k[t89Cw!35ٮq[ }9MC0Zx-Yh`gԡAJ1* ttNkjCjDN&veIS9M @R|G6\)R~`[1^Nci,,Һ=%2a1҆VUǷ&-p*N2m[7#a6T 5J.E!pY*ӝ,#΄ۺOW묈8'N54rw6"q֜F)qj Uڦܵ?ՍExHjŝH0\S;k:wXg}kiϷߧG _'j6[d  k Y͗~)}O "+S#˷%e:FCH޸UVDY${aB6k F(ݟh @;W!>CV$Wgw(c'|u7wSwx\+Md(C]Uycl&M}P۞_?#/>7򎭛 {ޖOuKu:H~|9\%(k:SsB "J2 H@0k@`pV&׊Qm%v^ oFy/dDgG7N Mm 0&t&a'geE['rڸ\:@:ϘLFCa^6+D| QHPI) *\6Z3Y4 QH8^ދ|p](ͅl µd*[Ѷ6iF]I>ӕȍIB\gyB2BY2ƹЬL)f{G^m˗/:8#ryi5Zdi"Bq4ͼ'n4@7 !%k uNoV;uy)R`Txvw  A+m[ | 8?B>PZ7$ ~TJpeS!ƺ]m94Aͪ鬱wښLk OߚLFyy.1FňB>w~GI1- BY8Xvwt5ͬNN_;`pslRb0-5u6$$ "+zlQu27{0,`pϹm- JGc܇Yt1&CH k{td BHЙ=+VUY%O=wt676UwV/VHPS7CCUy#7:wJh9>)s6;'3blOV؝Lc<$"/W@J(2qݪNOͬ ΆAWd[b坍I7(1Bhw66F 1|v2+MY:h/)?.vV~(?kGTgD%79'>\{!LDĬ>0glŁ Be B AsAܘB6S(0髧e՞.W\ݒ:yʶ?>: d BLE$lP ӗmTN$e1<)eNscw^wb,囹wpR5'U/:2t8uH'N(d?[(A@ﵚ=a@ SB[^_d$FpM?{\IYgʵ2+;[X$;鈰wPKGc-3H!q b>s۟خV P c6D.zE]CbTE5%:6sˆsLo+>9kjhBJCNxw]9eZif%iyt2 =STf1D[W1FszemkǧPmݭԣ q"&"g^ ֶf(9"\ I%2Q%"Aw{."-HmwP;|XE>t$0N[n()R(!#t!l+c| f+xKS}^ʹ-);Oq`E% uktR'2Z12=}L:2mC>@6L􆼰&޼+5{Zpt\'Bw.\ܚ"J˓nl>ƶ֫KFƪ<*!.6<ԫVMg#괿d!x}:B,0SPQ TDG1η=ٰZ.uâ!DwV zb(˦mw@ yD!.Z۫{gtxh@][EW~j6BnHf5!|>(hΎ&sx (F됎_QR(&+eXN2>qN m5;u&!a8ʦP{OӐejܬʹF3..IDAT~ӺRc_W!D-iyty=rZdpR'Z6JM.=6r~(;AX"T(:vwǍS bR,׎K!uukcPJcBO: C.e/rծ}H-rO:9 HcS1=ڳL@9SlMq*7}lFT!l0̢ e8zPJ4Bt<FzR9v{wqrI{p7gVκէU)Z'@(!r } (-N)A!Rz)e7[딖"kگxH5cB_:R`4RRٝ`~voWsph`imCmoH 5|`;gFIE89 f LظL&YeJyxQaB ]$*W=юN4!YUƿy{鬶:sSwbus .Ez;Lo7ߒ rg:`)](ë.e>V|)x߱ؿ" GXemul: Installing and running "guest OSes"

GXemul: Installing and running "guest OSes"

Back to the index.



General notes on running "guest OSes":

The emulator works well enough to run complete operating systems. These are referred to as guest operating systems, in contrast to the host operating system which the emulator is running under.

The emulation, however, is not necessarily complete enough to support previously untested guest operating. In many cases, the emulated devices have been implemented "on demand" as required by a specific guest operating system, and trying to run another operating system (or even a different version of a supported one) will trigger new things that are not yet implemented in the emulator. This page lists specific versions that are known to work. What this usually means is:

  • A full installation from scratch should work (usually from a CD-ROM image or via the network).
  • Logging in to the installed guest OS after install.

Usually (but not always, due to lack of spare time for testing), it also means:

  • Doing something non-trivial inside the guest OS.

Printing "Hello world" is considered trivial, whereas e.g. building GXemul itself inside the emulated guest operating system is considered non-trivial. As this takes quite some time, this is not always done.

Disk images:

Although it is possible to let a guest OS access real hardware, such as harddisks, it is much more flexible and attractive to simulate harddisks using files residing in the host's filesystem. See this section for details about how to use disk images.

While these files may look large (several GBs is common for hard disks), on Unix-like file systems, files may contain holes, which means that the disk image files do not actually use up all that space from the start, but rather grows only as data is written to it. To the guest operating system, the harddisk image looks and acts like a real disk.

Unsupported guest operating systems, or experimental install instructions:

In addition to the "working" guest operating systems listed on this page, there is a page about unsupported modes or guest operating systems, which you may find interesting. These are either mode that are not-yet-working, or modes that did work at some point in time but are now broken.

Version numbers:

The version numbers of the various operating systems were the latest versions that worked satisfactory with GXemul at the time this page was updated; if new versions have been released since then, they could work too, but there is no guarantee. New versions of guest operating systems may trigger previously untriggered bugs in the emulator, or they may make use of devices in the machine that the emulator simply doesn't have yet.

Some operating systems are listed with a version number less than what was available at the time of this GXemul release (e.g. NetBSD/prep). The reasons for this is usually one of the following:

  • incompleteness/bugs in GXemul's machine, device, and/or processor implementations, which the newer version of the guest operating system triggers, but not the older version, or
  • the newer guest operating system version would work, but the full installation procedure has not been verified.


NetBSD/pmax:

NetBSD/pmax was the first guest OS that could be installed onto a disk image in GXemul. The device emulation of the DECstation 5000/200 is reasonably complete; it should be enough to emulate a networked X-windows-capable workstation.

        

To install NetBSD/pmax onto a harddisk image in the emulator, follow these instructions:

  1. Create an empty harddisk image, which will be the root disk that NetBSD installs itself onto:
    	dd if=/dev/zero of=nbsd_pmax.img bs=1024 count=1 seek=7800000
    
    
  2. Download a NetBSD CD-ROM iso image:
    	ftp://ftp.netbsd.org/pub/NetBSD/iso/7.1.2/NetBSD-7.1.2-pmax.iso
    
    
  3. Start the emulator like this:
    	gxemul -X -e 3max -d nbsd_pmax.img -d b:NetBSD-7.1.2-pmax.iso
    

(NetBSD 8.0 can also be installed, but for some reason, the Xorg server is missing after installation, so 7.1.2 is preferred if you want to use X.)

If you do not want to use the graphical framebuffer during the install, you can skip the -X command line option. Remember to enter xterm instead of vt100 when asked about your terminal type, if you do this.

You can also add -Y 2 to the command line options, if you feel that the default framebuffer window is too large.

When the installation has finished, the following command should start NetBSD from the harddisk image:

	gxemul -X -e 3max -d nbsd_pmax.img
and log in as root. Type startx to start X windows.

Remove -X if you only want a serial console.

If you selected to install xdm, you may not be able to login as root unless you also set a root password.


NetBSD/arc:

It is possible to install and run NetBSD/arc on an emulated Acer PICA-61 in the emulator.

        

To install NetBSD/arc from a CDROM image onto an emulated harddisk image, follow these instructions:

  1. Create an empty harddisk image, which will be the root disk that NetBSD installs itself onto:
    	dd if=/dev/zero of=nbsd_arc.img bs=1024 count=1 seek=2000000
    
    
  2. Download a NetBSD/arc CDROM image, and the generic + ramdisk NetBSD/arc kernels:
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-7.1.2/iso/NetBSD-7.1.2-arc.iso
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-7.1.2/arc/binary/kernel/netbsd-GENERIC.gz
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-7.1.2/arc/binary/kernel/netbsd-RAMDISK.gz
    
    
  3. Start the emulator using this command line:
    	gxemul -x -e pica -d nbsd_arc.img -d b:NetBSD-7.1.2-arc.iso netbsd-RAMDISK.gz
    
    
    and proceed like you would do if you were installing NetBSD on a real PICA-61. (Choose "Use entire disk" when doing the MBR partitioning, and choose to install from CD-ROM.)

    (Use -X if you feel more comfortable with a "graphical" text display.)

You can now use the generic NetBSD/arc kernel to boot from the harddisk image, using the following command:

	gxemul -x -e pica -d nbsd_arc.img netbsd-GENERIC.gz

Known issue: The clock may be running too fast inside the emulated machine.


NetBSD/hpcmips:

It is possible to install NetBSD/hpcmips onto a disk image, on an an emulated MobilePro 770 or 800. (MobilePro 780 and 880 might work too, but I don't test those for every release of the emulator. They have unaligned framebuffers, and run a bit slower.)

            

These instructions show an example of how to install NetBSD/hpcmips on an emulated MobilePro 770:

  1. Create an empty harddisk image, which will be the root disk that you will install NetBSD/hpcmips onto:
    	dd if=/dev/zero of=nbsd_hpcmips.img bs=1024 count=1 seek=3000000
    
    
  2. Download the NetBSD/hpcmips 5.0.2 ISO image, a generic kernel, and the installer kernel:
    	ftp://ftp.netbsd.org/pub/NetBSD/iso/5.0.2/hpcmipscd-5.0.2.iso
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-5.0.2/hpcmips/binary/kernel/netbsd-GENERIC.gz
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-5.0.2/hpcmips/installation/netbsd.gz
    
    

  3. Start the installation like this:
    	gxemul -e mobilepro770 -X -d nbsd_hpcmips.img -d b:hpcmipscd-5.0.2.iso netbsd.gz
    
    
    and proceed like you would do if you were installing NetBSD on a real MobilePro 770. (Install onto wd0, choose "Use entire disk" when doing the MBR partitioning, and choose to install from CD-ROM.)

(While it is possible to install and run NetBSD/hpcmips without the -X command line option (i.e. using serial console), NetBSD 4.0.1's default /etc/ttys file after a full install did not have /dev/console enabled, so you needed to edit /etc/ttys before you reboot after the install, to be able to log in. Whether this has changed after 4.0.1, I don't know.)

If everything worked, NetBSD should now be installed on the disk image. Use the following command line to boot the emulated hpcmips machine:

	gxemul -e mobilepro770 -X -d nbsd_hpcmips.img netbsd-GENERIC.gz

When you have logged in as root, you can use startx to start X Windows, but there is no mouse support yet so only keyboard input is available. This makes it a bit akward to use X.


NetBSD/cobalt:

NetBSD/cobalt is possible to install on an emulated Cobalt Cube.

        

The following instructions will let you install NetBSD/cobalt onto a disk image:

  1. Create an empty harddisk image, which will be the disk image that you will install NetBSD/cobalt onto:
    	dd if=/dev/zero of=nbsd_cobalt.img bs=1024 count=1 seek=2700000
    
    
  2. Download the generic kernel for Cobalt and the ISO image:
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-7.1.2/cobalt/binary/kernel/netbsd-GENERIC.gz
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-7.1.2/iso/NetBSD-7.1.2-cobalt.iso
    
    
  3. Start the installation like this:
      	gxemul -x -E cobalt -d nbsd_cobalt.img -d bd:NetBSD-7.1.2-cobalt.iso -j cobalt/binary/kernel/netbsd-RAMDISK
    
    
    and proceed like you would do if you were installing NetBSD on a real Cobalt. (Install onto wd0, choose "Use entire disk" when doing the MBR partitioning, and choose to install from CD-ROM device "wd1d".)

You should now be able to boot NetBSD/cobalt like this:

	gxemul -x -E cobalt -d nbsd_cobalt.img netbsd-GENERIC.gz

Known issues: The clock may go too fast inside the emulator.


NetBSD/evbmips:

NetBSD/evbmips can run in GXemul on an emulated Malta evaluation board, with a 5Kc (MIPS64) or 4Kc (MIPS32) processor. 5Kc is the default.

        

One way to install the NetBSD/evbmips distribution onto a disk image is to install the files using another (emulated) machine.

The following instructions will let you install NetBSD/evbmips onto a disk image, from an emulated DECstation 3MAX machine:

  1. Download a NetBSD/pmax (DECstation) install RAMDISK kernel:
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-7.1.2/pmax/binary/kernel/netbsd-INSTALL.gz
    

  2. Create an empty harddisk image, which will be the disk image that you will install NetBSD onto:
    	dd if=/dev/zero of=nbsd_malta.img bs=1024 count=1 seek=700000
    
    
  3. Download the Malta kernel and the ISO image:
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-7.1.2/evbmips-mipsel/binary/kernel/netbsd-MALTA.gz
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-7.1.2/iso/NetBSD-7.1.2-evbmips-mipsel.iso
    
    

  4. Start the emulated DECstation machine like this:
    	gxemul -e 3max -d nbsd_malta.img -d NetBSD-7.1.2-evbmips-mipsel.iso netbsd-INSTALL.gz
    
    
  5. At the Terminal type? [vt100] prompt, type CTRL-B to simulate a CTRL-C sent to NetBSD/pmax. Then execute the following commands:

           
    newfs /dev/sd0c
    mount -t cd9660 /dev/cd0c /mnt
    mkdir /mnt2; mount /dev/sd0c /mnt2
    cd /mnt2; sh
    for a in /mnt/*/binary/sets/[bcemt]*.tgz; do echo $a; tar zxfp $a; done
    exit
    cd dev; sh ./MAKEDEV all; cd ../etc
    echo rc_configured=YES >> rc.conf
    echo "/dev/wd0c / ffs rw 1 1" > fstab
    cd /; umount /mnt; umount /mnt2; halt
    

You should now be able to boot NetBSD/evbmips using this command:

	gxemul -x -e malta -d nbsd_malta.img netbsd-MALTA.gz

NOTE: To select a 4Kc (MIPS32) CPU instead of the default 5Kc (MIPS64) CPU, add -C 4Kc to the command line. There are at least two things that differ:

  1. The dynamic translation core runs faster when emulating 32-bit processors, so -C 4Kc might make things go faster.
  2. 4Kc only has 16 TLB entries, whereas 5Kc has 48. This makes 4Kc emulation slower in general, because there are more TLB misses.

The installation instructions above create a filesystem without a disklabel, so there is only one ffs partition and no swap. You will need to enter the following things when booting with the generic kernel:

	root device (default wd0a): wd0c
	dump device (default wd0b):		(just press enter)
	file system (default generic):		(just press enter)
	init path (default /sbin/init):		(just press enter)

The clock is probably wrong (showing the year 2118 instead of 2018), and it goes too fast inside the emulator. If it hangs during boot-up, before the login prompt has appeared, type CTRL-C in the xterm window.


NetBSD/algor:

NetBSD/algor can run in GXemul on an emulated Algorithmics P5064 evaluation board.

        

One way to install the NetBSD/algor distribution onto a disk image is to install the files using another (emulated) machine.

The following instructions will let you install NetBSD/algor onto a disk image, from an emulated DECstation 3MAX machine:

  1. Download a NetBSD/pmax (DECstation) install RAMDISK kernel (NOTE: not 5.0.2!):
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-4.0.1/pmax/binary/kernel/netbsd-INSTALL.gz
    

  2. Create an empty harddisk image, which will be the disk image that you will install NetBSD/algor onto:
    	dd if=/dev/zero of=nbsd_algor.img bs=1024 count=1 seek=700000
    
    
  3. Download the P5064 Algor kernel and the install sets:
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-5.0.2/algor/binary/kernel/netbsd-P5064.gz
    
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-5.0.2/algor/binary/sets/base.tgz
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-5.0.2/algor/binary/sets/comp.tgz
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-5.0.2/algor/binary/sets/etc.tgz
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-5.0.2/algor/binary/sets/man.tgz
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-5.0.2/algor/binary/sets/misc.tgz
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-5.0.2/algor/binary/sets/text.tgz
    
    
  4. Prepare an ISO image of the install sets:
    	mkisofs -U -o algor_files.iso base.tgz comp.tgz etc.tgz man.tgz misc.tgz text.tgz
    
    

  5. Start the emulated DECstation machine like this:
    	gxemul -e 3max -d nbsd_algor.img -d algor_files.iso netbsd-INSTALL.gz
    
    
  6. At the Terminal type? [rcons] prompt, type CTRL-B to simulate a CTRL-C sent to NetBSD/pmax. Then execute the following commands:

           
    newfs /dev/sd0c
    mount /dev/cd0c /mnt
    mkdir /mnt2; mount /dev/sd0c /mnt2
    cd /mnt2; sh
    for a in /mnt/*.tgz; do echo $a; tar zxfp $a; done
    exit
    cd dev; sh ./MAKEDEV all; cd ../etc
    echo rc_configured=YES >> rc.conf
    echo "/dev/wd0c / ffs rw 1 1" > fstab
    cd /; umount /mnt; umount /mnt2; halt
    

You should now be able to boot NetBSD/algor using this command:

	gxemul -x -e p5064 -d nbsd_algor.img netbsd-P5064.gz

The installation instructions above create a filesystem without a disklabel, so there is only one ffs partition and no swap. You will need to enter the following things when booting with the generic kernel:

	root device (default wd0a): wd0c
	dump device (default wd0b):		(just press enter)
	file system (default generic):		(just press enter)
	init path (default /sbin/init):		(just press enter)


NetBSD/sgimips:

        

NetBSD/sgimips can run in GXemul on an emulated SGI O2 (also known as IP32). The SCSI controller is not emulated yet, so NetBSD needs to boot with root-on-NFS:

  1. First of all, an "nfs server" machine must be set up. This needs to have a 4000 MB /tftpboot partition. Install NetBSD/pmax 8.0 from CDROM. Do not configure the network and do not install any X11 packages on the nfs server, as they are not needed. Don't forget to add the extra partition!

  2. Download the files corresponding to a NetBSD/sgimips CD-ROM iso image, and the GENERIC and INSTALL kernels:
    	ftp://ftp.NetBSD.org/pub/NetBSD/NetBSD-8.0/sgimips/binary/kernel/netbsd-GENERIC32_IP3x.gz
    	ftp://ftp.NetBSD.org/pub/NetBSD/NetBSD-8.0/sgimips/binary/kernel/netbsd-INSTALL32_IP3x.gz
    
    	wget -np -l 0 -r ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-8.0/sgimips/binary/sets/
    	mkisofs -U -o sgimips.iso ftp.netbsd.org/pub/NetBSD/NetBSD-8.0
    
    
  3. Start the DECstation emulation:
    	gxemul -e 3max -d nbsd_pmax.img -d sgimips.iso
    
    
    Log in as root, configure the pmax machine as an NFS server, and extract the files from the sgimips CD-ROM image:

           
    echo hostname=server >> /etc/rc.conf
    echo ifconfig_le0=\"inet 10.0.0.2\" >> /etc/rc.conf
    echo nameserver 10.0.0.254 >> /etc/resolv.conf
    echo 10.0.0.254 > /etc/mygate
    echo /tftpboot -maproot=root 10.0.0.1 > /etc/exports
    echo rpcbind=YES >> /etc/rc.conf
    echo nfs_server=YES >> /etc/rc.conf
    echo mountd=YES >> /etc/rc.conf
    echo bootparamd=YES >> /etc/rc.conf
    printf "client root=10.0.0.2:/tftpboot \\\n swap=10.0.0.2:/tftpboot/swap\n" > /etc/bootparams
    echo "bootps dgram udp wait root /usr/sbin/bootpd bootpd -d 4 -h 10.0.0.2" >> /etc/inetd.conf
    cat >> /etc/bootptab
    client:\
            :ht=ether:\
            :ha=082030000010:\
            :sm=255.0.0.0:\
            :lg=10.0.0.254:\
            :ip=10.0.0.1:\
            :rp=/tftpboot:
    (press CTRL-D)
    echo "08:20:30:00:00:10 client" > /etc/ethers
    echo 10.0.0.1 client > /etc/hosts
    
    cd /tftpboot; mount /dev/cd0a /mnt
    for a in /mnt/*/binary/sets/[bcegmtx]*.tgz; do echo $a; tar zxfp $a; done
    echo 10.0.0.2:/tftpboot / nfs rw 0 0 > /tftpboot/etc/fstab
    echo rc_configured=YES >> /tftpboot/etc/rc.conf
    echo 10.0.0.254 >> /tftpboot/etc/mygate
    echo nameserver 10.0.0.254 >> /tftpboot/etc/resolv.conf
    echo rc_configured=YES >> /tftpboot/etc/rc.conf
    dd if=/dev/zero of=swap bs=1024 count=262144
    cd /; umount /mnt; halt
    

  4. Create a configuration file called config_client:
           
    !  Configuration file for running NetBSD/sgimips diskless with
    !  a NetBSD/pmax machine as the nfs server.
    
    net(
    	add_remote("localhost:12444")   ! the server
    	local_port(12445)               ! the client
    )
    
    machine(
    	name("client machine")
    	serial_nr(1)
    
            type("sgi")
            subtype("o2")
    	use_x11(1)
    	memory(256)
    
            load("netbsd-INSTALL32_IP3x.gz")
            ! load("netbsd-GENERIC32_IP3x.gz")
    )
    
    
    ... and another configuration file for the server, config_server:
           
    net(
    	local_port(12444)               ! the server
    	add_remote("localhost:12445")   ! the client
    )
    
    machine(
    	name("nfs server")
    	serial_nr(2)
    
            type("dec")
            subtype("5000/200")
    
            disk("nbsd_pmax.img")
    )
    
    
  5. Boot the "nfs server" and the NetBSD/sgimips "client machine" as two separate emulator instances:
    	in one xterm:
    	gxemul @config_server
    
    	and then, in another xterm:
    	gxemul @config_client
    
    
  6. In the NetBSD/sgimips window, choose "x: Exit Install System" in the installer's main menu, and then type:
    	ifconfig mec0 10.0.0.1; route add default 10.0.0.254
    	mount -v 10.0.0.2:/tftpboot /mnt
    	cd /mnt/dev; ./MAKEDEV all; cd /; umount /mnt
    	halt
    
    Then, once the client machine has halted, log in as root on the server machine and type reboot.

  7. Once everything has been set up correctly, change netbsd-INSTALL32_IP3x.gz in config_client to netbsd-GENERIC32_IP3x.gz (the GENERIC kernel).

You might want to log in as root on the server machine, and run tcpdump -lnvv or similar, to see that what the client machine actually does on the network.

It should now be possible to boot NetBSD/sgimips using the NetBSD/pmax nfs server, using the following commands: (NOTE! Execute these two commands in separate xterms!)

	gxemul @config_server
	gxemul @config_client

If/when asked for "root device:" etc. on the client machine, enter the following values:

	root device: mec0
	dump device: 				(leave blank)
	file system (default generic): 		(leave blank)
	..
	init path (default /sbin/init):		(leave blank)
	Enter pathname of shell or RETURN for /bin/sh:	(leave blank)
	Terminal type? [unknown] xterm
	..
	# exit			(to leave the single-user shell)

Note: Netbooting like this is very slow, so you need a lot of patience.


NetBSD/cats:

It is possible to install and run NetBSD/cats in GXemul.

        

To install NetBSD/cats onto a disk image, follow these instructions:

  1. Create an empty harddisk image, which will be the root disk that you will install NetBSD/cats onto:
    	dd if=/dev/zero of=nbsd_cats.img bs=1024 count=1 seek=3000000
    
    
  2. Download the NetBSD/cats ISO image and the generic and install kernels:
    	ftp://ftp.netbsd.org/pub/NetBSD/iso/5.0/catscd-5.0.iso
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-5.0/cats/binary/kernel/netbsd.aout-GENERIC.gz
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-5.0/cats/binary/kernel/netbsd.aout-INSTALL.gz
    
    

  3. Start the installation like this:
    	gxemul -XEcats -d nbsd_cats.img -d catscd-5.0.iso netbsd.aout-INSTALL.gz
    
    
    and proceed like you would do if you were installing NetBSD on a real CATS from CDROM.

Note that there are long delays during bootup.

Alternatively, to install from FTP, you can skip downloading the ISO, and start the install without -d catscd-5.0.iso. Suitable network settings are IP 10.0.0.1, gateway/default route 10.0.0.254, netmask 255.0.0.0, nameserver 10.0.0.254.

If everything worked, NetBSD should now be installed on the disk image. Use the following command line to boot the emulated CATS machine:

	gxemul -XEcats -d nbsd_cats.img netbsd.aout-GENERIC.gz


NetBSD/evbarm:

NetBSD/evbarm can run in GXemul on an emulated IQ80321 evaluation board.

        

It is tricky to install, because there is (as far as I know) no INSTALL kernel. One way to install the NetBSD/evbarm distribution onto a disk image is to install the files using another (emulated) machine.

The following instructions will let you install NetBSD/evbarm onto a disk image, from an emulated CATS machine:

  1. Download a NetBSD/cats 3.1 ramdisk kernel:
    	wget ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-3.1/cats/binary/kernel/netbsd.aout-INSTALL.gz
    
    
  2. Create an empty harddisk image, which will be the disk image that you will install NetBSD/evbarm onto:
    	dd if=/dev/zero of=nbsd_iq80321.img bs=1024 count=1 seek=999000
    
    
  3. Download an IQ80321 kernel with wdc support, and the 2.1 ISO image:
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.1/evbarm/binary/kernel/netbsd-wd0-IQ80321.gz
    	ftp://ftp.netbsd.org/pub/NetBSD/iso/2.1/evbarmcd.iso
    
    

  4. Now let's extract the files from the CD-ROM image onto the IQ80321's disk image. Start the CATS machine using the following command line:
    	gxemul -XEcats -d nbsd_iq80321.img -d evbarmcd.iso netbsd.aout-INSTALL.gz
    
    
    Exit from the installer, and execute the following commands as root:

           
    
    disklabel -I -i wd0
        (enter suitable commands, e.g. a, 4.2BSD, 1c, 750M, b,
         swap, a, 200M, P, W, y, Q)
    newfs /dev/wd0a; mount /dev/wd0a /mnt2; cd /mnt2
    mount /dev/cd0a /mnt; sh
    for a in /mnt/*/binary/sets/[bcegmt]*.tgz; do echo $a; tar zxfp $a; done
    exit
    cd dev; sh ./MAKEDEV all; cd ../etc
    echo rc_configured=YES >> rc.conf
    echo "/dev/wd0a / ffs rw 1 1" > fstab
    echo "/dev/wd0b none swap sw 0 0" >> fstab
    cd /; umount /mnt; umount /mnt2; sync; halt
    

You should now be able to boot NetBSD/evbarm using this command:

	gxemul -x -E iq80321 -d nbsd_iq80321.img netbsd-wd0-IQ80321.gz


NetBSD/netwinder:

It is possible to run NetBSD/netwinder in GXemul.

            

There is no INSTALL ramdisk kernel, so one way to install the NetBSD/netwinder distribution onto a disk image is to install the files using another (emulated) machine. The following instructions will let you install the NetBSD/netwinder distribution onto a disk image, from an emulated DECstation 3MAX machine:

  1. Download a NetBSD/pmax (DECstation) install RAMDISK kernel:
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-3.1/pmax/binary/kernel/netbsd-INSTALL.gz
    

  2. Create an empty harddisk image, which will be the disk image that you will install NetBSD onto:
    	dd if=/dev/zero of=nbsd_netwinder.img bs=1024 count=1 seek=999000
    
    
  3. Download the generic kernel and the 3.1 ISO image:
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-3.1/netwinder/binary/kernel/netbsd-GENERIC.gz
    	ftp://ftp.netbsd.org/pub/NetBSD/iso/3.1/netwindercd-3.1.iso
    
    

  4. Start the emulated DECstation machine like this:
    	gxemul -e 3max -d nbsd_netwinder.img -d netwindercd-3.1.iso netbsd-INSTALL.gz
    
    
  5. At the Terminal type? [rcons] prompt, type CTRL-B to simulate a CTRL-C sent to NetBSD/pmax. Then execute the following commands:

           
    newfs /dev/sd0c
    mount /dev/cd0c /mnt
    mkdir /mnt2; mount /dev/sd0c /mnt2
    cd /mnt2; sh
    for a in /mnt/*/binary/sets/*.tgz; do echo $a; tar zxfp $a; done
    exit
    cd dev; sh ./MAKEDEV all; cd ../etc
    echo rc_configured=YES >> rc.conf
    echo "/dev/wd0c / ffs rw 1 1" > fstab
    cd /; umount /mnt; umount /mnt2; halt
    

NetBSD/netwinder is now installed on the disk image. The following command line can be used to start NetBSD/netwinder:

	gxemul -X -E netwinder -d nbsd_netwinder.img netbsd-GENERIC.gz

This will result in a 1024x768 framebuffer. Add -Y2 to the command line if you want to scale it down to 512x384.

Note: The installation instructions above create a filesystem without a disklabel, so there is only one ffs partition and no swap. You will need to enter the following things when booting with the generic kernel:

	root device (default wd0a): wd0c
	dump device (default wd0b): (just press enter)
	file system (default generic):    (just press enter)
	init path (default /sbin/init):   (just press enter)

Known bugs/problems:

  • There is a long delay when starting up NetBSD/netwinder (several seconds even on a very fast host machine), so you need to be patient.
  • There is a minor bug in the keyboard device, so you need to press a key (any key) before typing wd0c.
  • When halting/rebooting NetBSD/netwinder, the emulator prints a message saying something about an internal error. This doesn't matter; ignore the message.


NetBSD/prep:

It is possible to install and run NetBSD/prep 2.1 in GXemul on an emulated IBM 6050 (PowerPC) machine. (Newer versions of NetBSD/prep use the wdc controller in a way which isn't implemented in GXemul yet, or there are bugs in GXemul's PowerPC CPU emulation.)

        

To install NetBSD/prep onto a disk image, follow these instructions:

  1. Create an empty harddisk image, which will be the root disk that you will install NetBSD/prep onto:
        dd if=/dev/zero of=nbsd_prep.img bs=1024 count=1 seek=1000000
    
    
  2. Download the NetBSD/prep 2.1 ISO image and the generic kernel:
        ftp://ftp.netbsd.org/pub/NetBSD/iso/2.1/prepcd.iso
        ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-2.1/prep/binary/kernel/netbsd-GENERIC.gz
    
    

  3. Start the installation like this:
        gxemul -X -e ibm6050 -d nbsd_prep.img -d rdb:prepcd.iso -j prep/binary/kernel/netbsd-INSTALL.gz
    
    

  4. Installation is a bit unsmooth, possibly due to bugs in GXemul, possibly due to bugs in NetBSD itself; others have been having problems on real hardware: http://mail-index.NetBSD.org/port-prep/2005/11/25/0004.html. Creating an MBR slice and a disklabel with sysinst bugs out, so some things have to be done manually:

    At "(I)nstall, (S)hell, or (H)alt", choose s.
    # fdisk -u wd0
    Do you want to change our idea of what BIOS thinks? [n] (just press ENTER)
    Which partition do you want to change?: [none] 0
    sysid: ... (just press ENTER)
    start: ... 1cyl
    size: ... (just press ENTER)
    Which partition do you want to change?: [none] (press ENTER)
    Should we write new partition table? [n] y
    # disklabel -I -i wd0
    partition> a
    Filesystem type [?] [unused]: 4.2BSD
    Start offset ('x' to start after partition 'x') [0c, 0s, 0M]: 1c
    Partition size ('$' for all remaining) [0c, 0s, 0M]: 900M
    partition> b
    Filesystem type [?] [unused]: swap
    Start offset ('x' to start after partition 'x') [0c, 0s, 0M]: a
    Partition size ('$' for all remaining) [0c, 0s, 0M]: $
    partition> W
    Label disk [n]? y
    partition> Q
    # newfs wd0a
    # sysinst
    Choose to install onto wd0. Choose "a: Edit the MBR partition table" when presented with that option.
    Choose the 'a' partition/slice, set the 'e' ("active") and 'f' ("install") fields to Yes, and then choose "x: Partition table OK".
    Choose "b: Use existing partition sizes" in the next menu.
    Select partition 'a' and press ENTER. Set field 'k' (mount point) to '/'.
    Get out of the partitioner by selecting "x: Partition sizes ok" twice.
    At "Write outside MBR partition? [n]:", just press ENTER.
    Install from CD-ROM, device wd1c.

If everything worked, NetBSD should now be installed on the disk image. Use the following command line to boot the emulated machine:

	gxemul -X -e ibm6050 -d nbsd_prep.img netbsd-GENERIC.gz

When asked which the root device is, type wd0 and just press ENTER to select the default values for dump device, file system type, and init path.


NetBSD/macppc:

It is possible to install and run NetBSD/macppc in GXemul on an emulated generic PowerPC machine. No specific Machintosh model is emulated, but it is enough to for NetBSD to recognize it.

        

To install NetBSD/macppc onto a disk image, follow these instructions:

  1. Create an empty harddisk image, which will be the root disk that you will install NetBSD/macppc onto:
        dd if=/dev/zero of=nbsd_macppc.img bs=1024 count=1 seek=3000000
    
    
  2. Download the NetBSD/macppc 4.0.1 ISO image and a generic kernel:
        ftp://ftp.netbsd.org/pub/NetBSD/iso/4.0.1/macppccd-4.0.1.iso
        ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-4.0.1/macppc/binary/kernel/netbsd-GENERIC.MP.gz
    
    

  3. Start the installation like this:
        gxemul -x -e g4 -d nbsd_macppc.img -d b:macppccd-4.0.1.iso -j macppc/binary/kernel/netbsd-INSTALL
    
    
    and continue as you would do when installing NetBSD on a real machine.

If everything worked, NetBSD/macppc should now be installed on the disk image.

Use the following command line to boot the emulated machine:

	gxemul -x -e g4 -d nbsd_macppc.img netbsd-GENERIC.MP.gz

If asked about root device, enter wd0.


NetBSD/pmppc:

NetBSD/pmppc can run in GXemul on an emulated Artesyn PM/PPC board. Currently, no SCSI or other disk controller is emulated for this machine type, but it is possible to run NetBSD with root-on-nfs.

        

These setup steps will let you run NetBSD/pmppc with root-on-nfs:

  1. First of all, the "nfs server" machine must be set up. This needs to have a 750 MB /tftpboot partition. Install NetBSD/pmax 3.1 from CDROM. (Don't forget to add the extra partition!)

  2. Configure the nfs server machine to act as an nfs server. Start up the emulated DECstation:
    	gxemul -e 3max -d nbsd_pmax.img
    
    and enter the following commands as root inside the emulator:

           
    echo hostname=server >> /etc/rc.conf
    echo ifconfig_le0=\"inet 10.0.0.2\" >> /etc/rc.conf
    echo nameserver 10.0.0.254 >> /etc/resolv.conf
    echo 10.0.0.254 > /etc/mygate
    echo /tftpboot -maproot=root 10.0.0.1 > /etc/exports
    echo rpcbind=YES >> /etc/rc.conf
    echo nfs_server=YES >> /etc/rc.conf
    echo mountd=YES >> /etc/rc.conf
    echo bootparamd=YES >> /etc/rc.conf
    printf "client root=10.0.0.2:/tftpboot \\\n swap=10.0.0.2:/tftpboot/swap\n" > /etc/bootparams
    echo "bootps dgram udp wait root /usr/sbin/bootpd bootpd -d 4 -h 10.0.0.2" >> /etc/inetd.conf
    cat >> /etc/bootptab
    client:\
            :ht=ether:\
            :ha=102030000010:\
            :sm=255.0.0.0:\
            :lg=10.0.0.254:\
            :ip=10.0.0.1:\
            :rp=/tftpboot:
    (press CTRL-D)
    echo "10:20:30:00:00:10 client" > /etc/ethers
    echo 10.0.0.1 client > /etc/hosts
    reboot
    

  3. Download the NetBSD/pmppc CD-ROM iso image, and the GENERIC kernel:
    	ftp://ftp.netbsd.org/pub/NetBSD/iso/3.1/pmppccd-3.1.iso
    	ftp://ftp.NetBSD.org/pub/NetBSD/NetBSD-3.1/pmppc/binary/kernel/netbsd-PMPPC.gz
    
    
  4. Start the DECstation emulation again:
    	gxemul -e 3max -d nbsd_pmax.img -d pmppccd-3.1.iso
    
    
    and extract the files from the PM/PPC CD-ROM image to the DECstation disk image:

           
    cd /tftpboot; mount /dev/cd0a /mnt
    for a in /mnt/*/binary/sets/[bcemt]*; do echo $a; tar zxfp $a; done
    echo 10.0.0.2:/tftpboot / nfs rw 0 0 > /tftpboot/etc/fstab
    echo rc_configured=YES >> /tftpboot/etc/rc.conf
    echo 10.0.0.254 >> /tftpboot/etc/mygate
    echo nameserver 10.0.0.254 >> /tftpboot/etc/resolv.conf
    echo rc_configured=YES >> /tftpboot/etc/rc.conf
    dd if=/dev/zero of=swap bs=1024 count=65536
    cd /tftpboot/dev; sh MAKEDEV all
    cd /; umount /mnt; halt
    

  5. Create a configuration file called config_client:
           
    !  Configuration file for running NetBSD/pmppc diskless with
    !  a NetBSD/pmax machine as the nfs server.
    
    net(
    	add_remote("localhost:12444")   ! the server
    	local_port(12445)               ! the client
    )
    
    machine(
    	name("client machine")
    	serial_nr(1)
    
            type("pmppc")
    
            load("netbsd-PMPPC.gz")
    )
    
    
    ... and another configuration file for the server, config_server:
           
    net(
    	local_port(12444)               ! the server
    	add_remote("localhost:12445")   ! the client
    )
    
    machine(
    	name("nfs server")
    	serial_nr(2)
    
            type("dec")
            subtype("5000/200")
    
            disk("nbsd_pmax.img")
    )
    
    

It should now be possible to boot NetBSD/pmppc using the NetBSD/pmax nfs server, using the following commands: (NOTE! Execute these two commands in separate xterms!)

	gxemul @config_server
	gxemul @config_client

You might want to log in as root on the server machine, and run tcpdump -lnvv or similar, to see that what the client machine actually does on the network.

When asked for "root device:" etc. on the client machine, enter the following values:

	root device: tlp0
	dump device: 				(leave blank)
	file system (default generic): 		(leave blank)
	..
	init path (default /sbin/init):		(leave blank)


NetBSD/landisk:

NetBSD/landisk can run in GXemul.

        

The NetBSD/landisk distribution does not include any INSTALL kernel, so it must be installed using another (emulated) machine.

The following instructions will let you install NetBSD/landisk onto a disk image, using an emulated CATS machine:

  1. Download a NetBSD/cats install kernel:
    	ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-4.0.1/cats/binary/kernel/netbsd.aout-INSTALL.gz
    

  2. Create an empty harddisk image, which will be the disk image that you will install NetBSD/landisk onto:
    	dd if=/dev/zero of=nbsd_landisk.img bs=1024 count=1 seek=900000
    
    

  3. Download NetBSD/landisk and make an iso image of it:
    	wget -np -l 0 -r ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-5.0.1/landisk
    	cp ftp.netbsd.org/pub/NetBSD/NetBSD-5.0.1/landisk/binary/kernel/netbsd-GENERIC.gz .
    	mkisofs -U -o landisk.iso ftp.netbsd.org/pub/NetBSD/NetBSD-5.0.1
    

  4. Start the emulated CATS machine like this:
    	gxemul -XEcats -d nbsd_landisk.img -d landisk.iso netbsd.aout-INSTALL.gz
    
    
  5. Exit the installer, then execute the following commands:

           
    disklabel -i -I wd0    (for example 'a', '4.2BSD', '1c',
        '700M', 'b', 'swap', '701M', '$', 'P', 'W', 'y', and 'Q')
    newfs /dev/wd0a
    mount /dev/cd0c /mnt
    mkdir /mnt2; mount /dev/wd0a /mnt2
    cd /mnt2; sh
    ls -R /mnt
    for a in /mnt/*/binary/sets/[bcekmt]*.tgz; do ls -R /mnt > /dev/null; echo $a; tar zxfp $a; done
    exit
    cd dev; sh ./MAKEDEV all; cd ../etc
    echo rc_configured=YES >> rc.conf
    echo "/dev/wd0a / ffs rw 1 1" > fstab
    echo "/dev/wd0b none swap sw 0 0" >> fstab
    cd /; umount /mnt; umount /mnt2; halt
    

NOTE: For some reason, reading the iso image created by mkisofs does not work as expected. The "ls -R /mnt" commands included above seem to make it work. (Yes, this is a serious bug, but I am not sure how to diagnose it.)

You should now be able to boot NetBSD/landisk using this command:

	gxemul -x -E landisk -d nbsd_landisk.img netbsd-GENERIC.gz


NetBSD/dreamcast:

Moved here.


OpenBSD/pmax:

Installing OpenBSD/pmax is a bit harder than installing NetBSD/pmax. You should first read the section above on how to install NetBSD/pmax, before continuing here. If you have never installed OpenBSD on any architecture, then you need a great deal of patience to do this. If, on the other hand you are used to installing OpenBSD, then this should be no problem for you.

            

OpenBSD/pmax died at release 2.8 of OpenBSD, so you should be aware of the fact that this will not give you an up-to-date OpenBSD system.

Following these instructions might work. If not, then use common sense and imagination to modify them as you see fit.

  1. Create an empty harddisk image, which will be the root disk that OpenBSD installs itself onto:
    	dd if=/dev/zero of=obsd_pmax.img bs=1 count=512 seek=900000000
    
    
  2. Download the entire pmax directory from the ftp server: (approx. 99 MB)
    	wget -r ftp://ftp.se.openbsd.org/pub/OpenBSD/2.8/pmax/
    
    
  3. Execute the following commands:

           
    mv ftp.se.openbsd.org/pub/OpenBSD/2.8/pmax/simpleroot28.fs.gz .
    gunzip simpleroot28.fs.gz
    chmod +w simpleroot28.fs		<--- make sure
    

  4. You now need to make an ISO image of the entire directory you downloaded. (I recommend using mkisofs for that purpose. If you don't already have mkisofs installed on your system, you need to install it in order to do this.)
    	mkisofs -o openbsd_pmax_2.8.iso ftp.se.openbsd.org/pub/OpenBSD/2.8/pmax
    	rm -rf ftp.se.openbsd.org      (this directory is not needed anymore)
    
    
  5. Start the emulator with all three (!) disk images:
    	gxemul -e 3max -d obsd_pmax.img -d b:simpleroot28.fs -j bsd -d c:openbsd_pmax_2.8.iso
    
    
    (If you add -X, you will run with the graphical framebuffer. This is REALLY slow because the console has to scroll a lot during the install. I don't recommend it.)

  6. Go on with the installation as you would do if you were installing on a real machine. If you are not used to the OpenBSD installer, then this will most likely be a very uncomfortable experience. Some important things to keep in mind are:
    • rz0 is the rootdisk you wish to install onto.
    • rz1 is the simpleroot image.
    • rz2 is the CDROM containing the "install sets".
    • When asked for the "root device?", enter rz1.
    • At "Enter pathname of shell or RETURN for sh:", press enter.
    • At the # prompt, do the following:
      	fsck /dev/rz1a        (and mark the filesystem as clean)
      	mount /dev/rz1a /
      	mkdir /kern
      	mkdir /mnt2
      	mount -t kernfs kern kern
      	./install
      
      
      and proceed with the install. Good luck. :-)
    • Answer "y" when asked if you wish to configure the network. (See the section about installing NetBSD/pmax for suitable network settings.)
    • Install from "c" (cdrom), choose "rz2" as the cdrom device, and "/" as the directory containing the install sets.

  7. For some unknown reason, the install script does not set the root password! The first time you boot up OpenBSD after the install, you need to go into single user mode and run passwd root to set the root password, or you will not be able to log in at all!
    	gxemul -e 3max -d obsd_pmax.img -d 2c:openbsd_pmax_2.8.iso -j bsd -o '-s'
    
    While you are at it, you might want to extract the X11 install sets as well, as the installer seems to ignore them too. (Perhaps due to a bug in the installer, perhaps because of the way I used mkisofs.)

    Execute the following commands in the emulator:

           
    fsck /dev/rz0a
    mount /
    passwd root
    
    cd /; mount -t cd9660 /dev/rz2c /mnt; sh
    for a in /mnt/[xX]*; do tar zxvf $a; done
    ln -s /usr/X11R6/bin/Xcfbpmax /usr/X11R6/bin/X
    ln -s /dev/fb0 /dev/mouse
    echo /usr/X11R6/lib >> /etc/ld.so.conf
    ldconfig
    
    sync
    halt
    

NOTE: It is also possible to install via ftp instead of using a CDROM image. This is not much less awkward, you still need the simpleroot filesystem image, and you still have to manually add the X11 install sets and set the root password, and so on.

Once you have completed the installation procedure, the following command will let you boot from the new rootdisk image:

	gxemul -e 3max -X -o '-aN' -d obsd_pmax.img -j bsd

(Normally, you would be asked about which root device to use (rz0), but using -o '-aN' supresses that.)

When asked for which terminal type to use, when logging in as root, enter rcons if you are using the graphical framebuffer, vt100 for text-mode.
Use startx to start X windows.


OpenBSD/cats:

It is possible to install and run OpenBSD/cats in GXemul. Unfortunately, "The OpenBSD/cats port was discontinued after the 4.0 release" according to http://www.openbsd.org/cats.html, so from a security perspective it is not up to date, but it is still possible to run for experimental purposes.

        

To install OpenBSD/cats onto an emulated harddisk image, follow these instructions:

  1. Create an empty harddisk image, which will be the root disk that OpenBSD installs itself onto:
    	dd if=/dev/zero of=obsd_cats.img bs=1024 count=1 seek=1900000
    
    
  2. Download the entire cats directory from the ftp server:
    	wget -np -l 0 -r https://ftp.nluug.nl/OpenBSD/4.0/cats/
    	cp ftp.nluug.nl/OpenBSD/4.0/cats/bsd .
    	cp ftp.nluug.nl/OpenBSD/4.0/cats/bsd.rd .
    
    
    (Replace ftp.se.openbsd.org with a server closer to you, for increased download speed.)

  3. You now need to make an ISO image of the entire directory you downloaded. (I recommend using mkisofs for that purpose. If you don't already have mkisofs installed on your system, you need to install it in order to do this.)
    	mkisofs -allow-lowercase -o openbsd_cats_4.0.iso ftp.nluug.nl/OpenBSD/
    	rm -rf ftp.nluug.nl      (this directory is not needed anymore)
    
    
  4. Start the emulator using this command line:
    	gxemul -XEcats -d obsd_cats.img -d openbsd_cats_4.0.iso bsd.rd
    
    
    and proceed like you would do if you were installing OpenBSD on a real CATS. (Install onto wd0, don't configure the network, install from CD.)

(Although it is possible to configure the network, IPv4 address 10.0.0.1, netmask 255.0.0.0, gateway/default route 10.0.0.254, and nameserver 10.0.0.254, the userland NAT-like networking layer is not stable enough yet to support a full install via ftp.)

NOTE: Make sure that you sync and reboot correctly once the installation is finished, or the /dev nodes may not have been written correctly to disk.

Once the install has finished, the following command should let you boot from the harddisk image:

	gxemul -XEcats -d obsd_cats.img bsd


OpenBSD/landisk:

It is possible to install and run OpenBSD/landisk 6.3 in GXemul.

                 

To install OpenBSD/landisk onto an emulated harddisk image, follow these instructions:

  1. Create an empty harddisk image, which will be the root disk that OpenBSD installs itself onto:
    	dd if=/dev/zero of=obsd_landisk.img bs=1024 count=1 seek=3500000
    
    
  2. Download the Landisk RAMDISK kernel, the regular kernel, and the files needed to produce a working .iso from the ftp server, and create the .iso using the mkisofs tool (may be part of the cdrtools package):
    	wget http://ftp.openbsd.org/pub/OpenBSD/6.3/landisk/base63.tgz http://ftp.openbsd.org/pub/OpenBSD/6.3/landisk/comp63.tgz http://ftp.openbsd.org/pub/OpenBSD/6.3/landisk/man63.tgz http://ftp.openbsd.org/pub/OpenBSD/6.3/landisk/bsd http://ftp.openbsd.org/pub/OpenBSD/6.3/landisk/bsd.rd
    	mkisofs -J -o openbsd_landisk.iso base63.tgz comp63.tgz man63.tgz
    

    (The installer will complain about missing INSTALL.landisk and SHA256.sig files, but it seems to work anyway.)

  3. Start the emulator using this command line (note the d: prefix):
    	gxemul -E landisk -d obsd_landisk.img -d d:openbsd_landisk.iso bsd.rd
    
    
    and proceed like you would do if you were installing OpenBSD on a real landisk. The following hints are useful to get you through the installation:

    • Terminal type = xterm
    • Do not configure the network. (The Realtek NIC found in the Landisk machine is not implemented yet in the emulator.)
    • root disk = wd0 (the disk to install onto), use the whole disk for OpenBSD
    • Accept the auto-layout (one big root partition (a) and a small swap partition (b). c is the entire disk).
    • Location of sets = disk, is the disk partition already mounted = no, disk containing the install media = wd1
    • Pathname to the sets = /

    Ignore the warning about missing 'bsd' file by the installer, we are supplying the bsd kernel file directly on the GXemul command line.

Once the install has finished, the following command should let you boot from the disk image:

	gxemul -E landisk -d obsd_landisk.img bsd

Note: Generating ssh keys on the first bootup is extremely time consuming.

As with most emulation modes in GXemul, the NIC in this machine is not emulated yet. If you want to transfer files to/from the emulated landisk machine, see this chapter in the documentation.


OpenBSD/mvme88k:

It is possible to run OpenBSD/mvme88k on an emulated Motorola MVME187 machine in the emulator.

To install OpenBSD/mvme88k onto an emulated harddisk image, follow these instructions:

  1. Create an empty harddisk image, which will be the root disk that OpenBSD installs itself onto:
    	dd if=/dev/zero of=obsd_mvme88k.img bs=1024 count=1 seek=1900000
    
    
  2. Download the entire mvme88k directory from the ftp server:
    	wget -np -l 0 -r ftp://ftp.se.openbsd.org/pub/OpenBSD/4.5/mvme88k/
    
    
  3. You now need to make an ISO image of the entire directory you downloaded. (I recommend using mkisofs for that purpose. If you don't already have mkisofs installed on your system, you need to install it in order to do this.)
    	mkisofs -o openbsd_mvme88k_4.5.iso -U ftp.se.openbsd.org/pub/OpenBSD/
    
    
  4. Copy away the kernel, we'll need it later. But remove the rest of the downloaded tree.
    	cp ftp.se.openbsd.org/pub/OpenBSD/4.5/mvme88k/bsd .
    	rm -rf ftp.se.openbsd.org
    
  5. Start the emulator using this command line:
    	gxemul -e mvme187old -d obsd_mvme88k.img -d b:openbsd_mvme88k_4.5.iso -j 4.5/mvme88k/bsd.rd
    
    
    and proceed like you would do if you were installing OpenBSD on a real MVME187. There is a problem with finding the filesystem on the CDROM, since there is no disklabel [and/or because the emulator perhaps does not simulate CDROM TOCs well enough], but it's possible to mount the filesystem using manual intervention. Here is an example (from 4.4) of what an install can look like: (user input in blue italic)
    	CPU0 is associated to 2 MC88200 CMMUs
    	Copyright (c) 1982, 1986, 1989, 1991, 1993
    		The Regents of the University of California.  All rights reserved.
    	Copyright (c) 1995-2008 OpenBSD. All rights reserved.  http://www.OpenBSD.org
    
    	OpenBSD 4.4 (RAMDISK) #19: Sun Aug 10 21:03:44 GMT 2008
    	    root@arzon.gentiane.org:/usr/src/sys/arch/mvme88k/compile/RAMDISK
    	real mem = 67108864 (64MB)
    	avail mem = 56791040 (54MB)
    	mainbus0 at root: Motorola MVME187, 33MHz
    	cpu0: M88100 rev 0x3, 2 CMMU
    	cpu0: M88200 (16K) rev 0x9, full Icache, M88200 (16K) rev 0x9, full Dcache
    	pcctwo0 at mainbus0 addr 0xfff00000: rev 0
    	nvram0 at pcctwo0 offset 0xc0000: MK48T08
    	cl0 at pcctwo0 offset 0x45000 ipl 3: console
    	osiop0 at pcctwo0 offset 0x47000 ipl 2: NCR53C710 rev 2, 66MHz
    	scsibus0 at osiop0: 8 targets, initiator 7
    	osiop0: target 0 ignored sync request
    	osiop0: target 0 now using 8 bit asynch xfers
    	sd0 at scsibus0 targ 0 lun 0:  SCSI2 0/direct fixed
    	sd0: 1855MB, 1855 cyl, 16 head, 128 sec, 512 bytes/sec, 3800003 sec total
    	osiop0: target 1 ignored sync request
    	osiop0: target 1 now using 8 bit asynch xfers
    	cd0 at scsibus0 targ 1 lun 0:  SCSI2 5/cdrom removable
    	vme0 at pcctwo0 offset 0x40000
    	vme0: using BUG parameters
    	vme0: vme to cpu irq level 1:1
    	vmes0 at vme0
    	rd0: fixed, 4096 blocks
    	boot device: 
    	root on rd0a swap on rd0b dump on rd0b
    	WARNING: clock gained 138 days -- CHECK AND RESET THE DATE!
    	erase ^?, werase ^W, kill ^U, intr ^C, status ^T
    	(I)nstall, (U)pgrade or (S)hell? i
    
    	Welcome to the OpenBSD/mvme88k 4.4 install program.
    
    	This program will help you install OpenBSD. At any prompt except password
    	prompts you can escape to a shell by typing '!'. Default answers are shown
    	in []'s and are selected by pressing RETURN.  At any time you can exit this
    	program by pressing Control-C, but exiting during an install can leave your
    	system in an inconsistent state.
    
    	Terminal type? [vt100] xterm
    
    	IS YOUR DATA BACKED UP? As with anything that modifies disk contents, this
    	program can cause SIGNIFICANT data loss.
    
    	It is often helpful to have the installation notes handy. For complex disk
    	configurations, relevant disk hardware manuals and a calculator are useful.
    
    	Proceed with install? [no] yes
    	Cool! Let's get to it.
    
    	You will now initialize the disk(s) that OpenBSD will use. To enable all
    	available security features you should configure the disk(s) to allow the
    	creation of separate filesystems for /, /tmp, /var, /usr, and /home.
    
    	Available disks are: sd0.
    	Which one is the root disk? (or 'done') [sd0] sd0
    	osiop0: target 0 ignored sync request
    	osiop0: target 0 now using 8 bit asynch xfers
    	Initial label editor (enter '?' for help at any prompt)
    	> a a
    	offset: [0] 63
    	size: [3799940] 3500000
    	FS type: [4.2BSD] 
    	mount point: [none] /
    	> a b
    	offset: [3500063] 
    	size: [299940] 
    	FS type: [swap] 
    	> w
    	> q
    	No label changes.
    	No more disks to initialize.
    
    	OpenBSD filesystems:
    	sd0a /
    
    	The next step *DESTROYS* all existing data on these partitions!
    	Are you really sure that you're ready to proceed? [no] yes
    	/dev/rsd0a: 1709.0MB in 3500000 sectors of 512 bytes
    	9 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each
    	/dev/sd0a on /mnt type ffs (rw, asynchronous, local, ctime=Thu Jan  1 16:29:57 2009)
    
    	System hostname? (short form, e.g. 'foo') test
    	Configure the network? [yes] no
    	Password for root account? (will not echo) 
    	Password for root account? (again) 
    
    	Let's install the sets!
    	Location of sets? (cd disk ftp http nfs or 'done') [cd] disk
    	Is the disk partition already mounted? [no] !mount -t cd9660 /dev/cd0c /mnt2
    	osiop0: target 1 ignored sync request
    	osiop0: target 1 now using 8 bit asynch xfers
    	Is the disk partition already mounted? [no] yes
    	Pathname to the sets? (or 'done') [4.4/mvme88k] /mnt2/4.4/mvme88k
    
    	Select sets by entering a set name, a file name pattern or 'all'. De-select
    	sets by prepending a '-' to the set name, file name pattern or 'all'. Selected
    	sets are labelled '[X]'.
    
    	        [X] bsd
    	        [X] bsd.rd
    	        [ ] bsd.mp
    	        [X] base44.tgz
    	        [X] etc44.tgz
    	        [X] misc44.tgz
    	        [X] comp44.tgz
    	        [X] man44.tgz
    	        [X] game44.tgz
    	        [ ] xbase44.tgz
    	        [ ] xetc44.tgz
    	        [ ] xshare44.tgz
    	        [ ] xfont44.tgz
    	        [ ] xserv44.tgz
    	Set name? (or 'done') [bsd.mp] done
    	Ready to install sets? [yes] yes
    	Getting bsd ...
    	100% |**************************************************|  2329 KB    01:21    
    	Getting bsd.rd ...
    	100% |**************************************************|  3150 KB    01:48    
    	Getting base44.tgz ...
    	100% |**************************************************| 87686 KB    11:56    
    	Getting etc44.tgz ...
    	100% |**************************************************|   629 KB    00:14    
    	Getting misc44.tgz ...
    	100% |**************************************************|  2866 KB    00:37    
    	Getting comp44.tgz ...
    	100% |**************************************************| 38869 KB    06:19    
    	Getting man44.tgz ...
    	100% |**************************************************|  6967 KB    01:50    
    	Getting game44.tgz ...
    	100% |**************************************************|  7037 KB    01:16    
    	Location of sets? (cd disk ftp http nfs or 'done') [done] done
    	Start sshd(8) by default? [yes] yes
    	Start ntpd(8) by default? [no] no
    	Saving configuration files...done.
    	Generating initial host.random file...done.
    	What timezone are you in? ('?' for list) [Canada/Mountain] Europe/Stockholm
    	Setting local timezone to 'Europe/Stockholm'...done.
    	Making all device nodes...done.
    	Installing boot block...
    	boot: /mnt/boot
    	proto: /mnt/usr/mdec/bootxx
    	device: /dev/rsd0a
    	cdevice: /dev/rsd0c
    	modifying vid.
    	/mnt/usr/mdec/bootxx: entry point 0x9f0000
    	proto bootblock size 5120
    	room for 64 filesystem blocks at 0x9f1198
    	Will load 2 blocks of size 16384 each.
    	0: 17696
    	1: 17728
    
    	CONGRATULATIONS! Your OpenBSD install has been successfully completed!
    	To boot the new system, enter halt at the command prompt. Once the
    	system has halted, reset the machine and boot from the disk.
    	# umount /mnt
    	# halt
    
    

Once the install has finished, the following command should let you boot from the harddisk image:

	gxemul -e mvme187old -d obsd_mvme88k.img bsd

When asked about root disk, enter sd0.

No NIC has been implemented yet for mvme187, so there is no network connectivity from within the guest OS.


OpenBSD/sgi:

OpenBSD/sgi can run in GXemul on an emulated O2 (SGI-IP32), with root on NFS.

           

GXemul does not yet emulate the AHC PCI SCSI controller in the O2, so it needs to boot via the emulated network. Another emulated machine must then be used as the nfs root server, and the emulated O2 machine must boot as a diskless client. Performing this setup is quite time consuming, but necessary:

  1. First of all, the "nfs server" machine must be set up. Install NetBSD/pmax 8.0 from CDROM, perform a default install from CDROM without configuring the network, but add a 4000 MB /tftpboot partition when configuring the disk!

  2. On the host, download the OpenBSD distribution, and do some fixup to make it possible to treat the tar files as SCSI disk images:

           
    wget http://ftp.openbsd.org/pub/OpenBSD/6.4/sgi/base64.tgz
    wget http://ftp.openbsd.org/pub/OpenBSD/6.4/sgi/comp64.tgz
    wget http://ftp.openbsd.org/pub/OpenBSD/6.4/sgi/xbase64.tgz
    wget http://ftp.openbsd.org/pub/OpenBSD/6.4/sgi/xfont64.tgz
    wget http://ftp.openbsd.org/pub/OpenBSD/6.4/sgi/xserv64.tgz
    wget http://ftp.openbsd.org/pub/OpenBSD/6.4/sgi/xshare64.tgz
    gunzip base64.tgz
    gunzip comp64.tgz
    gunzip xbase64.tgz
    gunzip xfont64.tgz
    gunzip xserv64.tgz
    gunzip xshare64.tgz
    dd if=/dev/zero of=/dev/stdout bs=65536 count=1 >> base64.tar
    dd if=/dev/zero of=/dev/stdout bs=65536 count=1 >> comp64.tar
    dd if=/dev/zero of=/dev/stdout bs=65536 count=1 >> xbase64.tar
    dd if=/dev/zero of=/dev/stdout bs=65536 count=1 >> xfont64.tar
    dd if=/dev/zero of=/dev/stdout bs=65536 count=1 >> xserv64.tar
    dd if=/dev/zero of=/dev/stdout bs=65536 count=1 >> xshare64.tar
    

  3. Start the emulation of the DECstation NFS server using this command line:

           
    gxemul -xe 3max -d nbsd_pmax.img -d base64.tar -d comp64.tar -d xbase64.tar -d xfont64.tar -d xserv64.tar -d xshare64.tar
    
    and enter the following commands to configure the server for NFS serving and extract the OpenBSD distribution:
           
    echo hostname=server >> /etc/rc.conf
    echo ifconfig_le0=\"inet 10.0.0.2\" >> /etc/rc.conf
    echo nameserver 10.0.0.254 >> /etc/resolv.conf
    echo 10.0.0.254 > /etc/mygate
    echo /tftpboot -maproot=root 10.0.0.1 > /etc/exports
    echo rpcbind=YES >> /etc/rc.conf
    echo nfs_server=YES >> /etc/rc.conf
    echo mountd=YES >> /etc/rc.conf
    echo bootparamd=YES >> /etc/rc.conf
    printf "client root=10.0.0.2:/tftpboot \\\n swap=10.0.0.2:/tftpboot/swap\n" > /etc/bootparams
    echo "08:20:30:00:00:10 client" > /etc/ethers
    echo 10.0.0.1 client > /etc/hosts
    
    cd /tftpboot
    tar xf /dev/sd1c
    tar xf /dev/sd2c
    tar xf /dev/sd3c
    tar xf /dev/sd4c
    tar xf /dev/sd5c
    tar xf /dev/sd6c
    
    tar zxfv var/sysmerge/etc.tgz
    tar zxfv var/sysmerge/xetc.tgz
    
    dd if=/dev/zero of=swap bs=1024 count=262144
    
    echo inet 10.0.0.1 > /tftpboot/etc/hostname.mec0
    echo nameserver 10.0.0.254 > /tftpboot/etc/resolv.conf
    echo 10.0.0.2:/tftpboot / nfs rw 0 0 > /tftpboot/etc/fstab
    echo 10.0.0.2:/tftpboot/swap none swap sw >> /tftpboot/etc/fstab
    
    halt
    

  4. Download the OpenBSD/sgi GENERIC and RAMDISK kernels:
    	http://ftp.openbsd.org/pub/OpenBSD/6.4/sgi/bsd.IP32
    	http://ftp.openbsd.org/pub/OpenBSD/6.4/sgi/bsd.rd.IP32
    
    
  5. Create a configuration file called config_client:
           
    !  Configuration file for running OpenBSD/sgi diskless with
    !  a NetBSD/pmax machine as the nfs server.
    !
    !  This config file is for the client.
    
    net(
    	add_remote("localhost:12444")   ! the server
    	local_port(12445)               ! the client
    )
    
    machine(
    	name("client machine")
    	serial_nr(1)
    
            type("sgi")
            subtype("o2")
    	use_x11(1)
    	memory(256)
    
            load("bsd.rd.IP32")
            ! load("bsd.IP32")
    )
    
    
    ... and another configuration file for the server, config_server:
           
    net(
    	local_port(12444)               ! the server
    	add_remote("localhost:12445")   ! the client
    )
    
    machine(
    	name("nfs server")
    	serial_nr(2)
    
            type("dec")
            subtype("5000/200")
    
            disk("nbsd_pmax.img")
    )
    
    
  6. Boot the "nfs server" and the OpenBSD/sgi "client machine" as two separate emulator instances:
    	in one xterm:
    	gxemul @config_server
    
    	and then, in another xterm:
    	gxemul @config_client
    
    
  7. In the emulated OpenBSD/sgi client, type 's' for Shell and run these commands:
           
    ifconfig mec0 10.0.0.1; route add default 10.0.0.254
    mount -v 10.0.0.2:/tftpboot /mnt
    cd /mnt/dev; ./MAKEDEV all; cd /; umount /mnt
    reboot
    
  8. Change bsd.rd.IP32 to bsd.IP32 in the client configuration file.
  9. Finally, run the client again:
    	gxemul @config_client
    
    
    If the root device is not auto-detected, enter mec0. Note that booting is very slow, so be patient.

Many things are not working yet, for example X11 does not start yet due to some bug in the keyboard emulation. It is also very slow, mostly due to having the file system on NFS. In order to self-compile GXemul under emulated OpenBSD/sgi, you need to run swapctl -a /swap as root.


HelenOS/testmips and testarm:

Old versions of HelenOS can run in GXemul's testarm and oldtestmips machine modes.

To run HelenOS for testarm in GXemul:

  1. Download the HelenOS kernel:
    	http://www.helenos.org/releases/HelenOS-0.5.0-arm32-GXemul.boot
      
  2. Start GXemul using the following command line:
      	gxemul -X -E testarm HelenOS-0.5.0-arm32-GXemul.boot
      

To run HelenOS for testmips in GXemul:

  1. Download the HelenOS kernel:
    	http://www.helenos.org/releases/HelenOS-0.5.0-mips32-GXemul.boot
      
  2. Start GXemul using the following command line:
      	gxemul -X -E oldtestmips HelenOS-0.5.0-mips32-GXemul.boot
      


Ultrix/RISC:

Ultrix 4.x can run in GXemul on an emulated DECstation 5000/200. (Ultrix was the native OS for these machines, but NetBSD/pmax is also usable.)

            

The following instructions should let you install Ultrix onto a disk image:

  1. Create an empty harddisk image, which will be the root disk that Ultrix installs itself onto:
            dd if=/dev/zero of=rootdisk.img bs=1024 count=1 seek=800000
    
    
  2. Place your Ultrix installation media in your CDROM drive. (On FreeBSD and similar systems, it is called /dev/cd0c. Replace that with the name of your CDROM drive, or the name of a .iso image file.) Then, start the emulator like this:
            gxemul -X -e 3max -d rootdisk.img -d bc:/dev/cd0c -j vmunix
    
    
  3. Once the first stage of the installation is done (restoring the root filesystem), you need to restart the emulator, booting from the new rootdisk, to continue the installation process. This is done by removing the bootflag ('b') from the second diskimage argument:
            gxemul -X -e 3max -d rootdisk.img -d c:/dev/cd0c -j vmunix
    
    

When the installation is completed, the following command should start Ultrix from the harddisk image:

        gxemul -X -e 3max -j vmunix -d rootdisk.img

If you have a very fast host machine, you might experience a weird timer related bug, which makes it impossible to logon to the system. It is triggered when the emulation goes faster than any real DECstation machine was capable of running. The first thing to try is to re-attempt the login a couple of times. If that doesn't work, a workaround is to add -I33000000 to fix the emulated clock speed to 33 million instructions per emulated second. If the workaround above doesn't work, you can also start up other processes on the host, apart from the emulator, so that the emulator runs more slowly. This is an ugly workaround, but seems to work. Once you have logged in into Ultrix, you can kill the extra processes.

You can experiment with adding -Z2 (for emulating a dual-headed workstation) or even -Z3 (tripple-headed), and also the -Y2 option for scaling down the framebuffer windows by a factor 2x2. There is also a -z option for supplying names of X11 displays to use. The following example starts Ultrix on an emulated tripple-headed workstation, on three different displays (remote1:0.0, localhost:0.0, and remote2:0.0), using no scaledown:

        gxemul -N -e 3max -jgenvmunix -d rootdisk.img \
            -XZ3 -z remote1:0.0 -z localhost:0.0 -z remote2:0.0

The photo below shows a single Ultrix session running tripple-headed in GXemul on an Alpha 21164PC, with displays on a Sun Ultra1 (to the left), on the Alpha itself (in the middle), and on an HP700/RX X-terminal (8-bit color depth, running off the Alpha) to the right.

        

The X11 displays may differ in bit depth and endianness. Unfortunately, there is no way yet to set the scaledown factor on a per-window basis, so the scaledown factor affects all windows.

(If you didn't use -Zn during the installation, and compiled your own /vmunix, then it will not contain support for multiple graphics cards. To overcome this problem, use the generic kernel, -j genvmunix, whenever you are running the emulator with a different setup than the one you used when Ultrix was installed.)

A note for the historically interested: OSF/1 for MIPS was quite similar to Ultrix, so that is possible to run as well. If you are unsuccessful in installing Ultrix or OSF/1 directly in the emulator, you can always install it on your real machine onto a real SCSI disk, and then copy the contents of that SCSI disk into a file (using dd(1)), and use that file as a disk image file in the emulator.


Sprite for DECstation:

Sprite was a research operating system at the University of Berkeley. A copy of a Sprite harddisk image for a DECstation 5000/200 is still available. If you want to find out more about Sprite in general, read https://web.stanford.edu/~ouster/cgi-bin/spriteRetrospective.php.

            

The following instructions should let you run Sprite in the emulator:

  1. Download the Sprite harddisk image:
    https://github.com/OSPreservProject/sprite/raw/master/ds5000.bt
    
    (83973120 bytes, MD5 = ec84eeeb20fe77b758370d5e312e4a5e)
    
  2. Start the emulator with the following command line:
    	gxemul -X -e 3max -M128 -d ds5000.bt -j vmsprite -o ''
    
    

The first time you boot up with the disk image, you will be asked a number of questions regarding network settings. If you feel like entering correct values, then you should use the following:

    Your machine's Ethernet address:    10:20:30:00:00:10
    Your machine's IP:                  10.0.0.1
    Subnet mask:                        0xff000000
    Gateway's Ethernet address:         60:50:40:30:20:10
    Gateway's IP:                       10.0.0.254

Unfortunately, at the end of https://raw.githubusercontent.com/OSPreservProject/sprite/master/boot.txt, the following sad statement can be found:

    The bootable Sprite image is meant to be a demonstration of Sprite, not
    a robust Sprite system.  There are several missing things, such as 
    floating point and network support.

Once you are logged in as root, running xinit will start the X11 environment.


Debian GNU/Linux for DECstation:

It is possible to run Debian GNU/Linux for DECstation in the emulator, on an emulated 5000/200 ("3max"). However, just choosing any Linux/DECstation kernel at random for the installation will not work.

  • Linux 2.4/DECstation DZ serial console output doesn't work too well in GXemul. Linux oopses randomly, which may be due to bugs in GXemul, but may also be due to bugs in the serial controller code in Linux. (The speed at which serial interrupts are generated can be lowered with the -U command line option, but it only reduces the risk, it doesn't take away the oopses completely.)
  • The Linux 2.6/DECstation DZ serial console driver doesn't work at all in the emulator, and I'm not really sure it would work on a real 5000/200 either. Hopefully this will be fixed in Linux in the future.
  • To get around the serial console problem, the obvious solution is to use a graphical framebuffer instead. Old Debian install kernels supported the graphical framebuffer on the 3max, but not the keyboard. (This has been fixed now, it seems.)
  • For quite some time, the MIPS linux cvs tree has had support for the framebuffer and keyboard, but it did not include Debian's patches for networking, which made it unusable for network installs. (Possibly fixed now.)
  • The kernel has to be for 5000/200. This rules out using the default kernel on netinst ISO images provided by Debian. These ISO images boot directly into a kernel which is meant for a different DECstation model.
  • The kernel has to have an initrd which more or less matches the version of Debian that will be installed.

Luckily, a precompiled install kernel has been made available by David Muse, for Debian for R3000 DECstations, which has support for framebuffer, keyboard, and networking, which works pretty well. Thanks David. :-)

The following steps should let you install Debian GNU/Linux for DECstation onto a harddisk image in the emulator:

  1. Create an empty harddisk image, which will be the root disk that Debian installs itself onto:
    	dd if=/dev/zero of=debian_pmax.img bs=1024 count=1 seek=6000000
    
    
  2. Download David Muse' install kernel, and a Debian Netinstall CD-ROM:
    	http://www.firstworks.com/mips-linux-2.4.31/vmlinux-2.4.31
    	http://cdimage.debian.org/cdimage/archive/3.1_r6a/mipsel/iso-cd/debian-31r6a-mipsel-netinst.iso
    
    	MD5 (vmlinux-2.4.31) = c88dc0a26b91e3646698179c18e8169b
    	MD5 (debian-31r6a-mipsel-netinst.iso) = db1bf2f8e5b24f820f37034ec1d20bdc
    

  3. Start the installation like this:
    	gxemul -X -e3max -d debian_pmax.img -d debian-31r6a-mipsel-netinst.iso vmlinux-2.4.31
    

    If everything goes well, you will see Linux' boot messages, and then arrive at the language chooser.

                                       

    There will be a warning about the keyboard layout. Don't mind this. Continue, and then select Detect and mount CD-ROM in the next menu.

                                       

    There will also be a warning about lack of loadable modules. Don't mind this either, continue anyway by choosing Yes.

    When you reach the network configuration part of the install, choose Configure network manually and enter the following values:

    	IP address:                 10.0.0.1
    	Netmask:                    255.0.0.0
    	Gateway:                    10.0.0.254
    	Name server addresses:      10.0.0.254
    
    

    Choose Erase entire disk in the partitioner.

    Wait for the base system to be installed. This takes almost forever, so you can go fetch several Jolts or cups of coffee in the meanwhile.

                                       

    Congratulations! The first phase of the installation is now completed. Reboot using the following command line:

    	gxemul -X -e3max -o 'root=/dev/sda1' -d debian_pmax.img vmlinux-2.4.31
    
    

    The post-install step takes quite some time as well. A perfect opportunity for more coffee.

    When asked about whether the hardware clock is set to GMT or not, answer Yes.

    When asked about "Apt configuration", choose http as the method to use for accessing the Debian archive.

                              

    Downloading the packages takes almost forever. Be patient.

    Congratulations (again)! You are now fully done with the installation.


Debian GNU/Linux for DECstation is now installed and ready to be used. Use this command to boot from the installed disk image:

	gxemul -X -e3max -o 'root=/dev/sda1' -d debian_pmax.img vmlinux-2.4.31



gxemul-0.6.1/doc/20140802-dreamcast-bios-test1.png000644 001750 001750 00000030022 13402411501 021325 0ustar00debugdebug000000 000000 PNG  IHDR/sBIT|dtEXtSoftwaregnome-screenshot> IDATxy^ea=3Y&{& !ŽQ@#nUֺV"XmS[[姸C[ ԵU0lo!$!d̒CB$\sϼ߯׼ ۙ\:Ts.YPs.9ʦs.YPJ}ZJ_3tgL- 7BgdNRR`TՌkϨtsN%IO"B؃*JZzF'u>ՖϨ«p0*3Ҟ$f:V<^PWwS5`Hz=fк* ݷW*ⴥJCzeY| IYG/@Ҿvy.~$:ߗhYՋLWG[R V][ӾvEFoʈc7Zg{K7 S0ja!<2{ZS?ow__߼2k?ζ$Ɉ?}4NѯaʺeOmt'~dF4Mܣ$| adc|B6nKWG[LIZ"Mrwڥ9u #2~ӴfߞYGOgۺZlOҐQi<#c~l6v}~} eWѺrI-LwG6y_I*O]CCF͘32zTx u -_ԏ32nT꒧[:︌;qhYܑ2*k&eykui_p9Ϣg^qsOHI̞61?ҏ(uo|9Ӳj][n>4cնr9t}h,^ޜffg׶o;֥cnˮ,c͢s?9#Njw?դ+kZ+sͯwߖM]e!?DGgwl5z0|W׷{vO?Yܒ1Ѳ&$W,[.g[-Zʵ큧?= 3aYP>3i\ؒ",z(dO|;O.[Co>y b8YdZM>g]6g-_}i__߼*`>ӎ] _\P33wfSjnZjNB;ohg;+27>G0vϿ七r!O}+Mͨqetuk=y}L/_ysnttg/;6f✃s r~Ss[__RI>dy|ЉjIZ/JWG[G)f}76ˆQͺeOk}F֜ݕ1!8~tѢ&udJg'孟,_i'Sλx{yzT*^|owYL06=|M+?y0&d>&IZ/ʚo6d>l>[ǚg?xnK]È|#o2&ãyyƼNy*mҩ8cGe9#w`Q>gǧR5YlagQz~URIaD'LɄR{>]}M&IۚeiyfQַRWq3fl>vGڬ]H[Rf三;mvFkZ| } cr/̟L7:|s/N=2^umY(gqtN&Sλ8#w=2ߤi3i\%+76=vhO??} w|_暻g~'RZ_J^zm#gcț_,$=7c^ sIROݗޔyz:!V7ޓL}Dܨuc2u,\:_ :-g3*<2_YCm52hі:ny'd|銛teK*u7i6e:oqIoLypνGi<#')SF5_C}[__\t/=TՔ >zn~xZٺUR?1c'M{-M=Y~1wfC'sj>S_AZvpYі U::sƋ[O;2ݺ0˞<^t/?=;&˩_1gJoܼ1禧Z'rɏ̘GeɽKrc7h˝/7ܛwݵu,Z tuf;G)m+ݟֵ9a u}MǤCrᷮKxĜt׬)GlvfykJ}}V7Kמj5_YiݘOUGN͇%yx#H>S#uyw\yr៽&N\#N_m~V?yƟnbb59Ͽ;W-NȺwڳT59r 9}tesWift|N7Sumw`(3[R?bt.bA|ry?E9`|Wؕ<),|&]`E͵w/OϫՏߕq@>p'5ٿ%/IVڜJ}}F4KӜʛIN7CL;pup^o=ݙfkeSy1S"ͭnaMW><-43rμ'd)uyҼ-OؔhkN:$+u咜C3>?TMeTw>r†uԦ嬣穟ۥӎ~9oY%ĴzmuNjyɣs^yE7~E3o|}IGw=g ?FO/^KWe>y|.] xu|AAVݕΎ~}tuw4jjfuݑI$+ֶٹ^!F4/[XJ*e%i'Ƿe][G$g?*/l_e#s}On2z,L̝99]^Gne_΍SIn+o'gȼugSok~,o峣?=cB=NIO\yK&{P&9&̧|LK[g>z鵙4茚0% ]|9#?sy/o|ayڡY ]]TvYe3{U>oǞꅿm~,]{ԉcݵ~_[3fߣ3}~ߔK,\֜ΞѾ7[~^?7vLWܒfcv\v3njJgWOYݒj5w=<u5T"t]7傳^$mq6'߽THEi]T^wߝqӷ׶_M%qbr7}.=v^>o89ҏj\<|y|ݪ>=f۲ٝ+~|G2qcRdELjGsr܁RI2{\w#Y92M#FosyIdEs[3;6{.Ғ͙6}Bd?fM{ڥb<_$j{9[ܖTRޏofgGwTsw\QOqVOq3տ8+iM|s-n3FOX~QKv_f-~%IWL.$Ʌݔ|=xrʬikNY53s\&:(I֜}tG񥽡qro3>ӻ>g/81jdC4ٶnA\I3VіO.x$4NeOlgz[v)I~}ߢ44/gȩ9*Vd5eB[fqY0ZxNo{LӬǷ>y3'G?yw4g}]^ Ɇ7<}c&ɄssiN=b㩲.7cCrř0vT}Iyɇϟ]qf:n/ծviim }=Pr4lLW{.mbFo>GdΝ-}=Ӗ;;R]h>gf y|\J?/ivwW*]#ՕJe CYUi;?pimHKxy?\58mքs?myjE=/?"#V="m>jݼ|ݯ--o/#GyeZ'˯ݵtޙ/̤q8:/:|Cggcw6O1Ӿkw|ަ vA7mNyI7^=vG.suwiTgN;n^/_kn{|Ѵm t?M9z|7 CdzRɺE}ez|kKMOOiYtOV_xwr?͏h_L^r܁?)$S]ǗܙMyɱ}3}ZGDLu7-mdGw4mo |⛷$Ɉq?c^&ARߐ?ri_UҾ>,|&,|&/>)sfLcKVW.Hӳg=nQ37-YcOnѧ_&;Z8|[7Co:9}Kxys.yIQc'摧Wgy׫OȻ^v_~grSλ8{iƤ|eezOro߼|M'ݑoor#J%͗{s~pۓi;'q[trw/|J~tq.Κ}*MhNRWOg/ڬln7zns@V5_7vLoLk{Q fҜi;1Sfs_1wz:zrCիih]KgO5P}?3}Lgv~Ĩ4+_Wy 7|L{nˤ9Gi篓MKh.WeYj].MU443`ۡ߆]e?9~{;Mݦ'Or{`㱌>-r% +[lKz:ٞΎ~g'c'J%uuohH1bTGNOtm/!X'-u9ITF3>=$/mN豙vZ3ݞ4N -m v9]4hM̦ve;+KӺַumF4%>;ۚ3r̄>̾f!ZIRWU{jwݝtӓj2+TRO!4'u); M55_Mݓt.I]R?"{v ض! @ Ira;>s% P! @B"(EQ!D(BP! @B"(EQ0 ?@,q 72P! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ; IDAT!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQh(@^z`0*}$D z{-&0\|+_zqڻ(! Pepss{clx R܄( B3¹ 1kt7! {e8487ߛ( ~BPΒyap Pjݦ#[v 08 Q؃D(/#Z4F0Q(F77|np DaPmpeW= B Yt52AyBeoQlz:P @vҖP]$B]yiKQػ(-}N{~lF77?i`MugW=YBvBO[^ʲV/ms 9BC}:( վ]z`ZᄐVKo} ms.YPsɂ[}ndjW̟?~}]) ]|FEkn]KnVo[ÃM Bb\``َRk(lkԨ( QsF` : D&D)/M;LjvKje3g&!J0g!JM0tQI&l#FRl؜"FR&Dibj9&!J1=$}`Q#FE6Z#DR!Dr D&D)foL7qNl5BbhQQ`QQk(900("sF`Q bv2~Qk( ġvc;D0@0(N7Bb~vZ#D)f8 9! {9}B0sF`ۄ(%FG`sBbx6Z#D)f y/! {9KB!0 Q(H0 Q1('!J1F7vF a7=ÍAD0Qd BRI;vZ#D)ƈy͠Q`(0ș3 P%DF`cR}ỳQ1kPk(sF*((sFuBj Q1~`x l5Bb ,'`;@0DM@0Qjs + _!J1F,/ ?! C vB01 `&DasIP+!J1&]oϩ5Bb}sڼǩ5BsFL( 30XQP=Mc4np GXemul: Configuration files

GXemul: Configuration files

Back to the index.



Introduction:

GXemul can be started by entering machine settings directly on the command line, or by reading a configuration file (a "configuration script").

NOTE/TODO: This section is about the legacy configuration file format. It should be rewritten some day.

Configuration files in GXemul are useful/necessary for three reasons:

  1. It can be difficult to remember long command lines with lots of options.
  2. Some settings cannot be fully controlled on the command line. They can only be set using configuration files.
  3. Complex setups of multiple machines, or complex network setups, are not supported on the command line.


Configuration file syntax:

Configuration files are simple text files. I don't have time to write down a formal syntax right now, so I hope that conveying the syntax through an example is good enough:

 
!  This is an example configuration file for GXemul.
!  Anything following an exclamation mark (and also the exclamation
!  mark itself) is ignored.
!
!  Almost all settings are optional.

name("my test emul")	 !  Optional name of this emulation

!  This creates an ethernet network:
net(
	ipv4net("10.2.0.0")  !  The default is 10.0.0.0/8, but
	ipv4len(16)          !  it can be overridden like this.
	!  local_port(12345)
	!  add_remote("localhost:12346")
)

!  This creates a machine:
machine(
	name("My test machine")

	! serial_nr(123)    ! Useful when emulating multiple machines
	                    ! on multiple hosts, and they need to have
	                    ! unique MAC addresses, etc.

	type("dec")		!  This is actually not optional
	subtype("5000/200")

	cpu("R3000")    !  Normally set implicitly to a reasonable
			!  value, depending on type and subtype

	! ncpus(4)
	! use_random_bootstrap_cpu(yes)

	memory(128)	!  128 MB memory. This overrides
			!  the default amount of memory for
			!  this machine type.

	! random_mem_contents(yes)

	! prom_emulation(no)

	! byte_order(big)    !  Normally set implicitly (because
			     !  of type and subtype, or decided
			     !  from the file loaded with load

	load("netbsd-INSTALL")
	bootname("netbsd")
	bootarg("-a")

	! n_gfx_cards(2)         !  for DECstation dual/tripple-head
	! emulated_hz(10000000)  !  for setting the emulated clock speed (mostly fake)

	! add_x11_display("otherbox:0")  !  for dual/tripple-head etc
	! add_x11_display("thisbox:0")

	{
	    Devices can be added like this:

	    device("ns16550 addr=0x18000800 addr_mult=4")

	    The name comes first, followed by optional parameters.
	    Remember to use 0x for hexadecimal values.
	}

	! force_netboot(yes)
	! start_paused(yes)

	disk("nbsd.img")
	disk("6c:cdrom.iso")

	use_x11(yes)
	x11_scaledown(2)

	! slow_serial_interrupts_hack_for_linux(yes)

	{
	    Long comments spanning multiple lines should be surrounded
	    with tuborg parentheses.

	    {  Long comments can be nested.  }

	}

)

!  Multiple machine definitions are allowed.
machine(
	name("another machine")
	type("hpcmips")
	subtype("be300")

	...
)

Starting the emulator with a configuration file is as simple as

	$ gxemul @myconfig
if myconfig is the name of the configuration file.


A minimal example:

Here is an example of what a minimal configuration file might look like:

 
machine(
    subtype("3max")
    load("netbsd-pmax-INSTALL-2.0")
)

For most machine types, type is needed. If only subtype is specified, and the name is unique (i.e. there is only one major type which has such a subtype), then the type can be omitted. Also, adding a net is quite useful, especially for netbooting kernels.

gxemul-0.6.1/doc/20051007-netbsd-cats-installed_small.png000644 001750 001750 00000006526 13402411501 022760 0ustar00debugdebug000000 000000 PNG  IHDRtMRgAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxYovz=/IIGM3L츞m&f'HEEۧ˾@>EmЬ;l:xdDKDx[$MZ[;@@;OK*KD1Ԍvgm?i dv65JWwj`wvk3Z`V tSX#bПnꝏb9+$^QiAfh,DǗH@)'oNpkkp󵟗Vdk٘`bV4sCq"gbȠ#oPԧaɝcLT> gtYeh`aC=a|:U<[u>te- ڽ;-ߠ{-k 'M1=tUXD\6rYQ{M\ہ淕GfjKbro l"T9#ꄓmPp(n! jY8q=-_eSc^jXd|Ç竟*_ i/?jsx;mν.Lη9' nGL.c$o|$/:$tIE[M*+kg: y3ӶD\6H!Iľ̢EC qW)HYOn Lx8O"a1R*]H!ZOvCs8ݵ×P cSjkߺIE'zqU{ۿ.f[?D\_?s^+ݐ_nWX [ꅼ%4& Z^`=a, P0ʹJf=#j@mMNb 鄅$1-NHS.$N:9Я7i͟ŵ"/b}{kmSb#v{q[z`bݰOu ׄe6Gju6"08||t`Z'|( ^¦0T/z%/am8ώAeqb,e|G_ٗ8G~ԫ 4gwY? f]@A`Re-ץ4u^nZo~*40>$QTw.? $MZ}پqC䚓D~)w֬XUEn#7Ϝ E~k#~Q vI;"eb}rק{TGїatjcO~J<֤u̮d"Bod-.P梥?kOQyT%8$}e/E  8l !o  ^Ȣ+tۙ,\.kd?fCe+~)ȹ3 ^kU}Wʹ *ۤIbw! Cj99yEݮꬽ}] =9Ovوil>{;WpgZu:SX8&y +'EZښW9.hCJ3nډ^%7B4cҫgjKҦ#|xO:%nB'Fn(E/=*R`e|\z^$WOqB]8\O.6o=?BKm? j,+_sl0e"CfУͪ;4ftyћj7|3a@E]„ݫ4:(k|#vsԒ\kr %`ەcdo(((ڤ{go]uzAz11AB,YmpE]Enڗ'K\^;ONWYW3t}%ąS%GMl{u58jgtt;^G Ք%wwul ^? ǻ \sB<eP] _-cn2@%z18$qw&Z 9`1gڜcf @pJw+{rq0ws،=MI^X8$]F>ǭƎ?.X0:<*q[7RT}ިѥMNw'\DmP\ 9q&2Øi;B1|?0Sp0݂ʼZ?X4 ` ݑ:K֏?$ôKϓŧD呃j7=HH=:+xf0d`<0!Cr0ӑ' 3=PhSu!Y~V^88~t2iB w14}tIME4IENDB`gxemul-0.6.1/doc/20051007-netbsd-cats-installed.png000644 001750 001750 00000016054 13402411501 021565 0ustar00debugdebug000000 000000 PNG  IHDRS,=gAMA aPLTEHHHd6MtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0YIDATxmn뺮u!X{/#ApQ M,|Gig&lOdzM-J 痗bQ}ZogXTw-o_^Eo?]~1[? G/?)_?>^ϖ.gO_gJstq>w|pr|KuGrwi`||˟JT>|< #?߇oqt1Or|~8V>;=0A8ZB{aʂmiu'XG䧊f㐏@GPx(+T R[8.~IGá4|p`a;|-i[{=W1^g,'`nQt8~XW{N{Y~UReQpz /w so]p?>pПNs:S ^)R>qO$J+{$?actWx:RDxt|]8.)^V93?xd?˕cp59ޏ#9Q䰼:.Cw,x@%|_{=w8G[8ERBm@EĞbvmzh<G=$^#lGÿ2=AFY@^fyYn7=N>p;nmo8W<;|W3vI͘ ߙz п~^=xeVOOʢp akdfꋺbp{Rb-u*ǐd=8jp,OY n4_?5O/yvQ; p3㼌#~!۫18Mc Gp0]jlGUЯ?:m3 {یg!kP^ }NtőhbEv;ۑL}.<U6wz`85ǚԨ^ߔ!1?i8G7q}&>Q Ή̎tΎ@ϕ?]h #uXvcOl6¾S O>cpk39yZ@qDt~vS-Ӣ򳆢kVZU9^GsM_c;, ~==|t{7N_9./شǎv$?3{X3z|M=",(-q=#t#U9ڧRRg1=m1QG~MÓS,I}"FV٧Gv4Pp&V8ޣv۾v4];@]qsȟq9fo GEqϷI c?0ޭŭr;9lJ^FmM4kX| g%{aˑivZ>zP`}G;ï4}ϱN[G?3kǮ8ȇopO?_W'P?>Y%G1 )] Y9 ɯ\E%{fYGXȢS6@I3/CcT] iBT|+oT/GG,qB1_qT)=c%,eX 5dő'+@r,X>ɇroOlO#v9&c`swp|VcG!. Gy*xwɚ5pͣ2q|#oTF3^gKue\&u9N;x|(/MGt_R#{Q/nw#w9:G9:G8Gst9zq9:G/rR2G1ڵ1Wq }"DbskH=G[d4%}:K>J|Gy%Y,ZE`eIL %ƈ i8\hbΚG+!6W%47k9X{=T\K{}&7uh#ɞivi8r?OAp-9=MP7Reıs9ƫ9x~aӞ3gC8Kv924BS{˼<5pL|as#ps8?msʾG 05^|nQ~geAukz;8z~N{T߮#s)B#\[ͺkȑߛc8#&CѰhGmfM6:KҵU?usr$:#8rSR8s:jvdIr_"uIuKE˜#@]3N&qB׌9Ĭj/A>Ҽ0>AOQGR}3]?q=9:G/Gx9|Ƌst9zq8 r321:G縝u3>ۑeu)&o֒}OFK~IWq'$@1/αϱ 8 ; GtWǪl8z:$uD_} qlL[6Y]9^p]al{s|f]b>f_^Â@ǓxIZ6j8uфل%OؑVS}/!ƙTNp_$# Q6y B\Z{5Oov x}u1'/̑5n#u,khaM$,q5Ѩp$Ҭ3:ms&A] _;8Y3J9.$A~b9Ag_'1'1R(kHc:#5L<>ak5aN8 8XmJ4/HƱ^Ƒ97%=[u3&ìuƵ`WzסN*];8^;?/ٜ9>RCmz=96 -2YWsZL]lA{ht.2*-l]U;.]c튣L+hg^1﹚'gsƻum3=۞GQz%'Cl8:qYSpUȺ)9kЗjnȱE0j[ Wkvq0Lr;s=QHN֍i&vwZ7O/ysܝz?rHƹ/z=e='n:ns9X? L_Qԏ$sc]G}!Q}Qo~!Rrk8ec ~.ď3 mY}4"N:/ vMN\'kF̃(i7T #hrqϚps ^wV'*/9 Gͱӷ{y$H=(G#/˘ZriW| $%7 19hsotRb,K/]X4wjT:돡Z0tǁ)hDz4 tHI=[=BN]vG[T5Ƙf/&7< ^9=^?:ǻGr?{scl>q9zqqv؉%:OF7؇(BʱƖݖcnZz h,Ky5Tl0YQf1fQUWy$x"۴V9vW){,f-x1@d9mҎ9 6CH8U~9FckKAGuS:h@^?v}p#ϓ:90!gޒ;Vywyϯs8+&߆ϯ{u>stO}$?v1}롍#N1$liWhmt501U; {wlo1_^g8B(z&|Rc>?2I1k?O:%dB#ݎ?+z*kaY%#OهYQHuT%e߹VKIdf&gӨQH:K˺Eu50yؑ8Ĝd]Nh257V(1un"aek C&>4d D\&ٴ=.,YBҾ}Qt(A52昖87bf&~$.!i<ѹ&u$N(o@_Ľ>ѳ r6P,GlMc#¾s5Lg"똠eZMt\V}Mtp\'"39BKчMnnL38ה1*9i5GÑjkA+R1cC-welBȞn?ףsU|F (=xr&ϨheZ.#;^%tu3{9݄V8Ecm`݌}.y=nA+3/0t.>יs-'j:G}{u[q|V#/E5|-<YT-.Nq|V(~v:uzF'"Ѩ:55\~_?M+4c//,Gb}v2ty# 97Bk8„ehy1Ƿ?O Q Ros9%?[#B}{> Tņ#aλe{̋8?78/'k+͇sܦNqm98G)ss9:G/?z{t>9do^+_R>Ljߜlyk8k9P/sŢ:r|wh{O4fEMNPޠtIME  ;(XӵIENDB`gxemul-0.6.1/doc/20110703-dreamcast-gltest-small.png000644 001750 001750 00000023275 13402411501 021754 0ustar00debugdebug000000 000000 PNG  IHDR% gAMA a=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATx}{p[uă ERЋe[fC_ N2Ifg놙&δgʤ33Գ;>v]lg$FQ-7UjlKd=)$xGG 2@~g4ˋ~.;ˋobW'hRtEqU=ǟݜ"nGJ2lJtoDi0˖EpW v|F G"&EK2o|şoQUbek(iVkg}j?=}#ȵX5t>kc|^=m Ssӗ;ҚPBס_9?l|pOJXOu5G 9N 5@ٔ3RŃbl/2F:u5kCշNsf:p,k3kvI~r l_ҥcҼQ??WR%9NՀ TRժ D2\UO=BDdkσHY&R9En*3zPdlШ-3bt"L=]X"bLͥp\ߜ~Gk\?d;=+)=xae%JookVՑHg>?ڳ{;#ѹ_{⥩=.^/='woWǣ==wiV^>ߙI¥>6I.ҕ3'Mf;JϷߞ:sCuN /;h]ܷ5|&kmsL^0553z}fۍW['Ou[wlk[jf|FͥEտ?/?mKe &>`xZ-jo^Ʒnh>PY:Vc+Aخ+]yos{dO6*}֮]צ;?~'zޖ`Ig;[27Z5ikS)g1~mSoye~ٔO|xa.B zwf_~(%MH,EwoZVޮ\iЩϞ#:?}WwN.h5=zygy`W  czfⓓ,// Kמ|!&j;'mM86=7cjɈ7<Mu tzÒW~-o$QͿ2OXf&t,Meu\^ \!03scr'|Hj1Y/K ) kAQLk0x鲥u?󁹹klhuޏ&,&cD^[^Ym\tYw-e{%$עEWMROMQi!0mip i[f QV}ͩeYGuj.k'g)݊Dpv1h<19-Y4P(7rKeu:bݦ?:Mp<0tD:NS;ztZM>?2_i5x⹯<3޽նn[Y tw7#ю6[> Gzy{gGu:mGm%n|4fͻvlWJL*z?y;573X4̹WHwgc8jTK]t& 5[-|3|HRt"t,jSRlߟ[ Ay2mⷿ )X6贷tpY3י:5q<#}Mٙix4X^;SZt:Mv^R,Nj??|n‹>n5ғ;:v,{|>Á?:p8$I6^fI488H&xzxdd[lhH+;!< n7 z Z4x+\h$ixxvn7Hp88q^X]Xx1labCC8<Á*I 3]͆i܇p8@zU:U>C|_{3 ].:NPIn7Z?. +qya EmMmOUg_Qxzhђ|w&IXH˷C%kk2WimVsacF2::яІ,q{-ms#h|>J ~Wx !x8w\NS=7![΅CmhLlATbٗ$idd)LfcNsyt"V\l}[mt]B!Fnǃj{q {sbB QR[kߤt\ʧ! #YQQ:5n7=2G9A(3GބlHmk;OJ z2#! Deȩ't*)#mK( "mڙoT,t-<%Vډd+&l`Ű2gTܶ5oݯ5T3%n7j!BmØT<\~G$ފ*e͵ D[qpp"D1}r(Bx"[ȑ1::"WzJ$o]xoB( 8ΧB{022ي( E&Gsܰi"l"~o A!==Cl6<&2Aܐ'~ڶ*v,jŝ: U<*+Yh5-I{\,gT>,'<:~Xl|Yc'EPMWhʸ7Ĕ 0 GJtq@ =Lc]XLJ%@ )&*,'\6$/{_[-ry EKGw#S3 dD[x<L|>ۍZU~@r2qk-v7X"ݕ rL9^4ס>(i|i!n,! 'J0qG:<|H-x9)qyUfZɛ5j*R(UlIx~ ^#s p_#/)zy-3Tފt1nZEşך= Çu||x[XT5Oê6KE&B.DCmm;h\ٓ-t#pxxB)p=Ϗfuhn8 Þ9'IAa2קQ) c-ܒ'9 sE'V,y ϿXNkihEO:oZzzkhhȑ#CCCV/׿׾+Nzg1e PvPΛq:/]b^Ga$ CoOkN,~{4taf  uvvV0 FfFZC9ŁСC{><Gm#lF(|t]gCMyYOCZugS bȆ'ʦm *IMP4) M}>Q7!riV_:uɩ?'x<ʵ u"Xj̓G^ yŽ^7>F- {`xTKx[GZW,!]meB@ MJ2P)!qQ###䛡exp`7ڢFHAk-C ];,Uߠ~?<`Tc"%R% dTp+nd4nHgphCkj^*<0UIhVqW###n8)Mf%9Y,ݙPهx9 US].ل$ZJx.{]END\$ V% uƓ TVTTSؓKV=>9e$aXn~KZ{kh}e]s]u74eQi%h:R)r2x4 oQW~{_*=ž܄ooVt~{幫}udOZO7H5V%D*/4AHy9>(ɚ'7v}KR-3-uMI%pG5xp|Pp:jv1FE=P ʅ6ӟP)F钍qK -ҫd9ޯIzoE'%̌w1ER_B"W &E4ex|Lt,xr[58V\ї0.MPLxΎ˛`ҕ'=)+sE\WDi|L})*eД=)P3s$Or uűD7))Ǵ+4b _"&*uW8iV?J~qKe"B#O #2^",k#D7!E?,HZ\Ef^EJ󜁬erEokН79޴zc&`rԩY:;;;44w^?11aZDww7W^ye޽KCCCV:u 񠻻ȑ#p<344xV+)z?mU757NUV|V-ņd&SW$$Chr`5nɳm8`Xy7@A|9|0l1W2V6l6h6GCUb¬V ϧK?8=> To:leJ^]&@R.ުbO-`/|Nǝ_xw# y2z\`FY~A5b6B&4ooE8bN|rOR;|ҏvFNk,u5aʐjOeR=i{9xZS5גBo Ef6hO޵fOBkR;7]пrewU{k t4|Ÿa5ؘ:xSΞzX.MSo <%`ex+&zi%ʑrg%sVwMr7qb*I DGFxg(iPy^PNjJ)gwFhV#W tA.ɵLV7?m)ѐʗ,2\px  BbT\r>W](T oJ-bvxo+cYؿ$pMڎDtAF1lddB%fh9E|e%!}gH_f5ʱ'#ixa5;%zkxb+;e<6Դ=Y7g˪JؓP7y4.P)ڹum)޴چ]1U>b-oj7\.:B&)D66ܟ' `&u"=6 $,m N@sc4S=9w_Z8 !]< YJPcfRxIaI8iH<o%E9f T_Dhwf$楟=XQ$Qtsra!>܃`"r (A> ެEVT!(,]o22ZUXSЧ. ;#6>>rgT$˅?Rt\.;>>l^vł#8!pw8Z#Iv۸hNK~k̯'lz~/\ā3Y|sLGMCoذFq```nn.H xgyqbۏ=J!Jd``G}IDAT888h)8)InN$FшQ4x"Dʡw~dm85Y%Q}D  022B͂dӺ)B%p;nU @x(ocұ;S󃿊ۜ N}i2&MD?Χń )OP:!נESx+ L1񛹇"+%3չmTs/oBX  D7%&DIAj?UR/:L(OdK$xR=U6عuttJNVGM$"+u-.Z6⢉2xF/mx!EMj7 xrq6oV4w2i6bn\6* Ӊ<6*cO})oA߅XMvwćBoMɛRm9)+Mx%(Qca9hl ̅/ɮڲ"7!B~reϮ 555>Aq/\._"ģ!qO*TmcrtIME %}AtEXtSoftwaregnome-screenshot AIIENDB`gxemul-0.6.1/doc/20110606-dreamcast-roto.png000644 001750 001750 00000275552 13402411501 020340 0ustar00debugdebug000000 000000 PNG  IHDR1k#@gAMA a=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)| IDATxwXI$JIbTPY vγ`ogٰ(JP*=c5 مn3}g%$- ોq _(˞c,P X:' ͛ |6,;1!fNIPfng:z۶͚%z8ܭ[6#~!Ӿ <8>F2CYy%DFD̜1ܲDi'ZʿU?BHWWw$g~W$D},^ѣW\|Ҋ644ܾcGfKLkorq@[ ͝C`Ӧ@0166n jbllfݻC*9tS'\͠6_rr|yՊև|jwKΏ7N霴[6ߋ9c}{\4pS6X\\}εk0uk׮ )++'Y_NNTԉkW9BmFٸػ&/BmsgwSCC<!vApW/}c8FFFkV~L{G۷(>f^4q#G/8x㾓&aܵ+=#*=#c׮^Æ(ir,5ٿt:}N6vڵp[;XXzk&&csQ#7l8/xСօc@ i]z% SFmr%K͘>ŋBϙIӅOp9w%_yu! -_ז-['Mu2xҥ^>߼yn-yB֭{/6w~I˖>bٳw sB=~e葅9I޸qc̙JJJ3gθzIڞ*'׸}= Ya >^^ YK4Hw˶mƌ A|Wd"PZQ]]O>/\ p 4qZړ'O"WVU-Zt+/[xIUUhuii9uqvm!B~]x##R?O޿khXXFf& g{9ir~yQQQd!;<aaagϝ+--}K0LLLSRLֲhhhx!hKDyV©IOEP+l۾DemO[xs~BаpgJBaa\.7#33,<צ KMM-,, ׷/Vh{%&XǍ8pϾ))-8n/NTboo|J|93\.۷B!⦧ w6]A\ZV& Q;aIF_}ǎ';2-kOlgdfJ<,QB&&&,)aB< (K2f…foظ1޽$ĢEZg-;Vy'Lzw~_M~25_[['Oƃ]SȺ>BH~f{7D8|CQ&V>}˺P(LK VZa ZNxz|9.}zzz^Æ|-~}w|B*.֝SNҹs +V\japK11;u`0Oޒ@@v︱EYDLMMyzkBhmǍ300 Y@6ښh2>jjj~Ǐv,ւিuѣS^jj&&&C֑9yE]]]`299989z츟dI'9z/Wkkeeekٿ]pDemO[lk++k++6; ..ܯ۷y;v  oyP,W Ҳ.۷gIX mg u) NNNcihh ]r^Q}elOjggݻ;طw_pwwwп]]cbqrr .((r_߾Y,Fk2oCd ~I2L?__Ǯ;v|yrJÇ+++O5}Q;or㟨tװaGD}ŋhgכI[v)%%%OD\(9f{P=-(X 3<=Ι;d[Ӧ 99 c:|XS۶n155511-zgĈW-_g$˖.}8ePaG֭5۰^Dp+ -s||~n_~5/_~1;(aeW$޿_QQO9ڕSQ'yzhn9}2WϞ} 'QިTСOs[|y sjH7oZtٌ/\.d9yM_j~[m5fLMMMdV*xœ}= Ya >^^<Bq]::vkƮ߸6 _vws~zyFyyymٲu$_ǮxeK?1m;DsR|޾sG{xx,Xx}z Ϝy*ܯ_zzzII I>9t6ls&Ǜ(;s<_z쑒273{YlXIІu}={.yzz{y]p"~oyȐ.͛uk'D|@[ĮI\ʋ722!n8--'7w._nLJJJz!t?~rJηݽа~}~yi_gVPP 妧sCBqqq]vEmټi!Gqqqo 0m7n6gО%&Ξ3/a(+뙘()*&L6^Ղ=aa\.7#33,<ݗcbz89zx\|PUUu-oagΞsppXd y>/_R9M9QZ/4mܹ:ݻwiiM :vG@T.:](((XYY'O^l f^"O~$ү_}#ܽ;uJ BDȲe-]\4Dqlbbbٚb& 'D|@[ 8\5"q3Osf~ 23k\ne|ʊ_fg 4ٳ/_ue+QD߸6mE-<qyyy۶5fL}9 8Rd-,̳<%5L[YYr>ϯBgFW[[KO"?oxC|*ښqN􋱱ѱ#GƎsUVݗ)=vrm۷_4ozLu}",[[ kWsҮ]`ڒDsrsϜeuۑR'$Kmy9={w]*''':.zijj:]B[n?nBRL̢Nݻ3 GǮvnoq/jҝ;wj~|Xi%VVVVlv@\\<^7kWb.\ 5Kt!߸vƗ_u5χ#0L&ɫDEn;ѧ[%ݣӺk{`0M@6ʒ iuA3g֝SNҹsfnp|EY9Qdaf̜%!tq?__??==~&N8r(IÇe0sHhzȺ>WW zkwnl meeicmf|?ڱX 7y>!Y_*Y fmB͛;ښ`d~}+W}An mg u6BիG>s' _`Xh߾} ;_ov*~<(h Bi_Q(KW\%fݸy_ƌoE&ZN{ 6zH_g.\ïv50 s릛 |AW/ PZVv"*zQqc?o^I[j>FR= `;p`Ųeݝ~}LgX4e(/~էoEEŐFFFoBq5BpiS+ڰ^. Z_&._xɓ'>}`iiia>D(''1dq444Z/o㔄3e;}T;;wǾ{j|>!Y_j;I >?U=-([&Mߵd6+}cǿF 2t 7&ȭlmlO63(ێD`NhF=v}ee1GGGiem[ڽG(N/ᛏsx RÐ3jߏ0'ec\iewc]]]Wt/@bldHMbfsr!qe&U\tIW ''!A6 W~hZsr;: #f~R7je~3Voh|Zsr; ?[vOfm۵2Gs<qNk N*]?[?nZYYX'B(SҲj!~N|Тw-`ٞϿΫ|Ut:3/_6F!thtcm9uJ>C7uB!Y-.5s;3]Ք͐hPš:r5o52i퍴^}*'8:՛99O:v㎫K?4TԬ|S /X8"V/p __l\\PX{ƕQONxӠOZſTl!~zMۍ/u= !{^MM֊B_K77u1z\tҙ\r[!$;.Y]: }Wi堮L->a.US{ Px䱋㗌÷T?j{JRk1ҒCݹuM؍Ks IDATtdw~AOЪk<_)Q^RBq d)SOŕ!EyʨުJtBRB ʓ>Pp!B׷ѣGE={Nm3>zxKJJBrrrCƏdDE A=z8͙Al\\xDDvv6y{KFFS6_ O@tϡCnj%SO_xѕ(霴kL8QCC#< !Ryh7fʋ곉U:-߹קO|i3U n"M\'`Ўᨲн;WO!R;g˲2KNga{e M&m| zRTBWx\k!cykcKc-NW5uh6 #m9%:%}}\FB^#Bh`:-Ba^vbd KRczM`2twMr/ -UFl "NdA<1bO#v=k'ĶI{!Կ_S={[:=Oa%%LHS<~lEߖ*kk6M1(L%%}՘J*wx 5Nc(+[ݽ{!2%%%sΡ`'Nk2xҥ%!Θ9 !4su!TuoM_f@ݲm۷o+WN/[{+K@6=xРBͥR)g6Z//-[}vyknoo)FGDM6N8D$ʳ#Q_??ߣǎ yQDI[.\ܳ{ע%Kʗ,Y|-|Jxg%fM/Q{d=ڪ8:vݾcgۉXhϟ7o.p!}ȑ#9s~\=D9tφ xys4x&:Og^ wWCDo!h4J( F0 ÐP Dxu<B(:a{?ok9kB$x]_Fu!"{EDzճ_NztlI\&ezw5?&)- aIw/TW|xIҨho3xV/S^ն:(OU^ЋOI>+3w$ Ha+Wݴ0 68Bm ~ςԁ!ҽG/uO}*C;_;YY:Dbܬi`3vN!Pz30'_໽ٳhG'?&q͟>q!7~}FJt5n|NiK+pjm{uN^/cJmIdDɆlNΠMvWGSSV6V@ !T4cK{ ^|\#G޿jj޳YngϞEFc> 54,,#3ᆅG3BCRSS CCC+z!Hz&&&J))SM˝;MO禧;7g{9|zvܹׯ_/Ze$CNaQ(BP)T*B!x<4Th'/hZ:Bv\h}m>_N" B`K|]Nپ}GJ[>}T|9BFiO/Žq+%ᖭ[>ICr#>BE">H0$1!NƳW>? ͠:6*S|LANAG S+k;=}}mhg>_z("T^um];5[@c~ 2f- =F(4Im QuB&F*?{ez1*ƘUi} ay e!BȡFku~ Ў?vݾ}3rIk00A\݄[b놫gJK/tx`ᆴ*ͧB_B=x G !;ף@ <}IN=EN^+K!t+6 CK=$8>{]ɏg'>/:v-!Y+ge/~%$B©Dע[ӵhh%6'ZA o5e2a邂y4ur;VV{vyVrJJny[&&&,)aaٲ.[/gdfEI/|(*VQ{,\d/c-\hnn]Cqppn޺5s,iY{헯\)dZ@Lt$*'D%k<^JP(T*BQi4JP)uuWǓ@aiSW{4yFy%CX^B,vuM@ b1zLym}ӚzX!t+ӗ$Վ\?o`F(!#myKcޥk4*Ŗ9USU4CE*1ߍu@9SLdʖ3EO2˫u}V7:#չs¤6[,SEL JMT㭃GW8~S*'M B՞}'U}vV2(1koDԧ 5= } hT !ԽMɻw2mfwkt@e>ۜQDI޿27yuLg/I>m4m_qxo~{RRS6STnee2.>c[\deeq%+|' %k1:yN STߪPmmMWSS-thZUe-?h@= g徭Z_mZ5;xƘg+Nbʪeqx`\RNQPj'! +!BRB IZ۾Tw6RDɫwb"Kަ0 UuBNȓLQ^]C05ej`J/rJV+%46}a"!npk^0uڙaeQMCOӀjU&«5 v4y:Iwdk94rZ~ʯ.ߗj[[vijj()3!4E(gQgec7g/FAlM@N;aɭkF#:|&`鈶m !K<$;5yYuH/2P_Q^L;:?)WeQ0 57'Zs MM!t,8}])rhI)MHH(++z)&fт` c455?|xG;kA|цwVV6lv@sq8> rD!r8򠫫 d2srr@6ʊ:SMѣS^jj&&&CֵqIgY%G"$/:G~YK($yno|{;?wiڵ={`0&og mcmmeeں3oܸ<ߺs{)vv]:wIYIt$*'D%kRIkQuH#yq??_pm[dg şݸiS/Zݻ;}K|~544vstl돈/[Jȿ(11Qj{ 0 `}HHAAݸi^~|`ψ.4sf]]ϯ5em'QvYzQ eAΖX"(>Q>e_YI4x}Eo|iqHII/tb==ׯ_ #o7oZZVv"*hgΞ?o/], .]`;pޮmϓ&d :mC%+ aQY餗^%O-*ŒiH9KW|U25tuۙtHPW&nn/ݫԆW| T.teM#Ώ-Dt!D0%,'_/׭SID2j Rt܎od`j rRs*uWdba860|svɒG=L -s|V=Ԕ`Mѵh:Rc: ܂x6i\HOUcBhM͂T74xۏ?*ri LeeY׉zNJ՗WP Z:&$_T"5;h3xɹU !y[2BH]oN;7V(t&?Iid1 jձcGuue+!\&o^0##*j%% j!!B *4b*[ <:]AWCHWWg= s wY^ڡ#0%-LW"ygԉ^]Y T9j J|5/;fZ_W! t%uMS_Yș  Gϼ{ӸR(˚}jBkbҶ0LSbB~vFRS jh5EJJ*ZzJJ*(Z : 9_-O0*E!7U!x4srZ}}! g7}{vWWW% IDAT ?L~~sA$xMnc@^BUu5Uu_Q'1761ſ)(垅:4!]A!c l&}]] ݫ&퉶j2UL$6+)]Aȴ9q*****"dJJR>ԠTQa,3_ Cc'&%u5Mg$ΒeRm\ҲzAS )V|`9"<9Hn\g;I/]xҏuI.q9v=z?qx7oJ礭^fJ``YYٱ'\@R7B׷ѣGE={d}##)lkk}}/^'_bG$~s7o.[DTԃZsjn޼u=w-Z|ɒ7oByxx,XXϛ7B_HRdm۷̝;Q8AeKvS]Sceifsr8Rgdj?Жۮ߸>%}/>^7KJJJz!t?~rJ^r323]]]Ƀ 2xmrrswL>CYY__DIQ19%eʴi-CBACD9},Ju4iŶ;H6+-+_PPP>y_|@^wn6yK2f…foظ1޽aCvN.SR޿z|NNҲ˃I!++KR55ղrQIb/^43x^^޶;ڡ5l؂`|NNST>/*)..PTofEA?zdڵSRRblΝs̙ dm,o*1hAS ѱkGtuuQWWWa0L&tMp8>t:]Tvnf9iR?Z/k9!7i҂4-#==v5|Sڍ7oZZVv"*#"f%'=P(xDpm[dg %w!!\.wMgdq"FL_l)F=xP ;ov٧wh[-b ߡz޸/eO F{P-^k)~0ŅoK~7ܸ:'ɛIsr1W#6eڴ9300 FQ(~}=xTٳrтeur?_-۶3&`?^f թ{Q#Gf_7\hhXjjjaaahhh}!CoݾqZZNn={] f~ SM/|(*ėw6]NCC1Pظ01~Dd/nT*χNC߻~)&fт` cşp8>t:]btNL֝maF |R s򖐘Q [7 @ 0'3(%&NIvFO(2"b Na}dR(Ə߻oOp7~8 nO)sҾiFJ <`ddMXx7|XΛb(+NحsN,9%ȑUUUwu/HNIq4 rꨯ?4;MJJJ dz㰙=)//ÈRPPrm/%K}YhG\1cҥ? =?r` pY_of.T\~ Ŀ:Ҥ`OFHIIٴyszFFNٷom޽[@v=>ʕϲÖ'}{cnYM|>EG!gRZUBs)9:D䰻NC!SEJLcYh%oq1}4Ny=\s}ky]C9!& hbwn,,8~ڞ={m\^./[|2?/tlHe9Iŷ+Wbll\}z^re֞ݾ>LG}%c $rMssϛgnno_?Y{od077ڻb``0xР-6o!ڹ#/xc[ް~\*7li.MIMM߰1]oֲeV_;~y9p_V(?wѣGέXs@Rv Mj ̞5a֬ bU\ v1`-dl\&.:=c欂S~ &Lx+~c@̜}1!c]Z:|<>2=zؐ={ΏY0iDMUUUyJe.>8<.l|Ν f7?fZdǀ4t鐡Cm׵[Z=*=sŻ ?μڮ]O>]vc7kʕVe;s߾],"j2x)>Te;粯-;=vL0R? ڏ;keeە+f&1lԨY3S33O⒒QcRTTTt4!T⒒/BGO믗ܹZP/YX|r}zfҝΝ?/%%STZZz֭^={WI^^^ǎ !q.X@똗GݫWBRbYyyYyybRrWZdA &,Z`RKi˗ !"!.]4iң{{S-dl*:U%c@trBnUÇEN=k欙3"?Z_utJHL:+_p!%5>Us.jo͚5;+>˓K䴈6)vI(Ӡ۷5k֓Oi,,ZUW06ɓܫUDJE<Z[[x?N_1V3c|y"%;wLLL̙iẺ]:w~n6-=sbeeyؼCm-Çݻuۛibd8BH6mjjj>ܵӧ0׮Yj5|xgR_hURR*nyaYYٍ7^ eqwυٳ/esRV@f޽{EOglެl\Gv{{6}XZYMye Y.<*{Mq_Y߻gdYmbdMBT*mٲݻ~).(8 )rV|] !ڷqU粯ҟn%ڵ FƗ+SV^hG>%[ЦMpkڭ+W؈3;[[N~o/||c땕_VLK QQQBIF!ggU v;?{%l߾}u9}mQRZR(}?b^D[o9-)+jڢ6 aTG>M4аqlmGg&&&q6SK$o//FkȈ.;wLgҏ  j߾eAAǁ>?yyBCޗ?lܸܼ<&=/?/8(Cڷ |ӧOo޼9s֬EJVF njj:rpay^^' 'o١CF,;t0>lv.;ϵM|ڡɴYfϞôp \`#ǎ=mG.\~Yyvu044]j%O~uxsu!çN:eJq?'j՘ѣo\\]_b|t~ХKRiYYYBBb8#*8(w^7n\OIA[[XsGWWI =ƦzO?YJ1=Gguuuuѿ+*'$% |Gݾ566NHLal߾J7_r򧉑QΡ};rŵ#& <v`Bȶ{VybwCZv Z,%\UآEʪ$Ź*w?Ӹqڴisҥҵ=|PLW7;k?ȏ(j\p%UU2yҤ35<\`+==IH5c}.<?J/k޸0v׮]KHL:r'۞7n|2?|ɸPggwkr^zǏg߿_EEE瓿rui{ T9!7>nV ',}/[g {J> A.ܷǀIhˠ0'GAAoL,-Cƌ {O#L~x[f{; ؛:N{cxc`:M@7$yX1yy2p1hH KKIA}RR!䯠ѻ*-@o(]azg5b`EDN)w_Y̅RhѼ*)9С~;5^i陒Ғ;w=}=Cn,cFcccDqcݬٵk=<~7reDzC__NzgΜ)))ٹkӧOU/KvX\R"rѣP %GԌ=zDEN>{РΌՁ9Ԩ1c{ \!k׮s]zzzqRѱCS6mus/+Vuqoo S;*˥ѧG1pN:͛;Gq|j'r999# ai-Z̝홅'ׯ[۳gT\"^d~^ؐ5rۗiĤ'WXltuuzʬ=}}} >sKƦ<׿ǀ[l>Kwͳ᱿usF]k\[\*Mssϛ8.UW<W~CڵsG^?&qΝ66̵;4T 7li.MIMM߰1--3k?Hb-ѽ`)&Npv}RvbʄaEOϘ9c<(?wn_3;rkw}ɓ'e+VU;\foW3gD_tyLXg~V":ÇL16$d޽cL4QGEEG{zSUU3s  JJN6KCfzxxyzΛ3-2czx v cG(寿?ymw㱟}] {*///K ɓ#/xr qqK;3)r80׮.̎hTS3-,b~%uu())e9\rhڴq:v(ӣ{ww~3g͢7kֲ+WSlmo޼1}=w3d?X3U8"zʤI'Nbe~r C䆍5kfjffɿU\R2j[N&*8U\R_h)Sҝ;wX[ %˖WV\OLcbRҹ%d::%$&/\41$n !vxv҅п־}1yĤ[n%&&SOa5' WVN4&?Lqq{(fv{(166|2!$rZ!ҥK^wWڒ 1%uܩܹ󪫫cחϛ;'*zFmCf;'$&H߰MvTWԵP.[gh4îV;loӢ|74r4 Vտ/=q$-jk/D"R皙Z[[x?N_1V3f2Ο|ٳ/hן3gEv纺m=:|䈗;vENN6RX"a.sDOX˗/?}*$::O<ˎibd8BH6m#OU?}}kJ%`Yّ]:w644Ϥ?Ծ};=?cKFF^~q|mjJ^6mڴiSWWmۉMi&K;vk?ŔSٳq]:w4iL S];\Ruk]KCCC;;ɓ'+?zQ׎f @N+ ]t  `A*%$$V;amΞMtW_ƍ)9)QQ3 ا.nmm2zMuu~^zb^={ammϤvͣ=WT\OHJ?A裏}kllZEOO{@kf͘a߹ibds`:::ǎvq)SŜ̯NoU_\swsc?XaZ#]آEʪ$UUJn=zZ[Yn N=v=3fvvYP~x[f{޺?'G4ygoVެwk[;T .B@ z M^[;oa7ٮo-hW%\"5} ŏH$trtZ~}ل;[[?+KK==3%%;vz !&&&BYk׮%$%=z̰QNڶ/Z\R~}G4.3,YMEMZJ599 VVcƌ~cǣ"mܾbJ:(0&2j6m%cSaQ/+V=cA͛7_|kZ}AA?B]\#/JIMGxis[h1wΏ;g\nmϞ=t'BdžįY_s߾4]wn,8r/Ɗe;ۧw+Wfc``G^^[26<A-l޴)?7wy,/?\AAIwyL@/OycEFz @qK:ɓ'#GU^.ɕ3.n}G{&P!gСCV{P)W ꝇϞ /SR趐ӭCIIlmo޼1}=1d?3.4]v|IvBC8x})E֦ױcGyݻ9k@ 5jdԘ1>M9Up/S;wK-=+_\ju޽t''ĤsK$eI)4MLL*--uVbbb=QY^.ɕa5' WVN46;Lqq{(fv-/?l?yʥV;Ak۶M0K΍7ճ ?3Ϡ i`YfxoFYDd ڒTM"e_w6N};uq;w^uuu̼BysDEϨ}ziQ}9mEƞ8y{"H)ŝutt^xsN\]/ k+3sY,0ܹcbb"rO JN^|S%yo.;4(֗k~Te_vz׌}ٺz66׮]+,:-!D__}:U]]?y/bxѻw_zEVÇ0{?75/^rꕫWܹ3cF؅[n+--%pͥ˖\$yNܽ{Msbkk,32Lq)"|X,Y J[lw.Ϟ={M4аqׯ_N~/>vTp[2+HLLLm#§*H$^^YeegGFw޾cb|<~xnpPP,;t 8+\y8sPNsU_e^ ?/__:99.oooˊ[22Ɔc Z@$#csԩzlܸqΝ'M-3/;{:4jȲC ٣}\MMݫWӦM6m-s;QBqc xgiHҲEn/]c{7))aa㊋ uuuSY]]BRRG9#Z___PP@{钸 ILνYYϞ͞98!1{\Æxr_/_]!ҥKURe^ N#\}ϝӲeKϔ~;BȂ!!cCB>rQOƏkѼyYYyNY!I§NiӦͥKKJ׮[\pغu*,O8zwtF7OnNsqfŘpBHš7D/[ D@*ſ]"([&M@mU`\khv3M@ahrxIycC׬޿/˹o_-g3 N\񋱱kkCٵ{^2kn__4@䄐ÇL16$d޽cL4Iwww*f<&3f+W|;q޽{ [tСO< 9IZL2c>AAIwyhU,IHJ-[ܻ{~ƍݺٻ}\S2A˗/E&&&q6SGyyy612233[3_Ύҹ}xw7'](d?ܫgO&}׮ݕ+]]]BC>}UF. o.vͣQ<9Yŭc !y' kn`Ml wohr&49Mhr}G!xYYZ镖))-ٱsӧOKxqw>˭[6ݶMD̤Q N3һv:wΏ|jhؾ};BH 5[ZXZq/+Zh9bx 䯑rxIycC׬޿/˹o_Bn޽W\g~mشyӦo?cG }]y^>r$8@^*^D"BHN緲pLm^J}#G<n߱.rzՄɓu =Z0f5DŽewD6m 5cFTt4Z9@i N]|2YYyv_B:o_V^U b<|'4vecyO_y?' e2YYY+~Yv-84}׳##»tlhhho11>?^~^pPP;o/sda99ߢmǖ(9? MY8y!oK**'$%߹kggϚIٖ}޽4Oپc)SNj炘!!cCBz|^Ǐ;w|JJ*8tFÀ7~(b.nݬN;YXshe h`ܽU׿k]>4jh>PPhzQp"#E!ֶv89M@h`Wpws lѢyeUURrC9T_˳}grF1'R.+Y~f?޽lBBDBd擱yA] W/6H-B!DW-_|5AIJ *L>Rl*TLSJ6 RUxȮMCE# JNTY *'M)>A̙ÇϘ>}SFFaQLƇSOO/|qK={Ɵ~Ɵ~z…SZ Ֆ{@ψBtIy)[ౡA)|q-()S ɋD}4*'>uɣ-C\!S2."4CD aIII;vw޵k"JLJ*++;w|Rr#cc˗/B"EB.]dll,چfd顜CNm޴s̼U.+Sƍ'NOqܩܹ󪫫cW4c/ aGH2o}rO!ΔB #TZ!U&R㦯fab(6VP(fz QBRKr]J;.NY+TBڔ*>P͛8Y \?ΎAGGG~]SSbɢq6mhϓ'O2ܾCOO߯uK-'>4|d5/^\zիwܙ1#zSF{dBWe7ָ#MtmD_L_ԅ"BT-f_xV1;L+&Xb aƍݻuSVv_3۷H$ݻw?oڔgr?v]RǞ={V\Rt2WWWƎݗ2ϺL:;IЀ\.Ҍ[2yثg6ǣ3e ቐ,-~[VHTKg(TLIVH!yժTY)J}DH2LH7B zOb"$4!KOƌ=c&VpPУxo_6"88(%%y棂v7l?w΋nEEGߥmc 7Ijkk#Gؾ};-Z} MԔ_@-sxУY4?&Z[㖦TYMM!cJPTg5P{PJ5NEu٧5H~ɮ]+W>}tu|˖.W[)#CS׮  ܱ=ƍGL'-  RYYpf/]pp}}s$ee6֭[߿Taa||cǴ?y566$nWkk+cl%u""vSߔN?-5ؖ.LKyp>ԝor;BctneS: xb.nݬN;YXshe (($LY€-U`,RkFB"Ka{+ir':Xf%*P1kABm6Tx*ë1 D&y\'>&l'Ga@[UGPyyRL]qK-aE&]qK&MGثUR(iչRb芩݁do~; |;.B2.) AD1&>ʁCX+[O} QZNҐuwDx[FTyF!{ IDAT* w2nɪM+;SP`;wR|=h䘸Z*']k CKJȨOɪk-ݱUiRW䚕Ht$D$^VDF6kt?4:eOwA zҴeW4]V˩e9`>Q1S|shroEk|AXfxP%pMsl5ש]JZ>Œ:*(Ne! J[}ر2}r Z>* BA/Eĕb+:2MT߂[QyhID\.ݺes)M4yOKV~'GSlm/[z$G|g``方ukѩm[oJB+v%[6_nݲ);;1).)Jo9OjDHU.UkNȭƹ\U)0cn}'[MS/ר(l Vd7'.eQ\ UՑ|@&o@XZ۸>=ѣ[226mࡃ)Q N3һv:wΏ=zDEN>{РΌՁ' m!|jhؾ};BH 5OrrrG} ȣsک.Ey[[9D]r7R!1{9t4aܼ䔔 04}\"5f ;n=~m˖-6fdرӧwuf?xk=z8i„g3F̝gll>}sUƁ'n\QiE,;th֬٥˗O(ƍ+*177߹kbP_DRh- !~֭_T!W:e}!??wȐw4qewȯǀ $N8dX"R7 \f+?'ra!1x9I5SfDԫR jck =F'o/ /#uj2=zؐ={ΏY0iD&-*:D//Ϙ\Sz%3< n!C>y$pR*;<.l|Ν 2;kee)?sUƁ+nej8sv{Bݻ5]n'11XLILLܶusUwww[lX,!\:2"bMJL2޾}YfV)**"L4I*7cبQffffׯ_/.)):}U %_|9-bK.s-;;w..^lYwޕ/ 3FOO+}@}YҖ=D{Bn:~r E%j1-RCzɎ-&O퉌x-T*yKX:܁5Z.SgH2U+ag(0x eʱ!45Z HD133  277yy'N#H?111|;u*SWW2~R?_JqŇδ> 6¢Uu ccO}tu!GA !x{/]WQq=!)Q"K߯|}ݻsW|쬎O \#Jb-R8r4G :rS`lH֣ؐ'-  RYYp!):W:ڲ.#G 'LϦtѣ@']e WSJIFaEZ-IjuU4~RJF >"uzLx|lŸl Vo~ +U9ZjW+p`e(w aNN#>=v4}F469Yŭc !y' kn`MlЏUП̣$R8;HHUE^D }X ΠVDLBaᭌCxOiloz;M)oTV(uV"fhV#V9 ;WJÀww ?p9!Gu1NS=c* UZ-h:POG"HrulV%cuxk*ߡװb\E,WkBëmU. L뿮-UKȸӕQtT8jD:,Q:f\bDq.o۾G2t$\U9O>#t Pۋ"6)gxM$eE^FQvӕ4qrT׭h ;wRf`~XrHfȑP(%̩RߖYCj@]#o񋼾Wkeݔ(HۥB4V`?C[Ug]]-s֢S۶nquulبQؐS'O 1lH3\S k+]`#ȅB) r?@ID(EqR+(muTaDLiN9ׄBˋܦ 6'yJ4@2nE _U"> @#*rZރ8ppftt׮|AZZ|ke˗j*((P36q`JƅX+e) AYBKx?[ CMz̥OyN !-|eBfȔ׬z}{qq2v+Q]ًQ/ P@ǛǀCٲuy9tlȗ_~y?XSSC裏wǨI$H|-G3i?yy))===w7Ɵ~8o~֭_Ta<;o>!YDMA8p*BHs+VLMIkk+WWggI|Bbd 9l5NgO0۶6ϊ_p OnWq WP&uQ>c\G@ɘRVH[BPѐɽ< Yp…^=oEEG{zSUU38si3Lft鐡CBXe'O3"OFuՖhBNo%{JHJ,+//+/OLJݻ)Sҝ;wX[3NNIIΟHʒShTZZz֭^={2}Ί.\HIM4bll|eBHBȥK !=={Y3gDFMqhKƦS[26 DK-'HJJڱs{]5߾h+_ZdA & ֣YIIeeeΟOJNvrrԬ7AE5ίv(W2-5+Za,'ůx:"n̥wШ2&iQ^M4蚇btlDID&pm^*@33ysٵL|F/7HVOD\q玉 smkk+ FjjjZ5!d8BH6m􄐲7nTU(+/_s}ݳf"4o叶)..Guy/XQ,/r%U-KH:*aN}"+# ΊcMݿsP]_%lŸYq2vmRlԜg_:+N:[!JbݻgdbJYYyv_3ڷ/+/c#§^ gcq~V|V1?C_xN<{%sݾ};A#W^G7v s=`@O5jdبwy=z\ܹGbeϞ= !7nޭZG[<\)={G_%۷;sf=YI) J-MBs8Qs5#v&ɋ8JuHyJ>c̜z}w;zuDyH3^V??sPM'fBַ6 gS>) 󂃂>xH *8HGW'/7g=*zLt{$W־}O>ɯAA>zyP`޽{u1N.Dd):[$#$Bl6&X"TsShבp߉3 Q3&5tn%ima6αO]]]۞~;d0!d[={2*dh?f*&G}{__ccffҕN˹rXQ_wwpMB¬3;ww-8(EUIB-]RUY !'Mj?S#!7`ѮM6.]*.)]nÇ !v.}>}:>>;{?}qV:wҹꑡWϞ#GX[[;s%\SSqSFuuu;KnNsqfŘpBHš7D/[ D@Uj:)K:Ԕj*{84\=2U^FTz+V s)}9TDs[QSn c=PswW^3JsoU|GJČqzfn,ucOlg*d;=u:qUiN3Ø1nV뺫,eEj@_X:xaù:YĖWh&8҃yԸ2?%޼BgG!tY~Li?v|-c'xW6PqQ*m6>A/n *FnbČ<IPiWnӍ͏@8}VJ :٬^Jn@m̯|qpqrۄ IDATtHL\dm[]NwGc_jp%S͙-xjUww?uNKִ`0=8rʲHJM ];Ovz]]ZnE'3{unq>k<0k;S5Xt&[JBZl1b{[7zԨ-r955^zSNm)S֫W/%%ٝFq}uɶk*\me Ѧfm:-!]Z8]SHGn4 99o+֮;3;eaŊN[TqqvtYk֮e.IM-))yEkN:e7 >`¹3̝տ_mmgxڵIMi԰aZ|mٛ7oaHrE |_6mڵm57~qG}\~[NpU#p")J7i!XΙb)opVqG*x#r-;v?"cdO99_}u٭[۩^~1|clϞ=իW6 ۺu q=E9_|ŏ?}gVٕ7̙;bG'<81bƌ3#O8aIZŋoEZm򔩂.tu7<,!^c\Ieڤx4X'r(1Ji~"(V"4W–d924 7ܰ峭5^|7M6PRGc:1v-+1hyԩ3W,_V듏?Zَ;BϿRF u&MH#ƒ8pp/<yǃ}:}}@@h68ѦTdoS؜V͸&֍M*׎Ǹ 1A'p`(~=Ɖvw-2*i:~1^4hPL9r亿%K'&#M4޽.9t)S{⎖ .nӧ+Wl>2,} |"]u7/0Μ9xgϞܵkWF#5"`;uUzv4%jrĉwZw;?\0 r 樣xJo^,a ^M~97IM֭11uԙ0~\O))6lР~Jr򧟮7n޼%55kڤ#)|C^7 ձ?np^TVm߾}t֭J*#5j矎?7,vTd>HM|tx\Fc^{cU,%X xFV\cyc֬1>q tGZw+,55lHl\7`[#K#{[>_c۱_p-3w4TK#tWc9F.Uݴ$&VWi.xNAOxMRVZr*p9r ʒ$h4YRRB1x&٦_p- mqovNSzP |$N(*/lpir+iqKE.{хnMtZ z">K:brAztD/]@ 3-O/7J|,ayy"49%TN羮(K(9pQKImC3k1݁?|ɢA@Z !ƕ2mC%+F[ȕ͌>vpj)D.3tm!Gz4cLߪ#g%m:y0=cXRf4ydQ˥gJD+NIdRtM=T*i "+틲49*M3cYSLR l tOVR[r탰Kd;f/9Cޖ=DluMPq ِI,-"c<2Y.5{q{',!dh*ױ\yIȺnn82-m&fX '49y" UeQ JjP29ve2O19õnNα.*ws*駇3chf3eW\&ŅDv*i=IqJ ؾNmq4Ȃ؉*7T1]!?xvoK"1[=5ër%- .mXfJjEHeNK~B{y]el%BW-{.oWEGrrG'\Xؒz&)RF3K/dx"cy2#ؾ.KjkeRWJW"=\\h, Ğ."Nk3uYvYyfy{ě[t9w'L5$NBOLTN7g:;iaҫɴ)B -c|.6S~-*W|wA񥗂GwRk.Wv_`ՎRJT%SX\^g>իW[6YٰqqB{}- ژAhvkZY=7?`9 ))qqe7K&]kGE*`uMI&K8Zس%Aqu%ӎQeW"b UkfClBWvfr`Mky?:!'.XO>i׶'<~xP9jU T^=wѢ۷7[IM j֭6oޒpWP_{ܹW_WGjjKc.Zj@ PRe~3y%CD|Bmc=ƭf)S9oȺkwK3ƕzuq8zNI:qsGNs|τ /oܴ1h?}M7 Qf|͇ ~MfϙS\\Ldڵk?ҨaZjۜٳ7o"0t;۵xZ͚5ܵ_8zhٓmݶkع;8i͚5u_.4MuA>7ٱs玝;co/Z4b>3b~FEE٪Uo/^No|u['$̞Ġ'~{=OFz+W?a{-x_{Ļ_ݻuܩ /OxݺvYp~Νu:v#Ftԉ2o=酬b~Usi.[{ʼn\n68""¢IO$66Ed'S(!$\I?^ 5Oxyo[{®9~x?^{؜=ڬBw7;;gW~>c,;;%OTZN:۱s?wwQv>n7o˗|z|q6 ?]1~ o`ժUkW.?7fx|FW*'M_>ca^wضN[w7ް]w9+'pnXv줤7.6mZg|׌snV!qԗI(D6`{56`z'0zxMN8*7od6)lvz]&)q*1nP9#[ R)~$ ?R^q&?|71xȱjժ]_s5ǎtx~A_~Q#=bnw/gfn3USN丸u֭Tٳg]q>qFNq!ˣYY6]res;ca =?w2w=oČqb*W%WO_uX%N1m:ybR_ -5•1zŹÚ RJ\YqAweԩScǍ1u#3F$Kwƈ]D̛ۺuµ^{SZ}];5j矎?7,km۴~7o^Jkݺu֬YYcz}|ر-Z<O&Mޘ1uWY3bXzox<͚ݚ%>-)_w]&MIM+>I}?筠{nUTiԔ 4l %%yӦ 64hPQÆ))y 'b{5]ML)Wb\a8YqYJ8'qUB#q趤q٢)Cl)GfߺbDWNu@%vm{ժU{_O?}36oˑ R;xřYR' 3_y|啴G1SvgV!XÇCƏ}|#2F2ڴN12x _yyiӎ=z4hTFge縘[2}fdϟ;~jJ-=xiZq4QQQ`6g~vTtter,kN>ܘьwb>o<+W:}sGW^}Vvm͚7@H@V(ۀmc\sShr5I|,)+uz=ޞosF a<e5’.G} IDATYJDTj8\x6~x36}?A`1EW&K m&K:Ws퍚P9JGGodZξ3EgiYO,әM :g2/xF%[oގ&zqѼV" 'h\8[tLƤ\V(Uۢ/qU\,,u#MrfBQݚ\]n 9F*ep۱n1Zq.(y{<_Ѻ+hrǒںS,z O Xd&nΔ]}mO`7?d6YYh~l ٬RňپȭAdft-MPx(b.KUX ŷH3bO>x˟BWxaBm.zr38[=^rh;S>|.>JgE}9&=VLEdOQjd3Ȳ6شc:hz-hlxC8]cl_si 3,R&MMJӋ'>|1*~e hr+GY gK3N`ql6&JƸ^1u6)xjqJ2m<&9E8rZ=oUیKM6ĕ-*DXLۻ1jImF0K3c$^qJoY̓&9QKxQz3x;[ɠ 49@af8]`!:zZO;cJnzKlqs\sD +U'vD/kR~pH1 C9&e56,,8 9Bpe kQ2cqsK2 OŁ4r!&Ȓ ƕD{ -cf"oq:=cڒ˜1n1.zKqB:6,2^xA錱Mt8XfmL0X^9Pڃ'H/M&K69 6{rbdCNW 6y[DI6 rL::z+][nPy*xFkNq z9\s،vcF/- \)-:&a:.HMi_g6*~Ϗ@p7|=MǸD`_ɶ@hrAL?%F,&u0ۀ]Yg.W5nОO[eҷjSNPÔ1n}H>|J|7hrq9l1vYbU/ےu d?4yʟ;cK]g7~: &|(k1^ٳna hr H&Y?УmDZJݧO;4k!@+-Ufdrǥ=8+/S6 +a>řϭFnA49eY dK(ͬ$Kxۀ gѸdt#Ɵ[?Y*7˙^DQfJW%be+.> -|ahrGY?(+㎲w!xT7f16l3<-̕t q6Ŭ|yub" q׍*}@&P' E+mp$zCƸL%#/|A6S{Hn\83!ٺ3gj4hPx&ߵ,l,u"3Wیqt,OiR뎳Y@Q.v'ڙh2ƕi![zŹea .QKAoe?zy3:RwfәY:?]*u$1_L)h?3Ƙ,:859)V'Ǣ-ݓ<5NxYs*'',\ƒ8*UO)CEqF1lR0DYn<#hh|YNWJ>خuF:(xGBTNX=)eCvW 1 [@T|΄ۀ~r)u){Ѯs\{Ƹ@L1c\IhŐiveKN#m)9g\5{sr{"(p]]:{EtF`[~{\'gl@,q)v'uV<~]s3MuÖ1<-]ʿ̭eaKBǸT?!G{qYH&f)id_'IgڌKYd OF8;Y=xì͚&*"Ry@`3SQ*)RcF3d+N/lhJ}P9S/8_-=i,^)e`#TUq1tE[dI@LZQb"\ͤ1%R}nX6;έn'Gg  c|:zPy}a+O}hrbi4Zf:1c|xN6Q=%U+{ũ]+NwI^쭦 !%4~-}a+ @\e=h'VvY*xNV>$Đ+@Q\i$Ao̶49@EC*0ۀ5~Dq8*.z$Nc׺ `ܦS8c,:>%':`2oSؓȔBrBWD@h=-vۀdoFq#Bsr jRo5ݝ,ujM<ـ{$0s3\|@m&9I* 'ʒ<6`, nt]lsuc/[Jij>t$] ` 2V.jjat0x;~e.w/ND@[1n>zI--"{Id]S8T i,:,1/"+mMw<dYN7E7p krC9P%zyn7kw3c+R*xyBekiq-g,<o3H,lPɫW>A6mZfݛa)'}g0yfӵjJ6pQƄۀ酬"c\'hxYuH"cy6hdEL/& ̼Ǹ|\O4~fX6 2yE*7LڧOcl{k߱cqc.E=K_h:^aάL22L'{);z;?wK*^UXkZgou6:M'7tElR?Ni&AH$5@J9pɟ4h붭c;~ם;x,qؑ#GL6<ϸcǍ_RXTTT]w͜>}ՊIRakwA~yӲޘvvm2tf5k҇ W˗i"J", J\aThne ,]dkX^r,qDNskHq5.]`-!O@۷3ZvJD̘{X\*kۚݺaF?Xȑ#Kr_8:!!5%%g'={ˢX)rjG{nur1yMNT&œV"-b׻ ͡M7׮]{CIS&߷3+۷osضvY]}_zuvskbS&K5cmݺoCJRcf6_|͛WRa>suv_8i}eZfİx55;+K|͛\uM4y$5׭[I?)xdİNpJާr+Cʒ l`Im6`M}0mKb>m٘b&n[ytۍ 1cNK:c4PNO>ar$@0: mɁьÇ?دЧGd49s;  .1bГn{ɓ&-SSoN;=gΠAOj>' r!0*: gƨ\q-@/"zKpxt#:qo?NL61P%e1I m;D8pO0 gG?*~lP:clg?4֨YSLdפxJ&MQ Ex fAT@Q 9gV$K UiOdRQ0zy]*V'lp9Q*^]=NL5v8|q-:&EcR.lqq~;қ4mf=Ƌ8T{\f}u ][i4u\pCBӫrGJ5N7@49e#C%|#lk:E %_6dݖ+5n-OOytt#vb%B`>%.tLPҊ Bt%SņvMP8]ٵE?d)c^RE]v|N"4~\I:3ƋL#UǨ"qyrrR&v]R Ѯ&]]쭮ΐg*\"YBmc%Z1}_/VqtK8`^zs-D>qф9]Z]2.˗W{["K,uY"L/T.Vtkݨڕ֩=5].e/ 1\L.U-{[Hx|*]o4ᣟoPzVBuƸWm,+oceC9x SG[:qԫWoԩ3ezꥤ$(.޾Aw~ERj3ZIdQG0`<mgƐ Zks<~c.}Bx̘1s K{gsG5~OFz+W?aȐKcuڵsNIk;s٣W_kMRmUHW)1c{>UV"P 16Vd;vlDsr c9g߻qիÇ={CJE+S rټq81b_{rS'2_8i,^d'O*_n7o˗5SL۲峹smO>-9c.y'gdΙtTZN:۱s?7^OV^ѣ:v\zu-۷oc۶n;o5=Чϲ]c۷o7Vpg  }$,B&9Z*f3fu n>^ExuqZSE,cjժO8Ξ={ϿRF uƍ- y̙Ç[ZqqĉI]UִiOׯXIɓ'i-..Ν?RΞ=7EO ]tg,SˮIt~t'/ܽ_Ooժy;>,} |"]u p琧v~oaaajJO>~~̘͛Kթ`a}oؠABCM2W-h`a?-]^=ڷ{M+=o_~%şcǎ\C͛??fO>NMI)(,!OWI,_&M͔3,!kY+vv4c<ä)Kg4/y8Jo~=,CLQ:J3Ƶ25G6VTxg6ܹ$JD3#)*mڸ5<#=W,5%D3gϤ$'^8yԔ9sp m^zYn]{}0c(f}u޸jԨ1<=AOVTo7ҫ׬,o` DW\Z}ؾJO8_R}V\Igm}̙;?1,}՚5X%: XkHq<"jesۀ-ֈYyRN]gx+g.N>mYfi21L$tƐ-BX@J 1ƚ6iҾm۴9y̬5k*z )JJ-^zo)wyN6;';r;$&$׮]{ٳs障w]qM<S_{1!7g҇1ƪUPnmz-ٳg//XPZZ*7ot5N{ÇO3g\]o~ VRk.{w{+V4h޼yjrrF @aaYه!>I?3t  ^bwAKc=HѣG^xڵNsM7 D넄F!ok\lhCŏ Jgm5kc؛N՜e{&Tkѱ/TLok6[o4qMds;x;z+Ԩ>1v)hK/G;>NqS[ '/~t> y \$<<-:&tXN:swC`*BPr5uqr-dr&o|mI3&VFXYNJGiSnM8p&"/nWd9{\Vg>@ɣ1)Qjݷt{ P6d:y-}Wet~.O95.6KՅj_s$]DUI"ɴr,r!D?Jl|R3tK! " S*[l>~k1*:cgP7Z [Oҹ&-R=!W+F\N>"At^V &yi=&iS}7J Qbm u"qMbThJȥq$`,DEە40$;Q Yڢp7b9΀}{<1~[qK56hR. 7##w3m]un1h{n#ogaZ@ɯ4hZxys\3ѱ .7~.8 ̛3_ @إB '#Q[y_79p*U<߹q*#EzH4ExMeb;zzUz%njqnM<ȼ#| LFqDBo ^j| TTe ɒxw.I+)5r[mTzth]Z7~IZ8] n{jmł})\^ 1 PjK,پmKi 3MժqN3b'[#wڴn;w._,y'ט #he%?3k +rx]^F㽢.>wếq;['$o Ů]XΌ 9N|eq]`օ ,"D$Qb5 ʕǞd7f'UJ;zJx{I8> ^t* [l1b{[7zԨ-|`܍r_}eܹR;>\ (--j:a݇,x4kؠjFq:u9rԉx_|C~AE>Ï>lӦ5 \Z 9HT *j7J!=V A(lDAh3{*͚uDoK"dWr2ٺN$T? 2/)KO0/oe;t0.ճǺkYKf_}p…ss|O#hj׮ҋ/,{og oժH=/{ 0sW ύm1/Oo~S+)Y[R;>y-/U֭{-{Ycz|e?{~kex.֭UW]G%yuW]uUn]Yh]^={D⺓&MOzcիڵmFW]uU].^vM{u ]e-ݺeUzu7…u |Z+1@yJB%:ʒǚ[^de/-0=g*>Su7p.2-]1N~M{DH N,}꺝4P%1֭[GRSΝ7{Μ]v;qC[7ի5+_~^.|͛L>oP~jJ[ڵĉ<СfūoDAA&o\Əw;m۴T׼W紼w;>n mwAe_unq,ޟ9su~ {'9) .;wy O }~w萘1jԑ#GS?n~/5mO?>,gTOx7\&߻49TxҢ)@---߱c)?ȑ#Ojr} ކ^m2B'1v 7l̹z7믿iڴJ*_=z{Չ[n/T:3F9sf֮wa;. UXXx 3w_Dq`7T~|/]_}0sb~By*F8.菡~c%%'O4^~&aGԩ3W,_V듏?ZVAԿo;H|DF4ۇ2AMBu{XvzBƸ ASÔqΜ)!XMaƸC8ʪ =c'bn7fNN"Y8#?Kiy(}r曊 ? )v(9*~ztљ&=5qՔ.mfOeݮ I}̝lذ15%_lyO?]Rk)c,9өQ?t8 N}y]HqK߾bۥx̛3WM*ŏO5jY LQlgJFhۤc@Wl;7cL?u`%jOn>O$h?PonmDg xctǹ  gg6^lk¡Q8Y$>DVnv@#?0׿EǤhL ovq'| #<~7:-;n&G=&]* +<w9ʉ̳r{ L<(/I:ZRXc@.J8c:}@3C+5cN2J@KzߏV^y<pI"P;>ی;fe=c]fX3o.auo_~,); wi=o=!AH:GqƘ-Ԭ6Ro j k*SJ~"cRΞ1XEǸE|A IDATY#DčJ '4TxC:r&pHGF fo#or\?xrk1R:cŊRM.,) (O97ɳۋʲ}9xWQ"cc<1n>X&8pq& \PU"c#˓`yv6b|(L{۽SJ1֩g zŹuz9zx 9õqEhr"!ŃԎR.@3Ko3{l7C'ϭFvVLo_DݮJQ.YI Wea Q5!1q%۷m}w;]aIu\/yEq|~DLrQA#-[PT)FEł`FCQ(%c0X & (hyw4W>;7<;{ ԚDO$-iڹ7d/$% PP*Leu9xy,}w${{xg#ۅ5x] o KD$6(TKIo'2I=նOS =][IMO:}zzcw:bZ.]@W~oפ%#pޔvQbچbQY+io!Fw(z1v_WUpom00[t[Dug@2PDjZBhs@;W__HRZzׯ[?]'$!cb\]\s+TrvvVWWJH<uDU[ Ц e_GRW6֓&y-__\~=*:Ç=zLVtZysB{E](>[b{a71񓪋jf`ioa@$B x|kdd䏧O=xotDd$Ͽ]Z5i$ݻ]*++SWW_ble&<\MMk7nXa:_MMM黊)v=sZÉdn9 77WJ|#" _UUUYY/)ؙB#E_Ojhh#Gvi5~k[ZZ|׬9vLƏ'MMM/]rҳgOCCW?RW_L?+oG6D[ ȃؠcC!58a:ȦUbo>_LQpiTjE@.N]RVz$I\r?2ú= ߏf-OױUUUǍxZO+`0:ٳgC߿oN^^.[K23NS.;;ۏUUUTmE&S*vx\e?uqW.]ܴaØ1cS/}a>}&?޹+tYcǛ'$x{ Owi;Y%*Dwĺ~z^-t_8rZZ[nn))13Ǎrqy%>?oc\?Q%xp\k=.cX%ƙw 444}|lL\BBQQrϞ==zf}[ h^۹spvrt𛯏ϩjj`K@^hb1%[S}l.d%0Γfv6e+@h7B~yV3lIb[L(jJ/hcD-L6 #W, =ƱB)05|$!dh``eeinf| <<5ͺA[x\䔔Tb=An'Lz{wTdPX[nQ.dȠɩHK˵kʊ={B+XC_]ŮPѣ)͜:qsyT36|>PD:9^jx L;().  ZΫ=FOϐ.7JJJrO 3qEKBoYE5jC%k)Uh'BHVbKaHk$F7ZK7IwMŏpZDҲWlUJӀTu+]bL箑v;I\^@}O ulIVWDIX[7G;u];agg &:&CL9ƩO7 /E`!u`.E_URIG?҅jNtM/u`Kұ1QLB׻!*ouly[};5 T PUUw'O +a1-ӽe+Rg>ZbǯvN4Ql t3fִ4=GZ{e}qJ@ݐ33SҠ*nLӍwŸI%% 썷V=jRHqF*j2Ql"אDW>}QUJ-7.0 &up RS [c ɺ|U%zP*;Cf\ 0_M7uK|Jq2jR$7"#K!JK-49ЕD8o}5cqQFJRdN B8bɌzx\j7@RwJ+L$ 3ootj2{ȢƗnۢ۩sv;hr.QjXƸLCdm#HFMŒ~3(!i<8-Fq8ox{TZexcIcnd~l |(u _j0IIdjO"57nhTZ 7RPrc*9oTrNMغw1 T5%bZHfx;I]]wD6@=mOy?<%zkIZ}'F^ʫ<ظ.`@~j`\R,Kτjha*Id3o;JoS1.q8JoH~8W {暤0 Vq}PRň)& ;[ci㍢j'zm/M3“5Lf)IlH!v+B[n'o5E,~+u xFqv_ v]5ӧ_?vq7;JUGQ>ׯquttvZX}+4TGGu*.>6,l'I!Nw%]h) ǎnGhwԅ&RD!@/UC8[ո1$!䀀%cTO*(hԝ&t;Ҽ[E޷f_|:\@*QFn{-ΛH+K+K ebc<^}}#Ii_&@O 1q%%%Wa2YIq IJ9rw xBc}޺q4#x-__\~=*:Çr;nݲ!6m/{:]δ~G4aj[>eʔnn۷ ڳwBh<Ϗ$'z !4cۥ뙙 W\𸸘uǎJm(++X[͛E쬮x];>DT^3X]Ҵ^B]" $MT`1$y.C=Kf9>~ 4Ǹ_SllDWl[qBAA峝V\5qi[[[_iӦ5XG֭wj ,[/^Zngϝ 嵂XOVYYHisY^|`T IAc,͍oOUG} pZlԚʞᡧyx,I?^}9O#-VQ _qc ɓ9:I?}HWQFڹո% b`Ï8`z?:ZO G# Iӏcx.Bw 53S8+-R1WecKNKsbNЄq@FM>522ӧC,((xIDDSSPƦ&ߵ7߰~ڦ&].##Gl>u,9݃sW(}i_OZb_szy-kWl c'UTtΝS'ͬG˽ݵsqJ)U lYB!Kp0c1f;a= l&%&ˡw $@u):_,YX JҺDSmC떍ӎ-ѱ\KK,8(-chhHNbǵCڶ=!4tPd777F 0 pgNn]v,>АoєWUUUVVKJ*BaG|i?3x.}irHIM=q%=5eB[ԫZ[^]]-8 ?B :I>v@5R_pZZJl-t(VRq'qLQ,|iL$6eқ&+o'Ro)%2Rg#&K!tl&?nzz_ÆշϞ=Oua p^^.G_}W?Xo8jTaw3CKS^;;ۏUUUTmE&S*#Bw^!L151 _rvSSd0ӷS6DWaa!q|)ϥƙuqV}>0xoɷ=޺ukB?B ZZZuv@G U OIO8DKxnv%Bx/r37’Θ۶SbK*-6:Jꉐ&!u様”h e)DF!㲔Xׯ]٫עy\nScSKk -%%0ff1ZZZ<0G6muq/F_ }Gtj7jhh\bۻ'''JUB8fee;9:E?G._,.>:͟?ٳu9¸'44<"G[Yō̔ɓ%>~(BT +\^нI _ zJ:g;"VL8{K9o'c½I}1fQOclX%WzCu[ _|īO{KF1{cvlՀa AXYY577OM}zP׭>)99%%XWyРA< !UmcmikkWTTFDE^!&..v\p~uuu=Fڹ2tJ//-/V{OW3B^q$2xҥFIIHs;={j4pСeeeyq񍍍%EA yGS҈} ,-,/Zؿ?  k8ӆQYY5mX1u%\8xᢥ7sjzӃW*liDCb{4zY4&'OU4i}cӦiE>r}R@K J66F֒acN4jRhv@mH=uݟgO*E: !4rĈŋy,] UɁRU.Vt#YXY"J5ԺJp[u:EA$GV+L\&Rmoi/s3n$gAhrS@@!.X0? kJ1^Cmvc1-,-o5}$=;O6uPMTo'[ao[]lO8- &@ W^;?>q䙟Bt&ؤAisqd zN|=B[Qp-zo)1MmbZ8HڮLJi*gNRkI@*Qitlg,a:s?|矡:&gy!ZuCA!JA@eeS lrޢ"y<֮ 4o+g>d^vc5Ra&o%wkRH 0zyH$mآ&ieieia! ?FH<^}}#Ii_&좿itqQRRruqV#-QQQ 8u˖_ڴa눏XZXx,Yܷo[6nV+/OH<,)S,psDܾo_XLtԞD?5Դfǎ]$ƫ`/a-*/;@~ƌKKB33<==~h{f9: n~3^Ly<Ϗ$'zJU$1^sKJOJy4tw}$9O 'H}ފ=*Y*h_H50epSd ^CȑP5;ݻwŋ _˿ZRIs4y ?$gAaf왽}HȎիVA啿a[_`T >q263slak?gjn xx˗.;wsr e2~͞-D{FFG|BÇ8%yޫWm]. QhbyNu?PoZ H?("^|gW9R:} }zƋf7nJOܓXof;w]Kt$)y+G?pM>522uuuU#"#|>B(2*jY\]]޽{!5>۶ȓsssB˽pLJ'Tmlj]onв+YZllOgN^b p'%'S٧l^[_\*;wK~;+;w&prtz|M4qrE;KH8~Qѿ޽-߫W/+"^6+Ƌگsri1^BE}hLS'/TvzޱkgQQ1B(l_&o_b=@>\KK,8(-chhHNbǵCRTTm{BhСs7|h󫪪Z[D~<77gY,Vk{c߿uߺcO֨oϫu`y\7mܰ^z ].(KdRRS\]] 篧OB!CeE"դǪ![[7}WP]WCCce,k=998_ }}7>_zB;qMb~ =%5ueqĺ;{,FGgi{BR4T{BC#"*++zlG'ˋ)'K<|8PD[zXzꙪ='ϽI/KJ`۝0^TTsjwdTt;pb%05|$!dh``eeinf| <(). '%' 4u8aBUݻ"#Dqݴ+**#"EeĔ4+ݵsGeEe=^^ZZ_Aq8#/\_]]{ 2ŋ99YYٗ\!fZ┋N={su5e8tвxb__zbw-'^+~JoiaxWWQPXD-M.KǙ644|PJ@~Kjkk$%Ӫiڻ\ehh8uJJ|~Qqc{zIS՛Ҹq&ښѡbo3%G_Z-F]Sg՛3ϞT~u| -@vMhr|&@hr@hr:.|溹ikkUTVFFE]?/9鈺zBǴ\TK ?"#/_Dt$T?y?>ܬKv5UUWWFuuڡިC--z'S/NŋM'txQ=7#wrrmdRXXO2s'冉Ĵ4[ 9XYY9do#JOeӧϱ䤜ܽ0`BwB Qw͉sEUϓ&ǛNXo߾nm}mmϏ$'zZ-F]Sga ?SIX[G%}pPPyyl'+WMW_`PiSlmssֻ!쫽}HWQFB6߮߰-PR\D\Ac,͍oOOe740xĄaΜ1?}.5jώk_ ?].^gddxzx}zzzKϟGM<>0(xd;;K& ޖEzUȎ /fsVyyݸf|~@﵀ {{rSjc}0E!4522Buuu+#"#|>B(2*jYD*ݻ]m{HYY,1"{y>40`m)3SOߞeW4}*=_~FED<ׯ,?T@b p'%'^|l''9'UpR}{ȎН;%'!23y!-sUއZpm_8KcU7ov!sy"GUTk8V9iksN9#`BHKK,8(-chhHNbǵCڶ=!4tPblYn\G4UUUUϟٷzfsssw8{6?Z~Ooayz_TTxy-t{}EO׍oϫu67~_oڸ!GB7^L-^Rz7I.իW/wwyHܠc<ߍи~?Bh7=s_t UUUkc@ !TUU5~8" +..&={i>ı0q-G{y̞YFyz,])NLjҔcUUU5U[T>HOz*qڇqtt2'UhR$,lMMMLMMBn abz~hAb˱}y.YF]׍sl;w233Cx~TQSpǢkO y\={Z]mjljimẹ<7::FKK˝xHPV~.sE--Yc)rihh\bۻ'''JOeON>zȢtuy'NbcKAx'NBM<_"D˫>K˖ϟ?ٳW܆%&gCT.GttYZZO֖L:[TC-6_ }G~;wN 7XYY577OM}zP׭>)99%%XvРA< !UgcmikkWTTFDE[tu)sYoڵsGeEe=^^ZZ_*gggm-->g~z؀r&nC yEvNNVV+WZ[[%z31mhhW}J,? ^ s(áC766~G6sEDqu!^1HվndⴻW^;vx;m(4^T *|W#++)EǏoljpF.^P__:t НW[[{$)95-O] o4y^MɕRCMOuMhrMX: ÆMJjK ~ޮ@@{k.@wjЮhT䛝5M[[22*… 9f2hݽ[^~^BBbcSS;TrQ~"$xb'͞`o6l ))s[+^4~nF_"};Qx ڮۡ})=ʜEe%_;8ӧ_?v:::BC-庵C1-Uz|CoͬH[VVVq6aa89MM=؈~|i8JVZKQ/{lOnvfieieia! ?*).>k.OO 1q%%%Wa2=nC\Y]]=***!0Bhʔ) ***B%og>EUn˿B6l`MzY|y]}}BaoogΘ=HrrjjګW|`jOcǤֿD,-,<,۷o[7}_[[+[I׌o"gf644xzz\rċ]H_!1^L볫/EGW\PvKeP4J!ࠠNN+V8q𴭭_`PiSlmsֻC3{{..FKFF$y~d(WPpXccs33 ssc1A[ԏ6߮'͙$? 0~YeeeիBv|b/qK==G%Lccco?uZeeepP`[$rZmiEi ؅E.br/Urugk_n2xu硢T|kdd䏧O=xotDd$Ͽ]Z5i$ݻ]*++SWW'd7UT,",Cv{%'fgKNb`*C&Ku\MMk7nXa:_MolJOeO6.vi73'GǪ7nޤ1sZoeO>pr'u +|uϞ='XW^](^4uƗ*^4qKdkם})=2_CE:&Һq3K;w~%JKX,qmm/ mA :T<169sǍכ6b<4UUUU[p缯{n߱[[[-?l7!4`͛Ϟ9/ubj[j\]]SS-t/(txѴ Fו-x/K/EG+:^]yh;@gUUUǍxZO+`0bٳgC߿onr=kii/}_Rw_ 93IS.;;ۏUUUTmE&S62X"/,,sɒԴ2@^b)SEW'Oy.]6tPh_r02KKiWW*PA'&,%k{hiusndyFGhii¼ ڊϟy/?ԶsRRS/[AϟwYaU444x{{.]bݓKP1ZDܹs4::,--N3.&:6.;w)ŋ"VQYYף-͍f;:uxѴ Fe_xQ }Ki^#9!C++Ks3ᩩo֗ '%' 4u8aBUݻ"#ly\7mm튊ʈH`NNٳgyF ZVV_>H,׮;*+*CAb}=%EA yGS҈uBzڱq4?u2dȋk IDAT/sr/_\p~uuu=엹Db,-,/Zؿ? hvASdė*^Tvy @i]})=%Eċ]%CTi;/v-g㇋z#̩0jՆ)xRM h&WJ49t>Mc4949'i0IIbFN49YXs+vnmO?u1++K[R\D BwqK;CBgѣcE4~{3+KAx>|KpP˗.8{Kqm{|ޯߵ+1]h$KhfgT+P&711]6uǎ5#8?5YYNp8qرrQ(;=بKbs_h7yJBBѣ6C߶Nj@YY9d$5^Ukŋ>z^1wDTq8#,,-,"RB%EyG_~ME0 <7>!!&6!⒝#LW#.쬮x&,G'qq1'cQk-; 0!ikѤ(G}dkk3ѱ)Z2r3Gx/)?1>%]"X|y]}}Baoo>kBK۷֭mh/Jbjc`B>8(|ӊ&N $d(#F78?.T kllnffannl<&(x }O<>0(xd;;a`\dqKf{;dxoo؀) !^ıiA־._Kn|\ROQFuxQAbjo`绺FFFxt]]݃| OGDFۥQQ&MK]]޽{!5>2uuu/$L8x3+QEr//OX[Xb[Hv;֯[Dff""#o#t'1WIqQ^nNb||ްqKf٧l_W_'g0.V{[ӧOcc9i_#8fVWWqrBR4TwBHKKMɫܹ+qPZzАb kkk|9!m{BhС2D1Jko{uu눦\|>_R"5}G9#98.-UН4^#8w664_ٮxmñ' ttx 0 pgNn]ڞOy\P ]G?nzz_ÆϞ=O@}w,YKK ~'$ oeդ)Ǫj"wV-a;QAAA] ^2FFKDk!^{8Ll%le*](^PA'&,%k{hiusKII%7xPKCCce,k=99ĸ U_z644(\KJ`/FŖxx_xBiv_zB;qT(XGrBVVffSS߬uOJNNII}BhРA< !UgcmikkWTTFDE^!&/5GQڍ31mhhW5I,׮;*+*CAb}=t>䤮~("bƍo ehh8uJJ|~Qqc߾} xa~%fpF.^P__:t\oe2~<6dȐ/^ddee_r ŋ> |;9/F\8xᢥ7sj"}g t3=kF3!hrڮɕRCMOuMhrnt൅$y#GpA,o՗/[:аo߾GDD^vm?ۿHz~yeϋt&WWW?ݻCy׮oԉ3~@_v̙ݣ G !lҬ 6А_hгgv PSS RRRfaa?ɱGD^%E;B̼dqi)?[#Ҹ4yZOp[0o߾eS'sn&Ǚ@\Ώ BhѨ;wI<}9G\J'}͂wU[[rKHRqKgϞw׮xSǎ^^z!#&u70==y/]'wg3J!MM""ѡ뙙W]ZllwyQEEL(Eݻ:1c理l߱~Ǐw E(fO퍣ɅeevF !٤o3fL=F8pɓۇ ٱs_|95{_Ff ٧bg->ޕf9:-rO^#cc&M'jj={|}&ӧO>VV>>'N[hgTBs]\W  PSSZBGE!jjj.]<++ !4mԝ;B>|t(21qq<ۏNVU=ݽdxѳQKz())[M2?ss\SSnF>*:u2dȋ/sr]rna ɁZZ-F]Sga U݌gO*E:*A@@hr@hrJMPA6wD1kkVEeedTԅ ]89Qhhhxz,144_| Ub6=lو#*++RRR;gzzbνzJ3i{:::BC-|wMjzϯ;X(-Mz|:>}?ܣG[Zo6u*Mz{{++xk۰s&M ""TUU._oSe 0j/tOM>eʔܾTr}aS9>Ϟ9mkcC]'$GMtLL#..4נJOS'nd۫.J?%Em|xn˗444ܾl f̘kWhVvϯgfرs92OWhG=,?x -g ssP=fL~,9hRҴS:}Z_CsΜQ%fΘ~>-d>H()+mG~C8QX39kW]]N_E|&<L %IX~}r~I}aƑ?S~iCiAQEbO}QSX,"?Çb|)ϥƙuqVQ ]K"/ O]ȸhiiaei3H3l^aa|믿x.-57dnn&zE,=U!ô=5yJjeF :bޝ5u? XxA패EK[Q6(v! A**BHeQD[`[)kEXnP:Rmd0;o=='{7m$$ S&O9s0꜔ԣ<WW^yeW))4ck//>u;wn?xfw=g[Zq?***r/hzkĉKw/f @/((QZZXXXX~W(455|~;ܸx1!@\+`|}!axs+$%uttBtu---LMbⲳsӬjs4>Axkopwp8---џ~v vy#Yu|s]:3f"f7$WS udog;+ !'23+Kv֙LB}zͣD\&lmm=z,-;'xKLLm~۶owͼHReP~n/!rTp4U`wK_C'y1)SDEG_Rr|]xWU@MY3>|mae ,+wH)NJNNJN~~}}$Pjr0| !'L\ |+W˒S::;iNӛRQBBnnm6g GBEEeyEӪ{/gyl6Zr$)93+ѣGC|($55hseQjjj##s9ϝ;APYҷ מ_\\n]rjaH]gyΠֳ?a„n[|>_0 kr;;vvvJjk틱^fu|}sϝzB34Xg|E˜}X,Ym$6&LW\RQ$jٮм=׮5bq{RαF"[TX#@l3ff%%iǎ;b^zjUFæ9S4ʜ5kVȬYde[xgSy.m ;wݸq~;xp ͸^{bjjUUOߊ9gӌ!=M?VAAWHP*t@ JHذqyYf!\tۂ 嵅w;Rsr--cK \ /`ooӟOrr /Opt\`|q?5ވHe%c%iǔ?&D"ѩm9,ի?BHCC4lo{G8lFssXf#ex.nmee=C1!%%e^~bxAQ|DR#ċLܼ aanw炂sB"xnB܂(*.ܼˋ` B{x$Gq? !voV;_kj۹ÝO~9s^S]-޳7J33glάY Fww7<en?~\2T2~灲2!DGGuu?1zjWCmm`ize2{ TWrBYY[vXS!Z>~ #48f/.&!(&f?5b !7o\pas]<ݑf y|}n47{xn͵sX`0%Kk9!1C559yl5''n}}˻NH44ޢ45k$5r.XX[ZoS߼\~jٲqeSu̓'OrΝ;Tں:3ӥffxkٛ7mҚ0aM333 !I))nBɓgΜ;<:'%+W^YyurJ ˋO:Ν<~>~dgΟ7oĉszxMOK+(,XA;JAaP =j\K ܼO;<=dٸaCsЯƍŋ !\y?K00t***<\=uu#II=]]KK 3SӮظ4k++,O}>9Egu<9NKKKOd2.\hkccdE񅅗zBٞoIȸ}PIQI"`%%%{;wYI9ŗYY%+bkg,ؔɓr/15c0~}rYoL-/\***ERNvA۬߶/o\y(w:u} !E[oߤS"E̽[Ҟ81t r|]xW{?2eJTt+=^UIDATxMDR?UB|ͷOǭ w{xwwwRrrRr2R=a59jr53>f7ɛVL7&bcbYZN4% H(B&NWԗ%'ttvҜfme%UU7K<*.fs^^|\-Pmn,*:ZMMM Ӝcdd}.gs? 24\ +{U4iÂxEűp%n%R_6[M۷orjfy[xq)BRBv߾C }fXZXZ?|︃99IɉB%&2LKIeyckO;+݄MKy_KrF`hʫӇp9qe5{2^F=MVYUcVBȸqllW99M2E$ˋ}C =!M(fs0qupH3JHHHNI&!$//o544<=ן;`>{bjjUUO]QY9gl1䵧/ 0$46)((l~4,? @64QV^;b0`~axN,%5) c%W;q쁢͛yUڹGZ`.sLJӧ_**{NkkB SUG^{~꠮{5`I& {## !~~^^[n---x ͜93488tFMu&L@:l<ˋj+Wyʞc&762/쬑H>cllLy梅 x.鎴4ckOӏ[ԁFee ןι~\ɳg99qFṁ7a9UUyԔlG)m6GR[V fsˇݷǁ~^``hUTT\y>R.w[1u*}^+yTQQ)*,J6v ~ ͺ,? up6B .޾INSEF{=7qbh鰑Ar|]xW @MCəH `9X#zxv'@MbM3E'oZ1 !'L\ |+W˒S::;iNӛRQBBnnyj9i///=]]gmmS+ZZ\beeeyyy鯺n>x`b ð/D(L>=*:ZSkgwQ`RJJNNAA%%eK"D^{~/_#9N@'}s渺{cqb /,jXfjrbggonB$$Jjr6[!8NJNN<|r(1d\\hjiyiygPxii9="ĕ)|gU8=~ӪUd_^mʫ7oziӦUVUع2n8UNNLD#H" qvvfX )ϩBȽ[R$`cB6xzjhh?^CCs !aas[kjjUUOw+*+̞M349۾v.4\P^^<᰷zy]*L_;6Y[[/_!JB}hX@@IY..<ϩ[5ވHe%c%iǔ?&D"ѩ&ٯY,իW !~E34ċD555uuSӥVV[6o!h9GquY唤S&cgϗNN7otyyŶ7ܽ{#6 .jQ!Ycy?@Qq^^ϩ; !voV;_kj۹ÝO~9s^S]-޳7NVYyix\Voo33S[KK˰gDQVV]]!T|ҤInBZ_ /o̙3|>3k,M:Pǵuu#3cܭ# c&762ZR#|/p!B͛7-\kt9j1?tullC^{~44޺|QYY)j սྒྷ_SR>|XQQK[É|gs_$/oOu?3:Mūd󨥩)k//>~",nlm[<=ޒH$kj%KjjYX/_1~m:u;~zN/槟8oaۨfxs8O?;øqlVq,`|;#[`{ WEE@* yƸ3苚`pN>.+&!c"bEP3RD Ga59jr5y<itjrR$L0s17x7\/+/KNN9J竪NoJE yT\ 8jڱ,(H[Ku2WPT,//8UWW꺸8hk+((TTTW8ՅU5: c" Ԣ-EEG |s,wtk֬$cdEƋm07\1mڴʪ;wBƍgcci)"hȋ j9;;XԾmz1(? up68!'c SCCcϝ?Oqp kll|jdZUrUTVΙ=f yi  s}mYE}5){ץK4e bVAAWHP*hgk`osG}DD O~ d;~~`{#"ӎSVR$*D22ښQXWB! ,f yijjjjD K{hHp`_~w~6?quY唤S&c'M~(ڲy˞b[}|޽{MMMƋDuubq(ᐬ{Fsf/~t1g nMkj󂅋V;<BO~9s^Cٳ7NVYyixQ5#lk䇢EBj̙3j7a*a汶N^^|d;~XɍbbKjk;;;k$Bn޼h¾4^y#cc#uQYYIo\/WShVTT|ejjJBȌɳg99qV~>7=<7p9,g0TJ6Z#ɓ'}`Y?0)Bfgo޴HRҵ&^[533&0Iֹmz4,$;j 1䵧G(tvt>~"󳲲`=ޒH$kj%4 w0g%&/oԩSܹ/ v&9y;&o0t***<\=uu#II=]]KK 3SӮظ?nme%UUU 'UEko\" sw=㾗>5OK[KT'OttvO mTbu<9NKKKV\u0>?_|ZK.󫢢RTX Jmlq:0tpN>.+&!c"bEP3RD G`]R59M0\#c$e[9A#O^X];wd}u%ǎ.11!D}qYSޑ{2aY,c afQ\!$|Gt| uB.ccc [MiwbzBȽ{? 8qbXhhXx/'0%&&11g2r$ȈE==cnfF/~ꋓkMQ^Ͻx1ߗ3ݻwxF%K(!aM{gJY }GfVVXn/-C=3NOMСtIME # ctEXtSoftwaregnome-screenshot YIENDB`gxemul-0.6.1/doc/ultrix4.5-20040706_small.png000644 001750 001750 00000012606 13402411501 020352 0ustar00debugdebug000000 000000 PNG  IHDRtc}6gAMA aCPLTEDBDt^TĤDBL^lttvtrt&$"\JD$"̌rdĢl^l^L42442ܴTJ<|fT~l| 4*$̪|$*dbd~lt|~|42dfdVL<:,&$4:̲\ZL>4\n|TRLBdRD$\^Lbt$&ĄvllntDFDtbTĤtvt\NDvdĦlb46TVTLNL  <>zן-as|ΕC9>rWI4x Migԙp4&2бҪIs ԯR ՜yXC:jI=uWmyBDVgK,#Ǒ^VRv!Tz B-"-Q~WQc9*$J(b[tI; YuPi& |9Ia).z^p(^"0 `+<#NGO'zXV1KcZ@(?Tdb#H%hPdA]$~Γא3QaئSڮ) C:. %n5V9dh"X281MhN)'+2 Ⱥ`(,Ҕf3L3Y=tI6uFp{^D*4ꅴRf2PM0 㐁KBsكoIZ"=uam8I]p^}@Y5 @KViCHF>\18p#O5n7[A*SɼrГJ!7iʤ7NKд2ki=qpb 1H/[Pqa%n8ܩpC,41Ik.^0HZm׮ cB(^ZU:֪ՒvD5d8%jiV$C:2cTfm, [QJO~)^cd/!H@!RRIBp)G8Navt֪`m ɦ,9+LQ?P C*`ZRG#Qk5Ȕ8jUjq\ KA7ծBOEjشtd8 *E2HEPԡL=oiK42Ɔ5cv2NlmZ*kx8@D}Z쇭V!KZC^%=ѽ$t h(jԹSθ k"`"WS.pU楩,5},͠ܤWj*}HO#Q$>gGolY{0(t?TXn$ZZ05H7}ˈzVgo(L++eq]?2X6!198q`2AN\NM M^/L>I|F0H;li iohdډ WA >{[F,TНͰg 8իǠ.7a7:xΈkQ@c-.?LGy w~ O! kYSΥ6\nxIjPl@%:(Sv+\L@ Ҟy0Ezh^RgrOBn^`a7*4eA餚GJq)QUmnCt] 'T錏OsL< HкjHW0kbn'22TBՁ rNChndLQ ^ͩj.JK`Q_9ރ1V9(NIM&LO29&*&EGW- ;325TXfEC͊&yoD Hi;"5IHn>ɪT_\i0PF^5Mf+huy2O}yl Ru[Ԣ)X?{N~v{Q{]nr5pڵZvRҺ{N?בgg /.tdgKլ A N{N94,}p>^O>D%vqtME:B%bJM8}o?+~ds gK5P]@;%v#%fϷDx!o2 35߆y X瀠 91Ғ+mfnϴ]Yd𛎻#A|!5D_:P y0) Bz;!.@x)EoRDvyK6ueu!^6odߪBoyapocM䡃CM<w˕*bb]EHyIƴhVdzhs+onty ‘~ ۯcD$iFv'5CM0+ l,sp8Fq#Q~ꍼ.{pB"iNPF (RQIX$كԣu6-R_J7+ܟ﵊I"(A TWUF\ wqӯ`D GU$t0RZXH"EV3 "@߸eOzI v m+F(ݚzx5US7X _5H7"5(>gQji]_Vݎ(7>52-t(Y q'm \XtLOffA{BQ]<=!0)ZI=$z D)J H%8/`PWK|ZYFnT$(L j7y$P%HŦ2f( ]0H|: S5,@4 c#/.3l)N39dU&:l'?q# }n ҁwh=9a+BO6-a<_/KKq̮3ah7bBWڔoF;.% k[;;JÑMtbnN̦ˈ>,nU  :WN R@G\׃h<)16/J aBI`RftWZG*A](I[R68/iqeV^˅Xv-V 2dM [gFaQ Jͅ- =J$# NpcࠝL{/K#VqnaQ8Db*5f{ho6i]zmڞ'F)HKGKԻ1>O(8p'FDTRuZfWTU}p:Hi! Ć芈aTy˴!\ IDATxyfWU໾RC*IB0$L"3Ҷ m;v6סNݷ[/}Vm#m***" d IHHHR+Ur*gsyyg8MYuozœWOxś>zL6mrL6ICI2+"'a9M=UVVVRc}Eț^ ""'dPX/gsx<Z/ ʊ8UNȆ_񦏬X*e!9{Ƚ>u{~Mz#G=ODDgKNōriI/Lz`"dѓ{ W&7oəTtƃϖ+r[ι\z]};ΗmO#W F±m&}w\x\s\u<C.ϹHv{rNOࡍr֯{ΐw=hXLMz\p'r=˖e<;z9ٺlٴe{TN7}a^?"?#6\q-~cyſ(OOşZ0o=_DD6o);}l;k˿/߱F'9GU;7*snaqţףSK's%yuCۿ$%UWLE"YDG=[??!Knxӟ7!߿iUv|rág۞M+>W<7-{?=ܟ.+Ko-;J* dN9{vyF>wʑc'Kϗ~cEN?L^?"_Gw?yAYY= u#rCt`yw;rH6n*}~vw3>\z9ql:m<29zhw8~L6m.g^xl޶s{tmu5/{_MU_W_ -G7l[|y?!E.YY=qLmrډx?ry')~-%v?\y[+""Ozr]~ED}WEvlشYV6nۯwM[-_+Ix^9ٴuk#?=ϒ/߸Ogȫ_tG푃w޴FG_ }\vn<]}k~呗+?ϖnwVWE"lظI<,""/WcY*}rrm5۷O֟uw=6yc/?eׅM[deٲ,D_`_e{57;~͍䲽{߼yL'|#}~N9rY;_S^ws![wI hYD}㦿yiE>sNwArX袟[/AH?ꪬɆOFi`BN?"g&""sP>c)@Osa#/9*r'w~w\=tD/>%? /~c?\o{%'O?[zѣß\rYr쾃,W>TO<+習W}Sȷ=mO~=v\[nY?6W+"r7/?\{oı#{y> g?hKBz|3Ǽ8~L9&f׾\DD^wȿ!9*'NXpwgO'^?iw>zX6mvʘ _+)#/9WwTN#/9W*uKCrx{=C>m#Grr;_VVdUq5,~x@ٽU䩏y;QvE~軞,o[7OǎuvoxB<òm2Ǽu#'~EDء]eEV䬋ZQm7ɖoܳvʵ77Agu9iA0KvwϮ_~[UY?;s֎xyч>/[EV6?z?;e{m)~ "rCϗ=/ݴe|%~ܥ?Yy }gۯZ^C,xߧ/]''>~FٺcVS5)=yx9p証꿓GC~S5C&]aشtgi[&E^!6y.={ٗ+_Ny㏽@.9<|;FD C,!9!_x]rgE`w/m;dya􋮒?? y/ӣe9paWo/|6ٸe,w\{Dv߿RzݯkeǥO-g[ rOȁM[$Ϲs_"u7]e 9r}'WNʆͲqټ}yr Cw".!; :Oκ 9y΁}7Zy e"ߏ9p}ӗ}d㖭㜽r _X'tU0}ZwPN;"zB6l:M#;SeC$7;_ c"qA9rټmHΣiwٽrw0w?t?7qD^'*#rm'Z 20W>`b^Xz~?J%0 ah 3@C` f04!0 ah 3@C` f:{uuuTeS1βQ7wr#ܚqׄ1ײe[RT㿲rʘiK~TL?@,a^$ӛ%X7lt=~j[baotk_N(陓%` 2"kKIu r?p[=ɯ!ےtC,M9hۙf9W-;Km RG˽= LNRqX's6>CU/OU- @IFY;{7ճvO}>&bµFG_,^tL95̾խ>| yYM-;YEo(cRa&C 9L:ҐqLM3BP2a2 5RWi[ ї'$g }|mp sr)^k[B[|luG6 əJQem09vN 5b1}ZS[&EK3Dw}ch }h{()ŢӚ25"Xю`g,rhm2v!?ԦosߪOmS YqhۥXhRS j Pcҗc5h#SC5>h䍩&j+sl}8ksxh WZ C,hz5euIB;Ѥ23>3lKeb2, R- ɰ zcsGyG>֖ @8sca/% PԪTEݾUK~YmNYXzsdӼsN2݊UahYvXݢ$mZ,Sjkͯ_m ')WjWD=7d,a2u^*N]5ëcl1\t~$Zrw}%/?;GV:'f%c1_(ξpK[~X˹%son Typʟ3KcL]m(Cr}դO?nQ(R鬉Cnƚ1a!qLiͯ|7Cw(Kwv#$v%%,ae5bBȿaq2sRT%)jHIR̯/ݿ5n|k_kyX ɷԻs60ȩ *Tʜ)tSj a=1s(UC|@s_=,/6tZ\YIoSmS5F "t)剕E= Qݰ/n)-=f  }q)ߐ>ѳ(r+O*\]WǾPB5)JO|kD?_GZ0 ;/+>w1}Js|mYeXiJF&=KkZI}YU~Y(>ۍ"G!e>,J`Peҗ392s* P ~q̏u=9 +˙O-&껇 ~2$ܡXm>|ԺdNshc2e{Qm=CǢ)Yc27vDxhC8|K8t\BFXf*t:h-?PZ ֠X>5ѡ챿8])V;B[M4z5}6sIw(K[nEze7$ c\}J #Wmr>4RJK7P Edza)=Zh9HKZp\߭2̱ f[b=TtJ^W7oHFJ4^ w_Pٙ!^P9,eb%%4tKv+n |8 #K)5<<=&?4lf.i|Txc75;RS*=K[P4 m3G%wCc1aVTJa\9 '+=CXˉU'}V#+䗨9[S*_RzI34`u3[]5X7]zl!,_[w Xג^9i9H?)ڼW]/jiupKY~C~m&_u*KwF&D*1A c by9fXD^ٚ>V?fdKjˁ CΟEExq 04!0 ah 3@C` f04!0 ah s&5/ɮ\X]XI(׼w_3w̿ 7^\}Y/$!jUJN~ G[S%Fo(}zYHp~E clb'T G_o\Be6֑3_2}񴖇>qLICcWKEl Ow^V6Z[,WVK~2JOIka^YYY/66pc\FUoɆ8TB-rCCɗ9ᖒhU&Fº9!Ԑ\_kTwm#J?scc+zJX~ Ys0E904,jڨ sXR>П IDAT:B„N1Okbv%t,G%b>rȩlz9nFƜ[hk߮cιllFe ˁ0b_9ZĒz6گ1g~<(3]ڎ6º@TuT!ߜ_-f(;5bv{91}j!i=_;hB:@ɉ߂5mΡOʕ^kd:ҳvJn9rη%Nj:ϦӆJ; fɹXߖQi%_Ȕ6!& ^5'JVV1s̩TJ l 3:LM',+VCj έbwϢu之V[(C͗!vԾ{ֺύc[[Z}|zh=ɗX:Xצsl(,N)}4 WoKBߒn1ZVj?~K3ߎ(@3s̡ hϭ,9WLRʉkWUN(VxŌNJ7d-G-X"Xea7cg=,$ԋ]pK ?wJūvVʿE3ϕ=4͡_ .s5NPpBšݿX%rkoM4F1 }G3kM繍r Q]57Gfih7^̑Q{̡uݭCmSB_>'S+'&3'HNtіR >CH? W+?V!ߗh*eRgֿqι/Um4Nk5JC[JN2X*}r疇ZjX^oM57c̽?L,R`0B7ȋ><\<\1| ܯ)bYc5xV>s= Qc[PHMz .́s-n}GkX3>Q\޲{Ȇ7` - ͹hNo"Ja d0E4C斵Vtl5Nuc6~Ccs%JEs!7AC<58!0 a^R^:ծ}""2YrJH=>wk/aP\FKc,(%?OHPkJ!Xj*350^wӺ[o=m/c>34 PuCپ`lk?m!>VbsC R %5aIs__0%F4K|ӵ~>/*?up =j;_5h=*%c֭|XK֪vZ Y-<\Z]J`Ҩ fN_{vlp]bd u٪Rya;n O"fpC+5 A_mw_ǂV~(c2-`2(0404NXKCyaPhەݕ=D=8fc}2x \(L{|h]h+vP]1ae>f﷦aɇRry?J0.p݇"0eX ki\1؈i`CK|gΔzsАlo׭$pE\-.ea!)9#q[R~Ln*QYcCrCP*Z-- u_s9 {uuuݿpnxߐx4M=V#v{3TjΜkjUET=|ZC7whpaDi ^|loJ/9ߡֆ 5m$1k04!F5̥Wns#,E z)|1c/q'@ ;KĿm&5td=vu3}aWp`yc2kN1m''j_Bzs`aa..atiP|@e[bHsJ,6jEr E<  1.^V"uB" W'M9\r.(.,n \Vs23|]JGr4!0 ǜâQ:>CYOLNR6[, MrKg|5V\='d 9Og'+Uɑ_3`yfC2WNM('OvӠX4F:>0Uz>Jȱ(El͑-1QvgWt\B0jS*}rr!Bu;hmͺftH*D,\~_wf'YzhTyc/˩8[^fьbǺۥBO~P[1Rkt=ɜi*MѴ~HH}`Iɩk%ǘ޳~ZP._DǮ-/wm궄1$ ϐphGS,^1CaX[{xS`-aɷAUZbs#4Sn-U:&ZrFe?.r_hhS>+!nuXjk|0YF| &Q.ܜX^iIC(CugeB3>cI ;G'$?1\jNk%͑oϝ!M士Ox{IJȷꟓ%UN׳f0? e[ FxΣʉ;%'E~*ܹprrO5S9吜i*#9e*+7}#GK#9 &˼ ` 3`14,.H\jXabSCL_cvIsfp-cUBlߊPZp/:NbXyLN_-Z_]&B𹫓-U(J_)RU ~j OUclrLo,wTE蝐%JR*}ϴstss~aK,tƤ/S[2#T;,/CŕS,ޅwh2GXNRR w)qЖs+k8\bQBn ?"?FhtqWƮܵhӦ&%kOX9+ꗝE_4qEibPJ-5j*j M4ˁAx?/YP1bK, hoVe̘{NC͔ڠM.sSE*F-5~E` q73&/#FLI 3{'eJ-!9!EAS4r}n>}BXʭ&ƿ&Nr5NZ\][B-kk)ԯ<_~SԮ_c1ԑ^tZi Cڨ 3o~g~AM!T92罹R:>>0Y^bQ) dbK,Zc oϿ6wߚFPR\=}"wȿ˞羜a>=C='_a?I\'_cbscfWT+w)f :fq9%|=S^`A}/FSJ Oy9&.Q"]nTX.c).r+K,J^n;8!0 ah"PJ0K,_P.(E3XXC[t{xV},4s=}ȱ`K,r40<K,ƠT|!>M]b+{%W{\"'GRr|z\ࣙK,Җpc__-Mɉqe) `bs)Jf=c*Bz]9L{ &N1 ̃jESrM)sNj mg1Y[,ݧ(s2ˡԑ3e%N` obν ).{H)9ZczZ-%a2cP}Cnv}.j_S Zd[/ӪSݾ =gJZk[,.biS[Q_`:zܣ!hdJ ҡdCh229c.\a֦-r}P/JbAЬ9%%Ҩ54ó-|Z͸r|Cs1Sk!EJLZ)9J[2ZvpMU94gOqupew:d`1=]BCXeMg{/8Kǚn|waR!%5 |p,. e[rN{32]n^N!1\T"6dگ;zWv:Mɩ1(+{w! J I7/׏FC)(^7lmo964 źFܓr)u*D˗RakY!3$P9yXsRslTRc[c.2UX2 9Yi֕S+Wc2] \js(cCJV c ɷ&w ͜_l~B=ɷ~@>S,ȷz0Pv-`k;m\s *'7\.-Zk `~ 24e U s+Qc`>1̱ERA;pvn}ʳ>S|CZˆgu唌/g#@ s/'zaLOe\2caP蔾e3gCБeKSr_`.[UR~u'XNge[.迣=9o̿uP.%p$'@C1ֳ[@cha.}MI@)]b;-0\zT".u{znY]*7^R[{sfSrRgwfRB5/u(qE_O]0BphsKe4mK^n1\>F<C嗠/?v8^,7kz̚B5.u(uO|7$K/ vs"m\S5`HN04! vs+GJ.%V=+CrRY,_N^V1%9Ţg)S[0u:ԌQwU h˖XK8zjȟ}%wwB)B6곲5TC*ON݇./7R!Ǘ)ch2[Cu$! VPCi' ~[5 R唐 >c2$sNG;06Vzˌ!;[V%?(j7%|K?/Z3PcB:X]Z wkeXANVVVN+՘!eFwZXIEMtvc w,Ԁ2 P\ڹ>)X|s9&?&'gN15bMkT=!X e+n%%GY*cl+W!a~[>SXt92,k,p$'@C`+BO1`%SkS?glsi=,j 05{̖m')9SPJ3ڲKʊ1t]Ƈʟs=( ìR2sXedR`Ǣv\KVXzb%V|w{,1V=ca׷/9^R+w|ې}1!XO,PJ%=Ce3,;.@GVNrSsow(0'u&7eh9|.|,s}٪/ܐ9.S%"RZ&75wksi=ZdPvhjTXcV(^xfS2-.[d]Z"܎QC k~́r"e/VRFw籨z /Jb. ּbK{lOMr22of7g,˖𵿾 veouG%F^_)k k)+C j|DrZXq)e<HzFTC.(1-9RC8>h,CSҘîuR`6Z)[US%I}Q#w|zE yᜏ\jV1_5n,>!k ISa-X>b2hg2VRg,\#Ah̙)4K૏%{ƵI CmiZ\}U/ZJ%c~O?h԰!kdҧD=yl4-eN!PD;տչPlu2uէ&.`w ?wouwi"UBZ4 7%+nl|H?U>}cI1%ȪCےPlukrjhSTšԳa"D1ܡh-_pK[IwK1ݧ/_M Yc?&F]y cܧԑ[fJҟs|c=^s/C0_b⢒!,Z|- o`_^Yp27՟U@sXí j_[ ףrS E]b[nѩm68Tߒ3X%(s[u_Bΐt9!e!Z3tŦ%zP IDATB}ᖽ%z%w~tua`ݮKP|Nt(w(vo!W~J%3YpXS2Z2aMT.6Z2jSS[' Og_o*'O+ߘ<}mBS*P_؜e(ԇP!b<n|-CjtׄRecv7Q4$}r(MK,:wȷZP4jR: `04!TKQe;ԣD|c'Iucmh^Ĩuɇ5cb>P0a-K>Ɗ?=fʮ}YEh(zy^X}ɇ`M,atq%" P.U򲊐1Vj^>1%qH}d|tцnpKXcK \Jʯ9;u 5CSPkH ɮY>j=SD[[)!s%{k-BLk," 5BgNsz)2bg`[VC-ϴ2k[*ZCiUk4!sbԓf|2a&% Q0V շ0Wf{), $|T,7Ek j9_b==}ɷo8n)|ȍאp`|E[dS|$eeoO'M K,\%P/(Au\uPt 1PmWֳK]nߗcjXĢ-J_AX^8!0 ahQ},k.qL+tPe}|gSQ\s[r/%8V˜T5̵zFs)~XFiy0/rD1iN^҈Er06~8/S`,_b2!K\gɹF,%ִbbh)pkȺgbs))0Uc:daFY{h;MGJNHvrg%VVJAJIK1EF>Z[d]bѦ[\!>psұaZ}Zc%!wb}>F.VINkBFY#thn>}r'191}Rjȥ%;gœ1&3wxUKXܬgC7>bI1/hE3>t``a°0hސ05Ki}r[T[[-Z%l'$_Ž*k ^O MEMKoE/FٷUϘSК>LȐn`a){-FVYe ]jt-COLn`{Vomjr=/ףZMkmձrωwt۾_9 e/)M'72,ۥuZlR=iOQbh4]Ws!s{l[=n!q{GBύ69ԗ\rLC I CM)6r9a>B5 FOC~ ei>jcNU_->f9_S1a:B5r1V wװju OJVӹOL\5CgZ#[w<ݫՏ-M}).nhzڹRw\"&Bl*T}ûÚn}Pitigɹm74 +C"b[eJ7X.",_VTx|NwjkLO)gvMJ'mVZ/9en9)`9X}5G C 0fc   3@Cx V`Y []\R*˞ sڅҒsgFf~uWB+[ P5YZk]R^:/V,7}̡#{DEM=Z1CG3n,]Srb{wCr*!G{+cH-'}XTNqīD?Xuw*nhϺ'5Z- LLW\C[UJxN+Y-d;`ճT9 P RSP#9VR:{i9r{n#[K*W5gRYӳdAwpSF7'%.5 APo2 W#g˕5mS香52f92"a\c[E6]ѡ_f}_NHNLސxYHJϾkkR}tJ[+K,> q /_4 ׇHNL~HTzZ1]ݬrr͒+Mz!n-ZCہ=-5r=RJPET0[i1wCm,z+-i{niܬ:ʕaq2Y2=Hܬ:9s`Veb3P:Eb ja1%==?a!Ǽ!`QWW!VVۖJ|>Zi_bvq>S^4HWh;cZWewBrvk ZI!ڐiX3J eX˜t]6!c[D#%V+~J,䖏R$sEFK# mI!cڪ~9[w(?k̿eO(J7,b頉Fn 7%lK|^Ü2m94F:G!)JPǶXC?sak,y_?T~GhvC[CH5se W^FBKpK,,ӣ /5 Hع ݢO!X3+Zֆ5EOb1V}㾟"=&Ӣߘ(ܧv12^T̡C{kB5>V3PrEw~Y54STk2*k0-φZhE\Yi2 >s[dtiZ)瞓'J7ȸ"~zرkr+w ҭpSciu?}xoNKHNJ~B?4L]ՊE>,X?GſF^ZŲLLM 3;9ܴ/dsԸS]`б{k4B:b9q=^ܬ !r46dHYж-ːzm}#>CpVPch#%=*HCڡah(2#9 sՉX 69[2j[D̻@ &1/[x@;x]ӸB,R>=m1!Cr5M+uq7 GLxm `r 4Prn(;4̻FƇGܬĢ#4➢!w+RJFЗnKp(swiknէANKCXCZw;c'G5}|Yٵ{SP@ H}5Qhay۹ZEmC7LCd ec>C p e9R B[.u\"R%/o(e,10gcR=Z`ά[տ\9ҥ) ` ge[9!+tiD+[RK\"w3RZ#9baW 0-<,DK,J1Zzq=`_#ut fRK bge[.H)%!,rg\ڡ5=z͢+RJ2ivT1.X|1L[Es{9ti瘇S냃3%8=]52>9"K)RrwZ/@DKi. Y5rRtLּ ˉvChYf1,&M4oKʏUC5=WZyüCS^1u w'Ź,4oc,jWcdN;5q+V; Kh,j{gKVsiI>19)Y?{J>}bj,5OyfaH;K,D†ryCNCc9#'\}czXV}B[=^JOnHv_.C V[zK T=El_FϬfK,U~O F R* fk &W 9=H}-t4V!|տ2r"_++l 51wN:ݿr CY*U~~s>%Xܖ@?-lX0%.9<=n)5}k%d4|=PY k!>}}-s}1caY닥@J7kXDLX4š%][ycJ!ŀ~4^Cҿo|~rgmHyOА]k=7_0ʰl}Zg/RSњ>c2̋PQ!>987HSe',K53U9i| B \ck2J;,X3k$||{c{ 7$[s|W1P,I6_!_{Q*ܹoEu;fA#?vE~տdcՒ.z~iMMZ1=}ք4yB3w RJN/md>"{Pc)bߧP/"ܒK#|O{hKөD?d0D6|iDL #S[B~r^#>'2nES}h+T_U|=V:[)i.N!Jkbf͇H-d{<Ia1%_2m`i˧5SgJt ڌ.BuExL~(,_CgXnۘ=TɝwgCo͗n1En)}\]J31"iYsjdh g5xݭ VgCµ=cIOȿՠ W+?ll#c- "~A/jjn/h0jƫ6lN&tԢ0oԆTcQcϘ0t9f6@ 1ȵ>Ƅr 5Y˲/߷T#u Cݯ ~%1BH!FAPC9tiJȗ95'M`(K,|KIנ@JNhp%.!g+F-wJ)}᧞ ˗BrB-o)>}9?rlʣ}? Z|m-=PriiCaK跥oɗTV5O],Z/`/=5:?+ۇGX)N0K,^c՚>1⵩e̛NXvfcۢsw,g9,%Fu ?@Mn٪^.KsEm4hҭ9,'} 6KqE'݂ƈj?bfi.JӓB#ǗevYK,D-j{5#]bʺǘSX,%VG'J|!hҙEamXXj 瞚w;\;F`zfy k|D40`D`1i/eü@``b! 3=G+K,B3rRk]P҄w 6\ e>b% %.#^pS_XZO3Ԋ,>K,B=P/ڣ[x%%/(;^0USFR>CuE_o9%G"e )/Ϗm%ajKCoq % CkkH^9a@}r3Bf @;`Be[Ze #"Tyg:|i0/\'F\ԗXY.鞇NsԸAs+GZO֚CZ|gok6P_bat!uNik:X[}IϺś*`.Csט| /a֐sRբb=r_vJZD14K~RsRL{mMP^bb nٺ2g!oQUK|5U5r,F:.ȹ졄# ~t0xy =ViMXFfiE JS',;k Tr'oFzY)r=&gQ $+ i1^o8A:(`j scwk黕BNߩprʕ ʶ[ȹ"v8F!r|Sq`'ߢ&ƟV%ܜr'x}uhH{Vk {)=ojH-/shXO5J1ڼ MyR8xCg3צT2|L!s!3$CV*\퐿Oqy( V db k5+g rqezѤ1|OC٢ źۥJ5!1a鐊5~CzZ];Z|~j 9@T9+{p`%H Xt/6̋tzҢacq hj({,<%HΎCbSB]1]60 <fa_a>.QH /'\-RzC)Ç90x&X末]5~z3Zt IDATdYٖ!J^a|"[K&t {!K RrbdzY@-fyV62K,21j_yA}lc]194=ΰ>@1C S"tC̿oFNK,BO$rG=txm=cgZ9U>rC׺4K,R=4¥%=c2w̠jcH-r:\$aaIX_!MQ겊cΕNJ7Ͱ!oz Gc`J'Y{qE8ҭEX1C-_ۓɚ_nh\CfٲomSa IRy݋·uh gbwCk3/=5s|>XSCͥ+/X/= {ZbYJ?Z#k&=Kz#'Wz@߹`,fyV`@4"i9_B)WZV/2ӡ|_}YSOyls,bApyY>Z۷ q_}Ctii @Iz4ӲO#:/,gY*|u9tpϽSsK[Zj1}zEkXxS=[ȯX\%!=J 7E=_Xsgu׆ۗZωoNjkxv_Z| aN/e[z. WsEtΚeLd5 1ʩp$$c|\2X/rC?Hb'<cQRr Wd|o-JQ)vE{NUzrjs~K YޘUnr2[=kjhY(P]brwiܭ,w8UBL%^tָLJX>Zה. wrg|g`}'_Xq Kjuɑsaq7p}rR''r>%ˉe||C~it>F鳲K`ҿ5Zӧ5H?Mf*ԐPge LLɨA=VZӧUH'60&SRn-joR3OS=gNk>[[?u#$Ƿߪǩ?7_tsh°zwSXYP97WY vTX.[sb:6d>9>Wtp Yoo<%zW^@}ۥ1w2R BHᆨ=7N5jͯR5Ox ?VN`c R3U$_&RMLtb KK9r {so.Ѡ9whۢz=+K,B \Bs~B֡ OO;>}kB{GZ=}間=5hh,陪9EQ]bjS)Cu]4߷F[6d~QΩp5nJfni>raҬ iʧu*4VR=-[yn]?3K,B:: `0թ%W@yfm[30m+\]]]7O !SanLOΪkhugeq'qOm3FОO>1XeXǜ{ؽ=wС=CXY*b?>CqzT>2:c ojT㮙Kq2 ["^g9PBel cPta]gxb{Vc;%'P!,r{tS[cح;B2p5oILn(}S6k[.Rғ;Pj8-$'P:Xdt[I}Dʉ%m|rbKYL<Ѫn0#9ܘ}h{59[1KtYm:ݺt)1|SZ͐9rːr^C2k[.0Co߳А y7o[CiJ>c-3TcKgPH}j-%n 7kaaʍf^5$;gNV#+/k:䤛u^FLֿ6=-RebHC~@Yf*;,&Mx sV^ř*w.UrXjoEX54_5wA𿈬3B[[qBs;F,__kjOi9-s` CًIsdS2W/_JF~M,׿{EHN~]_jpkBkLnk=f[1NHrsBHjK9tXӡD4SKo3YYwE_3~(9rD8*=MkKUΐa[񲺧74Jm[WHNd էd{b)vU=+IC [Lni Ԑ*WcD,7>w @}4=\r%'!dooVFt}qe49Kʦbw#kHS}KoA\TF}̾a%b|QJ}E":/ں=OESŷT́a钋ǜ32r+D̿E; +4aAؼH݊F69# t+|BN9 syhI<^[ۙCXۓ%Tr /'bG(] r̓h37p iZU*}e!Ǫ\Xה/E77e9FrӸ[XS-_fE1-/ge/cX XܭoQ2:?j\{KO0|FgJT&cݪl>3w~hT߿oF 7Ծ17/p 謻gc{|CONHO+!91oMO>’XtXt[{H,VZhCFRE|%;4Xo_mON`/Xzo9F*װuQ*Cìv*[߾gE@9YkWJX~[z1CUڿU9"7wis܆ q2^B~@߹[[C("3iA>okdYNXv暫K R+kʱ+>9}7K!UI]U0rAyFoLkl7n6E&HgB!Rwd'iqr͖7*Hλ\Rޭ|YezW^%h>'F3xHbvzcPgtRh^PkFQSy3:$+>$bW~u m\([<λ$<4":!`C{> |ɲ`WK,$Q\y{CP^=O+ǥѸ/x+9rz+M݈޹Q9sky:7yuN)X.ؑ%҅`ozykyoZR|FGן#Ki7co#9ED$B` 3H @"f!0D$B` 3H @">Exzܵw-7?_2:t-}7ww2Z/d(ϏRG@.!7𳳫+c;:i NCٞY흵w=;3Fˣy%QW9:6iZ߯i8뢮25/K9ZUSv5F؇)0Jw/'y Z !rY̿hyz#ͷ^wNH=[n_r1f4B:V522ӪEw3rWCW֍e^4Z;P5\Ӂy`H+.Q C궢NmE'; we1)<#yzZ_#f\oМ$+[!jizK\1r櫕G:𥉉RrjzgסlFn[GMF*OoG;ZgcrUшߖ|FlnWtF1ca;qekٵ0f6bR> "0D$B` 3H @"f!0D$B` 3|:_9;xA x ˠYzϏ]W^><`Y8~N)Vzkpl-wvUZ2-.@"S<u=1.ªK4FҷH앟Y|f)8kA5 8r:6+ojFfS8Dl5bJe4CBO^EZ<]-E9]{V9v$>`84B ؖU$(ve~HkZf[O*yY*] $(Y~.4bM>?[災Ԃ=v+0[_`9ۛ[z:AGLPꑁ]zٮ0?`$ ,)%oΤN{0Wu>Xg]xkmW{FW >;$ٶ_)0>_iwW @1T-숥v%}+}ڹU#Gh7O2va~Y\gf6W/7zu,ozh,ՏST<-_snԛWd>#Sy̬yWk'߮޹nv9E/roc~3uwK/ފ @"f!0D$B` 3H @"f!0D$뵏 -/?_|/owkZyY=>[=nT#lF+Ͽӯ V|FyeyOZz)۰]Ēfu~,YިvA9fEcnl?h87-vZQei'D$B` 3H @"f!0D$B` 3a{7W`|>{/ [zzOߧ.5bߛ_ƪ[]?Z'}Two';?,.ʆ5ZFЧգfNv*k6iT5]gsT4Z:HOoh?#kNIHPڛ~]{ż][wwgy̷e4XXɆl]nnKZ+L-QuDzoyCٽsNʿ7_o ,Sۃu{$CBЋCMCNqu+ү*G 習wԑwst3RVLY{G!+k_ZjWYv2ag1+u^Ԛ.-/KVךv&l>%z逬u+O+V;.?2Bio-\Ώ#]SZ^wlo{Jg?2~fmIY[:CFoFvw=wF`qla2v*JQV-70-`f`vLN/F)vOt(?jyW)z֗zڀ]ܛOkrJZۑ{ڃ7۝J#6,m̭tVl?όFZ.g^QVo/+X/#"IT]IDՏ7ke_1g'f'N_jg].KD|g!_;{O{++3,[+5|Ke+7Owwm{fھk\Uk"Y~$V#ʺS:OˆZ.-^ywwoIDATȮ>)%z.'ڹ7]^ȳSlhr&˼=,?VvkWK^b17Hza"OkKyF^3Dz#eOmFږ5|Z/l]ǖ;ȾxV FNQF`Om}xWi2?˶C yU` }W|̶}[ 漀GⴕMvWd;̽-OV4$SP>S}v_4ԽK"箿,{Gw/w<>={KVZD[O>3pR=h&wOrJGO#Vc*!u(ٛZl#ZkDkZzDԧfӽVUoSod;J_=˫5R[\"Idg&O^)jWRRڨKZtw,^9ͻl]zHfzws2ntzz{鍲ua~oe}j9,yE!_ޚr6v[12N>rr͔5rjx[*Hݯھ)DK{wf_rkYo?2ߙfד:2V={iGP=Ճeٽ<{.4os֎A[qw xq]ٹXkIk8,ߍ6i#˧Ԉr]Y4Z3;8<#mS3K+H?^zy$'-˨'_GXYv)'/P{ճ.E`vqVޕ\޻uvokO"0cEnG`C{]q7Sq;=:0nY6,^RY#[a#XYۻ\#"ލn?W4nݣWN;Yk壥-ﱫ;LֲזS~K9-h+cI?B:UծZZH{KigM+Q ~͗X>B)tdvWvb҈fdyϿ=;#fj1#j="B+"|ȥ/ZH]\iOzy:yyʫv-k}кu.>/ܤg#噩Xףl>;ms@f⓿,#gs#Z s|+<-ۚ\Xs.Doo[= |嗶Go=Lvg<~;r6mu|fC<+:;|>G, 'F̊Ve~柟y}zg1pQ`oY+'rQۓHy̷:;sNVG-cux4s+Hsx-x5_ Y<`$A0 @"f$0u2 ң+zese3~.U-AR7~_}l/9?+F[#fJP`r b^5z^2zVgly~eixt1ff!0t`|>\@Xpq8 @"07>K)薌`|,{e\U?? K,ao%&K,߸D$B` Wegv-wrESshX#f"_;[ym};R0|t_vrH^֣:Wɿ~$L[ӥGxDY.Kޖwx@YyR=glovXO]v*>o3)0K ܫZ>Qm)"XOxP:`7S#HQ\R<:z~|Vv;^J~/]R$B` gŎ^zZzEgoo^GÊe}B}J'{KKv]q'4# xKipD\}R9˫γ_yU`d{Zt{roZ.yG|b2Y3{WW=mkNV{Nemٽw]*/ˆVe{{G{g񶫙Dі7ba%o;Ы5N-YגRtS2֗^K>G|N/qoGAdyH u[:Ez,Y׃=Jէ5JY^@j oEs]zEOkF_ͲF{!Gi8e/Oi0RUX iކ4n-ZԈbi30փΝyk/:hi_O*#_QWxEҶitGym']Wz-O =rsTYFzQz 5»32@/6JtWwwqu0Z̷pYy\!@oZ]x:[zX3Zw+_ӟfk# k9F(rhJwEj馋LAu>֕\Si{HɿOk$QiG*ש6_VZzO=kWfeߒ[oQ󵰦FQ]52BmRv$g|x|Fy|Ǭ;ݺRFG3oZ[:VvpEEQ##k[Oz,d$x.GaT[K-yjM]J3D ꨟQqG&c[f>v摜 i`r&Wsf&k3X>fִvo~bި2nlMo݄.MԷK8tM@v}̜@6-#ҳRGJL+f>?yF=H@{sPLwh5^zmޙO D|@Mv@/>}0Oq 'l h)BY5 +VFFfŧOO5w|!e?B"Ç毟[~.vIO`L`_'b5х#ͧOOLtӧ?\ѻw7|ssso|<߾zHDw |b"D¿]nӧO.=}~DDo<]=#`t{'~ë~xl"ztxwOD7"<CnOBtD_޿VwxǿfDB'"o?FK?G[!y|>qO{]սXDfǻۇw4pyfػ{|~pRi ѿ|k̓k]Z}/sF.B^o*>ofCܕg vuQ3O$:?6ЯNK" $]*QC[AFHa`;[!x*gRFaVxl`L:ZXvԏ>XmCDH׀Ǻ YQe(( `Qj":8:j-^npA{:cy-  kO4Ԟ)W]W.>zIH82:}ow9t4.rD9",EC鲋w:nuwԈ3,M=4L4vFH/ jZ<@j-D!"Ϫ{ꔺҀ{/Ф }Ĉ^CDyw!"%v|$DAA-"HD9rd5twkGms$MCju~Pl#;ϰiΨ^QLԊ+;uEhj U]WutgK; O4 o"0HZbVݰ:o*xWe]_:SH: XYhg%R`7UU7ht_7D$W]"J"zvY_Qk(ުd;#G'6YFӲW:|I+'"- q$h8`r<z(DءC`*S[Dl$*u`D_ ʶ*Xƾ'`?o.ҫ/1*ؐg[ 65>2%"l+.Tj85USϳ kI(`!EC*H:miy"%pPE"HT{E4R_ Ѡ;z 6Xi']Z(zOUtiu~jXzfGU̎T~晴تEp:*PQMձmDU[PdGPWNRfjbUfG2VUulAq*?ID Rh_(QQegU^ALQrhZ+k+rBU(Q&-TE- 6pƴY, GB6]eR=&"'V˾d /ȟ&Cghd-1BA+hc >VުJAkiY^+ȯ~Qm0w*)ĥ*KSD 1jDnZ2؏~ W9z-Q42bRӈ GB[Up7-zZZl?Z,\GJʦ, WҨ]((uqbQ_H7졊R(\3RU Q*ћ(>=&J(U'|qD(U MC8R-Ħ2JоlΦZRy$DaT):oLT%ؠ mJZ3J5P*QUzc(BCd(w(_:JldS ѼjD-m; W(OUvT)Eٚ+U QUzGo8T:B#sʍ|bCU(2?v#"+0d+82@&ZDj2Pr"7@uMUQ" g_mP,/wTqf MWWJN4nVRDW'h3Wx{Kd@\CV/M  @e%i?HDwLl+3-_SL䜀fмhnz& IV#G(TNDN-QI?:$<8TGHD0"[]9DD:qZϪ7X;4ESu]%DUJT*Q%DDz{oDlijC~E=JGDTXA1DAib粖[vP FŁU):,F)5/UyoDRIT H8bN].rX&G Q5 583' DЉo5:@c?bSq Qm [ zE3^Wq8v9E+I3{%kDUVJT*Q%DUJTRP jm JFAOěYF2i)VJY"3ުG8&pࣷ4[7UfM_ As(vɮ:,9ωJmoAtb/U;Ǥ<{&,b/G? L$C,[$:K|]d!O2QXq.{:z/tR_O&bObVN\ {$4tODESZ:"+ҹ&tJ1GDAy˽T>"Fc""%o([iuR)*Lлc8 ~4r/}iS Pj)DN/ӥȀooHchSq`Ds&V dth@SP0yuSD>"OL4>T}S0yuSD :Wqx?ꖈ2T4"rSm3Yrth$(H-ꆾC͙ҳtt3Mj4 F*Hgċm #\` G[Qˏ\>n!)  ̢@UR55\zwA7<eLF#).Zq&:(otQU,>D4A! 5mb.T Nhml'=t{JD*]J9Ц!I$6|& LHƻ59gQqkgI)tK N 0GcStD#i*HCzy $Y! TH7Mnp@ ۺoyD @j YtJq1Z3\p=8W d%*E]U?u6Qvd-k+~mfŶRo%AOUvg=6g6TO 7n6NpdSܺ=36mM-TPɔVm[ !R!cVm36UHTISt&36U՜1.ڦf%6ՍUj%z ".`Hwn䛣^dTo䪓0g&AKbΈVkV` h)c-zqBl94[Rz&J72}m}"S JTfKW+;%j.7oGJ(^ Ū$FTo4Rh[G":U[Jn\Dڼ TU+dKi$ BjD\#:JD]--6DlSE-D-QUl#YA9^6@N]Mqd>!.RvQL <ό]mӎ`\t/-Ϝ_:ފzk[ުT+Q%DUJT*Q%zS"כ'ZNEwPi1^Z͸y0j:GYz:=Dܱdԉr:o5{7sQcGaq&&@ j2_gDojFD&CDCO0g7{ƴߟڹb =2" #*Hԑ{ ҊQ8W!8;R"zU#tLs"7? Kel:Ǻc|$+/Bќ 0t8HlzEJUJT*Q%DUJTˈ8P (h ,Ș3P2Q;d 2cU[4˵1)䑈:u[2QCv:c^kd DbE"e.z*Wf*!r#FReuǢ磪*Q%DUJT*Q%DhDYVr#0 P%9RnBF2 %!Q9ơX"5mluHD1ءi8q*cc ( Lѫk% \%/O(>Eb^IQh@BIAlTTG *m( _?/Q($09F'"ҁ(eV Nʝ$L]ՅŰT> Zԑ"AeSѤU v9%h T0IE/REZ @e>CWoU*f\}_^x5us^W}UV"rmh#k:Du>DU:zWcfUL쟼e^ΰdmRG^vTwBy ,:yd [*auO#zYxM~^qx$AM8J/2 =@{(*}RjWNn &;K~AH.OV )Lzc<^QBDI^F"'8q*>|MJr&b-JDn&J]H:ύ`Q^tS?2қ|0S\%h.38K]cfy T%O8,JYnT@'SdJ2,{3G>:dž ֣q(;q+_*vm}(\*J+bhDQJTgJT*WZtX.uv&‰uQ0ΐLˮ#1:0L˯#2ujd2-6&xdZ5C%D$r^(s Agsp~@Vqv[>"Jn^Q*~\'x[iI%[OؑYBrv89]/'$"Dc@]5h"QȈ)[G#hg=bSyj8Ԫj3{^T8ɤt}="j9MOnlCoyH`+N)erɭ.g }k1/Z@UeH-bnw "kʡM'"1.(A@/u *(wԜIDATMعQj [lYӒlV"iěgG~$Ez& @Dh}~TY9]8&"$/|(,5XHѫVD@D \t$㷙#hğ 'Tnu"qZ9r§O#:cE6&y=FOVC3GPZ:=e;]F[Eq[X9*EMo (5G~s9};+n(ddor|C ~ۚ&t3^LtPJTum^WQJTgJTmKDؾA0qe觉 CIn0$<>H_ tIME 'wZIENDB`gxemul-0.6.1/doc/20051007-openbsd-cats-installed_small.png000644 001750 001750 00000006571 13402411501 023133 0ustar00debugdebug000000 000000 PNG  IHDRtMRgAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxY[lWzRp("9q(eS]ײ[ZI6 8Jn} Zd@X/}hR~0^]Vqly#KJWH(C83 IMDzb@@̜9s>b;tnY;cJ鐪!.`!ŪE|w`J#9P)9U|UdVVg$fZYۥ-Uވn;&:l֢ $Ae&,hJ(P}ּ#kaϲX~J9gוw?#wƇ.V6/Q{kgw,7?G &/ȑǡvԎxo+:葏#H 7Ilt`%JBfWLjT2 d)YaӦC>TJIFdI21)#FYa% 4)1z{dsIp٢БTɴODлEү{ޤo@U0)XSbW~F5]:[?O$íVs'ʓM?Vu}̱bTZd'+ 1|Ȗ)T[BV'1_-bwN3-bzU*k:HHӇjɝ3<Zhs8:zz9@~;}w;:q}>}|YEHv͠?̩k[C /jl#a8k'FܩiW%њ%bԁࡩAƴL hĿ>}5*j Ok#p&)O׻ZS(emF8^%eSe#цU\*E3ڴ;*kh-⮸v]`']%ǍG{#=l/|lw$ ooTfG׬Y^yF(U9{Q7v`d%poƑ-'Eb fL|鮘j!K!_-x< Ys^5?6ᡎu:Ϳulǔy^4 385;Pߺi18{ƾ28tPߕf[/ЀR4IJ.7?P^rZGS𝶏G'NjΛhK;zٖ+Dp'\f`( ~,w]?>Ø `tYRxǪ*qֿYq$VPJx }Q::<<4kj*& Q-۞ 6*g pȑs ZУŮQ0c;|P;>g %4*Pæ|t.$^ $C ##?:1|?@SX"4$xk悧-77"]$FreŊa)7^'cŚ)e/=4L.sq3G!{;Se`7$)MoަΫ!FN?^u砭})(^x-K }R^1%3qⅿ\$LﺵjJ Z(k!ĄB굈{&Bhkӿ8/XV 6C ^*hQxS~Cg˴@^o^H^rq ):[[,N:;.uP&]L:J?~3߱lC usToρhЗ8Y.ń+mSx7xku<7k:Җ}fbḢO(+㜐\L"pe9ɨ+LiiN@rQ%qq9эe [qbh5@ cҝ$1[m|t_-8{rHaO({1%w_[W|&X3RB3Q{0ùRba;j]0PD JT1. "RעZ[\ CkȜv%j"iֺzr eV]8<[TV޻(dKKk} /-D|f,!/)kZ'E7oxr0z*nhP:s~rT&2Kho{T~8tIME*' IENDB`gxemul-0.6.1/doc/20041212-debian_2_small.gif000644 001750 001750 00000003454 13402411501 020212 0ustar00debugdebug000000 000000 GIF87aO1  !!!"""###%%%&&&'''((()))***+++,,,---...000222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEGGGIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVXXXZZZ[[[\\\^^^___```aaaeeehhhiiijjjkkkllloooqqqrrrsss}}},,,333777eee~~~;;;333111 111VVV555###"""sssXXXbbb***sss'''PPPEEE 666777 tttHHHSSS @@@777,O1H*\P '8B~LF;rE!IRydFA ɏ68B#6hѣD hȴi *8$(,@S%4P,pt+^X≎-DcG>,!n܈1 1nDȑ>}X"a+` u6ِ@ ,@ 0P p $`cа`*tKA$ f/BX#NJ*haJ Ia `9DM$D  qeI P "XT@$PAx`8XdlBS#8` /q WdH7B$D @ C PCM(H 10DDc-,y @W@*/Pp#@(J p~.k(DЃ >4)@ \| `. Zx"X( (@414C e =DHi #Aim#TA| )X@;` TAl`!A8`P04# )Đ^3<0$9 4RPO   #P+0!rBl` /$ (# |6)d@|@ H'Zm d@p l[ 6@%X (Iε$U4AD $Ё &,`B~C<b\AD m<8Hk "KAu H<@K  O3H? rz6(B{yC!NKb! 6_T6E>\ !A8b]ă;gxemul-0.6.1/doc/20061029-netbsd-dreamcast.png000644 001750 001750 00000023060 13402411501 020621 0ustar00debugdebug000000 000000 PNG  IHDR)߲gAMA aMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATx]==u FubNG_eaU %`|_990ځNb9=[_`$9~c.I`#N6zkxY~%c;bl [/m4f/o l&,s5>FKfYɛ6kLqWwOcIh_4[3O'o`o6[K"dK e54`<>&TMdfubnDžw~2i/ffwڸYy!oGo47n>Dedz7랍iJKQ|.i֘]E?t`\oV:EINuݾp9O,`ߴ-4+S0't-/ uuM/k_ \-}JM0OM[etxu|qم]'woRUU9_&KL3??~?% x M:^TvEo0 580g{~{|xè<߿ vj2:xݿfǴ5]m߳fG_ %p <6cǎ#%Xat9B0H.6p b#vt@Gh#s܈G#t?ޑocxι/́S(Qy$ot"'hqL _8.;,:CWَ${j'QN!o'kz΂C#`@Gxd]Q(-+M.wܓfP˳m:6o]y\myc_AFy<[ߑhK+_[m0ʧO)wUz޳oޠdwNLt^`$.:*S>SzrTy^vk1fFoc];m|r?t n|,`8 \&2M YO4ds6l\>FY~{YU>'%'Ȩ}ZyNߪuA2o\>36\[2vPUrylytƓd#'aA{_S,O WO8z8\lGb>HK%z gl_m@Sg?=l뎎ഞgZbIzv <Ӯuǝq\n1zzuBGos<s\3B:qQ,EHiт@Tf.3f'n|Fxt\ba6~-2Q%]j=YnHs&k.s}d-'?eGb<}%⭁|5 TnjS':e~tLLb^Go. }H|݆X_Vu>m/lf'uņdgycܼhl>2X@suGO?Zi~w'Q;QޘdLg8ǕyW_V!Y;.o:9Uຐ!I- ! ['k}j~eu7*vH)nu^9Wd5KO'3Xz[OpʧaxUn3pKp<#cx:6Y߱6be<3QT|4'ix;ߊ :;&D>Re嵟z0n;D}=wKk;Rfk̿t+.x:-ّ⸋\W,^V>.1SP `lFkѤ{tdE룛_2`IyU>;&Z5UŃ,la%@eB; =kv lT| vEkJ:Qe{2Lq)?/d:?^rXʕGZa8C.[yfNG;PR"OveR)$*fW1Ӟ~MxNK?0d-%B0+~\h:\|t{I<[7aCǙ `E%'mng*uӾ[Yy:ɴ{^~Ae}f?m*QbɎ뎵_%$K33vY].q&;Lֹ'Y5#<>;b:c8G~Y/1N.dyƏ3yj|ǻI.iq50{Rݭ^] it[N>U!&ktt@G@Gttt@G;b8AE""`тP~(5GOͩ kgC\%b(yls)Ma&|;QgPM$#q|NJ=(hòQ/U(9h|*G\v Y L7gKpaޡ*d"z޺v2/`V˙ۋ 2rt\nwGE3p]crAP-dJo#q8iHtQD3tΖY.} iģY""gv'h +jo1}oёXLѣ P~a'rnnA-pjv!6=^7XY "+xzn߁X۞x򭩦žmquCa)9l2s6>_ǜXFURXT|ٮaVT«anw.Lo2D|JCZYOuS1GF)8Jo:2N ŗwB :g2n]>P#؎ Gy,Sy4 E%~dRϹ,[4"w/&l]]|w:BT}](QP";w/U==tdM}OLtE+$ǧDJOn? 1ϟYLqR7}V2uʐS>b/XԧL1XlfUL@j'G`&=jy5# L!.{)So ۻl{I®X}BESj6MR Jb9rtޅHWl9hJNu:zd]<l][s7wޒx ;hc\xÀ><`nf@] O.&[#i_wqX= Kn]>fUwtm9׷>'Ļ8ޏb_B}xVup v1Y/ە4W+Stl(~ۉ9-=l1~nOJ $]aIm]L=?{)𨮰q-YzFko[wbXKf7ޏaʲr_J˕4xwGQ<<^Xuv|Ty=`GP+<G> 1g+ܜԷA߸h-zt> tJc2t $U:qTGth&*MGdj6;a;nb]Q} tl |]& >]i@ڕMG\ R2N4ʵ Y@gWk@FBCn: בֿnyžՔX0z.ԧ DĂzse H>`td't[=.ϮrB#Dћ1D<~&=w,1m5b A<װ?8<x.G*:I,(O_:D?:Өy&f>hwfNMG2[X2@W&ot>{/R?wxQ'w;~2OT9@G;?Y|"l|>9Z_hAB5%GȤ+:L@ptƼαѴZ0~+C^s<*CQӥ]^w|i:sK Oߕ9adĤ CG08YNs.b=q=P)md%>%@G>| mI>`޷\S5;2ѥNN OG/$:H@aBD1k:sh_'0wh]Y/ 3[g1Rf˾=zzqLMKHec^c!Y7Yt;kVǏLAa&Y`sVG *pȎ[7 @9Z Z$>YGz jԞWI iڎ/=^QybS d*\R=@ZXqt5t{t4F$x")+yq~;#zGQ #a~`K%re[ TˉzYLU+*9 ]ag oAeB˷B$K)_Mʗ}lׂoϳFvP=3+ SM TrsI\܍q bod>ğ q'm.qL3q 9&%giy *wx/K88>FNViYn_ˢ^"1۷hbŹ-8|wS̙)\dO墍8cqƼ_N (DD/\%og]ŭW{ ͓>s !"9vϨ[|\Zn^rC}Z%ur͓&(5yS6?{ٜ-cqk[]"КCμX @0:#O,rsϕPQk钗% X tG|ch//yrZߦzwa Mz5-Fw>0̽yBu AJ]e+::m\tE.qG]zGą/,HoKE Rk59/4B3ozb]`\d]^:y{wYvH(iZΤ+7͹l혻)W|K*ڜNgxϺ8t >tl;,yinGky7W',-~R_YAj|Ik0"XE[zCy^]' ;zw Xhx+:M `t@Ghՙ,%G-6UVngW]p$!h=ʐ<'k[KgkЂq/il`cToqd@ZGRĥ~z۱so{/YVGyU7qe]tt<&@nl3Ny#3)X&mЙZzg/)ȰIɼN!8gwhYi@ \WS;B@Gc&keuʔXʥ9KZ0l[;huʯxI'WHsۃV,=@OcG9l*M ioeۛڤTCخw,H5v#2 W8wB͸N\i4@Fc'Q2!Es/4>v^v%9 :Q104GZ##:-B(.g78i;#-dd]S'ۛli.o.AU[i~ZmǶޣ`2GgHs*ҜxS=TW<YL9hiS't9h*Sy}X;eVQYd}\ F̪!EL$/t|ڤߺD=jugwF6plGFGL֊#s]q9zIV!S<юnF$~u?{ܑXh-;ygR2O:z49hySwS[Qk]mRpH$]5H&zx>9i1KI;hoYa~6d26xaNO;vAV'p;SezOOEoXWwcí@˝ ֽp\Uvh>2wYZB|ֱ-cCfS(CgٞG-/wg-~f3^uA{86:/x p4cnl:<%%b$t @8]"ګ2CtytIH{ֽ<_x@:zC Yw6uIHێ#c^NZ!X@GtD#MCoIDAT&}`[ZVN* k$Fj1Գ;6 rgбHHKʼn'3G|?s7[==ayAr2קC׏/y dv\;wʢ!V"BGy{@\qߑ(cn3G5~Rg;Gn>rɺTtݸ B\!3rGIGeq$FS#wgIGtz&R{2Qcc٩5E}Guˑ;vx*:50g>tݍtdKPOGN1s/e.*{,Gԧ *SlG#9{ף( OB:z>AKWͶ{ӑ 5s"=S@QFL\,o/`RW~tdy{/z|GrtG Co[BG:2bxO@G[YFXu[R R~E_ja)>V:1 ׶㽬Y'%FZw8̴˶ҕa= 5^Q6 A³踿,oQɛc~0D6v_99y˕8̋]. z׍>{E-&1Uרvy8o4g*a}r童;pdMsG`qqnq_ `;v,7z4K=eeiz` o=3A0_1Z݀qlEu=TKukIdvmǧ#+(s #2,ӑ/ #pg t@G{ұ*4<:v#?_O0ݷaFoeI{a  CGӑgt`;lG5ET `tv!4t [_9r: 8z8 Ʊ6p|\g`?(otIME 7&5(IENDB`gxemul-0.6.1/doc/20070308-linux-dreamcast-2_small.png000644 001750 001750 00000006311 13402411501 022030 0ustar00debugdebug000000 000000 PNG  IHDR{bG\gAMA apPLTE  &'''. ..,6664:& :.>6 >>UWU[E^^\fR& j: i=.n`kmu26aahl; 榃ncEĪRuLSku5O5 XQlw*L6gnl]|}0Bpa*պH綐W3 6Bhg$vjH猳rL }%l(̍T͢ (sCJcIHʤB99&Pc/>dD Wy|) "\NgR4 4ToF)Z*E!A.Sb 80՚y>v7qݱbh %GG̐%M (Hu^cij.'X#oڎ'ZYEԐeD,w)c B[ bXN\\Ӏ n׋>a76xJG+\ [|<-#ĶsUc C,if @a*,oR,u\R(MJ6/ۊVw=c΍)=-A <6Lk%h<'brjd74\컾CZm+4kBE ]k|M&#PPi'jC{Q'U2a{%iڮ΃ dZ GrD KDփd}%v:(CqQDt, 9IɥGgR(ь҄tbO?35w1ٚ()F SjF9 oݷ*LbuG3\P^{ Hk?zZZC&ŜecmH吤9tV"{y41C O8_L&I;<-H=n<2;eOl/m8$Pg^:L`.,ΐ: &ԡ^tȨHtԖsT^X~V)F{U@!cGms]F% PSܕ#;",ZM##!^7e,[zτF>`"qҗ ݔ!ҩ)-~kJLYJ*G4>>???@@AABBBCCCEEEEEHHHJJJKKKKKLLMMMNNNNNPPQQQQQSSUUUUUVVXXXXXZZ[[[\\\\\^^^^^__aaaccffttժMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxZs7Y6XV=**FpiDAv,SCHZRrΝx 3ط7ڛ}{gr|x$[?9utt֯nG7V7nӧO~?~~i|/}|K/| dB6>/O~A_Wj_q/Rs^$;մAoDZ삳?\tC S ߭DKM04`]TZc^,9ިCC6f!%;Mz/DJvBQj/V;@&Rp$Ey"t3od8%KiC]z kvkhl⺆I ֧GuP sGs/g!e8QXXwLdSPZN{!Vr> aW$hLat1Qla.t V^GiJVg<_z OzGq j.ReQ( ao9 y|{zmǡer7d%% ,(T\pNTj'`/(8gutnA$BRct$aX_zZJj"a T=rJd"m*,^}! ǣPV%/5eǘ{ʱUb\[,f.j N뽩T+g3tP'hȭkLSn:M5ᖣΆD WcElaXIr:II[JFnj0$>fHv8Tu&AQU .$ Έ,D"5lt&螢FەHA!F1d D7ҳJ+!6`9xȍ_SG7zaўC|[.m1m%dykwJ u댊(OzS>.7}얯B˚ @#]sESK:Fꐄ̩FW$fSMQrO(9!]ךJr^L(g-vj%h3AܩDCx=kCpQχؗlmFVjI3!\ F fAY v=bL@>/f3V 0rГ[cI 9Zc/K1"`RԁEْݵ0/QU-f($5iYW4M=a;%1*i#@zp:fd zh/nfvTm&ːxE9&ђhD| [9ŦѾӄ!thZJ/ؓxxIx(R Iڄ[gZwZ[1 fZlBG+rI|Y(kvb 6$dFdnǓV@no- (Ta z'pβՋ&RNB&c ЈC$Q^ b(Oh^͙ӿ|Qlv,_Aw+BwlH)ǛAGjJQn$_sGB=XgV9 .[+`k*< PeudD㪔M%pצh5$HH6(ꋴ؜PmըjTpR vz;◿8xSeiL7]lWh&v0Nl-mkgVh@pܤxV jH _rgS3[P1a'U:Ϊ wQu32LGm\&iЄrj@6hszg}+dld론eF>(\)RYKbtOzm5׎+K}۶d'h$sKΕ3ɥmd 6FAM |w?Dz0tu䨑= FKڂ5s9&w:AnmX%zRamlF2N#|qk$4aMEbnϟv]!95<3M>ەO kf656;*ltIME!4\IENDB`gxemul-0.6.1/doc/20041212-debian_1_small.gif000644 001750 001750 00000003337 13402411501 020211 0ustar00debugdebug000000 000000 GIF87aQ3f -->>>>>>>HHHJJPPyRRSDDSSSSS|SSZMZPZR[[ppxxxڃۉۋۍېܒܙݚݠަީު߲߳ߵཽ""0066>>BBDDFFIIKKMMPPQQYYggyy܏ܑܓܗݚݠޤަިު߮߰߳ߵ෷໻  |('`#w! @ x dtn''``n $,Q3H*\Ȑ` *HHŋ3j܈1b Iɓ(S\ɲ-cʜI$Ț8strϟ)oJT(ѣ;"]JS)ӧ,BzR*ի"bu+Ԯ^ UٳhZC2. BH˷͞LaT8F JC,1zTH#@AP%(S@P0ɞM>|hɃI8iz|2'`Zb+nK)D'4La 4z^6C.%ّ.sRƇ"8&&x{T|D/ 0( U1[a;BU W8POP:zb.nN/o'?}+l\S~ɮPWvku5'DT"Db4JBNR1#=>nVpgIDs, dc;Y4VB.[8{Č5vhEz&/c p(7b127nqWhV,p7"rʜ,W0b{Nw=x -aD ;SaR!Ϳ![&=SDy)|NkG~MȢ$k_Evn O9v [֚S͖ z08Λb{=Hjm:~2=ս\MަoO01pqHm *=&w]2=:\#Nd4<ՄtO-lW#0W̡5oynx4Rjk0.嘁=Ugsٍ[ؽ7Nͣn`-ֿuvgwvgwvgwvgwvgwvgwvgwvgwbۧszc~ZqtIMEbjIENDB`gxemul-0.6.1/doc/20061104-netbsd-dreamcast-real.jpg000644 001750 001750 00000211654 13402411501 021540 0ustar00debugdebug000000 000000 JFIFmCREATOR: XV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d) Quality = 60, Smoothing = 0 C    ' .)10.)-,3:J>36F7,-@WAFLNRSR2>ZaZP`JQROC&&O5-5OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?zQ%:4ހ(J^ b8 C3N▐)åGցGuRZ@(Hw(` _z9G"UuՑRhN(QJ(f28Zn35pܙla[\?gF@Ojkc0Fռ$GC94*9Ss0'MѬ[чe{T: m=sI nq s5inIXd``B|j{@ޫʣ+ێku!Ʉx>'SWB/,"k1r󫖄֫\6S-o`+M")0VHB;Ҍ*3:~5`|(JLJ1՛U TJ)""_hyW|gf=I<}jʈ˓U&I>LnRq\$`fLdc@#҆~l l+C i(oqC)z.bxLD|U0z֚nJ=wnV{ _-chFj,➪Xb6|;,p$U{ۛZ&Jş}Uzal(jRKS6Nef;x,[ L ٫mܴW rvBTSbMOP\d1m^\֕ۈyi߇luI anSp wWl;d}"#n{Ug!bWs6JH^j9Cw7լ#"v8" ϟj qLޠ5bbcUh{,wr}*Hwݏ)LS3PzU9{w[V@G|@h\g+*% u ETcTA5)E@FQt{)-'t8j9m fuBP/̼1Fc<ҔqHc+ϥ0i2Js($s@23U|v5cpx7J!ܘ5 .ϭ>#4+GGkt$Q,aH#*jRm[:<>mnÚh4t6pT)w6Q[ejrG~cu}gqJ)9zQ"- җ'ZZP=)Qץ!'zrhR•O4R/zP98u#*+ҥZUuFң PՆm~|t5SR5qR9pq \f3XLJCVfNNځ֬C<9054"'dt2;o 1,.aSI NidKW+9"4B:UkVY j)dJg$cS(TQօ8|ҕBɩ sUy&FJP(#98P,qB{2R4rKgO M^R9)j^Lc$) Cz@.iVmp`CvCEcGj/`d8_zPAR6Pc֓E|{Tp=M9vR(OT@+ȤV4${R6 t,|+ހ#L,ȧ;}3Wn-!hGPsTf?((M1OIڡr ȅO֕HJPY.HjD슋O_jk4eWp#َ]y%.(.2T9B==+Apy=)%B~`C};QzPB)½Bzz:$lrǡ,@ڗ @ )H@ mj#:Ebt7HhXُW(JWHq#$|#啻]U5QƑث4AcA䚹m= 1VvK!$K4DmqQXRgsRP/gz/57'䏖[յbJnY *9m}qvԖkiPmAa75GWI:j̺GpKd2g9۸kXlQ^ j2Z19N(9y0 $l^n͏QPEI (`s&љG ;98H{ A*Z`&h-F*9;N3֢IO840blv=)AzQ$$np #G9@V23~W#FiH4m9R;|BTq)H朇L(9(F'@JcE,[U(h]O ԆC$ۈRӸUDQK#G 7FI8ǭ_:tT#>6ԥ3 gǰ Ibt%1H7UG #c⑸ҍz`'Ҝc\zcMF*vsq9)4(~n֚<ӕxzF)~Z>@-ҶæUP&%- @j'ubs'(> :/,ݗzsXs㭵V>W&ksp9[¦s5=FVvur)lr1ԱD| BxҩEI*mVj̛bg=qS#iL H[|V3[n c_!rkx5mLTHM=;v݂ ŽQ~\z$`c'9*ONrPGY.ъHR5 j(L.sO< j Ƣ#`!Iӊ1'8C"uÑNG/ϟ֢4֨ dfnj)  D`rjO#<6) #,e==j:^AzpB*ePAN/qҥGOcN( :Թ&){KͺE5ׁW?ȷ;GN+J:!EMHq'ַI6!&@*ѹٱӀ7ޝR@iENi8RAK@J5i J)旭! _/j;Rv-!/U<= `%{R 3Rf!qT/ZfS׭$o&r3JGkٝ;LUsgֵ"fe-F Zi_CVHL5+)MxG\h&YJ1µS *¢;\\1'P3֮Mxe3&LVai \'V7DH68C3ICQt"ҁOhG1LUL(8OEY4$kU# k7M)OAPW]ٝX[ZΦq֖(7W#]~:H4k2Jǣ~uε%QJZNzT^޽|',q=d26ҵG.ݖ#i;g8@5*8ȭF;ygH<3{?:+٘c95X]#f O>R83b8rYK˂HG лzU&rZ׮ ]ʪ[ MWG {mbT_ʐ[ßkRVWgg${ <@;:jrSP穡IrԘ P SĩrO4|M2d!ݤY$UDzu&3PۯI%;.Ӂ3OepHn<*8MD#% ЀEźS]*6r@3]7tU̞xaN~gW*(5? ֋bYKG~kP$3kEfb(yf>|E>_hoSl/5IFQ pjk;e̞4켚 6ǨCS`8C+Oիv}6HҰ zjȇv-\z(٩Pj7&HoJ({QO;̻qր.[NPCGzi(HlI4K2yfL]f;c=-1T>jOhC_&ǓqsQHjR7ަ?c@zSL#ր>5cp+U<zG  )(݀}iK t~c >iHE|zӁ7,3Rc,|ܚA2o۟5!#-5CU*>tG+ș;#%8P:RanÃU Gjp{X%80}EfHN%?)◽8qO\P1MZ@8qNӅu;旵 5,=jR E'Ҫ5aO]n!Zq$iz●AM {QMPJAҊerJjR܄{UX+9rqRQ3V񞆹km*/0HV-JpG?+fJp=-ZI5s ͧbı.ڭ7PRFZF{נtFvLδҤI#;tG($cfAYMqB/y@?| j`g.2s BCYܢQWCVޫɊv E'")Hit˸܎U %]+0e7Q:2AZ~ڎ~c|6 օiEA!0E@Vd&Fj6n+Tc2'ia?:nǽk>g5ԏ?6l8QOn@4g _ۍ@Pj1b*9YlUs׌q\Mu6(0#ː=G:𭍴Ҵ\}O!hJ83~c+i֫ʴKHLCE>4 X"H&kBa5}i6+ʻr;8lSRpc?B )։)%[ rO56O4d,qNMDK`\͜;{c($SRb}*%"ӛa{E2/aL*'ʛ"ӕpEFx%|/-ӊmli@=E_q՗n.xɪcyq>;(|辤UE{Ɣ1jڮMAj6 qK'5ǹOQ`8A|FOBh[WqsKI%ojP@9< >-F+1# 4_q2$5w@Ѧ׵/(Ytӷ;ϗ@U"cIIkc;;j.N0j׾av1iA_z}-J'|Aqj?uk}^P䗆B~)֥ u'?WDeMGէ={FxM9}ZkG_eDw>{IUc#—1HS/PTgq#YXqN >b1PKSh>rM;&Ѐ#-Y6Rv"KrhdY/;q̫5Qi4 탚F96scC՘.%G4ФtiG 1pQ[1꺊t9PVҫJW`Z'tbYRFG>badg,]NUs[Y|M9OB1OKpDdG7컜d>Qk4G9" ttڌQ΂˹4W9u|1ꑏ֘|0j8)iA>?w=}$ƢDj4{\w]ޗfqsh2C,fxOv⺴]jhpB\\]z(pגd|I -9=kg1hc.P~5&SQy:1u, dFTl8)K*yr=Oj_;.x_;񤣵8өMyQ8fNi 1+ qڤ㚣id` ,ik3(ڗ+ ڪM" H;)[%GX\GN_βlRa{W+TΜ?:?_Q;y2`=.P\CJ:MR.jU5*0{1)3y?zN -M&sUyA;W,flF0M0Q>pyHeKXX V"]IUMG5ᘺfG*~SOPDjQ\?J'CSA%;r85_WAtpәZhE;gk1R5mP~"18j4(R1RMaB+Ҏm괢f¹x֤D}dQZĖKi Q֯e2R52Zy&$WHrӏ &>@BϝyDQR:sڦn'5^3ۣX ~QS 4605?1Z2dJ#0qQI: ˹ ƴt&vi` iFaH%Q Hu6̊"˷1]#K (ك8'!5Uu.>ASJ8ɏֲCNU[z ;~J g޶q\&vU)xllx:WuaPǪ)7nQ+k$!ROTӦ<ʓ: ?k\G[fSզa_HO^omm[UfɑiA[X0曡kt7^ 3vS ӏjkH9w28| s\Mͥ] Hpx YзE%ѢĻJ<<Vt72k[IzkH0 _yơrK~U$U6!7d gilj{o/ݗX("WOw*~9?ѭZ~;gir˲:)]~>**cv?XF"G%?宝|֥ >6q3h:5\C/k#IAqDS࿓y#FQK9|Oq?ߌ)V[>EK?yȃZpzhb9#UF2t>!8to!F*X|bPv $?S?UW9fu|BucFLᕘ jeCrNUnZgJKyv!s[X֥yu_ua)pQHr@G?y Zj%GE⨊c7bZJN몃ONx/B)SSQԆf}I6wMN=ц(UbGg4S׭0J:iå9ii VNt5j;ǡf \КPZI0{JGV'kxt帔c5<;lE;+1aTIɌz )byQU|4m9ir-TbCUU1m.^qtӅGgʂ懟!KVurq7zBU=P|ҪoZ]폼hn6PŎ:N8VRҼpԢ廨U ڲqۄU N{LO›uo3z?aE1e7Xs}ʸ X.On`;+fvX` 2­tbYf9*jߥA.6?b^61rkZGi.ZHp#R+Le$ңlP'mMH)D5.Gj͞vzTMR֢|cȚzd59Zr)'S NkSΓԘ!#KTL֕ػ?n'Ež>-\ x +ZyCA9f#v8`Epd*@V^y>}Pn*܊VnVAuUrؐ ؽǖ+v /Ic9 WOcZTkuj1iW9;P\ vxXwIjfLEzWDv. Ҟҩ 5yکHՀ5 EY`-mUʮ}JtP-A$JR﵇ec i,,caԫfK@sԫdag3TgJ/e%@ Y8ٸi8ƞMu4)TCʷU="R{ a V£ XcYZN!-8 fs5ԒьS#f@ RRPuGރYQkq94֌+&Յ=+V%~\玵Q#XSL{Ұ;J`8PisMg(n'0:4Qf4Ep''$h&bn)Sb֚V(*+EƑ Iu.)&+h6~f9,U;g) U.9>DإñImE Ǝ 56(' T2'ʟ0r{։3'٣) Dj\$~"cK'5dsJCjݘ|,BqGyfѺTF)OM,{P[!#@?7PG%1 SY>ksIw&~wcRRQb晷#4Crx&zP RKjw&})sE%ᚙ2CvZbWv$]5\V!Jb*H5eu E$0U,r@qSy@JDA;Gp7v"@|o̺c2 W9"mpaQKkR('5GedcOUE2۞T֊iG)FvLN0*$junMUw8Mwm閦-6kҍk1AI Iوvjx"gO?:IjEWhX>bJ.2Oo, Yl2:*E]%Fjq;dtt}w!$'#ǑX 0_)?O.ۖ];#Q28yHA SIbIQ"[ѷEdKM Ͳ Jl[V\jV6@w'[{溁E퍕jWX`h6hJE6"?zU"FDwf &ln G kR 5RGP#>IjR;݄TS˦jLTvfQi.t}S!I뜊ֱJ$aК9`sfB"-XIK2ֽ&!%J9A -߈ '|хiJt͈m+3hP졗+2& p@_C|_aF_-Σ(?4L??CZ@Q9r,0<ҏ~HE>qrӆ+PZiOUPRJ#Ҭb?)f<?G2z O6HmHQqv+zmXҚmdjDدފ25W$`b:9]F?47GNM"s?QPdf;o?5Bѩ=*Ji4&3\uB8Rf֗ȏ֌ўh(5qI[^t+%qӚ}koB<T#l*6Gzci7dWQٷ+cG- hg ؚOYK3hz U$,6N)й';+ !Gb9=I+Ey7»PxbI331h?G>!,^+&[ ^t$c|VX[}es7{V\OG6錩%P$ K׺ܐڰN8-znǗ-,A+  ܪ{sƺ/>n$ *QZj!Yd0?wϵe${#lṞ弙0Sҝa{3}'RILf}dUv7F9׮.@ePz bq|;6 uNOzUWw[3eNF\UE~X]JЗVMIInU#ТSʜa&:g.d_,T^LyUc*OSc4@k2QF6=4>t.:[$yTG.O;Aq͵dp@I/٢!02Ϙ9T%Dr⬂)*FInei~.ۮۊ]17) ~+A$洊|?qR;LɦiqbGm SogP~?ҩͦ,\ kW_x3Tl5AeG&y%bk)mcd\ %[H@\le_yd-r9cQs|T_jq@5֨ڠzW'E&h'5eij;+̷29kftvWLVhٝFH)i-t))i(M9 Ӈk?rvrީ{3Sr֋2)$eۂEbj./隧opğRr12:NSԠ@Fi w"u"PiiJ\`QZ6"A2k9d?2JJ[f0th RӕM< )"*>J%8 LhZv525-(+QLE.a򕈤iSD J_ŒRҸt E.((@)JZ0(P1Ӎ4 bE-0E-%!=iFQHGL0TǕrš"6~ZKw0֧{ʹZRx? Z9njW)zUK覐7xjš1zRiRPJntѨhFTƓ84E"mx{Z1ZgAVu~Tw45rM^T7ҹ4#jGe5_mXaghE^Ҏ (SF֨Ck#ģ|jK'b;c2ȑW`S@Ku+ 4cpN;WVjNJz$Cu$|- xx` ϞH%qZErPv liǍdz=*[³Ƕ$_J:#"mfN5+,hq{q&_G5!I,]Ibx؏jG40;m ~4B'hxL}ېZb{#j/\ϵNKnЀRUj8o.Hd:ԐJZd7_m'Ykҹh;|9UH[,Z~auwrQ˺ÊM Qn|m/?+cُIv;C8xb+=t}IEYNL%sE>HdF+"2f;Vn2] M1(~RF$!o!^ҽaJ S\\GY{)Xbܳ t|B3I?ƭ)]-d]hvpcO ;T4{\hCnlc׊n]ic(~S`}w7I:XW^[ǧߣiS>ey%ߕw_t89[OR w#$4hxjNIDbFst~6v76D'\^6sĻdVha֫\ؘueݑhj2Jyk? Ew5nWc*s֓>y`!=rSL؊8~k>3yQMZ(NQK@=hsTw#+!Ui s߰tdWB)X=RR湖VWԙ2I&XO\3֫?,NVl=NhLtX:qx?et+<šT9 Q4gNt]~ٮ@Z_fuo-V |bF?J4b¯ uEIc躭h$WAoiw)c~M!vՈ` *."Aiv+p@^p 58RG,E$ ,=]/ UM4)lujT;HE]wkۍPԓTWŌgq־}.reS 5m>NU6Q"Chd1S$tS,Bܭֳ4n^y珡R-RfbRڣk}{F}1Y܂UjՍΒm%bWc\x1R&^}>h{`kzn#U9&DbUY$ ⵌݵ%{#=AZ%<Z\0sΥK>^irM+ðIj$W; 3w WD M]ZͲT\m4  MtіD7hązr,t_1䶟&Ov :5R0;ȼ}:fM;۷);UƫÛHFɸ]霈̌ZĎiN-9#Il^OXd'^JIuA~e0>4PԭqMFDUJ>Bw2-+{{-[g+[{*ĉq-;~9`)57[r+Ldeʩn#//EdbH$3iO ;bE#85mi.vUmUC}0ճ ElEy]1ɐsT9hsD[xS=a@ϊ 'KzZii){(5P'O@1vV xjx +yo&p!=k5^]ECM1Md5imxcDXfehx.Նg{wlej>Z+3j@!uB1뚜w"/ۻd}8/cLS4w5QGUwNK[) 8xKgXV7QNxwH> .KxIOOdL;-`=ۣaӚ5ϙJzzVw$4C~QG7&0QdŹkj,2^nǙ<1yu֩I)bl#_QLvĪAN>+!j hf=jnJ"ڔU݆q2y9=|Ԣ-9ؽ ړږ0;@FȈpƒP-a\R]dsa\e,frP Taj|Tx)ҟ@.Z@~j=HZQM4P2hN%ZqZ0>+9糊gocPY)Q烏ƠПi2WfٿJZ%C{@vP4COAYOP x֗(ho<2DR@ݛ8CA]ԂJ) ~`nz\zzοJv*⮘|͇#4-Xeҭ|% ӭV)`0+Ƚ eiX(-XM3Dz ޛQ2%rz6)s1흪Ygަ& \* Mƍe|V/ [VZ:Y8Q8?Ω5ūƶC+Twbw:&\; {b $=@}JP)Zl'k@#[@bqZlz|QR [Z `G=*q21P; wNScCG&IcaOCWyE蹨 Iu+e$Y{j39!b1g&رFVIw?•qrIj_>b`m[#\8jĄEe}0(vIq+K!7SPd5-qߡ"h~δSIY%PX L I ؞L;=o=-,x-@:6t\o{ƷK!FS2=87ѵDzsa;~h\W k(Dj򦙓mN:2V{[eFDXl^lw=U$[xL:˲YɍW'2M}D*8zשVcUfUmX~yn4[MKfWɭ6mrȒK~Amr2Q#S%+hi^+yI\JiV-[4rE"H`Qbjf1 BkT{Ss>w \ -nZi%4R`gNO3P^x'֞kא2߉ӂݢ&zqTOj:uSVAI &MbzͶ>7a>+s^8F8KWJcw2T5&tv¥veMC,JV Oݐ~u"ݚ٫Lw=3Yw9izlwv)*O;iDotMK#6sSS(bW~-⠃j}%*O3y^[l:djAi ).dqTqU@wu SC:m5#gxҰ'3iJ$I#BČW)M 2ď3bܽ8u/en0ݜ7ρ>?YnB-[^Gkݲ{jk6QJF9vQk0[_LG&MXӮ u:P;H*+T_W8˖ǎ3zS}mB7#ae U \zD$>[{5ԟ)-i>WԜc*8<H=è:ܝA%sS&&5Nw$-p>b C_Y 9e?>zJauWm#ZkYhy=UH/h;o8E^I/>C gyh\"mGOKi$>NTKIt廽ag$.'_:jG/}[:K+vs,ŘԜ_|-WMY .ȒKuVqswn{F=Lnɩf٥-6E ^ߥ?"%D?Yr.F}%i6Ԭع_)G?%r+#IҐH(V'4O# )'V\u|i2RBD֒fnq*qEI)FɝcÒ.o,$ޕ ׁm DzE^B\fdXv]e+5_r2~߶Mմ05Bݰm`db0/xe  ]cy۩k8Q{Ӽ|8:ۺ9) HIGҮ/ԖaFx\yǞ#~l4b':nh&HHX簎S[mr9faL~R~+ZF 9E%Ǡ43 5V-3/t8%)(otr;M]uU"൛d(~Kii?5б 383]LU9|5:ȭU}E. t{غ{sU^t?4N>I1Y BxOLו@vp*B85TU[YOTpsRJu1yԖ~11^՝%=KE$gmg]8Oͳ埥gSq:;OY~)dCZv}MU({\sM{|4%A݇]d~ućkSXUss\1Mq^-l_kVozd#') f0M ð:XX1JC Yzj}1! ީkܯ߄~kcUQ3'=yJFzʰ^#EL+7NHdk\>4Sk>=Zt:Ŕ@I?PEF!4 $a7AKJF)sN {@~u"ަ3M0ʕtj88#v+,rCl4(ɋpe+#FQѫ%nd~iEGZ8cQqak0?u5"'p,l"l˸Q XƠ<-<y5I!I斚MP Z̐֞KI)(  P/~#x~˩uRL:M$v2Ɨ,ÔҴ׎qQ=1Ozz w}5'ң%J!ӇJ(.){R} ltgAQS*;ՇP&d~ӯM!E 8YYT,nL'NZ}W@h` " s=Iq,k!AQiH9ʭ!}+Qvhƙq1ImZUΗyh}1OK]vYV ݾ9q&:$j:qgSh?_ڡAFg0˴sHÌ#h?Nn}Y=4̭bsHJg*~\+5cټlx =^1V5;KqgE3퓞3tkG ~+Ilђ'fd|R4dT\0''x=b৆$i-7w'Q@ :≨5LsFk7f^\y"(I1{UFiGȷf4`&gJWݮ|Skl;?MKO0w8I'ArC,Չ5`#ƚM&i]FIF<˨ca]z_GO3PQ]M|iW6QҊy:HEbyҠke?u8]S f(ɧ#7(Ϧi F2M7J> UE>'+}LҎCREӥJ`h `TVJ)0.BZUhz*YC ).Fv&[mGc ?sP<ߍWT~b9E v6/c5RXbqFV/RUK -QMENtWds/;bh0psvyRFk`mF?qKiKnjĸAO2r:]kJ~R=qw 2?9ⷚ%6͜𧋛e,2JlTKļr桶$ ٠A/I^%,tc)D[NcdR,w 9o4\s-?+JY}Npj핖Y.ODOcgkO׺gǘ dm1X\ ܖ%Q'^xBF:PO50䵸W'k Yj"f5iۈ-)[ƪJ[Q-=5(Ğ'5dci  RYhg~솤[?,fFEFqY0j T ?<@jڣ)^/s3UPzTmT:1;:,>%ݻl~c QIcAw9} ~C\K38k}Ұy]0BG|c޹Cq̆8)THG@FcO(D2pFk:?ɍK9CxԤSsڡ­>0s:ɒ1\DWw0bҶNk*~;,?ZiN[_hۼ[I Ƌh".4A-m]C(\K*~=J-ZmoSc?Rz?NzmX!ǚ7ry㹮5X+,1cҸu }?`=t \-ϤN7VEwEZiv?H#Ӯ&Rːpq]N6ӼIbC5JkE sR+Zy]ʧ%l\xoYϛ](ⳤ#V)ǹ;iҡ*J3G4RfSM4JQր=;we̚]U_߇eč忨!zOvSlRƚp)SbMbqֺ`zh`kBP52m`AGJ{[6aRG| oJѳm.w*>'RQdF"K:=:1:-XFOZPiL\;sJi3R0M4 l6)X51h%-ң(T qJMr Pт*l)6@ϊ"\w5x8'sr97t~5jHRSHcSҁ=Vx /=i< 斀.CdHU94}|vZj.(E/NkcG?褒 YOp?vAWcY2ʡsYUbʏ+}JΎUV{ W;^;֝q3e`nٱEż*Vj7l;Vf]Pj G'ڣ߰\uslp[ó7͏=)LvR,z-xR5L\S]vR+~TiC@x NiI]ɴuъ.&/К]AhhX0C=#|m"UȪHZAlU>/t>ݩۇkN?p-XX(ffWՋGiCҚf29wֹ,Ra5ĵYΰh֧'gR7-:/gs+u**(5"'%?o ly3): 5qbnr*ŵ ?[6_fhhu(9j#x'SF(8z"Ve\W@?ʑuq$ZGB^/Kgy!}JU(!G<B Rs _U9o[v8ES}qkLO?fB=c$*iA$#ͨڛ9\O&flF CXmƛbO0uS^&Kӥex3k 84J4iMs" JpV눅x$O֧3NY4Z8&GsŪFi&GLTin=NAUsD5jM*ݺqDMXri}q\GyR;K27F?p= snb?27N[c=*]'?᫦SdR\zPyZL'(z̬pqB795~ŲN8UhR0O0̣SS{qEi2_Ee:{X|2ySo&2{V1&V?TrmqG+lWHWGhtݑʌ6F86ܣ $"Nm i˨\ۀy\fG` Tqu5Bc];6˫g[YI¢[ư9*R q3Yk5'ғ4J^S][,QGeU{7Ia-D%ۅx1T"t4Y GVksĤ}'4\Si>v8Aw3,p#qn>rEm)F%9~R>{V[Diʣ]F}?Z2jx)CR]cVaOvx %Ȫih{U5}bI.&y 4Gc^j1֬#Fb}+h$N6Q[IIe"Ƭ-E aAqUОfXzavzi=ƊCARVHқӔH~ ,EҬ *r)2pN)¤֚)F-ߎ)7Ѹ3NBJ\ ȇ8=pGDp}h^ |ڲֵ%2S}iiusp% xr^1Z˘/1|~=ks(W/x gn wǧyW?UVKzKW1Q3p"j䪺=j/v#xcfwK$-㤋Pi5${yP8*MTu1R.>ӰVKk.{NW}B77S(7P/#{ Tй[kwh QGqynF/c1a@z{`־iZ:[PK%2a> Z"J#d~ iA#z?Jvox:{{ ${ӴmksgXqQE(sHVX|E<ˏ}<SI}^i$qO SoN/N>Ntsk6W16zqWվM`Gm¥U{6S ^ hj7?yc`k&UԴ#v}q\ )4,}2G7Lf9Ew2WӮmxՐtSg?]7Fͧu WvY9m6MY\2[\[7`{6UjnH[شs Gql 6?]tR0G~)<-Fiѫ@)DWЭU{.%W,xl^wz\дM'mUVib9SOB-[q^\ҡʻpjf+=~jPu:;<C^ t-%x`UԩFpkM5VkK85ڸkxcrN5ȇ獗1][O0yUl1I䵶⪾d:[jh'*=^*6:ST z$>Ҙ@C6E\gI!js֝\&?`rNrW4vX#xN=n[xF][4!`lҚK۱Iӓ;R `,2=+sN2.]#⅗h;b2FQU"vDZցrFB0ά3ڕSid 댊l`rYWP`7:Ed?)lq|.H/!J|7 6g&|+7}-Ƥ'+{zR\y?1J~ul{](uy\ +t)gqH4a) R)V K느ubTz5CiyXчC,,~x@>Ċ+Sķ BGZ/jVvӰT v!s.~hѿ -ه-2YTwecu%hKF/){tdI* lu$ L `+*GjrCGv5%N]6W!Z=T5j=N6ND~x[:U$Y!;sU]Q13LaOi`46sA}ipjg"b&X)֘9*F(4GZpH qRdfc})Y)EDXqF[ҦhwdTT@]KȪ;V<ԎkrMiZuimC=rӤm_)vmt"[93 axu1/їʷq؃MNBG+.zuUUd p(V#ZIV_)1]F/ΈyAvR*HN>-[\/ VòW }HU"+3ГENtiqd_) 8A<LRm_Z(ǵ; 6z\8i&0߸x=S}3?*.AD +yF=hewm83oR:@JK|=qMsN*H=8$*Mn6n8**i\0e/vy8z F 2.1&UVztR[I~<ݣ隴`KSSy̠xOF@};i'{UQGVVf{p:ZQ2[Ƕ+q+F9Xp@k>(|rINFQtX[} OoSG. e\JIvzӺq@ 7V,ܶBKGb9B+9KDi\H-d|zZP4\Ǭk.wӕv" ylҭ*MؖoSRCM$SaU 89F㽋 @B*R]3t!'Z(Mp q4ѩM&HͳVYTl.+8kZ'C*)C(&5v LJ3T*X5)]S?C*aSaqKjFY* vV$ OR֣oҞiBݩtQj] '(L;f?(KzW][vÊK1kqmp9zʽvG|9*66> v^9%1Z6z}r(i2^iL8?LUd9?Ҭ2I3WPvk(8=jsz"rV^ uc7m*jP:Lt mbymb7O b5 oּڕ-!8(q8L.\`V\^1C]nGcKZƴ SMy ~*iˬʟ~#J+pEC%$9ZWOtG}ǭ!ŗ*z/:ƭ͠YI MRs0*./}z$g6@zW?/bcuk_ZQ{1YyV@t   rkq$@Ab/4rHWGG@[R)^$*z-9f|5jrRQT𼋓ߎ?taBk$.Tqh7cf=^v*JBĦx5J%xpAJ7gشrEOy4K9MfUQr̒5?HyªK^&v:8*ԚuC}7SzwLVE.)@t M)LW`( V>U=hbaTu5gaI~TL`Y&*pjy*bA=b7Q֫30F KzsRp(5 (HEإMaiރVCL֝#H@AK`GZkzzV<z-!X# jTV[B ^1N+p8=! NG^*r*JjkQ1\GU%9*)O*jWD`~iiH-M.F1LB1e1 ̹籩cy`UfṳSK uk2 [EfIZS u 'ՐzU485j3RƉU *J͝Jhzk1kVfo*[&{; LjyMnd+Cjs mqȭc+6G͔| ܽFQ u+ϼJꞻ \\^pAwmYw@]k9'q忈b[XW37R|>e :81R]K{ X{4\s9NO6?%m&Ķ}d9=5vRHc,."t>.v}+H-.c)mc(u-T˧ᵰwN"FpOңke)sˎ:qg fC#J~xțXMc8{FvU;@'8ċNđ< >~J0OQ)rs=@4>Um8s;yuĒ3!%ܒ5$uWIwRsmnyQZZ=r8Ժ<쑗qSI/g%H0?η$^+FzVEƃ@%/k&NȡIZI!F3TԑX=(Lc4]C|t!OZM6vLTUƟΛO"E+ CMRiyL5,Kf]Zqt~sVğZTW˸f*J!8&KL4f})i +FiS46QLDs}ZVVkNBt)iݩYOFSQң)F|Ru顆kJۤ˖0yȖ9!ajGPMB>V]H8¤v7ethy|d'Z*f@yX+b`9AJpf&ՄA[}Ո0>RdC3J ) 3rv) z5fUsV\ Ld?ך uSf jغC]j"8Hn>T}-ĄztE`Cշ޴~!MJޕx _GFrͼ\բ4?chX4y{qwSd:GyS>l*]G׸U 5, <|Ү>b׃Lya5!olsqS}` w8|䢁Ն)$+K ӷ?Q1 m|8NkX~bzj]d& r+2: ? IrDWBOϏSC{a4mrBGN]y1Ϙ:'v%dR;kaF[o>>dC52.wI*TZlG̅[hu4yP\(~/7~=NmFm 7] 4cOq>B?H$nވijPYh`T!mZ\U6i> ⱎLaZ{',^YgiuԝBeZ,mwg]*uΧ\0W drCDͧĂI<(#<4<,$|vb Āqj_iV5ݐ8CװpAU9hQisjLYYE,1Vk۲ W5S3N,ѾjiWpY#mqhg&6_pKY^/4_vBzpGq>EԒvg֥%(RFv:/-k|O+{:nd {v}iYopM9)TSRR Sڢn*)1mxOtҹNkO+YL`.8zj+>d)Kf#ٔQ@ @=MiJ"$*4 {I4'TRQHES)՚ӳR1Y}ѳ?.x) sF?~x407Ҙ~*U- Yז*`=*?P@[,g4"4g>3"Տ˃4EHmalZEẺOLeu@sG(YF niEl֖?r~ R0U#Q n?⨵L bd1ӛ֦EK~}W#JJIӃ NKC8l,Cg(N+0pG'صV]N&AX{Ԁ 6;zTWМR¾Yu;0i<!.@UAlI Nk7R8<\QYj9ahbq rToVrBLqE;̍ *]#4* Q Gzx׹h %G5 ISềJ'h ShvR=)|1ɊVQYP*#?:5fdENbҪd zs]YhK ؿ!F*DX}(?UJDP1To1#}jZMJloοR.9oU)}D$mE}쏥XZj>ɾe-[ZdGeS2䟭ri\!q}ŽIk\}k98QB\*rjm'OHB7b/N-"|+NV\ќ7-7Jº]nk硩U6+Ӂ"0iz}Ӛĕ$W"'\:;@d6>./p78Dt hyðjtFO#y|mY Z麲XQƮ;SO5ٝ}q&01&ZO±q5&#B{3W?MJ`9wD+ QxV{2!Zf4W=rUGsǨ=؝RX%e>ZlM| -!g 85@67pOl&p`Dcvh-7}PLEI>VPMH$<W>|P}*[N , 6"t?t#TFŔ5|n!>^Z%IeyLMMKFV/ӬQfE6 wL,i\w zv4B:,h07 =3\ĎOZkEg'[hz}4ȋ\2jzM<U)De=jy!ؾyuGܛkW<AH,QH{)֮-e=T t3ːr0;+We[k'kHہ qTMd\E!\sW)gy>UF(qVj% “%5R= Ƣw]X?Q,\g'Cm"DVZϑ^vYYp$k0-1V ,cGҤ'kWFXf\`|y51@.YAm-\y #QYo"N3Vv6#,h"!? l+Mkvͻ6M5wpLZ>I{~uN@mJ$d.G+!7o ?:_FF _/kmfsڭ7-![<ݭܶbHEz8HnDp+}ΨǐyQ['bZ*:u9xLzHpW9}뢏 ᮶:`V£ZTkYt,w^Q({Ri(o~WNI֞?Zc 4RJ &h9V%Ug?=*8eUZnzQ5MfE,srj,;9_i)Ɛ0 ְmOZCQ~`"]4r 62NjO1ZG; j1a`t52D+\U뎿GpFhOQ4J%xAO,u!tHn'+Ԛ7W_P@M]V3!hW*c!%~+7-UGuo'ܙS z sVhcw_5ve*ʁZ jN*"Y<ƴEžx6,SSيɘɠGkZZ "kB 8)nd$B/Ү)T#2疪UNjC8!ҦG&)P{hP0cҗ<ӈ(j6c=֊7ꢌbK`8y_<{t\nc;=+T_)Z+?RBTƟi=ӗ(}*TL*żtt\H]zVO\;(84c.Q<zSi+>%1bGP$˓֯ 8qU5Wnmga ,3ӞaCX"ț!6Ījc07n\8ף`6ykm$sI]Tr3 Մzzyr>I UᵼX%AXr3ҸGmyw( C]M Ƕ6}R}LwV)"U>`G ^UK$ݩlo*$mBde'_jt[aԾp>򩔛U<"hJ9~4l2U [KHed#VzRZK#X<,*Sص&.̑ `le/.p Jӑ<7{"g@NsKhO]ON(WOf%zA`6v\ JIК|Yi-Iikwkr[泊PO4M7mnM RV&ޥYwy\0ZF[ϭs(oz|%Zjrc?iZԒͲꍏ\^[3`V7ishuM 3uEyP(.Hg]p u"kTV߃䕤[,I%SRE`U vsI[f&7> 9 ; Rd񶤤n\wjyh 㑸cԺٍrழԂB~1krrHcpM&T*5.zk\ Gvo~M +zczt>-!i(9>j#,$S4!׊LSrMRUzd- F9ҝژ>QҲ0Si\1PGNPι6)Ea3 ֡6uk*qBqY;u _JhO̟,E\D!XY׆QD>ѾMlpOhh4DV6ܣG05Y.dψZ#ZDwdeEީ]x~#2\g֌& ocWE $MRWgbd|ZJȿ#ْQʁU9tݔU:і AZj3Ү6y 7CQ2=@"[0MW>@OY W"lҘ4kWGAB)E!\j{TMnõZh&E3n8;\RTi ӸGѵsҜW&o 1Ftj~ S[vH)G ~}4lC`zsK RKo% .rY= XMbBPɝ:Xѵ&Ѿ:e{I#P~(>+ 5)bȤ卲Y2UN4W+sV75bz|E*GLԉq*}jŏ[C+欦jx9.)&l&::n?RM)x#֧Rr5O4{9#x5,dRm(1EL|hG(e=RwS4h#Ҏ4#nbl֧ƽ'ȷ5[Y1alvu6lM1V"l+;l J9.j9C*r-JEyb?5; r f;u +1 9?0&KFb{UkvEMLgi"z vtM]NjwLrf#j%,ctšԐ few+QO>N7ȸOX[դ TخMpL4_iQ(ҷmw#mμ0޶挝䌹d:EͳnJ)kdn^!)5xрƒs IKgTqE_鿐G)q``YTfLIXliaI GzXd:piF֓G)U7+F|} `P=Ɣ&]Q7kRy@o[[ zr0v`j ;j̭/ FTDѷeGz}ǃu8#.#Y16k@NkWʺAp"Urq)FG^iV #'qёڽ{SI)Jrï?Zù}&X$\~E)i$MN3joK 8`s75xVUʘd>rz~U+&h.ifIލњ.$iwTy,IT{ .iiԹ D]ِ] GC\oWGns + 뚍j[ b;RRaKQ'HEu5r-BN%Юdˬ!^].o)"?(ᾆ*Sf{9WSPC%=p OJҗGV`uU"mh3Ԏq5zmTM<5h̗@ڣ1zUspĩ X_ƫeZMðk_J|鋔Mp0b-9X )iⰢ_QQ]Ɲ6GCsF(#8i A4jS&GJ5 S,H:,.IS$QPՋ 4&t$U M6뎧5 9F=Qr~n=qCXsMpt nB䎚=V/ՄCє>izӉqw:?txy-J:o.+=i֭ZњRY%oZ= {l$_ѹVqkr^j:ZPhY-T ] ;T*X'ƍxNPR3jejWz3~\19ȧ8䏹abDOF8e(q-nO|uR2EܤSL +ӚȺP qtmzЃ~<8pTm(#ms '9zUwaF=1)?{ l8"k. }*G^j]-r}iwC{rK ĺӮNUK𨌜HAP y xoB+u"Iթ5\587jd8fgANDn5iA%!bxvݫnH,EdW.:6L̷ qă"-kEՆx8=ϭ&CJKf[%KH⨚Hk6ZAFi3EIBџZ@;4f(٤&ڐ4M&1 tv oǚE)fkR}8Q7X&у)MDwV}S?Z`5枓ܑoٕ;fM :ծPrC}EYZ%БJfߜ?/ԭdySjȍ]On nRh{U$m_ʟcV)IlM} BudղáyU]IGG[7Y>£'&Ћ+ڲߕWgi<H._7rl[Eip1R4&T5Se8H"ؗisUenTM3K5b@isQ斋Iڛ3@v4b4@ G8i3Fhɠ iIBk~glmXUܞEB9nzQ lX(&R3A(?ާk E%!4PU TkHlD t]E 'b*X›CE25t⬤[(VGVT 8@HzV)[`_r8=#8yќ1)qq =OLmvq>j_!$F>?t3ۆ%ܮHAnS9B Ƌ3YFyOqM6בr#sQydȧ .##i=( rnIv{gex&ljuҬ_9淆OqQA$CڊSHiRZ;P!tJ(*y;Jj ~a5ZҒ5$\Pi8~"I"ƟjXIJ>VM>Hj GBjIm?= BmV\wժϪ*9ϵIbe)kw>VQ&k/ETĞFfyh0~n [B)Yj?#N=_b[TmnGJ.%ϸFZ&ɲ*v>@~4Z7 )w)VҢkzjh\,sIU5jaXPH4Ҵ\Vb3ڤWLS';OL f2(>ojZanJhLU#_/-;TrMs72Fί`im?hDT]. =>bqU꣱)hPSXeM>3d۞*k,3ҵ[ƀhf="n`VȬ-nqOqݝ:6x7!1ʜlf_`ҹ' 1vCb>qiZ4x&Ǯ*Xq@5Z}=57cr?x[zI9tD?j?&ZdE@0xnߕB0}!Qkn;{JmnF. Sjp2ҳqi쌌 W9G=Z ֦y)ZdԨyO~vX]Zp1<̇fI~>ʹ$8B.ۏ4m:T@a=b +CQ#ҵ^1Q\/?@҈x? i xE89?A#iW&#Y#z{ßzԳ3j#]+bRS֐;LQE=@ IiM;Rt)CFzR/JVw.:}EX]QH՛|'D`痥*1 P.PRv5 z?N*P;p|zMZ.acȵ[ozւQ*" B)sNAmd }*x)XV$Sðժ]IqF+ʶꉤ tS 7}U_T.N:.Z#)?GmUOUeR\t#qbMRP5?tZ{1Y"65)>$??jɲ+S J&RFA.S?o4kpMC,;A5!4:=q2&&#޴cYpiBr J>JӵZj)D%QP)pQ"cjE6fJz.j8;uHt^2 bϵڬD84OJϽ.HvCRD=9[&PSiHqZ1ݢ]22p0jHqRpL|H/,x R_浸DZ|IT3[jKl;lWoQh[%Rު[`n.o:O楧 vmgqSnh6>E̒CU櫘>՟T+:SPi6 t_nMsjSb=iEeA_S5m')0+5kV#Yxɭa JQNHՒSiJvpҤYpFej{RC/}: WZfqj!SΒZȱ2tS$`ʜҙ9<)ELs&. (oHLVQdl3&8d o"F㸭I]I؅1[2q^O99v>s}MN!)(=h4b CJir|rEOh?uK(TE϶#ZҪCܘ5r% <皈WҞNEIDԙ@ ZZF(X*蘼DFUNz<Ug]yCZAqOjQ8a=] 5Zcw+F97ÕZLVGbll O W#'NiKTTt%#"j|TP*Pޤy⣽&*H.(BF~)1@ ";qVqM0AQ25 d y JfQ@'h3Q T 0hCcjHӣLNN<H({Ӄh;,=3{'C't :NFtm5ǥFn.hX\V|7BF#"֛~/d1֤'1N)ۿ[~Tҏ޵Ϡ5.ށ0e+ Q+ZdEwԔ"4Yrں?`j@οu:G<ԱԫpT7Jz=M(>b\ETT4zFԠ&zh[ le rfcxpZ/RZRKQI1m?*ґE*["1!TT\pXҊm-0GcH.i Hz~1ՈCIKڛhIKHi^Ufн?rkhlC%@%cŠnqUa\SWV7^VD`=.[TJ-~"{OY~IY4ry)jM4I2e}*s^՝})A+W{B g4+) wsqxơ]Zӻ- ?2>Ԧ(1jߑ\1ԏ͍K- 2yqC\.iAwDMV @k ~{VVQsZw*ı鴴HwښiNv44J(AE%%)4-"я:!2C>՟R%bך`0i\cTlejtNTEJ1(2;tmuءSɨր}(AҔuR^(iZSҐu4v ҀyzP1/JҀ⡏/ZҐ}\qH(ր>9fh=qLtYpH)i:ʃdu SncRfjH'^AQe*w}= ~U@֗ h @:i !GZZ\S)@ F)izHGz.)qM;X}V[r?S9q5v j?ރIG4yFSQޑPi: 'JSM'&,=6kW&:\lީ]ڥC㿩+Urs qH~^"⪼0 4KMnh["1w2lf!`qV2cDa2I۸aՔym= K-ʘ<ҿqV2p3ɴC #j`W?X2.K%jrn^C`q4}"جQQH(x1TjgW0Sj7%^bp̺â/b.$_F۝B;Ėʍ+·`F,QG*ٱ:fVSбv#j֤rOZD>4iiSO:imJ()4RJ>PM!A 4( 4 ˏi1P\#:ګܜ/{O`VuS籭2*[p*Z Ԣ`n:r.NGZv@lx5 5ї)U-8riNH=)47Lin :P:P(?xJB)C"nQ`OTa5s,4$$1HzQN"JKڣa4!G4|Ԡz(:SH#Km@yڰPaҘQJTJ*Ų,Uz zdOlU5hI,gTtĀ~4:1( P`:fH1EH yt= DAEr\~*W٬#IΊS3Ü{քzʰѫjVy|jd1YEDl}86"m>kIj7rEG#[1kc؁߭>-I45F=jйӯP)=->5rSuY_浹ǶsP5lxD.\f5o3hshϱȡu 2ߊ/X4.ehb$B7WW`=#4ua"QWl5VgXcZD@jB6|\ZI'4؝y0ix,ҡ=)+[rt#Ү=ЖV5\q+8&{kmZ̙*hvjTv!T2E^K'>^jjIbVwC /-&/>DTⲣ7Ԍ&MRcJ) oeHIޝhn%Rr*’V`d慗oI{OlvRXc@i,?xk'Na84u԰kXESn''T\GǑOpACtjđ%&zoJ5SEruԆQ;4Ѐm{QLAHiM4ZC@EGj`!O % {7QΙǥ3HpMJCsxS\R)ЊVys=*l3QݧFSL֯tFqңLpR @hBGzKIM4H{ӁFgHCN*@ȤϮ %!4aR)R")N1N@f' Mܸ=A:iG?pi OAd~YUpI" 0f HHcZcF m>1u =T}>[VA拁W0 L7܊~Z#_˺4_Z,nk?oґ!7Sæҍc‹Ej-\EOZ1U]\fRwIߚ24Ӎ6h) 6ihEojTA)QždQj0˚@OM404I*EV֧w“ޢ9TppiR{"8nO֠+phaܜ#?L>:sEڠߚ&qE&(4A@1iaS 0#jqQM()RqLGJ])iZҗplsEu Jzfi5=hnJM ғ0sJO@ j 951S獠SBd zUAqj|qKK 9 O(K1%%(h(b )h`ъZ '4vsփ:I"v\0h^h"+].cOD?0"̼担@H9Yr~5]70hZz: Q?J}|CjDsP'Z nzyQՐPE%) ( ZJZ r"VĖvEGDI8oԿ1g[wI<6,(T 2֝K S(ox$߫4mcAWfP~t.>C> [D^rWWT bg?2MJq]Lavֆ5PYJs [?Jʺ vnۓXf=b7$ wp{eَ&H[DtuRGq5(17mKA*f׮=fI)^ h-ޤpZl>K=@B` Ṛ5oDfj2ұn>}kZm:ڀPM!4Pi)M6A!aj#SB>LY#WSU`Y B}4-)|Dn]p*)ziRpTpZ(=jE \fErE<`֔|ƀSP0iԤ(6)r2 4^WM C@ɷLRuvj\>/CJH5FA!4S8Թ?Z@.)6 7z҆H=7.i(q׭)"ҀJ>J7٠QӚRC78jaQOƚp*qZ^ؑ9Ȭ Ni1?Zv8-0x*S=(;H@=1K֐)1RBqLDc=qKϵ>89Fz ՘mA~}hTbU; (hOIM3cTԳlvry.ت:Z"O]cBuBEc:D@q:J!y[7=*@T89gYbbYO*92I|{v$w8Χ-Ph/T- Q픟 WRnaڴde<ƫ#$mʒe=+f;i2=Fvғka|S޶d'jc(;\>Vg1ĉF1?:{ʣ爑9|c U#M槃PWeQUs4GluYb稡'-cFV_/:1E %)&CL@i(4@M0 :U0?sޚIa ARI0E9 lDmI~cd*ǗSX`KH5#*%#5 40M~ƖpfD;IڊGgRT2.ߙjD`@R vFA))(v4#ޘy$)sQhdS?Z;EE.@#=E6q hL<>iHU[ݳVؑp vn8mE+gҒ("(F (}i1r jb-S$AyS*gR.D) qS❊r0Rg;AhISJa^S8𧥀LQ~(H 9$s C 4jV=χc|OO"KDC4'_ZIX⮬崗˕pj5vZԱY c5], /uf;Ǔ*:P s|=).O_ʭG{*9Z*蕭<qdFhfLh3^Ң(گ94=j&*JP,:SGzі*iH%NMF;Ԕ8μFӜ'$ih@st56zFAdQQJ.(-Ҋ)i:Q@ I )i( ]ø>0qL3JiҀ!'qV#oWl{5,gU2QIȧ W9RZP9~$>_v  ܞNA*π OT Ү!Q#ҥ2G,!TqO~U0bSJ1K~]u!s֔E.* 9> A-$V\s~CU0~idvN/Mw)}j)ݑi9<7QI.5L5HF@ѫ 0P`jBbcm ( =SMXnLi2`]愚lJ{4\R9q4~5zy% q T;j8?-`պxS fosݛOb:)JP+ 6N􆖊bi)iƛ@7;48Ky5iEitq1@6y\Ӽ񎆣hudnzMc?';t]OB)g5Xq(2QE@Hc-!E !_JZRh B ȩMe 0E0}*1Oa4X zQLzRh`E81hJ3@ MwRf4Q@NtB)&85B:>P3ގZ))Ê@'JM.=)q!A' S*w4-3Xq*[K'81hl(RAPaXi#mr+B H?N:ܸ-.j@ʑ\eH4!4J!I7uF?F$#vgO||@nV/?8|&}i 9o@5YL Wo1:SXF5HO88̀E;:g*tOQ+YAS}銛YmZ.z j7sҩM8H̤TEOzZ0j*0kEWJJ5YF+U$%b1S1¥WVj/J,; U* R\x"0=h$1U]pE[vf94И֒< p\UZFhPIK@PEPEP_ƒ&4kgORX$s WyԾ1 h;NRIJ凚wvbhu[dTr 8{թbqe -k ꆪ%m>v}(u>NHbdR޶Off&Tc-ڢ9"yߥUDI2LYT~09PX V˃RT[žP#(wJWG'' 4{" w7XҹNdooHOJs'޹7Z(bi֚hvA44:QE1iBiԔ)i!4=zINF2(1b3FAEi7:PhVc%^Xw-Z>ƞCJrTB:ӄ}E+SCg .}hH< vIcASCh>q4yԄ4h{*áր_Ƣ`P(ϭ3FM?>SzӲ)XS׮*#LyQ74ЙҏJLzSW9P(\Pyސ֧ݾvSTef<'5Uܑ'Ү+ssC4ҨI,O@7NȒHX(;;IdnzӥW"Tl0O6/E1SlVlUwz՘;Fy4Gshf]g{3a=o#}V noNYns(,DZs.84cOAj 8QGp1IC=Ui#*+b4i@.$TSlzAXfozU SC QM]nK [8ӾsS;&nHSNɊtP* I1.B8dOqRInqDcL9xVpn^V'ϭLb:␼}  2[yj ^v.}7g2[gR+jÐ h4Km6&p}ʿxc4qhŽhsXr~D\(U"D*EQf(ӊ(4@75A"Z(N(JME;m}Sջ+m͐[W"mm#\(a"@0)596{RKY&H m<P(+h` NQɥpP{jB8b01R+Q[U)l't@s{TRƨͤHۇZ)O+Es1ɃjޗbIg 5F,Ҷӵ9/Pk,} ۸PJ5-!t[M4M=h(?ZZCby֎iM ڐJSM45 qwZ zpi=ih4 LRC:P!(4((!PE $piB2(r{R v?.=<1G4&F 3q4y(%HPq@"x֛JzsE3 tl}iM*7#֔zRd␂9hqBE(47wHq@ ZC81/z==BsN9W=ŠZ@'>'4S4Q@ уڗh4i ӆif֊ju%Q@QK@-!~GCO{L#(qߊp>`% j<v:s@$yoPfEO7N(U'ITe^n>\1. ij1D ɬ$%Ӑ@صx"NϲZBaVR5.)4PrVm歸uPm_*noZee@s+>kT5e|fO 6XRAǁ¥B/ vAʳL^;SE9Uwh62*l4y aSRCD>Z%jUp9M (sIKBЋ3d׮=&C }sS߅nqޟƵd6RC1bXac*[6<`TbA*SSLB8.Wf&,n&j)X3JM+"G7\簪wY!Kc4]\c,Ma\KM7=ɲ6>GqҴ1YIYj7/5#~Q<.=iQ~QEr'&EJ> C%ct 3W +mr^I֍ѦZ6ֱ@Ur>zDvL.wzQ5f\2v )-t, B`b'NU].Yp|ҵlPF}jwurI ==Ҥi>5wea>,?I>ȃa%pj6Ȭ2;1Uw| T$RdJNzEfP`Kcgk8HQk1cB[ΆL\%2]"ƈP)\j;')CՍ?T('֠J#\Z-4%q$֗Orlκ# 3V2FO?&03U-r:ƥSɥvp}tL*|bǎ=ʞUGF~aٔ!RF2UT =jmϽ>p)˒ާ qÐ~n)7pH]FiiLfN(@Kș5ZHbCO[8#8xUVDb5ڞxZLsRB*K(@r8Nm.)h))֌`uPΜ*12jLҍAIh9ZJBz^֌޴uuH@=h{`0ӀғacuEh@ E-%0 (h1HE.}h=)()S<E<Ƙ9h\7sVl&Z6|p>`(ˢ)GV^}jY%HWs0Zp.{g|zRQoV6h]ĈxJ8g8'=͎a$JۍV w䣰;=)!!ܖj(]j@RPGIwH׹!yoJź8m-5i!VQɷ`6^ݶ|j~0=%QICxϭeϥRRh!AOfbiZ{.j],n1!Ehʵ&,E >j&5Ljg. d{⧗]ʹUYwdAN46o(˸UOv(:I*GVBHbF sKAa)ihN)mKqӊ|@ldLsKYRR(3Gj-7t4PbҚNhLd?DSIR*SM}iJQMz9gLdФHJ @қr)RҗACs)iE'"P)G=~qROSw{Px$ ~! QAҌPLE@!4'ACqEaWyjZ?8khlL (AR; u斀RX姹wSS+膑&hRh{PfjHRV3Z#Q#iy^/j2Z(ړm*|PAJciZx4ҵ.)Dc Кbb,4lojLQpޤME z]vсދ蠊((KE h(@EQE%)QE(GJ(F(&8~^=f u$1}?*v]v 2PI#ojKEKmJ}“#R("9R} j\w AGz\b.F=qG֐ޗL!0~/HsN:"Rz@11An)On(uu)4g)zZojQ(4 I)JB3Kӭ!8="sLH9c&GQӹMERNs!n%QLBSK8 Bnoje+‚(cCҳ(BGCGn(+iq#qN(4("sN3GE'ZOjZ␆iP@Z)}h#:Ӹ ǭ5440 NE&=V+4U +T+B+ERzEZhFb5JDدCR RLJ1O&)f0i)@b>6R@ 4ZJ(0 PbZJ*n4(PhY{Sx&R=lJM7<Ҋ8p.iҊp8z'Hbu2ܞ=P?1\S)_(\1A5?ʪ&[3]ֽM8X*X{ֳؘ}絹7OUuGM)i@؍SRS~26aKXz:ujzȻauM1T.zɬt5~.Srŭ4<@8r"~4@CE"RtA0)M > })HhN9hLRRvӭh>7( @ hxJ1&hp(ϭHaȥJ1(9)!(s@ F9I@ zS9J:SH4A/qJG`;wg7N;P):j):Vxz2zSzRX=)4?*`38֛ڞzTdHΗgN޷[uTBe~G Dgۥ['4(:S^+I<ӱ7RSiɥ89=(@ GSN4=iԔv FN:R}iqޝm!!HғڌZ`4~("a8&8Ǯi *)s֦bD*6b=jc=hȨY&D{U\V+HELc"VGJ}&)=(IҘ?IN4S%(@ 1Et❚`49NS֐sKZJ^(A?( *e@*\f]k m5HZQzrQBחoΩSbGRHN)r?:f+ƛF=Xt{WmJ sf)O9*Tr1 r)8vkI3ۓu&⸫CF;JSwLӮ#]PjÐb.\ζ,<Nj;Fjr2(sݨN[-9F(bA/('gG A>PK()֓Nh>9K)(֎hGz)QIHҗ{RNsӊ@wI/'z1FhҁKi\vmO'CҋܰQ⋅n:΍T!Hu#")NhQ K&1P~6 s]|H]ŠEX*;hDi?JRHV4N})HcNsp4s@3wzOŠ.cER:R4hsG=8{P2sgqMb|$1sq'jQ@ B1FphhRH7f*AM0Fhӈ4 0{1Ji hf@40AR=&W(R  4LUBHJqW.}*61XLT)j+LSȤ" %:S%? #ޔ(gxemul-0.6.1/doc/20131109-displayDreamcastMemory.png000644 001750 001750 00000025256 13402411501 022071 0ustar00debugdebug000000 000000 PNG  IHDR/sBIT|dtEXtSoftwaregnome-screenshot> IDATxy]ua-36BXYQJ]nGbm*ڂ]l-"{UeUAְ}̾!! & +/^9̙=;l n| N;.ڗtTҗ_x٪K+K $ڝhLRT`;TմteXzriGVjd 5i*J3?;tgXJ0,^J]g=˞)370kj*ai)/+}Ϸg]T?<:Vn7%N䝯;} Q~̿$ft^礿+T.wcs۴NxeHe657=m8rl5oq:k?>D7]Gk2fH:%yCmyV"mI1a48˚Ϥs v%!M:$gMNJkhʸns>~Wz:tUi~xRMڟ+wdQG-۫cŢڰ"=ugXәO/Ls.ڔc8?{KyebttdҶϝwݛ1{/M=nk3oƲ=X5wT3yysY&=}}Yޝ/5x<7-ݶ"#x:yޕ\{󭏟ZSVs[=*l%DS lfԽ(fu=s^S]52ehG`ٹzҷ|=cG6ߚ{*=}9hIyI5mfλ̜:.ܒJ%^GgȘ=  ұt^z:S[ߘcd)eQQSΚd;u 1iFz;ұt~RԜSJ}ӈ {kGhRoW{,<9?8ϟ\ܺK&4+ǜq{K,Z&J>G>oU.Y1#C'O=&{N}8cI5X \'Iڗ˪Olp5ɋ2?csgCc?έNc7m ̫7僿wDgp{c~ oFc˧7;輜7dR}a23kM_w&8kJ*ui96#'Jw)o6$}ɼuwRS3u6ϻcuV/Tih㧦Ej7nS6ZG5ʇzDF4u59T*5Yyþ9'dʸYbM._e2|颛ޏqg9;sqdDynyr-Y]^tdhE֣Ik?txkn߽.gq?{th;?;&]18rόۘ|[#񯚙/]tsݯ G=]rK~'j[s9G=RSچ Kj[66nvX>2bO{SΚ%f߱՜cg_a[z,̹<=9;m3^.%S2~tK=4-y93Pfe[gny\p}iz`<۵M7g͑7L0:ݽܝ^᭓:20?Ȭ̘26u5Ƈro&cO>hVkݖgfpUo{4Wu]v[{j0&#]폾5|_'*̜Gg^Q|i^[/w_WC3e_֖v_{䑌&)mm7u͍כ-s ,oى"4IfLoى9W.M&Zǵ[;Z$ OޑS_]I cFdμ9kWn>i:k*gH?SHOas/!}{g^9$G7-=iмtV-1 ^hv=OfO6˞?]kt %VzD>#R&49uMi_\޴|_'-;?r=sS7{\[s%SƏ{?i>/f>9 [l^*<\r {Y3T6< }Uudc,\ޖijq{cvXS*5v{ \=9;سKsɯ#Ǩqґytwg}(~8!oޯ%+?O.vXvLcXzWe|ސ:'YV}CUjkSԒiLwfs y?\>.gn6ߟ1=~?\mG逬^6پO[Gw揿xEszlӼW}8~|? Nrq `su>_=Ԛpj#JDzX 'z懷=jӋƦ´[9c_gtK7%w6/I~hs˾GMٶxsu5?|CoL{goιڌ~P;}9{pI/mGO:*wVol{ǒJ͖1yϬx|#og<Ԣ!o} Ylq{/irP&8komON3ϻ"Y S }=ilM>XoVƆ iZhRI_zz6J&u M #Gq'=;_uT*{^$#ϾJM~j|uG&i1-Nݰuym ێOHGWo7}B~{ǟΈә)_rϟ:aT;7mLmDzz_8de{&Ok\j*!m]Sאm?zx.~H.|G؃v/%๐]k2mTmZ,kOz2c:rݴz{W3Ozgk߽1/c$>wH修7eLCsN?0|ΌkZ#}n{傫I3iwt,2޴hyg&p˷NQL; -]՞ںaZwUmz;2a๜s3s긌>,5Ə {C&{3aW_:cǍJf]n˼GMΜykr'O@5[wϽ<:R[ߐ:2i순xf sE% TGcv÷mX%s[^xۗJv-x*g2x4rWhhDzkks3nޖg-Ssʬ8eց族guG[G$Ձ T?M?61.Ec\il"d3Vә*{ǫ$4l9۲-~ӧNΤ#I~گ|p6 4vD&թolɚ%Og=bC[ws_w>_?}vmk뛚LXI2r\|}}،}Uݗ/nc8?#o?2o;zi?uǸmYWkIcGc0@wi}BɥSДg؈1I^ko͝ù+7e[ic=.{2_2i<`yb/闯Hqtf?Tuh___*FOȊJk{HGWO;s=OCpqVUZ8jvv_zo<,7f#d X{(i͏n{$7jqn}ly~pig?t<`ZN%7 ~tIGetKS755,{oݰ]4xqĬCH׼nJO3Ҏe|{$u@}VyfSӲ&" Y$; bmjwX( ?}<-yi_o'IGlN5=dt^M汹;Plz=mnԑLw[k>yM%#&HR[?9}3=rHM&]yt<:wIj5O92&S 竗ߑWܙ'/\}o{V,}pxrQ_et-Ұ6kԽŋnO=:u-_w_ro2gъݿ,GoyUX9yqmo:$55Oesg>Ǘ;|\3ϧ7;M},$ɹ߻9G+E˜2kJMKWkޚlZ\(䎎uL~{mu;;?ڻސ}.3hƆ}d[jj.vo|?%?Ѭh6}pwka3zλy\uý9m~'o <>?߼N/=sտOxU.y+vz|g?2QݗLk뇥~\r9m:&_=3}iַK7d7eQYbM͹=u54Pomϑϝ=a#NtϓY 퓜+C <ۦiVNͬIjzەޞ?E@'d'J%55Km}}뇥15 ۶O UHҹXt\@*5tGdهӹbQgAڟ%ߝ41d./"Qi;%F ^m=jLƴ>c6~P*MYv1c&en\rcX>?w'c6ϭ|Ьur̴}4z]s^ۖ}ɼtN564u%[ L;c,+mu-}TIMm}5i4N/+miz[޺Wes=5u i?-{|m698%i_l:R͈)ߖyw-ϚsіJM%u-5yƺl_\=€]Z4˟ MMoY4wӶFOgq=Ϭܶ쇶}{RHO7lKCm2ʪ͇h%IMMRSH:П@ʬTjRI6ںRԤOjW$IR'/~̖oMKEPD]\z+i(eQ!D(BP! @B"(EQ!D(BP! @u;c"+wD~ Uzet54! @B"(EQ!D(BP! @B"(EQ!D(^v;W4?>ոc~#"D(BP! @B"(EQ!D(BP! @B"(EԕAcc+zT]]][mG^rD"(EQk 4IDAT!D(BP! @B"(EQ!D(BPVVz7v˂#!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(E팉NΘo~ώrD"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BP! @B"(EQ!D(BPx9ڡ766*wTi~~~[z6^! @B"(EQ!D(BP! @B"(EQ!D(^w]]];i$Jׯ+WzYW P! @B"(EQ!D(BP! @B"(EQQWz/];Ɲ4W濣o?oo*Fwt_vҗGD(DP! @B"(EQ!D(BP! @B"(EQ9i9-e! @B"(EQ!D(BP! @B"(EQ!D(.I-z8x뫞sD2j8xX۞$9;EG+YW3IENDB`gxemul-0.6.1/doc/20070224-netbsd-landisk.png000644 001750 001750 00000026176 13402411501 020313 0ustar00debugdebug000000 000000 PNG  IHDRLOcVgAMA a PLTEiiizMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATx}MHmAaU W,^Lj{D?1 (f1zQ;皙L$lyzzIzL&;v{n^o=^oE1ϿV5~|913OOѹGD ~os0_/ljPT[7_~] >~y_0K6L?݁w/?*>[1މ>7?~|v|^>}?މy?o˗/?/B `__LhN?|zBL7Sh//U%B{L|?ׄw/oxxA1}Աk ^_Wy^O^՗3_//V4k1D꿮>BϕN8ן澰oak??΀zo$r]ypn&L:sgȀlGbW`wwڻn0;S>|}xug8ʓ]m`p4(ZpZλVz'}x?3\=ܖ24 Ov|Ij[,ک~L' jh~h<(abЍM(+N*a N1Ąw)|fL)YLa;7{7mFS#O6>BǒFǂS]wlzk ]5tdžpMUzwxv찻Ѕ6ASߒC#^/B:uG'#c8- `&L0=X=px\;>h+iF:䪴ǖ{9 IdCdo>m4q͇Mos3Sfk0/ŞYdlqCѥCW`5M\L/& }l}:{7&Fm0ZdհOIy{F0 AnicNn$4d*0$n{q9|-&&sMlb>L;K``?ȥ6pڱm{!]ڐl㸑ϱwO  aNhaU>c=Źq|w`%S\)}>đ>?e~"LzBc:%1M _#qA7cd<^)Vڵ:>yVXZ0k2k-z`݇g,73FqksK=/l}g6tS?ӷ}ѧҔn0]Egϳ?EK馞_$o{TgtM?66Y\N\ВܽJ\/Z z L} ZQ3tV\ГCsgô;0}]4:NgNǤߛB$}W:ĝ.?ǣX*|Lt4 6l 9 {>siƺAN hv.8#\1N&ʘJ jΕ]tP7%1 }NVswoHWʁk,4><>!qŧՑ)|u2t0D@NLJء6;#W]Ӆ}0nH\%cԪ=xZEa瘷"&q0h\;%0m$1͋oIG!w"л- S8o6wIN&uuSsB *UaWRb׸,ݍi<Ǫh5iFEefĜvT.WcrštmMCFdǚ^[b;ð2>e3#"'T9Pm+ĺаN01u]bEL%k;UN:O09ӄ'9{GLƄtt{WKnF|<ˠUUń;>V#Gh&׉t|:>tX(|Y;ob;`3]θ[/乹0q!+8kɍ{ Cy.Lhb[4o;)c4_"h}D"YC=˖R!|$6'áꌠNǢ e-n k;qBKFHI17Ojhfd$L^1ibB.oIsose-S& jT!K)^:ux+8XY0>! ^)GŪ BEĻ;Z?z,pz72 &W`,UTߝR.p3- vd1i+Ґ`*&"LCj![ L@g5RY;Ww\= ? ^;f(n$rU0QTCcf꽌)' AĤ5lL2PN$c<8LJ{ii!x:>dltq,P~nz`)RFoqpDulO "zC3R~ƨ)X&=4֋z Šy=4\b- 0 ZY8Ў}7V_pڟtE;>* ij@ /cavߓ&^|0=4 SS k}DߩjWG9nٙCsq=OYO:4 d#ɟ[ (jX#sczL<(Nc#& Vjp2&=ꤧ+0ywiN;bqk qÚ21&=OWr0\ 2&{&%i%9S;US!"cNw43cB/B;VFL\VL^1#Àl@LC,%]7yn3ܻN[wiewauMnUa K5|,5o?%<n8:1ӷӍiAGO]8[ߤ,ͭʾ _4cLqS6>E(ꄎ\8&icQ916qtp9o”9B&JmUyhNwԻסyJ,cNTb(X ^h|尃iΩ.t9Y~؋bP1g<|itF)&OEL9Knw c» ĵpo4…VfǢ5s}bGX}F> X2ljK|o6GO;3 ݍ6 qb:*sqkbBL\i\t9.z^^ޡi\}qu_1NA#:GnN*1ng`bc8Xݽ:5۩1(o TfS`k:д*sG+!X }i \]jQgei'”8p&Spj`*,$VX~(+&x~{.rq7z[fÆA:2%D*Ў΃p3rњpPa7-#g  xsbTsЪ#`-k[,$2 h S+`rD"g]'(wDc<J @ 3&{ib#0k$.Oh'^yK#0Wyt] BAXA 8eD8/qˆJL1~WD͆ԛ/V픩77J5Dj}5"b%Q1z]?4M/S`UOsYS^vnizQ>W6n0=S{̾TBF=661@qh6ئ?y1嘬 R"#&m48K?fΖy|@V5E[bq_`jzhw<SU9 5 L1w/Z& R1X{rY 3`rSXf?oV,e?#b:^8OEmQLBeh kKL 0FH/Ma?lwp0&%)@ƚt;5j4|VH$PrLMo4&U\S"hWꑦ5yGK?wJ/) c-=w|iJâI^ 9֐T$* 1Or L`R/j-‰ F,`9m3+98 "4,*E4?L"^|ӿMΡưg.6,i8ca:=_a LĈ3;}!R6Q#T BBcbQB|vx &U:?Pw8`${IZ0Ə!Qn8 Cû+ZGï ggQߊ"Yr8L8G 4FrI n8>;V}pWO7ܩLfwL!n94P_+}?\*mSF]4| S!75|;%`Tz0CX?%`f-BsYQLG\iJpp”`?FpyDSL5HS]ּ`[|${JyiZ Ysx4q5>x?>K0&qciR0*vR41><b)Ъ&sX3T aγc^NZK˴Syp!l[>zoPyhaXjst2;N^=x1L}yVݐԟK9LMܽ:H}-7n0=O!ZhzXď.w)GDQ,:VuɥYcBm”#(=N[](㢺\팿n|.U,hӒJ0L V`Ѱ#S`ĺ5VO ?w4:Eĺ-3Tq8v:Ӵ>(ō,X%D>ua0FH"}I$e*S6&?O;tH]uJ FkYkQnfO7,%^hF{&:[<&XɁ$TFIZ㻑tU!BaI:T,ZQGq8L4N0Yz3&FQƲǘ][5us76vh1ގ Xk<9E(%uA`,Qh-D, lqZJdBʱs'ιr{Կr9@KV#M>tZ7HiبW!=XO%1){x9;5Wުa$jx}&Ljf`1Vpbbqvva(AE=X*U?#b `\i1 pyCUBؽ>ڧ2~XB8}[w|ƓmTLA&n4a}NWi MTt҄d-ziVpL'Ǖ9Ly\[{/-tqv0rްE/naLoSLB޶jﰃzYR޶5*Zө\`:#97[{f }|^;xnyFL3X:E7+cJϠW|߁ƫb `u,F;\xek\ĭ鰃U؊Pα{U;KqH׊d-L, x`(ً8"D+ͰcB _c|:ٻn~UK0+O6mW1ӂ#B %mbSE1u[vp"|z_[\;㤊Y[w+bS;]S޶M^΅1y`$&ށ/ǝ^q\;LquTvNUe%?Z!`rW#P֗9Xo"V)&)ăVW1"}f[#\i;7IZb!,)\+9NYArN#84!(GԇY] 1m\rpzu]%ppm^S42ZL$ i6iyugr5884#<ƟY5`B ҅F^ v)0H6S$ ^l &YM9xBMKKѩfZ\'/rO6~׈ m58E<u*&TFTppBO2|T;U&_bYS`$L ]ӔQ냒SYH!&کb&,RT?=´ܽ+e;Ŵ'R]9 i7`ko|a^1T3thv׍i37Lm,xbnڽ0X*g<]O2[8|&iO);> bʅE3#&>n^/R  ;4r`E]Hgs[BrhbҀj)嫲GG4`@tey2R7&B\LcTKzQΚ}ҷoj.cBm`1Ak 9 q C g. PSKL1SbSL}4uh Z(0(Qk &&LHjhB WDLCT,)͓vc QS*,>qnU:Y}|WYY` Cc0( vX(ר$:]nS<4 EU0%^4b)[4T`4bw 3Hɷ].cٞ`Õ;Qsvs.*01 `15z|JjI!ᷓ^k.0KSڙ'xЧf.qVQ K&21l;tJ:UfZ΍g2$y|bD?q `3;2B کc*-V):OJ}&Bc|W\.8FNRh$2Z| óiո/rS,0 6#hBOZ;iվ}bDLmФ$[H3b+&` '"Wшm18uC Qi0ԧ5ŸۖJI ^¢RK\L޾k%Dɢa[v*XYh6eB@|oAM h~0 ChdbleU$mx3.^$gGLZ)0}3;c;uófls'zXo\$1.N+XIvJՠ/5P!cbTqC[DZФ!*O/wsH 7is-Z r˻rcppaڞdXm^0 bMӒ aGLcIu1evRaULi;)ɰrO$ژs7dxmYa7Lyץ6LmkǴ{@'d |myvZP$azt}| ӣnHY^uI$;0ϲ򃖼yFcD\aݘ^K޼) }VL]L pQ0k5Z=TmAU9PDzlìnOvCff#3bSwC +TAGLIjB`q)&0I5ֱ?EIb-£4D.`vC;p1X%>LrX}SazE쾦3'^o#]%n$4EBPO!xT#=awPELeiVsY,A4G9C{Gc0il~2X@8f:Fiu,2צ Բ(XReє%#cbj }YEfRzG6Z@F؟G Q7CS :utq_^rҨQ-Y~UxplN1 0el'3";4r ?5?}~7aTO E;p<\e8>a^%\~~g|w7L%`nik_5m1mv1zc?ODg~yLN^_򄘴cG|٪me6tIME!S{jIENDB`gxemul-0.6.1/doc/head.html000644 001750 001750 00000003441 13402411501 015562 0ustar00debugdebug000000 000000 GXemul: PAGETITLE

GXemul: PAGETITLE

Back to the index.


gxemul-0.6.1/doc/20041212-debian_1.png000644 001750 001750 00000007373 13402411501 017044 0ustar00debugdebug000000 000000 PNG  IHDR2}gAMA aPLTEHHH& MtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0%IDATxMR)杳S bo \g H?$6`5}?cd$h9s/ XʏeNrer9]ȧT>2Ex{?ɐ2b3WHYuBh?d2d!d! C! CA|BtB8$'d iU1Ȕ7[32mFA A A A 2 2d2d2d!d! C! CA 2d! C! CA CA Ad! CA CA A A 2 CA A A A 2 2d2d2d!d! C! CA 2d! C!Oi*Uj\ody?+g(y=e@}WQ)\$S 2xoVͦe؛*~:4ʶ%k3oe(;4\),u=b*쟺m{p%~~RiW@2'3GYV|]>~_TgBJɸ/?v ը6ߙ;Ӥ^Ls UͨXmu3 2*nE'n3Hj*QvLY~̞Sb ke/dW{S=W =K myvm6|}yȼ(sTybeim,TZ`&>"xJ: ]5ܛ2Wowe^ |z;dr߷-)3febL,Q︕([B\32W`kh0,f!y385G~'kpPf#}{h?qY[BdA e$A'tK.Ljd uJy*qdm&m5i?HT{TʂEM_-eRF^[ x Fw˼7wF 'ȂVlo&(imd7`#Rפ, X_|>pdwwE%E_n*.*"zzYI*Ѿybӆ -A`Ylf>.l%{3W[ ]XX~K[ H-%*V}[o|af k\J+g턨5MIO.%k϶LW1`v7Y[JE'ee(~PF_qOWQd~Q1͸PeTjofHFu%m3Ȕ*c[%9[̸.<@RL$Oe'L$!/>HSq;K3@S=?V ~QSfjDfj_pBKu,HFM+Z[q+QeU2 ShOu*}.7 )Nfq^G)H((p~KC/g5\25yVF^R@Х#&=_5|XF`lޮ2B_ Lʈ|N[~v DQA+@Ԥ 1V~.ᝋt'*g*m{2 ׍ɘЄգ~v7*xg{7}v["!ӟ=HTO5\gSgMu]jqHTvܻE]m@S7s){T-ٓI,87^ 겟؛!!F2an3jr FDVzq<Uʄ}Aoduߍ%MFPޫU2TvojVq7fF*vmf4?Wfs` 83#wq+g$4wf̺m%]ec}Y"%2>ؿS w?9=+N~GʘfM͔`>)+*Lq2˹9#SiP|! A 2 2d2d2d2˜Hitcg|!KPZN|.̗E>;/dʔ w_ۚ~Ưnm_IUEeAG2Hq^_MM-y2_Q]Hk9Ӽ[ƶRqz}j}V;`o+9ݯal4{FfVNAјsƗk;sxֲ5jy9+ٽ?7}pcONe įv5ހjr ?Qy %Ұyeמ82_/5c*"ZMk754lYE7iz#6ݞ-{|s]Ǜ6DҘ^]~]2Acfۚ>߹N7ZF؊YNa sVZul _9"6}{3- kҞ:Al"P@RELZ NY#fv3d>t }~ene|m( z_ucBDD֍o;`֨Bgvpg۟dLq˶3Z>s<mtS{!(3־u+9_Ѱmֻ͟}U!/^4sX77uOU~+nwmZ}㗿`Rv'Q7gUCWZ5Ա{uq|u}cY6ΏlxtE_};_;fxÀ#G|ß}/z% '/|vf9WLoI:;?{dپښ_:OGQmMv-EkP/jn.Ͼio9tq~k.;owUOwpPH]fWNaIv hu{8#8n6sPQÏ=d&D3ltyniBiժ2 1<3f:EĖ?z̹r oAfU |V_חwF);8ylWk!*r2mj xaͦfUDEUCf.*˶=; vxq',`#GD|oٴ{qߗCV[rB! j vHIg̐՟5,DD4-ݻiJ:oҖ˫f qep!xXTfh!9fbRאoxlq#ЪMhzmxöv4'~nݭLJ{}eUǟśF ؜zܹ veFoQ{noj άa&8D6"mfw:r]Πݧj 㦎uwoUT;cn]Z7n5jD=~o7ǟ=mFtw _z⑟L`Ÿ\w^Iq{o,y쑯GA[e/+^<ƻ5O:m*-3?poֵW/;eg?7v7v>m L-6{e>`CWE|鴏pg޻qR:ӑ7㮟^ߺ"A_?{?~lEsd_8c̈n?㮟^}WݫKVdWEmuvUB_? ȿzWIJK۽~qӺ.@Ė[>._ܪd%mx>\W~bЉC*wnڞ99vͷq[z1ȵ{fm6WZOcgg!>aFڴzYZ:} #\=۞駌mdT?^7[7mޔQUQXĉWqS9*LP)4䱹͛?ޭdg6d'U6OѱUݶG?lp}Ἂ36nwz+E"rӗ#r`9˜.qh(m 47qI_m2( dR߮Kk%^ ENx\ĞkϰKH}*"r"~Uz bujq{:JFBToQ%:uz%>d@+"6@Bkvw5FNx6,·^.ef/Q_U8iӦ~rUGUܟz;42PSz.dަF[>EkܿuS2_07o}ߞ//ɖk?%o }s)3f9%C 66ݭG1Y;5*w#[~o;9MUxu2 Fmÿz1hq]3g玜Px-\]YU61ky9gV;C<.]+'#w[G~pLpOyq[?3JqOKb7 ruܨag"2zЭ;\sLoPS4T4#j-m-O\V}Ҵ##l6j7ln0GZ<渑#]§ߖݛ:]R1wg縪9kloQD᪚6q%yvk6-{ FuԠ?,K֮9dL>Ӈʮ~qkHO s[wʏ9cD4'K7nl6;,=ӎHm;Κr։S=X-NYN?+QsKN M0C "BZ]K0/HԤ=glg=HVY84ͦ=9+VLt}2W蕞ctZ)35Ƶ{ [v^ _D־hlgu|""E92")> ߽FDoeL[?{Q_usyG=^xyy_JñgWp/66瓿23oϹ鎏.xIiMMBTRo}'G!̹o,{eǼQ7J4*Z(6mۻ%]wT%o6g.@!0fH[SS+ :GNٵy{=/˛l+r[V-!'8c۞uU.5 hgl& 19Ծs:D\ ~`ã2ߑʉw^R:ȶs/{9C/ms5jO79\Ό̽ 2i\_3LvpSeܨa[vԎU%".7ݑ78J?[T5YvCxa5qZ+}[} gi請۷yAU4y*?`xEEQT5v#P4mN۶gzo|gǎ1XeE1tެ kZ1 N>k%<ilqz\e|sSͫ8RED? ?R|H }~ Qxg+ VpܞϻkAk++E׷KKDD=nܢC_CWoˠW?k+Vlo 㗜'Un~̋G\ |}/ܿcO!+;X5ˇnsxa(A_KO>w7XsN/7_X1͖Y8;LVc,!zy۞WYbsqhq˘ږ̿9+|{ipYFtWWg#J],]D崗w5鑚( k?0U)" mjV?pg':nބ3ݛ^ }Ke_b5χ\8}˫GxNnu4?8[D==[,"x)]1e+o 5R~qg7neG| u=o=국ekBY(AF Dr*J,OYSr+O(/sv_qnoIߙ\P9_~ }~խvF]#q0:g1v}NSSwߛ-^R(-+;-pׯT<<r`x>aEo@(@Dv-._[SС>CM""e%E!4 6G$0O|L>G&n W\sj鼤yKsMϽjw_{nh}`fAYKDdjA;# -k6];׾\z/񻟴A4 =S%-Å5QS E>&A%)!᩿5K=R./&JPQP(jP-p/D qϸ,7^=PDD]s/m߮O6N?%"kn߮k:mZMWX䑕>lҴAoljvhMW${vxGJ \9@NK/$ɣ/xKU_@-ki~[agL+hUK'?Yy獛yXڶ~'MBSDԠ7qdeIeW_6ym6W^z\=^ϰ>Sϟ663E*\wXѦC' :~O GOn`jH tP=fZiá@@ :rDuOW/-6~V=%ݵaSJR7(1CTi۴umGn:y E&3;,;6x8g|tAŶ`!y"e{DYj+ #5QWrÅ5q$dhR}@1XA]*"l=xbQnVbm޿f|'lrEV}FlNOcW$;dPO+9v}W>կ|e(a/ 4fݟM"2n3c65ghv%hlj۳B*"]S5}Rե BYCN4HRHK&mz:N^pꉧN*2_?摟L?o3?o|}ݔ#eww_l g?2!VXd+V6D\Y Y"h8pv:DyeWNє)p"*alXh kwPHտe$w牻ǎܶNDƎ߸ 9];^P5HաB`0h%)J($7 @ݣ89.M *k彿> N)M &J':.W~ɫָE \)=V Ӯ`F-;6M WӔ $ij(TD )|m#Y͞w[^-$1S}pO|V2og]u݊fӂJPD9D$T?o<&4udUbǨ>ghv&/Tvyc'U7t숢\Gƍ^fO}&-QՖew>S *\;oƱs[*=ﶢϚ;|XIvv=|F^C z-cpA<"Yy94;,;׶$QYFK<?p&1_@ټAz&Z{&AAN9."YNhfթDSUc5K]'%{G@l.釯\73%-lcւyjロE?/w=#郑/(볇Th/# J DGrHm?Me3 ;%69ݏ<TedrF z_BrJ]e2Einqʎ+p4ozW|&0וƋ׳k⍯T˖e&U0ƣ쬰\s\Su[ ߸moUD^Ǝx_][6͑i .UUQl6[H=Oطykpڤacf9<^SC!EV0Z;CZ0|v55d\yYvkXH EaPGL )(r6M )!+u䭎ǒjGBV8+O 4.y/.Gʶ [ۥu~QJЦUsՐr]y"Z}`(d;RG13~ڒjr1OH:G:N-Z ˍS6un\1l72PC!%Vu{*doڽi6YUYZs No։μhxۡzݽ^ydMBJHr?D'h""9!%$#"f%Lε=R",3 ȫccnI#KyKABpa N}Div)"2fP^vcDiz%_ skJt춬b&(#sŭz.eEǗF&c_;!KoΆly{8/ٿ8^z9]6v.,xy';7)޺qxiE_ՑLQ4>o>~.>˧H뻿;h(g͞ڒ& 2LtqQy7!}u[(_hv3Gr9rrEս;UɱW;ZÆPP%]n7Y+"Nm=ό; rDZ};T-AԦժWlySGn>U񋪊g5J]ݿEUV<ÑmqWBwiՔ3l!LhBvGζco֍7W˿z%WMj0 b9sl<pз.;7Gۢj9,%juо'|>u=ռjKhݖQd+jpu:J Z(l$4%)gׂaݧ)YHYC[~%WSmv~/Co8|u#Ֆ}⍑EK 7yocLumjz\O=SϬOzӽ-3[^1ϳ h$˖ۡ-jULq{i?]s >ԯ_\>N:"ٵ*⯚˜E}NspYMѴlߦ%;^-K:% Z8(_/btﹻ9^D25%8~К5/0o+!m9wƹՏSirrco,H&Szߗ4{n 8dC'9W?)Єi78c_m۶~nرeRd9["@zxN/H!4rRd6MӴxo_W_!j#&mf߇=t]Dߊi3m E9[z0ǔ)އ歈z7|h޺\KfxZe8j}{ކ0yK#FQ[%`xФ]$"G0x1D+sQw7Άo%Lf?b2*`+2; #ݰ] +pt06NrѝȱFe8][1F7͋~S KN%Aԃ/0Q{DIzd/ Y#&Ing&DX610$ `JI8؇<2j[2P1"'*yKM$#aFrT8rjMGpv? OP…+&06y+L i֟h}h1rH.fKqy6LHjyk#.}t@s J`NH!f4Mu-c#$q_y0G*}73M&b/@Hsl5tz0ǔ)އ歈z7fzs}.P}ӢðNӌMEl~3uw2= oCNǼ_#Ĩ0H'4cb_b8.˨ubo1ʰBSċl$vN-5pއ=ERb{ȩ7\0{c?QK C Ʈ`KXz80y(ŖZe {#3=w,.iQ,0!e8qӯѥi*D* ;] JiH%4']ii4rR 9M&TBN@*! 8H]HJiH%4rR 9My }hL| JiH%4rR 9MI@4 JiH%4rR @И00N@*! JiH%4rR 9M&TBN@*qifE^kFt4~qiHo&RWݰi@xtpQx<W:rgKc`춱HQ[0:QVQKĶJYV2ꮖp<riJK:"u s 3[rfX*aYh]mE]аt+q8AN3 bIV=(αc'#FR{9XT98fzM?1ٝvuTAi("d:e Q7'lITM1K=aLfTqOr 8\ы&I[NZVn؇ QǛYȤ7L;| @!nPѓ(-\dSciXxXlJ} k>W$VV N DI{VI,H-4-Vfm@o` &TBN@*! 0Gf JiH%4rR 9My 09 1N@*! JiH%4=i{HJiH%4rR 9M&T }ht 1N@*! JiH%4=19``&TBN@*! JiH%4']C@c&TBN@*! lҾk4CNs lZH/VG1xtPtZ/̒12Fhr`o$'u^ݩ_d+Q[F6a[V aLBE=nXk}@t 9́H" g lYR?4^孬#tAj{/_뇵5rT9v d謄2JOiTzaԇoe t+8w܋+rk]z9l%aJB8IMn6v~&$sG=GJ@S]]M'i_(av~yrR @ЄPSL1_;ws\oiڦLbe W9MRX8Y;}j-Қ9MGUMMuuu… :  M,[hjx1= ͐ TԄ6jj ͐41?`Ꟙp9ir\gt!v &in&9MAdHS՗/\ns:@yӗ-ZppB E=Ԓ%/9^~rүE@ ifzp1 p ܜŋ&" .˄f$]sjIlN0j vZt+ 4̈́+}gO2;}\ÄWUJﴝuI43 % tGYkp/6hUWW[t+ (4IV}t$inw }0UT랤Yۑ%V֌nVf\9! u_DZUuq^[a: K7\'^D*:V:`V8ҭ$"-FuE-x^]]lѢP3{:7=[as4CNk‰0K:[ES~Q[n\[Xs:TxIc'^TIVaܝ^Kkx6LZHBUMMQ4\$4Vb&`{Hl&걃oMaZ#Fv7LZ\viطkiT{yOdb֏[%~$!rt4糬LO#䝕+Wڃ\Kcl " $-<ڏ? 7<* LV / WaPa0laߍj+lXH„{{E[+2rQՋ]Ǽ=Ҋ$QelK٫Ve9ټz+X @7SO=UNkMɯ]7㛇L\W[k4Y!?9-~fD ǬoUreIAq~IXiaYVf:XM,ŞOXz5uo{.QWJd=r'Ne^~prS:ߍ{c5ZHkAk~[ᭌtĦ\ IDATcS- vZ-jێި.\am]|$~~鷗N4-'崒LbT4abScU}Vc"'QL1}j9a+'jrޥc^?RlY߃vmTfյ}0k4^;487RezE5*lu$z H-=2ym_z|\ҩxRr-^#b򎷹a&V9~'3{5W5K] W:^ݯ>BFf1c3 9pza'dU55D,^M7YlѢna&})[nN#\;wFieba Izj)va+*S+=YlQrm~}z{_thpBYDn-#-'wrQٺ,^: d.^q="òL"7-ȤQoUfdx +]i {bl6-za8"2V։5= V:3Iwn`: 0~0߃<IXȭ""fѭEsn_WW_zE#w3+jn{2.{25$Jn"#ޥdA7[ѳp3#ӧzi^r5쑄>vu>=udƑɫ縣'^[jN׳~ z,{L V̹}qxfU55 .szUwrH=my^'aD{ݩy:}YC+Rh#13rD@]dI[]O[[Yi]jWa}7_\' ǼI'cvޥ.އ(^F/v:'< > |&Wa@W;}zdڞ qߣe_18 /ALHW2S]ݪKuRC]N.t7b RCK2H3.X 1՞.áx}*ʧܝOw|N(ׯ9<*O=.o4T}Ҳ]W.\:v9} =yh)STWW ILNH!9ͨ-F7qpͲm۳OXɾ챞jQH.\SOU/{n>s<̀\Y'%b'c!Ȁ @4arW'U4lÆ tJ g /L2_'B²RC+"'23"7*^Y&iM+aYI Xlirec$?Ci7w?uluɸ4V­,$jx̷2\b I%<^+C҇IcxOViTXy>mF' K9lQr}<<[IDZs8y i8'kHng87̝;Nṡ[j"9߮Liﻀ^D8`dٳ8SE݅{#ްhWwb&=NSJC g9*[焏4lId1zV:[채st}jǒ+ݤ>&!R@3&!&٬ 7L{WH6#a9Lۣ~4ϋ-F/4`@ݜM V4y0mqi&p8 18Bm`s6=WȘ Ӗ4y0medye,Y9M^y'o7jvMj~奟 2PDFK QX,X.bys6owl1DY%P$Ug{qx奟Q^d@W?GF 0]2M2\G{{ 'eq$F 62M~[RR9;;+4gȉF2PKRTH p8Vyqpw)&۟3g{oqcjg/}r+&ʿJ[o~/}r㳍1ZTU7qZ@L s~qd(:l^~x9/S*g͘p&7Jd0%UYƗׯ?q;s["cf18<*xcH[ą$hRz?&7eV? D% O|ۦmxw$spTd0dғ'\\Çן'ϮFo:l}sZ[y0v7#t]7&TTsZ[ɼ˶,o{Ư 5={W;Qf`>|bqp)]-W6r\4i_sl-VA Ӫ@ǘt:Qkqwҷrڤ{5&“;4`'i֕*,'O>(NVEQ,Uyr{(߶T.g}z{yX1ISIېn2G{*;+=>!)svQsREqsɓ?wX'jyJ//?<͵K<8qٶǘl}FDS~gd7` O 1哋UKƿ_ܹsQEV͋X<\?jqQ?}߿rX8_uhaj3jU;%ycοVź@쯶qK h>yArsEQ,???E_xf@5OFx׶76#{U A=^d؁W1 702M2(V'EQc84[8t iͅWR7vjZilZ?t鷮<=P0eQ 4 x"ЩaygBWEezVu海A9$q=Y9ej~1h4HW8ϗ{iL4r_L'$ 3nRUg{z__O%rplڎ= fSgeV| ֒kjK'۞k ӡ q(4$dO- Tg^u#8Q-jg洧ZSsN=28pMzYb0ާYj޳c"ŋ?'>kўCLgw2V8NRŅƯ}!lCAL`$N ՕAh$8´1z?V% ;UeV09;R0/rK>@ peK263l+8ٳ|f6nmspfNLw\?&2knOpɛ0fa٘l^T1D՞G&S4G(DVW5Ǡ!l]'knowePE]y6b\f?mr. XW{ ̙9Nms//U?|խF%44X[.LJ=>hO oggs{=ggg?#:OsY.ˮ)^݉ =bUz33'mL9)Ǐ%F9$ *KT>;%;s'9Ǭm׊i@o Լ&œR0W=Ȗogp? rW\ռy\nO˨a7ȆfdƓL0=k5i4K iY}1D`Uݞg߳Uw8<ճʃ{OiL2񏉳I1oO_957i;1(D%MŢ|KՕ:)tًbqqqQ~f(cVn:\.gfkSino'tj:fuwT\cӰy]3S 0ϗeh LZ8O>c`q TfHLS`?~\<]feZA9Us) 4*МWWWmLWszZ~~_7OקGYk]v岜Y}8H {UZf囉2N`Mz*C\&>lzN=*vb 4\=}Do/g^dkX U8x8qp \ 1rz[n{ 4~2?nCtFa`L- Xs{ovqQlN绉tM9Us34Ъ ch'_qw7,lUZIa9=W&=3@?1;'`WaYkWlʨR D|ّ̾wE=U,bʡT~-Мi6$>Ѽ/Q pd-3,b>W<;; "rnBg ϲ2=(|S8*]}...ESdUBSsG6>_Kԅ{<@?+MY۳ <&p...y9Q6Ӽu;S~.cPFL-q8Z 4M9kJ>4h12~&_KyMf+j-qI{ʑ1IS 5FcB~Om\VF *͙fmcsPsy|VzgsHsʪڪp~[MM0!RKw->TgNѲx6 ֕313иr8e{/ azs!.k; 8BXc"N*k=k 8x 0!YS{o؂LIZ*mc`qPO\OεǠ}aGP~9iSҽiSol!?t54d{ٓmnB>lAPl`Xwިsvvsm%4! ڿW 2jb{㑴d>ISN{ &?I z[,i#gZTVVk~lzAij_okOh{\7g4s䃚G,'~ns|VzsqHsM,=^-F;lLXSHpV1מC&_'ٞ.nۺ߈lp&$nS؞^-q.:}㘲w^yPIP0iqzoQci\._ko"|4|hp:56gaCxsן fp#ܑ~S6t~~ޘcE1ݚfEQfl6[.sLLA5734|_Nhr,? LKizgLN7|EQ,WeoF`*=k$3Ζˏ̢(./?fh^s5h\ w~~kE1ܙ-˻w?> 4C9sXghif0/[9~]kCp9_;*ǩu &Kh/,כE1./w~L3ឫeQ_YpT/WtF/ҏS/5ZM@oݻY.<ߍ Gc 0>64h8frN9Xx^ƠvT0OS ;Ьr&[rUF+40N@홁r'đI#`Q k0BAV"Y:oKمqVSvH`?̹mݙ:vɲ (>@bHmL@©!iY+\,jwLIZw~INNC%MGlK71"Mwm027nBq4*[(~|/+|MF iB߷Mj *ZX2_0]ifQ;"N`d(pQ| pLFjKw?/ݸOs׃ eIA)8 L3q$4wύe3^ޘV#k52na[6j&cZvQ\##ܑ7QVg.@uOz0f&%ܳ ~D&\]]F ē+YK0g'jHO̜ιV MY,y> l+S#.LY nn$l$49/ @Ls?rvB߰~ w!M@QG0%2FG6bv_wkV#=UeꛀOtx;E|h2ڨߑAƤ$}06iAn2=3]m.IlB0in*X<;)#'&fwxttj~m6>4֘3 4~_Z  mx3CI4זxgbNn]j`&** 4gW^G{ֺkZd{ӖΉ Ugf=#5({Zųێlr]pkx5|$6d]1GuT<mo:N<ߑΖ7>JTgu4דHӁ溯bđ~ > / |h[M_26&Ԧ4hҰjW܋lN؆\=djö1*wg$]hqFfo>=/`sZ4ޤkeiH(j+ xVg(^s48:pvi6&YA}z7I0ۮ\+Nɶdmj|ic:ƤOWܘ{9M mfU'X4-WOgM,N4s1x}iʶ;ǡ1C1>;Nōx.gib]K72dzpm4tmMOϗ<996 .xL}a~L8;[X%ZfJs}㠶zrνt^p،z2- ^yVG/8+>)1=費L32d3޽ݖۼX<_#y9Q&@Q篌UƗ`TNWFgnݻ77WfL$m xd[{r2ֶk5Yfcc'v+nL&ws^{€L3Ϊz,Vy&u'ѹ>4~e[͝И!vC 8m8Sq:7.BOrv-ȜiKMh3?<[skmzzɰYpƫ礜me er^ْ۵*7^7<=*8pFi!We9+UU ^Uɩ'L<'5ge^^s$I8#4j5M֞'^8_^Bn{{f͛ QΈy{,`?etj,bMdK3,W<}vi1=W\;Ԏr< Vg3^^x&p2ߜoج. TŪӵ;X_kû)#P {ҵNIѣiwfvumj/T]n#Щ>rT w#B|+{l)~ƶqJ)T=^m{2me}5'.߉/<ʌ_=1qeL"}>͓6?+(<` e2:Kw*'ml,Tk#Mt< G^wgӀ0cdwds<tzD=׊k6ǗcXKY ,MVfعz=~2x3|G9q@~/pqfj^9H :AӍ̜(uA#)(G1MUp<Tgm] NIDsJD 驚5rzVG~=vs^d=0nerVảW]4BH|ۓR$bt|ۘԣtTtgZl@pM4&6¶W8oq(UC43eޠI?i;98+34^"k6i,Oi Wqfܘu6=z;jn򫭮ݼyMqUzxv duӗhKqkr Gl~ާɑૠLp%bAc2W9-d|VJUt4'nyc"UU3JFdz_5~Wt )sTn@U2!qz͋xP[U{tksFi21lҞXX}(ǪX[p[LS\P nR\l]Ńm3z/ݵ%W_W~S7X?Peee3kbyӼdzjx-CVG)JN=׿A{6k[xlܼyX<߶xAٙii,_\6tpI4h=3[ s߻\?7?3D|뿺wǏX.󳳳^EUنr+6MWe67q]r.]Хt--nK wð][m紭w_zekK'+fZ= IDAT5O3qncmA {1nkpq 0 %ܑ D#C+IiBh  ww`롢.q=608z 47/WVW'IٯUljb\tj`~uuu"$4m Yi`7*cML\Z QAbM`N۾i6U˥Ms)Q瘥'ޝf( M'nyѓ^|X%H4S/urb7(\^Xܾ77^߻o.V&lzq i 4`\^ Go|> 6wj`| 1>x\^/^EQ6z_ Ajqkwܗ 6:s;:&LCbrY_|Z;?zX -`Q(6ng|Vµ;s;U`ryQ7^q(|~_ZKUT) <Yq: _ip0NՒs3>Tf͢(vbMIJ( 4` { M1ETrY*0|7_(۷~AS jLit`r} |>~|>˯h>zoX3կ|!~v+*k{B97b&_~XY ?'TBGm ȹzPsYW6-|X@s>~yQ\.s߻]-Wߥ*[ Ƭ$_4p۶նsilyU g2kRgmk F;8%?lr :4QyX8yfw kI1 NoR?(VygΫ;+%{cBA+767߼s}ry|6]\\|=!:W~g;rV׫g?V_o+8| ?[O>GZȪ᪏Akw$>}ɼ=:opL3su\m?}wrڜٯ:w<>fox(޿~[ˢi|^mO'?kfrAz}p2mc_KŚW[չqk̷ ї1cvj696dw(.?|>/xVYqXU1i(r2U|>|-t{Us0;sDza&PVٸ=G0.G ;UIey0:sx-{$G鿈W#q٘ueWhkh@(]34)]ir`sCUm|c ;Tמ )kf 3 SeWI9{(5~Txq/ ݤ͍m;S5ɼ:cy݌OUOƽ:0Wvޑzp|vģ!Yi߮ߧi*[jd ^r6 4&!`VONpv1ON W6_=760H=>os7W72 =- 43߇S p|u^ߚ5=\?ޘfXsN2#h6\9~D %#SC0fZgnfֲ{ci l"kfbr9'9؁$j|2/Z1K˃G2MXyֽޕ 0~ݙfcXdIq՘7uaS4䨪G1kka=ly6yDYi,!o,s$Pٙƍt&wYMAG]FO^\90T瑡JG=o{KcJs`oi}dۇXrږLםiƁQcT?U~8=+&$ӯwGڮieC-f60Y4YRuuކFAXgSO浊hΫTmU)qVsnc;=zfphayl3vokk4!i[A4s^nxA?2͓_ 5>@LdTUʯb$!t#(KXv=򸃌 -+ӔӵJWsS{p3 UW Y_<9a:Y{oSs9'q:]x&`Bd;rTNw/`KN Gerx<~i}^$N9+Ng1XyIh}ZGgcH=Hy[0WF=붪*kf1L ͙̚(`3͜51~+"uܛb/w~>Ǡ43c/IF&?EG[88x=3MƺLm4=ʤ9W4ǧGUݎC4G<`]{ GGD9"{85?qGDbާ @i=*=:K][}:7\BZg!9+*^wlc2'(3h2D;{%O샞}[=4p@W"i@Hcxm$2 bx!D,i{f{ٗZy(uR̬'&&de̪{η 4sV],GuML3㜘Y&O|p\Uqµ}ߊ̗ub; tAgFqTr2rx2[K> R0e|vE:fd͉;V>)Nƾж ǛW,1sQ>o]L3 gQSlk^3) ѰJʔiƣÊ+ͱ}kUfIk E1h;L@3څ,]Jɭj_-皵}.e.<4#KČ^4" h7ƒ@F+>MMP{ ^ wcDY3,9cdCSd>@feϼZfhkeOs\V bǔ/h{KH>TiCQl&w}F?I)g>b@3^6ʹ#0Ya\(iLf|D `m 15c9,,nt.S9M}FI;cO1!-rRεPj`LcSz#㇧D׉J>T _ ij"{tG+yq5W}`dwY;s>:dH\ju¦ gX4 #5,pP"d4kxb8z=1nCd-ُ+XixXΥI%G.$wܽ4p8R$fybTYJ᪺Fk2(rsH4{ \#(K2/ J?|aYSϥz3ϺaxJ=9VXPX%#K=wt'2!S?pL*I3 ¦M5\-:iF]I`^4IqHb~׉גeIuYQrrQghƓrV3WU{ɋd,c_nk *E`̰FЂTZBϾKtȄBq-r<TI=NE]2Ƨ Ja{dz# 8k9PRG7/[j롐 IDAT?붔us>hйe2uxV%]L3>Z<>zj{FJN<*ry'T`A/a PaY< "g1w옸NJ+,ʄhΫp)y\J9zGI#WҦ1ۚHL4Dw1s9ӹϾ5ƤC8ʔiN띾%+9㖥 lzjWڤ{P=uMHSTӴf,=ʤ>$OÕÍٷj߹>2"[y\bB'ptE-SI&y[#hk.|A$oOܧñ> dz)a>PMMP+ ^ZVO2TN/ `JO3\2(r*P^+oCo濤(,K/Y3+\U.Ux0 7w3ژE',4|Ӆ󕩟fbyfm>lR^9uLqҷOS FWf.7e 0o9ǞǧJL'E|-qUSO9$y.zBh@O=dyMpG+^|j2'`U}&x.`}H3x7rg٩yeR|v{w9*`6~ Ya;$DIE#3|)Y& ME\"j%.LTO H>EFMY{>i*I?Nz}dL* !+_0T#Pԇsa4rΧ93e<i}xJ 랇3B<V~>`^=K;i 9L_#V Q>ٷ~/g< 9k_}=wth2DZ;wy-TUuQ~Iֲllɒ%X(mo m)wf8g~_v'Si>}K!}y3ߓ/xιBh(LK9'=bMbw<>2:quʖ,)g)c.}͸^p3)kU' GR_gmY?=;&RŚKn @3bMn&~Ě@eL4IcsnV>$КD.\~"Ě@54KQK0+fQvn5jXe)>74|h2:?Y&PruMT:s P>#@55A ėWJܒXN>ŚMRdˉU (3wP:sXZ \a$?פS'x >"^2$Zhfj@`qĪ w!ݑOI3tߵ n2eM2z1>#>YT'jj.iRϧe~`|#Eܒ'aӥ7ifO?usg 5\lasoǾw}&L3>1b`|VrO1S֩ī[ۧ5T43O7|@eZ1&5Y@s!LuK;k}&P.3=O mxRX~deƚ9ӵd**,r9kkk cσ;%Ι8>;&PJI-nVGqIS|'nB-5_$$Z\)͜Rjǚ/zVGm#R7'W=ufXNT{o>hηі2?>Ϸf9ZP=L ԩEW`rX(Lfk-?&nlRr|I!so!4f.%Uȱo0`|Z-r-|k",%Ob9=h5Pf ȯ5jҗEZ'|C,>?L w2(|M-G? "bT< 4@Poުe 9~U #Ӻsx}Vۇh'Q撛Z*iS32u\3uzʹ`AցN)N%Os<L9~Tbɓua@hU{b*8 n)[sV&yY=eyJ}7.hնP^ XX.{)@&SsAaj&0+Pij7w畼D5_.!7ttK? ̤EuHqNʘmk^3Ehw JGY؛rT6zyQfN DY}5#^Ƿ$O4>b8&? kf2:9f Z2>bux$:5; <hܷڇ"}ʒc,SYi u<:i|r+দ 24XfUh#oorT|#XO KvՁ(-c]I$K7||\]~aI1ƷĻ%W^mMޤY=S,TsOzA F9("d }W:M/1zra {FģQ)e}ƪRj_mkaH7CR7oKʬJ',2ˈŚ4\g#FJgRᑉ&Ěl=NCW͊{9@WMHi-u1ITz,D ^+ &w37q͒[^O6(z&8zkIBa7bTnjJ9*glAիƃAsW4? `&alVy'/OP_".6 JQSǖ%ܩj<T{0q<,@- &JYfq\hS]iyO뇿W{Mmx0X-Aᓵ@HQP(ߊﰒ ϭYgr*RE;|38ֲ3Mnk( u75Ⱦ#a\IE?ٝ<-`3<΁N0G4<>Iygz(NtwYTǚ3 e. i&4kZÐ1q86A9)GKlU&yɳ^y O^Tt #+yRZ&K[<,\@44)ŋn}<.{9Q%>c|-T߇~?z_cxvT(]?qOcxҹ_Qy_OJÅ88v>7fޑjz(K ɦg ,J-_qaM ]~L-2z$SDQPo@U%1<9Ģ# ,'_ Ɯ'٪{r\?VEt5,ڃA4K,_OYZ|[>YB[r%ѱ疣W+ +;mA'EãGC[srEwyig/Wچ+|0*l|ChBvL37P.s:{4(BN÷tV {aeƏKTuW@T"̠$]Sk@q{ͣo/)#Ot}+9鸃GsUNIFoՃ^k^­vϱ =W7䐼X|oGҞ-K>i2WuE:?m%J"PG`M+:`/"&>5z}ãI{;?jE=,vk *3Z$4 O=h@ ZJOZ=c?8:~(~M(bvR9jQyƅw“>Cpm|W`4DB)q4"oUgnqKV{RՊ=,Nٍ;ip`q@,基b'-Hy2CP@MX7LS D4SST,@%WihsWI:ZvmS4Y5T#TM f B8;~2PF DiZ,t@W` @@%=_r[( ?*$45'o41Fw'2~,0I9,4= `I&{kFLJ9#d|H,gbuӂ e^{`̷z#Xb|zxx$3,hL$< q>`Z Ǥ5jo0fTfe ΎO>iqr|L&dLh1Ќ̏9qd=P%]5.e&͂=*&:f$1g6N2`of;wU zU f[ЏJM[5hdA1+V45P"w*y]t 1S'bi i5H'b:q*Єji%Sծױ,,*hOiU ̈́&P>I*AMX+iTP@4Nw@S'aMjpX%4Rz?yWwSY1}UIS~o|V趌wXꥁVj>5 d@5q%G'M]#UiXS/ZGk|1Zu_Ƨy/웿 {'P:i&aߧ|M/BNG`Ude"e9PF2M j\wtVK TĺM7)zӤw&PR2M:pɦf-w&r=(QgaMJM P%CM?/?Ͽo{fi5}ThX9cY\bms: >*h{kcuۜ2Ν4VO TӃtAi@54j= 5G3eFX &PYb͸u7Eh L:֟$' w㊄?EisWMPd@]5SģB̌ 9G TXsV 3;F# jp>X30qArKh4kZzŷo +1˲Ejrp(ru Ě#v,>C΁ 7 6\o%z}*r4,] v7 ƞ1>'n&PP E&U7@`ׯ@aw/Ok>?N'ޚxSjI20h2e.ǰ#SvGTNZ%^g*`<kR1s D|[ $s)$Y 4g!kJ6O2V=_r@& i0ּc}r_ĚT| 4ȳF(  K}Wϧ*TXC+J9 ' &3;X`ʁ,sh/Ş~!4`6;WᏣRq0 IDAT{Zo}ID "B *c`'EMo&ʥ 5I=she&@r&2R|ӌ{ud/V&{ ϛRĒ#gxSkYhꖙ4^,[`{k:lRH@y%Tep,u˱Ly<̘ϕW+ deOb |@ɪ,@(Χg˿IN2S_+̕(l{*]MVbQ_R>x^}-/a|LQ% TOvL-Aݞ>s%̰,b̩O8@Y駙{];'S'+ޑ3ˈ:g[3a[ht.!Xb| ʗN#S[3- $D)f dahJ3*əiRVO浈wCFd= 21(ыptPI0s$t:63rR].f =O@f65KZo%P: J6Gڪȏ 452-4gvkr?Č<iqkr(<diNZ'<;PdI˗g2}҂EJ~v qgg좙xf)d(O|IorH\Y0wKnj\г2e =:#aʖJ5+{ Jnsn7EgeeL.(g\t8(|*f{<$=`.f觙u1qp`cxȹ,6r\22^{icƆkEY["d43ˌŚnP3͙z;)oeْw4(8f1o4s|,& l*Prpn:+ߋi."Ќ8;SFvans'2p'2,3QfI#^:{NwᤣY2Ќ@)d43Sw2c!{&3EK 2L}>_=~\5~/"qjªg59畦I k_[~֙9E>ïPl cϳhcnҜ8{ʹ7fX,ϥZ5KiA3O'M712;dfgjuj"ch+ ȮW.K2kDd@45@uU5&P&2MLd@42ie"ʤ *c8j*O?MLd@42ie4kF +p8jYVͲ[d%X/a(֜wstR W3qޚ3as|cFf_l_'{}chIWo5)H5}9Ý}j Qbn_ddR#[;,=ژ+ -I&fJDXV8JlIs*_(LSJŠ dR=")E2)CT8=S*R$dK4e3׈<-W͋_uk/HkxND3͌icu#rw_Lyw=w'qd,3y7xWpOm,^o Sok=rQƗrI] 6x9@ +?SspKD#I9icz_fiI,9{qg~s:65@Mh8NX*0iRfJM}3ؙ?_ߥ=rs7;g/'c[7iJq5/멩 eȉEѦSw~5`DwTrL{!si9|ϕqL0峐X…gBɼ4!qƺE MInbM?Kfj7%\l_N.v/gU]?ybJrۺK%e)K 3q|cQy^6\Ϊ9VXrL,,ku2/yi&EhV3 DT+oÂ\~UD5-:V)L F[20ycX/}`owK8ѤX&*M86thYT 9@=Z3uqf ,S7q5sP˹j_nB?f8w2wk䋽c ;&˲oG+{!]L+O3E;n!ÑhO<+  QS; Sn^ˤ,{׹57g@U)i/'r>%^㬗6QHLsne<"/Kn̒vQLoxҵ@K+rō/m2ͧj= ՆEϘ> (Px05Ⱦ1qdh|ό0r)T~r~wikH#ռ6fo#uyIz ,qqiFV.%s0.}uN=j.=rL6\~kQē1 <PqR_?A%%nΒw_?/Ojޤ bsI_3=3]~s2}ssN=cg`A>uWH4bēQɟ1JN/$>e+M1u\Z#_3U,^xvlI-kPj " o-tgɸk56I;,bk5k{v+ߔXՅq|0zpN " +g 5/Ψ][?;agػm7_D15 >ʹuJ9˯yqڰz*B%5E( XgM }RW i!>iI3f\6\l<|s@A )LLp9fLVކoqvX/{_*imET_P9]r\Qp$=չ~,29}0w8F{0_ic'FpUmRY[#Gỳv#TBr\e4#ΉoM ҧߒ%/KٝXr'^ k7RH,'3]x4ǻM 1 dpjǰqKXr&k$.4 @eZ#h^ ;*_|JBa3殏 7L3˘Y¸Y;Dx9&\Z.5(w}[F#t}]?WI,9<ӯ45Vކsi|%Tx9N4q)8P 4O`i9Wb7rү"eRȌW}FaƒF3&s;zTKsN Zk^65hlKkDd@45@u5&P&2MLd@42iebs9@?MLd@42Χ9 (.429@kO(&P&2MLd@42ie15&P&2MLd@42ie{jD PN[mzj h5@;5U+7C;no`Pn:g'A7 nooVhZ~w=;l?|p;Zbk{k;[[ް``ՆQ:fm xs99~yW=o۫/.aͷ7W7{v V3 [^hnkW7//.Nv[nнg]^_\^_\7Mռwo/\\za|?w~Qл{ݫuуF z7f kݽ0hۍFnzquu>b0ZMw~uszav'/OZe~Vu5ꛗ[;nmo>}rՋW˛ݽ/{nZpr^n{f{k{W/vsެ7;[[x8O^n;zUjN^^{Zj<ɫ~\_덃Wϟz~zr7睍f;ׂaPnmln<:w[[[Apzuେ_|U}o;/OƇʿO~ώv~'_>9n_=;t:/.`cڬ?zw^}{?}t}vz{pqOn;;fck}nhn:W7u^km ?_ Nn_zyr2Ax^][f}q{}2Z7{{ݻ ZgW77ۻN>|lnu{{_='GV= M[_^ͣGg/z?xfhֆNqq11Ӭ7j ͭzP`8jp0vZ?M#huݨAF>^v VmA5l6ZۨkV~{ڰ^kp0nh Í_zn;;;~WON7;^vFt/7ZV{;e 6[Zmj7qt?yՋ?|3ϿkmowZ7͍nlܞ_˓O6Zg{5 ?=Z0l5e{k7;{}Ƀ<|`0ק'gϞljaq4 ./o'_~y|hwnm~G?ڽw{o6[nӏ<={˳fZ˫v>y?W7_=9~νG/?msݿt:_p;WhԚGVu<|{gw jzݬlfރ~O:v[wFl:gg^u?z[ۃްnfw;7Ϟ~y}}[϶n$ׂß}i=~qnw7fwA7O_\]^zUl^_j|=yl|{osq {g[[~n7._v6MރV0mokϟ>{?ӋV-h.NOwZAm WVßy勓ˋ͝Y|FmѪn{;n}sw{kwxoG'?yo4[N>{~|{qm0|uvh||asvA?h\O<޷^,IDATt`h՞8<|{([a>ƿvjͭVuv^ZZPloonv:ۛãn7 zlZfԺ^^jwm^wsӹt`0j~v:Nj4pv:pXkԚmv{g\ߴV=no`kksg{llmmmln4`йm7[F{Vl57 ܿwl;7;[acٳώ_nZww7vo7' h7_۫o>G]\\\\\ޜtozAW/no{ay~}{ytO?wtpq~ՓVj5yV}~~Q{y綻nQzuzql;^]|G?p08>>77'O_=yv:=|{l?{f`ˋ^ݾvNÃ|'?Ͼx; vu}lַ67WnO>yɋӯOO^vo;޹hN϶|r{}}p Vj_/O{Fsxe#=;;./.N<[lm?Zl[WW;Eo8nɋӓfv_]\^{v{}l7jz joun[ۛO_;gNgPo6vڛ[|{ Mny7yoӨ7?a߿ll7ƿg^ڏ<~ztfQi|~ {{ys{{}gPϿyN·oj ư1^_nްQ?|Q:poɒ\?'}VU׷@C!4Z5@#n}>׀@>߈/a$۶Mh!i|_6%hy/~Uˇ0Fq&BI>?Z^].nŴ0xID E^㩙(hJqr |~P4Ͳa",is:]Di0͓EQuwm5ȵ6O,K7M= ` p'p7&m4Fh4F?o;.8bF1G[-wBp1mڮv';[aFy!NR1 53G#W@A9s9O)5v]<`!!B!BIF56"cl]κ0il4\-甒J((Py7TvGMgY6u7q~6H9wH\L8 UFeq8:.Phk<:}Dƙvb[G~zm,zmW/uo')իnϿkܗ] oڮB觯v~1=+з26O,)g|+q2o?aP7տ;ԧ~}{~:Vz1Ȼ6ݐt}|8T 2${!XձWo'\AQu% ?Ȗ,>>SULRq]ꓗiY SNRUR z]U| "V$`})a}|חnۇC>ίҘmmףHOՠ4 Ņxki))2t ")L2^x{<~~jvFJb1[b\vJ@I5 SṢ UiU%{7n[EjWVv4rB$CAl6Xz~~_aQ#J(C>?Z*0x N~ŋoj502{t}|)#:n* e9M߹<-3BG}?" ҚG$IXt}߱HM_;+wlj'B#Դݾ/Fj0xyL󸮛on+Ly_N$h&m!UZ?=4}C*.4b }~~nȣp]c5C2HI c:H(ɇ+@`0㱭bNK0~EGI0ҼrNt_\Lw')M[4gD$bX~b1{{ڭ_9!%8ͩ5x(B?9/{mΉ 90]L5Mb5oRMuCe|Jw{#5I뜵@@8VdEga4iڸ Ap'iZ̧݁P|ᱬá>ZDP1Kj~yѷJ<]`?U$ep< ]W;3<".e%0IjtADX͛X|)eθ?!fQADe?Xmv0b_D)IxI$H9%8Մ"Bn0/sJ@u}U549ex6ˬ64聓} Cvq̓4tΗskv=n0;9HPYֈ@qw n}& (8fv D )=-)mx2}w?LǤFh4FiFAPu=QQJ  &4PI$+k r> M0 >Y< ¶ڦRB)Ȟ RR FHB@#A2A: m[T"{dʨ3pJӉs7F5MԪ.ٛA[0a$=A4O?[LiU6<8Y_Fz]"t`J Hx?>EOM:?;,8IDYקJ*b?3OY.R~xQjMbm3!h[r.yPpg-oNSziDWiy]ҋ儋(JR%poc|}mFEXMyV|fxr~*d*w&QuuA(ugYCN)$H*UWmD" 4Fx"5˹w;1>;@y猄1!Eq ڬק>Di+Ψ`=>!h>DF".NRֶc4rМjEb Z?lTL`zȳP+- !{#6˛t^l`cXV4M6IℯβaXRYF*A]#R)J[붯>si6#xw<Y$q'gdDڞ{ߵ?ތ=Fh4FOry}[tIME !#IENDB`gxemul-0.6.1/doc/20060724-netbsd-netwinder-2.png000644 001750 001750 00000024735 13402411501 021027 0ustar00debugdebug000000 000000 PNG  IHDRdu'gAMA aPLTE:uMtEXtSoftwareXV Version 3.10a Rev: 12/29/94 (jp-extension 5.3.3 + PNG patch 1.2d){0 IDATxoF.b(Hv4.e "x/ in7to &b̦5Խ^?H0= Æ7z")ʖr_?Xd:ɕސMFnHDJ4@\Ch 8h{tݝOrۑ͟G,bb{eM%X'ARȬNy6Wi6Oi;V%ʏ>nvsl3:\~FU&Sgt3:mYVeNvt{~m9OlvlvN[괥^*VjFČ D5!4\%R1:'YǸ܈Dc˕4>@7˗g!5tKvO@@!]T*=-$H-$+RP3LxuԂ=魄Ȅt#ȃg>A?Z|qEѻ ݬb9@)6j0+|Ŵ>Bjc-XÅn1ռ)k[`P ~ܕRD ZbI}~ZMѿz?3K.H m~GQ+!n@FiN^}2PNɁ1Y ;]sgbG:My',ݬXDok'[߉&zpStϸ.;:"j { K}|օ, ԳNI'&Ec q;C)mAnm =f/O;G6w:E<_V5:<<~UZJ)RJ)RJ)RJ_*tB򧳿zޓTVMq+؇{ymb@߾XMWDPYQS$qX`͇=[W½9ӷqLַ'qjC",8ݳJ5bF_3/5րkfUDդ¦N2cy*ugU˛҅|[cRRj-v9xaoO$Bߗիȵ5Unagka֘'( Oz~48AąVMdf|.M?;;'H_jo*uz~tZ#k'jazxUi@,G Mgf-AϝMgfwM|GA> Wۥ@dDWjڼHtpV7;;l?eTbkEwԞbfL݂Sggq},80:D߰3>I<0j}ۼh:߯;JaUlZoã$\w1/5e`I?lpCC^N}kGBx`"鯝H])#!#Hak)0X訸L}CB%)&t.9ۊx%bQVEC\Uqa9Y0 H IlSM̡/ݷ{Y* .ICR0=Th$Amɪ[st{[s.b*I;3 p; 8^$Hy;Y5>-z8D WLTfB7: E `$KXɪ9.Z?{y˿J"" #)$tqn$$Y;6ZSui`H &7if0>jxR]~; taA$O$t'c'Vj9Y2TuYJΫ`D'X 4)K^Bǂdd ;bF @Q ]%B3KΡCUF`N  O E]Yr@DWv^K`> ")8I&*t[ {HE3'܋ #.K(JRI[ j/.Q]Dc 6NtU)% ")$W:jRIa2 1alfɱi.suS TB3)j$'!YœBgn*hk|o/͉^KO Tz4Zo0W4嬵v о +*ڨI"bP#v2RlD=3dQȲŘbegגY]}@ n uvz}Ӿ.//fAΓ n RJ)RJ)RKZ4V̎`nzav3qM8M=VqXx dƇ'7Ɠ䳰cc86aji`b #r [zm]Wl%*^K [/\:MkTLaG/n)6,_EƇ6PvkV*KQoRYBw:'B0jkjmݓN}hi8~gW,uM.|Pߔ0ul~sƇZv0K߭)} +QeΧ eLlַh/4GO@и }C˦UWұeS :fe2mJ Y #8C0|k5-\f OlGo(89C^wpc)9tSZV8zVMK- <~)::սac5+xàk`f]>8 !Fcz=@еOj\l2W/eЮAvfEZLj72FC> k7 `U(}PW*RJ)RJ)RJ*ĕcjxu]<F{v!R} q;Zc"zQ޾^q߯ E>?&rnH)|o¤b#7'1{tCL4ىwH!x/bܙm^\9E!=bT ~? ސnCw'FO{N>5Q}usnʏV4ib͒RJ)RJ)RJ)9;i*,N،YX?^/֣,ݚ UaҒ8JKU!/l#S 7kWw(_wqAh̡h=I\7Eiz]=#{D7>Z0o/!=tQ0jA.u1br&)oG.n|<`"/6?:C{}+M q X#PG\;NOΪ8Q6&:< mv}{uncڅ8.[ac eu;)hRC8^G춓WtFBHEdK.pL]Za1}K0Zuz >Av㌴ڣDR UisxXϛstK' }B5T_M/COsMjNX'=WɹT]vg辦74eQaw 5 ”?(91(qö?ϣ(!Ɵ3]]P{0.cƘp{qԱ]v8{2(q* ~eD uI_&*ͧ`$2%%  OK75t/M+At#57?j!CO˙уѣ> 37bPsџx%Ӳ_i+Rm#fFD7 ˕ŌL,/Ԃ|)#S-ˋUl ,&NLљX^hYLVfLcD-(WJ z&VIAfT2zX^cb|}Mv͡TO_;( ib| >~8U5RDW$YttCB|Sz&ה_1]E45똙l1zhJOcy1aK-(WHGR +X^pv1lZPᓡj}du_fw+>@w󏟡o3.E~("^UԊ}+  ye?%:?oE) L˚ɳ>Qb,O[6' CʪW&e8r+H,^1,YoxB5yt+WRέ7]^)⫚~E3I_6ٹtzw? s-f7+oV3δN~ +ܰ3_[cS tytydC~/xd}(?ֻ| jm?|3xXTVvC5HoQ{賛}^V?P0iVC:ԸYQq3v+(??W81v1}v:n皞l~t" C]K7tRlz: 4>f6׆1n^VWCow+B]wGoVYhg6;~A@Mv~2@D_ܧu?V7Zhg6;@wFSTQvNFGQ$%D`-o㿅ߠvf$wLJJ -J~EptxW^㥗RJ)EuKhku꜃`k:ٳjGSz箵J8:>5Nu*^9m?PmWmpR"hUq^|ӵj}3ڛ+ttښ׭zrky%#8S:pݫu78G,Z._e^ IDATnORJ)A9ť EBhJ{|(o/起\,}_:`tO&/-Ǖ¹`VH3j3t@?R93Xr-EycAM0E2fkTTaGR!eBq\XM:eYIVvB_ܹй $]w1B/ nHgQ ϝDo)1=~)h+@A "=~U gjn[Ͼ :Vqjd[j75zPz^U* _VMۋR9(pN[ Zn2qjm)eHJKjAaUB׼h)1c{nIͳ jmo¤Dz|~jWcnR~2S\pU8} }"T4>z^F!tuIF4@lo:K<rpEukcꁐ+bꁐ+"B ]fB+Y]j*_S<\t6^h5ZO=pEO#cڲ,j1NMPZ%2ʧoЊ^)L↔ޕi,pn=&Hot)L T,=6}KmsKpH7rA2Tʃ_eaw)UZ6898&8؄k0[ Yn_`FVc|UiQI6ٜ 0mXe@7 MZ3^~#? T_8xΥ^#ǔ2\Zٜ {ؙ´eպd\^| /n\+/`qw׹hr-ME̕[>SJƍRdԭ!ֻt3gCk6qM\RgH =>B&[ ևKc^YN]jzIb:[=<n>@T]S*ӷ0Jrv3;z\|B3l+]&j#Z{է (;r~*SxV5bx<2"7ĵU#TYmw*f;|Ek)ezk,N7DSAӆsJem!+jB?הNr?(nD9bu6gf:[]y<%H]g O SX'c͛SB7=+YOTbm)ÖbY=iOg(Eыfz1lۜ&^6'ҋ'g z{P==(I}J)yĊ2XARqq8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2).I IDATxٕ8]#  C_ `&Cy)L?ؿx'/|hb1(5/s_G?> 8Si?¿]ď1c3c_ݯwygo|?;,i Mb2K'}5pn{q{؃~o>])g:75ύ|Nt:Oa0  T?:P2{sc0| x~U_:kտo{? 2{p=HctyM0\_wگ`K{ _eT=U ߾b`OAK\с0@25߫U+p<|;N38pa ˿|˟75e)~bp .Nb|و^ :{z?h0 { c8_qov3 %"~b1 Ƒg\ _2Š<]^qƎO$-~ו23|_C@90x #111F$߇/$uG?v">vbb@ 11111111111111111111111111111115{laC;A3m9.Ylx m$8rxx\ r#_Cɐ;tZ}^Xv RixC/ u)'`7`a 0㵝Y F@r]1_ "Y $u0Hi hp4 pߋd!Ơv)``^@Gh#zC#`G<'Ŗul:33E- Aznb'1oS0uD }x p8рF hĀH{6БljةTu;d y,]]KCzJ+\"moH`   G!M yPYj=><ň1`N!1e%/ 4b@#<!>k G > Sa1(dH%P5ԡ>N{+ 0$gTmdL=uà6-h4hP.b7%-:$!Ԝ)J|2w)h~@!:b&l;x:9$b`^^hĀF hWP'3]n[-}*Q~gw^v#0ݨ;bG[KnXWl~&:1(K]`$[es!K3aR_S/YĠJ6N^k%ĝNrj(Ԝ61xVeQhRKov//?JLhIZ|#'aPH~D_[Xk)DA||ݨK{ lm0V1xh0*/c`魝ɠi$<,q4x5b|P  f1u4|} yhqek-P:f Tp;`壍ksCEȡ0E3_7R۬‹Ј31h$lXPAv} dy90eR7`X~18eiUPE€++c 5C C4SF 8 s /. *18">4[wJCE0ԔF/܅p4dnGߐ%7!a9V)1&} |bGQ$bPBZ $, 1bݟg pBqhUgj.Ld`(&:s ΄b@ 11 f t˪k$V5g5'mc=c0ݨGQrl$}eI0+\_W* պ'x`N ȥ,i `"a1x(z%Hu1Y6܆,"5Pi0hڋ#PĶpgF k\̾[Ca(Hym30{KMI!>ZK= PEs#E#c]0oQ#PG j `iz iN18!$D@uڍ1p(zۛb]0hRI4;nC!$`-`5d& J_2bhH;h5b`@hn0@"b ̛1aRzc݃fk'\˶|o-.nw:`NB-3CӖp^;%4b@#4b@#[7&毓4p'c~A{WSaik0=b ښFoF'UӶ2 KR<td݃^PGѰW"E,7dZ M;]7@0xnL "ʠ`Nv䙨3 z q`s>9VaZ!閡 _|Y b0n_ 7AiDV=3Ěb] b ‚h:y wk^ ])R!z/`Rh <10}yf4?!h7;0H27t'" `05`2zf  6{  cLb{70,O[!7-e$#1K8mm1x P6l?FH\m<1b\w47S1Xa0^~(ЈβnrڋzZ_Or ZG\-^ ub^sn0LV0Hr`}!p.3e ށޮO4%q'FLE!jE/+X%j\CO"4F6'p4"Je 1QCM{iQԖv &uh)@ո`+-Am?M1X /VJNp_ 2`^1xh`b oOZ`  c`n@J`:1Hބu|57Ma3!I~&!j3{$i  RwK Z=1b@ 7R?`a&'`rθkوA R`:i{ڞ#еL~Q16j9s^r2/tP9q!`6?DԶ] 21s`omʪSQs(>?bw!?ށbBFVMKa|lrPpN'ڈL*k)0d--}Qȸ2ێAG?:X~@[c-Z!З>\K!=51+_y' hĀF E1Љ/onxuY&Y aL{mNՁk " QWvx w5{ u{LwJݑG {]O߀C@-c4Hbo ."1n@Dliu߀<`FVX ,,(W?! npEC. 4b@#<=,z<;nϬ[^ $Wpnl yA#asa❯mI\eq_qw Telh؈'atى^ ͷW0ȰWۮ`@ 6ɨUC-ëRz Pظ Lr$wv u6 ȸ6ˆz +$kP"z ]ޤ:SP]1$hAs(]im&010? ӭRyZc.}|7 CA[!%Iӹ-^dh1Pu[)PU릞<_HMuݵ= X?ݘňSdbuߣ;&ʤ^L0mx{8&r Lf&)b l\D$_zakB <{Xoa8ߠ>`kxK bM70]MrZ=IY8z({%3mZmDǿY NB``Z) x 4MPr uJҌG92ūi4k#Ac!hZ]^z^C ^<7q{DNGKx8S.>#4b@#ɄQ_>]0h'+k=ab 0+xK Bц|B`7o $sf0H Wfx lV>!`_>/ 4b@#Fm1hO\5VQatV?2}^:ٱI4',RP@mc 4խp$>\D|vls[>=0D9tn 6e -|A}PTLf_]K|4({{>''e_dC={u v1 ʫJ@V/s!0z<=~=0БwشbP5 7Sw1ysvIr=FoJB Aڧk^>΁_]݅9Ԏx<ph_tο PE8 xC|ݺBI9X;[C R.?G0m 79Xo~AylA$ta1}\k_I: k|m2ђ빟7 Ok^w!d7;3a<ѬW}IXg/rp0 l ANb@<F :51vc2G#<8xwZ и~<18>w@g?!5!{5(Ј>lsi9*яOnQmĂ6CZ8G9w<! T>'2p88i(j\ q8Tl muia#MMiF Av4 ^r$N0н] $)J @ ·E A @ NA5P͉0l.b5HufM!hp08"1 ĀF hĀF huS]|^{E@YAԩsfج>Tl %lfFBmPw/a5k\E.@@ɸ=VGdv i)@ iVj,@`0XY 'eAd."Yf1xz0x. &ADۘ8ALn/&A ime{- |9N 6!|b@#4b@#)wC 8Q$Ā(p|53_c1%wI PF hAPC1М- n@#4b@#4b@#4b0hLvY~g 8Vk \<m]^b0'g`F ~~gP6vJ;6?lg{F ʱNsU;HE܎A j'dw3-Rt:̈́04A9XY:0{0m1x> ?Ac06(Q18@qU >/YJs'Q1X>f\q@?0F9oxQ1}5+E70*@ۜZݲ3)w0+b^!q)=xPO!4oa@a!!ǘ.)*٫2z $1fa5s?T'drޓz sL]`p AHSOAs 18ΟRIDATe./!x p c9h0(ECF c& zD߀ Z>\z Or1K{3`n`hC 'ϝ'xQ1}|#q1s/Ǜ69 `kj_YH=y6.Ĭa0bpbpm5L Ta-9D7N㭮C7A @P%O${vDCMıS2{H0xKh M _+WbPccQݿa'քAwexBKq% n(b$=?p /R%H\aV0` @& 2F%d}{x_mg`e1]#7 5)R$INb}Z/޼~\CǠ NYr}0S^6f#!_^ZWbb@x f 1ǮllHZ ]ǡq'puٯa.9,a)1b K\W_K 4/5J)j"(8h~Q1ܚ겳@DAG b %'`+XPVZqsNA n mrg6co.,\0uo JY1G%SKAcJZa$6s}=ǡ0+1`[a{V}f1GNE=h\^~^;/7]EӧVWO{8}}9AζG rQ !(iABihFK{#@7=NP3N_;ԍqu?".(y;A3rutr:)b{" X@sJވAJ1HiĨԃ]ī07cWb-`": 1 xC_3!x)L`@3V <7XnH˯ˇ@n@n@|t&8EF hĀyŸ306?uD/^7Bˎ!h];|418<n*i’AyM=ArTDmf@x9n;]߉ja^xxRGNA `ezAA j AkLF <Ww{QG0`F `9AS;GZ> u ̛yA1G^u5y<àQ@݂àQ@݂(Ј>sz 1o{o/ ~߼5NQ'\UOaMυ5¥x];4\c1Nd aʾF]@W,`.D7۹x*.1c* T3!7,Qa|oyA_Pn;?<=vդ&4"fB,oRlq,o1ءo X hcmںc{^ cpi=V*"os~FMx[{qN^^Ybqȣ0^̶7(ak` &L7]#1 x}_kA o*] 7 J-󃸎tb^DY!h6bV0O*}GO>I> sq [KB9GixyFiĀF h] `Ǒf a;@ ѧa0t05Sg0P\o $K#10p1 @}I`. 1( hĀF 1 4b@{4\r8H毯r] =_J1Mf->V[)ݯ-;T,60)ӻdϯhIiKbmôgLwk5˙S'%6cB7]l+;R["w2ӻ״u˩ b*:u$*ze0X+m ?ڲ Q`F+ Zx[m XL67m/ƶ$ݱ;+ ]0z$5eue-nn G2` }>;V~n~vIcR)olokK7h13`?/8ڨ5P40H2X ۚ|7%|_Wz}`e17m9k/lh-}ݠo AnD|mh 2{XytyC f0%wl+,V}]o, zD[W<a[/l }G`fʹ|1,Ůyj)b0X]7 hصƭUTG -,Ů:1X]`S ͺصƭKcX^ЈЈЈЈЈЈ1 ĀF hĀF hĀF hĀF hSi:4mVm4v9vplf?o`B!tU>-,Kmdů#k1c0 nk1s_d/ yl0n=~k&ðn9FW{ -t1TmAKA6E\j^5` v>إfI=J3sۂMQUucaZXO C"ߠ: ]A+m(ǔ@c_CyXBm`]K?d/Աms$WeTA]9S(% W׾ɜ_lW6` XHk:,_xnz $Oj*d}M'5$6zUױA{ܦ@ Ҏz m'| dFI0TηsQ1}/'`% _"9Po8, @]>ea 9ھܽkȫ{KOe.n`5kȪ=rqu N?Z>gn3hUڐG"xpE <:k{G[svj. %>04A[3}sHd` y\c^LaBWށ``.4$ /ȦE`Rf:C0кAaru _uB} E@bC10q(T*Ĩ`"RnmK.v=IhXwV XռA8A[fo1(EF hĀ, Mq[+6cn+1X6]j1,Y 1@5Qn9MUҵO3mǰ;܂bP C%',0J}0,x4(qW3F1_`\$ Nfn/ ZG4`nGoVs![aeAee_"b -U :$ s ^|4q24yUL!0pNO 6b<b'@ hĀF hA]'^Vt1`ipc0jVz `>Up j4rUVS޵d V,*aQAu 0HS5U"h+h P⥾E>3OXWwm^K{2WG'm (Ј>pˆ#߽t; Ùgp4 t|+1X_ǥ/ yC X`Wf\ }]:;  6SؐoPd 0|L ̓q K."MoZ70_|`|-7XǏ{ n_s_p \3<\hĀF h8a v\hDy`K`\0}0h'v5dٻ?bpB^7ℋZ;ao,$)&_1X4a4H^r4xq3X#Fb0@1`3-`!3u0,zb|bP~ĀF hĀFtR>7q nxsbulsIgbp$ ,#ȍO qQ kuT?f/ԍցGK ^"n7\:UC :mpo0hu+lS j;\|!hlp7ttn'%bpf l;;`A |ǠsiovBiWBqoP`떏 R@k.ga2uR \(ؿ$@;5B u\zËЈ'tvbgڶ6p<MA{ǤR1h-lnJՉe<܁&)=mYAŲI"*#^(휅>EQOA0 ^Y\Bgq9퐏Ap!<~E@j4z屺0hhS0ز]0o@e uwrIxA:,>n1xx "y<5}|Q^;ad?. |P}uޱZ;S( ?07|q`}%`L xM&|CEF hĀFtL\ygb-ߠ%|-πr 6\u<S/ yC=,eBD]M#k.1je8DA1ߠf,5y@  b-1ga2/l)su& ؐqlj~ibn"Ƅ7Ş:e(}tU7Ѯ(v]v Kma^ j h@5l< 0&h>Cu^ xQP`QolcKa fi/P~ B neG RuC5@X^܄M1gA/U[X'h xȞѠV{\h!O@^h3vVK=Ss!yn#\\kRƂnW|-r`0|49~`7Cڧ=y0V8^kU0xЈ}1.9ކ23QHXc@{*M ̮")`.ЎNd ajgc \gwqaXsnsL )qA30P=d]լK+ڞ EE@vs0Z8ߎ>g!wPZ I7;I_@W/` \楕pW3;t  H'Tbpj`A 0AAa3_(rU:"r,`5b.hg}Iec\KzE?6^tQb@ mFN>D=l ] AO`usz/RKAT0&E <`c|W^^p, 2(zPw k >A9|^B $# %(p ."@'xzJ//Aw>b-{_&uhc0dSOǭwM`HNLm/(NUƜv Zdҟ~ -xXz. A(1`WO# !9nx_(@``3@ /t5 D= -xv+7kev:zI|A&n/YM49m=I=db0Y~}.4b@#'b|bo|OĀĀĀ4 h  4b@;;11k3O+,sO.X U07Jw'2ʗ`rjJ_5*4j*X̠o,A΁Ffk' { z@N!BmOサ8h Y ܟȚ 0}(#AN@ "VH g0 9ߠ֧^&|-hs.q~ ky"c: vAC AZ'P aՙ5~Āb@ ЈЈЈЈЈЈm϶?-ۿ~s d C=O WA=n G 6tIME  ںUIENDB`gxemul-0.6.1/doc/components/component_cpu.html000644 001750 001750 00000001724 13402411501 021721 0ustar00debugdebug000000 000000 GXemul: Components: cpu

GXemul: Components: cpu

Back to the index.

Back to the component index.


cpu component

This is a base class for CPU components.

Examples of CPUs include:

Source code for this component can be found here (and Doxygen documentation here).



gxemul-0.6.1/doc/components/component_m88k_cpu.html000644 001750 001750 00000001631 13402411501 022565 0ustar00debugdebug000000 000000 GXemul: Components: m88k_cpu

GXemul: Components: m88k_cpu

Back to the index.

Back to the component index.


m88k_cpu component

This component represents a Motorola 88000-like CPU component.

Features that have been implemented:

  • 88100 disassembly.

TODO: Almost everything.

Source code documentation for this component can be found here.



gxemul-0.6.1/doc/components/component_mainbus.html000644 001750 001750 00000001702 13402411501 022564 0ustar00debugdebug000000 000000 GXemul: Components: mainbus

GXemul: Components: mainbus

Back to the index.

Back to the component index.


mainbus component

The mainbus component forwards address/data requests from e.g. CPUs to memory mapped components. A typical example of a memory mapped component is RAM.

Source code for this component can be found here (and Doxygen documentation here).



gxemul-0.6.1/doc/components/component_mips_cpu.html000644 001750 001750 00000004040 13402411501 022743 0ustar00debugdebug000000 000000 GXemul: Components: mips_cpu

GXemul: Components: mips_cpu

Back to the index.

Back to the component index.


mips_cpu component

This component represents a MIPS-like CPU component.

Features that have been implemented:

  • Some instruction disassembly.

TODO: Almost everything.

The following example shows, in addition to starting GXemul with a template machine, how to add mips_cpu components to the configuration. To add a specific CPU model, e.g. R4400, type mips_cpu(model=R4400) instead of just mips_cpu.

$ gxemul -V -e testmips
GXemul (unknown version)      Copyright (C) 2003-2009  Anders Gavare

  mainbus0
  |-- ram0  (32 MB at offset 0)
  |-- rom0  (16 MB at offset 0x1fc00000)
  \-- cpu0  (5KE, 100 MHz)

GXemul> add mips_cpu mainbus0
GXemul> root
  root
  \-- machine0  [testmips]
      \-- mainbus0
          |-- ram0  (32 MB at offset 0)
          |-- rom0  (16 MB at offset 0x1fc00000)
          |-- cpu0  (5KE, 100 MHz)
          \-- cpu1  (5KE, 100 MHz)

  accuracy = cycle
  step     = 0
GXemul> add mips_cpu(model=R4400) mainbus0
GXemul> root
  root
  \-- machine0  [testmips]
      \-- mainbus0
          |-- ram0  (32 MB at offset 0)
          |-- rom0  (16 MB at offset 0x1fc00000)
          |-- cpu0  (5KE, 100 MHz)
          |-- cpu1  (5KE, 100 MHz)
          \-- cpu2  (R4400, 100 MHz)

  accuracy = cycle
  step     = 0
GXemul> 

Source code documentation for this component can be found here.



gxemul-0.6.1/doc/components/component_ram.html000644 001750 001750 00000003221 13402411501 021703 0ustar00debugdebug000000 000000 GXemul: Components: ram

GXemul: Components: ram

Back to the index.

Back to the component index.


ram component

The ram component represents a Random Access Memory.

Note that also ROM (Read-Only Memory) circuits are emulated using this component. A ROM circuit is a RAM with writeProtect = true.

The following example shows how to interactively add a ram component to a machine:

$ gxemul -V
..
GXemul> add machine
GXemul> add mainbus machine0
GXemul> root
  root
  \-- machine0
      \-- mainbus0

  accuracy = cycle
  step     = 0
GXemul> add ram mainbus0
GXemul> ram
  ram0  (0 bytes at offset 0)

  data                = (custom)
  lastDumpAddr        = 0
  memoryMappedAddrMul = 0x1
  memoryMappedBase    = 0
  memoryMappedSize    = 0
  step                = 0
  writeProtect        = false
GXemul> ram0.memoryMappedSize = 0x400000
GXemul> root
  root
  \-- machine0
      \-- mainbus0
          \-- ram0  (4 MB at offset 0)

  accuracy = cycle
  step     = 0
GXemul> 

Source code for this component can be found here (and Doxygen documentation here).



gxemul-0.6.1/doc/components/component_i960_cpu.html000644 001750 001750 00000002661 13402411501 022471 0ustar00debugdebug000000 000000 GXemul: Components: i960_cpu

GXemul: Components: i960_cpu

Back to the index.

Back to the component index.


i960_cpu component

This component represents an Intel i960-like CPU component.

Things that have been implemented:

  • i960 Cx disassembly.

Things that have not yet been implemented: TODOs in approximate priority order:

  • Disassembly of instructions for variants other than i960 CA / CF.
  • Implement register dump functionality better (specifics about SFRs, AC/PC/TC flags etc).
  • b.out file loader: symbol support. (Not in the CPU component but related.)
  • ECOFF file loader. (Not in the CPU component but related.)
  • Start implementing execution of instructions.
  • Implement some kind of "short diff" format for execution, rather than the verbose format of today.

Source code documentation for this component can be found here.



gxemul-0.6.1/doc/components/component_dummy.html000644 001750 001750 00000001427 13402411501 022265 0ustar00debugdebug000000 000000 GXemul: Components: dummy

GXemul: Components: dummy

Back to the index.

Back to the component index.


dummy component

The dummy component does not do anything. It can contain any other components. It is also used for the emulator's internal unit tests.

Source code documentation for this component can be found here.



gxemul-0.6.1/doc/components/component_cache.html000644 001750 001750 00000001537 13402411501 022177 0ustar00debugdebug000000 000000 GXemul: Components: cache

GXemul: Components: cache

Back to the index.

Back to the component index.


cache component

The cache component represents a memory cache. Caches are usually connected to CPUs, between the CPU and main memory.

TODO.

Source code for this component can be found here (and Doxygen documentation here).



gxemul-0.6.1/doc/machines/machine_sgi_ip32.html.SKEL000644 001750 001750 00000011477 13402411501 022320 0ustar00debugdebug000000 000000 The sgi_ip32 machine template tries to emulate an SGI O2 machine, for experiments with primarily NetBSD/sgimips, OpenBSD/sgi, and Linux for O2.

NOTE: THE SGI O2 EMULATION MODE IN THE NEW FRAMEWORK IS NOT WORKING YET AT ALL! These are preliminary instructions on how it may work when the new GXemul framework, and in particular the SGI O2 emulation within that framework, is complete enough.

The new framework is planned to support things such as emulation of real CPU caches, and RAM at a non-zero base address, features used by the SGI O2 (and its PROM).


Experimenting with a PROM from a real SGI O2

This requires that you dump the PROM memory range from your real SGI O2 machine into a file. Using a serial console hooked up to your O2, executing the PROM command
	>> dump -b 0xBFC00000:0xBFC80000
will dump 512 KB of the PROM range. Make sure you capture all the output into a file, and then convert the result into a raw binary. (If you don't have time to write a converter tool yourself, there is an example converter in the GXemul source code distribution: experiments/sgiprom_to_bin.)

Assuming you have extracted the PROM from your real machine into a file called prom, the following example shows how to start up the emulator in the paused state with the PROM image:

$ gxemul -V -e sgi_ip32 raw:0xffffffffbfc00000:prom
GXemul (unknown version)      Copyright (C) 2003-2009  Anders Gavare

  mainbus0
  |-- ram0  (128 MB at offset 0)
  |-- prom0  (512 KB at offset 0x1fc00000)
  \-- cpu0  (R5000, 100 MHz)

cpu0: raw:0xffffffffbfc00000:prom loaded
      Raw file: entry point 0xffffffffbfc00000
      loadable chunk: vaddr 0xffffffffbfc00000, 524288 bytes

GXemul>

As mentioned above, nothing works yet.


Legacy framework

As the new framework is not working yet, and especially the SGI O2 emulation mode in it, the following notes about the legacy framework may also be of interest.

Normally, a dump of the PROM image from your real SGI O2 is not needed, if what you want to do is to run guest operating systems in the emulator. See the following sections of the documentation for how to set up NetBSD/sgimips and OpenBSD/sgi:

In order to experiment with a raw PROM dump using the legacy framework, the following command line may be used as a starting point:

$ gxemul -QXeo2 0xbfc00000:prom

-Q turns off GXemul's built-in PROM emulation, allowing raw PROM images to be used. -X is used to display the graphical framebuffer. (-X can be omitted if only serial console is what you want.) And finally, -e o2 selects the O2 emulation mode. 0xbfc00000 is the standard ROM address for MIPS-based systems.

            

The photo on the left is from the real machine. The screenshot to the right is from the emulator.

NOTE: The SGI O2 PROM does some hardware tests during startup that do not work in GXemul, in particular cache detection. So right now, there is a hack/workaround which skips cache detection in an ugly way. This has been verified to work with PROM versions 2.3, 4.13, and 4.18. For other versions, it may need to be manually skipped.

With a IP32 PROM version 4.13 for example, if the hack is commented out, the cache detection routine at 0xbfc05180 must be skipped:

$ gxemul -p 0xffffffffbfc05180 -X -Q -e o2 0xbfc00000:prom-4.13

...
when the breakpoint is hit, type:

pc = ra
continue

If the 'console' variable in the PROM's environment variable section was set to something starting with 'g', output will be graphical, otherwise it will be to serial console.

Note however that almost nothing works; most importantly, SCSI is not implemented for the SGI O2, so the emulated machine will not be able to boot from any kind of disk or CDROM. Audio or video hardware is not emulated at all yet either. Also, while the graphics emulation has been implemented well enough to run NetBSD, OpenBSD, and perhaps also Linux, other things may not work.


gxemul-0.6.1/doc/machines/machine_cyclonevh.html.SKEL000644 001750 001750 00000005030 13402411501 022657 0ustar00debugdebug000000 000000 The cyclonevh machine template tries to emulate a Cyclone/VH i960 evaluation board.

Its only purpose is to allow experiments with uClinux/i960 binaries. See https://web.archive.org/web/20010417034914/http://www.cse.ogi.edu/~kma/uClinux.html for more info.

NOTE!

A binary (vmlinux) can be found on this page:
https://web.archive.org/web/20010417034914/http://www.cse.ogi.edu/~kma/uClinux.html

However, there is also a binary at http://www.uclinux.org/pub/uClinux/ports/i960/, which is corrupt; it seems to have been uploaded/encoded with the wrong character encoding. (At least it is broken as of 2016-04-18.)

TODO:
Everything.

Until there is an ECOFF file loader, the vmlinux binary image may be experimented with manually, using the raw file loader.

$ ./gxemul -V -e cyclonevh raw:0xa3c08000:0xb8:0xa3c08020:vmlinux 

GXemul (unknown version)      Copyright (C) 2003-2018  Anders Gavare

  mainbus0
  |-- cpu0  (25 MHz)
  \-- ram0  (4 MB at offset 0xa3c00000)

cpu0: raw:0xa3c08000:0xb8:0xa3c08020:/home/debug/emul/i960/vmlinux loaded
      Raw file: entry point 0xa3c08020
      loadable chunk at offset 184: vaddr 0xa3c08000, 774924 bytes

GXemul> cp.u 
0xa3c08020 <- 58a0198c            unimplemented: 88 
0xa3c08024    64a50294            unimplemented: 100
0xa3c08028    58a0198d            unimplemented: 88 
0xa3c0802c    65a50294            unimplemented: 101
0xa3c08030    09000700            unimplemented: 9  
0xa3c08034    8c803000            lda               
0xa3c08038    a3c08000            unimplemented: 163
0xa3c0803c    090077a4            unimplemented: 9  
0xa3c08040    08000000            unimplemented: 8  
0xa3c08044    00000000            unimplemented: 0  
0xa3c08048    00000000            unimplemented: 0  
0xa3c0804c    00000000            unimplemented: 0  
0xa3c08050    8cf03000            lda               
0xa3c08054    a3c08064            unimplemented: 163
0xa3c08058    5c80161e            unimplemented: 92 
0xa3c0805c    5cf01e00            unimplemented: 92 
0xa3c08060    84041000            unimplemented: 132
0xa3c08064    0a000000            unimplemented: 10 
0xa3c08068    74696e69            unimplemented: 116
0xa3c0806c    00000000            unimplemented: 0  
GXemul> quit


gxemul-0.6.1/doc/machines/machine_testm88k.html.SKEL000644 001750 001750 00000017233 13402411501 022364 0ustar00debugdebug000000 000000

The testm88k machine is a GXemul-specific machine used for simple tests. It is based around a Motorola 88100 CPU, and some simple devices.

To start the emulator with a binary built for the testm88k machine, type:

	gxemul -e testm88k filename

You may add -V to start in the paused mode, and enter the single-step debugger.

Example:

$ gxemul -V -e testm88k test/FileLoader_A.OUT_M88K
GXemul (unknown version)      Copyright (C) 2003-2010  Anders Gavare

  mainbus0
  |-- cpu0  (88100, 50 MHz)
  |-- ram0  (32 MB at offset 0)
  |-- fb_videoram0  (15 MB at offset 0x12000000)
  \-- rom0  (4 MB at offset 0xff800000)

cpu0: test/FileLoader_A.OUT_M88K loaded
      a.out: entry point 0x000012b8
      text + data = 4096 + 4096 bytes
      symbols: 1260 bytes at 0x2000
      strings: 1070 bytes at 0x24ec
      13 symbols read

GXemul> cpu0.unassemble
<_f>      
0x12b8 <- 67ff0020   subu    r31,r31,0x20 
0x12bc    27df0010   st      r30,r31,0x10 
0x12c0    63df0010   addu    r30,r31,0x10 
0x12c4    58400320   or      r2,r0,0x320  
0x12c8    58600258   or      r3,r0,0x258  
0x12cc    243f0014   st      r1,r31,0x14  
0x12d0    231f0008   st.d    r24,r31,0x8  
0x12d4    cfffffe7   bsr.n   0x1270          ; <_change_resolution>
0x12d8    f6c0201f   st.d    r22,r0,r31   
0x12dc    cbffff89   bsr     0x1100          ; <_my_random>        
0x12e0    f6c05802   or      r22,r0,r2    
0x12e4    69b60320   divu    r13,r22,0x320
0x12e8    6dad0320   mulu    r13,r13,0x320
0x12ec    cfffff85   bsr.n   0x1100          ; <_my_random>        
0x12f0    f6d6640d   subu    r22,r22,r13  
0x12f4    f6e05802   or      r23,r0,r2    
0x12f8    69b70258   divu    r13,r23,0x258
0x12fc    6dad0258   mulu    r13,r13,0x258
0x1300    cfffff80   bsr.n   0x1100          ; <_my_random>        
0x1304    f6f7640d   subu    r23,r23,r13  
GXemul> cpu0.registers
   pc = 0x000012b8  <_f>
   r0 = 0x00000000     r1 = 0x00000000     r2 = 0x00000000     r3 = 0x00000000
   r4 = 0x00000000     r5 = 0x00000000     r6 = 0x00000000     r7 = 0x00000000
   r8 = 0x00000000     r9 = 0x00000000    r10 = 0x00000000    r11 = 0x00000000
  r12 = 0x00000000    r13 = 0x00000000    r14 = 0x00000000    r15 = 0x00000000
  r16 = 0x00000000    r17 = 0x00000000    r18 = 0x00000000    r19 = 0x00000000
  r20 = 0x00000000    r21 = 0x00000000    r22 = 0x00000000    r23 = 0x00000000
  r24 = 0x00000000    r25 = 0x00000000    r26 = 0x00000000    r27 = 0x00000000
  r28 = 0x00000000    r29 = 0x00000000    r30 = 0x00000000    r31 = 0x00000ff0
GXemul> step 6 
step 0: cpu0: <_f>      
              0x12b8    67ff0020   subu   r31,r31,0x20
        => cpu0.pc: 0x12b8 -> 0x12bc
        => cpu0.r31: 0xff0 -> 0xfd0

step 1: cpu0: 0x12bc    27df0010   st   r30,r31,0x10
        => cpu0.pc: 0x12bc -> 0x12c0

step 2: cpu0: 0x12c0    63df0010   addu   r30,r31,0x10
        => cpu0.pc: 0x12c0 -> 0x12c4
        => cpu0.r30: 0 -> 0xfe0

step 3: cpu0: 0x12c4    58400320   or   r2,r0,0x320
        => cpu0.pc: 0x12c4 -> 0x12c8
        => cpu0.r2: 0 -> 0x320

step 4: cpu0: 0x12c8    58600258   or   r3,r0,0x258
        => cpu0.pc: 0x12c8 -> 0x12cc
        => cpu0.r3: 0 -> 0x258

step 5: cpu0: 0x12cc    243f0014   st   r1,r31,0x14
        => cpu0.pc: 0x12cc -> 0x12d0
GXemul> cpu0.showFunctionTraceCall = true
=> cpu0.showFunctionTraceCall: false -> true
GXemul> continue
[ cpu0: _change_resolution(800,600,0,0,0,0,0,0,...) ]
[ cpu0:   _fbctrl_set_x1(800,600,0,0,0,0,0,0,...) ]
[ cpu0:     _fbctrl_write_port(1,600,0,0,0,0,0,0,...) ]
[ cpu0:     _fbctrl_write_data(800,600,0,0,0,0,0,0x12f00000,...) ]
[ cpu0:   _fbctrl_set_y1(600,600,0,0,0,0,0,0x12f00010,...) ]
[ cpu0:     _fbctrl_write_port(2,600,0,0,0,0,0,0x12f00010,...) ]
[ cpu0:     _fbctrl_write_data(600,600,0,0,0,0,0,0x12f00000,...) ]
[ cpu0:   _fbctrl_command(1,600,0,0,0,0,0,0x12f00010,...) ]
[ cpu0:     _fbctrl_write_port(0,600,0,0,0,0,0,0x12f00010,...) ]
[ cpu0:     _fbctrl_write_data(1,600,0,0,0,0,0,0x12f00000,...) ]
[ cpu0: _my_random(1,600,0,0,0,0,0,0x12f00010,...) ]
[ cpu0: _my_random(0x8eb1badd,258,0,0,0,0,0x96219136,0xe3abd777,...) ]
[ cpu0: _my_random(0x6c3eea31,258,0,0,0,0,0x96219136,0x9a0bfc0b,...) ]
[ cpu0: _my_random(0x159ec14d,258,0,0,0,0,0x96219136,0xd96944e7,...) ]
[ cpu0: _my_random(0x56fc79a1,258,0,0,0,0,0x96219136,0x30a2827b,...) ]
[ cpu0: _draw_rectangle(381,513,109,185,0xbf37bf3d,0,0x96219136,0x1c9221d7,...) ]
[ cpu0: _my_random(381,513,109,185,0xbf37bf3d,0,0x96219136,0x1c9221d7,...) ]
[ cpu0: _my_random(0x93071c91,201,6d,b9,0xbf37bf3d,0,0x96219136,0x2d57546b,...) ]
[ cpu0: _my_random(0xa2c2692d,201,6d,b9,0xbf37bf3d,0,0x96219136,0x38c76ac7,...) ]
[ cpu0: _my_random(0xb7525781,201,6d,b9,0xbf37bf3d,0,0x96219136,0x96563e5b,...) ]
[ cpu0: _my_random(0x19c3031d,201,6d,b9,0xbf37bf3d,0,0x96219136,0x1fd1a3b7,...) ]
[ cpu0: _draw_rectangle(17,101,481,117,0x90449ef1,0,0x96219136,0xfe6cfccb,...) ]
[ cpu0:   _my_memset(0x1203b313,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0xfe6cfccb,...) ]
[ cpu0:   _my_memset(0x1203bc73,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
[ cpu0:   _my_memset(0x1203c5d3,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
[ cpu0:   _my_memset(0x1203cf33,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
[ cpu0:   _my_memset(0x1203d893,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
[ cpu0:   _my_memset(0x1203e1f3,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
[ cpu0:   _my_memset(0x1203eb53,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
[ cpu0:   _my_memset(0x1203f4b3,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
^C
[ cpu0:   _my_memset(0x1203fe13,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
[ cpu0:   _my_memset(0x12040773,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
[ cpu0:   _my_memset(0x120410d3,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
[ cpu0:   _my_memset(0x12041a33,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
[ cpu0:   _my_memset(0x12042393,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
[ cpu0:   _my_memset(0x12042cf3,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
[ cpu0:   _my_memset(0x12043653,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
[ 100006 steps (1104 steps/second) ]
GXemul> fb_videoram0.dump 0x3b300
TODO: parse address expression
(for now, only hex immediate values are supported!)
0003b300  00000000 00000000 00000000 00000000  ................
0003b310  000000f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b320  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b330  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b340  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b350  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b360  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b370  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b380  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b390  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b3a0  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b3b0  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b3c0  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b3d0  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b3e0  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
0003b3f0  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
GXemul> quit

Source code for this component can be found here.



gxemul-0.6.1/doc/machines/machine_testmips-thumb.png000644 001750 001750 00000006007 13402411501 022742 0ustar00debugdebug000000 000000 PNG  IHDR0gAMA aPLTE===ݝ]]]111AAA}}}aaaQQQ ---=:7ímmmMMMOL%+3LbDRշ}ytRQPqqqpkfbN]MҡY;j!!!-l2U3_nHӟ/CVPn.T?_~?zb;kb-=L;kݰ*Pt-?`2IdRCNi,Qu;?L3>L͌gjW>r.Qy/N+Qt1EZB@4X]z˨8^yYAt-=O.AcKMx򆐑r@O_tߏ}v;l;o;l|UВ.IvL?@L^JPvیaݔq`N>x^ck`n=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)|eIDATx흽oH`Ç]2gDh%t[pN']RHw %+=^]mRm*R- gc{ yel&F(Bˋs-n 0U{'Ժx\p;y{q~uw>ut{xg{拱y7̳scӿɰպhw[w֥9 fo\ZPVa*ӞaIɪq4C{NJ:е2Wӽ_P?74O4M+>N ~տ >igU_h>vcz#M{gڇ76}0YB?@aRSꇇR뛛͍uiݸ o߾2'NLYBe]((/MUm"ԢNKW(AtRӱ\q-^e*LœPXD%sr-J@iPLW/B/e8P"O#z1oD A]2BdSc|M!VQZ= ElJ 1 7#$:<[MsŒ>(=SȦвj90`=VKU\hR(mՓՓfW]ʸʍ %'®x(!'`\YlJƕebXmB Y@eb5 9+W}bR v%ve"&Ǖ,+"CW !\Ǖ^(1t%i+P!7fkl+Ŝ%ȑ$3Xr,@,1WȎX+ˀ'&&bw0<`4d$lVKf#yXJ,%MW"sT]٤`,)WܶT:_k3Ř b/k<㡸Hk 伶a] *mǗT`7e 0X@CNh\gH̍cds0+I+-M%`ۏi` xG+"/>i,T0 },_[l+=ŅWIʫڣo+/(J(s(\8r\!c JeYf(z&Ĩ`%EQO(9ۇV\T0IPCQb,6s+2!aخDfAorkX:`Q`\i- Xu? TJq'`<9`{XzCO? f x̉JKW\Bl :R-`ak$Ղ+6¸BW-XPAV(}u\qZ$QF!]+m1. HrNXWlJ'.,DE)$FA, ^_=S\^)fehrA 72\1P C0+lj2]I1`]I/`ݺW[ Vb˓壂QOOvs 6A.Z0JC#[A7&0%_5;V:J̀ܠ RIJ̀qJ܀v'`;=VVg hNP|IQ(xF@ot,(PE`%7<<lfIځ|=̆h4{L2nZRC8|%P*Rhn- kQ쿶F@0j+蹂jX%¡`e)E( -wamv7tIME:4S;WIENDB`gxemul-0.6.1/doc/machines/machine_testmips.png000644 001750 001750 00000013742 13402411501 021631 0ustar00debugdebug000000 000000 PNG  IHDR*ucgAMA aPLTE===ݝ]]]111AAA}}}aaaQQQ ---=:7ímmmMMMOL%+3LbDRշ}ytRQPqqqpkfbN]MҡY;j!!!-l2U3_nHӟ/CVPn.T?_~?zb;kb-=L;kݰ*Pt-?`2IdRCNi,Qu;?L3>L͌gjW>r.Qy/N+Qt1EZB@4X]z˨8^yYAt-=O.AcKMx򆐑r@O_tߏ}v;l;o;l|UВ.IvL?@L^JPvیaݔq`N>x^ck`n=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)|@IDATxyaq1"J|h ,Kv\kM=,7 +@94xk%h}}ywg,*5fK@9IR%X"*?lJ*^g#tOTr9 u#߈tyr%]j蝓) wn{GTNK겵.$B(zyʠ>Qw:֍SGRm7ʎ:j~wG=JӮ|hm16zpUpDŽP _;=W2hܑ]޻!7G!Nr*nqmiMkނI#RS[7#36|Oѝ~ꞥSU Ϗڳ0{ KUшpaƓ=o4wlZ4#׳]v  __R}UqBMTjͽ[0I5u  2#B#MHτJeRmݧ.tQetqiN}ҩ7VNZqvˆϝU7~*+CxN;rJݎ_ŏ*Ӌu~ySGWmE*65"z=TT P6]cEgܰ;-l^zoEJŅTz]Ga}5MM \~AKRQޔyOQ?sb|œ+|)S{u+K3=8qu!8Hγ9Zez^杪^*%m 9_G>B>l* 6(,%**^T/=_Q1"<}訉pD_,{4um#~Vyh96py8tl }Zq\{R8{OI>5$G&'颦lZX~E.hӪǶ[ʚ"9ό2JީJyJH/#/:&MwRmOY]:];oqz!z Կ\WLM_#\Bfy*s}gέrŃu[feڈ]1eIsn,tfwx>޽/|'9̺ڱÝ/*wKæYxNʚ.p[8ro)k+M7ei#%3? )~gFrĻ;+6ٲbJjՍ5/%<7/̚kxBѴ;QÛ4𿩛o7 uʮff%OxFۚ%5̙3EWPrd6ydϒ;ۍ^pe5ey*y쯓2ǞٽezWB<6>aGTK߼2aҥVzfCu<{QM2{]y{yQ}d~K'I?wuWު_xф{Ez*Z40g&L^zEX7UEniܴ[gI9faߦ4eִ*?vV[޺<*_HCѥEgqp*5x]֫gG`D5<0T޴npj/ ~5hhT^>):lƕh5~MoXxe`+F-/pQ9[gIN/ڶʛ2{ڼS( # OMMދ:uW՞}֘kݚimU~u#&TNIRv9EKW/@}jD[| lyFNI|1iY_wş_87mv$r]S vUDxI GqDWIgۀyҾ T *B1-Աڟt0TPAPA=?TP)*]rkCTPATPA%â:. * *>_>* * * *wTh TPATPATPAP * * *f$w* *T:T*N{P9BTPATPACQ9RukPATPATPATPi[** * *J;wؾTPATPATv۹ʮ! * * *J* * * * * * * * * *ҩ * * * * * *{J* * * * * * * * * * * * * * * * *9PATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPAk* *JrlV * * * * * * * * * * * * * * * * * *ʾ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */!TPATPATPATPATPATPATPATPATPATP]* TPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATکm:` * *%]Y TPATPATPATPATPATPATPATPATPATPATPATPATPA_A *O.

The testmips machine is a GXemul-specific machine used for simple tests. It is based around a MIPS CPU, and some simple devices.

TODO.



gxemul-0.6.1/doc/machines/machine_testm88k-thumb.png000644 001750 001750 00000006007 13402411501 022561 0ustar00debugdebug000000 000000 PNG  IHDR0gAMA aPLTE===ݝ]]]111AAA}}}aaaQQQ ---=:7ímmmMMMOL%+3LbDRշ}ytRQPqqqpkfbN]MҡY;j!!!-l2U3_nHӟ/CVPn.T?_~?zb;kb-=L;kݰ*Pt-?`2IdRCNi,Qu;?L3>L͌gjW>r.Qy/N+Qt1EZB@4X]z˨8^yYAt-=O.AcKMx򆐑r@O_tߏ}v;l;o;l|UВ.IvL?@L^JPvیaݔq`N>x^ck`n=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)|eIDATx흽oH`Ç]2gDh%t[pN']RHw %+=^]mRm*R- gc{ yel&F(Bˋs-n 0U{'Ժx\p;y{q~uw>ut{xg{拱y7̳scӿɰպhw[w֥9 fo\ZPVa*ӞaIɪq4C{NJ:е2Wӽ_P?74O4M+>N ~տ >igU_h>vcz#M{gڇ76}0YB?@aRSꇇR뛛͍uiݸ o߾2'NLYBe]((/MUm"ԢNKW(AtRӱ\q-^e*LœPXD%sr-J@iPLW/B/e8P"O#z1oD A]2BdSc|M!VQZ= ElJ 1 7#$:<[MsŒ>(=SȦвj90`=VKU\hR(mՓՓfW]ʸʍ %'®x(!'`\YlJƕebXmB Y@eb5 9+W}bR v%ve"&Ǖ,+"CW !\Ǖ^(1t%i+P!7fkl+Ŝ%ȑ$3Xr,@,1WȎX+ˀ'&&bw0<`4d$lVKf#yXJ,%MW"sT]٤`,)WܶT:_k3Ř b/k<㡸Hk 伶a] *mǗT`7e 0X@CNh\gH̍cds0+I+-M%`ۏi` xG+"/>i,T0 },_[l+=ŅWIʫڣo+/(J(s(\8r\!c JeYf(z&Ĩ`%EQO(9ۇV\T0IPCQb,6s+2!aخDfAorkX:`Q`\i- Xu? TJq'`<9`{XzCO? f x̉JKW\Bl :R-`ak$Ղ+6¸BW-XPAV(}u\qZ$QF!]+m1. HrNXWlJ'.,DE)$FA, ^_=S\^)fehrA 72\1P C0+lj2]I1`]I/`ݺW[ Vb˓壂QOOvs 6A.Z0JC#[A7&0%_5;V:J̀ܠ RIJ̀qJ܀v'`;=VVg hNP|IQ(xF@ot,(PE`%7<<lfIځ|=̆h4{L2nZRC8|%P*Rhn- kQ쿶F@0j+蹂jX%¡`e)E( -wamv7tIME:4S;WIENDB`gxemul-0.6.1/doc/machines/machine_mvme187.html.SKEL000644 001750 001750 00000022747 13402411501 022107 0ustar00debugdebug000000 000000 The mvme187 machine is a VMEbus based machine with a Motorola 88100 CPU.


OpenBSD/mvme88k:

NOTE: THIS DOES NOT WORK YET! These are preliminary instructions on how it may work when the new GXemul framework is complete enough.

It is possible to run OpenBSD/mvme88k on the emulated Motorola MVME187 machine.

To install OpenBSD/mvme88k onto an emulated harddisk image, follow these instructions:

  1. Create an empty harddisk image, which will be the root disk that OpenBSD installs itself onto:
    	dd if=/dev/zero of=obsd_mvme88k.img bs=1024 count=1 seek=1900000
    
    
  2. Download the entire mvme88k directory from the ftp server:
    	wget -np -l 0 -r ftp://ftp.se.openbsd.org/pub/OpenBSD/4.4/mvme88k/
    
    
  3. You now need to make an ISO image of the entire directory you downloaded. (I recommend using mkisofs for that purpose. If you don't already have mkisofs installed on your system, you need to install it in order to do this.)
    	mkisofs -o openbsd_mvme88k_4.4.iso -U ftp.se.openbsd.org/pub/OpenBSD/
    
    
  4. Copy away the kernel, we'll need it later. But remove the rest of the downloaded tree.
    	cp ftp.se.openbsd.org/pub/OpenBSD/4.4/mvme88k/bsd .
    	rm -rf ftp.se.openbsd.org
    
  5. Start the emulator using this command line:
    	gxemul -e mvme187 -d obsd_mvme88k.img -d b:openbsd_mvme88k_4.4.iso -j 4.4/mvme88k/bsd.rd
    
    
    and proceed like you would do if you were installing OpenBSD on a real MVME187. There is a problem with finding the filesystem on the CDROM, since there is no disklabel [and/or because the emulator perhaps does not simulate CDROM TOCs well enough], but it's possible to mount the filesystem using manual intervention. Here is an example of what an install can look like: (user input in blue italic)
    	CPU0 is associated to 2 MC88200 CMMUs
    	Copyright (c) 1982, 1986, 1989, 1991, 1993
    		The Regents of the University of California.  All rights reserved.
    	Copyright (c) 1995-2008 OpenBSD. All rights reserved.  http://www.OpenBSD.org
    
    	OpenBSD 4.4 (RAMDISK) #19: Sun Aug 10 21:03:44 GMT 2008
    	    root@arzon.gentiane.org:/usr/src/sys/arch/mvme88k/compile/RAMDISK
    	real mem = 67108864 (64MB)
    	avail mem = 56791040 (54MB)
    	mainbus0 at root: Motorola MVME187, 33MHz
    	cpu0: M88100 rev 0x3, 2 CMMU
    	cpu0: M88200 (16K) rev 0x9, full Icache, M88200 (16K) rev 0x9, full Dcache
    	pcctwo0 at mainbus0 addr 0xfff00000: rev 0
    	nvram0 at pcctwo0 offset 0xc0000: MK48T08
    	cl0 at pcctwo0 offset 0x45000 ipl 3: console
    	osiop0 at pcctwo0 offset 0x47000 ipl 2: NCR53C710 rev 2, 66MHz
    	scsibus0 at osiop0: 8 targets, initiator 7
    	osiop0: target 0 ignored sync request
    	osiop0: target 0 now using 8 bit asynch xfers
    	sd0 at scsibus0 targ 0 lun 0:  SCSI2 0/direct fixed
    	sd0: 1855MB, 1855 cyl, 16 head, 128 sec, 512 bytes/sec, 3800003 sec total
    	osiop0: target 1 ignored sync request
    	osiop0: target 1 now using 8 bit asynch xfers
    	cd0 at scsibus0 targ 1 lun 0:  SCSI2 5/cdrom removable
    	vme0 at pcctwo0 offset 0x40000
    	vme0: using BUG parameters
    	vme0: vme to cpu irq level 1:1
    	vmes0 at vme0
    	rd0: fixed, 4096 blocks
    	boot device: 
    	root on rd0a swap on rd0b dump on rd0b
    	WARNING: clock gained 138 days -- CHECK AND RESET THE DATE!
    	erase ^?, werase ^W, kill ^U, intr ^C, status ^T
    	(I)nstall, (U)pgrade or (S)hell? i
    
    	Welcome to the OpenBSD/mvme88k 4.4 install program.
    
    	This program will help you install OpenBSD. At any prompt except password
    	prompts you can escape to a shell by typing '!'. Default answers are shown
    	in []'s and are selected by pressing RETURN.  At any time you can exit this
    	program by pressing Control-C, but exiting during an install can leave your
    	system in an inconsistent state.
    
    	Terminal type? [vt100] xterm
    
    	IS YOUR DATA BACKED UP? As with anything that modifies disk contents, this
    	program can cause SIGNIFICANT data loss.
    
    	It is often helpful to have the installation notes handy. For complex disk
    	configurations, relevant disk hardware manuals and a calculator are useful.
    
    	Proceed with install? [no] yes
    	Cool! Let's get to it.
    
    	You will now initialize the disk(s) that OpenBSD will use. To enable all
    	available security features you should configure the disk(s) to allow the
    	creation of separate filesystems for /, /tmp, /var, /usr, and /home.
    
    	Available disks are: sd0.
    	Which one is the root disk? (or 'done') [sd0] sd0
    	osiop0: target 0 ignored sync request
    	osiop0: target 0 now using 8 bit asynch xfers
    	Initial label editor (enter '?' for help at any prompt)
    	> a a
    	offset: [0] 63
    	size: [3799940] 3500000
    	FS type: [4.2BSD] 
    	mount point: [none] /
    	> a b
    	offset: [3500063] 
    	size: [299940] 
    	FS type: [swap] 
    	> w
    	> q
    	No label changes.
    	No more disks to initialize.
    
    	OpenBSD filesystems:
    	sd0a /
    
    	The next step *DESTROYS* all existing data on these partitions!
    	Are you really sure that you're ready to proceed? [no] yes
    	/dev/rsd0a: 1709.0MB in 3500000 sectors of 512 bytes
    	9 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each
    	/dev/sd0a on /mnt type ffs (rw, asynchronous, local, ctime=Thu Jan  1 16:29:57 2009)
    
    	System hostname? (short form, e.g. 'foo') test
    	Configure the network? [yes] no
    	Password for root account? (will not echo) 
    	Password for root account? (again) 
    
    	Let's install the sets!
    	Location of sets? (cd disk ftp http nfs or 'done') [cd] disk
    	Is the disk partition already mounted? [no] !mount -t cd9660 /dev/cd0c /mnt2
    	osiop0: target 1 ignored sync request
    	osiop0: target 1 now using 8 bit asynch xfers
    	Is the disk partition already mounted? [no] yes
    	Pathname to the sets? (or 'done') [4.4/mvme88k] /mnt2/4.4/mvme88k
    
    	Select sets by entering a set name, a file name pattern or 'all'. De-select
    	sets by prepending a '-' to the set name, file name pattern or 'all'. Selected
    	sets are labelled '[X]'.
    
    	        [X] bsd
    	        [X] bsd.rd
    	        [ ] bsd.mp
    	        [X] base44.tgz
    	        [X] etc44.tgz
    	        [X] misc44.tgz
    	        [X] comp44.tgz
    	        [X] man44.tgz
    	        [X] game44.tgz
    	        [ ] xbase44.tgz
    	        [ ] xetc44.tgz
    	        [ ] xshare44.tgz
    	        [ ] xfont44.tgz
    	        [ ] xserv44.tgz
    	Set name? (or 'done') [bsd.mp] done
    	Ready to install sets? [yes] yes
    	Getting bsd ...
    	100% |**************************************************|  2329 KB    01:21    
    	Getting bsd.rd ...
    	100% |**************************************************|  3150 KB    01:48    
    	Getting base44.tgz ...
    	100% |**************************************************| 87686 KB    11:56    
    	Getting etc44.tgz ...
    	100% |**************************************************|   629 KB    00:14    
    	Getting misc44.tgz ...
    	100% |**************************************************|  2866 KB    00:37    
    	Getting comp44.tgz ...
    	100% |**************************************************| 38869 KB    06:19    
    	Getting man44.tgz ...
    	100% |**************************************************|  6967 KB    01:50    
    	Getting game44.tgz ...
    	100% |**************************************************|  7037 KB    01:16    
    	Location of sets? (cd disk ftp http nfs or 'done') [done] done
    	Start sshd(8) by default? [yes] yes
    	Start ntpd(8) by default? [no] no
    	Saving configuration files...done.
    	Generating initial host.random file...done.
    	What timezone are you in? ('?' for list) [Canada/Mountain] Europe/Stockholm
    	Setting local timezone to 'Europe/Stockholm'...done.
    	Making all device nodes...done.
    	Installing boot block...
    	boot: /mnt/boot
    	proto: /mnt/usr/mdec/bootxx
    	device: /dev/rsd0a
    	cdevice: /dev/rsd0c
    	modifying vid.
    	/mnt/usr/mdec/bootxx: entry point 0x9f0000
    	proto bootblock size 5120
    	room for 64 filesystem blocks at 0x9f1198
    	Will load 2 blocks of size 16384 each.
    	0: 17696
    	1: 17728
    
    	CONGRATULATIONS! Your OpenBSD install has been successfully completed!
    	To boot the new system, enter halt at the command prompt. Once the
    	system has halted, reset the machine and boot from the disk.
    	# umount /mnt
    	# halt
    
    

Once the install has finished, the following command should let you boot from the harddisk image:

	gxemul -e mvme187 -d obsd_mvme88k.img bsd

When asked about root disk, enter sd0.

No NIC has been implemented yet for mvme187, so there is no network connectivity from within the guest OS.


gxemul-0.6.1/doc/machines/machine_hp700rx.html.SKEL000644 001750 001750 00000004070 13402411501 022100 0ustar00debugdebug000000 000000 The hp700rx machine template tries to emulate a HP 700/RX X-terminal, with an i960CA processor.

TODO:
Everything.

Note: this should hopefully/eventually work:

$ ./gxemul -V -e hp700rx C2708A 

but the entry point (according to Intel's b.out format) is 0x3fe05000, which is wrong. Clearly, the HP 700/RX deduces the entry point some other way. For now, one way to load the binary with correct entry point is to use the "raw" file loader and specify addresses explicitly:

$ ./gxemul -V -e hp700rx raw:0x3fe05000:0x2c:0x3fe05094:C2708A 
GXemul (unknown version)      Copyright (C) 2003-2018  Anders Gavare

  mainbus0
  |-- cpu0  (25 MHz)
  \-- ram0  (2 MB at offset 0x3fe00000)

cpu0: raw:0x3fe05000:0x2c:0x3fe05094:C2708A loaded
      Raw file: entry point 0x3fe05094
      loadable chunk at offset 44: vaddr 0x3fe05000, 1605668 bytes

GXemul> cpu.u 
0x3fe05094 <- 8c180100            lda      0x100,r3      
0x3fe05098    6518c483            sysctl   r3,r3,r3      
0x3fe0509c    5c201e06            mov      6,r4          
0x3fe050a0    8c683000 c0003000   lda      0xc0003000,r13
0x3fe050a8    82235000            stob     r4,(r13)      
0x3fe050ac    5c881e08            mov      8,g1          
0x3fe050b0    90745000            ld       (g1),r14      
0x3fe050b4    5cf01e00            mov      0,g14         
0x3fe050b8    8c183000 001f0002   lda      0x001f0002,r3 
0x3fe050c0    8c203000 001f0002   lda      0x001f0002,r4 
0x3fe050c8    6520ca80            modpc    0,r3,r4       
0x3fe050cc    5c103e00            mov      0,sfr2        
0x3fe050d0    5c083e00            mov      0,sfr1        
0x3fe050d4    5c003e00            mov      0,sfr0        
0x3fe050d8    5c001e00            mov      0,pfp         
0x3fe050dc    8cf80040            lda      0x40,fp       
0x3fe050e0    8c0fe040            lda      0x40(fp),sp   
0x3fe050e4    59185e0c            shlo     12,1,r3       
0x3fe050e8    6420c283            modac    r3,r3,r4      
0x3fe050ec    59805e1e            shlo     30,1,g0       
GXemul> q 


gxemul-0.6.1/doc/machines/machine_testm88k.png000644 001750 001750 00000013742 13402411501 021450 0ustar00debugdebug000000 000000 PNG  IHDR*ucgAMA aPLTE===ݝ]]]111AAA}}}aaaQQQ ---=:7ímmmMMMOL%+3LbDRշ}ytRQPqqqpkfbN]MҡY;j!!!-l2U3_nHӟ/CVPn.T?_~?zb;kb-=L;kݰ*Pt-?`2IdRCNi,Qu;?L3>L͌gjW>r.Qy/N+Qt1EZB@4X]z˨8^yYAt-=O.AcKMx򆐑r@O_tߏ}v;l;o;l|UВ.IvL?@L^JPvیaݔq`N>x^ck`n=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)|@IDATxyaq1"J|h ,Kv\kM=,7 +@94xk%h}}ywg,*5fK@9IR%X"*?lJ*^g#tOTr9 u#߈tyr%]j蝓) wn{GTNK겵.$B(zyʠ>Qw:֍SGRm7ʎ:j~wG=JӮ|hm16zpUpDŽP _;=W2hܑ]޻!7G!Nr*nqmiMkނI#RS[7#36|Oѝ~ꞥSU Ϗڳ0{ KUшpaƓ=o4wlZ4#׳]v  __R}UqBMTjͽ[0I5u  2#B#MHτJeRmݧ.tQetqiN}ҩ7VNZqvˆϝU7~*+CxN;rJݎ_ŏ*Ӌu~ySGWmE*65"z=TT P6]cEgܰ;-l^zoEJŅTz]Ga}5MM \~AKRQޔyOQ?sb|œ+|)S{u+K3=8qu!8Hγ9Zez^杪^*%m 9_G>B>l* 6(,%**^T/=_Q1"<}訉pD_,{4um#~Vyh96py8tl }Zq\{R8{OI>5$G&'颦lZX~E.hӪǶ[ʚ"9ό2JީJyJH/#/:&MwRmOY]:];oqz!z Կ\WLM_#\Bfy*s}gέrŃu[feڈ]1eIsn,tfwx>޽/|'9̺ڱÝ/*wKæYxNʚ.p[8ro)k+M7ei#%3? )~gFrĻ;+6ٲbJjՍ5/%<7/̚kxBѴ;QÛ4𿩛o7 uʮff%OxFۚ%5̙3EWPrd6ydϒ;ۍ^pe5ey*y쯓2ǞٽezWB<6>aGTK߼2aҥVzfCu<{QM2{]y{yQ}d~K'I?wuWު_xф{Ez*Z40g&L^zEX7UEniܴ[gI9faߦ4eִ*?vV[޺<*_HCѥEgqp*5x]֫gG`D5<0T޴npj/ ~5hhT^>):lƕh5~MoXxe`+F-/pQ9[gIN/ڶʛ2{ڼS( # OMMދ:uW՞}֘kݚimU~u#&TNIRv9EKW/@}jD[| lyFNI|1iY_wş_87mv$r]S vUDxI GqDWIgۀyҾ T *B1-Աڟt0TPAPA=?TP)*]rkCTPATPA%â:. * *>_>* * * *wTh TPATPATPAP * * *f$w* *T:T*N{P9BTPATPACQ9RukPATPATPATPi[** * *J;wؾTPATPATv۹ʮ! * * *J* * * * * * * * * *ҩ * * * * * *{J* * * * * * * * * * * * * * * * *9PATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPAk* *JrlV * * * * * * * * * * * * * * * * * *ʾ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */!TPATPATPATPATPATPATPATPATPATP]* TPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATPATکm:` * *%]Y TPATPATPATPATPATPATPATPATPATPATPATPATPA_A *O.> 4]); printchar("0123456789abcdef"[i & 15]); } void printhex4(int i) { printhex2(i >> 8); printhex2(i & 255); } void f(void) { int ofs, ide_id = 0, status, i; unsigned char ch; printstr("Testing dev_disk.\n"); printstr("Assuming that IDE ID 0 (primary master) is available.\n"); for (ofs = 0; ofs < 1024; ofs += 512) { printstr("\n"); *((volatile int *) (DISK_ADDRESS + DEV_DISK_OFFSET)) = ofs; *((volatile int *) (DISK_ADDRESS + DEV_DISK_ID)) = ide_id; *((volatile int *) (DISK_ADDRESS + DEV_DISK_START_OPERATION)) = DEV_DISK_OPERATION_READ; /* Get status: */ status = *((volatile int *) (DISK_ADDRESS + DEV_DISK_STATUS)); if (status == 0) { printstr("Read failed.\n"); halt(); } printstr("Sector dump:\n"); for (i = 0; i < 512; i++) { if ((i % 16) == 0) { printhex4(i); printstr(" "); } printstr(" "); ch = *((volatile unsigned char *) DISK_ADDRESS + DEV_DISK_BUFFER + i); printhex2(ch); if ((i % 16) == 15) { int j; printstr(" "); for (j = i-15; j <= i; j++) { ch = *((volatile unsigned char *) DISK_ADDRESS + DEV_DISK_BUFFER + j); if (ch < 32 || ch >= 127) ch = '.'; printchar(ch); } printstr("\n"); } } } printstr("\nDone.\n"); halt(); } gxemul-0.6.1/demos/disk/Makefile000644 001750 001750 00000000174 13402411502 016730 0ustar00debugdebug000000 000000 all: @echo Read the README file for instructions on how to build @echo the demo program. clean: rm -f *.o disk_* *core gxemul-0.6.1/demos/rectangles/rectangles.c000644 001750 001750 00000003707 13402411502 020765 0ustar00debugdebug000000 000000 /* * $Id: rectangles.c,v 1.5 2006-07-09 07:53:33 debug Exp $ * * GXemul demo: Random rectangles * * This file is in the Public Domain. */ #include "dev_fb.h" #ifdef MIPS /* Note: The ugly cast to a signed int (32-bit) causes the address to be sign-extended correctly on MIPS when compiled in 64-bit mode */ #define PHYSADDR_OFFSET ((signed int)0xa0000000) #else #define PHYSADDR_OFFSET 0 #endif /* Framebuffer linear memory and controller base addresss: */ #define FB_BASE (PHYSADDR_OFFSET + DEV_FB_ADDRESS) #define FBCTRL_BASE (PHYSADDR_OFFSET + DEV_FBCTRL_ADDRESS) #define XRES 800 #define YRES 600 void my_memset(unsigned char *a, int x, int len) { while (len-- > 0) *a++ = x; } void draw_rectangle(int x1, int y1, int x2, int y2, int c) { int y, len; for (y=y1; y<=y2; y++) { len = 3 * (x2-x1+1); if (len > 0) { my_memset((unsigned char *)FB_BASE + 3 * (XRES * y + x1), c, len); } } } unsigned int my_random() { static int a = 0x124879b; static int b = 0xb7856fa2; int c = a ^ (b * 51); a = 17 * c - (b * 171); return c; } void fbctrl_write_port(int p) { *(volatile int *)(FBCTRL_BASE + DEV_FBCTRL_PORT) = p; } void fbctrl_write_data(int d) { *(volatile int *)(FBCTRL_BASE + DEV_FBCTRL_DATA) = d; } void fbctrl_set_x1(int v) { fbctrl_write_port(DEV_FBCTRL_PORT_X1); fbctrl_write_data(v); } void fbctrl_set_y1(int v) { fbctrl_write_port(DEV_FBCTRL_PORT_Y1); fbctrl_write_data(v); } void fbctrl_command(int c) { fbctrl_write_port(DEV_FBCTRL_PORT_COMMAND); fbctrl_write_data(c); } void change_resolution(int xres, int yres) { fbctrl_set_x1(xres); fbctrl_set_y1(yres); fbctrl_command(DEV_FBCTRL_COMMAND_SET_RESOLUTION); } void f(void) { /* Change to the resolution we want: */ change_resolution(XRES, YRES); /* Draw random rectangles forever: */ for (;;) { draw_rectangle(my_random() % XRES, my_random() % YRES, my_random() % XRES, my_random() % YRES, my_random()); } } gxemul-0.6.1/demos/rectangles/Makefile000644 001750 001750 00000000202 13402411502 020115 0ustar00debugdebug000000 000000 all: @echo Read the README file for instructions on how to build @echo the demo program. clean: rm -f *.o rectangles_* *core gxemul-0.6.1/demos/rectangles/README000644 001750 001750 00000004677 13402411502 017361 0ustar00debugdebug000000 000000 Alpha ----- alpha-unknown-elf-gcc -I../../src/include/testmachine -g rectangles.c -O2 -c -o rectangles_alpha.o alpha-unknown-elf-ld -Ttext 0x10000 -e f rectangles_alpha.o -o rectangles_alpha file rectangles_alpha ../../gxemul -X -E testalpha rectangles_alpha ARM --- arm-unknown-elf-gcc -I../../src/include/testmachine -g rectangles.c -O2 -c -o rectangles_arm.o arm-unknown-elf-ld -e f rectangles_arm.o -o rectangles_arm file rectangles_arm ../../gxemul -X -E testarm rectangles_arm ARM THUMB --------- arm-unknown-elf-gcc -I../../src/include/testmachine -g rectangles.c -O2 -mthumb -c -o rectangles_arm_thumb.o arm-unknown-elf-ld -e f rectangles_arm_thumb.o $CROSSDEV/lib/gcc/arm-unknown-elf/3.4.6/thumb/libgcc.a -o rectangles_arm_thumb file rectangles_arm_thumb ../../gxemul -X -E testarm rectangles_arm_thumb M32R ---- m32r-elf-gcc -I../../src/include/testmachine -g rectangles.c -O2 -c -o rectangles_m32r.o m32r-elf-ld -e f rectangles_m32r.o -o rectangles_m32r file rectangles_m32r ../../gxemul -X -E testm32r rectangles_m32r MIPS (64-bit) ------------- mips64-unknown-elf-gcc -I../../src/include/testmachine -g -DMIPS rectangles.c -O2 -mips4 -mabi=64 -c -o rectangles_mips.o mips64-unknown-elf-ld -Ttext 0xa800000000030000 -e f rectangles_mips.o -o rectangles_mips --oformat=elf64-bigmips file rectangles_mips ../../gxemul -X -E testmips rectangles_mips MIPS (32-bit) ------------- mips64-unknown-elf-gcc -I../../src/include/testmachine -g -DMIPS rectangles.c -O2 -mips1 -mabi=32 -c -o rectangles_mips32.o mips64-unknown-elf-ld -Ttext 0x80030000 -e f rectangles_mips32.o -o rectangles_mips32 file rectangles_mips32 ../../gxemul -X -E testmips -C 4Kc rectangles_mips32 PPC (64-bit) ------------ TODO PPC (32-bit) ------------ ppc-unknown-elf-gcc -I../../src/include/testmachine -g rectangles.c -O2 -c -o rectangles_ppc.o ppc-unknown-elf-ld -e f rectangles_ppc.o -o rectangles_ppc file rectangles_ppc ../../gxemul -X -E testppc -C PPC750 rectangles_ppc SH (32-bit) ----------- sh64-superh-elf-gcc -m5-compact -I../../src/include/testmachine -g rectangles.c -c -o rectangles_sh.o sh64-superh-elf-ld -mshelf32 -e _f rectangles_sh.o -o rectangles_sh file rectangles_sh ../../gxemul -X -E testsh rectangles_sh SPARC (64-bit) -------------- sparc64-unknown-elf-gcc -I../../src/include/testmachine -g rectangles.c -O2 -c -o rectangles_sparc.o sparc64-unknown-elf-ld -e f rectangles_sparc.o -o rectangles_sparc file rectangles_sparc ../../gxemul -X -E testsparc rectangles_sparc gxemul-0.6.1/demos/mp/Makefile000644 001750 001750 00000000172 13402411502 016410 0ustar00debugdebug000000 000000 all: @echo Read the README file for instructions on how to build @echo the demo program. clean: rm -f *.o mp_* *core gxemul-0.6.1/demos/mp/README000644 001750 001750 00000001161 13402411502 015627 0ustar00debugdebug000000 000000 Replace the compiler target name with the name on your system. MIPS (64-bit) ------------- mips64-unknown-elf-gcc -I../../src/include/testmachine -g -O3 -DMIPS mp.c -mips64 -mabi=64 -c -o mp_mips.o mips64-unknown-elf-ld -Ttext 0xa800000000030000 -e f mp_mips.o -o mp_mips --oformat=elf64-bigmips file mp_mips ../../gxemul -E testmips -n 8 mp_mips MIPS (32-bit) ------------- mips64-unknown-elf-gcc -I../../src/include/testmachine -g -O3 -DMIPS mp.c -mips32r2 -mabi=32 -c -o mp_mips32.o mips64-unknown-elf-ld -Ttext 0x80030000 -e f mp_mips32.o -o mp_mips32 file mp_mips32 ../../gxemul -E testmips -C 4KEc -n 8 mp_mips32 gxemul-0.6.1/demos/mp/mp.c000644 001750 001750 00000002552 13402411502 015534 0ustar00debugdebug000000 000000 /* * $Id: mp.c,v 1.1 2007-02-11 09:19:27 debug Exp $ * * GXemul demo: Multi-Processor test * * This file is in the Public Domain. */ #include "dev_cons.h" #include "dev_mp.h" #ifdef MIPS /* Note: The ugly cast to a signed int (32-bit) causes the address to be sign-extended correctly on MIPS when compiled in 64-bit mode */ #define PHYSADDR_OFFSET ((signed int)0xa0000000) #else #define PHYSADDR_OFFSET 0 #endif #define PUTCHAR_ADDRESS (PHYSADDR_OFFSET + \ DEV_CONS_ADDRESS + DEV_CONS_PUTGETCHAR) #define HALT_ADDRESS (PHYSADDR_OFFSET + \ DEV_CONS_ADDRESS + DEV_CONS_HALT) #define NCPUS_ADDRESS (PHYSADDR_OFFSET + \ DEV_MP_ADDRESS + DEV_MP_NCPUS) void printchar(char ch) { *((volatile unsigned char *) PUTCHAR_ADDRESS) = ch; } void halt(void) { *((volatile unsigned char *) HALT_ADDRESS) = 0; } void printstr(char *s) { while (*s) printchar(*s++); } void printuint_internal(unsigned int u) { int z = u / 10; if (z > 0) printuint_internal(z); printchar('0' + (u - z*10)); } void printuint(unsigned int u) { if (u == 0) printchar('0'); else printuint_internal(u); } int get_nr_of_cpus(void) { return *((volatile int *) NCPUS_ADDRESS); } void f(void) { printstr("Multi-Processor demo\n"); printstr("--------------------\n\n"); printstr("Number of CPUs: "); printuint(get_nr_of_cpus()); printstr("\n\n"); halt(); }

Back to the index.