Compare commits

...

67 Commits

Author SHA1 Message Date
Peter Rutenbar
a9b2af09c0
Update README.md
Added a note of appreciation for issues/PRs
2023-03-29 10:49:13 -07:00
Peter Rutenbar
2b4768daee Update README.md 2017-04-17 11:52:13 -07:00
Peter Rutenbar
3fd03263fa Merge pull request #12 from mietek/master
Fix linking with Xcode 7
2016-09-04 02:02:17 -07:00
Miëtek Bak
578d274ab0 Fix linking with Xcode 7
Closes #11.
2015-11-28 22:03:13 +00:00
Miëtek Bak
bbb89edf8c Update .gitignore 2015-11-28 22:03:12 +00:00
Peter Rutenbar
70cf3734fb Update README.md 2015-09-13 20:16:46 -07:00
Peter Rutenbar
d26cbef0c1 Closing out some final simple changes 2015-09-13 19:11:18 -07:00
Peter Rutenbar
0322e558b4 Preliminary support for ethernet/multiple screens in cocoa client 2015-09-13 00:39:58 -07:00
Peter Rutenbar
1ab8a6a988 Fixed bugs in addx, subx, and cmpm
(cmpm was setting the CC codes based on a garbage source operand, so fixing that might fix a lot of other problems)
2015-09-10 16:27:00 -04:00
Peter Rutenbar
7f8b393fcc Fixed that dumb bsun bug 2015-09-04 12:01:01 -04:00
Peter Rutenbar
c0439a2f57 Fixed some integer division bugs, and other misc bugs 2015-09-01 16:04:30 -04:00
Peter Rutenbar
2ffbc963d2 Implemented chk2/cmp2, sbcd, and nbcd 2015-08-31 17:33:52 -04:00
Peter Rutenbar
36fdd1a6d6 Fixed/implemented roxx_mem, rox_mem, abcd, pack, unpk, cas2
Trying to finish up the last few unimplemented 68020 insts
2015-08-31 01:57:37 -04:00
Peter Rutenbar
3bc6aed00a Some preliminary work on ASC (Apple Sound Chip) emulation 2015-08-24 22:41:52 -04:00
Peter Rutenbar
b936ace3eb Update README.md 2015-04-09 22:22:51 -04:00
Peter Rutenbar
a66ad6d9b4 A/UX 3 should boot reliably now
- Added a hack to bypass SetUpTimeK, which works on 3.0.0,
  not sure about other versions.
2015-01-29 23:20:23 -05:00
Peter Rutenbar
476a8bb570 Major speed improvements (25-50%)
There may be bugs lurking in it. On my Core i7 macbook pro,
shoebill now runs so fast that SetUpTimeK() on A/UX 3 hangs.
(SetUpTimeK tries to time a dbra loop, and refuses to accept any
speed faster than a certain threshold, which shoebill is now
surpassing. If you see A/UX hanging early in boot, it's probably
that.)

- Added a new specialized cache for instruction stream reads
-- This also lets us distinguish between data and instruction
   reads, which the 68020 does. Instruction reads are now done
   with the correct function code (2 or 6), although that
   doesn't currently fix or improve anything currently
- Added an obvious condition code optimization, dunno how I missed
  it earlier
- Other little changes
2015-01-29 00:19:57 -05:00
Peter Rutenbar
76f2b35170 Unbroke shoebill, speed improvements
- Fixed inst_ext, which was completely broken since
  last commit, whoops!
- Added a bunch of __builtin_expect()s in all the
  critical paths, and now Marathon runs quite noticeably
  faster.
- Fixed (I think) all the SDL makefiles
2015-01-26 22:26:30 -05:00
Peter Rutenbar
9c3640cf48 fcmp and various other changes
- Read the 68881 docs for fcmp more carefully, and tweaked it to more
  accurately implement the (documented) behavior
- Implemented de-un-normalizing for all x80 softfloat ops
- Some other changes I don't remember - it's my emulator, I can be vague
  if I want XD
2014-12-10 22:22:45 -05:00
Peter Rutenbar
aea23c6dfc Implemented ftentox and fixed fscale again
- (Badly) worked around a clang bug to implement ftentox
- (Very badly) fixed another edge case in fscale
- Found another bug in softfloat (floatx80_to_int32)
-- Not so sure anymore that my floatx80/subnormal math fix works right.
   Just figured out that x80's exp is relative to the second mantissa
   bit. float128{exp=0x3fff, man=0} == floatx80{exp=0x3fff, man=0x800...}
   even though x80 has an explicit bit, the exponents are the same...
2014-11-24 01:31:53 -05:00
Peter Rutenbar
9e91b8067a Fixed a million SoftFloat bugs, and an edge case in fscale
SoftFloat's support for subnormal numbers is completely broken
on floatx80. Particularly when the result of an op on a subnormal
number is normal, and vice versa. I'm not completely sure that
my fixes are correct, or that they didn't break anything. I need
to do more testing.

Also fixed an edge case in fscale that gets weird when the
input goes from normal to subnormal... oh, and I still need to
fix the opposite case.
2014-11-23 19:41:06 -05:00
Peter Rutenbar
8142098fa1 Implemented fgetman,fscale,fsincos, and partial-fixed a softfloat bug
- fgetman, fscale, and fsincos are implemented but not tested at all

- fixed part of a softbug float when converting subnormal numbers between
  floatx80 and float128

- also, I checked in the wrong core/Makefile with the last commit.
  Re-committing the correct Makefile
2014-11-22 16:47:49 -05:00
Peter Rutenbar
f04e039dca Promoting newfpu to be the current fpu (aka fpu.c)
Just merged the newfpu branch to master, almost everything
is implemented, but there are clearly lots of problems still.

(According to xcalc, sin(3.1415927) == 0.054803665, which is
pretty far beyond the acceptable error margin.)
2014-11-10 20:40:54 -05:00
Peter Rutenbar
c8e7ba594c Implemented fatanh,cosh,etox,etoxm1,lognp1,tanh, and twotox
but not ftentox, because this hits a clang bug. Clang 3.5
(and earlier?) wants to optimize pow(10.0, x) to
__exp10(x), but __exp10() doesn't exist in the 10.8 SDK,
so the linker fails. There's probably some simple workaround...
2014-11-09 15:31:48 -05:00
Peter Rutenbar
7fa1e15257 Implemented flog2, flog10, and flogn, fixed fneg
xeyes works now
2014-11-09 13:56:16 -05:00
Peter Rutenbar
c7a28b8520 Implemented fsin,fcos,ftan,fatan,fasin,facos
Not sure if they work exactly right yet - xeyes is messed up,
but xclock seems to work.
2014-11-09 13:16:34 -05:00
Peter Rutenbar
0910915301 Finished the native-half of the transcendental impls
... for x86. Remains to be seen whether this will *really*
work on PowerPC or other architectures.
2014-11-09 12:25:39 -05:00
Peter Rutenbar
937a28a8bb Implemented frem, fmod, fsglmul/div, and fixed fabs
- And also fixed an assert
- New frem impl is slower, but easier to get the quotient bits.
2014-11-09 10:56:58 -05:00
Peter Rutenbar
db111528e8 Marathon works!
Fixed a bunch of dumb bugs, and now newfpu is working almost as well as old-fpu.
Presumably it's also running much more slowly, but I'm not noticing a speed difference.
2014-11-07 19:55:13 -05:00
Peter Rutenbar
df66c085da fmovecr now actually works
a cursory boot of 3.0.0 didn't reveal any asserts, except for x11. And I'm sure Marathon will die, and Mathematica, etc. Calculator works though. IE 2 hangs, and finder shutdown crashes.

... getting there
2014-11-06 01:12:28 -05:00
Peter Rutenbar
18c5a2b261 Newfpu works enough to "boot" A/UX
... but that's not saying much
2014-11-06 00:13:31 -05:00
Peter Rutenbar
2d04c6c104 Implemented fmovem_control()
I'm on a roll
2014-11-05 21:40:07 -05:00
Peter Rutenbar
2790b03327 Added a bunch of disassemblers for newfpu 2014-11-05 18:31:33 -05:00
Peter Rutenbar
688199cf6d Dumping a lot of new FPU-related changes in a new branch
A/UX doesn't even come close to booting yet with the new FPU,
but we're getting there. I don't want to trash master with
a code base that doesn't work. Also, I turned off ethernet
in the cocoa GUI, since the TAP driver isn't working right
on 10.10 yet.
2014-11-05 13:38:51 -05:00
pruten
a155eb7734 Merge branch 'master' of https://github.com/pruten/Shoebill 2014-10-16 15:55:19 -04:00
pruten
7c96e7c101 Began implementing a few more newfpu instructions
Though Motorola's documentation is surprisingly buggy
and imprecise.
2014-10-16 15:53:32 -04:00
Peter Rutenbar
16f1af72f8 Update README.md 2014-10-15 18:11:54 -04:00
pruten
78fbd8235f Refactored a big chunk of newfpu
- the framework for throwing exceptions should work correctly now
- NaNs and signaling NaNs should work
- condition codes are set now
- write-back and rounding (including throwing INEX2) are now implemented

(Note: you can't actually use any of this code yet, and it doesn't actually
       fully implement any fmath_* instructions yet)
2014-10-13 23:21:06 -04:00
pruten
c9adc49a82 More minor tweaks to newfpu 2014-10-07 22:37:22 -04:00
pruten
adc2e16ffd Implemented CAS
It compiles, but I haven't even tested it once. *fingers crossed*
2014-09-28 19:40:16 -04:00
pruten
bb6d1e719f More half-baked newfpu goodness
Once the framework for handling exceptions, accrued exceptions,
condition codes, and rounding is done, I can start implementing
actual "fmath" instructions. Everything not handled by softfloat
will be imprecisely and hackily implemented by using the best
available native float math (e.g. cosf(), cos(), or cosl())
2014-09-28 16:51:08 -04:00
pruten
bb2ec0a27d Working on a total FPU rewrite based on softfloat
5 instructions down, a million more to go
2014-09-27 13:46:57 -04:00
pruten
a0810f55b9 Added a hook for shutdown
To which the Macintosh II usually responds by powering off
2014-09-22 17:02:17 -04:00
pruten
b29c69453e Mostly-working ethernet and various changes
This may break the linux/windows builds - I haven't tried to compile
on those platforms yet.

- Ethernet is more or less working with a hardcoded /dev/tun0 network interface
and hardcoded MAC address, though there's no automatic ifconfig/route
configuration yet.

- Instructions TAS and ILLEGAL are implemented now

- Fixed some bugs in MOVEP

- Implemented some other instruction disassemblers

- Other little changes
2014-09-11 03:40:20 -04:00
pruten
4af4262993 Implemented movep 2014-08-30 05:10:54 -04:00
name
fd31d642b0 Lots of new ethernet-related code (doesn't work yet)
The board is basically implemented. It's just a dummy slot ROM
with no driver or primary/secondary init, that looks enough
like the Apple EtherTalk card. The DP8390 controller chip
has its address space implemented, and some of its registers
work. Lots more work to do on that

With slog() tracing enabled, you can see A/UX try to send a
multicast ethernet frame, then give up waiting for some kind
of response from the chip, then decide that the ethernet
controller is dead and print an error to console
2014-08-27 19:37:26 -04:00
Peter Rutenbar
20fedf386b Improved SCSI a bit.
Apple HD SC Setup still doesn't work, but it won't crash anymore.
Non-existent SCSI devices can no longer be selected
2014-07-28 01:09:16 -04:00
Peter Rutenbar
ea23ef3ac6 Update README.md 2014-07-03 22:10:32 -04:00
Peter Rutenbar
df614785c9 Update README.md 2014-07-03 22:09:05 -04:00
Peter Rutenbar
4ac0c6c4b2 Update README.md 2014-06-30 19:06:33 -04:00
Peter Rutenbar
6773dd6020 Tweaks to SDL GUI, video driver, and FPU
- Fewer FPU-related crashes
- Fewer video driver-related crashes
- Cleaned up the SDL GUI
- Bumped up cocoa GUI to v0.0.4
2014-06-30 16:50:38 -04:00
Peter Rutenbar
305d84faad Very dumb bug fixed, 3.0.1 boots now!
For READ(6) and WRITE(6), SCSI spec says,
"A TRANSFER LENGTH field set to zero specifies that 256 logical blocks shall be written"
Oops
2014-06-23 10:55:41 -04:00
Peter Rutenbar
f051d42597 Resuscitated the toby frame buffer
- Integrated it into the SDL GUI (via the "toby" cli parameter)
- It does not include the card ROM, so it will not run on A/UX 1, 2, or 3
2014-06-15 16:41:06 -04:00
Peter Rutenbar
42fd2a0b4e Fixed some dumbness in that last commit
- #ifdef __LITTLE_ENDIAN__ is not how you check for little endianness
- Also fixed the last pointer-to-int warnings on GCC

Also, shout out to  Neozeed for figuring out how to compile this on windows!
2014-06-14 01:25:37 -04:00
Peter Rutenbar
1bee24316c Now more Windows-friendly
- cpu_thread now stops and waits on a pthread condition variable, rather
  than sleep(1)ing and waiting to be pthread_kill()'d. Signals don't
  work well on Windows, apparently.
- fopen() now open binary files with the "b" mode
- the keymap red-black tree no longer casts pointers to ints, because
  mingw/gcc complains about it
- added a dumb batch script to compile the sdl gui on windows
- {n,h}to{h,n}{s,l,ll} is now handled better on windows
2014-06-14 00:19:08 -04:00
Peter Rutenbar
952fe7ae89 Linux SDL GUI + bug fixes + printf->slog
- sdl-gui/sdl.c is a tiny, basically working SDL2-based GUI that can compile and run on linux.
  It still needs PRAM integration and a config file.

- Fixed a dumb bug in shoebill_initialize that was causing sporadic crashes

- Replaced a million printf() calls with slog(), to make the SDL client run more quietly on the CLI

- Added more corruption checking to alloc_pool
2014-06-09 16:21:12 -04:00
Peter Rutenbar
5c1fdf6b73 VIA Timers + 16/32-bit video support
- VIA timers should probably work now, although it turns out A/UX rarely uses them
  (only during startup to time a dbra loop and other stuff)

- Updated video.c and the fake nubus video card driver to support "thousands"
  and "millions" of colors when 32-bit QuickDraw is available
2014-06-02 00:59:08 -04:00
Peter Rutenbar
a16a6700e4 Update README.md 2014-05-24 16:51:01 -04:00
Peter Rutenbar
d5dd7385b1 Minor twiddling before releasing 0.0.3 2014-05-24 16:35:36 -04:00
Peter Rutenbar
f4f546deb5 Restart + PRAM integrated into GUI + misc
Restart/shutdown now work (most of the time)
PRAM is now integrated into the GUI
The real time clock sorta works, but is a bit wonky
Full-screen support
Lots of other little bug fixes
2014-05-24 13:39:39 -04:00
Peter Rutenbar
d19c17812c New debugger + inital PRAM/real-time clock + fixes
- Refactored VIA rega/b implementation
  - Timers don't "work" yet, but they work a little better
  - Split rega/b into input and output versions
  - Fixed a bug that would mistake VIA1 accesses for VIA2

- Added basic support for PRAM and the RTC, although they're not
  wired into the GUI yet

- Replaced every *alloc() call with an alloc_pool call, which is
  a start toward supporting clean restarts

- Replaced ea_addr, ea_read, ea_write, and ea_read_commit with
  jump tables

- Got rid of ~inst() macro in cpu.c

- added a GLUT-based debugger
2014-05-10 19:25:31 -04:00
Peter Rutenbar
2800cc3c7e Twiddling README.md some more 2014-05-10 19:01:13 -04:00
Peter Rutenbar
1ffea71ed3 Twiddling the README.md 2014-05-10 18:55:12 -04:00
Peter Rutenbar
9f0e6ed115 Speed improvements + little fixes + 0.0.2 release
- Converted condition-code + physical_get/set switch statements to jump tables
- Moved the pmmu_cache lookup code out of translate_logical_addr
- Broke MOVE into move-to-datareg, -from-datareg, and datareg-to-datareg
- Fixed UFS code to ignore high 32 bits of inode size (it sometimes contains garbage)
- Support for zero-length reads in scsi.c + 256kb read/write buffer
- pushing interrupt stack frames now actually changes the priority mask
- Updated the READMEs, screencaps for 0.0.2
2014-04-26 13:35:56 -04:00
Peter Rutenbar
cc2bb3c605 Implemented trapv/trapcc + a few more FPU instructions.
Implemented the divide-by-zero exception.
Made some progress toward 16/24-bit video.
2014-04-19 12:12:15 -04:00
Peter Rutenbar
ba8b9e80d1 Integrated filesystem.c into the gui and cleaned up mem.c 2014-04-11 20:33:35 -04:00
Peter Rutenbar
e82172884e - Made a lot of progress getting 3.0.0 to run.
- Implemented support for reading the kernel from SVFS/UFS filesystems
- Other little changes
2014-04-05 19:20:53 -04:00
78 changed files with 22715 additions and 6809 deletions

3
.gitignore vendored
View File

@ -3,3 +3,6 @@
.DS_Store
*.xcworkspace
xcuserdata
/gui/build
/debugger/debugger
/debugger/debugger.dSYM

View File

@ -1,16 +1,19 @@
CC = clang
CFLAGS = -O4 -arch x86_64 -Wno-deprecated-declarations
LFLAGS = -framework OpenGL -framework GLUT
CFLAGS = -O3 -flto -Wno-deprecated-declarations
all: shoebill
shoebill: make_core test.c
$(CC) $(LFLAGS) $(CFLAGS) -L intermediates -l shoebill_core test.c -o shoebill
shoebill: make_gui debugger
make_gui: make_core
xcodebuild -project gui/Shoebill.xcodeproj SYMROOT=build
debugger: make_core
$(MAKE) -C debugger
make_core:
$(MAKE) -C core -j 4
clean:
rm -rf intermediates
rm -f shoebill
rm -rf intermediates gui/build

View File

@ -1,35 +1,46 @@
Shoebill
========
<h1><img align=right src="../../../pruten.github.io/raw/master/web/stork_tiny_head3.jpg"/>Shoebill</h1>
A Macintosh II emulator that runs A/UX (and A/UX only).
Shoebill is an all-new, BSD-licensed Macintosh II emulator designed from the ground up with the singular goal of running A/UX.
A/UX 1.x.x through 2.0.0 are supported currently, and 3.x.x support is in progress.
Shoebill requires a OS X, a Macintosh II or IIx ROM, a disk image with A/UX installed, and an A/UX kernel.
Shoebill requires a Macintosh II, IIx or IIcx ROM, and a disk image with A/UX installed.
[Download the latest release], and then see the [getting started] wiki.
Also check out [screenshots].
####Currently Implements
__Update (March 29, 2023): About issues/pull requests__
__I just wanted to say that I appreciate some folks are still using Shoebill and submitting issues and pull requests. I wish I could continue working on this project, but there's a likely conflict of interest, and so I've mostly avoided pushing changes. I apologize for being unable to address the many, many bugs in this repo. (Also for anyone unaware, [Qemu is now able] now to run A/UX 3.x on its emulated Quadra 800.)__
__Update (Sept 13, 2015): [Shoebill 0.0.5 is available]__
__This will probably be the last release. I won't be able to work on Shoebill going forward (by contractual obligation), so I wanted to race out one last release. Only an OS X binary is available, sorry, and it's very unpolished. But the SDL GUI should still build on linux/windows.__
#### Supports
* A/UX 1.1.1 through 3.1 (and 3.1.1 a little)
#### Currently Implements
* 68020 CPU (mostly)
* 68881 FPU (a little)
* 68881 FPU (mostly)
* 68851 PMMU (just enough to boot A/UX)
* SCSI
* ADB
* A NuBus video card with 8-bit resolution
* PRAM
* Ethernet (via emulated Apple EtherTalk/DP8390 card)
* A NuBus video card with 24-bit depth.
#### Does not implement (yet)
* Sound
* Floppy
* Serial ports
* Ethernet
* PRAM / VIA timers
* Support for multiple screens, or 16/24-bit resolutions
[Download the latest release]:https://github.com/pruten/Shoebill/releases
[getting started]:https://github.com/pruten/Shoebill/wiki/Getting-Started
[screenshots]:https://github.com/pruten/Shoebill/wiki/Screenshots
[Shoebill 0.0.5 is available]:https://github.com/pruten/Shoebill/releases
[The thread on emaculation.com]:http://www.emaculation.com/forum/viewtopic.php?f=7&t=8288
[Qemu is now able]:https://virtuallyfun.com/2021/09/02/qemus-macintosh-quadra-in-alpha-usability-runs-a-ux/

View File

@ -1,56 +0,0 @@
Shoebill - a Macintosh II emulator that runs A/UX
(except A/UX 3.x.x currently)
See the wiki on https://github.com/pruten/shoebill for better
documentation on building and running Shoebill.
*** KEEP IN MIND ***
* Shoebill v.first-terrible-code-drop (a.k.a. version 0.0.1)
* ONLY RUNS A/UX
* BUT NOT 3.x.x (Im working on it)
* Only 1.x.x and 2.x.x
* Shoebill has broken, ultra-minimalist support for
* 68020 (CPU) + 68851 (MMU) + 68881 (FPU)
* Some instructions for 020 and most for the MMU and FPU are unimplemented
* SCSI, ADB, and VIA
* Shoebill does not support
* The floppy controller, IWM/SWIM
* Serial
* Ethernet
* PRAM
* Most other things
*** RUNNING ***
You will need
* OS X and a 64-bit Intel Macintosh
(32-bit builds are possible by twiddling the makefiles)
* A Macintosh II or IIx ROM
* A disk image with A/UX 1.x.x or 2.x.x installed
* If you happen to have an installation CD image for A/UX, that will work
* The kernel on that image (/unix). Shoebill cant read
SVFS or UFS file sytems yet to load the kernel directly
from the disk image.
To boot A/UX
* Backup your disk images!!
When Shoebill inevitably crashes, your A/UX boot image
will very likely be corrupted - sometimes so severely
that A/UX cant even boot enough to run fsck.
* Open Shoebill.app and select Preferences menu item
* Set the paths for your ROM, kernel, and disk image(s).
* Do use SCSI ID #0 for your A/UX boot image.
* Press “Apply and Run”
*** BUILDING ***
1) cd to shoebill/
2) make # to build shoebill_core
3) xcodebuild -project gui/Shoebill.xcodeproj # to build the Cocoa GUI

View File

@ -1,20 +1,35 @@
CC = clang
CFLAGS = -O4 -ggdb -arch x86_64 -Wno-deprecated-declarations
CFLAGS = -O3 -ggdb -flto -Wno-deprecated-declarations
# CFLAGS = -O0 -ggdb -Wno-deprecated-declarations
DEPS = core_api.h coff.h mc68851.h redblack.h shoebill.h Makefile macro.pl
DEPS = mc68851.h shoebill.h Makefile macro.pl
NEED_DECODER = cpu dis
NEED_PREPROCESSING = adb fpu mc68851 mem via
NEED_NOTHING = atrap_tab coff exception floppy macii_symbols redblack scsi toby_frame_buffer video core_api
NEED_PREPROCESSING = adb mc68851 mem via floppy core_api fpu
NEED_NOTHING = atrap_tab coff exception macii_symbols redblack scsi video filesystem alloc_pool toby_frame_buffer sound ethernet SoftFloat/softfloat
# Object files that can be compiled directly from the source
OBJ_NEED_NOTHING = $(patsubst %,$(TEMP)/%.o,$(NEED_NOTHING))
# Object files than need preprocessing with macro.pl
OBJ_NEED_PREPROCESSING = $(patsubst %,$(TEMP)/%.o,$(NEED_PREPROCESSING))
# Object files that depend on the instruction decoder
OBJ_NEED_DECODER = $(patsubst %,$(TEMP)/%.o,$(NEED_DECODER))
# Files that NEED_DECODER also NEED_PREPROCESSING
POST_PREPROCESSING = $(patsubst %,$(TEMP)/%.post.c,$(NEED_PREPROCESSING)) $(patsubst %,$(TEMP)/%.post.c,$(NEED_DECODER))
# All the object files compiled for x86_64
OBJ_x86_64 = $(OBJ_NEED_NOTHING) $(OBJ_NEED_PREPROCESSING) $(OBJ_NEED_DECODER)
# The object files compiled for i386 (the same as x86_64 files, but with .i386 appended)
OBJ_i386 = $(patsubst %,%.i386,$(OBJ_x86_64))
MACRO = perl macro.pl
TEMP = ../intermediates
@ -22,18 +37,29 @@ TEMP = ../intermediates
all: $(TEMP)/libshoebill_core.a
$(TEMP)/libshoebill_core.a: $(TEMP) $(DEPS) $(OBJ_NEED_NOTHING) $(OBJ_NEED_PREPROCESSING) $(OBJ_NEED_DECODER)
libtool -static -o $(TEMP)/libshoebill_core.a $(OBJ_NEED_NOTHING) $(OBJ_NEED_PREPROCESSING) $(OBJ_NEED_DECODER)
$(TEMP)/libshoebill_core.a: $(TEMP) $(DEPS) $(OBJ_x86_64)
libtool -static -v -o $(TEMP)/libshoebill_core.a.x86_64 $(OBJ_x86_64)
libtool -static -v -o $(TEMP)/libshoebill_core.a.i386 $(OBJ_i386)
lipo -create -output $(TEMP)/libshoebill_core.a $(TEMP)/libshoebill_core.a.x86_64 $(TEMP)/libshoebill_core.a.i386
# Split object files into i386/x86_64 versions, since it seems that libtool is unable to
# link a static universal library for -O4 object files.
# x86_64 object files have the form "intermediates/<file_name>.o
# i386 object files have the form "intermediates/<file_name>.o.i386
# Build object files
$(OBJ_NEED_NOTHING): $(TEMP)/%.o: %.c $(DEPS)
$(CC) -c $(CFLAGS) $< -o $@
$(CC) -c -arch x86_64 $(CFLAGS) $< -o $@
$(CC) -c -arch i386 $(CFLAGS) $< -o $@.i386
$(OBJ_NEED_PREPROCESSING): $(TEMP)/%.o: $(TEMP)/%.post.c $(DEPS)
$(CC) -c $(CFLAGS) $< -o $@
$(CC) -c -arch x86_64 $(CFLAGS) $< -o $@
$(CC) -c -arch i386 $(CFLAGS) $< -o $@.i386
$(OBJ_NEED_DECODER): $(TEMP)/%.o: $(TEMP)/%.post.c $(DEPS) $(TEMP)/dis_decoder_guts.c $(TEMP)/inst_decoder_guts.c
$(CC) -c $(CFLAGS) $< -o $@
$(CC) -c -arch x86_64 $(CFLAGS) $< -o $@
$(CC) -c -arch i386 $(CFLAGS) $< -o $@.i386
# Preprocess C files
$(POST_PREPROCESSING): $(TEMP)/%.post.c: %.c $(DEPS)
@ -47,11 +73,12 @@ $(TEMP)/dis_decoder_guts.c: $(TEMP)/decoder_gen $(DEPS)
# Compile the decoder generator
$(TEMP)/decoder_gen: decoder_gen.c $(DEPS)
$(CC) $(CFLAGS) decoder_gen.c -o $(TEMP)/decoder_gen
$(CC) decoder_gen.c -o $(TEMP)/decoder_gen
$(TEMP):
mkdir -p $(TEMP)
mkdir -p $(TEMP)/SoftFloat
clean:
rm -rf $(TEMP)

68
core/SoftFloat/386-GCC.h Normal file
View File

@ -0,0 +1,68 @@
/*----------------------------------------------------------------------------
| One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
*----------------------------------------------------------------------------*/
#define LITTLEENDIAN
/*----------------------------------------------------------------------------
| The macro `BITS64' can be defined to indicate that 64-bit integer types are
| supported by the compiler.
*----------------------------------------------------------------------------*/
#define BITS64
/*----------------------------------------------------------------------------
| Each of the following `typedef's defines the most convenient type that holds
| integers of at least as many bits as specified. For example, `uint8' should
| be the most convenient type that can hold unsigned integers of as many as
| 8 bits. The `flag' type must be able to hold either a 0 or 1. For most
| implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
| to the same as `int'.
*----------------------------------------------------------------------------*/
typedef char flag;
typedef unsigned char uint8;
typedef signed char int8;
typedef int uint16;
typedef int int16;
typedef unsigned int uint32;
typedef signed int int32;
#ifdef BITS64
typedef unsigned long long int uint64;
typedef signed long long int int64;
#endif
/*----------------------------------------------------------------------------
| Each of the following `typedef's defines a type that holds integers
| of _exactly_ the number of bits specified. For instance, for most
| implementation of C, `bits16' and `sbits16' should be `typedef'ed to
| `unsigned short int' and `signed short int' (or `short int'), respectively.
*----------------------------------------------------------------------------*/
typedef unsigned char bits8;
typedef signed char sbits8;
typedef unsigned short int bits16;
typedef signed short int sbits16;
typedef unsigned int bits32;
typedef signed int sbits32;
#ifdef BITS64
typedef unsigned long long int bits64;
typedef signed long long int sbits64;
#endif
#ifdef BITS64
/*----------------------------------------------------------------------------
| The `LIT64' macro takes as its argument a textual integer literal and
| if necessary ``marks'' the literal as having a 64-bit integer type.
| For example, the GNU C Compiler (`gcc') requires that 64-bit literals be
| appended with the letters `LL' standing for `long long', which is `gcc's
| name for the 64-bit integer type. Some compilers may allow `LIT64' to be
| defined as the identity macro: `#define LIT64( a ) a'.
*----------------------------------------------------------------------------*/
#define LIT64( a ) a##LL
#endif
/*----------------------------------------------------------------------------
| The macro `INLINE' can be used before functions that should be inlined. If
| a compiler does not support explicit inlining, this macro should be defined
| to be `static'.
*----------------------------------------------------------------------------*/
#define INLINE static

View File

@ -0,0 +1,728 @@
/*
* SoftFloat with lots of fixes and modified for use by Shoebill.
*
* Based on SoftFloat 2b by John R. Hauser.
* Modifications by Peter Rutenbar. (pruten@gmail.com)
*/
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
| the result by setting the least significant bit to 1. The value of `count'
| can be arbitrarily large; in particular, if `count' is greater than 32, the
| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
| The result is stored in the location pointed to by `zPtr'.
*----------------------------------------------------------------------------*/
INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr )
{
bits32 z;
if ( count == 0 ) {
z = a;
}
else if ( count < 32 ) {
z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 );
}
else {
z = ( a != 0 );
}
*zPtr = z;
}
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
| the result by setting the least significant bit to 1. The value of `count'
| can be arbitrarily large; in particular, if `count' is greater than 64, the
| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
| The result is stored in the location pointed to by `zPtr'.
*----------------------------------------------------------------------------*/
INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr )
{
bits64 z;
if ( count == 0 ) {
z = a;
}
else if ( count < 64 ) {
z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 );
}
else {
z = ( a != 0 );
}
*zPtr = z;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64
| _plus_ the number of bits given in `count'. The shifted result is at most
| 64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The
| bits shifted off form a second 64-bit result as follows: The _last_ bit
| shifted off is the most-significant bit of the extra result, and the other
| 63 bits of the extra result are all zero if and only if _all_but_the_last_
| bits shifted off were all zero. This extra result is stored in the location
| pointed to by `z1Ptr'. The value of `count' can be arbitrarily large.
| (This routine makes more sense if `a0' and `a1' are considered to form
| a fixed-point value with binary point between `a0' and `a1'. This fixed-
| point value is shifted right by the number of bits given in `count', and
| the integer part of the result is returned at the location pointed to by
| `z0Ptr'. The fractional part of the result may be slightly corrupted as
| described above, and is returned at the location pointed to by `z1Ptr'.)
*----------------------------------------------------------------------------*/
INLINE void
shift64ExtraRightJamming(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1 != 0 );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z1 = a0 | ( a1 != 0 );
}
else {
z1 = ( ( a0 | a1 ) != 0 );
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
| number of bits given in `count'. Any bits shifted off are lost. The value
| of `count' can be arbitrarily large; in particular, if `count' is greater
| than 128, the result will be 0. The result is broken into two 64-bit pieces
| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
shift128Right(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1>>count );
z0 = a0>>count;
}
else {
// [shoebill] This is a bug, right? ( count < 64 ) can never be true
// z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0;
z1 = ( count < 128 ) ? ( a0>>( count & 63 ) ) : 0;
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
| number of bits given in `count'. If any nonzero bits are shifted off, they
| are ``jammed'' into the least significant bit of the result by setting the
| least significant bit to 1. The value of `count' can be arbitrarily large;
| in particular, if `count' is greater than 128, the result will be either
| 0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or
| nonzero. The result is broken into two 64-bit pieces which are stored at
| the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
shift128RightJamming(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z1 = a0 | ( a1 != 0 );
}
else if ( count < 128 ) {
z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 );
}
else {
z1 = ( ( a0 | a1 ) != 0 );
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right
| by 64 _plus_ the number of bits given in `count'. The shifted result is
| at most 128 nonzero bits; these are broken into two 64-bit pieces which are
| stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted
| off form a third 64-bit result as follows: The _last_ bit shifted off is
| the most-significant bit of the extra result, and the other 63 bits of the
| extra result are all zero if and only if _all_but_the_last_ bits shifted off
| were all zero. This extra result is stored in the location pointed to by
| `z2Ptr'. The value of `count' can be arbitrarily large.
| (This routine makes more sense if `a0', `a1', and `a2' are considered
| to form a fixed-point value with binary point between `a1' and `a2'. This
| fixed-point value is shifted right by the number of bits given in `count',
| and the integer part of the result is returned at the locations pointed to
| by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly
| corrupted as described above, and is returned at the location pointed to by
| `z2Ptr'.)
*----------------------------------------------------------------------------*/
INLINE void
shift128ExtraRightJamming(
bits64 a0,
bits64 a1,
bits64 a2,
int16 count,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z2 = a2;
z1 = a1;
z0 = a0;
}
else {
if ( count < 64 ) {
z2 = a1<<negCount;
z1 = ( a0<<negCount ) | ( a1>>count );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z2 = a1;
z1 = a0;
}
else {
a2 |= a1;
if ( count < 128 ) {
z2 = a0<<negCount;
z1 = a0>>( count & 63 );
}
else {
z2 = ( count == 128 ) ? a0 : ( a0 != 0 );
z1 = 0;
}
}
z0 = 0;
}
z2 |= ( a2 != 0 );
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the
| number of bits given in `count'. Any bits shifted off are lost. The value
| of `count' must be less than 64. The result is broken into two 64-bit
| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
shortShift128Left(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
*z1Ptr = a1<<count;
*z0Ptr =
( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 63 ) );
}
/*----------------------------------------------------------------------------
| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left
| by the number of bits given in `count'. Any bits shifted off are lost.
| The value of `count' must be less than 64. The result is broken into three
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
| `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
shortShift192Left(
bits64 a0,
bits64 a1,
bits64 a2,
int16 count,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 negCount;
z2 = a2<<count;
z1 = a1<<count;
z0 = a0<<count;
if ( 0 < count ) {
negCount = ( ( - count ) & 63 );
z1 |= a2>>negCount;
z0 |= a1>>negCount;
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit
| value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so
| any carry out is lost. The result is broken into two 64-bit pieces which
| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
add128(
bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z1;
z1 = a1 + b1;
*z1Ptr = z1;
*z0Ptr = a0 + b0 + ( z1 < a1 );
}
/*----------------------------------------------------------------------------
| Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the
| 192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is
| modulo 2^192, so any carry out is lost. The result is broken into three
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
| `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
add192(
bits64 a0,
bits64 a1,
bits64 a2,
bits64 b0,
bits64 b1,
bits64 b2,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 carry0, carry1;
z2 = a2 + b2;
carry1 = ( z2 < a2 );
z1 = a1 + b1;
carry0 = ( z1 < a1 );
z0 = a0 + b0;
z1 += carry1;
z0 += ( z1 < carry1 );
z0 += carry0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the
| 128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo
| 2^128, so any borrow out (carry out) is lost. The result is broken into two
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr' and
| `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
sub128(
bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
{
*z1Ptr = a1 - b1;
*z0Ptr = a0 - b0 - ( a1 < b1 );
}
/*----------------------------------------------------------------------------
| Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2'
| from the 192-bit value formed by concatenating `a0', `a1', and `a2'.
| Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The
| result is broken into three 64-bit pieces which are stored at the locations
| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
sub192(
bits64 a0,
bits64 a1,
bits64 a2,
bits64 b0,
bits64 b1,
bits64 b2,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 borrow0, borrow1;
z2 = a2 - b2;
borrow1 = ( a2 < b2 );
z1 = a1 - b1;
borrow0 = ( a1 < b1 );
z0 = a0 - b0;
z0 -= ( z1 < borrow1 );
z1 -= borrow1;
z0 -= borrow0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Multiplies `a' by `b' to obtain a 128-bit product. The product is broken
| into two 64-bit pieces which are stored at the locations pointed to by
| `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits32 aHigh, aLow, bHigh, bLow;
bits64 z0, zMiddleA, zMiddleB, z1;
aLow = a;
aHigh = a>>32;
bLow = b;
bHigh = b>>32;
z1 = ( (bits64) aLow ) * bLow;
zMiddleA = ( (bits64) aLow ) * bHigh;
zMiddleB = ( (bits64) aHigh ) * bLow;
z0 = ( (bits64) aHigh ) * bHigh;
zMiddleA += zMiddleB;
z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 );
zMiddleA <<= 32;
z1 += zMiddleA;
z0 += ( z1 < zMiddleA );
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Multiplies the 128-bit value formed by concatenating `a0' and `a1' by
| `b' to obtain a 192-bit product. The product is broken into three 64-bit
| pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
| `z2Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
mul128By64To192(
bits64 a0,
bits64 a1,
bits64 b,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2, more1;
mul64To128( a1, b, &z1, &z2 );
mul64To128( a0, b, &z0, &more1 );
add128( z0, more1, 0, z1, &z0, &z1 );
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the
| 128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit
| product. The product is broken into four 64-bit pieces which are stored at
| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
*----------------------------------------------------------------------------*/
INLINE void
mul128To256(
bits64 a0,
bits64 a1,
bits64 b0,
bits64 b1,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr,
bits64 *z3Ptr
)
{
bits64 z0, z1, z2, z3;
bits64 more1, more2;
mul64To128( a1, b1, &z2, &z3 );
mul64To128( a1, b0, &z1, &more2 );
add128( z1, more2, 0, z2, &z1, &z2 );
mul64To128( a0, b0, &z0, &more1 );
add128( z0, more1, 0, z1, &z0, &z1 );
mul64To128( a0, b1, &more1, &more2 );
add128( more1, more2, 0, z2, &more1, &z2 );
add128( z0, z1, 0, more1, &z0, &z1 );
*z3Ptr = z3;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Returns an approximation to the 64-bit integer quotient obtained by dividing
| `b' into the 128-bit value formed by concatenating `a0' and `a1'. The
| divisor `b' must be at least 2^63. If q is the exact quotient truncated
| toward zero, the approximation returned lies between q and q + 2 inclusive.
| If the exact quotient q is larger than 64 bits, the maximum positive 64-bit
| unsigned integer is returned.
*----------------------------------------------------------------------------*/
static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b )
{
bits64 b0, b1;
bits64 rem0, rem1, term0, term1;
bits64 z;
if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF );
b0 = b>>32;
z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32;
mul64To128( b, z, &term0, &term1 );
sub128( a0, a1, term0, term1, &rem0, &rem1 );
while ( ( (sbits64) rem0 ) < 0 ) {
z -= LIT64( 0x100000000 );
b1 = b<<32;
add128( rem0, rem1, b0, b1, &rem0, &rem1 );
}
rem0 = ( rem0<<32 ) | ( rem1>>32 );
z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0;
return z;
}
/*----------------------------------------------------------------------------
| Returns an approximation to the square root of the 32-bit significand given
| by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of
| `aExp' (the least significant bit) is 1, the integer returned approximates
| 2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp'
| is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either
| case, the approximation returned lies strictly within +/-2 of the exact
| value.
*----------------------------------------------------------------------------*/
static bits32 estimateSqrt32( int16 aExp, bits32 a )
{
static const bits16 sqrtOddAdjustments[] = {
0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
};
static const bits16 sqrtEvenAdjustments[] = {
0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
};
int8 index;
bits32 z;
index = ( a>>27 ) & 15;
if ( aExp & 1 ) {
z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
z = ( ( a / z )<<14 ) + ( z<<15 );
a >>= 1;
}
else {
z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
z = a / z + z;
z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
}
return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 );
}
/*----------------------------------------------------------------------------
| Returns the number of leading 0 bits before the most-significant 1 bit of
| `a'. If `a' is zero, 32 is returned.
*----------------------------------------------------------------------------*/
static int8 countLeadingZeros32( bits32 a )
{
static const int8 countLeadingZerosHigh[] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int8 shiftCount;
shiftCount = 0;
if ( a < 0x10000 ) {
shiftCount += 16;
a <<= 16;
}
if ( a < 0x1000000 ) {
shiftCount += 8;
a <<= 8;
}
shiftCount += countLeadingZerosHigh[ a>>24 ];
return shiftCount;
}
/*----------------------------------------------------------------------------
| Returns the number of leading 0 bits before the most-significant 1 bit of
| `a'. If `a' is zero, 64 is returned.
*----------------------------------------------------------------------------*/
static int8 countLeadingZeros64( bits64 a )
{
int8 shiftCount;
shiftCount = 0;
if ( a < ( (bits64) 1 )<<32 ) {
shiftCount += 32;
}
else {
a >>= 32;
}
shiftCount += countLeadingZeros32( a );
return shiftCount;
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1'
| is equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 == b0 ) && ( a1 == b1 );
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
| than or equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
| than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise,
| returns 0.
*----------------------------------------------------------------------------*/
INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is
| not equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 != b0 ) || ( a1 != b1 );
}

View File

@ -0,0 +1,464 @@
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*----------------------------------------------------------------------------
| Underflow tininess-detection mode, statically initialized to default value.
| (The declaration in `softfloat.h' must match the `int8' type here.)
*----------------------------------------------------------------------------*/
int8 float_detect_tininess = float_tininess_after_rounding;
/*----------------------------------------------------------------------------
| Raises the exceptions specified by `flags'. Floating-point traps can be
| defined here if desired. It is currently not possible for such a trap
| to substitute a result value. If traps are not implemented, this routine
| should be simply `float_exception_flags |= flags;'.
*----------------------------------------------------------------------------*/
void float_raise( int8 flags )
{
float_exception_flags |= flags;
}
/*----------------------------------------------------------------------------
| Internal canonical NaN format.
*----------------------------------------------------------------------------*/
typedef struct {
flag sign;
bits64 high, low;
} commonNaNT;
/*----------------------------------------------------------------------------
| The pattern for a default generated single-precision NaN.
*----------------------------------------------------------------------------*/
#define float32_default_nan 0xFFC00000
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float32_is_nan( float32 a )
{
return ( 0xFF000000 < (bits32) ( a<<1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float32_is_signaling_nan( float32 a )
{
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the single-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT float32ToCommonNaN( float32 a )
{
commonNaNT z;
if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a>>31;
z.low = 0;
z.high = ( (bits64) a )<<41;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the single-
| precision floating-point format.
*----------------------------------------------------------------------------*/
static float32 commonNaNToFloat32( commonNaNT a )
{
return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
}
/*----------------------------------------------------------------------------
| Takes two single-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static float32 propagateFloat32NaN( float32 a, float32 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float32_is_nan( a );
aIsSignalingNaN = float32_is_signaling_nan( a );
bIsNaN = float32_is_nan( b );
bIsSignalingNaN = float32_is_signaling_nan( b );
a |= 0x00400000;
b |= 0x00400000;
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( (bits32) ( a<<1 ) < (bits32) ( b<<1 ) ) return b;
if ( (bits32) ( b<<1 ) < (bits32) ( a<<1 ) ) return a;
return ( a < b ) ? a : b;
}
else {
return b;
}
}
/*----------------------------------------------------------------------------
| The pattern for a default generated double-precision NaN.
*----------------------------------------------------------------------------*/
#define float64_default_nan LIT64( 0xFFF8000000000000 )
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float64_is_nan( float64 a )
{
return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float64_is_signaling_nan( float64 a )
{
return
( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
&& ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the double-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT float64ToCommonNaN( float64 a )
{
commonNaNT z;
if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a>>63;
z.low = 0;
z.high = a<<12;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the double-
| precision floating-point format.
*----------------------------------------------------------------------------*/
static float64 commonNaNToFloat64( commonNaNT a )
{
return
( ( (bits64) a.sign )<<63 )
| LIT64( 0x7FF8000000000000 )
| ( a.high>>12 );
}
/*----------------------------------------------------------------------------
| Takes two double-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static float64 propagateFloat64NaN( float64 a, float64 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float64_is_nan( a );
aIsSignalingNaN = float64_is_signaling_nan( a );
bIsNaN = float64_is_nan( b );
bIsSignalingNaN = float64_is_signaling_nan( b );
a |= LIT64( 0x0008000000000000 );
b |= LIT64( 0x0008000000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( (bits64) ( a<<1 ) < (bits64) ( b<<1 ) ) return b;
if ( (bits64) ( b<<1 ) < (bits64) ( a<<1 ) ) return a;
return ( a < b ) ? a : b;
}
else {
return b;
}
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN. The
| `high' and `low' values hold the most- and least-significant bits,
| respectively.
*----------------------------------------------------------------------------*/
#define floatx80_default_nan_high 0xFFFF
#define floatx80_default_nan_low LIT64( 0xC000000000000000 )
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag floatx80_is_nan( floatx80 a )
{
return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag floatx80_is_signaling_nan( floatx80 a )
{
bits64 aLow;
aLow = a.low & ~ LIT64( 0x4000000000000000 );
return
( ( a.high & 0x7FFF ) == 0x7FFF )
&& (bits64) ( aLow<<1 )
&& ( a.low == aLow );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the extended double-precision floating-
| point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
| invalid exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT floatx80ToCommonNaN( floatx80 a )
{
commonNaNT z;
if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a.high>>15;
z.low = 0;
z.high = a.low<<1;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the extended
| double-precision floating-point format.
*----------------------------------------------------------------------------*/
static floatx80 commonNaNToFloatx80( commonNaNT a )
{
floatx80 z;
z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
return z;
}
/*----------------------------------------------------------------------------
| Takes two extended double-precision floating-point values `a' and `b', one
| of which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = floatx80_is_nan( a );
aIsSignalingNaN = floatx80_is_signaling_nan( a );
bIsNaN = floatx80_is_nan( b );
bIsSignalingNaN = floatx80_is_signaling_nan( b );
a.low |= LIT64( 0xC000000000000000 );
b.low |= LIT64( 0xC000000000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( a.low < b.low ) return b;
if ( b.low < a.low ) return a;
return ( a.high < b.high ) ? a : b;
}
else {
return b;
}
}
#endif
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| The pattern for a default generated quadruple-precision NaN. The `high' and
| `low' values hold the most- and least-significant bits, respectively.
*----------------------------------------------------------------------------*/
#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
#define float128_default_nan_low LIT64( 0x0000000000000000 )
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float128_is_nan( float128 a )
{
return
( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
&& ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float128_is_signaling_nan( float128 a )
{
return
( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
&& ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the quadruple-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT float128ToCommonNaN( float128 a )
{
commonNaNT z;
if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a.high>>63;
shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the quadruple-
| precision floating-point format.
*----------------------------------------------------------------------------*/
static float128 commonNaNToFloat128( commonNaNT a )
{
float128 z;
shift128Right( a.high, a.low, 16, &z.high, &z.low );
z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
return z;
}
/*----------------------------------------------------------------------------
| Takes two quadruple-precision floating-point values `a' and `b', one of
| which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static float128 propagateFloat128NaN( float128 a, float128 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float128_is_nan( a );
aIsSignalingNaN = float128_is_signaling_nan( a );
bIsNaN = float128_is_nan( b );
bIsSignalingNaN = float128_is_signaling_nan( b );
a.high |= LIT64( 0x0000800000000000 );
b.high |= LIT64( 0x0000800000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsSignalingNaN ) {
if ( bIsSignalingNaN ) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if ( aIsNaN ) {
if ( bIsSignalingNaN | ! bIsNaN ) return a;
returnLargerSignificand:
if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b;
if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a;
return ( a.high < b.high ) ? a : b;
}
else {
return b;
}
}
#endif

5400
core/SoftFloat/softfloat.c Normal file

File diff suppressed because it is too large Load Diff

259
core/SoftFloat/softfloat.h Normal file
View File

@ -0,0 +1,259 @@
/*============================================================================
This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*----------------------------------------------------------------------------
| The macro `FLOATX80' must be defined to enable the extended double-precision
| floating-point format `floatx80'. If this macro is not defined, the
| `floatx80' type will not be defined, and none of the functions that either
| input or output the `floatx80' type will be defined. The same applies to
| the `FLOAT128' macro and the quadruple-precision format `float128'.
*----------------------------------------------------------------------------*/
#define FLOATX80
#define FLOAT128
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point types.
*----------------------------------------------------------------------------*/
typedef unsigned int float32;
typedef unsigned long long float64;
#ifdef FLOATX80
typedef struct {
unsigned long long low;
unsigned short high;
} floatx80;
#endif
#ifdef FLOAT128
typedef struct {
unsigned long long low, high;
} float128;
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point underflow tininess-detection mode.
*----------------------------------------------------------------------------*/
extern signed char float_detect_tininess;
enum {
float_tininess_after_rounding = 0,
float_tininess_before_rounding = 1
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point rounding mode.
*----------------------------------------------------------------------------*/
extern signed char float_rounding_mode;
enum {
float_round_nearest_even = 0,
float_round_down = 1,
float_round_up = 2,
float_round_to_zero = 3
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point exception flags.
*----------------------------------------------------------------------------*/
extern signed char float_exception_flags;
enum {
float_flag_invalid = 1,
float_flag_divbyzero = 4,
float_flag_overflow = 8,
float_flag_underflow = 16,
float_flag_inexact = 32
};
/*----------------------------------------------------------------------------
| Routine to raise any or all of the software IEC/IEEE floating-point
| exception flags.
*----------------------------------------------------------------------------*/
void float_raise( signed char );
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
float32 int32_to_float32( int );
float64 int32_to_float64( int );
#ifdef FLOATX80
floatx80 int32_to_floatx80( int );
#endif
#ifdef FLOAT128
float128 int32_to_float128( int );
#endif
float32 int64_to_float32( long long );
float64 int64_to_float64( long long );
#ifdef FLOATX80
floatx80 int64_to_floatx80( long long );
#endif
#ifdef FLOAT128
float128 int64_to_float128( long long );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
*----------------------------------------------------------------------------*/
int float32_to_int32( float32 );
int float32_to_int32_round_to_zero( float32 );
long long float32_to_int64( float32 );
long long float32_to_int64_round_to_zero( float32 );
float64 float32_to_float64( float32 );
#ifdef FLOATX80
floatx80 float32_to_floatx80( float32 );
#endif
#ifdef FLOAT128
float128 float32_to_float128( float32 );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision operations.
*----------------------------------------------------------------------------*/
float32 float32_round_to_int( float32 );
float32 float32_add( float32, float32 );
float32 float32_sub( float32, float32 );
float32 float32_mul( float32, float32 );
float32 float32_div( float32, float32 );
float32 float32_rem( float32, float32 );
float32 float32_sqrt( float32 );
char float32_eq( float32, float32 );
char float32_le( float32, float32 );
char float32_lt( float32, float32 );
char float32_eq_signaling( float32, float32 );
char float32_le_quiet( float32, float32 );
char float32_lt_quiet( float32, float32 );
char float32_is_signaling_nan( float32 );
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
*----------------------------------------------------------------------------*/
int float64_to_int32( float64 );
int float64_to_int32_round_to_zero( float64 );
long long float64_to_int64( float64 );
long long float64_to_int64_round_to_zero( float64 );
float32 float64_to_float32( float64 );
#ifdef FLOATX80
floatx80 float64_to_floatx80( float64 );
#endif
#ifdef FLOAT128
float128 float64_to_float128( float64 );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision operations.
*----------------------------------------------------------------------------*/
float64 float64_round_to_int( float64 );
float64 float64_add( float64, float64 );
float64 float64_sub( float64, float64 );
float64 float64_mul( float64, float64 );
float64 float64_div( float64, float64 );
float64 float64_rem( float64, float64 );
float64 float64_sqrt( float64 );
char float64_eq( float64, float64 );
char float64_le( float64, float64 );
char float64_lt( float64, float64 );
char float64_eq_signaling( float64, float64 );
char float64_le_quiet( float64, float64 );
char float64_lt_quiet( float64, float64 );
char float64_is_signaling_nan( float64 );
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion routines.
*----------------------------------------------------------------------------*/
int floatx80_to_int32( floatx80 );
int floatx80_to_int32_round_to_zero( floatx80 );
long long floatx80_to_int64( floatx80 );
long long floatx80_to_int64_round_to_zero( floatx80 );
float32 floatx80_to_float32( floatx80 );
float64 floatx80_to_float64( floatx80 );
#ifdef FLOAT128
float128 floatx80_to_float128( floatx80 );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision rounding precision. Valid
| values are 32, 64, and 80.
*----------------------------------------------------------------------------*/
extern signed char floatx80_rounding_precision;
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
floatx80 floatx80_round_to_int( floatx80 );
floatx80 floatx80_add( floatx80, floatx80 );
floatx80 floatx80_sub( floatx80, floatx80 );
floatx80 floatx80_mul( floatx80, floatx80 );
floatx80 floatx80_div( floatx80, floatx80 );
floatx80 floatx80_rem( floatx80, floatx80 );
floatx80 floatx80_sqrt( floatx80 );
char floatx80_eq( floatx80, floatx80 );
char floatx80_le( floatx80, floatx80 );
char floatx80_lt( floatx80, floatx80 );
char floatx80_eq_signaling( floatx80, floatx80 );
char floatx80_le_quiet( floatx80, floatx80 );
char floatx80_lt_quiet( floatx80, floatx80 );
char floatx80_is_signaling_nan( floatx80 );
#endif
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision conversion routines.
*----------------------------------------------------------------------------*/
int float128_to_int32( float128 );
int float128_to_int32_round_to_zero( float128 );
long long float128_to_int64( float128 );
long long float128_to_int64_round_to_zero( float128 );
float32 float128_to_float32( float128 );
float64 float128_to_float64( float128 );
#ifdef FLOATX80
floatx80 float128_to_floatx80( float128 );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision operations.
*----------------------------------------------------------------------------*/
float128 float128_round_to_int( float128 );
float128 float128_add( float128, float128 );
float128 float128_sub( float128, float128 );
float128 float128_mul( float128, float128 );
float128 float128_div( float128, float128 );
float128 float128_rem( float128, float128 );
float128 float128_sqrt( float128 );
char float128_eq( float128, float128 );
char float128_le( float128, float128 );
char float128_lt( float128, float128 );
char float128_eq_signaling( float128, float128 );
char float128_le_quiet( float128, float128 );
char float128_lt_quiet( float128, float128 );
char float128_is_signaling_nan( float128 );
#endif

View File

@ -79,9 +79,35 @@
*/
void reset_adb_state()
{
pthread_mutex_t lock = shoe.adb.lock;
memset(&shoe.adb, 0, sizeof(adb_state_t));
memset(&shoe.key, 0, sizeof(keyboard_state_t));
memset(&shoe.mouse, 0, sizeof(mouse_state_t));
// Put the adb chip in state 3 (idle)
shoe.adb.state = 3;
shoe.adb.lock = lock;
}
void init_adb_state()
{
memset(&shoe.adb, 0, sizeof(adb_state_t));
memset(&shoe.key, 0, sizeof(keyboard_state_t));
memset(&shoe.mouse, 0, sizeof(mouse_state_t));
// Put the adb chip in state 3 (idle)
shoe.adb.state = 3;
pthread_mutex_init(&shoe.adb.lock, NULL);
}
void adb_start_service_request()
{
printf("adb_start_service_request: pending_requests = 0x%02x\n", shoe.adb.pending_service_requests);
//slog("adb_start_service_request: pending_requests = 0x%02x\n", shoe.adb.pending_service_requests);
if (shoe.adb.pending_service_requests) {
shoe.adb.service_request = 1;
@ -118,53 +144,65 @@ static void keyboard_talk(uint8_t reg)
else
shoe.adb.timeout = 1;
return ;
break ;
case 2:
// All the modifier keys are up
shoe.adb.data[0] = 0b01111111;
shoe.adb.data[1] = 0b11100111;
shoe.adb.data[0] = ~b(01111111);
shoe.adb.data[1] = ~b(11100111);
shoe.adb.data_len = 2;
return ;
break ;
case 1:
shoe.adb.timeout = 1;
return ;
break ;
case 3:
shoe.adb.data[0] = 0;
shoe.adb.data[1] = 0;
shoe.adb.data[0] = 0x02; // device address == 2 -> keyboard
shoe.adb.data[1] = 0x02; // device handler ID == 0x03 -> Apple Extended Keyboard
shoe.adb.data_len = 2;
return ;
break ;
}
slog("keyboard_talk: reg=%u timeout=%u data=0x%02x%02x datalen=%u\n", reg, shoe.adb.timeout, shoe.adb.data[0], shoe.adb.data[1], shoe.adb.data_len);
}
static void mouse_talk(uint8_t reg)
{
shoe.adb.timeout = 0;
printf("mouse_talk: reg=%u\n", reg);
slog("mouse_talk: reg=%u\n", reg);
switch (reg) {
case 0:
if (shoe.mouse.changed) {
const int32_t hi_delta_limit = 32;
const int32_t low_delta_limit = -32;
printf("mouse_talk: x=%d, y=%d button=%u\n", shoe.mouse.delta_x, shoe.mouse.delta_y, shoe.mouse.button_down);
int32_t x = shoe.mouse.delta_x;
int32_t y = shoe.mouse.delta_y;
shoe.adb.data[1] = shoe.mouse.delta_x & 0x7f;
shoe.adb.data[0] = shoe.mouse.delta_y & 0x7f;
//slog("mouse_talk: x=%d, y=%d button=%u\n", shoe.mouse.delta_x, shoe.mouse.delta_y, shoe.mouse.button_down);
if (x > hi_delta_limit) x = hi_delta_limit;
if (x < low_delta_limit) x = low_delta_limit;
if (y > hi_delta_limit) y = hi_delta_limit;
if (y < low_delta_limit) y = low_delta_limit;
shoe.adb.data[1] = x & 0x7f;
shoe.adb.data[0] = y & 0x7f;
if (!shoe.mouse.button_down) {
//shoe.adb.data[1] |= 0x80;
shoe.adb.data[0] |= 0x80;
}
// printf("mouse_talk: ")
// slog("mouse_talk: ")
shoe.adb.data_len = 2;
shoe.mouse.delta_x = 0;
shoe.mouse.delta_y = 0;
// shoe.mouse.button_down = 0;
shoe.mouse.changed = 0;
}
else
@ -206,7 +244,7 @@ static void adb_handle_state_zero(uint8_t command_byte, uint8_t is_poll) // "Com
else
assert(!"What is this adb state-0 command? xxxx 01xx");
printf("adb_handle_state_zero: command_byte=0x%02x, id=%u, reg=%u\n", command_byte, id, reg);
slog("adb_handle_state_zero: command_byte=0x%02x, id=%u, reg=%u\n", command_byte, id, reg);
shoe.adb.command_device_id = id;
shoe.adb.command_reg = reg;
@ -234,7 +272,7 @@ static void adb_handle_state_zero(uint8_t command_byte, uint8_t is_poll) // "Com
shoe.adb.poll = 0;
via->regb |= VIA_REGB_ADB_STATUS;
via->regb_input |= VIA_REGB_ADB_STATUS;
via_raise_interrupt(1, IFR_SHIFT_REG);
}
@ -242,7 +280,7 @@ static void adb_handle_state_one (void) // "Even" state
{
via_state_t *via = &shoe.via[0];
printf("adb_handle_state_one: ");
slog("adb_handle_state_one: ");
if (shoe.adb.poll) {
// Upon receiving a service request, the adb controller sends a TALK/reg=0 to the last accessed device
adb_handle_state_zero((shoe.adb.command_device_id << 4) | 0x0c, 1);
@ -255,12 +293,12 @@ static void adb_handle_state_one (void) // "Even" state
break;
case adb_talk:
printf("adb_talk: ");
slog("adb_talk: ");
if (shoe.adb.timeout) {
shoe.adb.timeout = 0;
via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
via->regb_input &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
via_raise_interrupt(1, IFR_SHIFT_REG);
printf("timeout\n");
slog("timeout\n");
return ;
}
@ -269,17 +307,17 @@ static void adb_handle_state_one (void) // "Even" state
else
via->sr = 0;
printf("set sr = 0x%02x\n", via->sr);
slog("set sr = 0x%02x\n", via->sr);
break;
case adb_listen:
printf("adb_listen: ");
slog("adb_listen: ");
if (shoe.adb.timeout) {
shoe.adb.timeout = 0;
via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
via->regb_input &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout
via_raise_interrupt(1, IFR_SHIFT_REG);
printf("timeout\n");
slog("timeout\n");
return ;
}
@ -288,12 +326,12 @@ static void adb_handle_state_one (void) // "Even" state
else
assert(!"OS made us listen to > 8 bytes");
printf("loaded sr = 0x%02x\n", via->sr);
slog("loaded sr = 0x%02x\n", via->sr);
break;
}
via->regb |= VIA_REGB_ADB_STATUS; // adb_status_line set == didn't-timeout
via->regb_input |= VIA_REGB_ADB_STATUS; // adb_status_line set == didn't-timeout
via_raise_interrupt(1, IFR_SHIFT_REG);
}
@ -301,39 +339,39 @@ static void adb_handle_state_two (void) // "Odd" state
{
via_state_t *via = &shoe.via[0];
printf("adb_handle_state_two: ");
slog("adb_handle_state_two: ");
// If this transaction was part of a service request, clear the service_request flag now
if (shoe.adb.service_request) {
shoe.adb.service_request = 0;
via->regb &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == service request
printf("(service request) ");
via->regb_input &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == service request
slog("(service request) ");
}
else
via->regb |= VIA_REGB_ADB_STATUS; // adb_status_line set == no-service request
via->regb_input |= VIA_REGB_ADB_STATUS; // adb_status_line set == no-service request
switch (shoe.adb.command_type) {
case adb_flush:
case adb_reset:
printf("adb_flush/reset\n");
slog("adb_flush/reset\n");
break;
case adb_talk:
printf("adb_talk: ");
slog("adb_talk: ");
if (shoe.adb.data_i < shoe.adb.data_len)
via->sr = shoe.adb.data[shoe.adb.data_i++];
else
via->sr = 0;
printf("set sr = 0x%02x\n", via->sr);
slog("set sr = 0x%02x\n", via->sr);
break;
case adb_listen:
printf("adb_listen: ");
slog("adb_listen: ");
if (shoe.adb.data_i < 8)
shoe.adb.data[shoe.adb.data_i++] = via->sr;
else
assert(!"OS made us listen to > 8 bytes");
printf("read sr = 0x%02x\n", via->sr);
slog("read sr = 0x%02x\n", via->sr);
break;
}
@ -342,7 +380,7 @@ static void adb_handle_state_two (void) // "Odd" state
static void adb_handle_state_three (void) // "idle" state
{
printf("adb_handle_state_three: completed for id %u\n", shoe.adb.command_device_id);
slog("adb_handle_state_three: completed for id %u\n", shoe.adb.command_device_id);
switch (shoe.adb.command_type) {
case adb_reset:
@ -351,7 +389,7 @@ static void adb_handle_state_three (void) // "idle" state
break;
case adb_listen:
printf("adb_handle_state_three: listen completed for id %u, reg %u, data_len = %u {%02x %02x}\n",
slog("adb_handle_state_three: listen completed for id %u, reg %u, data_len = %u {%02x %02x}\n",
shoe.adb.command_device_id, shoe.adb.command_reg, shoe.adb.data_i, shoe.adb.data[0], shoe.adb.data[1]);
break;
}
@ -363,7 +401,7 @@ void adb_handle_state_change(uint8_t old_state, uint8_t new_state)
{
via_state_t *via = &shoe.via[0];
printf("%s: lock\n", __func__); fflush(stdout);
slog("%s: lock\n", __func__); fflush(stdout);
assert(pthread_mutex_lock(&shoe.adb.lock) == 0);
shoe.adb.state = new_state;
@ -387,7 +425,7 @@ void adb_handle_state_change(uint8_t old_state, uint8_t new_state)
break ;
}
printf("%s: unlock\n", __func__); fflush(stdout);
slog("%s: unlock\n", __func__); fflush(stdout);
pthread_mutex_unlock(&shoe.adb.lock);
}

195
core/alloc_pool.c Normal file
View File

@ -0,0 +1,195 @@
/*
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <stdlib.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "../core/shoebill.h"
/*
#define POOL_ALLOC_TYPE 0
#define POOL_CHILD_LINK 1
#define POOL_HEAD 2
typedef struct _alloc_pool_t {
struct _alloc_pool_t *prev, *next;
uint8_t type;
union {
struct {
uint32_t size;
} alloc;
struct {
struct _alloc_pool_t *child; // pointer to the child's HEAD
} child_link;
struct {
struct _alloc_pool_t *parent_link; // pointer to the parent's CHILD_LINK
} head;
} t;
uint32_t magic;
} alloc_pool_t;
*/
static void _check_pool(alloc_pool_t *pool)
{
}
static alloc_pool_t* _ptr_to_header(void *ptr)
{
alloc_pool_t *apt = (alloc_pool_t*)ptr;
return &apt[-1];
}
void* p_alloc(alloc_pool_t *pool, uint64_t size)
{
alloc_pool_t *buf = calloc(sizeof(alloc_pool_t) + size, 1);
buf->type = POOL_ALLOC_TYPE;
buf->t.alloc.size = size;
buf->start_magic = POOL_START_MAGIC;
buf->end_magic = POOL_END_MAGIC;
buf->next = pool->next;
buf->prev = pool;
if (pool->next)
pool->next->prev = buf;
pool->next = buf;
return &buf[1];
}
void* p_realloc(void *ptr, uint64_t size)
{
alloc_pool_t *header = _ptr_to_header(ptr);
assert(header->start_magic == POOL_START_MAGIC);
assert(header->end_magic == POOL_END_MAGIC);
assert(header->type == POOL_ALLOC_TYPE);
alloc_pool_t *new_header = realloc(header, size + sizeof(alloc_pool_t));
if (new_header) {
new_header->t.alloc.size = size;
if (new_header->next)
new_header->next->prev = new_header;
if (new_header->prev)
new_header->prev->next = new_header;
return &new_header[1];
}
return NULL;
}
/*
* Free *any* kind of alloc_pool_t header
*/
static void _p_free_any(alloc_pool_t *header)
{
assert(header->start_magic == POOL_START_MAGIC);
assert(header->end_magic == POOL_END_MAGIC);
if (header->next)
header->next->prev = header->prev;
if (header->prev)
header->prev->next = header->next;
free(header);
}
/*
* Free an alloc_pool allocation (but not HEAD or CHILD_LINK)
*/
void p_free(void *ptr)
{
alloc_pool_t *header = _ptr_to_header(ptr);
assert(header->type == POOL_ALLOC_TYPE);
memset(ptr, 0xaa, header->t.alloc.size);
_p_free_any(header);
}
void p_free_pool(alloc_pool_t *pool)
{
while (pool->prev)
pool = pool->prev;
while (pool) {
alloc_pool_t *cur = pool;
pool = cur->next;
assert(cur->start_magic == POOL_START_MAGIC);
assert(cur->end_magic == POOL_END_MAGIC);
switch (cur->type) {
case POOL_ALLOC_TYPE:
_p_free_any(cur);
break;
case POOL_CHILD_LINK: {
// p_free_pool will free and unlink cur
// (its parent's CHILD_LINK)
p_free_pool(cur->t.child_link.child);
break;
}
case POOL_HEAD: {
if (cur->t.head.parent_link) {
assert(cur->t.head.parent_link->type == POOL_CHILD_LINK);
_p_free_any(cur->t.head.parent_link);
}
_p_free_any(cur);
break;
}
default:
assert(!"unknown POOL_ type");
}
}
}
alloc_pool_t* p_new_pool(alloc_pool_t *parent_pool)
{
alloc_pool_t *pool = calloc(sizeof(alloc_pool_t), 1);
pool->start_magic = POOL_START_MAGIC;
pool->end_magic = POOL_END_MAGIC;
pool->type = POOL_HEAD;
if (parent_pool) {
alloc_pool_t *link = _ptr_to_header(p_alloc(parent_pool, 0));
link->type = POOL_CHILD_LINK;
link->t.child_link.child = pool; // child_link.child points to the child's HEAD
pool->t.head.parent_link = link; // head.parent_link points to the parent's CHILD_LINK
}
else
pool->t.head.parent_link = NULL;
return pool;
}

View File

@ -28,43 +28,61 @@
#include <string.h>
#include <time.h>
#include <stdint.h>
#include <assert.h>
#include "shoebill.h"
#include "coff.h"
void symb_inorder(rb_node *cur) {
const coff_symbol *sym = (coff_symbol*)cur->value;
const coff_symbol *sym = *(coff_symbol**)&cur[1];
if (!sym)
return ;
symb_inorder(cur->left);
printf("0x%x %s\n", cur->key, sym->name);
slog("0x%x %s\n", cur->key, sym->name);
symb_inorder(cur->right);
}
// Given a path to a COFF binary, create a coff_file structure and return a pointer.
// God help you if you want to free it.
coff_file* coff_parser(const char *path)
#define _coff_buf_seek(__len) ({ \
uint32_t _result = 1, _len=(__len); \
if (_len > buflen) _result = 0; \
else bufptr = _len; \
_result; \
})
#define _coff_buf_read(_dst, __len) ({\
uint32_t _result = 1, _len=(__len); \
if ((bufptr + _len) > buflen) \
_result = 0; \
else {\
memcpy((_dst), buf+bufptr, _len); \
bufptr += _len; \
} \
_result; \
})
void coff_free(coff_file *coff)
{
p_free_pool(coff->pool);
}
// Given a path to a COFF binary, create a coff_file structure and return a pointer.
coff_file* coff_parse(uint8_t *buf, uint32_t buflen, alloc_pool_t *parent_pool)
{
FILE *f;
uint8_t rawhead[20], *ptr;
uint32_t i;
coff_file *cf = NULL;
// Open the file
f = fopen(path, "r");
if (!f) {
printf("coff_parser: I couldn't open that binary for reading (%s)\n", path);
goto fail;
}
uint32_t bufptr = 0;
alloc_pool_t *pool = p_new_pool(parent_pool);
// Pull out 20 bytes (the file header)
if (fread(rawhead, 20, 1, f) != 1) {
printf("coff_parser: error: this binary is missing its file header\n");
if (!_coff_buf_read(rawhead, 20)) {
slog("coff_parse: error: this binary is missing its file header\n");
goto fail;
}
// Allocate a coff_file and copy in the header
cf = (coff_file*)calloc(1, sizeof(coff_file));
cf = (coff_file*)p_alloc(pool, sizeof(coff_file));
cf->pool = pool;
ptr = rawhead;
cf->magic = be2native(&ptr, 2);
cf->num_sections = be2native(&ptr, 2);
cf->timestamp = be2native(&ptr, 4);
@ -75,32 +93,32 @@ coff_file* coff_parser(const char *path)
// A little sanity checking...
if (cf->magic != 0x150) {
printf("coff_parse: I don't recognize this magic number: 0x%04x\n", cf->magic);
slog("coff_parse: I don't recognize this magic number: 0x%04x\n", cf->magic);
goto fail;
}
else if (cf->num_sections != 3) {
//printf("coff_parse: warning: there are %u sections in this file (not 3, like I expect)\n", cf->num_sections);
//slog("coff_parse: warning: there are %u sections in this file (not 3, like I expect)\n", cf->num_sections);
// FIXME: investigate all the other possible section types
}
// pull out cf->opt_header bytes (a.out-format header, I guess?)
if (cf->opt_header_len > 0) {
uint8_t *opt = malloc(cf->opt_header_len);
if (fread(opt, cf->opt_header_len, 1, f) != 1) {
printf("coff_parse: I ran out of data pulling the optional header (%u bytes)\n", cf->opt_header_len);
free(opt);
uint8_t *opt = p_alloc(cf->pool, cf->opt_header_len);
if (!_coff_buf_read(opt, cf->opt_header_len)) {
slog("coff_parse: I ran out of data pulling the optional header (%u bytes)\n", cf->opt_header_len);
p_free(opt);
goto fail;
}
cf->opt_header = opt;
}
// start pulling out sections
cf->sections = calloc(cf->num_sections, sizeof(coff_section));
cf->sections = p_alloc(cf->pool, cf->num_sections * sizeof(coff_section));
for (i=0; i<cf->num_sections; i++) {
// read the header
uint8_t rawsec[40];
if (fread(rawsec, 40, 1, f) != 1) {
printf("coff_parse: I ran out of data pulling section #%u\n", i+1);
if (!_coff_buf_read(rawsec, 40)) {
slog("coff_parse: I ran out of data pulling section #%u\n", i+1);
goto fail;
}
// and copy it into cf->sections[i]
@ -118,7 +136,7 @@ coff_file* coff_parser(const char *path)
// a little bit of sanity checking:
if (cf->sections[i].v_addr != cf->sections[i].p_addr) {
//printf("coff_parse: warning: section %u's virtual_addr and physical_addr don't match: p=%x v=%x\n",
//slog("coff_parse: warning: section %u's virtual_addr and physical_addr don't match: p=%x v=%x\n",
// i+1, cf->sections[i].p_addr, cf->sections[i].v_addr);
// This is okay for the unix kernel
}
@ -139,16 +157,16 @@ coff_file* coff_parser(const char *path)
}
// seek to the position in the binary that holds this section's raw data
if (fseek(f, cf->sections[i].data_ptr, SEEK_SET) != 0) {
printf("coff_parse: I couldn't seek to 0x%x in section %u\n", cf->sections[i].data_ptr, i+1);
if (!_coff_buf_seek(cf->sections[i].data_ptr)) {
slog("coff_parse: I couldn't seek to 0x%x in section %u\n", cf->sections[i].data_ptr, i+1);
goto fail;
}
// load the data and attach it to the section struct
data = malloc(cf->sections[i].sz); // FIXME: sz might not be a sane value
if (fread(data, cf->sections[i].sz, 1, f) != 1) {
printf("coff_parse: I couldn't fread section %u (%s)'s data (%u bytes)\n", i+1, cf->sections[i].name, cf->sections[i].sz);
free(data);
data = p_alloc(cf->pool, cf->sections[i].sz); // FIXME: sz might not be a sane value
if (!_coff_buf_read(data, cf->sections[i].sz)) {
slog("coff_parse: I couldn't fread section %u (%s)'s data (%u bytes)\n", i+1, cf->sections[i].name, cf->sections[i].sz);
p_free(data);
goto fail;
}
cf->sections[i].data = data;
@ -159,20 +177,20 @@ coff_file* coff_parser(const char *path)
if (cf->num_symbols == 0) // if num_symbols==0, symtab_offset may be bogus
return cf; // just return
cf->func_tree = rb_new();
//printf("func_tree = %llx, *func_tree = %llx\n", cf->func_tree, *cf->func_tree);
cf->symbols = (coff_symbol*)calloc(sizeof(coff_symbol), cf->num_symbols);
cf->func_tree = rb_new(cf->pool, sizeof(coff_symbol*));
//slog("func_tree = %llx, *func_tree = %llx\n", cf->func_tree, *cf->func_tree);
cf->symbols = (coff_symbol*)p_alloc(cf->pool, sizeof(coff_symbol) *cf->num_symbols);
// Seek to the symbol table
if (fseek(f, cf->symtab_offset, SEEK_SET) != 0) {
printf("coff_parse: I couldn't seek to symtab_offset, 0x%x\n", cf->symtab_offset);
if (!_coff_buf_seek(cf->symtab_offset)) {
slog("coff_parse: I couldn't seek to symtab_offset, 0x%x\n", cf->symtab_offset);
goto fail;
}
for (i=0; i < cf->num_symbols; i++) {
uint8_t raw_symb[18];
if (fread(raw_symb, 18, 1, f) != 1) {
printf("coff_parse: I ran out of data pulling symbol #%u\n", i+1);
if (!_coff_buf_read(raw_symb, 18)) {
slog("coff_parse: I ran out of data pulling symbol #%u\n", i+1);
goto fail;
}
@ -183,25 +201,22 @@ coff_file* coff_parser(const char *path)
for (j=4, offset=0; j<8; j++) offset = (offset<<8) | raw_symb[j];
idx += offset;
// printf("Loading from external: base idx=0x%x, offset=%u, addr=0x%x\n", idx-offset, offset, idx);
// slog("Loading from external: base idx=0x%x, offset=%u, addr=0x%x\n", idx-offset, offset, idx);
if (fseek(f, idx, SEEK_SET) != 0) {
printf("coff_parse: I ran out of data pulling symbol %u's name (idx=0x%x)\n", i+1, idx);
if (!_coff_buf_seek(idx)) {
slog("coff_parse: I ran out of data pulling symbol %u's name (idx=0x%x)\n", i+1, idx);
goto fail;
}
for (j=0; (fread(&tmp_name[j], 1, 1, f)==1) && tmp_name[j]; j++) {
for (j=0; (_coff_buf_read(&tmp_name[j], 1)) && tmp_name[j]; j++) {
if (j >= 255) {
// printf("coff_parse: this symbol's name is too long: %u\n", i+1);
// slog("coff_parse: this symbol's name is too long: %u\n", i+1);
goto fail;
}
}
cf->symbols[i].name = malloc(j+1);
cf->symbols[i].name = p_alloc(cf->pool, j+1);
memcpy(cf->symbols[i].name, tmp_name, j);
cf->symbols[i].name[j] = 0;
fseek(f, cf->symtab_offset + (i+1)*18, SEEK_SET);
//printf("cf->symtab_offset = 0x%x, i=%u, (i+1)*18 = %u\n",
//cf->symtab_offset, i, (i+1)*18);
//printf("seeking back to 0x%x\n", cf->symtab_offset + (i+1)*18);
_coff_buf_seek(cf->symtab_offset + (i+1)*18);
}
else {
uint8_t tmp_name[9];
@ -220,17 +235,18 @@ coff_file* coff_parser(const char *path)
// FIXME: I need to handle numaux > 0.
//if (cf->symbols[i].numaux > 0) {
printf("%s\n", cf->symbols[i].name);
printf("value=0x%08x scnum=0x%04x type=0x%04x sclass=0x%02x numaux=%u\n\n",
slog("%s\n", cf->symbols[i].name);
slog("value=0x%08x scnum=0x%04x type=0x%04x sclass=0x%02x numaux=%u\n\n",
cf->symbols[i].value, cf->symbols[i].scnum, cf->symbols[i].type, cf->symbols[i].sclass, cf->symbols[i].numaux);
//}
if (cf->symbols[i].sclass == 2 || cf->symbols[i].sclass == 3) {
rb_insert(cf->func_tree, cf->symbols[i].value, &cf->symbols[i], NULL);
//printf("%s addr=0x%x\n", cf->symbols[i].name, cf->symbols[i].value);
void *ptr = &cf->symbols[i];
rb_insert(cf->func_tree, cf->symbols[i].value, &ptr, NULL);
//slog("%s addr=0x%x\n", cf->symbols[i].name, cf->symbols[i].value);
}
// printf("%u: %s (class=%u)\n", i+1, cf->symbols[i].name, cf->symbols[i].sclass);
// slog("%u: %s (class=%u)\n", i+1, cf->symbols[i].name, cf->symbols[i].sclass);
}
@ -242,21 +258,43 @@ coff_file* coff_parser(const char *path)
fail:
if (cf) {
if (cf->opt_header) {
free(cf->opt_header);
p_free(cf->opt_header);
}
if (cf->sections) {
for (i=0; i<cf->num_sections; i++) {
if (cf->sections[i].data) {
free(cf->sections[i].data);
p_free(cf->sections[i].data);
}
}
free(cf->sections);
p_free(cf->sections);
}
free(cf);
p_free(cf);
}
return NULL;
}
coff_file* coff_parse_from_path(const char *path, alloc_pool_t *parent_pool)
{
FILE *f = fopen(path, "rb");
uint8_t *buf = malloc(1);
uint32_t i=0, tmp;
coff_file *coff;
do {
buf = realloc(buf, i + 128*1024);
assert(buf);
tmp = fread(buf+i, 1, 128*1024, f);
i += tmp;
// don't load more than 64mb - there are surely no 64MB A/UX kernels
} while ((tmp > 0) && (i < 64*1024*1024));
coff = coff_parse(buf, i, parent_pool);
free(buf);
return coff;
}
// dump some data about a coff_file structure
void print_coff_info(coff_file *coff)
{
@ -264,19 +302,19 @@ void print_coff_info(coff_file *coff)
time_t timestamp = coff->timestamp;
uint32_t i;
printf("Magic = 0x%04x\n", coff->magic);
printf("Linked on %s", ctime_r(&timestamp, timebuf));
printf("Num sections = %u\n", coff->num_sections);
slog("Magic = 0x%04x\n", coff->magic);
slog("Linked on %s", ctime_r(&timestamp, timebuf));
slog("Num sections = %u\n", coff->num_sections);
printf("debug: num_symbols=%u, symtab_offset=0x%x\n", coff->num_symbols, coff->symtab_offset);
slog("debug: num_symbols=%u, symtab_offset=0x%x\n", coff->num_symbols, coff->symtab_offset);
for (i=0; i<coff->num_sections; i++) {
coff_section *s = &coff->sections[i];
char name[9];
memcpy(name, s->name, 8);
name[8] = 0;
printf("Section #%u: %s\n", i+1, name);
printf("\taddr=0x%08x, len=0x%x, (debug: paddr=0x%08x, flags=0x%08x)\n", s->v_addr, s->sz, s->p_addr, s->flags);
slog("Section #%u: %s\n", i+1, name);
slog("\taddr=0x%08x, len=0x%x, (debug: paddr=0x%08x, flags=0x%08x)\n", s->v_addr, s->sz, s->p_addr, s->flags);
}
}
@ -296,21 +334,21 @@ coff_symbol* coff_find_func(coff_file *coff, uint32_t addr)
rb_node *cur;
coff_symbol *last = NULL;
// printf("coff->num_symbols = %u\n", coff->num_symbols);
// slog("coff->num_symbols = %u\n", coff->num_symbols);
if (coff->num_symbols == 0)
return NULL;
cur = *coff->func_tree;
cur = coff->func_tree->root;
while (cur) {
// printf("... iterating\n");
// slog("... iterating\n");
if (addr < cur->key)
cur = cur->left;
else if (addr > cur->key) {
last = cur->value;
last = *(coff_symbol**)&cur[1];
cur = cur->right;
}
else
return cur->value;
return *(coff_symbol**)&cur[1];
}
return last;

View File

@ -1,84 +0,0 @@
/*
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 _COFF_H
#define _COFF_H
#include <stdint.h>
#include "redblack.h"
typedef struct {
char *name;
uint32_t value;
uint16_t scnum, type;
uint8_t sclass, numaux;
} coff_symbol;
// informed by http://www.delorie.com/djgpp/doc/coff/scnhdr.html
typedef struct {
char name[8];
uint32_t p_addr;
uint32_t v_addr;
uint32_t sz;
uint32_t data_ptr;
uint32_t reloc_ptr;
uint32_t line_ptr;
uint16_t num_relocs;
uint16_t num_lines;
uint32_t flags;
uint8_t *data;
} coff_section;
// data for this segment appears in the file, but shouldn't be copied into memory
#define coff_copy 0x0010
#define coff_text 0x0020
#define coff_data 0x0040
#define coff_bss 0x0080
typedef struct {
uint16_t magic;
uint16_t num_sections;
uint32_t timestamp;
uint32_t symtab_offset;
uint32_t num_symbols;
uint16_t opt_header_len;
uint16_t flags;
uint8_t *opt_header;
coff_section *sections;
rb_tree *func_tree;
coff_symbol *symbols;
} coff_file;
coff_symbol* coff_find_func(coff_file *coff, uint32_t addr);
coff_symbol* coff_find_symbol(coff_file *coff, const char *name);
coff_file* coff_parser(const char *path);
uint32_t be2native (uint8_t **dat, uint32_t bytes);
void print_coff_info(coff_file *coff);
#endif // _COFF_H

File diff suppressed because it is too large Load Diff

View File

@ -1,129 +0,0 @@
/*
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 _CORE_API_H
#define _CORE_API_H
#include <stdint.h>
typedef enum {
card_none = 0, // Empty slot
card_toby_frame_buffer, // Original Macintosh II video card
card_shoebill_video, // Fancy 21st-century Shoebill video card
card_shoebill_ethernet // FIXME: doesn't exist yet
} card_names_t;
typedef struct {
uint8_t *frame_buffer;
} shoebill_card_tfb_t;
typedef struct {
uint8_t r, g, b, a;
} video_ctx_color_t;
typedef struct {
video_ctx_color_t *direct_buf, *clut;
uint8_t *indexed_buf, *rom;
uint32_t pixels;
uint16_t width, height, scanline_width;
uint16_t depth, clut_idx;
double refresh_rate;
} shoebill_card_video_t;
typedef struct {
// Doesn't exist yet
} shoebill_card_ethernet_t;
typedef struct {
/*
* Fill in this part of the struct
* before you call shoebill_initialize()
*/
uint32_t ram_size;
const char *rom_path;
const char *aux_kernel_path;
uint8_t aux_verbose : 1; // Whether to boot A/UX in verbose mode
uint8_t aux_autoconfig : 1; // Whether to run A/UX autoconfig
uint16_t root_ctrl, swap_ctrl;
uint8_t root_drive, swap_drive;
uint8_t root_partition, swap_partition;
uint8_t root_cluster;
/* Devices at the 7 possible target SCSI ids */
struct {
const char *path;
uint64_t size; // will be filled in later
} scsi_devices[7]; // scsi device #7 is the initiator (can't be a target)
/* ^^^ You can stop now ^^^ */
/* Cards installed in the 16 (really, just 0x9 to 0xe) nubus slots */
struct {
card_names_t card_type;
union {
shoebill_card_tfb_t tfb;
shoebill_card_video_t video;
shoebill_card_ethernet_t ethernet;
} card;
} slots[16];
pthread_t cpu_thread_pid, clock_pid;
char error_msg[8192];
} shoebill_control_t;
uint32_t shoebill_initialize(shoebill_control_t *params);
uint32_t shoebill_install_video_card(shoebill_control_t *control, uint8_t slotnum,
uint16_t width, uint16_t height,
double refresh_rate);
/*
* These keyboard modifier constants match the ones used
* in NSEvent shifted right by 16 bits.
*/
enum {
modCapsLock = 1 << 0,
modShift = 1 << 1,
modControl = 1 << 2,
modOption = 1 << 3,
modCommand = 1 << 4
};
void shoebill_key(uint8_t down, uint8_t key);
void shoebill_key_modifier(uint8_t modifier_mask);
void shoebill_mouse_move(int32_t x, int32_t y);
void shoebill_mouse_move_delta (int32_t x, int32_t y);
void shoebill_mouse_click(uint8_t down);
void shoebill_start();
#endif

2059
core/cpu.c

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -929,6 +929,65 @@ void begin_definitions()
// subtract illegal size (00)
sub_range(inst, "00 00 xxxxxx xxxxxx");
// subtract move_from_d
sub_range(inst, "00 xx xxxxxx 000xxx");
// subtract move_to_d
sub_range(inst, "00 xx xxx000 xxxxxx");
}
{ // move_d_to_d
inst_t *inst = new_inst("move_d_to_d", "all", 1);
no_ea(inst);
add_range(inst, "00 xx xxx 000 000 xxx");
sub_range(inst, "00 00 xxx 000 000 xxx");
}
{ // move_to_d
inst_t *inst = new_inst("move_to_d", "all", 2);
{ // EA mode == addr register (byte-size not allowed)
set_range_group(inst, 0);
add_range(inst, "00 11 xxx000 MMMMMM");
add_range(inst, "00 10 xxx000 MMMMMM");
ea_add_mode(inst, EA_001);
}
{ // all other EA modes
set_range_group(inst, 1);
add_range(inst, "00 xx xxx000 MMMMMM");
sub_range(inst, "00 00 xxx000 MMMMMM");
ea_all(inst);
ea_sub_mode(inst, EA_001);
ea_sub_mode(inst, EA_000); // EA_000 is handled by move_d_to_d
}
}
{ // move_from_d
inst_t *inst = new_inst("move_from_d", "all", 1);
// I'm manually specifying this entire thing, since the EA description is too complicated
no_ea(inst);
// Add in all modes, all sizes
add_range(inst, "00 xx xxxxxx 000xxx");
// subtract the invalid destination modes (001, 111_010, 111_011, 111_100)
sub_range(inst, "00 xx xxx 001 xxxxxx");
sub_range(inst, "00 xx 010 111 xxxxxx");
sub_range(inst, "00 xx 011 111 xxxxxx");
sub_range(inst, "00 xx 100 111 xxxxxx");
// subtract the illegal destination modes (111_101, 111_110, 111_111)
sub_range(inst, "00 xx 101 111 xxxxxx");
sub_range(inst, "00 xx 110 111 xxxxxx");
sub_range(inst, "00 xx 111 111 xxxxxx");
// subtract illegal size (00)
sub_range(inst, "00 00 xxxxxx xxxxxx");
// subtract move_d_to_d
sub_range(inst, "00 xx xxx 000 000xxx");
}
{ // movea
@ -1434,14 +1493,8 @@ void begin_definitions()
/* --- FPU (68881) instructions --- */
{
inst_t *inst = new_inst("fpu_decode", "2", 1);
add_range(inst, "1111 001 xxx xxxxxx");
no_ea(inst);
}
/* { // all other fpu ops
inst_t *inst = new_inst("fpu_decode", "2", 1);
{ // all other fpu ops
inst_t *inst = new_inst("fpu_other", "2", 1);
add_range(inst, "1111 001 000 MMMMMM");
ea_all(inst);
}
@ -1452,9 +1505,30 @@ void begin_definitions()
ea_data_alterable(inst);
}
{ // FDBcc
inst_t *inst = new_inst("fdbcc", "2", 1);
add_range(inst, "1111 001 001 001xxx");
no_ea(inst);
}
{ // FTRAPcc
inst_t *inst = new_inst("ftrapcc", "2", 1);
add_range(inst, "1111 001 001 111 010");
add_range(inst, "1111 001 001 111 011");
add_range(inst, "1111 001 001 111 100");
no_ea(inst);
}
{ // FBcc
inst_t *inst = new_inst("fbcc", "2", 1);
add_range(inst, "1111 001 01x xxxxxx");
sub_range(inst, "1111 001 010 000000"); // fnop
no_ea(inst);
}
{ // fnop
inst_t *inst = new_inst("fnop", "2", 1);
add_range(inst, "1111 001 010 000000");
no_ea(inst);
}
@ -1470,7 +1544,7 @@ void begin_definitions()
add_range(inst, "1111 001 101 MMMMMM");
ea_control(inst);
ea_add_mode(inst, EA_011);
}*/
}
}

View File

@ -47,6 +47,12 @@ uint16_t dis_next_word (void)
return next;
}
uint32_t dis_next_long (void)
{
uint32_t next = dis_next_word();
return (next << 16) | dis_next_word();
}
//
// EA decoder routines
//
@ -67,7 +73,7 @@ void disass_ea_extended (char *buf, uint8_t mr)
// z == base displacement size
// I == index/indirect selection
// printf("index_reg_type=%u, index_reg=%u, index_sz=%u, scale=%u, brief/ful=%u, supress_base=%u, suppress_index=%u, base_disp_sz=%u, I=%x\n",
// slog("index_reg_type=%u, index_reg=%u, index_sz=%u, scale=%u, brief/ful=%u, supress_base=%u, suppress_index=%u, base_disp_sz=%u, I=%x\n",
// d, r, w, s, F, b, i, z, I);
if (F == 0) { // If this is the brief extension word
@ -269,8 +275,13 @@ char* decode_ea_rw (uint8_t mr, uint8_t sz)
} else if (sz == 2) {
sprintf(str, "0x%04x", ext);
} else {
const uint16_t ext2 = dis_next_word();
sprintf(str, "0x%04x%04x", ext, ext2);
uint32_t i;
assert((sz & 1) == 0);
sprintf(str, "0x%04x", ext);
for (i=2; i<sz; i+=2) {
const uint16_t ext2 = dis_next_word();
sprintf(str + strlen(str), "%04x", ext2);
}
}
return str;
}
@ -290,7 +301,8 @@ char* decode_ea_addr (uint8_t mr)
char *str = dis.ea_str_internal + dis.ea_last_pos_internal;
dis.ea_last_pos_internal = (dis.ea_last_pos_internal+256) % 1024;
switch (mode) {
case 0 ... 1: { // Data/address register direct mode
case 0:
case 1: { // Data/address register direct mode
sprintf(str, "???");
return str;
}
@ -299,11 +311,11 @@ char* decode_ea_addr (uint8_t mr)
return str;
}
case 3: { // address register indirect with postincrement mode
sprintf(str, "???");
sprintf(str, "(a%u)+", reg);
return str;
}
case 4: { // address register indirect with predecrement mode
sprintf(str, "???");
sprintf(str, "-(a%u)", reg);
return str;
}
case 5: { // address register indirect with displacement mode
@ -537,7 +549,18 @@ void dis_eori_to_sr() {
}
void dis_movep() {
sprintf(dis.str, "movep???");
const int16_t disp = dis_next_word();
~decompose(dis_op, 0000 ddd 1 s r 001 aaa);
if (r) { // reg -> mem
sprintf(dis.str, "movep.%c d%u,%s0x%x(a%u)", "wl"[s], d,
(disp >= 0) ? "" : "-", abs(disp), a);
}
else { // mem -> reg
sprintf(dis.str, "movep.%c %s0x%x(a%u),d%u", "wl"[s],
(disp >= 0) ? "" : "-", abs(disp), a, d);
}
}
void dis_bfextu() {
@ -754,7 +777,7 @@ void dis_long_div () {
sprintf(dest, "d%u", R);
if (Q != R)
sprintf(dest+2, ":d%u", Q);
sprintf(dis.str, "div%c%s.l %s,%s", "us"[u], s?"":"l", decode_ea_rw(M, 4), dest);
sprintf(dis.str, "div%c%s.l %s,%s", "us"[u], s?"l":"", decode_ea_rw(M, 4), dest);
}
void dis_cmpm () {
@ -794,12 +817,40 @@ void dis_movea () {
}
void dis_move () {
~decompose(dis_op, 00 ss RRR MMM oooooo)
~decompose(dis_op, 00 ss RRR MMM oooooo);
// (oooooo = source EA), (MMMRRR = dest EA)
const uint8_t sizes[3] = {1, 4, 2};
const char *sourceStr = decode_ea_rw(o, sizes[s-1]);
const char *destStr = decode_ea_rw((M<<3)|R, sizes[s-1]);
sprintf(dis.str, "move.%c %s,%s", "blw"[s-1], sourceStr, destStr);
const uint8_t sizes[4] = {0, 1, 4, 2};
const char *sourceStr = decode_ea_rw(o, sizes[s]);
const char *destStr = decode_ea_rw((M<<3)|R, sizes[s]);
sprintf(dis.str, "move.%c %s,%s", "?blw"[s], sourceStr, destStr);
}
void dis_move_d_to_d () {
~decompose(dis_op, 00 ss DDD 000 000 SSS);
sprintf(dis.str, "move.%c d%u,d%u", "?blw"[s], S, D);
}
void dis_move_to_d () {
~decompose(dis_op, 00 ss rrr 000 MMMMMM);
const uint8_t sizes[4] = {0, 1, 4, 2};
sprintf(dis.str,
"move.%c %s,d%u",
"?blw"[s],
decode_ea_rw(M, sizes[s]),
r);
}
void dis_move_from_d () {
~decompose(dis_op, 00 ss RRR MMM 000 rrr);
const uint8_t sizes[4] = {0, 1, 4, 2};
sprintf(dis.str,
"move.%c d%u,%s",
"?blw"[s],
r,
decode_ea_rw((M<<3) | R, sizes[s]));
}
void dis_scc () {
@ -1065,11 +1116,16 @@ void dis_pea() {
}
void dis_nbcd() {
sprintf(dis.str, "nbcd???");
~decompose(dis_op, 0100 1000 00 MMMMMM);
sprintf(dis.str, "nbcd %s", decode_ea_rw(M, 1));
}
void dis_sbcd() {
sprintf(dis.str, "sbcd???");
~decompose(dis_op, 1000 yyy 10000 r xxx);
if (r)
sprintf(dis.str, "sbcd d%u,d%u", x, y);
else
sprintf(dis.str, "sbcd -(a%u),-(a%u)", x, y);
}
void dis_pack() {
@ -1091,7 +1147,8 @@ void dis_divs() {
}
void dis_bkpt() {
sprintf(dis.str, "bkpt???");
~decompose(dis_op, 0100 1000 0100 1 vvv);
sprintf(dis.str, "bkpt %u", v);
}
void dis_swap() {
@ -1372,23 +1429,43 @@ void dis_move16 () {
}
void dis_rtm () {
sprintf(dis.str, "rtm???");
~decompose(dis_op, 0000 0110 1100 d rrr);
sprintf(dis.str, "rtm %c%u", "da"[d], r);
}
void dis_tas () {
sprintf(dis.str, "tas???");
~decompose(dis_op, 1000 rrr 011 MMMMMM);
sprintf(dis.str, "tas.b %s", decode_ea_rw(M, 1));
}
void dis_trapcc() {
sprintf(dis.str, "trapcc???");
~decompose(dis_op, 0101 cccc 11111 ooo);
const char *condition_names[16] = {
"t", "ra", "hi", "ls", "cc", "cs", "ne", "eq",
"vc", "vs", "pl", "mi", "ge", "lt", "gt", "le"
};
uint32_t data;
switch (o) {
case 2:
data = dis_next_word();
sprintf(dis.str, "trap%s.w 0x%04x", condition_names[c], data);
break;
case 3:
data = dis_next_long();
sprintf(dis.str, "trap%s.l 0x%08x", condition_names[c], data);
break;
case 4:
sprintf(dis.str, "trap%s", condition_names[c]);
break;
}
}
void dis_trapv() {
sprintf(dis.str, "trapv???");
sprintf(dis.str, "trapv");
}
void dis_mc68851_decode() {
~decompose(dis_op, 1111 000 a b c MMMMMM);
@ -1456,6 +1533,203 @@ void dis_mc68851_decode() {
assert(!"never get here");
}
const char *_fcc_names[32] = {
"f", "eq", "ogt", "oge", "olt", "ole", "ogl", "or",
"un", "ueq", "ugt", "uge", "ult", "ule", "ne", "t",
"sf", "seq", "gt", "ge", "lt", "le", "gl", "gle",
"ngle", "ngl", "nle", "nlt", "nge", "ngt", "sne", "st"
};
static void dis_fmove_to_mem(uint16_t ext)
{
const uint8_t _format_sizes[8] = {4, 4, 12, 12, 2, 8, 1, 12};
~decompose(dis_op, 1111 001 000 MMMMMM);
~decompose(ext, 011 fff sss kkkkkkk);
sprintf(dis.str, "fmove.%c", "lsxpwdbp"[f]);
if (f == 3)
sprintf(dis.str + strlen(dis.str), "{#%u}", k);
else
sprintf(dis.str + strlen(dis.str), "{d%u}", k >> 4);
sprintf(dis.str + strlen(dis.str), " fp%u,%s", s,
decode_ea_rw(M, _format_sizes[f]));
}
static void dis_fmovem_control(uint16_t ext)
{
~decompose(dis_op, 1111 001 000 MMMMMM);
~decompose(ext, 10 d CSI 0000 000000);
sprintf(dis.str, "fmovem.l ");
const uint16_t count = C + S + I;
if (count == 0)
sprintf(dis.str + strlen(dis.str), "0,");
if (C)
sprintf(dis.str + strlen(dis.str), "fpcr%s", (count > 1)?"&":",");
if (S)
sprintf(dis.str + strlen(dis.str), "fpsr%s", ((S+I) > 1)?"&":",");
if (I)
sprintf(dis.str + strlen(dis.str), "fpiar,");
sprintf(dis.str + strlen(dis.str), "%s", decode_ea_rw(M, count * 4));
}
static void dis_fmovem(uint16_t ext)
{
~decompose(dis_op, 1111 001 000 mmmrrr);
~decompose(dis_op, 1111 001 000 MMMMMM);
~decompose(ext, 11 d ps 000 LLLLLLLL); // Static register mask
~decompose(ext, 11 0 00 000 0yyy0000); // Register for dynamic mode
if (s) { // if dynamic mode
if (d) // mem -> reg
sprintf(dis.str, "fmovem.x %s,a%u", decode_ea_rw(M, 4), y);
else
sprintf(dis.str, "fmovem.x a%u,%s", y, decode_ea_rw(M, 4));
return;
}
uint32_t i, count=0;
char list[64] = "";
uint8_t oldmask = L, mask = L;
// for predecrement mode, the mask is reversed
if (m == 4) {
for (i=0; i<8; i++) {
mask <<= 1;
mask |= (oldmask & 1);
oldmask >>= 1;
count++;
}
}
for (i=0; i<8; i++) {
if (mask & 0x80)
sprintf(list + strlen(list), "fp%u.", i);
mask <<= 1;
}
if (d) // mem -> reg
sprintf(dis.str, "fmovem.x %s,%s", decode_ea_rw(M, 4), list);
else // reg -> mem
sprintf(dis.str, "fmovem.x %s,%s", list, decode_ea_rw(M, 4));
}
void dis_fscc () {
~decompose(dis_op, 1111 001 001 MMMMMM);
const uint16_t ext = dis_next_word();
~decompose(ext, 0000 0000 00 0ccccc);
sprintf(dis.str, "fs%s.b %s", _fcc_names[c], decode_ea_rw(M, 1));
}
void dis_fbcc () {
~decompose(dis_op, 1111 001 01s 0ccccc);
uint32_t new_pc = dis.orig_pc + 2;
if (s == 0) {
const int16_t tmp = dis_next_word();
new_pc += tmp;
}
else
new_pc += dis_next_long();
sprintf(dis.str, "fb%s.%c *0x%08x", _fcc_names[c], "wl"[s], new_pc);
}
void dis_fsave () {
~decompose(dis_op, 1111 001 100 MMMMMM);
sprintf(dis.str, "fsave %s", decode_ea_addr(M));
}
void dis_frestore () {
~decompose(dis_op, 1111 001 101 MMMMMM);
sprintf(dis.str, "frestore %s", decode_ea_addr(M));
}
void dis_fpu_other () {
~decompose(dis_op, 1111 001 000 MMMMMM);
const uint16_t ext = dis_next_word();
~decompose(ext, ccc xxx yyy eeeeeee);
switch (c) {
case 0: // Reg to reg
dis_fmath(dis_op, ext, dis.str);
return;
case 1: // unused
sprintf(dis.str, "f???");
return;
case 2: // Memory->reg & movec
dis_fmath(dis_op, ext, dis.str);
return;
case 3: // reg->mem
dis_fmove_to_mem(ext);
return;
case 4: // mem -> sys ctl registers
case 5: // sys ctl registers -> mem
dis_fmovem_control(ext);
return;
case 6: // movem to fp registers
case 7: // movem to memory
dis_fmovem(ext);
return;
}
}
void dis_fdbcc () {
~decompose(dis_op, 1111 001 001 001 rrr);
const uint16_t ext = dis_next_word();
~decompose(ext, 0000 0000 00 0ccccc);
const int16_t disp = dis_next_word();
// FIXME: 68kprm is helpfully unclear about which address
// to add the displacement. Based on cpDBcc, dbcc, bcc, and fbcc,
// I'm guessing it starts at the address *of* the displacement
const uint32_t newpc = dis.orig_pc + 4 + disp;
sprintf(dis.str, "fdb%s d%u,0x%08x", _fcc_names[c], r, newpc);
}
void dis_ftrapcc () {
~decompose(dis_op, 1111 001 001 111 ooo);
const uint16_t ext = dis_next_word();
~decompose(ext, 0000 0000 00 0ccccc);
uint32_t data;
switch (o) {
case 2:
data = dis_next_word();
sprintf(dis.str, "ftrap%s.w 0x%04x", _fcc_names[c], data);
break;
case 3:
data = dis_next_long();
sprintf(dis.str, "ftrap%s.l 0x%08x", _fcc_names[c], data);
break;
case 4:
sprintf(dis.str, "ftrap%s", _fcc_names[c]);
break;
default:
sprintf(dis.str, "ftrap????");
break;
}
}
void dis_fnop () {
const uint16_t ext = dis_next_word();
sprintf(dis.str, "fnop");
}
#include "dis_decoder_guts.c"
/*

862
core/ethernet.c Normal file
View File

@ -0,0 +1,862 @@
/*
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <stdlib.h>
#include <string.h>
#include "shoebill.h"
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/select.h>
#include "ethernet_rom/rom.c"
static uint32_t compute_nubus_crc(uint8_t *rom, uint32_t len)
{
uint32_t i, sum = 0;
for (i=0; i<len; i++) {
uint8_t byte = rom[i];
if (i==(len-9) || i==(len-10) || i==(len-11) || i==(len-12))
byte = 0;
sum = (sum << 1) + (sum >> 31) + byte;
}
rom[len-9] = sum & 0xff;
rom[len-10] = (sum >> 8) & 0xff;
rom[len-11] = (sum >> 16) & 0xff;
rom[len-12] = (sum >> 24) & 0xff;
return sum;
}
#define ETHPAGE() (ctx->cr >> 6)
const char *eth_r0_reg_names[16] = {
"cr", "clda0", "clda1", "bnry",
"tsr", "ncr", "fifo", "isr",
"crda0", "crda1", "reserved1", "reserved2",
"rsr", "cntr0", "cntr1", "cntr2"
};
const char *eth_1_reg_names[16] = {
"cr", "par0", "par1", "par2",
"par3", "par4", "par5", "curr",
"mar0", "mar1", "mar2", "mar3",
"mar4", "mar5", "mar6", "mar7"
};
const char *eth_w0_reg_names[16] = {
"cr", "pstart", "pstop", "bnry",
"tpsr", "tbcr0", "tbcr1", "isr",
"rsar0", "rsar1", "rbcr0", "rbcr1",
"rcr", "tcr", "dcr", "imr"
};
// command register bit masks
enum ether_cr_masks {
cr_stp = 1<<0, // stop
cr_sta = 1<<1, // start
cr_txp = 1<<2, // transmit packet
cr_rd0 = 1<<3, // remote dma command (0)
cr_rd1 = 1<<4, // remote dma command (1)
cr_rd2 = 1<<5, // remote dma command (2)
cr_ps0 = 1<<6, // page select (0)
cr_ps1 = 1<<7, // page select (1)
};
// interrupt service register bit masks
enum ether_isr_masks {
isr_prx = 1<<0, // packet received
isr_ptx = 1<<1, // packet transmitted
isr_rxe = 1<<2, // receive error
isr_txe = 1<<3, // transmit error
isr_ovw = 1<<4, // overwrite warning
isr_cnt = 1<<5, // counter overflow
isr_rdc = 1<<6, // remote dma complete
isr_rst = 1<<7, // reset status (not actually an interrupt)
};
// interrupt mask register bit masks
enum ether_imr_masks {
imr_pxre = 1<<0, // packet received interrupt enable
imr_ptxe = 1<<1, // packet transmitted interrupt enable
imr_rxee = 1<<2, // receive error interrupt enable
imr_txee = 1<<3, // transmit error interrupt enable
imr_ovwe = 1<<4, // overwrite warning interrupt enable
imr_cnte = 1<<5, // counter overflow interrupt enable
imr_rdce = 1<<6, // dma complete
};
// receive configuration register bit masks
enum ether_rcr_masks {
rcr_sep = 1<<0, // save error packets
rcr_ar = 1<<1, // accept runt packets
rcr_ab = 1<<2, // accept broadcast
rcr_am = 1<<3, // accept multicast
rcr_pro = 1<<4, // promiscuous physical
rcr_mon = 1<<5, // monitor mode
};
// transmit configuration register bit masks
enum ether_tcr_masks {
tcr_crc = 1<<0, // inhibit crc
tcr_lb0 = 1<<1, // encoded loopback control (0)
tcr_lb1 = 1<<2, // encoded loopback control (1)
tcr_atd = 1<<3, // auto transmit disable
tcr_ofst = 1<<4, // collision offset enable
};
// data configuration register bit masks
enum ether_dcr_masks {
dcr_wts = 1<<0, // word transfer select
dcr_bos = 1<<1, // byte order select
dcr_las = 1<<2, // long address select
dcr_ls = 1<<3, // loopback select
dcr_arm = 1<<4, // auto-initialize remote
dcr_ft0 = 1<<5, // fifo threshhold select (0)
dcr_ft1 = 1<<6, // fifo threshhold select (1)
};
// receive status register
enum ether_rsr_masks {
rsr_prx = 1<<0, // packet received intact
rsr_crc = 1<<1, // crc error
rsr_fae = 1<<2, // frame alignment error
rsr_fo = 1<<3, // fifo overrun
rsr_mpa = 1<<4, // missed packet
rsr_phy = 1<<5, // physical/multicast address (0->phys, 1->multi)
rsr_dis = 1<<6, // received disabled
rsr_dfr = 1<<7, // deferring
};
static void _nubus_interrupt(uint8_t slotnum)
{
shoe.via[1].rega_input &= 0x3f & ~(1 << (slotnum - 9));
via_raise_interrupt(2, IFR_CA1);
}
static void _clear_nubus_interrupt(uint8_t slotnum)
{
shoe.via[1].rega_input |= (1 << (slotnum - 9));
}
/*
* How many recv buffers (256-byte buffers) does the
* given number of bytes require?
*/
#define eth_recv_required_bufs(a) ({ \
const uint32_t sz = (a); \
(sz >> 8) + ((sz & 0xff) != 0); \
})
/*
* The number of 256-byte buffers available for writing
* in the receive buffer (between ctx->curr and ctx->bnry)
*/
#define eth_recv_free_bufs() ({ \
const uint8_t boundary = (ctx->bnry >= ctx->pstop) ? ctx->pstart : ctx->bnry; \
const uint8_t curr = (ctx->curr >= ctx->pstop) ? ctx->pstart : ctx->curr; \
const uint8_t total_bufs = ctx->pstop - ctx->pstart; \
uint8_t f; \
if (curr == boundary) \
f = 0; /* This shouldn't happen */ \
else if (curr > boundary) \
f = (ctx->pstop - curr) + (boundary- ctx->pstart) - 1; \
else \
f = boundary - curr - 1; \
f; \
})
void *_ethernet_receiver_thread(void *arg)
{
const uint8_t multicast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
shoebill_card_ethernet_t *ctx = (shoebill_card_ethernet_t*)arg;
uint8_t *buf = malloc(4096);
assert(buf);
// While nubus_ethernet_destroy() hasn't been called
while (!ctx->teardown) {
struct timeval tv;
fd_set fdset;
int ret;
uint32_t i;
FD_ZERO(&fdset);
FD_SET(ctx->tap_fd, &fdset);
tv.tv_sec = 0;
tv.tv_usec = 100000;
ret = select(ctx->tap_fd + 1, &fdset, NULL, NULL, &tv);
assert(ret != -1);
if (FD_ISSET(ctx->tap_fd, &fdset)) {
FD_CLR(ctx->tap_fd, &fdset);
/*
* Read in the next packet, leaving space for the 4 byte
* header
*/
int actual_packet_length = read(ctx->tap_fd, buf + 4, 4092);
slog("ethernet: received packet bnry=%x curr=%x pstart=%x pstop=%x cr=%x ret=%d frame=0x%02x%02x\n",
ctx->bnry, ctx->curr, ctx->pstart, ctx->pstop, ctx->cr, actual_packet_length,
buf[0x10], buf[0x11]);
/*
* If it's a bogus packet length, reject it
* (what's the actual minimum allowable packet length?)
*/
if (actual_packet_length <= 12) {
slog("ethernet: too small len\n");
continue;
}
/* I'm sure A/UX can't handle > 2kb packets */
if (actual_packet_length > 2048) {
slog("ethernet: too high len\n");
continue;
}
/* If it's neither multicast nor addressed to us, reject it */
if ((memcmp(buf + 4, ctx->ethernet_addr, 6) != 0) &&
(memcmp(buf + 4, multicast_addr, 6) != 0)) {
slog("ethernet: bad address\n");
continue;
}
/* A/UX seems to expect a minimum packet length (60 bytes??) */
if (actual_packet_length < 60)
actual_packet_length = 60;
/* The number of bytes to write + the 4 byte header */
const uint32_t received_bytes = actual_packet_length + 4;
pthread_mutex_lock(&ctx->lock);
/*
* If the card isn't initialized yet, just drop the packet
*/
if (ctx->cr & cr_stp) {
slog("ethernet: uninit\n");
pthread_mutex_unlock(&ctx->lock);
continue;
}
/*
* If the receive-register state is bogus, just drop the
* packet
*/
if ((ctx->pstop <= ctx->pstart) ||
(ctx->curr < ctx->pstart) ||
(ctx->bnry < ctx->pstart) ||
(ctx->pstop > 0x40) ||
(ctx->pstart == 0)) {
// This shouldn't happen if the card is initialized
assert(!"ethernet: receive register state is bogus");
pthread_mutex_unlock(&ctx->lock);
continue;
}
slog("ethernet: success, req=%u free=%u\n", eth_recv_required_bufs(received_bytes), eth_recv_free_bufs());
/*
* If there isn't enough buffer space to store the packet,
* block until ctx->bnry is modified.
*/
const uint8_t required_bufs = eth_recv_required_bufs(received_bytes);
while (eth_recv_free_bufs() < required_bufs) {
pthread_mutex_unlock(&ctx->lock);
if (ctx->teardown)
goto bail;
printf("ethernet: sleeping\n");
usleep(50); // FIXME: use a cond variable here
pthread_mutex_lock(&ctx->lock);
}
/* Roll around ctx->curr if necessary */
if (ctx->curr >= ctx->pstop)
ctx->curr = ctx->pstart;
const uint8_t orig_curr = ctx->curr;
/* Copy the packet to card RAM */
for (i = 0; i < required_bufs; i++) {
assert(ctx->curr != ctx->bnry); // this can't happen if we did our math right earlier
uint8_t *ptr = &ctx->ram[ctx->curr * 256];
memcpy(ptr, &buf[i * 256], 256);
ctx->curr++;
if (ctx->curr >= ctx->pstop)
ctx->curr = ctx->pstart;
}
assert(ctx->curr != ctx->bnry); // this can't happen if we did our math right earlier
/* The packet was received intact */
ctx->rsr = rsr_prx;
/* Fill in the 4 byte packet header */
ctx->ram[orig_curr * 256 + 0] = ctx->rsr;
ctx->ram[orig_curr * 256 + 1] = ctx->curr;
ctx->ram[orig_curr * 256 + 2] = received_bytes & 0xff; // low byte
ctx->ram[orig_curr * 256 + 3] = (received_bytes >> 8) & 0xff; // high byte
/* If the prx interrupt is enabled, interrupt */
if (ctx->imr & imr_pxre) {
ctx->isr |= isr_prx;
_nubus_interrupt(ctx->slotnum);
}
slog("ethernet: received packet (len=%d)\n", ret);
pthread_mutex_unlock(&ctx->lock);
}
}
bail:
free(buf);
return NULL;
}
/*
_Bool sent_arp_response = 0;
const uint8_t arp_response[60] = {
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // router's MAC address
0x22, 0x33, 0x55, 0x77, 0xbb, 0xdd, // card MAC address
0x08, 0x06, // ARP frame
0x00, 0x01, // Ethernet
0x08, 0x00, // IP
0x06, // MAC size
0x04, // IP size
0x00, 0x02, // reply
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // router's MAC address
192, 168, 2, 1, // router IP address
0x22, 0x33, 0x55, 0x77, 0xbb, 0xdd, // card MAC address
192, 168, 2, 100, // card IP address
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // padding
};
void _test_write_packet(shoebill_card_ethernet_t *ctx)
{
slog("ethernet: writing packet to curr=0x%02x\n", ctx->curr);
uint8_t *ptr = &ctx->ram[ctx->curr * 256];
// The packet was received intact
ctx->rsr = rsr_prx;
// The next packet address is the next 256 byte chunk
ctx->curr += 1;
ptr[0] = ctx->rsr;
ptr[1] = ctx->curr; // next packet ptr (8 bit)
ptr[2] = 60; // low byte of the packet size
ptr[3] = 0; // high byte of the packet size
memcpy(ptr + 4, arp_response, 60); // the packet
if (ctx->imr & imr_pxre)
ctx->isr |= isr_prx;
_nubus_interrupt(ctx->slotnum);
}
*/
void *_ethernet_sender_thread(void *arg)
{
shoebill_card_ethernet_t *ctx = (shoebill_card_ethernet_t*)arg;
slog("ethernet: ethernet_sender_thread starts...\n");
// While nubus_ethernet_destroy() hasn't been called
while (!ctx->teardown) {
struct timeval now;
struct timespec later;
int ret;
// Wait on the condition variable, with a timeout of 100ms
// slog("ethernet: locking cond mutex...\n");
pthread_mutex_lock(&ctx->sender_cond_mutex);
// slog("ethernet: locked cond mutex...\n");
gettimeofday(&now, NULL);
later.tv_sec = now.tv_sec;
later.tv_nsec = (now.tv_usec * 1000) + (1000000000 / 10);
if (later.tv_nsec >= 1000000000) {
later.tv_nsec -= 1000000000;
later.tv_sec++;
}
// slog("ethernet: waiting on cond...\n");
pthread_cond_timedwait(&ctx->sender_cond,
&ctx->sender_cond_mutex,
&later);
assert(pthread_mutex_unlock(&ctx->sender_cond_mutex) == 0);
// Only proceed if there's a packet ready to send
if (!ctx->send_ready)
continue;
slog("ethernet: sender thread wakes up...\n");
ctx->send_ready = 0;
// --- Send the packet here ---
assert(ctx->tbcr <= 2048); // sanity check the packet len
assert(ctx->tbcr >= 42);
ret = write(ctx->tap_fd, ctx->ram, ctx->tbcr);
if (ret != ctx->tbcr) {
slog("ethernet: write() returned %d, not %d errno=%d\n", ret, ctx->tbcr, errno);
}
// Lock the ethernet context (we're going to manipulate the ethernet registers)
pthread_mutex_lock(&ctx->lock);
// indicate that the packet has been sent
ctx->cr &= ~cr_txp; // clear the command register txp bit
ctx->isr |= isr_ptx; // interrupt status: packet transmitted with no errors
// the "packet transmitted" interrupt really should be enabled
if (ctx->imr & imr_ptxe) {
_nubus_interrupt(ctx->slotnum);
slog("ethernet: sender: sending interrupt to slot %u\n", ctx->slotnum);
}
assert(pthread_mutex_unlock(&ctx->lock) == 0);
}
return NULL;
}
void nubus_ethernet_init(void *_ctx, uint8_t slotnum, uint8_t ethernet_addr[6], int tap_fd)
{
shoebill_card_ethernet_t *ctx = (shoebill_card_ethernet_t*)_ctx;
memset(ctx, 0, sizeof(shoebill_card_ethernet_t));
memcpy(ctx->rom, _ethernet_rom, 4096);
memcpy(ctx->ethernet_addr, ethernet_addr, 6);
memcpy(ctx->rom, ethernet_addr, 6);
ctx->rom[6] = 0x00;
ctx->rom[7] = 0x00;
ctx->slotnum = slotnum; // so the threads know which slot this is
pthread_mutex_init(&ctx->lock, NULL);
pthread_cond_init(&ctx->sender_cond, NULL);
pthread_mutex_init(&ctx->sender_cond_mutex, NULL);
pthread_create(&ctx->sender_pid, NULL, _ethernet_sender_thread, ctx);
pthread_create(&ctx->receiver_pid, NULL, _ethernet_receiver_thread, ctx);
/*
* The first 8 bytes contain the MAC address
* and aren't part of the CRC
*/
compute_nubus_crc(&ctx->rom[8], 4096 - 8);
ctx->cr |= cr_stp; // "STP powers up high"
ctx->isr |= isr_rst; // I presume ISR's RST powers up high too
/* Platform-specific tap code */
ctx->tap_fd = tap_fd;
}
void nubus_ethernet_destroy_func(uint8_t slotnum)
{
shoebill_card_ethernet_t *ctx = (shoebill_card_ethernet_t*)shoe.slots[slotnum].ctx;
ctx->teardown = 1;
pthread_join(ctx->sender_pid, NULL);
pthread_join(ctx->receiver_pid, NULL);
pthread_mutex_destroy(&ctx->lock);
pthread_mutex_destroy(&ctx->sender_cond_mutex);
pthread_cond_destroy(&ctx->sender_cond);
}
uint32_t nubus_ethernet_read_func(const uint32_t rawaddr,
const uint32_t size,
const uint8_t slotnum)
{
shoebill_card_ethernet_t *ctx = (shoebill_card_ethernet_t*)shoe.slots[slotnum].ctx;
uint32_t result = 0;
pthread_mutex_lock(&ctx->lock);
switch ((rawaddr >> 16) & 0xf) {
case 0xd: { // ram
const uint16_t addr = rawaddr & 0x3fff;
uint8_t *ram = ctx->ram;
if (size == 1)
result = ram[addr];
else if (size == 2) {
result = ram[addr] << 8;
result |= ram[(addr+1) & 0x3fff];
}
else
assert(!"read: bogus size");
// slog("ethernet: reading from ram addr 0x%x sz=%u ", addr, size);
goto done;
}
case 0xe: { // registers
// For some reason, the register address bits are all inverted
const uint8_t reg = 15 ^ ((rawaddr >> 2) & 15);
assert(size == 1);
{
const char *name = "???";
if (ETHPAGE() == 0) name = eth_r0_reg_names[reg];
else if (ETHPAGE() == 1) name = eth_1_reg_names[reg];
slog("ethernet: reading from register %u (%s) (raw=0x%x) pc=0x%x ", reg, name, rawaddr, shoe.pc);
}
if (reg == 0) { // command register (exists in all pages)
result = ctx->cr;
goto done;
} else if (ETHPAGE() == 0) { // page 0
switch (reg) {
default:
assert(!"never get here");
goto done;
case 1: // clda0 (current local dma address 0)
goto done;
case 2: // clda1 (current local dma address 1)
goto done;
case 3: // bnry (boundary pointer)
result = ctx->bnry;
goto done;
case 4: // tsr (transmit status)
goto done;
case 5: // ncr (number of collisions)
goto done;
case 6: // fifo
goto done;
case 7: // isr (interrupt status register)
result = ctx->isr;
// test test test
// if we're reading isr_ptx for the first time,
// send a test packet (but never again)
/*if ((result & isr_ptx) && (!sent_arp_response)) {
sent_arp_response = 1;
_test_write_packet(ctx);
}*/
goto done;
case 8: // crda0 (current remote DMA address 0)
goto done;
case 9: // crda1 (current remote DMA address 1)
goto done;
case 10: // reserved 1
assert(!"read to reserved 1");
goto done;
case 11: // reserved 2
assert(!"read to reserved 2");
goto done;
case 12: // rsr (receive status register)
result = ctx->rsr;
goto done;
case 13: // cntr0 (tally counter 0 (frame alignment errors))
goto done;
case 14: // cntr1 (tally counter 1 (crc errors))
goto done;
case 15: // cntr2 (tally counter 2 (missed packet errors))
goto done;
}
} else if (ETHPAGE() == 1) { // page 1
switch (reg) {
default:
assert(!"never get here");
goto done;
case 1: // par (physical address)
case 2:
case 3:
case 4:
case 5:
case 6:
result = ctx->par[reg - 1];
goto done;
case 7: // curr (current page register)
result = ctx->curr;
goto done;
case 8: // mar (multicast address)
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
result = ctx->mar[reg - 8];
goto done;
}
} else
assert(!"read: Somebody accessed page 2 or 3!");
assert(!"never get here");
goto done;
}
case 0xf: { // rom
// Byte lanes = 0101 (respond to shorts)
// respond to (addr & 3 == 0) and (addr & 3 == 2)
// xxxx00 xxxx10
if ((rawaddr & 1) == 0)
result = ctx->rom[(rawaddr >> 1) % 4096];
slog("ethernet: reading from rom addr=%x ", rawaddr);
goto done;
}
default: // Not sure what happens when you access a different addr
assert(!"read: unknown ethernet register");
}
done:
pthread_mutex_unlock(&ctx->lock);
slog("result = 0x%x\n", result);
// slog("ethernet: reading 0x%x sz=%u from addr 0x%x\n", result, size, rawaddr);
return result;
}
void nubus_ethernet_write_func(const uint32_t rawaddr,
const uint32_t size,
const uint32_t data,
const uint8_t slotnum)
{
shoebill_card_ethernet_t *ctx = (shoebill_card_ethernet_t*)shoe.slots[slotnum].ctx;
uint32_t i;
pthread_mutex_lock(&ctx->lock);
switch ((rawaddr >> 16) & 0xf) {
case 0xd: { // ram
const uint16_t addr = rawaddr & 0x3fff;
uint8_t *ram = ctx->ram;
if (size == 1)
ram[addr] = data;
else if (size == 2) {
ram[addr] = data >> 8;
ram[(addr+1) & 0x3fff] = data & 0xff;
}
else
assert(!"write: bogus size");
// slog("ethernet: writing 0x%x sz=%u to ram addr 0x%x\n", data, size, addr);
goto done;
}
case 0xe: { // registers
// For some reason, the register address bits are all inverted
const uint8_t reg = 15 ^ ((rawaddr >> 2) & 15);
assert(size == 1);
{
const char *name = "???";
if (ETHPAGE() == 0) name = eth_w0_reg_names[reg];
else if (ETHPAGE() == 1) name = eth_1_reg_names[reg];
slog("ethernet: writing 0x%02x to register %u (%s) (rawaddr=0x%x) pc=0x%x\n", data, reg, name, rawaddr, shoe.pc);
}
if (reg == 0) { // command register (exists in all pages)
// If we're setting TXP, wake up the sender thread
if (((ctx->cr & cr_txp) == 0) &&
((data & cr_txp) != 0)) {
ctx->send_ready = 1;
assert(pthread_mutex_lock(&ctx->sender_cond_mutex) == 0);
assert(pthread_cond_signal(&ctx->sender_cond) == 0);
assert(pthread_mutex_unlock(&ctx->sender_cond_mutex) == 0);
}
// if we're setting STA, clear isr_rst
if (data & cr_sta)
ctx->isr &= ~isr_rst;
// FIXME: if we're setting STP, then we probably need to set isr_rst
ctx->cr = data;
goto done;
} else if (ETHPAGE() == 0) { // page 0
switch (reg) {
default:
assert(!"never get here");
goto done;
case 1: // pstart (page start)
ctx->pstart = data;
goto done;
case 2: // pstop (page stop)
ctx->pstop = data;
goto done;
case 3: // bnry (boundary pointer)
ctx->bnry = data;
goto done;
case 4: // tpsr (transmit page start address)
ctx->tpsr = data;
goto done;
case 5: // tbcr0 (transmit byte count 0)
ctx->tbcr = (ctx->tbcr & 0xff00) | data;
goto done;
case 6: // tbcr1 (transmit byte count 1)
ctx->tbcr = (ctx->tbcr & 0x00ff) | (data<<8);
goto done;
case 7: { // isr (interrupt status)
// writing 1's clears the bits in the ISR
uint8_t mask = data & 0x7f; // but not the RST bit
ctx->isr &= ~mask;
/*
* If there are packets yet to be processed,
* then continue to assert the isr_prx bit
*/
uint8_t inc_boundary = ctx->bnry + 1;
if (inc_boundary >= ctx->pstop)
inc_boundary = ctx->pstart;
if (ctx->curr != inc_boundary)
ctx->isr |= isr_prx;
/*
* If prx and ptx are no longer asserted,
* then we may clear the nubus interrupt.
*/
if (((ctx->isr & (isr_prx | isr_ptx)) == 0) &&
((ctx->cr & cr_stp) == 0))
_clear_nubus_interrupt(slotnum);
goto done;
}
case 8: // rsar0 (remote start address 0)
goto done;
case 9: // rsar1 (remote start address 1)
goto done;
case 10: // rbcr0 (remote byte count 0)
goto done;
case 11: // rbcr1 (remote byte count 1)
goto done;
case 12: // rcr (receive configuration)
ctx->rcr = data;
goto done;
case 13: // tcr (transmit configuration)
ctx->tcr = data;
goto done;
case 14: // dcr (data configuration)
ctx->dcr = data;
goto done;
case 15: // imr (interrupt mask)
ctx->imr = data & 0x7f;
goto done;
}
} else if (ETHPAGE() == 1) { // page 1
switch (reg) {
default:
assert(!"never get here");
goto done;
case 1: // par (physical address)
case 2:
case 3:
case 4:
case 5:
case 6:
ctx->par[reg - 1] = data;
goto done;
case 7: // curr (current page register)
ctx->curr = data;
goto done;
case 8: // mar (multicast address)
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
ctx->mar[reg - 8] = data;
goto done;
}
} else
assert(!"write: Somebody accessed page 2 or 3!");
assert(!"never get here");
goto done;
}
default:
assert(!"write: unknown ethernet register");
}
done:
pthread_mutex_unlock(&ctx->lock);
return;
}

BIN
core/ethernet_rom/rom.bin Normal file

Binary file not shown.

514
core/ethernet_rom/rom.c Normal file
View File

@ -0,0 +1,514 @@
uint8_t _ethernet_rom[4096] = {
0x77, 0x6f, 0x6f, 0x66, 0x00, 0x00, 0x00, 0x00,
0x77, 0x6f, 0x6f, 0x66, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x0c, 0x80, 0x00, 0x00, 0x64,
0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x14,
0x02, 0x00, 0x00, 0x18, 0x20, 0x00, 0x00, 0x08,
0x24, 0x00, 0x00, 0x28, 0xff, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x53, 0x68, 0x6f, 0x65, 0x62, 0x69, 0x6c, 0x6c,
0x20, 0x50, 0x68, 0x6f, 0x6e, 0x79, 0x20, 0x45,
0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x00,
0x01, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x14,
0x04, 0x00, 0x00, 0x18, 0x53, 0x68, 0x6f, 0x65,
0x62, 0x69, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
0x52, 0x65, 0x76, 0x2d, 0x31, 0x00, 0x00, 0x00,
0x42, 0x6f, 0x72, 0x74, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x14, 0x02, 0x00, 0x00, 0x18,
0x0a, 0x00, 0x00, 0x30, 0x80, 0xff, 0xff, 0x7c,
0xff, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01,
0x00, 0x00, 0x00, 0x01, 0x4e, 0x65, 0x74, 0x77,
0x6f, 0x72, 0x6b, 0x5f, 0x45, 0x74, 0x68, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x5f, 0x53, 0x68, 0x6f,
0x65, 0x62, 0x69, 0x6c, 0x6c, 0x00, 0x00, 0x00,
0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0, 0x24,
0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x5a, 0x93, 0x2b, 0xc7, 0x00, 0xa5
};

View File

@ -0,0 +1 @@
# File: shoebill_ether.make # Target: shoebill_ether # Sources: shoebill_ether_rom.a OBJECTS = shoebill_ether_rom.a.o shoebill_ether ÄÄ shoebill_ether.make {OBJECTS} Link ¶ {OBJECTS} ¶ -o shoebill_ether shoebill_ether_rom.a.o Ä shoebill_ether.make shoebill_ether_rom.a Asm shoebill_ether_rom.a

View File

@ -0,0 +1 @@
MACHINE MC68020 STRING C PRINT OFF ; What does this do? INCLUDE 'SysErr.a' INCLUDE 'SysEqu.a' INCLUDE 'ROMEqu.a' INCLUDE 'SlotEqu.a' INCLUDE 'TimeEqu.a' INCLUDE 'Traps.a' INCLUDE 'VideoEqu.a' INCLUDE 'QuickEqu.a' PRINT ON VideoDeclROM MAIN WITH VDPageInfo,SlotIntQElement ; EtherAddr is placed here, before sResourceDir and out of the range of the CRC ; check, because I guess it was too difficult to recompute the CRC when they were ; burning EPROMs back in 1986. ; So there's some ugly offset-accounting to make the rom seem (4096-8) bytes long, ; but still access this MAC address. myEtherAddr dc.l 'woof' dc.l 'woof' FormatBlockSize EQU 20 ROMSize EQU 4096 MyBoardID EQU $0008 ; Apple EtherTalk board ID ; ---- sResource directory ---- CategoryBoard EQU 1 CategoryEther EQU 128 sResourceDir OSLstEntry CategoryBoard, sResourceBoard OSLstEntry CategoryEther, sResourceEther DatLstEntry endOfList,0 ; ---- Board sResource ---- sResourceBoard OSLstEntry sRsrcType, boardType OSLstEntry sRsrcName, boardName DatLstEntry boardID, MyBoardID OSLstEntry vendorInfo, myVendorInfo ; No primary or secondary init needed (phew) DatLstEntry endOfList, 0 boardType DC.W CatBoard ; category DC.W TypBoard ; type DC.W 0 ; driver sw ? DC.W 0 ; driver hw ? STRING C boardName DC.L 'Shoebill Phony Ethernet' myVendorInfo OSLstEntry VendorId, myVendorID OSLstEntry RevLevel, myRevLevel OSLstEntry PartNum, myPartNum myVendorID DC.L 'Shoebill' myRevLevel DC.L 'Rev-1' myPartNum DC.L 'Bort' ; ---- Ethernet sResource ---- sResourceEther OSLstEntry sRsrcType, myEtherType OSLstEntry sRsrcName, myEtherName OSLstEntry MinorBaseOS, myMinorBaseOS dc.w $80ff ; 80 -> MAC address, $FFFFxx relative address of the MAC address dc.w -*+2 DatLstEntry endOfList, 0 myEtherType dc.w CatNetwork dc.w TypEtherNet dc.w 0 ; drvrSw, doesn't matter dc.w 1 ; drvrHw, this is DrHw3Com on Apple EtherTalk myEtherName dc.l 'Network_Ethernet_Shoebill' myMinorBaseOS DC.L $D0000 STRING C ; ---- Format block ---- ; Pad to align this structure with the end of the rom ORG ROMSize-FormatBlockSize ; Offset to sResource directory ;OSLstEntry 0,sResourceDir DC.L (sResourceDir-*)**$00FFFFFF DC.L ROMSize-8 DC.L 0 ; CRC goes here DC.B 1 ; Rom revision level DC.B AppleFormat DC.L TestPattern DC.B 0 ; Reserved DC.B $A5 ; Byte lanes 1010 0101 (LSB from CPU's perspective) ENDP END

View File

@ -30,8 +30,12 @@
#define SSW_IS_READ (1<<6)
#define SSW_DF (1<<8)
// throw the long-format (format 0xb) buss error. Mac II ROM expects to see this format for nubus bus errors.
// FIXME: nearly all the fields here are bogus
/*
* Throw the long-format (format 0xb) bus error. Mac II ROM expects to see
* this format for nubus bus errors.
*
* FIXME: nearly all the fields here are bogus
*/
void throw_long_bus_error(uint32_t addr, uint8_t is_write)
{
if (shoe.suppress_exceptions) {
@ -41,7 +45,7 @@ void throw_long_bus_error(uint32_t addr, uint8_t is_write)
// Save this value now, because lset() calls will reset it
const uint8_t fc = shoe.logical_fc;
//printf("throw_long_bus_error(): I'm throwing a LONG bus error (at pc = 0x%08x)!\n", shoe.orig_pc);
//slog("throw_long_bus_error(): I'm throwing a LONG bus error (at pc = 0x%08x)!\n", shoe.orig_pc);
// set supervisor bit
set_sr_s(1);
@ -56,12 +60,12 @@ void throw_long_bus_error(uint32_t addr, uint8_t is_write)
// fetch vector handler address
const uint32_t vector_addr = lget(shoe.vbr + vector_offset, 4);
//printf("throw_long_bus_error(): shoe.vbr=0x%08x, vector_addr=0x%08x, offending addr=0x%08x, shoe.op=0x%04x\n", shoe.vbr, vector_addr, addr, shoe.op);
//slog("throw_long_bus_error(): shoe.vbr=0x%08x, vector_addr=0x%08x, offending addr=0x%08x, shoe.op=0x%04x\n", shoe.vbr, vector_addr, addr, shoe.op);
assert(!shoe.abort); // FIXME: I can't handle another exception here
const uint16_t ssw = SSW_DF | (is_write ? 0 : SSW_IS_READ) | fc;
// Note: We're pushing frame format 0xA
// Note: We're pushing frame format 0xB
push_a7(0, 4); // internal registers, 18 words
push_a7(0, 4);
@ -93,7 +97,7 @@ void throw_long_bus_error(uint32_t addr, uint8_t is_write)
push_a7(0, 4); // instruction pipe stage B and C
push_a7(ssw, 2); // special status word
push_a7(0, 2); // internal register 1
push_a7(0xB000 | vector_offset, 2); // format word
push_a7(0xB000 | vector_offset, 2); // format word (frame format B)
push_a7(shoe.orig_pc, 4); // PC for the current instruction
push_a7(shoe.orig_sr, 2); // original status register
@ -116,7 +120,7 @@ void throw_bus_error(uint32_t addr, uint8_t is_write)
//dbg_state.running = 0;
//printf("throw_bus_error(): I'm throwing a bus error (at pc = 0x%08x)!\n", shoe.orig_pc);
//slog("throw_bus_error(): I'm throwing a bus error (at pc = 0x%08x)!\n", shoe.orig_pc);
// set supervisor bit
set_sr_s(1);
@ -131,7 +135,7 @@ void throw_bus_error(uint32_t addr, uint8_t is_write)
// fetch vector handler address
const uint32_t vector_addr = lget(shoe.vbr + vector_offset, 4);
//printf("throw_bus_error(): shoe.vbr=0x%08x, vector_addr=0x%08x, offending addr=0x%08x, shoe.op=0x%04x, a7=0x%08x", shoe.vbr, vector_addr, addr, shoe.op, shoe.a[7]);
//slog("throw_bus_error(): shoe.vbr=0x%08x, vector_addr=0x%08x, offending addr=0x%08x, shoe.op=0x%04x, a7=0x%08x", shoe.vbr, vector_addr, addr, shoe.op, shoe.a[7]);
assert(!shoe.abort); // FIXME: I can't handle another exception here
const uint16_t ssw =
@ -139,7 +143,7 @@ void throw_bus_error(uint32_t addr, uint8_t is_write)
(is_write ? 0 : SSW_IS_READ) | // read or write
fc; // a/ux 3.0.1 cares about this - the address space
//printf(" fc=%u\n", shoe.logical_fc);
//slog(" fc=%u\n", shoe.logical_fc);
// Note: We're pushing frame format 0xA
push_a7(0, 4); // internal registers 5 and 4
@ -163,12 +167,12 @@ void throw_bus_error(uint32_t addr, uint8_t is_write)
void throw_address_error()
{
printf("throw_address_error(): I'm throwing an address error!\n");
slog("throw_address_error(): I'm throwing an address error!\n");
assert(!"address error");
shoe.abort = 1;
}
static void throw_frame_zero(uint16_t sr, uint32_t pc, uint16_t vector_num)
void throw_frame_zero(uint16_t sr, uint32_t pc, uint16_t vector_num)
{
// set supervisor bit
set_sr_s(1);
@ -213,11 +217,11 @@ void throw_frame_two (uint16_t sr, uint32_t next_pc, uint32_t vector_num, uint32
void throw_illegal_instruction()
{
//printf("throw_illegal_instruction(): I'm throwing an illegal instruction exception! (shoe.pc = 0x%08x, op=0x%04x, a7=0x%08x)\n", shoe.orig_pc, shoe.op, shoe.a[7]);
//slog("throw_illegal_instruction(): I'm throwing an illegal instruction exception! (shoe.pc = 0x%08x, op=0x%04x, a7=0x%08x)\n", shoe.orig_pc, shoe.op, shoe.a[7]);
if ((shoe.op != 0xf010) && ((shoe.op >> 12) != 0xa))
/*if ((shoe.op != 0xf010) && ((shoe.op >> 12) != 0xa))
//assert(!"illegal");
dbg_state.running = 0;
dbg_state.running = 0; */
// fetch vector number
const uint32_t vector_num =
@ -227,7 +231,7 @@ void throw_illegal_instruction()
throw_frame_zero(shoe.orig_sr, shoe.orig_pc, vector_num);
/*if ((shoe.op >> 12) == 0xa) {
printf("Atrap: %s\n", atrap_names[shoe.op & 0xfff]?atrap_names[shoe.op & 0xfff]:"???");
slog("Atrap: %s\n", atrap_names[shoe.op & 0xfff]?atrap_names[shoe.op & 0xfff]:"???");
}
else
dbg_state.running = 0;*/
@ -236,16 +240,9 @@ void throw_illegal_instruction()
void throw_privilege_violation()
{
//printf("throw_privilege_violation(): I'm throwing a privilege violation exception! (shoe.orig_pc = 0x%08x op=0x%04x\n", shoe.orig_pc, shoe.op);
//slog("throw_privilege_violation(): I'm throwing a privilege violation exception! (shoe.orig_pc = 0x%08x op=0x%04x\n", shoe.orig_pc, shoe.op);
throw_frame_zero(shoe.orig_sr, shoe.orig_pc, 8);
shoe.abort = 1;
// shoe.abort = 1;
}
void throw_divide_by_zero()
{
printf("throw_divide_by_zero(): I'm throwing a divide-by-zero exception!\n");
assert(0);
shoe.abort = 1;
}

1307
core/filesystem.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,8 @@
#include <stdio.h>
#include <assert.h>
#include "shoebill.h"
#include <string.h>
#include "../core/shoebill.h"
const char *latch_names[8] = {
"phase0", "phase1", "phase2", "phase3",
@ -47,13 +48,13 @@ uint8_t iwm_dma_read()
if (latch_val)
shoe.iwm.latch |= (1 << latch_addr);
else
shoe.iwm.latch &= (~(1 << latch_addr));
shoe.iwm.latch &= (~~(1 << latch_addr));
// reg = {q7, q6, motor}
const uint8_t reg = ((shoe.iwm.latch >> 5) & 6) |
((shoe.iwm.latch >> 4) & 1);
printf("iwm_dma_read: %s %s (reg = %u%u%u '%s' ",
slog("iwm_dma_read: %s %s (reg = %u%u%u '%s' ",
latch_val ? "setting" : "clearing",
latch_names[latch_addr],
(reg>>2), (reg>>1)&1, reg&1, reg_names[reg]);
@ -75,12 +76,12 @@ uint8_t iwm_dma_read()
case 2:
case 3: // Read status register
// High 3 bits are mode register, low 5 are status
result = (shoe.iwm.status & 0b10100000);
result |= (shoe.iwm.mode & 0b11111);
result = (shoe.iwm.status & ~b(10100000));
result |= (shoe.iwm.mode & ~b(11111));
break;
case 4:
case 5: // Read "write-handshake" register
result = (shoe.iwm.handshake | 0b00111111); // low 6 bits all 1's
result = (shoe.iwm.handshake | ~b(00111111)); // low 6 bits all 1's
break;
default:
result = 0;
@ -88,7 +89,7 @@ uint8_t iwm_dma_read()
}
done:
printf("result=0x%02x)\n", result);
slog("result=0x%02x)\n", result);
return result;
}
@ -102,17 +103,17 @@ void iwm_dma_write()
if (latch_val)
shoe.iwm.latch |= (1 << latch_addr);
else
shoe.iwm.latch &= (~(1 << latch_addr));
shoe.iwm.latch &= (~~(1 << latch_addr));
// reg = {q7, q6, motor}
const uint8_t reg = ((shoe.iwm.latch >> 5) & 6) |
((shoe.iwm.latch >> 4) & 1);
printf("iwm_dma_write: %s %s (reg = %u%u%u '%s' val 0x%02x)\n",
latch_val ? "setting" : "clearing",
latch_names[latch_addr],
(reg>>2), (reg>>1)&1, reg&1, reg_names[reg],
data);
slog("iwm_dma_write: %s %s (reg = %u%u%u '%s' val 0x%02x)\n",
latch_val ? "setting" : "clearing",
latch_names[latch_addr],
(reg>>2), (reg>>1)&1, reg&1, reg_names[reg],
data);
// Allegedly, register writes can only occur when latch_val==1
if (!latch_val) {
@ -121,10 +122,20 @@ void iwm_dma_write()
switch (reg) {
case 6: // Write mode
shoe.iwm.mode = data & 0b01111111;
shoe.iwm.mode = data & ~b(01111111);
break;
case 7: // Write data
shoe.iwm.data = data;
break;
}
}
void init_iwm_state ()
{
memset(&shoe.iwm, 0, sizeof(iwm_state_t));
}
void reset_iwm_state ()
{
memset(&shoe.iwm, 0, sizeof(iwm_state_t));
}

4256
core/fpu.c

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,6 @@ use strict;
use Carp;
use Storable qw(dclone);
my $glob_printLineNumbers = 1; # Whether to prepend generated lines with their corresponding input file's line numbers
my $tab = " "; # one tab => four spaces
main();
@ -140,9 +139,6 @@ sub parse {
if ($newline) { # a newline just began
$newline = 0;
$ctx->{indent} = $text->{indents}->[$line_no]; # keep track of how many indents are on this line
if ($glob_printLineNumbers and ($ctx->{depth}==0)) {
# $out .= sprintf('/*%04u*/ ', $line_no+1);
}
$out .= spaces($ctx->{indent}); # and begin the line with the appropriate indentation
}
@ -155,9 +151,6 @@ sub parse {
my $macro = resolve_macro($ctx);
$i = $ctx->{cur_pos};
if ($glob_printLineNumbers and ($ctx->{depth}==0)) {
# $line_str = sprintf('/*%04u*/ ', $line_no+1);
}
$out .= join("\n$line_str".spaces($ctx->{indent}), split(/\n/, $macro->{str}));
}
@ -328,19 +321,6 @@ sub count_args {
# Macros go here:
# ------------------------------------------------------------------
sub macro_repeat {
my $args = shift;
my $num = $args->[0];
my $text = $args->[1];
my $str = "";
for (my $i=0; $i < $num; $i++) {
$str .= $text;
}
return "{$str}";
}
# ~decompose(op, "0101 ab0cd mmmrrr")
sub macro_decompose {
my ($args, $ctx) = @_;
@ -416,23 +396,6 @@ sub macro_b {
return sprintf("0x%x", $val);
}
# ~perl({my $str="hello"; print $str; return $str;}) // causes macrophile.pl to print hello and insert "hello" into the generated file
sub macro_perl {
my ($args, $ctx) = @_;
if (scalar(@$args) != 1) {
croak(sprintf("line %u: ~perl: ~perl() expects 1 argument (preferably a block), got %u", $ctx->{current_line}, scalar(@$args)));
}
my $code = $args->[0];
my $_perl_return_val;
eval 'sub ___macro_perl_sub {'.$code.'} $_perl_return_val=___macro_perl_sub($args,$ctx);';
if ($@) {
croak(sprintf("line %u: ~perl: code fragment croaked, err={%s}", $ctx->{current_line}, $@));
}
return $_perl_return_val;
}
# if (~bmatch(op, 1000 xxxx 01 xxx xxx)) {...}
sub macro_bmatch {
my ($args, $ctx) = @_;
@ -497,29 +460,6 @@ sub macro_newmacro {
return "";
}
# ~ignore( This is a comment, the only character you can't use is the closing paren. )
sub macro_ignore {
# ignore arguments, return empty string
return "";
}
# qw(word, foobar) -> {"word", "foobar"}
sub macro_qw {
my ($args, $ctx) = @_;
my $str = "{";
if (scalar(@$args)==0) {
return "{}";
}
foreach my $word (@$args) {
$str .= '"'.$word.'", ';
}
$str = substr($str, 0, -2);
$str .= "}";
return $str;
}
sub macro_bytes {
my ($args, $ctx) = @_;
count_args("bytes", $args, $ctx, 1);

View File

@ -36,61 +36,67 @@ extern struct dis_t dis;
extern uint16_t dis_op;
void inst_mc68851_prestore() {
printf("%s: Error, not implemented!\n", __func__);
slog("%s: Error, not implemented!\n", __func__);
assert(!"blowup");
}
void inst_mc68851_psave(){
printf("%s: Error, not implemented!\n", __func__);
slog("%s: Error, not implemented!\n", __func__);
assert(!"blowup");
}
void inst_mc68851_pbcc(){
printf("%s: Error, not implemented!\n", __func__);
slog("%s: Error, not implemented!\n", __func__);
assert(!"blowup");
}
void inst_mc68851_pdbcc(uint16_t cond){
printf("%s: Error, not implemented!\n", __func__);
slog("%s: Error, not implemented!\n", __func__);
assert(!"blowup");
}
void inst_mc68851_ptrapcc(uint16_t cond){
printf("%s: Error, not implemented!\n", __func__);
slog("%s: Error, not implemented!\n", __func__);
assert(!"blowup");
}
void inst_mc68851_pscc(uint16_t cond){
printf("%s: Error, not implemented!\n", __func__);
slog("%s: Error, not implemented!\n", __func__);
assert(!"blowup");
}
void inst_mc68851_pload(uint16_t ext){
printf("%s: Error, not implemented!\n", __func__);
slog("%s: Error, not implemented!\n", __func__);
assert(!"blowup");
}
void inst_mc68851_pvalid(uint16_t ext){
printf("%s: Error, not implemented!\n", __func__);
slog("%s: Error, not implemented!\n", __func__);
assert(!"blowup");
}
void inst_mc68851_pflushr(uint16_t ext){
verify_supervisor();
printf("pflushr!");
slog("pflushr!");
// Just nuke the entire cache
bzero(shoe.pmmu_cache[0].valid_map, 512/8);
bzero(shoe.pmmu_cache[1].valid_map, 512/8);
memset(shoe.pmmu_cache[0].valid_map, 0, PMMU_CACHE_SIZE/8);
memset(shoe.pmmu_cache[1].valid_map, 0, PMMU_CACHE_SIZE/8);
/* Invalidate the pc cache */
invalidate_pccache();
}
void inst_mc68851_pflush(uint16_t ext){
verify_supervisor();
printf("pflush!");
bzero(shoe.pmmu_cache[0].valid_map, 512/8);
bzero(shoe.pmmu_cache[1].valid_map, 512/8);
// printf("%s: Error, not implemented!\n", __func__);
slog("pflush!");
memset(shoe.pmmu_cache[0].valid_map, 0, PMMU_CACHE_SIZE/8);
memset(shoe.pmmu_cache[1].valid_map, 0, PMMU_CACHE_SIZE/8);
// slog("%s: Error, not implemented!\n", __func__);
/* Invalidate the pc cache */
invalidate_pccache();
}
void inst_mc68851_pmove(uint16_t ext){
@ -100,6 +106,12 @@ void inst_mc68851_pmove(uint16_t ext){
~decompose(shoe.op, 1111 000 000 MMMMMM);
~decompose(ext, fff ppp w 0000 nnn 00);
/*
* For simplicity, just blow away pccache whenever
* the PMMU state changes at all
*/
if (!w)
invalidate_pccache();
// instruction format #1
@ -119,7 +131,16 @@ void inst_mc68851_pmove(uint16_t ext){
switch (p) {
case 0: // tc
if (!w) shoe.tc = shoe.dat & 0x83FFFFFF;
if (!w) {
shoe.tc = shoe.dat & 0x83FFFFFF;
shoe.tc_is = (shoe.tc >> 16) & 0xf;
shoe.tc_ps = (shoe.tc >> 20) & 0xf;
shoe.tc_pagesize = 1 << shoe.tc_ps;
shoe.tc_pagemask = shoe.tc_pagesize - 1;
shoe.tc_is_plus_ps = shoe.tc_is + shoe.tc_ps;
shoe.tc_enable = (shoe.tc >> 31) & 1;
shoe.tc_sre = (shoe.tc >> 25) & 1;
}
else {
shoe.dat = shoe.tc;
//if (!tc_fcl()) assert(!"pmove->tc: function codes not supported\n");
@ -193,7 +214,7 @@ static int64_t ptest_search(const uint32_t _logical_addr, const uint64_t rootp)
uint8_t i;
uint64_t desc = rootp; // Initial descriptor is the root pointer descriptor
uint8_t desc_size = 1; // And the root pointer descriptor is always 8 bytes (1==8 bytes, 0==4 bytes)
uint8_t used_bits = tc_is(); // Keep track of how many bits will be the effective "page size"
uint8_t used_bits = shoe.tc_is; // Keep track of how many bits will be the effective "page size"
// (If the table search terminates early (before used_bits == ts_ps()),
// then this will be the effective page size. That is, the number of bits
// we or into the physical addr from the virtual addr)
@ -232,7 +253,7 @@ static int64_t ptest_search(const uint32_t _logical_addr, const uint64_t rootp)
// load the child descriptor
if (_logical_addr == 0)
printf("Loading descriptor s=%llu from addr=0x%08x\n", desc_dt(desc, desc_size) & 1, (uint32_t)desc_table_addr(desc));
slog("Loading descriptor s=%llu from addr=0x%08x\n", desc_dt(desc, desc_size) & 1, (uint32_t)desc_table_addr(desc));
const uint32_t table_base_addr = desc_table_addr(desc);
const uint8_t s = desc_dt(desc, desc_size) & 1;
@ -244,7 +265,7 @@ static int64_t ptest_search(const uint32_t _logical_addr, const uint64_t rootp)
const uint8_t dt = desc_dt(desc, desc_size);
if (_logical_addr == 0)
printf("i=%u desc = 0x%llx dt=%u\n", i, desc, dt);
slog("i=%u desc = 0x%llx dt=%u\n", i, desc, dt);
// If this descriptor is invalid, throw a bus error
if (dt == 0) {
@ -315,7 +336,7 @@ void inst_mc68851_ptest(uint16_t ext){
~decompose(shoe.op, 1111 0000 00 MMMMMM);
~decompose(ext, 100 LLL R AAAA FFFFF); // Erata in 68kPRM - F is 6 bits, and A is 3
assert(tc_enable()); // XXX: Throws some exception if tc_enable isn't set
assert(shoe.tc_enable); // XXX: Throws some exception if tc_enable isn't set
assert(tc_fcl() == 0); // XXX: I can't handle function code lookups, and I don't want to
assert(L == 7); // XXX: Not currently handling searching to a particular level
@ -339,7 +360,7 @@ void inst_mc68851_ptest(uint16_t ext){
else if (fc == 5)
rootp = shoe.srp;
else {
printf("ptest: I can't handle this FC: %u pc=0x%08x\n", fc, shoe.orig_pc);
slog("ptest: I can't handle this FC: %u pc=0x%08x\n", fc, shoe.orig_pc);
assert(!"ptest: I can't handle this FC");
}
@ -353,7 +374,7 @@ void inst_mc68851_ptest(uint16_t ext){
// printf("%s: Error, not implemented!\n", __func__);
// slog("%s: Error, not implemented!\n", __func__);
}
void dis_mc68851_prestore() {

1974
core/mem.c

File diff suppressed because it is too large Load Diff

1539
core/oldfpu.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -26,26 +26,33 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "shoebill.h"
#include "redblack.h"
// Create a new red-black tree
// (just return an empty black leaf pointer)
rb_tree* rb_new()
// Create a new red-black tree
rb_tree* rb_new(alloc_pool_t *parent_pool, uint32_t sz)
{
return calloc(sizeof(rb_tree), 1);
alloc_pool_t *pool = p_new_pool(parent_pool);
rb_tree *tree = (rb_tree*)p_alloc(pool, sizeof(rb_tree));
tree->root = NULL;
tree->pool = pool;
tree->sz = sz;
return tree;
}
// Insert a new key/value into the tree
// Insert a new key/value into the tree
// (and return the old value if *old_value is non-null.)
// Returns true if the key already existed.
uint8_t rb_insert(rb_tree *root, rb_key_t key, rb_value_t value, rb_value_t *old_value)
{
uint8_t rb_insert(rb_tree *tree, rb_key_t key, void *value, void *old_value)
{
const uint32_t alloc_size = sizeof(rb_node) + tree->sz;
rb_node **root = &tree->root;
// Special edge case: insert the root node if tree's empty
if (*root == NULL) {
*root = calloc(sizeof(rb_node), 1);
*root = p_alloc(tree->pool, alloc_size);
(*root)->key = key;
(*root)->value = value;
memcpy(&(*root)[1], value, tree->sz);
return 0;
}
@ -58,19 +65,19 @@ uint8_t rb_insert(rb_tree *root, rb_key_t key, rb_value_t value, rb_value_t *old
else if (key > (*cur)->key) // right
cur = &((*cur)->right);
else { // the key already exists
if (old_value)
*old_value = (*cur)->value;
(*cur)->value = value;
if (old_value)
memcpy(old_value, &(*cur)[1], tree->sz);
memcpy(&(*cur)[1], value, tree->sz);
return 1; // 1 => the key already existed
}
}
// insert
*cur = calloc(sizeof(rb_node), 1);
*cur = p_alloc(tree->pool, alloc_size);
(*cur)->parent = parent;
(*cur)->key = key;
(*cur)->value = value;
(*cur)->is_red = 1;
memcpy(&(*cur)[1], value, tree->sz);
// resolve
@ -113,7 +120,7 @@ uint8_t rb_insert(rb_tree *root, rb_key_t key, rb_value_t value, rb_value_t *old
uint8_t mycase = ((gparent->left==parent)?0:1);
mycase = (mycase << 1) | ((parent->left==red)?0:1);
switch (mycase) {
case 0: {// LLb
rb_node *Br = parent->right;
*gparent_ptr = parent;
@ -125,11 +132,11 @@ uint8_t rb_insert(rb_tree *root, rb_key_t key, rb_value_t value, rb_value_t *old
parent->parent = gparent->parent;
gparent->parent = parent;
if (Br) Br->parent = gparent;
red = gparent->right; // gparent became red, gparent->left is black, check gparent->right
break ;
}
case 1: {// LRb
case 1: {// LRb
rb_node *Cl = red->left;
rb_node *Cr = red->right;
*gparent_ptr = red;
@ -165,7 +172,7 @@ uint8_t rb_insert(rb_tree *root, rb_key_t key, rb_value_t value, rb_value_t *old
parent->parent = red;
if (Cr) Cr->parent = parent;
if (Cl) Cl->parent = gparent;
red = gparent->left;
break;
}
@ -186,24 +193,24 @@ uint8_t rb_insert(rb_tree *root, rb_key_t key, rb_value_t value, rb_value_t *old
}
}
}
(*root)->is_red = 0; // make double-sure root is red
return 0;
}
// Find a value given a key
uint8_t rb_find (rb_tree *tree, rb_key_t key, rb_value_t *value)
uint8_t rb_find (rb_tree *tree, rb_key_t key, void *value)
{
rb_node *cur = *tree;
rb_node *cur = tree->root;
while (cur) {
if (key < cur->key)
if (key < cur->key)
cur = cur->left;
else if (key > cur->key)
cur = cur->right;
else {
if (value)
*value = cur->value;
memcpy(value, &cur[1], tree->sz);
return 1;
}
}
@ -212,56 +219,51 @@ uint8_t rb_find (rb_tree *tree, rb_key_t key, rb_value_t *value)
uint8_t _rb_index (rb_node *cur, uint32_t *index, rb_node **result)
{
if (!cur)
if (!cur)
return 0;
else if (_rb_index(cur->left, index, result) == 1)
else if (_rb_index(cur->left, index, result) == 1)
return 1;
else if (0 == *index) {
*result = cur;
return 1;
}
--*index;
return _rb_index(cur->right, index, result);
}
// Do an in-order traversal, and retrieve the (index)th sorted key/value
uint8_t rb_index (rb_tree *tree, uint32_t index, rb_key_t *key, rb_value_t *value)
uint8_t rb_index (rb_tree *tree, uint32_t index, rb_key_t *key, void *value)
{
rb_node *cur = *tree, *result;
rb_node *cur = tree->root, *result;
if (_rb_index(cur, &index, &result)) {
if (key) *key = result->key;
if (value) *value = result->value;
if (key)
*key = result->key;
if (value)
memcpy(value, &result[1], tree->sz);
return 1;
}
return 0;
}
// Count the number of nodes in the tree
uint32_t rb_count (rb_tree *tree)
static uint32_t _rb_count (rb_node *node)
{
rb_node *node = *tree;
if (!node)
if (!node)
return 0;
return 1 + rb_count(&node->left) + rb_count(&node->right);
return 1 + _rb_count(node->left) + _rb_count(node->right);
}
void _rb_free (rb_node *node)
uint32_t rb_count (rb_tree *tree)
{
if (!node) return ;
_rb_free(node->right);
if (node->right) free(node->right);
_rb_free(node->left);
if (node->left) free(node->left);
return _rb_count(tree->root);
}
// Free all the nodes (and the rb_tree ptr itself)
void rb_free (rb_tree *tree)
{
_rb_free(*tree);
free(*tree);
free(tree);
p_free_pool(tree->pool);
}

View File

@ -102,162 +102,105 @@ const char *scsi_write_reg_str[8] = {
"start_dma_initiator_receive"
};
enum scsi_bus_phase {
BUS_FREE = 0,
ARBITRATION,
SELECTION,
RESELECTION,
COMMAND,
DATA_OUT,
DATA_IN,
STATUS,
MESSAGE_IN,
MESSAGE_OUT
};
static void scsi_raise_irq() {via_raise_interrupt(2, IFR_CB2);}
static void scsi_raise_drq() {via_raise_interrupt(2, IFR_CA2);}
typedef struct {
// Phase
enum scsi_bus_phase phase;
// Scsi bus signals
uint8_t init_bsy:1; // BSY, driven by initiator
uint8_t target_bsy:1; // BSY, driven by target
uint8_t sel:1; // SEL, driven by both target and initiator
uint8_t rst:1; // RST, driven by both target and initiator
uint8_t cd:1; // C/D (control or data), driven by target
uint8_t io:1; // I/O, driven by target
uint8_t ack:1; // ACK, driven by initiator
uint8_t msg:1; // MSG, driven by target
uint8_t atn:1; // ATN, driven by initiator
uint8_t req:1; // REQ, driven by target
uint8_t data; // DB0-7, data lines, driven by both target and initiator
// NCR 5380 registers
uint8_t initiator_command;
uint8_t mode;
uint8_t target_command;
uint8_t select_enable; // probably not implementing this...
// Arbitration state
uint8_t init_id; // initiator ID (as a bit mask) (usually 0x80)
// Selection state
uint8_t target_id; // target ID (as an int [0, 7])
// transfer buffers
uint8_t buf[512 * 64];
uint32_t bufi;
uint32_t in_len, in_i;
uint32_t out_len, out_i;
uint32_t write_offset;
uint8_t status_byte;
uint8_t message_byte; // only one-byte messages supported for now
// hack
uint8_t dma_send_written; // Gets set whenever register 5 (start_dma_send) is written to, and cleared randomly.
// This is because aux 1.1.1 sends an extra byte after sending the write command, and that's not
// part of the write data. start_dma_send will be written when the data is actually starting.
uint8_t sent_status_byte_via_reg0; // Gets set when the status byte is red via register 0.
// This lets us know it's safe to switch to the MESSAGE_IN phase
} scsi_bus_state_t;
scsi_bus_state_t scsi;
static _Bool phase_match (void)
{
uint8_t phase_tmp = shoe.scsi.msg;
phase_tmp = (phase_tmp << 1) | shoe.scsi.cd;
phase_tmp = (phase_tmp << 1) | shoe.scsi.io;
return (phase_tmp == (shoe.scsi.target_command & 7));
}
static void switch_status_phase (uint8_t status_byte)
{
slog("scsi_reg_something: switching to STATUS phase\n");
printf("scsi_reg_something: switching to STATUS phase\n");
shoe.scsi.phase = STATUS;
shoe.scsi.status_byte = status_byte;
shoe.scsi.msg = 0;
shoe.scsi.cd = 1;
shoe.scsi.io = 1;
scsi.phase = STATUS;
scsi.status_byte = status_byte;
scsi.msg = 0;
scsi.cd = 1;
scsi.io = 1;
scsi.bufi = 0;
shoe.scsi.bufi = 0;
// Phase mismatch (I think)
via_raise_interrupt(2, 0);
scsi_raise_drq();
}
static void switch_command_phase (void)
{
printf("scsi_reg_something: switching to COMMAND phase\n");
scsi.phase = COMMAND;
slog("scsi_reg_something: switching to COMMAND phase\n");
shoe.scsi.phase = COMMAND;
scsi.msg = 0;
scsi.cd = 1;
scsi.io = 0;
shoe.scsi.msg = 0;
shoe.scsi.cd = 1;
shoe.scsi.io = 0;
scsi.bufi = 0;
shoe.scsi.bufi = 0;
// Phase mismatch, probably
via_raise_interrupt(2, 0);
scsi_raise_drq();
}
static void switch_message_in_phase (uint8_t message_byte)
{
printf("scsi_reg_something: switching to MESSAGE_IN phase\n");
slog("scsi_reg_something: switching to MESSAGE_IN phase\n");
scsi.phase = MESSAGE_IN;
scsi.msg = 1;
scsi.cd = 1;
scsi.io = 1;
shoe.scsi.phase = MESSAGE_IN;
shoe.scsi.msg = 1;
shoe.scsi.cd = 1;
shoe.scsi.io = 1;
scsi.message_byte = message_byte; // only one-byte messages supported for now
shoe.scsi.message_byte = message_byte; // only one-byte messages supported for now
// Phase mismatch, probably
via_raise_interrupt(2, 0);
scsi_raise_drq();
}
static void switch_bus_free_phase (void)
{
printf("scsi_reg_something: switching to BUS_FREE phase\n");
slog("scsi_reg_something: switching to BUS_FREE phase\n");
scsi.phase = BUS_FREE;
shoe.scsi.phase = BUS_FREE;
scsi.msg = 0;
scsi.cd = 0;
scsi.io = 0;
shoe.scsi.msg = 0;
shoe.scsi.cd = 0;
shoe.scsi.io = 0;
scsi.target_bsy = 0;
scsi.req = 0;
shoe.scsi.target_bsy = 0;
shoe.scsi.req = 0;
scsi.bufi = 0;
shoe.scsi.bufi = 0;
// Phase mismatch not possible here.
}
static void switch_data_in_phase (void)
{
printf("scsi_reg_something: switching to DATA_IN phase\n");
slog("scsi_reg_something: switching to DATA_IN phase\n");
scsi.phase = DATA_IN;
shoe.scsi.phase = DATA_IN;
scsi.msg = 0;
scsi.cd = 0;
scsi.io = 1;
shoe.scsi.msg = 0;
shoe.scsi.cd = 0;
shoe.scsi.io = 1;
// Phase mismatch, probably
via_raise_interrupt(2, 0);
scsi_raise_drq();
}
static void switch_data_out_phase (void)
{
printf("scsi_reg_something: switching to DATA_OUT phase\n");
slog("scsi_reg_something: switching to DATA_OUT phase\n");
scsi.phase = DATA_OUT;
shoe.scsi.phase = DATA_OUT;
scsi.msg = 0;
scsi.cd = 0;
scsi.io = 0;
shoe.scsi.msg = 0;
shoe.scsi.cd = 0;
shoe.scsi.io = 0;
via_raise_interrupt(2, 0);
scsi_raise_drq();
}
struct inquiry_response_t {
@ -334,150 +277,200 @@ static void scsi_handle_inquiry_command(const uint8_t alloc_len)
// XXX: added this because A/UX 3.0.1 requsts 6 bytes of the the inquiry response (sometimes?) I think it's polling for all attached scsi devices.
// Fixme: figure out how to respond "not attached"
if (alloc_len > sizeof(resp))
scsi.in_len = sizeof(resp);
shoe.scsi.in_len = sizeof(resp);
else
scsi.in_len = alloc_len;
memcpy(scsi.buf, &resp, scsi.in_len);
scsi.in_i = 0;
shoe.scsi.in_len = alloc_len;
memcpy(shoe.scsi.buf, &resp, shoe.scsi.in_len);
shoe.scsi.in_i = 0;
switch_data_in_phase();
}
static void scsi_buf_set (uint8_t byte)
{
assert(scsi.bufi <= sizeof(scsi.buf));
scsi.buf[scsi.bufi++] = byte;
assert(shoe.scsi.bufi <= sizeof(shoe.scsi.buf));
shoe.scsi.buf[shoe.scsi.bufi++] = byte;
if (scsi.phase == COMMAND) {
const uint32_t cmd_len = (scsi.buf[0] >= 0x20) ? 10 : 6; // 10 or 6 byte command?
if (shoe.scsi.phase == COMMAND) {
const uint32_t cmd_len = (shoe.scsi.buf[0] >= 0x20) ? 10 : 6; // 10 or 6 byte command?
assert(scsi.target_id < 8);
scsi_device_t *dev = &shoe.scsi_devices[scsi.target_id];
assert(shoe.scsi.target_id < 8);
scsi_device_t *dev = &shoe.scsi_devices[shoe.scsi.target_id];
// If we need more data for this command, keep driving REQ
if (scsi.bufi < cmd_len) {
// scsi.req = 1;
if (shoe.scsi.bufi < cmd_len) {
// shoe.scsi.req = 1;
// FIXME: keep driving DMA_REQUEST too
return ;
}
switch (scsi.buf[0]) {
switch (shoe.scsi.buf[0]) {
case 0: // test unit ready (6)
printf("scsi_buf_set: responding to test-unit-ready\n");
slog("scsi_buf_set: responding to test-unit-ready\n");
switch_status_phase(0); // switch to the status phase, with a status byte of 0
break;
case 0x15: // mode select (6)
printf("scsi_buf_set: responding to mode-select\n");
switch_status_phase(0);
break;
case 0x3: { // request sense (6)
const uint8_t alloc_len = shoe.scsi.buf[4];
const uint8_t control = shoe.scsi.buf[5];
const _Bool desc = shoe.scsi.buf[1] & 1;
case 0x25: // read capacity (10)
printf("scsi_buf_set: responding to read-capacity\n");
// bytes [0,3] -> BE number of blocks
scsi.buf[0] = (dev->num_blocks >> 24) & 0xff;
scsi.buf[1] = (dev->num_blocks >> 16) & 0xff;
scsi.buf[2] = (dev->num_blocks >> 8) & 0xff;
scsi.buf[3] = (dev->num_blocks) & 0xff;
switch_status_phase(2); // CHECK_CONDITION
// bytes [4,7] -> BE block size (needs to be 512)
scsi.buf[4] = (dev->block_size >> 24) & 0xff;
scsi.buf[5] = (dev->block_size >> 16) & 0xff;
scsi.buf[6] = (dev->block_size >> 8) & 0xff;
scsi.buf[7] = (dev->block_size) & 0xff;
scsi.in_i = 0;
scsi.in_len = 8;
switch_data_in_phase();
break;
case 0x12: { // inquiry command (6)
printf("scsi_buf_set: responding to inquiry\n");
const uint8_t alloc_len = scsi.buf[4];
scsi_handle_inquiry_command(alloc_len);
break;
}
case 0x8: { // read (6)
const uint32_t offset =
(scsi.buf[1] << 16) |
(scsi.buf[2] << 8 ) |
(scsi.buf[3]);
const uint8_t len = scsi.buf[4];
(shoe.scsi.buf[1] << 16) |
(shoe.scsi.buf[2] << 8 ) |
(shoe.scsi.buf[3]);
const uint16_t len = (shoe.scsi.buf[4]==0) ? 0x100 : shoe.scsi.buf[4]; // len==0 -> 256 sectors
assert(dev->f);
printf("scsi_buf_set: Responding to read at off=%u len=%u\n", offset, len);
slog("scsi_buf_set: Responding to read at off=%u len=%u\n", offset, len);
assert(len <= 64);
//assert(len <= 64);
assert(dev->num_blocks > offset);
assert(0 == fseeko(dev->f, 512 * offset, SEEK_SET));
assert(fread(scsi.buf, len * 512, 1, dev->f) == 1);
if (len == 0) {
switch_status_phase(0);
break;
}
scsi.in_len = len * 512;
scsi.in_i = 0;
assert(0 == fseeko(dev->f, 512 * offset, SEEK_SET));
assert(fread(shoe.scsi.buf, len * 512, 1, dev->f) == 1);
shoe.scsi.in_len = len * 512;
shoe.scsi.in_i = 0;
switch_data_in_phase();
break;
}
case 0xa: { // write (6)
const uint32_t offset =
(scsi.buf[1] << 16) |
(scsi.buf[2] << 8 ) |
(scsi.buf[3]);
const uint8_t len = scsi.buf[4];
(shoe.scsi.buf[1] << 16) |
(shoe.scsi.buf[2] << 8 ) |
(shoe.scsi.buf[3]);
const uint16_t len = (shoe.scsi.buf[4]==0) ? 0x100 : shoe.scsi.buf[4]; // len==0 -> 256 sectors
printf("scsi_buf_set: Responding to write at off=%u len=%u\n", offset, len);
slog("scsi_buf_set: Responding to write at off=%u len=%u\n", offset, len);
assert(len <= 64);
//assert(len <= 64);
scsi.write_offset = offset;
scsi.out_len = len * 512;
scsi.out_i = 0;
shoe.scsi.write_offset = offset;
shoe.scsi.out_len = len * 512;
shoe.scsi.out_i = 0;
scsi.dma_send_written = 0; // reset here. The real data will come in after start_dma_send is written to.
shoe.scsi.dma_send_written = 0; // reset here. The real data will come in after start_dma_send is written to.
switch_data_out_phase();
break;
}
case 0x12: { // inquiry command (6)
slog("scsi_buf_set: responding to inquiry\n");
const uint8_t alloc_len = shoe.scsi.buf[4];
scsi_handle_inquiry_command(alloc_len);
break;
}
case 0x15: // mode select (6)
slog("scsi_buf_set: responding to mode-select\n");
switch_status_phase(0);
break;
case 0x1a: { // mode sense (6)
const _Bool dbd = (shoe.scsi.buf[1] >> 3) & 1;
const uint8_t pc = (shoe.scsi.buf[2] >> 6) & 3;
const uint8_t page_code = shoe.scsi.buf[2] & 0x3f;
const uint8_t subpage_code = shoe.scsi.buf[3];
const uint8_t alloc_len = shoe.scsi.buf[4];
const uint8_t control = shoe.scsi.buf[6];
slog("scsi_bug_set: responding to mode-sense\n");
slog("dbd=%u pc=%u page_code=%u subpage_code=%u alloc_len=%u control=%u\n",
dbd, pc, page_code, subpage_code, alloc_len, control);
// FIXME: set sense code!
switch_status_phase(2); // CHECK_CONDITION
}
case 0x25: // read capacity (10)
slog("scsi_buf_set: responding to read-capacity\n");
// bytes [0,3] -> BE number of blocks
shoe.scsi.buf[0] = (dev->num_blocks >> 24) & 0xff;
shoe.scsi.buf[1] = (dev->num_blocks >> 16) & 0xff;
shoe.scsi.buf[2] = (dev->num_blocks >> 8) & 0xff;
shoe.scsi.buf[3] = (dev->num_blocks) & 0xff;
// bytes [4,7] -> BE block size (needs to be 512)
shoe.scsi.buf[4] = (dev->block_size >> 24) & 0xff;
shoe.scsi.buf[5] = (dev->block_size >> 16) & 0xff;
shoe.scsi.buf[6] = (dev->block_size >> 8) & 0xff;
shoe.scsi.buf[7] = (dev->block_size) & 0xff;
shoe.scsi.in_i = 0;
shoe.scsi.in_len = 8;
switch_data_in_phase();
break;
case 0x28: { // read (10)
// FIXME: set sense code!
switch_status_phase(2); // CHECK_CONDITION
break;
}
default:
assert(!"unknown commmand!");
printf("unknown scsi command (0x%02x)\n", shoe.scsi.buf[0]);
// FIXME: set sense code
switch_status_phase(2); // CHECK_CONDITION
break;
}
scsi.bufi = 0;
shoe.scsi.bufi = 0;
}
}
void init_scsi_bus_state ()
{
memset(&scsi, 0, sizeof(scsi_bus_state_t));
memset(&shoe.scsi, 0, sizeof(scsi_bus_state_t));
scsi.phase = BUS_FREE;
shoe.scsi.phase = BUS_FREE;
}
void reset_scsi_bus_state ()
{
memset(&shoe.scsi, 0, sizeof(scsi_bus_state_t));
shoe.scsi.phase = BUS_FREE;
}
void scsi_reg_read ()
{
const uint32_t reg = ((shoe.physical_addr & 0xffff) >> 4) & 0xf;
printf("\nscsi_reg_read: reading from register %s(%u) ", scsi_read_reg_str[reg], reg);
//slog("\nscsi_reg_read: reading from register %s(%u) ", scsi_read_reg_str[reg], reg);
switch (reg) {
case 0: // Current scsi data bus register
if (scsi.phase == ARBITRATION)
if (shoe.scsi.phase == ARBITRATION)
shoe.physical_dat = 0; // I don't know why A/UX expects 0 here. It should be the initiator's ID, I think
else if (scsi.phase == MESSAGE_IN) {
shoe.physical_dat = scsi.message_byte; // one-byte messages supported for now
else if (shoe.scsi.phase == MESSAGE_IN) {
shoe.physical_dat = shoe.scsi.message_byte; // one-byte messages supported for now
}
else if (scsi.phase == STATUS) {
shoe.physical_dat = scsi.status_byte;
scsi.sent_status_byte_via_reg0 = 1;
else if (shoe.scsi.phase == STATUS) {
shoe.physical_dat = shoe.scsi.status_byte;
shoe.scsi.sent_status_byte_via_reg0 = 1;
}
else
assert(!"scsi_reg_read: reading data reg (0) from unknown phase\n");
@ -486,38 +479,38 @@ void scsi_reg_read ()
case 1: // Initiator command register
if (scsi.phase == ARBITRATION &&
(scsi.initiator_command & INIT_COMM_ARBITRATION_IN_PROGRESS)) {
if (shoe.scsi.phase == ARBITRATION &&
(shoe.scsi.initiator_command & INIT_COMM_ARBITRATION_IN_PROGRESS)) {
shoe.physical_dat = scsi.initiator_command;
shoe.physical_dat = shoe.scsi.initiator_command;
// the INIT_COMM_ARBITRATION_IN_PROGRESS bit is transient. Just clear
// it after the first access (it needs to go hi, then later low)
scsi.initiator_command &= ~INIT_COMM_ARBITRATION_IN_PROGRESS;
shoe.scsi.initiator_command &= ~INIT_COMM_ARBITRATION_IN_PROGRESS;
}
else
shoe.physical_dat = scsi.initiator_command;
shoe.physical_dat = shoe.scsi.initiator_command;
break;
case 2: // Mode register
shoe.physical_dat = scsi.mode;
shoe.physical_dat = shoe.scsi.mode;
break;
case 3: // Target command register
shoe.physical_dat = scsi.target_command & 0xf; // only the low 4 bits are significant
shoe.physical_dat = shoe.scsi.target_command & 0xf; // only the low 4 bits are significant
break;
case 4: { // Current SCSI control register
uint8_t tmp = 0;
tmp |= (scsi.sel * CURR_SCSI_CONTROL_SEL);
tmp |= (scsi.io * CURR_SCSI_CONTROL_IO);
tmp |= (scsi.cd * CURR_SCSI_CONTROL_CD);
tmp |= (scsi.msg * CURR_SCSI_CONTROL_MSG);
tmp |= (scsi.req * CURR_SCSI_CONTROL_REQ);
tmp |= ((scsi.target_bsy || scsi.init_bsy) ? CURR_SCSI_CONTROL_BSY : 0);
tmp |= (scsi.rst * CURR_SCSI_CONTROL_RST);
tmp |= (shoe.scsi.sel * CURR_SCSI_CONTROL_SEL);
tmp |= (shoe.scsi.io * CURR_SCSI_CONTROL_IO);
tmp |= (shoe.scsi.cd * CURR_SCSI_CONTROL_CD);
tmp |= (shoe.scsi.msg * CURR_SCSI_CONTROL_MSG);
tmp |= (shoe.scsi.req * CURR_SCSI_CONTROL_REQ);
tmp |= ((shoe.scsi.target_bsy || shoe.scsi.init_bsy) ? CURR_SCSI_CONTROL_BSY : 0);
tmp |= (shoe.scsi.rst * CURR_SCSI_CONTROL_RST);
shoe.physical_dat = tmp;
break;
}
@ -526,16 +519,10 @@ void scsi_reg_read ()
uint8_t tmp = 0;
// Compute phase match (IO, CD, MSG match the assertions in target_command register)
uint8_t phase_tmp = 0;
{
phase_tmp = (phase_tmp << 1) | scsi.msg;
phase_tmp = (phase_tmp << 1) | scsi.cd;
phase_tmp = (phase_tmp << 1) | scsi.io;
phase_tmp = (phase_tmp == (scsi.target_command & 7));
}
uint8_t phase_tmp = phase_match();
tmp |= (scsi.ack * BUS_STATUS_ACK);
tmp |= (scsi.atn * BUS_STATUS_ATN);
tmp |= (shoe.scsi.ack * BUS_STATUS_ACK);
tmp |= (shoe.scsi.atn * BUS_STATUS_ATN);
tmp |= (phase_tmp * BUS_STATUS_PHASE_MATCH);
// let's just say BUS_ERROR is always false (fixme: wrong)
@ -555,7 +542,7 @@ void scsi_reg_read ()
break;
}
printf("(set to 0x%02x)\n\n", (uint32_t)shoe.physical_dat);
//slog("(set to 0x%02x)\n\n", (uint32_t)shoe.physical_dat);
}
void scsi_reg_write ()
@ -565,67 +552,73 @@ void scsi_reg_write ()
switch (reg) {
case 0: // Output data register
scsi.data = dat;
shoe.scsi.data = dat;
break;
case 1: { // Initiator command register
scsi.initiator_command = dat;
shoe.scsi.initiator_command = dat;
scsi.ack = ((scsi.initiator_command & INIT_COMM_ASSERT_ACK) != 0);
scsi.rst = ((scsi.initiator_command & INIT_COMM_ASSERT_RST) != 0);
scsi.init_bsy = ((scsi.initiator_command & INIT_COMM_ASSERT_BSY) != 0);
scsi.sel = ((scsi.initiator_command & INIT_COMM_ASSERT_SEL) != 0);
scsi.atn = ((scsi.initiator_command & INIT_COMM_ASSERT_ATN) != 0);
shoe.scsi.ack = ((shoe.scsi.initiator_command & INIT_COMM_ASSERT_ACK) != 0);
shoe.scsi.rst = ((shoe.scsi.initiator_command & INIT_COMM_ASSERT_RST) != 0);
shoe.scsi.init_bsy = ((shoe.scsi.initiator_command & INIT_COMM_ASSERT_BSY) != 0);
shoe.scsi.sel = ((shoe.scsi.initiator_command & INIT_COMM_ASSERT_SEL) != 0);
shoe.scsi.atn = ((shoe.scsi.initiator_command & INIT_COMM_ASSERT_ATN) != 0);
/*
// --- Arbitration ---
// Check whether to switch from ARBITRATION to SELECTION
if (scsi.sel && scsi.phase == ARBITRATION) {
if (shoe.scsi.sel && shoe.scsi.phase == ARBITRATION) {
// Asserting SEL in arbitration phase means we switch to selection phase :)
scsi.phase = SELECTION;
scsi.target_id = INVALID_ID; // invalid ID
printf("scsi_reg_write: selection phase\n");
shoe.scsi.phase = SELECTION;
shoe.scsi.target_id = INVALID_ID; // invalid ID
slog("scsi_reg_write: selection phase\n");
break;
}
*/
// --- Selection ---
// If we're in SELECTION, receive the target_id from scsi.data
if (scsi.sel && (scsi.initiator_command & INIT_COMM_ASSERT_DATA_BUS) &&
((scsi.phase == ARBITRATION) || (scsi.phase == BUS_FREE)))
// If we're in SELECTION, receive the target_id from shoe.scsi.data
if (shoe.scsi.sel && (shoe.scsi.initiator_command & INIT_COMM_ASSERT_DATA_BUS) &&
((shoe.scsi.phase == ARBITRATION) || (shoe.scsi.phase == BUS_FREE)))
{
uint8_t id;
for (id=0; (id < 8) && !(scsi.data & (1 << id)); id++) ;
for (id=0; (id < 8) && !(shoe.scsi.data & (1 << id)); id++) ;
assert(id != 8);
scsi.target_id = id;
printf("scsi_reg_write: selected target id %u\n", id);
scsi.target_bsy = 1; // target asserts BSY to acknowledge being selected
scsi.phase = SELECTION;
shoe.scsi.target_id = id;
slog("scsi_reg_write: selected target id %u\n", id);
if (shoe.scsi_devices[shoe.scsi.target_id].f == NULL) {
shoe.scsi.phase = BUS_FREE;
}
else {
shoe.scsi.target_bsy = 1; // target asserts BSY to acknowledge being selected
shoe.scsi.phase = SELECTION;
}
break;
}
// SELECTION ends when SEL gets unset
if (!scsi.sel && scsi.phase == SELECTION) {
printf("scsi_reg_write: switch to COMMAND phase\n"); // what's next?
if (!shoe.scsi.sel && shoe.scsi.phase == SELECTION) {
slog("scsi_reg_write: switch to COMMAND phase\n"); // what's next?
scsi.req = 1; // target asserts REQ after initiator deasserts SEL
shoe.scsi.req = 1; // target asserts REQ after initiator deasserts SEL
// Switch to COMMAND phase
scsi.cd = 1;
scsi.io = 0;
scsi.msg = 0;
scsi.phase = COMMAND;
shoe.scsi.cd = 1;
shoe.scsi.io = 0;
shoe.scsi.msg = 0;
shoe.scsi.phase = COMMAND;
break;
}
// --- Information transfer ---
// If initiator asserts ACK, then target needs to deassert REQ
// (I think this only makes sense for non-arbitration/selection/busfree situations
if ((scsi.phase != BUS_FREE) && (scsi.phase != ARBITRATION) && (scsi.phase != SELECTION)) {
if ((shoe.scsi.phase != BUS_FREE) && (shoe.scsi.phase != ARBITRATION) && (shoe.scsi.phase != SELECTION)) {
// If this is the message_in phase, use the unsetting-ACK portion of the REQ/ACK handshake
// to go to BUS_FREE.
// Don't bother asserting REQ here. Also, switch_bus_free_phase() will deassert target_BSY.
if (scsi.phase == MESSAGE_IN && !scsi.ack && !scsi.req) {
if (shoe.scsi.phase == MESSAGE_IN && !shoe.scsi.ack && !shoe.scsi.req) {
switch_bus_free_phase();
break ;
}
@ -634,12 +627,12 @@ void scsi_reg_write ()
// Do this when the OS deasserts ACK. We know that ACK was previously asserted if !REQ.
// (This is kinda hacky - maybe I can detect if ACK is deasserted by looking at the
// previous value of reg1)
else if (scsi.phase == STATUS && !scsi.ack && !scsi.req && scsi.sent_status_byte_via_reg0) {
scsi.req = 1;
else if (shoe.scsi.phase == STATUS && !shoe.scsi.ack && !shoe.scsi.req && shoe.scsi.sent_status_byte_via_reg0) {
shoe.scsi.req = 1;
switch_message_in_phase(0);
}
else {
scsi.req = !scsi.ack;
shoe.scsi.req = !shoe.scsi.ack;
}
}
@ -647,12 +640,12 @@ void scsi_reg_write ()
}
case 2: { // Mode register
scsi.mode = dat;
shoe.scsi.mode = dat;
if (scsi.mode & MODE_ARBITRATE) {
printf("scsi_reg_write: arbitration phase\n");
scsi.phase = ARBITRATION;
scsi.initiator_command |= INIT_COMM_ARBITRATION_IN_PROGRESS;
if (shoe.scsi.mode & MODE_ARBITRATE) {
slog("scsi_reg_write: arbitration phase\n");
shoe.scsi.phase = ARBITRATION;
shoe.scsi.initiator_command |= INIT_COMM_ARBITRATION_IN_PROGRESS;
}
else {
@ -661,27 +654,27 @@ void scsi_reg_write ()
break;
}
case 3: // Target command register
scsi.target_command = dat & 0xf; // only the bottom 4 bits are writable
shoe.scsi.target_command = dat & 0xf; // only the bottom 4 bits are writable
break;
case 4: // ID select register
scsi.select_enable = dat;
shoe.scsi.select_enable = dat;
break;
case 5: // Start DMA send
scsi.dma_send_written = 1;
via_raise_interrupt(2, 0);
shoe.scsi.dma_send_written = 1;
scsi_raise_drq();
break;
case 6: // Start DMA target receive
break;
case 7: // Start DMA initiator receive
via_raise_interrupt(2, 0);
scsi_raise_drq();
break;
}
printf("\nscsi_reg_write: writing to register %s(%u) (0x%x)\n\n", scsi_write_reg_str[reg], reg, dat);
slog("\nscsi_reg_write: writing to register %s(%u) (0x%x)\n\n", scsi_write_reg_str[reg], reg, dat);
}
void scsi_dma_write_long(const uint32_t dat)
@ -694,34 +687,34 @@ void scsi_dma_write_long(const uint32_t dat)
void scsi_dma_write (const uint8_t byte)
{
if (scsi.phase == COMMAND) {
printf("scsi_reg_dma_write: writing COMMAND byte 0x%02x\n", byte);
if (shoe.scsi.phase == COMMAND) {
slog("scsi_reg_dma_write: writing COMMAND byte 0x%02x\n", byte);
scsi_buf_set(byte);
}
else if (scsi.phase == DATA_OUT && scsi.dma_send_written) {
scsi.buf[scsi.out_i++] = byte;
else if (shoe.scsi.phase == DATA_OUT && shoe.scsi.dma_send_written) {
shoe.scsi.buf[shoe.scsi.out_i++] = byte;
//printf("scsi_reg_dma_write: writing DATA_OUT byte 0x%02x (%c)\n", byte, isprint(byte)?byte:'.');
//slog("scsi_reg_dma_write: writing DATA_OUT byte 0x%02x (%c)\n", byte, isprint(byte)?byte:'.');
if (scsi.out_i >= scsi.out_len) {
assert(scsi.target_id < 8);
scsi_device_t *dev = &shoe.scsi_devices[scsi.target_id];
if (shoe.scsi.out_i >= shoe.scsi.out_len) {
assert(shoe.scsi.target_id < 8);
scsi_device_t *dev = &shoe.scsi_devices[shoe.scsi.target_id];
assert(dev->f);
assert(0 == fseeko(dev->f, 512 * scsi.write_offset, SEEK_SET));
assert(fwrite(scsi.buf, scsi.out_len, 1, dev->f) == 1);
assert(0 == fseeko(dev->f, 512 * shoe.scsi.write_offset, SEEK_SET));
assert(fwrite(shoe.scsi.buf, shoe.scsi.out_len, 1, dev->f) == 1);
fflush(dev->f);
scsi.out_i = 0;
scsi.out_len = 0;
shoe.scsi.out_i = 0;
shoe.scsi.out_len = 0;
switch_status_phase(0);
}
}
else if (scsi.phase == DATA_OUT) {
printf("scsi_reg_dma_write: writing DATA_OUT byte (without scsi.dma_send_written) 0x%02x\n", byte);
else if (shoe.scsi.phase == DATA_OUT) {
slog("scsi_reg_dma_write: writing DATA_OUT byte (without shoe.scsi.dma_send_written) 0x%02x\n", byte);
}
else {
printf("scsi_reg_dma_write: writing 0x%02x in UNKNOWN PHASE!\n", byte);
slog("scsi_reg_dma_write: writing 0x%02x in UNKNOWN PHASE!\n", byte);
}
}
@ -741,23 +734,23 @@ uint8_t scsi_dma_read ()
{
uint8_t result = 0;
if (scsi.phase == STATUS) {
if (shoe.scsi.phase == STATUS) {
// If in the STATUS phase, return the status byte and switch back to COMMAND phase
result = scsi.status_byte;
result = shoe.scsi.status_byte;
switch_message_in_phase(0);
}
else if (scsi.phase == DATA_IN) {
assert(scsi.in_len > 0);
result = scsi.buf[scsi.in_i++];
if (scsi.in_i >= scsi.in_len) {
scsi.in_i = 0;
scsi.in_len = 0;
else if (shoe.scsi.phase == DATA_IN) {
assert(shoe.scsi.in_len > 0);
result = shoe.scsi.buf[shoe.scsi.in_i++];
if (shoe.scsi.in_i >= shoe.scsi.in_len) {
shoe.scsi.in_i = 0;
shoe.scsi.in_len = 0;
switch_status_phase(0);
}
}
//printf("scsi_reg_dma_read: called, returning 0x%02x\n", (uint8_t)result);
//slog("scsi_reg_dma_read: called, returning 0x%02x\n", (uint8_t)result);
return result;
}

File diff suppressed because it is too large Load Diff

279
core/sound.c Normal file
View File

@ -0,0 +1,279 @@
/*
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Props to MESS for their EASC register map: http://www.mess.org/mess/driver_info/easc
* EASC's PCM mode is backwards compatible with ASC, so their registers are very similar.
*/
#include <assert.h>
#include <string.h>
#include "../core/shoebill.h"
#define r_ptr (0x400 + (asc->right_ptr & 0x3ff)) /* right buf ptr */
#define l_ptr (asc->left_ptr & 0x3ff) /* left buf ptr */
#define m_ptr (asc->left_ptr & 0x7ff) /* mono buf ptr */
void init_asc_state(void)
{
memset(&shoe.asc, 0, sizeof(shoe.asc));
shoe.asc.version = 0x00; // My Mac II's ASC reports 0x00 as its version.
// From the ROM, it looks like other Mac II ASC masks have different version numbers
}
static uint8_t sound_dma_read_byte(uint16_t addr)
{
apple_sound_chip_registers_t *asc = &shoe.asc;
if (addr < 0x800) {
if (asc->asc_mode == 1) {
// PCM mode (FIFO is append-only)
if (asc->channel_ctrl & 2) {
// stereo mode - return the byte referenced by the right pointer
return asc->buf[r_ptr];
}
else {
// mono mode - return the byte referenced by the left pointer
return asc->buf[m_ptr];
}
}
else {
// Off or wavetable mode (FIFO is random access)
return asc->buf[addr];
}
}
switch (addr) {
case 0x800: // Version
return asc->version;
case 0x801: // ASC-mode
return asc->asc_mode;
case 0x802: // Channel control
return asc->channel_ctrl;
case 0x803: // FIFO control
return asc->fifo_ctrl;
case 0x804: // FIFO interrupt
//return asc->fifo_intr;
return 0xff;
case 0x805: // Unknown (??)
return asc->unknown1;
case 0x806: // Volume control
return asc->volume_ctrl;
case 0x807: // Clock control
return asc->clock_ctrl;
}
return 0;
}
static void sound_dma_write_byte(uint16_t addr, uint8_t data)
{
apple_sound_chip_registers_t *asc = &shoe.asc;
if (addr < 0x800) { // buf_a/b
if (asc->asc_mode == 1) {
// PCM mode (FIFO is append-only)
if (asc->channel_ctrl & 2) {
// stereo mode - each channel has its own buffer pointer
if (addr < 0x400) {
// left buffer
asc->buf[l_ptr] = data;
asc->left_ptr++;
}
else {
// right buffer
asc->buf[r_ptr] = data;
asc->right_ptr++;
}
return ;
}
else {
// Mono mode
asc->buf[m_ptr] = data;
asc->left_ptr++;
return ;
}
}
else {
// Off or wavetable mode (FIFO is random access)
asc->buf[addr] = data;
return ;
}
}
else {
switch (addr) {
case 0x800: // Version
// Version is read-only
break;
case 0x801: // ASC-mode
// ASC version 0x00 preserves the low 2 bits
asc->asc_mode = data & 0x03;
assert(asc->asc_mode != 3); // mode-3 produces noise, but isn't deterministic
break;
case 0x802: // Channel control
// ASC version 0x00 preserves the high bit and low 2 bits
asc->channel_ctrl = data & 0x83;
break;
case 0x803: // FIFO control
// ASC version 0x00 preserves the low 2 bits
asc->fifo_ctrl = data & 0x83;
break;
case 0x804: // FIFO interrupt
// FIFO interrupt is read-only
break;
case 0x805: // unknown (???)
// ASC version 0x00 preserves the high bit and low 4 bits
// (But what does it do?)
asc->unknown1 = data & 0x8f;
break;
case 0x806: // Volume control
// ASC version 0x00 preserves the high 6 bits
asc->volume_ctrl = data & 0xfc;
break;
case 0x807: // Clock control
// ASC version 0x00 preserves the low 2 bits
asc->clock_ctrl = data & 0x03;
break;
}
}
}
void sound_dma_write_raw(uint16_t addr, uint8_t sz, uint32_t data)
{
int32_t i;
slog("sound_dma_write: addr=0x%04x sz=%u dat=0x%x\n", addr, sz, data);
for (i = (sz-1) * 8; i >= 0; i -= 8)
sound_dma_write_byte(addr, (data >> i) & 0xff);
}
uint32_t sound_dma_read_raw(uint16_t addr, uint8_t sz)
{
uint32_t i, result = 0;
slog("sound_dma_read: addr=0x%04x sz=%u\n", addr, sz);
for (i=0; i<sz; i++) {
result <<= 8;
result |= sound_dma_read_byte(addr + i);
}
return result;
}
/*
ASC notes:
buf_a (0x000-0x3ff) -> left
buf_b (0x400-0x7ff) -> right
writing to any address in buf_a or buf_b appends to the end pointer in the ring buffer (ignoring the address)
reading from any address returns... the currently-being-read byte? Or the about-to-be-overwritten byte?
(def one or the other)
- Update: MODE=0: You can do regular random read/write access to buf_a/b when MODE=0.
MODE=1: Writing anywhere within the buffer automatically appends to the end of the ring buffer
For stereo mode, writing between 0-0x3ff appends to buf_a, 0x400-0x7ff to buf_b
Reading anywhere in the buffer is strange - it seems non-deterministic.
Update 2: no wait, it's returning the byte at buf_b's ring pointer, does it always do that?
Update 3: yes, it looks like reading anywhere returns the byte at buf_b's pointer in stereo mode,
and buf_a's pointer in mono mode
MODE=2: Same as MODE=0 (?)
- ASC maintains two distinct ring buffer pointers for stereo mode
0x800 - Version (?) MacII only ever seems to TST.B it
(READ ONLY)
$00 -> My Mac II's ASC's version
$?? -> Mac II's ROM is aware of other non-$00 ASC masks
$b0 -> EASC
0x801 - Mode (?) 0 == no output, 1 == PCM, 2 == wavetable, 3 == hissing static(??)
- Preserves low 2 bits, ignores high 6 bits
0x802 - Channel selector
Preserves mask 0x83 (high bit, low 2 bits)
- High bit is set if engine overflow (according to MESS)
- Low bits, 0x?2 -> stereo output (buf_a -> left, buf_b -> right)
0x?0 -> Mono output (from buf_a)
- Switching to stereo from mono produces a blip of sound in the right ear, unless the fifo has been cleared (buf_b), (or unless there was nothing in buf_b to start with)
0x803 - Fifo control (cycle 0x80 to reset the internal FIFO pointer (pointers?))
Preserves mask 0x83 (high bit, low 2 bits)
0x804 - Fifo interrupt status
(READ ONLY, doesnt preserve any written bits (doesnt acknowledge writes at all?))
0x805 - ???
- Preserves bits at 0x8F, (high bit, low 4 bits), doesn't seem to do anything
0x806 - Volume control (high 3 bits)
Preserves top 6 bits, ignores bottom 2 bits. (Only top 3 bits control volume)
0x807 - Clock rate select (0, 2, or 3, I think)
0x00 -> 11127hz
0x01 -> Illegal???
0x02 -> 11025hz
0x03 -> 22050hz
Writes to fifo_a/b(?) seem to block for clock rates 0, 2, and 3, but not 1. The speaker clicks like the sound chip is turning off when you set clock to 0x01.
ASC has more registers past 0x807 for wave table control
*/

View File

@ -26,7 +26,6 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <GLUT/glut.h>
#include "shoebill.h"
#define ROM_SIZE 4096
@ -41,45 +40,11 @@ uint8_t macii_video_rom[ROM_SIZE] = {
*/
};
typedef struct {
uint8_t *buf_base;
uint32_t buf_size;
uint32_t clut_idx;
uint32_t h_offset; // offset in bytes for each horizontal line
uint8_t clut[256 * 3];
uint8_t depth;
uint8_t vsync;
uint8_t *gldat;
} tfb_ctx_t;
void nubus_tfb_display_func (void)
static void nubus_tfb_clut_translate(shoebill_card_tfb_t *ctx)
{
uint32_t myw = glutGet(GLUT_WINDOW_WIDTH);
uint32_t myh = glutGet(GLUT_WINDOW_HEIGHT);
uint32_t slotnum, i;
int32_t my_window_id = glutGetWindow();
for (slotnum = 0; slotnum < 16; slotnum++)
if (shoe.slots[slotnum].glut_window_id == my_window_id)
break;
tfb_ctx_t *ctx = (tfb_ctx_t*)shoe.slots[slotnum].ctx;
uint32_t i, gli = 0;
const uint8_t depth = ctx->depth;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, myw, 0, myh, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.1, 0.1, 0.8);
uint32_t gli = 0;
for (i=0; i < (1024 * 480);) {
uint8_t code;
@ -91,87 +56,60 @@ void nubus_tfb_display_func (void)
assert(gli < (640 * 480));
if (depth <= 1) {
code = (ctx->buf_base[ctx->h_offset + i/8] & (0x80 >> (i % 8))) != 0;
code = (ctx->direct_buf[ctx->line_offset + i/8] & (0x80 >> (i % 8))) != 0;
code = (code << 7) | 0x7f;
}
else if (depth == 2) {
const uint8_t byte = ctx->buf_base[ctx->h_offset + i/4];
const uint8_t byte = ctx->direct_buf[ctx->line_offset + i/4];
const uint8_t mod = i % 4;
code = (byte << (mod * 2)) & 0xc0;
code |= 0x3f;
}
else if (depth == 4) {
const uint8_t byte = ctx->buf_base[ctx->h_offset + i/2];
const uint8_t byte = ctx->direct_buf[ctx->line_offset + i/2];
const uint8_t mod = i % 2;
code = (byte << (mod * 4)) & 0xf0;
code |= 0x0f;
}
else if (depth == 8) {
code = ctx->buf_base[ctx->h_offset + i];
code = ctx->direct_buf[ctx->line_offset + i];
}
ctx->gldat[gli * 3 + 0] = ctx->clut[code * 3 + 2];
ctx->gldat[gli * 3 + 1] = ctx->clut[code * 3 + 1];
ctx->gldat[gli * 3 + 2] = ctx->clut[code * 3 + 0];
ctx->temp_buf[gli * 4 + 0] = ctx->clut[code * 3 + 2];
ctx->temp_buf[gli * 4 + 1] = ctx->clut[code * 3 + 1];
ctx->temp_buf[gli * 4 + 2] = ctx->clut[code * 3 + 0];
gli++;
i++;
}
glViewport(0, 0, myw, myh);
glRasterPos2i(0, myh);
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelZoom(1.0, -1.0);
glDrawPixels(myw, myh, GL_RGB, GL_UNSIGNED_BYTE, ctx->gldat);
glFlush();
}
void global_mouse_func (int button, int state, int x, int y);
void global_motion_func (int x, int y);
void global_passive_motion_func (int x, int y);
void global_keyboard_up_func (unsigned char c, int x, int y);
void global_keyboard_down_func (unsigned char c, int x, int y);
void global_special_up_func (int special, int x, int y);
void global_special_down_func (int special, int x, int y);
void nubus_tfb_init(uint8_t slotnum)
void nubus_tfb_init(void *_ctx, uint8_t slotnum)
{
tfb_ctx_t *ctx = (tfb_ctx_t*)calloc(sizeof(tfb_ctx_t), 1);
shoebill_card_tfb_t *ctx = (shoebill_card_tfb_t*)_ctx;
ctx->direct_buf = p_alloc(shoe.pool, 512 * 1024 + 4);
ctx->temp_buf = p_alloc(shoe.pool, 640 * 480 * 4);
ctx->rom = p_alloc(shoe.pool, 4096);
ctx->clut = p_alloc(shoe.pool, 256 * 3);
ctx->buf_size = 512 * 1024;
ctx->buf_base = (uint8_t*)calloc(ctx->buf_size, 1);
ctx->depth = 1;
ctx->clut_idx = 786;
ctx->gldat = valloc(480 * 640 * 3);
ctx->line_offset = 0;
memset(ctx->clut, 0x0, 384);
memset(ctx->clut+384, 0xff, 384);
memset(ctx->buf_base, 0xff, ctx->buf_size);
// memcpy(ctx->rom, macii_video_rom, 4096);
// Offset to the TFB sResource
ctx->rom[4096 - 20] = 0;
ctx->rom[4096 - 19] = 0xff;
ctx->rom[4096 - 18] = 0xf0;
ctx->rom[4096 - 17] = 0x14;
// Init CLUT to 1-bit depth
ctx->depth = 1;
memset(ctx->clut, 0x0, 3*128);
memset(ctx->clut + (3*128), 0xff, 3*128);
shoe.slots[slotnum].ctx = ctx;
glutInitWindowSize(640, 480);
shoe.slots[slotnum].glut_window_id = glutCreateWindow("");
glutDisplayFunc(nubus_tfb_display_func);
glutIgnoreKeyRepeat(1);
glutKeyboardFunc(global_keyboard_down_func);
glutKeyboardUpFunc(global_keyboard_up_func);
glutSpecialFunc(global_special_down_func);
glutSpecialUpFunc(global_special_up_func);
glutMouseFunc(global_mouse_func);
glutMotionFunc(global_motion_func);
glutPassiveMotionFunc(global_passive_motion_func);
glShadeModel(GL_FLAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glClearColor(0.1, 1.0, 0.1, 1.0);
}
uint32_t nubus_tfb_read_func(const uint32_t rawaddr, const uint32_t size, const uint8_t slotnum)
@ -190,7 +128,8 @@ uint32_t nubus_tfb_read_func(const uint32_t rawaddr, const uint32_t size, const
// 1101
// 1110
// 1111 = ROM (repeating 4kb images in S bits)
tfb_ctx_t *ctx = (tfb_ctx_t*)shoe.slots[slotnum].ctx;
//tfb_ctx_t *ctx = (tfb_ctx_t*)shoe.slots[slotnum].ctx;
shoebill_card_tfb_t *ctx = (shoebill_card_tfb_t*)shoe.slots[slotnum].ctx;
const uint32_t addr = rawaddr & 0x000fffff;
uint32_t result = 0;
@ -199,15 +138,15 @@ uint32_t nubus_tfb_read_func(const uint32_t rawaddr, const uint32_t size, const
case 0x0 ... 0x7: { // frame buffer
uint32_t i;
for (i=0; i<size; i++)
result = (result << 8) | ctx->buf_base[addr + i];
result = (result << 8) | ctx->direct_buf[addr + i];
break;
}
case 0xf: { // rom
if ((addr & 3) == 0) {
const uint32_t rom_addr = (addr >> 2) % 4096;
result = macii_video_rom[rom_addr];
printf("nubus_tfb_read_func: returning %x for addr %x (rom_addr=%x)\n", (uint32_t)result, shoe.physical_addr, rom_addr);
result = ctx->rom[rom_addr];
slog("nubus_tfb_read_func: returning %x for addr %x (rom_addr=%x)\n", (uint32_t)result, rawaddr, rom_addr);
}
else
result = 0;
@ -220,21 +159,21 @@ uint32_t nubus_tfb_read_func(const uint32_t rawaddr, const uint32_t size, const
if (addr == 0xd0000) {
ctx->vsync++;
result = (ctx->vsync >> 7)&1;
printf("nubus_tfb_read_func: reading vsync bit shoe.pc=0x%08x\n", shoe.orig_pc);
slog("nubus_tfb_read_func: reading vsync bit shoe.pc=0x%08x\n", shoe.orig_pc);
// We just need to oscillate the vsync bit, to pretend we're going in and out of the blanking interval.
// The card driver waits until the bit goes low, then waits until it goes high
// FIXME: clean this up
break;
}
else {
printf("nubus_tfb_read_func: unknown read of *0x%08x\n", shoe.physical_addr);
slog("nubus_tfb_read_func: unknown read of *0x%08x\n", rawaddr);
result = 0;
break;
}
}
default: {
printf("nubus_tfb_read_func: unknown read of *0x%08x\n", shoe.physical_addr);
slog("nubus_tfb_read_func: unknown read of *0x%08x\n", rawaddr);
result = 0;
break;
}
@ -246,7 +185,7 @@ uint32_t nubus_tfb_read_func(const uint32_t rawaddr, const uint32_t size, const
void nubus_tfb_write_func(const uint32_t rawaddr, const uint32_t size,
const uint32_t data, const uint8_t slotnum)
{
tfb_ctx_t *ctx = (tfb_ctx_t*)shoe.slots[slotnum].ctx;
shoebill_card_tfb_t *ctx = (shoebill_card_tfb_t*)shoe.slots[slotnum].ctx;
const uint32_t addr = rawaddr & 0x000fffff;
switch (addr >> 16) {
@ -254,7 +193,7 @@ void nubus_tfb_write_func(const uint32_t rawaddr, const uint32_t size,
case 0x0 ... 0x7: { // frame buffer
uint32_t i;
for (i=0; i<size; i++) {
ctx->buf_base[addr + size - (i+1)] = (data >> (8*i)) & 0xFF;
ctx->direct_buf[addr + size - (i+1)] = (data >> (8*i)) & 0xFF;
}
return ;
}
@ -277,19 +216,20 @@ void nubus_tfb_write_func(const uint32_t rawaddr, const uint32_t size,
}
if (addr == 0x8000c) { // horizontal offset
ctx->h_offset = 4 * ((~data) & 0xff);
ctx->line_offset = 4 * ((~data) & 0xff);
return ;
}
else {
printf("video_nubus_set: unknown write to *0x%08x (0x%x)\n", shoe.physical_addr, data);
slog("video_nubus_set: unknown write to *0x%08x (0x%x)\n", rawaddr, data);
return ;
}
}
case 0x9: { // CLUT registers?
if (addr == 0x90018) { // CLUT
printf("clut[0x%03x (0x%02x+%u)] = 0x%02x\n", ctx->clut_idx, ctx->clut_idx/3, ctx->clut_idx%3, (uint8_t)(data & 0xff));
ctx->clut[ctx->clut_idx] = 255 - (data & 0xff);
uint8_t *clut = (uint8_t*)ctx->clut;
slog("clut[0x%03x (0x%02x+%u)] = 0x%02x\n", ctx->clut_idx, ctx->clut_idx/3, ctx->clut_idx%3, (uint8_t)(data & 0xff));
clut[ctx->clut_idx] = 255 - (data & 0xff);
ctx->clut_idx = (ctx->clut_idx == 0) ? 767 : ctx->clut_idx-1;
@ -302,20 +242,41 @@ void nubus_tfb_write_func(const uint32_t rawaddr, const uint32_t size,
ctx->clut_idx = clut_dat * 3 + 2;
}
printf("video_nubus_set: unknown write to *0x%08x (0x%x)\n", shoe.physical_addr, data);
slog("video_nubus_set: unknown write to *0x%08x (0x%x)\n", rawaddr, data);
return ;
}
case 0xa: { // clear interrupt for slot 0xa(?) in via2.rega (by setting the appropriate bit)
assert((data & 0xff) == 0);
// shoe.via[1].rega |= 0b00000010;
shoe.via[1].rega |= (1 << (slotnum - 9));
shoe.via[1].rega_input |= (1 << (slotnum - 9));
return ;
}
default: {
printf("video_nubus_set: unknown write to *0x%08x (0x%x)\n", shoe.physical_addr, data);
slog("video_nubus_set: unknown write to *0x%08x (0x%x)\n", rawaddr, data);
return ;
}
}
}
shoebill_video_frame_info_t nubus_tfb_get_frame(shoebill_card_tfb_t *ctx,
_Bool just_params)
{
shoebill_video_frame_info_t result;
result.width = 640;
result.height = 480;
result.scan_width = 640;
result.depth = ctx->depth;
// If caller just wants video parameters...
if (just_params)
return result;
nubus_tfb_clut_translate(ctx);
result.buf = ctx->temp_buf;
return result;
}

View File

@ -29,11 +29,14 @@
#include <pthread.h>
#include <math.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
#include "../core/shoebill.h"
char *via_reg_str[16] = {
"orb",
"ora",
"regb",
"rega",
"ddrb",
"ddra",
"t1c-l",
@ -66,8 +69,11 @@ void via_raise_interrupt(uint8_t vianum, uint8_t ifr_bit)
// Only if the bit is enabled in IER do we raise a cpu interrupt
if (via->ier & (1 << ifr_bit))
set_pending_interrupt(vianum);
else
printf("didn't set pending interrupt\n");
// if the CPU was stopped, wake it up
if (shoe.cpu_thread_notifications & SHOEBILL_STATE_STOPPED) {
unstop_cpu_thread();
}
}
@ -96,30 +102,28 @@ void process_pending_interrupt ()
return ;
}
// If the CPU was stopped, unstop it
shoe.cpu_thread_notifications &= ~~SHOEBILL_STATE_STOPPED;
printf("Interrupt pri %u! mask=%u\n", priority, sr_mask());
const uint16_t vector_offset = (priority + 24) * 4;
slog("Interrupt pri %u! mask=%u vector_offset=0x%08x\n", priority, sr_mask(), vector_offset);
// Save the old SR, and switch to supervisor mode
const uint16_t old_sr = shoe.sr;
set_sr_s(1);
// Write a "format 0" exception frame to ISP or MSP
push_a7(0x0000 | vector_offset, 2);
printf("interrupt: pushed format 0x%04x to 0x%08x\n", 0x0000 | vector_offset, shoe.a[7]);
slog("interrupt: pushed format 0x%04x to 0x%08x\n", 0x0000 | vector_offset, shoe.a[7]);
assert(!shoe.abort);
push_a7(shoe.pc, 4);
printf("interrupt: pushed pc 0x%08x to 0x%08x\n", shoe.pc, shoe.a[7]);
slog("interrupt: pushed pc 0x%08x to 0x%08x\n", shoe.pc, shoe.a[7]);
assert(!shoe.abort);
push_a7(old_sr, 2);
printf("interrupt: pushed sr 0x%04x to 0x%08x\n", old_sr, shoe.a[7]);
slog("interrupt: pushed sr 0x%04x to 0x%08x\n", old_sr, shoe.a[7]);
assert(!shoe.abort);
if (sr_m()) {
// clear sr_m, and write a format 1 exception to the ISP
@ -137,8 +141,18 @@ void process_pending_interrupt ()
assert(!shoe.abort);
}
/*
* "When processing an interrupt exception, the MC68020/EC020 first makes an internal copy of the SR,
* sets the privilege level to supervisor, suppresses tracing, and sets the processor interrupt mask
* level to the level of the interrupt being serviced."
*/
set_sr_mask(priority);
set_sr_t0(0);
set_sr_t1(0);
// Fetch the autovector handler address
const uint32_t newpc = lget(shoe.vbr + vector_offset, 4);
slog("autovector handler = *0x%08x = 0x%08x\n", shoe.vbr + vector_offset, newpc);
assert(!shoe.abort);
shoe.pc = newpc;
@ -147,33 +161,6 @@ void process_pending_interrupt ()
shoe.cpu_thread_notifications &= ~~(1 << priority);
}
/*
Reset:
Host sends command, switch to state 0
Device sends byte 1
Host switches to state 2
Device sends byte 2
Host switches to state 3
Talk:
Host sends command, switch to state 0
Device sends byte 0 (even)
Hosts switches to state 1 (even = "just got even byte")
Device sends byte 1 (odd)
Host switches to state 2 (odd = "just got odd byte")
Device sends byte 2 (even)
*/
// via1 ORB bits abcd efgh
// cd -> adb FSM state
// e -> adb timeout occurred / service request (?)
// f/g/h nvram stuff
#define VIA_REGB_DONE 8
// VIA registers
#define VIA_ORB 0
@ -193,78 +180,465 @@ void process_pending_interrupt ()
#define VIA_IER 14
#define VIA_ORA_AUX 15
uint16_t counter;
// Interrupt flag register bits
#define VIA_IFR_CA2 (1<<0)
#define VIA_IFR_CA1 (1<<1)
#define VIA_IFR_SHIFT_REG (1<<2)
#define VIA_IFR_CB2 (1<<3)
#define VIA_IFR_CB1 (1<<4)
#define VIA_IFR_T2 (1<<5)
#define VIA_IFR_T1 (1<<6)
#define VIA_IFR_IRQ (1<<7)
void via_reg_read ()
static long double _now (void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
const long double secs = tv.tv_sec;
const long double usecs = tv.tv_usec;
const long double result = secs + (usecs / 1000000.0);
return result;
}
static void handle_pram_write_byte (void)
{
pram_state_t *pram = &shoe.pram;
slog("PRAMPRAM: wrote_byte 0x%02x\n", pram->byte);
pram->mode = PRAM_READ;
pram->byte = 0;
}
static void handle_pram_read_byte (void)
{
pram_state_t *pram = &shoe.pram;
assert(pram->command_i < 8);
pram->command[pram->command_i++] = pram->byte;
slog("PRAMPRAM: read_byte: 0x%02x\n", pram->byte);
// If this is a pram-read/write...
if ((pram->command[0] & 0x78) == 0x38) {
const _Bool isget = pram->command[0] >> 7;
const uint8_t addr = (pram->command[0] << 5) | ((pram->command[1] >> 2) & 0x1f);
if ((pram->command_i == 3) && !isget) { // complete set command
pram->mode = PRAM_READ; // stay in read-mode
pram->data[addr] = pram->command[2];
if (pram->callback)
pram->callback(pram->callback_param, addr, pram->command[2]);
slog("PRAMPRAM: setting pram addr 0x%02x = 0x%02x\n", addr, pram->command[2]);
pram->byte = 0;
pram->command_i = 0;
return ;
}
else if ((pram->command_i == 2) && isget) { // complete get command
pram->mode = PRAM_WRITE; // switch to write-mode
pram->byte = pram->data[addr];
pram->command_i = 0;
slog("PRAMPRAM: fetching pram addr 0x%02x (= 0x%02x)\n", addr, pram->byte);
return ;
}
else { // incomplete command, keep reading
assert(pram->command_i < 4);
pram->mode = PRAM_READ; // keep reading
return ;
}
}
// if this is clock-read/write
else if (~bmatch(pram->command[0], x 00x xx 01)) {
const _Bool isget = pram->command[0] >> 7;
const uint8_t addr = (pram->command[0] >> 2) & 3;
const _Bool mysterybit = (pram->command[0] >> 4) & 1; // FIXME: What does this do?
if ((pram->command_i == 2) && !isget) { // complete set command
pram->mode = PRAM_READ; // stay in read-mode
slog("PRAMPRAM: setting time byte %u to 0x%02x (mysterybit=%u)\n", addr, pram->command[1], mysterybit);
pram->byte = 0;
pram->command_i = 0;
return ;
}
else if ((pram->command_i == 1) && isget) { // complete get command
const uint32_t now = time(NULL) + 0x7c25b080;
//uint32_t now = 0xafd56d80; // Tue, 24 Jun 1997 12:26:40 GMT
const uint8_t now_byte = now >> (8*addr);
pram->mode = PRAM_WRITE;
pram->byte = now_byte;
pram->command_i = 0;
slog("PRAMPRAM: fetching time byte %u of 0x%08x (mysterybit=%u)\n", addr, now, mysterybit);
return ;
}
else { // incomplete command, keep reading
assert(pram->command_i < 3);
pram->mode = PRAM_READ;
return ;
}
}
// This is mystery command # 2
else if (pram->command[0] == 0x35) {
// Arrives in pairs of two bytes
if (pram->command_i == 2) {
slog("PRAMPRAM: mystery command 2 0x%02x 0x%02x (?))\n", pram->command[0], pram->command[1]);
pram->mode = PRAM_READ;
pram->command_i = 0;
return ;
}
else { // keep reading
assert(pram->command_i < 3);
pram->mode = PRAM_READ;
return ;
}
}
slog("PRAMPRAM: don't understand this command\n");
pram->command_i = 0;
pram->mode = PRAM_READ;
}
static void handle_pram_state_change (void)
{
pram_state_t *pram = &shoe.pram;
// If rtcClock or rtcEnable changed, then the state machine needs updating
if (pram->last_bits == (shoe.via[0].regb_output & shoe.via[0].ddrb & 6))
return ;
slog("PRAMPRAM: pram->last_bits = %u, (shoe.via[0].regb & 6) = %u\n", pram->last_bits, (shoe.via[0].regb_output & shoe.via[0].ddrb & 6));
// it doesn't matter what the last rtcData value was
const _Bool last_rtcClock = (pram->last_bits >> 1) & 1;
const _Bool last_rtcEnable = (pram->last_bits >> 2) & 1;
const _Bool rtcData = shoe.via[0].regb_output & 1;
const _Bool rtcClock = (shoe.via[0].regb_output >> 1) & 1;
const _Bool rtcEnable = (shoe.via[0].regb_output >> 2) & 1;
slog("PRAMPRAM: bits changed %u%ux -> %u%u%u\n", last_rtcEnable, last_rtcClock, rtcEnable, rtcClock, rtcData);
if (rtcEnable) {
// rtcEnable==true => the RTC chip is enabled and we are talking to it
// Not sure what happens when you toggle data/clock bits while rtcEnable is asserted...
if (last_rtcEnable)
slog("PRAMPRAM: toggled bits while rtcEnable was asserted!\n");
goto done;
}
if (!rtcEnable && last_rtcEnable) {
// if rtcEnable went from hi to low, then reset all the state stuff
pram->mode = PRAM_READ;
pram->command_i = 0; // the current command byte we're working on
pram->bit_i = 0; // the current bit num we're reading/writing
pram->byte = 0; // the current byte we're reading/writing
memset(pram->command, 0, 8);
goto done;
}
switch (pram->mode) {
case PRAM_READ: {
// if rtcClock goes from low to hi, then rtcData represents a new bit
if (rtcClock && !last_rtcClock) {
pram->byte <<= 1;
pram->byte |= rtcData;
pram->bit_i++;
}
if ((shoe.via[0].ddrb & 1) == 0) {
// This is input-mode -- should be output-mode
slog("PRAMPRAM: BOGUS MODE ddrb&1 == 0\n");
}
if (pram->bit_i >= 8) {
pram->bit_i = 0;
handle_pram_read_byte();
}
goto done;
}
case PRAM_WRITE: {
// if rtcClock goes from hi to low, load in the new rtcData bit
if (!rtcClock && last_rtcClock) {
const uint8_t newData = (pram->byte >> (7 - pram->bit_i)) & 1;
shoe.via[0].regb_input &= 0xfe;
shoe.via[0].regb_input |= newData;
}
// if B goes from low to hi, skip to the next bit
if (rtcClock && !last_rtcClock)
pram->bit_i++;
assert((shoe.via[0].ddrb & 1) == 0);
if (pram->bit_i >= 8) {
pram->bit_i = 0;
handle_pram_write_byte();
}
goto done;
}
default:
assert(!"can't get here");
}
done:
// Remember the last state of the bits
pram->last_bits = (shoe.via[0].regb_output & shoe.via[0].ddrb & 6);
}
void reset_via_state (void)
{
uint8_t pram_data[256];
shoebill_pram_callback_t callback = shoe.pram.callback;
void *callback_param = shoe.pram.callback_param;
memcpy(pram_data, shoe.pram.data, 256);
init_via_state(pram_data, callback, callback_param);
}
void init_via_state (uint8_t pram_data[256], shoebill_pram_callback_t callback, void *callback_param)
{
/* -- Zero everything -- */
memset(&shoe.pram, 0, sizeof(pram_state_t));
memset(&shoe.via, 0, 2 * sizeof(via_state_t));
// Jeez, keep this straight!
// DDR 0 -> input (from pins to OS)
// 1 -> output (from OS to pins)
/* -- Initialize VIA1 -- */
/* VIA 1 reg A
* Bit 7 - input - vSCCWrReq
* Bit 6 - input - CPU.ID1
* Bit 5 - output - vHeadSel
* Bit 4 - output - vOverlay
* Bit 3 - output - vSync
* Bit 2-0 unused
*/
shoe.via[0].ddra = ~b(00111000);
/* VIA 1 reg B
* Bit 7 - output - vSndEnb
* Bit 6 - unused
* Bit 5 - output - vFDesk2
* Bit 4 - output - vFDesk1
* Bit 3 - input - vFDBInt
* Bit 2 - output - rTCEnb
* Bit 1 - output - rtcClk
* Bit 0 - in/out - rtcData (initialize to output)
*/
shoe.via[0].ddrb = ~b(10110111); // A/UX apparently neglects to initialize ddra/b
/* -- Initialize VIA2 -- */
/* VIA 2 reg A
* Bit 7 - unused
* Bit 6 - unused
* Bit 5 - Interrupt for slot 15
* ...
* Bit 0 - Interrupt for slot 9
*/
shoe.via[1].ddra = 0x00; // via2/rega consists of input pins for nubus interrupts
shoe.via[1].rega_input = ~b(00111111); // no nubus interrupts currently asserted
/* VIA 2 reg B
* Bit 7 - output - v2VBL
* Bit 6 - input - v2SNDEXT
* Bit 5 - input - v2TM0A (nubus transfer what??)
* Bit 4 - input - v2TM1A
* Bit 3 - output - AMU/PMMU control
* Bit 2 - output - v2PowerOff (but leave this in input mode)
* Bit 1 - output - v2BusLk
* Bit 0 - output - v2cdis
*/
shoe.via[1].ddrb = 0x00;
shoe.via[1].ddrb = ~b(10001011);
// FIXME: apparently via2/regb bit 7 is tied to VIA1, and driven by timer T1, to
// generate 60.15hz (really 60.0hz) interrupts on VIA1
// emulate this more accurately!
// The power unit is wired to bit 2, waiting for it to be set 0.
// I guess we're supposed to leave it as an input, because the shutdown
// routine first sets the bit to 0, *then* switches the direction to output.
// FIXME: verify that this is correct
/* -- Initialize PRAM -- */
pram_state_t *pram = &shoe.pram;
pram->mode = PRAM_READ;
memcpy(pram->data, pram_data, 256);
pram->callback = callback;
pram->callback_param = callback_param;
/* -- Init clock stuff -- */
const long double now = _now();
shoe.via[0].t1_last_set = now;
shoe.via[0].t2_last_set = now;
shoe.via[1].t1_last_set = now;
shoe.via[1].t2_last_set = now;
}
#define E_CLOCK 783360
#define V2POWEROFF_MASK 0x04
#define _via_get_delta_counter(last_set) ({ \
const long double delta_t = now - (last_set); \
const long double delta_ticks = fmodl((delta_t * (long double)E_CLOCK), 0x80000000); \
/* The VIA timers decrement by 2 for every E_CLOCK tick */ \
const uint32_t delta_counter = ((uint32_t)delta_ticks) << 1; \
delta_counter; \
})
// from the pins' perspective
#define VIA_REGA_PINS(n) ((shoe.via[(n)-1].rega_output & shoe.via[(n)-1].ddra) | \
(shoe.via[(n)-1].rega_input & (~~shoe.via[(n)-1].ddra)))
#define VIA_REGB_PINS(n) ((shoe.via[(n)-1].regb_output & shoe.via[(n)-1].ddrb) | \
(shoe.via[(n)-1].regb_input & (~~shoe.via[(n)-1].ddrb)))
static void _via_poweroff(void)
{
slog("Poweroff!\n");
// exit(0);
}
static uint8_t via_read_reg(const uint8_t vianum, const uint8_t reg, const long double now)
{
const uint8_t vianum = (shoe.physical_addr >= 0x50002000) ? 2 : 1;
const uint8_t reg = (shoe.physical_addr >> 9) & 15;
via_state_t *via = &shoe.via[vianum - 1];
printf("via_reg_read: reading from via%u reg %s (%u)\n", vianum, via_reg_str[reg], reg);
slog("via_reg_read: reading from via%u reg %s (%u) (shoe.pc = 0x%08x)\n", vianum, via_reg_str[reg], reg, shoe.pc);
switch (reg) {
case VIA_ACR:
return via->acr;
case VIA_PCR:
return via->pcr;
case VIA_IER:
// According to the eratta, bit 7 is always set during a read
shoe.physical_dat = via->ier | 0x80;
break ;
return via->ier | 0x80;
case VIA_IFR: {
// Figure out whether any enabled interrupts are set, and set IRQ accordingly
const uint8_t irq = (via->ifr & via->ier & 0x7f) ? 0x80 : 0x0;
shoe.physical_dat = (via->ifr & 0x7f) | irq;
break ;
return (via->ifr & 0x7f) | irq;
}
case VIA_SR:
shoe.physical_dat = via->sr;
break;
case VIA_ORB:
shoe.physical_dat = via->regb;
break;
return via->sr;
case VIA_ORB: {
/*
* FIXME: this is not exactly correct.
* if input latching is enabled, then the value of input pins
* is held in escrow until a CB1 transition occurs. I'm not doing that.
*/
slog("via_reg_read: FYI: regb_output=0x%02x regb_input=0x%02x ddrb=0x%02x combined=0x%02x\n",
shoe.via[vianum-1].regb_output, shoe.via[vianum-1].regb_input, via->ddrb, VIA_REGB_PINS(vianum));
return VIA_REGB_PINS(vianum);
}
case VIA_ORA_AUX:
case VIA_ORA:
//if ((vianum==2) && !(via->ifr & (1<<IFR_CA1)))
//via->rega = 0x3f;
shoe.physical_dat = via->rega;
break;
case VIA_ORA: {
/*
* FIXME: This is not exactly correct either, and it behaves differently from regb
* Reading regA never returns the contents of the output register directly,
* it returns the the value of the pins - unless input latching is enabled,
* then it holds the pin values in escrow until a CA1 transition occurs.
* I'm just returning the value of the "pins"
*/
return VIA_REGA_PINS(vianum);
}
case VIA_DDRB:
shoe.physical_dat = via->ddrb;
break;
return via->ddrb;
case VIA_DDRA:
shoe.physical_dat = via->ddra;
break;
return via->ddra;
case VIA_T2C_HI: {
uint16_t counter = via->t2c - (uint16_t)_via_get_delta_counter(via->t2_last_set);
case VIA_T2C_LO:
// XXX: A/UX 3.0.1 tries to precisely time a huge dbra loop
// using via timer2. It won't accept any result shorter than
// 0x492, and hypothetically, this emulator could execute the
// loop faster than that (although not currently). So this is
// a super dumb hack that always returns a delta-t of 0x492
// between sequential reads from t2c.
// (oh, also, a/ux 3.0.1 cleverly reads from both t2c_lo and _hi
// simultaneously by doing a word-size read at VIA+0x11ff)
counter -= 0x492;
shoe.physical_dat = 0xffff & ((counter >> 8) | (counter << 8));
break;
/*
* This is a hack to allow A/UX 3.x.x to boot on fast hosts.
* The A/UX 3 kernel calls a function, SetUpTimeK, during boot
* to run a giant drba-to-self loop and time it via T2C.
* If the loop completes too quickly, (quicker than 0x492 E_CLOCK
* ticks on 3.0.0), it rejects it and tries again.
*
* SetUpTimeK reads T2C twice and compares them to determine the
* time elapsed. I don't want to count on getting the order correct,
* however. Therefore, we will fake it out by randomly adding 0x500
* to the the value of the clock whenever it's read by SetUpTimeK.
* By the Monte Carlo method, we'll eventually get a case where
* two sequential reads differ by at least 0x500.
*
* FIXME: optimize this better, stop using coff_find_func()
*/
if (sr_s()) {
coff_symbol *symb = coff_find_func(shoe.coff, shoe.pc);
if (symb && strcmp(symb->name, "SetUpTimeK") == 0) {
if (random() & 1)
counter += 0x500;
}
}
default:
printf("via_reg_read: (unhandled!)\n");
break;
return counter >> 8;
}
case VIA_T2C_LO: {
const uint16_t counter = via->t2c - (uint16_t)_via_get_delta_counter(via->t2_last_set);
via->ifr &= ~~VIA_IFR_T2; // Read from T2C_LOW clears TIMER 2 interrupt
return (uint8_t)counter;
}
case VIA_T1C_LO:
via->ifr &= ~~VIA_IFR_T1; // Read from T1C_LOW clears TIMER 1 interrupt
return 0; // FIXME
case VIA_T1C_HI:
return 0; // FIXME
case VIA_T1L_LO:
return 0; // FIXME
case VIA_T1L_HI:
return 0; // FIXME
}
assert(!"never get here");
}
void via_reg_write()
static void via_write_reg(const uint8_t vianum, const uint8_t reg, const uint8_t data, const long double now)
{
const uint8_t vianum = (shoe.physical_addr >= 0x50002000) ? 2 : 1;
const uint8_t reg = (shoe.physical_addr >> 9) & 15;
const uint8_t data = (uint8_t)shoe.physical_dat;
via_state_t *via = &shoe.via[vianum - 1];
printf("via_reg_write: writing 0x%02x to via%u reg %s (%u)\n", (uint8_t)shoe.physical_dat, vianum, via_reg_str[reg], reg);
slog("via_reg_write: writing 0x%02x to via%u reg %s (%u) (pc=0x%08x)\n", data, vianum, via_reg_str[reg], reg, shoe.pc);
switch (reg) {
case VIA_IER: {
@ -291,104 +665,175 @@ void via_reg_write()
break;
case VIA_ORB: {
via->regb = data;
via->regb_output = data;
if (vianum == 1) {
const uint8_t adb_state = (data >> 4) & 3;
const uint8_t adb_state = (data >> 4) & 3; // just assume that the corresponding ddrb bits are marked "output"
if (shoe.adb.state != adb_state) {
const uint8_t old_state = shoe.adb.state;
shoe.adb.state = adb_state;
adb_handle_state_change(old_state, adb_state);
}
handle_pram_state_change();
}
if ((vianum == 2) &&
(via->ddrb & V2POWEROFF_MASK) &&
!(via->regb_output & V2POWEROFF_MASK))
_via_poweroff();
break;
}
case VIA_ORA_AUX:
case VIA_ORA:
via->rega = data;
break;
case VIA_ORA: {
via->rega_output = data;
case VIA_DDRB:
via->ddrb = data;
break;
}
case VIA_DDRB: {
via->ddrb = data;
if ((vianum == 2) &&
(via->ddrb & V2POWEROFF_MASK) &&
!(via->regb_output & V2POWEROFF_MASK))
_via_poweroff();
break;
}
case VIA_DDRA:
via->ddra = data;
break;
default:
printf("via_reg_read: (unhandled!)\n");
case VIA_ACR:
via->acr = data;
break;
case VIA_PCR:
via->pcr = data;
break;
case VIA_T2C_LO:
break;
case VIA_T2C_HI:
via->ifr &= ~~VIA_IFR_T2; // Write to T2C_HI clears TIMER 2 interrupt
via->t2_last_set = now;
via->t2_interrupt_enabled = 1;
break;
case VIA_T1C_LO:
break;
case VIA_T1C_HI:
via->ifr &= ~~VIA_IFR_T1; // Write to T1C_HI clears TIMER 1 interrupt
break;
case VIA_T1L_LO:
break;
case VIA_T1L_HI:
break;
}
}
// FIXME: check_time() is bad and needs rewritten
void check_time()
void via_write_raw (void)
{
struct timeval now, delta_tv;
const uint32_t hz = 10;
const uint8_t vianum = ((shoe.physical_addr >> 13) & 1) + 1;
const uint8_t reg = (shoe.physical_addr >> 9) & 15;
// return ;
pthread_mutex_lock(&shoe.via_cpu_lock);
gettimeofday(&now, NULL);
delta_tv.tv_sec = now.tv_sec - shoe.start_time.tv_sec;
if (now.tv_usec < shoe.start_time.tv_usec) {
delta_tv.tv_sec--;
delta_tv.tv_usec = (now.tv_usec + 1000000) - shoe.start_time.tv_usec;
if (shoe.physical_size == 1) {
const long double now = ((reg >= VIA_T1C_LO) && (reg <= VIA_T2C_HI)) ? _now() : 0.0;
// Common case: writing to only one register
via_write_reg(vianum, reg, (uint8_t)shoe.physical_dat, now);
}
else if ((shoe.physical_size == 2) && ((shoe.physical_addr & 0x1ff) == 0x1ff)) {
const long double now = ((reg >= VIA_T1C_LO) && ((reg+1) <= VIA_T2C_HI)) ? _now() : 0.0;
// Uncommon case: writing to two registers simultaneously
slog("via_write_raw: writing to two registers simultaneously %u and %u (0x%x)\n", reg, reg+1 , (uint32_t)shoe.physical_dat);
assert(reg != 15); // If A/UX is trying to write to two VIA chips simultanously, that's not cool
via_write_reg(vianum, reg, (uint8_t)(shoe.physical_dat >> 8), now);
via_write_reg(vianum, reg+1, (uint8_t)shoe.physical_dat, now);
}
else
delta_tv.tv_usec = now.tv_usec - shoe.start_time.tv_usec;
uint64_t delta = delta_tv.tv_sec * 1000;
delta += delta_tv.tv_usec / 1000;
uint64_t ticks = delta / hz;
if (ticks <= shoe.total_ticks)
return ;
shoe.total_ticks = ticks;
//printf("ticks = %llu\n", ticks);
via_raise_interrupt(1, IFR_CA1);
//
shoe.via[1].rega = 0b00111101;
via_raise_interrupt(2, IFR_CA1);
assert(!"Writing multiple bytes to the same VIA register!");
pthread_mutex_unlock(&shoe.via_cpu_lock);
}
static long double _now (void)
void via_read_raw (void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
const uint8_t vianum = ((shoe.physical_addr >> 13) & 1) + 1;
const uint8_t reg = (shoe.physical_addr >> 9) & 15;
long double secs = tv.tv_sec;
long double usecs = tv.tv_usec;
pthread_mutex_lock(&shoe.via_cpu_lock);
return secs + (usecs / 1000000.0);
if (shoe.physical_size == 1) {
const long double now = ((reg >= VIA_T1C_LO) && (reg <= VIA_T2C_HI)) ? _now() : 0.0;
// Common case: reading only one register
shoe.physical_dat = via_read_reg(vianum, reg, now);
}
else if ((shoe.physical_size == 2) && ((shoe.physical_addr & 0x1ff) == 0x1ff)) {
const long double now = ((reg >= VIA_T1C_LO) && ((reg+1) <= VIA_T2C_HI)) ? _now() : 0.0;
// Uncommon case: reading from two registers simultaneously
slog("via_read_raw: reading from two registers simultaneously %u and %u\n", reg, reg+1);
assert(reg != 15); // If A/UX is trying to read from two VIA chips simultaneously, that's not cool
uint16_t result = via_read_reg(vianum, reg, now);
result = (result << 8) | via_read_reg(vianum, reg+1, now);
shoe.physical_dat = result;
}
else
assert(!"Reading multiple bytes from the same VIA register!");
pthread_mutex_unlock(&shoe.via_cpu_lock);
}
#define fire(s) ({assert((s) >= 0); if (earliest_next_timer > (s)) earliest_next_timer = (s);})
void *via_clock_thread(void *arg)
{
pthread_mutex_lock(&shoe.via_clock_thread_lock);
const long double start_time = _now();
// const long double multiplier = 1.0 / 60.0;
const long double multiplier = 1.0;
const long double start_time = multiplier * _now();
uint64_t ca1_ticks = 0, ca2_ticks = 0;
uint32_t i;
while (1) {
const long double now = _now();
pthread_mutex_lock(&shoe.via_cpu_lock);
const long double now = multiplier * _now();
long double earliest_next_timer = 1.0;
const uint32_t via1_t2_delta = _via_get_delta_counter(shoe.via[0].t2_last_set);
// Check whether the 60.15hz timer should fire (via1 CA1)
const uint64_t expected_ca1_ticks = ((now - start_time) * 60.15L);
/*
* Check whether the 60hz timer should fire (via1 CA1)
*
* Note! Inside Macintosh claims this should be 60.15hz,
* but every version of A/UX configures the timer to be
* exactly 60.0hz
*/
const uint64_t expected_ca1_ticks = ((now - start_time) * 60.0L);
if (expected_ca1_ticks > ca1_ticks) {
// Figure out when the timer should fire next
const long double next_firing = (1.0L/60.15L) - fmodl(now - start_time, 1.0L/60.15L);
const long double next_firing = (1.0L/60.0L) - fmodl(now - start_time, 1.0L/60.0L);
fire(next_firing);
ca1_ticks = expected_ca1_ticks;
@ -413,28 +858,25 @@ void *via_clock_thread(void *arg)
via_raise_interrupt(2, IFR_TIMER2);*/
}
// Check if any nubus cards have interrupt timers
for (i=9; i<15; i++) {
if (!shoe.slots[i].connected)
continue;
if (now >= (shoe.slots[i].last_fired + (1.0L/shoe.slots[i].interrupt_rate))) {
shoe.slots[i].last_fired = now;
fire(1.0L/shoe.slots[i].interrupt_rate);
if (shoe.slots[i].interrupts_enabled) {
shoe.via[1].rega = 0b00111111 & ~~(1<<(i-9));
via_raise_interrupt(2, IFR_CA1);
printf("Fired nubus interrupt %u\n", i);
}
// I'm only checking VIA1 T2, since the time manager only seems to use/care about that timer
if (shoe.via[0].t2_interrupt_enabled) {
if (via1_t2_delta >= shoe.via[0].t2c) {
shoe.via[0].t2_interrupt_enabled = 0;
via_raise_interrupt(1, IFR_TIMER2);
}
else {
fire((long double)(shoe.via[0].t2c - via1_t2_delta) / (E_CLOCK / 2.0));
}
}
pthread_mutex_unlock(&shoe.via_cpu_lock);
usleep((useconds_t)(earliest_next_timer * 1000000.0L));
if (shoe.via_thread_notifications & SHOEBILL_STATE_RETURN) {
pthread_mutex_unlock(&shoe.via_clock_thread_lock);
return NULL;
}
}
}

View File

@ -26,9 +26,7 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <GLUT/glut.h>
#include "shoebill.h"
#include "core_api.h"
#include "video_rom/rom.c"
@ -56,86 +54,7 @@ typedef struct __attribute__ ((__packed__)) {
uint32_t plane_bytes;
} video_params_t;
/*void nubus_video_display_func (void)
{
uint32_t myw = glutGet(GLUT_WINDOW_WIDTH);
uint32_t myh = glutGet(GLUT_WINDOW_HEIGHT);
uint32_t slotnum, i;
int32_t my_window_id = glutGetWindow();
for (slotnum = 0; slotnum < 16; slotnum++)
if (shoe.slots[slotnum].glut_window_id == my_window_id)
break;
video_ctx_t *ctx = (video_ctx_t*)shoe.slots[slotnum].ctx;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, myw, 0, myh, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.1, 0.1, 0.8);
uint32_t gli = 0;
switch (ctx->depth) {
case 1: {
for (i=0; i < ctx->pixels/8; i++) {
const uint8_t byte = ctx->indexed_buf[i];
ctx->direct_buf[i * 8 + 0] = ctx->clut[(byte >> 7) & 1];
ctx->direct_buf[i * 8 + 1] = ctx->clut[(byte >> 6) & 1];
ctx->direct_buf[i * 8 + 2] = ctx->clut[(byte >> 5) & 1];
ctx->direct_buf[i * 8 + 3] = ctx->clut[(byte >> 4) & 1];
ctx->direct_buf[i * 8 + 4] = ctx->clut[(byte >> 3) & 1];
ctx->direct_buf[i * 8 + 5] = ctx->clut[(byte >> 2) & 1];
ctx->direct_buf[i * 8 + 6] = ctx->clut[(byte >> 1) & 1];
ctx->direct_buf[i * 8 + 7] = ctx->clut[(byte >> 0) & 1];
}
break;
}
case 2: {
for (i=0; i < ctx->pixels/4; i++) {
const uint8_t byte = ctx->indexed_buf[i];
ctx->direct_buf[i * 4 + 0] = ctx->clut[(byte >> 6) & 3];
ctx->direct_buf[i * 4 + 1] = ctx->clut[(byte >> 4) & 3];
ctx->direct_buf[i * 4 + 2] = ctx->clut[(byte >> 2) & 3];
ctx->direct_buf[i * 4 + 3] = ctx->clut[(byte >> 0) & 3];
}
break;
}
case 4: {
for (i=0; i < ctx->pixels/2; i++) {
const uint8_t byte = ctx->indexed_buf[i];
ctx->direct_buf[i * 2 + 0] = ctx->clut[(byte >> 4) & 0xf];
ctx->direct_buf[i * 2 + 1] = ctx->clut[(byte >> 0) & 0xf];
}
break;
}
case 8:
for (i=0; i < ctx->pixels; i++)
ctx->direct_buf[i] = ctx->clut[ctx->indexed_buf[i]];
break;
default:
assert(!"unknown depth");
}
glViewport(0, 0, myw, myh);
glRasterPos2i(0, myh);
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelZoom(1.0, -1.0);
glDrawPixels(myw, myh, GL_RGBA, GL_UNSIGNED_BYTE, ctx->direct_buf);
glFlush();
}*/
uint32_t compute_nubus_crc(uint8_t *rom, uint32_t len)
static uint32_t compute_nubus_crc(uint8_t *rom, uint32_t len)
{
uint32_t i, sum = 0;
@ -156,24 +75,30 @@ uint32_t compute_nubus_crc(uint8_t *rom, uint32_t len)
return sum;
}
static void _switch_depth(shoebill_card_video_t *ctx, uint32_t depth)
{
ctx->depth = depth;
}
void nubus_video_init(void *_ctx, uint8_t slotnum,
uint16_t width, uint16_t height, uint16_t scanline_width,
double refresh_rate)
uint16_t width, uint16_t height, uint16_t scanline_width)
{
shoebill_card_video_t *ctx = (shoebill_card_video_t*)_ctx;
ctx->width = width;
ctx->height = height;
ctx->scanline_width = scanline_width;
ctx->pixels = scanline_width * height;
ctx->line_offset = 0;
ctx->direct_buf = valloc(ctx->pixels * sizeof(video_ctx_color_t));
ctx->indexed_buf = valloc(ctx->pixels);
ctx->clut = malloc(256 * sizeof(video_ctx_color_t));
ctx->rom = malloc(4096);
ctx->direct_buf = p_alloc(shoe.pool, (ctx->pixels+4) * sizeof(video_ctx_color_t));
ctx->temp_buf = p_alloc(shoe.pool, (ctx->pixels+4) * sizeof(video_ctx_color_t));
ctx->clut = p_alloc(shoe.pool, 256 * sizeof(video_ctx_color_t));
ctx->rom = p_alloc(shoe.pool, 4096);
// Set the depth and clut for B&W
ctx->depth = 1;
bzero(ctx->clut, 256 * 4);
_switch_depth(ctx, 1);
memset(ctx->clut, 0, 256 * 4);
ctx->clut[0].r = 0xff;
ctx->clut[0].g = 0xff;
ctx->clut[0].b = 0xff;
@ -199,6 +124,14 @@ void nubus_video_init(void *_ctx, uint8_t slotnum,
params[3].right = htons(width);
params[3].bottom = htons(height);
params[4].line_width = htons(scanline_width * 2);
params[4].right = htons(width);
params[4].bottom = htons(height);
params[5].line_width = htons(scanline_width * 4);
params[5].right = htons(width);
params[5].bottom = htons(height);
// Recompute the rom crc
compute_nubus_crc(ctx->rom, 4096);
@ -212,9 +145,9 @@ uint32_t nubus_video_read_func(const uint32_t rawaddr, const uint32_t size,
const uint32_t addr = rawaddr & 0x00ffffff;
// ROM and control registers
if ((addr >> 20) == 0xf) {
if sunlikely((addr >> 20) == 0xf) {
printf("nubus_video_read_func: got a read to 0x%08x sz=%u\n", rawaddr, size);
slog("nubus_video_read_func: got a read to 0x%08x sz=%u\n", rawaddr, size);
// ROM (0xFsFFxxxx)
if ((addr >> 16) == 0xff) {
@ -238,27 +171,72 @@ uint32_t nubus_video_read_func(const uint32_t rawaddr, const uint32_t size,
// Else, this is video ram
uint32_t i, myaddr = addr % ctx->pixels, result = 0;
for (i=0; i<size; i++) {
result <<= 8;
result |= ctx->indexed_buf[(myaddr + i) % ctx->pixels];
uint32_t i, result = 0;
if slikely(addr < (ctx->pixels * 4)) {
for (i=0; i<size; i++)
result = (result << 8) | ((uint8_t*)ctx->direct_buf)[addr + i];
}
return result;
}
void _gray_page(shoebill_card_video_t *ctx)
{
uint32_t h, w, i;
if (ctx->depth <= 8) {
uint16_t pat;
uint8_t *ptr = ctx->direct_buf;
uint32_t width_bytes = (ctx->depth * ctx->scanline_width) / 8;
switch (ctx->depth) {
case 1:
pat = 0xaaaa;
break;
case 2:
pat = 0xcccc;
break;
case 4:
pat = 0xf0f0;
break;
case 8:
pat = 0x00ff;
break;
}
for (h=0; h<ctx->height; h++) {
for (w=0; w < width_bytes; w++)
ptr[w] = pat >> ((w&1)*8);
ptr += width_bytes;
pat ^= 0xffff;
}
}
else if (ctx->depth == 16) {
const uint16_t fill_word = htons(0x4210);
uint16_t *ptr = (uint16_t*)ctx->direct_buf;
for (i=0; i < (ctx->width * ctx->height); i++)
ptr[i] = fill_word;
}
else if (ctx->depth == 32) {
const uint32_t fill_long = htonl(0x00808080);
uint32_t *ptr = (uint32_t*)ctx->direct_buf;
for (i=0; i < (ctx->width * ctx->height); i++)
ptr[i] = fill_long;
}
else
assert(!"unknown depth");
}
void nubus_video_write_func(const uint32_t rawaddr, const uint32_t size,
const uint32_t data, const uint8_t slotnum)
{
shoebill_card_video_t *ctx = (shoebill_card_video_t*)shoe.slots[slotnum].ctx;
const uint32_t addr = rawaddr & 0x00ffffff;
uint32_t i;
// ROM and control registers
if ((addr >> 20) == 0xf) {
if sunlikely((addr >> 20) == 0xf) {
printf("nubus_video_write_func: got a write to 0x%08x sz=%u data=0x%x\n", rawaddr, size, data);
slog("nubus_video_write_func: got a write to 0x%08x sz=%u data=0x%x\n", rawaddr, size, data);
// ROM (0xFsFFxxxx)
if ((addr >> 16) == 0xff)
@ -270,41 +248,90 @@ void nubus_video_write_func(const uint32_t rawaddr, const uint32_t size,
if ((addr >> 16) == 0xf0) {
switch ((addr & 0x0000ffff) >> 2) {
case 0: {// Clear interrupt flag
shoe.via[1].rega |= (1 << (slotnum - 9));
shoe.via[1].rega_input |= (1 << (slotnum - 9));
break;
}
case 1: { // Set depth
const uint32_t depth = 1 << (data - 128); // FIXME: this won't work for direct mode
ctx->depth = depth;
printf("nubus_magic: set depth = %u\n", ctx->depth);
uint32_t newdepth;
switch (data) {
case 128:
newdepth = 1;
break;
case 129:
newdepth = 2;
break;
case 130:
newdepth = 4;
break;
case 131:
newdepth = 8;
break;
case 132:
newdepth = 16;
break;
case 133:
newdepth = 32;
break;
default:
assert(!"driver tried to set bogus depth");
}
_switch_depth(ctx, newdepth);
slog("nubus_magic: set depth = %u\n", ctx->depth);
break;
}
case 2: { // Gray out screen
// FIXME: implement me
printf("nubus_magic: grey screen\n");
case 2: { // Gray out screen buffer
_gray_page(ctx);
slog("nubus_magic: grey screen\n");
break;
}
case 3: { // Set clut index
ctx->clut_idx = data & 0xff;
// assert(ctx->clut_idx < 256);
printf("nubus_magic: set clut_idx = %u\n", ctx->clut_idx);
slog("nubus_magic: set clut_idx = %u\n", ctx->clut_idx);
break;
}
case 4: { // Set red component of clut
ctx->clut[ctx->clut_idx].r = (data >> 8) & 0xff;
printf("nubus_magic: set %u.red = 0x%04x\n", ctx->clut_idx, data);
slog("nubus_magic: set %u.red = 0x%04x\n", ctx->clut_idx, data);
break;
}
case 5: { // Set green component of clut
ctx->clut[ctx->clut_idx].g = (data >> 8) & 0xff;
printf("nubus_magic: set %u.green = 0x%04x\n", ctx->clut_idx, data);
slog("nubus_magic: set %u.green = 0x%04x\n", ctx->clut_idx, data);
break;
}
case 6: { // Set blue component of clut
ctx->clut[ctx->clut_idx].b = (data >> 8) & 0xff;
printf("nubus_magic: set %u.blue = 0x%04x\n", ctx->clut_idx, data);
slog("nubus_magic: set %u.blue = 0x%04x\n", ctx->clut_idx, data);
break;
}
case 7: { // Set interrupts
shoe.slots[slotnum].interrupts_enabled = (data != 0);
slog("nubus_magic: interrupts_enabled = %u\n",
shoe.slots[slotnum].interrupts_enabled);
break;
}
case 8: { // Debug
slog("video_debug: 0x%08x\n", data);
break;
}
case 9: { // Gray out CLUT
if (!data) break;
for (i=0; i<256; i++) {
ctx->clut[i].r = 0x80;
ctx->clut[i].g = 0x80;
ctx->clut[i].b = 0x80;
}
break;
}
case 10: { // Use luminance (a.k.a. setGray)
slog("nubus_magic: use_luminance = %u\n", data);
// FIXME: not implemented
break;
}
}
}
@ -312,20 +339,113 @@ void nubus_video_write_func(const uint32_t rawaddr, const uint32_t size,
}
// Else, this is video ram
// uint32_t i, myaddr = addr % ctx->indexed_buf_len, mydata = data;
uint32_t myaddr, mydata;
for (myaddr = addr + size, mydata = data; addr < myaddr; ) {
// assert(myaddr < ctx->pixels)
ctx->indexed_buf[(--myaddr) % ctx->pixels] = mydata & 0xff;
mydata >>= 8;
if slikely(addr < (ctx->pixels * 4)) {
uint32_t mydata, myaddr;
for (myaddr = addr + size, mydata = data; addr < myaddr; ) {
((uint8_t*)ctx->direct_buf)[--myaddr] = mydata & 0xff;
mydata >>= 8;
}
}
}
static void _do_clut_translation(shoebill_card_video_t *ctx)
{
uint32_t i;
switch (ctx->depth) {
case 1: {
for (i=0; i < ctx->pixels/8; i++) {
const uint8_t byte = ctx->direct_buf[i];
ctx->temp_buf[i * 8 + 0] = ctx->clut[(byte >> 7) & 1];
ctx->temp_buf[i * 8 + 1] = ctx->clut[(byte >> 6) & 1];
ctx->temp_buf[i * 8 + 2] = ctx->clut[(byte >> 5) & 1];
ctx->temp_buf[i * 8 + 3] = ctx->clut[(byte >> 4) & 1];
ctx->temp_buf[i * 8 + 4] = ctx->clut[(byte >> 3) & 1];
ctx->temp_buf[i * 8 + 5] = ctx->clut[(byte >> 2) & 1];
ctx->temp_buf[i * 8 + 6] = ctx->clut[(byte >> 1) & 1];
ctx->temp_buf[i * 8 + 7] = ctx->clut[(byte >> 0) & 1];
}
break;
}
case 2: {
for (i=0; i < ctx->pixels/4; i++) {
const uint8_t byte = ctx->direct_buf[i];
ctx->temp_buf[i * 4 + 0] = ctx->clut[(byte >> 6) & 3];
ctx->temp_buf[i * 4 + 1] = ctx->clut[(byte >> 4) & 3];
ctx->temp_buf[i * 4 + 2] = ctx->clut[(byte >> 2) & 3];
ctx->temp_buf[i * 4 + 3] = ctx->clut[(byte >> 0) & 3];
}
break;
}
case 4: {
for (i=0; i < ctx->pixels/2; i++) {
const uint8_t byte = ctx->direct_buf[i];
ctx->temp_buf[i * 2 + 0] = ctx->clut[(byte >> 4) & 0xf];
ctx->temp_buf[i * 2 + 1] = ctx->clut[(byte >> 0) & 0xf];
}
break;
}
case 8: {
for (i=0; i < ctx->pixels; i++)
ctx->temp_buf[i] = ctx->clut[ctx->direct_buf[i]];
break;
}
case 16: {
uint16_t *direct = (uint16_t*)ctx->direct_buf;
for (i=0; i < ctx->pixels; i++) {
const uint16_t p = ntohs(direct[i]);
video_ctx_color_t tmp;
tmp.r = ((p >> 10) & 31);
tmp.g = (p >> 5) & 31;
tmp.b = (p >> 0) & 31;
ctx->temp_buf[i].r = (tmp.r << 3) | (tmp.r >> 2);
ctx->temp_buf[i].g = (tmp.g << 3) | (tmp.g >> 2);
ctx->temp_buf[i].b = (tmp.b << 3) | (tmp.b >> 2);
}
break;
}
case 32: {
uint32_t *direct = (uint32_t*)ctx->direct_buf, *tmp = (uint32_t*)ctx->temp_buf;
for (i=0; i < ctx->pixels; i++)
tmp[i] = direct[i] >> 8;
// OpenGL wants RGBA
// Apple must be ARGB (which is BGRA, when dereferenced)
break;
}
default:
assert(!"unsupported depth");
}
}
shoebill_video_frame_info_t nubus_video_get_frame(shoebill_card_video_t *ctx,
_Bool just_params)
{
shoebill_video_frame_info_t result;
result.width = ctx->width;
result.height = ctx->height;
result.scan_width = ctx->scanline_width;
result.depth = ctx->depth;
// If caller just wants video parameters...
if (just_params)
return result;
_do_clut_translation(ctx);
result.buf = (uint8_t*)ctx->temp_buf;
return result;
}

Binary file not shown.

View File

@ -22,92 +22,156 @@ uint8_t _video_rom[4096] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x80, 0x00,
0x00, 0x04, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08,
0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x0c, 0x80, 0x00, 0x00, 0x7e,
0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x18,
0x02, 0x00, 0x00, 0x1c, 0x20, 0x00, 0x00, 0x50,
0x22, 0x00, 0x00, 0x2c, 0x24, 0x00, 0x00, 0x3e,
0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x53, 0x68, 0x6f, 0x65,
0x62, 0x69, 0x6c, 0x6c, 0x20, 0x50, 0x68, 0x6f,
0x6e, 0x79, 0x20, 0x56, 0x69, 0x64, 0x65, 0x6f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00,
0x0b, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x84,
0x05, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x04,
0x80, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x03,
0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x16, 0x80,
0x00, 0x00, 0x00, 0x00, 0x03, 0x84, 0x05, 0xa0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x80, 0x00, 0x00, 0x04, 0x80, 0x00,
0x00, 0x10, 0x00, 0x20, 0x00, 0x03, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10,
0x80, 0x00, 0x01, 0x66, 0x81, 0x00, 0x01, 0x2e,
0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1c,
0x02, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x50,
0x22, 0x00, 0x00, 0x30, 0x24, 0x00, 0x00, 0xee,
0x26, 0x00, 0x00, 0x3c, 0xff, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x53, 0x68, 0x6f, 0x65, 0x62, 0x69, 0x6c, 0x6c,
0x20, 0x50, 0x68, 0x6f, 0x6e, 0x79, 0x20, 0x56,
0x69, 0x64, 0x65, 0x6f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x14, 0x02, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x31, 0x7c, 0x00, 0x01,
0x00, 0x02, 0x4e, 0x75, 0x00, 0x00, 0x00, 0xae,
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x31, 0x7c, 0x00, 0x01, 0x00, 0x02, 0x2a, 0x48,
0x31, 0x7c, 0x00, 0x01, 0x00, 0x02, 0x10, 0x10,
0x12, 0x00, 0x00, 0x01, 0x00, 0xf0, 0xe0, 0x99,
0x22, 0x41, 0x9e, 0xfc, 0x00, 0x38, 0x20, 0x4f,
0x11, 0x40, 0x00, 0x31, 0x42, 0x28, 0x00, 0x33,
0x42, 0xa8, 0x00, 0x04, 0x20, 0x3c, 0x00, 0x00,
0xa8, 0x9f, 0xa7, 0x46, 0x22, 0x08, 0x20, 0x3c,
0x00, 0x00, 0xab, 0x03, 0xa7, 0x46, 0xb1, 0xc1,
0x67, 0x62, 0x20, 0x4f, 0x42, 0x28, 0x00, 0x32,
0x42, 0x28, 0x00, 0x30, 0x31, 0x7c, 0x00, 0x03,
0x00, 0x28, 0x31, 0x7c, 0x00, 0x01, 0x00, 0x2a,
0x31, 0x7c, 0x00, 0x01, 0x00, 0x2c, 0x31, 0x7c,
0x54, 0x03, 0x00, 0x2e, 0x70, 0x15, 0xa0, 0x6e,
0x3a, 0x28, 0x00, 0x26, 0x0c, 0x28, 0x00, 0x81,
0x00, 0x32, 0x67, 0x00, 0x00, 0x30, 0x70, 0x31,
0xa0, 0x6e, 0x11, 0x78, 0x00, 0x81, 0x00, 0x32,
0x42, 0x68, 0x00, 0x26, 0x42, 0xa8, 0x00, 0x18,
0x42, 0xa8, 0x00, 0x04, 0x70, 0x0a, 0xa0, 0x6e,
0x59, 0x4f, 0xaa, 0x29, 0x20, 0x5f, 0x20, 0x50,
0xba, 0x50, 0x66, 0x08, 0x20, 0x68, 0x00, 0x16,
0x20, 0x50, 0x20, 0x89, 0x4f, 0xef, 0x00, 0x38,
0x4e, 0x75, 0x01, 0x00, 0x00, 0x0c, 0x03, 0x00,
0x00, 0x14, 0x04, 0x00, 0x00, 0x18, 0x53, 0x68,
0x6f, 0x65, 0x62, 0x69, 0x6c, 0x6c, 0x00, 0x00,
0x00, 0x00, 0x52, 0x65, 0x76, 0x2d, 0x31, 0x00,
0x00, 0x00, 0x4d, 0x6f, 0x6f, 0x66, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x9c, 0x02, 0x00,
0x00, 0x78, 0x04, 0x00, 0x00, 0x9c, 0x08, 0x00,
0x00, 0x01, 0x0c, 0x00, 0x00, 0x64, 0x0d, 0x00,
0x00, 0x64, 0x80, 0x00, 0x00, 0x14, 0x81, 0x00,
0x00, 0x20, 0x82, 0x00, 0x00, 0x2c, 0x83, 0x00,
0x00, 0x38, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff,
0xfe, 0x9a, 0x03, 0x00, 0x00, 0x01, 0x04, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff,
0xfe, 0xb8, 0x03, 0x00, 0x00, 0x01, 0x04, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff,
0xfe, 0xd6, 0x03, 0x00, 0x00, 0x01, 0x04, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff,
0xfe, 0xf4, 0x03, 0x00, 0x00, 0x01, 0x04, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x44, 0x69,
0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x56, 0x69,
0x64, 0x65, 0x6f, 0x5f, 0x41, 0x70, 0x70, 0x6c,
0x65, 0x5f, 0x53, 0x68, 0x6f, 0x65, 0x62, 0x69,
0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x01, 0x00, 0x01, 0x54, 0x03, 0x02, 0x00,
0x00, 0x08, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0xa6, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x62,
0x01, 0x62, 0x01, 0x70, 0x1d, 0x2e, 0x44, 0x69,
0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x56, 0x69,
0x64, 0x65, 0x6f, 0x5f, 0x41, 0x70, 0x70, 0x6c,
0x65, 0x5f, 0x53, 0x68, 0x6f, 0x65, 0x62, 0x69,
0x6c, 0x6c, 0x00, 0x00, 0x24, 0x48, 0x26, 0x49,
0x70, 0x10, 0xa7, 0x1e, 0x66, 0x00, 0x01, 0x64,
0x49, 0xfa, 0x01, 0x3e, 0x31, 0x7c, 0x00, 0x06,
0x00, 0x04, 0x21, 0x4c, 0x00, 0x08, 0x21, 0x6b,
0x00, 0x2a, 0x00, 0x0c, 0x70, 0x00, 0x10, 0x2b,
0x00, 0x28, 0xa0, 0x75, 0x66, 0x00, 0x01, 0x44,
0x70, 0x00, 0x4e, 0x75, 0x48, 0xe7, 0x7f, 0xfe,
0x72, 0x00, 0x32, 0x28, 0x00, 0x1a, 0x24, 0x69,
0x00, 0x00, 0x01, 0x00, 0x00, 0xf0, 0x02, 0x00,
0x00, 0xcc, 0x04, 0x00, 0x00, 0xf0, 0x08, 0x00,
0x00, 0x01, 0x0c, 0x00, 0x00, 0xb8, 0x0d, 0x00,
0x00, 0xb8, 0x80, 0x00, 0x00, 0x48, 0x81, 0x00,
0x00, 0x54, 0x82, 0x00, 0x00, 0x60, 0x83, 0x00,
0x00, 0x6c, 0x84, 0x00, 0x00, 0x78, 0x85, 0x00,
0x00, 0x84, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0xbc, 0x02, 0x00, 0x00, 0x98, 0x04, 0x00,
0x00, 0xbc, 0x08, 0x00, 0x00, 0x01, 0x0c, 0x00,
0x00, 0x84, 0x0d, 0x00, 0x00, 0x84, 0x80, 0x00,
0x00, 0x14, 0x81, 0x00, 0x00, 0x20, 0x82, 0x00,
0x00, 0x2c, 0x83, 0x00, 0x00, 0x38, 0xff, 0x00,
0x00, 0x00, 0x01, 0xff, 0xfd, 0x56, 0x03, 0x00,
0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x01, 0xff, 0xfd, 0x74, 0x03, 0x00,
0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x01, 0xff, 0xfd, 0x92, 0x03, 0x00,
0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x01, 0xff, 0xfd, 0xb0, 0x03, 0x00,
0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x01, 0xff, 0xfd, 0xce, 0x03, 0x00,
0x00, 0x01, 0x04, 0x00, 0x00, 0x02, 0xff, 0x00,
0x00, 0x00, 0x01, 0xff, 0xfd, 0xec, 0x03, 0x00,
0x00, 0x01, 0x04, 0x00, 0x00, 0x02, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
0x00, 0x00, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61,
0x79, 0x5f, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x5f,
0x41, 0x70, 0x70, 0x6c, 0x65, 0x5f, 0x53, 0x68,
0x6f, 0x65, 0x62, 0x69, 0x6c, 0x6c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01,
0x54, 0x03, 0x02, 0x00, 0x00, 0x08, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x42, 0x4c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32,
0x00, 0x00, 0x00, 0x62, 0x01, 0xd4, 0x01, 0xf8,
0x1d, 0x2e, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61,
0x79, 0x5f, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x5f,
0x41, 0x70, 0x70, 0x6c, 0x65, 0x5f, 0x53, 0x68,
0x6f, 0x65, 0x62, 0x69, 0x6c, 0x6c, 0x00, 0x00,
0x24, 0x48, 0x26, 0x49, 0x70, 0x10, 0xa7, 0x1e,
0x66, 0x00, 0x02, 0x00, 0x49, 0xfa, 0x01, 0xda,
0x31, 0x7c, 0x00, 0x06, 0x00, 0x04, 0x21, 0x4c,
0x00, 0x08, 0x21, 0x6b, 0x00, 0x2a, 0x00, 0x0c,
0x70, 0x00, 0x10, 0x2b, 0x00, 0x28, 0xa0, 0x75,
0x66, 0x00, 0x01, 0xe0, 0x70, 0x00, 0x4e, 0x75,
0x48, 0xe7, 0x7f, 0xfe, 0x72, 0x00, 0x32, 0x28,
0x00, 0x1a, 0x24, 0x69, 0x00, 0x2a, 0xd5, 0xfc,
0x00, 0xf0, 0x00, 0x00, 0x26, 0x68, 0x00, 0x1c,
0x0c, 0x41, 0x00, 0x00, 0x66, 0x00, 0x00, 0x16,
0x25, 0x78, 0x00, 0x80, 0x00, 0x04, 0x25, 0x7c,
0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x70, 0x00,
0x60, 0x00, 0x01, 0x3a, 0x0c, 0x41, 0x00, 0x01,
0x66, 0x00, 0x00, 0x08, 0x70, 0x00, 0x60, 0x00,
0x01, 0x2c, 0x0c, 0x41, 0x00, 0x02, 0x66, 0x00,
0x00, 0x12, 0x15, 0x7c, 0x00, 0x01, 0x00, 0x24,
0x35, 0x53, 0x00, 0x04, 0x70, 0x00, 0x60, 0x00,
0x01, 0x14, 0x0c, 0x41, 0x00, 0x03, 0x66, 0x00,
0x00, 0x4a, 0x28, 0x53, 0x74, 0x00, 0x34, 0x2b,
0x00, 0x04, 0x76, 0x00, 0x36, 0x2b, 0x00, 0x06,
0x0c, 0x42, 0xff, 0xff, 0x66, 0x00, 0x00, 0x04,
0x4e, 0x70, 0x28, 0x02, 0xe7, 0x8c, 0xd9, 0xc4,
0x52, 0x83, 0x78, 0x00, 0x25, 0x42, 0x00, 0x0c,
0x35, 0x6c, 0x00, 0x02, 0x00, 0x10, 0x35, 0x6c,
0x00, 0x04, 0x00, 0x14, 0x35, 0x6c, 0x00, 0x06,
0x00, 0x18, 0x52, 0x82, 0x50, 0x8c, 0x52, 0x84,
0xb6, 0x44, 0x66, 0xe0, 0x70, 0x00, 0x60, 0x00,
0x00, 0xc4, 0x0c, 0x41, 0x00, 0x04, 0x66, 0x00,
0x00, 0x12, 0x28, 0x3c, 0xb0, 0x04, 0x00, 0x00,
0x25, 0x44, 0x00, 0x20, 0x70, 0xef, 0x60, 0x00,
0x00, 0xac, 0x0c, 0x41, 0x00, 0x05, 0x66, 0x00,
0x00, 0x16, 0x28, 0x3c, 0xb0, 0x05, 0x00, 0x00,
0x25, 0x44, 0x00, 0x20, 0x42, 0xaa, 0x00, 0x08,
0x70, 0x00, 0x60, 0x00, 0x00, 0x90, 0x0c, 0x41,
0x00, 0x06, 0x66, 0x00, 0x00, 0x16, 0x28, 0x3c,
0xb0, 0x06, 0x00, 0x00, 0x25, 0x44, 0x00, 0x20,
0x15, 0x53, 0x00, 0x28, 0x70, 0x00, 0x60, 0x00,
0x00, 0x74, 0x0c, 0x41, 0x00, 0x07, 0x66, 0x00,
0x00, 0x1a, 0x28, 0x3c, 0xb0, 0x07, 0x00, 0x00,
0x18, 0x13, 0x25, 0x44, 0x00, 0x20, 0x12, 0x13,
0x15, 0x41, 0x00, 0x1c, 0x70, 0x00, 0x60, 0x00,
0x00, 0x54, 0x0c, 0x41, 0x00, 0x08, 0x66, 0x00,
0x00, 0x08, 0x70, 0xef, 0x60, 0x00, 0x00, 0x46,
0x0c, 0x41, 0x00, 0x09, 0x66, 0x00, 0x00, 0x3c,
0x28, 0x3c, 0xb0, 0x09, 0x00, 0x00, 0x18, 0x13,
0x25, 0x44, 0x00, 0x20, 0x9e, 0xfc, 0x00, 0x38,
0x20, 0x4f, 0x11, 0x69, 0x00, 0x28, 0x00, 0x31,
0x42, 0x28, 0x00, 0x33, 0x51, 0x4f, 0x20, 0x8f,
0x70, 0x11, 0xa0, 0x6e, 0x1f, 0x53, 0x00, 0x03,
0x21, 0x4f, 0x00, 0x04, 0x70, 0x12, 0xa0, 0x6e,
0x4f, 0xef, 0x00, 0x40, 0x70, 0x00, 0x60, 0x00,
0x00, 0x04, 0x70, 0xef, 0x4c, 0xdf, 0x7f, 0xfe,
0x4e, 0x75, 0x48, 0xe7, 0x7f, 0xfe, 0x24, 0x69,
0x00, 0x2a, 0xd5, 0xfc, 0x00, 0xf0, 0x00, 0x00,
0x26, 0x68, 0x00, 0x1c, 0x0c, 0x41, 0x00, 0x00,
0x66, 0x00, 0x00, 0x16, 0x25, 0x78, 0x00, 0x80,
0x00, 0x04, 0x25, 0x7c, 0x00, 0x00, 0x00, 0x01,
0x00, 0x08, 0x70, 0x00, 0x60, 0x00, 0x00, 0xc8,
0x0c, 0x41, 0x00, 0x01, 0x66, 0x00, 0x00, 0x08,
0x70, 0x00, 0x60, 0x00, 0x00, 0xba, 0x0c, 0x41,
0x00, 0x02, 0x66, 0x00, 0x00, 0x0c, 0x35, 0x53,
0x00, 0x04, 0x70, 0x00, 0x60, 0x00, 0x00, 0xa8,
0x0c, 0x41, 0x00, 0x03, 0x66, 0x00, 0x00, 0x4a,
0x28, 0x53, 0x74, 0x00, 0x34, 0x2b, 0x00, 0x04,
0x76, 0x00, 0x36, 0x2b, 0x00, 0x06, 0x0c, 0x42,
0xff, 0xff, 0x66, 0x00, 0x00, 0x04, 0x4e, 0x70,
0x28, 0x02, 0xe7, 0x8c, 0xd9, 0xc4, 0x52, 0x83,
0x78, 0x00, 0x25, 0x42, 0x00, 0x0c, 0x35, 0x6c,
0x00, 0x02, 0x00, 0x10, 0x35, 0x6c, 0x00, 0x04,
0x00, 0x14, 0x35, 0x6c, 0x00, 0x06, 0x00, 0x18,
0x52, 0x82, 0x50, 0x8c, 0x52, 0x84, 0xb6, 0x44,
0x66, 0xe0, 0x70, 0xef, 0x60, 0x00, 0x00, 0x58,
0x0c, 0x41, 0x00, 0x04, 0x66, 0x00, 0x00, 0x08,
0x70, 0xef, 0x60, 0x00, 0x00, 0x4a, 0x0c, 0x41,
0x00, 0x05, 0x66, 0x00, 0x00, 0x08, 0x70, 0xef,
0x60, 0x00, 0x00, 0x3c, 0x0c, 0x41, 0x00, 0x06,
0x66, 0x00, 0x00, 0x08, 0x70, 0xef, 0x60, 0x00,
0x00, 0x2e, 0x0c, 0x41, 0x00, 0x07, 0x66, 0x00,
0x00, 0x08, 0x70, 0xef, 0x60, 0x00, 0x00, 0x20,
0x0c, 0x41, 0x00, 0x08, 0x66, 0x00, 0x00, 0x08,
0x70, 0xef, 0x60, 0x00, 0x00, 0x12, 0x0c, 0x41,
0x00, 0x09, 0x66, 0x00, 0x00, 0x08, 0x70, 0xef,
0x60, 0x00, 0x00, 0x04, 0x70, 0xef, 0x4c, 0xdf,
0x7f, 0xfe, 0x4e, 0x75, 0x26, 0x7c, 0xfa, 0x00,
0xbe, 0xef, 0x26, 0xbc, 0xde, 0xad, 0xbe, 0xef,
0x4e, 0x70, 0x26, 0x7c, 0xfa, 0x00, 0xbe, 0xef,
0x26, 0xbc, 0xde, 0xad, 0xbe, 0xef, 0x4e, 0x70,
0x25, 0x7c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x20,
0x70, 0xee, 0x60, 0x00, 0x00, 0x04, 0x70, 0xee,
0x4c, 0xdf, 0x7f, 0xfe, 0x4e, 0x75, 0x48, 0xe7,
0x7f, 0xfe, 0x24, 0x69, 0x00, 0x2a, 0xd5, 0xfc,
0x00, 0xf0, 0x00, 0x00, 0x42, 0xaa, 0x00, 0x1c,
0x25, 0x7c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x20,
0x4c, 0xdf, 0x7f, 0xfe, 0x70, 0x00, 0x4e, 0x75,
0x20, 0x09, 0xe1, 0x98, 0x02, 0x80, 0x00, 0x00,
0x00, 0x0f, 0x20, 0x49, 0xd1, 0xfc, 0x00, 0xf0,
0x00, 0x00, 0x20, 0xbc, 0x00, 0x00, 0x00, 0x01,
@ -444,70 +508,7 @@ uint8_t _video_rom[4096] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0, 0xcc,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf1, 0x28,
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x5a, 0x93, 0x2b, 0xc7, 0x00, 0xe1};
0x01, 0x01, 0x5a, 0x93, 0x2b, 0xc7, 0x00, 0xe1
};

View File

@ -10,16 +10,16 @@ int main (int argc, char **argv)
uint32_t i;
if (argc != 3) {
printf("usage ./rom_to_c video_rom.bin video_rom.c\n");
printf("usage ./rom_to_c video|ethernet rom.bin rom.c\n");
return 0;
}
assert(in = fopen(argv[1], "r"));
assert(out = fopen(argv[2], "w"));
assert(in = fopen(argv[2], "rb"));
assert(out = fopen(argv[3], "w"));
assert(fread(rom, 4096, 1, in) == 1);
fprintf(out, "uint8_t _video_rom[4096] = {\n\t");
fprintf(out, "static uint8_t _%s_rom[4096] = {\n\t", argv[1]);
for (i=0; i<4095; i++) {
fprintf(out, "0x%02x, ", rom[i]);
if ((i % 8) == 7)

0
core/video_rom/shoebill_video.make Normal file → Executable file
View File

2
core/video_rom/shoebill_video_driver.a Normal file → Executable file

File diff suppressed because one or more lines are too long

2
core/video_rom/shoebill_video_primary_init.a Normal file → Executable file
View File

@ -1 +1 @@
BLANKS ON STRING ASIS MACHINE MC68020 WITH seBlock DC.B 2 ; Code revision DC.B 2 ; 68020 DC.W 0 ; reserved DC.L PrimaryInitStart-* PrimaryInitStart move.w #1, seStatus(a0) ; seStatus > 0 -> success move.l a0, a5 rts PrimaryInitEnd
BLANKS ON STRING ASIS MACHINE MC68020 WITH seBlock DC.B 2 ; Code revision DC.B 2 ; 68020 DC.W 0 ; reserved DC.L PrimaryInitStart-* PrimaryInitStart ; Return "success" move.w #1, seStatus(a0) ; seStatus > 0 -> success ; FIXME: Designing Cards and Drivers for the Macintosh Family says I should disable VBLs here... ; FIXME: Also gray out the screen ; Usually, we would check if 32bit QD exists ; If it doesn't, then we'd try to invalidate sResourceVideo_qd32 ; unless the Mac II slot manager is loaded, in which case, we can't actually ; invalidate anything. ; Since Shoebill very likely won't support non-Mac II ROMs for a while, ; we have nothing to do rts PrimaryInitEnd

2
core/video_rom/shoebill_video_rom.a Normal file → Executable file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
BLANKS ON STRING ASIS MACHINE MC68020 WITH seBlock,spBlock DC.B 2 ; Code revision DC.B 2 ; 68020 DC.W 0 ; reserved DC.L SecondaryInitStart-* SecondaryInitStart ; Return "success" move.w #1, seStatus(a0) ; seStatus > 0 -> success ; Figure out the slot base address (non-superslot) move.b seSlot(a0), d0 ; -> d0.b = slotnum move.b d0, d1 or.b #$F0, d1 ror.l #8, d1 move.l d1, a1 ; -> a1 = slot base addr ; Set up a slot parameter block suba #spBlockSize, sp move.l sp, a0 move.b d0, spSlot(a0) clr.b spExtDev(a0) clr.l spsPointer(a0) ; Verify that 32bit QD is loaded move.l #$a89f, d0 _GetTrapAddress ,NewTool move.l a0, d1 move.l #$ab03, d0 _GetTrapAddress ,NewTool cmpa.l d1, a0 beq.s sec_done ; Find the current video sResource move.l sp, a0 clr.b spID(a0) ; start at id=0 clr.b spTBMask(a0) ; match exactly move.w #CatDisplay, spCategory(a0) move.w #TypVideo, spCType(a0) move.w #DrSwApple, spDrvrSW(a0) move.w #DrHwShoe, spDrvrHW(a0) _sNextTypesRsrc move.w spRefNum(a0), d5 ; If, somehow, the 32 bit video sResource is the only active one, then just return cmp.b #CategoryVideo_qd32, spID(a0) beq.w sec_done ; Otherwise, it's the non-32bit sResource - so nuke it _sDeleteSRTRec ; Load our PRAM bytes, which contain the default depth ; suba.l #sizesPRAMRec, sp ; _sReadPRAMRec ; move.b VendorUse2(sp), spID(a0) ; adda.l #sizesPRAMRec, sp ; And activate the 32bit sResource move.b CategoryVideo_qd32, spID(a0) clr.w spRefNum(a0) ; ? clr.l spParamData(a0) ; clear for activation clr.l spsPointer(a0) ; add back a sRsrc in directory _InsertSRTRec ; If this is the boot screen, then update its gDevice subq #4, sp ; make room for function return _GetDeviceList ; get the boot gDevice move.l (sp)+, a0 ; get the gdHandle move.l (a0), a0 ; get pointer to gDevice cmp.w gdRefNum(a0), d5 ; was this the boot device? bne.s sec_done ; No? then return move.l gdPMap(a0), a0 ; get pixMap handle move.l (a0), a0 ; getpixMap ptr move.l a1, pmBaseAddr(a0) ; save new base address ; FIXME: Wait, that wasn't necessary. All video modes have the same pmBaseAddr, I think sec_done adda #spBlockSize, sp rts SecondaryInitEnd

12
debugger/Makefile Normal file
View File

@ -0,0 +1,12 @@
CC = clang
CFLAGS = -O3 -ggdb -flto -Wno-deprecated-declarations
LFLAGS = -L ../intermediates -lshoebill_core -framework GLUT -framework OpenGL -ledit
all: debugger
debugger: Makefile debugger.c ../intermediates/libshoebill_core.a
$(CC) $(CFLAGS) $(LFLAGS) debugger.c -o debugger
clean:
rm -rf debugger

903
debugger/debugger.c Normal file
View File

@ -0,0 +1,903 @@
/*
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <GLUT/glut.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <histedit.h>
#include "../core/shoebill.h"
rb_tree *keymap;
struct dbg_state_t {
EditLine *el;
uint8_t running;
uint64_t breakpoint_counter;
dbg_breakpoint_t *breakpoints;
_Bool trace;
uint32_t slow_factor;
char *ring;
uint32_t ring_i, ring_len;
uint64_t op_count[0x10000];
};
struct dbg_state_t dbg_state;
void print_mmu_rp(uint64_t rp)
{
printf("lu=%u limit=0x%x sg=%u dt=%u addr=0x%08x\n", rp_lu(rp), rp_limit(rp), rp_sg(rp), rp_dt(rp), rp_addr(rp));
}
void printregs()
{
printf("[d0]%08x [d1]%08x [d2]%08x [d3]%08x\n", shoe.d[0], shoe.d[1], shoe.d[2], shoe.d[3]);
printf("[d4]%08x [d5]%08x [d6]%08x [d7]%08x\n", shoe.d[4], shoe.d[5], shoe.d[6], shoe.d[7]);
printf("[a0]%08x [a1]%08x [a2]%08x [a3]%08x\n", shoe.a[0], shoe.a[1], shoe.a[2], shoe.a[3]);
printf("[a4]%08x [a5]%08x [a6]%08x [a7]%08x\n", shoe.a[4], shoe.a[5], shoe.a[6], shoe.a[7]);
printf("[pc]%08x [sr]%c%c%c%c%c%c%c [tc]%08x\n", shoe.pc,
sr_s()?'S':'s',
sr_m()?'M':'m',
sr_x()?'X':'x',
sr_n()?'N':'n',
sr_z()?'Z':'z',
sr_v()?'V':'v',
sr_c()?'C':'c',
shoe.tc
);
printf("[vbr]%08x\n", shoe.vbr);
printf("srp: ");
print_mmu_rp(shoe.srp);
printf("crp: ");
print_mmu_rp(shoe.crp);
printf("tc: e=%u sre=%u fcl=%u ps=%u is=%u (tia=%u tib=%u tic=%u tid=%u)\n",
_tc_enable(), _tc_sre(), tc_fcl(), _tc_ps(), _tc_is(), tc_tia(), tc_tib(), tc_tic(), tc_tid());
printf("\n");
}
void print_pc()
{
char str[1024];
uint8_t binary[32];
uint32_t i;
uint32_t len;
const char *name = NULL;
if ((shoe.pc >= 0x40000000) && (shoe.pc < 0x50000000)) {
uint32_t i, addr = shoe.pc % (shoe.physical_rom_size);
for (i=0; macii_rom_symbols[i].name; i++) {
if (macii_rom_symbols[i].addr > addr) {
break;
}
name = macii_rom_symbols[i].name;
}
}
else if (sr_s()) { // these symbols are only meaningful in supervisor mode
coff_symbol *symb = coff_find_func(shoe.coff, shoe.pc);
if (symb && strlen(symb->name))
name = symb->name;
}
else {
if ((shoe.pc >= 0x10000000) && (shoe.pc < 0x20000000)) {
uint32_t i, addr = shoe.pc % (shoe.physical_rom_size);
for (i=0; macii_rom_symbols[i].name; i++) {
if (macii_rom_symbols[i].addr > addr) {
break;
}
name = macii_rom_symbols[i].name;
}
}
else {
name = "";
}
}
const uint16_t old_abort = shoe.abort;
shoe.suppress_exceptions = 1;
for (i=0; i<32; i++) {
binary[i] = (uint8_t) lget(shoe.pc+i, 1);
}
disassemble_inst(binary, shoe.pc, str, &len);
printf("*0x%08x %s [ ", shoe.pc, name ? name : "");
for (i=0; i<len; i+=2) {
printf("%02x%02x ", binary[i], binary[i+1]);
}
printf("] %s\n", str);
shoe.abort = old_abort;
shoe.suppress_exceptions = 0;
}
static void dump_proc(uint32_t procnum)
{
uint32_t u_proc_p;
uint16_t pid;
uint8_t do_print = 0, cpuflag;
// Only dump this process state if we're in user mode
if (sr_s())
return ;
shoe.suppress_exceptions = 1;
cpuflag = lget(0x0000012f, 1);
set_sr_s(1); // set supervisor mode so we can access the proc structure
u_proc_p = lget(0x1ff01000, 4);
if (shoe.abort)
goto done;
pid = lget(u_proc_p + 0x26, 2);
if (shoe.abort)
goto done;
do_print = 1;
done:
set_sr_s(0);
shoe.abort = 0;
shoe.suppress_exceptions = 0;
if (do_print) {
printf("pid = %u, cpuflag=0x%02x\n", pid, cpuflag);
// print_pc();
// printregs();
}
}
void verb_backtrace_handler (const char *line)
{
const uint32_t old_abort = shoe.abort;
shoe.suppress_exceptions = 1;
shoe.abort = 0;
// link
// push a6 to a7
// set a6 = a7
// set a7 = a7 - (some stack space)
// jsr
// push return pointer to a7
// call
// set a7 = a7 - (some stack space)
// push arguments to a7
// push return pointer to a7
// (jump to function)
// push
// bt algorithm
// set a7 = a6
// pop a7 -> a6
// pop a7 -> return pointer
uint32_t i, j, a7, a6 = shoe.a[6];
coff_symbol *symb;
if (sr_s()) {
symb = coff_find_func(shoe.coff, shoe.pc);
printf("%u: *0x%08x %s+%u\n", 0, shoe.pc, (symb && strlen(symb->name))?symb->name:"?", shoe.pc - symb->value);
}
else
printf("%u: *0x%08x\n", 0, shoe.pc);
for (i=1; 1; i++) {
a7 = a6;
const uint32_t last_a6 = lget(a7, 4);
const uint32_t last_pc = lget(a7+4, 4);
if ((last_a6 - a6) <= 1000) {
printf(" {");
for (j = a6+8; j < last_a6; j+=4) {
uint32_t data = lget(j, 4);
printf("%x, ", data);
}
printf("}\n");
}
if (sr_s()) {
symb = coff_find_func(shoe.coff, last_pc);
printf("%u: *0x%08x %s+%u\n", i, last_pc, (symb && strlen(symb->name))?symb->name:"?", last_pc - symb->value);
}
else
printf("%u: *0x%08x\n", i, last_pc);
if ((last_a6 - a6) > 1000) {
break;
}
a6 = last_a6;
}
shoe.suppress_exceptions = 0;
shoe.abort = old_abort;
}
void verb_break_handler (const char *line)
{
errno = 0;
const uint32_t addr = (uint32_t) strtoul(line, NULL, 0);
if (errno) {
printf("errno: %d\n", errno);
return ;
}
dbg_breakpoint_t *brk = calloc(sizeof(dbg_breakpoint_t), 1);
brk->next = NULL;
brk->addr = addr;
brk->num = dbg_state.breakpoint_counter++;
dbg_breakpoint_t **cur = &dbg_state.breakpoints;
while (*cur)
cur = &(*cur)->next;
*cur = brk;
printf("Set breakpoint %llu = *0x%08x\n", brk->num, brk->addr);
}
void verb_delete_handler (const char *line)
{
errno = 0;
uint64_t num = strtoull(line, NULL, 0);
if (errno) {
printf("errno: %d\n", errno);
return ;
}
dbg_breakpoint_t **cur = &dbg_state.breakpoints;
while (*cur) {
if ((*cur)->num == num) {
dbg_breakpoint_t *victim = *cur;
*cur = (*cur)->next;
free(victim);
return ;
}
cur = &(*cur)->next;
}
printf("No such breakpoint (#%llu)\n", num);
}
void verb_help_handler (const char *line)
{
printf("Help help help\n");
}
void verb_stepi_handler (const char *line)
{
dbg_state.running = 1;
cpu_step();
dbg_state.running = 0;
print_pc();
}
void verb_registers_handler (const char *line)
{
printregs();
}
void verb_trace_toggle_handler (const char *line)
{
dbg_state.trace = !dbg_state.trace;
}
void verb_examine_handler (const char *line)
{
uint32_t addr = (uint32_t)strtoul(line, NULL, 0);
uint32_t old_suppress = shoe.suppress_exceptions;
shoe.suppress_exceptions = 1;
printf("(uint32_t)*0x%08x = 0x%08x\n", addr, (uint32_t)lget(addr, 4));
shoe.suppress_exceptions = old_suppress;
}
void verb_lookup_handler (const char *line)
{
char *sym_name = malloc(strlen(line)+1);
sscanf(line, "%s", sym_name);
coff_symbol *symb = coff_find_symbol(shoe.coff, sym_name);
free(sym_name);
if (symb == NULL) {
printf("Couldn't find \"%s\"\n", sym_name);
return ;
}
printf("%s = *0x%08x\n", symb->name, symb->value);
}
void stepper()
{
dbg_breakpoint_t *cur;
if (shoe.cpu_thread_notifications) {
// If there's an interrupt pending
if (shoe.cpu_thread_notifications & 0xff) {
// process_pending_interrupt() may clear SHOEBILL_STATE_STOPPED
process_pending_interrupt();
}
if (shoe.cpu_thread_notifications & SHOEBILL_STATE_STOPPED) {
// I think it's safe to ignore STOP instructions...
}
}
cpu_step();
if (dbg_state.trace) {
print_pc();
printregs();
}
for (cur = dbg_state.breakpoints; cur != NULL; cur = cur->next) {
if (shoe.pc == cur->addr) {
printf("Hit breakpoint %llu *0x%08x\n", cur->num, shoe.pc);
dbg_state.running = 0;
return ;
}
}
}
void verb_continue_handler (const char *line)
{
dbg_state.running = 1;
while (dbg_state.running) {
if (dbg_state.slow_factor)
usleep(dbg_state.slow_factor);
stepper();
}
print_pc();
}
void verb_quit_handler (const char *line)
{
printf("Quitting\n");
fflush(stdout);
exit(0);
}
void verb_reset_handler (const char *line)
{
p_free_pool(shoe.pool);
shoe.pool = NULL;
}
void verb_slow_handler (const char *line)
{
const uint64_t usecs = strtoul(line, NULL, 0);
printf("Slow factor %u -> %u\n", dbg_state.slow_factor, (uint32_t)usecs);
dbg_state.slow_factor = usecs;
}
struct verb_handler_table_t {
const char *name;
void (*func)(const char *);
} verb_handler_table[] =
{
{"quit", verb_quit_handler},
{"continue", verb_continue_handler},
{"help", verb_help_handler},
{"registers", verb_registers_handler},
{"stepi", verb_stepi_handler},
{"backtrace", verb_backtrace_handler},
{"bt", verb_backtrace_handler},
{"break", verb_break_handler},
{"delete", verb_delete_handler},
{"lookup", verb_lookup_handler},
{"trace", verb_trace_toggle_handler},
{"x", verb_examine_handler},
{"reset", verb_reset_handler},
{"slow", verb_slow_handler},
};
void execute_verb (const char *line)
{
char verb[128];
uint32_t max_len=0, max_i=0;
const char *remainder;
uint32_t i, matches = 0, match_i;
if (sscanf(line, "%127s", verb) != 1)
return ;
// Skip past the verb
for (remainder = line; *remainder && !isspace(*remainder); remainder++)
;
// Skip past the space between the verb and the arguments
for (; *remainder && isspace(*remainder); remainder++)
;
const uint32_t verb_len = strlen(verb);
for (i=0; i < (sizeof(verb_handler_table) / sizeof(struct verb_handler_table_t)); i++) {
const uint32_t i_len = strlen(verb_handler_table[i].name);
// If it's a perfect match,
if (strcasecmp(verb, verb_handler_table[i].name)==0) {
verb_handler_table[i].func(remainder);
return ;
}
// Otherwise, see if it's a partial match
if ((i_len >= verb_len) && strncasecmp(verb, verb_handler_table[i].name, verb_len)==0) {
matches++;
match_i = i;
}
}
// Only execute the verb if it's an unambiguous match (matches == 1)
if (matches == 1) {
verb_handler_table[match_i].func(remainder);
return ;
}
printf(" %s?\n", verb);
}
char *cli_prompt_callback(EditLine *el)
{
return "~ ";
}
// Hack to clear line after ^C. el_reset() screws up tty when called from the signal handler.
void ch_reset(EditLine *el, int mclear);
void signal_callback(int sig)
{
EditLine *el = dbg_state.el;
(void) signal(SIGINT, signal_callback);
(void) signal(SIGWINCH, signal_callback);
switch (sig) {
case SIGWINCH:
el_resize(el);
break ;
case SIGINT:
if (dbg_state.running) {
dbg_state.running = 0;
}
else {
printf("\n");
ch_reset(el, 0);
el_set(el, EL_REFRESH);
}
break ;
}
return ;
}
void *ui_thread (void *arg)
{
EditLine *el;
History *hist;
HistEvent histev;
const char *buf;
int num;
hist = history_init();
history(hist, &histev, H_SETSIZE, 10000); // Remember 10000 previous user inputs
el = el_init("Shoebill", stdin, stdout, stderr);
dbg_state.el = el;
el_set(el, EL_SIGNAL, 0);
el_set(el, EL_PROMPT, cli_prompt_callback);
el_set(el, EL_EDITOR, "emacs");
el_set(el, EL_HIST, history, hist);
(void) signal(SIGINT, signal_callback);
(void) signal(SIGWINCH, signal_callback);
while ((buf = el_gets(el, &num)) != NULL) {
if (strcmp(buf, "\n")!=0) {
execute_verb(buf);
history(hist, &histev, H_ENTER, buf);
}
}
el_end(el);
history_end(hist);
return NULL;
}
static uint8_t lookup_special(int special)
{
switch (special) {
case GLUT_KEY_UP: return 0x3e;
case GLUT_KEY_DOWN: return 0x3d;
case GLUT_KEY_LEFT: return 0x3b;
case GLUT_KEY_RIGHT: return 0x3c;
default: return 0xff;
}
}
static uint32_t _get_modifiers (void)
{
int glut_modifiers = glutGetModifiers();
uint32_t result = 0;
result |= (glut_modifiers & GLUT_ACTIVE_SHIFT) ? (1 << 17) : 0;
result |= (glut_modifiers & GLUT_ACTIVE_CTRL) ? (1 << 18) : 0;
result |= (glut_modifiers & GLUT_ACTIVE_ALT) ? (1 << 19) : 0;
return result;
}
void global_mouse_func (int button, int state, int x, int y)
{
shoebill_mouse_click(state == GLUT_DOWN);
shoebill_mouse_move(x, y);
}
void global_motion_func (int x, int y)
{
shoebill_mouse_click(1);
shoebill_mouse_move(x, y);
}
void global_passive_motion_func (int x, int y)
{
shoebill_mouse_click(0);
shoebill_mouse_move(x, y);
}
void global_keyboard_up_func (unsigned char c, int x, int y)
{
uint16_t value;
if (rb_find(keymap, c, &value)) {
shoebill_key_modifier((value >> 8) | (_get_modifiers() >> 16));
shoebill_key(0, value & 0xff);
}
}
void global_keyboard_down_func (unsigned char c, int x, int y)
{
uint16_t value;
if (rb_find(keymap, c, &value)) {
shoebill_key_modifier((value >> 8) | (_get_modifiers() >> 16));
shoebill_key(1, value & 0xff);
}
}
void global_special_up_func (int special, int x, int y)
{
const uint8_t code = lookup_special(special);
if (code != 0xff) {
shoebill_key_modifier(_get_modifiers() >> 16);
shoebill_key(0, code);
}
}
void global_special_down_func (int special, int x, int y)
{
const uint8_t code = lookup_special(special);
if (code != 0xff) {
shoebill_key_modifier(_get_modifiers() >> 16);
shoebill_key(1, code);
}
}
void timer_func (int arg)
{
glutTimerFunc(15, timer_func, 0); // 15ms = 66.67hz
glutPostRedisplay();
}
void _display_func (void)
{
shoebill_video_frame_info_t frame = shoebill_get_video_frame(9, 0);
shoebill_send_vbl_interrupt(9);
glDrawBuffer(GL_BACK);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0, 0.0, 0.0, 0.0);
glViewport(0, 0, frame.width, frame.height);
glRasterPos2i(0, frame.height);
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelZoom(1.0, -1.0);
glDrawPixels(frame.width,
frame.height,
GL_RGBA,
GL_UNSIGNED_BYTE,
frame.buf);
glutSwapBuffers();
}
static void _init_keyboard_map (void)
{
#define mapkeymod(u, a, m) do { \
assert((a >> 7) == 0); \
uint16_t value = ((m) << 8)| (a); \
rb_insert(keymap, u, &value, NULL); \
} while (0)
#define mapkey(_u, a) mapkeymod(_u, a, 0)
keymap = rb_new(p_new_pool(NULL), sizeof(uint16_t));
// Letters
mapkey('a', 0x00);
mapkey('b', 0x0b);
mapkey('c', 0x08);
mapkey('d', 0x02);
mapkey('e', 0x0e);
mapkey('f', 0x03);
mapkey('g', 0x05);
mapkey('h', 0x04);
mapkey('i', 0x22);
mapkey('j', 0x26);
mapkey('k', 0x28);
mapkey('l', 0x25);
mapkey('m', 0x2e);
mapkey('n', 0x2d);
mapkey('o', 0x1f);
mapkey('p', 0x23);
mapkey('q', 0x0c);
mapkey('r', 0x0f);
mapkey('s', 0x01);
mapkey('t', 0x11);
mapkey('u', 0x20);
mapkey('v', 0x09);
mapkey('w', 0x0d);
mapkey('x', 0x07);
mapkey('y', 0x10);
mapkey('z', 0x06);
// Numbers
mapkey('0', 0x1d);
mapkey('1', 0x12);
mapkey('2', 0x13);
mapkey('3', 0x14);
mapkey('4', 0x15);
mapkey('5', 0x17);
mapkey('6', 0x16);
mapkey('7', 0x1a);
mapkey('8', 0x1c);
mapkey('9', 0x19);
// Top row symbols
mapkeymod(')', 0x1d, modShift);
mapkeymod('!', 0x12, modShift);
mapkeymod('@', 0x13, modShift);
mapkeymod('#', 0x14, modShift);
mapkeymod('$', 0x15, modShift);
mapkeymod('%', 0x17, modShift);
mapkeymod('^', 0x16, modShift);
mapkeymod('&', 0x1a, modShift);
mapkeymod('*', 0x1c, modShift);
mapkeymod('(', 0x19, modShift);
// Other symbols (no shift)
mapkeymod('`', 0x32, 0);
mapkeymod('-', 0x1b, 0);
mapkeymod('=', 0x18, 0);
mapkeymod('[', 0x21, 0);
mapkeymod(']', 0x1e, 0);
mapkeymod('\\', 0x2a, 0);
mapkeymod(';', 0x29, 0);
mapkeymod('\'', 0x27, 0);
mapkeymod(',', 0x2b, 0);
mapkeymod('.', 0x2f, 0);
mapkeymod('/', 0x2c, 0);
// Other symbols (with shift)
mapkeymod('~', 0x32, modShift);
mapkeymod('_', 0x1b, modShift);
mapkeymod('+', 0x18, modShift);
mapkeymod('{', 0x21, modShift);
mapkeymod('}', 0x1e, modShift);
mapkeymod('|', 0x2a, modShift);
mapkeymod(':', 0x29, modShift);
mapkeymod('"', 0x27, modShift);
mapkeymod('<', 0x2b, modShift);
mapkeymod('>', 0x2f, modShift);
mapkeymod('?', 0x2c, modShift);
// Function keys
/*mapkey(NSF1FunctionKey, 0x7a);
mapkey(NSF2FunctionKey, 0x78);
mapkey(NSF3FunctionKey, 0x63);
mapkey(NSF4FunctionKey, 0x76);
mapkey(NSF5FunctionKey, 0x60);
mapkey(NSF6FunctionKey, 0x61);
mapkey(NSF7FunctionKey, 0x62);
mapkey(NSF8FunctionKey, 0x64);
mapkey(NSF9FunctionKey, 0x65);
mapkey(NSF10FunctionKey, 0x6d);
mapkey(NSF11FunctionKey, 0x67);
mapkey(NSF12FunctionKey, 0x6f);
mapkey(NSF13FunctionKey, 0x69);
mapkey(NSF14FunctionKey, 0x6b);
mapkey(NSF15FunctionKey, 0x71);*/
// Arrows
/*mapkey(NSUpArrowFunctionKey, 0x3e);
mapkey(NSDownArrowFunctionKey, 0x3d);
mapkey(NSRightArrowFunctionKey, 0x3c);
mapkey(NSLeftArrowFunctionKey, 0x3b);*/
// Delete
//mapkey(NSDeleteFunctionKey, 0x75);
mapkey(0x08, 0x33);
mapkey(0x7f, 0x33);
// Enter, NL, CR
mapkey('\r', 0x24);
mapkey('\n', 0x24);
mapkey(0x03, 0x24);
// Other keys
mapkey(0x1b, 0x35); // escape
mapkey(' ', 0x31); // space
mapkey('\t', 0x30); // tab
}
static void _init_glut_video (void)
{
shoebill_video_frame_info_t frame = shoebill_get_video_frame(9, 1);
glutInitWindowSize(frame.width, frame.height);
glutCreateWindow("Shoebill");
glutDisplayFunc(_display_func);
glutIgnoreKeyRepeat(1);
glutKeyboardFunc(global_keyboard_down_func);
glutKeyboardUpFunc(global_keyboard_up_func);
glutSpecialFunc(global_special_down_func);
glutSpecialUpFunc(global_special_up_func);
glutMouseFunc(global_mouse_func);
glutMotionFunc(global_motion_func);
glutPassiveMotionFunc(global_passive_motion_func);
glutInitDisplayMode (GLUT_DOUBLE);
glShadeModel(GL_FLAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glClearColor(0.1, 1.0, 0.1, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, frame.width, 0, frame.height, -1.0, 1.0);
glViewport(0, 0, frame.width, frame.height);
}
int main (int argc, char **argv)
{
shoebill_config_t config;
pthread_t pid;
bzero(&config, sizeof(shoebill_config_t));
/*
* A variety of hacky things happen in debug mode.
* shoebill_start() will not create a new thread to run
* the CPU loop. We'll create a CPU thread here, bypass
* core_api, and directly manipulate the emulator guts.
*
* This is not a great example of how to write a GUI
* for shoebill...
*/
config.debug_mode = 1;
config.aux_verbose = 0;
config.ram_size = 16 * 1024 * 1024;
config.aux_kernel_path = "/unix";
config.rom_path = "../../../shoebill_priv/macii.rom";
config.scsi_devices[0].path = "../../../shoebill_priv/root3.img";
//config.scsi_devices[1].path = "../priv/marathon.img";
/*dbg_state.ring_len = 256 * 1024 * 1024;
dbg_state.ring = malloc(dbg_state.ring_len);
dbg_state.ring_i = 0;*/
shoebill_validate_or_zap_pram(config.pram, 1);
if (!shoebill_initialize(&config)) {
printf("%s\n", config.error_msg);
return 0;
}
_init_keyboard_map();
shoebill_install_video_card(&config,
9, // slotnum
640, // 1024,
480); // 768,
// uint8_t ethernet_addr[6] = {0x22, 0x33, 0x55, 0x77, 0xbb, 0xdd};
// shoebill_install_ethernet_card(&config, 13, ethernet_addr);
// Start the VIA timer thread
shoebill_start();
// Create a new thread to drive the CPU & debugger UI
pthread_create(&pid, NULL, ui_thread, NULL);
int dummyargc = 1;
glutInit(&dummyargc, argv);
// Create/configure the screen
_init_glut_video();
// Set a GLUT timer to update the screen
glutTimerFunc(15, timer_func, 0);
glutMainLoop();
return 0;
}

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
870A2F9E192D2A6D00ABBC14 /* shoeScreenWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 870A2F9D192D2A6D00ABBC14 /* shoeScreenWindowController.m */; };
87495445189980E200E80F5B /* shoeScreenView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 87495444189980E200E80F5B /* shoeScreenView.xib */; };
8749544718999F5300E80F5B /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8749544618999F5300E80F5B /* OpenGL.framework */; };
874954491899A22D00E80F5B /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 874954481899A22D00E80F5B /* QuartzCore.framework */; };
@ -26,12 +27,14 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
870A2F9C192D2A6D00ABBC14 /* shoeScreenWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shoeScreenWindowController.h; sourceTree = "<group>"; };
870A2F9D192D2A6D00ABBC14 /* shoeScreenWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = shoeScreenWindowController.m; sourceTree = "<group>"; };
87495444189980E200E80F5B /* shoeScreenView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = shoeScreenView.xib; sourceTree = "<group>"; };
8749544618999F5300E80F5B /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
874954481899A22D00E80F5B /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = "<absolute>"; };
8781D24918A19C340016F604 /* shoePreferencesWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shoePreferencesWindowController.h; sourceTree = "<group>"; };
8781D24A18A19C340016F604 /* shoePreferencesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = shoePreferencesWindowController.m; sourceTree = "<group>"; };
8781D24B18A19C340016F604 /* shoePreferencesWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = shoePreferencesWindowController.xib; sourceTree = "<group>"; };
8781D24918A19C340016F604 /* shoePreferencesWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = shoePreferencesWindowController.h; path = Shoebill/shoePreferencesWindowController.h; sourceTree = "<group>"; };
8781D24A18A19C340016F604 /* shoePreferencesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = shoePreferencesWindowController.m; path = Shoebill/shoePreferencesWindowController.m; sourceTree = "<group>"; };
8781D24B18A19C340016F604 /* shoePreferencesWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = shoePreferencesWindowController.xib; path = Shoebill/shoePreferencesWindowController.xib; sourceTree = "<group>"; };
8782FCE2189AFEFB0081E19E /* shoeApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shoeApplication.h; sourceTree = "<group>"; };
8782FCE3189AFEFB0081E19E /* shoeApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = shoeApplication.m; sourceTree = "<group>"; };
87F9772818987700000D589E /* Shoebill.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Shoebill.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -70,6 +73,20 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
870A2F9F192D2ADA00ABBC14 /* Screen */ = {
isa = PBXGroup;
children = (
870A2F9C192D2A6D00ABBC14 /* shoeScreenWindowController.h */,
870A2F9D192D2A6D00ABBC14 /* shoeScreenWindowController.m */,
87495444189980E200E80F5B /* shoeScreenView.xib */,
AE75B30718A8210D00E66DB6 /* shoeScreenWindow.h */,
AE75B30818A8210D00E66DB6 /* shoeScreenWindow.m */,
87F9775F18987767000D589E /* shoeScreenView.h */,
87F9776018987767000D589E /* shoeScreenView.m */,
);
name = Screen;
sourceTree = "<group>";
};
87F9771F18987700000D589E = {
isa = PBXGroup;
children = (
@ -117,14 +134,8 @@
8782FCE3189AFEFB0081E19E /* shoeApplication.m */,
87F9773D18987700000D589E /* shoeAppDelegate.h */,
87F9773E18987700000D589E /* shoeAppDelegate.m */,
87495444189980E200E80F5B /* shoeScreenView.xib */,
AE75B30718A8210D00E66DB6 /* shoeScreenWindow.h */,
AE75B30818A8210D00E66DB6 /* shoeScreenWindow.m */,
87F9775F18987767000D589E /* shoeScreenView.h */,
87F9776018987767000D589E /* shoeScreenView.m */,
8781D24B18A19C340016F604 /* shoePreferencesWindowController.xib */,
8781D24918A19C340016F604 /* shoePreferencesWindowController.h */,
8781D24A18A19C340016F604 /* shoePreferencesWindowController.m */,
870A2F9F192D2ADA00ABBC14 /* Screen */,
AE0D1AAB193132E700EBBED0 /* Preferences */,
87F9773218987700000D589E /* Supporting Files */,
);
path = Shoebill;
@ -143,6 +154,17 @@
name = "Supporting Files";
sourceTree = "<group>";
};
AE0D1AAB193132E700EBBED0 /* Preferences */ = {
isa = PBXGroup;
children = (
8781D24B18A19C340016F604 /* shoePreferencesWindowController.xib */,
8781D24918A19C340016F604 /* shoePreferencesWindowController.h */,
8781D24A18A19C340016F604 /* shoePreferencesWindowController.m */,
);
name = Preferences;
path = ..;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -219,6 +241,7 @@
8781D24C18A19C340016F604 /* shoePreferencesWindowController.m in Sources */,
AE75B30918A8210D00E66DB6 /* shoeScreenWindow.m in Sources */,
8782FCE4189AFEFB0081E19E /* shoeApplication.m in Sources */,
870A2F9E192D2A6D00ABBC14 /* shoeScreenWindowController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -256,9 +279,11 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_ARC = NO;
CLANG_LINK_OBJC_RUNTIME = NO;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
@ -284,8 +309,9 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
ONLY_ACTIVE_ARCH = NO;
SDKROOT = macosx10.8;
VALID_ARCHS = "x86_64 i386";
};
name = Debug;
};
@ -293,9 +319,11 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_ARC = NO;
CLANG_LINK_OBJC_RUNTIME = NO;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
@ -316,15 +344,19 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8;
SDKROOT = macosx;
SDKROOT = macosx10.8;
VALID_ARCHS = "x86_64 i386";
};
name = Release;
};
87F9775A18987700000D589E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_OBJC_ARC = NO;
COMBINE_HIDPI_IMAGES = YES;
GCC_FAST_OBJC_DISPATCH = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Shoebill/Shoebill-Prefix.pch";
INFOPLIST_FILE = "Shoebill/Shoebill-Info.plist";
@ -332,7 +364,9 @@
"$(inherited)",
../intermediates,
);
ONLY_ACTIVE_ARCH = NO;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx10.8;
WRAPPER_EXTENSION = app;
};
name = Debug;
@ -340,8 +374,11 @@
87F9775B18987700000D589E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_OBJC_ARC = NO;
COMBINE_HIDPI_IMAGES = YES;
GCC_FAST_OBJC_DISPATCH = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Shoebill/Shoebill-Prefix.pch";
INFOPLIST_FILE = "Shoebill/Shoebill-Info.plist";
@ -350,6 +387,7 @@
../intermediates,
);
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx10.8;
WRAPPER_EXTENSION = app;
};
name = Release;

View File

@ -1,13 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="4514" systemVersion="13B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13C1021" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment defaultVersion="1080" identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="4514"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="shoeApplication">
<connections>
<outlet property="delegate" destination="494" id="495"/>
<outlet property="run_stop_menu_item" destination="82" id="kWm-r3-myc"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
@ -185,4 +186,4 @@
<customObject id="420" customClass="NSFontManager"/>
<customObject id="VMD-IW-vcf" userLabel="Preferences" customClass="shoePreferencesWindowController"/>
</objects>
</document>
</document>

View File

@ -2,12 +2,12 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2013-2015 Peter Rutenbar</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>org.shoebill.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
@ -16,10 +16,12 @@
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleVersion</key>
<string>0.0.1</string>
<key>CFBundleShortVersionString</key>
<string>0.0.5</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.0.5</string>
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSMainNibFile</key>

View File

@ -1,13 +1,12 @@
{\rtf1\ansi\ansicpg1252\cocoartf1265
{\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\vieww9600\viewh8400\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\qc
\f0\b\fs24 \cf0 Shoebill
\b0 \
A Macintosh II emulator that runs A/UX\
\
{\field{\*\fldinst{HYPERLINK "https://github.com/pruten/shoebill"}}{\fldrslt https://github.com/pruten/shoebill}}\
\
Peter Rutenbar (pruten@gmail.com)}
}

View File

@ -24,7 +24,8 @@
*/
#import "shoeAppDelegate.h"
#import "shoeApplication.h"
#import "shoePreferencesWindowController.h"
@implementation shoeAppDelegate
@ -33,13 +34,14 @@
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
uint32_t i;
[defaults setObject:@"" forKey:@"kernelPath"];
[((shoeApplication*)NSApp) zapPram:defaults ptr:nil];
[defaults setObject:@"/unix" forKey:@"rootKernelPath"];
[defaults setObject:@"" forKey:@"romPath"];
[defaults setInteger:NSOffState forKey:@"verboseState"];
[defaults setInteger:NSOnState forKey:@"verboseState"];
[defaults setInteger:16 forKey:@"memorySize"];
[defaults setInteger:640 forKey:@"screenWidth"];
[defaults setInteger:480 forKey:@"screenHeight"];
// [defaults setInteger:640 forKey:@"screenWidth"];
// [defaults setInteger:480 forKey:@"screenHeight"];
for (i=0; i<7; i++)
[defaults setObject:@"" forKey:[NSString stringWithFormat:@"scsiPath%u", i]];
@ -49,12 +51,41 @@
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
uint32_t i;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL isInitialized = [defaults boolForKey:@"defaultsInitialized"];
if (!isInitialized)
[self createFirstTimeUserDefaults];
// < 0.0.2 leaves rootKernelPath uninitialized
if ([defaults objectForKey:@"rootKernelPath"] == nil)
[defaults setObject:@"/unix" forKey:@"rootKernelPath"];
// < 0.0.3 leaves pramData uninitialized
if ([defaults objectForKey:@"pramData"] == nil)
[((shoeApplication*)NSApp) zapPram:defaults ptr:nil];
// < 0.0.5 leaves ethernet settings uninitialized
if ([defaults objectForKey:@"tapPathE"] == nil) {
uint8_t mac[6];
generateMACAddr(mac);
[defaults setObject:[NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]]
forKey:@"macAddressE"];
[defaults setObject:@"/dev/tap0" forKey:@"tapPathE"];
[defaults setInteger:0 forKey:@"ethernetEnabledE"];
for (i=0; i<4; i++) {
[defaults setInteger:640 forKey:[NSString stringWithFormat:@"screenWidth%u", i]];
[defaults setInteger:480 forKey:[NSString stringWithFormat:@"screenHeight%u", i]];
[defaults setInteger:0 forKey:[NSString stringWithFormat:@"screenEnabled%u", i]];
}
[defaults setInteger:1 forKey:@"screenEnabled0"];
}
[defaults synchronize];
}

View File

@ -24,19 +24,39 @@
*/
#import <Cocoa/Cocoa.h>
#include "../../core/core_api.h"
#include "../../core/redblack.h"
#import "shoeScreenWindowController.h"
#include "../../core/shoebill.h"
struct shoe_app_pram_data_t
{
uint8_t pram[256];
volatile _Bool updated;
};
@interface shoeApplication : NSApplication {
rb_tree *keymap;
NSWindowController *windowController[16];
shoeScreenWindowController *windowController[16];
IBOutlet __weak NSMenuItem *run_stop_menu_item;
NSTimer *pram_flush_timer;
struct shoe_app_pram_data_t *pram;
@public
BOOL doCaptureMouse, doCaptureKeys;
BOOL isRunning;
shoebill_control_t control;
shoebill_config_t config;
char *tapPath;
uint8_t mac[6];
int tap_fd;
BOOL ethEnabled, tap_fd_valid;
struct {
uint16_t height, width, enabled;
} screens[4];
}
- (void) startEmulator;
- (void) startEmulator;
- (void) zapPram:(NSUserDefaults*)defaults ptr:(uint8_t*)ptr;
@end

View File

@ -25,20 +25,23 @@
#import "shoeApplication.h"
#import "shoeScreenWindow.h"
#import "shoeScreenWindowController.h"
#import "shoePreferencesWindowController.h"
#include <ctype.h>
@implementation shoeApplication
#define mapkeymod(u, a, m) do { \
assert((a >> 7) == 0); \
void *value = (void*)(((m) << 8)| (a)); \
rb_insert(keymap, u, value, NULL); \
uint16_t value = ((m) << 8)| (a); \
rb_insert(keymap, u, &value, NULL); \
} while (0) \
#define mapkey(_u, a) mapkeymod(_u, a, 0)
- (void)initKeyboardMap
{
keymap = rb_new();
keymap = rb_new(p_new_pool(NULL), sizeof(uint16_t));
// Letters
mapkey('a', 0x00);
@ -176,13 +179,12 @@
NSString *chars = [[event charactersIgnoringModifiers] lowercaseString];
NSUInteger modifierFlags = [event modifierFlags];
unichar c = [chars characterAtIndex:0];
void *_value;
uint16_t value;
if (keymap == NULL)
[self initKeyboardMap];
if (rb_find(keymap, c, &_value)) {
uint16_t value = (uint16_t)_value;
if (rb_find(keymap, c, &value)) {
shoebill_key_modifier((value >> 8) | (modifierFlags >> 16));
shoebill_key((type == NSKeyDown), value & 0xff);
@ -214,17 +216,18 @@
}
- (BOOL) fetchUserDefaults:(uint16_t*)height width:(uint16_t*)width
- (BOOL) fetchUserDefaults
{
uint32_t i;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *kernelPathStr = [defaults objectForKey:@"kernelPath"];
NSString *rootKernelPathStr = [defaults objectForKey:@"rootKernelPath"];
NSString *romPathStr = [defaults objectForKey:@"romPath"];
NSInteger verboseState = [defaults integerForKey:@"verboseState"];
NSInteger memsize = [defaults integerForKey:@"memorySize"];
NSData *pramData = [defaults objectForKey:@"pramData"];
if (kernelPathStr == Nil || [kernelPathStr length]==0) {
if (rootKernelPathStr == Nil || [rootKernelPathStr length]==0) {
[self complain:@"Kernel path invalid!"];
return NO;
}
@ -237,37 +240,69 @@
if ((memsize < 1) || (memsize > 1024))
memsize = 8;
NSInteger screenHeightValue = [defaults integerForKey:@"screenHeight"];
NSInteger screenWidthValue = [defaults integerForKey:@"screenWidth"];
for (i=0; i<4; i++) {
NSInteger height = [defaults integerForKey:[NSString stringWithFormat:@"screenHeight%u", i]];
NSInteger width = [defaults integerForKey:[NSString stringWithFormat:@"screenWidth%u", i]];
NSInteger enabled = [defaults integerForKey:[NSString stringWithFormat:@"screenEnabled%u", i]];
if ((screenHeightValue < 342) || (screenHeightValue > 0xffff))
screenHeightValue = 480;
if ((screenWidthValue < 512) || (screenWidthValue > 0xffff))
screenWidthValue = 640;
if ((height < 342) || (height > 0xffff))
height = 480;
if ((width < 512) || (width > 0xffff))
width = 640;
screens[i].width = (uint16_t)width;
screens[i].height = (uint16_t)height;
screens[i].enabled = (uint16_t)enabled;
}
for (i=0; i<7; i++) {
NSString *str = [defaults objectForKey:[NSString stringWithFormat:@"scsiPath%u", i]];
if (str == nil || [str length] == 0)
control.scsi_devices[i].path = NULL;
config.scsi_devices[i].path = NULL;
else
control.scsi_devices[i].path = strdup([str UTF8String]);
config.scsi_devices[i].path = strdup([str UTF8String]);
}
char *kernelPathCString = strdup([kernelPathStr UTF8String]);
char *rootKernelPathCString = strdup([rootKernelPathStr UTF8String]);
char *romPathCString = strdup([romPathStr UTF8String]);
// FIXME: I'm leaking these strings. Stop leaking stuff when the UI is more finalized
config.aux_verbose = (verboseState == NSOnState);
config.ram_size = (uint32_t)memsize * 1024 * 1024;
config.aux_kernel_path = rootKernelPathCString;
config.rom_path = romPathCString;
config.debug_mode = 0;
control.aux_verbose = (verboseState == NSOnState);
control.ram_size = (uint32_t)memsize * 1024 * 1024;
control.aux_kernel_path = kernelPathCString;
control.rom_path = romPathCString;
[pramData getBytes:config.pram length:256];
*width = screenWidthValue;
*height = screenHeightValue;
/*
* If the pram is corrupt, zap it.
* A/UX will apparently never zap corrupted pram,
* probably because it expects the bootloader/MacOS to do it.
*/
if (memcmp(config.pram+0xc, "NuMc", 4) != 0)
[self zapPram:defaults ptr:config.pram];
NSString *defaultTapPath = [defaults objectForKey:@"tapPathE"];
NSString *defaultMacAddr = [defaults objectForKey:@"macAddressE"];
ethEnabled = [defaults integerForKey:@"ethernetEnabledE"];
if (ethEnabled) {
if (tap_fd_valid && strcmp(tapPath, [defaultTapPath UTF8String]) != 0) {
close(tap_fd);
tap_fd_valid = 0;
}
if (tapPath)
free(tapPath);
tapPath = strdup([defaultTapPath UTF8String]);
if (!(parseMACAddr([defaultMacAddr UTF8String], mac))) {
[self complain:@"Bad MAC addr"];
ethEnabled = 0;
return NO;
}
}
return YES;
}
@ -275,17 +310,59 @@
- (void) createScreenWindow:(uint8_t)slotnum
height:(uint16_t)height
width:(uint16_t)width
refresh_freq:(double)refresh_freq
{
shoebill_install_video_card(&control,
shoebill_install_video_card(&config,
slotnum,
width,
height,
refresh_freq);
height);
windowController[slotnum] = [[NSWindowController alloc] initWithWindowNibName:@"shoeScreenView"];
shoeScreenWindow *win = (shoeScreenWindow*)windowController[slotnum].window;
[win configure:slotnum];
windowController[slotnum] = [[shoeScreenWindowController alloc]
initWithWindowNibName:@"shoeScreenView"
slotnum:slotnum];
}
- (void) zapPram:(NSUserDefaults*)defaults ptr:(uint8_t*)ptr
{
uint8_t init[256];
shoebill_validate_or_zap_pram(init, 1);
if (ptr)
memcpy(ptr, init, 256);
NSData *data = [NSData dataWithBytes:init length:256];
[defaults setObject:data forKey:@"pramData"];
[defaults synchronize];
assert("zapPram" && (memcmp(init+0xc, "NuMc", 4) == 0));
}
void pram_callback (void *param, const uint8_t addr, const uint8_t byte)
{
struct shoe_app_pram_data_t *pram = (struct shoe_app_pram_data_t*)param;
pram->pram[addr] = byte;
pram->updated = 1;
//printf("pram_callback: set pram[0x%x] = 0x%02x (%c)\n", addr, byte, isprint(byte)?byte:'.');
}
- (void) flushPram
{
uint8_t copy[256];
if (pram->updated) {
pram->updated = 0;
memcpy(copy, pram->pram, 256);
NSData* data = [NSData dataWithBytes:copy length:256];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:data forKey:@"pramData"];
[defaults synchronize];
}
}
- (void) pramFlushTimerFired:(NSTimer *)timer
{
[self flushPram];
}
- (void) startEmulator
@ -293,36 +370,110 @@
if (isRunning)
return;
uint16_t width, height;
uint32_t i;
bzero(&control, sizeof(shoebill_control_t));
bzero(&config, sizeof(shoebill_config_t));
[self fetchUserDefaults:&height width:&width];
if (![self fetchUserDefaults])
return ;
uint32_t result = shoebill_initialize(&control);
self->pram = calloc(1, sizeof(struct shoe_app_pram_data_t));
memcpy(self->pram, config.pram, 256);
pram_flush_timer = [NSTimer
scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(pramFlushTimerFired:)
userInfo:nil
repeats:YES];
config.pram_callback = pram_callback;
config.pram_callback_param = (void*)self->pram;
uint32_t result = shoebill_initialize(&config);
if (!result) {
[self complain:[NSString stringWithFormat:@"%s", control.error_msg]];
[self complain:[NSString stringWithFormat:@"%s", config.error_msg]];
return ;
}
[self createScreenWindow:10 height:height width:width refresh_freq:200.0/3.0];
for (i=0; i<4; i++) {
if (screens[i].enabled)
[self createScreenWindow:(9+i) height:screens[i].height width:screens[i].width];
}
if (ethEnabled) {
if (!tap_fd_valid) {
tap_fd = open(tapPath, O_RDWR | O_NOFOLLOW);
if (tap_fd == -1) {
NSAlert *theAlert = [NSAlert
alertWithMessageText:nil
defaultButton:nil
alternateButton:nil
otherButton:nil
informativeTextWithFormat:@"Couldn't open tap device (errno = %d)", errno
];
[theAlert runModal];
return ;
}
tap_fd_valid = 1;
}
if (!shoebill_install_ethernet_card(&config, 13, mac, tap_fd)) {
[self complain:[NSString stringWithFormat:@"%s", config.error_msg]];
return ;
}
}
shoebill_start();
isRunning = true;
for (i=0; i<16; i++)
for (i=0; i<16; i++) {
if (windowController[i]) {
shoeScreenWindow *win = (shoeScreenWindow*)[windowController[i] window];
[win reevaluateKeyWindowness];
}
}
[run_stop_menu_item setTitle: @"Stop"];
[run_stop_menu_item setKeyEquivalent:@""];
}
- (void) stopEmulator
{
uint32_t i;
for (i=0; i<16; i++) {
if (windowController[i]) {
[windowController[i] close];
windowController[i] = NULL;
}
}
doCaptureKeys = false;
doCaptureMouse = false;
isRunning = false;
shoebill_stop();
[pram_flush_timer invalidate];
pram_flush_timer = nil;
[self flushPram];
free(self->pram);
if (config.aux_kernel_path)
free((void*)config.aux_kernel_path);
if (config.rom_path)
free((void*)config.rom_path);
[run_stop_menu_item setTitle: @"Run"];
[run_stop_menu_item setKeyEquivalent:@"r"];
}
- (IBAction)runMenuItem:(id)sender
{
[self startEmulator];
if (isRunning)
[self stopEmulator];
else
[self startEmulator];
}

View File

@ -27,10 +27,17 @@
@interface shoePreferencesWindowController : NSWindowController {
IBOutlet __weak NSButton *apply, *cancel, *applyAndRun, *verbose;
IBOutlet __weak NSButton *apply, *cancel, *applyAndRun, *verbose, *ethernetEnabled;
IBOutlet __weak NSTextField *kernelPath, *romPath, *memorySize;
IBOutlet __weak NSTextField *scsiPath0, *scsiPath1, *scsiPath2, *scsiPath3, *scsiPath4, *scsiPath5, *scsiPath6;
IBOutlet __weak NSTextField *screenHeight, *screenWidth;
IBOutlet __weak NSTextField *macAddress, *tapPath;
IBOutlet __weak NSTextField *screenHeight1, *screenWidth1;
IBOutlet __weak NSTextField *screenHeight2, *screenWidth2;
IBOutlet __weak NSTextField *screenHeight3, *screenWidth3;
IBOutlet __weak NSTextField *screenHeight4, *screenWidth4;
IBOutlet __weak NSButton *enableScreen1, *enableScreen2, *enableScreen3, *enableScreen4;
}
@ -40,3 +47,6 @@
- (IBAction)browsePressed:(id)sender;
@end
void generateMACAddr (uint8_t *mac);
_Bool parseMACAddr (const char *str, uint8_t *mac);

View File

@ -25,6 +25,7 @@
#import "shoePreferencesWindowController.h"
#import "shoeApplication.h"
#include <ctype.h>
@implementation shoePreferencesWindowController
@ -35,9 +36,17 @@
- (void)windowDidLoad
{
uint32_t i;
NSTextField *screenWidths[4] = {
screenWidth1, screenWidth2, screenWidth3, screenWidth4};
NSTextField *screenHeights[4] = {
screenHeight1, screenHeight2, screenHeight3, screenHeight4};
NSButton *screenEnableds[4] = {
enableScreen1, enableScreen2, enableScreen3, enableScreen4};
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *kernelPathStr = [defaults objectForKey:@"kernelPath"];
NSString *rootKernelPathStr = [defaults objectForKey:@"rootKernelPath"];
NSString *romPathStr = [defaults objectForKey:@"romPath"];
NSInteger verboseState = [defaults integerForKey:@"verboseState"];
NSInteger memsize = [defaults integerForKey:@"memorySize"];
@ -59,7 +68,7 @@
NSString *scsiPath6Str = [defaults objectForKey:@"scsiPath6"];
if (romPath) [romPath setStringValue:romPathStr];
if (kernelPath) [kernelPath setStringValue:kernelPathStr];
if (kernelPath) [kernelPath setStringValue:rootKernelPathStr];
[verbose setState:verboseState];
[memorySize setStringValue:[NSString stringWithFormat:@"%u", (uint32_t)memsize]];
@ -71,21 +80,28 @@
if (scsiPath5Str) [scsiPath5 setStringValue:scsiPath5Str];
if (scsiPath6Str) [scsiPath6 setStringValue:scsiPath6Str];
NSInteger screenHeightValue = [defaults integerForKey:@"screenHeight"];
NSInteger screenWidthValue = [defaults integerForKey:@"screenWidth"];
if ((screenHeightValue < 342) || (screenHeightValue > 0xffff)) {
screenHeightValue = 480;
[defaults setInteger:screenHeightValue forKey:@"screenHeight"];
for (i=0; i<4; i++) {
NSInteger height = [defaults integerForKey:[NSString stringWithFormat:@"screenHeight%u", i]];
NSInteger width = [defaults integerForKey:[NSString stringWithFormat:@"screenWidth%u", i]];
NSInteger enabled = [defaults integerForKey:[NSString stringWithFormat:@"screenEnabled%u", i]];
if ((height < 342) || (height > 0xffff))
height = 480;
if ((width < 342) || (width > 0xffff))
width = 640;
[screenHeights[i] setStringValue:[NSString stringWithFormat:@"%u", (uint32_t)height]];
[screenWidths[i] setStringValue:[NSString stringWithFormat:@"%u", (uint32_t)width]];
[screenEnableds[i] setState:enabled];
}
NSString *tapPathStr = [defaults objectForKey:@"tapPathE"];
NSString *macAddressStr = [defaults objectForKey:@"macAddressE"];
NSInteger ethernetEnabledState = [defaults integerForKey:@"ethernetEnabledE"];
if ((screenWidthValue < 512) || (screenWidthValue > 0xffff)) {
screenWidthValue = 640;
[defaults setInteger:screenWidthValue forKey:@"screenWidth"];
}
[screenWidth setStringValue:[NSString stringWithFormat:@"%u", (uint32_t)screenWidthValue]];
[screenHeight setStringValue:[NSString stringWithFormat:@"%u", (uint32_t)screenHeightValue]];
[tapPath setStringValue:tapPathStr];
[macAddress setStringValue:macAddressStr];
[ethernetEnabled setIntegerValue:ethernetEnabledState];
[defaults synchronize];
}
@ -105,16 +121,14 @@
if ([urls count] != 1)
return ;
NSURL *url = [urls firstObject];
NSURL *url = [urls objectAtIndex:0];
if (![url isFileURL])
return ;
NSString *buttonID = [sender identifier];
NSTextField *field;
if ([buttonID isEqualToString:@"kernelPathBrowse"])
field = kernelPath;
else if ([buttonID isEqualToString:@"romPathBrowse"])
if ([buttonID isEqualToString:@"romPathBrowse"])
field = romPath;
else if ([buttonID isEqualToString:@"scsiPath0Browse"])
field = scsiPath0;
@ -136,10 +150,29 @@
[field setStringValue: [url path]];
}
- (void) complain:(NSString*)str
{
NSAlert *theAlert = [NSAlert
alertWithMessageText:nil
defaultButton:nil
alternateButton:nil
otherButton:nil
informativeTextWithFormat:@"%@", str
];
[theAlert runModal];
}
- (IBAction)applyPressed:(id)sender
{
uint32_t i;
NSTextField *screenWidths[4] = {
screenWidth1, screenWidth2, screenWidth3, screenWidth4};
NSTextField *screenHeights[4] = {
screenHeight1, screenHeight2, screenHeight3, screenHeight4};
NSButton *screenEnableds[4] = {
enableScreen1, enableScreen2, enableScreen3, enableScreen4};
NSString *kernelPathStr = [kernelPath stringValue];
NSString *rootKernelPathStr = [kernelPath stringValue];
NSString *romPathStr = [romPath stringValue];
NSInteger verboseState = [verbose state];
NSInteger memsize = [memorySize integerValue];
@ -152,12 +185,22 @@
NSString *scsiPath5Str = [scsiPath5 stringValue];
NSString *scsiPath6Str = [scsiPath6 stringValue];
NSInteger screenHeightValue = [screenHeight integerValue];
NSInteger screenWidthValue = [screenWidth integerValue];
NSString *macAddressStr = [macAddress stringValue];
NSString *tapPathStr = [tapPath stringValue];
NSInteger ethernetEnabledState = [ethernetEnabled state];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:kernelPathStr forKey:@"kernelPath"];
uint8_t mac[6];
if (!parseMACAddr ([macAddressStr UTF8String], mac)) {
[self complain:@"Bad MAC address"];
}
else {
[macAddress setStringValue:[NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]]];
}
[defaults setObject:rootKernelPathStr forKey:@"rootKernelPath"];
[defaults setObject:romPathStr forKey:@"romPath"];
[defaults setInteger:verboseState forKey:@"verboseState"];
[defaults setInteger:memsize forKey:@"memorySize"];
@ -170,8 +213,24 @@
[defaults setObject:scsiPath5Str forKey:@"scsiPath5"];
[defaults setObject:scsiPath6Str forKey:@"scsiPath6"];
[defaults setInteger:screenHeightValue forKey:@"screenHeight"];
[defaults setInteger:screenWidthValue forKey:@"screenWidth"];
for (i=0; i<4; i++) {
NSInteger height = [screenHeights[i] integerValue];
NSInteger width = [screenWidths[i] integerValue];
NSInteger enabled = [screenEnableds[i] state];
if ((height < 342) || (height > 0xffff))
height = 480;
if ((width < 342) || (width > 0xffff))
width = 640;
[defaults setInteger:height forKey:[NSString stringWithFormat:@"screenHeight%u", i]];
[defaults setInteger:width forKey:[NSString stringWithFormat:@"screenWidth%u", i]];
[defaults setInteger:enabled forKey:[NSString stringWithFormat:@"screenEnabled%u", i]];
}
[defaults setObject:macAddressStr forKey:@"macAddressE"];
[defaults setObject:tapPathStr forKey:@"tapPathE"];
[defaults setInteger:ethernetEnabledState forKey:@"ethernetEnabledE"];
[defaults synchronize];
}
@ -188,4 +247,69 @@
[[self window] close];
}
-(IBAction)zapPramPressed:(id)sender
{
shoeApplication *shoeApp = (shoeApplication*) NSApp;
[shoeApp zapPram:[NSUserDefaults standardUserDefaults] ptr:nil];
}
void generateMACAddr (uint8_t *mac)
{
srandom((unsigned)(random() ^ time(NULL)));
/* Generate a MAC address in the range of the original EtherTalk card */
mac[0] = 0x02;
mac[1] = 0x60;
mac[2] = 0x8c;
mac[3] = random() & 0x07;
mac[4] = random() & 0xff;
mac[5] = random() & 0xff;
}
_Bool parseMACAddr (const char *str, uint8_t *mac)
{
uint32_t i, nibbles = 0;
uint8_t allowed[256];
memset(allowed, 30, 256);
for (i=0; i<256; i++)
if (isspace(i))
allowed[i] = 20;
allowed[':'] = 20;
allowed['-'] = 20;
for (i=0; i<10; i++)
allowed['0' + i] = i;
for (i=0; i<6; i++) {
allowed['a' + i] = 10 + i;
allowed['A' + i] = 10 + i;
}
for (i=0; str[i]; i++) {
const uint8_t v = allowed[str[i]];
if (v == 30)
return 0;
else if (v == 20)
continue;
if (nibbles >= 12)
return 0;
mac[nibbles/2] <<= 4;
mac[nibbles/2] |= v;
nibbles++;
}
return (nibbles == 12);
}
-(IBAction)newMacAddrPressed:(id)sender
{
uint8_t mac[6];
generateMACAddr(mac);
[macAddress setStringValue:[NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]]];
}
@end

View File

@ -1,17 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="4514" systemVersion="13B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7706" systemVersion="14F27" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment defaultVersion="1080" identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="4514"/>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="7706"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="shoePreferencesWindowController">
<connections>
<outlet property="kernelPath" destination="ZXf-9X-ulR" id="fFe-5B-6dc"/>
<outlet property="enableScreen1" destination="JSa-Bw-xDM" id="3Vr-kl-5To"/>
<outlet property="enableScreen2" destination="QR4-Cc-AkE" id="An0-V4-7Gg"/>
<outlet property="enableScreen3" destination="C6X-Zw-psD" id="Ipx-9O-5jD"/>
<outlet property="enableScreen4" destination="isQ-0Q-gQ4" id="4rO-YL-FaT"/>
<outlet property="ethernetEnabled" destination="GCJ-G0-drE" id="urw-x8-B7H"/>
<outlet property="kernelPath" destination="zU0-5O-afD" id="Q3V-Ly-Y6B"/>
<outlet property="macAddress" destination="UAs-x7-p28" id="PTo-JO-bHU"/>
<outlet property="memorySize" destination="uvm-gd-pCd" id="zzI-jI-ZUW"/>
<outlet property="romPath" destination="LoN-Nd-9cy" id="R3k-vY-TPo"/>
<outlet property="screenHeight" destination="Wyt-jg-xmk" id="Sq6-IJ-xbQ"/>
<outlet property="screenWidth" destination="EMf-gC-m9T" id="xxW-Ji-t7R"/>
<outlet property="screenHeight1" destination="Wyt-jg-xmk" id="dCS-jW-MMh"/>
<outlet property="screenHeight2" destination="IPj-pY-K2b" id="cnW-fh-y05"/>
<outlet property="screenHeight3" destination="tqh-iM-5GM" id="sF2-HA-acz"/>
<outlet property="screenHeight4" destination="3aP-6m-As4" id="fsH-cL-DLg"/>
<outlet property="screenWidth1" destination="EMf-gC-m9T" id="GSA-cX-c70"/>
<outlet property="screenWidth2" destination="B2c-pG-rIH" id="1BQ-0g-PMw"/>
<outlet property="screenWidth3" destination="cQO-ri-LxM" id="fBQ-VU-X4L"/>
<outlet property="screenWidth4" destination="VvE-c8-mBx" id="acc-3d-WMa"/>
<outlet property="scsiPath0" destination="nhQ-gw-2di" id="Ayi-Wk-Nhf"/>
<outlet property="scsiPath1" destination="8th-va-hXP" id="xTk-Kd-9v2"/>
<outlet property="scsiPath2" destination="RTT-NZ-Tte" id="w7D-05-cvN"/>
@ -19,72 +31,41 @@
<outlet property="scsiPath4" destination="Biz-iI-IiP" id="gbh-Jl-dxV"/>
<outlet property="scsiPath5" destination="GE2-3P-G1I" id="ohD-Fj-EX9"/>
<outlet property="scsiPath6" destination="cy8-jg-woV" id="QoH-Z0-e8d"/>
<outlet property="verbose" destination="RnS-Yp-G7M" id="VjB-1f-ejM"/>
<outlet property="tapPath" destination="Wvc-cC-QWO" id="kuK-DA-ui3"/>
<outlet property="verbose" destination="fkL-RE-iRz" id="uba-U2-Zkh"/>
<outlet property="window" destination="rKy-wc-8AE" id="sYz-fH-ohd"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application"/>
<window title="Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" wantsToBeColor="NO" visibleAtLaunch="NO" animationBehavior="default" id="rKy-wc-8AE">
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="rKy-wc-8AE">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="498" height="433"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<view key="contentView" id="4Fm-p8-6h9">
<rect key="frame" x="0.0" y="0.0" width="498" height="433"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<tabView fixedFrame="YES" drawsBackground="NO" initialItem="Ffn-1Z-2rp" translatesAutoresizingMaskIntoConstraints="NO" id="i29-bb-k7Y">
<rect key="frame" x="13" y="33" width="472" height="394"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<font key="font" metaFont="system"/>
<tabViewItems>
<tabViewItem label="General" identifier="1" id="Ffn-1Z-2rp">
<view key="view" ambiguous="YES" id="BF8-Dm-rF5">
<view key="view" id="BF8-Dm-rF5">
<rect key="frame" x="10" y="33" width="452" height="348"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Nqd-aN-fI5">
<rect key="frame" x="12" y="311" width="81" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="Kernel Path:" usesSingleLineMode="YES" id="i7G-KP-OrH">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oVj-nA-5GP">
<rect key="frame" x="12" y="264" width="81" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<rect key="frame" x="11" y="314" width="81" height="17"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="Rom Path:" usesSingleLineMode="YES" id="7qD-i1-FXI">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<button identifier="kernelPathBrowse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="Dep-2G-fPK">
<rect key="frame" x="359" y="300" width="97" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Dnb-hA-OHJ">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="browsePressed:" target="-2" id="hW9-m5-Ovo"/>
</connections>
</button>
<textField identifier="kernelPath" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZXf-9X-ulR">
<rect key="frame" x="99" y="289" width="258" height="39"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="unix" drawsBackground="YES" id="gUb-0H-eoA">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button identifier="romPathBrowse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="fjl-Jg-nIF">
<rect key="frame" x="359" y="253" width="97" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<rect key="frame" x="358" y="303" width="97" height="32"/>
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="ITb-nX-hmP">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -94,8 +75,7 @@
</connections>
</button>
<textField identifier="romPath" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LoN-Nd-9cy">
<rect key="frame" x="99" y="242" width="258" height="39"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<rect key="frame" x="98" y="292" width="258" height="39"/>
<textFieldCell key="cell" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="macii.rom" drawsBackground="YES" id="IvC-yQ-qdn">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
@ -103,8 +83,7 @@
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RDI-wU-bdg">
<rect key="frame" x="3" y="217" width="90" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<rect key="frame" x="2" y="267" width="90" height="17"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="Memory (MB):" usesSingleLineMode="YES" id="8mu-le-9YC">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -112,26 +91,74 @@
</textFieldCell>
</textField>
<textField identifier="memorySize" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uvm-gd-pCd">
<rect key="frame" x="99" y="212" width="42" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<rect key="frame" x="98" y="262" width="42" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="8" placeholderString="8" drawsBackground="YES" id="I5v-kb-eCo">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fNZ-zo-4uj">
<rect key="frame" x="7" y="10" width="103" height="32"/>
<buttonCell key="cell" type="push" title="Zap PRAM" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="EGV-fk-y4d">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="zapPramPressed:" target="-2" id="9N7-dY-Fl6"/>
</connections>
</button>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0nJ-ho-P1P">
<rect key="frame" x="11" y="235" width="81" height="17"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="Kernel Path:" usesSingleLineMode="YES" id="Wdx-2C-yGA">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<textField identifier="kernelPath" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zU0-5O-afD">
<rect key="frame" x="98" y="232" width="325" height="22"/>
<string key="toolTip">The path to the kernel on the root image. If you don't know what this is, just use "/unix" (Note: the root image needs to be at SCSI ID 0)</string>
<textFieldCell key="cell" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="/unix" drawsBackground="YES" id="0MQ-1P-9gJ">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button identifier="verbose" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fkL-RE-iRz">
<rect key="frame" x="283" y="18" width="142" height="18"/>
<string key="toolTip">Verbose mode causes A/UX to print diagnostic info during boot, and it will also run fsck to repair the root filesystem if necessary.</string>
<buttonCell key="cell" type="check" title="A/UX Verbose Boot" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="htQ-zH-VRv">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
</view>
</tabViewItem>
<tabViewItem label="Screens" identifier="" id="3o8-Ma-LAk">
<view key="view" id="Zdy-ik-svz">
<rect key="frame" x="10" y="33" width="452" height="348"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tgt-1x-QT0">
<rect key="frame" x="3" y="160" width="90" height="42"/>
<autoresizingMask key="autoresizingMask"/>
<rect key="frame" x="186" y="312" width="125" height="17"/>
<textFieldCell key="cell" allowsUndo="NO" alignment="right" title="Screen Resolution:" id="9bl-WA-bhb">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ld1-xq-pdG">
<rect key="frame" x="186" y="287" width="47" height="17"/>
<textFieldCell key="cell" allowsUndo="NO" alignment="right" title="Width" id="QBW-rk-c7E">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JNe-0k-g4e">
<rect key="frame" x="147" y="174" width="14" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<rect key="frame" x="241" y="259" width="14" height="17"/>
<textFieldCell key="cell" allowsUndo="NO" alignment="center" title="x" id="9cf-Xq-tuu">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -139,36 +166,161 @@
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="aSg-xG-o1t">
<rect key="frame" x="224" y="173" width="59" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<rect key="frame" x="317" y="259" width="59" height="17"/>
<textFieldCell key="cell" allowsUndo="NO" alignment="left" title="pixels" id="D5V-Zm-Grd">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<textField identifier="memorySize" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="EMf-gC-m9T">
<rect key="frame" x="99" y="170" width="43" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textField identifier="width1" toolTip="width" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="EMf-gC-m9T">
<rect key="frame" x="192" y="256" width="43" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="width" placeholderString="width" drawsBackground="YES" id="sbq-WW-C05">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField identifier="memorySize" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Wyt-jg-xmk">
<rect key="frame" x="169" y="170" width="49" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textField identifier="height1" toolTip="height" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Wyt-jg-xmk">
<rect key="frame" x="262" y="256" width="49" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="height" placeholderString="height" drawsBackground="YES" id="qvE-Bk-NDl">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button identifier="verbose" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RnS-Yp-G7M">
<rect key="frame" x="295" y="210" width="142" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="A/UX Verbose Boot" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Ww6-qg-dn1">
<button identifier="verbose" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JSa-Bw-xDM">
<rect key="frame" x="57" y="258" width="129" height="18"/>
<string key="toolTip">Verbose mode causes A/UX to print diagnostic info during boot, and it will also run fsck to repair the root filesystem if necessary.</string>
<buttonCell key="cell" type="check" title="Enable Screen 1" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="azN-j2-txA">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<button identifier="verbose" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="QR4-Cc-AkE">
<rect key="frame" x="57" y="228" width="129" height="18"/>
<string key="toolTip">Verbose mode causes A/UX to print diagnostic info during boot, and it will also run fsck to repair the root filesystem if necessary.</string>
<buttonCell key="cell" type="check" title="Enable Screen 2" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Zqf-mb-br4">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<button identifier="verbose" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="C6X-Zw-psD">
<rect key="frame" x="57" y="198" width="129" height="18"/>
<string key="toolTip">Verbose mode causes A/UX to print diagnostic info during boot, and it will also run fsck to repair the root filesystem if necessary.</string>
<buttonCell key="cell" type="check" title="Enable Screen 3" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Cfv-ZG-aBO">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="G8E-Jw-aPd">
<rect key="frame" x="241" y="229" width="14" height="17"/>
<textFieldCell key="cell" allowsUndo="NO" alignment="center" title="x" id="1RP-Cp-YFY">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8hd-at-UXU">
<rect key="frame" x="317" y="229" width="59" height="17"/>
<textFieldCell key="cell" allowsUndo="NO" alignment="left" title="pixels" id="2DF-kS-r5B">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<textField identifier="width2" toolTip="width" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="B2c-pG-rIH">
<rect key="frame" x="192" y="226" width="43" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="width" placeholderString="width" drawsBackground="YES" id="DMe-fk-aJx">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField identifier="height2" toolTip="height" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="IPj-pY-K2b">
<rect key="frame" x="262" y="226" width="49" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="height" placeholderString="height" drawsBackground="YES" id="3F9-jB-hfl">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uAk-QS-Kpu">
<rect key="frame" x="241" y="199" width="14" height="17"/>
<textFieldCell key="cell" allowsUndo="NO" alignment="center" title="x" id="XrI-eJ-Xmq">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="a0D-DN-Abg">
<rect key="frame" x="317" y="199" width="59" height="17"/>
<textFieldCell key="cell" allowsUndo="NO" alignment="left" title="pixels" id="V3B-61-meh">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<textField identifier="width3" toolTip="width" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cQO-ri-LxM">
<rect key="frame" x="192" y="196" width="43" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="width" placeholderString="width" drawsBackground="YES" id="5Rx-30-P1a">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField identifier="height3" toolTip="height" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tqh-iM-5GM">
<rect key="frame" x="262" y="196" width="49" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="height" placeholderString="height" drawsBackground="YES" id="PdC-tw-Mou">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="WMg-rd-urO">
<rect key="frame" x="241" y="169" width="14" height="17"/>
<textFieldCell key="cell" allowsUndo="NO" alignment="center" title="x" id="r21-SX-0ht">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="NDL-uY-GIk">
<rect key="frame" x="317" y="169" width="59" height="17"/>
<textFieldCell key="cell" allowsUndo="NO" alignment="left" title="pixels" id="gKj-k6-3XK">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<textField identifier="width4" toolTip="width" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VvE-c8-mBx">
<rect key="frame" x="192" y="166" width="43" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="width" placeholderString="width" drawsBackground="YES" id="rfI-7T-Vc2">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField identifier="height4" toolTip="height" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3aP-6m-As4">
<rect key="frame" x="262" y="166" width="49" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="height" placeholderString="height" drawsBackground="YES" id="56I-cY-cml">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bgh-Ds-kMn">
<rect key="frame" x="260" y="287" width="47" height="17"/>
<textFieldCell key="cell" allowsUndo="NO" alignment="right" title="Height" id="Ato-zm-vpN">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<button identifier="verbose" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="isQ-0Q-gQ4">
<rect key="frame" x="57" y="168" width="129" height="18"/>
<string key="toolTip">Verbose mode causes A/UX to print diagnostic info during boot, and it will also run fsck to repair the root filesystem if necessary.</string>
<buttonCell key="cell" type="check" title="Enable Screen 4" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="dNj-R0-mIT">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
@ -183,7 +335,6 @@
<subviews>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dA0-AE-SsA">
<rect key="frame" x="1" y="321" width="72" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 0" usesSingleLineMode="YES" id="YYd-8o-kqe">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -192,7 +343,6 @@
</textField>
<button identifier="scsiPath0Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="BUV-3F-sRD">
<rect key="frame" x="353" y="310" width="97" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Ekq-OL-WH9">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -203,7 +353,6 @@
</button>
<textField identifier="scsiPath0" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="nhQ-gw-2di">
<rect key="frame" x="79" y="299" width="272" height="39"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="4NZ-tu-sNu">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
@ -212,7 +361,6 @@
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Gjz-Nn-CkC">
<rect key="frame" x="1" y="274" width="72" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 1" usesSingleLineMode="YES" id="oPB-iw-Fuy">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -221,7 +369,6 @@
</textField>
<button identifier="scsiPath1Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="0OE-Ny-sRU">
<rect key="frame" x="353" y="263" width="97" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="iRT-nY-bQx">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -232,7 +379,6 @@
</button>
<textField identifier="scsiPath1" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8th-va-hXP">
<rect key="frame" x="79" y="252" width="272" height="39"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="wM4-Hu-6dD">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
@ -241,7 +387,6 @@
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="17i-H8-woP">
<rect key="frame" x="1" y="227" width="72" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 2" usesSingleLineMode="YES" id="rWu-qs-tIH">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -250,7 +395,6 @@
</textField>
<button identifier="scsiPath2Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="OS6-vm-18P">
<rect key="frame" x="353" y="216" width="97" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="ojq-kT-7Hz">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -261,7 +405,6 @@
</button>
<textField identifier="scsiPath2" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RTT-NZ-Tte">
<rect key="frame" x="79" y="205" width="272" height="39"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="bx9-L2-52p">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
@ -270,7 +413,6 @@
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zeV-Os-yjZ">
<rect key="frame" x="1" y="180" width="72" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 3" usesSingleLineMode="YES" id="4Ir-Qy-6TG">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -279,7 +421,6 @@
</textField>
<button identifier="scsiPath3Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="hyG-x9-NBA">
<rect key="frame" x="353" y="169" width="97" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Toc-PB-8FO">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -290,7 +431,6 @@
</button>
<textField identifier="scsiPath3" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pKG-3S-zID">
<rect key="frame" x="79" y="158" width="272" height="39"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="Ksz-dn-t4g">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
@ -299,7 +439,6 @@
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Rpv-lh-1BC">
<rect key="frame" x="1" y="133" width="72" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 4" usesSingleLineMode="YES" id="RSB-J8-WHv">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -308,7 +447,6 @@
</textField>
<button identifier="scsiPath4Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="FUw-LT-FRg">
<rect key="frame" x="353" y="122" width="97" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="CDZ-hc-2Kz">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -319,7 +457,6 @@
</button>
<textField identifier="scsiPath4" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Biz-iI-IiP">
<rect key="frame" x="79" y="111" width="272" height="39"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="j2E-vU-3LZ">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
@ -328,7 +465,6 @@
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="eGO-wX-v7I">
<rect key="frame" x="1" y="86" width="72" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 5" usesSingleLineMode="YES" id="lVw-XZ-DkQ">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -337,7 +473,6 @@
</textField>
<button identifier="scsiPath5Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="Ur1-2a-9nV">
<rect key="frame" x="353" y="75" width="97" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="QW3-hO-eDz">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -348,7 +483,6 @@
</button>
<textField identifier="scsiPath5" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GE2-3P-G1I">
<rect key="frame" x="79" y="64" width="272" height="39"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="BrK-XM-gcx">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
@ -357,7 +491,6 @@
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="c4H-Kt-ANK">
<rect key="frame" x="1" y="39" width="72" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="SCSI ID 6" usesSingleLineMode="YES" id="NS8-2m-U2B">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -366,7 +499,6 @@
</textField>
<button identifier="scsiPath6Browse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="Twn-Yd-cyf">
<rect key="frame" x="353" y="28" width="97" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Browse..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="JNl-qq-v8p">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -377,7 +509,6 @@
</button>
<textField identifier="scsiPath6" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cy8-jg-woV">
<rect key="frame" x="79" y="17" width="272" height="39"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" truncatesLastVisibleLine="YES" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="None" drawsBackground="YES" id="gZa-0y-cOt">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
@ -387,11 +518,67 @@
</subviews>
</view>
</tabViewItem>
<tabViewItem label="Ethernet" identifier="" id="npc-ti-4lo">
<view key="view" id="2Hm-kn-wCU">
<rect key="frame" x="10" y="33" width="452" height="348"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oLm-yd-Ca2">
<rect key="frame" x="15" y="272" width="93" height="17"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="MAC Address:" usesSingleLineMode="YES" id="vve-T4-Rce">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<textField identifier="macAddress" toolTip="The MAC address of the emulated ethernet card" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="UAs-x7-p28">
<rect key="frame" x="114" y="269" width="160" height="22"/>
<textFieldCell key="cell" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="AA:AA:AA:AA:AA:AA" placeholderString="01:02:03:04:05:06" drawsBackground="YES" id="2is-7Y-0d2">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vp5-0F-Hl5">
<rect key="frame" x="30" y="302" width="78" height="17"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="TAP Device:" usesSingleLineMode="YES" id="QWi-Fs-xtO">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</textFieldCell>
</textField>
<textField identifier="tapPath" toolTip="The path to the TAP device (/dev/tap0 should be fine)" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Wvc-cC-QWO">
<rect key="frame" x="114" y="299" width="313" height="22"/>
<textFieldCell key="cell" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="/dev/tap0" placeholderString="/dev/tap0" drawsBackground="YES" id="Sb8-nl-Q5r">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button toolTip="Generate a new MAC address" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gZ8-0N-f6V">
<rect key="frame" x="276" y="263" width="157" height="32"/>
<buttonCell key="cell" type="push" title="New MAC Address" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="04X-Ao-SYd">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="newMacAddrPressed:" target="-2" id="Lgm-OH-3ff"/>
</connections>
</button>
<button identifier="enableEthernet" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GCJ-G0-drE">
<rect key="frame" x="15" y="218" width="142" height="18"/>
<buttonCell key="cell" type="check" title="Enable Ethernet" bezelStyle="regularSquare" imagePosition="left" inset="2" id="03F-wY-3oH">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
</view>
</tabViewItem>
</tabViewItems>
</tabView>
<button identifier="applyAndRun" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="r8k-B7-iXM">
<rect key="frame" x="352" y="5" width="132" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Apply and Run" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="oR1-x8-VgY">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -402,7 +589,6 @@
</button>
<button identifier="cancel" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T6y-kh-jgH">
<rect key="frame" x="188" y="5" width="82" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Sk4-hr-Ot6">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -416,7 +602,6 @@ Gw
</button>
<button identifier="apply" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZDd-0H-a3B">
<rect key="frame" x="270" y="5" width="82" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Apply" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="bC6-3u-5Op">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -435,4 +620,4 @@ Gw
</connections>
</window>
</objects>
</document>
</document>

View File

@ -31,7 +31,6 @@
@interface shoeScreenView : NSOpenGLView {
CGColorSpaceRef colorspace;
shoebill_control_t *control;
NSTimer *timer;
NSRecursiveLock *lock;
CIContext *ciContext;

View File

@ -35,7 +35,6 @@
- (void)initCommon
{
shoeApp = (shoeApplication*) NSApp;
control = &shoeApp->control;
}
@ -73,20 +72,17 @@
colorspace = CGColorSpaceCreateDeviceRGB();
timer = [NSTimer
scheduledTimerWithTimeInterval:(0.015/2.0)
scheduledTimerWithTimeInterval:(1.0/60.0)
target:self
selector:@selector(timerFireMethod:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSEventTrackingRunLoopMode];
shoebill_card_video_t *video = &control->slots[10].card.video;
NSSize size = {
.height=video->height,
.width=video->width
};
[[self window] setContentSize:size];
[[self window] setTitle:[NSString stringWithFormat:@"Shoebill - Screen 1"]];
[[self window] setTitle:[NSString stringWithFormat:@"Shoebill"]];
[[self window] makeKeyAndOrderFront:nil];
}
@ -97,82 +93,35 @@
- (void)prepareOpenGL
{
NSRect frame = [self frame];
NSRect bounds = [self bounds];
GLfloat minX, minY, maxX, maxY;
minX = NSMinX(bounds);
minY = NSMinY(bounds);
maxX = NSMaxX(bounds);
maxY = NSMaxY(bounds);
//[self update];
if(NSIsEmptyRect([self visibleRect]))
{
glViewport(0, 0, 1, 1);
} else {
glViewport(0, 0, frame.size.width ,frame.size.height);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(minX, maxX, minY, maxY, -1.0, 1.0);
}
static void _do_clut_translation(shoebill_card_video_t *ctx)
{
uint32_t i;
switch (ctx->depth) {
case 1: {
for (i=0; i < ctx->pixels/8; i++) {
const uint8_t byte = ctx->indexed_buf[i];
ctx->direct_buf[i * 8 + 0] = ctx->clut[(byte >> 7) & 1];
ctx->direct_buf[i * 8 + 1] = ctx->clut[(byte >> 6) & 1];
ctx->direct_buf[i * 8 + 2] = ctx->clut[(byte >> 5) & 1];
ctx->direct_buf[i * 8 + 3] = ctx->clut[(byte >> 4) & 1];
ctx->direct_buf[i * 8 + 4] = ctx->clut[(byte >> 3) & 1];
ctx->direct_buf[i * 8 + 5] = ctx->clut[(byte >> 2) & 1];
ctx->direct_buf[i * 8 + 6] = ctx->clut[(byte >> 1) & 1];
ctx->direct_buf[i * 8 + 7] = ctx->clut[(byte >> 0) & 1];
}
break;
}
case 2: {
for (i=0; i < ctx->pixels/4; i++) {
const uint8_t byte = ctx->indexed_buf[i];
ctx->direct_buf[i * 4 + 0] = ctx->clut[(byte >> 6) & 3];
ctx->direct_buf[i * 4 + 1] = ctx->clut[(byte >> 4) & 3];
ctx->direct_buf[i * 4 + 2] = ctx->clut[(byte >> 2) & 3];
ctx->direct_buf[i * 4 + 3] = ctx->clut[(byte >> 0) & 3];
}
break;
}
case 4: {
for (i=0; i < ctx->pixels/2; i++) {
const uint8_t byte = ctx->indexed_buf[i];
ctx->direct_buf[i * 2 + 0] = ctx->clut[(byte >> 4) & 0xf];
ctx->direct_buf[i * 2 + 1] = ctx->clut[(byte >> 0) & 0xf];
}
break;
}
case 8:
for (i=0; i < ctx->pixels; i++)
ctx->direct_buf[i] = ctx->clut[ctx->indexed_buf[i]];
break;
default:
assert(!"unknown depth");
}
GLint swapInt = 1;
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
}
- (void)drawRect:(NSRect)rect
{
const uint8_t slotnum = ((shoeScreenWindowController*)[[self window] windowController])->slotnum;
[[self openGLContext] makeCurrentContext];
NSRect frame = [self frame];
NSRect bounds = [self bounds];
GLfloat minX = NSMinX(bounds);
GLfloat minY = NSMinY(bounds);
GLfloat maxX = NSMaxX(bounds);
GLfloat maxY = NSMaxY(bounds);
if(NSIsEmptyRect([self visibleRect]))
glViewport(0, 0, 1, 1);
else
glViewport(0, 0, frame.size.width ,frame.size.height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(minX, maxX, minY, maxY, -1.0, 1.0);
glDrawBuffer(GL_BACK);
glClear(GL_COLOR_BUFFER_BIT);
@ -180,23 +129,29 @@ static void _do_clut_translation(shoebill_card_video_t *ctx)
glClearColor(0.0, 0.0, 0.0, 0.0);
if (shoeApp->isRunning) {
shoebill_card_video_t *video = &control->slots[10].card.video;
_do_clut_translation(video);
glViewport(0, 0, video->width, video->height);
glRasterPos2i(0, video->height);
shoebill_video_frame_info_t frame = shoebill_get_video_frame(slotnum, 0);
glViewport(0, 0, frame.width, frame.height);
glRasterPos2i(0, frame.height);
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelZoom(1.0, -1.0);
glDrawPixels(video->width,
video->height,
glDrawPixels(frame.width,
frame.height,
GL_RGBA,
GL_UNSIGNED_BYTE,
video->direct_buf);
frame.buf);
[[self openGLContext] flushBuffer];
shoebill_send_vbl_interrupt(slotnum);
}
else {
[[self openGLContext] flushBuffer];
}
[[self openGLContext] flushBuffer];
}
- (void)viewDidMoveToWindow
@ -231,18 +186,6 @@ static void _do_clut_translation(shoebill_card_video_t *ctx)
[self mouseMoved:theEvent];
}
/*- (void) say:(NSString*)str
{
NSAlert *theAlert = [NSAlert
alertWithMessageText:nil
defaultButton:nil
alternateButton:nil
otherButton:nil
informativeTextWithFormat:@"%@", str
];
[theAlert runModal];
}*/
- (void)mouseDown:(NSEvent *)theEvent
{

View File

@ -1,19 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="4514" systemVersion="13B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13D65" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment defaultVersion="1080" identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="4514"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSWindowController">
<customObject id="-2" userLabel="File's Owner" customClass="shoeScreenWindowController">
<connections>
<outlet property="window" destination="1" id="aqm-Nb-PaF"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="shoeApplication"/>
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" wantsToBeColor="NO" visibleAtLaunch="NO" animationBehavior="default" id="1" customClass="shoeScreenWindow">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="1" customClass="shoeScreenWindow">
<windowStyleMask key="styleMask" titled="YES" miniaturizable="YES"/>
<windowCollectionBehavior key="collectionBehavior" fullScreenPrimary="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
@ -23,4 +24,4 @@
</view>
</window>
</objects>
</document>
</document>

View File

@ -28,10 +28,8 @@
@interface shoeScreenWindow : NSWindow {
@public
uint8_t slotnum;
}
- (void) configure:(uint8_t) _slotnum;
- (void) reevaluateKeyWindowness;
- (void) warpToCenter;
- (void) captureMouse;

View File

@ -29,10 +29,6 @@
@implementation shoeScreenWindow
- (void)configure:(uint8_t) _slotnum
{
slotnum = _slotnum;
}
// Called after all the shoeScreenWindows are created and configured,
// because one of them was already made key while isRunning==NO,
@ -40,7 +36,7 @@
- (void)reevaluateKeyWindowness
{
shoeApplication *shoeApp = (shoeApplication*)NSApp;
assert(shoeApp->isRunning);
if ([self isKeyWindow]) {
@ -52,6 +48,19 @@
}
}
- (void)toggleFullScreen:(id)sender
{
[super toggleFullScreen:sender];
const uint8_t slotnum = ((shoeScreenWindowController*)[self windowController])->slotnum;
shoebill_video_frame_info_t frame = shoebill_get_video_frame(slotnum, 1);
NSSize size = {
.height=frame.height,
.width=frame.width,
};
[self setContentSize:size];
}
- (void)becomeKeyWindow
{
shoeApplication *shoeApp = (shoeApplication*)NSApp;
@ -95,7 +104,7 @@
shoeApplication *shoeApp = (shoeApplication*)NSApp;
shoeApp->doCaptureMouse = NO;
CGDisplayShowCursor(0);
[self setTitle:@"Shoebill - Screen 1"];
[self setTitle:@"Shoebill"];
}
- (void) captureMouse
@ -104,7 +113,8 @@
shoeApp->doCaptureMouse = YES;
CGDisplayHideCursor(0);
[self warpToCenter];
[self setTitle:@"Shoebill - Screen 1 (Ctrl-click to escape)"];
[self setTitle:@"Shoebill (Ctrl-click to escape)"];
}
@end

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Peter Rutenbar <pruten@gmail.com>
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -23,28 +23,13 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _REDBLACK_H
#define _REDBLACK_H
#import <Cocoa/Cocoa.h>
typedef uint32_t rb_key_t;
typedef void* rb_value_t;
@interface shoeScreenWindowController : NSWindowController {
@public
uint8_t slotnum;
}
typedef struct _rb_node {
struct _rb_node *left, *right, *parent;
rb_key_t key;
rb_value_t value;
uint8_t is_red : 1;
} rb_node;
- (id)initWithWindowNibName:(NSString *)windowNibName slotnum:(uint8_t)_slotnum;
typedef rb_node* rb_tree;
rb_tree* rb_new();
void rb_free (rb_tree *tree);
uint8_t rb_insert (rb_tree *root, rb_key_t key, rb_value_t value, rb_value_t *old_value);
uint8_t rb_find (rb_tree *tree, rb_key_t key, rb_value_t *value);
uint8_t rb_index (rb_tree *tree, uint32_t index, rb_key_t *key, rb_value_t *value);
uint32_t rb_count (rb_tree *tree);
#endif // _REDBLACK_H
@end

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "shoeScreenWindowController.h"
#import "shoeApplication.h"
@interface shoeScreenWindowController ()
@end
@implementation shoeScreenWindowController
- (id)initWithWindowNibName:(NSString *)windowNibName
slotnum:(uint8_t)_slotnum
{
shoeScreenWindowController *result = [super initWithWindowNibName:windowNibName];
result->slotnum = _slotnum;
return result;
}
- (void)windowDidLoad
{
[super windowDidLoad];
shoebill_video_frame_info_t frame = shoebill_get_video_frame(slotnum, 1);
NSSize size = {
.height=frame.height,
.width=frame.width,
};
[[self window] setContentSize:size];
}
- (NSApplicationPresentationOptions)window:(NSWindow *)window
willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions
{
return (NSApplicationPresentationFullScreen | // support full screen for this window (required)
NSApplicationPresentationHideDock | // completely hide the dock
NSApplicationPresentationAutoHideMenuBar); // yes we want the menu bar to show/hide
}
- (NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize
{
shoebill_video_frame_info_t frame = shoebill_get_video_frame(slotnum, 1);
NSSize size = {
.height=frame.height,
.width=frame.width,
};
return size;
}
@end

22
sdl-gui/lin_build.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/bash
CC=gcc
files=""
for i in adb fpu mc68851 mem via floppy core_api cpu dis; do
perl ../core/macro.pl ../core/$i.c $i.post.c
files="$files $i.post.c"
done
for i in SoftFloat/softfloat atrap_tab coff exception macii_symbols redblack scsi video filesystem alloc_pool toby_frame_buffer ethernet sound; do
files="$files ../core/$i.c"
done
$CC -O1 ../core/decoder_gen.c -o decoder_gen
./decoder_gen inst .
./decoder_gen dis .
cmd="$CC -O3 -ggdb -flto $files sdl.c -lpthread -lm -lSDL2 -lGL -o shoebill"
echo $cmd
$cmd

22
sdl-gui/osx_build.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/bash
CC=gcc
files=""
for i in adb fpu mc68851 mem via floppy core_api cpu dis; do
perl ../core/macro.pl ../core/$i.c $i.post.c
files="$files $i.post.c"
done
for i in SoftFloat/softfloat atrap_tab coff exception macii_symbols redblack scsi video filesystem alloc_pool toby_frame_buffer ethernet sound; do
files="$files ../core/$i.c"
done
$CC -O1 ../core/decoder_gen.c -o decoder_gen
./decoder_gen inst .
./decoder_gen dis .
cmd="$CC -F/Library/Frameworks -O3 -ggdb -flto $files sdl.c -framework OpenGL -framework SDL2 -o shoebill"
echo $cmd
$cmd

635
sdl-gui/sdl.c Normal file
View File

@ -0,0 +1,635 @@
/*
* Copyright (c) 2014, Peter Rutenbar <pruten@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <stdio.h>
#include <assert.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include "../core/shoebill.h"
static void _print_vers(void)
{
printf("Shoebill v0.0.4 - http://github.com/pruten/shoebill - Peter Rutenbar (c) 2014\n\n");
}
rb_tree *keymap;
static void _init_keyboard_map (void)
{
#define mapkeymod(u, a, m) do { \
assert((a >> 7) == 0); \
uint16_t value = ((m) << 8)| (a); \
rb_insert(keymap, u, &value, NULL); \
} while (0)
#define mapkey(_u, a) mapkeymod(_u, a, 0)
keymap = rb_new(p_new_pool(NULL), sizeof(uint16_t));
// Letters
mapkey('a', 0x00);
mapkey('b', 0x0b);
mapkey('c', 0x08);
mapkey('d', 0x02);
mapkey('e', 0x0e);
mapkey('f', 0x03);
mapkey('g', 0x05);
mapkey('h', 0x04);
mapkey('i', 0x22);
mapkey('j', 0x26);
mapkey('k', 0x28);
mapkey('l', 0x25);
mapkey('m', 0x2e);
mapkey('n', 0x2d);
mapkey('o', 0x1f);
mapkey('p', 0x23);
mapkey('q', 0x0c);
mapkey('r', 0x0f);
mapkey('s', 0x01);
mapkey('t', 0x11);
mapkey('u', 0x20);
mapkey('v', 0x09);
mapkey('w', 0x0d);
mapkey('x', 0x07);
mapkey('y', 0x10);
mapkey('z', 0x06);
// Numbers
mapkey('0', 0x1d);
mapkey('1', 0x12);
mapkey('2', 0x13);
mapkey('3', 0x14);
mapkey('4', 0x15);
mapkey('5', 0x17);
mapkey('6', 0x16);
mapkey('7', 0x1a);
mapkey('8', 0x1c);
mapkey('9', 0x19);
// Top row symbols
mapkeymod(')', 0x1d, modShift);
mapkeymod('!', 0x12, modShift);
mapkeymod('@', 0x13, modShift);
mapkeymod('#', 0x14, modShift);
mapkeymod('$', 0x15, modShift);
mapkeymod('%', 0x17, modShift);
mapkeymod('^', 0x16, modShift);
mapkeymod('&', 0x1a, modShift);
mapkeymod('*', 0x1c, modShift);
mapkeymod('(', 0x19, modShift);
// Other symbols (no shift)
mapkeymod('`', 0x32, 0);
mapkeymod('-', 0x1b, 0);
mapkeymod('=', 0x18, 0);
mapkeymod('[', 0x21, 0);
mapkeymod(']', 0x1e, 0);
mapkeymod('\\', 0x2a, 0);
mapkeymod(';', 0x29, 0);
mapkeymod('\'', 0x27, 0);
mapkeymod(',', 0x2b, 0);
mapkeymod('.', 0x2f, 0);
mapkeymod('/', 0x2c, 0);
// Other symbols (with shift)
mapkeymod('~', 0x32, modShift);
mapkeymod('_', 0x1b, modShift);
mapkeymod('+', 0x18, modShift);
mapkeymod('{', 0x21, modShift);
mapkeymod('}', 0x1e, modShift);
mapkeymod('|', 0x2a, modShift);
mapkeymod(':', 0x29, modShift);
mapkeymod('"', 0x27, modShift);
mapkeymod('<', 0x2b, modShift);
mapkeymod('>', 0x2f, modShift);
mapkeymod('?', 0x2c, modShift);
// Function keys
mapkey(SDLK_F1, 0x7a);
mapkey(SDLK_F2, 0x78);
mapkey(SDLK_F3, 0x63);
mapkey(SDLK_F4, 0x76);
mapkey(SDLK_F5, 0x60);
mapkey(SDLK_F6, 0x61);
mapkey(SDLK_F7, 0x62);
mapkey(SDLK_F8, 0x64);
mapkey(SDLK_F9, 0x65);
mapkey(SDLK_F10, 0x6d);
mapkey(SDLK_F11, 0x67);
mapkey(SDLK_F12, 0x6f);
mapkey(SDLK_F13, 0x69);
mapkey(SDLK_F14, 0x6b);
mapkey(SDLK_F15, 0x71);
// Arrows
mapkey(SDLK_UP, 0x3e);
mapkey(SDLK_DOWN, 0x3d);
mapkey(SDLK_RIGHT, 0x3c);
mapkey(SDLK_LEFT, 0x3b);
// Delete
mapkey(SDLK_DELETE, 0x75);
mapkey(SDLK_BACKSPACE, 0x33);
mapkey(SDLK_BACKSPACE, 0x33);
// Enter, NL, CR
mapkey(SDLK_RETURN2, 0x24);
mapkey(SDLK_RETURN, 0x24);
// mapkey(0x03, 0x24);
// Other keys
mapkey(SDLK_ESCAPE, 0x35); // escape
mapkey(SDLK_SPACE, 0x31); // space
mapkey(SDLK_TAB, 0x30); // tab
}
static void _display_frame (SDL_Window *win)
{
shoebill_video_frame_info_t frame = shoebill_get_video_frame(9, 0);
shoebill_send_vbl_interrupt(9);
glDrawBuffer(GL_BACK);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0, 0, 0, 1.0);
glViewport(0, 0, frame.width, frame.height);
glRasterPos2i(0, frame.height);
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelZoom(1.0, -1.0);
glDrawPixels(frame.width,
frame.height,
GL_RGBA,
GL_UNSIGNED_BYTE,
frame.buf);
SDL_GL_SwapWindow(win);
}
struct shoe_app_pram_data_t {
uint8_t pram[256];
FILE *f;
pthread_t threadid;
volatile _Bool updated, tear_down_thread;
};
struct {
const char *scsi_path[8];
const char *rom_path;
const char *relative_unix_path;
const char *pram_path;
uint32_t height, width;
uint32_t ram_megabytes;
_Bool verbose, use_tfb;
struct shoe_app_pram_data_t pram_data;
} user_params;
#define equals_arg(name) keylen = strlen(name); value = argv[i]+keylen; if (strncmp((name), argv[i], keylen) == 0)
#if !((defined WIN32) || (defined _WIN64))
#include <sys/types.h>
#include <pwd.h>
#include <uuid/uuid.h>
#endif
static char* _get_home_dir (const char *terminal_element)
{
char *result = NULL;
#if (defined WIN32) || (defined _WIN64)
if (getenv("USERPROFILE") != NULL) {
result = malloc(strlen(getenv("USERPROFILE")) + strlen(terminal_element) + 32);
sprintf(result, "%s\\%s", getenv("USERPROFILE"), terminal_element);
goto done;
}
if (getenv("HOMEDRIVE") && getenv("HOMEPATH")) {
result = malloc(strlen(getenv("HOMEDRIVE")) + strlen(getenv("HOMEPATH")) + strlen(terminal_element) + 32);
sprintf(result, "%s\\%s\\%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"), terminal_element);
goto done;
}
#else
if (getenv("HOME") != NULL) {
result = malloc(strlen(getenv("HOME")) + strlen(terminal_element) + 32);
sprintf(result, "%s/%s", getenv("HOME"), terminal_element);
goto done;
}
struct passwd *pwd = getpwuid(getuid());
if (pwd) {
result = malloc(strlen(pwd->pw_dir) + strlen(terminal_element) + 32);
sprintf(result, "%s/%s", pwd->pw_dir, terminal_element);
goto done;
}
#endif
done:
// printf("_get_home_dir: debug: %s\n", result);
return result;
}
static void _print_help (void)
{
printf("Arguments have the form name=value.\n");
printf("\n");
printf("rom=<path to Mac II ROM>\n");
printf("Specifies the path to a Macintosh II ROM.\n");
printf("E.g. rom=/home/foo/macii.rom\n");
printf("\n");
printf("disk0..disk6=<path to disk image>\n");
printf("Specifies the path to a disk image for the given SCSI ID. Shoebill will always boot from disk0, so make sure disk0 points to a bootable A/UX image.\n");
printf("E.g. disk0=/home/foo/aux3.img disk1=/blah.img\n");
printf("\n");
printf("ram=<megabytes of memory>\n");
printf("E.g. ram=16\n");
printf("\n");
printf("height=<num pixels>\n");
printf("Specifies the height of the screen in pixels.\n");
printf("\n");
printf("width=<num pixels>\n");
printf("Specifies the width of the screen in pixels.\n");
printf("\n");
printf("pram-path=<path to PRAM file>\n");
printf("Defaults to ~/.shoebill_pram\n");
printf("\n");
printf("verbose=<1 or 0>\n");
printf("Whether to boot A/UX in verbose mode. Best to leave it at default (1).\n");
printf("\n");
printf("unix-path=<path to kernel on disk0>\n");
printf("Path to the kernel file on the root disk image. Best to leave it at default (/unix).\n");
printf("\n");
printf("\n");
printf("Examples:\n");
printf("\n");
printf("shoebill.exe disk0=C:\\aux3.img rom=C:\\macii.rom width=1024 height=768 ram=64\n");
printf("\n");
printf("./shoebill disk0=/aux3.img rom=/macii.rom width=1024 height=768 ram=64\n");
printf("\n");
}
static void _init_user_params (int argc, char **argv)
{
char *key;
uint32_t i;
for (i=0; i<8; i++)
user_params.scsi_path[i] = NULL;
user_params.rom_path = "macii.rom";
user_params.relative_unix_path = "/unix";
user_params.height = 640;
user_params.width = 800;
user_params.ram_megabytes = 16;
user_params.verbose = 1;
user_params.use_tfb = 0;
user_params.pram_path = _get_home_dir(".shoebill_pram");
if (argc < 2) {
_print_help();
exit(0);
}
for (i=1; i<argc; i++) {
key = "-h";
if (strncmp(key, argv[i], strlen(key)) == 0) {
_print_help();
exit(0);
}
key = "help";
if (strncmp(key, argv[i], strlen(key)) == 0) {
_print_help();
exit(0);
}
key = "toby"; // Whether to use the "toby frame buffer" card, instead of the regular shoebill video card
if(strncmp(key, argv[i], strlen(key)) == 0) {
user_params.use_tfb = 1;
continue;
}
key = "ram=";
if (strncmp(key, argv[i], strlen(key)) == 0) {
user_params.ram_megabytes = strtoul(argv[i]+strlen(key), NULL, 10);
continue;
}
key = "height=";
if (strncmp(key, argv[i], strlen(key)) == 0) {
user_params.height = strtoul(argv[i]+strlen(key), NULL, 10);
continue;
}
key = "width=";
if (strncmp(key, argv[i], strlen(key)) == 0) {
user_params.width = strtoul(argv[i]+strlen(key), NULL, 10);
continue;
}
key = "verbose=";
if (strncmp(key, argv[i], strlen(key)) == 0) {
user_params.verbose = strtoul(argv[i]+strlen(key), NULL, 10);
continue;
}
key = "rom=";
if (strncmp(key, argv[i], strlen(key)) == 0) {
user_params.rom_path = argv[i] + strlen(key);
continue;
}
key = "unix-path=";
if (strncmp(key, argv[i], strlen(key)) == 0) {
user_params.relative_unix_path = argv[i] + strlen(key);
continue;
}
key = "pram-path=";
if (strncmp(key, argv[i], strlen(key)) == 0) {
user_params.pram_path = argv[i] + strlen(key);
continue;
}
if ((strncmp("disk", argv[i], 4) == 0) && (isdigit(argv[i][4])) && (argv[i][5] == '=')) {
uint8_t scsi_num = argv[i][4] - '0';
if (scsi_num < 7) {
user_params.scsi_path[scsi_num] = &argv[i][6];
continue;
}
}
}
}
void _pram_callback (void *param, const uint8_t addr, const uint8_t byte)
{
struct shoe_app_pram_data_t *pram_data = (struct shoe_app_pram_data_t*)param;
pram_data->pram[addr] = byte;
pram_data->updated = 1;
}
void* _pram_writer_thread (void *param)
{
struct shoe_app_pram_data_t *pram_data = (struct shoe_app_pram_data_t*)param;
while (!pram_data->tear_down_thread) {
if (pram_data->updated) {
pram_data->updated = 0;
rewind(pram_data->f);
assert(fwrite(pram_data->pram, 256, 1, pram_data->f) == 1);
fflush(stdout);
pram_data->tear_down_thread = 0;
}
sleep(1);
}
return NULL;
}
static _Bool _setup_shoebill (void)
{
uint32_t i;
shoebill_config_t config;
memset(&config, 0, sizeof(shoebill_config_t));
config.aux_verbose = user_params.verbose;
config.ram_size = user_params.ram_megabytes * 1024 * 1024;
config.aux_kernel_path = user_params.relative_unix_path;
config.rom_path = user_params.rom_path;
config.pram_callback = _pram_callback;
config.pram_callback_param = (void*)&user_params.pram_data;
memcpy(config.pram, user_params.pram_data.pram, 256);
for (i=0; i<7; i++)
config.scsi_devices[i].path = user_params.scsi_path[i];
if (!shoebill_initialize(&config)) {
printf("%s\n", config.error_msg);
return 0;
}
if (user_params.use_tfb) {
shoebill_install_tfb_card(&config, 9);
}
else {
shoebill_install_video_card(&config,
9, // slotnum
user_params.width,
user_params.height);
}
shoebill_start();
return 1;
}
static void _handle_key_event (SDL_Event *event)
{
const SDL_Keycode sym = event->key.keysym.sym;
const _Bool key_down = (event->type == SDL_KEYDOWN);
const SDL_Keymod sdl_mod = SDL_GetModState();
uint16_t adb_mod = 0;
uint16_t value;
if (sdl_mod & KMOD_SHIFT) adb_mod |= modShift;
if (sdl_mod & KMOD_CTRL) adb_mod |= modControl;
if (sdl_mod & KMOD_ALT) adb_mod |= modOption;
if (sdl_mod & KMOD_GUI) adb_mod |= modCommand;
if (sdl_mod & KMOD_CAPS) adb_mod |= modCapsLock;
if (rb_find(keymap, sym, &value)) {
shoebill_key_modifier((value >> 8) | adb_mod);
shoebill_key(key_down, value & 0xff);
}
}
static _Bool _init_pram (void)
{
FILE *f = fopen(user_params.pram_path, "r+b");
memset(&user_params.pram_data, 0, sizeof(struct shoe_app_pram_data_t));
if ((f == NULL) || (fread(user_params.pram_data.pram, 256, 1, f) != 1)) {
if (f == NULL)
f = fopen(user_params.pram_path, "w+b");
if (f == NULL) {
printf("Can't open pram_path! [%s] [errno=%s]\n",
user_params.pram_path,
sys_errlist[errno]);
return 0;
}
rewind(f);
shoebill_validate_or_zap_pram(user_params.pram_data.pram, 1);
assert(fwrite(user_params.pram_data.pram, 256, 1, f) == 1);
fflush(f);
}
user_params.pram_data.f = f;
shoebill_validate_or_zap_pram(user_params.pram_data.pram, 0);
pthread_create(&user_params.pram_data.threadid,
NULL,
_pram_writer_thread,
&user_params.pram_data);
return 1;
}
int main (int argc, char **argv)
{
const uint32_t frame_ticks = 1000 / 60;
uint32_t last_frame_ticks;
_Bool capture_cursor;
_print_vers();
_init_keyboard_map();
_init_user_params(argc, argv);
if (!_init_pram())
return 0;
else if (!_setup_shoebill())
return 0;
shoebill_video_frame_info_t frame = shoebill_get_video_frame(9, 1);
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *win = SDL_CreateWindow("Shoebill",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
frame.width, frame.height,
SDL_WINDOW_OPENGL);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GLContext glctx = SDL_GL_CreateContext(win);
glShadeModel(GL_FLAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glClearColor(0.5, 0.5, 0.5, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, frame.width, 0, frame.height, -1.0, 1.0);
capture_cursor = 1;
SDL_ShowCursor(0);
SDL_SetRelativeMouseMode(1);
SDL_GL_SetSwapInterval(1);
last_frame_ticks = SDL_GetTicks();
while (1) {
const uint32_t now = SDL_GetTicks();
uint32_t ticks_to_next_frame;
SDL_Event event;
if ((now - last_frame_ticks) >= frame_ticks) {
_display_frame(win);
last_frame_ticks = now;
ticks_to_next_frame = frame_ticks;
}
else
ticks_to_next_frame = frame_ticks - (now - last_frame_ticks);
event.type = SDL_USEREVENT;
SDL_WaitEventTimeout(&event, ticks_to_next_frame);
switch (event.type) {
case SDL_QUIT:
goto quit;
case SDL_MOUSEBUTTONDOWN: {
if ((event.button.button == SDL_BUTTON_LEFT) && capture_cursor)
shoebill_mouse_click(1);
break;
}
case SDL_MOUSEBUTTONUP: {
// If the cursor isn't captured, then any click will capture it
if (!capture_cursor)
capture_cursor = 1;
// If the cursor is captured, then left clicks get sent to the OS
else if (event.button.button == SDL_BUTTON_LEFT)
shoebill_mouse_click(0);
// If the cursor is captured, then right clicks will uncapture it
else if ((event.button.button == SDL_BUTTON_RIGHT) && capture_cursor)
capture_cursor = 0;
break;
}
case SDL_MOUSEMOTION: {
if (capture_cursor) {
_Bool down = event.motion.state & SDL_BUTTON(SDL_BUTTON_LEFT);
shoebill_mouse_click(down);
shoebill_mouse_move_delta(event.motion.xrel, event.motion.yrel);
}
break;
}
case SDL_KEYDOWN:
case SDL_KEYUP:
if (!event.key.repeat)
_handle_key_event(&event);
break;
}
if (capture_cursor) {
SDL_ShowCursor(0);
SDL_SetRelativeMouseMode(1);
}
else {
SDL_ShowCursor(1);
SDL_SetRelativeMouseMode(0);
}
}
quit:
// FIXME: tear down the pram thread and flush pram
return 0;
}

9
sdl-gui/win_build.bat Executable file
View File

@ -0,0 +1,9 @@
for %%i in (adb fpu mc68851 mem via floppy core_api cpu dis) do (
perl ..\core\macro.pl ..\core\%%i.c %%i.post.c
)
gcc -O1 ..\core\decoder_gen.c -o decoder_gen
decoder_gen inst .
decoder_gen dis .
gcc -O3 -flto -mno-ms-bitfields sdl.c adb.post.c fpu.post.c mc68851.post.c mem.post.c via.post.c floppy.post.c core_api.post.c cpu.post.c dis.post.c ..\core\atrap_tab.c ..\core\coff.c ..\core\exception.c ..\core\macii_symbols.c ..\core\redblack.c ..\core\scsi.c ..\core\video.c ..\core\filesystem.c ..\core\alloc_pool.c ..\core\toby_frame_buffer.c ..\core\ethernet.c ..\core\sound.c ..\core\SoftFloat\softfloat.c -lmingw32 -lopengl32 -lsdl2main -lsdl2 -o shoebill

407
test.c
View File

@ -1,407 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <pthread.h>
#include <GLUT/glut.h>
#include "core/shoebill.h"
#include "core/core_api.h"
shoebill_control_t control;
shoebill_card_video_t *video_card = NULL;
void glut_display_func (void)
{
uint32_t myw = glutGet(GLUT_WINDOW_WIDTH);
uint32_t myh = glutGet(GLUT_WINDOW_HEIGHT);
uint32_t slotnum, i;
shoebill_card_video_t *ctx = video_card;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, myw, 0, myh, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.1, 0.1, 0.8);
uint32_t gli = 0;
switch (ctx->depth) {
case 1: {
for (i=0; i < ctx->pixels/8; i++) {
const uint8_t byte = ctx->indexed_buf[i];
ctx->direct_buf[i * 8 + 0] = ctx->clut[(byte >> 7) & 1];
ctx->direct_buf[i * 8 + 1] = ctx->clut[(byte >> 6) & 1];
ctx->direct_buf[i * 8 + 2] = ctx->clut[(byte >> 5) & 1];
ctx->direct_buf[i * 8 + 3] = ctx->clut[(byte >> 4) & 1];
ctx->direct_buf[i * 8 + 4] = ctx->clut[(byte >> 3) & 1];
ctx->direct_buf[i * 8 + 5] = ctx->clut[(byte >> 2) & 1];
ctx->direct_buf[i * 8 + 6] = ctx->clut[(byte >> 1) & 1];
ctx->direct_buf[i * 8 + 7] = ctx->clut[(byte >> 0) & 1];
}
break;
}
case 2: {
for (i=0; i < ctx->pixels/4; i++) {
const uint8_t byte = ctx->indexed_buf[i];
ctx->direct_buf[i * 4 + 0] = ctx->clut[(byte >> 6) & 3];
ctx->direct_buf[i * 4 + 1] = ctx->clut[(byte >> 4) & 3];
ctx->direct_buf[i * 4 + 2] = ctx->clut[(byte >> 2) & 3];
ctx->direct_buf[i * 4 + 3] = ctx->clut[(byte >> 0) & 3];
}
break;
}
case 4: {
for (i=0; i < ctx->pixels/2; i++) {
const uint8_t byte = ctx->indexed_buf[i];
ctx->direct_buf[i * 2 + 0] = ctx->clut[(byte >> 4) & 0xf];
ctx->direct_buf[i * 2 + 1] = ctx->clut[(byte >> 0) & 0xf];
}
break;
}
case 8:
for (i=0; i < ctx->pixels; i++)
ctx->direct_buf[i] = ctx->clut[ctx->indexed_buf[i]];
break;
default:
assert(!"unknown depth");
}
glViewport(0, 0, myw, myh);
glRasterPos2i(0, myh);
glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelZoom(1.0, -1.0);
glDrawPixels(myw, myh, GL_RGBA, GL_UNSIGNED_BYTE, ctx->direct_buf);
glFlush();
}
/*void vbl_callback (shoebill_control_t *ctrl, uint8_t slotnum)
{
}
void video_depth_calback (sheobill_control_t *ctrl, uint8_t slotnum)
{
}*/
#define KEY_SHIFT 1
const struct {
uint8_t code;
char c;
uint8_t modifiers;
} key_codes[] = {
{0x0, 'A', 0},
{0x1, 'S', 0},
{2, 'D', 0},
{3, 'F', 0},
{4, 'H', 0},
{5, 'G', 0},
{6, 'Z', 0},
{7, 'X', 0},
{8, 'C', 0},
{9, 'V', 0},
// {0xa ??
{0xb, 'B', 0},
{0xc, 'Q', 0},
{0xd, 'W', 0},
{0xe, 'E', 0},
{0xf, 'R', 0},
{0x10, 'Y', 0},
{0x11, 'T', 0},
{0x12, '1', 0},
{0x12, '!', KEY_SHIFT},
{0x13, '2', 0},
{0x13, '@', KEY_SHIFT},
{0x14, '3', 0},
{0x14, '#', KEY_SHIFT},
{0x15, '4', 0},
{0x15, '$', KEY_SHIFT},
{0x16, '6', 0},
{0x16, '^', KEY_SHIFT},
{0x17, '5', 0},
{0x17, '%', KEY_SHIFT},
{0x18, '=', 0},
{0x18, '+', KEY_SHIFT},
{0x19, '9', 0},
{0x19, '(', KEY_SHIFT},
{0x1a, '7', 0},
{0x1a, '&', KEY_SHIFT},
{0x1b, '-', 0},
{0x1b, '_', KEY_SHIFT},
{0x1c, '8', 0},
{0x1c, '*', KEY_SHIFT},
{0x1d, '0', 0},
{0x1d, ')', KEY_SHIFT},
{0x1e, ']', 0},
{0x1e, '}', KEY_SHIFT},
{0x1f, 'O', 0},
{0x20, 'U', 0},
{0x21, '[', 0},
{0x21, '{', KEY_SHIFT},
{0x22, 'I', 0},
{0x23, 'P', 0},
{0x24, '\n', 0},
{0x24, '\r', 0},
{0x25, 'L', 0},
{0x26, 'J', 0},
{0x27, '"', KEY_SHIFT},
{0x27, '\'', 0},
{0x28, 'K', 0},
{0x29, ';', 0},
{0x29, ':', KEY_SHIFT},
{0x2a, '\\', 0},
{0x2a, '|', KEY_SHIFT},
{0x2b, ',', 0},
{0x2b, '<', KEY_SHIFT},
{0x2c, '/', 0},
{0x2c, '?', 0},
{0x2d, 'N', 0},
{0x2e, 'M', 0},
{0x2f, '.', 0},
{0x2f, '>', KEY_SHIFT},
{0x30, '\t', 0},
{0x31, ' ', 0},
{0x32, '`', 0},
{0x32, '~', KEY_SHIFT},
{0x33, '\b', 0},
{0x33, 0x7f, 0},
// {0x34, ??
// {0x35 // escape char
// 0x36 // ctrl
// 0x37 // command
// 0x38 // shift
// 0x39 // caps lock
// 0x3a // option
// 0x3b // left arrow
// 0x3c // right arrow
// 0x3d // down arrow
// 0x3e // up arrow
{0, 0, 0},
};
static uint8_t lookup_key(char c)
{
uint32_t i;
uint8_t upper=toupper(c);
for (i=0; key_codes[i].c; i++) {
if (key_codes[i].c == upper)
return key_codes[i].code;
}
return 0xff;
}
static uint8_t lookup_special(int special)
{
switch (special) {
case GLUT_KEY_UP: return 0x3e;
case GLUT_KEY_DOWN: return 0x3d;
case GLUT_KEY_LEFT: return 0x3b;
case GLUT_KEY_RIGHT: return 0x3c;
default: return 0xff;
}
}
static void keyboard_add_entry(uint8_t code, uint8_t up)
{
uint8_t up_mask = up ? 0x80 : 0;
uint32_t i;
int modifiers = glutGetModifiers();
assert(pthread_mutex_lock(&shoe.adb.lock) == 0);
if ((shoe.key.key_i+1) < KEYBOARD_STATE_MAX_KEYS) {
if (modifiers & GLUT_ACTIVE_SHIFT) {
shoe.key.keys[shoe.key.key_i].code_a = 0x38;
shoe.key.keys[shoe.key.key_i].code_b = 0xff;
shoe.key.key_i++;
}
else if (shoe.key.down_modifiers & GLUT_ACTIVE_SHIFT) {
shoe.key.keys[shoe.key.key_i].code_a = 0x80 | 0x38;
shoe.key.keys[shoe.key.key_i].code_b = 0xff;
shoe.key.key_i++;
}
shoe.key.keys[shoe.key.key_i].code_a = code | up_mask;
shoe.key.keys[shoe.key.key_i].code_b = 0xff;
shoe.key.key_i++;
}
shoe.key.down_modifiers = modifiers;
adb_request_service_request(2);
pthread_mutex_unlock(&shoe.adb.lock);
}
void global_mouse_func (int button, int state, int x, int y)
{
//if (button != GLUT_LEFT_BUTTON)
// return ;
assert(pthread_mutex_lock(&shoe.adb.lock) == 0);
shoe.mouse.button_down = (state == GLUT_DOWN);
shoe.mouse.changed = 1;
adb_request_service_request(3);
pthread_mutex_unlock(&shoe.adb.lock);
// printf("mouse_func: setting service request\n");
}
static void move_mouse (int x, int y, uint8_t button_down)
{
printf("%s: lock\n", __func__); fflush(stdout);
assert(pthread_mutex_lock(&shoe.adb.lock) == 0);
int32_t delta_x = x - shoe.mouse.old_x;
int32_t delta_y = y - shoe.mouse.old_y;
shoe.mouse.old_x = x;
shoe.mouse.old_y = y;
shoe.mouse.delta_x += delta_x;
shoe.mouse.delta_y += delta_y;
shoe.mouse.button_down = button_down;
shoe.mouse.changed = 1;
adb_request_service_request(3);
printf("%s: unlock\n", __func__); fflush(stdout);
pthread_mutex_unlock(&shoe.adb.lock);
// printf("move_mouse: setting service request\n");
}
void global_motion_func (int x, int y)
{
move_mouse(x, y, 1);
}
void global_passive_motion_func (int x, int y)
{
move_mouse(x, y, 0);
}
void global_keyboard_up_func (unsigned char c, int x, int y)
{
uint8_t code = lookup_key(c);
if (code != 0xff)
keyboard_add_entry(code, 1);
}
void global_keyboard_down_func (unsigned char c, int x, int y)
{
uint8_t code = lookup_key(c);
if (code != 0xff)
keyboard_add_entry(code, 0);
}
void global_special_up_func (int special, int x, int y)
{
const uint8_t code = lookup_special(special);
if (code != 0xff)
keyboard_add_entry(code, 1);
}
void global_special_down_func (int special, int x, int y)
{
const uint8_t code = lookup_special(special);
if (code != 0xff)
keyboard_add_entry(code, 0);
}
void timer_func (int arg)
{
glutTimerFunc(15, timer_func, 0); // 66.67hz is the usual refresh interval (right?)
glutPostRedisplay();
}
int main (int argc, char **argv)
{
bzero(&control, sizeof(shoebill_control_t));
control.aux_verbose = 1;
control.ram_size = 1024*1024*1024;
control.aux_kernel_path = "priv/unix2";
control.rom_path = "priv/macii.rom";
control.scsi_devices[0].path = "priv/aux2.img";
uint32_t result = shoebill_initialize(&control);
if (!result) {
printf("fail: %s\n", control.error_msg);
return 0;
}
else
printf("success!\n");
shoebill_install_video_card(&control, 10, 800, 600,
(2.0/3.0) * 100.0); // 66.67hz
video_card = &control.slots[10].card.video;
int dummyargc = 1;
glutInit(&dummyargc, argv);
glutInitWindowSize(video_card->scanline_width, video_card->height);
glutCreateWindow("");
glutDisplayFunc(glut_display_func);
glShadeModel(GL_FLAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glClearColor(0.1, 1.0, 0.1, 1.0);
shoebill_start();
glutTimerFunc(15, timer_func, 0);
glutMainLoop();
return 0;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 KiB