Compare commits
63 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a9b2af09c0 | ||
|
2b4768daee | ||
|
3fd03263fa | ||
|
578d274ab0 | ||
|
bbb89edf8c | ||
|
70cf3734fb | ||
|
d26cbef0c1 | ||
|
0322e558b4 | ||
|
1ab8a6a988 | ||
|
7f8b393fcc | ||
|
c0439a2f57 | ||
|
2ffbc963d2 | ||
|
36fdd1a6d6 | ||
|
3bc6aed00a | ||
|
b936ace3eb | ||
|
a66ad6d9b4 | ||
|
476a8bb570 | ||
|
76f2b35170 | ||
|
9c3640cf48 | ||
|
aea23c6dfc | ||
|
9e91b8067a | ||
|
8142098fa1 | ||
|
f04e039dca | ||
|
c8e7ba594c | ||
|
7fa1e15257 | ||
|
c7a28b8520 | ||
|
0910915301 | ||
|
937a28a8bb | ||
|
db111528e8 | ||
|
df66c085da | ||
|
18c5a2b261 | ||
|
2d04c6c104 | ||
|
2790b03327 | ||
|
688199cf6d | ||
|
a155eb7734 | ||
|
7c96e7c101 | ||
|
16f1af72f8 | ||
|
78fbd8235f | ||
|
c9adc49a82 | ||
|
adc2e16ffd | ||
|
bb6d1e719f | ||
|
bb2ec0a27d | ||
|
a0810f55b9 | ||
|
b29c69453e | ||
|
4af4262993 | ||
|
fd31d642b0 | ||
|
20fedf386b | ||
|
ea23ef3ac6 | ||
|
df614785c9 | ||
|
4ac0c6c4b2 | ||
|
6773dd6020 | ||
|
305d84faad | ||
|
f051d42597 | ||
|
42fd2a0b4e | ||
|
1bee24316c | ||
|
952fe7ae89 | ||
|
5c1fdf6b73 | ||
|
a16a6700e4 | ||
|
d5dd7385b1 | ||
|
f4f546deb5 | ||
|
d19c17812c | ||
|
2800cc3c7e | ||
|
1ffea71ed3 |
2
.gitignore
vendored
|
@ -4,3 +4,5 @@
|
|||
*.xcworkspace
|
||||
xcuserdata
|
||||
/gui/build
|
||||
/debugger/debugger
|
||||
/debugger/debugger.dSYM
|
||||
|
|
8
Makefile
|
@ -1,11 +1,17 @@
|
|||
|
||||
CC = clang
|
||||
CFLAGS = -O3 -flto -Wno-deprecated-declarations
|
||||
|
||||
all: shoebill
|
||||
|
||||
shoebill: make_gui
|
||||
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
|
||||
|
||||
|
|
31
README.md
|
@ -1,39 +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.
|
||||
|
||||
Shoebill requires a OS X, a Macintosh II, IIx or IIcx ROM, and a disk image with A/UX installed.
|
||||
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].
|
||||
|
||||
__Update (April 26, 2014): Shoebill 0.0.2 is available, and it supports A/UX 3.0.0! And you no longer need to supply your own kernel.__
|
||||
__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.0.0 (but not 3.0.1 or higher, yet)
|
||||
#### Supports
|
||||
* A/UX 1.1.1 through 3.1 (and 3.1.1 a little)
|
||||
|
||||
####Currently Implements
|
||||
#### 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/
|
||||
|
||||
|
|
55
README.txt
|
@ -1,55 +0,0 @@
|
|||
|
||||
Shoebill - a Macintosh II emulator that runs A/UX
|
||||
|
||||
See the wiki on https://github.com/pruten/shoebill for better
|
||||
documentation on building and running Shoebill.
|
||||
|
||||
*** KEEP IN MIND ***
|
||||
|
||||
* Shoebill v.0.0.2
|
||||
* ONLY RUNS A/UX
|
||||
* 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 10.8 or 10.9
|
||||
* A Macintosh II, IIx, or IIcx ROM
|
||||
* A disk image with A/UX 1.x.x or 2.x.x, or 3.0.0 installed
|
||||
* Note: 3.0.1 and 3.1.x do not work!
|
||||
* If you happen to have an installation CD image for A/UX, that will work
|
||||
|
||||
|
||||
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 can’t even boot enough to run fsck.
|
||||
* Open Shoebill.app and select Preferences menu item
|
||||
* Set the paths for your ROM and disk image(s).
|
||||
* Do use SCSI ID #0 for your A/UX boot image.
|
||||
* Press “Apply and Run”
|
||||
* Note: As of 0.0.2, you no longer need to provide your own kernel file
|
||||
|
||||
|
||||
*** BUILDING ***
|
||||
|
||||
1) cd to shoebill/
|
||||
2) make
|
||||
3) The resulting app will be in gui/build
|
||||
|
||||
|
||||
|
||||
*** ETC. ***
|
||||
Props to Jared Falter for technical and emotional support!
|
||||
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
|
||||
CC = clang
|
||||
CFLAGS = -O3 -flto -ggdb -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 filesystem debug_server alloc_pool
|
||||
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))
|
||||
|
@ -73,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
|
@ -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
|
||||
|
728
core/SoftFloat/softfloat-macros.h
Normal 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 );
|
||||
|
||||
}
|
||||
|
464
core/SoftFloat/softfloat-specialize.h
Normal 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
259
core/SoftFloat/softfloat.h
Normal 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
|
||||
|
101
core/adb.c
|
@ -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,32 +144,33 @@ 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:
|
||||
|
@ -154,7 +181,7 @@ static void mouse_talk(uint8_t reg)
|
|||
int32_t x = shoe.mouse.delta_x;
|
||||
int32_t y = shoe.mouse.delta_y;
|
||||
|
||||
//printf("mouse_talk: x=%d, y=%d button=%u\n", shoe.mouse.delta_x, shoe.mouse.delta_y, shoe.mouse.button_down);
|
||||
//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;
|
||||
|
@ -168,7 +195,7 @@ static void mouse_talk(uint8_t reg)
|
|||
//shoe.adb.data[1] |= 0x80;
|
||||
shoe.adb.data[0] |= 0x80;
|
||||
}
|
||||
// printf("mouse_talk: ")
|
||||
// slog("mouse_talk: ")
|
||||
|
||||
|
||||
shoe.adb.data_len = 2;
|
||||
|
@ -217,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;
|
||||
|
@ -245,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);
|
||||
}
|
||||
|
||||
|
@ -253,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);
|
||||
|
@ -266,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 ;
|
||||
}
|
||||
|
||||
|
@ -280,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 ;
|
||||
}
|
||||
|
||||
|
@ -299,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);
|
||||
}
|
||||
|
||||
|
@ -312,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;
|
||||
}
|
||||
|
||||
|
@ -353,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:
|
||||
|
@ -362,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;
|
||||
}
|
||||
|
@ -374,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;
|
||||
|
@ -398,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,18 +26,54 @@
|
|||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "../core/shoebill.h"
|
||||
|
||||
/*typedef struct _alloc_pool_t {
|
||||
|
||||
|
||||
/*
|
||||
#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;
|
||||
uint32_t size, magic;
|
||||
} alloc_pool_t;*/
|
||||
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->size = size;
|
||||
buf->magic = 'moof';
|
||||
|
||||
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;
|
||||
|
@ -51,19 +87,36 @@ void* p_alloc(alloc_pool_t *pool, uint64_t size)
|
|||
|
||||
void* p_realloc(void *ptr, uint64_t size)
|
||||
{
|
||||
alloc_pool_t *header = &((alloc_pool_t*)ptr)[-1];
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
void p_free(void *ptr)
|
||||
/*
|
||||
* Free *any* kind of alloc_pool_t header
|
||||
*/
|
||||
static void _p_free_any(alloc_pool_t *header)
|
||||
{
|
||||
alloc_pool_t *header = &((alloc_pool_t*)ptr)[-1];
|
||||
assert(header->magic == 'moof');
|
||||
assert(header->start_magic == POOL_START_MAGIC);
|
||||
assert(header->end_magic == POOL_END_MAGIC);
|
||||
|
||||
if (header->next)
|
||||
header->next->prev = header->prev;
|
||||
|
@ -74,6 +127,17 @@ void p_free(void *ptr)
|
|||
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)
|
||||
|
@ -82,14 +146,50 @@ void p_free_pool(alloc_pool_t *pool)
|
|||
while (pool) {
|
||||
alloc_pool_t *cur = pool;
|
||||
pool = cur->next;
|
||||
assert(cur->magic == 'moof');
|
||||
free(cur);
|
||||
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(void)
|
||||
alloc_pool_t* p_new_pool(alloc_pool_t *parent_pool)
|
||||
{
|
||||
alloc_pool_t *pool = calloc(sizeof(alloc_pool_t), 1);
|
||||
pool->magic = 'moof';
|
||||
|
||||
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;
|
||||
}
|
108
core/coff.c
|
@ -30,14 +30,13 @@
|
|||
#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);
|
||||
}
|
||||
|
||||
|
@ -59,25 +58,31 @@ void symb_inorder(rb_node *cur) {
|
|||
_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.
|
||||
// God help you if you want to free it.
|
||||
coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
||||
coff_file* coff_parse(uint8_t *buf, uint32_t buflen, alloc_pool_t *parent_pool)
|
||||
{
|
||||
uint8_t rawhead[20], *ptr;
|
||||
uint32_t i;
|
||||
coff_file *cf = NULL;
|
||||
uint32_t bufptr = 0;
|
||||
alloc_pool_t *pool = p_new_pool(parent_pool);
|
||||
|
||||
// Pull out 20 bytes (the file header)
|
||||
if (!_coff_buf_read(rawhead, 20)) {
|
||||
printf("coff_parse: error: this binary is missing its file header\n");
|
||||
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);
|
||||
|
@ -88,32 +93,32 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
|||
|
||||
// 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);
|
||||
uint8_t *opt = p_alloc(cf->pool, cf->opt_header_len);
|
||||
if (!_coff_buf_read(opt, cf->opt_header_len)) {
|
||||
printf("coff_parse: I ran out of data pulling the optional header (%u bytes)\n", cf->opt_header_len);
|
||||
free(opt);
|
||||
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 (!_coff_buf_read(rawsec, 40)) {
|
||||
printf("coff_parse: I ran out of data pulling section #%u\n", i+1);
|
||||
slog("coff_parse: I ran out of data pulling section #%u\n", i+1);
|
||||
goto fail;
|
||||
}
|
||||
// and copy it into cf->sections[i]
|
||||
|
@ -131,7 +136,7 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
|||
|
||||
// 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
|
||||
}
|
||||
|
@ -153,15 +158,15 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
|||
|
||||
// seek to the position in the binary that holds this section's raw data
|
||||
if (!_coff_buf_seek(cf->sections[i].data_ptr)) {
|
||||
printf("coff_parse: I couldn't seek to 0x%x in section %u\n", cf->sections[i].data_ptr, i+1);
|
||||
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
|
||||
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)) {
|
||||
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);
|
||||
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;
|
||||
|
@ -172,20 +177,20 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
|||
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 (!_coff_buf_seek(cf->symtab_offset)) {
|
||||
printf("coff_parse: I couldn't seek to symtab_offset, 0x%x\n", 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 (!_coff_buf_read(raw_symb, 18)) {
|
||||
printf("coff_parse: I ran out of data pulling symbol #%u\n", i+1);
|
||||
slog("coff_parse: I ran out of data pulling symbol #%u\n", i+1);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -196,19 +201,19 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
|||
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 (!_coff_buf_seek(idx)) {
|
||||
printf("coff_parse: I ran out of data pulling symbol %u's name (idx=0x%x)\n", i+1, 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; (_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;
|
||||
_coff_buf_seek(cf->symtab_offset + (i+1)*18);
|
||||
|
@ -230,17 +235,18 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
|||
// 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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -252,24 +258,24 @@ coff_file* coff_parse(uint8_t *buf, uint32_t buflen)
|
|||
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)
|
||||
coff_file* coff_parse_from_path(const char *path, alloc_pool_t *parent_pool)
|
||||
{
|
||||
FILE *f = fopen(path, "r");
|
||||
FILE *f = fopen(path, "rb");
|
||||
uint8_t *buf = malloc(1);
|
||||
uint32_t i=0, tmp;
|
||||
coff_file *coff;
|
||||
|
@ -284,7 +290,7 @@ coff_file* coff_parse_from_path(const char *path)
|
|||
} while ((tmp > 0) && (i < 64*1024*1024));
|
||||
|
||||
|
||||
coff = coff_parse(buf, i);
|
||||
coff = coff_parse(buf, i, parent_pool);
|
||||
free(buf);
|
||||
return coff;
|
||||
}
|
||||
|
@ -296,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(×tamp, timebuf));
|
||||
printf("Num sections = %u\n", coff->num_sections);
|
||||
slog("Magic = 0x%04x\n", coff->magic);
|
||||
slog("Linked on %s", ctime_r(×tamp, 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,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;
|
||||
|
|
85
core/coff.h
|
@ -1,85 +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_parse(uint8_t *buf, uint32_t buflen);
|
||||
coff_file* coff_parse_from_path(const char *path);
|
||||
uint32_t be2native (uint8_t **dat, uint32_t bytes);
|
||||
void print_coff_info(coff_file *coff);
|
||||
|
||||
|
||||
#endif // _COFF_H
|
752
core/core_api.c
132
core/core_api.h
|
@ -1,132 +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;
|
||||
uint8_t *cur_buf;
|
||||
|
||||
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, via_thread_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();
|
||||
|
||||
uint8_t* shoebill_extract_kernel(const char *disk_path, const char *kernel_path, char *error_str, uint32_t *len);
|
||||
|
||||
#endif
|
1751
core/cpu.c
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include "../core/shoebill.h"
|
||||
#include "../core/coff.h"
|
||||
|
||||
#define DEBUG_MODE_STOPPED 0
|
||||
#define DEBUG_MODE_RUNNING 1
|
||||
#define DEBUG_MODE_STEP 2
|
||||
|
||||
#define SHOEBILL_DEBUG_PORT 0xfded
|
||||
static int _start_debug_server(void)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_len = sizeof(struct sockaddr_in);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(SHOEBILL_DEBUG_PORT);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
if (sock == -1) {
|
||||
assert(!"can't socket");
|
||||
}
|
||||
else if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr)) != 0) {
|
||||
assert(!"can't bind");
|
||||
// return -1;
|
||||
}
|
||||
else if (listen(sock, 1) != 0) {
|
||||
assert(!"can't listen");
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
void *debug_server_thread (void *arg)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
socklen_t sin_size = sizeof(struct sockaddr_in);
|
||||
uint8_t *inbuf = calloc(0x10000, 1);
|
||||
uint8_t *outbuf = calloc(0x10000, 1);
|
||||
int sock = _start_debug_server();
|
||||
int clientfd = accept(sock, (struct sockaddr*)&addr, &sin_size);
|
||||
|
||||
shoe.dbg.connected = 1;
|
||||
shoe.dbg.mode = DEBUG_MODE_RUNNING;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *debug_cpu_thread (void *arg)
|
||||
{
|
||||
memset(&shoe.dbg, 0, sizeof(shoe.dbg));
|
||||
shoe.dbg.mode = DEBUG_MODE_STOPPED;
|
||||
|
||||
pthread_t server_thread_pid;
|
||||
pthread_create(&server_thread_pid,
|
||||
NULL,
|
||||
debug_server_thread,
|
||||
NULL);
|
||||
|
||||
/*
|
||||
* The CPU only runs once the debugger is connected, and the
|
||||
* emulator has started
|
||||
*/
|
||||
pthread_mutex_lock(&shoe.cpu_thread_lock);
|
||||
while (!shoe.dbg.connected)
|
||||
usleep(1000);
|
||||
|
||||
while (1) {
|
||||
if (shoe.dbg.mode == DEBUG_MODE_RUNNING) {
|
||||
if (!shoe.dbg.ignore_interrupts &&
|
||||
(shoe.cpu_thread_notifications & 0xff)) {
|
||||
process_pending_interrupt();
|
||||
}
|
||||
|
||||
if (shoe.cpu_thread_notifications & SHOEBILL_STATE_STOPPED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cpu_step();
|
||||
}
|
||||
else if (shoe.dbg.mode == DEBUG_MODE_STOPPED)
|
||||
pthread_yield_np();
|
||||
else if (shoe.dbg.mode == DEBUG_MODE_STEP) {
|
||||
cpu_step();
|
||||
shoe.dbg.mode = DEBUG_MODE_STOPPED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1493,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);
|
||||
}
|
||||
|
@ -1511,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);
|
||||
}
|
||||
|
||||
|
@ -1529,7 +1544,7 @@ void begin_definitions()
|
|||
add_range(inst, "1111 001 101 MMMMMM");
|
||||
ea_control(inst);
|
||||
ea_add_mode(inst, EA_011);
|
||||
}*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
312
core/dis.c
|
@ -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,24 +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 () {
|
||||
sprintf(dis.str, "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 () {
|
||||
sprintf(dis.str, "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 () {
|
||||
sprintf(dis.str, "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 () {
|
||||
|
@ -1077,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() {
|
||||
|
@ -1103,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() {
|
||||
|
@ -1384,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);
|
||||
|
||||
|
@ -1468,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
|
@ -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
514
core/ethernet_rom/rom.c
Normal 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
|
||||
};
|
1
core/ethernet_rom/shoebill_ether.make
Executable 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
|
1
core/ethernet_rom/shoebill_ether_rom.a
Executable 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
|
|
@ -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,7 +217,7 @@ 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))
|
||||
//assert(!"illegal");
|
||||
|
@ -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,7 +240,7 @@ 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;
|
||||
|
|
|
@ -30,16 +30,6 @@
|
|||
#include <string.h>
|
||||
#include "../core/shoebill.h"
|
||||
|
||||
#define fix_endian(x) do { \
|
||||
if (ntohs(1) == 1) \
|
||||
break; \
|
||||
switch (sizeof(x)) { \
|
||||
case 1: break; \
|
||||
case 2: (x) = ntohs(x); break; \
|
||||
case 4: (x) = ntohl(x); break; \
|
||||
default: assert(!"bogus size"); \
|
||||
}} while (0)
|
||||
|
||||
/* --- Disk/partition management stuff --- */
|
||||
#pragma mark Disk/partition management stuff
|
||||
|
||||
|
@ -197,7 +187,7 @@ static disk_t* open_disk (const char *disk_path, char *error_str)
|
|||
uint8_t block[512];
|
||||
apple_partition_map_t apm;
|
||||
uint32_t i;
|
||||
alloc_pool_t *pool = p_new_pool();
|
||||
alloc_pool_t *pool = p_new_pool(NULL);
|
||||
FILE *f;
|
||||
|
||||
disk = p_alloc(pool, sizeof(disk_t));
|
||||
|
@ -207,7 +197,7 @@ static disk_t* open_disk (const char *disk_path, char *error_str)
|
|||
disk->error_str = error_str;
|
||||
disk->path = disk_path;
|
||||
|
||||
f = fopen(disk_path, "r");
|
||||
f = fopen(disk_path, "rb");
|
||||
if (f == NULL) {
|
||||
sprintf(error_str, "Can't open that path");
|
||||
goto fail;
|
||||
|
@ -240,7 +230,7 @@ static disk_t* open_disk (const char *disk_path, char *error_str)
|
|||
}
|
||||
}
|
||||
|
||||
// printf("sizeof(apple_part_map_t) = %lu\n", sizeof(apple_partition_map_t));
|
||||
// slog("sizeof(apple_part_map_t) = %lu\n", sizeof(apple_partition_map_t));
|
||||
|
||||
// Load the partition maps
|
||||
|
||||
|
@ -269,8 +259,8 @@ static disk_t* open_disk (const char *disk_path, char *error_str)
|
|||
memcpy(disk->partitions[i].name, disk->partition_maps[i].pmPartName, 32);
|
||||
memcpy(disk->partitions[i].type, disk->partition_maps[i].pmPartType, 32);
|
||||
|
||||
printf("%u type:%s name:%s\n", i, disk->partitions[i].type, disk->partitions[i].name);
|
||||
printf("bz_magic=0x%08x slice=%u\n", disk->partition_maps[i].bz.magic, disk->partition_maps[i].bz.slice);
|
||||
slog("%u type:%s name:%s\n", i, disk->partitions[i].type, disk->partitions[i].name);
|
||||
slog("bz_magic=0x%08x slice=%u\n", disk->partition_maps[i].bz.magic, disk->partition_maps[i].bz.slice);
|
||||
}
|
||||
|
||||
return disk;
|
||||
|
@ -332,7 +322,7 @@ static int32_t find_root_partition_number(disk_t *disk, uint8_t clus_num)
|
|||
partition_t *part = &disk->partitions[i];
|
||||
apple_partition_map_t *apm = &disk->partition_maps[i];
|
||||
|
||||
// printf("%u magic=0x%08x root=%u type=%s\n", i, apm->bz.magic, apm->bz.root, part->type);
|
||||
// slog("%u magic=0x%08x root=%u type=%s\n", i, apm->bz.magic, apm->bz.root, part->type);
|
||||
|
||||
if (apm->bz.magic != 0xabadbabe)
|
||||
continue;
|
||||
|
@ -417,7 +407,7 @@ static uint8_t svfs_read_block(svfs_t *mount, uint8_t *block, uint32_t blockno)
|
|||
const uint32_t start_sector = blockno * sectors_per_block;
|
||||
uint32_t i;
|
||||
|
||||
// printf("sectors_per_block = %u, start_sector=%u\n", sectors_per_block, start_sector);
|
||||
// slog("sectors_per_block = %u, start_sector=%u\n", sectors_per_block, start_sector);
|
||||
|
||||
for (i=0; i<sectors_per_block; i++) {
|
||||
part_get_block(mount->part, &block[i * 512], start_sector+i);
|
||||
|
@ -637,9 +627,9 @@ svfs_inode_t* svfs_traverse_path(svfs_t *mount, const char *_path)
|
|||
for (elem = strtok_r(path, "/", &last);
|
||||
elem;
|
||||
elem = strtok_r(NULL, "/", &last)) {
|
||||
//printf("elem = [%s]\n", elem);
|
||||
//slog("elem = [%s]\n", elem);
|
||||
const uint32_t num_entries = inode->size / 16;
|
||||
//printf("inode size = %u\n", inode->size);
|
||||
//slog("inode size = %u\n", inode->size);
|
||||
svfs_dir_entry_t *dir = (svfs_dir_entry_t*)svfs_read_inode_data(mount, inode);
|
||||
if (!dir)
|
||||
goto fail;
|
||||
|
@ -660,7 +650,7 @@ svfs_inode_t* svfs_traverse_path(svfs_t *mount, const char *_path)
|
|||
goto fail;
|
||||
}
|
||||
}
|
||||
//printf("final inode size = %u\n", inode->size);
|
||||
//slog("final inode size = %u\n", inode->size);
|
||||
p_free(path);
|
||||
return inode;
|
||||
|
||||
|
@ -900,8 +890,8 @@ static uint8_t ufs_load_inode(ufs_t *mount, ufs_inode_t *inode, uint32_t inum)
|
|||
uint32_t i;
|
||||
uint8_t *buf = p_alloc(mount->pool, mount->frag_size);
|
||||
|
||||
// printf("group_num = %u, ino_offset=%u, addr = 0x%08x, offset = 0x%08x\n", group_num, group_ino_offset, frag_addr, frag_offset);
|
||||
// printf("mount->superblock.iblkno = 0x%08x\n", mount->superblock.iblkno);
|
||||
// slog("group_num = %u, ino_offset=%u, addr = 0x%08x, offset = 0x%08x\n", group_num, group_ino_offset, frag_addr, frag_offset);
|
||||
// slog("mount->superblock.iblkno = 0x%08x\n", mount->superblock.iblkno);
|
||||
|
||||
if (!ufs_read_frag(mount, buf, frag_addr))
|
||||
goto fail;
|
||||
|
@ -953,7 +943,7 @@ static uint8_t ufs_read_level(ufs_t *mount,
|
|||
goto fail;
|
||||
|
||||
// for (i=0; i<num_pointers; i++)
|
||||
// printf("%u 0x%08x\n", i, ntohl(table[i]));
|
||||
// slog("%u 0x%08x\n", i, ntohl(table[i]));
|
||||
|
||||
if (level == 1)
|
||||
block = p_alloc(mount->pool, mount->block_size);
|
||||
|
@ -970,11 +960,11 @@ static uint8_t ufs_read_level(ufs_t *mount,
|
|||
const uint32_t block_addr = (blockno / mount->frag_per_block) * mount->frag_per_block;
|
||||
const uint32_t block_offset = (blockno - block_addr) * mount->frag_size;
|
||||
|
||||
printf("L%u: raw_blkno=0x%08x len=0x%08x blockno:0x%08x chunk_size=0x%08x\n", level-1, blockno, (uint32_t)*len, block_addr, (uint32_t)chunk_size);
|
||||
slog("L%u: raw_blkno=0x%08x len=0x%08x blockno:0x%08x chunk_size=0x%08x\n", level-1, blockno, (uint32_t)*len, block_addr, (uint32_t)chunk_size);
|
||||
|
||||
// If the chunk_size is a whole block, then we better be reading in a whole block
|
||||
if (chunk_size == mount->block_size) {
|
||||
// printf("block_offset = 0x%x\n", block_offset);
|
||||
// slog("block_offset = 0x%x\n", block_offset);
|
||||
assert(block_offset == 0);
|
||||
}
|
||||
|
||||
|
@ -1020,7 +1010,7 @@ static uint8_t* ufs_read_inode_data(ufs_t *mount, ufs_inode_t *inode)
|
|||
const uint32_t block_addr = (inode->direct[i] / mount->frag_per_block) * mount->frag_per_block;
|
||||
const uint32_t block_offset = (inode->direct[i] - block_addr) * mount->frag_size;
|
||||
|
||||
// printf("block_addr=0x%08x, block_offset")
|
||||
// slog("block_addr=0x%08x, block_offset")
|
||||
|
||||
// If the chunk_size is a whole block, then we better be reading in a whole block
|
||||
if (chunk_size == mount->block_size)
|
||||
|
@ -1032,7 +1022,7 @@ static uint8_t* ufs_read_inode_data(ufs_t *mount, ufs_inode_t *inode)
|
|||
memcpy(buf + len, block + block_offset, chunk_size);
|
||||
|
||||
len += chunk_size;
|
||||
// printf("direct block %u = 0x%08x\n", i, inode->direct[i]);
|
||||
// slog("direct block %u = 0x%08x\n", i, inode->direct[i]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1252,7 +1242,7 @@ uint8_t* shoebill_extract_kernel(const char *disk_path, const char *kernel_path,
|
|||
sprintf(error_str, "Couldn't find root partition");
|
||||
goto done;
|
||||
}
|
||||
printf("apm_part_num = %u\n", apm_part_num);
|
||||
slog("apm_part_num = %u\n", apm_part_num);
|
||||
|
||||
svfs_mount_obj = svfs_mount(&disk->partitions[apm_part_num]);
|
||||
if (svfs_mount_obj) {
|
||||
|
@ -1290,7 +1280,7 @@ uint8_t* shoebill_extract_kernel(const char *disk_path, const char *kernel_path,
|
|||
|
||||
done:
|
||||
if (strlen(error_str))
|
||||
printf("error: [%s]\n", error_str);
|
||||
slog("error: [%s]\n", error_str);
|
||||
if (disk)
|
||||
close_disk(disk);
|
||||
return kernel_data;
|
||||
|
@ -1306,7 +1296,7 @@ done:
|
|||
if (!buf)
|
||||
return 0;
|
||||
|
||||
FILE *f = fopen("result", "w");
|
||||
FILE *f = fopen("result", "wb");
|
||||
fwrite(buf, size, 1, f);
|
||||
fclose(f);
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
4275
core/fpu.c
|
@ -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);
|
||||
|
|
|
@ -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, PMMU_CACHE_SIZE/8);
|
||||
bzero(shoe.pmmu_cache[1].valid_map, PMMU_CACHE_SIZE/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, PMMU_CACHE_SIZE/8);
|
||||
bzero(shoe.pmmu_cache[1].valid_map, PMMU_CACHE_SIZE/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() {
|
||||
|
|
1169
core/mem.c
1240
core/old_debugger.c
1539
core/oldfpu.c
Normal 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);
|
||||
}
|
||||
|
||||
|
|
527
core/scsi.c
|
@ -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 * 256];
|
||||
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,83 +277,59 @@ 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);
|
||||
|
||||
|
@ -422,68 +341,136 @@ static void scsi_buf_set (uint8_t byte)
|
|||
}
|
||||
|
||||
assert(0 == fseeko(dev->f, 512 * offset, SEEK_SET));
|
||||
assert(fread(scsi.buf, len * 512, 1, dev->f) == 1);
|
||||
assert(fread(shoe.scsi.buf, len * 512, 1, dev->f) == 1);
|
||||
|
||||
|
||||
scsi.in_len = len * 512;
|
||||
scsi.in_i = 0;
|
||||
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);
|
||||
|
||||
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");
|
||||
|
@ -492,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;
|
||||
}
|
||||
|
@ -532,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)
|
||||
|
@ -561,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 ()
|
||||
|
@ -571,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 ;
|
||||
}
|
||||
|
@ -640,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -653,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 {
|
||||
|
||||
|
@ -667,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)
|
||||
|
@ -700,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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -747,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;
|
||||
}
|
||||
|
|
749
core/shoebill.h
|
@ -31,12 +31,156 @@
|
|||
#include <stdint.h>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
//#include <histedit.h>
|
||||
|
||||
// void ring_print(const char *str);
|
||||
// extern char *ring_tmp;
|
||||
|
||||
#include "coff.h"
|
||||
#if (defined WIN32) || (defined _WIN64)
|
||||
|
||||
#ifndef ntohl
|
||||
/* Assumes that all windows platforms are little endian */
|
||||
#define ntohs(_v) ({const uint16_t v = (_v); (v>>8) | (v<<8);})
|
||||
#define ntohl(_v) ({const uint32_t v = (_v); (v>>24) | (((v>>16)&0xff)<<8) | (((v>>8)&0xff)<<16) | ((v&0xff)<<24);})
|
||||
#define ntohll(_x) ({uint64_t x = (_x); (((uint64_t)ntohl((uint32_t)x))<<32) | ntohl(x>>32);})
|
||||
#define htons(_v) ntohs(_v)
|
||||
#define htonl(_v) ntohl(_v)
|
||||
#endif
|
||||
|
||||
#else /* #if (defined WIN32) || (defined _WIN64) */
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#if (defined __APPLE__)
|
||||
|
||||
#include <machine/endian.h>
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#ifndef ntohll
|
||||
#define ntohll(x) OSSwapBigToHostInt64(x)
|
||||
#endif
|
||||
#else /* #if (defined __APPLE__) */
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define ntohll(_x) ({uint64_t x = (_x); (((uint64_t)ntohl((uint32_t)x))<<32) | ntohl(x>>32);})
|
||||
#else
|
||||
#define ntohll(_x) (_x)
|
||||
#endif
|
||||
|
||||
#endif /* #if (defined __APPLE__) */
|
||||
#endif /* #if (defined WIN32) || (defined _WIN64) */
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define fix_endian(x) do { \
|
||||
switch (sizeof(x)) { \
|
||||
case 1: break; \
|
||||
case 2: (x) = ntohs(x); break; \
|
||||
case 4: (x) = ntohl(x); break; \
|
||||
case 8: (x) = ntohll(x); break; \
|
||||
default: assert(!"bogus size"); \
|
||||
}} while (0)
|
||||
#else
|
||||
#define fix_endian(x)
|
||||
#endif
|
||||
|
||||
|
||||
#define slikely(e) (__builtin_expect(!!(e), 1))
|
||||
#define sunlikely(e) (__builtin_expect(!!(e), 0))
|
||||
|
||||
/*
|
||||
* core_api.c stuff
|
||||
*/
|
||||
|
||||
|
||||
typedef void (*shoebill_pram_callback_t) (void *param, const uint8_t addr, const uint8_t byte);
|
||||
|
||||
typedef struct {
|
||||
uint32_t ram_size;
|
||||
const char *rom_path;
|
||||
const char *aux_kernel_path; // almost always "/unix"
|
||||
|
||||
_Bool aux_verbose : 1; // Whether to boot A/UX in verbose mode
|
||||
_Bool aux_autoconfig : 1; // Whether to run A/UX autoconfig
|
||||
_Bool debug_mode : 1; // Whether to enable hacks that debugger depends on
|
||||
|
||||
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;
|
||||
} scsi_devices[7]; // scsi id #7 is the initiator (can't be a target)
|
||||
|
||||
/* Initialize pram[] with initial PRAM data */
|
||||
uint8_t pram[256];
|
||||
|
||||
/*
|
||||
* This callback is called whenever a PRAM byte is changed.
|
||||
* It blocks the CPU, so try to return immediately.
|
||||
*/
|
||||
shoebill_pram_callback_t pram_callback;
|
||||
void *pram_callback_param;
|
||||
|
||||
char error_msg[8192];
|
||||
} shoebill_config_t;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *buf;
|
||||
uint16_t width, height, scan_width, depth;
|
||||
} shoebill_video_frame_info_t;
|
||||
|
||||
/* Take a shoebill_config_t structure and configure the global emulator context */
|
||||
uint32_t shoebill_initialize(shoebill_config_t *params);
|
||||
|
||||
void shoebill_restart (void);
|
||||
|
||||
/* Call this after shoebill_initialize() to configure a video card */
|
||||
uint32_t shoebill_install_video_card(shoebill_config_t *config, uint8_t slotnum,
|
||||
uint16_t width, uint16_t height);
|
||||
|
||||
uint32_t shoebill_install_tfb_card(shoebill_config_t *config, uint8_t slotnum);
|
||||
|
||||
/* Call this after shoebill_initialize() to add an ethernet card */
|
||||
uint32_t shoebill_install_ethernet_card(shoebill_config_t *config, uint8_t slotnum, uint8_t ethernet_addr[6], int tap_fd);
|
||||
|
||||
/* Get a video frame from a particular video card */
|
||||
shoebill_video_frame_info_t shoebill_get_video_frame(uint8_t slotnum, _Bool just_params);
|
||||
|
||||
/* Call this after rendering a video frame to send a VBL interrupt */
|
||||
void shoebill_send_vbl_interrupt(uint8_t slotnum);
|
||||
|
||||
/* Call to validate input pram and zap if invalid */
|
||||
void shoebill_validate_or_zap_pram(uint8_t *pram, _Bool forcezap);
|
||||
|
||||
/*
|
||||
* 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();
|
||||
void shoebill_stop();
|
||||
|
||||
void slog(const char *fmt, ...);
|
||||
|
||||
uint8_t* shoebill_extract_kernel(const char *disk_path, const char *kernel_path, char *error_str, uint32_t *len);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Internal shoebill stuff
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// -- Global constants --
|
||||
|
||||
|
@ -100,7 +244,7 @@
|
|||
// set the status register, swapping a7 if necessary
|
||||
#define set_sr(newsr) { \
|
||||
make_stack_pointers_valid(); \
|
||||
shoe.sr = newsr & 0xf71f; \
|
||||
shoe.sr = (newsr) & 0xf71f; \
|
||||
load_stack_pointer(); \
|
||||
}
|
||||
|
||||
|
@ -117,11 +261,11 @@
|
|||
#define set_sr_t1(b) {shoe.sr &= (~(1<<15)); shoe.sr |= (((b)!=0)<<15);}
|
||||
|
||||
// MMU
|
||||
#define tc_enable() (shoe.tc >> 31)
|
||||
#define tc_sre() ((shoe.tc >> 25) & 1)
|
||||
#define _tc_enable() (shoe.tc >> 31) // _tc_enable,sre,ps,is are all extracted in shoe.tc_*
|
||||
#define _tc_sre() ((shoe.tc >> 25) & 1)
|
||||
#define tc_fcl() ((shoe.tc >> 24) & 1)
|
||||
#define tc_ps() ((shoe.tc >> 20) & 0xf)
|
||||
#define tc_is() ((shoe.tc >> 16) & 0xf)
|
||||
#define _tc_ps() ((shoe.tc >> 20) & 0xf)
|
||||
#define _tc_is() ((shoe.tc >> 16) & 0xf)
|
||||
#define tc_tia() ((shoe.tc >> 12) & 0xf)
|
||||
#define tc_tib() ((shoe.tc >> 8) & 0xf)
|
||||
#define tc_tic() ((shoe.tc >> 4) & 0xf)
|
||||
|
@ -138,18 +282,124 @@
|
|||
#define ea_n(s) ((shoe.dat>>((s)*8-1))&1)
|
||||
#define ea_z(s) (chop(shoe.dat, (s))==0)
|
||||
|
||||
// alloc_pool.c
|
||||
/*
|
||||
* alloc_pool.c
|
||||
*/
|
||||
#define POOL_START_MAGIC 0x231eb4af
|
||||
#define POOL_END_MAGIC 0xb09f39f1
|
||||
#define POOL_ALLOC_TYPE 0
|
||||
#define POOL_CHILD_LINK 1
|
||||
#define POOL_HEAD 2
|
||||
typedef struct _alloc_pool_t {
|
||||
uint32_t start_magic;
|
||||
struct _alloc_pool_t *prev, *next;
|
||||
uint32_t size, magic;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint64_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 type;
|
||||
uint32_t end_magic;
|
||||
} alloc_pool_t;
|
||||
|
||||
void* p_alloc(alloc_pool_t *pool, uint64_t size);
|
||||
void* p_realloc(void *ptr, uint64_t size);
|
||||
void p_free(void *ptr);
|
||||
void p_free_pool(alloc_pool_t *pool);
|
||||
alloc_pool_t* p_new_pool(void);
|
||||
alloc_pool_t* p_new_pool(alloc_pool_t *parent_pool);
|
||||
|
||||
/*
|
||||
* redblack.c
|
||||
*/
|
||||
|
||||
typedef uint32_t rb_key_t;
|
||||
|
||||
typedef struct _rb_node {
|
||||
struct _rb_node *left, *right, *parent;
|
||||
rb_key_t key;
|
||||
uint8_t is_red : 1;
|
||||
} rb_node;
|
||||
|
||||
typedef struct {
|
||||
rb_node *root;
|
||||
alloc_pool_t *pool;
|
||||
uint32_t sz;
|
||||
} rb_tree;
|
||||
|
||||
|
||||
rb_tree* rb_new(alloc_pool_t *pool, uint32_t sz);
|
||||
void rb_free (rb_tree *tree);
|
||||
|
||||
uint8_t rb_insert (rb_tree *root, rb_key_t key, void *value, void *old_value);
|
||||
uint8_t rb_find (rb_tree *tree, rb_key_t key, void *value);
|
||||
uint8_t rb_index (rb_tree *tree, uint32_t index, rb_key_t *key, void *value);
|
||||
uint32_t rb_count (rb_tree *tree);
|
||||
|
||||
|
||||
/*
|
||||
* coff.c
|
||||
*/
|
||||
|
||||
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;
|
||||
alloc_pool_t *pool;
|
||||
} 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_parse(uint8_t *buf, uint32_t buflen, alloc_pool_t *parent_pool);
|
||||
coff_file* coff_parse_from_path(const char *path, alloc_pool_t *parent_pool);
|
||||
void coff_free(coff_file *coff);
|
||||
uint32_t be2native (uint8_t **dat, uint32_t bytes);
|
||||
void print_coff_info(coff_file *coff);
|
||||
|
||||
|
||||
typedef struct dbg_breakpoint_t {
|
||||
|
@ -167,6 +417,27 @@ typedef struct {
|
|||
dbg_breakpoint_t *breakpoints;
|
||||
} debugger_state_t;
|
||||
|
||||
// Sound (Apple Sound Chip)
|
||||
void sound_dma_write_raw(uint16_t addr, uint8_t sz, uint32_t data);
|
||||
uint32_t sound_dma_read_raw(uint16_t addr, uint8_t sz);
|
||||
void init_asc_state(void);
|
||||
|
||||
typedef struct {
|
||||
uint8_t buf[0x800];
|
||||
uint8_t version; // read-only
|
||||
uint8_t asc_mode;
|
||||
uint8_t channel_ctrl;
|
||||
uint8_t fifo_ctrl;
|
||||
uint8_t fifo_intr; // read-only
|
||||
uint8_t unknown1;
|
||||
uint8_t volume_ctrl;
|
||||
uint8_t clock_ctrl;
|
||||
|
||||
|
||||
uint16_t left_ptr, right_ptr;
|
||||
} apple_sound_chip_registers_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
adb_talk,
|
||||
adb_listen,
|
||||
|
@ -196,9 +467,40 @@ typedef struct {
|
|||
} adb_state_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t ifr, ier, rega, regb, ddrb, ddra, sr;
|
||||
uint8_t ifr, ier, ddrb, ddra, sr, acr, pcr;
|
||||
|
||||
uint8_t rega_input, regb_input;
|
||||
uint8_t rega_output, regb_output;
|
||||
|
||||
uint16_t t1c, t2c, t1l;
|
||||
long double t1_last_set, t2_last_set;
|
||||
_Bool /*t1_interrupt_enabled,*/ t2_interrupt_enabled; // whether the "one-shot" interrupt can fire
|
||||
} via_state_t;
|
||||
|
||||
#define PRAM_READ 1
|
||||
#define PRAM_WRITE 2
|
||||
typedef struct {
|
||||
uint8_t data[256];
|
||||
uint8_t last_bits;
|
||||
|
||||
// FSM
|
||||
uint8_t command[8];
|
||||
uint8_t byte, mode, command_i, bit_i;
|
||||
|
||||
shoebill_pram_callback_t callback;
|
||||
void *callback_param;
|
||||
} pram_state_t;
|
||||
|
||||
void init_via_state (uint8_t pram_data[256], shoebill_pram_callback_t callback, void *callback_param);
|
||||
void init_adb_state();
|
||||
void init_scsi_bus_state();
|
||||
void init_iwm_state();
|
||||
|
||||
void reset_via_state();
|
||||
void reset_adb_state();
|
||||
void reset_scsi_bus_state();
|
||||
void reset_iwm_state();
|
||||
|
||||
typedef struct {
|
||||
uint8_t scsi_id;
|
||||
uint32_t num_blocks, block_size;
|
||||
|
@ -224,22 +526,6 @@ typedef struct {
|
|||
uint8_t changed;
|
||||
} mouse_state_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *buf_base;
|
||||
uint32_t buf_size;
|
||||
|
||||
uint32_t h_offset; // offset in bytes for each horizontal line
|
||||
|
||||
uint8_t vsync;
|
||||
|
||||
// unit8_t via_interrupt_flag;
|
||||
|
||||
uint8_t depth;
|
||||
uint8_t clut[256 * 3];
|
||||
uint32_t clut_idx;
|
||||
|
||||
} video_state_t;
|
||||
|
||||
typedef struct {
|
||||
// lsb==phase0, msb==L7
|
||||
uint8_t latch;
|
||||
|
@ -248,14 +534,163 @@ typedef struct {
|
|||
uint8_t data, status, mode, handshake;
|
||||
} iwm_state_t;
|
||||
|
||||
enum scsi_bus_phase {
|
||||
BUS_FREE = 0,
|
||||
ARBITRATION,
|
||||
SELECTION,
|
||||
RESELECTION,
|
||||
COMMAND,
|
||||
DATA_OUT,
|
||||
DATA_IN,
|
||||
STATUS,
|
||||
MESSAGE_IN,
|
||||
MESSAGE_OUT
|
||||
};
|
||||
|
||||
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 * 256];
|
||||
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;
|
||||
|
||||
typedef struct {
|
||||
uint8_t r, g, b, a;
|
||||
} video_ctx_color_t;
|
||||
|
||||
typedef struct {
|
||||
video_ctx_color_t *temp_buf, *clut;
|
||||
uint8_t *rom, *direct_buf;
|
||||
|
||||
uint32_t pixels;
|
||||
|
||||
uint16_t width, height, scanline_width, line_offset;
|
||||
|
||||
uint16_t depth, clut_idx;
|
||||
} shoebill_card_video_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *direct_buf, *temp_buf, *clut, *rom;
|
||||
uint16_t depth, clut_idx, line_offset;
|
||||
uint8_t vsync;
|
||||
} shoebill_card_tfb_t;
|
||||
|
||||
typedef struct {
|
||||
// Card ROM (4kb)
|
||||
uint8_t rom[0x1000];
|
||||
|
||||
// Card RAM (16kb buffer, apparently)
|
||||
uint8_t ram[0x4000];
|
||||
|
||||
// Card MAC address
|
||||
uint8_t ethernet_addr[6];
|
||||
|
||||
// Card slot number
|
||||
uint8_t slotnum;
|
||||
|
||||
// -- thread state --
|
||||
uint8_t recv_buf[4096], send_buf[4096];
|
||||
uint16_t recv_len, send_len;
|
||||
_Bool teardown, send_ready;
|
||||
|
||||
pthread_t sender_pid, receiver_pid;
|
||||
pthread_mutex_t lock, sender_cond_mutex;
|
||||
pthread_cond_t sender_cond;
|
||||
|
||||
// -- registers --
|
||||
|
||||
uint8_t cr; // command register, all pages, read/write
|
||||
|
||||
// Page 0 registers
|
||||
uint8_t isr; // interrupt status register, read/write
|
||||
uint8_t imr; // interrupt mask register, write
|
||||
|
||||
uint8_t dcr; // data configuration register (write)
|
||||
uint8_t tcr; // transmit configuration register (write)
|
||||
uint8_t rcr; // receive configuration register (write)
|
||||
|
||||
uint8_t pstart; // receive buffer start pointer (write)
|
||||
uint8_t pstop; // receive buffer boundary (write)
|
||||
uint8_t bnry; // a different kind of receive buffer boundary (read/write)
|
||||
|
||||
uint8_t tpsr; // transmit page start pointer (write)
|
||||
uint16_t tbcr; // transmit buffer count register (write)
|
||||
|
||||
uint8_t rsr; // receive status register (read)
|
||||
|
||||
|
||||
// Page 1 registers (read/write)
|
||||
uint8_t mar[8]; // multicast address
|
||||
uint8_t par[6]; // physical address
|
||||
uint8_t curr; // current page
|
||||
|
||||
|
||||
int tap_fd;
|
||||
} shoebill_card_ethernet_t;
|
||||
|
||||
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 // "Register-compatible" Apple EtherTalk card
|
||||
} card_names_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t (*read_func)(uint32_t, uint32_t, uint8_t);
|
||||
void (*write_func)(uint32_t, uint32_t, uint32_t, uint8_t);
|
||||
void (*destroy_func)(uint8_t);
|
||||
|
||||
uint8_t slotnum;
|
||||
_Bool connected;
|
||||
_Bool interrupts_enabled;
|
||||
|
||||
void *ctx;
|
||||
uint8_t slotnum, connected, interrupts_enabled;
|
||||
int32_t glut_window_id;
|
||||
long double interrupt_rate, last_fired;
|
||||
card_names_t card_type;
|
||||
} nubus_card_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -274,25 +709,31 @@ typedef struct {
|
|||
|
||||
} via_clock_t;
|
||||
|
||||
#define unstop_cpu_thread() do {\
|
||||
assert(pthread_mutex_lock(&shoe.cpu_stop_mutex) == 0); \
|
||||
assert(pthread_cond_signal(&shoe.cpu_stop_cond) == 0); \
|
||||
assert(pthread_mutex_unlock(&shoe.cpu_stop_mutex) == 0); \
|
||||
} while (0)
|
||||
|
||||
typedef struct {
|
||||
|
||||
#define SHOEBILL_STATE_STOPPED (1<<9)
|
||||
_Bool running;
|
||||
|
||||
#define SHOEBILL_STATE_STOPPED (1 << 8)
|
||||
#define SHOEBILL_STATE_RETURN (1 << 9)
|
||||
|
||||
// bits 0-6 are CPU interrupt priorities
|
||||
// bit 8 indicates that STOP was called
|
||||
volatile uint32_t cpu_thread_notifications;
|
||||
volatile uint32_t via_thread_notifications;
|
||||
|
||||
pthread_mutex_t cpu_thread_lock;
|
||||
pthread_mutex_t via_clock_thread_lock;
|
||||
pthread_mutex_t cpu_freeze_lock;
|
||||
pthread_mutex_t via_clock_thread_lock; // synchronizes shoebill_start() and the starting of via_clock_thread()
|
||||
pthread_mutex_t via_cpu_lock; // synchronizes reads/writes of VIA registers and via_clock_thread()
|
||||
|
||||
// -- PMMU caching structures ---
|
||||
#define PMMU_CACHE_KEY_BITS 10
|
||||
#define PMMU_CACHE_SIZE (1<<PMMU_CACHE_KEY_BITS)
|
||||
struct {
|
||||
pmmu_cache_entry_t entry[PMMU_CACHE_SIZE];
|
||||
uint8_t valid_map[PMMU_CACHE_SIZE / 8];
|
||||
} pmmu_cache[2];
|
||||
// The pthread condition/mutex pair for yielding CPU on STOP, and waking up upon receiving an interrupt
|
||||
pthread_mutex_t cpu_stop_mutex;
|
||||
pthread_cond_t cpu_stop_cond;
|
||||
|
||||
// -- Assorted CPU state variables --
|
||||
uint16_t op; // the first word of the instruction we're currently running
|
||||
|
@ -318,18 +759,26 @@ typedef struct {
|
|||
_Bool logical_is_write; // <- boolean: true iff the operation is logical_set()
|
||||
uint8_t logical_fc; // logical function code
|
||||
|
||||
// -- Interrupts/VIA chips --
|
||||
#define invalidate_pccache() do {shoe.pccache_use_srp = 2;} while (0)
|
||||
uint32_t pccache_use_srp; // 1 -> use srp, 0 -> use crp, other -> pccache is invalid
|
||||
uint32_t pccache_logical_page;
|
||||
uint8_t *pccache_ptr;
|
||||
|
||||
// uint8_t stopped; // whether STOP was called
|
||||
// uint8_t pending_interrupt; // (0 -> no pending interrupt, >0 -> interrupt priority (autovector))
|
||||
via_state_t via[2];
|
||||
adb_state_t adb;
|
||||
keyboard_state_t key;
|
||||
mouse_state_t mouse;
|
||||
iwm_state_t iwm;
|
||||
// -- PMMU caching structures ---
|
||||
#define PMMU_CACHE_KEY_BITS 10
|
||||
#define PMMU_CACHE_SIZE (1<<PMMU_CACHE_KEY_BITS)
|
||||
struct {
|
||||
pmmu_cache_entry_t entry[PMMU_CACHE_SIZE];
|
||||
uint8_t valid_map[PMMU_CACHE_SIZE / 8];
|
||||
} pmmu_cache[2];
|
||||
|
||||
nubus_card_t slots[16];
|
||||
// video_state_t video;
|
||||
// -- EA state --
|
||||
uint32_t uncommitted_ea_read_pc; // set by ea_read(). It's the PC that ea_read_commit will set.
|
||||
uint64_t dat; // the raw input/output for the transaction
|
||||
uint32_t extended_addr; // EA returned by ea_decode_extended()
|
||||
uint32_t extended_len; // number of instruction bytes used by ea_decode_extended()
|
||||
uint8_t sz; // the size of the EA transaction
|
||||
uint8_t mr; // a 6-bit mode/reg pair
|
||||
|
||||
// -- Registers --
|
||||
uint32_t d[8];
|
||||
|
@ -350,6 +799,10 @@ typedef struct {
|
|||
// 68851 registers
|
||||
uint64_t crp, srp, drp; // user/supervisor/DMA root pointers
|
||||
uint32_t tc; // translation control
|
||||
|
||||
uint32_t tc_pagesize, tc_pagemask; // page size and page mask
|
||||
uint8_t tc_ps, tc_is, tc_is_plus_ps, tc_enable, tc_sre; // commonly read bits in shoe.tc
|
||||
|
||||
uint16_t pcsr; // PMMU cache status
|
||||
uint16_t ac; // access control
|
||||
uint16_t bad[8]; // breakpoint acknowledge data registers
|
||||
|
@ -374,93 +827,63 @@ typedef struct {
|
|||
} bits;
|
||||
} psr;
|
||||
|
||||
// FPU registers
|
||||
uint32_t fpiar; // FPU iaddr
|
||||
|
||||
union { // fpcr, fpu control register
|
||||
struct {
|
||||
// Mode control byte
|
||||
uint16_t mc_zero : 4; // zero/dummy
|
||||
uint16_t mc_rnd : 2; // rounding mode
|
||||
uint16_t mc_prec : 2; // rounding precision
|
||||
// Exception enable byte
|
||||
uint16_t ee_inex1 : 1; // inexact decimal input
|
||||
uint16_t ee_inex2 : 1; // inxact operation
|
||||
uint16_t ee_dz : 1; // divide by zero
|
||||
uint16_t ee_unfl : 1; // underflow
|
||||
uint16_t ee_ovfl : 1; // overflow
|
||||
uint16_t ee_operr : 1; // operand error
|
||||
uint16_t ee_snan : 1; // signalling not a number
|
||||
uint16_t ee_bsun : 1; // branch/set on unordered
|
||||
} b;
|
||||
|
||||
uint16_t raw;
|
||||
} fpcr;
|
||||
|
||||
union { // fpsr, fpu status register
|
||||
struct {
|
||||
// Accrued exception byte
|
||||
uint32_t dummy1 : 3; // dummy/zero
|
||||
uint32_t ae_inex : 1; // inexact
|
||||
uint32_t ae_dz : 1; // divide by zero
|
||||
uint32_t ae_unfl : 1; // underflow
|
||||
uint32_t ae_ovfl : 1; // overflow
|
||||
uint32_t ae_iop : 1; // invalid operation
|
||||
// Exception status byte
|
||||
uint32_t es_inex1 : 1; // inexact decimal input
|
||||
uint32_t es_inex2 : 1; // inxact operation
|
||||
uint32_t es_dz : 1; // divide by zero
|
||||
uint32_t es_unfl : 1; // underflow
|
||||
uint32_t es_ovfl : 1; // overflow
|
||||
uint32_t es_operr : 1; // operand error
|
||||
uint32_t es_snan : 1; // signalling not a number
|
||||
uint32_t es_bsun : 1; // branch/set on unordered
|
||||
// Quotient byte
|
||||
uint32_t qu_quotient : 7;
|
||||
uint32_t qu_s : 1;
|
||||
// Condition code byte
|
||||
uint32_t cc_nan : 1; // not a number
|
||||
uint32_t cc_i : 1; // infinity
|
||||
uint32_t cc_z : 1; // zero
|
||||
uint32_t cc_n : 1; // negative
|
||||
uint32_t dummy2 : 4; // dummy/zero
|
||||
} b;
|
||||
uint32_t raw;
|
||||
} fpsr;
|
||||
|
||||
long double fp[8]; // 80 bit floating point general registers
|
||||
// fpu_state_t pointer
|
||||
// (declared here as a void*, to prevent other files
|
||||
// from needing to include SoftFloat/softfloat.h)
|
||||
void *fpu_state;
|
||||
|
||||
|
||||
// -- EA state --
|
||||
uint32_t uncommitted_ea_read_pc; // set by ea_read(). It's the PC that ea_read_commit will set.
|
||||
uint64_t dat; // the raw input/output for the transaction
|
||||
uint32_t extended_addr; // EA returned by ea_decode_extended()
|
||||
uint32_t extended_len; // number of instruction bytes used by ea_decode_extended()
|
||||
uint8_t sz; // the size of the EA transaction
|
||||
uint8_t mr; // a 6-bit mode/reg pair
|
||||
// -- Interrupts/VIA chips --
|
||||
|
||||
via_state_t via[2];
|
||||
via_clock_t via_clocks;
|
||||
adb_state_t adb;
|
||||
pram_state_t pram;
|
||||
keyboard_state_t key;
|
||||
mouse_state_t mouse;
|
||||
apple_sound_chip_registers_t asc;
|
||||
|
||||
iwm_state_t iwm;
|
||||
|
||||
struct timeval start_time; // when the emulator started (for computing timer interrupts)
|
||||
uint64_t total_ticks; // how many 60hz ticks have been generated
|
||||
scsi_bus_state_t scsi;
|
||||
scsi_device_t scsi_devices[8]; // SCSI devices
|
||||
|
||||
nubus_card_t slots[16];
|
||||
|
||||
coff_file *coff; // Data/symbols from the unix kernel
|
||||
|
||||
coff_file *launch; // FIXME: delete me: coff symbols from aux 1.1.1 launch binary
|
||||
|
||||
scsi_device_t scsi_devices[8]; // SCSI devices
|
||||
pthread_t cpu_thread_pid, via_thread_pid;
|
||||
|
||||
debugger_state_t dbg;
|
||||
alloc_pool_t *pool;
|
||||
|
||||
shoebill_config_t config_copy; // copy of the config structure passed to shoebill_initialize()
|
||||
} global_shoebill_context_t;
|
||||
|
||||
extern global_shoebill_context_t shoe; // declared in cpu.c
|
||||
|
||||
// fpu.c functions
|
||||
void inst_fpu_decode(void);
|
||||
void dis_fpu_decode(void);
|
||||
void fpu_setup_jump_table();
|
||||
void inst_fscc();
|
||||
void inst_fbcc();
|
||||
void inst_fsave();
|
||||
void inst_frestore();
|
||||
void inst_ftrapcc();
|
||||
void inst_fdbcc();
|
||||
void inst_fnop();
|
||||
void inst_fpu_other();
|
||||
|
||||
void dis_fscc();
|
||||
void dis_fbcc();
|
||||
void dis_fsave();
|
||||
void dis_frestore();
|
||||
void dis_ftrapcc();
|
||||
void dis_fdbcc();
|
||||
void dis_fnop();
|
||||
void dis_fpu_other();
|
||||
void dis_fmath (uint16_t op, uint16_t ext, char *output);
|
||||
|
||||
void fpu_initialize();
|
||||
void fpu_reset();
|
||||
|
||||
// cpu.c fuctions
|
||||
void cpu_step (void);
|
||||
|
@ -475,10 +898,14 @@ void throw_illegal_instruction();
|
|||
void throw_privilege_violation();
|
||||
void throw_divide_by_zero();
|
||||
void throw_frame_two (uint16_t sr, uint32_t next_pc, uint32_t vector_num, uint32_t orig_pc);
|
||||
void throw_frame_zero(uint16_t sr, uint32_t pc, uint16_t vector_num);
|
||||
|
||||
|
||||
// mem.c functions
|
||||
|
||||
uint16_t pccache_nextword(uint32_t pc);
|
||||
uint32_t pccache_nextlong(uint32_t pc);
|
||||
|
||||
//void physical_get (void);
|
||||
typedef void (*physical_get_ptr) (void);
|
||||
typedef void (*physical_set_ptr) (void);
|
||||
|
@ -486,7 +913,12 @@ extern const physical_get_ptr physical_get_jump_table[16];
|
|||
extern const physical_set_ptr physical_set_jump_table[16];
|
||||
|
||||
#define physical_set() physical_set_jump_table[shoe.physical_addr >> 28]()
|
||||
#define pset(addr, s, val) {shoe.physical_addr=(addr); shoe.physical_size=(s); shoe.physical_dat=(val); physical_set();}
|
||||
#define pset(addr, s, val) do { \
|
||||
shoe.physical_addr=(addr); \
|
||||
shoe.physical_size=(s); \
|
||||
shoe.physical_dat=(val); \
|
||||
physical_set(); \
|
||||
} while (0)
|
||||
|
||||
#define physical_get() physical_get_jump_table[shoe.physical_addr >> 28]()
|
||||
#define pget(addr, s) ({shoe.physical_addr=(addr); shoe.physical_size=(s); physical_get(); shoe.physical_dat;})
|
||||
|
@ -499,37 +931,34 @@ void logical_get (void);
|
|||
logical_get(); \
|
||||
shoe.logical_dat; \
|
||||
})
|
||||
|
||||
#define lget(addr, s) ({ \
|
||||
shoe.logical_addr=(addr); \
|
||||
shoe.logical_size=(s); \
|
||||
shoe.logical_fc = (sr_s() ? 5 : 1); \
|
||||
logical_get(); \
|
||||
shoe.logical_dat; \
|
||||
})
|
||||
#define lget(addr, s) lget_fc((addr), (s), (sr_s() ? 5 : 1))
|
||||
|
||||
void logical_set (void);
|
||||
#define lset_fc(addr, s, val, fc) {\
|
||||
#define lset_fc(addr, s, val, fc) do { \
|
||||
shoe.logical_addr=(addr); \
|
||||
shoe.logical_size=(s); \
|
||||
shoe.logical_dat=(val); \
|
||||
shoe.logical_fc = (fc); \
|
||||
logical_set();\
|
||||
}
|
||||
#define lset(addr, s, val) { \
|
||||
lset_fc((addr), (s), (val), sr_s() ? 5 : 1) \
|
||||
}
|
||||
} while (0)
|
||||
#define lset(addr, s, val) lset_fc((addr), (s), (val), sr_s() ? 5 : 1)
|
||||
|
||||
typedef void (*_ea_func) (void);
|
||||
extern const _ea_func ea_read_jump_table[64];
|
||||
extern const _ea_func ea_read_commit_jump_table[64];
|
||||
extern const _ea_func ea_write_jump_table[64];
|
||||
extern const _ea_func ea_addr_jump_table[64];
|
||||
|
||||
#define ea_read() ea_read_jump_table[shoe.mr]()
|
||||
#define ea_read_commit() ea_read_commit_jump_table[shoe.mr]()
|
||||
#define ea_write() ea_write_jump_table[shoe.mr]()
|
||||
#define ea_addr() ea_addr_jump_table[shoe.mr]()
|
||||
|
||||
|
||||
void ea_read();
|
||||
void ea_read_commit();
|
||||
void ea_write();
|
||||
void ea_addr();
|
||||
|
||||
#define call_ea_read(M, s) {shoe.mr=(M);shoe.sz=(s);ea_read();if (shoe.abort) return;}
|
||||
#define call_ea_write(M, s) {shoe.mr=(M);shoe.sz=(s);ea_write();if (shoe.abort) return;}
|
||||
#define call_ea_read_commit(M, s) {shoe.mr=(M);shoe.sz=(s);ea_read_commit();if (shoe.abort) return;}
|
||||
#define call_ea_addr(M) {shoe.mr=(M);ea_addr();if (shoe.abort) return;}
|
||||
#define call_ea_read(M, s) {shoe.mr=(M);shoe.sz=(s);ea_read();if sunlikely(shoe.abort) return;}
|
||||
#define call_ea_write(M, s) {shoe.mr=(M);shoe.sz=(s);ea_write();if sunlikely(shoe.abort) return;}
|
||||
#define call_ea_read_commit(M, s) {shoe.mr=(M);shoe.sz=(s);ea_read_commit();if sunlikely(shoe.abort) return;}
|
||||
#define call_ea_addr(M) {shoe.mr=(M);ea_addr();if sunlikely(shoe.abort) return;}
|
||||
|
||||
#define push_a7(_dat, _sz) {shoe.a[7]-=(_sz);lset(shoe.a[7], (_sz), (_dat));}
|
||||
|
||||
|
@ -549,9 +978,6 @@ void ea_addr();
|
|||
desc_addr = (_addr); \
|
||||
desc_level++; \
|
||||
}
|
||||
// if (shoe.dbg) \
|
||||
// printf("desc_addr *0x%08x = 0x%llx\n", (uint32_t)(_addr), desc); \
|
||||
// }
|
||||
|
||||
|
||||
// dis.c functions
|
||||
|
@ -589,11 +1015,10 @@ void scsi_dma_write(uint8_t byte);
|
|||
void scsi_dma_write_long(uint32_t dat);
|
||||
|
||||
// via1 & via2 (+ CPU interrupts)
|
||||
void check_time();
|
||||
void via_raise_interrupt(uint8_t vianum, uint8_t ifr_bit);
|
||||
void process_pending_interrupt();
|
||||
void via_reg_read();
|
||||
void via_reg_write();
|
||||
void via_read_raw();
|
||||
void via_write_raw();
|
||||
void *via_clock_thread(void *arg);
|
||||
|
||||
// VIA registers
|
||||
|
@ -620,8 +1045,8 @@ void *via_clock_thread(void *arg);
|
|||
#define IFR_SHIFT_REG 2
|
||||
#define IFR_CB2 3
|
||||
#define IFR_CB1 4
|
||||
#define IFR_TIMER1 5
|
||||
#define IFR_TIMER2 6
|
||||
#define IFR_TIMER2 5
|
||||
#define IFR_TIMER1 6
|
||||
#define IFR_IRQ 7
|
||||
|
||||
// adb / keyboard / mouse stuff
|
||||
|
@ -638,23 +1063,27 @@ struct macii_rom_symbols_t {
|
|||
extern const struct macii_rom_symbols_t macii_rom_symbols[];
|
||||
|
||||
// Emulated Toby Frame Buffer nubus card
|
||||
void nubus_tfb_init(uint8_t slotnum);
|
||||
void nubus_tfb_init(void *_ctx, uint8_t slotnum);
|
||||
uint32_t nubus_tfb_read_func(uint32_t, uint32_t, uint8_t);
|
||||
void nubus_tfb_write_func(uint32_t, uint32_t, uint32_t, uint8_t);
|
||||
shoebill_video_frame_info_t nubus_tfb_get_frame(shoebill_card_tfb_t *ctx,
|
||||
_Bool just_params);
|
||||
|
||||
// Shoebill Virtual Video Card
|
||||
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);
|
||||
|
||||
uint32_t nubus_video_read_func(const uint32_t rawaddr, const uint32_t size,
|
||||
const uint8_t slotnum);
|
||||
void nubus_video_write_func(const uint32_t rawaddr, const uint32_t size,
|
||||
const uint32_t data, const uint8_t slotnum);
|
||||
shoebill_video_frame_info_t nubus_video_get_frame(shoebill_card_video_t *ctx,
|
||||
_Bool just_params);
|
||||
|
||||
// debug_server.c
|
||||
void *debug_cpu_thread (void *arg);
|
||||
|
||||
|
||||
// Apple EtherTalk
|
||||
void nubus_ethernet_init(void *_ctx, uint8_t slotnum, uint8_t ethernet_addr[6], int tap_fd);
|
||||
uint32_t nubus_ethernet_read_func(uint32_t, uint32_t, uint8_t);
|
||||
void nubus_ethernet_write_func(uint32_t, uint32_t, uint32_t, uint8_t);
|
||||
void nubus_ethernet_destroy_func(uint8_t);
|
||||
|
||||
#endif // _SHOEBILL_H
|
||||
|
|
279
core/sound.c
Normal 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, doesn’t preserve any written bits (doesn’t 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
729
core/via.c
|
@ -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,12 +102,11 @@ void process_pending_interrupt ()
|
|||
return ;
|
||||
}
|
||||
|
||||
// If the CPU was stopped, unstop it
|
||||
shoe.cpu_thread_notifications &= ~~SHOEBILL_STATE_STOPPED;
|
||||
|
||||
const uint16_t vector_offset = (priority + 24) * 4;
|
||||
|
||||
printf("Interrupt pri %u! mask=%u vector_offset=0x%08x\n", priority, sr_mask(), vector_offset);
|
||||
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;
|
||||
|
@ -109,15 +114,15 @@ void process_pending_interrupt ()
|
|||
|
||||
// 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()) {
|
||||
|
@ -147,7 +152,7 @@ void process_pending_interrupt ()
|
|||
|
||||
// Fetch the autovector handler address
|
||||
const uint32_t newpc = lget(shoe.vbr + vector_offset, 4);
|
||||
printf("autovector handler = *0x%08x = 0x%08x\n", shoe.vbr + vector_offset, newpc);
|
||||
slog("autovector handler = *0x%08x = 0x%08x\n", shoe.vbr + vector_offset, newpc);
|
||||
assert(!shoe.abort);
|
||||
|
||||
shoe.pc = newpc;
|
||||
|
@ -156,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
|
||||
|
@ -202,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: {
|
||||
|
@ -300,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;
|
||||
|
@ -422,30 +858,25 @@ void *via_clock_thread(void *arg)
|
|||
via_raise_interrupt(2, IFR_TIMER2);*/
|
||||
}
|
||||
|
||||
// Check if any nubus cards have interrupt timers
|
||||
shoe.via[1].rega = 0b00111111;
|
||||
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));
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
244
core/video.c
|
@ -27,7 +27,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "shoebill.h"
|
||||
#include "core_api.h"
|
||||
|
||||
#include "video_rom/rom.c"
|
||||
|
||||
|
@ -55,7 +54,7 @@ typedef struct __attribute__ ((__packed__)) {
|
|||
uint32_t plane_bytes;
|
||||
} video_params_t;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -79,30 +78,27 @@ uint32_t compute_nubus_crc(uint8_t *rom, uint32_t len)
|
|||
static void _switch_depth(shoebill_card_video_t *ctx, uint32_t depth)
|
||||
{
|
||||
ctx->depth = depth;
|
||||
if (depth > 8)
|
||||
ctx->cur_buf = (uint8_t*)ctx->direct_buf;
|
||||
else
|
||||
ctx->cur_buf = ctx->indexed_buf;
|
||||
}
|
||||
|
||||
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
|
||||
_switch_depth(ctx, 1);
|
||||
bzero(ctx->clut, 256 * 4);
|
||||
memset(ctx->clut, 0, 256 * 4);
|
||||
ctx->clut[0].r = 0xff;
|
||||
ctx->clut[0].g = 0xff;
|
||||
ctx->clut[0].b = 0xff;
|
||||
|
@ -128,13 +124,13 @@ 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].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);*/
|
||||
params[5].bottom = htons(height);
|
||||
|
||||
// Recompute the rom crc
|
||||
compute_nubus_crc(ctx->rom, 4096);
|
||||
|
@ -149,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) {
|
||||
|
@ -175,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)
|
||||
|
@ -207,7 +248,7 @@ 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
|
||||
|
@ -235,35 +276,62 @@ void nubus_video_write_func(const uint32_t rawaddr, const uint32_t size,
|
|||
assert(!"driver tried to set bogus depth");
|
||||
}
|
||||
_switch_depth(ctx, newdepth);
|
||||
printf("nubus_magic: set depth = %u\n", ctx->depth);
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -272,20 +340,112 @@ void nubus_video_write_func(const uint32_t rawaddr, const uint32_t size,
|
|||
|
||||
// Else, this is video ram
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
2
core/video_rom/shoebill_video_driver.a
Normal file → Executable file
2
core/video_rom/shoebill_video_primary_init.a
Normal file → Executable 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
1
core/video_rom/shoebill_video_secondary_init.a
Executable 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
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
@ -260,6 +283,7 @@
|
|||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
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;
|
||||
|
@ -299,6 +323,7 @@
|
|||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
@ -17,11 +17,11 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.0.2</string>
|
||||
<string>0.0.5</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.0.2</string>
|
||||
<string>0.0.5</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>NSMainNibFile</key>
|
||||
|
|
|
@ -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)}
|
||||
}
|
|
@ -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;
|
||||
|
||||
[((shoeApplication*)NSApp) zapPram:defaults ptr:nil];
|
||||
[defaults setObject:@"/unix" forKey:@"rootKernelPath"];
|
||||
[defaults setObject:@"" forKey:@"romPath"];
|
||||
[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,6 +51,7 @@
|
|||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
uint32_t i;
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
BOOL isInitialized = [defaults boolForKey:@"defaultsInitialized"];
|
||||
|
@ -56,9 +59,33 @@
|
|||
if (!isInitialized)
|
||||
[self createFirstTimeUserDefaults];
|
||||
|
||||
// Going from 0.0.1 to 0.0.2 leaves rootKernelPath uninitialized
|
||||
// < 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];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,7 +216,7 @@
|
|||
}
|
||||
|
||||
|
||||
- (BOOL) fetchUserDefaults:(uint16_t*)height width:(uint16_t*)width
|
||||
- (BOOL) fetchUserDefaults
|
||||
{
|
||||
uint32_t i;
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
@ -223,6 +225,7 @@
|
|||
NSString *romPathStr = [defaults objectForKey:@"romPath"];
|
||||
NSInteger verboseState = [defaults integerForKey:@"verboseState"];
|
||||
NSInteger memsize = [defaults integerForKey:@"memorySize"];
|
||||
NSData *pramData = [defaults objectForKey:@"pramData"];
|
||||
|
||||
if (rootKernelPathStr == Nil || [rootKernelPathStr length]==0) {
|
||||
[self complain:@"Kernel path invalid!"];
|
||||
|
@ -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 *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 = rootKernelPathCString;
|
||||
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,41 +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:9 height:height width:width refresh_freq:200.0/3.0];
|
||||
/*[self createScreenWindow:10 height:height width:width refresh_freq:200.0/3.0];
|
||||
[self createScreenWindow:11 height:height width:width refresh_freq:200.0/3.0];
|
||||
[self createScreenWindow:12 height:height width:width refresh_freq:200.0/3.0];
|
||||
[self createScreenWindow:13 height:height width:width refresh_freq:200.0/3.0];
|
||||
[self createScreenWindow:14 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];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#import "shoePreferencesWindowController.h"
|
||||
#import "shoeApplication.h"
|
||||
#include <ctype.h>
|
||||
|
||||
@implementation shoePreferencesWindowController
|
||||
|
||||
|
@ -35,6 +36,14 @@
|
|||
|
||||
- (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 *rootKernelPathStr = [defaults objectForKey:@"rootKernelPath"];
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -134,8 +150,27 @@
|
|||
[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 *rootKernelPathStr = [kernelPath stringValue];
|
||||
NSString *romPathStr = [romPath stringValue];
|
||||
|
@ -150,11 +185,21 @@
|
|||
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];
|
||||
|
||||
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"];
|
||||
|
@ -168,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];
|
||||
}
|
||||
|
@ -186,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
|
||||
|
|
|
@ -1,17 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5053" systemVersion="13C64" 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="5053"/>
|
||||
<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="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,24 +31,24 @@
|
|||
<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="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"/>
|
||||
<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">
|
||||
|
@ -46,7 +58,6 @@
|
|||
<subviews>
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oVj-nA-5GP">
|
||||
<rect key="frame" x="11" y="314" width="81" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<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"/>
|
||||
|
@ -55,7 +66,6 @@
|
|||
</textField>
|
||||
<button identifier="romPathBrowse" verticalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="fjl-Jg-nIF">
|
||||
<rect key="frame" x="358" y="303" 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="ITb-nX-hmP">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
|
@ -66,7 +76,6 @@
|
|||
</button>
|
||||
<textField identifier="romPath" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LoN-Nd-9cy">
|
||||
<rect key="frame" x="98" y="292" 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="macii.rom" drawsBackground="YES" id="IvC-yQ-qdn">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -75,7 +84,6 @@
|
|||
</textField>
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RDI-wU-bdg">
|
||||
<rect key="frame" x="2" y="267" width="90" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<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"/>
|
||||
|
@ -84,25 +92,73 @@
|
|||
</textField>
|
||||
<textField identifier="memorySize" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uvm-gd-pCd">
|
||||
<rect key="frame" x="98" y="262" width="42" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<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="2" y="210" 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="146" y="224" 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"/>
|
||||
|
@ -110,32 +166,165 @@
|
|||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="aSg-xG-o1t">
|
||||
<rect key="frame" x="223" y="223" 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="98" y="220" 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="168" y="220" 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="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>
|
||||
</button>
|
||||
</subviews>
|
||||
</view>
|
||||
</tabViewItem>
|
||||
|
@ -146,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"/>
|
||||
|
@ -155,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"/>
|
||||
|
@ -166,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"/>
|
||||
|
@ -175,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"/>
|
||||
|
@ -184,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"/>
|
||||
|
@ -195,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"/>
|
||||
|
@ -204,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"/>
|
||||
|
@ -213,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"/>
|
||||
|
@ -224,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"/>
|
||||
|
@ -233,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"/>
|
||||
|
@ -242,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"/>
|
||||
|
@ -253,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"/>
|
||||
|
@ -262,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"/>
|
||||
|
@ -271,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"/>
|
||||
|
@ -282,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"/>
|
||||
|
@ -291,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"/>
|
||||
|
@ -300,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"/>
|
||||
|
@ -311,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"/>
|
||||
|
@ -320,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"/>
|
||||
|
@ -329,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"/>
|
||||
|
@ -340,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"/>
|
||||
|
@ -350,35 +518,56 @@
|
|||
</subviews>
|
||||
</view>
|
||||
</tabViewItem>
|
||||
<tabViewItem label="Booting" identifier="" id="3o8-Ma-LAk">
|
||||
<view key="view" ambiguous="YES" id="Zdy-ik-svz">
|
||||
<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="0nJ-ho-P1P">
|
||||
<rect key="frame" x="6" y="315" width="81" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" allowsUndo="NO" alignment="right" title="Kernel Path:" usesSingleLineMode="YES" id="Wdx-2C-yGA">
|
||||
<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="kernelPath" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zU0-5O-afD">
|
||||
<rect key="frame" x="93" y="310" width="342" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<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">
|
||||
<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>
|
||||
<button identifier="verbose" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fkL-RE-iRz">
|
||||
<rect key="frame" x="6" y="271" width="142" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<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">
|
||||
<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>
|
||||
|
@ -390,7 +579,6 @@
|
|||
</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"/>
|
||||
|
@ -401,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"/>
|
||||
|
@ -415,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"/>
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
@interface shoeScreenView : NSOpenGLView {
|
||||
CGColorSpaceRef colorspace;
|
||||
shoebill_control_t *control;
|
||||
NSTimer *timer;
|
||||
NSRecursiveLock *lock;
|
||||
CIContext *ciContext;
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
- (void)initCommon
|
||||
{
|
||||
shoeApp = (shoeApplication*) NSApp;
|
||||
control = &shoeApp->control;
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,7 +72,7 @@
|
|||
colorspace = CGColorSpaceCreateDeviceRGB();
|
||||
|
||||
timer = [NSTimer
|
||||
scheduledTimerWithTimeInterval:0.001
|
||||
scheduledTimerWithTimeInterval:(1.0/60.0)
|
||||
target:self
|
||||
selector:@selector(timerFireMethod:)
|
||||
userInfo:nil
|
||||
|
@ -83,16 +82,7 @@
|
|||
[[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];
|
||||
}
|
||||
|
||||
|
@ -103,83 +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);
|
||||
|
||||
GLint swapInt = 1;
|
||||
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (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);
|
||||
|
@ -187,32 +129,29 @@ static void _do_clut_translation(shoebill_card_video_t *ctx)
|
|||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
if (shoeApp->isRunning) {
|
||||
uint8_t slotnum = ((shoeScreenWindow*)[self window])->slotnum;
|
||||
shoebill_card_video_t *video = &control->slots[slotnum].card.video;
|
||||
shoebill_video_frame_info_t frame = shoebill_get_video_frame(slotnum, 0);
|
||||
|
||||
/*NSSize size = {
|
||||
.height=video->height,
|
||||
.width=video->width
|
||||
};
|
||||
[self setFrameSize:size];
|
||||
[[self window] setContentSize:size];*/
|
||||
|
||||
_do_clut_translation(video);
|
||||
glViewport(0, 0, video->width, video->height);
|
||||
glRasterPos2i(0, video->height);
|
||||
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
|
||||
|
@ -247,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
|
||||
{
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -28,10 +28,8 @@
|
|||
|
||||
@interface shoeScreenWindow : NSWindow {
|
||||
@public
|
||||
uint8_t slotnum;
|
||||
}
|
||||
|
||||
- (void) configure:(uint8_t) _slotnum;
|
||||
- (void) reevaluateKeyWindowness;
|
||||
- (void) warpToCenter;
|
||||
- (void) captureMouse;
|
||||
|
|
|
@ -29,20 +29,6 @@
|
|||
|
||||
@implementation shoeScreenWindow
|
||||
|
||||
- (void)configure:(uint8_t) _slotnum
|
||||
{
|
||||
slotnum = _slotnum;
|
||||
|
||||
shoeApplication *shoeApp = (shoeApplication*) NSApp;
|
||||
shoebill_control_t *control = &shoeApp->control;
|
||||
shoebill_card_video_t *video = &control->slots[slotnum].card.video;
|
||||
NSSize size = {
|
||||
.height=video->height,
|
||||
.width=video->width
|
||||
};
|
||||
|
||||
[self setContentSize:size];
|
||||
}
|
||||
|
||||
// Called after all the shoeScreenWindows are created and configured,
|
||||
// because one of them was already made key while isRunning==NO,
|
||||
|
@ -50,7 +36,7 @@
|
|||
- (void)reevaluateKeyWindowness
|
||||
{
|
||||
shoeApplication *shoeApp = (shoeApplication*)NSApp;
|
||||
|
||||
|
||||
assert(shoeApp->isRunning);
|
||||
|
||||
if ([self isKeyWindow]) {
|
||||
|
@ -62,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;
|
||||
|
@ -105,7 +104,7 @@
|
|||
shoeApplication *shoeApp = (shoeApplication*)NSApp;
|
||||
shoeApp->doCaptureMouse = NO;
|
||||
CGDisplayShowCursor(0);
|
||||
[self setTitle:@"Shoebill - Screen 1"];
|
||||
[self setTitle:@"Shoebill"];
|
||||
}
|
||||
|
||||
- (void) captureMouse
|
||||
|
@ -114,7 +113,7 @@
|
|||
shoeApp->doCaptureMouse = YES;
|
||||
CGDisplayHideCursor(0);
|
||||
[self warpToCenter];
|
||||
[self setTitle:@"Shoebill - Screen 1 (Ctrl-click to escape)"];
|
||||
[self setTitle:@"Shoebill (Ctrl-click to escape)"];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
76
gui/Shoebill/shoeScreenWindowController.m
Normal 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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 247 KiB |
Before Width: | Height: | Size: 151 KiB |