├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── core ├── Makefile ├── SoftFloat │ ├── 386-GCC.h │ ├── softfloat-macros.h │ ├── softfloat-specialize.h │ ├── softfloat.c │ └── softfloat.h ├── adb.c ├── alloc_pool.c ├── atrap_tab.c ├── coff.c ├── core_api.c ├── cpu.c ├── decoder_gen.c ├── dis.c ├── ethernet.c ├── ethernet_rom │ ├── rom.bin │ ├── rom.c │ ├── shoebill_ether.make │ └── shoebill_ether_rom.a ├── exception.c ├── filesystem.c ├── floppy.c ├── fpu.c ├── macii_symbols.c ├── macro.pl ├── mc68851.c ├── mc68851.h ├── mem.c ├── oldfpu.c ├── redblack.c ├── scsi.c ├── shoebill.h ├── sound.c ├── toby_frame_buffer.c ├── via.c ├── video.c └── video_rom │ ├── rom.bin │ ├── rom.c │ ├── rom_to_c.c │ ├── shoebill_video.make │ ├── shoebill_video_driver.a │ ├── shoebill_video_primary_init.a │ ├── shoebill_video_rom.a │ └── shoebill_video_secondary_init.a ├── debugger ├── Makefile └── debugger.c ├── gui ├── Shoebill.xcodeproj │ └── project.pbxproj └── Shoebill │ ├── Base.lproj │ └── MainMenu.xib │ ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Shoebill-Info.plist │ ├── Shoebill-Prefix.pch │ ├── en.lproj │ ├── Credits.rtf │ └── InfoPlist.strings │ ├── main.m │ ├── shoeAppDelegate.h │ ├── shoeAppDelegate.m │ ├── shoeApplication.h │ ├── shoeApplication.m │ ├── shoePreferencesWindowController.h │ ├── shoePreferencesWindowController.m │ ├── shoePreferencesWindowController.xib │ ├── shoeScreenView.h │ ├── shoeScreenView.m │ ├── shoeScreenView.xib │ ├── shoeScreenWindow.h │ ├── shoeScreenWindow.m │ ├── shoeScreenWindowController.h │ └── shoeScreenWindowController.m └── sdl-gui ├── lin_build.sh ├── osx_build.sh ├── sdl.c └── win_build.bat /.gitignore: -------------------------------------------------------------------------------- 1 | /intermediates 2 | /shoebill 3 | .DS_Store 4 | *.xcworkspace 5 | xcuserdata 6 | /gui/build 7 | /debugger/debugger 8 | /debugger/debugger.dSYM 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Peter Rutenbar 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = clang 3 | CFLAGS = -O3 -flto -Wno-deprecated-declarations 4 | 5 | all: shoebill 6 | 7 | shoebill: make_gui debugger 8 | 9 | make_gui: make_core 10 | xcodebuild -project gui/Shoebill.xcodeproj SYMROOT=build 11 | 12 | debugger: make_core 13 | $(MAKE) -C debugger 14 | 15 | make_core: 16 | $(MAKE) -C core -j 4 17 | 18 | clean: 19 | rm -rf intermediates gui/build 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Shoebill

2 | 3 | A Macintosh II emulator that runs A/UX (and A/UX only). 4 | 5 | Shoebill is an all-new, BSD-licensed Macintosh II emulator designed from the ground up with the singular goal of running A/UX. 6 | 7 | Shoebill requires a Macintosh II, IIx or IIcx ROM, and a disk image with A/UX installed. 8 | 9 | [Download the latest release], and then see the [getting started] wiki. 10 | Also check out [screenshots]. 11 | 12 | __Update (March 29, 2023): About issues/pull requests__ 13 | 14 | __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.)__ 15 | 16 | __Update (Sept 13, 2015): [Shoebill 0.0.5 is available]__ 17 | 18 | __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.__ 19 | 20 | 21 | #### Supports 22 | * A/UX 1.1.1 through 3.1 (and 3.1.1 a little) 23 | 24 | #### Currently Implements 25 | * 68020 CPU (mostly) 26 | * 68881 FPU (mostly) 27 | * 68851 PMMU (just enough to boot A/UX) 28 | * SCSI 29 | * ADB 30 | * PRAM 31 | * Ethernet (via emulated Apple EtherTalk/DP8390 card) 32 | * A NuBus video card with 24-bit depth. 33 | 34 | #### Does not implement (yet) 35 | * Sound 36 | * Floppy 37 | * Serial ports 38 | 39 | 40 | [Download the latest release]:https://github.com/pruten/Shoebill/releases 41 | [getting started]:https://github.com/pruten/Shoebill/wiki/Getting-Started 42 | [screenshots]:https://github.com/pruten/Shoebill/wiki/Screenshots 43 | [Shoebill 0.0.5 is available]:https://github.com/pruten/Shoebill/releases 44 | [The thread on emaculation.com]:http://www.emaculation.com/forum/viewtopic.php?f=7&t=8288 45 | [Qemu is now able]:https://virtuallyfun.com/2021/09/02/qemus-macintosh-quadra-in-alpha-usability-runs-a-ux/ 46 | 47 | -------------------------------------------------------------------------------- /core/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = clang 3 | CFLAGS = -O3 -ggdb -flto -Wno-deprecated-declarations 4 | # CFLAGS = -O0 -ggdb -Wno-deprecated-declarations 5 | 6 | 7 | DEPS = mc68851.h shoebill.h Makefile macro.pl 8 | NEED_DECODER = cpu dis 9 | NEED_PREPROCESSING = adb mc68851 mem via floppy core_api fpu 10 | NEED_NOTHING = atrap_tab coff exception macii_symbols redblack scsi video filesystem alloc_pool toby_frame_buffer sound ethernet SoftFloat/softfloat 11 | 12 | # Object files that can be compiled directly from the source 13 | OBJ_NEED_NOTHING = $(patsubst %,$(TEMP)/%.o,$(NEED_NOTHING)) 14 | 15 | # Object files than need preprocessing with macro.pl 16 | OBJ_NEED_PREPROCESSING = $(patsubst %,$(TEMP)/%.o,$(NEED_PREPROCESSING)) 17 | 18 | # Object files that depend on the instruction decoder 19 | OBJ_NEED_DECODER = $(patsubst %,$(TEMP)/%.o,$(NEED_DECODER)) 20 | 21 | # Files that NEED_DECODER also NEED_PREPROCESSING 22 | POST_PREPROCESSING = $(patsubst %,$(TEMP)/%.post.c,$(NEED_PREPROCESSING)) $(patsubst %,$(TEMP)/%.post.c,$(NEED_DECODER)) 23 | 24 | 25 | 26 | # All the object files compiled for x86_64 27 | OBJ_x86_64 = $(OBJ_NEED_NOTHING) $(OBJ_NEED_PREPROCESSING) $(OBJ_NEED_DECODER) 28 | 29 | # The object files compiled for i386 (the same as x86_64 files, but with .i386 appended) 30 | OBJ_i386 = $(patsubst %,%.i386,$(OBJ_x86_64)) 31 | 32 | 33 | MACRO = perl macro.pl 34 | 35 | TEMP = ../intermediates 36 | 37 | 38 | all: $(TEMP)/libshoebill_core.a 39 | 40 | $(TEMP)/libshoebill_core.a: $(TEMP) $(DEPS) $(OBJ_x86_64) 41 | libtool -static -v -o $(TEMP)/libshoebill_core.a.x86_64 $(OBJ_x86_64) 42 | libtool -static -v -o $(TEMP)/libshoebill_core.a.i386 $(OBJ_i386) 43 | lipo -create -output $(TEMP)/libshoebill_core.a $(TEMP)/libshoebill_core.a.x86_64 $(TEMP)/libshoebill_core.a.i386 44 | 45 | 46 | # Split object files into i386/x86_64 versions, since it seems that libtool is unable to 47 | # link a static universal library for -O4 object files. 48 | # x86_64 object files have the form "intermediates/.o 49 | # i386 object files have the form "intermediates/.o.i386 50 | 51 | # Build object files 52 | $(OBJ_NEED_NOTHING): $(TEMP)/%.o: %.c $(DEPS) 53 | $(CC) -c -arch x86_64 $(CFLAGS) $< -o $@ 54 | $(CC) -c -arch i386 $(CFLAGS) $< -o $@.i386 55 | 56 | $(OBJ_NEED_PREPROCESSING): $(TEMP)/%.o: $(TEMP)/%.post.c $(DEPS) 57 | $(CC) -c -arch x86_64 $(CFLAGS) $< -o $@ 58 | $(CC) -c -arch i386 $(CFLAGS) $< -o $@.i386 59 | 60 | $(OBJ_NEED_DECODER): $(TEMP)/%.o: $(TEMP)/%.post.c $(DEPS) $(TEMP)/dis_decoder_guts.c $(TEMP)/inst_decoder_guts.c 61 | $(CC) -c -arch x86_64 $(CFLAGS) $< -o $@ 62 | $(CC) -c -arch i386 $(CFLAGS) $< -o $@.i386 63 | 64 | # Preprocess C files 65 | $(POST_PREPROCESSING): $(TEMP)/%.post.c: %.c $(DEPS) 66 | $(MACRO) $< $@ 67 | 68 | # Generate instruction decoders 69 | $(TEMP)/inst_decoder_guts.c: $(TEMP)/decoder_gen $(DEPS) 70 | $(TEMP)/decoder_gen inst $(TEMP)/ 71 | $(TEMP)/dis_decoder_guts.c: $(TEMP)/decoder_gen $(DEPS) 72 | $(TEMP)/decoder_gen dis $(TEMP)/ 73 | 74 | # Compile the decoder generator 75 | $(TEMP)/decoder_gen: decoder_gen.c $(DEPS) 76 | $(CC) decoder_gen.c -o $(TEMP)/decoder_gen 77 | 78 | 79 | $(TEMP): 80 | mkdir -p $(TEMP) 81 | mkdir -p $(TEMP)/SoftFloat 82 | 83 | clean: 84 | rm -rf $(TEMP) 85 | 86 | -------------------------------------------------------------------------------- /core/SoftFloat/386-GCC.h: -------------------------------------------------------------------------------- 1 | 2 | /*---------------------------------------------------------------------------- 3 | | One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined. 4 | *----------------------------------------------------------------------------*/ 5 | #define LITTLEENDIAN 6 | 7 | /*---------------------------------------------------------------------------- 8 | | The macro `BITS64' can be defined to indicate that 64-bit integer types are 9 | | supported by the compiler. 10 | *----------------------------------------------------------------------------*/ 11 | #define BITS64 12 | 13 | /*---------------------------------------------------------------------------- 14 | | Each of the following `typedef's defines the most convenient type that holds 15 | | integers of at least as many bits as specified. For example, `uint8' should 16 | | be the most convenient type that can hold unsigned integers of as many as 17 | | 8 bits. The `flag' type must be able to hold either a 0 or 1. For most 18 | | implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed 19 | | to the same as `int'. 20 | *----------------------------------------------------------------------------*/ 21 | typedef char flag; 22 | typedef unsigned char uint8; 23 | typedef signed char int8; 24 | typedef int uint16; 25 | typedef int int16; 26 | typedef unsigned int uint32; 27 | typedef signed int int32; 28 | #ifdef BITS64 29 | typedef unsigned long long int uint64; 30 | typedef signed long long int int64; 31 | #endif 32 | 33 | /*---------------------------------------------------------------------------- 34 | | Each of the following `typedef's defines a type that holds integers 35 | | of _exactly_ the number of bits specified. For instance, for most 36 | | implementation of C, `bits16' and `sbits16' should be `typedef'ed to 37 | | `unsigned short int' and `signed short int' (or `short int'), respectively. 38 | *----------------------------------------------------------------------------*/ 39 | typedef unsigned char bits8; 40 | typedef signed char sbits8; 41 | typedef unsigned short int bits16; 42 | typedef signed short int sbits16; 43 | typedef unsigned int bits32; 44 | typedef signed int sbits32; 45 | #ifdef BITS64 46 | typedef unsigned long long int bits64; 47 | typedef signed long long int sbits64; 48 | #endif 49 | 50 | #ifdef BITS64 51 | /*---------------------------------------------------------------------------- 52 | | The `LIT64' macro takes as its argument a textual integer literal and 53 | | if necessary ``marks'' the literal as having a 64-bit integer type. 54 | | For example, the GNU C Compiler (`gcc') requires that 64-bit literals be 55 | | appended with the letters `LL' standing for `long long', which is `gcc's 56 | | name for the 64-bit integer type. Some compilers may allow `LIT64' to be 57 | | defined as the identity macro: `#define LIT64( a ) a'. 58 | *----------------------------------------------------------------------------*/ 59 | #define LIT64( a ) a##LL 60 | #endif 61 | 62 | /*---------------------------------------------------------------------------- 63 | | The macro `INLINE' can be used before functions that should be inlined. If 64 | | a compiler does not support explicit inlining, this macro should be defined 65 | | to be `static'. 66 | *----------------------------------------------------------------------------*/ 67 | #define INLINE static 68 | 69 | -------------------------------------------------------------------------------- /core/SoftFloat/softfloat.h: -------------------------------------------------------------------------------- 1 | 2 | /*============================================================================ 3 | 4 | This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic 5 | Package, Release 2b. 6 | 7 | Written by John R. Hauser. This work was made possible in part by the 8 | International Computer Science Institute, located at Suite 600, 1947 Center 9 | Street, Berkeley, California 94704. Funding was partially provided by the 10 | National Science Foundation under grant MIP-9311980. The original version 11 | of this code was written as part of a project to build a fixed-point vector 12 | processor in collaboration with the University of California at Berkeley, 13 | overseen by Profs. Nelson Morgan and John Wawrzynek. More information 14 | is available through the Web page `http://www.cs.berkeley.edu/~jhauser/ 15 | arithmetic/SoftFloat.html'. 16 | 17 | THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has 18 | been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES 19 | RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS 20 | AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES, 21 | COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE 22 | EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE 23 | INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR 24 | OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE. 25 | 26 | Derivative works are acceptable, even for commercial purposes, so long as 27 | (1) the source code for the derivative work includes prominent notice that 28 | the work is derivative, and (2) the source code includes prominent notice with 29 | these four paragraphs for those parts of this code that are retained. 30 | 31 | =============================================================================*/ 32 | 33 | /*---------------------------------------------------------------------------- 34 | | The macro `FLOATX80' must be defined to enable the extended double-precision 35 | | floating-point format `floatx80'. If this macro is not defined, the 36 | | `floatx80' type will not be defined, and none of the functions that either 37 | | input or output the `floatx80' type will be defined. The same applies to 38 | | the `FLOAT128' macro and the quadruple-precision format `float128'. 39 | *----------------------------------------------------------------------------*/ 40 | #define FLOATX80 41 | #define FLOAT128 42 | 43 | /*---------------------------------------------------------------------------- 44 | | Software IEC/IEEE floating-point types. 45 | *----------------------------------------------------------------------------*/ 46 | typedef unsigned int float32; 47 | typedef unsigned long long float64; 48 | #ifdef FLOATX80 49 | typedef struct { 50 | unsigned long long low; 51 | unsigned short high; 52 | } floatx80; 53 | #endif 54 | #ifdef FLOAT128 55 | typedef struct { 56 | unsigned long long low, high; 57 | } float128; 58 | #endif 59 | 60 | /*---------------------------------------------------------------------------- 61 | | Software IEC/IEEE floating-point underflow tininess-detection mode. 62 | *----------------------------------------------------------------------------*/ 63 | extern signed char float_detect_tininess; 64 | enum { 65 | float_tininess_after_rounding = 0, 66 | float_tininess_before_rounding = 1 67 | }; 68 | 69 | /*---------------------------------------------------------------------------- 70 | | Software IEC/IEEE floating-point rounding mode. 71 | *----------------------------------------------------------------------------*/ 72 | extern signed char float_rounding_mode; 73 | enum { 74 | float_round_nearest_even = 0, 75 | float_round_down = 1, 76 | float_round_up = 2, 77 | float_round_to_zero = 3 78 | }; 79 | 80 | /*---------------------------------------------------------------------------- 81 | | Software IEC/IEEE floating-point exception flags. 82 | *----------------------------------------------------------------------------*/ 83 | extern signed char float_exception_flags; 84 | enum { 85 | float_flag_invalid = 1, 86 | float_flag_divbyzero = 4, 87 | float_flag_overflow = 8, 88 | float_flag_underflow = 16, 89 | float_flag_inexact = 32 90 | }; 91 | 92 | /*---------------------------------------------------------------------------- 93 | | Routine to raise any or all of the software IEC/IEEE floating-point 94 | | exception flags. 95 | *----------------------------------------------------------------------------*/ 96 | void float_raise( signed char ); 97 | 98 | /*---------------------------------------------------------------------------- 99 | | Software IEC/IEEE integer-to-floating-point conversion routines. 100 | *----------------------------------------------------------------------------*/ 101 | float32 int32_to_float32( int ); 102 | float64 int32_to_float64( int ); 103 | #ifdef FLOATX80 104 | floatx80 int32_to_floatx80( int ); 105 | #endif 106 | #ifdef FLOAT128 107 | float128 int32_to_float128( int ); 108 | #endif 109 | float32 int64_to_float32( long long ); 110 | float64 int64_to_float64( long long ); 111 | #ifdef FLOATX80 112 | floatx80 int64_to_floatx80( long long ); 113 | #endif 114 | #ifdef FLOAT128 115 | float128 int64_to_float128( long long ); 116 | #endif 117 | 118 | /*---------------------------------------------------------------------------- 119 | | Software IEC/IEEE single-precision conversion routines. 120 | *----------------------------------------------------------------------------*/ 121 | int float32_to_int32( float32 ); 122 | int float32_to_int32_round_to_zero( float32 ); 123 | long long float32_to_int64( float32 ); 124 | long long float32_to_int64_round_to_zero( float32 ); 125 | float64 float32_to_float64( float32 ); 126 | #ifdef FLOATX80 127 | floatx80 float32_to_floatx80( float32 ); 128 | #endif 129 | #ifdef FLOAT128 130 | float128 float32_to_float128( float32 ); 131 | #endif 132 | 133 | /*---------------------------------------------------------------------------- 134 | | Software IEC/IEEE single-precision operations. 135 | *----------------------------------------------------------------------------*/ 136 | float32 float32_round_to_int( float32 ); 137 | float32 float32_add( float32, float32 ); 138 | float32 float32_sub( float32, float32 ); 139 | float32 float32_mul( float32, float32 ); 140 | float32 float32_div( float32, float32 ); 141 | float32 float32_rem( float32, float32 ); 142 | float32 float32_sqrt( float32 ); 143 | char float32_eq( float32, float32 ); 144 | char float32_le( float32, float32 ); 145 | char float32_lt( float32, float32 ); 146 | char float32_eq_signaling( float32, float32 ); 147 | char float32_le_quiet( float32, float32 ); 148 | char float32_lt_quiet( float32, float32 ); 149 | char float32_is_signaling_nan( float32 ); 150 | 151 | /*---------------------------------------------------------------------------- 152 | | Software IEC/IEEE double-precision conversion routines. 153 | *----------------------------------------------------------------------------*/ 154 | int float64_to_int32( float64 ); 155 | int float64_to_int32_round_to_zero( float64 ); 156 | long long float64_to_int64( float64 ); 157 | long long float64_to_int64_round_to_zero( float64 ); 158 | float32 float64_to_float32( float64 ); 159 | #ifdef FLOATX80 160 | floatx80 float64_to_floatx80( float64 ); 161 | #endif 162 | #ifdef FLOAT128 163 | float128 float64_to_float128( float64 ); 164 | #endif 165 | 166 | /*---------------------------------------------------------------------------- 167 | | Software IEC/IEEE double-precision operations. 168 | *----------------------------------------------------------------------------*/ 169 | float64 float64_round_to_int( float64 ); 170 | float64 float64_add( float64, float64 ); 171 | float64 float64_sub( float64, float64 ); 172 | float64 float64_mul( float64, float64 ); 173 | float64 float64_div( float64, float64 ); 174 | float64 float64_rem( float64, float64 ); 175 | float64 float64_sqrt( float64 ); 176 | char float64_eq( float64, float64 ); 177 | char float64_le( float64, float64 ); 178 | char float64_lt( float64, float64 ); 179 | char float64_eq_signaling( float64, float64 ); 180 | char float64_le_quiet( float64, float64 ); 181 | char float64_lt_quiet( float64, float64 ); 182 | char float64_is_signaling_nan( float64 ); 183 | 184 | #ifdef FLOATX80 185 | 186 | /*---------------------------------------------------------------------------- 187 | | Software IEC/IEEE extended double-precision conversion routines. 188 | *----------------------------------------------------------------------------*/ 189 | int floatx80_to_int32( floatx80 ); 190 | int floatx80_to_int32_round_to_zero( floatx80 ); 191 | long long floatx80_to_int64( floatx80 ); 192 | long long floatx80_to_int64_round_to_zero( floatx80 ); 193 | float32 floatx80_to_float32( floatx80 ); 194 | float64 floatx80_to_float64( floatx80 ); 195 | #ifdef FLOAT128 196 | float128 floatx80_to_float128( floatx80 ); 197 | #endif 198 | 199 | /*---------------------------------------------------------------------------- 200 | | Software IEC/IEEE extended double-precision rounding precision. Valid 201 | | values are 32, 64, and 80. 202 | *----------------------------------------------------------------------------*/ 203 | extern signed char floatx80_rounding_precision; 204 | 205 | /*---------------------------------------------------------------------------- 206 | | Software IEC/IEEE extended double-precision operations. 207 | *----------------------------------------------------------------------------*/ 208 | floatx80 floatx80_round_to_int( floatx80 ); 209 | floatx80 floatx80_add( floatx80, floatx80 ); 210 | floatx80 floatx80_sub( floatx80, floatx80 ); 211 | floatx80 floatx80_mul( floatx80, floatx80 ); 212 | floatx80 floatx80_div( floatx80, floatx80 ); 213 | floatx80 floatx80_rem( floatx80, floatx80 ); 214 | floatx80 floatx80_sqrt( floatx80 ); 215 | char floatx80_eq( floatx80, floatx80 ); 216 | char floatx80_le( floatx80, floatx80 ); 217 | char floatx80_lt( floatx80, floatx80 ); 218 | char floatx80_eq_signaling( floatx80, floatx80 ); 219 | char floatx80_le_quiet( floatx80, floatx80 ); 220 | char floatx80_lt_quiet( floatx80, floatx80 ); 221 | char floatx80_is_signaling_nan( floatx80 ); 222 | 223 | #endif 224 | 225 | #ifdef FLOAT128 226 | 227 | /*---------------------------------------------------------------------------- 228 | | Software IEC/IEEE quadruple-precision conversion routines. 229 | *----------------------------------------------------------------------------*/ 230 | int float128_to_int32( float128 ); 231 | int float128_to_int32_round_to_zero( float128 ); 232 | long long float128_to_int64( float128 ); 233 | long long float128_to_int64_round_to_zero( float128 ); 234 | float32 float128_to_float32( float128 ); 235 | float64 float128_to_float64( float128 ); 236 | #ifdef FLOATX80 237 | floatx80 float128_to_floatx80( float128 ); 238 | #endif 239 | 240 | /*---------------------------------------------------------------------------- 241 | | Software IEC/IEEE quadruple-precision operations. 242 | *----------------------------------------------------------------------------*/ 243 | float128 float128_round_to_int( float128 ); 244 | float128 float128_add( float128, float128 ); 245 | float128 float128_sub( float128, float128 ); 246 | float128 float128_mul( float128, float128 ); 247 | float128 float128_div( float128, float128 ); 248 | float128 float128_rem( float128, float128 ); 249 | float128 float128_sqrt( float128 ); 250 | char float128_eq( float128, float128 ); 251 | char float128_le( float128, float128 ); 252 | char float128_lt( float128, float128 ); 253 | char float128_eq_signaling( float128, float128 ); 254 | char float128_le_quiet( float128, float128 ); 255 | char float128_lt_quiet( float128, float128 ); 256 | char float128_is_signaling_nan( float128 ); 257 | 258 | #endif 259 | 260 | -------------------------------------------------------------------------------- /core/adb.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include "../core/shoebill.h" 30 | #include 31 | 32 | // via1 ORB bits abcd efgh 33 | // cd -> adb FSM state 34 | // e -> adb timeout occurred / service request (?) 35 | // f/g/h nvram stuff 36 | 37 | #define VIA_REGB_ADB_STATUS 8 38 | 39 | /* 40 | Reset: 41 | 42 | -> OS writes reset command to sr, sets state 0 43 | <- chip sets ADB status line, raises interrupt 44 | -> OS dummy-reads sr, sets state 2 45 | <- chip sets ADB status line, raises interrupt 46 | -> OS dummy-reads sr, sets state 3 47 | 48 | 49 | Talk: 50 | -> OS writes talk command to sr, sets state 0 51 | <- chip responds with an interrupt. Status=0 -> poll(unsolicited?), status=1 -> response? 52 | -> OS sets state=1 53 | <- chip responds with an interrupt. Status=0 -> timeout, status=1 -> not-timedout? 54 | -> OS reads first byte from sr, sets state=2 55 | <- chip responds with interrupt. Status=0 -> service request, service=1 no-service-reques 56 | -> OS reads second byte from sr, sets state=3 57 | 58 | 59 | Listen: 60 | -> OS writes listen command to sr, sets state 0 61 | <- chip 62 | ??? 63 | 64 | Keyboard: 65 | -> OS sends EXISTS (TALK) for id 2, reg 3 66 | <- (if no keyboard: timeout. If keyboard: respond with some data) 67 | 68 | -> OS sends FLUSH 69 | <- Keyboard responds 70 | 71 | -> OS sends LISTEN for id 2, reg 3 (data: 0x2201 - sets the service request enable bit) 72 | <- Keyboard respnods 73 | 74 | -> OS sends TALK for id 2 reg 2 75 | <- Keyboard responds with some keyboard setup data 76 | 77 | -> OS sends TALK for id 2 reg 0 78 | <- if there's a key, keyboard returns key data. Otherwise, response times out. 79 | 80 | */ 81 | 82 | void reset_adb_state() 83 | { 84 | pthread_mutex_t lock = shoe.adb.lock; 85 | 86 | memset(&shoe.adb, 0, sizeof(adb_state_t)); 87 | memset(&shoe.key, 0, sizeof(keyboard_state_t)); 88 | memset(&shoe.mouse, 0, sizeof(mouse_state_t)); 89 | 90 | // Put the adb chip in state 3 (idle) 91 | shoe.adb.state = 3; 92 | 93 | shoe.adb.lock = lock; 94 | } 95 | 96 | void init_adb_state() 97 | { 98 | memset(&shoe.adb, 0, sizeof(adb_state_t)); 99 | memset(&shoe.key, 0, sizeof(keyboard_state_t)); 100 | memset(&shoe.mouse, 0, sizeof(mouse_state_t)); 101 | 102 | // Put the adb chip in state 3 (idle) 103 | shoe.adb.state = 3; 104 | 105 | pthread_mutex_init(&shoe.adb.lock, NULL); 106 | } 107 | 108 | void adb_start_service_request() 109 | { 110 | //slog("adb_start_service_request: pending_requests = 0x%02x\n", shoe.adb.pending_service_requests); 111 | if (shoe.adb.pending_service_requests) { 112 | shoe.adb.service_request = 1; 113 | 114 | shoe.adb.poll = shoe.adb.pending_poll; 115 | shoe.adb.pending_poll = 0; 116 | 117 | via_raise_interrupt(1, IFR_SHIFT_REG); 118 | } 119 | } 120 | 121 | void adb_request_service_request(uint8_t id) 122 | { 123 | shoe.adb.pending_service_requests |= (1 << id); 124 | shoe.adb.pending_poll = 1; 125 | 126 | if (shoe.adb.state == 3) { 127 | adb_start_service_request(); 128 | } 129 | } 130 | 131 | static void keyboard_talk(uint8_t reg) 132 | { 133 | shoe.adb.timeout = 0; 134 | 135 | switch (reg) { 136 | case 0: 137 | if (shoe.key.key_i > 0) { 138 | shoe.adb.data[0] = shoe.key.keys[0].code_b; 139 | shoe.adb.data[1] = shoe.key.keys[0].code_a; 140 | shoe.adb.data_len = 2; 141 | shoe.key.key_i--; 142 | memmove(&shoe.key.keys[0], &shoe.key.keys[1], shoe.key.key_i * sizeof(shoe.key.keys[0])); 143 | } 144 | else 145 | shoe.adb.timeout = 1; 146 | 147 | break ; 148 | 149 | case 2: 150 | // All the modifier keys are up 151 | shoe.adb.data[0] = ~b(01111111); 152 | shoe.adb.data[1] = ~b(11100111); 153 | shoe.adb.data_len = 2; 154 | break ; 155 | 156 | case 1: 157 | shoe.adb.timeout = 1; 158 | break ; 159 | 160 | case 3: 161 | shoe.adb.data[0] = 0x02; // device address == 2 -> keyboard 162 | shoe.adb.data[1] = 0x02; // device handler ID == 0x03 -> Apple Extended Keyboard 163 | shoe.adb.data_len = 2; 164 | break ; 165 | } 166 | 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); 167 | } 168 | 169 | static void mouse_talk(uint8_t reg) 170 | { 171 | shoe.adb.timeout = 0; 172 | 173 | slog("mouse_talk: reg=%u\n", reg); 174 | switch (reg) { 175 | 176 | case 0: 177 | if (shoe.mouse.changed) { 178 | const int32_t hi_delta_limit = 32; 179 | const int32_t low_delta_limit = -32; 180 | 181 | int32_t x = shoe.mouse.delta_x; 182 | int32_t y = shoe.mouse.delta_y; 183 | 184 | //slog("mouse_talk: x=%d, y=%d button=%u\n", shoe.mouse.delta_x, shoe.mouse.delta_y, shoe.mouse.button_down); 185 | 186 | 187 | if (x > hi_delta_limit) x = hi_delta_limit; 188 | if (x < low_delta_limit) x = low_delta_limit; 189 | if (y > hi_delta_limit) y = hi_delta_limit; 190 | if (y < low_delta_limit) y = low_delta_limit; 191 | 192 | shoe.adb.data[1] = x & 0x7f; 193 | shoe.adb.data[0] = y & 0x7f; 194 | if (!shoe.mouse.button_down) { 195 | //shoe.adb.data[1] |= 0x80; 196 | shoe.adb.data[0] |= 0x80; 197 | } 198 | // slog("mouse_talk: ") 199 | 200 | 201 | shoe.adb.data_len = 2; 202 | 203 | shoe.mouse.delta_x = 0; 204 | shoe.mouse.delta_y = 0; 205 | 206 | shoe.mouse.changed = 0; 207 | } 208 | else 209 | shoe.adb.timeout = 1; 210 | 211 | return ; 212 | 213 | case 1: 214 | assert(!"Can't handle reg 1"); 215 | 216 | case 2: 217 | assert(!"Can't handle reg 2"); 218 | 219 | case 3: 220 | shoe.adb.data[0] = 3; // device address: 3 221 | shoe.adb.data[1] = 1; // handler ID: 1 222 | shoe.adb.data_len = 2; 223 | return ; 224 | 225 | } 226 | } 227 | 228 | static void adb_handle_state_zero(uint8_t command_byte, uint8_t is_poll) // "Command" state 229 | { 230 | via_state_t *via = &shoe.via[0]; 231 | const uint8_t id = command_byte >> 4; // the target device ID 232 | const uint8_t reg = command_byte & 3; 233 | 234 | // Figure out the command type (reset/flush/talk/listen) 235 | 236 | if ((command_byte & 0xf) == 0) // reset 237 | shoe.adb.command_type = adb_reset; 238 | else if ((command_byte & 0xf) == 1) // flush 239 | shoe.adb.command_type = adb_flush; 240 | else if (~bmatch(command_byte, xxxx 11 xx)) // talk 241 | shoe.adb.command_type = adb_talk; 242 | else if (~bmatch(command_byte, xxxx 10 xx)) // listen 243 | shoe.adb.command_type = adb_listen; 244 | else 245 | assert(!"What is this adb state-0 command? xxxx 01xx"); 246 | 247 | slog("adb_handle_state_zero: command_byte=0x%02x, id=%u, reg=%u\n", command_byte, id, reg); 248 | 249 | shoe.adb.command_device_id = id; 250 | shoe.adb.command_reg = reg; 251 | 252 | // Flush/reset/listen and talk-with-timeout need data_i initialized to 0 253 | shoe.adb.data_i = 0; 254 | shoe.adb.data_len = 0; 255 | 256 | // If talk, go ask they keyboard/mouse if they have anything to say 257 | if (shoe.adb.command_type == adb_talk) { 258 | 259 | if (id == 2) { 260 | keyboard_talk(reg); 261 | } 262 | else if (id == 3) { 263 | mouse_talk(reg); 264 | } 265 | else { // timeout 266 | shoe.adb.timeout = 1; 267 | } 268 | 269 | // If there was a service request pending for this device, it is now handled. 270 | shoe.adb.pending_service_requests &= ~~(1 << id); 271 | } 272 | 273 | shoe.adb.poll = 0; 274 | 275 | via->regb_input |= VIA_REGB_ADB_STATUS; 276 | via_raise_interrupt(1, IFR_SHIFT_REG); 277 | } 278 | 279 | static void adb_handle_state_one (void) // "Even" state 280 | { 281 | via_state_t *via = &shoe.via[0]; 282 | 283 | slog("adb_handle_state_one: "); 284 | if (shoe.adb.poll) { 285 | // Upon receiving a service request, the adb controller sends a TALK/reg=0 to the last accessed device 286 | adb_handle_state_zero((shoe.adb.command_device_id << 4) | 0x0c, 1); 287 | } 288 | 289 | switch (shoe.adb.command_type) { 290 | case adb_flush: 291 | case adb_reset: 292 | assert(!"adb_handle_state_one: unexpected command type"); 293 | break; 294 | 295 | case adb_talk: 296 | slog("adb_talk: "); 297 | if (shoe.adb.timeout) { 298 | shoe.adb.timeout = 0; 299 | via->regb_input &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout 300 | via_raise_interrupt(1, IFR_SHIFT_REG); 301 | slog("timeout\n"); 302 | return ; 303 | } 304 | 305 | if (shoe.adb.data_i < shoe.adb.data_len) 306 | via->sr = shoe.adb.data[shoe.adb.data_i++]; 307 | else 308 | via->sr = 0; 309 | 310 | slog("set sr = 0x%02x\n", via->sr); 311 | 312 | break; 313 | 314 | case adb_listen: 315 | slog("adb_listen: "); 316 | if (shoe.adb.timeout) { 317 | shoe.adb.timeout = 0; 318 | via->regb_input &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == timeout 319 | via_raise_interrupt(1, IFR_SHIFT_REG); 320 | slog("timeout\n"); 321 | return ; 322 | } 323 | 324 | if (shoe.adb.data_i < 8) 325 | shoe.adb.data[shoe.adb.data_i++] = via->sr; 326 | else 327 | assert(!"OS made us listen to > 8 bytes"); 328 | 329 | slog("loaded sr = 0x%02x\n", via->sr); 330 | 331 | break; 332 | } 333 | 334 | via->regb_input |= VIA_REGB_ADB_STATUS; // adb_status_line set == didn't-timeout 335 | via_raise_interrupt(1, IFR_SHIFT_REG); 336 | } 337 | 338 | static void adb_handle_state_two (void) // "Odd" state 339 | { 340 | via_state_t *via = &shoe.via[0]; 341 | 342 | slog("adb_handle_state_two: "); 343 | 344 | // If this transaction was part of a service request, clear the service_request flag now 345 | if (shoe.adb.service_request) { 346 | shoe.adb.service_request = 0; 347 | via->regb_input &= ~~VIA_REGB_ADB_STATUS; // adb_status_line cleared == service request 348 | slog("(service request) "); 349 | } 350 | else 351 | via->regb_input |= VIA_REGB_ADB_STATUS; // adb_status_line set == no-service request 352 | 353 | switch (shoe.adb.command_type) { 354 | case adb_flush: 355 | case adb_reset: 356 | slog("adb_flush/reset\n"); 357 | break; 358 | 359 | case adb_talk: 360 | slog("adb_talk: "); 361 | if (shoe.adb.data_i < shoe.adb.data_len) 362 | via->sr = shoe.adb.data[shoe.adb.data_i++]; 363 | else 364 | via->sr = 0; 365 | slog("set sr = 0x%02x\n", via->sr); 366 | break; 367 | 368 | case adb_listen: 369 | slog("adb_listen: "); 370 | if (shoe.adb.data_i < 8) 371 | shoe.adb.data[shoe.adb.data_i++] = via->sr; 372 | else 373 | assert(!"OS made us listen to > 8 bytes"); 374 | slog("read sr = 0x%02x\n", via->sr); 375 | break; 376 | } 377 | 378 | via_raise_interrupt(1, IFR_SHIFT_REG); 379 | } 380 | 381 | static void adb_handle_state_three (void) // "idle" state 382 | { 383 | slog("adb_handle_state_three: completed for id %u\n", shoe.adb.command_device_id); 384 | 385 | switch (shoe.adb.command_type) { 386 | case adb_reset: 387 | case adb_flush: 388 | case adb_talk: 389 | break; 390 | 391 | case adb_listen: 392 | slog("adb_handle_state_three: listen completed for id %u, reg %u, data_len = %u {%02x %02x}\n", 393 | shoe.adb.command_device_id, shoe.adb.command_reg, shoe.adb.data_i, shoe.adb.data[0], shoe.adb.data[1]); 394 | break; 395 | } 396 | 397 | adb_start_service_request(); 398 | } 399 | 400 | void adb_handle_state_change(uint8_t old_state, uint8_t new_state) 401 | { 402 | via_state_t *via = &shoe.via[0]; 403 | 404 | slog("%s: lock\n", __func__); fflush(stdout); 405 | assert(pthread_mutex_lock(&shoe.adb.lock) == 0); 406 | 407 | shoe.adb.state = new_state; 408 | 409 | switch (new_state) { 410 | case 0: 411 | shoe.adb.command_byte = via->sr; 412 | adb_handle_state_zero(shoe.adb.command_byte, 0); 413 | break ; 414 | 415 | case 1: 416 | adb_handle_state_one(); 417 | break ; 418 | 419 | case 2: 420 | adb_handle_state_two(); 421 | break ; 422 | 423 | case 3: 424 | adb_handle_state_three(); 425 | break ; 426 | } 427 | 428 | slog("%s: unlock\n", __func__); fflush(stdout); 429 | pthread_mutex_unlock(&shoe.adb.lock); 430 | } 431 | 432 | -------------------------------------------------------------------------------- /core/alloc_pool.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "../core/shoebill.h" 31 | 32 | 33 | 34 | /* 35 | #define POOL_ALLOC_TYPE 0 36 | #define POOL_CHILD_LINK 1 37 | #define POOL_HEAD 2 38 | typedef struct _alloc_pool_t { 39 | struct _alloc_pool_t *prev, *next; 40 | uint8_t type; 41 | union { 42 | struct { 43 | uint32_t size; 44 | } alloc; 45 | struct { 46 | struct _alloc_pool_t *child; // pointer to the child's HEAD 47 | } child_link; 48 | struct { 49 | struct _alloc_pool_t *parent_link; // pointer to the parent's CHILD_LINK 50 | } head; 51 | } t; 52 | 53 | uint32_t magic; 54 | } alloc_pool_t; 55 | */ 56 | 57 | static void _check_pool(alloc_pool_t *pool) 58 | { 59 | 60 | } 61 | 62 | static alloc_pool_t* _ptr_to_header(void *ptr) 63 | { 64 | alloc_pool_t *apt = (alloc_pool_t*)ptr; 65 | return &apt[-1]; 66 | } 67 | 68 | void* p_alloc(alloc_pool_t *pool, uint64_t size) 69 | { 70 | alloc_pool_t *buf = calloc(sizeof(alloc_pool_t) + size, 1); 71 | 72 | buf->type = POOL_ALLOC_TYPE; 73 | buf->t.alloc.size = size; 74 | 75 | buf->start_magic = POOL_START_MAGIC; 76 | buf->end_magic = POOL_END_MAGIC; 77 | 78 | buf->next = pool->next; 79 | buf->prev = pool; 80 | 81 | if (pool->next) 82 | pool->next->prev = buf; 83 | pool->next = buf; 84 | 85 | return &buf[1]; 86 | } 87 | 88 | void* p_realloc(void *ptr, uint64_t size) 89 | { 90 | alloc_pool_t *header = _ptr_to_header(ptr); 91 | 92 | assert(header->start_magic == POOL_START_MAGIC); 93 | assert(header->end_magic == POOL_END_MAGIC); 94 | assert(header->type == POOL_ALLOC_TYPE); 95 | 96 | alloc_pool_t *new_header = realloc(header, size + sizeof(alloc_pool_t)); 97 | 98 | if (new_header) { 99 | new_header->t.alloc.size = size; 100 | 101 | if (new_header->next) 102 | new_header->next->prev = new_header; 103 | 104 | if (new_header->prev) 105 | new_header->prev->next = new_header; 106 | 107 | return &new_header[1]; 108 | } 109 | 110 | return NULL; 111 | } 112 | 113 | /* 114 | * Free *any* kind of alloc_pool_t header 115 | */ 116 | static void _p_free_any(alloc_pool_t *header) 117 | { 118 | assert(header->start_magic == POOL_START_MAGIC); 119 | assert(header->end_magic == POOL_END_MAGIC); 120 | 121 | if (header->next) 122 | header->next->prev = header->prev; 123 | 124 | if (header->prev) 125 | header->prev->next = header->next; 126 | 127 | free(header); 128 | } 129 | 130 | /* 131 | * Free an alloc_pool allocation (but not HEAD or CHILD_LINK) 132 | */ 133 | void p_free(void *ptr) 134 | { 135 | alloc_pool_t *header = _ptr_to_header(ptr); 136 | assert(header->type == POOL_ALLOC_TYPE); 137 | memset(ptr, 0xaa, header->t.alloc.size); 138 | _p_free_any(header); 139 | } 140 | 141 | void p_free_pool(alloc_pool_t *pool) 142 | { 143 | while (pool->prev) 144 | pool = pool->prev; 145 | 146 | while (pool) { 147 | alloc_pool_t *cur = pool; 148 | pool = cur->next; 149 | assert(cur->start_magic == POOL_START_MAGIC); 150 | assert(cur->end_magic == POOL_END_MAGIC); 151 | 152 | switch (cur->type) { 153 | case POOL_ALLOC_TYPE: 154 | _p_free_any(cur); 155 | break; 156 | case POOL_CHILD_LINK: { 157 | // p_free_pool will free and unlink cur 158 | // (its parent's CHILD_LINK) 159 | p_free_pool(cur->t.child_link.child); 160 | break; 161 | } 162 | case POOL_HEAD: { 163 | if (cur->t.head.parent_link) { 164 | assert(cur->t.head.parent_link->type == POOL_CHILD_LINK); 165 | _p_free_any(cur->t.head.parent_link); 166 | } 167 | _p_free_any(cur); 168 | break; 169 | } 170 | default: 171 | assert(!"unknown POOL_ type"); 172 | } 173 | } 174 | } 175 | 176 | alloc_pool_t* p_new_pool(alloc_pool_t *parent_pool) 177 | { 178 | alloc_pool_t *pool = calloc(sizeof(alloc_pool_t), 1); 179 | 180 | pool->start_magic = POOL_START_MAGIC; 181 | pool->end_magic = POOL_END_MAGIC; 182 | pool->type = POOL_HEAD; 183 | 184 | if (parent_pool) { 185 | alloc_pool_t *link = _ptr_to_header(p_alloc(parent_pool, 0)); 186 | link->type = POOL_CHILD_LINK; 187 | link->t.child_link.child = pool; // child_link.child points to the child's HEAD 188 | 189 | pool->t.head.parent_link = link; // head.parent_link points to the parent's CHILD_LINK 190 | } 191 | else 192 | pool->t.head.parent_link = NULL; 193 | 194 | return pool; 195 | } -------------------------------------------------------------------------------- /core/coff.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "shoebill.h" 33 | 34 | void symb_inorder(rb_node *cur) { 35 | const coff_symbol *sym = *(coff_symbol**)&cur[1]; 36 | if (!sym) 37 | return ; 38 | symb_inorder(cur->left); 39 | slog("0x%x %s\n", cur->key, sym->name); 40 | symb_inorder(cur->right); 41 | } 42 | 43 | #define _coff_buf_seek(__len) ({ \ 44 | uint32_t _result = 1, _len=(__len); \ 45 | if (_len > buflen) _result = 0; \ 46 | else bufptr = _len; \ 47 | _result; \ 48 | }) 49 | 50 | #define _coff_buf_read(_dst, __len) ({\ 51 | uint32_t _result = 1, _len=(__len); \ 52 | if ((bufptr + _len) > buflen) \ 53 | _result = 0; \ 54 | else {\ 55 | memcpy((_dst), buf+bufptr, _len); \ 56 | bufptr += _len; \ 57 | } \ 58 | _result; \ 59 | }) 60 | 61 | void coff_free(coff_file *coff) 62 | { 63 | p_free_pool(coff->pool); 64 | } 65 | 66 | // Given a path to a COFF binary, create a coff_file structure and return a pointer. 67 | coff_file* coff_parse(uint8_t *buf, uint32_t buflen, alloc_pool_t *parent_pool) 68 | { 69 | uint8_t rawhead[20], *ptr; 70 | uint32_t i; 71 | coff_file *cf = NULL; 72 | uint32_t bufptr = 0; 73 | alloc_pool_t *pool = p_new_pool(parent_pool); 74 | 75 | // Pull out 20 bytes (the file header) 76 | if (!_coff_buf_read(rawhead, 20)) { 77 | slog("coff_parse: error: this binary is missing its file header\n"); 78 | goto fail; 79 | } 80 | 81 | // Allocate a coff_file and copy in the header 82 | cf = (coff_file*)p_alloc(pool, sizeof(coff_file)); 83 | cf->pool = pool; 84 | ptr = rawhead; 85 | 86 | cf->magic = be2native(&ptr, 2); 87 | cf->num_sections = be2native(&ptr, 2); 88 | cf->timestamp = be2native(&ptr, 4); 89 | cf->symtab_offset = be2native(&ptr, 4); 90 | cf->num_symbols = be2native(&ptr, 4); 91 | cf->opt_header_len = be2native(&ptr, 2); 92 | cf->flags = be2native(&ptr, 2); 93 | 94 | // A little sanity checking... 95 | if (cf->magic != 0x150) { 96 | slog("coff_parse: I don't recognize this magic number: 0x%04x\n", cf->magic); 97 | goto fail; 98 | } 99 | else if (cf->num_sections != 3) { 100 | //slog("coff_parse: warning: there are %u sections in this file (not 3, like I expect)\n", cf->num_sections); 101 | // FIXME: investigate all the other possible section types 102 | } 103 | 104 | // pull out cf->opt_header bytes (a.out-format header, I guess?) 105 | if (cf->opt_header_len > 0) { 106 | uint8_t *opt = p_alloc(cf->pool, cf->opt_header_len); 107 | if (!_coff_buf_read(opt, cf->opt_header_len)) { 108 | slog("coff_parse: I ran out of data pulling the optional header (%u bytes)\n", cf->opt_header_len); 109 | p_free(opt); 110 | goto fail; 111 | } 112 | cf->opt_header = opt; 113 | } 114 | 115 | // start pulling out sections 116 | cf->sections = p_alloc(cf->pool, cf->num_sections * sizeof(coff_section)); 117 | for (i=0; inum_sections; i++) { 118 | // read the header 119 | uint8_t rawsec[40]; 120 | if (!_coff_buf_read(rawsec, 40)) { 121 | slog("coff_parse: I ran out of data pulling section #%u\n", i+1); 122 | goto fail; 123 | } 124 | // and copy it into cf->sections[i] 125 | memcpy(cf->sections[i].name, rawsec, 8); 126 | ptr = &rawsec[8]; 127 | cf->sections[i].p_addr = be2native(&ptr, 4); 128 | cf->sections[i].v_addr = be2native(&ptr, 4); 129 | cf->sections[i].sz = be2native(&ptr, 4); 130 | cf->sections[i].data_ptr = be2native(&ptr, 4); 131 | cf->sections[i].reloc_ptr = be2native(&ptr, 4); 132 | cf->sections[i].line_ptr = be2native(&ptr, 4); 133 | cf->sections[i].num_relocs = be2native(&ptr, 2); 134 | cf->sections[i].num_lines = be2native(&ptr, 2); 135 | cf->sections[i].flags = be2native(&ptr, 4); 136 | 137 | // a little bit of sanity checking: 138 | if (cf->sections[i].v_addr != cf->sections[i].p_addr) { 139 | //slog("coff_parse: warning: section %u's virtual_addr and physical_addr don't match: p=%x v=%x\n", 140 | // i+1, cf->sections[i].p_addr, cf->sections[i].v_addr); 141 | // This is okay for the unix kernel 142 | } 143 | } 144 | 145 | // pull out the corresponding raw data for each section 146 | for (i=0; inum_sections; i++) { 147 | uint8_t *data; 148 | 149 | // don't bother if there's no data 150 | if (cf->sections[i].sz == 0) { 151 | continue ; 152 | } 153 | 154 | // don't bother if it's .bss 155 | if (memcmp(cf->sections[i].name, ".bss\0\0\0\0", 8)==0) { 156 | continue ; 157 | } 158 | 159 | // seek to the position in the binary that holds this section's raw data 160 | if (!_coff_buf_seek(cf->sections[i].data_ptr)) { 161 | slog("coff_parse: I couldn't seek to 0x%x in section %u\n", cf->sections[i].data_ptr, i+1); 162 | goto fail; 163 | } 164 | 165 | // load the data and attach it to the section struct 166 | data = p_alloc(cf->pool, cf->sections[i].sz); // FIXME: sz might not be a sane value 167 | if (!_coff_buf_read(data, cf->sections[i].sz)) { 168 | 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); 169 | p_free(data); 170 | goto fail; 171 | } 172 | cf->sections[i].data = data; 173 | } 174 | 175 | // pull out the symbol table 176 | 177 | if (cf->num_symbols == 0) // if num_symbols==0, symtab_offset may be bogus 178 | return cf; // just return 179 | 180 | cf->func_tree = rb_new(cf->pool, sizeof(coff_symbol*)); 181 | //slog("func_tree = %llx, *func_tree = %llx\n", cf->func_tree, *cf->func_tree); 182 | cf->symbols = (coff_symbol*)p_alloc(cf->pool, sizeof(coff_symbol) *cf->num_symbols); 183 | 184 | // Seek to the symbol table 185 | if (!_coff_buf_seek(cf->symtab_offset)) { 186 | slog("coff_parse: I couldn't seek to symtab_offset, 0x%x\n", cf->symtab_offset); 187 | goto fail; 188 | } 189 | 190 | for (i=0; i < cf->num_symbols; i++) { 191 | uint8_t raw_symb[18]; 192 | if (!_coff_buf_read(raw_symb, 18)) { 193 | slog("coff_parse: I ran out of data pulling symbol #%u\n", i+1); 194 | goto fail; 195 | } 196 | 197 | // load the name 198 | if (*((uint32_t*)raw_symb) == 0) { 199 | uint8_t tmp_name[256]; 200 | uint32_t j, offset, idx = cf->symtab_offset + 18*cf->num_symbols; 201 | for (j=4, offset=0; j<8; j++) offset = (offset<<8) | raw_symb[j]; 202 | idx += offset; 203 | 204 | // slog("Loading from external: base idx=0x%x, offset=%u, addr=0x%x\n", idx-offset, offset, idx); 205 | 206 | if (!_coff_buf_seek(idx)) { 207 | slog("coff_parse: I ran out of data pulling symbol %u's name (idx=0x%x)\n", i+1, idx); 208 | goto fail; 209 | } 210 | for (j=0; (_coff_buf_read(&tmp_name[j], 1)) && tmp_name[j]; j++) { 211 | if (j >= 255) { 212 | // slog("coff_parse: this symbol's name is too long: %u\n", i+1); 213 | goto fail; 214 | } 215 | } 216 | cf->symbols[i].name = p_alloc(cf->pool, j+1); 217 | memcpy(cf->symbols[i].name, tmp_name, j); 218 | cf->symbols[i].name[j] = 0; 219 | _coff_buf_seek(cf->symtab_offset + (i+1)*18); 220 | } 221 | else { 222 | uint8_t tmp_name[9]; 223 | memcpy(tmp_name, raw_symb, 8); 224 | tmp_name[8] = 0; 225 | cf->symbols[i].name = strdup((char*)tmp_name); 226 | } 227 | 228 | ptr = &raw_symb[8]; 229 | cf->symbols[i].value = be2native(&ptr, 4); 230 | cf->symbols[i].scnum = be2native(&ptr, 2); 231 | cf->symbols[i].type = be2native(&ptr, 2); 232 | cf->symbols[i].sclass = raw_symb[16]; 233 | cf->symbols[i].numaux = raw_symb[17]; 234 | 235 | // FIXME: I need to handle numaux > 0. 236 | 237 | //if (cf->symbols[i].numaux > 0) { 238 | slog("%s\n", cf->symbols[i].name); 239 | slog("value=0x%08x scnum=0x%04x type=0x%04x sclass=0x%02x numaux=%u\n\n", 240 | cf->symbols[i].value, cf->symbols[i].scnum, cf->symbols[i].type, cf->symbols[i].sclass, cf->symbols[i].numaux); 241 | //} 242 | 243 | 244 | if (cf->symbols[i].sclass == 2 || cf->symbols[i].sclass == 3) { 245 | void *ptr = &cf->symbols[i]; 246 | rb_insert(cf->func_tree, cf->symbols[i].value, &ptr, NULL); 247 | //slog("%s addr=0x%x\n", cf->symbols[i].name, cf->symbols[i].value); 248 | } 249 | // slog("%u: %s (class=%u)\n", i+1, cf->symbols[i].name, cf->symbols[i].sclass); 250 | 251 | } 252 | 253 | // symb_inorder(*cf->func_tree); 254 | 255 | // and we're done 256 | return cf; 257 | 258 | fail: 259 | if (cf) { 260 | if (cf->opt_header) { 261 | p_free(cf->opt_header); 262 | } 263 | if (cf->sections) { 264 | for (i=0; inum_sections; i++) { 265 | if (cf->sections[i].data) { 266 | p_free(cf->sections[i].data); 267 | } 268 | } 269 | p_free(cf->sections); 270 | } 271 | p_free(cf); 272 | } 273 | return NULL; 274 | } 275 | 276 | coff_file* coff_parse_from_path(const char *path, alloc_pool_t *parent_pool) 277 | { 278 | FILE *f = fopen(path, "rb"); 279 | uint8_t *buf = malloc(1); 280 | uint32_t i=0, tmp; 281 | coff_file *coff; 282 | 283 | do { 284 | buf = realloc(buf, i + 128*1024); 285 | assert(buf); 286 | tmp = fread(buf+i, 1, 128*1024, f); 287 | i += tmp; 288 | 289 | // don't load more than 64mb - there are surely no 64MB A/UX kernels 290 | } while ((tmp > 0) && (i < 64*1024*1024)); 291 | 292 | 293 | coff = coff_parse(buf, i, parent_pool); 294 | free(buf); 295 | return coff; 296 | } 297 | 298 | // dump some data about a coff_file structure 299 | void print_coff_info(coff_file *coff) 300 | { 301 | char timebuf[32]; 302 | time_t timestamp = coff->timestamp; 303 | uint32_t i; 304 | 305 | slog("Magic = 0x%04x\n", coff->magic); 306 | slog("Linked on %s", ctime_r(×tamp, timebuf)); 307 | slog("Num sections = %u\n", coff->num_sections); 308 | 309 | slog("debug: num_symbols=%u, symtab_offset=0x%x\n", coff->num_symbols, coff->symtab_offset); 310 | 311 | for (i=0; inum_sections; i++) { 312 | coff_section *s = &coff->sections[i]; 313 | char name[9]; 314 | memcpy(name, s->name, 8); 315 | name[8] = 0; 316 | slog("Section #%u: %s\n", i+1, name); 317 | 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); 318 | } 319 | } 320 | 321 | coff_symbol* coff_find_symbol(coff_file *coff, const char *name) 322 | { 323 | uint32_t i; 324 | 325 | for (i=0; i < coff->num_symbols; i++) { 326 | if (strcmp(coff->symbols[i].name, name) == 0) 327 | return &coff->symbols[i]; 328 | } 329 | return NULL; 330 | } 331 | 332 | coff_symbol* coff_find_func(coff_file *coff, uint32_t addr) 333 | { 334 | rb_node *cur; 335 | coff_symbol *last = NULL; 336 | 337 | // slog("coff->num_symbols = %u\n", coff->num_symbols); 338 | if (coff->num_symbols == 0) 339 | return NULL; 340 | cur = coff->func_tree->root; 341 | 342 | while (cur) { 343 | // slog("... iterating\n"); 344 | if (addr < cur->key) 345 | cur = cur->left; 346 | else if (addr > cur->key) { 347 | last = *(coff_symbol**)&cur[1]; 348 | cur = cur->right; 349 | } 350 | else 351 | return *(coff_symbol**)&cur[1]; 352 | } 353 | 354 | return last; 355 | } 356 | 357 | 358 | // big endian -> native int 359 | uint32_t be2native (uint8_t **dat, uint32_t bytes) 360 | { 361 | uint32_t i, v = 0; 362 | for (i=0; i < bytes; i++) 363 | v = (v<<8) | (*dat)[i]; 364 | (*dat) += bytes; 365 | return v; 366 | } 367 | 368 | -------------------------------------------------------------------------------- /core/ethernet_rom/rom.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pruten/shoebill/a9b2af09c078c16d9b286067d72e3e6deaad9660/core/ethernet_rom/rom.bin -------------------------------------------------------------------------------- /core/ethernet_rom/shoebill_ether.make: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pruten/shoebill/a9b2af09c078c16d9b286067d72e3e6deaad9660/core/ethernet_rom/shoebill_ether.make -------------------------------------------------------------------------------- /core/ethernet_rom/shoebill_ether_rom.a: -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- /core/exception.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | #include 26 | #include 27 | #include "shoebill.h" 28 | 29 | 30 | #define SSW_IS_READ (1<<6) 31 | #define SSW_DF (1<<8) 32 | 33 | /* 34 | * Throw the long-format (format 0xb) bus error. Mac II ROM expects to see 35 | * this format for nubus bus errors. 36 | * 37 | * FIXME: nearly all the fields here are bogus 38 | */ 39 | void throw_long_bus_error(uint32_t addr, uint8_t is_write) 40 | { 41 | if (shoe.suppress_exceptions) { 42 | shoe.abort = 1; 43 | return ; 44 | } 45 | // Save this value now, because lset() calls will reset it 46 | const uint8_t fc = shoe.logical_fc; 47 | 48 | //slog("throw_long_bus_error(): I'm throwing a LONG bus error (at pc = 0x%08x)!\n", shoe.orig_pc); 49 | 50 | // set supervisor bit 51 | set_sr_s(1); 52 | 53 | // inhibit tracing 54 | set_sr_t0(0); 55 | set_sr_t1(0); 56 | 57 | // compute vector offset 58 | const uint32_t vector_num = 2; 59 | const uint32_t vector_offset = vector_num * 4; 60 | 61 | // fetch vector handler address 62 | const uint32_t vector_addr = lget(shoe.vbr + vector_offset, 4); 63 | //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); 64 | assert(!shoe.abort); // FIXME: I can't handle another exception here 65 | 66 | const uint16_t ssw = SSW_DF | (is_write ? 0 : SSW_IS_READ) | fc; 67 | 68 | // Note: We're pushing frame format 0xB 69 | 70 | push_a7(0, 4); // internal registers, 18 words 71 | push_a7(0, 4); 72 | push_a7(0, 4); 73 | push_a7(0, 4); 74 | push_a7(0, 4); 75 | push_a7(0, 4); 76 | push_a7(0, 4); 77 | push_a7(0, 4); 78 | push_a7(0, 4); 79 | 80 | push_a7(0x0000, 2); // version + internal information 81 | 82 | push_a7(0, 2); // internal registers, 3 words 83 | push_a7(0, 4); 84 | 85 | push_a7(0, 4); // data input buffer 86 | 87 | push_a7(0, 4); // Internal register, 2 words 88 | 89 | push_a7(0, 4); // Stage B addr 90 | 91 | push_a7(0, 4); // Internal register, 4 words 92 | push_a7(0, 4); // 93 | 94 | push_a7(0, 4); // data output buffer 95 | push_a7(0, 4); // internal registers 3 and 2 96 | push_a7(addr, 4); // data cycle fault address 97 | push_a7(0, 4); // instruction pipe stage B and C 98 | push_a7(ssw, 2); // special status word 99 | push_a7(0, 2); // internal register 1 100 | push_a7(0xB000 | vector_offset, 2); // format word (frame format B) 101 | push_a7(shoe.orig_pc, 4); // PC for the current instruction 102 | push_a7(shoe.orig_sr, 2); // original status register 103 | 104 | shoe.pc = vector_addr; 105 | 106 | assert(!shoe.abort); // FIXME: again, can't handle an exception here 107 | 108 | shoe.abort = 1; 109 | } 110 | 111 | void throw_bus_error(uint32_t addr, uint8_t is_write) 112 | { 113 | if (shoe.suppress_exceptions) { 114 | shoe.abort = 1; 115 | return ; 116 | } 117 | 118 | // Save this value now, because lset() calls will reset it 119 | const uint8_t fc = shoe.logical_fc; 120 | 121 | //dbg_state.running = 0; 122 | 123 | //slog("throw_bus_error(): I'm throwing a bus error (at pc = 0x%08x)!\n", shoe.orig_pc); 124 | 125 | // set supervisor bit 126 | set_sr_s(1); 127 | 128 | // inhibit tracing 129 | set_sr_t0(0); 130 | set_sr_t1(0); 131 | 132 | // compute vector offset 133 | const uint32_t vector_num = 2; 134 | const uint32_t vector_offset = vector_num * 4; 135 | 136 | // fetch vector handler address 137 | const uint32_t vector_addr = lget(shoe.vbr + vector_offset, 4); 138 | //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]); 139 | assert(!shoe.abort); // FIXME: I can't handle another exception here 140 | 141 | const uint16_t ssw = 142 | SSW_DF | // the cpu will rerun the memory access 143 | (is_write ? 0 : SSW_IS_READ) | // read or write 144 | fc; // a/ux 3.0.1 cares about this - the address space 145 | 146 | //slog(" fc=%u\n", shoe.logical_fc); 147 | 148 | // Note: We're pushing frame format 0xA 149 | push_a7(0, 4); // internal registers 5 and 4 150 | push_a7(0, 4); // data output buffer 151 | push_a7(0, 4); // internal registers 3 and 2 152 | push_a7(addr, 4); // data cycle fault address 153 | push_a7(0, 4); // instruction pipe stage B and C 154 | push_a7(ssw, 2); // special status word 155 | push_a7(0, 2); // internal register 1 156 | push_a7(0xA000 | vector_offset, 2); // format word 157 | push_a7(shoe.orig_pc, 4); // PC for the current instruction 158 | push_a7(shoe.orig_sr, 2); // original status register 159 | 160 | shoe.pc = vector_addr; 161 | 162 | assert(!shoe.abort); // FIXME: again, can't handle an exception here 163 | 164 | shoe.abort = 1; 165 | } 166 | 167 | 168 | void throw_address_error() 169 | { 170 | slog("throw_address_error(): I'm throwing an address error!\n"); 171 | assert(!"address error"); 172 | shoe.abort = 1; 173 | } 174 | 175 | void throw_frame_zero(uint16_t sr, uint32_t pc, uint16_t vector_num) 176 | { 177 | // set supervisor bit 178 | set_sr_s(1); 179 | 180 | // inhibit tracing 181 | set_sr_t0(0); 182 | set_sr_t1(0); 183 | 184 | const uint32_t vector_addr = lget(shoe.vbr + vector_num*4, 4); 185 | assert(!shoe.abort); // FIXME: I can't handle another exception here 186 | 187 | push_a7(vector_num*4, 2); 188 | push_a7(pc, 4); 189 | push_a7(sr, 2); 190 | 191 | shoe.pc = vector_addr; 192 | 193 | shoe.abort = 1; 194 | } 195 | 196 | void throw_frame_two (uint16_t sr, uint32_t next_pc, uint32_t vector_num, uint32_t orig_pc) 197 | { 198 | set_sr_s(1); 199 | 200 | // inhibit tracing 201 | set_sr_t0(0); 202 | set_sr_t1(0); 203 | 204 | const uint32_t vector_addr = lget(shoe.vbr + vector_num*4, 4); 205 | assert(!shoe.abort); // FIXME: can't handle exception here 206 | 207 | const uint16_t frame_word = 0x2000 | (vector_num*4); 208 | 209 | push_a7(orig_pc, 4); 210 | push_a7(frame_word, 2); 211 | push_a7(next_pc, 4); 212 | push_a7(sr, 2); 213 | 214 | shoe.pc = vector_addr; 215 | shoe.abort = 1; 216 | } 217 | 218 | void throw_illegal_instruction() 219 | { 220 | //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]); 221 | 222 | /*if ((shoe.op != 0xf010) && ((shoe.op >> 12) != 0xa)) 223 | //assert(!"illegal"); 224 | dbg_state.running = 0; */ 225 | 226 | // fetch vector number 227 | const uint32_t vector_num = 228 | ((shoe.op>>12) == 0xa) ? 10 : 229 | (((shoe.op>>12) == 0xf) ? 11 : 4); 230 | 231 | throw_frame_zero(shoe.orig_sr, shoe.orig_pc, vector_num); 232 | 233 | /*if ((shoe.op >> 12) == 0xa) { 234 | slog("Atrap: %s\n", atrap_names[shoe.op & 0xfff]?atrap_names[shoe.op & 0xfff]:"???"); 235 | } 236 | else 237 | dbg_state.running = 0;*/ 238 | shoe.abort = 1; 239 | } 240 | 241 | void throw_privilege_violation() 242 | { 243 | //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); 244 | 245 | throw_frame_zero(shoe.orig_sr, shoe.orig_pc, 8); 246 | // shoe.abort = 1; 247 | 248 | } 249 | -------------------------------------------------------------------------------- /core/floppy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | 27 | #include 28 | #include 29 | #include 30 | #include "../core/shoebill.h" 31 | 32 | const char *latch_names[8] = { 33 | "phase0", "phase1", "phase2", "phase3", 34 | "motor", "drive", "L6", "L7" 35 | }; 36 | 37 | const char *reg_names[8] = { 38 | "ones", "read-data", "status", "status", 39 | "handshake", "handshake", "mode", "write-data" 40 | }; 41 | 42 | uint8_t iwm_dma_read() 43 | { 44 | const uint8_t latch_addr = (shoe.physical_addr >> 10) & 0x7; 45 | const uint8_t latch_val = (shoe.physical_addr >> 9) & 1; 46 | uint8_t result; 47 | 48 | if (latch_val) 49 | shoe.iwm.latch |= (1 << latch_addr); 50 | else 51 | shoe.iwm.latch &= (~~(1 << latch_addr)); 52 | 53 | // reg = {q7, q6, motor} 54 | const uint8_t reg = ((shoe.iwm.latch >> 5) & 6) | 55 | ((shoe.iwm.latch >> 4) & 1); 56 | 57 | slog("iwm_dma_read: %s %s (reg = %u%u%u '%s' ", 58 | latch_val ? "setting" : "clearing", 59 | latch_names[latch_addr], 60 | (reg>>2), (reg>>1)&1, reg&1, reg_names[reg]); 61 | 62 | 63 | // Allegedly, register reads can only occur when latch_val==0 64 | if (latch_val) { 65 | result = 0; 66 | goto done; 67 | } 68 | 69 | switch (reg) { 70 | case 0: // read all ones 71 | result = 0xff; 72 | break; 73 | case 1: // read data register 74 | result = shoe.iwm.data; 75 | break; 76 | case 2: 77 | case 3: // Read status register 78 | // High 3 bits are mode register, low 5 are status 79 | result = (shoe.iwm.status & ~b(10100000)); 80 | result |= (shoe.iwm.mode & ~b(11111)); 81 | break; 82 | case 4: 83 | case 5: // Read "write-handshake" register 84 | result = (shoe.iwm.handshake | ~b(00111111)); // low 6 bits all 1's 85 | break; 86 | default: 87 | result = 0; 88 | break; 89 | } 90 | done: 91 | 92 | slog("result=0x%02x)\n", result); 93 | 94 | return result; 95 | } 96 | void iwm_dma_write() 97 | { 98 | const uint8_t latch_addr = (shoe.physical_addr >> 10) & 0x7; 99 | const uint8_t latch_val = (shoe.physical_addr >> 9) & 1; 100 | 101 | uint8_t data = shoe.physical_dat; 102 | 103 | if (latch_val) 104 | shoe.iwm.latch |= (1 << latch_addr); 105 | else 106 | shoe.iwm.latch &= (~~(1 << latch_addr)); 107 | 108 | // reg = {q7, q6, motor} 109 | const uint8_t reg = ((shoe.iwm.latch >> 5) & 6) | 110 | ((shoe.iwm.latch >> 4) & 1); 111 | 112 | slog("iwm_dma_write: %s %s (reg = %u%u%u '%s' val 0x%02x)\n", 113 | latch_val ? "setting" : "clearing", 114 | latch_names[latch_addr], 115 | (reg>>2), (reg>>1)&1, reg&1, reg_names[reg], 116 | data); 117 | 118 | // Allegedly, register writes can only occur when latch_val==1 119 | if (!latch_val) { 120 | return ; 121 | } 122 | 123 | switch (reg) { 124 | case 6: // Write mode 125 | shoe.iwm.mode = data & ~b(01111111); 126 | break; 127 | case 7: // Write data 128 | shoe.iwm.data = data; 129 | break; 130 | } 131 | } 132 | 133 | void init_iwm_state () 134 | { 135 | memset(&shoe.iwm, 0, sizeof(iwm_state_t)); 136 | } 137 | 138 | void reset_iwm_state () 139 | { 140 | memset(&shoe.iwm, 0, sizeof(iwm_state_t)); 141 | } -------------------------------------------------------------------------------- /core/macro.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # Copyright (c) 2013, Peter Rutenbar 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, 12 | # this list of conditions and the following disclaimer in the documentation 13 | # and/or other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | 27 | use strict; 28 | use Carp; 29 | use Storable qw(dclone); 30 | 31 | my $tab = " "; # one tab => four spaces 32 | 33 | main(); 34 | 35 | sub main { 36 | 37 | my $input = ""; 38 | 39 | if (($#ARGV) != 1) { 40 | my $args = $#ARGV + 1; 41 | croak "I need two arguments (got $args)"; 42 | } 43 | 44 | open(INPUT, $ARGV[0]) or die croak "I can't open $ARGV[0]!"; 45 | while (my $line = ) { 46 | $input .= $line; 47 | } 48 | close(INPUT); 49 | 50 | $input = tabs_to_spaces($input); # it's simpler to deal with if all indentation can be represented as a # of spaces 51 | my $ctx = { 52 | text => line_logic($input), # the input text 53 | out => "", # the output text 54 | depth => 0, # the recursive depth of the parser 55 | filename => $ARGV[0], # the name of the input file 56 | adhoc => {} # hash of adhoc function refs 57 | }; 58 | parse($ctx); 59 | 60 | open(OUTPUT, '>'.$ARGV[1]); 61 | print OUTPUT "/* Generated from $ARGV[0] */\n\n"; 62 | print OUTPUT $ctx->{out}; 63 | close(OUTPUT); 64 | } 65 | 66 | sub tabs_to_spaces { 67 | my @chars = split //,shift; 68 | my $output = ""; 69 | foreach my $c (@chars) { 70 | if ($c eq "\t") { 71 | $output .= $tab; # a tab is 4 spaces (imho) 72 | } else { 73 | $output .= $c; 74 | } 75 | } 76 | return $output; 77 | } 78 | 79 | sub line_logic { 80 | # For simplicity, line numbers start at 0 81 | my $raw = shift; 82 | my @lines = split /\n/,$raw; 83 | 84 | my @indents; # $indents[n] => the indent prefix for nth line 85 | my @chars; # all the characters in the input text 86 | my @line_map; # $line_map[n] => the line number to which the nth character belongs 87 | 88 | my $line_no = 0; 89 | foreach my $line (@lines) { 90 | my $past_indent = 0; 91 | my $indent_count = 0; 92 | my @l_chars = split //, $line; 93 | foreach my $c (@l_chars) { 94 | unless ($c eq " ") { 95 | $past_indent = 1; 96 | } 97 | if ($past_indent) { 98 | push @chars, $c; 99 | push @line_map, $line_no; 100 | } 101 | else { 102 | $indent_count++; 103 | } 104 | } 105 | push @indents, $indent_count; 106 | push @chars, "\n"; 107 | push @line_map, $line_no; 108 | $line_no++; 109 | } 110 | 111 | return { 112 | indents => \@indents, 113 | chars => \@chars, 114 | line_map => \@line_map, 115 | line_no => $line_no 116 | }; 117 | } 118 | 119 | sub spaces { 120 | my $count = shift; 121 | my $out = ""; 122 | for (my $i=0; $i < $count; $i++) { 123 | $out .= " "; 124 | } 125 | return $out; 126 | } 127 | 128 | sub parse { 129 | my $ctx = shift; 130 | my $out = ""; 131 | my $text = $ctx->{text}; 132 | 133 | my $newline = 1; 134 | for (my $i=0; $i < scalar(@{$text->{chars}}); $i++) { # iterate over every character in the input 135 | my $c = $text->{chars}->[$i]; 136 | my $line_no = $text->{line_map}->[$i]; 137 | $ctx->{current_line} = $line_no+1; # this is so macros can know what line they were called from 138 | 139 | if ($newline) { # a newline just began 140 | $newline = 0; 141 | $ctx->{indent} = $text->{indents}->[$line_no]; # keep track of how many indents are on this line 142 | $out .= spaces($ctx->{indent}); # and begin the line with the appropriate indentation 143 | } 144 | 145 | if ($c ne "~") { 146 | $out .= $c; 147 | } else { 148 | my $line_str = ""; 149 | $ctx->{cur_pos} = $i; 150 | 151 | my $macro = resolve_macro($ctx); 152 | 153 | $i = $ctx->{cur_pos}; 154 | $out .= join("\n$line_str".spaces($ctx->{indent}), split(/\n/, $macro->{str})); 155 | } 156 | 157 | if ($c eq "\n") { # a newline begins on the next character 158 | $newline = 1; 159 | } 160 | } 161 | 162 | $ctx->{out} = $out; 163 | } 164 | 165 | sub trim { 166 | my $str = shift; 167 | $str =~ s/^\s+//; 168 | $str =~ s/\s+$//; 169 | return $str; 170 | } 171 | 172 | sub resolve_macro { 173 | my $ctx = shift; 174 | my $text = $ctx->{text}; 175 | my $chars = $text->{chars}; 176 | my $i = $ctx->{cur_pos}; 177 | 178 | # "~~" => "~" 179 | if (($chars->[$i] eq "~") and ($chars->[$i+1] eq "~")) { 180 | $ctx->{cur_pos} = $i+1; 181 | return {str => "~"}; 182 | } 183 | 184 | # ~macro_name(arg1, arg2, { 185 | # printf("code goes here"); 186 | # }) 187 | 188 | # parse out the macro name 189 | my $macro_name = ""; 190 | for ($i++; ($i < scalar(@$chars)) and ($chars->[$i] ne "("); $i++) { 191 | $macro_name .= $chars->[$i]; 192 | } 193 | if ((length($macro_name) > 80) or ($i == scalar(@$chars)) or ($chars->[$i] ne "(")) { 194 | croak sprintf("line=%u: I call bullshit on this macro call: starts \"%s...\"", 195 | 1+$text->{line_map}->[$ctx->{cur_pos}], substr($macro_name, 0, 10)); 196 | } 197 | $macro_name = trim($macro_name); 198 | 199 | # parse out the macro arguments 200 | my @macro_args; 201 | for ($i++; ($i < scalar(@$chars)) and ($chars->[$i] ne ")"); ) { 202 | 203 | if (($chars->[$i] =~ /\s/) or ($chars->[$i] eq ',')) { 204 | $i++; 205 | } 206 | elsif ($chars->[$i] eq "{") { 207 | # process code block 208 | $ctx->{cur_pos} = $i; 209 | my $block = do_parse_recurse($ctx); 210 | $i = $ctx->{cur_pos}; 211 | push @macro_args, $block; 212 | } 213 | else { 214 | # plain text argument 215 | my $arg = ""; 216 | my $paren_count = 1; 217 | for (; ($i < scalar(@$chars)) and (!(($paren_count==1)and($chars->[$i]eq')'))) and ($chars->[$i] ne ","); $i++) { 218 | if ($chars->[$i] eq ')') {$paren_count--;} 219 | elsif ($chars->[$i] eq '(') {$paren_count++;} 220 | $arg .= $chars->[$i]; 221 | # printf("character = %s, paren_count = %u\n", $chars->[$i], $paren_count); 222 | } 223 | 224 | if ($i == scalar(@$chars)) { 225 | croak(sprintf('line=%u: argument #%u seems bogus', $text->{line_map}->[$ctx->{cur_pos}], scalar(@macro_args))); 226 | } 227 | $arg = trim($arg); 228 | 229 | # if the argument is encased in quotes, eval it 230 | if ( (length($arg)>0) and ( (substr($arg, 0, 1) eq "'") or (substr($arg, 0, 1) eq "\"") ) ) { 231 | my $newarg = ""; 232 | eval '$newarg'." = $arg;"; 233 | croak(sprintf("line=%u: eval() doesn't like argument at all: \"%s\" (%s)", 234 | 1+$text->{line_map}->[$ctx->{cur_pos}], $arg, $@)) if $@; 235 | $arg = $newarg; 236 | } 237 | 238 | push @macro_args, $arg; 239 | } 240 | } 241 | 242 | # evaluate macro 243 | my $macro_call; 244 | my $macro_return; 245 | if (exists $ctx->{adhoc}->{$macro_name}) { 246 | $macro_call = sprintf('$macro_return = $ctx->{adhoc}->{%s}->(\@macro_args,$ctx);', $macro_name); 247 | } else { 248 | $macro_call = sprintf('$macro_return = macro_%s(\@macro_args,$ctx);', $macro_name); 249 | } 250 | eval $macro_call; 251 | if ($@) { 252 | croak(sprintf("line=%u: Macro failed (exploded):\n%s", 1+$text->{line_map}->[$ctx->{cur_pos}], $@)); 253 | } 254 | 255 | $ctx->{cur_pos} = $i; 256 | return {str => $macro_return}; 257 | } 258 | 259 | sub do_parse_recurse { 260 | my $oldctx = shift; 261 | my $oldtext = $oldctx->{text}; 262 | my $oldchars = $oldtext->{chars}; 263 | my $oldline_map = $oldtext->{line_map}; 264 | my $old_indents = $oldtext->{indents}; 265 | 266 | # dclone can't handle CODE references, apparently 267 | my $adhoc_backup = $oldctx->{adhoc}; 268 | delete $oldctx->{adhoc}; 269 | my $newctx = dclone($oldctx); 270 | $oldctx->{adhoc} = $adhoc_backup; 271 | $newctx->{adhoc} = {}; 272 | foreach my $key (keys %$adhoc_backup) { 273 | $newctx->{adhoc}->{$key} = $adhoc_backup->{$key}; 274 | } 275 | 276 | my $blockstart = $oldctx->{cur_pos}; # points to '{' 277 | my $i = $blockstart+1; # the first character we're given is '{', skip past it 278 | for (my $curly_level=1; ($i < scalar(@$oldchars)) and ($curly_level != 0); $i++) { 279 | if ($oldchars->[$i] eq '{') {$curly_level++;} 280 | elsif ($oldchars->[$i] eq '}') {$curly_level--;} 281 | } 282 | my $blockend = $i - 1; # points to '}' 283 | my $blocklen = $blockend - ($blockstart + 1); # the length of the text inside the block 284 | 285 | my @newchars = @{$oldchars}[($blockstart+1)..($blockend-1)]; 286 | my @newline_map = @{$oldline_map}[($blockstart+1)..($blockend-1)]; 287 | 288 | my $orig_indent = $old_indents->[$oldline_map->[$blockstart]]; 289 | for (my $i=0; $i < $blocklen; $i++) { 290 | my $oldi = $blockstart+1+$i; 291 | my $line = $newline_map[$i]; 292 | 293 | if ($old_indents->[$line] >= $orig_indent) { 294 | $newctx->{text}->{indents}->[$line] = $old_indents->[$line] - $orig_indent; 295 | } else { 296 | $newctx->{text}->{indents}->[$line] = 0; 297 | } 298 | } 299 | 300 | $newctx->{text}->{chars} = \@newchars; 301 | $newctx->{text}->{line_map} = \@newline_map; 302 | $newctx->{depth}++; 303 | $newctx->{out} = ""; 304 | 305 | parse($newctx); 306 | 307 | $oldctx->{cur_pos} = $blockend+1; 308 | return $newctx->{out}; 309 | } 310 | 311 | sub count_args { 312 | my ($name, $args, $ctx, $num) = @_; 313 | if ($num == -1) {return ;} 314 | if ((scalar(@$args)) != $num) { 315 | croak(sprintf("line %u: ~$name: I expect $num arguments, but I got %u instead.", $ctx->{current_line}, scalar(@$args))); 316 | } 317 | } 318 | 319 | 320 | # ------------------------------------------------------------------ 321 | # Macros go here: 322 | # ------------------------------------------------------------------ 323 | 324 | # ~decompose(op, "0101 ab0cd mmmrrr") 325 | sub macro_decompose { 326 | my ($args, $ctx) = @_; 327 | count_args("decompose", $args, $ctx, 2); 328 | 329 | my ($op, $input_pattern) = @$args; 330 | my @raw = split //, $input_pattern; 331 | my @spaceless; 332 | foreach my $c (reverse(@raw)) { 333 | if ($c ne " ") {push @spaceless, $c;} 334 | } 335 | 336 | if (scalar(@spaceless) != 16) { 337 | carp sprintf("line %u: ~decompose: the pattern doesn't have 16 bits (or something else is wrong with it)", $ctx->{current_line}); 338 | } 339 | 340 | my $lastc = ""; 341 | my %symbols; 342 | for (my $i = 0; $i < scalar(@spaceless); $i++) { 343 | my $c = $spaceless[$i]; 344 | if (index("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", $c) != -1) { 345 | if (exists $symbols{$c}) { 346 | if ($lastc ne $c) { 347 | croak sprintf("line %u: ~decompose: the pattern uses '%s' more than once", $ctx->{current_line}, $c); 348 | } 349 | $symbols{$c}->{len}++; 350 | } 351 | else { 352 | $symbols{$c} = { 353 | start => $i, 354 | len => 1 355 | }; 356 | } 357 | } 358 | 359 | $lastc = $c; 360 | } 361 | 362 | my $output = ""; 363 | foreach my $key (keys %symbols) { 364 | my $dat = $symbols{$key}; 365 | my $mask = sprintf("0x%x", (2 ** $dat->{len})-1); 366 | $output .= sprintf("const uint16_t %s = ((%s)>>%u)&%s;\n", $key, $op, $dat->{start}, $mask); 367 | } 368 | 369 | return $output; 370 | } 371 | 372 | # ~b(1010) == 5 373 | sub macro_b { 374 | my $args = shift; 375 | my $ctx = shift; 376 | if (scalar(@$args) != 1) { 377 | croak(sprintf("line %u: ~bin: ~bin() expects 1 argument, got %u", $ctx->{current_line}, scalar(@$args))); 378 | } 379 | my @digits; 380 | foreach my $c (split //, $args->[0]) { 381 | unless ($c eq ' ') { 382 | push @digits, $c; 383 | } 384 | } 385 | my $count = 0; 386 | my $val = 0; 387 | foreach my $c (@digits) { 388 | if ($c eq "0") { 389 | $val = ($val * 2); 390 | } elsif ($c eq "1") { 391 | $val = ($val * 2) + 1; 392 | } else { 393 | croak(sprintf("line %u: ~bin: non-digit in [%s]", $ctx->{current_line}, $args->[0])); 394 | } 395 | } 396 | return sprintf("0x%x", $val); 397 | } 398 | 399 | # if (~bmatch(op, 1000 xxxx 01 xxx xxx)) {...} 400 | sub macro_bmatch { 401 | my ($args, $ctx) = @_; 402 | count_args("bmatch", $args, $ctx, 2); 403 | 404 | my $op = $args->[0]; 405 | my $pattern_raw = $args->[1]; 406 | 407 | my @pattern; 408 | foreach my $c (split '', $pattern_raw) { 409 | if (($c eq 'x') or ($c eq '1') or ($c eq '0')) { 410 | push @pattern, $c; 411 | } elsif ($c ne ' ') { 412 | croak(sprintf("line %u: ~bmatch: I hate to be picky! But there's a bogus character in this bit pattern '%s'.", $ctx->{current_line}, $c)); 413 | } 414 | } 415 | if ((scalar(@pattern) != 8) and (scalar(@pattern) != 16) and (scalar(@pattern) != 32)) { 416 | croak(sprintf("line %u: ~bmatch: The number of bits in this pattern isn't in {8,16,32} (it's %u).", $ctx->{current_line}, scalar(@pattern))); 417 | } 418 | 419 | (my $count=0, my $mask_val=0, my $eq_val=0, my $mask="0x", my $eq="0x"); 420 | foreach my $c (@pattern) { 421 | if ($c eq '1') { 422 | $mask_val = ($mask_val * 2) + 1; 423 | $eq_val = ($eq_val * 2) + 1; 424 | } elsif ($c eq '0') { 425 | $mask_val = ($mask_val * 2) + 1; 426 | $eq_val = ($eq_val * 2) + 0; 427 | } else { # $c eq 'x' 428 | $mask_val = ($mask_val * 2) + 0; 429 | $eq_val = ($eq_val * 2) + 0; 430 | } 431 | $count++; 432 | if ($count == 8) { 433 | $mask .= sprintf("%02x", $mask_val); 434 | $eq .= sprintf("%02x", $eq_val); 435 | $mask_val = 0; 436 | $eq_val = 0; 437 | $count = 0; 438 | } 439 | } 440 | return sprintf("(((%s)&%s)==%s)", $op, $mask, $eq); 441 | } 442 | 443 | # ~newmacro(memcpy, 3, {return "memcpy($args->[0], $args->[1], $args->[2])";} 444 | sub macro_newmacro { 445 | my ($args, $ctx) = @_; 446 | count_args("newmacro", $args, $ctx, 3); 447 | 448 | my ($name, $numargs, $code) = @$args; 449 | my $sub_ref; 450 | eval sprintf('$sub_ref = sub {my ($args, $ctx) = @_;count_args("%s", $args, $ctx, %d);%s};', $name, $numargs, $code); 451 | if ($@) { 452 | croak(sprintf("line %u: ~newmacro: failed to create adhoc macro: {%s}", $ctx->{current_line}, $@)); 453 | } 454 | 455 | if (exists $ctx->{adhoc}->{$name}) { 456 | carp(sprintf("line %u: ~newmacro: warning! redefining already-existing adhoc function (%s)", $ctx->{current_line}, $name)); 457 | } 458 | $ctx->{adhoc}->{$name} = $sub_ref; 459 | 460 | return ""; 461 | } 462 | 463 | sub macro_bytes { 464 | my ($args, $ctx) = @_; 465 | count_args("bytes", $args, $ctx, 1); 466 | my $input_str = $args->[0]; 467 | 468 | my %tab; 469 | foreach my $c (qw(0 1 2 3 4 5 6 7 8 9 a b c d e f)) { 470 | $tab{$c} = hex($c); 471 | } 472 | 473 | # parse out each hex character (nibble) 474 | my @nibbles; 475 | foreach my $c (split //,$input_str) { 476 | if (exists $tab{lc($c)}) { 477 | push @nibbles, $tab{lc($c)}; 478 | } 479 | } 480 | # if it's an empty string, just return {} 481 | if (scalar(@nibbles) == 0) { 482 | return "{}"; 483 | } 484 | # make sure we have an even number of nibbles (for bytes) 485 | if ((scalar(@nibbles)%2)==1) { 486 | croak("~bytes: I need an even number of hex nibbles"); 487 | } 488 | # concatenate them into bytes 489 | my @bytes; 490 | for (my $i=0; $i < scalar(@nibbles); $i+=2) { 491 | push @bytes, (($nibbles[$i]<<4) + $nibbles[$i+1]); 492 | } 493 | # generate a set of hex constants, e.g. {0xde, 0xad, 0xbe, 0xef} 494 | my $out = "{"; 495 | foreach my $c (@bytes) { 496 | $out .= sprintf("0x%02x, ", $c); 497 | } 498 | # kill the final ', ', and replace it with a '}' 499 | $out = substr($out, 0, -2) . "}"; 500 | return $out 501 | } 502 | 503 | -------------------------------------------------------------------------------- /core/mc68851.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | // FIXME: unify all these weird instruction decoders (cpu/68881/68851) 27 | 28 | #ifndef _MC68851_H 29 | #define _MC68851_H 30 | 31 | #include 32 | 33 | void inst_mc68851_prestore(); 34 | void inst_mc68851_psave(); 35 | void inst_mc68851_pbcc(); 36 | 37 | void inst_mc68851_pdbcc(uint16_t cond); 38 | void inst_mc68851_ptrapcc(uint16_t cond); 39 | void inst_mc68851_pscc(uint16_t cond); 40 | 41 | void inst_mc68851_pload(uint16_t ext); 42 | void inst_mc68851_pvalid(uint16_t ext); 43 | void inst_mc68851_pflush(uint16_t ext); 44 | void inst_mc68851_pmove(uint16_t ext); 45 | void inst_mc68851_ptest(uint16_t ext); 46 | void inst_mc68851_pflushr(uint16_t ext); 47 | 48 | 49 | void dis_mc68851_prestore(); 50 | void dis_mc68851_psave(); 51 | void dis_mc68851_pbcc(); 52 | 53 | void dis_mc68851_pdbcc(uint16_t cond); 54 | void dis_mc68851_ptrapcc(uint16_t cond); 55 | void dis_mc68851_pscc(uint16_t cond); 56 | 57 | void dis_mc68851_pload(uint16_t ext); 58 | void dis_mc68851_pvalid(uint16_t ext); 59 | void dis_mc68851_pflush(uint16_t ext); 60 | void dis_mc68851_pmove(uint16_t ext); 61 | void dis_mc68851_ptest(uint16_t ext); 62 | void dis_mc68851_pflushr(uint16_t ext); 63 | 64 | #endif // _MC68851_H -------------------------------------------------------------------------------- /core/redblack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "shoebill.h" 31 | 32 | // Create a new red-black tree 33 | rb_tree* rb_new(alloc_pool_t *parent_pool, uint32_t sz) 34 | { 35 | alloc_pool_t *pool = p_new_pool(parent_pool); 36 | rb_tree *tree = (rb_tree*)p_alloc(pool, sizeof(rb_tree)); 37 | tree->root = NULL; 38 | tree->pool = pool; 39 | tree->sz = sz; 40 | return tree; 41 | } 42 | 43 | // Insert a new key/value into the tree 44 | // (and return the old value if *old_value is non-null.) 45 | // Returns true if the key already existed. 46 | uint8_t rb_insert(rb_tree *tree, rb_key_t key, void *value, void *old_value) 47 | { 48 | const uint32_t alloc_size = sizeof(rb_node) + tree->sz; 49 | rb_node **root = &tree->root; 50 | 51 | // Special edge case: insert the root node if tree's empty 52 | if (*root == NULL) { 53 | *root = p_alloc(tree->pool, alloc_size); 54 | (*root)->key = key; 55 | memcpy(&(*root)[1], value, tree->sz); 56 | return 0; 57 | } 58 | 59 | // traverse 60 | rb_node **cur = root, *parent = NULL; 61 | while (*cur) { 62 | parent = *cur; 63 | if (key < (*cur)->key) // left 64 | cur = &((*cur)->left); 65 | else if (key > (*cur)->key) // right 66 | cur = &((*cur)->right); 67 | else { // the key already exists 68 | if (old_value) 69 | memcpy(old_value, &(*cur)[1], tree->sz); 70 | memcpy(&(*cur)[1], value, tree->sz); 71 | return 1; // 1 => the key already existed 72 | } 73 | } 74 | 75 | // insert 76 | *cur = p_alloc(tree->pool, alloc_size); 77 | (*cur)->parent = parent; 78 | (*cur)->key = key; 79 | (*cur)->is_red = 1; 80 | memcpy(&(*cur)[1], value, tree->sz); 81 | 82 | // resolve 83 | 84 | rb_node *red = *cur; 85 | while (red) { 86 | rb_node *parent = red->parent; 87 | if (red->is_red == 0) // if this node isn't actually red, return 88 | break; 89 | else if (!parent) // if this is the root node, return 90 | break; 91 | else if (!parent->is_red) // if the parent is black, then we're done. 92 | break; 93 | 94 | // otherwise, the parent is red - the grandparent must exist, and must be black 95 | assert((red->parent->parent) && (!red->parent->parent->is_red)); 96 | 97 | rb_node *gparent = parent->parent; 98 | rb_node *uncle = (gparent->left==parent)?gparent->right:gparent->left; 99 | 100 | // 8 cases: 101 | // LLr LRr RLr RRr (uncle is red) 102 | if (uncle && (uncle->is_red)) { 103 | uncle->is_red = 0; 104 | parent->is_red = 0; 105 | gparent->is_red = 1; 106 | red = gparent; 107 | continue ; 108 | } 109 | 110 | // uncle is black 111 | 112 | rb_node **gparent_ptr; 113 | if (gparent->parent) { // great-grandparent exists 114 | rb_node *ggparent = gparent->parent; 115 | gparent_ptr = (ggparent->left==gparent)? (&ggparent->left) : (&ggparent->right); 116 | } else { // grandparent is root 117 | gparent_ptr = root; 118 | } 119 | 120 | uint8_t mycase = ((gparent->left==parent)?0:1); 121 | mycase = (mycase << 1) | ((parent->left==red)?0:1); 122 | switch (mycase) { 123 | 124 | case 0: {// LLb 125 | rb_node *Br = parent->right; 126 | *gparent_ptr = parent; 127 | parent->right = gparent; 128 | gparent->left = Br; 129 | parent->is_red = 0; 130 | gparent->is_red = 1; 131 | 132 | parent->parent = gparent->parent; 133 | gparent->parent = parent; 134 | if (Br) Br->parent = gparent; 135 | 136 | red = gparent->right; // gparent became red, gparent->left is black, check gparent->right 137 | break ; 138 | } 139 | case 1: {// LRb 140 | rb_node *Cl = red->left; 141 | rb_node *Cr = red->right; 142 | *gparent_ptr = red; 143 | red->left = parent; 144 | red->right = gparent; 145 | parent->right = Cl; 146 | gparent->left = Cr; 147 | red->is_red = 0; 148 | gparent->is_red = 1; 149 | 150 | red->parent = gparent->parent; 151 | parent->parent = red; 152 | gparent->parent = red; 153 | if (Cl) Cl->parent = parent; 154 | if (Cr) Cr->parent = gparent; 155 | 156 | red = gparent->right; 157 | break ; 158 | } 159 | case 2: { // RLb 160 | rb_node *Cr = red->right, *Cl = red->left; 161 | *gparent_ptr = red; 162 | red->left = gparent; 163 | red->right = parent; 164 | gparent->right = Cl; 165 | parent->left = Cr; 166 | red->is_red = 0; 167 | gparent->is_red = 1; 168 | 169 | 170 | red->parent = gparent->parent; 171 | gparent->parent = red; 172 | parent->parent = red; 173 | if (Cr) Cr->parent = parent; 174 | if (Cl) Cl->parent = gparent; 175 | 176 | red = gparent->left; 177 | break; 178 | } 179 | case 3: { // RRb 180 | rb_node *Bl = parent->left; 181 | *gparent_ptr = parent; 182 | parent->left = gparent; 183 | gparent->right = Bl; 184 | parent->is_red = 0; 185 | gparent->is_red = 1; 186 | 187 | parent->parent = gparent->parent; 188 | gparent->parent = parent; 189 | if (Bl) Bl->parent = gparent; 190 | 191 | red = gparent->left; 192 | break; 193 | } 194 | } 195 | } 196 | 197 | (*root)->is_red = 0; // make double-sure root is red 198 | return 0; 199 | } 200 | 201 | // Find a value given a key 202 | uint8_t rb_find (rb_tree *tree, rb_key_t key, void *value) 203 | { 204 | rb_node *cur = tree->root; 205 | 206 | while (cur) { 207 | if (key < cur->key) 208 | cur = cur->left; 209 | else if (key > cur->key) 210 | cur = cur->right; 211 | else { 212 | if (value) 213 | memcpy(value, &cur[1], tree->sz); 214 | return 1; 215 | } 216 | } 217 | return 0; 218 | } 219 | 220 | uint8_t _rb_index (rb_node *cur, uint32_t *index, rb_node **result) 221 | { 222 | if (!cur) 223 | return 0; 224 | 225 | else if (_rb_index(cur->left, index, result) == 1) 226 | return 1; 227 | 228 | else if (0 == *index) { 229 | *result = cur; 230 | return 1; 231 | } 232 | --*index; 233 | 234 | return _rb_index(cur->right, index, result); 235 | } 236 | 237 | // Do an in-order traversal, and retrieve the (index)th sorted key/value 238 | uint8_t rb_index (rb_tree *tree, uint32_t index, rb_key_t *key, void *value) 239 | { 240 | rb_node *cur = tree->root, *result; 241 | if (_rb_index(cur, &index, &result)) { 242 | if (key) 243 | *key = result->key; 244 | if (value) 245 | memcpy(value, &result[1], tree->sz); 246 | return 1; 247 | } 248 | return 0; 249 | } 250 | 251 | // Count the number of nodes in the tree 252 | static uint32_t _rb_count (rb_node *node) 253 | { 254 | if (!node) 255 | return 0; 256 | return 1 + _rb_count(node->left) + _rb_count(node->right); 257 | } 258 | 259 | uint32_t rb_count (rb_tree *tree) 260 | { 261 | return _rb_count(tree->root); 262 | } 263 | 264 | // Free all the nodes (and the rb_tree ptr itself) 265 | void rb_free (rb_tree *tree) 266 | { 267 | p_free_pool(tree->pool); 268 | } 269 | 270 | -------------------------------------------------------------------------------- /core/sound.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | /* 27 | * Props to MESS for their EASC register map: http://www.mess.org/mess/driver_info/easc 28 | * EASC's PCM mode is backwards compatible with ASC, so their registers are very similar. 29 | */ 30 | 31 | #include 32 | #include 33 | #include "../core/shoebill.h" 34 | 35 | #define r_ptr (0x400 + (asc->right_ptr & 0x3ff)) /* right buf ptr */ 36 | #define l_ptr (asc->left_ptr & 0x3ff) /* left buf ptr */ 37 | #define m_ptr (asc->left_ptr & 0x7ff) /* mono buf ptr */ 38 | 39 | void init_asc_state(void) 40 | { 41 | memset(&shoe.asc, 0, sizeof(shoe.asc)); 42 | 43 | shoe.asc.version = 0x00; // My Mac II's ASC reports 0x00 as its version. 44 | // From the ROM, it looks like other Mac II ASC masks have different version numbers 45 | } 46 | 47 | static uint8_t sound_dma_read_byte(uint16_t addr) 48 | { 49 | apple_sound_chip_registers_t *asc = &shoe.asc; 50 | 51 | if (addr < 0x800) { 52 | if (asc->asc_mode == 1) { 53 | // PCM mode (FIFO is append-only) 54 | if (asc->channel_ctrl & 2) { 55 | // stereo mode - return the byte referenced by the right pointer 56 | return asc->buf[r_ptr]; 57 | } 58 | else { 59 | // mono mode - return the byte referenced by the left pointer 60 | return asc->buf[m_ptr]; 61 | } 62 | } 63 | else { 64 | // Off or wavetable mode (FIFO is random access) 65 | return asc->buf[addr]; 66 | } 67 | } 68 | 69 | switch (addr) { 70 | case 0x800: // Version 71 | return asc->version; 72 | 73 | case 0x801: // ASC-mode 74 | return asc->asc_mode; 75 | 76 | case 0x802: // Channel control 77 | return asc->channel_ctrl; 78 | 79 | case 0x803: // FIFO control 80 | return asc->fifo_ctrl; 81 | 82 | case 0x804: // FIFO interrupt 83 | //return asc->fifo_intr; 84 | return 0xff; 85 | 86 | case 0x805: // Unknown (??) 87 | return asc->unknown1; 88 | 89 | case 0x806: // Volume control 90 | return asc->volume_ctrl; 91 | 92 | case 0x807: // Clock control 93 | return asc->clock_ctrl; 94 | } 95 | 96 | return 0; 97 | } 98 | 99 | static void sound_dma_write_byte(uint16_t addr, uint8_t data) 100 | { 101 | apple_sound_chip_registers_t *asc = &shoe.asc; 102 | 103 | if (addr < 0x800) { // buf_a/b 104 | if (asc->asc_mode == 1) { 105 | // PCM mode (FIFO is append-only) 106 | if (asc->channel_ctrl & 2) { 107 | // stereo mode - each channel has its own buffer pointer 108 | if (addr < 0x400) { 109 | // left buffer 110 | asc->buf[l_ptr] = data; 111 | asc->left_ptr++; 112 | } 113 | else { 114 | // right buffer 115 | asc->buf[r_ptr] = data; 116 | asc->right_ptr++; 117 | } 118 | return ; 119 | 120 | } 121 | else { 122 | // Mono mode 123 | asc->buf[m_ptr] = data; 124 | asc->left_ptr++; 125 | return ; 126 | } 127 | } 128 | else { 129 | // Off or wavetable mode (FIFO is random access) 130 | asc->buf[addr] = data; 131 | return ; 132 | } 133 | } 134 | else { 135 | switch (addr) { 136 | case 0x800: // Version 137 | // Version is read-only 138 | break; 139 | 140 | case 0x801: // ASC-mode 141 | // ASC version 0x00 preserves the low 2 bits 142 | asc->asc_mode = data & 0x03; 143 | assert(asc->asc_mode != 3); // mode-3 produces noise, but isn't deterministic 144 | break; 145 | 146 | case 0x802: // Channel control 147 | // ASC version 0x00 preserves the high bit and low 2 bits 148 | asc->channel_ctrl = data & 0x83; 149 | break; 150 | 151 | case 0x803: // FIFO control 152 | // ASC version 0x00 preserves the low 2 bits 153 | asc->fifo_ctrl = data & 0x83; 154 | break; 155 | 156 | case 0x804: // FIFO interrupt 157 | // FIFO interrupt is read-only 158 | break; 159 | 160 | case 0x805: // unknown (???) 161 | // ASC version 0x00 preserves the high bit and low 4 bits 162 | // (But what does it do?) 163 | asc->unknown1 = data & 0x8f; 164 | break; 165 | 166 | case 0x806: // Volume control 167 | // ASC version 0x00 preserves the high 6 bits 168 | asc->volume_ctrl = data & 0xfc; 169 | break; 170 | 171 | case 0x807: // Clock control 172 | // ASC version 0x00 preserves the low 2 bits 173 | asc->clock_ctrl = data & 0x03; 174 | break; 175 | 176 | } 177 | } 178 | 179 | } 180 | 181 | 182 | void sound_dma_write_raw(uint16_t addr, uint8_t sz, uint32_t data) 183 | { 184 | int32_t i; 185 | slog("sound_dma_write: addr=0x%04x sz=%u dat=0x%x\n", addr, sz, data); 186 | 187 | for (i = (sz-1) * 8; i >= 0; i -= 8) 188 | sound_dma_write_byte(addr, (data >> i) & 0xff); 189 | } 190 | 191 | uint32_t sound_dma_read_raw(uint16_t addr, uint8_t sz) 192 | { 193 | uint32_t i, result = 0; 194 | slog("sound_dma_read: addr=0x%04x sz=%u\n", addr, sz); 195 | 196 | for (i=0; i left 211 | buf_b (0x400-0x7ff) -> right 212 | writing to any address in buf_a or buf_b appends to the end pointer in the ring buffer (ignoring the address) 213 | reading from any address returns... the currently-being-read byte? Or the about-to-be-overwritten byte? 214 | (def one or the other) 215 | - Update: MODE=0: You can do regular random read/write access to buf_a/b when MODE=0. 216 | MODE=1: Writing anywhere within the buffer automatically appends to the end of the ring buffer 217 | For stereo mode, writing between 0-0x3ff appends to buf_a, 0x400-0x7ff to buf_b 218 | Reading anywhere in the buffer is strange - it seems non-deterministic. 219 | Update 2: no wait, it's returning the byte at buf_b's ring pointer, does it always do that? 220 | Update 3: yes, it looks like reading anywhere returns the byte at buf_b's pointer in stereo mode, 221 | and buf_a's pointer in mono mode 222 | MODE=2: Same as MODE=0 (?) 223 | 224 | - ASC maintains two distinct ring buffer pointers for stereo mode 225 | 226 | 227 | 228 | 229 | 0x800 - Version (?) MacII only ever seems to TST.B it 230 | (READ ONLY) 231 | 232 | $00 -> My Mac II's ASC's version 233 | 234 | $?? -> Mac II's ROM is aware of other non-$00 ASC masks 235 | 236 | $b0 -> EASC 237 | 238 | ———— 239 | 240 | 0x801 - Mode (?) 0 == no output, 1 == PCM, 2 == wavetable, 3 == hissing static(??) 241 | - Preserves low 2 bits, ignores high 6 bits 242 | 243 | 0x802 - Channel selector 244 | Preserves mask 0x83 (high bit, low 2 bits) 245 | - High bit is set if “engine overflow” (according to MESS) 246 | - Low bits, 0x?2 -> stereo output (buf_a -> left, buf_b -> right) 247 | 0x?0 -> Mono output (from buf_a) 248 | - 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) 249 | 250 | 0x803 - Fifo control (cycle 0x80 to reset the internal FIFO pointer (pointers?)) 251 | Preserves mask 0x83 (high bit, low 2 bits) 252 | 253 | 0x804 - Fifo interrupt status 254 | (READ ONLY, doesn’t preserve any written bits (doesn’t acknowledge writes at all?)) 255 | 256 | 0x805 - ??? 257 | - Preserves bits at 0x8F, (high bit, low 4 bits), doesn't seem to do anything 258 | 259 | 0x806 - Volume control (high 3 bits) 260 | Preserves top 6 bits, ignores bottom 2 bits. (Only top 3 bits control volume) 261 | 262 | 0x807 - Clock rate select (0, 2, or 3, I think) 263 | 0x00 -> 11127hz 264 | 0x01 -> Illegal??? 265 | 0x02 -> 11025hz 266 | 0x03 -> 22050hz 267 | 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. 268 | 269 | 270 | 271 | ASC has more registers past 0x807 for wave table control 272 | 273 | 274 | 275 | 276 | 277 | */ 278 | 279 | 280 | -------------------------------------------------------------------------------- /core/toby_frame_buffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include "shoebill.h" 30 | 31 | #define ROM_SIZE 4096 32 | 33 | uint8_t macii_video_rom[ROM_SIZE] = { 34 | /* 35 | * Redacted! 36 | * But if you own a toby frame buffer card, you 37 | * can dump its 4kb ROM and stick it here. 38 | * A/UX 1, 2 and 3 seem happy with this hacky 39 | * implementation. 40 | */ 41 | }; 42 | 43 | static void nubus_tfb_clut_translate(shoebill_card_tfb_t *ctx) 44 | { 45 | uint32_t i, gli = 0; 46 | const uint8_t depth = ctx->depth; 47 | 48 | for (i=0; i < (1024 * 480);) { 49 | uint8_t code; 50 | 51 | if (i % 1024 == 640) { 52 | i += (1024 - 640); 53 | continue; 54 | } 55 | 56 | assert(gli < (640 * 480)); 57 | 58 | if (depth <= 1) { 59 | code = (ctx->direct_buf[ctx->line_offset + i/8] & (0x80 >> (i % 8))) != 0; 60 | code = (code << 7) | 0x7f; 61 | } 62 | else if (depth == 2) { 63 | const uint8_t byte = ctx->direct_buf[ctx->line_offset + i/4]; 64 | const uint8_t mod = i % 4; 65 | code = (byte << (mod * 2)) & 0xc0; 66 | code |= 0x3f; 67 | } 68 | else if (depth == 4) { 69 | const uint8_t byte = ctx->direct_buf[ctx->line_offset + i/2]; 70 | const uint8_t mod = i % 2; 71 | code = (byte << (mod * 4)) & 0xf0; 72 | code |= 0x0f; 73 | } 74 | else if (depth == 8) { 75 | code = ctx->direct_buf[ctx->line_offset + i]; 76 | } 77 | 78 | ctx->temp_buf[gli * 4 + 0] = ctx->clut[code * 3 + 2]; 79 | ctx->temp_buf[gli * 4 + 1] = ctx->clut[code * 3 + 1]; 80 | ctx->temp_buf[gli * 4 + 2] = ctx->clut[code * 3 + 0]; 81 | 82 | gli++; 83 | i++; 84 | } 85 | } 86 | 87 | void nubus_tfb_init(void *_ctx, uint8_t slotnum) 88 | { 89 | shoebill_card_tfb_t *ctx = (shoebill_card_tfb_t*)_ctx; 90 | 91 | ctx->direct_buf = p_alloc(shoe.pool, 512 * 1024 + 4); 92 | ctx->temp_buf = p_alloc(shoe.pool, 640 * 480 * 4); 93 | ctx->rom = p_alloc(shoe.pool, 4096); 94 | ctx->clut = p_alloc(shoe.pool, 256 * 3); 95 | 96 | ctx->clut_idx = 786; 97 | ctx->line_offset = 0; 98 | 99 | // memcpy(ctx->rom, macii_video_rom, 4096); 100 | 101 | // Offset to the TFB sResource 102 | ctx->rom[4096 - 20] = 0; 103 | ctx->rom[4096 - 19] = 0xff; 104 | ctx->rom[4096 - 18] = 0xf0; 105 | ctx->rom[4096 - 17] = 0x14; 106 | 107 | // Init CLUT to 1-bit depth 108 | ctx->depth = 1; 109 | memset(ctx->clut, 0x0, 3*128); 110 | memset(ctx->clut + (3*128), 0xff, 3*128); 111 | 112 | shoe.slots[slotnum].ctx = ctx; 113 | } 114 | 115 | uint32_t nubus_tfb_read_func(const uint32_t rawaddr, const uint32_t size, const uint8_t slotnum) 116 | { 117 | // 1111 nnnn xxxx rrrr SSSSSSSS SSSSSSxx 118 | // n -> slot number 119 | // S -> significant bits 120 | // x -> ignored 121 | // region -> 122 | // 0000-0111(?) - framebuffer 123 | // 1000 124 | // 1001 125 | // 1010 126 | // 1011 127 | // 1100 128 | // 1101 129 | // 1110 130 | // 1111 = ROM (repeating 4kb images in S bits) 131 | //tfb_ctx_t *ctx = (tfb_ctx_t*)shoe.slots[slotnum].ctx; 132 | shoebill_card_tfb_t *ctx = (shoebill_card_tfb_t*)shoe.slots[slotnum].ctx; 133 | 134 | const uint32_t addr = rawaddr & 0x000fffff; 135 | uint32_t result = 0; 136 | 137 | switch (addr >> 16) { 138 | case 0x0 ... 0x7: { // frame buffer 139 | uint32_t i; 140 | for (i=0; idirect_buf[addr + i]; 142 | break; 143 | } 144 | 145 | case 0xf: { // rom 146 | if ((addr & 3) == 0) { 147 | const uint32_t rom_addr = (addr >> 2) % 4096; 148 | result = ctx->rom[rom_addr]; 149 | slog("nubus_tfb_read_func: returning %x for addr %x (rom_addr=%x)\n", (uint32_t)result, rawaddr, rom_addr); 150 | } 151 | else 152 | result = 0; 153 | break; 154 | } 155 | 156 | case 0xd: { // vsync registers 157 | // 0xd0000 = ReadVSync 158 | // 0xd0004, d0008 = ?? 159 | if (addr == 0xd0000) { 160 | ctx->vsync++; 161 | result = (ctx->vsync >> 7)&1; 162 | slog("nubus_tfb_read_func: reading vsync bit shoe.pc=0x%08x\n", shoe.orig_pc); 163 | // We just need to oscillate the vsync bit, to pretend we're going in and out of the blanking interval. 164 | // The card driver waits until the bit goes low, then waits until it goes high 165 | // FIXME: clean this up 166 | break; 167 | } 168 | else { 169 | slog("nubus_tfb_read_func: unknown read of *0x%08x\n", rawaddr); 170 | result = 0; 171 | break; 172 | } 173 | } 174 | 175 | default: { 176 | slog("nubus_tfb_read_func: unknown read of *0x%08x\n", rawaddr); 177 | result = 0; 178 | break; 179 | } 180 | } 181 | 182 | return result; 183 | } 184 | 185 | void nubus_tfb_write_func(const uint32_t rawaddr, const uint32_t size, 186 | const uint32_t data, const uint8_t slotnum) 187 | { 188 | shoebill_card_tfb_t *ctx = (shoebill_card_tfb_t*)shoe.slots[slotnum].ctx; 189 | const uint32_t addr = rawaddr & 0x000fffff; 190 | 191 | switch (addr >> 16) { 192 | 193 | case 0x0 ... 0x7: { // frame buffer 194 | uint32_t i; 195 | for (i=0; idirect_buf[addr + size - (i+1)] = (data >> (8*i)) & 0xFF; 197 | } 198 | return ; 199 | } 200 | 201 | case 0x8: { // other registers 202 | 203 | if (addr == 0x80000) { // some register that seems to indicate the color depth 204 | const uint8_t val = data & 0xff; 205 | if (val == 0xdf) 206 | ctx->depth = 1; 207 | else if (val == 0xbf) 208 | ctx->depth = 2; 209 | else if (val == 0x7f) 210 | ctx->depth = 4; 211 | else if (val == 0xff) 212 | ctx->depth = 8; 213 | else 214 | assert(!"Can't figure out the color depth!"); 215 | return ; 216 | } 217 | 218 | if (addr == 0x8000c) { // horizontal offset 219 | ctx->line_offset = 4 * ((~data) & 0xff); 220 | return ; 221 | } 222 | else { 223 | slog("video_nubus_set: unknown write to *0x%08x (0x%x)\n", rawaddr, data); 224 | return ; 225 | } 226 | } 227 | 228 | case 0x9: { // CLUT registers? 229 | if (addr == 0x90018) { // CLUT 230 | uint8_t *clut = (uint8_t*)ctx->clut; 231 | 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)); 232 | clut[ctx->clut_idx] = 255 - (data & 0xff); 233 | 234 | ctx->clut_idx = (ctx->clut_idx == 0) ? 767 : ctx->clut_idx-1; 235 | 236 | return ; 237 | } 238 | 239 | if (addr == 0x9001c) { // CLUT register? 240 | const uint32_t clut_dat = data & 0xff; 241 | 242 | ctx->clut_idx = clut_dat * 3 + 2; 243 | 244 | } 245 | slog("video_nubus_set: unknown write to *0x%08x (0x%x)\n", rawaddr, data); 246 | return ; 247 | } 248 | 249 | case 0xa: { // clear interrupt for slot 0xa(?) in via2.rega (by setting the appropriate bit) 250 | assert((data & 0xff) == 0); 251 | shoe.via[1].rega_input |= (1 << (slotnum - 9)); 252 | return ; 253 | } 254 | 255 | default: { 256 | slog("video_nubus_set: unknown write to *0x%08x (0x%x)\n", rawaddr, data); 257 | return ; 258 | } 259 | } 260 | } 261 | 262 | shoebill_video_frame_info_t nubus_tfb_get_frame(shoebill_card_tfb_t *ctx, 263 | _Bool just_params) 264 | { 265 | shoebill_video_frame_info_t result; 266 | 267 | result.width = 640; 268 | result.height = 480; 269 | result.scan_width = 640; 270 | result.depth = ctx->depth; 271 | 272 | // If caller just wants video parameters... 273 | if (just_params) 274 | return result; 275 | 276 | nubus_tfb_clut_translate(ctx); 277 | 278 | result.buf = ctx->temp_buf; 279 | return result; 280 | } 281 | 282 | 283 | -------------------------------------------------------------------------------- /core/video_rom/rom.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pruten/shoebill/a9b2af09c078c16d9b286067d72e3e6deaad9660/core/video_rom/rom.bin -------------------------------------------------------------------------------- /core/video_rom/rom_to_c.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main (int argc, char **argv) 7 | { 8 | FILE *in, *out; 9 | uint8_t *rom = malloc(4096); 10 | uint32_t i; 11 | 12 | if (argc != 3) { 13 | printf("usage ./rom_to_c video|ethernet rom.bin rom.c\n"); 14 | return 0; 15 | } 16 | 17 | assert(in = fopen(argv[2], "rb")); 18 | assert(out = fopen(argv[3], "w")); 19 | 20 | assert(fread(rom, 4096, 1, in) == 1); 21 | 22 | fprintf(out, "static uint8_t _%s_rom[4096] = {\n\t", argv[1]); 23 | for (i=0; i<4095; i++) { 24 | fprintf(out, "0x%02x, ", rom[i]); 25 | if ((i % 8) == 7) 26 | fprintf(out, "\n\t"); 27 | } 28 | fprintf(out, "0x%02x\n};\n", rom[i]); 29 | fclose(out); 30 | 31 | return 0; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /core/video_rom/shoebill_video.make: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pruten/shoebill/a9b2af09c078c16d9b286067d72e3e6deaad9660/core/video_rom/shoebill_video.make -------------------------------------------------------------------------------- /core/video_rom/shoebill_video_driver.a: -------------------------------------------------------------------------------- 1 | BLANKS ON STRING ASIS IMPORT test_func shoeClearInterrupt EQU 4*0 ; Write 1 to clear the via2 interrupt shoeSetMode EQU 4*1 ; write depth in bits shoeGrayPage EQU 4*2 ; Gray out the screen buffer shoeSetClutIndex EQU 4*3 ; Set the index of the clut entry I'm about to modify shoeSetClutRed EQU 4*4 ; Set the red uint16_t for this clut entry shoeSetClutGreen EQU 4*5 ; green shoeSetClutBlue EQU 4*6 ; blue shoeEnableInts EQU 4*7 ; Enable/disable interrupts shoeDebug EQU 4*8 ; Print out the long value written to this "register" shoeGrayCLUT EQU 4*9 ; Gray out the CLUT shoeUseLuminance EQU 4*10 ; "designing cards" calls this SetGray, but that's confusing DriverStart DC.W $4C00 ; "ctl, status, needsLock" (what?) DC.W 0, 0, 0 ; "not an ornament" (??) DC.W VideoOpen-DriverStart DC.W 0 ; What does "prime" do? DC.W VideoCtl-DriverStart DC.W VideoStatus-DriverStart DC.W VideoClose-DriverStart STRING Pascal ; This needs to match the name in shoebill_video_rom.a DC.B '.Display_Video_Apple_Shoebill' STRING ASIS ALIGN 2 DC.W $0 ; Version number (overrides INIT if very high) VideoOpen move.l a0, a2 ; param block pointer move.l a1, a3 ; DCE pointer ; Allocate a slot queue element moveq.l #sqHDSize, d0 _NewPtr ,SYS,CLEAR bne Reset ; Install the interrupt handler lea InterruptHandler, a4 move.w #SIQType, SQType(a0) move.l a4, SQAddr(a0) move.l dctlDevBase(a3), SQParm(a0) moveq.l #0, d0 move.b dctlSlot(a3), d0 _SIntInstall bne Reset ; Return success moveq.l #0, d0 rts VideoCtl movem.l a0-a6/d1-d7, -(sp) moveq.l #0, d1 move.w csCode(a0), d1 move.l dCtlDevBase(a1), a2 add.l #$00F00000, a2 move.l csParam(a0), a3 ; a0 -> "IO parameter block" ; a1 -> DCE pointer ; a2 -> register base address ; a3 -> parameters ; d1 -> ctl code VideoCtl_reset cmp.w #0, d1 bne VideoCtl_killio move.l OneBitMode, shoeSetMode(a2) ; set to B&W move.l #1, shoeGrayPage(a2) ; gray out the screen move.l #noErr, d0 ; success bra VideoCtl_rtn VideoCtl_killio cmp.w #1, d1 bne VideoCtl_setvidmode moveq.l #noErr, d0 ; no async IO on shoebill, so succeed bra VideoCtl_rtn VideoCtl_setvidmode cmp.w #2, d1 bne VideoCtl_setentries ; Gray out the CLUT move.b #1, shoeGrayCLUT(a2) ; (it's okay to write bytes/words to these long register addresses) move.w csMode(a3), shoeSetMode(a2) moveq.l #noErr, d0 bra VideoCtl_rtn VideoCtl_setentries cmp.w #3, d1 bne VideoCtl_setgamma move.l (a3), a4 ; csTable moveq.l #0, d2 move.w 4(a3), d2 ; csStart moveq.l #0, d3 move.w 6(a3), d3 ; csCount cmp.w #$ffff, d2 bne cont reset cont: move.l d2, d4 lsl.l #3, d4 ; multiply csStart by 8, sizeof(ColorSpec)==8 add.l d4, a4 ; add (csStart*8) to csTable addq.l #1, d3 ; csCount is 0-based (why??) Make it 1-based moveq.l #0, d4 setentries_loop: move.l d2, shoeSetClutIndex(a2) ; communicate the clut entry index move.w 2(a4), shoeSetClutRed(a2) ; communicate the red component move.w 4(a4), shoeSetClutGreen(a2) move.w 6(a4), shoeSetClutBlue(a2) addq.l #1, d2 ; increment csStart addq.l #8, a4 ; increment csTable pointer addq.l #1, d4 ; increment loop counter cmp d4, d3 bne setentries_loop moveq.l #noErr, d0 bra VideoCtl_rtn VideoCtl_setgamma cmp.w #4, d1 bne VideoCtl_graypage ; Debug-print setgamma move.l #$b0040000, d4 move.l d4, shoeDebug(a2) ; Not implemented moveq.l #controlErr, d0 bra VideoCtl_rtn VideoCtl_graypage cmp.w #5, d1 bne VideoCtl_setgray ; Debug-print graypage move.l #$b0050000, d4 move.l d4, shoeDebug(a2) move.l #0, shoeGrayPage(a2) moveq.l #noErr, d0 bra VideoCtl_rtn VideoCtl_setgray ; cmp.w #6, d1 bne VideoCtl_setinterrupt ; Debug-print setgray move.l #$b0060000, d4 move.l d4, shoeDebug(a2) move.b csMode(a3), shoeUseLuminance(a2) moveq.l #noErr, d0 bra VideoCtl_rtn VideoCtl_setinterrupt cmp.w #7, d1 bne VideoCtl_directsetentries ; Debug-print csMode(a3) move.l #$b0070000, d4 move.b csMode(a3), d4 move.l d4, shoeDebug(a2) move.b csMode(a3), d1 move.b d1, shoeEnableInts(a2) moveq.l #noErr, d0 bra VideoCtl_rtn VideoCtl_directsetentries cmp.w #8, d1 bne VideoCtl_setdefault ; Not implemented moveq.l #controlErr, d0 bra VideoCtl_rtn VideoCtl_setdefault ; setDefaultMode cmp.w #9, d1 bne VideoCtl_bogus ; Debug-print csMode(a3) move.l #$b0090000, d4 move.b csMode(a3), d4 move.l d4, shoeDebug(a2) suba #spBlockSize, sp ; allocate a slot parameter block move.l sp, a0 move.b dCtlSlot(a1), spSlot(a0) clr.b spExtDev(a0) suba #sizesPRAMRec, sp move.l sp,spResult(a0) _sReadPRAMRec ; read this slot's pram data ; copy the new default mode to VendorUse2 (byte idx 3) move.b csMode(a3), 3(sp) move.l sp, spsPointer(a0) _SPutPRAMRec ; write the new pram data adda #SizesPRAMRec+spBlockSize, SP moveq.l #noErr, d0 bra VideoCtl_rtn VideoCtl_bogus move.l #controlErr, d0; ; fall through VideoCtl_rtn movem.l (sp)+, a0-a6/d1-d7 rts ; ---- Video status ---- VideoStatus movem.l a0-a6/d1-d7, -(sp) move.l dCtlDevBase(a1), a2 add.l #$00F00000, a2 move.l #$e0000000, shoeDebug(a2) move.l #statusErr, d0 bra VideoStatus_rtn VideoStatus_bogus move.l #statusErr, d0 VideoStatus_rtn movem.l (sp)+, a0-a6/d1-d7 rts ; ---- Video close ---- VideoClose movem.l a0-a6/d1-d7, -(sp) move.l dCtlDevBase(a1), a2 add.l #$00F00000, a2 ; Nothing much to do except disable interrupts ; I don't think VideoClose is ever even called move.l #0, shoeEnableInts(a2) move.l #$a0000000, shoeDebug(a2) movem.l (sp)+, a0-a6/d1-d7 moveq.l #0, d0 rts ; --- Interrupt handler --- InterruptHandler ; Compute the slot number given the base address in a1 move.l a1, d0 rol.l #8, d0 and.l #$0f, d0 ; Tell Shoebill to clear the interrupt flag move.l a1, a0 add.l #$00F00000, a0 ; the "clear interrupt" register move.l #1, (a0) ; Call JVBLTask (with d0 = slot number) move.l JVBLTask, a0 jsr (a0) ; Return success moveq.l #1, d0 rts Reset reset -------------------------------------------------------------------------------- /core/video_rom/shoebill_video_primary_init.a: -------------------------------------------------------------------------------- 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 ; 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 -------------------------------------------------------------------------------- /core/video_rom/shoebill_video_rom.a: -------------------------------------------------------------------------------- 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 FormatBlockSize EQU 20 ROMSize EQU 4096 MyBoardID EQU $0050 ; FIXME: CHANGE THIS DrHwShoe EQU $5403 ; ---- 1 bit video params ---- myVidParams_one DC.L myVidParams_one_end-myVidParams_one DC.L 0 ; offset to video RAM base (why is this 32 on TFB?) DC.W 1440/8 ; width of the buffer for a video scan line DC.W 0, 0, 900, 1440 DC.W 0 ; version DC.W 0 ; packType DC.L 0 ; packSize DC.L $48000 ; horizontal resolution (px/in) DC.L $48000 ; vertical resolution DC.W 0 ; Pixel type (chunky) DC.W 1 ; Pixel size (1 bit/px) DC.W 1 ; Number of components DC.W 1 ; Size of components (size of a single component, or of all?) DC.L 0 ; hmPlaneBytes (??) myVidParams_one_end ; ---- 2 bit video params ---- myVidParams_two DC.L myVidParams_two_end-myVidParams_two DC.L 0 ; offset to video RAM base (why is this 32 on TFB?) DC.W 1440/4 ; width of the buffer for a video scan line DC.W 0, 0, 900, 1440 DC.W 0 ; version DC.W 0 ; packType DC.L 0 ; packSize DC.L $48000 ; horizontal resolution (px/in) DC.L $48000 ; vertical resolution DC.W 0 ; Pixel type (chunky) DC.W 2 ; Pixel size (3 bit/px) DC.W 1 ; Number of components DC.W 2 ; Size of each component DC.L 0 ; hmPlaneBytes (??) myVidParams_two_end ; ---- 4 bit video params ---- myVidParams_four DC.L myVidParams_four_end-myVidParams_four DC.L 0 ; offset to video RAM base (why is this 32 on TFB?) DC.W 1440/2 ; width of the buffer for a video scan line DC.W 0, 0, 900, 1440 DC.W 0 ; version DC.W 0 ; packType DC.L 0 ; packSize DC.L $48000 ; horizontal resolution (px/in) DC.L $48000 ; vertical resolution DC.W 0 ; Pixel type (chunky) DC.W 4 ; Pixel size (4 bit/px) DC.W 1 ; Number of components DC.W 4 ; Size of each component DC.L 0 ; hmPlaneBytes (??) myVidParams_four_end ; ---- 8 bit video params ---- myVidParams_eight DC.L myVidParams_eight_end-myVidParams_eight DC.L 0 ; offset to video RAM base (why is this 32 on TFB?) DC.W 1440 ; width of the buffer for a video scan line DC.W 0, 0, 900, 1440 DC.W 0 ; version DC.W 0 ; packType DC.L 0 ; packSize DC.L $48000 ; horizontal resolution (px/in) DC.L $48000 ; vertical resolution DC.W 0 ; Pixel type (chunky) DC.W 8 ; Pixel size (8 bit/px) DC.W 1 ; Number of components DC.W 8 ; Size of each component DC.L 0 ; hmPlaneBytes (??) myVidParams_eight_end ; ---- 16 bit video params ---- myVidParams_sixteen DC.L myVidParams_sixteen_end-myVidParams_sixteen DC.L 0 ; offset to video RAM base (why is this 32 on TFB?) DC.W 2880 ; width of the buffer for a video scan line DC.W 0, 0, 900, 1440 DC.W 0 ; version DC.W 0 ; packType DC.L 0 ; packSize DC.L $48000 ; horizontal resolution (px/in) DC.L $48000 ; vertical resolution DC.W 16 ; Pixel type (ChunkyyDirect) DC.W 16 ; Pixel size (16 bit/px) DC.W 3 ; Number of components DC.W 5 ; Size of each component DC.L 0 ; hmPlaneBytes (??) myVidParams_sixteen_end ; ---- 32 bit (really, 24 bit) video params ---- myVidParams_thirtytwo DC.L myVidParams_thirtytwo_end-myVidParams_thirtytwo DC.L 0 ; offset to video RAM base (why is this 32 on TFB?) DC.W 5760 ; width of the buffer for a video scan line DC.W 0, 0, 900, 1440 DC.W 0 ; version DC.W 0 ; packType DC.L 0 ; packSize DC.L $48000 ; horizontal resolution (px/in) DC.L $48000 ; vertical resolution DC.W 16 ; Pixel type (ChunkyyDirect) DC.W 32 ; Pixel size (24 bit/px) DC.W 3 ; Number of components DC.W 8 ; Size of each component DC.L 0 ; hmPlaneBytes (??) myVidParams_thirtytwo_end ; ---- sResource directory ---- CategoryBoard EQU 1 CategoryVideo_oldqd EQU 128 CategoryVideo_qd32 EQU 129 sResourceDir OSLstEntry CategoryBoard, sResourceBoard OSLstEntry CategoryVideo_oldqd, sResourceVideo_oldqd OSLstEntry CategoryVideo_qd32, sResourceVideo_qd32 DatLstEntry endOfList,0 ; ---- Board sResource ---- sResourceBoard OSLstEntry sRsrcType, boardType OSLstEntry sRsrcName, boardName DatLstEntry boardID, MyBoardID OSLstEntry primaryInit, myPrimaryInit OSLstEntry vendorInfo, myVendorInfo OSLstEntry secondaryInit, mySecondaryInit DatLstEntry endOfList, 0 boardType DC.W CatBoard ; category DC.W TypBoard ; type DC.W 0 ; driver sw ? DC.W 0 ; driver hw ? boardName DC.L 'Shoebill Phony Video' myPrimaryInit DC.L myPrimaryInit_end-myPrimaryInit INCLUDE 'shoebill_video_primary_init.a' myPrimaryInit_end EQU * mySecondaryInit DC.L mySecondaryInit_end-mySecondaryInit INCLUDE 'shoebill_video_secondary_init.a' mySecondaryInit_end EQU * STRING C myVendorInfo OSLstEntry VendorId, myVendorID OSLstEntry RevLevel, myRevLevel OSLstEntry PartNum, myPartNum myVendorID DC.L 'Shoebill' myRevLevel DC.L 'Rev-1' myPartNum DC.L 'Moof' ; ---- Video sResource ---- ; Video sResource for 32 bit quickdraw sResourceVideo_qd32 OSLstEntry sRsrcType, myVideoType OSLstEntry sRsrcName, myVideoName OSLstEntry sRsrcDrvrDir, videoDriverDirectory DatLstEntry sRsrcHWDevId, 1 ; DatLstEntry sRsrcFlags, 6 ; f32BitMode | fOpenAtStart OSLstEntry MajorBaseOS, myMajorBaseOS OSLstEntry MajorLength, myMajorLength OSLstEntry OneBitMode, myOneBitMode OSLstEntry TwoBitMode, myTwoBitMode OSLstEntry FourBitMode, myFourBitMode OSLstEntry EightBitMode, myEightBitMode OSLstEntry SixteenBitMode, mySixteenBitMode OSLstEntry ThirtyTwoBitMode, myThirtyTwoBitMode DatLstEntry endOfList, 0 ; Video sResource for old color quicktime sResourceVideo_oldqd OSLstEntry sRsrcType, myVideoType OSLstEntry sRsrcName, myVideoName OSLstEntry sRsrcDrvrDir, videoDriverDirectory DatLstEntry sRsrcHWDevId, 1 ; DatLstEntry sRsrcFlags, 4 ; f32BitMode (A/UX refuses to load the driver when field is included) OSLstEntry MajorBaseOS, myMajorBaseOS OSLstEntry MajorLength, myMajorLength OSLstEntry OneBitMode, myOneBitMode OSLstEntry TwoBitMode, myTwoBitMode OSLstEntry FourBitMode, myFourBitMode OSLstEntry EightBitMode, myEightBitMode DatLstEntry endOfList, 0 myOneBitMode OSLstEntry mVidParams, myVidParams_one DatLstEntry mPageCnt, 1 ; DatLstEntry mDevType, 0 ; 0 means "clutType" (indexed buffer) DatLstEntry endOfList, 0 myTwoBitMode OSLstEntry mVidParams, myVidParams_two DatLstEntry mPageCnt, 1 ; DatLstEntry mDevType, 0 ; 0 means "clutType" (indexed buffer) DatLstEntry endOfList, 0 myFourBitMode OSLstEntry mVidParams, myVidParams_four DatLstEntry mPageCnt, 1 ; DatLstEntry mDevType, 0 ; 0 means "clutType" (indexed buffer) DatLstEntry endOfList, 0 myEightBitMode OSLstEntry mVidParams, myVidParams_eight DatLstEntry mPageCnt, 1 ; DatLstEntry mDevType, 0 ; 0 means "clutType" (indexed buffer) DatLstEntry endOfList, 0 mySixteenBitMode OSLstEntry mVidParams, myVidParams_sixteen DatLstEntry mPageCnt, 1 ; DatLstEntry mDevType, 2 ; directType DatLstEntry endOfList, 0 ; myThirtyTwoBitMode OSLstEntry mVidParams, myVidParams_thirtytwo DatLstEntry mPageCnt, 1 ; DatLstEntry mDevType, 2 ; 2 means "directType" DatLstEntry endOfList, 0 ; myMinorBaseOS DC.L 0 myMinorLength DC.L $00040000 myMajorBaseOS DC.L 0 ; // the offset into the superslot space for video ram myMajorLength DC.L $00F00000 ; // the maxsize of video ram myVideoName DC.L 'Display_Video_Apple_Shoebill' myVideoType DC.W CatDisplay DC.W TypVideo DC.W DrSwApple ; implements the standard apple video driver api DC.W DrHwShoe ; FIXME: is this right? videoDriverDirectory OSLstEntry sMacOS68020, driver_020_start DatLstEntry endOfList, 0 driver_020_start DC.L driver_020_end-driver_020_start INCLUDE 'shoebill_video_driver.a' driver_020_end EQU * ; Cleanup any macros the driver code modified 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 DC.L 0 ; CRC goes here DC.B 1 ; Rom revision level DC.B AppleFormat DC.L TestPattern DC.B 0 ; Reserved DC.B $E1 ; Byte lanes 1110 0001 (LSB from CPU's perspective) ENDP END -------------------------------------------------------------------------------- /core/video_rom/shoebill_video_secondary_init.a: -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- /debugger/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = clang 3 | CFLAGS = -O3 -ggdb -flto -Wno-deprecated-declarations 4 | LFLAGS = -L ../intermediates -lshoebill_core -framework GLUT -framework OpenGL -ledit 5 | 6 | all: debugger 7 | 8 | debugger: Makefile debugger.c ../intermediates/libshoebill_core.a 9 | $(CC) $(CFLAGS) $(LFLAGS) debugger.c -o debugger 10 | 11 | clean: 12 | rm -rf debugger 13 | -------------------------------------------------------------------------------- /gui/Shoebill/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /gui/Shoebill/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /gui/Shoebill/Shoebill-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSHumanReadableCopyright 6 | Copyright © 2013-2015 Peter Rutenbar 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | org.shoebill.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 0.0.5 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 0.0.5 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | shoeApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /gui/Shoebill/Shoebill-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #endif 10 | -------------------------------------------------------------------------------- /gui/Shoebill/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | \vieww9600\viewh8400\viewkind0 5 | \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\qc 6 | 7 | \f0\b\fs24 \cf0 Shoebill 8 | \b0 \ 9 | A Macintosh II emulator that runs A/UX\ 10 | \ 11 | {\field{\*\fldinst{HYPERLINK "https://github.com/pruten/shoebill"}}{\fldrslt https://github.com/pruten/shoebill}}\ 12 | } -------------------------------------------------------------------------------- /gui/Shoebill/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /gui/Shoebill/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | int main(int argc, const char * argv[]) 4 | { 5 | return NSApplicationMain(argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /gui/Shoebill/shoeAppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #import 27 | 28 | @interface shoeAppDelegate : NSObject { 29 | 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /gui/Shoebill/shoeAppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #import "shoeAppDelegate.h" 27 | #import "shoeApplication.h" 28 | #import "shoePreferencesWindowController.h" 29 | 30 | @implementation shoeAppDelegate 31 | 32 | - (void)createFirstTimeUserDefaults 33 | { 34 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 35 | uint32_t i; 36 | 37 | [((shoeApplication*)NSApp) zapPram:defaults ptr:nil]; 38 | [defaults setObject:@"/unix" forKey:@"rootKernelPath"]; 39 | [defaults setObject:@"" forKey:@"romPath"]; 40 | [defaults setInteger:NSOnState forKey:@"verboseState"]; 41 | [defaults setInteger:16 forKey:@"memorySize"]; 42 | 43 | // [defaults setInteger:640 forKey:@"screenWidth"]; 44 | // [defaults setInteger:480 forKey:@"screenHeight"]; 45 | 46 | for (i=0; i<7; i++) 47 | [defaults setObject:@"" forKey:[NSString stringWithFormat:@"scsiPath%u", i]]; 48 | 49 | [defaults setBool:YES forKey:@"defaultsInitialized"]; 50 | } 51 | 52 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 53 | { 54 | uint32_t i; 55 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 56 | 57 | BOOL isInitialized = [defaults boolForKey:@"defaultsInitialized"]; 58 | 59 | if (!isInitialized) 60 | [self createFirstTimeUserDefaults]; 61 | 62 | // < 0.0.2 leaves rootKernelPath uninitialized 63 | if ([defaults objectForKey:@"rootKernelPath"] == nil) 64 | [defaults setObject:@"/unix" forKey:@"rootKernelPath"]; 65 | 66 | // < 0.0.3 leaves pramData uninitialized 67 | if ([defaults objectForKey:@"pramData"] == nil) 68 | [((shoeApplication*)NSApp) zapPram:defaults ptr:nil]; 69 | 70 | // < 0.0.5 leaves ethernet settings uninitialized 71 | if ([defaults objectForKey:@"tapPathE"] == nil) { 72 | uint8_t mac[6]; 73 | generateMACAddr(mac); 74 | [defaults setObject:[NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", 75 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]] 76 | forKey:@"macAddressE"]; 77 | [defaults setObject:@"/dev/tap0" forKey:@"tapPathE"]; 78 | [defaults setInteger:0 forKey:@"ethernetEnabledE"]; 79 | 80 | for (i=0; i<4; i++) { 81 | [defaults setInteger:640 forKey:[NSString stringWithFormat:@"screenWidth%u", i]]; 82 | [defaults setInteger:480 forKey:[NSString stringWithFormat:@"screenHeight%u", i]]; 83 | [defaults setInteger:0 forKey:[NSString stringWithFormat:@"screenEnabled%u", i]]; 84 | } 85 | [defaults setInteger:1 forKey:@"screenEnabled0"]; 86 | } 87 | 88 | [defaults synchronize]; 89 | } 90 | 91 | 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /gui/Shoebill/shoeApplication.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #import 27 | #import "shoeScreenWindowController.h" 28 | #include "../../core/shoebill.h" 29 | 30 | struct shoe_app_pram_data_t 31 | { 32 | uint8_t pram[256]; 33 | volatile _Bool updated; 34 | }; 35 | 36 | @interface shoeApplication : NSApplication { 37 | rb_tree *keymap; 38 | shoeScreenWindowController *windowController[16]; 39 | IBOutlet __weak NSMenuItem *run_stop_menu_item; 40 | 41 | NSTimer *pram_flush_timer; 42 | struct shoe_app_pram_data_t *pram; 43 | 44 | @public 45 | 46 | BOOL doCaptureMouse, doCaptureKeys; 47 | BOOL isRunning; 48 | shoebill_config_t config; 49 | 50 | char *tapPath; 51 | uint8_t mac[6]; 52 | int tap_fd; 53 | BOOL ethEnabled, tap_fd_valid; 54 | struct { 55 | uint16_t height, width, enabled; 56 | } screens[4]; 57 | } 58 | 59 | 60 | - (void) startEmulator; 61 | - (void) zapPram:(NSUserDefaults*)defaults ptr:(uint8_t*)ptr; 62 | @end 63 | -------------------------------------------------------------------------------- /gui/Shoebill/shoeApplication.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #import "shoeApplication.h" 27 | #import "shoeScreenWindow.h" 28 | #import "shoeScreenWindowController.h" 29 | #import "shoePreferencesWindowController.h" 30 | #include 31 | 32 | @implementation shoeApplication 33 | 34 | #define mapkeymod(u, a, m) do { \ 35 | assert((a >> 7) == 0); \ 36 | uint16_t value = ((m) << 8)| (a); \ 37 | rb_insert(keymap, u, &value, NULL); \ 38 | } while (0) \ 39 | 40 | #define mapkey(_u, a) mapkeymod(_u, a, 0) 41 | 42 | - (void)initKeyboardMap 43 | { 44 | keymap = rb_new(p_new_pool(NULL), sizeof(uint16_t)); 45 | 46 | // Letters 47 | mapkey('a', 0x00); 48 | mapkey('b', 0x0b); 49 | mapkey('c', 0x08); 50 | mapkey('d', 0x02); 51 | mapkey('e', 0x0e); 52 | mapkey('f', 0x03); 53 | mapkey('g', 0x05); 54 | mapkey('h', 0x04); 55 | mapkey('i', 0x22); 56 | mapkey('j', 0x26); 57 | mapkey('k', 0x28); 58 | mapkey('l', 0x25); 59 | mapkey('m', 0x2e); 60 | mapkey('n', 0x2d); 61 | mapkey('o', 0x1f); 62 | mapkey('p', 0x23); 63 | mapkey('q', 0x0c); 64 | mapkey('r', 0x0f); 65 | mapkey('s', 0x01); 66 | mapkey('t', 0x11); 67 | mapkey('u', 0x20); 68 | mapkey('v', 0x09); 69 | mapkey('w', 0x0d); 70 | mapkey('x', 0x07); 71 | mapkey('y', 0x10); 72 | mapkey('z', 0x06); 73 | 74 | // Numbers 75 | mapkey('0', 0x1d); 76 | mapkey('1', 0x12); 77 | mapkey('2', 0x13); 78 | mapkey('3', 0x14); 79 | mapkey('4', 0x15); 80 | mapkey('5', 0x17); 81 | mapkey('6', 0x16); 82 | mapkey('7', 0x1a); 83 | mapkey('8', 0x1c); 84 | mapkey('9', 0x19); 85 | 86 | // Top row symbols 87 | mapkeymod(')', 0x1d, modShift); 88 | mapkeymod('!', 0x12, modShift); 89 | mapkeymod('@', 0x13, modShift); 90 | mapkeymod('#', 0x14, modShift); 91 | mapkeymod('$', 0x15, modShift); 92 | mapkeymod('%', 0x17, modShift); 93 | mapkeymod('^', 0x16, modShift); 94 | mapkeymod('&', 0x1a, modShift); 95 | mapkeymod('*', 0x1c, modShift); 96 | mapkeymod('(', 0x19, modShift); 97 | 98 | // Other symbols (no shift) 99 | mapkeymod('`', 0x32, 0); 100 | mapkeymod('-', 0x1b, 0); 101 | mapkeymod('=', 0x18, 0); 102 | mapkeymod('[', 0x21, 0); 103 | mapkeymod(']', 0x1e, 0); 104 | mapkeymod('\\', 0x2a, 0); 105 | mapkeymod(';', 0x29, 0); 106 | mapkeymod('\'', 0x27, 0); 107 | mapkeymod(',', 0x2b, 0); 108 | mapkeymod('.', 0x2f, 0); 109 | mapkeymod('/', 0x2c, 0); 110 | 111 | // Other symbols (with shift) 112 | mapkeymod('~', 0x32, modShift); 113 | mapkeymod('_', 0x1b, modShift); 114 | mapkeymod('+', 0x18, modShift); 115 | mapkeymod('{', 0x21, modShift); 116 | mapkeymod('}', 0x1e, modShift); 117 | mapkeymod('|', 0x2a, modShift); 118 | mapkeymod(':', 0x29, modShift); 119 | mapkeymod('"', 0x27, modShift); 120 | mapkeymod('<', 0x2b, modShift); 121 | mapkeymod('>', 0x2f, modShift); 122 | mapkeymod('?', 0x2c, modShift); 123 | 124 | // Function keys 125 | mapkey(NSF1FunctionKey, 0x7a); 126 | mapkey(NSF2FunctionKey, 0x78); 127 | mapkey(NSF3FunctionKey, 0x63); 128 | mapkey(NSF4FunctionKey, 0x76); 129 | mapkey(NSF5FunctionKey, 0x60); 130 | mapkey(NSF6FunctionKey, 0x61); 131 | mapkey(NSF7FunctionKey, 0x62); 132 | mapkey(NSF8FunctionKey, 0x64); 133 | mapkey(NSF9FunctionKey, 0x65); 134 | mapkey(NSF10FunctionKey, 0x6d); 135 | mapkey(NSF11FunctionKey, 0x67); 136 | mapkey(NSF12FunctionKey, 0x6f); 137 | mapkey(NSF13FunctionKey, 0x69); 138 | mapkey(NSF14FunctionKey, 0x6b); 139 | mapkey(NSF15FunctionKey, 0x71); 140 | 141 | // Arrows 142 | mapkey(NSUpArrowFunctionKey, 0x3e); 143 | mapkey(NSDownArrowFunctionKey, 0x3d); 144 | mapkey(NSRightArrowFunctionKey, 0x3c); 145 | mapkey(NSLeftArrowFunctionKey, 0x3b); 146 | 147 | // Delete 148 | mapkey(NSDeleteFunctionKey, 0x75); 149 | mapkey(NSBackspaceCharacter, 0x33); 150 | mapkey(NSDeleteCharacter, 0x33); 151 | 152 | // Enter, NL, CR 153 | mapkey(NSCarriageReturnCharacter, 0x24); 154 | mapkey(NSNewlineCharacter, 0x24); 155 | mapkey(NSEnterCharacter, 0x24); 156 | 157 | // Other keys 158 | mapkey(0x1b, 0x35); // escape 159 | mapkey(' ', 0x31); // space 160 | mapkey(NSTabCharacter, 0x30); // tab 161 | } 162 | 163 | - (void)sendEvent:(NSEvent *)event 164 | { 165 | if (doCaptureKeys) { 166 | assert(isRunning); 167 | NSEventType type = [event type]; 168 | if (type == NSFlagsChanged) { 169 | NSUInteger modifierFlags = [event modifierFlags]; 170 | shoebill_key_modifier(modifierFlags >> 16); 171 | 172 | // Block any key-related event while the command key is down 173 | if (modifierFlags & NSCommandKeyMask) 174 | return ; 175 | 176 | [super sendEvent:event]; 177 | } 178 | else if (type == NSKeyDown || type == NSKeyUp) { 179 | NSString *chars = [[event charactersIgnoringModifiers] lowercaseString]; 180 | NSUInteger modifierFlags = [event modifierFlags]; 181 | unichar c = [chars characterAtIndex:0]; 182 | uint16_t value; 183 | 184 | if (keymap == NULL) 185 | [self initKeyboardMap]; 186 | 187 | if (rb_find(keymap, c, &value)) { 188 | shoebill_key_modifier((value >> 8) | (modifierFlags >> 16)); 189 | shoebill_key((type == NSKeyDown), value & 0xff); 190 | 191 | } 192 | 193 | // Block any key-related event while the command key is down 194 | if (modifierFlags & NSCommandKeyMask) 195 | return ; 196 | 197 | [super sendEvent:event]; 198 | 199 | } 200 | } 201 | 202 | [super sendEvent:event]; 203 | } 204 | 205 | 206 | - (void) complain:(NSString*)str 207 | { 208 | NSAlert *theAlert = [NSAlert 209 | alertWithMessageText:nil 210 | defaultButton:nil 211 | alternateButton:nil 212 | otherButton:nil 213 | informativeTextWithFormat:@"%@", str 214 | ]; 215 | [theAlert runModal]; 216 | } 217 | 218 | 219 | - (BOOL) fetchUserDefaults 220 | { 221 | uint32_t i; 222 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 223 | 224 | NSString *rootKernelPathStr = [defaults objectForKey:@"rootKernelPath"]; 225 | NSString *romPathStr = [defaults objectForKey:@"romPath"]; 226 | NSInteger verboseState = [defaults integerForKey:@"verboseState"]; 227 | NSInteger memsize = [defaults integerForKey:@"memorySize"]; 228 | NSData *pramData = [defaults objectForKey:@"pramData"]; 229 | 230 | if (rootKernelPathStr == Nil || [rootKernelPathStr length]==0) { 231 | [self complain:@"Kernel path invalid!"]; 232 | return NO; 233 | } 234 | 235 | else if (romPathStr == Nil || [romPathStr length] == 0) { 236 | [self complain:@"ROM path invalid!"]; 237 | return NO; 238 | } 239 | 240 | if ((memsize < 1) || (memsize > 1024)) 241 | memsize = 8; 242 | 243 | for (i=0; i<4; i++) { 244 | NSInteger height = [defaults integerForKey:[NSString stringWithFormat:@"screenHeight%u", i]]; 245 | NSInteger width = [defaults integerForKey:[NSString stringWithFormat:@"screenWidth%u", i]]; 246 | NSInteger enabled = [defaults integerForKey:[NSString stringWithFormat:@"screenEnabled%u", i]]; 247 | 248 | 249 | if ((height < 342) || (height > 0xffff)) 250 | height = 480; 251 | 252 | if ((width < 512) || (width > 0xffff)) 253 | width = 640; 254 | 255 | screens[i].width = (uint16_t)width; 256 | screens[i].height = (uint16_t)height; 257 | screens[i].enabled = (uint16_t)enabled; 258 | } 259 | 260 | 261 | for (i=0; i<7; i++) { 262 | NSString *str = [defaults objectForKey:[NSString stringWithFormat:@"scsiPath%u", i]]; 263 | if (str == nil || [str length] == 0) 264 | config.scsi_devices[i].path = NULL; 265 | else 266 | config.scsi_devices[i].path = strdup([str UTF8String]); 267 | 268 | } 269 | 270 | char *rootKernelPathCString = strdup([rootKernelPathStr UTF8String]); 271 | char *romPathCString = strdup([romPathStr UTF8String]); 272 | 273 | config.aux_verbose = (verboseState == NSOnState); 274 | config.ram_size = (uint32_t)memsize * 1024 * 1024; 275 | config.aux_kernel_path = rootKernelPathCString; 276 | config.rom_path = romPathCString; 277 | config.debug_mode = 0; 278 | 279 | [pramData getBytes:config.pram length:256]; 280 | 281 | /* 282 | * If the pram is corrupt, zap it. 283 | * A/UX will apparently never zap corrupted pram, 284 | * probably because it expects the bootloader/MacOS to do it. 285 | */ 286 | if (memcmp(config.pram+0xc, "NuMc", 4) != 0) 287 | [self zapPram:defaults ptr:config.pram]; 288 | 289 | NSString *defaultTapPath = [defaults objectForKey:@"tapPathE"]; 290 | NSString *defaultMacAddr = [defaults objectForKey:@"macAddressE"]; 291 | ethEnabled = [defaults integerForKey:@"ethernetEnabledE"]; 292 | if (ethEnabled) { 293 | if (tap_fd_valid && strcmp(tapPath, [defaultTapPath UTF8String]) != 0) { 294 | close(tap_fd); 295 | tap_fd_valid = 0; 296 | } 297 | if (tapPath) 298 | free(tapPath); 299 | tapPath = strdup([defaultTapPath UTF8String]); 300 | if (!(parseMACAddr([defaultMacAddr UTF8String], mac))) { 301 | [self complain:@"Bad MAC addr"]; 302 | ethEnabled = 0; 303 | return NO; 304 | } 305 | } 306 | 307 | return YES; 308 | } 309 | 310 | - (void) createScreenWindow:(uint8_t)slotnum 311 | height:(uint16_t)height 312 | width:(uint16_t)width 313 | { 314 | shoebill_install_video_card(&config, 315 | slotnum, 316 | width, 317 | height); 318 | 319 | windowController[slotnum] = [[shoeScreenWindowController alloc] 320 | initWithWindowNibName:@"shoeScreenView" 321 | slotnum:slotnum]; 322 | } 323 | 324 | - (void) zapPram:(NSUserDefaults*)defaults ptr:(uint8_t*)ptr 325 | { 326 | uint8_t init[256]; 327 | 328 | shoebill_validate_or_zap_pram(init, 1); 329 | 330 | if (ptr) 331 | memcpy(ptr, init, 256); 332 | 333 | NSData *data = [NSData dataWithBytes:init length:256]; 334 | [defaults setObject:data forKey:@"pramData"]; 335 | [defaults synchronize]; 336 | 337 | assert("zapPram" && (memcmp(init+0xc, "NuMc", 4) == 0)); 338 | } 339 | 340 | void pram_callback (void *param, const uint8_t addr, const uint8_t byte) 341 | { 342 | struct shoe_app_pram_data_t *pram = (struct shoe_app_pram_data_t*)param; 343 | pram->pram[addr] = byte; 344 | pram->updated = 1; 345 | //printf("pram_callback: set pram[0x%x] = 0x%02x (%c)\n", addr, byte, isprint(byte)?byte:'.'); 346 | } 347 | 348 | - (void) flushPram 349 | { 350 | uint8_t copy[256]; 351 | if (pram->updated) { 352 | pram->updated = 0; 353 | memcpy(copy, pram->pram, 256); 354 | 355 | NSData* data = [NSData dataWithBytes:copy length:256]; 356 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 357 | 358 | [defaults setObject:data forKey:@"pramData"]; 359 | [defaults synchronize]; 360 | } 361 | } 362 | 363 | - (void) pramFlushTimerFired:(NSTimer *)timer 364 | { 365 | [self flushPram]; 366 | } 367 | 368 | - (void) startEmulator 369 | { 370 | if (isRunning) 371 | return; 372 | 373 | uint32_t i; 374 | 375 | bzero(&config, sizeof(shoebill_config_t)); 376 | 377 | if (![self fetchUserDefaults]) 378 | return ; 379 | 380 | self->pram = calloc(1, sizeof(struct shoe_app_pram_data_t)); 381 | memcpy(self->pram, config.pram, 256); 382 | pram_flush_timer = [NSTimer 383 | scheduledTimerWithTimeInterval:1.0 384 | target:self 385 | selector:@selector(pramFlushTimerFired:) 386 | userInfo:nil 387 | repeats:YES]; 388 | config.pram_callback = pram_callback; 389 | config.pram_callback_param = (void*)self->pram; 390 | 391 | uint32_t result = shoebill_initialize(&config); 392 | 393 | if (!result) { 394 | [self complain:[NSString stringWithFormat:@"%s", config.error_msg]]; 395 | return ; 396 | } 397 | 398 | for (i=0; i<4; i++) { 399 | if (screens[i].enabled) 400 | [self createScreenWindow:(9+i) height:screens[i].height width:screens[i].width]; 401 | } 402 | 403 | if (ethEnabled) { 404 | if (!tap_fd_valid) { 405 | tap_fd = open(tapPath, O_RDWR | O_NOFOLLOW); 406 | if (tap_fd == -1) { 407 | NSAlert *theAlert = [NSAlert 408 | alertWithMessageText:nil 409 | defaultButton:nil 410 | alternateButton:nil 411 | otherButton:nil 412 | informativeTextWithFormat:@"Couldn't open tap device (errno = %d)", errno 413 | ]; 414 | [theAlert runModal]; 415 | return ; 416 | } 417 | tap_fd_valid = 1; 418 | } 419 | if (!shoebill_install_ethernet_card(&config, 13, mac, tap_fd)) { 420 | [self complain:[NSString stringWithFormat:@"%s", config.error_msg]]; 421 | return ; 422 | } 423 | 424 | } 425 | 426 | shoebill_start(); 427 | 428 | isRunning = true; 429 | 430 | for (i=0; i<16; i++) { 431 | if (windowController[i]) { 432 | shoeScreenWindow *win = (shoeScreenWindow*)[windowController[i] window]; 433 | [win reevaluateKeyWindowness]; 434 | } 435 | } 436 | 437 | [run_stop_menu_item setTitle: @"Stop"]; 438 | [run_stop_menu_item setKeyEquivalent:@""]; 439 | } 440 | 441 | - (void) stopEmulator 442 | { 443 | uint32_t i; 444 | 445 | for (i=0; i<16; i++) { 446 | if (windowController[i]) { 447 | [windowController[i] close]; 448 | windowController[i] = NULL; 449 | } 450 | } 451 | doCaptureKeys = false; 452 | doCaptureMouse = false; 453 | isRunning = false; 454 | 455 | shoebill_stop(); 456 | 457 | [pram_flush_timer invalidate]; 458 | pram_flush_timer = nil; 459 | [self flushPram]; 460 | free(self->pram); 461 | 462 | if (config.aux_kernel_path) 463 | free((void*)config.aux_kernel_path); 464 | if (config.rom_path) 465 | free((void*)config.rom_path); 466 | 467 | [run_stop_menu_item setTitle: @"Run"]; 468 | [run_stop_menu_item setKeyEquivalent:@"r"]; 469 | } 470 | 471 | - (IBAction)runMenuItem:(id)sender 472 | { 473 | if (isRunning) 474 | [self stopEmulator]; 475 | else 476 | [self startEmulator]; 477 | } 478 | 479 | 480 | @end 481 | -------------------------------------------------------------------------------- /gui/Shoebill/shoePreferencesWindowController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #import 27 | 28 | @interface shoePreferencesWindowController : NSWindowController { 29 | 30 | IBOutlet __weak NSButton *apply, *cancel, *applyAndRun, *verbose, *ethernetEnabled; 31 | IBOutlet __weak NSTextField *kernelPath, *romPath, *memorySize; 32 | IBOutlet __weak NSTextField *scsiPath0, *scsiPath1, *scsiPath2, *scsiPath3, *scsiPath4, *scsiPath5, *scsiPath6; 33 | IBOutlet __weak NSTextField *macAddress, *tapPath; 34 | 35 | IBOutlet __weak NSTextField *screenHeight1, *screenWidth1; 36 | IBOutlet __weak NSTextField *screenHeight2, *screenWidth2; 37 | IBOutlet __weak NSTextField *screenHeight3, *screenWidth3; 38 | IBOutlet __weak NSTextField *screenHeight4, *screenWidth4; 39 | 40 | IBOutlet __weak NSButton *enableScreen1, *enableScreen2, *enableScreen3, *enableScreen4; 41 | } 42 | 43 | 44 | - (IBAction)applyPressed:(id)sender; 45 | - (IBAction)cancelPressed:(id)sender; 46 | - (IBAction)applyAndRunPressed:(id)sender; 47 | - (IBAction)browsePressed:(id)sender; 48 | 49 | @end 50 | 51 | void generateMACAddr (uint8_t *mac); 52 | _Bool parseMACAddr (const char *str, uint8_t *mac); -------------------------------------------------------------------------------- /gui/Shoebill/shoePreferencesWindowController.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #import "shoePreferencesWindowController.h" 27 | #import "shoeApplication.h" 28 | #include 29 | 30 | @implementation shoePreferencesWindowController 31 | 32 | - (id) init 33 | { 34 | return [super initWithWindowNibName:@"shoePreferencesWindowController"]; 35 | } 36 | 37 | - (void)windowDidLoad 38 | { 39 | uint32_t i; 40 | NSTextField *screenWidths[4] = { 41 | screenWidth1, screenWidth2, screenWidth3, screenWidth4}; 42 | NSTextField *screenHeights[4] = { 43 | screenHeight1, screenHeight2, screenHeight3, screenHeight4}; 44 | NSButton *screenEnableds[4] = { 45 | enableScreen1, enableScreen2, enableScreen3, enableScreen4}; 46 | 47 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 48 | 49 | NSString *rootKernelPathStr = [defaults objectForKey:@"rootKernelPath"]; 50 | NSString *romPathStr = [defaults objectForKey:@"romPath"]; 51 | NSInteger verboseState = [defaults integerForKey:@"verboseState"]; 52 | NSInteger memsize = [defaults integerForKey:@"memorySize"]; 53 | 54 | if ((memsize < 1) || (memsize > 1024)) { 55 | memsize = 8; 56 | [defaults setInteger:memsize forKey:@"memorySize"]; 57 | } 58 | 59 | verboseState = (verboseState == NSOnState) ? NSOnState : NSOffState; 60 | [defaults setInteger:verboseState forKey:@"verboseState"]; 61 | 62 | NSString *scsiPath0Str = [defaults objectForKey:@"scsiPath0"]; 63 | NSString *scsiPath1Str = [defaults objectForKey:@"scsiPath1"]; 64 | NSString *scsiPath2Str = [defaults objectForKey:@"scsiPath2"]; 65 | NSString *scsiPath3Str = [defaults objectForKey:@"scsiPath3"]; 66 | NSString *scsiPath4Str = [defaults objectForKey:@"scsiPath4"]; 67 | NSString *scsiPath5Str = [defaults objectForKey:@"scsiPath5"]; 68 | NSString *scsiPath6Str = [defaults objectForKey:@"scsiPath6"]; 69 | 70 | if (romPath) [romPath setStringValue:romPathStr]; 71 | if (kernelPath) [kernelPath setStringValue:rootKernelPathStr]; 72 | [verbose setState:verboseState]; 73 | [memorySize setStringValue:[NSString stringWithFormat:@"%u", (uint32_t)memsize]]; 74 | 75 | if (scsiPath0Str) [scsiPath0 setStringValue:scsiPath0Str]; 76 | if (scsiPath1Str) [scsiPath1 setStringValue:scsiPath1Str]; 77 | if (scsiPath2Str) [scsiPath2 setStringValue:scsiPath2Str]; 78 | if (scsiPath3Str) [scsiPath3 setStringValue:scsiPath3Str]; 79 | if (scsiPath4Str) [scsiPath4 setStringValue:scsiPath4Str]; 80 | if (scsiPath5Str) [scsiPath5 setStringValue:scsiPath5Str]; 81 | if (scsiPath6Str) [scsiPath6 setStringValue:scsiPath6Str]; 82 | 83 | for (i=0; i<4; i++) { 84 | NSInteger height = [defaults integerForKey:[NSString stringWithFormat:@"screenHeight%u", i]]; 85 | NSInteger width = [defaults integerForKey:[NSString stringWithFormat:@"screenWidth%u", i]]; 86 | NSInteger enabled = [defaults integerForKey:[NSString stringWithFormat:@"screenEnabled%u", i]]; 87 | 88 | if ((height < 342) || (height > 0xffff)) 89 | height = 480; 90 | if ((width < 342) || (width > 0xffff)) 91 | width = 640; 92 | 93 | [screenHeights[i] setStringValue:[NSString stringWithFormat:@"%u", (uint32_t)height]]; 94 | [screenWidths[i] setStringValue:[NSString stringWithFormat:@"%u", (uint32_t)width]]; 95 | [screenEnableds[i] setState:enabled]; 96 | } 97 | 98 | NSString *tapPathStr = [defaults objectForKey:@"tapPathE"]; 99 | NSString *macAddressStr = [defaults objectForKey:@"macAddressE"]; 100 | NSInteger ethernetEnabledState = [defaults integerForKey:@"ethernetEnabledE"]; 101 | 102 | [tapPath setStringValue:tapPathStr]; 103 | [macAddress setStringValue:macAddressStr]; 104 | [ethernetEnabled setIntegerValue:ethernetEnabledState]; 105 | 106 | [defaults synchronize]; 107 | } 108 | 109 | 110 | - (IBAction)browsePressed:(id)sender 111 | { 112 | NSOpenPanel* openPanel = [NSOpenPanel openPanel]; 113 | 114 | [openPanel setCanChooseFiles:YES]; 115 | [openPanel setAllowsMultipleSelection:NO]; 116 | 117 | if ([openPanel runModal] != NSOKButton) 118 | return ; 119 | 120 | NSArray *urls = [openPanel URLs]; 121 | if ([urls count] != 1) 122 | return ; 123 | 124 | NSURL *url = [urls objectAtIndex:0]; 125 | if (![url isFileURL]) 126 | return ; 127 | 128 | NSString *buttonID = [sender identifier]; 129 | NSTextField *field; 130 | 131 | if ([buttonID isEqualToString:@"romPathBrowse"]) 132 | field = romPath; 133 | else if ([buttonID isEqualToString:@"scsiPath0Browse"]) 134 | field = scsiPath0; 135 | else if ([buttonID isEqualToString:@"scsiPath1Browse"]) 136 | field = scsiPath1; 137 | else if ([buttonID isEqualToString:@"scsiPath2Browse"]) 138 | field = scsiPath2; 139 | else if ([buttonID isEqualToString:@"scsiPath3Browse"]) 140 | field = scsiPath3; 141 | else if ([buttonID isEqualToString:@"scsiPath4Browse"]) 142 | field = scsiPath4; 143 | else if ([buttonID isEqualToString:@"scsiPath5Browse"]) 144 | field = scsiPath5; 145 | else if ([buttonID isEqualToString:@"scsiPath6Browse"]) 146 | field = scsiPath6; 147 | else 148 | return ; 149 | 150 | [field setStringValue: [url path]]; 151 | } 152 | 153 | - (void) complain:(NSString*)str 154 | { 155 | NSAlert *theAlert = [NSAlert 156 | alertWithMessageText:nil 157 | defaultButton:nil 158 | alternateButton:nil 159 | otherButton:nil 160 | informativeTextWithFormat:@"%@", str 161 | ]; 162 | [theAlert runModal]; 163 | } 164 | 165 | - (IBAction)applyPressed:(id)sender 166 | { 167 | uint32_t i; 168 | NSTextField *screenWidths[4] = { 169 | screenWidth1, screenWidth2, screenWidth3, screenWidth4}; 170 | NSTextField *screenHeights[4] = { 171 | screenHeight1, screenHeight2, screenHeight3, screenHeight4}; 172 | NSButton *screenEnableds[4] = { 173 | enableScreen1, enableScreen2, enableScreen3, enableScreen4}; 174 | 175 | NSString *rootKernelPathStr = [kernelPath stringValue]; 176 | NSString *romPathStr = [romPath stringValue]; 177 | NSInteger verboseState = [verbose state]; 178 | NSInteger memsize = [memorySize integerValue]; 179 | 180 | NSString *scsiPath0Str = [scsiPath0 stringValue]; 181 | NSString *scsiPath1Str = [scsiPath1 stringValue]; 182 | NSString *scsiPath2Str = [scsiPath2 stringValue]; 183 | NSString *scsiPath3Str = [scsiPath3 stringValue]; 184 | NSString *scsiPath4Str = [scsiPath4 stringValue]; 185 | NSString *scsiPath5Str = [scsiPath5 stringValue]; 186 | NSString *scsiPath6Str = [scsiPath6 stringValue]; 187 | 188 | NSString *macAddressStr = [macAddress stringValue]; 189 | NSString *tapPathStr = [tapPath stringValue]; 190 | NSInteger ethernetEnabledState = [ethernetEnabled state]; 191 | 192 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 193 | 194 | uint8_t mac[6]; 195 | if (!parseMACAddr ([macAddressStr UTF8String], mac)) { 196 | [self complain:@"Bad MAC address"]; 197 | } 198 | else { 199 | [macAddress setStringValue:[NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", 200 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]]]; 201 | } 202 | 203 | [defaults setObject:rootKernelPathStr forKey:@"rootKernelPath"]; 204 | [defaults setObject:romPathStr forKey:@"romPath"]; 205 | [defaults setInteger:verboseState forKey:@"verboseState"]; 206 | [defaults setInteger:memsize forKey:@"memorySize"]; 207 | 208 | [defaults setObject:scsiPath0Str forKey:@"scsiPath0"]; 209 | [defaults setObject:scsiPath1Str forKey:@"scsiPath1"]; 210 | [defaults setObject:scsiPath2Str forKey:@"scsiPath2"]; 211 | [defaults setObject:scsiPath3Str forKey:@"scsiPath3"]; 212 | [defaults setObject:scsiPath4Str forKey:@"scsiPath4"]; 213 | [defaults setObject:scsiPath5Str forKey:@"scsiPath5"]; 214 | [defaults setObject:scsiPath6Str forKey:@"scsiPath6"]; 215 | 216 | for (i=0; i<4; i++) { 217 | NSInteger height = [screenHeights[i] integerValue]; 218 | NSInteger width = [screenWidths[i] integerValue]; 219 | NSInteger enabled = [screenEnableds[i] state]; 220 | 221 | if ((height < 342) || (height > 0xffff)) 222 | height = 480; 223 | if ((width < 342) || (width > 0xffff)) 224 | width = 640; 225 | 226 | [defaults setInteger:height forKey:[NSString stringWithFormat:@"screenHeight%u", i]]; 227 | [defaults setInteger:width forKey:[NSString stringWithFormat:@"screenWidth%u", i]]; 228 | [defaults setInteger:enabled forKey:[NSString stringWithFormat:@"screenEnabled%u", i]]; 229 | } 230 | 231 | [defaults setObject:macAddressStr forKey:@"macAddressE"]; 232 | [defaults setObject:tapPathStr forKey:@"tapPathE"]; 233 | [defaults setInteger:ethernetEnabledState forKey:@"ethernetEnabledE"]; 234 | 235 | [defaults synchronize]; 236 | } 237 | 238 | - (IBAction)cancelPressed:(id)sender 239 | { 240 | [[self window] close]; 241 | } 242 | - (IBAction)applyAndRunPressed:(id)sender 243 | { 244 | shoeApplication *shoeApp = (shoeApplication*) NSApp; 245 | [self applyPressed:sender]; 246 | [shoeApp startEmulator]; 247 | [[self window] close]; 248 | } 249 | 250 | -(IBAction)zapPramPressed:(id)sender 251 | { 252 | shoeApplication *shoeApp = (shoeApplication*) NSApp; 253 | [shoeApp zapPram:[NSUserDefaults standardUserDefaults] ptr:nil]; 254 | } 255 | 256 | void generateMACAddr (uint8_t *mac) 257 | { 258 | srandom((unsigned)(random() ^ time(NULL))); 259 | 260 | /* Generate a MAC address in the range of the original EtherTalk card */ 261 | 262 | mac[0] = 0x02; 263 | mac[1] = 0x60; 264 | mac[2] = 0x8c; 265 | mac[3] = random() & 0x07; 266 | mac[4] = random() & 0xff; 267 | mac[5] = random() & 0xff; 268 | } 269 | 270 | _Bool parseMACAddr (const char *str, uint8_t *mac) 271 | { 272 | uint32_t i, nibbles = 0; 273 | uint8_t allowed[256]; 274 | 275 | memset(allowed, 30, 256); 276 | for (i=0; i<256; i++) 277 | if (isspace(i)) 278 | allowed[i] = 20; 279 | allowed[':'] = 20; 280 | allowed['-'] = 20; 281 | for (i=0; i<10; i++) 282 | allowed['0' + i] = i; 283 | for (i=0; i<6; i++) { 284 | allowed['a' + i] = 10 + i; 285 | allowed['A' + i] = 10 + i; 286 | } 287 | 288 | for (i=0; str[i]; i++) { 289 | const uint8_t v = allowed[str[i]]; 290 | 291 | if (v == 30) 292 | return 0; 293 | else if (v == 20) 294 | continue; 295 | 296 | if (nibbles >= 12) 297 | return 0; 298 | mac[nibbles/2] <<= 4; 299 | mac[nibbles/2] |= v; 300 | nibbles++; 301 | } 302 | return (nibbles == 12); 303 | } 304 | 305 | -(IBAction)newMacAddrPressed:(id)sender 306 | { 307 | uint8_t mac[6]; 308 | 309 | generateMACAddr(mac); 310 | 311 | [macAddress setStringValue:[NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", 312 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]]]; 313 | } 314 | 315 | @end 316 | -------------------------------------------------------------------------------- /gui/Shoebill/shoeScreenView.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #import 27 | #import 28 | #import 29 | #import "shoeApplication.h" 30 | 31 | 32 | @interface shoeScreenView : NSOpenGLView { 33 | CGColorSpaceRef colorspace; 34 | NSTimer *timer; 35 | NSRecursiveLock *lock; 36 | CIContext *ciContext; 37 | shoeApplication *shoeApp; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /gui/Shoebill/shoeScreenView.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #import "shoeScreenView.h" 27 | #import "shoeScreenWindow.h" 28 | #import "shoeAppDelegate.h" 29 | #import "shoeApplication.h" 30 | #import 31 | 32 | @implementation shoeScreenView 33 | 34 | 35 | - (void)initCommon 36 | { 37 | shoeApp = (shoeApplication*) NSApp; 38 | } 39 | 40 | 41 | - (id)initWithFrame:(NSRect)frame 42 | { 43 | self = [super initWithFrame:frame]; 44 | if (self) 45 | [self initCommon]; 46 | return self; 47 | } 48 | 49 | - (id)initWithCoder:(NSCoder *)aDecoder 50 | { 51 | self = [super initWithCoder:aDecoder]; 52 | if (self) 53 | [self initCommon]; 54 | return self; 55 | } 56 | 57 | - (void) awakeFromNib 58 | { 59 | NSOpenGLPixelFormatAttribute attrs[] = 60 | { 61 | NSOpenGLPFADoubleBuffer, 62 | 0 63 | }; 64 | 65 | NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; 66 | assert(pf); 67 | 68 | NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil]; 69 | [self setPixelFormat:pf]; 70 | [self setOpenGLContext:context]; 71 | 72 | colorspace = CGColorSpaceCreateDeviceRGB(); 73 | 74 | timer = [NSTimer 75 | scheduledTimerWithTimeInterval:(1.0/60.0) 76 | target:self 77 | selector:@selector(timerFireMethod:) 78 | userInfo:nil 79 | repeats:YES]; 80 | [[NSRunLoop currentRunLoop] addTimer:timer 81 | forMode:NSDefaultRunLoopMode]; 82 | [[NSRunLoop currentRunLoop] addTimer:timer 83 | forMode:NSEventTrackingRunLoopMode]; 84 | 85 | [[self window] setTitle:[NSString stringWithFormat:@"Shoebill"]]; 86 | [[self window] makeKeyAndOrderFront:nil]; 87 | } 88 | 89 | - (void)timerFireMethod:(NSTimer *)timer 90 | { 91 | [self setNeedsDisplay:YES]; 92 | } 93 | 94 | - (void)prepareOpenGL 95 | { 96 | GLint swapInt = 1; 97 | [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; 98 | } 99 | 100 | 101 | - (void)drawRect:(NSRect)rect 102 | { 103 | const uint8_t slotnum = ((shoeScreenWindowController*)[[self window] windowController])->slotnum; 104 | 105 | [[self openGLContext] makeCurrentContext]; 106 | 107 | NSRect frame = [self frame]; 108 | NSRect bounds = [self bounds]; 109 | 110 | GLfloat minX = NSMinX(bounds); 111 | GLfloat minY = NSMinY(bounds); 112 | GLfloat maxX = NSMaxX(bounds); 113 | GLfloat maxY = NSMaxY(bounds); 114 | 115 | if(NSIsEmptyRect([self visibleRect])) 116 | glViewport(0, 0, 1, 1); 117 | else 118 | glViewport(0, 0, frame.size.width ,frame.size.height); 119 | 120 | glMatrixMode(GL_MODELVIEW); 121 | glLoadIdentity(); 122 | glMatrixMode(GL_PROJECTION); 123 | glLoadIdentity(); 124 | glOrtho(minX, maxX, minY, maxY, -1.0, 1.0); 125 | 126 | glDrawBuffer(GL_BACK); 127 | glClear(GL_COLOR_BUFFER_BIT); 128 | 129 | glClearColor(0.0, 0.0, 0.0, 0.0); 130 | 131 | if (shoeApp->isRunning) { 132 | shoebill_video_frame_info_t frame = shoebill_get_video_frame(slotnum, 0); 133 | 134 | glViewport(0, 0, frame.width, frame.height); 135 | glRasterPos2i(0, frame.height); 136 | glPixelStorei(GL_UNPACK_LSB_FIRST, GL_TRUE); 137 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 138 | 139 | glPixelZoom(1.0, -1.0); 140 | 141 | glDrawPixels(frame.width, 142 | frame.height, 143 | GL_RGBA, 144 | GL_UNSIGNED_BYTE, 145 | frame.buf); 146 | 147 | [[self openGLContext] flushBuffer]; 148 | 149 | shoebill_send_vbl_interrupt(slotnum); 150 | } 151 | else { 152 | [[self openGLContext] flushBuffer]; 153 | } 154 | 155 | } 156 | 157 | - (void)viewDidMoveToWindow 158 | { 159 | [[self window] setAcceptsMouseMovedEvents:YES]; 160 | [[self window] makeFirstResponder:self]; 161 | } 162 | 163 | - (void)mouseEntered:(NSEvent *)theEvent 164 | { 165 | [[self window] setAcceptsMouseMovedEvents:YES]; 166 | [[self window] makeFirstResponder:self]; 167 | } 168 | 169 | 170 | - (void)mouseMoved:(NSEvent *)theEvent 171 | { 172 | if (shoeApp->doCaptureMouse) { 173 | shoeScreenWindow *win = (shoeScreenWindow*)[self window]; 174 | 175 | assert(shoeApp->isRunning); 176 | 177 | int32_t delta_x, delta_y; 178 | CGGetLastMouseDelta(&delta_x, &delta_y); 179 | shoebill_mouse_move_delta(delta_x, delta_y); 180 | [win warpToCenter]; 181 | } 182 | } 183 | 184 | -(void)mouseDragged:(NSEvent *)theEvent 185 | { 186 | [self mouseMoved:theEvent]; 187 | } 188 | 189 | - (void)mouseDown:(NSEvent *)theEvent 190 | { 191 | 192 | if (shoeApp->doCaptureMouse) { 193 | assert(shoeApp->isRunning); 194 | 195 | // ctrl - left click doesn't get reported as rightMouseDown 196 | // on Mavericks (and maybe other OS X versions?) 197 | if ([theEvent modifierFlags] & NSControlKeyMask) { 198 | shoeScreenWindow *win = (shoeScreenWindow*)[self window]; 199 | [win uncaptureMouse]; 200 | } 201 | else 202 | shoebill_mouse_click(1); 203 | 204 | } 205 | else { 206 | shoeScreenWindow *win = (shoeScreenWindow*)[self window]; 207 | if ([win isKeyWindow]) { 208 | shoeApp->doCaptureKeys = YES; 209 | [win captureMouse]; 210 | } 211 | } 212 | } 213 | 214 | - (void)mouseUp:(NSEvent *)theEvent 215 | { 216 | if (shoeApp->doCaptureMouse) { 217 | assert(shoeApp->isRunning); 218 | shoebill_mouse_click(0); 219 | } 220 | } 221 | 222 | - (void)rightMouseDown:(NSEvent *)theEvent 223 | { 224 | if (shoeApp->doCaptureMouse) { 225 | shoeScreenWindow *win = (shoeScreenWindow*)[self window]; 226 | [win uncaptureMouse]; 227 | } 228 | } 229 | 230 | /* 231 | * Ignore keyDown/Up events here. 232 | * shoeApplication captures and sends them down to the emulator. 233 | * We need to implement these methods though, because if they make it all 234 | * the way down to NSOpenGLView, they'll generate a beep, which is annoying. 235 | */ 236 | - (void) keyDown:(NSEvent *)theEvent 237 | { 238 | } 239 | - (void) keyUp:(NSEvent *)theEvent 240 | { 241 | } 242 | 243 | @end 244 | -------------------------------------------------------------------------------- /gui/Shoebill/shoeScreenView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /gui/Shoebill/shoeScreenWindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | 27 | #import 28 | 29 | @interface shoeScreenWindow : NSWindow { 30 | @public 31 | } 32 | 33 | - (void) reevaluateKeyWindowness; 34 | - (void) warpToCenter; 35 | - (void) captureMouse; 36 | - (void) uncaptureMouse; 37 | @end 38 | -------------------------------------------------------------------------------- /gui/Shoebill/shoeScreenWindow.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #import "shoeScreenWindow.h" 27 | #import "shoeApplication.h" 28 | #import "shoeAppDelegate.h" 29 | 30 | @implementation shoeScreenWindow 31 | 32 | 33 | // Called after all the shoeScreenWindows are created and configured, 34 | // because one of them was already made key while isRunning==NO, 35 | // so -becomeKeyWindow didn't set doCapture=YES 36 | - (void)reevaluateKeyWindowness 37 | { 38 | shoeApplication *shoeApp = (shoeApplication*)NSApp; 39 | 40 | assert(shoeApp->isRunning); 41 | 42 | if ([self isKeyWindow]) { 43 | shoeApp->doCaptureKeys = YES; 44 | } 45 | else { 46 | shoeApp->doCaptureKeys = NO; 47 | [self uncaptureMouse]; 48 | } 49 | } 50 | 51 | - (void)toggleFullScreen:(id)sender 52 | { 53 | [super toggleFullScreen:sender]; 54 | 55 | const uint8_t slotnum = ((shoeScreenWindowController*)[self windowController])->slotnum; 56 | shoebill_video_frame_info_t frame = shoebill_get_video_frame(slotnum, 1); 57 | NSSize size = { 58 | .height=frame.height, 59 | .width=frame.width, 60 | }; 61 | [self setContentSize:size]; 62 | } 63 | 64 | - (void)becomeKeyWindow 65 | { 66 | shoeApplication *shoeApp = (shoeApplication*)NSApp; 67 | 68 | if (shoeApp->isRunning) { 69 | shoeApp->doCaptureKeys = YES; 70 | } 71 | 72 | [super becomeKeyWindow]; 73 | } 74 | 75 | - (void)resignKeyWindow 76 | { 77 | shoeApplication *shoeApp = (shoeApplication*)NSApp; 78 | 79 | if (shoeApp->isRunning) { 80 | shoeApp->doCaptureKeys = NO; 81 | [self uncaptureMouse]; 82 | } 83 | 84 | [super resignKeyWindow]; 85 | } 86 | 87 | - (void) warpToCenter 88 | { 89 | // Convert the cocoa window frame to quartz global coordinates 90 | NSRect winrect = [self frame]; 91 | NSScreen *mainScreen = (NSScreen*)[[NSScreen screens] objectAtIndex:0]; 92 | winrect.origin.y = NSMaxY([mainScreen frame]) - NSMaxY(winrect); 93 | CGRect cgwinrect = NSRectToCGRect(winrect); 94 | 95 | // Find the center of the window 96 | cgwinrect.origin.x += cgwinrect.size.width / 2.0; 97 | cgwinrect.origin.y += cgwinrect.size.height / 2.0; 98 | 99 | CGWarpMouseCursorPosition(cgwinrect.origin); 100 | } 101 | 102 | - (void) uncaptureMouse 103 | { 104 | shoeApplication *shoeApp = (shoeApplication*)NSApp; 105 | shoeApp->doCaptureMouse = NO; 106 | CGDisplayShowCursor(0); 107 | [self setTitle:@"Shoebill"]; 108 | } 109 | 110 | - (void) captureMouse 111 | { 112 | shoeApplication *shoeApp = (shoeApplication*)NSApp; 113 | shoeApp->doCaptureMouse = YES; 114 | CGDisplayHideCursor(0); 115 | [self warpToCenter]; 116 | [self setTitle:@"Shoebill (Ctrl-click to escape)"]; 117 | } 118 | 119 | 120 | @end 121 | -------------------------------------------------------------------------------- /gui/Shoebill/shoeScreenWindowController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #import 27 | 28 | @interface shoeScreenWindowController : NSWindowController { 29 | @public 30 | uint8_t slotnum; 31 | } 32 | 33 | - (id)initWithWindowNibName:(NSString *)windowNibName slotnum:(uint8_t)_slotnum; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /gui/Shoebill/shoeScreenWindowController.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Peter Rutenbar 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #import "shoeScreenWindowController.h" 27 | #import "shoeApplication.h" 28 | 29 | @interface shoeScreenWindowController () 30 | 31 | @end 32 | 33 | @implementation shoeScreenWindowController 34 | 35 | - (id)initWithWindowNibName:(NSString *)windowNibName 36 | slotnum:(uint8_t)_slotnum 37 | { 38 | shoeScreenWindowController *result = [super initWithWindowNibName:windowNibName]; 39 | result->slotnum = _slotnum; 40 | return result; 41 | } 42 | 43 | - (void)windowDidLoad 44 | { 45 | [super windowDidLoad]; 46 | 47 | shoebill_video_frame_info_t frame = shoebill_get_video_frame(slotnum, 1); 48 | NSSize size = { 49 | .height=frame.height, 50 | .width=frame.width, 51 | }; 52 | 53 | [[self window] setContentSize:size]; 54 | } 55 | 56 | - (NSApplicationPresentationOptions)window:(NSWindow *)window 57 | willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions 58 | { 59 | 60 | return (NSApplicationPresentationFullScreen | // support full screen for this window (required) 61 | NSApplicationPresentationHideDock | // completely hide the dock 62 | NSApplicationPresentationAutoHideMenuBar); // yes we want the menu bar to show/hide 63 | } 64 | 65 | - (NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize 66 | { 67 | shoebill_video_frame_info_t frame = shoebill_get_video_frame(slotnum, 1); 68 | NSSize size = { 69 | .height=frame.height, 70 | .width=frame.width, 71 | }; 72 | 73 | return size; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /sdl-gui/lin_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CC=gcc 4 | 5 | files="" 6 | for i in adb fpu mc68851 mem via floppy core_api cpu dis; do 7 | perl ../core/macro.pl ../core/$i.c $i.post.c 8 | files="$files $i.post.c" 9 | done 10 | 11 | for i in SoftFloat/softfloat atrap_tab coff exception macii_symbols redblack scsi video filesystem alloc_pool toby_frame_buffer ethernet sound; do 12 | files="$files ../core/$i.c" 13 | done 14 | 15 | $CC -O1 ../core/decoder_gen.c -o decoder_gen 16 | ./decoder_gen inst . 17 | ./decoder_gen dis . 18 | 19 | 20 | cmd="$CC -O3 -ggdb -flto $files sdl.c -lpthread -lm -lSDL2 -lGL -o shoebill" 21 | echo $cmd 22 | $cmd 23 | -------------------------------------------------------------------------------- /sdl-gui/osx_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CC=gcc 4 | 5 | files="" 6 | for i in adb fpu mc68851 mem via floppy core_api cpu dis; do 7 | perl ../core/macro.pl ../core/$i.c $i.post.c 8 | files="$files $i.post.c" 9 | done 10 | 11 | for i in SoftFloat/softfloat atrap_tab coff exception macii_symbols redblack scsi video filesystem alloc_pool toby_frame_buffer ethernet sound; do 12 | files="$files ../core/$i.c" 13 | done 14 | 15 | $CC -O1 ../core/decoder_gen.c -o decoder_gen 16 | ./decoder_gen inst . 17 | ./decoder_gen dis . 18 | 19 | 20 | cmd="$CC -F/Library/Frameworks -O3 -ggdb -flto $files sdl.c -framework OpenGL -framework SDL2 -o shoebill" 21 | echo $cmd 22 | $cmd 23 | -------------------------------------------------------------------------------- /sdl-gui/win_build.bat: -------------------------------------------------------------------------------- 1 | for %%i in (adb fpu mc68851 mem via floppy core_api cpu dis) do ( 2 | perl ..\core\macro.pl ..\core\%%i.c %%i.post.c 3 | ) 4 | 5 | gcc -O1 ..\core\decoder_gen.c -o decoder_gen 6 | decoder_gen inst . 7 | decoder_gen dis . 8 | 9 | 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 10 | --------------------------------------------------------------------------------